Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corefx.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMarek Safar <marek.safar@gmail.com>2018-04-02 00:54:57 +0300
committerMarek Safar <marek.safar@gmail.com>2018-04-02 00:54:57 +0300
commitf4951179bb053a9264f063c824720d6237ae55f1 (patch)
treef7beda10c1e1c9f8a8f4c21a000993598ea0502c /src
parente89c5c9646d29d74a069f8f9630e35858b6bb076 (diff)
parent79b3c40e4322fd1778ad075214c90af93e5d2adf (diff)
Merge remote-tracking branch 'upstream/release/2.1' into 2.1-merge
Diffstat (limited to 'src')
-rw-r--r--src/Common/src/CoreLib/Internal/IO/File.Unix.cs25
-rw-r--r--src/Common/src/CoreLib/Internal/IO/File.Windows.cs77
-rw-r--r--src/Common/src/CoreLib/Internal/IO/File.cs77
-rw-r--r--src/Common/src/CoreLib/Internal/Runtime/CompilerServices/Unsafe.cs40
-rw-r--r--src/Common/src/CoreLib/Interop/Unix/Interop.Errors.cs2
-rw-r--r--src/Common/src/CoreLib/Interop/Unix/Interop.Libraries.cs2
-rw-r--r--src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Calendar.cs12
-rw-r--r--src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Casing.cs14
-rw-r--r--src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Collation.cs56
-rw-r--r--src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.ICU.cs4
-rw-r--r--src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Idna.cs10
-rw-r--r--src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Locale.cs30
-rw-r--r--src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Normalization.cs6
-rw-r--r--src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.ResultCode.cs2
-rw-r--r--src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.TimeZoneInfo.cs4
-rw-r--r--src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Utils.cs8
-rw-r--r--src/Common/src/CoreLib/Interop/Unix/System.Native/Interop.GetRandomBytes.cs2
-rw-r--r--src/Common/src/CoreLib/Interop/Unix/System.Native/Interop.PathConf.cs2
-rw-r--r--src/Common/src/CoreLib/Interop/Unix/System.Native/Interop.Read.cs2
-rw-r--r--src/Common/src/CoreLib/Interop/Unix/System.Native/Interop.ReadDir.cs102
-rw-r--r--src/Common/src/CoreLib/Interop/Unix/System.Native/Interop.Write.cs4
-rw-r--r--src/Common/src/CoreLib/Interop/Windows/BCrypt/Interop.BCryptGenRandom.cs2
-rw-r--r--src/Common/src/CoreLib/Interop/Windows/Interop.Errors.cs1
-rw-r--r--src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.FindClose.cs2
-rw-r--r--src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetFileAttributesEx.cs4
-rw-r--r--src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetFileType_SafeHandle.cs2
-rw-r--r--src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetFullPathNameW.cs14
-rw-r--r--src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetLongPathNameW.cs14
-rw-r--r--src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetTempFileNameW.cs16
-rw-r--r--src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetTempPathW.cs15
-rw-r--r--src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.Globalization.cs34
-rw-r--r--src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.MAX_PATH.cs (renamed from src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/IExprWithObject.cs)6
-rw-r--r--src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.MUI.cs (renamed from src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/Native/Interop.localization.cs)15
-rw-r--r--src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.MultiByteToWideChar.cs20
-rw-r--r--src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.TimeZone.Registry.cs31
-rw-r--r--src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.TimeZone.cs94
-rw-r--r--src/Common/src/CoreLib/Interop/Windows/Ole32/Interop.CoCreateGuid.cs15
-rw-r--r--src/Common/src/CoreLib/Microsoft/Win32/SafeHandles/SafeDirectoryHandle.Unix.cs26
-rw-r--r--src/Common/src/CoreLib/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs11
-rw-r--r--src/Common/src/CoreLib/Microsoft/Win32/SafeHandles/SafeFindHandle.Windows.cs22
-rw-r--r--src/Common/src/CoreLib/System.Private.CoreLib.Shared.projitems75
-rw-r--r--src/Common/src/CoreLib/System/ArraySegment.cs2
-rw-r--r--src/Common/src/CoreLib/System/Boolean.cs21
-rw-r--r--src/Common/src/CoreLib/System/Buffers/ArrayPoolEventSource.cs14
-rw-r--r--src/Common/src/CoreLib/System/Buffers/OwnedMemory.cs6
-rw-r--r--src/Common/src/CoreLib/System/Buffers/TlsOverPerCoreLockedStacksArrayPool.cs6
-rw-r--r--src/Common/src/CoreLib/System/Byte.cs4
-rw-r--r--src/Common/src/CoreLib/System/Char.cs8
-rw-r--r--src/Common/src/CoreLib/System/Collections/Generic/Dictionary.cs717
-rw-r--r--src/Common/src/CoreLib/System/Collections/Generic/List.cs169
-rw-r--r--src/Common/src/CoreLib/System/Collections/Generic/NonRandomizedStringEqualityComparer.cs8
-rw-r--r--src/Common/src/CoreLib/System/Collections/Generic/ValueListBuilder.cs76
-rw-r--r--src/Common/src/CoreLib/System/Collections/ListDictionaryInternal.cs8
-rw-r--r--src/Common/src/CoreLib/System/Convert.Base64.cs217
-rw-r--r--src/Common/src/CoreLib/System/Convert.cs352
-rw-r--r--src/Common/src/CoreLib/System/DateTime.cs41
-rw-r--r--src/Common/src/CoreLib/System/DateTimeOffset.cs33
-rw-r--r--src/Common/src/CoreLib/System/Diagnostics/Debug.Unix.cs18
-rw-r--r--src/Common/src/CoreLib/System/Diagnostics/Debug.cs39
-rw-r--r--src/Common/src/CoreLib/System/Diagnostics/Tracing/ActivityTracker.cs5
-rw-r--r--src/Common/src/CoreLib/System/Diagnostics/Tracing/EventDescriptor.cs8
-rw-r--r--src/Common/src/CoreLib/System/Diagnostics/Tracing/EventProvider.cs19
-rw-r--r--src/Common/src/CoreLib/System/Diagnostics/Tracing/EventSource.cs1413
-rw-r--r--src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/DataCollector.cs39
-rw-r--r--src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/EventSourceActivity.cs2
-rw-r--r--src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/FieldMetadata.cs2
-rw-r--r--src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/InvokeTypeInfo.cs2
-rw-r--r--src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/NameInfo.cs47
-rw-r--r--src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/SimpleTypeInfos.cs16
-rw-r--r--src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/TraceLoggingDataCollector.cs11
-rw-r--r--src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs80
-rw-r--r--src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventTypes.cs20
-rw-r--r--src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/TraceLoggingMetadataCollector.cs31
-rw-r--r--src/Common/src/CoreLib/System/Double.cs39
-rw-r--r--src/Common/src/CoreLib/System/Globalization/CalendarData.Unix.cs44
-rw-r--r--src/Common/src/CoreLib/System/Globalization/CompareInfo.Invariant.cs13
-rw-r--r--src/Common/src/CoreLib/System/Globalization/CompareInfo.Unix.cs1014
-rw-r--r--src/Common/src/CoreLib/System/Globalization/CompareInfo.Windows.cs644
-rw-r--r--src/Common/src/CoreLib/System/Globalization/CompareInfo.cs182
-rw-r--r--src/Common/src/CoreLib/System/Globalization/CultureData.Unix.cs16
-rw-r--r--src/Common/src/CoreLib/System/Globalization/DateTimeFormat.cs309
-rw-r--r--src/Common/src/CoreLib/System/Globalization/DateTimeFormatInfo.cs6
-rw-r--r--src/Common/src/CoreLib/System/Globalization/DateTimeParse.cs50
-rw-r--r--src/Common/src/CoreLib/System/Globalization/DateTimeStyles.cs2
-rw-r--r--src/Common/src/CoreLib/System/Globalization/DaylightTime.cs4
-rw-r--r--src/Common/src/CoreLib/System/Globalization/GlobalizationExtensions.cs32
-rw-r--r--src/Common/src/CoreLib/System/Globalization/GregorianCalendar.cs18
-rw-r--r--src/Common/src/CoreLib/System/Globalization/HijriCalendar.Win32.cs2
-rw-r--r--src/Common/src/CoreLib/System/Globalization/IdnMapping.Unix.cs14
-rw-r--r--src/Common/src/CoreLib/System/Globalization/InternalGlobalizationHelper.cs2
-rw-r--r--src/Common/src/CoreLib/System/Globalization/JapaneseCalendar.Unix.cs4
-rw-r--r--src/Common/src/CoreLib/System/Globalization/JapaneseCalendar.Win32.cs2
-rw-r--r--src/Common/src/CoreLib/System/Globalization/Normalization.Unix.cs4
-rw-r--r--src/Common/src/CoreLib/System/Globalization/TextInfo.Unix.cs55
-rw-r--r--src/Common/src/CoreLib/System/Globalization/TextInfo.Windows.cs38
-rw-r--r--src/Common/src/CoreLib/System/Globalization/TextInfo.cs90
-rw-r--r--src/Common/src/CoreLib/System/Globalization/TimeSpanFormat.cs3
-rw-r--r--src/Common/src/CoreLib/System/Globalization/TimeSpanParse.cs76
-rw-r--r--src/Common/src/CoreLib/System/Guid.Unix.cs38
-rw-r--r--src/Common/src/CoreLib/System/Guid.Windows.cs29
-rw-r--r--src/Common/src/CoreLib/System/Guid.cs18
-rw-r--r--src/Common/src/CoreLib/System/IO/DriveNotFoundException.cs36
-rw-r--r--src/Common/src/CoreLib/System/IO/FileStream.Unix.cs14
-rw-r--r--src/Common/src/CoreLib/System/IO/FileStream.Windows.cs107
-rw-r--r--src/Common/src/CoreLib/System/IO/FileStream.cs47
-rw-r--r--src/Common/src/CoreLib/System/IO/FileStreamCompletionSource.Win32.cs22
-rw-r--r--src/Common/src/CoreLib/System/IO/MemoryStream.cs36
-rw-r--r--src/Common/src/CoreLib/System/IO/Path.Unix.cs118
-rw-r--r--src/Common/src/CoreLib/System/IO/Path.Windows.cs253
-rw-r--r--src/Common/src/CoreLib/System/IO/Path.cs496
-rw-r--r--src/Common/src/CoreLib/System/IO/PathHelper.Windows.cs428
-rw-r--r--src/Common/src/CoreLib/System/IO/PathInternal.Unix.cs34
-rw-r--r--src/Common/src/CoreLib/System/IO/PathInternal.Windows.StringBuffer.cs93
-rw-r--r--src/Common/src/CoreLib/System/IO/PathInternal.Windows.cs210
-rw-r--r--src/Common/src/CoreLib/System/IO/PathInternal.cs149
-rw-r--r--src/Common/src/CoreLib/System/IO/PinnedBufferMemoryStream.cs4
-rw-r--r--src/Common/src/CoreLib/System/IO/StreamReader.cs20
-rw-r--r--src/Common/src/CoreLib/System/IO/StreamWriter.cs72
-rw-r--r--src/Common/src/CoreLib/System/IO/TextReader.cs5
-rw-r--r--src/Common/src/CoreLib/System/IO/UnmanagedMemoryStream.cs50
-rw-r--r--src/Common/src/CoreLib/System/IO/UnmanagedMemoryStreamWrapper.cs16
-rw-r--r--src/Common/src/CoreLib/System/IO/Win32Marshal.cs110
-rw-r--r--src/Common/src/CoreLib/System/IntPtr.cs6
-rw-r--r--src/Common/src/CoreLib/System/Marvin.cs139
-rw-r--r--src/Common/src/CoreLib/System/Memory.cs126
-rw-r--r--src/Common/src/CoreLib/System/MemoryDebugView.cs27
-rw-r--r--src/Common/src/CoreLib/System/MemoryExtensions.Fast.cs496
-rw-r--r--src/Common/src/CoreLib/System/MemoryExtensions.cs (renamed from src/System.Memory/src/System/MemoryExtensions.cs)583
-rw-r--r--src/Common/src/CoreLib/System/Number.Formatting.cs9
-rw-r--r--src/Common/src/CoreLib/System/Number.Parsing.cs46
-rw-r--r--src/Common/src/CoreLib/System/Numerics/ConstantHelper.cs (renamed from src/System.Numerics.Vectors/src/System/Numerics/ConstantHelper.cs)0
-rw-r--r--src/Common/src/CoreLib/System/Numerics/ConstantHelper.tt (renamed from src/System.Numerics.Vectors/src/System/Numerics/ConstantHelper.tt)0
-rw-r--r--src/Common/src/CoreLib/System/Numerics/GenerationConfig.ttinclude (renamed from src/System.Numerics.Vectors/src/System/Numerics/GenerationConfig.ttinclude)28
-rw-r--r--src/Common/src/CoreLib/System/Numerics/Register.cs (renamed from src/System.Numerics.Vectors/src/System/Numerics/Register.cs)0
-rw-r--r--src/Common/src/CoreLib/System/Numerics/Register.tt (renamed from src/System.Numerics.Vectors/src/System/Numerics/Register.tt)0
-rw-r--r--src/Common/src/CoreLib/System/Numerics/Vector.cs (renamed from src/System.Numerics.Vectors/src/System/Numerics/Vector.cs)236
-rw-r--r--src/Common/src/CoreLib/System/Numerics/Vector.tt (renamed from src/System.Numerics.Vectors/src/System/Numerics/Vector.tt)132
-rw-r--r--src/Common/src/CoreLib/System/Numerics/Vector_Operations.cs (renamed from src/System.Numerics.Vectors/src/System/Numerics/Vector_Operations.cs)2
-rw-r--r--src/Common/src/CoreLib/System/OverflowException.cs2
-rw-r--r--src/Common/src/CoreLib/System/ReadOnlyMemory.cs76
-rw-r--r--src/Common/src/CoreLib/System/ReadOnlySpan.Fast.cs270
-rw-r--r--src/Common/src/CoreLib/System/ReadOnlySpan.cs250
-rw-r--r--src/Common/src/CoreLib/System/Reflection/SignatureTypeExtensions.cs1
-rw-r--r--src/Common/src/CoreLib/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs112
-rw-r--r--src/Common/src/CoreLib/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs220
-rw-r--r--src/Common/src/CoreLib/System/Runtime/CompilerServices/IntrinsicAttribute.cs4
-rw-r--r--src/Common/src/CoreLib/System/Runtime/CompilerServices/TypeForwardedFromAttribute.cs3
-rw-r--r--src/Common/src/CoreLib/System/Runtime/CompilerServices/ValueTaskAwaiter.cs190
-rw-r--r--src/Common/src/CoreLib/System/Runtime/InteropServices/MemoryMarshal.Fast.cs232
-rw-r--r--src/Common/src/CoreLib/System/Runtime/InteropServices/MemoryMarshal.cs241
-rw-r--r--src/Common/src/CoreLib/System/Runtime/InteropServices/StringBuffer.cs301
-rw-r--r--src/Common/src/CoreLib/System/Security/SafeBSTRHandle.cs2
-rw-r--r--src/Common/src/CoreLib/System/Security/SecureString.cs23
-rw-r--r--src/Common/src/CoreLib/System/Single.cs38
-rw-r--r--src/Common/src/CoreLib/System/Span.Fast.cs350
-rw-r--r--src/Common/src/CoreLib/System/Span.NonGeneric.cs638
-rw-r--r--src/Common/src/CoreLib/System/Span.cs335
-rw-r--r--src/Common/src/CoreLib/System/SpanHelpers.BinarySearch.cs (renamed from src/System.Memory/src/System/SpanHelpers.BinarySearch.cs)4
-rw-r--r--src/Common/src/CoreLib/System/SpanHelpers.Byte.cs (renamed from src/System.Memory/src/System/SpanHelpers.byte.cs)320
-rw-r--r--src/Common/src/CoreLib/System/SpanHelpers.Char.cs201
-rw-r--r--src/Common/src/CoreLib/System/SpanHelpers.T.cs (renamed from src/System.Memory/src/System/SpanHelpers.T.cs)41
-rw-r--r--src/Common/src/CoreLib/System/SpanHelpers.cs537
-rw-r--r--src/Common/src/CoreLib/System/String.Comparison.cs1011
-rw-r--r--src/Common/src/CoreLib/System/String.Manipulation.cs1852
-rw-r--r--src/Common/src/CoreLib/System/String.Searching.cs192
-rw-r--r--src/Common/src/CoreLib/System/String.cs759
-rw-r--r--src/Common/src/CoreLib/System/StringComparer.cs75
-rw-r--r--src/Common/src/CoreLib/System/StringSpanHelpers.cs129
-rw-r--r--src/Common/src/CoreLib/System/Text/Decoder.cs10
-rw-r--r--src/Common/src/CoreLib/System/Text/Encoder.cs10
-rw-r--r--src/Common/src/CoreLib/System/Text/Encoding.cs14
-rw-r--r--src/Common/src/CoreLib/System/Text/StringBuilder.Debug.cs37
-rw-r--r--src/Common/src/CoreLib/System/Text/StringBuilder.cs89
-rw-r--r--src/Common/src/CoreLib/System/Text/UTF8Encoding.cs6
-rw-r--r--src/Common/src/CoreLib/System/Text/ValueStringBuilder.cs92
-rw-r--r--src/Common/src/CoreLib/System/Threading/AsyncLocal.cs4
-rw-r--r--src/Common/src/CoreLib/System/Threading/ExecutionContext.cs297
-rw-r--r--src/Common/src/CoreLib/System/Threading/ReaderWriterLockSlim.cs2
-rw-r--r--src/Common/src/CoreLib/System/Threading/Tasks/Sources/IValueTaskSource.cs82
-rw-r--r--src/Common/src/CoreLib/System/Threading/Tasks/TaskCanceledException.cs12
-rw-r--r--src/Common/src/CoreLib/System/Threading/Tasks/ValueTask.cs791
-rw-r--r--src/Common/src/CoreLib/System/TimeZoneInfo.Unix.cs1560
-rw-r--r--src/Common/src/CoreLib/System/TimeZoneInfo.Win32.cs999
-rw-r--r--src/Common/src/CoreLib/System/TimeZoneInfo.cs2
-rw-r--r--src/Common/src/CoreLib/System/Type.cs2
-rw-r--r--src/Common/src/CoreLib/System/UIntPtr.cs6
-rw-r--r--src/Common/src/CoreLib/System/UnitySerializationHolder.cs8
-rw-r--r--src/Common/src/CoreLib/System/Version.cs16
-rw-r--r--src/Common/src/Interop/Linux/procfs/Interop.ProcFsStat.cs2
-rw-r--r--src/Common/src/Interop/OSX/Interop.CoreFoundation.CFData.cs29
-rw-r--r--src/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.KeyAgree.cs61
-rw-r--r--src/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.RSA.cs120
-rw-r--r--src/Common/src/Interop/Unix/Interop.Libraries.cs1
-rw-r--r--src/Common/src/Interop/Unix/System.Globalization.Native/Interop.Idna.cs21
-rw-r--r--src/Common/src/Interop/Unix/System.Native/Interop.ForkAndExecProcess.cs3
-rw-r--r--src/Common/src/Interop/Unix/System.Native/Interop.GetPwUid.cs5
-rw-r--r--src/Common/src/Interop/Unix/System.Native/Interop.HostEntry.cs21
-rw-r--r--src/Common/src/Interop/Unix/System.Native/Interop.ReadDir.cs96
-rw-r--r--src/Common/src/Interop/Unix/System.Native/Interop.RegisterForSigChld.cs16
-rw-r--r--src/Common/src/Interop/Unix/System.Native/Interop.Stat.Span.cs41
-rw-r--r--src/Common/src/Interop/Unix/System.Native/Interop.WaitId.cs26
-rw-r--r--src/Common/src/Interop/Unix/System.Native/Interop.WaitPid.cs49
-rw-r--r--src/Common/src/Interop/Unix/System.Net.Http.Native/Interop.Easy.cs3
-rw-r--r--src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Ecdh.cs43
-rw-r--r--src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs2
-rw-r--r--src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSslVersion.cs2
-rw-r--r--src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs27
-rw-r--r--src/Common/src/Interop/Windows/BCrypt/Interop.CreateCryptographicException.cs4
-rw-r--r--src/Common/src/Interop/Windows/Interop.Errors.cs1
-rw-r--r--src/Common/src/Interop/Windows/Interop.Libraries.cs1
-rw-r--r--src/Common/src/Interop/Windows/Interop.LongFileTime.cs2
-rw-r--r--src/Common/src/Interop/Windows/Interop.UNICODE_STRING.cs9
-rw-r--r--src/Common/src/Interop/Windows/NCrypt/Interop.NCryptBuffer.cs42
-rw-r--r--src/Common/src/Interop/Windows/NCrypt/Interop.NCryptDeriveKeyMaterial.cs249
-rw-r--r--src/Common/src/Interop/Windows/NCrypt/Interop.NCryptDeriveSecretAgreement.cs53
-rw-r--r--src/Common/src/Interop/Windows/NtDll/Interop.FILE_FULL_DIR_INFORMATION.cs3
-rw-r--r--src/Common/src/Interop/Windows/NtDll/Interop.NtCreateFile.cs580
-rw-r--r--src/Common/src/Interop/Windows/SChannel/UnmanagedCertificateContext.IntPtr.cs7
-rw-r--r--src/Common/src/Interop/Windows/Winsock/AddressInfoEx.cs25
-rw-r--r--src/Common/src/Interop/Windows/Winsock/Interop.GetAddrInfoExW.cs36
-rw-r--r--src/Common/src/Interop/Windows/Winsock/Interop.gethostbyaddr.cs23
-rw-r--r--src/Common/src/Interop/Windows/Winsock/Interop.gethostbyname.cs17
-rw-r--r--src/Common/src/Interop/Windows/advapi32/Interop.ClaimSecurityAttributes.cs128
-rw-r--r--src/Common/src/Interop/Windows/advapi32/Interop.CreateProcessWithLogon.cs8
-rw-r--r--src/Common/src/Interop/Windows/advapi32/Interop.LookupAccountNameW.cs13
-rw-r--r--src/Common/src/Interop/Windows/advapi32/Interop.ServiceProcessOptions.cs1
-rw-r--r--src/Common/src/Interop/Windows/kernel32/Interop.CopyFileEx.cs4
-rw-r--r--src/Common/src/Interop/Windows/kernel32/Interop.CreateFile.cs4
-rw-r--r--src/Common/src/Interop/Windows/kernel32/Interop.CreateFile2.cs2
-rw-r--r--src/Common/src/Interop/Windows/kernel32/Interop.CreateProcess.cs82
-rw-r--r--src/Common/src/Interop/Windows/kernel32/Interop.DeleteFile.cs2
-rw-r--r--src/Common/src/Interop/Windows/kernel32/Interop.DeleteVolumeMountPoint.cs2
-rw-r--r--src/Common/src/Interop/Windows/kernel32/Interop.ExpandEnvironmentStrings.cs3
-rw-r--r--src/Common/src/Interop/Windows/kernel32/Interop.FindFirstFileEx.cs2
-rw-r--r--src/Common/src/Interop/Windows/kernel32/Interop.FormatMessage.cs43
-rw-r--r--src/Common/src/Interop/Windows/kernel32/Interop.GetComputerName.cs11
-rw-r--r--src/Common/src/Interop/Windows/kernel32/Interop.GetCurrentDirectory.cs3
-rw-r--r--src/Common/src/Interop/Windows/kernel32/Interop.GetCurrentThreadId.cs15
-rw-r--r--src/Common/src/Interop/Windows/kernel32/Interop.GetFileAttributesEx.cs2
-rw-r--r--src/Common/src/Interop/Windows/kernel32/Interop.GetLongPathName.cs25
-rw-r--r--src/Common/src/Interop/Windows/kernel32/Interop.GetSystemDirectoryW.cs11
-rw-r--r--src/Common/src/Interop/Windows/kernel32/Interop.LoadLibraryEx.cs1
-rw-r--r--src/Common/src/Interop/Windows/kernel32/Interop.MaxLengths.cs14
-rw-r--r--src/Common/src/Interop/Windows/kernel32/Interop.MoveFileEx.cs4
-rw-r--r--src/Common/src/Interop/Windows/kernel32/Interop.RemoveDirectory.cs2
-rw-r--r--src/Common/src/Interop/Windows/kernel32/Interop.ReplaceFile.cs6
-rw-r--r--src/Common/src/Interop/Windows/kernel32/Interop.SetFileAttributes.cs2
-rw-r--r--src/Common/src/Interop/Windows/secur32/Interop.GetUserNameExW.cs3
-rw-r--r--src/Common/src/Interop/Windows/sspicli/SecuritySafeHandles.cs104
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.Constants.cs229
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.CreateWindowEx.cs16
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.DefWindowProc.cs15
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.DestroyWindow.cs15
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.DispatchMessage.cs15
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.FindWindow.cs15
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.GetClassInfo.cs15
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.GetProcessWindowStation.cs15
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.GetUserObjectInformation.cs15
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.GetWindowThreadProcessId.cs5
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.IsWindow.cs15
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.KillTimer.cs15
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.MSG.cs23
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.MsgWaitForMultipleObjectsEx.cs15
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.PeekMessage.cs15
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.PostMessage.cs7
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.RegisterClass.cs14
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.RegisterWindowMessage.cs14
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.SendMessage.cs18
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.SetClassLong.cs15
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.SetClassLongPtr.cs15
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.SetTimer.cs15
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.SetWindowLong.cs15
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.SetWindowLongPtr.cs15
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.TranslateMessage.cs15
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.USEROBJECTFLAGS.cs18
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.UnregisterClass.cs15
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.WNDCLASS.cs40
-rw-r--r--src/Common/src/Interop/Windows/user32/Interop.WndProc.cs13
-rw-r--r--src/Common/src/Interop/Windows/winhttp/Interop.SafeWinHttpHandle.cs41
-rw-r--r--src/Common/src/Interop/Windows/winhttp/Interop.winhttp.cs75
-rw-r--r--src/Common/src/Interop/Windows/wtsapi32/Interop.Constants.cs21
-rw-r--r--src/Common/src/Interop/Windows/wtsapi32/Interop.WTSRegisterSessionNotification.cs14
-rw-r--r--src/Common/src/Interop/Windows/wtsapi32/Interop.WTSUnRegisterSessionNotification.cs14
-rw-r--r--src/Common/src/Microsoft/Win32/SafeHandles/SafeEvpPKeyHandle.Unix.cs (renamed from src/System.Security.Cryptography.OpenSsl/src/System/Security/Cryptography/SafeEvpPKeyHandle.Unix.cs)7
-rw-r--r--src/Common/src/Microsoft/Win32/SafeHandles/SafeEvpPkeyCtxHandle.Unix.cs31
-rw-r--r--src/Common/src/System/Collections/Generic/LargeArrayBuilder.cs55
-rw-r--r--src/Common/src/System/Collections/HashHelpers.cs55
-rw-r--r--src/Common/src/System/Data/Common/AdapterUtil.Drivers.cs35
-rw-r--r--src/Common/src/System/Data/Common/AdapterUtil.cs5
-rw-r--r--src/Common/src/System/Data/ProviderBase/DbConnectionClosed.cs138
-rw-r--r--src/Common/src/System/Data/ProviderBase/DbConnectionFactory.cs427
-rw-r--r--src/Common/src/System/Data/ProviderBase/DbConnectionInternal.cs434
-rw-r--r--src/Common/src/System/Data/ProviderBase/DbConnectionPoolGroup.cs (renamed from src/System.Data.SqlClient/src/System/Data/ProviderBase/DbConnectionPoolGroup.cs)37
-rw-r--r--src/Common/src/System/Data/ProviderBase/DbMetaDataFactory.cs (renamed from src/System.Data.SqlClient/src/System/Data/ProviderBase/DbMetaDataFactory.cs)45
-rw-r--r--src/Common/src/System/Data/ProviderBase/DbReferenceCollection.cs (renamed from src/System.Data.SqlClient/src/System/Data/ProviderBase/DbReferenceCollection.cs)0
-rw-r--r--src/Common/src/System/Data/ProviderBase/TimeoutTimer.cs (renamed from src/System.Data.Odbc/src/Common/System/Data/ProviderBase/TimeoutTimer.cs)0
-rw-r--r--src/Common/src/System/Drawing/KnownColor.cs7
-rw-r--r--src/Common/src/System/Drawing/KnownColorTable.cs19
-rw-r--r--src/Common/src/System/Globalization/FormatProvider.Number.cs3
-rw-r--r--src/Common/src/System/IO/DelegatingStream.cs16
-rw-r--r--src/Common/src/System/IO/PathInternal.Unix.cs57
-rw-r--r--src/Common/src/System/IO/PathInternal.Windows.cs233
-rw-r--r--src/Common/src/System/IO/PathInternal.cs149
-rw-r--r--src/Common/src/System/IO/PersistedFiles.Unix.cs2
-rw-r--r--src/Common/src/System/IO/ReadOnlyMemoryStream.cs20
-rw-r--r--src/Common/src/System/IO/Win32Marshal.cs136
-rw-r--r--src/Common/src/System/Marvin.cs7
-rw-r--r--src/Common/src/System/MutableDecimal.cs (renamed from src/System.Memory/Common/src/System/MutableDecimal.cs)0
-rw-r--r--src/Common/src/System/Net/Http/HttpHandlerDefaults.cs10
-rw-r--r--src/Common/src/System/Net/Http/NoWriteNoSeekStreamContent.cs21
-rw-r--r--src/Common/src/System/Net/HttpStatusDescription.cs15
-rw-r--r--src/Common/src/System/Net/Logging/NetEventSource.Common.cs188
-rw-r--r--src/Common/src/System/Net/NTAuthentication.Common.cs22
-rw-r--r--src/Common/src/System/Net/NetworkInformation/UnixCommandLinePing.cs3
-rw-r--r--src/Common/src/System/Net/SafeCloseSocket.Windows.cs28
-rw-r--r--src/Common/src/System/Net/Security/CertificateHelper.Unix.cs24
-rw-r--r--src/Common/src/System/Net/Security/CertificateHelper.Windows.cs3
-rw-r--r--src/Common/src/System/Net/Security/NetEventSource.Security.cs10
-rw-r--r--src/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs23
-rw-r--r--src/Common/src/System/Net/SocketAddressPal.Unix.cs8
-rw-r--r--src/Common/src/System/Net/SocketAddressPal.Windows.cs4
-rw-r--r--src/Common/src/System/Net/WebSockets/ManagedWebSocket.cs281
-rw-r--r--src/Common/src/System/PasteArguments.Unix.cs28
-rw-r--r--src/Common/src/System/PasteArguments.Windows.cs66
-rw-r--r--src/Common/src/System/PasteArguments.cs151
-rw-r--r--src/Common/src/System/Runtime/InteropServices/FunctionWrapper.cs4
-rw-r--r--src/Common/src/System/Security/Cryptography/Asn1V2.Serializer.cs145
-rw-r--r--src/Common/src/System/Security/Cryptography/Asn1V2.cs2
-rw-r--r--src/Common/src/System/Security/Cryptography/AsnWriter.cs64
-rw-r--r--src/Common/src/System/Security/Cryptography/DSACng.SignVerify.cs16
-rw-r--r--src/Common/src/System/Security/Cryptography/DSAOpenSsl.cs16
-rw-r--r--src/Common/src/System/Security/Cryptography/DSASecurityTransforms.cs4
-rw-r--r--src/Common/src/System/Security/Cryptography/ECCng.HashAlgorithm.cs33
-rw-r--r--src/Common/src/System/Security/Cryptography/ECCng.ImportExport.cs79
-rw-r--r--src/Common/src/System/Security/Cryptography/ECDiffieHellmanCng.ImportExport.cs94
-rw-r--r--src/Common/src/System/Security/Cryptography/ECDiffieHellmanCng.cs146
-rw-r--r--src/Common/src/System/Security/Cryptography/ECDiffieHellmanDerivation.cs259
-rw-r--r--src/Common/src/System/Security/Cryptography/ECDiffieHellmanOpenSsl.Derive.cs202
-rw-r--r--src/Common/src/System/Security/Cryptography/ECDiffieHellmanOpenSsl.cs90
-rw-r--r--src/Common/src/System/Security/Cryptography/ECDiffieHellmanOpenSslPublicKey.cs98
-rw-r--r--src/Common/src/System/Security/Cryptography/ECDiffieHellmanSecurityTransforms.cs289
-rw-r--r--src/Common/src/System/Security/Cryptography/ECDsaCng.ImportExport.cs10
-rw-r--r--src/Common/src/System/Security/Cryptography/ECDsaCng.cs36
-rw-r--r--src/Common/src/System/Security/Cryptography/ECDsaOpenSsl.ImportExport.cs204
-rw-r--r--src/Common/src/System/Security/Cryptography/ECDsaOpenSsl.cs112
-rw-r--r--src/Common/src/System/Security/Cryptography/ECDsaSecurityTransforms.cs384
-rw-r--r--src/Common/src/System/Security/Cryptography/ECOpenSsl.ImportExport.cs191
-rw-r--r--src/Common/src/System/Security/Cryptography/ECOpenSsl.cs139
-rw-r--r--src/Common/src/System/Security/Cryptography/EccSecurityTransforms.cs416
-rw-r--r--src/Common/src/System/Security/Cryptography/RSACng.EncryptDecrypt.cs115
-rw-r--r--src/Common/src/System/Security/Cryptography/RSACng.SignVerify.cs47
-rw-r--r--src/Common/src/System/Security/Cryptography/RSACng.cs4
-rw-r--r--src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs429
-rw-r--r--src/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs364
-rw-r--r--src/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs559
-rw-r--r--src/Common/src/System/Text/ValueStringBuilder.cs200
-rw-r--r--src/Common/src/System/Text/ValueUtf8Converter.cs51
-rw-r--r--src/Common/tests/Common.Tests.csproj39
-rw-r--r--src/Common/tests/Resources/Strings.resx3
-rw-r--r--src/Common/tests/System/Buffers/NativeOwnedMemory.cs10
-rw-r--r--src/Common/tests/System/Collections/TestBase.Generic.cs8
-rw-r--r--src/Common/tests/System/Collections/TestBase.NonGeneric.cs3
-rw-r--r--src/Common/tests/System/IO/Compression/CompressionStreamPerfTestBase.cs43
-rw-r--r--src/Common/tests/System/IO/Compression/CompressionStreamUnitTestBase.cs50
-rw-r--r--src/Common/tests/System/Net/Configuration.Certificates.cs7
-rw-r--r--src/Common/tests/System/Net/Configuration.Http.cs12
-rw-r--r--src/Common/tests/System/Net/Configuration.WebSockets.cs2
-rw-r--r--src/Common/tests/System/Net/Http/LoopbackServer.AuthenticationHelpers.cs305
-rw-r--r--src/Common/tests/System/Net/Http/LoopbackServer.cs496
-rw-r--r--src/Common/tests/System/RandomExtensions.cs23
-rw-r--r--src/Common/tests/System/Runtime/Serialization/Utils.cs (renamed from src/System.Runtime.Serialization.Xml/tests/Utils.cs)0
-rw-r--r--src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/CurveDef.cs6
-rw-r--r--src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/EccTestBase.cs235
-rw-r--r--src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/EccTestData.cs (renamed from src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTestData.cs)6
-rw-r--r--src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanFactory.cs44
-rw-r--r--src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.Hash.cs287
-rw-r--r--src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.Hmac.cs345
-rw-r--r--src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.ImportExport.cs440
-rw-r--r--src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.NistValidation.cs233
-rw-r--r--src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.Tls.cs213
-rw-r--r--src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.Xml.cs21
-rw-r--r--src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.cs158
-rw-r--r--src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaImportExport.cs44
-rw-r--r--src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTests.NistValidation.cs20
-rw-r--r--src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTests.cs12
-rw-r--r--src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTests.netcoreapp.cs7
-rw-r--r--src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTestsBase.cs220
-rw-r--r--src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/EncryptDecrypt.cs312
-rw-r--r--src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/EncryptDecrypt.netcoreapp.cs2
-rw-r--r--src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/RSAFactory.cs10
-rw-r--r--src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs359
-rw-r--r--src/Common/tests/System/Security/Cryptography/ByteUtils.cs2
-rw-r--r--src/Common/tests/System/Threading/Tasks/TaskTimeoutExtensions.cs10
-rw-r--r--src/Common/tests/Tests/System/IO/PathInternal.Tests.cs367
-rw-r--r--src/Common/tests/Tests/System/IO/PathInternal.Unix.Tests.cs54
-rw-r--r--src/Common/tests/Tests/System/IO/PathInternal.Windows.Tests.cs406
-rw-r--r--src/Common/tests/Tests/System/IO/PathInternal_Unix_Tests.cs42
-rw-r--r--src/Common/tests/Tests/System/PasteArgumentsTests.cs45
-rw-r--r--src/Common/tests/Tests/System/Text/ValueStringBuilderTests.cs27
-rw-r--r--src/CoreFx.Private.TestUtilities/dir.props2
-rw-r--r--src/CoreFx.Private.TestUtilities/pkg/CoreFx.Private.TestUtilities.pkgproj11
-rw-r--r--src/CoreFx.Private.TestUtilities/ref/CoreFx.Private.TestUtilities.cs16
-rw-r--r--src/CoreFx.Private.TestUtilities/src/Configurations.props3
-rw-r--r--src/CoreFx.Private.TestUtilities/src/CoreFx.Private.TestUtilities.csproj23
-rw-r--r--src/CoreFx.Private.TestUtilities/src/System/Diagnostics/RemoteExecutorTestBase.Process.cs16
-rw-r--r--src/CoreFx.Private.TestUtilities/src/System/Diagnostics/RemoteExecutorTestBase.cs101
-rw-r--r--src/CoreFx.Private.TestUtilities/src/System/Diagnostics/RemoteExecutorTestBase.uap.cs10
-rw-r--r--src/CoreFx.Private.TestUtilities/src/System/PlatformDetection.NetFx.cs3
-rw-r--r--src/CoreFx.Private.TestUtilities/src/System/PlatformDetection.NonNetFx.cs47
-rw-r--r--src/CoreFx.Private.TestUtilities/src/System/PlatformDetection.Unix.cs45
-rw-r--r--src/CoreFx.Private.TestUtilities/src/System/PlatformDetection.Windows.cs5
-rw-r--r--src/CoreFx.Private.TestUtilities/src/System/PlatformDetection.cs2
-rw-r--r--src/CoreFx.Private.TestUtilities/src/System/TestEnvironment.cs25
-rw-r--r--src/Microsoft.CSharp/Microsoft.CSharp.sln7
-rw-r--r--src/Microsoft.CSharp/pkg/Microsoft.CSharp.pkgproj2
-rw-r--r--src/Microsoft.CSharp/src/Microsoft.CSharp.csproj11
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/BinderHelper.cs37
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpBinaryOperationBinder.cs18
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpConvertBinder.cs18
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpGetIndexBinder.cs13
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpGetMemberBinder.cs13
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpInvokeBinder.cs13
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpInvokeConstructorBinder.cs11
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpInvokeMemberBinder.cs10
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpIsEventBinder.cs11
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpSetIndexBinder.cs14
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpSetMemberBinder.cs14
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpUnaryOperationBinder.cs14
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Error.cs2
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Errors/ErrorCode.cs4
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Errors/ErrorFacts.cs12
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Errors/ErrorHandling.cs15
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Errors/UserStringBuilder.cs298
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ExpressionTreeCallRewriter.cs326
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ICSharpBinder.cs10
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/RuntimeBinder.cs407
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/BinOpArgInfo.cs10
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/BinOpSig.cs6
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Binding/Better.cs92
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Binding/ErrorReporting.cs107
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/BindingContext.cs29
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Conversion.cs196
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Conversions.cs102
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Declarations/AggregateDeclaration.cs37
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/EXPRExtensions.cs11
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ExplicitConversion.cs122
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ExprFactory.cs147
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ExpressionBinder.cs570
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/GlobalSymbolContext.cs36
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/GroupToArgsBinder.cs217
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/GroupToArgsBinderResult.cs6
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ImplicitConversion.cs89
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/MemberLookup.cs234
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/MemberLookupResults.cs12
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/MethodIterator.cs21
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/MethodTypeInferrer.cs343
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Nullable.cs87
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Operators.cs582
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/PredefinedMembers.cs170
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/SemanticChecker.cs87
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/SubstitutionContext.cs87
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/AggregateSymbol.cs31
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/FieldSymbol.cs12
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/MethodSymbol.cs31
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/NamespaceOrAggregateSymbol.cs41
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymFactory.cs71
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/Symbol.cs40
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymbolKind.cs1
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymbolLoader.cs263
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymbolManagerBase.cs304
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymbolMask.cs1
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymbolStore.cs (renamed from src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymbolTable.cs)54
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/BoundAnonymousFunction.cs2
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Cast.cs14
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Concatenate.cs6
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Constant.cs81
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/EXPR.cs11
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/ExprWithArgs.cs8
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/ExprWithType.cs6
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Field.cs6
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/MemberGroup.cs8
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/MethodInfo.cs134
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Property.cs1
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/PropertyInfo.cs59
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/TypeOf.cs2
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Visitors/ExprVisitorBase.cs29
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Visitors/ExpressionTreeRewriter.cs208
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/ZeroInitialize.cs4
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/TypeBind.cs161
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/AggregateType.cs408
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/ArgumentListType.cs9
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/ArrayType.cs54
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/MethodGroupType.cs9
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/NullType.cs12
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/NullableType.cs50
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/ParameterModifierType.cs18
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/PointerType.cs32
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/PredefinedTypes.cs37
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/Type.cs472
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/TypeArray.cs130
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/TypeFactory.cs115
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/TypeManager.cs682
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/TypeParameterType_.cs67
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/TypeTable.cs169
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/VoidType.cs10
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/UnaOpSig.cs4
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/UtilityTypeExtensions.cs45
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/WithType.cs4
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/SpecialNames.cs6
-rw-r--r--src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/SymbolTable.cs352
-rw-r--r--src/Microsoft.CSharp/src/Resources/Strings.de.resx3
-rw-r--r--src/Microsoft.CSharp/src/Resources/Strings.es.resx3
-rw-r--r--src/Microsoft.CSharp/src/Resources/Strings.fr.resx3
-rw-r--r--src/Microsoft.CSharp/src/Resources/Strings.it.resx3
-rw-r--r--src/Microsoft.CSharp/src/Resources/Strings.ja.resx3
-rw-r--r--src/Microsoft.CSharp/src/Resources/Strings.ko.resx3
-rw-r--r--src/Microsoft.CSharp/src/Resources/Strings.resx15
-rw-r--r--src/Microsoft.CSharp/src/Resources/Strings.ru.resx3
-rw-r--r--src/Microsoft.CSharp/src/Resources/Strings.zh-Hans.resx3
-rw-r--r--src/Microsoft.CSharp/src/Resources/Strings.zh-Hant.resx3
-rw-r--r--src/Microsoft.CSharp/tests/AccessTests.cs294
-rw-r--r--src/Microsoft.CSharp/tests/AccessTests.netcoreapp.cs2
-rw-r--r--src/Microsoft.CSharp/tests/BindingErrors.cs133
-rw-r--r--src/Microsoft.CSharp/tests/Microsoft.CSharp.Tests.csproj2
-rw-r--r--src/Microsoft.Diagnostics.Tracing.EventSource.Redist/dir.props4
-rw-r--r--src/Microsoft.Diagnostics.Tracing.EventSource.Redist/pkg/Microsoft.Diagnostics.Tracing.EventSource.Redist.pkgproj1
-rw-r--r--src/Microsoft.VisualBasic/pkg/Microsoft.VisualBasic.pkgproj2
-rw-r--r--src/Microsoft.VisualBasic/src/MatchingRefApiCompatBaseline.netstandard.txt41
-rw-r--r--src/Microsoft.VisualBasic/tests/ConversionsTests.cs87
-rw-r--r--src/Microsoft.VisualBasic/tests/Microsoft.VisualBasic.Tests.csproj3
-rw-r--r--src/Microsoft.Win32.Primitives/src/Microsoft.Win32.Primitives.csproj1
-rw-r--r--src/Microsoft.Win32.Registry/src/Configurations.props4
-rw-r--r--src/Microsoft.Win32.Registry/src/Microsoft.Win32.Registry.csproj15
-rw-r--r--src/Microsoft.Win32.SystemEvents/Microsoft.Win32.SystemEvents.sln50
-rw-r--r--src/Microsoft.Win32.SystemEvents/dir.props (renamed from src/System.Runtime.Intrinsics/dir.props)1
-rw-r--r--src/Microsoft.Win32.SystemEvents/pkg/Microsoft.Win32.SystemEvents.pkgproj11
-rw-r--r--src/Microsoft.Win32.SystemEvents/ref/Configurations.props9
-rw-r--r--src/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.cs117
-rw-r--r--src/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.csproj20
-rw-r--r--src/Microsoft.Win32.SystemEvents/src/Configurations.props14
-rw-r--r--src/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj178
-rw-r--r--src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/PowerModeChangedEventArgs.cs36
-rw-r--r--src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/PowerModeChangedEventHandler.cs12
-rw-r--r--src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/PowerModes.cs32
-rw-r--r--src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionEndReasons.cs26
-rw-r--r--src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionEndedEventArgs.cs36
-rw-r--r--src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionEndedEventHandler.cs12
-rw-r--r--src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionEndingEventArgs.cs52
-rw-r--r--src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionEndingEventHandler.cs12
-rw-r--r--src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionSwitchEventArgs.cs36
-rw-r--r--src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionSwitchEventHandler.cs12
-rw-r--r--src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionSwitchReason.cs61
-rw-r--r--src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs1485
-rw-r--r--src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/TimerElapsedEventArgs.cs36
-rw-r--r--src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/TimerElapsedEventHandler.cs12
-rw-r--r--src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/UserPreferenceCategories.cs110
-rw-r--r--src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/UserPreferenceChangedEventArgs.cs36
-rw-r--r--src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/UserPreferenceChangedEventHandler.cs11
-rw-r--r--src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/UserPreferenceChangingEventArgs.cs36
-rw-r--r--src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/UserPreferenceChangingEventHandler.cs11
-rw-r--r--src/Microsoft.Win32.SystemEvents/src/PinvokeAnalyzerExceptionList.analyzerdata27
-rw-r--r--src/Microsoft.Win32.SystemEvents/src/Resources/Strings.resx (renamed from src/System.Globalization.Extensions/src/Resources/Strings.resx)22
-rw-r--r--src/Microsoft.Win32.SystemEvents/tests/Configurations.props9
-rw-r--r--src/Microsoft.Win32.SystemEvents/tests/GenericEventTests.cs66
-rw-r--r--src/Microsoft.Win32.SystemEvents/tests/Microsoft.Win32.SystemEvents.Tests.csproj43
-rw-r--r--src/Microsoft.Win32.SystemEvents/tests/SystemEvents.CreateTimer.cs170
-rw-r--r--src/Microsoft.Win32.SystemEvents/tests/SystemEvents.DisplaySettings.cs72
-rw-r--r--src/Microsoft.Win32.SystemEvents/tests/SystemEvents.InstalledFontsChanged.cs26
-rw-r--r--src/Microsoft.Win32.SystemEvents/tests/SystemEvents.InvokeOnEventsThread.cs57
-rw-r--r--src/Microsoft.Win32.SystemEvents/tests/SystemEvents.LowMemory.cs28
-rw-r--r--src/Microsoft.Win32.SystemEvents/tests/SystemEvents.PaletteChanged.cs26
-rw-r--r--src/Microsoft.Win32.SystemEvents/tests/SystemEvents.PowerMode.cs80
-rw-r--r--src/Microsoft.Win32.SystemEvents/tests/SystemEvents.SessionEnded.cs74
-rw-r--r--src/Microsoft.Win32.SystemEvents/tests/SystemEvents.SessionEnding.cs74
-rw-r--r--src/Microsoft.Win32.SystemEvents/tests/SystemEvents.SessionSwitch.cs51
-rw-r--r--src/Microsoft.Win32.SystemEvents/tests/SystemEvents.TimeChanged.cs26
-rw-r--r--src/Microsoft.Win32.SystemEvents/tests/SystemEvents.UserPreference.cs327
-rw-r--r--src/Microsoft.Win32.SystemEvents/tests/SystemEventsTest.cs63
-rw-r--r--src/Microsoft.XmlSerializer.Generator/dir.props5
-rw-r--r--src/Microsoft.XmlSerializer.Generator/pkg/build/Microsoft.XmlSerializer.Generator.targets12
-rw-r--r--src/Microsoft.XmlSerializer.Generator/src/Microsoft.XmlSerializer.Generator.csproj2
-rw-r--r--src/Microsoft.XmlSerializer.Generator/src/Sgen.cs216
-rw-r--r--src/Microsoft.XmlSerializer.Generator/tests/Microsoft.XmlSerializer.Generator.Tests.csproj19
-rw-r--r--src/Microsoft.XmlSerializer.Generator/tests/SGenTests.cs2
-rw-r--r--src/Native/Unix/CMakeLists.txt15
-rw-r--r--src/Native/Unix/Common/pal_config.h.in5
-rw-r--r--src/Native/Unix/System.Native/CMakeLists.txt1
-rw-r--r--src/Native/Unix/System.Native/pal_console.cpp211
-rw-r--r--src/Native/Unix/System.Native/pal_console.h53
-rw-r--r--src/Native/Unix/System.Native/pal_networking.c462
-rw-r--r--src/Native/Unix/System.Native/pal_networking.h9
-rw-r--r--src/Native/Unix/System.Native/pal_process.cpp73
-rw-r--r--src/Native/Unix/System.Native/pal_process.h35
-rw-r--r--src/Native/Unix/System.Native/pal_random.cpp73
-rw-r--r--src/Native/Unix/System.Native/pal_signal.c291
-rw-r--r--src/Native/Unix/System.Native/pal_signal.h54
-rw-r--r--src/Native/Unix/System.Native/pal_uid.cpp64
-rw-r--r--src/Native/Unix/System.Native/pal_uid.h9
-rw-r--r--src/Native/Unix/System.Net.Http.Native/pal_easy.cpp5
-rw-r--r--src/Native/Unix/System.Net.Http.Native/pal_easy.h3
-rw-r--r--src/Native/Unix/System.Security.Cryptography.Native.Apple/CMakeLists.txt1
-rw-r--r--src/Native/Unix/System.Security.Cryptography.Native.Apple/pal_keyagree.cpp27
-rw-r--r--src/Native/Unix/System.Security.Cryptography.Native.Apple/pal_keyagree.h17
-rw-r--r--src/Native/Unix/System.Security.Cryptography.Native.Apple/pal_rsa.cpp73
-rw-r--r--src/Native/Unix/System.Security.Cryptography.Native.Apple/pal_rsa.h32
-rw-r--r--src/Native/Unix/System.Security.Cryptography.Native/CMakeLists.txt1
-rw-r--r--src/Native/Unix/System.Security.Cryptography.Native/opensslshim.cpp36
-rw-r--r--src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h16
-rw-r--r--src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_ecdh.cpp64
-rw-r--r--src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_ecdh.h12
-rw-r--r--src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.cpp30
-rw-r--r--src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h19
-rw-r--r--src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.cpp2
-rw-r--r--src/Native/Unix/configure.cmake66
-rw-r--r--src/System.Buffers/pkg/System.Buffers.pkgproj15
-rw-r--r--src/System.Buffers/ref/Configurations.props10
-rw-r--r--src/System.Buffers/ref/System.Buffers.csproj17
-rw-r--r--src/System.Buffers/src/Configurations.props6
-rw-r--r--src/System.Buffers/src/System.Buffers.csproj8
-rw-r--r--src/System.Buffers/src/System/Buffers/ArrayPoolEventSource.cs63
-rw-r--r--src/System.CodeDom/tests/CSharpCodeGenerationTests.cs2260
-rw-r--r--src/System.CodeDom/tests/CodeGenerationTests.cs3
-rw-r--r--src/System.CodeDom/tests/System.CodeDom.Tests.csproj6
-rw-r--r--src/System.CodeDom/tests/VBCodeGenerationTests.cs2326
-rw-r--r--src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.Builder.cs14
-rw-r--r--src/System.Collections.Immutable/src/System/Linq/ImmutableArrayExtensions.cs2
-rw-r--r--src/System.Collections.Specialized/src/MatchingRefApiCompatBaseline.txt2
-rw-r--r--src/System.Collections/ref/System.Collections.cs4
-rw-r--r--src/System.Collections/src/Resources/Strings.resx3
-rw-r--r--src/System.Collections/src/System.Collections.csproj2
-rw-r--r--src/System.Collections/src/System/Collections/Generic/HashSet.cs120
-rw-r--r--src/System.Collections/src/System/Collections/Generic/Queue.cs27
-rw-r--r--src/System.Collections/src/System/Collections/Generic/Stack.cs64
-rw-r--r--src/System.Collections/tests/Generic/Dictionary/Dictionary.Generic.Tests.cs10
-rw-r--r--src/System.Collections/tests/Generic/Dictionary/Dictionary.Generic.Tests.netcoreapp.cs334
-rw-r--r--src/System.Collections/tests/Generic/HashSet/HashSet.Generic.Tests.netcoreapp.cs146
-rw-r--r--src/System.Collections/tests/Generic/List/List.Generic.Tests.Misc.cs103
-rw-r--r--src/System.Collections/tests/System.Collections.Tests.csproj7
-rw-r--r--src/System.ComponentModel.Annotations/pkg/System.ComponentModel.Annotations.pkgproj2
-rw-r--r--src/System.ComponentModel.Annotations/ref/System.ComponentModel.Annotations.cs2
-rw-r--r--src/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/RangeAttribute.cs36
-rw-r--r--src/System.ComponentModel.Annotations/tests/RangeAttributeTests.cs663
-rw-r--r--src/System.ComponentModel.Annotations/tests/ValidatorTests.cs2
-rw-r--r--src/System.ComponentModel.Composition/System.ComponentModel.Composition.sln10
-rw-r--r--src/System.ComponentModel.Composition/dir.props2
-rw-r--r--src/System.ComponentModel.Composition/pkg/System.ComponentModel.Composition.pkgproj6
-rw-r--r--src/System.ComponentModel.Composition/ref/Configurations.props1
-rw-r--r--src/System.ComponentModel.Composition/ref/System.ComponentModel.Composition.cs2
-rw-r--r--src/System.ComponentModel.Composition/src/Configurations.props1
-rw-r--r--src/System.ComponentModel.Composition/src/System.ComponentModel.Composition.csproj3
-rw-r--r--src/System.ComponentModel.Composition/src/System/ComponentModel/Composition/Hosting/AssemblyCatalog.cs11
-rw-r--r--src/System.ComponentModel.Composition/src/System/ComponentModel/Composition/Hosting/CompositionContainer.cs2
-rw-r--r--src/System.ComponentModel.Composition/src/TypeForwards.cs5
-rw-r--r--src/System.ComponentModel.Composition/tests/Configurations.props1
-rw-r--r--src/System.ComponentModel.Composition/tests/System.ComponentModel.Composition.Noop.Assembly/Configurations.props9
-rw-r--r--src/System.ComponentModel.Composition/tests/System.ComponentModel.Composition.Noop.Assembly/System.ComponentModel.Composition.Noop.Assembly.csproj15
-rw-r--r--src/System.ComponentModel.Composition/tests/System.ComponentModel.Composition.Noop.Assembly/TestClass.cs (renamed from src/System.IO.FileSystem/src/System/IO/FindTransform.cs)10
-rw-r--r--src/System.ComponentModel.Composition/tests/System.ComponentModel.Composition.Tests.csproj12
-rw-r--r--src/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/CompositionContainerTests.cs18
-rw-r--r--src/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/CompositionExceptionTests.cs8
-rw-r--r--src/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/Hosting/AssemblyCatalogTests.cs140
-rw-r--r--src/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/Hosting/DirectoryCatalogTests.cs33
-rw-r--r--src/System.ComponentModel.Primitives/src/FxCopBaseline.cs4
-rw-r--r--src/System.ComponentModel.TypeConverter/src/System.ComponentModel.TypeConverter.csproj2
-rw-r--r--src/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesignerOptionService.cs1
-rw-r--r--src/System.ComponentModel.TypeConverter/src/System/ComponentModel/MemberDescriptor.cs10
-rw-r--r--src/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs6
-rw-r--r--src/System.ComponentModel.TypeConverter/src/System/ComponentModel/UInt16Converter.cs2
-rw-r--r--src/System.ComponentModel.TypeConverter/tests/ArrayConverterTests.cs16
-rw-r--r--src/System.ComponentModel.TypeConverter/tests/CollectionConverterTests.cs16
-rw-r--r--src/System.ComponentModel.TypeConverter/tests/CultureInfoConverterTests.cs30
-rw-r--r--src/System.ComponentModel.TypeConverter/tests/DateTimeConverterTests.cs2
-rw-r--r--src/System.ComponentModel.TypeConverter/tests/DateTimeOffsetConverterTests.cs2
-rw-r--r--src/System.ComponentModel.TypeConverter/tests/Design/DesignerOptionServiceTests.cs18
-rw-r--r--src/System.ComponentModel.TypeConverter/tests/MultilineStringConverterTests.cs16
-rw-r--r--src/System.ComponentModel.TypeConverter/tests/ReferenceConverterTests.cs15
-rw-r--r--src/System.ComponentModel.TypeConverter/tests/TypeConverterTests.cs2
-rw-r--r--src/System.ComponentModel.TypeConverter/tests/TypeDescriptorTests.cs19
-rw-r--r--src/System.ComponentModel.TypeConverter/tests/TypeListConverterTests.cs17
-rw-r--r--src/System.ComponentModel.TypeConverter/tests/UInt16ConverterTests.cs7
-rw-r--r--src/System.Composition.Runtime/src/System/Composition/CompositionContext.cs37
-rw-r--r--src/System.Composition.Runtime/tests/CompositionContextTests.cs6
-rw-r--r--src/System.Composition/tests/ConstraintTests.cs40
-rw-r--r--src/System.Configuration.ConfigurationManager/ref/System.Configuration.ConfigurationManager.csproj6
-rw-r--r--src/System.Configuration.ConfigurationManager/ref/System.Configuration.cs6
-rw-r--r--src/System.Configuration.ConfigurationManager/src/ApiCompatBaseline.netfx.txt3
-rw-r--r--src/System.Configuration.ConfigurationManager/src/MatchingRefApiCompatBaseline.netstandard.txt5
-rw-r--r--src/System.Configuration.ConfigurationManager/src/System.Configuration.ConfigurationManager.csproj1
-rw-r--r--src/System.Configuration.ConfigurationManager/src/System/Configuration/ConfigurationSettings.cs2
-rw-r--r--src/System.Configuration.ConfigurationManager/src/System/Configuration/DateTimeConfigurationCollection.cs2
-rw-r--r--src/System.Configuration.ConfigurationManager/src/System/Configuration/Internal/DelegatingConfigHost.cs9
-rw-r--r--src/System.Configuration.ConfigurationManager/src/System/Configuration/Internal/IInternalConfigHost.cs5
-rw-r--r--src/System.Configuration.ConfigurationManager/src/System/Configuration/Internal/IInternalConfigHostPaths.cs2
-rw-r--r--src/System.Configuration.ConfigurationManager/src/System/Configuration/Internal/InternalConfigHost.cs9
-rw-r--r--src/System.Configuration.ConfigurationManager/src/System/Configuration/SectionInformation.cs4
-rw-r--r--src/System.Configuration.ConfigurationManager/src/System/Configuration/SettingValueElement.cs2
-rw-r--r--src/System.Configuration.ConfigurationManager/src/System/Configuration/TypeUtil.cs12
-rw-r--r--src/System.Configuration.ConfigurationManager/tests/System.Configuration.ConfigurationManager.Tests.csproj1
-rw-r--r--src/System.Configuration.ConfigurationManager/tests/System/Configuration/SettingElementTests.cs80
-rw-r--r--src/System.Configuration.ConfigurationManager/tests/System/Configuration/TypeUtilTests.cs6
-rw-r--r--src/System.Console/src/FxCopBaseline.cs6
-rw-r--r--src/System.Console/src/Resources/Strings.resx3
-rw-r--r--src/System.Console/src/System.Console.csproj6
-rw-r--r--src/System.Console/src/System/Console.cs81
-rw-r--r--src/System.Console/src/System/ConsolePal.Unix.cs14
-rw-r--r--src/System.Console/src/System/ConsolePal.Windows.cs4
-rw-r--r--src/System.Console/src/System/TermInfo.cs54
-rw-r--r--src/System.Console/tests/System.Console.Tests.csproj11
-rw-r--r--src/System.Console/tests/TermInfo.cs9
-rw-r--r--src/System.Console/tests/TestData/ncursesFormats/s/screen-256colorbin0 -> 1988 bytes
-rw-r--r--src/System.Console/tests/TestData/ncursesFormats/x/xtermbin0 -> 3617 bytes
-rw-r--r--src/System.Data.Common/ref/System.Data.Common.cs8
-rw-r--r--src/System.Data.Common/ref/System.Data.Common.csproj14
-rw-r--r--src/System.Data.Common/ref/System.Data.Common.netcoreapp.cs22
-rw-r--r--src/System.Data.Common/src/MatchingRefApiCompatBaseline.uapaot.txt2
-rw-r--r--src/System.Data.Common/src/System/Data/Common/NameValuePermission.cs6
-rw-r--r--src/System.Data.Common/src/System/Data/Common/SqlUDTStorage.cs45
-rw-r--r--src/System.Data.Common/src/System/Data/DataTable.cs6
-rw-r--r--src/System.Data.Common/tests/System/Data/DataColumnTest.cs26
-rw-r--r--src/System.Data.Common/tests/System/Data/DataTableReadXmlSchemaTest.cs4
-rw-r--r--src/System.Data.Common/tests/System/Data/DataTableTest.cs20
-rw-r--r--src/System.Data.DataSetExtensions/dir.props2
-rw-r--r--src/System.Data.DataSetExtensions/pkg/System.Data.DataSetExtensions.pkgproj2
-rw-r--r--src/System.Data.DataSetExtensions/src/Configurations.props1
-rw-r--r--src/System.Data.Odbc/pkg/System.Data.Odbc.pkgproj2
-rw-r--r--src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbConnectionClosed.cs156
-rw-r--r--src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbConnectionFactory.cs388
-rw-r--r--src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbConnectionInternal.cs418
-rw-r--r--src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbConnectionPool.cs8
-rw-r--r--src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbConnectionPoolGroup.cs302
-rw-r--r--src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbMetaDataFactory.cs583
-rw-r--r--src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbReferenceCollection.cs282
-rw-r--r--src/System.Data.Odbc/src/MatchingRefApiCompatBaseline.txt6
-rw-r--r--src/System.Data.Odbc/src/Resources/System.Data.Odbc.OdbcMetaData.xml1013
-rw-r--r--src/System.Data.Odbc/src/System.Data.Odbc.csproj33
-rw-r--r--src/System.Data.Odbc/src/System/Data/Odbc/OdbcConnectionFactory.cs32
-rw-r--r--src/System.Data.Odbc/src/System/Data/Odbc/OdbcConnectionHelper.cs16
-rw-r--r--src/System.Data.Odbc/tests/Helpers.cs6
-rw-r--r--src/System.Data.Odbc/tests/OdbcConnectionSchemaTests.cs37
-rw-r--r--src/System.Data.Odbc/tests/System.Data.Odbc.Tests.csproj3
-rw-r--r--src/System.Data.SqlClient/pkg/System.Data.SqlClient.pkgproj4
-rw-r--r--src/System.Data.SqlClient/ref/System.Data.SqlClient.cs27
-rw-r--r--src/System.Data.SqlClient/src/MatchingRefApiCompatBaseline.txt5
-rw-r--r--src/System.Data.SqlClient/src/Microsoft/SqlServer/Server/SqlDataRecord.cs2
-rw-r--r--src/System.Data.SqlClient/src/Resources/Strings.resx107
-rw-r--r--src/System.Data.SqlClient/src/System.Data.SqlClient.csproj30
-rw-r--r--src/System.Data.SqlClient/src/System/Data/Common/AdapterUtil.SqlClient.cs32
-rw-r--r--src/System.Data.SqlClient/src/System/Data/ProviderBase/DbConnectionClosed.cs167
-rw-r--r--src/System.Data.SqlClient/src/System/Data/ProviderBase/DbConnectionFactory.cs418
-rw-r--r--src/System.Data.SqlClient/src/System/Data/ProviderBase/DbConnectionInternal.cs426
-rw-r--r--src/System.Data.SqlClient/src/System/Data/ProviderBase/DbConnectionPool.cs32
-rw-r--r--src/System.Data.SqlClient/src/System/Data/ProviderBase/TimeoutTimer.cs170
-rw-r--r--src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIHandle.cs2
-rw-r--r--src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIMarsConnection.cs5
-rw-r--r--src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIMarsHandle.cs7
-rw-r--r--src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNINpHandle.cs82
-rw-r--r--src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIPacket.cs131
-rw-r--r--src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIProxy.cs38
-rw-r--r--src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNITcpHandle.cs86
-rw-r--r--src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SslOverTdsStream.cs86
-rw-r--r--src/System.Data.SqlClient/src/System/Data/SqlClient/SqlBulkCopy.cs40
-rw-r--r--src/System.Data.SqlClient/src/System/Data/SqlClient/SqlCommand.cs6
-rw-r--r--src/System.Data.SqlClient/src/System/Data/SqlClient/SqlConnection.cs219
-rw-r--r--src/System.Data.SqlClient/src/System/Data/SqlClient/SqlConnectionFactory.cs4
-rw-r--r--src/System.Data.SqlClient/src/System/Data/SqlClient/SqlConnectionPoolKey.cs18
-rw-r--r--src/System.Data.SqlClient/src/System/Data/SqlClient/SqlCredential.cs51
-rw-r--r--src/System.Data.SqlClient/src/System/Data/SqlClient/SqlDependencyListener.cs9
-rw-r--r--src/System.Data.SqlClient/src/System/Data/SqlClient/SqlDependencyUtils.cs6
-rw-r--r--src/System.Data.SqlClient/src/System/Data/SqlClient/SqlInternalConnectionTds.cs72
-rw-r--r--src/System.Data.SqlClient/src/System/Data/SqlClient/SqlParameterCollection.cs3
-rw-r--r--src/System.Data.SqlClient/src/System/Data/SqlClient/SqlUtil.cs16
-rw-r--r--src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParser.cs62
-rw-r--r--src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserHelperClasses.cs4
-rw-r--r--src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserStateObject.cs75
-rw-r--r--src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserStateObjectManaged.cs19
-rw-r--r--src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserStateObjectNative.cs2
-rw-r--r--src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserStaticMethods.cs14
-rw-r--r--src/System.Data.SqlClient/tests/FunctionalTests/DiagnosticTest.cs43
-rw-r--r--src/System.Data.SqlClient/tests/FunctionalTests/SqlConnectionBasicTests.cs89
-rw-r--r--src/System.Data.SqlClient/tests/FunctionalTests/SqlCredentialTest.cs74
-rw-r--r--src/System.Data.SqlClient/tests/FunctionalTests/SqlDataRecordTest.cs256
-rw-r--r--src/System.Data.SqlClient/tests/FunctionalTests/SqlMetaDataTest.cs46
-rw-r--r--src/System.Data.SqlClient/tests/FunctionalTests/System.Data.SqlClient.Tests.csproj6
-rw-r--r--src/System.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs30
-rw-r--r--src/System.Data.SqlClient/tests/ManualTests/SQL/AdapterTest/AdapterTest.cs122
-rw-r--r--src/System.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncTest.cs144
-rw-r--r--src/System.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/BeginExecAsyncTest.cs38
-rw-r--r--src/System.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/XmlReaderAsyncTest.cs66
-rw-r--r--src/System.Data.SqlClient/tests/ManualTests/SQL/CommandCancelTest/CommandCancelTest.cs20
-rw-r--r--src/System.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ExceptionTest.cs17
-rw-r--r--src/System.Data.SqlClient/tests/ManualTests/SQL/IntegratedAuthenticationTest/IntegratedAuthenticationTest.cs8
-rw-r--r--src/System.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/SqlParameterTest_DebugMode.bsl596
-rw-r--r--src/System.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/SqlParameterTest_ReleaseMode.bsl596
-rw-r--r--src/System.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/TvpTest.cs5
-rw-r--r--src/System.Data.SqlClient/tests/ManualTests/SQL/SqlCredentialTest/SqlCredentialTest.cs157
-rw-r--r--src/System.Data.SqlClient/tests/ManualTests/SQL/SqlNotificationTest/SqlNotificationTest.cs16
-rw-r--r--src/System.Data.SqlClient/tests/ManualTests/System.Data.SqlClient.ManualTesting.Tests.csproj2
-rw-r--r--src/System.Diagnostics.Debug/tests/DebugTests.cs12
-rw-r--r--src/System.Diagnostics.DiagnosticSource/pkg/System.Diagnostics.DiagnosticSource.pkgproj4
-rw-r--r--src/System.Diagnostics.DiagnosticSource/ref/Configurations.props3
-rw-r--r--src/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSource.csproj10
-rw-r--r--src/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.DateTime.netfx.cs30
-rw-r--r--src/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs1
-rw-r--r--src/System.Diagnostics.EventLog/pkg/System.Diagnostics.EventLog.pkgproj2
-rw-r--r--src/System.Diagnostics.EventLog/src/System/Diagnostics/EventLog.cs6
-rw-r--r--src/System.Diagnostics.EventLog/src/System/Diagnostics/EventLogInternal.cs6
-rw-r--r--src/System.Diagnostics.EventLog/tests/EventLogTests/EventLogTests.cs9
-rw-r--r--src/System.Diagnostics.PerformanceCounter/pkg/System.Diagnostics.PerformanceCounter.pkgproj2
-rw-r--r--src/System.Diagnostics.PerformanceCounter/src/System.Diagnostics.PerformanceCounter.csproj1
-rw-r--r--src/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PerformanceCounterLib.cs66
-rw-r--r--src/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PrivilegedConfigurationManager.cs9
-rw-r--r--src/System.Diagnostics.Process/System.Diagnostics.Process.sln8
-rw-r--r--src/System.Diagnostics.Process/ref/System.Diagnostics.Process.cs1
-rw-r--r--src/System.Diagnostics.Process/src/FxCopBaseline.cs4
-rw-r--r--src/System.Diagnostics.Process/src/Resources/Strings.resx6
-rw-r--r--src/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj23
-rw-r--r--src/System.Diagnostics.Process/src/System/Diagnostics/AsyncStreamReader.cs2
-rw-r--r--src/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs37
-rw-r--r--src/System.Diagnostics.Process/src/System/Diagnostics/Process.Unix.cs188
-rw-r--r--src/System.Diagnostics.Process/src/System/Diagnostics/Process.Win32.cs16
-rw-r--r--src/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs178
-rw-r--r--src/System.Diagnostics.Process/src/System/Diagnostics/Process.cs18
-rw-r--r--src/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Linux.cs8
-rw-r--r--src/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Windows.cs4
-rw-r--r--src/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.Unix.cs6
-rw-r--r--src/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.Windows.cs7
-rw-r--r--src/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.cs21
-rw-r--r--src/System.Diagnostics.Process/src/System/Diagnostics/ProcessWaitHandle.Unix.cs2
-rw-r--r--src/System.Diagnostics.Process/src/System/Diagnostics/ProcessWaitState.Unix.cs439
-rw-r--r--src/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs33
-rw-r--r--src/System.Diagnostics.Process/tests/ProcessStartInfoTests.netcoreapp.cs74
-rw-r--r--src/System.Diagnostics.Process/tests/ProcessTestBase.NonUap.cs7
-rw-r--r--src/System.Diagnostics.Process/tests/ProcessTestBase.Uap.cs27
-rw-r--r--src/System.Diagnostics.Process/tests/ProcessTestBase.cs14
-rw-r--r--src/System.Diagnostics.Process/tests/ProcessTests.Unix.cs361
-rw-r--r--src/System.Diagnostics.Process/tests/ProcessTests.cs67
-rw-r--r--src/System.Diagnostics.Process/tests/ProcessTests.netcoreapp.cs87
-rw-r--r--src/System.Diagnostics.Process/tests/RemotelyInvokable.cs4
-rw-r--r--src/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csproj17
-rw-r--r--src/System.Diagnostics.StackTrace/tests/StackTraceTests.cs20
-rw-r--r--src/System.Diagnostics.TextWriterTraceListener/src/FxCopBaseline.cs4
-rw-r--r--src/System.Diagnostics.TraceSource/src/FxCopBaseline.cs4
-rw-r--r--src/System.Diagnostics.TraceSource/tests/TraceClassTests.cs13
-rw-r--r--src/System.Diagnostics.TraceSource/tests/TraceEventCacheClassTests.cs2
-rw-r--r--src/System.Diagnostics.Tracing/System.Diagnostics.Tracing.sln8
-rw-r--r--src/System.Diagnostics.Tracing/src/System/Diagnostics/Tracing/EventCounter.cs19
-rw-r--r--src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/FuzzyTests.cs12
-rw-r--r--src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/Harness/EventTestHarness.cs2
-rw-r--r--src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/Harness/Listeners.cs36
-rw-r--r--src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/LoudListener.cs5
-rw-r--r--src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestEventCounter.cs12
-rw-r--r--src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestShutdown.cs9
-rw-r--r--src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestUtilities.cs4
-rw-r--r--src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsManifestNegative.cs6
-rw-r--r--src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsUserErrors.cs44
-rw-r--r--src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWrite.cs60
-rw-r--r--src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWriteEvent.cs116
-rw-r--r--src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWriteEventToListener.cs48
-rw-r--r--src/System.Diagnostics.Tracing/tests/Configurations.props4
-rw-r--r--src/System.Diagnostics.Tracing/tests/CustomEventSources/EventSourceTest.cs5
-rw-r--r--src/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj12
-rw-r--r--src/System.DirectoryServices.AccountManagement/pkg/System.DirectoryServices.AccountManagement.pkgproj2
-rw-r--r--src/System.DirectoryServices.AccountManagement/src/Configurations.props1
-rw-r--r--src/System.DirectoryServices.AccountManagement/src/Resources/Strings.resx5
-rw-r--r--src/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/Principal.cs8
-rw-r--r--src/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/PrincipalSearcher.cs4
-rw-r--r--src/System.DirectoryServices.AccountManagement/tests/ComputerPrincipalTest.cs2
-rw-r--r--src/System.DirectoryServices.AccountManagement/tests/Configurations.props1
-rw-r--r--src/System.DirectoryServices.AccountManagement/tests/System.DirectoryServices.AccountManagement.Tests.csproj8
-rw-r--r--src/System.DirectoryServices.AccountManagement/tests/testobj.cs10
-rw-r--r--src/System.DirectoryServices.Protocols/pkg/System.DirectoryServices.Protocols.pkgproj2
-rw-r--r--src/System.DirectoryServices.Protocols/src/Configurations.props1
-rw-r--r--src/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/BerConverter.cs4
-rw-r--r--src/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/DirectoryControl.cs2
-rw-r--r--src/System.DirectoryServices.Protocols/tests/Configurations.props1
-rw-r--r--src/System.DirectoryServices.Protocols/tests/System.DirectoryServices.Protocols.Tests.csproj3
-rw-r--r--src/System.DirectoryServices/pkg/System.DirectoryServices.pkgproj2
-rw-r--r--src/System.DirectoryServices/src/Configurations.props1
-rw-r--r--src/System.DirectoryServices/src/System/DirectoryServices/DirectorySearcher.cs2
-rw-r--r--src/System.DirectoryServices/src/System/DirectoryServices/DirectorySynchronization.cs2
-rw-r--r--src/System.DirectoryServices/src/System/DirectoryServices/DirectoryVirtualListViewContext.cs4
-rw-r--r--src/System.DirectoryServices/src/System/DirectoryServices/ResultPropertyCollection.cs2
-rw-r--r--src/System.DirectoryServices/src/System/DirectoryServices/SchemaNameCollection.cs5
-rw-r--r--src/System.DirectoryServices/tests/Configurations.props1
-rw-r--r--src/System.DirectoryServices/tests/System.DirectoryServices.Tests.csproj7
-rw-r--r--src/System.DirectoryServices/tests/System/DirectoryServices/ActiveDirectory/ForestTests.cs1
-rw-r--r--src/System.DirectoryServices/tests/System/DirectoryServices/PropertyCollectionTests.cs4
-rw-r--r--src/System.Drawing.Common/pkg/System.Drawing.Common.pkgproj2
-rw-r--r--src/System.Drawing.Common/ref/System.Drawing.Common.cs3
-rw-r--r--src/System.Drawing.Common/src/PinvokeAnalyzerExceptionList.analyzerdata65
-rw-r--r--src/System.Drawing.Common/src/System.Drawing.Common.csproj20
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Bitmap.Unix.cs6
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/BufferedGraphicsManager.Unix.cs6
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/ColorConverter.cs12
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/ColorTranslator.cs2
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Design/IPropertyValueUIService.cs10
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Design/IToolboxItemProvider.cs8
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Design/IToolboxService.cs8
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Design/IToolboxUser.cs8
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Design/PaintValueEventArgs.cs8
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Design/PropertyValueUIHandler.cs8
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Design/PropertyValueUIItem.cs8
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Design/PropertyValueUIItemInvokeHandler.cs8
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Design/ToolboxComponentsCreatedEventArgs.cs8
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Design/ToolboxComponentsCreatedEventHandler.cs8
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Design/ToolboxComponentsCreatingEventArgs.cs8
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Design/ToolboxComponentsCreatingEventHandler.cs8
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Design/ToolboxItem.cs12
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Design/ToolboxItemCollection.cs10
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Design/ToolboxItemCreatorCallback.cs10
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Design/UITypeEditor.cs10
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Design/UITypeEditorEditStyle.cs10
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Drawing2D/AdjustableArrowCap.Unix.cs2
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Drawing2D/CustomLineCap.cs7
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Drawing2D/GraphicsPath.Unix.cs2
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Font.Unix.cs26
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Graphics.Unix.cs4
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Icon.Unix.cs2
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Image.Unix.cs40
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Image.Windows.cs4
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Internal/ISystemEventTracker.cs (renamed from src/System.IO.FileSystem/src/System/IO/FileSystemInfo.Win32.cs)9
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Internal/SystemColorTracker.cs152
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Pen.cs31
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/PointConverter.cs12
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Printing/PrinterSettings.Windows.cs4
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Printing/PrintingPermission.cs220
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Printing/PrintingPermissionAttribute.cs51
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/Printing/PrintingPermissionLevel.cs58
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/RectangleConverter.cs10
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/SizeConverter.cs12
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/SolidBrush.cs33
-rw-r--r--src/System.Drawing.Common/src/System/Drawing/SystemIcons.Unix.cs6
-rw-r--r--src/System.Drawing.Common/tests/BitmapTests.cs2
-rw-r--r--src/System.Drawing.Common/tests/FontFamilyTests.cs2
-rw-r--r--src/System.Drawing.Common/tests/FontTests.cs14
-rw-r--r--src/System.Drawing.Common/tests/Imaging/EncoderParameterTests.cs2
-rw-r--r--src/System.Drawing.Common/tests/Imaging/MetafileTests.cs8
-rw-r--r--src/System.Drawing.Common/tests/Printing/PrintDocumentTests.cs2
-rw-r--r--src/System.Drawing.Common/tests/Printing/PrinterSettingsTests.cs36
-rw-r--r--src/System.Drawing.Primitives/src/PinvokeAnalyzerExceptionList.analyzerdata1
-rw-r--r--src/System.Drawing.Primitives/src/System.Drawing.Primitives.csproj2
-rw-r--r--src/System.Drawing.Primitives/tests/DataContractSerializerTests.cs146
-rw-r--r--src/System.Drawing.Primitives/tests/System.Drawing.Primitives.Tests.csproj3
-rw-r--r--src/System.Globalization.Calendars/tests/CalendarHelpers.cs2
-rw-r--r--src/System.Globalization.Calendars/tests/JapaneseCalendar/JapaneseCalendarEras.cs12
-rw-r--r--src/System.Globalization.Calendars/tests/Misc/MiscCalendars.cs2
-rw-r--r--src/System.Globalization.Extensions/ref/System.Globalization.Extensions.csproj11
-rw-r--r--src/System.Globalization.Extensions/ref/System.Globalization.Extensions.netfx.cs25
-rw-r--r--src/System.Globalization.Extensions/src/ApiCompatBaseline.netfx.txt4
-rw-r--r--src/System.Globalization.Extensions/src/System.Globalization.Extensions.csproj15
-rw-r--r--src/System.Globalization.Extensions/src/System/Globalization/Extensions.cs98
-rw-r--r--src/System.Globalization.Extensions/src/System/StringNormalizationExtensions.netfx.cs29
-rw-r--r--src/System.Globalization/System.Globalization.sln8
-rw-r--r--src/System.Globalization/tests/CharUnicodeInfo/CharUnicodeInfoTestData.cs8
-rw-r--r--src/System.Globalization/tests/CharUnicodeInfo/CharUnicodeInfoTests.cs95
-rw-r--r--src/System.Globalization/tests/Configurations.props1
-rw-r--r--src/System.Globalization/tests/CultureInfo/CultureInfoAll.cs1
-rw-r--r--src/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoTests.cs38
-rw-r--r--src/System.Globalization/tests/Invariant/InvariantMode.cs40
-rw-r--r--src/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoCurrencyNegativePattern.cs2
-rw-r--r--src/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoData.cs6
-rw-r--r--src/System.Globalization/tests/RegionInfo/RegionInfoTests.Properties.cs14
-rw-r--r--src/System.Globalization/tests/System.Globalization.Tests.csproj3
-rw-r--r--src/System.IO.Compression.Brotli/System.IO.Compression.Brotli.sln15
-rw-r--r--src/System.IO.Compression.Brotli/ref/System.IO.Compression.Brotli.cs10
-rw-r--r--src/System.IO.Compression.Brotli/src/System/IO/Compression/dec/BrotliStream.Decompress.cs28
-rw-r--r--src/System.IO.Compression.Brotli/src/System/IO/Compression/enc/BrotliStream.Compress.cs34
-rw-r--r--src/System.IO.Compression.Brotli/tests/CompressionStreamUnitTests.Brotli.cs4
-rw-r--r--src/System.IO.Compression.Brotli/tests/Performance/BrotliPerfTests.cs83
-rw-r--r--src/System.IO.Compression.ZipFile/tests/ZipFileInvalidFileTests.cs1
-rw-r--r--src/System.IO.Compression/System.IO.Compression.sln54
-rw-r--r--src/System.IO.Compression/ref/System.IO.Compression.csproj2
-rw-r--r--src/System.IO.Compression/src/MatchingRefApiCompatBaseline.txt2
-rw-r--r--src/System.IO.Compression/src/System.IO.Compression.csproj5
-rw-r--r--src/System.IO.Compression/src/System/IO/Compression/DeflateZLib/DeflateStream.cs78
-rw-r--r--src/System.IO.Compression/src/System/IO/Compression/DeflateZLib/Deflater.cs2
-rw-r--r--src/System.IO.Compression/src/System/IO/Compression/GZipStream.cs24
-rw-r--r--src/System.IO.Compression/src/System/IO/Compression/PositionPreservingWriteOnlyStreamWrapper.netcoreapp.cs12
-rw-r--r--src/System.IO.Compression/tests/CompressionStreamUnitTests.Deflate.cs2
-rw-r--r--src/System.IO.Compression/tests/CompressionStreamUnitTests.Gzip.cs2
-rw-r--r--src/System.IO.Compression/tests/Performance/System.IO.Compression.Performance.Tests.csproj2
-rw-r--r--src/System.IO.Compression/tests/System.IO.Compression.Tests.csproj6
-rw-r--r--src/System.IO.FileSystem.AccessControl/pkg/System.IO.FileSystem.AccessControl.pkgproj6
-rw-r--r--src/System.IO.FileSystem.AccessControl/src/Configurations.props2
-rw-r--r--src/System.IO.FileSystem.AccessControl/src/System.IO.FileSystem.AccessControl.csproj10
-rw-r--r--src/System.IO.FileSystem.AccessControl/tests/DirectoryObjectSecurityTests.cs187
-rw-r--r--src/System.IO.FileSystem.AccessControl/tests/FileSystemAccessRuleTests.cs5
-rw-r--r--src/System.IO.FileSystem.AccessControl/tests/FileSystemAclExtensionsTests.cs5
-rw-r--r--src/System.IO.FileSystem.AccessControl/tests/FileSystemAuditRuleTests.cs6
-rw-r--r--src/System.IO.FileSystem.AccessControl/tests/FileSystemSecurityTests.cs23
-rw-r--r--src/System.IO.FileSystem.DriveInfo/src/System.IO.FileSystem.DriveInfo.csproj8
-rw-r--r--src/System.IO.FileSystem.DriveInfo/src/System/IO/DriveInfo.Windows.cs4
-rw-r--r--src/System.IO.FileSystem.DriveInfo/tests/DriveInfo.Windows.Tests.cs30
-rw-r--r--src/System.IO.FileSystem.Watcher/src/System.IO.FileSystem.Watcher.csproj7
-rw-r--r--src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.cs31
-rw-r--r--src/System.IO.FileSystem.Watcher/src/System/IO/PatternMatcher.cs505
-rw-r--r--src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.unit.cs18
-rw-r--r--src/System.IO.FileSystem/ref/System.IO.FileSystem.cs93
-rw-r--r--src/System.IO.FileSystem/src/MatchingRefApiCompatBaseline.txt8
-rw-r--r--src/System.IO.FileSystem/src/Microsoft/Win32/SafeHandles/SafeFindHandle.Windows.cs3
-rw-r--r--src/System.IO.FileSystem/src/System.IO.FileSystem.csproj171
-rw-r--r--src/System.IO.FileSystem/src/System/IO/CharSpanExtensions.Unix.cs38
-rw-r--r--src/System.IO.FileSystem/src/System/IO/CharSpanExtensions.Windows.cs44
-rw-r--r--src/System.IO.FileSystem/src/System/IO/CharSpanExtensions.cs24
-rw-r--r--src/System.IO.FileSystem/src/System/IO/Directory.cs333
-rw-r--r--src/System.IO.FileSystem/src/System/IO/DirectoryInfo.Windows.cs18
-rw-r--r--src/System.IO.FileSystem/src/System/IO/DirectoryInfo.cs358
-rw-r--r--src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEntry.Unix.cs152
-rw-r--r--src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEntry.Windows.cs90
-rw-r--r--src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerable.cs69
-rw-r--r--src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerableFactory.cs173
-rw-r--r--src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.Unix.cs224
-rw-r--r--src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.Win32.cs78
-rw-r--r--src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.WinRT.cs (renamed from src/System.IO.FileSystem/src/System/IO/FindEnumerable.WinRT.cs)24
-rw-r--r--src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.Windows.cs234
-rw-r--r--src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.cs89
-rw-r--r--src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemName.cs (renamed from src/System.IO.FileSystem/src/System/IO/DosMatcher.cs)155
-rw-r--r--src/System.IO.FileSystem/src/System/IO/EnumerationOptions.cs99
-rw-r--r--src/System.IO.FileSystem/src/System/IO/File.cs241
-rw-r--r--src/System.IO.FileSystem/src/System/IO/FileInfo.Windows.cs18
-rw-r--r--src/System.IO.FileSystem/src/System/IO/FileInfo.cs171
-rw-r--r--src/System.IO.FileSystem/src/System/IO/FileStatus.Unix.cs277
-rw-r--r--src/System.IO.FileSystem/src/System/IO/FileSystem.Unix.cs278
-rw-r--r--src/System.IO.FileSystem/src/System/IO/FileSystem.Windows.cs146
-rw-r--r--src/System.IO.FileSystem/src/System/IO/FileSystemInfo.Unix.cs327
-rw-r--r--src/System.IO.FileSystem/src/System/IO/FileSystemInfo.Windows.cs31
-rw-r--r--src/System.IO.FileSystem/src/System/IO/FileSystemInfo.cs125
-rw-r--r--src/System.IO.FileSystem/src/System/IO/FindEnumerable.Win32.cs43
-rw-r--r--src/System.IO.FileSystem/src/System/IO/FindEnumerable.Windows.cs251
-rw-r--r--src/System.IO.FileSystem/src/System/IO/FindEnumerableFactory.cs138
-rw-r--r--src/System.IO.FileSystem/src/System/IO/FindPredicate.cs11
-rw-r--r--src/System.IO.FileSystem/src/System/IO/FindPredicates.cs18
-rw-r--r--src/System.IO.FileSystem/src/System/IO/FindTransforms.cs40
-rw-r--r--src/System.IO.FileSystem/src/System/IO/MatchCasing.cs24
-rw-r--r--src/System.IO.FileSystem/src/System/IO/MatchType.cs20
-rw-r--r--src/System.IO.FileSystem/src/System/IO/PathHelpers.Unix.cs21
-rw-r--r--src/System.IO.FileSystem/src/System/IO/PathHelpers.Windows.cs48
-rw-r--r--src/System.IO.FileSystem/src/System/IO/PathHelpers.cs192
-rw-r--r--src/System.IO.FileSystem/src/System/IO/PathPair.cs18
-rw-r--r--src/System.IO.FileSystem/src/System/IO/RawFindData.cs33
-rw-r--r--src/System.IO.FileSystem/tests/Base/BaseGetSetTimes.cs70
-rw-r--r--src/System.IO.FileSystem/tests/Base/FileGetSetAttributes.cs53
-rw-r--r--src/System.IO.FileSystem/tests/Base/StaticGetSetTimes.cs2
-rw-r--r--src/System.IO.FileSystem/tests/Directory/CreateDirectory.cs109
-rw-r--r--src/System.IO.FileSystem/tests/Directory/Delete.cs2
-rw-r--r--src/System.IO.FileSystem/tests/Directory/EnumerableTests.cs11
-rw-r--r--src/System.IO.FileSystem/tests/Directory/GetFileSystemEntries_str.cs122
-rw-r--r--src/System.IO.FileSystem/tests/Directory/GetFileSystemEntries_str_str.cs14
-rw-r--r--src/System.IO.FileSystem/tests/Directory/Move.cs24
-rw-r--r--src/System.IO.FileSystem/tests/DirectoryInfo/CreateSubdirectory.cs42
-rw-r--r--src/System.IO.FileSystem/tests/DirectoryInfo/Exists.cs6
-rw-r--r--src/System.IO.FileSystem/tests/DirectoryInfo/GetSetTimes.cs2
-rw-r--r--src/System.IO.FileSystem/tests/DirectoryInfo/ToString.cs18
-rw-r--r--src/System.IO.FileSystem/tests/Enumeration/AttributeTests.netcoreapp.cs141
-rw-r--r--src/System.IO.FileSystem/tests/Enumeration/ConstructionTests.netcoreapp.cs46
-rw-r--r--src/System.IO.FileSystem/tests/Enumeration/ErrorHandlingTests.netcoreapp.cs71
-rw-r--r--src/System.IO.FileSystem/tests/Enumeration/ExampleTests.netcoreapp.cs141
-rw-r--r--src/System.IO.FileSystem/tests/Enumeration/FileSystemNameTests.netcoreapp.cs154
-rw-r--r--src/System.IO.FileSystem/tests/Enumeration/IncludePredicateTests.netcoreapp.cs55
-rw-r--r--src/System.IO.FileSystem/tests/Enumeration/MatchCasingTests.netcoreapp.cs60
-rw-r--r--src/System.IO.FileSystem/tests/Enumeration/MatchTypesTests.netcoreapp.cs80
-rw-r--r--src/System.IO.FileSystem/tests/Enumeration/PatternTransformTests.netcoreapp.cs126
-rw-r--r--src/System.IO.FileSystem/tests/Enumeration/RootTests.netcoreapp.cs59
-rw-r--r--src/System.IO.FileSystem/tests/Enumeration/SkipAttributeTests.netcoreapp.cs107
-rw-r--r--src/System.IO.FileSystem/tests/Enumeration/SpecialDirectoryTests.netcoreapp.cs76
-rw-r--r--src/System.IO.FileSystem/tests/Enumeration/TrimmedPaths.netcoreapp.cs284
-rw-r--r--src/System.IO.FileSystem/tests/FSAssert.cs7
-rw-r--r--src/System.IO.FileSystem/tests/File/Copy.cs131
-rw-r--r--src/System.IO.FileSystem/tests/File/Create.cs93
-rw-r--r--src/System.IO.FileSystem/tests/File/Delete.cs25
-rw-r--r--src/System.IO.FileSystem/tests/File/Exists.cs2
-rw-r--r--src/System.IO.FileSystem/tests/File/GetSetAttributes.cs14
-rw-r--r--src/System.IO.FileSystem/tests/File/Move.cs111
-rw-r--r--src/System.IO.FileSystem/tests/File/ReadWriteAllBytes.cs53
-rw-r--r--src/System.IO.FileSystem/tests/File/ReadWriteAllBytesAsync.cs52
-rw-r--r--src/System.IO.FileSystem/tests/FileInfo/GetSetTimes.cs2
-rw-r--r--src/System.IO.FileSystem/tests/FileInfo/Open.cs12
-rw-r--r--src/System.IO.FileSystem/tests/FileStream/Dispose.cs92
-rw-r--r--src/System.IO.FileSystem/tests/FileStream/Name.cs14
-rw-r--r--src/System.IO.FileSystem/tests/FileStream/ReadWriteSpan.netcoreapp.cs48
-rw-r--r--src/System.IO.FileSystem/tests/FileStream/WriteAsync.cs35
-rw-r--r--src/System.IO.FileSystem/tests/FileStream/ctor_str_fm.cs106
-rw-r--r--src/System.IO.FileSystem/tests/FileSystemTest.cs2
-rw-r--r--src/System.IO.FileSystem/tests/Performance/Perf.Directory.cs86
-rw-r--r--src/System.IO.FileSystem/tests/Performance/System.IO.FileSystem.Performance.Tests.csproj3
-rw-r--r--src/System.IO.FileSystem/tests/PortedCommon/IOInputs.cs2
-rw-r--r--src/System.IO.FileSystem/tests/System.IO.FileSystem.Tests.csproj19
-rw-r--r--src/System.IO.FileSystem/tests/TestData.cs23
-rw-r--r--src/System.IO.IsolatedStorage/src/System/IO/IsolatedStorage/IsolatedStorage.cs4
-rw-r--r--src/System.IO.IsolatedStorage/src/System/IO/IsolatedStorage/IsolatedStorageFileStream.cs10
-rw-r--r--src/System.IO.MemoryMappedFiles/src/System.IO.MemoryMappedFiles.csproj5
-rw-r--r--src/System.IO.Packaging/pkg/System.IO.Packaging.pkgproj6
-rw-r--r--src/System.IO.Packaging/src/System.IO.Packaging.csproj5
-rw-r--r--src/System.IO.Packaging/src/System/IO/Packaging/PartBasedPackageProperties.cs10
-rw-r--r--src/System.IO.Packaging/tests/Tests.cs38
-rw-r--r--src/System.IO.Pipelines/System.IO.Pipelines.sln50
-rw-r--r--src/System.IO.Pipelines/dir.props8
-rw-r--r--src/System.IO.Pipelines/pkg/System.IO.Pipelines.pkgproj11
-rw-r--r--src/System.IO.Pipelines/ref/Configurations.props12
-rw-r--r--src/System.IO.Pipelines/ref/System.IO.Pipelines.cs80
-rw-r--r--src/System.IO.Pipelines/ref/System.IO.Pipelines.csproj24
-rw-r--r--src/System.IO.Pipelines/src/Configurations.props10
-rw-r--r--src/System.IO.Pipelines/src/Properties/InternalsVisibleTo.cs7
-rw-r--r--src/System.IO.Pipelines/src/Resources/Strings.resx159
-rw-r--r--src/System.IO.Pipelines/src/System.IO.Pipelines.csproj60
-rw-r--r--src/System.IO.Pipelines/src/System/IO/Pipelines/BufferSegment.cs114
-rw-r--r--src/System.IO.Pipelines/src/System/IO/Pipelines/CompletionData.cs24
-rw-r--r--src/System.IO.Pipelines/src/System/IO/Pipelines/FlushResult.cs42
-rw-r--r--src/System.IO.Pipelines/src/System/IO/Pipelines/IDuplexPipe.cs22
-rw-r--r--src/System.IO.Pipelines/src/System/IO/Pipelines/InlineScheduler.cs14
-rw-r--r--src/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.DefaultPipeReader.cs46
-rw-r--r--src/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.DefaultPipeWriter.cs46
-rw-r--r--src/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.cs880
-rw-r--r--src/System.IO.Pipelines/src/System/IO/Pipelines/PipeAwaitable.cs178
-rw-r--r--src/System.IO.Pipelines/src/System/IO/Pipelines/PipeCompletion.cs120
-rw-r--r--src/System.IO.Pipelines/src/System/IO/Pipelines/PipeCompletionCallback.cs12
-rw-r--r--src/System.IO.Pipelines/src/System/IO/Pipelines/PipeCompletionCallbacks.cs64
-rw-r--r--src/System.IO.Pipelines/src/System/IO/Pipelines/PipeOptions.cs93
-rw-r--r--src/System.IO.Pipelines/src/System/IO/Pipelines/PipeReader.cs66
-rw-r--r--src/System.IO.Pipelines/src/System/IO/Pipelines/PipeReaderState.cs59
-rw-r--r--src/System.IO.Pipelines/src/System/IO/Pipelines/PipeScheduler.cs30
-rw-r--r--src/System.IO.Pipelines/src/System/IO/Pipelines/PipeWriter.cs55
-rw-r--r--src/System.IO.Pipelines/src/System/IO/Pipelines/ReadResult.cs50
-rw-r--r--src/System.IO.Pipelines/src/System/IO/Pipelines/ResultFlags.cs14
-rw-r--r--src/System.IO.Pipelines/src/System/IO/Pipelines/ThreadPoolScheduler.netcoreapp.cs17
-rw-r--r--src/System.IO.Pipelines/src/System/IO/Pipelines/ThreadPoolScheduler.netstandard.cs22
-rw-r--r--src/System.IO.Pipelines/src/System/IO/Pipelines/ThreadPoolScheduler.netstandard1.3.cs17
-rw-r--r--src/System.IO.Pipelines/src/System/IO/Pipelines/ThrowHelper.cs74
-rw-r--r--src/System.IO.Pipelines/tests/BackpressureTests.cs173
-rw-r--r--src/System.IO.Pipelines/tests/Configurations.props10
-rw-r--r--src/System.IO.Pipelines/tests/FlushAsyncCancellationTests.cs339
-rw-r--r--src/System.IO.Pipelines/tests/FlushAsyncCompletionTests.cs37
-rw-r--r--src/System.IO.Pipelines/tests/FlushResultTests.cs24
-rw-r--r--src/System.IO.Pipelines/tests/PipeCompletionCallbacksTests.cs487
-rw-r--r--src/System.IO.Pipelines/tests/PipeLengthTests.cs101
-rw-r--r--src/System.IO.Pipelines/tests/PipeOptionsTests.cs23
-rw-r--r--src/System.IO.Pipelines/tests/PipePoolTests.cs239
-rw-r--r--src/System.IO.Pipelines/tests/PipeReaderWriterFacts.cs826
-rw-r--r--src/System.IO.Pipelines/tests/PipeResetTests.cs82
-rw-r--r--src/System.IO.Pipelines/tests/PipeTest.cs38
-rw-r--r--src/System.IO.Pipelines/tests/PipeWriterTests.cs209
-rw-r--r--src/System.IO.Pipelines/tests/ReadAsyncCancellationTests.cs434
-rw-r--r--src/System.IO.Pipelines/tests/ReadAsyncCompletionTests.cs34
-rw-r--r--src/System.IO.Pipelines/tests/ReadResultTests.cs27
-rw-r--r--src/System.IO.Pipelines/tests/SchedulerFacts.cs568
-rw-r--r--src/System.IO.Pipelines/tests/System.IO.Pipelines.Tests.csproj41
-rw-r--r--src/System.IO.Pipelines/tests/TestMemoryPool.cs144
-rw-r--r--src/System.IO.Pipes.AccessControl/System.IO.Pipes.AccessControl.sln8
-rw-r--r--src/System.IO.Pipes.AccessControl/dir.props3
-rw-r--r--src/System.IO.Pipes.AccessControl/pkg/System.IO.Pipes.AccessControl.pkgproj6
-rw-r--r--src/System.IO.Pipes.AccessControl/src/Configurations.props9
-rw-r--r--src/System.IO.Pipes.AccessControl/src/System.IO.Pipes.AccessControl.csproj32
-rw-r--r--src/System.IO.Pipes/ref/System.IO.Pipes.cs1
-rw-r--r--src/System.IO.Pipes/src/MatchingRefApiCompatBaseline.txt6
-rw-r--r--src/System.IO.Pipes/src/Resources/Strings.resx19
-rw-r--r--src/System.IO.Pipes/src/System.IO.Pipes.csproj19
-rw-r--r--src/System.IO.Pipes/src/System/IO/Pipes/AnonymousPipeServerStream.Unix.cs2
-rw-r--r--src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.Unix.cs30
-rw-r--r--src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.Windows.cs30
-rw-r--r--src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.cs7
-rw-r--r--src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeServerStream.Unix.cs35
-rw-r--r--src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeServerStream.Windows.cs55
-rw-r--r--src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeServerStream.cs10
-rw-r--r--src/System.IO.Pipes/src/System/IO/Pipes/PipeAccessRights.cs (renamed from src/System.IO.Pipes.AccessControl/src/System/IO/PipeAccessRights.cs)0
-rw-r--r--src/System.IO.Pipes/src/System/IO/Pipes/PipeAccessRule.cs (renamed from src/System.IO.Pipes.AccessControl/src/System/IO/PipeAccessRule.cs)0
-rw-r--r--src/System.IO.Pipes/src/System/IO/Pipes/PipeAuditRule.cs (renamed from src/System.IO.Pipes.AccessControl/src/System/IO/PipeAuditRule.cs)0
-rw-r--r--src/System.IO.Pipes/src/System/IO/Pipes/PipeCompletionSource.cs2
-rw-r--r--src/System.IO.Pipes/src/System/IO/Pipes/PipeOptions.cs1
-rw-r--r--src/System.IO.Pipes/src/System/IO/Pipes/PipeSecurity.cs (renamed from src/System.IO.Pipes.AccessControl/src/System/IO/PipeSecurity.cs)0
-rw-r--r--src/System.IO.Pipes/src/System/IO/Pipes/PipeStream.Unix.cs37
-rw-r--r--src/System.IO.Pipes/src/System/IO/Pipes/PipeStream.Windows.cs27
-rw-r--r--src/System.IO.Pipes/src/System/IO/Pipes/PipeStream.cs45
-rw-r--r--src/System.IO.Pipes/src/System/IO/Pipes/PipesAclExtensions.cs (renamed from src/System.IO.Pipes.AccessControl/src/System/IO/PipesAclExtensions.cs)0
-rw-r--r--src/System.IO.Pipes/tests/AnonymousPipeTests/AnonymousPipeTest.CrossProcess.cs2
-rw-r--r--src/System.IO.Pipes/tests/AnonymousPipeTests/AnonymousPipeTest.Specific.cs5
-rw-r--r--src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CreateClient.cs4
-rw-r--r--src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CrossProcess.cs4
-rw-r--r--src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CurrentUserOnly.netcoreapp.Unix.cs65
-rw-r--r--src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CurrentUserOnly.netcoreapp.Windows.cs190
-rw-r--r--src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CurrentUserOnly.netcoreapp.cs154
-rw-r--r--src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.RunAsClient.Unix.cs4
-rw-r--r--src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.UnixDomainSockets.cs55
-rw-r--r--src/System.IO.Pipes/tests/PipeTest.Read.netcoreapp.cs4
-rw-r--r--src/System.IO.Pipes/tests/System.IO.Pipes.Tests.csproj20
-rw-r--r--src/System.IO.Ports/pkg/System.IO.Ports.pkgproj4
-rw-r--r--src/System.IO.Ports/src/System.IO.Ports.csproj1
-rw-r--r--src/System.IO/tests/BufferedStream/BufferedStreamTests.netcoreapp.cs2
-rw-r--r--src/System.IO/tests/StringWriter/StringWriterTests.cs25
-rw-r--r--src/System.IO/tests/System.IO.Tests.csproj6
-rw-r--r--src/System.Json/src/System.Json.csproj1
-rw-r--r--src/System.Json/src/System/Json/JsonObject.cs30
-rw-r--r--src/System.Json/src/System/Json/JsonValue.cs7
-rw-r--r--src/System.Json/tests/JsonObjectTests.cs2
-rw-r--r--src/System.Json/tests/JsonValueTests.cs17
-rw-r--r--src/System.Linq.Expressions/src/System.Linq.Expressions.csproj10
-rw-r--r--src/System.Linq.Expressions/src/System/Dynamic/DynamicMetaObject.cs11
-rw-r--r--src/System.Linq.Expressions/src/System/Dynamic/UpdateDelegates.Generated.cs100
-rw-r--r--src/System.Linq.Expressions/src/System/Dynamic/UpdateDelegates.Generated.tt10
-rw-r--r--src/System.Linq.Expressions/src/System/Dynamic/Utils/CollectionExtensions.cs3
-rw-r--r--src/System.Linq.Expressions/src/System/Linq/Expressions/BinaryExpression.cs28
-rw-r--r--src/System.Linq.Expressions/src/System/Runtime/CompilerServices/CallSite.cs30
-rw-r--r--src/System.Linq.Expressions/src/System/Runtime/CompilerServices/RuleCache.cs2
-rw-r--r--src/System.Linq.Expressions/tests/BinaryOperators/Arithmetic/BinaryMultiplyTests.cs82
-rw-r--r--src/System.Linq.Expressions/tests/Dynamic/CallSiteCachingTests.cs126
-rw-r--r--src/System.Linq.Expressions/tests/System.Linq.Expressions.Tests.csproj5
-rw-r--r--src/System.Linq.Expressions/tests/Variables/ParameterTests.cs1
-rw-r--r--src/System.Linq.Parallel/tests/ParallelEnumerableTests.cs1
-rw-r--r--src/System.Linq/src/MatchingRefApiCompatBaseline.txt2
-rw-r--r--src/System.Linq/tests/ConsistencyTests.cs45
-rw-r--r--src/System.Management/pkg/System.Management.pkgproj2
-rw-r--r--src/System.Management/src/Configurations.props1
-rw-r--r--src/System.Management/src/System/Management/ManagementDateTime.cs79
-rw-r--r--src/System.Management/src/System/Management/WMIGenerator.cs2
-rw-r--r--src/System.Management/tests/Configurations.props1
-rw-r--r--src/System.Management/tests/System.Management.Tests.csproj2
-rw-r--r--src/System.Management/tests/System/Management/ManagementDateTimeConverterTests.cs7
-rw-r--r--src/System.Memory/System.Memory.sln8
-rw-r--r--src/System.Memory/pkg/System.Memory.pkgproj6
-rw-r--r--src/System.Memory/ref/Configurations.props6
-rw-r--r--src/System.Memory/ref/System.Memory.cs404
-rw-r--r--src/System.Memory/ref/System.Memory.csproj14
-rw-r--r--src/System.Memory/src/Configurations.props8
-rw-r--r--src/System.Memory/src/Resources/Strings.resx66
-rw-r--r--src/System.Memory/src/System.Memory.csproj62
-rw-r--r--src/System.Memory/src/System/Buffers/ArrayMemoryPool.ArrayMemoryPoolBuffer.cs127
-rw-r--r--src/System.Memory/src/System/Buffers/ArrayMemoryPool.cs30
-rw-r--r--src/System.Memory/src/System/Buffers/Binary/Reader.cs62
-rw-r--r--src/System.Memory/src/System/Buffers/Binary/ReaderBigEndian.cs49
-rw-r--r--src/System.Memory/src/System/Buffers/Binary/ReaderLittleEndian.cs49
-rw-r--r--src/System.Memory/src/System/Buffers/Binary/Writer.cs69
-rw-r--r--src/System.Memory/src/System/Buffers/Binary/WriterBigEndian.cs49
-rw-r--r--src/System.Memory/src/System/Buffers/Binary/WriterLittleEndian.cs49
-rw-r--r--src/System.Memory/src/System/Buffers/BuffersExtensions.cs141
-rw-r--r--src/System.Memory/src/System/Buffers/IBufferWriter.cs28
-rw-r--r--src/System.Memory/src/System/Buffers/MemoryPool.cs50
-rw-r--r--src/System.Memory/src/System/Buffers/ReadOnlySequence.cs454
-rw-r--r--src/System.Memory/src/System/Buffers/ReadOnlySequenceSegment.cs27
-rw-r--r--src/System.Memory/src/System/Buffers/ReadOnlySequence_helpers.cs418
-rw-r--r--src/System.Memory/src/System/Buffers/StandardFormat.cs2
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Base64Decoder.cs30
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Base64Encoder.cs26
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Formatter/FormattingHelpers.cs4
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Boolean.cs18
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.G.cs38
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.L.cs48
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.O.cs42
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.R.cs48
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.cs24
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Decimal.E.cs28
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Decimal.F.cs20
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Decimal.G.cs18
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Decimal.cs14
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Float.cs18
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Guid.cs78
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Signed.D.cs16
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Signed.Default.cs64
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Signed.N.cs16
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Signed.cs14
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Unsigned.D.cs12
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Unsigned.Default.cs60
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Unsigned.N.cs14
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Unsigned.X.cs8
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Unsigned.cs14
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.cs48
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.TimeSpan.cs26
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Boolean.cs26
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.Default.cs20
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.G.cs42
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.O.cs72
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.R.cs62
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.cs30
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Decimal.cs8
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Float.cs42
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Guid.cs50
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Signed.D.cs154
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Signed.N.cs370
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Signed.cs48
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Unsigned.D.cs122
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Unsigned.N.cs320
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Unsigned.X.cs80
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Unsigned.cs48
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Number.cs44
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.TimeSpan.BigG.cs30
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.TimeSpan.C.cs4
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.TimeSpan.LittleG.cs4
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.TimeSpan.cs22
-rw-r--r--src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.TimeSpanSplitter.cs32
-rw-r--r--src/System.Memory/src/System/MemoryExtensions.Fast.cs145
-rw-r--r--src/System.Memory/src/System/MemoryExtensions.Portable.cs409
-rw-r--r--src/System.Memory/src/System/NUint.cs35
-rw-r--r--src/System.Memory/src/System/ReadOnlySpan.Portable.cs (renamed from src/System.Memory/src/System/ReadOnlySpan.cs)178
-rw-r--r--src/System.Memory/src/System/Runtime/InteropServices/MemoryMarshal.Portable.cs145
-rw-r--r--src/System.Memory/src/System/Runtime/InteropServices/SequenceMarshal.cs63
-rw-r--r--src/System.Memory/src/System/SequencePosition.cs61
-rw-r--r--src/System.Memory/src/System/Span.Portable.cs (renamed from src/System.Memory/src/System/Span.cs)182
-rw-r--r--src/System.Memory/src/System/SpanDebugView.cs62
-rw-r--r--src/System.Memory/src/System/SpanHelpers.Clear.cs156
-rw-r--r--src/System.Memory/src/System/SpanHelpers.cs140
-rw-r--r--src/System.Memory/src/System/ThrowHelper.cs94
-rw-r--r--src/System.Memory/tests/Base64/Base64DecoderUnitTests.cs2
-rw-r--r--src/System.Memory/tests/Base64/Base64EncoderUnitTests.cs43
-rw-r--r--src/System.Memory/tests/Binary/BinaryReaderUnitTests.cs84
-rw-r--r--src/System.Memory/tests/Binary/BinaryWriterUnitTests.cs77
-rw-r--r--src/System.Memory/tests/Configurations.props2
-rw-r--r--src/System.Memory/tests/Memory/AsMemory.cs122
-rw-r--r--src/System.Memory/tests/Memory/CtorArray.cs18
-rw-r--r--src/System.Memory/tests/Memory/CustomMemoryForTest.cs42
-rw-r--r--src/System.Memory/tests/Memory/OwnedMemory.cs16
-rw-r--r--src/System.Memory/tests/Memory/Pin.cs133
-rw-r--r--src/System.Memory/tests/Memory/Retain.cs56
-rw-r--r--src/System.Memory/tests/Memory/Strings.cs21
-rw-r--r--src/System.Memory/tests/Memory/ToString.cs130
-rw-r--r--src/System.Memory/tests/Memory/TryGetArray.cs49
-rw-r--r--src/System.Memory/tests/MemoryMarshal/AsBytesReadOnlySpan.cs (renamed from src/System.Memory/tests/ReadOnlySpan/AsBytes.cs)12
-rw-r--r--src/System.Memory/tests/MemoryMarshal/AsBytesSpan.cs (renamed from src/System.Memory/tests/Span/AsBytes.cs)12
-rw-r--r--src/System.Memory/tests/MemoryMarshal/AsMemory.cs34
-rw-r--r--src/System.Memory/tests/MemoryMarshal/CastReadOnlySpan.cs (renamed from src/System.Memory/tests/ReadOnlySpan/NonPortableCast.cs)26
-rw-r--r--src/System.Memory/tests/MemoryMarshal/CastSpan.cs (renamed from src/System.Memory/tests/Span/NonPortableCast.cs)38
-rw-r--r--src/System.Memory/tests/MemoryMarshal/CreateReadOnlySpan.cs (renamed from src/System.Memory/tests/ReadOnlySpan/DangerousCreate.cs)16
-rw-r--r--src/System.Memory/tests/MemoryMarshal/CreateSpan.cs (renamed from src/System.Memory/tests/Span/DangerousCreate.cs)17
-rw-r--r--src/System.Memory/tests/MemoryMarshal/GetReference.cs20
-rw-r--r--src/System.Memory/tests/MemoryMarshal/ToEnumerable.cs90
-rw-r--r--src/System.Memory/tests/MemoryMarshal/TryGetArray.cs39
-rw-r--r--src/System.Memory/tests/MemoryMarshal/TryGetOwnedMemory.cs93
-rw-r--r--src/System.Memory/tests/MemoryMarshal/TryGetString.cs73
-rw-r--r--src/System.Memory/tests/MemoryPool/MemoryPool.cs345
-rw-r--r--src/System.Memory/tests/ParsersAndFormatters/Parser/ParserTests.2gbOverflow.cs9
-rw-r--r--src/System.Memory/tests/ParsersAndFormatters/Parser/ParserTests.cs24
-rw-r--r--src/System.Memory/tests/ParsersAndFormatters/Parser/TestData.Parser.Integer.cs94
-rw-r--r--src/System.Memory/tests/ParsersAndFormatters/Parser/TestData.Parser.TimeSpan.cs3
-rw-r--r--src/System.Memory/tests/ParsersAndFormatters/PseudoDateTime.cs28
-rw-r--r--src/System.Memory/tests/ParsersAndFormatters/StandardFormatTests.cs2
-rw-r--r--src/System.Memory/tests/ParsersAndFormatters/SupportedFormats.cs6
-rw-r--r--src/System.Memory/tests/ParsersAndFormatters/TestData.cs17
-rw-r--r--src/System.Memory/tests/ParsersAndFormatters/TestUtils.cs2
-rw-r--r--src/System.Memory/tests/Performance/Perf.Span.BinaryReadAndWrite.cs5
-rw-r--r--src/System.Memory/tests/Performance/Perf.Span.Clear.cs46
-rw-r--r--src/System.Memory/tests/Performance/Perf.Span.IndexOf.cs5
-rw-r--r--src/System.Memory/tests/Performance/Perf.Span.IndexOfAny.cs11
-rw-r--r--src/System.Memory/tests/ReadOnlyBuffer/BufferSegment.cs26
-rw-r--r--src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.byte.cs150
-rw-r--r--src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.char.cs184
-rw-r--r--src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.cs483
-rw-r--r--src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.TryGet.cs128
-rw-r--r--src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.byte.cs315
-rw-r--r--src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.char.cs318
-rw-r--r--src/System.Memory/tests/ReadOnlyBuffer/SequencePosition.cs38
-rw-r--r--src/System.Memory/tests/ReadOnlyMemory/CtorArray.cs18
-rw-r--r--src/System.Memory/tests/ReadOnlyMemory/Pin.cs133
-rw-r--r--src/System.Memory/tests/ReadOnlyMemory/Retain.cs32
-rw-r--r--src/System.Memory/tests/ReadOnlyMemory/Strings.cs116
-rw-r--r--src/System.Memory/tests/ReadOnlyMemory/ToString.cs128
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/AsReadOnlySpan.cs46
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/CompareTo.cs281
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/Contains.cs181
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/CopyTo.cs31
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/CtorArray.cs18
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/CtorPointerInt.cs14
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/EndsWith.StringComparison.cs347
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/EndsWith.char.cs104
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/EndsWith.long.cs104
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/Equals.cs262
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/IndexOf.byte.cs1
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/IndexOf.charSpan.cs409
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/IndexOfAny.byte.cs1
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/IndexOfSequence.char.cs12
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/IsWhiteSpace.cs113
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/Overlaps.cs37
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.T.cs273
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.bool.cs149
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.byte.cs145
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.char.cs145
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.int.cs145
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.long.cs145
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/SequenceEqual.long.cs104
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/StartsWith.StringComparison.cs355
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/StartsWith.char.cs104
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/StartsWith.long.cs104
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/ToLower.cs310
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/ToString.cs107
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/ToUpper.cs329
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/TrimAnyCharacter.cs169
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/TrimManyCharacters.cs263
-rw-r--r--src/System.Memory/tests/ReadOnlySpan/TrimWhiteSpace.cs169
-rw-r--r--src/System.Memory/tests/Span/AsSpan.cs122
-rw-r--r--src/System.Memory/tests/Span/Clear.cs36
-rw-r--r--src/System.Memory/tests/Span/CopyTo.cs31
-rw-r--r--src/System.Memory/tests/Span/CtorArray.cs18
-rw-r--r--src/System.Memory/tests/Span/CtorPointerInt.cs14
-rw-r--r--src/System.Memory/tests/Span/EndsWith.char.cs104
-rw-r--r--src/System.Memory/tests/Span/EndsWith.long.cs104
-rw-r--r--src/System.Memory/tests/Span/IndexOf.byte.cs1
-rw-r--r--src/System.Memory/tests/Span/IndexOfAny.byte.cs1
-rw-r--r--src/System.Memory/tests/Span/Reverse.cs7
-rw-r--r--src/System.Memory/tests/Span/SequenceCompareTo.T.cs180
-rw-r--r--src/System.Memory/tests/Span/SequenceCompareTo.bool.cs149
-rw-r--r--src/System.Memory/tests/Span/SequenceCompareTo.byte.cs2
-rw-r--r--src/System.Memory/tests/Span/SequenceCompareTo.char.cs145
-rw-r--r--src/System.Memory/tests/Span/SequenceCompareTo.int.cs145
-rw-r--r--src/System.Memory/tests/Span/SequenceCompareTo.long.cs145
-rw-r--r--src/System.Memory/tests/Span/SequenceEqual.long.cs104
-rw-r--r--src/System.Memory/tests/Span/StartsWith.char.cs104
-rw-r--r--src/System.Memory/tests/Span/StartsWith.long.cs104
-rw-r--r--src/System.Memory/tests/Span/ToString.cs95
-rw-r--r--src/System.Memory/tests/System.Memory.Tests.csproj121
-rw-r--r--src/System.Memory/tests/TestHelpers.cs34
-rw-r--r--src/System.Net.Http.WinHttpHandler/src/Resources/Strings.resx3
-rw-r--r--src/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.csproj2
-rw-r--r--src/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.msbuild2
-rw-r--r--src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpAuthHelper.cs17
-rw-r--r--src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpCookieContainerAdapter.cs4
-rw-r--r--src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpException.cs (renamed from src/Common/src/System/Net/Http/WinHttpException.cs)25
-rw-r--r--src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs48
-rw-r--r--src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs45
-rw-r--r--src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestStream.cs2
-rw-r--r--src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseParser.cs10
-rw-r--r--src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseStream.cs8
-rw-r--r--src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpTraceHelper.cs6
-rw-r--r--src/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs21
-rw-r--r--src/System.Net.Http.WinHttpHandler/tests/UnitTests/System.Net.Http.WinHttpHandler.Unit.Tests.csproj6
-rw-r--r--src/System.Net.Http/ref/System.Net.Http.cs28
-rw-r--r--src/System.Net.Http/ref/System.Net.Http.csproj2
-rw-r--r--src/System.Net.Http/src/ILLinkTrim.xml2
-rw-r--r--src/System.Net.Http/src/MatchingRefApiCompatBaseline.uap.txt4
-rw-r--r--src/System.Net.Http/src/Resources/Strings.resx86
-rw-r--r--src/System.Net.Http/src/System.Net.Http.csproj268
-rw-r--r--src/System.Net.Http/src/System/Net/Http/ByteArrayHelpers.cs11
-rw-r--r--src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlException.cs (renamed from src/System.Net.Http/src/System/Net/Http/Unix/CurlException.cs)0
-rw-r--r--src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.ClientCertificateProvider.cs (renamed from src/System.Net.Http/src/System/Net/Http/Unix/CurlHandler.ClientCertificateProvider.cs)0
-rw-r--r--src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.CurlResponseMessage.cs (renamed from src/System.Net.Http/src/System/Net/Http/Unix/CurlHandler.CurlResponseMessage.cs)24
-rw-r--r--src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.EasyRequest.cs (renamed from src/System.Net.Http/src/System/Net/Http/Unix/CurlHandler.EasyRequest.cs)25
-rw-r--r--src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.MultiAgent.cs (renamed from src/System.Net.Http/src/System/Net/Http/Unix/CurlHandler.MultiAgent.cs)6
-rw-r--r--src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.SslProvider.Linux.cs (renamed from src/System.Net.Http/src/System/Net/Http/Unix/CurlHandler.SslProvider.cs)64
-rw-r--r--src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.SslProvider.OSX.cs (renamed from src/System.Net.Http/src/System/Net/Http/OSX/CurlHandler.SslProvider.cs)17
-rw-r--r--src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.cs (renamed from src/System.Net.Http/src/System/Net/Http/Unix/CurlHandler.cs)10
-rw-r--r--src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlResponseHeaderReader.cs (renamed from src/System.Net.Http/src/System/Net/Http/Unix/CurlResponseHeaderReader.cs)0
-rw-r--r--src/System.Net.Http/src/System/Net/Http/DiagnosticsHandler.cs17
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Headers/AuthenticationHeaderValue.cs15
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Headers/HeaderDescriptor.cs5
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Headers/HttpHeaderParser.cs24
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs67
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Headers/KnownHeader.cs27
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Headers/KnownHeaders.cs2
-rw-r--r--src/System.Net.Http/src/System/Net/Http/HttpClient.cs16
-rw-r--r--src/System.Net.Http/src/System/Net/Http/HttpClientHandler.Unix.cs164
-rw-r--r--src/System.Net.Http/src/System/Net/Http/HttpClientHandler.Windows.cs197
-rw-r--r--src/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs44
-rw-r--r--src/System.Net.Http/src/System/Net/Http/HttpClientHandler.netcoreapp.cs24
-rw-r--r--src/System.Net.Http/src/System/Net/Http/HttpContent.cs50
-rw-r--r--src/System.Net.Http/src/System/Net/Http/HttpMethod.cs12
-rw-r--r--src/System.Net.Http/src/System/Net/Http/HttpResponseMessage.cs6
-rw-r--r--src/System.Net.Http/src/System/Net/Http/HttpRuleParser.cs7
-rw-r--r--src/System.Net.Http/src/System/Net/Http/HttpUtilities.cs31
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Managed/AuthenticateAndRedirectHandler.cs228
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Managed/AuthenticationHelper.Basic.cs49
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Managed/ChunkedEncodingReadStream.cs159
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Managed/ChunkedEncodingWriteStream.cs91
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Managed/ConnectHelper.cs100
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Managed/ConnectionCloseReadStream.cs67
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Managed/ContentLengthReadStream.cs88
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Managed/ContentLengthWriteStream.cs52
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Managed/CookieHandler.cs56
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Managed/HttpConnection.cs1198
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionHandler.cs154
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionKey.cs40
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionPools.cs138
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionSettings.cs43
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Managed/HttpContentDuplexStream.cs34
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Managed/HttpContentReadStream.cs60
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Managed/HttpContentStream.cs29
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Managed/HttpContentWriteStream.cs70
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Managed/HttpProxyConnectionHandler.cs196
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Managed/README.md3
-rw-r--r--src/System.Net.Http/src/System/Net/Http/Managed/RawConnectionStream.cs78
-rw-r--r--src/System.Net.Http/src/System/Net/Http/MultipartContent.cs24
-rw-r--r--src/System.Net.Http/src/System/Net/Http/NetEventSource.Http.cs40
-rw-r--r--src/System.Net.Http/src/System/Net/Http/ReadOnlyMemoryContent.cs6
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.Digest.cs (renamed from src/System.Net.Http/src/System/Net/Http/Managed/AuthenticationHelper.Digest.cs)110
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.NtAuth.cs98
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.cs281
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/CancellationHelper.cs46
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ChunkedEncodingReadStream.cs407
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ChunkedEncodingWriteStream.cs57
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs174
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionCloseReadStream.cs129
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ContentLengthReadStream.cs216
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ContentLengthWriteStream.cs36
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/CookieHelper.cs41
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/DecompressionHandler.cs (renamed from src/System.Net.Http/src/System/Net/Http/Managed/DecompressionHandler.cs)21
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/EmptyReadStream.cs (renamed from src/System.Net.Http/src/System/Net/Http/Managed/EmptyReadStream.cs)13
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpAuthenticatedConnectionHandler.cs35
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs1559
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionHandler.cs34
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionKind.cs16
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs (renamed from src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionPool.cs)406
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPoolManager.cs354
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionResponseContent.cs (renamed from src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionContent.cs)40
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionSettings.cs75
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentDuplexStream.cs49
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentReadStream.cs113
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentStream.cs101
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentWriteStream.cs44
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpEnvironmentProxy.cs317
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpSystemProxy.cs186
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RawConnectionStream.cs182
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RedirectHandler.cs150
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs (renamed from src/System.Net.Http/src/System/Net/Http/Managed/ManagedHandler.cs)222
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SystemProxyInfo.Unix.cs16
-rw-r--r--src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SystemProxyInfo.Windows.cs15
-rw-r--r--src/System.Net.Http/src/System/Net/Http/StreamContent.cs19
-rw-r--r--src/System.Net.Http/src/System/Net/Http/StreamToStreamCopy.cs8
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/CancellationTest.cs162
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/DefaultCredentialsTest.cs171
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs175
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/DribbleStream.cs68
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpClient.SelectedSitesTest.cs133
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpClientEKUTest.cs9
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.AcceptAllCerts.cs5
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs492
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Cancellation.cs449
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ClientCertificates.cs135
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Decompression.cs67
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.DefaultProxyCredentials.cs124
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.MaxConnectionsPerServer.cs44
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.MaxResponseHeadersLength.cs124
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ResponseDrain.cs301
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ServerCertificates.Unix.cs69
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ServerCertificates.Windows.cs4
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ServerCertificates.cs95
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.Unix.cs14
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.Windows.cs2
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.cs82
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.cs1358
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpClientMiniStressTest.cs69
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpClientTest.cs25
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpClientTest.netcoreapp.cs4
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpClientTestBase.cs67
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpCookieProtocolTests.cs641
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpProtocolTests.cs620
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpRequestMessageTest.cs2
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/HttpRetryProtocolTests.cs140
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/IdnaProtocolTests.cs133
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/LoopbackGetRequestHttpProxy.cs48
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/ManagedHandlerTest.cs384
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/PlatformHandlerTest.cs159
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/PostScenarioTest.cs21
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/PostScenarioUWPTest.cs32
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/ReadOnlyMemoryContentTest.cs4
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/ResponseStreamTest.cs118
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/SchSendAuxRecordHttpTest.cs4
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/SelectedSitesTest.txt50
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs1420
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/StreamContentTest.cs6
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj34
-rw-r--r--src/System.Net.Http/tests/FunctionalTests/TestHelper.cs48
-rw-r--r--src/System.Net.Http/tests/UnitTests/DigestAuthenticationTests.cs20
-rw-r--r--src/System.Net.Http/tests/UnitTests/HttpEnvironmentProxyTest.cs208
-rw-r--r--src/System.Net.Http/tests/UnitTests/HttpSystemProxyTest.cs44
-rw-r--r--src/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj74
-rw-r--r--src/System.Net.HttpListener/src/System/Net/Managed/HttpListenerResponse.Managed.cs10
-rw-r--r--src/System.Net.HttpListener/src/System/Net/ServiceNameStore.cs4
-rw-r--r--src/System.Net.HttpListener/src/System/Net/Windows/HttpListener.Windows.cs29
-rw-r--r--src/System.Net.HttpListener/src/System/Net/Windows/WebSockets/WebSocketBuffer.cs37
-rw-r--r--src/System.Net.HttpListener/tests/HttpListenerResponseTests.Cookies.cs32
-rw-r--r--src/System.Net.HttpListener/tests/HttpListenerWebSocketTests.cs36
-rw-r--r--src/System.Net.HttpListener/tests/HttpRequestStreamTests.cs70
-rw-r--r--src/System.Net.HttpListener/tests/System.Net.HttpListener.Tests.csproj3
-rw-r--r--src/System.Net.HttpListener/tests/WebSocketTests.cs3
-rw-r--r--src/System.Net.Mail/ref/System.Net.Mime.cs2
-rw-r--r--src/System.Net.Mail/src/System/Net/Mime/MediaTypeNames.cs2
-rw-r--r--src/System.Net.Mail/src/System/Net/Mime/SmtpDateTime.cs6
-rw-r--r--src/System.Net.Mail/tests/Functional/SmtpExceptionTest.cs15
-rw-r--r--src/System.Net.NameResolution/src/MatchingRefApiCompatBaseline.txt4
-rw-r--r--src/System.Net.NameResolution/src/System.Net.NameResolution.csproj40
-rw-r--r--src/System.Net.NameResolution/src/System/Net/DNS.cs236
-rw-r--r--src/System.Net.NameResolution/src/System/Net/DnsResolveAsyncResult.cs26
-rw-r--r--src/System.Net.NameResolution/src/System/Net/NameResolutionPal.Uap.cs11
-rw-r--r--src/System.Net.NameResolution/src/System/Net/NameResolutionPal.Unix.cs101
-rw-r--r--src/System.Net.NameResolution/src/System/Net/NameResolutionPal.Win32.cs24
-rw-r--r--src/System.Net.NameResolution/src/System/Net/NameResolutionPal.Windows.cs289
-rw-r--r--src/System.Net.NameResolution/tests/PalTests/Configurations.props2
-rw-r--r--src/System.Net.NameResolution/tests/PalTests/Fakes/FakeContextAwareResult.cs91
-rw-r--r--src/System.Net.NameResolution/tests/PalTests/NameResolutionPalTests.cs88
-rw-r--r--src/System.Net.NameResolution/tests/PalTests/System.Net.NameResolution.Pal.Tests.csproj49
-rw-r--r--src/System.Net.NameResolution/tests/UnitTests/Fakes/FakeNameResolutionPal.cs7
-rw-r--r--src/System.Net.NameResolution/tests/UnitTests/System.Net.NameResolution.Unit.Tests.csproj3
-rw-r--r--src/System.Net.NetworkInformation/src/System.Net.NetworkInformation.csproj2
-rw-r--r--src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.Linux.cs188
-rw-r--r--src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.OSX.cs135
-rw-r--r--src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.UnknownUnix.cs2
-rw-r--r--src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.Windows.cs295
-rw-r--r--src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.cs41
-rw-r--r--src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/SystemNetworkInterface.cs2
-rw-r--r--src/System.Net.Ping/tests/FunctionalTests/UnixPingUtilityTests.cs65
-rw-r--r--src/System.Net.Primitives/ref/System.Net.Primitives.cs19
-rw-r--r--src/System.Net.Primitives/src/MatchingRefApiCompatBaseline.netcoreapp.txt4
-rw-r--r--src/System.Net.Primitives/src/MatchingRefApiCompatBaseline.uap.txt12
-rw-r--r--src/System.Net.Primitives/src/System.Net.Primitives.csproj1
-rw-r--r--src/System.Net.Primitives/src/System/Net/HttpStatusCode.cs29
-rw-r--r--src/System.Net.Primitives/src/System/Net/IPAddress.cs9
-rw-r--r--src/System.Net.Primitives/src/System/Net/IPAddressParser.cs1
-rw-r--r--src/System.Net.Primitives/tests/FunctionalTests/IPAddressParsingSpan.cs4
-rw-r--r--src/System.Net.Primitives/tests/FunctionalTests/IPAddressSpanTest.cs2
-rw-r--r--src/System.Net.Primitives/tests/UnitTests/CookieInternalTest.cs28
-rw-r--r--src/System.Net.Requests/src/FxCopBaseline.cs4
-rw-r--r--src/System.Net.Requests/src/MatchingRefApiCompatBaseline.txt3
-rw-r--r--src/System.Net.Requests/src/System.Net.Requests.csproj3
-rw-r--r--src/System.Net.Requests/src/System/Net/HttpWebRequest.cs2
-rw-r--r--src/System.Net.Requests/src/System/Net/WebException.cs24
-rw-r--r--src/System.Net.Requests/src/System/Net/WebExceptionPal.Unix.cs2
-rw-r--r--src/System.Net.Requests/src/System/Net/WebExceptionPal.Windows.cs2
-rw-r--r--src/System.Net.Requests/tests/HttpWebRequestTest.cs36
-rw-r--r--src/System.Net.Requests/tests/HttpWebResponseHeaderTest.cs30
-rw-r--r--src/System.Net.Requests/tests/HttpWebResponseTest.cs15
-rw-r--r--src/System.Net.Requests/tests/System.Net.Requests.Tests.csproj3
-rw-r--r--src/System.Net.Security/ref/System.Net.Security.cs2
-rw-r--r--src/System.Net.Security/src/Resources/Strings.resx2
-rw-r--r--src/System.Net.Security/src/System.Net.Security.csproj1
-rw-r--r--src/System.Net.Security/src/System/Net/FixedSizeReader.cs2
-rw-r--r--src/System.Net.Security/src/System/Net/Security/NetEventSource.Security.cs76
-rw-r--r--src/System.Net.Security/src/System/Net/Security/Pal.OSX/SafeDeleteSslContext.cs4
-rw-r--r--src/System.Net.Security/src/System/Net/Security/SecureChannel.cs26
-rw-r--r--src/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs6
-rw-r--r--src/System.Net.Security/src/System/Net/Security/SslClientAuthenticationOptions.cs3
-rw-r--r--src/System.Net.Security/src/System/Net/Security/SslState.cs97
-rw-r--r--src/System.Net.Security/src/System/Net/Security/SslStream.cs20
-rw-r--r--src/System.Net.Security/src/System/Net/Security/SslStreamInternal.Adapters.cs8
-rw-r--r--src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs68
-rw-r--r--src/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs6
-rw-r--r--src/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs4
-rw-r--r--src/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs4
-rw-r--r--src/System.Net.Security/src/System/Net/Security/StreamSizes.OSX.cs9
-rw-r--r--src/System.Net.Security/src/System/Net/Security/StreamSizes.Unix.cs9
-rw-r--r--src/System.Net.Security/src/System/Net/Security/StreamSizes.Windows.cs2
-rw-r--r--src/System.Net.Security/src/System/Net/Security/StreamSizes.cs2
-rw-r--r--src/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs11
-rw-r--r--src/System.Net.Security/tests/FunctionalTests/NegotiateStreamStreamToStreamTest.cs2
-rw-r--r--src/System.Net.Security/tests/FunctionalTests/SslAuthenticationOptionsTest.cs108
-rw-r--r--src/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs46
-rw-r--r--src/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj4
-rw-r--r--src/System.Net.Security/tests/UnitTests/Fakes/FakeAuthenticatedStream.cs2
-rw-r--r--src/System.Net.Security/tests/UnitTests/Fakes/FakeSslState.cs4
-rw-r--r--src/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj3
-rw-r--r--src/System.Net.ServicePoint/src/System/Net/ServicePointManager.cs25
-rw-r--r--src/System.Net.ServicePoint/tests/ServicePointManagerTest.cs38
-rw-r--r--src/System.Net.ServicePoint/tests/TlsSystemDefault.cs4
-rw-r--r--src/System.Net.Sockets/src/Resources/Strings.resx6
-rw-r--r--src/System.Net.Sockets/src/System.Net.Sockets.csproj3
-rw-r--r--src/System.Net.Sockets/src/System/Net/Sockets/NetEventSource.Sockets.cs3
-rw-r--r--src/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs238
-rw-r--r--src/System.Net.Sockets/src/System/Net/Sockets/Socket.Tasks.cs500
-rw-r--r--src/System.Net.Sockets/src/System/Net/Sockets/Socket.Windows.cs13
-rw-r--r--src/System.Net.Sockets/src/System/Net/Sockets/Socket.cs55
-rw-r--r--src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Unix.cs87
-rw-r--r--src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs298
-rw-r--r--src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs20
-rw-r--r--src/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs22
-rw-r--r--src/System.Net.Sockets/src/System/Net/Sockets/SocketTaskExtensions.cs4
-rw-r--r--src/System.Net.Sockets/src/System/Net/Sockets/TCPListener.cs14
-rw-r--r--src/System.Net.Sockets/src/System/Net/Sockets/UDPClient.cs2
-rw-r--r--src/System.Net.Sockets/src/System/Net/Sockets/UnixDomainSocketEndPoint.Unix.cs112
-rw-r--r--src/System.Net.Sockets/src/System/Net/Sockets/UnixDomainSocketEndPoint.Windows.cs21
-rw-r--r--src/System.Net.Sockets/src/System/Net/Sockets/UnixDomainSocketEndPoint.cs140
-rw-r--r--src/System.Net.Sockets/tests/FunctionalTests/Accept.cs24
-rw-r--r--src/System.Net.Sockets/tests/FunctionalTests/Connect.cs2
-rw-r--r--src/System.Net.Sockets/tests/FunctionalTests/ExecutionContextFlowTest.cs501
-rw-r--r--src/System.Net.Sockets/tests/FunctionalTests/ExecutionContextFlowTest.netcoreapp.cs89
-rw-r--r--src/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.cs15
-rw-r--r--src/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.netcoreapp.cs327
-rw-r--r--src/System.Net.Sockets/tests/FunctionalTests/OSSupport.cs74
-rw-r--r--src/System.Net.Sockets/tests/FunctionalTests/SendPacketsAsync.cs3
-rw-r--r--src/System.Net.Sockets/tests/FunctionalTests/SendReceive.netcoreapp.cs50
-rw-r--r--src/System.Net.Sockets/tests/FunctionalTests/SocketAsyncEventArgsTest.netcoreapp.cs5
-rw-r--r--src/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj6
-rw-r--r--src/System.Net.Sockets/tests/FunctionalTests/TcpListenerTest.cs18
-rw-r--r--src/System.Net.Sockets/tests/FunctionalTests/UnixDomainSocketTest.cs30
-rw-r--r--src/System.Net.Sockets/tests/FunctionalTests/UnixDomainSocketTest.netcoreapp.cs96
-rw-r--r--src/System.Net.Sockets/tests/ManualPerformanceTests/System.Net.Sockets.Async.Performance.Tests.csproj5
-rw-r--r--src/System.Net.Sockets/tests/Performance/Perf.Socket.SendReceive.cs34
-rw-r--r--src/System.Net.Sockets/tests/Performance/System.Net.Sockets.Performance.Tests.csproj3
-rw-r--r--src/System.Net.WebClient/src/System/Net/WebClient.cs19
-rw-r--r--src/System.Net.WebClient/tests/System.Net.WebClient.Tests.csproj5
-rw-r--r--src/System.Net.WebClient/tests/WebClientTest.cs75
-rw-r--r--src/System.Net.WebSockets.Client/ref/System.Net.WebSockets.Client.cs1
-rw-r--r--src/System.Net.WebSockets.Client/ref/System.Net.WebSockets.Client.csproj1
-rw-r--r--src/System.Net.WebSockets.Client/src/Resources/Strings.resx3
-rw-r--r--src/System.Net.WebSockets.Client/src/System.Net.WebSockets.Client.csproj81
-rw-r--r--src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ClientWebSocket.cs13
-rw-r--r--src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ClientWebSocketOptions.cs12
-rw-r--r--src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Managed.cs215
-rw-r--r--src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Win32.cs64
-rw-r--r--src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.WinRT.cs5
-rw-r--r--src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Windows.cs2
-rw-r--r--src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketMessageTypeAdapter.cs69
-rw-r--r--src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WinHttpWebSocket.cs865
-rw-r--r--src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WinHttpWebSocketCallback.cs376
-rw-r--r--src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WinHttpWebSocketState.cs286
-rw-r--r--src/System.Net.WebSockets.Client/tests/ClientWebSocketOptionsTests.Unix.cs36
-rw-r--r--src/System.Net.WebSockets.Client/tests/ClientWebSocketOptionsTests.Windows.cs20
-rw-r--r--src/System.Net.WebSockets.Client/tests/ClientWebSocketOptionsTests.cs128
-rw-r--r--src/System.Net.WebSockets.Client/tests/ClientWebSocketOptionsTests.netcoreapp.cs136
-rw-r--r--src/System.Net.WebSockets.Client/tests/ClientWebSocketUnitTest.cs62
-rw-r--r--src/System.Net.WebSockets.Client/tests/LoopbackHelper.cs59
-rw-r--r--src/System.Net.WebSockets.Client/tests/SendReceiveTest.cs124
-rw-r--r--src/System.Net.WebSockets.Client/tests/SendReceiveTest.netcoreapp.cs7
-rw-r--r--src/System.Net.WebSockets.Client/tests/System.Net.WebSockets.Client.Tests.csproj10
-rw-r--r--src/System.Net.WebSockets.Client/tests/WebSocketHelper.cs58
-rw-r--r--src/System.Net.WebSockets.WebSocketProtocol/System.Net.WebSockets.WebSocketProtocol.sln65
-rw-r--r--src/System.Net.WebSockets.WebSocketProtocol/pkg/System.Net.WebSockets.WebSocketProtocol.pkgproj2
-rw-r--r--src/System.Net.WebSockets.WebSocketProtocol/ref/System.Net.WebSockets.WebSocketProtocol.csproj5
-rw-r--r--src/System.Net.WebSockets.WebSocketProtocol/src/System.Net.WebSockets.WebSocketProtocol.csproj1
-rw-r--r--src/System.Net.WebSockets.WebSocketProtocol/src/System/Net/WebSockets/ManagedWebSocketExtensions.cs34
-rw-r--r--src/System.Net.WebSockets.WebSocketProtocol/tests/System.Net.WebSockets.WebSocketProtocol.Tests.csproj4
-rw-r--r--src/System.Net.WebSockets.WebSocketProtocol/tests/WebSocketProtocolTests.cs106
-rw-r--r--src/System.Net.WebSockets/ref/System.Net.WebSockets.cs2
-rw-r--r--src/System.Net.WebSockets/src/System.Net.WebSockets.csproj1
-rw-r--r--src/System.Net.WebSockets/src/System/Net/WebSockets/ManagedWebSocket.netcoreapp.cs7
-rw-r--r--src/System.Net.WebSockets/src/System/Net/WebSockets/WebSocket.cs8
-rw-r--r--src/System.Numerics.Vectors/System.Numerics.Vectors.sln8
-rw-r--r--src/System.Numerics.Vectors/pkg/System.Numerics.Vectors.pkgproj11
-rw-r--r--src/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs3
-rw-r--r--src/System.Numerics.Vectors/ref/System.Numerics.Vectors.csproj9
-rw-r--r--src/System.Numerics.Vectors/src/ApiCompatBaseline.uapaot.txt1
-rw-r--r--src/System.Numerics.Vectors/src/Configurations.props6
-rw-r--r--src/System.Numerics.Vectors/src/Resources/Strings.resx3
-rw-r--r--src/System.Numerics.Vectors/src/System.Numerics.Vectors.csproj60
-rw-r--r--src/System.Numerics.Vectors/src/System/Numerics/JitIntrinsicAttribute.cs14
-rw-r--r--src/System.Numerics.Vectors/src/System/Numerics/Vector2_Intrinsics.cs34
-rw-r--r--src/System.Numerics.Vectors/src/System/Numerics/Vector3_Intrinsics.cs40
-rw-r--r--src/System.Numerics.Vectors/src/System/Numerics/Vector4_Intrinsics.cs41
-rw-r--r--src/System.Numerics.Vectors/tests/GenericVectorTests.cs8
-rw-r--r--src/System.Numerics.Vectors/tests/GenericVectorTests.netcoreapp.cs226
-rw-r--r--src/System.Numerics.Vectors/tests/GenericVectorTests.netcoreapp.tt174
-rw-r--r--src/System.Numerics.Vectors/tests/GenericVectorTests.tt12
-rw-r--r--src/System.Numerics.Vectors/tests/Performance/Constructor/GenericVectorConstructorTests.cs352
-rw-r--r--src/System.Numerics.Vectors/tests/Performance/Constructor/GenericVectorConstructorTests.tt119
-rw-r--r--src/System.Numerics.Vectors/tests/Performance/System.Numerics.Vectors.Performance.Tests.csproj25
-rw-r--r--src/System.Numerics.Vectors/tests/QuaternionTests.cs114
-rw-r--r--src/System.Numerics.Vectors/tests/System.Numerics.Vectors.Tests.csproj23
-rw-r--r--src/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SurrogateDataContract.cs7
-rw-r--r--src/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlReaderDelegator.cs2
-rw-r--r--src/System.Private.DataContractSerialization/src/System/Xml/XmlDictionaryReader.cs5
-rw-r--r--src/System.Private.Reflection.Metadata.Ecma335/src/Resources/Strings.resx9
-rw-r--r--src/System.Private.Reflection.Metadata.Ecma335/src/System.Private.Reflection.Metadata.Ecma335.csproj1
-rw-r--r--src/System.Private.Uri/src/FxCopBaseline.cs4
-rw-r--r--src/System.Private.Uri/src/System.Private.Uri.csproj3
-rw-r--r--src/System.Private.Uri/src/System/IPv4AddressHelper.cs15
-rw-r--r--src/System.Private.Uri/src/System/Uri.cs38
-rw-r--r--src/System.Private.Uri/tests/FunctionalTests/IriTest.cs27
-rw-r--r--src/System.Private.Xml.Linq/src/System/Xml/Linq/XContainer.cs28
-rw-r--r--src/System.Private.Xml.Linq/tests/misc/System.Xml.Linq.Misc.Tests.csproj1
-rw-r--r--src/System.Private.Xml.Linq/tests/misc/XAttribute.cs22
-rw-r--r--src/System.Private.Xml.Linq/tests/xNodeBuilder/CommonTests.cs26
-rw-r--r--src/System.Private.Xml/src/Resources/Strings.resx30
-rw-r--r--src/System.Private.Xml/src/System/Xml/Core/XmlEncodedRawTextWriter.cs6
-rw-r--r--src/System.Private.Xml/src/System/Xml/NameTable.cs7
-rw-r--r--src/System.Private.Xml/src/System/Xml/Serialization/SchemaImporter.cs2
-rw-r--r--src/System.Private.Xml/src/System/Xml/Serialization/SoapReflectionImporter.cs4
-rw-r--r--src/System.Private.Xml/src/System/Xml/Serialization/Types.cs2
-rw-r--r--src/System.Private.Xml/src/System/Xml/Serialization/XmlSchemaImporter.cs8
-rw-r--r--src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReader.cs8
-rw-r--r--src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationWriter.cs29
-rw-r--r--src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializer.cs6
-rw-r--r--src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializerFactory.cs4
-rw-r--r--src/System.Private.Xml/src/System/Xml/Xsl/XsltOld/DbgCompiler.cs2
-rw-r--r--src/System.Private.Xml/src/System/Xml/Xsl/XsltOld/UseAttributeSetsAction.cs4
-rw-r--r--src/System.Private.Xml/tests/Misc/System.Xml.Misc.Tests.csproj1
-rw-r--r--src/System.Private.Xml/tests/Misc/XmlUrlResolverTests.cs77
-rw-r--r--src/System.Private.Xml/tests/Writers/XmlWriterApi/TCFullEndElement.cs4
-rw-r--r--src/System.Private.Xml/tests/XmlReader/XmlResolver/XmlSystemPathResolverTests.cs1
-rw-r--r--src/System.Private.Xml/tests/XmlSchema/XmlSchemaSet/TC_SchemaSet_Reprocess.cs14
-rw-r--r--src/System.Private.Xml/tests/XmlSerializer/Performance/System.Xml.XmlSerializer.Performance.Tests.csproj4
-rw-r--r--src/System.Private.Xml/tests/XmlSerializer/ReflectionOnly/System.Xml.XmlSerializer.ReflectionOnly.Tests.csproj2
-rw-r--r--src/System.Private.Xml/tests/XmlSerializer/System.Xml.XmlSerializer.Tests.csproj2
-rw-r--r--src/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.cs105
-rw-r--r--src/System.Private.Xml/tests/XmlWriter/WriteWithEncoding.cs35
-rw-r--r--src/System.Private.Xml/tests/Xslt/XslCompiledTransformApi/XslCompiledTransform.cs4
-rw-r--r--src/System.Private.Xml/tests/Xslt/XslCompiledTransformApi/XsltApiV2.cs2
-rw-r--r--src/System.Private.Xml/tests/Xslt/XslCompiledTransformApi/XsltSettings.cs10
-rw-r--r--src/System.Private.Xml/tests/Xslt/XslTransformApi/CXslTransform.cs4
-rw-r--r--src/System.Private.Xml/tests/Xslt/XslTransformApi/XSLTransform.cs2
-rw-r--r--src/System.Reflection.DispatchProxy/ref/Configurations.props4
-rw-r--r--src/System.Reflection.DispatchProxy/ref/System.Reflection.DispatchProxy.csproj12
-rw-r--r--src/System.Reflection.DispatchProxy/src/Configurations.props6
-rw-r--r--src/System.Reflection.DispatchProxy/src/System.Reflection.DispatchProxy.csproj10
-rw-r--r--src/System.Reflection.Emit.ILGeneration/ref/System.Reflection.Emit.ILGeneration.cs1
-rw-r--r--src/System.Reflection.Emit.ILGeneration/ref/System.Reflection.Emit.ILGeneration.csproj1
-rw-r--r--src/System.Reflection.Emit.ILGeneration/tests/ILGenerator/Emit4Tests.cs147
-rw-r--r--src/System.Reflection.Emit.ILGeneration/tests/System.Reflection.Emit.ILGeneration.Tests.csproj1
-rw-r--r--src/System.Reflection.Metadata/pkg/System.Reflection.Metadata.pkgproj8
-rw-r--r--src/System.Reflection.Metadata/ref/System.Reflection.Metadata.cs70
-rw-r--r--src/System.Reflection.Metadata/specs/PE-COFF.md48
-rw-r--r--src/System.Reflection.Metadata/src/Resources/Strings.resx6
-rw-r--r--src/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj1
-rw-r--r--src/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/PathUtilities.cs2
-rw-r--r--src/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/Encoding/ControlFlowBuilder.cs36
-rw-r--r--src/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/Encoding/MethodBodyAttributes.cs10
-rw-r--r--src/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/Encoding/MethodBodyStreamEncoder.cs95
-rw-r--r--src/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataReaderExtensions.cs2
-rw-r--r--src/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.cs67
-rw-r--r--src/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReaderProvider.cs4
-rw-r--r--src/System.Reflection.Metadata/src/System/Reflection/Metadata/PEReaderExtensions.cs4
-rw-r--r--src/System.Reflection.Metadata/src/System/Reflection/Metadata/PortablePdb/DebugMetadataHeader.cs9
-rw-r--r--src/System.Reflection.Metadata/src/System/Reflection/Metadata/TypeSystem/TypeDefinition.cs5
-rw-r--r--src/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/DebugDirectory/DebugDirectoryBuilder.EmbeddedPortablePdb.cs2
-rw-r--r--src/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/DebugDirectory/DebugDirectoryBuilder.cs96
-rw-r--r--src/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/DebugDirectory/DebugDirectoryEntryType.cs19
-rw-r--r--src/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/DebugDirectory/PdbChecksumDebugDirectoryData.cs31
-rw-r--r--src/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEReader.cs37
-rw-r--r--src/System.Reflection.Metadata/src/System/Reflection/Throw.cs6
-rw-r--r--src/System.Reflection.Metadata/tests/Metadata/Ecma335/Encoding/ControlFlowBuilderTests.cs161
-rw-r--r--src/System.Reflection.Metadata/tests/Metadata/Ecma335/Encoding/MethodBodyStreamEncoderTests.cs113
-rw-r--r--src/System.Reflection.Metadata/tests/Metadata/MetadataReaderProviderTests.cs16
-rw-r--r--src/System.Reflection.Metadata/tests/Metadata/MetadataReaderTests.cs234
-rw-r--r--src/System.Reflection.Metadata/tests/Metadata/PortablePdb/StandalonePortablePdbStreamTests.cs2
-rw-r--r--src/System.Reflection.Metadata/tests/Metadata/TypeSystem/TypeDefinitionTests.cs37
-rw-r--r--src/System.Reflection.Metadata/tests/PortableExecutable/DebugDirectoryBuilderTests.cs100
-rw-r--r--src/System.Reflection.Metadata/tests/PortableExecutable/DebugDirectoryTests.cs51
-rw-r--r--src/System.Reflection.Metadata/tests/PortableExecutable/PEReaderTests.cs17
-rw-r--r--src/System.Reflection.Metadata/tests/System.Reflection.Metadata.Tests.csproj1
-rw-r--r--src/System.Reflection.TypeExtensions/pkg/System.Reflection.TypeExtensions.pkgproj4
-rw-r--r--src/System.Reflection/ref/System.Reflection.Manual.cs17
-rw-r--r--src/System.Reflection/ref/System.Reflection.csproj1
-rw-r--r--src/System.Runtime.Caching/System.Runtime.Caching.sln102
-rw-r--r--src/System.Runtime.Caching/pkg/System.Runtime.Caching.pkgproj2
-rw-r--r--src/System.Runtime.Caching/src/Configurations.props2
-rw-r--r--src/System.Runtime.Caching/src/MatchingRefApiCompatBaseline.txt6
-rw-r--r--src/System.Runtime.Caching/src/Resources/Strings.resx3
-rw-r--r--src/System.Runtime.Caching/src/System.Runtime.Caching.csproj16
-rw-r--r--src/System.Runtime.Caching/src/System/Runtime/Caching/Dbg.cs95
-rw-r--r--src/System.Runtime.Caching/src/System/Runtime/Caching/MemoryCacheStatistics.cs4
-rw-r--r--src/System.Runtime.Caching/src/System/Runtime/Caching/MemoryMonitor.Windows.cs26
-rw-r--r--src/System.Runtime.Caching/src/System/Runtime/Caching/MemoryMonitor.cs21
-rw-r--r--src/System.Runtime.Caching/src/System/Runtime/Caching/PhysicalMemoryMonitor.Unix.cs16
-rw-r--r--src/System.Runtime.Caching/src/System/Runtime/Caching/PhysicalMemoryMonitor.Windows.cs27
-rw-r--r--src/System.Runtime.Caching/src/System/Runtime/Caching/PhysicalMemoryMonitor.cs16
-rw-r--r--src/System.Runtime.Caching/tests/System.Runtime.Caching/MemoryCacheTest.cs45
-rw-r--r--src/System.Runtime.CompilerServices.Unsafe/pkg/System.Runtime.CompilerServices.Unsafe.pkgproj4
-rw-r--r--src/System.Runtime.CompilerServices.Unsafe/ref/System.Runtime.CompilerServices.Unsafe.cs2
-rw-r--r--src/System.Runtime.CompilerServices.Unsafe/src/Configurations.props9
-rw-r--r--src/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.il20
-rw-r--r--src/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.ilproj6
-rw-r--r--src/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.xml24
-rw-r--r--src/System.Runtime.CompilerServices.Unsafe/tests/UnsafeTests.cs38
-rw-r--r--src/System.Runtime.Extensions/ref/System.Runtime.Extensions.cs24
-rw-r--r--src/System.Runtime.Extensions/src/ApiCompatBaseline.uapaot.txt5
-rw-r--r--src/System.Runtime.Extensions/src/System.Runtime.Extensions.csproj52
-rw-r--r--src/System.Runtime.Extensions/src/System/Collections/Hashtable.cs89
-rw-r--r--src/System.Runtime.Extensions/src/System/Environment.Unix.cs8
-rw-r--r--src/System.Runtime.Extensions/src/System/Environment.Win32.cs111
-rw-r--r--src/System.Runtime.Extensions/src/System/Environment.WinRT.cs3
-rw-r--r--src/System.Runtime.Extensions/src/System/Environment.Windows.cs131
-rw-r--r--src/System.Runtime.Extensions/src/System/Environment.cs34
-rw-r--r--src/System.Runtime.Extensions/src/System/Globalization/Extensions.cs99
-rw-r--r--src/System.Runtime.Extensions/src/System/IO/BufferedStream.cs85
-rw-r--r--src/System.Runtime.Extensions/src/System/IO/StringReader.cs4
-rw-r--r--src/System.Runtime.Extensions/src/System/OperatingSystem.cs2
-rw-r--r--src/System.Runtime.Extensions/tests/Performance/System.Runtime.Extensions.Performance.Tests.csproj3
-rw-r--r--src/System.Runtime.Extensions/tests/System.Runtime.Extensions.Tests.csproj22
-rw-r--r--src/System.Runtime.Extensions/tests/System/AppDomainTests.cs19
-rw-r--r--src/System.Runtime.Extensions/tests/System/Convert.netcoreapp.cs292
-rw-r--r--src/System.Runtime.Extensions/tests/System/Environment.UserDomainName.cs23
-rw-r--r--src/System.Runtime.Extensions/tests/System/Environment.UserName.cs16
-rw-r--r--src/System.Runtime.Extensions/tests/System/EnvironmentTests.cs48
-rw-r--r--src/System.Runtime.Extensions/tests/System/IO/Path.IsPathFullyQualified.cs4
-rw-r--r--src/System.Runtime.Extensions/tests/System/IO/Path.IsPathFullyQualified.netcoreapp.cs50
-rw-r--r--src/System.Runtime.Extensions/tests/System/IO/PathTests.cs909
-rw-r--r--src/System.Runtime.Extensions/tests/System/IO/PathTests.netcoreapp.cs246
-rw-r--r--src/System.Runtime.Extensions/tests/System/IO/PathTestsBase.cs226
-rw-r--r--src/System.Runtime.Extensions/tests/System/IO/PathTestsBase.netcoreapp.cs23
-rw-r--r--src/System.Runtime.Extensions/tests/System/IO/PathTests_Combine.cs (renamed from src/System.Runtime.Extensions/tests/System/IO/Path.Combine.cs)2
-rw-r--r--src/System.Runtime.Extensions/tests/System/IO/PathTests_Join.netcoreapp.cs111
-rw-r--r--src/System.Runtime.Extensions/tests/System/IO/PathTests_Unix.cs131
-rw-r--r--src/System.Runtime.Extensions/tests/System/IO/PathTests_Windows.cs369
-rw-r--r--src/System.Runtime.Extensions/tests/System/IO/PathTests_Windows.netcoreapp.cs268
-rw-r--r--src/System.Runtime.Extensions/tests/System/IO/PathTests_Windows_NetFX.cs106
-rw-r--r--src/System.Runtime.Extensions/tests/System/Math.cs26
-rw-r--r--src/System.Runtime.Extensions/tests/System/MathF.netcoreapp.cs181
-rw-r--r--src/System.Runtime.Extensions/tests/System/MathTests.netcoreapp.cs158
-rw-r--r--src/System.Runtime.Extensions/tests/System/StringComparer.cs18
-rw-r--r--src/System.Runtime.Extensions/tests/System/StringComparer.netcoreapp.cs79
-rw-r--r--src/System.Runtime.Extensions/tests/TestHelpers.cs35
-rw-r--r--src/System.Runtime.InteropServices.RuntimeInformation/tests/DescriptionNameTests.cs4
-rw-r--r--src/System.Runtime.InteropServices/src/System/Runtime/InteropServices/ComTypes/IDataObject.cs86
-rw-r--r--src/System.Runtime.InteropServices/src/System/Runtime/InteropServices/ComTypes/IEnumSTATDATA.cs42
-rw-r--r--src/System.Runtime.Intrinsics.Experimental/System.Runtime.Intrinsics.Experimental.sln (renamed from src/System.Runtime.Intrinsics/System.Runtime.Intrinsics.sln)4
-rw-r--r--src/System.Runtime.Intrinsics.Experimental/dir.props10
-rw-r--r--src/System.Runtime.Intrinsics.Experimental/pkg/System.Runtime.Intrinsics.Experimental.pkgproj11
-rw-r--r--src/System.Runtime.Intrinsics.Experimental/ref/Configurations.props (renamed from src/System.Runtime.Intrinsics/ref/Configurations.props)0
-rw-r--r--src/System.Runtime.Intrinsics.Experimental/ref/System.Runtime.Intrinsics.Experimental.csproj (renamed from src/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.csproj)4
-rw-r--r--src/System.Runtime.Intrinsics.Experimental/ref/System.Runtime.Intrinsics.cs (renamed from src/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.X86.cs)932
-rw-r--r--src/System.Runtime.Intrinsics.Experimental/src/Configurations.props (renamed from src/System.Runtime.Intrinsics/src/Configurations.props)0
-rw-r--r--src/System.Runtime.Intrinsics.Experimental/src/System.Runtime.Intrinsics.Experimental.csproj (renamed from src/System.Runtime.Intrinsics/src/System.Runtime.Intrinsics.csproj)2
-rw-r--r--src/System.Runtime.Loader/System.Runtime.Loader.sln12
-rw-r--r--src/System.Runtime.Loader/tests/System.Runtime.Loader.Test.Assembly/System.Runtime.Loader.Test.Assembly.csproj2
-rw-r--r--src/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj4
-rw-r--r--src/System.Runtime.Numerics/src/System/Numerics/BigNumber.cs4
-rw-r--r--src/System.Runtime.Numerics/tests/BigInteger/parse.netcoreapp.cs28
-rw-r--r--src/System.Runtime.Serialization.Formatters/src/MatchingRefApiCompatBaseline.txt3
-rw-r--r--src/System.Runtime.Serialization.Formatters/src/Resources/Strings.resx3
-rw-r--r--src/System.Runtime.Serialization.Formatters/src/System.Runtime.Serialization.Formatters.csproj5
-rw-r--r--src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/ObjectIDGenerator.cs31
-rw-r--r--src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/SurrogateSelector.cs2
-rw-r--r--src/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTestData.cs1171
-rw-r--r--src/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTests.cs61
-rw-r--r--src/System.Runtime.Serialization.Formatters/tests/System.Runtime.Serialization.Formatters.Tests.csproj10
-rw-r--r--src/System.Runtime.Serialization.Formatters/tests/TypeSerializableValue.cs70
-rw-r--r--src/System.Runtime.Serialization.Json/tests/Performance/System.Runtime.Serialization.Json.Performance.Tests.csproj4
-rw-r--r--src/System.Runtime.Serialization.Json/tests/ReflectionOnly/System.Runtime.Serialization.Json.ReflectionOnly.Tests.csproj2
-rw-r--r--src/System.Runtime.Serialization.Json/tests/System.Runtime.Serialization.Json.Tests.csproj4
-rw-r--r--src/System.Runtime.Serialization.Xml/src/MatchingRefApiCompatBaseline.txt3
-rw-r--r--src/System.Runtime.Serialization.Xml/tests/Performance/System.Runtime.Serialization.Xml.Performance.Tests.csproj2
-rw-r--r--src/System.Runtime.Serialization.Xml/tests/ReflectionOnly/System.Runtime.Serialization.Xml.ReflectionOnly.Tests.csproj4
-rw-r--r--src/System.Runtime.Serialization.Xml/tests/SerializationTypes.cs68
-rw-r--r--src/System.Runtime.Serialization.Xml/tests/System.Runtime.Serialization.Xml.Tests.csproj4
-rw-r--r--src/System.Runtime.Serialization.Xml/tests/XmlDictionaryReaderTests.cs35
-rw-r--r--src/System.Runtime.WindowsRuntime/src/System.Runtime.WindowsRuntime.csproj6
-rw-r--r--src/System.Runtime.WindowsRuntime/src/System/InternalHelpers.cs10
-rw-r--r--src/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/AsyncInfoToTaskBridge.CoreCLR.cs4
-rw-r--r--src/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/AsyncInfoToTaskBridge.CoreRT.cs9
-rw-r--r--src/System.Runtime/ref/System.Runtime.cs220
-rw-r--r--src/System.Runtime/src/ApiCompatBaseline.uapaot.txt4
-rw-r--r--src/System.Runtime/src/System.Runtime.csproj1
-rw-r--r--src/System.Runtime/tests/Performance/System.Runtime.Performance.Tests.csproj3
-rw-r--r--src/System.Runtime/tests/System.Runtime.Tests.csproj8
-rw-r--r--src/System.Runtime/tests/System/ArraySegmentTests.netcoreapp.cs22
-rw-r--r--src/System.Runtime/tests/System/BooleanTests.netcoreapp.cs8
-rw-r--r--src/System.Runtime/tests/System/ByteTests.netcoreapp.cs8
-rw-r--r--src/System.Runtime/tests/System/DateTimeOffsetTests.cs99
-rw-r--r--src/System.Runtime/tests/System/DateTimeOffsetTests.netcoreapp.cs23
-rw-r--r--src/System.Runtime/tests/System/DateTimeTests.cs159
-rw-r--r--src/System.Runtime/tests/System/DateTimeTests.netcoreapp.cs31
-rw-r--r--src/System.Runtime/tests/System/DecimalTests.cs210
-rw-r--r--src/System.Runtime/tests/System/DecimalTests.netcoreapp.cs8
-rw-r--r--src/System.Runtime/tests/System/DoubleTests.cs2
-rw-r--r--src/System.Runtime/tests/System/DoubleTests.netcoreapp.cs8
-rw-r--r--src/System.Runtime/tests/System/GCTests.cs4
-rw-r--r--src/System.Runtime/tests/System/GuidTests.netcoreapp.cs20
-rw-r--r--src/System.Runtime/tests/System/Int16Tests.netcoreapp.cs8
-rw-r--r--src/System.Runtime/tests/System/Int32Tests.netcoreapp.cs8
-rw-r--r--src/System.Runtime/tests/System/Int64Tests.netcoreapp.cs8
-rw-r--r--src/System.Runtime/tests/System/PseudoCustomAttributeTests.cs178
-rw-r--r--src/System.Runtime/tests/System/Reflection/AssemblyNameTests.cs23
-rw-r--r--src/System.Runtime/tests/System/Reflection/PointerTests.cs79
-rw-r--r--src/System.Runtime/tests/System/Runtime/CompilerServices/AttributesTests.cs22
-rw-r--r--src/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeHelpersTests.cs69
-rw-r--r--src/System.Runtime/tests/System/Runtime/ExceptionServices/HandleProcessCorruptedStateExceptions.cs5
-rw-r--r--src/System.Runtime/tests/System/SByteTests.netcoreapp.cs8
-rw-r--r--src/System.Runtime/tests/System/SingleTests.cs2
-rw-r--r--src/System.Runtime/tests/System/SingleTests.netcoreapp.cs8
-rw-r--r--src/System.Runtime/tests/System/StringGetHashCodeTests.cs64
-rw-r--r--src/System.Runtime/tests/System/StringTests.cs340
-rw-r--r--src/System.Runtime/tests/System/StringTests.netcoreapp.cs24
-rw-r--r--src/System.Runtime/tests/System/Text/StringBuilderTests.cs34
-rw-r--r--src/System.Runtime/tests/System/Text/StringBuilderTests.netcoreapp.cs63
-rw-r--r--src/System.Runtime/tests/System/Threading/WaitHandleTests.cs13
-rw-r--r--src/System.Runtime/tests/System/TimeSpanTests.netcoreapp.cs24
-rw-r--r--src/System.Runtime/tests/System/TimeZoneInfoTests.cs17
-rw-r--r--src/System.Runtime/tests/System/TypeTests.cs83
-rw-r--r--src/System.Runtime/tests/System/TypedReferenceTests.cs3
-rw-r--r--src/System.Runtime/tests/System/UInt16Tests.netcoreapp.cs8
-rw-r--r--src/System.Runtime/tests/System/UInt32Tests.netcoreapp.cs8
-rw-r--r--src/System.Runtime/tests/System/UInt64Tests.netcoreapp.cs8
-rw-r--r--src/System.Runtime/tests/System/ValueTypeTests.cs23
-rw-r--r--src/System.Runtime/tests/System/VersionTests.netcoreapp.cs8
-rw-r--r--src/System.Runtime/tests/app.config8
-rw-r--r--src/System.Security.AccessControl/pkg/System.Security.AccessControl.pkgproj4
-rw-r--r--src/System.Security.Cryptography.Algorithms/ref/System.Security.Cryptography.Algorithms.cs26
-rw-r--r--src/System.Security.Cryptography.Algorithms/ref/System.Security.Cryptography.Algorithms.netcoreapp.cs25
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.OSX.cs4
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.Unix.cs4
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.OSX.cs2
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.Unix.cs2
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.Windows.cs2
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.cs10
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/Resources/Strings.resx27
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj73
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/CngKeyLite.cs9
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/CryptoConfig.cs19
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/DSA.cs22
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECCngKey.cs216
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellman.Create.Cng.cs35
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellman.Create.OpenSsl.cs35
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellman.Create.SecurityTransforms.cs46
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellman.Xml.cs19
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellman.cs170
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanCng.Derive.cs72
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanCng.Key.cs46
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanCng.cs68
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanCngPublicKey.cs81
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanPublicKey.ExportParameters.cs32
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanPublicKey.cs9
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDsa.cs18
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDsaCng.Key.cs148
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDsaCng.cs18
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/RSA.cs26
-rw-r--r--src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/RandomNumberGenerator.cs5
-rw-r--r--src/System.Security.Cryptography.Algorithms/tests/CryptoConfigTests.cs16
-rw-r--r--src/System.Security.Cryptography.Algorithms/tests/DSATests.cs6
-rw-r--r--src/System.Security.Cryptography.Algorithms/tests/DefaultECDiffieHellmanProvider.Unix.cs54
-rw-r--r--src/System.Security.Cryptography.Algorithms/tests/DefaultECDiffieHellmanProvider.Windows.cs45
-rw-r--r--src/System.Security.Cryptography.Algorithms/tests/DefaultECDiffieHellmanProvider.cs32
-rw-r--r--src/System.Security.Cryptography.Algorithms/tests/DefaultRSAProvider.cs11
-rw-r--r--src/System.Security.Cryptography.Algorithms/tests/ECDiffieHellmanPublicKeyTests.cs2
-rw-r--r--src/System.Security.Cryptography.Algorithms/tests/ECDiffieHellmanTests.cs50
-rw-r--r--src/System.Security.Cryptography.Algorithms/tests/ECDsaTests.cs4
-rw-r--r--src/System.Security.Cryptography.Algorithms/tests/HashAlgorithmTest.netcoreapp.cs2
-rw-r--r--src/System.Security.Cryptography.Algorithms/tests/IncrementalHashTests.cs14
-rw-r--r--src/System.Security.Cryptography.Algorithms/tests/RandomNumberGeneratorTests.netcoreapp.cs37
-rw-r--r--src/System.Security.Cryptography.Algorithms/tests/System.Security.Cryptography.Algorithms.Tests.csproj41
-rw-r--r--src/System.Security.Cryptography.Cng/pkg/System.Security.Cryptography.Cng.pkgproj5
-rw-r--r--src/System.Security.Cryptography.Cng/ref/System.Security.Cryptography.Cng.ECDiffieHellman.cs70
-rw-r--r--src/System.Security.Cryptography.Cng/ref/System.Security.Cryptography.Cng.cs2
-rw-r--r--src/System.Security.Cryptography.Cng/ref/System.Security.Cryptography.Cng.csproj10
-rw-r--r--src/System.Security.Cryptography.Cng/src/Internal/Cryptography/CngAlgorithmCore.cs7
-rw-r--r--src/System.Security.Cryptography.Cng/src/Internal/Cryptography/KeyPropertyName.cs1
-rw-r--r--src/System.Security.Cryptography.Cng/src/Resources/Strings.resx27
-rw-r--r--src/System.Security.Cryptography.Cng/src/System.Security.Cryptography.Cng.csproj41
-rw-r--r--src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/CngKey.EC.cs103
-rw-r--r--src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/ECCng.ImportExport.cs77
-rw-r--r--src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/ECDiffieHellmanCng.Derive.cs143
-rw-r--r--src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/ECDiffieHellmanCng.Key.cs137
-rw-r--r--src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/ECDiffieHellmanCng.Xml.cs19
-rw-r--r--src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/ECDiffieHellmanCng.cs174
-rw-r--r--src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/ECDiffieHellmanCngPublicKey.cs143
-rw-r--r--src/System.Security.Cryptography.Cng/tests/ECDiffieHellmanCngProvider.cs63
-rw-r--r--src/System.Security.Cryptography.Cng/tests/ECDiffieHellmanCngTests.cs177
-rw-r--r--src/System.Security.Cryptography.Cng/tests/ECDsaCngImportExportTests.cs1
-rw-r--r--src/System.Security.Cryptography.Cng/tests/ECDsaCngTests.cs11
-rw-r--r--src/System.Security.Cryptography.Cng/tests/RSACngProvider.cs2
-rw-r--r--src/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj37
-rw-r--r--src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/CapiHelper.Windows.cs2
-rw-r--r--src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/DSACryptoServiceProvider.Unix.cs16
-rw-r--r--src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/RSACryptoServiceProvider.Unix.cs36
-rw-r--r--src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/RSACryptoServiceProvider.Windows.cs14
-rw-r--r--src/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderProvider.cs2
-rw-r--r--src/System.Security.Cryptography.Encoding/src/System.Security.Cryptography.Encoding.csproj1
-rw-r--r--src/System.Security.Cryptography.Encoding/tests/Asn1/Reader/ParseTag.cs2
-rw-r--r--src/System.Security.Cryptography.Encoding/tests/Asn1/Reader/ReadBMPString.cs4
-rw-r--r--src/System.Security.Cryptography.Encoding/tests/Asn1/Reader/ReadIA5String.cs4
-rw-r--r--src/System.Security.Cryptography.Encoding/tests/Asn1/Reader/ReadUTF8String.cs4
-rw-r--r--src/System.Security.Cryptography.Encoding/tests/Asn1/Serializer/SimpleDeserialize.cs20
-rw-r--r--src/System.Security.Cryptography.Encoding/tests/Asn1/Writer/Asn1WriterTests.cs4
-rw-r--r--src/System.Security.Cryptography.Encoding/tests/Asn1/Writer/WriteCharacterString.cs36
-rw-r--r--src/System.Security.Cryptography.Encoding/tests/Asn1/Writer/WriteObjectIdentifier.cs12
-rw-r--r--src/System.Security.Cryptography.Encoding/tests/System.Security.Cryptography.Encoding.Tests.csproj1
-rw-r--r--src/System.Security.Cryptography.Encoding/tests/TestHelpers.cs12
-rw-r--r--src/System.Security.Cryptography.OpenSsl/System.Security.Cryptography.OpenSsl.sln8
-rw-r--r--src/System.Security.Cryptography.OpenSsl/ref/System.Security.Cryptography.OpenSsl.cs20
-rw-r--r--src/System.Security.Cryptography.OpenSsl/src/Resources/Strings.resx21
-rw-r--r--src/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj34
-rw-r--r--src/System.Security.Cryptography.OpenSsl/src/System/Security/Cryptography/ECDiffieHellmanOpenSsl.cs88
-rw-r--r--src/System.Security.Cryptography.OpenSsl/src/System/Security/Cryptography/ECDsaOpenSsl.cs7
-rw-r--r--src/System.Security.Cryptography.OpenSsl/tests/EcDiffieHellmanOpenSslProvider.cs36
-rw-r--r--src/System.Security.Cryptography.OpenSsl/tests/EcDiffieHellmanOpenSslTests.cs283
-rw-r--r--src/System.Security.Cryptography.OpenSsl/tests/EcDsaOpenSslTests.cs2
-rw-r--r--src/System.Security.Cryptography.OpenSsl/tests/RSAOpenSslProvider.cs4
-rw-r--r--src/System.Security.Cryptography.OpenSsl/tests/System.Security.Cryptography.OpenSsl.Tests.csproj35
-rw-r--r--src/System.Security.Cryptography.Pkcs/pkg/System.Security.Cryptography.Pkcs.pkgproj6
-rw-r--r--src/System.Security.Cryptography.Pkcs/ref/System.Security.Cryptography.Pkcs.csproj1
-rw-r--r--src/System.Security.Cryptography.Pkcs/ref/System.Security.Cryptography.Pkcs.netcoreapp.cs52
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Helpers.cs68
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Oids.cs17
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/AsnHelpers.cs140
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.Asn.cs149
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.Decode.cs94
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.Decrypt.cs186
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.Encrypt.cs186
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.Exceptions.cs38
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.KeyAgree.cs94
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.KeyTrans.cs179
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.cs176
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/PkcsPal.AnyOS.cs212
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/Windows/HelpersWindows.cs4
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/MatchingRefApiCompatBaseline.netstandard.txt3
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/Resources/Strings.resx21
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System.Security.Cryptography.Pkcs.csproj35
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/AlgorithmIdentifierAsn.cs2
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/EncryptedContentInfoAsn.cs33
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/EnvelopedDataAsn.cs39
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/GeneralName.cs87
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/KeyAgreeRecipientIdentifierAsn.cs24
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/KeyAgreeRecipientInfoAsn.cs39
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/KeyTransRecipientInfoAsn.cs33
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/MessageImprint.cs23
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/OriginatorIdentifierOrKeyAsn.cs31
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/OriginatorInfoAsn.cs28
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/OriginatorPublicKeyAsn.cs23
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/OtherKeyAttributeAsn.cs25
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rc2CbcParameters.cs80
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientEncryptedKeyAsn.cs27
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientIdentifierAsn.cs27
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientInfoAsn.cs30
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientKeyIdentifier.cs31
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161Accuracy.cs77
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TimeStampReq.cs44
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TimeStampResp.cs76
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TstInfo.cs68
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/SigningCertificateAsn.cs89
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/X509ExtensionAsn.cs38
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSigner.cs4
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161RequestResponseStatus.cs19
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampRequest.cs427
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampToken.cs641
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampTokenInfo.cs265
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/SignedCms.cs30
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/SignerInfo.cs6
-rw-r--r--src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/SubjectIdentifier.cs24
-rw-r--r--src/System.Security.Cryptography.Pkcs/tests/Certificates.cs577
-rw-r--r--src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/ContentEncryptionAlgorithmTests.cs155
-rw-r--r--src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/DecryptTests.KeyPersistence.cs5
-rw-r--r--src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/DecryptTests.cs305
-rw-r--r--src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/EdgeCasesTests.cs40
-rw-r--r--src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/GeneralTests.cs104
-rw-r--r--src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/KeyAgreeRecipientInfoTests.cs115
-rw-r--r--src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/KeyTransRecipientInfoTests.cs33
-rw-r--r--src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/StateTests.cs52
-rw-r--r--src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/UnprotectedAttributeTests.cs74
-rw-r--r--src/System.Security.Cryptography.Pkcs/tests/Oids.cs4
-rw-r--r--src/System.Security.Cryptography.Pkcs/tests/Pkcs9AttributeTests.cs43
-rw-r--r--src/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampRequestTests.cs783
-rw-r--r--src/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampTokenInfoTests.cs501
-rw-r--r--src/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampTokenTestData.cs301
-rw-r--r--src/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampTokenTests.cs1087
-rw-r--r--src/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.cs2
-rw-r--r--src/System.Security.Cryptography.Pkcs/tests/System.Security.Cryptography.Pkcs.Tests.csproj24
-rw-r--r--src/System.Security.Cryptography.Primitives/System.Security.Cryptography.Primitives.sln10
-rw-r--r--src/System.Security.Cryptography.Primitives/ref/System.Security.Cryptography.Primitives.cs5
-rw-r--r--src/System.Security.Cryptography.Primitives/ref/System.Security.Cryptography.Primitives.csproj2
-rw-r--r--src/System.Security.Cryptography.Primitives/src/Resources/Strings.resx3
-rw-r--r--src/System.Security.Cryptography.Primitives/src/System.Security.Cryptography.Primitives.csproj2
-rw-r--r--src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/AsymmetricAlgorithm.cs12
-rw-r--r--src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/CryptoConfigForwarder.cs33
-rw-r--r--src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/CryptoStream.cs156
-rw-r--r--src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/CryptographicOperations.cs63
-rw-r--r--src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/HMAC.cs6
-rw-r--r--src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/HashAlgorithm.cs26
-rw-r--r--src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/KeyedHashAlgorithm.cs12
-rw-r--r--src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/SymmetricAlgorithm.cs12
-rw-r--r--src/System.Security.Cryptography.Primitives/tests/CryptoConfigTests.cs147
-rw-r--r--src/System.Security.Cryptography.Primitives/tests/FixedTimeEqualsTests.cs109
-rw-r--r--src/System.Security.Cryptography.Primitives/tests/Performance/Configurations.props8
-rw-r--r--src/System.Security.Cryptography.Primitives/tests/Performance/Perf.FixedTimeEquals.cs115
-rw-r--r--src/System.Security.Cryptography.Primitives/tests/Performance/System.Security.Cryptography.Primitives.Performance.Tests.csproj30
-rw-r--r--src/System.Security.Cryptography.Primitives/tests/System.Security.Cryptography.Primitives.Tests.csproj14
-rw-r--r--src/System.Security.Cryptography.Primitives/tests/ZeroMemoryTests.cs77
-rw-r--r--src/System.Security.Cryptography.ProtectedData/src/System.Security.Cryptography.ProtectedData.csproj1
-rw-r--r--src/System.Security.Cryptography.ProtectedData/src/System/Security/Cryptography/ProtectedData.cs11
-rw-r--r--src/System.Security.Cryptography.ProtectedData/tests/ProtectedDataTests.cs18
-rw-r--r--src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/ChainPal.cs6
-rw-r--r--src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/DirectoryBasedStoreProvider.cs16
-rw-r--r--src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509ChainProcessor.cs9
-rw-r--r--src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/ChainPal.GetChainStatusInformation.cs19
-rw-r--r--src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/FindPal.cs2
-rw-r--r--src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/Native/Helpers.cs33
-rw-r--r--src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/Native/Primitives.cs7
-rw-r--r--src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/StorePal.Import.cs4
-rw-r--r--src/System.Security.Cryptography.X509Certificates/src/Resources/Strings.resx18
-rw-r--r--src/System.Security.Cryptography.X509Certificates/src/System.Security.Cryptography.X509Certificates.csproj9
-rw-r--r--src/System.Security.Cryptography.X509Certificates/tests/LoadFromFileTests.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/src/MatchingRefApiCompatBaseline.netstandard.txt2
-rw-r--r--src/System.Security.Cryptography.Xml/src/System.Security.Cryptography.Xml.csproj2
-rw-r--r--src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/CanonicalXml.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/ExcCanonicalXml.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/KeyInfoX509Data.cs6
-rw-r--r--src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Utils.cs29
-rw-r--r--src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/X509IssuerSerial.cs55
-rw-r--r--src/System.Security.Cryptography.Xml/tests/AssertCrypto.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/tests/DSAKeyValueTest.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/tests/DataObjectTest.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/tests/DataReferenceTest.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/tests/EncryptedXmlTest.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/tests/EncryptionMethodTests.cs5
-rw-r--r--src/System.Security.Cryptography.Xml/tests/KeyInfoNameTest.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/tests/KeyInfoNodeTest.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/tests/KeyInfoRetrievalMethodTest.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/tests/KeyInfoTest.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/tests/KeyInfoX509DataTest.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/tests/RSAKeyValueTest.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/tests/ReferenceTest.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/tests/SignatureTest.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/tests/SignedInfoTest.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/tests/SignedXmlTest.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/tests/TransformChainTest.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/tests/TransformTest.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/tests/XmlDecryptionTransformTest.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/tests/XmlDsigBase64TransformTest.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/tests/XmlDsigC14NTransformTest.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/tests/XmlDsigC14NWithCommentsTransformTest.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/tests/XmlDsigEnvelopedSignatureTransformTest.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/tests/XmlDsigExcC14NTransformTest.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/tests/XmlDsigExcC14NWithCommentsTransformTest.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/tests/XmlDsigXPathTransformTest.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/tests/XmlDsigXsltTransformTest.cs2
-rw-r--r--src/System.Security.Cryptography.Xml/tests/XmlLicenseTransformTest.cs2
-rw-r--r--src/System.Security.Permissions/ref/Configurations.props1
-rw-r--r--src/System.Security.Permissions/ref/System.Security.Permissions.cs57
-rw-r--r--src/System.Security.Permissions/ref/System.Security.Permissions.csproj18
-rw-r--r--src/System.Security.Permissions/src/Resources/Strings.resx2
-rw-r--r--src/System.Security.Permissions/src/System.Security.Permissions.csproj7
-rw-r--r--src/System.Security.Permissions/src/System/Security/Permissions/PrincipalPermission.cs8
-rw-r--r--src/System.Security.Permissions/src/System/Security/Policy/FirstMatchCodeGroup.cs2
-rw-r--r--src/System.Security.Permissions/src/System/Security/Policy/PermissionRequestEvidence.cs2
-rw-r--r--src/System.Security.Permissions/src/System/Security/Policy/PolicyLevel.cs1
-rw-r--r--src/System.Security.Permissions/src/System/Security/Policy/UnionCodeGroup.cs2
-rw-r--r--src/System.Security.Permissions/src/System/ServiceProcess/ServiceControllerPermission.cs17
-rw-r--r--src/System.Security.Permissions/src/System/ServiceProcess/ServiceControllerPermissionAccess.cs14
-rw-r--r--src/System.Security.Permissions/src/System/ServiceProcess/ServiceControllerPermissionAttribute.cs19
-rw-r--r--src/System.Security.Permissions/src/System/ServiceProcess/ServiceControllerPermissionEntry.cs15
-rw-r--r--src/System.Security.Permissions/src/System/ServiceProcess/ServiceControllerPermissionEntryCollection.cs26
-rw-r--r--src/System.Security.Permissions/tests/CodeGroupTests.cs4
-rw-r--r--src/System.Security.Permissions/tests/EvidenceBaseTests.cs2
-rw-r--r--src/System.Security.Permissions/tests/PolicyTests.cs2
-rw-r--r--src/System.Security.Permissions/tests/PrincipalPermissionTests.cs6
-rw-r--r--src/System.Security.Principal.Windows/pkg/System.Security.Principal.Windows.pkgproj4
-rw-r--r--src/System.Security.Principal.Windows/ref/System.Security.Principal.Windows.cs5
-rw-r--r--src/System.Security.Principal.Windows/src/System.Security.Principal.Windows.csproj3
-rw-r--r--src/System.Security.Principal.Windows/src/System/Security/Principal/WindowsIdentity.cs176
-rw-r--r--src/System.Security.Principal.Windows/tests/WindowsIdentityTests.cs29
-rw-r--r--src/System.Security.Principal.Windows/tests/WindowsPrincipalTests.cs53
-rw-r--r--src/System.ServiceModel.Syndication/pkg/System.ServiceModel.Syndication.pkgproj2
-rw-r--r--src/System.ServiceModel.Syndication/ref/System.ServiceModel.Syndication.netcoreapp.cs34
-rw-r--r--src/System.ServiceModel.Syndication/src/MatchingRefApiCompatBaseline.netstandard.txt19
-rw-r--r--src/System.ServiceModel.Syndication/src/Resources/Strings.resx19
-rw-r--r--src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/Atom10FeedFormatter.cs8
-rw-r--r--src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/DateTimeHelper.cs29
-rw-r--r--src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/ExtensibleSyndicationObject.cs4
-rw-r--r--src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/Rss20Constants.cs8
-rw-r--r--src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/Rss20FeedFormatter.cs72
-rw-r--r--src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/SyndicationElementExtensionCollection.cs8
-rw-r--r--src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/SyndicationFeed.cs316
-rw-r--r--src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/SyndicationFeedFormatter.cs68
-rw-r--r--src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/SyndicationTextInput.cs14
-rw-r--r--src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/XmlDateTimeData.cs21
-rw-r--r--src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/XmlUriData.cs24
-rw-r--r--src/System.ServiceModel.Syndication/tests/BasicScenarioTests.cs119
-rw-r--r--src/System.ServiceModel.Syndication/tests/System.ServiceModel.Syndication.Tests.csproj5
-rw-r--r--src/System.ServiceModel.Syndication/tests/TestFeeds/rssOptionalElements.xml31
-rw-r--r--src/System.ServiceModel.Syndication/tests/TestFeeds/rssSpecExample.xml23
-rw-r--r--src/System.ServiceModel.Syndication/tests/netcoreapp/BasicScenarioTests.netcoreapp.cs157
-rw-r--r--src/System.ServiceProcess.ServiceController/ref/System.ServiceProcess.ServiceController.cs6
-rw-r--r--src/System.ServiceProcess.ServiceController/src/Configurations.props2
-rw-r--r--src/System.ServiceProcess.ServiceController/src/System.ServiceProcess.ServiceController.csproj11
-rw-r--r--src/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceBase.cs34
-rw-r--r--src/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceProcessDescriptionAttribute.cs42
-rw-r--r--src/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs117
-rw-r--r--src/System.ServiceProcess.ServiceController/tests/ServiceControllerTests.cs40
-rw-r--r--src/System.ServiceProcess.ServiceController/tests/ServiceProcessDescriptionAttributeTests.cs23
-rw-r--r--src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/Helpers.cs18
-rw-r--r--src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/Program.cs33
-rw-r--r--src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/System.ServiceProcess.ServiceController.TestService.csproj4
-rw-r--r--src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/TestService.cs84
-rw-r--r--src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/TestServiceInstaller.cs55
-rw-r--r--src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.Tests.csproj1
-rw-r--r--src/System.ServiceProcess.ServiceController/tests/TestServiceProvider.cs73
-rw-r--r--src/System.Text.Encoding.CodePages/ref/System.Text.Encoding.CodePages.cs5
-rw-r--r--src/System.Text.Encoding/tests/Decoder/DecoderSpanTests.netcoreapp.cs4
-rw-r--r--src/System.Text.Encoding/tests/Encoder/EncoderSpanTests.netcoreapp.cs10
-rw-r--r--src/System.Text.Encoding/tests/Encoding/EncodingGetEncodingTests.cs15
-rw-r--r--src/System.Text.Encoding/tests/EncodingTestHelpers.netcoreapp.cs22
-rw-r--r--src/System.Text.Encoding/tests/System.Text.Encoding.Tests.csproj6
-rw-r--r--src/System.Text.Encoding/tests/UTF8Encoding/UTF8EncodingDecode.cs1
-rw-r--r--src/System.Text.Encoding/tests/UnicodeEncoding/UnicodeEncodingDecode.cs1
-rw-r--r--src/System.Text.RegularExpressions/System.Text.RegularExpressions.sln10
-rw-r--r--src/System.Text.RegularExpressions/src/MatchingRefApiCompatBaseline.txt2
-rw-r--r--src/System.Text.RegularExpressions/src/System.Text.RegularExpressions.csproj32
-rw-r--r--src/System.Text.RegularExpressions/src/System/Collections/Generic/ValueListBuilder.Pop.cs21
-rw-r--r--src/System.Text.RegularExpressions/src/System/Collections/HashtableExtensions.cs (renamed from src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/HashtableExtensions.cs)6
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Capture.cs61
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/CaptureCollection.cs (renamed from src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCaptureCollection.cs)28
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/CollectionDebuggerProxy.cs (renamed from src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCollectionDebuggerProxy.cs)11
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/CompiledRegexRunner.cs4
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/CompiledRegexRunnerFactory.cs5
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Group.cs (renamed from src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexGroup.cs)42
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/GroupCollection.cs (renamed from src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexGroupCollection.cs)9
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Match.cs (renamed from src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexMatch.cs)128
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/MatchCollection.cs (renamed from src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexMatchCollection.cs)6
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Reference.cs88
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Cache.cs303
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Match.cs184
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Replace.cs230
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Split.cs165
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Timeout.cs104
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.cs1017
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexBoyerMoore.cs179
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCapture.cs106
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCharClass.cs207
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCode.cs202
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompilationInfo.cs7
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs439
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexFCD.cs364
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexInterpreter.cs75
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexLWCGCompiler.cs22
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs437
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexParser.cs344
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefix.cs21
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexReplacement.cs252
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexRunner.cs11
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexTree.cs40
-rw-r--r--src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexWriter.cs412
-rw-r--r--src/System.Text.RegularExpressions/tests/Performance/Configurations.props8
-rw-r--r--src/System.Text.RegularExpressions/tests/Performance/Perf.Regex.Cache.cs122
-rw-r--r--src/System.Text.RegularExpressions/tests/Performance/Perf.Regex.cs452
-rw-r--r--src/System.Text.RegularExpressions/tests/Performance/Perf.RegexRedux.cs70
-rw-r--r--src/System.Text.RegularExpressions/tests/Performance/System.Text.RegularExpressions.Performance.Tests.csproj31
-rw-r--r--src/System.Text.RegularExpressions/tests/Performance/THIRD-PARTY-NOTICES31
-rw-r--r--src/System.Text.RegularExpressions/tests/Regex.Cache.Tests.cs156
-rw-r--r--src/System.Text.RegularExpressions/tests/Regex.Ctor.Tests.cs39
-rw-r--r--src/System.Text.RegularExpressions/tests/Regex.Groups.Tests.cs7
-rw-r--r--src/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs44
-rw-r--r--src/System.Text.RegularExpressions/tests/RegexCompilationHelper.cs2
-rw-r--r--src/System.Text.RegularExpressions/tests/System.Text.RegularExpressions.Tests.csproj9
-rw-r--r--src/System.Threading.Channels/System.Threading.Channels.sln42
-rw-r--r--src/System.Threading.Channels/ref/System.Threading.Channels.cs12
-rw-r--r--src/System.Threading.Channels/ref/System.Threading.Channels.csproj6
-rw-r--r--src/System.Threading.Channels/src/Configurations.props1
-rw-r--r--src/System.Threading.Channels/src/Resources/Strings.resx11
-rw-r--r--src/System.Threading.Channels/src/System.Threading.Channels.csproj9
-rw-r--r--src/System.Threading.Channels/src/System/Threading/Channels/AsyncOperation.cs449
-rw-r--r--src/System.Threading.Channels/src/System/Threading/Channels/BoundedChannel.cs379
-rw-r--r--src/System.Threading.Channels/src/System/Threading/Channels/Channel.cs20
-rw-r--r--src/System.Threading.Channels/src/System/Threading/Channels/ChannelOptions.cs5
-rw-r--r--src/System.Threading.Channels/src/System/Threading/Channels/ChannelReader.cs27
-rw-r--r--src/System.Threading.Channels/src/System/Threading/Channels/ChannelUtilities.cs103
-rw-r--r--src/System.Threading.Channels/src/System/Threading/Channels/ChannelWriter.cs28
-rw-r--r--src/System.Threading.Channels/src/System/Threading/Channels/Interactor.cs149
-rw-r--r--src/System.Threading.Channels/src/System/Threading/Channels/SingleConsumerUnboundedChannel.cs259
-rw-r--r--src/System.Threading.Channels/src/System/Threading/Channels/UnboundedChannel.cs256
-rw-r--r--src/System.Threading.Channels/src/System/Threading/Channels/UnbufferedChannel.cs324
-rw-r--r--src/System.Threading.Channels/tests/BoundedChannelTests.cs33
-rw-r--r--src/System.Threading.Channels/tests/ChannelClosedExceptionTests.cs5
-rw-r--r--src/System.Threading.Channels/tests/ChannelTestBase.cs643
-rw-r--r--src/System.Threading.Channels/tests/ChannelTests.cs94
-rw-r--r--src/System.Threading.Channels/tests/DebugAttributeTests.cs50
-rw-r--r--src/System.Threading.Channels/tests/Performance/Perf.Channel.cs31
-rw-r--r--src/System.Threading.Channels/tests/Stress.cs212
-rw-r--r--src/System.Threading.Channels/tests/System.Threading.Channels.Tests.csproj5
-rw-r--r--src/System.Threading.Channels/tests/TestBase.cs14
-rw-r--r--src/System.Threading.Channels/tests/UnboundedChannelTests.cs26
-rw-r--r--src/System.Threading.Channels/tests/UnbufferedChannelTests.cs95
-rw-r--r--src/System.Threading.Tasks.Dataflow/pkg/System.Threading.Tasks.Dataflow.pkgproj16
-rw-r--r--src/System.Threading.Tasks.Extensions/System.Threading.Tasks.Extensions.sln10
-rw-r--r--src/System.Threading.Tasks.Extensions/dir.props2
-rw-r--r--src/System.Threading.Tasks.Extensions/pkg/System.Threading.Tasks.Extensions.pkgproj4
-rw-r--r--src/System.Threading.Tasks.Extensions/ref/System.Threading.Tasks.Extensions.cs94
-rw-r--r--src/System.Threading.Tasks.Extensions/ref/System.Threading.Tasks.Extensions.csproj6
-rw-r--r--src/System.Threading.Tasks.Extensions/src/System.Threading.Tasks.Extensions.csproj33
-rw-r--r--src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/AsyncMethodBuilderAttribute.cs21
-rw-r--r--src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs102
-rw-r--r--src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs71
-rw-r--r--src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/ValueTaskAwaiter.cs37
-rw-r--r--src/System.Threading.Tasks.Extensions/src/System/Threading/Tasks/ValueTask.cs167
-rw-r--r--src/System.Threading.Tasks.Extensions/src/System/ThrowHelper.cs40
-rw-r--r--src/System.Threading.Tasks.Extensions/tests/AsyncMethodBuilderAttributeTests.cs1
-rw-r--r--src/System.Threading.Tasks.Extensions/tests/AsyncValueTaskMethodBuilderTests.cs330
-rw-r--r--src/System.Threading.Tasks.Extensions/tests/Configurations.props1
-rw-r--r--src/System.Threading.Tasks.Extensions/tests/ManualResetValueTaskSource.cs164
-rw-r--r--src/System.Threading.Tasks.Extensions/tests/Performance/Configurations.props8
-rw-r--r--src/System.Threading.Tasks.Extensions/tests/Performance/Perf.ValueTask.cs189
-rw-r--r--src/System.Threading.Tasks.Extensions/tests/Performance/System.Threading.Tasks.Extensions.Performance.Tests.csproj24
-rw-r--r--src/System.Threading.Tasks.Extensions/tests/System.Threading.Tasks.Extensions.Tests.csproj6
-rw-r--r--src/System.Threading.Tasks.Extensions/tests/ValueTaskTests.cs1077
-rw-r--r--src/System.Threading.Tasks.Parallel/src/System/Threading/Tasks/ParallelETWProvider.cs105
-rw-r--r--src/System.Threading.Tasks/ref/System.Threading.Tasks.cs1
-rw-r--r--src/System.Threading.Tasks/tests/System.Runtime.CompilerServices/AsyncTaskMethodBuilderTests.cs17
-rw-r--r--src/System.Threading.Tasks/tests/System.Runtime.CompilerServices/TaskAwaiterTests.cs47
-rw-r--r--src/System.Threading.Tasks/tests/System.Threading.Tasks.Tests.csproj1
-rw-r--r--src/System.Threading.Tasks/tests/Task/TaskCanceledExceptionTests.netcoreapp.cs27
-rw-r--r--src/System.Threading.Thread/System.Threading.Thread.sln28
-rw-r--r--src/System.Threading.Thread/ref/System.Threading.Thread.cs1
-rw-r--r--src/System.Threading.Thread/src/System/Threading/Thread.cs1
-rw-r--r--src/System.Threading.Thread/tests/Configurations.props2
-rw-r--r--src/System.Threading.Thread/tests/System.Threading.Thread.Tests.csproj7
-rw-r--r--src/System.Threading.Thread/tests/ThreadTests.cs68
-rw-r--r--src/System.Threading.Thread/tests/ThreadTests.netcoreapp.cs16
-rw-r--r--src/System.Threading.ThreadPool/ref/System.Threading.ThreadPool.cs2
-rw-r--r--src/System.Threading.ThreadPool/src/ApiCompatBaseline.uapaot.txt1
-rw-r--r--src/System.Threading.ThreadPool/tests/ThreadPoolTests.netcoreapp.cs50
-rw-r--r--src/System.Threading/src/System/Threading/CDSsyncETWBCLProvider.cs14
-rw-r--r--src/System.Threading/tests/AsyncLocalTests.cs240
-rw-r--r--src/System.Threading/tests/MonitorTests.cs237
-rw-r--r--src/System.Threading/tests/SemaphoreTests.cs2
-rw-r--r--src/System.ValueTuple/pkg/System.ValueTuple.pkgproj2
-rw-r--r--src/System.Xml.XDocument/src/MatchingRefApiCompatBaseline.uap.txt2
-rw-r--r--src/System.Xml.XmlSerializer/src/MatchingRefApiCompatBaseline.netcoreapp.txt7
-rw-r--r--src/System.Xml.XmlSerializer/src/MatchingRefApiCompatBaseline.uap.txt7
-rw-r--r--src/System.Xml.XmlSerializer/src/MatchingRefApiCompatBaseline.uapaot.txt10
-rw-r--r--src/packages.builds35
-rw-r--r--src/publish.proj20
-rw-r--r--src/shims/ApiCompat.proj6
-rw-r--r--src/shims/ApiCompatBaseline.netcoreapp.netstandard20.txt24
-rw-r--r--src/shims/ApiCompatBaseline.uap.netstandard20.txt25
-rw-r--r--src/shims/ApiCompatBaseline.uapaot.netstandard20.txt29
-rw-r--r--src/shims/manual/System.Data.csproj19
-rw-r--r--src/shims/manual/System.csproj19
-rw-r--r--src/shims/manual/dir.props24
-rw-r--r--src/shims/manual/mscorlib.csproj19
-rw-r--r--src/syncAzure.proj5
-rw-r--r--src/upload-tests.proj7
2399 files changed, 125498 insertions, 50329 deletions
diff --git a/src/Common/src/CoreLib/Internal/IO/File.Unix.cs b/src/Common/src/CoreLib/Internal/IO/File.Unix.cs
new file mode 100644
index 0000000000..50fa0f0d0c
--- /dev/null
+++ b/src/Common/src/CoreLib/Internal/IO/File.Unix.cs
@@ -0,0 +1,25 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Internal.IO
+{
+ internal static partial class File
+ {
+ internal static bool InternalExists(string fullPath)
+ {
+ Interop.Sys.FileStatus fileinfo;
+
+ // First use stat, as we want to follow symlinks. If that fails, it could be because the symlink
+ // is broken, we don't have permissions, etc., in which case fall back to using LStat to evaluate
+ // based on the symlink itself.
+ if (Interop.Sys.Stat(fullPath, out fileinfo) < 0 &&
+ Interop.Sys.LStat(fullPath, out fileinfo) < 0)
+ {
+ return false;
+ }
+
+ return ((fileinfo.Mode & Interop.Sys.FileTypes.S_IFMT) != Interop.Sys.FileTypes.S_IFDIR);
+ }
+ }
+}
diff --git a/src/Common/src/CoreLib/Internal/IO/File.Windows.cs b/src/Common/src/CoreLib/Internal/IO/File.Windows.cs
new file mode 100644
index 0000000000..0acae3b457
--- /dev/null
+++ b/src/Common/src/CoreLib/Internal/IO/File.Windows.cs
@@ -0,0 +1,77 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.Win32;
+using Microsoft.Win32.SafeHandles;
+using System.IO;
+using System.Runtime.InteropServices;
+
+namespace Internal.IO
+{
+ internal static partial class File
+ {
+ internal static bool InternalExists(string fullPath)
+ {
+ Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data = new Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA();
+ int errorCode = FillAttributeInfo(fullPath, ref data, returnErrorOnNotFound: true);
+
+ return (errorCode == 0) && (data.dwFileAttributes != -1)
+ && ((data.dwFileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY) == 0);
+ }
+
+ /// <summary>
+ /// Returns 0 on success, otherwise a Win32 error code. Note that
+ /// classes should use -1 as the uninitialized state for dataInitialized.
+ /// </summary>
+ /// <param name="returnErrorOnNotFound">Return the error code for not found errors?</param>
+ internal static int FillAttributeInfo(string path, ref Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data, bool returnErrorOnNotFound)
+ {
+ int errorCode = Interop.Errors.ERROR_SUCCESS;
+
+ using (DisableMediaInsertionPrompt.Create())
+ {
+ if (!Interop.Kernel32.GetFileAttributesEx(path, Interop.Kernel32.GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, ref data))
+ {
+ errorCode = Marshal.GetLastWin32Error();
+ if (errorCode == Interop.Errors.ERROR_ACCESS_DENIED)
+ {
+ // Files that are marked for deletion will not let you GetFileAttributes,
+ // ERROR_ACCESS_DENIED is given back without filling out the data struct.
+ // FindFirstFile, however, will. Historically we always gave back attributes
+ // for marked-for-deletion files.
+
+ var findData = new Interop.Kernel32.WIN32_FIND_DATA();
+ using (SafeFindHandle handle = Interop.Kernel32.FindFirstFile(path, ref findData))
+ {
+ if (handle.IsInvalid)
+ {
+ errorCode = Marshal.GetLastWin32Error();
+ }
+ else
+ {
+ errorCode = Interop.Errors.ERROR_SUCCESS;
+ data.PopulateFrom(ref findData);
+ }
+ }
+ }
+ }
+ }
+
+ if (errorCode != Interop.Errors.ERROR_SUCCESS && !returnErrorOnNotFound)
+ {
+ switch (errorCode)
+ {
+ case Interop.Errors.ERROR_FILE_NOT_FOUND:
+ case Interop.Errors.ERROR_PATH_NOT_FOUND:
+ case Interop.Errors.ERROR_NOT_READY: // Removable media not ready
+ // Return default value for backward compatibility
+ data.dwFileAttributes = -1;
+ return Interop.Errors.ERROR_SUCCESS;
+ }
+ }
+
+ return errorCode;
+ }
+ }
+}
diff --git a/src/Common/src/CoreLib/Internal/IO/File.cs b/src/Common/src/CoreLib/Internal/IO/File.cs
new file mode 100644
index 0000000000..2fcc0f391f
--- /dev/null
+++ b/src/Common/src/CoreLib/Internal/IO/File.cs
@@ -0,0 +1,77 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics;
+using System.Security;
+using System.IO;
+
+namespace Internal.IO
+{
+ //
+ // Subsetted clone of System.IO.File for internal runtime use.
+ // Keep in sync with https://github.com/dotnet/corefx/tree/master/src/System.IO.FileSystem.
+ //
+ internal static partial class File
+ {
+ // Tests if a file exists. The result is true if the file
+ // given by the specified path exists; otherwise, the result is
+ // false. Note that if path describes a directory,
+ // Exists will return true.
+ public static bool Exists(string path)
+ {
+ try
+ {
+ if (path == null)
+ return false;
+ if (path.Length == 0)
+ return false;
+
+ path = Path.GetFullPath(path);
+
+ // After normalizing, check whether path ends in directory separator.
+ // Otherwise, FillAttributeInfo removes it and we may return a false positive.
+ // GetFullPath should never return null
+ Debug.Assert(path != null, "File.Exists: GetFullPath returned null");
+ if (path.Length > 0 && PathInternal.IsDirectorySeparator(path[path.Length - 1]))
+ {
+ return false;
+ }
+
+ return InternalExists(path);
+ }
+ catch (ArgumentException) { }
+ catch (NotSupportedException) { } // Security can throw this on ":"
+ catch (SecurityException) { }
+ catch (IOException) { }
+ catch (UnauthorizedAccessException) { }
+
+ return false;
+ }
+
+ public static byte[] ReadAllBytes(string path)
+ {
+ // bufferSize == 1 used to avoid unnecessary buffer in FileStream
+ using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 1))
+ {
+ long fileLength = fs.Length;
+ if (fileLength > int.MaxValue)
+ throw new IOException(SR.IO_FileTooLong2GB);
+
+ int index = 0;
+ int count = (int)fileLength;
+ byte[] bytes = new byte[count];
+ while (count > 0)
+ {
+ int n = fs.Read(bytes, index, count);
+ if (n == 0)
+ throw Error.GetEndOfFile();
+ index += n;
+ count -= n;
+ }
+ return bytes;
+ }
+ }
+ }
+}
diff --git a/src/Common/src/CoreLib/Internal/Runtime/CompilerServices/Unsafe.cs b/src/Common/src/CoreLib/Internal/Runtime/CompilerServices/Unsafe.cs
index cd3dd052a2..aeff3ce2ca 100644
--- a/src/Common/src/CoreLib/Internal/Runtime/CompilerServices/Unsafe.cs
+++ b/src/Common/src/CoreLib/Internal/Runtime/CompilerServices/Unsafe.cs
@@ -169,6 +169,46 @@ namespace Internal.Runtime.CompilerServices
}
/// <summary>
+ /// Determines whether the memory address referenced by <paramref name="left"/> is greater than
+ /// the memory address referenced by <paramref name="right"/>.
+ /// </summary>
+ /// <remarks>
+ /// This check is conceptually similar to "(void*)(&amp;left) &gt; (void*)(&amp;right)".
+ /// </remarks>
+ [Intrinsic]
+ [NonVersionable]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool IsAddressGreaterThan<T>(ref T left, ref T right)
+ {
+ throw new PlatformNotSupportedException();
+
+ // ldarg.0
+ // ldarg.1
+ // cgt.un
+ // ret
+ }
+
+ /// <summary>
+ /// Determines whether the memory address referenced by <paramref name="left"/> is less than
+ /// the memory address referenced by <paramref name="right"/>.
+ /// </summary>
+ /// <remarks>
+ /// This check is conceptually similar to "(void*)(&amp;left) &lt; (void*)(&amp;right)".
+ /// </remarks>
+ [Intrinsic]
+ [NonVersionable]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool IsAddressLessThan<T>(ref T left, ref T right)
+ {
+ throw new PlatformNotSupportedException();
+
+ // ldarg.0
+ // ldarg.1
+ // clt.un
+ // ret
+ }
+
+ /// <summary>
/// Initializes a block of memory at the given location with a given initial value
/// without assuming architecture dependent alignment of the address.
/// </summary>
diff --git a/src/Common/src/CoreLib/Interop/Unix/Interop.Errors.cs b/src/Common/src/CoreLib/Interop/Unix/Interop.Errors.cs
index 4248434db3..e8aef9903f 100644
--- a/src/Common/src/CoreLib/Interop/Unix/Interop.Errors.cs
+++ b/src/Common/src/CoreLib/Interop/Unix/Interop.Errors.cs
@@ -186,7 +186,7 @@ internal static partial class Interop
internal static extern int ConvertErrorPalToPlatform(Error error);
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_StrErrorR")]
- private static unsafe extern byte* StrErrorR(int platformErrno, byte* buffer, int bufferSize);
+ private static extern unsafe byte* StrErrorR(int platformErrno, byte* buffer, int bufferSize);
}
}
diff --git a/src/Common/src/CoreLib/Interop/Unix/Interop.Libraries.cs b/src/Common/src/CoreLib/Interop/Unix/Interop.Libraries.cs
index 7b3dea453d..02d0092445 100644
--- a/src/Common/src/CoreLib/Interop/Unix/Interop.Libraries.cs
+++ b/src/Common/src/CoreLib/Interop/Unix/Interop.Libraries.cs
@@ -6,7 +6,7 @@ internal static partial class Interop
{
internal static partial class Libraries
{
- internal const string GlobalizationInterop = "System.Globalization.Native";
+ internal const string GlobalizationNative = "System.Globalization.Native";
internal const string SystemNative = "System.Native";
}
}
diff --git a/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Calendar.cs b/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Calendar.cs
index 7b3caeabdd..55553cc7ea 100644
--- a/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Calendar.cs
+++ b/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Calendar.cs
@@ -9,25 +9,25 @@ using System.Text;
internal static partial class Interop
{
- internal static partial class GlobalizationInterop
+ internal static partial class Globalization
{
internal delegate void EnumCalendarInfoCallback(
[MarshalAs(UnmanagedType.LPWStr)] string calendarString,
IntPtr context);
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetCalendars")]
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetCalendars")]
internal static extern int GetCalendars(string localeName, CalendarId[] calendars, int calendarsCapacity);
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetCalendarInfo")]
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetCalendarInfo")]
internal static extern ResultCode GetCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType calendarDataType, [Out] StringBuilder result, int resultCapacity);
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_EnumCalendarInfo")]
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_EnumCalendarInfo")]
internal static extern bool EnumCalendarInfo(EnumCalendarInfoCallback callback, string localeName, CalendarId calendarId, CalendarDataType calendarDataType, IntPtr context);
- [DllImport(Libraries.GlobalizationInterop, EntryPoint = "GlobalizationNative_GetLatestJapaneseEra")]
+ [DllImport(Libraries.GlobalizationNative, EntryPoint = "GlobalizationNative_GetLatestJapaneseEra")]
internal static extern int GetLatestJapaneseEra();
- [DllImport(Libraries.GlobalizationInterop, EntryPoint = "GlobalizationNative_GetJapaneseEraStartDate")]
+ [DllImport(Libraries.GlobalizationNative, EntryPoint = "GlobalizationNative_GetJapaneseEraStartDate")]
internal static extern bool GetJapaneseEraStartDate(int era, out int startYear, out int startMonth, out int startDay);
}
}
diff --git a/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Casing.cs b/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Casing.cs
index 769506b8f6..503a864d69 100644
--- a/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Casing.cs
+++ b/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Casing.cs
@@ -9,15 +9,15 @@ using System.Text;
internal static partial class Interop
{
- internal static partial class GlobalizationInterop
+ internal static partial class Globalization
{
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ChangeCase")]
- internal unsafe static extern void ChangeCase(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper);
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ChangeCase")]
+ internal static extern unsafe void ChangeCase(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper);
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ChangeCaseInvariant")]
- internal unsafe static extern void ChangeCaseInvariant(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper);
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ChangeCaseInvariant")]
+ internal static extern unsafe void ChangeCaseInvariant(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper);
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ChangeCaseTurkish")]
- internal unsafe static extern void ChangeCaseTurkish(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper);
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ChangeCaseTurkish")]
+ internal static extern unsafe void ChangeCaseTurkish(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper);
}
}
diff --git a/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Collation.cs b/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Collation.cs
index 683845dbc1..9942882f1a 100644
--- a/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Collation.cs
+++ b/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Collation.cs
@@ -9,41 +9,53 @@ using System.Security;
internal static partial class Interop
{
- internal static partial class GlobalizationInterop
+ internal static partial class Globalization
{
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetSortHandle")]
- internal unsafe static extern ResultCode GetSortHandle(byte[] localeName, out SafeSortHandle sortHandle);
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetSortHandle")]
+ internal static extern unsafe ResultCode GetSortHandle(byte[] localeName, out SafeSortHandle sortHandle);
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_CloseSortHandle")]
- internal unsafe static extern void CloseSortHandle(IntPtr handle);
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_CloseSortHandle")]
+ internal static extern unsafe void CloseSortHandle(IntPtr handle);
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_CompareString")]
- internal unsafe static extern int CompareString(SafeSortHandle sortHandle, char* lpStr1, int cwStr1Len, char* lpStr2, int cwStr2Len, CompareOptions options);
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_CompareString")]
+ internal static extern unsafe int CompareString(SafeSortHandle sortHandle, char* lpStr1, int cwStr1Len, char* lpStr2, int cwStr2Len, CompareOptions options);
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IndexOf")]
- internal unsafe static extern int IndexOf(SafeSortHandle sortHandle, string target, int cwTargetLength, char* pSource, int cwSourceLength, CompareOptions options, int* matchLengthPtr);
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IndexOf")]
+ internal static extern unsafe int IndexOf(SafeSortHandle sortHandle, string target, int cwTargetLength, char* pSource, int cwSourceLength, CompareOptions options, int* matchLengthPtr);
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IndexOf")]
+ internal static extern unsafe int IndexOf(SafeSortHandle sortHandle, char* target, int cwTargetLength, char* pSource, int cwSourceLength, CompareOptions options, int* matchLengthPtr);
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_LastIndexOf")]
- internal unsafe static extern int LastIndexOf(SafeSortHandle sortHandle, string target, int cwTargetLength, char* pSource, int cwSourceLength, CompareOptions options);
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_LastIndexOf")]
+ internal static extern unsafe int LastIndexOf(SafeSortHandle sortHandle, string target, int cwTargetLength, char* pSource, int cwSourceLength, CompareOptions options);
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IndexOfOrdinalIgnoreCase")]
- internal unsafe static extern int IndexOfOrdinalIgnoreCase(string target, int cwTargetLength, char* pSource, int cwSourceLength, bool findLast);
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IndexOfOrdinalIgnoreCase")]
+ internal static extern unsafe int IndexOfOrdinalIgnoreCase(string target, int cwTargetLength, char* pSource, int cwSourceLength, bool findLast);
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IndexOfOrdinalIgnoreCase")]
+ internal static extern unsafe int IndexOfOrdinalIgnoreCase(char* target, int cwTargetLength, char* pSource, int cwSourceLength, bool findLast);
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_StartsWith")]
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_StartsWith")]
[return: MarshalAs(UnmanagedType.Bool)]
- internal unsafe static extern bool StartsWith(SafeSortHandle sortHandle, string target, int cwTargetLength, string source, int cwSourceLength, CompareOptions options);
+ internal static extern unsafe bool StartsWith(SafeSortHandle sortHandle, char* target, int cwTargetLength, char* source, int cwSourceLength, CompareOptions options);
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_EndsWith")]
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_EndsWith")]
[return: MarshalAs(UnmanagedType.Bool)]
- internal unsafe static extern bool EndsWith(SafeSortHandle sortHandle, string target, int cwTargetLength, string source, int cwSourceLength, CompareOptions options);
+ internal static extern unsafe bool EndsWith(SafeSortHandle sortHandle, char* target, int cwTargetLength, char* source, int cwSourceLength, CompareOptions options);
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetSortKey")]
- internal unsafe static extern int GetSortKey(SafeSortHandle sortHandle, string str, int strLength, byte* sortKey, int sortKeyLength, CompareOptions options);
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_StartsWith")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern unsafe bool StartsWith(SafeSortHandle sortHandle, string target, int cwTargetLength, string source, int cwSourceLength, CompareOptions options);
+
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_EndsWith")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern unsafe bool EndsWith(SafeSortHandle sortHandle, string target, int cwTargetLength, string source, int cwSourceLength, CompareOptions options);
+
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetSortKey")]
+ internal static extern unsafe int GetSortKey(SafeSortHandle sortHandle, string str, int strLength, byte* sortKey, int sortKeyLength, CompareOptions options);
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_CompareStringOrdinalIgnoreCase")]
- internal unsafe static extern int CompareStringOrdinalIgnoreCase(char* lpStr1, int cwStr1Len, char* lpStr2, int cwStr2Len);
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_CompareStringOrdinalIgnoreCase")]
+ internal static extern unsafe int CompareStringOrdinalIgnoreCase(char* lpStr1, int cwStr1Len, char* lpStr2, int cwStr2Len);
- [DllImport(Libraries.GlobalizationInterop, EntryPoint = "GlobalizationNative_GetSortVersion")]
+ [DllImport(Libraries.GlobalizationNative, EntryPoint = "GlobalizationNative_GetSortVersion")]
internal static extern int GetSortVersion(SafeSortHandle sortHandle);
internal class SafeSortHandle : SafeHandle
diff --git a/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.ICU.cs b/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.ICU.cs
index c690884145..a16c813b2f 100644
--- a/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.ICU.cs
+++ b/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.ICU.cs
@@ -8,9 +8,9 @@ using System.Runtime.CompilerServices;
internal static partial class Interop
{
- internal static partial class GlobalizationInterop
+ internal static partial class Globalization
{
- [DllImport(Libraries.GlobalizationInterop, EntryPoint = "GlobalizationNative_LoadICU")]
+ [DllImport(Libraries.GlobalizationNative, EntryPoint = "GlobalizationNative_LoadICU")]
internal static extern int LoadICU();
}
}
diff --git a/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Idna.cs b/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Idna.cs
index 43c72281ae..89b6c3cebe 100644
--- a/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Idna.cs
+++ b/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Idna.cs
@@ -7,15 +7,15 @@ using System.Runtime.InteropServices;
internal static partial class Interop
{
- internal static partial class GlobalizationInterop
+ internal static partial class Globalization
{
internal const int AllowUnassigned = 0x1;
internal const int UseStd3AsciiRules = 0x2;
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ToAscii")]
- internal static unsafe extern int ToAscii(uint flags, char* src, int srcLen, char* dstBuffer, int dstBufferCapacity);
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ToAscii")]
+ internal static extern unsafe int ToAscii(uint flags, char* src, int srcLen, char* dstBuffer, int dstBufferCapacity);
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ToUnicode")]
- internal static unsafe extern int ToUnicode(uint flags, char* src, int srcLen, char* dstBuffer, int dstBufferCapacity);
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ToUnicode")]
+ internal static extern unsafe int ToUnicode(uint flags, char* src, int srcLen, char* dstBuffer, int dstBufferCapacity);
}
}
diff --git a/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Locale.cs b/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Locale.cs
index fcea708ee8..9ef41dedf2 100644
--- a/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Locale.cs
+++ b/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Locale.cs
@@ -8,33 +8,33 @@ using System.Text;
internal static partial class Interop
{
- internal static partial class GlobalizationInterop
+ internal static partial class Globalization
{
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleName")]
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleName")]
[return: MarshalAs(UnmanagedType.Bool)]
- internal unsafe static extern bool GetLocaleName(string localeName, [Out] StringBuilder value, int valueLength);
+ internal static extern unsafe bool GetLocaleName(string localeName, [Out] StringBuilder value, int valueLength);
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleInfoString")]
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleInfoString")]
[return: MarshalAs(UnmanagedType.Bool)]
- internal unsafe static extern bool GetLocaleInfoString(string localeName, uint localeStringData, [Out] StringBuilder value, int valueLength);
+ internal static extern unsafe bool GetLocaleInfoString(string localeName, uint localeStringData, [Out] StringBuilder value, int valueLength);
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetDefaultLocaleName")]
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetDefaultLocaleName")]
[return: MarshalAs(UnmanagedType.Bool)]
- internal unsafe static extern bool GetDefaultLocaleName([Out] StringBuilder value, int valueLength);
+ internal static extern unsafe bool GetDefaultLocaleName([Out] StringBuilder value, int valueLength);
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleTimeFormat")]
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleTimeFormat")]
[return: MarshalAs(UnmanagedType.Bool)]
- internal unsafe static extern bool GetLocaleTimeFormat(string localeName, bool shortFormat, [Out] StringBuilder value, int valueLength);
+ internal static extern unsafe bool GetLocaleTimeFormat(string localeName, bool shortFormat, [Out] StringBuilder value, int valueLength);
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleInfoInt")]
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleInfoInt")]
[return: MarshalAs(UnmanagedType.Bool)]
- internal unsafe static extern bool GetLocaleInfoInt(string localeName, uint localeNumberData, ref int value);
+ internal static extern unsafe bool GetLocaleInfoInt(string localeName, uint localeNumberData, ref int value);
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleInfoGroupingSizes")]
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocaleInfoGroupingSizes")]
[return: MarshalAs(UnmanagedType.Bool)]
- internal unsafe static extern bool GetLocaleInfoGroupingSizes(string localeName, uint localeGroupingData, ref int primaryGroupSize, ref int secondaryGroupSize);
+ internal static extern unsafe bool GetLocaleInfoGroupingSizes(string localeName, uint localeGroupingData, ref int primaryGroupSize, ref int secondaryGroupSize);
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocales")]
- internal unsafe static extern int GetLocales([Out] Char[] value, int valueLength);
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetLocales")]
+ internal static extern unsafe int GetLocales([Out] Char[] value, int valueLength);
}
}
diff --git a/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Normalization.cs b/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Normalization.cs
index c4cb9fb851..d442da0ea1 100644
--- a/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Normalization.cs
+++ b/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Normalization.cs
@@ -8,12 +8,12 @@ using System.Text;
internal static partial class Interop
{
- internal static partial class GlobalizationInterop
+ internal static partial class Globalization
{
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IsNormalized")]
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IsNormalized")]
internal static extern int IsNormalized(NormalizationForm normalizationForm, string src, int srcLen);
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_NormalizeString")]
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_NormalizeString")]
internal static extern int NormalizeString(NormalizationForm normalizationForm, string src, int srcLen, [Out] char[] dstBuffer, int dstBufferCapacity);
}
}
diff --git a/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.ResultCode.cs b/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.ResultCode.cs
index cca6ae4dcb..4a9933f929 100644
--- a/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.ResultCode.cs
+++ b/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.ResultCode.cs
@@ -4,7 +4,7 @@
internal static partial class Interop
{
- internal static partial class GlobalizationInterop
+ internal static partial class Globalization
{
// needs to be kept in sync with ResultCode in System.Globalization.Native
internal enum ResultCode
diff --git a/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.TimeZoneInfo.cs b/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.TimeZoneInfo.cs
index 271ec3f9dc..47cf26662b 100644
--- a/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.TimeZoneInfo.cs
+++ b/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.TimeZoneInfo.cs
@@ -7,7 +7,7 @@ using System.Text;
internal static partial class Interop
{
- internal static partial class GlobalizationInterop
+ internal static partial class Globalization
{
// needs to be kept in sync with TimeZoneDisplayNameType in System.Globalization.Native
internal enum TimeZoneDisplayNameType
@@ -17,7 +17,7 @@ internal static partial class Interop
DaylightSavings = 2,
}
- [DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetTimeZoneDisplayName")]
+ [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_GetTimeZoneDisplayName")]
internal static extern ResultCode GetTimeZoneDisplayName(
string localeName,
string timeZoneId,
diff --git a/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Utils.cs b/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Utils.cs
index 33b10c0d74..9887bd4f0b 100644
--- a/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Utils.cs
+++ b/src/Common/src/CoreLib/Interop/Unix/System.Globalization.Native/Interop.Utils.cs
@@ -13,7 +13,7 @@ internal static partial class Interop
/// increasing buffer until the size is big enough.
/// </summary>
internal static bool CallStringMethod<TArg1, TArg2, TArg3>(
- Func<TArg1, TArg2, TArg3, StringBuilder, GlobalizationInterop.ResultCode> interopCall,
+ Func<TArg1, TArg2, TArg3, StringBuilder, Interop.Globalization.ResultCode> interopCall,
TArg1 arg1,
TArg2 arg2,
TArg3 arg3,
@@ -26,14 +26,14 @@ internal static partial class Interop
for (int i = 0; i < maxDoubleAttempts; i++)
{
- GlobalizationInterop.ResultCode resultCode = interopCall(arg1, arg2, arg3, stringBuilder);
+ Interop.Globalization.ResultCode resultCode = interopCall(arg1, arg2, arg3, stringBuilder);
- if (resultCode == GlobalizationInterop.ResultCode.Success)
+ if (resultCode == Interop.Globalization.ResultCode.Success)
{
result = StringBuilderCache.GetStringAndRelease(stringBuilder);
return true;
}
- else if (resultCode == GlobalizationInterop.ResultCode.InsufficentBuffer)
+ else if (resultCode == Interop.Globalization.ResultCode.InsufficentBuffer)
{
// increase the string size and loop
stringBuilder.EnsureCapacity(stringBuilder.Capacity * 2);
diff --git a/src/Common/src/CoreLib/Interop/Unix/System.Native/Interop.GetRandomBytes.cs b/src/Common/src/CoreLib/Interop/Unix/System.Native/Interop.GetRandomBytes.cs
index 62156e8d8e..e911b13583 100644
--- a/src/Common/src/CoreLib/Interop/Unix/System.Native/Interop.GetRandomBytes.cs
+++ b/src/Common/src/CoreLib/Interop/Unix/System.Native/Interop.GetRandomBytes.cs
@@ -11,7 +11,7 @@ internal partial class Interop
internal unsafe partial class Sys
{
[DllImport(Interop.Libraries.SystemNative, EntryPoint = "SystemNative_GetNonCryptographicallySecureRandomBytes")]
- internal static unsafe extern void GetNonCryptographicallySecureRandomBytes(byte* buffer, int length);
+ internal static extern unsafe void GetNonCryptographicallySecureRandomBytes(byte* buffer, int length);
}
internal static unsafe void GetRandomBytes(byte* buffer, int length)
diff --git a/src/Common/src/CoreLib/Interop/Unix/System.Native/Interop.PathConf.cs b/src/Common/src/CoreLib/Interop/Unix/System.Native/Interop.PathConf.cs
index eb9e32db0c..7213cb0264 100644
--- a/src/Common/src/CoreLib/Interop/Unix/System.Native/Interop.PathConf.cs
+++ b/src/Common/src/CoreLib/Interop/Unix/System.Native/Interop.PathConf.cs
@@ -9,8 +9,6 @@ internal static partial class Interop
{
internal static partial class Sys
{
- internal static int DEFAULT_PC_NAME_MAX = 255;
-
internal enum PathConfName : int
{
PC_LINK_MAX = 1,
diff --git a/src/Common/src/CoreLib/Interop/Unix/System.Native/Interop.Read.cs b/src/Common/src/CoreLib/Interop/Unix/System.Native/Interop.Read.cs
index 812ae348dc..1be5e789c2 100644
--- a/src/Common/src/CoreLib/Interop/Unix/System.Native/Interop.Read.cs
+++ b/src/Common/src/CoreLib/Interop/Unix/System.Native/Interop.Read.cs
@@ -20,6 +20,6 @@ internal static partial class Interop
/// Note - on fail. the position of the stream may change depending on the platform; consult man 2 read for more info
/// </returns>
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_Read", SetLastError = true)]
- internal static unsafe extern int Read(SafeFileHandle fd, byte* buffer, int count);
+ internal static extern unsafe int Read(SafeFileHandle fd, byte* buffer, int count);
}
}
diff --git a/src/Common/src/CoreLib/Interop/Unix/System.Native/Interop.ReadDir.cs b/src/Common/src/CoreLib/Interop/Unix/System.Native/Interop.ReadDir.cs
new file mode 100644
index 0000000000..d98c4285c0
--- /dev/null
+++ b/src/Common/src/CoreLib/Interop/Unix/System.Native/Interop.ReadDir.cs
@@ -0,0 +1,102 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+using System.Threading;
+using Microsoft.Win32.SafeHandles;
+
+internal static partial class Interop
+{
+ internal static partial class Sys
+ {
+ private static readonly int s_readBufferSize = GetReadDirRBufferSize();
+
+ internal enum NodeType : int
+ {
+ DT_UNKNOWN = 0,
+ DT_FIFO = 1,
+ DT_CHR = 2,
+ DT_DIR = 4,
+ DT_BLK = 6,
+ DT_REG = 8,
+ DT_LNK = 10,
+ DT_SOCK = 12,
+ DT_WHT = 14
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private unsafe struct InternalDirectoryEntry
+ {
+ internal IntPtr Name;
+ internal int NameLength;
+ internal NodeType InodeType;
+ }
+
+ internal struct DirectoryEntry
+ {
+ internal NodeType InodeType;
+ internal string InodeName;
+ }
+
+ [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_OpenDir", SetLastError = true)]
+ internal static extern Microsoft.Win32.SafeHandles.SafeDirectoryHandle OpenDir(string path);
+
+ [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetReadDirRBufferSize", SetLastError = false)]
+ internal static extern int GetReadDirRBufferSize();
+
+ [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_ReadDirR", SetLastError = false)]
+ private static extern unsafe int ReadDirR(IntPtr dir, byte* buffer, int bufferSize, out InternalDirectoryEntry outputEntry);
+
+ [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_CloseDir", SetLastError = true)]
+ internal static extern int CloseDir(IntPtr dir);
+
+ // The calling pattern for ReadDir is described in src/Native/System.Native/pal_readdir.cpp
+ internal static int ReadDir(SafeDirectoryHandle dir, out DirectoryEntry outputEntry)
+ {
+ bool addedRef = false;
+ try
+ {
+ // We avoid a native string copy into InternalDirectoryEntry.
+ // - If the platform suppors reading into a buffer, the data is read directly into the buffer. The
+ // data can be read as long as the buffer is valid.
+ // - If the platform does not support reading into a buffer, the information returned in
+ // InternalDirectoryEntry points to native memory owned by the SafeDirectoryHandle. The data is only
+ // valid until the next call to CloseDir/ReadDir. We extend the reference until we have copied all data
+ // to ensure it does not become invalid by a CloseDir; and we copy the data so our caller does not
+ // use the native memory held by the SafeDirectoryHandle.
+ dir.DangerousAddRef(ref addedRef);
+
+ unsafe
+ {
+ // s_readBufferSize is zero when the native implementation does not support reading into a buffer.
+ byte* buffer = stackalloc byte[s_readBufferSize];
+ InternalDirectoryEntry temp;
+ int ret = ReadDirR(dir.DangerousGetHandle(), buffer, s_readBufferSize, out temp);
+ // We copy data into DirectoryEntry to ensure there are no dangling references.
+ outputEntry = ret == 0 ?
+ new DirectoryEntry() { InodeName = GetDirectoryEntryName(temp), InodeType = temp.InodeType } :
+ default(DirectoryEntry);
+
+ return ret;
+ }
+ }
+ finally
+ {
+ if (addedRef)
+ {
+ dir.DangerousRelease();
+ }
+ }
+ }
+
+ private static unsafe string GetDirectoryEntryName(InternalDirectoryEntry dirEnt)
+ {
+ if (dirEnt.NameLength == -1)
+ return Marshal.PtrToStringAnsi(dirEnt.Name);
+ else
+ return Marshal.PtrToStringAnsi(dirEnt.Name, dirEnt.NameLength);
+ }
+ }
+}
diff --git a/src/Common/src/CoreLib/Interop/Unix/System.Native/Interop.Write.cs b/src/Common/src/CoreLib/Interop/Unix/System.Native/Interop.Write.cs
index c14fc26263..0636615a8b 100644
--- a/src/Common/src/CoreLib/Interop/Unix/System.Native/Interop.Write.cs
+++ b/src/Common/src/CoreLib/Interop/Unix/System.Native/Interop.Write.cs
@@ -19,9 +19,9 @@ internal static partial class Interop
/// Returns the number of bytes written on success; otherwise, returns -1 and sets errno
/// </returns>
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_Write", SetLastError = true)]
- internal static unsafe extern int Write(SafeFileHandle fd, byte* buffer, int bufferSize);
+ internal static extern unsafe int Write(SafeFileHandle fd, byte* buffer, int bufferSize);
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_Write", SetLastError = true)]
- internal static unsafe extern int Write(int fd, byte* buffer, int bufferSize);
+ internal static extern unsafe int Write(int fd, byte* buffer, int bufferSize);
}
}
diff --git a/src/Common/src/CoreLib/Interop/Windows/BCrypt/Interop.BCryptGenRandom.cs b/src/Common/src/CoreLib/Interop/Windows/BCrypt/Interop.BCryptGenRandom.cs
index bc357125b5..75288accd9 100644
--- a/src/Common/src/CoreLib/Interop/Windows/BCrypt/Interop.BCryptGenRandom.cs
+++ b/src/Common/src/CoreLib/Interop/Windows/BCrypt/Interop.BCryptGenRandom.cs
@@ -23,7 +23,7 @@ internal partial class Interop
internal const int STATUS_NO_MEMORY = unchecked((int)0xC0000017);
[DllImport(Libraries.BCrypt, CharSet = CharSet.Unicode)]
- private static unsafe extern int BCryptGenRandom(IntPtr hAlgorithm, byte* pbBuffer, int cbBuffer, int dwFlags);
+ private static extern unsafe int BCryptGenRandom(IntPtr hAlgorithm, byte* pbBuffer, int cbBuffer, int dwFlags);
}
internal static unsafe void GetRandomBytes(byte* buffer, int length)
diff --git a/src/Common/src/CoreLib/Interop/Windows/Interop.Errors.cs b/src/Common/src/CoreLib/Interop/Windows/Interop.Errors.cs
index ec52a81bf6..7f907fb6ca 100644
--- a/src/Common/src/CoreLib/Interop/Windows/Interop.Errors.cs
+++ b/src/Common/src/CoreLib/Interop/Windows/Interop.Errors.cs
@@ -39,6 +39,7 @@ internal partial class Interop
internal const int ERROR_NO_UNICODE_TRANSLATION = 0x459;
internal const int ERROR_NOT_FOUND = 0x490;
internal const int ERROR_BAD_IMPERSONATION_LEVEL = 0x542;
+ internal const int ERROR_NO_SYSTEM_RESOURCES = 0x5AA;
internal const int E_FILENOTFOUND = unchecked((int)0x80070002);
internal const int ERROR_TIMEOUT = 0x000005B4;
}
diff --git a/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.FindClose.cs b/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.FindClose.cs
index 03d8c8b323..fcf9254aca 100644
--- a/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.FindClose.cs
+++ b/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.FindClose.cs
@@ -11,6 +11,6 @@ internal partial class Interop
internal partial class Kernel32
{
[DllImport(Libraries.Kernel32, SetLastError = true)]
- internal extern static bool FindClose(IntPtr hFindFile);
+ internal static extern bool FindClose(IntPtr hFindFile);
}
}
diff --git a/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetFileAttributesEx.cs b/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetFileAttributesEx.cs
index 4cce56bd05..181fb10105 100644
--- a/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetFileAttributesEx.cs
+++ b/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetFileAttributesEx.cs
@@ -31,7 +31,7 @@ internal partial class Interop
internal struct WIN32_FILE_ATTRIBUTE_DATA
{
- internal int fileAttributes;
+ internal int dwFileAttributes;
internal uint ftCreationTimeLow;
internal uint ftCreationTimeHigh;
internal uint ftLastAccessTimeLow;
@@ -44,7 +44,7 @@ internal partial class Interop
internal void PopulateFrom(ref WIN32_FIND_DATA findData)
{
// Copy the information to data
- fileAttributes = (int)findData.dwFileAttributes;
+ dwFileAttributes = (int)findData.dwFileAttributes;
ftCreationTimeLow = findData.ftCreationTime.dwLowDateTime;
ftCreationTimeHigh = findData.ftCreationTime.dwHighDateTime;
ftLastAccessTimeLow = findData.ftLastAccessTime.dwLowDateTime;
diff --git a/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetFileType_SafeHandle.cs b/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetFileType_SafeHandle.cs
index c07a1683a5..faa57cc2f1 100644
--- a/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetFileType_SafeHandle.cs
+++ b/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetFileType_SafeHandle.cs
@@ -10,6 +10,6 @@ internal partial class Interop
internal partial class Kernel32
{
[DllImport(Libraries.Kernel32, SetLastError = true)]
- internal extern static int GetFileType(SafeHandle hFile);
+ internal static extern int GetFileType(SafeHandle hFile);
}
}
diff --git a/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetFullPathNameW.cs b/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetFullPathNameW.cs
index 15dd581113..2f3aad85cc 100644
--- a/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetFullPathNameW.cs
+++ b/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetFullPathNameW.cs
@@ -13,6 +13,18 @@ internal partial class Interop
/// WARNING: This method does not implicitly handle long paths. Use GetFullPathName or PathHelper.
/// </summary>
[DllImport(Libraries.Kernel32, SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)]
- unsafe internal static extern uint GetFullPathNameW(char* path, uint numBufferChars, char[] buffer, IntPtr mustBeZero);
+#if PROJECTN
+ internal static extern unsafe uint GetFullPathNameW(char* lpFileName, uint nBufferLength, char* lpBuffer, IntPtr lpFilePart);
+
+ // Works around https://devdiv.visualstudio.com/web/wi.aspx?pcguid=011b8bdf-6d56-4f87-be0d-0092136884d9&id=575202
+ internal static unsafe uint GetFullPathNameW(ref char lpFileName, uint nBufferLength, ref char lpBuffer, IntPtr lpFilePart)
+ {
+ fixed (char* pBuffer = &lpBuffer)
+ fixed (char* pFileName = &lpFileName)
+ return GetFullPathNameW(pFileName, nBufferLength, pBuffer, lpFilePart);
+ }
+#else
+ internal static extern uint GetFullPathNameW(ref char lpFileName, uint nBufferLength, ref char lpBuffer, IntPtr lpFilePart);
+#endif
}
}
diff --git a/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetLongPathNameW.cs b/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetLongPathNameW.cs
index ce04078af5..ef8fd36aa1 100644
--- a/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetLongPathNameW.cs
+++ b/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetLongPathNameW.cs
@@ -13,6 +13,18 @@ internal partial class Interop
/// WARNING: This method does not implicitly handle long paths. Use GetFullPath/PathHelper.
/// </summary>
[DllImport(Libraries.Kernel32, SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)]
- internal static extern uint GetLongPathNameW(char[] lpszShortPath, char[] lpszLongPath, uint cchBuffer);
+#if PROJECTN
+ internal static extern unsafe uint GetLongPathNameW(char* lpszShortPath, char* lpszLongPath, uint cchBuffer);
+
+ // Works around https://devdiv.visualstudio.com/web/wi.aspx?pcguid=011b8bdf-6d56-4f87-be0d-0092136884d9&id=575202
+ internal static unsafe uint GetLongPathNameW(ref char lpszShortPath, ref char lpszLongPath, uint cchBuffer)
+ {
+ fixed (char* plpszLongPath = &lpszLongPath)
+ fixed (char* plpszShortPath = &lpszShortPath)
+ return GetLongPathNameW(plpszShortPath, plpszLongPath, cchBuffer);
+ }
+#else
+ internal static extern uint GetLongPathNameW(ref char lpszShortPath, ref char lpszLongPath, uint cchBuffer);
+#endif
}
}
diff --git a/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetTempFileNameW.cs b/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetTempFileNameW.cs
index 36673895b4..92da88c5df 100644
--- a/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetTempFileNameW.cs
+++ b/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetTempFileNameW.cs
@@ -2,8 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System;
-using System.Text;
using System.Runtime.InteropServices;
internal partial class Interop
@@ -11,6 +9,18 @@ internal partial class Interop
internal partial class Kernel32
{
[DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, BestFitMapping = false)]
- internal static extern uint GetTempFileNameW(string tmpPath, string prefix, uint uniqueIdOrZero, [Out]StringBuilder tmpFileName);
+#if PROJECTN
+ internal static extern unsafe uint GetTempFileNameW(char* lpPathName, string lpPrefixString, uint uUnique, char* lpTempFileName);
+
+ // Works around https://devdiv.visualstudio.com/web/wi.aspx?pcguid=011b8bdf-6d56-4f87-be0d-0092136884d9&id=575202
+ internal static unsafe uint GetTempFileNameW(ref char lpPathName, string lpPrefixString, uint uUnique, ref char lpTempFileName)
+ {
+ fixed (char* plpPathName = &lpPathName)
+ fixed (char* plpTempFileName = &lpTempFileName)
+ return GetTempFileNameW(plpPathName, lpPrefixString, uUnique, plpTempFileName);
+ }
+#else
+ internal static extern uint GetTempFileNameW(ref char lpPathName, string lpPrefixString, uint uUnique, ref char lpTempFileName);
+#endif
}
}
diff --git a/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetTempPathW.cs b/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetTempPathW.cs
index ff2783be26..19dbae346b 100644
--- a/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetTempPathW.cs
+++ b/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.GetTempPathW.cs
@@ -2,8 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.IO;
-using System.Text;
using System.Runtime.InteropServices;
internal partial class Interop
@@ -11,6 +9,17 @@ internal partial class Interop
internal partial class Kernel32
{
[DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, BestFitMapping = false)]
- internal static extern uint GetTempPathW(int bufferLen, [Out]StringBuilder buffer);
+#if PROJECTN
+ internal static extern unsafe uint GetTempPathW(int bufferLen, char* buffer);
+
+ // Works around https://devdiv.visualstudio.com/web/wi.aspx?pcguid=011b8bdf-6d56-4f87-be0d-0092136884d9&id=575202
+ internal static unsafe uint GetTempPathW(int bufferLen, ref char buffer)
+ {
+ fixed (char* pbuffer = &buffer)
+ return GetTempPathW(bufferLen, pbuffer);
+ }
+#else
+ internal static extern uint GetTempPathW(int bufferLen, ref char buffer);
+#endif
}
}
diff --git a/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.Globalization.cs b/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.Globalization.cs
index 00bec5d3e2..2227d59b0e 100644
--- a/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.Globalization.cs
+++ b/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.Globalization.cs
@@ -18,13 +18,13 @@ internal static partial class Interop
internal const int COMPARE_STRING = 0x0001;
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
- internal extern static unsafe int LCIDToLocaleName(int locale, char *pLocaleName, int cchName, uint dwFlags);
+ internal static extern unsafe int LCIDToLocaleName(int locale, char *pLocaleName, int cchName, uint dwFlags);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
- internal extern static int LocaleNameToLCID(string lpName, uint dwFlags);
+ internal static extern int LocaleNameToLCID(string lpName, uint dwFlags);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
- internal extern static unsafe int LCMapStringEx(
+ internal static extern unsafe int LCMapStringEx(
string lpLocaleName,
uint dwMapFlags,
char* lpSrcStr,
@@ -36,7 +36,7 @@ internal static partial class Interop
IntPtr sortHandle);
[DllImport("kernel32.dll", EntryPoint = "FindNLSStringEx")]
- internal extern static unsafe int FindNLSStringEx(
+ internal static extern unsafe int FindNLSStringEx(
char* lpLocaleName,
uint dwFindNLSStringFlags,
char* lpStringSource,
@@ -49,7 +49,7 @@ internal static partial class Interop
IntPtr sortHandle);
[DllImport("kernel32.dll", EntryPoint = "CompareStringEx")]
- internal extern static unsafe int CompareStringEx(
+ internal static extern unsafe int CompareStringEx(
char* lpLocaleName,
uint dwCmpFlags,
char* lpString1,
@@ -61,7 +61,7 @@ internal static partial class Interop
IntPtr lParam);
[DllImport("kernel32.dll", EntryPoint = "CompareStringOrdinal")]
- internal extern static unsafe int CompareStringOrdinal(
+ internal static extern unsafe int CompareStringOrdinal(
char* lpString1,
int cchCount1,
char* lpString2,
@@ -69,7 +69,7 @@ internal static partial class Interop
bool bIgnoreCase);
[DllImport("kernel32.dll", EntryPoint = "FindStringOrdinal")]
- internal extern static unsafe int FindStringOrdinal(
+ internal static extern unsafe int FindStringOrdinal(
uint dwFindStringOrdinalFlags,
char* lpStringSource,
int cchSource,
@@ -78,42 +78,42 @@ internal static partial class Interop
int bIgnoreCase);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
- internal extern static unsafe bool IsNLSDefinedString(
+ internal static extern unsafe bool IsNLSDefinedString(
int Function,
uint dwFlags,
IntPtr lpVersionInformation,
char* lpString,
int cchStr);
-#if !PROJECTN
+#if !ENABLE_WINRT
[DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
internal static extern bool GetUserPreferredUILanguages(uint dwFlags, out uint pulNumLanguages, char [] pwszLanguagesBuffer, ref uint pcchLanguagesBuffer);
-#endif //!PROJECTN
+#endif //!ENABLE_WINRT
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
internal static extern int GetLocaleInfoEx(string lpLocaleName, uint LCType, void* lpLCData, int cchData);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
- internal extern static bool EnumSystemLocalesEx(EnumLocalesProcEx lpLocaleEnumProcEx, uint dwFlags, void* lParam, IntPtr reserved);
+ internal static extern bool EnumSystemLocalesEx(EnumLocalesProcEx lpLocaleEnumProcEx, uint dwFlags, void* lParam, IntPtr reserved);
internal delegate BOOL EnumLocalesProcEx(char* lpLocaleString, uint dwFlags, void* lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
- internal extern static int ResolveLocaleName(string lpNameToResolve, char* lpLocaleName, int cchLocaleName);
+ internal static extern int ResolveLocaleName(string lpNameToResolve, char* lpLocaleName, int cchLocaleName);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
- internal extern static bool EnumTimeFormatsEx(EnumTimeFormatsProcEx lpTimeFmtEnumProcEx, string lpLocaleName, uint dwFlags, void* lParam);
+ internal static extern bool EnumTimeFormatsEx(EnumTimeFormatsProcEx lpTimeFmtEnumProcEx, string lpLocaleName, uint dwFlags, void* lParam);
internal delegate BOOL EnumTimeFormatsProcEx(char* lpTimeFormatString, void* lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
- internal extern static int GetCalendarInfoEx(string lpLocaleName, uint Calendar, IntPtr lpReserved, uint CalType, IntPtr lpCalData, int cchData, out int lpValue);
+ internal static extern int GetCalendarInfoEx(string lpLocaleName, uint Calendar, IntPtr lpReserved, uint CalType, IntPtr lpCalData, int cchData, out int lpValue);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
- internal extern static int GetCalendarInfoEx(string lpLocaleName, uint Calendar, IntPtr lpReserved, uint CalType, IntPtr lpCalData, int cchData, IntPtr lpValue);
+ internal static extern int GetCalendarInfoEx(string lpLocaleName, uint Calendar, IntPtr lpReserved, uint CalType, IntPtr lpCalData, int cchData, IntPtr lpValue);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
- internal extern static bool EnumCalendarInfoExEx(EnumCalendarInfoProcExEx pCalInfoEnumProcExEx, string lpLocaleName, uint Calendar, string lpReserved, uint CalType, void* lParam);
+ internal static extern bool EnumCalendarInfoExEx(EnumCalendarInfoProcExEx pCalInfoEnumProcExEx, string lpLocaleName, uint Calendar, string lpReserved, uint CalType, void* lParam);
internal delegate BOOL EnumCalendarInfoProcExEx(char* lpCalendarInfoString, uint Calendar, IntPtr lpReserved, void* lParam);
@@ -128,6 +128,6 @@ internal static partial class Interop
}
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
- internal extern static unsafe bool GetNLSVersionEx(int function, string localeName, NlsVersionInfoEx* lpVersionInformation);
+ internal static extern unsafe bool GetNLSVersionEx(int function, string localeName, NlsVersionInfoEx* lpVersionInformation);
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/IExprWithObject.cs b/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.MAX_PATH.cs
index 98929888ba..f7fa32669b 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/IExprWithObject.cs
+++ b/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.MAX_PATH.cs
@@ -2,10 +2,10 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-namespace Microsoft.CSharp.RuntimeBinder.Semantics
+internal partial class Interop
{
- internal interface IExprWithObject
+ internal partial class Kernel32
{
- Expr OptionalObject { get; set; }
+ internal const int MAX_PATH = 260;
}
}
diff --git a/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/Native/Interop.localization.cs b/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.MUI.cs
index d0f9190535..6ed7aa2dc4 100644
--- a/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/Native/Interop.localization.cs
+++ b/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.MUI.cs
@@ -3,19 +3,16 @@
// See the LICENSE file in the project root for more information.
using System;
-using System.Text;
-using System.Diagnostics;
using System.Runtime.InteropServices;
-
-using Internal.Cryptography.Pal.Native;
+using System.Text;
internal static partial class Interop
{
- public static class localization
+ internal static partial class Kernel32
{
- [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, EntryPoint = "FormatMessageW")]
- public static extern int FormatMessage(FormatMessageFlags dwFlags, IntPtr lpSource, int dwMessageId, int dwLanguageId, [Out] StringBuilder lpBuffer, int nSize, IntPtr Arguments);
+ internal const uint MUI_PREFERRED_UI_LANGUAGES = 0x10;
+
+ [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]
+ internal static extern bool GetFileMUIPath(uint flags, String filePath, [Out] StringBuilder language, ref int languageLength, [Out] StringBuilder fileMuiPath, ref int fileMuiPathLength, ref Int64 enumerator);
}
}
-
-
diff --git a/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.MultiByteToWideChar.cs b/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.MultiByteToWideChar.cs
new file mode 100644
index 0000000000..158e4db3fd
--- /dev/null
+++ b/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.MultiByteToWideChar.cs
@@ -0,0 +1,20 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class Kernel32
+ {
+ [DllImport(Libraries.Kernel32)]
+ internal static extern unsafe int MultiByteToWideChar(
+ uint CodePage, uint dwFlags,
+ byte* lpMultiByteStr, int cbMultiByte,
+ char* lpWideCharStr, int cchWideChar);
+
+ internal const uint MB_PRECOMPOSED = 0x00000001;
+ }
+}
diff --git a/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.TimeZone.Registry.cs b/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.TimeZone.Registry.cs
new file mode 100644
index 0000000000..062d1caeba
--- /dev/null
+++ b/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.TimeZone.Registry.cs
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal static partial class Interop
+{
+ internal static partial class Kernel32
+ {
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct REG_TZI_FORMAT
+ {
+ internal int Bias;
+ internal int StandardBias;
+ internal int DaylightBias;
+ internal SYSTEMTIME StandardDate;
+ internal SYSTEMTIME DaylightDate;
+
+ internal REG_TZI_FORMAT(in TIME_ZONE_INFORMATION tzi)
+ {
+ Bias = tzi.Bias;
+ StandardDate = tzi.StandardDate;
+ StandardBias = tzi.StandardBias;
+ DaylightDate = tzi.DaylightDate;
+ DaylightBias = tzi.DaylightBias;
+ }
+ }
+ }
+}
diff --git a/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.TimeZone.cs b/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.TimeZone.cs
new file mode 100644
index 0000000000..68d4583b54
--- /dev/null
+++ b/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.TimeZone.cs
@@ -0,0 +1,94 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal static partial class Interop
+{
+ internal static partial class Kernel32
+ {
+ internal struct SYSTEMTIME
+ {
+ internal ushort Year;
+ internal ushort Month;
+ internal ushort DayOfWeek;
+ internal ushort Day;
+ internal ushort Hour;
+ internal ushort Minute;
+ internal ushort Second;
+ internal ushort Milliseconds;
+
+ internal bool Equals(in SYSTEMTIME other) =>
+ Year == other.Year &&
+ Month == other.Month &&
+ DayOfWeek == other.DayOfWeek &&
+ Day == other.Day &&
+ Hour == other.Hour &&
+ Minute == other.Minute &&
+ Second == other.Second &&
+ Milliseconds == other.Milliseconds;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ internal unsafe struct TIME_DYNAMIC_ZONE_INFORMATION
+ {
+ internal int Bias;
+ internal fixed char StandardName[32];
+ internal SYSTEMTIME StandardDate;
+ internal int StandardBias;
+ internal fixed char DaylightName[32];
+ internal SYSTEMTIME DaylightDate;
+ internal int DaylightBias;
+ internal fixed char TimeZoneKeyName[128];
+ internal byte DynamicDaylightTimeDisabled;
+
+ internal string GetTimeZoneKeyName()
+ {
+ fixed (char* p = TimeZoneKeyName)
+ return new string(p);
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ internal unsafe struct TIME_ZONE_INFORMATION
+ {
+ internal int Bias;
+ internal fixed char StandardName[32];
+ internal SYSTEMTIME StandardDate;
+ internal int StandardBias;
+ internal fixed char DaylightName[32];
+ internal SYSTEMTIME DaylightDate;
+ internal int DaylightBias;
+
+ internal TIME_ZONE_INFORMATION(in TIME_DYNAMIC_ZONE_INFORMATION dtzi)
+ {
+ // The start of TIME_DYNAMIC_ZONE_INFORMATION has identical layout as TIME_ZONE_INFORMATION
+ fixed (TIME_ZONE_INFORMATION* pTo = &this)
+ fixed (TIME_DYNAMIC_ZONE_INFORMATION* pFrom = &dtzi)
+ *pTo = *(TIME_ZONE_INFORMATION*)pFrom;
+ }
+
+ internal string GetStandardName()
+ {
+ fixed (char* p = StandardName)
+ return new string(p);
+ }
+
+ internal string GetDaylightName()
+ {
+ fixed (char* p = DaylightName)
+ return new string(p);
+ }
+ }
+
+ internal const uint TIME_ZONE_ID_INVALID = unchecked((uint)-1);
+
+ [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]
+ internal static extern uint GetDynamicTimeZoneInformation(out TIME_DYNAMIC_ZONE_INFORMATION pTimeZoneInformation);
+
+ [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]
+ internal static extern uint GetTimeZoneInformation(out TIME_ZONE_INFORMATION lpTimeZoneInformation);
+ }
+}
diff --git a/src/Common/src/CoreLib/Interop/Windows/Ole32/Interop.CoCreateGuid.cs b/src/Common/src/CoreLib/Interop/Windows/Ole32/Interop.CoCreateGuid.cs
new file mode 100644
index 0000000000..57accbe7c0
--- /dev/null
+++ b/src/Common/src/CoreLib/Interop/Windows/Ole32/Interop.CoCreateGuid.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal static partial class Interop
+{
+ internal static partial class Ole32
+ {
+ [DllImport(Interop.Libraries.Ole32)]
+ internal static extern int CoCreateGuid(out Guid guid);
+ }
+}
diff --git a/src/Common/src/CoreLib/Microsoft/Win32/SafeHandles/SafeDirectoryHandle.Unix.cs b/src/Common/src/CoreLib/Microsoft/Win32/SafeHandles/SafeDirectoryHandle.Unix.cs
new file mode 100644
index 0000000000..f7435eaae1
--- /dev/null
+++ b/src/Common/src/CoreLib/Microsoft/Win32/SafeHandles/SafeDirectoryHandle.Unix.cs
@@ -0,0 +1,26 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace Microsoft.Win32.SafeHandles
+{
+ internal sealed class SafeDirectoryHandle : SafeHandle
+ {
+ private SafeDirectoryHandle() : base(IntPtr.Zero, true)
+ {
+ }
+
+ protected override bool ReleaseHandle()
+ {
+ return Interop.Sys.CloseDir(handle) == 0;
+ }
+
+ public override bool IsInvalid
+ {
+ get { return handle == IntPtr.Zero; }
+ }
+ }
+}
diff --git a/src/Common/src/CoreLib/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs b/src/Common/src/CoreLib/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs
index f28f44fdad..b284c116ba 100644
--- a/src/Common/src/CoreLib/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs
+++ b/src/Common/src/CoreLib/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs
@@ -83,10 +83,7 @@ namespace Microsoft.Win32.SafeHandles
private static bool DirectoryExists(string fullPath)
{
- int fileType = Interop.Sys.FileTypes.S_IFDIR;
-
Interop.Sys.FileStatus fileinfo;
- Interop.ErrorInfo errorInfo = default(Interop.ErrorInfo);
// First use stat, as we want to follow symlinks. If that fails, it could be because the symlink
// is broken, we don't have permissions, etc., in which case fall back to using LStat to evaluate
@@ -94,16 +91,10 @@ namespace Microsoft.Win32.SafeHandles
if (Interop.Sys.Stat(fullPath, out fileinfo) < 0 &&
Interop.Sys.LStat(fullPath, out fileinfo) < 0)
{
- errorInfo = Interop.Sys.GetLastErrorInfo();
return false;
}
- // Something exists at this path. If the caller is asking for a directory, return true if it's
- // a directory and false for everything else. If the caller is asking for a file, return false for
- // a directory and true for everything else.
- return
- (fileType == Interop.Sys.FileTypes.S_IFDIR) ==
- ((fileinfo.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFDIR);
+ return ((fileinfo.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFDIR);
}
/// <summary>Opens a SafeFileHandle for a file descriptor created by a provided delegate.</summary>
diff --git a/src/Common/src/CoreLib/Microsoft/Win32/SafeHandles/SafeFindHandle.Windows.cs b/src/Common/src/CoreLib/Microsoft/Win32/SafeHandles/SafeFindHandle.Windows.cs
new file mode 100644
index 0000000000..4ba05409fd
--- /dev/null
+++ b/src/Common/src/CoreLib/Microsoft/Win32/SafeHandles/SafeFindHandle.Windows.cs
@@ -0,0 +1,22 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Security;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using Microsoft.Win32;
+
+namespace Microsoft.Win32.SafeHandles
+{
+ internal sealed class SafeFindHandle : SafeHandleZeroOrMinusOneIsInvalid
+ {
+ internal SafeFindHandle() : base(true) { }
+
+ override protected bool ReleaseHandle()
+ {
+ return Interop.Kernel32.FindClose(handle);
+ }
+ }
+}
diff --git a/src/Common/src/CoreLib/System.Private.CoreLib.Shared.projitems b/src/Common/src/CoreLib/System.Private.CoreLib.Shared.projitems
index e49edfd367..1143580173 100644
--- a/src/Common/src/CoreLib/System.Private.CoreLib.Shared.projitems
+++ b/src/Common/src/CoreLib/System.Private.CoreLib.Shared.projitems
@@ -19,6 +19,7 @@
</Compile>
</ItemDefinitionGroup>
<ItemGroup>
+ <Compile Include="$(MSBuildThisFileDirectory)Internal\IO\File.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Internal\Runtime\CompilerServices\Unsafe.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\CriticalHandleMinusOneIsInvalid.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\CriticalHandleZeroOrMinusOneIsInvalid.cs" />
@@ -72,6 +73,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\KeyNotFoundException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\KeyValuePair.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\NonRandomizedStringEqualityComparer.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\ValueListBuilder.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\List.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\HashHelpers.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\ICollection.cs" />
@@ -92,6 +94,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Configuration\Assemblies\AssemblyHashAlgorithm.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Configuration\Assemblies\AssemblyVersionCompatibility.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Convert.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Convert.Base64.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\CurrentSystemTimeZone.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\DataMisalignedException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\DateTime.cs" />
@@ -147,6 +150,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\DaylightTime.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\DigitShapes.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\EastAsianLunisolarCalendar.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\GlobalizationExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\GregorianCalendar.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\GregorianCalendarHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\GregorianCalendarTypes.cs" />
@@ -197,7 +201,6 @@
<Compile Include="$(MSBuildThisFileDirectory)System\InvalidTimeZoneException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\BinaryWriter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\DirectoryNotFoundException.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\IO\DriveNotFoundException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\EncodingCache.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\EndOfStreamException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Error.cs" />
@@ -232,12 +235,15 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Int64.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IntPtr.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Lazy.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Marvin.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Math.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\MathF.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\MarshalByRefObject.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\MemberAccessException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Memory.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\MemoryDebugView.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\MemoryExtensions.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\MemoryExtensions.Fast.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\MethodAccessException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\MidpointRounding.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\MissingMethodException.cs" />
@@ -263,6 +269,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Random.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\RankException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\ReadOnlySpan.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\ReadOnlySpan.Fast.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\ReadOnlyMemory.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\AmbiguousMatchException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\Assembly.cs" />
@@ -435,12 +442,12 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\LayoutKind.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\MarshalAsAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\MarshalDirectiveException.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\MemoryMarshal.Fast.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\MemoryMarshal.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\OptionalAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\OutAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\PreserveSigAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\SafeBuffer.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\StringBuffer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\StructLayoutAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\UnmanagedFunctionPointerAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Runtime\InteropServices\UnmanagedType.cs" />
@@ -480,10 +487,17 @@
<Compile Include="$(MSBuildThisFileDirectory)System\SerializableAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Single.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Span.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Span.Fast.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SpanDebugView.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Span.NonGeneric.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\SpanHelpers.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\SpanHelpers.BinarySearch.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\SpanHelpers.Byte.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\SpanHelpers.Char.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\SpanHelpers.T.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\String.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\String.Comparison.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\String.Manipulation.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\String.Searching.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\StringSpanHelpers.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\StackOverflowException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\StringComparer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\StringComparison.cs" />
@@ -509,6 +523,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Text\Latin1Encoding.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Text\NormalizationForm.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Text\StringBuilder.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Text\StringBuilder.Debug.cs" Condition="'$(Configuration)' == 'Debug'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Text\UnicodeEncoding.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Text\UTF32Encoding.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Text\UTF7Encoding.cs" />
@@ -539,6 +554,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Tasks\TaskToApm.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Tasks\TaskSchedulerException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Tasks\ValueTask.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Threading\Tasks\Sources\IValueTaskSource.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\ThreadAbortException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\ThreadPriority.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\ThreadStart.cs" />
@@ -572,7 +588,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\UnauthorizedAccessException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\UnhandledExceptionEventArgs.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\UnhandledExceptionEventHandler.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\UnitySerializationHolder.cs"/>
+ <Compile Include="$(MSBuildThisFileDirectory)System\UnitySerializationHolder.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)System\ValueTuple.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Version.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Void.cs" />
@@ -618,6 +634,37 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\TraceLoggingTypeInfo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\TraceLogging\TypeAnalysis.cs" />
</ItemGroup>
+ <ItemGroup>
+ <Compile Include="$(MSBuildThisFileDirectory)System\Numerics\ConstantHelper.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTime>True</DesignTime>
+ <DependentUpon>ConstantHelper.tt</DependentUpon>
+ </Compile>
+ <Content Include="$(MSBuildThisFileDirectory)System\Numerics\ConstantHelper.tt">
+ <Generator>TextTemplatingFileGenerator</Generator>
+ <LastGenOutput>ConstantHelper.cs</LastGenOutput>
+ </Content>
+ <None Include="$(MSBuildThisFileDirectory)System\Numerics\GenerationConfig.ttinclude" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Numerics\Register.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTime>True</DesignTime>
+ <DependentUpon>Register.tt</DependentUpon>
+ </Compile>
+ <Content Include="$(MSBuildThisFileDirectory)System\Numerics\Register.tt">
+ <Generator>TextTemplatingFileGenerator</Generator>
+ <LastGenOutput>Register.cs</LastGenOutput>
+ </Content>
+ <Compile Include="$(MSBuildThisFileDirectory)System\Numerics\Vector.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTime>True</DesignTime>
+ <DependentUpon>Vector.tt</DependentUpon>
+ </Compile>
+ <Content Include="$(MSBuildThisFileDirectory)System\Numerics\Vector.tt">
+ <Generator>TextTemplatingFileGenerator</Generator>
+ <LastGenOutput>Vector.cs</LastGenOutput>
+ </Content>
+ <Compile Include="$(MSBuildThisFileDirectory)System\Numerics\Vector_Operations.cs" />
+ </ItemGroup>
<ItemGroup Condition="$(TargetsWindows)">
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\BCrypt\Interop.BCryptGenRandom.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Crypt32\Interop.CryptProtectMemory.cs" />
@@ -643,6 +690,8 @@
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.GetTempPathW.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.Globalization.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.LockFile.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.MAX_PATH.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.MultiByteToWideChar.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.OutputDebugString.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.ReadFile_SafeHandle_IntPtr.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.ReadFile_SafeHandle_NativeOverlapped.cs" />
@@ -657,11 +706,16 @@
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.WriteFile_SafeHandle_NativeOverlapped.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Normaliz\Interop.Idna.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Normaliz\Interop.Normalization.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.TimeZone.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Ole32\Interop.CoCreateGuid.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\OleAut32\Interop.SysAllocStringLen.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\OleAut32\Interop.SysFreeString.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\OleAut32\Interop.SysStringLen.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Internal\IO\File.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeFileHandle.Windows.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeFindHandle.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendarData.Windows.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.Windows.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureData.Windows.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HijriCalendar.Win32.cs" Condition="'$(EnableWinRT)' != 'true' and '$(EnableDummyGlobalizationImplementation)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HijriCalendar.WinRT.cs" Condition="'$(EnableWinRT)' == 'true'" />
@@ -670,22 +724,25 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseCalendar.WinRT.cs" Condition="'$(EnableWinRT)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\Normalization.Windows.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TextInfo.Windows.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Guid.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStreamCompletionSource.Win32.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Path.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\PathHelper.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\PathInternal.Windows.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\IO\PathInternal.Windows.StringBuffer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\DisableMediaInsertionPrompt.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Security\SafeBSTRHandle.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Security\SecureString.Windows.cs" />
</ItemGroup>
<ItemGroup Condition="$(TargetsWindows) and '$(EnableWinRT)' != 'true'">
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Win32.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\TimeZoneInfo.Win32.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeLibraryHandle.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.LoadLibraryEx.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.FreeLibrary.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.CreateFile.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.MUI.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\Kernel32\Interop.TimeZone.Registry.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\User32\Interop.Constants.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\User32\Interop.SendMessageTimeout.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Windows\User32\Interop.LoadString.cs" />
@@ -729,14 +786,18 @@
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.Permissions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.PosixFAdvise.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.Read.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.ReadDir.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.ReadLink.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.Stat.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.SysLog.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.Unlink.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Native\Interop.Write.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Internal\IO\File.Unix.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeDirectoryHandle.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeFileHandle.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Debug.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendarData.Unix.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.Unix.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureData.Unix.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HijriCalendar.Unix.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\IdnMapping.Unix.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
@@ -744,11 +805,13 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\LocaleData.Unix.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\Normalization.Unix.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TextInfo.Unix.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Guid.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.OSX.cs" Condition="'$(TargetsOSX)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Linux.cs" Condition="'$(TargetsOSX)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\Path.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\PathInternal.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Security\SecureString.Unix.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\TimeZoneInfo.Unix.cs" />
</ItemGroup>
</Project>
diff --git a/src/Common/src/CoreLib/System/ArraySegment.cs b/src/Common/src/CoreLib/System/ArraySegment.cs
index d45fb0dc2b..3a13595e83 100644
--- a/src/Common/src/CoreLib/System/ArraySegment.cs
+++ b/src/Common/src/CoreLib/System/ArraySegment.cs
@@ -192,7 +192,7 @@ namespace System
return !(a == b);
}
- public static implicit operator ArraySegment<T>(T[] array) => new ArraySegment<T>(array);
+ public static implicit operator ArraySegment<T>(T[] array) => array != null ? new ArraySegment<T>(array) : default;
#region IList<T>
T IList<T>.this[int index]
diff --git a/src/Common/src/CoreLib/System/Boolean.cs b/src/Common/src/CoreLib/System/Boolean.cs
index 896e5f18e5..e476ef7ce6 100644
--- a/src/Common/src/CoreLib/System/Boolean.cs
+++ b/src/Common/src/CoreLib/System/Boolean.cs
@@ -12,7 +12,6 @@
**
===========================================================*/
-using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
@@ -100,10 +99,8 @@ namespace System
{
string s = m_value ? TrueLiteral : FalseLiteral;
- if (s.Length <= destination.Length)
+ if (s.AsSpan().TryCopyTo(destination))
{
- bool copied = s.AsReadOnlySpan().TryCopyTo(destination);
- Debug.Assert(copied);
charsWritten = s.Length;
return true;
}
@@ -183,7 +180,7 @@ namespace System
public static Boolean Parse(String value)
{
if (value == null) throw new ArgumentNullException(nameof(value));
- return Parse(value.AsReadOnlySpan());
+ return Parse(value.AsSpan());
}
public static bool Parse(ReadOnlySpan<char> value) =>
@@ -199,20 +196,20 @@ namespace System
return false;
}
- return TryParse(value.AsReadOnlySpan(), out result);
+ return TryParse(value.AsSpan(), out result);
}
public static bool TryParse(ReadOnlySpan<char> value, out bool result)
{
- ReadOnlySpan<char> trueSpan = TrueLiteral.AsReadOnlySpan();
- if (StringSpanHelpers.Equals(trueSpan, value, StringComparison.OrdinalIgnoreCase))
+ ReadOnlySpan<char> trueSpan = TrueLiteral.AsSpan();
+ if (trueSpan.EqualsOrdinalIgnoreCase(value))
{
result = true;
return true;
}
- ReadOnlySpan<char> falseSpan = FalseLiteral.AsReadOnlySpan();
- if (StringSpanHelpers.Equals(falseSpan, value, StringComparison.OrdinalIgnoreCase))
+ ReadOnlySpan<char> falseSpan = FalseLiteral.AsSpan();
+ if (falseSpan.EqualsOrdinalIgnoreCase(value))
{
result = false;
return true;
@@ -221,13 +218,13 @@ namespace System
// Special case: Trim whitespace as well as null characters.
value = TrimWhiteSpaceAndNull(value);
- if (StringSpanHelpers.Equals(trueSpan, value, StringComparison.OrdinalIgnoreCase))
+ if (trueSpan.EqualsOrdinalIgnoreCase(value))
{
result = true;
return true;
}
- if (StringSpanHelpers.Equals(falseSpan, value, StringComparison.OrdinalIgnoreCase))
+ if (falseSpan.EqualsOrdinalIgnoreCase(value))
{
result = false;
return true;
diff --git a/src/Common/src/CoreLib/System/Buffers/ArrayPoolEventSource.cs b/src/Common/src/CoreLib/System/Buffers/ArrayPoolEventSource.cs
index 9482744144..b2d0dbd32d 100644
--- a/src/Common/src/CoreLib/System/Buffers/ArrayPoolEventSource.cs
+++ b/src/Common/src/CoreLib/System/Buffers/ArrayPoolEventSource.cs
@@ -6,7 +6,7 @@ using System.Diagnostics.Tracing;
namespace System.Buffers
{
- [EventSource(Name = "System.Buffers.ArrayPoolEventSource")]
+ [EventSource(Guid = "0866B2B8-5CEF-5DB9-2612-0C0FFD814A44", Name = "System.Buffers.ArrayPoolEventSource")]
internal sealed class ArrayPoolEventSource : EventSource
{
internal readonly static ArrayPoolEventSource Log = new ArrayPoolEventSource();
@@ -22,6 +22,9 @@ namespace System.Buffers
PoolExhausted
}
+ // The ArrayPoolEventSource GUID is {0866b2b8-5cef-5db9-2612-0c0ffd814a44}
+ private ArrayPoolEventSource() : base(new Guid(0x0866b2b8, 0x5cef, 0x5db9, 0x26, 0x12, 0x0c, 0x0f, 0xfd, 0x81, 0x4a, 0x44), "System.Buffers.ArrayPoolEventSource") { }
+
/// <summary>
/// Event for when a buffer is rented. This is invoked once for every successful call to Rent,
/// regardless of whether a buffer is allocated or a buffer is taken from the pool. In a
@@ -36,12 +39,16 @@ namespace System.Buffers
EventData* payload = stackalloc EventData[4];
payload[0].Size = sizeof(int);
payload[0].DataPointer = ((IntPtr)(&bufferId));
+ payload[0].Reserved = 0;
payload[1].Size = sizeof(int);
payload[1].DataPointer = ((IntPtr)(&bufferSize));
+ payload[1].Reserved = 0;
payload[2].Size = sizeof(int);
payload[2].DataPointer = ((IntPtr)(&poolId));
+ payload[2].Reserved = 0;
payload[3].Size = sizeof(int);
payload[3].DataPointer = ((IntPtr)(&bucketId));
+ payload[3].Reserved = 0;
WriteEventCore(1, 4, payload);
}
@@ -56,14 +63,19 @@ namespace System.Buffers
EventData* payload = stackalloc EventData[5];
payload[0].Size = sizeof(int);
payload[0].DataPointer = ((IntPtr)(&bufferId));
+ payload[0].Reserved = 0;
payload[1].Size = sizeof(int);
payload[1].DataPointer = ((IntPtr)(&bufferSize));
+ payload[1].Reserved = 0;
payload[2].Size = sizeof(int);
payload[2].DataPointer = ((IntPtr)(&poolId));
+ payload[2].Reserved = 0;
payload[3].Size = sizeof(int);
payload[3].DataPointer = ((IntPtr)(&bucketId));
+ payload[3].Reserved = 0;
payload[4].Size = sizeof(BufferAllocatedReason);
payload[4].DataPointer = ((IntPtr)(&reason));
+ payload[4].Reserved = 0;
WriteEventCore(2, 5, payload);
}
diff --git a/src/Common/src/CoreLib/System/Buffers/OwnedMemory.cs b/src/Common/src/CoreLib/System/Buffers/OwnedMemory.cs
index 6946addc80..8acd5b224a 100644
--- a/src/Common/src/CoreLib/System/Buffers/OwnedMemory.cs
+++ b/src/Common/src/CoreLib/System/Buffers/OwnedMemory.cs
@@ -34,7 +34,7 @@ namespace System.Buffers
{
if (IsDisposed)
{
- ThrowHelper.ThrowObjectDisposedException_MemoryDisposed(nameof(OwnedMemory<T>));
+ ThrowHelper.ThrowObjectDisposedException_MemoryDisposed();
}
return new Memory<T>(owner: this, 0, Length);
}
@@ -43,12 +43,12 @@ namespace System.Buffers
/// <summary>
/// Returns a handle for the array that has been pinned and hence its address can be taken
/// </summary>
- public abstract MemoryHandle Pin(int offset = 0);
+ public abstract MemoryHandle Pin(int byteOffset = 0);
/// <summary>
/// Returns an array segment.
/// </summary>
- protected internal abstract bool TryGetArray(out ArraySegment<T> arraySegment);
+ protected internal abstract bool TryGetArray(out ArraySegment<T> segment);
/// <summary>
/// Implements IDisposable.
diff --git a/src/Common/src/CoreLib/System/Buffers/TlsOverPerCoreLockedStacksArrayPool.cs b/src/Common/src/CoreLib/System/Buffers/TlsOverPerCoreLockedStacksArrayPool.cs
index 64c5cebe85..f6affca0db 100644
--- a/src/Common/src/CoreLib/System/Buffers/TlsOverPerCoreLockedStacksArrayPool.cs
+++ b/src/Common/src/CoreLib/System/Buffers/TlsOverPerCoreLockedStacksArrayPool.cs
@@ -6,6 +6,8 @@ using Microsoft.Win32;
using System.Runtime.CompilerServices;
using System.Threading;
+using Internal.Runtime.Augments;
+
namespace System.Buffers
{
/// <summary>
@@ -228,7 +230,7 @@ namespace System.Buffers
// Try to push on to the associated stack first. If that fails,
// round-robin through the other stacks.
LockedStack[] stacks = _perCoreStacks;
- int index = Environment.CurrentExecutionId % stacks.Length;
+ int index = RuntimeThread.GetCurrentProcessorId() % stacks.Length;
for (int i = 0; i < stacks.Length; i++)
{
if (stacks[index].TryPush(array)) return;
@@ -244,7 +246,7 @@ namespace System.Buffers
// round-robin through the other stacks.
T[] arr;
LockedStack[] stacks = _perCoreStacks;
- int index = Environment.CurrentExecutionId % stacks.Length;
+ int index = RuntimeThread.GetCurrentProcessorId() % stacks.Length;
for (int i = 0; i < stacks.Length; i++)
{
if ((arr = stacks[index].TryPop()) != null) return arr;
diff --git a/src/Common/src/CoreLib/System/Byte.cs b/src/Common/src/CoreLib/System/Byte.cs
index 13ceb7573d..31185f0ed0 100644
--- a/src/Common/src/CoreLib/System/Byte.cs
+++ b/src/Common/src/CoreLib/System/Byte.cs
@@ -192,10 +192,6 @@ namespace System
return Number.FormatInt32(m_value, format, provider);
}
- // TODO https://github.com/dotnet/corefx/issues/25337: Remove this overload once corefx is updated to target the new signatures
- public bool TryFormat(Span<char> destination, out int charsWritten, string format, IFormatProvider provider) =>
- TryFormat(destination, out charsWritten, (ReadOnlySpan<char>)format, provider);
-
public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider provider = null)
{
return Number.TryFormatInt32(m_value, format, provider, destination, out charsWritten);
diff --git a/src/Common/src/CoreLib/System/Char.cs b/src/Common/src/CoreLib/System/Char.cs
index 179ac40282..d3ed1f5b68 100644
--- a/src/Common/src/CoreLib/System/Char.cs
+++ b/src/Common/src/CoreLib/System/Char.cs
@@ -401,14 +401,14 @@ namespace System
//
public static char ToUpper(char c)
{
- return ToUpper(c, CultureInfo.CurrentCulture);
+ return CultureInfo.CurrentCulture.TextInfo.ToUpper(c);
}
// Converts a character to upper-case for invariant culture.
public static char ToUpperInvariant(char c)
{
- return ToUpper(c, CultureInfo.InvariantCulture);
+ return CultureInfo.InvariantCulture.TextInfo.ToUpper(c);
}
@@ -432,14 +432,14 @@ namespace System
// Converts a character to lower-case for the default culture.
public static char ToLower(char c)
{
- return ToLower(c, CultureInfo.CurrentCulture);
+ return CultureInfo.CurrentCulture.TextInfo.ToLower(c);
}
// Converts a character to lower-case for invariant culture.
public static char ToLowerInvariant(char c)
{
- return ToLower(c, CultureInfo.InvariantCulture);
+ return CultureInfo.InvariantCulture.TextInfo.ToLower(c);
}
diff --git a/src/Common/src/CoreLib/System/Collections/Generic/Dictionary.cs b/src/Common/src/CoreLib/System/Collections/Generic/Dictionary.cs
index 7801f7d1d6..8d043e2f79 100644
--- a/src/Common/src/CoreLib/System/Collections/Generic/Dictionary.cs
+++ b/src/Common/src/CoreLib/System/Collections/Generic/Dictionary.cs
@@ -2,11 +2,10 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System;
-using System.Collections;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
+using System.Threading;
namespace System.Collections.Generic
{
@@ -74,10 +73,15 @@ namespace System.Collections.Generic
{
if (capacity < 0) ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity);
if (capacity > 0) Initialize(capacity);
- _comparer = comparer ?? EqualityComparer<TKey>.Default;
+ if (comparer != EqualityComparer<TKey>.Default)
+ {
+ _comparer = comparer;
+ }
+
#if !MONO
- if (_comparer == EqualityComparer<string>.Default)
+ if (typeof(TKey) == typeof(string) && _comparer == null)
{
+ // To start, move off default comparer for string which is randomised
_comparer = (IEqualityComparer<TKey>)NonRandomizedStringEqualityComparer.Default;
}
#endif
@@ -146,7 +150,7 @@ namespace System.Collections.Generic
{
get
{
- return _comparer;
+ return (_comparer == null || _comparer is NonRandomizedStringEqualityComparer) ? EqualityComparer<TKey>.Default : _comparer;
}
}
@@ -216,7 +220,7 @@ namespace System.Collections.Generic
int i = FindEntry(key);
if (i >= 0) return _entries[i].value;
ThrowHelper.ThrowKeyNotFoundException(key);
- return default(TValue);
+ return default;
}
set
{
@@ -236,9 +240,7 @@ namespace System.Collections.Generic
}
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> keyValuePair)
- {
- Add(keyValuePair.Key, keyValuePair.Value);
- }
+ => Add(keyValuePair.Key, keyValuePair.Value);
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> keyValuePair)
{
@@ -266,40 +268,49 @@ namespace System.Collections.Generic
int count = _count;
if (count > 0)
{
- int[] buckets = _buckets;
- for (int i = 0; i < buckets.Length; i++)
- {
- buckets[i] = -1;
- }
+ Array.Clear(_buckets, 0, _buckets.Length);
_count = 0;
_freeList = -1;
_freeCount = 0;
- _version++;
Array.Clear(_entries, 0, count);
}
+ _version++;
}
public bool ContainsKey(TKey key)
- {
- return FindEntry(key) >= 0;
- }
+ => FindEntry(key) >= 0;
public bool ContainsValue(TValue value)
{
+ Entry[] entries = _entries;
if (value == null)
{
for (int i = 0; i < _count; i++)
{
- if (_entries[i].hashCode >= 0 && _entries[i].value == null) return true;
+ if (entries[i].hashCode >= 0 && entries[i].value == null) return true;
}
}
else
{
- EqualityComparer<TValue> c = EqualityComparer<TValue>.Default;
- for (int i = 0; i < _count; i++)
+ if (default(TValue) != null)
+ {
+ // ValueType: Devirtualize with EqualityComparer<TValue>.Default intrinsic
+ for (int i = 0; i < _count; i++)
+ {
+ if (entries[i].hashCode >= 0 && EqualityComparer<TValue>.Default.Equals(entries[i].value, value)) return true;
+ }
+ }
+ else
{
- if (_entries[i].hashCode >= 0 && c.Equals(_entries[i].value, value)) return true;
+ // Object type: Shared Generic, EqualityComparer<TValue>.Default won't devirtualize
+ // https://github.com/dotnet/coreclr/issues/17273
+ // So cache in a local rather than get EqualityComparer per loop iteration
+ EqualityComparer<TValue> defaultComparer = EqualityComparer<TValue>.Default;
+ for (int i = 0; i < _count; i++)
+ {
+ if (entries[i].hashCode >= 0 && defaultComparer.Equals(entries[i].value, value)) return true;
+ }
}
}
return false;
@@ -312,7 +323,7 @@ namespace System.Collections.Generic
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
}
- if (index < 0 || index > array.Length)
+ if ((uint)index > (uint)array.Length)
{
ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
}
@@ -328,20 +339,16 @@ namespace System.Collections.Generic
{
if (entries[i].hashCode >= 0)
{
- array[index++] = new KeyValuePair<TKey, TValue>(entries[i].key, entries[i].value);
+ array[index + i] = new KeyValuePair<TKey, TValue>(entries[i].key, entries[i].value);
}
}
}
public Enumerator GetEnumerator()
- {
- return new Enumerator(this, Enumerator.KeyValuePair);
- }
+ => new Enumerator(this, Enumerator.KeyValuePair);
IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
- {
- return new Enumerator(this, Enumerator.KeyValuePair);
- }
+ => new Enumerator(this, Enumerator.KeyValuePair);
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
@@ -351,7 +358,7 @@ namespace System.Collections.Generic
}
info.AddValue(VersionName, _version);
- info.AddValue(ComparerName, _comparer, typeof(IEqualityComparer<TKey>));
+ info.AddValue(ComparerName, _comparer ?? EqualityComparer<TKey>.Default, typeof(IEqualityComparer<TKey>));
info.AddValue(HashSizeName, _buckets == null ? 0 : _buckets.Length); // This is the length of the bucket array
if (_buckets != null)
@@ -369,28 +376,102 @@ namespace System.Collections.Generic
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
}
- if (_buckets != null)
+ int i = -1;
+ int[] buckets = _buckets;
+ Entry[] entries = _entries;
+ int collisionCount = 0;
+ if (buckets != null)
{
- int hashCode = _comparer.GetHashCode(key) & 0x7FFFFFFF;
- for (int i = _buckets[hashCode % _buckets.Length]; i >= 0; i = _entries[i].next)
+ IEqualityComparer<TKey> comparer = _comparer;
+ if (comparer == null)
+ {
+ int hashCode = key.GetHashCode() & 0x7FFFFFFF;
+ // Value in _buckets is 1-based
+ i = buckets[hashCode % buckets.Length] - 1;
+ if (default(TKey) != null)
+ {
+ // ValueType: Devirtualize with EqualityComparer<TValue>.Default intrinsic
+ do
+ {
+ // Should be a while loop https://github.com/dotnet/coreclr/issues/15476
+ // Test in if to drop range check for following array access
+ if ((uint)i >= (uint)entries.Length || (entries[i].hashCode == hashCode && EqualityComparer<TKey>.Default.Equals(entries[i].key, key)))
+ {
+ break;
+ }
+
+ i = entries[i].next;
+ if (collisionCount >= entries.Length)
+ {
+ // The chain of entries forms a loop; which means a concurrent update has happened.
+ // Break out of the loop and throw, rather than looping forever.
+ ThrowHelper.ThrowInvalidOperationException_ConcurrentOperationsNotSupported();
+ }
+ collisionCount++;
+ } while (true);
+ }
+ else
+ {
+ // Object type: Shared Generic, EqualityComparer<TValue>.Default won't devirtualize
+ // https://github.com/dotnet/coreclr/issues/17273
+ // So cache in a local rather than get EqualityComparer per loop iteration
+ EqualityComparer<TKey> defaultComparer = EqualityComparer<TKey>.Default;
+ do
+ {
+ // Should be a while loop https://github.com/dotnet/coreclr/issues/15476
+ // Test in if to drop range check for following array access
+ if ((uint)i >= (uint)entries.Length || (entries[i].hashCode == hashCode && defaultComparer.Equals(entries[i].key, key)))
+ {
+ break;
+ }
+
+ i = entries[i].next;
+ if (collisionCount >= entries.Length)
+ {
+ // The chain of entries forms a loop; which means a concurrent update has happened.
+ // Break out of the loop and throw, rather than looping forever.
+ ThrowHelper.ThrowInvalidOperationException_ConcurrentOperationsNotSupported();
+ }
+ collisionCount++;
+ } while (true);
+ }
+ }
+ else
{
- if (_entries[i].hashCode == hashCode && _comparer.Equals(_entries[i].key, key)) return i;
+ int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
+ // Value in _buckets is 1-based
+ i = buckets[hashCode % buckets.Length] - 1;
+ do
+ {
+ // Should be a while loop https://github.com/dotnet/coreclr/issues/15476
+ // Test in if to drop range check for following array access
+ if ((uint)i >= (uint)entries.Length ||
+ (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)))
+ {
+ break;
+ }
+
+ i = entries[i].next;
+ if (collisionCount >= entries.Length)
+ {
+ // The chain of entries forms a loop; which means a concurrent update has happened.
+ // Break out of the loop and throw, rather than looping forever.
+ ThrowHelper.ThrowInvalidOperationException_ConcurrentOperationsNotSupported();
+ }
+ collisionCount++;
+ } while (true);
}
}
- return -1;
+
+ return i;
}
private int Initialize(int capacity)
{
int size = HashHelpers.GetPrime(capacity);
- int[] buckets = new int[size];
- for (int i = 0; i < buckets.Length; i++)
- {
- buckets[i] = -1;
- }
_freeList = -1;
- _buckets = buckets;
+ _buckets = new int[size];
_entries = new Entry[size];
return size;
@@ -403,64 +484,190 @@ namespace System.Collections.Generic
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
}
- if (_buckets == null) Initialize(0);
- int hashCode = _comparer.GetHashCode(key) & 0x7FFFFFFF;
- int targetBucket = hashCode % _buckets.Length;
+ _version++;
+ if (_buckets == null)
+ {
+ Initialize(0);
+ }
+
+ Entry[] entries = _entries;
+ IEqualityComparer<TKey> comparer = _comparer;
+
+ int hashCode = ((comparer == null) ? key.GetHashCode() : comparer.GetHashCode(key)) & 0x7FFFFFFF;
+
int collisionCount = 0;
+ ref int bucket = ref _buckets[hashCode % _buckets.Length];
+ // Value in _buckets is 1-based
+ int i = bucket - 1;
- for (int i = _buckets[targetBucket]; i >= 0; i = _entries[i].next)
+ if (comparer == null)
{
- if (_entries[i].hashCode == hashCode && _comparer.Equals(_entries[i].key, key))
+ if (default(TKey) != null)
{
- if (behavior == InsertionBehavior.OverwriteExisting)
+ // ValueType: Devirtualize with EqualityComparer<TValue>.Default intrinsic
+ do
{
- _entries[i].value = value;
- _version++;
- return true;
+ // Should be a while loop https://github.com/dotnet/coreclr/issues/15476
+ // Test uint in if rather than loop condition to drop range check for following array access
+ if ((uint)i >= (uint)entries.Length)
+ {
+ break;
+ }
+
+ if (entries[i].hashCode == hashCode && EqualityComparer<TKey>.Default.Equals(entries[i].key, key))
+ {
+ if (behavior == InsertionBehavior.OverwriteExisting)
+ {
+ entries[i].value = value;
+ return true;
+ }
+
+ if (behavior == InsertionBehavior.ThrowOnExisting)
+ {
+ ThrowHelper.ThrowAddingDuplicateWithKeyArgumentException(key);
+ }
+
+ return false;
+ }
+
+ i = entries[i].next;
+ if (collisionCount >= entries.Length)
+ {
+ // The chain of entries forms a loop; which means a concurrent update has happened.
+ // Break out of the loop and throw, rather than looping forever.
+ ThrowHelper.ThrowInvalidOperationException_ConcurrentOperationsNotSupported();
+ }
+ collisionCount++;
+ } while (true);
+ }
+ else
+ {
+ // Object type: Shared Generic, EqualityComparer<TValue>.Default won't devirtualize
+ // https://github.com/dotnet/coreclr/issues/17273
+ // So cache in a local rather than get EqualityComparer per loop iteration
+ EqualityComparer<TKey> defaultComparer = EqualityComparer<TKey>.Default;
+ do
+ {
+ // Should be a while loop https://github.com/dotnet/coreclr/issues/15476
+ // Test uint in if rather than loop condition to drop range check for following array access
+ if ((uint)i >= (uint)entries.Length)
+ {
+ break;
+ }
+
+ if (entries[i].hashCode == hashCode && defaultComparer.Equals(entries[i].key, key))
+ {
+ if (behavior == InsertionBehavior.OverwriteExisting)
+ {
+ entries[i].value = value;
+ return true;
+ }
+
+ if (behavior == InsertionBehavior.ThrowOnExisting)
+ {
+ ThrowHelper.ThrowAddingDuplicateWithKeyArgumentException(key);
+ }
+
+ return false;
+ }
+
+ i = entries[i].next;
+ if (collisionCount >= entries.Length)
+ {
+ // The chain of entries forms a loop; which means a concurrent update has happened.
+ // Break out of the loop and throw, rather than looping forever.
+ ThrowHelper.ThrowInvalidOperationException_ConcurrentOperationsNotSupported();
+ }
+ collisionCount++;
+ } while (true);
+ }
+ }
+ else
+ {
+ do
+ {
+ // Should be a while loop https://github.com/dotnet/coreclr/issues/15476
+ // Test uint in if rather than loop condition to drop range check for following array access
+ if ((uint)i >= (uint)entries.Length)
+ {
+ break;
}
- if (behavior == InsertionBehavior.ThrowOnExisting)
+ if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key))
{
- ThrowHelper.ThrowAddingDuplicateWithKeyArgumentException(key);
+ if (behavior == InsertionBehavior.OverwriteExisting)
+ {
+ entries[i].value = value;
+ return true;
+ }
+
+ if (behavior == InsertionBehavior.ThrowOnExisting)
+ {
+ ThrowHelper.ThrowAddingDuplicateWithKeyArgumentException(key);
+ }
+
+ return false;
}
- return false;
- }
- collisionCount++;
+ i = entries[i].next;
+ if (collisionCount >= entries.Length)
+ {
+ // The chain of entries forms a loop; which means a concurrent update has happened.
+ // Break out of the loop and throw, rather than looping forever.
+ ThrowHelper.ThrowInvalidOperationException_ConcurrentOperationsNotSupported();
+ }
+ collisionCount++;
+ } while (true);
+
}
+ // Can be improved with "Ref Local Reassignment"
+ // https://github.com/dotnet/csharplang/blob/master/proposals/ref-local-reassignment.md
+ bool resized = false;
+ bool updateFreeList = false;
int index;
if (_freeCount > 0)
{
index = _freeList;
- _freeList = _entries[index].next;
+ updateFreeList = true;
_freeCount--;
}
else
{
- if (_count == _entries.Length)
+ int count = _count;
+ if (count == entries.Length)
{
Resize();
- targetBucket = hashCode % _buckets.Length;
+ resized = true;
}
- index = _count;
- _count++;
+ index = count;
+ _count = count + 1;
+ entries = _entries;
}
- _entries[index].hashCode = hashCode;
- _entries[index].next = _buckets[targetBucket];
- _entries[index].key = key;
- _entries[index].value = value;
- _buckets[targetBucket] = index;
- _version++;
-#if !MONO
- // If we hit the collision threshold we'll need to switch to the comparer which is using randomized string hashing
- // i.e. EqualityComparer<string>.Default.
+ ref int targetBucket = ref resized ? ref _buckets[hashCode % _buckets.Length] : ref bucket;
+ ref Entry entry = ref entries[index];
- if (collisionCount > HashHelpers.HashCollisionThreshold && _comparer is NonRandomizedStringEqualityComparer)
+ if (updateFreeList)
{
- _comparer = (IEqualityComparer<TKey>)EqualityComparer<string>.Default;
- Resize(_entries.Length, true);
+ _freeList = entry.next;
+ }
+ entry.hashCode = hashCode;
+ // Value in _buckets is 1-based
+ entry.next = targetBucket - 1;
+ entry.key = key;
+ entry.value = value;
+ // Value in _buckets is 1-based
+ targetBucket = index + 1;
+
+#if !MONO
+ // Value types never rehash
+ if (default(TKey) == null && collisionCount > HashHelpers.HashCollisionThreshold && comparer is NonRandomizedStringEqualityComparer)
+ {
+ // If we hit the collision threshold we'll need to switch to the comparer which is using randomized string hashing
+ // i.e. EqualityComparer<string>.Default.
+ _comparer = null;
+ Resize(entries.Length, true);
}
#endif
return true;
@@ -468,8 +675,7 @@ namespace System.Collections.Generic
public virtual void OnDeserialization(object sender)
{
- SerializationInfo siInfo;
- HashHelpers.SerializationInfoTable.TryGetValue(this, out siInfo);
+ HashHelpers.SerializationInfoTable.TryGetValue(this, out SerializationInfo siInfo);
if (siInfo == null)
{
@@ -513,9 +719,7 @@ namespace System.Collections.Generic
}
private void Resize()
- {
- Resize(HashHelpers.ExpandPrime(_count), false);
- }
+ => Resize(HashHelpers.ExpandPrime(_count), false);
private void Resize(int newSize, bool forceNewHashCodes)
{
@@ -524,22 +728,19 @@ namespace System.Collections.Generic
#endif
int[] buckets = new int[newSize];
- for (int i = 0; i < buckets.Length; i++)
- {
- buckets[i] = -1;
- }
Entry[] entries = new Entry[newSize];
int count = _count;
Array.Copy(_entries, 0, entries, 0, count);
- if (forceNewHashCodes)
+ if (default(TKey) == null && forceNewHashCodes)
{
for (int i = 0; i < count; i++)
{
- if (entries[i].hashCode != -1)
+ if (entries[i].hashCode >= 0)
{
- entries[i].hashCode = (_comparer.GetHashCode(entries[i].key) & 0x7FFFFFFF);
+ Debug.Assert(_comparer == null);
+ entries[i].hashCode = (entries[i].key.GetHashCode() & 0x7FFFFFFF);
}
}
}
@@ -549,8 +750,10 @@ namespace System.Collections.Generic
if (entries[i].hashCode >= 0)
{
int bucket = entries[i].hashCode % newSize;
- entries[i].next = buckets[bucket];
- buckets[bucket] = i;
+ // Value in _buckets is 1-based
+ entries[i].next = buckets[bucket] - 1;
+ // Value in _buckets is 1-based
+ buckets[bucket] = i + 1;
}
}
@@ -570,19 +773,21 @@ namespace System.Collections.Generic
if (_buckets != null)
{
- int hashCode = _comparer.GetHashCode(key) & 0x7FFFFFFF;
+ int hashCode = (_comparer?.GetHashCode(key) ?? key.GetHashCode()) & 0x7FFFFFFF;
int bucket = hashCode % _buckets.Length;
int last = -1;
- int i = _buckets[bucket];
+ // Value in _buckets is 1-based
+ int i = _buckets[bucket] - 1;
while (i >= 0)
{
ref Entry entry = ref _entries[i];
- if (entry.hashCode == hashCode && _comparer.Equals(entry.key, key))
+ if (entry.hashCode == hashCode && (_comparer?.Equals(entry.key, key) ?? EqualityComparer<TKey>.Default.Equals(entry.key, key)))
{
if (last < 0)
{
- _buckets[bucket] = entry.next;
+ // Value in _buckets is 1-based
+ _buckets[bucket] = entry.next + 1;
}
else
{
@@ -593,11 +798,11 @@ namespace System.Collections.Generic
if (RuntimeHelpers.IsReferenceOrContainsReferences<TKey>())
{
- entry.key = default(TKey);
+ entry.key = default;
}
if (RuntimeHelpers.IsReferenceOrContainsReferences<TValue>())
{
- entry.value = default(TValue);
+ entry.value = default;
}
_freeList = i;
_freeCount++;
@@ -624,19 +829,21 @@ namespace System.Collections.Generic
if (_buckets != null)
{
- int hashCode = _comparer.GetHashCode(key) & 0x7FFFFFFF;
+ int hashCode = (_comparer?.GetHashCode(key) ?? key.GetHashCode()) & 0x7FFFFFFF;
int bucket = hashCode % _buckets.Length;
int last = -1;
- int i = _buckets[bucket];
+ // Value in _buckets is 1-based
+ int i = _buckets[bucket] - 1;
while (i >= 0)
{
ref Entry entry = ref _entries[i];
- if (entry.hashCode == hashCode && _comparer.Equals(entry.key, key))
+ if (entry.hashCode == hashCode && (_comparer?.Equals(entry.key, key) ?? EqualityComparer<TKey>.Default.Equals(entry.key, key)))
{
if (last < 0)
{
- _buckets[bucket] = entry.next;
+ // Value in _buckets is 1-based
+ _buckets[bucket] = entry.next + 1;
}
else
{
@@ -650,11 +857,11 @@ namespace System.Collections.Generic
if (RuntimeHelpers.IsReferenceOrContainsReferences<TKey>())
{
- entry.key = default(TKey);
+ entry.key = default;
}
if (RuntimeHelpers.IsReferenceOrContainsReferences<TValue>())
{
- entry.value = default(TValue);
+ entry.value = default;
}
_freeList = i;
_freeCount++;
@@ -666,7 +873,7 @@ namespace System.Collections.Generic
i = entry.next;
}
}
- value = default(TValue);
+ value = default;
return false;
}
@@ -678,63 +885,43 @@ namespace System.Collections.Generic
value = _entries[i].value;
return true;
}
- value = default(TValue);
+ value = default;
return false;
}
- public bool TryAdd(TKey key, TValue value) => TryInsert(key, value, InsertionBehavior.None);
+ public bool TryAdd(TKey key, TValue value)
+ => TryInsert(key, value, InsertionBehavior.None);
- bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly
- {
- get { return false; }
- }
+ bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly => false;
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int index)
- {
- CopyTo(array, index);
- }
+ => CopyTo(array, index);
void ICollection.CopyTo(Array array, int index)
{
if (array == null)
- {
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- }
-
if (array.Rank != 1)
- {
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported);
- }
-
if (array.GetLowerBound(0) != 0)
- {
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound);
- }
-
- if (index < 0 || index > array.Length)
- {
+ if ((uint)index > (uint)array.Length)
ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
- }
-
if (array.Length - index < Count)
- {
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
- }
- KeyValuePair<TKey, TValue>[] pairs = array as KeyValuePair<TKey, TValue>[];
- if (pairs != null)
+ if (array is KeyValuePair<TKey, TValue>[] pairs)
{
CopyTo(pairs, index);
}
- else if (array is DictionaryEntry[])
+ else if (array is DictionaryEntry[] dictEntryArray)
{
- DictionaryEntry[] dictEntryArray = array as DictionaryEntry[];
Entry[] entries = _entries;
for (int i = 0; i < _count; i++)
{
if (entries[i].hashCode >= 0)
{
- dictEntryArray[index++] = new DictionaryEntry(entries[i].key, entries[i].value);
+ dictEntryArray[index + i] = new DictionaryEntry(entries[i].key, entries[i].value);
}
}
}
@@ -754,7 +941,7 @@ namespace System.Collections.Generic
{
if (entries[i].hashCode >= 0)
{
- objects[index++] = new KeyValuePair<TKey, TValue>(entries[i].key, entries[i].value);
+ objects[index + i] = new KeyValuePair<TKey, TValue>(entries[i].key, entries[i].value);
}
}
}
@@ -766,9 +953,7 @@ namespace System.Collections.Generic
}
IEnumerator IEnumerable.GetEnumerator()
- {
- return new Enumerator(this, Enumerator.KeyValuePair);
- }
+ => new Enumerator(this, Enumerator.KeyValuePair);
/// <summary>
/// Ensures that the dictionary can hold up to 'capacity' entries without any further expansion of its backing storage
@@ -777,8 +962,9 @@ namespace System.Collections.Generic
{
if (capacity < 0)
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity);
- if (_entries != null && _entries.Length >= capacity)
- return _entries.Length;
+ int currentCapacity = _entries == null ? 0 : _entries.Length;
+ if (currentCapacity >= capacity)
+ return currentCapacity;
if (_buckets == null)
return Initialize(capacity);
int newSize = HashHelpers.GetPrime(capacity);
@@ -786,42 +972,82 @@ namespace System.Collections.Generic
return newSize;
}
- bool ICollection.IsSynchronized
+ /// <summary>
+ /// Sets the capacity of this dictionary to what it would be if it had been originally initialized with all its entries
+ ///
+ /// This method can be used to minimize the memory overhead
+ /// once it is known that no new elements will be added.
+ ///
+ /// To allocate minimum size storage array, execute the following statements:
+ ///
+ /// dictionary.Clear();
+ /// dictionary.TrimExcess();
+ /// </summary>
+ public void TrimExcess()
+ => TrimExcess(Count);
+
+ /// <summary>
+ /// Sets the capacity of this dictionary to hold up 'capacity' entries without any further expansion of its backing storage
+ ///
+ /// This method can be used to minimize the memory overhead
+ /// once it is known that no new elements will be added.
+ /// </summary>
+ public void TrimExcess(int capacity)
{
- get { return false; }
+ if (capacity < Count)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity);
+ int newSize = HashHelpers.GetPrime(capacity);
+
+ Entry[] oldEntries = _entries;
+ int currentCapacity = oldEntries == null ? 0 : oldEntries.Length;
+ if (newSize >= currentCapacity)
+ return;
+
+ int oldCount = _count;
+ Initialize(newSize);
+ Entry[] entries = _entries;
+ int[] buckets = _buckets;
+ int count = 0;
+ for (int i = 0; i < oldCount; i++)
+ {
+ int hashCode = oldEntries[i].hashCode;
+ if (hashCode >= 0)
+ {
+ ref Entry entry = ref entries[count];
+ entry = oldEntries[i];
+ int bucket = hashCode % newSize;
+ // Value in _buckets is 1-based
+ entry.next = buckets[bucket] - 1;
+ // Value in _buckets is 1-based
+ buckets[bucket] = count + 1;
+ count++;
+ }
+ }
+ _count = count;
+ _freeCount = 0;
}
+ bool ICollection.IsSynchronized => false;
+
object ICollection.SyncRoot
{
get
{
if (_syncRoot == null)
{
- System.Threading.Interlocked.CompareExchange<Object>(ref _syncRoot, new Object(), null);
+ Interlocked.CompareExchange<object>(ref _syncRoot, new object(), null);
}
return _syncRoot;
}
}
- bool IDictionary.IsFixedSize
- {
- get { return false; }
- }
+ bool IDictionary.IsFixedSize => false;
- bool IDictionary.IsReadOnly
- {
- get { return false; }
- }
+ bool IDictionary.IsReadOnly => false;
- ICollection IDictionary.Keys
- {
- get { return (ICollection)Keys; }
- }
+ ICollection IDictionary.Keys => (ICollection)Keys;
- ICollection IDictionary.Values
- {
- get { return (ICollection)Values; }
- }
+ ICollection IDictionary.Values => (ICollection)Values;
object IDictionary.this[object key]
{
@@ -911,9 +1137,7 @@ namespace System.Collections.Generic
}
IDictionaryEnumerator IDictionary.GetEnumerator()
- {
- return new Enumerator(this, Enumerator.DictEntry);
- }
+ => new Enumerator(this, Enumerator.DictEntry);
void IDictionary.Remove(object key)
{
@@ -972,10 +1196,7 @@ namespace System.Collections.Generic
return false;
}
- public KeyValuePair<TKey, TValue> Current
- {
- get { return _current; }
- }
+ public KeyValuePair<TKey, TValue> Current => _current;
public void Dispose()
{
@@ -992,7 +1213,7 @@ namespace System.Collections.Generic
if (_getEnumeratorRetType == DictEntry)
{
- return new System.Collections.DictionaryEntry(_current.Key, _current.Value);
+ return new DictionaryEntry(_current.Key, _current.Value);
}
else
{
@@ -1071,9 +1292,7 @@ namespace System.Collections.Generic
}
public Enumerator GetEnumerator()
- {
- return new Enumerator(_dictionary);
- }
+ => new Enumerator(_dictionary);
public void CopyTo(TKey[] array, int index)
{
@@ -1096,34 +1315,22 @@ namespace System.Collections.Generic
Entry[] entries = _dictionary._entries;
for (int i = 0; i < count; i++)
{
- if (entries[i].hashCode >= 0) array[index++] = entries[i].key;
+ if (entries[i].hashCode >= 0) array[index + i] = entries[i].key;
}
}
- public int Count
- {
- get { return _dictionary.Count; }
- }
+ public int Count => _dictionary.Count;
- bool ICollection<TKey>.IsReadOnly
- {
- get { return true; }
- }
+ bool ICollection<TKey>.IsReadOnly => true;
void ICollection<TKey>.Add(TKey item)
- {
- ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_KeyCollectionSet);
- }
+ => ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_KeyCollectionSet);
void ICollection<TKey>.Clear()
- {
- ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_KeyCollectionSet);
- }
+ => ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_KeyCollectionSet);
bool ICollection<TKey>.Contains(TKey item)
- {
- return _dictionary.ContainsKey(item);
- }
+ => _dictionary.ContainsKey(item);
bool ICollection<TKey>.Remove(TKey item)
{
@@ -1132,44 +1339,25 @@ namespace System.Collections.Generic
}
IEnumerator<TKey> IEnumerable<TKey>.GetEnumerator()
- {
- return new Enumerator(_dictionary);
- }
+ => new Enumerator(_dictionary);
IEnumerator IEnumerable.GetEnumerator()
- {
- return new Enumerator(_dictionary);
- }
+ => new Enumerator(_dictionary);
void ICollection.CopyTo(Array array, int index)
{
if (array == null)
- {
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- }
-
if (array.Rank != 1)
- {
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported);
- }
-
if (array.GetLowerBound(0) != 0)
- {
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound);
- }
-
- if (index < 0 || index > array.Length)
- {
+ if ((uint)index > (uint)array.Length)
ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
- }
-
if (array.Length - index < _dictionary.Count)
- {
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
- }
- TKey[] keys = array as TKey[];
- if (keys != null)
+ if (array is TKey[] keys)
{
CopyTo(keys, index);
}
@@ -1187,7 +1375,7 @@ namespace System.Collections.Generic
{
for (int i = 0; i < count; i++)
{
- if (entries[i].hashCode >= 0) objects[index++] = entries[i].key;
+ if (entries[i].hashCode >= 0) objects[index + i] = entries[i].key;
}
}
catch (ArrayTypeMismatchException)
@@ -1197,20 +1385,14 @@ namespace System.Collections.Generic
}
}
- bool ICollection.IsSynchronized
- {
- get { return false; }
- }
+ bool ICollection.IsSynchronized => false;
- object ICollection.SyncRoot
- {
- get { return ((ICollection)_dictionary).SyncRoot; }
- }
+ object ICollection.SyncRoot => ((ICollection)_dictionary).SyncRoot;
#if MONO
[Serializable]
#endif
- public struct Enumerator : IEnumerator<TKey>, System.Collections.IEnumerator
+ public struct Enumerator : IEnumerator<TKey>, IEnumerator
{
private Dictionary<TKey, TValue> _dictionary;
private int _index;
@@ -1222,7 +1404,7 @@ namespace System.Collections.Generic
_dictionary = dictionary;
_version = dictionary._version;
_index = 0;
- _currentKey = default(TKey);
+ _currentKey = default;
}
public void Dispose()
@@ -1248,19 +1430,13 @@ namespace System.Collections.Generic
}
_index = _dictionary._count + 1;
- _currentKey = default(TKey);
+ _currentKey = default;
return false;
}
- public TKey Current
- {
- get
- {
- return _currentKey;
- }
- }
+ public TKey Current => _currentKey;
- object System.Collections.IEnumerator.Current
+ object IEnumerator.Current
{
get
{
@@ -1273,7 +1449,7 @@ namespace System.Collections.Generic
}
}
- void System.Collections.IEnumerator.Reset()
+ void IEnumerator.Reset()
{
if (_version != _dictionary._version)
{
@@ -1281,7 +1457,7 @@ namespace System.Collections.Generic
}
_index = 0;
- _currentKey = default(TKey);
+ _currentKey = default;
}
}
}
@@ -1305,9 +1481,7 @@ namespace System.Collections.Generic
}
public Enumerator GetEnumerator()
- {
- return new Enumerator(_dictionary);
- }
+ => new Enumerator(_dictionary);
public void CopyTo(TValue[] array, int index)
{
@@ -1330,24 +1504,16 @@ namespace System.Collections.Generic
Entry[] entries = _dictionary._entries;
for (int i = 0; i < count; i++)
{
- if (entries[i].hashCode >= 0) array[index++] = entries[i].value;
+ if (entries[i].hashCode >= 0) array[index + i] = entries[i].value;
}
}
- public int Count
- {
- get { return _dictionary.Count; }
- }
+ public int Count => _dictionary.Count;
- bool ICollection<TValue>.IsReadOnly
- {
- get { return true; }
- }
+ bool ICollection<TValue>.IsReadOnly => true;
void ICollection<TValue>.Add(TValue item)
- {
- ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ValueCollectionSet);
- }
+ => ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ValueCollectionSet);
bool ICollection<TValue>.Remove(TValue item)
{
@@ -1356,52 +1522,31 @@ namespace System.Collections.Generic
}
void ICollection<TValue>.Clear()
- {
- ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ValueCollectionSet);
- }
+ => ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ValueCollectionSet);
bool ICollection<TValue>.Contains(TValue item)
- {
- return _dictionary.ContainsValue(item);
- }
+ => _dictionary.ContainsValue(item);
IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator()
- {
- return new Enumerator(_dictionary);
- }
+ => new Enumerator(_dictionary);
IEnumerator IEnumerable.GetEnumerator()
- {
- return new Enumerator(_dictionary);
- }
+ => new Enumerator(_dictionary);
void ICollection.CopyTo(Array array, int index)
{
if (array == null)
- {
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- }
-
if (array.Rank != 1)
- {
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RankMultiDimNotSupported);
- }
-
if (array.GetLowerBound(0) != 0)
- {
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NonZeroLowerBound);
- }
-
- if (index < 0 || index > array.Length)
- {
+ if ((uint)index > (uint)array.Length)
ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException();
- }
-
if (array.Length - index < _dictionary.Count)
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall);
- TValue[] values = array as TValue[];
- if (values != null)
+ if (array is TValue[] values)
{
CopyTo(values, index);
}
@@ -1419,7 +1564,7 @@ namespace System.Collections.Generic
{
for (int i = 0; i < count; i++)
{
- if (entries[i].hashCode >= 0) objects[index++] = entries[i].value;
+ if (entries[i].hashCode >= 0) objects[index + i] = entries[i].value;
}
}
catch (ArrayTypeMismatchException)
@@ -1429,20 +1574,14 @@ namespace System.Collections.Generic
}
}
- bool ICollection.IsSynchronized
- {
- get { return false; }
- }
+ bool ICollection.IsSynchronized => false;
- object ICollection.SyncRoot
- {
- get { return ((ICollection)_dictionary).SyncRoot; }
- }
+ object ICollection.SyncRoot => ((ICollection)_dictionary).SyncRoot;
#if MONO
[Serializable]
#endif
- public struct Enumerator : IEnumerator<TValue>, System.Collections.IEnumerator
+ public struct Enumerator : IEnumerator<TValue>, IEnumerator
{
private Dictionary<TKey, TValue> _dictionary;
private int _index;
@@ -1454,7 +1593,7 @@ namespace System.Collections.Generic
_dictionary = dictionary;
_version = dictionary._version;
_index = 0;
- _currentValue = default(TValue);
+ _currentValue = default;
}
public void Dispose()
@@ -1479,19 +1618,13 @@ namespace System.Collections.Generic
}
}
_index = _dictionary._count + 1;
- _currentValue = default(TValue);
+ _currentValue = default;
return false;
}
- public TValue Current
- {
- get
- {
- return _currentValue;
- }
- }
+ public TValue Current => _currentValue;
- object System.Collections.IEnumerator.Current
+ object IEnumerator.Current
{
get
{
@@ -1504,14 +1637,14 @@ namespace System.Collections.Generic
}
}
- void System.Collections.IEnumerator.Reset()
+ void IEnumerator.Reset()
{
if (_version != _dictionary._version)
{
ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion();
}
_index = 0;
- _currentValue = default(TValue);
+ _currentValue = default;
}
}
}
diff --git a/src/Common/src/CoreLib/System/Collections/Generic/List.cs b/src/Common/src/CoreLib/System/Collections/Generic/List.cs
index 1426d84021..cc82302628 100644
--- a/src/Common/src/CoreLib/System/Collections/Generic/List.cs
+++ b/src/Common/src/CoreLib/System/Collections/Generic/List.cs
@@ -6,6 +6,7 @@ using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Diagnostics.Private;
using System.Runtime.CompilerServices;
+using System.Threading;
namespace System.Collections.Generic
{
@@ -19,9 +20,9 @@ namespace System.Collections.Generic
[DebuggerDisplay("Count = {Count}")]
[Serializable]
#if !MONO
- [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+ [TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
#endif
- public class List<T> : IList<T>, System.Collections.IList, IReadOnlyList<T>
+ public class List<T> : IList<T>, IList, IReadOnlyList<T>
{
private const int DefaultCapacity = 4;
@@ -66,8 +67,7 @@ namespace System.Collections.Generic
if (collection == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
- ICollection<T> c = collection as ICollection<T>;
- if (c != null)
+ if (collection is ICollection<T> c)
{
int count = c.Count;
if (count == 0)
@@ -126,44 +126,26 @@ namespace System.Collections.Generic
}
// Read-only property describing how many elements are in the List.
- public int Count
- {
- get
- {
- return _size;
- }
- }
+ public int Count => _size;
- bool System.Collections.IList.IsFixedSize
- {
- get { return false; }
- }
+ bool IList.IsFixedSize => false;
// Is this List read-only?
- bool ICollection<T>.IsReadOnly
- {
- get { return false; }
- }
+ bool ICollection<T>.IsReadOnly => false;
- bool System.Collections.IList.IsReadOnly
- {
- get { return false; }
- }
+ bool IList.IsReadOnly => false;
// Is this List synchronized (thread-safe)?
- bool System.Collections.ICollection.IsSynchronized
- {
- get { return false; }
- }
+ bool ICollection.IsSynchronized => false;
// Synchronization root for this object.
- object System.Collections.ICollection.SyncRoot
+ object ICollection.SyncRoot
{
get
{
if (_syncRoot == null)
{
- System.Threading.Interlocked.CompareExchange<object>(ref _syncRoot, new object(), null);
+ Interlocked.CompareExchange<object>(ref _syncRoot, new object(), null);
}
return _syncRoot;
}
@@ -184,12 +166,12 @@ namespace System.Collections.Generic
set
{
+ _version++;
if ((uint)index >= (uint)_size)
{
ThrowHelper.ThrowArgumentOutOfRange_IndexException();
}
_items[index] = value;
- _version++;
}
}
@@ -200,7 +182,7 @@ namespace System.Collections.Generic
return ((value is T) || (value == null && default(T) == null));
}
- object System.Collections.IList.this[int index]
+ object IList.this[int index]
{
get
{
@@ -228,9 +210,9 @@ namespace System.Collections.Generic
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Add(T item)
{
- var array = _items;
- var size = _size;
_version++;
+ T[] array = _items;
+ int size = _size;
if ((uint)size < (uint)array.Length)
{
_size = size + 1;
@@ -246,13 +228,13 @@ namespace System.Collections.Generic
[MethodImpl(MethodImplOptions.NoInlining)]
private void AddWithResize(T item)
{
- var size = _size;
+ int size = _size;
EnsureCapacity(size + 1);
_size = size + 1;
_items[size] = item;
}
- int System.Collections.IList.Add(Object item)
+ int IList.Add(object item)
{
ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(item, ExceptionArgument.item);
@@ -273,14 +255,10 @@ namespace System.Collections.Generic
// capacity or the new size, whichever is larger.
//
public void AddRange(IEnumerable<T> collection)
- {
- InsertRange(_size, collection);
- }
+ => InsertRange(_size, collection);
public ReadOnlyCollection<T> AsReadOnly()
- {
- return new ReadOnlyCollection<T>(this);
- }
+ => new ReadOnlyCollection<T>(this);
// Searches a section of the list for a given element using a binary search
// algorithm. Elements of the list are compared to the search value using
@@ -315,25 +293,20 @@ namespace System.Collections.Generic
}
public int BinarySearch(T item)
- {
- return BinarySearch(0, Count, item, null);
- }
+ => BinarySearch(0, Count, item, null);
public int BinarySearch(T item, IComparer<T> comparer)
- {
- return BinarySearch(0, Count, item, comparer);
- }
-
+ => BinarySearch(0, Count, item, comparer);
// Clears the contents of List.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear()
{
+ _version++;
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
{
int size = _size;
_size = 0;
- _version++;
if (size > 0)
{
Array.Clear(_items, 0, size); // Clear the elements so that the gc can reclaim the references.
@@ -342,7 +315,6 @@ namespace System.Collections.Generic
else
{
_size = 0;
- _version++;
}
}
@@ -363,7 +335,7 @@ namespace System.Collections.Generic
return _size != 0 && IndexOf(item) != -1;
}
- bool System.Collections.IList.Contains(object item)
+ bool IList.Contains(object item)
{
if (IsCompatibleObject(item))
{
@@ -391,13 +363,11 @@ namespace System.Collections.Generic
// Copies this List into array, which must be of a
// compatible array type.
public void CopyTo(T[] array)
- {
- CopyTo(array, 0);
- }
+ => CopyTo(array, 0);
// Copies this List into array, which must be of a
// compatible array type.
- void System.Collections.ICollection.CopyTo(Array array, int arrayIndex)
+ void ICollection.CopyTo(Array array, int arrayIndex)
{
if ((array != null) && (array.Rank != 1))
{
@@ -459,9 +429,7 @@ namespace System.Collections.Generic
}
public bool Exists(Predicate<T> match)
- {
- return FindIndex(match) != -1;
- }
+ => FindIndex(match) != -1;
public T Find(Predicate<T> match)
{
@@ -477,7 +445,7 @@ namespace System.Collections.Generic
return _items[i];
}
}
- return default(T);
+ return default;
}
public List<T> FindAll(Predicate<T> match)
@@ -499,14 +467,10 @@ namespace System.Collections.Generic
}
public int FindIndex(Predicate<T> match)
- {
- return FindIndex(0, _size, match);
- }
+ => FindIndex(0, _size, match);
public int FindIndex(int startIndex, Predicate<T> match)
- {
- return FindIndex(startIndex, _size - startIndex, match);
- }
+ => FindIndex(startIndex, _size - startIndex, match);
public int FindIndex(int startIndex, int count, Predicate<T> match)
{
@@ -547,18 +511,14 @@ namespace System.Collections.Generic
return _items[i];
}
}
- return default(T);
+ return default;
}
public int FindLastIndex(Predicate<T> match)
- {
- return FindLastIndex(_size - 1, _size, match);
- }
+ => FindLastIndex(_size - 1, _size, match);
public int FindLastIndex(int startIndex, Predicate<T> match)
- {
- return FindLastIndex(startIndex, startIndex + 1, match);
- }
+ => FindLastIndex(startIndex, startIndex + 1, match);
public int FindLastIndex(int startIndex, int count, Predicate<T> match)
{
@@ -629,19 +589,13 @@ namespace System.Collections.Generic
// GetObject methods of the enumerator will throw an exception.
//
public Enumerator GetEnumerator()
- {
- return new Enumerator(this);
- }
+ => new Enumerator(this);
IEnumerator<T> IEnumerable<T>.GetEnumerator()
- {
- return new Enumerator(this);
- }
+ => new Enumerator(this);
- System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
- {
- return new Enumerator(this);
- }
+ IEnumerator IEnumerable.GetEnumerator()
+ => new Enumerator(this);
public List<T> GetRange(int index, int count)
{
@@ -676,11 +630,9 @@ namespace System.Collections.Generic
// search.
//
public int IndexOf(T item)
- {
- return Array.IndexOf(_items, item, 0, _size);
- }
+ => Array.IndexOf(_items, item, 0, _size);
- int System.Collections.IList.IndexOf(object item)
+ int IList.IndexOf(object item)
{
if (IsCompatibleObject(item))
{
@@ -746,7 +698,7 @@ namespace System.Collections.Generic
_version++;
}
- void System.Collections.IList.Insert(int index, Object item)
+ void IList.Insert(int index, object item)
{
ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(item, ExceptionArgument.item);
@@ -777,9 +729,8 @@ namespace System.Collections.Generic
ThrowHelper.ThrowArgumentOutOfRange_IndexException();
}
- ICollection<T> c = collection as ICollection<T>;
- if (c != null)
- { // if collection is ICollection<T>
+ if (collection is ICollection<T> c)
+ {
int count = c.Count;
if (count > 0)
{
@@ -912,7 +863,7 @@ namespace System.Collections.Generic
return false;
}
- void System.Collections.IList.Remove(object item)
+ void IList.Remove(object item)
{
if (IsCompatibleObject(item))
{
@@ -974,7 +925,7 @@ namespace System.Collections.Generic
}
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
{
- _items[_size] = default(T);
+ _items[_size] = default;
}
_version++;
}
@@ -1014,9 +965,7 @@ namespace System.Collections.Generic
// Reverses the elements in this list.
public void Reverse()
- {
- Reverse(0, Count);
- }
+ => Reverse(0, Count);
// Reverses the elements in a range of this list. Following a call to this
// method, an element in the range given by index and count
@@ -1048,16 +997,12 @@ namespace System.Collections.Generic
// Sorts the elements in this list. Uses the default comparer and
// Array.Sort.
public void Sort()
- {
- Sort(0, Count, null);
- }
+ => Sort(0, Count, null);
// Sorts the elements in this list. Uses Array.Sort with the
// provided comparer.
public void Sort(IComparer<T> comparer)
- {
- Sort(0, Count, comparer);
- }
+ => Sort(0, Count, comparer);
// Sorts the elements in a section of this list. The sort compares the
// elements to each other using the given IComparer interface. If
@@ -1157,9 +1102,9 @@ namespace System.Collections.Generic
Debug.Assert(enumerable != null);
Debug.Assert(!(enumerable is ICollection<T>), "We should have optimized for this beforehand.");
+ _version++; // Even if the enumerable has no items, we can update _version.
using (IEnumerator<T> en = enumerable.GetEnumerator())
{
- _version++; // Even if the enumerable has no items, we can update _version.
while (en.MoveNext())
{
@@ -1180,7 +1125,7 @@ namespace System.Collections.Generic
#if MONO
[System.Serializable]
#endif
- public struct Enumerator : IEnumerator<T>, System.Collections.IEnumerator
+ public struct Enumerator : IEnumerator<T>, IEnumerator
{
private List<T> _list;
private int _index;
@@ -1192,7 +1137,7 @@ namespace System.Collections.Generic
_list = list;
_index = 0;
_version = list._version;
- _current = default(T);
+ _current = default;
}
public void Dispose()
@@ -1220,19 +1165,13 @@ namespace System.Collections.Generic
}
_index = _list._size + 1;
- _current = default(T);
+ _current = default;
return false;
}
- public T Current
- {
- get
- {
- return _current;
- }
- }
+ public T Current => _current;
- object System.Collections.IEnumerator.Current
+ object IEnumerator.Current
{
get
{
@@ -1244,7 +1183,7 @@ namespace System.Collections.Generic
}
}
- void System.Collections.IEnumerator.Reset()
+ void IEnumerator.Reset()
{
if (_version != _list._version)
{
@@ -1252,7 +1191,7 @@ namespace System.Collections.Generic
}
_index = 0;
- _current = default(T);
+ _current = default;
}
}
}
diff --git a/src/Common/src/CoreLib/System/Collections/Generic/NonRandomizedStringEqualityComparer.cs b/src/Common/src/CoreLib/System/Collections/Generic/NonRandomizedStringEqualityComparer.cs
index 72f62c2b9a..e7efa22b24 100644
--- a/src/Common/src/CoreLib/System/Collections/Generic/NonRandomizedStringEqualityComparer.cs
+++ b/src/Common/src/CoreLib/System/Collections/Generic/NonRandomizedStringEqualityComparer.cs
@@ -11,12 +11,8 @@ namespace System.Collections.Generic
// keeps the performance not affected till we hit collision threshold and then we switch to the comparer which is using
// randomized string hashing.
[Serializable] // Required for compatibility with .NET Core 2.0 as we exposed the NonRandomizedStringEqualityComparer inside the serialization blob
-#if CORERT
- public
-#else
- internal
-#endif
- sealed class NonRandomizedStringEqualityComparer : EqualityComparer<string>, ISerializable
+ // Needs to be public to support binary serialization compatibility
+ public sealed class NonRandomizedStringEqualityComparer : EqualityComparer<string>, ISerializable
{
internal static new IEqualityComparer<string> Default { get; } = new NonRandomizedStringEqualityComparer();
diff --git a/src/Common/src/CoreLib/System/Collections/Generic/ValueListBuilder.cs b/src/Common/src/CoreLib/System/Collections/Generic/ValueListBuilder.cs
new file mode 100644
index 0000000000..72da4a9e19
--- /dev/null
+++ b/src/Common/src/CoreLib/System/Collections/Generic/ValueListBuilder.cs
@@ -0,0 +1,76 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+
+namespace System.Collections.Generic
+{
+ internal ref partial struct ValueListBuilder<T>
+ {
+ private Span<T> _span;
+ private T[] _arrayFromPool;
+ private int _pos;
+
+ public ValueListBuilder(Span<T> initialSpan)
+ {
+ _span = initialSpan;
+ _arrayFromPool = null;
+ _pos = 0;
+ }
+
+ public int Length => _pos;
+
+ public ref T this[int index]
+ {
+ get
+ {
+ Debug.Assert(index < _pos);
+ return ref _span[index];
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Append(T item)
+ {
+ int pos = _pos;
+ if (pos >= _span.Length)
+ Grow();
+
+ _span[pos] = item;
+ _pos = pos + 1;
+ }
+
+ public ReadOnlySpan<T> AsSpan()
+ {
+ return _span.Slice(0, _pos);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Dispose()
+ {
+ if (_arrayFromPool != null)
+ {
+ ArrayPool<T>.Shared.Return(_arrayFromPool);
+ _arrayFromPool = null;
+ }
+ }
+
+ private void Grow()
+ {
+ T[] array = ArrayPool<T>.Shared.Rent(_span.Length * 2);
+
+ bool success = _span.TryCopyTo(array);
+ Debug.Assert(success);
+
+ T[] toReturn = _arrayFromPool;
+ _span = _arrayFromPool = array;
+ if (toReturn != null)
+ {
+ ArrayPool<T>.Shared.Return(toReturn);
+ }
+ }
+ }
+}
diff --git a/src/Common/src/CoreLib/System/Collections/ListDictionaryInternal.cs b/src/Common/src/CoreLib/System/Collections/ListDictionaryInternal.cs
index a8b7a187d9..eccb9f0347 100644
--- a/src/Common/src/CoreLib/System/Collections/ListDictionaryInternal.cs
+++ b/src/Common/src/CoreLib/System/Collections/ListDictionaryInternal.cs
@@ -20,12 +20,8 @@ namespace System.Collections
/// This should not be used if performance is important for large numbers of elements.
[Serializable]
[System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
-#if CORERT
- public
-#else
- internal
-#endif
- class ListDictionaryInternal : IDictionary
+ // Needs to be public to support binary serialization compatibility
+ public class ListDictionaryInternal : IDictionary
{
private DictionaryNode head; // Do not rename (binary serialization)
private int version; // Do not rename (binary serialization)
diff --git a/src/Common/src/CoreLib/System/Convert.Base64.cs b/src/Common/src/CoreLib/System/Convert.Base64.cs
new file mode 100644
index 0000000000..7e2aee31b2
--- /dev/null
+++ b/src/Common/src/CoreLib/System/Convert.Base64.cs
@@ -0,0 +1,217 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Internal.Runtime.CompilerServices;
+
+namespace System
+{
+ public static partial class Convert
+ {
+ /// <summary>
+ /// Decode the span of UTF-16 encoded text represented as base 64 into binary data.
+ /// If the input is not a multiple of 4, or contains illegal characters, it will decode as much as it can, to the largest possible multiple of 4.
+ /// This invariant allows continuation of the parse with a slower, whitespace-tolerant algorithm.
+ ///
+ /// <param name="utf16">The input span which contains UTF-16 encoded text in base 64 that needs to be decoded.</param>
+ /// <param name="bytes">The output span which contains the result of the operation, i.e. the decoded binary data.</param>
+ /// <param name="consumed">The number of input bytes consumed during the operation. This can be used to slice the input for subsequent calls, if necessary.</param>
+ /// <param name="written">The number of bytes written into the output span. This can be used to slice the output for subsequent calls, if necessary.</param>
+ /// <returns>Returns:
+ /// - true - The entire input span was successfully parsed.
+ /// - false - Only a part of the input span was successfully parsed. Failure causes may include embedded or trailing whitespace,
+ /// other illegal Base64 characters, trailing characters after an encoding pad ('='), an input span whose length is not divisible by 4
+ /// or a destination span that's too small. <paramref name="consumed"/> and <paramref name="written"/> are set so that
+ /// parsing can continue with a slower whitespace-tolerant algorithm.
+ ///
+ /// Note: This is a cut down version of the implementation of Base64.DecodeFromUtf8(), modified the accept UTF16 chars and act as a fast-path
+ /// helper for the Convert routines when the input string contains no whitespace.
+ ///
+ /// </summary>
+ private static bool TryDecodeFromUtf16(ReadOnlySpan<char> utf16, Span<byte> bytes, out int consumed, out int written)
+ {
+ ref char srcChars = ref MemoryMarshal.GetReference(utf16);
+ ref byte destBytes = ref MemoryMarshal.GetReference(bytes);
+
+ int srcLength = utf16.Length & ~0x3; // only decode input up to the closest multiple of 4.
+ int destLength = bytes.Length;
+
+ int sourceIndex = 0;
+ int destIndex = 0;
+
+ if (utf16.Length == 0)
+ goto DoneExit;
+
+ ref sbyte decodingMap = ref s_decodingMap[0];
+
+ // Last bytes could have padding characters, so process them separately and treat them as valid.
+ const int skipLastChunk = 4;
+
+ int maxSrcLength;
+ if (destLength >= (srcLength >> 2) * 3)
+ {
+ maxSrcLength = srcLength - skipLastChunk;
+ }
+ else
+ {
+ // This should never overflow since destLength here is less than int.MaxValue / 4 * 3 (i.e. 1610612733)
+ // Therefore, (destLength / 3) * 4 will always be less than 2147483641
+ maxSrcLength = (destLength / 3) * 4;
+ }
+
+ while (sourceIndex < maxSrcLength)
+ {
+ int result = Decode(ref Unsafe.Add(ref srcChars, sourceIndex), ref decodingMap);
+ if (result < 0)
+ goto InvalidExit;
+ WriteThreeLowOrderBytes(ref Unsafe.Add(ref destBytes, destIndex), result);
+ destIndex += 3;
+ sourceIndex += 4;
+ }
+
+ if (maxSrcLength != srcLength - skipLastChunk)
+ goto InvalidExit;
+
+ // If input is less than 4 bytes, srcLength == sourceIndex == 0
+ // If input is not a multiple of 4, sourceIndex == srcLength != 0
+ if (sourceIndex == srcLength)
+ {
+ goto InvalidExit;
+ }
+
+ int i0 = Unsafe.Add(ref srcChars, srcLength - 4);
+ int i1 = Unsafe.Add(ref srcChars, srcLength - 3);
+ int i2 = Unsafe.Add(ref srcChars, srcLength - 2);
+ int i3 = Unsafe.Add(ref srcChars, srcLength - 1);
+ if (((i0 | i1 | i2 | i3) & 0xffffff00) != 0)
+ goto InvalidExit;
+
+ i0 = Unsafe.Add(ref decodingMap, i0);
+ i1 = Unsafe.Add(ref decodingMap, i1);
+
+ i0 <<= 18;
+ i1 <<= 12;
+
+ i0 |= i1;
+
+ if (i3 != EncodingPad)
+ {
+ i2 = Unsafe.Add(ref decodingMap, i2);
+ i3 = Unsafe.Add(ref decodingMap, i3);
+
+ i2 <<= 6;
+
+ i0 |= i3;
+ i0 |= i2;
+
+ if (i0 < 0)
+ goto InvalidExit;
+ if (destIndex > destLength - 3)
+ goto InvalidExit;
+ WriteThreeLowOrderBytes(ref Unsafe.Add(ref destBytes, destIndex), i0);
+ destIndex += 3;
+ }
+ else if (i2 != EncodingPad)
+ {
+ i2 = Unsafe.Add(ref decodingMap, i2);
+
+ i2 <<= 6;
+
+ i0 |= i2;
+
+ if (i0 < 0)
+ goto InvalidExit;
+ if (destIndex > destLength - 2)
+ goto InvalidExit;
+ Unsafe.Add(ref destBytes, destIndex) = (byte)(i0 >> 16);
+ Unsafe.Add(ref destBytes, destIndex + 1) = (byte)(i0 >> 8);
+ destIndex += 2;
+ }
+ else
+ {
+ if (i0 < 0)
+ goto InvalidExit;
+ if (destIndex > destLength - 1)
+ goto InvalidExit;
+ Unsafe.Add(ref destBytes, destIndex) = (byte)(i0 >> 16);
+ destIndex += 1;
+ }
+
+ sourceIndex += 4;
+
+ if (srcLength != utf16.Length)
+ goto InvalidExit;
+
+ DoneExit:
+ consumed = sourceIndex;
+ written = destIndex;
+ return true;
+
+ InvalidExit:
+ consumed = sourceIndex;
+ written = destIndex;
+ Debug.Assert((consumed % 4) == 0);
+ return false;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static int Decode(ref char encodedChars, ref sbyte decodingMap)
+ {
+ int i0 = encodedChars;
+ int i1 = Unsafe.Add(ref encodedChars, 1);
+ int i2 = Unsafe.Add(ref encodedChars, 2);
+ int i3 = Unsafe.Add(ref encodedChars, 3);
+
+ if (((i0 | i1 | i2 | i3) & 0xffffff00) != 0)
+ return -1; // One or more chars falls outside the 00..ff range. This cannot be a valid Base64 character.
+
+ i0 = Unsafe.Add(ref decodingMap, i0);
+ i1 = Unsafe.Add(ref decodingMap, i1);
+ i2 = Unsafe.Add(ref decodingMap, i2);
+ i3 = Unsafe.Add(ref decodingMap, i3);
+
+ i0 <<= 18;
+ i1 <<= 12;
+ i2 <<= 6;
+
+ i0 |= i3;
+ i1 |= i2;
+
+ i0 |= i1;
+ return i0;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void WriteThreeLowOrderBytes(ref byte destination, int value)
+ {
+ destination = (byte)(value >> 16);
+ Unsafe.Add(ref destination, 1) = (byte)(value >> 8);
+ Unsafe.Add(ref destination, 2) = (byte)value;
+ }
+
+ // Pre-computing this table using a custom string(s_characters) and GenerateDecodingMapAndVerify (found in tests)
+ private static readonly sbyte[] s_decodingMap = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, //62 is placed at index 43 (for +), 63 at index 47 (for /)
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, //52-61 are placed at index 48-57 (for 0-9), 64 at index 61 (for =)
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, //0-25 are placed at index 65-90 (for A-Z)
+ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, //26-51 are placed at index 97-122 (for a-z)
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Bytes over 122 ('z') are invalid and cannot be decoded
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Hence, padding the map with 255, which indicates invalid input
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ };
+
+ private const byte EncodingPad = (byte)'='; // '=', for padding
+ }
+}
diff --git a/src/Common/src/CoreLib/System/Convert.cs b/src/Common/src/CoreLib/System/Convert.cs
index 488ea77338..63342ad000 100644
--- a/src/Common/src/CoreLib/System/Convert.cs
+++ b/src/Common/src/CoreLib/System/Convert.cs
@@ -96,7 +96,7 @@ namespace System
// When passed Value.DBNull, the Value.ToXXX() methods all throw an
// InvalidCastException.
- public static class Convert
+ public static partial class Convert
{
//A typeof operation is fairly expensive (does a system call), so we'll cache these here
//statically. These are exactly lined up with the TypeCode, eg. ConvertType[TypeCode.Int16]
@@ -2198,7 +2198,7 @@ namespace System
return 0;
}
- int r = ParseNumbers.StringToInt(value.AsReadOnlySpan(), fromBase, ParseNumbers.IsTight | ParseNumbers.TreatAsUnsigned);
+ int r = ParseNumbers.StringToInt(value.AsSpan(), fromBase, ParseNumbers.IsTight | ParseNumbers.TreatAsUnsigned);
if (r < Byte.MinValue || r > Byte.MaxValue)
ThrowByteOverflowException();
return (byte)r;
@@ -2221,7 +2221,7 @@ namespace System
return 0;
}
- int r = ParseNumbers.StringToInt(value.AsReadOnlySpan(), fromBase, ParseNumbers.IsTight | ParseNumbers.TreatAsI1);
+ int r = ParseNumbers.StringToInt(value.AsSpan(), fromBase, ParseNumbers.IsTight | ParseNumbers.TreatAsI1);
if (fromBase != 10 && r <= Byte.MaxValue)
return (sbyte)r;
@@ -2246,7 +2246,7 @@ namespace System
return 0;
}
- int r = ParseNumbers.StringToInt(value.AsReadOnlySpan(), fromBase, ParseNumbers.IsTight | ParseNumbers.TreatAsI2);
+ int r = ParseNumbers.StringToInt(value.AsSpan(), fromBase, ParseNumbers.IsTight | ParseNumbers.TreatAsI2);
if (fromBase != 10 && r <= UInt16.MaxValue)
return (short)r;
@@ -2272,7 +2272,7 @@ namespace System
return 0;
}
- int r = ParseNumbers.StringToInt(value.AsReadOnlySpan(), fromBase, ParseNumbers.IsTight | ParseNumbers.TreatAsUnsigned);
+ int r = ParseNumbers.StringToInt(value.AsSpan(), fromBase, ParseNumbers.IsTight | ParseNumbers.TreatAsUnsigned);
if (r < UInt16.MinValue || r > UInt16.MaxValue)
ThrowUInt16OverflowException();
return (ushort)r;
@@ -2289,7 +2289,7 @@ namespace System
throw new ArgumentException(SR.Arg_InvalidBase);
}
return value != null ?
- ParseNumbers.StringToInt(value.AsReadOnlySpan(), fromBase, ParseNumbers.IsTight) :
+ ParseNumbers.StringToInt(value.AsSpan(), fromBase, ParseNumbers.IsTight) :
0;
}
@@ -2305,7 +2305,7 @@ namespace System
throw new ArgumentException(SR.Arg_InvalidBase);
}
return value != null ?
- (uint)ParseNumbers.StringToInt(value.AsReadOnlySpan(), fromBase, ParseNumbers.TreatAsUnsigned | ParseNumbers.IsTight) :
+ (uint)ParseNumbers.StringToInt(value.AsSpan(), fromBase, ParseNumbers.TreatAsUnsigned | ParseNumbers.IsTight) :
0;
}
@@ -2320,7 +2320,7 @@ namespace System
throw new ArgumentException(SR.Arg_InvalidBase);
}
return value != null ?
- ParseNumbers.StringToLong(value.AsReadOnlySpan(), fromBase, ParseNumbers.IsTight) :
+ ParseNumbers.StringToLong(value.AsSpan(), fromBase, ParseNumbers.IsTight) :
0;
}
@@ -2336,7 +2336,7 @@ namespace System
throw new ArgumentException(SR.Arg_InvalidBase);
}
return value != null ?
- (ulong)ParseNumbers.StringToLong(value.AsReadOnlySpan(), fromBase, ParseNumbers.TreatAsUnsigned | ParseNumbers.IsTight) :
+ (ulong)ParseNumbers.StringToLong(value.AsSpan(), fromBase, ParseNumbers.TreatAsUnsigned | ParseNumbers.IsTight) :
0;
}
@@ -2653,47 +2653,127 @@ namespace System
throw new ArgumentNullException(nameof(s));
}
- return TryFromBase64Chars(s.AsReadOnlySpan(), bytes, out bytesWritten);
+ return TryFromBase64Chars(s.AsSpan(), bytes, out bytesWritten);
}
- public static unsafe bool TryFromBase64Chars(ReadOnlySpan<char> chars, Span<byte> bytes, out int bytesWritten)
+ public static bool TryFromBase64Chars(ReadOnlySpan<char> chars, Span<byte> bytes, out int bytesWritten)
{
- if (chars.Length == 0)
- {
- bytesWritten = 0;
- return true;
- }
+ // This is actually local to one of the nested blocks but is being declared at the top as we don't want multiple stackallocs
+ // for each iteraton of the loop.
+ Span<char> tempBuffer = stackalloc char[4]; // Note: The tempBuffer size could be made larger than 4 but the size must be a multiple of 4.
- // We need to get rid of any trailing white spaces.
- // Otherwise we would be rejecting input such as "abc= ":
- while (chars.Length > 0)
+ bytesWritten = 0;
+
+ while (chars.Length != 0)
{
- char lastChar = chars[chars.Length - 1];
- if (lastChar != ' ' && lastChar != '\n' && lastChar != '\r' && lastChar != '\t')
+ // Attempt to decode a segment that doesn't contain whitespace.
+ bool complete = TryDecodeFromUtf16(chars, bytes, out int consumedInThisIteration, out int bytesWrittenInThisIteration);
+ bytesWritten += bytesWrittenInThisIteration;
+ if (complete)
+ return true;
+
+ chars = chars.Slice(consumedInThisIteration);
+ bytes = bytes.Slice(bytesWrittenInThisIteration);
+
+ Debug.Assert(chars.Length != 0); // If TryDecodeFromUtf16() consumed the entire buffer, it could not have returned false.
+ if (chars[0].IsSpace())
{
- break;
- }
- chars = chars.Slice(0, chars.Length - 1);
- }
+ // If we got here, the very first character not consumed was a whitespace. We can skip past any consecutive whitespace, then continue decoding.
- fixed (char* charsPtr = &MemoryMarshal.GetReference(chars))
- {
- int resultLength = FromBase64_ComputeResultLength(charsPtr, chars.Length);
- Debug.Assert(resultLength >= 0);
- if (resultLength > bytes.Length)
+ int indexOfFirstNonSpace = 1;
+ for (; ; )
+ {
+ if (indexOfFirstNonSpace == chars.Length)
+ break;
+ if (!chars[indexOfFirstNonSpace].IsSpace())
+ break;
+ indexOfFirstNonSpace++;
+ }
+
+ chars = chars.Slice(indexOfFirstNonSpace);
+
+ if ((bytesWrittenInThisIteration % 3) != 0 && chars.Length != 0)
+ {
+ // If we got here, the last successfully decoded block encountered an end-marker, yet we have trailing non-whitespace characters.
+ // That is not allowed.
+ bytesWritten = default;
+ return false;
+ }
+
+ // We now loop again to decode the next run of non-space characters.
+ }
+ else
{
- bytesWritten = 0;
- return false;
+ Debug.Assert(chars.Length != 0 && !chars[0].IsSpace());
+
+ // If we got here, it is possible that there is whitespace that occurred in the middle of a 4-byte chunk. That is, we still have
+ // up to three Base64 characters that were left undecoded by the fast-path helper because they didn't form a complete 4-byte chunk.
+ // This is hopefully the rare case (multiline-formatted base64 message with a non-space character width that's not a multiple of 4.)
+ // We'll filter out whitespace and copy the remaining characters into a temporary buffer.
+ CopyToTempBufferWithoutWhiteSpace(chars, tempBuffer, out int consumedFromChars, out int charsWritten);
+ if ((charsWritten & 0x3) != 0)
+ {
+ // Even after stripping out whitespace, the number of characters is not divisible by 4. This cannot be a legal Base64 string.
+ bytesWritten = default;
+ return false;
+ }
+
+ tempBuffer = tempBuffer.Slice(0, charsWritten);
+ if (!TryDecodeFromUtf16(tempBuffer, bytes, out int consumedFromTempBuffer, out int bytesWrittenFromTempBuffer))
+ {
+ bytesWritten = default;
+ return false;
+ }
+ bytesWritten += bytesWrittenFromTempBuffer;
+ chars = chars.Slice(consumedFromChars);
+ bytes = bytes.Slice(bytesWrittenFromTempBuffer);
+
+ if ((bytesWrittenFromTempBuffer % 3) != 0)
+ {
+ // If we got here, this decode contained one or more padding characters ('='). We can accept trailing whitespace after this
+ // but nothing else.
+ for (int i = 0; i < chars.Length; i++)
+ {
+ if (!chars[i].IsSpace())
+ {
+ bytesWritten = default;
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // We now loop again to decode the next run of non-space characters.
}
+ }
- fixed (byte* bytesPtr = &MemoryMarshal.GetReference(bytes))
+ return true;
+ }
+
+ private static void CopyToTempBufferWithoutWhiteSpace(ReadOnlySpan<char> chars, Span<char> tempBuffer, out int consumed, out int charsWritten)
+ {
+ Debug.Assert(tempBuffer.Length != 0); // We only bound-check after writing a character to the tempBuffer.
+
+ charsWritten = 0;
+ for (int i = 0; i < chars.Length; i++)
+ {
+ char c = chars[i];
+ if (!c.IsSpace())
{
- bytesWritten = FromBase64_Decode(charsPtr, chars.Length, bytesPtr, bytes.Length);
- return true;
+ tempBuffer[charsWritten++] = c;
+ if (charsWritten == tempBuffer.Length)
+ {
+ consumed = i + 1;
+ return;
+ }
}
}
+ consumed = chars.Length;
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static bool IsSpace(this char c) => c == ' ' || c == '\t' || c == '\r' || c == '\n';
+
/// <summary>
/// Converts the specified range of a Char array, which encodes binary data as Base64 digits, to the equivalent byte array.
/// </summary>
@@ -2730,8 +2810,6 @@ namespace System
}
}
-
-
/// <summary>
/// Convert Base64 encoding characters to bytes:
/// - Compute result length exactly by actually walking the input;
@@ -2769,11 +2847,10 @@ namespace System
Byte[] decodedBytes = new Byte[resultLength];
// Convert Base64 chars into bytes:
- Int32 actualResultLength;
- fixed (Byte* decodedBytesPtr = decodedBytes)
- actualResultLength = FromBase64_Decode(inputPtr, inputLength, decodedBytesPtr, resultLength);
+ if (!TryFromBase64Chars(new ReadOnlySpan<char>(inputPtr, inputLength), decodedBytes, out int _))
+ throw new FormatException(SR.Format_BadBase64Char);
- // Note that actualResultLength can differ from resultLength if the caller is modifying the array
+ // Note that the number of bytes written can differ from resultLength if the caller is modifying the array
// as it is being converted. Silently ignore the failure.
// Consider throwing exception in an non in-place release.
@@ -2781,199 +2858,6 @@ namespace System
return decodedBytes;
}
-
- /// <summary>
- /// Decode characters representing a Base64 encoding into bytes:
- /// Walk the input. Every time 4 chars are read, convert them to the 3 corresponding output bytes.
- /// This method is a bit lengthy on purpose. We are trying to avoid jumps to helpers in the loop
- /// to aid performance.
- /// </summary>
- /// <param name="inputPtr">Pointer to first input char</param>
- /// <param name="inputLength">Number of input chars</param>
- /// <param name="destPtr">Pointer to location for the first result byte</param>
- /// <param name="destLength">Max length of the preallocated result buffer</param>
- /// <returns>If the result buffer was not large enough to write all result bytes, return -1;
- /// Otherwise return the number of result bytes actually produced.</returns>
- private static unsafe Int32 FromBase64_Decode(Char* startInputPtr, Int32 inputLength, Byte* startDestPtr, Int32 destLength)
- {
- // You may find this method weird to look at. It's written for performance, not aesthetics.
- // You will find unrolled loops label jumps and bit manipulations.
-
- const UInt32 intA = (UInt32)'A';
- const UInt32 inta = (UInt32)'a';
- const UInt32 int0 = (UInt32)'0';
- const UInt32 intEq = (UInt32)'=';
- const UInt32 intPlus = (UInt32)'+';
- const UInt32 intSlash = (UInt32)'/';
- const UInt32 intSpace = (UInt32)' ';
- const UInt32 intTab = (UInt32)'\t';
- const UInt32 intNLn = (UInt32)'\n';
- const UInt32 intCRt = (UInt32)'\r';
- const UInt32 intAtoZ = (UInt32)('Z' - 'A'); // = ('z' - 'a')
- const UInt32 int0to9 = (UInt32)('9' - '0');
-
- Char* inputPtr = startInputPtr;
- Byte* destPtr = startDestPtr;
-
- // Pointers to the end of input and output:
- Char* endInputPtr = inputPtr + inputLength;
- Byte* endDestPtr = destPtr + destLength;
-
- // Current char code/value:
- UInt32 currCode;
-
- // This 4-byte integer will contain the 4 codes of the current 4-char group.
- // Eeach char codes for 6 bits = 24 bits.
- // The remaining byte will be FF, we use it as a marker when 4 chars have been processed.
- UInt32 currBlockCodes = 0x000000FFu;
-
- unchecked
- {
- while (true)
- {
- // break when done:
- if (inputPtr >= endInputPtr)
- goto _AllInputConsumed;
-
- // Get current char:
- currCode = (UInt32)(*inputPtr);
- inputPtr++;
-
- // Determine current char code:
-
- if (currCode - intA <= intAtoZ)
- currCode -= intA;
-
- else if (currCode - inta <= intAtoZ)
- currCode -= (inta - 26u);
-
- else if (currCode - int0 <= int0to9)
- currCode -= (int0 - 52u);
-
- else
- {
- // Use the slower switch for less common cases:
- switch (currCode)
- {
- // Significant chars:
- case intPlus:
- currCode = 62u;
- break;
-
- case intSlash:
- currCode = 63u;
- break;
-
- // Legal no-value chars (we ignore these):
- case intCRt:
- case intNLn:
- case intSpace:
- case intTab:
- continue;
-
- // The equality char is only legal at the end of the input.
- // Jump after the loop to make it easier for the JIT register predictor to do a good job for the loop itself:
- case intEq:
- goto _EqualityCharEncountered;
-
- // Other chars are illegal:
- default:
- throw new FormatException(SR.Format_BadBase64Char);
- }
- }
-
- // Ok, we got the code. Save it:
- currBlockCodes = (currBlockCodes << 6) | currCode;
-
- // Last bit in currBlockCodes will be on after in shifted right 4 times:
- if ((currBlockCodes & 0x80000000u) != 0u)
- {
- if ((Int32)(endDestPtr - destPtr) < 3)
- return -1;
-
- *(destPtr) = (Byte)(currBlockCodes >> 16);
- *(destPtr + 1) = (Byte)(currBlockCodes >> 8);
- *(destPtr + 2) = (Byte)(currBlockCodes);
- destPtr += 3;
-
- currBlockCodes = 0x000000FFu;
- }
- }
- } // unchecked while
-
- // 'd be nice to have an assert that we never get here, but CS0162: Unreachable code detected.
- // Debug.Fail("We only leave the above loop by jumping; should never get here.");
-
- // We jump here out of the loop if we hit an '=':
- _EqualityCharEncountered:
-
- Debug.Assert(currCode == intEq);
-
- // Recall that inputPtr is now one position past where '=' was read.
- // '=' can only be at the last input pos:
- if (inputPtr == endInputPtr)
- {
- // Code is zero for trailing '=':
- currBlockCodes <<= 6;
-
- // The '=' did not complete a 4-group. The input must be bad:
- if ((currBlockCodes & 0x80000000u) == 0u)
- throw new FormatException(SR.Format_BadBase64CharArrayLength);
-
- if ((int)(endDestPtr - destPtr) < 2) // Autch! We underestimated the output length!
- return -1;
-
- // We are good, store bytes form this past group. We had a single "=", so we take two bytes:
- *(destPtr++) = (Byte)(currBlockCodes >> 16);
- *(destPtr++) = (Byte)(currBlockCodes >> 8);
-
- currBlockCodes = 0x000000FFu;
- }
- else
- { // '=' can also be at the pre-last position iff the last is also a '=' excluding the white spaces:
- // We need to get rid of any intermediate white spaces.
- // Otherwise we would be rejecting input such as "abc= =":
- while (inputPtr < (endInputPtr - 1))
- {
- Int32 lastChar = *(inputPtr);
- if (lastChar != (Int32)' ' && lastChar != (Int32)'\n' && lastChar != (Int32)'\r' && lastChar != (Int32)'\t')
- break;
- inputPtr++;
- }
-
- if (inputPtr == (endInputPtr - 1) && *(inputPtr) == '=')
- {
- // Code is zero for each of the two '=':
- currBlockCodes <<= 12;
-
- // The '=' did not complete a 4-group. The input must be bad:
- if ((currBlockCodes & 0x80000000u) == 0u)
- throw new FormatException(SR.Format_BadBase64CharArrayLength);
-
- if ((Int32)(endDestPtr - destPtr) < 1) // Autch! We underestimated the output length!
- return -1;
-
- // We are good, store bytes form this past group. We had a "==", so we take only one byte:
- *(destPtr++) = (Byte)(currBlockCodes >> 16);
-
- currBlockCodes = 0x000000FFu;
- }
- else // '=' is not ok at places other than the end:
- throw new FormatException(SR.Format_BadBase64Char);
- }
-
- // We get here either from above or by jumping out of the loop:
- _AllInputConsumed:
-
- // The last block of chars has less than 4 items
- if (currBlockCodes != 0x000000FFu)
- throw new FormatException(SR.Format_BadBase64CharArrayLength);
-
- // Return how many bytes were actually recovered:
- return (Int32)(destPtr - startDestPtr);
- } // Int32 FromBase64_Decode(...)
-
-
/// <summary>
/// Compute the number of bytes encoded in the specified Base 64 char array:
/// Walk the entire input counting white spaces and padding chars, then compute result length
diff --git a/src/Common/src/CoreLib/System/DateTime.cs b/src/Common/src/CoreLib/System/DateTime.cs
index b5deefa94a..9c3b3989e4 100644
--- a/src/Common/src/CoreLib/System/DateTime.cs
+++ b/src/Common/src/CoreLib/System/DateTime.cs
@@ -1141,13 +1141,6 @@ namespace System
return (DateTimeParse.ParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style));
}
- // TODO https://github.com/dotnet/corefx/issues/25337: Remove this overload once corefx is updated to target the new signatures
- public static DateTime ParseExact(ReadOnlySpan<char> s, string format, IFormatProvider provider, DateTimeStyles style)
- {
- if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format);
- return ParseExact(s, (ReadOnlySpan<char>)format, provider, style);
- }
-
public static DateTime ParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, IFormatProvider provider, DateTimeStyles style = DateTimeStyles.None)
{
DateTimeFormatInfo.ValidateStyles(style, nameof(style));
@@ -1262,50 +1255,46 @@ namespace System
public String ToLongDateString()
{
- return DateTimeFormat.Format(this, "D", DateTimeFormatInfo.CurrentInfo);
+ return DateTimeFormat.Format(this, "D", null);
}
public String ToLongTimeString()
{
- return DateTimeFormat.Format(this, "T", DateTimeFormatInfo.CurrentInfo);
+ return DateTimeFormat.Format(this, "T", null);
}
public String ToShortDateString()
{
- return DateTimeFormat.Format(this, "d", DateTimeFormatInfo.CurrentInfo);
+ return DateTimeFormat.Format(this, "d", null);
}
public String ToShortTimeString()
{
- return DateTimeFormat.Format(this, "t", DateTimeFormatInfo.CurrentInfo);
+ return DateTimeFormat.Format(this, "t", null);
}
public override String ToString()
{
- return DateTimeFormat.Format(this, null, DateTimeFormatInfo.CurrentInfo);
+ return DateTimeFormat.Format(this, null, null);
}
public String ToString(String format)
{
- return DateTimeFormat.Format(this, format, DateTimeFormatInfo.CurrentInfo);
+ return DateTimeFormat.Format(this, format, null);
}
public String ToString(IFormatProvider provider)
{
- return DateTimeFormat.Format(this, null, DateTimeFormatInfo.GetInstance(provider));
+ return DateTimeFormat.Format(this, null, provider);
}
public String ToString(String format, IFormatProvider provider)
{
- return DateTimeFormat.Format(this, format, DateTimeFormatInfo.GetInstance(provider));
+ return DateTimeFormat.Format(this, format, provider);
}
- // TODO https://github.com/dotnet/corefx/issues/25337: Remove this overload once corefx is updated to target the new signatures
- public bool TryFormat(Span<char> destination, out int charsWritten, string format, IFormatProvider provider) =>
- TryFormat(destination, out charsWritten, (ReadOnlySpan<char>)format, provider);
-
public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider provider = null) =>
- DateTimeFormat.TryFormat(this, destination, out charsWritten, format, DateTimeFormatInfo.GetInstance(provider));
+ DateTimeFormat.TryFormat(this, destination, out charsWritten, format, provider);
public DateTime ToUniversalTime()
{
@@ -1359,18 +1348,6 @@ namespace System
return DateTimeParse.TryParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style, out result);
}
- // TODO https://github.com/dotnet/corefx/issues/25337: Remove this overload once corefx is updated to target the new signatures
- public static bool TryParseExact(ReadOnlySpan<char> s, string format, IFormatProvider provider, DateTimeStyles style, out DateTime result)
- {
- if (format == null)
- {
- result = default;
- return false;
- }
-
- return TryParseExact(s, (ReadOnlySpan<char>)format, provider, style, out result);
- }
-
public static bool TryParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, IFormatProvider provider, DateTimeStyles style, out DateTime result)
{
DateTimeFormatInfo.ValidateStyles(style, nameof(style));
diff --git a/src/Common/src/CoreLib/System/DateTimeOffset.cs b/src/Common/src/CoreLib/System/DateTimeOffset.cs
index bb2196348c..3c3f3f42a2 100644
--- a/src/Common/src/CoreLib/System/DateTimeOffset.cs
+++ b/src/Common/src/CoreLib/System/DateTimeOffset.cs
@@ -669,13 +669,6 @@ namespace System
return new DateTimeOffset(dateResult.Ticks, offset);
}
- // TODO https://github.com/dotnet/corefx/issues/25337: Remove this overload once corefx is updated to target the new signatures
- public static DateTimeOffset ParseExact(ReadOnlySpan<char> input, string format, IFormatProvider formatProvider, DateTimeStyles styles)
- {
- if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format);
- return ParseExact(input, (ReadOnlySpan<char>)format, formatProvider, styles);
- }
-
public static DateTimeOffset ParseExact(ReadOnlySpan<char> input, ReadOnlySpan<char> format, IFormatProvider formatProvider, DateTimeStyles styles = DateTimeStyles.None)
{
styles = ValidateStyles(styles, nameof(styles));
@@ -762,30 +755,26 @@ namespace System
public override String ToString()
{
- return DateTimeFormat.Format(ClockDateTime, null, DateTimeFormatInfo.CurrentInfo, Offset);
+ return DateTimeFormat.Format(ClockDateTime, null, null, Offset);
}
public String ToString(String format)
{
- return DateTimeFormat.Format(ClockDateTime, format, DateTimeFormatInfo.CurrentInfo, Offset);
+ return DateTimeFormat.Format(ClockDateTime, format, null, Offset);
}
public String ToString(IFormatProvider formatProvider)
{
- return DateTimeFormat.Format(ClockDateTime, null, DateTimeFormatInfo.GetInstance(formatProvider), Offset);
+ return DateTimeFormat.Format(ClockDateTime, null, formatProvider, Offset);
}
public String ToString(String format, IFormatProvider formatProvider)
{
- return DateTimeFormat.Format(ClockDateTime, format, DateTimeFormatInfo.GetInstance(formatProvider), Offset);
+ return DateTimeFormat.Format(ClockDateTime, format, formatProvider, Offset);
}
- // TODO https://github.com/dotnet/corefx/issues/25337: Remove this overload once corefx is updated to target the new signatures
- public bool TryFormat(Span<char> destination, out int charsWritten, string format, IFormatProvider provider) =>
- TryFormat(destination, out charsWritten, (ReadOnlySpan<char>)format, provider);
-
public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format = default, IFormatProvider formatProvider = null) =>
- DateTimeFormat.TryFormat(ClockDateTime, destination, out charsWritten, format, DateTimeFormatInfo.GetInstance(formatProvider), Offset);
+ DateTimeFormat.TryFormat(ClockDateTime, destination, out charsWritten, format, formatProvider, Offset);
public DateTimeOffset ToUniversalTime()
{
@@ -862,18 +851,6 @@ namespace System
return parsed;
}
- // TODO https://github.com/dotnet/corefx/issues/25337: Remove this overload once corefx is updated to target the new signatures
- public static bool TryParseExact(ReadOnlySpan<char> input, string format, IFormatProvider formatProvider, DateTimeStyles styles, out DateTimeOffset result)
- {
- if (format == null)
- {
- result = default;
- return false;
- }
-
- return TryParseExact(input, (ReadOnlySpan<char>)format, formatProvider, styles, out result);
- }
-
public static bool TryParseExact(
ReadOnlySpan<char> input, ReadOnlySpan<char> format, IFormatProvider formatProvider, DateTimeStyles styles, out DateTimeOffset result)
{
diff --git a/src/Common/src/CoreLib/System/Diagnostics/Debug.Unix.cs b/src/Common/src/CoreLib/System/Diagnostics/Debug.Unix.cs
index 495f2f713c..627ea4ab7e 100644
--- a/src/Common/src/CoreLib/System/Diagnostics/Debug.Unix.cs
+++ b/src/Common/src/CoreLib/System/Diagnostics/Debug.Unix.cs
@@ -10,7 +10,7 @@ namespace System.Diagnostics
{
private static readonly bool s_shouldWriteToStdErr = Environment.GetEnvironmentVariable("COMPlus_DebugWriteToStdErr") == "1";
- private static void ShowAssertDialog(string stackTrace, string message, string detailMessage)
+ private static void ShowDialog(string stackTrace, string message, string detailMessage, string errorSource)
{
if (Debugger.IsAttached)
{
@@ -21,8 +21,20 @@ namespace System.Diagnostics
// In Core, we do not show a dialog.
// Fail in order to avoid anyone catching an exception and masking
// an assert failure.
- var ex = new DebugAssertException(message, detailMessage, stackTrace);
- Environment.FailFast(ex.Message, ex);
+ DebugAssertException ex;
+ if (message == String.Empty)
+ {
+ ex = new DebugAssertException(stackTrace);
+ }
+ else if (detailMessage == String.Empty)
+ {
+ ex = new DebugAssertException(message, stackTrace);
+ }
+ else
+ {
+ ex = new DebugAssertException(message, detailMessage, stackTrace);
+ }
+ Environment.FailFast(ex.Message, ex, errorSource);
}
}
diff --git a/src/Common/src/CoreLib/System/Diagnostics/Debug.cs b/src/Common/src/CoreLib/System/Diagnostics/Debug.cs
index 5178f7f5c5..7bc43ccfcb 100644
--- a/src/Common/src/CoreLib/System/Diagnostics/Debug.cs
+++ b/src/Common/src/CoreLib/System/Diagnostics/Debug.cs
@@ -4,6 +4,8 @@
// Do not remove this, it is needed to retain calls to these conditional methods in release builds
#define DEBUG
+using System.Diagnostics.Contracts;
+using System.Runtime.CompilerServices;
namespace System.Diagnostics
{
@@ -91,18 +93,34 @@ namespace System.Diagnostics
if (!condition)
{
string stackTrace;
-
try
{
- stackTrace = Internal.Runtime.Augments.EnvironmentAugments.StackTrace;
+ stackTrace = new StackTrace(0, true).ToString(System.Diagnostics.StackTrace.TraceFormat.Normal);
}
catch
{
stackTrace = "";
}
+ WriteLine(FormatAssert(stackTrace, message, detailMessage));
+ s_ShowDialog(stackTrace, message, detailMessage, "Assertion Failed");
+ }
+ }
+ internal static void ContractFailure(bool condition, string message, string detailMessage, string failureKindMessage)
+ {
+ if (!condition)
+ {
+ string stackTrace;
+ try
+ {
+ stackTrace = new StackTrace(2, true).ToString(System.Diagnostics.StackTrace.TraceFormat.Normal);
+ }
+ catch
+ {
+ stackTrace = "";
+ }
WriteLine(FormatAssert(stackTrace, message, detailMessage));
- s_ShowAssertDialog(stackTrace, message, detailMessage);
+ s_ShowDialog(stackTrace, message, detailMessage, SR.GetResourceString(failureKindMessage));
}
}
@@ -308,14 +326,25 @@ namespace System.Diagnostics
private sealed class DebugAssertException : Exception
{
+ internal DebugAssertException(string stackTrace) :
+ base(Environment.NewLine + stackTrace)
+ {
+ }
+
+ internal DebugAssertException(string message, string stackTrace) :
+ base(message + Environment.NewLine + Environment.NewLine + stackTrace)
+ {
+ }
+
internal DebugAssertException(string message, string detailMessage, string stackTrace) :
- base(message + Environment.NewLine + detailMessage + Environment.NewLine + stackTrace)
+ base(message + Environment.NewLine + detailMessage + Environment.NewLine + Environment.NewLine + stackTrace)
{
}
}
// internal and not readonly so that the tests can swap this out.
- internal static Action<string, string, string> s_ShowAssertDialog = ShowAssertDialog;
+ internal static Action<string, string, string, string> s_ShowDialog = ShowDialog;
+
internal static Action<string> s_WriteCore = WriteCore;
}
}
diff --git a/src/Common/src/CoreLib/System/Diagnostics/Tracing/ActivityTracker.cs b/src/Common/src/CoreLib/System/Diagnostics/Tracing/ActivityTracker.cs
index 9ac32c3bd6..d9f9f081cb 100644
--- a/src/Common/src/CoreLib/System/Diagnostics/Tracing/ActivityTracker.cs
+++ b/src/Common/src/CoreLib/System/Diagnostics/Tracing/ActivityTracker.cs
@@ -248,11 +248,6 @@ namespace System.Diagnostics.Tracing
#region private
/// <summary>
- /// The current activity ID. Use this to log normal events.
- /// </summary>
- private Guid CurrentActivityId { get { return m_current.Value.ActivityId; } }
-
- /// <summary>
/// Searched for a active (nonstopped) activity with the given name. Returns null if not found.
/// </summary>
private ActivityInfo FindActiveActivity(string name, ActivityInfo startLocation)
diff --git a/src/Common/src/CoreLib/System/Diagnostics/Tracing/EventDescriptor.cs b/src/Common/src/CoreLib/System/Diagnostics/Tracing/EventDescriptor.cs
index b036b28b4b..0fed7b5c00 100644
--- a/src/Common/src/CoreLib/System/Diagnostics/Tracing/EventDescriptor.cs
+++ b/src/Common/src/CoreLib/System/Diagnostics/Tracing/EventDescriptor.cs
@@ -168,6 +168,14 @@ namespace System.Diagnostics.Tracing
}
}
+ internal int TraceLoggingId
+ {
+ get
+ {
+ return m_traceloggingId;
+ }
+ }
+
public override bool Equals(object obj)
{
if (!(obj is EventDescriptor))
diff --git a/src/Common/src/CoreLib/System/Diagnostics/Tracing/EventProvider.cs b/src/Common/src/CoreLib/System/Diagnostics/Tracing/EventProvider.cs
index 64c2491769..c1e4298da8 100644
--- a/src/Common/src/CoreLib/System/Diagnostics/Tracing/EventProvider.cs
+++ b/src/Common/src/CoreLib/System/Diagnostics/Tracing/EventProvider.cs
@@ -182,7 +182,7 @@ namespace System.Diagnostics.Tracing
//
//
- // check if the object has been allready disposed
+ // check if the object has been already disposed
//
if (m_disposed) return;
@@ -259,12 +259,6 @@ namespace System.Diagnostics.Tracing
m_anyKeywordMask = anyKeyword;
m_allKeywordMask = allKeyword;
- // ES_SESSION_INFO is a marker for additional places we #ifdeffed out to remove
- // references to EnumerateTraceGuidsEx. This symbol is actually not used because
- // today we use FEATURE_ACTIVITYSAMPLING to determine if this code is there or not.
- // However we put it in the #if so that we don't lose the fact that this feature
- // switch is at least partially independent of FEATURE_ACTIVITYSAMPLING
-
List<Tuple<SessionInfo, bool>> sessionsChanged = GetSessions();
foreach (var session in sessionsChanged)
{
@@ -337,7 +331,7 @@ namespace System.Diagnostics.Tracing
protected EventKeywords MatchAnyKeyword { get { return (EventKeywords)m_anyKeywordMask; } set { m_anyKeywordMask = unchecked((long)value); } }
protected EventKeywords MatchAllKeyword { get { return (EventKeywords)m_allKeywordMask; } set { m_allKeywordMask = unchecked((long)value); } }
- static private int FindNull(byte[] buffer, int idx)
+ private static int FindNull(byte[] buffer, int idx)
{
while (idx < buffer.Length && buffer[idx] != 0)
idx++;
@@ -567,7 +561,7 @@ namespace System.Diagnostics.Tracing
if (filterData == null)
{
#if (!ES_BUILD_PCL && !ES_BUILD_PN && PLATFORM_WINDOWS)
- string regKey = @"\Microsoft\Windows\CurrentVersion\Winevt\Publishers\{" + m_providerName + "}";
+ string regKey = @"\Microsoft\Windows\CurrentVersion\Winevt\Publishers\{" + m_providerId + "}";
if (System.Runtime.InteropServices.Marshal.SizeOf(typeof(IntPtr)) == 8)
regKey = @"HKEY_LOCAL_MACHINE\Software" + @"\Wow6432Node" + regKey;
else
@@ -964,6 +958,8 @@ namespace System.Diagnostics.Tracing
List<int> refObjPosition = new List<int>(s_etwAPIMaxRefObjCount);
List<object> dataRefObj = new List<object>(s_etwAPIMaxRefObjCount);
EventData* userData = stackalloc EventData[2 * argCount];
+ for (int i = 0; i < 2 * argCount; i++)
+ userData[i] = default(EventData);
EventData* userDataPtr = (EventData*)userData;
byte* dataBuffer = stackalloc byte[s_basicTypeAllocationBufferSize * 2 * argCount]; // Assume 16 chars for non-string argument
byte* currentBuffer = dataBuffer;
@@ -1137,7 +1133,7 @@ namespace System.Diagnostics.Tracing
// <CallsSuppressUnmanagedCode Name="UnsafeNativeMethods.ManifestEtw.EventWrite(System.Int64,EventDescriptor&,System.UInt32,System.Void*):System.UInt32" />
// </SecurityKernel>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference")]
- internal unsafe protected bool WriteEvent(ref EventDescriptor eventDescriptor, IntPtr eventHandle, Guid* activityID, Guid* childActivityID, int dataCount, IntPtr data)
+ internal protected unsafe bool WriteEvent(ref EventDescriptor eventDescriptor, IntPtr eventHandle, Guid* activityID, Guid* childActivityID, int dataCount, IntPtr data)
{
if (childActivityID != null)
{
@@ -1161,6 +1157,7 @@ namespace System.Diagnostics.Tracing
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference")]
internal unsafe bool WriteEventRaw(
ref EventDescriptor eventDescriptor,
+ IntPtr eventHandle,
Guid* activityID,
Guid* relatedActivityID,
int dataCount,
@@ -1171,7 +1168,7 @@ namespace System.Diagnostics.Tracing
status = m_eventProvider.EventWriteTransferWrapper(
m_regHandle,
ref eventDescriptor,
- IntPtr.Zero,
+ eventHandle,
activityID,
relatedActivityID,
dataCount,
diff --git a/src/Common/src/CoreLib/System/Diagnostics/Tracing/EventSource.cs b/src/Common/src/CoreLib/System/Diagnostics/Tracing/EventSource.cs
index f6d4899843..1836a1f27d 100644
--- a/src/Common/src/CoreLib/System/Diagnostics/Tracing/EventSource.cs
+++ b/src/Common/src/CoreLib/System/Diagnostics/Tracing/EventSource.cs
@@ -4,10 +4,6 @@
// This program uses code hyperlinks available as part of the HyperAddin Visual Studio plug-in.
// It is available from http://www.codeplex.com/hyperAddin
-#if PLATFORM_WINDOWS && !ES_BUILD_STANDALONE && !CORECLR && !ES_BUILD_PN
-#define FEATURE_ACTIVITYSAMPLING
-#endif // !ES_BUILD_STANDALONE
-
#if ES_BUILD_STANDALONE
#define FEATURE_MANAGED_ETW_CHANNELS
// #define FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
@@ -24,13 +20,13 @@
//
// Conceptually and EventSouce is something takes event logging data from the source methods
// To the EventListener that can subscribe them. Note that CONCEPTUALLY EVENTSOURCES DON'T
-// KNOW ABOUT ETW!. The MODEL of the system is that there is a special EventListern Which
+// KNOW ABOUT ETW!. The MODEL of the system is that there is a special EventListener Which
// we will call the EtwEventListener, that forwards commands from ETW to EventSources and
// listeners to the EventSources and forwards on those events to ETW. THus the model should
// be that you DON'T NEED ETW.
//
// Now in actual practice, EventSouce have rather intimate knowledge of ETW and send events
-// to it directly, but this can be VIEWED AS AN OPTIMIATION.
+// to it directly, but this can be VIEWED AS AN OPTIMIZATION.
//
// Basic Event Data Flow:
//
@@ -115,13 +111,13 @@
//
// On output there are the following routines
// Writing to all listeners that are NOT ETW, we have the following routines
-// * WriteToAllListeners(ID, Guid*, COUNT, EventData*)
-// * WriteToAllListeners(ID, Guid*, object[])
-// * WriteToAllListeners(NAME, Guid*, EventPayload)
+// * WriteToAllListeners(ID, Guid*, Guid*, COUNT, EventData*)
+// * WriteToAllListeners(ID, Guid*, Guid*, object[])
+// * WriteToAllListeners(NAME, Guid*, Guid*, EventPayload)
//
// EventPayload is the internal type that implements the IDictionary<string, object> interface
// The EventListeners will pass back for serialized classes for nested object, but
-// WriteToAllListeners(NAME, Guid*, EventPayload) unpacks this uses the fields as if they
+// WriteToAllListeners(NAME, Guid*, Guid*, EventPayload) unpacks this uses the fields as if they
// were parameters to a method.
//
// The first two are used for the WriteEvent* case, and the later is used for the Write<T> case.
@@ -170,9 +166,6 @@
//
using System;
using System.Runtime.CompilerServices;
-#if FEATURE_ACTIVITYSAMPLING
-using System.Collections.Concurrent;
-#endif
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
@@ -308,83 +301,7 @@ namespace System.Diagnostics.Tracing
if (!IsEnabledCommon(m_eventSourceEnabled, m_level, m_matchAnyKeyword, level, keywords, channel))
return false;
-#if !FEATURE_ACTIVITYSAMPLING
-
return true;
-
-#else // FEATURE_ACTIVITYSAMPLING
-
- return true;
-
-#if OPTIMIZE_IS_ENABLED
- //================================================================================
- // 2013/03/06 - The code below is a possible optimization for IsEnabled(level, kwd)
- // in case activity tracing/sampling is enabled. The added complexity of this
- // code however weighs against having it "on" until we know it's really needed.
- // For now we'll have this #ifdef-ed out in case we see evidence this is needed.
- //================================================================================
-
- // At this point we believe the event is enabled, however we now need to check
- // if we filter because of activity
-
- // Optimization, all activity filters also register a delegate here, so if there
- // is no delegate, we know there are no activity filters, which means that there
- // is no additional filtering, which means that we can return true immediately.
- if (s_activityDying == null)
- return true;
-
- // if there's at least one legacy ETW listener we can't filter this
- if (m_legacySessions != null && m_legacySessions.Count > 0)
- return true;
-
- // if any event ID that triggers a new activity, or "transfers" activities
- // is covered by 'keywords' we can't filter this
- if (unchecked(((long)keywords & m_keywordTriggers)) != 0)
- return true;
-
- // See if all listeners have activity filters that would block the event.
- for (int perEventSourceSessionId = 0; perEventSourceSessionId < SessionMask.MAX; ++perEventSourceSessionId)
- {
- EtwSession etwSession = m_etwSessionIdMap[perEventSourceSessionId];
- if (etwSession == null)
- continue;
-
- ActivityFilter activityFilter = etwSession.m_activityFilter;
- if (activityFilter == null ||
- ActivityFilter.GetFilter(activityFilter, this) == null)
- {
- // No activity filter for ETW, if event is active for ETW, we can't filter.
- for (int i = 0; i < m_eventData.Length; i++)
- if (m_eventData[i].EnabledForETW)
- return true;
- }
- else if (ActivityFilter.IsCurrentActivityActive(activityFilter))
- return true;
- }
-
- // for regular event listeners
- var curDispatcher = m_Dispatchers;
- while (curDispatcher != null)
- {
- ActivityFilter activityFilter = curDispatcher.m_Listener.m_activityFilter;
- if (activityFilter == null)
- {
- // See if any event is enabled.
- for (int i = 0; i < curDispatcher.m_EventEnabled.Length; i++)
- if (curDispatcher.m_EventEnabled[i])
- return true;
- }
- else if (ActivityFilter.IsCurrentActivityActive(activityFilter))
- return true;
- curDispatcher = curDispatcher.m_Next;
- }
-
- // Every listener has an activity filter that is blocking writing the event,
- // thus the event is not enabled.
- return false;
-#endif // OPTIMIZE_IS_ENABLED
-
-#endif // FEATURE_ACTIVITYSAMPLING
}
/// <summary>
@@ -620,7 +537,7 @@ namespace System.Diagnostics.Tracing
}
}
- #region protected
+#region protected
/// <summary>
/// This is the constructor that most users will use to create their eventSource. It takes
/// no parameters. The ETW provider name and GUID of the EventSource are determined by the EventSource
@@ -689,6 +606,13 @@ namespace System.Diagnostics.Tracing
// typed event methods. Dynamically defined events (that use Write) hare defined on the fly and are handled elsewhere.
private unsafe void DefineEventPipeEvents()
{
+ // If the EventSource is set to emit all events as TraceLogging events, skip this initialization.
+ // Events will be defined when they are emitted for the first time.
+ if(SelfDescribingEvents)
+ {
+ return;
+ }
+
Debug.Assert(m_eventData != null);
Debug.Assert(m_provider != null);
int cnt = m_eventData.Length;
@@ -698,90 +622,30 @@ namespace System.Diagnostics.Tracing
if (eventID == 0)
continue;
+ byte[] metadata = EventPipeMetadataGenerator.Instance.GenerateEventMetadata(m_eventData[i]);
+ uint metadataLength = (metadata != null) ? (uint)metadata.Length : 0;
+
string eventName = m_eventData[i].Name;
Int64 keywords = m_eventData[i].Descriptor.Keywords;
uint eventVersion = m_eventData[i].Descriptor.Version;
uint level = m_eventData[i].Descriptor.Level;
- // evnetID : 4 bytes
- // eventName : (eventName.Length + 1) * 2 bytes
- // keywords : 8 bytes
- // eventVersion : 4 bytes
- // level : 4 bytes
- // parameterCount : 4 bytes
- uint metadataLength = 24 + ((uint)eventName.Length + 1) * 2;
-
- // Increase the metadataLength for the types of all parameters.
- metadataLength += (uint)m_eventData[i].Parameters.Length * 4;
-
- // Increase the metadataLength for the names of all parameters.
- foreach (var parameter in m_eventData[i].Parameters)
- {
- string parameterName = parameter.Name;
- metadataLength = metadataLength + ((uint)parameterName.Length + 1) * 2;
- }
-
- byte[] metadata = new byte[metadataLength];
-
- // Write metadata: evnetID, eventName, keywords, eventVersion, level, parameterCount, param1 type, param1 name...
fixed (byte *pMetadata = metadata)
{
- uint offset = 0;
- WriteToBuffer(pMetadata, metadataLength, ref offset, eventID);
- fixed(char *pEventName = eventName)
- {
- WriteToBuffer(pMetadata, metadataLength, ref offset, (byte *)pEventName, ((uint)eventName.Length + 1) * 2);
- }
- WriteToBuffer(pMetadata, metadataLength, ref offset, keywords);
- WriteToBuffer(pMetadata, metadataLength, ref offset, eventVersion);
- WriteToBuffer(pMetadata, metadataLength, ref offset, level);
- WriteToBuffer(pMetadata, metadataLength, ref offset, (uint)m_eventData[i].Parameters.Length);
- foreach (var parameter in m_eventData[i].Parameters)
- {
- // Write parameter type.
- WriteToBuffer(pMetadata, metadataLength, ref offset, (uint)Type.GetTypeCode(parameter.ParameterType));
-
- // Write parameter name.
- string parameterName = parameter.Name;
- fixed (char *pParameterName = parameterName)
- {
- WriteToBuffer(pMetadata, metadataLength, ref offset, (byte *)pParameterName, ((uint)parameterName.Length + 1) * 2);
- }
- }
- Debug.Assert(metadataLength == offset);
- IntPtr eventHandle = m_provider.m_eventProvider.DefineEventHandle(eventID, eventName, keywords, eventVersion, level, pMetadata, metadataLength);
- m_eventData[i].EventHandle = eventHandle;
- }
- }
- }
+ IntPtr eventHandle = m_provider.m_eventProvider.DefineEventHandle(
+ eventID,
+ eventName,
+ keywords,
+ eventVersion,
+ level,
+ pMetadata,
+ metadataLength);
- // Copy src to buffer and modify the offset.
- // Note: We know the buffer size ahead of time to make sure no buffer overflow.
- private static unsafe void WriteToBuffer(byte *buffer, uint bufferLength, ref uint offset, byte *src, uint srcLength)
- {
- Debug.Assert(bufferLength >= (offset + srcLength));
- for (int i = 0; i < srcLength; i++)
- {
- *(byte *)(buffer + offset + i) = *(byte *)(src + i);
+ Debug.Assert(eventHandle != IntPtr.Zero);
+ m_eventData[i].EventHandle = eventHandle;
+ }
}
- offset += srcLength;
- }
-
- // Copy uint value to buffer.
- private static unsafe void WriteToBuffer(byte *buffer, uint bufferLength, ref uint offset, uint value)
- {
- Debug.Assert(bufferLength >= (offset + 4));
- *(uint *)(buffer + offset) = value;
- offset += 4;
}
-
- // Copy long value to buffer.
- private static unsafe void WriteToBuffer(byte *buffer, uint bufferLength, ref uint offset, long value)
- {
- Debug.Assert(bufferLength >= (offset + 8));
- *(long *)(buffer + offset) = value;
- offset += 8;
- }
#endif
internal virtual void GetMetadata(out Guid eventSourceGuid, out string eventSourceName, out EventMetadata[] eventData, out byte[] manifestBytes)
@@ -825,6 +689,7 @@ namespace System.Diagnostics.Tracing
EventSource.EventData* descrs = stackalloc EventSource.EventData[1];
descrs[0].DataPointer = (IntPtr)(&arg1);
descrs[0].Size = 4;
+ descrs[0].Reserved = 0;
WriteEventCore(eventId, 1, descrs);
}
}
@@ -837,8 +702,10 @@ namespace System.Diagnostics.Tracing
EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
descrs[0].DataPointer = (IntPtr)(&arg1);
descrs[0].Size = 4;
+ descrs[0].Reserved = 0;
descrs[1].DataPointer = (IntPtr)(&arg2);
descrs[1].Size = 4;
+ descrs[1].Reserved = 0;
WriteEventCore(eventId, 2, descrs);
}
}
@@ -851,10 +718,13 @@ namespace System.Diagnostics.Tracing
EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
descrs[0].DataPointer = (IntPtr)(&arg1);
descrs[0].Size = 4;
+ descrs[0].Reserved = 0;
descrs[1].DataPointer = (IntPtr)(&arg2);
descrs[1].Size = 4;
+ descrs[1].Reserved = 0;
descrs[2].DataPointer = (IntPtr)(&arg3);
descrs[2].Size = 4;
+ descrs[2].Reserved = 0;
WriteEventCore(eventId, 3, descrs);
}
}
@@ -868,6 +738,7 @@ namespace System.Diagnostics.Tracing
EventSource.EventData* descrs = stackalloc EventSource.EventData[1];
descrs[0].DataPointer = (IntPtr)(&arg1);
descrs[0].Size = 8;
+ descrs[0].Reserved = 0;
WriteEventCore(eventId, 1, descrs);
}
}
@@ -880,8 +751,10 @@ namespace System.Diagnostics.Tracing
EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
descrs[0].DataPointer = (IntPtr)(&arg1);
descrs[0].Size = 8;
+ descrs[0].Reserved = 0;
descrs[1].DataPointer = (IntPtr)(&arg2);
descrs[1].Size = 8;
+ descrs[1].Reserved = 0;
WriteEventCore(eventId, 2, descrs);
}
}
@@ -894,10 +767,13 @@ namespace System.Diagnostics.Tracing
EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
descrs[0].DataPointer = (IntPtr)(&arg1);
descrs[0].Size = 8;
+ descrs[0].Reserved = 0;
descrs[1].DataPointer = (IntPtr)(&arg2);
descrs[1].Size = 8;
+ descrs[1].Reserved = 0;
descrs[2].DataPointer = (IntPtr)(&arg3);
descrs[2].Size = 8;
+ descrs[2].Reserved = 0;
WriteEventCore(eventId, 3, descrs);
}
}
@@ -914,6 +790,7 @@ namespace System.Diagnostics.Tracing
EventSource.EventData* descrs = stackalloc EventSource.EventData[1];
descrs[0].DataPointer = (IntPtr)string1Bytes;
descrs[0].Size = ((arg1.Length + 1) * 2);
+ descrs[0].Reserved = 0;
WriteEventCore(eventId, 1, descrs);
}
}
@@ -932,8 +809,10 @@ namespace System.Diagnostics.Tracing
EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
descrs[0].DataPointer = (IntPtr)string1Bytes;
descrs[0].Size = ((arg1.Length + 1) * 2);
+ descrs[0].Reserved = 0;
descrs[1].DataPointer = (IntPtr)string2Bytes;
descrs[1].Size = ((arg2.Length + 1) * 2);
+ descrs[1].Reserved = 0;
WriteEventCore(eventId, 2, descrs);
}
}
@@ -954,10 +833,13 @@ namespace System.Diagnostics.Tracing
EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
descrs[0].DataPointer = (IntPtr)string1Bytes;
descrs[0].Size = ((arg1.Length + 1) * 2);
+ descrs[0].Reserved = 0;
descrs[1].DataPointer = (IntPtr)string2Bytes;
descrs[1].Size = ((arg2.Length + 1) * 2);
+ descrs[1].Reserved = 0;
descrs[2].DataPointer = (IntPtr)string3Bytes;
descrs[2].Size = ((arg3.Length + 1) * 2);
+ descrs[2].Reserved = 0;
WriteEventCore(eventId, 3, descrs);
}
}
@@ -975,8 +857,10 @@ namespace System.Diagnostics.Tracing
EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
descrs[0].DataPointer = (IntPtr)string1Bytes;
descrs[0].Size = ((arg1.Length + 1) * 2);
+ descrs[0].Reserved = 0;
descrs[1].DataPointer = (IntPtr)(&arg2);
descrs[1].Size = 4;
+ descrs[1].Reserved = 0;
WriteEventCore(eventId, 2, descrs);
}
}
@@ -993,10 +877,13 @@ namespace System.Diagnostics.Tracing
EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
descrs[0].DataPointer = (IntPtr)string1Bytes;
descrs[0].Size = ((arg1.Length + 1) * 2);
+ descrs[0].Reserved = 0;
descrs[1].DataPointer = (IntPtr)(&arg2);
descrs[1].Size = 4;
+ descrs[1].Reserved = 0;
descrs[2].DataPointer = (IntPtr)(&arg3);
descrs[2].Size = 4;
+ descrs[2].Reserved = 0;
WriteEventCore(eventId, 3, descrs);
}
}
@@ -1014,8 +901,10 @@ namespace System.Diagnostics.Tracing
EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
descrs[0].DataPointer = (IntPtr)string1Bytes;
descrs[0].Size = ((arg1.Length + 1) * 2);
+ descrs[0].Reserved = 0;
descrs[1].DataPointer = (IntPtr)(&arg2);
descrs[1].Size = 8;
+ descrs[1].Reserved = 0;
WriteEventCore(eventId, 2, descrs);
}
}
@@ -1033,8 +922,10 @@ namespace System.Diagnostics.Tracing
EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
descrs[0].DataPointer = (IntPtr)(&arg1);
descrs[0].Size = 8;
+ descrs[0].Reserved = 0;
descrs[1].DataPointer = (IntPtr)string2Bytes;
descrs[1].Size = ((arg2.Length + 1) * 2);
+ descrs[1].Reserved = 0;
WriteEventCore(eventId, 2, descrs);
}
}
@@ -1052,8 +943,10 @@ namespace System.Diagnostics.Tracing
EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
descrs[0].DataPointer = (IntPtr)(&arg1);
descrs[0].Size = 4;
+ descrs[0].Reserved = 0;
descrs[1].DataPointer = (IntPtr)string2Bytes;
descrs[1].Size = ((arg2.Length + 1) * 2);
+ descrs[1].Reserved = 0;
WriteEventCore(eventId, 2, descrs);
}
}
@@ -1070,8 +963,10 @@ namespace System.Diagnostics.Tracing
int blobSize = 0;
descrs[0].DataPointer = (IntPtr)(&blobSize);
descrs[0].Size = 4;
+ descrs[0].Reserved = 0;
descrs[1].DataPointer = (IntPtr)(&blobSize); // valid address instead of empty content
descrs[1].Size = 0;
+ descrs[1].Reserved = 0;
WriteEventCore(eventId, 2, descrs);
}
else
@@ -1081,8 +976,10 @@ namespace System.Diagnostics.Tracing
{
descrs[0].DataPointer = (IntPtr)(&blobSize);
descrs[0].Size = 4;
+ descrs[0].Reserved = 0;
descrs[1].DataPointer = (IntPtr)blob;
descrs[1].Size = blobSize;
+ descrs[1].Reserved = 0;
WriteEventCore(eventId, 2, descrs);
}
}
@@ -1097,13 +994,16 @@ namespace System.Diagnostics.Tracing
EventSource.EventData* descrs = stackalloc EventSource.EventData[3];
descrs[0].DataPointer = (IntPtr)(&arg1);
descrs[0].Size = 8;
+ descrs[0].Reserved = 0;
if (arg2 == null || arg2.Length == 0)
{
int blobSize = 0;
descrs[1].DataPointer = (IntPtr)(&blobSize);
descrs[1].Size = 4;
+ descrs[1].Reserved = 0;
descrs[2].DataPointer = (IntPtr)(&blobSize); // valid address instead of empty contents
descrs[2].Size = 0;
+ descrs[2].Reserved = 0;
WriteEventCore(eventId, 3, descrs);
}
else
@@ -1113,8 +1013,10 @@ namespace System.Diagnostics.Tracing
{
descrs[1].DataPointer = (IntPtr)(&blobSize);
descrs[1].Size = 4;
+ descrs[1].Reserved = 0;
descrs[2].DataPointer = (IntPtr)blob;
descrs[2].Size = blobSize;
+ descrs[2].Reserved = 0;
WriteEventCore(eventId, 3, descrs);
}
}
@@ -1139,7 +1041,13 @@ namespace System.Diagnostics.Tracing
/// </summary>
public int Size { get { return m_Size; } set { m_Size = value; } }
- #region private
+ /// <summary>
+ /// Reserved by ETW. This property is present to ensure that we can zero it
+ /// since System.Private.CoreLib uses are not zero'd.
+ /// </summary>
+ internal int Reserved { get { return m_Reserved; } set { m_Reserved = value; } }
+
+#region private
/// <summary>
/// Initializes the members of this EventData object to point at a previously-pinned
/// tracelogging-compatible metadata blob.
@@ -1161,7 +1069,7 @@ namespace System.Diagnostics.Tracing
#pragma warning disable 0649
internal int m_Reserved; // Used to pad the size to match the Win32 API
#pragma warning restore 0649
- #endregion
+#endregion
}
/// <summary>
@@ -1180,8 +1088,10 @@ namespace System.Diagnostics.Tracing
/// EventSource.EventData* descrs = stackalloc EventSource.EventData[2];
/// descrs[0].DataPointer = (IntPtr)(&amp;arg1);
/// descrs[0].Size = 8;
+ /// descrs[0].Reserved = 0;
/// descrs[1].DataPointer = (IntPtr)string2Bytes;
/// descrs[1].Size = ((arg2.Length + 1) * 2);
+ /// descrs[1].Reserved = 0;
/// WriteEventCore(eventId, 2, descrs);
/// }
/// }
@@ -1257,75 +1167,6 @@ namespace System.Diagnostics.Tracing
#if FEATURE_MANAGED_ETW
if (m_eventData[eventId].EnabledForETW)
{
-
-#if FEATURE_ACTIVITYSAMPLING
- // this code should be kept in sync with WriteEventVarargs().
- SessionMask etwSessions = SessionMask.All;
- // only compute etwSessions if there are *any* ETW filters enabled...
- if ((ulong)m_curLiveSessions != 0)
- etwSessions = GetEtwSessionMask(eventId, relatedActivityId);
- // OutputDebugString(string.Format("{0}.WriteEvent(id {1}) -> to sessions {2:x}",
- // m_name, m_eventData[eventId].Name, (ulong) etwSessions));
-
- if ((ulong)etwSessions != 0 || m_legacySessions != null && m_legacySessions.Count > 0)
- {
- if (!SelfDescribingEvents)
- {
- if (etwSessions.IsEqualOrSupersetOf(m_curLiveSessions))
- {
- // OutputDebugString(string.Format(" (1) id {0}, kwd {1:x}",
- // m_eventData[eventId].Name, m_eventData[eventId].Descriptor.Keywords));
- // by default the Descriptor.Keyword will have the perEventSourceSessionId bit
- // mask set to 0x0f so, when all ETW sessions want the event we don't need to
- // synthesize a new one
- if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, m_eventData[eventId].EventHandle, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data))
- ThrowEventSourceException(m_eventData[eventId].Name);
- }
- else
- {
- long origKwd = unchecked((long)((ulong)m_eventData[eventId].Descriptor.Keywords & ~(SessionMask.All.ToEventKeywords())));
- // OutputDebugString(string.Format(" (2) id {0}, kwd {1:x}",
- // m_eventData[eventId].Name, etwSessions.ToEventKeywords() | (ulong) origKwd));
- // only some of the ETW sessions will receive this event. Synthesize a new
- // Descriptor whose Keywords field will have the appropriate bits set.
- // etwSessions might be 0, if there are legacy ETW listeners that want this event
- var desc = new EventDescriptor(
- m_eventData[eventId].Descriptor.EventId,
- m_eventData[eventId].Descriptor.Version,
- m_eventData[eventId].Descriptor.Channel,
- m_eventData[eventId].Descriptor.Level,
- m_eventData[eventId].Descriptor.Opcode,
- m_eventData[eventId].Descriptor.Task,
- unchecked((long)etwSessions.ToEventKeywords() | origKwd));
-
- if (!m_provider.WriteEvent(ref desc, m_eventData[eventId].EventHandle, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data))
- ThrowEventSourceException(m_eventData[eventId].Name);
- }
- }
- else
- {
- TraceLoggingEventTypes tlet = m_eventData[eventId].TraceLoggingEventTypes;
- if (tlet == null)
- {
- tlet = new TraceLoggingEventTypes(m_eventData[eventId].Name,
- EventTags.None,
- m_eventData[eventId].Parameters);
- Interlocked.CompareExchange(ref m_eventData[eventId].TraceLoggingEventTypes, tlet, null);
-
- }
- long origKwd = unchecked((long)((ulong)m_eventData[eventId].Descriptor.Keywords & ~(SessionMask.All.ToEventKeywords())));
- // TODO: activity ID support
- EventSourceOptions opt = new EventSourceOptions
- {
- Keywords = (EventKeywords)unchecked((long)etwSessions.ToEventKeywords() | origKwd),
- Level = (EventLevel)m_eventData[eventId].Descriptor.Level,
- Opcode = (EventOpcode)m_eventData[eventId].Descriptor.Opcode
- };
-
- WriteMultiMerge(m_eventData[eventId].Name, ref opt, tlet, pActivityId, relatedActivityId, data);
- }
- }
-#else
if (!SelfDescribingEvents)
{
if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, m_eventData[eventId].EventHandle, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data))
@@ -1351,12 +1192,11 @@ namespace System.Diagnostics.Tracing
WriteMultiMerge(m_eventData[eventId].Name, ref opt, tlet, pActivityId, relatedActivityId, data);
}
-#endif // FEATURE_ACTIVITYSAMPLING
}
#endif // FEATURE_MANAGED_ETW
if (m_Dispatchers != null && m_eventData[eventId].EnabledForAnyListener)
- WriteToAllListeners(eventId, relatedActivityId, eventDataCount, data);
+ WriteToAllListeners(eventId, pActivityId, relatedActivityId, eventDataCount, data);
}
catch (Exception ex)
{
@@ -1395,9 +1235,9 @@ namespace System.Diagnostics.Tracing
WriteEventVarargs(eventId, &relatedActivityId, args);
}
- #endregion
+#endregion
- #region IDisposable Members
+#region IDisposable Members
/// <summary>
/// Disposes of an EventSource.
/// </summary>
@@ -1452,37 +1292,14 @@ namespace System.Diagnostics.Tracing
{
this.Dispose(false);
}
- #endregion
-
- #region private
-#if FEATURE_ACTIVITYSAMPLING
- internal void WriteStringToListener(EventListener listener, string msg, SessionMask m)
- {
- Debug.Assert(listener == null || (uint)m == (uint)SessionMask.FromId(0));
+#endregion
- if (m_eventSourceEnabled)
- {
- if (listener == null)
- {
- WriteEventString(0, unchecked((long)m.ToEventKeywords()), msg);
- }
- else
- {
- EventWrittenEventArgs eventCallbackArgs = new EventWrittenEventArgs(this);
- eventCallbackArgs.EventId = 0;
- eventCallbackArgs.Message = msg;
- eventCallbackArgs.Payload = new ReadOnlyCollection<object>(new List<object>() { msg });
- eventCallbackArgs.PayloadNames = new ReadOnlyCollection<string>(new List<string> { "message" });
- eventCallbackArgs.EventName = "EventSourceMessage";
- listener.OnEventWritten(eventCallbackArgs);
- }
- }
- }
-#endif
+#region private
private unsafe void WriteEventRaw(
string eventName,
ref EventDescriptor eventDescriptor,
+ IntPtr eventHandle,
Guid* activityID,
Guid* relatedActivityID,
int dataCount,
@@ -1495,7 +1312,7 @@ namespace System.Diagnostics.Tracing
}
else
{
- if (!m_provider.WriteEventRaw(ref eventDescriptor, activityID, relatedActivityID, dataCount, data))
+ if (!m_provider.WriteEventRaw(ref eventDescriptor, eventHandle, activityID, relatedActivityID, dataCount, data))
ThrowEventSourceException(eventName);
}
#endif // FEATURE_MANAGED_ETW
@@ -1543,10 +1360,6 @@ namespace System.Diagnostics.Tracing
m_name = eventSourceName;
m_guid = eventSourceGuid;
-#if FEATURE_ACTIVITYSAMPLING
- m_curLiveSessions = new SessionMask(0);
- m_etwSessionIdMap = new EtwSession[SessionMask.MAX];
-#endif // FEATURE_ACTIVITYSAMPLING
//Enable Implicit Activity tracker
m_activityTracker = ActivityTracker.Instance;
@@ -2024,67 +1837,6 @@ namespace System.Diagnostics.Tracing
#if FEATURE_MANAGED_ETW
if (m_eventData[eventId].EnabledForETW)
{
-#if FEATURE_ACTIVITYSAMPLING
- // this code should be kept in sync with WriteEventWithRelatedActivityIdCore().
- SessionMask etwSessions = SessionMask.All;
- // only compute etwSessions if there are *any* ETW filters enabled...
- if ((ulong)m_curLiveSessions != 0)
- etwSessions = GetEtwSessionMask(eventId, childActivityID);
-
- if ((ulong)etwSessions != 0 || m_legacySessions != null && m_legacySessions.Count > 0)
- {
- if (!SelfDescribingEvents)
- {
- if (etwSessions.IsEqualOrSupersetOf(m_curLiveSessions))
- {
- // by default the Descriptor.Keyword will have the perEventSourceSessionId bit
- // mask set to 0x0f so, when all ETW sessions want the event we don't need to
- // synthesize a new one
- if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, m_eventData[eventId].EventHandle, pActivityId, childActivityID, args))
- ThrowEventSourceException(m_eventData[eventId].Name);
- }
- else
- {
- long origKwd = unchecked((long)((ulong)m_eventData[eventId].Descriptor.Keywords & ~(SessionMask.All.ToEventKeywords())));
- // only some of the ETW sessions will receive this event. Synthesize a new
- // Descriptor whose Keywords field will have the appropriate bits set.
- var desc = new EventDescriptor(
- m_eventData[eventId].Descriptor.EventId,
- m_eventData[eventId].Descriptor.Version,
- m_eventData[eventId].Descriptor.Channel,
- m_eventData[eventId].Descriptor.Level,
- m_eventData[eventId].Descriptor.Opcode,
- m_eventData[eventId].Descriptor.Task,
- unchecked((long)etwSessions.ToEventKeywords() | origKwd));
-
- if (!m_provider.WriteEvent(ref desc, m_eventData[eventId].EventHandle, pActivityId, childActivityID, args))
- ThrowEventSourceException(m_eventData[eventId].Name);
- }
- }
- else
- {
- TraceLoggingEventTypes tlet = m_eventData[eventId].TraceLoggingEventTypes;
- if (tlet == null)
- {
- tlet = new TraceLoggingEventTypes(m_eventData[eventId].Name,
- EventTags.None,
- m_eventData[eventId].Parameters);
- Interlocked.CompareExchange(ref m_eventData[eventId].TraceLoggingEventTypes, tlet, null);
-
- }
- long origKwd = unchecked((long)((ulong)m_eventData[eventId].Descriptor.Keywords & ~(SessionMask.All.ToEventKeywords())));
- // TODO: activity ID support
- EventSourceOptions opt = new EventSourceOptions
- {
- Keywords = (EventKeywords)unchecked((long)etwSessions.ToEventKeywords() | origKwd),
- Level = (EventLevel)m_eventData[eventId].Descriptor.Level,
- Opcode = (EventOpcode)m_eventData[eventId].Descriptor.Opcode
- };
-
- WriteMultiMerge(m_eventData[eventId].Name, ref opt, tlet, pActivityId, childActivityID, args);
- }
- }
-#else
if (!SelfDescribingEvents)
{
if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, m_eventData[eventId].EventHandle, pActivityId, childActivityID, args))
@@ -2111,7 +1863,6 @@ namespace System.Diagnostics.Tracing
WriteMultiMerge(m_eventData[eventId].Name, ref opt, tlet, pActivityId, childActivityID, args);
}
-#endif // FEATURE_ACTIVITYSAMPLING
}
#endif // FEATURE_MANAGED_ETW
if (m_Dispatchers != null && m_eventData[eventId].EnabledForAnyListener)
@@ -2120,13 +1871,13 @@ namespace System.Diagnostics.Tracing
// Maintain old behavior - object identity is preserved
if (AppContextSwitches.PreserveEventListnerObjectIdentity)
{
- WriteToAllListeners(eventId, childActivityID, args);
+ WriteToAllListeners(eventId, pActivityId, childActivityID, args);
}
else
#endif // !ES_BUILD_STANDALONE
{
object[] serializedArgs = SerializeEventArgs(eventId, args);
- WriteToAllListeners(eventId, childActivityID, serializedArgs);
+ WriteToAllListeners(eventId, pActivityId, childActivityID, serializedArgs);
}
}
}
@@ -2140,7 +1891,7 @@ namespace System.Diagnostics.Tracing
}
}
- unsafe private object[] SerializeEventArgs(int eventId, object[] args)
+ private unsafe object[] SerializeEventArgs(int eventId, object[] args)
{
TraceLoggingEventTypes eventTypes = m_eventData[eventId].TraceLoggingEventTypes;
if (eventTypes == null)
@@ -2197,7 +1948,7 @@ namespace System.Diagnostics.Tracing
#endif //!ES_BUILD_PCL
}
- unsafe private void WriteToAllListeners(int eventId, Guid* childActivityID, int eventDataCount, EventSource.EventData* data)
+ private unsafe void WriteToAllListeners(int eventId, Guid* activityID, Guid* childActivityID, int eventDataCount, EventSource.EventData* data)
{
// We represent a byte[] as a integer denoting the length and then a blob of bytes in the data pointer. This causes a spurious
// warning because eventDataCount is off by one for the byte[] case since a byte[] has 2 items associated it. So we want to check
@@ -2228,14 +1979,16 @@ namespace System.Diagnostics.Tracing
EventSource.EventData* dataPtr = data;
for (int i = 0; i < paramCount; i++)
args[i] = DecodeObject(eventId, i, ref dataPtr);
- WriteToAllListeners(eventId, childActivityID, args);
+ WriteToAllListeners(eventId, activityID, childActivityID, args);
}
// helper for writing to all EventListeners attached the current eventSource.
- unsafe private void WriteToAllListeners(int eventId, Guid* childActivityID, params object[] args)
+ private unsafe void WriteToAllListeners(int eventId, Guid* activityID, Guid* childActivityID, params object[] args)
{
EventWrittenEventArgs eventCallbackArgs = new EventWrittenEventArgs(this);
eventCallbackArgs.EventId = eventId;
+ if (activityID != null)
+ eventCallbackArgs.ActivityId = *activityID;
if (childActivityID != null)
eventCallbackArgs.RelatedActivityId = *childActivityID;
eventCallbackArgs.EventName = m_eventData[eventId].Name;
@@ -2253,18 +2006,6 @@ namespace System.Diagnostics.Tracing
Debug.Assert(dispatcher.m_EventEnabled != null);
if (eventId == -1 || dispatcher.m_EventEnabled[eventId])
{
-#if FEATURE_ACTIVITYSAMPLING
- var activityFilter = dispatcher.m_Listener.m_activityFilter;
- // order below is important as PassesActivityFilter will "flow" active activities
- // even when the current EventSource doesn't have filtering enabled. This allows
- // interesting activities to be updated so that sources that do sample can get
- // accurate data
- if (activityFilter == null ||
- ActivityFilter.PassesActivityFilter(activityFilter, childActivityID,
- m_eventData[eventId].TriggersActivityTracking > 0,
- this, eventId) ||
- !dispatcher.m_activityFilteringEnabled)
-#endif // FEATURE_ACTIVITYSAMPLING
{
try
{
@@ -2379,62 +2120,6 @@ namespace System.Diagnostics.Tracing
}
}
-#if FEATURE_ACTIVITYSAMPLING
- unsafe private SessionMask GetEtwSessionMask(int eventId, Guid* childActivityID)
- {
- SessionMask etwSessions = new SessionMask();
-
- for (int i = 0; i < SessionMask.MAX; ++i)
- {
- EtwSession etwSession = m_etwSessionIdMap[i];
- if (etwSession != null)
- {
- ActivityFilter activityFilter = etwSession.m_activityFilter;
- // PassesActivityFilter() will flow "interesting" activities, so make sure
- // to perform this test first, before ORing with ~m_activityFilteringForETWEnabled
- // (note: the first test for !m_activityFilteringForETWEnabled[i] ensures we
- // do not fire events indiscriminately, when no filters are specified, but only
- // if, in addition, the session did not also enable ActivitySampling)
- if (activityFilter == null && !m_activityFilteringForETWEnabled[i] ||
- activityFilter != null &&
- ActivityFilter.PassesActivityFilter(activityFilter, childActivityID,
- m_eventData[eventId].TriggersActivityTracking > 0, this, eventId) ||
- !m_activityFilteringForETWEnabled[i])
- {
- etwSessions[i] = true;
- }
- }
- }
- // flow "interesting" activities for all legacy sessions in which there's some
- // level of activity tracing enabled (even other EventSources)
- if (m_legacySessions != null && m_legacySessions.Count > 0 &&
- (EventOpcode)m_eventData[eventId].Descriptor.Opcode == EventOpcode.Send)
- {
- // only calculate InternalCurrentThreadActivityId once
- Guid* pCurrentActivityId = null;
- Guid currentActivityId;
- foreach (var legacyEtwSession in m_legacySessions)
- {
- if (legacyEtwSession == null)
- continue;
-
- ActivityFilter activityFilter = legacyEtwSession.m_activityFilter;
- if (activityFilter != null)
- {
- if (pCurrentActivityId == null)
- {
- currentActivityId = InternalCurrentThreadActivityId;
- pCurrentActivityId = &currentActivityId;
- }
- ActivityFilter.FlowActivityIfNeeded(activityFilter, pCurrentActivityId, childActivityID);
- }
- }
- }
-
- return etwSessions;
- }
-#endif // FEATURE_ACTIVITYSAMPLING
-
/// <summary>
/// Returns true if 'eventNum' is enabled if you only consider the level and matchAnyKeyword filters.
/// It is possible that eventSources turn off the event based on additional filtering criteria.
@@ -2616,13 +2301,9 @@ namespace System.Diagnostics.Tracing
public bool EnabledForETW; // is this event on for the OS ETW data dispatcher?
public bool HasRelatedActivityID; // Set if the event method's first parameter is a Guid named 'relatedActivityId'
-#if !FEATURE_ACTIVITYSAMPLING
#pragma warning disable 0649
-#endif
public byte TriggersActivityTracking; // count of listeners that marked this event as trigger for start of activity logging.
-#if !FEATURE_ACTIVITYSAMPLING
#pragma warning restore 0649
-#endif
public string Name; // the name of the event
public string Message; // If the event has a message associated with it, this is it.
public ParameterInfo[] Parameters; // TODO can we remove?
@@ -2790,43 +2471,6 @@ namespace System.Diagnostics.Tracing
#endif
}
-#if FEATURE_ACTIVITYSAMPLING
- if (bSessionEnable && commandArgs.perEventSourceSessionId != -1)
- {
- bool participateInSampling = false;
- string activityFilters;
- int sessionIdBit;
-
- ParseCommandArgs(commandArgs.Arguments, out participateInSampling,
- out activityFilters, out sessionIdBit);
-
- if (commandArgs.listener == null && commandArgs.Arguments.Count > 0 && commandArgs.perEventSourceSessionId != sessionIdBit)
- {
- throw new ArgumentException(SR.Format(SR.EventSource_SessionIdError,
- commandArgs.perEventSourceSessionId + SessionMask.SHIFT_SESSION_TO_KEYWORD,
- sessionIdBit + SessionMask.SHIFT_SESSION_TO_KEYWORD));
- }
-
- if (commandArgs.listener == null)
- {
- UpdateEtwSession(commandArgs.perEventSourceSessionId, commandArgs.etwSessionId, true, activityFilters, participateInSampling);
- }
- else
- {
- ActivityFilter.UpdateFilter(ref commandArgs.listener.m_activityFilter, this, 0, activityFilters);
- commandArgs.dispatcher.m_activityFilteringEnabled = participateInSampling;
- }
- }
- else if (!bSessionEnable && commandArgs.listener == null)
- {
- // if we disable an ETW session, indicate that in a synthesized command argument
- if (commandArgs.perEventSourceSessionId >= 0 && commandArgs.perEventSourceSessionId < SessionMask.MAX)
- {
- commandArgs.Arguments["EtwSessionKeyword"] = (commandArgs.perEventSourceSessionId + SessionMask.SHIFT_SESSION_TO_KEYWORD).ToString(CultureInfo.InvariantCulture);
- }
- }
-#endif // FEATURE_ACTIVITYSAMPLING
-
// Turn on the enable bit before making the OnEventCommand callback This allows you to do useful
// things like log messages, or test if keywords are enabled in the callback.
if (commandArgs.enable)
@@ -2840,47 +2484,11 @@ namespace System.Diagnostics.Tracing
if (eventCommandCallback != null)
eventCommandCallback(this, commandArgs);
-#if FEATURE_ACTIVITYSAMPLING
- if (commandArgs.listener == null && !bSessionEnable && commandArgs.perEventSourceSessionId != -1)
- {
- // if we disable an ETW session, complete disabling it
- UpdateEtwSession(commandArgs.perEventSourceSessionId, commandArgs.etwSessionId, false, null, false);
- }
-#endif // FEATURE_ACTIVITYSAMPLING
-
if (!commandArgs.enable)
{
// If we are disabling, maybe we can turn on 'quick checks' to filter
// quickly. These are all just optimizations (since later checks will still filter)
-#if FEATURE_ACTIVITYSAMPLING
- // Turn off (and forget) any information about Activity Tracing.
- if (commandArgs.listener == null)
- {
- // reset all filtering information for activity-tracing-aware sessions
- for (int i = 0; i < SessionMask.MAX; ++i)
- {
- EtwSession etwSession = m_etwSessionIdMap[i];
- if (etwSession != null)
- ActivityFilter.DisableFilter(ref etwSession.m_activityFilter, this);
- }
- m_activityFilteringForETWEnabled = new SessionMask(0);
- m_curLiveSessions = new SessionMask(0);
- // reset activity-tracing-aware sessions
- if (m_etwSessionIdMap != null)
- for (int i = 0; i < SessionMask.MAX; ++i)
- m_etwSessionIdMap[i] = null;
- // reset legacy sessions
- if (m_legacySessions != null)
- m_legacySessions.Clear();
- }
- else
- {
- ActivityFilter.DisableFilter(ref commandArgs.listener.m_activityFilter, this);
- commandArgs.dispatcher.m_activityFilteringEnabled = false;
- }
-#endif // FEATURE_ACTIVITYSAMPLING
-
// There is a good chance EnabledForAnyListener are not as accurate as
// they could be, go ahead and get a better estimate.
for (int i = 0; i < m_eventData.Length; i++)
@@ -2905,9 +2513,6 @@ namespace System.Diagnostics.Tracing
m_eventSourceEnabled = false;
}
}
-#if FEATURE_ACTIVITYSAMPLING
- UpdateKwdTriggers(commandArgs.enable);
-#endif // FEATURE_ACTIVITYSAMPLING
}
else
{
@@ -2930,14 +2535,6 @@ namespace System.Diagnostics.Tracing
if (eventCommandCallback != null)
eventCommandCallback(this, commandArgs);
}
-
-#if FEATURE_ACTIVITYSAMPLING
- if (m_completelyInited && (commandArgs.listener != null || shouldReport))
- {
- SessionMask m = SessionMask.FromId(commandArgs.perEventSourceSessionId);
- ReportActivitySamplingInfo(commandArgs.listener, m);
- }
-#endif // FEATURE_ACTIVITYSAMPLING
}
catch (Exception e)
{
@@ -2948,133 +2545,6 @@ namespace System.Diagnostics.Tracing
}
}
-#if FEATURE_ACTIVITYSAMPLING
-
- internal void UpdateEtwSession(
- int sessionIdBit,
- int etwSessionId,
- bool bEnable,
- string activityFilters,
- bool participateInSampling)
- {
- if (sessionIdBit < SessionMask.MAX)
- {
- // activity-tracing-aware etw session
- if (bEnable)
- {
- var etwSession = EtwSession.GetEtwSession(etwSessionId, true);
- ActivityFilter.UpdateFilter(ref etwSession.m_activityFilter, this, sessionIdBit, activityFilters);
- m_etwSessionIdMap[sessionIdBit] = etwSession;
- m_activityFilteringForETWEnabled[sessionIdBit] = participateInSampling;
- }
- else
- {
- var etwSession = EtwSession.GetEtwSession(etwSessionId);
- m_etwSessionIdMap[sessionIdBit] = null;
- m_activityFilteringForETWEnabled[sessionIdBit] = false;
- if (etwSession != null)
- {
- ActivityFilter.DisableFilter(ref etwSession.m_activityFilter, this);
- // the ETW session is going away; remove it from the global list
- EtwSession.RemoveEtwSession(etwSession);
- }
- }
- m_curLiveSessions[sessionIdBit] = bEnable;
- }
- else
- {
- // legacy etw session
- if (bEnable)
- {
- if (m_legacySessions == null)
- m_legacySessions = new List<EtwSession>(8);
- var etwSession = EtwSession.GetEtwSession(etwSessionId, true);
- if (!m_legacySessions.Contains(etwSession))
- m_legacySessions.Add(etwSession);
- }
- else
- {
- var etwSession = EtwSession.GetEtwSession(etwSessionId);
- if (etwSession != null)
- {
- if (m_legacySessions != null)
- m_legacySessions.Remove(etwSession);
- // the ETW session is going away; remove it from the global list
- EtwSession.RemoveEtwSession(etwSession);
- }
- }
- }
- }
-
- internal static bool ParseCommandArgs(
- IDictionary<string, string> commandArguments,
- out bool participateInSampling,
- out string activityFilters,
- out int sessionIdBit)
- {
- bool res = true;
- participateInSampling = false;
- string activityFilterString;
- if (commandArguments.TryGetValue("ActivitySamplingStartEvent", out activityFilters))
- {
- // if a start event is specified default the event source to participate in sampling
- participateInSampling = true;
- }
-
- if (commandArguments.TryGetValue("ActivitySampling", out activityFilterString))
- {
- if (string.Compare(activityFilterString, "false", StringComparison.OrdinalIgnoreCase) == 0 ||
- activityFilterString == "0")
- participateInSampling = false;
- else
- participateInSampling = true;
- }
-
- string sSessionKwd;
- int sessionKwd = -1;
- if (!commandArguments.TryGetValue("EtwSessionKeyword", out sSessionKwd) ||
- !int.TryParse(sSessionKwd, out sessionKwd) ||
- sessionKwd < SessionMask.SHIFT_SESSION_TO_KEYWORD ||
- sessionKwd >= SessionMask.SHIFT_SESSION_TO_KEYWORD + SessionMask.MAX)
- {
- sessionIdBit = -1;
- res = false;
- }
- else
- {
- sessionIdBit = sessionKwd - SessionMask.SHIFT_SESSION_TO_KEYWORD;
- }
- return res;
- }
-
- internal void UpdateKwdTriggers(bool enable)
- {
- if (enable)
- {
- // recompute m_keywordTriggers
- ulong gKeywords = unchecked((ulong)m_matchAnyKeyword);
- if (gKeywords == 0)
- gKeywords = 0xFFFFffffFFFFffff;
-
- m_keywordTriggers = 0;
- for (int sessId = 0; sessId < SessionMask.MAX; ++sessId)
- {
- EtwSession etwSession = m_etwSessionIdMap[sessId];
- if (etwSession == null)
- continue;
-
- ActivityFilter activityFilter = etwSession.m_activityFilter;
- ActivityFilter.UpdateKwdTriggers(activityFilter, m_guid, this, unchecked((EventKeywords)gKeywords));
- }
- }
- else
- {
- m_keywordTriggers = 0;
- }
- }
-
-#endif // FEATURE_ACTIVITYSAMPLING
-
/// <summary>
/// If 'value is 'true' then set the eventSource so that 'dispatcher' will receive event with the eventId
/// of 'eventId. If value is 'false' disable the event for that dispatcher. If 'eventId' is out of
@@ -3198,7 +2668,7 @@ namespace System.Diagnostics.Tracing
Debug.Assert(!SelfDescribingEvents);
-#if FEATURE_MANAGED_ETW
+#if FEATURE_MANAGED_ETW
fixed (byte* dataPtr = rawManifest)
{
// we don't want the manifest to show up in the event log channels so we specify as keywords
@@ -3933,7 +3403,7 @@ namespace System.Diagnostics.Tracing
/// <param name="method">The method to probe.</param>
/// <returns>The literal value or -1 if the value could not be determined. </returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Switch statement is clearer than alternatives")]
- static private int GetHelperCallFirstArg(MethodInfo method)
+ private static int GetHelperCallFirstArg(MethodInfo method)
{
#if (!ES_BUILD_PCL && !ES_BUILD_PN)
// Currently searches for the following pattern
@@ -4148,48 +3618,6 @@ namespace System.Diagnostics.Tracing
}
}
-#if FEATURE_ACTIVITYSAMPLING
- private void ReportActivitySamplingInfo(EventListener listener, SessionMask sessions)
- {
- Debug.Assert(listener == null || (uint)sessions == (uint)SessionMask.FromId(0));
-
- for (int perEventSourceSessionId = 0; perEventSourceSessionId < SessionMask.MAX; ++perEventSourceSessionId)
- {
- if (!sessions[perEventSourceSessionId])
- continue;
-
- ActivityFilter af;
- if (listener == null)
- {
- EtwSession etwSession = m_etwSessionIdMap[perEventSourceSessionId];
- Debug.Assert(etwSession != null);
- af = etwSession.m_activityFilter;
- }
- else
- {
- af = listener.m_activityFilter;
- }
-
- if (af == null)
- continue;
-
- SessionMask m = new SessionMask();
- m[perEventSourceSessionId] = true;
-
- foreach (var t in af.GetFilterAsTuple(m_guid))
- {
- WriteStringToListener(listener, string.Format(CultureInfo.InvariantCulture, "Session {0}: {1} = {2}", perEventSourceSessionId, t.Item1, t.Item2), m);
- }
-
- bool participateInSampling = (listener == null) ?
- m_activityFilteringForETWEnabled[perEventSourceSessionId] :
- GetDispatcher(listener).m_activityFilteringEnabled;
- WriteStringToListener(listener, string.Format(CultureInfo.InvariantCulture, "Session {0}: Activity Sampling support: {1}",
- perEventSourceSessionId, participateInSampling ? "enabled" : "disabled"), m);
- }
- }
-#endif // FEATURE_ACTIVITYSAMPLING
-
// private instance state
private string m_name; // My friendly name (privided in ctor)
internal int m_id; // A small integer that is unique to this instance.
@@ -4231,16 +3659,6 @@ namespace System.Diagnostics.Tracing
internal volatile ulong[] m_channelData;
#endif
-#if FEATURE_ACTIVITYSAMPLING
- private SessionMask m_curLiveSessions; // the activity-tracing aware sessions' bits
- private EtwSession[] m_etwSessionIdMap; // the activity-tracing aware sessions
- private List<EtwSession> m_legacySessions; // the legacy ETW sessions listening to this source
- internal long m_keywordTriggers; // a bit is set if it corresponds to a keyword that's part of an enabled triggering event
- internal SessionMask m_activityFilteringForETWEnabled; // does THIS EventSource have activity filtering turned on for each ETW session
- static internal Action<Guid> s_activityDying; // Fires when something calls SetCurrentThreadToActivity()
- // Also used to mark that activity tracing is on for some case
-#endif // FEATURE_ACTIVITYSAMPLING
-
// We use a single instance of ActivityTracker for all EventSources instances to allow correlation between multiple event providers.
// We have m_activityTracker field simply because instance field is more efficient than static field fetch.
ActivityTracker m_activityTracker;
@@ -4772,9 +4190,6 @@ namespace System.Diagnostics.Tracing
// Instance fields
internal volatile EventListener m_Next; // These form a linked list in s_Listeners
-#if FEATURE_ACTIVITYSAMPLING
- internal ActivityFilter m_activityFilter; // If we are filtering by activity on this Listener, this keeps track of it.
-#endif // FEATURE_ACTIVITYSAMPLING
// static fields
@@ -4924,7 +4339,20 @@ namespace System.Diagnostics.Tracing
/// </summary>
public Guid ActivityId
{
- get { return EventSource.CurrentThreadActivityId; }
+ get
+ {
+ Guid activityId = m_activityId;
+ if (activityId == Guid.Empty)
+ {
+ activityId = EventSource.CurrentThreadActivityId;
+ }
+
+ return activityId;
+ }
+ internal set
+ {
+ m_activityId = value;
+ }
}
/// <summary>
@@ -5099,6 +4527,7 @@ namespace System.Diagnostics.Tracing
private string m_eventName;
private EventSource m_eventSource;
private ReadOnlyCollection<string> m_payloadNames;
+ private Guid m_activityId;
internal EventTags m_tags;
internal EventOpcode m_opcode;
internal EventLevel m_level;
@@ -5360,629 +4789,6 @@ namespace System.Diagnostics.Tracing
#region private classes
-#if FEATURE_ACTIVITYSAMPLING
-
- /// <summary>
- /// ActivityFilter is a helper structure that is used to keep track of run-time state
- /// associated with activity filtering. It is 1-1 with EventListeners (logically
- /// every listener has one of these, however we actually allocate them lazily), as well
- /// as 1-to-1 with tracing-aware EtwSessions.
- ///
- /// This structure also keeps track of the sampling counts associated with 'trigger'
- /// events. Because these trigger events are rare, and you typically only have one of
- /// them, we store them here as a linked list.
- /// </summary>
- internal sealed class ActivityFilter : IDisposable
- {
- /// <summary>
- /// Disable all activity filtering for the listener associated with 'filterList',
- /// (in the session associated with it) that is triggered by any event in 'source'.
- /// </summary>
- public static void DisableFilter(ref ActivityFilter filterList, EventSource source)
- {
-#if !ES_BUILD_STANDALONE
- Debug.Assert(Monitor.IsEntered(EventListener.EventListenersLock));
-#endif
-
- if (filterList == null)
- return;
-
- ActivityFilter cur;
- // Remove it from anywhere in the list (except the first element, which has to
- // be treated specially)
- ActivityFilter prev = filterList;
- cur = prev.m_next;
- while (cur != null)
- {
- if (cur.m_providerGuid == source.Guid)
- {
- // update TriggersActivityTracking bit
- if (cur.m_eventId >= 0 && cur.m_eventId < source.m_eventData.Length)
- --source.m_eventData[cur.m_eventId].TriggersActivityTracking;
-
- // Remove it from the linked list.
- prev.m_next = cur.m_next;
- // dispose of the removed node
- cur.Dispose();
- // update cursor
- cur = prev.m_next;
- }
- else
- {
- // update cursors
- prev = cur;
- cur = prev.m_next;
- }
- }
-
- // Sadly we have to treat the first element specially in linked list removal in C#
- if (filterList.m_providerGuid == source.Guid)
- {
- // update TriggersActivityTracking bit
- if (filterList.m_eventId >= 0 && filterList.m_eventId < source.m_eventData.Length)
- --source.m_eventData[filterList.m_eventId].TriggersActivityTracking;
-
- // We are the first element in the list.
- var first = filterList;
- filterList = first.m_next;
- // dispose of the removed node
- first.Dispose();
- }
- // the above might have removed the one ActivityFilter in the session that contains the
- // cleanup delegate; re-create the delegate if needed
- if (filterList != null)
- {
- EnsureActivityCleanupDelegate(filterList);
- }
- }
-
- /// <summary>
- /// Currently this has "override" semantics. We first disable all filters
- /// associated with 'source', and next we add new filters for each entry in the
- /// string 'startEvents'. participateInSampling specifies whether non-startEvents
- /// always trigger or only trigger when current activity is 'active'.
- /// </summary>
- public static void UpdateFilter(
- ref ActivityFilter filterList,
- EventSource source,
- int perEventSourceSessionId,
- string startEvents)
- {
-#if !ES_BUILD_STANDALONE
- Debug.Assert(Monitor.IsEntered(EventListener.EventListenersLock));
-#endif
-
- // first remove all filters associated with 'source'
- DisableFilter(ref filterList, source);
-
- if (!string.IsNullOrEmpty(startEvents))
- {
- // ActivitySamplingStartEvents is a space-separated list of Event:Frequency pairs.
- // The Event may be specified by name or by ID. Errors in parsing such a pair
- // result in the error being reported to the listeners, and the pair being ignored.
- // E.g. "CustomActivityStart:1000 12:10" specifies that for event CustomActivityStart
- // we should initiate activity tracing once every 1000 events, *and* for event ID 12
- // we should initiate activity tracing once every 10 events.
- string[] activityFilterStrings = startEvents.Split(' ');
-
- for (int i = 0; i < activityFilterStrings.Length; ++i)
- {
- string activityFilterString = activityFilterStrings[i];
- int sampleFreq = 1;
- int eventId = -1;
- int colonIdx = activityFilterString.IndexOf(':');
- if (colonIdx < 0)
- {
- source.ReportOutOfBandMessage("ERROR: Invalid ActivitySamplingStartEvent specification: " +
- activityFilterString, false);
- // ignore failure...
- continue;
- }
- string sFreq = activityFilterString.Substring(colonIdx + 1);
- if (!int.TryParse(sFreq, out sampleFreq))
- {
- source.ReportOutOfBandMessage("ERROR: Invalid sampling frequency specification: " + sFreq, false);
- continue;
- }
- activityFilterString = activityFilterString.Substring(0, colonIdx);
- if (!int.TryParse(activityFilterString, out eventId))
- {
- // reset eventId
- eventId = -1;
- // see if it's an event name
- for (int j = 0; j < source.m_eventData.Length; j++)
- {
- EventSource.EventMetadata[] ed = source.m_eventData;
- if (ed[j].Name != null && ed[j].Name.Length == activityFilterString.Length &&
- string.Compare(ed[j].Name, activityFilterString, StringComparison.OrdinalIgnoreCase) == 0)
- {
- eventId = ed[j].Descriptor.EventId;
- break;
- }
- }
- }
- if (eventId < 0 || eventId >= source.m_eventData.Length)
- {
- source.ReportOutOfBandMessage("ERROR: Invalid eventId specification: " + activityFilterString, false);
- continue;
- }
- EnableFilter(ref filterList, source, perEventSourceSessionId, eventId, sampleFreq);
- }
- }
- }
-
- /// <summary>
- /// Returns the first ActivityFilter from 'filterList' corresponding to 'source'.
- /// </summary>
- public static ActivityFilter GetFilter(ActivityFilter filterList, EventSource source)
- {
- for (var af = filterList; af != null; af = af.m_next)
- {
- if (af.m_providerGuid == source.Guid && af.m_samplingFreq != -1)
- return af;
- }
- return null;
- }
-
- /// <summary>
- /// Returns a session mask representing all sessions in which the activity
- /// associated with the current thread is allowed through the activity filter.
- /// If 'triggeringEvent' is true the event MAY be a triggering event. Ideally
- /// most of the time this is false as you can guarantee this event is NOT a
- /// triggering event. If 'triggeringEvent' is true, then it checks the
- /// 'EventSource' and 'eventID' of the event being logged to see if it is actually
- /// a trigger. If so it activates the current activity.
- ///
- /// If 'childActivityID' is present, it will be added to the active set if the
- /// current activity is active.
- /// </summary>
- unsafe public static bool PassesActivityFilter(
- ActivityFilter filterList,
- Guid* childActivityID,
- bool triggeringEvent,
- EventSource source,
- int eventId)
- {
- Debug.Assert(filterList != null && filterList.m_activeActivities != null);
- bool shouldBeLogged = false;
- if (triggeringEvent)
- {
- for (ActivityFilter af = filterList; af != null; af = af.m_next)
- {
- if (eventId == af.m_eventId && source.Guid == af.m_providerGuid)
- {
- // Update the sampling count with wrap-around
- int curSampleCount, newSampleCount;
- do
- {
- curSampleCount = af.m_curSampleCount;
- if (curSampleCount <= 1)
- newSampleCount = af.m_samplingFreq; // Wrap around, counting down to 1
- else
- newSampleCount = curSampleCount - 1;
- }
- while (Interlocked.CompareExchange(ref af.m_curSampleCount, newSampleCount, curSampleCount) != curSampleCount);
- // If we hit zero, then start tracking the activity.
- if (curSampleCount <= 1)
- {
- Guid currentActivityId = EventSource.InternalCurrentThreadActivityId;
- Tuple<Guid, int> startId;
- // only add current activity if it's not already a root activity
- if (!af.m_rootActiveActivities.TryGetValue(currentActivityId, out startId))
- {
- // EventSource.OutputDebugString(string.Format(" PassesAF - Triggering(session {0}, evt {1})", af.m_perEventSourceSessionId, eventId));
- shouldBeLogged = true;
- af.m_activeActivities[currentActivityId] = Environment.TickCount;
- af.m_rootActiveActivities[currentActivityId] = Tuple.Create(source.Guid, eventId);
- }
- }
- else
- {
- // a start event following a triggering start event
- Guid currentActivityId = EventSource.InternalCurrentThreadActivityId;
- Tuple<Guid, int> startId;
- // only remove current activity if we added it
- if (af.m_rootActiveActivities.TryGetValue(currentActivityId, out startId) &&
- startId.Item1 == source.Guid && startId.Item2 == eventId)
- {
- // EventSource.OutputDebugString(string.Format("Activity dying: {0} -> StartEvent({1})", currentActivityId, eventId));
- // remove activity only from current logging scope (af)
- int dummy;
- af.m_activeActivities.TryRemove(currentActivityId, out dummy);
- }
- }
- break;
- }
- }
- }
-
- var activeActivities = GetActiveActivities(filterList);
- if (activeActivities != null)
- {
- // if we hadn't already determined this should be logged, test further
- if (!shouldBeLogged)
- {
- shouldBeLogged = !activeActivities.IsEmpty &&
- activeActivities.ContainsKey(EventSource.InternalCurrentThreadActivityId);
- }
- if (shouldBeLogged && childActivityID != null &&
- ((EventOpcode)source.m_eventData[eventId].Descriptor.Opcode == EventOpcode.Send))
- {
- FlowActivityIfNeeded(filterList, null, childActivityID);
- // EventSource.OutputDebugString(string.Format(" PassesAF - activity {0}", *childActivityID));
- }
- }
- // EventSource.OutputDebugString(string.Format(" PassesAF - shouldBeLogged(evt {0}) = {1:x}", eventId, shouldBeLogged));
- return shouldBeLogged;
- }
-
- public static bool IsCurrentActivityActive(ActivityFilter filterList)
- {
- var activeActivities = GetActiveActivities(filterList);
- if (activeActivities != null &&
- activeActivities.ContainsKey(EventSource.InternalCurrentThreadActivityId))
- return true;
-
- return false;
- }
-
- /// <summary>
- /// For the EventListener/EtwSession associated with 'filterList', add 'childActivityid'
- /// to list of active activities IF 'currentActivityId' is also active. Passing in a null
- /// value for 'currentActivityid' is an indication the caller has already verified
- /// that the current activity is active.
- /// </summary>
- unsafe public static void FlowActivityIfNeeded(ActivityFilter filterList, Guid* currentActivityId, Guid* childActivityID)
- {
- Debug.Assert(childActivityID != null);
-
- var activeActivities = GetActiveActivities(filterList);
- Debug.Assert(activeActivities != null);
-
- // take currentActivityId == null to mean we *know* the current activity is "active"
- if (currentActivityId != null && !activeActivities.ContainsKey(*currentActivityId))
- return;
-
- if (activeActivities.Count > MaxActivityTrackCount)
- {
- TrimActiveActivityStore(activeActivities);
- // make sure current activity is still in the set:
- activeActivities[EventSource.InternalCurrentThreadActivityId] = Environment.TickCount;
- }
- // add child activity to list of activities
- activeActivities[*childActivityID] = Environment.TickCount;
-
- }
-
- /// <summary>
- /// </summary>
- public static void UpdateKwdTriggers(ActivityFilter activityFilter, Guid sourceGuid, EventSource source, EventKeywords sessKeywords)
- {
- for (var af = activityFilter; af != null; af = af.m_next)
- {
- if ((sourceGuid == af.m_providerGuid) &&
- (source.m_eventData[af.m_eventId].TriggersActivityTracking > 0 ||
- ((EventOpcode)source.m_eventData[af.m_eventId].Descriptor.Opcode == EventOpcode.Send)))
- {
- // we could be more precise here, if we tracked 'anykeywords' per session
- unchecked
- {
- source.m_keywordTriggers |= (source.m_eventData[af.m_eventId].Descriptor.Keywords & (long)sessKeywords);
- }
- }
- }
- }
-
- /// <summary>
- /// For the EventSource specified by 'sourceGuid' and the EventListener/EtwSession
- /// associated with 'this' ActivityFilter list, return configured sequence of
- /// [eventId, sampleFreq] pairs that defines the sampling policy.
- /// </summary>
- public IEnumerable<Tuple<int, int>> GetFilterAsTuple(Guid sourceGuid)
- {
- for (ActivityFilter af = this; af != null; af = af.m_next)
- {
- if (af.m_providerGuid == sourceGuid)
- yield return Tuple.Create(af.m_eventId, af.m_samplingFreq);
- }
- }
-
- /// <summary>
- /// The cleanup being performed consists of removing the m_myActivityDelegate from
- /// the static s_activityDying, therefore allowing the ActivityFilter to be reclaimed.
- /// </summary>
- public void Dispose()
- {
-#if !ES_BUILD_STANDALONE
- Debug.Assert(Monitor.IsEntered(EventListener.EventListenersLock));
-#endif
- // m_myActivityDelegate is still alive (held by the static EventSource.s_activityDying).
- // Therefore we are ok to take a dependency on m_myActivityDelegate being valid even
- // during the finalization of the ActivityFilter
- if (m_myActivityDelegate != null)
- {
- EventSource.s_activityDying = (Action<Guid>)Delegate.Remove(EventSource.s_activityDying, m_myActivityDelegate);
- m_myActivityDelegate = null;
- }
- }
-
-#region private
-
- /// <summary>
- /// Creates a new ActivityFilter that is triggered by 'eventId' from 'source' ever
- /// 'samplingFreq' times the event fires. You can have several of these forming a
- /// linked list.
- /// </summary>
- private ActivityFilter(EventSource source, int perEventSourceSessionId, int eventId, int samplingFreq, ActivityFilter existingFilter = null)
- {
- m_providerGuid = source.Guid;
- m_perEventSourceSessionId = perEventSourceSessionId;
- m_eventId = eventId;
- m_samplingFreq = samplingFreq;
- m_next = existingFilter;
-
- Debug.Assert(existingFilter == null ||
- (existingFilter.m_activeActivities == null) == (existingFilter.m_rootActiveActivities == null));
-
- // if this is the first filter we add for this session, we need to create a new
- // table of activities. m_activeActivities is common across EventSources in the same
- // session
- ConcurrentDictionary<Guid, int> activeActivities = null;
- if (existingFilter == null ||
- (activeActivities = GetActiveActivities(existingFilter)) == null)
- {
- m_activeActivities = new ConcurrentDictionary<Guid, int>();
- m_rootActiveActivities = new ConcurrentDictionary<Guid, Tuple<Guid, int>>();
-
- // Add a delegate to the 'SetCurrentThreadToActivity callback so that I remove 'dead' activities
- m_myActivityDelegate = GetActivityDyingDelegate(this);
- EventSource.s_activityDying = (Action<Guid>)Delegate.Combine(EventSource.s_activityDying, m_myActivityDelegate);
- }
- else
- {
- m_activeActivities = activeActivities;
- m_rootActiveActivities = existingFilter.m_rootActiveActivities;
- }
-
- }
-
- /// <summary>
- /// Ensure there's at least one ActivityFilter in the 'filterList' that contains an
- /// activity-removing delegate for the listener/session associated with 'filterList'.
- /// </summary>
- private static void EnsureActivityCleanupDelegate(ActivityFilter filterList)
- {
- if (filterList == null)
- return;
-
- for (ActivityFilter af = filterList; af != null; af = af.m_next)
- {
- if (af.m_myActivityDelegate != null)
- return;
- }
-
- // we didn't find a delegate
- filterList.m_myActivityDelegate = GetActivityDyingDelegate(filterList);
- EventSource.s_activityDying = (Action<Guid>)Delegate.Combine(EventSource.s_activityDying, filterList.m_myActivityDelegate);
- }
-
- /// <summary>
- /// Builds the delegate to be called when an activity is dying. This is responsible
- /// for performing whatever cleanup is needed for the ActivityFilter list passed in.
- /// This gets "added" to EventSource.s_activityDying and ends up being called from
- /// EventSource.SetCurrentThreadActivityId and ActivityFilter.PassesActivityFilter.
- /// </summary>
- /// <returns>The delegate to be called when an activity is dying</returns>
- private static Action<Guid> GetActivityDyingDelegate(ActivityFilter filterList)
- {
- return (Guid oldActivity) =>
- {
- int dummy;
- filterList.m_activeActivities.TryRemove(oldActivity, out dummy);
- Tuple<Guid, int> dummyTuple;
- filterList.m_rootActiveActivities.TryRemove(oldActivity, out dummyTuple);
- };
- }
-
- /// <summary>
- /// Enables activity filtering for the listener associated with 'filterList', triggering on
- /// the event 'eventID' from 'source' with a sampling frequency of 'samplingFreq'
- ///
- /// if 'eventID' is out of range (e.g. negative), it means we are not triggering (but we are
- /// activitySampling if something else triggered).
- /// </summary>
- /// <returns>true if activity sampling is enabled the samplingFreq is non-zero </returns>
- private static bool EnableFilter(ref ActivityFilter filterList, EventSource source, int perEventSourceSessionId, int eventId, int samplingFreq)
- {
-#if !ES_BUILD_STANDALONE
- Debug.Assert(Monitor.IsEntered(EventListener.EventListenersLock));
-#endif
- Debug.Assert(samplingFreq > 0);
- Debug.Assert(eventId >= 0);
-
- filterList = new ActivityFilter(source, perEventSourceSessionId, eventId, samplingFreq, filterList);
-
- // Mark the 'quick Check' that indicates this is a trigger event.
- // If eventId is out of range then this mark is not done which has the effect of ignoring
- // the trigger.
- if (0 <= eventId && eventId < source.m_eventData.Length)
- ++source.m_eventData[eventId].TriggersActivityTracking;
-
- return true;
- }
-
- /// <summary>
- /// Normally this code never runs, it is here just to prevent run-away resource usage.
- /// </summary>
- private static void TrimActiveActivityStore(ConcurrentDictionary<Guid, int> activities)
- {
- if (activities.Count > MaxActivityTrackCount)
- {
- // Remove half of the oldest activity ids.
- var keyValues = activities.ToArray();
- var tickNow = Environment.TickCount;
-
- // Sort by age, taking into account wrap-around. As long as x and y are within
- // 23 days of now then (0x7FFFFFFF & (tickNow - x.Value)) is the delta (even if
- // TickCount wraps). I then sort by DESCENDING age. (that is oldest value first)
- Array.Sort(keyValues, (x, y) => (0x7FFFFFFF & (tickNow - y.Value)) - (0x7FFFFFFF & (tickNow - x.Value)));
- for (int i = 0; i < keyValues.Length / 2; i++)
- {
- int dummy;
- activities.TryRemove(keyValues[i].Key, out dummy);
- }
- }
- }
-
- private static ConcurrentDictionary<Guid, int> GetActiveActivities(
- ActivityFilter filterList)
- {
- for (ActivityFilter af = filterList; af != null; af = af.m_next)
- {
- if (af.m_activeActivities != null)
- return af.m_activeActivities;
- }
- return null;
- }
-
- // m_activeActivities always points to the sample dictionary for EVERY ActivityFilter
- // in the m_next list. The 'int' value in the m_activities set is a timestamp
- // (Environment.TickCount) of when the entry was put in the system and is used to
- // remove 'old' entries that if the set gets too big.
- ConcurrentDictionary<Guid, int> m_activeActivities;
-
- // m_rootActiveActivities holds the "root" active activities, i.e. the activities
- // that were marked as active because a Start event fired on them. We need to keep
- // track of these to enable sampling in the scenario of an app's main thread that
- // never explicitly sets distinct activity IDs as it executes. To handle these
- // situations we manufacture a Guid from the thread's ID, and:
- // (a) we consider the firing of a start event when the sampling counter reaches
- // zero to mark the beginning of an interesting activity, and
- // (b) we consider the very next firing of the same start event to mark the
- // ending of that activity.
- // We use a ConcurrentDictionary to avoid taking explicit locks.
- // The key (a guid) represents the activity ID of the root active activity
- // The value is made up of the Guid of the event provider and the eventId of
- // the start event.
- ConcurrentDictionary<Guid, Tuple<Guid, int>> m_rootActiveActivities;
- Guid m_providerGuid; // We use the GUID rather than object identity because we don't want to keep the eventSource alive
- int m_eventId; // triggering event
- int m_samplingFreq; // Counter reset to this when it hits 0
- int m_curSampleCount; // We count down to 0 and then activate the activity.
- int m_perEventSourceSessionId; // session ID bit for ETW, 0 for EventListeners
-
- const int MaxActivityTrackCount = 100000; // maximum number of tracked activities
-
- ActivityFilter m_next; // We create a linked list of these
- Action<Guid> m_myActivityDelegate;
-#endregion
- };
-
-
- /// <summary>
- /// An EtwSession instance represents an activity-tracing-aware ETW session. Since these
- /// are limited to 8 concurrent sessions per machine (currently) we're going to store
- /// the active ones in a singly linked list.
- /// </summary>
- internal class EtwSession
- {
- public static EtwSession GetEtwSession(int etwSessionId, bool bCreateIfNeeded = false)
- {
- if (etwSessionId < 0)
- return null;
-
- EtwSession etwSession;
- foreach (var wrEtwSession in s_etwSessions)
- {
-#if ES_BUILD_STANDALONE
- if ((etwSession = (EtwSession) wrEtwSession.Target) != null && etwSession.m_etwSessionId == etwSessionId)
- return etwSession;
-#else
- if (wrEtwSession.TryGetTarget(out etwSession) && etwSession.m_etwSessionId == etwSessionId)
- return etwSession;
-#endif
- }
-
- if (!bCreateIfNeeded)
- return null;
-
-#if ES_BUILD_STANDALONE
- if (s_etwSessions == null)
- s_etwSessions = new List<WeakReference>();
-
- etwSession = new EtwSession(etwSessionId);
- s_etwSessions.Add(new WeakReference(etwSession));
-#else
- if (s_etwSessions == null)
- s_etwSessions = new List<WeakReference<EtwSession>>();
-
- etwSession = new EtwSession(etwSessionId);
- s_etwSessions.Add(new WeakReference<EtwSession>(etwSession));
-#endif
-
- if (s_etwSessions.Count > s_thrSessionCount)
- TrimGlobalList();
-
- return etwSession;
-
- }
-
- public static void RemoveEtwSession(EtwSession etwSession)
- {
- Debug.Assert(etwSession != null);
- if (s_etwSessions == null || etwSession == null)
- return;
-
- s_etwSessions.RemoveAll((wrEtwSession) =>
- {
- EtwSession session;
-#if ES_BUILD_STANDALONE
- return (session = (EtwSession) wrEtwSession.Target) != null &&
- (session.m_etwSessionId == etwSession.m_etwSessionId);
-#else
- return wrEtwSession.TryGetTarget(out session) &&
- (session.m_etwSessionId == etwSession.m_etwSessionId);
-#endif
- });
-
- if (s_etwSessions.Count > s_thrSessionCount)
- TrimGlobalList();
- }
-
- private static void TrimGlobalList()
- {
- if (s_etwSessions == null)
- return;
-
- s_etwSessions.RemoveAll((wrEtwSession) =>
- {
-#if ES_BUILD_STANDALONE
- return wrEtwSession.Target == null;
-#else
- EtwSession session;
- return !wrEtwSession.TryGetTarget(out session);
-#endif
- });
- }
-
- private EtwSession(int etwSessionId)
- {
- m_etwSessionId = etwSessionId;
- }
-
- public readonly int m_etwSessionId; // ETW session ID (as retrieved by EventProvider)
- public ActivityFilter m_activityFilter; // all filters enabled for this session
-
-#if ES_BUILD_STANDALONE
- private static List<WeakReference> s_etwSessions = new List<WeakReference>();
-#else
- private static List<WeakReference<EtwSession>> s_etwSessions = new List<WeakReference<EtwSession>>();
-#endif
- private const int s_thrSessionCount = 16;
- }
-
-#endif // FEATURE_ACTIVITYSAMPLING
-
// holds a bitfield representing a session mask
/// <summary>
/// A SessionMask represents a set of (at most MAX) sessions as a bit mask. The perEventSourceSessionId
@@ -6096,9 +4902,6 @@ namespace System.Diagnostics.Tracing
// Instance fields
readonly internal EventListener m_Listener; // The dispatcher this entry is for
internal bool[] m_EventEnabled; // For every event in a the eventSource, is it enabled?
-#if FEATURE_ACTIVITYSAMPLING
- internal bool m_activityFilteringEnabled; // does THIS EventSource have activity filtering turned on for this listener?
-#endif // FEATURE_ACTIVITYSAMPLING
// Only guaranteed to exist after a InsureInit()
internal EventDispatcher m_Next; // These form a linked list in code:EventSource.m_Dispatchers
diff --git a/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/DataCollector.cs b/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/DataCollector.cs
index 1444c267cb..11c18a260f 100644
--- a/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/DataCollector.cs
+++ b/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/DataCollector.cs
@@ -143,6 +143,45 @@ namespace System.Diagnostics.Tracing
}
}
+ internal unsafe void AddNullTerminatedString(string value)
+ {
+ // Treat null strings as empty strings.
+ if (value == null)
+ {
+ value = string.Empty;
+ }
+
+ // Calculate the size of the string including the trailing NULL char.
+ // Don't use value.Length here because string allows for embedded NULL characters.
+ int nullCharIndex = value.IndexOf((char)0);
+ if (nullCharIndex < 0)
+ {
+ nullCharIndex = value.Length;
+ }
+ int size = (nullCharIndex + 1) * 2;
+
+ if (this.bufferNesting != 0)
+ {
+ this.EnsureBuffer(size);
+ }
+
+ if (this.bufferNesting == 0)
+ {
+ this.ScalarsEnd();
+ this.PinArray(value, size);
+ }
+ else
+ {
+ var oldPos = this.bufferPos;
+ this.bufferPos = checked(this.bufferPos + size);
+ this.EnsureBuffer();
+ fixed (void* p = value)
+ {
+ Marshal.Copy((IntPtr)p, buffer, oldPos, size);
+ }
+ }
+ }
+
internal void AddBinary(Array value, int size)
{
this.AddArray(value, size, 1);
diff --git a/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/EventSourceActivity.cs b/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/EventSourceActivity.cs
index 865082f767..2d71550803 100644
--- a/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/EventSourceActivity.cs
+++ b/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/EventSourceActivity.cs
@@ -314,7 +314,7 @@ namespace System.Diagnostics.Tracing
private State state;
private string eventName;
- static internal Guid s_empty;
+ internal static Guid s_empty;
#endregion
}
}
diff --git a/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/FieldMetadata.cs b/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/FieldMetadata.cs
index 9c7c6369ec..f153734752 100644
--- a/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/FieldMetadata.cs
+++ b/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/FieldMetadata.cs
@@ -135,13 +135,11 @@ namespace System.Diagnostics.Tracing
{
throw new NotSupportedException(SR.EventSource_NotSupportedArrayOfBinary);
}
-#if !BROKEN_UNTIL_M3
if (coreType == (int)TraceLoggingDataType.Utf16String ||
coreType == (int)TraceLoggingDataType.MbcsString)
{
throw new NotSupportedException(SR.EventSource_NotSupportedArrayOfNullTerminatedString);
}
-#endif
}
if (((int)this.tags & 0xfffffff) != 0)
diff --git a/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/InvokeTypeInfo.cs b/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/InvokeTypeInfo.cs
index 3e5997bc9b..2a7113e5d7 100644
--- a/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/InvokeTypeInfo.cs
+++ b/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/InvokeTypeInfo.cs
@@ -21,7 +21,7 @@ namespace System.Diagnostics.Tracing
/// </typeparam>
internal sealed class InvokeTypeInfo : TraceLoggingTypeInfo
{
- private readonly PropertyAnalysis[] properties;
+ internal readonly PropertyAnalysis[] properties;
public InvokeTypeInfo(
Type type,
diff --git a/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/NameInfo.cs b/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/NameInfo.cs
index 668043ae68..b1c7327c18 100644
--- a/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/NameInfo.cs
+++ b/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/NameInfo.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
+using System.Collections.Concurrent;
using Interlocked = System.Threading.Interlocked;
#if ES_BUILD_STANDALONE
@@ -41,6 +42,10 @@ namespace System.Diagnostics.Tracing
internal readonly int identity;
internal readonly byte[] nameMetadata;
+#if FEATURE_PERFTRACING
+ private readonly object eventHandleCreationLock = new object();
+#endif
+
public NameInfo(string name, EventTags tags, int typeMetadataSize)
{
this.name = name;
@@ -75,5 +80,47 @@ namespace System.Diagnostics.Tracing
}
return result;
}
+
+#if FEATURE_PERFTRACING
+ public IntPtr GetOrCreateEventHandle(EventProvider provider, ConcurrentDictionary<int, IntPtr> eventHandleMap, EventDescriptor descriptor, TraceLoggingEventTypes eventTypes)
+ {
+ IntPtr eventHandle = IntPtr.Zero;
+ if(!eventHandleMap.TryGetValue(descriptor.EventId, out eventHandle))
+ {
+ lock (eventHandleCreationLock)
+ {
+ if (!eventHandleMap.TryGetValue(descriptor.EventId, out eventHandle))
+ {
+ byte[] metadataBlob = EventPipeMetadataGenerator.Instance.GenerateEventMetadata(
+ descriptor.EventId,
+ name,
+ (EventKeywords)descriptor.Keywords,
+ (EventLevel)descriptor.Level,
+ descriptor.Version,
+ eventTypes);
+ uint metadataLength = (metadataBlob != null) ? (uint)metadataBlob.Length : 0;
+
+ unsafe
+ {
+ fixed (byte* pMetadataBlob = metadataBlob)
+ {
+ // Define the event.
+ eventHandle = provider.m_eventProvider.DefineEventHandle(
+ (uint)descriptor.EventId,
+ name,
+ descriptor.Keywords,
+ descriptor.Version,
+ descriptor.Level,
+ pMetadataBlob,
+ metadataLength);
+ }
+ }
+ }
+ }
+ }
+
+ return eventHandle;
+ }
+#endif
}
}
diff --git a/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/SimpleTypeInfos.cs b/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/SimpleTypeInfos.cs
index 901a0ed1a2..001a8e8f05 100644
--- a/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/SimpleTypeInfos.cs
+++ b/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/SimpleTypeInfos.cs
@@ -136,7 +136,7 @@ namespace System.Diagnostics.Tracing
public static TraceLoggingTypeInfo UIntPtr() { return new ScalarArrayTypeInfo(typeof(UIntPtr[]), Statics.FormatPtr, Statics.UIntPtrType, System.IntPtr.Size); }
public static TraceLoggingTypeInfo Single() { return new ScalarArrayTypeInfo(typeof(Single[]), Statics.Format32, TraceLoggingDataType.Float, sizeof(Single)); }
public static TraceLoggingTypeInfo Double() { return new ScalarArrayTypeInfo(typeof(Double[]), Statics.Format64, TraceLoggingDataType.Double, sizeof(Double)); }
- public unsafe static TraceLoggingTypeInfo Guid() { return new ScalarArrayTypeInfo(typeof(Guid), (f, t) => Statics.MakeDataType(TraceLoggingDataType.Guid, f), TraceLoggingDataType.Guid, sizeof(Guid)); }
+ public static unsafe TraceLoggingTypeInfo Guid() { return new ScalarArrayTypeInfo(typeof(Guid), (f, t) => Statics.MakeDataType(TraceLoggingDataType.Guid, f), TraceLoggingDataType.Guid, sizeof(Guid)); }
}
/// <summary>
@@ -151,12 +151,12 @@ namespace System.Diagnostics.Tracing
string name,
EventFieldFormat format)
{
- collector.AddBinary(name, Statics.MakeDataType(TraceLoggingDataType.CountedUtf16String, format));
+ collector.AddNullTerminatedString(name, Statics.MakeDataType(TraceLoggingDataType.Utf16String, format));
}
public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
{
- collector.AddBinary((string)value.ReferenceValue);
+ collector.AddNullTerminatedString((string)value.ReferenceValue);
}
public override object GetData(object value)
@@ -187,8 +187,14 @@ namespace System.Diagnostics.Tracing
public override void WriteData(TraceLoggingDataCollector collector, PropertyValue value)
{
- var ticks = value.ScalarValue.AsDateTime.Ticks;
- collector.AddScalar(ticks < 504911232000000000 ? 0 : ticks - 504911232000000000);
+ DateTime dateTime = value.ScalarValue.AsDateTime;
+ const long UTCMinTicks = 504911232000000000;
+ long dateTimeTicks = 0;
+ // We cannot translate dates sooner than 1/1/1601 in UTC.
+ // To avoid getting an ArgumentOutOfRangeException we compare with 1/1/1601 DateTime ticks
+ if (dateTime.Ticks > UTCMinTicks)
+ dateTimeTicks = dateTime.ToFileTimeUtc();
+ collector.AddScalar(dateTimeTicks);
}
}
diff --git a/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/TraceLoggingDataCollector.cs b/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/TraceLoggingDataCollector.cs
index 04a047fb35..f6d0a59aa6 100644
--- a/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/TraceLoggingDataCollector.cs
+++ b/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/TraceLoggingDataCollector.cs
@@ -85,6 +85,17 @@ namespace System.Diagnostics.Tracing
}
/// <summary>
+ /// Adds a null-terminated String value to the event payload.
+ /// </summary>
+ /// <param name="value">
+ /// Value to be added. A null value is treated as a zero-length string.
+ /// </param>
+ public void AddNullTerminatedString(string value)
+ {
+ DataCollector.ThreadInstance.AddNullTerminatedString(value);
+ }
+
+ /// <summary>
/// Adds a counted String value to the event payload.
/// </summary>
/// <param name="value">
diff --git a/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs b/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs
index bf29d71844..ccdc8bf7c4 100644
--- a/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs
+++ b/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs
@@ -7,10 +7,6 @@
#if PLATFORM_WINDOWS
#define FEATURE_MANAGED_ETW
-
-#if !ES_BUILD_STANDALONE
-#define FEATURE_ACTIVITYSAMPLING
-#endif
#endif // PLATFORM_WINDOWS
#if ES_BUILD_STANDALONE
@@ -28,6 +24,7 @@ using System.Resources;
using System.Runtime.InteropServices;
using System.Security;
using System.Collections.ObjectModel;
+using System.Collections.Concurrent;
#if !ES_BUILD_AGAINST_DOTNET_V35
using Contract = System.Diagnostics.Contracts.Contract;
@@ -51,6 +48,10 @@ namespace System.Diagnostics.Tracing
private byte[] providerMetadata;
#endif
+#if FEATURE_PERFTRACING
+ private ConcurrentDictionary<int, IntPtr> m_eventHandleMap = new ConcurrentDictionary<int, IntPtr>();
+#endif
+
/// <summary>
/// Construct an EventSource with a given name for non-contract based events (e.g. those using the Write() API).
/// </summary>
@@ -435,9 +436,18 @@ namespace System.Diagnostics.Tracing
identity = nameInfo.identity;
EventDescriptor descriptor = new EventDescriptor(identity, level, opcode, (long)keywords);
+#if FEATURE_PERFTRACING
+ IntPtr eventHandle = nameInfo.GetOrCreateEventHandle(m_provider, m_eventHandleMap, descriptor, eventTypes);
+ Debug.Assert(eventHandle != IntPtr.Zero);
+#else
+ IntPtr eventHandle = IntPtr.Zero;
+#endif
+
var pinCount = eventTypes.pinCount;
var scratch = stackalloc byte[eventTypes.scratchSize];
var descriptors = stackalloc EventData[eventTypes.dataCount + 3];
+ for(int i = 0; i < eventTypes.dataCount + 3; i++)
+ descriptors[i] = default(EventData);
var pins = stackalloc GCHandle[pinCount];
for (int i = 0; i < pinCount; i++)
@@ -474,6 +484,7 @@ namespace System.Diagnostics.Tracing
this.WriteEventRaw(
eventName,
ref descriptor,
+ eventHandle,
activityID,
childActivityID,
(int)(DataCollector.ThreadInstance.Finish() - descriptors),
@@ -540,9 +551,19 @@ namespace System.Diagnostics.Tracing
return;
}
+#if FEATURE_PERFTRACING
+ IntPtr eventHandle = nameInfo.GetOrCreateEventHandle(m_provider, m_eventHandleMap, descriptor, eventTypes);
+ Debug.Assert(eventHandle != IntPtr.Zero);
+#else
+ IntPtr eventHandle = IntPtr.Zero;
+#endif
+
// We make a descriptor for each EventData, and because we morph strings to counted strings
// we may have 2 for each arg, so we allocate enough for this.
- var descriptors = stackalloc EventData[eventTypes.dataCount + eventTypes.typeInfos.Length * 2 + 3];
+ var descriptorsLength = eventTypes.dataCount + eventTypes.typeInfos.Length * 2 + 3;
+ var descriptors = stackalloc EventData[descriptorsLength];
+ for(int i = 0; i < descriptorsLength; i++)
+ descriptors[i] = default(EventData);
fixed (byte*
pMetadata0 = this.providerMetadata,
@@ -556,35 +577,20 @@ namespace System.Diagnostics.Tracing
for (int i = 0; i < eventTypes.typeInfos.Length; i++)
{
- // Until M3, we need to morph strings to a counted representation
- // When TDH supports null terminated strings, we can remove this.
- if (eventTypes.typeInfos[i].DataType == typeof(string))
- {
- // Write out the size of the string
- descriptors[numDescrs].DataPointer = (IntPtr) (&descriptors[numDescrs + 1].m_Size);
- descriptors[numDescrs].m_Size = 2;
- numDescrs++;
-
- descriptors[numDescrs].m_Ptr = data[i].m_Ptr;
- descriptors[numDescrs].m_Size = data[i].m_Size - 2; // Remove the null terminator
- numDescrs++;
- }
- else
- {
- descriptors[numDescrs].m_Ptr = data[i].m_Ptr;
- descriptors[numDescrs].m_Size = data[i].m_Size;
+ descriptors[numDescrs].m_Ptr = data[i].m_Ptr;
+ descriptors[numDescrs].m_Size = data[i].m_Size;
- // old conventions for bool is 4 bytes, but meta-data assumes 1.
- if (data[i].m_Size == 4 && eventTypes.typeInfos[i].DataType == typeof(bool))
- descriptors[numDescrs].m_Size = 1;
+ // old conventions for bool is 4 bytes, but meta-data assumes 1.
+ if (data[i].m_Size == 4 && eventTypes.typeInfos[i].DataType == typeof(bool))
+ descriptors[numDescrs].m_Size = 1;
- numDescrs++;
- }
+ numDescrs++;
}
this.WriteEventRaw(
eventName,
ref descriptor,
+ eventHandle,
activityID,
childActivityID,
numDescrs,
@@ -614,10 +620,19 @@ namespace System.Diagnostics.Tracing
return;
}
+#if FEATURE_PERFTRACING
+ IntPtr eventHandle = nameInfo.GetOrCreateEventHandle(m_provider, m_eventHandleMap, descriptor, eventTypes);
+ Debug.Assert(eventHandle != IntPtr.Zero);
+#else
+ IntPtr eventHandle = IntPtr.Zero;
+#endif
+
#if FEATURE_MANAGED_ETW
var pinCount = eventTypes.pinCount;
var scratch = stackalloc byte[eventTypes.scratchSize];
var descriptors = stackalloc EventData[eventTypes.dataCount + 3];
+ for(int i=0; i<eventTypes.dataCount + 3; i++)
+ descriptors[i] = default(EventData);
var pins = stackalloc GCHandle[pinCount];
for (int i = 0; i < pinCount; i++)
@@ -634,7 +649,7 @@ namespace System.Diagnostics.Tracing
#endif // FEATURE_MANAGED_ETW
#if (!ES_BUILD_PCL && !ES_BUILD_PN)
- System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions();
+ System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions();
#endif
EventOpcode opcode = (EventOpcode)descriptor.Opcode;
@@ -674,6 +689,7 @@ namespace System.Diagnostics.Tracing
this.WriteEventRaw(
eventName,
ref descriptor,
+ eventHandle,
pActivityId,
pRelatedActivityId,
(int)(DataCollector.ThreadInstance.Finish() - descriptors),
@@ -684,7 +700,7 @@ namespace System.Diagnostics.Tracing
if (m_Dispatchers != null)
{
var eventData = (EventPayload)(eventTypes.typeInfos[0].GetData(data));
- WriteToAllListeners(eventName, ref descriptor, nameInfo.tags, pActivityId, eventData);
+ WriteToAllListeners(eventName, ref descriptor, nameInfo.tags, pActivityId, pRelatedActivityId, eventData);
}
}
@@ -713,7 +729,7 @@ namespace System.Diagnostics.Tracing
}
}
- private unsafe void WriteToAllListeners(string eventName, ref EventDescriptor eventDescriptor, EventTags tags, Guid* pActivityId, EventPayload payload)
+ private unsafe void WriteToAllListeners(string eventName, ref EventDescriptor eventDescriptor, EventTags tags, Guid* pActivityId, Guid* pChildActivityId, EventPayload payload)
{
EventWrittenEventArgs eventCallbackArgs = new EventWrittenEventArgs(this);
eventCallbackArgs.EventName = eventName;
@@ -725,7 +741,9 @@ namespace System.Diagnostics.Tracing
// Self described events do not have an id attached. We mark it internally with -1.
eventCallbackArgs.EventId = -1;
if (pActivityId != null)
- eventCallbackArgs.RelatedActivityId = *pActivityId;
+ eventCallbackArgs.ActivityId = *pActivityId;
+ if (pChildActivityId != null)
+ eventCallbackArgs.RelatedActivityId = *pChildActivityId;
if (payload != null)
{
diff --git a/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventTypes.cs b/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventTypes.cs
index 3c775a3cef..8887714fdb 100644
--- a/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventTypes.cs
+++ b/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventTypes.cs
@@ -25,6 +25,9 @@ namespace System.Diagnostics.Tracing
public class TraceLoggingEventTypes
{
internal readonly TraceLoggingTypeInfo[] typeInfos;
+#if FEATURE_PERFTRACING
+ internal readonly string[] paramNames;
+#endif
internal readonly string name;
internal readonly EventTags tags;
internal readonly byte level;
@@ -98,6 +101,9 @@ namespace System.Diagnostics.Tracing
}
this.typeInfos = MakeArray(paramInfos);
+#if FEATURE_PERFTRACING
+ this.paramNames = MakeParamNameArray(paramInfos);
+#endif
this.name = name;
this.tags = tags;
this.level = Statics.DefaultLevel;
@@ -248,5 +254,19 @@ namespace System.Diagnostics.Tracing
return (TraceLoggingTypeInfo[])typeInfos.Clone(); ;
}
+
+#if FEATURE_PERFTRACING
+ private static string[] MakeParamNameArray(
+ System.Reflection.ParameterInfo[] paramInfos)
+ {
+ string[] paramNames = new string[paramInfos.Length];
+ for (int i = 0; i < paramNames.Length; i++)
+ {
+ paramNames[i] = paramInfos[i].Name;
+ }
+
+ return paramNames;
+ }
+#endif
}
}
diff --git a/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/TraceLoggingMetadataCollector.cs b/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/TraceLoggingMetadataCollector.cs
index 1db1a28c9d..b5b199dbca 100644
--- a/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/TraceLoggingMetadataCollector.cs
+++ b/src/Common/src/CoreLib/System/Diagnostics/Tracing/TraceLogging/TraceLoggingMetadataCollector.cs
@@ -192,22 +192,43 @@ namespace System.Diagnostics.Tracing
}
/// <summary>
+ /// Adds a null-terminated string field to an event.
+ /// Compatible with core types: Utf16String, MbcsString.
+ /// Compatible with dataCollector method: AddNullTerminatedString(string).
+ /// </summary>
+ /// <param name="name">
+ /// The name to use for the added field. This value must not be null.
+ /// </param>
+ /// <param name="type">
+ /// The type code for the added field. This must be a null-terminated string type.
+ /// </param>
+ public void AddNullTerminatedString(string name, TraceLoggingDataType type)
+ {
+ switch ((TraceLoggingDataType)((int)type & Statics.InTypeMask))
+ {
+ case TraceLoggingDataType.Utf16String:
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(type));
+ }
+
+ this.impl.AddNonscalar();
+ this.AddField(new FieldMetadata(name, type, this.Tags, this.BeginningBufferedArray));
+ }
+
+ /// <summary>
/// Adds an array field to an event.
/// </summary>
/// <param name="name">
/// The name to use for the added field. This value must not be null.
/// </param>
/// <param name="type">
- /// The type code for the added field. This must be a fixed-size type
- /// or a string type. In the case of a string type, this adds an array
- /// of characters, not an array of strings.
+ /// The type code for the added field. This must be a fixed-size type.
/// </param>
public void AddArray(string name, TraceLoggingDataType type)
{
switch ((TraceLoggingDataType)((int)type & Statics.InTypeMask))
{
- case TraceLoggingDataType.Utf16String:
- case TraceLoggingDataType.MbcsString:
case TraceLoggingDataType.Int8:
case TraceLoggingDataType.UInt8:
case TraceLoggingDataType.Int16:
diff --git a/src/Common/src/CoreLib/System/Double.cs b/src/Common/src/CoreLib/System/Double.cs
index 3652963ef6..8eae31232f 100644
--- a/src/Common/src/CoreLib/System/Double.cs
+++ b/src/Common/src/CoreLib/System/Double.cs
@@ -17,6 +17,8 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
+using Internal.Runtime.CompilerServices;
+
namespace System
{
[Serializable]
@@ -45,7 +47,7 @@ namespace System
/// <summary>Determines whether the specified value is finite (zero, subnormal, or normal).</summary>
[NonVersionable]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public unsafe static bool IsFinite(double d)
+ public static unsafe bool IsFinite(double d)
{
var bits = BitConverter.DoubleToInt64Bits(d);
return (bits & 0x7FFFFFFFFFFFFFFF) < 0x7FF0000000000000;
@@ -54,7 +56,7 @@ namespace System
/// <summary>Determines whether the specified value is infinite.</summary>
[NonVersionable]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public unsafe static bool IsInfinity(double d)
+ public static unsafe bool IsInfinity(double d)
{
var bits = BitConverter.DoubleToInt64Bits(d);
return (bits & 0x7FFFFFFFFFFFFFFF) == 0x7FF0000000000000;
@@ -63,7 +65,7 @@ namespace System
/// <summary>Determines whether the specified value is NaN.</summary>
[NonVersionable]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public unsafe static bool IsNaN(double d)
+ public static unsafe bool IsNaN(double d)
{
var bits = BitConverter.DoubleToInt64Bits(d);
return (bits & 0x7FFFFFFFFFFFFFFF) > 0x7FF0000000000000;
@@ -72,7 +74,7 @@ namespace System
/// <summary>Determines whether the specified value is negative.</summary>
[NonVersionable]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public unsafe static bool IsNegative(double d)
+ public static unsafe bool IsNegative(double d)
{
var bits = unchecked((ulong)BitConverter.DoubleToInt64Bits(d));
return (bits & 0x8000000000000000) == 0x8000000000000000;
@@ -89,7 +91,7 @@ namespace System
/// <summary>Determines whether the specified value is normal.</summary>
[NonVersionable]
// This is probably not worth inlining, it has branches and should be rarely called
- public unsafe static bool IsNormal(double d)
+ public static unsafe bool IsNormal(double d)
{
var bits = BitConverter.DoubleToInt64Bits(d);
bits &= 0x7FFFFFFFFFFFFFFF;
@@ -107,7 +109,7 @@ namespace System
/// <summary>Determines whether the specified value is subnormal.</summary>
[NonVersionable]
// This is probably not worth inlining, it has branches and should be rarely called
- public unsafe static bool IsSubnormal(double d)
+ public static unsafe bool IsSubnormal(double d)
{
var bits = BitConverter.DoubleToInt64Bits(d);
bits &= 0x7FFFFFFFFFFFFFFF;
@@ -221,16 +223,19 @@ namespace System
//The hashcode for a double is the absolute value of the integer representation
//of that double.
//
- public unsafe override int GetHashCode()
+ [MethodImpl(MethodImplOptions.AggressiveInlining)] // 64-bit constants make the IL unusually large that makes the inliner to reject the method
+ public override int GetHashCode()
{
- double d = m_value;
- if (d == 0)
+ var bits = Unsafe.As<double, long>(ref m_value);
+
+ // Optimized check for IsNan() || IsZero()
+ if (((bits - 1) & 0x7FFFFFFFFFFFFFFF) >= 0x7FF0000000000000)
{
- // Ensure that 0 and -0 have the same hash code
- return 0;
+ // Ensure that all NaNs and both zeros have the same hash code
+ bits &= 0x7FF0000000000000;
}
- long value = *(long*)(&d);
- return unchecked((int)value) ^ ((int)(value >> 32));
+
+ return unchecked((int)bits) ^ ((int)(bits >> 32));
}
public override String ToString()
@@ -340,16 +345,16 @@ namespace System
bool success = Number.TryParseDouble(s, style, info, out result);
if (!success)
{
- ReadOnlySpan<char> sTrim = StringSpanHelpers.Trim(s);
- if (StringSpanHelpers.Equals(sTrim, info.PositiveInfinitySymbol))
+ ReadOnlySpan<char> sTrim = s.Trim();
+ if (sTrim.EqualsOrdinal(info.PositiveInfinitySymbol))
{
result = PositiveInfinity;
}
- else if (StringSpanHelpers.Equals(sTrim, info.NegativeInfinitySymbol))
+ else if (sTrim.EqualsOrdinal(info.NegativeInfinitySymbol))
{
result = NegativeInfinity;
}
- else if (StringSpanHelpers.Equals(sTrim, info.NaNSymbol))
+ else if (sTrim.EqualsOrdinal(info.NaNSymbol))
{
result = NaN;
}
diff --git a/src/Common/src/CoreLib/System/Globalization/CalendarData.Unix.cs b/src/Common/src/CoreLib/System/Globalization/CalendarData.Unix.cs
index 4d1a63c23c..17d6ed7a01 100644
--- a/src/Common/src/CoreLib/System/Globalization/CalendarData.Unix.cs
+++ b/src/Common/src/CoreLib/System/Globalization/CalendarData.Unix.cs
@@ -45,10 +45,27 @@ namespace System.Globalization
result &= EnumCalendarInfo(localeName, calendarId, CalendarDataType.DayNames, out this.saDayNames);
result &= EnumCalendarInfo(localeName, calendarId, CalendarDataType.AbbrevDayNames, out this.saAbbrevDayNames);
result &= EnumCalendarInfo(localeName, calendarId, CalendarDataType.SuperShortDayNames, out this.saSuperShortDayNames);
- result &= EnumMonthNames(localeName, calendarId, CalendarDataType.MonthNames, out this.saMonthNames);
- result &= EnumMonthNames(localeName, calendarId, CalendarDataType.AbbrevMonthNames, out this.saAbbrevMonthNames);
- result &= EnumMonthNames(localeName, calendarId, CalendarDataType.MonthGenitiveNames, out this.saMonthGenitiveNames);
- result &= EnumMonthNames(localeName, calendarId, CalendarDataType.AbbrevMonthGenitiveNames, out this.saAbbrevMonthGenitiveNames);
+
+ string leapHebrewMonthName = null;
+ result &= EnumMonthNames(localeName, calendarId, CalendarDataType.MonthNames, out this.saMonthNames, ref leapHebrewMonthName);
+ if (leapHebrewMonthName != null)
+ {
+ // In Hebrew calendar, get the leap month name Adar II and override the non-leap month 7
+ Debug.Assert(calendarId == CalendarId.HEBREW && saMonthNames.Length == 13);
+ saLeapYearMonthNames = (string[]) saMonthNames.Clone();
+ saLeapYearMonthNames[6] = leapHebrewMonthName;
+
+ // The returned data from ICU has 6th month name as 'Adar I' and 7th month name as 'Adar'
+ // We need to adjust that in the list used with non-leap year to have 6th month as 'Adar' and 7th month as 'Adar II'
+ // note that when formatting non-leap year dates, 7th month shouldn't get used at all.
+ saMonthNames[5] = saMonthNames[6];
+ saMonthNames[6] = leapHebrewMonthName;
+
+ }
+ result &= EnumMonthNames(localeName, calendarId, CalendarDataType.AbbrevMonthNames, out this.saAbbrevMonthNames, ref leapHebrewMonthName);
+ result &= EnumMonthNames(localeName, calendarId, CalendarDataType.MonthGenitiveNames, out this.saMonthGenitiveNames, ref leapHebrewMonthName);
+ result &= EnumMonthNames(localeName, calendarId, CalendarDataType.AbbrevMonthGenitiveNames, out this.saAbbrevMonthGenitiveNames, ref leapHebrewMonthName);
+
result &= EnumEraNames(localeName, calendarId, CalendarDataType.EraNames, out this.saEraNames);
result &= EnumEraNames(localeName, calendarId, CalendarDataType.AbbrevEraNames, out this.saAbbrevEraNames);
@@ -68,7 +85,7 @@ namespace System.Globalization
Debug.Assert(!GlobalizationMode.Invariant);
// NOTE: there are no 'user overrides' on Linux
- int count = Interop.GlobalizationInterop.GetCalendars(localeName, calendars, calendars.Length);
+ int count = Interop.Globalization.GetCalendars(localeName, calendars, calendars.Length);
// ensure there is at least 1 calendar returned
if (count == 0 && calendars.Length > 0)
@@ -93,7 +110,7 @@ namespace System.Globalization
return Interop.CallStringMethod(
(locale, calId, type, stringBuilder) =>
- Interop.GlobalizationInterop.GetCalendarInfo(
+ Interop.Globalization.GetCalendarInfo(
locale,
calId,
type,
@@ -241,7 +258,7 @@ namespace System.Globalization
return index - startIndex;
}
- private static bool EnumMonthNames(string localeName, CalendarId calendarId, CalendarDataType dataType, out string[] monthNames)
+ private static bool EnumMonthNames(string localeName, CalendarId calendarId, CalendarDataType dataType, out string[] monthNames, ref string leapHebrewMonthName)
{
monthNames = null;
@@ -257,6 +274,17 @@ namespace System.Globalization
callbackContext.Results.Add(string.Empty);
}
+ if (callbackContext.Results.Count > 13)
+ {
+ Debug.Assert(calendarId == CalendarId.HEBREW && callbackContext.Results.Count == 14);
+
+ if (calendarId == CalendarId.HEBREW)
+ {
+ leapHebrewMonthName = callbackContext.Results[13];
+ }
+ callbackContext.Results.RemoveRange(13, callbackContext.Results.Count - 13);
+ }
+
monthNames = callbackContext.Results.ToArray();
}
@@ -295,7 +323,7 @@ namespace System.Globalization
private static unsafe bool EnumCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType dataType, ref EnumCalendarsData callbackContext)
{
- return Interop.GlobalizationInterop.EnumCalendarInfo(EnumCalendarInfoCallback, localeName, calendarId, dataType, (IntPtr)Unsafe.AsPointer(ref callbackContext));
+ return Interop.Globalization.EnumCalendarInfo(EnumCalendarInfoCallback, localeName, calendarId, dataType, (IntPtr)Unsafe.AsPointer(ref callbackContext));
}
private static unsafe void EnumCalendarInfoCallback(string calendarString, IntPtr context)
diff --git a/src/Common/src/CoreLib/System/Globalization/CompareInfo.Invariant.cs b/src/Common/src/CoreLib/System/Globalization/CompareInfo.Invariant.cs
index c47db7b0fd..69f4b4e095 100644
--- a/src/Common/src/CoreLib/System/Globalization/CompareInfo.Invariant.cs
+++ b/src/Common/src/CoreLib/System/Globalization/CompareInfo.Invariant.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Diagnostics.Private;
+using System.Runtime.InteropServices;
namespace System.Globalization
{
@@ -26,6 +27,18 @@ namespace System.Globalization
}
}
+ internal static unsafe int InvariantIndexOf(ReadOnlySpan<char> source, ReadOnlySpan<char> value, bool ignoreCase)
+ {
+ Debug.Assert(source.Length != 0);
+ Debug.Assert(value.Length != 0);
+
+ fixed (char* pSource = &MemoryMarshal.GetReference(source))
+ fixed (char* pValue = &MemoryMarshal.GetReference(value))
+ {
+ return InvariantFindString(pSource, source.Length, pValue, value.Length, ignoreCase, start: true);
+ }
+ }
+
internal static unsafe int InvariantLastIndexOf(string source, string value, int startIndex, int count, bool ignoreCase)
{
Debug.Assert(source != null);
diff --git a/src/Common/src/CoreLib/System/Globalization/CompareInfo.Unix.cs b/src/Common/src/CoreLib/System/Globalization/CompareInfo.Unix.cs
new file mode 100644
index 0000000000..5a68492c69
--- /dev/null
+++ b/src/Common/src/CoreLib/System/Globalization/CompareInfo.Unix.cs
@@ -0,0 +1,1014 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Security;
+
+namespace System.Globalization
+{
+ public partial class CompareInfo
+ {
+ [NonSerialized]
+ private Interop.Globalization.SafeSortHandle _sortHandle;
+
+ [NonSerialized]
+ private bool _isAsciiEqualityOrdinal;
+
+ private void InitSort(CultureInfo culture)
+ {
+ _sortName = culture.SortName;
+
+ if (_invariantMode)
+ {
+ _isAsciiEqualityOrdinal = true;
+ }
+ else
+ {
+ Interop.Globalization.ResultCode resultCode = Interop.Globalization.GetSortHandle(GetNullTerminatedUtf8String(_sortName), out _sortHandle);
+ if (resultCode != Interop.Globalization.ResultCode.Success)
+ {
+ _sortHandle.Dispose();
+
+ if (resultCode == Interop.Globalization.ResultCode.OutOfMemory)
+ throw new OutOfMemoryException();
+
+ throw new ExternalException(SR.Arg_ExternalException);
+ }
+ _isAsciiEqualityOrdinal = (_sortName == "en-US" || _sortName == "");
+ }
+ }
+
+ internal static unsafe int IndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase)
+ {
+ Debug.Assert(!GlobalizationMode.Invariant);
+
+ Debug.Assert(source != null);
+ Debug.Assert(value != null);
+
+ if (value.Length == 0)
+ {
+ return startIndex;
+ }
+
+ if (count < value.Length)
+ {
+ return -1;
+ }
+
+ if (ignoreCase)
+ {
+ fixed (char* pSource = source)
+ {
+ int index = Interop.Globalization.IndexOfOrdinalIgnoreCase(value, value.Length, pSource + startIndex, count, findLast: false);
+ return index != -1 ?
+ startIndex + index :
+ -1;
+ }
+ }
+
+ int endIndex = startIndex + (count - value.Length);
+ for (int i = startIndex; i <= endIndex; i++)
+ {
+ int valueIndex, sourceIndex;
+
+ for (valueIndex = 0, sourceIndex = i;
+ valueIndex < value.Length && source[sourceIndex] == value[valueIndex];
+ valueIndex++, sourceIndex++) ;
+
+ if (valueIndex == value.Length)
+ {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ internal static unsafe int IndexOfOrdinalCore(ReadOnlySpan<char> source, ReadOnlySpan<char> value, bool ignoreCase)
+ {
+ Debug.Assert(!GlobalizationMode.Invariant);
+
+ Debug.Assert(source.Length != 0);
+ Debug.Assert(value.Length != 0);
+
+ if (source.Length < value.Length)
+ {
+ return -1;
+ }
+
+ if (ignoreCase)
+ {
+ fixed (char* pSource = &MemoryMarshal.GetReference(source))
+ fixed (char* pValue = &MemoryMarshal.GetReference(value))
+ {
+ int index = Interop.Globalization.IndexOfOrdinalIgnoreCase(pValue, value.Length, pSource, source.Length, findLast: false);
+ return index;
+ }
+ }
+
+ int endIndex = source.Length - value.Length;
+ for (int i = 0; i <= endIndex; i++)
+ {
+ int valueIndex, sourceIndex;
+
+ for (valueIndex = 0, sourceIndex = i;
+ valueIndex < value.Length && source[sourceIndex] == value[valueIndex];
+ valueIndex++, sourceIndex++)
+ ;
+
+ if (valueIndex == value.Length)
+ {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ internal static unsafe int LastIndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase)
+ {
+ Debug.Assert(!GlobalizationMode.Invariant);
+
+ Debug.Assert(source != null);
+ Debug.Assert(value != null);
+
+ if (value.Length == 0)
+ {
+ return startIndex;
+ }
+
+ if (count < value.Length)
+ {
+ return -1;
+ }
+
+ // startIndex is the index into source where we start search backwards from.
+ // leftStartIndex is the index into source of the start of the string that is
+ // count characters away from startIndex.
+ int leftStartIndex = startIndex - count + 1;
+
+ if (ignoreCase)
+ {
+ fixed (char* pSource = source)
+ {
+ int lastIndex = Interop.Globalization.IndexOfOrdinalIgnoreCase(value, value.Length, pSource + leftStartIndex, count, findLast: true);
+ return lastIndex != -1 ?
+ leftStartIndex + lastIndex :
+ -1;
+ }
+ }
+
+ for (int i = startIndex - value.Length + 1; i >= leftStartIndex; i--)
+ {
+ int valueIndex, sourceIndex;
+
+ for (valueIndex = 0, sourceIndex = i;
+ valueIndex < value.Length && source[sourceIndex] == value[valueIndex];
+ valueIndex++, sourceIndex++) ;
+
+ if (valueIndex == value.Length) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ private static unsafe int CompareStringOrdinalIgnoreCase(char* string1, int count1, char* string2, int count2)
+ {
+ Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(string1 != null);
+ Debug.Assert(string2 != null);
+
+ return Interop.Globalization.CompareStringOrdinalIgnoreCase(string1, count1, string2, count2);
+ }
+
+ // TODO https://github.com/dotnet/coreclr/issues/13827:
+ // This method shouldn't be necessary, as we should be able to just use the overload
+ // that takes two spans. But due to this issue, that's adding significant overhead.
+ private unsafe int CompareString(ReadOnlySpan<char> string1, string string2, CompareOptions options)
+ {
+ Debug.Assert(!_invariantMode);
+ Debug.Assert(string2 != null);
+ Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ fixed (char* pString1 = &MemoryMarshal.GetReference(string1))
+ fixed (char* pString2 = &string2.GetRawStringData())
+ {
+ return Interop.Globalization.CompareString(_sortHandle, pString1, string1.Length, pString2, string2.Length, options);
+ }
+ }
+
+ private unsafe int CompareString(ReadOnlySpan<char> string1, ReadOnlySpan<char> string2, CompareOptions options)
+ {
+ Debug.Assert(!_invariantMode);
+ Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ fixed (char* pString1 = &MemoryMarshal.GetReference(string1))
+ fixed (char* pString2 = &MemoryMarshal.GetReference(string2))
+ {
+ return Interop.Globalization.CompareString(_sortHandle, pString1, string1.Length, pString2, string2.Length, options);
+ }
+ }
+
+ internal unsafe int IndexOfCore(string source, string target, int startIndex, int count, CompareOptions options, int* matchLengthPtr)
+ {
+ Debug.Assert(!_invariantMode);
+
+ Debug.Assert(!string.IsNullOrEmpty(source));
+ Debug.Assert(target != null);
+ Debug.Assert((options & CompareOptions.OrdinalIgnoreCase) == 0);
+
+ int index;
+
+ if (target.Length == 0)
+ {
+ if (matchLengthPtr != null)
+ *matchLengthPtr = 0;
+ return startIndex;
+ }
+
+ if (options == CompareOptions.Ordinal)
+ {
+ index = IndexOfOrdinal(source, target, startIndex, count, ignoreCase: false);
+ if (index != -1)
+ {
+ if (matchLengthPtr != null)
+ *matchLengthPtr = target.Length;
+ }
+ return index;
+ }
+
+#if CORECLR
+ if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options) && source.IsFastSort() && target.IsFastSort())
+ {
+ index = IndexOf(source, target, startIndex, count, GetOrdinalCompareOptions(options));
+ if (index != -1)
+ {
+ if (matchLengthPtr != null)
+ *matchLengthPtr = target.Length;
+ }
+ return index;
+ }
+#endif
+
+ fixed (char* pSource = source)
+ {
+ index = Interop.Globalization.IndexOf(_sortHandle, target, target.Length, pSource + startIndex, count, options, matchLengthPtr);
+
+ return index != -1 ? index + startIndex : -1;
+ }
+ }
+
+ // For now, this method is only called from Span APIs with either options == CompareOptions.None or CompareOptions.IgnoreCase
+ internal unsafe int IndexOfCore(ReadOnlySpan<char> source, ReadOnlySpan<char> target, CompareOptions options, int* matchLengthPtr)
+ {
+ Debug.Assert(!_invariantMode);
+ Debug.Assert(source.Length != 0);
+ Debug.Assert(target.Length != 0);
+
+ if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options))
+ {
+ if ((options & CompareOptions.IgnoreCase) == CompareOptions.IgnoreCase)
+ {
+ return IndexOfOrdinalIgnoreCaseHelper(source, target, options, matchLengthPtr);
+ }
+ else
+ {
+ return IndexOfOrdinalHelper(source, target, options, matchLengthPtr);
+ }
+ }
+ else
+ {
+ fixed (char* pSource = &MemoryMarshal.GetReference(source))
+ fixed (char* pTarget = &MemoryMarshal.GetReference(target))
+ {
+ return Interop.Globalization.IndexOf(_sortHandle, pTarget, target.Length, pSource, source.Length, options, matchLengthPtr);
+ }
+ }
+ }
+
+ private unsafe int IndexOfOrdinalIgnoreCaseHelper(ReadOnlySpan<char> source, ReadOnlySpan<char> target, CompareOptions options, int* matchLengthPtr)
+ {
+ Debug.Assert(!_invariantMode);
+
+ Debug.Assert(!source.IsEmpty);
+ Debug.Assert(!target.IsEmpty);
+ Debug.Assert(_isAsciiEqualityOrdinal);
+
+ fixed (char* ap = &MemoryMarshal.GetReference(source))
+ fixed (char* bp = &MemoryMarshal.GetReference(target))
+ {
+ char* a = ap;
+ char* b = bp;
+ int endIndex = source.Length - target.Length;
+
+ if (endIndex < 0)
+ goto InteropCall;
+
+ for (int j = 0; j < target.Length; j++)
+ {
+ char targetChar = *(b + j);
+ if (targetChar >= 0x80 || s_highCharTable[targetChar])
+ goto InteropCall;
+ }
+
+ int i = 0;
+ for (; i <= endIndex; i++)
+ {
+ int targetIndex = 0;
+ int sourceIndex = i;
+
+ for (; targetIndex < target.Length; targetIndex++)
+ {
+ char valueChar = *(a + sourceIndex);
+ char targetChar = *(b + targetIndex);
+
+ if (valueChar == targetChar && valueChar < 0x80 && !s_highCharTable[valueChar])
+ {
+ sourceIndex++;
+ continue;
+ }
+
+ // uppercase both chars - notice that we need just one compare per char
+ if ((uint)(valueChar - 'a') <= ('z' - 'a'))
+ valueChar = (char)(valueChar - 0x20);
+ if ((uint)(targetChar - 'a') <= ('z' - 'a'))
+ targetChar = (char)(targetChar - 0x20);
+
+ if (valueChar >= 0x80 || s_highCharTable[valueChar])
+ goto InteropCall;
+ else if (valueChar != targetChar)
+ break;
+ sourceIndex++;
+ }
+
+ if (targetIndex == target.Length)
+ {
+ if (matchLengthPtr != null)
+ *matchLengthPtr = target.Length;
+ return i;
+ }
+ }
+ if (i > endIndex)
+ return -1;
+ InteropCall:
+ return Interop.Globalization.IndexOf(_sortHandle, b, target.Length, a, source.Length, options, matchLengthPtr);
+ }
+ }
+
+ private unsafe int IndexOfOrdinalHelper(ReadOnlySpan<char> source, ReadOnlySpan<char> target, CompareOptions options, int* matchLengthPtr)
+ {
+ Debug.Assert(!_invariantMode);
+
+ Debug.Assert(!source.IsEmpty);
+ Debug.Assert(!target.IsEmpty);
+ Debug.Assert(_isAsciiEqualityOrdinal);
+
+ fixed (char* ap = &MemoryMarshal.GetReference(source))
+ fixed (char* bp = &MemoryMarshal.GetReference(target))
+ {
+ char* a = ap;
+ char* b = bp;
+ int endIndex = source.Length - target.Length;
+
+ if (endIndex < 0)
+ goto InteropCall;
+
+ for (int j = 0; j < target.Length; j++)
+ {
+ char targetChar = *(b + j);
+ if (targetChar >= 0x80 || s_highCharTable[targetChar])
+ goto InteropCall;
+ }
+
+ int i = 0;
+ for (; i <= endIndex; i++)
+ {
+ int targetIndex = 0;
+ int sourceIndex = i;
+
+ for (; targetIndex < target.Length; targetIndex++)
+ {
+ char valueChar = *(a + sourceIndex);
+ char targetChar = *(b + targetIndex);
+ if (valueChar >= 0x80 || s_highCharTable[valueChar])
+ goto InteropCall;
+ else if (valueChar != targetChar)
+ break;
+ sourceIndex++;
+ }
+
+ if (targetIndex == target.Length)
+ {
+ if (matchLengthPtr != null)
+ *matchLengthPtr = target.Length;
+ return i;
+ }
+ }
+ if (i > endIndex)
+ return -1;
+ InteropCall:
+ return Interop.Globalization.IndexOf(_sortHandle, b, target.Length, a, source.Length, options, matchLengthPtr);
+ }
+ }
+
+ private unsafe int LastIndexOfCore(string source, string target, int startIndex, int count, CompareOptions options)
+ {
+ Debug.Assert(!_invariantMode);
+
+ Debug.Assert(!string.IsNullOrEmpty(source));
+ Debug.Assert(target != null);
+ Debug.Assert((options & CompareOptions.OrdinalIgnoreCase) == 0);
+
+ if (target.Length == 0)
+ {
+ return startIndex;
+ }
+
+ if (options == CompareOptions.Ordinal)
+ {
+ return LastIndexOfOrdinalCore(source, target, startIndex, count, ignoreCase: false);
+ }
+
+#if CORECLR
+ if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options) && source.IsFastSort() && target.IsFastSort())
+ {
+ return LastIndexOf(source, target, startIndex, count, GetOrdinalCompareOptions(options));
+ }
+#endif
+
+ // startIndex is the index into source where we start search backwards from. leftStartIndex is the index into source
+ // of the start of the string that is count characters away from startIndex.
+ int leftStartIndex = (startIndex - count + 1);
+
+ fixed (char* pSource = source)
+ {
+ int lastIndex = Interop.Globalization.LastIndexOf(_sortHandle, target, target.Length, pSource + (startIndex - count + 1), count, options);
+
+ return lastIndex != -1 ? lastIndex + leftStartIndex : -1;
+ }
+ }
+
+ private bool StartsWith(string source, string prefix, CompareOptions options)
+ {
+ Debug.Assert(!_invariantMode);
+
+ Debug.Assert(!string.IsNullOrEmpty(source));
+ Debug.Assert(!string.IsNullOrEmpty(prefix));
+ Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+#if CORECLR
+ if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options) && source.IsFastSort() && prefix.IsFastSort())
+ {
+ return IsPrefix(source, prefix, GetOrdinalCompareOptions(options));
+ }
+#endif
+
+ return Interop.Globalization.StartsWith(_sortHandle, prefix, prefix.Length, source, source.Length, options);
+ }
+
+ private unsafe bool StartsWith(ReadOnlySpan<char> source, ReadOnlySpan<char> prefix, CompareOptions options)
+ {
+ Debug.Assert(!_invariantMode);
+
+ Debug.Assert(!source.IsEmpty);
+ Debug.Assert(!prefix.IsEmpty);
+ Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options))
+ {
+ if (source.Length < prefix.Length)
+ {
+ return false;
+ }
+
+ if ((options & CompareOptions.IgnoreCase) == CompareOptions.IgnoreCase)
+ {
+ return StartsWithOrdinalIgnoreCaseHelper(source, prefix, options);
+ }
+ else
+ {
+ return StartsWithOrdinalHelper(source, prefix, options);
+ }
+ }
+ else
+ {
+ fixed (char* pSource = &MemoryMarshal.GetReference(source))
+ fixed (char* pPrefix = &MemoryMarshal.GetReference(prefix))
+ {
+ return Interop.Globalization.StartsWith(_sortHandle, pPrefix, prefix.Length, pSource, source.Length, options);
+ }
+ }
+ }
+
+ private unsafe bool StartsWithOrdinalIgnoreCaseHelper(ReadOnlySpan<char> source, ReadOnlySpan<char> prefix, CompareOptions options)
+ {
+ Debug.Assert(!_invariantMode);
+
+ Debug.Assert(!source.IsEmpty);
+ Debug.Assert(!prefix.IsEmpty);
+ Debug.Assert(_isAsciiEqualityOrdinal);
+ Debug.Assert(source.Length >= prefix.Length);
+
+ int length = prefix.Length;
+
+ fixed (char* ap = &MemoryMarshal.GetReference(source))
+ fixed (char* bp = &MemoryMarshal.GetReference(prefix))
+ {
+ char* a = ap;
+ char* b = bp;
+
+ while (length != 0 && (*a < 0x80) && (*b < 0x80) && (!s_highCharTable[*a]) && (!s_highCharTable[*b]))
+ {
+ int charA = *a;
+ int charB = *b;
+
+ if (charA == charB)
+ {
+ a++; b++;
+ length--;
+ continue;
+ }
+
+ // uppercase both chars - notice that we need just one compare per char
+ if ((uint)(charA - 'a') <= (uint)('z' - 'a')) charA -= 0x20;
+ if ((uint)(charB - 'a') <= (uint)('z' - 'a')) charB -= 0x20;
+
+ if (charA != charB)
+ return false;
+
+ // Next char
+ a++; b++;
+ length--;
+ }
+
+ if (length == 0) return true;
+ return Interop.Globalization.StartsWith(_sortHandle, b, length, a, length, options);
+ }
+ }
+
+ private unsafe bool StartsWithOrdinalHelper(ReadOnlySpan<char> source, ReadOnlySpan<char> prefix, CompareOptions options)
+ {
+ Debug.Assert(!_invariantMode);
+
+ Debug.Assert(!source.IsEmpty);
+ Debug.Assert(!prefix.IsEmpty);
+ Debug.Assert(_isAsciiEqualityOrdinal);
+ Debug.Assert(source.Length >= prefix.Length);
+
+ int length = prefix.Length;
+
+ fixed (char* ap = &MemoryMarshal.GetReference(source))
+ fixed (char* bp = &MemoryMarshal.GetReference(prefix))
+ {
+ char* a = ap;
+ char* b = bp;
+
+ while (length != 0 && (*a < 0x80) && (*b < 0x80) && (!s_highCharTable[*a]) && (!s_highCharTable[*b]))
+ {
+ int charA = *a;
+ int charB = *b;
+
+ if (charA != charB)
+ return false;
+
+ // Next char
+ a++; b++;
+ length--;
+ }
+
+ if (length == 0) return true;
+ return Interop.Globalization.StartsWith(_sortHandle, b, length, a, length, options);
+ }
+ }
+
+ private bool EndsWith(string source, string suffix, CompareOptions options)
+ {
+ Debug.Assert(!_invariantMode);
+
+ Debug.Assert(!string.IsNullOrEmpty(source));
+ Debug.Assert(!string.IsNullOrEmpty(suffix));
+ Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+#if CORECLR
+ if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options) && source.IsFastSort() && suffix.IsFastSort())
+ {
+ return IsSuffix(source, suffix, GetOrdinalCompareOptions(options));
+ }
+#endif
+
+ return Interop.Globalization.EndsWith(_sortHandle, suffix, suffix.Length, source, source.Length, options);
+ }
+
+ private unsafe bool EndsWith(ReadOnlySpan<char> source, ReadOnlySpan<char> suffix, CompareOptions options)
+ {
+ Debug.Assert(!_invariantMode);
+
+ Debug.Assert(!source.IsEmpty);
+ Debug.Assert(!suffix.IsEmpty);
+ Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options))
+ {
+ if (source.Length < suffix.Length)
+ {
+ return false;
+ }
+
+ if ((options & CompareOptions.IgnoreCase) == CompareOptions.IgnoreCase)
+ {
+ return EndsWithOrdinalIgnoreCaseHelper(source, suffix, options);
+ }
+ else
+ {
+ return EndsWithOrdinalHelper(source, suffix, options);
+ }
+ }
+ else
+ {
+ fixed (char* pSource = &MemoryMarshal.GetReference(source))
+ fixed (char* pSuffix = &MemoryMarshal.GetReference(suffix))
+ {
+ return Interop.Globalization.EndsWith(_sortHandle, pSuffix, suffix.Length, pSource, source.Length, options);
+ }
+ }
+ }
+
+ private unsafe bool EndsWithOrdinalIgnoreCaseHelper(ReadOnlySpan<char> source, ReadOnlySpan<char> suffix, CompareOptions options)
+ {
+ Debug.Assert(!_invariantMode);
+
+ Debug.Assert(!source.IsEmpty);
+ Debug.Assert(!suffix.IsEmpty);
+ Debug.Assert(_isAsciiEqualityOrdinal);
+ Debug.Assert(source.Length >= suffix.Length);
+
+ int length = suffix.Length;
+
+ fixed (char* ap = &MemoryMarshal.GetReference(source))
+ fixed (char* bp = &MemoryMarshal.GetReference(suffix))
+ {
+ char* a = ap + source.Length - 1;
+ char* b = bp + suffix.Length - 1;
+
+ while (length != 0 && (*a < 0x80) && (*b < 0x80) && (!s_highCharTable[*a]) && (!s_highCharTable[*b]))
+ {
+ int charA = *a;
+ int charB = *b;
+
+ if (charA == charB)
+ {
+ a--; b--;
+ length--;
+ continue;
+ }
+
+ // uppercase both chars - notice that we need just one compare per char
+ if ((uint)(charA - 'a') <= (uint)('z' - 'a')) charA -= 0x20;
+ if ((uint)(charB - 'a') <= (uint)('z' - 'a')) charB -= 0x20;
+
+ if (charA != charB)
+ return false;
+
+ // Next char
+ a--; b--;
+ length--;
+ }
+
+ if (length == 0) return true;
+ return Interop.Globalization.EndsWith(_sortHandle, b - length + 1, length, a - length + 1, length, options);
+ }
+ }
+
+ private unsafe bool EndsWithOrdinalHelper(ReadOnlySpan<char> source, ReadOnlySpan<char> suffix, CompareOptions options)
+ {
+ Debug.Assert(!_invariantMode);
+
+ Debug.Assert(!source.IsEmpty);
+ Debug.Assert(!suffix.IsEmpty);
+ Debug.Assert(_isAsciiEqualityOrdinal);
+ Debug.Assert(source.Length >= suffix.Length);
+
+ int length = suffix.Length;
+
+ fixed (char* ap = &MemoryMarshal.GetReference(source))
+ fixed (char* bp = &MemoryMarshal.GetReference(suffix))
+ {
+ char* a = ap + source.Length - 1;
+ char* b = bp + suffix.Length - 1;
+
+ while (length != 0 && (*a < 0x80) && (*b < 0x80) && (!s_highCharTable[*a]) && (!s_highCharTable[*b]))
+ {
+ int charA = *a;
+ int charB = *b;
+
+ if (charA != charB)
+ return false;
+
+ // Next char
+ a--; b--;
+ length--;
+ }
+
+ if (length == 0) return true;
+ return Interop.Globalization.EndsWith(_sortHandle, b - length + 1, length, a - length + 1, length, options);
+ }
+ }
+
+ private unsafe SortKey CreateSortKey(String source, CompareOptions options)
+ {
+ Debug.Assert(!_invariantMode);
+
+ if (source==null) { throw new ArgumentNullException(nameof(source)); }
+
+ if ((options & ValidSortkeyCtorMaskOffFlags) != 0)
+ {
+ throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options));
+ }
+
+ byte [] keyData;
+ if (source.Length == 0)
+ {
+ keyData = Array.Empty<Byte>();
+ }
+ else
+ {
+ int sortKeyLength = Interop.Globalization.GetSortKey(_sortHandle, source, source.Length, null, 0, options);
+ keyData = new byte[sortKeyLength];
+
+ fixed (byte* pSortKey = keyData)
+ {
+ if (Interop.Globalization.GetSortKey(_sortHandle, source, source.Length, pSortKey, sortKeyLength, options) != sortKeyLength)
+ {
+ throw new ArgumentException(SR.Arg_ExternalException);
+ }
+ }
+ }
+
+ return new SortKey(Name, source, options, keyData);
+ }
+
+ private static unsafe bool IsSortable(char *text, int length)
+ {
+ Debug.Assert(!GlobalizationMode.Invariant);
+
+ int index = 0;
+ UnicodeCategory uc;
+
+ while (index < length)
+ {
+ if (Char.IsHighSurrogate(text[index]))
+ {
+ if (index == length - 1 || !Char.IsLowSurrogate(text[index+1]))
+ return false; // unpaired surrogate
+
+ uc = CharUnicodeInfo.GetUnicodeCategory(Char.ConvertToUtf32(text[index], text[index+1]));
+ if (uc == UnicodeCategory.PrivateUse || uc == UnicodeCategory.OtherNotAssigned)
+ return false;
+
+ index += 2;
+ continue;
+ }
+
+ if (Char.IsLowSurrogate(text[index]))
+ {
+ return false; // unpaired surrogate
+ }
+
+ uc = CharUnicodeInfo.GetUnicodeCategory(text[index]);
+ if (uc == UnicodeCategory.PrivateUse || uc == UnicodeCategory.OtherNotAssigned)
+ {
+ return false;
+ }
+
+ index++;
+ }
+
+ return true;
+ }
+
+ // -----------------------------
+ // ---- PAL layer ends here ----
+ // -----------------------------
+
+ internal unsafe int GetHashCodeOfStringCore(string source, CompareOptions options)
+ {
+ Debug.Assert(!_invariantMode);
+
+ Debug.Assert(source != null);
+ Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ if (source.Length == 0)
+ {
+ return 0;
+ }
+
+ int sortKeyLength = Interop.Globalization.GetSortKey(_sortHandle, source, source.Length, null, 0, options);
+
+ byte[] borrowedArr = null;
+ Span<byte> span = sortKeyLength <= 512 ?
+ stackalloc byte[512] :
+ (borrowedArr = ArrayPool<byte>.Shared.Rent(sortKeyLength));
+
+ fixed (byte* pSortKey = &MemoryMarshal.GetReference(span))
+ {
+ if (Interop.Globalization.GetSortKey(_sortHandle, source, source.Length, pSortKey, sortKeyLength, options) != sortKeyLength)
+ {
+ throw new ArgumentException(SR.Arg_ExternalException);
+ }
+ }
+
+ int hash = Marvin.ComputeHash32(span.Slice(0, sortKeyLength), Marvin.DefaultSeed);
+
+ // Return the borrowed array if necessary.
+ if (borrowedArr != null)
+ {
+ ArrayPool<byte>.Shared.Return(borrowedArr);
+ }
+
+ return hash;
+ }
+
+ private static CompareOptions GetOrdinalCompareOptions(CompareOptions options)
+ {
+ if ((options & CompareOptions.IgnoreCase) == CompareOptions.IgnoreCase)
+ {
+ return CompareOptions.OrdinalIgnoreCase;
+ }
+ else
+ {
+ return CompareOptions.Ordinal;
+ }
+ }
+
+ private static bool CanUseAsciiOrdinalForOptions(CompareOptions options)
+ {
+ // Unlike the other Ignore options, IgnoreSymbols impacts ASCII characters (e.g. ').
+ return (options & CompareOptions.IgnoreSymbols) == 0;
+ }
+
+ private static byte[] GetNullTerminatedUtf8String(string s)
+ {
+ int byteLen = System.Text.Encoding.UTF8.GetByteCount(s);
+
+ // Allocate an extra byte (which defaults to 0) as the null terminator.
+ byte[] buffer = new byte[byteLen + 1];
+
+ int bytesWritten = System.Text.Encoding.UTF8.GetBytes(s, 0, s.Length, buffer, 0);
+
+ Debug.Assert(bytesWritten == byteLen);
+
+ return buffer;
+ }
+
+ private SortVersion GetSortVersion()
+ {
+ Debug.Assert(!_invariantMode);
+
+ int sortVersion = Interop.Globalization.GetSortVersion(_sortHandle);
+ return new SortVersion(sortVersion, LCID, new Guid(sortVersion, 0, 0, 0, 0, 0, 0,
+ (byte) (LCID >> 24),
+ (byte) ((LCID & 0x00FF0000) >> 16),
+ (byte) ((LCID & 0x0000FF00) >> 8),
+ (byte) (LCID & 0xFF)));
+ }
+
+ // See https://github.com/dotnet/coreclr/blob/master/src/utilcode/util_nodependencies.cpp#L970
+ private static readonly bool[] s_highCharTable = new bool[0x80]
+ {
+ true, /* 0x0, 0x0 */
+ true, /* 0x1, .*/
+ true, /* 0x2, .*/
+ true, /* 0x3, .*/
+ true, /* 0x4, .*/
+ true, /* 0x5, .*/
+ true, /* 0x6, .*/
+ true, /* 0x7, .*/
+ true, /* 0x8, .*/
+ false, /* 0x9, */
+ true, /* 0xA, */
+ false, /* 0xB, .*/
+ false, /* 0xC, .*/
+ true, /* 0xD, */
+ true, /* 0xE, .*/
+ true, /* 0xF, .*/
+ true, /* 0x10, .*/
+ true, /* 0x11, .*/
+ true, /* 0x12, .*/
+ true, /* 0x13, .*/
+ true, /* 0x14, .*/
+ true, /* 0x15, .*/
+ true, /* 0x16, .*/
+ true, /* 0x17, .*/
+ true, /* 0x18, .*/
+ true, /* 0x19, .*/
+ true, /* 0x1A, */
+ true, /* 0x1B, .*/
+ true, /* 0x1C, .*/
+ true, /* 0x1D, .*/
+ true, /* 0x1E, .*/
+ true, /* 0x1F, .*/
+ false, /*0x20, */
+ false, /*0x21, !*/
+ false, /*0x22, "*/
+ false, /*0x23, #*/
+ false, /*0x24, $*/
+ false, /*0x25, %*/
+ false, /*0x26, &*/
+ true, /*0x27, '*/
+ false, /*0x28, (*/
+ false, /*0x29, )*/
+ false, /*0x2A **/
+ false, /*0x2B, +*/
+ false, /*0x2C, ,*/
+ true, /*0x2D, -*/
+ false, /*0x2E, .*/
+ false, /*0x2F, /*/
+ false, /*0x30, 0*/
+ false, /*0x31, 1*/
+ false, /*0x32, 2*/
+ false, /*0x33, 3*/
+ false, /*0x34, 4*/
+ false, /*0x35, 5*/
+ false, /*0x36, 6*/
+ false, /*0x37, 7*/
+ false, /*0x38, 8*/
+ false, /*0x39, 9*/
+ false, /*0x3A, :*/
+ false, /*0x3B, ;*/
+ false, /*0x3C, <*/
+ false, /*0x3D, =*/
+ false, /*0x3E, >*/
+ false, /*0x3F, ?*/
+ false, /*0x40, @*/
+ false, /*0x41, A*/
+ false, /*0x42, B*/
+ false, /*0x43, C*/
+ false, /*0x44, D*/
+ false, /*0x45, E*/
+ false, /*0x46, F*/
+ false, /*0x47, G*/
+ false, /*0x48, H*/
+ false, /*0x49, I*/
+ false, /*0x4A, J*/
+ false, /*0x4B, K*/
+ false, /*0x4C, L*/
+ false, /*0x4D, M*/
+ false, /*0x4E, N*/
+ false, /*0x4F, O*/
+ false, /*0x50, P*/
+ false, /*0x51, Q*/
+ false, /*0x52, R*/
+ false, /*0x53, S*/
+ false, /*0x54, T*/
+ false, /*0x55, U*/
+ false, /*0x56, V*/
+ false, /*0x57, W*/
+ false, /*0x58, X*/
+ false, /*0x59, Y*/
+ false, /*0x5A, Z*/
+ false, /*0x5B, [*/
+ false, /*0x5C, \*/
+ false, /*0x5D, ]*/
+ false, /*0x5E, ^*/
+ false, /*0x5F, _*/
+ false, /*0x60, `*/
+ false, /*0x61, a*/
+ false, /*0x62, b*/
+ false, /*0x63, c*/
+ false, /*0x64, d*/
+ false, /*0x65, e*/
+ false, /*0x66, f*/
+ false, /*0x67, g*/
+ false, /*0x68, h*/
+ false, /*0x69, i*/
+ false, /*0x6A, j*/
+ false, /*0x6B, k*/
+ false, /*0x6C, l*/
+ false, /*0x6D, m*/
+ false, /*0x6E, n*/
+ false, /*0x6F, o*/
+ false, /*0x70, p*/
+ false, /*0x71, q*/
+ false, /*0x72, r*/
+ false, /*0x73, s*/
+ false, /*0x74, t*/
+ false, /*0x75, u*/
+ false, /*0x76, v*/
+ false, /*0x77, w*/
+ false, /*0x78, x*/
+ false, /*0x79, y*/
+ false, /*0x7A, z*/
+ false, /*0x7B, {*/
+ false, /*0x7C, |*/
+ false, /*0x7D, }*/
+ false, /*0x7E, ~*/
+ true, /*0x7F, */
+ };
+ }
+}
diff --git a/src/Common/src/CoreLib/System/Globalization/CompareInfo.Windows.cs b/src/Common/src/CoreLib/System/Globalization/CompareInfo.Windows.cs
new file mode 100644
index 0000000000..37ed9469d9
--- /dev/null
+++ b/src/Common/src/CoreLib/System/Globalization/CompareInfo.Windows.cs
@@ -0,0 +1,644 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Diagnostics;
+using System.Security;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace System.Globalization
+{
+ public partial class CompareInfo
+ {
+ private unsafe void InitSort(CultureInfo culture)
+ {
+ _sortName = culture.SortName;
+
+ if (_invariantMode)
+ {
+ _sortHandle = IntPtr.Zero;
+ }
+ else
+ {
+ const uint LCMAP_SORTHANDLE = 0x20000000;
+
+ IntPtr handle;
+ int ret = Interop.Kernel32.LCMapStringEx(_sortName, LCMAP_SORTHANDLE, null, 0, &handle, IntPtr.Size, null, null, IntPtr.Zero);
+ _sortHandle = ret > 0 ? handle : IntPtr.Zero;
+ }
+ }
+
+ private static unsafe int FindStringOrdinal(
+ uint dwFindStringOrdinalFlags,
+ string stringSource,
+ int offset,
+ int cchSource,
+ string value,
+ int cchValue,
+ bool bIgnoreCase)
+ {
+ Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(stringSource != null);
+ Debug.Assert(value != null);
+
+ fixed (char* pSource = stringSource)
+ fixed (char* pValue = value)
+ {
+ int ret = Interop.Kernel32.FindStringOrdinal(
+ dwFindStringOrdinalFlags,
+ pSource + offset,
+ cchSource,
+ pValue,
+ cchValue,
+ bIgnoreCase ? 1 : 0);
+ return ret < 0 ? ret : ret + offset;
+ }
+ }
+
+ private static unsafe int FindStringOrdinal(
+ uint dwFindStringOrdinalFlags,
+ ReadOnlySpan<char> source,
+ ReadOnlySpan<char> value,
+ bool bIgnoreCase)
+ {
+ Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!source.IsEmpty);
+ Debug.Assert(!value.IsEmpty);
+
+ fixed (char* pSource = &MemoryMarshal.GetReference(source))
+ fixed (char* pValue = &MemoryMarshal.GetReference(value))
+ {
+ int ret = Interop.Kernel32.FindStringOrdinal(
+ dwFindStringOrdinalFlags,
+ pSource,
+ source.Length,
+ pValue,
+ value.Length,
+ bIgnoreCase ? 1 : 0);
+ return ret;
+ }
+ }
+
+ internal static int IndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase)
+ {
+ Debug.Assert(!GlobalizationMode.Invariant);
+
+ Debug.Assert(source != null);
+ Debug.Assert(value != null);
+
+ return FindStringOrdinal(FIND_FROMSTART, source, startIndex, count, value, value.Length, ignoreCase);
+ }
+
+ internal static int IndexOfOrdinalCore(ReadOnlySpan<char> source, ReadOnlySpan<char> value, bool ignoreCase)
+ {
+ Debug.Assert(!GlobalizationMode.Invariant);
+
+ Debug.Assert(source.Length != 0);
+ Debug.Assert(value.Length != 0);
+
+ return FindStringOrdinal(FIND_FROMSTART, source, value, ignoreCase);
+ }
+
+ internal static int LastIndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase)
+ {
+ Debug.Assert(!GlobalizationMode.Invariant);
+
+ Debug.Assert(source != null);
+ Debug.Assert(value != null);
+
+ return FindStringOrdinal(FIND_FROMEND, source, startIndex - count + 1, count, value, value.Length, ignoreCase);
+ }
+
+ private unsafe int GetHashCodeOfStringCore(string source, CompareOptions options)
+ {
+ Debug.Assert(!_invariantMode);
+
+ Debug.Assert(source != null);
+ Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ if (source.Length == 0)
+ {
+ return 0;
+ }
+
+ uint flags = LCMAP_SORTKEY | (uint)GetNativeCompareFlags(options);
+
+ fixed (char* pSource = source)
+ {
+ int sortKeyLength = Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _sortName,
+ flags,
+ pSource, source.Length,
+ null, 0,
+ null, null, _sortHandle);
+ if (sortKeyLength == 0)
+ {
+ throw new ArgumentException(SR.Arg_ExternalException);
+ }
+
+ byte[] borrowedArr = null;
+ Span<byte> span = sortKeyLength <= 512 ?
+ stackalloc byte[512] :
+ (borrowedArr = ArrayPool<byte>.Shared.Rent(sortKeyLength));
+
+ fixed (byte* pSortKey = &MemoryMarshal.GetReference(span))
+ {
+ if (Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _sortName,
+ flags,
+ pSource, source.Length,
+ pSortKey, sortKeyLength,
+ null, null, _sortHandle) != sortKeyLength)
+ {
+ throw new ArgumentException(SR.Arg_ExternalException);
+ }
+ }
+
+ int hash = Marvin.ComputeHash32(span.Slice(0, sortKeyLength), Marvin.DefaultSeed);
+
+ // Return the borrowed array if necessary.
+ if (borrowedArr != null)
+ {
+ ArrayPool<byte>.Shared.Return(borrowedArr);
+ }
+
+ return hash;
+ }
+ }
+
+ private static unsafe int CompareStringOrdinalIgnoreCase(char* string1, int count1, char* string2, int count2)
+ {
+ Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(string1 != null);
+ Debug.Assert(string2 != null);
+
+ // Use the OS to compare and then convert the result to expected value by subtracting 2
+ return Interop.Kernel32.CompareStringOrdinal(string1, count1, string2, count2, true) - 2;
+ }
+
+ // TODO https://github.com/dotnet/coreclr/issues/13827:
+ // This method shouldn't be necessary, as we should be able to just use the overload
+ // that takes two spans. But due to this issue, that's adding significant overhead.
+ private unsafe int CompareString(ReadOnlySpan<char> string1, string string2, CompareOptions options)
+ {
+ Debug.Assert(string2 != null);
+ Debug.Assert(!_invariantMode);
+ Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ string localeName = _sortHandle != IntPtr.Zero ? null : _sortName;
+
+ fixed (char* pLocaleName = localeName)
+ fixed (char* pString1 = &MemoryMarshal.GetReference(string1))
+ fixed (char* pString2 = &string2.GetRawStringData())
+ {
+ Debug.Assert(pString1 != null);
+ int result = Interop.Kernel32.CompareStringEx(
+ pLocaleName,
+ (uint)GetNativeCompareFlags(options),
+ pString1,
+ string1.Length,
+ pString2,
+ string2.Length,
+ null,
+ null,
+ _sortHandle);
+
+ if (result == 0)
+ {
+ throw new ArgumentException(SR.Arg_ExternalException);
+ }
+
+ // Map CompareStringEx return value to -1, 0, 1.
+ return result - 2;
+ }
+ }
+
+ private unsafe int CompareString(ReadOnlySpan<char> string1, ReadOnlySpan<char> string2, CompareOptions options)
+ {
+ Debug.Assert(!_invariantMode);
+ Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ string localeName = _sortHandle != IntPtr.Zero ? null : _sortName;
+
+ fixed (char* pLocaleName = localeName)
+ fixed (char* pString1 = &MemoryMarshal.GetReference(string1))
+ fixed (char* pString2 = &MemoryMarshal.GetReference(string2))
+ {
+ Debug.Assert(pString1 != null);
+ Debug.Assert(pString2 != null);
+ int result = Interop.Kernel32.CompareStringEx(
+ pLocaleName,
+ (uint)GetNativeCompareFlags(options),
+ pString1,
+ string1.Length,
+ pString2,
+ string2.Length,
+ null,
+ null,
+ _sortHandle);
+
+ if (result == 0)
+ {
+ throw new ArgumentException(SR.Arg_ExternalException);
+ }
+
+ // Map CompareStringEx return value to -1, 0, 1.
+ return result - 2;
+ }
+ }
+
+ private unsafe int FindString(
+ uint dwFindNLSStringFlags,
+ ReadOnlySpan<char> lpStringSource,
+ ReadOnlySpan<char> lpStringValue,
+ int* pcchFound)
+ {
+ Debug.Assert(!_invariantMode);
+ Debug.Assert(!lpStringSource.IsEmpty);
+ Debug.Assert(!lpStringValue.IsEmpty);
+
+ string localeName = _sortHandle != IntPtr.Zero ? null : _sortName;
+
+ fixed (char* pLocaleName = localeName)
+ fixed (char* pSource = &MemoryMarshal.GetReference(lpStringSource))
+ fixed (char* pValue = &MemoryMarshal.GetReference(lpStringValue))
+ {
+ return Interop.Kernel32.FindNLSStringEx(
+ pLocaleName,
+ dwFindNLSStringFlags,
+ pSource,
+ lpStringSource.Length,
+ pValue,
+ lpStringValue.Length,
+ pcchFound,
+ null,
+ null,
+ _sortHandle);
+ }
+ }
+
+ private unsafe int FindString(
+ uint dwFindNLSStringFlags,
+ string lpStringSource,
+ int startSource,
+ int cchSource,
+ string lpStringValue,
+ int startValue,
+ int cchValue,
+ int* pcchFound)
+ {
+ Debug.Assert(!_invariantMode);
+ Debug.Assert(lpStringSource != null);
+ Debug.Assert(lpStringValue != null);
+
+ string localeName = _sortHandle != IntPtr.Zero ? null : _sortName;
+
+ fixed (char* pLocaleName = localeName)
+ fixed (char* pSource = lpStringSource)
+ fixed (char* pValue = lpStringValue)
+ {
+ char* pS = pSource + startSource;
+ char* pV = pValue + startValue;
+
+ return Interop.Kernel32.FindNLSStringEx(
+ pLocaleName,
+ dwFindNLSStringFlags,
+ pS,
+ cchSource,
+ pV,
+ cchValue,
+ pcchFound,
+ null,
+ null,
+ _sortHandle);
+ }
+ }
+
+ internal unsafe int IndexOfCore(String source, String target, int startIndex, int count, CompareOptions options, int* matchLengthPtr)
+ {
+ Debug.Assert(!_invariantMode);
+
+ Debug.Assert(source != null);
+ Debug.Assert(target != null);
+ Debug.Assert((options & CompareOptions.OrdinalIgnoreCase) == 0);
+
+ if (target.Length == 0)
+ {
+ if (matchLengthPtr != null)
+ *matchLengthPtr = 0;
+ return startIndex;
+ }
+
+ if (source.Length == 0)
+ {
+ return -1;
+ }
+
+ if ((options & CompareOptions.Ordinal) != 0)
+ {
+ int retValue = FastIndexOfString(source, target, startIndex, count, target.Length, findLastIndex: false);
+ if (retValue >= 0)
+ {
+ if (matchLengthPtr != null)
+ *matchLengthPtr = target.Length;
+ }
+ return retValue;
+ }
+ else
+ {
+ int retValue = FindString(FIND_FROMSTART | (uint)GetNativeCompareFlags(options), source, startIndex, count,
+ target, 0, target.Length, matchLengthPtr);
+ if (retValue >= 0)
+ {
+ return retValue + startIndex;
+ }
+ }
+
+ return -1;
+ }
+
+ internal unsafe int IndexOfCore(ReadOnlySpan<char> source, ReadOnlySpan<char> target, CompareOptions options, int* matchLengthPtr)
+ {
+ Debug.Assert(!_invariantMode);
+
+ Debug.Assert(source.Length != 0);
+ Debug.Assert(target.Length != 0);
+ Debug.Assert((options == CompareOptions.None || options == CompareOptions.IgnoreCase));
+
+ int retValue = FindString(FIND_FROMSTART | (uint)GetNativeCompareFlags(options), source, target, matchLengthPtr);
+ return retValue;
+ }
+
+ private unsafe int LastIndexOfCore(string source, string target, int startIndex, int count, CompareOptions options)
+ {
+ Debug.Assert(!_invariantMode);
+
+ Debug.Assert(!string.IsNullOrEmpty(source));
+ Debug.Assert(target != null);
+ Debug.Assert((options & CompareOptions.OrdinalIgnoreCase) == 0);
+
+ if (target.Length == 0)
+ return startIndex;
+
+ if ((options & CompareOptions.Ordinal) != 0)
+ {
+ return FastIndexOfString(source, target, startIndex, count, target.Length, findLastIndex: true);
+ }
+ else
+ {
+ int retValue = FindString(FIND_FROMEND | (uint)GetNativeCompareFlags(options), source, startIndex - count + 1,
+ count, target, 0, target.Length, null);
+
+ if (retValue >= 0)
+ {
+ return retValue + startIndex - (count - 1);
+ }
+ }
+
+ return -1;
+ }
+
+ private unsafe bool StartsWith(string source, string prefix, CompareOptions options)
+ {
+ Debug.Assert(!_invariantMode);
+
+ Debug.Assert(!string.IsNullOrEmpty(source));
+ Debug.Assert(!string.IsNullOrEmpty(prefix));
+ Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ return FindString(FIND_STARTSWITH | (uint)GetNativeCompareFlags(options), source, 0, source.Length,
+ prefix, 0, prefix.Length, null) >= 0;
+ }
+
+ private unsafe bool StartsWith(ReadOnlySpan<char> source, ReadOnlySpan<char> prefix, CompareOptions options)
+ {
+ Debug.Assert(!_invariantMode);
+
+ Debug.Assert(!source.IsEmpty);
+ Debug.Assert(!prefix.IsEmpty);
+ Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ return FindString(FIND_STARTSWITH | (uint)GetNativeCompareFlags(options), source, prefix, null) >= 0;
+ }
+
+ private unsafe bool EndsWith(string source, string suffix, CompareOptions options)
+ {
+ Debug.Assert(!_invariantMode);
+
+ Debug.Assert(!string.IsNullOrEmpty(source));
+ Debug.Assert(!string.IsNullOrEmpty(suffix));
+ Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ return FindString(FIND_ENDSWITH | (uint)GetNativeCompareFlags(options), source, 0, source.Length,
+ suffix, 0, suffix.Length, null) >= 0;
+ }
+
+ private unsafe bool EndsWith(ReadOnlySpan<char> source, ReadOnlySpan<char> suffix, CompareOptions options)
+ {
+ Debug.Assert(!_invariantMode);
+
+ Debug.Assert(!source.IsEmpty);
+ Debug.Assert(!suffix.IsEmpty);
+ Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ return FindString(FIND_ENDSWITH | (uint)GetNativeCompareFlags(options), source, suffix, null) >= 0;
+ }
+
+ // PAL ends here
+ [NonSerialized]
+ private IntPtr _sortHandle;
+
+ private const uint LCMAP_SORTKEY = 0x00000400;
+ private const uint LCMAP_HASH = 0x00040000;
+
+ private const int FIND_STARTSWITH = 0x00100000;
+ private const int FIND_ENDSWITH = 0x00200000;
+ private const int FIND_FROMSTART = 0x00400000;
+ private const int FIND_FROMEND = 0x00800000;
+
+ // TODO: Instead of this method could we just have upstack code call IndexOfOrdinal with ignoreCase = false?
+ private static unsafe int FastIndexOfString(string source, string target, int startIndex, int sourceCount, int targetCount, bool findLastIndex)
+ {
+ int retValue = -1;
+
+ int sourceStartIndex = findLastIndex ? startIndex - sourceCount + 1 : startIndex;
+
+ fixed (char* pSource = source, spTarget = target)
+ {
+ char* spSubSource = pSource + sourceStartIndex;
+
+ if (findLastIndex)
+ {
+ int startPattern = (sourceCount - 1) - targetCount + 1;
+ if (startPattern < 0)
+ return -1;
+
+ char patternChar0 = spTarget[0];
+ for (int ctrSrc = startPattern; ctrSrc >= 0; ctrSrc--)
+ {
+ if (spSubSource[ctrSrc] != patternChar0)
+ continue;
+
+ int ctrPat;
+ for (ctrPat = 1; ctrPat < targetCount; ctrPat++)
+ {
+ if (spSubSource[ctrSrc + ctrPat] != spTarget[ctrPat])
+ break;
+ }
+ if (ctrPat == targetCount)
+ {
+ retValue = ctrSrc;
+ break;
+ }
+ }
+
+ if (retValue >= 0)
+ {
+ retValue += startIndex - sourceCount + 1;
+ }
+ }
+ else
+ {
+ int endPattern = (sourceCount - 1) - targetCount + 1;
+ if (endPattern < 0)
+ return -1;
+
+ char patternChar0 = spTarget[0];
+ for (int ctrSrc = 0; ctrSrc <= endPattern; ctrSrc++)
+ {
+ if (spSubSource[ctrSrc] != patternChar0)
+ continue;
+ int ctrPat;
+ for (ctrPat = 1; ctrPat < targetCount; ctrPat++)
+ {
+ if (spSubSource[ctrSrc + ctrPat] != spTarget[ctrPat])
+ break;
+ }
+ if (ctrPat == targetCount)
+ {
+ retValue = ctrSrc;
+ break;
+ }
+ }
+
+ if (retValue >= 0)
+ {
+ retValue += startIndex;
+ }
+ }
+ }
+
+ return retValue;
+ }
+
+ private unsafe SortKey CreateSortKey(String source, CompareOptions options)
+ {
+ Debug.Assert(!_invariantMode);
+
+ if (source == null) { throw new ArgumentNullException(nameof(source)); }
+
+ if ((options & ValidSortkeyCtorMaskOffFlags) != 0)
+ {
+ throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options));
+ }
+
+ byte [] keyData = null;
+ if (source.Length == 0)
+ {
+ keyData = Array.Empty<byte>();
+ }
+ else
+ {
+ uint flags = LCMAP_SORTKEY | (uint)GetNativeCompareFlags(options);
+
+ fixed (char *pSource = source)
+ {
+ int sortKeyLength = Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _sortName,
+ flags,
+ pSource, source.Length,
+ null, 0,
+ null, null, _sortHandle);
+ if (sortKeyLength == 0)
+ {
+ throw new ArgumentException(SR.Arg_ExternalException);
+ }
+
+ keyData = new byte[sortKeyLength];
+
+ fixed (byte* pBytes = keyData)
+ {
+ if (Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _sortName,
+ flags,
+ pSource, source.Length,
+ pBytes, keyData.Length,
+ null, null, _sortHandle) != sortKeyLength)
+ {
+ throw new ArgumentException(SR.Arg_ExternalException);
+ }
+ }
+ }
+ }
+
+ return new SortKey(Name, source, options, keyData);
+ }
+
+ private static unsafe bool IsSortable(char* text, int length)
+ {
+ Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(text != null);
+
+ return Interop.Kernel32.IsNLSDefinedString(Interop.Kernel32.COMPARE_STRING, 0, IntPtr.Zero, text, length);
+ }
+
+ private const int COMPARE_OPTIONS_ORDINAL = 0x40000000; // Ordinal
+ private const int NORM_IGNORECASE = 0x00000001; // Ignores case. (use LINGUISTIC_IGNORECASE instead)
+ private const int NORM_IGNOREKANATYPE = 0x00010000; // Does not differentiate between Hiragana and Katakana characters. Corresponding Hiragana and Katakana will compare as equal.
+ private const int NORM_IGNORENONSPACE = 0x00000002; // Ignores nonspacing. This flag also removes Japanese accent characters. (use LINGUISTIC_IGNOREDIACRITIC instead)
+ private const int NORM_IGNORESYMBOLS = 0x00000004; // Ignores symbols.
+ private const int NORM_IGNOREWIDTH = 0x00020000; // Does not differentiate between a single-byte character and the same character as a double-byte character.
+ private const int NORM_LINGUISTIC_CASING = 0x08000000; // use linguistic rules for casing
+ private const int SORT_STRINGSORT = 0x00001000; // Treats punctuation the same as symbols.
+
+ private static int GetNativeCompareFlags(CompareOptions options)
+ {
+ // Use "linguistic casing" by default (load the culture's casing exception tables)
+ int nativeCompareFlags = NORM_LINGUISTIC_CASING;
+
+ if ((options & CompareOptions.IgnoreCase) != 0) { nativeCompareFlags |= NORM_IGNORECASE; }
+ if ((options & CompareOptions.IgnoreKanaType) != 0) { nativeCompareFlags |= NORM_IGNOREKANATYPE; }
+ if ((options & CompareOptions.IgnoreNonSpace) != 0) { nativeCompareFlags |= NORM_IGNORENONSPACE; }
+ if ((options & CompareOptions.IgnoreSymbols) != 0) { nativeCompareFlags |= NORM_IGNORESYMBOLS; }
+ if ((options & CompareOptions.IgnoreWidth) != 0) { nativeCompareFlags |= NORM_IGNOREWIDTH; }
+ if ((options & CompareOptions.StringSort) != 0) { nativeCompareFlags |= SORT_STRINGSORT; }
+
+ // TODO: Can we try for GetNativeCompareFlags to never
+ // take Ordinal or OrdinalIgnoreCase. This value is not part of Win32, we just handle it special
+ // in some places.
+ // Suffix & Prefix shouldn't use this, make sure to turn off the NORM_LINGUISTIC_CASING flag
+ if (options == CompareOptions.Ordinal) { nativeCompareFlags = COMPARE_OPTIONS_ORDINAL; }
+
+ Debug.Assert(((options & ~(CompareOptions.IgnoreCase |
+ CompareOptions.IgnoreKanaType |
+ CompareOptions.IgnoreNonSpace |
+ CompareOptions.IgnoreSymbols |
+ CompareOptions.IgnoreWidth |
+ CompareOptions.StringSort)) == 0) ||
+ (options == CompareOptions.Ordinal), "[CompareInfo.GetNativeCompareFlags]Expected all flags to be handled");
+
+ return nativeCompareFlags;
+ }
+
+ private unsafe SortVersion GetSortVersion()
+ {
+ Debug.Assert(!_invariantMode);
+
+ Interop.Kernel32.NlsVersionInfoEx nlsVersion = new Interop.Kernel32.NlsVersionInfoEx();
+ nlsVersion.dwNLSVersionInfoSize = sizeof(Interop.Kernel32.NlsVersionInfoEx);
+ Interop.Kernel32.GetNLSVersionEx(Interop.Kernel32.COMPARE_STRING, _sortName, &nlsVersion);
+ return new SortVersion(
+ nlsVersion.dwNLSVersion,
+ nlsVersion.dwEffectiveId == 0 ? LCID : nlsVersion.dwEffectiveId,
+ nlsVersion.guidCustomVersion);
+ }
+ }
+}
diff --git a/src/Common/src/CoreLib/System/Globalization/CompareInfo.cs b/src/Common/src/CoreLib/System/Globalization/CompareInfo.cs
index 38201530e8..76b65b9895 100644
--- a/src/Common/src/CoreLib/System/Globalization/CompareInfo.cs
+++ b/src/Common/src/CoreLib/System/Globalization/CompareInfo.cs
@@ -16,6 +16,8 @@ using System.Reflection;
using System.Diagnostics.Private;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
+using System.Buffers;
+using System.Text;
namespace System.Globalization
{
@@ -96,7 +98,7 @@ namespace System.Globalization
** culture the ID of the culture
** assembly the assembly which contains the sorting table.
**Exceptions:
- ** ArugmentNullException when the assembly is null
+ ** ArgumentNullException when the assembly is null
** ArgumentException if culture is invalid.
============================================================================*/
// Assembly constructor should be deprecated, we don't act on the assembly information any more
@@ -123,7 +125,7 @@ namespace System.Globalization
** name the name of the culture
** assembly the assembly which contains the sorting table.
**Exceptions:
- ** ArugmentNullException when the assembly is null
+ ** ArgumentNullException when the assembly is null
** ArgumentException if name is invalid.
============================================================================*/
// Assembly constructor should be deprecated, we don't act on the assembly information any more
@@ -300,7 +302,7 @@ namespace System.Globalization
return (Compare(string1, string2, CompareOptions.None));
}
- public unsafe virtual int Compare(string string1, string string2, CompareOptions options)
+ public virtual int Compare(string string1, string string2, CompareOptions options)
{
if (options == CompareOptions.OrdinalIgnoreCase)
{
@@ -341,7 +343,7 @@ namespace System.Globalization
if (_invariantMode)
{
if ((options & CompareOptions.IgnoreCase) != 0)
- return CompareOrdinalIgnoreCase(string1, 0, string1.Length, string2, 0, string2.Length);
+ return CompareOrdinalIgnoreCase(string1, string2);
return String.CompareOrdinal(string1, string2);
}
@@ -349,18 +351,18 @@ namespace System.Globalization
#if MONO
return internal_compare_switch(string1, 0, string1.Length, string2, 0, string2.Length, options);
#else
- return CompareString(string1.AsReadOnlySpan(), string2.AsReadOnlySpan(), options);
+ return CompareString(string1.AsSpan(), string2.AsSpan(), options);
#endif
}
// TODO https://github.com/dotnet/coreclr/issues/13827:
// This method shouldn't be necessary, as we should be able to just use the overload
// that takes two spans. But due to this issue, that's adding significant overhead.
- internal unsafe int Compare(ReadOnlySpan<char> string1, string string2, CompareOptions options)
+ internal int Compare(ReadOnlySpan<char> string1, string string2, CompareOptions options)
{
if (options == CompareOptions.OrdinalIgnoreCase)
{
- return CompareOrdinalIgnoreCase(string1, string2.AsReadOnlySpan());
+ return CompareOrdinalIgnoreCase(string1, string2.AsSpan());
}
// Verify the options before we do any real comparison.
@@ -371,7 +373,7 @@ namespace System.Globalization
throw new ArgumentException(SR.Argument_CompareOptionOrdinal, nameof(options));
}
- return string.CompareOrdinal(string1, string2.AsReadOnlySpan());
+ return string.CompareOrdinal(string1, string2.AsSpan());
}
if ((options & ValidCompareMaskOffFlags) != 0)
@@ -388,45 +390,33 @@ namespace System.Globalization
if (_invariantMode)
{
return (options & CompareOptions.IgnoreCase) != 0 ?
- CompareOrdinalIgnoreCase(string1, string2.AsReadOnlySpan()) :
- string.CompareOrdinal(string1, string2.AsReadOnlySpan());
+ CompareOrdinalIgnoreCase(string1, string2.AsSpan()) :
+ string.CompareOrdinal(string1, string2.AsSpan());
}
return CompareString(string1, string2, options);
}
- // TODO https://github.com/dotnet/corefx/issues/21395: Expose this publicly?
- internal unsafe virtual int Compare(ReadOnlySpan<char> string1, ReadOnlySpan<char> string2, CompareOptions options)
+ internal int CompareOptionNone(ReadOnlySpan<char> string1, ReadOnlySpan<char> string2)
{
- if (options == CompareOptions.OrdinalIgnoreCase)
- {
- return CompareOrdinalIgnoreCase(string1, string2);
- }
-
- // Verify the options before we do any real comparison.
- if ((options & CompareOptions.Ordinal) != 0)
- {
- if (options != CompareOptions.Ordinal)
- {
- throw new ArgumentException(SR.Argument_CompareOptionOrdinal, nameof(options));
- }
+ // Check for empty span or span from a null string
+ if (string1.Length == 0 || string2.Length == 0)
+ return string1.Length - string2.Length;
- return string.CompareOrdinal(string1, string2);
- }
-
- if ((options & ValidCompareMaskOffFlags) != 0)
- {
- throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options));
- }
+ return _invariantMode ?
+ string.CompareOrdinal(string1, string2) :
+ CompareString(string1, string2, CompareOptions.None);
+ }
- if (_invariantMode)
- {
- return (options & CompareOptions.IgnoreCase) != 0 ?
- CompareOrdinalIgnoreCase(string1, string2) :
- string.CompareOrdinal(string1, string2);
- }
+ internal int CompareOptionIgnoreCase(ReadOnlySpan<char> string1, ReadOnlySpan<char> string2)
+ {
+ // Check for empty span or span from a null string
+ if (string1.Length == 0 || string2.Length == 0)
+ return string1.Length - string2.Length;
- return CompareString(string1, string2, options);
+ return _invariantMode ?
+ CompareOrdinalIgnoreCase(string1, string2) :
+ CompareString(string1, string2, CompareOptions.IgnoreCase);
}
////////////////////////////////////////////////////////////////////////
@@ -442,7 +432,7 @@ namespace System.Globalization
////////////////////////////////////////////////////////////////////////
- public unsafe virtual int Compare(string string1, int offset1, int length1, string string2, int offset2, int length2)
+ public virtual int Compare(string string1, int offset1, int length1, string string2, int offset2, int length2)
{
return Compare(string1, offset1, length1, string2, offset2, length2, 0);
}
@@ -517,51 +507,39 @@ namespace System.Globalization
return (1);
}
+ ReadOnlySpan<char> span1 = string1.AsSpan(offset1, length1);
+ ReadOnlySpan<char> span2 = string2.AsSpan(offset2, length2);
+
if (options == CompareOptions.Ordinal)
{
- return CompareOrdinal(string1, offset1, length1,
- string2, offset2, length2);
+ return string.CompareOrdinal(span1, span2);
}
if (_invariantMode)
{
if ((options & CompareOptions.IgnoreCase) != 0)
- return CompareOrdinalIgnoreCase(string1, offset1, length1, string2, offset2, length2);
+ return CompareOrdinalIgnoreCase(span1, span2);
- return CompareOrdinal(string1, offset1, length1, string2, offset2, length2);
+ return string.CompareOrdinal(span1, span2);
}
#if MONO
return internal_compare_switch(string1, offset1, length1, string2, offset2, length2, options);
#else
- return CompareString(
- string1.AsReadOnlySpan().Slice(offset1, length1),
- string2.AsReadOnlySpan().Slice(offset2, length2),
- options);
+ return CompareString(span1, span2, options);
#endif
}
- private static int CompareOrdinal(string string1, int offset1, int length1, string string2, int offset2, int length2)
- {
- int result = String.CompareOrdinal(string1, offset1, string2, offset2,
- (length1 < length2 ? length1 : length2));
- if ((length1 != length2) && result == 0)
- {
- return (length1 > length2 ? 1 : -1);
- }
- return (result);
- }
-
//
// CompareOrdinalIgnoreCase compare two string ordinally with ignoring the case.
// it assumes the strings are Ascii string till we hit non Ascii character in strA or strB and then we continue the comparison by
// calling the OS.
//
- internal static unsafe int CompareOrdinalIgnoreCase(string strA, int indexA, int lengthA, string strB, int indexB, int lengthB)
+ internal static int CompareOrdinalIgnoreCase(string strA, int indexA, int lengthA, string strB, int indexB, int lengthB)
{
Debug.Assert(indexA + lengthA <= strA.Length);
Debug.Assert(indexB + lengthB <= strB.Length);
- return CompareOrdinalIgnoreCase(strA.AsReadOnlySpan().Slice(indexA, lengthA), strB.AsReadOnlySpan().Slice(indexB, lengthB));
+ return CompareOrdinalIgnoreCase(strA.AsSpan(indexA, lengthA), strB.AsSpan(indexB, lengthB));
}
internal static unsafe int CompareOrdinalIgnoreCase(ReadOnlySpan<char> strA, ReadOnlySpan<char> strB)
@@ -576,7 +554,7 @@ namespace System.Globalization
char* b = bp;
// in InvariantMode we support all range and not only the ascii characters.
- char maxChar = (char) (GlobalizationMode.Invariant ? 0xFFFF : 0x80);
+ char maxChar = (char) (GlobalizationMode.Invariant ? 0xFFFF : 0x7F);
while (length != 0 && (*a <= maxChar) && (*b <= maxChar))
{
@@ -663,6 +641,17 @@ namespace System.Globalization
return StartsWith(source, prefix, options);
}
+ internal bool IsPrefix(ReadOnlySpan<char> source, ReadOnlySpan<char> prefix, CompareOptions options)
+ {
+ Debug.Assert(prefix.Length != 0);
+ Debug.Assert(source.Length != 0);
+ Debug.Assert((options & ValidIndexMaskOffFlags) == 0);
+ Debug.Assert(!_invariantMode);
+ Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ return StartsWith(source, prefix, options);
+ }
+
public virtual bool IsPrefix(string source, string prefix)
{
return (IsPrefix(source, prefix, 0));
@@ -717,6 +706,17 @@ namespace System.Globalization
return EndsWith(source, suffix, options);
}
+ internal bool IsSuffix(ReadOnlySpan<char> source, ReadOnlySpan<char> suffix, CompareOptions options)
+ {
+ Debug.Assert(suffix.Length != 0);
+ Debug.Assert(source.Length != 0);
+ Debug.Assert((options & ValidIndexMaskOffFlags) == 0);
+ Debug.Assert(!_invariantMode);
+ Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ return EndsWith(source, suffix, options);
+ }
+
public virtual bool IsSuffix(string source, string suffix)
{
@@ -829,6 +829,11 @@ namespace System.Globalization
if (count < 0 || startIndex > source.Length - count)
throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count);
+ if (source.Length == 0)
+ {
+ return -1;
+ }
+
if (options == CompareOptions.OrdinalIgnoreCase)
{
return source.IndexOf(value.ToString(), startIndex, count, StringComparison.OrdinalIgnoreCase);
@@ -838,7 +843,7 @@ namespace System.Globalization
// Ordinal can't be selected with other flags
if ((options & ValidIndexMaskOffFlags) != 0 && (options != CompareOptions.Ordinal))
throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options));
-
+
if (_invariantMode)
return IndexOfOrdinal(source, new string(value, 1), startIndex, count, ignoreCase: (options & (CompareOptions.IgnoreCase | CompareOptions.OrdinalIgnoreCase)) != 0);
@@ -893,6 +898,22 @@ namespace System.Globalization
return IndexOfCore(source, value, startIndex, count, options, null);
}
+ internal int IndexOfOrdinal(ReadOnlySpan<char> source, ReadOnlySpan<char> value, bool ignoreCase)
+ {
+ Debug.Assert(!_invariantMode);
+ Debug.Assert(!source.IsEmpty);
+ Debug.Assert(!value.IsEmpty);
+ return IndexOfOrdinalCore(source, value, ignoreCase);
+ }
+
+ internal unsafe int IndexOf(ReadOnlySpan<char> source, ReadOnlySpan<char> value, CompareOptions options)
+ {
+ Debug.Assert(!_invariantMode);
+ Debug.Assert(!source.IsEmpty);
+ Debug.Assert(!value.IsEmpty);
+ return IndexOfCore(source, value, options, null);
+ }
+
// The following IndexOf overload is mainly used by String.Replace. This overload assumes the parameters are already validated
// and the caller is passing a valid matchLengthPtr pointer.
internal unsafe int IndexOf(string source, string value, int startIndex, int count, CompareOptions options, int* matchLengthPtr)
@@ -1208,6 +1229,34 @@ namespace System.Globalization
return (this.Name.GetHashCode());
}
+ internal static unsafe int GetIgnoreCaseHash(string source)
+ {
+ Debug.Assert(source != null, "source must not be null");
+
+ // Do not allocate on the stack if string is empty
+ if (source.Length == 0)
+ {
+ return source.GetHashCode();
+ }
+
+ char[] borrowedArr = null;
+ Span<char> span = source.Length <= 255 ?
+ stackalloc char[255] :
+ (borrowedArr = ArrayPool<char>.Shared.Rent(source.Length));
+
+ int charsWritten = source.AsSpan().ToUpperInvariant(span);
+
+ // Slice the array to the size returned by ToUpperInvariant.
+ int hash = Marvin.ComputeHash32(MemoryMarshal.AsBytes(span.Slice(0, charsWritten)), Marvin.DefaultSeed);
+
+ // Return the borrowed array if necessary.
+ if (borrowedArr != null)
+ {
+ ArrayPool<char>.Shared.Return(borrowedArr);
+ }
+
+ return hash;
+ }
////////////////////////////////////////////////////////////////////////
//
@@ -1248,6 +1297,11 @@ namespace System.Globalization
throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options));
}
+ if (_invariantMode)
+ {
+ return ((options & CompareOptions.IgnoreCase) != 0) ? GetIgnoreCaseHash(source) : source.GetHashCode();
+ }
+
return GetHashCodeOfStringCore(source, options);
}
@@ -1265,11 +1319,11 @@ namespace System.Globalization
if (options == CompareOptions.OrdinalIgnoreCase)
{
- return TextInfo.GetHashCodeOrdinalIgnoreCase(source);
+ return GetIgnoreCaseHash(source);
}
//
- // GetHashCodeOfString does more parameters validation. basically will throw when
+ // GetHashCodeOfString does more parameters validation. basically will throw when
// having Ordinal, OrdinalIgnoreCase and StringSort
//
diff --git a/src/Common/src/CoreLib/System/Globalization/CultureData.Unix.cs b/src/Common/src/CoreLib/System/Globalization/CultureData.Unix.cs
index 1b335c28ee..3fce527929 100644
--- a/src/Common/src/CoreLib/System/Globalization/CultureData.Unix.cs
+++ b/src/Common/src/CoreLib/System/Globalization/CultureData.Unix.cs
@@ -91,7 +91,7 @@ namespace System.Globalization
{
// Get the locale name from ICU
StringBuilder sb = StringBuilderCache.Acquire(ICU_ULOC_FULLNAME_CAPACITY);
- if (!Interop.GlobalizationInterop.GetLocaleName(localeName, sb, sb.Capacity))
+ if (!Interop.Globalization.GetLocaleName(localeName, sb, sb.Capacity))
{
StringBuilderCache.Release(sb);
windowsName = null;
@@ -107,7 +107,7 @@ namespace System.Globalization
{
// Get the default (system) locale name from ICU
StringBuilder sb = StringBuilderCache.Acquire(ICU_ULOC_FULLNAME_CAPACITY);
- if (!Interop.GlobalizationInterop.GetDefaultLocaleName(sb, sb.Capacity))
+ if (!Interop.Globalization.GetDefaultLocaleName(sb, sb.Capacity))
{
StringBuilderCache.Release(sb);
windowsName = null;
@@ -143,7 +143,7 @@ namespace System.Globalization
StringBuilder sb = StringBuilderCache.Acquire(ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY);
- bool result = Interop.GlobalizationInterop.GetLocaleInfoString(localeName, (uint)type, sb, sb.Capacity);
+ bool result = Interop.Globalization.GetLocaleInfoString(localeName, (uint)type, sb, sb.Capacity);
if (!result)
{
// Failed, just use empty string
@@ -169,7 +169,7 @@ namespace System.Globalization
int value = 0;
- bool result = Interop.GlobalizationInterop.GetLocaleInfoInt(_sWindowsName, (uint)type, ref value);
+ bool result = Interop.Globalization.GetLocaleInfoInt(_sWindowsName, (uint)type, ref value);
if (!result)
{
// Failed, just use 0
@@ -185,7 +185,7 @@ namespace System.Globalization
int primaryGroupingSize = 0;
int secondaryGroupingSize = 0;
- bool result = Interop.GlobalizationInterop.GetLocaleInfoGroupingSizes(_sWindowsName, (uint)type, ref primaryGroupingSize, ref secondaryGroupingSize);
+ bool result = Interop.Globalization.GetLocaleInfoGroupingSizes(_sWindowsName, (uint)type, ref primaryGroupingSize, ref secondaryGroupingSize);
if (!result)
{
Debug.Fail("[CultureData.GetLocaleInfo(LocaleGroupingData type)] failed");
@@ -210,7 +210,7 @@ namespace System.Globalization
StringBuilder sb = StringBuilderCache.Acquire(ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY);
- bool result = Interop.GlobalizationInterop.GetLocaleTimeFormat(_sWindowsName, shortFormat, sb, sb.Capacity);
+ bool result = Interop.Globalization.GetLocaleTimeFormat(_sWindowsName, shortFormat, sb, sb.Capacity);
if (!result)
{
// Failed, just use empty string
@@ -365,7 +365,7 @@ namespace System.Globalization
return Array.Empty<CultureInfo>();
}
- int bufferLength = Interop.GlobalizationInterop.GetLocales(null, 0);
+ int bufferLength = Interop.Globalization.GetLocales(null, 0);
if (bufferLength <= 0)
{
return Array.Empty<CultureInfo>();
@@ -373,7 +373,7 @@ namespace System.Globalization
Char [] chars = new Char[bufferLength];
- bufferLength = Interop.GlobalizationInterop.GetLocales(chars, bufferLength);
+ bufferLength = Interop.Globalization.GetLocales(chars, bufferLength);
if (bufferLength <= 0)
{
return Array.Empty<CultureInfo>();
diff --git a/src/Common/src/CoreLib/System/Globalization/DateTimeFormat.cs b/src/Common/src/CoreLib/System/Globalization/DateTimeFormat.cs
index d15cc1cc8c..092ad0365d 100644
--- a/src/Common/src/CoreLib/System/Globalization/DateTimeFormat.cs
+++ b/src/Common/src/CoreLib/System/Globalization/DateTimeFormat.cs
@@ -6,6 +6,8 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Text;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
namespace System
{
@@ -172,7 +174,7 @@ namespace System
FormatDigits(outputBuffer, value, len, false);
}
- internal unsafe static void FormatDigits(StringBuilder outputBuffer, int value, int len, bool overrideLengthLimit)
+ internal static unsafe void FormatDigits(StringBuilder outputBuffer, int value, int len, bool overrideLengthLimit)
{
Debug.Assert(value >= 0, "DateTimeFormat.FormatDigits(): value >= 0");
@@ -703,7 +705,7 @@ namespace System
if (nextChar >= 0 && nextChar != '%')
{
char nextCharChar = (char)nextChar;
- StringBuilder origStringBuilder = FormatCustomized(dateTime, ReadOnlySpan<char>.DangerousCreate(null, ref nextCharChar, 1), dtfi, offset, result);
+ StringBuilder origStringBuilder = FormatCustomized(dateTime, MemoryMarshal.CreateReadOnlySpan<char>(ref nextCharChar, 1), dtfi, offset, result);
Debug.Assert(ReferenceEquals(origStringBuilder, result));
tokenLen = 2;
}
@@ -851,9 +853,15 @@ namespace System
offset = offset.Negate();
}
- AppendNumber(result, offset.Hours, 2);
+ Append2DigitNumber(result, offset.Hours);
result.Append(':');
- AppendNumber(result, offset.Minutes, 2);
+ Append2DigitNumber(result, offset.Minutes);
+ }
+
+ private static void Append2DigitNumber(StringBuilder result, int val)
+ {
+ result.Append((char)('0' + (val / 10)));
+ result.Append((char)('0' + (val % 10)));
}
internal static String GetRealFormat(ReadOnlySpan<char> format, DateTimeFormatInfo dtfi)
@@ -980,19 +988,65 @@ namespace System
return GetRealFormat(format, dtfi);
}
- internal static String Format(DateTime dateTime, String format, DateTimeFormatInfo dtfi)
+ internal static String Format(DateTime dateTime, String format, IFormatProvider provider)
{
- return Format(dateTime, format, dtfi, NullOffset);
+ return Format(dateTime, format, provider, NullOffset);
}
- internal static string Format(DateTime dateTime, String format, DateTimeFormatInfo dtfi, TimeSpan offset) =>
- StringBuilderCache.GetStringAndRelease(FormatStringBuilder(dateTime, format, dtfi, offset));
+ internal static string Format(DateTime dateTime, String format, IFormatProvider provider, TimeSpan offset)
+ {
+ if (format != null && format.Length == 1)
+ {
+ // Optimize for these standard formats that are not affected by culture.
+ switch (format[0])
+ {
+ // Round trip format
+ case 'o':
+ case 'O':
+ const int MinFormatOLength = 27, MaxFormatOLength = 33;
+ Span<char> span = stackalloc char[MaxFormatOLength];
+ TryFormatO(dateTime, offset, span, out int ochars);
+ Debug.Assert(ochars >= MinFormatOLength && ochars <= MaxFormatOLength);
+ return span.Slice(0, ochars).ToString();
+
+ // RFC1123
+ case 'r':
+ case 'R':
+ const int FormatRLength = 29;
+ string str = string.FastAllocateString(FormatRLength);
+ TryFormatR(dateTime, offset, new Span<char>(ref str.GetRawStringData(), str.Length), out int rchars);
+ Debug.Assert(rchars == str.Length);
+ return str;
+ }
+ }
+
+ DateTimeFormatInfo dtfi = DateTimeFormatInfo.GetInstance(provider);
+ return StringBuilderCache.GetStringAndRelease(FormatStringBuilder(dateTime, format, dtfi, offset));
+ }
- internal static bool TryFormat(DateTime dateTime, Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi) =>
- TryFormat(dateTime, destination, out charsWritten, format, dtfi, NullOffset);
+ internal static bool TryFormat(DateTime dateTime, Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider provider) =>
+ TryFormat(dateTime, destination, out charsWritten, format, provider, NullOffset);
- internal static bool TryFormat(DateTime dateTime, Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, TimeSpan offset)
+ internal static bool TryFormat(DateTime dateTime, Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider provider, TimeSpan offset)
{
+ if (format.Length == 1)
+ {
+ // Optimize for these standard formats that are not affected by culture.
+ switch (format[0])
+ {
+ // Round trip format
+ case 'o':
+ case 'O':
+ return TryFormatO(dateTime, offset, destination, out charsWritten);
+
+ // RFC1123
+ case 'r':
+ case 'R':
+ return TryFormatR(dateTime, offset, destination, out charsWritten);
+ }
+ }
+
+ DateTimeFormatInfo dtfi = DateTimeFormatInfo.GetInstance(provider);
StringBuilder sb = FormatStringBuilder(dateTime, format, dtfi, offset);
bool success = sb.Length <= destination.Length;
@@ -1010,7 +1064,7 @@ namespace System
return success;
}
- internal static StringBuilder FormatStringBuilder(DateTime dateTime, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, TimeSpan offset)
+ private static StringBuilder FormatStringBuilder(DateTime dateTime, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, TimeSpan offset)
{
Debug.Assert(dtfi != null);
if (format.Length == 0)
@@ -1059,101 +1113,204 @@ namespace System
if (format.Length == 1)
{
- switch (format[0])
+ format = ExpandPredefinedFormat(format, ref dateTime, ref dtfi, ref offset);
+ }
+
+ return FormatCustomized(dateTime, format, dtfi, offset, result: null);
+ }
+
+ // Roundtrippable format. One of
+ // 012345678901234567890123456789012
+ // ---------------------------------
+ // 2017-06-12T05:30:45.7680000-07:00
+ // 2017-06-12T05:30:45.7680000Z (Z is short for "+00:00" but also distinguishes DateTimeKind.Utc from DateTimeKind.Local)
+ // 2017-06-12T05:30:45.7680000 (interpreted as local time wrt to current time zone)
+ private static bool TryFormatO(DateTime dateTime, TimeSpan offset, Span<char> destination, out int charsWritten)
+ {
+ const int MinimumBytesNeeded = 27;
+
+ int charsRequired = MinimumBytesNeeded;
+ DateTimeKind kind = DateTimeKind.Local;
+
+ if (offset == NullOffset)
+ {
+ kind = dateTime.Kind;
+ if (kind == DateTimeKind.Local)
{
- case 'O':
- case 'o':
- return FastFormatRoundtrip(dateTime, offset);
- case 'R':
- case 'r':
- return FastFormatRfc1123(dateTime, offset, dtfi);
+ offset = TimeZoneInfo.Local.GetUtcOffset(dateTime);
+ charsRequired += 6;
+ }
+ else if (kind == DateTimeKind.Utc)
+ {
+ charsRequired += 1;
}
+ }
+ else
+ {
+ charsRequired += 6;
+ }
- format = ExpandPredefinedFormat(format, ref dateTime, ref dtfi, ref offset);
+ if (destination.Length < charsRequired)
+ {
+ charsWritten = 0;
+ return false;
}
+ charsWritten = charsRequired;
+
+ // Hoist most of the bounds checks on destination.
+ { var unused = destination[MinimumBytesNeeded - 1]; }
+
+ WriteFourDecimalDigits((uint)dateTime.Year, destination, 0);
+ destination[4] = '-';
+ WriteTwoDecimalDigits((uint)dateTime.Month, destination, 5);
+ destination[7] = '-';
+ WriteTwoDecimalDigits((uint)dateTime.Day, destination, 8);
+ destination[10] = 'T';
+ WriteTwoDecimalDigits((uint)dateTime.Hour, destination, 11);
+ destination[13] = ':';
+ WriteTwoDecimalDigits((uint)dateTime.Minute, destination, 14);
+ destination[16] = ':';
+ WriteTwoDecimalDigits((uint)dateTime.Second, destination, 17);
+ destination[19] = '.';
+ WriteDigits((uint)((ulong)dateTime.Ticks % (ulong)TimeSpan.TicksPerSecond), destination.Slice(20, 7));
+
+ if (kind == DateTimeKind.Local)
+ {
+ char sign;
+ if (offset < default(TimeSpan) /* a "const" version of TimeSpan.Zero */)
+ {
+ sign = '-';
+ offset = TimeSpan.FromTicks(-offset.Ticks);
+ }
+ else
+ {
+ sign = '+';
+ }
- return FormatCustomized(dateTime, format, dtfi, offset, result: null);
+ // Writing the value backward allows the JIT to optimize by
+ // performing a single bounds check against buffer.
+ WriteTwoDecimalDigits((uint)offset.Minutes, destination, 31);
+ destination[30] = ':';
+ WriteTwoDecimalDigits((uint)offset.Hours, destination, 28);
+ destination[27] = sign;
+ }
+ else if (kind == DateTimeKind.Utc)
+ {
+ destination[27] = 'Z';
+ }
+
+ return true;
}
- internal static StringBuilder FastFormatRfc1123(DateTime dateTime, TimeSpan offset, DateTimeFormatInfo dtfi)
+ // Rfc1123
+ // 01234567890123456789012345678
+ // -----------------------------
+ // Tue, 03 Jan 2017 08:08:05 GMT
+ private static bool TryFormatR(DateTime dateTime, TimeSpan offset, Span<char> destination, out int charsWritten)
{
- // ddd, dd MMM yyyy HH:mm:ss GMT
- const int Rfc1123FormatLength = 29;
- StringBuilder result = StringBuilderCache.Acquire(Rfc1123FormatLength);
+ // Writing the check in this fashion elides all bounds checks on 'destination'
+ // for the remainder of the method.
+ if (28 >= (uint)destination.Length)
+ {
+ charsWritten = 0;
+ return false;
+ }
if (offset != NullOffset)
{
- // Convert to UTC invariants
+ // Convert to UTC invariants.
dateTime = dateTime - offset;
}
dateTime.GetDatePart(out int year, out int month, out int day);
- result.Append(InvariantAbbreviatedDayNames[(int)dateTime.DayOfWeek]);
- result.Append(',');
- result.Append(' ');
- AppendNumber(result, day, 2);
- result.Append(' ');
- result.Append(InvariantAbbreviatedMonthNames[month - 1]);
- result.Append(' ');
- AppendNumber(result, year, 4);
- result.Append(' ');
- AppendHHmmssTimeOfDay(result, dateTime);
- result.Append(' ');
- result.Append(Gmt);
- return result;
+ string dayAbbrev = InvariantAbbreviatedDayNames[(int)dateTime.DayOfWeek];
+ Debug.Assert(dayAbbrev.Length == 3);
+
+ string monthAbbrev = InvariantAbbreviatedMonthNames[month - 1];
+ Debug.Assert(monthAbbrev.Length == 3);
+
+ destination[0] = dayAbbrev[0];
+ destination[1] = dayAbbrev[1];
+ destination[2] = dayAbbrev[2];
+ destination[3] = ',';
+ destination[4] = ' ';
+ WriteTwoDecimalDigits((uint)day, destination, 5);
+ destination[7] = ' ';
+ destination[8] = monthAbbrev[0];
+ destination[9] = monthAbbrev[1];
+ destination[10] = monthAbbrev[2];
+ destination[11] = ' ';
+ WriteFourDecimalDigits((uint)year, destination, 12);
+ destination[16] = ' ';
+ WriteTwoDecimalDigits((uint)dateTime.Hour, destination, 17);
+ destination[19] = ':';
+ WriteTwoDecimalDigits((uint)dateTime.Minute, destination, 20);
+ destination[22] = ':';
+ WriteTwoDecimalDigits((uint)dateTime.Second, destination, 23);
+ destination[25] = ' ';
+ destination[26] = 'G';
+ destination[27] = 'M';
+ destination[28] = 'T';
+
+ charsWritten = 29;
+ return true;
}
- internal static StringBuilder FastFormatRoundtrip(DateTime dateTime, TimeSpan offset)
+ /// <summary>
+ /// Writes a value [ 00 .. 99 ] to the buffer starting at the specified offset.
+ /// This method performs best when the starting index is a constant literal.
+ /// </summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void WriteTwoDecimalDigits(uint value, Span<char> destination, int offset)
{
- // yyyy-MM-ddTHH:mm:ss.fffffffK
- const int roundTripFormatLength = 28;
- StringBuilder result = StringBuilderCache.Acquire(roundTripFormatLength);
+ Debug.Assert(0 <= value && value <= 99);
- dateTime.GetDatePart(out int year, out int month, out int day);
- AppendNumber(result, year, 4);
- result.Append('-');
- AppendNumber(result, month, 2);
- result.Append('-');
- AppendNumber(result, day, 2);
- result.Append('T');
- AppendHHmmssTimeOfDay(result, dateTime);
- result.Append('.');
+ uint temp = '0' + value;
+ value /= 10;
+ destination[offset + 1] = (char)(temp - (value * 10));
+ destination[offset] = (char)('0' + value);
+ }
- long fraction = dateTime.Ticks % TimeSpan.TicksPerSecond;
- AppendNumber(result, fraction, 7);
+ /// <summary>
+ /// Writes a value [ 0000 .. 9999 ] to the buffer starting at the specified offset.
+ /// This method performs best when the starting index is a constant literal.
+ /// </summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void WriteFourDecimalDigits(uint value, Span<char> buffer, int startingIndex = 0)
+ {
+ Debug.Assert(0 <= value && value <= 9999);
- FormatCustomizedRoundripTimeZone(dateTime, offset, result);
+ uint temp = '0' + value;
+ value /= 10;
+ buffer[startingIndex + 3] = (char)(temp - (value * 10));
- return result;
- }
+ temp = '0' + value;
+ value /= 10;
+ buffer[startingIndex + 2] = (char)(temp - (value * 10));
- private static void AppendHHmmssTimeOfDay(StringBuilder result, DateTime dateTime)
- {
- // HH:mm:ss
- AppendNumber(result, dateTime.Hour, 2);
- result.Append(':');
- AppendNumber(result, dateTime.Minute, 2);
- result.Append(':');
- AppendNumber(result, dateTime.Second, 2);
+ temp = '0' + value;
+ value /= 10;
+ buffer[startingIndex + 1] = (char)(temp - (value * 10));
+
+ buffer[startingIndex] = (char)('0' + value);
}
- internal static void AppendNumber(StringBuilder builder, long val, int digits)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void WriteDigits(ulong value, Span<char> buffer)
{
- for (int i = 0; i < digits; i++)
- {
- builder.Append('0');
- }
+ // We can mutate the 'value' parameter since it's a copy-by-value local.
+ // It'll be used to represent the value left over after each division by 10.
- int index = 1;
- while (val > 0 && index <= digits)
+ for (int i = buffer.Length - 1; i >= 1; i--)
{
- builder[builder.Length - index] = (char)('0' + (val % 10));
- val = val / 10;
- index++;
+ ulong temp = '0' + value;
+ value /= 10;
+ buffer[i] = (char)(temp - (value * 10));
}
- Debug.Assert(val == 0, "DateTimeFormat.AppendNumber(): digits less than size of val");
+ Debug.Assert(value < 10);
+ buffer[0] = (char)('0' + value);
}
internal static String[] GetAllDateTimes(DateTime dateTime, char format, DateTimeFormatInfo dtfi)
diff --git a/src/Common/src/CoreLib/System/Globalization/DateTimeFormatInfo.cs b/src/Common/src/CoreLib/System/Globalization/DateTimeFormatInfo.cs
index c8f5ee477e..edec75ac85 100644
--- a/src/Common/src/CoreLib/System/Globalization/DateTimeFormatInfo.cs
+++ b/src/Common/src/CoreLib/System/Globalization/DateTimeFormatInfo.cs
@@ -1463,7 +1463,7 @@ namespace System.Globalization
//
// Actions: Retrieve the month names used in a leap year.
// If this culture does not have different month names in a leap year, the normal month name is returned.
- // Agruments: None. (can use abbreviated later if needed)
+ // Arguments: None. (can use abbreviated later if needed)
//
internal String[] internalGetLeapYearMonthNames(/*bool abbreviated*/)
{
@@ -1602,7 +1602,7 @@ namespace System.Globalization
result = this.AllYearMonthPatterns;
break;
default:
- throw new ArgumentException(SR.Format_BadFormatSpecifier, nameof(format));
+ throw new ArgumentException(SR.Format(SR.Format_BadFormatSpecifier, format), nameof(format));
}
return (result);
}
@@ -1950,7 +1950,7 @@ namespace System.Globalization
break;
default:
- throw new ArgumentException(SR.Format_BadFormatSpecifier, nameof(format));
+ throw new ArgumentException(SR.Format(SR.Format_BadFormatSpecifier, format), nameof(format));
}
// Clear the token hash table, note that even short dates could require this
diff --git a/src/Common/src/CoreLib/System/Globalization/DateTimeParse.cs b/src/Common/src/CoreLib/System/Globalization/DateTimeParse.cs
index 40962f890c..970d1765bb 100644
--- a/src/Common/src/CoreLib/System/Globalization/DateTimeParse.cs
+++ b/src/Common/src/CoreLib/System/Globalization/DateTimeParse.cs
@@ -331,7 +331,7 @@ namespace System
//
////////////////////////////////////////////////////////////////////////////
- // End NumEnd NumAmPm NumSpace NumDaySep NumTimesep MonthEnd MonthSpace MonthDSep NumDateSuff NumTimeSuff DayOfWeek YearSpace YearDateSep YearEnd TimeZone Era UTCTimeMark
+ // End NumEnd NumAmPm NumSpace NumDaySep NumTimesep MonthEnd MonthSpace MonthDSep NumDateSuff NumTimeSuff DayOfWeek YearSpace YearDateSep YearEnd TimeZone Era UTCTimeMark
private static DS[][] dateParsingStates = {
// DS.BEGIN // DS.BEGIN
new DS[] { DS.BEGIN, DS.ERROR, DS.TX_N, DS.N, DS.D_Nd, DS.T_Nt, DS.ERROR, DS.D_M, DS.D_M, DS.D_S, DS.T_S, DS.BEGIN, DS.D_Y, DS.D_Y, DS.ERROR, DS.BEGIN, DS.BEGIN, DS.ERROR},
@@ -713,7 +713,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
return false;
}
- // we have the date and time separators are same and getting a year number, then change the token to YearDateSep as
+ // we have the date and time separators are same and getting a year number, then change the token to YearDateSep as
// we are sure we are not parsing time.
dtok.dtt = DTT.YearDateSep;
break;
@@ -1002,7 +1002,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
return false;
}
- // we have the date and time separators are same and getting a Month name, then change the token to MonthDatesep as
+ // we have the date and time separators are same and getting a Month name, then change the token to MonthDatesep as
// we are sure we are not parsing time.
dtok.dtt = DTT.MonthDatesep;
break;
@@ -1200,7 +1200,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
}
else if ((!Char.IsWhiteSpace(ch)))
{
- // Anthyhing other than whitespace outside hashes is invalid
+ // Anything other than whitespace outside hashes is invalid
if (!foundStart || foundEnd)
{
return false;
@@ -1212,7 +1212,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
// The has was un-paired
return false;
}
- // Valid Hash usage: eat the hash and continue.
+ // Valid Hash usage: eat the hash and continue.
str.GetNext();
return true;
}
@@ -2108,7 +2108,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
}
if (result.Year != -1)
{
- // Aleady has a year suffix
+ // Already has a year suffix
result.SetBadDateTimeFailure();
return false;
}
@@ -2591,7 +2591,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
{
if (dtok.dtt == DTT.YearEnd || dtok.dtt == DTT.YearSpace || dtok.dtt == DTT.YearDateSep)
{
- // When time and date separators are same and we are hitting a year number while the first parsed part of the string was recognized
+ // When time and date separators are same and we are hitting a year number while the first parsed part of the string was recognized
// as part of time (and not a date) DS.T_Nt, DS.T_NNt then change the state to be a date so we try to parse it as a date instead
if (dps == DS.T_Nt)
{
@@ -2608,7 +2608,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
{
switch (dtok.dtt)
{
- // we have the case of Serbia have dates in forms 'd.M.yyyy.' so we can expect '.' after the date parts.
+ // we have the case of Serbia have dates in forms 'd.M.yyyy.' so we can expect '.' after the date parts.
// changing the token to end with space instead of Date Separator will avoid failing the parsing.
case DTT.YearDateSep: dtok.dtt = atEnd ? DTT.YearEnd : DTT.YearSpace; break;
@@ -2702,7 +2702,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
//
// We have to check day of week before we adjust to the time zone.
- // Otherwise, the value of day of week may change after adjustting to the time zone.
+ // Otherwise, the value of day of week may change after adjusting to the time zone.
//
if (raw.dayOfWeek != -1)
{
@@ -2734,7 +2734,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
{
if ((result.flags & ParseFlags.CaptureOffset) != 0)
{
- // This is a DateTimeOffset parse, so the offset will actually be captured directly, and
+ // This is a DateTimeOffset parse, so the offset will actually be captured directly, and
// no adjustment is required in most cases
return DateTimeOffsetTimeZonePostProcessing(ref str, ref result, styles);
}
@@ -2810,7 +2810,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
// Apply validation and adjustments specific to DateTimeOffset
private static Boolean DateTimeOffsetTimeZonePostProcessing(ref __DTString str, ref DateTimeResult result, DateTimeStyles styles)
{
- // For DateTimeOffset, default to the Utc or Local offset when an offset was not specified by
+ // For DateTimeOffset, default to the Utc or Local offset when an offset was not specified by
// the input string.
if ((result.flags & ParseFlags.TimeZoneUsed) == 0)
{
@@ -2833,7 +2833,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
Int64 utcTicks = result.parsedDate.Ticks - offsetTicks;
// For DateTimeOffset, both the parsed time and the corresponding UTC value must be within the boundaries
- // of a DateTime instance.
+ // of a DateTime instance.
if (utcTicks < DateTime.MinTicks || utcTicks > DateTime.MaxTicks)
{
result.SetFailure(ParseFailureKind.FormatWithOriginalDateTime, nameof(SR.Format_UTCOutOfRange));
@@ -2860,7 +2860,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
}
// The constructor should always succeed because of the range check earlier in the function
- // Althought it is UTC, internally DateTimeOffset does not use this flag
+ // Although it is UTC, internally DateTimeOffset does not use this flag
result.parsedDate = new DateTime(utcTicks, DateTimeKind.Utc);
result.timeZoneOffset = TimeSpan.Zero;
}
@@ -3668,7 +3668,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
}
}
- // assume the offset is Local
+ // assume the offset is Local
return DateTime.Now;
}
@@ -4218,7 +4218,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
}
// The "r" and "u" formats incorrectly quoted 'GMT' and 'Z', respectively. We cannot
- // correct this mistake for DateTime.ParseExact for compatibility reasons, but we can
+ // correct this mistake for DateTime.ParseExact for compatibility reasons, but we can
// fix it for DateTimeOffset.ParseExact as DateTimeOffset has not been publically released
// with this issue.
if ((result.flags & ParseFlags.CaptureOffset) != 0)
@@ -5045,7 +5045,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
{
return false;
}
- if (m_info.Compare(Value.Slice(thisPosition, segmentLength), target.AsReadOnlySpan().Slice(targetPosition, segmentLength), CompareOptions.IgnoreCase) != 0)
+ if (m_info.CompareOptionIgnoreCase(Value.Slice(thisPosition, segmentLength), target.AsSpan(targetPosition, segmentLength)) != 0)
{
return false;
}
@@ -5071,7 +5071,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
{
return false;
}
- if (m_info.Compare(Value.Slice(thisPosition, segmentLength), target.AsReadOnlySpan().Slice(targetPosition, segmentLength), CompareOptions.IgnoreCase) != 0)
+ if (m_info.CompareOptionIgnoreCase(Value.Slice(thisPosition, segmentLength), target.AsSpan(targetPosition, segmentLength)) != 0)
{
return false;
}
@@ -5286,14 +5286,17 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
// Check if the last character is a quote.
if (ch == '\'' || ch == '\"')
{
- if (Char.IsWhiteSpace(Value[i - 1]))
+ if (char.IsWhiteSpace(Value[i - 1]))
{
i--;
- while (i >= 1 && Char.IsWhiteSpace(Value[i - 1]))
+ while (i >= 1 && char.IsWhiteSpace(Value[i - 1]))
{
i--;
}
- Value = Value.Remove(i, Value.Length - 1 - i);
+ Span<char> result = new char[i + 1];
+ result[i] = ch;
+ Value.Slice(0, i).CopyTo(result);
+ Value = result;
}
}
}
@@ -5311,13 +5314,16 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
// Check if the last character is a quote.
if (ch == '\'' || ch == '\"')
{
- while ((i + 1) < Length && Char.IsWhiteSpace(Value[i + 1]))
+ while ((i + 1) < Length && char.IsWhiteSpace(Value[i + 1]))
{
i++;
}
if (i != 0)
{
- Value = Value.Remove(1, i);
+ Span<char> result = new char[Value.Length - i];
+ result[0] = ch;
+ Value.Slice(i + 1).CopyTo(result.Slice(1));
+ Value = result;
}
}
}
diff --git a/src/Common/src/CoreLib/System/Globalization/DateTimeStyles.cs b/src/Common/src/CoreLib/System/Globalization/DateTimeStyles.cs
index 79232ff199..bf68ac91d5 100644
--- a/src/Common/src/CoreLib/System/Globalization/DateTimeStyles.cs
+++ b/src/Common/src/CoreLib/System/Globalization/DateTimeStyles.cs
@@ -36,7 +36,7 @@ namespace System.Globalization
NoCurrentDateDefault = 0x00000008,
// When parsing a date/time string, if a timezone specifier ("GMT","Z","+xxxx", "-xxxx" exists), we will
- // ajdust the parsed time based to GMT.
+ // adjust the parsed time based to GMT.
AdjustToUniversal = 0x00000010,
diff --git a/src/Common/src/CoreLib/System/Globalization/DaylightTime.cs b/src/Common/src/CoreLib/System/Globalization/DaylightTime.cs
index e6920b3666..72a572c97d 100644
--- a/src/Common/src/CoreLib/System/Globalization/DaylightTime.cs
+++ b/src/Common/src/CoreLib/System/Globalization/DaylightTime.cs
@@ -11,10 +11,6 @@ namespace System.Globalization
private readonly DateTime _end;
private readonly TimeSpan _delta;
- private DaylightTime()
- {
- }
-
public DaylightTime(DateTime start, DateTime end, TimeSpan delta)
{
_start = start;
diff --git a/src/Common/src/CoreLib/System/Globalization/GlobalizationExtensions.cs b/src/Common/src/CoreLib/System/Globalization/GlobalizationExtensions.cs
new file mode 100644
index 0000000000..007283aa6b
--- /dev/null
+++ b/src/Common/src/CoreLib/System/Globalization/GlobalizationExtensions.cs
@@ -0,0 +1,32 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics;
+
+namespace System.Globalization
+{
+ public static class GlobalizationExtensions
+ {
+ public static StringComparer GetStringComparer(this CompareInfo compareInfo, CompareOptions options)
+ {
+ if (compareInfo == null)
+ {
+ throw new ArgumentNullException(nameof(compareInfo));
+ }
+
+ if (options == CompareOptions.Ordinal)
+ {
+ return StringComparer.Ordinal;
+ }
+
+ if (options == CompareOptions.OrdinalIgnoreCase)
+ {
+ return StringComparer.OrdinalIgnoreCase;
+ }
+
+ return new CultureAwareComparer(compareInfo, options);
+ }
+ }
+}
diff --git a/src/Common/src/CoreLib/System/Globalization/GregorianCalendar.cs b/src/Common/src/CoreLib/System/Globalization/GregorianCalendar.cs
index 16023209ea..94963a19cc 100644
--- a/src/Common/src/CoreLib/System/Globalization/GregorianCalendar.cs
+++ b/src/Common/src/CoreLib/System/Globalization/GregorianCalendar.cs
@@ -520,25 +520,11 @@ namespace System.Globalization
throw new ArgumentOutOfRangeException(nameof(era), SR.ArgumentOutOfRange_InvalidEraValue);
}
- internal override Boolean TryToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era, out DateTime result)
+ internal override bool TryToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era, out DateTime result)
{
if (era == CurrentEra || era == ADEra)
{
- try
- {
- result = new DateTime(year, month, day, hour, minute, second, millisecond);
- return true;
- }
- catch (ArgumentOutOfRangeException)
- {
- result = DateTime.Now;
- return false;
- }
- catch (ArgumentException)
- {
- result = DateTime.Now;
- return false;
- }
+ return DateTime.TryCreate(year, month, day, hour, minute, second, millisecond, out result);
}
result = DateTime.MinValue;
return false;
diff --git a/src/Common/src/CoreLib/System/Globalization/HijriCalendar.Win32.cs b/src/Common/src/CoreLib/System/Globalization/HijriCalendar.Win32.cs
index 09b1f20c48..64a73fb81d 100644
--- a/src/Common/src/CoreLib/System/Globalization/HijriCalendar.Win32.cs
+++ b/src/Common/src/CoreLib/System/Globalization/HijriCalendar.Win32.cs
@@ -69,7 +69,7 @@ namespace System.Globalization
{
try
{
- int advance = Int32.Parse(str.AsReadOnlySpan().Slice(HijriAdvanceRegKeyEntry.Length), provider:CultureInfo.InvariantCulture);
+ int advance = Int32.Parse(str.AsSpan(HijriAdvanceRegKeyEntry.Length), provider:CultureInfo.InvariantCulture);
if ((advance >= MinAdvancedHijri) && (advance <= MaxAdvancedHijri))
{
hijriAdvance = advance;
diff --git a/src/Common/src/CoreLib/System/Globalization/IdnMapping.Unix.cs b/src/Common/src/CoreLib/System/Globalization/IdnMapping.Unix.cs
index 2bbda0d3a7..5320936a73 100644
--- a/src/Common/src/CoreLib/System/Globalization/IdnMapping.Unix.cs
+++ b/src/Common/src/CoreLib/System/Globalization/IdnMapping.Unix.cs
@@ -23,7 +23,7 @@ namespace System.Globalization
if (estimatedLength < StackallocThreshold)
{
char* outputStack = stackalloc char[estimatedLength];
- actualLength = Interop.GlobalizationInterop.ToAscii(flags, unicode, count, outputStack, estimatedLength);
+ actualLength = Interop.Globalization.ToAscii(flags, unicode, count, outputStack, estimatedLength);
if (actualLength > 0 && actualLength <= estimatedLength)
{
return new string(outputStack, 0, actualLength);
@@ -31,7 +31,7 @@ namespace System.Globalization
}
else
{
- actualLength = Interop.GlobalizationInterop.ToAscii(flags, unicode, count, null, 0);
+ actualLength = Interop.Globalization.ToAscii(flags, unicode, count, null, 0);
}
if (actualLength == 0)
{
@@ -41,7 +41,7 @@ namespace System.Globalization
char[] outputHeap = new char[actualLength];
fixed (char* pOutputHeap = &outputHeap[0])
{
- actualLength = Interop.GlobalizationInterop.ToAscii(flags, unicode, count, pOutputHeap, actualLength);
+ actualLength = Interop.Globalization.ToAscii(flags, unicode, count, pOutputHeap, actualLength);
if (actualLength == 0 || actualLength > outputHeap.Length)
{
throw new ArgumentException(SR.Argument_IdnIllegalName, nameof(unicode));
@@ -77,7 +77,7 @@ namespace System.Globalization
{
Debug.Assert(!GlobalizationMode.Invariant);
- int realLen = Interop.GlobalizationInterop.ToUnicode(flags, ascii, count, output, outputLength);
+ int realLen = Interop.Globalization.ToUnicode(flags, ascii, count, output, outputLength);
if (realLen == 0)
{
@@ -108,8 +108,8 @@ namespace System.Globalization
get
{
int flags =
- (AllowUnassigned ? Interop.GlobalizationInterop.AllowUnassigned : 0) |
- (UseStd3AsciiRules ? Interop.GlobalizationInterop.UseStd3AsciiRules : 0);
+ (AllowUnassigned ? Interop.Globalization.AllowUnassigned : 0) |
+ (UseStd3AsciiRules ? Interop.Globalization.UseStd3AsciiRules : 0);
return (uint)flags;
}
}
@@ -123,7 +123,7 @@ namespace System.Globalization
/// </summary>
private static unsafe void CheckInvalidIdnCharacters(char* s, int count, uint flags, string paramName)
{
- if ((flags & Interop.GlobalizationInterop.UseStd3AsciiRules) == 0)
+ if ((flags & Interop.Globalization.UseStd3AsciiRules) == 0)
{
for (int i = 0; i < count; i++)
{
diff --git a/src/Common/src/CoreLib/System/Globalization/InternalGlobalizationHelper.cs b/src/Common/src/CoreLib/System/Globalization/InternalGlobalizationHelper.cs
index f5eea1b629..60abcecf61 100644
--- a/src/Common/src/CoreLib/System/Globalization/InternalGlobalizationHelper.cs
+++ b/src/Common/src/CoreLib/System/Globalization/InternalGlobalizationHelper.cs
@@ -6,7 +6,7 @@ namespace System.Globalization
{
internal class InternalGlobalizationHelper
{
- // Copied from the TimeSpan to be used inside the globalization code and avoid internal dependancy on TimeSpan class
+ // Copied from the TimeSpan to be used inside the globalization code and avoid internal dependency on TimeSpan class
internal static long TimeToTicks(int hour, int minute, int second)
{
// totalSeconds is bounded by 2^31 * 2^12 + 2^31 * 2^8 + 2^31,
diff --git a/src/Common/src/CoreLib/System/Globalization/JapaneseCalendar.Unix.cs b/src/Common/src/CoreLib/System/Globalization/JapaneseCalendar.Unix.cs
index 51ff8095a3..5e66c94b2c 100644
--- a/src/Common/src/CoreLib/System/Globalization/JapaneseCalendar.Unix.cs
+++ b/src/Common/src/CoreLib/System/Globalization/JapaneseCalendar.Unix.cs
@@ -31,7 +31,7 @@ namespace System.Globalization
List<EraInfo> eras = new List<EraInfo>();
int lastMaxYear = GregorianCalendar.MaxYear;
- int latestEra = Interop.GlobalizationInterop.GetLatestJapaneseEra();
+ int latestEra = Interop.Globalization.GetLatestJapaneseEra();
for (int i = latestEra; i >= 0; i--)
{
DateTime dt;
@@ -79,7 +79,7 @@ namespace System.Globalization
int startYear;
int startMonth;
int startDay;
- bool result = Interop.GlobalizationInterop.GetJapaneseEraStartDate(
+ bool result = Interop.Globalization.GetJapaneseEraStartDate(
era,
out startYear,
out startMonth,
diff --git a/src/Common/src/CoreLib/System/Globalization/JapaneseCalendar.Win32.cs b/src/Common/src/CoreLib/System/Globalization/JapaneseCalendar.Win32.cs
index 9ea6c21c2e..1d0180b00e 100644
--- a/src/Common/src/CoreLib/System/Globalization/JapaneseCalendar.Win32.cs
+++ b/src/Common/src/CoreLib/System/Globalization/JapaneseCalendar.Win32.cs
@@ -159,7 +159,7 @@ namespace System.Globalization
int month;
int day;
- ReadOnlySpan<char> valueSpan = value.AsReadOnlySpan();
+ ReadOnlySpan<char> valueSpan = value.AsSpan();
if (!Int32.TryParse(valueSpan.Slice(0, 4), NumberStyles.None, NumberFormatInfo.InvariantInfo, out year) ||
!Int32.TryParse(valueSpan.Slice(5, 2), NumberStyles.None, NumberFormatInfo.InvariantInfo, out month) ||
!Int32.TryParse(valueSpan.Slice(8, 2), NumberStyles.None, NumberFormatInfo.InvariantInfo, out day))
diff --git a/src/Common/src/CoreLib/System/Globalization/Normalization.Unix.cs b/src/Common/src/CoreLib/System/Globalization/Normalization.Unix.cs
index a25c1b9380..443dbae530 100644
--- a/src/Common/src/CoreLib/System/Globalization/Normalization.Unix.cs
+++ b/src/Common/src/CoreLib/System/Globalization/Normalization.Unix.cs
@@ -20,7 +20,7 @@ namespace System.Globalization
ValidateArguments(strInput, normalizationForm);
- int ret = Interop.GlobalizationInterop.IsNormalized(normalizationForm, strInput, strInput.Length);
+ int ret = Interop.Globalization.IsNormalized(normalizationForm, strInput, strInput.Length);
if (ret == -1)
{
@@ -45,7 +45,7 @@ namespace System.Globalization
for (int attempts = 2; attempts > 0; attempts--)
{
- int realLen = Interop.GlobalizationInterop.NormalizeString(normalizationForm, strInput, strInput.Length, buf, buf.Length);
+ int realLen = Interop.Globalization.NormalizeString(normalizationForm, strInput, strInput.Length, buf, buf.Length);
if (realLen == -1)
{
diff --git a/src/Common/src/CoreLib/System/Globalization/TextInfo.Unix.cs b/src/Common/src/CoreLib/System/Globalization/TextInfo.Unix.cs
index dd2433d18f..d13d3e8cee 100644
--- a/src/Common/src/CoreLib/System/Globalization/TextInfo.Unix.cs
+++ b/src/Common/src/CoreLib/System/Globalization/TextInfo.Unix.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
+using System.Runtime.InteropServices;
using System.Security;
using System.Text;
@@ -64,6 +65,54 @@ namespace System.Globalization
return result;
}
+ internal unsafe void ChangeCase(ReadOnlySpan<char> source, Span<char> destination, bool toUpper)
+ {
+ Debug.Assert(!_invariantMode);
+ Debug.Assert(destination.Length >= source.Length);
+
+ if (source.IsEmpty)
+ {
+ return;
+ }
+
+ fixed (char* pSource = &MemoryMarshal.GetReference(source))
+ {
+ fixed (char* pResult = &MemoryMarshal.GetReference(destination))
+ {
+ if (IsAsciiCasingSameAsInvariant)
+ {
+ int length = 0;
+ char* a = pSource, b = pResult;
+ if (toUpper)
+ {
+ while (length < source.Length && *a < 0x80)
+ {
+ *b++ = ToUpperAsciiInvariant(*a++);
+ length++;
+ }
+ }
+ else
+ {
+ while (length < source.Length && *a < 0x80)
+ {
+ *b++ = ToLowerAsciiInvariant(*a++);
+ length++;
+ }
+ }
+
+ if (length != source.Length)
+ {
+ ChangeCase(a, source.Length - length, b, destination.Length - length, toUpper);
+ }
+ }
+ else
+ {
+ ChangeCase(pSource, source.Length, pResult, destination.Length, toUpper);
+ }
+ }
+ }
+ }
+
private unsafe char ChangeCase(char c, bool toUpper)
{
Debug.Assert(!_invariantMode);
@@ -94,7 +143,7 @@ namespace System.Globalization
if (IsInvariant)
{
- Interop.GlobalizationInterop.ChangeCaseInvariant(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper);
+ Interop.Globalization.ChangeCaseInvariant(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper);
}
else
{
@@ -104,11 +153,11 @@ namespace System.Globalization
}
if (_needsTurkishCasing == Tristate.True)
{
- Interop.GlobalizationInterop.ChangeCaseTurkish(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper);
+ Interop.Globalization.ChangeCaseTurkish(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper);
}
else
{
- Interop.GlobalizationInterop.ChangeCase(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper);
+ Interop.Globalization.ChangeCase(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper);
}
}
}
diff --git a/src/Common/src/CoreLib/System/Globalization/TextInfo.Windows.cs b/src/Common/src/CoreLib/System/Globalization/TextInfo.Windows.cs
index 8b27e42d1d..015b37fcc4 100644
--- a/src/Common/src/CoreLib/System/Globalization/TextInfo.Windows.cs
+++ b/src/Common/src/CoreLib/System/Globalization/TextInfo.Windows.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
+using System.Runtime.InteropServices;
namespace System.Globalization
{
@@ -75,6 +76,43 @@ namespace System.Globalization
return result;
}
+ internal unsafe void ChangeCase(ReadOnlySpan<char> source, Span<char> destination, bool toUpper)
+ {
+ Debug.Assert(!_invariantMode);
+ Debug.Assert(destination.Length >= source.Length);
+
+ if (source.IsEmpty)
+ {
+ return;
+ }
+
+ int ret;
+
+ // Check for Invariant to avoid A/V in LCMapStringEx
+ uint linguisticCasing = IsInvariantLocale(_textInfoName) ? 0 : LCMAP_LINGUISTIC_CASING;
+
+ fixed (char* pSource = &MemoryMarshal.GetReference(source))
+ fixed (char* pResult = &MemoryMarshal.GetReference(destination))
+ {
+ ret = Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _textInfoName,
+ linguisticCasing | (toUpper ? LCMAP_UPPERCASE : LCMAP_LOWERCASE),
+ pSource,
+ source.Length,
+ pResult,
+ source.Length,
+ null,
+ null,
+ _sortHandle);
+ }
+
+ if (ret == 0)
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_ReadOnly);
+ }
+
+ Debug.Assert(ret == source.Length, "Expected getting the same length of the original span");
+ }
+
private unsafe char ChangeCase(char c, bool toUpper)
{
Debug.Assert(!_invariantMode);
diff --git a/src/Common/src/CoreLib/System/Globalization/TextInfo.cs b/src/Common/src/CoreLib/System/Globalization/TextInfo.cs
index d9d6f3bd3b..431458bc7a 100644
--- a/src/Common/src/CoreLib/System/Globalization/TextInfo.cs
+++ b/src/Common/src/CoreLib/System/Globalization/TextInfo.cs
@@ -80,17 +80,6 @@ namespace System.Globalization
throw new PlatformNotSupportedException();
}
- //
- // Internal ordinal comparison functions
- //
-
- internal static int GetHashCodeOrdinalIgnoreCase(string s)
- {
- // This is the same as an case insensitive hash for Invariant
- // (not necessarily true for sorting, but OK for casing & then we apply normal hash code rules)
- return Invariant.GetCaseInsensitiveHashCode(s);
- }
-
public virtual int ANSICodePage => _cultureData.IDEFAULTANSICODEPAGE;
public virtual int OEMCodePage => _cultureData.IDEFAULTOEMCODEPAGE;
@@ -258,6 +247,16 @@ namespace System.Globalization
}
}
+ internal void ToLowerAsciiInvariant(ReadOnlySpan<char> source, Span<char> destination)
+ {
+ Debug.Assert(destination.Length >= source.Length);
+
+ for (int i = 0; i < source.Length; i++)
+ {
+ destination[i] = ToLowerAsciiInvariant(source[i]);
+ }
+ }
+
private unsafe string ToUpperAsciiInvariant(string s)
{
if (s.Length == 0)
@@ -304,6 +303,16 @@ namespace System.Globalization
}
}
+ internal void ToUpperAsciiInvariant(ReadOnlySpan<char> source, Span<char> destination)
+ {
+ Debug.Assert(destination.Length >= source.Length);
+
+ for (int i = 0; i < source.Length; i++)
+ {
+ destination[i] = ToUpperAsciiInvariant(source[i]);
+ }
+ }
+
private static char ToLowerAsciiInvariant(char c)
{
if ((uint)(c - 'A') <= (uint)('Z' - 'A'))
@@ -673,64 +682,5 @@ namespace System.Globalization
|| uc == UnicodeCategory.ModifierLetter
|| uc == UnicodeCategory.OtherLetter);
}
-
- //
- // Get case-insensitive hash code for the specified string.
- //
- internal unsafe int GetCaseInsensitiveHashCode(string str)
- {
- // Validate inputs
- if (str == null)
- {
- throw new ArgumentNullException(nameof(str));
- }
-
- // This code assumes that ASCII casing is safe for whatever context is passed in.
- // this is true today, because we only ever call these methods on Invariant. It would be ideal to refactor
- // these methods so they were correct by construction and we could only ever use Invariant.
-
- uint hash = 5381;
- uint c;
-
- // Note: We assume that str contains only ASCII characters until
- // we hit a non-ASCII character to optimize the common case.
- for (int i = 0; i < str.Length; i++)
- {
- c = str[i];
- if (c >= 0x80)
- {
- return GetCaseInsensitiveHashCodeSlow(str);
- }
-
- // If we have a lowercase character, ANDing off 0x20
- // will make it an uppercase character.
- if ((c - 'a') <= ('z' - 'a'))
- {
- c = (uint)((int)c & ~0x20);
- }
-
- hash = ((hash << 5) + hash) ^ c;
- }
-
- return (int)hash;
- }
-
- private unsafe int GetCaseInsensitiveHashCodeSlow(string str)
- {
- Debug.Assert(str != null);
-
- string upper = ToUpper(str);
-
- uint hash = 5381;
- uint c;
-
- for (int i = 0; i < upper.Length; i++)
- {
- c = upper[i];
- hash = ((hash << 5) + hash) ^ c;
- }
-
- return (int)hash;
- }
}
}
diff --git a/src/Common/src/CoreLib/System/Globalization/TimeSpanFormat.cs b/src/Common/src/CoreLib/System/Globalization/TimeSpanFormat.cs
index bf12b246b0..a66e4600aa 100644
--- a/src/Common/src/CoreLib/System/Globalization/TimeSpanFormat.cs
+++ b/src/Common/src/CoreLib/System/Globalization/TimeSpanFormat.cs
@@ -4,6 +4,7 @@
using System.Text;
using System.Diagnostics;
+using System.Runtime.InteropServices;
namespace System.Globalization
{
@@ -315,7 +316,7 @@ namespace System.Globalization
if (nextChar >= 0 && nextChar != (int)'%')
{
char nextCharChar = (char)nextChar;
- StringBuilder origStringBuilder = FormatCustomized(value, ReadOnlySpan<char>.DangerousCreate(null, ref nextCharChar, 1), dtfi, result);
+ StringBuilder origStringBuilder = FormatCustomized(value, MemoryMarshal.CreateReadOnlySpan<char>(ref nextCharChar, 1), dtfi, result);
Debug.Assert(ReferenceEquals(origStringBuilder, result));
tokenLen = 2;
}
diff --git a/src/Common/src/CoreLib/System/Globalization/TimeSpanParse.cs b/src/Common/src/CoreLib/System/Globalization/TimeSpanParse.cs
index ae77957cec..51fac39d0a 100644
--- a/src/Common/src/CoreLib/System/Globalization/TimeSpanParse.cs
+++ b/src/Common/src/CoreLib/System/Globalization/TimeSpanParse.cs
@@ -274,83 +274,83 @@ namespace System.Globalization
internal bool FullAppCompatMatch(TimeSpanFormat.FormatLiterals pattern) =>
_sepCount == 5
&& _numCount == 4
- && StringSpanHelpers.Equals(_literals0, pattern.Start)
- && StringSpanHelpers.Equals(_literals1, pattern.DayHourSep)
- && StringSpanHelpers.Equals(_literals2, pattern.HourMinuteSep)
- && StringSpanHelpers.Equals(_literals3, pattern.AppCompatLiteral)
- && StringSpanHelpers.Equals(_literals4, pattern.End);
+ && _literals0.EqualsOrdinal(pattern.Start)
+ && _literals1.EqualsOrdinal(pattern.DayHourSep)
+ && _literals2.EqualsOrdinal(pattern.HourMinuteSep)
+ && _literals3.EqualsOrdinal(pattern.AppCompatLiteral)
+ && _literals4.EqualsOrdinal(pattern.End);
internal bool PartialAppCompatMatch(TimeSpanFormat.FormatLiterals pattern) =>
_sepCount == 4
&& _numCount == 3
- && StringSpanHelpers.Equals(_literals0, pattern.Start)
- && StringSpanHelpers.Equals(_literals1, pattern.HourMinuteSep)
- && StringSpanHelpers.Equals(_literals2, pattern.AppCompatLiteral)
- && StringSpanHelpers.Equals(_literals3, pattern.End);
+ && _literals0.EqualsOrdinal(pattern.Start)
+ && _literals1.EqualsOrdinal(pattern.HourMinuteSep)
+ && _literals2.EqualsOrdinal(pattern.AppCompatLiteral)
+ && _literals3.EqualsOrdinal(pattern.End);
/// <summary>DHMSF (all values matched)</summary>
internal bool FullMatch(TimeSpanFormat.FormatLiterals pattern) =>
_sepCount == MaxLiteralTokens
&& _numCount == MaxNumericTokens
- && StringSpanHelpers.Equals(_literals0, pattern.Start)
- && StringSpanHelpers.Equals(_literals1, pattern.DayHourSep)
- && StringSpanHelpers.Equals(_literals2, pattern.HourMinuteSep)
- && StringSpanHelpers.Equals(_literals3, pattern.MinuteSecondSep)
- && StringSpanHelpers.Equals(_literals4, pattern.SecondFractionSep)
- && StringSpanHelpers.Equals(_literals5, pattern.End);
+ && _literals0.EqualsOrdinal(pattern.Start)
+ && _literals1.EqualsOrdinal(pattern.DayHourSep)
+ && _literals2.EqualsOrdinal(pattern.HourMinuteSep)
+ && _literals3.EqualsOrdinal(pattern.MinuteSecondSep)
+ && _literals4.EqualsOrdinal(pattern.SecondFractionSep)
+ && _literals5.EqualsOrdinal(pattern.End);
/// <summary>D (no hours, minutes, seconds, or fractions)</summary>
internal bool FullDMatch(TimeSpanFormat.FormatLiterals pattern) =>
_sepCount == 2
&& _numCount == 1
- && StringSpanHelpers.Equals(_literals0, pattern.Start)
- && StringSpanHelpers.Equals(_literals1, pattern.End);
+ && _literals0.EqualsOrdinal(pattern.Start)
+ && _literals1.EqualsOrdinal(pattern.End);
/// <summary>HM (no days, seconds, or fractions)</summary>
internal bool FullHMMatch(TimeSpanFormat.FormatLiterals pattern) =>
_sepCount == 3
&& _numCount == 2
- && StringSpanHelpers.Equals(_literals0, pattern.Start)
- && StringSpanHelpers.Equals(_literals1, pattern.HourMinuteSep)
- && StringSpanHelpers.Equals(_literals2, pattern.End);
+ && _literals0.EqualsOrdinal(pattern.Start)
+ && _literals1.EqualsOrdinal(pattern.HourMinuteSep)
+ && _literals2.EqualsOrdinal(pattern.End);
/// <summary>DHM (no seconds or fraction)</summary>
internal bool FullDHMMatch(TimeSpanFormat.FormatLiterals pattern) =>
_sepCount == 4
&& _numCount == 3
- && StringSpanHelpers.Equals(_literals0, pattern.Start)
- && StringSpanHelpers.Equals(_literals1, pattern.DayHourSep)
- && StringSpanHelpers.Equals(_literals2, pattern.HourMinuteSep)
- && StringSpanHelpers.Equals(_literals3, pattern.End);
+ && _literals0.EqualsOrdinal(pattern.Start)
+ && _literals1.EqualsOrdinal(pattern.DayHourSep)
+ && _literals2.EqualsOrdinal(pattern.HourMinuteSep)
+ && _literals3.EqualsOrdinal(pattern.End);
/// <summary>HMS (no days or fraction)</summary>
internal bool FullHMSMatch(TimeSpanFormat.FormatLiterals pattern) =>
_sepCount == 4
&& _numCount == 3
- && StringSpanHelpers.Equals(_literals0, pattern.Start)
- && StringSpanHelpers.Equals(_literals1, pattern.HourMinuteSep)
- && StringSpanHelpers.Equals(_literals2, pattern.MinuteSecondSep)
- && StringSpanHelpers.Equals(_literals3, pattern.End);
+ && _literals0.EqualsOrdinal(pattern.Start)
+ && _literals1.EqualsOrdinal(pattern.HourMinuteSep)
+ && _literals2.EqualsOrdinal(pattern.MinuteSecondSep)
+ && _literals3.EqualsOrdinal(pattern.End);
/// <summary>DHMS (no fraction)</summary>
internal bool FullDHMSMatch(TimeSpanFormat.FormatLiterals pattern) =>
_sepCount == 5
&& _numCount == 4
- && StringSpanHelpers.Equals(_literals0, pattern.Start)
- && StringSpanHelpers.Equals(_literals1, pattern.DayHourSep)
- && StringSpanHelpers.Equals(_literals2, pattern.HourMinuteSep)
- && StringSpanHelpers.Equals(_literals3, pattern.MinuteSecondSep)
- && StringSpanHelpers.Equals(_literals4, pattern.End);
+ && _literals0.EqualsOrdinal(pattern.Start)
+ && _literals1.EqualsOrdinal(pattern.DayHourSep)
+ && _literals2.EqualsOrdinal(pattern.HourMinuteSep)
+ && _literals3.EqualsOrdinal(pattern.MinuteSecondSep)
+ && _literals4.EqualsOrdinal(pattern.End);
/// <summary>HMSF (no days)</summary>
internal bool FullHMSFMatch(TimeSpanFormat.FormatLiterals pattern) =>
_sepCount == 5
&& _numCount == 4
- && StringSpanHelpers.Equals(_literals0, pattern.Start)
- && StringSpanHelpers.Equals(_literals1, pattern.HourMinuteSep)
- && StringSpanHelpers.Equals(_literals2, pattern.MinuteSecondSep)
- && StringSpanHelpers.Equals(_literals3, pattern.SecondFractionSep)
- && StringSpanHelpers.Equals(_literals4, pattern.End);
+ && _literals0.EqualsOrdinal(pattern.Start)
+ && _literals1.EqualsOrdinal(pattern.HourMinuteSep)
+ && _literals2.EqualsOrdinal(pattern.MinuteSecondSep)
+ && _literals3.EqualsOrdinal(pattern.SecondFractionSep)
+ && _literals4.EqualsOrdinal(pattern.End);
internal TTT _lastSeenTTT;
internal int _tokenCount;
diff --git a/src/Common/src/CoreLib/System/Guid.Unix.cs b/src/Common/src/CoreLib/System/Guid.Unix.cs
new file mode 100644
index 0000000000..442e7f8837
--- /dev/null
+++ b/src/Common/src/CoreLib/System/Guid.Unix.cs
@@ -0,0 +1,38 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+
+namespace System
+{
+ partial struct Guid
+ {
+ // This will create a new random guid based on the https://www.ietf.org/rfc/rfc4122.txt
+ public static unsafe Guid NewGuid()
+ {
+ Guid g;
+ Interop.GetRandomBytes((byte*)&g, sizeof(Guid));
+
+ const ushort VersionMask = 0xF000;
+ const ushort RandomGuidVersion = 0x4000;
+
+ const byte ClockSeqHiAndReservedMask = 0xC0;
+ const byte ClockSeqHiAndReservedValue = 0x80;
+
+ // Modify bits indicating the type of the GUID
+
+ unchecked
+ {
+ // time_hi_and_version
+ g._c = (short)((g._c & ~VersionMask) | RandomGuidVersion);
+ // clock_seq_hi_and_reserved
+ g._d = (byte)((g._d & ~ClockSeqHiAndReservedMask) | ClockSeqHiAndReservedValue);
+ }
+
+ return g;
+ }
+ }
+}
+
diff --git a/src/Common/src/CoreLib/System/Guid.Windows.cs b/src/Common/src/CoreLib/System/Guid.Windows.cs
new file mode 100644
index 0000000000..f00fbe45b3
--- /dev/null
+++ b/src/Common/src/CoreLib/System/Guid.Windows.cs
@@ -0,0 +1,29 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System
+{
+ partial struct Guid
+ {
+ public static Guid NewGuid()
+ {
+ // CoCreateGuid should never return Guid.Empty, since it attempts to maintain some
+ // uniqueness guarantees.
+
+ Guid g;
+ int hr = Interop.Ole32.CoCreateGuid(out g);
+ // We don't expect that this will ever throw an error, none are even documented, and so we don't want to pull
+ // in the HR to ComException mappings into the core library just for this so we will try a generic exception if
+ // we ever hit this condition.
+ if (hr != 0)
+ {
+ Exception ex = new Exception();
+ ex.SetErrorCode(hr);
+ throw ex;
+ }
+ return g;
+ }
+ }
+}
+
diff --git a/src/Common/src/CoreLib/System/Guid.cs b/src/Common/src/CoreLib/System/Guid.cs
index 423d5bc78c..37a8dce94c 100644
--- a/src/Common/src/CoreLib/System/Guid.cs
+++ b/src/Common/src/CoreLib/System/Guid.cs
@@ -449,7 +449,7 @@ namespace System
}
// Check for braces
- bool bracesExistInString = (guidString.IndexOf('{', 0) >= 0);
+ bool bracesExistInString = (guidString.IndexOf('{') >= 0);
if (bracesExistInString)
{
@@ -471,7 +471,7 @@ namespace System
}
// Check for parenthesis
- bool parenthesisExistInString = (guidString.IndexOf('(', 0) >= 0);
+ bool parenthesisExistInString = (guidString.IndexOf('(') >= 0);
if (parenthesisExistInString)
{
@@ -548,7 +548,7 @@ namespace System
// Find the end of this hex number (since it is not fixed length)
numStart = 3;
- numLen = guidString.IndexOf(',', numStart) - numStart;
+ numLen = guidString.Slice(numStart).IndexOf(',');
if (numLen <= 0)
{
result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidComma));
@@ -566,7 +566,7 @@ namespace System
}
// +3 to get by ',0x'
numStart = numStart + numLen + 3;
- numLen = guidString.IndexOf(',', numStart) - numStart;
+ numLen = guidString.Slice(numStart).IndexOf(',');
if (numLen <= 0)
{
result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidComma));
@@ -584,7 +584,7 @@ namespace System
}
// +3 to get by ',0x'
numStart = numStart + numLen + 3;
- numLen = guidString.IndexOf(',', numStart) - numStart;
+ numLen = guidString.Slice(numStart).IndexOf(',');
if (numLen <= 0)
{
result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidComma));
@@ -621,7 +621,7 @@ namespace System
// Calculate number length
if (i < 7) // first 7 cases
{
- numLen = guidString.IndexOf(',', numStart) - numStart;
+ numLen = guidString.Slice(numStart).IndexOf(',');
if (numLen <= 0)
{
result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidComma));
@@ -630,7 +630,7 @@ namespace System
}
else // last case ends with '}', not ','
{
- numLen = guidString.IndexOf('}', numStart) - numStart;
+ numLen = guidString.Slice(numStart).IndexOf('}');
if (numLen <= 0)
{
result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_GuidBraceAfterLastNumber));
@@ -1232,7 +1232,7 @@ namespace System
return (char)((a > 9) ? a - 10 + 0x61 : a + 0x30);
}
- unsafe private static int HexsToChars(char* guidChars, int a, int b)
+ private static unsafe int HexsToChars(char* guidChars, int a, int b)
{
guidChars[0] = HexToChar(a >> 4);
guidChars[1] = HexToChar(a);
@@ -1243,7 +1243,7 @@ namespace System
return 4;
}
- unsafe private static int HexsToCharsHexOutput(char* guidChars, int a, int b)
+ private static unsafe int HexsToCharsHexOutput(char* guidChars, int a, int b)
{
guidChars[0] = '0';
guidChars[1] = 'x';
diff --git a/src/Common/src/CoreLib/System/IO/DriveNotFoundException.cs b/src/Common/src/CoreLib/System/IO/DriveNotFoundException.cs
deleted file mode 100644
index 3f2c88c74b..0000000000
--- a/src/Common/src/CoreLib/System/IO/DriveNotFoundException.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Runtime.Serialization;
-
-namespace System.IO
-{
- //Thrown when trying to access a drive that is not available.
- [Serializable]
- [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
- internal class DriveNotFoundException : IOException
- {
- public DriveNotFoundException()
- : base(SR.Arg_DriveNotFoundException)
- {
- HResult = HResults.COR_E_DIRECTORYNOTFOUND;
- }
-
- public DriveNotFoundException(string message)
- : base(message)
- {
- HResult = HResults.COR_E_DIRECTORYNOTFOUND;
- }
-
- public DriveNotFoundException(string message, Exception innerException)
- : base(message, innerException)
- {
- HResult = HResults.COR_E_DIRECTORYNOTFOUND;
- }
-
- protected DriveNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
- {
- }
- }
-}
diff --git a/src/Common/src/CoreLib/System/IO/FileStream.Unix.cs b/src/Common/src/CoreLib/System/IO/FileStream.Unix.cs
index 34164abc33..d9fcf65711 100644
--- a/src/Common/src/CoreLib/System/IO/FileStream.Unix.cs
+++ b/src/Common/src/CoreLib/System/IO/FileStream.Unix.cs
@@ -240,7 +240,7 @@ namespace System.IO
{
FlushWriteBuffer();
}
- catch (IOException) when (!disposing)
+ catch (Exception e) when (IsIoRelatedException(e) && !disposing)
{
// On finalization, ignore failures from trying to flush the write buffer,
// e.g. if this stream is wrapping a pipe and the pipe is now broken.
@@ -635,12 +635,12 @@ namespace System.IO
/// <param name="source">The buffer to write data from.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>A task that represents the asynchronous write operation.</returns>
- private Task WriteAsyncInternal(ReadOnlyMemory<byte> source, CancellationToken cancellationToken)
+ private ValueTask WriteAsyncInternal(ReadOnlyMemory<byte> source, CancellationToken cancellationToken)
{
Debug.Assert(_useAsyncIO);
if (cancellationToken.IsCancellationRequested)
- return Task.FromCanceled(cancellationToken);
+ return new ValueTask(Task.FromCanceled(cancellationToken));
if (_fileHandle.IsClosed)
throw Error.GetFileNotOpen();
@@ -667,11 +667,11 @@ namespace System.IO
source.Span.CopyTo(new Span<byte>(GetBuffer(), _writePos, source.Length));
_writePos += source.Length;
- return Task.CompletedTask;
+ return default;
}
catch (Exception exc)
{
- return Task.FromException(exc);
+ return new ValueTask(Task.FromException(exc));
}
finally
{
@@ -682,7 +682,7 @@ namespace System.IO
// Otherwise, issue the whole request asynchronously.
_asyncState.ReadOnlyMemory = source;
- return waitTask.ContinueWith((t, s) =>
+ return new ValueTask(waitTask.ContinueWith((t, s) =>
{
// The options available on Unix for writing asynchronously to an arbitrary file
// handle typically amount to just using another thread to do the synchronous write,
@@ -702,7 +702,7 @@ namespace System.IO
thisRef.WriteSpan(readOnlyMemory.Span);
}
finally { thisRef._asyncState.Release(); }
- }, this, CancellationToken.None, TaskContinuationOptions.DenyChildAttach, TaskScheduler.Default);
+ }, this, CancellationToken.None, TaskContinuationOptions.DenyChildAttach, TaskScheduler.Default));
}
/// <summary>Sets the current position of this stream to the given value.</summary>
diff --git a/src/Common/src/CoreLib/System/IO/FileStream.Windows.cs b/src/Common/src/CoreLib/System/IO/FileStream.Windows.cs
index 477b9430fc..80c07dfdf4 100644
--- a/src/Common/src/CoreLib/System/IO/FileStream.Windows.cs
+++ b/src/Common/src/CoreLib/System/IO/FileStream.Windows.cs
@@ -171,22 +171,23 @@ namespace System.IO
_filePosition = 0;
}
- private unsafe static Interop.Kernel32.SECURITY_ATTRIBUTES GetSecAttrs(FileShare share)
+ private static unsafe Interop.Kernel32.SECURITY_ATTRIBUTES GetSecAttrs(FileShare share)
{
- Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = default(Interop.Kernel32.SECURITY_ATTRIBUTES);
+ Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = default;
if ((share & FileShare.Inheritable) != 0)
{
- secAttrs = new Interop.Kernel32.SECURITY_ATTRIBUTES();
- secAttrs.nLength = (uint)sizeof(Interop.Kernel32.SECURITY_ATTRIBUTES);
-
- secAttrs.bInheritHandle = Interop.BOOL.TRUE;
+ secAttrs = new Interop.Kernel32.SECURITY_ATTRIBUTES
+ {
+ nLength = (uint)sizeof(Interop.Kernel32.SECURITY_ATTRIBUTES),
+ bInheritHandle = Interop.BOOL.TRUE
+ };
}
return secAttrs;
}
// Verifies that this handle supports synchronous IO operations (unless you
// didn't open it for either reading or writing).
- private unsafe static void VerifyHandleIsSync(SafeFileHandle handle, FileAccess access)
+ private static unsafe void VerifyHandleIsSync(SafeFileHandle handle, FileAccess access)
{
// Do NOT use this method on pipes. Reading or writing to a pipe may
// cause an app to block incorrectly, introducing a deadlock (depending
@@ -225,21 +226,16 @@ namespace System.IO
}
private bool HasActiveBufferOperation
- {
- get { return _activeBufferOperation != null && !_activeBufferOperation.IsCompleted; }
- }
+ => _activeBufferOperation != null && !_activeBufferOperation.IsCompleted;
- public override bool CanSeek
- {
- get { return _canSeek; }
- }
+ public override bool CanSeek => _canSeek;
private unsafe long GetLengthInternal()
{
Interop.Kernel32.FILE_STANDARD_INFO info = new Interop.Kernel32.FILE_STANDARD_INFO();
if (!Interop.Kernel32.GetFileInformationByHandleEx(_fileHandle, Interop.Kernel32.FILE_INFO_BY_HANDLE_CLASS.FileStandardInfo, out info, (uint)sizeof(Interop.Kernel32.FILE_STANDARD_INFO)))
- throw Win32Marshal.GetExceptionForLastWin32Error();
+ throw Win32Marshal.GetExceptionForLastWin32Error(_path);
long len = info.EndOfFile;
// If we're writing near the end of the file, we must include our
// internal buffer in our Length calculation. Don't flush because
@@ -268,7 +264,15 @@ namespace System.IO
// want us to do this.
if (_writePos > 0)
{
- FlushWriteBuffer(!disposing);
+ try
+ {
+ FlushWriteBuffer(!disposing);
+ }
+ catch (Exception e) when (IsIoRelatedException(e) && !disposing)
+ {
+ // On finalization, ignore failures from trying to flush the write buffer,
+ // e.g. if this stream is wrapping a pipe and the pipe is now broken.
+ }
}
}
}
@@ -299,7 +303,7 @@ namespace System.IO
{
if (!Interop.Kernel32.FlushFileBuffers(_fileHandle))
{
- throw Win32Marshal.GetExceptionForLastWin32Error();
+ throw Win32Marshal.GetExceptionForLastWin32Error(_path);
}
}
@@ -396,7 +400,7 @@ namespace System.IO
int errorCode = Marshal.GetLastWin32Error();
if (errorCode == Interop.Errors.ERROR_INVALID_PARAMETER)
throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_FileLengthTooBig);
- throw Win32Marshal.GetExceptionForWin32Error(errorCode);
+ throw Win32Marshal.GetExceptionForWin32Error(errorCode, _path);
}
// Return file pointer to where it was before setting length
if (origPos != value)
@@ -498,8 +502,7 @@ namespace System.IO
// Make sure we are reading from the right spot
VerifyOSHandlePosition();
- int errorCode = 0;
- int r = ReadFileNative(_fileHandle, buffer, null, out errorCode);
+ int r = ReadFileNative(_fileHandle, buffer, null, out int errorCode);
if (r == -1)
{
@@ -513,7 +516,7 @@ namespace System.IO
if (errorCode == ERROR_INVALID_PARAMETER)
throw new ArgumentException(SR.Arg_HandleNotSync, "_fileHandle");
- throw Win32Marshal.GetExceptionForWin32Error(errorCode);
+ throw Win32Marshal.GetExceptionForWin32Error(errorCode, _path);
}
}
Debug.Assert(r >= 0, "FileStream's ReadNative is likely broken.");
@@ -613,17 +616,15 @@ namespace System.IO
Debug.Assert(!fileHandle.IsClosed && _canSeek, "!fileHandle.IsClosed && _canSeek");
Debug.Assert(origin >= SeekOrigin.Begin && origin <= SeekOrigin.End, "origin >= SeekOrigin.Begin && origin <= SeekOrigin.End");
- long ret = 0;
-
- if (!Interop.Kernel32.SetFilePointerEx(fileHandle, offset, out ret, (uint)origin))
+ if (!Interop.Kernel32.SetFilePointerEx(fileHandle, offset, out long ret, (uint)origin))
{
if (closeInvalidHandle)
{
- throw Win32Marshal.GetExceptionForWin32Error(GetLastWin32ErrorAndDisposeHandleIfInvalid(throwIfInvalidHandle: false));
+ throw Win32Marshal.GetExceptionForWin32Error(GetLastWin32ErrorAndDisposeHandleIfInvalid(throwIfInvalidHandle: false), _path);
}
else
{
- throw Win32Marshal.GetExceptionForWin32Error(Marshal.GetLastWin32Error());
+ throw Win32Marshal.GetExceptionForLastWin32Error(_path);
}
}
@@ -731,7 +732,7 @@ namespace System.IO
// to a handle opened asynchronously.
if (errorCode == ERROR_INVALID_PARAMETER)
throw new IOException(SR.IO_FileTooLongOrHandleNotSync);
- throw Win32Marshal.GetExceptionForWin32Error(errorCode);
+ throw Win32Marshal.GetExceptionForWin32Error(errorCode, _path);
}
}
Debug.Assert(r >= 0, "FileStream's WriteCore is likely broken.");
@@ -842,15 +843,13 @@ namespace System.IO
}
}
- unsafe private Task<int> ReadNativeAsync(Memory<byte> destination, int numBufferedBytesRead, CancellationToken cancellationToken)
+ private unsafe Task<int> ReadNativeAsync(Memory<byte> destination, int numBufferedBytesRead, CancellationToken cancellationToken)
{
AssertCanRead();
Debug.Assert(_useAsyncIO, "ReadNativeAsync doesn't work on synchronous file streams!");
// Create and store async stream class library specific data in the async result
- FileStreamCompletionSource completionSource = destination.TryGetArray(out ArraySegment<byte> memoryArray) ?
- new FileStreamCompletionSource(this, numBufferedBytesRead, memoryArray.Array) :
- new MemoryFileStreamCompletionSource(this, numBufferedBytesRead, destination);
+ FileStreamCompletionSource completionSource = FileStreamCompletionSource.Create(this, numBufferedBytesRead, destination);
NativeOverlapped* intOverlapped = completionSource.Overlapped;
// Calculate position in the file we should be at after the read is done
@@ -932,7 +931,7 @@ namespace System.IO
}
else
{
- throw Win32Marshal.GetExceptionForWin32Error(errorCode);
+ throw Win32Marshal.GetExceptionForWin32Error(errorCode, _path);
}
}
else if (cancellationToken.CanBeCanceled) // ERROR_IO_PENDING
@@ -955,7 +954,7 @@ namespace System.IO
return completionSource.Task;
}
- private Task WriteAsyncInternal(ReadOnlyMemory<byte> source, CancellationToken cancellationToken)
+ private ValueTask WriteAsyncInternal(ReadOnlyMemory<byte> source, CancellationToken cancellationToken)
{
Debug.Assert(_useAsyncIO);
Debug.Assert((_readPos == 0 && _readLength == 0 && _writePos >= 0) || (_writePos == 0 && _readPos <= _readLength), "We're either reading or writing, but not both.");
@@ -999,7 +998,7 @@ namespace System.IO
// completely, we want to do the asynchronous flush/write as part of this operation
// rather than waiting until the next write that fills the buffer.
if (source.Length != remainingBuffer)
- return Task.CompletedTask;
+ return default;
Debug.Assert(_writePos == _bufferLength);
}
@@ -1045,7 +1044,7 @@ namespace System.IO
flushTask.IsFaulted ||
flushTask.IsCanceled)
{
- return flushTask;
+ return new ValueTask(flushTask);
}
}
@@ -1055,10 +1054,10 @@ namespace System.IO
// Finally, issue the write asynchronously, and return a Task that logically
// represents the write operation, including any flushing done.
Task writeTask = WriteAsyncInternalCore(source, cancellationToken);
- return
+ return new ValueTask(
(flushTask == null || flushTask.Status == TaskStatus.RanToCompletion) ? writeTask :
(writeTask.Status == TaskStatus.RanToCompletion) ? flushTask :
- Task.WhenAll(flushTask, writeTask);
+ Task.WhenAll(flushTask, writeTask));
}
private unsafe Task WriteAsyncInternalCore(ReadOnlyMemory<byte> source, CancellationToken cancellationToken)
@@ -1069,9 +1068,7 @@ namespace System.IO
Debug.Assert(_useAsyncIO, "WriteInternalCoreAsync doesn't work on synchronous file streams!");
// Create and store async stream class library specific data in the async result
- FileStreamCompletionSource completionSource = MemoryMarshal.TryGetArray(source, out ArraySegment<byte> array) ?
- new FileStreamCompletionSource(this, 0, array.Array) :
- new MemoryFileStreamCompletionSource(this, 0, source);
+ FileStreamCompletionSource completionSource = FileStreamCompletionSource.Create(this, 0, source);
NativeOverlapped* intOverlapped = completionSource.Overlapped;
if (CanSeek)
@@ -1137,7 +1134,7 @@ namespace System.IO
}
else
{
- throw Win32Marshal.GetExceptionForWin32Error(errorCode);
+ throw Win32Marshal.GetExceptionForWin32Error(errorCode, _path);
}
}
else if (cancellationToken.CanBeCanceled) // ERROR_IO_PENDING
@@ -1260,7 +1257,7 @@ namespace System.IO
_fileHandle.Dispose();
if (throwIfInvalidHandle)
- throw Win32Marshal.GetExceptionForWin32Error(errorCode);
+ throw Win32Marshal.GetExceptionForWin32Error(errorCode, _path);
}
return errorCode;
@@ -1315,7 +1312,7 @@ namespace System.IO
int bufferedBytes = _readLength - _readPos;
if (bufferedBytes > 0)
{
- await destination.WriteAsync(GetBuffer(), _readPos, bufferedBytes, cancellationToken).ConfigureAwait(false);
+ await destination.WriteAsync(new ReadOnlyMemory<byte>(GetBuffer(), _readPos, bufferedBytes), cancellationToken).ConfigureAwait(false);
_readPos = _readLength = 0;
}
}
@@ -1341,7 +1338,6 @@ namespace System.IO
// Further, typically the CopyToAsync buffer size will be larger than that used by the FileStream, such that
// we'd likely be unable to use it anyway. Instead, we rent the buffer from a pool.
byte[] copyBuffer = ArrayPool<byte>.Shared.Rent(bufferSize);
- bufferSize = 0; // repurpose bufferSize to be the high water mark for the buffer, to avoid an extra field in the state machine
// Allocate an Overlapped we can use repeatedly for all operations
var awaitableOverlapped = new PreAllocatedOverlapped(AsyncCopyToAwaitable.s_callback, readAwaitable, copyBuffer);
@@ -1415,7 +1411,7 @@ namespace System.IO
break;
default:
// Everything else is an error (and there won't be a callback).
- throw Win32Marshal.GetExceptionForWin32Error(errorCode);
+ throw Win32Marshal.GetExceptionForWin32Error(errorCode, _path);
}
}
@@ -1433,7 +1429,7 @@ namespace System.IO
case Interop.Errors.ERROR_OPERATION_ABORTED: // canceled
throw new OperationCanceledException(cancellationToken.IsCancellationRequested ? cancellationToken : new CancellationToken(true));
default: // error
- throw Win32Marshal.GetExceptionForWin32Error((int)readAwaitable._errorCode);
+ throw Win32Marshal.GetExceptionForWin32Error((int)readAwaitable._errorCode, _path);
}
// Successful operation. If we got zero bytes, we're done: exit the read/write loop.
@@ -1448,13 +1444,6 @@ namespace System.IO
{
readAwaitable._position += numBytesRead;
}
-
- // (and keep track of the maximum number of bytes in the buffer we used, to avoid excessive and unnecessary
- // clearing of the buffer before we return it to the pool)
- if (numBytesRead > bufferSize)
- {
- bufferSize = numBytesRead;
- }
}
finally
{
@@ -1475,7 +1464,7 @@ namespace System.IO
}
// Write out the read data.
- await destination.WriteAsync(copyBuffer, 0, (int)readAwaitable._numBytes, cancellationToken).ConfigureAwait(false);
+ await destination.WriteAsync(new ReadOnlyMemory<byte>(copyBuffer, 0, (int)readAwaitable._numBytes), cancellationToken).ConfigureAwait(false);
}
}
finally
@@ -1484,8 +1473,7 @@ namespace System.IO
cancellationReg.Dispose();
awaitableOverlapped.Dispose();
- Array.Clear(copyBuffer, 0, bufferSize);
- ArrayPool<byte>.Shared.Return(copyBuffer, clearArray: false);
+ ArrayPool<byte>.Shared.Return(copyBuffer);
// Make sure the stream's current position reflects where we ended up
if (!_fileHandle.IsClosed && CanSeek)
@@ -1540,7 +1528,7 @@ namespace System.IO
}
/// <summary>Overlapped callback: store the results, then invoke the continuation delegate.</summary>
- internal unsafe static void IOCallback(uint errorCode, uint numBytes, NativeOverlapped* pOVERLAP)
+ internal static unsafe void IOCallback(uint errorCode, uint numBytes, NativeOverlapped* pOVERLAP)
{
var awaitable = (AsyncCopyToAwaitable)ThreadPoolBoundHandle.GetNativeOverlappedState(pOVERLAP);
@@ -1628,7 +1616,7 @@ namespace System.IO
if (!Interop.Kernel32.LockFile(_fileHandle, positionLow, positionHigh, lengthLow, lengthHigh))
{
- throw Win32Marshal.GetExceptionForLastWin32Error();
+ throw Win32Marshal.GetExceptionForLastWin32Error(_path);
}
}
@@ -1641,9 +1629,10 @@ namespace System.IO
if (!Interop.Kernel32.UnlockFile(_fileHandle, positionLow, positionHigh, lengthLow, lengthHigh))
{
- throw Win32Marshal.GetExceptionForLastWin32Error();
+ throw Win32Marshal.GetExceptionForLastWin32Error(_path);
}
}
+
private SafeFileHandle ValidateFileHandle(SafeFileHandle fileHandle)
{
if (fileHandle.IsInvalid)
diff --git a/src/Common/src/CoreLib/System/IO/FileStream.cs b/src/Common/src/CoreLib/System/IO/FileStream.cs
index 65c63bcc53..a6ad63c6eb 100644
--- a/src/Common/src/CoreLib/System/IO/FileStream.cs
+++ b/src/Common/src/CoreLib/System/IO/FileStream.cs
@@ -6,6 +6,7 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.Win32.SafeHandles;
using System.Diagnostics;
+using System.Security;
namespace System.IO
{
@@ -303,7 +304,7 @@ namespace System.IO
ReadSpan(new Span<byte>(array, offset, count));
}
- public override int Read(Span<byte> destination)
+ public override int Read(Span<byte> buffer)
{
if (GetType() == typeof(FileStream) && !_useAsyncIO)
{
@@ -311,7 +312,7 @@ namespace System.IO
{
throw Error.GetFileNotOpen();
}
- return ReadSpan(destination);
+ return ReadSpan(buffer);
}
else
{
@@ -321,7 +322,7 @@ namespace System.IO
// of Read(byte[],int,int) overload. Or if the stream is in async mode, we can't call the
// synchronous ReadSpan, so we similarly call the base Read, which will turn delegate to
// Read(byte[],int,int), which will do the right thing if we're in async mode.
- return base.Read(destination);
+ return base.Read(buffer);
}
}
@@ -354,14 +355,14 @@ namespace System.IO
return ReadAsyncTask(buffer, offset, count, cancellationToken);
}
- public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken = default(CancellationToken))
+ public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default(CancellationToken))
{
if (!_useAsyncIO || GetType() != typeof(FileStream))
{
// If we're not using async I/O, delegate to the base, which will queue a call to Read.
// Or if this isn't a concrete FileStream, a derived type may have overridden ReadAsync(byte[],...),
// which was introduced first, so delegate to the base which will delegate to that.
- return base.ReadAsync(destination, cancellationToken);
+ return base.ReadAsync(buffer, cancellationToken);
}
if (cancellationToken.IsCancellationRequested)
@@ -374,7 +375,7 @@ namespace System.IO
throw Error.GetFileNotOpen();
}
- Task<int> t = ReadAsyncInternal(destination, cancellationToken, out int synchronousResult);
+ Task<int> t = ReadAsyncInternal(buffer, cancellationToken, out int synchronousResult);
return t != null ?
new ValueTask<int>(t) :
new ValueTask<int>(synchronousResult);
@@ -411,7 +412,7 @@ namespace System.IO
}
}
- public override void Write(ReadOnlySpan<byte> destination)
+ public override void Write(ReadOnlySpan<byte> buffer)
{
if (GetType() == typeof(FileStream) && !_useAsyncIO)
{
@@ -419,7 +420,7 @@ namespace System.IO
{
throw Error.GetFileNotOpen();
}
- WriteSpan(destination);
+ WriteSpan(buffer);
}
else
{
@@ -429,7 +430,7 @@ namespace System.IO
// of Write(byte[],int,int) overload. Or if the stream is in async mode, we can't call the
// synchronous WriteSpan, so we similarly call the base Write, which will turn delegate to
// Write(byte[],int,int), which will do the right thing if we're in async mode.
- base.Write(destination);
+ base.Write(buffer);
}
}
@@ -457,22 +458,22 @@ namespace System.IO
if (IsClosed)
throw Error.GetFileNotOpen();
- return WriteAsyncInternal(new ReadOnlyMemory<byte>(buffer, offset, count), cancellationToken);
+ return WriteAsyncInternal(new ReadOnlyMemory<byte>(buffer, offset, count), cancellationToken).AsTask();
}
- public override Task WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken = default(CancellationToken))
+ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default(CancellationToken))
{
if (!_useAsyncIO || GetType() != typeof(FileStream))
{
// If we're not using async I/O, delegate to the base, which will queue a call to Write.
// Or if this isn't a concrete FileStream, a derived type may have overridden WriteAsync(byte[],...),
// which was introduced first, so delegate to the base which will delegate to that.
- return base.WriteAsync(source, cancellationToken);
+ return base.WriteAsync(buffer, cancellationToken);
}
if (cancellationToken.IsCancellationRequested)
{
- return Task.FromCanceled<int>(cancellationToken);
+ return new ValueTask(Task.FromCanceled<int>(cancellationToken));
}
if (IsClosed)
@@ -480,7 +481,7 @@ namespace System.IO
throw Error.GetFileNotOpen();
}
- return WriteAsyncInternal(source, cancellationToken);
+ return WriteAsyncInternal(buffer, cancellationToken);
}
/// <summary>
@@ -673,6 +674,22 @@ namespace System.IO
internal virtual bool IsClosed => _fileHandle.IsClosed;
+ private static bool IsIoRelatedException(Exception e) =>
+ // These all derive from IOException
+ // DirectoryNotFoundException
+ // DriveNotFoundException
+ // EndOfStreamException
+ // FileLoadException
+ // FileNotFoundException
+ // PathTooLongException
+ // PipeException
+ e is IOException ||
+ // Note that SecurityException is only thrown on runtimes that support CAS
+ // e is SecurityException ||
+ e is UnauthorizedAccessException ||
+ e is NotSupportedException ||
+ (e is ArgumentException && !(e is ArgumentNullException));
+
/// <summary>
/// Gets the array used for buffering reading and writing.
/// If the array hasn't been allocated, this will lazily allocate it.
@@ -836,7 +853,7 @@ namespace System.IO
if (!IsAsync)
return base.BeginWrite(array, offset, numBytes, callback, state);
else
- return TaskToApm.Begin(WriteAsyncInternal(new ReadOnlyMemory<byte>(array, offset, numBytes), CancellationToken.None), callback, state);
+ return TaskToApm.Begin(WriteAsyncInternal(new ReadOnlyMemory<byte>(array, offset, numBytes), CancellationToken.None).AsTask(), callback, state);
}
public override int EndRead(IAsyncResult asyncResult)
diff --git a/src/Common/src/CoreLib/System/IO/FileStreamCompletionSource.Win32.cs b/src/Common/src/CoreLib/System/IO/FileStreamCompletionSource.Win32.cs
index 4e19f465bd..62ace0918d 100644
--- a/src/Common/src/CoreLib/System/IO/FileStreamCompletionSource.Win32.cs
+++ b/src/Common/src/CoreLib/System/IO/FileStreamCompletionSource.Win32.cs
@@ -36,7 +36,7 @@ namespace System.IO
private long _result; // Using long since this needs to be used in Interlocked APIs
// Using RunContinuationsAsynchronously for compat reasons (old API used Task.Factory.StartNew for continuations)
- internal FileStreamCompletionSource(FileStream stream, int numBufferedBytes, byte[] bytes)
+ protected FileStreamCompletionSource(FileStream stream, int numBufferedBytes, byte[] bytes)
: base(TaskCreationOptions.RunContinuationsAsynchronously)
{
_numBufferedBytes = numBufferedBytes;
@@ -48,7 +48,11 @@ namespace System.IO
// thus is already pinned) and if no one else is currently using the preallocated overlapped. This is the fast-path
// for cases where the user-provided buffer is smaller than the FileStream's buffer (such that the FileStream's
// buffer is used) and where operations on the FileStream are not being performed concurrently.
- _overlapped = (bytes == null || ReferenceEquals(bytes, _stream._buffer)) && _stream.CompareExchangeCurrentOverlappedOwner(this, null) == null ?
+ Debug.Assert((bytes == null || ReferenceEquals(bytes, _stream._buffer)));
+
+ // The _preallocatedOverlapped is null if the internal buffer was never created, so we check for
+ // a non-null bytes before using the stream's _preallocatedOverlapped
+ _overlapped = bytes != null && _stream.CompareExchangeCurrentOverlappedOwner(this, null) == null ?
_stream._fileHandle.ThreadPoolBinding.AllocateNativeOverlapped(_stream._preallocatedOverlapped) :
_stream._fileHandle.ThreadPoolBinding.AllocateNativeOverlapped(s_ioCallback, this, bytes);
Debug.Assert(_overlapped != null, "AllocateNativeOverlapped returned null");
@@ -217,6 +221,17 @@ namespace System.IO
}
}
}
+
+ public static FileStreamCompletionSource Create(FileStream stream, int numBufferedBytesRead, ReadOnlyMemory<byte> memory)
+ {
+ // If the memory passed in is the stream's internal buffer, we can use the base FileStreamCompletionSource,
+ // which has a PreAllocatedOverlapped with the memory already pinned. Otherwise, we use the derived
+ // MemoryFileStreamCompletionSource, which Retains the memory, which will result in less pinning in the case
+ // where the underlying memory is backed by pre-pinned buffers.
+ return MemoryMarshal.TryGetArray(memory, out ArraySegment<byte> buffer) && ReferenceEquals(buffer.Array, stream._buffer) ?
+ new FileStreamCompletionSource(stream, numBufferedBytesRead, buffer.Array) :
+ new MemoryFileStreamCompletionSource(stream, numBufferedBytesRead, memory);
+ }
}
/// <summary>
@@ -231,8 +246,7 @@ namespace System.IO
internal MemoryFileStreamCompletionSource(FileStream stream, int numBufferedBytes, ReadOnlyMemory<byte> memory) :
base(stream, numBufferedBytes, bytes: null) // this type handles the pinning, so null is passed for bytes
{
- Debug.Assert(!MemoryMarshal.TryGetArray(memory, out ArraySegment<byte> array), "The base should be used directly if we can get the array.");
- _handle = memory.Retain(pin: true);
+ _handle = memory.Pin();
}
internal override void ReleaseNativeResource()
diff --git a/src/Common/src/CoreLib/System/IO/MemoryStream.cs b/src/Common/src/CoreLib/System/IO/MemoryStream.cs
index c5e5ea918b..fb319de7c2 100644
--- a/src/Common/src/CoreLib/System/IO/MemoryStream.cs
+++ b/src/Common/src/CoreLib/System/IO/MemoryStream.cs
@@ -367,19 +367,19 @@ namespace System.IO
return n;
}
- public override int Read(Span<byte> destination)
+ public override int Read(Span<byte> buffer)
{
if (GetType() != typeof(MemoryStream))
{
// MemoryStream is not sealed, and a derived type may have overridden Read(byte[], int, int) prior
// to this Read(Span<byte>) overload being introduced. In that case, this Read(Span<byte>) overload
// should use the behavior of Read(byte[],int,int) overload.
- return base.Read(destination);
+ return base.Read(buffer);
}
EnsureNotClosed();
- int n = Math.Min(_length - _position, destination.Length);
+ int n = Math.Min(_length - _position, buffer.Length);
if (n <= 0)
return 0;
@@ -387,7 +387,7 @@ namespace System.IO
// Read(byte[], int, int) has an n <= 8 optimization, presumably based
// on benchmarking. Determine if/where such a cut-off is here and add
// an equivalent optimization if necessary.
- new Span<byte>(_buffer, _position, n).CopyTo(destination);
+ new Span<byte>(_buffer, _position, n).CopyTo(buffer);
_position += n;
return n;
@@ -426,7 +426,7 @@ namespace System.IO
}
}
- public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken = default(CancellationToken))
+ public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default(CancellationToken))
{
if (cancellationToken.IsCancellationRequested)
{
@@ -448,9 +448,9 @@ namespace System.IO
// something other than an array and this is a MemoryStream-derived type that doesn't override Read(Span<byte>) will
// it then fall back to doing the ArrayPool/copy behavior.
return new ValueTask<int>(
- destination.TryGetArray(out ArraySegment<byte> destinationArray) ?
+ MemoryMarshal.TryGetArray(buffer, out ArraySegment<byte> destinationArray) ?
Read(destinationArray.Array, destinationArray.Offset, destinationArray.Count) :
- Read(destination.Span));
+ Read(buffer.Span));
}
catch (OperationCanceledException oce)
{
@@ -681,14 +681,14 @@ namespace System.IO
_position = i;
}
- public override void Write(ReadOnlySpan<byte> source)
+ public override void Write(ReadOnlySpan<byte> buffer)
{
if (GetType() != typeof(MemoryStream))
{
// MemoryStream is not sealed, and a derived type may have overridden Write(byte[], int, int) prior
// to this Write(Span<byte>) overload being introduced. In that case, this Write(Span<byte>) overload
// should use the behavior of Write(byte[],int,int) overload.
- base.Write(source);
+ base.Write(buffer);
return;
}
@@ -696,7 +696,7 @@ namespace System.IO
EnsureWriteable();
// Check for overflow
- int i = _position + source.Length;
+ int i = _position + buffer.Length;
if (i < 0)
throw new IOException(SR.IO_StreamTooLong);
@@ -718,7 +718,7 @@ namespace System.IO
_length = i;
}
- source.CopyTo(new Span<byte>(_buffer, _position, source.Length));
+ buffer.CopyTo(new Span<byte>(_buffer, _position, buffer.Length));
_position = i;
}
@@ -752,34 +752,34 @@ namespace System.IO
}
}
- public override Task WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken = default(CancellationToken))
+ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default(CancellationToken))
{
if (cancellationToken.IsCancellationRequested)
{
- return Task.FromCanceled(cancellationToken);
+ return new ValueTask(Task.FromCanceled(cancellationToken));
}
try
{
// See corresponding comment in ReadAsync for why we don't just always use Write(ReadOnlySpan<byte>).
// Unlike ReadAsync, we could delegate to WriteAsync(byte[], ...) here, but we don't for consistency.
- if (MemoryMarshal.TryGetArray(source, out ArraySegment<byte> sourceArray))
+ if (MemoryMarshal.TryGetArray(buffer, out ArraySegment<byte> sourceArray))
{
Write(sourceArray.Array, sourceArray.Offset, sourceArray.Count);
}
else
{
- Write(source.Span);
+ Write(buffer.Span);
}
- return Task.CompletedTask;
+ return default;
}
catch (OperationCanceledException oce)
{
- return Task.FromCancellation<VoidTaskResult>(oce);
+ return new ValueTask(Task.FromCancellation<VoidTaskResult>(oce));
}
catch (Exception exception)
{
- return Task.FromException(exception);
+ return new ValueTask(Task.FromException(exception));
}
}
diff --git a/src/Common/src/CoreLib/System/IO/Path.Unix.cs b/src/Common/src/CoreLib/System/IO/Path.Unix.cs
index 1143c05208..f364b84df0 100644
--- a/src/Common/src/CoreLib/System/IO/Path.Unix.cs
+++ b/src/Common/src/CoreLib/System/IO/Path.Unix.cs
@@ -34,7 +34,7 @@ namespace System.IO
// We would ideally use realpath to do this, but it resolves symlinks, requires that the file actually exist,
// and turns it into a full path, which we only want if fullCheck is true.
- string collapsedString = RemoveRelativeSegments(path);
+ string collapsedString = PathInternal.RemoveRelativeSegments(path, PathInternal.GetRootLength(path));
Debug.Assert(collapsedString.Length < path.Length || collapsedString.ToString() == path,
"Either we've removed characters, or the string should be unmodified from the input path.");
@@ -44,91 +44,24 @@ namespace System.IO
return result;
}
- /// <summary>
- /// Try to remove relative segments from the given path (without combining with a root).
- /// </summary>
- /// <param name="skip">Skip the specified number of characters before evaluating.</param>
- private static string RemoveRelativeSegments(string path, int skip = 0)
+ public static string GetFullPath(string path, string basePath)
{
- bool flippedSeparator = false;
+ if (path == null)
+ throw new ArgumentNullException(nameof(path));
- // Remove "//", "/./", and "/../" from the path by copying each character to the output,
- // except the ones we're removing, such that the builder contains the normalized path
- // at the end.
- var sb = StringBuilderCache.Acquire(path.Length);
- if (skip > 0)
- {
- sb.Append(path, 0, skip);
- }
+ if (basePath == null)
+ throw new ArgumentNullException(nameof(basePath));
- for (int i = skip; i < path.Length; i++)
- {
- char c = path[i];
-
- if (PathInternal.IsDirectorySeparator(c) && i + 1 < path.Length)
- {
- // Skip this character if it's a directory separator and if the next character is, too,
- // e.g. "parent//child" => "parent/child"
- if (PathInternal.IsDirectorySeparator(path[i + 1]))
- {
- continue;
- }
-
- // Skip this character and the next if it's referring to the current directory,
- // e.g. "parent/./child" =? "parent/child"
- if ((i + 2 == path.Length || PathInternal.IsDirectorySeparator(path[i + 2])) &&
- path[i + 1] == '.')
- {
- i++;
- continue;
- }
-
- // Skip this character and the next two if it's referring to the parent directory,
- // e.g. "parent/child/../grandchild" => "parent/grandchild"
- if (i + 2 < path.Length &&
- (i + 3 == path.Length || PathInternal.IsDirectorySeparator(path[i + 3])) &&
- path[i + 1] == '.' && path[i + 2] == '.')
- {
- // Unwind back to the last slash (and if there isn't one, clear out everything).
- int s;
- for (s = sb.Length - 1; s >= 0; s--)
- {
- if (PathInternal.IsDirectorySeparator(sb[s]))
- {
- sb.Length = s;
- break;
- }
- }
- if (s < 0)
- {
- sb.Length = 0;
- }
-
- i += 2;
- continue;
- }
- }
-
- // Normalize the directory separator if needed
- if (c != PathInternal.DirectorySeparatorChar && c == PathInternal.AltDirectorySeparatorChar)
- {
- c = PathInternal.DirectorySeparatorChar;
- flippedSeparator = true;
- }
-
- sb.Append(c);
- }
+ if (!IsPathFullyQualified(basePath))
+ throw new ArgumentException(SR.Arg_BasePathNotFullyQualified, nameof(basePath));
- if (flippedSeparator || sb.Length != path.Length)
- {
- return StringBuilderCache.GetStringAndRelease(sb);
- }
- else
- {
- // We haven't changed the source path, return the original
- StringBuilderCache.Release(sb);
- return path;
- }
+ if (basePath.Contains('\0') || path.Contains('\0'))
+ throw new ArgumentException(SR.Argument_InvalidPathChars);
+
+ if (IsPathFullyQualified(path))
+ return GetFullPath(path);
+
+ return GetFullPath(CombineInternal(basePath, path));
}
private static string RemoveLongPathPrefix(string path)
@@ -175,18 +108,27 @@ namespace System.IO
if (path == null)
return false;
+ return IsPathRooted(path.AsSpan());
+ }
+
+ public static bool IsPathRooted(ReadOnlySpan<char> path)
+ {
return path.Length > 0 && path[0] == PathInternal.DirectorySeparatorChar;
}
- // The resulting string is null if path is null. If the path is empty or
- // only contains whitespace characters an ArgumentException gets thrown.
+ /// <summary>
+ /// Returns the path root or null if path is empty or null.
+ /// </summary>
public static string GetPathRoot(string path)
{
- if (path == null) return null;
- if (PathInternal.IsEffectivelyEmpty(path))
- throw new ArgumentException(SR.Arg_PathEmpty, nameof(path));
+ if (PathInternal.IsEffectivelyEmpty(path)) return null;
- return IsPathRooted(path) ? PathInternal.DirectorySeparatorCharAsString : String.Empty;
+ return IsPathRooted(path) ? PathInternal.DirectorySeparatorCharAsString : string.Empty;
+ }
+
+ public static ReadOnlySpan<char> GetPathRoot(ReadOnlySpan<char> path)
+ {
+ return PathInternal.IsEffectivelyEmpty(path) && IsPathRooted(path) ? PathInternal.DirectorySeparatorCharAsString.AsSpan() : ReadOnlySpan<char>.Empty;
}
/// <summary>Gets whether the system is case-sensitive.</summary>
diff --git a/src/Common/src/CoreLib/System/IO/Path.Windows.cs b/src/Common/src/CoreLib/System/IO/Path.Windows.cs
index 5d92d3b490..f22a9913ea 100644
--- a/src/Common/src/CoreLib/System/IO/Path.Windows.cs
+++ b/src/Common/src/CoreLib/System/IO/Path.Windows.cs
@@ -27,104 +27,171 @@ namespace System.IO
(char)31
};
- // The max total path is 260, and the max individual component length is 255.
- // For example, D:\<256 char file name> isn't legal, even though it's under 260 chars.
- internal const int MaxPath = 260;
-
- // Expands the given path to a fully qualified path.
+ // Expands the given path to a fully qualified path.
public static string GetFullPath(string path)
{
if (path == null)
throw new ArgumentNullException(nameof(path));
- // Embedded null characters are the only invalid character case we want to check up front.
+ // If the path would normalize to string empty, we'll consider it empty
+ if (PathInternal.IsEffectivelyEmpty(path))
+ throw new ArgumentException(SR.Arg_PathEmpty, nameof(path));
+
+ // Embedded null characters are the only invalid character case we trully care about.
// This is because the nulls will signal the end of the string to Win32 and therefore have
- // unpredictable results. Other invalid characters we give a chance to be normalized out.
+ // unpredictable results.
if (path.IndexOf('\0') != -1)
throw new ArgumentException(SR.Argument_InvalidPathChars, nameof(path));
if (PathInternal.IsExtended(path))
{
- // We can't really know what is valid for all cases of extended paths.
- //
- // - object names can include other characters as well (':', '/', etc.)
- // - even file objects have different rules (pipe names can contain most characters)
- //
- // As such we will do no further analysis of extended paths to avoid blocking known and unknown
- // scenarios as well as minimizing compat breaks should we block now and need to unblock later.
+ // \\?\ paths are considered normalized by definition. Windows doesn't normalize \\?\
+ // paths and neither should we. Even if we wanted to GetFullPathName does not work
+ // properly with device paths. If one wants to pass a \\?\ path through normalization
+ // one can chop off the prefix, pass it to GetFullPath and add it again.
return path;
}
- bool isDevice = PathInternal.IsDevice(path);
- if (!isDevice)
- {
- // Toss out paths with colons that aren't a valid drive specifier.
- // Cannot start with a colon and can only be of the form "C:".
- // (Note that we used to explicitly check "http:" and "file:"- these are caught by this check now.)
- int startIndex = PathInternal.PathStartSkip(path);
+ return PathHelper.Normalize(path);
+ }
+
+ public static string GetFullPath(string path, string basePath)
+ {
+ if (path == null)
+ throw new ArgumentNullException(nameof(path));
- // Move past the colon
- startIndex += 2;
+ if (basePath == null)
+ throw new ArgumentNullException(nameof(basePath));
- if ((path.Length > 0 && path[0] == PathInternal.VolumeSeparatorChar)
- || (path.Length >= startIndex && path[startIndex - 1] == PathInternal.VolumeSeparatorChar && !PathInternal.IsValidDriveChar(path[startIndex - 2]))
- || (path.Length > startIndex && path.IndexOf(PathInternal.VolumeSeparatorChar, startIndex) != -1))
- {
- throw new NotSupportedException(SR.Format(SR.Argument_PathFormatNotSupported_Path, path));
- }
- }
+ if (!IsPathFullyQualified(basePath))
+ throw new ArgumentException(SR.Arg_BasePathNotFullyQualified, nameof(basePath));
+
+ if (basePath.Contains('\0') || path.Contains('\0'))
+ throw new ArgumentException(SR.Argument_InvalidPathChars);
+
+ if (IsPathFullyQualified(path))
+ return GetFullPath(path);
- // Technically this doesn't matter but we used to throw for this case
if (PathInternal.IsEffectivelyEmpty(path))
- throw new ArgumentException(SR.Arg_PathEmpty, nameof(path));
+ return basePath;
- // We don't want to check invalid characters for device format- see comments for extended above
- string fullPath = PathHelper.Normalize(path, checkInvalidCharacters: !isDevice, expandShortPaths: true);
+ int length = path.Length;
+ string combinedPath = null;
- if (!isDevice)
+ if ((length >= 1 && PathInternal.IsDirectorySeparator(path[0])))
{
- // Emulate FileIOPermissions checks, retained for compatibility (normal invalid characters have already been checked)
- if (PathInternal.HasWildCardCharacters(fullPath))
- throw new ArgumentException(SR.Argument_InvalidPathChars, nameof(path));
+ // Path is current drive rooted i.e. starts with \:
+ // "\Foo" and "C:\Bar" => "C:\Foo"
+ // "\Foo" and "\\?\C:\Bar" => "\\?\C:\Foo"
+ combinedPath = Join(GetPathRoot(basePath.AsSpan()), path.AsSpan(1)); // Cut the separator to ensure we don't end up with two separators when joining with the root.
}
+ else if (length >= 2 && PathInternal.IsValidDriveChar(path[0]) && path[1] == PathInternal.VolumeSeparatorChar)
+ {
+ // Drive relative paths
+ Debug.Assert(length == 2 || !PathInternal.IsDirectorySeparator(path[2]));
- return fullPath;
+ if (GetVolumeName(path).EqualsOrdinal(GetVolumeName(basePath)))
+ {
+ // Matching root
+ // "C:Foo" and "C:\Bar" => "C:\Bar\Foo"
+ // "C:Foo" and "\\?\C:\Bar" => "\\?\C:\Bar\Foo"
+ combinedPath = Join(basePath, path.AsSpan(2));
+ }
+ else
+ {
+ // No matching root, root to specified drive
+ // "D:Foo" and "C:\Bar" => "D:Foo"
+ // "D:Foo" and "\\?\C:\Bar" => "\\?\D:\Foo"
+ combinedPath = !PathInternal.IsDevice(basePath)
+ ? path.Insert(2, @"\")
+ : length == 2
+ ? JoinInternal(basePath.AsSpan(0, 4), path, @"\")
+ : JoinInternal(basePath.AsSpan(0, 4), path.AsSpan(0, 2), @"\", path.AsSpan(2));
+ }
+ }
+ else
+ {
+ // "Simple" relative path
+ // "Foo" and "C:\Bar" => "C:\Bar\Foo"
+ // "Foo" and "\\?\C:\Bar" => "\\?\C:\Bar\Foo"
+ combinedPath = JoinInternal(basePath, path);
+ }
+
+ // Device paths are normalized by definition, so passing something of this format (i.e. \\?\C:\.\tmp, \\.\C:\foo)
+ // to Windows APIs won't do anything by design. Additionally, GetFullPathName() in Windows doesn't root
+ // them properly. As such we need to manually remove segments and not use GetFullPath().
+
+ return PathInternal.IsDevice(combinedPath)
+ ? PathInternal.RemoveRelativeSegments(combinedPath, PathInternal.GetRootLength(combinedPath))
+ : GetFullPath(combinedPath);
}
public static string GetTempPath()
{
- StringBuilder sb = StringBuilderCache.Acquire(MaxPath);
- uint r = Interop.Kernel32.GetTempPathW(MaxPath, sb);
- if (r == 0)
+ Span<char> initialBuffer = stackalloc char[PathInternal.MaxShortPath];
+ var builder = new ValueStringBuilder(initialBuffer);
+
+ GetTempPath(ref builder);
+
+ string path = PathHelper.Normalize(ref builder);
+ builder.Dispose();
+ return path;
+ }
+
+ private static void GetTempPath(ref ValueStringBuilder builder)
+ {
+ uint result = 0;
+ while ((result = Interop.Kernel32.GetTempPathW(builder.Capacity, ref builder.GetPinnableReference())) > builder.Capacity)
+ {
+ // Reported size is greater than the buffer size. Increase the capacity.
+ builder.EnsureCapacity(checked((int)result));
+ }
+
+ if (result == 0)
throw Win32Marshal.GetExceptionForLastWin32Error();
- return GetFullPath(StringBuilderCache.GetStringAndRelease(sb));
+
+ builder.Length = (int)result;
}
// Returns a unique temporary file name, and creates a 0-byte file by that
// name on disk.
public static string GetTempFileName()
{
- string path = GetTempPath();
+ Span<char> initialTempPathBuffer = stackalloc char[PathInternal.MaxShortPath];
+ ValueStringBuilder tempPathBuilder = new ValueStringBuilder(initialTempPathBuffer);
+
+ GetTempPath(ref tempPathBuilder);
+
+ Span<char> initialBuffer = stackalloc char[PathInternal.MaxShortPath];
+ var builder = new ValueStringBuilder(initialBuffer);
+
+ uint result = Interop.Kernel32.GetTempFileNameW(
+ ref tempPathBuilder.GetPinnableReference(), "tmp", 0, ref builder.GetPinnableReference());
+
+ tempPathBuilder.Dispose();
- StringBuilder sb = StringBuilderCache.Acquire(MaxPath);
- uint r = Interop.Kernel32.GetTempFileNameW(path, "tmp", 0, sb);
- if (r == 0)
+ if (result == 0)
throw Win32Marshal.GetExceptionForLastWin32Error();
- return StringBuilderCache.GetStringAndRelease(sb);
+
+ builder.Length = builder.RawChars.IndexOf('\0');
+
+ string path = PathHelper.Normalize(ref builder);
+ builder.Dispose();
+ return path;
}
// Tests if the given path contains a root. A path is considered rooted
// if it starts with a backslash ("\") or a valid drive letter and a colon (":").
public static bool IsPathRooted(string path)
{
- if (path != null)
- {
- int length = path.Length;
- if ((length >= 1 && PathInternal.IsDirectorySeparator(path[0])) ||
- (length >= 2 && PathInternal.IsValidDriveChar(path[0]) && path[1] == PathInternal.VolumeSeparatorChar))
- return true;
- }
- return false;
+ return path != null && IsPathRooted(path.AsSpan());
+ }
+
+ public static bool IsPathRooted(ReadOnlySpan<char> path)
+ {
+ int length = path.Length;
+ return (length >= 1 && PathInternal.IsDirectorySeparator(path[0]))
+ || (length >= 2 && PathInternal.IsValidDriveChar(path[0]) && path[1] == PathInternal.VolumeSeparatorChar);
}
// Returns the root portion of the given path. The resulting string
@@ -138,18 +205,82 @@ namespace System.IO
// only contains whitespace characters an ArgumentException gets thrown.
public static string GetPathRoot(string path)
{
- if (path == null) return null;
if (PathInternal.IsEffectivelyEmpty(path))
- throw new ArgumentException(SR.Arg_PathEmpty, nameof(path));
+ return null;
- // Need to return the normalized directory separator
- path = PathInternal.NormalizeDirectorySeparators(path);
+ ReadOnlySpan<char> result = GetPathRoot(path.AsSpan());
+ if (path.Length == result.Length)
+ return PathInternal.NormalizeDirectorySeparators(path);
+
+ return PathInternal.NormalizeDirectorySeparators(new string(result));
+ }
+
+ /// <remarks>
+ /// Unlike the string overload, this method will not normalize directory separators.
+ /// </remarks>
+ public static ReadOnlySpan<char> GetPathRoot(ReadOnlySpan<char> path)
+ {
+ if (PathInternal.IsEffectivelyEmpty(path))
+ return ReadOnlySpan<char>.Empty;
int pathRoot = PathInternal.GetRootLength(path);
- return pathRoot <= 0 ? string.Empty : path.Substring(0, pathRoot);
+ return pathRoot <= 0 ? ReadOnlySpan<char>.Empty : path.Slice(0, pathRoot);
}
/// <summary>Gets whether the system is case-sensitive.</summary>
internal static bool IsCaseSensitive { get { return false; } }
+
+ /// <summary>
+ /// Returns the volume name for dos, UNC and device paths.
+ /// </summary>
+ internal static ReadOnlySpan<char> GetVolumeName(ReadOnlySpan<char> path)
+ {
+ // 3 cases: UNC ("\\server\share"), Device ("\\?\C:\"), or Dos ("C:\")
+ ReadOnlySpan<char> root = GetPathRoot(path);
+ if (root.Length == 0)
+ return root;
+
+ int offset = GetUncRootLength(path);
+ if (offset >= 0)
+ {
+ // Cut from "\\?\UNC\Server\Share" to "Server\Share"
+ // Cut from "\\Server\Share" to "Server\Share"
+ return TrimEndingDirectorySeparator(root.Slice(offset));
+ }
+ else if (PathInternal.IsDevice(path))
+ {
+ return TrimEndingDirectorySeparator(root.Slice(4)); // Cut from "\\?\C:\" to "C:"
+ }
+
+ return TrimEndingDirectorySeparator(root); // e.g. "C:"
+ }
+
+ /// <summary>
+ /// Trims the ending directory separator if present.
+ /// </summary>
+ /// <param name="path"></param>
+ internal static ReadOnlySpan<char> TrimEndingDirectorySeparator(ReadOnlySpan<char> path) =>
+ PathInternal.EndsInDirectorySeparator(path) ?
+ path.Slice(0, path.Length - 1) :
+ path;
+
+ /// <summary>
+ /// Returns offset as -1 if the path is not in Unc format, otherwise returns the root length.
+ /// </summary>
+ /// <param name="path"></param>
+ /// <returns></returns>
+ internal static int GetUncRootLength(ReadOnlySpan<char> path)
+ {
+ bool isDevice = PathInternal.IsDevice(path);
+
+ if (!isDevice && path.Slice(0, 2).EqualsOrdinal(@"\\") )
+ return 2;
+ else if (isDevice && path.Length >= 8
+ && (path.Slice(0, 8).EqualsOrdinal(PathInternal.UncExtendedPathPrefix)
+ || path.Slice(5, 4).EqualsOrdinal(@"UNC\")))
+ return 8;
+
+ return -1;
+ }
}
}
diff --git a/src/Common/src/CoreLib/System/IO/Path.cs b/src/Common/src/CoreLib/System/IO/Path.cs
index 9f3f486000..1e40ab5e60 100644
--- a/src/Common/src/CoreLib/System/IO/Path.cs
+++ b/src/Common/src/CoreLib/System/IO/Path.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
+using System.Runtime.InteropServices;
using System.Text;
namespace System.IO
@@ -50,7 +51,7 @@ namespace System.IO
s = path.Substring(0, i);
break;
}
- if (PathInternal.IsDirectoryOrVolumeSeparator(ch)) break;
+ if (PathInternal.IsDirectorySeparator(ch)) break;
}
if (extension != null && path.Length != 0)
@@ -65,70 +66,133 @@ namespace System.IO
return null;
}
- // Returns the directory path of a file path. This method effectively
- // removes the last element of the given file path, i.e. it returns a
- // string consisting of all characters up to but not including the last
- // backslash ("\") in the file path. The returned value is null if the file
- // path is null or if the file path denotes a root (such as "\", "C:", or
- // "\\server\share").
+ /// <summary>
+ /// Returns the directory portion of a file path. This method effectively
+ /// removes the last segment of the given file path, i.e. it returns a
+ /// string consisting of all characters up to but not including the last
+ /// backslash ("\") in the file path. The returned value is null if the
+ /// specified path is null, empty, or a root (such as "\", "C:", or
+ /// "\\server\share").
+ /// </summary>
+ /// <remarks>
+ /// Directory separators are normalized in the returned string.
+ /// </remarks>
public static string GetDirectoryName(string path)
{
- if (path == null)
+ if (path == null || PathInternal.IsEffectivelyEmpty(path))
return null;
+ int end = GetDirectoryNameOffset(path);
+ return end >= 0 ? PathInternal.NormalizeDirectorySeparators(path.Substring(0, end)) : null;
+ }
+
+ /// <summary>
+ /// Returns the directory portion of a file path. The returned value is empty
+ /// if the specified path is null, empty, or a root (such as "\", "C:", or
+ /// "\\server\share").
+ /// </summary>
+ /// <remarks>
+ /// Unlike the string overload, this method will not normalize directory separators.
+ /// </remarks>
+ public static ReadOnlySpan<char> GetDirectoryName(ReadOnlySpan<char> path)
+ {
if (PathInternal.IsEffectivelyEmpty(path))
- throw new ArgumentException(SR.Arg_PathEmpty, nameof(path));
+ return ReadOnlySpan<char>.Empty;
- path = PathInternal.NormalizeDirectorySeparators(path);
- int root = PathInternal.GetRootLength(path);
+ int end = GetDirectoryNameOffset(path);
+ return end >= 0 ? path.Slice(0, end) : ReadOnlySpan<char>.Empty;
+ }
- int i = path.Length;
- if (i > root)
- {
- while (i > root && !PathInternal.IsDirectorySeparator(path[--i])) ;
- return path.Substring(0, i);
- }
-
- return null;
+ private static int GetDirectoryNameOffset(ReadOnlySpan<char> path)
+ {
+ int rootLength = PathInternal.GetRootLength(path);
+ int end = path.Length;
+ if (end <= rootLength)
+ return -1;
+
+ while (end > rootLength && !PathInternal.IsDirectorySeparator(path[--end]));
+
+ // Trim off any remaining separators (to deal with C:\foo\\bar)
+ while (end > rootLength && PathInternal.IsDirectorySeparator(path[end - 1]))
+ end--;
+
+ return end;
}
- // Returns the extension of the given path. The returned value includes the
- // period (".") character of the extension except when you have a terminal period when you get string.Empty, such as ".exe" or
- // ".cpp". The returned value is null if the given path is
- // null or if the given path does not include an extension.
+ /// <summary>
+ /// Returns the extension of the given path. The returned value includes the period (".") character of the
+ /// extension except when you have a terminal period when you get string.Empty, such as ".exe" or ".cpp".
+ /// The returned value is null if the given path is null or empty if the given path does not include an
+ /// extension.
+ /// </summary>
public static string GetExtension(string path)
{
if (path == null)
return null;
+ return new string(GetExtension(path.AsSpan()));
+ }
+
+ /// <summary>
+ /// Returns the extension of the given path.
+ /// </summary>
+ /// <remarks>
+ /// The returned value is an empty ReadOnlySpan if the given path does not include an extension.
+ /// </remarks>
+ public static ReadOnlySpan<char> GetExtension(ReadOnlySpan<char> path)
+ {
int length = path.Length;
+
for (int i = length - 1; i >= 0; i--)
{
char ch = path[i];
if (ch == '.')
{
if (i != length - 1)
- return path.Substring(i, length - i);
+ return path.Slice(i, length - i);
else
- return string.Empty;
+ return ReadOnlySpan<char>.Empty;
}
- if (PathInternal.IsDirectoryOrVolumeSeparator(ch))
+ if (PathInternal.IsDirectorySeparator(ch))
break;
}
- return string.Empty;
+ return ReadOnlySpan<char>.Empty;
}
- // Returns the name and extension parts of the given path. The resulting
- // string contains the characters of path that follow the last
- // separator in path. The resulting string is null if path is null.
+ /// <summary>
+ /// Returns the name and extension parts of the given path. The resulting string contains
+ /// the characters of path that follow the last separator in path. The resulting string is
+ /// null if path is null.
+ /// </summary>
public static string GetFileName(string path)
{
if (path == null)
return null;
- int offset = PathInternal.FindFileNameIndex(path);
- int count = path.Length - offset;
- return path.Substring(offset, count);
+ ReadOnlySpan<char> result = GetFileName(path.AsSpan());
+ if (path.Length == result.Length)
+ return path;
+
+ return new string(result);
+ }
+
+ /// <summary>
+ /// The returned ReadOnlySpan contains the characters of the path that follows the last separator in path.
+ /// </summary>
+ public static ReadOnlySpan<char> GetFileName(ReadOnlySpan<char> path)
+ {
+ int root = GetPathRoot(path).Length;
+
+ // We don't want to cut off "C:\file.txt:stream" (i.e. should be "file.txt:stream")
+ // but we *do* want "C:Foo" => "Foo". This necessitates checking for the root.
+
+ for (int i = path.Length; --i >= 0;)
+ {
+ if (i < root || PathInternal.IsDirectorySeparator(path[i]))
+ return path.Slice(i + 1, path.Length - i - 1);
+ }
+
+ return path;
}
public static string GetFileNameWithoutExtension(string path)
@@ -136,17 +200,29 @@ namespace System.IO
if (path == null)
return null;
- int length = path.Length;
- int offset = PathInternal.FindFileNameIndex(path);
+ ReadOnlySpan<char> result = GetFileNameWithoutExtension(path.AsSpan());
+ if (path.Length == result.Length)
+ return path;
- int end = path.LastIndexOf('.', length - 1, length - offset);
- return end == -1 ?
- path.Substring(offset) : // No extension was found
- path.Substring(offset, end - offset);
+ return new string(result);
}
- // Returns a cryptographically strong random 8.3 string that can be
- // used as either a folder name or a file name.
+ /// <summary>
+ /// Returns the characters between the last separator and last (.) in the path.
+ /// </summary>
+ public static ReadOnlySpan<char> GetFileNameWithoutExtension(ReadOnlySpan<char> path)
+ {
+ ReadOnlySpan<char> fileName = GetFileName(path);
+ int lastPeriod = fileName.LastIndexOf('.');
+ return lastPeriod == -1 ?
+ fileName : // No extension was found
+ fileName.Slice(0, lastPeriod);
+ }
+
+ /// <summary>
+ /// Returns a cryptographically strong random 8.3 string that can be
+ /// used as either a folder name or a file name.
+ /// </summary>
public static unsafe string GetRandomFileName()
{
byte* pKey = stackalloc byte[KeyLength];
@@ -176,29 +252,40 @@ namespace System.IO
public static bool IsPathFullyQualified(string path)
{
if (path == null)
- {
throw new ArgumentNullException(nameof(path));
- }
+
+ return IsPathFullyQualified(path.AsSpan());
+ }
+
+ public static bool IsPathFullyQualified(ReadOnlySpan<char> path)
+ {
return !PathInternal.IsPartiallyQualified(path);
}
- // Tests if a path includes a file extension. The result is
- // true if the characters that follow the last directory
- // separator ('\\' or '/') or volume separator (':') in the path include
- // a period (".") other than a terminal period. The result is false otherwise.
+ /// <summary>
+ /// Tests if a path's file name includes a file extension. A trailing period
+ /// is not considered an extension.
+ /// </summary>
public static bool HasExtension(string path)
{
if (path != null)
{
- for (int i = path.Length - 1; i >= 0; i--)
+ return HasExtension(path.AsSpan());
+ }
+ return false;
+ }
+
+ public static bool HasExtension(ReadOnlySpan<char> path)
+ {
+ for (int i = path.Length - 1; i >= 0; i--)
+ {
+ char ch = path[i];
+ if (ch == '.')
{
- char ch = path[i];
- if (ch == '.')
- {
- return i != path.Length - 1;
- }
- if (PathInternal.IsDirectoryOrVolumeSeparator(ch)) break;
+ return i != path.Length - 1;
}
+ if (PathInternal.IsDirectorySeparator(ch))
+ break;
}
return false;
}
@@ -208,7 +295,7 @@ namespace System.IO
if (path1 == null || path2 == null)
throw new ArgumentNullException((path1 == null) ? nameof(path1) : nameof(path2));
- return CombineNoChecks(path1, path2);
+ return CombineInternal(path1, path2);
}
public static string Combine(string path1, string path2, string path3)
@@ -216,7 +303,7 @@ namespace System.IO
if (path1 == null || path2 == null || path3 == null)
throw new ArgumentNullException((path1 == null) ? nameof(path1) : (path2 == null) ? nameof(path2) : nameof(path3));
- return CombineNoChecks(path1, path2, path3);
+ return CombineInternal(path1, path2, path3);
}
public static string Combine(string path1, string path2, string path3, string path4)
@@ -224,7 +311,7 @@ namespace System.IO
if (path1 == null || path2 == null || path3 == null || path4 == null)
throw new ArgumentNullException((path1 == null) ? nameof(path1) : (path2 == null) ? nameof(path2) : (path3 == null) ? nameof(path3) : nameof(path4));
- return CombineNoChecks(path1, path2, path3, path4);
+ return CombineInternal(path1, path2, path3, path4);
}
public static string Combine(params string[] paths)
@@ -263,7 +350,7 @@ namespace System.IO
}
char ch = paths[i][paths[i].Length - 1];
- if (!PathInternal.IsDirectoryOrVolumeSeparator(ch))
+ if (!PathInternal.IsDirectorySeparator(ch))
finalSize++;
}
@@ -283,7 +370,7 @@ namespace System.IO
else
{
char ch = finalPath[finalPath.Length - 1];
- if (!PathInternal.IsDirectoryOrVolumeSeparator(ch))
+ if (!PathInternal.IsDirectorySeparator(ch))
{
finalPath.Append(PathInternal.DirectorySeparatorChar);
}
@@ -295,120 +382,234 @@ namespace System.IO
return StringBuilderCache.GetStringAndRelease(finalPath);
}
- private static string CombineNoChecks(string path1, string path2)
- {
- if (path2.Length == 0)
- return path1;
+ // Unlike Combine(), Join() methods do not consider rooting. They simply combine paths, ensuring that there
+ // is a directory separator between them.
+ public static string Join(ReadOnlySpan<char> path1, ReadOnlySpan<char> path2)
+ {
if (path1.Length == 0)
- return path2;
-
- if (IsPathRooted(path2))
- return path2;
+ return new string(path2);
+ if (path2.Length == 0)
+ return new string(path1);
- char ch = path1[path1.Length - 1];
- return PathInternal.IsDirectoryOrVolumeSeparator(ch) ?
- path1 + path2 :
- path1 + PathInternal.DirectorySeparatorCharAsString + path2;
+ return JoinInternal(path1, path2);
}
- private static string CombineNoChecks(string path1, string path2, string path3)
+ public static string Join(ReadOnlySpan<char> path1, ReadOnlySpan<char> path2, ReadOnlySpan<char> path3)
{
if (path1.Length == 0)
- return CombineNoChecks(path2, path3);
+ return Join(path2, path3);
+
if (path2.Length == 0)
- return CombineNoChecks(path1, path3);
+ return Join(path1, path3);
+
if (path3.Length == 0)
- return CombineNoChecks(path1, path2);
+ return Join(path1, path2);
- if (IsPathRooted(path3))
- return path3;
- if (IsPathRooted(path2))
- return CombineNoChecks(path2, path3);
+ return JoinInternal(path1, path2, path3);
+ }
- bool hasSep1 = PathInternal.IsDirectoryOrVolumeSeparator(path1[path1.Length - 1]);
- bool hasSep2 = PathInternal.IsDirectoryOrVolumeSeparator(path2[path2.Length - 1]);
+ public static bool TryJoin(ReadOnlySpan<char> path1, ReadOnlySpan<char> path2, Span<char> destination, out int charsWritten)
+ {
+ charsWritten = 0;
+ if (path1.Length == 0 && path2.Length == 0)
+ return true;
- if (hasSep1 && hasSep2)
+ if (path1.Length == 0 || path2.Length == 0)
{
- return path1 + path2 + path3;
- }
- else if (hasSep1)
- {
- return path1 + path2 + PathInternal.DirectorySeparatorCharAsString + path3;
- }
- else if (hasSep2)
- {
- return path1 + PathInternal.DirectorySeparatorCharAsString + path2 + path3;
- }
- else
- {
- // string.Concat only has string-based overloads up to four arguments; after that requires allocating
- // a params string[]. Instead, try to use a cached StringBuilder.
- StringBuilder sb = StringBuilderCache.Acquire(path1.Length + path2.Length + path3.Length + 2);
- sb.Append(path1)
- .Append(PathInternal.DirectorySeparatorChar)
- .Append(path2)
- .Append(PathInternal.DirectorySeparatorChar)
- .Append(path3);
- return StringBuilderCache.GetStringAndRelease(sb);
+ ref ReadOnlySpan<char> pathToUse = ref path1.Length == 0 ? ref path2 : ref path1;
+ if (destination.Length < pathToUse.Length)
+ {
+ return false;
+ }
+
+ pathToUse.CopyTo(destination);
+ charsWritten = pathToUse.Length;
+ return true;
}
+
+ bool needsSeparator = !(PathInternal.EndsInDirectorySeparator(path1) || PathInternal.StartsWithDirectorySeparator(path2));
+ int charsNeeded = path1.Length + path2.Length + (needsSeparator ? 1 : 0);
+ if (destination.Length < charsNeeded)
+ return false;
+
+ path1.CopyTo(destination);
+ if (needsSeparator)
+ destination[path1.Length] = DirectorySeparatorChar;
+
+ path2.CopyTo(destination.Slice(path1.Length + (needsSeparator ? 1 : 0)));
+
+ charsWritten = charsNeeded;
+ return true;
}
- private static string CombineNoChecks(string path1, string path2, string path3, string path4)
+ public static bool TryJoin(ReadOnlySpan<char> path1, ReadOnlySpan<char> path2, ReadOnlySpan<char> path3, Span<char> destination, out int charsWritten)
{
+ charsWritten = 0;
+ if (path1.Length == 0 && path2.Length == 0 && path3.Length == 0)
+ return true;
+
if (path1.Length == 0)
- return CombineNoChecks(path2, path3, path4);
+ return TryJoin(path2, path3, destination, out charsWritten);
if (path2.Length == 0)
- return CombineNoChecks(path1, path3, path4);
+ return TryJoin(path1, path3, destination, out charsWritten);
if (path3.Length == 0)
- return CombineNoChecks(path1, path2, path4);
- if (path4.Length == 0)
- return CombineNoChecks(path1, path2, path3);
-
- if (IsPathRooted(path4))
- return path4;
- if (IsPathRooted(path3))
- return CombineNoChecks(path3, path4);
- if (IsPathRooted(path2))
- return CombineNoChecks(path2, path3, path4);
-
- bool hasSep1 = PathInternal.IsDirectoryOrVolumeSeparator(path1[path1.Length - 1]);
- bool hasSep2 = PathInternal.IsDirectoryOrVolumeSeparator(path2[path2.Length - 1]);
- bool hasSep3 = PathInternal.IsDirectoryOrVolumeSeparator(path3[path3.Length - 1]);
-
- if (hasSep1 && hasSep2 && hasSep3)
+ return TryJoin(path1, path2, destination, out charsWritten);
+
+ int neededSeparators = PathInternal.EndsInDirectorySeparator(path1) || PathInternal.StartsWithDirectorySeparator(path2) ? 0 : 1;
+ bool needsSecondSeparator = !(PathInternal.EndsInDirectorySeparator(path2) || PathInternal.StartsWithDirectorySeparator(path3));
+ if (needsSecondSeparator)
+ neededSeparators++;
+
+ int charsNeeded = path1.Length + path2.Length + path3.Length + neededSeparators;
+ if (destination.Length < charsNeeded)
+ return false;
+
+ bool result = TryJoin(path1, path2, destination, out charsWritten);
+ Debug.Assert(result, "should never fail joining first two paths");
+
+ if (needsSecondSeparator)
+ destination[charsWritten++] = DirectorySeparatorChar;
+
+ path3.CopyTo(destination.Slice(charsWritten));
+ charsWritten += path3.Length;
+
+ return true;
+ }
+
+ private static string CombineInternal(string first, string second)
+ {
+ if (string.IsNullOrEmpty(first))
+ return second;
+
+ if (string.IsNullOrEmpty(second))
+ return first;
+
+ if (IsPathRooted(second.AsSpan()))
+ return second;
+
+ return JoinInternal(first, second);
+ }
+
+ private static string CombineInternal(string first, string second, string third)
+ {
+ if (string.IsNullOrEmpty(first))
+ return CombineInternal(second, third);
+ if (string.IsNullOrEmpty(second))
+ return CombineInternal(first, third);
+ if (string.IsNullOrEmpty(third))
+ return CombineInternal(first, second);
+
+ if (IsPathRooted(third.AsSpan()))
+ return third;
+ if (IsPathRooted(second.AsSpan()))
+ return CombineInternal(second, third);
+
+ return JoinInternal(first, second, third);
+ }
+
+ private static string CombineInternal(string first, string second, string third, string fourth)
+ {
+ if (string.IsNullOrEmpty(first))
+ return CombineInternal(second, third, fourth);
+ if (string.IsNullOrEmpty(second))
+ return CombineInternal(first, third, fourth);
+ if (string.IsNullOrEmpty(third))
+ return CombineInternal(first, second, fourth);
+ if (string.IsNullOrEmpty(fourth))
+ return CombineInternal(first, second, third);
+
+ if (IsPathRooted(fourth.AsSpan()))
+ return fourth;
+ if (IsPathRooted(third.AsSpan()))
+ return CombineInternal(third, fourth);
+ if (IsPathRooted(second.AsSpan()))
+ return CombineInternal(second, third, fourth);
+
+ return JoinInternal(first, second, third, fourth);
+ }
+
+ private static unsafe string JoinInternal(ReadOnlySpan<char> first, ReadOnlySpan<char> second)
+ {
+ Debug.Assert(first.Length > 0 && second.Length > 0, "should have dealt with empty paths");
+
+ bool hasSeparator = PathInternal.IsDirectorySeparator(first[first.Length - 1])
+ || PathInternal.IsDirectorySeparator(second[0]);
+
+ fixed (char* f = &MemoryMarshal.GetReference(first), s = &MemoryMarshal.GetReference(second))
{
- // Use string.Concat overload that takes four strings
- return path1 + path2 + path3 + path4;
+ return string.Create(
+ first.Length + second.Length + (hasSeparator ? 0 : 1),
+ (First: (IntPtr)f, FirstLength: first.Length, Second: (IntPtr)s, SecondLength: second.Length, HasSeparator: hasSeparator),
+ (destination, state) =>
+ {
+ new Span<char>((char*)state.First, state.FirstLength).CopyTo(destination);
+ if (!state.HasSeparator)
+ destination[state.FirstLength] = PathInternal.DirectorySeparatorChar;
+ new Span<char>((char*)state.Second, state.SecondLength).CopyTo(destination.Slice(state.FirstLength + (state.HasSeparator ? 0 : 1)));
+ });
}
- else
- {
- // string.Concat only has string-based overloads up to four arguments; after that requires allocating
- // a params string[]. Instead, try to use a cached StringBuilder.
- StringBuilder sb = StringBuilderCache.Acquire(path1.Length + path2.Length + path3.Length + path4.Length + 3);
+ }
- sb.Append(path1);
- if (!hasSep1)
- {
- sb.Append(PathInternal.DirectorySeparatorChar);
- }
+ private static unsafe string JoinInternal(ReadOnlySpan<char> first, ReadOnlySpan<char> second, ReadOnlySpan<char> third)
+ {
+ Debug.Assert(first.Length > 0 && second.Length > 0 && third.Length > 0, "should have dealt with empty paths");
- sb.Append(path2);
- if (!hasSep2)
- {
- sb.Append(PathInternal.DirectorySeparatorChar);
- }
+ bool firstHasSeparator = PathInternal.IsDirectorySeparator(first[first.Length - 1])
+ || PathInternal.IsDirectorySeparator(second[0]);
+ bool thirdHasSeparator = PathInternal.IsDirectorySeparator(second[second.Length - 1])
+ || PathInternal.IsDirectorySeparator(third[0]);
- sb.Append(path3);
- if (!hasSep3)
- {
- sb.Append(PathInternal.DirectorySeparatorChar);
- }
+ fixed (char* f = &MemoryMarshal.GetReference(first), s = &MemoryMarshal.GetReference(second), t = &MemoryMarshal.GetReference(third))
+ {
+ return string.Create(
+ first.Length + second.Length + third.Length + (firstHasSeparator ? 0 : 1) + (thirdHasSeparator ? 0 : 1),
+ (First: (IntPtr)f, FirstLength: first.Length, Second: (IntPtr)s, SecondLength: second.Length,
+ Third: (IntPtr)t, ThirdLength: third.Length, FirstHasSeparator: firstHasSeparator, ThirdHasSeparator: thirdHasSeparator),
+ (destination, state) =>
+ {
+ new Span<char>((char*)state.First, state.FirstLength).CopyTo(destination);
+ if (!state.FirstHasSeparator)
+ destination[state.FirstLength] = PathInternal.DirectorySeparatorChar;
+ new Span<char>((char*)state.Second, state.SecondLength).CopyTo(destination.Slice(state.FirstLength + (state.FirstHasSeparator ? 0 : 1)));
+ if (!state.ThirdHasSeparator)
+ destination[destination.Length - state.ThirdLength - 1] = PathInternal.DirectorySeparatorChar;
+ new Span<char>((char*)state.Third, state.ThirdLength).CopyTo(destination.Slice(destination.Length - state.ThirdLength));
+ });
+ }
+ }
+
+ private static unsafe string JoinInternal(ReadOnlySpan<char> first, ReadOnlySpan<char> second, ReadOnlySpan<char> third, ReadOnlySpan<char> fourth)
+ {
+ Debug.Assert(first.Length > 0 && second.Length > 0 && third.Length > 0 && fourth.Length > 0, "should have dealt with empty paths");
- sb.Append(path4);
+ bool firstHasSeparator = PathInternal.IsDirectorySeparator(first[first.Length - 1])
+ || PathInternal.IsDirectorySeparator(second[0]);
+ bool thirdHasSeparator = PathInternal.IsDirectorySeparator(second[second.Length - 1])
+ || PathInternal.IsDirectorySeparator(third[0]);
+ bool fourthHasSeparator = PathInternal.IsDirectorySeparator(third[third.Length - 1])
+ || PathInternal.IsDirectorySeparator(fourth[0]);
- return StringBuilderCache.GetStringAndRelease(sb);
+ fixed (char* f = &MemoryMarshal.GetReference(first), s = &MemoryMarshal.GetReference(second), t = &MemoryMarshal.GetReference(third), u = &MemoryMarshal.GetReference(fourth))
+ {
+ return string.Create(
+ first.Length + second.Length + third.Length + fourth.Length + (firstHasSeparator ? 0 : 1) + (thirdHasSeparator ? 0 : 1) + (fourthHasSeparator ? 0 : 1),
+ (First: (IntPtr)f, FirstLength: first.Length, Second: (IntPtr)s, SecondLength: second.Length,
+ Third: (IntPtr)t, ThirdLength: third.Length, Fourth: (IntPtr)u, FourthLength:fourth.Length,
+ FirstHasSeparator: firstHasSeparator, ThirdHasSeparator: thirdHasSeparator, FourthHasSeparator: fourthHasSeparator),
+ (destination, state) =>
+ {
+ new Span<char>((char*)state.First, state.FirstLength).CopyTo(destination);
+ if (!state.FirstHasSeparator)
+ destination[state.FirstLength] = PathInternal.DirectorySeparatorChar;
+ new Span<char>((char*)state.Second, state.SecondLength).CopyTo(destination.Slice(state.FirstLength + (state.FirstHasSeparator ? 0 : 1)));
+ if (!state.ThirdHasSeparator)
+ destination[state.FirstLength + state.SecondLength + (state.FirstHasSeparator ? 0 : 1)] = PathInternal.DirectorySeparatorChar;
+ new Span<char>((char*)state.Third, state.ThirdLength).CopyTo(destination.Slice(state.FirstLength + state.SecondLength + (state.FirstHasSeparator ? 0 : 1) + (state.ThirdHasSeparator ? 0 : 1)));
+ if (!state.FourthHasSeparator)
+ destination[destination.Length - state.FourthLength - 1] = PathInternal.DirectorySeparatorChar;
+ new Span<char>((char*)state.Fourth, state.FourthLength).CopyTo(destination.Slice(destination.Length - state.FourthLength));
+ });
}
}
@@ -556,9 +757,6 @@ namespace System.IO
return StringBuilderCache.GetStringAndRelease(sb);
}
- // StringComparison and IsCaseSensitive are also available in PathInternal.CaseSensitivity but we are
- // too low in System.Runtime.Extensions to use it (no FileStream, etc.)
-
/// <summary>Returns a comparison that can be used to compare file and directory names for equality.</summary>
internal static StringComparison StringComparison
{
diff --git a/src/Common/src/CoreLib/System/IO/PathHelper.Windows.cs b/src/Common/src/CoreLib/System/IO/PathHelper.Windows.cs
index a0dba661f8..ed49422c1a 100644
--- a/src/Common/src/CoreLib/System/IO/PathHelper.Windows.cs
+++ b/src/Common/src/CoreLib/System/IO/PathHelper.Windows.cs
@@ -3,8 +3,8 @@
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
-using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using System.Text;
namespace System.IO
{
@@ -13,197 +13,88 @@ namespace System.IO
/// </summary>
internal class PathHelper
{
- // Can't be over 8.3 and be a short name
- private const int MaxShortName = 12;
-
- private const char LastAnsi = (char)255;
- private const char Delete = (char)127;
-
/// <summary>
/// Normalize the given path.
/// </summary>
/// <remarks>
- /// Normalizes via Win32 GetFullPathName(). Will also trim initial
- /// spaces if the path is determined to be rooted.
- ///
- /// Note that invalid characters will be checked after the path is normalized, which could remove bad characters. (C:\|\..\a.txt -- C:\a.txt)
+ /// Normalizes via Win32 GetFullPathName().
/// </remarks>
/// <param name="path">Path to normalize</param>
- /// <param name="checkInvalidCharacters">True to check for invalid characters</param>
- /// <param name="expandShortPaths">Attempt to expand short paths if true</param>
- /// <exception cref="ArgumentException">Thrown if the path is an illegal UNC (does not contain a full server/share) or contains illegal characters.</exception>
- /// <exception cref="PathTooLongException">Thrown if the path or a path segment exceeds the filesystem limits.</exception>
- /// <exception cref="FileNotFoundException">Thrown if Windows returns ERROR_FILE_NOT_FOUND. (See Win32Marshal.GetExceptionForWin32Error)</exception>
- /// <exception cref="DirectoryNotFoundException">Thrown if Windows returns ERROR_PATH_NOT_FOUND. (See Win32Marshal.GetExceptionForWin32Error)</exception>
- /// <exception cref="UnauthorizedAccessException">Thrown if Windows returns ERROR_ACCESS_DENIED. (See Win32Marshal.GetExceptionForWin32Error)</exception>
- /// <exception cref="IOException">Thrown if Windows returns an error that doesn't map to the above. (See Win32Marshal.GetExceptionForWin32Error)</exception>
+ /// <exception cref="PathTooLongException">Thrown if we have a string that is too large to fit into a UNICODE_STRING.</exception>
+ /// <exception cref="IOException">Thrown if the path is empty.</exception>
/// <returns>Normalized path</returns>
- internal static string Normalize(string path, bool checkInvalidCharacters, bool expandShortPaths)
+ internal static string Normalize(string path)
{
- // Get the full path
- StringBuffer fullPath = new StringBuffer(PathInternal.MaxShortPath);
-
- try
- {
- GetFullPathName(path, ref fullPath);
-
- // Checking path validity used to happen before getting the full path name. To avoid additional input allocation
- // (to trim trailing whitespace) we now do it after the Win32 call. This will allow legitimate paths through that
- // used to get kicked back (notably segments with invalid characters might get removed via "..").
- //
- // There is no way that GetLongPath can invalidate the path so we'll do this (cheaper) check before we attempt to
- // expand short file names.
-
- // Scan the path for:
- //
- // - Illegal path characters.
- // - Invalid UNC paths like \\, \\server, \\server\.
-
- // As the path could be > 30K, we'll combine the validity scan. None of these checks are performed by the Win32
- // GetFullPathName() API.
-
- bool possibleShortPath = false;
- bool foundTilde = false;
-
- // We can get UNCs as device paths through this code (e.g. \\.\UNC\), we won't validate them as there isn't
- // an easy way to normalize without extensive cost (we'd have to hunt down the canonical name for any device
- // path that contains UNC or to see if the path was doing something like \\.\GLOBALROOT\Device\Mup\,
- // \\.\GLOBAL\UNC\, \\.\GLOBALROOT\GLOBAL??\UNC\, etc.
- bool specialPath = fullPath.Length > 1 && fullPath[0] == '\\' && fullPath[1] == '\\';
- bool isDevice = PathInternal.IsDevice(ref fullPath);
- bool possibleBadUnc = specialPath && !isDevice;
- int index = specialPath ? 2 : 0;
- int lastSeparator = specialPath ? 1 : 0;
- int segmentLength;
- char current;
-
- while (index < fullPath.Length)
- {
- current = fullPath[index];
+ Span<char> initialBuffer = stackalloc char[PathInternal.MaxShortPath];
+ var builder = new ValueStringBuilder(initialBuffer);
- // Try to skip deeper analysis. '?' and higher are valid/ignorable except for '\', '|', and '~'
- if (current < '?' || current == '\\' || current == '|' || current == '~')
- {
- switch (current)
- {
- case '|':
- case '>':
- case '<':
- case '\"':
- if (checkInvalidCharacters) throw new ArgumentException(SR.Argument_InvalidPathChars);
- foundTilde = false;
- break;
- case '~':
- foundTilde = true;
- break;
- case '\\':
- segmentLength = index - lastSeparator - 1;
- lastSeparator = index;
-
- if (foundTilde)
- {
- if (segmentLength <= MaxShortName)
- {
- // Possibly a short path.
- possibleShortPath = true;
- }
-
- foundTilde = false;
- }
-
- if (possibleBadUnc)
- {
- // If we're at the end of the path and this is the first separator, we're missing the share.
- // Otherwise we're good, so ignore UNC tracking from here.
- if (index == fullPath.Length - 1)
- throw new ArgumentException(SR.Format(SR.Arg_PathIllegalUNC_Path, fullPath.ToString()));
- else
- possibleBadUnc = false;
- }
-
- break;
-
- default:
- if (checkInvalidCharacters && current < ' ') throw new ArgumentException(SR.Argument_InvalidPathChars, nameof(path));
- break;
- }
- }
+ // Get the full path
+ GetFullPathName(path.AsSpan(), ref builder);
- index++;
- }
+ // If we have the exact same string we were passed in, don't allocate another string.
+ // TryExpandShortName does this input identity check.
+ string result = builder.AsSpan().IndexOf('~') >= 0
+ ? TryExpandShortFileName(ref builder, originalPath: path)
+ : builder.AsSpan().Equals(path.AsSpan(), StringComparison.Ordinal) ? path : builder.ToString();
- if (possibleBadUnc)
- throw new ArgumentException(SR.Format(SR.Arg_PathIllegalUNC_Path, fullPath.ToString()));
+ // Clear the buffer
+ builder.Dispose();
+ return result;
+ }
- segmentLength = fullPath.Length - lastSeparator - 1;
+ /// <summary>
+ /// Normalize the given path.
+ /// </summary>
+ /// <remarks>
+ /// Exceptions are the same as the string overload.
+ /// </remarks>
+ internal static string Normalize(ref ValueStringBuilder path)
+ {
+ Span<char> initialBuffer = stackalloc char[PathInternal.MaxShortPath];
+ var builder = new ValueStringBuilder(initialBuffer);
- if (foundTilde && segmentLength <= MaxShortName)
- possibleShortPath = true;
+ // Get the full path
+ GetFullPathName(path.AsSpan(terminate: true), ref builder);
- // Check for a short filename path and try and expand it. Technically you don't need to have a tilde for a short name, but
- // this is how we've always done this. This expansion is costly so we'll continue to let other short paths slide.
- if (expandShortPaths && possibleShortPath)
- {
- return TryExpandShortFileName(ref fullPath, originalPath: path);
- }
- else
- {
- if (fullPath.Length == path.Length && fullPath.StartsWith(path))
- {
- // If we have the exact same string we were passed in, don't bother to allocate another string from the StringBuilder.
- return path;
- }
- else
- {
- return fullPath.ToString();
- }
- }
- }
- finally
- {
- // Clear the buffer
- fullPath.Free();
- }
- }
+ string result = builder.AsSpan().IndexOf('~') >= 0
+ ? TryExpandShortFileName(ref builder, originalPath: null)
+ : builder.ToString();
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool IsDosUnc(ref StringBuffer buffer)
- {
- return !PathInternal.IsDevice(ref buffer) && buffer.Length > 1 && buffer[0] == '\\' && buffer[1] == '\\';
+ // Clear the buffer
+ builder.Dispose();
+ return result;
}
- private static unsafe void GetFullPathName(string path, ref StringBuffer fullPath)
+ /// <summary>
+ /// Calls GetFullPathName on the given path.
+ /// </summary>
+ /// <param name="path">The path name. MUST be null terminated after the span.</param>
+ private static void GetFullPathName(ReadOnlySpan<char> path, ref ValueStringBuilder builder)
{
// If the string starts with an extended prefix we would need to remove it from the path before we call GetFullPathName as
// it doesn't root extended paths correctly. We don't currently resolve extended paths, so we'll just assert here.
Debug.Assert(PathInternal.IsPartiallyQualified(path) || !PathInternal.IsExtended(path));
- // Historically we would skip leading spaces *only* if the path started with a drive " C:" or a UNC " \\"
- int startIndex = PathInternal.PathStartSkip(path);
-
- fixed (char* pathStart = path)
+ uint result = 0;
+ while ((result = Interop.Kernel32.GetFullPathNameW(ref MemoryMarshal.GetReference(path), (uint)builder.Capacity, ref builder.GetPinnableReference(), IntPtr.Zero)) > builder.Capacity)
{
- uint result = 0;
- while ((result = Interop.Kernel32.GetFullPathNameW(pathStart + startIndex, (uint)fullPath.Capacity, fullPath.UnderlyingArray, IntPtr.Zero)) > fullPath.Capacity)
- {
- // Reported size is greater than the buffer size. Increase the capacity.
- fullPath.EnsureCapacity(checked((int)result));
- }
-
- if (result == 0)
- {
- // Failure, get the error and throw
- int errorCode = Marshal.GetLastWin32Error();
- if (errorCode == 0)
- errorCode = Interop.Errors.ERROR_BAD_PATHNAME;
- throw Win32Marshal.GetExceptionForWin32Error(errorCode, path);
- }
+ // Reported size is greater than the buffer size. Increase the capacity.
+ builder.EnsureCapacity(checked((int)result));
+ }
- fullPath.Length = checked((int)result);
+ if (result == 0)
+ {
+ // Failure, get the error and throw
+ int errorCode = Marshal.GetLastWin32Error();
+ if (errorCode == 0)
+ errorCode = Interop.Errors.ERROR_BAD_PATHNAME;
+ throw Win32Marshal.GetExceptionForWin32Error(errorCode, path.ToString());
}
+
+ builder.Length = (int)result;
}
- private static int GetInputBuffer(ref StringBuffer content, bool isDosUnc, ref StringBuffer buffer)
+ internal static int PrependDevicePathChars(ref ValueStringBuilder content, bool isDosUnc, ref ValueStringBuilder buffer)
{
int length = content.Length;
@@ -212,37 +103,34 @@ namespace System.IO
: PathInternal.DevicePrefixLength;
buffer.EnsureCapacity(length + 1);
+ buffer.Length = 0;
if (isDosUnc)
{
- // Put the extended UNC prefix (\\?\UNC\) in front of the path
- buffer.CopyFrom(bufferIndex: 0, source: PathInternal.UncExtendedPathPrefix);
+ // Is a \\Server\Share, put \\?\UNC\ in the front
+ buffer.Append(PathInternal.UncExtendedPathPrefix);
- // Copy the source buffer over after the existing UNC prefix
- content.CopyTo(
- bufferIndex: PathInternal.UncPrefixLength,
- destination: ref buffer,
- destinationIndex: PathInternal.UncExtendedPrefixLength,
- count: content.Length - PathInternal.UncPrefixLength);
+ // Copy Server\Share\... over to the buffer
+ buffer.Append(content.AsSpan(PathInternal.UncPrefixLength));
// Return the prefix difference
return PathInternal.UncExtendedPrefixLength - PathInternal.UncPrefixLength;
}
else
{
- int prefixSize = PathInternal.ExtendedPathPrefix.Length;
- buffer.CopyFrom(bufferIndex: 0, source: PathInternal.ExtendedPathPrefix);
- content.CopyTo(bufferIndex: 0, destination: ref buffer, destinationIndex: prefixSize, count: content.Length);
- return prefixSize;
+ // Not an UNC, put the \\?\ prefix in front, then the original string
+ buffer.Append(PathInternal.ExtendedPathPrefix);
+ buffer.Append(content.AsSpan());
+ return PathInternal.DevicePrefixLength;
}
}
- private static string TryExpandShortFileName(ref StringBuffer outputBuffer, string originalPath)
+ internal static string TryExpandShortFileName(ref ValueStringBuilder outputBuilder, string originalPath)
{
// We guarantee we'll expand short names for paths that only partially exist. As such, we need to find the part of the path that actually does exist. To
// avoid allocating like crazy we'll create only one input array and modify the contents with embedded nulls.
- Debug.Assert(!PathInternal.IsPartiallyQualified(ref outputBuffer), "should have resolved by now");
+ Debug.Assert(!PathInternal.IsPartiallyQualified(outputBuilder.AsSpan()), "should have resolved by now");
// We'll have one of a few cases by now (the normalized path will have already:
//
@@ -250,135 +138,115 @@ namespace System.IO
// 2. Dos UNC (\\Server\Share)
// 3. Dos device path (\\.\C:\, \\?\C:\)
//
- // We want to put the extended syntax on the front if it doesn't already have it, which may mean switching from \\.\.
+ // We want to put the extended syntax on the front if it doesn't already have it (for long path support and speed), which may mean switching from \\.\.
//
// Note that we will never get \??\ here as GetFullPathName() does not recognize \??\ and will return it as C:\??\ (or whatever the current drive is).
- int rootLength = PathInternal.GetRootLength(ref outputBuffer);
- bool isDevice = PathInternal.IsDevice(ref outputBuffer);
+ int rootLength = PathInternal.GetRootLength(outputBuilder.AsSpan());
+ bool isDevice = PathInternal.IsDevice(outputBuilder.AsSpan());
- StringBuffer inputBuffer = new StringBuffer(0);
- try
- {
- bool isDosUnc = false;
- int rootDifference = 0;
- bool wasDotDevice = false;
+ // As this is a corner case we're not going to add a stackalloc here to keep the stack pressure down.
+ var inputBuilder = new ValueStringBuilder();
- // Add the extended prefix before expanding to allow growth over MAX_PATH
- if (isDevice)
- {
- // We have one of the following (\\?\ or \\.\)
- inputBuffer.Append(ref outputBuffer);
+ bool isDosUnc = false;
+ int rootDifference = 0;
+ bool wasDotDevice = false;
- if (outputBuffer[2] == '.')
- {
- wasDotDevice = true;
- inputBuffer[2] = '?';
- }
- }
- else
+ // Add the extended prefix before expanding to allow growth over MAX_PATH
+ if (isDevice)
+ {
+ // We have one of the following (\\?\ or \\.\)
+ inputBuilder.Append(outputBuilder.AsSpan());
+
+ if (outputBuilder[2] == '.')
{
- isDosUnc = IsDosUnc(ref outputBuffer);
- rootDifference = GetInputBuffer(ref outputBuffer, isDosUnc, ref inputBuffer);
+ wasDotDevice = true;
+ inputBuilder[2] = '?';
}
+ }
+ else
+ {
+ isDosUnc = !PathInternal.IsDevice(outputBuilder.AsSpan()) && outputBuilder.Length > 1 && outputBuilder[0] == '\\' && outputBuilder[1] == '\\';
+ rootDifference = PrependDevicePathChars(ref outputBuilder, isDosUnc, ref inputBuilder);
+ }
- rootLength += rootDifference;
- int inputLength = inputBuffer.Length;
+ rootLength += rootDifference;
+ int inputLength = inputBuilder.Length;
- bool success = false;
- int foundIndex = inputBuffer.Length - 1;
+ bool success = false;
+ int foundIndex = inputBuilder.Length - 1;
- while (!success)
- {
- uint result = Interop.Kernel32.GetLongPathNameW(inputBuffer.UnderlyingArray, outputBuffer.UnderlyingArray, (uint)outputBuffer.Capacity);
+ while (!success)
+ {
+ uint result = Interop.Kernel32.GetLongPathNameW(
+ ref inputBuilder.GetPinnableReference(terminate: true), ref outputBuilder.GetPinnableReference(), (uint)outputBuilder.Capacity);
- // Replace any temporary null we added
- if (inputBuffer[foundIndex] == '\0') inputBuffer[foundIndex] = '\\';
+ // Replace any temporary null we added
+ if (inputBuilder[foundIndex] == '\0') inputBuilder[foundIndex] = '\\';
- if (result == 0)
+ if (result == 0)
+ {
+ // Look to see if we couldn't find the file
+ int error = Marshal.GetLastWin32Error();
+ if (error != Interop.Errors.ERROR_FILE_NOT_FOUND && error != Interop.Errors.ERROR_PATH_NOT_FOUND)
{
- // Look to see if we couldn't find the file
- int error = Marshal.GetLastWin32Error();
- if (error != Interop.Errors.ERROR_FILE_NOT_FOUND && error != Interop.Errors.ERROR_PATH_NOT_FOUND)
- {
- // Some other failure, give up
- break;
- }
-
- // We couldn't find the path at the given index, start looking further back in the string.
- foundIndex--;
-
- for (; foundIndex > rootLength && inputBuffer[foundIndex] != '\\'; foundIndex--) ;
- if (foundIndex == rootLength)
- {
- // Can't trim the path back any further
- break;
- }
- else
- {
- // Temporarily set a null in the string to get Windows to look further up the path
- inputBuffer[foundIndex] = '\0';
- }
+ // Some other failure, give up
+ break;
}
- else if (result > outputBuffer.Capacity)
+
+ // We couldn't find the path at the given index, start looking further back in the string.
+ foundIndex--;
+
+ for (; foundIndex > rootLength && inputBuilder[foundIndex] != '\\'; foundIndex--) ;
+ if (foundIndex == rootLength)
{
- // Not enough space. The result count for this API does not include the null terminator.
- outputBuffer.EnsureCapacity(checked((int)result));
- result = Interop.Kernel32.GetLongPathNameW(inputBuffer.UnderlyingArray, outputBuffer.UnderlyingArray, (uint)outputBuffer.Capacity);
+ // Can't trim the path back any further
+ break;
}
else
{
- // Found the path
- success = true;
- outputBuffer.Length = checked((int)result);
- if (foundIndex < inputLength - 1)
- {
- // It was a partial find, put the non-existent part of the path back
- outputBuffer.Append(ref inputBuffer, foundIndex, inputBuffer.Length - foundIndex);
- }
+ // Temporarily set a null in the string to get Windows to look further up the path
+ inputBuilder[foundIndex] = '\0';
}
}
-
- // Strip out the prefix and return the string
- ref StringBuffer bufferToUse = ref Choose(success, ref outputBuffer, ref inputBuffer);
-
- // Switch back from \\?\ to \\.\ if necessary
- if (wasDotDevice)
- bufferToUse[2] = '.';
-
- string returnValue = null;
-
- int newLength = (int)(bufferToUse.Length - rootDifference);
- if (isDosUnc)
- {
- // Need to go from \\?\UNC\ to \\?\UN\\
- bufferToUse[PathInternal.UncExtendedPrefixLength - PathInternal.UncPrefixLength] = '\\';
- }
-
- // We now need to strip out any added characters at the front of the string
- if (bufferToUse.SubstringEquals(originalPath, rootDifference, newLength))
+ else if (result > outputBuilder.Capacity)
{
- // Use the original path to avoid allocating
- returnValue = originalPath;
+ // Not enough space. The result count for this API does not include the null terminator.
+ outputBuilder.EnsureCapacity(checked((int)result));
+ result = Interop.Kernel32.GetLongPathNameW(ref inputBuilder.GetPinnableReference(), ref outputBuilder.GetPinnableReference(), (uint)outputBuilder.Capacity);
}
else
{
- returnValue = bufferToUse.Substring(rootDifference, newLength);
+ // Found the path
+ success = true;
+ outputBuilder.Length = checked((int)result);
+ if (foundIndex < inputLength - 1)
+ {
+ // It was a partial find, put the non-existent part of the path back
+ outputBuilder.Append(inputBuilder.AsSpan(foundIndex, inputBuilder.Length - foundIndex));
+ }
}
-
- return returnValue;
}
- finally
- {
- inputBuffer.Free();
- }
- }
- // Helper method to workaround lack of operator ? support for ref values
- private static ref StringBuffer Choose(bool condition, ref StringBuffer s1, ref StringBuffer s2)
- {
- if (condition) return ref s1;
- else return ref s2;
+ // If we were able to expand the path, use it, otherwise use the original full path result
+ ref ValueStringBuilder builderToUse = ref (success ? ref outputBuilder : ref inputBuilder);
+
+ // Switch back from \\?\ to \\.\ if necessary
+ if (wasDotDevice)
+ builderToUse[2] = '.';
+
+ // Change from \\?\UNC\ to \\?\UN\\ if needed
+ if (isDosUnc)
+ builderToUse[PathInternal.UncExtendedPrefixLength - PathInternal.UncPrefixLength] = '\\';
+
+ // Strip out any added characters at the front of the string
+ ReadOnlySpan<char> output = builderToUse.AsSpan(rootDifference);
+
+ string returnValue = ((originalPath != null) && output.Equals(originalPath.AsSpan(), StringComparison.Ordinal))
+ ? originalPath : new string(output);
+
+ inputBuilder.Dispose();
+ return returnValue;
}
}
}
diff --git a/src/Common/src/CoreLib/System/IO/PathInternal.Unix.cs b/src/Common/src/CoreLib/System/IO/PathInternal.Unix.cs
index 2f65a4252b..fae309be56 100644
--- a/src/Common/src/CoreLib/System/IO/PathInternal.Unix.cs
+++ b/src/Common/src/CoreLib/System/IO/PathInternal.Unix.cs
@@ -4,6 +4,7 @@
using System.Diagnostics;
using System.Text;
+using System.Runtime.InteropServices;
namespace System.IO
{
@@ -22,7 +23,7 @@ namespace System.IO
internal const string ParentDirectoryPrefix = @"../";
- internal static int GetRootLength(string path)
+ internal static int GetRootLength(ReadOnlySpan<char> path)
{
return path.Length > 0 && IsDirectorySeparator(path[0]) ? 1 : 0;
}
@@ -40,7 +41,8 @@ namespace System.IO
/// </summary>
internal static string NormalizeDirectorySeparators(string path)
{
- if (string.IsNullOrEmpty(path)) return path;
+ if (string.IsNullOrEmpty(path))
+ return path;
// Make a pass to see if we need to normalize so we can potentially skip allocating
bool normalized = true;
@@ -55,7 +57,8 @@ namespace System.IO
}
}
- if (normalized) return path;
+ if (normalized)
+ return path;
StringBuilder builder = new StringBuilder(path.Length);
@@ -73,32 +76,14 @@ namespace System.IO
return builder.ToString();
}
-
- /// <summary>
- /// Returns true if the character is a directory or volume separator.
- /// </summary>
- /// <param name="ch">The character to test.</param>
- internal static bool IsDirectoryOrVolumeSeparator(char ch)
- {
- // The directory separator, volume separator, and the alternate directory
- // separator should be the same on Unix, so we only need to check one.
- Debug.Assert(DirectorySeparatorChar == AltDirectorySeparatorChar);
- Debug.Assert(DirectorySeparatorChar == VolumeSeparatorChar);
- return ch == DirectorySeparatorChar;
- }
- internal static bool IsPartiallyQualified(string path)
+ internal static bool IsPartiallyQualified(ReadOnlySpan<char> path)
{
// This is much simpler than Windows where paths can be rooted, but not fully qualified (such as Drive Relative)
// As long as the path is rooted in Unix it doesn't use the current directory and therefore is fully qualified.
return !Path.IsPathRooted(path);
}
- internal static string TrimEndingDirectorySeparator(string path) =>
- path.Length > 1 && IsDirectorySeparator(path[path.Length - 1]) ? // exclude root "/"
- path.Substring(0, path.Length - 1) :
- path;
-
/// <summary>
/// Returns true if the path is effectively empty for the current OS.
/// For unix, this is empty or null. For Windows, this is empty, null, or
@@ -108,5 +93,10 @@ namespace System.IO
{
return string.IsNullOrEmpty(path);
}
+
+ internal static bool IsEffectivelyEmpty(ReadOnlySpan<char> path)
+ {
+ return path.IsEmpty;
+ }
}
}
diff --git a/src/Common/src/CoreLib/System/IO/PathInternal.Windows.StringBuffer.cs b/src/Common/src/CoreLib/System/IO/PathInternal.Windows.StringBuffer.cs
deleted file mode 100644
index 84953df37b..0000000000
--- a/src/Common/src/CoreLib/System/IO/PathInternal.Windows.StringBuffer.cs
+++ /dev/null
@@ -1,93 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-
-namespace System.IO
-{
- /// <summary>Contains internal path helpers that are shared between many projects.</summary>
- internal static partial class PathInternal
- {
- /// <summary>
- /// Returns true if the path uses the extended syntax (\\?\)
- /// </summary>
- internal static bool IsExtended(ref StringBuffer path)
- {
- // While paths like "//?/C:/" will work, they're treated the same as "\\.\" paths.
- // Skipping of normalization will *only* occur if back slashes ('\') are used.
- return path.Length >= DevicePrefixLength
- && path[0] == '\\'
- && (path[1] == '\\' || path[1] == '?')
- && path[2] == '?'
- && path[3] == '\\';
- }
-
- /// <summary>
- /// Gets the length of the root of the path (drive, share, etc.).
- /// </summary>
- internal unsafe static int GetRootLength(ref StringBuffer path)
- {
- if (path.Length == 0) return 0;
-
- fixed (char* value = path.UnderlyingArray)
- {
- return GetRootLength(value, path.Length);
- }
- }
-
- /// <summary>
- /// Returns true if the path uses any of the DOS device path syntaxes. ("\\.\", "\\?\", or "\??\")
- /// </summary>
- internal static bool IsDevice(ref StringBuffer path)
- {
- // If the path begins with any two separators is will be recognized and normalized and prepped with
- // "\??\" for internal usage correctly. "\??\" is recognized and handled, "/??/" is not.
- return IsExtended(ref path)
- ||
- (
- path.Length >= DevicePrefixLength
- && IsDirectorySeparator(path[0])
- && IsDirectorySeparator(path[1])
- && (path[2] == '.' || path[2] == '?')
- && IsDirectorySeparator(path[3])
- );
- }
-
- /// <summary>
- /// Returns true if the path specified is relative to the current drive or working directory.
- /// Returns false if the path is fixed to a specific drive or UNC path. This method does no
- /// validation of the path (URIs will be returned as relative as a result).
- /// </summary>
- /// <remarks>
- /// Handles paths that use the alternate directory separator. It is a frequent mistake to
- /// assume that rooted paths (Path.IsPathRooted) are not relative. This isn't the case.
- /// "C:a" is drive relative- meaning that it will be resolved against the current directory
- /// for C: (rooted, but relative). "C:\a" is rooted and not relative (the current directory
- /// will not be used to modify the path).
- /// </remarks>
- internal static bool IsPartiallyQualified(ref StringBuffer path)
- {
- if (path.Length < 2)
- {
- // It isn't fixed, it must be relative. There is no way to specify a fixed
- // path with one character (or less).
- return true;
- }
-
- if (IsDirectorySeparator(path[0]))
- {
- // There is no valid way to specify a relative path with two initial slashes or
- // \? as ? isn't valid for drive relative paths and \??\ is equivalent to \\?\
- return !(path[1] == '?' || IsDirectorySeparator(path[1]));
- }
-
- // The only way to specify a fixed path that doesn't begin with two slashes
- // is the drive, colon, slash format- i.e. C:\
- return !((path.Length >= 3)
- && (path[1] == VolumeSeparatorChar)
- && IsDirectorySeparator(path[2]));
- }
- }
-}
diff --git a/src/Common/src/CoreLib/System/IO/PathInternal.Windows.cs b/src/Common/src/CoreLib/System/IO/PathInternal.Windows.cs
index f315f43fd5..b01482abd2 100644
--- a/src/Common/src/CoreLib/System/IO/PathInternal.Windows.cs
+++ b/src/Common/src/CoreLib/System/IO/PathInternal.Windows.cs
@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Text;
@@ -71,7 +70,36 @@ namespace System.IO
return ((value >= 'A' && value <= 'Z') || (value >= 'a' && value <= 'z'));
}
+ internal static bool EndsWithPeriodOrSpace(string path)
+ {
+ if (string.IsNullOrEmpty(path))
+ return false;
+
+ char c = path[path.Length - 1];
+ return c == ' ' || c == '.';
+ }
+
+ /// <summary>
+ /// Adds the extended path prefix (\\?\) if not already a device path, IF the path is not relative,
+ /// AND the path is more than 259 characters. (> MAX_PATH + null). This will also insert the extended
+ /// prefix if the path ends with a period or a space. Trailing periods and spaces are normally eaten
+ /// away from paths during normalization, but if we see such a path at this point it should be
+ /// normalized and has retained the final characters. (Typically from one of the *Info classes)
+ /// </summary>
+ internal static string EnsureExtendedPrefixIfNeeded(string path)
+ {
+ if (path != null && (path.Length >= MaxShortPath || EndsWithPeriodOrSpace(path)))
+ {
+ return EnsureExtendedPrefix(path);
+ }
+ else
+ {
+ return path;
+ }
+ }
+
/// <summary>
+ /// DO NOT USE- Use EnsureExtendedPrefixIfNeeded. This will be removed shortly.
/// Adds the extended path prefix (\\?\) if not already a device path, IF the path is not relative,
/// AND the path is more than 259 characters. (> MAX_PATH + null)
/// </summary>
@@ -115,7 +143,7 @@ namespace System.IO
/// <summary>
/// Returns true if the path uses any of the DOS device path syntaxes. ("\\.\", "\\?\", or "\??\")
/// </summary>
- internal static bool IsDevice(string path)
+ internal static bool IsDevice(ReadOnlySpan<char> path)
{
// If the path begins with any two separators is will be recognized and normalized and prepped with
// "\??\" for internal usage correctly. "\??\" is recognized and handled, "/??/" is not.
@@ -131,11 +159,24 @@ namespace System.IO
}
/// <summary>
+ /// Returns true if the path is a device UNC (\\?\UNC\, \\.\UNC\)
+ /// </summary>
+ internal static bool IsDeviceUNC(ReadOnlySpan<char> path)
+ {
+ return path.Length >= UncExtendedPrefixLength
+ && IsDevice(path)
+ && IsDirectorySeparator(path[7])
+ && path[4] == 'U'
+ && path[5] == 'N'
+ && path[6] == 'C';
+ }
+
+ /// <summary>
/// Returns true if the path uses the canonical form of extended syntax ("\\?\" or "\??\"). If the
/// path matches exactly (cannot use alternate directory separators) Windows will skip normalization
/// and path length checks.
/// </summary>
- internal static bool IsExtended(string path)
+ internal static bool IsExtended(ReadOnlySpan<char> path)
{
// While paths like "//?/C:/" will work, they're treated the same as "\\.\" paths.
// Skipping of normalization will *only* occur if back slashes ('\') are used.
@@ -149,7 +190,7 @@ namespace System.IO
/// <summary>
/// Check for known wildcard characters. '*' and '?' are the most common ones.
/// </summary>
- internal static bool HasWildCardCharacters(string path)
+ internal static bool HasWildCardCharacters(ReadOnlySpan<char> path)
{
// Question mark is part of dos device syntax so we have to skip if we are
int startIndex = IsDevice(path) ? ExtendedPathPrefix.Length : 0;
@@ -172,69 +213,61 @@ namespace System.IO
/// <summary>
/// Gets the length of the root of the path (drive, share, etc.).
/// </summary>
- internal unsafe static int GetRootLength(string path)
- {
- fixed (char* value = path)
- {
- return GetRootLength(value, path.Length);
- }
- }
-
- private unsafe static int GetRootLength(char* path, int pathLength)
+ internal static int GetRootLength(ReadOnlySpan<char> path)
{
+ int pathLength = path.Length;
int i = 0;
- int volumeSeparatorLength = 2; // Length to the colon "C:"
- int uncRootLength = 2; // Length to the start of the server name "\\"
- bool extendedSyntax = StartsWithOrdinal(path, pathLength, ExtendedPathPrefix);
- bool extendedUncSyntax = StartsWithOrdinal(path, pathLength, UncExtendedPathPrefix);
- if (extendedSyntax)
+ bool deviceSyntax = IsDevice(path);
+ bool deviceUnc = deviceSyntax && IsDeviceUNC(path);
+
+ if ((!deviceSyntax || deviceUnc) && pathLength > 0 && IsDirectorySeparator(path[0]))
{
- // Shift the position we look for the root from to account for the extended prefix
- if (extendedUncSyntax)
+ // UNC or simple rooted path (e.g. "\foo", NOT "\\?\C:\foo")
+ if (deviceUnc || (pathLength > 1 && IsDirectorySeparator(path[1])))
{
- // "\\" -> "\\?\UNC\"
- uncRootLength = UncExtendedPathPrefix.Length;
+ // UNC (\\?\UNC\ or \\), scan past server\share
+
+ // Start past the prefix ("\\" or "\\?\UNC\")
+ i = deviceUnc ? UncExtendedPrefixLength : UncPrefixLength;
+
+ // Skip two separators at most
+ int n = 2;
+ while (i < pathLength && (!IsDirectorySeparator(path[i]) || --n > 0))
+ i++;
}
else
{
- // "C:" -> "\\?\C:"
- volumeSeparatorLength += ExtendedPathPrefix.Length;
+ // Current drive rooted (e.g. "\foo")
+ i = 1;
}
}
-
- if ((!extendedSyntax || extendedUncSyntax) && pathLength > 0 && IsDirectorySeparator(path[0]))
+ else if (deviceSyntax)
{
- // UNC or simple rooted path (e.g. "\foo", NOT "\\?\C:\foo")
-
- i = 1; // Drive rooted (\foo) is one character
- if (extendedUncSyntax || (pathLength > 1 && IsDirectorySeparator(path[1])))
- {
- // UNC (\\?\UNC\ or \\), scan past the next two directory separators at most
- // (e.g. to \\?\UNC\Server\Share or \\Server\Share\)
- i = uncRootLength;
- int n = 2; // Maximum separators to skip
- while (i < pathLength && (!IsDirectorySeparator(path[i]) || --n > 0)) i++;
- }
+ // Device path (e.g. "\\?\.", "\\.\")
+ // Skip any characters following the prefix that aren't a separator
+ i = DevicePrefixLength;
+ while (i < pathLength && !IsDirectorySeparator(path[i]))
+ i++;
+
+ // If there is another separator take it, as long as we have had at least one
+ // non-separator after the prefix (e.g. don't take "\\?\\", but take "\\?\a\")
+ if (i < pathLength && i > DevicePrefixLength && IsDirectorySeparator(path[i]))
+ i++;
}
- else if (pathLength >= volumeSeparatorLength && path[volumeSeparatorLength - 1] == VolumeSeparatorChar)
+ else if (pathLength >= 2
+ && path[1] == VolumeSeparatorChar
+ && IsValidDriveChar(path[0]))
{
- // Path is at least longer than where we expect a colon, and has a colon (\\?\A:, A:)
- // If the colon is followed by a directory separator, move past it
- i = volumeSeparatorLength;
- if (pathLength >= volumeSeparatorLength + 1 && IsDirectorySeparator(path[volumeSeparatorLength])) i++;
- }
- return i;
- }
+ // Valid drive specified path ("C:", "D:", etc.)
+ i = 2;
- private unsafe static bool StartsWithOrdinal(char* source, int sourceLength, string value)
- {
- if (sourceLength < value.Length) return false;
- for (int i = 0; i < value.Length; i++)
- {
- if (value[i] != source[i]) return false;
+ // If the colon is followed by a directory separator, move past it (e.g "C:\")
+ if (pathLength > 2 && IsDirectorySeparator(path[2]))
+ i++;
}
- return true;
+
+ return i;
}
/// <summary>
@@ -249,7 +282,7 @@ namespace System.IO
/// for C: (rooted, but relative). "C:\a" is rooted and not relative (the current directory
/// will not be used to modify the path).
/// </remarks>
- internal static bool IsPartiallyQualified(string path)
+ internal static bool IsPartiallyQualified(ReadOnlySpan<char> path)
{
if (path.Length < 2)
{
@@ -276,29 +309,6 @@ namespace System.IO
}
/// <summary>
- /// Returns the characters to skip at the start of the path if it starts with space(s) and a drive or directory separator.
- /// (examples are " C:", " \")
- /// This is a legacy behavior of Path.GetFullPath().
- /// </summary>
- /// <remarks>
- /// Note that this conflicts with IsPathRooted() which doesn't (and never did) such a skip.
- /// </remarks>
- internal static int PathStartSkip(string path)
- {
- int startIndex = 0;
- while (startIndex < path.Length && path[startIndex] == ' ') startIndex++;
-
- if (startIndex > 0 && (startIndex < path.Length && IsDirectorySeparator(path[startIndex]))
- || (startIndex + 1 < path.Length && path[startIndex + 1] == ':' && IsValidDriveChar(path[startIndex])))
- {
- // Go ahead and skip spaces as we're either " C:" or " \"
- return startIndex;
- }
-
- return 0;
- }
-
- /// <summary>
/// True if the given character is a directory separator.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -341,34 +351,33 @@ namespace System.IO
/// </remarks>
internal static string NormalizeDirectorySeparators(string path)
{
- if (string.IsNullOrEmpty(path)) return path;
+ if (string.IsNullOrEmpty(path))
+ return path;
char current;
- int start = PathStartSkip(path);
- if (start == 0)
- {
- // Make a pass to see if we need to normalize so we can potentially skip allocating
- bool normalized = true;
+ // Make a pass to see if we need to normalize so we can potentially skip allocating
+ bool normalized = true;
- for (int i = 0; i < path.Length; i++)
+ for (int i = 0; i < path.Length; i++)
+ {
+ current = path[i];
+ if (IsDirectorySeparator(current)
+ && (current != DirectorySeparatorChar
+ // Check for sequential separators past the first position (we need to keep initial two for UNC/extended)
+ || (i > 0 && i + 1 < path.Length && IsDirectorySeparator(path[i + 1]))))
{
- current = path[i];
- if (IsDirectorySeparator(current)
- && (current != DirectorySeparatorChar
- // Check for sequential separators past the first position (we need to keep initial two for UNC/extended)
- || (i > 0 && i + 1 < path.Length && IsDirectorySeparator(path[i + 1]))))
- {
- normalized = false;
- break;
- }
+ normalized = false;
+ break;
}
-
- if (normalized) return path;
}
+ if (normalized)
+ return path;
+
StringBuilder builder = new StringBuilder(path.Length);
+ int start = 0;
if (IsDirectorySeparator(path[start]))
{
start++;
@@ -399,22 +408,13 @@ namespace System.IO
}
/// <summary>
- /// Returns true if the character is a directory or volume separator.
- /// </summary>
- /// <param name="ch">The character to test.</param>
- internal static bool IsDirectoryOrVolumeSeparator(char ch)
- {
- return IsDirectorySeparator(ch) || VolumeSeparatorChar == ch;
- }
-
- /// <summary>
/// Returns true if the path is effectively empty for the current OS.
/// For unix, this is empty or null. For Windows, this is empty, null, or
/// just spaces ((char)32).
/// </summary>
- internal static bool IsEffectivelyEmpty(string path)
+ internal static bool IsEffectivelyEmpty(ReadOnlySpan<char> path)
{
- if (string.IsNullOrEmpty(path))
+ if (path.IsEmpty)
return true;
foreach (char c in path)
diff --git a/src/Common/src/CoreLib/System/IO/PathInternal.cs b/src/Common/src/CoreLib/System/IO/PathInternal.cs
index bfd69e9251..00a709213f 100644
--- a/src/Common/src/CoreLib/System/IO/PathInternal.cs
+++ b/src/Common/src/CoreLib/System/IO/PathInternal.cs
@@ -11,36 +11,31 @@ namespace System.IO
internal static partial class PathInternal
{
/// <summary>
- /// Returns the start index of the filename
- /// in the given path, or 0 if no directory
- /// or volume separator is found.
+ /// Returns true if the path ends in a directory separator.
/// </summary>
- /// <param name="path">The path in which to find the index of the filename.</param>
- /// <remarks>
- /// This method returns path.Length for
- /// inputs like "/usr/foo/" on Unix. As such,
- /// it is not safe for being used to index
- /// the string without additional verification.
- /// </remarks>
- internal static int FindFileNameIndex(string path)
- {
- Debug.Assert(path != null);
-
- for (int i = path.Length - 1; i >= 0; i--)
- {
- char ch = path[i];
- if (IsDirectoryOrVolumeSeparator(ch))
- return i + 1;
- }
-
- return 0; // the whole path is the filename
- }
+ internal static bool EndsInDirectorySeparator(ReadOnlySpan<char> path)
+ => path.Length > 0 && IsDirectorySeparator(path[path.Length - 1]);
/// <summary>
- /// Returns true if the path ends in a directory separator.
+ /// Returns true if the path starts in a directory separator.
/// </summary>
- internal static bool EndsInDirectorySeparator(string path) =>
- !string.IsNullOrEmpty(path) && IsDirectorySeparator(path[path.Length - 1]);
+ internal static bool StartsWithDirectorySeparator(ReadOnlySpan<char> path) => path.Length > 0 && IsDirectorySeparator(path[0]);
+
+ internal static string EnsureTrailingSeparator(string path)
+ => EndsInDirectorySeparator(path) ? path : path + DirectorySeparatorCharAsString;
+
+ internal static string TrimEndingDirectorySeparator(string path) =>
+ EndsInDirectorySeparator(path) && !IsRoot(path) ?
+ path.Substring(0, path.Length - 1) :
+ path;
+
+ internal static ReadOnlySpan<char> TrimEndingDirectorySeparator(ReadOnlySpan<char> path) =>
+ EndsInDirectorySeparator(path) && !IsRoot(path) ?
+ path.Slice(0, path.Length - 1) :
+ path;
+
+ internal static bool IsRoot(ReadOnlySpan<char> path)
+ => path.Length == GetRootLength(path);
/// <summary>
/// Get the common path length from the start of the string.
@@ -71,7 +66,7 @@ namespace System.IO
/// <summary>
/// Gets the count of common characters from the left optionally ignoring case
/// </summary>
- unsafe internal static int EqualStartingCharacterCount(string first, string second, bool ignoreCase)
+ internal static unsafe int EqualStartingCharacterCount(string first, string second, bool ignoreCase)
{
if (string.IsNullOrEmpty(first) || string.IsNullOrEmpty(second)) return 0;
@@ -116,24 +111,98 @@ namespace System.IO
}
/// <summary>
- /// Returns false for ".." unless it is specified as a part of a valid File/Directory name.
- /// (Used to avoid moving up directories.)
- ///
- /// Valid: a..b abc..d
- /// Invalid: ..ab ab.. .. abc..d\abc..
+ /// Try to remove relative segments from the given path (without combining with a root).
/// </summary>
- internal static void CheckSearchPattern(string searchPattern)
+ /// <param name="rootLength">The length of the root of the given path</param>
+ internal static string RemoveRelativeSegments(string path, int rootLength)
{
- int index;
- while ((index = searchPattern.IndexOf("..", StringComparison.Ordinal)) != -1)
+ Debug.Assert(rootLength > 0);
+ bool flippedSeparator = false;
+
+ int skip = rootLength;
+ // We treat "\.." , "\." and "\\" as a relative segment. We want to collapse the first separator past the root presuming
+ // the root actually ends in a separator. Otherwise the first segment for RemoveRelativeSegments
+ // in cases like "\\?\C:\.\" and "\\?\C:\..\", the first segment after the root will be ".\" and "..\" which is not considered as a relative segment and hence not be removed.
+ if (PathInternal.IsDirectorySeparator(path[skip - 1]))
+ skip--;
+
+ Span<char> initialBuffer = stackalloc char[260 /* PathInternal.MaxShortPath */];
+ ValueStringBuilder sb = new ValueStringBuilder(initialBuffer);
+
+ // Remove "//", "/./", and "/../" from the path by copying each character to the output,
+ // except the ones we're removing, such that the builder contains the normalized path
+ // at the end.
+ if (skip > 0)
{
- // Terminal ".." . Files names cannot end in ".."
- if (index + 2 == searchPattern.Length
- || IsDirectorySeparator(searchPattern[index + 2]))
- throw new ArgumentException(SR.Format(SR.Arg_InvalidSearchPattern, searchPattern));
+ sb.Append(path.AsSpan().Slice(0, skip));
+ }
- searchPattern = searchPattern.Substring(index + 2);
+ for (int i = skip; i < path.Length; i++)
+ {
+ char c = path[i];
+
+ if (PathInternal.IsDirectorySeparator(c) && i + 1 < path.Length)
+ {
+ // Skip this character if it's a directory separator and if the next character is, too,
+ // e.g. "parent//child" => "parent/child"
+ if (PathInternal.IsDirectorySeparator(path[i + 1]))
+ {
+ continue;
+ }
+
+ // Skip this character and the next if it's referring to the current directory,
+ // e.g. "parent/./child" => "parent/child"
+ if ((i + 2 == path.Length || PathInternal.IsDirectorySeparator(path[i + 2])) &&
+ path[i + 1] == '.')
+ {
+ i++;
+ continue;
+ }
+
+ // Skip this character and the next two if it's referring to the parent directory,
+ // e.g. "parent/child/../grandchild" => "parent/grandchild"
+ if (i + 2 < path.Length &&
+ (i + 3 == path.Length || PathInternal.IsDirectorySeparator(path[i + 3])) &&
+ path[i + 1] == '.' && path[i + 2] == '.')
+ {
+ // Unwind back to the last slash (and if there isn't one, clear out everything).
+ int s;
+ for (s = sb.Length - 1; s >= skip; s--)
+ {
+ if (PathInternal.IsDirectorySeparator(sb[s]))
+ {
+ sb.Length = (i + 3 >= path.Length && s == skip) ? s + 1 : s; // to avoid removing the complete "\tmp\" segment in cases like \\?\C:\tmp\..\, C:\tmp\..
+ break;
+ }
+ }
+ if (s < skip)
+ {
+ sb.Length = skip;
+ }
+
+ i += 2;
+ continue;
+ }
+ }
+
+ // Normalize the directory separator if needed
+ if (c != PathInternal.DirectorySeparatorChar && c == PathInternal.AltDirectorySeparatorChar)
+ {
+ c = PathInternal.DirectorySeparatorChar;
+ flippedSeparator = true;
+ }
+
+ sb.Append(c);
+ }
+
+ // If we haven't changed the source path, return the original
+ if (!flippedSeparator && sb.Length == path.Length)
+ {
+ sb.Dispose();
+ return path;
}
+
+ return sb.Length < rootLength ? path.Substring(0, rootLength) : sb.ToString();
}
}
}
diff --git a/src/Common/src/CoreLib/System/IO/PinnedBufferMemoryStream.cs b/src/Common/src/CoreLib/System/IO/PinnedBufferMemoryStream.cs
index dfcc05d066..94331a2ef8 100644
--- a/src/Common/src/CoreLib/System/IO/PinnedBufferMemoryStream.cs
+++ b/src/Common/src/CoreLib/System/IO/PinnedBufferMemoryStream.cs
@@ -38,9 +38,9 @@ namespace System.IO
Initialize(ptr, len, len, FileAccess.Read);
}
- public override int Read(Span<byte> destination) => ReadCore(destination);
+ public override int Read(Span<byte> buffer) => ReadCore(buffer);
- public override void Write(ReadOnlySpan<byte> source) => WriteCore(source);
+ public override void Write(ReadOnlySpan<byte> buffer) => WriteCore(buffer);
~PinnedBufferMemoryStream()
{
diff --git a/src/Common/src/CoreLib/System/IO/StreamReader.cs b/src/Common/src/CoreLib/System/IO/StreamReader.cs
index 392582b960..46729af793 100644
--- a/src/Common/src/CoreLib/System/IO/StreamReader.cs
+++ b/src/Common/src/CoreLib/System/IO/StreamReader.cs
@@ -71,21 +71,21 @@ namespace System.IO
// We don't guarantee thread safety on StreamReader, but we should at
// least prevent users from trying to read anything while an Async
// read from the same thread is in progress.
- private volatile Task _asyncReadTask;
+ private Task _asyncReadTask = Task.CompletedTask;
private void CheckAsyncTaskInProgress()
{
// We are not locking the access to _asyncReadTask because this is not meant to guarantee thread safety.
// We are simply trying to deter calling any Read APIs while an async Read from the same thread is in progress.
-
- Task t = _asyncReadTask;
-
- if (t != null && !t.IsCompleted)
+ if (!_asyncReadTask.IsCompleted)
{
- throw new InvalidOperationException(SR.InvalidOperation_AsyncIOInProgress);
+ ThrowAsyncIOInProgress();
}
}
+ private static void ThrowAsyncIOInProgress() =>
+ throw new InvalidOperationException(SR.InvalidOperation_AsyncIOInProgress);
+
// StreamReader by default will ignore illegal UTF8 characters. We don't want to
// throw here because we want to be able to read ill-formed data without choking.
// The high level goal is to be tolerant of encoding errors when we read and very strict
@@ -1092,7 +1092,7 @@ namespace System.IO
{
Debug.Assert(_bytePos <= _encoding.Preamble.Length, "possible bug in _compressPreamble. Are two threads using this StreamReader at the same time?");
int tmpBytePos = _bytePos;
- int len = await tmpStream.ReadAsync(tmpByteBuffer, tmpBytePos, tmpByteBuffer.Length - tmpBytePos, cancellationToken).ConfigureAwait(false);
+ int len = await tmpStream.ReadAsync(new Memory<byte>(tmpByteBuffer, tmpBytePos, tmpByteBuffer.Length - tmpBytePos), cancellationToken).ConfigureAwait(false);
Debug.Assert(len >= 0, "Stream.Read returned a negative number! This is a bug in your stream class.");
if (len == 0)
@@ -1128,7 +1128,7 @@ namespace System.IO
{
Debug.Assert(_bytePos == 0, "_bytePos can be non zero only when we are trying to _checkPreamble. Are two threads using this StreamReader at the same time?");
- _byteLen = await tmpStream.ReadAsync(tmpByteBuffer, 0, tmpByteBuffer.Length, cancellationToken).ConfigureAwait(false);
+ _byteLen = await tmpStream.ReadAsync(new Memory<byte>(tmpByteBuffer), cancellationToken).ConfigureAwait(false);
Debug.Assert(_byteLen >= 0, "Stream.Read returned a negative number! This is a bug in your stream class.");
@@ -1304,7 +1304,7 @@ namespace System.IO
{
Debug.Assert(_bytePos <= _encoding.Preamble.Length, "possible bug in _compressPreamble. Are two threads using this StreamReader at the same time?");
int tmpBytePos = _bytePos;
- int len = await tmpStream.ReadAsync(tmpByteBuffer, tmpBytePos, tmpByteBuffer.Length - tmpBytePos).ConfigureAwait(false);
+ int len = await tmpStream.ReadAsync(new Memory<byte>(tmpByteBuffer, tmpBytePos, tmpByteBuffer.Length - tmpBytePos)).ConfigureAwait(false);
Debug.Assert(len >= 0, "Stream.Read returned a negative number! This is a bug in your stream class.");
if (len == 0)
@@ -1326,7 +1326,7 @@ namespace System.IO
else
{
Debug.Assert(_bytePos == 0, "_bytePos can be non zero only when we are trying to _checkPreamble. Are two threads using this StreamReader at the same time?");
- _byteLen = await tmpStream.ReadAsync(tmpByteBuffer, 0, tmpByteBuffer.Length).ConfigureAwait(false);
+ _byteLen = await tmpStream.ReadAsync(new Memory<byte>(tmpByteBuffer)).ConfigureAwait(false);
Debug.Assert(_byteLen >= 0, "Stream.Read returned a negative number! Bug in stream class.");
if (_byteLen == 0) // We're at EOF
diff --git a/src/Common/src/CoreLib/System/IO/StreamWriter.cs b/src/Common/src/CoreLib/System/IO/StreamWriter.cs
index d0d014db33..cc92d8aea6 100644
--- a/src/Common/src/CoreLib/System/IO/StreamWriter.cs
+++ b/src/Common/src/CoreLib/System/IO/StreamWriter.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
@@ -45,19 +46,21 @@ namespace System.IO
// We don't guarantee thread safety on StreamWriter, but we should at
// least prevent users from trying to write anything while an Async
// write from the same thread is in progress.
- private volatile Task _asyncWriteTask;
+ private Task _asyncWriteTask = Task.CompletedTask;
private void CheckAsyncTaskInProgress()
{
// We are not locking the access to _asyncWriteTask because this is not meant to guarantee thread safety.
// We are simply trying to deter calling any Write APIs while an async Write from the same thread is in progress.
-
- Task t = _asyncWriteTask;
-
- if (t != null && !t.IsCompleted)
- throw new InvalidOperationException(SR.InvalidOperation_AsyncIOInProgress);
+ if (!_asyncWriteTask.IsCompleted)
+ {
+ ThrowAsyncIOInProgress();
+ }
}
+ private static void ThrowAsyncIOInProgress() =>
+ throw new InvalidOperationException(SR.InvalidOperation_AsyncIOInProgress);
+
// The high level goal is to be tolerant of encoding errors when we read and very strict
// when we write. Hence, default StreamWriter encoding will throw on encoding error.
// Note: when StreamWriter throws on invalid encoding chars (for ex, high surrogate character
@@ -324,14 +327,13 @@ namespace System.IO
}
}
+ [MethodImpl(MethodImplOptions.NoInlining)] // prevent WriteSpan from bloating call sites
public override void Write(char[] buffer)
{
- if (buffer != null)
- {
- WriteCore(buffer, _autoFlush);
- }
+ WriteSpan(buffer, appendNewLine: false);
}
+ [MethodImpl(MethodImplOptions.NoInlining)] // prevent WriteSpan from bloating call sites
public override void Write(char[] buffer, int index, int count)
{
if (buffer == null)
@@ -351,14 +353,15 @@ namespace System.IO
throw new ArgumentException(SR.Argument_InvalidOffLen);
}
- WriteCore(new ReadOnlySpan<char>(buffer, index, count), _autoFlush);
+ WriteSpan(buffer.AsSpan(index, count), appendNewLine: false);
}
+ [MethodImpl(MethodImplOptions.NoInlining)] // prevent WriteSpan from bloating call sites
public override void Write(ReadOnlySpan<char> buffer)
{
if (GetType() == typeof(StreamWriter))
{
- WriteCore(buffer, _autoFlush);
+ WriteSpan(buffer, appendNewLine: false);
}
else
{
@@ -368,7 +371,8 @@ namespace System.IO
}
}
- private unsafe void WriteCore(ReadOnlySpan<char> buffer, bool autoFlush)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private unsafe void WriteSpan(ReadOnlySpan<char> buffer, bool appendNewLine)
{
CheckAsyncTaskInProgress();
@@ -423,41 +427,47 @@ namespace System.IO
}
}
- if (autoFlush)
+ if (appendNewLine)
+ {
+ char[] coreNewLine = CoreNewLine;
+ for (int i = 0; i < coreNewLine.Length; i++) // Generally 1 (\n) or 2 (\r\n) iterations
+ {
+ if (_charPos == _charLen)
+ {
+ Flush(false, false);
+ }
+
+ _charBuffer[_charPos] = coreNewLine[i];
+ _charPos++;
+ }
+ }
+
+ if (_autoFlush)
{
Flush(true, false);
}
}
+ [MethodImpl(MethodImplOptions.NoInlining)] // prevent WriteSpan from bloating call sites
public override void Write(string value)
{
- if (value != null)
- {
- WriteCore(value.AsReadOnlySpan(), _autoFlush);
- }
+ WriteSpan(value, appendNewLine: false);
}
- //
- // Optimize the most commonly used WriteLine overload. This optimization is important for System.Console in particular
- // because of it will make one WriteLine equal to one call to the OS instead of two in the common case.
- //
+ [MethodImpl(MethodImplOptions.NoInlining)] // prevent WriteSpan from bloating call sites
public override void WriteLine(string value)
{
CheckAsyncTaskInProgress();
- if (value != null)
- {
- WriteCore(value.AsReadOnlySpan(), autoFlush: false);
- }
- WriteCore(new ReadOnlySpan<char>(CoreNewLine), autoFlush: true);
+ WriteSpan(value, appendNewLine: true);
}
+ [MethodImpl(MethodImplOptions.NoInlining)] // prevent WriteSpan from bloating call sites
public override void WriteLine(ReadOnlySpan<char> value)
{
if (GetType() == typeof(StreamWriter))
{
CheckAsyncTaskInProgress();
- WriteCore(value, autoFlush: false);
- WriteCore(new ReadOnlySpan<char>(CoreNewLine), autoFlush: true);
+ WriteSpan(value, appendNewLine: true);
}
else
{
@@ -964,14 +974,14 @@ namespace System.IO
byte[] preamble = encoding.GetPreamble();
if (preamble.Length > 0)
{
- await stream.WriteAsync(preamble, 0, preamble.Length, cancellationToken).ConfigureAwait(false);
+ await stream.WriteAsync(new ReadOnlyMemory<byte>(preamble), cancellationToken).ConfigureAwait(false);
}
}
int count = encoder.GetBytes(charBuffer, 0, charPos, byteBuffer, 0, flushEncoder);
if (count > 0)
{
- await stream.WriteAsync(byteBuffer, 0, count, cancellationToken).ConfigureAwait(false);
+ await stream.WriteAsync(new ReadOnlyMemory<byte>(byteBuffer, 0, count), cancellationToken).ConfigureAwait(false);
}
// By definition, calling Flush should flush the stream, but this is
diff --git a/src/Common/src/CoreLib/System/IO/TextReader.cs b/src/Common/src/CoreLib/System/IO/TextReader.cs
index 321c974739..d4d7e54a18 100644
--- a/src/Common/src/CoreLib/System/IO/TextReader.cs
+++ b/src/Common/src/CoreLib/System/IO/TextReader.cs
@@ -7,6 +7,7 @@ using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using System.Buffers;
namespace System.IO
@@ -252,7 +253,7 @@ namespace System.IO
}
public virtual ValueTask<int> ReadAsync(Memory<char> buffer, CancellationToken cancellationToken = default(CancellationToken)) =>
- new ValueTask<int>(buffer.TryGetArray(out ArraySegment<char> array) ?
+ new ValueTask<int>(MemoryMarshal.TryGetArray(buffer, out ArraySegment<char> array) ?
ReadAsync(array.Array, array.Offset, array.Count) :
Task<int>.Factory.StartNew(state =>
{
@@ -290,7 +291,7 @@ namespace System.IO
}
public virtual ValueTask<int> ReadBlockAsync(Memory<char> buffer, CancellationToken cancellationToken = default(CancellationToken)) =>
- new ValueTask<int>(buffer.TryGetArray(out ArraySegment<char> array) ?
+ new ValueTask<int>(MemoryMarshal.TryGetArray(buffer, out ArraySegment<char> array) ?
ReadBlockAsync(array.Array, array.Offset, array.Count) :
Task<int>.Factory.StartNew(state =>
{
diff --git a/src/Common/src/CoreLib/System/IO/UnmanagedMemoryStream.cs b/src/Common/src/CoreLib/System/IO/UnmanagedMemoryStream.cs
index 171113542f..2bcb16f24e 100644
--- a/src/Common/src/CoreLib/System/IO/UnmanagedMemoryStream.cs
+++ b/src/Common/src/CoreLib/System/IO/UnmanagedMemoryStream.cs
@@ -379,22 +379,22 @@ namespace System.IO
return ReadCore(new Span<byte>(buffer, offset, count));
}
- public override int Read(Span<byte> destination)
+ public override int Read(Span<byte> buffer)
{
if (GetType() == typeof(UnmanagedMemoryStream))
{
- return ReadCore(destination);
+ return ReadCore(buffer);
}
else
{
// UnmanagedMemoryStream is not sealed, and a derived type may have overridden Read(byte[], int, int) prior
// to this Read(Span<byte>) overload being introduced. In that case, this Read(Span<byte>) overload
// should use the behavior of Read(byte[],int,int) overload.
- return base.Read(destination);
+ return base.Read(buffer);
}
}
- internal int ReadCore(Span<byte> destination)
+ internal int ReadCore(Span<byte> buffer)
{
EnsureNotClosed();
EnsureReadable();
@@ -403,7 +403,7 @@ namespace System.IO
// changes our position after we decide we can read some bytes.
long pos = Interlocked.Read(ref _position);
long len = Interlocked.Read(ref _length);
- long n = Math.Min(len - pos, destination.Length);
+ long n = Math.Min(len - pos, buffer.Length);
if (n <= 0)
{
return 0;
@@ -418,7 +418,7 @@ namespace System.IO
unsafe
{
- fixed (byte* pBuffer = &MemoryMarshal.GetReference(destination))
+ fixed (byte* pBuffer = &MemoryMarshal.GetReference(buffer))
{
if (_buffer != null)
{
@@ -486,9 +486,9 @@ namespace System.IO
/// <summary>
/// Reads bytes from stream and puts them into the buffer
/// </summary>
- /// <param name="destination">Buffer to read the bytes to.</param>
+ /// <param name="buffer">Buffer to read the bytes to.</param>
/// <param name="cancellationToken">Token that can be used to cancel this operation.</param>
- public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken = default(CancellationToken))
+ public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default(CancellationToken))
{
if (cancellationToken.IsCancellationRequested)
{
@@ -510,9 +510,9 @@ namespace System.IO
// something other than an array and this is an UnmanagedMemoryStream-derived type that doesn't override Read(Span<byte>) will
// it then fall back to doing the ArrayPool/copy behavior.
return new ValueTask<int>(
- destination.TryGetArray(out ArraySegment<byte> destinationArray) ?
+ MemoryMarshal.TryGetArray(buffer, out ArraySegment<byte> destinationArray) ?
Read(destinationArray.Array, destinationArray.Offset, destinationArray.Count) :
- Read(destination.Span));
+ Read(buffer.Span));
}
catch (Exception ex)
{
@@ -659,29 +659,29 @@ namespace System.IO
WriteCore(new Span<byte>(buffer, offset, count));
}
- public override void Write(ReadOnlySpan<byte> source)
+ public override void Write(ReadOnlySpan<byte> buffer)
{
if (GetType() == typeof(UnmanagedMemoryStream))
{
- WriteCore(source);
+ WriteCore(buffer);
}
else
{
// UnmanagedMemoryStream is not sealed, and a derived type may have overridden Write(byte[], int, int) prior
// to this Write(Span<byte>) overload being introduced. In that case, this Write(Span<byte>) overload
// should use the behavior of Write(byte[],int,int) overload.
- base.Write(source);
+ base.Write(buffer);
}
}
- internal unsafe void WriteCore(ReadOnlySpan<byte> source)
+ internal unsafe void WriteCore(ReadOnlySpan<byte> buffer)
{
EnsureNotClosed();
EnsureWriteable();
long pos = Interlocked.Read(ref _position); // Use a local to avoid a race condition
long len = Interlocked.Read(ref _length);
- long n = pos + source.Length;
+ long n = pos + buffer.Length;
// Check for overflow
if (n < 0)
{
@@ -709,12 +709,12 @@ namespace System.IO
}
}
- fixed (byte* pBuffer = &MemoryMarshal.GetReference(source))
+ fixed (byte* pBuffer = &MemoryMarshal.GetReference(buffer))
{
if (_buffer != null)
{
long bytesLeft = _capacity - pos;
- if (bytesLeft < source.Length)
+ if (bytesLeft < buffer.Length)
{
throw new ArgumentException(SR.Arg_BufferTooSmall);
}
@@ -724,7 +724,7 @@ namespace System.IO
try
{
_buffer.AcquirePointer(ref pointer);
- Buffer.Memcpy(pointer + pos + _offset, pBuffer, source.Length);
+ Buffer.Memcpy(pointer + pos + _offset, pBuffer, buffer.Length);
}
finally
{
@@ -736,7 +736,7 @@ namespace System.IO
}
else
{
- Buffer.Memcpy(_mem + pos, pBuffer, source.Length);
+ Buffer.Memcpy(_mem + pos, pBuffer, buffer.Length);
}
}
@@ -783,30 +783,30 @@ namespace System.IO
/// </summary>
/// <param name="buffer">Buffer that will be written.</param>
/// <param name="cancellationToken">Token that can be used to cancel the operation.</param>
- public override Task WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken = default(CancellationToken))
+ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default(CancellationToken))
{
if (cancellationToken.IsCancellationRequested)
{
- return Task.FromCanceled(cancellationToken);
+ return new ValueTask(Task.FromCanceled(cancellationToken));
}
try
{
// See corresponding comment in ReadAsync for why we don't just always use Write(ReadOnlySpan<byte>).
// Unlike ReadAsync, we could delegate to WriteAsync(byte[], ...) here, but we don't for consistency.
- if (MemoryMarshal.TryGetArray(source, out ArraySegment<byte> sourceArray))
+ if (MemoryMarshal.TryGetArray(buffer, out ArraySegment<byte> sourceArray))
{
Write(sourceArray.Array, sourceArray.Offset, sourceArray.Count);
}
else
{
- Write(source.Span);
+ Write(buffer.Span);
}
- return Task.CompletedTask;
+ return default;
}
catch (Exception ex)
{
- return Task.FromException(ex);
+ return new ValueTask(Task.FromException(ex));
}
}
diff --git a/src/Common/src/CoreLib/System/IO/UnmanagedMemoryStreamWrapper.cs b/src/Common/src/CoreLib/System/IO/UnmanagedMemoryStreamWrapper.cs
index 90bb21ac5b..65a33961db 100644
--- a/src/Common/src/CoreLib/System/IO/UnmanagedMemoryStreamWrapper.cs
+++ b/src/Common/src/CoreLib/System/IO/UnmanagedMemoryStreamWrapper.cs
@@ -112,9 +112,9 @@ namespace System.IO
return _unmanagedStream.Read(buffer, offset, count);
}
- public override int Read(Span<byte> destination)
+ public override int Read(Span<byte> buffer)
{
- return _unmanagedStream.Read(destination);
+ return _unmanagedStream.Read(buffer);
}
public override int ReadByte()
@@ -139,9 +139,9 @@ namespace System.IO
_unmanagedStream.Write(buffer, offset, count);
}
- public override void Write(ReadOnlySpan<byte> source)
+ public override void Write(ReadOnlySpan<byte> buffer)
{
- _unmanagedStream.Write(source);
+ _unmanagedStream.Write(buffer);
}
public override void WriteByte(byte value)
@@ -206,9 +206,9 @@ namespace System.IO
return _unmanagedStream.ReadAsync(buffer, offset, count, cancellationToken);
}
- public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken = default(CancellationToken))
+ public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default(CancellationToken))
{
- return _unmanagedStream.ReadAsync(destination, cancellationToken);
+ return _unmanagedStream.ReadAsync(buffer, cancellationToken);
}
@@ -217,9 +217,9 @@ namespace System.IO
return _unmanagedStream.WriteAsync(buffer, offset, count, cancellationToken);
}
- public override Task WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken = default(CancellationToken))
+ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default(CancellationToken))
{
- return _unmanagedStream.WriteAsync(source, cancellationToken);
+ return _unmanagedStream.WriteAsync(buffer, cancellationToken);
}
} // class UnmanagedMemoryStreamWrapper
} // namespace
diff --git a/src/Common/src/CoreLib/System/IO/Win32Marshal.cs b/src/Common/src/CoreLib/System/IO/Win32Marshal.cs
index 14a064a700..7888d8d61b 100644
--- a/src/Common/src/CoreLib/System/IO/Win32Marshal.cs
+++ b/src/Common/src/CoreLib/System/IO/Win32Marshal.cs
@@ -2,106 +2,94 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System;
-using System.Diagnostics;
using System.Runtime.InteropServices;
namespace System.IO
{
/// <summary>
- /// Provides static methods for converting from Win32 errors codes to exceptions, HRESULTS and error messages.
+ /// Provides static methods for converting from Win32 errors codes to exceptions, HRESULTS and error messages.
/// </summary>
internal static class Win32Marshal
{
/// <summary>
- /// Converts, resetting it, the last Win32 error into a corresponding <see cref="Exception"/> object.
+ /// Converts, resetting it, the last Win32 error into a corresponding <see cref="Exception"/> object, optionally
+ /// including the specified path in the error message.
/// </summary>
- internal static Exception GetExceptionForLastWin32Error()
- {
- int errorCode = Marshal.GetLastWin32Error();
- return GetExceptionForWin32Error(errorCode, string.Empty);
- }
-
- /// <summary>
- /// Converts the specified Win32 error into a corresponding <see cref="Exception"/> object.
- /// </summary>
- internal static Exception GetExceptionForWin32Error(int errorCode)
- {
- return GetExceptionForWin32Error(errorCode, string.Empty);
- }
+ internal static Exception GetExceptionForLastWin32Error(string path = "")
+ => GetExceptionForWin32Error(Marshal.GetLastWin32Error(), path);
/// <summary>
- /// Converts the specified Win32 error into a corresponding <see cref="Exception"/> object, optionally
- /// including the specified path in the error message.
+ /// Converts the specified Win32 error into a corresponding <see cref="Exception"/> object, optionally
+ /// including the specified path in the error message.
/// </summary>
- internal static Exception GetExceptionForWin32Error(int errorCode, string path)
+ internal static Exception GetExceptionForWin32Error(int errorCode, string path = "")
{
switch (errorCode)
{
case Interop.Errors.ERROR_FILE_NOT_FOUND:
- if (path.Length == 0)
- return new FileNotFoundException(SR.IO_FileNotFound);
- else
- return new FileNotFoundException(SR.Format(SR.IO_FileNotFound_FileName, path), path);
-
+ return new FileNotFoundException(
+ string.IsNullOrEmpty(path) ? SR.IO_FileNotFound : SR.Format(SR.IO_FileNotFound_FileName, path), path);
case Interop.Errors.ERROR_PATH_NOT_FOUND:
- if (path.Length == 0)
- return new DirectoryNotFoundException(SR.IO_PathNotFound_NoPathName);
- else
- return new DirectoryNotFoundException(SR.Format(SR.IO_PathNotFound_Path, path));
-
+ return new DirectoryNotFoundException(
+ string.IsNullOrEmpty(path) ? SR.IO_PathNotFound_NoPathName : SR.Format(SR.IO_PathNotFound_Path, path));
case Interop.Errors.ERROR_ACCESS_DENIED:
- if (path.Length == 0)
- return new UnauthorizedAccessException(SR.UnauthorizedAccess_IODenied_NoPathName);
- else
- return new UnauthorizedAccessException(SR.Format(SR.UnauthorizedAccess_IODenied_Path, path));
-
+ return new UnauthorizedAccessException(
+ string.IsNullOrEmpty(path) ? SR.UnauthorizedAccess_IODenied_NoPathName : SR.Format(SR.UnauthorizedAccess_IODenied_Path, path));
case Interop.Errors.ERROR_ALREADY_EXISTS:
- if (path.Length == 0)
+ if (string.IsNullOrEmpty(path))
goto default;
-
return new IOException(SR.Format(SR.IO_AlreadyExists_Name, path), MakeHRFromErrorCode(errorCode));
-
case Interop.Errors.ERROR_FILENAME_EXCED_RANGE:
- if (path.Length == 0)
- return new PathTooLongException(SR.IO_PathTooLong);
- else
- return new PathTooLongException(SR.Format(SR.IO_PathTooLong_Path, path));
-
- case Interop.Errors.ERROR_INVALID_DRIVE:
- throw new DriveNotFoundException(SR.Format(SR.IO_DriveNotFound_Drive, path));
-
- case Interop.Errors.ERROR_INVALID_PARAMETER:
- return new IOException(Interop.Kernel32.GetMessage(errorCode), MakeHRFromErrorCode(errorCode));
-
+ return new PathTooLongException(
+ string.IsNullOrEmpty(path) ? SR.IO_PathTooLong : SR.Format(SR.IO_PathTooLong_Path, path));
case Interop.Errors.ERROR_SHARING_VIOLATION:
- if (path.Length == 0)
- return new IOException(SR.IO_SharingViolation_NoFileName, MakeHRFromErrorCode(errorCode));
- else
- return new IOException(SR.Format(SR.IO_SharingViolation_File, path), MakeHRFromErrorCode(errorCode));
-
+ return new IOException(
+ string.IsNullOrEmpty(path) ? SR.IO_SharingViolation_NoFileName : SR.Format(SR.IO_SharingViolation_File, path),
+ MakeHRFromErrorCode(errorCode));
case Interop.Errors.ERROR_FILE_EXISTS:
- if (path.Length == 0)
+ if (string.IsNullOrEmpty(path))
goto default;
-
return new IOException(SR.Format(SR.IO_FileExists_Name, path), MakeHRFromErrorCode(errorCode));
-
case Interop.Errors.ERROR_OPERATION_ABORTED:
return new OperationCanceledException();
-
+ case Interop.Errors.ERROR_INVALID_PARAMETER:
default:
- return new IOException(Interop.Kernel32.GetMessage(errorCode), MakeHRFromErrorCode(errorCode));
+ return new IOException(
+ string.IsNullOrEmpty(path) ? GetMessage(errorCode) : $"{GetMessage(errorCode)} : '{path}'",
+ MakeHRFromErrorCode(errorCode));
}
}
/// <summary>
- /// Returns a HRESULT for the specified Win32 error code.
+ /// If not already an HRESULT, returns an HRESULT for the specified Win32 error code.
/// </summary>
internal static int MakeHRFromErrorCode(int errorCode)
{
- Debug.Assert((0xFFFF0000 & errorCode) == 0, "This is an HRESULT, not an error code!");
+ // Don't convert it if it is already an HRESULT
+ if ((0xFFFF0000 & errorCode) != 0)
+ return errorCode;
return unchecked(((int)0x80070000) | errorCode);
}
+
+ /// <summary>
+ /// Returns a Win32 error code for the specified HRESULT if it came from FACILITY_WIN32
+ /// If not, returns the HRESULT unchanged
+ /// </summary>
+ internal static int TryMakeWin32ErrorCodeFromHR(int hr)
+ {
+ if ((0xFFFF0000 & hr) == 0x80070000)
+ {
+ // Win32 error, Win32Marshal.GetExceptionForWin32Error expects the Win32 format
+ hr &= 0x0000FFFF;
+ }
+
+ return hr;
+ }
+
+ /// <summary>
+ /// Returns a string message for the specified Win32 error code.
+ /// </summary>
+ internal static string GetMessage(int errorCode) => Interop.Kernel32.GetMessage(errorCode);
}
}
diff --git a/src/Common/src/CoreLib/System/IntPtr.cs b/src/Common/src/CoreLib/System/IntPtr.cs
index 45c2ded160..44638ddd8e 100644
--- a/src/Common/src/CoreLib/System/IntPtr.cs
+++ b/src/Common/src/CoreLib/System/IntPtr.cs
@@ -23,7 +23,7 @@ namespace System
// See https://github.com/dotnet/corert/blob/master/Documentation/design-docs/diagnostics/diagnostics-tools-contract.md for more details.
// Please do not change the type, the name, or the semantic usage of this member without understanding the implication for tools.
// Get in touch with the diagnostics team if you have questions.
- unsafe private void* _value; // Do not rename (binary serialization)
+ private unsafe void* _value; // Do not rename (binary serialization)
[Intrinsic]
public static readonly IntPtr Zero;
@@ -81,9 +81,9 @@ namespace System
return false;
}
- unsafe bool IEquatable<IntPtr>.Equals(IntPtr value)
+ unsafe bool IEquatable<IntPtr>.Equals(IntPtr other)
{
- return _value == value._value;
+ return _value == other._value;
}
public unsafe override int GetHashCode()
diff --git a/src/Common/src/CoreLib/System/Marvin.cs b/src/Common/src/CoreLib/System/Marvin.cs
new file mode 100644
index 0000000000..e51ad9c552
--- /dev/null
+++ b/src/Common/src/CoreLib/System/Marvin.cs
@@ -0,0 +1,139 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Internal.Runtime.CompilerServices;
+
+#if BIT64
+using nuint = System.UInt64;
+#else
+using nuint = System.UInt32;
+#endif
+
+namespace System
+{
+ internal static class Marvin
+ {
+ /// <summary>
+ /// Compute a Marvin hash and collapse it into a 32-bit hash.
+ /// </summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int ComputeHash32(ReadOnlySpan<byte> data, ulong seed) => ComputeHash32(ref MemoryMarshal.GetReference(data), data.Length, seed);
+
+ /// <summary>
+ /// Compute a Marvin hash and collapse it into a 32-bit hash.
+ /// </summary>
+ public static int ComputeHash32(ref byte data, int count, ulong seed)
+ {
+ nuint ucount = (nuint)count;
+ uint p0 = (uint)seed;
+ uint p1 = (uint)(seed >> 32);
+
+ nuint byteOffset = 0;
+
+ while (ucount >= 8)
+ {
+ p0 += Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref data, byteOffset));
+ Block(ref p0, ref p1);
+
+ p0 += Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref data, byteOffset + 4));
+ Block(ref p0, ref p1);
+
+ byteOffset += 8;
+ ucount -= 8;
+ }
+
+ switch (ucount)
+ {
+ case 4:
+ p0 += Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref data, byteOffset));
+ Block(ref p0, ref p1);
+ goto case 0;
+
+ case 0:
+ p0 += 0x80u;
+ break;
+
+ case 5:
+ p0 += Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref data, byteOffset));
+ byteOffset += 4;
+ Block(ref p0, ref p1);
+ goto case 1;
+
+ case 1:
+ p0 += 0x8000u | Unsafe.AddByteOffset(ref data, byteOffset);
+ break;
+
+ case 6:
+ p0 += Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref data, byteOffset));
+ byteOffset += 4;
+ Block(ref p0, ref p1);
+ goto case 2;
+
+ case 2:
+ p0 += 0x800000u | Unsafe.ReadUnaligned<ushort>(ref Unsafe.AddByteOffset(ref data, byteOffset));
+ break;
+
+ case 7:
+ p0 += Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref data, byteOffset));
+ byteOffset += 4;
+ Block(ref p0, ref p1);
+ goto case 3;
+
+ case 3:
+ p0 += 0x80000000u | (((uint)(Unsafe.AddByteOffset(ref data, byteOffset + 2))) << 16)| (uint)(Unsafe.ReadUnaligned<ushort>(ref Unsafe.AddByteOffset(ref data, byteOffset)));
+ break;
+
+ default:
+ Debug.Fail("Should not get here.");
+ break;
+ }
+
+ Block(ref p0, ref p1);
+ Block(ref p0, ref p1);
+
+ return (int)(p1 ^ p0);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void Block(ref uint rp0, ref uint rp1)
+ {
+ uint p0 = rp0;
+ uint p1 = rp1;
+
+ p1 ^= p0;
+ p0 = _rotl(p0, 20);
+
+ p0 += p1;
+ p1 = _rotl(p1, 9);
+
+ p1 ^= p0;
+ p0 = _rotl(p0, 27);
+
+ p0 += p1;
+ p1 = _rotl(p1, 19);
+
+ rp0 = p0;
+ rp1 = p1;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static uint _rotl(uint value, int shift)
+ {
+ // This is expected to be optimized into a single rol (or ror with negated shift value) instruction
+ return (value << shift) | (value >> (32 - shift));
+ }
+
+ public static ulong DefaultSeed { get; } = GenerateSeed();
+
+ private static unsafe ulong GenerateSeed()
+ {
+ ulong seed;
+ Interop.GetRandomBytes((byte*)&seed, sizeof(ulong));
+ return seed;
+ }
+ }
+}
diff --git a/src/Common/src/CoreLib/System/Memory.cs b/src/Common/src/CoreLib/System/Memory.cs
index 40c4cd9e53..e1316f8509 100644
--- a/src/Common/src/CoreLib/System/Memory.cs
+++ b/src/Common/src/CoreLib/System/Memory.cs
@@ -20,8 +20,8 @@ namespace System
/// Memory represents a contiguous region of arbitrary memory similar to <see cref="Span{T}"/>.
/// Unlike <see cref="Span{T}"/>, it is not a byref-like type.
/// </summary>
- [DebuggerDisplay("{DebuggerDisplay,nq}")]
[DebuggerTypeProxy(typeof(MemoryDebugView<>))]
+ [DebuggerDisplay("{ToString(),raw}")]
public readonly struct Memory<T>
{
// NOTE: With the current implementation, Memory<T> and ReadOnlyMemory<T> must have the same layout,
@@ -42,14 +42,16 @@ namespace System
/// Creates a new memory over the entirety of the target array.
/// </summary>
/// <param name="array">The target array.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
- /// reference (Nothing in Visual Basic).</exception>
+ /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
/// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Memory(T[] array)
{
if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
+ {
+ this = default;
+ return; // returns default
+ }
if (default(T) == null && array.GetType() != typeof(T[]))
ThrowHelper.ThrowArrayTypeMismatchException();
@@ -58,6 +60,26 @@ namespace System
_length = array.Length;
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal Memory(T[] array, int start)
+ {
+ if (array == null)
+ {
+ if (start != 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+ this = default;
+ return; // returns default
+ }
+ if (default(T) == null && array.GetType() != typeof(T[]))
+ ThrowHelper.ThrowArrayTypeMismatchException();
+ if ((uint)start > (uint)array.Length)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ _object = array;
+ _index = start;
+ _length = array.Length - start;
+ }
+
/// <summary>
/// Creates a new memory over the portion of the target array beginning
/// at 'start' index and ending at 'end' index (exclusive).
@@ -65,8 +87,7 @@ namespace System
/// <param name="array">The target array.</param>
/// <param name="start">The index at which to begin the memory.</param>
/// <param name="length">The number of items in the memory.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
- /// reference (Nothing in Visual Basic).</exception>
+ /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
/// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// Thrown when the specified <paramref name="start"/> or end index is not in the range (&lt;0 or &gt;=Length).
@@ -75,7 +96,12 @@ namespace System
public Memory(T[] array, int start, int length)
{
if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
+ {
+ if (start != 0 || length != 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+ this = default;
+ return; // returns default
+ }
if (default(T) == null && array.GetType() != typeof(T[]))
ThrowHelper.ThrowArrayTypeMismatchException();
if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
@@ -113,7 +139,7 @@ namespace System
/// <summary>
/// Defines an implicit conversion of a <see cref="ArraySegment{T}"/> to a <see cref="Memory{T}"/>
/// </summary>
- public static implicit operator Memory<T>(ArraySegment<T> arraySegment) => new Memory<T>(arraySegment.Array, arraySegment.Offset, arraySegment.Count);
+ public static implicit operator Memory<T>(ArraySegment<T> segment) => new Memory<T>(segment.Array, segment.Offset, segment.Count);
/// <summary>
/// Defines an implicit conversion of a <see cref="Memory{T}"/> to a <see cref="ReadOnlyMemory{T}"/>
@@ -121,9 +147,6 @@ namespace System
public static implicit operator ReadOnlyMemory<T>(Memory<T> memory) =>
Unsafe.As<Memory<T>, ReadOnlyMemory<T>>(ref memory);
- //Debugger Display = {T[length]}
- private string DebuggerDisplay => string.Format("{{{0}[{1}]}}", typeof(T).Name, _length);
-
/// <summary>
/// Returns an empty <see cref="Memory{T}"/>
/// </summary>
@@ -140,6 +163,19 @@ namespace System
public bool IsEmpty => _length == 0;
/// <summary>
+ /// For <see cref="Memory{Char}"/>, returns a new instance of string that represents the characters pointed to by the memory.
+ /// Otherwise, returns a <see cref="string"/> with the name of the type and the number of elements.
+ /// </summary>
+ public override string ToString()
+ {
+ if (typeof(T) == typeof(char))
+ {
+ return (_object is string str) ? str.Substring(_index, _length) : Span.ToString();
+ }
+ return string.Format("System.Memory<{0}>[{1}]", typeof(T).Name, _length);
+ }
+
+ /// <summary>
/// Forms a slice out of the given memory, beginning at 'start'.
/// </summary>
/// <param name="start">The index at which to begin this slice.</param>
@@ -236,9 +272,49 @@ namespace System
public bool TryCopyTo(Memory<T> destination) => Span.TryCopyTo(destination.Span);
/// <summary>
- /// Returns a handle for the array.
- /// <param name="pin">If pin is true, the GC will not move the array and hence its address can be taken</param>
+ /// Creates a handle for the memory.
+ /// The GC will not move the array until the returned <see cref="MemoryHandle"/>
+ /// is disposed, enabling taking and using the memory's address.
/// </summary>
+ public unsafe MemoryHandle Pin()
+ {
+ if (_index < 0)
+ {
+ return ((OwnedMemory<T>)_object).Pin((_index & RemoveOwnedFlagBitMask) * Unsafe.SizeOf<T>());
+ }
+ else if (typeof(T) == typeof(char) && _object is string s)
+ {
+ // This case can only happen if a ReadOnlyMemory<char> was created around a string
+ // and then that was cast to a Memory<char> using unsafe / marshaling code. This needs
+ // to work, however, so that code that uses a single Memory<char> field to store either
+ // a readable ReadOnlyMemory<char> or a writable Memory<char> can still be pinned and
+ // used for interop purposes.
+ GCHandle handle = GCHandle.Alloc(s, GCHandleType.Pinned);
+#if FEATURE_PORTABLE_SPAN
+ void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
+#else
+ void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref s.GetRawStringData()), _index);
+#endif // FEATURE_PORTABLE_SPAN
+ return new MemoryHandle(null, pointer, handle);
+ }
+ else if (_object is T[] array)
+ {
+ var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
+#if FEATURE_PORTABLE_SPAN
+ void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
+#else
+ void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index);
+#endif // FEATURE_PORTABLE_SPAN
+ return new MemoryHandle(null, pointer, handle);
+ }
+ return default;
+ }
+
+ /// <summary>[Obsolete, use Pin()] Creates a handle for the memory.</summary>
+ /// <param name="pin">
+ /// If pin is true, the GC will not move the array until the returned <see cref="MemoryHandle"/>
+ /// is disposed, enabling taking and using the memory's address.
+ /// </param>
public unsafe MemoryHandle Retain(bool pin = false)
{
MemoryHandle memoryHandle = default;
@@ -286,30 +362,6 @@ namespace System
}
/// <summary>
- /// Get an array segment from the underlying memory.
- /// If unable to get the array segment, return false with a default array segment.
- /// </summary>
- public bool TryGetArray(out ArraySegment<T> arraySegment)
- {
- if (_index < 0)
- {
- if (((OwnedMemory<T>)_object).TryGetArray(out var segment))
- {
- arraySegment = new ArraySegment<T>(segment.Array, segment.Offset + (_index & RemoveOwnedFlagBitMask), _length);
- return true;
- }
- }
- else if (_object is T[] arr)
- {
- arraySegment = new ArraySegment<T>(arr, _index, _length);
- return true;
- }
-
- arraySegment = default(ArraySegment<T>);
- return false;
- }
-
- /// <summary>
/// Copies the contents from the memory into a new array. This heap
/// allocates, so should generally be avoided, however it is sometimes
/// necessary to bridge the gap with APIs written in terms of arrays.
diff --git a/src/Common/src/CoreLib/System/MemoryDebugView.cs b/src/Common/src/CoreLib/System/MemoryDebugView.cs
index fa508b286f..f56a67c636 100644
--- a/src/Common/src/CoreLib/System/MemoryDebugView.cs
+++ b/src/Common/src/CoreLib/System/MemoryDebugView.cs
@@ -22,31 +22,6 @@ namespace System
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
- public T[] Items
- {
- // This is a work around since we cannot use _memory.ToArray() due to
- // https://devdiv.visualstudio.com/DevDiv/_workitems?id=286592
- get
- {
- if (MemoryMarshal.TryGetArray(_memory, out ArraySegment<T> segment))
- {
- T[] array = new T[_memory.Length];
- Array.Copy(segment.Array, segment.Offset, array, 0, array.Length);
- return array;
- }
-
- if (typeof(T) == typeof(char) &&
- ((ReadOnlyMemory<char>)(object)_memory).TryGetString(out string text, out int start, out int length))
- {
- return (T[])(object)text.Substring(start, length).ToCharArray();
- }
-
-#if FEATURE_PORTABLE_SPAN
- return SpanHelpers.PerTypeValues<T>.EmptyArray;
-#else
- return Array.Empty<T>();
-#endif // FEATURE_PORTABLE_SPAN
- }
- }
+ public T[] Items => _memory.ToArray();
}
}
diff --git a/src/Common/src/CoreLib/System/MemoryExtensions.Fast.cs b/src/Common/src/CoreLib/System/MemoryExtensions.Fast.cs
new file mode 100644
index 0000000000..d9e3af8804
--- /dev/null
+++ b/src/Common/src/CoreLib/System/MemoryExtensions.Fast.cs
@@ -0,0 +1,496 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+using Internal.Runtime.CompilerServices;
+
+namespace System
+{
+ /// <summary>
+ /// Extension methods for Span{T}, Memory{T}, and friends.
+ /// </summary>
+ public static partial class MemoryExtensions
+ {
+ /// <summary>
+ /// Returns a value indicating whether the specified <paramref name="value"/> occurs within the <paramref name="span"/>.
+ /// <param name="span">The source span.</param>
+ /// <param name="value">The value to seek within the source span.</param>
+ /// <param name="comparisonType">One of the enumeration values that determines how the <paramref name="span"/> and <paramref name="value"/> are compared.</param>
+ /// </summary>
+ public static bool Contains(this ReadOnlySpan<char> span, ReadOnlySpan<char> value, StringComparison comparisonType)
+ {
+ return (IndexOf(span, value, comparisonType) >= 0);
+ }
+
+ /// <summary>
+ /// Determines whether this <paramref name="span"/> and the specified <paramref name="other"/> span have the same characters
+ /// when compared using the specified <paramref name="comparisonType"/> option.
+ /// <param name="span">The source span.</param>
+ /// <param name="other">The value to compare with the source span.</param>
+ /// <param name="comparisonType">One of the enumeration values that determines how the <paramref name="span"/> and <paramref name="other"/> are compared.</param>
+ /// </summary>
+ public static bool Equals(this ReadOnlySpan<char> span, ReadOnlySpan<char> other, StringComparison comparisonType)
+ {
+ string.CheckStringComparison(comparisonType);
+
+ switch (comparisonType)
+ {
+ case StringComparison.CurrentCulture:
+ return (CultureInfo.CurrentCulture.CompareInfo.CompareOptionNone(span, other) == 0);
+
+ case StringComparison.CurrentCultureIgnoreCase:
+ return (CultureInfo.CurrentCulture.CompareInfo.CompareOptionIgnoreCase(span, other) == 0);
+
+ case StringComparison.InvariantCulture:
+ return (CompareInfo.Invariant.CompareOptionNone(span, other) == 0);
+
+ case StringComparison.InvariantCultureIgnoreCase:
+ return (CompareInfo.Invariant.CompareOptionIgnoreCase(span, other) == 0);
+
+ case StringComparison.Ordinal:
+ return EqualsOrdinal(span, other);
+
+ case StringComparison.OrdinalIgnoreCase:
+ return EqualsOrdinalIgnoreCase(span, other);
+ }
+
+ Debug.Fail("StringComparison outside range");
+ return false;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static bool EqualsOrdinal(this ReadOnlySpan<char> span, ReadOnlySpan<char> value)
+ {
+ if (span.Length != value.Length)
+ return false;
+ if (value.Length == 0) // span.Length == value.Length == 0
+ return true;
+ return span.SequenceEqual(value); //TODO: Optimize - https://github.com/dotnet/corefx/issues/27487
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static bool EqualsOrdinalIgnoreCase(this ReadOnlySpan<char> span, ReadOnlySpan<char> value)
+ {
+ if (span.Length != value.Length)
+ return false;
+ if (value.Length == 0) // span.Length == value.Length == 0
+ return true;
+ return (CompareInfo.CompareOrdinalIgnoreCase(span, value) == 0);
+ }
+
+ // TODO https://github.com/dotnet/corefx/issues/27526
+ internal static bool Contains(this ReadOnlySpan<char> source, char value)
+ {
+ for (int i = 0; i < source.Length; i++)
+ {
+ if (source[i] == value)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// Compares the specified <paramref name="span"/> and <paramref name="other"/> using the specified <paramref name="comparisonType"/>,
+ /// and returns an integer that indicates their relative position in the sort order.
+ /// <param name="span">The source span.</param>
+ /// <param name="other">The value to compare with the source span.</param>
+ /// <param name="comparisonType">One of the enumeration values that determines how the <paramref name="span"/> and <paramref name="other"/> are compared.</param>
+ /// </summary>
+ public static int CompareTo(this ReadOnlySpan<char> span, ReadOnlySpan<char> other, StringComparison comparisonType)
+ {
+ string.CheckStringComparison(comparisonType);
+
+ switch (comparisonType)
+ {
+ case StringComparison.CurrentCulture:
+ return CultureInfo.CurrentCulture.CompareInfo.CompareOptionNone(span, other);
+
+ case StringComparison.CurrentCultureIgnoreCase:
+ return CultureInfo.CurrentCulture.CompareInfo.CompareOptionIgnoreCase(span, other);
+
+ case StringComparison.InvariantCulture:
+ return CompareInfo.Invariant.CompareOptionNone(span, other);
+
+ case StringComparison.InvariantCultureIgnoreCase:
+ return CompareInfo.Invariant.CompareOptionIgnoreCase(span, other);
+
+ case StringComparison.Ordinal:
+ if (span.Length == 0 || other.Length == 0)
+ return span.Length - other.Length;
+ return string.CompareOrdinal(span, other);
+
+ case StringComparison.OrdinalIgnoreCase:
+ return CompareInfo.CompareOrdinalIgnoreCase(span, other);
+ }
+
+ Debug.Fail("StringComparison outside range");
+ return 0;
+ }
+
+ /// <summary>
+ /// Reports the zero-based index of the first occurrence of the specified <paramref name="value"/> in the current <paramref name="span"/>.
+ /// <param name="span">The source span.</param>
+ /// <param name="value">The value to seek within the source span.</param>
+ /// <param name="comparisonType">One of the enumeration values that determines how the <paramref name="span"/> and <paramref name="value"/> are compared.</param>
+ /// </summary>
+ public static int IndexOf(this ReadOnlySpan<char> span, ReadOnlySpan<char> value, StringComparison comparisonType)
+ {
+ string.CheckStringComparison(comparisonType);
+
+ if (value.Length == 0)
+ {
+ return 0;
+ }
+
+ if (span.Length == 0)
+ {
+ return -1;
+ }
+
+ switch (comparisonType)
+ {
+ case StringComparison.CurrentCulture:
+ return SpanHelpers.IndexOfCultureHelper(span, value, CultureInfo.CurrentCulture.CompareInfo);
+
+ case StringComparison.CurrentCultureIgnoreCase:
+ return SpanHelpers.IndexOfCultureIgnoreCaseHelper(span, value, CultureInfo.CurrentCulture.CompareInfo);
+
+ case StringComparison.InvariantCulture:
+ return SpanHelpers.IndexOfCultureHelper(span, value, CompareInfo.Invariant);
+
+ case StringComparison.InvariantCultureIgnoreCase:
+ return SpanHelpers.IndexOfCultureIgnoreCaseHelper(span, value, CompareInfo.Invariant);
+
+ case StringComparison.Ordinal:
+ return SpanHelpers.IndexOfOrdinalHelper(span, value, ignoreCase: false);
+
+ case StringComparison.OrdinalIgnoreCase:
+ return SpanHelpers.IndexOfOrdinalHelper(span, value, ignoreCase: true);
+ }
+
+ Debug.Fail("StringComparison outside range");
+ return -1;
+ }
+
+ /// <summary>
+ /// Copies the characters from the source span into the destination, converting each character to lowercase,
+ /// using the casing rules of the specified culture.
+ /// </summary>
+ /// <param name="source">The source span.</param>
+ /// <param name="destination">The destination span which contains the transformed characters.</param>
+ /// <param name="culture">An object that supplies culture-specific casing rules.</param>
+ /// <remarks>If the source and destinations overlap, this method behaves as if the original values are in
+ /// a temporary location before the destination is overwritten.</remarks>
+ /// <exception cref="System.ArgumentNullException">
+ /// Thrown when <paramref name="culture"/> is null.
+ /// </exception>
+ public static int ToLower(this ReadOnlySpan<char> source, Span<char> destination, CultureInfo culture)
+ {
+ if (culture == null)
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.culture);
+
+ // Assuming that changing case does not affect length
+ if (destination.Length < source.Length)
+ return -1;
+
+ if (GlobalizationMode.Invariant)
+ culture.TextInfo.ToLowerAsciiInvariant(source, destination);
+ else
+ culture.TextInfo.ChangeCase(source, destination, toUpper: false);
+ return source.Length;
+ }
+
+ /// <summary>
+ /// Copies the characters from the source span into the destination, converting each character to lowercase,
+ /// using the casing rules of the invariant culture.
+ /// </summary>
+ /// <param name="source">The source span.</param>
+ /// <param name="destination">The destination span which contains the transformed characters.</param>
+ /// <remarks>If the source and destinations overlap, this method behaves as if the original values are in
+ /// a temporary location before the destination is overwritten.</remarks>
+ public static int ToLowerInvariant(this ReadOnlySpan<char> source, Span<char> destination)
+ {
+ // Assuming that changing case does not affect length
+ if (destination.Length < source.Length)
+ return -1;
+
+ if (GlobalizationMode.Invariant)
+ CultureInfo.InvariantCulture.TextInfo.ToLowerAsciiInvariant(source, destination);
+ else
+ CultureInfo.InvariantCulture.TextInfo.ChangeCase(source, destination, toUpper: false);
+ return source.Length;
+ }
+
+ /// <summary>
+ /// Copies the characters from the source span into the destination, converting each character to uppercase,
+ /// using the casing rules of the specified culture.
+ /// </summary>
+ /// <param name="source">The source span.</param>
+ /// <param name="destination">The destination span which contains the transformed characters.</param>
+ /// <param name="culture">An object that supplies culture-specific casing rules.</param>
+ /// <remarks>If the source and destinations overlap, this method behaves as if the original values are in
+ /// a temporary location before the destination is overwritten.</remarks>
+ /// <exception cref="System.ArgumentNullException">
+ /// Thrown when <paramref name="culture"/> is null.
+ /// </exception>
+ public static int ToUpper(this ReadOnlySpan<char> source, Span<char> destination, CultureInfo culture)
+ {
+ if (culture == null)
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.culture);
+
+ // Assuming that changing case does not affect length
+ if (destination.Length < source.Length)
+ return -1;
+
+ if (GlobalizationMode.Invariant)
+ culture.TextInfo.ToUpperAsciiInvariant(source, destination);
+ else
+ culture.TextInfo.ChangeCase(source, destination, toUpper: true);
+ return source.Length;
+ }
+
+ /// <summary>
+ /// Copies the characters from the source span into the destination, converting each character to uppercase
+ /// using the casing rules of the invariant culture.
+ /// </summary>
+ /// <param name="source">The source span.</param>
+ /// <param name="destination">The destination span which contains the transformed characters.</param>
+ /// <remarks>If the source and destinations overlap, this method behaves as if the original values are in
+ /// a temporary location before the destination is overwritten.</remarks>
+ public static int ToUpperInvariant(this ReadOnlySpan<char> source, Span<char> destination)
+ {
+ // Assuming that changing case does not affect length
+ if (destination.Length < source.Length)
+ return -1;
+
+ if (GlobalizationMode.Invariant)
+ CultureInfo.InvariantCulture.TextInfo.ToUpperAsciiInvariant(source, destination);
+ else
+ CultureInfo.InvariantCulture.TextInfo.ChangeCase(source, destination, toUpper: true);
+ return source.Length;
+ }
+
+ /// <summary>
+ /// Determines whether the end of the <paramref name="span"/> matches the specified <paramref name="value"/> when compared using the specified <paramref name="comparisonType"/> option.
+ /// </summary>
+ /// <param name="span">The source span.</param>
+ /// <param name="value">The sequence to compare to the end of the source span.</param>
+ /// <param name="comparisonType">One of the enumeration values that determines how the <paramref name="span"/> and <paramref name="value"/> are compared.</param>
+ public static bool EndsWith(this ReadOnlySpan<char> span, ReadOnlySpan<char> value, StringComparison comparisonType)
+ {
+ if (value.Length == 0)
+ {
+ string.CheckStringComparison(comparisonType);
+ return true;
+ }
+
+ switch (comparisonType)
+ {
+ case StringComparison.CurrentCulture:
+ return SpanHelpers.EndsWithCultureHelper(span, value, CultureInfo.CurrentCulture.CompareInfo);
+
+ case StringComparison.CurrentCultureIgnoreCase:
+ return SpanHelpers.EndsWithCultureIgnoreCaseHelper(span, value, CultureInfo.CurrentCulture.CompareInfo);
+
+ case StringComparison.InvariantCulture:
+ return SpanHelpers.EndsWithCultureHelper(span, value, CompareInfo.Invariant);
+
+ case StringComparison.InvariantCultureIgnoreCase:
+ return SpanHelpers.EndsWithCultureIgnoreCaseHelper(span, value, CompareInfo.Invariant);
+
+ case StringComparison.Ordinal:
+ return span.EndsWith(value); //TODO: Optimize - https://github.com/dotnet/corefx/issues/27487
+
+ case StringComparison.OrdinalIgnoreCase:
+ return SpanHelpers.EndsWithOrdinalIgnoreCaseHelper(span, value);
+
+ default:
+ throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType));
+ }
+ }
+
+ /// <summary>
+ /// Determines whether the beginning of the <paramref name="span"/> matches the specified <paramref name="value"/> when compared using the specified <paramref name="comparisonType"/> option.
+ /// </summary>
+ /// <param name="span">The source span.</param>
+ /// <param name="value">The sequence to compare to the beginning of the source span.</param>
+ /// <param name="comparisonType">One of the enumeration values that determines how the <paramref name="span"/> and <paramref name="value"/> are compared.</param>
+ public static bool StartsWith(this ReadOnlySpan<char> span, ReadOnlySpan<char> value, StringComparison comparisonType)
+ {
+ if (value.Length == 0)
+ {
+ string.CheckStringComparison(comparisonType);
+ return true;
+ }
+
+ switch (comparisonType)
+ {
+ case StringComparison.CurrentCulture:
+ return SpanHelpers.StartsWithCultureHelper(span, value, CultureInfo.CurrentCulture.CompareInfo);
+
+ case StringComparison.CurrentCultureIgnoreCase:
+ return SpanHelpers.StartsWithCultureIgnoreCaseHelper(span, value, CultureInfo.CurrentCulture.CompareInfo);
+
+ case StringComparison.InvariantCulture:
+ return SpanHelpers.StartsWithCultureHelper(span, value, CompareInfo.Invariant);
+
+ case StringComparison.InvariantCultureIgnoreCase:
+ return SpanHelpers.StartsWithCultureIgnoreCaseHelper(span, value, CompareInfo.Invariant);
+
+ case StringComparison.Ordinal:
+ return span.StartsWith(value); //TODO: Optimize - https://github.com/dotnet/corefx/issues/27487
+
+ case StringComparison.OrdinalIgnoreCase:
+ return SpanHelpers.StartsWithOrdinalIgnoreCaseHelper(span, value);
+
+ default:
+ throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType));
+ }
+ }
+
+ /// <summary>
+ /// Creates a new span over the portion of the target array.
+ /// </summary>
+ public static Span<T> AsSpan<T>(this T[] array, int start)
+ {
+ if (array == null)
+ {
+ if (start != 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+ return default;
+ }
+ if (default(T) == null && array.GetType() != typeof(T[]))
+ ThrowHelper.ThrowArrayTypeMismatchException();
+ if ((uint)start > (uint)array.Length)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ return new Span<T>(ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), start), array.Length - start);
+ }
+
+ /// <summary>
+ /// Creates a new readonly span over the portion of the target string.
+ /// </summary>
+ /// <param name="text">The target string.</param>
+ /// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
+ public static ReadOnlySpan<char> AsSpan(this string text)
+ {
+ if (text == null)
+ return default;
+
+ return new ReadOnlySpan<char>(ref text.GetRawStringData(), text.Length);
+ }
+
+ /// <summary>
+ /// Creates a new readonly span over the portion of the target string.
+ /// </summary>
+ /// <param name="text">The target string.</param>
+ /// <param name="start">The index at which to begin this slice.</param>
+ /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is null.</exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> index is not in range (&lt;0 or &gt;text.Length).
+ /// </exception>
+ public static ReadOnlySpan<char> AsSpan(this string text, int start)
+ {
+ if (text == null)
+ {
+ if (start != 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+ return default;
+ }
+
+ if ((uint)start > (uint)text.Length)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+
+ return new ReadOnlySpan<char>(ref Unsafe.Add(ref text.GetRawStringData(), start), text.Length - start);
+ }
+
+ /// <summary>
+ /// Creates a new readonly span over the portion of the target string.
+ /// </summary>
+ /// <param name="text">The target string.</param>
+ /// <param name="start">The index at which to begin this slice.</param>
+ /// <param name="length">The desired length for the slice (exclusive).</param>
+ /// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> index or <paramref name="length"/> is not in range.
+ /// </exception>
+ public static ReadOnlySpan<char> AsSpan(this string text, int start, int length)
+ {
+ if (text == null)
+ {
+ if (start != 0 || length != 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+ return default;
+ }
+
+ if ((uint)start > (uint)text.Length || (uint)length > (uint)(text.Length - start))
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+
+ return new ReadOnlySpan<char>(ref Unsafe.Add(ref text.GetRawStringData(), start), length);
+ }
+
+ /// <summary>Creates a new <see cref="ReadOnlyMemory{T}"/> over the portion of the target string.</summary>
+ /// <param name="text">The target string.</param>
+ /// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
+ public static ReadOnlyMemory<char> AsMemory(this string text)
+ {
+ if (text == null)
+ return default;
+
+ return new ReadOnlyMemory<char>(text, 0, text.Length);
+ }
+
+ /// <summary>Creates a new <see cref="ReadOnlyMemory{T}"/> over the portion of the target string.</summary>
+ /// <param name="text">The target string.</param>
+ /// <param name="start">The index at which to begin this slice.</param>
+ /// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> index is not in range (&lt;0 or &gt;text.Length).
+ /// </exception>
+ public static ReadOnlyMemory<char> AsMemory(this string text, int start)
+ {
+ if (text == null)
+ {
+ if (start != 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+ return default;
+ }
+
+ if ((uint)start > (uint)text.Length)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+
+ return new ReadOnlyMemory<char>(text, start, text.Length - start);
+ }
+
+ /// <summary>Creates a new <see cref="ReadOnlyMemory{T}"/> over the portion of the target string.</summary>
+ /// <param name="text">The target string.</param>
+ /// <param name="start">The index at which to begin this slice.</param>
+ /// <param name="length">The desired length for the slice (exclusive).</param>
+ /// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> index or <paramref name="length"/> is not in range.
+ /// </exception>
+ public static ReadOnlyMemory<char> AsMemory(this string text, int start, int length)
+ {
+ if (text == null)
+ {
+ if (start != 0 || length != 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+ return default;
+ }
+
+ if ((uint)start > (uint)text.Length || (uint)length > (uint)(text.Length - start))
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+
+ return new ReadOnlyMemory<char>(text, start, length);
+ }
+ }
+}
diff --git a/src/System.Memory/src/System/MemoryExtensions.cs b/src/Common/src/CoreLib/System/MemoryExtensions.cs
index d886fd5864..1a3b33acc7 100644
--- a/src/System.Memory/src/System/MemoryExtensions.cs
+++ b/src/Common/src/CoreLib/System/MemoryExtensions.cs
@@ -10,6 +10,16 @@ using System.Runtime.InteropServices;
using Internal.Runtime.CompilerServices;
#endif
+#if netstandard
+using nuint = System.NUInt;
+#else
+#if BIT64
+using nuint = System.UInt64;
+#else
+using nuint = System.UInt32;
+#endif // BIT64
+#endif // netstandard
+
namespace System
{
/// <summary>
@@ -18,6 +28,169 @@ namespace System
public static partial class MemoryExtensions
{
/// <summary>
+ /// Removes all leading and trailing white-space characters from the span.
+ /// </summary>
+ public static ReadOnlySpan<char> Trim(this ReadOnlySpan<char> span)
+ {
+ return span.TrimStart().TrimEnd();
+ }
+
+ /// <summary>
+ /// Removes all leading white-space characters from the span.
+ /// </summary>
+ public static ReadOnlySpan<char> TrimStart(this ReadOnlySpan<char> span)
+ {
+ int start = 0;
+ for (; start < span.Length; start++)
+ {
+ if (!char.IsWhiteSpace(span[start]))
+ break;
+ }
+ return span.Slice(start);
+ }
+
+ /// <summary>
+ /// Removes all trailing white-space characters from the span.
+ /// </summary>
+ public static ReadOnlySpan<char> TrimEnd(this ReadOnlySpan<char> span)
+ {
+ int end = span.Length - 1;
+ for (; end >= 0; end--)
+ {
+ if (!char.IsWhiteSpace(span[end]))
+ break;
+ }
+ return span.Slice(0, end + 1);
+ }
+
+ /// <summary>
+ /// Removes all leading and trailing occurrences of a specified character.
+ /// </summary>
+ /// <param name="span">The source span from which the character is removed.</param>
+ /// <param name="trimChar">The specified character to look for and remove.</param>
+ //[MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ReadOnlySpan<char> Trim(this ReadOnlySpan<char> span, char trimChar)
+ {
+ return span.TrimStart(trimChar).TrimEnd(trimChar);
+ }
+
+ /// <summary>
+ /// Removes all leading occurrences of a specified character.
+ /// </summary>
+ /// <param name="span">The source span from which the character is removed.</param>
+ /// <param name="trimChar">The specified character to look for and remove.</param>
+ //[MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ReadOnlySpan<char> TrimStart(this ReadOnlySpan<char> span, char trimChar)
+ {
+ int start = 0;
+ for (; start < span.Length; start++)
+ {
+ if (span[start] != trimChar)
+ break;
+ }
+ return span.Slice(start);
+ }
+
+ /// <summary>
+ /// Removes all trailing occurrences of a specified character.
+ /// </summary>
+ /// <param name="span">The source span from which the character is removed.</param>
+ /// <param name="trimChar">The specified character to look for and remove.</param>
+ public static ReadOnlySpan<char> TrimEnd(this ReadOnlySpan<char> span, char trimChar)
+ {
+ int end = span.Length - 1;
+ for (; end >= 0; end--)
+ {
+ if (span[end] != trimChar)
+ break;
+ }
+ return span.Slice(0, end + 1);
+ }
+
+ /// <summary>
+ /// Removes all leading and trailing occurrences of a set of characters specified
+ /// in a readonly span from the span.
+ /// </summary>
+ /// <param name="span">The source span from which the characters are removed.</param>
+ /// <param name="trimChars">The span which contains the set of characters to remove.</param>
+ /// <remarks>If <paramref name="trimChars"/> is empty, white-space characters are removed instead.</remarks>
+ public static ReadOnlySpan<char> Trim(this ReadOnlySpan<char> span, ReadOnlySpan<char> trimChars)
+ {
+ return span.TrimStart(trimChars).TrimEnd(trimChars);
+ }
+
+ /// <summary>
+ /// Removes all leading occurrences of a set of characters specified
+ /// in a readonly span from the span.
+ /// </summary>
+ /// <param name="span">The source span from which the characters are removed.</param>
+ /// <param name="trimChars">The span which contains the set of characters to remove.</param>
+ /// <remarks>If <paramref name="trimChars"/> is empty, white-space characters are removed instead.</remarks>
+ public static ReadOnlySpan<char> TrimStart(this ReadOnlySpan<char> span, ReadOnlySpan<char> trimChars)
+ {
+ if (trimChars.IsEmpty)
+ {
+ return span.TrimStart();
+ }
+
+ int start = 0;
+ for (; start < span.Length; start++)
+ {
+ for (int i = 0; i < trimChars.Length; i++)
+ {
+ if (span[start] == trimChars[i])
+ goto Next;
+ }
+ break;
+ Next:
+ ;
+ }
+ return span.Slice(start);
+ }
+
+ /// <summary>
+ /// Removes all trailing occurrences of a set of characters specified
+ /// in a readonly span from the span.
+ /// </summary>
+ /// <param name="span">The source span from which the characters are removed.</param>
+ /// <param name="trimChars">The span which contains the set of characters to remove.</param>
+ /// <remarks>If <paramref name="trimChars"/> is empty, white-space characters are removed instead.</remarks>
+ public static ReadOnlySpan<char> TrimEnd(this ReadOnlySpan<char> span, ReadOnlySpan<char> trimChars)
+ {
+ if (trimChars.IsEmpty)
+ {
+ return span.TrimEnd();
+ }
+
+ int end = span.Length - 1;
+ for (; end >= 0; end--)
+ {
+ for (int i = 0; i < trimChars.Length; i++)
+ {
+ if (span[end] == trimChars[i])
+ goto Next;
+ }
+ break;
+ Next:
+ ;
+ }
+ return span.Slice(0, end + 1);
+ }
+
+ /// <summary>
+ /// Indicates whether the specified span contains only white-space characters.
+ /// </summary>
+ public static bool IsWhiteSpace(this ReadOnlySpan<char> span)
+ {
+ for (int i = 0; i < span.Length; i++)
+ {
+ if (!char.IsWhiteSpace(span[i]))
+ return false;
+ }
+ return true;
+ }
+
+ /// <summary>
/// Searches for the specified value and returns the index of its first occurrence. If not found, returns -1. Values are compared using IEquatable{T}.Equals(T).
/// </summary>
/// <param name="span">The span to search.</param>
@@ -31,7 +204,13 @@ namespace System
ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
Unsafe.As<T, byte>(ref value),
span.Length);
- return SpanHelpers.IndexOf<T>(ref MemoryMarshal.GetReference(span), value, span.Length);
+ if (typeof(T) == typeof(char))
+ return SpanHelpers.IndexOf(
+ ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
+ Unsafe.As<T, char>(ref value),
+ span.Length);
+
+ return SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(span), value, span.Length);
}
/// <summary>
@@ -49,7 +228,8 @@ namespace System
span.Length,
ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(value)),
value.Length);
- return SpanHelpers.IndexOf<T>(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(value), value.Length);
+
+ return SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(value), value.Length);
}
/// <summary>
@@ -66,6 +246,7 @@ namespace System
ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
Unsafe.As<T, byte>(ref value),
span.Length);
+
return SpanHelpers.LastIndexOf<T>(ref MemoryMarshal.GetReference(span), value, span.Length);
}
@@ -84,6 +265,7 @@ namespace System
span.Length,
ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(value)),
value.Length);
+
return SpanHelpers.LastIndexOf<T>(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(value), value.Length);
}
@@ -91,50 +273,42 @@ namespace System
/// Determines whether two sequences are equal by comparing the elements using IEquatable{T}.Equals(T).
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool SequenceEqual<T>(this Span<T> first, ReadOnlySpan<T> second)
+ public static bool SequenceEqual<T>(this Span<T> span, ReadOnlySpan<T> other)
where T : IEquatable<T>
{
- int length = first.Length;
- if (typeof(T) == typeof(byte))
- return length == second.Length &&
+ int length = span.Length;
+
+ if (default(T) != null && IsTypeComparableAsBytes<T>(out nuint size))
+ return length == other.Length &&
SpanHelpers.SequenceEqual(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(first)),
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(second)),
- length);
- return length == second.Length && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(first), ref MemoryMarshal.GetReference(second), length);
+ ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
+ ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(other)),
+ ((nuint)length) * size); // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this api in such a case so we choose not to take the overhead of checking.
+
+ return length == other.Length && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(span), ref MemoryMarshal.GetReference(other), length);
}
/// <summary>
/// Determines the relative order of the sequences being compared by comparing the elements using IComparable{T}.CompareTo(T).
/// </summary>
- public static int SequenceCompareTo<T>(this Span<T> first, ReadOnlySpan<T> second)
+ public static int SequenceCompareTo<T>(this Span<T> span, ReadOnlySpan<T> other)
where T : IComparable<T>
{
if (typeof(T) == typeof(byte))
return SpanHelpers.SequenceCompareTo(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(first)),
- first.Length,
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(second)),
- second.Length);
- return SpanHelpers.SequenceCompareTo(ref MemoryMarshal.GetReference(first), first.Length, ref MemoryMarshal.GetReference(second), second.Length);
- }
+ ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
+ span.Length,
+ ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(other)),
+ other.Length);
- /// <summary>
- /// Reverses the sequence of the elements in the entire span.
- /// </summary>
- public static void Reverse<T>(this Span<T> span)
- {
- ref T p = ref MemoryMarshal.GetReference(span);
- int i = 0;
- int j = span.Length - 1;
- while (i < j)
- {
- T temp = Unsafe.Add(ref p, i);
- Unsafe.Add(ref p, i) = Unsafe.Add(ref p, j);
- Unsafe.Add(ref p, j) = temp;
- i++;
- j--;
- }
+ if (typeof(T) == typeof(char))
+ return SpanHelpers.SequenceCompareTo(
+ ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
+ span.Length,
+ ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(other)),
+ other.Length);
+
+ return SpanHelpers.SequenceCompareTo(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(other), other.Length);
}
/// <summary>
@@ -151,7 +325,13 @@ namespace System
ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
Unsafe.As<T, byte>(ref value),
span.Length);
- return SpanHelpers.IndexOf<T>(ref MemoryMarshal.GetReference(span), value, span.Length);
+ if (typeof(T) == typeof(char))
+ return SpanHelpers.IndexOf(
+ ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
+ Unsafe.As<T, char>(ref value),
+ span.Length);
+
+ return SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(span), value, span.Length);
}
/// <summary>
@@ -169,7 +349,8 @@ namespace System
span.Length,
ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(value)),
value.Length);
- return SpanHelpers.IndexOf<T>(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(value), value.Length);
+
+ return SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(value), value.Length);
}
/// <summary>
@@ -186,6 +367,7 @@ namespace System
ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
Unsafe.As<T, byte>(ref value),
span.Length);
+
return SpanHelpers.LastIndexOf<T>(ref MemoryMarshal.GetReference(span), value, span.Length);
}
@@ -204,6 +386,7 @@ namespace System
span.Length,
ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(value)),
value.Length);
+
return SpanHelpers.LastIndexOf<T>(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(value), value.Length);
}
@@ -345,6 +528,7 @@ namespace System
Unsafe.As<T, byte>(ref value0),
Unsafe.As<T, byte>(ref value1),
span.Length);
+
return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, span.Length);
}
@@ -366,6 +550,7 @@ namespace System
Unsafe.As<T, byte>(ref value1),
Unsafe.As<T, byte>(ref value2),
span.Length);
+
return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, value2, span.Length);
}
@@ -384,6 +569,7 @@ namespace System
span.Length,
ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(values)),
values.Length);
+
return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(values), values.Length);
}
@@ -403,6 +589,7 @@ namespace System
Unsafe.As<T, byte>(ref value0),
Unsafe.As<T, byte>(ref value1),
span.Length);
+
return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, span.Length);
}
@@ -424,6 +611,7 @@ namespace System
Unsafe.As<T, byte>(ref value1),
Unsafe.As<T, byte>(ref value2),
span.Length);
+
return SpanHelpers.LastIndexOfAny(ref MemoryMarshal.GetReference(span), value0, value1, value2, span.Length);
}
@@ -442,6 +630,7 @@ namespace System
span.Length,
ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(values)),
values.Length);
+
return SpanHelpers.LastIndexOfAny<T>(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(values), values.Length);
}
@@ -449,32 +638,42 @@ namespace System
/// Determines whether two sequences are equal by comparing the elements using IEquatable{T}.Equals(T).
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool SequenceEqual<T>(this ReadOnlySpan<T> first, ReadOnlySpan<T> second)
+ public static bool SequenceEqual<T>(this ReadOnlySpan<T> span, ReadOnlySpan<T> other)
where T : IEquatable<T>
{
- int length = first.Length;
- if (typeof(T) == typeof(byte))
- return length == second.Length &&
+ int length = span.Length;
+ if (default(T) != null && IsTypeComparableAsBytes<T>(out nuint size))
+ return length == other.Length &&
SpanHelpers.SequenceEqual(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(first)),
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(second)),
- length);
- return length == second.Length && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(first), ref MemoryMarshal.GetReference(second), length);
+ ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
+ ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(other)),
+ ((nuint)length) * size); // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this api in such a case so we choose not to take the overhead of checking.
+
+ return length == other.Length && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(span), ref MemoryMarshal.GetReference(other), length);
}
/// <summary>
/// Determines the relative order of the sequences being compared by comparing the elements using IComparable{T}.CompareTo(T).
/// </summary>
- public static int SequenceCompareTo<T>(this ReadOnlySpan<T> first, ReadOnlySpan<T> second)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int SequenceCompareTo<T>(this ReadOnlySpan<T> span, ReadOnlySpan<T> other)
where T : IComparable<T>
{
if (typeof(T) == typeof(byte))
return SpanHelpers.SequenceCompareTo(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(first)),
- first.Length,
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(second)),
- second.Length);
- return SpanHelpers.SequenceCompareTo(ref MemoryMarshal.GetReference(first), first.Length, ref MemoryMarshal.GetReference(second), second.Length);
+ ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
+ span.Length,
+ ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(other)),
+ other.Length);
+
+ if (typeof(T) == typeof(char))
+ return SpanHelpers.SequenceCompareTo(
+ ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(span)),
+ span.Length,
+ ref Unsafe.As<T, char>(ref MemoryMarshal.GetReference(other)),
+ other.Length);
+
+ return SpanHelpers.SequenceCompareTo(ref MemoryMarshal.GetReference(span), span.Length, ref MemoryMarshal.GetReference(other), other.Length);
}
/// <summary>
@@ -485,12 +684,13 @@ namespace System
where T : IEquatable<T>
{
int valueLength = value.Length;
- if (typeof(T) == typeof(byte))
+ if (default(T) != null && IsTypeComparableAsBytes<T>(out nuint size))
return valueLength <= span.Length &&
SpanHelpers.SequenceEqual(
ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(value)),
- valueLength);
+ ((nuint)valueLength) * size); // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this api in such a case so we choose not to take the overhead of checking.
+
return valueLength <= span.Length && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(span), ref MemoryMarshal.GetReference(value), valueLength);
}
@@ -502,12 +702,13 @@ namespace System
where T : IEquatable<T>
{
int valueLength = value.Length;
- if (typeof(T) == typeof(byte))
+ if (default(T) != null && IsTypeComparableAsBytes<T>(out nuint size))
return valueLength <= span.Length &&
SpanHelpers.SequenceEqual(
ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(span)),
ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(value)),
- valueLength);
+ ((nuint)valueLength) * size); // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this api in such a case so we choose not to take the overhead of checking.
+
return valueLength <= span.Length && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(span), ref MemoryMarshal.GetReference(value), valueLength);
}
@@ -520,12 +721,13 @@ namespace System
{
int spanLength = span.Length;
int valueLength = value.Length;
- if (typeof(T) == typeof(byte))
+ if (default(T) != null && IsTypeComparableAsBytes<T>(out nuint size))
return valueLength <= spanLength &&
SpanHelpers.SequenceEqual(
ref Unsafe.As<T, byte>(ref Unsafe.Add(ref MemoryMarshal.GetReference(span), spanLength - valueLength)),
ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(value)),
- valueLength);
+ ((nuint)valueLength) * size); // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this api in such a case so we choose not to take the overhead of checking.
+
return valueLength <= spanLength &&
SpanHelpers.SequenceEqual(
ref Unsafe.Add(ref MemoryMarshal.GetReference(span), spanLength - valueLength),
@@ -542,12 +744,13 @@ namespace System
{
int spanLength = span.Length;
int valueLength = value.Length;
- if (typeof(T) == typeof(byte))
+ if (default(T) != null && IsTypeComparableAsBytes<T>(out nuint size))
return valueLength <= spanLength &&
SpanHelpers.SequenceEqual(
ref Unsafe.As<T, byte>(ref Unsafe.Add(ref MemoryMarshal.GetReference(span), spanLength - valueLength)),
ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(value)),
- valueLength);
+ ((nuint)valueLength) * size); // If this multiplication overflows, the Span we got overflows the entire address range. There's no happy outcome for this api in such a case so we choose not to take the overhead of checking.
+
return valueLength <= spanLength &&
SpanHelpers.SequenceEqual(
ref Unsafe.Add(ref MemoryMarshal.GetReference(span), spanLength - valueLength),
@@ -556,7 +759,25 @@ namespace System
}
/// <summary>
- /// Creates a new span over the portion of the target array.
+ /// Reverses the sequence of the elements in the entire span.
+ /// </summary>
+ public static void Reverse<T>(this Span<T> span)
+ {
+ ref T p = ref MemoryMarshal.GetReference(span);
+ int i = 0;
+ int j = span.Length - 1;
+ while (i < j)
+ {
+ T temp = Unsafe.Add(ref p, i);
+ Unsafe.Add(ref p, i) = Unsafe.Add(ref p, j);
+ Unsafe.Add(ref p, j) = temp;
+ i++;
+ j--;
+ }
+ }
+
+ /// <summary>
+ /// Creates a new span over the target array.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span<T> AsSpan<T>(this T[] array)
@@ -565,57 +786,168 @@ namespace System
}
/// <summary>
- /// Creates a new span over the portion of the target array segment.
+ /// Creates a new Span over the portion of the target array beginning
+ /// at 'start' index and ending at 'end' index (exclusive).
/// </summary>
+ /// <param name="array">The target array.</param>
+ /// <param name="start">The index at which to begin the Span.</param>
+ /// <param name="length">The number of items in the Span.</param>
+ /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
+ /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> or end index is not in the range (&lt;0 or &gt;=Length).
+ /// </exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Span<T> AsSpan<T>(this ArraySegment<T> arraySegment)
+ public static Span<T> AsSpan<T>(this T[] array, int start, int length)
{
- return new Span<T>(arraySegment.Array, arraySegment.Offset, arraySegment.Count);
+ return new Span<T>(array, start, length);
}
/// <summary>
- /// Creates a new readonly span over the entire target array.
+ /// Creates a new span over the portion of the target array segment.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ReadOnlySpan<T> AsReadOnlySpan<T>(this T[] array)
+ public static Span<T> AsSpan<T>(this ArraySegment<T> segment)
{
- return new ReadOnlySpan<T>(array);
+ return new Span<T>(segment.Array, segment.Offset, segment.Count);
}
/// <summary>
- /// Creates a new readonly span over the entire target span.
+ /// Creates a new Span over the portion of the target array beginning
+ /// at 'start' index and ending at 'end' index (exclusive).
/// </summary>
- public static ReadOnlySpan<T> AsReadOnlySpan<T>(this Span<T> span) => span;
+ /// <param name="segment">The target array.</param>
+ /// <param name="start">The index at which to begin the Span.</param>
+ /// <remarks>Returns default when <paramref name="segment"/> is null.</remarks>
+ /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="segment"/> is covariant and array's type is not exactly T[].</exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> or end index is not in the range (&lt;0 or &gt;=segment.Count).
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Span<T> AsSpan<T>(this ArraySegment<T> segment, int start)
+ {
+ if (((uint)start) > segment.Count)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+
+ return new Span<T>(segment.Array, segment.Offset + start, segment.Count - start);
+ }
/// <summary>
- /// Creates a new readonly span over the target array segment.
+ /// Creates a new Span over the portion of the target array beginning
+ /// at 'start' index and ending at 'end' index (exclusive).
/// </summary>
+ /// <param name="segment">The target array.</param>
+ /// <param name="start">The index at which to begin the Span.</param>
+ /// <param name="length">The number of items in the Span.</param>
+ /// <remarks>Returns default when <paramref name="segment"/> is null.</remarks>
+ /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="segment"/> is covariant and array's type is not exactly T[].</exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> or end index is not in the range (&lt;0 or &gt;=segment.Count).
+ /// </exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ReadOnlySpan<T> AsReadOnlySpan<T>(this ArraySegment<T> arraySegment)
+ public static Span<T> AsSpan<T>(this ArraySegment<T> segment, int start, int length)
+ {
+ if (((uint)start) > segment.Count)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+ if (((uint)length) > segment.Count - start)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length);
+
+ return new Span<T>(segment.Array, segment.Offset + start, length);
+ }
+
+ /// <summary>
+ /// Creates a new memory over the target array.
+ /// </summary>
+ public static Memory<T> AsMemory<T>(this T[] array) => new Memory<T>(array);
+
+ /// <summary>
+ /// Creates a new memory over the portion of the target array beginning
+ /// at 'start' index and ending at 'end' index (exclusive).
+ /// </summary>
+ /// <param name="array">The target array.</param>
+ /// <param name="start">The index at which to begin the memory.</param>
+ /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
+ /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> or end index is not in the range (&lt;0 or &gt;=array.Length).
+ /// </exception>
+ public static Memory<T> AsMemory<T>(this T[] array, int start) => new Memory<T>(array, start);
+
+ /// <summary>
+ /// Creates a new memory over the portion of the target array beginning
+ /// at 'start' index and ending at 'end' index (exclusive).
+ /// </summary>
+ /// <param name="array">The target array.</param>
+ /// <param name="start">The index at which to begin the memory.</param>
+ /// <param name="length">The number of items in the memory.</param>
+ /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
+ /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> or end index is not in the range (&lt;0 or &gt;=Length).
+ /// </exception>
+ public static Memory<T> AsMemory<T>(this T[] array, int start, int length) => new Memory<T>(array, start, length);
+
+ /// <summary>
+ /// Creates a new memory over the portion of the target array.
+ /// </summary>
+ public static Memory<T> AsMemory<T>(this ArraySegment<T> segment) => new Memory<T>(segment.Array, segment.Offset, segment.Count);
+
+ /// <summary>
+ /// Creates a new memory over the portion of the target array beginning
+ /// at 'start' index and ending at 'end' index (exclusive).
+ /// </summary>
+ /// <param name="segment">The target array.</param>
+ /// <param name="start">The index at which to begin the memory.</param>
+ /// <remarks>Returns default when <paramref name="segment"/> is null.</remarks>
+ /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="segment"/> is covariant and array's type is not exactly T[].</exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> or end index is not in the range (&lt;0 or &gt;=segment.Count).
+ /// </exception>
+ public static Memory<T> AsMemory<T>(this ArraySegment<T> segment, int start)
{
- return new ReadOnlySpan<T>(arraySegment.Array, arraySegment.Offset, arraySegment.Count);
+ if (((uint)start) > segment.Count)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+
+ return new Memory<T>(segment.Array, segment.Offset + start, segment.Count - start);
}
/// <summary>
- /// Creates a new readonly memory over the entire target memory.
+ /// Creates a new memory over the portion of the target array beginning
+ /// at 'start' index and ending at 'end' index (exclusive).
/// </summary>
- public static ReadOnlyMemory<T> AsReadOnlyMemory<T>(this Memory<T> memory) => memory;
+ /// <param name="segment">The target array.</param>
+ /// <param name="start">The index at which to begin the memory.</param>
+ /// <param name="length">The number of items in the memory.</param>
+ /// <remarks>Returns default when <paramref name="segment"/> is null.</remarks>
+ /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="segment"/> is covariant and array's type is not exactly T[].</exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> or end index is not in the range (&lt;0 or &gt;=segment.Count).
+ /// </exception>
+ public static Memory<T> AsMemory<T>(this ArraySegment<T> segment, int start, int length)
+ {
+ if (((uint)start) > segment.Count)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+ if (((uint)length) > segment.Count - start)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length);
+
+ return new Memory<T>(segment.Array, segment.Offset + start, length);
+ }
/// <summary>
/// Copies the contents of the array into the span. If the source
/// and destinations overlap, this method behaves as if the original values in
/// a temporary location before the destination is overwritten.
///
- ///<param name="array">The array to copy items from.</param>
+ ///<param name="source">The array to copy items from.</param>
/// <param name="destination">The span to copy items into.</param>
/// <exception cref="System.ArgumentException">
/// Thrown when the destination Span is shorter than the source array.
/// </exception>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void CopyTo<T>(this T[] array, Span<T> destination)
+ public static void CopyTo<T>(this T[] source, Span<T> destination)
{
- new ReadOnlySpan<T>(array).CopyTo(destination);
+ new ReadOnlySpan<T>(source).CopyTo(destination);
}
/// <summary>
@@ -623,16 +955,16 @@ namespace System
/// and destinations overlap, this method behaves as if the original values are in
/// a temporary location before the destination is overwritten.
///
- ///<param name="array">The array to copy items from.</param>
+ ///<param name="source">The array to copy items from.</param>
/// <param name="destination">The memory to copy items into.</param>
/// <exception cref="System.ArgumentException">
/// Thrown when the destination is shorter than the source array.
/// </exception>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void CopyTo<T>(this T[] array, Memory<T> destination)
+ public static void CopyTo<T>(this T[] source, Memory<T> destination)
{
- array.CopyTo(destination.Span);
+ source.CopyTo(destination.Span);
}
//
@@ -686,10 +1018,10 @@ namespace System
//
// Let's say there are two sequences, x and y. Let
//
- // ref T xRef = MemoryMarshal.GetReference(x)
- // uint xLength = x.Length * Unsafe.SizeOf<T>()
- // ref T yRef = MemoryMarshal.GetReference(y)
- // uint yLength = y.Length * Unsafe.SizeOf<T>()
+ // ref T xRef = MemoryMarshal.GetReference(x)
+ // uint xLength = x.Length * Unsafe.SizeOf<T>()
+ // ref T yRef = MemoryMarshal.GetReference(y)
+ // uint yLength = y.Length * Unsafe.SizeOf<T>()
//
// Visually, the two sequences are located somewhere in the 32-bit
// address space as follows:
@@ -745,18 +1077,18 @@ namespace System
//
// After substituting x2 and y2 with their respective definition:
//
- // == (y1 < xLength) || (y1 + yLength > 2³²)
+ // == (y1 < xLength) || (y1 + yLength > 2³²)
//
// Since yLength can't be greater than the size of the address space,
// the overflow can be avoided as follows:
//
- // == (y1 < xLength) || (y1 > 2³² - yLength)
+ // == (y1 < xLength) || (y1 > 2³² - yLength)
//
// However, 2³² cannot be stored in an unsigned 32-bit integer, so one
// more change is needed to keep doing everything with unsigned 32-bit
// integers:
//
- // == (y1 < xLength) || (y1 > -yLength)
+ // == (y1 < xLength) || (y1 > -yLength)
//
// Due to modulo arithmetic, this gives exactly same result *except* if
// yLength is zero, since 2³² - 0 is 0 and not 2³². So the case
@@ -767,65 +1099,65 @@ namespace System
/// Determines whether two sequences overlap in memory.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool Overlaps<T>(this Span<T> first, ReadOnlySpan<T> second)
+ public static bool Overlaps<T>(this Span<T> span, ReadOnlySpan<T> other)
{
- return Overlaps((ReadOnlySpan<T>)first, second);
+ return Overlaps((ReadOnlySpan<T>)span, other);
}
/// <summary>
/// Determines whether two sequences overlap in memory and outputs the element offset.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool Overlaps<T>(this Span<T> first, ReadOnlySpan<T> second, out int elementOffset)
+ public static bool Overlaps<T>(this Span<T> span, ReadOnlySpan<T> other, out int elementOffset)
{
- return Overlaps((ReadOnlySpan<T>)first, second, out elementOffset);
+ return Overlaps((ReadOnlySpan<T>)span, other, out elementOffset);
}
/// <summary>
/// Determines whether two sequences overlap in memory.
/// </summary>
- public static bool Overlaps<T>(this ReadOnlySpan<T> first, ReadOnlySpan<T> second)
+ public static bool Overlaps<T>(this ReadOnlySpan<T> span, ReadOnlySpan<T> other)
{
- if (first.IsEmpty || second.IsEmpty)
+ if (span.IsEmpty || other.IsEmpty)
{
return false;
}
IntPtr byteOffset = Unsafe.ByteOffset(
- ref MemoryMarshal.GetReference(first),
- ref MemoryMarshal.GetReference(second));
+ ref MemoryMarshal.GetReference(span),
+ ref MemoryMarshal.GetReference(other));
if (Unsafe.SizeOf<IntPtr>() == sizeof(int))
{
- return (uint)byteOffset < (uint)(first.Length * Unsafe.SizeOf<T>()) ||
- (uint)byteOffset > (uint)-(second.Length * Unsafe.SizeOf<T>());
+ return (uint)byteOffset < (uint)(span.Length * Unsafe.SizeOf<T>()) ||
+ (uint)byteOffset > (uint)-(other.Length * Unsafe.SizeOf<T>());
}
else
{
- return (ulong)byteOffset < (ulong)((long)first.Length * Unsafe.SizeOf<T>()) ||
- (ulong)byteOffset > (ulong)-((long)second.Length * Unsafe.SizeOf<T>());
+ return (ulong)byteOffset < (ulong)((long)span.Length * Unsafe.SizeOf<T>()) ||
+ (ulong)byteOffset > (ulong)-((long)other.Length * Unsafe.SizeOf<T>());
}
}
/// <summary>
/// Determines whether two sequences overlap in memory and outputs the element offset.
/// </summary>
- public static bool Overlaps<T>(this ReadOnlySpan<T> first, ReadOnlySpan<T> second, out int elementOffset)
+ public static bool Overlaps<T>(this ReadOnlySpan<T> span, ReadOnlySpan<T> other, out int elementOffset)
{
- if (first.IsEmpty || second.IsEmpty)
+ if (span.IsEmpty || other.IsEmpty)
{
elementOffset = 0;
return false;
}
IntPtr byteOffset = Unsafe.ByteOffset(
- ref MemoryMarshal.GetReference(first),
- ref MemoryMarshal.GetReference(second));
+ ref MemoryMarshal.GetReference(span),
+ ref MemoryMarshal.GetReference(other));
if (Unsafe.SizeOf<IntPtr>() == sizeof(int))
{
- if ((uint)byteOffset < (uint)(first.Length * Unsafe.SizeOf<T>()) ||
- (uint)byteOffset > (uint)-(second.Length * Unsafe.SizeOf<T>()))
+ if ((uint)byteOffset < (uint)(span.Length * Unsafe.SizeOf<T>()) ||
+ (uint)byteOffset > (uint)-(other.Length * Unsafe.SizeOf<T>()))
{
if ((int)byteOffset % Unsafe.SizeOf<T>() != 0)
ThrowHelper.ThrowArgumentException_OverlapAlignmentMismatch();
@@ -841,8 +1173,8 @@ namespace System
}
else
{
- if ((ulong)byteOffset < (ulong)((long)first.Length * Unsafe.SizeOf<T>()) ||
- (ulong)byteOffset > (ulong)-((long)second.Length * Unsafe.SizeOf<T>()))
+ if ((ulong)byteOffset < (ulong)((long)span.Length * Unsafe.SizeOf<T>()) ||
+ (ulong)byteOffset > (ulong)-((long)other.Length * Unsafe.SizeOf<T>()))
{
if ((long)byteOffset % Unsafe.SizeOf<T>() != 0)
ThrowHelper.ThrowArgumentException_OverlapAlignmentMismatch();
@@ -872,7 +1204,7 @@ namespace System
/// no larger element, the bitwise complement of <see cref="Span{T}.Length"/>.
/// </returns>
/// <exception cref="T:System.ArgumentNullException">
- /// <paramref name = "comparable" /> is <see langword="null"/> .
+ /// <paramref name = "comparable" /> is <see langword="null"/> .
/// </exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int BinarySearch<T>(
@@ -896,7 +1228,7 @@ namespace System
/// no larger element, the bitwise complement of <see cref="Span{T}.Length"/>.
/// </returns>
/// <exception cref="T:System.ArgumentNullException">
- /// <paramref name = "comparable" /> is <see langword="null"/> .
+ /// <paramref name = "comparable" /> is <see langword="null"/> .
/// </exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int BinarySearch<T, TComparable>(
@@ -922,7 +1254,7 @@ namespace System
/// no larger element, the bitwise complement of <see cref="Span{T}.Length"/>.
/// </returns>
/// <exception cref="T:System.ArgumentNullException">
- /// <paramref name = "comparer" /> is <see langword="null"/> .
+ /// <paramref name = "comparer" /> is <see langword="null"/> .
/// </exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int BinarySearch<T, TComparer>(
@@ -946,7 +1278,7 @@ namespace System
/// no larger element, the bitwise complement of <see cref="ReadOnlySpan{T}.Length"/>.
/// </returns>
/// <exception cref="T:System.ArgumentNullException">
- /// <paramref name = "comparable" /> is <see langword="null"/> .
+ /// <paramref name = "comparable" /> is <see langword="null"/> .
/// </exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int BinarySearch<T>(
@@ -970,7 +1302,7 @@ namespace System
/// no larger element, the bitwise complement of <see cref="ReadOnlySpan{T}.Length"/>.
/// </returns>
/// <exception cref="T:System.ArgumentNullException">
- /// <paramref name = "comparable" /> is <see langword="null"/> .
+ /// <paramref name = "comparable" /> is <see langword="null"/> .
/// </exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int BinarySearch<T, TComparable>(
@@ -996,7 +1328,7 @@ namespace System
/// no larger element, the bitwise complement of <see cref="ReadOnlySpan{T}.Length"/>.
/// </returns>
/// <exception cref="T:System.ArgumentNullException">
- /// <paramref name = "comparer" /> is <see langword="null"/> .
+ /// <paramref name = "comparer" /> is <see langword="null"/> .
/// </exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int BinarySearch<T, TComparer>(
@@ -1010,5 +1342,36 @@ namespace System
value, comparer);
return BinarySearch(span, comparable);
}
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static bool IsTypeComparableAsBytes<T>(out nuint size)
+ {
+ if (typeof(T) == typeof(byte) || typeof(T) == typeof(sbyte))
+ {
+ size = (nuint)sizeof(byte);
+ return true;
+ }
+
+ if (typeof(T) == typeof(char) || typeof(T) == typeof(short) || typeof(T) == typeof(ushort))
+ {
+ size = (nuint)sizeof(char);
+ return true;
+ }
+
+ if (typeof(T) == typeof(int) || typeof(T) == typeof(uint))
+ {
+ size = (nuint)sizeof(int);
+ return true;
+ }
+
+ if (typeof(T) == typeof(long) || typeof(T) == typeof(ulong))
+ {
+ size = (nuint)sizeof(long);
+ return true;
+ }
+
+ size = default;
+ return false;
+ }
}
}
diff --git a/src/Common/src/CoreLib/System/Number.Formatting.cs b/src/Common/src/CoreLib/System/Number.Formatting.cs
index 70b35a08aa..24d5db1da9 100644
--- a/src/Common/src/CoreLib/System/Number.Formatting.cs
+++ b/src/Common/src/CoreLib/System/Number.Formatting.cs
@@ -564,7 +564,7 @@ namespace System
{
Debug.Assert(source != null);
- if (source.AsReadOnlySpan().TryCopyTo(destination))
+ if (source.AsSpan().TryCopyTo(destination))
{
charsWritten = source.Length;
return true;
@@ -1128,10 +1128,8 @@ namespace System
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe bool TryCopyTo(char* src, int length, Span<char> destination, out int charsWritten)
{
- if (length <= destination.Length)
+ if (new ReadOnlySpan<char>(src, length).TryCopyTo(destination))
{
- bool copied = new ReadOnlySpan<char>(src, length).TryCopyTo(destination);
- Debug.Assert(copied);
charsWritten = length;
return true;
}
@@ -1708,8 +1706,7 @@ namespace System
if (thousandsSepCtr >= thousandsSepPos.Length)
{
var newThousandsSepPos = new int[thousandsSepPos.Length * 2];
- bool copied = thousandsSepPos.TryCopyTo(newThousandsSepPos);
- Debug.Assert(copied, "Expect copy to succeed, as the new array is larger than the original");
+ thousandsSepPos.CopyTo(newThousandsSepPos);
thousandsSepPos = newThousandsSepPos;
}
diff --git a/src/Common/src/CoreLib/System/Number.Parsing.cs b/src/Common/src/CoreLib/System/Number.Parsing.cs
index 46951094eb..2ae06180d2 100644
--- a/src/Common/src/CoreLib/System/Number.Parsing.cs
+++ b/src/Common/src/CoreLib/System/Number.Parsing.cs
@@ -300,7 +300,7 @@ namespace System
return true;
}
- internal unsafe static int ParseInt32(ReadOnlySpan<char> s, NumberStyles style, NumberFormatInfo info)
+ internal static unsafe int ParseInt32(ReadOnlySpan<char> s, NumberStyles style, NumberFormatInfo info)
{
NumberBuffer number = default;
int i = 0;
@@ -324,7 +324,7 @@ namespace System
return i;
}
- internal unsafe static long ParseInt64(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt)
+ internal static unsafe long ParseInt64(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt)
{
NumberBuffer number = default;
long i = 0;
@@ -348,7 +348,7 @@ namespace System
return i;
}
- internal unsafe static uint ParseUInt32(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt)
+ internal static unsafe uint ParseUInt32(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt)
{
NumberBuffer number = default;
uint i = 0;
@@ -373,7 +373,7 @@ namespace System
return i;
}
- internal unsafe static ulong ParseUInt64(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt)
+ internal static unsafe ulong ParseUInt64(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt)
{
NumberBuffer number = default;
ulong i = 0;
@@ -396,7 +396,7 @@ namespace System
return i;
}
- private unsafe static bool ParseNumber(ref char* str, NumberStyles options, ref NumberBuffer number, NumberFormatInfo numfmt, bool parseDecimal)
+ private static unsafe bool ParseNumber(ref char* str, NumberStyles options, ref NumberBuffer number, NumberFormatInfo numfmt, bool parseDecimal)
{
const int StateSign = 0x0001;
const int StateParens = 0x0002;
@@ -601,7 +601,7 @@ namespace System
return false;
}
- internal unsafe static bool TryParseInt32(ReadOnlySpan<char> s, NumberStyles style, NumberFormatInfo info, out int result)
+ internal static unsafe bool TryParseInt32(ReadOnlySpan<char> s, NumberStyles style, NumberFormatInfo info, out int result)
{
NumberBuffer number = default;
result = 0;
@@ -628,7 +628,7 @@ namespace System
return true;
}
- internal unsafe static bool TryParseInt64(ReadOnlySpan<char> s, NumberStyles style, NumberFormatInfo info, out long result)
+ internal static unsafe bool TryParseInt64(ReadOnlySpan<char> s, NumberStyles style, NumberFormatInfo info, out long result)
{
NumberBuffer number = default;
result = 0;
@@ -655,7 +655,7 @@ namespace System
return true;
}
- internal unsafe static bool TryParseUInt32(ReadOnlySpan<char> s, NumberStyles style, NumberFormatInfo info, out uint result)
+ internal static unsafe bool TryParseUInt32(ReadOnlySpan<char> s, NumberStyles style, NumberFormatInfo info, out uint result)
{
NumberBuffer number = default;
result = 0;
@@ -682,7 +682,7 @@ namespace System
return true;
}
- internal unsafe static bool TryParseUInt64(ReadOnlySpan<char> s, NumberStyles style, NumberFormatInfo info, out ulong result)
+ internal static unsafe bool TryParseUInt64(ReadOnlySpan<char> s, NumberStyles style, NumberFormatInfo info, out ulong result)
{
NumberBuffer number = default;
result = 0;
@@ -709,7 +709,7 @@ namespace System
return true;
}
- internal unsafe static decimal ParseDecimal(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt)
+ internal static unsafe decimal ParseDecimal(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt)
{
NumberBuffer number = default;
decimal result = 0;
@@ -723,7 +723,7 @@ namespace System
return result;
}
- internal unsafe static double ParseDouble(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt)
+ internal static unsafe double ParseDouble(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt)
{
NumberBuffer number = default;
double d = 0;
@@ -734,15 +734,15 @@ namespace System
//Check the three with which we're concerned and rethrow if it's not one of
//those strings.
ReadOnlySpan<char> sTrim = value.Trim();
- if (StringSpanHelpers.Equals(sTrim, numfmt.PositiveInfinitySymbol))
+ if (sTrim.EqualsOrdinal(numfmt.PositiveInfinitySymbol))
{
return double.PositiveInfinity;
}
- if (StringSpanHelpers.Equals(sTrim, numfmt.NegativeInfinitySymbol))
+ if (sTrim.EqualsOrdinal(numfmt.NegativeInfinitySymbol))
{
return double.NegativeInfinity;
}
- if (StringSpanHelpers.Equals(sTrim, numfmt.NaNSymbol))
+ if (sTrim.EqualsOrdinal(numfmt.NaNSymbol))
{
return double.NaN;
}
@@ -757,7 +757,7 @@ namespace System
return d;
}
- internal unsafe static float ParseSingle(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt)
+ internal static unsafe float ParseSingle(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt)
{
NumberBuffer number = default;
double d = 0;
@@ -768,15 +768,15 @@ namespace System
//Check the three with which we're concerned and rethrow if it's not one of
//those strings.
ReadOnlySpan<char> sTrim = value.Trim();
- if (StringSpanHelpers.Equals(sTrim, numfmt.PositiveInfinitySymbol))
+ if (sTrim.EqualsOrdinal(numfmt.PositiveInfinitySymbol))
{
return float.PositiveInfinity;
}
- if (StringSpanHelpers.Equals(sTrim, numfmt.NegativeInfinitySymbol))
+ if (sTrim.EqualsOrdinal(numfmt.NegativeInfinitySymbol))
{
return float.NegativeInfinity;
}
- if (StringSpanHelpers.Equals(sTrim, numfmt.NaNSymbol))
+ if (sTrim.EqualsOrdinal(numfmt.NaNSymbol))
{
return float.NaN;
}
@@ -795,7 +795,7 @@ namespace System
return castSingle;
}
- internal unsafe static bool TryParseDecimal(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt, out decimal result)
+ internal static unsafe bool TryParseDecimal(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt, out decimal result)
{
NumberBuffer number = default;
result = 0;
@@ -812,7 +812,7 @@ namespace System
return true;
}
- internal unsafe static bool TryParseDouble(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt, out double result)
+ internal static unsafe bool TryParseDouble(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt, out double result)
{
NumberBuffer number = default;
result = 0;
@@ -829,7 +829,7 @@ namespace System
return true;
}
- internal unsafe static bool TryParseSingle(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt, out float result)
+ internal static unsafe bool TryParseSingle(ReadOnlySpan<char> value, NumberStyles options, NumberFormatInfo numfmt, out float result)
{
NumberBuffer number = default;
result = 0;
@@ -897,7 +897,7 @@ namespace System
return true;
}
- private unsafe static char* MatchChars(char* p, string str)
+ private static unsafe char* MatchChars(char* p, string str)
{
fixed (char* stringPointer = str)
{
@@ -905,7 +905,7 @@ namespace System
}
}
- private unsafe static char* MatchChars(char* p, char* str)
+ private static unsafe char* MatchChars(char* p, char* str)
{
Debug.Assert(p != null && str != null);
diff --git a/src/System.Numerics.Vectors/src/System/Numerics/ConstantHelper.cs b/src/Common/src/CoreLib/System/Numerics/ConstantHelper.cs
index ea32ed3803..ea32ed3803 100644
--- a/src/System.Numerics.Vectors/src/System/Numerics/ConstantHelper.cs
+++ b/src/Common/src/CoreLib/System/Numerics/ConstantHelper.cs
diff --git a/src/System.Numerics.Vectors/src/System/Numerics/ConstantHelper.tt b/src/Common/src/CoreLib/System/Numerics/ConstantHelper.tt
index 4b1c677574..4b1c677574 100644
--- a/src/System.Numerics.Vectors/src/System/Numerics/ConstantHelper.tt
+++ b/src/Common/src/CoreLib/System/Numerics/ConstantHelper.tt
diff --git a/src/System.Numerics.Vectors/src/System/Numerics/GenerationConfig.ttinclude b/src/Common/src/CoreLib/System/Numerics/GenerationConfig.ttinclude
index cdd9c95213..a21188e51b 100644
--- a/src/System.Numerics.Vectors/src/System/Numerics/GenerationConfig.ttinclude
+++ b/src/Common/src/CoreLib/System/Numerics/GenerationConfig.ttinclude
@@ -1,5 +1,6 @@
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Collections.Generic" #>
+<#@ import namespace="System.Text" #>
<#+
/* This file includes static data used as compilation configuration for the rest of the code generation.
It is shared here to ensure that all generated code compiles with the same constants and configurations. */
@@ -144,4 +145,29 @@
string keyword = (type == allTypes.ToArray()[0]) ? "if" : "else if";
return string.Format("{0} (typeof(T) == typeof({1}))", keyword, type.Name);
}
-#> \ No newline at end of file
+
+ public string MakeTypeComparisonCondition(Type type)
+ {
+ return string.Format("(typeof(T) == typeof({0}))", type.Name);
+ }
+
+ public string GenerateIfConditionAllTypes(IEnumerable<Type> allTypes)
+ {
+ StringBuilder sbuilder = new StringBuilder();
+ bool firstTime = true;
+ foreach (var type in allTypes)
+ {
+ if (firstTime)
+ {
+ sbuilder.Append("if (").Append(MakeTypeComparisonCondition(type));
+ firstTime = false;
+ }
+ else
+ {
+ sbuilder.AppendLine().Append(" || ").Append(MakeTypeComparisonCondition(type));
+ }
+ }
+ sbuilder.Append(")");
+ return sbuilder.ToString();
+ }
+#>
diff --git a/src/System.Numerics.Vectors/src/System/Numerics/Register.cs b/src/Common/src/CoreLib/System/Numerics/Register.cs
index a27e922b9d..a27e922b9d 100644
--- a/src/System.Numerics.Vectors/src/System/Numerics/Register.cs
+++ b/src/Common/src/CoreLib/System/Numerics/Register.cs
diff --git a/src/System.Numerics.Vectors/src/System/Numerics/Register.tt b/src/Common/src/CoreLib/System/Numerics/Register.tt
index a9de3b9748..a9de3b9748 100644
--- a/src/System.Numerics.Vectors/src/System/Numerics/Register.tt
+++ b/src/Common/src/CoreLib/System/Numerics/Register.tt
diff --git a/src/System.Numerics.Vectors/src/System/Numerics/Vector.cs b/src/Common/src/CoreLib/System/Numerics/Vector.cs
index 9e4eb703aa..42f86d9297 100644
--- a/src/System.Numerics.Vectors/src/System/Numerics/Vector.cs
+++ b/src/Common/src/CoreLib/System/Numerics/Vector.cs
@@ -2,9 +2,13 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+#if netcoreapp
+using Internal.Runtime.CompilerServices;
+#endif
using System.Globalization;
using System.Numerics.Hashing;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using System.Text;
namespace System.Numerics
@@ -38,6 +42,7 @@ namespace System.Numerics
/// This struct only supports numerical types. This type is intended to be used as a building block for vectorizing
/// large algorithms. This type is immutable, individual elements cannot be modified.
/// </summary>
+ [Intrinsic]
public struct Vector<T> : IEquatable<Vector<T>>, IFormattable where T : struct
{
#region Fields
@@ -48,9 +53,9 @@ namespace System.Numerics
/// <summary>
/// Returns the number of elements stored in the vector. This value is hardware dependent.
/// </summary>
- [JitIntrinsic]
public static int Count
{
+ [Intrinsic]
get
{
return s_count;
@@ -61,19 +66,31 @@ namespace System.Numerics
/// <summary>
/// Returns a vector containing all zeroes.
/// </summary>
- [JitIntrinsic]
- public static Vector<T> Zero { get { return zero; } }
- private static readonly Vector<T> zero = new Vector<T>(GetZeroValue());
+ public static Vector<T> Zero
+ {
+ [Intrinsic]
+ get
+ {
+ return s_zero;
+ }
+ }
+ private static readonly Vector<T> s_zero = new Vector<T>();
/// <summary>
/// Returns a vector containing all ones.
/// </summary>
- [JitIntrinsic]
- public static Vector<T> One { get { return one; } }
- private static readonly Vector<T> one = new Vector<T>(GetOneValue());
+ public static Vector<T> One
+ {
+ [Intrinsic]
+ get
+ {
+ return s_one;
+ }
+ }
+ private static readonly Vector<T> s_one = new Vector<T>(GetOneValue());
- internal static Vector<T> AllOnes { get { return allOnes; } }
- private static readonly Vector<T> allOnes = new Vector<T>(GetAllBitsSetValue());
+ internal static Vector<T> AllOnes { get { return s_allOnes; } }
+ private static readonly Vector<T> s_allOnes = new Vector<T>(GetAllBitsSetValue());
#endregion Static Members
#region Static Initialization
@@ -145,7 +162,7 @@ namespace System.Numerics
/// <summary>
/// Constructs a vector whose components are all <code>value</code>
/// </summary>
- [JitIntrinsic]
+ [Intrinsic]
public unsafe Vector(T value)
: this()
{
@@ -356,7 +373,7 @@ namespace System.Numerics
/// <summary>
/// Constructs a vector from the given array. The size of the given array must be at least Vector'T.Count.
/// </summary>
- [JitIntrinsic]
+ [Intrinsic]
public unsafe Vector(T[] values) : this(values, 0) { }
/// <summary>
@@ -373,7 +390,7 @@ namespace System.Numerics
}
if (index < 0 || (values.Length - index) < Count)
{
- throw new IndexOutOfRangeException();
+ throw new IndexOutOfRangeException(SR.Format(SR.Arg_InsufficientNumberOfElements, Vector<T>.Count, nameof(values)));
}
if (Vector.IsHardwareAccelerated)
@@ -750,6 +767,37 @@ namespace System.Numerics
{
this.register = existingRegister;
}
+
+#if netcoreapp
+ /// <summary>
+ /// Constructs a vector from the given span. The span must contain at least Vector'T.Count elements.
+ /// </summary>
+ public Vector(Span<T> values)
+ : this()
+ {
+ if ((typeof(T) == typeof(Byte))
+ || (typeof(T) == typeof(SByte))
+ || (typeof(T) == typeof(UInt16))
+ || (typeof(T) == typeof(Int16))
+ || (typeof(T) == typeof(UInt32))
+ || (typeof(T) == typeof(Int32))
+ || (typeof(T) == typeof(UInt64))
+ || (typeof(T) == typeof(Int64))
+ || (typeof(T) == typeof(Single))
+ || (typeof(T) == typeof(Double)))
+ {
+ if (values.Length < Count)
+ {
+ throw new IndexOutOfRangeException(SR.Format(SR.Arg_InsufficientNumberOfElements, Vector<T>.Count, nameof(values)));
+ }
+ this = Unsafe.ReadUnaligned<Vector<T>>(ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(values)));
+ }
+ else
+ {
+ throw new NotSupportedException(SR.Arg_TypeNotSupported);
+ }
+ }
+#endif
#endregion Constructors
#region Public Instance Methods
@@ -759,7 +807,7 @@ namespace System.Numerics
/// <param name="destination">The destination array which the values are copied into</param>
/// <exception cref="ArgumentNullException">If the destination array is null</exception>
/// <exception cref="ArgumentException">If number of elements in source vector is greater than those available in destination array</exception>
- [JitIntrinsic]
+ [Intrinsic]
public unsafe void CopyTo(T[] destination)
{
CopyTo(destination, 0);
@@ -773,7 +821,7 @@ namespace System.Numerics
/// <exception cref="ArgumentNullException">If the destination array is null</exception>
/// <exception cref="ArgumentOutOfRangeException">If index is greater than end of the array or index is less than zero</exception>
/// <exception cref="ArgumentException">If number of elements in source vector is greater than those available in destination array</exception>
- [JitIntrinsic]
+ [Intrinsic]
public unsafe void CopyTo(T[] destination, int startIndex)
{
if (destination == null)
@@ -1047,9 +1095,9 @@ namespace System.Numerics
/// <summary>
/// Returns the element at the given index.
/// </summary>
- [JitIntrinsic]
public unsafe T this[int index]
{
+ [Intrinsic]
get
{
if (index >= Count || index < 0)
@@ -1153,7 +1201,7 @@ namespace System.Numerics
/// </summary>
/// <param name="other">The vector to compare this instance to.</param>
/// <returns>True if the other vector is equal to this instance; False otherwise.</returns>
- [JitIntrinsic]
+ [Intrinsic]
public bool Equals(Vector<T> other)
{
if (Vector.IsHardwareAccelerated)
@@ -2639,7 +2687,7 @@ namespace System.Numerics
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The resultant vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe Vector<T> operator &(Vector<T> left, Vector<T> right)
{
Vector<T> result = new Vector<T>();
@@ -2670,7 +2718,7 @@ namespace System.Numerics
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The resultant vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe Vector<T> operator |(Vector<T> left, Vector<T> right)
{
Vector<T> result = new Vector<T>();
@@ -2701,7 +2749,7 @@ namespace System.Numerics
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The resultant vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe Vector<T> operator ^(Vector<T> left, Vector<T> right)
{
Vector<T> result = new Vector<T>();
@@ -2734,7 +2782,7 @@ namespace System.Numerics
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static Vector<T> operator ~(Vector<T> value)
{
- return allOnes ^ value;
+ return s_allOnes ^ value;
}
#endregion Bitwise Operators
@@ -2770,7 +2818,7 @@ namespace System.Numerics
/// </summary>
/// <param name="value">The source vector</param>
/// <returns>The reinterpreted vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
public static explicit operator Vector<Byte>(Vector<T> value)
{
return new Vector<Byte>(ref value.register);
@@ -2782,7 +2830,7 @@ namespace System.Numerics
/// <param name="value">The source vector</param>
/// <returns>The reinterpreted vector.</returns>
[CLSCompliant(false)]
- [JitIntrinsic]
+ [Intrinsic]
public static explicit operator Vector<SByte>(Vector<T> value)
{
return new Vector<SByte>(ref value.register);
@@ -2794,7 +2842,7 @@ namespace System.Numerics
/// <param name="value">The source vector</param>
/// <returns>The reinterpreted vector.</returns>
[CLSCompliant(false)]
- [JitIntrinsic]
+ [Intrinsic]
public static explicit operator Vector<UInt16>(Vector<T> value)
{
return new Vector<UInt16>(ref value.register);
@@ -2805,7 +2853,7 @@ namespace System.Numerics
/// </summary>
/// <param name="value">The source vector</param>
/// <returns>The reinterpreted vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
public static explicit operator Vector<Int16>(Vector<T> value)
{
return new Vector<Int16>(ref value.register);
@@ -2817,7 +2865,7 @@ namespace System.Numerics
/// <param name="value">The source vector</param>
/// <returns>The reinterpreted vector.</returns>
[CLSCompliant(false)]
- [JitIntrinsic]
+ [Intrinsic]
public static explicit operator Vector<UInt32>(Vector<T> value)
{
return new Vector<UInt32>(ref value.register);
@@ -2828,7 +2876,7 @@ namespace System.Numerics
/// </summary>
/// <param name="value">The source vector</param>
/// <returns>The reinterpreted vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
public static explicit operator Vector<Int32>(Vector<T> value)
{
return new Vector<Int32>(ref value.register);
@@ -2840,7 +2888,7 @@ namespace System.Numerics
/// <param name="value">The source vector</param>
/// <returns>The reinterpreted vector.</returns>
[CLSCompliant(false)]
- [JitIntrinsic]
+ [Intrinsic]
public static explicit operator Vector<UInt64>(Vector<T> value)
{
return new Vector<UInt64>(ref value.register);
@@ -2851,7 +2899,7 @@ namespace System.Numerics
/// </summary>
/// <param name="value">The source vector</param>
/// <returns>The reinterpreted vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
public static explicit operator Vector<Int64>(Vector<T> value)
{
return new Vector<Int64>(ref value.register);
@@ -2862,7 +2910,7 @@ namespace System.Numerics
/// </summary>
/// <param name="value">The source vector</param>
/// <returns>The reinterpreted vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
public static explicit operator Vector<Single>(Vector<T> value)
{
return new Vector<Single>(ref value.register);
@@ -2873,7 +2921,7 @@ namespace System.Numerics
/// </summary>
/// <param name="value">The source vector</param>
/// <returns>The reinterpreted vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
public static explicit operator Vector<Double>(Vector<T> value)
{
return new Vector<Double>(ref value.register);
@@ -2882,7 +2930,7 @@ namespace System.Numerics
#endregion Conversions
#region Internal Comparison Methods
- [JitIntrinsic]
+ [Intrinsic]
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
internal static unsafe Vector<T> Equals(Vector<T> left, Vector<T> right)
{
@@ -3099,7 +3147,7 @@ namespace System.Numerics
}
}
- [JitIntrinsic]
+ [Intrinsic]
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
internal static unsafe Vector<T> LessThan(Vector<T> left, Vector<T> right)
{
@@ -3316,7 +3364,7 @@ namespace System.Numerics
}
}
- [JitIntrinsic]
+ [Intrinsic]
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
internal static unsafe Vector<T> GreaterThan(Vector<T> left, Vector<T> right)
{
@@ -3533,19 +3581,19 @@ namespace System.Numerics
}
}
- [JitIntrinsic]
+ [Intrinsic]
internal static Vector<T> GreaterThanOrEqual(Vector<T> left, Vector<T> right)
{
return Equals(left, right) | GreaterThan(left, right);
}
- [JitIntrinsic]
+ [Intrinsic]
internal static Vector<T> LessThanOrEqual(Vector<T> left, Vector<T> right)
{
return Equals(left, right) | LessThan(left, right);
}
- [JitIntrinsic]
+ [Intrinsic]
internal static Vector<T> ConditionalSelect(Vector<T> condition, Vector<T> left, Vector<T> right)
{
return (left & condition) | (Vector.AndNot(right, condition));
@@ -3553,7 +3601,7 @@ namespace System.Numerics
#endregion Comparison Methods
#region Internal Math Methods
- [JitIntrinsic]
+ [Intrinsic]
internal static unsafe Vector<T> Abs(Vector<T> value)
{
if (typeof(T) == typeof(Byte))
@@ -3702,7 +3750,7 @@ namespace System.Numerics
}
}
- [JitIntrinsic]
+ [Intrinsic]
internal static unsafe Vector<T> Min(Vector<T> left, Vector<T> right)
{
if (Vector.IsHardwareAccelerated)
@@ -3918,7 +3966,7 @@ namespace System.Numerics
}
}
- [JitIntrinsic]
+ [Intrinsic]
internal static unsafe Vector<T> Max(Vector<T> left, Vector<T> right)
{
if (Vector.IsHardwareAccelerated)
@@ -4134,12 +4182,12 @@ namespace System.Numerics
}
}
- [JitIntrinsic]
+ [Intrinsic]
internal static T DotProduct(Vector<T> left, Vector<T> right)
{
if (Vector.IsHardwareAccelerated)
{
- T product = GetZeroValue();
+ T product = default;
for (int g = 0; g < Count; g++)
{
product = ScalarAdd(product, ScalarMultiply(left[g], right[g]));
@@ -4271,7 +4319,7 @@ namespace System.Numerics
}
}
- [JitIntrinsic]
+ [Intrinsic]
internal static unsafe Vector<T> SquareRoot(Vector<T> value)
{
if (Vector.IsHardwareAccelerated)
@@ -4832,65 +4880,6 @@ namespace System.Numerics
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
- private static T GetZeroValue()
- {
- if (typeof(T) == typeof(Byte))
- {
- Byte value = 0;
- return (T)(object)value;
- }
- else if (typeof(T) == typeof(SByte))
- {
- SByte value = 0;
- return (T)(object)value;
- }
- else if (typeof(T) == typeof(UInt16))
- {
- UInt16 value = 0;
- return (T)(object)value;
- }
- else if (typeof(T) == typeof(Int16))
- {
- Int16 value = 0;
- return (T)(object)value;
- }
- else if (typeof(T) == typeof(UInt32))
- {
- UInt32 value = 0;
- return (T)(object)value;
- }
- else if (typeof(T) == typeof(Int32))
- {
- Int32 value = 0;
- return (T)(object)value;
- }
- else if (typeof(T) == typeof(UInt64))
- {
- UInt64 value = 0;
- return (T)(object)value;
- }
- else if (typeof(T) == typeof(Int64))
- {
- Int64 value = 0;
- return (T)(object)value;
- }
- else if (typeof(T) == typeof(Single))
- {
- Single value = 0;
- return (T)(object)value;
- }
- else if (typeof(T) == typeof(Double))
- {
- Double value = 0;
- return (T)(object)value;
- }
- else
- {
- throw new NotSupportedException(SR.Arg_TypeNotSupported);
- }
- }
-
- [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
private static T GetOneValue()
{
if (typeof(T) == typeof(Byte))
@@ -5000,6 +4989,7 @@ namespace System.Numerics
#endregion
}
+ [Intrinsic]
public static partial class Vector
{
#region Widen/Narrow
@@ -5010,7 +5000,7 @@ namespace System.Numerics
/// <param name="high">The second output vector, whose elements will contain the widened elements from higher indices in the source vector.</param>
/// </summary>
[CLSCompliant(false)]
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe void Widen(Vector<Byte> source, out Vector<UInt16> low, out Vector<UInt16> high)
{
int elements = Vector<Byte>.Count;
@@ -5036,7 +5026,7 @@ namespace System.Numerics
/// <param name="high">The second output vector, whose elements will contain the widened elements from higher indices in the source vector.</param>
/// </summary>
[CLSCompliant(false)]
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe void Widen(Vector<UInt16> source, out Vector<UInt32> low, out Vector<UInt32> high)
{
int elements = Vector<UInt16>.Count;
@@ -5062,7 +5052,7 @@ namespace System.Numerics
/// <param name="high">The second output vector, whose elements will contain the widened elements from higher indices in the source vector.</param>
/// </summary>
[CLSCompliant(false)]
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe void Widen(Vector<UInt32> source, out Vector<UInt64> low, out Vector<UInt64> high)
{
int elements = Vector<UInt32>.Count;
@@ -5088,7 +5078,7 @@ namespace System.Numerics
/// <param name="high">The second output vector, whose elements will contain the widened elements from higher indices in the source vector.</param>
/// </summary>
[CLSCompliant(false)]
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe void Widen(Vector<SByte> source, out Vector<Int16> low, out Vector<Int16> high)
{
int elements = Vector<SByte>.Count;
@@ -5113,7 +5103,7 @@ namespace System.Numerics
/// <param name="low">The first output vector, whose elements will contain the widened elements from lower indices in the source vector.</param>
/// <param name="high">The second output vector, whose elements will contain the widened elements from higher indices in the source vector.</param>
/// </summary>
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe void Widen(Vector<Int16> source, out Vector<Int32> low, out Vector<Int32> high)
{
int elements = Vector<Int16>.Count;
@@ -5138,7 +5128,7 @@ namespace System.Numerics
/// <param name="low">The first output vector, whose elements will contain the widened elements from lower indices in the source vector.</param>
/// <param name="high">The second output vector, whose elements will contain the widened elements from higher indices in the source vector.</param>
/// </summary>
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe void Widen(Vector<Int32> source, out Vector<Int64> low, out Vector<Int64> high)
{
int elements = Vector<Int32>.Count;
@@ -5163,7 +5153,7 @@ namespace System.Numerics
/// <param name="low">The first output vector, whose elements will contain the widened elements from lower indices in the source vector.</param>
/// <param name="high">The second output vector, whose elements will contain the widened elements from higher indices in the source vector.</param>
/// </summary>
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe void Widen(Vector<Single> source, out Vector<Double> low, out Vector<Double> high)
{
int elements = Vector<Single>.Count;
@@ -5189,7 +5179,7 @@ namespace System.Numerics
/// <returns>A Vector{Byte} containing elements narrowed from the source vectors.</returns>
/// </summary>
[CLSCompliant(false)]
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe Vector<Byte> Narrow(Vector<UInt16> low, Vector<UInt16> high)
{
unchecked
@@ -5216,7 +5206,7 @@ namespace System.Numerics
/// <returns>A Vector{UInt16} containing elements narrowed from the source vectors.</returns>
/// </summary>
[CLSCompliant(false)]
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe Vector<UInt16> Narrow(Vector<UInt32> low, Vector<UInt32> high)
{
unchecked
@@ -5243,7 +5233,7 @@ namespace System.Numerics
/// <returns>A Vector{UInt32} containing elements narrowed from the source vectors.</returns>
/// </summary>
[CLSCompliant(false)]
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe Vector<UInt32> Narrow(Vector<UInt64> low, Vector<UInt64> high)
{
unchecked
@@ -5270,7 +5260,7 @@ namespace System.Numerics
/// <returns>A Vector{SByte} containing elements narrowed from the source vectors.</returns>
/// </summary>
[CLSCompliant(false)]
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe Vector<SByte> Narrow(Vector<Int16> low, Vector<Int16> high)
{
unchecked
@@ -5296,7 +5286,7 @@ namespace System.Numerics
/// <param name="high">The second source vector, whose elements become the higher-index elements of the return value.</param>
/// <returns>A Vector{Int16} containing elements narrowed from the source vectors.</returns>
/// </summary>
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe Vector<Int16> Narrow(Vector<Int32> low, Vector<Int32> high)
{
unchecked
@@ -5322,7 +5312,7 @@ namespace System.Numerics
/// <param name="high">The second source vector, whose elements become the higher-index elements of the return value.</param>
/// <returns>A Vector{Int32} containing elements narrowed from the source vectors.</returns>
/// </summary>
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe Vector<Int32> Narrow(Vector<Int64> low, Vector<Int64> high)
{
unchecked
@@ -5348,7 +5338,7 @@ namespace System.Numerics
/// <param name="high">The second source vector, whose elements become the higher-index elements of the return value.</param>
/// <returns>A Vector{Single} containing elements narrowed from the source vectors.</returns>
/// </summary>
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe Vector<Single> Narrow(Vector<Double> low, Vector<Double> high)
{
unchecked
@@ -5376,7 +5366,7 @@ namespace System.Numerics
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The converted vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe Vector<Single> ConvertToSingle(Vector<Int32> value)
{
unchecked
@@ -5398,7 +5388,7 @@ namespace System.Numerics
/// <param name="value">The source vector.</param>
/// <returns>The converted vector.</returns>
[CLSCompliant(false)]
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe Vector<Single> ConvertToSingle(Vector<UInt32> value)
{
unchecked
@@ -5419,7 +5409,7 @@ namespace System.Numerics
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The converted vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe Vector<Double> ConvertToDouble(Vector<Int64> value)
{
unchecked
@@ -5441,7 +5431,7 @@ namespace System.Numerics
/// <param name="value">The source vector.</param>
/// <returns>The converted vector.</returns>
[CLSCompliant(false)]
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe Vector<Double> ConvertToDouble(Vector<UInt64> value)
{
unchecked
@@ -5462,7 +5452,7 @@ namespace System.Numerics
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The converted vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe Vector<Int32> ConvertToInt32(Vector<Single> value)
{
unchecked
@@ -5484,7 +5474,7 @@ namespace System.Numerics
/// <param name="value">The source vector.</param>
/// <returns>The converted vector.</returns>
[CLSCompliant(false)]
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe Vector<UInt32> ConvertToUInt32(Vector<Single> value)
{
unchecked
@@ -5505,7 +5495,7 @@ namespace System.Numerics
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The converted vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe Vector<Int64> ConvertToInt64(Vector<Double> value)
{
unchecked
@@ -5527,7 +5517,7 @@ namespace System.Numerics
/// <param name="value">The source vector.</param>
/// <returns>The converted vector.</returns>
[CLSCompliant(false)]
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe Vector<UInt64> ConvertToUInt64(Vector<Double> value)
{
unchecked
diff --git a/src/System.Numerics.Vectors/src/System/Numerics/Vector.tt b/src/Common/src/CoreLib/System/Numerics/Vector.tt
index 1bb47f5c1a..d7622466b7 100644
--- a/src/System.Numerics.Vectors/src/System/Numerics/Vector.tt
+++ b/src/Common/src/CoreLib/System/Numerics/Vector.tt
@@ -7,9 +7,13 @@
<#@ import namespace="System.Runtime.InteropServices" #>
<#@ include file="GenerationConfig.ttinclude" #><# GenerateCopyrightHeader(); #>
+#if netcoreapp
+using Internal.Runtime.CompilerServices;
+#endif
using System.Globalization;
using System.Numerics.Hashing;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using System.Text;
namespace System.Numerics
@@ -43,6 +47,7 @@ namespace System.Numerics
/// This struct only supports numerical types. This type is intended to be used as a building block for vectorizing
/// large algorithms. This type is immutable, individual elements cannot be modified.
/// </summary>
+ [Intrinsic]
public struct Vector<T> : IEquatable<Vector<T>>, IFormattable where T : struct
{
#region Fields
@@ -53,9 +58,9 @@ namespace System.Numerics
/// <summary>
/// Returns the number of elements stored in the vector. This value is hardware dependent.
/// </summary>
- [JitIntrinsic]
public static int Count
{
+ [Intrinsic]
get
{
return s_count;
@@ -66,19 +71,31 @@ namespace System.Numerics
/// <summary>
/// Returns a vector containing all zeroes.
/// </summary>
- [JitIntrinsic]
- public static Vector<T> Zero { get { return zero; } }
- private static readonly Vector<T> zero = new Vector<T>(GetZeroValue());
+ public static Vector<T> Zero
+ {
+ [Intrinsic]
+ get
+ {
+ return s_zero;
+ }
+ }
+ private static readonly Vector<T> s_zero = new Vector<T>();
/// <summary>
/// Returns a vector containing all ones.
/// </summary>
- [JitIntrinsic]
- public static Vector<T> One { get { return one; } }
- private static readonly Vector<T> one = new Vector<T>(GetOneValue());
+ public static Vector<T> One
+ {
+ [Intrinsic]
+ get
+ {
+ return s_one;
+ }
+ }
+ private static readonly Vector<T> s_one = new Vector<T>(GetOneValue());
- internal static Vector<T> AllOnes { get { return allOnes; } }
- private static readonly Vector<T> allOnes = new Vector<T>(GetAllBitsSetValue());
+ internal static Vector<T> AllOnes { get { return s_allOnes; } }
+ private static readonly Vector<T> s_allOnes = new Vector<T>(GetAllBitsSetValue());
#endregion Static Members
#region Static Initialization
@@ -120,7 +137,7 @@ namespace System.Numerics
/// <summary>
/// Constructs a vector whose components are all <code>value</code>
/// </summary>
- [JitIntrinsic]
+ [Intrinsic]
public unsafe Vector(T value)
: this()
{
@@ -168,7 +185,7 @@ namespace System.Numerics
/// <summary>
/// Constructs a vector from the given array. The size of the given array must be at least Vector'T.Count.
/// </summary>
- [JitIntrinsic]
+ [Intrinsic]
public unsafe Vector(T[] values) : this(values, 0) { }
/// <summary>
@@ -185,7 +202,7 @@ namespace System.Numerics
}
if (index < 0 || (values.Length - index) < Count)
{
- throw new IndexOutOfRangeException();
+ throw new IndexOutOfRangeException(SR.Format(SR.Arg_InsufficientNumberOfElements, Vector<T>.Count, nameof(values)));
}
if (Vector.IsHardwareAccelerated)
@@ -270,6 +287,28 @@ namespace System.Numerics
{
this.register = existingRegister;
}
+
+#if netcoreapp
+ /// <summary>
+ /// Constructs a vector from the given span. The span must contain at least Vector'T.Count elements.
+ /// </summary>
+ public Vector(Span<T> values)
+ : this()
+ {
+ <#=GenerateIfConditionAllTypes(supportedTypes)#>
+ {
+ if (values.Length < Count)
+ {
+ throw new IndexOutOfRangeException(SR.Format(SR.Arg_InsufficientNumberOfElements, Vector<T>.Count, nameof(values)));
+ }
+ this = Unsafe.ReadUnaligned<Vector<T>>(ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(values)));
+ }
+ else
+ {
+ throw new NotSupportedException(SR.Arg_TypeNotSupported);
+ }
+ }
+#endif
#endregion Constructors
#region Public Instance Methods
@@ -279,7 +318,7 @@ namespace System.Numerics
/// <param name="destination">The destination array which the values are copied into</param>
/// <exception cref="ArgumentNullException">If the destination array is null</exception>
/// <exception cref="ArgumentException">If number of elements in source vector is greater than those available in destination array</exception>
- [JitIntrinsic]
+ [Intrinsic]
public unsafe void CopyTo(T[] destination)
{
CopyTo(destination, 0);
@@ -293,7 +332,7 @@ namespace System.Numerics
/// <exception cref="ArgumentNullException">If the destination array is null</exception>
/// <exception cref="ArgumentOutOfRangeException">If index is greater than end of the array or index is less than zero</exception>
/// <exception cref="ArgumentException">If number of elements in source vector is greater than those available in destination array</exception>
- [JitIntrinsic]
+ [Intrinsic]
public unsafe void CopyTo(T[] destination, int startIndex)
{
if (destination == null)
@@ -359,9 +398,9 @@ namespace System.Numerics
/// <summary>
/// Returns the element at the given index.
/// </summary>
- [JitIntrinsic]
public unsafe T this[int index]
{
+ [Intrinsic]
get
{
if (index >= Count || index < 0)
@@ -408,7 +447,7 @@ namespace System.Numerics
/// </summary>
/// <param name="other">The vector to compare this instance to.</param>
/// <returns>True if the other vector is equal to this instance; False otherwise.</returns>
- [JitIntrinsic]
+ [Intrinsic]
public bool Equals(Vector<T> other)
{
if (Vector.IsHardwareAccelerated)
@@ -891,7 +930,7 @@ namespace System.Numerics
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The resultant vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe Vector<T> operator &(Vector<T> left, Vector<T> right)
{
Vector<T> result = new Vector<T>();
@@ -922,7 +961,7 @@ namespace System.Numerics
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The resultant vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe Vector<T> operator |(Vector<T> left, Vector<T> right)
{
Vector<T> result = new Vector<T>();
@@ -953,7 +992,7 @@ namespace System.Numerics
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The resultant vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe Vector<T> operator ^(Vector<T> left, Vector<T> right)
{
Vector<T> result = new Vector<T>();
@@ -986,7 +1025,7 @@ namespace System.Numerics
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
public static Vector<T> operator ~(Vector<T> value)
{
- return allOnes ^ value;
+ return s_allOnes ^ value;
}
#endregion Bitwise Operators
@@ -1033,7 +1072,7 @@ namespace System.Numerics
<#
}
#>
- [JitIntrinsic]
+ [Intrinsic]
public static explicit operator Vector<<#=type.Name#>>(Vector<T> value)
{
return new Vector<<#=type.Name#>>(ref value.register);
@@ -1045,7 +1084,7 @@ namespace System.Numerics
#endregion Conversions
#region Internal Comparison Methods
- [JitIntrinsic]
+ [Intrinsic]
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
internal static unsafe Vector<T> Equals(Vector<T> left, Vector<T> right)
{
@@ -1099,7 +1138,7 @@ namespace System.Numerics
}
}
- [JitIntrinsic]
+ [Intrinsic]
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
internal static unsafe Vector<T> LessThan(Vector<T> left, Vector<T> right)
{
@@ -1153,7 +1192,7 @@ namespace System.Numerics
}
}
- [JitIntrinsic]
+ [Intrinsic]
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
internal static unsafe Vector<T> GreaterThan(Vector<T> left, Vector<T> right)
{
@@ -1207,19 +1246,19 @@ namespace System.Numerics
}
}
- [JitIntrinsic]
+ [Intrinsic]
internal static Vector<T> GreaterThanOrEqual(Vector<T> left, Vector<T> right)
{
return Equals(left, right) | GreaterThan(left, right);
}
- [JitIntrinsic]
+ [Intrinsic]
internal static Vector<T> LessThanOrEqual(Vector<T> left, Vector<T> right)
{
return Equals(left, right) | LessThan(left, right);
}
- [JitIntrinsic]
+ [Intrinsic]
internal static Vector<T> ConditionalSelect(Vector<T> condition, Vector<T> left, Vector<T> right)
{
return (left & condition) | (Vector.AndNot(right, condition));
@@ -1227,7 +1266,7 @@ namespace System.Numerics
#endregion Comparison Methods
#region Internal Math Methods
- [JitIntrinsic]
+ [Intrinsic]
internal static unsafe Vector<T> Abs(Vector<T> value)
{
<#
@@ -1295,7 +1334,7 @@ namespace System.Numerics
}
}
- [JitIntrinsic]
+ [Intrinsic]
internal static unsafe Vector<T> Min(Vector<T> left, Vector<T> right)
{
if (Vector.IsHardwareAccelerated)
@@ -1348,7 +1387,7 @@ namespace System.Numerics
}
}
- [JitIntrinsic]
+ [Intrinsic]
internal static unsafe Vector<T> Max(Vector<T> left, Vector<T> right)
{
if (Vector.IsHardwareAccelerated)
@@ -1401,12 +1440,12 @@ namespace System.Numerics
}
}
- [JitIntrinsic]
+ [Intrinsic]
internal static T DotProduct(Vector<T> left, Vector<T> right)
{
if (Vector.IsHardwareAccelerated)
{
- T product = GetZeroValue();
+ T product = default;
for (int g = 0; g < Count; g++)
{
product = ScalarAdd(product, ScalarMultiply(left[g], right[g]));
@@ -1441,7 +1480,7 @@ namespace System.Numerics
}
}
- [JitIntrinsic]
+ [Intrinsic]
internal static unsafe Vector<T> SquareRoot(Vector<T> value)
{
if (Vector.IsHardwareAccelerated)
@@ -1629,26 +1668,6 @@ namespace System.Numerics
}
[MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
- private static T GetZeroValue()
- {
-<# foreach (Type type in supportedTypes)
- {
-#>
- <#=GenerateIfStatementHeader(type)#>
- {
- <#=type.Name#> value = 0;
- return (T)(object)value;
- }
-<#
- }
-#>
- else
- {
- throw new NotSupportedException(SR.Arg_TypeNotSupported);
- }
- }
-
- [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
private static T GetOneValue()
{
<# foreach (Type type in supportedTypes)
@@ -1689,6 +1708,7 @@ namespace System.Numerics
#endregion
}
+ [Intrinsic]
public static partial class Vector
{
#region Widen/Narrow
@@ -1710,7 +1730,7 @@ namespace System.Numerics
<#
}
#>
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe void Widen(Vector<<#=type.Name#>> source, out Vector<<#=widenTarget.Name#>> low, out Vector<<#=widenTarget.Name#>> high)
{
int elements = Vector<<#=type.Name#>>.Count;
@@ -1750,7 +1770,7 @@ namespace System.Numerics
<#
}
#>
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe Vector<<#=narrowTarget.Name#>> Narrow(Vector<<#=narrowSource.Name#>> low, Vector<<#=narrowSource.Name#>> high)
{
unchecked
@@ -1792,7 +1812,7 @@ namespace System.Numerics
<#
}
#>
- [JitIntrinsic]
+ [Intrinsic]
public static unsafe Vector<<#=pair.Value.Name#>> ConvertTo<#=pair.Value.Name#>(Vector<<#=pair.Key.Name#>> value)
{
unchecked
diff --git a/src/System.Numerics.Vectors/src/System/Numerics/Vector_Operations.cs b/src/Common/src/CoreLib/System/Numerics/Vector_Operations.cs
index 4fbcb1670f..b69b058be9 100644
--- a/src/System.Numerics.Vectors/src/System/Numerics/Vector_Operations.cs
+++ b/src/Common/src/CoreLib/System/Numerics/Vector_Operations.cs
@@ -524,9 +524,9 @@ namespace System.Numerics
/// <summary>
/// Returns whether or not vector operations are subject to hardware acceleration through JIT intrinsic support.
/// </summary>
- [JitIntrinsic]
public static bool IsHardwareAccelerated
{
+ [Intrinsic]
get
{
return false;
diff --git a/src/Common/src/CoreLib/System/OverflowException.cs b/src/Common/src/CoreLib/System/OverflowException.cs
index 963825b350..e28dcb87ed 100644
--- a/src/Common/src/CoreLib/System/OverflowException.cs
+++ b/src/Common/src/CoreLib/System/OverflowException.cs
@@ -6,7 +6,7 @@
**
**
**
-** Purpose: Exception class for Arthimatic Overflows.
+** Purpose: Exception class for Arithmetic Overflows.
**
**
=============================================================================*/
diff --git a/src/Common/src/CoreLib/System/ReadOnlyMemory.cs b/src/Common/src/CoreLib/System/ReadOnlyMemory.cs
index de423bbd06..5385ceca76 100644
--- a/src/Common/src/CoreLib/System/ReadOnlyMemory.cs
+++ b/src/Common/src/CoreLib/System/ReadOnlyMemory.cs
@@ -20,8 +20,8 @@ namespace System
/// Represents a contiguous region of memory, similar to <see cref="ReadOnlySpan{T}"/>.
/// Unlike <see cref="ReadOnlySpan{T}"/>, it is not a byref-like type.
/// </summary>
- [DebuggerDisplay("{DebuggerDisplay,nq}")]
[DebuggerTypeProxy(typeof(MemoryDebugView<>))]
+ [DebuggerDisplay("{ToString(),raw}")]
public readonly struct ReadOnlyMemory<T>
{
// NOTE: With the current implementation, Memory<T> and ReadOnlyMemory<T> must have the same layout,
@@ -40,14 +40,16 @@ namespace System
/// Creates a new memory over the entirety of the target array.
/// </summary>
/// <param name="array">The target array.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
- /// reference (Nothing in Visual Basic).</exception>
+ /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
/// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlyMemory(T[] array)
{
if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
+ {
+ this = default;
+ return; // returns default
+ }
_object = array;
_index = 0;
@@ -61,8 +63,7 @@ namespace System
/// <param name="array">The target array.</param>
/// <param name="start">The index at which to begin the memory.</param>
/// <param name="length">The number of items in the memory.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
- /// reference (Nothing in Visual Basic).</exception>
+ /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
/// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// Thrown when the specified <paramref name="start"/> or end index is not in the range (&lt;0 or &gt;=Length).
@@ -71,7 +72,12 @@ namespace System
public ReadOnlyMemory(T[] array, int start, int length)
{
if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
+ {
+ if (start != 0 || length != 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+ this = default;
+ return; // returns default
+ }
if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
ThrowHelper.ThrowArgumentOutOfRangeException();
@@ -93,9 +99,6 @@ namespace System
_length = length;
}
- //Debugger Display = {T[length]}
- private string DebuggerDisplay => string.Format("{{{0}[{1}]}}", typeof(T).Name, _length);
-
/// <summary>
/// Defines an implicit conversion of an array to a <see cref="ReadOnlyMemory{T}"/>
/// </summary>
@@ -104,7 +107,7 @@ namespace System
/// <summary>
/// Defines an implicit conversion of a <see cref="ArraySegment{T}"/> to a <see cref="ReadOnlyMemory{T}"/>
/// </summary>
- public static implicit operator ReadOnlyMemory<T>(ArraySegment<T> arraySegment) => new ReadOnlyMemory<T>(arraySegment.Array, arraySegment.Offset, arraySegment.Count);
+ public static implicit operator ReadOnlyMemory<T>(ArraySegment<T> segment) => new ReadOnlyMemory<T>(segment.Array, segment.Offset, segment.Count);
/// <summary>
/// Returns an empty <see cref="ReadOnlyMemory{T}"/>
@@ -122,6 +125,19 @@ namespace System
public bool IsEmpty => _length == 0;
/// <summary>
+ /// For <see cref="ReadOnlyMemory{Char}"/>, returns a new instance of string that represents the characters pointed to by the memory.
+ /// Otherwise, returns a <see cref="string"/> with the name of the type and the number of elements.
+ /// </summary>
+ public override string ToString()
+ {
+ if (typeof(T) == typeof(char))
+ {
+ return (_object is string str) ? str.Substring(_index, _length) : Span.ToString();
+ }
+ return string.Format("System.ReadOnlyMemory<{0}>[{1}]", typeof(T).Name, _length);
+ }
+
+ /// <summary>
/// Forms a slice out of the given memory, beginning at 'start'.
/// </summary>
/// <param name="start">The index at which to begin this slice.</param>
@@ -212,10 +228,44 @@ namespace System
/// <param name="destination">The span to copy items into.</param>
public bool TryCopyTo(Memory<T> destination) => Span.TryCopyTo(destination.Span);
- /// <summary>Creates a handle for the memory.</summary>
+ /// <summary>
+ /// Creates a handle for the memory.
+ /// The GC will not move the array until the returned <see cref="MemoryHandle"/>
+ /// is disposed, enabling taking and using the memory's address.
+ /// </summary>
+ public unsafe MemoryHandle Pin()
+ {
+ if (_index < 0)
+ {
+ return ((OwnedMemory<T>)_object).Pin((_index & RemoveOwnedFlagBitMask) * Unsafe.SizeOf<T>());
+ }
+ else if (typeof(T) == typeof(char) && _object is string s)
+ {
+ GCHandle handle = GCHandle.Alloc(s, GCHandleType.Pinned);
+#if FEATURE_PORTABLE_SPAN
+ void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
+#else
+ void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref s.GetRawStringData()), _index);
+#endif // FEATURE_PORTABLE_SPAN
+ return new MemoryHandle(null, pointer, handle);
+ }
+ else if (_object is T[] array)
+ {
+ var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
+#if FEATURE_PORTABLE_SPAN
+ void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
+#else
+ void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index);
+#endif // FEATURE_PORTABLE_SPAN
+ return new MemoryHandle(null, pointer, handle);
+ }
+ return default;
+ }
+
+ /// <summary>[Obsolete, use Pin()] Creates a handle for the memory.</summary>
/// <param name="pin">
/// If pin is true, the GC will not move the array until the returned <see cref="MemoryHandle"/>
- /// is disposed, enabling the memory's address can be taken and used.
+ /// is disposed, enabling taking and using the memory's address.
/// </param>
public unsafe MemoryHandle Retain(bool pin = false)
{
diff --git a/src/Common/src/CoreLib/System/ReadOnlySpan.Fast.cs b/src/Common/src/CoreLib/System/ReadOnlySpan.Fast.cs
new file mode 100644
index 0000000000..9bf3f211a8
--- /dev/null
+++ b/src/Common/src/CoreLib/System/ReadOnlySpan.Fast.cs
@@ -0,0 +1,270 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Runtime.Versioning;
+using Internal.Runtime.CompilerServices;
+
+#pragma warning disable 0809 //warning CS0809: Obsolete member 'Span<T>.Equals(object)' overrides non-obsolete member 'object.Equals(object)'
+
+#if BIT64
+using nuint = System.UInt64;
+#else
+using nuint = System.UInt32;
+#endif
+
+namespace System
+{
+ /// <summary>
+ /// ReadOnlySpan represents a contiguous region of arbitrary memory. Unlike arrays, it can point to either managed
+ /// or native memory, or to memory allocated on the stack. It is type- and memory-safe.
+ /// </summary>
+ [DebuggerTypeProxy(typeof(SpanDebugView<>))]
+ [DebuggerDisplay("{ToString(),raw}")]
+ [NonVersionable]
+ public readonly ref partial struct ReadOnlySpan<T>
+ {
+ /// <summary>A byref or a native ptr.</summary>
+ internal readonly ByReference<T> _pointer;
+ /// <summary>The number of elements this ReadOnlySpan contains.</summary>
+#if PROJECTN
+ [Bound]
+#endif
+ private readonly int _length;
+
+ /// <summary>
+ /// Creates a new read-only span over the entirety of the target array.
+ /// </summary>
+ /// <param name="array">The target array.</param>
+ /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
+ /// reference (Nothing in Visual Basic).</exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ReadOnlySpan(T[] array)
+ {
+ if (array == null)
+ {
+ this = default;
+ return; // returns default
+ }
+
+ _pointer = new ByReference<T>(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()));
+ _length = array.Length;
+ }
+
+ /// <summary>
+ /// Creates a new read-only span over the portion of the target array beginning
+ /// at 'start' index and ending at 'end' index (exclusive).
+ /// </summary>
+ /// <param name="array">The target array.</param>
+ /// <param name="start">The index at which to begin the read-only span.</param>
+ /// <param name="length">The number of items in the read-only span.</param>
+ /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
+ /// reference (Nothing in Visual Basic).</exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> or end index is not in the range (&lt;0 or &gt;=Length).
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ReadOnlySpan(T[] array, int start, int length)
+ {
+ if (array == null)
+ {
+ if (start != 0 || length != 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+ this = default;
+ return; // returns default
+ }
+ if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ _pointer = new ByReference<T>(ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), start));
+ _length = length;
+ }
+
+ /// <summary>
+ /// Creates a new read-only span over the target unmanaged buffer. Clearly this
+ /// is quite dangerous, because we are creating arbitrarily typed T's
+ /// out of a void*-typed block of memory. And the length is not checked.
+ /// But if this creation is correct, then all subsequent uses are correct.
+ /// </summary>
+ /// <param name="pointer">An unmanaged pointer to memory.</param>
+ /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
+ /// <exception cref="System.ArgumentException">
+ /// Thrown when <typeparamref name="T"/> is reference type or contains pointers and hence cannot be stored in unmanaged memory.
+ /// </exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="length"/> is negative.
+ /// </exception>
+ [CLSCompliant(false)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public unsafe ReadOnlySpan(void* pointer, int length)
+ {
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
+ ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
+ if (length < 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ _pointer = new ByReference<T>(ref Unsafe.As<byte, T>(ref *(byte*)pointer));
+ _length = length;
+ }
+
+ // Constructor for internal use only.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal ReadOnlySpan(ref T ptr, int length)
+ {
+ Debug.Assert(length >= 0);
+
+ _pointer = new ByReference<T>(ref ptr);
+ _length = length;
+ }
+
+ /// <summary>
+ /// Returns the specified element of the read-only span.
+ /// </summary>
+ /// <param name="index"></param>
+ /// <returns></returns>
+ /// <exception cref="System.IndexOutOfRangeException">
+ /// Thrown when index less than 0 or index greater than or equal to Length
+ /// </exception>
+ public ref readonly T this[int index]
+ {
+#if PROJECTN
+ [BoundsChecking]
+ get
+ {
+ return ref Unsafe.Add(ref _pointer.Value, index);
+ }
+#else
+ [Intrinsic]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [NonVersionable]
+ get
+ {
+ if ((uint)index >= (uint)_length)
+ ThrowHelper.ThrowIndexOutOfRangeException();
+ return ref Unsafe.Add(ref _pointer.Value, index);
+ }
+#endif
+ }
+
+ /// <summary>
+ /// Copies the contents of this read-only span into destination span. If the source
+ /// and destinations overlap, this method behaves as if the original values in
+ /// a temporary location before the destination is overwritten.
+ ///
+ /// <param name="destination">The span to copy items into.</param>
+ /// <exception cref="System.ArgumentException">
+ /// Thrown when the destination Span is shorter than the source Span.
+ /// </exception>
+ /// </summary>
+ public void CopyTo(Span<T> destination)
+ {
+ // Using "if (!TryCopyTo(...))" results in two branches: one for the length
+ // check, and one for the result of TryCopyTo. Since these checks are equivalent,
+ // we can optimize by performing the check once ourselves then calling Memmove directly.
+
+ if ((uint)_length <= (uint)destination.Length)
+ {
+ Buffer.Memmove(ref destination._pointer.Value, ref _pointer.Value, (nuint)_length);
+ }
+ else
+ {
+ ThrowHelper.ThrowArgumentException_DestinationTooShort();
+ }
+ }
+
+ /// Copies the contents of this read-only span into destination span. If the source
+ /// and destinations overlap, this method behaves as if the original values in
+ /// a temporary location before the destination is overwritten.
+ /// </summary>
+ /// <returns>If the destination span is shorter than the source span, this method
+ /// return false and no data is written to the destination.</returns>
+ /// <param name="destination">The span to copy items into.</param>
+ public bool TryCopyTo(Span<T> destination)
+ {
+ bool retVal = false;
+ if ((uint)_length <= (uint)destination.Length)
+ {
+ Buffer.Memmove(ref destination._pointer.Value, ref _pointer.Value, (nuint)_length);
+ retVal = true;
+ }
+ return retVal;
+ }
+
+ /// <summary>
+ /// Returns true if left and right point at the same memory and have the same length. Note that
+ /// this does *not* check to see if the *contents* are equal.
+ /// </summary>
+ public static bool operator ==(ReadOnlySpan<T> left, ReadOnlySpan<T> right)
+ {
+ return left._length == right._length && Unsafe.AreSame<T>(ref left._pointer.Value, ref right._pointer.Value);
+ }
+
+ /// <summary>
+ /// For <see cref="ReadOnlySpan{Char}"/>, returns a new instance of string that represents the characters pointed to by the span.
+ /// Otherwise, returns a <see cref="String"/> with the name of the type and the number of elements.
+ /// </summary>
+ public override string ToString()
+ {
+ if (typeof(T) == typeof(char))
+ {
+ unsafe
+ {
+ fixed (char* src = &Unsafe.As<T, char>(ref _pointer.Value))
+ return new string(src, 0, _length);
+ }
+ }
+ return string.Format("System.ReadOnlySpan<{0}>[{1}]", typeof(T).Name, _length);
+ }
+
+ /// <summary>
+ /// Forms a slice out of the given read-only span, beginning at 'start'.
+ /// </summary>
+ /// <param name="start">The index at which to begin this slice.</param>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> index is not in range (&lt;0 or &gt;=Length).
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ReadOnlySpan<T> Slice(int start)
+ {
+ if ((uint)start > (uint)_length)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ return new ReadOnlySpan<T>(ref Unsafe.Add(ref _pointer.Value, start), _length - start);
+ }
+
+ /// <summary>
+ /// Forms a slice out of the given read-only span, beginning at 'start', of given length
+ /// </summary>
+ /// <param name="start">The index at which to begin this slice.</param>
+ /// <param name="length">The desired length for the slice (exclusive).</param>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> or end index is not in range (&lt;0 or &gt;=Length).
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ReadOnlySpan<T> Slice(int start, int length)
+ {
+ if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ return new ReadOnlySpan<T>(ref Unsafe.Add(ref _pointer.Value, start), length);
+ }
+
+ /// <summary>
+ /// Copies the contents of this read-only span into a new array. This heap
+ /// allocates, so should generally be avoided, however it is sometimes
+ /// necessary to bridge the gap with APIs written in terms of arrays.
+ /// </summary>
+ public T[] ToArray()
+ {
+ if (_length == 0)
+ return Array.Empty<T>();
+
+ var destination = new T[_length];
+ Buffer.Memmove(ref Unsafe.As<byte, T>(ref destination.GetRawSzArrayData()), ref _pointer.Value, (nuint)_length);
+ return destination;
+ }
+ }
+}
diff --git a/src/Common/src/CoreLib/System/ReadOnlySpan.cs b/src/Common/src/CoreLib/System/ReadOnlySpan.cs
index 1854df40fa..14b33e23f2 100644
--- a/src/Common/src/CoreLib/System/ReadOnlySpan.cs
+++ b/src/Common/src/CoreLib/System/ReadOnlySpan.cs
@@ -5,8 +5,9 @@
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;
+#if !FEATURE_PORTABLE_SPAN
using System.Runtime.Versioning;
-using Internal.Runtime.CompilerServices;
+#endif // !FEATURE_PORTABLE_SPAN
#pragma warning disable 0809 //warning CS0809: Obsolete member 'Span<T>.Equals(object)' overrides non-obsolete member 'object.Equals(object)'
@@ -17,128 +18,17 @@ namespace System
/// or native memory, or to memory allocated on the stack. It is type- and memory-safe.
/// </summary>
[DebuggerTypeProxy(typeof(SpanDebugView<>))]
- [DebuggerDisplay("{DebuggerDisplay,nq}")]
- [NonVersionable]
- public readonly ref struct ReadOnlySpan<T>
+ [DebuggerDisplay("{ToString(),raw}")]
+ public readonly ref partial struct ReadOnlySpan<T>
{
- /// <summary>A byref or a native ptr.</summary>
- internal readonly ByReference<T> _pointer;
- /// <summary>The number of elements this ReadOnlySpan contains.</summary>
-#if PROJECTN
- [Bound]
-#endif
- private readonly int _length;
-
- /// <summary>
- /// Creates a new read-only span over the entirety of the target array.
- /// </summary>
- /// <param name="array">The target array.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
- /// reference (Nothing in Visual Basic).</exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ReadOnlySpan(T[] array)
- {
- if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
-
- _pointer = new ByReference<T>(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()));
- _length = array.Length;
- }
-
- /// <summary>
- /// Creates a new read-only span over the portion of the target array beginning
- /// at 'start' index and ending at 'end' index (exclusive).
- /// </summary>
- /// <param name="array">The target array.</param>
- /// <param name="start">The index at which to begin the read-only span.</param>
- /// <param name="length">The number of items in the read-only span.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
- /// reference (Nothing in Visual Basic).</exception>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> or end index is not in the range (&lt;0 or &gt;=Length).
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ReadOnlySpan(T[] array, int start, int length)
- {
- if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
- ThrowHelper.ThrowArgumentOutOfRangeException();
-
- _pointer = new ByReference<T>(ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), start));
- _length = length;
- }
-
- /// <summary>
- /// Creates a new read-only span over the target unmanaged buffer. Clearly this
- /// is quite dangerous, because we are creating arbitrarily typed T's
- /// out of a void*-typed block of memory. And the length is not checked.
- /// But if this creation is correct, then all subsequent uses are correct.
- /// </summary>
- /// <param name="pointer">An unmanaged pointer to memory.</param>
- /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when <typeparamref name="T"/> is reference type or contains pointers and hence cannot be stored in unmanaged memory.
- /// </exception>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="length"/> is negative.
- /// </exception>
- [CLSCompliant(false)]
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public unsafe ReadOnlySpan(void* pointer, int length)
- {
- if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
- ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
- if (length < 0)
- ThrowHelper.ThrowArgumentOutOfRangeException();
-
- _pointer = new ByReference<T>(ref Unsafe.As<byte, T>(ref *(byte*)pointer));
- _length = length;
- }
-
- /// <summary>
- /// Create a new read-only span over a portion of a regular managed object. This can be useful
- /// if part of a managed object represents a "fixed array." This is dangerous because neither the
- /// <paramref name="length"/> is checked, nor <paramref name="obj"/> being null, nor the fact that
- /// "rawPointer" actually lies within <paramref name="obj"/>.
- /// </summary>
- /// <param name="obj">The managed object that contains the data to span over.</param>
- /// <param name="objectData">A reference to data within that object.</param>
- /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- [EditorBrowsable(EditorBrowsableState.Never)]
- public static ReadOnlySpan<T> DangerousCreate(object obj, ref T objectData, int length) => new ReadOnlySpan<T>(ref objectData, length);
-
- // Constructor for internal use only.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal ReadOnlySpan(ref T ptr, int length)
- {
- Debug.Assert(length >= 0);
-
- _pointer = new ByReference<T>(ref ptr);
- _length = length;
- }
-
- //Debugger Display = {T[length]}
- private string DebuggerDisplay => string.Format("{{{0}[{1}]}}", typeof(T).Name, _length);
-
- /// <summary>
- /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element
- /// would have been stored. Such a reference can be used for pinning but must never be dereferenced.
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal ref readonly T DangerousGetPinnableReference()
- {
- return ref _pointer.Value;
- }
-
/// <summary>
/// The number of items in the read-only span.
/// </summary>
public int Length
{
+#if !FEATURE_PORTABLE_SPAN
[NonVersionable]
+#endif // !FEATURE_PORTABLE_SPAN
get
{
return _length;
@@ -150,84 +40,14 @@ namespace System
/// </summary>
public bool IsEmpty
{
+#if !FEATURE_PORTABLE_SPAN
[NonVersionable]
+#endif // !FEATURE_PORTABLE_SPAN
get
{
return _length == 0;
}
}
-
- /// <summary>
- /// Returns the specified element of the read-only span.
- /// </summary>
- /// <param name="index"></param>
- /// <returns></returns>
- /// <exception cref="System.IndexOutOfRangeException">
- /// Thrown when index less than 0 or index greater than or equal to Length
- /// </exception>
-
- public ref readonly T this[int index]
- {
-#if PROJECTN
- [BoundsChecking]
- get
- {
- return ref Unsafe.Add(ref _pointer.Value, index);
- }
-#else
- [Intrinsic]
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- [NonVersionable]
- get
- {
- if ((uint)index >= (uint)_length)
- ThrowHelper.ThrowIndexOutOfRangeException();
- return ref Unsafe.Add(ref _pointer.Value, index);
- }
-#endif
- }
-
- /// <summary>
- /// Copies the contents of this read-only span into destination span. If the source
- /// and destinations overlap, this method behaves as if the original values in
- /// a temporary location before the destination is overwritten.
- ///
- /// <param name="destination">The span to copy items into.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when the destination Span is shorter than the source Span.
- /// </exception>
- /// </summary>
- public void CopyTo(Span<T> destination)
- {
- if (!TryCopyTo(destination))
- ThrowHelper.ThrowArgumentException_DestinationTooShort();
- }
-
- /// Copies the contents of this read-only span into destination span. If the source
- /// and destinations overlap, this method behaves as if the original values in
- /// a temporary location before the destination is overwritten.
- /// </summary>
- /// <returns>If the destination span is shorter than the source span, this method
- /// return false and no data is written to the destination.</returns>
- /// <param name="destination">The span to copy items into.</param>
- public bool TryCopyTo(Span<T> destination)
- {
- if ((uint)_length > (uint)destination.Length)
- return false;
-
- Span.CopyTo<T>(ref destination.DangerousGetPinnableReference(), ref _pointer.Value, _length);
- return true;
- }
-
- /// <summary>
- /// Returns true if left and right point at the same memory and have the same length. Note that
- /// this does *not* check to see if the *contents* are equal.
- /// </summary>
- public static bool operator ==(ReadOnlySpan<T> left, ReadOnlySpan<T> right)
- {
- return left._length == right._length && Unsafe.AreSame<T>(ref left._pointer.Value, ref right._pointer.Value);
- }
-
/// <summary>
/// Returns false if left and right point at the same memory and have the same length. Note that
/// this does *not* check to see if the *contents* are equal.
@@ -263,61 +83,13 @@ namespace System
/// <summary>
/// Defines an implicit conversion of an array to a <see cref="ReadOnlySpan{T}"/>
/// </summary>
- public static implicit operator ReadOnlySpan<T>(T[] array) => array != null ? new ReadOnlySpan<T>(array) : default;
+ public static implicit operator ReadOnlySpan<T>(T[] array) => new ReadOnlySpan<T>(array);
/// <summary>
/// Defines an implicit conversion of a <see cref="ArraySegment{T}"/> to a <see cref="ReadOnlySpan{T}"/>
/// </summary>
- public static implicit operator ReadOnlySpan<T>(ArraySegment<T> arraySegment)
- => arraySegment.Array != null ? new ReadOnlySpan<T>(arraySegment.Array, arraySegment.Offset, arraySegment.Count) : default;
-
- /// <summary>
- /// Forms a slice out of the given read-only span, beginning at 'start'.
- /// </summary>
- /// <param name="start">The index at which to begin this slice.</param>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> index is not in range (&lt;0 or &gt;=Length).
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ReadOnlySpan<T> Slice(int start)
- {
- if ((uint)start > (uint)_length)
- ThrowHelper.ThrowArgumentOutOfRangeException();
-
- return new ReadOnlySpan<T>(ref Unsafe.Add(ref _pointer.Value, start), _length - start);
- }
-
- /// <summary>
- /// Forms a slice out of the given read-only span, beginning at 'start', of given length
- /// </summary>
- /// <param name="start">The index at which to begin this slice.</param>
- /// <param name="length">The desired length for the slice (exclusive).</param>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> or end index is not in range (&lt;0 or &gt;=Length).
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ReadOnlySpan<T> Slice(int start, int length)
- {
- if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
- ThrowHelper.ThrowArgumentOutOfRangeException();
-
- return new ReadOnlySpan<T>(ref Unsafe.Add(ref _pointer.Value, start), length);
- }
-
- /// <summary>
- /// Copies the contents of this read-only span into a new array. This heap
- /// allocates, so should generally be avoided, however it is sometimes
- /// necessary to bridge the gap with APIs written in terms of arrays.
- /// </summary>
- public T[] ToArray()
- {
- if (_length == 0)
- return Array.Empty<T>();
-
- var destination = new T[_length];
- Span.CopyTo<T>(ref Unsafe.As<byte, T>(ref destination.GetRawSzArrayData()), ref _pointer.Value, _length);
- return destination;
- }
+ public static implicit operator ReadOnlySpan<T>(ArraySegment<T> segment)
+ => new ReadOnlySpan<T>(segment.Array, segment.Offset, segment.Count);
/// <summary>
/// Returns a 0-length read-only span whose base is the null pointer.
diff --git a/src/Common/src/CoreLib/System/Reflection/SignatureTypeExtensions.cs b/src/Common/src/CoreLib/System/Reflection/SignatureTypeExtensions.cs
index 5847944f14..9247132546 100644
--- a/src/Common/src/CoreLib/System/Reflection/SignatureTypeExtensions.cs
+++ b/src/Common/src/CoreLib/System/Reflection/SignatureTypeExtensions.cs
@@ -9,6 +9,7 @@ using System.Diagnostics;
namespace System.Reflection
{
#if CORERT
+ [System.Runtime.CompilerServices.ReflectionBlocked]
public // Needs to be public so that Reflection.Core can see it.
#else
internal
diff --git a/src/Common/src/CoreLib/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs b/src/Common/src/CoreLib/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs
index b5ecd7924c..0e1220d119 100644
--- a/src/Common/src/CoreLib/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs
+++ b/src/Common/src/CoreLib/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs
@@ -8,6 +8,108 @@ using System.Threading.Tasks;
namespace System.Runtime.CompilerServices
{
+ /// <summary>Represents a builder for asynchronous methods that return a <see cref="ValueTask"/>.</summary>
+ [StructLayout(LayoutKind.Auto)]
+ public struct AsyncValueTaskMethodBuilder
+ {
+ /// <summary>The <see cref="AsyncTaskMethodBuilder"/> to which most operations are delegated.</summary>
+ private AsyncTaskMethodBuilder _methodBuilder; // mutable struct; do not make it readonly
+ /// <summary>true if completed synchronously and successfully; otherwise, false.</summary>
+ private bool _haveResult;
+ /// <summary>true if the builder should be used for setting/getting the result; otherwise, false.</summary>
+ private bool _useBuilder;
+
+ /// <summary>Creates an instance of the <see cref="AsyncValueTaskMethodBuilder"/> struct.</summary>
+ /// <returns>The initialized instance.</returns>
+ public static AsyncValueTaskMethodBuilder Create() =>
+#if CORERT
+ // corert's AsyncTaskMethodBuilder.Create() currently does additional debugger-related
+ // work, so we need to delegate to it.
+ new AsyncValueTaskMethodBuilder() { _methodBuilder = AsyncTaskMethodBuilder.Create() };
+#else
+ // _methodBuilder should be initialized to AsyncTaskMethodBuilder.Create(), but on coreclr
+ // that Create() is a nop, so we can just return the default here.
+ default;
+#endif
+
+ /// <summary>Begins running the builder with the associated state machine.</summary>
+ /// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
+ /// <param name="stateMachine">The state machine instance, passed by reference.</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine =>
+ // will provide the right ExecutionContext semantics
+#if netstandard
+ _methodBuilder.Start(ref stateMachine);
+#else
+ AsyncMethodBuilderCore.Start(ref stateMachine);
+#endif
+
+ /// <summary>Associates the builder with the specified state machine.</summary>
+ /// <param name="stateMachine">The state machine instance to associate with the builder.</param>
+ public void SetStateMachine(IAsyncStateMachine stateMachine) => _methodBuilder.SetStateMachine(stateMachine);
+
+ /// <summary>Marks the task as successfully completed.</summary>
+ public void SetResult()
+ {
+ if (_useBuilder)
+ {
+ _methodBuilder.SetResult();
+ }
+ else
+ {
+ _haveResult = true;
+ }
+ }
+
+ /// <summary>Marks the task as failed and binds the specified exception to the task.</summary>
+ /// <param name="exception">The exception to bind to the task.</param>
+ public void SetException(Exception exception) => _methodBuilder.SetException(exception);
+
+ /// <summary>Gets the task for this builder.</summary>
+ public ValueTask Task
+ {
+ get
+ {
+ if (_haveResult)
+ {
+ return default;
+ }
+ else
+ {
+ _useBuilder = true;
+ return new ValueTask(_methodBuilder.Task);
+ }
+ }
+ }
+
+ /// <summary>Schedules the state machine to proceed to the next action when the specified awaiter completes.</summary>
+ /// <typeparam name="TAwaiter">The type of the awaiter.</typeparam>
+ /// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
+ /// <param name="awaiter">The awaiter.</param>
+ /// <param name="stateMachine">The state machine.</param>
+ public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
+ where TAwaiter : INotifyCompletion
+ where TStateMachine : IAsyncStateMachine
+ {
+ _useBuilder = true;
+ _methodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine);
+ }
+
+ /// <summary>Schedules the state machine to proceed to the next action when the specified awaiter completes.</summary>
+ /// <typeparam name="TAwaiter">The type of the awaiter.</typeparam>
+ /// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
+ /// <param name="awaiter">The awaiter.</param>
+ /// <param name="stateMachine">The state machine.</param>
+ [SecuritySafeCritical]
+ public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
+ where TAwaiter : ICriticalNotifyCompletion
+ where TStateMachine : IAsyncStateMachine
+ {
+ _useBuilder = true;
+ _methodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
+ }
+ }
+
/// <summary>Represents a builder for asynchronous methods that returns a <see cref="ValueTask{TResult}"/>.</summary>
/// <typeparam name="TResult">The type of the result.</typeparam>
[StructLayout(LayoutKind.Auto)]
@@ -32,14 +134,20 @@ namespace System.Runtime.CompilerServices
#else
// _methodBuilder should be initialized to AsyncTaskMethodBuilder<TResult>.Create(), but on coreclr
// that Create() is a nop, so we can just return the default here.
- default(AsyncValueTaskMethodBuilder<TResult>);
+ default;
#endif
/// <summary>Begins running the builder with the associated state machine.</summary>
/// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
/// <param name="stateMachine">The state machine instance, passed by reference.</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine =>
- _methodBuilder.Start(ref stateMachine); // will provide the right ExecutionContext semantics
+ // will provide the right ExecutionContext semantics
+#if netstandard
+ _methodBuilder.Start(ref stateMachine);
+#else
+ AsyncMethodBuilderCore.Start(ref stateMachine);
+#endif
/// <summary>Associates the builder with the specified state machine.</summary>
/// <param name="stateMachine">The state machine instance to associate with the builder.</param>
diff --git a/src/Common/src/CoreLib/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs b/src/Common/src/CoreLib/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs
index 4e8ce691be..5994531981 100644
--- a/src/Common/src/CoreLib/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs
+++ b/src/Common/src/CoreLib/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs
@@ -5,9 +5,115 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
+using System.Threading.Tasks.Sources;
+
+#if !netstandard
+using Internal.Runtime.CompilerServices;
+#endif
namespace System.Runtime.CompilerServices
{
+ /// <summary>Provides an awaitable type that enables configured awaits on a <see cref="ValueTask"/>.</summary>
+ [StructLayout(LayoutKind.Auto)]
+ public readonly struct ConfiguredValueTaskAwaitable
+ {
+ /// <summary>The wrapped <see cref="Task"/>.</summary>
+ private readonly ValueTask _value;
+
+ /// <summary>Initializes the awaitable.</summary>
+ /// <param name="value">The wrapped <see cref="ValueTask"/>.</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal ConfiguredValueTaskAwaitable(ValueTask value) => _value = value;
+
+ /// <summary>Returns an awaiter for this <see cref="ConfiguredValueTaskAwaitable"/> instance.</summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ConfiguredValueTaskAwaiter GetAwaiter() => new ConfiguredValueTaskAwaiter(_value);
+
+ /// <summary>Provides an awaiter for a <see cref="ConfiguredValueTaskAwaitable"/>.</summary>
+ [StructLayout(LayoutKind.Auto)]
+ public readonly struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion
+#if CORECLR
+ , IValueTaskAwaiter
+#endif
+ {
+ /// <summary>The value being awaited.</summary>
+ private readonly ValueTask _value;
+
+ /// <summary>Initializes the awaiter.</summary>
+ /// <param name="value">The value to be awaited.</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal ConfiguredValueTaskAwaiter(ValueTask value) => _value = value;
+
+ /// <summary>Gets whether the <see cref="ConfiguredValueTaskAwaitable"/> has completed.</summary>
+ public bool IsCompleted
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _value.IsCompleted;
+ }
+
+ /// <summary>Gets the result of the ValueTask.</summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [StackTraceHidden]
+ public void GetResult() => _value.ThrowIfCompletedUnsuccessfully();
+
+ /// <summary>Schedules the continuation action for the <see cref="ConfiguredValueTaskAwaitable"/>.</summary>
+ public void OnCompleted(Action continuation)
+ {
+ if (_value.ObjectIsTask)
+ {
+ _value.UnsafeGetTask().ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().OnCompleted(continuation);
+ }
+ else if (_value._obj != null)
+ {
+ _value.UnsafeGetValueTaskSource().OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token,
+ ValueTaskSourceOnCompletedFlags.FlowExecutionContext |
+ (_value.ContinueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None));
+ }
+ else
+ {
+ ValueTask.CompletedTask.ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().OnCompleted(continuation);
+ }
+ }
+
+ /// <summary>Schedules the continuation action for the <see cref="ConfiguredValueTaskAwaitable"/>.</summary>
+ public void UnsafeOnCompleted(Action continuation)
+ {
+ if (_value.ObjectIsTask)
+ {
+ _value.UnsafeGetTask().ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation);
+ }
+ else if (_value._obj != null)
+ {
+ _value.UnsafeGetValueTaskSource().OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token,
+ _value.ContinueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None);
+ }
+ else
+ {
+ ValueTask.CompletedTask.ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation);
+ }
+ }
+
+#if CORECLR
+ void IValueTaskAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox box)
+ {
+ if (_value.ObjectIsTask)
+ {
+ TaskAwaiter.UnsafeOnCompletedInternal(_value.UnsafeGetTask(), box, _value.ContinueOnCapturedContext);
+ }
+ else if (_value._obj != null)
+ {
+ _value.UnsafeGetValueTaskSource().OnCompleted(ValueTaskAwaiter.s_invokeAsyncStateMachineBox, box, _value._token,
+ _value.ContinueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None);
+ }
+ else
+ {
+ TaskAwaiter.UnsafeOnCompletedInternal(Task.CompletedTask, box, _value.ContinueOnCapturedContext);
+ }
+ }
+#endif
+ }
+ }
+
/// <summary>Provides an awaitable type that enables configured awaits on a <see cref="ValueTask{TResult}"/>.</summary>
/// <typeparam name="TResult">The type of the result produced.</typeparam>
[StructLayout(LayoutKind.Auto)]
@@ -15,74 +121,98 @@ namespace System.Runtime.CompilerServices
{
/// <summary>The wrapped <see cref="ValueTask{TResult}"/>.</summary>
private readonly ValueTask<TResult> _value;
- /// <summary>true to attempt to marshal the continuation back to the original context captured; otherwise, false.</summary>
- private readonly bool _continueOnCapturedContext;
/// <summary>Initializes the awaitable.</summary>
/// <param name="value">The wrapped <see cref="ValueTask{TResult}"/>.</param>
- /// <param name="continueOnCapturedContext">
- /// true to attempt to marshal the continuation back to the original synchronization context captured; otherwise, false.
- /// </param>
- internal ConfiguredValueTaskAwaitable(ValueTask<TResult> value, bool continueOnCapturedContext)
- {
- _value = value;
- _continueOnCapturedContext = continueOnCapturedContext;
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal ConfiguredValueTaskAwaitable(ValueTask<TResult> value) => _value = value;
/// <summary>Returns an awaiter for this <see cref="ConfiguredValueTaskAwaitable{TResult}"/> instance.</summary>
- public ConfiguredValueTaskAwaiter GetAwaiter() =>
- new ConfiguredValueTaskAwaiter(_value, _continueOnCapturedContext);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ConfiguredValueTaskAwaiter GetAwaiter() => new ConfiguredValueTaskAwaiter(_value);
/// <summary>Provides an awaiter for a <see cref="ConfiguredValueTaskAwaitable{TResult}"/>.</summary>
[StructLayout(LayoutKind.Auto)]
- public struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion, IConfiguredValueTaskAwaiter
+ public readonly struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion
+#if CORECLR
+ , IValueTaskAwaiter
+#endif
{
/// <summary>The value being awaited.</summary>
- private ValueTask<TResult> _value; // Methods are called on this; avoid making it readonly so as to avoid unnecessary copies
- /// <summary>The value to pass to ConfigureAwait.</summary>
- internal readonly bool _continueOnCapturedContext;
+ private readonly ValueTask<TResult> _value;
/// <summary>Initializes the awaiter.</summary>
/// <param name="value">The value to be awaited.</param>
- /// <param name="continueOnCapturedContext">The value to pass to ConfigureAwait.</param>
- internal ConfiguredValueTaskAwaiter(ValueTask<TResult> value, bool continueOnCapturedContext)
- {
- _value = value;
- _continueOnCapturedContext = continueOnCapturedContext;
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal ConfiguredValueTaskAwaiter(ValueTask<TResult> value) => _value = value;
/// <summary>Gets whether the <see cref="ConfiguredValueTaskAwaitable{TResult}"/> has completed.</summary>
- public bool IsCompleted => _value.IsCompleted;
+ public bool IsCompleted
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _value.IsCompleted;
+ }
/// <summary>Gets the result of the ValueTask.</summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
[StackTraceHidden]
- public TResult GetResult() =>
- _value._task == null ?
- _value._result :
- _value._task.GetAwaiter().GetResult();
+ public TResult GetResult() => _value.Result;
/// <summary>Schedules the continuation action for the <see cref="ConfiguredValueTaskAwaitable{TResult}"/>.</summary>
- public void OnCompleted(Action continuation) =>
- _value.AsTask().ConfigureAwait(_continueOnCapturedContext).GetAwaiter().OnCompleted(continuation);
+ public void OnCompleted(Action continuation)
+ {
+ if (_value.ObjectIsTask)
+ {
+ _value.UnsafeGetTask().ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().OnCompleted(continuation);
+ }
+ else if (_value._obj != null)
+ {
+ _value.UnsafeGetValueTaskSource().OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token,
+ ValueTaskSourceOnCompletedFlags.FlowExecutionContext |
+ (_value.ContinueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None));
+ }
+ else
+ {
+ ValueTask.CompletedTask.ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().OnCompleted(continuation);
+ }
+ }
/// <summary>Schedules the continuation action for the <see cref="ConfiguredValueTaskAwaitable{TResult}"/>.</summary>
- public void UnsafeOnCompleted(Action continuation) =>
- _value.AsTask().ConfigureAwait(_continueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation);
-
- /// <summary>Gets the task underlying <see cref="_value"/>.</summary>
- internal Task<TResult> AsTask() => _value.AsTask();
+ public void UnsafeOnCompleted(Action continuation)
+ {
+ if (_value.ObjectIsTask)
+ {
+ _value.UnsafeGetTask().ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation);
+ }
+ else if (_value._obj != null)
+ {
+ _value.UnsafeGetValueTaskSource().OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token,
+ _value.ContinueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None);
+ }
+ else
+ {
+ ValueTask.CompletedTask.ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation);
+ }
+ }
- /// <summary>Gets the task underlying the incomplete <see cref="_value"/>.</summary>
- /// <remarks>This method is used when awaiting and IsCompleted returned false; thus we expect the value task to be wrapping a non-null task.</remarks>
- (Task task, bool continueOnCapturedContext) IConfiguredValueTaskAwaiter.GetTask() => (_value.AsTaskExpectNonNull(), _continueOnCapturedContext);
+#if CORECLR
+ void IValueTaskAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox box)
+ {
+ if (_value.ObjectIsTask)
+ {
+ TaskAwaiter.UnsafeOnCompletedInternal(_value.UnsafeGetTask(), box, _value.ContinueOnCapturedContext);
+ }
+ else if (_value._obj != null)
+ {
+ _value.UnsafeGetValueTaskSource().OnCompleted(ValueTaskAwaiter.s_invokeAsyncStateMachineBox, box, _value._token,
+ _value.ContinueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None);
+ }
+ else
+ {
+ TaskAwaiter.UnsafeOnCompletedInternal(Task.CompletedTask, box, _value.ContinueOnCapturedContext);
+ }
+ }
+#endif
}
}
-
- /// <summary>
- /// Internal interface used to enable extract the Task from arbitrary configured ValueTask awaiters.
- /// </summary>
- internal interface IConfiguredValueTaskAwaiter
- {
- (Task task, bool continueOnCapturedContext) GetTask();
- }
}
diff --git a/src/Common/src/CoreLib/System/Runtime/CompilerServices/IntrinsicAttribute.cs b/src/Common/src/CoreLib/System/Runtime/CompilerServices/IntrinsicAttribute.cs
index 381b4c63f7..6bdd91d844 100644
--- a/src/Common/src/CoreLib/System/Runtime/CompilerServices/IntrinsicAttribute.cs
+++ b/src/Common/src/CoreLib/System/Runtime/CompilerServices/IntrinsicAttribute.cs
@@ -6,8 +6,8 @@ namespace System.Runtime.CompilerServices
{
// Calls to methods or references to fields marked with this attribute may be replaced at
// some call sites with jit intrinsic expansions.
- // Types marked with this attribute may be specially treated by the rumtime/compiler.
- [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Field, Inherited = false)]
+ // Types marked with this attribute may be specially treated by the runtime/compiler.
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Field, Inherited = false)]
internal sealed class IntrinsicAttribute : Attribute
{
}
diff --git a/src/Common/src/CoreLib/System/Runtime/CompilerServices/TypeForwardedFromAttribute.cs b/src/Common/src/CoreLib/System/Runtime/CompilerServices/TypeForwardedFromAttribute.cs
index c4a8558243..27dd645755 100644
--- a/src/Common/src/CoreLib/System/Runtime/CompilerServices/TypeForwardedFromAttribute.cs
+++ b/src/Common/src/CoreLib/System/Runtime/CompilerServices/TypeForwardedFromAttribute.cs
@@ -9,6 +9,9 @@ namespace System.Runtime.CompilerServices
{
public TypeForwardedFromAttribute(string assemblyFullName)
{
+ if (string.IsNullOrEmpty(assemblyFullName))
+ throw new ArgumentNullException(nameof(assemblyFullName));
+
AssemblyFullName = assemblyFullName;
}
diff --git a/src/Common/src/CoreLib/System/Runtime/CompilerServices/ValueTaskAwaiter.cs b/src/Common/src/CoreLib/System/Runtime/CompilerServices/ValueTaskAwaiter.cs
index 7bc8b5cc7d..12bac0e828 100644
--- a/src/Common/src/CoreLib/System/Runtime/CompilerServices/ValueTaskAwaiter.cs
+++ b/src/Common/src/CoreLib/System/Runtime/CompilerServices/ValueTaskAwaiter.cs
@@ -4,50 +4,198 @@
using System.Diagnostics;
using System.Threading.Tasks;
+using System.Threading.Tasks.Sources;
namespace System.Runtime.CompilerServices
{
+ /// <summary>Provides an awaiter for a <see cref="ValueTask"/>.</summary>
+ public readonly struct ValueTaskAwaiter : ICriticalNotifyCompletion
+#if CORECLR
+ , IValueTaskAwaiter
+#endif
+ {
+ /// <summary>Shim used to invoke an <see cref="Action"/> passed as the state argument to a <see cref="Action{Object}"/>.</summary>
+ internal static readonly Action<object> s_invokeActionDelegate = state =>
+ {
+ if (!(state is Action action))
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.state);
+ return;
+ }
+
+ action();
+ };
+ /// <summary>The value being awaited.</summary>
+ private readonly ValueTask _value;
+
+ /// <summary>Initializes the awaiter.</summary>
+ /// <param name="value">The value to be awaited.</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal ValueTaskAwaiter(ValueTask value) => _value = value;
+
+ /// <summary>Gets whether the <see cref="ValueTask"/> has completed.</summary>
+ public bool IsCompleted
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _value.IsCompleted;
+ }
+
+ /// <summary>Gets the result of the ValueTask.</summary>
+ [StackTraceHidden]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void GetResult() => _value.ThrowIfCompletedUnsuccessfully();
+
+ /// <summary>Schedules the continuation action for this ValueTask.</summary>
+ public void OnCompleted(Action continuation)
+ {
+ if (_value.ObjectIsTask)
+ {
+ _value.UnsafeGetTask().GetAwaiter().OnCompleted(continuation);
+ }
+ else if (_value._obj != null)
+ {
+ _value.UnsafeGetValueTaskSource().OnCompleted(s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext | ValueTaskSourceOnCompletedFlags.FlowExecutionContext);
+ }
+ else
+ {
+ ValueTask.CompletedTask.GetAwaiter().OnCompleted(continuation);
+ }
+ }
+
+ /// <summary>Schedules the continuation action for this ValueTask.</summary>
+ public void UnsafeOnCompleted(Action continuation)
+ {
+ if (_value.ObjectIsTask)
+ {
+ _value.UnsafeGetTask().GetAwaiter().UnsafeOnCompleted(continuation);
+ }
+ else if (_value._obj != null)
+ {
+ _value.UnsafeGetValueTaskSource().OnCompleted(s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext);
+ }
+ else
+ {
+ ValueTask.CompletedTask.GetAwaiter().UnsafeOnCompleted(continuation);
+ }
+ }
+
+#if CORECLR
+ void IValueTaskAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox box)
+ {
+ if (_value.ObjectIsTask)
+ {
+ TaskAwaiter.UnsafeOnCompletedInternal(_value.UnsafeGetTask(), box, continueOnCapturedContext: true);
+ }
+ else if (_value._obj != null)
+ {
+ _value.UnsafeGetValueTaskSource().OnCompleted(s_invokeAsyncStateMachineBox, box, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext);
+ }
+ else
+ {
+ TaskAwaiter.UnsafeOnCompletedInternal(Task.CompletedTask, box, continueOnCapturedContext: true);
+ }
+ }
+
+ /// <summary>Shim used to invoke <see cref="ITaskCompletionAction.Invoke"/> of the supplied <see cref="IAsyncStateMachineBox"/>.</summary>
+ internal static readonly Action<object> s_invokeAsyncStateMachineBox = state =>
+ {
+ if (!(state is IAsyncStateMachineBox box))
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.state);
+ return;
+ }
+
+ box.MoveNext();
+ };
+#endif
+ }
+
/// <summary>Provides an awaiter for a <see cref="ValueTask{TResult}"/>.</summary>
- public struct ValueTaskAwaiter<TResult> : ICriticalNotifyCompletion, IValueTaskAwaiter
+ public readonly struct ValueTaskAwaiter<TResult> : ICriticalNotifyCompletion
+#if CORECLR
+ , IValueTaskAwaiter
+#endif
{
/// <summary>The value being awaited.</summary>
- private ValueTask<TResult> _value; // Methods are called on this; avoid making it readonly so as to avoid unnecessary copies
+ private readonly ValueTask<TResult> _value;
/// <summary>Initializes the awaiter.</summary>
/// <param name="value">The value to be awaited.</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ValueTaskAwaiter(ValueTask<TResult> value) => _value = value;
/// <summary>Gets whether the <see cref="ValueTask{TResult}"/> has completed.</summary>
- public bool IsCompleted => _value.IsCompleted;
+ public bool IsCompleted
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _value.IsCompleted;
+ }
/// <summary>Gets the result of the ValueTask.</summary>
[StackTraceHidden]
- public TResult GetResult() =>
- _value._task == null ?
- _value._result :
- _value._task.GetAwaiter().GetResult();
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public TResult GetResult() => _value.Result;
/// <summary>Schedules the continuation action for this ValueTask.</summary>
- public void OnCompleted(Action continuation) =>
- _value.AsTask().ConfigureAwait(continueOnCapturedContext: true).GetAwaiter().OnCompleted(continuation);
+ public void OnCompleted(Action continuation)
+ {
+ if (_value.ObjectIsTask)
+ {
+ _value.UnsafeGetTask().GetAwaiter().OnCompleted(continuation);
+ }
+ else if (_value._obj != null)
+ {
+ _value.UnsafeGetValueTaskSource().OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext | ValueTaskSourceOnCompletedFlags.FlowExecutionContext);
+ }
+ else
+ {
+ ValueTask.CompletedTask.GetAwaiter().OnCompleted(continuation);
+ }
+ }
/// <summary>Schedules the continuation action for this ValueTask.</summary>
- public void UnsafeOnCompleted(Action continuation) =>
- _value.AsTask().ConfigureAwait(continueOnCapturedContext: true).GetAwaiter().UnsafeOnCompleted(continuation);
-
- /// <summary>Gets the task underlying <see cref="_value"/>.</summary>
- internal Task<TResult> AsTask() => _value.AsTask();
+ public void UnsafeOnCompleted(Action continuation)
+ {
+ if (_value.ObjectIsTask)
+ {
+ _value.UnsafeGetTask().GetAwaiter().UnsafeOnCompleted(continuation);
+ }
+ else if (_value._obj != null)
+ {
+ _value.UnsafeGetValueTaskSource().OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext);
+ }
+ else
+ {
+ ValueTask.CompletedTask.GetAwaiter().UnsafeOnCompleted(continuation);
+ }
+ }
- /// <summary>Gets the task underlying the incomplete <see cref="_value"/>.</summary>
- /// <remarks>This method is used when awaiting and IsCompleted returned false; thus we expect the value task to be wrapping a non-null task.</remarks>
- Task IValueTaskAwaiter.GetTask() => _value.AsTaskExpectNonNull();
+#if CORECLR
+ void IValueTaskAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox box)
+ {
+ if (_value.ObjectIsTask)
+ {
+ TaskAwaiter.UnsafeOnCompletedInternal(_value.UnsafeGetTask(), box, continueOnCapturedContext: true);
+ }
+ else if (_value._obj != null)
+ {
+ _value.UnsafeGetValueTaskSource().OnCompleted(ValueTaskAwaiter.s_invokeAsyncStateMachineBox, box, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext);
+ }
+ else
+ {
+ TaskAwaiter.UnsafeOnCompletedInternal(Task.CompletedTask, box, continueOnCapturedContext: true);
+ }
+ }
+#endif
}
- /// <summary>
- /// Internal interface used to enable extract the Task from arbitrary ValueTask awaiters.
- /// </summary>>
+#if CORECLR
+ /// <summary>Internal interface used to enable optimizations from <see cref="AsyncTaskMethodBuilder"/> on <see cref="ValueTask"/>.</summary>>
internal interface IValueTaskAwaiter
{
- Task GetTask();
+ /// <summary>Invoked to set <see cref="ITaskCompletionAction.Invoke"/> of the <paramref name="box"/> as the awaiter's continuation.</summary>
+ /// <param name="box">The box object.</param>
+ void AwaitUnsafeOnCompleted(IAsyncStateMachineBox box);
}
+#endif
}
diff --git a/src/Common/src/CoreLib/System/Runtime/InteropServices/MemoryMarshal.Fast.cs b/src/Common/src/CoreLib/System/Runtime/InteropServices/MemoryMarshal.Fast.cs
new file mode 100644
index 0000000000..80ae450b51
--- /dev/null
+++ b/src/Common/src/CoreLib/System/Runtime/InteropServices/MemoryMarshal.Fast.cs
@@ -0,0 +1,232 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Runtime.CompilerServices;
+using System.Collections.Generic;
+using Internal.Runtime.CompilerServices;
+
+namespace System.Runtime.InteropServices
+{
+ /// <summary>
+ /// Provides a collection of methods for interoperating with <see cref="Memory{T}"/>, <see cref="ReadOnlyMemory{T}"/>,
+ /// <see cref="Span{T}"/>, and <see cref="ReadOnlySpan{T}"/>.
+ /// </summary>
+ public static partial class MemoryMarshal
+ {
+ /// <summary>
+ /// Casts a Span of one primitive type <typeparamref name="T"/> to Span of bytes.
+ /// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety.
+ /// </summary>
+ /// <param name="span">The source slice, of type <typeparamref name="T"/>.</param>
+ /// <exception cref="System.ArgumentException">
+ /// Thrown when <typeparamref name="T"/> contains pointers.
+ /// </exception>
+ /// <exception cref="System.OverflowException">
+ /// Thrown if the Length property of the new Span would exceed Int32.MaxValue.
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Span<byte> AsBytes<T>(Span<T> span)
+ where T : struct
+ {
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
+ ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
+
+ return new Span<byte>(
+ ref Unsafe.As<T, byte>(ref GetReference(span)),
+ checked(span.Length * Unsafe.SizeOf<T>()));
+ }
+
+ /// <summary>
+ /// Casts a ReadOnlySpan of one primitive type <typeparamref name="T"/> to ReadOnlySpan of bytes.
+ /// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety.
+ /// </summary>
+ /// <param name="span">The source slice, of type <typeparamref name="T"/>.</param>
+ /// <exception cref="System.ArgumentException">
+ /// Thrown when <typeparamref name="T"/> contains pointers.
+ /// </exception>
+ /// <exception cref="System.OverflowException">
+ /// Thrown if the Length property of the new Span would exceed Int32.MaxValue.
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ReadOnlySpan<byte> AsBytes<T>(ReadOnlySpan<T> span)
+ where T : struct
+ {
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
+ ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
+
+ return new ReadOnlySpan<byte>(
+ ref Unsafe.As<T, byte>(ref GetReference(span)),
+ checked(span.Length * Unsafe.SizeOf<T>()));
+ }
+
+ /// <summary>Creates a <see cref="Memory{T}"/> from a <see cref="ReadOnlyMemory{T}"/>.</summary>
+ /// <param name="memory">The <see cref="ReadOnlyMemory{T}"/>.</param>
+ /// <returns>A <see cref="Memory{T}"/> representing the same memory as the <see cref="ReadOnlyMemory{T}"/>, but writable.</returns>
+ /// <remarks>
+ /// <see cref="AsMemory{T}(ReadOnlyMemory{T})"/> must be used with extreme caution. <see cref="ReadOnlyMemory{T}"/> is used
+ /// to represent immutable data and other memory that is not meant to be written to; <see cref="Memory{T}"/> instances created
+ /// by <see cref="AsMemory{T}(ReadOnlyMemory{T})"/> should not be written to. The method exists to enable variables typed
+ /// as <see cref="Memory{T}"/> but only used for reading to store a <see cref="ReadOnlyMemory{T}"/>.
+ /// </remarks>
+ public static Memory<T> AsMemory<T>(ReadOnlyMemory<T> memory) =>
+ Unsafe.As<ReadOnlyMemory<T>, Memory<T>>(ref memory);
+
+ /// <summary>
+ /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element
+ /// would have been stored. Such a reference may or may not be null. It can be used for pinning but must never be dereferenced.
+ /// </summary>
+ public static ref T GetReference<T>(Span<T> span) => ref span._pointer.Value;
+
+ /// <summary>
+ /// Returns a reference to the 0th element of the ReadOnlySpan. If the ReadOnlySpan is empty, returns a reference to the location where the 0th element
+ /// would have been stored. Such a reference may or may not be null. It can be used for pinning but must never be dereferenced.
+ /// </summary>
+ public static ref T GetReference<T>(ReadOnlySpan<T> span) => ref span._pointer.Value;
+
+ /// <summary>
+ /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to fake non-null pointer. Such a reference can be used
+ /// for pinning but must never be dereferenced. This is useful for interop with methods that do not accept null pointers for zero-sized buffers.
+ /// </summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static unsafe ref T GetNonNullPinnableReference<T>(Span<T> span) => ref (span.Length != 0) ? ref span._pointer.Value : ref Unsafe.AsRef<T>((void*)1);
+
+ /// <summary>
+ /// Returns a reference to the 0th element of the ReadOnlySpan. If the ReadOnlySpan is empty, returns a reference to fake non-null pointer. Such a reference
+ /// can be used for pinning but must never be dereferenced. This is useful for interop with methods that do not accept null pointers for zero-sized buffers.
+ /// </summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static unsafe ref T GetNonNullPinnableReference<T>(ReadOnlySpan<T> span) => ref (span.Length != 0) ? ref span._pointer.Value : ref Unsafe.AsRef<T>((void*)1);
+
+ /// <summary>
+ /// Casts a Span of one primitive type <typeparamref name="TFrom"/> to another primitive type <typeparamref name="TTo"/>.
+ /// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety.
+ /// </summary>
+ /// <remarks>
+ /// Supported only for platforms that support misaligned memory access.
+ /// </remarks>
+ /// <param name="span">The source slice, of type <typeparamref name="TFrom"/>.</param>
+ /// <exception cref="System.ArgumentException">
+ /// Thrown when <typeparamref name="TFrom"/> or <typeparamref name="TTo"/> contains pointers.
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Span<TTo> Cast<TFrom, TTo>(Span<TFrom> span)
+ where TFrom : struct
+ where TTo : struct
+ {
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<TFrom>())
+ ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TFrom));
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<TTo>())
+ ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo));
+
+ // Use unsigned integers - unsigned division by constant (especially by power of 2)
+ // and checked casts are faster and smaller.
+ uint fromSize = (uint)Unsafe.SizeOf<TFrom>();
+ uint toSize = (uint)Unsafe.SizeOf<TTo>();
+ uint fromLength = (uint)span.Length;
+ int toLength;
+ if (fromSize == toSize)
+ {
+ // Special case for same size types - `(ulong)fromLength * (ulong)fromSize / (ulong)toSize`
+ // should be optimized to just `length` but the JIT doesn't do that today.
+ toLength = (int)fromLength;
+ }
+ else if (fromSize == 1)
+ {
+ // Special case for byte sized TFrom - `(ulong)fromLength * (ulong)fromSize / (ulong)toSize`
+ // becomes `(ulong)fromLength / (ulong)toSize` but the JIT can't narrow it down to `int`
+ // and can't eliminate the checked cast. This also avoids a 32 bit specific issue,
+ // the JIT can't eliminate long multiply by 1.
+ toLength = (int)(fromLength / toSize);
+ }
+ else
+ {
+ // Ensure that casts are done in such a way that the JIT is able to "see"
+ // the uint->ulong casts and the multiply together so that on 32 bit targets
+ // 32x32to64 multiplication is used.
+ ulong toLengthUInt64 = (ulong)fromLength * (ulong)fromSize / (ulong)toSize;
+ toLength = checked((int)toLengthUInt64);
+ }
+
+ return new Span<TTo>(
+ ref Unsafe.As<TFrom, TTo>(ref span._pointer.Value),
+ toLength);
+ }
+
+ /// <summary>
+ /// Casts a ReadOnlySpan of one primitive type <typeparamref name="TFrom"/> to another primitive type <typeparamref name="TTo"/>.
+ /// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety.
+ /// </summary>
+ /// <remarks>
+ /// Supported only for platforms that support misaligned memory access.
+ /// </remarks>
+ /// <param name="span">The source slice, of type <typeparamref name="TFrom"/>.</param>
+ /// <exception cref="System.ArgumentException">
+ /// Thrown when <typeparamref name="TFrom"/> or <typeparamref name="TTo"/> contains pointers.
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ReadOnlySpan<TTo> Cast<TFrom, TTo>(ReadOnlySpan<TFrom> span)
+ where TFrom : struct
+ where TTo : struct
+ {
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<TFrom>())
+ ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TFrom));
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<TTo>())
+ ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo));
+
+ // Use unsigned integers - unsigned division by constant (especially by power of 2)
+ // and checked casts are faster and smaller.
+ uint fromSize = (uint)Unsafe.SizeOf<TFrom>();
+ uint toSize = (uint)Unsafe.SizeOf<TTo>();
+ uint fromLength = (uint)span.Length;
+ int toLength;
+ if (fromSize == toSize)
+ {
+ // Special case for same size types - `(ulong)fromLength * (ulong)fromSize / (ulong)toSize`
+ // should be optimized to just `length` but the JIT doesn't do that today.
+ toLength = (int)fromLength;
+ }
+ else if (fromSize == 1)
+ {
+ // Special case for byte sized TFrom - `(ulong)fromLength * (ulong)fromSize / (ulong)toSize`
+ // becomes `(ulong)fromLength / (ulong)toSize` but the JIT can't narrow it down to `int`
+ // and can't eliminate the checked cast. This also avoids a 32 bit specific issue,
+ // the JIT can't eliminate long multiply by 1.
+ toLength = (int)(fromLength / toSize);
+ }
+ else
+ {
+ // Ensure that casts are done in such a way that the JIT is able to "see"
+ // the uint->ulong casts and the multiply together so that on 32 bit targets
+ // 32x32to64 multiplication is used.
+ ulong toLengthUInt64 = (ulong)fromLength * (ulong)fromSize / (ulong)toSize;
+ toLength = checked((int)toLengthUInt64);
+ }
+
+ return new ReadOnlySpan<TTo>(
+ ref Unsafe.As<TFrom, TTo>(ref MemoryMarshal.GetReference(span)),
+ toLength);
+ }
+
+ /// <summary>
+ /// Create a new span over a portion of a regular managed object. This can be useful
+ /// if part of a managed object represents a "fixed array." This is dangerous because the
+ /// <paramref name="length"/> is not checked.
+ /// </summary>
+ /// <param name="reference">A reference to data.</param>
+ /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Span<T> CreateSpan<T>(ref T reference, int length) => new Span<T>(ref reference, length);
+
+ /// <summary>
+ /// Create a new read-only span over a portion of a regular managed object. This can be useful
+ /// if part of a managed object represents a "fixed array." This is dangerous because the
+ /// <paramref name="length"/> is not checked.
+ /// </summary>
+ /// <param name="reference">A reference to data.</param>
+ /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ReadOnlySpan<T> CreateReadOnlySpan<T>(ref T reference, int length) => new ReadOnlySpan<T>(ref reference, length);
+ }
+}
diff --git a/src/Common/src/CoreLib/System/Runtime/InteropServices/MemoryMarshal.cs b/src/Common/src/CoreLib/System/Runtime/InteropServices/MemoryMarshal.cs
index 63e301beca..b4b17b0370 100644
--- a/src/Common/src/CoreLib/System/Runtime/InteropServices/MemoryMarshal.cs
+++ b/src/Common/src/CoreLib/System/Runtime/InteropServices/MemoryMarshal.cs
@@ -4,9 +4,11 @@
using System.Buffers;
using System.Runtime.CompilerServices;
-#if !FEATURE_PORTABLE_SPAN
+using System.Collections.Generic;
+
+#if !netstandard
using Internal.Runtime.CompilerServices;
-#endif // FEATURE_PORTABLE_SPAN
+#endif
namespace System.Runtime.InteropServices
{
@@ -14,81 +16,220 @@ namespace System.Runtime.InteropServices
/// Provides a collection of methods for interoperating with <see cref="Memory{T}"/>, <see cref="ReadOnlyMemory{T}"/>,
/// <see cref="Span{T}"/>, and <see cref="ReadOnlySpan{T}"/>.
/// </summary>
- public static class MemoryMarshal
+ public static partial class MemoryMarshal
{
- /// <summary>Creates a <see cref="Memory{T}"/> from a <see cref="ReadOnlyMemory{T}"/>.</summary>
- /// <param name="readOnlyMemory">The <see cref="ReadOnlyMemory{T}"/>.</param>
- /// <returns>A <see cref="Memory{T}"/> representing the same memory as the <see cref="ReadOnlyMemory{T}"/>, but writable.</returns>
- /// <remarks>
- /// <see cref="AsMemory{T}(ReadOnlyMemory{T})"/> must be used with extreme caution. <see cref="ReadOnlyMemory{T}"/> is used
- /// to represent immutable data and other memory that is not meant to be written to; <see cref="Memory{T}"/> instances created
- /// by <see cref="AsMemory{T}(ReadOnlyMemory{T})"/> should not be written to. The method exists to enable variables typed
- /// as <see cref="Memory{T}"/> but only used for reading to store a <see cref="ReadOnlyMemory{T}"/>.
- /// </remarks>
- public static Memory<T> AsMemory<T>(ReadOnlyMemory<T> readOnlyMemory) =>
- Unsafe.As<ReadOnlyMemory<T>, Memory<T>>(ref readOnlyMemory);
+ /// <summary>
+ /// Get an array segment from the underlying memory.
+ /// If unable to get the array segment, return false with a default array segment.
+ /// </summary>
+ public static bool TryGetArray<T>(ReadOnlyMemory<T> memory, out ArraySegment<T> segment)
+ {
+ object obj = memory.GetObjectStartLength(out int index, out int length);
+ if (index < 0)
+ {
+ if (((OwnedMemory<T>)obj).TryGetArray(out ArraySegment<T> arraySegment))
+ {
+ segment = new ArraySegment<T>(arraySegment.Array, arraySegment.Offset + (index & ReadOnlyMemory<T>.RemoveOwnedFlagBitMask), length);
+ return true;
+ }
+ }
+ else if (obj is T[] arr)
+ {
+ segment = new ArraySegment<T>(arr, index, length);
+ return true;
+ }
+ if (length == 0)
+ {
#if FEATURE_PORTABLE_SPAN
+ segment = new ArraySegment<T>(SpanHelpers.PerTypeValues<T>.EmptyArray);
+#else
+ segment = ArraySegment<T>.Empty;
+#endif // FEATURE_PORTABLE_SPAN
+ return true;
+ }
+
+ segment = default;
+ return false;
+ }
+
/// <summary>
- /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element
- /// would have been stored. Such a reference can be used for pinning but must never be dereferenced.
+ /// Gets an <see cref="OwnedMemory{T}"/> from the underlying read-only memory.
+ /// If unable to get the <typeparamref name="TOwner"/> type, returns false.
/// </summary>
- public static ref T GetReference<T>(Span<T> span)
+ /// <typeparam name="T">The element type of the <paramref name="memory" />.</typeparam>
+ /// <typeparam name="TOwner">The type of <see cref="OwnedMemory{T}"/> to try and retrive.</typeparam>
+ /// <param name="memory">The memory to get the owner for.</param>
+ /// <param name="owner">The returned owner of the <see cref="ReadOnlyMemory{T}"/>.</param>
+ /// <returns>A <see cref="bool"/> indicating if it was successful.</returns>
+ public static bool TryGetOwnedMemory<T, TOwner>(ReadOnlyMemory<T> memory, out TOwner owner)
+ where TOwner : OwnedMemory<T>
{
- if (span.Pinnable == null)
- unsafe { return ref Unsafe.AsRef<T>(span.ByteOffset.ToPointer()); }
- else
- return ref Unsafe.AddByteOffset<T>(ref span.Pinnable.Data, span.ByteOffset);
+ TOwner localOwner; // Use register for null comparison rather than byref
+ owner = localOwner = memory.GetObjectStartLength(out int index, out int length) as TOwner;
+ return !ReferenceEquals(owner, null);
+ }
+
+ /// <summary>
+ /// Gets an <see cref="OwnedMemory{T}"/> and <paramref name="start" />, <paramref name="length" /> from the underlying read-only memory.
+ /// If unable to get the <typeparamref name="TOwner"/> type, returns false.
+ /// </summary>
+ /// <typeparam name="T">The element type of the <paramref name="memory" />.</typeparam>
+ /// <typeparam name="TOwner">The type of <see cref="OwnedMemory{T}"/> to try and retrive.</typeparam>
+ /// <param name="memory">The memory to get the owner for.</param>
+ /// <param name="owner">The returned owner of the <see cref="ReadOnlyMemory{T}"/>.</param>
+ /// <param name="start">The offset from the start of the <paramref name="owner" /> that the <paramref name="memory" /> represents.</param>
+ /// <param name="length">The length of the <paramref name="owner" /> that the <paramref name="memory" /> represents.</param>
+ /// <returns>A <see cref="bool"/> indicating if it was successful.</returns>
+ public static bool TryGetOwnedMemory<T, TOwner>(ReadOnlyMemory<T> memory, out TOwner owner, out int start, out int length)
+ where TOwner : OwnedMemory<T>
+ {
+ TOwner localOwner; // Use register for null comparison rather than byref
+ owner = localOwner = memory.GetObjectStartLength(out start, out length) as TOwner;
+ start &= ReadOnlyMemory<T>.RemoveOwnedFlagBitMask;
+ return !ReferenceEquals(owner, null);
}
/// <summary>
- /// Returns a reference to the 0th element of the ReadOnlySpan. If the Span is empty, returns a reference to the location where the 0th element
- /// would have been stored. Such a reference can be used for pinning but must never be dereferenced.
+ /// Creates an <see cref="IEnumerable{T}"/> view of the given <paramref name="memory" /> to allow
+ /// the <paramref name="memory" /> to be used in existing APIs that take an <see cref="IEnumerable{T}"/>.
/// </summary>
- public static ref T GetReference<T>(ReadOnlySpan<T> span)
+ /// <typeparam name="T">The element type of the <paramref name="memory" />.</typeparam>
+ /// <param name="memory">The ReadOnlyMemory to view as an <see cref="IEnumerable{T}"/></param>
+ /// <returns>An <see cref="IEnumerable{T}"/> view of the given <paramref name="memory" /></returns>
+ public static IEnumerable<T> ToEnumerable<T>(ReadOnlyMemory<T> memory)
{
- if (span.Pinnable == null)
- unsafe { return ref Unsafe.AsRef<T>(span.ByteOffset.ToPointer()); }
+ for (int i = 0; i < memory.Length; i++)
+ yield return memory.Span[i];
+ }
+
+ /// <summary>Attempts to get the underlying <see cref="string"/> from a <see cref="ReadOnlyMemory{T}"/>.</summary>
+ /// <param name="memory">The memory that may be wrapping a <see cref="string"/> object.</param>
+ /// <param name="text">The string.</param>
+ /// <param name="start">The starting location in <paramref name="text"/>.</param>
+ /// <param name="length">The number of items in <paramref name="text"/>.</param>
+ /// <returns></returns>
+ public static bool TryGetString(ReadOnlyMemory<char> memory, out string text, out int start, out int length)
+ {
+ if (memory.GetObjectStartLength(out int offset, out int count) is string s)
+ {
+ text = s;
+ start = offset;
+ length = count;
+ return true;
+ }
else
- return ref Unsafe.AddByteOffset<T>(ref span.Pinnable.Data, span.ByteOffset);
+ {
+ text = null;
+ start = 0;
+ length = 0;
+ return false;
+ }
}
-#else
+
/// <summary>
- /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element
- /// would have been stored. Such a reference can be used for pinning but must never be dereferenced.
+ /// Reads a structure of type T out of a read-only span of bytes.
/// </summary>
- public static ref T GetReference<T>(Span<T> span) => ref span._pointer.Value;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static T Read<T>(ReadOnlySpan<byte> source)
+ where T : struct
+ {
+#if netstandard
+ if (SpanHelpers.IsReferenceOrContainsReferences<T>())
+ {
+ ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T));
+ }
+#else
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
+ {
+ ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
+ }
+#endif
+ if (Unsafe.SizeOf<T>() > source.Length)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length);
+ }
+ return Unsafe.ReadUnaligned<T>(ref GetReference(source));
+ }
/// <summary>
- /// Returns a reference to the 0th element of the ReadOnlySpan. If the Span is empty, returns a reference to the location where the 0th element
- /// would have been stored. Such a reference can be used for pinning but must never be dereferenced.
+ /// Reads a structure of type T out of a span of bytes.
+ /// <returns>If the span is too small to contain the type T, return false.</returns>
/// </summary>
- public static ref T GetReference<T>(ReadOnlySpan<T> span) => ref span._pointer.Value;
-#endif // FEATURE_PORTABLE_SPAN
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool TryRead<T>(ReadOnlySpan<byte> source, out T value)
+ where T : struct
+ {
+#if netstandard
+ if (SpanHelpers.IsReferenceOrContainsReferences<T>())
+ {
+ ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T));
+ }
+#else
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
+ {
+ ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
+ }
+#endif
+ if (Unsafe.SizeOf<T>() > (uint)source.Length)
+ {
+ value = default;
+ return false;
+ }
+ value = Unsafe.ReadUnaligned<T>(ref GetReference(source));
+ return true;
+ }
/// <summary>
- /// Get an array segment from the underlying memory.
- /// If unable to get the array segment, return false with a default array segment.
+ /// Writes a structure of type T into a span of bytes.
/// </summary>
- public static bool TryGetArray<T>(ReadOnlyMemory<T> readOnlyMemory, out ArraySegment<T> arraySegment)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void Write<T>(Span<byte> destination, ref T value)
+ where T : struct
{
- object obj = readOnlyMemory.GetObjectStartLength(out int index, out int length);
- if (index < 0)
+#if netstandard
+ if (SpanHelpers.IsReferenceOrContainsReferences<T>())
{
- if (((OwnedMemory<T>)obj).TryGetArray(out var segment))
- {
- arraySegment = new ArraySegment<T>(segment.Array, segment.Offset + (index & ReadOnlyMemory<T>.RemoveOwnedFlagBitMask), length);
- return true;
- }
+ ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T));
}
- else if (obj is T[] arr)
+#else
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
{
- arraySegment = new ArraySegment<T>(arr, index, length);
- return true;
+ ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
+ }
+#endif
+ if ((uint)Unsafe.SizeOf<T>() > (uint)destination.Length)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length);
}
+ Unsafe.WriteUnaligned<T>(ref GetReference(destination), value);
+ }
- arraySegment = default;
- return false;
+ /// <summary>
+ /// Writes a structure of type T into a span of bytes.
+ /// <returns>If the span is too small to contain the type T, return false.</returns>
+ /// </summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool TryWrite<T>(Span<byte> destination, ref T value)
+ where T : struct
+ {
+#if netstandard
+ if (SpanHelpers.IsReferenceOrContainsReferences<T>())
+ {
+ ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T));
+ }
+#else
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
+ {
+ ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
+ }
+#endif
+ if (Unsafe.SizeOf<T>() > (uint)destination.Length)
+ {
+ return false;
+ }
+ Unsafe.WriteUnaligned<T>(ref GetReference(destination), value);
+ return true;
}
}
}
diff --git a/src/Common/src/CoreLib/System/Runtime/InteropServices/StringBuffer.cs b/src/Common/src/CoreLib/System/Runtime/InteropServices/StringBuffer.cs
deleted file mode 100644
index fdd0b95590..0000000000
--- a/src/Common/src/CoreLib/System/Runtime/InteropServices/StringBuffer.cs
+++ /dev/null
@@ -1,301 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Buffers;
-using System.Runtime.CompilerServices;
-
-namespace System.Runtime.InteropServices
-{
- /// <summary>
- /// Buffer that deals in char size increments. Dispose to free memory. Always makes ordinal
- /// comparisons. Not thread safe.
- ///
- /// A more performant replacement for StringBuilder when performing native interop.
- ///
- /// "No copy" valuetype. Has to be passed as "ref".
- ///
- /// </summary>
- /// <remarks>
- /// Suggested use through P/Invoke: define DllImport arguments that take a character buffer as SafeHandle and pass StringBuffer.GetHandle().
- /// </remarks>
- internal struct StringBuffer
- {
- private char[] _buffer;
- private int _length;
-
- /// <summary>
- /// Instantiate the buffer with capacity for at least the specified number of characters. Capacity
- /// includes the trailing null character.
- /// </summary>
- public StringBuffer(int initialCapacity)
- {
- _buffer = ArrayPool<char>.Shared.Rent(initialCapacity);
- _length = 0;
- }
-
- /// <summary>
- /// Get/set the character at the given index.
- /// </summary>
- /// <exception cref="ArgumentOutOfRangeException">Thrown if attempting to index outside of the buffer length.</exception>
- public char this[int index]
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get
- {
- if (index >= _length) throw new ArgumentOutOfRangeException(nameof(index));
- return _buffer[index];
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- set
- {
- if (index >= _length) throw new ArgumentOutOfRangeException(nameof(index));
- _buffer[index] = value;
- }
- }
-
- /// <summary>
- /// Underlying storage of the buffer. Used for interop.
- /// </summary>
- public char[] UnderlyingArray => _buffer;
-
- /// <summary>
- /// Character capacity of the buffer. Includes the count for the trailing null character.
- /// </summary>
- public int Capacity => _buffer.Length;
-
- /// <summary>
- /// Ensure capacity in characters is at least the given minimum.
- /// </summary>
- /// <exception cref="OutOfMemoryException">Thrown if unable to allocate memory when setting.</exception>
- public void EnsureCapacity(int minCapacity)
- {
- if (minCapacity > Capacity)
- {
- char[] oldBuffer = _buffer;
- _buffer = ArrayPool<char>.Shared.Rent(minCapacity);
- Array.Copy(oldBuffer, 0, _buffer, 0, oldBuffer.Length);
- ArrayPool<char>.Shared.Return(oldBuffer);
- }
- }
-
- /// <summary>
- /// The logical length of the buffer in characters. (Does not include the final null.) Will automatically attempt to increase capacity.
- /// This is where the usable data ends.
- /// </summary>
- /// <exception cref="OutOfMemoryException">Thrown if unable to allocate memory when setting.</exception>
- /// <exception cref="ArgumentOutOfRangeException">Thrown if the set size in bytes is int.MaxValue (as space is implicitly reserved for the trailing null).</exception>
- public int Length
- {
- get { return _length; }
- set
- {
- // Null terminate
- EnsureCapacity(checked(value + 1));
- _buffer[value] = '\0';
-
- _length = value;
- }
- }
-
- /// <summary>
- /// True if the buffer contains the given character.
- /// </summary>
- public unsafe bool Contains(char value)
- {
- fixed (char* start = _buffer)
- {
- int length = _length;
- for (int i = 0; i < length; i++)
- {
- if (start[i] == value) return true;
- }
- }
-
- return false;
- }
-
- /// <summary>
- /// Returns true if the buffer starts with the given string.
- /// </summary>
- public bool StartsWith(string value)
- {
- if (value == null) throw new ArgumentNullException(nameof(value));
- if (_length < value.Length) return false;
- return SubstringEquals(value, startIndex: 0, count: value.Length);
- }
-
- /// <summary>
- /// Returns true if the specified StringBuffer substring equals the given value.
- /// </summary>
- /// <param name="value">The value to compare against the specified substring.</param>
- /// <param name="startIndex">Start index of the sub string.</param>
- /// <param name="count">Length of the substring, or -1 to check all remaining.</param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// Thrown if <paramref name="startIndex"/> or <paramref name="count"/> are outside the range
- /// of the buffer's length.
- /// </exception>
- public unsafe bool SubstringEquals(string value, int startIndex = 0, int count = -1)
- {
- if (value == null) return false;
- if (count < -1) throw new ArgumentOutOfRangeException(nameof(count));
- if (startIndex > _length) throw new ArgumentOutOfRangeException(nameof(startIndex));
-
- int realCount = count == -1 ? _length - startIndex : (int)count;
- if (checked(startIndex + realCount) > _length) throw new ArgumentOutOfRangeException(nameof(count));
-
- int length = value.Length;
-
- // Check the substring length against the input length
- if (realCount != length) return false;
-
- fixed (char* valueStart = value)
- fixed (char* bufferStart = _buffer)
- {
- char* subStringStart = bufferStart + startIndex;
-
- for (int i = 0; i < length; i++)
- {
- if (subStringStart[i] != valueStart[i]) return false;
- }
- }
-
- return true;
- }
-
- /// <summary>
- /// Append the given buffer.
- /// </summary>
- /// <param name="value">The buffer to append.</param>
- /// <param name="startIndex">The index in the input buffer to start appending from.</param>
- /// <param name="count">The count of characters to copy from the buffer string.</param>
- /// <exception cref="ArgumentNullException">Thrown if <paramref name="value"/> is null.</exception>
- /// <exception cref="ArgumentOutOfRangeException">
- /// Thrown if <paramref name="startIndex"/> or <paramref name="count"/> are outside the range
- /// of <paramref name="value"/> characters.
- /// </exception>
- public void Append(ref StringBuffer value, int startIndex = 0)
- {
- if (value.Length == 0) return;
-
- value.CopyTo(
- bufferIndex: startIndex,
- destination: ref this,
- destinationIndex: _length,
- count: value.Length);
- }
-
- /// <summary>
- /// Append the given buffer.
- /// </summary>
- /// <param name="value">The buffer to append.</param>
- /// <param name="startIndex">The index in the input buffer to start appending from.</param>
- /// <param name="count">The count of characters to copy from the buffer string.</param>
- /// <exception cref="ArgumentNullException">Thrown if <paramref name="value"/> is null.</exception>
- /// <exception cref="ArgumentOutOfRangeException">
- /// Thrown if <paramref name="startIndex"/> or <paramref name="count"/> are outside the range
- /// of <paramref name="value"/> characters.
- /// </exception>
- public void Append(ref StringBuffer value, int startIndex, int count)
- {
- if (count == 0) return;
-
- value.CopyTo(
- bufferIndex: startIndex,
- destination: ref this,
- destinationIndex: _length,
- count: count);
- }
-
- /// <summary>
- /// Copy contents to the specified buffer. Destination index must be within current destination length.
- /// Will grow the destination buffer if needed.
- /// </summary>
- /// <exception cref="ArgumentOutOfRangeException">
- /// Thrown if <paramref name="bufferIndex"/> or <paramref name="destinationIndex"/> or <paramref name="count"/> are outside the range
- /// of <paramref name="value"/> characters.
- /// </exception>
- /// <exception cref="ArgumentNullException">Thrown if <paramref name="destination"/> is null.</exception>
- public void CopyTo(int bufferIndex, ref StringBuffer destination, int destinationIndex, int count)
- {
- if (destinationIndex > destination._length) throw new ArgumentOutOfRangeException(nameof(destinationIndex));
- if (bufferIndex >= _length) throw new ArgumentOutOfRangeException(nameof(bufferIndex));
- if (_length < checked(bufferIndex + count)) throw new ArgumentOutOfRangeException(nameof(count));
-
- if (count == 0) return;
- int lastIndex = checked(destinationIndex + count);
- if (destination.Length < lastIndex) destination.Length = lastIndex;
-
- Array.Copy(UnderlyingArray, bufferIndex, destination.UnderlyingArray, destinationIndex, count);
- }
-
- /// <summary>
- /// Copy contents from the specified string into the buffer at the given index. Start index must be within the current length of
- /// the buffer, will grow as necessary.
- /// </summary>
- public void CopyFrom(int bufferIndex, string source, int sourceIndex = 0, int count = -1)
- {
- if (source == null) throw new ArgumentNullException(nameof(source));
- if (bufferIndex > _length) throw new ArgumentOutOfRangeException(nameof(bufferIndex));
- if (sourceIndex < 0 || sourceIndex > source.Length) throw new ArgumentOutOfRangeException(nameof(sourceIndex));
- if (count == -1) count = source.Length - sourceIndex;
- if (count < 0 || source.Length - count < sourceIndex) throw new ArgumentOutOfRangeException(nameof(count));
-
- if (count == 0) return;
- int lastIndex = bufferIndex + (int)count;
- if (_length < lastIndex) Length = lastIndex;
-
- source.CopyTo(sourceIndex, UnderlyingArray, bufferIndex, count);
- }
-
- /// <summary>
- /// Trim the specified values from the end of the buffer. If nothing is specified, nothing is trimmed.
- /// </summary>
- public void TrimEnd(char[] values)
- {
- if (values == null || values.Length == 0 || _length == 0) return;
-
- while (_length > 0 && Array.IndexOf(values, _buffer[_length - 1]) >= 0)
- {
- Length = _length - 1;
- }
- }
-
- /// <summary>
- /// String representation of the entire buffer. If the buffer is larger than the maximum size string (int.MaxValue) this will throw.
- /// </summary>
- /// <exception cref="InvalidOperationException">Thrown if the buffer is too big to fit into a string.</exception>
- public override string ToString()
- {
- return new string(_buffer, startIndex: 0, length: _length);
- }
-
- /// <summary>
- /// Get the given substring in the buffer.
- /// </summary>
- /// <param name="count">Count of characters to take, or remaining characters from <paramref name="startIndex"/> if -1.</param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// Thrown if <paramref name="startIndex"/> or <paramref name="count"/> are outside the range of the buffer's length
- /// or count is greater than the maximum string size (int.MaxValue).
- /// </exception>
- public string Substring(int startIndex, int count = -1)
- {
- if (startIndex > (_length == 0 ? 0 : _length - 1)) throw new ArgumentOutOfRangeException(nameof(startIndex));
- if (count < -1) throw new ArgumentOutOfRangeException(nameof(count));
-
- int realCount = count == -1 ? _length - startIndex : (int)count;
- if (realCount > int.MaxValue || checked(startIndex + realCount) > _length) throw new ArgumentOutOfRangeException(nameof(count));
-
- // The buffer could be bigger than will fit into a string, but the substring might fit. As the starting
- // index might be bigger than int we need to index ourselves.
- return new string(_buffer, startIndex: startIndex, length: realCount);
- }
-
- public void Free()
- {
- ArrayPool<char>.Shared.Return(_buffer);
- _buffer = null;
- _length = 0;
- }
- }
-}
diff --git a/src/Common/src/CoreLib/System/Security/SafeBSTRHandle.cs b/src/Common/src/CoreLib/System/Security/SafeBSTRHandle.cs
index 227fed3fc3..bc93fecef1 100644
--- a/src/Common/src/CoreLib/System/Security/SafeBSTRHandle.cs
+++ b/src/Common/src/CoreLib/System/Security/SafeBSTRHandle.cs
@@ -50,7 +50,7 @@ namespace System.Security
internal unsafe uint Length => Interop.OleAut32.SysStringLen(this);
- internal unsafe static void Copy(SafeBSTRHandle source, SafeBSTRHandle target, uint bytesToCopy)
+ internal static unsafe void Copy(SafeBSTRHandle source, SafeBSTRHandle target, uint bytesToCopy)
{
if (bytesToCopy == 0)
{
diff --git a/src/Common/src/CoreLib/System/Security/SecureString.cs b/src/Common/src/CoreLib/System/Security/SecureString.cs
index 9059f90e60..22f15accaa 100644
--- a/src/Common/src/CoreLib/System/Security/SecureString.cs
+++ b/src/Common/src/CoreLib/System/Security/SecureString.cs
@@ -2,9 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
+using System.Threading;
namespace System.Security
{
@@ -43,11 +43,8 @@ namespace System.Security
{
get
{
- lock (_methodLock)
- {
- EnsureNotDisposed();
- return _decryptedLength;
- }
+ EnsureNotDisposed();
+ return Volatile.Read(ref _decryptedLength);
}
}
@@ -108,20 +105,14 @@ namespace System.Security
public bool IsReadOnly()
{
- lock (_methodLock)
- {
- EnsureNotDisposed();
- return _readOnly;
- }
+ EnsureNotDisposed();
+ return Volatile.Read(ref _readOnly);
}
public void MakeReadOnly()
{
- lock (_methodLock)
- {
- EnsureNotDisposed();
- _readOnly = true;
- }
+ EnsureNotDisposed();
+ Volatile.Write(ref _readOnly, true);
}
public void RemoveAt(int index)
diff --git a/src/Common/src/CoreLib/System/Single.cs b/src/Common/src/CoreLib/System/Single.cs
index df97427d38..cb5a309871 100644
--- a/src/Common/src/CoreLib/System/Single.cs
+++ b/src/Common/src/CoreLib/System/Single.cs
@@ -16,6 +16,8 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
+using Internal.Runtime.CompilerServices;
+
namespace System
{
[Serializable]
@@ -50,7 +52,7 @@ namespace System
/// <summary>Determines whether the specified value is infinite.</summary>
[NonVersionable]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public unsafe static bool IsInfinity(float f)
+ public static unsafe bool IsInfinity(float f)
{
var bits = BitConverter.SingleToInt32Bits(f);
return (bits & 0x7FFFFFFF) == 0x7F800000;
@@ -59,7 +61,7 @@ namespace System
/// <summary>Determines whether the specified value is NaN.</summary>
[NonVersionable]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public unsafe static bool IsNaN(float f)
+ public static unsafe bool IsNaN(float f)
{
var bits = BitConverter.SingleToInt32Bits(f);
return (bits & 0x7FFFFFFF) > 0x7F800000;
@@ -68,7 +70,7 @@ namespace System
/// <summary>Determines whether the specified value is negative.</summary>
[NonVersionable]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public unsafe static bool IsNegative(float f)
+ public static unsafe bool IsNegative(float f)
{
var bits = unchecked((uint)BitConverter.SingleToInt32Bits(f));
return (bits & 0x80000000) == 0x80000000;
@@ -77,7 +79,7 @@ namespace System
/// <summary>Determines whether the specified value is negative infinity.</summary>
[NonVersionable]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public unsafe static bool IsNegativeInfinity(float f)
+ public static unsafe bool IsNegativeInfinity(float f)
{
return (f == float.NegativeInfinity);
}
@@ -85,7 +87,7 @@ namespace System
/// <summary>Determines whether the specified value is normal.</summary>
[NonVersionable]
// This is probably not worth inlining, it has branches and should be rarely called
- public unsafe static bool IsNormal(float f)
+ public static unsafe bool IsNormal(float f)
{
var bits = BitConverter.SingleToInt32Bits(f);
bits &= 0x7FFFFFFF;
@@ -95,7 +97,7 @@ namespace System
/// <summary>Determines whether the specified value is positive infinity.</summary>
[NonVersionable]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public unsafe static bool IsPositiveInfinity(float f)
+ public static unsafe bool IsPositiveInfinity(float f)
{
return (f == float.PositiveInfinity);
}
@@ -103,7 +105,7 @@ namespace System
/// <summary>Determines whether the specified value is subnormal.</summary>
[NonVersionable]
// This is probably not worth inlining, it has branches and should be rarely called
- public unsafe static bool IsSubnormal(float f)
+ public static unsafe bool IsSubnormal(float f)
{
var bits = BitConverter.SingleToInt32Bits(f);
bits &= 0x7FFFFFFF;
@@ -213,16 +215,18 @@ namespace System
return IsNaN(obj) && IsNaN(m_value);
}
- public unsafe override int GetHashCode()
+ public override int GetHashCode()
{
- float f = m_value;
- if (f == 0)
+ var bits = Unsafe.As<float, int>(ref m_value);
+
+ // Optimized check for IsNan() || IsZero()
+ if (((bits - 1) & 0x7FFFFFFF) >= 0x7F800000)
{
- // Ensure that 0 and -0 have the same hash code
- return 0;
+ // Ensure that all NaNs and both zeros have the same hash code
+ bits &= 0x7F800000;
}
- int v = *(int*)(&f);
- return v;
+
+ return bits;
}
public override String ToString()
@@ -331,15 +335,15 @@ namespace System
if (!success)
{
ReadOnlySpan<char> sTrim = s.Trim();
- if (StringSpanHelpers.Equals(sTrim, info.PositiveInfinitySymbol))
+ if (sTrim.EqualsOrdinal(info.PositiveInfinitySymbol))
{
result = PositiveInfinity;
}
- else if (StringSpanHelpers.Equals(sTrim, info.NegativeInfinitySymbol))
+ else if (sTrim.EqualsOrdinal(info.NegativeInfinitySymbol))
{
result = NegativeInfinity;
}
- else if (StringSpanHelpers.Equals(sTrim, info.NaNSymbol))
+ else if (sTrim.EqualsOrdinal(info.NaNSymbol))
{
result = NaN;
}
diff --git a/src/Common/src/CoreLib/System/Span.Fast.cs b/src/Common/src/CoreLib/System/Span.Fast.cs
new file mode 100644
index 0000000000..0ae1922fd4
--- /dev/null
+++ b/src/Common/src/CoreLib/System/Span.Fast.cs
@@ -0,0 +1,350 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Runtime.Versioning;
+using Internal.Runtime.CompilerServices;
+
+#pragma warning disable 0809 //warning CS0809: Obsolete member 'Span<T>.Equals(object)' overrides non-obsolete member 'object.Equals(object)'
+
+#if BIT64
+using nuint = System.UInt64;
+#else
+using nuint = System.UInt32;
+#endif
+
+namespace System
+{
+ /// <summary>
+ /// Span represents a contiguous region of arbitrary memory. Unlike arrays, it can point to either managed
+ /// or native memory, or to memory allocated on the stack. It is type- and memory-safe.
+ /// </summary>
+ [DebuggerTypeProxy(typeof(SpanDebugView<>))]
+ [DebuggerDisplay("{ToString(),raw}")]
+ [NonVersionable]
+ public readonly ref partial struct Span<T>
+ {
+ /// <summary>A byref or a native ptr.</summary>
+ internal readonly ByReference<T> _pointer;
+ /// <summary>The number of elements this Span contains.</summary>
+#if PROJECTN
+ [Bound]
+#endif
+ private readonly int _length;
+
+ /// <summary>
+ /// Creates a new span over the entirety of the target array.
+ /// </summary>
+ /// <param name="array">The target array.</param>
+ /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
+ /// reference (Nothing in Visual Basic).</exception>
+ /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Span(T[] array)
+ {
+ if (array == null)
+ {
+ this = default;
+ return; // returns default
+ }
+ if (default(T) == null && array.GetType() != typeof(T[]))
+ ThrowHelper.ThrowArrayTypeMismatchException();
+
+ _pointer = new ByReference<T>(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()));
+ _length = array.Length;
+ }
+
+ /// <summary>
+ /// Creates a new span over the portion of the target array beginning
+ /// at 'start' index and ending at 'end' index (exclusive).
+ /// </summary>
+ /// <param name="array">The target array.</param>
+ /// <param name="start">The index at which to begin the span.</param>
+ /// <param name="length">The number of items in the span.</param>
+ /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
+ /// reference (Nothing in Visual Basic).</exception>
+ /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> or end index is not in the range (&lt;0 or &gt;=Length).
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Span(T[] array, int start, int length)
+ {
+ if (array == null)
+ {
+ if (start != 0 || length != 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+ this = default;
+ return; // returns default
+ }
+ if (default(T) == null && array.GetType() != typeof(T[]))
+ ThrowHelper.ThrowArrayTypeMismatchException();
+ if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ _pointer = new ByReference<T>(ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), start));
+ _length = length;
+ }
+
+ /// <summary>
+ /// Creates a new span over the target unmanaged buffer. Clearly this
+ /// is quite dangerous, because we are creating arbitrarily typed T's
+ /// out of a void*-typed block of memory. And the length is not checked.
+ /// But if this creation is correct, then all subsequent uses are correct.
+ /// </summary>
+ /// <param name="pointer">An unmanaged pointer to memory.</param>
+ /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
+ /// <exception cref="System.ArgumentException">
+ /// Thrown when <typeparamref name="T"/> is reference type or contains pointers and hence cannot be stored in unmanaged memory.
+ /// </exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="length"/> is negative.
+ /// </exception>
+ [CLSCompliant(false)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public unsafe Span(void* pointer, int length)
+ {
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
+ ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
+ if (length < 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ _pointer = new ByReference<T>(ref Unsafe.As<byte, T>(ref *(byte*)pointer));
+ _length = length;
+ }
+
+ // Constructor for internal use only.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal Span(ref T ptr, int length)
+ {
+ Debug.Assert(length >= 0);
+
+ _pointer = new ByReference<T>(ref ptr);
+ _length = length;
+ }
+
+ /// Returns a reference to specified element of the Span.
+ /// </summary>
+ /// <param name="index"></param>
+ /// <returns></returns>
+ /// <exception cref="System.IndexOutOfRangeException">
+ /// Thrown when index less than 0 or index greater than or equal to Length
+ /// </exception>
+ public ref T this[int index]
+ {
+#if PROJECTN
+ [BoundsChecking]
+ get
+ {
+ return ref Unsafe.Add(ref _pointer.Value, index);
+ }
+#else
+ [Intrinsic]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [NonVersionable]
+ get
+ {
+ if ((uint)index >= (uint)_length)
+ ThrowHelper.ThrowIndexOutOfRangeException();
+ return ref Unsafe.Add(ref _pointer.Value, index);
+ }
+#endif
+ }
+
+ /// <summary>
+ /// Clears the contents of this span.
+ /// </summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Clear()
+ {
+ if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
+ {
+ SpanHelpers.ClearWithReferences(ref Unsafe.As<T, IntPtr>(ref _pointer.Value), (nuint)_length * (nuint)(Unsafe.SizeOf<T>() / sizeof(nuint)));
+ }
+ else
+ {
+ SpanHelpers.ClearWithoutReferences(ref Unsafe.As<T, byte>(ref _pointer.Value), (nuint)_length * (nuint)Unsafe.SizeOf<T>());
+ }
+ }
+
+ /// <summary>
+ /// Fills the contents of this span with the given value.
+ /// </summary>
+ public void Fill(T value)
+ {
+ if (Unsafe.SizeOf<T>() == 1)
+ {
+ uint length = (uint)_length;
+ if (length == 0)
+ return;
+
+ T tmp = value; // Avoid taking address of the "value" argument. It would regress performance of the loop below.
+ Unsafe.InitBlockUnaligned(ref Unsafe.As<T, byte>(ref _pointer.Value), Unsafe.As<T, byte>(ref tmp), length);
+ }
+ else
+ {
+ // Do all math as nuint to avoid unnecessary 64->32->64 bit integer truncations
+ nuint length = (uint)_length;
+ if (length == 0)
+ return;
+
+ ref T r = ref _pointer.Value;
+
+ // TODO: Create block fill for value types of power of two sizes e.g. 2,4,8,16
+
+ nuint elementSize = (uint)Unsafe.SizeOf<T>();
+ nuint i = 0;
+ for (; i < (length & ~(nuint)7); i += 8)
+ {
+ Unsafe.AddByteOffset<T>(ref r, (i + 0) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 1) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 2) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 3) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 4) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 5) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 6) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 7) * elementSize) = value;
+ }
+ if (i < (length & ~(nuint)3))
+ {
+ Unsafe.AddByteOffset<T>(ref r, (i + 0) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 1) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 2) * elementSize) = value;
+ Unsafe.AddByteOffset<T>(ref r, (i + 3) * elementSize) = value;
+ i += 4;
+ }
+ for (; i < length; i++)
+ {
+ Unsafe.AddByteOffset<T>(ref r, i * elementSize) = value;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Copies the contents of this span into destination span. If the source
+ /// and destinations overlap, this method behaves as if the original values in
+ /// a temporary location before the destination is overwritten.
+ /// </summary>
+ /// <param name="destination">The span to copy items into.</param>
+ /// <exception cref="System.ArgumentException">
+ /// Thrown when the destination Span is shorter than the source Span.
+ /// </exception>
+ public void CopyTo(Span<T> destination)
+ {
+ // Using "if (!TryCopyTo(...))" results in two branches: one for the length
+ // check, and one for the result of TryCopyTo. Since these checks are equivalent,
+ // we can optimize by performing the check once ourselves then calling Memmove directly.
+
+ if ((uint)_length <= (uint)destination.Length)
+ {
+ Buffer.Memmove(ref destination._pointer.Value, ref _pointer.Value, (nuint)_length);
+ }
+ else
+ {
+ ThrowHelper.ThrowArgumentException_DestinationTooShort();
+ }
+ }
+
+ /// <summary>
+ /// Copies the contents of this span into destination span. If the source
+ /// and destinations overlap, this method behaves as if the original values in
+ /// a temporary location before the destination is overwritten.
+ /// </summary>
+ /// <param name="destination">The span to copy items into.</param>
+ /// <returns>If the destination span is shorter than the source span, this method
+ /// return false and no data is written to the destination.</returns>
+ public bool TryCopyTo(Span<T> destination)
+ {
+ bool retVal = false;
+ if ((uint)_length <= (uint)destination.Length)
+ {
+ Buffer.Memmove(ref destination._pointer.Value, ref _pointer.Value, (nuint)_length);
+ retVal = true;
+ }
+ return retVal;
+ }
+
+ /// <summary>
+ /// Returns true if left and right point at the same memory and have the same length. Note that
+ /// this does *not* check to see if the *contents* are equal.
+ /// </summary>
+ public static bool operator ==(Span<T> left, Span<T> right)
+ {
+ return left._length == right._length && Unsafe.AreSame<T>(ref left._pointer.Value, ref right._pointer.Value);
+ }
+
+ /// <summary>
+ /// Defines an implicit conversion of a <see cref="Span{T}"/> to a <see cref="ReadOnlySpan{T}"/>
+ /// </summary>
+ public static implicit operator ReadOnlySpan<T>(Span<T> span) => new ReadOnlySpan<T>(ref span._pointer.Value, span._length);
+
+ /// <summary>
+ /// For <see cref="Span{Char}"/>, returns a new instance of string that represents the characters pointed to by the span.
+ /// Otherwise, returns a <see cref="String"/> with the name of the type and the number of elements.
+ /// </summary>
+ public override string ToString()
+ {
+ if (typeof(T) == typeof(char))
+ {
+ unsafe
+ {
+ fixed (char* src = &Unsafe.As<T, char>(ref _pointer.Value))
+ return new string(src, 0, _length);
+ }
+ }
+ return string.Format("System.Span<{0}>[{1}]", typeof(T).Name, _length);
+ }
+
+ /// <summary>
+ /// Forms a slice out of the given span, beginning at 'start'.
+ /// </summary>
+ /// <param name="start">The index at which to begin this slice.</param>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> index is not in range (&lt;0 or &gt;=Length).
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Span<T> Slice(int start)
+ {
+ if ((uint)start > (uint)_length)
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ return new Span<T>(ref Unsafe.Add(ref _pointer.Value, start), _length - start);
+ }
+
+ /// <summary>
+ /// Forms a slice out of the given span, beginning at 'start', of given length
+ /// </summary>
+ /// <param name="start">The index at which to begin this slice.</param>
+ /// <param name="length">The desired length for the slice (exclusive).</param>
+ /// <exception cref="System.ArgumentOutOfRangeException">
+ /// Thrown when the specified <paramref name="start"/> or end index is not in range (&lt;0 or &gt;=Length).
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Span<T> Slice(int start, int length)
+ {
+ if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
+ ThrowHelper.ThrowArgumentOutOfRangeException();
+
+ return new Span<T>(ref Unsafe.Add(ref _pointer.Value, start), length);
+ }
+
+ /// <summary>
+ /// Copies the contents of this span into a new array. This heap
+ /// allocates, so should generally be avoided, however it is sometimes
+ /// necessary to bridge the gap with APIs written in terms of arrays.
+ /// </summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public T[] ToArray()
+ {
+ if (_length == 0)
+ return Array.Empty<T>();
+
+ var destination = new T[_length];
+ Buffer.Memmove(ref Unsafe.As<byte, T>(ref destination.GetRawSzArrayData()), ref _pointer.Value, (nuint)_length);
+ return destination;
+ }
+ }
+}
diff --git a/src/Common/src/CoreLib/System/Span.NonGeneric.cs b/src/Common/src/CoreLib/System/Span.NonGeneric.cs
deleted file mode 100644
index f6cd939a73..0000000000
--- a/src/Common/src/CoreLib/System/Span.NonGeneric.cs
+++ /dev/null
@@ -1,638 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-using System.Runtime;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-using Internal.Runtime.CompilerServices;
-
-#if BIT64
-using nuint = System.UInt64;
-#else
-using nuint = System.UInt32;
-#endif
-
-namespace System
-{
- /// <summary>
- /// Extension methods and non-generic helpers for Span, ReadOnlySpan, Memory, and ReadOnlyMemory.
- /// </summary>
- public static class Span
- {
- /// <summary>Creates a new <see cref="ReadOnlyMemory{char}"/> over the portion of the target string.</summary>
- /// <param name="text">The target string.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is a null reference (Nothing in Visual Basic).</exception>
- public static ReadOnlyMemory<char> AsReadOnlyMemory(this string text)
- {
- if (text == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
-
- return new ReadOnlyMemory<char>(text, 0, text.Length);
- }
-
- /// <summary>Creates a new <see cref="ReadOnlyMemory{char}"/> over the portion of the target string.</summary>
- /// <param name="text">The target string.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is a null reference (Nothing in Visual Basic).</exception>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> index is not in range (&lt;0 or &gt;text.Length).
- /// </exception>
- public static ReadOnlyMemory<char> AsReadOnlyMemory(this string text, int start)
- {
- if (text == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
-
- if ((uint)start > (uint)text.Length)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
-
- return new ReadOnlyMemory<char>(text, start, text.Length - start);
- }
-
- /// <summary>Creates a new <see cref="ReadOnlyMemory{char}"/> over the portion of the target string.</summary>
- /// <param name="text">The target string.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is a null reference (Nothing in Visual Basic).</exception>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> index or <paramref name="length"/> is not in range.
- /// </exception>
- public static ReadOnlyMemory<char> AsReadOnlyMemory(this string text, int start, int length)
- {
- if (text == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
-
- if ((uint)start > (uint)text.Length || (uint)length > (uint)(text.Length - start))
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
-
- return new ReadOnlyMemory<char>(text, start, length);
- }
-
- /// <summary>Attempts to get the underlying <see cref="string"/> from a <see cref="ReadOnlyMemory{T}"/>.</summary>
- /// <param name="readOnlyMemory">The memory that may be wrapping a <see cref="string"/> object.</param>
- /// <param name="text">The string.</param>
- /// <param name="start">The starting location in <paramref name="text"/>.</param>
- /// <param name="length">The number of items in <paramref name="text"/>.</param>
- /// <returns></returns>
- public static bool TryGetString(this ReadOnlyMemory<char> readOnlyMemory, out string text, out int start, out int length)
- {
- if (readOnlyMemory.GetObjectStartLength(out int offset, out int count) is string s)
- {
- text = s;
- start = offset;
- length = count;
- return true;
- }
- else
- {
- text = null;
- start = 0;
- length = 0;
- return false;
- }
- }
-
- /// <summary>
- /// Casts a Span of one primitive type <typeparamref name="T"/> to Span of bytes.
- /// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety.
- /// </summary>
- /// <param name="source">The source slice, of type <typeparamref name="T"/>.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when <typeparamref name="T"/> contains pointers.
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Span<byte> AsBytes<T>(this Span<T> source)
- where T : struct
- {
- if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
- ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
-
- return new Span<byte>(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(source)),
- checked(source.Length * Unsafe.SizeOf<T>()));
- }
-
- /// <summary>
- /// Casts a ReadOnlySpan of one primitive type <typeparamref name="T"/> to ReadOnlySpan of bytes.
- /// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety.
- /// </summary>
- /// <param name="source">The source slice, of type <typeparamref name="T"/>.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when <typeparamref name="T"/> contains pointers.
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ReadOnlySpan<byte> AsBytes<T>(this ReadOnlySpan<T> source)
- where T : struct
- {
- if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
- ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
-
- return new ReadOnlySpan<byte>(
- ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(source)),
- checked(source.Length * Unsafe.SizeOf<T>()));
- }
-
- /// <summary>
- /// Casts a Span of one primitive type <typeparamref name="TFrom"/> to another primitive type <typeparamref name="TTo"/>.
- /// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety.
- /// </summary>
- /// <remarks>
- /// Supported only for platforms that support misaligned memory access.
- /// </remarks>
- /// <param name="source">The source slice, of type <typeparamref name="TFrom"/>.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when <typeparamref name="TFrom"/> or <typeparamref name="TTo"/> contains pointers.
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Span<TTo> NonPortableCast<TFrom, TTo>(this Span<TFrom> source)
- where TFrom : struct
- where TTo : struct
- {
- if (RuntimeHelpers.IsReferenceOrContainsReferences<TFrom>())
- ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TFrom));
- if (RuntimeHelpers.IsReferenceOrContainsReferences<TTo>())
- ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo));
-
- return new Span<TTo>(
- ref Unsafe.As<TFrom, TTo>(ref source.DangerousGetPinnableReference()),
- checked((int)((long)source.Length * Unsafe.SizeOf<TFrom>() / Unsafe.SizeOf<TTo>())));
- }
-
- /// <summary>
- /// Casts a ReadOnlySpan of one primitive type <typeparamref name="TFrom"/> to another primitive type <typeparamref name="TTo"/>.
- /// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety.
- /// </summary>
- /// <remarks>
- /// Supported only for platforms that support misaligned memory access.
- /// </remarks>
- /// <param name="source">The source slice, of type <typeparamref name="TFrom"/>.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when <typeparamref name="TFrom"/> or <typeparamref name="TTo"/> contains pointers.
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ReadOnlySpan<TTo> NonPortableCast<TFrom, TTo>(this ReadOnlySpan<TFrom> source)
- where TFrom : struct
- where TTo : struct
- {
- if (RuntimeHelpers.IsReferenceOrContainsReferences<TFrom>())
- ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TFrom));
- if (RuntimeHelpers.IsReferenceOrContainsReferences<TTo>())
- ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo));
-
- return new ReadOnlySpan<TTo>(
- ref Unsafe.As<TFrom, TTo>(ref MemoryMarshal.GetReference(source)),
- checked((int)((long)source.Length * Unsafe.SizeOf<TFrom>() / Unsafe.SizeOf<TTo>())));
- }
-
- /// <summary>
- /// Creates a new readonly span over the portion of the target string.
- /// </summary>
- /// <param name="text">The target string.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is a null
- /// reference (Nothing in Visual Basic).</exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ReadOnlySpan<char> AsReadOnlySpan(this string text)
- {
- if (text == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
-
- return new ReadOnlySpan<char>(ref text.GetRawStringData(), text.Length);
- }
-
- /// <summary>
- /// Creates a new readonly span over the portion of the target string.
- /// </summary>
- /// <param name="text">The target string.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is a null
- /// reference (Nothing in Visual Basic).
- /// </exception>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> index is not in range (&lt;0 or &gt;text.Length).
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ReadOnlySpan<char> AsReadOnlySpan(this string text, int start)
- {
- if (text == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
-
- if ((uint)start > (uint)text.Length)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
-
- return new ReadOnlySpan<char>(ref Unsafe.Add(ref text.GetRawStringData(), start), text.Length - start);
- }
-
- /// <summary>
- /// Creates a new readonly span over the portion of the target string.
- /// </summary>
- /// <param name="text">The target string.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is a null
- /// reference (Nothing in Visual Basic).
- /// </exception>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> index or <paramref name="length"/> is not in range.
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ReadOnlySpan<char> AsReadOnlySpan(this string text, int start, int length)
- {
- if (text == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
-
- if ((uint)start > (uint)text.Length || (uint)length > (uint)(text.Length - start))
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
-
- return new ReadOnlySpan<char>(ref Unsafe.Add(ref text.GetRawStringData(), start), length);
- }
-
- internal static unsafe void CopyTo<T>(ref T destination, ref T source, int elementsCount)
- {
- if (Unsafe.AreSame(ref destination, ref source))
- return;
-
- if (elementsCount <= 1)
- {
- if (elementsCount == 1)
- {
- destination = source;
- }
- return;
- }
-
- nuint byteCount = (nuint)elementsCount * (nuint)Unsafe.SizeOf<T>();
- if (!RuntimeHelpers.IsReferenceOrContainsReferences<T>())
- {
- fixed (byte* pDestination = &Unsafe.As<T, byte>(ref destination))
- {
- fixed (byte* pSource = &Unsafe.As<T, byte>(ref source))
- {
- Buffer.Memmove(pDestination, pSource, byteCount);
- }
- }
- }
- else
- {
- RuntimeImports.RhBulkMoveWithWriteBarrier(
- ref Unsafe.As<T, byte>(ref destination),
- ref Unsafe.As<T, byte>(ref source),
- byteCount);
- }
- }
-
- internal static unsafe void ClearWithoutReferences(ref byte b, nuint byteLength)
- {
- if (byteLength == 0)
- return;
-
-#if CORECLR && (AMD64 || ARM64)
- if (byteLength > 4096) goto PInvoke;
- Unsafe.InitBlockUnaligned(ref b, 0, (uint)byteLength);
- return;
-#else
- // TODO: Optimize other platforms to be on par with AMD64 CoreCLR
- // Note: It's important that this switch handles lengths at least up to 22.
- // See notes below near the main loop for why.
-
- // The switch will be very fast since it can be implemented using a jump
- // table in assembly. See http://stackoverflow.com/a/449297/4077294 for more info.
-
- switch (byteLength)
- {
- case 1:
- b = 0;
- return;
- case 2:
- Unsafe.As<byte, short>(ref b) = 0;
- return;
- case 3:
- Unsafe.As<byte, short>(ref b) = 0;
- Unsafe.Add<byte>(ref b, 2) = 0;
- return;
- case 4:
- Unsafe.As<byte, int>(ref b) = 0;
- return;
- case 5:
- Unsafe.As<byte, int>(ref b) = 0;
- Unsafe.Add<byte>(ref b, 4) = 0;
- return;
- case 6:
- Unsafe.As<byte, int>(ref b) = 0;
- Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
- return;
- case 7:
- Unsafe.As<byte, int>(ref b) = 0;
- Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
- Unsafe.Add<byte>(ref b, 6) = 0;
- return;
- case 8:
-#if BIT64
- Unsafe.As<byte, long>(ref b) = 0;
-#else
- Unsafe.As<byte, int>(ref b) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
-#endif
- return;
- case 9:
-#if BIT64
- Unsafe.As<byte, long>(ref b) = 0;
-#else
- Unsafe.As<byte, int>(ref b) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
-#endif
- Unsafe.Add<byte>(ref b, 8) = 0;
- return;
- case 10:
-#if BIT64
- Unsafe.As<byte, long>(ref b) = 0;
-#else
- Unsafe.As<byte, int>(ref b) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
-#endif
- Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
- return;
- case 11:
-#if BIT64
- Unsafe.As<byte, long>(ref b) = 0;
-#else
- Unsafe.As<byte, int>(ref b) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
-#endif
- Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
- Unsafe.Add<byte>(ref b, 10) = 0;
- return;
- case 12:
-#if BIT64
- Unsafe.As<byte, long>(ref b) = 0;
-#else
- Unsafe.As<byte, int>(ref b) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
-#endif
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
- return;
- case 13:
-#if BIT64
- Unsafe.As<byte, long>(ref b) = 0;
-#else
- Unsafe.As<byte, int>(ref b) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
-#endif
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
- Unsafe.Add<byte>(ref b, 12) = 0;
- return;
- case 14:
-#if BIT64
- Unsafe.As<byte, long>(ref b) = 0;
-#else
- Unsafe.As<byte, int>(ref b) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
-#endif
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
- Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
- return;
- case 15:
-#if BIT64
- Unsafe.As<byte, long>(ref b) = 0;
-#else
- Unsafe.As<byte, int>(ref b) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
-#endif
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
- Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
- Unsafe.Add<byte>(ref b, 14) = 0;
- return;
- case 16:
-#if BIT64
- Unsafe.As<byte, long>(ref b) = 0;
- Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
-#else
- Unsafe.As<byte, int>(ref b) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
-#endif
- return;
- case 17:
-#if BIT64
- Unsafe.As<byte, long>(ref b) = 0;
- Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
-#else
- Unsafe.As<byte, int>(ref b) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
-#endif
- Unsafe.Add<byte>(ref b, 16) = 0;
- return;
- case 18:
-#if BIT64
- Unsafe.As<byte, long>(ref b) = 0;
- Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
-#else
- Unsafe.As<byte, int>(ref b) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
-#endif
- Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 16)) = 0;
- return;
- case 19:
-#if BIT64
- Unsafe.As<byte, long>(ref b) = 0;
- Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
-#else
- Unsafe.As<byte, int>(ref b) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
-#endif
- Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 16)) = 0;
- Unsafe.Add<byte>(ref b, 18) = 0;
- return;
- case 20:
-#if BIT64
- Unsafe.As<byte, long>(ref b) = 0;
- Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
-#else
- Unsafe.As<byte, int>(ref b) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
-#endif
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 16)) = 0;
- return;
- case 21:
-#if BIT64
- Unsafe.As<byte, long>(ref b) = 0;
- Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
-#else
- Unsafe.As<byte, int>(ref b) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
-#endif
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 16)) = 0;
- Unsafe.Add<byte>(ref b, 20) = 0;
- return;
- case 22:
-#if BIT64
- Unsafe.As<byte, long>(ref b) = 0;
- Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
-#else
- Unsafe.As<byte, int>(ref b) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
-#endif
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 16)) = 0;
- Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 20)) = 0;
- return;
- }
-
- // P/Invoke into the native version for large lengths
- if (byteLength >= 512) goto PInvoke;
-
- nuint i = 0; // byte offset at which we're copying
-
- if ((Unsafe.As<byte, int>(ref b) & 3) != 0)
- {
- if ((Unsafe.As<byte, int>(ref b) & 1) != 0)
- {
- Unsafe.AddByteOffset<byte>(ref b, i) = 0;
- i += 1;
- if ((Unsafe.As<byte, int>(ref b) & 2) != 0)
- goto IntAligned;
- }
- Unsafe.As<byte, short>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
- i += 2;
- }
-
- IntAligned:
-
- // On 64-bit IntPtr.Size == 8, so we want to advance to the next 8-aligned address. If
- // (int)b % 8 is 0, 5, 6, or 7, we will already have advanced by 0, 3, 2, or 1
- // bytes to the next aligned address (respectively), so do nothing. On the other hand,
- // if it is 1, 2, 3, or 4 we will want to copy-and-advance another 4 bytes until
- // we're aligned.
- // The thing 1, 2, 3, and 4 have in common that the others don't is that if you
- // subtract one from them, their 3rd lsb will not be set. Hence, the below check.
-
- if (((Unsafe.As<byte, int>(ref b) - 1) & 4) == 0)
- {
- Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
- i += 4;
- }
-
- nuint end = byteLength - 16;
- byteLength -= i; // lower 4 bits of byteLength represent how many bytes are left *after* the unrolled loop
-
- // We know due to the above switch-case that this loop will always run 1 iteration; max
- // bytes we clear before checking is 23 (7 to align the pointers, 16 for 1 iteration) so
- // the switch handles lengths 0-22.
- Debug.Assert(end >= 7 && i <= end);
-
- // This is separated out into a different variable, so the i + 16 addition can be
- // performed at the start of the pipeline and the loop condition does not have
- // a dependency on the writes.
- nuint counter;
-
- do
- {
- counter = i + 16;
-
- // This loop looks very costly since there appear to be a bunch of temporary values
- // being created with the adds, but the jit (for x86 anyways) will convert each of
- // these to use memory addressing operands.
-
- // So the only cost is a bit of code size, which is made up for by the fact that
- // we save on writes to b.
-
-#if BIT64
- Unsafe.As<byte, long>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
- Unsafe.As<byte, long>(ref Unsafe.AddByteOffset<byte>(ref b, i + 8)) = 0;
-#else
- Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
- Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i + 4)) = 0;
- Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i + 8)) = 0;
- Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i + 12)) = 0;
-#endif
-
- i = counter;
-
- // See notes above for why this wasn't used instead
- // i += 16;
- }
- while (counter <= end);
-
- if ((byteLength & 8) != 0)
- {
-#if BIT64
- Unsafe.As<byte, long>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
-#else
- Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
- Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i + 4)) = 0;
-#endif
- i += 8;
- }
- if ((byteLength & 4) != 0)
- {
- Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
- i += 4;
- }
- if ((byteLength & 2) != 0)
- {
- Unsafe.As<byte, short>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
- i += 2;
- }
- if ((byteLength & 1) != 0)
- {
- Unsafe.AddByteOffset<byte>(ref b, i) = 0;
- // We're not using i after this, so not needed
- // i += 1;
- }
-
- return;
-#endif
-
- PInvoke:
- RuntimeImports.RhZeroMemory(ref b, byteLength);
- }
-
- internal static unsafe void ClearWithReferences(ref IntPtr ip, nuint pointerSizeLength)
- {
- if (pointerSizeLength == 0)
- return;
-
- // TODO: Perhaps do switch casing to improve small size perf
-
- nuint i = 0;
- nuint n = 0;
- while ((n = i + 8) <= (pointerSizeLength))
- {
- Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 0) * (nuint)sizeof(IntPtr)) = default(IntPtr);
- Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 1) * (nuint)sizeof(IntPtr)) = default(IntPtr);
- Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 2) * (nuint)sizeof(IntPtr)) = default(IntPtr);
- Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 3) * (nuint)sizeof(IntPtr)) = default(IntPtr);
- Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 4) * (nuint)sizeof(IntPtr)) = default(IntPtr);
- Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 5) * (nuint)sizeof(IntPtr)) = default(IntPtr);
- Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 6) * (nuint)sizeof(IntPtr)) = default(IntPtr);
- Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 7) * (nuint)sizeof(IntPtr)) = default(IntPtr);
- i = n;
- }
- if ((n = i + 4) <= (pointerSizeLength))
- {
- Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 0) * (nuint)sizeof(IntPtr)) = default(IntPtr);
- Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 1) * (nuint)sizeof(IntPtr)) = default(IntPtr);
- Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 2) * (nuint)sizeof(IntPtr)) = default(IntPtr);
- Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 3) * (nuint)sizeof(IntPtr)) = default(IntPtr);
- i = n;
- }
- if ((n = i + 2) <= (pointerSizeLength))
- {
- Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 0) * (nuint)sizeof(IntPtr)) = default(IntPtr);
- Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 1) * (nuint)sizeof(IntPtr)) = default(IntPtr);
- i = n;
- }
- if ((i + 1) <= (pointerSizeLength))
- {
- Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 0) * (nuint)sizeof(IntPtr)) = default(IntPtr);
- }
- }
- }
-}
diff --git a/src/Common/src/CoreLib/System/Span.cs b/src/Common/src/CoreLib/System/Span.cs
index 5a813174d9..81288a7627 100644
--- a/src/Common/src/CoreLib/System/Span.cs
+++ b/src/Common/src/CoreLib/System/Span.cs
@@ -5,17 +5,12 @@
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;
+#if !FEATURE_PORTABLE_SPAN
using System.Runtime.Versioning;
-using Internal.Runtime.CompilerServices;
+#endif // !FEATURE_PORTABLE_SPAN
#pragma warning disable 0809 //warning CS0809: Obsolete member 'Span<T>.Equals(object)' overrides non-obsolete member 'object.Equals(object)'
-#if BIT64
-using nuint = System.UInt64;
-#else
-using nuint = System.UInt32;
-#endif
-
namespace System
{
/// <summary>
@@ -23,134 +18,17 @@ namespace System
/// or native memory, or to memory allocated on the stack. It is type- and memory-safe.
/// </summary>
[DebuggerTypeProxy(typeof(SpanDebugView<>))]
- [DebuggerDisplay("{DebuggerDisplay,nq}")]
- [NonVersionable]
- public readonly ref struct Span<T>
+ [DebuggerDisplay("{ToString(),raw}")]
+ public readonly ref partial struct Span<T>
{
- /// <summary>A byref or a native ptr.</summary>
- internal readonly ByReference<T> _pointer;
- /// <summary>The number of elements this Span contains.</summary>
-#if PROJECTN
- [Bound]
-#endif
- private readonly int _length;
-
- /// <summary>
- /// Creates a new span over the entirety of the target array.
- /// </summary>
- /// <param name="array">The target array.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
- /// reference (Nothing in Visual Basic).</exception>
- /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Span(T[] array)
- {
- if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- if (default(T) == null && array.GetType() != typeof(T[]))
- ThrowHelper.ThrowArrayTypeMismatchException();
-
- _pointer = new ByReference<T>(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()));
- _length = array.Length;
- }
-
- /// <summary>
- /// Creates a new span over the portion of the target array beginning
- /// at 'start' index and ending at 'end' index (exclusive).
- /// </summary>
- /// <param name="array">The target array.</param>
- /// <param name="start">The index at which to begin the span.</param>
- /// <param name="length">The number of items in the span.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
- /// reference (Nothing in Visual Basic).</exception>
- /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> or end index is not in the range (&lt;0 or &gt;=Length).
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Span(T[] array, int start, int length)
- {
- if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
- if (default(T) == null && array.GetType() != typeof(T[]))
- ThrowHelper.ThrowArrayTypeMismatchException();
- if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
- ThrowHelper.ThrowArgumentOutOfRangeException();
-
- _pointer = new ByReference<T>(ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), start));
- _length = length;
- }
-
- /// <summary>
- /// Creates a new span over the target unmanaged buffer. Clearly this
- /// is quite dangerous, because we are creating arbitrarily typed T's
- /// out of a void*-typed block of memory. And the length is not checked.
- /// But if this creation is correct, then all subsequent uses are correct.
- /// </summary>
- /// <param name="pointer">An unmanaged pointer to memory.</param>
- /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when <typeparamref name="T"/> is reference type or contains pointers and hence cannot be stored in unmanaged memory.
- /// </exception>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="length"/> is negative.
- /// </exception>
- [CLSCompliant(false)]
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public unsafe Span(void* pointer, int length)
- {
- if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
- ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
- if (length < 0)
- ThrowHelper.ThrowArgumentOutOfRangeException();
-
- _pointer = new ByReference<T>(ref Unsafe.As<byte, T>(ref *(byte*)pointer));
- _length = length;
- }
-
- /// <summary>
- /// Create a new span over a portion of a regular managed object. This can be useful
- /// if part of a managed object represents a "fixed array." This is dangerous because neither the
- /// <paramref name="length"/> is checked, nor <paramref name="obj"/> being null, nor the fact that
- /// "rawPointer" actually lies within <paramref name="obj"/>.
- /// </summary>
- /// <param name="obj">The managed object that contains the data to span over.</param>
- /// <param name="objectData">A reference to data within that object.</param>
- /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- [EditorBrowsable(EditorBrowsableState.Never)]
- public static Span<T> DangerousCreate(object obj, ref T objectData, int length) => new Span<T>(ref objectData, length);
-
- // Constructor for internal use only.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal Span(ref T ptr, int length)
- {
- Debug.Assert(length >= 0);
-
- _pointer = new ByReference<T>(ref ptr);
- _length = length;
- }
-
- //Debugger Display = {T[length]}
- private string DebuggerDisplay => string.Format("{{{0}[{1}]}}", typeof(T).Name, _length);
-
- /// <summary>
- /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element
- /// would have been stored. Such a reference can be used for pinning but must never be dereferenced.
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal ref T DangerousGetPinnableReference()
- {
- return ref _pointer.Value;
- }
-
/// <summary>
/// The number of items in the span.
/// </summary>
public int Length
{
+#if !FEATURE_PORTABLE_SPAN
[NonVersionable]
+#endif // !FEATURE_PORTABLE_SPAN
get
{
return _length;
@@ -162,7 +40,9 @@ namespace System
/// </summary>
public bool IsEmpty
{
+#if !FEATURE_PORTABLE_SPAN
[NonVersionable]
+#endif // !FEATURE_PORTABLE_SPAN
get
{
return _length == 0;
@@ -170,145 +50,6 @@ namespace System
}
/// <summary>
- /// Returns a reference to specified element of the Span.
- /// </summary>
- /// <param name="index"></param>
- /// <returns></returns>
- /// <exception cref="System.IndexOutOfRangeException">
- /// Thrown when index less than 0 or index greater than or equal to Length
- /// </exception>
- public ref T this[int index]
- {
-#if PROJECTN
- [BoundsChecking]
- get
- {
- return ref Unsafe.Add(ref _pointer.Value, index);
- }
-#else
- [Intrinsic]
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- [NonVersionable]
- get
- {
- if ((uint)index >= (uint)_length)
- ThrowHelper.ThrowIndexOutOfRangeException();
- return ref Unsafe.Add(ref _pointer.Value, index);
- }
-#endif
- }
-
- /// <summary>
- /// Clears the contents of this span.
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Clear()
- {
- if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
- {
- Span.ClearWithReferences(ref Unsafe.As<T, IntPtr>(ref _pointer.Value), (nuint)_length * (nuint)(Unsafe.SizeOf<T>() / sizeof(nuint)));
- }
- else
- {
- Span.ClearWithoutReferences(ref Unsafe.As<T, byte>(ref _pointer.Value), (nuint)_length * (nuint)Unsafe.SizeOf<T>());
- }
- }
-
- /// <summary>
- /// Fills the contents of this span with the given value.
- /// </summary>
- public void Fill(T value)
- {
- if (Unsafe.SizeOf<T>() == 1)
- {
- uint length = (uint)_length;
- if (length == 0)
- return;
-
- T tmp = value; // Avoid taking address of the "value" argument. It would regress performance of the loop below.
- Unsafe.InitBlockUnaligned(ref Unsafe.As<T, byte>(ref _pointer.Value), Unsafe.As<T, byte>(ref tmp), length);
- }
- else
- {
- // Do all math as nuint to avoid unnecessary 64->32->64 bit integer truncations
- nuint length = (uint)_length;
- if (length == 0)
- return;
-
- ref T r = ref DangerousGetPinnableReference();
-
- // TODO: Create block fill for value types of power of two sizes e.g. 2,4,8,16
-
- nuint elementSize = (uint)Unsafe.SizeOf<T>();
- nuint i = 0;
- for (; i < (length & ~(nuint)7); i += 8)
- {
- Unsafe.AddByteOffset<T>(ref r, (i + 0) * elementSize) = value;
- Unsafe.AddByteOffset<T>(ref r, (i + 1) * elementSize) = value;
- Unsafe.AddByteOffset<T>(ref r, (i + 2) * elementSize) = value;
- Unsafe.AddByteOffset<T>(ref r, (i + 3) * elementSize) = value;
- Unsafe.AddByteOffset<T>(ref r, (i + 4) * elementSize) = value;
- Unsafe.AddByteOffset<T>(ref r, (i + 5) * elementSize) = value;
- Unsafe.AddByteOffset<T>(ref r, (i + 6) * elementSize) = value;
- Unsafe.AddByteOffset<T>(ref r, (i + 7) * elementSize) = value;
- }
- if (i < (length & ~(nuint)3))
- {
- Unsafe.AddByteOffset<T>(ref r, (i + 0) * elementSize) = value;
- Unsafe.AddByteOffset<T>(ref r, (i + 1) * elementSize) = value;
- Unsafe.AddByteOffset<T>(ref r, (i + 2) * elementSize) = value;
- Unsafe.AddByteOffset<T>(ref r, (i + 3) * elementSize) = value;
- i += 4;
- }
- for (; i < length; i++)
- {
- Unsafe.AddByteOffset<T>(ref r, i * elementSize) = value;
- }
- }
- }
-
- /// <summary>
- /// Copies the contents of this span into destination span. If the source
- /// and destinations overlap, this method behaves as if the original values in
- /// a temporary location before the destination is overwritten.
- /// </summary>
- /// <param name="destination">The span to copy items into.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when the destination Span is shorter than the source Span.
- /// </exception>
- public void CopyTo(Span<T> destination)
- {
- if (!TryCopyTo(destination))
- ThrowHelper.ThrowArgumentException_DestinationTooShort();
- }
-
- /// <summary>
- /// Copies the contents of this span into destination span. If the source
- /// and destinations overlap, this method behaves as if the original values in
- /// a temporary location before the destination is overwritten.
- /// </summary>
- /// <param name="destination">The span to copy items into.</param>
- /// <returns>If the destination span is shorter than the source span, this method
- /// return false and no data is written to the destination.</returns>
- public bool TryCopyTo(Span<T> destination)
- {
- if ((uint)_length > (uint)destination.Length)
- return false;
-
- Span.CopyTo<T>(ref destination._pointer.Value, ref _pointer.Value, _length);
- return true;
- }
-
- /// <summary>
- /// Returns true if left and right point at the same memory and have the same length. Note that
- /// this does *not* check to see if the *contents* are equal.
- /// </summary>
- public static bool operator ==(Span<T> left, Span<T> right)
- {
- return left._length == right._length && Unsafe.AreSame<T>(ref left._pointer.Value, ref right._pointer.Value);
- }
-
- /// <summary>
/// Returns false if left and right point at the same memory and have the same length. Note that
/// this does *not* check to see if the *contents* are equal.
/// </summary>
@@ -343,69 +84,15 @@ namespace System
/// <summary>
/// Defines an implicit conversion of an array to a <see cref="Span{T}"/>
/// </summary>
- public static implicit operator Span<T>(T[] array) => array != null ? new Span<T>(array) : default;
+ public static implicit operator Span<T>(T[] array) => new Span<T>(array);
/// <summary>
/// Defines an implicit conversion of a <see cref="ArraySegment{T}"/> to a <see cref="Span{T}"/>
/// </summary>
- public static implicit operator Span<T>(ArraySegment<T> arraySegment)
- => arraySegment.Array != null ? new Span<T>(arraySegment.Array, arraySegment.Offset, arraySegment.Count) : default;
-
- /// <summary>
- /// Defines an implicit conversion of a <see cref="Span{T}"/> to a <see cref="ReadOnlySpan{T}"/>
- /// </summary>
- public static implicit operator ReadOnlySpan<T>(Span<T> span) => new ReadOnlySpan<T>(ref span._pointer.Value, span._length);
-
- /// <summary>
- /// Forms a slice out of the given span, beginning at 'start'.
- /// </summary>
- /// <param name="start">The index at which to begin this slice.</param>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> index is not in range (&lt;0 or &gt;=Length).
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Span<T> Slice(int start)
- {
- if ((uint)start > (uint)_length)
- ThrowHelper.ThrowArgumentOutOfRangeException();
-
- return new Span<T>(ref Unsafe.Add(ref _pointer.Value, start), _length - start);
- }
-
- /// <summary>
- /// Forms a slice out of the given span, beginning at 'start', of given length
- /// </summary>
- /// <param name="start">The index at which to begin this slice.</param>
- /// <param name="length">The desired length for the slice (exclusive).</param>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> or end index is not in range (&lt;0 or &gt;=Length).
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Span<T> Slice(int start, int length)
- {
- if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
- ThrowHelper.ThrowArgumentOutOfRangeException();
-
- return new Span<T>(ref Unsafe.Add(ref _pointer.Value, start), length);
- }
+ public static implicit operator Span<T>(ArraySegment<T> segment)
+ => new Span<T>(segment.Array, segment.Offset, segment.Count);
/// <summary>
- /// Copies the contents of this span into a new array. This heap
- /// allocates, so should generally be avoided, however it is sometimes
- /// necessary to bridge the gap with APIs written in terms of arrays.
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public T[] ToArray()
- {
- if (_length == 0)
- return Array.Empty<T>();
-
- var destination = new T[_length];
- Span.CopyTo<T>(ref Unsafe.As<byte, T>(ref destination.GetRawSzArrayData()), ref _pointer.Value, _length);
- return destination;
- }
-
- // <summary>
/// Returns an empty <see cref="Span{T}"/>
/// </summary>
public static Span<T> Empty => default(Span<T>);
diff --git a/src/System.Memory/src/System/SpanHelpers.BinarySearch.cs b/src/Common/src/CoreLib/System/SpanHelpers.BinarySearch.cs
index cfd64f1e40..656b864e22 100644
--- a/src/System.Memory/src/System/SpanHelpers.BinarySearch.cs
+++ b/src/Common/src/CoreLib/System/SpanHelpers.BinarySearch.cs
@@ -15,7 +15,7 @@ namespace System
internal static partial class SpanHelpers
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static int BinarySearch<T, TComparable>(
+ public static int BinarySearch<T, TComparable>(
this ReadOnlySpan<T> span, TComparable comparable)
where TComparable : IComparable<T>
{
@@ -25,7 +25,7 @@ namespace System
return BinarySearch(ref MemoryMarshal.GetReference(span), span.Length, comparable);
}
- internal static int BinarySearch<T, TComparable>(
+ public static int BinarySearch<T, TComparable>(
ref T spanStart, int length, TComparable comparable)
where TComparable : IComparable<T>
{
diff --git a/src/System.Memory/src/System/SpanHelpers.byte.cs b/src/Common/src/CoreLib/System/SpanHelpers.Byte.cs
index e3c350d7a7..f6be744081 100644
--- a/src/System.Memory/src/System/SpanHelpers.byte.cs
+++ b/src/Common/src/CoreLib/System/SpanHelpers.Byte.cs
@@ -4,7 +4,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Diagnostics;
+using System.Diagnostics.Private;
using System.Runtime.CompilerServices;
#if !netstandard
@@ -15,9 +15,15 @@ using Internal.Runtime.CompilerServices;
using System.Numerics;
#endif
-#if MONO
-using System.Diagnostics.Private;
-#endif
+#if netstandard
+using nuint = System.NUInt;
+#else
+#if BIT64
+using nuint = System.UInt64;
+#else
+using nuint = System.UInt32;
+#endif // BIT64
+#endif // netstandard
namespace System
{
@@ -104,16 +110,13 @@ namespace System
Debug.Assert(length >= 0);
uint uValue = value; // Use uint for comparisons to avoid unnecessary 8->32 extensions
- IntPtr index = (IntPtr)0; // Use UIntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
- IntPtr nLength = (IntPtr)(uint)length;
+ IntPtr index = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
+ IntPtr nLength = (IntPtr)length;
#if !netstandard11
if (Vector.IsHardwareAccelerated && length >= Vector<byte>.Count * 2)
{
- unchecked
- {
- int unaligned = (int)(byte*)Unsafe.AsPointer(ref searchSpace) & (Vector<byte>.Count - 1);
- nLength = (IntPtr)(uint)((Vector<byte>.Count - unaligned) & (Vector<byte>.Count - 1));
- }
+ int unaligned = (int)Unsafe.AsPointer(ref searchSpace) & (Vector<byte>.Count - 1);
+ nLength = (IntPtr)((Vector<byte>.Count - unaligned) & (Vector<byte>.Count - 1));
}
SequentialScan:
#endif
@@ -121,21 +124,21 @@ namespace System
{
nLength -= 8;
- if (uValue == Unsafe.Add(ref searchSpace, index))
+ if (uValue == Unsafe.AddByteOffset(ref searchSpace, index))
goto Found;
- if (uValue == Unsafe.Add(ref searchSpace, index + 1))
+ if (uValue == Unsafe.AddByteOffset(ref searchSpace, index + 1))
goto Found1;
- if (uValue == Unsafe.Add(ref searchSpace, index + 2))
+ if (uValue == Unsafe.AddByteOffset(ref searchSpace, index + 2))
goto Found2;
- if (uValue == Unsafe.Add(ref searchSpace, index + 3))
+ if (uValue == Unsafe.AddByteOffset(ref searchSpace, index + 3))
goto Found3;
- if (uValue == Unsafe.Add(ref searchSpace, index + 4))
+ if (uValue == Unsafe.AddByteOffset(ref searchSpace, index + 4))
goto Found4;
- if (uValue == Unsafe.Add(ref searchSpace, index + 5))
+ if (uValue == Unsafe.AddByteOffset(ref searchSpace, index + 5))
goto Found5;
- if (uValue == Unsafe.Add(ref searchSpace, index + 6))
+ if (uValue == Unsafe.AddByteOffset(ref searchSpace, index + 6))
goto Found6;
- if (uValue == Unsafe.Add(ref searchSpace, index + 7))
+ if (uValue == Unsafe.AddByteOffset(ref searchSpace, index + 7))
goto Found7;
index += 8;
@@ -145,13 +148,13 @@ namespace System
{
nLength -= 4;
- if (uValue == Unsafe.Add(ref searchSpace, index))
+ if (uValue == Unsafe.AddByteOffset(ref searchSpace, index))
goto Found;
- if (uValue == Unsafe.Add(ref searchSpace, index + 1))
+ if (uValue == Unsafe.AddByteOffset(ref searchSpace, index + 1))
goto Found1;
- if (uValue == Unsafe.Add(ref searchSpace, index + 2))
+ if (uValue == Unsafe.AddByteOffset(ref searchSpace, index + 2))
goto Found2;
- if (uValue == Unsafe.Add(ref searchSpace, index + 3))
+ if (uValue == Unsafe.AddByteOffset(ref searchSpace, index + 3))
goto Found3;
index += 4;
@@ -161,7 +164,7 @@ namespace System
{
nLength -= 1;
- if (uValue == Unsafe.Add(ref searchSpace, index))
+ if (uValue == Unsafe.AddByteOffset(ref searchSpace, index))
goto Found;
index += 1;
@@ -169,9 +172,11 @@ namespace System
#if !netstandard11
if (Vector.IsHardwareAccelerated && ((int)(byte*)index < length))
{
- nLength = (IntPtr)(uint)((length - (uint)index) & ~(Vector<byte>.Count - 1));
+ nLength = (IntPtr)((length - (int)(byte*)index) & ~(Vector<byte>.Count - 1));
+
// Get comparison Vector
Vector<byte> vComparison = GetVector(value);
+
while ((byte*)nLength > (byte*)index)
{
var vMatches = Vector.Equals(vComparison, Unsafe.ReadUnaligned<Vector<byte>>(ref Unsafe.AddByteOffset(ref searchSpace, index)));
@@ -186,10 +191,7 @@ namespace System
if ((int)(byte*)index < length)
{
- unchecked
- {
- nLength = (IntPtr)(length - (int)(byte*)index);
- }
+ nLength = (IntPtr)(length - (int)(byte*)index);
goto SequentialScan;
}
}
@@ -252,16 +254,13 @@ namespace System
Debug.Assert(length >= 0);
uint uValue = value; // Use uint for comparisons to avoid unnecessary 8->32 extensions
- IntPtr index = (IntPtr)(uint)length; // Use UIntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
- IntPtr nLength = (IntPtr)(uint)length;
+ IntPtr index = (IntPtr)length; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
+ IntPtr nLength = (IntPtr)length;
#if !netstandard11
if (Vector.IsHardwareAccelerated && length >= Vector<byte>.Count * 2)
{
- unchecked
- {
- int unaligned = (int)(byte*)Unsafe.AsPointer(ref searchSpace) & (Vector<byte>.Count - 1);
- nLength = (IntPtr)(((length & (Vector<byte>.Count - 1)) + unaligned) & (Vector<byte>.Count - 1));
- }
+ int unaligned = (int)Unsafe.AsPointer(ref searchSpace) & (Vector<byte>.Count - 1);
+ nLength = (IntPtr)(((length & (Vector<byte>.Count - 1)) + unaligned) & (Vector<byte>.Count - 1));
}
SequentialScan:
#endif
@@ -270,21 +269,21 @@ namespace System
nLength -= 8;
index -= 8;
- if (uValue == Unsafe.Add(ref searchSpace, index + 7))
+ if (uValue == Unsafe.AddByteOffset(ref searchSpace, index + 7))
goto Found7;
- if (uValue == Unsafe.Add(ref searchSpace, index + 6))
+ if (uValue == Unsafe.AddByteOffset(ref searchSpace, index + 6))
goto Found6;
- if (uValue == Unsafe.Add(ref searchSpace, index + 5))
+ if (uValue == Unsafe.AddByteOffset(ref searchSpace, index + 5))
goto Found5;
- if (uValue == Unsafe.Add(ref searchSpace, index + 4))
+ if (uValue == Unsafe.AddByteOffset(ref searchSpace, index + 4))
goto Found4;
- if (uValue == Unsafe.Add(ref searchSpace, index + 3))
+ if (uValue == Unsafe.AddByteOffset(ref searchSpace, index + 3))
goto Found3;
- if (uValue == Unsafe.Add(ref searchSpace, index + 2))
+ if (uValue == Unsafe.AddByteOffset(ref searchSpace, index + 2))
goto Found2;
- if (uValue == Unsafe.Add(ref searchSpace, index + 1))
+ if (uValue == Unsafe.AddByteOffset(ref searchSpace, index + 1))
goto Found1;
- if (uValue == Unsafe.Add(ref searchSpace, index))
+ if (uValue == Unsafe.AddByteOffset(ref searchSpace, index))
goto Found;
}
@@ -293,13 +292,13 @@ namespace System
nLength -= 4;
index -= 4;
- if (uValue == Unsafe.Add(ref searchSpace, index + 3))
+ if (uValue == Unsafe.AddByteOffset(ref searchSpace, index + 3))
goto Found3;
- if (uValue == Unsafe.Add(ref searchSpace, index + 2))
+ if (uValue == Unsafe.AddByteOffset(ref searchSpace, index + 2))
goto Found2;
- if (uValue == Unsafe.Add(ref searchSpace, index + 1))
+ if (uValue == Unsafe.AddByteOffset(ref searchSpace, index + 1))
goto Found1;
- if (uValue == Unsafe.Add(ref searchSpace, index))
+ if (uValue == Unsafe.AddByteOffset(ref searchSpace, index))
goto Found;
}
@@ -308,16 +307,17 @@ namespace System
nLength -= 1;
index -= 1;
- if (uValue == Unsafe.Add(ref searchSpace, index))
+ if (uValue == Unsafe.AddByteOffset(ref searchSpace, index))
goto Found;
}
#if !netstandard11
- if (Vector.IsHardwareAccelerated && ((int)(byte*)index > 0))
+ if (Vector.IsHardwareAccelerated && ((byte*)index > (byte*)0))
{
- nLength = (IntPtr)(uint)((uint)index & ~(Vector<byte>.Count - 1));
+ nLength = (IntPtr)((int)(byte*)index & ~(Vector<byte>.Count - 1));
// Get comparison Vector
Vector<byte> vComparison = GetVector(value);
+
while ((byte*)nLength > (byte*)(Vector<byte>.Count - 1))
{
var vMatches = Vector.Equals(vComparison, Unsafe.ReadUnaligned<Vector<byte>>(ref Unsafe.AddByteOffset(ref searchSpace, index - Vector<byte>.Count)));
@@ -328,9 +328,9 @@ namespace System
continue;
}
// Find offset of first match
- return (int)(byte*)(index) - Vector<byte>.Count + LocateLastFoundByte(vMatches);
+ return (int)(index) - Vector<byte>.Count + LocateLastFoundByte(vMatches);
}
- if ((int)(byte*)index > 0)
+ if ((byte*)index > (byte*)0)
{
nLength = index;
goto SequentialScan;
@@ -362,16 +362,13 @@ namespace System
uint uValue0 = value0; // Use uint for comparisons to avoid unnecessary 8->32 extensions
uint uValue1 = value1; // Use uint for comparisons to avoid unnecessary 8->32 extensions
- IntPtr index = (IntPtr)0; // Use UIntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
- IntPtr nLength = (IntPtr)(uint)length;
+ IntPtr index = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
+ IntPtr nLength = (IntPtr)length;
#if !netstandard11
if (Vector.IsHardwareAccelerated && length >= Vector<byte>.Count * 2)
{
- unchecked
- {
- int unaligned = (int)(byte*)Unsafe.AsPointer(ref searchSpace) & (Vector<byte>.Count - 1);
- nLength = (IntPtr)(uint)((Vector<byte>.Count - unaligned) & (Vector<byte>.Count - 1));
- }
+ int unaligned = (int)Unsafe.AsPointer(ref searchSpace) & (Vector<byte>.Count - 1);
+ nLength = (IntPtr)((Vector<byte>.Count - unaligned) & (Vector<byte>.Count - 1));
}
SequentialScan:
#endif
@@ -380,28 +377,28 @@ namespace System
{
nLength -= 8;
- lookUp = Unsafe.Add(ref searchSpace, index);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index);
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found;
- lookUp = Unsafe.Add(ref searchSpace, index + 1);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 1);
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found1;
- lookUp = Unsafe.Add(ref searchSpace, index + 2);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 2);
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found2;
- lookUp = Unsafe.Add(ref searchSpace, index + 3);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 3);
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found3;
- lookUp = Unsafe.Add(ref searchSpace, index + 4);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 4);
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found4;
- lookUp = Unsafe.Add(ref searchSpace, index + 5);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 5);
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found5;
- lookUp = Unsafe.Add(ref searchSpace, index + 6);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 6);
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found6;
- lookUp = Unsafe.Add(ref searchSpace, index + 7);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 7);
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found7;
@@ -412,16 +409,16 @@ namespace System
{
nLength -= 4;
- lookUp = Unsafe.Add(ref searchSpace, index);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index);
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found;
- lookUp = Unsafe.Add(ref searchSpace, index + 1);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 1);
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found1;
- lookUp = Unsafe.Add(ref searchSpace, index + 2);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 2);
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found2;
- lookUp = Unsafe.Add(ref searchSpace, index + 3);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 3);
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found3;
@@ -432,7 +429,7 @@ namespace System
{
nLength -= 1;
- lookUp = Unsafe.Add(ref searchSpace, index);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index);
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found;
@@ -441,7 +438,8 @@ namespace System
#if !netstandard11
if (Vector.IsHardwareAccelerated && ((int)(byte*)index < length))
{
- nLength = (IntPtr)(uint)((length - (uint)index) & ~(Vector<byte>.Count - 1));
+ nLength = (IntPtr)((length - (int)(byte*)index) & ~(Vector<byte>.Count - 1));
+
// Get comparison Vector
Vector<byte> values0 = GetVector(value0);
Vector<byte> values1 = GetVector(value1);
@@ -463,10 +461,7 @@ namespace System
if ((int)(byte*)index < length)
{
- unchecked
- {
- nLength = (IntPtr)(length - (int)(byte*)index);
- }
+ nLength = (IntPtr)(length - (int)(byte*)index);
goto SequentialScan;
}
}
@@ -497,16 +492,13 @@ namespace System
uint uValue0 = value0; // Use uint for comparisons to avoid unnecessary 8->32 extensions
uint uValue1 = value1; // Use uint for comparisons to avoid unnecessary 8->32 extensions
uint uValue2 = value2; // Use uint for comparisons to avoid unnecessary 8->32 extensions
- IntPtr index = (IntPtr)0; // Use UIntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
- IntPtr nLength = (IntPtr)(uint)length;
+ IntPtr index = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
+ IntPtr nLength = (IntPtr)length;
#if !netstandard11
if (Vector.IsHardwareAccelerated && length >= Vector<byte>.Count * 2)
{
- unchecked
- {
- int unaligned = (int)(byte*)Unsafe.AsPointer(ref searchSpace) & (Vector<byte>.Count - 1);
- nLength = (IntPtr)(uint)((Vector<byte>.Count - unaligned) & (Vector<byte>.Count - 1));
- }
+ int unaligned = (int)Unsafe.AsPointer(ref searchSpace) & (Vector<byte>.Count - 1);
+ nLength = (IntPtr)((Vector<byte>.Count - unaligned) & (Vector<byte>.Count - 1));
}
SequentialScan:
#endif
@@ -515,28 +507,28 @@ namespace System
{
nLength -= 8;
- lookUp = Unsafe.Add(ref searchSpace, index);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index);
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found;
- lookUp = Unsafe.Add(ref searchSpace, index + 1);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 1);
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found1;
- lookUp = Unsafe.Add(ref searchSpace, index + 2);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 2);
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found2;
- lookUp = Unsafe.Add(ref searchSpace, index + 3);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 3);
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found3;
- lookUp = Unsafe.Add(ref searchSpace, index + 4);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 4);
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found4;
- lookUp = Unsafe.Add(ref searchSpace, index + 5);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 5);
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found5;
- lookUp = Unsafe.Add(ref searchSpace, index + 6);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 6);
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found6;
- lookUp = Unsafe.Add(ref searchSpace, index + 7);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 7);
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found7;
@@ -547,16 +539,16 @@ namespace System
{
nLength -= 4;
- lookUp = Unsafe.Add(ref searchSpace, index);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index);
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found;
- lookUp = Unsafe.Add(ref searchSpace, index + 1);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 1);
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found1;
- lookUp = Unsafe.Add(ref searchSpace, index + 2);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 2);
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found2;
- lookUp = Unsafe.Add(ref searchSpace, index + 3);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 3);
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found3;
@@ -567,7 +559,7 @@ namespace System
{
nLength -= 1;
- lookUp = Unsafe.Add(ref searchSpace, index);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index);
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found;
@@ -576,11 +568,13 @@ namespace System
#if !netstandard11
if (Vector.IsHardwareAccelerated && ((int)(byte*)index < length))
{
- nLength = (IntPtr)(uint)((length - (uint)index) & ~(Vector<byte>.Count - 1));
+ nLength = (IntPtr)((length - (int)(byte*)index) & ~(Vector<byte>.Count - 1));
+
// Get comparison Vector
Vector<byte> values0 = GetVector(value0);
Vector<byte> values1 = GetVector(value1);
Vector<byte> values2 = GetVector(value2);
+
while ((byte*)nLength > (byte*)index)
{
Vector<byte> vData = Unsafe.ReadUnaligned<Vector<byte>>(ref Unsafe.AddByteOffset(ref searchSpace, index));
@@ -602,10 +596,7 @@ namespace System
if ((int)(byte*)index < length)
{
- unchecked
- {
- nLength = (IntPtr)(length - (int)(byte*)index);
- }
+ nLength = (IntPtr)(length - (int)(byte*)index);
goto SequentialScan;
}
}
@@ -635,16 +626,13 @@ namespace System
uint uValue0 = value0; // Use uint for comparisons to avoid unnecessary 8->32 extensions
uint uValue1 = value1; // Use uint for comparisons to avoid unnecessary 8->32 extensions
- IntPtr index = (IntPtr)(uint)length; // Use UIntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
- IntPtr nLength = (IntPtr)(uint)length;
+ IntPtr index = (IntPtr)length; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
+ IntPtr nLength = (IntPtr)length;
#if !netstandard11
if (Vector.IsHardwareAccelerated && length >= Vector<byte>.Count * 2)
{
- unchecked
- {
- int unaligned = (int)(byte*)Unsafe.AsPointer(ref searchSpace) & (Vector<byte>.Count - 1);
- nLength = (IntPtr)(((length & (Vector<byte>.Count - 1)) + unaligned) & (Vector<byte>.Count - 1));
- }
+ int unaligned = (int)Unsafe.AsPointer(ref searchSpace) & (Vector<byte>.Count - 1);
+ nLength = (IntPtr)(((length & (Vector<byte>.Count - 1)) + unaligned) & (Vector<byte>.Count - 1));
}
SequentialScan:
#endif
@@ -654,28 +642,28 @@ namespace System
nLength -= 8;
index -= 8;
- lookUp = Unsafe.Add(ref searchSpace, index + 7);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 7);
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found7;
- lookUp = Unsafe.Add(ref searchSpace, index + 6);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 6);
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found6;
- lookUp = Unsafe.Add(ref searchSpace, index + 5);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 5);
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found5;
- lookUp = Unsafe.Add(ref searchSpace, index + 4);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 4);
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found4;
- lookUp = Unsafe.Add(ref searchSpace, index + 3);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 3);
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found3;
- lookUp = Unsafe.Add(ref searchSpace, index + 2);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 2);
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found2;
- lookUp = Unsafe.Add(ref searchSpace, index + 1);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 1);
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found1;
- lookUp = Unsafe.Add(ref searchSpace, index);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index);
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found;
}
@@ -685,16 +673,16 @@ namespace System
nLength -= 4;
index -= 4;
- lookUp = Unsafe.Add(ref searchSpace, index + 3);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 3);
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found3;
- lookUp = Unsafe.Add(ref searchSpace, index + 2);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 2);
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found2;
- lookUp = Unsafe.Add(ref searchSpace, index + 1);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 1);
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found1;
- lookUp = Unsafe.Add(ref searchSpace, index);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index);
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found;
}
@@ -704,14 +692,15 @@ namespace System
nLength -= 1;
index -= 1;
- lookUp = Unsafe.Add(ref searchSpace, index);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index);
if (uValue0 == lookUp || uValue1 == lookUp)
goto Found;
}
#if !netstandard11
- if (Vector.IsHardwareAccelerated && ((int)(byte*)index > 0))
+ if (Vector.IsHardwareAccelerated && ((byte*)index > (byte*)0))
{
- nLength = (IntPtr)(uint)((uint)index & ~(Vector<byte>.Count - 1));
+ nLength = (IntPtr)((int)(byte*)index & ~(Vector<byte>.Count - 1));
+
// Get comparison Vector
Vector<byte> values0 = GetVector(value0);
Vector<byte> values1 = GetVector(value1);
@@ -729,10 +718,10 @@ namespace System
continue;
}
// Find offset of first match
- return (int)(byte*)(index) - Vector<byte>.Count + LocateLastFoundByte(vMatches);
+ return (int)(index) - Vector<byte>.Count + LocateLastFoundByte(vMatches);
}
- if ((int)(byte*)index > 0)
+ if ((byte*)index > (byte*)0)
{
nLength = index;
goto SequentialScan;
@@ -765,16 +754,13 @@ namespace System
uint uValue0 = value0; // Use uint for comparisons to avoid unnecessary 8->32 extensions
uint uValue1 = value1; // Use uint for comparisons to avoid unnecessary 8->32 extensions
uint uValue2 = value2; // Use uint for comparisons to avoid unnecessary 8->32 extensions
- IntPtr index = (IntPtr)(uint)length; // Use UIntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
- IntPtr nLength = (IntPtr)(uint)length;
+ IntPtr index = (IntPtr)length; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
+ IntPtr nLength = (IntPtr)length;
#if !netstandard11
if (Vector.IsHardwareAccelerated && length >= Vector<byte>.Count * 2)
{
- unchecked
- {
- int unaligned = (int)(byte*)Unsafe.AsPointer(ref searchSpace) & (Vector<byte>.Count - 1);
- nLength = (IntPtr)(((length & (Vector<byte>.Count - 1)) + unaligned) & (Vector<byte>.Count - 1));
- }
+ int unaligned = (int)Unsafe.AsPointer(ref searchSpace) & (Vector<byte>.Count - 1);
+ nLength = (IntPtr)(((length & (Vector<byte>.Count - 1)) + unaligned) & (Vector<byte>.Count - 1));
}
SequentialScan:
#endif
@@ -784,28 +770,28 @@ namespace System
nLength -= 8;
index -= 8;
- lookUp = Unsafe.Add(ref searchSpace, index + 7);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 7);
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found7;
- lookUp = Unsafe.Add(ref searchSpace, index + 6);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 6);
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found6;
- lookUp = Unsafe.Add(ref searchSpace, index + 5);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 5);
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found5;
- lookUp = Unsafe.Add(ref searchSpace, index + 4);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 4);
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found4;
- lookUp = Unsafe.Add(ref searchSpace, index + 3);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 3);
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found3;
- lookUp = Unsafe.Add(ref searchSpace, index + 2);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 2);
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found2;
- lookUp = Unsafe.Add(ref searchSpace, index + 1);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 1);
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found1;
- lookUp = Unsafe.Add(ref searchSpace, index);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index);
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found;
}
@@ -815,16 +801,16 @@ namespace System
nLength -= 4;
index -= 4;
- lookUp = Unsafe.Add(ref searchSpace, index + 3);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 3);
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found3;
- lookUp = Unsafe.Add(ref searchSpace, index + 2);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 2);
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found2;
- lookUp = Unsafe.Add(ref searchSpace, index + 1);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index + 1);
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found1;
- lookUp = Unsafe.Add(ref searchSpace, index);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index);
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found;
}
@@ -834,18 +820,20 @@ namespace System
nLength -= 1;
index -= 1;
- lookUp = Unsafe.Add(ref searchSpace, index);
+ lookUp = Unsafe.AddByteOffset(ref searchSpace, index);
if (uValue0 == lookUp || uValue1 == lookUp || uValue2 == lookUp)
goto Found;
}
#if !netstandard11
- if (Vector.IsHardwareAccelerated && ((int)(byte*)index > 0))
+ if (Vector.IsHardwareAccelerated && ((byte*)index > (byte*)0))
{
- nLength = (IntPtr)(uint)((uint)index & ~(Vector<byte>.Count - 1));
+ nLength = (IntPtr)((int)(byte*)index & ~(Vector<byte>.Count - 1));
+
// Get comparison Vector
Vector<byte> values0 = GetVector(value0);
Vector<byte> values1 = GetVector(value1);
Vector<byte> values2 = GetVector(value2);
+
while ((byte*)nLength > (byte*)(Vector<byte>.Count - 1))
{
Vector<byte> vData = Unsafe.ReadUnaligned<Vector<byte>>(ref Unsafe.AddByteOffset(ref searchSpace, index - Vector<byte>.Count));
@@ -863,10 +851,10 @@ namespace System
continue;
}
// Find offset of first match
- return (int)(byte*)(index) - Vector<byte>.Count + LocateLastFoundByte(vMatches);
+ return (int)(index) - Vector<byte>.Count + LocateLastFoundByte(vMatches);
}
- if ((int)(byte*)index > 0)
+ if ((byte*)index > (byte*)0)
{
nLength = index;
goto SequentialScan;
@@ -892,15 +880,15 @@ namespace System
return (int)(byte*)(index + 7);
}
- public static unsafe bool SequenceEqual(ref byte first, ref byte second, int length)
+ // Optimized byte-based SequenceEquals. The "length" parameter for this one is declared a nuint rather than int as we also use it for types other than byte
+ // where the length can exceed 2Gb once scaled by sizeof(T).
+ public static unsafe bool SequenceEqual(ref byte first, ref byte second, nuint length)
{
- Debug.Assert(length >= 0);
-
if (Unsafe.AreSame(ref first, ref second))
goto Equal;
- IntPtr i = (IntPtr)0; // Use IntPtr and byte* for arithmetic to avoid unnecessary 64->32->64 truncations
- IntPtr n = (IntPtr)length;
+ IntPtr i = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
+ IntPtr n = (IntPtr)(void*)length;
#if !netstandard11
if (Vector.IsHardwareAccelerated && (byte*)n >= (byte*)Vector<byte>.Count)
@@ -981,11 +969,10 @@ namespace System
if (Unsafe.AreSame(ref first, ref second))
goto Equal;
- var minLength = firstLength;
- if (minLength > secondLength) minLength = secondLength;
+ IntPtr minLength = (IntPtr)((firstLength < secondLength) ? firstLength : secondLength);
- IntPtr i = (IntPtr)0; // Use IntPtr and byte* for arithmetic to avoid unnecessary 64->32->64 truncations
- IntPtr n = (IntPtr)minLength;
+ IntPtr i = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
+ IntPtr n = (IntPtr)(void*)minLength;
#if !netstandard11
if (Vector.IsHardwareAccelerated && (byte*)n > (byte*)Vector<byte>.Count)
@@ -1019,7 +1006,7 @@ namespace System
}
NotEqual: // Workaround for https://github.com/dotnet/coreclr/issues/13549
- while((byte*)minLength > (byte*)i)
+ while ((byte*)minLength > (byte*)i)
{
int result = Unsafe.AddByteOffset(ref first, i).CompareTo(Unsafe.AddByteOffset(ref second, i));
if (result != 0) return result;
@@ -1057,13 +1044,10 @@ namespace System
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int LocateFirstFoundByte(ulong match)
{
- unchecked
- {
- // Flag least significant power of two bit
- var powerOfTwoFlag = match ^ (match - 1);
- // Shift all powers of two into the high byte and extract
- return (int)((powerOfTwoFlag * XorPowerOfTwoToHighByte) >> 57);
- }
+ // Flag least significant power of two bit
+ var powerOfTwoFlag = match ^ (match - 1);
+ // Shift all powers of two into the high byte and extract
+ return (int)((powerOfTwoFlag * XorPowerOfTwoToHighByte) >> 57);
}
#endif
diff --git a/src/Common/src/CoreLib/System/SpanHelpers.Char.cs b/src/Common/src/CoreLib/System/SpanHelpers.Char.cs
new file mode 100644
index 0000000000..2033d8b906
--- /dev/null
+++ b/src/Common/src/CoreLib/System/SpanHelpers.Char.cs
@@ -0,0 +1,201 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+
+#if !netstandard
+using Internal.Runtime.CompilerServices;
+#endif
+
+#if !netstandard11
+using System.Numerics;
+#endif
+
+namespace System
+{
+ internal static partial class SpanHelpers
+ {
+ public static unsafe int SequenceCompareTo(ref char first, int firstLength, ref char second, int secondLength)
+ {
+ Debug.Assert(firstLength >= 0);
+ Debug.Assert(secondLength >= 0);
+
+ int lengthDelta = firstLength - secondLength;
+
+ if (Unsafe.AreSame(ref first, ref second))
+ goto Equal;
+
+ IntPtr minLength = (IntPtr)((firstLength < secondLength) ? firstLength : secondLength);
+ IntPtr i = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
+
+ if ((byte*)minLength >= (byte*)(sizeof(UIntPtr) / sizeof(char)))
+ {
+#if !netstandard11
+ if (Vector.IsHardwareAccelerated && (byte*)minLength >= (byte*)Vector<ushort>.Count)
+ {
+ IntPtr nLength = minLength - Vector<ushort>.Count;
+ do
+ {
+ if (Unsafe.ReadUnaligned<Vector<ushort>>(ref Unsafe.As<char, byte>(ref Unsafe.Add(ref first, i))) !=
+ Unsafe.ReadUnaligned<Vector<ushort>>(ref Unsafe.As<char, byte>(ref Unsafe.Add(ref second, i))))
+ {
+ break;
+ }
+ i += Vector<ushort>.Count;
+ }
+ while ((byte*)nLength >= (byte*)i);
+ }
+#endif
+
+ while ((byte*)minLength >= (byte*)(i + sizeof(UIntPtr) / sizeof(char)))
+ {
+ if (Unsafe.ReadUnaligned<UIntPtr>(ref Unsafe.As<char, byte>(ref Unsafe.Add(ref first, i))) !=
+ Unsafe.ReadUnaligned<UIntPtr>(ref Unsafe.As<char, byte>(ref Unsafe.Add(ref second, i))))
+ {
+ break;
+ }
+ i += sizeof(UIntPtr) / sizeof(char);
+ }
+ }
+
+ if (sizeof(UIntPtr) > sizeof(int) && (byte*)minLength >= (byte*)(i + sizeof(int) / sizeof(char)))
+ {
+ if (Unsafe.ReadUnaligned<int>(ref Unsafe.As<char, byte>(ref Unsafe.Add(ref first, i))) ==
+ Unsafe.ReadUnaligned<int>(ref Unsafe.As<char, byte>(ref Unsafe.Add(ref second, i))))
+ {
+ i += sizeof(int) / sizeof(char);
+ }
+ }
+
+ while ((byte*)i < (byte*)minLength)
+ {
+ int result = Unsafe.Add(ref first, i).CompareTo(Unsafe.Add(ref second, i));
+ if (result != 0) return result;
+ i += 1;
+ }
+
+ Equal:
+ return lengthDelta;
+ }
+
+ public static unsafe int IndexOf(ref char searchSpace, char value, int length)
+ {
+ Debug.Assert(length >= 0);
+
+ uint uValue = value; // Use uint for comparisons to avoid unnecessary 8->32 extensions
+ IntPtr index = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations
+ IntPtr nLength = (IntPtr)length;
+#if !netstandard11
+ if (Vector.IsHardwareAccelerated && length >= Vector<ushort>.Count * 2)
+ {
+ const int elementsPerByte = sizeof(ushort) / sizeof(byte);
+ int unaligned = ((int)Unsafe.AsPointer(ref searchSpace) & (Vector<byte>.Count - 1)) / elementsPerByte;
+ nLength = (IntPtr)((Vector<ushort>.Count - unaligned) & (Vector<ushort>.Count - 1));
+ }
+ SequentialScan:
+#endif
+ while ((byte*)nLength >= (byte*)4)
+ {
+ nLength -= 4;
+
+ if (uValue == Unsafe.Add(ref searchSpace, index))
+ goto Found;
+ if (uValue == Unsafe.Add(ref searchSpace, index + 1))
+ goto Found1;
+ if (uValue == Unsafe.Add(ref searchSpace, index + 2))
+ goto Found2;
+ if (uValue == Unsafe.Add(ref searchSpace, index + 3))
+ goto Found3;
+
+ index += 4;
+ }
+
+ while ((byte*)nLength > (byte*)0)
+ {
+ nLength -= 1;
+
+ if (uValue == Unsafe.Add(ref searchSpace, index))
+ goto Found;
+
+ index += 1;
+ }
+#if !netstandard11
+ if (Vector.IsHardwareAccelerated && ((int)(byte*)index < length))
+ {
+ nLength = (IntPtr)((length - (int)(byte*)index) & ~(Vector<ushort>.Count - 1));
+
+ // Get comparison Vector
+ Vector<ushort> vComparison = new Vector<ushort>(value);
+
+ while ((byte*)nLength > (byte*)index)
+ {
+ var vMatches = Vector.Equals(vComparison, Unsafe.ReadUnaligned<Vector<ushort>>(ref Unsafe.As<char, byte>(ref Unsafe.Add(ref searchSpace, index))));
+ if (Vector<ushort>.Zero.Equals(vMatches))
+ {
+ index += Vector<ushort>.Count;
+ continue;
+ }
+ // Find offset of first match
+ return (int)(byte*)index + LocateFirstFoundChar(vMatches);
+ }
+
+ if ((int)(byte*)index < length)
+ {
+ nLength = (IntPtr)(length - (int)(byte*)index);
+ goto SequentialScan;
+ }
+ }
+#endif
+ return -1;
+ Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549
+ return (int)(byte*)index;
+ Found1:
+ return (int)(byte*)(index + 1);
+ Found2:
+ return (int)(byte*)(index + 2);
+ Found3:
+ return (int)(byte*)(index + 3);
+ }
+
+#if !netstandard11
+ // Vector sub-search adapted from https://github.com/aspnet/KestrelHttpServer/pull/1138
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static int LocateFirstFoundChar(Vector<ushort> match)
+ {
+ var vector64 = Vector.AsVectorUInt64(match);
+ ulong candidate = 0;
+ int i = 0;
+ // Pattern unrolled by jit https://github.com/dotnet/coreclr/pull/8001
+ for (; i < Vector<ulong>.Count; i++)
+ {
+ candidate = vector64[i];
+ if (candidate != 0)
+ {
+ break;
+ }
+ }
+
+ // Single LEA instruction with jitted const (using function result)
+ return i * 4 + LocateFirstFoundChar(candidate);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static int LocateFirstFoundChar(ulong match)
+ {
+ unchecked
+ {
+ // Flag least significant power of two bit
+ var powerOfTwoFlag = match ^ (match - 1);
+ // Shift all powers of two into the high byte and extract
+ return (int)((powerOfTwoFlag * XorPowerOfTwoToHighChar) >> 49);
+ }
+ }
+
+ private const ulong XorPowerOfTwoToHighChar = (0x03ul |
+ 0x02ul << 16 |
+ 0x01ul << 32) + 1;
+#endif
+ }
+}
diff --git a/src/System.Memory/src/System/SpanHelpers.T.cs b/src/Common/src/CoreLib/System/SpanHelpers.T.cs
index 3c3f70bece..3e075d944b 100644
--- a/src/System.Memory/src/System/SpanHelpers.T.cs
+++ b/src/Common/src/CoreLib/System/SpanHelpers.T.cs
@@ -3,11 +3,14 @@
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
+using System.Runtime.CompilerServices;
#if !netstandard && !MONO
using Internal.Runtime.CompilerServices;
-#else
-using System.Runtime.CompilerServices;
+#endif
+
+#if !netstandard11
+using System.Numerics;
#endif
#if MONO
@@ -53,7 +56,7 @@ namespace System
}
return -1;
}
-
+
public static unsafe int IndexOf<T>(ref T searchSpace, T value, int length)
where T : IEquatable<T>
{
@@ -193,21 +196,21 @@ namespace System
}
return -1;
- Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549
+ Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549
return index;
- Found1:
+ Found1:
return index + 1;
- Found2:
+ Found2:
return index + 2;
- Found3:
+ Found3:
return index + 3;
- Found4:
+ Found4:
return index + 4;
- Found5:
+ Found5:
return index + 5;
- Found6:
+ Found6:
return index + 6;
- Found7:
+ Found7:
return index + 7;
}
@@ -276,21 +279,21 @@ namespace System
}
return -1;
- Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549
+ Found: // Workaround for https://github.com/dotnet/coreclr/issues/13549
return index;
- Found1:
+ Found1:
return index + 1;
- Found2:
+ Found2:
return index + 2;
- Found3:
+ Found3:
return index + 3;
- Found4:
+ Found4:
return index + 4;
- Found5:
+ Found5:
return index + 5;
- Found6:
+ Found6:
return index + 6;
- Found7:
+ Found7:
return index + 7;
}
diff --git a/src/Common/src/CoreLib/System/SpanHelpers.cs b/src/Common/src/CoreLib/System/SpanHelpers.cs
new file mode 100644
index 0000000000..c3cfe5a071
--- /dev/null
+++ b/src/Common/src/CoreLib/System/SpanHelpers.cs
@@ -0,0 +1,537 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Globalization;
+using System.Runtime;
+using System.Runtime.InteropServices;
+
+using Internal.Runtime.CompilerServices;
+
+#if BIT64
+using nuint = System.UInt64;
+#else
+using nuint = System.UInt32;
+#endif
+
+namespace System
+{
+ internal static partial class SpanHelpers
+ {
+ public static int IndexOfCultureHelper(ReadOnlySpan<char> span, ReadOnlySpan<char> value, CompareInfo compareInfo)
+ {
+ Debug.Assert(span.Length != 0);
+ Debug.Assert(value.Length != 0);
+
+ if (GlobalizationMode.Invariant)
+ {
+ return CompareInfo.InvariantIndexOf(span, value, ignoreCase: false);
+ }
+
+ return compareInfo.IndexOf(span, value, CompareOptions.None);
+ }
+
+ public static int IndexOfCultureIgnoreCaseHelper(ReadOnlySpan<char> span, ReadOnlySpan<char> value, CompareInfo compareInfo)
+ {
+ Debug.Assert(span.Length != 0);
+ Debug.Assert(value.Length != 0);
+
+ if (GlobalizationMode.Invariant)
+ {
+ return CompareInfo.InvariantIndexOf(span, value, ignoreCase: true);
+ }
+
+ return compareInfo.IndexOf(span, value, CompareOptions.IgnoreCase);
+ }
+
+ public static int IndexOfOrdinalHelper(ReadOnlySpan<char> span, ReadOnlySpan<char> value, bool ignoreCase)
+ {
+ Debug.Assert(span.Length != 0);
+ Debug.Assert(value.Length != 0);
+
+ if (GlobalizationMode.Invariant)
+ {
+ return CompareInfo.InvariantIndexOf(span, value, ignoreCase);
+ }
+
+ return CompareInfo.Invariant.IndexOfOrdinal(span, value, ignoreCase);
+ }
+
+ public static bool StartsWithCultureHelper(ReadOnlySpan<char> span, ReadOnlySpan<char> value, CompareInfo compareInfo)
+ {
+ Debug.Assert(value.Length != 0);
+
+ if (GlobalizationMode.Invariant)
+ {
+ return span.StartsWith(value);
+ }
+ if (span.Length == 0)
+ {
+ return false;
+ }
+ return compareInfo.IsPrefix(span, value, CompareOptions.None);
+ }
+
+ public static bool StartsWithCultureIgnoreCaseHelper(ReadOnlySpan<char> span, ReadOnlySpan<char> value, CompareInfo compareInfo)
+ {
+ Debug.Assert(value.Length != 0);
+
+ if (GlobalizationMode.Invariant)
+ {
+ return StartsWithOrdinalIgnoreCaseHelper(span, value);
+ }
+ if (span.Length == 0)
+ {
+ return false;
+ }
+ return compareInfo.IsPrefix(span, value, CompareOptions.IgnoreCase);
+ }
+
+ public static bool StartsWithOrdinalIgnoreCaseHelper(ReadOnlySpan<char> span, ReadOnlySpan<char> value)
+ {
+ Debug.Assert(value.Length != 0);
+
+ if (span.Length < value.Length)
+ {
+ return false;
+ }
+ return CompareInfo.CompareOrdinalIgnoreCase(span.Slice(0, value.Length), value) == 0;
+ }
+
+ public static bool EndsWithCultureHelper(ReadOnlySpan<char> span, ReadOnlySpan<char> value, CompareInfo compareInfo)
+ {
+ Debug.Assert(value.Length != 0);
+
+ if (GlobalizationMode.Invariant)
+ {
+ return span.EndsWith(value);
+ }
+ if (span.Length == 0)
+ {
+ return false;
+ }
+ return compareInfo.IsSuffix(span, value, CompareOptions.None);
+ }
+
+ public static bool EndsWithCultureIgnoreCaseHelper(ReadOnlySpan<char> span, ReadOnlySpan<char> value, CompareInfo compareInfo)
+ {
+ Debug.Assert(value.Length != 0);
+
+ if (GlobalizationMode.Invariant)
+ {
+ return EndsWithOrdinalIgnoreCaseHelper(span, value);
+ }
+ if (span.Length == 0)
+ {
+ return false;
+ }
+ return compareInfo.IsSuffix(span, value, CompareOptions.IgnoreCase);
+ }
+
+ public static bool EndsWithOrdinalIgnoreCaseHelper(ReadOnlySpan<char> span, ReadOnlySpan<char> value)
+ {
+ Debug.Assert(value.Length != 0);
+
+ if (span.Length < value.Length)
+ {
+ return false;
+ }
+ return (CompareInfo.CompareOrdinalIgnoreCase(span.Slice(span.Length - value.Length), value) == 0);
+ }
+
+ public static unsafe void ClearWithoutReferences(ref byte b, nuint byteLength)
+ {
+ if (byteLength == 0)
+ return;
+
+#if CORECLR && (AMD64 || ARM64)
+ if (byteLength > 4096)
+ goto PInvoke;
+ Unsafe.InitBlockUnaligned(ref b, 0, (uint)byteLength);
+ return;
+#else
+ // TODO: Optimize other platforms to be on par with AMD64 CoreCLR
+ // Note: It's important that this switch handles lengths at least up to 22.
+ // See notes below near the main loop for why.
+
+ // The switch will be very fast since it can be implemented using a jump
+ // table in assembly. See http://stackoverflow.com/a/449297/4077294 for more info.
+
+ switch (byteLength)
+ {
+ case 1:
+ b = 0;
+ return;
+ case 2:
+ Unsafe.As<byte, short>(ref b) = 0;
+ return;
+ case 3:
+ Unsafe.As<byte, short>(ref b) = 0;
+ Unsafe.Add<byte>(ref b, 2) = 0;
+ return;
+ case 4:
+ Unsafe.As<byte, int>(ref b) = 0;
+ return;
+ case 5:
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.Add<byte>(ref b, 4) = 0;
+ return;
+ case 6:
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+ return;
+ case 7:
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+ Unsafe.Add<byte>(ref b, 6) = 0;
+ return;
+ case 8:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+#endif
+ return;
+ case 9:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+#endif
+ Unsafe.Add<byte>(ref b, 8) = 0;
+ return;
+ case 10:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+#endif
+ Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+ return;
+ case 11:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+#endif
+ Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+ Unsafe.Add<byte>(ref b, 10) = 0;
+ return;
+ case 12:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+#endif
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+ return;
+ case 13:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+#endif
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+ Unsafe.Add<byte>(ref b, 12) = 0;
+ return;
+ case 14:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+#endif
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+ Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
+ return;
+ case 15:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+#endif
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+ Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
+ Unsafe.Add<byte>(ref b, 14) = 0;
+ return;
+ case 16:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+ Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
+#endif
+ return;
+ case 17:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+ Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
+#endif
+ Unsafe.Add<byte>(ref b, 16) = 0;
+ return;
+ case 18:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+ Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
+#endif
+ Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 16)) = 0;
+ return;
+ case 19:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+ Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
+#endif
+ Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 16)) = 0;
+ Unsafe.Add<byte>(ref b, 18) = 0;
+ return;
+ case 20:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+ Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
+#endif
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 16)) = 0;
+ return;
+ case 21:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+ Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
+#endif
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 16)) = 0;
+ Unsafe.Add<byte>(ref b, 20) = 0;
+ return;
+ case 22:
+#if BIT64
+ Unsafe.As<byte, long>(ref b) = 0;
+ Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+#else
+ Unsafe.As<byte, int>(ref b) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
+#endif
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 16)) = 0;
+ Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 20)) = 0;
+ return;
+ }
+
+ // P/Invoke into the native version for large lengths
+ if (byteLength >= 512) goto PInvoke;
+
+ nuint i = 0; // byte offset at which we're copying
+
+ if ((Unsafe.As<byte, int>(ref b) & 3) != 0)
+ {
+ if ((Unsafe.As<byte, int>(ref b) & 1) != 0)
+ {
+ Unsafe.AddByteOffset<byte>(ref b, i) = 0;
+ i += 1;
+ if ((Unsafe.As<byte, int>(ref b) & 2) != 0)
+ goto IntAligned;
+ }
+ Unsafe.As<byte, short>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
+ i += 2;
+ }
+
+ IntAligned:
+
+ // On 64-bit IntPtr.Size == 8, so we want to advance to the next 8-aligned address. If
+ // (int)b % 8 is 0, 5, 6, or 7, we will already have advanced by 0, 3, 2, or 1
+ // bytes to the next aligned address (respectively), so do nothing. On the other hand,
+ // if it is 1, 2, 3, or 4 we will want to copy-and-advance another 4 bytes until
+ // we're aligned.
+ // The thing 1, 2, 3, and 4 have in common that the others don't is that if you
+ // subtract one from them, their 3rd lsb will not be set. Hence, the below check.
+
+ if (((Unsafe.As<byte, int>(ref b) - 1) & 4) == 0)
+ {
+ Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
+ i += 4;
+ }
+
+ nuint end = byteLength - 16;
+ byteLength -= i; // lower 4 bits of byteLength represent how many bytes are left *after* the unrolled loop
+
+ // We know due to the above switch-case that this loop will always run 1 iteration; max
+ // bytes we clear before checking is 23 (7 to align the pointers, 16 for 1 iteration) so
+ // the switch handles lengths 0-22.
+ Debug.Assert(end >= 7 && i <= end);
+
+ // This is separated out into a different variable, so the i + 16 addition can be
+ // performed at the start of the pipeline and the loop condition does not have
+ // a dependency on the writes.
+ nuint counter;
+
+ do
+ {
+ counter = i + 16;
+
+ // This loop looks very costly since there appear to be a bunch of temporary values
+ // being created with the adds, but the jit (for x86 anyways) will convert each of
+ // these to use memory addressing operands.
+
+ // So the only cost is a bit of code size, which is made up for by the fact that
+ // we save on writes to b.
+
+#if BIT64
+ Unsafe.As<byte, long>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
+ Unsafe.As<byte, long>(ref Unsafe.AddByteOffset<byte>(ref b, i + 8)) = 0;
+#else
+ Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i + 4)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i + 8)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i + 12)) = 0;
+#endif
+
+ i = counter;
+
+ // See notes above for why this wasn't used instead
+ // i += 16;
+ }
+ while (counter <= end);
+
+ if ((byteLength & 8) != 0)
+ {
+#if BIT64
+ Unsafe.As<byte, long>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
+#else
+ Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
+ Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i + 4)) = 0;
+#endif
+ i += 8;
+ }
+ if ((byteLength & 4) != 0)
+ {
+ Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
+ i += 4;
+ }
+ if ((byteLength & 2) != 0)
+ {
+ Unsafe.As<byte, short>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
+ i += 2;
+ }
+ if ((byteLength & 1) != 0)
+ {
+ Unsafe.AddByteOffset<byte>(ref b, i) = 0;
+ // We're not using i after this, so not needed
+ // i += 1;
+ }
+
+ return;
+#endif
+
+ PInvoke:
+ RuntimeImports.RhZeroMemory(ref b, byteLength);
+ }
+
+ public static unsafe void ClearWithReferences(ref IntPtr ip, nuint pointerSizeLength)
+ {
+ Debug.Assert((int)Unsafe.AsPointer(ref ip) % sizeof(IntPtr) == 0, "Should've been aligned on natural word boundary.");
+
+ // First write backward 8 natural words at a time.
+ // Writing backward allows us to get away with only simple modifications to the
+ // mov instruction's base and index registers between loop iterations.
+
+ for (; pointerSizeLength >= 8; pointerSizeLength -= 8)
+ {
+ Unsafe.Add(ref Unsafe.Add(ref ip, (IntPtr)pointerSizeLength), -1) = default(IntPtr);
+ Unsafe.Add(ref Unsafe.Add(ref ip, (IntPtr)pointerSizeLength), -2) = default(IntPtr);
+ Unsafe.Add(ref Unsafe.Add(ref ip, (IntPtr)pointerSizeLength), -3) = default(IntPtr);
+ Unsafe.Add(ref Unsafe.Add(ref ip, (IntPtr)pointerSizeLength), -4) = default(IntPtr);
+ Unsafe.Add(ref Unsafe.Add(ref ip, (IntPtr)pointerSizeLength), -5) = default(IntPtr);
+ Unsafe.Add(ref Unsafe.Add(ref ip, (IntPtr)pointerSizeLength), -6) = default(IntPtr);
+ Unsafe.Add(ref Unsafe.Add(ref ip, (IntPtr)pointerSizeLength), -7) = default(IntPtr);
+ Unsafe.Add(ref Unsafe.Add(ref ip, (IntPtr)pointerSizeLength), -8) = default(IntPtr);
+ }
+
+ Debug.Assert(pointerSizeLength <= 7);
+
+ // The logic below works by trying to minimize the number of branches taken for any
+ // given range of lengths. For example, the lengths [ 4 .. 7 ] are handled by a single
+ // branch, [ 2 .. 3 ] are handled by a single branch, and [ 1 ] is handled by a single
+ // branch.
+ //
+ // We can write both forward and backward as a perf improvement. For example,
+ // the lengths [ 4 .. 7 ] can be handled by zeroing out the first four natural
+ // words and the last 3 natural words. In the best case (length = 7), there are
+ // no overlapping writes. In the worst case (length = 4), there are three
+ // overlapping writes near the middle of the buffer. In perf testing, the
+ // penalty for performing duplicate writes is less expensive than the penalty
+ // for complex branching.
+
+ if (pointerSizeLength >= 4)
+ {
+ goto Write4To7;
+ }
+ else if (pointerSizeLength >= 2)
+ {
+ goto Write2To3;
+ }
+ else if (pointerSizeLength > 0)
+ {
+ goto Write1;
+ }
+ else
+ {
+ return; // nothing to write
+ }
+
+ Write4To7:
+ Debug.Assert(pointerSizeLength >= 4);
+
+ // Write first four and last three.
+ Unsafe.Add(ref ip, 2) = default(IntPtr);
+ Unsafe.Add(ref ip, 3) = default(IntPtr);
+ Unsafe.Add(ref Unsafe.Add(ref ip, (IntPtr)pointerSizeLength), -3) = default(IntPtr);
+ Unsafe.Add(ref Unsafe.Add(ref ip, (IntPtr)pointerSizeLength), -2) = default(IntPtr);
+
+ Write2To3:
+ Debug.Assert(pointerSizeLength >= 2);
+
+ // Write first two and last one.
+ Unsafe.Add(ref ip, 1) = default(IntPtr);
+ Unsafe.Add(ref Unsafe.Add(ref ip, (IntPtr)pointerSizeLength), -1) = default(IntPtr);
+
+ Write1:
+ Debug.Assert(pointerSizeLength >= 1);
+
+ // Write only element.
+ ip = default(IntPtr);
+ }
+ }
+}
diff --git a/src/Common/src/CoreLib/System/String.Comparison.cs b/src/Common/src/CoreLib/System/String.Comparison.cs
new file mode 100644
index 0000000000..2a8be32d3f
--- /dev/null
+++ b/src/Common/src/CoreLib/System/String.Comparison.cs
@@ -0,0 +1,1011 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+using Internal.Runtime.CompilerServices;
+
+#if BIT64
+using nuint = System.UInt64;
+#else
+using nuint = System.UInt32;
+#endif
+
+namespace System
+{
+ public partial class String
+ {
+ private static unsafe int CompareOrdinalIgnoreCaseHelper(string strA, string strB)
+ {
+ Debug.Assert(strA != null);
+ Debug.Assert(strB != null);
+ int length = Math.Min(strA.Length, strB.Length);
+
+ fixed (char* ap = &strA._firstChar) fixed (char* bp = &strB._firstChar)
+ {
+ char* a = ap;
+ char* b = bp;
+ int charA = 0, charB = 0;
+
+ while (length != 0)
+ {
+ charA = *a;
+ charB = *b;
+
+ Debug.Assert((charA | charB) <= 0x7F, "strings have to be ASCII");
+
+ // uppercase both chars - notice that we need just one compare per char
+ if ((uint)(charA - 'a') <= (uint)('z' - 'a')) charA -= 0x20;
+ if ((uint)(charB - 'a') <= (uint)('z' - 'a')) charB -= 0x20;
+
+ //Return the (case-insensitive) difference between them.
+ if (charA != charB)
+ return charA - charB;
+
+ // Next char
+ a++; b++;
+ length--;
+ }
+
+ return strA.Length - strB.Length;
+ }
+ }
+
+ //
+ // Search/Query methods
+ //
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static bool EqualsHelper(string strA, string strB)
+ {
+ Debug.Assert(strA != null);
+ Debug.Assert(strB != null);
+ Debug.Assert(strA.Length == strB.Length);
+
+ return SpanHelpers.SequenceEqual(
+ ref Unsafe.As<char, byte>(ref strA.GetRawStringData()),
+ ref Unsafe.As<char, byte>(ref strB.GetRawStringData()),
+ ((nuint)strA.Length) * 2);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static int CompareOrdinalHelper(string strA, int indexA, int countA, string strB, int indexB, int countB)
+ {
+ Debug.Assert(strA != null);
+ Debug.Assert(strB != null);
+ Debug.Assert(indexA >= 0 && indexB >= 0);
+ Debug.Assert(countA >= 0 && countB >= 0);
+ Debug.Assert(indexA + countA <= strA.Length && indexB + countB <= strB.Length);
+
+ return SpanHelpers.SequenceCompareTo(ref Unsafe.Add(ref strA.GetRawStringData(), indexA), countA, ref Unsafe.Add(ref strB.GetRawStringData(), indexB), countB);
+ }
+
+ private static unsafe bool EqualsIgnoreCaseAsciiHelper(string strA, string strB)
+ {
+ Debug.Assert(strA != null);
+ Debug.Assert(strB != null);
+ Debug.Assert(strA.Length == strB.Length);
+ int length = strA.Length;
+
+ fixed (char* ap = &strA._firstChar) fixed (char* bp = &strB._firstChar)
+ {
+ char* a = ap;
+ char* b = bp;
+
+ while (length != 0)
+ {
+ int charA = *a;
+ int charB = *b;
+
+ Debug.Assert((charA | charB) <= 0x7F, "strings have to be ASCII");
+
+ // Ordinal equals or lowercase equals if the result ends up in the a-z range
+ if (charA == charB ||
+ ((charA | 0x20) == (charB | 0x20) &&
+ (uint)((charA | 0x20) - 'a') <= (uint)('z' - 'a')))
+ {
+ a++;
+ b++;
+ length--;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+
+ private static unsafe int CompareOrdinalHelper(string strA, string strB)
+ {
+ Debug.Assert(strA != null);
+ Debug.Assert(strB != null);
+
+ // NOTE: This may be subject to change if eliminating the check
+ // in the callers makes them small enough to be inlined
+ Debug.Assert(strA._firstChar == strB._firstChar,
+ "For performance reasons, callers of this method should " +
+ "check/short-circuit beforehand if the first char is the same.");
+
+ int length = Math.Min(strA.Length, strB.Length);
+
+ fixed (char* ap = &strA._firstChar) fixed (char* bp = &strB._firstChar)
+ {
+ char* a = ap;
+ char* b = bp;
+
+ // Check if the second chars are different here
+ // The reason we check if _firstChar is different is because
+ // it's the most common case and allows us to avoid a method call
+ // to here.
+ // The reason we check if the second char is different is because
+ // if the first two chars the same we can increment by 4 bytes,
+ // leaving us word-aligned on both 32-bit (12 bytes into the string)
+ // and 64-bit (16 bytes) platforms.
+
+ // For empty strings, the second char will be null due to padding.
+ // The start of the string is the type pointer + string length, which
+ // takes up 8 bytes on 32-bit, 12 on x64. For empty strings the null
+ // terminator immediately follows, leaving us with an object
+ // 10/14 bytes in size. Since everything needs to be a multiple
+ // of 4/8, this will get padded and zeroed out.
+
+ // For one-char strings the second char will be the null terminator.
+
+ // NOTE: If in the future there is a way to read the second char
+ // without pinning the string (e.g. System.Runtime.CompilerServices.Unsafe
+ // is exposed to mscorlib, or a future version of C# allows inline IL),
+ // then do that and short-circuit before the fixed.
+
+ if (*(a + 1) != *(b + 1)) goto DiffOffset1;
+
+ // Since we know that the first two chars are the same,
+ // we can increment by 2 here and skip 4 bytes.
+ // This leaves us 8-byte aligned, which results
+ // on better perf for 64-bit platforms.
+ length -= 2; a += 2; b += 2;
+
+ // unroll the loop
+#if BIT64
+ while (length >= 12)
+ {
+ if (*(long*)a != *(long*)b) goto DiffOffset0;
+ if (*(long*)(a + 4) != *(long*)(b + 4)) goto DiffOffset4;
+ if (*(long*)(a + 8) != *(long*)(b + 8)) goto DiffOffset8;
+ length -= 12; a += 12; b += 12;
+ }
+#else // BIT64
+ while (length >= 10)
+ {
+ if (*(int*)a != *(int*)b) goto DiffOffset0;
+ if (*(int*)(a + 2) != *(int*)(b + 2)) goto DiffOffset2;
+ if (*(int*)(a + 4) != *(int*)(b + 4)) goto DiffOffset4;
+ if (*(int*)(a + 6) != *(int*)(b + 6)) goto DiffOffset6;
+ if (*(int*)(a + 8) != *(int*)(b + 8)) goto DiffOffset8;
+ length -= 10; a += 10; b += 10;
+ }
+#endif // BIT64
+
+ // Fallback loop:
+ // go back to slower code path and do comparison on 4 bytes at a time.
+ // This depends on the fact that the String objects are
+ // always zero terminated and that the terminating zero is not included
+ // in the length. For odd string sizes, the last compare will include
+ // the zero terminator.
+ while (length > 0)
+ {
+ if (*(int*)a != *(int*)b) goto DiffNextInt;
+ length -= 2;
+ a += 2;
+ b += 2;
+ }
+
+ // At this point, we have compared all the characters in at least one string.
+ // The longer string will be larger.
+ return strA.Length - strB.Length;
+
+#if BIT64
+ DiffOffset8: a += 4; b += 4;
+ DiffOffset4: a += 4; b += 4;
+#else // BIT64
+ // Use jumps instead of falling through, since
+ // otherwise going to DiffOffset8 will involve
+ // 8 add instructions before getting to DiffNextInt
+ DiffOffset8: a += 8; b += 8; goto DiffOffset0;
+ DiffOffset6: a += 6; b += 6; goto DiffOffset0;
+ DiffOffset4: a += 2; b += 2;
+ DiffOffset2: a += 2; b += 2;
+#endif // BIT64
+
+ DiffOffset0:
+ // If we reached here, we already see a difference in the unrolled loop above
+#if BIT64
+ if (*(int*)a == *(int*)b)
+ {
+ a += 2; b += 2;
+ }
+#endif // BIT64
+
+ DiffNextInt:
+ if (*a != *b) return *a - *b;
+
+ DiffOffset1:
+ Debug.Assert(*(a + 1) != *(b + 1), "This char must be different if we reach here!");
+ return *(a + 1) - *(b + 1);
+ }
+ }
+
+ // Provides a culture-correct string comparison. StrA is compared to StrB
+ // to determine whether it is lexicographically less, equal, or greater, and then returns
+ // either a negative integer, 0, or a positive integer; respectively.
+ //
+ public static int Compare(string strA, string strB)
+ {
+ return Compare(strA, strB, StringComparison.CurrentCulture);
+ }
+
+
+ // Provides a culture-correct string comparison. strA is compared to strB
+ // to determine whether it is lexicographically less, equal, or greater, and then a
+ // negative integer, 0, or a positive integer is returned; respectively.
+ // The case-sensitive option is set by ignoreCase
+ //
+ public static int Compare(string strA, string strB, bool ignoreCase)
+ {
+ var comparisonType = ignoreCase ? StringComparison.CurrentCultureIgnoreCase : StringComparison.CurrentCulture;
+ return Compare(strA, strB, comparisonType);
+ }
+
+
+ // Provides a more flexible function for string comparison. See StringComparison
+ // for meaning of different comparisonType.
+ public static int Compare(string strA, string strB, StringComparison comparisonType)
+ {
+ if (object.ReferenceEquals(strA, strB))
+ {
+ CheckStringComparison(comparisonType);
+ return 0;
+ }
+
+ // They can't both be null at this point.
+ if (strA == null)
+ {
+ CheckStringComparison(comparisonType);
+ return -1;
+ }
+ if (strB == null)
+ {
+ CheckStringComparison(comparisonType);
+ return 1;
+ }
+
+ switch (comparisonType)
+ {
+ case StringComparison.CurrentCulture:
+ return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.None);
+
+ case StringComparison.CurrentCultureIgnoreCase:
+ return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreCase);
+
+ case StringComparison.InvariantCulture:
+ return CompareInfo.Invariant.Compare(strA, strB, CompareOptions.None);
+
+ case StringComparison.InvariantCultureIgnoreCase:
+ return CompareInfo.Invariant.Compare(strA, strB, CompareOptions.IgnoreCase);
+
+ case StringComparison.Ordinal:
+ // Most common case: first character is different.
+ // Returns false for empty strings.
+ if (strA._firstChar != strB._firstChar)
+ {
+ return strA._firstChar - strB._firstChar;
+ }
+
+ return CompareOrdinalHelper(strA, strB);
+
+ case StringComparison.OrdinalIgnoreCase:
+#if CORECLR
+ // If both strings are ASCII strings, we can take the fast path.
+ if (strA.IsAscii() && strB.IsAscii())
+ {
+ return CompareOrdinalIgnoreCaseHelper(strA, strB);
+ }
+#endif
+ return CompareInfo.CompareOrdinalIgnoreCase(strA, strB);
+
+ default:
+ throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType));
+ }
+ }
+
+
+ // Provides a culture-correct string comparison. strA is compared to strB
+ // to determine whether it is lexicographically less, equal, or greater, and then a
+ // negative integer, 0, or a positive integer is returned; respectively.
+ //
+ public static int Compare(string strA, string strB, CultureInfo culture, CompareOptions options)
+ {
+ if (culture == null)
+ {
+ throw new ArgumentNullException(nameof(culture));
+ }
+
+ return culture.CompareInfo.Compare(strA, strB, options);
+ }
+
+
+
+ // Provides a culture-correct string comparison. strA is compared to strB
+ // to determine whether it is lexicographically less, equal, or greater, and then a
+ // negative integer, 0, or a positive integer is returned; respectively.
+ // The case-sensitive option is set by ignoreCase, and the culture is set
+ // by culture
+ //
+ public static int Compare(string strA, string strB, bool ignoreCase, CultureInfo culture)
+ {
+ var options = ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None;
+ return Compare(strA, strB, culture, options);
+ }
+
+ // Determines whether two string regions match. The substring of strA beginning
+ // at indexA of given length is compared with the substring of strB
+ // beginning at indexB of the same length.
+ //
+ public static int Compare(string strA, int indexA, string strB, int indexB, int length)
+ {
+ // NOTE: It's important we call the boolean overload, and not the StringComparison
+ // one. The two have some subtly different behavior (see notes in the former).
+ return Compare(strA, indexA, strB, indexB, length, ignoreCase: false);
+ }
+
+ // Determines whether two string regions match. The substring of strA beginning
+ // at indexA of given length is compared with the substring of strB
+ // beginning at indexB of the same length. Case sensitivity is determined by the ignoreCase boolean.
+ //
+ public static int Compare(string strA, int indexA, string strB, int indexB, int length, bool ignoreCase)
+ {
+ // Ideally we would just forward to the string.Compare overload that takes
+ // a StringComparison parameter, and just pass in CurrentCulture/CurrentCultureIgnoreCase.
+ // That function will return early if an optimization can be applied, e.g. if
+ // (object)strA == strB && indexA == indexB then it will return 0 straightaway.
+ // There are a couple of subtle behavior differences that prevent us from doing so
+ // however:
+ // - string.Compare(null, -1, null, -1, -1, StringComparison.CurrentCulture) works
+ // since that method also returns early for nulls before validation. It shouldn't
+ // for this overload.
+ // - Since we originally forwarded to CompareInfo.Compare for all of the argument
+ // validation logic, the ArgumentOutOfRangeExceptions thrown will contain different
+ // parameter names.
+ // Therefore, we have to duplicate some of the logic here.
+
+ int lengthA = length;
+ int lengthB = length;
+
+ if (strA != null)
+ {
+ lengthA = Math.Min(lengthA, strA.Length - indexA);
+ }
+
+ if (strB != null)
+ {
+ lengthB = Math.Min(lengthB, strB.Length - indexB);
+ }
+
+ var options = ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None;
+ return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, options);
+ }
+
+ // Determines whether two string regions match. The substring of strA beginning
+ // at indexA of length length is compared with the substring of strB
+ // beginning at indexB of the same length. Case sensitivity is determined by the ignoreCase boolean,
+ // and the culture is set by culture.
+ //
+ public static int Compare(string strA, int indexA, string strB, int indexB, int length, bool ignoreCase, CultureInfo culture)
+ {
+ var options = ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None;
+ return Compare(strA, indexA, strB, indexB, length, culture, options);
+ }
+
+
+ // Determines whether two string regions match. The substring of strA beginning
+ // at indexA of length length is compared with the substring of strB
+ // beginning at indexB of the same length.
+ //
+ public static int Compare(string strA, int indexA, string strB, int indexB, int length, CultureInfo culture, CompareOptions options)
+ {
+ if (culture == null)
+ {
+ throw new ArgumentNullException(nameof(culture));
+ }
+
+ int lengthA = length;
+ int lengthB = length;
+
+ if (strA != null)
+ {
+ lengthA = Math.Min(lengthA, strA.Length - indexA);
+ }
+
+ if (strB != null)
+ {
+ lengthB = Math.Min(lengthB, strB.Length - indexB);
+ }
+
+ return culture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, options);
+ }
+
+ public static int Compare(string strA, int indexA, string strB, int indexB, int length, StringComparison comparisonType)
+ {
+ CheckStringComparison(comparisonType);
+
+ if (strA == null || strB == null)
+ {
+
+ if (object.ReferenceEquals(strA, strB))
+ {
+ // They're both null
+ return 0;
+ }
+
+ return strA == null ? -1 : 1;
+ }
+
+ if (length < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_NegativeLength);
+ }
+
+ if (indexA < 0 || indexB < 0)
+ {
+ string paramName = indexA < 0 ? nameof(indexA) : nameof(indexB);
+ throw new ArgumentOutOfRangeException(paramName, SR.ArgumentOutOfRange_Index);
+ }
+
+ if (strA.Length - indexA < 0 || strB.Length - indexB < 0)
+ {
+ string paramName = strA.Length - indexA < 0 ? nameof(indexA) : nameof(indexB);
+ throw new ArgumentOutOfRangeException(paramName, SR.ArgumentOutOfRange_Index);
+ }
+
+ if (length == 0 || (object.ReferenceEquals(strA, strB) && indexA == indexB))
+ {
+ return 0;
+ }
+
+ int lengthA = Math.Min(length, strA.Length - indexA);
+ int lengthB = Math.Min(length, strB.Length - indexB);
+
+ switch (comparisonType)
+ {
+ case StringComparison.CurrentCulture:
+ return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.None);
+
+ case StringComparison.CurrentCultureIgnoreCase:
+ return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.IgnoreCase);
+
+ case StringComparison.InvariantCulture:
+ return CompareInfo.Invariant.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.None);
+
+ case StringComparison.InvariantCultureIgnoreCase:
+ return CompareInfo.Invariant.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.IgnoreCase);
+
+ case StringComparison.Ordinal:
+ return CompareOrdinalHelper(strA, indexA, lengthA, strB, indexB, lengthB);
+
+ case StringComparison.OrdinalIgnoreCase:
+ return CompareInfo.CompareOrdinalIgnoreCase(strA, indexA, lengthA, strB, indexB, lengthB);
+
+ default:
+ throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType));
+ }
+ }
+
+ // Compares strA and strB using an ordinal (code-point) comparison.
+ //
+ public static int CompareOrdinal(string strA, string strB)
+ {
+ if (object.ReferenceEquals(strA, strB))
+ {
+ return 0;
+ }
+
+ // They can't both be null at this point.
+ if (strA == null)
+ {
+ return -1;
+ }
+ if (strB == null)
+ {
+ return 1;
+ }
+
+ // Most common case, first character is different.
+ // This will return false for empty strings.
+ if (strA._firstChar != strB._firstChar)
+ {
+ return strA._firstChar - strB._firstChar;
+ }
+
+ return CompareOrdinalHelper(strA, strB);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static int CompareOrdinal(ReadOnlySpan<char> strA, ReadOnlySpan<char> strB)
+ => SpanHelpers.SequenceCompareTo(ref MemoryMarshal.GetReference(strA), strA.Length, ref MemoryMarshal.GetReference(strB), strB.Length);
+
+ // Compares strA and strB using an ordinal (code-point) comparison.
+ //
+ public static int CompareOrdinal(string strA, int indexA, string strB, int indexB, int length)
+ {
+ if (strA == null || strB == null)
+ {
+ if (object.ReferenceEquals(strA, strB))
+ {
+ // They're both null
+ return 0;
+ }
+
+ return strA == null ? -1 : 1;
+ }
+
+ // COMPAT: Checking for nulls should become before the arguments are validated,
+ // but other optimizations which allow us to return early should come after.
+
+ if (length < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_NegativeCount);
+ }
+
+ if (indexA < 0 || indexB < 0)
+ {
+ string paramName = indexA < 0 ? nameof(indexA) : nameof(indexB);
+ throw new ArgumentOutOfRangeException(paramName, SR.ArgumentOutOfRange_Index);
+ }
+
+ int lengthA = Math.Min(length, strA.Length - indexA);
+ int lengthB = Math.Min(length, strB.Length - indexB);
+
+ if (lengthA < 0 || lengthB < 0)
+ {
+ string paramName = lengthA < 0 ? nameof(indexA) : nameof(indexB);
+ throw new ArgumentOutOfRangeException(paramName, SR.ArgumentOutOfRange_Index);
+ }
+
+ if (length == 0 || (object.ReferenceEquals(strA, strB) && indexA == indexB))
+ {
+ return 0;
+ }
+
+ return CompareOrdinalHelper(strA, indexA, lengthA, strB, indexB, lengthB);
+ }
+
+ // Compares this String to another String (cast as object), returning an integer that
+ // indicates the relationship. This method returns a value less than 0 if this is less than value, 0
+ // if this is equal to value, or a value greater than 0 if this is greater than value.
+ //
+ public int CompareTo(object value)
+ {
+ if (value == null)
+ {
+ return 1;
+ }
+
+ string other = value as string;
+
+ if (other == null)
+ {
+ throw new ArgumentException(SR.Arg_MustBeString);
+ }
+
+ return CompareTo(other); // will call the string-based overload
+ }
+
+ // Determines the sorting relation of StrB to the current instance.
+ //
+ public int CompareTo(string strB)
+ {
+ return string.Compare(this, strB, StringComparison.CurrentCulture);
+ }
+
+ // Determines whether a specified string is a suffix of the current instance.
+ //
+ // The case-sensitive and culture-sensitive option is set by options,
+ // and the default culture is used.
+ //
+ public bool EndsWith(string value)
+ {
+ return EndsWith(value, StringComparison.CurrentCulture);
+ }
+
+ public bool EndsWith(string value, StringComparison comparisonType)
+ {
+ if ((object)value == null)
+ {
+ throw new ArgumentNullException(nameof(value));
+ }
+
+ if ((object)this == (object)value)
+ {
+ CheckStringComparison(comparisonType);
+ return true;
+ }
+
+ if (value.Length == 0)
+ {
+ CheckStringComparison(comparisonType);
+ return true;
+ }
+
+ switch (comparisonType)
+ {
+ case StringComparison.CurrentCulture:
+ return CultureInfo.CurrentCulture.CompareInfo.IsSuffix(this, value, CompareOptions.None);
+
+ case StringComparison.CurrentCultureIgnoreCase:
+ return CultureInfo.CurrentCulture.CompareInfo.IsSuffix(this, value, CompareOptions.IgnoreCase);
+
+ case StringComparison.InvariantCulture:
+ return CompareInfo.Invariant.IsSuffix(this, value, CompareOptions.None);
+
+ case StringComparison.InvariantCultureIgnoreCase:
+ return CompareInfo.Invariant.IsSuffix(this, value, CompareOptions.IgnoreCase);
+
+ case StringComparison.Ordinal:
+ return this.Length < value.Length ? false : (CompareOrdinalHelper(this, this.Length - value.Length, value.Length, value, 0, value.Length) == 0);
+
+ case StringComparison.OrdinalIgnoreCase:
+ return this.Length < value.Length ? false : (CompareInfo.CompareOrdinalIgnoreCase(this, this.Length - value.Length, value.Length, value, 0, value.Length) == 0);
+
+ default:
+ throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType));
+ }
+ }
+
+ public bool EndsWith(string value, bool ignoreCase, CultureInfo culture)
+ {
+ if (null == value)
+ {
+ throw new ArgumentNullException(nameof(value));
+ }
+
+ if ((object)this == (object)value)
+ {
+ return true;
+ }
+
+ CultureInfo referenceCulture = culture ?? CultureInfo.CurrentCulture;
+ return referenceCulture.CompareInfo.IsSuffix(this, value, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
+ }
+
+ public bool EndsWith(char value)
+ {
+ int thisLen = Length;
+ return thisLen != 0 && this[thisLen - 1] == value;
+ }
+
+ // Determines whether two strings match.
+ public override bool Equals(object obj)
+ {
+ if (object.ReferenceEquals(this, obj))
+ return true;
+
+ string str = obj as string;
+ if (str == null)
+ return false;
+
+ if (this.Length != str.Length)
+ return false;
+
+ return EqualsHelper(this, str);
+ }
+
+ // Determines whether two strings match.
+ public bool Equals(string value)
+ {
+ if (object.ReferenceEquals(this, value))
+ return true;
+
+ // NOTE: No need to worry about casting to object here.
+ // If either side of an == comparison between strings
+ // is null, Roslyn generates a simple ceq instruction
+ // instead of calling string.op_Equality.
+ if (value == null)
+ return false;
+
+ if (this.Length != value.Length)
+ return false;
+
+ return EqualsHelper(this, value);
+ }
+
+ public bool Equals(string value, StringComparison comparisonType)
+ {
+ if ((object)this == (object)value)
+ {
+ CheckStringComparison(comparisonType);
+ return true;
+ }
+
+ if ((object)value == null)
+ {
+ CheckStringComparison(comparisonType);
+ return false;
+ }
+
+ switch (comparisonType)
+ {
+ case StringComparison.CurrentCulture:
+ return (CultureInfo.CurrentCulture.CompareInfo.Compare(this, value, CompareOptions.None) == 0);
+
+ case StringComparison.CurrentCultureIgnoreCase:
+ return (CultureInfo.CurrentCulture.CompareInfo.Compare(this, value, CompareOptions.IgnoreCase) == 0);
+
+ case StringComparison.InvariantCulture:
+ return (CompareInfo.Invariant.Compare(this, value, CompareOptions.None) == 0);
+
+ case StringComparison.InvariantCultureIgnoreCase:
+ return (CompareInfo.Invariant.Compare(this, value, CompareOptions.IgnoreCase) == 0);
+
+ case StringComparison.Ordinal:
+ if (this.Length != value.Length)
+ return false;
+ return EqualsHelper(this, value);
+
+ case StringComparison.OrdinalIgnoreCase:
+ if (this.Length != value.Length)
+ return false;
+#if CORECLR
+ // If both strings are ASCII strings, we can take the fast path.
+ if (this.IsAscii() && value.IsAscii())
+ {
+ return EqualsIgnoreCaseAsciiHelper(this, value);
+ }
+#endif
+ return (CompareInfo.CompareOrdinalIgnoreCase(this, 0, this.Length, value, 0, value.Length) == 0);
+
+ default:
+ throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType));
+ }
+ }
+
+
+ // Determines whether two Strings match.
+ public static bool Equals(string a, string b)
+ {
+ if ((object)a == (object)b)
+ {
+ return true;
+ }
+
+ if ((object)a == null || (object)b == null || a.Length != b.Length)
+ {
+ return false;
+ }
+
+ return EqualsHelper(a, b);
+ }
+
+ public static bool Equals(string a, string b, StringComparison comparisonType)
+ {
+ if ((object)a == (object)b)
+ {
+ CheckStringComparison(comparisonType);
+ return true;
+ }
+
+ if ((object)a == null || (object)b == null)
+ {
+ CheckStringComparison(comparisonType);
+ return false;
+ }
+
+ switch (comparisonType)
+ {
+ case StringComparison.CurrentCulture:
+ return (CultureInfo.CurrentCulture.CompareInfo.Compare(a, b, CompareOptions.None) == 0);
+
+ case StringComparison.CurrentCultureIgnoreCase:
+ return (CultureInfo.CurrentCulture.CompareInfo.Compare(a, b, CompareOptions.IgnoreCase) == 0);
+
+ case StringComparison.InvariantCulture:
+ return (CompareInfo.Invariant.Compare(a, b, CompareOptions.None) == 0);
+
+ case StringComparison.InvariantCultureIgnoreCase:
+ return (CompareInfo.Invariant.Compare(a, b, CompareOptions.IgnoreCase) == 0);
+
+ case StringComparison.Ordinal:
+ if (a.Length != b.Length)
+ return false;
+ return EqualsHelper(a, b);
+
+ case StringComparison.OrdinalIgnoreCase:
+ if (a.Length != b.Length)
+ return false;
+#if CORECLR
+ // If both strings are ASCII strings, we can take the fast path.
+ if (a.IsAscii() && b.IsAscii())
+ {
+ return EqualsIgnoreCaseAsciiHelper(a, b);
+ }
+#endif
+ return (CompareInfo.CompareOrdinalIgnoreCase(a, 0, a.Length, b, 0, b.Length) == 0);
+
+ default:
+ throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType));
+ }
+ }
+
+ public static bool operator ==(string a, string b)
+ {
+ return string.Equals(a, b);
+ }
+
+ public static bool operator !=(string a, string b)
+ {
+ return !string.Equals(a, b);
+ }
+
+ // Gets a hash code for this string. If strings A and B are such that A.Equals(B), then
+ // they will return the same hash code.
+ public override int GetHashCode()
+ {
+ return Marvin.ComputeHash32(ref Unsafe.As<char, byte>(ref _firstChar), _stringLength * 2, Marvin.DefaultSeed);
+ }
+
+ // Gets a hash code for this string and this comparison. If strings A and B and comparison C are such
+ // that string.Equals(A, B, C), then they will return the same hash code with this comparison C.
+ public int GetHashCode(StringComparison comparisonType) => StringComparer.FromComparison(comparisonType).GetHashCode(this);
+
+ // Use this if and only if you need the hashcode to not change across app domains (e.g. you have an app domain agile
+ // hash table).
+ internal int GetLegacyNonRandomizedHashCode()
+ {
+ unsafe
+ {
+ fixed (char* src = &_firstChar)
+ {
+ Debug.Assert(src[this.Length] == '\0', "src[this.Length] == '\\0'");
+ Debug.Assert(((int)src) % 4 == 0, "Managed string should start at 4 bytes boundary");
+#if BIT64
+ int hash1 = 5381;
+#else // !BIT64 (32)
+ int hash1 = (5381<<16) + 5381;
+#endif
+ int hash2 = hash1;
+
+#if BIT64
+ int c;
+ char* s = src;
+ while ((c = s[0]) != 0)
+ {
+ hash1 = ((hash1 << 5) + hash1) ^ c;
+ c = s[1];
+ if (c == 0)
+ break;
+ hash2 = ((hash2 << 5) + hash2) ^ c;
+ s += 2;
+ }
+#else // !BIT64 (32)
+ // 32 bit machines.
+ int* pint = (int *)src;
+ int len = this.Length;
+ while (len > 2)
+ {
+ hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0];
+ hash2 = ((hash2 << 5) + hash2 + (hash2 >> 27)) ^ pint[1];
+ pint += 2;
+ len -= 4;
+ }
+
+ if (len > 0)
+ {
+ hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0];
+ }
+#endif
+ return hash1 + (hash2 * 1566083941);
+ }
+ }
+ }
+
+ // Determines whether a specified string is a prefix of the current instance
+ //
+ public bool StartsWith(string value)
+ {
+ if ((object)value == null)
+ {
+ throw new ArgumentNullException(nameof(value));
+ }
+ return StartsWith(value, StringComparison.CurrentCulture);
+ }
+
+ public bool StartsWith(string value, StringComparison comparisonType)
+ {
+ if ((object)value == null)
+ {
+ throw new ArgumentNullException(nameof(value));
+ }
+
+ if ((object)this == (object)value)
+ {
+ CheckStringComparison(comparisonType);
+ return true;
+ }
+
+ if (value.Length == 0)
+ {
+ CheckStringComparison(comparisonType);
+ return true;
+ }
+
+ switch (comparisonType)
+ {
+ case StringComparison.CurrentCulture:
+ return CultureInfo.CurrentCulture.CompareInfo.IsPrefix(this, value, CompareOptions.None);
+
+ case StringComparison.CurrentCultureIgnoreCase:
+ return CultureInfo.CurrentCulture.CompareInfo.IsPrefix(this, value, CompareOptions.IgnoreCase);
+
+ case StringComparison.InvariantCulture:
+ return CompareInfo.Invariant.IsPrefix(this, value, CompareOptions.None);
+
+ case StringComparison.InvariantCultureIgnoreCase:
+ return CompareInfo.Invariant.IsPrefix(this, value, CompareOptions.IgnoreCase);
+
+ case StringComparison.Ordinal:
+ if (this.Length < value.Length || _firstChar != value._firstChar)
+ {
+ return false;
+ }
+ return (value.Length == 1) ?
+ true : // First char is the same and thats all there is to compare
+ SpanHelpers.SequenceEqual(
+ ref Unsafe.As<char, byte>(ref this.GetRawStringData()),
+ ref Unsafe.As<char, byte>(ref value.GetRawStringData()),
+ ((nuint)value.Length) * 2);
+
+ case StringComparison.OrdinalIgnoreCase:
+ if (this.Length < value.Length)
+ {
+ return false;
+ }
+ return (CompareInfo.CompareOrdinalIgnoreCase(this, 0, value.Length, value, 0, value.Length) == 0);
+
+ default:
+ throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType));
+ }
+ }
+
+ public bool StartsWith(string value, bool ignoreCase, CultureInfo culture)
+ {
+ if (null == value)
+ {
+ throw new ArgumentNullException(nameof(value));
+ }
+
+ if ((object)this == (object)value)
+ {
+ return true;
+ }
+
+ CultureInfo referenceCulture = culture ?? CultureInfo.CurrentCulture;
+ return referenceCulture.CompareInfo.IsPrefix(this, value, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
+ }
+
+ public bool StartsWith(char value) => Length != 0 && _firstChar == value;
+
+ internal static void CheckStringComparison(StringComparison comparisonType)
+ {
+ // Single comparison to check if comparisonType is within [CurrentCulture .. OrdinalIgnoreCase]
+ if ((uint)(comparisonType - StringComparison.CurrentCulture) > (StringComparison.OrdinalIgnoreCase - StringComparison.CurrentCulture))
+ {
+ ThrowHelper.ThrowArgumentException(ExceptionResource.NotSupported_StringComparison, ExceptionArgument.comparisonType);
+ }
+ }
+ }
+}
diff --git a/src/Common/src/CoreLib/System/String.Manipulation.cs b/src/Common/src/CoreLib/System/String.Manipulation.cs
new file mode 100644
index 0000000000..69609aacfb
--- /dev/null
+++ b/src/Common/src/CoreLib/System/String.Manipulation.cs
@@ -0,0 +1,1852 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Text;
+using Internal.Runtime.CompilerServices;
+
+namespace System
+{
+ public partial class String
+ {
+ private const int StackallocIntBufferSizeLimit = 128;
+
+ private static unsafe void FillStringChecked(string dest, int destPos, string src)
+ {
+ Debug.Assert(dest != null);
+ Debug.Assert(src != null);
+ if (src.Length > dest.Length - destPos)
+ {
+ throw new IndexOutOfRangeException();
+ }
+
+ fixed (char* pDest = &dest._firstChar)
+ fixed (char* pSrc = &src._firstChar)
+ {
+ wstrcpy(pDest + destPos, pSrc, src.Length);
+ }
+ }
+
+ public static string Concat(object arg0)
+ {
+ if (arg0 == null)
+ {
+ return string.Empty;
+ }
+ return arg0.ToString();
+ }
+
+ public static string Concat(object arg0, object arg1)
+ {
+ if (arg0 == null)
+ {
+ arg0 = string.Empty;
+ }
+
+ if (arg1 == null)
+ {
+ arg1 = string.Empty;
+ }
+ return Concat(arg0.ToString(), arg1.ToString());
+ }
+
+ public static string Concat(object arg0, object arg1, object arg2)
+ {
+ if (arg0 == null)
+ {
+ arg0 = string.Empty;
+ }
+
+ if (arg1 == null)
+ {
+ arg1 = string.Empty;
+ }
+
+ if (arg2 == null)
+ {
+ arg2 = string.Empty;
+ }
+
+ return Concat(arg0.ToString(), arg1.ToString(), arg2.ToString());
+ }
+
+ public static string Concat(params object[] args)
+ {
+ if (args == null)
+ {
+ throw new ArgumentNullException(nameof(args));
+ }
+
+ if (args.Length <= 1)
+ {
+ return args.Length == 0 ?
+ string.Empty :
+ args[0]?.ToString() ?? string.Empty;
+ }
+
+ // We need to get an intermediary string array
+ // to fill with each of the args' ToString(),
+ // and then just concat that in one operation.
+
+ // This way we avoid any intermediary string representations,
+ // or buffer resizing if we use StringBuilder (although the
+ // latter case is partially alleviated due to StringBuilder's
+ // linked-list style implementation)
+
+ var strings = new string[args.Length];
+
+ int totalLength = 0;
+
+ for (int i = 0; i < args.Length; i++)
+ {
+ object value = args[i];
+
+ string toString = value?.ToString() ?? string.Empty; // We need to handle both the cases when value or value.ToString() is null
+ strings[i] = toString;
+
+ totalLength += toString.Length;
+
+ if (totalLength < 0) // Check for a positive overflow
+ {
+ throw new OutOfMemoryException();
+ }
+ }
+
+ // If all of the ToStrings are null/empty, just return string.Empty
+ if (totalLength == 0)
+ {
+ return string.Empty;
+ }
+
+ string result = FastAllocateString(totalLength);
+ int position = 0; // How many characters we've copied so far
+
+ for (int i = 0; i < strings.Length; i++)
+ {
+ string s = strings[i];
+
+ Debug.Assert(s != null);
+ Debug.Assert(position <= totalLength - s.Length, "We didn't allocate enough space for the result string!");
+
+ FillStringChecked(result, position, s);
+ position += s.Length;
+ }
+
+ return result;
+ }
+
+ public static string Concat<T>(IEnumerable<T> values)
+ {
+ if (values == null)
+ throw new ArgumentNullException(nameof(values));
+
+ if (typeof(T) == typeof(char))
+ {
+ // Special-case T==char, as we can handle that case much more efficiently,
+ // and string.Concat(IEnumerable<char>) can be used as an efficient
+ // enumerable-based equivalent of new string(char[]).
+ using (IEnumerator<char> en = Unsafe.As<IEnumerable<char>>(values).GetEnumerator())
+ {
+ if (!en.MoveNext())
+ {
+ // There weren't any chars. Return the empty string.
+ return Empty;
+ }
+
+ char c = en.Current; // save the first char
+
+ if (!en.MoveNext())
+ {
+ // There was only one char. Return a string from it directly.
+ return CreateFromChar(c);
+ }
+
+ // Create the StringBuilder, add the chars we've already enumerated,
+ // add the rest, and then get the resulting string.
+ StringBuilder result = StringBuilderCache.Acquire();
+ result.Append(c); // first value
+ do
+ {
+ c = en.Current;
+ result.Append(c);
+ }
+ while (en.MoveNext());
+ return StringBuilderCache.GetStringAndRelease(result);
+ }
+ }
+ else
+ {
+ using (IEnumerator<T> en = values.GetEnumerator())
+ {
+ if (!en.MoveNext())
+ return string.Empty;
+
+ // We called MoveNext once, so this will be the first item
+ T currentValue = en.Current;
+
+ // Call ToString before calling MoveNext again, since
+ // we want to stay consistent with the below loop
+ // Everything should be called in the order
+ // MoveNext-Current-ToString, unless further optimizations
+ // can be made, to avoid breaking changes
+ string firstString = currentValue?.ToString();
+
+ // If there's only 1 item, simply call ToString on that
+ if (!en.MoveNext())
+ {
+ // We have to handle the case of either currentValue
+ // or its ToString being null
+ return firstString ?? string.Empty;
+ }
+
+ StringBuilder result = StringBuilderCache.Acquire();
+
+ result.Append(firstString);
+
+ do
+ {
+ currentValue = en.Current;
+
+ if (currentValue != null)
+ {
+ result.Append(currentValue.ToString());
+ }
+ }
+ while (en.MoveNext());
+
+ return StringBuilderCache.GetStringAndRelease(result);
+ }
+ }
+ }
+
+ public static string Concat(IEnumerable<string> values)
+ {
+ if (values == null)
+ throw new ArgumentNullException(nameof(values));
+
+ using (IEnumerator<string> en = values.GetEnumerator())
+ {
+ if (!en.MoveNext())
+ return string.Empty;
+
+ string firstValue = en.Current;
+
+ if (!en.MoveNext())
+ {
+ return firstValue ?? string.Empty;
+ }
+
+ StringBuilder result = StringBuilderCache.Acquire();
+ result.Append(firstValue);
+
+ do
+ {
+ result.Append(en.Current);
+ }
+ while (en.MoveNext());
+
+ return StringBuilderCache.GetStringAndRelease(result);
+ }
+ }
+
+ public static string Concat(string str0, string str1)
+ {
+ if (IsNullOrEmpty(str0))
+ {
+ if (IsNullOrEmpty(str1))
+ {
+ return string.Empty;
+ }
+ return str1;
+ }
+
+ if (IsNullOrEmpty(str1))
+ {
+ return str0;
+ }
+
+ int str0Length = str0.Length;
+
+ string result = FastAllocateString(str0Length + str1.Length);
+
+ FillStringChecked(result, 0, str0);
+ FillStringChecked(result, str0Length, str1);
+
+ return result;
+ }
+
+ public static string Concat(string str0, string str1, string str2)
+ {
+ if (IsNullOrEmpty(str0))
+ {
+ return Concat(str1, str2);
+ }
+
+ if (IsNullOrEmpty(str1))
+ {
+ return Concat(str0, str2);
+ }
+
+ if (IsNullOrEmpty(str2))
+ {
+ return Concat(str0, str1);
+ }
+
+ int totalLength = str0.Length + str1.Length + str2.Length;
+
+ string result = FastAllocateString(totalLength);
+ FillStringChecked(result, 0, str0);
+ FillStringChecked(result, str0.Length, str1);
+ FillStringChecked(result, str0.Length + str1.Length, str2);
+
+ return result;
+ }
+
+ public static string Concat(string str0, string str1, string str2, string str3)
+ {
+ if (IsNullOrEmpty(str0))
+ {
+ return Concat(str1, str2, str3);
+ }
+
+ if (IsNullOrEmpty(str1))
+ {
+ return Concat(str0, str2, str3);
+ }
+
+ if (IsNullOrEmpty(str2))
+ {
+ return Concat(str0, str1, str3);
+ }
+
+ if (IsNullOrEmpty(str3))
+ {
+ return Concat(str0, str1, str2);
+ }
+
+ int totalLength = str0.Length + str1.Length + str2.Length + str3.Length;
+
+ string result = FastAllocateString(totalLength);
+ FillStringChecked(result, 0, str0);
+ FillStringChecked(result, str0.Length, str1);
+ FillStringChecked(result, str0.Length + str1.Length, str2);
+ FillStringChecked(result, str0.Length + str1.Length + str2.Length, str3);
+
+ return result;
+ }
+
+ public static string Concat(params string[] values)
+ {
+ if (values == null)
+ throw new ArgumentNullException(nameof(values));
+
+ if (values.Length <= 1)
+ {
+ return values.Length == 0 ?
+ string.Empty :
+ values[0] ?? string.Empty;
+ }
+
+ // It's possible that the input values array could be changed concurrently on another
+ // thread, such that we can't trust that each read of values[i] will be equivalent.
+ // Worst case, we can make a defensive copy of the array and use that, but we first
+ // optimistically try the allocation and copies assuming that the array isn't changing,
+ // which represents the 99.999% case, in particular since string.Concat is used for
+ // string concatenation by the languages, with the input array being a params array.
+
+ // Sum the lengths of all input strings
+ long totalLengthLong = 0;
+ for (int i = 0; i < values.Length; i++)
+ {
+ string value = values[i];
+ if (value != null)
+ {
+ totalLengthLong += value.Length;
+ }
+ }
+
+ // If it's too long, fail, or if it's empty, return an empty string.
+ if (totalLengthLong > int.MaxValue)
+ {
+ throw new OutOfMemoryException();
+ }
+ int totalLength = (int)totalLengthLong;
+ if (totalLength == 0)
+ {
+ return string.Empty;
+ }
+
+ // Allocate a new string and copy each input string into it
+ string result = FastAllocateString(totalLength);
+ int copiedLength = 0;
+ for (int i = 0; i < values.Length; i++)
+ {
+ string value = values[i];
+ if (!string.IsNullOrEmpty(value))
+ {
+ int valueLen = value.Length;
+ if (valueLen > totalLength - copiedLength)
+ {
+ copiedLength = -1;
+ break;
+ }
+
+ FillStringChecked(result, copiedLength, value);
+ copiedLength += valueLen;
+ }
+ }
+
+ // If we copied exactly the right amount, return the new string. Otherwise,
+ // something changed concurrently to mutate the input array: fall back to
+ // doing the concatenation again, but this time with a defensive copy. This
+ // fall back should be extremely rare.
+ return copiedLength == totalLength ? result : Concat((string[])values.Clone());
+ }
+
+ public static string Format(string format, object arg0)
+ {
+ return FormatHelper(null, format, new ParamsArray(arg0));
+ }
+
+ public static string Format(string format, object arg0, object arg1)
+ {
+ return FormatHelper(null, format, new ParamsArray(arg0, arg1));
+ }
+
+ public static string Format(string format, object arg0, object arg1, object arg2)
+ {
+ return FormatHelper(null, format, new ParamsArray(arg0, arg1, arg2));
+ }
+
+ public static string Format(string format, params object[] args)
+ {
+ if (args == null)
+ {
+ // To preserve the original exception behavior, throw an exception about format if both
+ // args and format are null. The actual null check for format is in FormatHelper.
+ throw new ArgumentNullException((format == null) ? nameof(format) : nameof(args));
+ }
+
+ return FormatHelper(null, format, new ParamsArray(args));
+ }
+
+ public static string Format(IFormatProvider provider, string format, object arg0)
+ {
+ return FormatHelper(provider, format, new ParamsArray(arg0));
+ }
+
+ public static string Format(IFormatProvider provider, string format, object arg0, object arg1)
+ {
+ return FormatHelper(provider, format, new ParamsArray(arg0, arg1));
+ }
+
+ public static string Format(IFormatProvider provider, string format, object arg0, object arg1, object arg2)
+ {
+ return FormatHelper(provider, format, new ParamsArray(arg0, arg1, arg2));
+ }
+
+ public static string Format(IFormatProvider provider, string format, params object[] args)
+ {
+ if (args == null)
+ {
+ // To preserve the original exception behavior, throw an exception about format if both
+ // args and format are null. The actual null check for format is in FormatHelper.
+ throw new ArgumentNullException((format == null) ? nameof(format) : nameof(args));
+ }
+
+ return FormatHelper(provider, format, new ParamsArray(args));
+ }
+
+ private static string FormatHelper(IFormatProvider provider, string format, ParamsArray args)
+ {
+ if (format == null)
+ throw new ArgumentNullException(nameof(format));
+
+ return StringBuilderCache.GetStringAndRelease(
+ StringBuilderCache
+ .Acquire(format.Length + args.Length * 8)
+ .AppendFormatHelper(provider, format, args));
+ }
+
+ public string Insert(int startIndex, string value)
+ {
+ if (value == null)
+ throw new ArgumentNullException(nameof(value));
+ if (startIndex < 0 || startIndex > this.Length)
+ throw new ArgumentOutOfRangeException(nameof(startIndex));
+
+ int oldLength = Length;
+ int insertLength = value.Length;
+
+ if (oldLength == 0)
+ return value;
+ if (insertLength == 0)
+ return this;
+
+ // In case this computation overflows, newLength will be negative and FastAllocateString throws OutOfMemoryException
+ int newLength = oldLength + insertLength;
+ string result = FastAllocateString(newLength);
+ unsafe
+ {
+ fixed (char* srcThis = &_firstChar)
+ {
+ fixed (char* srcInsert = &value._firstChar)
+ {
+ fixed (char* dst = &result._firstChar)
+ {
+ wstrcpy(dst, srcThis, startIndex);
+ wstrcpy(dst + startIndex, srcInsert, insertLength);
+ wstrcpy(dst + startIndex + insertLength, srcThis + startIndex, oldLength - startIndex);
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ public static string Join(char separator, params string[] value)
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException(nameof(value));
+ }
+
+ return Join(separator, value, 0, value.Length);
+ }
+
+ public static unsafe string Join(char separator, params object[] values)
+ {
+ // Defer argument validation to the internal function
+ return JoinCore(&separator, 1, values);
+ }
+
+ public static unsafe string Join<T>(char separator, IEnumerable<T> values)
+ {
+ // Defer argument validation to the internal function
+ return JoinCore(&separator, 1, values);
+ }
+
+ public static unsafe string Join(char separator, string[] value, int startIndex, int count)
+ {
+ // Defer argument validation to the internal function
+ return JoinCore(&separator, 1, value, startIndex, count);
+ }
+
+ // Joins an array of strings together as one string with a separator between each original string.
+ //
+ public static string Join(string separator, params string[] value)
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException(nameof(value));
+ }
+ return Join(separator, value, 0, value.Length);
+ }
+
+ public static unsafe string Join(string separator, params object[] values)
+ {
+ separator = separator ?? string.Empty;
+ fixed (char* pSeparator = &separator._firstChar)
+ {
+ // Defer argument validation to the internal function
+ return JoinCore(pSeparator, separator.Length, values);
+ }
+ }
+
+ public static unsafe string Join<T>(string separator, IEnumerable<T> values)
+ {
+ separator = separator ?? string.Empty;
+ fixed (char* pSeparator = &separator._firstChar)
+ {
+ // Defer argument validation to the internal function
+ return JoinCore(pSeparator, separator.Length, values);
+ }
+ }
+
+ public static string Join(string separator, IEnumerable<string> values)
+ {
+ if (values == null)
+ {
+ throw new ArgumentNullException(nameof(values));
+ }
+
+ using (IEnumerator<string> en = values.GetEnumerator())
+ {
+ if (!en.MoveNext())
+ {
+ return string.Empty;
+ }
+
+ string firstValue = en.Current;
+
+ if (!en.MoveNext())
+ {
+ // Only one value available
+ return firstValue ?? string.Empty;
+ }
+
+ // Null separator and values are handled by the StringBuilder
+ StringBuilder result = StringBuilderCache.Acquire();
+ result.Append(firstValue);
+
+ do
+ {
+ result.Append(separator);
+ result.Append(en.Current);
+ }
+ while (en.MoveNext());
+
+ return StringBuilderCache.GetStringAndRelease(result);
+ }
+ }
+
+ // Joins an array of strings together as one string with a separator between each original string.
+ //
+ public static unsafe string Join(string separator, string[] value, int startIndex, int count)
+ {
+ separator = separator ?? string.Empty;
+ fixed (char* pSeparator = &separator._firstChar)
+ {
+ // Defer argument validation to the internal function
+ return JoinCore(pSeparator, separator.Length, value, startIndex, count);
+ }
+ }
+
+ private static unsafe string JoinCore(char* separator, int separatorLength, object[] values)
+ {
+ if (values == null)
+ {
+ throw new ArgumentNullException(nameof(values));
+ }
+
+ if (values.Length == 0)
+ {
+ return string.Empty;
+ }
+
+ string firstString = values[0]?.ToString();
+
+ if (values.Length == 1)
+ {
+ return firstString ?? string.Empty;
+ }
+
+ StringBuilder result = StringBuilderCache.Acquire();
+ result.Append(firstString);
+
+ for (int i = 1; i < values.Length; i++)
+ {
+ result.Append(separator, separatorLength);
+ object value = values[i];
+ if (value != null)
+ {
+ result.Append(value.ToString());
+ }
+ }
+
+ return StringBuilderCache.GetStringAndRelease(result);
+ }
+
+ private static unsafe string JoinCore<T>(char* separator, int separatorLength, IEnumerable<T> values)
+ {
+ if (values == null)
+ {
+ throw new ArgumentNullException(nameof(values));
+ }
+
+ using (IEnumerator<T> en = values.GetEnumerator())
+ {
+ if (!en.MoveNext())
+ {
+ return string.Empty;
+ }
+
+ // We called MoveNext once, so this will be the first item
+ T currentValue = en.Current;
+
+ // Call ToString before calling MoveNext again, since
+ // we want to stay consistent with the below loop
+ // Everything should be called in the order
+ // MoveNext-Current-ToString, unless further optimizations
+ // can be made, to avoid breaking changes
+ string firstString = currentValue?.ToString();
+
+ // If there's only 1 item, simply call ToString on that
+ if (!en.MoveNext())
+ {
+ // We have to handle the case of either currentValue
+ // or its ToString being null
+ return firstString ?? string.Empty;
+ }
+
+ StringBuilder result = StringBuilderCache.Acquire();
+
+ result.Append(firstString);
+
+ do
+ {
+ currentValue = en.Current;
+
+ result.Append(separator, separatorLength);
+ if (currentValue != null)
+ {
+ result.Append(currentValue.ToString());
+ }
+ }
+ while (en.MoveNext());
+
+ return StringBuilderCache.GetStringAndRelease(result);
+ }
+ }
+
+ private static unsafe string JoinCore(char* separator, int separatorLength, string[] value, int startIndex, int count)
+ {
+ // If the separator is null, it is converted to an empty string before entering this function.
+ // Even for empty strings, fixed should never return null (it should return a pointer to a null char).
+ Debug.Assert(separator != null);
+ Debug.Assert(separatorLength >= 0);
+
+ if (value == null)
+ {
+ throw new ArgumentNullException(nameof(value));
+ }
+ if (startIndex < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_StartIndex);
+ }
+ if (count < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NegativeCount);
+ }
+ if (startIndex > value.Length - count)
+ {
+ throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_IndexCountBuffer);
+ }
+
+ if (count <= 1)
+ {
+ return count == 0 ?
+ string.Empty :
+ value[startIndex] ?? string.Empty;
+ }
+
+ long totalSeparatorsLength = (long)(count - 1) * separatorLength;
+ if (totalSeparatorsLength > int.MaxValue)
+ {
+ throw new OutOfMemoryException();
+ }
+ int totalLength = (int)totalSeparatorsLength;
+
+ // Calculate the length of the resultant string so we know how much space to allocate.
+ for (int i = startIndex, end = startIndex + count; i < end; i++)
+ {
+ string currentValue = value[i];
+ if (currentValue != null)
+ {
+ totalLength += currentValue.Length;
+ if (totalLength < 0) // Check for overflow
+ {
+ throw new OutOfMemoryException();
+ }
+ }
+ }
+
+ // Copy each of the strings into the resultant buffer, interleaving with the separator.
+ string result = FastAllocateString(totalLength);
+ int copiedLength = 0;
+
+ for (int i = startIndex, end = startIndex + count; i < end; i++)
+ {
+ // It's possible that another thread may have mutated the input array
+ // such that our second read of an index will not be the same string
+ // we got during the first read.
+
+ // We range check again to avoid buffer overflows if this happens.
+
+ string currentValue = value[i];
+ if (currentValue != null)
+ {
+ int valueLen = currentValue.Length;
+ if (valueLen > totalLength - copiedLength)
+ {
+ copiedLength = -1;
+ break;
+ }
+
+ // Fill in the value.
+ FillStringChecked(result, copiedLength, currentValue);
+ copiedLength += valueLen;
+ }
+
+ if (i < end - 1)
+ {
+ // Fill in the separator.
+ fixed (char* pResult = &result._firstChar)
+ {
+ // If we are called from the char-based overload, we will not
+ // want to call MemoryCopy each time we fill in the separator. So
+ // specialize for 1-length separators.
+ if (separatorLength == 1)
+ {
+ pResult[copiedLength] = *separator;
+ }
+ else
+ {
+ wstrcpy(pResult + copiedLength, separator, separatorLength);
+ }
+ }
+ copiedLength += separatorLength;
+ }
+ }
+
+ // If we copied exactly the right amount, return the new string. Otherwise,
+ // something changed concurrently to mutate the input array: fall back to
+ // doing the concatenation again, but this time with a defensive copy. This
+ // fall back should be extremely rare.
+ return copiedLength == totalLength ?
+ result :
+ JoinCore(separator, separatorLength, (string[])value.Clone(), startIndex, count);
+ }
+
+ public string PadLeft(int totalWidth) => PadLeft(totalWidth, ' ');
+
+ public string PadLeft(int totalWidth, char paddingChar)
+ {
+ if (totalWidth < 0)
+ throw new ArgumentOutOfRangeException(nameof(totalWidth), SR.ArgumentOutOfRange_NeedNonNegNum);
+ int oldLength = Length;
+ int count = totalWidth - oldLength;
+ if (count <= 0)
+ return this;
+ string result = FastAllocateString(totalWidth);
+ unsafe
+ {
+ fixed (char* dst = &result._firstChar)
+ {
+ for (int i = 0; i < count; i++)
+ dst[i] = paddingChar;
+ fixed (char* src = &_firstChar)
+ {
+ wstrcpy(dst + count, src, oldLength);
+ }
+ }
+ }
+ return result;
+ }
+
+ public string PadRight(int totalWidth) => PadRight(totalWidth, ' ');
+
+ public string PadRight(int totalWidth, char paddingChar)
+ {
+ if (totalWidth < 0)
+ throw new ArgumentOutOfRangeException(nameof(totalWidth), SR.ArgumentOutOfRange_NeedNonNegNum);
+ int oldLength = Length;
+ int count = totalWidth - oldLength;
+ if (count <= 0)
+ return this;
+ string result = FastAllocateString(totalWidth);
+ unsafe
+ {
+ fixed (char* dst = &result._firstChar)
+ {
+ fixed (char* src = &_firstChar)
+ {
+ wstrcpy(dst, src, oldLength);
+ }
+ for (int i = 0; i < count; i++)
+ dst[oldLength + i] = paddingChar;
+ }
+ }
+ return result;
+ }
+
+ public string Remove(int startIndex, int count)
+ {
+ if (startIndex < 0)
+ throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_StartIndex);
+ if (count < 0)
+ throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NegativeCount);
+ int oldLength = this.Length;
+ if (count > oldLength - startIndex)
+ throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_IndexCount);
+
+ if (count == 0)
+ return this;
+ int newLength = oldLength - count;
+ if (newLength == 0)
+ return string.Empty;
+
+ string result = FastAllocateString(newLength);
+ unsafe
+ {
+ fixed (char* src = &_firstChar)
+ {
+ fixed (char* dst = &result._firstChar)
+ {
+ wstrcpy(dst, src, startIndex);
+ wstrcpy(dst + startIndex, src + startIndex + count, newLength - startIndex);
+ }
+ }
+ }
+ return result;
+ }
+
+ // a remove that just takes a startindex.
+ public string Remove(int startIndex)
+ {
+ if (startIndex < 0)
+ throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_StartIndex);
+
+ if (startIndex >= Length)
+ throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_StartIndexLessThanLength);
+
+ return Substring(0, startIndex);
+ }
+
+ public string Replace(string oldValue, string newValue, bool ignoreCase, CultureInfo culture)
+ {
+ return ReplaceCore(oldValue, newValue, culture, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
+ }
+
+ public string Replace(string oldValue, string newValue, StringComparison comparisonType)
+ {
+ switch (comparisonType)
+ {
+ case StringComparison.CurrentCulture:
+ return ReplaceCore(oldValue, newValue, CultureInfo.CurrentCulture, CompareOptions.None);
+
+ case StringComparison.CurrentCultureIgnoreCase:
+ return ReplaceCore(oldValue, newValue, CultureInfo.CurrentCulture, CompareOptions.IgnoreCase);
+
+ case StringComparison.InvariantCulture:
+ return ReplaceCore(oldValue, newValue, CultureInfo.InvariantCulture, CompareOptions.None);
+
+ case StringComparison.InvariantCultureIgnoreCase:
+ return ReplaceCore(oldValue, newValue, CultureInfo.InvariantCulture, CompareOptions.IgnoreCase);
+
+ case StringComparison.Ordinal:
+ return Replace(oldValue, newValue);
+
+ case StringComparison.OrdinalIgnoreCase:
+ return ReplaceCore(oldValue, newValue, CultureInfo.InvariantCulture, CompareOptions.OrdinalIgnoreCase);
+
+ default:
+ throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType));
+ }
+ }
+
+ private unsafe string ReplaceCore(string oldValue, string newValue, CultureInfo culture, CompareOptions options)
+ {
+ if (oldValue == null)
+ throw new ArgumentNullException(nameof(oldValue));
+ if (oldValue.Length == 0)
+ throw new ArgumentException(SR.Argument_StringZeroLength, nameof(oldValue));
+
+ // If they asked to replace oldValue with a null, replace all occurrences
+ // with the empty string.
+ if (newValue == null)
+ newValue = string.Empty;
+
+ CultureInfo referenceCulture = culture ?? CultureInfo.CurrentCulture;
+ StringBuilder result = StringBuilderCache.Acquire();
+
+ int startIndex = 0;
+ int index = 0;
+
+ int matchLength = 0;
+
+ bool hasDoneAnyReplacements = false;
+ CompareInfo ci = referenceCulture.CompareInfo;
+
+ do
+ {
+ index = ci.IndexOf(this, oldValue, startIndex, this.Length - startIndex, options, &matchLength);
+ if (index >= 0)
+ {
+ // append the unmodified portion of string
+ result.Append(this, startIndex, index - startIndex);
+
+ // append the replacement
+ result.Append(newValue);
+
+ startIndex = index + matchLength;
+ hasDoneAnyReplacements = true;
+ }
+ else if (!hasDoneAnyReplacements)
+ {
+ // small optimization,
+ // if we have not done any replacements,
+ // we will return the original string
+ StringBuilderCache.Release(result);
+ return this;
+ }
+ else
+ {
+ result.Append(this, startIndex, this.Length - startIndex);
+ }
+ } while (index >= 0);
+
+ return StringBuilderCache.GetStringAndRelease(result);
+ }
+
+ // Replaces all instances of oldChar with newChar.
+ //
+ public string Replace(char oldChar, char newChar)
+ {
+ if (oldChar == newChar)
+ return this;
+
+ unsafe
+ {
+ int remainingLength = Length;
+
+ fixed (char* pChars = &_firstChar)
+ {
+ char* pSrc = pChars;
+
+ while (remainingLength > 0)
+ {
+ if (*pSrc == oldChar)
+ {
+ break;
+ }
+
+ remainingLength--;
+ pSrc++;
+ }
+ }
+
+ if (remainingLength == 0)
+ return this;
+
+ string result = FastAllocateString(Length);
+
+ fixed (char* pChars = &_firstChar)
+ {
+ fixed (char* pResult = &result._firstChar)
+ {
+ int copyLength = Length - remainingLength;
+
+ //Copy the characters already proven not to match.
+ if (copyLength > 0)
+ {
+ wstrcpy(pResult, pChars, copyLength);
+ }
+
+ //Copy the remaining characters, doing the replacement as we go.
+ char* pSrc = pChars + copyLength;
+ char* pDst = pResult + copyLength;
+
+ do
+ {
+ char currentChar = *pSrc;
+ if (currentChar == oldChar)
+ currentChar = newChar;
+ *pDst = currentChar;
+
+ remainingLength--;
+ pSrc++;
+ pDst++;
+ } while (remainingLength > 0);
+ }
+ }
+
+ return result;
+ }
+ }
+
+ public string Replace(string oldValue, string newValue)
+ {
+ if (oldValue == null)
+ throw new ArgumentNullException(nameof(oldValue));
+ if (oldValue.Length == 0)
+ throw new ArgumentException(SR.Argument_StringZeroLength, nameof(oldValue));
+
+ // Api behavior: if newValue is null, instances of oldValue are to be removed.
+ if (newValue == null)
+ newValue = string.Empty;
+
+ Span<int> initialSpan = stackalloc int[StackallocIntBufferSizeLimit];
+ var replacementIndices = new ValueListBuilder<int>(initialSpan);
+
+ unsafe
+ {
+ fixed (char* pThis = &_firstChar)
+ {
+ int matchIdx = 0;
+ int lastPossibleMatchIdx = this.Length - oldValue.Length;
+ while (matchIdx <= lastPossibleMatchIdx)
+ {
+ char* pMatch = pThis + matchIdx;
+ for (int probeIdx = 0; probeIdx < oldValue.Length; probeIdx++)
+ {
+ if (pMatch[probeIdx] != oldValue[probeIdx])
+ {
+ goto Next;
+ }
+ }
+ // Found a match for the string. Record the location of the match and skip over the "oldValue."
+ replacementIndices.Append(matchIdx);
+ matchIdx += oldValue.Length;
+ continue;
+
+ Next:
+ matchIdx++;
+ }
+ }
+ }
+
+ if (replacementIndices.Length == 0)
+ return this;
+
+ // String allocation and copying is in separate method to make this method faster for the case where
+ // nothing needs replacing.
+ string dst = ReplaceHelper(oldValue.Length, newValue, replacementIndices.AsSpan());
+
+ replacementIndices.Dispose();
+
+ return dst;
+ }
+
+ private string ReplaceHelper(int oldValueLength, string newValue, ReadOnlySpan<int> indices)
+ {
+ Debug.Assert(indices.Length > 0);
+
+ long dstLength = this.Length + ((long)(newValue.Length - oldValueLength)) * indices.Length;
+ if (dstLength > int.MaxValue)
+ throw new OutOfMemoryException();
+ string dst = FastAllocateString((int)dstLength);
+
+ Span<char> dstSpan = new Span<char>(ref dst.GetRawStringData(), dst.Length);
+
+ int thisIdx = 0;
+ int dstIdx = 0;
+
+ for (int r = 0; r < indices.Length; r++)
+ {
+ int replacementIdx = indices[r];
+
+ // Copy over the non-matching portion of the original that precedes this occurrence of oldValue.
+ int count = replacementIdx - thisIdx;
+ if (count != 0)
+ {
+ this.AsSpan(thisIdx, count).CopyTo(dstSpan.Slice(dstIdx));
+ dstIdx += count;
+ }
+ thisIdx = replacementIdx + oldValueLength;
+
+ // Copy over newValue to replace the oldValue.
+ newValue.AsSpan().CopyTo(dstSpan.Slice(dstIdx));
+ dstIdx += newValue.Length;
+ }
+
+ // Copy over the final non-matching portion at the end of the string.
+ Debug.Assert(this.Length - thisIdx == dstSpan.Length - dstIdx);
+ this.AsSpan(thisIdx).CopyTo(dstSpan.Slice(dstIdx));
+
+ return dst;
+ }
+
+ public string[] Split(char separator, StringSplitOptions options = StringSplitOptions.None)
+ {
+ return SplitInternal(new ReadOnlySpan<char>(ref separator, 1), int.MaxValue, options);
+ }
+
+ public string[] Split(char separator, int count, StringSplitOptions options = StringSplitOptions.None)
+ {
+ return SplitInternal(new ReadOnlySpan<char>(ref separator, 1), count, options);
+ }
+
+ // Creates an array of strings by splitting this string at each
+ // occurrence of a separator. The separator is searched for, and if found,
+ // the substring preceding the occurrence is stored as the first element in
+ // the array of strings. We then continue in this manner by searching
+ // the substring that follows the occurrence. On the other hand, if the separator
+ // is not found, the array of strings will contain this instance as its only element.
+ // If the separator is null
+ // whitespace (i.e., Character.IsWhitespace) is used as the separator.
+ //
+ public string[] Split(params char[] separator)
+ {
+ return SplitInternal(separator, int.MaxValue, StringSplitOptions.None);
+ }
+
+ // Creates an array of strings by splitting this string at each
+ // occurrence of a separator. The separator is searched for, and if found,
+ // the substring preceding the occurrence is stored as the first element in
+ // the array of strings. We then continue in this manner by searching
+ // the substring that follows the occurrence. On the other hand, if the separator
+ // is not found, the array of strings will contain this instance as its only element.
+ // If the separator is the empty string (i.e., string.Empty), then
+ // whitespace (i.e., Character.IsWhitespace) is used as the separator.
+ // If there are more than count different strings, the last n-(count-1)
+ // elements are concatenated and added as the last string.
+ //
+ public string[] Split(char[] separator, int count)
+ {
+ return SplitInternal(separator, count, StringSplitOptions.None);
+ }
+
+ public string[] Split(char[] separator, StringSplitOptions options)
+ {
+ return SplitInternal(separator, int.MaxValue, options);
+ }
+
+ public string[] Split(char[] separator, int count, StringSplitOptions options)
+ {
+ return SplitInternal(separator, count, options);
+ }
+
+ private string[] SplitInternal(ReadOnlySpan<char> separators, int count, StringSplitOptions options)
+ {
+ if (count < 0)
+ throw new ArgumentOutOfRangeException(nameof(count),
+ SR.ArgumentOutOfRange_NegativeCount);
+
+ if (options < StringSplitOptions.None || options > StringSplitOptions.RemoveEmptyEntries)
+ throw new ArgumentException(SR.Format(SR.Arg_EnumIllegalVal, options));
+
+ bool omitEmptyEntries = (options == StringSplitOptions.RemoveEmptyEntries);
+
+ if ((count == 0) || (omitEmptyEntries && Length == 0))
+ {
+ return Array.Empty<string>();
+ }
+
+ if (count == 1)
+ {
+ return new string[] { this };
+ }
+
+ Span<int> initialSpan = stackalloc int[StackallocIntBufferSizeLimit];
+ var sepListBuilder = new ValueListBuilder<int>(initialSpan);
+
+ MakeSeparatorList(separators, ref sepListBuilder);
+ ReadOnlySpan<int> sepList = sepListBuilder.AsSpan();
+
+ // Handle the special case of no replaces.
+ if (sepList.Length == 0)
+ {
+ return new string[] { this };
+ }
+
+ string[] result = omitEmptyEntries
+ ? SplitOmitEmptyEntries(sepList, default, 1, count)
+ : SplitKeepEmptyEntries(sepList, default, 1, count);
+
+ sepListBuilder.Dispose();
+
+ return result;
+ }
+
+ public string[] Split(string separator, StringSplitOptions options = StringSplitOptions.None)
+ {
+ return SplitInternal(separator ?? string.Empty, null, int.MaxValue, options);
+ }
+
+ public string[] Split(string separator, Int32 count, StringSplitOptions options = StringSplitOptions.None)
+ {
+ return SplitInternal(separator ?? string.Empty, null, count, options);
+ }
+
+ public string[] Split(string[] separator, StringSplitOptions options)
+ {
+ return SplitInternal(null, separator, int.MaxValue, options);
+ }
+
+ public string[] Split(string[] separator, Int32 count, StringSplitOptions options)
+ {
+ return SplitInternal(null, separator, count, options);
+ }
+
+ private string[] SplitInternal(string separator, string[] separators, int count, StringSplitOptions options)
+ {
+ if (count < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(count),
+ SR.ArgumentOutOfRange_NegativeCount);
+ }
+
+ if (options < StringSplitOptions.None || options > StringSplitOptions.RemoveEmptyEntries)
+ {
+ throw new ArgumentException(SR.Format(SR.Arg_EnumIllegalVal, (int)options));
+ }
+
+ bool omitEmptyEntries = (options == StringSplitOptions.RemoveEmptyEntries);
+
+ bool singleSeparator = separator != null;
+
+ if (!singleSeparator && (separators == null || separators.Length == 0))
+ {
+ return SplitInternal((char[])null, count, options);
+ }
+
+ if ((count == 0) || (omitEmptyEntries && Length == 0))
+ {
+ return Array.Empty<string>();
+ }
+
+ if (count == 1 || (singleSeparator && separator.Length == 0))
+ {
+ return new string[] { this };
+ }
+
+ if (singleSeparator)
+ {
+ return SplitInternal(separator, count, options);
+ }
+
+ Span<int> sepListInitialSpan = stackalloc int[StackallocIntBufferSizeLimit];
+ var sepListBuilder = new ValueListBuilder<int>(sepListInitialSpan);
+
+ Span<int> lengthListInitialSpan = stackalloc int[StackallocIntBufferSizeLimit];
+ var lengthListBuilder = new ValueListBuilder<int>(lengthListInitialSpan);
+
+ MakeSeparatorList(separators, ref sepListBuilder, ref lengthListBuilder);
+ ReadOnlySpan<int> sepList = sepListBuilder.AsSpan();
+ ReadOnlySpan<int> lengthList = lengthListBuilder.AsSpan();
+
+ // Handle the special case of no replaces.
+ if (sepList.Length == 0)
+ {
+ return new string[] { this };
+ }
+
+ string[] result = omitEmptyEntries
+ ? SplitOmitEmptyEntries(sepList, lengthList, 0, count)
+ : SplitKeepEmptyEntries(sepList, lengthList, 0, count);
+
+ sepListBuilder.Dispose();
+ lengthListBuilder.Dispose();
+
+ return result;
+ }
+
+ private string[] SplitInternal(string separator, int count, StringSplitOptions options)
+ {
+ Span<int> sepListInitialSpan = stackalloc int[StackallocIntBufferSizeLimit];
+ var sepListBuilder = new ValueListBuilder<int>(sepListInitialSpan);
+
+ MakeSeparatorList(separator, ref sepListBuilder);
+ ReadOnlySpan<int> sepList = sepListBuilder.AsSpan();
+ if (sepList.Length == 0)
+ {
+ // there are no separators so sepListBuilder did not rent an array from pool and there is no need to dispose it
+ return new string[] { this };
+ }
+
+ string[] result = options == StringSplitOptions.RemoveEmptyEntries
+ ? SplitOmitEmptyEntries(sepList, default, separator.Length, count)
+ : SplitKeepEmptyEntries(sepList, default, separator.Length, count);
+
+ sepListBuilder.Dispose();
+
+ return result;
+ }
+
+ private string[] SplitKeepEmptyEntries(ReadOnlySpan<int> sepList, ReadOnlySpan<int> lengthList, int defaultLength, int count)
+ {
+ Debug.Assert(count >= 2);
+
+ int currIndex = 0;
+ int arrIndex = 0;
+
+ count--;
+ int numActualReplaces = (sepList.Length < count) ? sepList.Length : count;
+
+ //Allocate space for the new array.
+ //+1 for the string from the end of the last replace to the end of the string.
+ string[] splitStrings = new string[numActualReplaces + 1];
+
+ for (int i = 0; i < numActualReplaces && currIndex < Length; i++)
+ {
+ splitStrings[arrIndex++] = Substring(currIndex, sepList[i] - currIndex);
+ currIndex = sepList[i] + (lengthList.IsEmpty ? defaultLength : lengthList[i]);
+ }
+
+ //Handle the last string at the end of the array if there is one.
+ if (currIndex < Length && numActualReplaces >= 0)
+ {
+ splitStrings[arrIndex] = Substring(currIndex);
+ }
+ else if (arrIndex == numActualReplaces)
+ {
+ //We had a separator character at the end of a string. Rather than just allowing
+ //a null character, we'll replace the last element in the array with an empty string.
+ splitStrings[arrIndex] = string.Empty;
+ }
+
+ return splitStrings;
+ }
+
+
+ // This function will not keep the Empty string
+ private string[] SplitOmitEmptyEntries(ReadOnlySpan<int> sepList, ReadOnlySpan<int> lengthList, int defaultLength, int count)
+ {
+ Debug.Assert(count >= 2);
+
+ int numReplaces = sepList.Length;
+
+ // Allocate array to hold items. This array may not be
+ // filled completely in this function, we will create a
+ // new array and copy string references to that new array.
+ int maxItems = (numReplaces < count) ? (numReplaces + 1) : count;
+ string[] splitStrings = new string[maxItems];
+
+ int currIndex = 0;
+ int arrIndex = 0;
+
+ for (int i = 0; i < numReplaces && currIndex < Length; i++)
+ {
+ if (sepList[i] - currIndex > 0)
+ {
+ splitStrings[arrIndex++] = Substring(currIndex, sepList[i] - currIndex);
+ }
+ currIndex = sepList[i] + (lengthList.IsEmpty ? defaultLength : lengthList[i]);
+ if (arrIndex == count - 1)
+ {
+ // If all the remaining entries at the end are empty, skip them
+ while (i < numReplaces - 1 && currIndex == sepList[++i])
+ {
+ currIndex += (lengthList.IsEmpty ? defaultLength : lengthList[i]);
+ }
+ break;
+ }
+ }
+
+ // we must have at least one slot left to fill in the last string.
+ Debug.Assert(arrIndex < maxItems);
+
+ //Handle the last string at the end of the array if there is one.
+ if (currIndex < Length)
+ {
+ splitStrings[arrIndex++] = Substring(currIndex);
+ }
+
+ string[] stringArray = splitStrings;
+ if (arrIndex != maxItems)
+ {
+ stringArray = new string[arrIndex];
+ for (int j = 0; j < arrIndex; j++)
+ {
+ stringArray[j] = splitStrings[j];
+ }
+ }
+ return stringArray;
+ }
+
+ /// <summary>
+ /// Uses ValueListBuilder to create list that holds indexes of separators in string.
+ /// </summary>
+ /// <param name="separators"><see cref="ReadOnlySpan{T}"/> of separator chars</param>
+ /// <param name="sepListBuilder"><see cref="ValueListBuilder{T}"/> to store indexes</param>
+ /// <returns></returns>
+ private void MakeSeparatorList(ReadOnlySpan<char> separators, ref ValueListBuilder<int> sepListBuilder)
+ {
+ char sep0, sep1, sep2;
+
+ switch (separators.Length)
+ {
+ // Special-case no separators to mean any whitespace is a separator.
+ case 0:
+ for (int i = 0; i < Length; i++)
+ {
+ if (char.IsWhiteSpace(this[i]))
+ {
+ sepListBuilder.Append(i);
+ }
+ }
+ break;
+
+ // Special-case the common cases of 1, 2, and 3 separators, with manual comparisons against each separator.
+ case 1:
+ sep0 = separators[0];
+ for (int i = 0; i < Length; i++)
+ {
+ if (this[i] == sep0)
+ {
+ sepListBuilder.Append(i);
+ }
+ }
+ break;
+ case 2:
+ sep0 = separators[0];
+ sep1 = separators[1];
+ for (int i = 0; i < Length; i++)
+ {
+ char c = this[i];
+ if (c == sep0 || c == sep1)
+ {
+ sepListBuilder.Append(i);
+ }
+ }
+ break;
+ case 3:
+ sep0 = separators[0];
+ sep1 = separators[1];
+ sep2 = separators[2];
+ for (int i = 0; i < Length; i++)
+ {
+ char c = this[i];
+ if (c == sep0 || c == sep1 || c == sep2)
+ {
+ sepListBuilder.Append(i);
+ }
+ }
+ break;
+
+ // Handle > 3 separators with a probabilistic map, ala IndexOfAny.
+ // This optimizes for chars being unlikely to match a separator.
+ default:
+ unsafe
+ {
+ ProbabilisticMap map = default;
+ uint* charMap = (uint*)&map;
+ InitializeProbabilisticMap(charMap, separators);
+
+ for (int i = 0; i < Length; i++)
+ {
+ char c = this[i];
+ if (IsCharBitSet(charMap, (byte)c) && IsCharBitSet(charMap, (byte)(c >> 8)) &&
+ separators.Contains(c))
+ {
+ sepListBuilder.Append(i);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ /// <summary>
+ /// Uses ValueListBuilder to create list that holds indexes of separators in string.
+ /// </summary>
+ /// <param name="separator">separator string</param>
+ /// <param name="sepListBuilder"><see cref="ValueListBuilder{T}"/> to store indexes</param>
+ /// <returns></returns>
+ private void MakeSeparatorList(string separator, ref ValueListBuilder<int> sepListBuilder)
+ {
+ Debug.Assert(!IsNullOrEmpty(separator), "!string.IsNullOrEmpty(separator)");
+
+ int currentSepLength = separator.Length;
+
+ for (int i = 0; i < Length; i++)
+ {
+ if (this[i] == separator[0] && currentSepLength <= Length - i)
+ {
+ if (currentSepLength == 1
+ || this.AsSpan(i, currentSepLength).SequenceEqual(separator))
+ {
+ sepListBuilder.Append(i);
+ i += currentSepLength - 1;
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Uses ValueListBuilder to create list that holds indexes of separators in string and list that holds length of separator strings.
+ /// </summary>
+ /// <param name="separators">separator strngs</param>
+ /// <param name="sepListBuilder"><see cref="ValueListBuilder{T}"/> for separator indexes</param>
+ /// <param name="lengthListBuilder"><see cref="ValueListBuilder{T}"/> for separator length values</param>
+ private void MakeSeparatorList(string[] separators, ref ValueListBuilder<int> sepListBuilder, ref ValueListBuilder<int> lengthListBuilder)
+ {
+ Debug.Assert(separators != null && separators.Length > 0, "separators != null && separators.Length > 0");
+
+ int sepCount = separators.Length;
+
+ for (int i = 0; i < Length; i++)
+ {
+ for (int j = 0; j < separators.Length; j++)
+ {
+ string separator = separators[j];
+ if (IsNullOrEmpty(separator))
+ {
+ continue;
+ }
+ int currentSepLength = separator.Length;
+ if (this[i] == separator[0] && currentSepLength <= Length - i)
+ {
+ if (currentSepLength == 1
+ || this.AsSpan(i, currentSepLength).SequenceEqual(separator))
+ {
+ sepListBuilder.Append(i);
+ lengthListBuilder.Append(currentSepLength);
+ i += currentSepLength - 1;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Returns a substring of this string.
+ //
+ public string Substring(int startIndex) => Substring(startIndex, Length - startIndex);
+
+ public string Substring(int startIndex, int length)
+ {
+ if (startIndex < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_StartIndex);
+ }
+
+ if (startIndex > Length)
+ {
+ throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_StartIndexLargerThanLength);
+ }
+
+ if (length < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_NegativeLength);
+ }
+
+ if (startIndex > Length - length)
+ {
+ throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_IndexLength);
+ }
+
+ if (length == 0)
+ {
+ return string.Empty;
+ }
+
+ if (startIndex == 0 && length == this.Length)
+ {
+ return this;
+ }
+
+ return InternalSubString(startIndex, length);
+ }
+
+ private unsafe string InternalSubString(int startIndex, int length)
+ {
+ Debug.Assert(startIndex >= 0 && startIndex <= this.Length, "StartIndex is out of range!");
+ Debug.Assert(length >= 0 && startIndex <= this.Length - length, "length is out of range!");
+
+ string result = FastAllocateString(length);
+
+ fixed (char* dest = &result._firstChar)
+ fixed (char* src = &_firstChar)
+ {
+ wstrcpy(dest, src + startIndex, length);
+ }
+
+ return result;
+ }
+
+ // Creates a copy of this string in lower case. The culture is set by culture.
+ public string ToLower()
+ {
+ return CultureInfo.CurrentCulture.TextInfo.ToLower(this);
+ }
+
+ // Creates a copy of this string in lower case. The culture is set by culture.
+ public string ToLower(CultureInfo culture)
+ {
+ if (culture == null)
+ {
+ throw new ArgumentNullException(nameof(culture));
+ }
+ return culture.TextInfo.ToLower(this);
+ }
+
+ // Creates a copy of this string in lower case based on invariant culture.
+ public string ToLowerInvariant()
+ {
+ return CultureInfo.InvariantCulture.TextInfo.ToLower(this);
+ }
+
+ public string ToUpper()
+ {
+ return CultureInfo.CurrentCulture.TextInfo.ToUpper(this);
+ }
+
+ // Creates a copy of this string in upper case. The culture is set by culture.
+ public string ToUpper(CultureInfo culture)
+ {
+ if (culture == null)
+ {
+ throw new ArgumentNullException(nameof(culture));
+ }
+ return culture.TextInfo.ToUpper(this);
+ }
+
+ //Creates a copy of this string in upper case based on invariant culture.
+ public string ToUpperInvariant()
+ {
+ return CultureInfo.InvariantCulture.TextInfo.ToUpper(this);
+ }
+
+ // Trims the whitespace from both ends of the string. Whitespace is defined by
+ // Char.IsWhiteSpace.
+ //
+ public string Trim() => TrimWhiteSpaceHelper(TrimType.Both);
+
+ // Removes a set of characters from the beginning and end of this string.
+ public unsafe string Trim(char trimChar) => TrimHelper(&trimChar, 1, TrimType.Both);
+
+ // Removes a set of characters from the beginning and end of this string.
+ public unsafe string Trim(params char[] trimChars)
+ {
+ if (trimChars == null || trimChars.Length == 0)
+ {
+ return TrimWhiteSpaceHelper(TrimType.Both);
+ }
+ fixed (char* pTrimChars = &trimChars[0])
+ {
+ return TrimHelper(pTrimChars, trimChars.Length, TrimType.Both);
+ }
+ }
+
+ // Removes a set of characters from the beginning of this string.
+ public string TrimStart() => TrimWhiteSpaceHelper(TrimType.Head);
+
+ // Removes a set of characters from the beginning of this string.
+ public unsafe string TrimStart(char trimChar) => TrimHelper(&trimChar, 1, TrimType.Head);
+
+ // Removes a set of characters from the beginning of this string.
+ public unsafe string TrimStart(params char[] trimChars)
+ {
+ if (trimChars == null || trimChars.Length == 0)
+ {
+ return TrimWhiteSpaceHelper(TrimType.Head);
+ }
+ fixed (char* pTrimChars = &trimChars[0])
+ {
+ return TrimHelper(pTrimChars, trimChars.Length, TrimType.Head);
+ }
+ }
+
+ // Removes a set of characters from the end of this string.
+ public string TrimEnd() => TrimWhiteSpaceHelper(TrimType.Tail);
+
+ // Removes a set of characters from the end of this string.
+ public unsafe string TrimEnd(char trimChar) => TrimHelper(&trimChar, 1, TrimType.Tail);
+
+ // Removes a set of characters from the end of this string.
+ public unsafe string TrimEnd(params char[] trimChars)
+ {
+ if (trimChars == null || trimChars.Length == 0)
+ {
+ return TrimWhiteSpaceHelper(TrimType.Tail);
+ }
+ fixed (char* pTrimChars = &trimChars[0])
+ {
+ return TrimHelper(pTrimChars, trimChars.Length, TrimType.Tail);
+ }
+ }
+
+ private string TrimWhiteSpaceHelper(TrimType trimType)
+ {
+ // end will point to the first non-trimmed character on the right.
+ // start will point to the first non-trimmed character on the left.
+ int end = Length - 1;
+ int start = 0;
+
+ // Trim specified characters.
+ if (trimType != TrimType.Tail)
+ {
+ for (start = 0; start < Length; start++)
+ {
+ if (!char.IsWhiteSpace(this[start]))
+ {
+ break;
+ }
+ }
+ }
+
+ if (trimType != TrimType.Head)
+ {
+ for (end = Length - 1; end >= start; end--)
+ {
+ if (!char.IsWhiteSpace(this[end]))
+ {
+ break;
+ }
+ }
+ }
+
+ return CreateTrimmedString(start, end);
+ }
+
+ private unsafe string TrimHelper(char* trimChars, int trimCharsLength, TrimType trimType)
+ {
+ Debug.Assert(trimChars != null);
+ Debug.Assert(trimCharsLength > 0);
+
+ // end will point to the first non-trimmed character on the right.
+ // start will point to the first non-trimmed character on the left.
+ int end = Length - 1;
+ int start = 0;
+
+ // Trim specified characters.
+ if (trimType != TrimType.Tail)
+ {
+ for (start = 0; start < Length; start++)
+ {
+ int i = 0;
+ char ch = this[start];
+ for (i = 0; i < trimCharsLength; i++)
+ {
+ if (trimChars[i] == ch)
+ {
+ break;
+ }
+ }
+ if (i == trimCharsLength)
+ {
+ // The character is not in trimChars, so stop trimming.
+ break;
+ }
+ }
+ }
+
+ if (trimType != TrimType.Head)
+ {
+ for (end = Length - 1; end >= start; end--)
+ {
+ int i = 0;
+ char ch = this[end];
+ for (i = 0; i < trimCharsLength; i++)
+ {
+ if (trimChars[i] == ch)
+ {
+ break;
+ }
+ }
+ if (i == trimCharsLength)
+ {
+ // The character is not in trimChars, so stop trimming.
+ break;
+ }
+ }
+ }
+
+ return CreateTrimmedString(start, end);
+ }
+
+ private string CreateTrimmedString(int start, int end)
+ {
+ int len = end - start + 1;
+ return
+ len == Length ? this :
+ len == 0 ? string.Empty :
+ InternalSubString(start, len);
+ }
+
+ private enum TrimType
+ {
+ Head = 0,
+ Tail = 1,
+ Both = 2
+ }
+ }
+}
diff --git a/src/Common/src/CoreLib/System/String.Searching.cs b/src/Common/src/CoreLib/System/String.Searching.cs
index b0ba92b6e5..cc6e218d8d 100644
--- a/src/Common/src/CoreLib/System/String.Searching.cs
+++ b/src/Common/src/CoreLib/System/String.Searching.cs
@@ -3,7 +3,10 @@
// See the LICENSE file in the project root for more information.
using System.Globalization;
+using System.Numerics;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using Internal.Runtime.CompilerServices;
namespace System
{
@@ -63,24 +66,35 @@ namespace System
case StringComparison.OrdinalIgnoreCase:
return CompareInfo.Invariant.IndexOf(this, value, CompareOptions.OrdinalIgnoreCase);
-
+
default:
throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType));
}
}
-
+
public unsafe int IndexOf(char value, int startIndex, int count)
{
- if (startIndex < 0 || startIndex > Length)
+ if ((uint)startIndex > (uint)Length)
throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
- if (count < 0 || count > Length - startIndex)
+ if ((uint)count > (uint)(Length - startIndex))
throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count);
fixed (char* pChars = &_firstChar)
{
char* pCh = pChars + startIndex;
+ char* pEndCh = pCh + count;
+ if (Vector.IsHardwareAccelerated && count >= Vector<ushort>.Count * 2)
+ {
+ unchecked
+ {
+ const int elementsPerByte = sizeof(ushort) / sizeof(byte);
+ int unaligned = ((int)pCh & (Vector<byte>.Count - 1)) / elementsPerByte;
+ count = ((Vector<ushort>.Count - unaligned) & (Vector<ushort>.Count - 1));
+ }
+ }
+ SequentialScan:
while (count >= 4)
{
if (*pCh == value) goto ReturnIndex;
@@ -101,6 +115,34 @@ namespace System
pCh++;
}
+ if (pCh < pEndCh)
+ {
+ count = (int)((pEndCh - pCh) & ~(Vector<ushort>.Count - 1));
+ // Get comparison Vector
+ Vector<ushort> vComparison = new Vector<ushort>(value);
+ while (count > 0)
+ {
+ var vMatches = Vector.Equals(vComparison, Unsafe.ReadUnaligned<Vector<ushort>>(pCh));
+ if (Vector<ushort>.Zero.Equals(vMatches))
+ {
+ pCh += Vector<ushort>.Count;
+ count -= Vector<ushort>.Count;
+ continue;
+ }
+ // Find offset of first match
+ return (int)(pCh - pChars) + LocateFirstFoundChar(vMatches);
+ }
+
+ if (pCh < pEndCh)
+ {
+ unchecked
+ {
+ count = (int)(pEndCh - pCh);
+ }
+ goto SequentialScan;
+ }
+ }
+
return -1;
ReturnIndex3: pCh++;
@@ -111,6 +153,43 @@ namespace System
}
}
+ // Vector sub-search adapted from https://github.com/aspnet/KestrelHttpServer/pull/1138
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static int LocateFirstFoundChar(Vector<ushort> match)
+ {
+ var vector64 = Vector.AsVectorUInt64(match);
+ ulong candidate = 0;
+ int i = 0;
+ // Pattern unrolled by jit https://github.com/dotnet/coreclr/pull/8001
+ for (; i < Vector<ulong>.Count; i++)
+ {
+ candidate = vector64[i];
+ if (candidate != 0)
+ {
+ break;
+ }
+ }
+
+ // Single LEA instruction with jitted const (using function result)
+ return i * 4 + LocateFirstFoundChar(candidate);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static int LocateFirstFoundChar(ulong match)
+ {
+ unchecked
+ {
+ // Flag least significant power of two bit
+ var powerOfTwoFlag = match ^ (match - 1);
+ // Shift all powers of two into the high byte and extract
+ return (int)((powerOfTwoFlag * XorPowerOfTwoToHighChar) >> 49);
+ }
+ }
+
+ private const ulong XorPowerOfTwoToHighChar = (0x03ul |
+ 0x02ul << 16 |
+ 0x01ul << 32) + 1;
+
// Returns the index of the first occurrence of any specified character in the current instance.
// The search starts at startIndex and runs to startIndex + count - 1.
//
@@ -295,27 +374,27 @@ namespace System
return false;
}
- private unsafe static bool IsCharBitSet(uint* charMap, byte value)
+ private static unsafe bool IsCharBitSet(uint* charMap, byte value)
{
return (charMap[value & PROBABILISTICMAP_BLOCK_INDEX_MASK] & (1u << (value >> PROBABILISTICMAP_BLOCK_INDEX_SHIFT))) != 0;
}
- private unsafe static void SetCharBit(uint* charMap, byte value)
+ private static unsafe void SetCharBit(uint* charMap, byte value)
{
charMap[value & PROBABILISTICMAP_BLOCK_INDEX_MASK] |= 1u << (value >> PROBABILISTICMAP_BLOCK_INDEX_SHIFT);
}
- public int IndexOf(String value)
+ public int IndexOf(string value)
{
return IndexOf(value, StringComparison.CurrentCulture);
}
- public int IndexOf(String value, int startIndex)
+ public int IndexOf(string value, int startIndex)
{
return IndexOf(value, startIndex, StringComparison.CurrentCulture);
}
- public int IndexOf(String value, int startIndex, int count)
+ public int IndexOf(string value, int startIndex, int count)
{
if (startIndex < 0 || startIndex > this.Length)
{
@@ -330,17 +409,17 @@ namespace System
return IndexOf(value, startIndex, count, StringComparison.CurrentCulture);
}
- public int IndexOf(String value, StringComparison comparisonType)
+ public int IndexOf(string value, StringComparison comparisonType)
{
return IndexOf(value, 0, this.Length, comparisonType);
}
- public int IndexOf(String value, int startIndex, StringComparison comparisonType)
+ public int IndexOf(string value, int startIndex, StringComparison comparisonType)
{
return IndexOf(value, startIndex, this.Length - startIndex, comparisonType);
}
- public int IndexOf(String value, int startIndex, int count, StringComparison comparisonType)
+ public int IndexOf(string value, int startIndex, int count, StringComparison comparisonType)
{
// Validate inputs
if (value == null)
@@ -397,17 +476,27 @@ namespace System
if (Length == 0)
return -1;
- if (startIndex < 0 || startIndex >= Length)
+ if ((uint)startIndex >= (uint)Length)
throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
- if (count < 0 || count - 1 > startIndex)
+ if ((uint)count > (uint)startIndex + 1)
throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count);
fixed (char* pChars = &_firstChar)
{
char* pCh = pChars + startIndex;
+ char* pEndCh = pCh - count;
//We search [startIndex..EndIndex]
+ if (Vector.IsHardwareAccelerated && count >= Vector<ushort>.Count * 2)
+ {
+ unchecked
+ {
+ const int elementsPerByte = sizeof(ushort) / sizeof(byte);
+ count = (((int)pCh & (Vector<byte>.Count - 1)) / elementsPerByte) + 1;
+ }
+ }
+ SequentialScan:
while (count >= 4)
{
if (*pCh == value) goto ReturnIndex;
@@ -428,6 +517,35 @@ namespace System
pCh--;
}
+ if (pCh > pEndCh)
+ {
+ count = (int)((pCh - pEndCh) & ~(Vector<ushort>.Count - 1));
+
+ // Get comparison Vector
+ Vector<ushort> vComparison = new Vector<ushort>(value);
+ while (count > 0)
+ {
+ char* pStart = pCh - Vector<ushort>.Count + 1;
+ var vMatches = Vector.Equals(vComparison, Unsafe.ReadUnaligned<Vector<ushort>>(pStart));
+ if (Vector<ushort>.Zero.Equals(vMatches))
+ {
+ pCh -= Vector<ushort>.Count;
+ count -= Vector<ushort>.Count;
+ continue;
+ }
+ // Find offset of last match
+ return (int)(pStart - pChars) + LocateLastFoundChar(vMatches);
+ }
+
+ if (pCh > pEndCh)
+ {
+ unchecked
+ {
+ count = (int)(pCh - pEndCh);
+ }
+ goto SequentialScan;
+ }
+ }
return -1;
ReturnIndex3: pCh--;
@@ -438,6 +556,40 @@ namespace System
}
}
+ // Vector sub-search adapted from https://github.com/aspnet/KestrelHttpServer/pull/1138
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static int LocateLastFoundChar(Vector<ushort> match)
+ {
+ var vector64 = Vector.AsVectorUInt64(match);
+ ulong candidate = 0;
+ int i = Vector<ulong>.Count - 1;
+ // Pattern unrolled by jit https://github.com/dotnet/coreclr/pull/8001
+ for (; i >= 0; i--)
+ {
+ candidate = vector64[i];
+ if (candidate != 0)
+ {
+ break;
+ }
+ }
+
+ // Single LEA instruction with jitted const (using function result)
+ return i * 4 + LocateLastFoundChar(candidate);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static int LocateLastFoundChar(ulong match)
+ {
+ // Find the most significant char that has its highest bit set
+ int index = 3;
+ while ((long)match > 0)
+ {
+ match = match << 16;
+ index--;
+ }
+ return index;
+ }
+
// Returns the index of the last occurrence of any specified character in the current instance.
// The search starts at startIndex and runs backwards to startIndex - count + 1.
// The character at position startIndex is included in the search. startIndex is the larger
@@ -521,17 +673,17 @@ namespace System
// The character at position startIndex is included in the search. startIndex is the larger
// index within the string.
//
- public int LastIndexOf(String value)
+ public int LastIndexOf(string value)
{
return LastIndexOf(value, this.Length - 1, this.Length, StringComparison.CurrentCulture);
}
- public int LastIndexOf(String value, int startIndex)
+ public int LastIndexOf(string value, int startIndex)
{
return LastIndexOf(value, startIndex, startIndex + 1, StringComparison.CurrentCulture);
}
- public int LastIndexOf(String value, int startIndex, int count)
+ public int LastIndexOf(string value, int startIndex, int count)
{
if (count < 0)
{
@@ -541,17 +693,17 @@ namespace System
return LastIndexOf(value, startIndex, count, StringComparison.CurrentCulture);
}
- public int LastIndexOf(String value, StringComparison comparisonType)
+ public int LastIndexOf(string value, StringComparison comparisonType)
{
return LastIndexOf(value, this.Length - 1, this.Length, comparisonType);
}
- public int LastIndexOf(String value, int startIndex, StringComparison comparisonType)
+ public int LastIndexOf(string value, int startIndex, StringComparison comparisonType)
{
return LastIndexOf(value, startIndex, startIndex + 1, comparisonType);
}
- public int LastIndexOf(String value, int startIndex, int count, StringComparison comparisonType)
+ public int LastIndexOf(string value, int startIndex, int count, StringComparison comparisonType)
{
if (value == null)
throw new ArgumentNullException(nameof(value));
diff --git a/src/Common/src/CoreLib/System/String.cs b/src/Common/src/CoreLib/System/String.cs
new file mode 100644
index 0000000000..a1251d6be0
--- /dev/null
+++ b/src/Common/src/CoreLib/System/String.cs
@@ -0,0 +1,759 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Versioning;
+using System.Text;
+
+namespace System
+{
+ // The String class represents a static string of characters. Many of
+ // the String methods perform some type of transformation on the current
+ // instance and return the result as a new String. As with arrays, character
+ // positions (indices) are zero-based.
+
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+ public sealed partial class String : IComparable, IEnumerable, IEnumerable<char>, IComparable<String>, IEquatable<String>, IConvertible, ICloneable
+ {
+ // String constructors
+ // These are special. The implementation methods for these have a different signature from the
+ // declared constructors.
+
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ public extern String(char[] value);
+
+#if PROJECTN
+ [DependencyReductionRoot]
+#endif
+#if !CORECLR
+ static
+#endif
+ private string Ctor(char[] value)
+ {
+ if (value == null || value.Length == 0)
+ return Empty;
+
+ string result = FastAllocateString(value.Length);
+ unsafe
+ {
+ fixed (char* dest = &result._firstChar, source = value)
+ wstrcpy(dest, source, value.Length);
+ }
+ return result;
+ }
+
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ public extern String(char[] value, int startIndex, int length);
+
+#if PROJECTN
+ [DependencyReductionRoot]
+#endif
+#if !CORECLR
+ static
+#endif
+ private string Ctor(char[] value, int startIndex, int length)
+ {
+ if (value == null)
+ throw new ArgumentNullException(nameof(value));
+
+ if (startIndex < 0)
+ throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_StartIndex);
+
+ if (length < 0)
+ throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_NegativeLength);
+
+ if (startIndex > value.Length - length)
+ throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
+
+ if (length == 0)
+ return Empty;
+
+ string result = FastAllocateString(length);
+ unsafe
+ {
+ fixed (char* dest = &result._firstChar, source = value)
+ wstrcpy(dest, source + startIndex, length);
+ }
+ return result;
+ }
+
+ [CLSCompliant(false)]
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ public extern unsafe String(char* value);
+
+#if PROJECTN
+ [DependencyReductionRoot]
+#endif
+#if !CORECLR
+ static
+#endif
+ private unsafe string Ctor(char* ptr)
+ {
+ if (ptr == null)
+ return Empty;
+
+ int count = wcslen(ptr);
+ if (count == 0)
+ return Empty;
+
+ string result = FastAllocateString(count);
+ fixed (char* dest = &result._firstChar)
+ wstrcpy(dest, ptr, count);
+ return result;
+ }
+
+ [CLSCompliant(false)]
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ public extern unsafe String(char* value, int startIndex, int length);
+
+#if PROJECTN
+ [DependencyReductionRoot]
+#endif
+#if !CORECLR
+ static
+#endif
+ private unsafe string Ctor(char* ptr, int startIndex, int length)
+ {
+ if (length < 0)
+ throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_NegativeLength);
+
+ if (startIndex < 0)
+ throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_StartIndex);
+
+ char* pStart = ptr + startIndex;
+
+ // overflow check
+ if (pStart < ptr)
+ throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_PartialWCHAR);
+
+ if (length == 0)
+ return Empty;
+
+ if (ptr == null)
+ throw new ArgumentOutOfRangeException(nameof(ptr), SR.ArgumentOutOfRange_PartialWCHAR);
+
+ string result = FastAllocateString(length);
+ fixed (char* dest = &result._firstChar)
+ wstrcpy(dest, pStart, length);
+ return result;
+ }
+
+ [CLSCompliant(false)]
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ public extern unsafe String(sbyte* value);
+
+#if PROJECTN
+ [DependencyReductionRoot]
+#endif
+#if !CORECLR
+ static
+#endif
+ private unsafe string Ctor(sbyte* value)
+ {
+ byte* pb = (byte*)value;
+ if (pb == null)
+ return Empty;
+
+ int numBytes = new ReadOnlySpan<byte>((byte*)value, int.MaxValue).IndexOf<byte>(0);
+
+ // Check for overflow
+ if (numBytes < 0)
+ throw new ArgumentException(SR.Arg_MustBeNullTerminatedString);
+
+ return CreateStringForSByteConstructor(pb, numBytes);
+ }
+
+ [CLSCompliant(false)]
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ public extern unsafe String(sbyte* value, int startIndex, int length);
+
+#if PROJECTN
+ [DependencyReductionRoot]
+#endif
+#if !CORECLR
+ static
+#endif
+ private unsafe string Ctor(sbyte* value, int startIndex, int length)
+ {
+ if (startIndex < 0)
+ throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_StartIndex);
+
+ if (length < 0)
+ throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_NegativeLength);
+
+ if (value == null)
+ {
+ if (length == 0)
+ return Empty;
+
+ throw new ArgumentNullException(nameof(value));
+ }
+
+ byte* pStart = (byte*)(value + startIndex);
+
+ // overflow check
+ if (pStart < value)
+ throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_PartialWCHAR);
+
+ return CreateStringForSByteConstructor(pStart, length);
+ }
+
+ // Encoder for String..ctor(sbyte*) and String..ctor(sbyte*, int, int)
+ private static unsafe string CreateStringForSByteConstructor(byte *pb, int numBytes)
+ {
+ Debug.Assert(numBytes >= 0);
+ Debug.Assert(pb <= (pb + numBytes));
+
+ if (numBytes == 0)
+ return Empty;
+
+#if PLATFORM_UNIX
+ return Encoding.UTF8.GetString(pb, numBytes);
+#else
+ int numCharsRequired = Interop.Kernel32.MultiByteToWideChar(Interop.Kernel32.CP_ACP, Interop.Kernel32.MB_PRECOMPOSED, pb, numBytes, (char*)null, 0);
+ if (numCharsRequired == 0)
+ throw new ArgumentException(SR.Arg_InvalidANSIString);
+
+ string newString = FastAllocateString(numCharsRequired);
+ fixed (char *pFirstChar = &newString._firstChar)
+ {
+ numCharsRequired = Interop.Kernel32.MultiByteToWideChar(Interop.Kernel32.CP_ACP, Interop.Kernel32.MB_PRECOMPOSED, pb, numBytes, pFirstChar, numCharsRequired);
+ }
+ if (numCharsRequired == 0)
+ throw new ArgumentException(SR.Arg_InvalidANSIString);
+ return newString;
+#endif
+ }
+
+ [CLSCompliant(false)]
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ public extern unsafe String(sbyte* value, int startIndex, int length, Encoding enc);
+
+#if PROJECTN
+ [DependencyReductionRoot]
+#endif
+#if !CORECLR
+ static
+#endif
+ private unsafe string Ctor(sbyte* value, int startIndex, int length, Encoding enc)
+ {
+ if (enc == null)
+ return new string(value, startIndex, length);
+
+ if (length < 0)
+ throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_NeedNonNegNum);
+
+ if (startIndex < 0)
+ throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_StartIndex);
+
+ if (value == null)
+ {
+ if (length == 0)
+ return Empty;
+
+ throw new ArgumentNullException(nameof(value));
+ }
+
+ byte* pStart = (byte*)(value + startIndex);
+
+ // overflow check
+ if (pStart < value)
+ throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_PartialWCHAR);
+
+ return enc.GetString(new ReadOnlySpan<byte>(pStart, length));
+ }
+
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ public extern String(char c, int count);
+
+#if PROJECTN
+ [DependencyReductionRoot]
+#endif
+#if !CORECLR
+ static
+#endif
+ private string Ctor(char c, int count)
+ {
+ if (count <= 0)
+ {
+ if (count == 0)
+ return Empty;
+ throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NegativeCount);
+ }
+
+ string result = FastAllocateString(count);
+
+ if (c != '\0') // Fast path null char string
+ {
+ unsafe
+ {
+ fixed (char* dest = &result._firstChar)
+ {
+ uint cc = (uint)((c << 16) | c);
+ uint* dmem = (uint*)dest;
+ if (count >= 4)
+ {
+ count -= 4;
+ do
+ {
+ dmem[0] = cc;
+ dmem[1] = cc;
+ dmem += 2;
+ count -= 4;
+ } while (count >= 0);
+ }
+ if ((count & 2) != 0)
+ {
+ *dmem = cc;
+ dmem++;
+ }
+ if ((count & 1) != 0)
+ ((char*)dmem)[0] = c;
+ }
+ }
+ }
+ return result;
+ }
+
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ public extern String(ReadOnlySpan<char> value);
+
+#if PROJECTN
+ [DependencyReductionRoot]
+#endif
+#if !CORECLR
+ static
+#endif
+ private unsafe string Ctor(ReadOnlySpan<char> value)
+ {
+ if (value.Length == 0)
+ return Empty;
+
+ string result = FastAllocateString(value.Length);
+ fixed (char* dest = &result._firstChar, src = &MemoryMarshal.GetReference(value))
+ wstrcpy(dest, src, value.Length);
+ return result;
+ }
+
+ public static string Create<TState>(int length, TState state, SpanAction<char, TState> action)
+ {
+ if (action == null)
+ throw new ArgumentNullException(nameof(action));
+
+ if (length <= 0)
+ {
+ if (length == 0)
+ return Empty;
+ throw new ArgumentOutOfRangeException(nameof(length));
+ }
+
+ string result = FastAllocateString(length);
+ action(new Span<char>(ref result.GetRawStringData(), length), state);
+ return result;
+ }
+
+ public static implicit operator ReadOnlySpan<char>(string value) =>
+ value != null ? new ReadOnlySpan<char>(ref value.GetRawStringData(), value.Length) : default;
+
+ public object Clone()
+ {
+ return this;
+ }
+
+ public static unsafe string Copy(string str)
+ {
+ if (str == null)
+ throw new ArgumentNullException(nameof(str));
+
+ string result = FastAllocateString(str.Length);
+ fixed (char* dest = &result._firstChar, src = &str._firstChar)
+ wstrcpy(dest, src, str.Length);
+ return result;
+ }
+
+ // Converts a substring of this string to an array of characters. Copies the
+ // characters of this string beginning at position sourceIndex and ending at
+ // sourceIndex + count - 1 to the character array buffer, beginning
+ // at destinationIndex.
+ //
+ public unsafe void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count)
+ {
+ if (destination == null)
+ throw new ArgumentNullException(nameof(destination));
+ if (count < 0)
+ throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NegativeCount);
+ if (sourceIndex < 0)
+ throw new ArgumentOutOfRangeException(nameof(sourceIndex), SR.ArgumentOutOfRange_Index);
+ if (count > Length - sourceIndex)
+ throw new ArgumentOutOfRangeException(nameof(sourceIndex), SR.ArgumentOutOfRange_IndexCount);
+ if (destinationIndex > destination.Length - count || destinationIndex < 0)
+ throw new ArgumentOutOfRangeException(nameof(destinationIndex), SR.ArgumentOutOfRange_IndexCount);
+
+ fixed (char* src = &_firstChar, dest = destination)
+ wstrcpy(dest + destinationIndex, src + sourceIndex, count);
+ }
+
+ // Returns the entire string as an array of characters.
+ public unsafe char[] ToCharArray()
+ {
+ if (Length == 0)
+ return Array.Empty<char>();
+
+ char[] chars = new char[Length];
+ fixed (char* src = &_firstChar, dest = &chars[0])
+ wstrcpy(dest, src, Length);
+ return chars;
+ }
+
+ // Returns a substring of this string as an array of characters.
+ //
+ public unsafe char[] ToCharArray(int startIndex, int length)
+ {
+ // Range check everything.
+ if (startIndex < 0 || startIndex > Length || startIndex > Length - length)
+ throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
+
+ if (length <= 0)
+ {
+ if (length == 0)
+ return Array.Empty<char>();
+ throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_Index);
+ }
+
+ char[] chars = new char[length];
+ fixed (char* src = &_firstChar, dest = &chars[0])
+ wstrcpy(dest, src + startIndex, length);
+ return chars;
+ }
+
+ [NonVersionable]
+ public static bool IsNullOrEmpty(string value)
+ {
+ return (value == null || value.Length == 0);
+ }
+
+ public static bool IsNullOrWhiteSpace(string value)
+ {
+ if (value == null) return true;
+
+ for (int i = 0; i < value.Length; i++)
+ {
+ if (!Char.IsWhiteSpace(value[i])) return false;
+ }
+
+ return true;
+ }
+
+ internal ref char GetRawStringData() => ref _firstChar;
+
+ // Helper for encodings so they can talk to our buffer directly
+ // stringLength must be the exact size we'll expect
+ internal static unsafe string CreateStringFromEncoding(
+ byte* bytes, int byteLength, Encoding encoding)
+ {
+ Debug.Assert(bytes != null);
+ Debug.Assert(byteLength >= 0);
+
+ // Get our string length
+ int stringLength = encoding.GetCharCount(bytes, byteLength, null);
+ Debug.Assert(stringLength >= 0, "stringLength >= 0");
+
+ // They gave us an empty string if they needed one
+ // 0 bytelength might be possible if there's something in an encoder
+ if (stringLength == 0)
+ return Empty;
+
+ string s = FastAllocateString(stringLength);
+ fixed (char* pTempChars = &s._firstChar)
+ {
+ int doubleCheck = encoding.GetChars(bytes, byteLength, pTempChars, stringLength, null);
+ Debug.Assert(stringLength == doubleCheck,
+ "Expected encoding.GetChars to return same length as encoding.GetCharCount");
+ }
+
+ return s;
+ }
+
+ // This is only intended to be used by char.ToString.
+ // It is necessary to put the code in this class instead of Char, since _firstChar is a private member.
+ // Making _firstChar internal would be dangerous since it would make it much easier to break String's immutability.
+ internal static string CreateFromChar(char c)
+ {
+ string result = FastAllocateString(1);
+ result._firstChar = c;
+ return result;
+ }
+
+ internal static unsafe void wstrcpy(char* dmem, char* smem, int charCount)
+ {
+ Buffer.Memmove((byte*)dmem, (byte*)smem, ((uint)charCount) * 2);
+ }
+
+
+ // Returns this string.
+ public override string ToString()
+ {
+ return this;
+ }
+
+ // Returns this string.
+ public string ToString(IFormatProvider provider)
+ {
+ return this;
+ }
+
+ public CharEnumerator GetEnumerator()
+ {
+ return new CharEnumerator(this);
+ }
+
+ IEnumerator<char> IEnumerable<char>.GetEnumerator()
+ {
+ return new CharEnumerator(this);
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return new CharEnumerator(this);
+ }
+
+ internal static unsafe int wcslen(char* ptr)
+ {
+ char* end = ptr;
+
+ // First make sure our pointer is aligned on a word boundary
+ int alignment = IntPtr.Size - 1;
+
+ // If ptr is at an odd address (e.g. 0x5), this loop will simply iterate all the way
+ while (((uint)end & (uint)alignment) != 0)
+ {
+ if (*end == 0) goto FoundZero;
+ end++;
+ }
+
+#if !BIT64
+ // The following code is (somewhat surprisingly!) significantly faster than a naive loop,
+ // at least on x86 and the current jit.
+
+ // The loop condition below works because if "end[0] & end[1]" is non-zero, that means
+ // neither operand can have been zero. If is zero, we have to look at the operands individually,
+ // but we hope this going to fairly rare.
+
+ // In general, it would be incorrect to access end[1] if we haven't made sure
+ // end[0] is non-zero. However, we know the ptr has been aligned by the loop above
+ // so end[0] and end[1] must be in the same word (and therefore page), so they're either both accessible, or both not.
+
+ while ((end[0] & end[1]) != 0 || (end[0] != 0 && end[1] != 0))
+ {
+ end += 2;
+ }
+
+ Debug.Assert(end[0] == 0 || end[1] == 0);
+ if (end[0] != 0) end++;
+#else // !BIT64
+ // Based on https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
+
+ // 64-bit implementation: process 1 ulong (word) at a time
+
+ // What we do here is add 0x7fff from each of the
+ // 4 individual chars within the ulong, using MagicMask.
+ // If the char > 0 and < 0x8001, it will have its high bit set.
+ // We then OR with MagicMask, to set all the other bits.
+ // This will result in all bits set (ulong.MaxValue) for any
+ // char that fits the above criteria, and something else otherwise.
+
+ // Note that for any char > 0x8000, this will be a false
+ // positive and we will fallback to the slow path and
+ // check each char individually. This is OK though, since
+ // we optimize for the common case (ASCII chars, which are < 0x80).
+
+ // NOTE: We can access a ulong a time since the ptr is aligned,
+ // and therefore we're only accessing the same word/page. (See notes
+ // for the 32-bit version above.)
+
+ const ulong MagicMask = 0x7fff7fff7fff7fff;
+
+ while (true)
+ {
+ ulong word = *(ulong*)end;
+ word += MagicMask; // cause high bit to be set if not zero, and <= 0x8000
+ word |= MagicMask; // set everything besides the high bits
+
+ if (word == ulong.MaxValue) // 0xffff...
+ {
+ // all of the chars have their bits set (and therefore none can be 0)
+ end += 4;
+ continue;
+ }
+
+ // at least one of them didn't have their high bit set!
+ // go through each char and check for 0.
+
+ if (end[0] == 0) goto EndAt0;
+ if (end[1] == 0) goto EndAt1;
+ if (end[2] == 0) goto EndAt2;
+ if (end[3] == 0) goto EndAt3;
+
+ // if we reached here, it was a false positive-- just continue
+ end += 4;
+ }
+
+ EndAt3: end++;
+ EndAt2: end++;
+ EndAt1: end++;
+ EndAt0:
+#endif // !BIT64
+
+ FoundZero:
+ Debug.Assert(*end == 0);
+
+ int count = (int)(end - ptr);
+
+#if BIT64
+ // Check for overflow
+ if (ptr + count != end)
+ throw new ArgumentException(SR.Arg_MustBeNullTerminatedString);
+#else
+ Debug.Assert(ptr + count == end);
+#endif
+
+ return count;
+ }
+
+ //
+ // IConvertible implementation
+ //
+
+ public TypeCode GetTypeCode()
+ {
+ return TypeCode.String;
+ }
+
+ bool IConvertible.ToBoolean(IFormatProvider provider)
+ {
+ return Convert.ToBoolean(this, provider);
+ }
+
+ char IConvertible.ToChar(IFormatProvider provider)
+ {
+ return Convert.ToChar(this, provider);
+ }
+
+ sbyte IConvertible.ToSByte(IFormatProvider provider)
+ {
+ return Convert.ToSByte(this, provider);
+ }
+
+ byte IConvertible.ToByte(IFormatProvider provider)
+ {
+ return Convert.ToByte(this, provider);
+ }
+
+ short IConvertible.ToInt16(IFormatProvider provider)
+ {
+ return Convert.ToInt16(this, provider);
+ }
+
+ ushort IConvertible.ToUInt16(IFormatProvider provider)
+ {
+ return Convert.ToUInt16(this, provider);
+ }
+
+ int IConvertible.ToInt32(IFormatProvider provider)
+ {
+ return Convert.ToInt32(this, provider);
+ }
+
+ uint IConvertible.ToUInt32(IFormatProvider provider)
+ {
+ return Convert.ToUInt32(this, provider);
+ }
+
+ long IConvertible.ToInt64(IFormatProvider provider)
+ {
+ return Convert.ToInt64(this, provider);
+ }
+
+ ulong IConvertible.ToUInt64(IFormatProvider provider)
+ {
+ return Convert.ToUInt64(this, provider);
+ }
+
+ float IConvertible.ToSingle(IFormatProvider provider)
+ {
+ return Convert.ToSingle(this, provider);
+ }
+
+ double IConvertible.ToDouble(IFormatProvider provider)
+ {
+ return Convert.ToDouble(this, provider);
+ }
+
+ Decimal IConvertible.ToDecimal(IFormatProvider provider)
+ {
+ return Convert.ToDecimal(this, provider);
+ }
+
+ DateTime IConvertible.ToDateTime(IFormatProvider provider)
+ {
+ return Convert.ToDateTime(this, provider);
+ }
+
+ Object IConvertible.ToType(Type type, IFormatProvider provider)
+ {
+ return Convert.DefaultToType((IConvertible)this, type, provider);
+ }
+
+ // Normalization Methods
+ // These just wrap calls to Normalization class
+ public bool IsNormalized()
+ {
+ return IsNormalized(NormalizationForm.FormC);
+ }
+
+ public bool IsNormalized(NormalizationForm normalizationForm)
+ {
+#if CORECLR
+ if (this.IsFastSort())
+ {
+ // If its FastSort && one of the 4 main forms, then its already normalized
+ if (normalizationForm == NormalizationForm.FormC ||
+ normalizationForm == NormalizationForm.FormKC ||
+ normalizationForm == NormalizationForm.FormD ||
+ normalizationForm == NormalizationForm.FormKD)
+ return true;
+ }
+#endif
+ return Normalization.IsNormalized(this, normalizationForm);
+ }
+
+ public string Normalize()
+ {
+ return Normalize(NormalizationForm.FormC);
+ }
+
+ public string Normalize(NormalizationForm normalizationForm)
+ {
+#if CORECLR
+ if (this.IsAscii())
+ {
+ // If its FastSort && one of the 4 main forms, then its already normalized
+ if (normalizationForm == NormalizationForm.FormC ||
+ normalizationForm == NormalizationForm.FormKC ||
+ normalizationForm == NormalizationForm.FormD ||
+ normalizationForm == NormalizationForm.FormKD)
+ return this;
+ }
+#endif
+ return Normalization.Normalize(this, normalizationForm);
+ }
+ }
+}
diff --git a/src/Common/src/CoreLib/System/StringComparer.cs b/src/Common/src/CoreLib/System/StringComparer.cs
index 73c013599d..cb2d32fccb 100644
--- a/src/Common/src/CoreLib/System/StringComparer.cs
+++ b/src/Common/src/CoreLib/System/StringComparer.cs
@@ -13,8 +13,8 @@ namespace System
[System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public abstract class StringComparer : IComparer, IEqualityComparer, IComparer<string>, IEqualityComparer<string>
{
- private static readonly CultureAwareComparer s_invariantCulture = new CultureAwareComparer(CultureInfo.InvariantCulture, false);
- private static readonly CultureAwareComparer s_invariantCultureIgnoreCase = new CultureAwareComparer(CultureInfo.InvariantCulture, true);
+ private static readonly CultureAwareComparer s_invariantCulture = new CultureAwareComparer(CultureInfo.InvariantCulture, CompareOptions.None);
+ private static readonly CultureAwareComparer s_invariantCultureIgnoreCase = new CultureAwareComparer(CultureInfo.InvariantCulture, CompareOptions.IgnoreCase);
private static readonly OrdinalCaseSensitiveComparer s_ordinal = new OrdinalCaseSensitiveComparer();
private static readonly OrdinalIgnoreCaseComparer s_ordinalIgnoreCase = new OrdinalIgnoreCaseComparer();
@@ -38,7 +38,7 @@ namespace System
{
get
{
- return new CultureAwareComparer(CultureInfo.CurrentCulture, false);
+ return new CultureAwareComparer(CultureInfo.CurrentCulture, CompareOptions.None);
}
}
@@ -46,7 +46,7 @@ namespace System
{
get
{
- return new CultureAwareComparer(CultureInfo.CurrentCulture, true);
+ return new CultureAwareComparer(CultureInfo.CurrentCulture, CompareOptions.IgnoreCase);
}
}
@@ -94,8 +94,18 @@ namespace System
{
throw new ArgumentNullException(nameof(culture));
}
+
+ return new CultureAwareComparer(culture, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
+ }
+
+ public static StringComparer Create(CultureInfo culture, CompareOptions options)
+ {
+ if (culture == null)
+ {
+ throw new ArgumentException(nameof(culture));
+ }
- return new CultureAwareComparer(culture, ignoreCase);
+ return new CultureAwareComparer(culture, options);
}
public int Compare(object x, object y)
@@ -123,7 +133,6 @@ namespace System
throw new ArgumentException(SR.Argument_ImplementIComparable);
}
-
public new bool Equals(Object x, Object y)
{
if (x == y) return true;
@@ -163,32 +172,52 @@ namespace System
[Serializable]
[System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
- public sealed class CultureAwareComparer : StringComparer
+ public sealed class CultureAwareComparer : StringComparer, ISerializable
{
+ private const CompareOptions ValidCompareMaskOffFlags = ~(CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols | CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreWidth | CompareOptions.IgnoreKanaType | CompareOptions.StringSort);
+
private readonly CompareInfo _compareInfo; // Do not rename (binary serialization)
- private readonly bool _ignoreCase; // Do not rename (binary serialization)
+ private CompareOptions _options;
- internal CultureAwareComparer(CultureInfo culture, bool ignoreCase)
+ internal CultureAwareComparer(CultureInfo culture, CompareOptions options) : this(culture.CompareInfo, options) { }
+
+ internal CultureAwareComparer(CompareInfo compareInfo, CompareOptions options)
{
- _compareInfo = culture.CompareInfo;
- _ignoreCase = ignoreCase;
+ _compareInfo = compareInfo;
+
+ if ((options & ValidCompareMaskOffFlags) != 0)
+ {
+ throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options));
+ }
+ _options = options;
}
- private CompareOptions Options => _ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None;
+ private CultureAwareComparer(SerializationInfo info, StreamingContext context)
+ {
+ _compareInfo = (CompareInfo)info.GetValue("_compareInfo", typeof(CompareInfo));
+ bool ignoreCase = info.GetBoolean("_ignoreCase");
+
+ var obj = info.GetValueNoThrow("_options", typeof(CompareOptions));
+ if (obj != null)
+ _options = (CompareOptions)obj;
+
+ // fix up the _options value in case we are getting old serialized object not having _options
+ _options |= ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None;
+ }
public override int Compare(string x, string y)
{
if (object.ReferenceEquals(x, y)) return 0;
if (x == null) return -1;
if (y == null) return 1;
- return _compareInfo.Compare(x, y, Options);
+ return _compareInfo.Compare(x, y, _options);
}
public override bool Equals(string x, string y)
{
if (object.ReferenceEquals(x, y)) return true;
if (x == null || y == null) return false;
- return _compareInfo.Compare(x, y, Options) == 0;
+ return _compareInfo.Compare(x, y, _options) == 0;
}
public override int GetHashCode(string obj)
@@ -197,7 +226,7 @@ namespace System
{
throw new ArgumentNullException(nameof(obj));
}
- return _compareInfo.GetHashCodeOfString(obj, Options);
+ return _compareInfo.GetHashCodeOfString(obj, _options);
}
// Equals method for the comparer itself.
@@ -206,14 +235,20 @@ namespace System
CultureAwareComparer comparer = obj as CultureAwareComparer;
return
comparer != null &&
- _ignoreCase == comparer._ignoreCase &&
+ _options == comparer._options &&
_compareInfo.Equals(comparer._compareInfo);
}
public override int GetHashCode()
{
- int hashCode = _compareInfo.GetHashCode();
- return _ignoreCase ? ~hashCode : hashCode;
+ return _compareInfo.GetHashCode() ^ ((int)_options & 0x7FFFFFFF);
+ }
+
+ public void GetObjectData(SerializationInfo info, StreamingContext context)
+ {
+ info.AddValue("_compareInfo", _compareInfo);
+ info.AddValue("_options", _options);
+ info.AddValue("_ignoreCase", (_options & CompareOptions.IgnoreCase) != 0);
}
}
@@ -272,7 +307,7 @@ namespace System
if (_ignoreCase)
{
- return TextInfo.GetHashCodeOrdinalIgnoreCase(obj);
+ return CompareInfo.GetIgnoreCaseHash(obj);
}
return obj.GetHashCode();
@@ -340,7 +375,7 @@ namespace System
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.obj);
}
- return TextInfo.GetHashCodeOrdinalIgnoreCase(obj);
+ return CompareInfo.GetIgnoreCaseHash(obj);
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
diff --git a/src/Common/src/CoreLib/System/StringSpanHelpers.cs b/src/Common/src/CoreLib/System/StringSpanHelpers.cs
deleted file mode 100644
index 1c127b19d0..0000000000
--- a/src/Common/src/CoreLib/System/StringSpanHelpers.cs
+++ /dev/null
@@ -1,129 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Globalization;
-
-namespace System
-{
- /// <summary>Helpers for string-like operations on spans of chars.</summary>
- internal static class StringSpanHelpers
- {
- // TODO https://github.com/dotnet/corefx/issues/21395: Provide public, efficient implementations
-
- public static bool Equals(this ReadOnlySpan<char> left, ReadOnlySpan<char> right, StringComparison comparisonType) =>
- comparisonType == StringComparison.Ordinal ? Equals(left, right) :
- comparisonType == StringComparison.OrdinalIgnoreCase ? EqualsOrdinalIgnoreCase(left, right) :
- throw new ArgumentOutOfRangeException(nameof(comparisonType));
-
- public static bool Equals(this ReadOnlySpan<char> left, string right) =>
- Equals(left, right.AsReadOnlySpan());
-
- public static bool Equals(this ReadOnlySpan<char> left, ReadOnlySpan<char> right)
- {
- if (left.Length != right.Length)
- {
- return false;
- }
-
- for (int i = 0; i < left.Length; i++)
- {
- if (left[i] != right[i])
- {
- return false;
- }
- }
-
- return true;
- }
-
- private static bool EqualsOrdinalIgnoreCase(this ReadOnlySpan<char> left, ReadOnlySpan<char> right)
- {
- if (left.Length != right.Length)
- {
- return false;
- }
-
- for (int i = 0; i < left.Length; i++)
- {
- char x = left[i], y = right[i];
- if (x != y &&
- TextInfo.ToUpperAsciiInvariant(x) != TextInfo.ToUpperAsciiInvariant(y))
- {
- return false;
- }
- }
-
- return true;
- }
-
- public static ReadOnlySpan<char> Trim(this ReadOnlySpan<char> source)
- {
- int startIndex = 0, endIndex = source.Length - 1;
-
- while (startIndex <= endIndex && char.IsWhiteSpace(source[startIndex]))
- {
- startIndex++;
- }
-
- while (endIndex >= startIndex && char.IsWhiteSpace(source[endIndex]))
- {
- endIndex--;
- }
-
- return source.Slice(startIndex, endIndex - startIndex + 1);
- }
-
- public static int IndexOf(this ReadOnlySpan<char> source, char value) =>
- IndexOf(source, value, 0);
-
- public static int IndexOf(this ReadOnlySpan<char> source, char value, int startIndex)
- {
- for (int i = startIndex; i < source.Length; i++)
- {
- if (source[i] == value)
- {
- return i;
- }
- }
-
- return -1;
- }
-
- public static bool Contains(this ReadOnlySpan<char> source, char value)
- {
- for (int i = 0; i < source.Length; i++)
- {
- if (source[i] == value)
- {
- return true;
- }
- }
-
- return false;
- }
-
- public static ReadOnlySpan<char> Remove(this ReadOnlySpan<char> source, int startIndex, int count)
- {
- if (startIndex < 0) throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_StartIndex);
- if (count < 0) throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NegativeCount);
- if (count > source.Length - startIndex) throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_IndexCount);
-
- if (count == 0)
- {
- return source;
- }
-
- int newLength = source.Length - count;
- if (newLength == 0)
- {
- return ReadOnlySpan<char>.Empty;
- }
-
- Span<char> result = new char[newLength];
- source.Slice(0, startIndex).CopyTo(result);
- source.Slice(startIndex + count).CopyTo(result.Slice(startIndex));
- return result;
- }
- }
-}
diff --git a/src/Common/src/CoreLib/System/Text/Decoder.cs b/src/Common/src/CoreLib/System/Text/Decoder.cs
index 94d88b126f..5266dc0727 100644
--- a/src/Common/src/CoreLib/System/Text/Decoder.cs
+++ b/src/Common/src/CoreLib/System/Text/Decoder.cs
@@ -135,7 +135,7 @@ namespace System.Text
public virtual unsafe int GetCharCount(ReadOnlySpan<byte> bytes, bool flush)
{
- fixed (byte* bytesPtr = &MemoryMarshal.GetReference(bytes))
+ fixed (byte* bytesPtr = &MemoryMarshal.GetNonNullPinnableReference(bytes))
{
return GetCharCount(bytesPtr, bytes.Length, flush);
}
@@ -228,8 +228,8 @@ namespace System.Text
public virtual unsafe int GetChars(ReadOnlySpan<byte> bytes, Span<char> chars, bool flush)
{
- fixed (byte* bytesPtr = &MemoryMarshal.GetReference(bytes))
- fixed (char* charsPtr = &MemoryMarshal.GetReference(chars))
+ fixed (byte* bytesPtr = &MemoryMarshal.GetNonNullPinnableReference(bytes))
+ fixed (char* charsPtr = &MemoryMarshal.GetNonNullPinnableReference(chars))
{
return GetChars(bytesPtr, bytes.Length, charsPtr, chars.Length, flush);
}
@@ -342,8 +342,8 @@ namespace System.Text
public virtual unsafe void Convert(ReadOnlySpan<byte> bytes, Span<char> chars, bool flush, out int bytesUsed, out int charsUsed, out bool completed)
{
- fixed (byte* bytesPtr = &MemoryMarshal.GetReference(bytes))
- fixed (char* charsPtr = &MemoryMarshal.GetReference(chars))
+ fixed (byte* bytesPtr = &MemoryMarshal.GetNonNullPinnableReference(bytes))
+ fixed (char* charsPtr = &MemoryMarshal.GetNonNullPinnableReference(chars))
{
Convert(bytesPtr, bytes.Length, charsPtr, chars.Length, flush, out bytesUsed, out charsUsed, out completed);
}
diff --git a/src/Common/src/CoreLib/System/Text/Encoder.cs b/src/Common/src/CoreLib/System/Text/Encoder.cs
index d3b96198c4..c31bafcdcb 100644
--- a/src/Common/src/CoreLib/System/Text/Encoder.cs
+++ b/src/Common/src/CoreLib/System/Text/Encoder.cs
@@ -133,7 +133,7 @@ namespace System.Text
public virtual unsafe int GetByteCount(ReadOnlySpan<char> chars, bool flush)
{
- fixed (char* charsPtr = &MemoryMarshal.GetReference(chars))
+ fixed (char* charsPtr = &MemoryMarshal.GetNonNullPinnableReference(chars))
{
return GetByteCount(charsPtr, chars.Length, flush);
}
@@ -222,8 +222,8 @@ namespace System.Text
public virtual unsafe int GetBytes(ReadOnlySpan<char> chars, Span<byte> bytes, bool flush)
{
- fixed (char* charsPtr = &MemoryMarshal.GetReference(chars))
- fixed (byte* bytesPtr = &MemoryMarshal.GetReference(bytes))
+ fixed (char* charsPtr = &MemoryMarshal.GetNonNullPinnableReference(chars))
+ fixed (byte* bytesPtr = &MemoryMarshal.GetNonNullPinnableReference(bytes))
{
return GetBytes(charsPtr, chars.Length, bytesPtr, bytes.Length, flush);
}
@@ -336,8 +336,8 @@ namespace System.Text
public virtual unsafe void Convert(ReadOnlySpan<char> chars, Span<byte> bytes, bool flush, out int charsUsed, out int bytesUsed, out bool completed)
{
- fixed (char* charsPtr = &MemoryMarshal.GetReference(chars))
- fixed (byte* bytesPtr = &MemoryMarshal.GetReference(bytes))
+ fixed (char* charsPtr = &MemoryMarshal.GetNonNullPinnableReference(chars))
+ fixed (byte* bytesPtr = &MemoryMarshal.GetNonNullPinnableReference(bytes))
{
Convert(charsPtr, chars.Length, bytesPtr, bytes.Length, flush, out charsUsed, out bytesUsed, out completed);
}
diff --git a/src/Common/src/CoreLib/System/Text/Encoding.cs b/src/Common/src/CoreLib/System/Text/Encoding.cs
index 8d7e0c7ebb..9056b1511b 100644
--- a/src/Common/src/CoreLib/System/Text/Encoding.cs
+++ b/src/Common/src/CoreLib/System/Text/Encoding.cs
@@ -714,7 +714,7 @@ namespace System.Text
public virtual unsafe int GetByteCount(ReadOnlySpan<char> chars)
{
- fixed (char* charsPtr = &MemoryMarshal.GetReference(chars))
+ fixed (char* charsPtr = &MemoryMarshal.GetNonNullPinnableReference(chars))
{
return GetByteCount(charsPtr, chars.Length);
}
@@ -896,8 +896,8 @@ namespace System.Text
public virtual unsafe int GetBytes(ReadOnlySpan<char> chars, Span<byte> bytes)
{
- fixed (char* charsPtr = &MemoryMarshal.GetReference(chars))
- fixed (byte* bytesPtr = &MemoryMarshal.GetReference(bytes))
+ fixed (char* charsPtr = &MemoryMarshal.GetNonNullPinnableReference(chars))
+ fixed (byte* bytesPtr = &MemoryMarshal.GetNonNullPinnableReference(bytes))
{
return GetBytes(charsPtr, chars.Length, bytesPtr, bytes.Length);
}
@@ -946,7 +946,7 @@ namespace System.Text
public virtual unsafe int GetCharCount(ReadOnlySpan<byte> bytes)
{
- fixed (byte* bytesPtr = &MemoryMarshal.GetReference(bytes))
+ fixed (byte* bytesPtr = &MemoryMarshal.GetNonNullPinnableReference(bytes))
{
return GetCharCount(bytesPtr, bytes.Length);
}
@@ -1058,8 +1058,8 @@ namespace System.Text
public virtual unsafe int GetChars(ReadOnlySpan<byte> bytes, Span<char> chars)
{
- fixed (byte* bytesPtr = &MemoryMarshal.GetReference(bytes))
- fixed (char* charsPtr = &MemoryMarshal.GetReference(chars))
+ fixed (byte* bytesPtr = &MemoryMarshal.GetNonNullPinnableReference(bytes))
+ fixed (char* charsPtr = &MemoryMarshal.GetNonNullPinnableReference(chars))
{
return GetChars(bytesPtr, bytes.Length, charsPtr, chars.Length);
}
@@ -1088,7 +1088,7 @@ namespace System.Text
public unsafe string GetString(ReadOnlySpan<byte> bytes)
{
- fixed (byte* bytesPtr = &MemoryMarshal.GetReference(bytes))
+ fixed (byte* bytesPtr = &MemoryMarshal.GetNonNullPinnableReference(bytes))
{
return GetString(bytesPtr, bytes.Length);
}
diff --git a/src/Common/src/CoreLib/System/Text/StringBuilder.Debug.cs b/src/Common/src/CoreLib/System/Text/StringBuilder.Debug.cs
new file mode 100644
index 0000000000..a62c4777ad
--- /dev/null
+++ b/src/Common/src/CoreLib/System/Text/StringBuilder.Debug.cs
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+
+namespace System.Text
+{
+ public sealed partial class StringBuilder
+ {
+ private void ShowChunks(int maxChunksToShow = 10)
+ {
+ int count = 0;
+ StringBuilder head = this, current = this;
+ while (current != null)
+ {
+ if (count < maxChunksToShow)
+ {
+ count++;
+ }
+ else
+ {
+ head = head.m_ChunkPrevious;
+ }
+ current = current.m_ChunkPrevious;
+ }
+ current = head;
+ string[] chunks = new string[count];
+ for (int i = count; i > 0; i--)
+ {
+ chunks[i - 1] = new string(current.m_ChunkChars).Replace('\0', '.');
+ current = current.m_ChunkPrevious;
+ }
+ Debug.WriteLine('|' + string.Join('|', chunks) + '|');
+ }
+ }
+}
diff --git a/src/Common/src/CoreLib/System/Text/StringBuilder.cs b/src/Common/src/CoreLib/System/Text/StringBuilder.cs
index c4b99e9a00..087bedb668 100644
--- a/src/Common/src/CoreLib/System/Text/StringBuilder.cs
+++ b/src/Common/src/CoreLib/System/Text/StringBuilder.cs
@@ -19,10 +19,10 @@ using System.Collections.Generic;
namespace System.Text
{
// This class represents a mutable string. It is convenient for situations in
- // which it is desirable to modify a string, perhaps by removing, replacing, or
+ // which it is desirable to modify a string, perhaps by removing, replacing, or
// inserting characters, without creating a new String subsequent to
- // each modification.
- //
+ // each modification.
+ //
// The methods contained within this class do not return a new StringBuilder
// object unless specified otherwise. This class may be used in conjunction with the String
// class to carry out modifications upon strings.
@@ -31,8 +31,8 @@ namespace System.Text
public sealed partial class StringBuilder : ISerializable
{
// A StringBuilder is internally represented as a linked list of blocks each of which holds
- // a chunk of the string. It turns out string as a whole can also be represented as just a chunk,
- // so that is what we do.
+ // a chunk of the string. It turns out string as a whole can also be represented as just a chunk,
+ // so that is what we do.
/// <summary>
/// The character buffer for this chunk.
@@ -74,7 +74,7 @@ namespace System.Text
// We want to keep chunk arrays out of large object heap (< 85K bytes ~ 40K chars) to be sure.
// Making the maximum chunk size big means less allocation code called, but also more waste
// in unused characters and slower inserts / replaces (since you do need to slide characters over
- // within a buffer).
+ // within a buffer).
internal const int MaxChunkSize = 8000;
/// <summary>
@@ -378,7 +378,7 @@ namespace System.Text
int chunkOffset = chunk.m_ChunkOffset;
int chunkLength = chunk.m_ChunkLength;
- // Check that we will not overrun our boundaries.
+ // Check that we will not overrun our boundaries.
if ((uint)(chunkLength + chunkOffset) <= (uint)result.Length && (uint)chunkLength <= (uint)sourceArray.Length)
{
fixed (char* sourcePtr = &sourceArray[0])
@@ -463,13 +463,10 @@ namespace System.Text
throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_SmallCapacity);
}
- int originalCapacity = Capacity;
-
if (value == 0 && m_ChunkPrevious == null)
{
m_ChunkLength = 0;
m_ChunkOffset = 0;
- Debug.Assert(Capacity >= originalCapacity);
return;
}
@@ -484,22 +481,32 @@ namespace System.Text
StringBuilder chunk = FindChunkForIndex(value);
if (chunk != this)
{
- // We crossed a chunk boundary when reducing the Length. We must replace this middle-chunk with a new larger chunk,
- // to ensure the original capacity is preserved.
- int newLen = originalCapacity - chunk.m_ChunkOffset;
- char[] newArray = new char[newLen];
-
- Debug.Assert(newLen > chunk.m_ChunkChars.Length, "The new chunk should be larger than the one it is replacing.");
- Array.Copy(chunk.m_ChunkChars, 0, newArray, 0, chunk.m_ChunkLength);
+ // Avoid possible infinite capacity growth. See https://github.com/dotnet/coreclr/pull/16926
+ int capacityToPreserve = Math.Min(Capacity, Math.Max(Length * 6 / 5, m_ChunkChars.Length));
+ int newLen = capacityToPreserve - chunk.m_ChunkOffset;
+ if (newLen > chunk.m_ChunkChars.Length)
+ {
+ // We crossed a chunk boundary when reducing the Length. We must replace this middle-chunk with a new larger chunk,
+ // to ensure the capacity we want is preserved.
+ char[] newArray = new char[newLen];
+ Array.Copy(chunk.m_ChunkChars, 0, newArray, 0, chunk.m_ChunkLength);
+ m_ChunkChars = newArray;
+ }
+ else
+ {
+ // Special case where the capacity we want to keep corresponds exactly to the size of the content.
+ // Just take ownership of the array.
+ Debug.Assert(newLen == chunk.m_ChunkChars.Length, "The new chunk should be larger or equal to the one it is replacing.");
+ m_ChunkChars = chunk.m_ChunkChars;
+ }
- m_ChunkChars = newArray;
m_ChunkPrevious = chunk.m_ChunkPrevious;
m_ChunkOffset = chunk.m_ChunkOffset;
}
m_ChunkLength = value - chunk.m_ChunkOffset;
AssertInvariants();
}
- Debug.Assert(Capacity >= originalCapacity);
+ Debug.Assert(Length == value, "Something went wrong setting Length.");
}
}
@@ -692,7 +699,7 @@ namespace System.Text
}
// We put this fixed in its own helper to avoid the cost of zero-initing `valueChars` in the
- // case we don't actually use it.
+ // case we don't actually use it.
private void AppendHelper(string value)
{
unsafe
@@ -922,7 +929,7 @@ namespace System.Text
return this;
}
- // Ensure we don't insert more chars than we can hold, and we don't
+ // Ensure we don't insert more chars than we can hold, and we don't
// have any integer overflow in our new length.
long insertingChars = (long)value.Length * count;
if (insertingChars > MaxCapacity - this.Length)
@@ -1123,7 +1130,7 @@ namespace System.Text
{
return AppendJoinCore(&separator, 1, values);
}
-
+
private unsafe StringBuilder AppendJoinCore<T>(char* separator, int separatorLength, IEnumerable<T> values)
{
Debug.Assert(separator != null);
@@ -1560,7 +1567,7 @@ namespace System.Text
if (startPos != pos)
{
// There was no brace escaping, extract the item format as a single string
- itemFormatSpan = format.AsReadOnlySpan().Slice(startPos, pos - startPos);
+ itemFormatSpan = format.AsSpan(startPos, pos - startPos);
}
}
else
@@ -1688,10 +1695,10 @@ namespace System.Text
/// <summary>
/// Determines if the contents of this builder are equal to the contents of ReadOnlySpan<char>.
/// </summary>
- /// <param name="value">The ReadOnlySpan{char}.</param>
- public bool Equals(ReadOnlySpan<char> value)
+ /// <param name="span">The ReadOnlySpan{char}.</param>
+ public bool Equals(ReadOnlySpan<char> span)
{
- if (value.Length != Length)
+ if (span.Length != Length)
return false;
StringBuilder sbChunk = this;
@@ -1704,7 +1711,7 @@ namespace System.Text
ReadOnlySpan<char> chunk = new ReadOnlySpan<char>(sbChunk.m_ChunkChars, 0, chunk_length);
- if (!chunk.Equals(value.Slice(value.Length - offset, chunk_length)))
+ if (!chunk.EqualsOrdinal(span.Slice(span.Length - offset, chunk_length)))
return false;
sbChunk = sbChunk.m_ChunkPrevious;
@@ -1757,7 +1764,7 @@ namespace System.Text
int indexInChunk = startIndex - chunk.m_ChunkOffset;
while (count > 0)
{
- // Look for a match in the chunk,indexInChunk pointer
+ // Look for a match in the chunk,indexInChunk pointer
if (StartsWith(chunk, indexInChunk, count, oldValue))
{
// Push it on the replacements array (with growth), we will do all replacements in a
@@ -1783,13 +1790,13 @@ namespace System.Text
if (indexInChunk >= chunk.m_ChunkLength || count == 0) // Have we moved out of the current chunk?
{
- // Replacing mutates the blocks, so we need to convert to a logical index and back afterwards.
+ // Replacing mutates the blocks, so we need to convert to a logical index and back afterwards.
int index = indexInChunk + chunk.m_ChunkOffset;
int indexBeforeAdjustment = index;
// See if we accumulated any replacements, if so apply them.
ReplaceAllInChunk(replacements, replacementsCount, chunk, oldValue.Length, newValue);
- // The replacement has affected the logical index. Adjust it.
+ // The replacement has affected the logical index. Adjust it.
index += ((newValue.Length - oldValue.Length) * replacementsCount);
replacementsCount = 0;
@@ -1882,7 +1889,7 @@ namespace System.Text
throw new ArgumentOutOfRangeException(nameof(valueCount), SR.ArgumentOutOfRange_LengthGreaterThanCapacity);
}
- // This case is so common we want to optimize for it heavily.
+ // This case is so common we want to optimize for it heavily.
int newIndex = valueCount + m_ChunkLength;
if (newIndex <= m_ChunkChars.Length)
{
@@ -1899,7 +1906,7 @@ namespace System.Text
m_ChunkLength = m_ChunkChars.Length;
}
- // Expand the builder to add another chunk.
+ // Expand the builder to add another chunk.
int restLength = valueCount - firstLength;
ExpandByABlock(restLength);
Debug.Assert(m_ChunkLength == 0, "A new block was not created.");
@@ -1956,16 +1963,16 @@ namespace System.Text
{
fixed (char* valuePtr = value)
{
- // calculate the total amount of extra space or space needed for all the replacements.
+ // calculate the total amount of extra space or space needed for all the replacements.
int delta = (value.Length - removeCount) * replacementsCount;
StringBuilder targetChunk = sourceChunk; // the target as we copy chars down
int targetIndexInChunk = replacements[0];
- // Make the room needed for all the new characters if needed.
+ // Make the room needed for all the new characters if needed.
if (delta > 0)
MakeRoom(targetChunk.m_ChunkOffset + targetIndexInChunk, delta, out targetChunk, out targetIndexInChunk, true);
- // We made certain that characters after the insertion point are not moved,
+ // We made certain that characters after the insertion point are not moved,
int i = 0;
for (;;)
{
@@ -1982,7 +1989,7 @@ namespace System.Text
Debug.Assert(gapStart < sourceChunk.m_ChunkChars.Length, "gap starts at end of buffer. Should not happen");
Debug.Assert(gapStart <= gapEnd, "negative gap size");
Debug.Assert(gapEnd <= sourceChunk.m_ChunkLength, "gap too big");
- if (delta != 0) // can skip the sliding of gaps if source an target string are the same size.
+ if (delta != 0) // can skip the sliding of gaps if source an target string are the same size.
{
// Copy the gap data between the current replacement and the next replacement
fixed (char* sourcePtr = &sourceChunk.m_ChunkChars[gapStart])
@@ -1995,7 +2002,7 @@ namespace System.Text
}
}
- // Remove extra space if necessary.
+ // Remove extra space if necessary.
if (delta < 0)
Remove(targetChunk.m_ChunkOffset + targetIndexInChunk, -delta, out targetChunk, out targetIndexInChunk);
}
@@ -2052,7 +2059,7 @@ namespace System.Text
/// </param>
/// <param name="value">The pointer to the start of the character buffer.</param>
/// <param name="count">The number of characters in the buffer.</param>
- unsafe private void ReplaceInPlaceAtChunk(ref StringBuilder chunk, ref int indexInChunk, char* value, int count)
+ private unsafe void ReplaceInPlaceAtChunk(ref StringBuilder chunk, ref int indexInChunk, char* value, int count)
{
if (count != 0)
{
@@ -2064,7 +2071,7 @@ namespace System.Text
int lengthToCopy = Math.Min(lengthInChunk, count);
ThreadSafeCopy(value, chunk.m_ChunkChars, indexInChunk, lengthToCopy);
- // Advance the index.
+ // Advance the index.
indexInChunk += lengthToCopy;
if (indexInChunk >= chunk.m_ChunkLength)
{
@@ -2382,7 +2389,7 @@ namespace System.Text
int endIndex = startIndex + count;
- // Find the chunks for the start and end of the block to delete.
+ // Find the chunks for the start and end of the block to delete.
chunk = this;
StringBuilder endChunk = null;
int endIndexInChunk = 0;
@@ -2433,7 +2440,7 @@ namespace System.Text
// SafeCritical: We ensure that `endIndexInChunk + copyCount` is within range of `m_ChunkChars`, and
// also ensure that `copyTargetIndexInChunk + copyCount` is within the chunk.
- // Remove any characters in the end chunk, by sliding the characters down.
+ // Remove any characters in the end chunk, by sliding the characters down.
if (copyTargetIndexInChunk != endIndexInChunk) // Sometimes no move is necessary
{
ThreadSafeCopy(endChunk.m_ChunkChars, endIndexInChunk, endChunk.m_ChunkChars, copyTargetIndexInChunk, copyCount);
diff --git a/src/Common/src/CoreLib/System/Text/UTF8Encoding.cs b/src/Common/src/CoreLib/System/Text/UTF8Encoding.cs
index 914651fdd0..987e2b46e2 100644
--- a/src/Common/src/CoreLib/System/Text/UTF8Encoding.cs
+++ b/src/Common/src/CoreLib/System/Text/UTF8Encoding.cs
@@ -784,13 +784,13 @@ namespace System.Text
// diffs two char pointers using unsigned arithmetic. The unsigned arithmetic
// is good enough for us, and it tends to generate better code than the signed
// arithmetic generated by default
- unsafe private static int PtrDiff(char* a, char* b)
+ private static unsafe int PtrDiff(char* a, char* b)
{
return (int)(((uint)((byte*)a - (byte*)b)) >> 1);
}
// byte* flavor just for parity
- unsafe private static int PtrDiff(byte* a, byte* b)
+ private static unsafe int PtrDiff(byte* a, byte* b)
{
return (int)(a - b);
}
@@ -853,7 +853,7 @@ namespace System.Text
{
if (ch == 0)
{
- // Check if there's anthing left to get out of the fallback buffer
+ // Check if there's anything left to get out of the fallback buffer
ch = fallbackBuffer != null ? fallbackBuffer.InternalGetNextChar() : 0;
if (ch > 0)
{
diff --git a/src/Common/src/CoreLib/System/Text/ValueStringBuilder.cs b/src/Common/src/CoreLib/System/Text/ValueStringBuilder.cs
index f391346cbf..65b7432d09 100644
--- a/src/Common/src/CoreLib/System/Text/ValueStringBuilder.cs
+++ b/src/Common/src/CoreLib/System/Text/ValueStringBuilder.cs
@@ -6,6 +6,7 @@ using System.Buffers;
using System.Diagnostics;
using System.Diagnostics.Private;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
namespace System.Text
{
@@ -22,27 +23,88 @@ namespace System.Text
_pos = 0;
}
- public int Length => _pos;
+ public int Length
+ {
+ get => _pos;
+ set
+ {
+ Debug.Assert(value >= 0);
+ Debug.Assert(value <= _chars.Length);
+ _pos = value;
+ }
+ }
+
+ public int Capacity => _chars.Length;
+
+ public void EnsureCapacity(int capacity)
+ {
+ if (capacity > _chars.Length)
+ Grow(capacity - _chars.Length);
+ }
+
+ /// <summary>
+ /// Get a pinnable reference to the builder.
+ /// </summary>
+ /// <param name="terminate">Ensures that the builder has a null char after <see cref="Length"/></param>
+ public ref char GetPinnableReference(bool terminate = false)
+ {
+ if (terminate)
+ {
+ EnsureCapacity(Length + 1);
+ _chars[Length] = '\0';
+ }
+ return ref MemoryMarshal.GetReference(_chars);
+ }
+
+ public ref char this[int index]
+ {
+ get
+ {
+ Debug.Assert(index < _pos);
+ return ref _chars[index];
+ }
+ }
public override string ToString()
{
var s = new string(_chars.Slice(0, _pos));
- Clear();
+ Dispose();
return s;
}
+ /// <summary>Returns the underlying storage of the builder.</summary>
+ public Span<char> RawChars => _chars;
+
+ /// <summary>
+ /// Returns a span around the contents of the builder.
+ /// </summary>
+ /// <param name="terminate">Ensures that the builder has a null char after <see cref="Length"/></param>
+ public ReadOnlySpan<char> AsSpan(bool terminate)
+ {
+ if (terminate)
+ {
+ EnsureCapacity(Length + 1);
+ _chars[Length] = '\0';
+ }
+ return _chars.Slice(0, _pos);
+ }
+
+ public ReadOnlySpan<char> AsSpan() => _chars.Slice(0, _pos);
+ public ReadOnlySpan<char> AsSpan(int start) => _chars.Slice(start, _pos - start);
+ public ReadOnlySpan<char> AsSpan(int start, int length) => _chars.Slice(start, length);
+
public bool TryCopyTo(Span<char> destination, out int charsWritten)
{
if (_chars.Slice(0, _pos).TryCopyTo(destination))
{
charsWritten = _pos;
- Clear();
+ Dispose();
return true;
}
else
{
charsWritten = 0;
- Clear();
+ Dispose();
return false;
}
}
@@ -98,8 +160,7 @@ namespace System.Text
Grow(s.Length);
}
- bool copied = s.AsReadOnlySpan().TryCopyTo(_chars.Slice(pos));
- Debug.Assert(copied, "Grow should have made enough room to successfully copy");
+ s.AsSpan().CopyTo(_chars.Slice(pos));
_pos += s.Length;
}
@@ -134,6 +195,18 @@ namespace System.Text
_pos += length;
}
+ public unsafe void Append(ReadOnlySpan<char> value)
+ {
+ int pos = _pos;
+ if (pos > _chars.Length - value.Length)
+ {
+ Grow(value.Length);
+ }
+
+ value.CopyTo(_chars.Slice(_pos));
+ _pos += value.Length;
+ }
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<char> AppendSpan(int length)
{
@@ -157,12 +230,11 @@ namespace System.Text
[MethodImpl(MethodImplOptions.NoInlining)]
private void Grow(int requiredAdditionalCapacity)
{
- Debug.Assert(requiredAdditionalCapacity > _chars.Length - _pos);
+ Debug.Assert(requiredAdditionalCapacity > 0);
char[] poolArray = ArrayPool<char>.Shared.Rent(Math.Max(_pos + requiredAdditionalCapacity, _chars.Length * 2));
- bool success = _chars.TryCopyTo(poolArray);
- Debug.Assert(success);
+ _chars.CopyTo(poolArray);
char[] toReturn = _arrayToReturnToPool;
_chars = _arrayToReturnToPool = poolArray;
@@ -173,7 +245,7 @@ namespace System.Text
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void Clear()
+ public void Dispose()
{
char[] toReturn = _arrayToReturnToPool;
this = default; // for safety, to avoid using pooled array if this instance is erroneously appended to again
diff --git a/src/Common/src/CoreLib/System/Threading/AsyncLocal.cs b/src/Common/src/CoreLib/System/Threading/AsyncLocal.cs
index 59c8fb3c88..3531265bec 100644
--- a/src/Common/src/CoreLib/System/Threading/AsyncLocal.cs
+++ b/src/Common/src/CoreLib/System/Threading/AsyncLocal.cs
@@ -125,7 +125,7 @@ namespace System.Threading
public static IAsyncLocalValueMap Empty { get; } = new EmptyAsyncLocalValueMap();
// Instance without any key/value pairs. Used as a singleton/
- private sealed class EmptyAsyncLocalValueMap : IAsyncLocalValueMap
+ internal sealed class EmptyAsyncLocalValueMap : IAsyncLocalValueMap
{
public IAsyncLocalValueMap Set(IAsyncLocal key, object value)
{
@@ -144,7 +144,7 @@ namespace System.Threading
}
// Instance with one key/value pair.
- private sealed class OneElementAsyncLocalValueMap : IAsyncLocalValueMap
+ internal sealed class OneElementAsyncLocalValueMap : IAsyncLocalValueMap
{
private readonly IAsyncLocal _key1;
private readonly object _value1;
diff --git a/src/Common/src/CoreLib/System/Threading/ExecutionContext.cs b/src/Common/src/CoreLib/System/Threading/ExecutionContext.cs
index 2d5f5be190..a840aa71fd 100644
--- a/src/Common/src/CoreLib/System/Threading/ExecutionContext.cs
+++ b/src/Common/src/CoreLib/System/Threading/ExecutionContext.cs
@@ -21,40 +21,19 @@ namespace System.Threading
{
public delegate void ContextCallback(Object state);
- internal struct ExecutionContextSwitcher
- {
- internal ExecutionContext m_ec;
- internal SynchronizationContext m_sc;
-
- internal void Undo(Thread currentThread)
- {
- Debug.Assert(currentThread == Thread.CurrentThread);
-
- // The common case is that these have not changed, so avoid the cost of a write if not needed.
- if (currentThread.SynchronizationContext != m_sc)
- {
- currentThread.SynchronizationContext = m_sc;
- }
-
- if (currentThread.ExecutionContext != m_ec)
- {
- ExecutionContext.Restore(currentThread, m_ec);
- }
- }
- }
-
public sealed class ExecutionContext : IDisposable, ISerializable
{
- internal static readonly ExecutionContext Default = new ExecutionContext();
+ internal static readonly ExecutionContext Default = new ExecutionContext(isDefault: true);
+ internal static readonly ExecutionContext DefaultFlowSuppressed = new ExecutionContext(AsyncLocalValueMap.Empty, Array.Empty<IAsyncLocal>(), isFlowSuppressed: true);
private readonly IAsyncLocalValueMap m_localValues;
private readonly IAsyncLocal[] m_localChangeNotifications;
private readonly bool m_isFlowSuppressed;
+ private readonly bool m_isDefault;
- private ExecutionContext()
+ private ExecutionContext(bool isDefault)
{
- m_localValues = AsyncLocalValueMap.Empty;
- m_localChangeNotifications = Array.Empty<IAsyncLocal>();
+ m_isDefault = isDefault;
}
private ExecutionContext(
@@ -85,12 +64,14 @@ namespace System.Threading
{
Debug.Assert(isFlowSuppressed != m_isFlowSuppressed);
- if (!isFlowSuppressed &&
- m_localValues == Default.m_localValues &&
- m_localChangeNotifications == Default.m_localChangeNotifications)
+ if (m_localValues == null ||
+ m_localValues.GetType() == typeof(AsyncLocalValueMap.EmptyAsyncLocalValueMap))
{
- return null; // implies the default context
+ return isFlowSuppressed ?
+ DefaultFlowSuppressed :
+ null; // implies the default context
}
+
return new ExecutionContext(m_localValues, m_localChangeNotifications, isFlowSuppressed);
}
@@ -128,134 +109,248 @@ namespace System.Threading
return executionContext != null && executionContext.m_isFlowSuppressed;
}
+ internal bool HasChangeNotifications => m_localChangeNotifications != null;
+
+ internal bool IsDefault => m_isDefault;
+
public static void Run(ExecutionContext executionContext, ContextCallback callback, Object state)
{
+ // Note: ExecutionContext.Run is an extremely hot function and used by every await, ThreadPool execution, etc.
if (executionContext == null)
- throw new InvalidOperationException(SR.InvalidOperation_NullContext);
+ {
+ ThrowNullContext();
+ }
- Thread currentThread = Thread.CurrentThread;
- ExecutionContextSwitcher ecsw = default(ExecutionContextSwitcher);
+ RunInternal(executionContext, callback, state);
+ }
+
+ internal static void RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
+ {
+ // Note: ExecutionContext.RunInternal is an extremely hot function and used by every await, ThreadPool execution, etc.
+ // Note: Manual enregistering may be addressed by "Exception Handling Write Through Optimization"
+ // https://github.com/dotnet/coreclr/blob/master/Documentation/design-docs/eh-writethru.md
+
+ // Enregister variables with 0 post-fix so they can be used in registers without EH forcing them to stack
+ // Capture references to Thread Contexts
+ Thread currentThread0 = Thread.CurrentThread;
+ Thread currentThread = currentThread0;
+ ExecutionContext previousExecutionCtx0 = currentThread0.ExecutionContext;
+
+ // Store current ExecutionContext and SynchronizationContext as "previousXxx".
+ // This allows us to restore them and undo any Context changes made in callback.Invoke
+ // so that they won't "leak" back into caller.
+ // These variables will cross EH so be forced to stack
+ ExecutionContext previousExecutionCtx = previousExecutionCtx0;
+ SynchronizationContext previousSyncCtx = currentThread0.SynchronizationContext;
+
+ if (executionContext != null && executionContext.m_isDefault)
+ {
+ // Default is a null ExecutionContext internally
+ executionContext = null;
+ }
+
+ if (previousExecutionCtx0 != executionContext)
+ {
+ // Restore changed ExecutionContext
+ currentThread0.ExecutionContext = executionContext;
+ if ((executionContext != null && executionContext.HasChangeNotifications) ||
+ (previousExecutionCtx0 != null && previousExecutionCtx0.HasChangeNotifications))
+ {
+ // There are change notifications; trigger any affected
+ OnValuesChanged(previousExecutionCtx0, executionContext);
+ }
+ }
+
+ ExceptionDispatchInfo edi = null;
try
{
- EstablishCopyOnWriteScope(currentThread, ref ecsw);
- ExecutionContext.Restore(currentThread, executionContext);
- callback(state);
+ callback.Invoke(state);
}
- catch
+ catch (Exception ex)
{
// Note: we have a "catch" rather than a "finally" because we want
// to stop the first pass of EH here. That way we can restore the previous
- // context before any of our callers' EH filters run. That means we need to
- // end the scope separately in the non-exceptional case below.
- ecsw.Undo(currentThread);
- throw;
+ // context before any of our callers' EH filters run.
+ edi = ExceptionDispatchInfo.Capture(ex);
}
- ecsw.Undo(currentThread);
- }
-
- internal static void Restore(Thread currentThread, ExecutionContext executionContext)
- {
- Debug.Assert(currentThread == Thread.CurrentThread);
-
- ExecutionContext previous = currentThread.ExecutionContext ?? Default;
- currentThread.ExecutionContext = executionContext;
-
- // New EC could be null if that's what ECS.Undo saved off.
- // For the purposes of dealing with context change, treat this as the default EC
- executionContext = executionContext ?? Default;
- if (previous != executionContext)
+ // Re-enregistrer variables post EH with 1 post-fix so they can be used in registers rather than from stack
+ SynchronizationContext previousSyncCtx1 = previousSyncCtx;
+ Thread currentThread1 = currentThread;
+ // The common case is that these have not changed, so avoid the cost of a write barrier if not needed.
+ if (currentThread1.SynchronizationContext != previousSyncCtx1)
{
- OnContextChanged(previous, executionContext);
+ // Restore changed SynchronizationContext back to previous
+ currentThread1.SynchronizationContext = previousSyncCtx1;
}
- }
- internal static void EstablishCopyOnWriteScope(Thread currentThread, ref ExecutionContextSwitcher ecsw)
- {
- Debug.Assert(currentThread == Thread.CurrentThread);
+ ExecutionContext previousExecutionCtx1 = previousExecutionCtx;
+ ExecutionContext currentExecutionCtx1 = currentThread1.ExecutionContext;
+ if (currentExecutionCtx1 != previousExecutionCtx1)
+ {
+ // Restore changed ExecutionContext back to previous
+ currentThread1.ExecutionContext = previousExecutionCtx1;
+ if ((currentExecutionCtx1 != null && currentExecutionCtx1.HasChangeNotifications) ||
+ (previousExecutionCtx1 != null && previousExecutionCtx1.HasChangeNotifications))
+ {
+ // There are change notifications; trigger any affected
+ OnValuesChanged(currentExecutionCtx1, previousExecutionCtx1);
+ }
+ }
- ecsw.m_ec = currentThread.ExecutionContext;
- ecsw.m_sc = currentThread.SynchronizationContext;
+ // If exception was thrown by callback, rethrow it now original contexts are restored
+ edi?.Throw();
}
- private static void OnContextChanged(ExecutionContext previous, ExecutionContext current)
+ internal static void OnValuesChanged(ExecutionContext previousExecutionCtx, ExecutionContext nextExecutionCtx)
{
- Debug.Assert(previous != null);
- Debug.Assert(current != null);
- Debug.Assert(previous != current);
+ Debug.Assert(previousExecutionCtx != nextExecutionCtx);
- foreach (IAsyncLocal local in previous.m_localChangeNotifications)
- {
- object previousValue;
- object currentValue;
- previous.m_localValues.TryGetValue(local, out previousValue);
- current.m_localValues.TryGetValue(local, out currentValue);
+ // Collect Change Notifications
+ IAsyncLocal[] previousChangeNotifications = previousExecutionCtx?.m_localChangeNotifications;
+ IAsyncLocal[] nextChangeNotifications = nextExecutionCtx?.m_localChangeNotifications;
- if (previousValue != currentValue)
- local.OnValueChanged(previousValue, currentValue, true);
- }
+ // At least one side must have notifications
+ Debug.Assert(previousChangeNotifications != null || nextChangeNotifications != null);
- if (current.m_localChangeNotifications != previous.m_localChangeNotifications)
+ // Fire Change Notifications
+ try
{
- try
+ if (previousChangeNotifications != null && nextChangeNotifications != null)
{
- foreach (IAsyncLocal local in current.m_localChangeNotifications)
+ // Notifications can't exist without values
+ Debug.Assert(previousExecutionCtx.m_localValues != null);
+ Debug.Assert(nextExecutionCtx.m_localValues != null);
+ // Both contexts have change notifications, check previousExecutionCtx first
+ foreach (IAsyncLocal local in previousChangeNotifications)
{
- // If the local has a value in the previous context, we already fired the event for that local
- // in the code above.
- object previousValue;
- if (!previous.m_localValues.TryGetValue(local, out previousValue))
+ previousExecutionCtx.m_localValues.TryGetValue(local, out object previousValue);
+ nextExecutionCtx.m_localValues.TryGetValue(local, out object currentValue);
+
+ if (previousValue != currentValue)
{
- object currentValue;
- current.m_localValues.TryGetValue(local, out currentValue);
+ local.OnValueChanged(previousValue, currentValue, contextChanged: true);
+ }
+ }
- if (previousValue != currentValue)
- local.OnValueChanged(previousValue, currentValue, true);
+ if (nextChangeNotifications != previousChangeNotifications)
+ {
+ // Check for additional notifications in nextExecutionCtx
+ foreach (IAsyncLocal local in nextChangeNotifications)
+ {
+ // If the local has a value in the previous context, we already fired the event
+ // for that local in the code above.
+ if (!previousExecutionCtx.m_localValues.TryGetValue(local, out object previousValue))
+ {
+ nextExecutionCtx.m_localValues.TryGetValue(local, out object currentValue);
+ if (previousValue != currentValue)
+ {
+ local.OnValueChanged(previousValue, currentValue, contextChanged: true);
+ }
+ }
+ }
+ }
+ }
+ else if (previousChangeNotifications != null)
+ {
+ // Notifications can't exist without values
+ Debug.Assert(previousExecutionCtx.m_localValues != null);
+ // No current values, so just check previous against null
+ foreach (IAsyncLocal local in previousChangeNotifications)
+ {
+ previousExecutionCtx.m_localValues.TryGetValue(local, out object previousValue);
+ if (previousValue != null)
+ {
+ local.OnValueChanged(previousValue, null, contextChanged: true);
}
}
}
- catch (Exception ex)
+ else // Implied: nextChangeNotifications != null
{
- Environment.FailFast(
- SR.ExecutionContext_ExceptionInAsyncLocalNotification,
- ex);
+ // Notifications can't exist without values
+ Debug.Assert(nextExecutionCtx.m_localValues != null);
+ // No previous values, so just check current against null
+ foreach (IAsyncLocal local in nextChangeNotifications)
+ {
+ nextExecutionCtx.m_localValues.TryGetValue(local, out object currentValue);
+ if (currentValue != null)
+ {
+ local.OnValueChanged(null, currentValue, contextChanged: true);
+ }
+ }
}
}
+ catch (Exception ex)
+ {
+ Environment.FailFast(
+ SR.ExecutionContext_ExceptionInAsyncLocalNotification,
+ ex);
+ }
+ }
+
+ [StackTraceHidden]
+ private static void ThrowNullContext()
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_NullContext);
}
internal static object GetLocalValue(IAsyncLocal local)
{
ExecutionContext current = Thread.CurrentThread.ExecutionContext;
if (current == null)
+ {
return null;
+ }
- object value;
- current.m_localValues.TryGetValue(local, out value);
+ current.m_localValues.TryGetValue(local, out object value);
return value;
}
internal static void SetLocalValue(IAsyncLocal local, object newValue, bool needChangeNotifications)
{
- ExecutionContext current = Thread.CurrentThread.ExecutionContext ?? ExecutionContext.Default;
+ ExecutionContext current = Thread.CurrentThread.ExecutionContext;
- object previousValue;
- bool hadPreviousValue = current.m_localValues.TryGetValue(local, out previousValue);
+ object previousValue = null;
+ bool hadPreviousValue = false;
+ if (current != null)
+ {
+ hadPreviousValue = current.m_localValues.TryGetValue(local, out previousValue);
+ }
if (previousValue == newValue)
+ {
return;
+ }
- IAsyncLocalValueMap newValues = current.m_localValues.Set(local, newValue);
+ IAsyncLocal[] newChangeNotifications = null;
+ IAsyncLocalValueMap newValues;
+ bool isFlowSuppressed = false;
+ if (current != null)
+ {
+ isFlowSuppressed = current.m_isFlowSuppressed;
+ newValues = current.m_localValues.Set(local, newValue);
+ newChangeNotifications = current.m_localChangeNotifications;
+ }
+ else
+ {
+ // First AsyncLocal
+ newValues = new AsyncLocalValueMap.OneElementAsyncLocalValueMap(local, newValue);
+ }
//
// Either copy the change notification array, or create a new one, depending on whether we need to add a new item.
//
- IAsyncLocal[] newChangeNotifications = current.m_localChangeNotifications;
if (needChangeNotifications)
{
if (hadPreviousValue)
{
+ Debug.Assert(newChangeNotifications != null);
Debug.Assert(Array.IndexOf(newChangeNotifications, local) >= 0);
}
+ else if (newChangeNotifications == null)
+ {
+ newChangeNotifications = new IAsyncLocal[1] { local };
+ }
else
{
int newNotificationIndex = newChangeNotifications.Length;
@@ -264,12 +359,14 @@ namespace System.Threading
}
}
- Thread.CurrentThread.ExecutionContext =
- new ExecutionContext(newValues, newChangeNotifications, current.m_isFlowSuppressed);
+ Thread.CurrentThread.ExecutionContext =
+ (!isFlowSuppressed && newValues.GetType() == typeof(AsyncLocalValueMap.EmptyAsyncLocalValueMap)) ?
+ null : // No values, return to Default context
+ new ExecutionContext(newValues, newChangeNotifications, isFlowSuppressed);
if (needChangeNotifications)
{
- local.OnValueChanged(previousValue, newValue, false);
+ local.OnValueChanged(previousValue, newValue, contextChanged: false);
}
}
diff --git a/src/Common/src/CoreLib/System/Threading/ReaderWriterLockSlim.cs b/src/Common/src/CoreLib/System/Threading/ReaderWriterLockSlim.cs
index 3c4aad603a..45175488e7 100644
--- a/src/Common/src/CoreLib/System/Threading/ReaderWriterLockSlim.cs
+++ b/src/Common/src/CoreLib/System/Threading/ReaderWriterLockSlim.cs
@@ -1249,7 +1249,7 @@ namespace System.Threading
}
// Don't want to Sleep(1) in this spin wait:
- // - Don't want to spin for that long, since a proper wait will follow when the spin wait fails. The artifical
+ // - Don't want to spin for that long, since a proper wait will follow when the spin wait fails. The artificial
// delay introduced by Sleep(1) will in some cases be much longer than desired.
// - Sleep(1) would put the thread into a wait state, and a proper wait will follow when the spin wait fails
// anyway, so it's preferable to put the thread into the proper wait state
diff --git a/src/Common/src/CoreLib/System/Threading/Tasks/Sources/IValueTaskSource.cs b/src/Common/src/CoreLib/System/Threading/Tasks/Sources/IValueTaskSource.cs
new file mode 100644
index 0000000000..e411146a1d
--- /dev/null
+++ b/src/Common/src/CoreLib/System/Threading/Tasks/Sources/IValueTaskSource.cs
@@ -0,0 +1,82 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Threading.Tasks.Sources
+{
+ /// <summary>
+ /// Flags passed from <see cref="ValueTask"/> and <see cref="ValueTask{TResult}"/> to
+ /// <see cref="IValueTaskSource.OnCompleted"/> and <see cref="IValueTaskSource{TResult}.OnCompleted"/>
+ /// to control behavior.
+ /// </summary>
+ [Flags]
+ public enum ValueTaskSourceOnCompletedFlags
+ {
+ /// <summary>
+ /// No requirements are placed on how the continuation is invoked.
+ /// </summary>
+ None,
+ /// <summary>
+ /// Set if OnCompleted should capture the current scheduling context (e.g. SynchronizationContext)
+ /// and use it when queueing the continuation for execution. If this is not set, the implementation
+ /// may choose to execute the continuation in an arbitrary location.
+ /// </summary>
+ UseSchedulingContext = 0x1,
+ /// <summary>
+ /// Set if OnCompleted should capture the current ExecutionContext and use it to run the continuation.
+ /// </summary>
+ FlowExecutionContext = 0x2,
+ }
+
+ /// <summary>Indicates the status of an <see cref="IValueTaskSource"/> or <see cref="IValueTaskSource{TResult}"/>.</summary>
+ public enum ValueTaskSourceStatus
+ {
+ /// <summary>The operation has not yet completed.</summary>
+ Pending = 0,
+ /// <summary>The operation completed successfully.</summary>
+ Succeeded = 1,
+ /// <summary>The operation completed with an error.</summary>
+ Faulted = 2,
+ /// <summary>The operation completed due to cancellation.</summary>
+ Canceled = 3
+ }
+
+ /// <summary>Represents an object that can be wrapped by a <see cref="ValueTask"/>.</summary>
+ public interface IValueTaskSource
+ {
+ /// <summary>Gets the status of the current operation.</summary>
+ /// <param name="token">Opaque value that was provided to the <see cref="ValueTask"/>'s constructor.</param>
+ ValueTaskSourceStatus GetStatus(short token);
+
+ /// <summary>Schedules the continuation action for this <see cref="IValueTaskSource"/>.</summary>
+ /// <param name="continuation">The continuation to invoke when the operation has completed.</param>
+ /// <param name="state">The state object to pass to <paramref name="continuation"/> when it's invoked.</param>
+ /// <param name="token">Opaque value that was provided to the <see cref="ValueTask"/>'s constructor.</param>
+ /// <param name="flags">The flags describing the behavior of the continuation.</param>
+ void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags);
+
+ /// <summary>Gets the result of the <see cref="IValueTaskSource"/>.</summary>
+ /// <param name="token">Opaque value that was provided to the <see cref="ValueTask"/>'s constructor.</param>
+ void GetResult(short token);
+ }
+
+ /// <summary>Represents an object that can be wrapped by a <see cref="ValueTask{TResult}"/>.</summary>
+ /// <typeparam name="TResult">Specifies the type of data returned from the object.</typeparam>
+ public interface IValueTaskSource<out TResult>
+ {
+ /// <summary>Gets the status of the current operation.</summary>
+ /// <param name="token">Opaque value that was provided to the <see cref="ValueTask"/>'s constructor.</param>
+ ValueTaskSourceStatus GetStatus(short token);
+
+ /// <summary>Schedules the continuation action for this <see cref="IValueTaskSource{TResult}"/>.</summary>
+ /// <param name="continuation">The continuation to invoke when the operation has completed.</param>
+ /// <param name="state">The state object to pass to <paramref name="continuation"/> when it's invoked.</param>
+ /// <param name="token">Opaque value that was provided to the <see cref="ValueTask"/>'s constructor.</param>
+ /// <param name="flags">The flags describing the behavior of the continuation.</param>
+ void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags);
+
+ /// <summary>Gets the result of the <see cref="IValueTaskSource{TResult}"/>.</summary>
+ /// <param name="token">Opaque value that was provided to the <see cref="ValueTask"/>'s constructor.</param>
+ TResult GetResult(short token);
+ }
+}
diff --git a/src/Common/src/CoreLib/System/Threading/Tasks/TaskCanceledException.cs b/src/Common/src/CoreLib/System/Threading/Tasks/TaskCanceledException.cs
index 556fd80f19..f42a403cd0 100644
--- a/src/Common/src/CoreLib/System/Threading/Tasks/TaskCanceledException.cs
+++ b/src/Common/src/CoreLib/System/Threading/Tasks/TaskCanceledException.cs
@@ -56,6 +56,18 @@ namespace System.Threading.Tasks
}
/// <summary>
+ /// Initializes a new instance of the <see cref="T:System.Threading.Tasks.TaskCanceledException"/>
+ /// class with a specified error message, a reference to the inner exception that is the cause of
+ /// this exception, and the <see cref="CancellationToken"/> that triggered the cancellation.
+ /// </summary>
+ /// <param name="message">The error message that explains the reason for the exception.</param>
+ /// <param name="innerException">The exception that is the cause of the current exception.</param>
+ /// <param name="token">The <see cref="CancellationToken"/> that triggered the cancellation.</param>
+ public TaskCanceledException(string message, Exception innerException, CancellationToken token) : base(message, innerException, token)
+ {
+ }
+
+ /// <summary>
/// Initializes a new instance of the <see cref="T:System.Threading.Tasks.TaskCanceledException"/> class
/// with a reference to the <see cref="T:System.Threading.Tasks.Task"/> that has been canceled.
/// </summary>
diff --git a/src/Common/src/CoreLib/System/Threading/Tasks/ValueTask.cs b/src/Common/src/CoreLib/System/Threading/Tasks/ValueTask.cs
index de9b016328..56d5f540d3 100644
--- a/src/Common/src/CoreLib/System/Threading/Tasks/ValueTask.cs
+++ b/src/Common/src/CoreLib/System/Threading/Tasks/ValueTask.cs
@@ -3,72 +3,404 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
-using System.ComponentModel;
+using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using System.Threading.Tasks.Sources;
+
+#if !netstandard
+using Internal.Runtime.CompilerServices;
+#endif
namespace System.Threading.Tasks
{
- /// <summary>
- /// Provides a value type that wraps a <see cref="Task{TResult}"/> and a <typeparamref name="TResult"/>,
- /// only one of which is used.
- /// </summary>
- /// <typeparam name="TResult">The type of the result.</typeparam>
+ /// <summary>Provides an awaitable result of an asynchronous operation.</summary>
/// <remarks>
- /// <para>
- /// Methods may return an instance of this value type when it's likely that the result of their
- /// operations will be available synchronously and when the method is expected to be invoked so
- /// frequently that the cost of allocating a new <see cref="Task{TResult}"/> for each call will
- /// be prohibitive.
- /// </para>
- /// <para>
- /// There are tradeoffs to using a <see cref="ValueTask{TResult}"/> instead of a <see cref="Task{TResult}"/>.
- /// For example, while a <see cref="ValueTask{TResult}"/> can help avoid an allocation in the case where the
- /// successful result is available synchronously, it also contains two fields whereas a <see cref="Task{TResult}"/>
- /// as a reference type is a single field. This means that a method call ends up returning two fields worth of
- /// data instead of one, which is more data to copy. It also means that if a method that returns one of these
- /// is awaited within an async method, the state machine for that async method will be larger due to needing
- /// to store the struct that's two fields instead of a single reference.
- /// </para>
- /// <para>
- /// Further, for uses other than consuming the result of an asynchronous operation via await,
- /// <see cref="ValueTask{TResult}"/> can lead to a more convoluted programming model, which can in turn actually
- /// lead to more allocations. For example, consider a method that could return either a <see cref="Task{TResult}"/>
- /// with a cached task as a common result or a <see cref="ValueTask{TResult}"/>. If the consumer of the result
- /// wants to use it as a <see cref="Task{TResult}"/>, such as to use with in methods like Task.WhenAll and Task.WhenAny,
- /// the <see cref="ValueTask{TResult}"/> would first need to be converted into a <see cref="Task{TResult}"/> using
- /// <see cref="ValueTask{TResult}.AsTask"/>, which leads to an allocation that would have been avoided if a cached
- /// <see cref="Task{TResult}"/> had been used in the first place.
- /// </para>
- /// <para>
- /// As such, the default choice for any asynchronous method should be to return a <see cref="Task"/> or
- /// <see cref="Task{TResult}"/>. Only if performance analysis proves it worthwhile should a <see cref="ValueTask{TResult}"/>
- /// be used instead of <see cref="Task{TResult}"/>. There is no non-generic version of <see cref="ValueTask{TResult}"/>
- /// as the Task.CompletedTask property may be used to hand back a successfully completed singleton in the case where
- /// a <see cref="Task"/>-returning method completes synchronously and successfully.
- /// </para>
+ /// <see cref="ValueTask"/>s are meant to be directly awaited. To do more complicated operations with them, a <see cref="Task"/>
+ /// should be extracted using <see cref="AsTask"/>. Such operations might include caching an instance to be awaited later,
+ /// registering multiple continuations with a single operation, awaiting the same task multiple times, and using combinators over
+ /// multiple operations.
+ /// </remarks>
+ [AsyncMethodBuilder(typeof(AsyncValueTaskMethodBuilder))]
+ [StructLayout(LayoutKind.Auto)]
+ public readonly struct ValueTask : IEquatable<ValueTask>
+ {
+ /// <summary>A task canceled using `new CancellationToken(true)`.</summary>
+ private static readonly Task s_canceledTask =
+#if netstandard
+ Task.Delay(Timeout.Infinite, new CancellationToken(canceled: true));
+#else
+ Task.FromCanceled(new CancellationToken(canceled: true));
+#endif
+ /// <summary>A successfully completed task.</summary>
+ internal static Task CompletedTask
+#if netstandard
+ { get; } = Task.Delay(0);
+#else
+ => Task.CompletedTask;
+#endif
+
+ /// <summary>null if representing a successful synchronous completion, otherwise a <see cref="Task"/> or a <see cref="IValueTaskSource"/>.</summary>
+ internal readonly object _obj;
+ /// <summary>Flags providing additional details about the ValueTask's contents and behavior.</summary>
+ internal readonly ValueTaskFlags _flags;
+ /// <summary>Opaque value passed through to the <see cref="IValueTaskSource"/>.</summary>
+ internal readonly short _token;
+
+ // An instance created with the default ctor (a zero init'd struct) represents a synchronously, successfully completed operation.
+
+ /// <summary>Initialize the <see cref="ValueTask"/> with a <see cref="Task"/> that represents the operation.</summary>
+ /// <param name="task">The task.</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ValueTask(Task task)
+ {
+ if (task == null)
+ {
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.task);
+ }
+
+ _obj = task;
+
+ _flags = ValueTaskFlags.ObjectIsTask;
+ _token = 0;
+ }
+
+ /// <summary>Initialize the <see cref="ValueTask"/> with a <see cref="IValueTaskSource"/> object that represents the operation.</summary>
+ /// <param name="source">The source.</param>
+ /// <param name="token">Opaque value passed through to the <see cref="IValueTaskSource"/>.</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ValueTask(IValueTaskSource source, short token)
+ {
+ if (source == null)
+ {
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source);
+ }
+
+ _obj = source;
+ _token = token;
+
+ _flags = 0;
+ }
+
+ /// <summary>Non-verified initialization of the struct to the specified values.</summary>
+ /// <param name="obj">The object.</param>
+ /// <param name="token">The token.</param>
+ /// <param name="flags">The flags.</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private ValueTask(object obj, short token, ValueTaskFlags flags)
+ {
+ _obj = obj;
+ _token = token;
+ _flags = flags;
+ }
+
+ /// <summary>Gets whether the contination should be scheduled to the current context.</summary>
+ internal bool ContinueOnCapturedContext
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => (_flags & ValueTaskFlags.AvoidCapturedContext) == 0;
+ }
+
+ /// <summary>Gets whether the object in the <see cref="_obj"/> field is a <see cref="Task"/>.</summary>
+ internal bool ObjectIsTask
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => (_flags & ValueTaskFlags.ObjectIsTask) != 0;
+ }
+
+ /// <summary>Returns the <see cref="Task"/> stored in <see cref="_obj"/>. This uses <see cref="Unsafe"/>.</summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal Task UnsafeGetTask()
+ {
+ Debug.Assert(ObjectIsTask);
+ Debug.Assert(_obj is Task);
+ return Unsafe.As<Task>(_obj);
+ }
+
+ /// <summary>Returns the <see cref="IValueTaskSource"/> stored in <see cref="_obj"/>. This uses <see cref="Unsafe"/>.</summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal IValueTaskSource UnsafeGetValueTaskSource()
+ {
+ Debug.Assert(!ObjectIsTask);
+ Debug.Assert(_obj is IValueTaskSource);
+ return Unsafe.As<IValueTaskSource>(_obj);
+ }
+
+ /// <summary>Returns the hash code for this instance.</summary>
+ public override int GetHashCode() => _obj?.GetHashCode() ?? 0;
+
+ /// <summary>Returns a value indicating whether this value is equal to a specified <see cref="object"/>.</summary>
+ public override bool Equals(object obj) =>
+ obj is ValueTask &&
+ Equals((ValueTask)obj);
+
+ /// <summary>Returns a value indicating whether this value is equal to a specified <see cref="ValueTask"/> value.</summary>
+ public bool Equals(ValueTask other) => _obj == other._obj && _token == other._token;
+
+ /// <summary>Returns a value indicating whether two <see cref="ValueTask"/> values are equal.</summary>
+ public static bool operator ==(ValueTask left, ValueTask right) =>
+ left.Equals(right);
+
+ /// <summary>Returns a value indicating whether two <see cref="ValueTask"/> values are not equal.</summary>
+ public static bool operator !=(ValueTask left, ValueTask right) =>
+ !left.Equals(right);
+
+ /// <summary>
+ /// Gets a <see cref="Task"/> object to represent this ValueTask.
+ /// </summary>
+ /// <remarks>
+ /// It will either return the wrapped task object if one exists, or it'll
+ /// manufacture a new task object to represent the result.
+ /// </remarks>
+ public Task AsTask() =>
+ _obj == null ? ValueTask.CompletedTask :
+ ObjectIsTask ? UnsafeGetTask() :
+ GetTaskForValueTaskSource();
+
+ /// <summary>Gets a <see cref="ValueTask"/> that may be used at any point in the future.</summary>
+ public ValueTask Preserve() => _obj == null ? this : new ValueTask(AsTask());
+
+ /// <summary>Creates a <see cref="Task"/> to represent the <see cref="IValueTaskSource"/>.</summary>
+ private Task GetTaskForValueTaskSource()
+ {
+ IValueTaskSource t = UnsafeGetValueTaskSource();
+ ValueTaskSourceStatus status = t.GetStatus(_token);
+ if (status != ValueTaskSourceStatus.Pending)
+ {
+ try
+ {
+ // Propagate any exceptions that may have occurred, then return
+ // an already successfully completed task.
+ t.GetResult(_token);
+ return ValueTask.CompletedTask;
+
+ // If status is Faulted or Canceled, GetResult should throw. But
+ // we can't guarantee every implementation will do the "right thing".
+ // If it doesn't throw, we just treat that as success and ignore
+ // the status.
+ }
+ catch (Exception exc)
+ {
+ if (status == ValueTaskSourceStatus.Canceled)
+ {
+#if !netstandard
+ if (exc is OperationCanceledException oce)
+ {
+ var task = new Task<VoidTaskResult>();
+ task.TrySetCanceled(oce.CancellationToken, oce);
+ return task;
+ }
+#endif
+ return s_canceledTask;
+ }
+ else
+ {
+#if netstandard
+ var tcs = new TaskCompletionSource<bool>();
+ tcs.TrySetException(exc);
+ return tcs.Task;
+#else
+ return Task.FromException(exc);
+#endif
+ }
+ }
+ }
+
+ var m = new ValueTaskSourceTask(t, _token);
+ return
+#if netstandard
+ m.Task;
+#else
+ m;
+#endif
+ }
+
+ /// <summary>Type used to create a <see cref="Task"/> to represent a <see cref="IValueTaskSource"/>.</summary>
+ private sealed class ValueTaskSourceTask :
+#if netstandard
+ TaskCompletionSource<bool>
+#else
+ Task<VoidTaskResult>
+#endif
+ {
+ private static readonly Action<object> s_completionAction = state =>
+ {
+ if (!(state is ValueTaskSourceTask vtst) ||
+ !(vtst._source is IValueTaskSource source))
+ {
+ // This could only happen if the IValueTaskSource passed the wrong state
+ // or if this callback were invoked multiple times such that the state
+ // was previously nulled out.
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.state);
+ return;
+ }
+
+ vtst._source = null;
+ ValueTaskSourceStatus status = source.GetStatus(vtst._token);
+ try
+ {
+ source.GetResult(vtst._token);
+ vtst.TrySetResult(default);
+ }
+ catch (Exception exc)
+ {
+ if (status == ValueTaskSourceStatus.Canceled)
+ {
+#if netstandard
+ vtst.TrySetCanceled();
+#else
+ if (exc is OperationCanceledException oce)
+ {
+ vtst.TrySetCanceled(oce.CancellationToken, oce);
+ }
+ else
+ {
+ vtst.TrySetCanceled(new CancellationToken(true));
+ }
+#endif
+ }
+ else
+ {
+ vtst.TrySetException(exc);
+ }
+ }
+ };
+
+ /// <summary>The associated <see cref="IValueTaskSource"/>.</summary>
+ private IValueTaskSource _source;
+ /// <summary>The token to pass through to operations on <see cref="_source"/></summary>
+ private readonly short _token;
+
+ public ValueTaskSourceTask(IValueTaskSource source, short token)
+ {
+ _token = token;
+ _source = source;
+ source.OnCompleted(s_completionAction, this, token, ValueTaskSourceOnCompletedFlags.None);
+ }
+ }
+
+ /// <summary>Gets whether the <see cref="ValueTask"/> represents a completed operation.</summary>
+ public bool IsCompleted
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _obj == null || (ObjectIsTask ? UnsafeGetTask().IsCompleted : UnsafeGetValueTaskSource().GetStatus(_token) != ValueTaskSourceStatus.Pending);
+ }
+
+ /// <summary>Gets whether the <see cref="ValueTask"/> represents a successfully completed operation.</summary>
+ public bool IsCompletedSuccessfully
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get =>
+ _obj == null ||
+ (ObjectIsTask ?
+#if netstandard
+ UnsafeGetTask().Status == TaskStatus.RanToCompletion :
+#else
+ UnsafeGetTask().IsCompletedSuccessfully :
+#endif
+ UnsafeGetValueTaskSource().GetStatus(_token) == ValueTaskSourceStatus.Succeeded);
+ }
+
+ /// <summary>Gets whether the <see cref="ValueTask"/> represents a failed operation.</summary>
+ public bool IsFaulted
+ {
+ get =>
+ _obj != null &&
+ (ObjectIsTask ? UnsafeGetTask().IsFaulted : UnsafeGetValueTaskSource().GetStatus(_token) == ValueTaskSourceStatus.Faulted);
+ }
+
+ /// <summary>Gets whether the <see cref="ValueTask"/> represents a canceled operation.</summary>
+ /// <remarks>
+ /// If the <see cref="ValueTask"/> is backed by a result or by a <see cref="IValueTaskSource"/>,
+ /// this will always return false. If it's backed by a <see cref="Task"/>, it'll return the
+ /// value of the task's <see cref="Task.IsCanceled"/> property.
+ /// </remarks>
+ public bool IsCanceled
+ {
+ get =>
+ _obj != null &&
+ (ObjectIsTask ? UnsafeGetTask().IsCanceled : UnsafeGetValueTaskSource().GetStatus(_token) == ValueTaskSourceStatus.Canceled);
+ }
+
+ /// <summary>Throws the exception that caused the <see cref="ValueTask"/> to fail. If it completed successfully, nothing is thrown.</summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [StackTraceHidden]
+ internal void ThrowIfCompletedUnsuccessfully()
+ {
+ if (_obj != null)
+ {
+ if (ObjectIsTask)
+ {
+#if netstandard
+ UnsafeGetTask().GetAwaiter().GetResult();
+#else
+ TaskAwaiter.ValidateEnd(UnsafeGetTask());
+#endif
+ }
+ else
+ {
+ UnsafeGetValueTaskSource().GetResult(_token);
+ }
+ }
+ }
+
+ /// <summary>Gets an awaiter for this <see cref="ValueTask"/>.</summary>
+ public ValueTaskAwaiter GetAwaiter() => new ValueTaskAwaiter(this);
+
+ /// <summary>Configures an awaiter for this <see cref="ValueTask"/>.</summary>
+ /// <param name="continueOnCapturedContext">
+ /// true to attempt to marshal the continuation back to the captured context; otherwise, false.
+ /// </param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ConfiguredValueTaskAwaitable ConfigureAwait(bool continueOnCapturedContext)
+ {
+ // TODO: Simplify once https://github.com/dotnet/coreclr/pull/16138 is fixed.
+ bool avoidCapture = !continueOnCapturedContext;
+ return new ConfiguredValueTaskAwaitable(new ValueTask(_obj, _token, _flags | Unsafe.As<bool, ValueTaskFlags>(ref avoidCapture)));
+ }
+ }
+
+ /// <summary>Provides a value type that can represent a synchronously available value or a task object.</summary>
+ /// <typeparam name="TResult">Specifies the type of the result.</typeparam>
+ /// <remarks>
+ /// <see cref="ValueTask{TResult}"/>s are meant to be directly awaited. To do more complicated operations with them, a <see cref="Task"/>
+ /// should be extracted using <see cref="AsTask"/> or <see cref="Preserve"/>. Such operations might include caching an instance to
+ /// be awaited later, registering multiple continuations with a single operation, awaiting the same task multiple times, and using
+ /// combinators over multiple operations.
/// </remarks>
[AsyncMethodBuilder(typeof(AsyncValueTaskMethodBuilder<>))]
[StructLayout(LayoutKind.Auto)]
public readonly struct ValueTask<TResult> : IEquatable<ValueTask<TResult>>
{
- /// <summary>The task to be used if the operation completed asynchronously or if it completed synchronously but non-successfully.</summary>
- internal readonly Task<TResult> _task;
+ /// <summary>A task canceled using `new CancellationToken(true)`. Lazily created only when first needed.</summary>
+ private static Task<TResult> s_canceledTask;
+ /// <summary>null if <see cref="_result"/> has the result, otherwise a <see cref="Task{TResult}"/> or a <see cref="IValueTaskSource{TResult}"/>.</summary>
+ internal readonly object _obj;
/// <summary>The result to be used if the operation completed successfully synchronously.</summary>
internal readonly TResult _result;
+ /// <summary>Flags providing additional details about the ValueTask's contents and behavior.</summary>
+ internal readonly ValueTaskFlags _flags;
+ /// <summary>Opaque value passed through to the <see cref="IValueTaskSource{TResult}"/>.</summary>
+ internal readonly short _token;
+
+ // An instance created with the default ctor (a zero init'd struct) represents a synchronously, successfully completed operation
+ // with a result of default(TResult).
- /// <summary>Initialize the <see cref="ValueTask{TResult}"/> with the result of the successful operation.</summary>
+ /// <summary>Initialize the <see cref="ValueTask{TResult}"/> with a <typeparamref name="TResult"/> result value.</summary>
/// <param name="result">The result.</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public ValueTask(TResult result)
{
- _task = null;
_result = result;
+
+ _obj = null;
+ _flags = 0;
+ _token = 0;
}
- /// <summary>
- /// Initialize the <see cref="ValueTask{TResult}"/> with a <see cref="Task{TResult}"/> that represents the operation.
- /// </summary>
+ /// <summary>Initialize the <see cref="ValueTask{TResult}"/> with a <see cref="Task{TResult}"/> that represents the operation.</summary>
/// <param name="task">The task.</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public ValueTask(Task<TResult> task)
{
if (task == null)
@@ -76,103 +408,378 @@ namespace System.Threading.Tasks
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.task);
}
- _task = task;
- _result = default(TResult);
+ _obj = task;
+
+ _result = default;
+ _flags = ValueTaskFlags.ObjectIsTask;
+ _token = 0;
+ }
+
+ /// <summary>Initialize the <see cref="ValueTask{TResult}"/> with a <see cref="IValueTaskSource{TResult}"/> object that represents the operation.</summary>
+ /// <param name="source">The source.</param>
+ /// <param name="token">Opaque value passed through to the <see cref="IValueTaskSource"/>.</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ValueTask(IValueTaskSource<TResult> source, short token)
+ {
+ if (source == null)
+ {
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source);
+ }
+
+ _obj = source;
+ _token = token;
+
+ _result = default;
+ _flags = 0;
+ }
+
+ /// <summary>Non-verified initialization of the struct to the specified values.</summary>
+ /// <param name="obj">The object.</param>
+ /// <param name="result">The result.</param>
+ /// <param name="token">The token.</param>
+ /// <param name="flags">The flags.</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private ValueTask(object obj, TResult result, short token, ValueTaskFlags flags)
+ {
+ _obj = obj;
+ _result = result;
+ _token = token;
+ _flags = flags;
+ }
+
+ /// <summary>Gets whether the contination should be scheduled to the current context.</summary>
+ internal bool ContinueOnCapturedContext
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => (_flags & ValueTaskFlags.AvoidCapturedContext) == 0;
+ }
+
+ /// <summary>Gets whether the object in the <see cref="_obj"/> field is a <see cref="Task{TResult}"/>.</summary>
+ internal bool ObjectIsTask
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => (_flags & ValueTaskFlags.ObjectIsTask) != 0;
+ }
+
+ /// <summary>Returns the <see cref="Task{TResult}"/> stored in <see cref="_obj"/>. This uses <see cref="Unsafe"/>.</summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal Task<TResult> UnsafeGetTask()
+ {
+ Debug.Assert(ObjectIsTask);
+ Debug.Assert(_obj is Task<TResult>);
+ return Unsafe.As<Task<TResult>>(_obj);
+ }
+
+ /// <summary>Returns the <see cref="IValueTaskSource{TResult}"/> stored in <see cref="_obj"/>. This uses <see cref="Unsafe"/>.</summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal IValueTaskSource<TResult> UnsafeGetValueTaskSource()
+ {
+ Debug.Assert(!ObjectIsTask);
+ Debug.Assert(_obj is IValueTaskSource<TResult>);
+ return Unsafe.As<IValueTaskSource<TResult>>(_obj);
}
/// <summary>Returns the hash code for this instance.</summary>
public override int GetHashCode() =>
- _task != null ? _task.GetHashCode() :
+ _obj != null ? _obj.GetHashCode() :
_result != null ? _result.GetHashCode() :
0;
/// <summary>Returns a value indicating whether this value is equal to a specified <see cref="object"/>.</summary>
public override bool Equals(object obj) =>
- obj is ValueTask<TResult> &&
+ obj is ValueTask<TResult> &&
Equals((ValueTask<TResult>)obj);
/// <summary>Returns a value indicating whether this value is equal to a specified <see cref="ValueTask{TResult}"/> value.</summary>
public bool Equals(ValueTask<TResult> other) =>
- _task != null || other._task != null ?
- _task == other._task :
+ _obj != null || other._obj != null ?
+ _obj == other._obj && _token == other._token :
EqualityComparer<TResult>.Default.Equals(_result, other._result);
/// <summary>Returns a value indicating whether two <see cref="ValueTask{TResult}"/> values are equal.</summary>
- public static bool operator==(ValueTask<TResult> left, ValueTask<TResult> right) =>
+ public static bool operator ==(ValueTask<TResult> left, ValueTask<TResult> right) =>
left.Equals(right);
/// <summary>Returns a value indicating whether two <see cref="ValueTask{TResult}"/> values are not equal.</summary>
- public static bool operator!=(ValueTask<TResult> left, ValueTask<TResult> right) =>
+ public static bool operator !=(ValueTask<TResult> left, ValueTask<TResult> right) =>
!left.Equals(right);
/// <summary>
- /// Gets a <see cref="Task{TResult}"/> object to represent this ValueTask. It will
- /// either return the wrapped task object if one exists, or it'll manufacture a new
- /// task object to represent the result.
+ /// Gets a <see cref="Task{TResult}"/> object to represent this ValueTask.
/// </summary>
+ /// <remarks>
+ /// It will either return the wrapped task object if one exists, or it'll
+ /// manufacture a new task object to represent the result.
+ /// </remarks>
public Task<TResult> AsTask() =>
- // Return the task if we were constructed from one, otherwise manufacture one. We don't
- // cache the generated task into _task as it would end up changing both equality comparison
- // and the hash code we generate in GetHashCode.
- _task ?? AsyncTaskMethodBuilder<TResult>.GetTaskForResult(_result);
+ _obj == null ?
+#if netstandard
+ Task.FromResult(_result) :
+#else
+ AsyncTaskMethodBuilder<TResult>.GetTaskForResult(_result) :
+#endif
+ ObjectIsTask ? UnsafeGetTask() :
+ GetTaskForValueTaskSource();
- internal Task<TResult> AsTaskExpectNonNull() =>
- // Return the task if we were constructed from one, otherwise manufacture one.
- // Unlike AsTask(), this method is called only when we expect _task to be non-null,
- // and thus we don't want GetTaskForResult inlined.
- _task ?? GetTaskForResultNoInlining();
+ /// <summary>Gets a <see cref="ValueTask{TResult}"/> that may be used at any point in the future.</summary>
+ public ValueTask<TResult> Preserve() => _obj == null ? this : new ValueTask<TResult>(AsTask());
- [MethodImpl(MethodImplOptions.NoInlining)]
- private Task<TResult> GetTaskForResultNoInlining() => AsyncTaskMethodBuilder<TResult>.GetTaskForResult(_result);
+ /// <summary>Creates a <see cref="Task{TResult}"/> to represent the <see cref="IValueTaskSource{TResult}"/>.</summary>
+ private Task<TResult> GetTaskForValueTaskSource()
+ {
+ IValueTaskSource<TResult> t = UnsafeGetValueTaskSource();
+ ValueTaskSourceStatus status = t.GetStatus(_token);
+ if (status != ValueTaskSourceStatus.Pending)
+ {
+ try
+ {
+ // Get the result of the operation and return a task for it.
+ // If any exception occurred, propagate it
+ return
+#if netstandard
+ Task.FromResult(t.GetResult(_token));
+#else
+ AsyncTaskMethodBuilder<TResult>.GetTaskForResult(t.GetResult(_token));
+#endif
+
+ // If status is Faulted or Canceled, GetResult should throw. But
+ // we can't guarantee every implementation will do the "right thing".
+ // If it doesn't throw, we just treat that as success and ignore
+ // the status.
+ }
+ catch (Exception exc)
+ {
+ if (status == ValueTaskSourceStatus.Canceled)
+ {
+#if !netstandard
+ if (exc is OperationCanceledException oce)
+ {
+ var task = new Task<TResult>();
+ task.TrySetCanceled(oce.CancellationToken, oce);
+ return task;
+ }
+#endif
+
+ Task<TResult> canceledTask = s_canceledTask;
+ if (canceledTask == null)
+ {
+#if netstandard
+ var tcs = new TaskCompletionSource<TResult>();
+ tcs.TrySetCanceled();
+ canceledTask = tcs.Task;
+#else
+ canceledTask = Task.FromCanceled<TResult>(new CancellationToken(true));
+#endif
+ // Benign race condition to initialize cached task, as identity doesn't matter.
+ s_canceledTask = canceledTask;
+ }
+ return canceledTask;
+ }
+ else
+ {
+#if netstandard
+ var tcs = new TaskCompletionSource<TResult>();
+ tcs.TrySetException(exc);
+ return tcs.Task;
+#else
+ return Task.FromException<TResult>(exc);
+#endif
+ }
+ }
+ }
+
+ var m = new ValueTaskSourceTask(t, _token);
+ return
+#if netstandard
+ m.Task;
+#else
+ m;
+#endif
+ }
+
+ /// <summary>Type used to create a <see cref="Task{TResult}"/> to represent a <see cref="IValueTaskSource{TResult}"/>.</summary>
+ private sealed class ValueTaskSourceTask :
+#if netstandard
+ TaskCompletionSource<TResult>
+#else
+ Task<TResult>
+#endif
+ {
+ private static readonly Action<object> s_completionAction = state =>
+ {
+ if (!(state is ValueTaskSourceTask vtst) ||
+ !(vtst._source is IValueTaskSource<TResult> source))
+ {
+ // This could only happen if the IValueTaskSource<TResult> passed the wrong state
+ // or if this callback were invoked multiple times such that the state
+ // was previously nulled out.
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.state);
+ return;
+ }
+
+ vtst._source = null;
+ ValueTaskSourceStatus status = source.GetStatus(vtst._token);
+ try
+ {
+ vtst.TrySetResult(source.GetResult(vtst._token));
+ }
+ catch (Exception exc)
+ {
+ if (status == ValueTaskSourceStatus.Canceled)
+ {
+#if netstandard
+ vtst.TrySetCanceled();
+#else
+ if (exc is OperationCanceledException oce)
+ {
+ vtst.TrySetCanceled(oce.CancellationToken, oce);
+ }
+ else
+ {
+ vtst.TrySetCanceled(new CancellationToken(true));
+ }
+#endif
+ }
+ else
+ {
+ vtst.TrySetException(exc);
+ }
+ }
+ };
+
+ /// <summary>The associated <see cref="IValueTaskSource"/>.</summary>
+ private IValueTaskSource<TResult> _source;
+ /// <summary>The token to pass through to operations on <see cref="_source"/></summary>
+ private readonly short _token;
+
+ public ValueTaskSourceTask(IValueTaskSource<TResult> source, short token)
+ {
+ _source = source;
+ _token = token;
+ source.OnCompleted(s_completionAction, this, token, ValueTaskSourceOnCompletedFlags.None);
+ }
+ }
/// <summary>Gets whether the <see cref="ValueTask{TResult}"/> represents a completed operation.</summary>
- public bool IsCompleted => _task == null || _task.IsCompleted;
+ public bool IsCompleted
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _obj == null || (ObjectIsTask ? UnsafeGetTask().IsCompleted : UnsafeGetValueTaskSource().GetStatus(_token) != ValueTaskSourceStatus.Pending);
+ }
/// <summary>Gets whether the <see cref="ValueTask{TResult}"/> represents a successfully completed operation.</summary>
- public bool IsCompletedSuccessfully => _task == null || _task.IsCompletedSuccessfully;
+ public bool IsCompletedSuccessfully
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get =>
+ _obj == null ||
+ (ObjectIsTask ?
+#if netstandard
+ UnsafeGetTask().Status == TaskStatus.RanToCompletion :
+#else
+ UnsafeGetTask().IsCompletedSuccessfully :
+#endif
+ UnsafeGetValueTaskSource().GetStatus(_token) == ValueTaskSourceStatus.Succeeded);
+ }
/// <summary>Gets whether the <see cref="ValueTask{TResult}"/> represents a failed operation.</summary>
- public bool IsFaulted => _task != null && _task.IsFaulted;
+ public bool IsFaulted
+ {
+ get =>
+ _obj != null &&
+ (ObjectIsTask ? UnsafeGetTask().IsFaulted : UnsafeGetValueTaskSource().GetStatus(_token) == ValueTaskSourceStatus.Faulted);
+ }
/// <summary>Gets whether the <see cref="ValueTask{TResult}"/> represents a canceled operation.</summary>
- public bool IsCanceled => _task != null && _task.IsCanceled;
+ /// <remarks>
+ /// If the <see cref="ValueTask{TResult}"/> is backed by a result or by a <see cref="IValueTaskSource{TResult}"/>,
+ /// this will always return false. If it's backed by a <see cref="Task"/>, it'll return the
+ /// value of the task's <see cref="Task.IsCanceled"/> property.
+ /// </remarks>
+ public bool IsCanceled
+ {
+ get =>
+ _obj != null &&
+ (ObjectIsTask ? UnsafeGetTask().IsCanceled : UnsafeGetValueTaskSource().GetStatus(_token) == ValueTaskSourceStatus.Canceled);
+ }
/// <summary>Gets the result.</summary>
- public TResult Result => _task == null ? _result : _task.GetAwaiter().GetResult();
+ public TResult Result
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ if (_obj == null)
+ {
+ return _result;
+ }
- /// <summary>Gets an awaiter for this value.</summary>
+ if (ObjectIsTask)
+ {
+#if netstandard
+ return UnsafeGetTask().GetAwaiter().GetResult();
+#else
+ Task<TResult> t = UnsafeGetTask();
+ TaskAwaiter.ValidateEnd(t);
+ return t.ResultOnSuccess;
+#endif
+ }
+
+ return UnsafeGetValueTaskSource().GetResult(_token);
+ }
+ }
+
+ /// <summary>Gets an awaiter for this <see cref="ValueTask{TResult}"/>.</summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public ValueTaskAwaiter<TResult> GetAwaiter() => new ValueTaskAwaiter<TResult>(this);
- /// <summary>Configures an awaiter for this value.</summary>
+ /// <summary>Configures an awaiter for this <see cref="ValueTask{TResult}"/>.</summary>
/// <param name="continueOnCapturedContext">
/// true to attempt to marshal the continuation back to the captured context; otherwise, false.
/// </param>
- public ConfiguredValueTaskAwaitable<TResult> ConfigureAwait(bool continueOnCapturedContext) =>
- new ConfiguredValueTaskAwaitable<TResult>(this, continueOnCapturedContext);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ConfiguredValueTaskAwaitable<TResult> ConfigureAwait(bool continueOnCapturedContext)
+ {
+ // TODO: Simplify once https://github.com/dotnet/coreclr/pull/16138 is fixed.
+ bool avoidCapture = !continueOnCapturedContext;
+ return new ConfiguredValueTaskAwaitable<TResult>(new ValueTask<TResult>(_obj, _result, _token, _flags | Unsafe.As<bool, ValueTaskFlags>(ref avoidCapture)));
+ }
/// <summary>Gets a string-representation of this <see cref="ValueTask{TResult}"/>.</summary>
public override string ToString()
{
- if (_task != null)
- {
- return _task.IsCompletedSuccessfully && _task.Result != null ?
- _task.Result.ToString() :
- string.Empty;
- }
- else
+ if (IsCompletedSuccessfully)
{
- return _result != null ?
- _result.ToString() :
- string.Empty;
+ TResult result = Result;
+ if (result != null)
+ {
+ return result.ToString();
+ }
}
+
+ return string.Empty;
}
+ }
- // TODO https://github.com/dotnet/corefx/issues/22171:
- // Remove CreateAsyncMethodBuilder once the C# compiler relies on the AsyncBuilder attribute.
+ /// <summary>Internal flags used in the implementation of <see cref="ValueTask"/> and <see cref="ValueTask{TResult}"/>.</summary>
+ [Flags]
+ internal enum ValueTaskFlags : byte
+ {
+ /// <summary>
+ /// Indicates that context (e.g. SynchronizationContext) should not be captured when adding
+ /// a continuation.
+ /// </summary>
+ /// <remarks>
+ /// The value here must be 0x1, to match the value of a true Boolean reinterpreted as a byte.
+ /// This only has meaning when awaiting a ValueTask, with ConfigureAwait creating a new
+ /// ValueTask setting or not setting this flag appropriately.
+ /// </remarks>
+ AvoidCapturedContext = 0x1,
- /// <summary>Creates a method builder for use with an async method.</summary>
- /// <returns>The created builder.</returns>
- [EditorBrowsable(EditorBrowsableState.Never)] // intended only for compiler consumption
- public static AsyncValueTaskMethodBuilder<TResult> CreateAsyncMethodBuilder() => AsyncValueTaskMethodBuilder<TResult>.Create();
+ /// <summary>
+ /// Indicates that the ValueTask's object field stores a Task. This is used to avoid
+ /// a type check on whatever is stored in the object field.
+ /// </summary>
+ ObjectIsTask = 0x2
}
}
diff --git a/src/Common/src/CoreLib/System/TimeZoneInfo.Unix.cs b/src/Common/src/CoreLib/System/TimeZoneInfo.Unix.cs
new file mode 100644
index 0000000000..2dcaf67bfd
--- /dev/null
+++ b/src/Common/src/CoreLib/System/TimeZoneInfo.Unix.cs
@@ -0,0 +1,1560 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Text;
+using System.Threading;
+using System.Security;
+
+using Internal.IO;
+
+namespace System
+{
+ public sealed partial class TimeZoneInfo
+ {
+ private const string DefaultTimeZoneDirectory = "/usr/share/zoneinfo/";
+ private const string ZoneTabFileName = "zone.tab";
+ private const string TimeZoneEnvironmentVariable = "TZ";
+ private const string TimeZoneDirectoryEnvironmentVariable = "TZDIR";
+
+ private TimeZoneInfo(byte[] data, string id, bool dstDisabled)
+ {
+ TZifHead t;
+ DateTime[] dts;
+ byte[] typeOfLocalTime;
+ TZifType[] transitionType;
+ string zoneAbbreviations;
+ bool[] StandardTime;
+ bool[] GmtTime;
+ string futureTransitionsPosixFormat;
+
+ // parse the raw TZif bytes; this method can throw ArgumentException when the data is malformed.
+ TZif_ParseRaw(data, out t, out dts, out typeOfLocalTime, out transitionType, out zoneAbbreviations, out StandardTime, out GmtTime, out futureTransitionsPosixFormat);
+
+ _id = id;
+ _displayName = LocalId;
+ _baseUtcOffset = TimeSpan.Zero;
+
+ // find the best matching baseUtcOffset and display strings based on the current utcNow value.
+ // NOTE: read the display strings from the tzfile now in case they can't be loaded later
+ // from the globalization data.
+ DateTime utcNow = DateTime.UtcNow;
+ for (int i = 0; i < dts.Length && dts[i] <= utcNow; i++)
+ {
+ int type = typeOfLocalTime[i];
+ if (!transitionType[type].IsDst)
+ {
+ _baseUtcOffset = transitionType[type].UtcOffset;
+ _standardDisplayName = TZif_GetZoneAbbreviation(zoneAbbreviations, transitionType[type].AbbreviationIndex);
+ }
+ else
+ {
+ _daylightDisplayName = TZif_GetZoneAbbreviation(zoneAbbreviations, transitionType[type].AbbreviationIndex);
+ }
+ }
+
+ if (dts.Length == 0)
+ {
+ // time zones like Africa/Bujumbura and Etc/GMT* have no transition times but still contain
+ // TZifType entries that may contain a baseUtcOffset and display strings
+ for (int i = 0; i < transitionType.Length; i++)
+ {
+ if (!transitionType[i].IsDst)
+ {
+ _baseUtcOffset = transitionType[i].UtcOffset;
+ _standardDisplayName = TZif_GetZoneAbbreviation(zoneAbbreviations, transitionType[i].AbbreviationIndex);
+ }
+ else
+ {
+ _daylightDisplayName = TZif_GetZoneAbbreviation(zoneAbbreviations, transitionType[i].AbbreviationIndex);
+ }
+ }
+ }
+ _displayName = _standardDisplayName;
+
+ GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType.Generic, ref _displayName);
+ GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType.Standard, ref _standardDisplayName);
+ GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType.DaylightSavings, ref _daylightDisplayName);
+
+ // TZif supports seconds-level granularity with offsets but TimeZoneInfo only supports minutes since it aligns
+ // with DateTimeOffset, SQL Server, and the W3C XML Specification
+ if (_baseUtcOffset.Ticks % TimeSpan.TicksPerMinute != 0)
+ {
+ _baseUtcOffset = new TimeSpan(_baseUtcOffset.Hours, _baseUtcOffset.Minutes, 0);
+ }
+
+ if (!dstDisabled)
+ {
+ // only create the adjustment rule if DST is enabled
+ TZif_GenerateAdjustmentRules(out _adjustmentRules, _baseUtcOffset, dts, typeOfLocalTime, transitionType, StandardTime, GmtTime, futureTransitionsPosixFormat);
+ }
+
+ ValidateTimeZoneInfo(_id, _baseUtcOffset, _adjustmentRules, out _supportsDaylightSavingTime);
+ }
+
+ private void GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType nameType, ref string displayName)
+ {
+ if (GlobalizationMode.Invariant)
+ {
+ displayName = _standardDisplayName;
+ return;
+ }
+
+ string timeZoneDisplayName;
+ bool result = Interop.CallStringMethod(
+ (locale, id, type, stringBuilder) => Interop.Globalization.GetTimeZoneDisplayName(
+ locale,
+ id,
+ type,
+ stringBuilder,
+ stringBuilder.Capacity),
+ CultureInfo.CurrentUICulture.Name,
+ _id,
+ nameType,
+ out timeZoneDisplayName);
+
+ // If there is an unknown error, don't set the displayName field.
+ // It will be set to the abbreviation that was read out of the tzfile.
+ if (result)
+ {
+ displayName = timeZoneDisplayName;
+ }
+ }
+
+ /// <summary>
+ /// Returns a cloned array of AdjustmentRule objects
+ /// </summary>
+ public AdjustmentRule[] GetAdjustmentRules()
+ {
+ if (_adjustmentRules == null)
+ {
+ return Array.Empty<AdjustmentRule>();
+ }
+
+ // The rules we use in Unix care mostly about the start and end dates but don't fill the transition start and end info.
+ // as the rules now is public, we should fill it properly so the caller doesn't have to know how we use it internally
+ // and can use it as it is used in Windows
+
+ AdjustmentRule[] rules = new AdjustmentRule[_adjustmentRules.Length];
+
+ for (int i = 0; i < _adjustmentRules.Length; i++)
+ {
+ var rule = _adjustmentRules[i];
+ var start = rule.DateStart.Kind == DateTimeKind.Utc ?
+ // At the daylight start we didn't start the daylight saving yet then we convert to Local time
+ // by adding the _baseUtcOffset to the UTC time
+ new DateTime(rule.DateStart.Ticks + _baseUtcOffset.Ticks, DateTimeKind.Unspecified) :
+ rule.DateStart;
+ var end = rule.DateEnd.Kind == DateTimeKind.Utc ?
+ // At the daylight saving end, the UTC time is mapped to local time which is already shifted by the daylight delta
+ // we calculate the local time by adding _baseUtcOffset + DaylightDelta to the UTC time
+ new DateTime(rule.DateEnd.Ticks + _baseUtcOffset.Ticks + rule.DaylightDelta.Ticks, DateTimeKind.Unspecified) :
+ rule.DateEnd;
+
+ var startTransition = TimeZoneInfo.TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1, start.Hour, start.Minute, start.Second), start.Month, start.Day);
+ var endTransition = TimeZoneInfo.TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1, end.Hour, end.Minute, end.Second), end.Month, end.Day);
+
+ rules[i] = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(start.Date, end.Date, rule.DaylightDelta, startTransition, endTransition);
+ }
+
+ return rules;
+ }
+
+ private static void PopulateAllSystemTimeZones(CachedData cachedData)
+ {
+ Debug.Assert(Monitor.IsEntered(cachedData));
+
+ string timeZoneDirectory = GetTimeZoneDirectory();
+ foreach (string timeZoneId in GetTimeZoneIds(timeZoneDirectory))
+ {
+ TimeZoneInfo value;
+ Exception ex;
+ TryGetTimeZone(timeZoneId, false, out value, out ex, cachedData, alwaysFallbackToLocalMachine: true); // populate the cache
+ }
+ }
+
+ /// <summary>
+ /// Helper function for retrieving the local system time zone.
+ /// May throw COMException, TimeZoneNotFoundException, InvalidTimeZoneException.
+ /// Assumes cachedData lock is taken.
+ /// </summary>
+ /// <returns>A new TimeZoneInfo instance.</returns>
+ private static TimeZoneInfo GetLocalTimeZone(CachedData cachedData)
+ {
+ Debug.Assert(Monitor.IsEntered(cachedData));
+
+ // Without Registry support, create the TimeZoneInfo from a TZ file
+ return GetLocalTimeZoneFromTzFile();
+ }
+
+ private static TimeZoneInfoResult TryGetTimeZoneFromLocalMachine(string id, out TimeZoneInfo value, out Exception e)
+ {
+ value = null;
+ e = null;
+
+ string timeZoneDirectory = GetTimeZoneDirectory();
+ string timeZoneFilePath = Path.Combine(timeZoneDirectory, id);
+ byte[] rawData;
+ try
+ {
+ rawData = File.ReadAllBytes(timeZoneFilePath);
+ }
+ catch (UnauthorizedAccessException ex)
+ {
+ e = ex;
+ return TimeZoneInfoResult.SecurityException;
+ }
+ catch (FileNotFoundException ex)
+ {
+ e = ex;
+ return TimeZoneInfoResult.TimeZoneNotFoundException;
+ }
+ catch (DirectoryNotFoundException ex)
+ {
+ e = ex;
+ return TimeZoneInfoResult.TimeZoneNotFoundException;
+ }
+ catch (IOException ex)
+ {
+ e = new InvalidTimeZoneException(SR.Format(SR.InvalidTimeZone_InvalidFileData, id, timeZoneFilePath), ex);
+ return TimeZoneInfoResult.InvalidTimeZoneException;
+ }
+
+ value = GetTimeZoneFromTzData(rawData, id);
+
+ if (value == null)
+ {
+ e = new InvalidTimeZoneException(SR.Format(SR.InvalidTimeZone_InvalidFileData, id, timeZoneFilePath));
+ return TimeZoneInfoResult.InvalidTimeZoneException;
+ }
+
+ return TimeZoneInfoResult.Success;
+ }
+
+ /// <summary>
+ /// Returns a collection of TimeZone Id values from the zone.tab file in the timeZoneDirectory.
+ /// </summary>
+ /// <remarks>
+ /// Lines that start with # are comments and are skipped.
+ /// </remarks>
+ private static List<string> GetTimeZoneIds(string timeZoneDirectory)
+ {
+ List<string> timeZoneIds = new List<string>();
+
+ try
+ {
+ using (StreamReader sr = new StreamReader(Path.Combine(timeZoneDirectory, ZoneTabFileName), Encoding.UTF8))
+ {
+ string zoneTabFileLine;
+ while ((zoneTabFileLine = sr.ReadLine()) != null)
+ {
+ if (!string.IsNullOrEmpty(zoneTabFileLine) && zoneTabFileLine[0] != '#')
+ {
+ // the format of the line is "country-code \t coordinates \t TimeZone Id \t comments"
+
+ int firstTabIndex = zoneTabFileLine.IndexOf('\t');
+ if (firstTabIndex != -1)
+ {
+ int secondTabIndex = zoneTabFileLine.IndexOf('\t', firstTabIndex + 1);
+ if (secondTabIndex != -1)
+ {
+ string timeZoneId;
+ int startIndex = secondTabIndex + 1;
+ int thirdTabIndex = zoneTabFileLine.IndexOf('\t', startIndex);
+ if (thirdTabIndex != -1)
+ {
+ int length = thirdTabIndex - startIndex;
+ timeZoneId = zoneTabFileLine.Substring(startIndex, length);
+ }
+ else
+ {
+ timeZoneId = zoneTabFileLine.Substring(startIndex);
+ }
+
+ if (!string.IsNullOrEmpty(timeZoneId))
+ {
+ timeZoneIds.Add(timeZoneId);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ catch (IOException) { }
+ catch (UnauthorizedAccessException) { }
+
+ return timeZoneIds;
+ }
+
+ /// <summary>
+ /// Gets the tzfile raw data for the current 'local' time zone using the following rules.
+ /// 1. Read the TZ environment variable. If it is set, use it.
+ /// 2. Look for the data in /etc/localtime.
+ /// 3. Look for the data in GetTimeZoneDirectory()/localtime.
+ /// 4. Use UTC if all else fails.
+ /// </summary>
+ private static bool TryGetLocalTzFile(out byte[] rawData, out string id)
+ {
+ rawData = null;
+ id = null;
+ string tzVariable = GetTzEnvironmentVariable();
+
+ // If the env var is null, use the localtime file
+ if (tzVariable == null)
+ {
+ return
+ TryLoadTzFile("/etc/localtime", ref rawData, ref id) ||
+ TryLoadTzFile(Path.Combine(GetTimeZoneDirectory(), "localtime"), ref rawData, ref id);
+ }
+
+ // If it's empty, use UTC (TryGetLocalTzFile() should return false).
+ if (tzVariable.Length == 0)
+ {
+ return false;
+ }
+
+ // Otherwise, use the path from the env var. If it's not absolute, make it relative
+ // to the system timezone directory
+ string tzFilePath;
+ if (tzVariable[0] != '/')
+ {
+ id = tzVariable;
+ tzFilePath = Path.Combine(GetTimeZoneDirectory(), tzVariable);
+ }
+ else
+ {
+ tzFilePath = tzVariable;
+ }
+ return TryLoadTzFile(tzFilePath, ref rawData, ref id);
+ }
+
+ private static string GetTzEnvironmentVariable()
+ {
+ string result = Environment.GetEnvironmentVariable(TimeZoneEnvironmentVariable);
+ if (!string.IsNullOrEmpty(result))
+ {
+ if (result[0] == ':')
+ {
+ // strip off the ':' prefix
+ result = result.Substring(1);
+ }
+ }
+
+ return result;
+ }
+
+ private static bool TryLoadTzFile(string tzFilePath, ref byte[] rawData, ref string id)
+ {
+ if (File.Exists(tzFilePath))
+ {
+ try
+ {
+ rawData = File.ReadAllBytes(tzFilePath);
+ if (string.IsNullOrEmpty(id))
+ {
+ id = FindTimeZoneIdUsingReadLink(tzFilePath);
+
+ if (string.IsNullOrEmpty(id))
+ {
+ id = FindTimeZoneId(rawData);
+ }
+ }
+ return true;
+ }
+ catch (IOException) { }
+ catch (SecurityException) { }
+ catch (UnauthorizedAccessException) { }
+ }
+ return false;
+ }
+
+ /// <summary>
+ /// Finds the time zone id by using 'readlink' on the path to see if tzFilePath is
+ /// a symlink to a file.
+ /// </summary>
+ private static string FindTimeZoneIdUsingReadLink(string tzFilePath)
+ {
+ string id = null;
+
+ string symlinkPath = Interop.Sys.ReadLink(tzFilePath);
+ if (symlinkPath != null)
+ {
+ // Use Path.Combine to resolve links that contain a relative path (e.g. /etc/localtime).
+ symlinkPath = Path.Combine(tzFilePath, symlinkPath);
+
+ string timeZoneDirectory = GetTimeZoneDirectory();
+ if (symlinkPath.StartsWith(timeZoneDirectory, StringComparison.Ordinal))
+ {
+ id = symlinkPath.Substring(timeZoneDirectory.Length);
+ }
+ }
+
+ return id;
+ }
+
+ /// <summary>
+ /// Enumerate files
+ /// </summary>
+ private static IEnumerable<string> EnumerateFilesRecursively(string path)
+ {
+ List<string> toExplore = null; // List used as a stack
+
+ string currentPath = path;
+ for(;;)
+ {
+ using (Microsoft.Win32.SafeHandles.SafeDirectoryHandle dirHandle = Interop.Sys.OpenDir(currentPath))
+ {
+ if (dirHandle.IsInvalid)
+ {
+ throw Interop.GetExceptionForIoErrno(Interop.Sys.GetLastErrorInfo(), currentPath, isDirectory: true);
+ }
+
+ // Read each entry from the enumerator
+ Interop.Sys.DirectoryEntry dirent;
+ while (Interop.Sys.ReadDir(dirHandle, out dirent) == 0)
+ {
+ if (dirent.InodeName == "." || dirent.InodeName == "..")
+ continue;
+
+ string fullPath = Path.Combine(currentPath, dirent.InodeName);
+
+ // Get from the dir entry whether the entry is a file or directory.
+ // We classify everything as a file unless we know it to be a directory.
+ bool isDir;
+ if (dirent.InodeType == Interop.Sys.NodeType.DT_DIR)
+ {
+ // We know it's a directory.
+ isDir = true;
+ }
+ else if (dirent.InodeType == Interop.Sys.NodeType.DT_LNK || dirent.InodeType == Interop.Sys.NodeType.DT_UNKNOWN)
+ {
+ // It's a symlink or unknown: stat to it to see if we can resolve it to a directory.
+ // If we can't (e.g. symlink to a file, broken symlink, etc.), we'll just treat it as a file.
+
+ Interop.Sys.FileStatus fileinfo;
+ if (Interop.Sys.Stat(fullPath, out fileinfo) >= 0)
+ {
+ isDir = (fileinfo.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFDIR;
+ }
+ else
+ {
+ isDir = false;
+ }
+ }
+ else
+ {
+ // Otherwise, treat it as a file. This includes regular files, FIFOs, etc.
+ isDir = false;
+ }
+
+ // Yield the result if the user has asked for it. In the case of directories,
+ // always explore it by pushing it onto the stack, regardless of whether
+ // we're returning directories.
+ if (isDir)
+ {
+ if (toExplore == null)
+ {
+ toExplore = new List<string>();
+ }
+ toExplore.Add(fullPath);
+ }
+ else
+ {
+ yield return fullPath;
+ }
+ }
+ }
+
+ if (toExplore == null || toExplore.Count == 0)
+ break;
+
+ currentPath = toExplore[toExplore.Count - 1];
+ toExplore.RemoveAt(toExplore.Count - 1);
+ }
+ }
+
+ /// <summary>
+ /// Find the time zone id by searching all the tzfiles for the one that matches rawData
+ /// and return its file name.
+ /// </summary>
+ private static string FindTimeZoneId(byte[] rawData)
+ {
+ // default to "Local" if we can't find the right tzfile
+ string id = LocalId;
+ string timeZoneDirectory = GetTimeZoneDirectory();
+ string localtimeFilePath = Path.Combine(timeZoneDirectory, "localtime");
+ string posixrulesFilePath = Path.Combine(timeZoneDirectory, "posixrules");
+ byte[] buffer = new byte[rawData.Length];
+
+ try
+ {
+ foreach (string filePath in EnumerateFilesRecursively(timeZoneDirectory))
+ {
+ // skip the localtime and posixrules file, since they won't give us the correct id
+ if (!string.Equals(filePath, localtimeFilePath, StringComparison.OrdinalIgnoreCase)
+ && !string.Equals(filePath, posixrulesFilePath, StringComparison.OrdinalIgnoreCase))
+ {
+ if (CompareTimeZoneFile(filePath, buffer, rawData))
+ {
+ // if all bytes are the same, this must be the right tz file
+ id = filePath;
+
+ // strip off the root time zone directory
+ if (id.StartsWith(timeZoneDirectory, StringComparison.Ordinal))
+ {
+ id = id.Substring(timeZoneDirectory.Length);
+ }
+ break;
+ }
+ }
+ }
+ }
+ catch (IOException) { }
+ catch (SecurityException) { }
+ catch (UnauthorizedAccessException) { }
+
+ return id;
+ }
+
+ private static bool CompareTimeZoneFile(string filePath, byte[] buffer, byte[] rawData)
+ {
+ try
+ {
+ // bufferSize == 1 used to avoid unnecessary buffer in FileStream
+ using (FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 1))
+ {
+ if (stream.Length == rawData.Length)
+ {
+ int index = 0;
+ int count = rawData.Length;
+
+ while (count > 0)
+ {
+ int n = stream.Read(buffer, index, count);
+ if (n == 0)
+ throw Error.GetEndOfFile();
+
+ int end = index + n;
+ for (; index < end; index++)
+ {
+ if (buffer[index] != rawData[index])
+ {
+ return false;
+ }
+ }
+
+ count -= n;
+ }
+
+ return true;
+ }
+ }
+ }
+ catch (IOException) { }
+ catch (SecurityException) { }
+ catch (UnauthorizedAccessException) { }
+
+ return false;
+ }
+
+ /// <summary>
+ /// Helper function used by 'GetLocalTimeZone()' - this function wraps the call
+ /// for loading time zone data from computers without Registry support.
+ ///
+ /// The TryGetLocalTzFile() call returns a Byte[] containing the compiled tzfile.
+ /// </summary>
+ private static TimeZoneInfo GetLocalTimeZoneFromTzFile()
+ {
+ byte[] rawData;
+ string id;
+ if (TryGetLocalTzFile(out rawData, out id))
+ {
+ TimeZoneInfo result = GetTimeZoneFromTzData(rawData, id);
+ if (result != null)
+ {
+ return result;
+ }
+ }
+
+ // if we can't find a local time zone, return UTC
+ return Utc;
+ }
+
+ private static TimeZoneInfo GetTimeZoneFromTzData(byte[] rawData, string id)
+ {
+ if (rawData != null)
+ {
+ try
+ {
+ return new TimeZoneInfo(rawData, id, dstDisabled: false); // create a TimeZoneInfo instance from the TZif data w/ DST support
+ }
+ catch (ArgumentException) { }
+ catch (InvalidTimeZoneException) { }
+ try
+ {
+ return new TimeZoneInfo(rawData, id, dstDisabled: true); // create a TimeZoneInfo instance from the TZif data w/o DST support
+ }
+ catch (ArgumentException) { }
+ catch (InvalidTimeZoneException) { }
+ }
+
+ return null;
+ }
+
+ private static string GetTimeZoneDirectory()
+ {
+ string tzDirectory = Environment.GetEnvironmentVariable(TimeZoneDirectoryEnvironmentVariable);
+
+ if (tzDirectory == null)
+ {
+ tzDirectory = DefaultTimeZoneDirectory;
+ }
+ else if (!tzDirectory.EndsWith(Path.DirectorySeparatorChar))
+ {
+ tzDirectory += Path.DirectorySeparatorChar;
+ }
+
+ return tzDirectory;
+ }
+
+ /// <summary>
+ /// Helper function for retrieving a TimeZoneInfo object by <time_zone_name>.
+ /// This function wraps the logic necessary to keep the private
+ /// SystemTimeZones cache in working order
+ ///
+ /// This function will either return a valid TimeZoneInfo instance or
+ /// it will throw 'InvalidTimeZoneException' / 'TimeZoneNotFoundException'.
+ /// </summary>
+ public static TimeZoneInfo FindSystemTimeZoneById(string id)
+ {
+ // Special case for Utc as it will not exist in the dictionary with the rest
+ // of the system time zones. There is no need to do this check for Local.Id
+ // since Local is a real time zone that exists in the dictionary cache
+ if (string.Equals(id, UtcId, StringComparison.OrdinalIgnoreCase))
+ {
+ return Utc;
+ }
+
+ if (id == null)
+ {
+ throw new ArgumentNullException(nameof(id));
+ }
+ else if (id.Length == 0 || id.Contains('\0'))
+ {
+ throw new TimeZoneNotFoundException(SR.Format(SR.TimeZoneNotFound_MissingData, id));
+ }
+
+ TimeZoneInfo value;
+ Exception e;
+
+ TimeZoneInfoResult result;
+
+ CachedData cachedData = s_cachedData;
+
+ lock (cachedData)
+ {
+ result = TryGetTimeZone(id, false, out value, out e, cachedData, alwaysFallbackToLocalMachine: true);
+ }
+
+ if (result == TimeZoneInfoResult.Success)
+ {
+ return value;
+ }
+ else if (result == TimeZoneInfoResult.InvalidTimeZoneException)
+ {
+ Debug.Assert(e is InvalidTimeZoneException,
+ "TryGetTimeZone must create an InvalidTimeZoneException when it returns TimeZoneInfoResult.InvalidTimeZoneException");
+ throw e;
+ }
+ else if (result == TimeZoneInfoResult.SecurityException)
+ {
+ throw new SecurityException(SR.Format(SR.Security_CannotReadFileData, id), e);
+ }
+ else
+ {
+ throw new TimeZoneNotFoundException(SR.Format(SR.TimeZoneNotFound_MissingData, id), e);
+ }
+ }
+
+ // DateTime.Now fast path that avoids allocating an historically accurate TimeZoneInfo.Local and just creates a 1-year (current year) accurate time zone
+ internal static TimeSpan GetDateTimeNowUtcOffsetFromUtc(DateTime time, out bool isAmbiguousLocalDst)
+ {
+ bool isDaylightSavings;
+ // Use the standard code path for Unix since there isn't a faster way of handling current-year-only time zones
+ return GetUtcOffsetFromUtc(time, Local, out isDaylightSavings, out isAmbiguousLocalDst);
+ }
+
+ // TZFILE(5) BSD File Formats Manual TZFILE(5)
+ //
+ // NAME
+ // tzfile -- timezone information
+ //
+ // SYNOPSIS
+ // #include "/usr/src/lib/libc/stdtime/tzfile.h"
+ //
+ // DESCRIPTION
+ // The time zone information files used by tzset(3) begin with the magic
+ // characters ``TZif'' to identify them as time zone information files, fol-
+ // lowed by sixteen bytes reserved for future use, followed by four four-
+ // byte values written in a ``standard'' byte order (the high-order byte of
+ // the value is written first). These values are, in order:
+ //
+ // tzh_ttisgmtcnt The number of UTC/local indicators stored in the file.
+ // tzh_ttisstdcnt The number of standard/wall indicators stored in the
+ // file.
+ // tzh_leapcnt The number of leap seconds for which data is stored in
+ // the file.
+ // tzh_timecnt The number of ``transition times'' for which data is
+ // stored in the file.
+ // tzh_typecnt The number of ``local time types'' for which data is
+ // stored in the file (must not be zero).
+ // tzh_charcnt The number of characters of ``time zone abbreviation
+ // strings'' stored in the file.
+ //
+ // The above header is followed by tzh_timecnt four-byte values of type
+ // long, sorted in ascending order. These values are written in ``stan-
+ // dard'' byte order. Each is used as a transition time (as returned by
+ // time(3)) at which the rules for computing local time change. Next come
+ // tzh_timecnt one-byte values of type unsigned char; each one tells which
+ // of the different types of ``local time'' types described in the file is
+ // associated with the same-indexed transition time. These values serve as
+ // indices into an array of ttinfo structures that appears next in the file;
+ // these structures are defined as follows:
+ //
+ // struct ttinfo {
+ // long tt_gmtoff;
+ // int tt_isdst;
+ // unsigned int tt_abbrind;
+ // };
+ //
+ // Each structure is written as a four-byte value for tt_gmtoff of type
+ // long, in a standard byte order, followed by a one-byte value for tt_isdst
+ // and a one-byte value for tt_abbrind. In each structure, tt_gmtoff gives
+ // the number of seconds to be added to UTC, tt_isdst tells whether tm_isdst
+ // should be set by localtime(3) and tt_abbrind serves as an index into the
+ // array of time zone abbreviation characters that follow the ttinfo struc-
+ // ture(s) in the file.
+ //
+ // Then there are tzh_leapcnt pairs of four-byte values, written in standard
+ // byte order; the first value of each pair gives the time (as returned by
+ // time(3)) at which a leap second occurs; the second gives the total number
+ // of leap seconds to be applied after the given time. The pairs of values
+ // are sorted in ascending order by time.b
+ //
+ // Then there are tzh_ttisstdcnt standard/wall indicators, each stored as a
+ // one-byte value; they tell whether the transition times associated with
+ // local time types were specified as standard time or wall clock time, and
+ // are used when a time zone file is used in handling POSIX-style time zone
+ // environment variables.
+ //
+ // Finally there are tzh_ttisgmtcnt UTC/local indicators, each stored as a
+ // one-byte value; they tell whether the transition times associated with
+ // local time types were specified as UTC or local time, and are used when a
+ // time zone file is used in handling POSIX-style time zone environment
+ // variables.
+ //
+ // localtime uses the first standard-time ttinfo structure in the file (or
+ // simply the first ttinfo structure in the absence of a standard-time
+ // structure) if either tzh_timecnt is zero or the time argument is less
+ // than the first transition time recorded in the file.
+ //
+ // SEE ALSO
+ // ctime(3), time2posix(3), zic(8)
+ //
+ // BSD September 13, 1994 BSD
+ //
+ //
+ //
+ // TIME(3) BSD Library Functions Manual TIME(3)
+ //
+ // NAME
+ // time -- get time of day
+ //
+ // LIBRARY
+ // Standard C Library (libc, -lc)
+ //
+ // SYNOPSIS
+ // #include <time.h>
+ //
+ // time_t
+ // time(time_t *tloc);
+ //
+ // DESCRIPTION
+ // The time() function returns the value of time in seconds since 0 hours, 0
+ // minutes, 0 seconds, January 1, 1970, Coordinated Universal Time, without
+ // including leap seconds. If an error occurs, time() returns the value
+ // (time_t)-1.
+ //
+ // The return value is also stored in *tloc, provided that tloc is non-null.
+ //
+ // ERRORS
+ // The time() function may fail for any of the reasons described in
+ // gettimeofday(2).
+ //
+ // SEE ALSO
+ // gettimeofday(2), ctime(3)
+ //
+ // STANDARDS
+ // The time function conforms to IEEE Std 1003.1-2001 (``POSIX.1'').
+ //
+ // BUGS
+ // Neither ISO/IEC 9899:1999 (``ISO C99'') nor IEEE Std 1003.1-2001
+ // (``POSIX.1'') requires time() to set errno on failure; thus, it is impos-
+ // sible for an application to distinguish the valid time value -1 (repre-
+ // senting the last UTC second of 1969) from the error return value.
+ //
+ // Systems conforming to earlier versions of the C and POSIX standards
+ // (including older versions of FreeBSD) did not set *tloc in the error
+ // case.
+ //
+ // HISTORY
+ // A time() function appeared in Version 6 AT&T UNIX.
+ //
+ // BSD July 18, 2003 BSD
+ //
+ //
+ private static void TZif_GenerateAdjustmentRules(out AdjustmentRule[] rules, TimeSpan baseUtcOffset, DateTime[] dts, byte[] typeOfLocalTime,
+ TZifType[] transitionType, bool[] StandardTime, bool[] GmtTime, string futureTransitionsPosixFormat)
+ {
+ rules = null;
+
+ if (dts.Length > 0)
+ {
+ int index = 0;
+ List<AdjustmentRule> rulesList = new List<AdjustmentRule>();
+
+ while (index <= dts.Length)
+ {
+ TZif_GenerateAdjustmentRule(ref index, baseUtcOffset, rulesList, dts, typeOfLocalTime, transitionType, StandardTime, GmtTime, futureTransitionsPosixFormat);
+ }
+
+ rules = rulesList.ToArray();
+ if (rules != null && rules.Length == 0)
+ {
+ rules = null;
+ }
+ }
+ }
+
+ private static void TZif_GenerateAdjustmentRule(ref int index, TimeSpan timeZoneBaseUtcOffset, List<AdjustmentRule> rulesList, DateTime[] dts,
+ byte[] typeOfLocalTime, TZifType[] transitionTypes, bool[] StandardTime, bool[] GmtTime, string futureTransitionsPosixFormat)
+ {
+ // To generate AdjustmentRules, use the following approach:
+ // The first AdjustmentRule will go from DateTime.MinValue to the first transition time greater than DateTime.MinValue.
+ // Each middle AdjustmentRule wil go from dts[index-1] to dts[index].
+ // The last AdjustmentRule will go from dts[dts.Length-1] to Datetime.MaxValue.
+
+ // 0. Skip any DateTime.MinValue transition times. In newer versions of the tzfile, there
+ // is a "big bang" transition time, which is before the year 0001. Since any times before year 0001
+ // cannot be represented by DateTime, there is no reason to make AdjustmentRules for these unrepresentable time periods.
+ // 1. If there are no DateTime.MinValue times, the first AdjustmentRule goes from DateTime.MinValue
+ // to the first transition and uses the first standard transitionType (or the first transitionType if none of them are standard)
+ // 2. Create an AdjustmentRule for each transition, i.e. from dts[index - 1] to dts[index].
+ // This rule uses the transitionType[index - 1] and the whole AdjustmentRule only describes a single offset - either
+ // all daylight savings, or all stanard time.
+ // 3. After all the transitions are filled out, the last AdjustmentRule is created from either:
+ // a. a POSIX-style timezone description ("futureTransitionsPosixFormat"), if there is one or
+ // b. continue the last transition offset until DateTime.Max
+
+ while (index < dts.Length && dts[index] == DateTime.MinValue)
+ {
+ index++;
+ }
+
+ if (index == 0)
+ {
+ TZifType transitionType = TZif_GetEarlyDateTransitionType(transitionTypes);
+ DateTime endTransitionDate = dts[index];
+
+ TimeSpan transitionOffset = TZif_CalculateTransitionOffsetFromBase(transitionType.UtcOffset, timeZoneBaseUtcOffset);
+ TimeSpan daylightDelta = transitionType.IsDst ? transitionOffset : TimeSpan.Zero;
+ TimeSpan baseUtcDelta = transitionType.IsDst ? TimeSpan.Zero : transitionOffset;
+
+ AdjustmentRule r = AdjustmentRule.CreateAdjustmentRule(
+ DateTime.MinValue,
+ endTransitionDate.AddTicks(-1),
+ daylightDelta,
+ default(TransitionTime),
+ default(TransitionTime),
+ baseUtcDelta,
+ noDaylightTransitions: true);
+ rulesList.Add(r);
+ }
+ else if (index < dts.Length)
+ {
+ DateTime startTransitionDate = dts[index - 1];
+ TZifType startTransitionType = transitionTypes[typeOfLocalTime[index - 1]];
+
+ DateTime endTransitionDate = dts[index];
+
+ TimeSpan transitionOffset = TZif_CalculateTransitionOffsetFromBase(startTransitionType.UtcOffset, timeZoneBaseUtcOffset);
+ TimeSpan daylightDelta = startTransitionType.IsDst ? transitionOffset : TimeSpan.Zero;
+ TimeSpan baseUtcDelta = startTransitionType.IsDst ? TimeSpan.Zero : transitionOffset;
+
+ TransitionTime dstStart;
+ if (startTransitionType.IsDst)
+ {
+ // the TransitionTime fields are not used when AdjustmentRule.NoDaylightTransitions == true.
+ // However, there are some cases in the past where DST = true, and the daylight savings offset
+ // now equals what the current BaseUtcOffset is. In that case, the AdjustmentRule.DaylightOffset
+ // is going to be TimeSpan.Zero. But we still need to return 'true' from AdjustmentRule.HasDaylightSaving.
+ // To ensure we always return true from HasDaylightSaving, make a "special" dstStart that will make the logic
+ // in HasDaylightSaving return true.
+ dstStart = TransitionTime.CreateFixedDateRule(DateTime.MinValue.AddMilliseconds(2), 1, 1);
+ }
+ else
+ {
+ dstStart = default(TransitionTime);
+ }
+
+ AdjustmentRule r = AdjustmentRule.CreateAdjustmentRule(
+ startTransitionDate,
+ endTransitionDate.AddTicks(-1),
+ daylightDelta,
+ dstStart,
+ default(TransitionTime),
+ baseUtcDelta,
+ noDaylightTransitions: true);
+ rulesList.Add(r);
+ }
+ else
+ {
+ // create the AdjustmentRule that will be used for all DateTimes after the last transition
+
+ // NOTE: index == dts.Length
+ DateTime startTransitionDate = dts[index - 1];
+
+ if (!string.IsNullOrEmpty(futureTransitionsPosixFormat))
+ {
+ AdjustmentRule r = TZif_CreateAdjustmentRuleForPosixFormat(futureTransitionsPosixFormat, startTransitionDate, timeZoneBaseUtcOffset);
+ if (r != null)
+ {
+ rulesList.Add(r);
+ }
+ }
+ else
+ {
+ // just use the last transition as the rule which will be used until the end of time
+
+ TZifType transitionType = transitionTypes[typeOfLocalTime[index - 1]];
+ TimeSpan transitionOffset = TZif_CalculateTransitionOffsetFromBase(transitionType.UtcOffset, timeZoneBaseUtcOffset);
+ TimeSpan daylightDelta = transitionType.IsDst ? transitionOffset : TimeSpan.Zero;
+ TimeSpan baseUtcDelta = transitionType.IsDst ? TimeSpan.Zero : transitionOffset;
+
+ AdjustmentRule r = AdjustmentRule.CreateAdjustmentRule(
+ startTransitionDate,
+ DateTime.MaxValue,
+ daylightDelta,
+ default(TransitionTime),
+ default(TransitionTime),
+ baseUtcDelta,
+ noDaylightTransitions: true);
+ rulesList.Add(r);
+ }
+ }
+
+ index++;
+ }
+
+ private static TimeSpan TZif_CalculateTransitionOffsetFromBase(TimeSpan transitionOffset, TimeSpan timeZoneBaseUtcOffset)
+ {
+ TimeSpan result = transitionOffset - timeZoneBaseUtcOffset;
+
+ // TZif supports seconds-level granularity with offsets but TimeZoneInfo only supports minutes since it aligns
+ // with DateTimeOffset, SQL Server, and the W3C XML Specification
+ if (result.Ticks % TimeSpan.TicksPerMinute != 0)
+ {
+ result = new TimeSpan(result.Hours, result.Minutes, 0);
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// Gets the first standard-time transition type, or simply the first transition type
+ /// if there are no standard transition types.
+ /// </summary>>
+ /// <remarks>
+ /// from 'man tzfile':
+ /// localtime(3) uses the first standard-time ttinfo structure in the file
+ /// (or simply the first ttinfo structure in the absence of a standard-time
+ /// structure) if either tzh_timecnt is zero or the time argument is less
+ /// than the first transition time recorded in the file.
+ /// </remarks>
+ private static TZifType TZif_GetEarlyDateTransitionType(TZifType[] transitionTypes)
+ {
+ foreach (TZifType transitionType in transitionTypes)
+ {
+ if (!transitionType.IsDst)
+ {
+ return transitionType;
+ }
+ }
+
+ if (transitionTypes.Length > 0)
+ {
+ return transitionTypes[0];
+ }
+
+ throw new InvalidTimeZoneException(SR.InvalidTimeZone_NoTTInfoStructures);
+ }
+
+ /// <summary>
+ /// Creates an AdjustmentRule given the POSIX TZ environment variable string.
+ /// </summary>
+ /// <remarks>
+ /// See http://man7.org/linux/man-pages/man3/tzset.3.html for the format and semantics of this POSX string.
+ /// </remarks>
+ private static AdjustmentRule TZif_CreateAdjustmentRuleForPosixFormat(string posixFormat, DateTime startTransitionDate, TimeSpan timeZoneBaseUtcOffset)
+ {
+ string standardName;
+ string standardOffset;
+ string daylightSavingsName;
+ string daylightSavingsOffset;
+ string start;
+ string startTime;
+ string end;
+ string endTime;
+
+ if (TZif_ParsePosixFormat(posixFormat, out standardName, out standardOffset, out daylightSavingsName,
+ out daylightSavingsOffset, out start, out startTime, out end, out endTime))
+ {
+ // a valid posixFormat has at least standardName and standardOffset
+
+ TimeSpan? parsedBaseOffset = TZif_ParseOffsetString(standardOffset);
+ if (parsedBaseOffset.HasValue)
+ {
+ TimeSpan baseOffset = parsedBaseOffset.Value.Negate(); // offsets are backwards in POSIX notation
+ baseOffset = TZif_CalculateTransitionOffsetFromBase(baseOffset, timeZoneBaseUtcOffset);
+
+ // having a daylightSavingsName means there is a DST rule
+ if (!string.IsNullOrEmpty(daylightSavingsName))
+ {
+ TimeSpan? parsedDaylightSavings = TZif_ParseOffsetString(daylightSavingsOffset);
+ TimeSpan daylightSavingsTimeSpan;
+ if (!parsedDaylightSavings.HasValue)
+ {
+ // default DST to 1 hour if it isn't specified
+ daylightSavingsTimeSpan = new TimeSpan(1, 0, 0);
+ }
+ else
+ {
+ daylightSavingsTimeSpan = parsedDaylightSavings.Value.Negate(); // offsets are backwards in POSIX notation
+ daylightSavingsTimeSpan = TZif_CalculateTransitionOffsetFromBase(daylightSavingsTimeSpan, timeZoneBaseUtcOffset);
+ daylightSavingsTimeSpan = TZif_CalculateTransitionOffsetFromBase(daylightSavingsTimeSpan, baseOffset);
+ }
+
+ TransitionTime dstStart = TZif_CreateTransitionTimeFromPosixRule(start, startTime);
+ TransitionTime dstEnd = TZif_CreateTransitionTimeFromPosixRule(end, endTime);
+
+ return AdjustmentRule.CreateAdjustmentRule(
+ startTransitionDate,
+ DateTime.MaxValue,
+ daylightSavingsTimeSpan,
+ dstStart,
+ dstEnd,
+ baseOffset,
+ noDaylightTransitions: false);
+ }
+ else
+ {
+ // if there is no daylightSavingsName, the whole AdjustmentRule should be with no transitions - just the baseOffset
+ return AdjustmentRule.CreateAdjustmentRule(
+ startTransitionDate,
+ DateTime.MaxValue,
+ TimeSpan.Zero,
+ default(TransitionTime),
+ default(TransitionTime),
+ baseOffset,
+ noDaylightTransitions: true);
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private static TimeSpan? TZif_ParseOffsetString(string offset)
+ {
+ TimeSpan? result = null;
+
+ if (!string.IsNullOrEmpty(offset))
+ {
+ bool negative = offset[0] == '-';
+ if (negative || offset[0] == '+')
+ {
+ offset = offset.Substring(1);
+ }
+
+ // Try parsing just hours first.
+ // Note, TimeSpan.TryParseExact "%h" can't be used here because some time zones using values
+ // like "26" or "144" and TimeSpan parsing would turn that into 26 or 144 *days* instead of hours.
+ int hours;
+ if (int.TryParse(offset, out hours))
+ {
+ result = new TimeSpan(hours, 0, 0);
+ }
+ else
+ {
+ TimeSpan parsedTimeSpan;
+ if (TimeSpan.TryParseExact(offset, "g", CultureInfo.InvariantCulture, out parsedTimeSpan))
+ {
+ result = parsedTimeSpan;
+ }
+ }
+
+ if (result.HasValue && negative)
+ {
+ result = result.Value.Negate();
+ }
+ }
+
+ return result;
+ }
+
+ private static TransitionTime TZif_CreateTransitionTimeFromPosixRule(string date, string time)
+ {
+ if (string.IsNullOrEmpty(date))
+ {
+ return default(TransitionTime);
+ }
+
+ if (date[0] == 'M')
+ {
+ // Mm.w.d
+ // This specifies day d of week w of month m. The day d must be between 0(Sunday) and 6.The week w must be between 1 and 5;
+ // week 1 is the first week in which day d occurs, and week 5 specifies the last d day in the month. The month m should be between 1 and 12.
+
+ int month;
+ int week;
+ DayOfWeek day;
+ if (!TZif_ParseMDateRule(date, out month, out week, out day))
+ {
+ throw new InvalidTimeZoneException(SR.Format(SR.InvalidTimeZone_UnparseablePosixMDateString, date));
+ }
+
+ DateTime timeOfDay;
+ TimeSpan? timeOffset = TZif_ParseOffsetString(time);
+ if (timeOffset.HasValue)
+ {
+ // This logic isn't correct and can't be corrected until https://github.com/dotnet/corefx/issues/2618 is fixed.
+ // Some time zones use time values like, "26", "144", or "-2".
+ // This allows the week to sometimes be week 4 and sometimes week 5 in the month.
+ // For now, strip off any 'days' in the offset, and just get the time of day correct
+ timeOffset = new TimeSpan(timeOffset.Value.Hours, timeOffset.Value.Minutes, timeOffset.Value.Seconds);
+ if (timeOffset.Value < TimeSpan.Zero)
+ {
+ timeOfDay = new DateTime(1, 1, 2, 0, 0, 0);
+ }
+ else
+ {
+ timeOfDay = new DateTime(1, 1, 1, 0, 0, 0);
+ }
+
+ timeOfDay += timeOffset.Value;
+ }
+ else
+ {
+ // default to 2AM.
+ timeOfDay = new DateTime(1, 1, 1, 2, 0, 0);
+ }
+
+ return TransitionTime.CreateFloatingDateRule(timeOfDay, month, week, day);
+ }
+ else
+ {
+ // Jn
+ // This specifies the Julian day, with n between 1 and 365.February 29 is never counted, even in leap years.
+
+ // n
+ // This specifies the Julian day, with n between 0 and 365.February 29 is counted in leap years.
+
+ // These two rules cannot be expressed with the current AdjustmentRules
+ // One of them *could* be supported if we relaxed the TransitionTime validation rules, and allowed
+ // "IsFixedDateRule = true, Month = 0, Day = n" to mean the nth day of the year, picking one of the rules above
+
+ throw new InvalidTimeZoneException(SR.InvalidTimeZone_JulianDayNotSupported);
+ }
+ }
+
+ /// <summary>
+ /// Parses a string like Mm.w.d into month, week and DayOfWeek values.
+ /// </summary>
+ /// <returns>
+ /// true if the parsing succeeded; otherwise, false.
+ /// </returns>
+ private static bool TZif_ParseMDateRule(string dateRule, out int month, out int week, out DayOfWeek dayOfWeek)
+ {
+ if (dateRule[0] == 'M')
+ {
+ int firstDotIndex = dateRule.IndexOf('.');
+ if (firstDotIndex > 0)
+ {
+ int secondDotIndex = dateRule.IndexOf('.', firstDotIndex + 1);
+ if (secondDotIndex > 0)
+ {
+ if (int.TryParse(dateRule.AsSpan(1, firstDotIndex - 1), out month) &&
+ int.TryParse(dateRule.AsSpan(firstDotIndex + 1, secondDotIndex - firstDotIndex - 1), out week) &&
+ int.TryParse(dateRule.AsSpan(secondDotIndex + 1), out int day))
+ {
+ dayOfWeek = (DayOfWeek)day;
+ return true;
+ }
+ }
+ }
+ }
+
+ month = 0;
+ week = 0;
+ dayOfWeek = default(DayOfWeek);
+ return false;
+ }
+
+ private static bool TZif_ParsePosixFormat(
+ string posixFormat,
+ out string standardName,
+ out string standardOffset,
+ out string daylightSavingsName,
+ out string daylightSavingsOffset,
+ out string start,
+ out string startTime,
+ out string end,
+ out string endTime)
+ {
+ standardName = null;
+ standardOffset = null;
+ daylightSavingsName = null;
+ daylightSavingsOffset = null;
+ start = null;
+ startTime = null;
+ end = null;
+ endTime = null;
+
+ int index = 0;
+ standardName = TZif_ParsePosixName(posixFormat, ref index);
+ standardOffset = TZif_ParsePosixOffset(posixFormat, ref index);
+
+ daylightSavingsName = TZif_ParsePosixName(posixFormat, ref index);
+ if (!string.IsNullOrEmpty(daylightSavingsName))
+ {
+ daylightSavingsOffset = TZif_ParsePosixOffset(posixFormat, ref index);
+
+ if (index < posixFormat.Length && posixFormat[index] == ',')
+ {
+ index++;
+ TZif_ParsePosixDateTime(posixFormat, ref index, out start, out startTime);
+
+ if (index < posixFormat.Length && posixFormat[index] == ',')
+ {
+ index++;
+ TZif_ParsePosixDateTime(posixFormat, ref index, out end, out endTime);
+ }
+ }
+ }
+
+ return !string.IsNullOrEmpty(standardName) && !string.IsNullOrEmpty(standardOffset);
+ }
+
+ private static string TZif_ParsePosixName(string posixFormat, ref int index)
+ {
+ bool isBracketEnclosed = index < posixFormat.Length && posixFormat[index] == '<';
+ if (isBracketEnclosed)
+ {
+ // move past the opening bracket
+ index++;
+
+ string result = TZif_ParsePosixString(posixFormat, ref index, c => c == '>');
+
+ // move past the closing bracket
+ if (index < posixFormat.Length && posixFormat[index] == '>')
+ {
+ index++;
+ }
+
+ return result;
+ }
+ else
+ {
+ return TZif_ParsePosixString(
+ posixFormat,
+ ref index,
+ c => char.IsDigit(c) || c == '+' || c == '-' || c == ',');
+ }
+ }
+
+ private static string TZif_ParsePosixOffset(string posixFormat, ref int index) =>
+ TZif_ParsePosixString(posixFormat, ref index, c => !char.IsDigit(c) && c != '+' && c != '-' && c != ':');
+
+ private static void TZif_ParsePosixDateTime(string posixFormat, ref int index, out string date, out string time)
+ {
+ time = null;
+
+ date = TZif_ParsePosixDate(posixFormat, ref index);
+ if (index < posixFormat.Length && posixFormat[index] == '/')
+ {
+ index++;
+ time = TZif_ParsePosixTime(posixFormat, ref index);
+ }
+ }
+
+ private static string TZif_ParsePosixDate(string posixFormat, ref int index) =>
+ TZif_ParsePosixString(posixFormat, ref index, c => c == '/' || c == ',');
+
+ private static string TZif_ParsePosixTime(string posixFormat, ref int index) =>
+ TZif_ParsePosixString(posixFormat, ref index, c => c == ',');
+
+ private static string TZif_ParsePosixString(string posixFormat, ref int index, Func<char, bool> breakCondition)
+ {
+ int startIndex = index;
+ for (; index < posixFormat.Length; index++)
+ {
+ char current = posixFormat[index];
+ if (breakCondition(current))
+ {
+ break;
+ }
+ }
+
+ return posixFormat.Substring(startIndex, index - startIndex);
+ }
+
+ // Returns the Substring from zoneAbbreviations starting at index and ending at '\0'
+ // zoneAbbreviations is expected to be in the form: "PST\0PDT\0PWT\0\PPT"
+ private static string TZif_GetZoneAbbreviation(string zoneAbbreviations, int index)
+ {
+ int lastIndex = zoneAbbreviations.IndexOf('\0', index);
+ return lastIndex > 0 ?
+ zoneAbbreviations.Substring(index, lastIndex - index) :
+ zoneAbbreviations.Substring(index);
+ }
+
+ // Converts an array of bytes into an int - always using standard byte order (Big Endian)
+ // per TZif file standard
+ private static unsafe int TZif_ToInt32(byte[] value, int startIndex)
+ {
+ fixed (byte* pbyte = &value[startIndex])
+ {
+ return (*pbyte << 24) | (*(pbyte + 1) << 16) | (*(pbyte + 2) << 8) | (*(pbyte + 3));
+ }
+ }
+
+ // Converts an array of bytes into a long - always using standard byte order (Big Endian)
+ // per TZif file standard
+ private static unsafe long TZif_ToInt64(byte[] value, int startIndex)
+ {
+ fixed (byte* pbyte = &value[startIndex])
+ {
+ int i1 = (*pbyte << 24) | (*(pbyte + 1) << 16) | (*(pbyte + 2) << 8) | (*(pbyte + 3));
+ int i2 = (*(pbyte + 4) << 24) | (*(pbyte + 5) << 16) | (*(pbyte + 6) << 8) | (*(pbyte + 7));
+ return (uint)i2 | ((long)i1 << 32);
+ }
+ }
+
+ private static long TZif_ToUnixTime(byte[] value, int startIndex, TZVersion version) =>
+ version != TZVersion.V1 ?
+ TZif_ToInt64(value, startIndex) :
+ TZif_ToInt32(value, startIndex);
+
+ private static DateTime TZif_UnixTimeToDateTime(long unixTime) =>
+ unixTime < DateTimeOffset.UnixMinSeconds ? DateTime.MinValue :
+ unixTime > DateTimeOffset.UnixMaxSeconds ? DateTime.MaxValue :
+ DateTimeOffset.FromUnixTimeSeconds(unixTime).UtcDateTime;
+
+ private static void TZif_ParseRaw(byte[] data, out TZifHead t, out DateTime[] dts, out byte[] typeOfLocalTime, out TZifType[] transitionType,
+ out string zoneAbbreviations, out bool[] StandardTime, out bool[] GmtTime, out string futureTransitionsPosixFormat)
+ {
+ // initialize the out parameters in case the TZifHead ctor throws
+ dts = null;
+ typeOfLocalTime = null;
+ transitionType = null;
+ zoneAbbreviations = string.Empty;
+ StandardTime = null;
+ GmtTime = null;
+ futureTransitionsPosixFormat = null;
+
+ // read in the 44-byte TZ header containing the count/length fields
+ //
+ int index = 0;
+ t = new TZifHead(data, index);
+ index += TZifHead.Length;
+
+ int timeValuesLength = 4; // the first version uses 4-bytes to specify times
+ if (t.Version != TZVersion.V1)
+ {
+ // move index past the V1 information to read the V2 information
+ index += (int)((timeValuesLength * t.TimeCount) + t.TimeCount + (6 * t.TypeCount) + ((timeValuesLength + 4) * t.LeapCount) + t.IsStdCount + t.IsGmtCount + t.CharCount);
+
+ // read the V2 header
+ t = new TZifHead(data, index);
+ index += TZifHead.Length;
+ timeValuesLength = 8; // the second version uses 8-bytes
+ }
+
+ // initialize the containers for the rest of the TZ data
+ dts = new DateTime[t.TimeCount];
+ typeOfLocalTime = new byte[t.TimeCount];
+ transitionType = new TZifType[t.TypeCount];
+ zoneAbbreviations = string.Empty;
+ StandardTime = new bool[t.TypeCount];
+ GmtTime = new bool[t.TypeCount];
+
+ // read in the UTC transition points and convert them to Windows
+ //
+ for (int i = 0; i < t.TimeCount; i++)
+ {
+ long unixTime = TZif_ToUnixTime(data, index, t.Version);
+ dts[i] = TZif_UnixTimeToDateTime(unixTime);
+ index += timeValuesLength;
+ }
+
+ // read in the Type Indices; there is a 1:1 mapping of UTC transition points to Type Indices
+ // these indices directly map to the array index in the transitionType array below
+ //
+ for (int i = 0; i < t.TimeCount; i++)
+ {
+ typeOfLocalTime[i] = data[index];
+ index += 1;
+ }
+
+ // read in the Type table. Each 6-byte entry represents
+ // {UtcOffset, IsDst, AbbreviationIndex}
+ //
+ // each AbbreviationIndex is a character index into the zoneAbbreviations string below
+ //
+ for (int i = 0; i < t.TypeCount; i++)
+ {
+ transitionType[i] = new TZifType(data, index);
+ index += 6;
+ }
+
+ // read in the Abbreviation ASCII string. This string will be in the form:
+ // "PST\0PDT\0PWT\0\PPT"
+ //
+ Encoding enc = Encoding.UTF8;
+ zoneAbbreviations = enc.GetString(data, index, (int)t.CharCount);
+ index += (int)t.CharCount;
+
+ // skip ahead of the Leap-Seconds Adjustment data. In a future release, consider adding
+ // support for Leap-Seconds
+ //
+ index += (int)(t.LeapCount * (timeValuesLength + 4)); // skip the leap second transition times
+
+ // read in the Standard Time table. There should be a 1:1 mapping between Type-Index and Standard
+ // Time table entries.
+ //
+ // TRUE = transition time is standard time
+ // FALSE = transition time is wall clock time
+ // ABSENT = transition time is wall clock time
+ //
+ for (int i = 0; i < t.IsStdCount && i < t.TypeCount && index < data.Length; i++)
+ {
+ StandardTime[i] = (data[index++] != 0);
+ }
+
+ // read in the GMT Time table. There should be a 1:1 mapping between Type-Index and GMT Time table
+ // entries.
+ //
+ // TRUE = transition time is UTC
+ // FALSE = transition time is local time
+ // ABSENT = transition time is local time
+ //
+ for (int i = 0; i < t.IsGmtCount && i < t.TypeCount && index < data.Length; i++)
+ {
+ GmtTime[i] = (data[index++] != 0);
+ }
+
+ if (t.Version != TZVersion.V1)
+ {
+ // read the POSIX-style format, which should be wrapped in newlines with the last newline at the end of the file
+ if (data[index++] == '\n' && data[data.Length - 1] == '\n')
+ {
+ futureTransitionsPosixFormat = enc.GetString(data, index, data.Length - index - 1);
+ }
+ }
+ }
+
+ private struct TZifType
+ {
+ public const int Length = 6;
+
+ public readonly TimeSpan UtcOffset;
+ public readonly bool IsDst;
+ public readonly byte AbbreviationIndex;
+
+ public TZifType(byte[] data, int index)
+ {
+ if (data == null || data.Length < index + Length)
+ {
+ throw new ArgumentException(SR.Argument_TimeZoneInfoInvalidTZif, nameof(data));
+ }
+ UtcOffset = new TimeSpan(0, 0, TZif_ToInt32(data, index + 00));
+ IsDst = (data[index + 4] != 0);
+ AbbreviationIndex = data[index + 5];
+ }
+ }
+
+ private struct TZifHead
+ {
+ public const int Length = 44;
+
+ public readonly uint Magic; // TZ_MAGIC "TZif"
+ public readonly TZVersion Version; // 1 byte for a \0 or 2 or 3
+ // public byte[15] Reserved; // reserved for future use
+ public readonly uint IsGmtCount; // number of transition time flags
+ public readonly uint IsStdCount; // number of transition time flags
+ public readonly uint LeapCount; // number of leap seconds
+ public readonly uint TimeCount; // number of transition times
+ public readonly uint TypeCount; // number of local time types
+ public readonly uint CharCount; // number of abbreviated characters
+
+ public TZifHead(byte[] data, int index)
+ {
+ if (data == null || data.Length < Length)
+ {
+ throw new ArgumentException("bad data", nameof(data));
+ }
+
+ Magic = (uint)TZif_ToInt32(data, index + 00);
+
+ if (Magic != 0x545A6966)
+ {
+ // 0x545A6966 = {0x54, 0x5A, 0x69, 0x66} = "TZif"
+ throw new ArgumentException(SR.Argument_TimeZoneInfoBadTZif, nameof(data));
+ }
+
+ byte version = data[index + 04];
+ Version =
+ version == '2' ? TZVersion.V2 :
+ version == '3' ? TZVersion.V3 :
+ TZVersion.V1; // default/fallback to V1 to guard against future, unsupported version numbers
+
+ // skip the 15 byte reserved field
+
+ // don't use the BitConverter class which parses data
+ // based on the Endianess of the machine architecture.
+ // this data is expected to always be in "standard byte order",
+ // regardless of the machine it is being processed on.
+
+ IsGmtCount = (uint)TZif_ToInt32(data, index + 20);
+ IsStdCount = (uint)TZif_ToInt32(data, index + 24);
+ LeapCount = (uint)TZif_ToInt32(data, index + 28);
+ TimeCount = (uint)TZif_ToInt32(data, index + 32);
+ TypeCount = (uint)TZif_ToInt32(data, index + 36);
+ CharCount = (uint)TZif_ToInt32(data, index + 40);
+ }
+ }
+
+ private enum TZVersion : byte
+ {
+ V1 = 0,
+ V2,
+ V3,
+ // when adding more versions, ensure all the logic using TZVersion is still correct
+ }
+ }
+}
diff --git a/src/Common/src/CoreLib/System/TimeZoneInfo.Win32.cs b/src/Common/src/CoreLib/System/TimeZoneInfo.Win32.cs
new file mode 100644
index 0000000000..03f54a5432
--- /dev/null
+++ b/src/Common/src/CoreLib/System/TimeZoneInfo.Win32.cs
@@ -0,0 +1,999 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Security;
+using System.Text;
+using System.Threading;
+
+using Microsoft.Win32;
+using Microsoft.Win32.SafeHandles;
+
+using Internal.Runtime.CompilerServices;
+
+using REG_TZI_FORMAT = Interop.Kernel32.REG_TZI_FORMAT;
+using TIME_ZONE_INFORMATION = Interop.Kernel32.TIME_ZONE_INFORMATION;
+using TIME_DYNAMIC_ZONE_INFORMATION = Interop.Kernel32.TIME_DYNAMIC_ZONE_INFORMATION;
+
+namespace System
+{
+ public sealed partial class TimeZoneInfo
+ {
+ // registry constants for the 'Time Zones' hive
+ //
+ private const string TimeZonesRegistryHive = @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones";
+ private const string DisplayValue = "Display";
+ private const string DaylightValue = "Dlt";
+ private const string StandardValue = "Std";
+ private const string MuiDisplayValue = "MUI_Display";
+ private const string MuiDaylightValue = "MUI_Dlt";
+ private const string MuiStandardValue = "MUI_Std";
+ private const string TimeZoneInfoValue = "TZI";
+ private const string FirstEntryValue = "FirstEntry";
+ private const string LastEntryValue = "LastEntry";
+
+ private const int MaxKeyLength = 255;
+
+#pragma warning disable 0420
+ private sealed partial class CachedData
+ {
+ private static TimeZoneInfo GetCurrentOneYearLocal()
+ {
+ // load the data from the OS
+ TIME_ZONE_INFORMATION timeZoneInformation;
+ uint result = Interop.Kernel32.GetTimeZoneInformation(out timeZoneInformation);
+ return result == Interop.Kernel32.TIME_ZONE_ID_INVALID ?
+ CreateCustomTimeZone(LocalId, TimeSpan.Zero, LocalId, LocalId) :
+ GetLocalTimeZoneFromWin32Data(timeZoneInformation, dstDisabled: false);
+ }
+
+ private volatile OffsetAndRule _oneYearLocalFromUtc;
+
+ public OffsetAndRule GetOneYearLocalFromUtc(int year)
+ {
+ OffsetAndRule oneYearLocFromUtc = _oneYearLocalFromUtc;
+ if (oneYearLocFromUtc == null || oneYearLocFromUtc.Year != year)
+ {
+ TimeZoneInfo currentYear = GetCurrentOneYearLocal();
+ AdjustmentRule rule = currentYear._adjustmentRules == null ? null : currentYear._adjustmentRules[0];
+ oneYearLocFromUtc = new OffsetAndRule(year, currentYear.BaseUtcOffset, rule);
+ _oneYearLocalFromUtc = oneYearLocFromUtc;
+ }
+ return oneYearLocFromUtc;
+ }
+ }
+#pragma warning restore 0420
+
+ private sealed class OffsetAndRule
+ {
+ public readonly int Year;
+ public readonly TimeSpan Offset;
+ public readonly AdjustmentRule Rule;
+
+ public OffsetAndRule(int year, TimeSpan offset, AdjustmentRule rule)
+ {
+ Year = year;
+ Offset = offset;
+ Rule = rule;
+ }
+ }
+
+ /// <summary>
+ /// Returns a cloned array of AdjustmentRule objects
+ /// </summary>
+ public AdjustmentRule[] GetAdjustmentRules()
+ {
+ if (_adjustmentRules == null)
+ {
+ return Array.Empty<AdjustmentRule>();
+ }
+
+ return (AdjustmentRule[])_adjustmentRules.Clone();
+ }
+
+ private static void PopulateAllSystemTimeZones(CachedData cachedData)
+ {
+ Debug.Assert(Monitor.IsEntered(cachedData));
+
+ using (RegistryKey reg = Registry.LocalMachine.OpenSubKey(TimeZonesRegistryHive, writable: false))
+ {
+ if (reg != null)
+ {
+ foreach (string keyName in reg.GetSubKeyNames())
+ {
+ TimeZoneInfo value;
+ Exception ex;
+ TryGetTimeZone(keyName, false, out value, out ex, cachedData); // populate the cache
+ }
+ }
+ }
+ }
+
+ private TimeZoneInfo(in TIME_ZONE_INFORMATION zone, bool dstDisabled)
+ {
+ string standardName = zone.GetStandardName();
+ if (standardName.Length == 0)
+ {
+ _id = LocalId; // the ID must contain at least 1 character - initialize _id to "Local"
+ }
+ else
+ {
+ _id = standardName;
+ }
+ _baseUtcOffset = new TimeSpan(0, -(zone.Bias), 0);
+
+ if (!dstDisabled)
+ {
+ // only create the adjustment rule if DST is enabled
+ REG_TZI_FORMAT regZone = new REG_TZI_FORMAT(zone);
+ AdjustmentRule rule = CreateAdjustmentRuleFromTimeZoneInformation(regZone, DateTime.MinValue.Date, DateTime.MaxValue.Date, zone.Bias);
+ if (rule != null)
+ {
+ _adjustmentRules = new[] { rule };
+ }
+ }
+
+ ValidateTimeZoneInfo(_id, _baseUtcOffset, _adjustmentRules, out _supportsDaylightSavingTime);
+ _displayName = standardName;
+ _standardDisplayName = standardName;
+ _daylightDisplayName = zone.GetDaylightName();
+ }
+
+ /// <summary>
+ /// Helper function to check if the current TimeZoneInformation struct does not support DST.
+ /// This check returns true when the DaylightDate == StandardDate.
+ /// This check is only meant to be used for "Local".
+ /// </summary>
+ private static bool CheckDaylightSavingTimeNotSupported(in TIME_ZONE_INFORMATION timeZone) =>
+ timeZone.DaylightDate.Equals(timeZone.StandardDate);
+
+ /// <summary>
+ /// Converts a REG_TZI_FORMAT struct to an AdjustmentRule.
+ /// </summary>
+ private static AdjustmentRule CreateAdjustmentRuleFromTimeZoneInformation(in REG_TZI_FORMAT timeZoneInformation, DateTime startDate, DateTime endDate, int defaultBaseUtcOffset)
+ {
+ bool supportsDst = timeZoneInformation.StandardDate.Month != 0;
+
+ if (!supportsDst)
+ {
+ if (timeZoneInformation.Bias == defaultBaseUtcOffset)
+ {
+ // this rule will not contain any information to be used to adjust dates. just ignore it
+ return null;
+ }
+
+ return AdjustmentRule.CreateAdjustmentRule(
+ startDate,
+ endDate,
+ TimeSpan.Zero, // no daylight saving transition
+ TransitionTime.CreateFixedDateRule(DateTime.MinValue, 1, 1),
+ TransitionTime.CreateFixedDateRule(DateTime.MinValue.AddMilliseconds(1), 1, 1),
+ new TimeSpan(0, defaultBaseUtcOffset - timeZoneInformation.Bias, 0), // Bias delta is all what we need from this rule
+ noDaylightTransitions: false);
+ }
+
+ //
+ // Create an AdjustmentRule with TransitionTime objects
+ //
+ TransitionTime daylightTransitionStart;
+ if (!TransitionTimeFromTimeZoneInformation(timeZoneInformation, out daylightTransitionStart, readStartDate: true))
+ {
+ return null;
+ }
+
+ TransitionTime daylightTransitionEnd;
+ if (!TransitionTimeFromTimeZoneInformation(timeZoneInformation, out daylightTransitionEnd, readStartDate: false))
+ {
+ return null;
+ }
+
+ if (daylightTransitionStart.Equals(daylightTransitionEnd))
+ {
+ // this happens when the time zone does support DST but the OS has DST disabled
+ return null;
+ }
+
+ return AdjustmentRule.CreateAdjustmentRule(
+ startDate,
+ endDate,
+ new TimeSpan(0, -timeZoneInformation.DaylightBias, 0),
+ daylightTransitionStart,
+ daylightTransitionEnd,
+ new TimeSpan(0, defaultBaseUtcOffset - timeZoneInformation.Bias, 0),
+ noDaylightTransitions: false);
+ }
+
+ /// <summary>
+ /// Helper function that searches the registry for a time zone entry
+ /// that matches the TimeZoneInformation struct.
+ /// </summary>
+ private static string FindIdFromTimeZoneInformation(in TIME_ZONE_INFORMATION timeZone, out bool dstDisabled)
+ {
+ dstDisabled = false;
+
+ using (RegistryKey key = Registry.LocalMachine.OpenSubKey(TimeZonesRegistryHive, writable: false))
+ {
+ if (key == null)
+ {
+ return null;
+ }
+
+ foreach (string keyName in key.GetSubKeyNames())
+ {
+ if (TryCompareTimeZoneInformationToRegistry(timeZone, keyName, out dstDisabled))
+ {
+ return keyName;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Helper function for retrieving the local system time zone.
+ /// May throw COMException, TimeZoneNotFoundException, InvalidTimeZoneException.
+ /// Assumes cachedData lock is taken.
+ /// </summary>
+ /// <returns>A new TimeZoneInfo instance.</returns>
+ private static TimeZoneInfo GetLocalTimeZone(CachedData cachedData)
+ {
+ Debug.Assert(Monitor.IsEntered(cachedData));
+
+ //
+ // Try using the "kernel32!GetDynamicTimeZoneInformation" API to get the "id"
+ //
+ var dynamicTimeZoneInformation = new TIME_DYNAMIC_ZONE_INFORMATION();
+
+ // call kernel32!GetDynamicTimeZoneInformation...
+ uint result = Interop.Kernel32.GetDynamicTimeZoneInformation(out dynamicTimeZoneInformation);
+ if (result == Interop.Kernel32.TIME_ZONE_ID_INVALID)
+ {
+ // return a dummy entry
+ return CreateCustomTimeZone(LocalId, TimeSpan.Zero, LocalId, LocalId);
+ }
+
+ // check to see if we can use the key name returned from the API call
+ string dynamicTimeZoneKeyName = dynamicTimeZoneInformation.GetTimeZoneKeyName();
+ if (dynamicTimeZoneKeyName.Length != 0)
+ {
+ TimeZoneInfo zone;
+ Exception ex;
+
+ if (TryGetTimeZone(dynamicTimeZoneKeyName, dynamicTimeZoneInformation.DynamicDaylightTimeDisabled != 0, out zone, out ex, cachedData) == TimeZoneInfoResult.Success)
+ {
+ // successfully loaded the time zone from the registry
+ return zone;
+ }
+ }
+
+ var timeZoneInformation = new TIME_ZONE_INFORMATION(dynamicTimeZoneInformation);
+
+ // the key name was not returned or it pointed to a bogus entry - search for the entry ourselves
+ string id = FindIdFromTimeZoneInformation(timeZoneInformation, out bool dstDisabled);
+
+ if (id != null)
+ {
+ TimeZoneInfo zone;
+ Exception ex;
+ if (TryGetTimeZone(id, dstDisabled, out zone, out ex, cachedData) == TimeZoneInfoResult.Success)
+ {
+ // successfully loaded the time zone from the registry
+ return zone;
+ }
+ }
+
+ // We could not find the data in the registry. Fall back to using
+ // the data from the Win32 API
+ return GetLocalTimeZoneFromWin32Data(timeZoneInformation, dstDisabled);
+ }
+
+ /// <summary>
+ /// Helper function used by 'GetLocalTimeZone()' - this function wraps a bunch of
+ /// try/catch logic for handling the TimeZoneInfo private constructor that takes
+ /// a TIME_ZONE_INFORMATION structure.
+ /// </summary>
+ private static TimeZoneInfo GetLocalTimeZoneFromWin32Data(in TIME_ZONE_INFORMATION timeZoneInformation, bool dstDisabled)
+ {
+ // first try to create the TimeZoneInfo with the original 'dstDisabled' flag
+ try
+ {
+ return new TimeZoneInfo(timeZoneInformation, dstDisabled);
+ }
+ catch (ArgumentException) { }
+ catch (InvalidTimeZoneException) { }
+
+ // if 'dstDisabled' was false then try passing in 'true' as a last ditch effort
+ if (!dstDisabled)
+ {
+ try
+ {
+ return new TimeZoneInfo(timeZoneInformation, dstDisabled: true);
+ }
+ catch (ArgumentException) { }
+ catch (InvalidTimeZoneException) { }
+ }
+
+ // the data returned from Windows is completely bogus; return a dummy entry
+ return CreateCustomTimeZone(LocalId, TimeSpan.Zero, LocalId, LocalId);
+ }
+
+ /// <summary>
+ /// Helper function for retrieving a TimeZoneInfo object by <time_zone_name>.
+ /// This function wraps the logic necessary to keep the private
+ /// SystemTimeZones cache in working order
+ ///
+ /// This function will either return a valid TimeZoneInfo instance or
+ /// it will throw 'InvalidTimeZoneException' / 'TimeZoneNotFoundException'.
+ /// </summary>
+ public static TimeZoneInfo FindSystemTimeZoneById(string id)
+ {
+ // Special case for Utc as it will not exist in the dictionary with the rest
+ // of the system time zones. There is no need to do this check for Local.Id
+ // since Local is a real time zone that exists in the dictionary cache
+ if (string.Equals(id, UtcId, StringComparison.OrdinalIgnoreCase))
+ {
+ return Utc;
+ }
+
+ if (id == null)
+ {
+ throw new ArgumentNullException(nameof(id));
+ }
+ if (id.Length == 0 || id.Length > MaxKeyLength || id.Contains('\0'))
+ {
+ throw new TimeZoneNotFoundException(SR.Format(SR.TimeZoneNotFound_MissingData, id));
+ }
+
+ TimeZoneInfo value;
+ Exception e;
+
+ TimeZoneInfoResult result;
+
+ CachedData cachedData = s_cachedData;
+
+ lock (cachedData)
+ {
+ result = TryGetTimeZone(id, false, out value, out e, cachedData);
+ }
+
+ if (result == TimeZoneInfoResult.Success)
+ {
+ return value;
+ }
+ else if (result == TimeZoneInfoResult.InvalidTimeZoneException)
+ {
+ throw new InvalidTimeZoneException(SR.Format(SR.InvalidTimeZone_InvalidRegistryData, id), e);
+ }
+ else if (result == TimeZoneInfoResult.SecurityException)
+ {
+ throw new SecurityException(SR.Format(SR.Security_CannotReadRegistryData, id), e);
+ }
+ else
+ {
+ throw new TimeZoneNotFoundException(SR.Format(SR.TimeZoneNotFound_MissingData, id), e);
+ }
+ }
+
+ // DateTime.Now fast path that avoids allocating an historically accurate TimeZoneInfo.Local and just creates a 1-year (current year) accurate time zone
+ internal static TimeSpan GetDateTimeNowUtcOffsetFromUtc(DateTime time, out bool isAmbiguousLocalDst)
+ {
+ bool isDaylightSavings = false;
+ isAmbiguousLocalDst = false;
+ TimeSpan baseOffset;
+ int timeYear = time.Year;
+
+ OffsetAndRule match = s_cachedData.GetOneYearLocalFromUtc(timeYear);
+ baseOffset = match.Offset;
+
+ if (match.Rule != null)
+ {
+ baseOffset = baseOffset + match.Rule.BaseUtcOffsetDelta;
+ if (match.Rule.HasDaylightSaving)
+ {
+ isDaylightSavings = GetIsDaylightSavingsFromUtc(time, timeYear, match.Offset, match.Rule, null, out isAmbiguousLocalDst, Local);
+ baseOffset += (isDaylightSavings ? match.Rule.DaylightDelta : TimeSpan.Zero /* FUTURE: rule.StandardDelta */);
+ }
+ }
+ return baseOffset;
+ }
+
+ /// <summary>
+ /// Converts a REG_TZI_FORMAT struct to a TransitionTime
+ /// - When the argument 'readStart' is true the corresponding daylightTransitionTimeStart field is read
+ /// - When the argument 'readStart' is false the corresponding dayightTransitionTimeEnd field is read
+ /// </summary>
+ private static bool TransitionTimeFromTimeZoneInformation(in REG_TZI_FORMAT timeZoneInformation, out TransitionTime transitionTime, bool readStartDate)
+ {
+ //
+ // SYSTEMTIME -
+ //
+ // If the time zone does not support daylight saving time or if the caller needs
+ // to disable daylight saving time, the wMonth member in the SYSTEMTIME structure
+ // must be zero. If this date is specified, the DaylightDate value in the
+ // TIME_ZONE_INFORMATION structure must also be specified. Otherwise, the system
+ // assumes the time zone data is invalid and no changes will be applied.
+ //
+ bool supportsDst = (timeZoneInformation.StandardDate.Month != 0);
+
+ if (!supportsDst)
+ {
+ transitionTime = default(TransitionTime);
+ return false;
+ }
+
+ //
+ // SYSTEMTIME -
+ //
+ // * FixedDateRule -
+ // If the Year member is not zero, the transition date is absolute; it will only occur one time
+ //
+ // * FloatingDateRule -
+ // To select the correct day in the month, set the Year member to zero, the Hour and Minute
+ // members to the transition time, the DayOfWeek member to the appropriate weekday, and the
+ // Day member to indicate the occurence of the day of the week within the month (first through fifth).
+ //
+ // Using this notation, specify the 2:00a.m. on the first Sunday in April as follows:
+ // Hour = 2,
+ // Month = 4,
+ // DayOfWeek = 0,
+ // Day = 1.
+ //
+ // Specify 2:00a.m. on the last Thursday in October as follows:
+ // Hour = 2,
+ // Month = 10,
+ // DayOfWeek = 4,
+ // Day = 5.
+ //
+ if (readStartDate)
+ {
+ //
+ // read the "daylightTransitionStart"
+ //
+ if (timeZoneInformation.DaylightDate.Year == 0)
+ {
+ transitionTime = TransitionTime.CreateFloatingDateRule(
+ new DateTime(1, /* year */
+ 1, /* month */
+ 1, /* day */
+ timeZoneInformation.DaylightDate.Hour,
+ timeZoneInformation.DaylightDate.Minute,
+ timeZoneInformation.DaylightDate.Second,
+ timeZoneInformation.DaylightDate.Milliseconds),
+ timeZoneInformation.DaylightDate.Month,
+ timeZoneInformation.DaylightDate.Day, /* Week 1-5 */
+ (DayOfWeek)timeZoneInformation.DaylightDate.DayOfWeek);
+ }
+ else
+ {
+ transitionTime = TransitionTime.CreateFixedDateRule(
+ new DateTime(1, /* year */
+ 1, /* month */
+ 1, /* day */
+ timeZoneInformation.DaylightDate.Hour,
+ timeZoneInformation.DaylightDate.Minute,
+ timeZoneInformation.DaylightDate.Second,
+ timeZoneInformation.DaylightDate.Milliseconds),
+ timeZoneInformation.DaylightDate.Month,
+ timeZoneInformation.DaylightDate.Day);
+ }
+ }
+ else
+ {
+ //
+ // read the "daylightTransitionEnd"
+ //
+ if (timeZoneInformation.StandardDate.Year == 0)
+ {
+ transitionTime = TransitionTime.CreateFloatingDateRule(
+ new DateTime(1, /* year */
+ 1, /* month */
+ 1, /* day */
+ timeZoneInformation.StandardDate.Hour,
+ timeZoneInformation.StandardDate.Minute,
+ timeZoneInformation.StandardDate.Second,
+ timeZoneInformation.StandardDate.Milliseconds),
+ timeZoneInformation.StandardDate.Month,
+ timeZoneInformation.StandardDate.Day, /* Week 1-5 */
+ (DayOfWeek)timeZoneInformation.StandardDate.DayOfWeek);
+ }
+ else
+ {
+ transitionTime = TransitionTime.CreateFixedDateRule(
+ new DateTime(1, /* year */
+ 1, /* month */
+ 1, /* day */
+ timeZoneInformation.StandardDate.Hour,
+ timeZoneInformation.StandardDate.Minute,
+ timeZoneInformation.StandardDate.Second,
+ timeZoneInformation.StandardDate.Milliseconds),
+ timeZoneInformation.StandardDate.Month,
+ timeZoneInformation.StandardDate.Day);
+ }
+ }
+
+ return true;
+ }
+
+ /// <summary>
+ /// Helper function that takes:
+ /// 1. A string representing a <time_zone_name> registry key name.
+ /// 2. A REG_TZI_FORMAT struct containing the default rule.
+ /// 3. An AdjustmentRule[] out-parameter.
+ /// </summary>
+ private static bool TryCreateAdjustmentRules(string id, in REG_TZI_FORMAT defaultTimeZoneInformation, out AdjustmentRule[] rules, out Exception e, int defaultBaseUtcOffset)
+ {
+ rules = null;
+ e = null;
+
+ try
+ {
+ // Optional, Dynamic Time Zone Registry Data
+ // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+ //
+ // HKLM
+ // Software
+ // Microsoft
+ // Windows NT
+ // CurrentVersion
+ // Time Zones
+ // <time_zone_name>
+ // Dynamic DST
+ // * "FirstEntry" REG_DWORD "1980"
+ // First year in the table. If the current year is less than this value,
+ // this entry will be used for DST boundaries
+ // * "LastEntry" REG_DWORD "2038"
+ // Last year in the table. If the current year is greater than this value,
+ // this entry will be used for DST boundaries"
+ // * "<year1>" REG_BINARY REG_TZI_FORMAT
+ // * "<year2>" REG_BINARY REG_TZI_FORMAT
+ // * "<year3>" REG_BINARY REG_TZI_FORMAT
+ //
+ using (RegistryKey dynamicKey = Registry.LocalMachine.OpenSubKey(TimeZonesRegistryHive + "\\" + id + "\\Dynamic DST", writable: false))
+ {
+ if (dynamicKey == null)
+ {
+ AdjustmentRule rule = CreateAdjustmentRuleFromTimeZoneInformation(
+ defaultTimeZoneInformation, DateTime.MinValue.Date, DateTime.MaxValue.Date, defaultBaseUtcOffset);
+ if (rule != null)
+ {
+ rules = new[] { rule };
+ }
+ return true;
+ }
+
+ //
+ // loop over all of the "<time_zone_name>\Dynamic DST" hive entries
+ //
+ // read FirstEntry {MinValue - (year1, 12, 31)}
+ // read MiddleEntry {(yearN, 1, 1) - (yearN, 12, 31)}
+ // read LastEntry {(yearN, 1, 1) - MaxValue }
+
+ // read the FirstEntry and LastEntry key values (ex: "1980", "2038")
+ int first = (int)dynamicKey.GetValue(FirstEntryValue, -1, RegistryValueOptions.None);
+ int last = (int)dynamicKey.GetValue(LastEntryValue, -1, RegistryValueOptions.None);
+
+ if (first == -1 || last == -1 || first > last)
+ {
+ return false;
+ }
+
+ // read the first year entry
+ REG_TZI_FORMAT dtzi;
+
+ if (!TryGetTimeZoneEntryFromRegistry(dynamicKey, first.ToString(CultureInfo.InvariantCulture), out dtzi))
+ {
+ return false;
+ }
+
+ if (first == last)
+ {
+ // there is just 1 dynamic rule for this time zone.
+ AdjustmentRule rule = CreateAdjustmentRuleFromTimeZoneInformation(dtzi, DateTime.MinValue.Date, DateTime.MaxValue.Date, defaultBaseUtcOffset);
+ if (rule != null)
+ {
+ rules = new[] { rule };
+ }
+ return true;
+ }
+
+ List<AdjustmentRule> rulesList = new List<AdjustmentRule>(1);
+
+ // there are more than 1 dynamic rules for this time zone.
+ AdjustmentRule firstRule = CreateAdjustmentRuleFromTimeZoneInformation(
+ dtzi,
+ DateTime.MinValue.Date, // MinValue
+ new DateTime(first, 12, 31), // December 31, <FirstYear>
+ defaultBaseUtcOffset);
+
+ if (firstRule != null)
+ {
+ rulesList.Add(firstRule);
+ }
+
+ // read the middle year entries
+ for (int i = first + 1; i < last; i++)
+ {
+ if (!TryGetTimeZoneEntryFromRegistry(dynamicKey, i.ToString(CultureInfo.InvariantCulture), out dtzi))
+ {
+ return false;
+ }
+ AdjustmentRule middleRule = CreateAdjustmentRuleFromTimeZoneInformation(
+ dtzi,
+ new DateTime(i, 1, 1), // January 01, <Year>
+ new DateTime(i, 12, 31), // December 31, <Year>
+ defaultBaseUtcOffset);
+
+ if (middleRule != null)
+ {
+ rulesList.Add(middleRule);
+ }
+ }
+
+ // read the last year entry
+ if (!TryGetTimeZoneEntryFromRegistry(dynamicKey, last.ToString(CultureInfo.InvariantCulture), out dtzi))
+ {
+ return false;
+ }
+ AdjustmentRule lastRule = CreateAdjustmentRuleFromTimeZoneInformation(
+ dtzi,
+ new DateTime(last, 1, 1), // January 01, <LastYear>
+ DateTime.MaxValue.Date, // MaxValue
+ defaultBaseUtcOffset);
+
+ if (lastRule != null)
+ {
+ rulesList.Add(lastRule);
+ }
+
+ // convert the List to an AdjustmentRule array
+ if (rulesList.Count != 0)
+ {
+ rules = rulesList.ToArray();
+ }
+ } // end of: using (RegistryKey dynamicKey...
+ }
+ catch (InvalidCastException ex)
+ {
+ // one of the RegistryKey.GetValue calls could not be cast to an expected value type
+ e = ex;
+ return false;
+ }
+ catch (ArgumentOutOfRangeException ex)
+ {
+ e = ex;
+ return false;
+ }
+ catch (ArgumentException ex)
+ {
+ e = ex;
+ return false;
+ }
+ return true;
+ }
+
+ private static unsafe bool TryGetTimeZoneEntryFromRegistry(RegistryKey key, string name, out REG_TZI_FORMAT dtzi)
+ {
+ byte[] regValue = key.GetValue(name, null, RegistryValueOptions.None) as byte[];
+ if (regValue == null || regValue.Length != sizeof(REG_TZI_FORMAT))
+ {
+ dtzi = default;
+ return false;
+ }
+ fixed (byte * pBytes = &regValue[0])
+ dtzi = *(REG_TZI_FORMAT *)pBytes;
+ return true;
+ }
+
+ /// <summary>
+ /// Helper function that compares the StandardBias and StandardDate portion a
+ /// TimeZoneInformation struct to a time zone registry entry.
+ /// </summary>
+ private static bool TryCompareStandardDate(in TIME_ZONE_INFORMATION timeZone, in REG_TZI_FORMAT registryTimeZoneInfo) =>
+ timeZone.Bias == registryTimeZoneInfo.Bias &&
+ timeZone.StandardBias == registryTimeZoneInfo.StandardBias &&
+ timeZone.StandardDate.Equals(registryTimeZoneInfo.StandardDate);
+
+ /// <summary>
+ /// Helper function that compares a TimeZoneInformation struct to a time zone registry entry.
+ /// </summary>
+ private static bool TryCompareTimeZoneInformationToRegistry(in TIME_ZONE_INFORMATION timeZone, string id, out bool dstDisabled)
+ {
+ dstDisabled = false;
+
+ using (RegistryKey key = Registry.LocalMachine.OpenSubKey(TimeZonesRegistryHive + "\\" + id, writable: false))
+ {
+ if (key == null)
+ {
+ return false;
+ }
+
+ REG_TZI_FORMAT registryTimeZoneInfo;
+ if (!TryGetTimeZoneEntryFromRegistry(key, TimeZoneInfoValue, out registryTimeZoneInfo))
+ {
+ return false;
+ }
+
+ //
+ // first compare the bias and standard date information between the data from the Win32 API
+ // and the data from the registry...
+ //
+ bool result = TryCompareStandardDate(timeZone, registryTimeZoneInfo);
+
+ if (!result)
+ {
+ return false;
+ }
+
+ result = dstDisabled || CheckDaylightSavingTimeNotSupported(timeZone) ||
+ //
+ // since Daylight Saving Time is not "disabled", do a straight comparision between
+ // the Win32 API data and the registry data ...
+ //
+ (timeZone.DaylightBias == registryTimeZoneInfo.DaylightBias &&
+ timeZone.DaylightDate.Equals(registryTimeZoneInfo.DaylightDate));
+
+ // Finally compare the "StandardName" string value...
+ //
+ // we do not compare "DaylightName" as this TimeZoneInformation field may contain
+ // either "StandardName" or "DaylightName" depending on the time of year and current machine settings
+ //
+ if (result)
+ {
+ string registryStandardName = key.GetValue(StandardValue, string.Empty, RegistryValueOptions.None) as string;
+ result = string.Equals(registryStandardName, timeZone.GetStandardName(), StringComparison.Ordinal);
+ }
+ return result;
+ }
+ }
+
+ /// <summary>
+ /// Helper function for retrieving a localized string resource via MUI.
+ /// The function expects a string in the form: "@resource.dll, -123"
+ ///
+ /// "resource.dll" is a language-neutral portable executable (LNPE) file in
+ /// the %windir%\system32 directory. The OS is queried to find the best-fit
+ /// localized resource file for this LNPE (ex: %windir%\system32\en-us\resource.dll.mui).
+ /// If a localized resource file exists, we LoadString resource ID "123" and
+ /// return it to our caller.
+ /// </summary>
+ private static string TryGetLocalizedNameByMuiNativeResource(string resource)
+ {
+ if (string.IsNullOrEmpty(resource))
+ {
+ return string.Empty;
+ }
+
+ // parse "@tzres.dll, -100"
+ //
+ // filePath = "C:\Windows\System32\tzres.dll"
+ // resourceId = -100
+ //
+ string[] resources = resource.Split(',');
+ if (resources.Length != 2)
+ {
+ return string.Empty;
+ }
+
+ string filePath;
+ int resourceId;
+
+ // get the path to Windows\System32
+ string system32 = Environment.SystemDirectory;
+
+ // trim the string "@tzres.dll" => "tzres.dll"
+ string tzresDll = resources[0].TrimStart('@');
+
+ try
+ {
+ filePath = Path.Combine(system32, tzresDll);
+ }
+ catch (ArgumentException)
+ {
+ // there were probably illegal characters in the path
+ return string.Empty;
+ }
+
+ if (!int.TryParse(resources[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out resourceId))
+ {
+ return string.Empty;
+ }
+ resourceId = -resourceId;
+
+ try
+ {
+ StringBuilder fileMuiPath = StringBuilderCache.Acquire(Interop.Kernel32.MAX_PATH);
+ fileMuiPath.Length = Interop.Kernel32.MAX_PATH;
+ int fileMuiPathLength = Interop.Kernel32.MAX_PATH;
+ int languageLength = 0;
+ long enumerator = 0;
+
+ bool succeeded = Interop.Kernel32.GetFileMUIPath(
+ Interop.Kernel32.MUI_PREFERRED_UI_LANGUAGES,
+ filePath, null /* language */, ref languageLength,
+ fileMuiPath, ref fileMuiPathLength, ref enumerator);
+ if (!succeeded)
+ {
+ StringBuilderCache.Release(fileMuiPath);
+ return string.Empty;
+ }
+ return TryGetLocalizedNameByNativeResource(StringBuilderCache.GetStringAndRelease(fileMuiPath), resourceId);
+ }
+ catch (EntryPointNotFoundException)
+ {
+ return string.Empty;
+ }
+ }
+
+ /// <summary>
+ /// Helper function for retrieving a localized string resource via a native resource DLL.
+ /// The function expects a string in the form: "C:\Windows\System32\en-us\resource.dll"
+ ///
+ /// "resource.dll" is a language-specific resource DLL.
+ /// If the localized resource DLL exists, LoadString(resource) is returned.
+ /// </summary>
+ private static string TryGetLocalizedNameByNativeResource(string filePath, int resource)
+ {
+ using (SafeLibraryHandle handle =
+ Interop.Kernel32.LoadLibraryEx(filePath, IntPtr.Zero, Interop.Kernel32.LOAD_LIBRARY_AS_DATAFILE))
+ {
+ if (!handle.IsInvalid)
+ {
+ const int LoadStringMaxLength = 500;
+
+ StringBuilder localizedResource = StringBuilderCache.Acquire(LoadStringMaxLength);
+
+ int result = Interop.User32.LoadString(handle, resource,
+ localizedResource, LoadStringMaxLength);
+
+ if (result != 0)
+ {
+ return StringBuilderCache.GetStringAndRelease(localizedResource);
+ }
+ }
+ }
+ return string.Empty;
+ }
+
+ /// <summary>
+ /// Helper function for retrieving the DisplayName, StandardName, and DaylightName from the registry
+ ///
+ /// The function first checks the MUI_ key-values, and if they exist, it loads the strings from the MUI
+ /// resource dll(s). When the keys do not exist, the function falls back to reading from the standard
+ /// key-values
+ /// </summary>
+ private static void GetLocalizedNamesByRegistryKey(RegistryKey key, out string displayName, out string standardName, out string daylightName)
+ {
+ displayName = string.Empty;
+ standardName = string.Empty;
+ daylightName = string.Empty;
+
+ // read the MUI_ registry keys
+ string displayNameMuiResource = key.GetValue(MuiDisplayValue, string.Empty, RegistryValueOptions.None) as string;
+ string standardNameMuiResource = key.GetValue(MuiStandardValue, string.Empty, RegistryValueOptions.None) as string;
+ string daylightNameMuiResource = key.GetValue(MuiDaylightValue, string.Empty, RegistryValueOptions.None) as string;
+
+ // try to load the strings from the native resource DLL(s)
+ if (!string.IsNullOrEmpty(displayNameMuiResource))
+ {
+ displayName = TryGetLocalizedNameByMuiNativeResource(displayNameMuiResource);
+ }
+
+ if (!string.IsNullOrEmpty(standardNameMuiResource))
+ {
+ standardName = TryGetLocalizedNameByMuiNativeResource(standardNameMuiResource);
+ }
+
+ if (!string.IsNullOrEmpty(daylightNameMuiResource))
+ {
+ daylightName = TryGetLocalizedNameByMuiNativeResource(daylightNameMuiResource);
+ }
+
+ // fallback to using the standard registry keys
+ if (string.IsNullOrEmpty(displayName))
+ {
+ displayName = key.GetValue(DisplayValue, string.Empty, RegistryValueOptions.None) as string;
+ }
+ if (string.IsNullOrEmpty(standardName))
+ {
+ standardName = key.GetValue(StandardValue, string.Empty, RegistryValueOptions.None) as string;
+ }
+ if (string.IsNullOrEmpty(daylightName))
+ {
+ daylightName = key.GetValue(DaylightValue, string.Empty, RegistryValueOptions.None) as string;
+ }
+ }
+
+ /// <summary>
+ /// Helper function that takes a string representing a <time_zone_name> registry key name
+ /// and returns a TimeZoneInfo instance.
+ /// </summary>
+ private static TimeZoneInfoResult TryGetTimeZoneFromLocalMachine(string id, out TimeZoneInfo value, out Exception e)
+ {
+ e = null;
+
+ // Standard Time Zone Registry Data
+ // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ // HKLM
+ // Software
+ // Microsoft
+ // Windows NT
+ // CurrentVersion
+ // Time Zones
+ // <time_zone_name>
+ // * STD, REG_SZ "Standard Time Name"
+ // (For OS installed zones, this will always be English)
+ // * MUI_STD, REG_SZ "@tzres.dll,-1234"
+ // Indirect string to localized resource for Standard Time,
+ // add "%windir%\system32\" after "@"
+ // * DLT, REG_SZ "Daylight Time Name"
+ // (For OS installed zones, this will always be English)
+ // * MUI_DLT, REG_SZ "@tzres.dll,-1234"
+ // Indirect string to localized resource for Daylight Time,
+ // add "%windir%\system32\" after "@"
+ // * Display, REG_SZ "Display Name like (GMT-8:00) Pacific Time..."
+ // * MUI_Display, REG_SZ "@tzres.dll,-1234"
+ // Indirect string to localized resource for the Display,
+ // add "%windir%\system32\" after "@"
+ // * TZI, REG_BINARY REG_TZI_FORMAT
+ //
+ using (RegistryKey key = Registry.LocalMachine.OpenSubKey(TimeZonesRegistryHive + "\\" + id, writable: false))
+ {
+ if (key == null)
+ {
+ value = null;
+ return TimeZoneInfoResult.TimeZoneNotFoundException;
+ }
+
+ REG_TZI_FORMAT defaultTimeZoneInformation;
+ if (!TryGetTimeZoneEntryFromRegistry(key, TimeZoneInfoValue, out defaultTimeZoneInformation))
+ {
+ // the registry value could not be cast to a byte array
+ value = null;
+ return TimeZoneInfoResult.InvalidTimeZoneException;
+ }
+
+ AdjustmentRule[] adjustmentRules;
+ if (!TryCreateAdjustmentRules(id, defaultTimeZoneInformation, out adjustmentRules, out e, defaultTimeZoneInformation.Bias))
+ {
+ value = null;
+ return TimeZoneInfoResult.InvalidTimeZoneException;
+ }
+
+ GetLocalizedNamesByRegistryKey(key, out string displayName, out string standardName, out string daylightName);
+
+ try
+ {
+ value = new TimeZoneInfo(
+ id,
+ new TimeSpan(0, -(defaultTimeZoneInformation.Bias), 0),
+ displayName,
+ standardName,
+ daylightName,
+ adjustmentRules,
+ disableDaylightSavingTime: false);
+
+ return TimeZoneInfoResult.Success;
+ }
+ catch (ArgumentException ex)
+ {
+ // TimeZoneInfo constructor can throw ArgumentException and InvalidTimeZoneException
+ value = null;
+ e = ex;
+ return TimeZoneInfoResult.InvalidTimeZoneException;
+ }
+ catch (InvalidTimeZoneException ex)
+ {
+ // TimeZoneInfo constructor can throw ArgumentException and InvalidTimeZoneException
+ value = null;
+ e = ex;
+ return TimeZoneInfoResult.InvalidTimeZoneException;
+ }
+ }
+ }
+ }
+}
diff --git a/src/Common/src/CoreLib/System/TimeZoneInfo.cs b/src/Common/src/CoreLib/System/TimeZoneInfo.cs
index f9b5ce872a..6e27376b68 100644
--- a/src/Common/src/CoreLib/System/TimeZoneInfo.cs
+++ b/src/Common/src/CoreLib/System/TimeZoneInfo.cs
@@ -1894,7 +1894,7 @@ namespace System
if (result == TimeZoneInfoResult.Success)
{
if (cachedData._systemTimeZones == null)
- cachedData._systemTimeZones = new Dictionary<string, TimeZoneInfo>();
+ cachedData._systemTimeZones = new Dictionary<string, TimeZoneInfo>(StringComparer.OrdinalIgnoreCase);
cachedData._systemTimeZones.Add(id, match);
diff --git a/src/Common/src/CoreLib/System/Type.cs b/src/Common/src/CoreLib/System/Type.cs
index a0d219ddd4..b57baa869f 100644
--- a/src/Common/src/CoreLib/System/Type.cs
+++ b/src/Common/src/CoreLib/System/Type.cs
@@ -349,7 +349,7 @@ namespace System
public static Type MakeGenericMethodParameter(int position)
{
if (position < 0)
- throw new ArgumentException(SR.ArgumentOutOfRange_MustBeNonNegNum, nameof(position));
+ throw new ArgumentException(SR.ArgumentOutOfRange_NeedNonNegNum, nameof(position));
return new SignatureGenericMethodParameterType(position);
}
diff --git a/src/Common/src/CoreLib/System/UIntPtr.cs b/src/Common/src/CoreLib/System/UIntPtr.cs
index 23750e95fa..8b2568fde1 100644
--- a/src/Common/src/CoreLib/System/UIntPtr.cs
+++ b/src/Common/src/CoreLib/System/UIntPtr.cs
@@ -20,7 +20,7 @@ namespace System
[System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public struct UIntPtr : IEquatable<UIntPtr>, ISerializable
{
- unsafe private void* _value; // Do not rename (binary serialization)
+ private unsafe void* _value; // Do not rename (binary serialization)
[Intrinsic]
public static readonly UIntPtr Zero;
@@ -77,9 +77,9 @@ namespace System
return false;
}
- unsafe bool IEquatable<UIntPtr>.Equals(UIntPtr value)
+ unsafe bool IEquatable<UIntPtr>.Equals(UIntPtr other)
{
- return _value == value._value;
+ return _value == other._value;
}
public unsafe override int GetHashCode()
diff --git a/src/Common/src/CoreLib/System/UnitySerializationHolder.cs b/src/Common/src/CoreLib/System/UnitySerializationHolder.cs
index 2f30356709..53323c32bc 100644
--- a/src/Common/src/CoreLib/System/UnitySerializationHolder.cs
+++ b/src/Common/src/CoreLib/System/UnitySerializationHolder.cs
@@ -11,12 +11,8 @@ namespace System
/// This only exists for compatibility with .NET Framework.
/// </summary>
[Serializable]
-#if CORERT
- public
-#else
- internal
-#endif
- sealed class UnitySerializationHolder : ISerializable, IObjectReference
+ // Needs to be public to support binary serialization compatibility
+ public sealed class UnitySerializationHolder : ISerializable, IObjectReference
{
internal const int NullUnity = 0x0002;
private readonly int _unityType;
diff --git a/src/Common/src/CoreLib/System/Version.cs b/src/Common/src/CoreLib/System/Version.cs
index df16be2cd2..fe086be512 100644
--- a/src/Common/src/CoreLib/System/Version.cs
+++ b/src/Common/src/CoreLib/System/Version.cs
@@ -300,7 +300,7 @@ namespace System
throw new ArgumentNullException(nameof(input));
}
- return ParseVersion(input.AsReadOnlySpan(), throwOnFailure: true);
+ return ParseVersion(input.AsSpan(), throwOnFailure: true);
}
public static Version Parse(ReadOnlySpan<char> input) =>
@@ -314,7 +314,7 @@ namespace System
return false;
}
- return (result = ParseVersion(input.AsReadOnlySpan(), throwOnFailure: false)) != null;
+ return (result = ParseVersion(input.AsSpan(), throwOnFailure: false)) != null;
}
public static bool TryParse(ReadOnlySpan<char> input, out Version result) =>
@@ -333,13 +333,15 @@ namespace System
// Find the ends of the optional minor and build portions.
// We musn't have any separators after build.
int buildEnd = -1;
- int minorEnd = input.IndexOf('.', majorEnd + 1);
+ int minorEnd = input.Slice(majorEnd + 1).IndexOf('.');
if (minorEnd != -1)
{
- buildEnd = input.IndexOf('.', minorEnd + 1);
+ minorEnd += (majorEnd + 1);
+ buildEnd = input.Slice(minorEnd + 1).IndexOf('.');
if (buildEnd != -1)
{
- if (input.IndexOf('.', buildEnd + 1) != -1)
+ buildEnd += (minorEnd + 1);
+ if (input.Slice(buildEnd + 1).IndexOf('.') != -1)
{
if (throwOnFailure) throw new ArgumentException(SR.Arg_VersionString, nameof(input));
return null;
@@ -347,10 +349,10 @@ namespace System
}
}
- int major, minor, build, revision;
+ int minor, build, revision;
// Parse the major version
- if (!TryParseComponent(input.Slice(0, majorEnd), nameof(input), throwOnFailure, out major))
+ if (!TryParseComponent(input.Slice(0, majorEnd), nameof(input), throwOnFailure, out int major))
{
return null;
}
diff --git a/src/Common/src/Interop/Linux/procfs/Interop.ProcFsStat.cs b/src/Common/src/Interop/Linux/procfs/Interop.ProcFsStat.cs
index 2b87afa3c7..a34184a8ef 100644
--- a/src/Common/src/Interop/Linux/procfs/Interop.ProcFsStat.cs
+++ b/src/Common/src/Interop/Linux/procfs/Interop.ProcFsStat.cs
@@ -21,7 +21,7 @@ internal static partial class Interop
private const string TaskDirectoryName = "/task/";
internal const string SelfExeFilePath = RootPath + "self" + ExeFileName;
- internal const string ProcUptimeFilePath = RootPath + "uptime";
+ internal const string ProcStatFilePath = RootPath + "stat";
internal struct ParsedStat
{
diff --git a/src/Common/src/Interop/OSX/Interop.CoreFoundation.CFData.cs b/src/Common/src/Interop/OSX/Interop.CoreFoundation.CFData.cs
index 5920e32038..e4eee4e078 100644
--- a/src/Common/src/Interop/OSX/Interop.CoreFoundation.CFData.cs
+++ b/src/Common/src/Interop/OSX/Interop.CoreFoundation.CFData.cs
@@ -27,7 +27,14 @@ internal static partial class Interop
try
{
cfData.DangerousAddRef(ref addedRef);
- byte[] bytes = new byte[CFDataGetLength(cfData).ToInt64()];
+ long length = CFDataGetLength(cfData).ToInt64();
+
+ if (length == 0)
+ {
+ return Array.Empty<byte>();
+ }
+
+ byte[] bytes = new byte[length];
unsafe
{
@@ -55,16 +62,20 @@ internal static partial class Interop
cfData.DangerousAddRef(ref addedRef);
long length = CFDataGetLength(cfData).ToInt64();
- if (destination.Length < length)
- {
- bytesWritten = 0;
- return false;
- }
- byte* dataBytes = CFDataGetBytePtr(cfData);
- fixed (byte* destinationPtr = &MemoryMarshal.GetReference(destination))
+ if (length > 0)
{
- Buffer.MemoryCopy(dataBytes, destinationPtr, destination.Length, length);
+ if (destination.Length < length)
+ {
+ bytesWritten = 0;
+ return false;
+ }
+
+ byte* dataBytes = CFDataGetBytePtr(cfData);
+ fixed (byte* destinationPtr = &MemoryMarshal.GetReference(destination))
+ {
+ Buffer.MemoryCopy(dataBytes, destinationPtr, destination.Length, length);
+ }
}
bytesWritten = (int)length;
diff --git a/src/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.KeyAgree.cs b/src/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.KeyAgree.cs
new file mode 100644
index 0000000000..e213670a95
--- /dev/null
+++ b/src/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.KeyAgree.cs
@@ -0,0 +1,61 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Apple;
+using Microsoft.Win32.SafeHandles;
+
+internal static partial class Interop
+{
+ internal static partial class AppleCrypto
+ {
+ [DllImport(Libraries.AppleCryptoNative)]
+ private static extern int AppleCryptoNative_EcdhKeyAgree(
+ SafeSecKeyRefHandle privateKey,
+ SafeSecKeyRefHandle publicKey,
+ out SafeCFDataHandle cfDataOut,
+ out SafeCFErrorHandle cfErrorOut);
+
+ internal static byte[] EcdhKeyAgree(
+ SafeSecKeyRefHandle privateKey,
+ SafeSecKeyRefHandle publicKey,
+ Span<byte> opportunisticDestination,
+ out int bytesWritten)
+ {
+ const int Success = 1;
+ const int kErrorSeeError = -2;
+
+ SafeCFDataHandle data;
+ SafeCFErrorHandle error;
+
+ int status = AppleCryptoNative_EcdhKeyAgree(privateKey, publicKey, out data, out error);
+
+ using (data)
+ using (error)
+ {
+ if (status == kErrorSeeError)
+ {
+ throw CreateExceptionForCFError(error);
+ }
+
+ if (status == Success && !data.IsInvalid)
+ {
+ if (CoreFoundation.TryCFWriteData(data, opportunisticDestination, out bytesWritten))
+ {
+ return null;
+ }
+
+ bytesWritten = 0;
+ return CoreFoundation.CFGetData(data);
+ }
+
+ Debug.Fail($"Unexpected status ({status})");
+ throw new CryptographicException();
+ }
+ }
+ }
+}
diff --git a/src/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.RSA.cs b/src/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.RSA.cs
index 1c99e6c5e6..17349f0cad 100644
--- a/src/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.RSA.cs
+++ b/src/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.RSA.cs
@@ -21,6 +21,38 @@ internal static partial class Interop
out SafeSecKeyRefHandle pPrivateKey,
out int pOSStatus);
+ [DllImport(Libraries.AppleCryptoNative)]
+ private static extern int AppleCryptoNative_RsaSignaturePrimitive(
+ SafeSecKeyRefHandle privateKey,
+ ref byte pbData,
+ int cbData,
+ out SafeCFDataHandle pDataOut,
+ out SafeCFErrorHandle pErrorOut);
+
+ [DllImport(Libraries.AppleCryptoNative)]
+ private static extern int AppleCryptoNative_RsaVerificationPrimitive(
+ SafeSecKeyRefHandle publicKey,
+ ref byte pbData,
+ int cbData,
+ out SafeCFDataHandle pDataOut,
+ out SafeCFErrorHandle pErrorOut);
+
+ [DllImport(Libraries.AppleCryptoNative)]
+ private static extern int AppleCryptoNative_RsaDecryptionPrimitive(
+ SafeSecKeyRefHandle privateKey,
+ ref byte pbData,
+ int cbData,
+ out SafeCFDataHandle pDataOut,
+ out SafeCFErrorHandle pErrorOut);
+
+ [DllImport(Libraries.AppleCryptoNative)]
+ private static extern int AppleCryptoNative_RsaEncryptionPrimitive(
+ SafeSecKeyRefHandle publicKey,
+ ref byte pbData,
+ int cbData,
+ out SafeCFDataHandle pDataOut,
+ out SafeCFErrorHandle pErrorOut);
+
private static int RsaEncryptOaep(
SafeSecKeyRefHandle publicKey,
ReadOnlySpan<byte> pbData,
@@ -220,6 +252,94 @@ internal static partial class Interop
});
}
+ private static bool ProcessPrimitiveResponse(
+ int returnValue,
+ SafeCFDataHandle cfData,
+ SafeCFErrorHandle cfError,
+ Span<byte> destination,
+ out int bytesWritten)
+ {
+ const int kErrorSeeError = -2;
+ const int kSuccess = 1;
+
+ if (returnValue == kErrorSeeError)
+ {
+ throw CreateExceptionForCFError(cfError);
+ }
+
+ if (returnValue == kSuccess && !cfData.IsInvalid)
+ {
+ return CoreFoundation.TryCFWriteData(cfData, destination, out bytesWritten);
+ }
+
+ Debug.Fail($"Unknown return value ({returnValue}) or no data object returned");
+ throw new CryptographicException();
+ }
+
+ internal static bool TryRsaDecryptionPrimitive(
+ SafeSecKeyRefHandle privateKey,
+ ReadOnlySpan<byte> source,
+ Span<byte> destination,
+ out int bytesWritten)
+ {
+ int returnValue = AppleCryptoNative_RsaDecryptionPrimitive(
+ privateKey,
+ ref MemoryMarshal.GetReference(source),
+ source.Length,
+ out SafeCFDataHandle cfData,
+ out SafeCFErrorHandle cfError);
+
+ return ProcessPrimitiveResponse(returnValue, cfData, cfError, destination, out bytesWritten);
+ }
+
+ internal static bool TryRsaEncryptionPrimitive(
+ SafeSecKeyRefHandle publicKey,
+ ReadOnlySpan<byte> source,
+ Span<byte> destination,
+ out int bytesWritten)
+ {
+ int returnValue = AppleCryptoNative_RsaEncryptionPrimitive(
+ publicKey,
+ ref MemoryMarshal.GetReference(source),
+ source.Length,
+ out SafeCFDataHandle cfData,
+ out SafeCFErrorHandle cfError);
+
+ return ProcessPrimitiveResponse(returnValue, cfData, cfError, destination, out bytesWritten);
+ }
+
+ internal static bool TryRsaSignaturePrimitive(
+ SafeSecKeyRefHandle privateKey,
+ ReadOnlySpan<byte> source,
+ Span<byte> destination,
+ out int bytesWritten)
+ {
+ int returnValue = AppleCryptoNative_RsaSignaturePrimitive(
+ privateKey,
+ ref MemoryMarshal.GetReference(source),
+ source.Length,
+ out SafeCFDataHandle cfData,
+ out SafeCFErrorHandle cfError);
+
+ return ProcessPrimitiveResponse(returnValue, cfData, cfError, destination, out bytesWritten);
+ }
+
+ internal static bool TryRsaVerificationPrimitive(
+ SafeSecKeyRefHandle publicKey,
+ ReadOnlySpan<byte> source,
+ Span<byte> destination,
+ out int bytesWritten)
+ {
+ int returnValue = AppleCryptoNative_RsaVerificationPrimitive(
+ publicKey,
+ ref MemoryMarshal.GetReference(source),
+ source.Length,
+ out SafeCFDataHandle cfData,
+ out SafeCFErrorHandle cfError);
+
+ return ProcessPrimitiveResponse(returnValue, cfData, cfError, destination, out bytesWritten);
+ }
+
private static PAL_HashAlgorithm PalAlgorithmFromAlgorithmName(HashAlgorithmName hashAlgorithmName) =>
hashAlgorithmName == HashAlgorithmName.MD5 ? PAL_HashAlgorithm.Md5 :
hashAlgorithmName == HashAlgorithmName.SHA1 ? PAL_HashAlgorithm.Sha1 :
diff --git a/src/Common/src/Interop/Unix/Interop.Libraries.cs b/src/Common/src/Interop/Unix/Interop.Libraries.cs
index f33671958c..0ea3c32ee4 100644
--- a/src/Common/src/Interop/Unix/Interop.Libraries.cs
+++ b/src/Common/src/Interop/Unix/Interop.Libraries.cs
@@ -11,7 +11,6 @@ internal static partial class Interop
internal const string HttpNative = "System.Net.Http.Native";
internal const string NetSecurityNative = "System.Net.Security.Native";
internal const string CryptoNative = "System.Security.Cryptography.Native.OpenSsl";
- internal const string GlobalizationNative = "System.Globalization.Native";
internal const string CompressionNative = "System.IO.Compression.Native";
internal const string Libdl = "libdl";
}
diff --git a/src/Common/src/Interop/Unix/System.Globalization.Native/Interop.Idna.cs b/src/Common/src/Interop/Unix/System.Globalization.Native/Interop.Idna.cs
deleted file mode 100644
index 0331c2a9f1..0000000000
--- a/src/Common/src/Interop/Unix/System.Globalization.Native/Interop.Idna.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Runtime.InteropServices;
-
-internal static partial class Interop
-{
- internal static partial class GlobalizationNative
- {
- internal const int AllowUnassigned = 0x1;
- internal const int UseStd3AsciiRules = 0x2;
-
- [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ToAscii")]
- internal static extern unsafe int ToAscii(uint flags, char* src, int srcLen, char* dstBuffer, int dstBufferCapacity);
-
- [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_ToUnicode")]
- internal static extern unsafe int ToUnicode(uint flags, char* src, int srcLen, char* dstBuffer, int dstBufferCapacity);
- }
-}
diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.ForkAndExecProcess.cs b/src/Common/src/Interop/Unix/System.Native/Interop.ForkAndExecProcess.cs
index 8667e21a9c..3aa37279bc 100644
--- a/src/Common/src/Interop/Unix/System.Native/Interop.ForkAndExecProcess.cs
+++ b/src/Common/src/Interop/Unix/System.Native/Interop.ForkAndExecProcess.cs
@@ -15,6 +15,7 @@ internal static partial class Interop
internal static unsafe void ForkAndExecProcess(
string filename, string[] argv, string[] envp, string cwd,
bool redirectStdin, bool redirectStdout, bool redirectStderr,
+ bool setUser, uint userId, uint groupId,
out int lpChildPid, out int stdinFd, out int stdoutFd, out int stderrFd, bool shouldThrow = true)
{
byte** argvPtr = null, envpPtr = null;
@@ -26,6 +27,7 @@ internal static partial class Interop
result = ForkAndExecProcess(
filename, argvPtr, envpPtr, cwd,
redirectStdin ? 1 : 0, redirectStdout ? 1 : 0, redirectStderr ? 1 :0,
+ setUser ? 1 : 0, userId, groupId,
out lpChildPid, out stdinFd, out stdoutFd, out stderrFd);
if (result != 0)
{
@@ -53,6 +55,7 @@ internal static partial class Interop
private static extern unsafe int ForkAndExecProcess(
string filename, byte** argv, byte** envp, string cwd,
int redirectStdin, int redirectStdout, int redirectStderr,
+ int setUser, uint userId, uint groupId,
out int lpChildPid, out int stdinFd, out int stdoutFd, out int stderrFd);
private static unsafe void AllocNullTerminatedArray(string[] arr, ref byte** arrPtr)
diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.GetPwUid.cs b/src/Common/src/Interop/Unix/System.Native/Interop.GetPwUid.cs
index 66142b7087..56d55c948f 100644
--- a/src/Common/src/Interop/Unix/System.Native/Interop.GetPwUid.cs
+++ b/src/Common/src/Interop/Unix/System.Native/Interop.GetPwUid.cs
@@ -11,6 +11,8 @@ internal static partial class Interop
{
internal unsafe struct Passwd
{
+ internal const int InitialBufferSize = 256;
+
internal byte* Name;
internal byte* Password;
internal uint UserId;
@@ -22,5 +24,8 @@ internal static partial class Interop
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetPwUidR", SetLastError = false)]
internal static extern unsafe int GetPwUidR(uint uid, out Passwd pwd, byte* buf, int bufLen);
+
+ [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetPwNamR", SetLastError = false)]
+ internal static extern unsafe int GetPwNamR(string name, out Passwd pwd, byte* buf, int bufLen);
}
}
diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.HostEntry.cs b/src/Common/src/Interop/Unix/System.Native/Interop.HostEntry.cs
index 4fb68a887f..944a235821 100644
--- a/src/Common/src/Interop/Unix/System.Native/Interop.HostEntry.cs
+++ b/src/Common/src/Interop/Unix/System.Native/Interop.HostEntry.cs
@@ -31,28 +31,27 @@ internal static partial class Interop
NO_DATA = 4,
NO_ADDRESS = NO_DATA,
}
+
+ //opaque structure to maintain consistency with native function signature
+ internal unsafe struct addrinfo
+ {
+
+ }
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct HostEntry
{
internal byte* CanonicalName; // Canonical Name of the Host
internal byte** Aliases; // List of aliases for the host
- internal void* AddressListHandle; // Handle for socket address list
- internal int IPAddressCount; // Number of IP addresses in the list
- private int _handleType; // Opaque handle type information.
+ internal addrinfo* AddressListHandle; // Handle for socket address list
+ internal int IPAddressCount; // Number of IP addresses in the list
}
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetHostEntryForName")]
internal static extern unsafe int GetHostEntryForName(string address, HostEntry* entry);
-
- [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetHostByName")]
- internal static extern unsafe int GetHostByName(string address, HostEntry* entry);
-
- [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetHostByAddress")]
- internal static extern unsafe int GetHostByAddress(IPAddress* address, HostEntry* entry);
-
+
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetNextIPAddress")]
- internal static extern unsafe int GetNextIPAddress(HostEntry* entry, void** addressListHandle, IPAddress* endPoint);
+ internal static extern unsafe int GetNextIPAddress(HostEntry* entry, addrinfo** addressListHandle, IPAddress* endPoint);
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_FreeHostEntry")]
internal static extern unsafe void FreeHostEntry(HostEntry* entry);
diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.ReadDir.cs b/src/Common/src/Interop/Unix/System.Native/Interop.ReadDir.cs
index d98c4285c0..695d50ba2b 100644
--- a/src/Common/src/Interop/Unix/System.Native/Interop.ReadDir.cs
+++ b/src/Common/src/Interop/Unix/System.Native/Interop.ReadDir.cs
@@ -3,15 +3,16 @@
// See the LICENSE file in the project root for more information.
using System;
+using System.Diagnostics;
using System.Runtime.InteropServices;
-using System.Threading;
+using System.Text;
using Microsoft.Win32.SafeHandles;
internal static partial class Interop
{
internal static partial class Sys
{
- private static readonly int s_readBufferSize = GetReadDirRBufferSize();
+ internal static int ReadBufferSize { get; } = GetReadDirRBufferSize();
internal enum NodeType : int
{
@@ -27,76 +28,59 @@ internal static partial class Interop
}
[StructLayout(LayoutKind.Sequential)]
- private unsafe struct InternalDirectoryEntry
+ internal unsafe struct DirectoryEntry
{
- internal IntPtr Name;
- internal int NameLength;
- internal NodeType InodeType;
- }
+ internal byte* Name;
+ internal int NameLength;
+ internal NodeType InodeType;
- internal struct DirectoryEntry
- {
- internal NodeType InodeType;
- internal string InodeName;
+ internal ReadOnlySpan<char> GetName(Span<char> buffer)
+ {
+ Debug.Assert(buffer.Length >= Encoding.UTF8.GetMaxCharCount(255), "should have enough space for the max file name");
+ Debug.Assert(Name != null, "should not have a null name");
+
+ ReadOnlySpan<byte> nameBytes = (NameLength == -1)
+ // In this case the struct was allocated via struct dirent *readdir(DIR *dirp);
+ ? new ReadOnlySpan<byte>(Name, new ReadOnlySpan<byte>(Name, 255).IndexOf<byte>(0))
+ : new ReadOnlySpan<byte>(Name, NameLength);
+
+ Debug.Assert(nameBytes.Length > 0, "we shouldn't have gotten a garbage value from the OS");
+ if (nameBytes.Length == 0)
+ return buffer.Slice(0, 0);
+
+ int charCount = Encoding.UTF8.GetChars(nameBytes, buffer);
+ ReadOnlySpan<char> value = buffer.Slice(0, charCount);
+ Debug.Assert(NameLength != -1 || value.IndexOf('\0') == -1, "should not have embedded nulls if we parsed the end of string");
+ return value;
+ }
}
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_OpenDir", SetLastError = true)]
- internal static extern Microsoft.Win32.SafeHandles.SafeDirectoryHandle OpenDir(string path);
+ internal static extern IntPtr OpenDir(string path);
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetReadDirRBufferSize", SetLastError = false)]
internal static extern int GetReadDirRBufferSize();
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_ReadDirR", SetLastError = false)]
- private static extern unsafe int ReadDirR(IntPtr dir, byte* buffer, int bufferSize, out InternalDirectoryEntry outputEntry);
+ private static extern unsafe int ReadDirR(IntPtr dir, ref byte buffer, int bufferSize, ref DirectoryEntry outputEntry);
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_CloseDir", SetLastError = true)]
internal static extern int CloseDir(IntPtr dir);
- // The calling pattern for ReadDir is described in src/Native/System.Native/pal_readdir.cpp
- internal static int ReadDir(SafeDirectoryHandle dir, out DirectoryEntry outputEntry)
+ /// <summary>
+ /// Get the next directory entry for the given handle. **Note** the actual memory used may be allocated
+ /// by the OS and will be freed when the handle is closed. As such, the handle lifespan MUST be kept tightly
+ /// controlled. The DirectoryEntry name cannot be accessed after the handle is closed.
+ ///
+ /// Call <see cref="ReadBufferSize"/> to see what size buffer to allocate.
+ /// </summary>
+ internal static int ReadDir(IntPtr dir, Span<byte> buffer, ref DirectoryEntry entry)
{
- bool addedRef = false;
- try
- {
- // We avoid a native string copy into InternalDirectoryEntry.
- // - If the platform suppors reading into a buffer, the data is read directly into the buffer. The
- // data can be read as long as the buffer is valid.
- // - If the platform does not support reading into a buffer, the information returned in
- // InternalDirectoryEntry points to native memory owned by the SafeDirectoryHandle. The data is only
- // valid until the next call to CloseDir/ReadDir. We extend the reference until we have copied all data
- // to ensure it does not become invalid by a CloseDir; and we copy the data so our caller does not
- // use the native memory held by the SafeDirectoryHandle.
- dir.DangerousAddRef(ref addedRef);
+ // The calling pattern for ReadDir is described in src/Native/Unix/System.Native/pal_io.cpp|.h
+ Debug.Assert(buffer.Length >= ReadBufferSize, "should have a big enough buffer for the raw data");
- unsafe
- {
- // s_readBufferSize is zero when the native implementation does not support reading into a buffer.
- byte* buffer = stackalloc byte[s_readBufferSize];
- InternalDirectoryEntry temp;
- int ret = ReadDirR(dir.DangerousGetHandle(), buffer, s_readBufferSize, out temp);
- // We copy data into DirectoryEntry to ensure there are no dangling references.
- outputEntry = ret == 0 ?
- new DirectoryEntry() { InodeName = GetDirectoryEntryName(temp), InodeType = temp.InodeType } :
- default(DirectoryEntry);
-
- return ret;
- }
- }
- finally
- {
- if (addedRef)
- {
- dir.DangerousRelease();
- }
- }
- }
-
- private static unsafe string GetDirectoryEntryName(InternalDirectoryEntry dirEnt)
- {
- if (dirEnt.NameLength == -1)
- return Marshal.PtrToStringAnsi(dirEnt.Name);
- else
- return Marshal.PtrToStringAnsi(dirEnt.Name, dirEnt.NameLength);
+ // ReadBufferSize is zero when the native implementation does not support reading into a buffer.
+ return ReadDirR(dir, ref MemoryMarshal.GetReference(buffer), ReadBufferSize, ref entry);
}
}
}
diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.RegisterForSigChld.cs b/src/Common/src/Interop/Unix/System.Native/Interop.RegisterForSigChld.cs
new file mode 100644
index 0000000000..f0d428d45c
--- /dev/null
+++ b/src/Common/src/Interop/Unix/System.Native/Interop.RegisterForSigChld.cs
@@ -0,0 +1,16 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class Sys
+ {
+ internal delegate void SigChldCallback(bool reapAll);
+
+ [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_RegisterForSigChld")]
+ internal static extern bool RegisterForSigChld(SigChldCallback handler);
+ }
+}
diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.Stat.Span.cs b/src/Common/src/Interop/Unix/System.Native/Interop.Stat.Span.cs
new file mode 100644
index 0000000000..6216a6bda8
--- /dev/null
+++ b/src/Common/src/Interop/Unix/System.Native/Interop.Stat.Span.cs
@@ -0,0 +1,41 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+
+internal static partial class Interop
+{
+ internal static partial class Sys
+ {
+ // Unix max paths are typically 1K or 4K UTF-8 bytes, 256 should handle the majority of paths
+ // without putting too much pressure on the stack.
+ private const int StackBufferSize = 256;
+
+ [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_Stat2", SetLastError = true)]
+ internal unsafe static extern int Stat(ref byte path, out FileStatus output);
+
+ internal unsafe static int Stat(ReadOnlySpan<char> path, out FileStatus output)
+ {
+ byte* buffer = stackalloc byte[StackBufferSize];
+ var converter = new ValueUtf8Converter(new Span<byte>(buffer, StackBufferSize));
+ int result = Stat(ref MemoryMarshal.GetReference(converter.ConvertAndTerminateString(path)), out output);
+ converter.Dispose();
+ return result;
+ }
+
+ [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_LStat2", SetLastError = true)]
+ internal static extern int LStat(ref byte path, out FileStatus output);
+
+ internal unsafe static int LStat(ReadOnlySpan<char> path, out FileStatus output)
+ {
+ byte* buffer = stackalloc byte[StackBufferSize];
+ var converter = new ValueUtf8Converter(new Span<byte>(buffer, StackBufferSize));
+ int result = LStat(ref MemoryMarshal.GetReference(converter.ConvertAndTerminateString(path)), out output);
+ converter.Dispose();
+ return result;
+ }
+ }
+}
diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.WaitId.cs b/src/Common/src/Interop/Unix/System.Native/Interop.WaitId.cs
new file mode 100644
index 0000000000..a8a0df58a8
--- /dev/null
+++ b/src/Common/src/Interop/Unix/System.Native/Interop.WaitId.cs
@@ -0,0 +1,26 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal static partial class Interop
+{
+ internal static partial class Sys
+ {
+ /// <summary>
+ /// Waits for terminated child processes.
+ /// </summary>
+ /// <param name="pid">The PID of a child process. -1 for any child.</param>
+ /// <param name="status">The output exit status of the process</param>
+ /// <param name="keepWaitable">Tells the OS to leave the child waitable or reap it.</param>
+ /// <returns>
+ /// 1) returns the process id of a terminated child process
+ /// 2) if no children are waiting, 0 is returned
+ /// 3) on error, -1 is returned
+ /// </returns>
+ [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_WaitIdExitedNoHang", SetLastError = true)]
+ internal static extern int WaitIdExitedNoHang(int pid, out int exitCode, bool keepWaitable);
+ }
+}
diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.WaitPid.cs b/src/Common/src/Interop/Unix/System.Native/Interop.WaitPid.cs
deleted file mode 100644
index 4d862b2ff5..0000000000
--- a/src/Common/src/Interop/Unix/System.Native/Interop.WaitPid.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Runtime.InteropServices;
-
-internal static partial class Interop
-{
- internal static partial class Sys
- {
- [Flags]
- internal enum WaitPidOptions : int
- {
- None = 0, /* no options */
- WNOHANG = 1, /* don't block waiting */
- WUNTRACED = 2, /* report status of stopped children */
- }
-
- /// <summary>
- /// Waits for child process(s) or gathers resource utilization information about child processes
- /// </summary>
- /// <param name="pid">The PID of a child process</param>
- /// <param name="status">The output wait status of the process</param>
- /// <param name="options">Tells the OS how to act on the WaitPid call (to block or not to block)</param>
- /// <returns>
- /// The return value from WaitPid can very greatly.
- /// 1) returns the process id of a terminating or stopped child process
- /// 2) if no children are waiting, -1 is returned and errno is set to ECHILD
- /// 3) if WNOHANG is specified and there are no stopped or exited children, 0 is returned
- /// 4) on error, -1 is returned
- /// </returns>
- [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_WaitPid", SetLastError = true)]
- internal static extern int WaitPid(int pid, out int status, WaitPidOptions options);
-
- // The following 4 functions are wrappers around macros of the same name
- [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_WExitStatus")]
- internal static extern int WExitStatus(int status);
-
- [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_WIfExited")]
- internal static extern bool WIfExited(int status);
-
- [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_WIfSignaled")]
- internal static extern bool WIfSignaled(int status);
-
- [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_WTermSig")]
- internal static extern int WTermSig(int status);
- }
-}
diff --git a/src/Common/src/Interop/Unix/System.Net.Http.Native/Interop.Easy.cs b/src/Common/src/Interop/Unix/System.Net.Http.Native/Interop.Easy.cs
index 16588e48ab..5f6c576883 100644
--- a/src/Common/src/Interop/Unix/System.Net.Http.Native/Interop.Easy.cs
+++ b/src/Common/src/Interop/Unix/System.Net.Http.Native/Interop.Easy.cs
@@ -111,6 +111,7 @@ internal static partial class Interop
CURLOPT_PROXYTYPE = CurlOptionLongBase + 101,
CURLOPT_HTTPAUTH = CurlOptionLongBase + 107,
CURLOPT_TCP_NODELAY = CurlOptionLongBase + 121,
+ CURLOPT_TCP_KEEPALIVE = CurlOptionLongBase + 213,
CURLOPT_CONNECTTIMEOUT_MS = CurlOptionLongBase + 156,
CURLOPT_ADDRESS_SCOPE = CurlOptionLongBase + 171,
CURLOPT_PROTOCOLS = CurlOptionLongBase + 181,
@@ -153,7 +154,7 @@ internal static partial class Interop
CURL_HTTP_VERSION_NONE = 0,
CURL_HTTP_VERSION_1_0 = 1,
CURL_HTTP_VERSION_1_1 = 2,
- CURL_HTTP_VERSION_2_0 = 3,
+ CURL_HTTP_VERSION_2TLS = 4,
};
// Enum for constants defined for CURL_SSLVERSION
diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Ecdh.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Ecdh.cs
new file mode 100644
index 0000000000..74967f6104
--- /dev/null
+++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Ecdh.cs
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using Microsoft.Win32.SafeHandles;
+
+internal static partial class Interop
+{
+ internal static partial class Crypto
+ {
+ [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpPKeyCtxCreate")]
+ internal static extern SafeEvpPKeyCtxHandle EvpPKeyCtxCreate(SafeEvpPKeyHandle pkey, SafeEvpPKeyHandle peerkey, out uint secretLength);
+
+ [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpPKeyDeriveSecretAgreement")]
+ private static extern int EvpPKeyDeriveSecretAgreement(
+ ref byte secret,
+ uint secretLength,
+ SafeEvpPKeyCtxHandle ctx);
+
+ [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpPKeyCtxDestroy")]
+ internal static extern void EvpPKeyCtxDestroy(IntPtr ctx);
+
+ internal static void EvpPKeyDeriveSecretAgreement(SafeEvpPKeyCtxHandle ctx, Span<byte> destination)
+ {
+ Debug.Assert(ctx != null);
+ Debug.Assert(!ctx.IsInvalid);
+
+ int ret = EvpPKeyDeriveSecretAgreement(
+ ref MemoryMarshal.GetReference(destination),
+ (uint)destination.Length,
+ ctx);
+
+ if (ret != 1)
+ {
+ throw CreateOpenSslCryptographicException();
+ }
+ }
+ }
+}
diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs
index 637aae916d..861ee6ca9b 100644
--- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs
+++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs
@@ -232,7 +232,7 @@ internal static partial class Interop
int retVal;
unsafe
{
- using (MemoryHandle handle = input.Retain(pin: true))
+ using (MemoryHandle handle = input.Pin())
{
retVal = Ssl.SslWrite(context, (byte*)handle.Pointer, input.Length);
}
diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSslVersion.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSslVersion.cs
index 1f5e68c15c..70805706ef 100644
--- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSslVersion.cs
+++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSslVersion.cs
@@ -23,7 +23,7 @@ internal static partial class Interop
const string OpenSSL = "OpenSSL ";
// Skip OpenSSL part, and get the version string of format x.y.z
- if (!Version.TryParse(OpenSslVersionDescription().AsReadOnlySpan().Slice(OpenSSL.Length, 5), out s_opensslVersion))
+ if (!Version.TryParse(OpenSslVersionDescription().AsSpan(OpenSSL.Length, 5).ToString(), out s_opensslVersion))
{
s_opensslVersion = new Version(0, 0, 0);
}
diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs
index 1748a66547..b6d6b66244 100644
--- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs
+++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs
@@ -57,6 +57,32 @@ internal static partial class Interop
SafeRsaHandle rsa,
RsaPadding padding);
+ internal static int RsaSignPrimitive(
+ ReadOnlySpan<byte> from,
+ Span<byte> to,
+ SafeRsaHandle rsa) =>
+ RsaSignPrimitive(from.Length, ref MemoryMarshal.GetReference(from), ref MemoryMarshal.GetReference(to), rsa);
+
+ [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaSignPrimitive")]
+ private static extern int RsaSignPrimitive(
+ int flen,
+ ref byte from,
+ ref byte to,
+ SafeRsaHandle rsa);
+
+ internal static int RsaVerificationPrimitive(
+ ReadOnlySpan<byte> from,
+ Span<byte> to,
+ SafeRsaHandle rsa) =>
+ RsaVerificationPrimitive(from.Length, ref MemoryMarshal.GetReference(from), ref MemoryMarshal.GetReference(to), rsa);
+
+ [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaVerificationPrimitive")]
+ private static extern int RsaVerificationPrimitive(
+ int flen,
+ ref byte from,
+ ref byte to,
+ SafeRsaHandle rsa);
+
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaSize")]
internal static extern int RsaSize(SafeRsaHandle rsa);
@@ -168,6 +194,7 @@ internal static partial class Interop
{
Pkcs1 = 0,
OaepSHA1 = 1,
+ NoPadding = 2,
}
}
}
diff --git a/src/Common/src/Interop/Windows/BCrypt/Interop.CreateCryptographicException.cs b/src/Common/src/Interop/Windows/BCrypt/Interop.CreateCryptographicException.cs
index 771c9c20d2..77ff030f9f 100644
--- a/src/Common/src/Interop/Windows/BCrypt/Interop.CreateCryptographicException.cs
+++ b/src/Common/src/Interop/Windows/BCrypt/Interop.CreateCryptographicException.cs
@@ -3,7 +3,7 @@
// See the LICENSE file in the project root for more information.
using System;
-using System.Security.Cryptography;
+using Internal.Cryptography;
internal partial class Interop
{
@@ -12,7 +12,7 @@ internal partial class Interop
internal static Exception CreateCryptographicException(NTSTATUS ntStatus)
{
int hr = unchecked((int)ntStatus) | 0x01000000;
- return new CryptographicException(hr);
+ return hr.ToCryptographicException();
}
}
}
diff --git a/src/Common/src/Interop/Windows/Interop.Errors.cs b/src/Common/src/Interop/Windows/Interop.Errors.cs
index 5581dd9d8e..d957025555 100644
--- a/src/Common/src/Interop/Windows/Interop.Errors.cs
+++ b/src/Common/src/Interop/Windows/Interop.Errors.cs
@@ -72,6 +72,7 @@ internal partial class Interop
internal const int ERROR_BAD_IMPERSONATION_LEVEL = 0x542;
internal const int ERROR_CANT_OPEN_ANONYMOUS = 0x543;
internal const int ERROR_NO_SECURITY_ON_OBJECT = 0x546;
+ internal const int ERROR_CLASS_ALREADY_EXISTS = 0x582;
internal const int ERROR_TRUSTED_RELATIONSHIP_FAILURE = 0x6FD;
internal const int ERROR_RESOURCE_LANG_NOT_FOUND = 0x717;
internal const int EFail = unchecked((int)0x80004005);
diff --git a/src/Common/src/Interop/Windows/Interop.Libraries.cs b/src/Common/src/Interop/Windows/Interop.Libraries.cs
index 293d9f8d48..77c19b795b 100644
--- a/src/Common/src/Interop/Windows/Interop.Libraries.cs
+++ b/src/Common/src/Interop/Windows/Interop.Libraries.cs
@@ -30,6 +30,7 @@ internal static partial class Interop
internal const string WebSocket = "websocket.dll";
internal const string WinHttp = "winhttp.dll";
internal const string Ws2_32 = "ws2_32.dll";
+ internal const string Wtsapi32 = "wtsapi32.dll";
internal const string CompressionNative = "clrcompression.dll";
}
}
diff --git a/src/Common/src/Interop/Windows/Interop.LongFileTime.cs b/src/Common/src/Interop/Windows/Interop.LongFileTime.cs
index 411ae9e4c8..5c8de320bf 100644
--- a/src/Common/src/Interop/Windows/Interop.LongFileTime.cs
+++ b/src/Common/src/Interop/Windows/Interop.LongFileTime.cs
@@ -23,6 +23,6 @@ internal partial class Interop
internal long TicksSince1601;
#pragma warning restore CS0649
- internal DateTime ToDateTimeUtc() => DateTime.FromFileTimeUtc(TicksSince1601);
+ internal DateTimeOffset ToDateTimeOffset() => new DateTimeOffset(DateTime.FromFileTimeUtc(TicksSince1601));
}
}
diff --git a/src/Common/src/Interop/Windows/Interop.UNICODE_STRING.cs b/src/Common/src/Interop/Windows/Interop.UNICODE_STRING.cs
index 237084a73a..a0ca032d16 100644
--- a/src/Common/src/Interop/Windows/Interop.UNICODE_STRING.cs
+++ b/src/Common/src/Interop/Windows/Interop.UNICODE_STRING.cs
@@ -7,10 +7,19 @@ using System.Runtime.InteropServices;
internal static partial class Interop
{
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/aa380518.aspx
+ // https://msdn.microsoft.com/en-us/library/windows/hardware/ff564879.aspx
[StructLayout(LayoutKind.Sequential)]
internal struct UNICODE_STRING
{
+ /// <summary>
+ /// Length, in bytes, not including the the null, if any.
+ /// </summary>
internal ushort Length;
+
+ /// <summary>
+ /// Max size of the buffer in bytes
+ /// </summary>
internal ushort MaximumLength;
internal IntPtr Buffer;
}
diff --git a/src/Common/src/Interop/Windows/NCrypt/Interop.NCryptBuffer.cs b/src/Common/src/Interop/Windows/NCrypt/Interop.NCryptBuffer.cs
new file mode 100644
index 0000000000..23d0d5b5d1
--- /dev/null
+++ b/src/Common/src/Interop/Windows/NCrypt/Interop.NCryptBuffer.cs
@@ -0,0 +1,42 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal static partial class Interop
+{
+ internal static partial class NCrypt
+ {
+ /// <summary>
+ /// Types of NCryptBuffers
+ /// </summary>
+ internal enum BufferType
+ {
+ KdfHashAlgorithm = 0x00000000, // KDF_HASH_ALGORITHM
+ KdfSecretPrepend = 0x00000001, // KDF_SECRET_PREPEND
+ KdfSecretAppend = 0x00000002, // KDF_SECRET_APPEND
+ KdfHmacKey = 0x00000003, // KDF_HMAC_KEY
+ KdfTlsLabel = 0x00000004, // KDF_TLS_PRF_LABEL
+ KdfTlsSeed = 0x00000005 // KDF_TLS_PRF_SEED
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct NCryptBuffer
+ {
+ public int cbBuffer;
+ public BufferType BufferType;
+ public IntPtr pvBuffer;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct NCryptBufferDesc
+ {
+ public int ulVersion;
+ public int cBuffers;
+ public IntPtr pBuffers; // NCryptBuffer[cBuffers]
+ }
+ }
+}
+
diff --git a/src/Common/src/Interop/Windows/NCrypt/Interop.NCryptDeriveKeyMaterial.cs b/src/Common/src/Interop/Windows/NCrypt/Interop.NCryptDeriveKeyMaterial.cs
new file mode 100644
index 0000000000..db8a6d6009
--- /dev/null
+++ b/src/Common/src/Interop/Windows/NCrypt/Interop.NCryptDeriveKeyMaterial.cs
@@ -0,0 +1,249 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using Internal.Cryptography;
+using Microsoft.Win32.SafeHandles;
+using Internal.NativeCrypto;
+
+internal static partial class Interop
+{
+ internal static partial class NCrypt
+ {
+ /// <summary>
+ /// Generate a key from a secret agreement
+ /// </summary>
+ [DllImport(Interop.Libraries.NCrypt, CharSet = CharSet.Unicode)]
+ private static extern ErrorCode NCryptDeriveKey(
+ SafeNCryptSecretHandle hSharedSecret,
+ string pwszKDF,
+ [In] ref NCryptBufferDesc pParameterList,
+ [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbDerivedKey,
+ int cbDerivedKey,
+ [Out] out int pcbResult,
+ SecretAgreementFlags dwFlags);
+
+ /// <summary>
+ /// Derive key material from a hash or HMAC KDF
+ /// </summary>
+ /// <returns></returns>
+ private static byte[] DeriveKeyMaterial(
+ SafeNCryptSecretHandle secretAgreement,
+ string kdf,
+ string hashAlgorithm,
+ byte[] hmacKey,
+ byte[] secretPrepend,
+ byte[] secretAppend,
+ SecretAgreementFlags flags)
+ {
+ // First marshal the hash algoritm
+ IntPtr hashAlgorithmString = IntPtr.Zero;
+
+ try
+ {
+ hashAlgorithmString = Marshal.StringToCoTaskMemUni(hashAlgorithm);
+
+ Span<NCryptBuffer> parameters = stackalloc NCryptBuffer[4];
+ int parameterCount = 0;
+ // We always need to marshal the hashing function
+ NCryptBuffer hashAlgorithmBuffer = new NCryptBuffer();
+ hashAlgorithmBuffer.cbBuffer = (hashAlgorithm.Length + 1) * sizeof(char);
+ hashAlgorithmBuffer.BufferType = BufferType.KdfHashAlgorithm;
+ hashAlgorithmBuffer.pvBuffer = hashAlgorithmString;
+
+ parameters[parameterCount] = hashAlgorithmBuffer;
+ parameterCount++;
+
+ unsafe
+ {
+ fixed (byte* pHmacKey = hmacKey, pSecretPrepend = secretPrepend, pSecretAppend = secretAppend)
+ {
+ //
+ // Now marshal the other parameters
+ //
+
+ if (pHmacKey != null)
+ {
+ NCryptBuffer hmacKeyBuffer = new NCryptBuffer();
+ hmacKeyBuffer.cbBuffer = hmacKey.Length;
+ hmacKeyBuffer.BufferType = BufferType.KdfHmacKey;
+ hmacKeyBuffer.pvBuffer = new IntPtr(pHmacKey);
+
+ parameters[parameterCount] = hmacKeyBuffer;
+ parameterCount++;
+ }
+
+ if (pSecretPrepend != null)
+ {
+ NCryptBuffer secretPrependBuffer = new NCryptBuffer();
+ secretPrependBuffer.cbBuffer = secretPrepend.Length;
+ secretPrependBuffer.BufferType = BufferType.KdfSecretPrepend;
+ secretPrependBuffer.pvBuffer = new IntPtr(pSecretPrepend);
+
+ parameters[parameterCount] = secretPrependBuffer;
+ parameterCount++;
+ }
+
+ if (pSecretAppend != null)
+ {
+ NCryptBuffer secretAppendBuffer = new NCryptBuffer();
+ secretAppendBuffer.cbBuffer = secretAppend.Length;
+ secretAppendBuffer.BufferType = BufferType.KdfSecretAppend;
+ secretAppendBuffer.pvBuffer = new IntPtr(pSecretAppend);
+
+ parameters[parameterCount] = secretAppendBuffer;
+ parameterCount++;
+ }
+
+ return DeriveKeyMaterial(
+ secretAgreement,
+ kdf,
+ parameters.Slice(0, parameterCount),
+ flags);
+ }
+ }
+ }
+ finally
+ {
+ if (hashAlgorithmString != IntPtr.Zero)
+ {
+ Marshal.FreeCoTaskMem(hashAlgorithmString);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Derive key material using a given KDF and secret agreement
+ /// </summary>
+ private static unsafe byte[] DeriveKeyMaterial(
+ SafeNCryptSecretHandle secretAgreement,
+ string kdf,
+ ReadOnlySpan<NCryptBuffer> parameters,
+ SecretAgreementFlags flags)
+ {
+ fixed (NCryptBuffer* pParameters = &MemoryMarshal.GetReference(parameters))
+ {
+ NCryptBufferDesc parameterDesc = new NCryptBufferDesc();
+ parameterDesc.ulVersion = 0;
+ parameterDesc.cBuffers = parameters.Length;
+ parameterDesc.pBuffers = new IntPtr(pParameters);
+
+ // Figure out how big the key material is
+ ErrorCode error = NCryptDeriveKey(
+ secretAgreement,
+ kdf,
+ ref parameterDesc,
+ null,
+ 0,
+ out int keySize,
+ flags);
+
+ if (error != ErrorCode.ERROR_SUCCESS && error != ErrorCode.NTE_BUFFER_TOO_SMALL)
+ {
+ throw error.ToCryptographicException();
+ }
+
+ // Allocate memory for the key material and generate it
+ byte[] keyMaterial = new byte[keySize];
+
+ error = NCryptDeriveKey(
+ secretAgreement,
+ kdf,
+ ref parameterDesc,
+ keyMaterial,
+ keyMaterial.Length,
+ out keySize,
+ flags);
+
+ if (error != ErrorCode.ERROR_SUCCESS)
+ {
+ throw error.ToCryptographicException();
+ }
+
+ // Just in case it shrank the answer once it had a buffer.
+ Array.Resize(ref keyMaterial, Math.Min(keySize, keyMaterial.Length));
+ return keyMaterial;
+ }
+ }
+
+ /// <summary>
+ /// Derive key material from a secret agreement using a hash KDF
+ /// </summary>
+ internal static byte[] DeriveKeyMaterialHash(
+ SafeNCryptSecretHandle secretAgreement,
+ string hashAlgorithm,
+ byte[] secretPrepend,
+ byte[] secretAppend,
+ SecretAgreementFlags flags)
+ {
+ return DeriveKeyMaterial(
+ secretAgreement,
+ BCryptNative.KeyDerivationFunction.Hash,
+ hashAlgorithm,
+ null,
+ secretPrepend,
+ secretAppend,
+ flags);
+ }
+
+ /// <summary>
+ /// Derive key material from a secret agreement using a HMAC KDF
+ /// </summary>
+ internal static byte[] DeriveKeyMaterialHmac(
+ SafeNCryptSecretHandle secretAgreement,
+ string hashAlgorithm,
+ byte[] hmacKey,
+ byte[] secretPrepend,
+ byte[] secretAppend,
+ SecretAgreementFlags flags)
+ {
+ return DeriveKeyMaterial(
+ secretAgreement,
+ BCryptNative.KeyDerivationFunction.Hmac,
+ hashAlgorithm,
+ hmacKey,
+ secretPrepend,
+ secretAppend,
+ flags);
+ }
+
+ /// <summary>
+ /// Derive key material from a secret agreeement using the TLS KDF
+ /// </summary>
+ internal static byte[] DeriveKeyMaterialTls(
+ SafeNCryptSecretHandle secretAgreement,
+ byte[] label,
+ byte[] seed,
+ SecretAgreementFlags flags)
+ {
+ Span<NCryptBuffer> buffers = stackalloc NCryptBuffer[2];
+
+ unsafe
+ {
+ fixed (byte* pLabel = label, pSeed = seed)
+ {
+ NCryptBuffer labelBuffer = new NCryptBuffer();
+ labelBuffer.cbBuffer = label.Length;
+ labelBuffer.BufferType = BufferType.KdfTlsLabel;
+ labelBuffer.pvBuffer = new IntPtr(pLabel);
+ buffers[0] = labelBuffer;
+
+ NCryptBuffer seedBuffer = new NCryptBuffer();
+ seedBuffer.cbBuffer = seed.Length;
+ seedBuffer.BufferType = BufferType.KdfTlsSeed;
+ seedBuffer.pvBuffer = new IntPtr(pSeed);
+ buffers[1] = seedBuffer;
+
+ return DeriveKeyMaterial(
+ secretAgreement,
+ BCryptNative.KeyDerivationFunction.Tls,
+ buffers,
+ flags);
+ }
+ }
+ }
+ }
+}
diff --git a/src/Common/src/Interop/Windows/NCrypt/Interop.NCryptDeriveSecretAgreement.cs b/src/Common/src/Interop/Windows/NCrypt/Interop.NCryptDeriveSecretAgreement.cs
new file mode 100644
index 0000000000..5fd4f1d9da
--- /dev/null
+++ b/src/Common/src/Interop/Windows/NCrypt/Interop.NCryptDeriveSecretAgreement.cs
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+using Internal.Cryptography;
+using Microsoft.Win32.SafeHandles;
+
+internal static partial class Interop
+{
+ internal static partial class NCrypt
+ {
+ [Flags]
+ internal enum SecretAgreementFlags
+ {
+ None = 0x00000000,
+ UseSecretAsHmacKey = 0x00000001 // KDF_USE_SECRET_AS_HMAC_KEY_FLAG
+ }
+
+ /// <summary>
+ /// Generate a secret agreement for generating shared key material
+ /// </summary>
+ [DllImport(Interop.Libraries.NCrypt)]
+ private static extern ErrorCode NCryptSecretAgreement(
+ SafeNCryptKeyHandle hPrivKey,
+ SafeNCryptKeyHandle hPubKey,
+ [Out] out SafeNCryptSecretHandle phSecret,
+ int dwFlags);
+
+
+ /// <summary>
+ /// Generate a secret agreement value for between two parties
+ /// </summary>
+ internal static SafeNCryptSecretHandle DeriveSecretAgreement(
+ SafeNCryptKeyHandle privateKey,
+ SafeNCryptKeyHandle otherPartyPublicKey)
+ {
+ ErrorCode error = NCryptSecretAgreement(
+ privateKey,
+ otherPartyPublicKey,
+ out SafeNCryptSecretHandle secretAgreement,
+ 0);
+
+ if (error != ErrorCode.ERROR_SUCCESS)
+ {
+ throw error.ToCryptographicException();
+ }
+
+ return secretAgreement;
+ }
+ }
+}
diff --git a/src/Common/src/Interop/Windows/NtDll/Interop.FILE_FULL_DIR_INFORMATION.cs b/src/Common/src/Interop/Windows/NtDll/Interop.FILE_FULL_DIR_INFORMATION.cs
index a1037696f6..5b3123bacf 100644
--- a/src/Common/src/Interop/Windows/NtDll/Interop.FILE_FULL_DIR_INFORMATION.cs
+++ b/src/Common/src/Interop/Windows/NtDll/Interop.FILE_FULL_DIR_INFORMATION.cs
@@ -62,6 +62,9 @@ internal partial class Interop
/// </summary>
public unsafe static FILE_FULL_DIR_INFORMATION* GetNextInfo(FILE_FULL_DIR_INFORMATION* info)
{
+ if (info == null)
+ return null;
+
uint nextOffset = (*info).NextEntryOffset;
if (nextOffset == 0)
return null;
diff --git a/src/Common/src/Interop/Windows/NtDll/Interop.NtCreateFile.cs b/src/Common/src/Interop/Windows/NtDll/Interop.NtCreateFile.cs
new file mode 100644
index 0000000000..07a3ba15b4
--- /dev/null
+++ b/src/Common/src/Interop/Windows/NtDll/Interop.NtCreateFile.cs
@@ -0,0 +1,580 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class NtDll
+ {
+ // https://msdn.microsoft.com/en-us/library/bb432380.aspx
+ // https://msdn.microsoft.com/en-us/library/windows/hardware/ff566424.aspx
+ [DllImport(Libraries.NtDll, CharSet = CharSet.Unicode, ExactSpelling = true)]
+ private unsafe static extern int NtCreateFile(
+ out IntPtr FileHandle,
+ DesiredAccess DesiredAccess,
+ ref OBJECT_ATTRIBUTES ObjectAttributes,
+ out IO_STATUS_BLOCK IoStatusBlock,
+ long* AllocationSize,
+ System.IO.FileAttributes FileAttributes,
+ System.IO.FileShare ShareAccess,
+ CreateDisposition CreateDisposition,
+ CreateOptions CreateOptions,
+ void* EaBuffer,
+ uint EaLength);
+
+ internal unsafe static (int status, IntPtr handle) CreateFile(
+ ReadOnlySpan<char> path,
+ IntPtr rootDirectory,
+ CreateDisposition createDisposition,
+ DesiredAccess desiredAccess = DesiredAccess.FILE_GENERIC_READ | DesiredAccess.SYNCHRONIZE,
+ System.IO.FileShare shareAccess = System.IO.FileShare.ReadWrite | System.IO.FileShare.Delete,
+ System.IO.FileAttributes fileAttributes = 0,
+ CreateOptions createOptions = CreateOptions.FILE_SYNCHRONOUS_IO_NONALERT,
+ ObjectAttributes objectAttributes = ObjectAttributes.OBJ_CASE_INSENSITIVE)
+ {
+ fixed (char* c = &MemoryMarshal.GetReference(path))
+ {
+ UNICODE_STRING name = new UNICODE_STRING
+ {
+ Length = checked((ushort)(path.Length * sizeof(char))),
+ MaximumLength = checked((ushort)(path.Length * sizeof(char))),
+ Buffer = (IntPtr)c
+ };
+
+ OBJECT_ATTRIBUTES attributes = new OBJECT_ATTRIBUTES(
+ &name,
+ objectAttributes,
+ rootDirectory);
+
+ int status = NtCreateFile(
+ out IntPtr handle,
+ desiredAccess,
+ ref attributes,
+ out IO_STATUS_BLOCK statusBlock,
+ AllocationSize: null,
+ FileAttributes: fileAttributes,
+ ShareAccess: shareAccess,
+ CreateDisposition: createDisposition,
+ CreateOptions: createOptions,
+ EaBuffer: null,
+ EaLength: 0);
+
+ return (status, handle);
+ }
+ }
+
+ // https://msdn.microsoft.com/en-us/library/windows/hardware/ff557749.aspx
+ public unsafe struct OBJECT_ATTRIBUTES
+ {
+ public uint Length;
+
+ /// <summary>
+ /// Optional handle to root object directory for the given ObjectName.
+ /// Can be a file system directory or object manager directory.
+ /// </summary>
+ public IntPtr RootDirectory;
+
+ /// <summary>
+ /// Name of the object. Must be fully qualified if RootDirectory isn't set.
+ /// Otherwise is relative to RootDirectory.
+ /// </summary>
+ public UNICODE_STRING* ObjectName;
+
+ public ObjectAttributes Attributes;
+
+ /// <summary>
+ /// If null, object will receive default security settings.
+ /// </summary>
+ public void* SecurityDescriptor;
+
+ /// <summary>
+ /// Optional quality of service to be applied to the object. Used to indicate
+ /// security impersonation level and context tracking mode (dynamic or static).
+ /// </summary>
+ public void* SecurityQualityOfService;
+
+ /// <summary>
+ /// Equivalent of InitializeObjectAttributes macro with the exception that you can directly set SQOS.
+ /// </summary>
+ public unsafe OBJECT_ATTRIBUTES(UNICODE_STRING* objectName, ObjectAttributes attributes, IntPtr rootDirectory)
+ {
+ Length = (uint)sizeof(OBJECT_ATTRIBUTES);
+ RootDirectory = rootDirectory;
+ ObjectName = objectName;
+ Attributes = attributes;
+ SecurityDescriptor = null;
+ SecurityQualityOfService = null;
+ }
+ }
+
+ [Flags]
+ public enum ObjectAttributes : uint
+ {
+ // https://msdn.microsoft.com/en-us/library/windows/hardware/ff564586.aspx
+ // https://msdn.microsoft.com/en-us/library/windows/hardware/ff547804.aspx
+
+ /// <summary>
+ /// This handle can be inherited by child processes of the current process.
+ /// </summary>
+ OBJ_INHERIT = 0x00000002,
+
+ /// <summary>
+ /// This flag only applies to objects that are named within the object manager.
+ /// By default, such objects are deleted when all open handles to them are closed.
+ /// If this flag is specified, the object is not deleted when all open handles are closed.
+ /// </summary>
+ OBJ_PERMANENT = 0x00000010,
+
+ /// <summary>
+ /// Only a single handle can be open for this object.
+ /// </summary>
+ OBJ_EXCLUSIVE = 0x00000020,
+
+ /// <summary>
+ /// Lookups for this object should be case insensitive.
+ /// </summary>
+ OBJ_CASE_INSENSITIVE = 0x00000040,
+
+ /// <summary>
+ /// Create on existing object should open, not fail with STATUS_OBJECT_NAME_COLLISION.
+ /// </summary>
+ OBJ_OPENIF = 0x00000080,
+
+ /// <summary>
+ /// Open the symbolic link, not its target.
+ /// </summary>
+ OBJ_OPENLINK = 0x00000100,
+
+ // Only accessible from kernel mode
+ // OBJ_KERNEL_HANDLE
+
+ // Access checks enforced, even in kernel mode
+ // OBJ_FORCE_ACCESS_CHECK
+ // OBJ_VALID_ATTRIBUTES = 0x000001F2
+ }
+
+ /// <summary>
+ /// File creation disposition when calling directly to NT apis.
+ /// </summary>
+ public enum CreateDisposition : uint
+ {
+ /// <summary>
+ /// Default. Replace or create. Deletes existing file instead of overwriting.
+ /// </summary>
+ /// <remarks>
+ /// As this potentially deletes it requires that DesiredAccess must include Delete.
+ /// This has no equivalent in CreateFile.
+ /// </remarks>
+ FILE_SUPERSEDE = 0,
+
+ /// <summary>
+ /// Open if exists or fail if doesn't exist. Equivalent to OPEN_EXISTING or
+ /// <see cref="System.IO.FileMode.Open"/>.
+ /// </summary>
+ /// <remarks>
+ /// TruncateExisting also uses Open and then manually truncates the file
+ /// by calling NtSetInformationFile with FileAllocationInformation and an
+ /// allocation size of 0.
+ /// </remarks>
+ FILE_OPEN = 1,
+
+ /// <summary>
+ /// Create if doesn't exist or fail if does exist. Equivalent to CREATE_NEW
+ /// or <see cref="System.IO.FileMode.CreateNew"/>.
+ /// </summary>
+ FILE_CREATE = 2,
+
+ /// <summary>
+ /// Open if exists or create if doesn't exist. Equivalent to OPEN_ALWAYS or
+ /// <see cref="System.IO.FileMode.OpenOrCreate"/>.
+ /// </summary>
+ FILE_OPEN_IF = 3,
+
+ /// <summary>
+ /// Open and overwrite if exists or fail if doesn't exist. Equivalent to
+ /// TRUNCATE_EXISTING or <see cref="System.IO.FileMode.Truncate"/>.
+ /// </summary>
+ FILE_OVERWRITE = 4,
+
+ /// <summary>
+ /// Open and overwrite if exists or create if doesn't exist. Equivalent to
+ /// CREATE_ALWAYS or <see cref="System.IO.FileMode.Create"/>.
+ /// </summary>
+ FILE_OVERWRITE_IF = 5
+ }
+
+ /// <summary>
+ /// Options for creating/opening files with NtCreateFile.
+ /// </summary>
+ public enum CreateOptions : uint
+ {
+ /// <summary>
+ /// File being created or opened must be a directory file. Disposition must be FILE_CREATE, FILE_OPEN,
+ /// or FILE_OPEN_IF.
+ /// </summary>
+ /// <remarks>
+ /// Can only be used with FILE_SYNCHRONOUS_IO_ALERT/NONALERT, FILE_WRITE_THROUGH, FILE_OPEN_FOR_BACKUP_INTENT,
+ /// and FILE_OPEN_BY_FILE_ID flags.
+ /// </remarks>
+ FILE_DIRECTORY_FILE = 0x00000001,
+
+ /// <summary>
+ /// Applications that write data to the file must actually transfer the data into
+ /// the file before any requested write operation is considered complete. This flag
+ /// is set automatically if FILE_NO_INTERMEDIATE_BUFFERING is set.
+ /// </summary>
+ FILE_WRITE_THROUGH = 0x00000002,
+
+ /// <summary>
+ /// All accesses to the file are sequential.
+ /// </summary>
+ FILE_SEQUENTIAL_ONLY = 0x00000004,
+
+ /// <summary>
+ /// File cannot be cached in driver buffers. Cannot use with AppendData desired access.
+ /// </summary>
+ FILE_NO_INTERMEDIATE_BUFFERING = 0x00000008,
+
+ /// <summary>
+ /// All operations are performed synchronously. Any wait on behalf of the caller is
+ /// subject to premature termination from alerts.
+ /// </summary>
+ /// <remarks>
+ /// Cannot be used with FILE_SYNCHRONOUS_IO_NONALERT.
+ /// Synchronous DesiredAccess flag is required. I/O system will maintain file position context.
+ /// </remarks>
+ FILE_SYNCHRONOUS_IO_ALERT = 0x00000010,
+
+ /// <summary>
+ /// All operations are performed synchronously. Waits in the system to synchronize I/O queuing
+ /// and completion are not subject to alerts.
+ /// </summary>
+ /// <remarks>
+ /// Cannot be used with FILE_SYNCHRONOUS_IO_ALERT.
+ /// Synchronous DesiredAccess flag is required. I/O system will maintain file position context.
+ /// </remarks>
+ FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020,
+
+ /// <summary>
+ /// File being created or opened must not be a directory file. Can be a data file, device,
+ /// or volume.
+ /// </summary>
+ FILE_NON_DIRECTORY_FILE = 0x00000040,
+
+ /// <summary>
+ /// Create a tree connection for this file in order to open it over the network.
+ /// </summary>
+ /// <remarks>
+ /// Not used by device and intermediate drivers.
+ /// </remarks>
+ FILE_CREATE_TREE_CONNECTION = 0x00000080,
+
+ /// <summary>
+ /// Complete the operation immediately with a success code of STATUS_OPLOCK_BREAK_IN_PROGRESS if
+ /// the target file is oplocked.
+ /// </summary>
+ /// <remarks>
+ /// Not compatible with ReserveOpfilter or OpenRequiringOplock.
+ /// Not used by device and intermediate drivers.
+ /// </remarks>
+ FILE_COMPLETE_IF_OPLOCKED = 0x00000100,
+
+ /// <summary>
+ /// If the extended attributes on an existing file being opened indicate that the caller must
+ /// understand extended attributes to properly interpret the file, fail the request.
+ /// </summary>
+ /// <remarks>
+ /// Not used by device and intermediate drivers.
+ /// </remarks>
+ FILE_NO_EA_KNOWLEDGE = 0x00000200,
+
+ // Behavior undocumented, defined in headers
+ // FILE_OPEN_REMOTE_INSTANCE = 0x00000400,
+
+ /// <summary>
+ /// Accesses to the file can be random, so no sequential read-ahead operations should be performed
+ /// on the file by FSDs or the system.
+ /// </summary>
+ FILE_RANDOM_ACCESS = 0x00000800,
+
+ /// <summary>
+ /// Delete the file when the last handle to it is passed to NtClose. Requires Delete flag in
+ /// DesiredAccess parameter.
+ /// </summary>
+ FILE_DELETE_ON_CLOSE = 0x00001000,
+
+ /// <summary>
+ /// Open the file by reference number or object ID. The file name that is specified by the ObjectAttributes
+ /// name parameter includes the 8 or 16 byte file reference number or ID for the file in the ObjectAttributes
+ /// name field. The device name can optionally be prefixed.
+ /// </summary>
+ /// <remarks>
+ /// NTFS supports both reference numbers and object IDs. 16 byte reference numbers are 8 byte numbers padded
+ /// with zeros. ReFS only supports reference numbers (not object IDs). 8 byte and 16 byte reference numbers
+ /// are not related. Note that as the UNICODE_STRING will contain raw byte data, it may not be a "valid" string.
+ /// Not used by device and intermediate drivers.
+ /// </remarks>
+ /// <example>
+ /// \??\C:\{8 bytes of binary FileID}
+ /// \device\HardDiskVolume1\{16 bytes of binary ObjectID}
+ /// {8 bytes of binary FileID}
+ /// </example>
+ FILE_OPEN_BY_FILE_ID = 0x00002000,
+
+ /// <summary>
+ /// The file is being opened for backup intent. Therefore, the system should check for certain access rights
+ /// and grant the caller the appropriate access to the file before checking the DesiredAccess parameter
+ /// against the file's security descriptor.
+ /// </summary>
+ /// <remarks>
+ /// Not used by device and intermediate drivers.
+ /// </remarks>
+ FILE_OPEN_FOR_BACKUP_INTENT = 0x00004000,
+
+ /// <summary>
+ /// When creating a file, specifies that it should not inherit the compression bit from the parent directory.
+ /// </summary>
+ FILE_NO_COMPRESSION = 0x00008000,
+
+ /// <summary>
+ /// The file is being opened and an opportunistic lock (oplock) on the file is being requested as a single atomic
+ /// operation.
+ /// </summary>
+ /// <remarks>
+ /// The file system checks for oplocks before it performs the create operation and will fail the create with a
+ /// return code of STATUS_CANNOT_BREAK_OPLOCK if the result would be to break an existing oplock.
+ /// Not compatible with CompleteIfOplocked or ReserveOpFilter. Windows 7 and up.
+ /// </remarks>
+ FILE_OPEN_REQUIRING_OPLOCK = 0x00010000,
+
+ /// <summary>
+ /// CreateFile2 uses this flag to prevent opening a file that you don't have access to without specifying
+ /// FILE_SHARE_READ. (Preventing users that can only read a file from denying access to other readers.)
+ /// </summary>
+ /// <remarks>
+ /// Windows 7 and up.
+ /// </remarks>
+ FILE_DISALLOW_EXCLUSIVE = 0x00020000,
+
+ /// <summary>
+ /// The client opening the file or device is session aware and per session access is validated if necessary.
+ /// </summary>
+ /// <remarks>
+ /// Windows 8 and up.
+ /// </remarks>
+ FILE_SESSION_AWARE = 0x00040000,
+
+ /// <summary>
+ /// This flag allows an application to request a filter opportunistic lock (oplock) to prevent other applications
+ /// from getting share violations.
+ /// </summary>
+ /// <remarks>
+ /// Not compatible with CompleteIfOplocked or OpenRequiringOplock.
+ /// If there are already open handles, the create request will fail with STATUS_OPLOCK_NOT_GRANTED.
+ /// </remarks>
+ FILE_RESERVE_OPFILTER = 0x00100000,
+
+ /// <summary>
+ /// Open a file with a reparse point attribute, bypassing the normal reparse point processing.
+ /// </summary>
+ FILE_OPEN_REPARSE_POINT = 0x00200000,
+
+ /// <summary>
+ /// Causes files that are marked with the Offline attribute not to be recalled from remote storage.
+ /// </summary>
+ /// <remarks>
+ /// More details can be found in Remote Storage documentation (see Basic Concepts).
+ /// https://technet.microsoft.com/en-us/library/cc938459.aspx
+ /// </remarks>
+ FILE_OPEN_NO_RECALL = 0x00400000
+
+ // Behavior undocumented, defined in headers
+ // FILE_OPEN_FOR_FREE_SPACE_QUERY = 0x00800000
+ }
+
+ /// <summary>
+ /// System.IO.FileAccess looks up these values when creating handles
+ /// </summary>
+ /// <remarks>
+ /// File Security and Access Rights
+ /// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364399.aspx
+ /// </remarks>
+ [Flags]
+ public enum DesiredAccess : uint
+ {
+ // File Access Rights Constants
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/gg258116.aspx
+
+ /// <summary>
+ /// For a file, the right to read data from the file.
+ /// </summary>
+ /// <remarks>
+ /// Directory version of this flag is <see cref="FILE_LIST_DIRECTORY"/>.
+ /// </remarks>
+ FILE_READ_DATA = 0x0001,
+
+ /// <summary>
+ /// For a directory, the right to list the contents.
+ /// </summary>
+ /// <remarks>
+ /// File version of this flag is <see cref="FILE_READ_DATA"/>.
+ /// </remarks>
+ FILE_LIST_DIRECTORY = 0x0001,
+
+ /// <summary>
+ /// For a file, the right to write data to the file.
+ /// </summary>
+ /// <remarks>
+ /// Directory version of this flag is <see cref="FILE_ADD_FILE"/>.
+ /// </remarks>
+ FILE_WRITE_DATA = 0x0002,
+
+ /// <summary>
+ /// For a directory, the right to create a file in a directory.
+ /// </summary>
+ /// <remarks>
+ /// File version of this flag is <see cref="FILE_WRITE_DATA"/>.
+ /// </remarks>
+ FILE_ADD_FILE = 0x0002,
+
+ /// <summary>
+ /// For a file, the right to append data to a file. <see cref="FILE_WRITE_DATA"/> is needed
+ /// to overwrite existing data.
+ /// </summary>
+ /// <remarks>
+ /// Directory version of this flag is <see cref="FILE_ADD_SUBDIRECTORY"/>.
+ /// </remarks>
+ FILE_APPEND_DATA = 0x0004,
+
+ /// <summary>
+ /// For a directory, the right to create a subdirectory.
+ /// </summary>
+ /// <remarks>
+ /// File version of this flag is <see cref="FILE_APPEND_DATA"/>.
+ /// </remarks>
+ FILE_ADD_SUBDIRECTORY = 0x0004,
+
+ /// <summary>
+ /// For a named pipe, the right to create a pipe instance.
+ /// </summary>
+ FILE_CREATE_PIPE_INSTANCE = 0x0004,
+
+ /// <summary>
+ /// The right to read extended attributes.
+ /// </summary>
+ FILE_READ_EA = 0x0008,
+
+ /// <summary>
+ /// The right to write extended attributes.
+ /// </summary>
+ FILE_WRITE_EA = 0x0010,
+
+ /// <summary>
+ /// The right to execute the file.
+ /// </summary>
+ /// <remarks>
+ /// Directory version of this flag is <see cref="FILE_TRAVERSE"/>.
+ /// </remarks>
+ FILE_EXECUTE = 0x0020,
+
+ /// <summary>
+ /// For a directory, the right to traverse the directory.
+ /// </summary>
+ /// <remarks>
+ /// File version of this flag is <see cref="FILE_EXECUTE"/>.
+ /// </remarks>
+ FILE_TRAVERSE = 0x0020,
+
+ /// <summary>
+ /// For a directory, the right to delete a directory and all
+ /// the files it contains, including read-only files.
+ /// </summary>
+ FILE_DELETE_CHILD = 0x0040,
+
+ /// <summary>
+ /// The right to read attributes.
+ /// </summary>
+ FILE_READ_ATTRIBUTES = 0x0080,
+
+ /// <summary>
+ /// The right to write attributes.
+ /// </summary>
+ FILE_WRITE_ATTRIBUTES = 0x0100,
+
+ /// <summary>
+ /// All standard and specific rights. [FILE_ALL_ACCESS]
+ /// </summary>
+ FILE_ALL_ACCESS = DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER | 0x1FF,
+
+ /// <summary>
+ /// The right to delete the object.
+ /// </summary>
+ DELETE = 0x00010000,
+
+ /// <summary>
+ /// The right to read the information in the object's security descriptor.
+ /// Doesn't include system access control list info (SACL).
+ /// </summary>
+ READ_CONTROL = 0x00020000,
+
+ /// <summary>
+ /// The right to modify the discretionary access control list (DACL) in the
+ /// object's security descriptor.
+ /// </summary>
+ WRITE_DAC = 0x00040000,
+
+ /// <summary>
+ /// The right to change the owner in the object's security descriptor.
+ /// </summary>
+ WRITE_OWNER = 0x00080000,
+
+ /// <summary>
+ /// The right to use the object for synchronization. Enables a thread to wait until the object
+ /// is in the signaled state. This is required if opening a synchronous handle.
+ /// </summary>
+ SYNCHRONIZE = 0x00100000,
+
+ /// <summary>
+ /// Same as READ_CONTROL.
+ /// </summary>
+ STANDARD_RIGHTS_READ = READ_CONTROL,
+
+ /// <summary>
+ /// Same as READ_CONTROL.
+ /// </summary>
+ STANDARD_RIGHTS_WRITE = READ_CONTROL,
+
+ /// <summary>
+ /// Same as READ_CONTROL.
+ /// </summary>
+ STANDARD_RIGHTS_EXECUTE = READ_CONTROL,
+
+ /// <summary>
+ /// Maps internally to <see cref="FILE_READ_ATTRIBUTES"/> | <see cref="FILE_READ_DATA"/> | <see cref="FILE_READ_EA"/>
+ /// | <see cref="STANDARD_RIGHTS_READ"/> | <see cref="SYNCHRONIZE"/>.
+ /// (For directories, <see cref="FILE_READ_ATTRIBUTES"/> | <see cref="FILE_LIST_DIRECTORY"/> | <see cref="FILE_READ_EA"/>
+ /// | <see cref="STANDARD_RIGHTS_READ"/> | <see cref="SYNCHRONIZE"/>.)
+ /// </summary>
+ FILE_GENERIC_READ = 0x80000000, // GENERIC_READ
+
+ /// <summary>
+ /// Maps internally to <see cref="FILE_APPEND_DATA"/> | <see cref="FILE_WRITE_ATTRIBUTES"/> | <see cref="FILE_WRITE_DATA"/>
+ /// | <see cref="FILE_WRITE_EA"/> | <see cref="STANDARD_RIGHTS_READ"/> | <see cref="SYNCHRONIZE"/>.
+ /// (For directories, <see cref="FILE_ADD_SUBDIRECTORY"/> | <see cref="FILE_WRITE_ATTRIBUTES"/> | <see cref="FILE_ADD_FILE"/> AddFile
+ /// | <see cref="FILE_WRITE_EA"/> | <see cref="STANDARD_RIGHTS_READ"/> | <see cref="SYNCHRONIZE"/>.)
+ /// </summary>
+ FILE_GENERIC_WRITE = 0x40000000, // GENERIC WRITE
+
+ /// <summary>
+ /// Maps internally to <see cref="FILE_EXECUTE"/> | <see cref="FILE_READ_ATTRIBUTES"/> | <see cref="STANDARD_RIGHTS_EXECUTE"/>
+ /// | <see cref="SYNCHRONIZE"/>.
+ /// (For directories, <see cref="FILE_DELETE_CHILD"/> | <see cref="FILE_READ_ATTRIBUTES"/> | <see cref="STANDARD_RIGHTS_EXECUTE"/>
+ /// | <see cref="SYNCHRONIZE"/>.)
+ /// </summary>
+ FILE_GENERIC_EXECUTE = 0x20000000 // GENERIC_EXECUTE
+ }
+ }
+}
diff --git a/src/Common/src/Interop/Windows/SChannel/UnmanagedCertificateContext.IntPtr.cs b/src/Common/src/Interop/Windows/SChannel/UnmanagedCertificateContext.IntPtr.cs
index f3d53c92fc..a508e5dcad 100644
--- a/src/Common/src/Interop/Windows/SChannel/UnmanagedCertificateContext.IntPtr.cs
+++ b/src/Common/src/Interop/Windows/SChannel/UnmanagedCertificateContext.IntPtr.cs
@@ -20,8 +20,11 @@ namespace System.Net
return result;
}
- Interop.Crypt32.CERT_CONTEXT context =
- Marshal.PtrToStructure<Interop.Crypt32.CERT_CONTEXT>(certContext);
+ Interop.Crypt32.CERT_CONTEXT context;
+ unsafe
+ {
+ context = *(Interop.Crypt32.CERT_CONTEXT*)certContext;
+ }
if (context.hCertStore != IntPtr.Zero)
{
diff --git a/src/Common/src/Interop/Windows/Winsock/AddressInfoEx.cs b/src/Common/src/Interop/Windows/Winsock/AddressInfoEx.cs
new file mode 100644
index 0000000000..0972101831
--- /dev/null
+++ b/src/Common/src/Interop/Windows/Winsock/AddressInfoEx.cs
@@ -0,0 +1,25 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Net.Internals;
+using System.Runtime.InteropServices;
+
+namespace System.Net.Sockets
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal unsafe struct AddressInfoEx
+ {
+ internal AddressInfoHints ai_flags;
+ internal AddressFamily ai_family;
+ internal SocketType ai_socktype;
+ internal ProtocolFamily ai_protocol;
+ internal int ai_addrlen;
+ internal IntPtr ai_canonname; // Ptr to the canonical name - check for NULL
+ internal byte* ai_addr; // Ptr to the sockaddr structure
+ internal IntPtr ai_blob; // Unused ptr to blob data about provider
+ internal int ai_bloblen;
+ internal IntPtr ai_provider; // Unused ptr to the namespace provider guid
+ internal AddressInfoEx* ai_next; // Next structure in linked list
+ }
+}
diff --git a/src/Common/src/Interop/Windows/Winsock/Interop.GetAddrInfoExW.cs b/src/Common/src/Interop/Windows/Winsock/Interop.GetAddrInfoExW.cs
new file mode 100644
index 0000000000..cb2070de81
--- /dev/null
+++ b/src/Common/src/Interop/Windows/Winsock/Interop.GetAddrInfoExW.cs
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Net.Sockets;
+using System.Runtime.InteropServices;
+using System.Threading;
+
+internal static partial class Interop
+{
+ internal static partial class Winsock
+ {
+ internal const string GetAddrInfoExCancelFunctionName = "GetAddrInfoExCancel";
+
+ internal unsafe delegate void LPLOOKUPSERVICE_COMPLETION_ROUTINE([In] int dwError, [In] int dwBytes, [In] NativeOverlapped* lpOverlapped);
+
+ [DllImport(Interop.Libraries.Ws2_32, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
+ internal static extern unsafe int GetAddrInfoExW(
+ [In] string pName,
+ [In] string pServiceName,
+ [In] int dwNamespace,
+ [In] IntPtr lpNspId,
+ [In] ref AddressInfoEx pHints,
+ [Out] out AddressInfoEx* ppResult,
+ [In] IntPtr timeout,
+ [In] ref NativeOverlapped lpOverlapped,
+ [In] LPLOOKUPSERVICE_COMPLETION_ROUTINE lpCompletionRoutine,
+ [Out] out IntPtr lpNameHandle
+ );
+
+ [DllImport("ws2_32.dll", ExactSpelling = true, SetLastError = true)]
+ internal static extern unsafe void FreeAddrInfoEx([In] AddressInfoEx* pAddrInfo);
+ }
+}
+
diff --git a/src/Common/src/Interop/Windows/Winsock/Interop.gethostbyaddr.cs b/src/Common/src/Interop/Windows/Winsock/Interop.gethostbyaddr.cs
deleted file mode 100644
index 5280eb6aa1..0000000000
--- a/src/Common/src/Interop/Windows/Winsock/Interop.gethostbyaddr.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Runtime.InteropServices;
-using System.Net.Sockets;
-#if !SYSTEM_NET_SOCKETS_DLL
-using ProtocolFamily = System.Net.Internals.ProtocolFamily;
-#endif
-
-internal static partial class Interop
-{
- internal static partial class Winsock
- {
- [DllImport(Interop.Libraries.Ws2_32, SetLastError = true)]
- internal static extern IntPtr gethostbyaddr(
- [In] ref int addr,
- [In] int len,
- [In] ProtocolFamily type
- );
- }
-}
diff --git a/src/Common/src/Interop/Windows/Winsock/Interop.gethostbyname.cs b/src/Common/src/Interop/Windows/Winsock/Interop.gethostbyname.cs
deleted file mode 100644
index ec141b55cf..0000000000
--- a/src/Common/src/Interop/Windows/Winsock/Interop.gethostbyname.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Runtime.InteropServices;
-
-internal static partial class Interop
-{
- internal static partial class Winsock
- {
- [DllImport(Interop.Libraries.Ws2_32, CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true, SetLastError = true)]
- internal static extern IntPtr gethostbyname(
- [In] string host
- );
- }
-}
diff --git a/src/Common/src/Interop/Windows/advapi32/Interop.ClaimSecurityAttributes.cs b/src/Common/src/Interop/Windows/advapi32/Interop.ClaimSecurityAttributes.cs
new file mode 100644
index 0000000000..e8cbf16a86
--- /dev/null
+++ b/src/Common/src/Interop/Windows/advapi32/Interop.ClaimSecurityAttributes.cs
@@ -0,0 +1,128 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ [StructLayout(LayoutKind.Explicit)]
+ internal struct CLAIM_SECURITY_ATTRIBUTE_INFORMATION_V1
+ {
+ // defined as union in CLAIM_SECURITY_ATTRIBUTES_INFORMATION
+ [FieldOffset(0)]
+ public IntPtr pAttributeV1;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct CLAIM_SECURITY_ATTRIBUTES_INFORMATION
+ {
+ /// WORD->unsigned short
+ public ushort Version;
+
+ /// WORD->unsigned short
+ public ushort Reserved;
+
+ /// DWORD->unsigned int
+ public uint AttributeCount;
+
+ /// CLAIM_SECURITY_ATTRIBUTE_V1
+ public CLAIM_SECURITY_ATTRIBUTE_INFORMATION_V1 Attribute;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ internal struct CLAIM_SECURITY_ATTRIBUTE_FQBN_VALUE
+ {
+ // DWORD64->unsigned __int64
+ public ulong Version;
+
+ // PWSTR->WCHAR*
+ [MarshalAsAttribute(UnmanagedType.LPWStr)]
+ public string Name;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ internal struct CLAIM_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE
+ {
+ /// PVOID->void*
+ public IntPtr pValue;
+
+ /// DWORD->unsigned int
+ public uint ValueLength;
+ }
+
+ [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
+ internal struct CLAIM_VALUES_ATTRIBUTE_V1
+ {
+ // PLONG64->__int64*
+ [FieldOffset(0)]
+ public IntPtr pInt64;
+
+ // PDWORD64->unsigned __int64*
+ [FieldOffset(0)]
+ public IntPtr pUint64;
+
+ // PWSTR*
+ [FieldOffset(0)]
+ public IntPtr ppString;
+
+ // PCLAIM_SECURITY_ATTRIBUTE_FQBN_VALUE->_CLAIM_SECURITY_ATTRIBUTE_FQBN_VALUE*
+ [FieldOffset(0)]
+ public IntPtr pFqbn;
+
+ // PCLAIM_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE->_CLAIM_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE*
+ [FieldOffset(0)]
+ public IntPtr pOctetString;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ internal struct CLAIM_SECURITY_ATTRIBUTE_V1
+ {
+ // PWSTR->WCHAR*
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string Name;
+
+ // WORD->unsigned short
+ public ClaimSecurityAttributeType ValueType;
+
+ // WORD->unsigned short
+ public ushort Reserved;
+
+ // DWORD->unsigned int
+ public uint Flags;
+
+ // DWORD->unsigned int
+ public uint ValueCount;
+
+ // struct CLAIM_VALUES - a union of 4 possible values
+ public CLAIM_VALUES_ATTRIBUTE_V1 Values;
+ }
+
+ internal enum ClaimSecurityAttributeType : ushort
+ {
+ // CLAIM_SECURITY_ATTRIBUTE_TYPE_INVALID -> 0x00
+ CLAIM_SECURITY_ATTRIBUTE_TYPE_INVALID = 0,
+
+ // CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64 -> 0x01
+ CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64 = 1,
+
+ // CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64 -> 0x02
+ CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64 = 2,
+
+ // CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING -> 0x03
+ CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING = 3,
+
+ // CLAIM_SECURITY_ATTRIBUTE_TYPE_FQBN -> 0x04
+ CLAIM_SECURITY_ATTRIBUTE_TYPE_FQBN = 4,
+
+ // CLAIM_SECURITY_ATTRIBUTE_TYPE_SID -> 0x05
+ CLAIM_SECURITY_ATTRIBUTE_TYPE_SID = 5,
+
+ // CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN -> 0x06
+ CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN = 6,
+
+ // CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING -> 0x10
+ CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING = 16,
+ }
+}
diff --git a/src/Common/src/Interop/Windows/advapi32/Interop.CreateProcessWithLogon.cs b/src/Common/src/Interop/Windows/advapi32/Interop.CreateProcessWithLogon.cs
index c5fade0454..80eae1076b 100644
--- a/src/Common/src/Interop/Windows/advapi32/Interop.CreateProcessWithLogon.cs
+++ b/src/Common/src/Interop/Windows/advapi32/Interop.CreateProcessWithLogon.cs
@@ -16,13 +16,13 @@ internal partial class Interop
string domain,
IntPtr password,
LogonFlags logonFlags,
- [MarshalAs(UnmanagedType.LPTStr)] string appName,
+ string appName,
StringBuilder cmdLine,
int creationFlags,
IntPtr environmentBlock,
- [MarshalAs(UnmanagedType.LPTStr)] string lpCurrentDirectory,
- Interop.Kernel32.STARTUPINFO lpStartupInfo,
- Interop.Kernel32.PROCESS_INFORMATION lpProcessInformation);
+ string lpCurrentDirectory,
+ ref Interop.Kernel32.STARTUPINFO lpStartupInfo,
+ ref Interop.Kernel32.PROCESS_INFORMATION lpProcessInformation);
[Flags]
internal enum LogonFlags
diff --git a/src/Common/src/Interop/Windows/advapi32/Interop.LookupAccountNameW.cs b/src/Common/src/Interop/Windows/advapi32/Interop.LookupAccountNameW.cs
index 6a8c6676d1..3554665e5f 100644
--- a/src/Common/src/Interop/Windows/advapi32/Interop.LookupAccountNameW.cs
+++ b/src/Common/src/Interop/Windows/advapi32/Interop.LookupAccountNameW.cs
@@ -3,16 +3,19 @@
// See the LICENSE file in the project root for more information.
using System.Runtime.InteropServices;
-using System.Text;
internal partial class Interop
{
internal partial class Advapi32
{
- [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, SetLastError = true)]
+ [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]
internal static extern bool LookupAccountNameW(
- string machineName, string accountName, byte[] sid,
- ref int sidLen,
- [Out] StringBuilder domainName, ref uint domainNameLen, out int peUse);
+ string lpSystemName,
+ ref char lpAccountName,
+ ref byte Sid,
+ ref uint cbSid,
+ ref char ReferencedDomainName,
+ ref uint cchReferencedDomainName,
+ out uint peUse);
}
}
diff --git a/src/Common/src/Interop/Windows/advapi32/Interop.ServiceProcessOptions.cs b/src/Common/src/Interop/Windows/advapi32/Interop.ServiceProcessOptions.cs
index 5e4a93b38f..26d8ca11fd 100644
--- a/src/Common/src/Interop/Windows/advapi32/Interop.ServiceProcessOptions.cs
+++ b/src/Common/src/Interop/Windows/advapi32/Interop.ServiceProcessOptions.cs
@@ -143,6 +143,7 @@ internal partial class Interop
internal const int STATE_START_PENDING = 0x00000002;
internal const int STATE_STOPPED = 0x00000001;
internal const int STATE_STOP_PENDING = 0x00000003;
+ internal const int ERROR_EXCEPTION_IN_SERVICE = 0x00000428;
}
internal partial class ServiceStartErrorModes
diff --git a/src/Common/src/Interop/Windows/kernel32/Interop.CopyFileEx.cs b/src/Common/src/Interop/Windows/kernel32/Interop.CopyFileEx.cs
index 7f8c10c4b3..46efbc61bc 100644
--- a/src/Common/src/Interop/Windows/kernel32/Interop.CopyFileEx.cs
+++ b/src/Common/src/Interop/Windows/kernel32/Interop.CopyFileEx.cs
@@ -30,8 +30,8 @@ internal partial class Interop
ref int cancel,
int flags)
{
- src = PathInternal.EnsureExtendedPrefixOverMaxPath(src);
- dst = PathInternal.EnsureExtendedPrefixOverMaxPath(dst);
+ src = PathInternal.EnsureExtendedPrefixIfNeeded(src);
+ dst = PathInternal.EnsureExtendedPrefixIfNeeded(dst);
return CopyFileExPrivate(src, dst, progressRoutine, progressData, ref cancel, flags);
}
}
diff --git a/src/Common/src/Interop/Windows/kernel32/Interop.CreateFile.cs b/src/Common/src/Interop/Windows/kernel32/Interop.CreateFile.cs
index 9c3639d6e2..3fe8360caf 100644
--- a/src/Common/src/Interop/Windows/kernel32/Interop.CreateFile.cs
+++ b/src/Common/src/Interop/Windows/kernel32/Interop.CreateFile.cs
@@ -34,7 +34,7 @@ internal partial class Interop
int dwFlagsAndAttributes,
IntPtr hTemplateFile)
{
- lpFileName = PathInternal.EnsureExtendedPrefixOverMaxPath(lpFileName);
+ lpFileName = PathInternal.EnsureExtendedPrefixIfNeeded(lpFileName);
fixed (SECURITY_ATTRIBUTES* sa = &securityAttrs)
{
IntPtr handle = CreateFilePrivate(lpFileName, dwDesiredAccess, dwShareMode, sa, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
@@ -76,7 +76,7 @@ internal partial class Interop
FileMode dwCreationDisposition,
int dwFlagsAndAttributes)
{
- lpFileName = PathInternal.EnsureExtendedPrefixOverMaxPath(lpFileName);
+ lpFileName = PathInternal.EnsureExtendedPrefixIfNeeded(lpFileName);
return CreateFilePrivate(lpFileName, dwDesiredAccess, dwShareMode, null, dwCreationDisposition, dwFlagsAndAttributes, IntPtr.Zero);
}
}
diff --git a/src/Common/src/Interop/Windows/kernel32/Interop.CreateFile2.cs b/src/Common/src/Interop/Windows/kernel32/Interop.CreateFile2.cs
index ed691ace46..8480332c00 100644
--- a/src/Common/src/Interop/Windows/kernel32/Interop.CreateFile2.cs
+++ b/src/Common/src/Interop/Windows/kernel32/Interop.CreateFile2.cs
@@ -92,7 +92,7 @@ internal partial class Interop
FileMode dwCreationDisposition,
int dwFlagsAndAttributes)
{
- lpFileName = PathInternal.EnsureExtendedPrefixOverMaxPath(lpFileName);
+ lpFileName = PathInternal.EnsureExtendedPrefixIfNeeded(lpFileName);
return CreateFile(lpFileName, dwDesiredAccess, dwShareMode, null, dwCreationDisposition, dwFlagsAndAttributes, IntPtr.Zero);
}
}
diff --git a/src/Common/src/Interop/Windows/kernel32/Interop.CreateProcess.cs b/src/Common/src/Interop/Windows/kernel32/Interop.CreateProcess.cs
index 47ba909aca..5446010d2d 100644
--- a/src/Common/src/Interop/Windows/kernel32/Interop.CreateProcess.cs
+++ b/src/Common/src/Interop/Windows/kernel32/Interop.CreateProcess.cs
@@ -13,76 +13,48 @@ internal partial class Interop
{
[DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, BestFitMapping = false, EntryPoint = "CreateProcessW")]
internal static extern bool CreateProcess(
- [MarshalAs(UnmanagedType.LPTStr)] string lpApplicationName,
+ string lpApplicationName,
StringBuilder lpCommandLine,
ref SECURITY_ATTRIBUTES procSecAttrs,
ref SECURITY_ATTRIBUTES threadSecAttrs,
bool bInheritHandles,
int dwCreationFlags,
IntPtr lpEnvironment,
- [MarshalAs(UnmanagedType.LPTStr)] string lpCurrentDirectory,
- STARTUPINFO lpStartupInfo,
- [Out] PROCESS_INFORMATION lpProcessInformation
+ string lpCurrentDirectory,
+ ref STARTUPINFO lpStartupInfo,
+ ref PROCESS_INFORMATION lpProcessInformation
);
[StructLayout(LayoutKind.Sequential)]
- internal class PROCESS_INFORMATION
+ internal struct PROCESS_INFORMATION
{
- internal IntPtr hProcess = IntPtr.Zero;
- internal IntPtr hThread = IntPtr.Zero;
- internal int dwProcessId = 0;
- internal int dwThreadId = 0;
+ internal IntPtr hProcess;
+ internal IntPtr hThread;
+ internal int dwProcessId;
+ internal int dwThreadId;
}
[StructLayout(LayoutKind.Sequential)]
- internal class STARTUPINFO : IDisposable
+ internal struct STARTUPINFO
{
internal int cb;
- internal IntPtr lpReserved = IntPtr.Zero;
- internal IntPtr lpDesktop = IntPtr.Zero;
- internal IntPtr lpTitle = IntPtr.Zero;
- internal int dwX = 0;
- internal int dwY = 0;
- internal int dwXSize = 0;
- internal int dwYSize = 0;
- internal int dwXCountChars = 0;
- internal int dwYCountChars = 0;
- internal int dwFillAttribute = 0;
- internal int dwFlags = 0;
- internal short wShowWindow = 0;
- internal short cbReserved2 = 0;
- internal IntPtr lpReserved2 = IntPtr.Zero;
- internal SafeFileHandle hStdInput = new SafeFileHandle(IntPtr.Zero, false);
- internal SafeFileHandle hStdOutput = new SafeFileHandle(IntPtr.Zero, false);
- internal SafeFileHandle hStdError = new SafeFileHandle(IntPtr.Zero, false);
-
- internal
- STARTUPINFO()
- {
- cb = Marshal.SizeOf(this);
- }
-
- public void Dispose()
- {
- // close the handles created for child process
- if (hStdInput != null && !hStdInput.IsInvalid)
- {
- hStdInput.Dispose();
- hStdInput = null;
- }
-
- if (hStdOutput != null && !hStdOutput.IsInvalid)
- {
- hStdOutput.Dispose();
- hStdOutput = null;
- }
-
- if (hStdError != null && !hStdError.IsInvalid)
- {
- hStdError.Dispose();
- hStdError = null;
- }
- }
+ internal IntPtr lpReserved;
+ internal IntPtr lpDesktop;
+ internal IntPtr lpTitle;
+ internal int dwX;
+ internal int dwY;
+ internal int dwXSize;
+ internal int dwYSize;
+ internal int dwXCountChars;
+ internal int dwYCountChars;
+ internal int dwFillAttribute;
+ internal int dwFlags;
+ internal short wShowWindow;
+ internal short cbReserved2;
+ internal IntPtr lpReserved2;
+ internal IntPtr hStdInput;
+ internal IntPtr hStdOutput;
+ internal IntPtr hStdError;
}
}
}
diff --git a/src/Common/src/Interop/Windows/kernel32/Interop.DeleteFile.cs b/src/Common/src/Interop/Windows/kernel32/Interop.DeleteFile.cs
index 3609f0da2c..dbcae6ee31 100644
--- a/src/Common/src/Interop/Windows/kernel32/Interop.DeleteFile.cs
+++ b/src/Common/src/Interop/Windows/kernel32/Interop.DeleteFile.cs
@@ -18,7 +18,7 @@ internal partial class Interop
internal static bool DeleteFile(string path)
{
- path = PathInternal.EnsureExtendedPrefixOverMaxPath(path);
+ path = PathInternal.EnsureExtendedPrefixIfNeeded(path);
return DeleteFilePrivate(path);
}
}
diff --git a/src/Common/src/Interop/Windows/kernel32/Interop.DeleteVolumeMountPoint.cs b/src/Common/src/Interop/Windows/kernel32/Interop.DeleteVolumeMountPoint.cs
index ccf10151f7..49b9bfc923 100644
--- a/src/Common/src/Interop/Windows/kernel32/Interop.DeleteVolumeMountPoint.cs
+++ b/src/Common/src/Interop/Windows/kernel32/Interop.DeleteVolumeMountPoint.cs
@@ -19,7 +19,7 @@ internal partial class Interop
internal static bool DeleteVolumeMountPoint(string mountPoint)
{
- mountPoint = PathInternal.EnsureExtendedPrefixOverMaxPath(mountPoint);
+ mountPoint = PathInternal.EnsureExtendedPrefixIfNeeded(mountPoint);
return DeleteVolumeMountPointPrivate(mountPoint);
}
}
diff --git a/src/Common/src/Interop/Windows/kernel32/Interop.ExpandEnvironmentStrings.cs b/src/Common/src/Interop/Windows/kernel32/Interop.ExpandEnvironmentStrings.cs
index a402bbd0e8..ba942ba6ff 100644
--- a/src/Common/src/Interop/Windows/kernel32/Interop.ExpandEnvironmentStrings.cs
+++ b/src/Common/src/Interop/Windows/kernel32/Interop.ExpandEnvironmentStrings.cs
@@ -3,13 +3,12 @@
// See the LICENSE file in the project root for more information.
using System.Runtime.InteropServices;
-using System.Text;
internal partial class Interop
{
internal partial class Kernel32
{
[DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true)]
- internal static extern int ExpandEnvironmentStringsW(string lpSrc, [Out] StringBuilder lpDst, int nSize);
+ internal static extern uint ExpandEnvironmentStringsW(string lpSrc, ref char lpDst, uint nSize);
}
}
diff --git a/src/Common/src/Interop/Windows/kernel32/Interop.FindFirstFileEx.cs b/src/Common/src/Interop/Windows/kernel32/Interop.FindFirstFileEx.cs
index 2d1ecefd98..a561132f94 100644
--- a/src/Common/src/Interop/Windows/kernel32/Interop.FindFirstFileEx.cs
+++ b/src/Common/src/Interop/Windows/kernel32/Interop.FindFirstFileEx.cs
@@ -19,7 +19,7 @@ internal partial class Interop
internal static SafeFindHandle FindFirstFile(string fileName, ref WIN32_FIND_DATA data)
{
- fileName = PathInternal.EnsureExtendedPrefixOverMaxPath(fileName);
+ fileName = PathInternal.EnsureExtendedPrefixIfNeeded(fileName);
// use FindExInfoBasic since we don't care about short name and it has better perf
return FindFirstFileExPrivate(fileName, FINDEX_INFO_LEVELS.FindExInfoBasic, ref data, FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, 0);
diff --git a/src/Common/src/Interop/Windows/kernel32/Interop.FormatMessage.cs b/src/Common/src/Interop/Windows/kernel32/Interop.FormatMessage.cs
index 8de0bc0627..1fe81ec173 100644
--- a/src/Common/src/Interop/Windows/kernel32/Interop.FormatMessage.cs
+++ b/src/Common/src/Interop/Windows/kernel32/Interop.FormatMessage.cs
@@ -3,7 +3,6 @@
// See the LICENSE file in the project root for more information.
using System;
-using System.Text;
using System.Runtime.InteropServices;
internal partial class Interop
@@ -16,17 +15,17 @@ internal partial class Interop
private const int FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000;
private const int ERROR_INSUFFICIENT_BUFFER = 0x7A;
- private const int InitialBufferSize = 256;
+ private const int InitialBufferSize = 256; // small enough to be on stack, and large enough for most error messages
private const int BufferSizeIncreaseFactor = 4;
private const int MaxAllowedBufferSize = 65 * 1024;
[DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, EntryPoint = "FormatMessageW", SetLastError = true, BestFitMapping = true)]
- private static extern int FormatMessage(
+ private static extern unsafe int FormatMessage(
int dwFlags,
IntPtr lpSource,
uint dwMessageId,
int dwLanguageId,
- [Out] StringBuilder lpBuffer,
+ char* lpBuffer,
int nSize,
IntPtr[] arguments);
@@ -40,50 +39,54 @@ internal partial class Interop
internal static string GetMessage(IntPtr moduleHandle, int errorCode)
{
- var sb = new StringBuilder(InitialBufferSize);
+ Span<char> buffer = stackalloc char[InitialBufferSize];
do
{
- string errorMsg;
- if (TryGetErrorMessage(moduleHandle, errorCode, sb, out errorMsg))
+ if (TryGetErrorMessage(moduleHandle, errorCode, buffer, out string errorMsg))
{
return errorMsg;
}
- else
- {
- // increase the capacity of the StringBuilder.
- sb.Capacity *= BufferSizeIncreaseFactor;
- }
+
+ // Increase the capacity of the buffer.
+ buffer = new char[buffer.Length * BufferSizeIncreaseFactor];
}
- while (sb.Capacity < MaxAllowedBufferSize);
+ while (buffer.Length < MaxAllowedBufferSize);
// If you come here then a size as large as 65K is also not sufficient and so we give the generic errorMsg.
return string.Format("Unknown error (0x{0:x})", errorCode);
}
- private static bool TryGetErrorMessage(IntPtr moduleHandle, int errorCode, StringBuilder sb, out string errorMsg)
+ private static bool TryGetErrorMessage(IntPtr moduleHandle, int errorCode, Span<char> buffer, out string errorMsg)
{
- errorMsg = "";
-
int flags = FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY;
if (moduleHandle != IntPtr.Zero)
{
flags |= FORMAT_MESSAGE_FROM_HMODULE;
}
- int result = FormatMessage(flags, moduleHandle, unchecked((uint)errorCode), 0, sb, sb.Capacity, null);
+ int result;
+ unsafe
+ {
+ fixed (char* bufferPtr = &MemoryMarshal.GetReference(buffer))
+ {
+ result = FormatMessage(flags, moduleHandle, unchecked((uint)errorCode), 0, bufferPtr, buffer.Length, null);
+ }
+ }
+
if (result != 0)
{
- int i = sb.Length;
+ int i = result;
while (i > 0)
{
- char ch = sb[i - 1];
+ char ch = buffer[i - 1];
if (ch > 32 && ch != '.') break;
i--;
}
- errorMsg = sb.ToString(0, i);
+ errorMsg = buffer.Slice(0, i).ToString();
}
else if (Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER)
{
+ errorMsg = "";
return false;
}
else
diff --git a/src/Common/src/Interop/Windows/kernel32/Interop.GetComputerName.cs b/src/Common/src/Interop/Windows/kernel32/Interop.GetComputerName.cs
index e0f8857bda..34a26c180f 100644
--- a/src/Common/src/Interop/Windows/kernel32/Interop.GetComputerName.cs
+++ b/src/Common/src/Interop/Windows/kernel32/Interop.GetComputerName.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
using System.Runtime.InteropServices;
internal partial class Interop
@@ -9,18 +10,18 @@ internal partial class Interop
internal partial class Kernel32
{
[DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, EntryPoint = "GetComputerNameW")]
- private static extern unsafe int GetComputerName(char* lpBuffer, ref uint nSize);
+ private static extern unsafe int GetComputerName(ref char lpBuffer, ref uint nSize);
// maximum length of the NETBIOS name (not including NULL)
private const int MAX_COMPUTERNAME_LENGTH = 15;
internal static unsafe string GetComputerName()
{
- uint length = MAX_COMPUTERNAME_LENGTH + 1;
- char* buffer = stackalloc char[(int)length];
+ Span<char> buffer = stackalloc char[MAX_COMPUTERNAME_LENGTH + 1];
+ uint length = (uint)buffer.Length;
- return GetComputerName(buffer, ref length) != 0 ?
- new string(buffer, 0, checked((int)length)) :
+ return GetComputerName(ref MemoryMarshal.GetReference(buffer), ref length) != 0 ?
+ buffer.Slice(0, (int)length).ToString() :
null;
}
}
diff --git a/src/Common/src/Interop/Windows/kernel32/Interop.GetCurrentDirectory.cs b/src/Common/src/Interop/Windows/kernel32/Interop.GetCurrentDirectory.cs
index c68e1b9510..611cc70d28 100644
--- a/src/Common/src/Interop/Windows/kernel32/Interop.GetCurrentDirectory.cs
+++ b/src/Common/src/Interop/Windows/kernel32/Interop.GetCurrentDirectory.cs
@@ -3,13 +3,12 @@
// See the LICENSE file in the project root for more information.
using System.Runtime.InteropServices;
-using System.Text;
internal partial class Interop
{
internal partial class Kernel32
{
[DllImport(Libraries.Kernel32, EntryPoint = "GetCurrentDirectoryW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)]
- internal static extern int GetCurrentDirectory(int nBufferLength, [Out]StringBuilder lpBuffer);
+ internal static extern uint GetCurrentDirectory(uint nBufferLength, ref char lpBuffer);
}
}
diff --git a/src/Common/src/Interop/Windows/kernel32/Interop.GetCurrentThreadId.cs b/src/Common/src/Interop/Windows/kernel32/Interop.GetCurrentThreadId.cs
new file mode 100644
index 0000000000..a92936e291
--- /dev/null
+++ b/src/Common/src/Interop/Windows/kernel32/Interop.GetCurrentThreadId.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal static partial class Interop
+{
+ internal static partial class Kernel32
+ {
+ [DllImport(Interop.Libraries.Kernel32, ExactSpelling = true)]
+ public static extern int GetCurrentThreadId();
+ }
+}
diff --git a/src/Common/src/Interop/Windows/kernel32/Interop.GetFileAttributesEx.cs b/src/Common/src/Interop/Windows/kernel32/Interop.GetFileAttributesEx.cs
index 1bd3bed103..7740e85a50 100644
--- a/src/Common/src/Interop/Windows/kernel32/Interop.GetFileAttributesEx.cs
+++ b/src/Common/src/Interop/Windows/kernel32/Interop.GetFileAttributesEx.cs
@@ -17,7 +17,7 @@ internal partial class Interop
internal static bool GetFileAttributesEx(string name, GET_FILEEX_INFO_LEVELS fileInfoLevel, ref WIN32_FILE_ATTRIBUTE_DATA lpFileInformation)
{
- name = PathInternal.EnsureExtendedPrefixOverMaxPath(name);
+ name = PathInternal.EnsureExtendedPrefixIfNeeded(name);
return GetFileAttributesExPrivate(name, fileInfoLevel, ref lpFileInformation);
}
}
diff --git a/src/Common/src/Interop/Windows/kernel32/Interop.GetLongPathName.cs b/src/Common/src/Interop/Windows/kernel32/Interop.GetLongPathName.cs
deleted file mode 100644
index eda148273a..0000000000
--- a/src/Common/src/Interop/Windows/kernel32/Interop.GetLongPathName.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.IO;
-using System.Runtime.InteropServices;
-using System.Text;
-
-internal partial class Interop
-{
- internal partial class Kernel32
- {
- /// <summary>
- /// WARNING: This method does not implicitly handle long paths. Use GetLongPathName.
- /// </summary>
- [DllImport(Libraries.Kernel32, EntryPoint = "GetLongPathNameW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = false)]
- private static extern int GetLongPathNamePrivate(string path, [Out]StringBuilder longPathBuffer, int bufferLength);
-
- internal static int GetLongPathName(string path, [Out]StringBuilder longPathBuffer, int bufferLength)
- {
- path = PathInternal.EnsureExtendedPrefixOverMaxPath(path);
- return GetLongPathNamePrivate(path, longPathBuffer, bufferLength);
- }
- }
-}
diff --git a/src/Common/src/Interop/Windows/kernel32/Interop.GetSystemDirectoryW.cs b/src/Common/src/Interop/Windows/kernel32/Interop.GetSystemDirectoryW.cs
index cf1b31d62c..197f6f5ead 100644
--- a/src/Common/src/Interop/Windows/kernel32/Interop.GetSystemDirectoryW.cs
+++ b/src/Common/src/Interop/Windows/kernel32/Interop.GetSystemDirectoryW.cs
@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System;
using System.Runtime.InteropServices;
internal static partial class Interop
@@ -10,14 +9,6 @@ internal static partial class Interop
internal static partial class Kernel32
{
[DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true)]
- private static extern unsafe int GetSystemDirectoryW(char* lpBuffer, int uSize);
-
- internal static unsafe int GetSystemDirectoryW(Span<char> buffer)
- {
- fixed (char* bufferPtr = &MemoryMarshal.GetReference(buffer))
- {
- return GetSystemDirectoryW(bufferPtr, buffer.Length);
- }
- }
+ internal static extern uint GetSystemDirectoryW(ref char lpBuffer, uint uSize);
}
}
diff --git a/src/Common/src/Interop/Windows/kernel32/Interop.LoadLibraryEx.cs b/src/Common/src/Interop/Windows/kernel32/Interop.LoadLibraryEx.cs
index 4ba2fd65a4..d24d4d3c6a 100644
--- a/src/Common/src/Interop/Windows/kernel32/Interop.LoadLibraryEx.cs
+++ b/src/Common/src/Interop/Windows/kernel32/Interop.LoadLibraryEx.cs
@@ -12,6 +12,7 @@ internal partial class Interop
internal partial class Kernel32
{
public const int LOAD_LIBRARY_AS_DATAFILE = 0x00000002;
+ public const int LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800;
[DllImport(Libraries.Kernel32, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
public static extern SafeLibraryHandle LoadLibraryExW([In] string lpwLibFileName, [In] IntPtr hFile, [In] uint dwFlags);
diff --git a/src/Common/src/Interop/Windows/kernel32/Interop.MaxLengths.cs b/src/Common/src/Interop/Windows/kernel32/Interop.MaxLengths.cs
index e85d354d00..dc9d621605 100644
--- a/src/Common/src/Interop/Windows/kernel32/Interop.MaxLengths.cs
+++ b/src/Common/src/Interop/Windows/kernel32/Interop.MaxLengths.cs
@@ -8,20 +8,6 @@ internal partial class Interop
{
internal const int MAX_PATH = 260;
- // Technically the maximum file/directory name is whatever GetVolumeInformation tells you in
- // MaximumComponentLength. For most file systems this is 255 (UDF is the notable exception at
- // 254).
- //
- // CreateDirectory will refuse directories that are over MAX_PATH - 12 (8.3 filename length).
- // This count includes the drive and NULL. This limitation existed to allow "del *.*" to work
- // successfully and now appears to be moot as you can create files in a directory that is over
- // 248 (up to MAX_PATH) and "del *.*" on them on both FAT and NTFS.
- //
- // Using extended syntax (\\?\) will allow creation of directory names that are full length
- // (e.g. 255 characters). MKDIR/MD, however, does not check extended syntax and will fail out
- // ANY string that is longer than OR equal to MAX_PATH. This effectively makes the longest
- // directory you can create 252 characters, excluding the prefix and drive (\\?\C:\).
- internal const int MAX_DIRECTORY_PATH = 248;
internal const int CREDUI_MAX_USERNAME_LENGTH = 513;
}
}
diff --git a/src/Common/src/Interop/Windows/kernel32/Interop.MoveFileEx.cs b/src/Common/src/Interop/Windows/kernel32/Interop.MoveFileEx.cs
index 3e384782d5..b76648bcc1 100644
--- a/src/Common/src/Interop/Windows/kernel32/Interop.MoveFileEx.cs
+++ b/src/Common/src/Interop/Windows/kernel32/Interop.MoveFileEx.cs
@@ -18,8 +18,8 @@ internal partial class Interop
internal static bool MoveFile(string src, string dst)
{
- src = PathInternal.EnsureExtendedPrefixOverMaxPath(src);
- dst = PathInternal.EnsureExtendedPrefixOverMaxPath(dst);
+ src = PathInternal.EnsureExtendedPrefixIfNeeded(src);
+ dst = PathInternal.EnsureExtendedPrefixIfNeeded(dst);
return MoveFileExPrivate(src, dst, 2 /* MOVEFILE_COPY_ALLOWED */);
}
}
diff --git a/src/Common/src/Interop/Windows/kernel32/Interop.RemoveDirectory.cs b/src/Common/src/Interop/Windows/kernel32/Interop.RemoveDirectory.cs
index af5f809b32..dd8e321ec7 100644
--- a/src/Common/src/Interop/Windows/kernel32/Interop.RemoveDirectory.cs
+++ b/src/Common/src/Interop/Windows/kernel32/Interop.RemoveDirectory.cs
@@ -18,7 +18,7 @@ internal partial class Interop
internal static bool RemoveDirectory(string path)
{
- path = PathInternal.EnsureExtendedPrefixOverMaxPath(path);
+ path = PathInternal.EnsureExtendedPrefixIfNeeded(path);
return RemoveDirectoryPrivate(path);
}
}
diff --git a/src/Common/src/Interop/Windows/kernel32/Interop.ReplaceFile.cs b/src/Common/src/Interop/Windows/kernel32/Interop.ReplaceFile.cs
index 8c9dee4da7..4b9dd79d5e 100644
--- a/src/Common/src/Interop/Windows/kernel32/Interop.ReplaceFile.cs
+++ b/src/Common/src/Interop/Windows/kernel32/Interop.ReplaceFile.cs
@@ -19,9 +19,9 @@ internal partial class Interop
string replacedFileName, string replacementFileName, string backupFileName,
int dwReplaceFlags, IntPtr lpExclude, IntPtr lpReserved)
{
- replacedFileName = PathInternal.EnsureExtendedPrefixOverMaxPath(replacedFileName);
- replacementFileName = PathInternal.EnsureExtendedPrefixOverMaxPath(replacementFileName);
- backupFileName = PathInternal.EnsureExtendedPrefixOverMaxPath(backupFileName);
+ replacedFileName = PathInternal.EnsureExtendedPrefixIfNeeded(replacedFileName);
+ replacementFileName = PathInternal.EnsureExtendedPrefixIfNeeded(replacementFileName);
+ backupFileName = PathInternal.EnsureExtendedPrefixIfNeeded(backupFileName);
return ReplaceFilePrivate(
replacedFileName, replacementFileName, backupFileName,
diff --git a/src/Common/src/Interop/Windows/kernel32/Interop.SetFileAttributes.cs b/src/Common/src/Interop/Windows/kernel32/Interop.SetFileAttributes.cs
index 865730d8c4..9f956dc5d2 100644
--- a/src/Common/src/Interop/Windows/kernel32/Interop.SetFileAttributes.cs
+++ b/src/Common/src/Interop/Windows/kernel32/Interop.SetFileAttributes.cs
@@ -17,7 +17,7 @@ internal partial class Interop
internal static bool SetFileAttributes(string name, int attr)
{
- name = PathInternal.EnsureExtendedPrefixOverMaxPath(name);
+ name = PathInternal.EnsureExtendedPrefixIfNeeded(name);
return SetFileAttributesPrivate(name, attr);
}
}
diff --git a/src/Common/src/Interop/Windows/secur32/Interop.GetUserNameExW.cs b/src/Common/src/Interop/Windows/secur32/Interop.GetUserNameExW.cs
index 7d910bba72..cf0dd5f698 100644
--- a/src/Common/src/Interop/Windows/secur32/Interop.GetUserNameExW.cs
+++ b/src/Common/src/Interop/Windows/secur32/Interop.GetUserNameExW.cs
@@ -3,14 +3,13 @@
// See the LICENSE file in the project root for more information.
using System.Runtime.InteropServices;
-using System.Text;
internal partial class Interop
{
internal partial class Secur32
{
[DllImport(Libraries.Secur32, CharSet = CharSet.Unicode, SetLastError = true)]
- internal static extern byte GetUserNameExW(int NameFormat, [Out] StringBuilder lpNameBuffer, ref uint lpnSize);
+ internal static extern BOOLEAN GetUserNameExW(int NameFormat, ref char lpNameBuffer, ref uint lpnSize);
internal const int NameSamCompatible = 2;
}
diff --git a/src/Common/src/Interop/Windows/sspicli/SecuritySafeHandles.cs b/src/Common/src/Interop/Windows/sspicli/SecuritySafeHandles.cs
index 5405349689..f105e729f8 100644
--- a/src/Common/src/Interop/Windows/sspicli/SecuritySafeHandles.cs
+++ b/src/Common/src/Interop/Windows/sspicli/SecuritySafeHandles.cs
@@ -562,66 +562,64 @@ namespace System.Net.Security
}
}
- Interop.SspiCli.SecBuffer[] outUnmanagedBuffer = new Interop.SspiCli.SecBuffer[1];
- fixed (void* outUnmanagedBufferPtr = &outUnmanagedBuffer[0])
+ Interop.SspiCli.SecBuffer outUnmanagedBuffer = default;
+
+ // Fix Descriptor pointer that points to unmanaged SecurityBuffers.
+ outSecurityBufferDescriptor.pBuffers = &outUnmanagedBuffer;
+ outUnmanagedBuffer.cbBuffer = outSecBuffer.size;
+ outUnmanagedBuffer.BufferType = outSecBuffer.type;
+ if (outSecBuffer.token == null || outSecBuffer.token.Length == 0)
{
- // Fix Descriptor pointer that points to unmanaged SecurityBuffers.
- outSecurityBufferDescriptor.pBuffers = outUnmanagedBufferPtr;
- outUnmanagedBuffer[0].cbBuffer = outSecBuffer.size;
- outUnmanagedBuffer[0].BufferType = outSecBuffer.type;
- if (outSecBuffer.token == null || outSecBuffer.token.Length == 0)
- {
- outUnmanagedBuffer[0].pvBuffer = IntPtr.Zero;
- }
- else
- {
- outUnmanagedBuffer[0].pvBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(outSecBuffer.token, outSecBuffer.offset);
- }
+ outUnmanagedBuffer.pvBuffer = IntPtr.Zero;
+ }
+ else
+ {
+ outUnmanagedBuffer.pvBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(outSecBuffer.token, outSecBuffer.offset);
+ }
- if (isSspiAllocated)
- {
- outFreeContextBuffer = SafeFreeContextBuffer.CreateEmptyHandle();
- }
+ if (isSspiAllocated)
+ {
+ outFreeContextBuffer = SafeFreeContextBuffer.CreateEmptyHandle();
+ }
- if (refContext == null || refContext.IsInvalid)
- {
- refContext = new SafeDeleteContext_SECURITY();
- }
+ if (refContext == null || refContext.IsInvalid)
+ {
+ refContext = new SafeDeleteContext_SECURITY();
+ }
- if (targetName == null || targetName.Length == 0)
- {
- targetName = dummyStr;
- }
+ if (targetName == null || targetName.Length == 0)
+ {
+ targetName = dummyStr;
+ }
- fixed (char* namePtr = targetName)
- {
- errorCode = MustRunInitializeSecurityContext_SECURITY(
- ref inCredentials,
- contextHandle.IsZero ? null : &contextHandle,
- (byte*)(((object)targetName == (object)dummyStr) ? null : namePtr),
- inFlags,
- endianness,
- haveInSecurityBufferDescriptor ? &inSecurityBufferDescriptor : null,
- refContext,
- ref outSecurityBufferDescriptor,
- ref outFlags,
- outFreeContextBuffer);
- }
+ fixed (char* namePtr = targetName)
+ {
+ errorCode = MustRunInitializeSecurityContext_SECURITY(
+ ref inCredentials,
+ contextHandle.IsZero ? null : &contextHandle,
+ (byte*)(((object)targetName == (object)dummyStr) ? null : namePtr),
+ inFlags,
+ endianness,
+ haveInSecurityBufferDescriptor ? &inSecurityBufferDescriptor : null,
+ refContext,
+ ref outSecurityBufferDescriptor,
+ ref outFlags,
+ outFreeContextBuffer);
+ }
- if (NetEventSource.IsEnabled) NetEventSource.Info(null, "Marshalling OUT buffer");
+ if (NetEventSource.IsEnabled) NetEventSource.Info(null, "Marshalling OUT buffer");
- // Get unmanaged buffer with index 0 as the only one passed into PInvoke.
- outSecBuffer.size = outUnmanagedBuffer[0].cbBuffer;
- outSecBuffer.type = outUnmanagedBuffer[0].BufferType;
- if (outSecBuffer.size > 0)
- {
- outSecBuffer.token = new byte[outSecBuffer.size];
- Marshal.Copy(outUnmanagedBuffer[0].pvBuffer, outSecBuffer.token, 0, outSecBuffer.size);
- }
- else
- {
- outSecBuffer.token = null;
- }
+ // Get unmanaged buffer with index 0 as the only one passed into PInvoke.
+ outSecBuffer.size = outUnmanagedBuffer.cbBuffer;
+ outSecBuffer.type = outUnmanagedBuffer.BufferType;
+ if (outSecBuffer.size > 0)
+ {
+ outSecBuffer.token = new byte[outSecBuffer.size];
+ Marshal.Copy(outUnmanagedBuffer.pvBuffer, outSecBuffer.token, 0, outSecBuffer.size);
+ }
+ else
+ {
+ outSecBuffer.token = null;
}
}
}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.Constants.cs b/src/Common/src/Interop/Windows/user32/Interop.Constants.cs
new file mode 100644
index 0000000000..65b6534a68
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.Constants.cs
@@ -0,0 +1,229 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ public const int COLOR_WINDOW = 5;
+
+ public const int CTRL_LOGOFF_EVENT = 5;
+ public const int CTRL_SHUTDOWN_EVENT = 6;
+
+ public const int ENDSESSION_CLOSEAPP = 0x00000001;
+ public const int ENDSESSION_CRITICAL = 0x40000000;
+ public const int ENDSESSION_LOGOFF = unchecked((int)0x80000000);
+
+ public const int GCL_WNDPROC = (-24);
+ public const int GWL_WNDPROC = (-4);
+
+ public const int MWMO_INPUTAVAILABLE = 0x0004;
+
+ public const int PBT_APMQUERYSUSPEND = 0x0000;
+ public const int PBT_APMQUERYSTANDBY = 0x0001;
+ public const int PBT_APMQUERYSUSPENDFAILED = 0x0002;
+ public const int PBT_APMQUERYSTANDBYFAILED = 0x0003;
+ public const int PBT_APMSUSPEND = 0x0004;
+ public const int PBT_APMSTANDBY = 0x0005;
+ public const int PBT_APMRESUMECRITICAL = 0x0006;
+ public const int PBT_APMRESUMESUSPEND = 0x0007;
+ public const int PBT_APMRESUMESTANDBY = 0x0008;
+ public const int PBT_APMBATTERYLOW = 0x0009;
+ public const int PBT_APMPOWERSTATUSCHANGE = 0x000A;
+ public const int PBT_APMOEMEVENT = 0x000B;
+
+ public const int PM_REMOVE = 0x0001;
+
+ public const int QS_KEY = 0x0001,
+ QS_MOUSEMOVE = 0x0002,
+ QS_MOUSEBUTTON = 0x0004,
+ QS_POSTMESSAGE = 0x0008,
+ QS_TIMER = 0x0010,
+ QS_PAINT = 0x0020,
+ QS_SENDMESSAGE = 0x0040,
+ QS_HOTKEY = 0x0080,
+ QS_ALLPOSTMESSAGE = 0x0100,
+ QS_MOUSE = QS_MOUSEMOVE | QS_MOUSEBUTTON,
+ QS_INPUT = QS_MOUSE | QS_KEY,
+ QS_ALLEVENTS = QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY,
+ QS_ALLINPUT = QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY | QS_SENDMESSAGE;
+
+ public const int SPI_GETBEEP = 1;
+ public const int SPI_SETBEEP = 2;
+ public const int SPI_GETMOUSE = 3;
+ public const int SPI_SETMOUSE = 4;
+ public const int SPI_GETBORDER = 5;
+ public const int SPI_SETBORDER = 6;
+ public const int SPI_GETKEYBOARDSPEED = 10;
+ public const int SPI_SETKEYBOARDSPEED = 11;
+ public const int SPI_LANGDRIVER = 12;
+ public const int SPI_ICONHORIZONTALSPACING = 13;
+ public const int SPI_GETSCREENSAVETIMEOUT = 14;
+ public const int SPI_SETSCREENSAVETIMEOUT = 15;
+ public const int SPI_GETSCREENSAVEACTIVE = 16;
+ public const int SPI_SETSCREENSAVEACTIVE = 17;
+ public const int SPI_GETGRIDGRANULARITY = 18;
+ public const int SPI_SETGRIDGRANULARITY = 19;
+ public const int SPI_SETDESKWALLPAPER = 20;
+ public const int SPI_SETDESKPATTERN = 21;
+ public const int SPI_GETKEYBOARDDELAY = 22;
+ public const int SPI_SETKEYBOARDDELAY = 23;
+ public const int SPI_ICONVERTICALSPACING = 24;
+ public const int SPI_GETICONTITLEWRAP = 25;
+ public const int SPI_SETICONTITLEWRAP = 26;
+ public const int SPI_GETMENUDROPALIGNMENT = 27;
+ public const int SPI_SETMENUDROPALIGNMENT = 28;
+ public const int SPI_SETDOUBLECLKWIDTH = 29;
+ public const int SPI_SETDOUBLECLKHEIGHT = 30;
+ public const int SPI_GETICONTITLELOGFONT = 31;
+ public const int SPI_SETDOUBLECLICKTIME = 32;
+ public const int SPI_SETMOUSEBUTTONSWAP = 33;
+ public const int SPI_SETICONTITLELOGFONT = 34;
+ public const int SPI_GETFASTTASKSWITCH = 35;
+ public const int SPI_SETFASTTASKSWITCH = 36;
+ public const int SPI_SETDRAGFULLWINDOWS = 37;
+ public const int SPI_GETDRAGFULLWINDOWS = 38;
+ public const int SPI_GETNONCLIENTMETRICS = 41;
+ public const int SPI_SETNONCLIENTMETRICS = 42;
+ public const int SPI_GETMINIMIZEDMETRICS = 43;
+ public const int SPI_SETMINIMIZEDMETRICS = 44;
+ public const int SPI_GETICONMETRICS = 45;
+ public const int SPI_SETICONMETRICS = 46;
+ public const int SPI_SETWORKAREA = 47;
+ public const int SPI_GETWORKAREA = 48;
+ public const int SPI_SETPENWINDOWS = 49;
+ public const int SPI_GETHIGHCONTRAST = 66;
+ public const int SPI_SETHIGHCONTRAST = 67;
+ public const int SPI_GETKEYBOARDPREF = 68;
+ public const int SPI_SETKEYBOARDPREF = 69;
+ public const int SPI_GETSCREENREADER = 70;
+ public const int SPI_SETSCREENREADER = 71;
+ public const int SPI_GETANIMATION = 72;
+ public const int SPI_SETANIMATION = 73;
+ public const int SPI_GETFONTSMOOTHING = 74;
+ public const int SPI_SETFONTSMOOTHING = 75;
+ public const int SPI_SETDRAGWIDTH = 76;
+ public const int SPI_SETDRAGHEIGHT = 77;
+ public const int SPI_SETHANDHELD = 78;
+ public const int SPI_GETLOWPOWERTIMEOUT = 79;
+ public const int SPI_GETPOWEROFFTIMEOUT = 80;
+ public const int SPI_SETLOWPOWERTIMEOUT = 81;
+ public const int SPI_SETPOWEROFFTIMEOUT = 82;
+ public const int SPI_GETLOWPOWERACTIVE = 83;
+ public const int SPI_GETPOWEROFFACTIVE = 84;
+ public const int SPI_SETLOWPOWERACTIVE = 85;
+ public const int SPI_SETPOWEROFFACTIVE = 86;
+ public const int SPI_SETCURSORS = 87;
+ public const int SPI_SETICONS = 88;
+ public const int SPI_GETDEFAULTINPUTLANG = 89;
+ public const int SPI_SETDEFAULTINPUTLANG = 90;
+ public const int SPI_SETLANGTOGGLE = 91;
+ public const int SPI_GETWINDOWSEXTENSION = 92;
+ public const int SPI_SETMOUSETRAILS = 93;
+ public const int SPI_GETMOUSETRAILS = 94;
+ public const int SPI_SETSCREENSAVERRUNNING = 97;
+ public const int SPI_SCREENSAVERRUNNING = SPI_SETSCREENSAVERRUNNING;
+ public const int SPI_GETFILTERKEYS = 50;
+ public const int SPI_SETFILTERKEYS = 51;
+ public const int SPI_GETTOGGLEKEYS = 52;
+ public const int SPI_SETTOGGLEKEYS = 53;
+ public const int SPI_GETMOUSEKEYS = 54;
+ public const int SPI_SETMOUSEKEYS = 55;
+ public const int SPI_GETSHOWSOUNDS = 56;
+ public const int SPI_SETSHOWSOUNDS = 57;
+ public const int SPI_GETSTICKYKEYS = 58;
+ public const int SPI_SETSTICKYKEYS = 59;
+ public const int SPI_GETACCESSTIMEOUT = 60;
+ public const int SPI_SETACCESSTIMEOUT = 61;
+ public const int SPI_GETSERIALKEYS = 62;
+ public const int SPI_SETSERIALKEYS = 63;
+ public const int SPI_GETSOUNDSENTRY = 64;
+ public const int SPI_SETSOUNDSENTRY = 65;
+ public const int SPI_GETSNAPTODEFBUTTON = 95;
+ public const int SPI_SETSNAPTODEFBUTTON = 96;
+ public const int SPI_GETMOUSEHOVERWIDTH = 98;
+ public const int SPI_SETMOUSEHOVERWIDTH = 99;
+ public const int SPI_GETMOUSEHOVERHEIGHT = 100;
+ public const int SPI_SETMOUSEHOVERHEIGHT = 101;
+ public const int SPI_GETMOUSEHOVERTIME = 102;
+ public const int SPI_SETMOUSEHOVERTIME = 103;
+ public const int SPI_GETWHEELSCROLLLINES = 104;
+ public const int SPI_SETWHEELSCROLLLINES = 105;
+ public const int SPI_GETMENUSHOWDELAY = 106;
+ public const int SPI_SETMENUSHOWDELAY = 107;
+ public const int SPI_GETSHOWIMEUI = 110;
+ public const int SPI_SETSHOWIMEUI = 111;
+ public const int SPI_GETMOUSESPEED = 112;
+ public const int SPI_SETMOUSESPEED = 113;
+ public const int SPI_GETSCREENSAVERRUNNING = 114;
+ public const int SPI_GETDESKWALLPAPER = 115;
+ public const int SPI_GETACTIVEWINDOWTRACKING = 0x1000;
+ public const int SPI_SETACTIVEWINDOWTRACKING = 0x1001;
+ public const int SPI_GETMENUANIMATION = 0x1002;
+ public const int SPI_SETMENUANIMATION = 0x1003;
+ public const int SPI_GETCOMBOBOXANIMATION = 0x1004;
+ public const int SPI_SETCOMBOBOXANIMATION = 0x1005;
+ public const int SPI_GETLISTBOXSMOOTHSCROLLING = 0x1006;
+ public const int SPI_SETLISTBOXSMOOTHSCROLLING = 0x1007;
+ public const int SPI_GETGRADIENTCAPTIONS = 0x1008;
+ public const int SPI_SETGRADIENTCAPTIONS = 0x1009;
+ public const int SPI_GETKEYBOARDCUES = 0x100A;
+ public const int SPI_SETKEYBOARDCUES = 0x100B;
+ public const int SPI_GETMENUUNDERLINES = SPI_GETKEYBOARDCUES;
+ public const int SPI_SETMENUUNDERLINES = SPI_SETKEYBOARDCUES;
+ public const int SPI_GETACTIVEWNDTRKZORDER = 0x100C;
+ public const int SPI_SETACTIVEWNDTRKZORDER = 0x100D;
+ public const int SPI_GETHOTTRACKING = 0x100E;
+ public const int SPI_SETHOTTRACKING = 0x100F;
+ public const int SPI_GETMENUFADE = 0x1012;
+ public const int SPI_SETMENUFADE = 0x1013;
+ public const int SPI_GETSELECTIONFADE = 0x1014;
+ public const int SPI_SETSELECTIONFADE = 0x1015;
+ public const int SPI_GETTOOLTIPANIMATION = 0x1016;
+ public const int SPI_SETTOOLTIPANIMATION = 0x1017;
+ public const int SPI_GETTOOLTIPFADE = 0x1018;
+ public const int SPI_SETTOOLTIPFADE = 0x1019;
+ public const int SPI_GETCURSORSHADOW = 0x101A;
+ public const int SPI_SETCURSORSHADOW = 0x101B;
+ public const int SPI_GETUIEFFECTS = 0x103E;
+ public const int SPI_SETUIEFFECTS = 0x103F;
+ public const int SPI_GETFOREGROUNDLOCKTIMEOUT = 0x2000;
+ public const int SPI_SETFOREGROUNDLOCKTIMEOUT = 0x2001;
+ public const int SPI_GETACTIVEWNDTRKTIMEOUT = 0x2002;
+ public const int SPI_SETACTIVEWNDTRKTIMEOUT = 0x2003;
+ public const int SPI_GETFOREGROUNDFLASHCOUNT = 0x2004;
+ public const int SPI_SETFOREGROUNDFLASHCOUNT = 0x2005;
+ public const int SPI_GETCARETWIDTH = 0x2006;
+ public const int SPI_SETCARETWIDTH = 0x2007;
+
+ public const int WAIT_TIMEOUT = 0x00000102;
+
+ public const int WM_CLOSE = 0x0010;
+ public const int WM_QUERYENDSESSION = 0x0011;
+ public const int WM_QUIT = 0x0012;
+ public const int WM_SYSCOLORCHANGE = 0x0015;
+ public const int WM_ENDSESSION = 0x0016;
+ public const int WM_SETTINGCHANGE = 0x001A;
+ public const int WM_FONTCHANGE = 0x001D;
+ public const int WM_TIMECHANGE = 0x001E;
+ public const int WM_COMPACTING = 0x0041;
+ public const int WM_DISPLAYCHANGE = 0x007E;
+ public const int WM_TIMER = 0x0113;
+ public const int WM_POWERBROADCAST = 0x0218;
+ public const int WM_WTSSESSION_CHANGE = 0x02B1;
+ public const int WM_PALETTECHANGED = 0x0311;
+ public const int WM_THEMECHANGED = 0x031A;
+ public const int WM_USER = 0x0400;
+ public const int WM_CREATETIMER = WM_USER + 1;
+ public const int WM_KILLTIMER = WM_USER + 2;
+ public const int WM_REFLECT = WM_USER + 0x1C00;
+
+ public const int WS_POPUP = unchecked((int)0x80000000);
+
+ public const int WSF_VISIBLE = 0x0001;
+
+ public const int UOI_FLAGS = 1;
+
+ }
+}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.CreateWindowEx.cs b/src/Common/src/Interop/Windows/user32/Interop.CreateWindowEx.cs
new file mode 100644
index 0000000000..f4b41b996b
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.CreateWindowEx.cs
@@ -0,0 +1,16 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ [DllImport(Libraries.User32, CharSet=CharSet.Unicode, SetLastError=true, BestFitMapping=true, ExactSpelling =true)]
+ public static extern IntPtr CreateWindowExW(int exStyle, string lpszClassName, string lpszWindowName, int style, int x, int y, int width,
+ int height, IntPtr hWndParent, IntPtr hMenu, IntPtr hInst, IntPtr pvParam);
+ }
+}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.DefWindowProc.cs b/src/Common/src/Interop/Windows/user32/Interop.DefWindowProc.cs
new file mode 100644
index 0000000000..f513e3dc74
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.DefWindowProc.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ [DllImport(Libraries.User32, CharSet = CharSet.Unicode, ExactSpelling = true)]
+ public static extern IntPtr DefWindowProcW(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
+ }
+}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.DestroyWindow.cs b/src/Common/src/Interop/Windows/user32/Interop.DestroyWindow.cs
new file mode 100644
index 0000000000..d9bc51ae85
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.DestroyWindow.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ [DllImport(Libraries.User32, ExactSpelling = true)]
+ public static extern bool DestroyWindow(IntPtr hWnd);
+ }
+}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.DispatchMessage.cs b/src/Common/src/Interop/Windows/user32/Interop.DispatchMessage.cs
new file mode 100644
index 0000000000..07b448c3fb
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.DispatchMessage.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ [DllImport(Libraries.User32, CharSet = CharSet.Unicode, ExactSpelling = true)]
+ public static extern int DispatchMessageW([In] ref MSG msg);
+ }
+}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.FindWindow.cs b/src/Common/src/Interop/Windows/user32/Interop.FindWindow.cs
new file mode 100644
index 0000000000..809beafc73
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.FindWindow.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ [DllImport(Libraries.User32, CharSet=CharSet.Auto, ExactSpelling = true)]
+ public static extern IntPtr FindWindowW(string lpClassName, string lpWindowName);
+ }
+}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.GetClassInfo.cs b/src/Common/src/Interop/Windows/user32/Interop.GetClassInfo.cs
new file mode 100644
index 0000000000..2cda3679fe
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.GetClassInfo.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ [DllImport(Libraries.User32, CharSet=CharSet.Unicode, ExactSpelling = true)]
+ public static extern bool GetClassInfoW(IntPtr hInst, string lpszClass, [In, Out] WNDCLASS_I wc);
+ }
+}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.GetProcessWindowStation.cs b/src/Common/src/Interop/Windows/user32/Interop.GetProcessWindowStation.cs
new file mode 100644
index 0000000000..7e16cbe783
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.GetProcessWindowStation.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ [DllImport(Libraries.User32, ExactSpelling=true)]
+ internal static extern IntPtr GetProcessWindowStation();
+ }
+}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.GetUserObjectInformation.cs b/src/Common/src/Interop/Windows/user32/Interop.GetUserObjectInformation.cs
new file mode 100644
index 0000000000..82df65c8f1
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.GetUserObjectInformation.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ [DllImport(Libraries.User32, SetLastError=true, CharSet = CharSet.Unicode, ExactSpelling = true)]
+ public static extern bool GetUserObjectInformationW(IntPtr hObj, int nIndex, [MarshalAs(UnmanagedType.LPStruct)] USEROBJECTFLAGS pvBuffer, int nLength, ref int lpnLengthNeeded);
+ }
+}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.GetWindowThreadProcessId.cs b/src/Common/src/Interop/Windows/user32/Interop.GetWindowThreadProcessId.cs
index e5d5aebfec..9f69b32ef2 100644
--- a/src/Common/src/Interop/Windows/user32/Interop.GetWindowThreadProcessId.cs
+++ b/src/Common/src/Interop/Windows/user32/Interop.GetWindowThreadProcessId.cs
@@ -9,7 +9,10 @@ internal partial class Interop
{
internal partial class User32
{
- [DllImport(Libraries.User32)]
+ [DllImport(Libraries.User32, ExactSpelling = true)]
public static extern int GetWindowThreadProcessId(IntPtr handle, out int processId);
+
+ [DllImport(Libraries.User32, ExactSpelling = true)]
+ public static extern int GetWindowThreadProcessId(HandleRef handle, out int processId);
}
}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.IsWindow.cs b/src/Common/src/Interop/Windows/user32/Interop.IsWindow.cs
new file mode 100644
index 0000000000..be4c2f75b5
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.IsWindow.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ [DllImport(Libraries.User32, ExactSpelling = true)]
+ public static extern bool IsWindow(IntPtr hWnd);
+ }
+}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.KillTimer.cs b/src/Common/src/Interop/Windows/user32/Interop.KillTimer.cs
new file mode 100644
index 0000000000..76a49229a6
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.KillTimer.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ [DllImport(Libraries.User32, ExactSpelling = true)]
+ public static extern bool KillTimer(IntPtr hwnd, IntPtr idEvent);
+ }
+}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.MSG.cs b/src/Common/src/Interop/Windows/user32/Interop.MSG.cs
new file mode 100644
index 0000000000..871d772723
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.MSG.cs
@@ -0,0 +1,23 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ [StructLayout(LayoutKind.Sequential)]
+ public struct MSG {
+ public IntPtr hwnd;
+ public int message;
+ public IntPtr wParam;
+ public IntPtr lParam;
+ public int time;
+ public int pt_x;
+ public int pt_y;
+ }
+ }
+}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.MsgWaitForMultipleObjectsEx.cs b/src/Common/src/Interop/Windows/user32/Interop.MsgWaitForMultipleObjectsEx.cs
new file mode 100644
index 0000000000..6d3a58a27b
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.MsgWaitForMultipleObjectsEx.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ [DllImport(Libraries.User32, ExactSpelling = true)]
+ public static extern int MsgWaitForMultipleObjectsEx(int nCount, IntPtr pHandles, int dwMilliseconds, int dwWakeMask, int dwFlags);
+ }
+}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.PeekMessage.cs b/src/Common/src/Interop/Windows/user32/Interop.PeekMessage.cs
new file mode 100644
index 0000000000..5b00c16585
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.PeekMessage.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ [DllImport(Libraries.User32, CharSet = CharSet.Unicode, ExactSpelling = true)]
+ public static extern bool PeekMessageW([In, Out] ref MSG msg, IntPtr hwnd, int msgMin, int msgMax, int remove);
+ }
+}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.PostMessage.cs b/src/Common/src/Interop/Windows/user32/Interop.PostMessage.cs
index e9e1a54e85..81e95be399 100644
--- a/src/Common/src/Interop/Windows/user32/Interop.PostMessage.cs
+++ b/src/Common/src/Interop/Windows/user32/Interop.PostMessage.cs
@@ -9,7 +9,10 @@ internal partial class Interop
{
internal partial class User32
{
- [DllImport(Libraries.User32, EntryPoint = "PostMessageW")]
- public static extern int PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
+ [DllImport(Libraries.User32, CharSet = CharSet.Unicode, ExactSpelling = true)]
+ public static extern int PostMessageW(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
+
+ [DllImport(Libraries.User32, CharSet = CharSet.Unicode, ExactSpelling = true)]
+ public static extern int PostMessageW(HandleRef hwnd, int msg, IntPtr wparam, IntPtr lparam);
}
}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.RegisterClass.cs b/src/Common/src/Interop/Windows/user32/Interop.RegisterClass.cs
new file mode 100644
index 0000000000..f501a8c8af
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.RegisterClass.cs
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ [DllImport(Libraries.User32, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]
+ public static extern short RegisterClassW(WNDCLASS wc);
+ }
+}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.RegisterWindowMessage.cs b/src/Common/src/Interop/Windows/user32/Interop.RegisterWindowMessage.cs
new file mode 100644
index 0000000000..a843030a3c
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.RegisterWindowMessage.cs
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ [DllImport(Libraries.User32, CharSet = CharSet.Unicode, ExactSpelling = true)]
+ public static extern int RegisterWindowMessageW(string msg);
+ }
+}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.SendMessage.cs b/src/Common/src/Interop/Windows/user32/Interop.SendMessage.cs
new file mode 100644
index 0000000000..1541d74826
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.SendMessage.cs
@@ -0,0 +1,18 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ [DllImport(Libraries.User32, CharSet = CharSet.Unicode, ExactSpelling = true)]
+ public static extern IntPtr SendMessageW(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
+
+ [DllImport(Libraries.User32, CharSet = CharSet.Unicode, ExactSpelling = true)]
+ public static extern IntPtr SendMessageW(HandleRef hWnd, int msg, IntPtr wParam, IntPtr lParam);
+ }
+}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.SetClassLong.cs b/src/Common/src/Interop/Windows/user32/Interop.SetClassLong.cs
new file mode 100644
index 0000000000..ef56107e88
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.SetClassLong.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ [DllImport(Libraries.User32, CharSet = CharSet.Unicode, ExactSpelling = true)]
+ public static extern IntPtr SetClassLongW(IntPtr hwnd, int nIndex, IntPtr dwNewLong);
+ }
+}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.SetClassLongPtr.cs b/src/Common/src/Interop/Windows/user32/Interop.SetClassLongPtr.cs
new file mode 100644
index 0000000000..fe875d0ce6
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.SetClassLongPtr.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ [DllImport(Libraries.User32, CharSet = CharSet.Unicode, ExactSpelling = true)]
+ public static extern IntPtr SetClassLongPtrW(IntPtr hwnd, int nIndex, IntPtr dwNewLong);
+ }
+}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.SetTimer.cs b/src/Common/src/Interop/Windows/user32/Interop.SetTimer.cs
new file mode 100644
index 0000000000..b5fdb6b700
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.SetTimer.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ [DllImport(Libraries.User32, ExactSpelling = true)]
+ public static extern IntPtr SetTimer(IntPtr hWnd, IntPtr nIDEvent, int uElapse, IntPtr lpTimerProc);
+ }
+}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.SetWindowLong.cs b/src/Common/src/Interop/Windows/user32/Interop.SetWindowLong.cs
new file mode 100644
index 0000000000..b536f77668
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.SetWindowLong.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ [DllImport(Libraries.User32, CharSet = CharSet.Unicode, ExactSpelling = true)]
+ public static extern IntPtr SetWindowLongW(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
+ }
+}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.SetWindowLongPtr.cs b/src/Common/src/Interop/Windows/user32/Interop.SetWindowLongPtr.cs
new file mode 100644
index 0000000000..3dfb27173c
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.SetWindowLongPtr.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ [DllImport(Libraries.User32, CharSet = CharSet.Unicode, ExactSpelling = true)]
+ public static extern IntPtr SetWindowLongPtrW(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
+ }
+}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.TranslateMessage.cs b/src/Common/src/Interop/Windows/user32/Interop.TranslateMessage.cs
new file mode 100644
index 0000000000..2fef33e6c1
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.TranslateMessage.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ [DllImport(Libraries.User32, ExactSpelling = true)]
+ public static extern bool TranslateMessage([In, Out] ref MSG msg);
+ }
+}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.USEROBJECTFLAGS.cs b/src/Common/src/Interop/Windows/user32/Interop.USEROBJECTFLAGS.cs
new file mode 100644
index 0000000000..38f4cc3e97
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.USEROBJECTFLAGS.cs
@@ -0,0 +1,18 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ [StructLayout(LayoutKind.Sequential)]
+ internal class USEROBJECTFLAGS {
+ public int fInherit = 0;
+ public int fReserved = 0;
+ public int dwFlags = 0;
+ }
+ }
+}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.UnregisterClass.cs b/src/Common/src/Interop/Windows/user32/Interop.UnregisterClass.cs
new file mode 100644
index 0000000000..af4bcb357c
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.UnregisterClass.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ [DllImport(Libraries.User32, CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]
+ public static extern short UnregisterClassW(string lpClassName, IntPtr hInstance);
+ }
+}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.WNDCLASS.cs b/src/Common/src/Interop/Windows/user32/Interop.WNDCLASS.cs
new file mode 100644
index 0000000000..dc9730b96a
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.WNDCLASS.cs
@@ -0,0 +1,40 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
+ internal class WNDCLASS_I {
+ public int style;
+ public IntPtr lpfnWndProc;
+ public int cbClsExtra = 0;
+ public int cbWndExtra = 0;
+ public IntPtr hInstance = IntPtr.Zero;
+ public IntPtr hIcon = IntPtr.Zero;
+ public IntPtr hCursor = IntPtr.Zero;
+ public IntPtr hbrBackground = IntPtr.Zero;
+ public IntPtr lpszMenuName = IntPtr.Zero;
+ public IntPtr lpszClassName = IntPtr.Zero;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
+ internal class WNDCLASS {
+ public int style;
+ public WndProc lpfnWndProc;
+ public int cbClsExtra = 0;
+ public int cbWndExtra = 0;
+ public IntPtr hInstance = IntPtr.Zero;
+ public IntPtr hIcon = IntPtr.Zero;
+ public IntPtr hCursor = IntPtr.Zero;
+ public IntPtr hbrBackground = IntPtr.Zero;
+ public string lpszMenuName = null;
+ public string lpszClassName = null;
+ }
+ }
+}
diff --git a/src/Common/src/Interop/Windows/user32/Interop.WndProc.cs b/src/Common/src/Interop/Windows/user32/Interop.WndProc.cs
new file mode 100644
index 0000000000..d4a9cda3a3
--- /dev/null
+++ b/src/Common/src/Interop/Windows/user32/Interop.WndProc.cs
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+internal partial class Interop
+{
+ internal partial class User32
+ {
+ public delegate IntPtr WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
+ }
+}
diff --git a/src/Common/src/Interop/Windows/winhttp/Interop.SafeWinHttpHandle.cs b/src/Common/src/Interop/Windows/winhttp/Interop.SafeWinHttpHandle.cs
index f04412fbc5..8342b8dd28 100644
--- a/src/Common/src/Interop/Windows/winhttp/Interop.SafeWinHttpHandle.cs
+++ b/src/Common/src/Interop/Windows/winhttp/Interop.SafeWinHttpHandle.cs
@@ -12,9 +12,6 @@ internal partial class Interop
{
internal partial class WinHttp
{
- // Issue 2501: Fold SafeWinHttpHandleWithCallback and SafeWinHttpHandle into a single type.
- // SafeWinHttpHandleWithCallback is incorrectly overriding the Dispose(bool disposing) method
- // and will be fixed as part of merging the classes.
internal class SafeWinHttpHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private SafeWinHttpHandle _parentHandle = null;
@@ -59,43 +56,5 @@ internal partial class Interop
return Interop.WinHttp.WinHttpCloseHandle(handle);
}
}
-
- internal sealed class SafeWinHttpHandleWithCallback : SafeWinHttpHandle
- {
- // Add a reference to this object so that the AppDomain doesn't get unloaded before the last WinHttp callback.
- public void AttachCallback()
- {
- bool ignore = false;
- DangerousAddRef(ref ignore);
- }
-
- public void DetachCallback()
- {
- DangerousRelease();
- }
-
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- // We need to initiate the asynchronous process of closing the WinHttp handle:
- // 1. Ensure that all other WinHttp function calls for this handle have returned.
- // 2. Call WinHttpCloseHandle.
- // 3. Wait for WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING in the callback.
- // On this event, call DetachCallback.
- //
- // WinHttp guarantees that no other calls to the callback are made for this handle after
- // WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING has been received.
- // Holding the reference to the SafeHandle object ensures that the appdomain where the SafeHandle
- // lives until it is guaranteed that no further callback calls are made from the native (WinHttp) side.
- Interop.WinHttp.WinHttpCloseHandle(handle);
- }
- }
-
- protected override bool ReleaseHandle()
- {
- return base.ReleaseHandle();
- }
- }
}
}
diff --git a/src/Common/src/Interop/Windows/winhttp/Interop.winhttp.cs b/src/Common/src/Interop/Windows/winhttp/Interop.winhttp.cs
index 4230bf7fd1..40c29fe741 100644
--- a/src/Common/src/Interop/Windows/winhttp/Interop.winhttp.cs
+++ b/src/Common/src/Interop/Windows/winhttp/Interop.winhttp.cs
@@ -29,14 +29,6 @@ internal partial class Interop
ushort serverPort,
uint reserved);
- // NOTE: except for the return type, this refers to the same function as WinHttpConnect.
- [DllImport(Interop.Libraries.WinHttp, EntryPoint = "WinHttpConnect", CharSet = CharSet.Unicode, SetLastError = true)]
- public static extern SafeWinHttpHandleWithCallback WinHttpConnectWithCallback(
- SafeWinHttpHandle sessionHandle,
- string serverName,
- ushort serverPort,
- uint reserved);
-
[DllImport(Interop.Libraries.WinHttp, CharSet = CharSet.Unicode, SetLastError = true)]
public static extern SafeWinHttpHandle WinHttpOpenRequest(
SafeWinHttpHandle connectHandle,
@@ -47,17 +39,6 @@ internal partial class Interop
string acceptTypes,
uint flags);
- // NOTE: except for the return type, this refers to the same function as WinHttpOpenRequest.
- [DllImport(Interop.Libraries.WinHttp, EntryPoint = "WinHttpOpenRequest", CharSet = CharSet.Unicode, SetLastError = true)]
- public static extern SafeWinHttpHandleWithCallback WinHttpOpenRequestWithCallback(
- SafeWinHttpHandle connectHandle,
- string verb,
- string objectName,
- string version,
- string referrer,
- string acceptTypes,
- uint flags);
-
[DllImport(Interop.Libraries.WinHttp, CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool WinHttpAddRequestHeaders(
@@ -256,61 +237,5 @@ internal partial class Interop
WINHTTP_STATUS_CALLBACK callback,
uint notificationFlags,
IntPtr reserved);
-
- [DllImport(Interop.Libraries.WinHttp, CharSet = CharSet.Unicode, SetLastError = true)]
- public static extern SafeWinHttpHandleWithCallback WinHttpWebSocketCompleteUpgrade(
- SafeWinHttpHandle requestHandle,
- IntPtr context);
-
- [DllImport(Interop.Libraries.WinHttp, CharSet = CharSet.Unicode, SetLastError = false)]
- public static extern uint WinHttpWebSocketSend(
- SafeWinHttpHandle webSocketHandle,
- WINHTTP_WEB_SOCKET_BUFFER_TYPE bufferType,
- IntPtr buffer,
- uint bufferLength);
-
- [DllImport(Interop.Libraries.WinHttp, CharSet = CharSet.Unicode, SetLastError = false)]
- public static extern uint WinHttpWebSocketReceive(
- SafeWinHttpHandle webSocketHandle,
- IntPtr buffer,
- uint bufferLength,
- out uint bytesRead,
- out WINHTTP_WEB_SOCKET_BUFFER_TYPE bufferType);
-
- [DllImport(Interop.Libraries.WinHttp, CharSet = CharSet.Unicode, SetLastError = false)]
- public static extern uint WinHttpWebSocketShutdown(
- SafeWinHttpHandle webSocketHandle,
- ushort status,
- byte[] reason,
- uint reasonLength);
-
- [DllImport(Interop.Libraries.WinHttp, CharSet = CharSet.Unicode, SetLastError = false)]
- public static extern uint WinHttpWebSocketShutdown(
- SafeWinHttpHandle webSocketHandle,
- ushort status,
- IntPtr reason,
- uint reasonLength);
-
- [DllImport(Interop.Libraries.WinHttp, CharSet = CharSet.Unicode, SetLastError = false)]
- public static extern uint WinHttpWebSocketClose(
- SafeWinHttpHandle webSocketHandle,
- ushort status,
- byte[] reason,
- uint reasonLength);
-
- [DllImport(Interop.Libraries.WinHttp, CharSet = CharSet.Unicode, SetLastError = false)]
- public static extern uint WinHttpWebSocketClose(
- SafeWinHttpHandle webSocketHandle,
- ushort status,
- IntPtr reason,
- uint reasonLength);
-
- [DllImport(Interop.Libraries.WinHttp, CharSet = CharSet.Unicode, SetLastError = false)]
- public static extern uint WinHttpWebSocketQueryCloseStatus(
- SafeWinHttpHandle webSocketHandle,
- out ushort status,
- byte[] reason,
- uint reasonLength,
- out uint reasonLengthConsumed);
}
}
diff --git a/src/Common/src/Interop/Windows/wtsapi32/Interop.Constants.cs b/src/Common/src/Interop/Windows/wtsapi32/Interop.Constants.cs
new file mode 100644
index 0000000000..91bf9a3aad
--- /dev/null
+++ b/src/Common/src/Interop/Windows/wtsapi32/Interop.Constants.cs
@@ -0,0 +1,21 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+internal partial class Interop
+{
+ internal partial class Wtsapi32
+ {
+ public const int NOTIFY_FOR_THIS_SESSION = 0x0;
+
+ public const int WTS_CONSOLE_CONNECT = 0x1;
+ public const int WTS_CONSOLE_DISCONNECT = 0x2;
+ public const int WTS_REMOTE_CONNECT = 0x3;
+ public const int WTS_REMOTE_DISCONNECT = 0x4;
+ public const int WTS_SESSION_LOGON = 0x5;
+ public const int WTS_SESSION_LOGOFF = 0x6;
+ public const int WTS_SESSION_LOCK = 0x7;
+ public const int WTS_SESSION_UNLOCK = 0x8;
+ public const int WTS_SESSION_REMOTE_CONTROL = 0x9;
+ }
+}
diff --git a/src/Common/src/Interop/Windows/wtsapi32/Interop.WTSRegisterSessionNotification.cs b/src/Common/src/Interop/Windows/wtsapi32/Interop.WTSRegisterSessionNotification.cs
new file mode 100644
index 0000000000..2fe4d593c2
--- /dev/null
+++ b/src/Common/src/Interop/Windows/wtsapi32/Interop.WTSRegisterSessionNotification.cs
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class Wtsapi32
+ {
+ [DllImport(Libraries.Wtsapi32, ExactSpelling = true)]
+ public static extern bool WTSRegisterSessionNotification(HandleRef hWnd, int dwFlags);
+ }
+}
diff --git a/src/Common/src/Interop/Windows/wtsapi32/Interop.WTSUnRegisterSessionNotification.cs b/src/Common/src/Interop/Windows/wtsapi32/Interop.WTSUnRegisterSessionNotification.cs
new file mode 100644
index 0000000000..c1d6b384f9
--- /dev/null
+++ b/src/Common/src/Interop/Windows/wtsapi32/Interop.WTSUnRegisterSessionNotification.cs
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+
+internal partial class Interop
+{
+ internal partial class Wtsapi32
+ {
+ [DllImport(Libraries.Wtsapi32, ExactSpelling = true)]
+ public static extern bool WTSUnRegisterSessionNotification(HandleRef hWnd);
+ }
+}
diff --git a/src/System.Security.Cryptography.OpenSsl/src/System/Security/Cryptography/SafeEvpPKeyHandle.Unix.cs b/src/Common/src/Microsoft/Win32/SafeHandles/SafeEvpPKeyHandle.Unix.cs
index ed69307a58..c706b1ce88 100644
--- a/src/System.Security.Cryptography.OpenSsl/src/System/Security/Cryptography/SafeEvpPKeyHandle.Unix.cs
+++ b/src/Common/src/Microsoft/Win32/SafeHandles/SafeEvpPKeyHandle.Unix.cs
@@ -7,7 +7,12 @@ using System.Runtime.InteropServices;
namespace System.Security.Cryptography
{
- public sealed class SafeEvpPKeyHandle : SafeHandle
+#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS
+ internal
+#else
+ public
+#endif
+ sealed class SafeEvpPKeyHandle : SafeHandle
{
internal static readonly SafeEvpPKeyHandle InvalidHandle = new SafeEvpPKeyHandle();
diff --git a/src/Common/src/Microsoft/Win32/SafeHandles/SafeEvpPkeyCtxHandle.Unix.cs b/src/Common/src/Microsoft/Win32/SafeHandles/SafeEvpPkeyCtxHandle.Unix.cs
new file mode 100644
index 0000000000..f6b0ef2777
--- /dev/null
+++ b/src/Common/src/Microsoft/Win32/SafeHandles/SafeEvpPkeyCtxHandle.Unix.cs
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace Microsoft.Win32.SafeHandles
+{
+ internal sealed class SafeEvpPKeyCtxHandle : SafeHandle
+ {
+ private SafeEvpPKeyCtxHandle()
+ : base(IntPtr.Zero, ownsHandle: true)
+ {
+ }
+
+ public SafeEvpPKeyCtxHandle(IntPtr handle, bool ownsHandle)
+ : base(handle, ownsHandle)
+ {
+ }
+
+ protected override bool ReleaseHandle()
+ {
+ Interop.Crypto.EvpPKeyCtxDestroy(handle);
+ SetHandle(IntPtr.Zero);
+ return true;
+ }
+
+ public override bool IsInvalid => handle == IntPtr.Zero;
+ }
+}
diff --git a/src/Common/src/System/Collections/Generic/LargeArrayBuilder.cs b/src/Common/src/System/Collections/Generic/LargeArrayBuilder.cs
index ff29326046..c0f441909d 100644
--- a/src/Common/src/System/Collections/Generic/LargeArrayBuilder.cs
+++ b/src/Common/src/System/Collections/Generic/LargeArrayBuilder.cs
@@ -124,14 +124,30 @@ namespace System.Collections.Generic
{
Debug.Assert(_maxCapacity > _count);
- if (_index == _current.Length)
+ int index = _index;
+ T[] current = _current;
+
+ // Must be >= and not == to enable range check elimination
+ if ((uint)index >= (uint)current.Length)
{
- AllocateBuffer();
+ AddWithBufferAllocation(item);
}
-
- _current[_index++] = item;
+ else
+ {
+ current[index] = item;
+ _index = index + 1;
+ }
+
_count++;
}
+
+ // Non-inline to improve code quality as uncommon path
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private void AddWithBufferAllocation(T item)
+ {
+ AllocateBuffer();
+ _current[_index++] = item;
+ }
/// <summary>
/// Adds a range of items to this builder.
@@ -155,17 +171,18 @@ namespace System.Collections.Generic
while (enumerator.MoveNext())
{
- if (index == destination.Length)
+ T item = enumerator.Current;
+
+ if ((uint)index >= (uint)destination.Length)
{
- // No more space in this buffer. Resize.
- _count += index - _index;
- _index = index;
- AllocateBuffer();
- destination = _current;
- index = _index; // May have been reset to 0
+ AddWithBufferAllocation(item, ref destination, ref index);
}
-
- destination[index++] = enumerator.Current;
+ else
+ {
+ destination[index] = item;
+ }
+
+ index++;
}
// Final update to _count and _index.
@@ -174,6 +191,18 @@ namespace System.Collections.Generic
}
}
+ // Non-inline to improve code quality as uncommon path
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private void AddWithBufferAllocation(T item, ref T[] destination, ref int index)
+ {
+ _count += index - _index;
+ _index = index;
+ AllocateBuffer();
+ destination = _current;
+ index = _index;
+ _current[index] = item;
+ }
+
/// <summary>
/// Copies the contents of this builder to the specified array.
/// </summary>
diff --git a/src/Common/src/System/Collections/HashHelpers.cs b/src/Common/src/System/Collections/HashHelpers.cs
index 661e9faf2e..68a7384099 100644
--- a/src/Common/src/System/Collections/HashHelpers.cs
+++ b/src/Common/src/System/Collections/HashHelpers.cs
@@ -2,27 +2,18 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-/*============================================================
-**
-**
-**
-**
-** Purpose: Hash table implementation
-**
-**
-===========================================================*/
-using System;
using System.Diagnostics;
-using System.Runtime;
-using System.Runtime.CompilerServices;
-using System.Runtime.Serialization;
-using System.Threading;
namespace System.Collections
{
internal static class HashHelpers
{
+ // This is the maximum prime smaller than Array.MaxArrayLength
+ public const int MaxPrimeArrayLength = 0x7FEFFFFD;
+
+ private const int HashPrime = 101;
+
// Table of prime numbers to use as hash table sizes.
// A typical resize algorithm would pick the smallest prime number in this array
// that is larger than twice the previous capacity.
@@ -34,16 +25,29 @@ namespace System.Collections
// hashtable operations such as add. Having a prime guarantees that double
// hashing does not lead to infinite loops. IE, your hash function will be
// h1(key) + i*h2(key), 0 <= i < size. h2 and the size must be relatively prime.
+ // We prefer the low computation costs of higher prime numbers over the increased
+ // memory allocation of a fixed prime number i.e. when right sizing a HashSet.
public static readonly int[] primes = {
3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919,
1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591,
17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437,
187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,
- 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369, 8639249, 10367101,
- 12440537, 14928671, 17914409, 21497293, 25796759, 30956117, 37147349, 44576837, 53492207, 64190669,
- 77028803, 92434613, 110921543, 133105859, 159727031, 191672443, 230006941, 276008387, 331210079,
- 397452101, 476942527, 572331049, 686797261, 824156741, 988988137, 1186785773, 1424142949, 1708971541,
- 2050765853, MaxPrimeArrayLength };
+ 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369 };
+
+ public static bool IsPrime(int candidate)
+ {
+ if ((candidate & 1) != 0)
+ {
+ int limit = (int)Math.Sqrt(candidate);
+ for (int divisor = 3; divisor <= limit; divisor += 2)
+ {
+ if ((candidate % divisor) == 0)
+ return false;
+ }
+ return true;
+ }
+ return (candidate == 2);
+ }
public static int GetPrime(int min)
{
@@ -56,6 +60,13 @@ namespace System.Collections
if (prime >= min) return prime;
}
+ //outside of our predefined table.
+ //compute the hard way.
+ for (int i = (min | 1); i < int.MaxValue; i += 2)
+ {
+ if (IsPrime(i) && ((i - 1) % HashPrime != 0))
+ return i;
+ }
return min;
}
@@ -64,7 +75,7 @@ namespace System.Collections
{
int newSize = 2 * oldSize;
- // Allow the hashtables to grow to maximum possible size (~2G elements) before encoutering capacity overflow.
+ // Allow the hashtables to grow to maximum possible size (~2G elements) before encountering capacity overflow.
// Note that this check works even when _items.Length overflowed thanks to the (uint) cast
if ((uint)newSize > MaxPrimeArrayLength && MaxPrimeArrayLength > oldSize)
{
@@ -74,9 +85,5 @@ namespace System.Collections
return GetPrime(newSize);
}
-
-
- // This is the maximum prime smaller than Array.MaxArrayLength
- public const int MaxPrimeArrayLength = 0x7FEFFFFD;
}
}
diff --git a/src/Common/src/System/Data/Common/AdapterUtil.Drivers.cs b/src/Common/src/System/Data/Common/AdapterUtil.Drivers.cs
new file mode 100644
index 0000000000..c8666a2c69
--- /dev/null
+++ b/src/Common/src/System/Data/Common/AdapterUtil.Drivers.cs
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading;
+
+namespace System.Data.Common
+{
+ internal static partial class ADP
+ {
+
+ internal static Timer UnsafeCreateTimer(TimerCallback callback, object state, int dueTime, int period)
+ {
+ // Don't capture the current ExecutionContext and its AsyncLocals onto
+ // a global timer causing them to live forever
+ bool restoreFlow = false;
+ try
+ {
+ if (!ExecutionContext.IsFlowSuppressed())
+ {
+ ExecutionContext.SuppressFlow();
+ restoreFlow = true;
+ }
+
+ return new Timer(callback, state, dueTime, period);
+ }
+ finally
+ {
+ // Restore the current ExecutionContext
+ if (restoreFlow)
+ ExecutionContext.RestoreFlow();
+ }
+ }
+ }
+}
diff --git a/src/Common/src/System/Data/Common/AdapterUtil.cs b/src/Common/src/System/Data/Common/AdapterUtil.cs
index 575e22f25d..d15c73c799 100644
--- a/src/Common/src/System/Data/Common/AdapterUtil.cs
+++ b/src/Common/src/System/Data/Common/AdapterUtil.cs
@@ -485,12 +485,9 @@ namespace System.Data.Common
return ArgumentOutOfRange(SR.ADP_InvalidSeekOrigin, parameterName);
}
- internal static readonly bool IsWindowsNT = (PlatformID.Win32NT == Environment.OSVersion.Platform);
- internal static readonly bool IsPlatformNT5 = (ADP.IsWindowsNT && (Environment.OSVersion.Version.Major >= 5));
-
internal static void SetCurrentTransaction(Transaction transaction)
{
Transaction.Current = transaction;
}
}
-} \ No newline at end of file
+}
diff --git a/src/Common/src/System/Data/ProviderBase/DbConnectionClosed.cs b/src/Common/src/System/Data/ProviderBase/DbConnectionClosed.cs
new file mode 100644
index 0000000000..1238beb3cc
--- /dev/null
+++ b/src/Common/src/System/Data/ProviderBase/DbConnectionClosed.cs
@@ -0,0 +1,138 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Data.Common;
+using System.Diagnostics;
+using System.Threading.Tasks;
+
+namespace System.Data.ProviderBase
+{
+ abstract internal partial class DbConnectionClosed : DbConnectionInternal
+ {
+ // Construct an "empty" connection
+ protected DbConnectionClosed(ConnectionState state, bool hidePassword, bool allowSetConnectionString) : base(state, hidePassword, allowSetConnectionString)
+ {
+ }
+
+ public override string ServerVersion => throw ADP.ClosedConnectionError();
+
+ public override DbTransaction BeginTransaction(IsolationLevel il) => throw ADP.ClosedConnectionError();
+
+ public override void ChangeDatabase(string database) => throw ADP.ClosedConnectionError();
+
+ internal override void CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory)
+ {
+ // not much to do here...
+ }
+
+ protected override void Deactivate() => ADP.ClosedConnectionError();
+
+ protected internal override DataTable GetSchema(DbConnectionFactory factory, DbConnectionPoolGroup poolGroup, DbConnection outerConnection, string collectionName, string[] restrictions)
+ => throw ADP.ClosedConnectionError();
+
+ protected override DbReferenceCollection CreateReferenceCollection() => throw ADP.ClosedConnectionError();
+
+ internal override bool TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
+ => base.TryOpenConnectionInternal(outerConnection, connectionFactory, retry, userOptions);
+ }
+
+ abstract internal class DbConnectionBusy : DbConnectionClosed
+ {
+ protected DbConnectionBusy(ConnectionState state) : base(state, true, false)
+ {
+ }
+
+ internal override bool TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
+ => throw ADP.ConnectionAlreadyOpen(State);
+ }
+
+ sealed internal class DbConnectionClosedBusy : DbConnectionBusy
+ {
+ // Closed Connection, Currently Busy - changing connection string
+ internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionClosedBusy(); // singleton object
+
+ private DbConnectionClosedBusy() : base(ConnectionState.Closed)
+ {
+ }
+ }
+
+ sealed internal class DbConnectionOpenBusy : DbConnectionBusy
+ {
+ // Open Connection, Currently Busy - closing connection
+ internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionOpenBusy(); // singleton object
+
+ private DbConnectionOpenBusy() : base(ConnectionState.Open)
+ {
+ }
+ }
+
+ sealed internal class DbConnectionClosedConnecting : DbConnectionBusy
+ {
+ // Closed Connection, Currently Connecting
+
+ internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionClosedConnecting(); // singleton object
+
+ private DbConnectionClosedConnecting() : base(ConnectionState.Connecting)
+ {
+ }
+
+ internal override void CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory)
+ {
+ connectionFactory.SetInnerConnectionTo(owningObject, DbConnectionClosedPreviouslyOpened.SingletonInstance);
+ }
+
+ internal override bool TryReplaceConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
+ => TryOpenConnection(outerConnection, connectionFactory, retry, userOptions);
+
+ internal override bool TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
+ {
+ if (retry == null || !retry.Task.IsCompleted)
+ {
+ // retry is null if this is a synchronous call
+
+ // if someone calls Open or OpenAsync while in this state,
+ // then the retry task will not be completed
+
+ throw ADP.ConnectionAlreadyOpen(State);
+ }
+
+ // we are completing an asynchronous open
+ Debug.Assert(retry.Task.Status == TaskStatus.RanToCompletion, "retry task must be completed successfully");
+ DbConnectionInternal openConnection = retry.Task.Result;
+ if (null == openConnection)
+ {
+ connectionFactory.SetInnerConnectionTo(outerConnection, this);
+ throw ADP.InternalConnectionError(ADP.ConnectionError.GetConnectionReturnsNull);
+ }
+ connectionFactory.SetInnerConnectionEvent(outerConnection, openConnection);
+
+ return true;
+ }
+ }
+
+ sealed internal class DbConnectionClosedNeverOpened : DbConnectionClosed
+ {
+ // Closed Connection, Has Never Been Opened
+
+ internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionClosedNeverOpened(); // singleton object
+
+ private DbConnectionClosedNeverOpened() : base(ConnectionState.Closed, false, true)
+ {
+ }
+ }
+
+ sealed internal class DbConnectionClosedPreviouslyOpened : DbConnectionClosed
+ {
+ // Closed Connection, Has Previously Been Opened
+
+ internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionClosedPreviouslyOpened(); // singleton object
+
+ private DbConnectionClosedPreviouslyOpened() : base(ConnectionState.Closed, true, true)
+ {
+ }
+
+ internal override bool TryReplaceConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
+ => TryOpenConnection(outerConnection, connectionFactory, retry, userOptions);
+ }
+}
diff --git a/src/Common/src/System/Data/ProviderBase/DbConnectionFactory.cs b/src/Common/src/System/Data/ProviderBase/DbConnectionFactory.cs
new file mode 100644
index 0000000000..9ac3330b4a
--- /dev/null
+++ b/src/Common/src/System/Data/ProviderBase/DbConnectionFactory.cs
@@ -0,0 +1,427 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Data.Common;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Data.ProviderBase
+{
+ internal abstract partial class DbConnectionFactory
+ {
+ private Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> _connectionPoolGroups;
+ private readonly List<DbConnectionPool> _poolsToRelease;
+ private readonly List<DbConnectionPoolGroup> _poolGroupsToRelease;
+ private readonly Timer _pruningTimer;
+ private const int PruningDueTime = 4 * 60 * 1000; // 4 minutes
+ private const int PruningPeriod = 30 * 1000; // thirty seconds
+
+
+ // s_pendingOpenNonPooled is an array of tasks used to throttle creation of non-pooled connections to
+ // a maximum of Environment.ProcessorCount at a time.
+ private static uint s_pendingOpenNonPooledNext = 0;
+ private static Task<DbConnectionInternal>[] s_pendingOpenNonPooled = new Task<DbConnectionInternal>[Environment.ProcessorCount];
+ private static Task<DbConnectionInternal> s_completedTask;
+
+ protected DbConnectionFactory()
+ {
+ _connectionPoolGroups = new Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup>();
+ _poolsToRelease = new List<DbConnectionPool>();
+ _poolGroupsToRelease = new List<DbConnectionPoolGroup>();
+ _pruningTimer = CreatePruningTimer();
+ }
+
+
+ abstract public DbProviderFactory ProviderFactory
+ {
+ get;
+ }
+
+
+ public void ClearAllPools()
+ {
+ Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> connectionPoolGroups = _connectionPoolGroups;
+ foreach (KeyValuePair<DbConnectionPoolKey, DbConnectionPoolGroup> entry in connectionPoolGroups)
+ {
+ DbConnectionPoolGroup poolGroup = entry.Value;
+ if (null != poolGroup)
+ {
+ poolGroup.Clear();
+ }
+ }
+ }
+
+ public void ClearPool(DbConnection connection)
+ {
+ ADP.CheckArgumentNull(connection, nameof(connection));
+
+ DbConnectionPoolGroup poolGroup = GetConnectionPoolGroup(connection);
+ if (null != poolGroup)
+ {
+ poolGroup.Clear();
+ }
+ }
+
+ public void ClearPool(DbConnectionPoolKey key)
+ {
+ Debug.Assert(key != null, "key cannot be null");
+ ADP.CheckArgumentNull(key.ConnectionString, nameof(key) + "." + nameof(key.ConnectionString));
+
+ DbConnectionPoolGroup poolGroup;
+ Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> connectionPoolGroups = _connectionPoolGroups;
+ if (connectionPoolGroups.TryGetValue(key, out poolGroup))
+ {
+ poolGroup.Clear();
+ }
+ }
+
+ internal virtual DbConnectionPoolProviderInfo CreateConnectionPoolProviderInfo(DbConnectionOptions connectionOptions)
+ {
+ return null;
+ }
+
+
+ internal DbConnectionInternal CreateNonPooledConnection(DbConnection owningConnection, DbConnectionPoolGroup poolGroup, DbConnectionOptions userOptions)
+ {
+ Debug.Assert(null != owningConnection, "null owningConnection?");
+ Debug.Assert(null != poolGroup, "null poolGroup?");
+
+ DbConnectionOptions connectionOptions = poolGroup.ConnectionOptions;
+ DbConnectionPoolGroupProviderInfo poolGroupProviderInfo = poolGroup.ProviderInfo;
+ DbConnectionPoolKey poolKey = poolGroup.PoolKey;
+
+ DbConnectionInternal newConnection = CreateConnection(connectionOptions, poolKey, poolGroupProviderInfo, null, owningConnection, userOptions);
+ if (null != newConnection)
+ {
+ newConnection.MakeNonPooledObject(owningConnection);
+ }
+ return newConnection;
+ }
+
+ internal DbConnectionInternal CreatePooledConnection(DbConnectionPool pool, DbConnection owningObject, DbConnectionOptions options, DbConnectionPoolKey poolKey, DbConnectionOptions userOptions)
+ {
+ Debug.Assert(null != pool, "null pool?");
+ DbConnectionPoolGroupProviderInfo poolGroupProviderInfo = pool.PoolGroup.ProviderInfo;
+
+ DbConnectionInternal newConnection = CreateConnection(options, poolKey, poolGroupProviderInfo, pool, owningObject, userOptions);
+ if (null != newConnection)
+ {
+ newConnection.MakePooledConnection(pool);
+ }
+ return newConnection;
+ }
+
+ virtual internal DbConnectionPoolGroupProviderInfo CreateConnectionPoolGroupProviderInfo(DbConnectionOptions connectionOptions)
+ {
+ return null;
+ }
+
+ private Timer CreatePruningTimer() =>
+ ADP.UnsafeCreateTimer(
+ new TimerCallback(PruneConnectionPoolGroups),
+ null,
+ PruningDueTime,
+ PruningPeriod);
+
+ protected DbConnectionOptions FindConnectionOptions(DbConnectionPoolKey key)
+ {
+ Debug.Assert(key != null, "key cannot be null");
+ if (!string.IsNullOrEmpty(key.ConnectionString))
+ {
+ DbConnectionPoolGroup connectionPoolGroup;
+ Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> connectionPoolGroups = _connectionPoolGroups;
+ if (connectionPoolGroups.TryGetValue(key, out connectionPoolGroup))
+ {
+ return connectionPoolGroup.ConnectionOptions;
+ }
+ }
+ return null;
+ }
+
+ private static Task<DbConnectionInternal> GetCompletedTask()
+ {
+ Debug.Assert(Monitor.IsEntered(s_pendingOpenNonPooled), $"Expected {nameof(s_pendingOpenNonPooled)} lock to be held.");
+ return s_completedTask ?? (s_completedTask = Task.FromResult<DbConnectionInternal>(null));
+ }
+
+ private DbConnectionPool GetConnectionPool(DbConnection owningObject, DbConnectionPoolGroup connectionPoolGroup)
+ {
+ // if poolgroup is disabled, it will be replaced with a new entry
+
+ Debug.Assert(null != owningObject, "null owningObject?");
+ Debug.Assert(null != connectionPoolGroup, "null connectionPoolGroup?");
+
+ // It is possible that while the outer connection object has
+ // been sitting around in a closed and unused state in some long
+ // running app, the pruner may have come along and remove this
+ // the pool entry from the master list. If we were to use a
+ // pool entry in this state, we would create "unmanaged" pools,
+ // which would be bad. To avoid this problem, we automagically
+ // re-create the pool entry whenever it's disabled.
+
+ // however, don't rebuild connectionOptions if no pooling is involved - let new connections do that work
+ if (connectionPoolGroup.IsDisabled && (null != connectionPoolGroup.PoolGroupOptions))
+ {
+ // reusing existing pool option in case user originally used SetConnectionPoolOptions
+ DbConnectionPoolGroupOptions poolOptions = connectionPoolGroup.PoolGroupOptions;
+
+ // get the string to hash on again
+ DbConnectionOptions connectionOptions = connectionPoolGroup.ConnectionOptions;
+ Debug.Assert(null != connectionOptions, "prevent expansion of connectionString");
+
+ connectionPoolGroup = GetConnectionPoolGroup(connectionPoolGroup.PoolKey, poolOptions, ref connectionOptions);
+ Debug.Assert(null != connectionPoolGroup, "null connectionPoolGroup?");
+ SetConnectionPoolGroup(owningObject, connectionPoolGroup);
+ }
+ DbConnectionPool connectionPool = connectionPoolGroup.GetConnectionPool(this);
+ return connectionPool;
+ }
+
+ internal DbConnectionPoolGroup GetConnectionPoolGroup(DbConnectionPoolKey key, DbConnectionPoolGroupOptions poolOptions, ref DbConnectionOptions userConnectionOptions)
+ {
+ if (string.IsNullOrEmpty(key.ConnectionString))
+ {
+ return (DbConnectionPoolGroup)null;
+ }
+
+ DbConnectionPoolGroup connectionPoolGroup;
+ Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> connectionPoolGroups = _connectionPoolGroups;
+ if (!connectionPoolGroups.TryGetValue(key, out connectionPoolGroup) || (connectionPoolGroup.IsDisabled && (null != connectionPoolGroup.PoolGroupOptions)))
+ {
+ // If we can't find an entry for the connection string in
+ // our collection of pool entries, then we need to create a
+ // new pool entry and add it to our collection.
+
+ DbConnectionOptions connectionOptions = CreateConnectionOptions(key.ConnectionString, userConnectionOptions);
+ if (null == connectionOptions)
+ {
+ throw ADP.InternalConnectionError(ADP.ConnectionError.ConnectionOptionsMissing);
+ }
+
+ if (null == userConnectionOptions)
+ { // we only allow one expansion on the connection string
+ userConnectionOptions = connectionOptions;
+ }
+
+ // We don't support connection pooling on Win9x
+ if (null == poolOptions)
+ {
+ if (null != connectionPoolGroup)
+ {
+ // reusing existing pool option in case user originally used SetConnectionPoolOptions
+ poolOptions = connectionPoolGroup.PoolGroupOptions;
+ }
+ else
+ {
+ // Note: may return null for non-pooled connections
+ poolOptions = CreateConnectionPoolGroupOptions(connectionOptions);
+ }
+ }
+
+ lock (this)
+ {
+ connectionPoolGroups = _connectionPoolGroups;
+ if (!connectionPoolGroups.TryGetValue(key, out connectionPoolGroup))
+ {
+ DbConnectionPoolGroup newConnectionPoolGroup = new DbConnectionPoolGroup(connectionOptions, key, poolOptions);
+ newConnectionPoolGroup.ProviderInfo = CreateConnectionPoolGroupProviderInfo(connectionOptions);
+
+ // build new dictionary with space for new connection string
+ Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> newConnectionPoolGroups = new Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup>(1 + connectionPoolGroups.Count);
+ foreach (KeyValuePair<DbConnectionPoolKey, DbConnectionPoolGroup> entry in connectionPoolGroups)
+ {
+ newConnectionPoolGroups.Add(entry.Key, entry.Value);
+ }
+
+ // lock prevents race condition with PruneConnectionPoolGroups
+ newConnectionPoolGroups.Add(key, newConnectionPoolGroup);
+ connectionPoolGroup = newConnectionPoolGroup;
+ _connectionPoolGroups = newConnectionPoolGroups;
+ }
+ else
+ {
+ Debug.Assert(!connectionPoolGroup.IsDisabled, "Disabled pool entry discovered");
+ }
+ }
+ Debug.Assert(null != connectionPoolGroup, "how did we not create a pool entry?");
+ Debug.Assert(null != userConnectionOptions, "how did we not have user connection options?");
+ }
+ else if (null == userConnectionOptions)
+ {
+ userConnectionOptions = connectionPoolGroup.ConnectionOptions;
+ }
+ return connectionPoolGroup;
+ }
+
+
+ private void PruneConnectionPoolGroups(object state)
+ {
+ // First, walk the pool release list and attempt to clear each
+ // pool, when the pool is finally empty, we dispose of it. If the
+ // pool isn't empty, it's because there are active connections or
+ // distributed transactions that need it.
+ lock (_poolsToRelease)
+ {
+ if (0 != _poolsToRelease.Count)
+ {
+ DbConnectionPool[] poolsToRelease = _poolsToRelease.ToArray();
+ foreach (DbConnectionPool pool in poolsToRelease)
+ {
+ if (null != pool)
+ {
+ pool.Clear();
+
+ if (0 == pool.Count)
+ {
+ _poolsToRelease.Remove(pool);
+ }
+ }
+ }
+ }
+ }
+
+ // Next, walk the pool entry release list and dispose of each
+ // pool entry when it is finally empty. If the pool entry isn't
+ // empty, it's because there are active pools that need it.
+ lock (_poolGroupsToRelease)
+ {
+ if (0 != _poolGroupsToRelease.Count)
+ {
+ DbConnectionPoolGroup[] poolGroupsToRelease = _poolGroupsToRelease.ToArray();
+ foreach (DbConnectionPoolGroup poolGroup in poolGroupsToRelease)
+ {
+ if (null != poolGroup)
+ {
+ int poolsLeft = poolGroup.Clear(); // may add entries to _poolsToRelease
+
+ if (0 == poolsLeft)
+ {
+ _poolGroupsToRelease.Remove(poolGroup);
+ }
+ }
+ }
+ }
+ }
+
+ // Finally, we walk through the collection of connection pool entries
+ // and prune each one. This will cause any empty pools to be put
+ // into the release list.
+ lock (this)
+ {
+ Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> connectionPoolGroups = _connectionPoolGroups;
+ Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> newConnectionPoolGroups = new Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup>(connectionPoolGroups.Count);
+
+ foreach (KeyValuePair<DbConnectionPoolKey, DbConnectionPoolGroup> entry in connectionPoolGroups)
+ {
+ if (null != entry.Value)
+ {
+ Debug.Assert(!entry.Value.IsDisabled, "Disabled pool entry discovered");
+
+ // entries start active and go idle during prune if all pools are gone
+ // move idle entries from last prune pass to a queue for pending release
+ // otherwise process entry which may move it from active to idle
+ if (entry.Value.Prune())
+ { // may add entries to _poolsToRelease
+ QueuePoolGroupForRelease(entry.Value);
+ }
+ else
+ {
+ newConnectionPoolGroups.Add(entry.Key, entry.Value);
+ }
+ }
+ }
+ _connectionPoolGroups = newConnectionPoolGroups;
+ }
+ }
+
+ internal void QueuePoolForRelease(DbConnectionPool pool, bool clearing)
+ {
+ // Queue the pool up for release -- we'll clear it out and dispose
+ // of it as the last part of the pruning timer callback so we don't
+ // do it with the pool entry or the pool collection locked.
+ Debug.Assert(null != pool, "null pool?");
+
+ // set the pool to the shutdown state to force all active
+ // connections to be automatically disposed when they
+ // are returned to the pool
+ pool.Shutdown();
+
+ lock (_poolsToRelease)
+ {
+ if (clearing)
+ {
+ pool.Clear();
+ }
+ _poolsToRelease.Add(pool);
+ }
+ }
+
+ internal void QueuePoolGroupForRelease(DbConnectionPoolGroup poolGroup)
+ {
+ Debug.Assert(null != poolGroup, "null poolGroup?");
+
+ lock (_poolGroupsToRelease)
+ {
+ _poolGroupsToRelease.Add(poolGroup);
+ }
+ }
+
+ virtual protected DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions)
+ {
+ return CreateConnection(options, poolKey, poolGroupProviderInfo, pool, owningConnection);
+ }
+
+ internal DbMetaDataFactory GetMetaDataFactory(DbConnectionPoolGroup connectionPoolGroup, DbConnectionInternal internalConnection)
+ {
+ Debug.Assert(connectionPoolGroup != null, "connectionPoolGroup may not be null.");
+
+ // get the matadatafactory from the pool entry. If it does not already have one
+ // create one and save it on the pool entry
+ DbMetaDataFactory metaDataFactory = connectionPoolGroup.MetaDataFactory;
+
+ // consider serializing this so we don't construct multiple metadata factories
+ // if two threads happen to hit this at the same time. One will be GC'd
+ if (metaDataFactory == null)
+ {
+ bool allowCache = false;
+ metaDataFactory = CreateMetaDataFactory(internalConnection, out allowCache);
+ if (allowCache)
+ {
+ connectionPoolGroup.MetaDataFactory = metaDataFactory;
+ }
+ }
+ return metaDataFactory;
+ }
+
+ protected virtual DbMetaDataFactory CreateMetaDataFactory(DbConnectionInternal internalConnection, out bool cacheMetaDataFactory)
+ {
+ // providers that support GetSchema must override this with a method that creates a meta data
+ // factory appropriate for them.
+ cacheMetaDataFactory = false;
+ throw ADP.NotSupported();
+ }
+
+ abstract protected DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection);
+
+ abstract protected DbConnectionOptions CreateConnectionOptions(string connectionString, DbConnectionOptions previous);
+
+ abstract protected DbConnectionPoolGroupOptions CreateConnectionPoolGroupOptions(DbConnectionOptions options);
+
+ abstract internal DbConnectionPoolGroup GetConnectionPoolGroup(DbConnection connection);
+
+ abstract internal DbConnectionInternal GetInnerConnection(DbConnection connection);
+
+ abstract internal void PermissionDemand(DbConnection outerConnection);
+
+ abstract internal void SetConnectionPoolGroup(DbConnection outerConnection, DbConnectionPoolGroup poolGroup);
+
+ abstract internal void SetInnerConnectionEvent(DbConnection owningObject, DbConnectionInternal to);
+
+ abstract internal bool SetInnerConnectionFrom(DbConnection owningObject, DbConnectionInternal to, DbConnectionInternal from);
+
+ abstract internal void SetInnerConnectionTo(DbConnection owningObject, DbConnectionInternal to);
+ }
+}
diff --git a/src/Common/src/System/Data/ProviderBase/DbConnectionInternal.cs b/src/Common/src/System/Data/ProviderBase/DbConnectionInternal.cs
new file mode 100644
index 0000000000..945a1c5ed5
--- /dev/null
+++ b/src/Common/src/System/Data/ProviderBase/DbConnectionInternal.cs
@@ -0,0 +1,434 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Data.Common;
+using System.Diagnostics;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Transactions;
+
+
+namespace System.Data.ProviderBase
+{
+ internal abstract partial class DbConnectionInternal
+ {
+ internal static readonly StateChangeEventArgs StateChangeClosed = new StateChangeEventArgs(ConnectionState.Open, ConnectionState.Closed);
+ internal static readonly StateChangeEventArgs StateChangeOpen = new StateChangeEventArgs(ConnectionState.Closed, ConnectionState.Open);
+
+ private readonly bool _allowSetConnectionString;
+ private readonly bool _hidePassword;
+ private readonly ConnectionState _state;
+
+ private readonly WeakReference _owningObject = new WeakReference(null, false); // [usage must be thread safe] the owning object, when not in the pool. (both Pooled and Non-Pooled connections)
+
+ private DbConnectionPool _connectionPool; // the pooler that the connection came from (Pooled connections only)
+ private DbReferenceCollection _referenceCollection; // collection of objects that we need to notify in some way when we're being deactivated
+ private int _pooledCount; // [usage must be thread safe] the number of times this object has been pushed into the pool less the number of times it's been popped (0 != inPool)
+
+ private bool _connectionIsDoomed; // true when the connection should no longer be used.
+ private bool _cannotBePooled; // true when the connection should no longer be pooled.
+
+ private DateTime _createTime; // when the connection was created.
+
+#if DEBUG
+ private int _activateCount; // debug only counter to verify activate/deactivates are in sync.
+#endif //DEBUG
+
+ protected DbConnectionInternal() : this(ConnectionState.Open, true, false)
+ {
+ }
+
+ // Constructor for internal connections
+ internal DbConnectionInternal(ConnectionState state, bool hidePassword, bool allowSetConnectionString)
+ {
+ _allowSetConnectionString = allowSetConnectionString;
+ _hidePassword = hidePassword;
+ _state = state;
+ }
+
+ internal bool AllowSetConnectionString
+ {
+ get
+ {
+ return _allowSetConnectionString;
+ }
+ }
+
+ internal bool CanBePooled
+ {
+ get
+ {
+ bool flag = (!_connectionIsDoomed && !_cannotBePooled && !_owningObject.IsAlive);
+ return flag;
+ }
+ }
+
+ protected internal bool IsConnectionDoomed
+ {
+ get
+ {
+ return _connectionIsDoomed;
+ }
+ }
+
+ internal bool IsEmancipated
+ {
+ get
+ {
+ // NOTE: There are race conditions between PrePush, PostPop and this
+ // property getter -- only use this while this object is locked;
+ // (DbConnectionPool.Clear and ReclaimEmancipatedObjects
+ // do this for us)
+
+ // The functionality is as follows:
+ //
+ // _pooledCount is incremented when the connection is pushed into the pool
+ // _pooledCount is decremented when the connection is popped from the pool
+ // _pooledCount is set to -1 when the connection is not pooled (just in case...)
+ //
+ // That means that:
+ //
+ // _pooledCount > 1 connection is in the pool multiple times (This should not happen)
+ // _pooledCount == 1 connection is in the pool
+ // _pooledCount == 0 connection is out of the pool
+ // _pooledCount == -1 connection is not a pooled connection; we shouldn't be here for non-pooled connections.
+ // _pooledCount < -1 connection out of the pool multiple times
+ //
+ // Now, our job is to return TRUE when the connection is out
+ // of the pool and it's owning object is no longer around to
+ // return it.
+
+ bool value = (_pooledCount < 1) && !_owningObject.IsAlive;
+ return value;
+ }
+ }
+
+ internal bool IsInPool
+ {
+ get
+ {
+ Debug.Assert(_pooledCount <= 1 && _pooledCount >= -1, "Pooled count for object is invalid");
+ return (_pooledCount == 1);
+ }
+ }
+
+
+ protected internal object Owner
+ {
+ // We use a weak reference to the owning object so we can identify when
+ // it has been garbage collected without thowing exceptions.
+ get
+ {
+ return _owningObject.Target;
+ }
+ }
+
+ internal DbConnectionPool Pool
+ {
+ get
+ {
+ return _connectionPool;
+ }
+ }
+
+ protected internal DbReferenceCollection ReferenceCollection
+ {
+ get
+ {
+ return _referenceCollection;
+ }
+ }
+
+ abstract public string ServerVersion
+ {
+ get;
+ }
+
+ // this should be abstract but until it is added to all the providers virtual will have to do
+ virtual public string ServerVersionNormalized
+ {
+ get
+ {
+ throw ADP.NotSupported();
+ }
+ }
+
+ public bool ShouldHidePassword
+ {
+ get
+ {
+ return _hidePassword;
+ }
+ }
+
+ public ConnectionState State
+ {
+ get
+ {
+ return _state;
+ }
+ }
+
+ internal void AddWeakReference(object value, int tag)
+ {
+ if (null == _referenceCollection)
+ {
+ _referenceCollection = CreateReferenceCollection();
+ if (null == _referenceCollection)
+ {
+ throw ADP.InternalError(ADP.InternalErrorCode.CreateReferenceCollectionReturnedNull);
+ }
+ }
+ _referenceCollection.Add(value, tag);
+ }
+
+ abstract public DbTransaction BeginTransaction(IsolationLevel il);
+
+ virtual public void ChangeDatabase(string value)
+ {
+ throw ADP.MethodNotImplemented();
+ }
+
+ virtual internal void PrepareForReplaceConnection()
+ {
+ // By default, there is no preparation required
+ }
+
+ virtual protected void PrepareForCloseConnection()
+ {
+ // By default, there is no preparation required
+ }
+
+ virtual protected object ObtainAdditionalLocksForClose()
+ {
+ return null; // no additional locks in default implementation
+ }
+
+ virtual protected void ReleaseAdditionalLocksForClose(object lockToken)
+ {
+ // no additional locks in default implementation
+ }
+
+ virtual protected DbReferenceCollection CreateReferenceCollection()
+ {
+ throw ADP.InternalError(ADP.InternalErrorCode.AttemptingToConstructReferenceCollectionOnStaticObject);
+ }
+
+ abstract protected void Deactivate();
+
+ internal void DeactivateConnection()
+ {
+ // Internal method called from the connection pooler so we don't expose
+ // the Deactivate method publicly.
+
+#if DEBUG
+ int activateCount = Interlocked.Decrement(ref _activateCount);
+#endif // DEBUG
+
+
+ if (!_connectionIsDoomed && Pool.UseLoadBalancing)
+ {
+ // If we're not already doomed, check the connection's lifetime and
+ // doom it if it's lifetime has elapsed.
+
+ DateTime now = DateTime.UtcNow;
+ if ((now.Ticks - _createTime.Ticks) > Pool.LoadBalanceTimeout.Ticks)
+ {
+ DoNotPoolThisConnection();
+ }
+ }
+ Deactivate();
+ }
+
+ protected internal void DoNotPoolThisConnection()
+ {
+ _cannotBePooled = true;
+ }
+
+ /// <devdoc>Ensure that this connection cannot be put back into the pool.</devdoc>
+ protected internal void DoomThisConnection()
+ {
+ _connectionIsDoomed = true;
+ }
+
+ protected internal virtual DataTable GetSchema(DbConnectionFactory factory, DbConnectionPoolGroup poolGroup, DbConnection outerConnection, string collectionName, string[] restrictions)
+ {
+ Debug.Assert(outerConnection != null, "outerConnection may not be null.");
+
+ DbMetaDataFactory metaDataFactory = factory.GetMetaDataFactory(poolGroup, this);
+ Debug.Assert(metaDataFactory != null, "metaDataFactory may not be null.");
+
+ return metaDataFactory.GetSchema(outerConnection, collectionName, restrictions);
+ }
+
+ internal void MakeNonPooledObject(object owningObject)
+ {
+ // Used by DbConnectionFactory to indicate that this object IS NOT part of
+ // a connection pool.
+
+ _connectionPool = null;
+ _owningObject.Target = owningObject;
+ _pooledCount = -1;
+ }
+
+ internal void MakePooledConnection(DbConnectionPool connectionPool)
+ {
+ // Used by DbConnectionFactory to indicate that this object IS part of
+ // a connection pool.
+ _createTime = DateTime.UtcNow;
+
+ _connectionPool = connectionPool;
+ }
+
+ internal void NotifyWeakReference(int message)
+ {
+ DbReferenceCollection referenceCollection = ReferenceCollection;
+ if (null != referenceCollection)
+ {
+ referenceCollection.Notify(message);
+ }
+ }
+
+ internal virtual void OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
+ {
+ if (!TryOpenConnection(outerConnection, connectionFactory, null, null))
+ {
+ throw ADP.InternalError(ADP.InternalErrorCode.SynchronousConnectReturnedPending);
+ }
+ }
+
+ /// <devdoc>The default implementation is for the open connection objects, and
+ /// it simply throws. Our private closed-state connection objects
+ /// override this and do the correct thing.</devdoc>
+ // User code should either override DbConnectionInternal.Activate when it comes out of the pool
+ // or override DbConnectionFactory.CreateConnection when the connection is created for non-pooled connections
+ internal virtual bool TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
+ {
+ throw ADP.ConnectionAlreadyOpen(State);
+ }
+
+ internal virtual bool TryReplaceConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
+ {
+ throw ADP.MethodNotImplemented();
+ }
+
+ protected bool TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
+ {
+ // ?->Connecting: prevent set_ConnectionString during Open
+ if (connectionFactory.SetInnerConnectionFrom(outerConnection, DbConnectionClosedConnecting.SingletonInstance, this))
+ {
+ DbConnectionInternal openConnection = null;
+ try
+ {
+ connectionFactory.PermissionDemand(outerConnection);
+ if (!connectionFactory.TryGetConnection(outerConnection, retry, userOptions, this, out openConnection))
+ {
+ return false;
+ }
+ }
+ catch
+ {
+ // This should occur for all exceptions, even ADP.UnCatchableExceptions.
+ connectionFactory.SetInnerConnectionTo(outerConnection, this);
+ throw;
+ }
+ if (null == openConnection)
+ {
+ connectionFactory.SetInnerConnectionTo(outerConnection, this);
+ throw ADP.InternalConnectionError(ADP.ConnectionError.GetConnectionReturnsNull);
+ }
+ connectionFactory.SetInnerConnectionEvent(outerConnection, openConnection);
+ }
+
+ return true;
+ }
+
+ internal void PrePush(object expectedOwner)
+ {
+ // Called by DbConnectionPool when we're about to be put into it's pool, we
+ // take this opportunity to ensure ownership and pool counts are legit.
+
+ // IMPORTANT NOTE: You must have taken a lock on the object before
+ // you call this method to prevent race conditions with Clear and
+ // ReclaimEmancipatedObjects.
+
+ //3 // The following tests are retail assertions of things we can't allow to happen.
+ if (null == expectedOwner)
+ {
+ if (null != _owningObject.Target)
+ {
+ throw ADP.InternalError(ADP.InternalErrorCode.UnpooledObjectHasOwner); // new unpooled object has an owner
+ }
+ }
+ else if (_owningObject.Target != expectedOwner)
+ {
+ throw ADP.InternalError(ADP.InternalErrorCode.UnpooledObjectHasWrongOwner); // unpooled object has incorrect owner
+ }
+ if (0 != _pooledCount)
+ {
+ throw ADP.InternalError(ADP.InternalErrorCode.PushingObjectSecondTime); // pushing object onto stack a second time
+ }
+ _pooledCount++;
+ _owningObject.Target = null; // NOTE: doing this and checking for InternalError.PooledObjectHasOwner degrades the close by 2%
+ }
+
+ internal void PostPop(object newOwner)
+ {
+ // Called by DbConnectionPool right after it pulls this from it's pool, we
+ // take this opportunity to ensure ownership and pool counts are legit.
+
+ Debug.Assert(!IsEmancipated, "pooled object not in pool");
+
+ // When another thread is clearing this pool, it
+ // will doom all connections in this pool without prejudice which
+ // causes the following assert to fire, which really mucks up stress
+ // against checked bits. The assert is benign, so we're commenting
+ // it out.
+ //Debug.Assert(CanBePooled, "pooled object is not poolable");
+
+ // IMPORTANT NOTE: You must have taken a lock on the object before
+ // you call this method to prevent race conditions with Clear and
+ // ReclaimEmancipatedObjects.
+
+ if (null != _owningObject.Target)
+ {
+ throw ADP.InternalError(ADP.InternalErrorCode.PooledObjectHasOwner); // pooled connection already has an owner!
+ }
+ _owningObject.Target = newOwner;
+ _pooledCount--;
+ //3 // The following tests are retail assertions of things we can't allow to happen.
+ if (null != Pool)
+ {
+ if (0 != _pooledCount)
+ {
+ throw ADP.InternalError(ADP.InternalErrorCode.PooledObjectInPoolMoreThanOnce); // popping object off stack with multiple pooledCount
+ }
+ }
+ else if (-1 != _pooledCount)
+ {
+ throw ADP.InternalError(ADP.InternalErrorCode.NonPooledObjectUsedMoreThanOnce); // popping object off stack with multiple pooledCount
+ }
+ }
+
+ internal void RemoveWeakReference(object value)
+ {
+ DbReferenceCollection referenceCollection = ReferenceCollection;
+ if (null != referenceCollection)
+ {
+ referenceCollection.Remove(value);
+ }
+ }
+
+ /// <summary>
+ /// When overridden in a derived class, will check if the underlying connection is still actually alive
+ /// </summary>
+ /// <param name="throwOnException">If true an exception will be thrown if the connection is dead instead of returning true\false
+ /// (this allows the caller to have the real reason that the connection is not alive (e.g. network error, etc))</param>
+ /// <returns>True if the connection is still alive, otherwise false (If not overridden, then always true)</returns>
+ internal virtual bool IsConnectionAlive(bool throwOnException = false)
+ {
+ return true;
+ }
+ }
+}
diff --git a/src/System.Data.SqlClient/src/System/Data/ProviderBase/DbConnectionPoolGroup.cs b/src/Common/src/System/Data/ProviderBase/DbConnectionPoolGroup.cs
index b28ade14d2..f32c4d0d99 100644
--- a/src/System.Data.SqlClient/src/System/Data/ProviderBase/DbConnectionPoolGroup.cs
+++ b/src/Common/src/System/Data/ProviderBase/DbConnectionPoolGroup.cs
@@ -3,8 +3,6 @@
// See the LICENSE file in the project root for more information.
-//------------------------------------------------------------------------------
-
using System.Collections.Concurrent;
using System.Data.Common;
using System.Diagnostics;
@@ -62,21 +60,9 @@ namespace System.Data.ProviderBase
_state = PoolGroupStateActive;
}
- internal DbConnectionOptions ConnectionOptions
- {
- get
- {
- return _connectionOptions;
- }
- }
+ internal DbConnectionOptions ConnectionOptions => _connectionOptions;
- internal DbConnectionPoolKey PoolKey
- {
- get
- {
- return _poolKey;
- }
- }
+ internal DbConnectionPoolKey PoolKey => _poolKey;
internal DbConnectionPoolGroupProviderInfo ProviderInfo
{
@@ -94,22 +80,9 @@ namespace System.Data.ProviderBase
}
}
- internal bool IsDisabled
- {
- get
- {
- return (PoolGroupStateDisabled == _state);
- }
- }
-
+ internal bool IsDisabled => (PoolGroupStateDisabled == _state);
- internal DbConnectionPoolGroupOptions PoolGroupOptions
- {
- get
- {
- return _poolGroupOptions;
- }
- }
+ internal DbConnectionPoolGroupOptions PoolGroupOptions => _poolGroupOptions;
internal DbMetaDataFactory MetaDataFactory
{
@@ -190,7 +163,7 @@ namespace System.Data.ProviderBase
if (null != currentIdentity)
{
if (!_poolCollection.TryGetValue(currentIdentity, out pool)) // find the pool
- {
+ {
lock (this)
{
// Did someone already add it to the list?
diff --git a/src/System.Data.SqlClient/src/System/Data/ProviderBase/DbMetaDataFactory.cs b/src/Common/src/System/Data/ProviderBase/DbMetaDataFactory.cs
index 3da59e4470..8233dc9849 100644
--- a/src/System.Data.SqlClient/src/System/Data/ProviderBase/DbMetaDataFactory.cs
+++ b/src/Common/src/System/Data/ProviderBase/DbMetaDataFactory.cs
@@ -46,29 +46,11 @@ namespace System.Data.ProviderBase
_normalizedServerVersion = normalizedServerVersion;
}
- protected DataSet CollectionDataSet
- {
- get
- {
- return _metaDataCollectionsDataSet;
- }
- }
+ protected DataSet CollectionDataSet => _metaDataCollectionsDataSet;
- protected string ServerVersion
- {
- get
- {
- return _serverVersionString;
- }
- }
+ protected string ServerVersion => _serverVersionString;
- protected string ServerVersionNormalized
- {
- get
- {
- return _normalizedServerVersion;
- }
- }
+ protected string ServerVersionNormalized => _normalizedServerVersion;
protected DataTable CloneAndFilterCollection(string collectionName, string[] hiddenColumnNames)
{
@@ -109,10 +91,7 @@ namespace System.Data.ProviderBase
return destinationTable;
}
- public void Dispose()
- {
- Dispose(true);
- }
+ public void Dispose() => Dispose(true);
protected virtual void Dispose(bool disposing)
{
@@ -216,11 +195,6 @@ namespace System.Data.ProviderBase
private DataColumn[] FilterColumns(DataTable sourceTable, string[] hiddenColumnNames, DataColumnCollection destinationColumns)
{
-
- DataColumn newDestinationColumn;
- int currentColumn;
- DataColumn[] filteredSourceColumns = null;
-
int columnCount = 0;
foreach (DataColumn sourceColumn in sourceTable.Columns)
{
@@ -235,14 +209,14 @@ namespace System.Data.ProviderBase
throw ADP.NoColumns();
}
- currentColumn = 0;
- filteredSourceColumns = new DataColumn[columnCount];
+ int currentColumn = 0;
+ DataColumn[] filteredSourceColumns = new DataColumn[columnCount];
foreach (DataColumn sourceColumn in sourceTable.Columns)
{
if (IncludeThisColumn(sourceColumn, hiddenColumnNames) == true)
{
- newDestinationColumn = new DataColumn(sourceColumn.ColumnName, sourceColumn.DataType);
+ DataColumn newDestinationColumn = new DataColumn(sourceColumn.ColumnName, sourceColumn.DataType);
destinationColumns.Add(newDestinationColumn);
filteredSourceColumns[currentColumn] = sourceColumn;
currentColumn++;
@@ -375,7 +349,7 @@ namespace System.Data.ProviderBase
DataColumn parameterName = null;
DataColumn restrictionName = null;
DataColumn restrictionNumber = null;
- ;
+
string result = null;
restrictionsTable = _metaDataCollectionsDataSet.Tables[DbMetaDataCollectionNames.Restrictions];
@@ -587,6 +561,3 @@ namespace System.Data.ProviderBase
}
}
}
-
-
-
diff --git a/src/System.Data.SqlClient/src/System/Data/ProviderBase/DbReferenceCollection.cs b/src/Common/src/System/Data/ProviderBase/DbReferenceCollection.cs
index 2bc3907f40..2bc3907f40 100644
--- a/src/System.Data.SqlClient/src/System/Data/ProviderBase/DbReferenceCollection.cs
+++ b/src/Common/src/System/Data/ProviderBase/DbReferenceCollection.cs
diff --git a/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/TimeoutTimer.cs b/src/Common/src/System/Data/ProviderBase/TimeoutTimer.cs
index 969f399d34..969f399d34 100644
--- a/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/TimeoutTimer.cs
+++ b/src/Common/src/System/Data/ProviderBase/TimeoutTimer.cs
diff --git a/src/Common/src/System/Drawing/KnownColor.cs b/src/Common/src/System/Drawing/KnownColor.cs
index 01497e7933..70a217c0e9 100644
--- a/src/Common/src/System/Drawing/KnownColor.cs
+++ b/src/Common/src/System/Drawing/KnownColor.cs
@@ -7,7 +7,12 @@ using System.Diagnostics.CodeAnalysis;
namespace System.Drawing
{
[SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue")]
- public enum KnownColor
+#if netcoreapp20
+ internal
+#else
+ public
+#endif
+ enum KnownColor
{
// This enum is order dependant!!!
//
diff --git a/src/Common/src/System/Drawing/KnownColorTable.cs b/src/Common/src/System/Drawing/KnownColorTable.cs
index 6681be42aa..f4b6dfabba 100644
--- a/src/Common/src/System/Drawing/KnownColorTable.cs
+++ b/src/Common/src/System/Drawing/KnownColorTable.cs
@@ -6,6 +6,11 @@ using System.Diagnostics;
namespace System.Drawing
{
+#if FEATURE_SYSTEM_EVENTS
+ using Microsoft.Win32;
+ using System.Drawing.Internal;
+#endif
+
static internal class KnownColorTable
{
private static int[] s_colorTable;
@@ -53,6 +58,10 @@ namespace System.Drawing
private static void InitColorTable()
{
int[] values = new int[(unchecked((int)KnownColor.MenuHighlight)) + 1];
+
+#if FEATURE_SYSTEM_EVENTS
+ SystemEvents.UserPreferenceChanging += new UserPreferenceChangingEventHandler(OnUserPreferenceChanging);
+#endif
UpdateSystemColors(values);
// just consts...
@@ -429,6 +438,16 @@ namespace System.Drawing
}
#endif
+#if FEATURE_SYSTEM_EVENTS
+ private static void OnUserPreferenceChanging(object sender, UserPreferenceChangingEventArgs e)
+ {
+ if (e.Category == UserPreferenceCategory.Color && s_colorTable != null)
+ {
+ UpdateSystemColors(s_colorTable);
+ }
+ }
+#endif
+
private static void UpdateSystemColors(int[] colorTable)
{
#if FEATURE_WINDOWS_SYSTEM_COLORS
diff --git a/src/Common/src/System/Globalization/FormatProvider.Number.cs b/src/Common/src/System/Globalization/FormatProvider.Number.cs
index fa92c9cce9..cda92cfcdd 100644
--- a/src/Common/src/System/Globalization/FormatProvider.Number.cs
+++ b/src/Common/src/System/Globalization/FormatProvider.Number.cs
@@ -1455,8 +1455,7 @@ namespace System.Globalization
if (thousandsSepCtr >= thousandsSepPos.Length)
{
var newThousandsSepPos = new int[thousandsSepPos.Length * 2];
- bool copied = thousandsSepPos.TryCopyTo(newThousandsSepPos);
- Debug.Assert(copied, "Expect copy to succeed, as the new array is larger than the original");
+ thousandsSepPos.CopyTo(newThousandsSepPos);
thousandsSepPos = newThousandsSepPos;
}
diff --git a/src/Common/src/System/IO/DelegatingStream.cs b/src/Common/src/System/IO/DelegatingStream.cs
index 3bb864887f..23dc10ca35 100644
--- a/src/Common/src/System/IO/DelegatingStream.cs
+++ b/src/Common/src/System/IO/DelegatingStream.cs
@@ -88,9 +88,9 @@ namespace System.Net.Http
return _innerStream.Read(buffer, offset, count);
}
- public override int Read(Span<byte> destination)
+ public override int Read(Span<byte> buffer)
{
- return _innerStream.Read(destination);
+ return _innerStream.Read(buffer);
}
public override int ReadByte()
@@ -103,9 +103,9 @@ namespace System.Net.Http
return _innerStream.ReadAsync(buffer, offset, count, cancellationToken);
}
- public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken = default)
+ public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
{
- return _innerStream.ReadAsync(destination, cancellationToken);
+ return _innerStream.ReadAsync(buffer, cancellationToken);
}
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
@@ -142,9 +142,9 @@ namespace System.Net.Http
_innerStream.Write(buffer, offset, count);
}
- public override void Write(ReadOnlySpan<byte> source)
+ public override void Write(ReadOnlySpan<byte> buffer)
{
- _innerStream.Write(source);
+ _innerStream.Write(buffer);
}
public override void WriteByte(byte value)
@@ -157,9 +157,9 @@ namespace System.Net.Http
return _innerStream.WriteAsync(buffer, offset, count, cancellationToken);
}
- public override Task WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken = default)
+ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
{
- return _innerStream.WriteAsync(source, cancellationToken);
+ return _innerStream.WriteAsync(buffer, cancellationToken);
}
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
diff --git a/src/Common/src/System/IO/PathInternal.Unix.cs b/src/Common/src/System/IO/PathInternal.Unix.cs
index 27424cb2fb..8e27f4b82d 100644
--- a/src/Common/src/System/IO/PathInternal.Unix.cs
+++ b/src/Common/src/System/IO/PathInternal.Unix.cs
@@ -11,12 +11,6 @@ namespace System.IO
/// <summary>Contains internal path helpers that are shared between many projects.</summary>
internal static partial class PathInternal
{
- // There is only one invalid path character in Unix
- private const char InvalidPathChar = '\0';
- internal static char[] GetInvalidPathChars() => new char[] { InvalidPathChar };
-
- internal const string ParentDirectoryPrefix = @"../";
-
internal static int GetRootLength(ReadOnlySpan<char> path)
{
return path.Length > 0 && IsDirectorySeparator(path[0]) ? 1 : 0;
@@ -30,57 +24,6 @@ namespace System.IO
return c == Path.DirectorySeparatorChar;
}
- /// <summary>
- /// Normalize separators in the given path. Compresses forward slash runs.
- /// </summary>
- internal static string NormalizeDirectorySeparators(string path)
- {
- if (string.IsNullOrEmpty(path)) return path;
-
- // Make a pass to see if we need to normalize so we can potentially skip allocating
- bool normalized = true;
-
- for (int i = 0; i < path.Length; i++)
- {
- if (IsDirectorySeparator(path[i])
- && (i + 1 < path.Length && IsDirectorySeparator(path[i + 1])))
- {
- normalized = false;
- break;
- }
- }
-
- if (normalized) return path;
-
- StringBuilder builder = new StringBuilder(path.Length);
-
- for (int i = 0; i < path.Length; i++)
- {
- char current = path[i];
-
- // Skip if we have another separator following
- if (IsDirectorySeparator(current)
- && (i + 1 < path.Length && IsDirectorySeparator(path[i + 1])))
- continue;
-
- builder.Append(current);
- }
-
- return builder.ToString();
- }
-
- /// <summary>
- /// Returns true if the character is a directory or volume separator.
- /// </summary>
- /// <param name="ch">The character to test.</param>
- internal static bool IsDirectoryOrVolumeSeparator(char ch)
- {
- // The directory separator, volume separator, and the alternate directory
- // separator should be the same on Unix, so we only need to check one.
- Debug.Assert(Path.DirectorySeparatorChar == Path.AltDirectorySeparatorChar);
- Debug.Assert(Path.DirectorySeparatorChar == Path.VolumeSeparatorChar);
- return ch == Path.DirectorySeparatorChar;
- }
internal static bool IsPartiallyQualified(string path)
{
diff --git a/src/Common/src/System/IO/PathInternal.Windows.cs b/src/Common/src/System/IO/PathInternal.Windows.cs
index 1d0dcbaf72..6bc6a0f65d 100644
--- a/src/Common/src/System/IO/PathInternal.Windows.cs
+++ b/src/Common/src/System/IO/PathInternal.Windows.cs
@@ -2,9 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Diagnostics;
using System.Runtime.CompilerServices;
-using System.Text;
namespace System.IO
{
@@ -40,38 +38,16 @@ namespace System.IO
// Local and Global MS-DOS Device Names
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff554302.aspx
- internal const string ExtendedPathPrefix = @"\\?\";
+ internal const string ExtendedDevicePathPrefix = @"\\?\";
internal const string UncPathPrefix = @"\\";
- internal const string UncExtendedPrefixToInsert = @"?\UNC\";
+ internal const string UncDevicePrefixToInsert = @"?\UNC\";
internal const string UncExtendedPathPrefix = @"\\?\UNC\";
internal const string DevicePathPrefix = @"\\.\";
- internal const string ParentDirectoryPrefix = @"..\";
internal const int MaxShortPath = 260;
- internal const int MaxShortDirectoryPath = 248;
- internal const int MaxLongPath = short.MaxValue;
+
// \\?\, \\.\, \??\
internal const int DevicePrefixLength = 4;
- // \\
- internal const int UncPrefixLength = 2;
- // \\?\UNC\, \\.\UNC\
- internal const int UncExtendedPrefixLength = 8;
-
- internal static char[] GetInvalidPathChars() => new char[]
- {
- '|', '\0',
- (char)1, (char)2, (char)3, (char)4, (char)5, (char)6, (char)7, (char)8, (char)9, (char)10,
- (char)11, (char)12, (char)13, (char)14, (char)15, (char)16, (char)17, (char)18, (char)19, (char)20,
- (char)21, (char)22, (char)23, (char)24, (char)25, (char)26, (char)27, (char)28, (char)29, (char)30,
- (char)31
- };
-
- // [MS - FSA] 2.1.4.4 Algorithm for Determining if a FileName Is in an Expression
- // https://msdn.microsoft.com/en-us/library/ff469270.aspx
- private static readonly char[] s_wildcardChars =
- {
- '\"', '<', '>', '*', '?'
- };
/// <summary>
/// Returns true if the given character is a valid drive letter
@@ -81,13 +57,25 @@ namespace System.IO
return ((value >= 'A' && value <= 'Z') || (value >= 'a' && value <= 'z'));
}
+ private static bool EndsWithPeriodOrSpace(string path)
+ {
+ if (string.IsNullOrEmpty(path))
+ return false;
+
+ char c = path[path.Length - 1];
+ return c == ' ' || c == '.';
+ }
+
/// <summary>
/// Adds the extended path prefix (\\?\) if not already a device path, IF the path is not relative,
- /// AND the path is more than 259 characters. (> MAX_PATH + null)
+ /// AND the path is more than 259 characters. (> MAX_PATH + null). This will also insert the extended
+ /// prefix if the path ends with a period or a space. Trailing periods and spaces are normally eaten
+ /// away from paths during normalization, but if we see such a path at this point it should be
+ /// normalized and has retained the final characters. (Typically from one of the *Info classes)
/// </summary>
- internal static string EnsureExtendedPrefixOverMaxPath(string path)
+ internal static string EnsureExtendedPrefixIfNeeded(string path)
{
- if (path != null && path.Length >= MaxShortPath)
+ if (path != null && (path.Length >= MaxShortPath || EndsWithPeriodOrSpace(path)))
{
return EnsureExtendedPrefix(path);
}
@@ -117,9 +105,9 @@ namespace System.IO
// Given \\server\share in longpath becomes \\?\UNC\server\share
if (path.StartsWith(UncPathPrefix, StringComparison.OrdinalIgnoreCase))
- return path.Insert(2, PathInternal.UncExtendedPrefixToInsert);
+ return path.Insert(2, UncDevicePrefixToInsert);
- return PathInternal.ExtendedPathPrefix + path;
+ return ExtendedDevicePathPrefix + path;
}
/// <summary>
@@ -156,85 +144,57 @@ namespace System.IO
&& path[3] == '\\';
}
- /// <summary>
- /// Check for known wildcard characters. '*' and '?' are the most common ones.
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static unsafe bool HasWildCardCharacters(string path)
- {
- // Question mark is part of dos device syntax so we have to skip if we are
- int startIndex = PathInternal.IsDevice(path) ? ExtendedPathPrefix.Length : 0;
-
- return path.IndexOfAny(s_wildcardChars, startIndex) >= 0;
- }
-
+#if !NOSPAN
/// <summary>
/// Gets the length of the root of the path (drive, share, etc.).
/// </summary>
- internal static unsafe int GetRootLength(string path)
+ internal static int GetRootLength(ReadOnlySpan<char> path)
{
- fixed(char* value = path)
- {
- return (int)GetRootLength(value, (uint)path.Length);
- }
- }
-
- private static unsafe uint GetRootLength(char* path, uint pathLength)
- {
- uint i = 0;
- uint volumeSeparatorLength = 2; // Length to the colon "C:"
- uint uncRootLength = 2; // Length to the start of the server name "\\"
+ int i = 0;
+ int volumeSeparatorLength = 2; // Length to the colon "C:"
+ int uncRootLength = 2; // Length to the start of the server name "\\"
- bool extendedSyntax = StartsWithOrdinal(path, pathLength, ExtendedPathPrefix);
- bool extendedUncSyntax = StartsWithOrdinal(path, pathLength, UncExtendedPathPrefix);
+ bool extendedSyntax = path.StartsWith(ExtendedDevicePathPrefix);
+ bool extendedUncSyntax = path.StartsWith(UncExtendedPathPrefix);
if (extendedSyntax)
{
// Shift the position we look for the root from to account for the extended prefix
if (extendedUncSyntax)
{
// "\\" -> "\\?\UNC\"
- uncRootLength = (uint)UncExtendedPathPrefix.Length;
+ uncRootLength = UncExtendedPathPrefix.Length;
}
else
{
// "C:" -> "\\?\C:"
- volumeSeparatorLength += (uint)ExtendedPathPrefix.Length;
+ volumeSeparatorLength += ExtendedDevicePathPrefix.Length;
}
}
- if ((!extendedSyntax || extendedUncSyntax) && pathLength > 0 && IsDirectorySeparator(path[0]))
+ if ((!extendedSyntax || extendedUncSyntax) && path.Length > 0 && IsDirectorySeparator(path[0]))
{
// UNC or simple rooted path (e.g. "\foo", NOT "\\?\C:\foo")
i = 1; // Drive rooted (\foo) is one character
- if (extendedUncSyntax || (pathLength > 1 && IsDirectorySeparator(path[1])))
+ if (extendedUncSyntax || (path.Length > 1 && IsDirectorySeparator(path[1])))
{
// UNC (\\?\UNC\ or \\), scan past the next two directory separators at most
// (e.g. to \\?\UNC\Server\Share or \\Server\Share\)
i = uncRootLength;
int n = 2; // Maximum separators to skip
- while (i < pathLength && (!IsDirectorySeparator(path[i]) || --n > 0)) i++;
+ while (i < path.Length && (!IsDirectorySeparator(path[i]) || --n > 0)) i++;
}
}
- else if (pathLength >= volumeSeparatorLength && path[volumeSeparatorLength - 1] == Path.VolumeSeparatorChar)
+ else if (path.Length >= volumeSeparatorLength && path[volumeSeparatorLength - 1] == Path.VolumeSeparatorChar)
{
// Path is at least longer than where we expect a colon, and has a colon (\\?\A:, A:)
// If the colon is followed by a directory separator, move past it
i = volumeSeparatorLength;
- if (pathLength >= volumeSeparatorLength + 1 && IsDirectorySeparator(path[volumeSeparatorLength])) i++;
+ if (path.Length >= volumeSeparatorLength + 1 && IsDirectorySeparator(path[volumeSeparatorLength])) i++;
}
return i;
}
-
- private static unsafe bool StartsWithOrdinal(char* source, uint sourceLength, string value)
- {
- if (sourceLength < (uint)value.Length) return false;
- for (int i = 0; i < value.Length; i++)
- {
- if (value[i] != source[i]) return false;
- }
- return true;
- }
+ #endif
/// <summary>
/// Returns true if the path specified is relative to the current drive or working directory.
@@ -275,29 +235,6 @@ namespace System.IO
}
/// <summary>
- /// Returns the characters to skip at the start of the path if it starts with space(s) and a drive or directory separator.
- /// (examples are " C:", " \")
- /// This is a legacy behavior of Path.GetFullPath().
- /// </summary>
- /// <remarks>
- /// Note that this conflicts with IsPathRooted() which doesn't (and never did) such a skip.
- /// </remarks>
- internal static int PathStartSkip(string path)
- {
- int startIndex = 0;
- while (startIndex < path.Length && path[startIndex] == ' ') startIndex++;
-
- if (startIndex > 0 && (startIndex < path.Length && PathInternal.IsDirectorySeparator(path[startIndex]))
- || (startIndex + 1 < path.Length && path[startIndex + 1] == ':' && PathInternal.IsValidDriveChar(path[startIndex])))
- {
- // Go ahead and skip spaces as we're either " C:" or " \"
- return startIndex;
- }
-
- return 0;
- }
-
- /// <summary>
/// True if the given character is a directory separator.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -305,105 +242,5 @@ namespace System.IO
{
return c == Path.DirectorySeparatorChar || c == Path.AltDirectorySeparatorChar;
}
-
- /// <summary>
- /// Normalize separators in the given path. Converts forward slashes into back slashes and compresses slash runs, keeping initial 2 if present.
- /// Also trims initial whitespace in front of "rooted" paths (see PathStartSkip).
- ///
- /// This effectively replicates the behavior of the legacy NormalizePath when it was called with fullCheck=false and expandShortpaths=false.
- /// The current NormalizePath gets directory separator normalization from Win32's GetFullPathName(), which will resolve relative paths and as
- /// such can't be used here (and is overkill for our uses).
- ///
- /// Like the current NormalizePath this will not try and analyze periods/spaces within directory segments.
- /// </summary>
- /// <remarks>
- /// The only callers that used to use Path.Normalize(fullCheck=false) were Path.GetDirectoryName() and Path.GetPathRoot(). Both usages do
- /// not need trimming of trailing whitespace here.
- ///
- /// GetPathRoot() could technically skip normalizing separators after the second segment- consider as a future optimization.
- ///
- /// For legacy desktop behavior with ExpandShortPaths:
- /// - It has no impact on GetPathRoot() so doesn't need consideration.
- /// - It could impact GetDirectoryName(), but only if the path isn't relative (C:\ or \\Server\Share).
- ///
- /// In the case of GetDirectoryName() the ExpandShortPaths behavior was undocumented and provided inconsistent results if the path was
- /// fixed/relative. For example: "C:\PROGRA~1\A.TXT" would return "C:\Program Files" while ".\PROGRA~1\A.TXT" would return ".\PROGRA~1". If you
- /// ultimately call GetFullPath() this doesn't matter, but if you don't or have any intermediate string handling could easily be tripped up by
- /// this undocumented behavior.
- ///
- /// We won't match this old behavior because:
- ///
- /// 1. It was undocumented
- /// 2. It was costly (extremely so if it actually contained '~')
- /// 3. Doesn't play nice with string logic
- /// 4. Isn't a cross-plat friendly concept/behavior
- /// </remarks>
- internal static string NormalizeDirectorySeparators(string path)
- {
- if (string.IsNullOrEmpty(path)) return path;
-
- char current;
- int start = PathStartSkip(path);
-
- if (start == 0)
- {
- // Make a pass to see if we need to normalize so we can potentially skip allocating
- bool normalized = true;
-
- for (int i = 0; i < path.Length; i++)
- {
- current = path[i];
- if (IsDirectorySeparator(current)
- && (current != Path.DirectorySeparatorChar
- // Check for sequential separators past the first position (we need to keep initial two for UNC/extended)
- || (i > 0 && i + 1 < path.Length && IsDirectorySeparator(path[i + 1]))))
- {
- normalized = false;
- break;
- }
- }
-
- if (normalized) return path;
- }
-
- StringBuilder builder = new StringBuilder(path.Length);
-
- if (IsDirectorySeparator(path[start]))
- {
- start++;
- builder.Append(Path.DirectorySeparatorChar);
- }
-
- for (int i = start; i < path.Length; i++)
- {
- current = path[i];
-
- // If we have a separator
- if (IsDirectorySeparator(current))
- {
- // If the next is a separator, skip adding this
- if (i + 1 < path.Length && IsDirectorySeparator(path[i + 1]))
- {
- continue;
- }
-
- // Ensure it is the primary separator
- current = Path.DirectorySeparatorChar;
- }
-
- builder.Append(current);
- }
-
- return builder.ToString();
- }
-
- /// <summary>
- /// Returns true if the character is a directory or volume separator.
- /// </summary>
- /// <param name="ch">The character to test.</param>
- internal static bool IsDirectoryOrVolumeSeparator(char ch)
- {
- return PathInternal.IsDirectorySeparator(ch) || Path.VolumeSeparatorChar == ch;
- }
}
}
diff --git a/src/Common/src/System/IO/PathInternal.cs b/src/Common/src/System/IO/PathInternal.cs
deleted file mode 100644
index 4d221e01a2..0000000000
--- a/src/Common/src/System/IO/PathInternal.cs
+++ /dev/null
@@ -1,149 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-using System.Text;
-
-namespace System.IO
-{
- /// <summary>Contains internal path helpers that are shared between many projects.</summary>
- internal static partial class PathInternal
- {
- /// <summary>
- /// Returns true if the given StringBuilder starts with the given value.
- /// </summary>
- /// <param name="value">The string to compare against the start of the StringBuilder.</param>
- internal static bool StartsWithOrdinal(this StringBuilder builder, string value)
- {
- if (value == null || builder.Length < value.Length)
- return false;
-
- for (int i = 0; i < value.Length; i++)
- {
- if (builder[i] != value[i]) return false;
- }
- return true;
- }
-
- /// <summary>
- /// Returns true if the given string starts with the given value.
- /// </summary>
- /// <param name="value">The string to compare against the start of the source string.</param>
- internal static bool StartsWithOrdinal(this string source, string value)
- {
- if (value == null || source.Length < value.Length)
- return false;
-
- return source.StartsWith(value, StringComparison.Ordinal);
- }
-
- /// <summary>
- /// Trims the specified characters from the end of the StringBuilder.
- /// </summary>
- internal static StringBuilder TrimEnd(this StringBuilder builder, params char[] trimChars)
- {
- if (trimChars == null || trimChars.Length == 0)
- return builder;
-
- int end = builder.Length - 1;
-
- for (; end >= 0; end--)
- {
- int i = 0;
- char ch = builder[end];
- for (; i < trimChars.Length; i++)
- {
- if (trimChars[i] == ch) break;
- }
- if (i == trimChars.Length)
- {
- // Not a trim char
- break;
- }
- }
-
- builder.Length = end + 1;
- return builder;
- }
-
- /// <summary>
- /// Returns true if the path ends in a directory separator.
- /// </summary>
- internal static bool EndsInDirectorySeparator(string path) =>
- !string.IsNullOrEmpty(path) && IsDirectorySeparator(path[path.Length - 1]);
-
- /// <summary>
- /// Get the common path length from the start of the string.
- /// </summary>
- internal static int GetCommonPathLength(string first, string second, bool ignoreCase)
- {
- int commonChars = EqualStartingCharacterCount(first, second, ignoreCase: ignoreCase);
-
- // If nothing matches
- if (commonChars == 0)
- return commonChars;
-
- // Or we're a full string and equal length or match to a separator
- if (commonChars == first.Length
- && (commonChars == second.Length || IsDirectorySeparator(second[commonChars])))
- return commonChars;
-
- if (commonChars == second.Length && IsDirectorySeparator(first[commonChars]))
- return commonChars;
-
- // It's possible we matched somewhere in the middle of a segment e.g. C:\Foodie and C:\Foobar.
- while (commonChars > 0 && !IsDirectorySeparator(first[commonChars - 1]))
- commonChars--;
-
- return commonChars;
- }
-
- /// <summary>
- /// Gets the count of common characters from the left optionally ignoring case
- /// </summary>
- internal static unsafe int EqualStartingCharacterCount(string first, string second, bool ignoreCase)
- {
- if (string.IsNullOrEmpty(first) || string.IsNullOrEmpty(second)) return 0;
-
- int commonChars = 0;
-
- fixed (char* f = first)
- fixed (char* s = second)
- {
- char* l = f;
- char* r = s;
- char* leftEnd = l + first.Length;
- char* rightEnd = r + second.Length;
-
- while (l != leftEnd && r != rightEnd
- && (*l == *r || (ignoreCase && char.ToUpperInvariant((*l)) == char.ToUpperInvariant((*r)))))
- {
- commonChars++;
- l++;
- r++;
- }
- }
-
- return commonChars;
- }
-
- /// <summary>
- /// Returns true if the two paths have the same root
- /// </summary>
- internal static bool AreRootsEqual(string first, string second, StringComparison comparisonType)
- {
- int firstRootLength = GetRootLength(first);
- int secondRootLength = GetRootLength(second);
-
- return firstRootLength == secondRootLength
- && string.Compare(
- strA: first,
- indexA: 0,
- strB: second,
- indexB: 0,
- length: firstRootLength,
- comparisonType: comparisonType) == 0;
- }
- }
-}
diff --git a/src/Common/src/System/IO/PersistedFiles.Unix.cs b/src/Common/src/System/IO/PersistedFiles.Unix.cs
index 243a38323f..d8064af2b7 100644
--- a/src/Common/src/System/IO/PersistedFiles.Unix.cs
+++ b/src/Common/src/System/IO/PersistedFiles.Unix.cs
@@ -97,7 +97,7 @@ namespace System.IO
// if we simply couldn't find a home directory for the current user.
// In that case, we pass back the null value and let the caller decide
// what to do.
- const int BufLen = 1024;
+ const int BufLen = Interop.Sys.Passwd.InitialBufferSize;
byte* stackBuf = stackalloc byte[BufLen];
if (TryGetHomeDirectoryFromPasswd(stackBuf, BufLen, out userHomeDirectory))
return userHomeDirectory;
diff --git a/src/Common/src/System/IO/ReadOnlyMemoryStream.cs b/src/Common/src/System/IO/ReadOnlyMemoryStream.cs
index 9c240b8e56..0c0f077c35 100644
--- a/src/Common/src/System/IO/ReadOnlyMemoryStream.cs
+++ b/src/Common/src/System/IO/ReadOnlyMemoryStream.cs
@@ -70,25 +70,25 @@ namespace System.IO
return Read(new Span<byte>(buffer, offset, count));
}
- public override int Read(Span<byte> destination)
+ public override int Read(Span<byte> buffer)
{
int remaining = _content.Length - _position;
- if (remaining <= 0 || destination.Length == 0)
+ if (remaining <= 0 || buffer.Length == 0)
{
return 0;
}
- else if (remaining <= destination.Length)
+ else if (remaining <= buffer.Length)
{
- _content.Span.Slice(_position).CopyTo(destination);
+ _content.Span.Slice(_position).CopyTo(buffer);
_position = _content.Length;
return remaining;
}
else
{
- _content.Span.Slice(_position, destination.Length).CopyTo(destination);
- _position += destination.Length;
- return destination.Length;
+ _content.Span.Slice(_position, buffer.Length).CopyTo(buffer);
+ _position += buffer.Length;
+ return buffer.Length;
}
}
@@ -100,10 +100,10 @@ namespace System.IO
Task.FromResult(Read(new Span<byte>(buffer, offset, count)));
}
- public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken = default(CancellationToken)) =>
+ public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default(CancellationToken)) =>
cancellationToken.IsCancellationRequested ?
new ValueTask<int>(Task.FromCanceled<int>(cancellationToken)) :
- new ValueTask<int>(Read(destination.Span));
+ new ValueTask<int>(Read(buffer.Span));
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) =>
TaskToApm.Begin(ReadAsync(buffer, offset, count), callback, state);
@@ -124,7 +124,7 @@ namespace System.IO
{
StreamHelpers.ValidateCopyToArgs(this, destination, bufferSize);
return _content.Length > _position ?
- destination.WriteAsync(_content.Slice(_position), cancellationToken) :
+ destination.WriteAsync(_content.Slice(_position), cancellationToken).AsTask() :
Task.CompletedTask;
}
diff --git a/src/Common/src/System/IO/Win32Marshal.cs b/src/Common/src/System/IO/Win32Marshal.cs
deleted file mode 100644
index d45b98bdc5..0000000000
--- a/src/Common/src/System/IO/Win32Marshal.cs
+++ /dev/null
@@ -1,136 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Runtime.InteropServices;
-
-namespace System.IO
-{
- /// <summary>
- /// Provides static methods for converting from Win32 errors codes to exceptions, HRESULTS and error messages.
- /// </summary>
- internal static class Win32Marshal
- {
- /// <summary>
- /// Converts, resetting it, the last Win32 error into a corresponding <see cref="Exception"/> object.
- /// </summary>
- internal static Exception GetExceptionForLastWin32Error()
- {
- int errorCode = Marshal.GetLastWin32Error();
- return GetExceptionForWin32Error(errorCode, string.Empty);
- }
-
- /// <summary>
- /// Converts, resetting it, the last Win32 error into a corresponding <see cref="Exception"/> object, optionally
- /// including the specified path in the error message.
- /// </summary>
- internal static Exception GetExceptionForLastWin32Error(string path)
- {
- int errorCode = Marshal.GetLastWin32Error();
- return GetExceptionForWin32Error(errorCode, path);
- }
-
- /// <summary>
- /// Converts the specified Win32 error into a corresponding <see cref="Exception"/> object.
- /// </summary>
- internal static Exception GetExceptionForWin32Error(int errorCode)
- {
- return GetExceptionForWin32Error(errorCode, string.Empty);
- }
-
- /// <summary>
- /// Converts the specified Win32 error into a corresponding <see cref="Exception"/> object, optionally
- /// including the specified path in the error message.
- /// </summary>
- internal static Exception GetExceptionForWin32Error(int errorCode, string path)
- {
- switch (errorCode)
- {
- case Interop.Errors.ERROR_FILE_NOT_FOUND:
- if (path.Length == 0)
- return new FileNotFoundException(SR.IO_FileNotFound);
- else
- return new FileNotFoundException(SR.Format(SR.IO_FileNotFound_FileName, path), path);
-
- case Interop.Errors.ERROR_PATH_NOT_FOUND:
- if (path.Length == 0)
- return new DirectoryNotFoundException(SR.IO_PathNotFound_NoPathName);
- else
- return new DirectoryNotFoundException(SR.Format(SR.IO_PathNotFound_Path, path));
-
- case Interop.Errors.ERROR_ACCESS_DENIED:
- if (path.Length == 0)
- return new UnauthorizedAccessException(SR.UnauthorizedAccess_IODenied_NoPathName);
- else
- return new UnauthorizedAccessException(SR.Format(SR.UnauthorizedAccess_IODenied_Path, path));
-
- case Interop.Errors.ERROR_ALREADY_EXISTS:
- if (path.Length == 0)
- goto default;
-
- return new IOException(SR.Format(SR.IO_AlreadyExists_Name, path), MakeHRFromErrorCode(errorCode));
-
- case Interop.Errors.ERROR_FILENAME_EXCED_RANGE:
- return !string.IsNullOrEmpty(path) ?
- new PathTooLongException(SR.Format(SR.IO_PathTooLong_Path, path)) :
- new PathTooLongException(SR.IO_PathTooLong);
-
- case Interop.Errors.ERROR_INVALID_PARAMETER:
- return new IOException(GetMessage(errorCode), MakeHRFromErrorCode(errorCode));
-
- case Interop.Errors.ERROR_SHARING_VIOLATION:
- if (path.Length == 0)
- return new IOException(SR.IO_SharingViolation_NoFileName, MakeHRFromErrorCode(errorCode));
- else
- return new IOException(SR.Format(SR.IO_SharingViolation_File, path), MakeHRFromErrorCode(errorCode));
-
- case Interop.Errors.ERROR_FILE_EXISTS:
- if (path.Length == 0)
- goto default;
-
- return new IOException(SR.Format(SR.IO_FileExists_Name, path), MakeHRFromErrorCode(errorCode));
-
- case Interop.Errors.ERROR_OPERATION_ABORTED:
- return new OperationCanceledException();
-
- default:
- return new IOException(GetMessage(errorCode), MakeHRFromErrorCode(errorCode));
- }
- }
-
- /// <summary>
- /// If not already an HRESULT, returns an HRESULT for the specified Win32 error code.
- /// </summary>
- internal static int MakeHRFromErrorCode(int errorCode)
- {
- // Don't convert it if it is already an HRESULT
- if ((0xFFFF0000 & errorCode) != 0)
- return errorCode;
-
- return unchecked(((int)0x80070000) | errorCode);
- }
-
- /// <summary>
- /// Returns a Win32 error code for the specified HRESULT if it came from FACILITY_WIN32
- /// If not, returns the HRESULT unchanged
- /// </summary>
- internal static int TryMakeWin32ErrorCodeFromHR(int hr)
- {
- if ((0xFFFF0000 & hr) == 0x80070000)
- {
- // Win32 error, Win32Marshal.GetExceptionForWin32Error expects the Win32 format
- hr &= 0x0000FFFF;
- }
-
- return hr;
- }
-
- /// <summary>
- /// Returns a string message for the specified Win32 error code.
- /// </summary>
- internal static string GetMessage(int errorCode)
- {
- return Interop.Kernel32.GetMessage(errorCode);
- }
- }
-}
diff --git a/src/Common/src/System/Marvin.cs b/src/Common/src/System/Marvin.cs
index ee22d27864..611fc5d51c 100644
--- a/src/Common/src/System/Marvin.cs
+++ b/src/Common/src/System/Marvin.cs
@@ -4,6 +4,7 @@
using System.Diagnostics;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using System.Security.Cryptography;
namespace System
@@ -30,7 +31,7 @@ namespace System
if (data.Length >= sizeof(uint))
{
- ReadOnlySpan<uint> uData = data.NonPortableCast<byte, uint>();
+ ReadOnlySpan<uint> uData = MemoryMarshal.Cast<byte, uint>(data);
for (int i = 0; i < uData.Length; i++)
{
@@ -56,11 +57,11 @@ namespace System
break;
case 2:
- p0 += 0x800000u | data.NonPortableCast<byte, ushort>()[0];
+ p0 += 0x800000u | MemoryMarshal.Cast<byte, ushort>(data)[0];
break;
case 3:
- p0 += 0x80000000u | (((uint)data[2]) << 16) | (uint)(data.NonPortableCast<byte, ushort>()[0]);
+ p0 += 0x80000000u | (((uint)data[2]) << 16) | (uint)(MemoryMarshal.Cast<byte, ushort>(data)[0]);
break;
default:
diff --git a/src/System.Memory/Common/src/System/MutableDecimal.cs b/src/Common/src/System/MutableDecimal.cs
index a5541a6f2a..a5541a6f2a 100644
--- a/src/System.Memory/Common/src/System/MutableDecimal.cs
+++ b/src/Common/src/System/MutableDecimal.cs
diff --git a/src/Common/src/System/Net/Http/HttpHandlerDefaults.cs b/src/Common/src/System/Net/Http/HttpHandlerDefaults.cs
index 5e82229bd7..e3991bd17f 100644
--- a/src/Common/src/System/Net/Http/HttpHandlerDefaults.cs
+++ b/src/Common/src/System/Net/Http/HttpHandlerDefaults.cs
@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Threading;
+
namespace System.Net.Http
{
/// <summary>
@@ -11,6 +13,8 @@ namespace System.Net.Http
{
public const int DefaultMaxAutomaticRedirections = 50;
public const int DefaultMaxConnectionsPerServer = int.MaxValue;
+ public const int DefaultMaxResponseDrainSize = 1024 * 1024;
+ public static readonly TimeSpan DefaultResponseDrainTimeout = TimeSpan.FromSeconds(2);
public const int DefaultMaxResponseHeadersLength = 64; // Units in K (1024) bytes.
public const DecompressionMethods DefaultAutomaticDecompression = DecompressionMethods.None;
public const bool DefaultAutomaticRedirection = true;
@@ -20,7 +24,9 @@ namespace System.Net.Http
public const bool DefaultUseProxy = true;
public const bool DefaultUseDefaultCredentials = false;
public const bool DefaultCheckCertificateRevocationList = false;
-
- public static TimeSpan DefaultConnectTimeout => TimeSpan.FromSeconds(60);
+ public static readonly TimeSpan DefaultPooledConnectionLifetime = Timeout.InfiniteTimeSpan;
+ public static readonly TimeSpan DefaultPooledConnectionIdleTimeout = TimeSpan.FromMinutes(2);
+ public static readonly TimeSpan DefaultExpect100ContinueTimeout = TimeSpan.FromSeconds(1);
+ public static readonly TimeSpan DefaultConnectTimeout = Timeout.InfiniteTimeSpan;
}
}
diff --git a/src/Common/src/System/Net/Http/NoWriteNoSeekStreamContent.cs b/src/Common/src/System/Net/Http/NoWriteNoSeekStreamContent.cs
index 2d55520f23..202782cc10 100644
--- a/src/Common/src/System/Net/Http/NoWriteNoSeekStreamContent.cs
+++ b/src/Common/src/System/Net/Http/NoWriteNoSeekStreamContent.cs
@@ -14,10 +14,9 @@ namespace System.Net.Http
internal sealed class NoWriteNoSeekStreamContent : HttpContent
{
private readonly Stream _content;
- private readonly CancellationToken _cancellationToken;
private bool _contentConsumed;
- internal NoWriteNoSeekStreamContent(Stream content, CancellationToken cancellationToken)
+ internal NoWriteNoSeekStreamContent(Stream content)
{
Debug.Assert(content != null);
Debug.Assert(content.CanRead);
@@ -25,10 +24,16 @@ namespace System.Net.Http
Debug.Assert(!content.CanSeek);
_content = content;
- _cancellationToken = cancellationToken;
}
- protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
+ protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) =>
+ SerializeToStreamAsync(stream, context, CancellationToken.None);
+
+ internal
+#if HTTP_DLL
+ override
+#endif
+ Task SerializeToStreamAsync(Stream stream, TransportContext context, CancellationToken cancellationToken)
{
Debug.Assert(stream != null);
@@ -39,7 +44,7 @@ namespace System.Net.Http
_contentConsumed = true;
const int BufferSize = 8192;
- Task copyTask = _content.CopyToAsync(stream, BufferSize, _cancellationToken);
+ Task copyTask = _content.CopyToAsync(stream, BufferSize, cancellationToken);
if (copyTask.IsCompleted)
{
try { _content.Dispose(); } catch { } // same as StreamToStreamCopy behavior
@@ -75,6 +80,10 @@ namespace System.Net.Http
base.Dispose(disposing);
}
- protected override Task<Stream> CreateContentReadStreamAsync() => Task.FromResult<Stream>(_content);
+ protected override Task<Stream> CreateContentReadStreamAsync() => Task.FromResult(_content);
+
+#if HTTP_DLL
+ internal override Stream TryCreateContentReadStream() => _content;
+#endif
}
}
diff --git a/src/Common/src/System/Net/HttpStatusDescription.cs b/src/Common/src/System/Net/HttpStatusDescription.cs
index a59baadff9..3bbc640fbd 100644
--- a/src/Common/src/System/Net/HttpStatusDescription.cs
+++ b/src/Common/src/System/Net/HttpStatusDescription.cs
@@ -2,8 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Runtime.CompilerServices;
-
namespace System.Net
{
internal static class HttpStatusDescription
@@ -20,6 +18,7 @@ namespace System.Net
case 100: return "Continue";
case 101: return "Switching Protocols";
case 102: return "Processing";
+ case 103: return "Early Hints";
case 200: return "OK";
case 201: return "Created";
@@ -29,6 +28,8 @@ namespace System.Net
case 205: return "Reset Content";
case 206: return "Partial Content";
case 207: return "Multi-Status";
+ case 208: return "Already Reported";
+ case 226: return "IM Used";
case 300: return "Multiple Choices";
case 301: return "Moved Permanently";
@@ -37,6 +38,7 @@ namespace System.Net
case 304: return "Not Modified";
case 305: return "Use Proxy";
case 307: return "Temporary Redirect";
+ case 308: return "Permanent Redirect";
case 400: return "Bad Request";
case 401: return "Unauthorized";
@@ -56,10 +58,15 @@ namespace System.Net
case 415: return "Unsupported Media Type";
case 416: return "Requested Range Not Satisfiable";
case 417: return "Expectation Failed";
+ case 421: return "Misdirected Request";
case 422: return "Unprocessable Entity";
case 423: return "Locked";
case 424: return "Failed Dependency";
case 426: return "Upgrade Required"; // RFC 2817
+ case 428: return "Precondition Required";
+ case 429: return "Too Many Requests";
+ case 431: return "Request Header Fields Too Large";
+ case 451: return "Unavailable For Legal Reasons";
case 500: return "Internal Server Error";
case 501: return "Not Implemented";
@@ -67,7 +74,11 @@ namespace System.Net
case 503: return "Service Unavailable";
case 504: return "Gateway Timeout";
case 505: return "Http Version Not Supported";
+ case 506: return "Variant Also Negotiates";
case 507: return "Insufficient Storage";
+ case 508: return "Loop Detected";
+ case 510: return "Not Extended";
+ case 511: return "Network Authentication Required";
}
return null;
}
diff --git a/src/Common/src/System/Net/Logging/NetEventSource.Common.cs b/src/Common/src/System/Net/Logging/NetEventSource.Common.cs
index de61e61aac..6d3b94e120 100644
--- a/src/Common/src/System/Net/Logging/NetEventSource.Common.cs
+++ b/src/Common/src/System/Net/Logging/NetEventSource.Common.cs
@@ -75,7 +75,19 @@ namespace System.Net
private const int CriticalFailureEventId = 6;
private const int DumpArrayEventId = 7;
- private const int NextAvailableEventId = 8; // Update this value whenever new events are added. Derived types should base all events off of this to avoid conflicts.
+ // These events are implemented in NetEventSource.Security.cs.
+ // Define the ids here so that projects that include NetEventSource.Security.cs will not have conflicts.
+ private const int EnumerateSecurityPackagesId = 8;
+ private const int SspiPackageNotFoundId = 9;
+ private const int AcquireDefaultCredentialId = 10;
+ private const int AcquireCredentialsHandleId = 11;
+ private const int InitializeSecurityContextId = 12;
+ private const int SecurityContextInputBufferId = 13;
+ private const int SecurityContextInputBuffersId = 14;
+ private const int AcceptSecuritContextId = 15;
+ private const int OperationReturnedSomethingId = 16;
+
+ private const int NextAvailableEventId = 17; // Update this value whenever new events are added. Derived types should base all events off of this to avoid conflicts.
#endregion
#region Events
@@ -395,7 +407,9 @@ namespace System.Net
Debug.Assert(IsEnabled || arg == null, $"Should not be formatting FormattableString \"{arg}\" if tracing isn't enabled");
}
- public static new bool IsEnabled => Log.IsEnabled();
+ public static new bool IsEnabled =>
+ Log.IsEnabled();
+ //true; // uncomment for debugging only
[NonEvent]
public static string IdOf(object value) => value != null ? value.GetType().Name + "#" + GetHashCode(value) : NullInstance;
@@ -502,17 +516,26 @@ namespace System.Net
const int NumEventDatas = 4;
var descrs = stackalloc EventData[NumEventDatas];
- descrs[0].DataPointer = (IntPtr)string1Bytes;
- descrs[0].Size = ((arg1.Length + 1) * 2);
-
- descrs[1].DataPointer = (IntPtr)string2Bytes;
- descrs[1].Size = ((arg2.Length + 1) * 2);
-
- descrs[2].DataPointer = (IntPtr)string3Bytes;
- descrs[2].Size = ((arg3.Length + 1) * 2);
-
- descrs[3].DataPointer = (IntPtr)string4Bytes;
- descrs[3].Size = ((arg4.Length + 1) * 2);
+ descrs[0] = new EventData
+ {
+ DataPointer = (IntPtr)string1Bytes,
+ Size = ((arg1.Length + 1) * 2)
+ };
+ descrs[1] = new EventData
+ {
+ DataPointer = (IntPtr)string2Bytes,
+ Size = ((arg2.Length + 1) * 2)
+ };
+ descrs[2] = new EventData
+ {
+ DataPointer = (IntPtr)string3Bytes,
+ Size = ((arg3.Length + 1) * 2)
+ };
+ descrs[3] = new EventData
+ {
+ DataPointer = (IntPtr)string4Bytes,
+ Size = ((arg4.Length + 1) * 2)
+ };
WriteEventCore(eventId, NumEventDatas, descrs);
}
@@ -536,17 +559,26 @@ namespace System.Net
const int NumEventDatas = 4;
var descrs = stackalloc EventData[NumEventDatas];
- descrs[0].DataPointer = (IntPtr)arg1Ptr;
- descrs[0].Size = (arg1.Length + 1) * sizeof(char);
-
- descrs[1].DataPointer = (IntPtr)arg2Ptr;
- descrs[1].Size = (arg2.Length + 1) * sizeof(char);
-
- descrs[2].DataPointer = (IntPtr)(&bufferLength);
- descrs[2].Size = 4;
-
- descrs[3].DataPointer = (IntPtr)arg3Ptr;
- descrs[3].Size = bufferLength;
+ descrs[0] = new EventData
+ {
+ DataPointer = (IntPtr)arg1Ptr,
+ Size = (arg1.Length + 1) * sizeof(char)
+ };
+ descrs[1] = new EventData
+ {
+ DataPointer = (IntPtr)arg2Ptr,
+ Size = (arg2.Length + 1) * sizeof(char)
+ };
+ descrs[2] = new EventData
+ {
+ DataPointer = (IntPtr)(&bufferLength),
+ Size = 4
+ };
+ descrs[3] = new EventData
+ {
+ DataPointer = (IntPtr)arg3Ptr,
+ Size = bufferLength
+ };
WriteEventCore(eventId, NumEventDatas, descrs);
}
@@ -565,17 +597,26 @@ namespace System.Net
const int NumEventDatas = 4;
var descrs = stackalloc EventData[NumEventDatas];
- descrs[0].DataPointer = (IntPtr)(arg1Ptr);
- descrs[0].Size = (arg1.Length + 1) * sizeof(char);
-
- descrs[1].DataPointer = (IntPtr)(&arg2);
- descrs[1].Size = sizeof(int);
-
- descrs[2].DataPointer = (IntPtr)(&arg3);
- descrs[2].Size = sizeof(int);
-
- descrs[3].DataPointer = (IntPtr)(&arg4);
- descrs[3].Size = sizeof(int);
+ descrs[0] = new EventData
+ {
+ DataPointer = (IntPtr)(arg1Ptr),
+ Size = (arg1.Length + 1) * sizeof(char)
+ };
+ descrs[1] = new EventData
+ {
+ DataPointer = (IntPtr)(&arg2),
+ Size = sizeof(int)
+ };
+ descrs[2] = new EventData
+ {
+ DataPointer = (IntPtr)(&arg3),
+ Size = sizeof(int)
+ };
+ descrs[3] = new EventData
+ {
+ DataPointer = (IntPtr)(&arg4),
+ Size = sizeof(int)
+ };
WriteEventCore(eventId, NumEventDatas, descrs);
}
@@ -596,14 +637,21 @@ namespace System.Net
const int NumEventDatas = 3;
var descrs = stackalloc EventData[NumEventDatas];
- descrs[0].DataPointer = (IntPtr)(arg1Ptr);
- descrs[0].Size = (arg1.Length + 1) * sizeof(char);
-
- descrs[1].DataPointer = (IntPtr)(&arg2);
- descrs[1].Size = sizeof(int);
-
- descrs[2].DataPointer = (IntPtr)(arg3Ptr);
- descrs[2].Size = (arg3.Length + 1) * sizeof(char);
+ descrs[0] = new EventData
+ {
+ DataPointer = (IntPtr)(arg1Ptr),
+ Size = (arg1.Length + 1) * sizeof(char)
+ };
+ descrs[1] = new EventData
+ {
+ DataPointer = (IntPtr)(&arg2),
+ Size = sizeof(int)
+ };
+ descrs[2] = new EventData
+ {
+ DataPointer = (IntPtr)(arg3Ptr),
+ Size = (arg3.Length + 1) * sizeof(char)
+ };
WriteEventCore(eventId, NumEventDatas, descrs);
}
@@ -624,14 +672,21 @@ namespace System.Net
const int NumEventDatas = 3;
var descrs = stackalloc EventData[NumEventDatas];
- descrs[0].DataPointer = (IntPtr)(arg1Ptr);
- descrs[0].Size = (arg1.Length + 1) * sizeof(char);
-
- descrs[1].DataPointer = (IntPtr)(arg2Ptr);
- descrs[1].Size = (arg2.Length + 1) * sizeof(char);
-
- descrs[2].DataPointer = (IntPtr)(&arg3);
- descrs[2].Size = sizeof(int);
+ descrs[0] = new EventData
+ {
+ DataPointer = (IntPtr)(arg1Ptr),
+ Size = (arg1.Length + 1) * sizeof(char)
+ };
+ descrs[1] = new EventData
+ {
+ DataPointer = (IntPtr)(arg2Ptr),
+ Size = (arg2.Length + 1) * sizeof(char)
+ };
+ descrs[2] = new EventData
+ {
+ DataPointer = (IntPtr)(&arg3),
+ Size = sizeof(int)
+ };
WriteEventCore(eventId, NumEventDatas, descrs);
}
@@ -654,17 +709,26 @@ namespace System.Net
const int NumEventDatas = 4;
var descrs = stackalloc EventData[NumEventDatas];
- descrs[0].DataPointer = (IntPtr)(arg1Ptr);
- descrs[0].Size = (arg1.Length + 1) * sizeof(char);
-
- descrs[1].DataPointer = (IntPtr)(arg2Ptr);
- descrs[1].Size = (arg2.Length + 1) * sizeof(char);
-
- descrs[2].DataPointer = (IntPtr)(arg3Ptr);
- descrs[2].Size = (arg3.Length + 1) * sizeof(char);
-
- descrs[3].DataPointer = (IntPtr)(&arg4);
- descrs[3].Size = sizeof(int);
+ descrs[0] = new EventData
+ {
+ DataPointer = (IntPtr)(arg1Ptr),
+ Size = (arg1.Length + 1) * sizeof(char)
+ };
+ descrs[1] = new EventData
+ {
+ DataPointer = (IntPtr)(arg2Ptr),
+ Size = (arg2.Length + 1) * sizeof(char)
+ };
+ descrs[2] = new EventData
+ {
+ DataPointer = (IntPtr)(arg3Ptr),
+ Size = (arg3.Length + 1) * sizeof(char)
+ };
+ descrs[3] = new EventData
+ {
+ DataPointer = (IntPtr)(&arg4),
+ Size = sizeof(int)
+ };
WriteEventCore(eventId, NumEventDatas, descrs);
}
diff --git a/src/Common/src/System/Net/NTAuthentication.Common.cs b/src/Common/src/System/Net/NTAuthentication.Common.cs
index 7ba6afb4b3..84916e3fd2 100644
--- a/src/Common/src/System/Net/NTAuthentication.Common.cs
+++ b/src/Common/src/System/Net/NTAuthentication.Common.cs
@@ -214,22 +214,22 @@ namespace System.Net
{
if (NetEventSource.IsEnabled) NetEventSource.Enter(this, incomingBlob);
- var list = new List<SecurityBuffer>(2);
-
- if (incomingBlob != null)
+ SecurityBuffer[] inSecurityBufferArray = null;
+ if (incomingBlob != null && _channelBinding != null)
{
- list.Add(new SecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN));
+ inSecurityBufferArray = new SecurityBuffer[2]
+ {
+ new SecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN),
+ new SecurityBuffer(_channelBinding)
+ };
}
-
- if (_channelBinding != null)
+ else if (incomingBlob != null)
{
- list.Add(new SecurityBuffer(_channelBinding));
+ inSecurityBufferArray = new SecurityBuffer[1] { new SecurityBuffer(incomingBlob, SecurityBufferType.SECBUFFER_TOKEN) };
}
-
- SecurityBuffer[] inSecurityBufferArray = null;
- if (list.Count > 0)
+ else if (_channelBinding != null)
{
- inSecurityBufferArray = list.ToArray();
+ inSecurityBufferArray = new SecurityBuffer[1] { new SecurityBuffer(_channelBinding) };
}
var outSecurityBuffer = new SecurityBuffer(_tokenSize, SecurityBufferType.SECBUFFER_TOKEN);
diff --git a/src/Common/src/System/Net/NetworkInformation/UnixCommandLinePing.cs b/src/Common/src/System/Net/NetworkInformation/UnixCommandLinePing.cs
index e18c29e67a..499ed10120 100644
--- a/src/Common/src/System/Net/NetworkInformation/UnixCommandLinePing.cs
+++ b/src/Common/src/System/Net/NetworkInformation/UnixCommandLinePing.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Globalization;
using System.IO;
using System.Text;
@@ -88,7 +89,7 @@ namespace System.Net.NetworkInformation
int msIndex = pingOutput.IndexOf("ms", afterTime);
int numLength = msIndex - afterTime - 1;
string timeSubstring = pingOutput.Substring(afterTime, numLength);
- double parsedRtt = double.Parse(timeSubstring);
+ double parsedRtt = double.Parse(timeSubstring, CultureInfo.InvariantCulture);
return (long)Math.Round(parsedRtt);
}
}
diff --git a/src/Common/src/System/Net/SafeCloseSocket.Windows.cs b/src/Common/src/System/Net/SafeCloseSocket.Windows.cs
index 778e9bd300..b1ae33243e 100644
--- a/src/Common/src/System/Net/SafeCloseSocket.Windows.cs
+++ b/src/Common/src/System/Net/SafeCloseSocket.Windows.cs
@@ -30,35 +30,31 @@ namespace System.Net.Sockets
}
}
+ public ThreadPoolBoundHandle GetThreadPoolBoundHandle() => !_released ? _iocpBoundHandle : null;
+
// Binds the Socket Win32 Handle to the ThreadPool's CompletionPort.
public ThreadPoolBoundHandle GetOrAllocateThreadPoolBoundHandle(bool trySkipCompletionPortOnSuccess)
{
- // Check to see if the socket native _handle is already
- // bound to the ThreadPool's completion port.
- if (_released || _iocpBoundHandle == null)
- {
- GetOrAllocateThreadPoolBoundHandleSlow(trySkipCompletionPortOnSuccess);
- }
-
- return _iocpBoundHandle;
- }
-
- private void GetOrAllocateThreadPoolBoundHandleSlow(bool trySkipCompletionPortOnSuccess)
- {
if (_released)
{
// Keep the exception message pointing at the external type.
throw new ObjectDisposedException(typeof(Socket).FullName);
}
+ if (_iocpBoundHandle != null)
+ {
+ return _iocpBoundHandle;
+ }
+
lock (_iocpBindingLock)
{
- if (_iocpBoundHandle == null)
+ ThreadPoolBoundHandle boundHandle = _iocpBoundHandle;
+
+ if (boundHandle == null)
{
// Bind the socket native _handle to the ThreadPool.
if (NetEventSource.IsEnabled) NetEventSource.Info(this, "calling ThreadPool.BindHandle()");
- ThreadPoolBoundHandle boundHandle;
try
{
// The handle (this) may have been already released:
@@ -80,8 +76,10 @@ namespace System.Net.Sockets
}
// Don't set this until after we've configured the handle above (if we did)
- _iocpBoundHandle = boundHandle;
+ Volatile.Write(ref _iocpBoundHandle, boundHandle);
}
+
+ return boundHandle;
}
}
diff --git a/src/Common/src/System/Net/Security/CertificateHelper.Unix.cs b/src/Common/src/System/Net/Security/CertificateHelper.Unix.cs
new file mode 100644
index 0000000000..3cc48f9662
--- /dev/null
+++ b/src/Common/src/System/Net/Security/CertificateHelper.Unix.cs
@@ -0,0 +1,24 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Security.Cryptography.X509Certificates;
+
+namespace System.Net.Security
+{
+ internal static partial class CertificateHelper
+ {
+ internal static X509Certificate2 GetEligibleClientCertificate()
+ {
+ // Get initial list of client certificates from the MY store.
+ X509Certificate2Collection candidateCerts;
+ using (var myStore = new X509Store(StoreName.My, StoreLocation.CurrentUser))
+ {
+ myStore.Open(OpenFlags.ReadOnly);
+ candidateCerts = myStore.Certificates;
+ }
+
+ return GetEligibleClientCertificate(candidateCerts);
+ }
+ }
+}
diff --git a/src/Common/src/System/Net/Security/CertificateHelper.Windows.cs b/src/Common/src/System/Net/Security/CertificateHelper.Windows.cs
index dd89e581c9..6692678c57 100644
--- a/src/Common/src/System/Net/Security/CertificateHelper.Windows.cs
+++ b/src/Common/src/System/Net/Security/CertificateHelper.Windows.cs
@@ -2,9 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using Microsoft.Win32.SafeHandles;
-using System.Diagnostics;
-using System.Globalization;
using System.Security.Cryptography.X509Certificates;
namespace System.Net.Security
diff --git a/src/Common/src/System/Net/Security/NetEventSource.Security.cs b/src/Common/src/System/Net/Security/NetEventSource.Security.cs
index f7dc49a27d..b003ce8b7e 100644
--- a/src/Common/src/System/Net/Security/NetEventSource.Security.cs
+++ b/src/Common/src/System/Net/Security/NetEventSource.Security.cs
@@ -13,15 +13,7 @@ namespace System.Net
//TODO: If localization resources are not found, logging does not work. Issue #5126.
internal sealed partial class NetEventSource
{
- private const int EnumerateSecurityPackagesId = NextAvailableEventId;
- private const int SspiPackageNotFoundId = EnumerateSecurityPackagesId + 1;
- private const int AcquireDefaultCredentialId = SspiPackageNotFoundId + 1;
- private const int AcquireCredentialsHandleId = AcquireDefaultCredentialId + 1;
- private const int InitializeSecurityContextId = AcquireCredentialsHandleId + 1;
- private const int SecurityContextInputBufferId = InitializeSecurityContextId + 1;
- private const int SecurityContextInputBuffersId = SecurityContextInputBufferId + 1;
- private const int AcceptSecuritContextId = SecurityContextInputBuffersId + 1;
- private const int OperationReturnedSomethingId = AcceptSecuritContextId + 1;
+ // Event ids are defined in NetEventSource.Common.cs.
[Event(EnumerateSecurityPackagesId, Keywords = Keywords.Default, Level = EventLevel.Informational)]
public void EnumerateSecurityPackages(string securityPackage)
diff --git a/src/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs b/src/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs
new file mode 100644
index 0000000000..b3296a0907
--- /dev/null
+++ b/src/Common/src/System/Net/Security/SslClientAuthenticationOptionsExtensions.cs
@@ -0,0 +1,23 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Net.Security
+{
+ internal static class SslClientAuthenticationOptionsExtensions
+ {
+ public static SslClientAuthenticationOptions ShallowClone(this SslClientAuthenticationOptions options) =>
+ new SslClientAuthenticationOptions()
+ {
+ AllowRenegotiation = options.AllowRenegotiation,
+ ApplicationProtocols = options.ApplicationProtocols,
+ CertificateRevocationCheckMode = options.CertificateRevocationCheckMode,
+ ClientCertificates = options.ClientCertificates,
+ EnabledSslProtocols = options.EnabledSslProtocols,
+ EncryptionPolicy = options.EncryptionPolicy,
+ LocalCertificateSelectionCallback = options.LocalCertificateSelectionCallback,
+ RemoteCertificateValidationCallback = options.RemoteCertificateValidationCallback,
+ TargetHost = options.TargetHost
+ };
+ }
+}
diff --git a/src/Common/src/System/Net/SocketAddressPal.Unix.cs b/src/Common/src/System/Net/SocketAddressPal.Unix.cs
index f7eaf04fbd..94360635e2 100644
--- a/src/Common/src/System/Net/SocketAddressPal.Unix.cs
+++ b/src/Common/src/System/Net/SocketAddressPal.Unix.cs
@@ -102,11 +102,11 @@ namespace System.Net
ThrowOnFailure(err);
}
- public static unsafe uint GetIPv4Address(byte[] buffer)
+ public static unsafe uint GetIPv4Address(ReadOnlySpan<byte> buffer)
{
uint ipAddress;
Interop.Error err;
- fixed (byte* rawAddress = buffer)
+ fixed (byte* rawAddress = &MemoryMarshal.GetReference(buffer))
{
err = Interop.Sys.GetIPv4Address(rawAddress, buffer.Length, &ipAddress);
}
@@ -115,11 +115,11 @@ namespace System.Net
return ipAddress;
}
- public static unsafe void GetIPv6Address(byte[] buffer, Span<byte> address, out uint scope)
+ public static unsafe void GetIPv6Address(ReadOnlySpan<byte> buffer, Span<byte> address, out uint scope)
{
uint localScope;
Interop.Error err;
- fixed (byte* rawAddress = buffer)
+ fixed (byte* rawAddress = &MemoryMarshal.GetReference(buffer))
fixed (byte* ipAddress = &MemoryMarshal.GetReference(address))
{
err = Interop.Sys.GetIPv6Address(rawAddress, buffer.Length, ipAddress, address.Length, &localScope);
diff --git a/src/Common/src/System/Net/SocketAddressPal.Windows.cs b/src/Common/src/System/Net/SocketAddressPal.Windows.cs
index 32685d4882..404a381ae8 100644
--- a/src/Common/src/System/Net/SocketAddressPal.Windows.cs
+++ b/src/Common/src/System/Net/SocketAddressPal.Windows.cs
@@ -38,7 +38,7 @@ namespace System.Net
port.HostToNetworkBytes(buffer, 2);
}
- public static unsafe uint GetIPv4Address(byte[] buffer)
+ public static unsafe uint GetIPv4Address(ReadOnlySpan<byte> buffer)
{
unchecked
{
@@ -49,7 +49,7 @@ namespace System.Net
}
}
- public static unsafe void GetIPv6Address(byte[] buffer, Span<byte> address, out uint scope)
+ public static unsafe void GetIPv6Address(ReadOnlySpan<byte> buffer, Span<byte> address, out uint scope)
{
for (int i = 0; i < address.Length; i++)
{
diff --git a/src/Common/src/System/Net/WebSockets/ManagedWebSocket.cs b/src/Common/src/System/Net/WebSockets/ManagedWebSocket.cs
index b0938c5a6a..69cbd29dac 100644
--- a/src/Common/src/System/Net/WebSockets/ManagedWebSocket.cs
+++ b/src/Common/src/System/Net/WebSockets/ManagedWebSocket.cs
@@ -63,8 +63,6 @@ namespace System.Net.WebSockets
private const int MaxControlPayloadLength = 125;
/// <summary>Length of the mask XOR'd with the payload data.</summary>
private const int MaskLength = 4;
- /// <summary>Default length of a receive buffer to create when an invalid scratch buffer is provided.</summary>
- private const int DefaultReceiveBufferSize = 0x1000;
/// <summary>The stream used to communicate with the remote server.</summary>
private readonly Stream _stream;
@@ -88,10 +86,7 @@ namespace System.Net.WebSockets
/// </summary>
private readonly Utf8MessageState _utf8TextState = new Utf8MessageState();
/// <summary>
- /// Semaphore used to ensure that calls to SendFrameAsync don't run concurrently. While <see cref="_lastSendAsync"/>
- /// is used to fail if a caller tries to issue another SendAsync while a previous one is running, internally
- /// we use SendFrameAsync as an implementation detail, and it should not cause user requests to SendAsync to fail,
- /// nor should such internal usage be allowed to run concurrently with other internal usage or with SendAsync.
+ /// Semaphore used to ensure that calls to SendFrameAsync don't run concurrently.
/// </summary>
private readonly SemaphoreSlim _sendFrameAsyncLock = new SemaphoreSlim(1, 1);
@@ -145,15 +140,10 @@ namespace System.Net.WebSockets
/// </summary>
private bool _lastSendWasFragment;
/// <summary>
- /// The task returned from the last SendAsync operation to not complete synchronously.
- /// If this is not null and not completed when a subsequent SendAsync is issued, an exception occurs.
- /// </summary>
- private Task _lastSendAsync;
- /// <summary>
- /// The task returned from the last ReceiveAsync operation to not complete synchronously.
+ /// The task returned from the last ReceiveAsync(ArraySegment, ...) operation to not complete synchronously.
/// If this is not null and not completed when a subsequent ReceiveAsync is issued, an exception occurs.
/// </summary>
- private Task _lastReceiveAsync;
+ private Task _lastReceiveAsync = Task.CompletedTask;
/// <summary>Lock used to protect update and check-and-update operations on _state.</summary>
private object StateUpdateLock => _abortSource;
@@ -192,8 +182,11 @@ namespace System.Net.WebSockets
// socket rents a similarly sized buffer from the pool for its duration, we'll end up draining
// the pool, such that other web sockets will allocate anyway, as will anyone else in the process using the
// pool. If someone wants to pool, they can do so by passing in the buffer they want to use, and they can
- // get it from whatever pool they like.
- _receiveBuffer = buffer.Length >= MaxMessageHeaderLength ? buffer : new byte[DefaultReceiveBufferSize];
+ // get it from whatever pool they like. If we create our own buffer, it's small, large enough for message
+ // headers and control payloads, but data for other message payloads is read directly into the buffers
+ // passed into ReceiveAsync.
+ const int ReceiveBufferMinLength = MaxControlPayloadLength;
+ _receiveBuffer = buffer.Length >= ReceiveBufferMinLength ? buffer : new byte[ReceiveBufferMinLength];
// Set up the abort source so that if it's triggered, we transition the instance appropriately.
_abortSource.Token.Register(s =>
@@ -262,10 +255,10 @@ namespace System.Net.WebSockets
WebSocketValidate.ValidateArraySegment(buffer, nameof(buffer));
- return SendPrivateAsync((ReadOnlyMemory<byte>)buffer, messageType, endOfMessage, cancellationToken);
+ return SendPrivateAsync((ReadOnlyMemory<byte>)buffer, messageType, endOfMessage, cancellationToken).AsTask();
}
- private Task SendPrivateAsync(ReadOnlyMemory<byte> buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken)
+ private ValueTask SendPrivateAsync(ReadOnlyMemory<byte> buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken)
{
if (messageType != WebSocketMessageType.Text && messageType != WebSocketMessageType.Binary)
{
@@ -278,11 +271,10 @@ namespace System.Net.WebSockets
try
{
WebSocketValidate.ThrowIfInvalidState(_state, _disposed, s_validSendStates);
- ThrowIfOperationInProgress(_lastSendAsync);
}
catch (Exception exc)
{
- return Task.FromException(exc);
+ return new ValueTask(Task.FromException(exc));
}
MessageOpcode opcode =
@@ -290,9 +282,8 @@ namespace System.Net.WebSockets
messageType == WebSocketMessageType.Binary ? MessageOpcode.Binary :
MessageOpcode.Text;
- Task t = SendFrameAsync(opcode, endOfMessage, buffer, cancellationToken);
+ ValueTask t = SendFrameAsync(opcode, endOfMessage, buffer, cancellationToken);
_lastSendWasFragment = !endOfMessage;
- _lastSendAsync = t;
return t;
}
@@ -307,7 +298,7 @@ namespace System.Net.WebSockets
Debug.Assert(!Monitor.IsEntered(StateUpdateLock), $"{nameof(StateUpdateLock)} must never be held when acquiring {nameof(ReceiveAsyncLock)}");
lock (ReceiveAsyncLock) // synchronize with receives in CloseAsync
{
- ThrowIfOperationInProgress(_lastReceiveAsync);
+ ThrowIfOperationInProgress(_lastReceiveAsync.IsCompleted);
Task<WebSocketReceiveResult> t = ReceiveAsyncPrivate<WebSocketReceiveResultGetter,WebSocketReceiveResult>(buffer, cancellationToken).AsTask();
_lastReceiveAsync = t;
return t;
@@ -362,23 +353,14 @@ namespace System.Net.WebSockets
/// <param name="endOfMessage">The value of the FIN bit for the message.</param>
/// <param name="payloadBuffer">The buffer containing the payload data fro the message.</param>
/// <param name="cancellationToken">The CancellationToken to use to cancel the websocket.</param>
- private Task SendFrameAsync(MessageOpcode opcode, bool endOfMessage, ReadOnlyMemory<byte> payloadBuffer, CancellationToken cancellationToken)
+ private ValueTask SendFrameAsync(MessageOpcode opcode, bool endOfMessage, ReadOnlyMemory<byte> payloadBuffer, CancellationToken cancellationToken)
{
- // TODO: #4900 SendFrameAsync should in theory typically complete synchronously, making it fast and allocation free.
- // However, due to #4900, it almost always yields, resulting in all of the allocations involved in an async method
- // yielding, e.g. the boxed state machine, the Action delegate, the MoveNextRunner, and the resulting Task, plus it's
- // common that the awaited operation completes so fast after the await that we may end up allocating an AwaitTaskContinuation
- // inside of the TaskAwaiter. Since SendFrameAsync is such a core code path, until that can be fixed, we put some
- // optimizations in place to avoid a few of those expenses, at the expense of more complicated code; for the common case,
- // this code has fewer than half the number and size of allocations. If/when that issue is fixed, this method should be deleted
- // and replaced by SendFrameFallbackAsync, which is the same logic but in a much more easily understand flow.
-
// If a cancelable cancellation token was provided, that would require registering with it, which means more state we have to
// pass around (the CancellationTokenRegistration), so if it is cancelable, just immediately go to the fallback path.
// Similarly, it should be rare that there are multiple outstanding calls to SendFrameAsync, but if there are, again
// fall back to the fallback path.
return cancellationToken.CanBeCanceled || !_sendFrameAsyncLock.Wait(0) ?
- SendFrameFallbackAsync(opcode, endOfMessage, payloadBuffer, cancellationToken) :
+ new ValueTask(SendFrameFallbackAsync(opcode, endOfMessage, payloadBuffer, cancellationToken)) :
SendFrameLockAcquiredNonCancelableAsync(opcode, endOfMessage, payloadBuffer);
}
@@ -386,19 +368,19 @@ namespace System.Net.WebSockets
/// <param name="opcode">The opcode for the message.</param>
/// <param name="endOfMessage">The value of the FIN bit for the message.</param>
/// <param name="payloadBuffer">The buffer containing the payload data fro the message.</param>
- private Task SendFrameLockAcquiredNonCancelableAsync(MessageOpcode opcode, bool endOfMessage, ReadOnlyMemory<byte> payloadBuffer)
+ private ValueTask SendFrameLockAcquiredNonCancelableAsync(MessageOpcode opcode, bool endOfMessage, ReadOnlyMemory<byte> payloadBuffer)
{
Debug.Assert(_sendFrameAsyncLock.CurrentCount == 0, "Caller should hold the _sendFrameAsyncLock");
// If we get here, the cancellation token is not cancelable so we don't have to worry about it,
// and we own the semaphore, so we don't need to asynchronously wait for it.
- Task writeTask = null;
+ ValueTask writeTask = default;
bool releaseSemaphoreAndSendBuffer = true;
try
{
// Write the payload synchronously to the buffer, then write that buffer out to the network.
int sendBytes = WriteFrameToSendBuffer(opcode, endOfMessage, payloadBuffer.Span);
- writeTask = _stream.WriteAsync(_sendBuffer, 0, sendBytes, CancellationToken.None);
+ writeTask = _stream.WriteAsync(new ReadOnlyMemory<byte>(_sendBuffer, 0, sendBytes));
// If the operation happens to complete synchronously (or, more specifically, by
// the time we get from the previous line to here), release the semaphore, return
@@ -415,9 +397,10 @@ namespace System.Net.WebSockets
}
catch (Exception exc)
{
- return Task.FromException(_state == WebSocketState.Aborted ?
- CreateOperationCanceledException(exc) :
- new WebSocketException(WebSocketError.ConnectionClosedPrematurely, exc));
+ return new ValueTask(Task.FromException(
+ exc is OperationCanceledException ? exc :
+ _state == WebSocketState.Aborted ? CreateOperationCanceledException(exc) :
+ new WebSocketException(WebSocketError.ConnectionClosedPrematurely, exc)));
}
finally
{
@@ -428,22 +411,26 @@ namespace System.Net.WebSockets
}
}
- // The write was not yet completed. Create and return a continuation that will
- // release the semaphore and translate any exception that occurred.
- return writeTask.ContinueWith((t, s) =>
- {
- var thisRef = (ManagedWebSocket)s;
- thisRef._sendFrameAsyncLock.Release();
- thisRef.ReleaseSendBuffer();
+ return new ValueTask(WaitForWriteTaskAsync(writeTask));
+ }
- try { t.GetAwaiter().GetResult(); }
- catch (Exception exc)
- {
- throw thisRef._state == WebSocketState.Aborted ?
- CreateOperationCanceledException(exc) :
- new WebSocketException(WebSocketError.ConnectionClosedPrematurely, exc);
- }
- }, this, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
+ private async Task WaitForWriteTaskAsync(ValueTask writeTask)
+ {
+ try
+ {
+ await writeTask.ConfigureAwait(false);
+ }
+ catch (Exception exc) when (!(exc is OperationCanceledException))
+ {
+ throw _state == WebSocketState.Aborted ?
+ CreateOperationCanceledException(exc) :
+ new WebSocketException(WebSocketError.ConnectionClosedPrematurely, exc);
+ }
+ finally
+ {
+ _sendFrameAsyncLock.Release();
+ ReleaseSendBuffer();
+ }
}
private async Task SendFrameFallbackAsync(MessageOpcode opcode, bool endOfMessage, ReadOnlyMemory<byte> payloadBuffer, CancellationToken cancellationToken)
@@ -454,10 +441,10 @@ namespace System.Net.WebSockets
int sendBytes = WriteFrameToSendBuffer(opcode, endOfMessage, payloadBuffer.Span);
using (cancellationToken.Register(s => ((ManagedWebSocket)s).Abort(), this))
{
- await _stream.WriteAsync(_sendBuffer, 0, sendBytes, cancellationToken).ConfigureAwait(false);
+ await _stream.WriteAsync(new ReadOnlyMemory<byte>(_sendBuffer, 0, sendBytes), default).ConfigureAwait(false);
}
}
- catch (Exception exc)
+ catch (Exception exc) when (!(exc is OperationCanceledException))
{
throw _state == WebSocketState.Aborted ?
CreateOperationCanceledException(exc, cancellationToken) :
@@ -517,12 +504,15 @@ namespace System.Net.WebSockets
{
// This exists purely to keep the connection alive; don't wait for the result, and ignore any failures.
// The call will handle releasing the lock.
- Task t = SendFrameLockAcquiredNonCancelableAsync(MessageOpcode.Ping, true, Memory<byte>.Empty);
-
- // "Observe" any exception, ignoring it to prevent the unobserved exception event from being raised.
- if (t.Status != TaskStatus.RanToCompletion)
+ ValueTask t = SendFrameLockAcquiredNonCancelableAsync(MessageOpcode.Ping, true, Memory<byte>.Empty);
+ if (t.IsCompletedSuccessfully)
{
- t.ContinueWith(p => { Exception ignored = p.Exception; },
+ t.GetAwaiter().GetResult();
+ }
+ else
+ {
+ // "Observe" any exception, ignoring it to prevent the unobserved exception event from being raised.
+ t.AsTask().ContinueWith(p => { Exception ignored = p.Exception; },
CancellationToken.None,
TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default);
@@ -650,7 +640,7 @@ namespace System.Net.WebSockets
// Make sure we have the first two bytes, which includes the start of the payload length.
if (_receiveBufferCount < 2)
{
- await EnsureBufferContainsAsync(2, cancellationToken, throwOnPrematureClosure: true).ConfigureAwait(false);
+ await EnsureBufferContainsAsync(2, throwOnPrematureClosure: true).ConfigureAwait(false);
}
// Then make sure we have the full header based on the payload length.
@@ -662,13 +652,13 @@ namespace System.Net.WebSockets
2 +
(_isServer ? MaskLength : 0) +
(payloadLength <= 125 ? 0 : payloadLength == 126 ? sizeof(ushort) : sizeof(ulong)); // additional 2 or 8 bytes for 16-bit or 64-bit length
- await EnsureBufferContainsAsync(minNeeded, cancellationToken).ConfigureAwait(false);
+ await EnsureBufferContainsAsync(minNeeded).ConfigureAwait(false);
}
}
if (!TryParseMessageHeaderFromReceiveBuffer(out header))
{
- await CloseWithReceiveErrorAndThrowAsync(WebSocketCloseStatus.ProtocolError, WebSocketError.Faulted, cancellationToken).ConfigureAwait(false);
+ await CloseWithReceiveErrorAndThrowAsync(WebSocketCloseStatus.ProtocolError, WebSocketError.Faulted).ConfigureAwait(false);
}
_receivedMaskOffsetOffset = 0;
}
@@ -678,12 +668,12 @@ namespace System.Net.WebSockets
// Alternatively, if it's a close message, handle it and exit.
if (header.Opcode == MessageOpcode.Ping || header.Opcode == MessageOpcode.Pong)
{
- await HandleReceivedPingPongAsync(header, cancellationToken).ConfigureAwait(false);
+ await HandleReceivedPingPongAsync(header).ConfigureAwait(false);
continue;
}
else if (header.Opcode == MessageOpcode.Close)
{
- await HandleReceivedCloseAsync(header, cancellationToken).ConfigureAwait(false);
+ await HandleReceivedCloseAsync(header).ConfigureAwait(false);
return resultGetter.GetResult(0, WebSocketMessageType.Close, true, _closeStatus, _closeStatusDescription);
}
@@ -708,43 +698,68 @@ namespace System.Net.WebSockets
}
// Otherwise, read as much of the payload as we can efficiently, and upate the header to reflect how much data
- // remains for future reads.
- int bytesToCopy = Math.Min(payloadBuffer.Length, (int)Math.Min(header.PayloadLength, _receiveBuffer.Length));
- Debug.Assert(bytesToCopy > 0, $"Expected {nameof(bytesToCopy)} > 0");
- if (_receiveBufferCount < bytesToCopy)
+ // remains for future reads. We first need to copy any data that may be lingering in the receive buffer
+ // into the destination; then to minimize ReceiveAsync calls, we want to read as much as we can, stopping
+ // only when we've either read the whole message or when we've filled the payload buffer.
+
+ // First copy any data lingering in the receive buffer.
+ int totalBytesReceived = 0;
+ if (_receiveBufferCount > 0)
+ {
+ int receiveBufferBytesToCopy = Math.Min(payloadBuffer.Length, (int)Math.Min(header.PayloadLength, _receiveBufferCount));
+ Debug.Assert(receiveBufferBytesToCopy > 0);
+ _receiveBuffer.Span.Slice(_receiveBufferOffset, receiveBufferBytesToCopy).CopyTo(payloadBuffer.Span);
+ ConsumeFromBuffer(receiveBufferBytesToCopy);
+ totalBytesReceived += receiveBufferBytesToCopy;
+ Debug.Assert(
+ _receiveBufferCount == 0 ||
+ totalBytesReceived == payloadBuffer.Length ||
+ totalBytesReceived == header.PayloadLength);
+ }
+
+ // Then read directly into the payload buffer until we've hit a limit.
+ while (totalBytesReceived < payloadBuffer.Length &&
+ totalBytesReceived < header.PayloadLength)
{
- await EnsureBufferContainsAsync(bytesToCopy, cancellationToken, throwOnPrematureClosure: true).ConfigureAwait(false);
+ int numBytesRead = await _stream.ReadAsync(payloadBuffer.Slice(
+ totalBytesReceived,
+ (int)Math.Min(payloadBuffer.Length, header.PayloadLength) - totalBytesReceived)).ConfigureAwait(false);
+ if (numBytesRead <= 0)
+ {
+ ThrowIfEOFUnexpected(throwOnPrematureClosure: true);
+ break;
+ }
+ totalBytesReceived += numBytesRead;
}
if (_isServer)
{
- _receivedMaskOffsetOffset = ApplyMask(_receiveBuffer.Span.Slice(_receiveBufferOffset, bytesToCopy), header.Mask, _receivedMaskOffsetOffset);
+ _receivedMaskOffsetOffset = ApplyMask(payloadBuffer.Span.Slice(0, totalBytesReceived), header.Mask, _receivedMaskOffsetOffset);
}
- _receiveBuffer.Span.Slice(_receiveBufferOffset, bytesToCopy).CopyTo(payloadBuffer.Span.Slice(0, bytesToCopy));
- ConsumeFromBuffer(bytesToCopy);
- header.PayloadLength -= bytesToCopy;
+ header.PayloadLength -= totalBytesReceived;
// If this a text message, validate that it contains valid UTF8.
if (header.Opcode == MessageOpcode.Text &&
- !TryValidateUtf8(payloadBuffer.Span.Slice(0, bytesToCopy), header.Fin, _utf8TextState))
+ !TryValidateUtf8(payloadBuffer.Span.Slice(0, totalBytesReceived), header.Fin, _utf8TextState))
{
- await CloseWithReceiveErrorAndThrowAsync(WebSocketCloseStatus.InvalidPayloadData, WebSocketError.Faulted, cancellationToken).ConfigureAwait(false);
+ await CloseWithReceiveErrorAndThrowAsync(WebSocketCloseStatus.InvalidPayloadData, WebSocketError.Faulted).ConfigureAwait(false);
}
_lastReceiveHeader = header;
return resultGetter.GetResult(
- bytesToCopy,
+ totalBytesReceived,
header.Opcode == MessageOpcode.Text ? WebSocketMessageType.Text : WebSocketMessageType.Binary,
header.Fin && header.PayloadLength == 0,
null, null);
}
}
- catch (Exception exc)
+ catch (Exception exc) when (!(exc is OperationCanceledException))
{
if (_state == WebSocketState.Aborted)
{
throw new OperationCanceledException(nameof(WebSocketState.Aborted), exc);
}
+ _abortSource.Cancel();
throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely, exc);
}
finally
@@ -755,10 +770,8 @@ namespace System.Net.WebSockets
/// <summary>Processes a received close message.</summary>
/// <param name="header">The message header.</param>
- /// <param name="cancellationToken">The cancellation token to use to cancel the websocket.</param>
/// <returns>The received result message.</returns>
- private async Task HandleReceivedCloseAsync(
- MessageHeader header, CancellationToken cancellationToken)
+ private async Task HandleReceivedCloseAsync(MessageHeader header)
{
lock (StateUpdateLock)
{
@@ -776,13 +789,13 @@ namespace System.Net.WebSockets
if (header.PayloadLength == 1)
{
// The close payload length can be 0 or >= 2, but not 1.
- await CloseWithReceiveErrorAndThrowAsync(WebSocketCloseStatus.ProtocolError, WebSocketError.Faulted, cancellationToken).ConfigureAwait(false);
+ await CloseWithReceiveErrorAndThrowAsync(WebSocketCloseStatus.ProtocolError, WebSocketError.Faulted).ConfigureAwait(false);
}
else if (header.PayloadLength >= 2)
{
if (_receiveBufferCount < header.PayloadLength)
{
- await EnsureBufferContainsAsync((int)header.PayloadLength, cancellationToken).ConfigureAwait(false);
+ await EnsureBufferContainsAsync((int)header.PayloadLength).ConfigureAwait(false);
}
if (_isServer)
@@ -793,7 +806,7 @@ namespace System.Net.WebSockets
closeStatus = (WebSocketCloseStatus)(_receiveBuffer.Span[_receiveBufferOffset] << 8 | _receiveBuffer.Span[_receiveBufferOffset + 1]);
if (!IsValidCloseStatus(closeStatus))
{
- await CloseWithReceiveErrorAndThrowAsync(WebSocketCloseStatus.ProtocolError, WebSocketError.Faulted, cancellationToken).ConfigureAwait(false);
+ await CloseWithReceiveErrorAndThrowAsync(WebSocketCloseStatus.ProtocolError, WebSocketError.Faulted).ConfigureAwait(false);
}
if (header.PayloadLength > 2)
@@ -804,7 +817,7 @@ namespace System.Net.WebSockets
}
catch (DecoderFallbackException exc)
{
- await CloseWithReceiveErrorAndThrowAsync(WebSocketCloseStatus.ProtocolError, WebSocketError.Faulted, cancellationToken, exc).ConfigureAwait(false);
+ await CloseWithReceiveErrorAndThrowAsync(WebSocketCloseStatus.ProtocolError, WebSocketError.Faulted, exc).ConfigureAwait(false);
}
}
ConsumeFromBuffer((int)header.PayloadLength);
@@ -813,17 +826,48 @@ namespace System.Net.WebSockets
// Store the close status and description onto the instance.
_closeStatus = closeStatus;
_closeStatusDescription = closeStatusDescription;
+
+ if (!_isServer && _sentCloseFrame)
+ {
+ await WaitForServerToCloseConnectionAsync().ConfigureAwait(false);
+ }
+ }
+
+ /// <summary>Issues a read on the stream to wait for EOF.</summary>
+ private async Task WaitForServerToCloseConnectionAsync()
+ {
+ // Per RFC 6455 7.1.1, try to let the server close the connection. We give it up to a second.
+ // We simply issue a read and don't care what we get back; we could validate that we don't get
+ // additional data, but at this point we're about to close the connection and we're just stalling
+ // to try to get the server to close first.
+ ValueTask<int> finalReadTask = _stream.ReadAsync(_receiveBuffer, default);
+ if (!finalReadTask.IsCompletedSuccessfully)
+ {
+ const int WaitForCloseTimeoutMs = 1_000; // arbitrary amount of time to give the server (same as netfx)
+ using (var finalCts = new CancellationTokenSource(WaitForCloseTimeoutMs))
+ using (finalCts.Token.Register(s => ((ManagedWebSocket)s).Abort(), this))
+ {
+ try
+ {
+ await finalReadTask.ConfigureAwait(false);
+ }
+ catch
+ {
+ // Eat any resulting exceptions. We were going to close the connection, anyway.
+ // TODO #24057: Log the exception to NetEventSource.
+ }
+ }
+ }
}
/// <summary>Processes a received ping or pong message.</summary>
/// <param name="header">The message header.</param>
- /// <param name="cancellationToken">The cancellation token to use to cancel the websocket.</param>
- private async Task HandleReceivedPingPongAsync(MessageHeader header, CancellationToken cancellationToken)
+ private async Task HandleReceivedPingPongAsync(MessageHeader header)
{
// Consume any (optional) payload associated with the ping/pong.
if (header.PayloadLength > 0 && _receiveBufferCount < header.PayloadLength)
{
- await EnsureBufferContainsAsync((int)header.PayloadLength, cancellationToken).ConfigureAwait(false);
+ await EnsureBufferContainsAsync((int)header.PayloadLength).ConfigureAwait(false);
}
// If this was a ping, send back a pong response.
@@ -836,7 +880,7 @@ namespace System.Net.WebSockets
await SendFrameAsync(
MessageOpcode.Pong, true,
- _receiveBuffer.Slice(_receiveBufferOffset, (int)header.PayloadLength), cancellationToken).ConfigureAwait(false);
+ _receiveBuffer.Slice(_receiveBufferOffset, (int)header.PayloadLength), default).ConfigureAwait(false);
}
// Regardless of whether it was a ping or pong, we no longer need the payload.
@@ -888,15 +932,14 @@ namespace System.Net.WebSockets
/// <summary>Send a close message to the server and throw an exception, in response to getting bad data from the server.</summary>
/// <param name="closeStatus">The close status code to use.</param>
/// <param name="error">The error reason.</param>
- /// <param name="cancellationToken">The CancellationToken used to cancel the websocket.</param>
/// <param name="innerException">An optional inner exception to include in the thrown exception.</param>
private async Task CloseWithReceiveErrorAndThrowAsync(
- WebSocketCloseStatus closeStatus, WebSocketError error, CancellationToken cancellationToken, Exception innerException = null)
+ WebSocketCloseStatus closeStatus, WebSocketError error, Exception innerException = null)
{
// Close the connection if it hasn't already been closed
if (!_sentCloseFrame)
{
- await CloseOutputAsync(closeStatus, string.Empty, cancellationToken).ConfigureAwait(false);
+ await CloseOutputAsync(closeStatus, string.Empty, default).ConfigureAwait(false);
}
// Dump our receive buffer; we're in a bad state to do any further processing
@@ -1113,6 +1156,11 @@ namespace System.Net.WebSockets
_state = WebSocketState.CloseSent;
}
}
+
+ if (!_isServer && _receivedCloseFrame)
+ {
+ await WaitForServerToCloseConnectionAsync().ConfigureAwait(false);
+ }
}
private void ConsumeFromBuffer(int count)
@@ -1123,7 +1171,7 @@ namespace System.Net.WebSockets
_receiveBufferOffset += count;
}
- private async Task EnsureBufferContainsAsync(int minimumRequiredBytes, CancellationToken cancellationToken, bool throwOnPrematureClosure = true)
+ private async Task EnsureBufferContainsAsync(int minimumRequiredBytes, bool throwOnPrematureClosure = true)
{
Debug.Assert(minimumRequiredBytes <= _receiveBuffer.Length, $"Requested number of bytes {minimumRequiredBytes} must not exceed {_receiveBuffer.Length}");
@@ -1140,29 +1188,34 @@ namespace System.Net.WebSockets
// While we don't have enough data, read more.
while (_receiveBufferCount < minimumRequiredBytes)
{
- int numRead = await _stream.ReadAsync(_receiveBuffer.Slice(_receiveBufferCount, _receiveBuffer.Length - _receiveBufferCount), cancellationToken).ConfigureAwait(false);
+ int numRead = await _stream.ReadAsync(_receiveBuffer.Slice(_receiveBufferCount, _receiveBuffer.Length - _receiveBufferCount), default).ConfigureAwait(false);
Debug.Assert(numRead >= 0, $"Expected non-negative bytes read, got {numRead}");
- _receiveBufferCount += numRead;
- if (numRead == 0)
+ if (numRead <= 0)
{
- // The connection closed before we were able to read everything we needed.
- // If it was due to use being disposed, fail. If it was due to the connection
- // being closed and it wasn't expected, fail. If it was due to the connection
- // being closed and that was expected, exit gracefully.
- if (_disposed)
- {
- throw new ObjectDisposedException(nameof(WebSocket));
- }
- else if (throwOnPrematureClosure)
- {
- throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely);
- }
+ ThrowIfEOFUnexpected(throwOnPrematureClosure);
break;
}
+ _receiveBufferCount += numRead;
}
}
}
+ private void ThrowIfEOFUnexpected(bool throwOnPrematureClosure)
+ {
+ // The connection closed before we were able to read everything we needed.
+ // If it was due to us being disposed, fail. If it was due to the connection
+ // being closed and it wasn't expected, fail. If it was due to the connection
+ // being closed and that was expected, exit gracefully.
+ if (_disposed)
+ {
+ throw new ObjectDisposedException(nameof(WebSocket));
+ }
+ if (throwOnPrematureClosure)
+ {
+ throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely);
+ }
+ }
+
/// <summary>Gets a send buffer from the pool.</summary>
private void AllocateSendBuffer(int minLength)
{
@@ -1216,7 +1269,7 @@ namespace System.Net.WebSockets
toMask.Length >= Vector<byte>.Count)
{
Vector<byte> maskVector = Vector.AsVectorByte(new Vector<int>(shiftedMask));
- Span<Vector<byte>> toMaskVector = toMask.NonPortableCast<byte, Vector<byte>>();
+ Span<Vector<byte>> toMaskVector = MemoryMarshal.Cast<byte, Vector<byte>>(toMask);
for (int i = 0; i < toMaskVector.Length; i++)
{
toMaskVector[i] ^= maskVector;
@@ -1269,15 +1322,17 @@ namespace System.Net.WebSockets
}
/// <summary>Aborts the websocket and throws an exception if an existing operation is in progress.</summary>
- private void ThrowIfOperationInProgress(Task operationTask, [CallerMemberName] string methodName = null)
+ private void ThrowIfOperationInProgress(bool operationCompleted, [CallerMemberName] string methodName = null)
{
- if (operationTask != null && !operationTask.IsCompleted)
+ if (!operationCompleted)
{
Abort();
- throw new InvalidOperationException(SR.Format(SR.net_Websockets_AlreadyOneOutstandingOperation, methodName));
+ ThrowOperationInProgress(methodName);
}
}
+ private void ThrowOperationInProgress(string methodName) => throw new InvalidOperationException(SR.Format(SR.net_Websockets_AlreadyOneOutstandingOperation, methodName));
+
/// <summary>Creates an OperationCanceledException instance, using a default message and the specified inner exception and token.</summary>
private static Exception CreateOperationCanceledException(Exception innerException, CancellationToken cancellationToken = default(CancellationToken))
{
diff --git a/src/Common/src/System/PasteArguments.Unix.cs b/src/Common/src/System/PasteArguments.Unix.cs
new file mode 100644
index 0000000000..1a4d92850f
--- /dev/null
+++ b/src/Common/src/System/PasteArguments.Unix.cs
@@ -0,0 +1,28 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using System.Text;
+
+namespace System
+{
+ internal static partial class PasteArguments
+ {
+ /// <summary>
+ /// Repastes a set of arguments into a linear string that parses back into the originals under pre- or post-2008 VC parsing rules.
+ /// On Unix: the rules for parsing the executable name (argv[0]) are ignored.
+ /// </summary>
+ internal static string Paste(IEnumerable<string> arguments, bool pasteFirstArgumentUsingArgV0Rules)
+ {
+ var stringBuilder = new StringBuilder();
+ foreach (string argument in arguments)
+ {
+ AppendArgument(stringBuilder, argument);
+ }
+ return stringBuilder.ToString();
+ }
+
+ }
+}
diff --git a/src/Common/src/System/PasteArguments.Windows.cs b/src/Common/src/System/PasteArguments.Windows.cs
new file mode 100644
index 0000000000..7cdcbc4533
--- /dev/null
+++ b/src/Common/src/System/PasteArguments.Windows.cs
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using System.Text;
+
+namespace System
+{
+ internal static partial class PasteArguments
+ {
+ /// <summary>
+ /// Repastes a set of arguments into a linear string that parses back into the originals under pre- or post-2008 VC parsing rules.
+ /// The rules for parsing the executable name (argv[0]) are special, so you must indicate whether the first argument actually is argv[0].
+ /// </summary>
+ internal static string Paste(IEnumerable<string> arguments, bool pasteFirstArgumentUsingArgV0Rules)
+ {
+ var stringBuilder = new StringBuilder();
+
+ foreach (string argument in arguments)
+ {
+ if (pasteFirstArgumentUsingArgV0Rules)
+ {
+ pasteFirstArgumentUsingArgV0Rules = false;
+
+ // Special rules for argv[0]
+ // - Backslash is a normal character.
+ // - Quotes used to include whitespace characters.
+ // - Parsing ends at first whitespace outside quoted region.
+ // - No way to get a literal quote past the parser.
+
+ bool hasWhitespace = false;
+ foreach (char c in argument)
+ {
+ if (c == Quote)
+ {
+ throw new ApplicationException("The argv[0] argument cannot include a double quote.");
+ }
+ if (char.IsWhiteSpace(c))
+ {
+ hasWhitespace = true;
+ }
+ }
+ if (argument.Length == 0 || hasWhitespace)
+ {
+ stringBuilder.Append(Quote);
+ stringBuilder.Append(argument);
+ stringBuilder.Append(Quote);
+ }
+ else
+ {
+ stringBuilder.Append(argument);
+ }
+ }
+ else
+ {
+ AppendArgument(stringBuilder, argument);
+ }
+ }
+
+ return stringBuilder.ToString();
+ }
+
+ }
+}
diff --git a/src/Common/src/System/PasteArguments.cs b/src/Common/src/System/PasteArguments.cs
index f78a95ad49..c088fd4eb7 100644
--- a/src/Common/src/System/PasteArguments.cs
+++ b/src/Common/src/System/PasteArguments.cs
@@ -2,124 +2,81 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Collections.Generic;
using System.Text;
namespace System
{
- internal static class PasteArguments
+ internal static partial class PasteArguments
{
- /// <summary>
- /// Repastes a set of arguments into a linear string that parses back into the originals under pre- or post-2008 VC parsing rules.
- /// The rules for parsing the executable name (argv[0]) are special, so you must indicate whether the first argument actually is argv[0].
- /// </summary>
- public static string Paste(IEnumerable<string> arguments, bool pasteFirstArgumentUsingArgV0Rules)
+ internal static void AppendArgument(StringBuilder stringBuilder, string argument)
{
- var stringBuilder = new StringBuilder();
+ if (stringBuilder.Length != 0)
+ {
+ stringBuilder.Append(' ');
+ }
- foreach (string argument in arguments)
+ // Parsing rules for non-argv[0] arguments:
+ // - Backslash is a normal character except followed by a quote.
+ // - 2N backslashes followed by a quote ==> N literal backslashes followed by unescaped quote
+ // - 2N+1 backslashes followed by a quote ==> N literal backslashes followed by a literal quote
+ // - Parsing stops at first whitespace outside of quoted region.
+ // - (post 2008 rule): A closing quote followed by another quote ==> literal quote, and parsing remains in quoting mode.
+ if (argument.Length != 0 && ContainsNoWhitespaceOrQuotes(argument))
+ {
+ // Simple case - no quoting or changes needed.
+ stringBuilder.Append(argument);
+ }
+ else
{
- if (pasteFirstArgumentUsingArgV0Rules)
+ stringBuilder.Append(Quote);
+ int idx = 0;
+ while (idx < argument.Length)
{
- pasteFirstArgumentUsingArgV0Rules = false;
-
- // Special rules for argv[0]
- // - Backslash is a normal character.
- // - Quotes used to include whitespace characters.
- // - Parsing ends at first whitespace outside quoted region.
- // - No way to get a literal quote past the parser.
-
- bool hasWhitespace = false;
- foreach (char c in argument)
+ char c = argument[idx++];
+ if (c == Backslash)
{
- if (c == Quote)
+ int numBackSlash = 1;
+ while (idx < argument.Length && argument[idx] == Backslash)
{
- throw new ApplicationException("The argv[0] argument cannot include a double quote.");
+ idx++;
+ numBackSlash++;
}
- if (char.IsWhiteSpace(c))
+
+ if (idx == argument.Length)
{
- hasWhitespace = true;
+ // We'll emit an end quote after this so must double the number of backslashes.
+ stringBuilder.Append(Backslash, numBackSlash * 2);
+ }
+ else if (argument[idx] == Quote)
+ {
+ // Backslashes will be followed by a quote. Must double the number of backslashes.
+ stringBuilder.Append(Backslash, numBackSlash * 2 + 1);
+ stringBuilder.Append(Quote);
+ idx++;
+ }
+ else
+ {
+ // Backslash will not be followed by a quote, so emit as normal characters.
+ stringBuilder.Append(Backslash, numBackSlash);
}
- }
- if (argument.Length == 0 || hasWhitespace)
- {
- stringBuilder.Append(Quote);
- stringBuilder.Append(argument);
- stringBuilder.Append(Quote);
- }
- else
- {
- stringBuilder.Append(argument);
- }
- }
- else
- {
- if (stringBuilder.Length != 0)
- {
- stringBuilder.Append(' ');
- }
- // Parsing rules for non-argv[0] arguments:
- // - Backslash is a normal character except followed by a quote.
- // - 2N backslashes followed by a quote ==> N literal backslashes followed by unescaped quote
- // - 2N+1 backslashes followed by a quote ==> N literal backslashes followed by a literal quote
- // - Parsing stops at first whitespace outside of quoted region.
- // - (post 2008 rule): A closing quote followed by another quote ==> literal quote, and parsing remains in quoting mode.
- if (argument.Length != 0 && ContainsNoWhitespaceOrQuotes(argument))
- {
- // Simple case - no quoting or changes needed.
- stringBuilder.Append(argument);
+ continue;
}
- else
+
+ if (c == Quote)
{
+ // Escape the quote so it appears as a literal. This also guarantees that we won't end up generating a closing quote followed
+ // by another quote (which parses differently pre-2008 vs. post-2008.)
+ stringBuilder.Append(Backslash);
stringBuilder.Append(Quote);
- int idx = 0;
- while (idx < argument.Length)
- {
- char c = argument[idx++];
- if (c == Backslash)
- {
- int numBackSlash = 1;
- while (idx < argument.Length && argument[idx] == Backslash)
- {
- idx++;
- numBackSlash++;
- }
- if (idx == argument.Length)
- {
- // We'll emit an end quote after this so must double the number of backslashes.
- stringBuilder.Append(Backslash, numBackSlash * 2);
- }
- else if (argument[idx] == Quote)
- {
- // Backslashes will be followed by a quote. Must double the number of backslashes.
- stringBuilder.Append(Backslash, numBackSlash * 2 + 1);
- stringBuilder.Append(Quote);
- idx++;
- }
- else
- {
- // Backslash will not be followed by a quote, so emit as normal characters.
- stringBuilder.Append(Backslash, numBackSlash);
- }
- continue;
- }
- if (c == Quote)
- {
- // Escape the quote so it appears as a literal. This also guarantees that we won't end up generating a closing quote followed
- // by another quote (which parses differently pre-2008 vs. post-2008.)
- stringBuilder.Append(Backslash);
- stringBuilder.Append(Quote);
- continue;
- }
- stringBuilder.Append(c);
- }
- stringBuilder.Append(Quote);
+ continue;
}
+
+ stringBuilder.Append(c);
}
- }
- return stringBuilder.ToString();
+ stringBuilder.Append(Quote);
+ }
}
private static bool ContainsNoWhitespaceOrQuotes(string s)
diff --git a/src/Common/src/System/Runtime/InteropServices/FunctionWrapper.cs b/src/Common/src/System/Runtime/InteropServices/FunctionWrapper.cs
index 692e6f64b9..9b56ef3de0 100644
--- a/src/Common/src/System/Runtime/InteropServices/FunctionWrapper.cs
+++ b/src/Common/src/System/Runtime/InteropServices/FunctionWrapper.cs
@@ -45,9 +45,9 @@ namespace System.Runtime.InteropServices
}
}
- public enum FunctionLoadResultKind { Success, LibraryNotFound, FunctionNotFound }
+ internal enum FunctionLoadResultKind { Success, LibraryNotFound, FunctionNotFound }
- public readonly struct FunctionLoadResult<T>
+ internal readonly struct FunctionLoadResult<T>
{
public FunctionLoadResultKind ResultKind { get; }
public T Delegate { get; }
diff --git a/src/Common/src/System/Security/Cryptography/Asn1V2.Serializer.cs b/src/Common/src/System/Security/Cryptography/Asn1V2.Serializer.cs
index 0eeb6fe912..c6b2ea69b5 100644
--- a/src/Common/src/System/Security/Cryptography/Asn1V2.Serializer.cs
+++ b/src/Common/src/System/Security/Cryptography/Asn1V2.Serializer.cs
@@ -3,11 +3,13 @@
// See the LICENSE file in the project root for more information.
using System.Buffers;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Numerics;
using System.Reflection;
+using System.Runtime.CompilerServices;
namespace System.Security.Cryptography.Asn1
{
@@ -59,6 +61,9 @@ namespace System.Security.Cryptography.Asn1
private delegate object Deserializer(AsnReader reader);
private delegate bool TryDeserializer<T>(AsnReader reader, out T value);
+ private static readonly ConcurrentDictionary<Type, FieldInfo[]> s_orderedFields =
+ new ConcurrentDictionary<Type, FieldInfo[]>();
+
private static Deserializer TryOrFail<T>(TryDeserializer<T> tryDeserializer)
{
return reader =>
@@ -70,6 +75,53 @@ namespace System.Security.Cryptography.Asn1
};
}
+ private static FieldInfo[] GetOrderedFields(Type typeT)
+ {
+ return s_orderedFields.GetOrAdd(
+ typeT,
+ t =>
+ {
+ // https://github.com/dotnet/corefx/issues/14606 asserts that ordering by the metadata
+ // token on a SequentialLayout will produce the fields in their layout order.
+ //
+ // Some other alternatives:
+ // * Add an attribute for controlling the field read order.
+ // fieldInfos.Select(fi => (fi, fi.GetCustomAttribute<AsnFieldOrderAttribute>(false)).
+ // Where(val => val.Item2 != null).OrderBy(val => val.Item2.OrderWeight).Select(val => val.Item1);
+ //
+ // * Use Marshal.OffsetOf as a sort key
+ //
+ // * Some sort of interface to return the fields in a declared order, using either
+ // an existing object, or Activator.CreateInstance. It would need to check that
+ // any returned fields actually were declared on the type that was queried.
+ //
+ // * Invent more alternatives
+ FieldInfo[] fieldInfos = t.GetFields(FieldFlags);
+
+ if (fieldInfos.Length == 0)
+ {
+ return Array.Empty<FieldInfo>();
+ }
+
+ try
+ {
+ int token = fieldInfos[0].MetadataToken;
+ }
+ catch (InvalidOperationException)
+ {
+ // If MetadataToken isn't available (like in ILC) then just hope that
+ // the fields are returned in declared order. For the most part that
+ // will result in data misaligning to fields and deserialization failing,
+ // thus a CryptographicException.
+ return fieldInfos;
+ }
+
+ Array.Sort(fieldInfos, (x, y) => x.MetadataToken.CompareTo(y.MetadataToken));
+ return fieldInfos;
+ });
+ }
+
+
private static ChoiceAttribute GetChoiceAttribute(Type typeT)
{
ChoiceAttribute attr = typeT.GetCustomAttribute<ChoiceAttribute>(inherit: false);
@@ -102,20 +154,7 @@ namespace System.Security.Cryptography.Asn1
Type typeT,
LinkedList<FieldInfo> currentSet)
{
- FieldInfo[] fieldInfos = typeT.GetFields(FieldFlags);
-
- // https://github.com/dotnet/corefx/issues/14606 asserts that ordering by the metadata
- // token on a SequentialLayout will produce the fields in their layout order.
- //
- // Some other alternatives:
- // * Add an attribute for controlling the field read order.
- // fieldInfos.Select(fi => (fi, fi.GetCustomAttribute<AsnFieldOrderAttribute>(false)).
- // Where(val => val.Item2 != null).OrderBy(val => val.Item2.OrderWeight).Select(val => val.Item1);
- //
- // * Use Marshal.OffsetOf as a sort key
- //
- // * Invent more alternatives
- foreach (FieldInfo fieldInfo in fieldInfos.OrderBy(fi => fi.MetadataToken))
+ foreach (FieldInfo fieldInfo in GetOrderedFields(typeT))
{
Type fieldType = fieldInfo.FieldType;
@@ -211,7 +250,7 @@ namespace System.Security.Cryptography.Asn1
}
else
{
- FieldInfo[] fieldInfos = typeT.GetFields(FieldFlags);
+ FieldInfo[] fieldInfos = GetOrderedFields(typeT);
for (int i = 0; i < fieldInfos.Length; i++)
{
@@ -312,11 +351,11 @@ namespace System.Security.Cryptography.Asn1
writer.PopSequence(tag);
}
- private static object DeserializeCustomType(AsnReader reader, Type typeT)
+ private static object DeserializeCustomType(AsnReader reader, Type typeT, Asn1Tag expectedTag)
{
object target = Activator.CreateInstance(typeT);
- AsnReader sequence = reader.ReadSequence();
+ AsnReader sequence = reader.ReadSequence(expectedTag);
foreach (FieldInfo fieldInfo in typeT.GetFields(FieldFlags))
{
@@ -596,7 +635,7 @@ namespace System.Security.Cryptography.Asn1
// TODO: split netstandard/netcoreapp for span usage?
ReadOnlyMemory<byte> valAsMemory = (ReadOnlyMemory<byte>)value;
byte[] tooBig = new byte[valAsMemory.Length + 1];
- valAsMemory.Span.CopyTo(tooBig.AsSpan().Slice(1));
+ valAsMemory.Span.CopyTo(tooBig.AsSpan(1));
Array.Reverse(tooBig);
BigInteger bigInt = new BigInteger(tooBig);
writer.WriteInteger(bigInt);
@@ -722,7 +761,7 @@ namespace System.Security.Cryptography.Asn1
{
expectedTag = fieldData.ExpectedTag;
}
-
+
deserializer = DefaultValueDeserializer(
deserializer,
fieldData.IsOptional,
@@ -837,12 +876,12 @@ namespace System.Security.Cryptography.Asn1
// Guaranteed too big, because it has the tag and length.
int length = reader.PeekEncodedValue().Length;
byte[] rented = ArrayPool<byte>.Shared.Rent(length);
-
+
try
{
if (reader.TryCopyBitStringBytes(rented, out _, out int bytesWritten))
{
- return new ReadOnlyMemory<byte>(rented.AsReadOnlySpan().Slice(0, bytesWritten).ToArray());
+ return new ReadOnlyMemory<byte>(rented.AsSpan(0, bytesWritten).ToArray());
}
Debug.Fail("TryCopyBitStringBytes produced more data than the encoded size");
@@ -873,7 +912,7 @@ namespace System.Security.Cryptography.Asn1
{
if (reader.TryCopyOctetStringBytes(rented, out int bytesWritten))
{
- return new ReadOnlyMemory<byte>(rented.AsReadOnlySpan().Slice(0, bytesWritten).ToArray());
+ return new ReadOnlyMemory<byte>(rented.AsSpan(0, bytesWritten).ToArray());
}
Debug.Fail("TryCopyOctetStringBytes produced more data than the encoded size");
@@ -984,14 +1023,14 @@ namespace System.Security.Cryptography.Asn1
{
if (fieldData.TagType == UniversalTagNumber.Sequence)
{
- return reader => DeserializeCustomType(reader, typeT);
+ return reader => DeserializeCustomType(reader, typeT, expectedTag);
}
}
throw new AsnSerializationConstraintException(
SR.Format(SR.Cryptography_AsnSerializer_UnhandledType, typeT.FullName));
}
-
+
private static object DefaultValue(
byte[] defaultContents,
Deserializer valueDeserializer)
@@ -1342,14 +1381,14 @@ namespace System.Security.Cryptography.Asn1
/// <remarks>
/// Except for where required to for avoiding ambiguity, this method does not check that there are
/// no cycles in the type graph for <typeparamref name="T"/>. If <typeparamref name="T"/> is a
- /// reference type (class) which includes a cycle in the type graph,
+ /// reference type (class) which includes a cycle in the type graph,
/// then it is possible for the data in <paramref name="source"/> to cause
/// an arbitrary extension to the maximum stack depth of this routine, leading to a
/// <see cref="StackOverflowException"/>.
- ///
+ ///
/// If <typeparamref name="T"/> is a value type (struct) the compiler will enforce that there are no
/// cycles in the type graph.
- ///
+ ///
/// When reference types are used the onus is on the caller of this method to prevent cycles, or to
/// mitigate the possibility of the stack overflow.
/// </remarks>
@@ -1373,6 +1412,50 @@ namespace System.Security.Cryptography.Asn1
}
/// <summary>
+ /// Read the first ASN.1 data element from <paramref name="source"/> encoded under the specified
+ /// encoding rules into the typed structure.
+ /// </summary>
+ /// <typeparam name="T">
+ /// The type to deserialize as.
+ /// In order to be deserialized the type must have sequential layout, be sealed, and be composed of
+ /// members that are also able to be deserialized by this method.
+ /// </typeparam>
+ /// <param name="source">A view of the encoded bytes to be deserialized.</param>
+ /// <param name="ruleSet">The ASN.1 encoding ruleset to use for reading <paramref name="source"/>.</param>
+ /// <param name="bytesRead">Receives the number of bytes read from <paramref name="source"/>.</param>
+ /// <returns>A deserialized instance of <typeparamref name="T"/>.</returns>
+ /// <remarks>
+ /// Except for where required to for avoiding ambiguity, this method does not check that there are
+ /// no cycles in the type graph for <typeparamref name="T"/>. If <typeparamref name="T"/> is a
+ /// reference type (class) which includes a cycle in the type graph,
+ /// then it is possible for the data in <paramref name="source"/> to cause
+ /// an arbitrary extension to the maximum stack depth of this routine, leading to a
+ /// <see cref="StackOverflowException"/>.
+ ///
+ /// If <typeparamref name="T"/> is a value type (struct) the compiler will enforce that there are no
+ /// cycles in the type graph.
+ ///
+ /// When reference types are used the onus is on the caller of this method to prevent cycles, or to
+ /// mitigate the possibility of the stack overflow.
+ /// </remarks>
+ /// <exception cref="AsnSerializationConstraintException">
+ /// A portion of <typeparamref name="T"/> is invalid for deserialization.
+ /// </exception>
+ /// <exception cref="CryptographicException">
+ /// Any of the data in <paramref name="source"/> is invalid for mapping to the return value.
+ /// </exception>
+ public static T Deserialize<T>(ReadOnlyMemory<byte> source, AsnEncodingRules ruleSet, out int bytesRead)
+ {
+ Deserializer deserializer = GetDeserializer(typeof(T), null);
+ AsnReader reader = new AsnReader(source, ruleSet);
+ ReadOnlyMemory<byte> firstElement = reader.PeekEncodedValue();
+
+ T t = (T)deserializer(reader);
+ bytesRead = firstElement.Length;
+ return t;
+ }
+
+ /// <summary>
/// Serialize <paramref name="value"/> into an ASN.1 writer under the specified encoding rules.
/// </summary>
/// <typeparam name="T">
@@ -1388,10 +1471,10 @@ namespace System.Security.Cryptography.Asn1
/// no cycles in the type graph for <typeparamref name="T"/>. If <typeparamref name="T"/> is a
/// reference type (class) which includes a cycle in the type graph, and there is a cycle within the
/// object graph this method will consume memory and stack space until one is exhausted.
- ///
+ ///
/// If <typeparamref name="T"/> is a value type (struct) the compiler will enforce that there are no
/// cycles in the type graph.
- ///
+ ///
/// When reference types are used the onus is on the caller of this method to prevent object cycles,
/// or to mitigate the possibility of the stack overflow or memory exhaustion.
/// </remarks>
@@ -1430,10 +1513,10 @@ namespace System.Security.Cryptography.Asn1
/// no cycles in the type graph for <typeparamref name="T"/>. If <typeparamref name="T"/> is a
/// reference type (class) which includes a cycle in the type graph, and there is a cycle within the
/// object graph this method will consume memory and stack space until one is exhausted.
- ///
+ ///
/// If <typeparamref name="T"/> is a value type (struct) the compiler will enforce that there are no
/// cycles in the type graph.
- ///
+ ///
/// When reference types are used the onus is on the caller of this method to prevent object cycles,
/// or to mitigate the possibility of the stack overflow or memory exhaustion.
/// </remarks>
diff --git a/src/Common/src/System/Security/Cryptography/Asn1V2.cs b/src/Common/src/System/Security/Cryptography/Asn1V2.cs
index 6594846641..0f9806ad67 100644
--- a/src/Common/src/System/Security/Cryptography/Asn1V2.cs
+++ b/src/Common/src/System/Security/Cryptography/Asn1V2.cs
@@ -395,7 +395,7 @@ namespace System.Security.Cryptography.Asn1
public override int GetByteCount(string s)
{
- return GetByteCount(s.AsReadOnlySpan());
+ return GetByteCount(s.AsSpan());
}
public
diff --git a/src/Common/src/System/Security/Cryptography/AsnWriter.cs b/src/Common/src/System/Security/Cryptography/AsnWriter.cs
index 8f2fc34369..cff5cddab2 100644
--- a/src/Common/src/System/Security/Cryptography/AsnWriter.cs
+++ b/src/Common/src/System/Security/Cryptography/AsnWriter.cs
@@ -62,7 +62,7 @@ namespace System.Security.Cryptography.Asn1
// past where the buffer was "allocated". This causes quite a number of reallocs
// and copies, so it's a #define opt-in.
byte[] newBytes = new byte[_offset + pendingCount];
-
+
if (_buffer != null)
{
Buffer.BlockCopy(_buffer, 0, newBytes, 0, _offset);
@@ -99,7 +99,7 @@ namespace System.Security.Cryptography.Asn1
int spaceRequired = tag.CalculateEncodedSize();
EnsureWriteCapacity(spaceRequired);
- if (!tag.TryWrite(_buffer.AsSpan().Slice(_offset, spaceRequired), out int written) ||
+ if (!tag.TryWrite(_buffer.AsSpan(_offset, spaceRequired), out int written) ||
written != spaceRequired)
{
Debug.Fail($"TryWrite failed or written was wrong value ({written} vs {spaceRequired})");
@@ -190,7 +190,7 @@ namespace System.Security.Cryptography.Asn1
Debug.Assert(parsedBack.Length == preEncodedValue.Length);
EnsureWriteCapacity(preEncodedValue.Length);
- preEncodedValue.Span.CopyTo(_buffer.AsSpan().Slice(_offset));
+ preEncodedValue.Span.CopyTo(_buffer.AsSpan(_offset));
_offset += preEncodedValue.Length;
}
@@ -216,7 +216,7 @@ namespace System.Security.Cryptography.Asn1
// T-REC-X.690-201508 sec 11.1, 8.2
private void WriteBooleanCore(Asn1Tag tag, bool value)
- {
+ {
Debug.Assert(!tag.IsConstructed);
WriteTag(tag);
WriteLength(1);
@@ -313,7 +313,7 @@ namespace System.Security.Cryptography.Asn1
private void WriteNonNegativeIntegerCore(Asn1Tag tag, ulong value)
{
int valueLength;
-
+
// 0x80 needs two bytes: 0x00 0x80
if (value < 0x80)
valueLength = 1;
@@ -449,7 +449,7 @@ namespace System.Security.Cryptography.Asn1
WriteLength(bitString.Length + 1);
_buffer[_offset] = (byte)unusedBitCount;
_offset++;
- bitString.CopyTo(_buffer.AsSpan().Slice(_offset));
+ bitString.CopyTo(_buffer.AsSpan(_offset));
_offset += bitString.Length;
}
@@ -508,7 +508,7 @@ namespace System.Security.Cryptography.Asn1
_buffer[_offset] = 0;
_offset++;
- dest = _buffer.AsSpan().Slice(_offset);
+ dest = _buffer.AsSpan(_offset);
remainingData.Slice(0, MaxCERContentSize).CopyTo(dest);
remainingData = remainingData.Slice(MaxCERContentSize);
@@ -521,7 +521,7 @@ namespace System.Security.Cryptography.Asn1
_buffer[_offset] = (byte)unusedBitCount;
_offset++;
- dest = _buffer.AsSpan().Slice(_offset);
+ dest = _buffer.AsSpan(_offset);
remainingData.CopyTo(dest);
_offset += remainingData.Length;
@@ -552,7 +552,7 @@ namespace System.Security.Cryptography.Asn1
WriteNamedBitList(tag, enumValue.GetType(), enumValue);
}
- public void WriteNamedBitList<TEnum>(Asn1Tag tag, TEnum enumValue) where TEnum : struct
+ public void WriteNamedBitList<TEnum>(Asn1Tag tag, TEnum enumValue) where TEnum : struct
{
WriteNamedBitList(tag, typeof(TEnum), enumValue);
}
@@ -655,7 +655,7 @@ namespace System.Security.Cryptography.Asn1
// Clear the constructed flag, if present.
WriteTag(tag.AsPrimitive());
WriteLength(octetString.Length);
- octetString.CopyTo(_buffer.AsSpan().Slice(_offset));
+ octetString.CopyTo(_buffer.AsSpan(_offset));
_offset += octetString.Length;
}
@@ -707,7 +707,7 @@ namespace System.Security.Cryptography.Asn1
WriteTag(primitiveOctetString);
WriteLength(MaxCERSegmentSize);
- dest = _buffer.AsSpan().Slice(_offset);
+ dest = _buffer.AsSpan(_offset);
remainingData.Slice(0, MaxCERSegmentSize).CopyTo(dest);
_offset += MaxCERSegmentSize;
@@ -716,7 +716,7 @@ namespace System.Security.Cryptography.Asn1
WriteTag(primitiveOctetString);
WriteLength(remainingData.Length);
- dest = _buffer.AsSpan().Slice(_offset);
+ dest = _buffer.AsSpan(_offset);
remainingData.CopyTo(dest);
_offset += remainingData.Length;
@@ -759,7 +759,7 @@ namespace System.Security.Cryptography.Asn1
if (oidValue == null)
throw new ArgumentNullException(nameof(oidValue));
- WriteObjectIdentifier(oidValue.AsReadOnlySpan());
+ WriteObjectIdentifier(oidValue.AsSpan());
}
public void WriteObjectIdentifier(ReadOnlySpan<char> oidValue)
@@ -780,7 +780,7 @@ namespace System.Security.Cryptography.Asn1
if (oidValue == null)
throw new ArgumentNullException(nameof(oidValue));
- WriteObjectIdentifier(tag, oidValue.AsReadOnlySpan());
+ WriteObjectIdentifier(tag, oidValue.AsSpan());
}
public void WriteObjectIdentifier(Asn1Tag tag, ReadOnlySpan<char> oidValue)
@@ -843,13 +843,13 @@ namespace System.Security.Cryptography.Asn1
BigInteger subIdentifier = ParseSubIdentifier(ref remaining);
subIdentifier += 40 * firstComponent;
- int localLen = EncodeSubIdentifier(tmp.AsSpan().Slice(tmpOffset), ref subIdentifier);
+ int localLen = EncodeSubIdentifier(tmp.AsSpan(tmpOffset), ref subIdentifier);
tmpOffset += localLen;
while (!remaining.IsEmpty)
{
subIdentifier = ParseSubIdentifier(ref remaining);
- localLen = EncodeSubIdentifier(tmp.AsSpan().Slice(tmpOffset), ref subIdentifier);
+ localLen = EncodeSubIdentifier(tmp.AsSpan(tmpOffset), ref subIdentifier);
tmpOffset += localLen;
}
@@ -920,7 +920,7 @@ namespace System.Security.Cryptography.Asn1
dest[0] = 0;
return 1;
}
-
+
BigInteger unencoded = subIdentifier;
int idx = 0;
@@ -974,7 +974,7 @@ namespace System.Security.Cryptography.Asn1
private void WriteEnumeratedValue(Asn1Tag tag, Type tEnum, object enumValue)
{
CheckUniversalTag(tag, UniversalTagNumber.Enumerated);
-
+
Type backingType = tEnum.GetEnumUnderlyingType();
if (tEnum.IsDefined(typeof(FlagsAttribute), false))
@@ -1080,7 +1080,7 @@ namespace System.Security.Cryptography.Asn1
PopTag(tag, sortContents);
}
-
+
public void WriteUtcTime(DateTimeOffset value)
{
WriteUtcTimeCore(Asn1Tag.UtcTime, value);
@@ -1097,7 +1097,7 @@ namespace System.Security.Cryptography.Asn1
// T-REC-X.680-201508 sec 47
// T-REC-X.690-201508 sec 11.8
private void WriteUtcTimeCore(Asn1Tag tag, DateTimeOffset value)
- {
+ {
// Because UtcTime is IMPLICIT VisibleString it technically can have
// a constructed form.
// DER says character strings must be primitive.
@@ -1121,7 +1121,7 @@ namespace System.Security.Cryptography.Asn1
int minute = normalized.Minute;
int second = normalized.Second;
- Span<byte> baseSpan = _buffer.AsSpan().Slice(_offset);
+ Span<byte> baseSpan = _buffer.AsSpan(_offset);
StandardFormat format = new StandardFormat('D', 2);
if (!Utf8Formatter.TryFormat(year % 100, baseSpan.Slice(0, 2), out _, format) ||
@@ -1134,7 +1134,7 @@ namespace System.Security.Cryptography.Asn1
Debug.Fail($"Utf8Formatter.TryFormat failed to build components of {normalized:O}");
throw new CryptographicException();
}
-
+
_buffer[_offset + 12] = (byte)'Z';
_offset += UtcTimeValueLength;
@@ -1188,7 +1188,7 @@ namespace System.Security.Cryptography.Asn1
if (!omitFractionalSeconds)
{
long floatingTicks = normalized.Ticks % TimeSpan.TicksPerSecond;
-
+
if (floatingTicks != 0)
{
// We're only loading in sub-second ticks.
@@ -1234,7 +1234,7 @@ namespace System.Security.Cryptography.Asn1
int minute = normalized.Minute;
int second = normalized.Second;
- Span<byte> baseSpan = _buffer.AsSpan().Slice(_offset);
+ Span<byte> baseSpan = _buffer.AsSpan(_offset);
StandardFormat d4 = new StandardFormat('D', 4);
StandardFormat d2 = new StandardFormat('D', 2);
@@ -1248,7 +1248,7 @@ namespace System.Security.Cryptography.Asn1
Debug.Fail($"Utf8Formatter.TryFormat failed to build components of {normalized:O}");
throw new CryptographicException();
}
-
+
_offset += IntegerPortionLength;
fraction.CopyTo(baseSpan.Slice(IntegerPortionLength));
_offset += fraction.Length;
@@ -1287,7 +1287,7 @@ namespace System.Security.Cryptography.Asn1
}
bytesWritten = _offset;
- _buffer.AsSpan().Slice(0, _offset).CopyTo(dest);
+ _buffer.AsSpan(0, _offset).CopyTo(dest);
return true;
}
@@ -1305,7 +1305,7 @@ namespace System.Security.Cryptography.Asn1
// If the stack is closed out then everything is a definite encoding (BER, DER) or a
// required indefinite encoding (CER). So we're correctly sized up, and ready to copy.
- return _buffer.AsSpan().Slice(0, _offset).ToArray();
+ return _buffer.AsSpan(0, _offset).ToArray();
}
public ReadOnlySpan<byte> EncodeAsSpan()
@@ -1408,7 +1408,7 @@ namespace System.Security.Cryptography.Asn1
if (str == null)
throw new ArgumentNullException(nameof(str));
- WriteCharacterString(encodingType, str.AsReadOnlySpan());
+ WriteCharacterString(encodingType, str.AsSpan());
}
public void WriteCharacterString(UniversalTagNumber encodingType, ReadOnlySpan<char> str)
@@ -1419,11 +1419,11 @@ namespace System.Security.Cryptography.Asn1
}
public void WriteCharacterString(Asn1Tag tag, UniversalTagNumber encodingType, string str)
- {
+ {
if (str == null)
throw new ArgumentNullException(nameof(str));
- WriteCharacterString(tag, encodingType, str.AsReadOnlySpan());
+ WriteCharacterString(tag, encodingType, str.AsSpan());
}
public void WriteCharacterString(Asn1Tag tag, UniversalTagNumber encodingType, ReadOnlySpan<char> str)
@@ -1472,7 +1472,7 @@ namespace System.Security.Cryptography.Asn1
// Clear the constructed tag, if present.
WriteTag(tag.AsPrimitive());
WriteLength(size);
- Span<byte> dest = _buffer.AsSpan().Slice(_offset, size);
+ Span<byte> dest = _buffer.AsSpan(_offset, size);
fixed (byte* destPtr = &MemoryMarshal.GetReference(dest))
{
@@ -1517,7 +1517,7 @@ namespace System.Security.Cryptography.Asn1
}
}
- WriteConstructedCerOctetString(tag, tmp.AsSpan().Slice(0, size));
+ WriteConstructedCerOctetString(tag, tmp.AsSpan(0, size));
Array.Clear(tmp, 0, size);
ArrayPool<byte>.Shared.Return(tmp);
}
diff --git a/src/Common/src/System/Security/Cryptography/DSACng.SignVerify.cs b/src/Common/src/System/Security/Cryptography/DSACng.SignVerify.cs
index 81425529bf..2b2452d733 100644
--- a/src/Common/src/System/Security/Cryptography/DSACng.SignVerify.cs
+++ b/src/Common/src/System/Security/Cryptography/DSACng.SignVerify.cs
@@ -45,21 +45,21 @@ namespace System.Security.Cryptography
}
}
- public override unsafe bool TryCreateSignature(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten)
+ public override unsafe bool TryCreateSignature(ReadOnlySpan<byte> hash, Span<byte> destination, out int bytesWritten)
{
- byte[] arrayToReturnToArrayPool = AdjustHashSizeIfNecessaryWithArrayPool(ref source);
+ byte[] arrayToReturnToArrayPool = AdjustHashSizeIfNecessaryWithArrayPool(ref hash);
try
{
using (SafeNCryptKeyHandle keyHandle = GetDuplicatedKeyHandle())
{
- return CngCommon.TrySignHash(keyHandle, source, destination, AsymmetricPaddingMode.None, null, out bytesWritten);
+ return CngCommon.TrySignHash(keyHandle, hash, destination, AsymmetricPaddingMode.None, null, out bytesWritten);
}
}
finally
{
if (arrayToReturnToArrayPool != null)
{
- Array.Clear(arrayToReturnToArrayPool, 0, source.Length);
+ Array.Clear(arrayToReturnToArrayPool, 0, hash.Length);
ArrayPool<byte>.Shared.Return(arrayToReturnToArrayPool);
}
}
@@ -79,16 +79,16 @@ namespace System.Security.Cryptography
return VerifySignature((ReadOnlySpan<byte>)rgbHash, (ReadOnlySpan<byte>)rgbSignature);
}
- public override bool VerifySignature(ReadOnlySpan<byte> rgbHash, ReadOnlySpan<byte> rgbSignature)
+ public override bool VerifySignature(ReadOnlySpan<byte> hash, ReadOnlySpan<byte> signature)
{
- byte[] arrayToReturnToArrayPool = AdjustHashSizeIfNecessaryWithArrayPool(ref rgbHash);
+ byte[] arrayToReturnToArrayPool = AdjustHashSizeIfNecessaryWithArrayPool(ref hash);
try
{
using (SafeNCryptKeyHandle keyHandle = GetDuplicatedKeyHandle())
{
unsafe
{
- return CngCommon.VerifyHash(keyHandle, rgbHash, rgbSignature, AsymmetricPaddingMode.None, null);
+ return CngCommon.VerifyHash(keyHandle, hash, signature, AsymmetricPaddingMode.None, null);
}
}
}
@@ -96,7 +96,7 @@ namespace System.Security.Cryptography
{
if (arrayToReturnToArrayPool != null)
{
- Array.Clear(arrayToReturnToArrayPool, 0, rgbHash.Length);
+ Array.Clear(arrayToReturnToArrayPool, 0, hash.Length);
ArrayPool<byte>.Shared.Return(arrayToReturnToArrayPool);
}
}
diff --git a/src/Common/src/System/Security/Cryptography/DSAOpenSsl.cs b/src/Common/src/System/Security/Cryptography/DSAOpenSsl.cs
index 9610621ec1..35de009005 100644
--- a/src/Common/src/System/Security/Cryptography/DSAOpenSsl.cs
+++ b/src/Common/src/System/Security/Cryptography/DSAOpenSsl.cs
@@ -180,8 +180,8 @@ namespace System.Security.Cryptography
protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) =>
AsymmetricAlgorithmHelpers.HashData(data, hashAlgorithm);
- protected override bool TryHashData(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) =>
- AsymmetricAlgorithmHelpers.TryHashData(source, destination, hashAlgorithm, out bytesWritten);
+ protected override bool TryHashData(ReadOnlySpan<byte> data, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) =>
+ AsymmetricAlgorithmHelpers.TryHashData(data, destination, hashAlgorithm, out bytesWritten);
public override byte[] CreateSignature(byte[] rgbHash)
{
@@ -216,7 +216,7 @@ namespace System.Security.Cryptography
}
}
- public override bool TryCreateSignature(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten)
+ public override bool TryCreateSignature(ReadOnlySpan<byte> hash, Span<byte> destination, out int bytesWritten)
{
byte[] converted;
SafeDsaHandle key = _key.Value;
@@ -224,7 +224,7 @@ namespace System.Security.Cryptography
byte[] signature = ArrayPool<byte>.Shared.Rent(signatureSize);
try
{
- bool success = Interop.Crypto.DsaSign(key, source, source.Length, new Span<byte>(signature, 0, signatureSize), out signatureSize);
+ bool success = Interop.Crypto.DsaSign(key, hash, hash.Length, new Span<byte>(signature, 0, signatureSize), out signatureSize);
if (!success)
{
throw Interop.Crypto.CreateOpenSslCryptographicException();
@@ -269,20 +269,20 @@ namespace System.Security.Cryptography
return VerifySignature((ReadOnlySpan<byte>)rgbHash, (ReadOnlySpan<byte>)rgbSignature);
}
- public override bool VerifySignature(ReadOnlySpan<byte> rgbHash, ReadOnlySpan<byte> rgbSignature)
+ public override bool VerifySignature(ReadOnlySpan<byte> hash, ReadOnlySpan<byte> signature)
{
SafeDsaHandle key = _key.Value;
int expectedSignatureBytes = Interop.Crypto.DsaSignatureFieldSize(key) * 2;
- if (rgbSignature.Length != expectedSignatureBytes)
+ if (signature.Length != expectedSignatureBytes)
{
// The input isn't of the right length (assuming no DER), so we can't sensibly re-encode it with DER.
return false;
}
- byte[] openSslFormat = AsymmetricAlgorithmHelpers.ConvertIeee1363ToDer(rgbSignature);
+ byte[] openSslFormat = AsymmetricAlgorithmHelpers.ConvertIeee1363ToDer(signature);
- return Interop.Crypto.DsaVerify(key, rgbHash, rgbHash.Length, openSslFormat, openSslFormat.Length);
+ return Interop.Crypto.DsaVerify(key, hash, hash.Length, openSslFormat, openSslFormat.Length);
}
private void SetKey(SafeDsaHandle newKey)
diff --git a/src/Common/src/System/Security/Cryptography/DSASecurityTransforms.cs b/src/Common/src/System/Security/Cryptography/DSASecurityTransforms.cs
index e06058c2b3..fefaabb2ff 100644
--- a/src/Common/src/System/Security/Cryptography/DSASecurityTransforms.cs
+++ b/src/Common/src/System/Security/Cryptography/DSASecurityTransforms.cs
@@ -235,8 +235,8 @@ namespace System.Security.Cryptography
protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) =>
AsymmetricAlgorithmHelpers.HashData(data, hashAlgorithm);
- protected override bool TryHashData(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) =>
- AsymmetricAlgorithmHelpers.TryHashData(source, destination, hashAlgorithm, out bytesWritten);
+ protected override bool TryHashData(ReadOnlySpan<byte> data, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) =>
+ AsymmetricAlgorithmHelpers.TryHashData(data, destination, hashAlgorithm, out bytesWritten);
protected override void Dispose(bool disposing)
{
diff --git a/src/Common/src/System/Security/Cryptography/ECCng.HashAlgorithm.cs b/src/Common/src/System/Security/Cryptography/ECCng.HashAlgorithm.cs
index 65abfd00f5..1eb4344389 100644
--- a/src/Common/src/System/Security/Cryptography/ECCng.HashAlgorithm.cs
+++ b/src/Common/src/System/Security/Cryptography/ECCng.HashAlgorithm.cs
@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Diagnostics;
+using Internal.NativeCrypto;
using static Interop.Crypt32;
namespace System.Security.Cryptography
@@ -46,5 +48,36 @@ namespace System.Security.Cryptography
return new HashAlgorithmName(oid.Name);
}
+
+ /// <summary>
+ /// Is the curve named, or once of the special nist curves
+ /// </summary>
+ internal static bool IsECNamedCurve(string algorithm)
+ {
+ return (algorithm == BCryptNative.AlgorithmName.ECDH ||
+ algorithm == BCryptNative.AlgorithmName.ECDsa);
+ }
+
+ /// <summary>
+ /// Maps algorithm to curve name accounting for the special nist curves
+ /// </summary>
+ internal static string SpecialNistAlgorithmToCurveName(string algorithm)
+ {
+ switch (algorithm)
+ {
+ case BCryptNative.AlgorithmName.ECDHP256:
+ case BCryptNative.AlgorithmName.ECDsaP256:
+ return "nistP256";
+ case BCryptNative.AlgorithmName.ECDHP384:
+ case BCryptNative.AlgorithmName.ECDsaP384:
+ return "nistP384";
+ case BCryptNative.AlgorithmName.ECDHP521:
+ case BCryptNative.AlgorithmName.ECDsaP521:
+ return "nistP521";
+ }
+
+ Debug.Fail($"Unknown curve {algorithm}");
+ throw new PlatformNotSupportedException(string.Format(SR.Cryptography_CurveNotSupported, algorithm));
+ }
}
}
diff --git a/src/Common/src/System/Security/Cryptography/ECCng.ImportExport.cs b/src/Common/src/System/Security/Cryptography/ECCng.ImportExport.cs
index 946d1dff61..120c871917 100644
--- a/src/Common/src/System/Security/Cryptography/ECCng.ImportExport.cs
+++ b/src/Common/src/System/Security/Cryptography/ECCng.ImportExport.cs
@@ -18,7 +18,7 @@ namespace System.Security.Cryptography
{
internal static partial class ECCng
{
- internal static byte[] GetNamedCurveBlob(ref ECParameters parameters)
+ internal static byte[] GetNamedCurveBlob(ref ECParameters parameters, bool ecdh)
{
Debug.Assert(parameters.Curve.IsNamed);
@@ -46,7 +46,9 @@ namespace System.Security.Cryptography
{
// Build the header
BCRYPT_ECCKEY_BLOB* pBcryptBlob = (BCRYPT_ECCKEY_BLOB*)pBlob;
- pBcryptBlob->Magic = CurveNameToMagicNumber(parameters.Curve.Oid.FriendlyName, includePrivateParameters);
+ pBcryptBlob->Magic = ecdh ?
+ EcdhCurveNameToMagicNumber(parameters.Curve.Oid.FriendlyName, includePrivateParameters) :
+ EcdsaCurveNameToMagicNumber(parameters.Curve.Oid.FriendlyName, includePrivateParameters);
pBcryptBlob->cbKey = parameters.Q.X.Length;
// Emit the blob
@@ -65,7 +67,7 @@ namespace System.Security.Cryptography
return blob;
}
- internal static byte[] GetPrimeCurveBlob(ref ECParameters parameters)
+ internal static byte[] GetPrimeCurveBlob(ref ECParameters parameters, bool ecdh)
{
Debug.Assert(parameters.Curve.IsPrime);
@@ -113,8 +115,8 @@ namespace System.Security.Cryptography
BCRYPT_ECCFULLKEY_BLOB* pBcryptBlob = (BCRYPT_ECCFULLKEY_BLOB*)pBlob;
pBcryptBlob->Version = 1; // No constant for this found in bcrypt.h
pBcryptBlob->Magic = includePrivateParameters ?
- KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_GENERIC_MAGIC :
- KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_GENERIC_MAGIC;
+ (ecdh ? KeyBlobMagicNumber.BCRYPT_ECDH_PRIVATE_GENERIC_MAGIC : KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_GENERIC_MAGIC) :
+ (ecdh ? KeyBlobMagicNumber.BCRYPT_ECDH_PUBLIC_GENERIC_MAGIC : KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_GENERIC_MAGIC);
pBcryptBlob->cbCofactor = curve.Cofactor.Length;
pBcryptBlob->cbFieldLength = parameters.Q.X.Length;
pBcryptBlob->cbSeed = curve.Seed == null ? 0 : curve.Seed.Length;
@@ -384,7 +386,7 @@ namespace System.Security.Cryptography
/// to the pre-Win10 magic numbers to support import on pre-Win10 environments
/// that don't have the named curve functionality.
/// </summary>
- private static KeyBlobMagicNumber CurveNameToMagicNumber(string name, bool includePrivateParameters)
+ private static KeyBlobMagicNumber EcdsaCurveNameToMagicNumber(string name, bool includePrivateParameters)
{
switch (EcdsaCurveNameToAlgorithm(name))
{
@@ -395,13 +397,13 @@ namespace System.Security.Cryptography
case AlgorithmName.ECDsaP384:
return includePrivateParameters ?
- KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_P384_MAGIC :
- KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_P384_MAGIC;
+ KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_P384_MAGIC :
+ KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_P384_MAGIC;
case AlgorithmName.ECDsaP521:
return includePrivateParameters ?
- KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_P521_MAGIC :
- KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_P521_MAGIC;
+ KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_P521_MAGIC :
+ KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_P521_MAGIC;
default:
// all other curves are new in Win10 so use named curves
@@ -412,6 +414,38 @@ namespace System.Security.Cryptography
}
/// <summary>
+ /// Map a curve name to magic number. Maps the names of the curves that worked pre-Win10
+ /// to the pre-Win10 magic numbers to support import on pre-Win10 environments
+ /// that don't have the named curve functionality.
+ /// </summary>
+ private static KeyBlobMagicNumber EcdhCurveNameToMagicNumber(string name, bool includePrivateParameters)
+ {
+ switch (EcdhCurveNameToAlgorithm(name))
+ {
+ case AlgorithmName.ECDHP256:
+ return includePrivateParameters ?
+ KeyBlobMagicNumber.BCRYPT_ECDH_PRIVATE_P256_MAGIC :
+ KeyBlobMagicNumber.BCRYPT_ECDH_PUBLIC_P256_MAGIC;
+
+ case AlgorithmName.ECDHP384:
+ return includePrivateParameters ?
+ KeyBlobMagicNumber.BCRYPT_ECDH_PRIVATE_P384_MAGIC :
+ KeyBlobMagicNumber.BCRYPT_ECDH_PUBLIC_P384_MAGIC;
+
+ case AlgorithmName.ECDHP521:
+ return includePrivateParameters ?
+ KeyBlobMagicNumber.BCRYPT_ECDH_PRIVATE_P521_MAGIC :
+ KeyBlobMagicNumber.BCRYPT_ECDH_PUBLIC_P521_MAGIC;
+
+ default:
+ // all other curves are new in Win10 so use named curves
+ return includePrivateParameters ?
+ KeyBlobMagicNumber.BCRYPT_ECDH_PRIVATE_GENERIC_MAGIC :
+ KeyBlobMagicNumber.BCRYPT_ECDH_PUBLIC_GENERIC_MAGIC;
+ }
+ }
+
+ /// <summary>
/// Helper method to map between BCrypt.ECC_CURVE_TYPE_ENUM and ECCurve.ECCurveType
/// </summary>
private static Interop.BCrypt.ECC_CURVE_TYPE_ENUM ConvertToCurveTypeEnum(ECCurve.ECCurveType value)
@@ -508,5 +542,30 @@ namespace System.Security.Cryptography
// All other curves are new in Win10 so use generic algorithm
return AlgorithmName.ECDsa;
}
+
+ /// <summary>
+ /// Map a curve name to algorithm. This enables curves that worked pre-Win10
+ /// to work with newer APIs for import and export.
+ /// </summary>
+ internal static string EcdhCurveNameToAlgorithm(string algorithm)
+ {
+ switch (algorithm)
+ {
+ case "nistP256":
+ case "ECDH_P256":
+ return AlgorithmName.ECDHP256;
+
+ case "nistP384":
+ case "ECDH_P384":
+ return AlgorithmName.ECDHP384;
+
+ case "nistP521":
+ case "ECDH_P521":
+ return AlgorithmName.ECDHP521;
+ }
+
+ // All other curves are new in Win10 so use generic algorithm
+ return AlgorithmName.ECDH;
+ }
}
}
diff --git a/src/Common/src/System/Security/Cryptography/ECDiffieHellmanCng.ImportExport.cs b/src/Common/src/System/Security/Cryptography/ECDiffieHellmanCng.ImportExport.cs
new file mode 100644
index 0000000000..f159aa44c6
--- /dev/null
+++ b/src/Common/src/System/Security/Cryptography/ECDiffieHellmanCng.ImportExport.cs
@@ -0,0 +1,94 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Security.Cryptography
+{
+#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS
+ internal static partial class ECDiffieHellmanImplementation
+ {
+#endif
+ public sealed partial class ECDiffieHellmanCng : ECDiffieHellman
+ {
+ public override void ImportParameters(ECParameters parameters)
+ {
+ parameters.Validate();
+ ECCurve curve = parameters.Curve;
+ bool includePrivateParamerters = (parameters.D != null);
+
+ if (curve.IsPrime)
+ {
+ byte[] ecExplicitBlob = ECCng.GetPrimeCurveBlob(ref parameters, ecdh: true);
+ ImportFullKeyBlob(ecExplicitBlob, includePrivateParamerters);
+ }
+ else if (curve.IsNamed)
+ {
+ // FriendlyName is required; an attempt was already made to default it in ECCurve
+ if (string.IsNullOrEmpty(curve.Oid.FriendlyName))
+ {
+ throw new PlatformNotSupportedException(
+ string.Format(SR.Cryptography_InvalidCurveOid, curve.Oid.Value));
+ }
+
+ byte[] ecNamedCurveBlob = ECCng.GetNamedCurveBlob(ref parameters, ecdh: true);
+ ImportKeyBlob(ecNamedCurveBlob, curve.Oid.FriendlyName, includePrivateParamerters);
+ }
+ else
+ {
+ throw new PlatformNotSupportedException(
+ string.Format(SR.Cryptography_CurveNotSupported, curve.CurveType.ToString()));
+ }
+ }
+
+ public override ECParameters ExportExplicitParameters(bool includePrivateParameters)
+ {
+ byte[] blob = ExportFullKeyBlob(includePrivateParameters);
+
+ try
+ {
+ ECParameters ecparams = new ECParameters();
+ ECCng.ExportPrimeCurveParameters(ref ecparams, blob, includePrivateParameters);
+ return ecparams;
+ }
+ finally
+ {
+ Array.Clear(blob, 0, blob.Length);
+ }
+ }
+
+ public override ECParameters ExportParameters(bool includePrivateParameters)
+ {
+ ECParameters ecparams = new ECParameters();
+
+ string curveName = GetCurveName();
+ byte[] blob = null;
+
+ try
+ {
+ if (string.IsNullOrEmpty(curveName))
+ {
+ blob = ExportFullKeyBlob(includePrivateParameters);
+ ECCng.ExportPrimeCurveParameters(ref ecparams, blob, includePrivateParameters);
+ }
+ else
+ {
+ blob = ExportKeyBlob(includePrivateParameters);
+ ECCng.ExportNamedCurveParameters(ref ecparams, blob, includePrivateParameters);
+ ecparams.Curve = ECCurve.CreateFromFriendlyName(curveName);
+ }
+
+ return ecparams;
+ }
+ finally
+ {
+ if (blob != null)
+ {
+ Array.Clear(blob, 0, blob.Length);
+ }
+ }
+ }
+ }
+#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS
+ }
+#endif
+}
diff --git a/src/Common/src/System/Security/Cryptography/ECDiffieHellmanCng.cs b/src/Common/src/System/Security/Cryptography/ECDiffieHellmanCng.cs
new file mode 100644
index 0000000000..0c23531c6f
--- /dev/null
+++ b/src/Common/src/System/Security/Cryptography/ECDiffieHellmanCng.cs
@@ -0,0 +1,146 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.Win32.SafeHandles;
+
+namespace System.Security.Cryptography
+{
+#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS
+ internal static partial class ECDiffieHellmanImplementation
+ {
+#endif
+ public sealed partial class ECDiffieHellmanCng : ECDiffieHellman
+ {
+ public ECDiffieHellmanCng() : this(521) { }
+
+ public ECDiffieHellmanCng(int keySize)
+ {
+ KeySize = keySize;
+ }
+
+ public ECDiffieHellmanCng(ECCurve curve)
+ {
+ // GenerateKey will already do all of the validation we need.
+ GenerateKey(curve);
+ }
+
+ public override int KeySize
+ {
+ get
+ {
+ return base.KeySize;
+ }
+ set
+ {
+ if (KeySize == value)
+ {
+ return;
+ }
+
+ // Set the KeySize before DisposeKey so that an invalid value doesn't throw away the key
+ base.KeySize = value;
+
+ DisposeKey();
+ // Key will be lazily re-created
+ }
+ }
+
+ /// <summary>
+ /// Set the KeySize without validating against LegalKeySizes.
+ /// </summary>
+ /// <param name="newKeySize">The value to set the KeySize to.</param>
+ private void ForceSetKeySize(int newKeySize)
+ {
+ // In the event that a key was loaded via ImportParameters, curve name, or an IntPtr/SafeHandle
+ // it could be outside of the bounds that we currently represent as "legal key sizes".
+ // Since that is our view into the underlying component it can be detached from the
+ // component's understanding. If it said it has opened a key, and this is the size, trust it.
+ KeySizeValue = newKeySize;
+ }
+
+ public override KeySizes[] LegalKeySizes
+ {
+ get
+ {
+ // Return the three sizes that can be explicitly set (for backwards compatibility)
+ return new[] {
+ new KeySizes(minSize: 256, maxSize: 384, skipSize: 128),
+ new KeySizes(minSize: 521, maxSize: 521, skipSize: 0),
+ };
+ }
+ }
+
+ public override byte[] DeriveKeyFromHash(
+ ECDiffieHellmanPublicKey otherPartyPublicKey,
+ HashAlgorithmName hashAlgorithm,
+ byte[] secretPrepend,
+ byte[] secretAppend)
+ {
+ if (otherPartyPublicKey == null)
+ throw new ArgumentNullException(nameof(otherPartyPublicKey));
+ if (string.IsNullOrEmpty(hashAlgorithm.Name))
+ throw new ArgumentException(SR.Cryptography_HashAlgorithmNameNullOrEmpty, nameof(hashAlgorithm));
+
+ using (SafeNCryptSecretHandle secretAgreement = DeriveSecretAgreementHandle(otherPartyPublicKey))
+ {
+ return Interop.NCrypt.DeriveKeyMaterialHash(
+ secretAgreement,
+ hashAlgorithm.Name,
+ secretPrepend,
+ secretAppend,
+ Interop.NCrypt.SecretAgreementFlags.None);
+ }
+ }
+
+ public override byte[] DeriveKeyFromHmac(
+ ECDiffieHellmanPublicKey otherPartyPublicKey,
+ HashAlgorithmName hashAlgorithm,
+ byte[] hmacKey,
+ byte[] secretPrepend,
+ byte[] secretAppend)
+ {
+ if (otherPartyPublicKey == null)
+ throw new ArgumentNullException(nameof(otherPartyPublicKey));
+ if (string.IsNullOrEmpty(hashAlgorithm.Name))
+ throw new ArgumentException(SR.Cryptography_HashAlgorithmNameNullOrEmpty, nameof(hashAlgorithm));
+
+ using (SafeNCryptSecretHandle secretAgreement = DeriveSecretAgreementHandle(otherPartyPublicKey))
+ {
+ Interop.NCrypt.SecretAgreementFlags flags = hmacKey == null ?
+ Interop.NCrypt.SecretAgreementFlags.UseSecretAsHmacKey :
+ Interop.NCrypt.SecretAgreementFlags.None;
+
+ return Interop.NCrypt.DeriveKeyMaterialHmac(
+ secretAgreement,
+ hashAlgorithm.Name,
+ hmacKey,
+ secretPrepend,
+ secretAppend,
+ flags);
+ }
+ }
+
+ public override byte[] DeriveKeyTls(ECDiffieHellmanPublicKey otherPartyPublicKey, byte[] prfLabel, byte[] prfSeed)
+ {
+ if (otherPartyPublicKey == null)
+ throw new ArgumentNullException(nameof(otherPartyPublicKey));
+ if (prfLabel == null)
+ throw new ArgumentNullException(nameof(prfLabel));
+ if (prfSeed == null)
+ throw new ArgumentNullException(nameof(prfSeed));
+
+ using (SafeNCryptSecretHandle secretAgreement = DeriveSecretAgreementHandle(otherPartyPublicKey))
+ {
+ return Interop.NCrypt.DeriveKeyMaterialTls(
+ secretAgreement,
+ prfLabel,
+ prfSeed,
+ Interop.NCrypt.SecretAgreementFlags.None);
+ }
+ }
+ }
+#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS
+ }
+#endif
+}
diff --git a/src/Common/src/System/Security/Cryptography/ECDiffieHellmanDerivation.cs b/src/Common/src/System/Security/Cryptography/ECDiffieHellmanDerivation.cs
new file mode 100644
index 0000000000..3b7071ab76
--- /dev/null
+++ b/src/Common/src/System/Security/Cryptography/ECDiffieHellmanDerivation.cs
@@ -0,0 +1,259 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+
+namespace System.Security.Cryptography
+{
+ internal static class ECDiffieHellmanDerivation
+ {
+ /// <summary>
+ /// Derive the raw ECDH value into <paramref name="hasher"/>, if present, otherwise returning the value.
+ /// </summary>
+ internal delegate byte[] DeriveSecretAgreement(ECDiffieHellmanPublicKey otherPartyPublicKey, IncrementalHash hasher);
+
+ internal static byte[] DeriveKeyFromHash(
+ ECDiffieHellmanPublicKey otherPartyPublicKey,
+ HashAlgorithmName hashAlgorithm,
+ ReadOnlySpan<byte> secretPrepend,
+ ReadOnlySpan<byte> secretAppend,
+ DeriveSecretAgreement deriveSecretAgreement)
+ {
+ Debug.Assert(otherPartyPublicKey != null);
+ Debug.Assert(!string.IsNullOrEmpty(hashAlgorithm.Name));
+
+ using (IncrementalHash hash = IncrementalHash.CreateHash(hashAlgorithm))
+ {
+ hash.AppendData(secretPrepend);
+
+ byte[] secretAgreement = deriveSecretAgreement(otherPartyPublicKey, hash);
+ // We want the side effect, and it should not have returned the answer.
+ Debug.Assert(secretAgreement == null);
+
+ hash.AppendData(secretAppend);
+
+ return hash.GetHashAndReset();
+ }
+ }
+
+ internal static unsafe byte[] DeriveKeyFromHmac(
+ ECDiffieHellmanPublicKey otherPartyPublicKey,
+ HashAlgorithmName hashAlgorithm,
+ byte[] hmacKey,
+ ReadOnlySpan<byte> secretPrepend,
+ ReadOnlySpan<byte> secretAppend,
+ DeriveSecretAgreement deriveSecretAgreement)
+ {
+ Debug.Assert(otherPartyPublicKey != null);
+ Debug.Assert(!string.IsNullOrEmpty(hashAlgorithm.Name));
+
+ // If an hmac key is provided then calculate
+ // HMAC(hmacKey, prepend || derived || append)
+ //
+ // Otherwise, calculate
+ // HMAC(derived, prepend || derived || append)
+
+ bool useSecretAsKey = hmacKey == null;
+
+ if (useSecretAsKey)
+ {
+ hmacKey = deriveSecretAgreement(otherPartyPublicKey, null);
+ Debug.Assert(hmacKey != null);
+ }
+
+ // Reduce the likelihood of the value getting copied during heap compaction.
+ fixed (byte* pinnedHmacKey = hmacKey)
+ {
+ try
+ {
+ using (IncrementalHash hash = IncrementalHash.CreateHMAC(hashAlgorithm, hmacKey))
+ {
+ hash.AppendData(secretPrepend);
+
+ if (useSecretAsKey)
+ {
+ hash.AppendData(hmacKey);
+ }
+ else
+ {
+ byte[] secretAgreement = deriveSecretAgreement(otherPartyPublicKey, hash);
+ // We want the side effect, and it should not have returned the answer.
+ Debug.Assert(secretAgreement == null);
+ }
+
+ hash.AppendData(secretAppend);
+ return hash.GetHashAndReset();
+ }
+ }
+ finally
+ {
+ // If useSecretAsKey is false then hmacKey is owned by the caller, not ours to clear.
+ if (useSecretAsKey)
+ {
+ Array.Clear(hmacKey, 0, hmacKey.Length);
+ }
+ }
+ }
+ }
+
+ internal static unsafe byte[] DeriveKeyTls(
+ ECDiffieHellmanPublicKey otherPartyPublicKey,
+ ReadOnlySpan<byte> prfLabel,
+ ReadOnlySpan<byte> prfSeed,
+ DeriveSecretAgreement deriveSecretAgreement)
+ {
+ Debug.Assert(otherPartyPublicKey != null);
+
+ if (prfSeed.Length != 64)
+ {
+ throw new CryptographicException(SR.Cryptography_TlsRequires64ByteSeed);
+ }
+
+ // Windows produces a 48-byte output, so that's what we do, too.
+ byte[] ret = new byte[48];
+
+ const int Sha1Size = 20;
+ const int Md5Size = 16;
+
+ byte[] secretAgreement = deriveSecretAgreement(otherPartyPublicKey, null);
+ Debug.Assert(secretAgreement != null);
+
+ // Reduce the likelihood of the value getting copied during heap compaction.
+ fixed (byte* pinnedSecretAgreement = secretAgreement)
+ {
+ try
+ {
+ // https://tools.ietf.org/html/rfc4346#section-5
+ //
+ // S1 and S2 are the two halves of the secret, and each is the same
+ // length. S1 is taken from the first half of the secret, S2 from the
+ // second half. Their length is created by rounding up the length of
+ // the overall secret, divided by two; thus, if the original secret is
+ // an odd number of bytes long, the last byte of S1 will be the same as
+ // the first byte of S2.
+ //
+ int half = secretAgreement.Length / 2;
+ int odd = secretAgreement.Length & 1;
+
+ // PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR
+ // P_SHA-1(S2, label + seed);
+
+ PHash(
+ HashAlgorithmName.MD5,
+ new ReadOnlySpan<byte>(secretAgreement, 0, half + odd),
+ prfLabel,
+ prfSeed,
+ Md5Size,
+ ret);
+
+ Span<byte> part2 = stackalloc byte[ret.Length];
+
+ PHash(
+ HashAlgorithmName.SHA1,
+ new ReadOnlySpan<byte>(secretAgreement, half, half + odd),
+ prfLabel,
+ prfSeed,
+ Sha1Size,
+ part2);
+
+ for (int i = 0; i < ret.Length; i++)
+ {
+ ret[i] ^= part2[i];
+ }
+
+ return ret;
+ }
+ finally
+ {
+ Array.Clear(secretAgreement, 0, secretAgreement.Length);
+ }
+ }
+ }
+
+ private static unsafe void PHash(
+ HashAlgorithmName algorithmName,
+ ReadOnlySpan<byte> secret,
+ ReadOnlySpan<byte> prfLabel,
+ ReadOnlySpan<byte> prfSeed,
+ int hashOutputSize,
+ Span<byte> ret)
+ {
+ // https://tools.ietf.org/html/rfc4346#section-5
+ //
+ // P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
+ // HMAC_hash(secret, A(2) + seed) +
+ // HMAC_hash(secret, A(3) + seed) + ...
+ //
+ // A(0) = seed
+ // A(i) = HMAC_hash(secret, A(i-1))
+ //
+ // This is called via PRF, which turns (label || seed) into seed.
+
+ byte[] secretTmp = new byte[secret.Length];
+
+ // Keep secretTmp pinned the whole time it has a secret in it, so it
+ // doesn't get copied around during heap compaction.
+ fixed (byte* pinnedSecretTmp = secretTmp)
+ {
+ secret.CopyTo(secretTmp);
+
+ try
+ {
+ Span<byte> retSpan = ret;
+
+ using (IncrementalHash hasher = IncrementalHash.CreateHMAC(algorithmName, secretTmp))
+ {
+ Span<byte> a = stackalloc byte[hashOutputSize];
+ Span<byte> p = stackalloc byte[hashOutputSize];
+
+ // A(1)
+ hasher.AppendData(prfLabel);
+ hasher.AppendData(prfSeed);
+
+ if (!hasher.TryGetHashAndReset(a, out int bytesWritten) || bytesWritten != hashOutputSize)
+ {
+ throw new CryptographicException();
+ }
+
+ while (true)
+ {
+ // HMAC_hash(secret, A(i) || seed) => p
+ hasher.AppendData(a);
+ hasher.AppendData(prfLabel);
+ hasher.AppendData(prfSeed);
+
+ if (!hasher.TryGetHashAndReset(p, out bytesWritten) || bytesWritten != hashOutputSize)
+ {
+ throw new CryptographicException();
+ }
+
+ int len = Math.Min(p.Length, retSpan.Length);
+
+ p.Slice(0, len).CopyTo(retSpan);
+ retSpan = retSpan.Slice(len);
+
+ if (retSpan.Length == 0)
+ {
+ return;
+ }
+
+ // Build the next A(i)
+ hasher.AppendData(a);
+
+ if (!hasher.TryGetHashAndReset(a, out bytesWritten) || bytesWritten != hashOutputSize)
+ {
+ throw new CryptographicException();
+ }
+ }
+ }
+ }
+ finally
+ {
+ Array.Clear(secretTmp, 0, secretTmp.Length);
+ }
+ }
+ }
+ }
+}
diff --git a/src/Common/src/System/Security/Cryptography/ECDiffieHellmanOpenSsl.Derive.cs b/src/Common/src/System/Security/Cryptography/ECDiffieHellmanOpenSsl.Derive.cs
new file mode 100644
index 0000000000..6426aefc69
--- /dev/null
+++ b/src/Common/src/System/Security/Cryptography/ECDiffieHellmanOpenSsl.Derive.cs
@@ -0,0 +1,202 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Diagnostics;
+using Microsoft.Win32.SafeHandles;
+
+namespace System.Security.Cryptography
+{
+#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS
+ internal static partial class ECDiffieHellmanImplementation
+ {
+#endif
+ public sealed partial class ECDiffieHellmanOpenSsl : ECDiffieHellman
+ {
+ /// <summary>
+ /// Given a second party's public key, derive shared key material
+ /// </summary>
+ public override byte[] DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey) =>
+ DeriveKeyFromHash(otherPartyPublicKey, HashAlgorithmName.SHA256, null, null);
+
+ public override byte[] DeriveKeyFromHash(
+ ECDiffieHellmanPublicKey otherPartyPublicKey,
+ HashAlgorithmName hashAlgorithm,
+ byte[] secretPrepend,
+ byte[] secretAppend)
+ {
+ if (otherPartyPublicKey == null)
+ throw new ArgumentNullException(nameof(otherPartyPublicKey));
+ if (string.IsNullOrEmpty(hashAlgorithm.Name))
+ throw new ArgumentException(SR.Cryptography_HashAlgorithmNameNullOrEmpty, nameof(hashAlgorithm));
+
+ return ECDiffieHellmanDerivation.DeriveKeyFromHash(
+ otherPartyPublicKey,
+ hashAlgorithm,
+ secretPrepend,
+ secretAppend,
+ (pubKey, hasher) => DeriveSecretAgreement(pubKey, hasher));
+ }
+
+ public override byte[] DeriveKeyFromHmac(
+ ECDiffieHellmanPublicKey otherPartyPublicKey,
+ HashAlgorithmName hashAlgorithm,
+ byte[] hmacKey,
+ byte[] secretPrepend,
+ byte[] secretAppend)
+ {
+ if (otherPartyPublicKey == null)
+ throw new ArgumentNullException(nameof(otherPartyPublicKey));
+ if (string.IsNullOrEmpty(hashAlgorithm.Name))
+ throw new ArgumentException(SR.Cryptography_HashAlgorithmNameNullOrEmpty, nameof(hashAlgorithm));
+
+ return ECDiffieHellmanDerivation.DeriveKeyFromHmac(
+ otherPartyPublicKey,
+ hashAlgorithm,
+ hmacKey,
+ secretPrepend,
+ secretAppend,
+ (pubKey, hasher) => DeriveSecretAgreement(pubKey, hasher));
+ }
+
+ public override byte[] DeriveKeyTls(ECDiffieHellmanPublicKey otherPartyPublicKey, byte[] prfLabel, byte[] prfSeed)
+ {
+ if (otherPartyPublicKey == null)
+ throw new ArgumentNullException(nameof(otherPartyPublicKey));
+ if (prfLabel == null)
+ throw new ArgumentNullException(nameof(prfLabel));
+ if (prfSeed == null)
+ throw new ArgumentNullException(nameof(prfSeed));
+
+ return ECDiffieHellmanDerivation.DeriveKeyTls(
+ otherPartyPublicKey,
+ prfLabel,
+ prfSeed,
+ (pubKey, hasher) => DeriveSecretAgreement(pubKey, hasher));
+ }
+
+ /// <summary>
+ /// Get the secret agreement generated between two parties
+ /// </summary>
+ private byte[] DeriveSecretAgreement(ECDiffieHellmanPublicKey otherPartyPublicKey, IncrementalHash hasher)
+ {
+ Debug.Assert(otherPartyPublicKey != null);
+
+ // Ensure that this ECDH object contains a private key by attempting a parameter export
+ // which will throw an OpenSslCryptoException if no private key is available
+ ECParameters thisKeyExplicit = ExportExplicitParameters(true);
+ bool thisIsNamed = Interop.Crypto.EcKeyHasCurveName(_key.Value);
+ ECDiffieHellmanOpenSslPublicKey otherKey = otherPartyPublicKey as ECDiffieHellmanOpenSslPublicKey;
+ bool disposeOtherKey = false;
+
+ if (otherKey == null)
+ {
+ disposeOtherKey = true;
+
+ ECParameters otherParameters =
+ thisIsNamed
+ ? otherPartyPublicKey.ExportParameters()
+ : otherPartyPublicKey.ExportExplicitParameters();
+
+ otherKey = new ECDiffieHellmanOpenSslPublicKey(otherParameters);
+ }
+
+ bool otherIsNamed = otherKey.HasCurveName;
+
+ SafeEvpPKeyHandle ourKey = null;
+ SafeEvpPKeyHandle theirKey = null;
+ byte[] rented = null;
+ int secretLength = 0;
+
+ try
+ {
+ if (otherKey.KeySize != KeySize)
+ {
+ throw new ArgumentException(SR.Cryptography_ArgECDHKeySizeMismatch, nameof(otherPartyPublicKey));
+ }
+
+ if (otherIsNamed == thisIsNamed)
+ {
+ ourKey = _key.UpRefKeyHandle();
+ theirKey = otherKey.DuplicateKeyHandle();
+ }
+ else if (otherIsNamed)
+ {
+ ourKey = _key.UpRefKeyHandle();
+
+ using (ECOpenSsl tmp = new ECOpenSsl(otherKey.ExportExplicitParameters()))
+ {
+ theirKey = tmp.UpRefKeyHandle();
+ }
+ }
+ else
+ {
+ using (ECOpenSsl tmp = new ECOpenSsl(thisKeyExplicit))
+ {
+ ourKey = tmp.UpRefKeyHandle();
+ }
+
+ theirKey = otherKey.DuplicateKeyHandle();
+ }
+
+ using (SafeEvpPKeyCtxHandle ctx = Interop.Crypto.EvpPKeyCtxCreate(ourKey, theirKey, out uint secretLengthU))
+ {
+ if (ctx == null || ctx.IsInvalid || secretLengthU == 0 || secretLengthU > int.MaxValue)
+ {
+ throw Interop.Crypto.CreateOpenSslCryptographicException();
+ }
+
+ secretLength = (int)secretLengthU;
+
+ // Indicate that secret can hold stackallocs from nested scopes
+ Span<byte> secret = stackalloc byte[0];
+
+ // Arbitrary limit. But it covers secp521r1, which is the biggest common case.
+ const int StackAllocMax = 66;
+
+ if (secretLength > StackAllocMax)
+ {
+ rented = ArrayPool<byte>.Shared.Rent(secretLength);
+ secret = new Span<byte>(rented, 0, secretLength);
+ }
+ else
+ {
+ secret = stackalloc byte[secretLength];
+ }
+
+ Interop.Crypto.EvpPKeyDeriveSecretAgreement(ctx, secret);
+
+ if (hasher == null)
+ {
+ return secret.ToArray();
+ }
+ else
+ {
+ hasher.AppendData(secret);
+ return null;
+ }
+ }
+ }
+ finally
+ {
+ theirKey?.Dispose();
+ ourKey?.Dispose();
+
+ if (disposeOtherKey)
+ {
+ otherKey.Dispose();
+ }
+
+ if (rented != null)
+ {
+ Array.Clear(rented, 0, secretLength);
+ ArrayPool<byte>.Shared.Return(rented);
+ }
+ }
+ }
+ }
+#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS
+ }
+#endif
+}
diff --git a/src/Common/src/System/Security/Cryptography/ECDiffieHellmanOpenSsl.cs b/src/Common/src/System/Security/Cryptography/ECDiffieHellmanOpenSsl.cs
new file mode 100644
index 0000000000..bf007e647c
--- /dev/null
+++ b/src/Common/src/System/Security/Cryptography/ECDiffieHellmanOpenSsl.cs
@@ -0,0 +1,90 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Security.Cryptography
+{
+#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS
+ internal static partial class ECDiffieHellmanImplementation
+ {
+#endif
+ public sealed partial class ECDiffieHellmanOpenSsl : ECDiffieHellman
+ {
+ private ECOpenSsl _key;
+
+ public ECDiffieHellmanOpenSsl(ECCurve curve)
+ {
+ _key = new ECOpenSsl(curve);
+ KeySizeValue = _key.KeySize;
+ }
+
+ public ECDiffieHellmanOpenSsl()
+ : this(521)
+ {
+ }
+
+ public ECDiffieHellmanOpenSsl(int keySize)
+ {
+ base.KeySize = keySize;
+ _key = new ECOpenSsl(this);
+ }
+
+ public override KeySizes[] LegalKeySizes =>
+ new[] {
+ new KeySizes(minSize: 256, maxSize: 384, skipSize: 128),
+ new KeySizes(minSize: 521, maxSize: 521, skipSize: 0)
+ };
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _key.Dispose();
+ }
+
+ base.Dispose(disposing);
+ }
+
+ public override int KeySize
+ {
+ get
+ {
+ return base.KeySize;
+ }
+ set
+ {
+ if (KeySize == value)
+ {
+ return;
+ }
+
+ // Set the KeySize before FreeKey so that an invalid value doesn't throw away the key
+ base.KeySize = value;
+ _key?.Dispose();
+ _key = new ECOpenSsl(this);
+ }
+ }
+
+ public override void GenerateKey(ECCurve curve)
+ {
+ KeySizeValue = _key.GenerateKey(curve);
+ }
+
+ public override ECDiffieHellmanPublicKey PublicKey =>
+ new ECDiffieHellmanOpenSslPublicKey(_key.UpRefKeyHandle());
+
+ public override void ImportParameters(ECParameters parameters)
+ {
+ KeySizeValue = _key.ImportParameters(parameters);
+ }
+
+ public override ECParameters ExportExplicitParameters(bool includePrivateParameters) =>
+ ECOpenSsl.ExportExplicitParameters(_key.Value, includePrivateParameters);
+
+ public override ECParameters ExportParameters(bool includePrivateParameters) =>
+ ECOpenSsl.ExportParameters(_key.Value, includePrivateParameters);
+ }
+#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS
+ }
+#endif
+}
diff --git a/src/Common/src/System/Security/Cryptography/ECDiffieHellmanOpenSslPublicKey.cs b/src/Common/src/System/Security/Cryptography/ECDiffieHellmanOpenSslPublicKey.cs
new file mode 100644
index 0000000000..5ecc47f6e7
--- /dev/null
+++ b/src/Common/src/System/Security/Cryptography/ECDiffieHellmanOpenSslPublicKey.cs
@@ -0,0 +1,98 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.Win32.SafeHandles;
+
+namespace System.Security.Cryptography
+{
+#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS
+ internal static partial class ECDiffieHellmanImplementation
+ {
+#endif
+ internal sealed class ECDiffieHellmanOpenSslPublicKey : ECDiffieHellmanPublicKey
+ {
+ private readonly ECOpenSsl _key;
+
+ internal ECDiffieHellmanOpenSslPublicKey(SafeEvpPKeyHandle pkeyHandle)
+ {
+ if (pkeyHandle == null)
+ throw new ArgumentNullException(nameof(pkeyHandle));
+ if (pkeyHandle.IsInvalid)
+ throw new ArgumentException(SR.Cryptography_OpenInvalidHandle, nameof(pkeyHandle));
+
+ // If ecKey is valid it has already been up-ref'd, so we can just use this handle as-is.
+ SafeEcKeyHandle key = Interop.Crypto.EvpPkeyGetEcKey(pkeyHandle);
+
+ if (key.IsInvalid)
+ {
+ key.Dispose();
+ throw Interop.Crypto.CreateOpenSslCryptographicException();
+ }
+
+ _key = new ECOpenSsl(key);
+ }
+
+ internal ECDiffieHellmanOpenSslPublicKey(ECParameters parameters)
+ {
+ _key = new ECOpenSsl(parameters);
+ }
+
+ public override string ToXmlString()
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ public override byte[] ToByteArray()
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ public override ECParameters ExportExplicitParameters() =>
+ ECOpenSsl.ExportExplicitParameters(_key.Value, includePrivateParameters: false);
+
+ public override ECParameters ExportParameters() =>
+ ECOpenSsl.ExportParameters(_key.Value, includePrivateParameters: false);
+
+ internal bool HasCurveName => Interop.Crypto.EcKeyHasCurveName(_key.Value);
+
+ internal int KeySize => _key.KeySize;
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _key?.Dispose();
+ }
+
+ base.Dispose(disposing);
+ }
+
+ internal SafeEvpPKeyHandle DuplicateKeyHandle()
+ {
+ SafeEcKeyHandle currentKey = _key.Value;
+ SafeEvpPKeyHandle pkeyHandle = Interop.Crypto.EvpPkeyCreate();
+
+ try
+ {
+ // Wrapping our key in an EVP_PKEY will up_ref our key.
+ // When the EVP_PKEY is Disposed it will down_ref the key.
+ // So everything should be copacetic.
+ if (!Interop.Crypto.EvpPkeySetEcKey(pkeyHandle, currentKey))
+ {
+ throw Interop.Crypto.CreateOpenSslCryptographicException();
+ }
+
+ return pkeyHandle;
+ }
+ catch
+ {
+ pkeyHandle.Dispose();
+ throw;
+ }
+ }
+ }
+#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS
+ }
+#endif
+}
diff --git a/src/Common/src/System/Security/Cryptography/ECDiffieHellmanSecurityTransforms.cs b/src/Common/src/System/Security/Cryptography/ECDiffieHellmanSecurityTransforms.cs
new file mode 100644
index 0000000000..9b57522297
--- /dev/null
+++ b/src/Common/src/System/Security/Cryptography/ECDiffieHellmanSecurityTransforms.cs
@@ -0,0 +1,289 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Security.Cryptography.Apple;
+
+namespace System.Security.Cryptography
+{
+ internal static partial class ECDiffieHellmanImplementation
+ {
+ public sealed partial class ECDiffieHellmanSecurityTransforms : ECDiffieHellman
+ {
+ private readonly EccSecurityTransforms _ecc = new EccSecurityTransforms();
+
+ public ECDiffieHellmanSecurityTransforms()
+ {
+ KeySize = 521;
+ }
+
+ internal ECDiffieHellmanSecurityTransforms(SafeSecKeyRefHandle publicKey)
+ {
+ KeySizeValue = _ecc.SetKeyAndGetSize(SecKeyPair.PublicOnly(publicKey));
+ }
+
+ internal ECDiffieHellmanSecurityTransforms(SafeSecKeyRefHandle publicKey, SafeSecKeyRefHandle privateKey)
+ {
+ KeySizeValue = _ecc.SetKeyAndGetSize(SecKeyPair.PublicPrivatePair(publicKey, privateKey));
+ }
+
+ public override KeySizes[] LegalKeySizes
+ {
+ get
+ {
+ // Return the three sizes that can be explicitly set (for backwards compatibility)
+ return new[]
+ {
+ new KeySizes(minSize: 256, maxSize: 384, skipSize: 128),
+ new KeySizes(minSize: 521, maxSize: 521, skipSize: 0),
+ };
+ }
+ }
+
+ public override int KeySize
+ {
+ get { return base.KeySize; }
+ set
+ {
+ if (KeySize == value)
+ return;
+
+ // Set the KeySize before freeing the key so that an invalid value doesn't throw away the key
+ base.KeySize = value;
+ _ecc.Dispose();
+ }
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _ecc.Dispose();
+ }
+
+ base.Dispose(disposing);
+ }
+
+ public override ECParameters ExportExplicitParameters(bool includePrivateParameters)
+ {
+ throw new PlatformNotSupportedException(SR.Cryptography_ECC_NamedCurvesOnly);
+ }
+
+ public override ECParameters ExportParameters(bool includePrivateParameters)
+ {
+ return _ecc.ExportParameters(includePrivateParameters, KeySize);
+ }
+
+ public override void ImportParameters(ECParameters parameters)
+ {
+ KeySizeValue = _ecc.ImportParameters(parameters);
+ }
+
+ public override void GenerateKey(ECCurve curve)
+ {
+ KeySizeValue = _ecc.GenerateKey(curve);
+ }
+
+ private SecKeyPair GetKeys()
+ {
+ return _ecc.GetOrGenerateKeys(KeySize);
+ }
+
+ public override byte[] DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey) =>
+ DeriveKeyFromHash(otherPartyPublicKey, HashAlgorithmName.SHA256, null, null);
+
+ public override byte[] DeriveKeyFromHash(
+ ECDiffieHellmanPublicKey otherPartyPublicKey,
+ HashAlgorithmName hashAlgorithm,
+ byte[] secretPrepend,
+ byte[] secretAppend)
+ {
+ if (otherPartyPublicKey == null)
+ throw new ArgumentNullException(nameof(otherPartyPublicKey));
+ if (string.IsNullOrEmpty(hashAlgorithm.Name))
+ throw new ArgumentException(SR.Cryptography_HashAlgorithmNameNullOrEmpty, nameof(hashAlgorithm));
+
+ return ECDiffieHellmanDerivation.DeriveKeyFromHash(
+ otherPartyPublicKey,
+ hashAlgorithm,
+ secretPrepend,
+ secretAppend,
+ (pubKey, hasher) => DeriveSecretAgreement(pubKey, hasher));
+ }
+
+ public override byte[] DeriveKeyFromHmac(
+ ECDiffieHellmanPublicKey otherPartyPublicKey,
+ HashAlgorithmName hashAlgorithm,
+ byte[] hmacKey,
+ byte[] secretPrepend,
+ byte[] secretAppend)
+ {
+ if (otherPartyPublicKey == null)
+ throw new ArgumentNullException(nameof(otherPartyPublicKey));
+ if (string.IsNullOrEmpty(hashAlgorithm.Name))
+ throw new ArgumentException(SR.Cryptography_HashAlgorithmNameNullOrEmpty, nameof(hashAlgorithm));
+
+ return ECDiffieHellmanDerivation.DeriveKeyFromHmac(
+ otherPartyPublicKey,
+ hashAlgorithm,
+ hmacKey,
+ secretPrepend,
+ secretAppend,
+ (pubKey, hasher) => DeriveSecretAgreement(pubKey, hasher));
+ }
+
+ public override byte[] DeriveKeyTls(ECDiffieHellmanPublicKey otherPartyPublicKey, byte[] prfLabel,
+ byte[] prfSeed)
+ {
+ if (otherPartyPublicKey == null)
+ throw new ArgumentNullException(nameof(otherPartyPublicKey));
+ if (prfLabel == null)
+ throw new ArgumentNullException(nameof(prfLabel));
+ if (prfSeed == null)
+ throw new ArgumentNullException(nameof(prfSeed));
+
+ return ECDiffieHellmanDerivation.DeriveKeyTls(
+ otherPartyPublicKey,
+ prfLabel,
+ prfSeed,
+ (pubKey, hasher) => DeriveSecretAgreement(pubKey, hasher));
+ }
+
+ private byte[] DeriveSecretAgreement(ECDiffieHellmanPublicKey otherPartyPublicKey, IncrementalHash hasher)
+ {
+ if (!(otherPartyPublicKey is ECDiffieHellmanSecurityTransformsPublicKey secTransPubKey))
+ {
+ secTransPubKey =
+ new ECDiffieHellmanSecurityTransformsPublicKey(otherPartyPublicKey.ExportParameters());
+ }
+
+ try
+ {
+ SafeSecKeyRefHandle otherPublic = secTransPubKey.KeyHandle;
+
+ if (Interop.AppleCrypto.EccGetKeySizeInBits(otherPublic) != KeySize)
+ {
+ throw new ArgumentException(
+ SR.Cryptography_ArgECDHKeySizeMismatch,
+ nameof(otherPartyPublicKey));
+ }
+
+ SafeSecKeyRefHandle thisPrivate = GetKeys().PrivateKey;
+
+ if (thisPrivate == null)
+ {
+ throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey);
+ }
+
+ // Since Apple only supports secp256r1, secp384r1, and secp521r1; and 521 fits in
+ // 66 bytes ((521 + 7) / 8), the Span path will always succeed.
+ Span<byte> secretSpan = stackalloc byte[66];
+
+ byte[] secret = Interop.AppleCrypto.EcdhKeyAgree(
+ thisPrivate,
+ otherPublic,
+ secretSpan,
+ out int bytesWritten);
+
+ // Either we wrote to the span or we returned an array, but not both, and not neither.
+ // ("neither" would have thrown)
+ Debug.Assert(
+ (bytesWritten == 0) != (secret == null),
+ $"bytesWritten={bytesWritten}, (secret==null)={secret == null}");
+
+ if (hasher == null)
+ {
+ return secret ?? secretSpan.Slice(0, bytesWritten).ToArray();
+ }
+
+ if (secret == null)
+ {
+ hasher.AppendData(secretSpan.Slice(0, bytesWritten));
+ }
+ else
+ {
+ hasher.AppendData(secret);
+ Array.Clear(secret, 0, secret.Length);
+ }
+
+ return null;
+ }
+ finally
+ {
+ if (!ReferenceEquals(otherPartyPublicKey, secTransPubKey))
+ {
+ secTransPubKey.Dispose();
+ }
+ }
+ }
+
+ public override ECDiffieHellmanPublicKey PublicKey =>
+ new ECDiffieHellmanSecurityTransformsPublicKey(ExportParameters(false));
+
+ private class ECDiffieHellmanSecurityTransformsPublicKey : ECDiffieHellmanPublicKey
+ {
+ private EccSecurityTransforms _ecc;
+
+ public ECDiffieHellmanSecurityTransformsPublicKey(ECParameters ecParameters)
+ {
+ Debug.Assert(ecParameters.D == null);
+ _ecc = new EccSecurityTransforms();
+ _ecc.ImportParameters(ecParameters);
+ }
+
+ public override string ToXmlString()
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ /// <summary>
+ /// There is no key blob format for OpenSSL ECDH like there is for Cng ECDH. Instead of allowing
+ /// this to return a potentially confusing empty byte array, we opt to throw instead.
+ /// </summary>
+ public override byte[] ToByteArray()
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _ecc.Dispose();
+ _ecc = null;
+ }
+
+ base.Dispose(disposing);
+ }
+
+ public override ECParameters ExportExplicitParameters() =>
+ throw new PlatformNotSupportedException(SR.Cryptography_ECC_NamedCurvesOnly);
+
+ public override ECParameters ExportParameters()
+ {
+ if (_ecc == null)
+ {
+ throw new ObjectDisposedException(typeof(ECDiffieHellmanSecurityTransformsPublicKey).Name);
+ }
+
+ return _ecc.ExportParameters(includePrivateParameters: false, keySizeInBIts: -1);
+ }
+
+ internal SafeSecKeyRefHandle KeyHandle
+ {
+ get
+ {
+ if (_ecc == null)
+ {
+ throw new ObjectDisposedException(
+ typeof(ECDiffieHellmanSecurityTransformsPublicKey).Name);
+ }
+
+ return _ecc.GetOrGenerateKeys(-1).PublicKey;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/Common/src/System/Security/Cryptography/ECDsaCng.ImportExport.cs b/src/Common/src/System/Security/Cryptography/ECDsaCng.ImportExport.cs
index b93cb608a7..1083ccca17 100644
--- a/src/Common/src/System/Security/Cryptography/ECDsaCng.ImportExport.cs
+++ b/src/Common/src/System/Security/Cryptography/ECDsaCng.ImportExport.cs
@@ -29,12 +29,12 @@ namespace System.Security.Cryptography
{
parameters.Validate();
ECCurve curve = parameters.Curve;
- bool includePrivateParamerters = (parameters.D != null);
+ bool includePrivateParameters = (parameters.D != null);
if (curve.IsPrime)
{
- byte[] ecExplicitBlob = ECCng.GetPrimeCurveBlob(ref parameters);
- ImportFullKeyBlob(ecExplicitBlob, includePrivateParamerters);
+ byte[] ecExplicitBlob = ECCng.GetPrimeCurveBlob(ref parameters, ecdh: false);
+ ImportFullKeyBlob(ecExplicitBlob, includePrivateParameters);
}
else if (curve.IsNamed)
{
@@ -42,8 +42,8 @@ namespace System.Security.Cryptography
if (string.IsNullOrEmpty(curve.Oid.FriendlyName))
throw new PlatformNotSupportedException(string.Format(SR.Cryptography_InvalidCurveOid, curve.Oid.Value.ToString()));
- byte[] ecNamedCurveBlob = ECCng.GetNamedCurveBlob(ref parameters);
- ImportKeyBlob(ecNamedCurveBlob, curve.Oid.FriendlyName, includePrivateParamerters);
+ byte[] ecNamedCurveBlob = ECCng.GetNamedCurveBlob(ref parameters, ecdh: false);
+ ImportKeyBlob(ecNamedCurveBlob, curve.Oid.FriendlyName, includePrivateParameters);
}
else
{
diff --git a/src/Common/src/System/Security/Cryptography/ECDsaCng.cs b/src/Common/src/System/Security/Cryptography/ECDsaCng.cs
index 1969dbd7fb..a6da8c2755 100644
--- a/src/Common/src/System/Security/Cryptography/ECDsaCng.cs
+++ b/src/Common/src/System/Security/Cryptography/ECDsaCng.cs
@@ -89,42 +89,6 @@ namespace System.Security.Cryptography
};
}
}
-
- /// <summary>
- /// Is the curve named, or once of the special nist curves
- /// </summary>
- internal static bool IsECNamedCurve(string algorithm)
- {
- return (algorithm == AlgorithmName.ECDH ||
- algorithm == AlgorithmName.ECDsa);
- }
-
- /// <summary>
- /// Maps algorithm to curve name accounting for the special nist curves
- /// </summary>
- internal static string SpecialNistAlgorithmToCurveName(string algorithm)
- {
- if (algorithm == AlgorithmName.ECDHP256 ||
- algorithm == AlgorithmName.ECDsaP256)
- {
- return "nistP256";
- }
-
- if (algorithm == AlgorithmName.ECDHP384 ||
- algorithm == AlgorithmName.ECDsaP384)
- {
- return "nistP384";
- }
-
- if (algorithm == AlgorithmName.ECDHP521 ||
- algorithm == AlgorithmName.ECDsaP521)
- {
- return "nistP521";
- }
-
- Debug.Fail(string.Format("Unknown curve {0}", algorithm));
- throw new PlatformNotSupportedException(string.Format(SR.Cryptography_CurveNotSupported, algorithm));
- }
}
#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS
}
diff --git a/src/Common/src/System/Security/Cryptography/ECDsaOpenSsl.ImportExport.cs b/src/Common/src/System/Security/Cryptography/ECDsaOpenSsl.ImportExport.cs
deleted file mode 100644
index 4dd9ac4b68..0000000000
--- a/src/Common/src/System/Security/Cryptography/ECDsaOpenSsl.ImportExport.cs
+++ /dev/null
@@ -1,204 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using Microsoft.Win32.SafeHandles;
-using System.Diagnostics;
-
-namespace System.Security.Cryptography
-{
-#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS
- internal static partial class ECDsaImplementation
- {
-#endif
- public sealed partial class ECDsaOpenSsl : ECDsa
- {
- /// <summary>
- /// ImportParameters will replace the existing key that ECDsaOpenSsl is working with by creating a
- /// new key. If the parameters contains only Q, then only a public key will be imported.
- /// If the parameters also contains D, then a full key pair will be imported.
- /// The parameters Curve value specifies the type of the curve to import.
- /// </summary>
- /// <param name="parameters">The curve parameters.</param>
- /// <exception cref="CryptographicException">
- /// if <paramref name="parameters" /> does not contain valid values.
- /// </exception>
- /// <exception cref="NotSupportedException">
- /// if <paramref name="parameters" /> references a curve that cannot be imported.
- /// </exception>
- /// <exception cref="PlatformNotSupportedException">
- /// if <paramref name="parameters" /> references a curve that is not supported by this platform.
- /// </exception>
- public override void ImportParameters(ECParameters parameters)
- {
- SafeEcKeyHandle key;
-
- parameters.Validate();
-
- if (parameters.Curve.IsPrime)
- {
- key = ImportPrimeCurveParameters(parameters);
- }
- else if (parameters.Curve.IsCharacteristic2)
- {
- key = ImportCharacteristic2CurveParameters(parameters);
- }
- else if (parameters.Curve.IsNamed)
- {
- key = ImportNamedCurveParameters(parameters);
- }
- else
- {
- throw new PlatformNotSupportedException(string.Format(SR.Cryptography_CurveNotSupported, parameters.Curve.CurveType.ToString()));
- }
-
- if (key == null || key.IsInvalid)
- throw Interop.Crypto.CreateOpenSslCryptographicException();
-
- SetKey(key);
- }
-
- /// <summary>
- /// Exports the key and explicit curve parameters used by the ECC object into an <see cref="ECParameters"/> object.
- /// </summary>
- /// <exception cref="CryptographicException">
- /// if there was an issue obtaining the curve values.
- /// </exception>
- /// <returns>The key and explicit curve parameters used by the ECC object.</returns>
- public override ECParameters ExportExplicitParameters(bool includePrivateParameters)
- {
- // It's entirely possible that this line will cause the key to be generated in the first place.
- SafeEcKeyHandle currentKey = _key.Value;
-
- ECParameters ecparams = ExportExplicitCurveParameters(currentKey, includePrivateParameters);
- return ecparams;
- }
-
- /// <summary>
- /// Exports the key used by the ECC object into an <see cref="ECParameters"/> object.
- /// If the curve has a name, the Curve property will contain named curve parameters otherwise it will contain explicit parameters.
- /// </summary>
- /// <exception cref="CryptographicException">
- /// if there was an issue obtaining the curve values.
- /// </exception>
- /// <returns>The key and named curve parameters used by the ECC object.</returns>
- public override ECParameters ExportParameters(bool includePrivateParameters)
- {
- // It's entirely possible that this line will cause the key to be generated in the first place.
- SafeEcKeyHandle currentKey = _key.Value;
-
- ECParameters ecparams;
- if (Interop.Crypto.EcKeyHasCurveName(currentKey))
- {
- ecparams = ExportNamedCurveParameters(currentKey, includePrivateParameters);
- }
- else
- {
- ecparams = ExportExplicitCurveParameters(currentKey, includePrivateParameters);
- }
- return ecparams;
- }
-
- private static ECParameters ExportNamedCurveParameters(SafeEcKeyHandle key, bool includePrivateParameters)
- {
- CheckInvalidKey(key);
-
- ECParameters parameters = Interop.Crypto.GetECKeyParameters(key, includePrivateParameters);
-
- bool hasPrivateKey = (parameters.D != null);
- if (hasPrivateKey != includePrivateParameters)
- {
- throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey);
- }
-
- // Assign Curve
- string keyOidValueName = Interop.Crypto.EcKeyGetCurveName(key);
- parameters.Curve = ECCurve.CreateFromValue(keyOidValueName);
-
- return parameters;
- }
-
- private static ECParameters ExportExplicitCurveParameters(SafeEcKeyHandle key, bool includePrivateParameters)
- {
- CheckInvalidKey(key);
-
- ECParameters parameters = Interop.Crypto.GetECCurveParameters(key, includePrivateParameters);
-
- bool hasPrivateKey = (parameters.D != null);
- if (hasPrivateKey != includePrivateParameters)
- {
- throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey);
- }
-
- return parameters;
- }
-
- private static SafeEcKeyHandle ImportNamedCurveParameters(ECParameters parameters)
- {
- Debug.Assert(parameters.Curve.IsNamed);
-
- // Use oid Value first if present, otherwise FriendlyName
- string oid = !string.IsNullOrEmpty(parameters.Curve.Oid.Value) ?
- parameters.Curve.Oid.Value : parameters.Curve.Oid.FriendlyName;
-
- SafeEcKeyHandle key = Interop.Crypto.EcKeyCreateByKeyParameters(
- oid,
- parameters.Q.X, parameters.Q.X.Length,
- parameters.Q.Y, parameters.Q.Y.Length,
- parameters.D, parameters.D == null ? 0 : parameters.D.Length);
-
- return key;
- }
-
- private static SafeEcKeyHandle ImportPrimeCurveParameters(ECParameters parameters)
- {
- Debug.Assert(parameters.Curve.IsPrime);
- SafeEcKeyHandle key = Interop.Crypto.EcKeyCreateByExplicitParameters(
- parameters.Curve.CurveType,
- parameters.Q.X, parameters.Q.X.Length,
- parameters.Q.Y, parameters.Q.Y.Length,
- parameters.D, parameters.D == null ? 0 : parameters.D.Length,
- parameters.Curve.Prime, parameters.Curve.Prime.Length,
- parameters.Curve.A, parameters.Curve.A.Length,
- parameters.Curve.B, parameters.Curve.B.Length,
- parameters.Curve.G.X, parameters.Curve.G.X.Length,
- parameters.Curve.G.Y, parameters.Curve.G.Y.Length,
- parameters.Curve.Order, parameters.Curve.Order.Length,
- parameters.Curve.Cofactor, parameters.Curve.Cofactor.Length,
- parameters.Curve.Seed, parameters.Curve.Seed == null ? 0 : parameters.Curve.Seed.Length);
-
- return key;
- }
-
- private static SafeEcKeyHandle ImportCharacteristic2CurveParameters(ECParameters parameters)
- {
- Debug.Assert(parameters.Curve.IsCharacteristic2);
- SafeEcKeyHandle key = Interop.Crypto.EcKeyCreateByExplicitParameters(
- parameters.Curve.CurveType,
- parameters.Q.X, parameters.Q.X.Length,
- parameters.Q.Y, parameters.Q.Y.Length,
- parameters.D, parameters.D == null ? 0 : parameters.D.Length,
- parameters.Curve.Polynomial, parameters.Curve.Polynomial.Length,
- parameters.Curve.A, parameters.Curve.A.Length,
- parameters.Curve.B, parameters.Curve.B.Length,
- parameters.Curve.G.X, parameters.Curve.G.X.Length,
- parameters.Curve.G.Y, parameters.Curve.G.Y.Length,
- parameters.Curve.Order, parameters.Curve.Order.Length,
- parameters.Curve.Cofactor, parameters.Curve.Cofactor.Length,
- parameters.Curve.Seed, parameters.Curve.Seed == null ? 0 : parameters.Curve.Seed.Length);
-
- return key;
- }
-
- private static void CheckInvalidKey(SafeEcKeyHandle key)
- {
- if (key == null || key.IsInvalid)
- {
- throw new CryptographicException(SR.Cryptography_OpenInvalidHandle);
- }
- }
- }
-#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS
- }
-#endif
-}
diff --git a/src/Common/src/System/Security/Cryptography/ECDsaOpenSsl.cs b/src/Common/src/System/Security/Cryptography/ECDsaOpenSsl.cs
index 1f490ce6e3..fda44274c7 100644
--- a/src/Common/src/System/Security/Cryptography/ECDsaOpenSsl.cs
+++ b/src/Common/src/System/Security/Cryptography/ECDsaOpenSsl.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Buffers;
+using System.Diagnostics;
using System.IO;
using Internal.Cryptography;
using Microsoft.Win32.SafeHandles;
@@ -15,11 +16,7 @@ namespace System.Security.Cryptography
#endif
public sealed partial class ECDsaOpenSsl : ECDsa
{
- internal const string ECDSA_P256_OID_VALUE = "1.2.840.10045.3.1.7"; // Also called nistP256 or secP256r1
- internal const string ECDSA_P384_OID_VALUE = "1.3.132.0.34"; // Also called nistP384 or secP384r1
- internal const string ECDSA_P521_OID_VALUE = "1.3.132.0.35"; // Also called nistP521or secP521r1
-
- private Lazy<SafeEcKeyHandle> _key;
+ private ECOpenSsl _key;
/// <summary>
/// Create an ECDsaOpenSsl algorithm with a named curve.
@@ -28,7 +25,8 @@ namespace System.Security.Cryptography
/// <exception cref="ArgumentNullException">if <paramref name="curve" /> is null.</exception>
public ECDsaOpenSsl(ECCurve curve)
{
- GenerateKey(curve);
+ _key = new ECOpenSsl(curve);
+ ForceSetKeySize(_key.KeySize);
}
/// <summary>
@@ -46,6 +44,8 @@ namespace System.Security.Cryptography
public ECDsaOpenSsl(int keySize)
{
KeySize = keySize;
+ // Setting KeySize wakes up _key.
+ Debug.Assert(_key != null);
}
/// <summary>
@@ -89,7 +89,7 @@ namespace System.Security.Cryptography
return converted;
}
- public override bool TrySignHash(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten)
+ public override bool TrySignHash(ReadOnlySpan<byte> hash, Span<byte> destination, out int bytesWritten)
{
SafeEcKeyHandle key = _key.Value;
@@ -98,7 +98,7 @@ namespace System.Security.Cryptography
byte[] signature = ArrayPool<byte>.Shared.Rent(signatureLength);
try
{
- if (!Interop.Crypto.EcDsaSign(source, source.Length, new Span<byte>(signature, 0, signatureLength), ref signatureLength, key))
+ if (!Interop.Crypto.EcDsaSign(hash, hash.Length, new Span<byte>(signature, 0, signatureLength), ref signatureLength, key))
{
throw Interop.Crypto.CreateOpenSslCryptographicException();
}
@@ -159,14 +159,14 @@ namespace System.Security.Cryptography
protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) =>
AsymmetricAlgorithmHelpers.HashData(data, hashAlgorithm);
- protected override bool TryHashData(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) =>
- AsymmetricAlgorithmHelpers.TryHashData(source, destination, hashAlgorithm, out bytesWritten);
+ protected override bool TryHashData(ReadOnlySpan<byte> data, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) =>
+ AsymmetricAlgorithmHelpers.TryHashData(data, destination, hashAlgorithm, out bytesWritten);
protected override void Dispose(bool disposing)
{
if (disposing)
{
- FreeKey();
+ _key.Dispose();
}
base.Dispose(disposing);
@@ -186,94 +186,34 @@ namespace System.Security.Cryptography
// Set the KeySize before FreeKey so that an invalid value doesn't throw away the key
base.KeySize = value;
- FreeKey();
- _key = new Lazy<SafeEcKeyHandle>(GenerateKeyLazy);
+ // This is the only place where _key can be null, because it's called by the constructor
+ // which sets KeySize.
+ _key?.Dispose();
+ _key = new ECOpenSsl(this);
}
}
public override void GenerateKey(ECCurve curve)
{
- curve.Validate();
- FreeKey();
-
- if (curve.IsNamed)
- {
- string oid = null;
- // Use oid Value first if present, otherwise FriendlyName because Oid maintains a hard-coded
- // cache that may have different casing for FriendlyNames than OpenSsl
- oid = !string.IsNullOrEmpty(curve.Oid.Value) ? curve.Oid.Value : curve.Oid.FriendlyName;
-
- SafeEcKeyHandle key = Interop.Crypto.EcKeyCreateByOid(oid);
-
- if (key == null || key.IsInvalid)
- throw new PlatformNotSupportedException(string.Format(SR.Cryptography_CurveNotSupported, oid));
-
- if (!Interop.Crypto.EcKeyGenerateKey(key))
- throw Interop.Crypto.CreateOpenSslCryptographicException();
-
- SetKey(key);
- }
- else if (curve.IsExplicit)
- {
- SafeEcKeyHandle key = Interop.Crypto.EcKeyCreateByExplicitCurve(curve);
-
- if (!Interop.Crypto.EcKeyGenerateKey(key))
- throw Interop.Crypto.CreateOpenSslCryptographicException();
+ _key.GenerateKey(curve);
- SetKey(key);
- }
- else
- {
- throw new PlatformNotSupportedException(string.Format(SR.Cryptography_CurveNotSupported, curve.CurveType.ToString()));
- }
+ // Use ForceSet instead of the property setter to ensure that LegalKeySizes doesn't interfere
+ // with the already loaded key.
+ ForceSetKeySize(_key.KeySize);
}
- private SafeEcKeyHandle GenerateKeyLazy()
+ public override void ImportParameters(ECParameters parameters)
{
- string oid = null;
- switch (KeySize)
- {
- case 256: oid = ECDSA_P256_OID_VALUE; break;
- case 384: oid = ECDSA_P384_OID_VALUE; break;
- case 521: oid = ECDSA_P521_OID_VALUE; break;
- default:
- // Only above three sizes supported for backwards compatibility; named curves should be used instead
- throw new InvalidOperationException(SR.Cryptography_InvalidKeySize);
- }
-
- SafeEcKeyHandle key = Interop.Crypto.EcKeyCreateByOid(oid);
-
- if (key == null || key.IsInvalid)
- throw new PlatformNotSupportedException(string.Format(SR.Cryptography_CurveNotSupported, oid));
-
- if (!Interop.Crypto.EcKeyGenerateKey(key))
- throw Interop.Crypto.CreateOpenSslCryptographicException();
-
- return key;
+ _key.ImportParameters(parameters);
+ ForceSetKeySize(_key.KeySize);
}
- private void FreeKey()
- {
- if (_key != null)
- {
- if (_key.IsValueCreated)
- {
- SafeEcKeyHandle handle = _key.Value;
- if (handle != null)
- handle.Dispose();
- }
- _key = null;
- }
- }
+ public override ECParameters ExportExplicitParameters(bool includePrivateParameters) =>
+ ECOpenSsl.ExportExplicitParameters(_key.Value, includePrivateParameters);
- private void SetKey(SafeEcKeyHandle newKey)
- {
- // Use ForceSet instead of the property setter to ensure that LegalKeySizes doesn't interfere
- // with the already loaded key.
- ForceSetKeySize(Interop.Crypto.EcKeyGetSize(newKey));
+ public override ECParameters ExportParameters(bool includePrivateParameters) =>
+ ECOpenSsl.ExportParameters(_key.Value, includePrivateParameters);
- _key = new Lazy<SafeEcKeyHandle>(newKey);
- }
}
#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS
}
diff --git a/src/Common/src/System/Security/Cryptography/ECDsaSecurityTransforms.cs b/src/Common/src/System/Security/Cryptography/ECDsaSecurityTransforms.cs
index e8b9f0d03b..d86ba86d67 100644
--- a/src/Common/src/System/Security/Cryptography/ECDsaSecurityTransforms.cs
+++ b/src/Common/src/System/Security/Cryptography/ECDsaSecurityTransforms.cs
@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Diagnostics;
using System.IO;
using System.Security.Cryptography.Apple;
using Internal.Cryptography;
@@ -50,7 +49,7 @@ namespace System.Security.Cryptography
{
public sealed partial class ECDsaSecurityTransforms : ECDsa
{
- private SecKeyPair _keys;
+ private readonly EccSecurityTransforms _ecc = new EccSecurityTransforms();
public ECDsaSecurityTransforms()
{
@@ -59,12 +58,12 @@ namespace System.Security.Cryptography
internal ECDsaSecurityTransforms(SafeSecKeyRefHandle publicKey)
{
- SetKey(SecKeyPair.PublicOnly(publicKey));
+ KeySizeValue = _ecc.SetKeyAndGetSize(SecKeyPair.PublicOnly(publicKey));
}
internal ECDsaSecurityTransforms(SafeSecKeyRefHandle publicKey, SafeSecKeyRefHandle privateKey)
{
- SetKey(SecKeyPair.PublicPrivatePair(publicKey, privateKey));
+ KeySizeValue = _ecc.SetKeyAndGetSize(SecKeyPair.PublicPrivatePair(publicKey, privateKey));
}
public override KeySizes[] LegalKeySizes
@@ -92,12 +91,7 @@ namespace System.Security.Cryptography
// Set the KeySize before freeing the key so that an invalid value doesn't throw away the key
base.KeySize = value;
-
- if (_keys != null)
- {
- _keys.Dispose();
- _keys = null;
- }
+ _ecc.Dispose();
}
}
@@ -180,11 +174,7 @@ namespace System.Security.Cryptography
{
if (disposing)
{
- if (_keys != null)
- {
- _keys.Dispose();
- _keys = null;
- }
+ _ecc.Dispose();
}
base.Dispose(disposing);
@@ -197,382 +187,26 @@ namespace System.Security.Cryptography
public override ECParameters ExportParameters(bool includePrivateParameters)
{
- SecKeyPair keys = GetKeys();
-
- SafeSecKeyRefHandle keyHandle = includePrivateParameters ? keys.PrivateKey : keys.PublicKey;
-
- if (keyHandle == null)
- {
- throw new CryptographicException(SR.Cryptography_OpenInvalidHandle);
- }
-
- DerSequenceReader keyReader = Interop.AppleCrypto.SecKeyExport(keyHandle, includePrivateParameters);
- ECParameters parameters = new ECParameters();
-
- if (includePrivateParameters)
- {
- keyReader.ReadPkcs8Blob(ref parameters);
- }
- else
- {
- keyReader.ReadSubjectPublicKeyInfo(ref parameters);
- }
-
- int size = AsymmetricAlgorithmHelpers.BitsToBytes(KeySize);
-
- KeyBlobHelpers.PadOrTrim(ref parameters.Q.X, size);
- KeyBlobHelpers.PadOrTrim(ref parameters.Q.Y, size);
-
- if (includePrivateParameters)
- {
- KeyBlobHelpers.PadOrTrim(ref parameters.D, size);
- }
-
- return parameters;
+ return _ecc.ExportParameters(includePrivateParameters, KeySize);
}
public override void ImportParameters(ECParameters parameters)
{
- parameters.Validate();
-
- bool isPrivateKey = parameters.D != null;
-
- if (isPrivateKey)
- {
- // Start with the private key, in case some of the private key fields don't
- // match the public key fields and the system determines an integrity failure.
- //
- // Public import should go off without a hitch.
- SafeSecKeyRefHandle privateKey = ImportKey(parameters);
-
- ECParameters publicOnly = parameters;
- publicOnly.D = null;
-
- SafeSecKeyRefHandle publicKey;
- try
- {
- publicKey = ImportKey(publicOnly);
- }
- catch
- {
- privateKey.Dispose();
- throw;
- }
-
- SetKey(SecKeyPair.PublicPrivatePair(publicKey, privateKey));
- }
- else
- {
- SafeSecKeyRefHandle publicKey = ImportKey(parameters);
- SetKey(SecKeyPair.PublicOnly(publicKey));
- }
+ KeySizeValue = _ecc.ImportParameters(parameters);
}
public override void GenerateKey(ECCurve curve)
{
- curve.Validate();
-
- if (!curve.IsNamed)
- {
- throw new PlatformNotSupportedException(SR.Cryptography_ECC_NamedCurvesOnly);
- }
-
- int keySize;
-
- switch (curve.Oid.Value)
- {
- // secp256r1 / nistp256
- case "1.2.840.10045.3.1.7":
- keySize = 256;
- break;
- // secp384r1 / nistp384
- case "1.3.132.0.34":
- keySize = 384;
- break;
- // secp521r1 / nistp521
- case "1.3.132.0.35":
- keySize = 521;
- break;
- default:
- throw new PlatformNotSupportedException(
- SR.Format(SR.Cryptography_CurveNotSupported, curve.Oid.Value));
- }
-
- // Clear the current key, because GenerateKey on the same curve makes a new key,
- // unlike setting the KeySize property to the current value.
- SetKey(null);
- KeySizeValue = keySize;
-
- // Generate the keys immediately, because that's what the verb of this method is.
- GetKeys();
- }
-
- private static SafeSecKeyRefHandle ImportKey(ECParameters parameters)
- {
- bool isPrivateKey = parameters.D != null;
- byte[] blob = isPrivateKey ? parameters.ToPrivateKeyBlob() : parameters.ToSubjectPublicKeyInfo();
-
- return Interop.AppleCrypto.ImportEphemeralKey(blob, isPrivateKey);
- }
-
- private void SetKey(SecKeyPair newKeyPair)
- {
- SecKeyPair current = _keys;
- _keys = newKeyPair;
- current?.Dispose();
-
- if (newKeyPair != null)
- {
- long size = Interop.AppleCrypto.EccGetKeySizeInBits(newKeyPair.PublicKey);
-
- Debug.Assert(size == 256 || size == 384 || size == 521, $"Unknown keysize ({size})");
- KeySizeValue = (int)size;
- }
+ KeySizeValue = _ecc.GenerateKey(curve);
}
internal SecKeyPair GetKeys()
{
- SecKeyPair current = _keys;
-
- if (current != null)
- {
- return current;
- }
-
- SafeSecKeyRefHandle publicKey;
- SafeSecKeyRefHandle privateKey;
-
- Interop.AppleCrypto.EccGenerateKey(KeySizeValue, out publicKey, out privateKey);
-
- current = SecKeyPair.PublicPrivatePair(publicKey, privateKey);
- _keys = current;
- return current;
+ return _ecc.GetOrGenerateKeys(KeySize);
}
}
}
#if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS
}
#endif
-
- internal static class EcKeyBlobHelpers
- {
- private static readonly byte[] s_version1 = { 1 };
- private static readonly byte[][] s_encodedVersion1 = DerEncoder.SegmentedEncodeUnsignedInteger(s_version1);
-
- private static readonly Oid s_idEcPublicKey = new Oid("1.2.840.10045.2.1", null);
- private static readonly byte[][] s_encodedIdEcPublicKey = DerEncoder.SegmentedEncodeOid(s_idEcPublicKey);
-
- internal static void ReadPkcs8Blob(this DerSequenceReader reader, ref ECParameters parameters)
- {
- // OneAsymmetricKey ::= SEQUENCE {
- // version Version,
- // privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
- // privateKey PrivateKey,
- // attributes [0] Attributes OPTIONAL,
- // ...,
- // [[2: publicKey [1] PublicKey OPTIONAL ]],
- // ...
- // }
- //
- // PrivateKeyInfo ::= OneAsymmetricKey
- //
- // PrivateKey ::= OCTET STRING
-
- int version = reader.ReadInteger();
-
- // We understand both version 0 and 1 formats,
- // which are now known as v1 and v2, respectively.
- if (version > 1)
- {
- throw new CryptographicException();
- }
-
- {
- // Ensure we're reading EC Public Key (well, Private, but the OID says Public)
- DerSequenceReader algorithm = reader.ReadSequence();
-
- string algorithmOid = algorithm.ReadOidAsString();
-
- if (algorithmOid != s_idEcPublicKey.Value)
- {
- throw new CryptographicException();
- }
- }
-
- byte[] privateKeyBlob = reader.ReadOctetString();
-
- // ECPrivateKey{CURVES:IOSet} ::= SEQUENCE {
- // version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
- // privateKey OCTET STRING,
- // parameters [0] Parameters{{IOSet}} OPTIONAL,
- // publicKey [1] BIT STRING OPTIONAL
- // }
- DerSequenceReader keyReader = new DerSequenceReader(privateKeyBlob);
- version = keyReader.ReadInteger();
-
- // We understand the version 1 format
- if (version > 1)
- {
- throw new CryptographicException();
- }
-
- parameters.D = keyReader.ReadOctetString();
-
- // Check for context specific 0
- const byte ConstructedContextSpecific =
- DerSequenceReader.ContextSpecificTagFlag | DerSequenceReader.ConstructedFlag;
-
- const byte ConstructedContextSpecific0 = (ConstructedContextSpecific | 0);
- const byte ConstructedContextSpecific1 = (ConstructedContextSpecific | 1);
-
- if (keyReader.PeekTag() != ConstructedContextSpecific0)
- {
- throw new CryptographicException();
- }
-
- // Parameters ::= CHOICE {
- // ecParameters ECParameters,
- // namedCurve CURVES.&id({ CurveNames}),
- // implicitlyCA NULL
- // }
- DerSequenceReader parametersReader = keyReader.ReadSequence();
-
- if (parametersReader.PeekTag() != (int)DerSequenceReader.DerTag.ObjectIdentifier)
- {
- throw new PlatformNotSupportedException(SR.Cryptography_ECC_NamedCurvesOnly);
- }
-
- parameters.Curve = ECCurve.CreateFromValue(parametersReader.ReadOidAsString());
-
- // Check for context specific 1
- if (keyReader.PeekTag() != ConstructedContextSpecific1)
- {
- throw new CryptographicException();
- }
-
- keyReader = keyReader.ReadSequence();
- byte[] encodedPoint = keyReader.ReadBitString();
- ReadEncodedPoint(encodedPoint, ref parameters);
-
- // We don't care about the rest of the blob here, but it's expected to not exist.
- }
-
- internal static void ReadSubjectPublicKeyInfo(this DerSequenceReader keyInfo, ref ECParameters parameters)
- {
- // SubjectPublicKeyInfo::= SEQUENCE {
- // algorithm AlgorithmIdentifier,
- // subjectPublicKey BIT STRING }
- DerSequenceReader algorithm = keyInfo.ReadSequence();
- string algorithmOid = algorithm.ReadOidAsString();
-
- // EC Public Key
- if (algorithmOid != s_idEcPublicKey.Value)
- {
- throw new CryptographicException();
- }
-
- if (algorithm.PeekTag() != (int)DerSequenceReader.DerTag.ObjectIdentifier)
- {
- throw new PlatformNotSupportedException(SR.Cryptography_ECC_NamedCurvesOnly);
- }
-
- parameters.Curve = ECCurve.CreateFromValue(algorithm.ReadOidAsString());
-
- byte[] encodedPoint = keyInfo.ReadBitString();
- ReadEncodedPoint(encodedPoint, ref parameters);
-
- // We don't care about the rest of the blob here, but it's expected to not exist.
- }
-
- internal static byte[] ToSubjectPublicKeyInfo(this ECParameters parameters)
- {
- parameters.Validate();
-
- if (!parameters.Curve.IsNamed)
- {
- throw new PlatformNotSupportedException(SR.Cryptography_ECC_NamedCurvesOnly);
- }
-
- byte[] pointBlob = GetPointBlob(ref parameters);
-
- return DerEncoder.ConstructSequence(
- DerEncoder.ConstructSegmentedSequence(
- s_encodedIdEcPublicKey,
- DerEncoder.SegmentedEncodeOid(parameters.Curve.Oid)),
- DerEncoder.SegmentedEncodeBitString(pointBlob));
- }
-
- private static byte[] GetPointBlob(ref ECParameters parameters)
- {
- byte[] pointBlob = new byte[parameters.Q.X.Length + parameters.Q.Y.Length + 1];
-
- // Uncompressed point
- pointBlob[0] = 0x04;
- Buffer.BlockCopy(parameters.Q.X, 0, pointBlob, 1, parameters.Q.X.Length);
- Buffer.BlockCopy(parameters.Q.Y, 0, pointBlob, 1 + parameters.Q.X.Length, parameters.Q.Y.Length);
- return pointBlob;
- }
-
- internal static byte[] ToPrivateKeyBlob(this ECParameters parameters)
- {
- parameters.Validate();
-
- if (!parameters.Curve.IsNamed)
- {
- throw new PlatformNotSupportedException(SR.Cryptography_ECC_NamedCurvesOnly);
- }
-
- byte[] pointBlob = GetPointBlob(ref parameters);
-
- // ECPrivateKey{CURVES:IOSet} ::= SEQUENCE {
- // version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
- // privateKey OCTET STRING,
- // parameters [0] Parameters{{IOSet}} OPTIONAL,
- // publicKey [1] BIT STRING OPTIONAL
- // }
- return DerEncoder.ConstructSequence(
- s_encodedVersion1,
- DerEncoder.SegmentedEncodeOctetString(parameters.D),
- DerEncoder.ConstructSegmentedContextSpecificValue(
- 0,
- DerEncoder.SegmentedEncodeOid(parameters.Curve.Oid)),
- DerEncoder.ConstructSegmentedContextSpecificValue(
- 1,
- DerEncoder.SegmentedEncodeBitString(pointBlob)));
- }
-
- private static void ReadEncodedPoint(byte[] encodedPoint, ref ECParameters parameters)
- {
- if (encodedPoint == null || encodedPoint.Length < 1)
- {
- throw new CryptographicException();
- }
-
- byte encoding = encodedPoint[0];
-
- switch (encoding)
- {
- // Uncompressed encoding (04 xbytes ybytes)
- case 0x04:
- // Hybrid encoding, ~yp == 0 (06 xbytes ybytes)
- case 0x06:
- // Hybrid encoding, ~yp == 1 (07 xbytes ybytes)
- case 0x07:
- break;
- default:
- Debug.Fail($"Don't know how to read point encoding {encoding}");
- throw new CryptographicException();
- }
-
- // For formats 04, 06, and 07 the X and Y points are equal length, and they should
- // already be left-padded with zeros in cases where they're short.
- int pointEncodingSize = (encodedPoint.Length - 1) / 2;
- byte[] encodedX = new byte[pointEncodingSize];
- byte[] encodedY = new byte[pointEncodingSize];
- Buffer.BlockCopy(encodedPoint, 1, encodedX, 0, pointEncodingSize);
- Buffer.BlockCopy(encodedPoint, 1 + pointEncodingSize, encodedY, 0, pointEncodingSize);
- parameters.Q.X = encodedX;
- parameters.Q.Y = encodedY;
- }
- }
}
diff --git a/src/Common/src/System/Security/Cryptography/ECOpenSsl.ImportExport.cs b/src/Common/src/System/Security/Cryptography/ECOpenSsl.ImportExport.cs
new file mode 100644
index 0000000000..050c610a74
--- /dev/null
+++ b/src/Common/src/System/Security/Cryptography/ECOpenSsl.ImportExport.cs
@@ -0,0 +1,191 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.Win32.SafeHandles;
+using System.Diagnostics;
+
+namespace System.Security.Cryptography
+{
+ internal sealed partial class ECOpenSsl
+ {
+ internal const string ECDSA_P256_OID_VALUE = "1.2.840.10045.3.1.7"; // Also called nistP256 or secP256r1
+ internal const string ECDSA_P384_OID_VALUE = "1.3.132.0.34"; // Also called nistP384 or secP384r1
+ internal const string ECDSA_P521_OID_VALUE = "1.3.132.0.35"; // Also called nistP521or secP521r1
+
+ public int ImportParameters(ECParameters parameters)
+ {
+ SafeEcKeyHandle key;
+
+ parameters.Validate();
+
+ if (parameters.Curve.IsPrime)
+ {
+ key = ImportPrimeCurveParameters(parameters);
+ }
+ else if (parameters.Curve.IsCharacteristic2)
+ {
+ key = ImportCharacteristic2CurveParameters(parameters);
+ }
+ else if (parameters.Curve.IsNamed)
+ {
+ key = ImportNamedCurveParameters(parameters);
+ }
+ else
+ {
+ throw new PlatformNotSupportedException(
+ string.Format(SR.Cryptography_CurveNotSupported, parameters.Curve.CurveType.ToString()));
+ }
+
+ if (key == null || key.IsInvalid)
+ {
+ throw Interop.Crypto.CreateOpenSslCryptographicException();
+ }
+
+ FreeKey();
+ _key = new Lazy<SafeEcKeyHandle>(key);
+ return KeySize;
+ }
+
+ public static ECParameters ExportExplicitParameters(SafeEcKeyHandle currentKey, bool includePrivateParameters) =>
+ ExportExplicitCurveParameters(currentKey, includePrivateParameters);
+
+ public static ECParameters ExportParameters(SafeEcKeyHandle currentKey, bool includePrivateParameters)
+ {
+ ECParameters ecparams;
+ if (Interop.Crypto.EcKeyHasCurveName(currentKey))
+ {
+ ecparams = ExportNamedCurveParameters(currentKey, includePrivateParameters);
+ }
+ else
+ {
+ ecparams = ExportExplicitCurveParameters(currentKey, includePrivateParameters);
+ }
+ return ecparams;
+ }
+
+ private static ECParameters ExportNamedCurveParameters(SafeEcKeyHandle key, bool includePrivateParameters)
+ {
+ CheckInvalidKey(key);
+
+ ECParameters parameters = Interop.Crypto.GetECKeyParameters(key, includePrivateParameters);
+
+ bool hasPrivateKey = (parameters.D != null);
+
+ if (hasPrivateKey != includePrivateParameters)
+ {
+ throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey);
+ }
+
+ // Assign Curve
+ string keyOidValueName = Interop.Crypto.EcKeyGetCurveName(key);
+ parameters.Curve = ECCurve.CreateFromValue(keyOidValueName);
+
+ return parameters;
+ }
+
+ private static ECParameters ExportExplicitCurveParameters(SafeEcKeyHandle key, bool includePrivateParameters)
+ {
+ CheckInvalidKey(key);
+
+ ECParameters parameters = Interop.Crypto.GetECCurveParameters(key, includePrivateParameters);
+
+ bool hasPrivateKey = (parameters.D != null);
+ if (hasPrivateKey != includePrivateParameters)
+ {
+ throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey);
+ }
+
+ return parameters;
+ }
+
+ private static SafeEcKeyHandle ImportNamedCurveParameters(ECParameters parameters)
+ {
+ Debug.Assert(parameters.Curve.IsNamed);
+
+ // Use oid Value first if present, otherwise FriendlyName
+ string oid = !string.IsNullOrEmpty(parameters.Curve.Oid.Value) ?
+ parameters.Curve.Oid.Value : parameters.Curve.Oid.FriendlyName;
+
+ SafeEcKeyHandle key = Interop.Crypto.EcKeyCreateByKeyParameters(
+ oid,
+ parameters.Q.X, parameters.Q.X.Length,
+ parameters.Q.Y, parameters.Q.Y.Length,
+ parameters.D, parameters.D == null ? 0 : parameters.D.Length);
+
+ return key;
+ }
+
+ private static SafeEcKeyHandle ImportPrimeCurveParameters(ECParameters parameters)
+ {
+ Debug.Assert(parameters.Curve.IsPrime);
+ SafeEcKeyHandle key = Interop.Crypto.EcKeyCreateByExplicitParameters(
+ parameters.Curve.CurveType,
+ parameters.Q.X, parameters.Q.X.Length,
+ parameters.Q.Y, parameters.Q.Y.Length,
+ parameters.D, parameters.D == null ? 0 : parameters.D.Length,
+ parameters.Curve.Prime, parameters.Curve.Prime.Length,
+ parameters.Curve.A, parameters.Curve.A.Length,
+ parameters.Curve.B, parameters.Curve.B.Length,
+ parameters.Curve.G.X, parameters.Curve.G.X.Length,
+ parameters.Curve.G.Y, parameters.Curve.G.Y.Length,
+ parameters.Curve.Order, parameters.Curve.Order.Length,
+ parameters.Curve.Cofactor, parameters.Curve.Cofactor.Length,
+ parameters.Curve.Seed, parameters.Curve.Seed == null ? 0 : parameters.Curve.Seed.Length);
+
+ return key;
+ }
+
+ private static SafeEcKeyHandle ImportCharacteristic2CurveParameters(ECParameters parameters)
+ {
+ Debug.Assert(parameters.Curve.IsCharacteristic2);
+ SafeEcKeyHandle key = Interop.Crypto.EcKeyCreateByExplicitParameters(
+ parameters.Curve.CurveType,
+ parameters.Q.X, parameters.Q.X.Length,
+ parameters.Q.Y, parameters.Q.Y.Length,
+ parameters.D, parameters.D == null ? 0 : parameters.D.Length,
+ parameters.Curve.Polynomial, parameters.Curve.Polynomial.Length,
+ parameters.Curve.A, parameters.Curve.A.Length,
+ parameters.Curve.B, parameters.Curve.B.Length,
+ parameters.Curve.G.X, parameters.Curve.G.X.Length,
+ parameters.Curve.G.Y, parameters.Curve.G.Y.Length,
+ parameters.Curve.Order, parameters.Curve.Order.Length,
+ parameters.Curve.Cofactor, parameters.Curve.Cofactor.Length,
+ parameters.Curve.Seed, parameters.Curve.Seed == null ? 0 : parameters.Curve.Seed.Length);
+
+ return key;
+ }
+
+ private static void CheckInvalidKey(SafeEcKeyHandle key)
+ {
+ if (key == null || key.IsInvalid)
+ {
+ throw new CryptographicException(SR.Cryptography_OpenInvalidHandle);
+ }
+ }
+
+ public static SafeEcKeyHandle GenerateKeyByKeySize(int keySize)
+ {
+ string oid = null;
+ switch (keySize)
+ {
+ case 256: oid = ECDSA_P256_OID_VALUE; break;
+ case 384: oid = ECDSA_P384_OID_VALUE; break;
+ case 521: oid = ECDSA_P521_OID_VALUE; break;
+ default:
+ // Only above three sizes supported for backwards compatibility; named curves should be used instead
+ throw new InvalidOperationException(SR.Cryptography_InvalidKeySize);
+ }
+
+ SafeEcKeyHandle key = Interop.Crypto.EcKeyCreateByOid(oid);
+
+ if (key == null || key.IsInvalid)
+ throw new PlatformNotSupportedException(string.Format(SR.Cryptography_CurveNotSupported, oid));
+
+ if (!Interop.Crypto.EcKeyGenerateKey(key))
+ throw Interop.Crypto.CreateOpenSslCryptographicException();
+
+ return key;
+ }
+ }
+}
diff --git a/src/Common/src/System/Security/Cryptography/ECOpenSsl.cs b/src/Common/src/System/Security/Cryptography/ECOpenSsl.cs
new file mode 100644
index 0000000000..e78787d3ef
--- /dev/null
+++ b/src/Common/src/System/Security/Cryptography/ECOpenSsl.cs
@@ -0,0 +1,139 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using Microsoft.Win32.SafeHandles;
+
+namespace System.Security.Cryptography
+{
+ internal sealed partial class ECOpenSsl : IDisposable
+ {
+ private Lazy<SafeEcKeyHandle> _key;
+
+ public ECOpenSsl(ECCurve curve)
+ {
+ GenerateKey(curve);
+ }
+
+ public ECOpenSsl(AsymmetricAlgorithm owner)
+ {
+ _key = new Lazy<SafeEcKeyHandle>(() => GenerateKeyLazy(owner));
+ }
+
+ public ECOpenSsl(ECParameters ecParameters)
+ {
+ ImportParameters(ecParameters);
+ }
+
+ public ECOpenSsl(SafeEcKeyHandle key)
+ {
+ _key = new Lazy<SafeEcKeyHandle>(key);
+ }
+
+ internal SafeEcKeyHandle Value => _key.Value;
+
+ private SafeEcKeyHandle GenerateKeyLazy(AsymmetricAlgorithm owner) =>
+ GenerateKeyByKeySize(owner.KeySize);
+
+ public void Dispose()
+ {
+ FreeKey();
+ }
+
+ internal int KeySize => Interop.Crypto.EcKeyGetSize(_key.Value);
+
+ internal SafeEvpPKeyHandle UpRefKeyHandle()
+ {
+ SafeEcKeyHandle currentKey = _key.Value;
+ Debug.Assert(currentKey != null, "null TODO");
+
+ SafeEvpPKeyHandle pkeyHandle = Interop.Crypto.EvpPkeyCreate();
+
+ try
+ {
+ // Wrapping our key in an EVP_PKEY will up_ref our key.
+ // When the EVP_PKEY is Disposed it will down_ref the key.
+ // So everything should be copacetic.
+ if (!Interop.Crypto.EvpPkeySetEcKey(pkeyHandle, currentKey))
+ {
+ throw Interop.Crypto.CreateOpenSslCryptographicException();
+ }
+
+ return pkeyHandle;
+ }
+ catch
+ {
+ pkeyHandle.Dispose();
+ throw;
+ }
+ }
+
+ internal void SetKey(SafeEcKeyHandle key)
+ {
+ Debug.Assert(key != null, "key != null");
+ Debug.Assert(!key.IsInvalid, "!key.IsInvalid");
+ Debug.Assert(!key.IsClosed, "!key.IsClosed");
+
+ FreeKey();
+ _key = new Lazy<SafeEcKeyHandle>(key);
+ }
+
+ internal int GenerateKey(ECCurve curve)
+ {
+ curve.Validate();
+ FreeKey();
+
+ if (curve.IsNamed)
+ {
+ string oid = null;
+ // Use oid Value first if present, otherwise FriendlyName because Oid maintains a hard-coded
+ // cache that may have different casing for FriendlyNames than OpenSsl
+ oid = !string.IsNullOrEmpty(curve.Oid.Value) ? curve.Oid.Value : curve.Oid.FriendlyName;
+
+ SafeEcKeyHandle key = Interop.Crypto.EcKeyCreateByOid(oid);
+
+ if (key == null || key.IsInvalid)
+ {
+ throw new PlatformNotSupportedException(string.Format(SR.Cryptography_CurveNotSupported, oid));
+ }
+
+ if (!Interop.Crypto.EcKeyGenerateKey(key))
+ {
+ throw Interop.Crypto.CreateOpenSslCryptographicException();
+ }
+
+ SetKey(key);
+ }
+ else if (curve.IsExplicit)
+ {
+ SafeEcKeyHandle key = Interop.Crypto.EcKeyCreateByExplicitCurve(curve);
+
+ if (!Interop.Crypto.EcKeyGenerateKey(key))
+ throw Interop.Crypto.CreateOpenSslCryptographicException();
+
+ SetKey(key);
+ }
+ else
+ {
+ throw new PlatformNotSupportedException(
+ string.Format(SR.Cryptography_CurveNotSupported, curve.CurveType.ToString()));
+ }
+
+ return KeySize;
+ }
+
+ private void FreeKey()
+ {
+ if (_key != null)
+ {
+ if (_key.IsValueCreated)
+ {
+ _key.Value?.Dispose();
+ }
+
+ _key = null;
+ }
+ }
+ }
+}
diff --git a/src/Common/src/System/Security/Cryptography/EccSecurityTransforms.cs b/src/Common/src/System/Security/Cryptography/EccSecurityTransforms.cs
new file mode 100644
index 0000000000..366d933eb7
--- /dev/null
+++ b/src/Common/src/System/Security/Cryptography/EccSecurityTransforms.cs
@@ -0,0 +1,416 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Security.Cryptography.Apple;
+using Internal.Cryptography;
+
+namespace System.Security.Cryptography
+{
+ internal sealed class EccSecurityTransforms : IDisposable
+ {
+ private SecKeyPair _keys;
+
+ public void Dispose()
+ {
+ _keys?.Dispose();
+ _keys = null;
+ }
+
+ internal int GenerateKey(ECCurve curve)
+ {
+ curve.Validate();
+
+ if (!curve.IsNamed)
+ {
+ throw new PlatformNotSupportedException(SR.Cryptography_ECC_NamedCurvesOnly);
+ }
+
+ int keySize;
+
+ switch (curve.Oid.Value)
+ {
+ // secp256r1 / nistp256
+ case "1.2.840.10045.3.1.7":
+ keySize = 256;
+ break;
+ // secp384r1 / nistp384
+ case "1.3.132.0.34":
+ keySize = 384;
+ break;
+ // secp521r1 / nistp521
+ case "1.3.132.0.35":
+ keySize = 521;
+ break;
+ default:
+ throw new PlatformNotSupportedException(
+ SR.Format(SR.Cryptography_CurveNotSupported, curve.Oid.Value));
+ }
+
+ GenerateKey(keySize);
+ return keySize;
+ }
+
+ private SecKeyPair GenerateKey(int keySizeInBits)
+ {
+ SafeSecKeyRefHandle publicKey;
+ SafeSecKeyRefHandle privateKey;
+
+ Interop.AppleCrypto.EccGenerateKey(keySizeInBits, out publicKey, out privateKey);
+
+ SecKeyPair newPair = SecKeyPair.PublicPrivatePair(publicKey, privateKey);
+ SetKey(newPair);
+ return newPair;
+ }
+
+ internal SecKeyPair GetOrGenerateKeys(int keySizeInBits)
+ {
+ SecKeyPair current = _keys;
+
+ if (current != null)
+ {
+ return current;
+ }
+
+ return GenerateKey(keySizeInBits);
+ }
+
+ internal int SetKeyAndGetSize(SecKeyPair keyPair)
+ {
+ int size = GetKeySize(keyPair);
+ SetKey(keyPair);
+ return size;
+ }
+
+ private void SetKey(SecKeyPair keyPair)
+ {
+ SecKeyPair current = _keys;
+ _keys = keyPair;
+ current?.Dispose();
+ }
+
+ internal ECParameters ExportParameters(bool includePrivateParameters, int keySizeInBIts)
+ {
+ SecKeyPair keys = GetOrGenerateKeys(keySizeInBIts);
+
+ SafeSecKeyRefHandle keyHandle = includePrivateParameters ? keys.PrivateKey : keys.PublicKey;
+
+ if (keyHandle == null)
+ {
+ throw new CryptographicException(SR.Cryptography_OpenInvalidHandle);
+ }
+
+ DerSequenceReader keyReader = Interop.AppleCrypto.SecKeyExport(keyHandle, includePrivateParameters);
+ ECParameters parameters = new ECParameters();
+
+ if (includePrivateParameters)
+ {
+ keyReader.ReadPkcs8Blob(ref parameters);
+ }
+ else
+ {
+ keyReader.ReadSubjectPublicKeyInfo(ref parameters);
+ }
+
+ int size = AsymmetricAlgorithmHelpers.BitsToBytes(keySizeInBIts);
+
+ KeyBlobHelpers.PadOrTrim(ref parameters.Q.X, size);
+ KeyBlobHelpers.PadOrTrim(ref parameters.Q.Y, size);
+
+ if (includePrivateParameters)
+ {
+ KeyBlobHelpers.PadOrTrim(ref parameters.D, size);
+ }
+
+ return parameters;
+ }
+
+ public int ImportParameters(ECParameters parameters)
+ {
+ parameters.Validate();
+
+ bool isPrivateKey = parameters.D != null;
+ SecKeyPair newKeys;
+
+ if (isPrivateKey)
+ {
+ // Start with the private key, in case some of the private key fields don't
+ // match the public key fields and the system determines an integrity failure.
+ //
+ // Public import should go off without a hitch.
+ SafeSecKeyRefHandle privateKey = ImportKey(parameters);
+
+ ECParameters publicOnly = parameters;
+ publicOnly.D = null;
+
+ SafeSecKeyRefHandle publicKey;
+ try
+ {
+ publicKey = ImportKey(publicOnly);
+ }
+ catch
+ {
+ privateKey.Dispose();
+ throw;
+ }
+
+ newKeys = SecKeyPair.PublicPrivatePair(publicKey, privateKey);
+ }
+ else
+ {
+ SafeSecKeyRefHandle publicKey = ImportKey(parameters);
+ newKeys = SecKeyPair.PublicOnly(publicKey);
+ }
+
+ int size = GetKeySize(newKeys);
+ SetKey(newKeys);
+
+ return size;
+ }
+
+ private static int GetKeySize(SecKeyPair newKeys)
+ {
+ long size = Interop.AppleCrypto.EccGetKeySizeInBits(newKeys.PublicKey);
+ Debug.Assert(size == 256 || size == 384 || size == 521, $"Unknown keysize ({size})");
+ return (int)size;
+ }
+
+ private static SafeSecKeyRefHandle ImportKey(ECParameters parameters)
+ {
+ bool isPrivateKey = parameters.D != null;
+ byte[] blob = isPrivateKey ? parameters.ToPrivateKeyBlob() : parameters.ToSubjectPublicKeyInfo();
+
+ return Interop.AppleCrypto.ImportEphemeralKey(blob, isPrivateKey);
+ }
+ }
+
+ internal static class EcKeyBlobHelpers
+ {
+ private static readonly byte[] s_version1 = { 1 };
+ private static readonly byte[][] s_encodedVersion1 = DerEncoder.SegmentedEncodeUnsignedInteger(s_version1);
+
+ private static readonly Oid s_idEcPublicKey = new Oid("1.2.840.10045.2.1", null);
+ private static readonly byte[][] s_encodedIdEcPublicKey = DerEncoder.SegmentedEncodeOid(s_idEcPublicKey);
+
+ internal static void ReadPkcs8Blob(this DerSequenceReader reader, ref ECParameters parameters)
+ {
+ // OneAsymmetricKey ::= SEQUENCE {
+ // version Version,
+ // privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+ // privateKey PrivateKey,
+ // attributes [0] Attributes OPTIONAL,
+ // ...,
+ // [[2: publicKey [1] PublicKey OPTIONAL ]],
+ // ...
+ // }
+ //
+ // PrivateKeyInfo ::= OneAsymmetricKey
+ //
+ // PrivateKey ::= OCTET STRING
+
+ int version = reader.ReadInteger();
+
+ // We understand both version 0 and 1 formats,
+ // which are now known as v1 and v2, respectively.
+ if (version > 1)
+ {
+ throw new CryptographicException();
+ }
+
+ {
+ // Ensure we're reading EC Public Key (well, Private, but the OID says Public)
+ DerSequenceReader algorithm = reader.ReadSequence();
+
+ string algorithmOid = algorithm.ReadOidAsString();
+
+ if (algorithmOid != s_idEcPublicKey.Value)
+ {
+ throw new CryptographicException();
+ }
+ }
+
+ byte[] privateKeyBlob = reader.ReadOctetString();
+
+ try
+ {
+ // ECPrivateKey{CURVES:IOSet} ::= SEQUENCE {
+ // version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
+ // privateKey OCTET STRING,
+ // parameters [0] Parameters{{IOSet}} OPTIONAL,
+ // publicKey [1] BIT STRING OPTIONAL
+ // }
+ DerSequenceReader keyReader = new DerSequenceReader(privateKeyBlob);
+ version = keyReader.ReadInteger();
+
+ // We understand the version 1 format
+ if (version > 1)
+ {
+ throw new CryptographicException();
+ }
+
+ parameters.D = keyReader.ReadOctetString();
+
+ // Check for context specific 0
+ const byte ConstructedContextSpecific =
+ DerSequenceReader.ContextSpecificTagFlag | DerSequenceReader.ConstructedFlag;
+
+ const byte ConstructedContextSpecific0 = (ConstructedContextSpecific | 0);
+ const byte ConstructedContextSpecific1 = (ConstructedContextSpecific | 1);
+
+ if (keyReader.PeekTag() != ConstructedContextSpecific0)
+ {
+ throw new CryptographicException();
+ }
+
+ // Parameters ::= CHOICE {
+ // ecParameters ECParameters,
+ // namedCurve CURVES.&id({ CurveNames}),
+ // implicitlyCA NULL
+ // }
+ DerSequenceReader parametersReader = keyReader.ReadSequence();
+
+ if (parametersReader.PeekTag() != (int)DerSequenceReader.DerTag.ObjectIdentifier)
+ {
+ throw new PlatformNotSupportedException(SR.Cryptography_ECC_NamedCurvesOnly);
+ }
+
+ parameters.Curve = ECCurve.CreateFromValue(parametersReader.ReadOidAsString());
+
+ // Check for context specific 1
+ if (keyReader.PeekTag() != ConstructedContextSpecific1)
+ {
+ throw new CryptographicException();
+ }
+
+ keyReader = keyReader.ReadSequence();
+ byte[] encodedPoint = keyReader.ReadBitString();
+ ReadEncodedPoint(encodedPoint, ref parameters);
+
+ // We don't care about the rest of the blob here, but it's expected to not exist.
+ }
+ finally
+ {
+ Array.Clear(privateKeyBlob, 0, privateKeyBlob.Length);
+ }
+ }
+
+ internal static void ReadSubjectPublicKeyInfo(this DerSequenceReader keyInfo, ref ECParameters parameters)
+ {
+ // SubjectPublicKeyInfo::= SEQUENCE {
+ // algorithm AlgorithmIdentifier,
+ // subjectPublicKey BIT STRING }
+ DerSequenceReader algorithm = keyInfo.ReadSequence();
+ string algorithmOid = algorithm.ReadOidAsString();
+
+ // EC Public Key
+ if (algorithmOid != s_idEcPublicKey.Value)
+ {
+ throw new CryptographicException();
+ }
+
+ if (algorithm.PeekTag() != (int)DerSequenceReader.DerTag.ObjectIdentifier)
+ {
+ throw new PlatformNotSupportedException(SR.Cryptography_ECC_NamedCurvesOnly);
+ }
+
+ parameters.Curve = ECCurve.CreateFromValue(algorithm.ReadOidAsString());
+
+ byte[] encodedPoint = keyInfo.ReadBitString();
+ ReadEncodedPoint(encodedPoint, ref parameters);
+
+ // We don't care about the rest of the blob here, but it's expected to not exist.
+ }
+
+ internal static byte[] ToSubjectPublicKeyInfo(this ECParameters parameters)
+ {
+ parameters.Validate();
+
+ if (!parameters.Curve.IsNamed)
+ {
+ throw new PlatformNotSupportedException(SR.Cryptography_ECC_NamedCurvesOnly);
+ }
+
+ byte[] pointBlob = GetPointBlob(ref parameters);
+
+ return DerEncoder.ConstructSequence(
+ DerEncoder.ConstructSegmentedSequence(
+ s_encodedIdEcPublicKey,
+ DerEncoder.SegmentedEncodeOid(parameters.Curve.Oid)),
+ DerEncoder.SegmentedEncodeBitString(pointBlob));
+ }
+
+ private static byte[] GetPointBlob(ref ECParameters parameters)
+ {
+ byte[] pointBlob = new byte[parameters.Q.X.Length + parameters.Q.Y.Length + 1];
+
+ // Uncompressed point
+ pointBlob[0] = 0x04;
+ Buffer.BlockCopy(parameters.Q.X, 0, pointBlob, 1, parameters.Q.X.Length);
+ Buffer.BlockCopy(parameters.Q.Y, 0, pointBlob, 1 + parameters.Q.X.Length, parameters.Q.Y.Length);
+ return pointBlob;
+ }
+
+ internal static byte[] ToPrivateKeyBlob(this ECParameters parameters)
+ {
+ parameters.Validate();
+
+ if (!parameters.Curve.IsNamed)
+ {
+ throw new PlatformNotSupportedException(SR.Cryptography_ECC_NamedCurvesOnly);
+ }
+
+ byte[] pointBlob = GetPointBlob(ref parameters);
+
+ // ECPrivateKey{CURVES:IOSet} ::= SEQUENCE {
+ // version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
+ // privateKey OCTET STRING,
+ // parameters [0] Parameters{{IOSet}} OPTIONAL,
+ // publicKey [1] BIT STRING OPTIONAL
+ // }
+ return DerEncoder.ConstructSequence(
+ s_encodedVersion1,
+ DerEncoder.SegmentedEncodeOctetString(parameters.D),
+ DerEncoder.ConstructSegmentedContextSpecificValue(
+ 0,
+ DerEncoder.SegmentedEncodeOid(parameters.Curve.Oid)),
+ DerEncoder.ConstructSegmentedContextSpecificValue(
+ 1,
+ DerEncoder.SegmentedEncodeBitString(pointBlob)));
+ }
+
+ private static void ReadEncodedPoint(byte[] encodedPoint, ref ECParameters parameters)
+ {
+ if (encodedPoint == null || encodedPoint.Length < 1)
+ {
+ throw new CryptographicException();
+ }
+
+ byte encoding = encodedPoint[0];
+
+ switch (encoding)
+ {
+ // Uncompressed encoding (04 xbytes ybytes)
+ case 0x04:
+ // Hybrid encoding, ~yp == 0 (06 xbytes ybytes)
+ case 0x06:
+ // Hybrid encoding, ~yp == 1 (07 xbytes ybytes)
+ case 0x07:
+ break;
+ default:
+ Debug.Fail($"Don't know how to read point encoding {encoding}");
+ throw new CryptographicException();
+ }
+
+ // For formats 04, 06, and 07 the X and Y points are equal length, and they should
+ // already be left-padded with zeros in cases where they're short.
+ int pointEncodingSize = (encodedPoint.Length - 1) / 2;
+ byte[] encodedX = new byte[pointEncodingSize];
+ byte[] encodedY = new byte[pointEncodingSize];
+ Buffer.BlockCopy(encodedPoint, 1, encodedX, 0, pointEncodingSize);
+ Buffer.BlockCopy(encodedPoint, 1 + pointEncodingSize, encodedY, 0, pointEncodingSize);
+ parameters.Q.X = encodedX;
+ parameters.Q.Y = encodedY;
+ }
+ }
+}
diff --git a/src/Common/src/System/Security/Cryptography/RSACng.EncryptDecrypt.cs b/src/Common/src/System/Security/Cryptography/RSACng.EncryptDecrypt.cs
index 0df93cb0b4..2230f91430 100644
--- a/src/Common/src/System/Security/Cryptography/RSACng.EncryptDecrypt.cs
+++ b/src/Common/src/System/Security/Cryptography/RSACng.EncryptDecrypt.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Buffers;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
using Internal.Cryptography;
@@ -18,6 +19,8 @@ namespace System.Security.Cryptography
#endif
public sealed partial class RSACng : RSA
{
+ private const int Pkcs1PaddingOverhead = 11;
+
/// <summary>Encrypts data using the public key.</summary>
public override unsafe byte[] Encrypt(byte[] data, RSAEncryptionPadding padding) =>
EncryptOrDecrypt(data, padding, encrypt: true);
@@ -27,12 +30,12 @@ namespace System.Security.Cryptography
EncryptOrDecrypt(data, padding, encrypt: false);
/// <summary>Encrypts data using the public key.</summary>
- public override bool TryEncrypt(ReadOnlySpan<byte> source, Span<byte> destination, RSAEncryptionPadding padding, out int bytesWritten) =>
- TryEncryptOrDecrypt(source, destination, padding, encrypt: true, bytesWritten: out bytesWritten);
+ public override bool TryEncrypt(ReadOnlySpan<byte> data, Span<byte> destination, RSAEncryptionPadding padding, out int bytesWritten) =>
+ TryEncryptOrDecrypt(data, destination, padding, encrypt: true, bytesWritten: out bytesWritten);
/// <summary>Decrypts data using the private key.</summary>
- public override bool TryDecrypt(ReadOnlySpan<byte> source, Span<byte> destination, RSAEncryptionPadding padding, out int bytesWritten) =>
- TryEncryptOrDecrypt(source, destination, padding, encrypt: false, bytesWritten: out bytesWritten);
+ public override bool TryDecrypt(ReadOnlySpan<byte> data, Span<byte> destination, RSAEncryptionPadding padding, out int bytesWritten) =>
+ TryEncryptOrDecrypt(data, destination, padding, encrypt: false, bytesWritten: out bytesWritten);
// Conveniently, Encrypt() and Decrypt() are identical save for the actual P/Invoke call to CNG. Thus, both
// array-based APIs invoke this common helper with the "encrypt" parameter determining whether encryption or decryption is done.
@@ -47,8 +50,56 @@ namespace System.Security.Cryptography
throw new ArgumentNullException(nameof(padding));
}
+ int modulusSizeInBytes = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize);
+
+ if (!encrypt && data.Length > modulusSizeInBytes)
+ {
+ throw new CryptographicException(
+ SR.Format(SR.Cryptography_Padding_DecDataTooBig, modulusSizeInBytes));
+ }
+
+ if (encrypt &&
+ padding.Mode == RSAEncryptionPaddingMode.Pkcs1 &&
+ data.Length > modulusSizeInBytes - Pkcs1PaddingOverhead)
+ {
+ throw new CryptographicException(
+ SR.Format(SR.Cryptography_Encryption_MessageTooLong, modulusSizeInBytes - Pkcs1PaddingOverhead));
+ }
+
using (SafeNCryptKeyHandle keyHandle = GetDuplicatedKeyHandle())
{
+ if (encrypt && data.Length == 0)
+ {
+ byte[] rented = ArrayPool<byte>.Shared.Rent(modulusSizeInBytes);
+ Span<byte> paddedMessage = new Span<byte>(rented, 0, modulusSizeInBytes);
+
+ try
+ {
+ if (padding == RSAEncryptionPadding.Pkcs1)
+ {
+ RsaPaddingProcessor.PadPkcs1Encryption(data, paddedMessage);
+ }
+ else if (padding.Mode == RSAEncryptionPaddingMode.Oaep)
+ {
+ RsaPaddingProcessor processor =
+ RsaPaddingProcessor.OpenProcessor(padding.OaepHashAlgorithm);
+
+ processor.PadOaep(data, paddedMessage);
+ }
+ else
+ {
+ throw new CryptographicException(SR.Cryptography_UnsupportedPaddingMode);
+ }
+
+ return EncryptOrDecrypt(keyHandle, paddedMessage, AsymmetricPaddingMode.NCRYPT_NO_PADDING_FLAG, null, encrypt);
+ }
+ finally
+ {
+ CryptographicOperations.ZeroMemory(paddedMessage);
+ ArrayPool<byte>.Shared.Return(rented);
+ }
+ }
+
switch (padding.Mode)
{
case RSAEncryptionPaddingMode.Pkcs1:
@@ -81,19 +132,67 @@ namespace System.Security.Cryptography
// Conveniently, Encrypt() and Decrypt() are identical save for the actual P/Invoke call to CNG. Thus, both
// span-based APIs invoke this common helper with the "encrypt" parameter determining whether encryption or decryption is done.
- private unsafe bool TryEncryptOrDecrypt(ReadOnlySpan<byte> source, Span<byte> destination, RSAEncryptionPadding padding, bool encrypt, out int bytesWritten)
+ private unsafe bool TryEncryptOrDecrypt(ReadOnlySpan<byte> data, Span<byte> destination, RSAEncryptionPadding padding, bool encrypt, out int bytesWritten)
{
if (padding == null)
{
throw new ArgumentNullException(nameof(padding));
}
+ int modulusSizeInBytes = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize);
+
+ if (!encrypt && data.Length > modulusSizeInBytes)
+ {
+ throw new CryptographicException(
+ SR.Format(SR.Cryptography_Padding_DecDataTooBig, modulusSizeInBytes));
+ }
+
+ if (encrypt &&
+ padding.Mode == RSAEncryptionPaddingMode.Pkcs1 &&
+ data.Length > modulusSizeInBytes - Pkcs1PaddingOverhead)
+ {
+ throw new CryptographicException(
+ SR.Format(SR.Cryptography_Encryption_MessageTooLong, modulusSizeInBytes - Pkcs1PaddingOverhead));
+ }
+
using (SafeNCryptKeyHandle keyHandle = GetDuplicatedKeyHandle())
{
+ if (encrypt && data.Length == 0)
+ {
+ byte[] rented = ArrayPool<byte>.Shared.Rent(modulusSizeInBytes);
+ Span<byte> paddedMessage = new Span<byte>(rented, 0, modulusSizeInBytes);
+
+ try
+ {
+ if (padding == RSAEncryptionPadding.Pkcs1)
+ {
+ RsaPaddingProcessor.PadPkcs1Encryption(data, paddedMessage);
+ }
+ else if (padding.Mode == RSAEncryptionPaddingMode.Oaep)
+ {
+ RsaPaddingProcessor processor =
+ RsaPaddingProcessor.OpenProcessor(padding.OaepHashAlgorithm);
+
+ processor.PadOaep(data, paddedMessage);
+ }
+ else
+ {
+ throw new CryptographicException(SR.Cryptography_UnsupportedPaddingMode);
+ }
+
+ return TryEncryptOrDecrypt(keyHandle, paddedMessage, destination, AsymmetricPaddingMode.NCRYPT_NO_PADDING_FLAG, null, encrypt, out bytesWritten);
+ }
+ finally
+ {
+ CryptographicOperations.ZeroMemory(paddedMessage);
+ ArrayPool<byte>.Shared.Return(rented);
+ }
+ }
+
switch (padding.Mode)
{
case RSAEncryptionPaddingMode.Pkcs1:
- return TryEncryptOrDecrypt(keyHandle, source, destination, AsymmetricPaddingMode.NCRYPT_PAD_PKCS1_FLAG, null, encrypt, out bytesWritten);
+ return TryEncryptOrDecrypt(keyHandle, data, destination, AsymmetricPaddingMode.NCRYPT_PAD_PKCS1_FLAG, null, encrypt, out bytesWritten);
case RSAEncryptionPaddingMode.Oaep:
IntPtr namePtr = Marshal.StringToHGlobalUni(padding.OaepHashAlgorithm.Name);
@@ -105,7 +204,7 @@ namespace System.Security.Cryptography
pbLabel = IntPtr.Zero, // It would nice to put randomized data here but RSAEncryptionPadding does not at this point provide support for this.
cbLabel = 0,
};
- return TryEncryptOrDecrypt(keyHandle, source, destination, AsymmetricPaddingMode.NCRYPT_PAD_OAEP_FLAG, &paddingInfo, encrypt, out bytesWritten);
+ return TryEncryptOrDecrypt(keyHandle, data, destination, AsymmetricPaddingMode.NCRYPT_PAD_OAEP_FLAG, &paddingInfo, encrypt, out bytesWritten);
}
finally
{
@@ -119,7 +218,7 @@ namespace System.Security.Cryptography
}
// Now that the padding mode and information have been marshaled to their native counterparts, perform the encryption or decryption.
- private unsafe byte[] EncryptOrDecrypt(SafeNCryptKeyHandle key, byte[] input, AsymmetricPaddingMode paddingMode, void* paddingInfo, bool encrypt)
+ private unsafe byte[] EncryptOrDecrypt(SafeNCryptKeyHandle key, ReadOnlySpan<byte> input, AsymmetricPaddingMode paddingMode, void* paddingInfo, bool encrypt)
{
int estimatedSize = KeySize / 8;
#if DEBUG
diff --git a/src/Common/src/System/Security/Cryptography/RSACng.SignVerify.cs b/src/Common/src/System/Security/Cryptography/RSACng.SignVerify.cs
index 5da42605df..3560eff152 100644
--- a/src/Common/src/System/Security/Cryptography/RSACng.SignVerify.cs
+++ b/src/Common/src/System/Security/Cryptography/RSACng.SignVerify.cs
@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Collections.Concurrent;
+using System.Collections.Generic;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
using Internal.Cryptography;
@@ -18,6 +20,28 @@ namespace System.Security.Cryptography
#endif
public sealed partial class RSACng : RSA
{
+ private static readonly ConcurrentDictionary<HashAlgorithmName, int> s_hashSizes =
+ new ConcurrentDictionary<HashAlgorithmName, int>(
+ new[]
+ {
+ KeyValuePair.Create(HashAlgorithmName.SHA256, 256 / 8),
+ KeyValuePair.Create(HashAlgorithmName.SHA384, 384 / 8),
+ KeyValuePair.Create(HashAlgorithmName.SHA512, 512 / 8),
+ });
+
+ private static int GetHashSizeInBytes(HashAlgorithmName hashAlgorithm)
+ {
+ return s_hashSizes.GetOrAdd(
+ hashAlgorithm,
+ alg =>
+ {
+ using (HashProviderCng hashProvider = new HashProviderCng(alg.Name, null))
+ {
+ return hashProvider.HashSizeInBytes;
+ }
+ });
+ }
+
/// <summary>
/// Computes the signature of a hash that was produced by the hash algorithm specified by "hashAlgorithm."
/// </summary>
@@ -38,6 +62,11 @@ namespace System.Security.Cryptography
throw new ArgumentNullException(nameof(padding));
}
+ if (hash.Length != GetHashSizeInBytes(hashAlgorithm))
+ {
+ throw new CryptographicException(SR.Cryptography_SignHash_WrongSize);
+ }
+
using (SafeNCryptKeyHandle keyHandle = GetDuplicatedKeyHandle())
{
IntPtr namePtr = Marshal.StringToHGlobalUni(hashAlgorithmName);
@@ -68,7 +97,7 @@ namespace System.Security.Cryptography
}
}
- public override unsafe bool TrySignHash(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding, out int bytesWritten)
+ public override unsafe bool TrySignHash(ReadOnlySpan<byte> hash, Span<byte> destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding, out int bytesWritten)
{
string hashAlgorithmName = hashAlgorithm.Name;
if (string.IsNullOrEmpty(hashAlgorithmName))
@@ -82,6 +111,11 @@ namespace System.Security.Cryptography
using (SafeNCryptKeyHandle keyHandle = GetDuplicatedKeyHandle())
{
+ if (hash.Length != GetHashSizeInBytes(hashAlgorithm))
+ {
+ throw new CryptographicException(SR.Cryptography_SignHash_WrongSize);
+ }
+
IntPtr namePtr = Marshal.StringToHGlobalUni(hashAlgorithmName);
try
{
@@ -89,11 +123,11 @@ namespace System.Security.Cryptography
{
case RSASignaturePaddingMode.Pkcs1:
var pkcs1PaddingInfo = new BCRYPT_PKCS1_PADDING_INFO() { pszAlgId = namePtr };
- return keyHandle.TrySignHash(source, destination, AsymmetricPaddingMode.NCRYPT_PAD_PKCS1_FLAG, &pkcs1PaddingInfo, out bytesWritten);
+ return keyHandle.TrySignHash(hash, destination, AsymmetricPaddingMode.NCRYPT_PAD_PKCS1_FLAG, &pkcs1PaddingInfo, out bytesWritten);
case RSASignaturePaddingMode.Pss:
- var pssPaddingInfo = new BCRYPT_PSS_PADDING_INFO() { pszAlgId = namePtr, cbSalt = source.Length };
- return keyHandle.TrySignHash(source, destination, AsymmetricPaddingMode.NCRYPT_PAD_PSS_FLAG, &pssPaddingInfo, out bytesWritten);
+ var pssPaddingInfo = new BCRYPT_PSS_PADDING_INFO() { pszAlgId = namePtr, cbSalt = hash.Length };
+ return keyHandle.TrySignHash(hash, destination, AsymmetricPaddingMode.NCRYPT_PAD_PSS_FLAG, &pssPaddingInfo, out bytesWritten);
default:
throw new CryptographicException(SR.Cryptography_UnsupportedPaddingMode);
@@ -137,6 +171,11 @@ namespace System.Security.Cryptography
using (SafeNCryptKeyHandle keyHandle = GetDuplicatedKeyHandle())
{
+ if (hash.Length != GetHashSizeInBytes(hashAlgorithm))
+ {
+ return false;
+ }
+
IntPtr namePtr = Marshal.StringToHGlobalUni(hashAlgorithmName);
try
{
diff --git a/src/Common/src/System/Security/Cryptography/RSACng.cs b/src/Common/src/System/Security/Cryptography/RSACng.cs
index 2899ab70dc..f7edcd6746 100644
--- a/src/Common/src/System/Security/Cryptography/RSACng.cs
+++ b/src/Common/src/System/Security/Cryptography/RSACng.cs
@@ -50,8 +50,8 @@ namespace System.Security.Cryptography
protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) =>
CngCommon.HashData(data, offset, count, hashAlgorithm);
- protected override bool TryHashData(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) =>
- CngCommon.TryHashData(source, destination, hashAlgorithm, out bytesWritten);
+ protected override bool TryHashData(ReadOnlySpan<byte> data, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) =>
+ CngCommon.TryHashData(data, destination, hashAlgorithm, out bytesWritten);
protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) =>
CngCommon.HashData(data, hashAlgorithm);
diff --git a/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs b/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs
index d2d6268fa2..8ee05705ed 100644
--- a/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs
+++ b/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Buffers;
using System.Diagnostics;
using System.IO;
@@ -88,65 +89,123 @@ namespace System.Security.Cryptography
if (padding == null)
throw new ArgumentNullException(nameof(padding));
- Interop.Crypto.RsaPadding rsaPadding = GetInteropPadding(padding);
+ Interop.Crypto.RsaPadding rsaPadding = GetInteropPadding(padding, out RsaPaddingProcessor oaepProcessor);
SafeRsaHandle key = _key.Value;
CheckInvalidKey(key);
- byte[] buf = new byte[Interop.Crypto.RsaSize(key)];
+ int rsaSize = Interop.Crypto.RsaSize(key);
+ byte[] buf = null;
+ Span<byte> destination = default;
- int returnValue = Interop.Crypto.RsaPrivateDecrypt(
- data.Length,
- data,
- buf,
- key,
- rsaPadding);
+ try
+ {
+ buf = ArrayPool<byte>.Shared.Rent(rsaSize);
+ destination = new Span<byte>(buf, 0, rsaSize);
- CheckReturn(returnValue);
+ if (!TryDecrypt(key, data, destination, rsaPadding, oaepProcessor, out int bytesWritten))
+ {
+ Debug.Fail($"{nameof(TryDecrypt)} should not return false for RSA_size buffer");
+ throw new CryptographicException();
+ }
- // If the padding mode is RSA_NO_PADDING then the size of the decrypted block
- // will be RSA_size, so let's just return buf.
- //
- // If any padding was used, then some amount (determined by the padding algorithm)
- // will have been reduced, and only returnValue bytes were part of the decrypted
- // body, so copy the decrypted bytes to an appropriately sized array before
- // returning it.
- if (returnValue == buf.Length)
+ return destination.Slice(0, bytesWritten).ToArray();
+ }
+ finally
{
- return buf;
+ CryptographicOperations.ZeroMemory(destination);
+ ArrayPool<byte>.Shared.Return(buf);
}
-
- byte[] plainBytes = new byte[returnValue];
- Buffer.BlockCopy(buf, 0, plainBytes, 0, returnValue);
- return plainBytes;
}
- public override bool TryDecrypt(ReadOnlySpan<byte> source, Span<byte> destination, RSAEncryptionPadding padding, out int bytesWritten)
+ public override bool TryDecrypt(
+ ReadOnlySpan<byte> data,
+ Span<byte> destination,
+ RSAEncryptionPadding padding,
+ out int bytesWritten)
{
if (padding == null)
{
throw new ArgumentNullException(nameof(padding));
}
- Interop.Crypto.RsaPadding rsaPadding = GetInteropPadding(padding);
+ Interop.Crypto.RsaPadding rsaPadding = GetInteropPadding(padding, out RsaPaddingProcessor oaepProcessor);
SafeRsaHandle key = _key.Value;
CheckInvalidKey(key);
- if (destination.Length < Interop.Crypto.RsaSize(key))
+ return TryDecrypt(key, data, destination, rsaPadding, oaepProcessor, out bytesWritten);
+ }
+
+ private static bool TryDecrypt(
+ SafeRsaHandle key,
+ ReadOnlySpan<byte> data,
+ Span<byte> destination,
+ Interop.Crypto.RsaPadding rsaPadding,
+ RsaPaddingProcessor rsaPaddingProcessor,
+ out int bytesWritten)
+ {
+ // If rsaPadding is PKCS1 or OAEP-SHA1 then no depadding method should be present.
+ // If rsaPadding is NoPadding then a depadding method should be present.
+ Debug.Assert(
+ (rsaPadding == Interop.Crypto.RsaPadding.NoPadding) ==
+ (rsaPaddingProcessor != null));
+
+ // Caller should have already checked this.
+ Debug.Assert(!key.IsInvalid);
+
+ int rsaSize = Interop.Crypto.RsaSize(key);
+
+ if (data.Length > rsaSize)
+ {
+ throw new CryptographicException(
+ SR.Format(SR.Cryptography_Padding_DecDataTooBig, rsaSize));
+ }
+
+ if (destination.Length < rsaSize)
{
bytesWritten = 0;
return false;
}
- int returnValue = Interop.Crypto.RsaPrivateDecrypt(source.Length, source, destination, key, rsaPadding);
- CheckReturn(returnValue);
+ Span<byte> decryptBuf = destination;
+ byte[] paddingBuf = null;
- // If the padding mode is RSA_NO_PADDING then the size of the decrypted block
- // will be RSA_size. If any padding was used, then some amount (determined by the padding algorithm)
- // will have been reduced, and only returnValue bytes were part of the decrypted
- // body. Either way, we can just use returnValue, but some additional bytes may have been overwritten
- // in the destination span.
- bytesWritten = returnValue;
- return true;
+ if (rsaPaddingProcessor != null)
+ {
+ paddingBuf = ArrayPool<byte>.Shared.Rent(rsaSize);
+ decryptBuf = paddingBuf;
+ }
+
+ try
+ {
+ int returnValue = Interop.Crypto.RsaPrivateDecrypt(data.Length, data, decryptBuf, key, rsaPadding);
+ CheckReturn(returnValue);
+
+ if (rsaPaddingProcessor != null)
+ {
+ return rsaPaddingProcessor.DepadOaep(paddingBuf, destination, out bytesWritten);
+ }
+ else
+ {
+ // If the padding mode is RSA_NO_PADDING then the size of the decrypted block
+ // will be RSA_size. If any padding was used, then some amount (determined by the padding algorithm)
+ // will have been reduced, and only returnValue bytes were part of the decrypted
+ // body. Either way, we can just use returnValue, but some additional bytes may have been overwritten
+ // in the destination span.
+ bytesWritten = returnValue;
+ }
+
+ return true;
+ }
+ finally
+ {
+ if (paddingBuf != null)
+ {
+ // DecryptBuf is paddingBuf if paddingBuf is not null, erase it before returning it.
+ // If paddingBuf IS null then decryptBuf was destination, and shouldn't be cleared.
+ CryptographicOperations.ZeroMemory(decryptBuf);
+ ArrayPool<byte>.Shared.Return(paddingBuf);
+ }
+ }
}
public override byte[] Encrypt(byte[] data, RSAEncryptionPadding padding)
@@ -156,52 +215,117 @@ namespace System.Security.Cryptography
if (padding == null)
throw new ArgumentNullException(nameof(padding));
- Interop.Crypto.RsaPadding rsaPadding = GetInteropPadding(padding);
+ Interop.Crypto.RsaPadding rsaPadding = GetInteropPadding(padding, out RsaPaddingProcessor oaepProcessor);
SafeRsaHandle key = _key.Value;
CheckInvalidKey(key);
byte[] buf = new byte[Interop.Crypto.RsaSize(key)];
- int returnValue = Interop.Crypto.RsaPublicEncrypt(
- data.Length,
+ bool encrypted = TryEncrypt(
+ key,
data,
buf,
- key,
- rsaPadding);
+ rsaPadding,
+ oaepProcessor,
+ out int bytesWritten);
- CheckReturn(returnValue);
+ if (!encrypted || bytesWritten != buf.Length)
+ {
+ Debug.Fail($"TryEncrypt behaved unexpectedly: {nameof(encrypted)}=={encrypted}, {nameof(bytesWritten)}=={bytesWritten}, {nameof(buf.Length)}=={buf.Length}");
+ throw new CryptographicException();
+ }
return buf;
}
- public override bool TryEncrypt(ReadOnlySpan<byte> source, Span<byte> destination, RSAEncryptionPadding padding, out int bytesWritten)
+ public override bool TryEncrypt(ReadOnlySpan<byte> data, Span<byte> destination, RSAEncryptionPadding padding, out int bytesWritten)
{
if (padding == null)
{
throw new ArgumentNullException(nameof(padding));
}
- Interop.Crypto.RsaPadding rsaPadding = GetInteropPadding(padding);
+ Interop.Crypto.RsaPadding rsaPadding = GetInteropPadding(padding, out RsaPaddingProcessor oaepProcessor);
SafeRsaHandle key = _key.Value;
CheckInvalidKey(key);
- if (destination.Length < Interop.Crypto.RsaSize(key))
+ return TryEncrypt(key, data, destination, rsaPadding, oaepProcessor, out bytesWritten);
+ }
+
+ private static bool TryEncrypt(
+ SafeRsaHandle key,
+ ReadOnlySpan<byte> data,
+ Span<byte> destination,
+ Interop.Crypto.RsaPadding rsaPadding,
+ RsaPaddingProcessor rsaPaddingProcessor,
+ out int bytesWritten)
+ {
+ int rsaSize = Interop.Crypto.RsaSize(key);
+
+ if (destination.Length < rsaSize)
{
bytesWritten = 0;
return false;
}
- int returnValue = Interop.Crypto.RsaPublicEncrypt(source.Length, source, destination, key, rsaPadding);
+ int returnValue;
+
+ if (rsaPaddingProcessor != null)
+ {
+ Debug.Assert(rsaPadding == Interop.Crypto.RsaPadding.NoPadding);
+ byte[] rented = ArrayPool<byte>.Shared.Rent(rsaSize);
+ Span<byte> tmp = new Span<byte>(rented, 0, rsaSize);
+
+ try
+ {
+ rsaPaddingProcessor.PadOaep(data, tmp);
+ returnValue = Interop.Crypto.RsaPublicEncrypt(tmp.Length, tmp, destination, key, rsaPadding);
+ }
+ finally
+ {
+ CryptographicOperations.ZeroMemory(tmp);
+ ArrayPool<byte>.Shared.Return(rented);
+ }
+ }
+ else
+ {
+ Debug.Assert(rsaPadding != Interop.Crypto.RsaPadding.NoPadding);
+
+ returnValue = Interop.Crypto.RsaPublicEncrypt(data.Length, data, destination, key, rsaPadding);
+ }
+
CheckReturn(returnValue);
bytesWritten = returnValue;
+ Debug.Assert(returnValue == rsaSize);
return true;
+
}
- private static Interop.Crypto.RsaPadding GetInteropPadding(RSAEncryptionPadding padding) =>
- padding == RSAEncryptionPadding.Pkcs1 ? Interop.Crypto.RsaPadding.Pkcs1 :
- padding == RSAEncryptionPadding.OaepSHA1 ? Interop.Crypto.RsaPadding.OaepSHA1 :
+ private static Interop.Crypto.RsaPadding GetInteropPadding(
+ RSAEncryptionPadding padding,
+ out RsaPaddingProcessor rsaPaddingProcessor)
+ {
+ if (padding == RSAEncryptionPadding.Pkcs1)
+ {
+ rsaPaddingProcessor = null;
+ return Interop.Crypto.RsaPadding.Pkcs1;
+ }
+
+ if (padding == RSAEncryptionPadding.OaepSHA1)
+ {
+ rsaPaddingProcessor = null;
+ return Interop.Crypto.RsaPadding.OaepSHA1;
+ }
+
+ if (padding.Mode == RSAEncryptionPaddingMode.Oaep)
+ {
+ rsaPaddingProcessor = RsaPaddingProcessor.OpenProcessor(padding.OaepHashAlgorithm);
+ return Interop.Crypto.RsaPadding.NoPadding;
+ }
+
throw PaddingModeNotSupported();
+ }
public override RSAParameters ExportParameters(bool includePrivateParameters)
{
@@ -389,8 +513,8 @@ namespace System.Security.Cryptography
protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) =>
AsymmetricAlgorithmHelpers.HashData(data, hashAlgorithm);
- protected override bool TryHashData(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) =>
- AsymmetricAlgorithmHelpers.TryHashData(source, destination, hashAlgorithm, out bytesWritten);
+ protected override bool TryHashData(ReadOnlySpan<byte> data, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) =>
+ AsymmetricAlgorithmHelpers.TryHashData(data, destination, hashAlgorithm, out bytesWritten);
public override byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding)
{
@@ -400,43 +524,29 @@ namespace System.Security.Cryptography
throw HashAlgorithmNameNullOrEmpty();
if (padding == null)
throw new ArgumentNullException(nameof(padding));
- if (padding != RSASignaturePadding.Pkcs1)
- throw PaddingModeNotSupported();
-
- return SignHash(hash, hashAlgorithm);
- }
-
- private byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithmName)
- {
- int algorithmNid = GetAlgorithmNid(hashAlgorithmName);
- SafeRsaHandle rsa = _key.Value;
- byte[] signature = new byte[Interop.Crypto.RsaSize(rsa)];
- int signatureSize;
- bool success = Interop.Crypto.RsaSign(
- algorithmNid,
+ if (!TrySignHash(
hash,
- hash.Length,
- signature,
- out signatureSize,
- rsa);
-
- if (!success)
+ Span<byte>.Empty,
+ hashAlgorithm, padding,
+ true,
+ out int bytesWritten,
+ out byte[] signature))
{
- throw Interop.Crypto.CreateOpenSslCryptographicException();
+ Debug.Fail("TrySignHash should not return false in allocation mode");
+ throw new CryptographicException();
}
- Debug.Assert(
- signatureSize == signature.Length,
- "RSA_sign reported an unexpected signature size",
- "RSA_sign reported signatureSize was {0}, when {1} was expected",
- signatureSize,
- signature.Length);
-
+ Debug.Assert(signature != null);
return signature;
}
- public override bool TrySignHash(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding, out int bytesWritten)
+ public override bool TrySignHash(
+ ReadOnlySpan<byte> hash,
+ Span<byte> destination,
+ HashAlgorithmName hashAlgorithm,
+ RSASignaturePadding padding,
+ out int bytesWritten)
{
if (string.IsNullOrEmpty(hashAlgorithm.Name))
{
@@ -446,30 +556,110 @@ namespace System.Security.Cryptography
{
throw new ArgumentNullException(nameof(padding));
}
- if (padding != RSASignaturePadding.Pkcs1)
- {
- throw PaddingModeNotSupported();
- }
- int algorithmNid = GetAlgorithmNid(hashAlgorithm);
- SafeRsaHandle rsa = _key.Value;
+ bool ret = TrySignHash(
+ hash,
+ destination,
+ hashAlgorithm,
+ padding,
+ false,
+ out bytesWritten,
+ out byte[] alloced);
+
+ Debug.Assert(alloced == null);
+ return ret;
+ }
+
+ private bool TrySignHash(
+ ReadOnlySpan<byte> hash,
+ Span<byte> destination,
+ HashAlgorithmName hashAlgorithm,
+ RSASignaturePadding padding,
+ bool allocateSignature,
+ out int bytesWritten,
+ out byte[] signature)
+ {
+ Debug.Assert(!string.IsNullOrEmpty(hashAlgorithm.Name));
+ Debug.Assert(padding != null);
+
+ signature = null;
+
+ // Do not factor out getting _key.Value, since the key creation should not happen on
+ // invalid padding modes.
- int bytesRequired = Interop.Crypto.RsaSize(rsa);
- if (destination.Length < bytesRequired)
+ if (padding.Mode == RSASignaturePaddingMode.Pkcs1)
{
- bytesWritten = 0;
- return false;
- }
+ int algorithmNid = GetAlgorithmNid(hashAlgorithm);
+ SafeRsaHandle rsa = _key.Value;
+
+ int bytesRequired = Interop.Crypto.RsaSize(rsa);
+
+ if (allocateSignature)
+ {
+ Debug.Assert(destination.Length == 0);
+ signature = new byte[bytesRequired];
+ destination = signature;
+ }
- int signatureSize;
- if (!Interop.Crypto.RsaSign(algorithmNid, source, source.Length, destination, out signatureSize, rsa))
+ if (destination.Length < bytesRequired)
+ {
+ bytesWritten = 0;
+ return false;
+ }
+
+ if (!Interop.Crypto.RsaSign(algorithmNid, hash, hash.Length, destination, out int signatureSize, rsa))
+ {
+ throw Interop.Crypto.CreateOpenSslCryptographicException();
+ }
+
+ Debug.Assert(
+ signatureSize == bytesRequired,
+ $"RSA_sign reported signatureSize was {signatureSize}, when {bytesRequired} was expected");
+
+ bytesWritten = signatureSize;
+ return true;
+ }
+ else if (padding.Mode == RSASignaturePaddingMode.Pss)
{
- throw Interop.Crypto.CreateOpenSslCryptographicException();
+ RsaPaddingProcessor processor = RsaPaddingProcessor.OpenProcessor(hashAlgorithm);
+ SafeRsaHandle rsa = _key.Value;
+
+ int bytesRequired = Interop.Crypto.RsaSize(rsa);
+
+ if (allocateSignature)
+ {
+ Debug.Assert(destination.Length == 0);
+ signature = new byte[bytesRequired];
+ destination = signature;
+ }
+
+ if (destination.Length < bytesRequired)
+ {
+ bytesWritten = 0;
+ return false;
+ }
+
+ byte[] pssRented = ArrayPool<byte>.Shared.Rent(bytesRequired);
+ Span<byte> pssBytes = new Span<byte>(pssRented, 0, bytesRequired);
+
+ processor.EncodePss(hash, pssBytes, KeySize);
+
+ int ret = Interop.Crypto.RsaSignPrimitive(pssBytes, destination, rsa);
+
+ pssBytes.Clear();
+ ArrayPool<byte>.Shared.Return(pssRented);
+
+ CheckReturn(ret);
+
+ Debug.Assert(
+ ret == bytesRequired,
+ $"RSA_private_encrypt returned {ret} when {bytesRequired} was expected");
+
+ bytesWritten = ret;
+ return true;
}
- Debug.Assert(signatureSize == bytesRequired, $"RSA_sign reported signatureSize was {signatureSize}, when {bytesRequired} was expected");
- bytesWritten = signatureSize;
- return true;
+ throw PaddingModeNotSupported();
}
public override bool VerifyHash(
@@ -500,14 +690,53 @@ namespace System.Security.Cryptography
{
throw new ArgumentNullException(nameof(padding));
}
- if (padding != RSASignaturePadding.Pkcs1)
+
+ if (padding == RSASignaturePadding.Pkcs1)
{
- throw PaddingModeNotSupported();
+ int algorithmNid = GetAlgorithmNid(hashAlgorithm);
+ SafeRsaHandle rsa = _key.Value;
+ return Interop.Crypto.RsaVerify(algorithmNid, hash, hash.Length, signature, signature.Length, rsa);
}
+ else if (padding == RSASignaturePadding.Pss)
+ {
+ RsaPaddingProcessor processor = RsaPaddingProcessor.OpenProcessor(hashAlgorithm);
+ SafeRsaHandle rsa = _key.Value;
- int algorithmNid = GetAlgorithmNid(hashAlgorithm);
- SafeRsaHandle rsa = _key.Value;
- return Interop.Crypto.RsaVerify(algorithmNid, hash, hash.Length, signature, signature.Length, rsa);
+ int requiredBytes = Interop.Crypto.RsaSize(rsa);
+
+ if (signature.Length != requiredBytes)
+ {
+ return false;
+ }
+
+ if (hash.Length != processor.HashLength)
+ {
+ return false;
+ }
+
+ byte[] rented = ArrayPool<byte>.Shared.Rent(requiredBytes);
+ Span<byte> unwrapped = new Span<byte>(rented, 0, requiredBytes);
+
+ try
+ {
+ int ret = Interop.Crypto.RsaVerificationPrimitive(signature, unwrapped, rsa);
+
+ CheckReturn(ret);
+
+ Debug.Assert(
+ ret == requiredBytes,
+ $"RSA_private_encrypt returned {ret} when {requiredBytes} was expected");
+
+ return processor.VerifyPss(hash, unwrapped, KeySize);
+ }
+ finally
+ {
+ unwrapped.Clear();
+ ArrayPool<byte>.Shared.Return(rented);
+ }
+ }
+
+ throw PaddingModeNotSupported();
}
private static int GetAlgorithmNid(HashAlgorithmName hashAlgorithmName)
diff --git a/src/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs b/src/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs
index 23ba66fcdb..131b93fc86 100644
--- a/src/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs
+++ b/src/Common/src/System/Security/Cryptography/RSASecurityTransforms.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Buffers;
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography.Apple;
@@ -166,17 +167,94 @@ namespace System.Security.Cryptography
throw new ArgumentNullException(nameof(padding));
}
- return Interop.AppleCrypto.RsaEncrypt(GetKeys().PublicKey, data, padding);
+ // The size of encrypt is always the keysize (in ceiling-bytes)
+ int outputSize = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize);
+ byte[] output = new byte[outputSize];
+
+ if (!TryEncrypt(data, output, padding, out int bytesWritten))
+ {
+ Debug.Fail($"TryEncrypt with a preallocated buffer should not fail");
+ throw new CryptographicException();
+ }
+
+ Debug.Assert(bytesWritten == outputSize);
+ return output;
}
- public override bool TryEncrypt(ReadOnlySpan<byte> source, Span<byte> destination, RSAEncryptionPadding padding, out int bytesWritten)
+ public override bool TryEncrypt(ReadOnlySpan<byte> data, Span<byte> destination, RSAEncryptionPadding padding, out int bytesWritten)
{
if (padding == null)
{
throw new ArgumentNullException(nameof(padding));
}
- return Interop.AppleCrypto.TryRsaEncrypt(GetKeys().PublicKey, source, destination, padding, out bytesWritten);
+ int rsaSize = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize);
+
+ if (destination.Length < rsaSize)
+ {
+ bytesWritten = 0;
+ return false;
+ }
+
+ if (padding == RSAEncryptionPadding.Pkcs1 && data.Length > 0)
+ {
+ const int Pkcs1PaddingOverhead = 11;
+ int maxAllowed = rsaSize - Pkcs1PaddingOverhead;
+
+ if (data.Length > maxAllowed)
+ {
+ throw new CryptographicException(
+ SR.Format(SR.Cryptography_Encryption_MessageTooLong, maxAllowed));
+ }
+
+ return Interop.AppleCrypto.TryRsaEncrypt(
+ GetKeys().PublicKey,
+ data,
+ destination,
+ padding,
+ out bytesWritten);
+ }
+
+ RsaPaddingProcessor processor;
+
+ switch (padding.Mode)
+ {
+ case RSAEncryptionPaddingMode.Pkcs1:
+ processor = null;
+ break;
+ case RSAEncryptionPaddingMode.Oaep:
+ processor = RsaPaddingProcessor.OpenProcessor(padding.OaepHashAlgorithm);
+ break;
+ default:
+ throw new CryptographicException(SR.Cryptography_InvalidPaddingMode);
+ }
+
+ byte[] rented = ArrayPool<byte>.Shared.Rent(rsaSize);
+ Span<byte> tmp = new Span<byte>(rented, 0, rsaSize);
+
+ try
+ {
+ if (processor != null)
+ {
+ processor.PadOaep(data, tmp);
+ }
+ else
+ {
+ Debug.Assert(padding.Mode == RSAEncryptionPaddingMode.Pkcs1);
+ RsaPaddingProcessor.PadPkcs1Encryption(data, tmp);
+ }
+
+ return Interop.AppleCrypto.TryRsaEncryptionPrimitive(
+ GetKeys().PublicKey,
+ tmp,
+ destination,
+ out bytesWritten);
+ }
+ finally
+ {
+ tmp.Clear();
+ ArrayPool<byte>.Shared.Return(rented);
+ }
}
public override byte[] Decrypt(byte[] data, RSAEncryptionPadding padding)
@@ -197,10 +275,42 @@ namespace System.Security.Cryptography
throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey);
}
- return Interop.AppleCrypto.RsaDecrypt(keys.PrivateKey, data, padding);
+ if (padding.Mode == RSAEncryptionPaddingMode.Pkcs1)
+ {
+ int modulusSizeInBytes = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize);
+
+ if (data.Length > modulusSizeInBytes)
+ {
+ throw new CryptographicException(
+ SR.Format(SR.Cryptography_Padding_DecDataTooBig, modulusSizeInBytes));
+ }
+
+ return Interop.AppleCrypto.RsaDecrypt(keys.PrivateKey, data, padding);
+ }
+
+ int maxOutputSize = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize);
+ byte[] rented = ArrayPool<byte>.Shared.Rent(maxOutputSize);
+ Span<byte> contentsSpan = Span<byte>.Empty;
+
+ try
+ {
+ if (!TryDecrypt(keys.PrivateKey, data, rented, padding, out int bytesWritten))
+ {
+ Debug.Fail($"TryDecrypt returned false with a modulus-sized destination");
+ throw new CryptographicException();
+ }
+
+ contentsSpan = new Span<byte>(rented, 0, bytesWritten);
+ return contentsSpan.ToArray();
+ }
+ finally
+ {
+ CryptographicOperations.ZeroMemory(contentsSpan);
+ ArrayPool<byte>.Shared.Return(rented);
+ }
}
- public override bool TryDecrypt(ReadOnlySpan<byte> source, Span<byte> destination, RSAEncryptionPadding padding, out int bytesWritten)
+ public override bool TryDecrypt(ReadOnlySpan<byte> data, Span<byte> destination, RSAEncryptionPadding padding, out int bytesWritten)
{
if (padding == null)
{
@@ -214,7 +324,61 @@ namespace System.Security.Cryptography
throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey);
}
- return Interop.AppleCrypto.TryRsaDecrypt(keys.PrivateKey, source, destination, padding, out bytesWritten);
+ return TryDecrypt(keys.PrivateKey, data, destination, padding, out bytesWritten);
+ }
+
+ private bool TryDecrypt(
+ SafeSecKeyRefHandle privateKey,
+ ReadOnlySpan<byte> data,
+ Span<byte> destination,
+ RSAEncryptionPadding padding,
+ out int bytesWritten)
+ {
+ Debug.Assert(privateKey != null);
+
+ if (padding.Mode != RSAEncryptionPaddingMode.Pkcs1 &&
+ padding.Mode != RSAEncryptionPaddingMode.Oaep)
+ {
+ throw new CryptographicException(SR.Cryptography_InvalidPaddingMode);
+ }
+
+ int modulusSizeInBytes = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize);
+
+ if (data.Length > modulusSizeInBytes)
+ {
+ throw new CryptographicException(
+ SR.Format(SR.Cryptography_Padding_DecDataTooBig, modulusSizeInBytes));
+ }
+
+ if (padding.Mode == RSAEncryptionPaddingMode.Pkcs1 ||
+ padding == RSAEncryptionPadding.OaepSHA1)
+ {
+ return Interop.AppleCrypto.TryRsaDecrypt(privateKey, data, destination, padding, out bytesWritten);
+ }
+
+ Debug.Assert(padding.Mode == RSAEncryptionPaddingMode.Oaep);
+ RsaPaddingProcessor processor = RsaPaddingProcessor.OpenProcessor(padding.OaepHashAlgorithm);
+
+ byte[] rented = ArrayPool<byte>.Shared.Rent(modulusSizeInBytes);
+ Span<byte> unpaddedData = Span<byte>.Empty;
+
+ try
+ {
+ if (!Interop.AppleCrypto.TryRsaDecryptionPrimitive(privateKey, data, rented, out int paddedSize))
+ {
+ Debug.Fail($"Raw decryption failed with KeySize={KeySize} and a buffer length {rented.Length}");
+ throw new CryptographicException();
+ }
+
+ Debug.Assert(modulusSizeInBytes == paddedSize);
+ unpaddedData = new Span<byte>(rented, 0, paddedSize);
+ return processor.DepadOaep(unpaddedData, destination, out bytesWritten);
+ }
+ finally
+ {
+ CryptographicOperations.ZeroMemory(unpaddedData);
+ ArrayPool<byte>.Shared.Return(rented);
+ }
}
public override byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding)
@@ -225,39 +389,53 @@ namespace System.Security.Cryptography
throw HashAlgorithmNameNullOrEmpty();
if (padding == null)
throw new ArgumentNullException(nameof(padding));
- if (padding != RSASignaturePadding.Pkcs1)
- throw new CryptographicException(SR.Cryptography_InvalidPaddingMode);
-
- SecKeyPair keys = GetKeys();
- if (keys.PrivateKey == null)
+ if (padding == RSASignaturePadding.Pkcs1)
{
- throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey);
+ SecKeyPair keys = GetKeys();
+
+ if (keys.PrivateKey == null)
+ {
+ throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey);
+ }
+
+ int expectedSize;
+ Interop.AppleCrypto.PAL_HashAlgorithm palAlgId =
+ PalAlgorithmFromAlgorithmName(hashAlgorithm, out expectedSize);
+
+ if (hash.Length != expectedSize)
+ {
+ // Windows: NTE_BAD_DATA ("Bad Data.")
+ // OpenSSL: RSA_R_INVALID_MESSAGE_LENGTH ("invalid message length")
+ throw new CryptographicException(
+ SR.Format(
+ SR.Cryptography_BadHashSize_ForAlgorithm,
+ hash.Length,
+ expectedSize,
+ hashAlgorithm.Name));
+ }
+
+ return Interop.AppleCrypto.GenerateSignature(
+ keys.PrivateKey,
+ hash,
+ palAlgId);
}
- int expectedSize;
- Interop.AppleCrypto.PAL_HashAlgorithm palAlgId =
- PalAlgorithmFromAlgorithmName(hashAlgorithm, out expectedSize);
+ // A signature will always be the keysize (in ceiling-bytes) in length.
+ int outputSize = RsaPaddingProcessor.BytesRequiredForBitCount(KeySize);
+ byte[] output = new byte[outputSize];
- if (hash.Length != expectedSize)
+ if (!TrySignHash(hash, output, hashAlgorithm, padding, out int bytesWritten))
{
- // Windows: NTE_BAD_DATA ("Bad Data.")
- // OpenSSL: RSA_R_INVALID_MESSAGE_LENGTH ("invalid message length")
- throw new CryptographicException(
- SR.Format(
- SR.Cryptography_BadHashSize_ForAlgorithm,
- hash.Length,
- expectedSize,
- hashAlgorithm.Name));
+ Debug.Fail("TrySignHash failed with a pre-allocated buffer");
+ throw new CryptographicException();
}
- return Interop.AppleCrypto.GenerateSignature(
- keys.PrivateKey,
- hash,
- palAlgId);
+ Debug.Assert(bytesWritten == outputSize);
+ return output;
}
- public override bool TrySignHash(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding, out int bytesWritten)
+ public override bool TrySignHash(ReadOnlySpan<byte> hash, Span<byte> destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding, out int bytesWritten)
{
if (string.IsNullOrEmpty(hashAlgorithm.Name))
{
@@ -267,7 +445,14 @@ namespace System.Security.Cryptography
{
throw new ArgumentNullException(nameof(padding));
}
- if (padding != RSASignaturePadding.Pkcs1)
+
+ RsaPaddingProcessor processor = null;
+
+ if (padding.Mode == RSASignaturePaddingMode.Pss)
+ {
+ processor = RsaPaddingProcessor.OpenProcessor(hashAlgorithm);
+ }
+ else if (padding != RSASignaturePadding.Pkcs1)
{
throw new CryptographicException(SR.Cryptography_InvalidPaddingMode);
}
@@ -279,20 +464,61 @@ namespace System.Security.Cryptography
throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey);
}
- Interop.AppleCrypto.PAL_HashAlgorithm palAlgId = PalAlgorithmFromAlgorithmName(hashAlgorithm, out int expectedSize);
- if (source.Length != expectedSize)
+ int keySize = KeySize;
+ int rsaSize = RsaPaddingProcessor.BytesRequiredForBitCount(keySize);
+
+ if (processor == null)
{
- // Windows: NTE_BAD_DATA ("Bad Data.")
- // OpenSSL: RSA_R_INVALID_MESSAGE_LENGTH ("invalid message length")
- throw new CryptographicException(
- SR.Format(
- SR.Cryptography_BadHashSize_ForAlgorithm,
- source.Length,
- expectedSize,
- hashAlgorithm.Name));
+ Interop.AppleCrypto.PAL_HashAlgorithm palAlgId =
+ PalAlgorithmFromAlgorithmName(hashAlgorithm, out int expectedSize);
+
+ if (hash.Length != expectedSize)
+ {
+ // Windows: NTE_BAD_DATA ("Bad Data.")
+ // OpenSSL: RSA_R_INVALID_MESSAGE_LENGTH ("invalid message length")
+ throw new CryptographicException(
+ SR.Format(
+ SR.Cryptography_BadHashSize_ForAlgorithm,
+ hash.Length,
+ expectedSize,
+ hashAlgorithm.Name));
+ }
+
+ if (destination.Length < rsaSize)
+ {
+ bytesWritten = 0;
+ return false;
+ }
+
+ return Interop.AppleCrypto.TryGenerateSignature(
+ keys.PrivateKey,
+ hash,
+ destination,
+ palAlgId,
+ out bytesWritten);
+ }
+
+ Debug.Assert(padding.Mode == RSASignaturePaddingMode.Pss);
+
+ if (destination.Length < rsaSize)
+ {
+ bytesWritten = 0;
+ return false;
}
- return Interop.AppleCrypto.TryGenerateSignature(keys.PrivateKey, source, destination, palAlgId, out bytesWritten);
+ byte[] rented = ArrayPool<byte>.Shared.Rent(rsaSize);
+ Span<byte> buf = new Span<byte>(rented, 0, rsaSize);
+ processor.EncodePss(hash, buf, keySize);
+
+ try
+ {
+ return Interop.AppleCrypto.TryRsaSignaturePrimitive(keys.PrivateKey, buf, destination, out bytesWritten);
+ }
+ finally
+ {
+ CryptographicOperations.ZeroMemory(buf);
+ ArrayPool<byte>.Shared.Return(rented);
+ }
}
public override bool VerifyHash(
@@ -323,13 +549,57 @@ namespace System.Security.Cryptography
{
throw new ArgumentNullException(nameof(padding));
}
- if (padding != RSASignaturePadding.Pkcs1)
+
+ if (padding == RSASignaturePadding.Pkcs1)
{
- throw new CryptographicException(SR.Cryptography_InvalidPaddingMode);
+ Interop.AppleCrypto.PAL_HashAlgorithm palAlgId =
+ PalAlgorithmFromAlgorithmName(hashAlgorithm, out int expectedSize);
+ return Interop.AppleCrypto.VerifySignature(GetKeys().PublicKey, hash, signature, palAlgId);
+ }
+ else if (padding.Mode == RSASignaturePaddingMode.Pss)
+ {
+ RsaPaddingProcessor processor = RsaPaddingProcessor.OpenProcessor(hashAlgorithm);
+ SafeSecKeyRefHandle publicKey = GetKeys().PublicKey;
+
+ int keySize = KeySize;
+ int rsaSize = RsaPaddingProcessor.BytesRequiredForBitCount(keySize);
+
+ if (signature.Length != rsaSize)
+ {
+ return false;
+ }
+
+ if (hash.Length != processor.HashLength)
+ {
+ return false;
+ }
+
+ byte[] rented = ArrayPool<byte>.Shared.Rent(rsaSize);
+ Span<byte> unwrapped = new Span<byte>(rented, 0, rsaSize);
+
+ try
+ {
+ if (!Interop.AppleCrypto.TryRsaVerificationPrimitive(
+ publicKey,
+ signature,
+ unwrapped,
+ out int bytesWritten))
+ {
+ Debug.Fail($"TryRsaVerificationPrimitive with a pre-allocated buffer");
+ throw new CryptographicException();
+ }
+
+ Debug.Assert(bytesWritten == rsaSize);
+ return processor.VerifyPss(hash, unwrapped, keySize);
+ }
+ finally
+ {
+ unwrapped.Clear();
+ ArrayPool<byte>.Shared.Return(rented);
+ }
}
- Interop.AppleCrypto.PAL_HashAlgorithm palAlgId = PalAlgorithmFromAlgorithmName(hashAlgorithm, out int expectedSize);
- return Interop.AppleCrypto.VerifySignature(GetKeys().PublicKey, hash, signature, palAlgId);
+ throw new CryptographicException(SR.Cryptography_InvalidPaddingMode);
}
protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) =>
@@ -338,8 +608,8 @@ namespace System.Security.Cryptography
protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) =>
AsymmetricAlgorithmHelpers.HashData(data, hashAlgorithm);
- protected override bool TryHashData(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) =>
- AsymmetricAlgorithmHelpers.TryHashData(source, destination, hashAlgorithm, out bytesWritten);
+ protected override bool TryHashData(ReadOnlySpan<byte> data, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) =>
+ AsymmetricAlgorithmHelpers.TryHashData(data, destination, hashAlgorithm, out bytesWritten);
protected override void Dispose(bool disposing)
{
diff --git a/src/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs b/src/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs
new file mode 100644
index 0000000000..34de84e443
--- /dev/null
+++ b/src/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs
@@ -0,0 +1,559 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Buffers.Binary;
+using System.Collections.Concurrent;
+using System.Diagnostics;
+
+namespace System.Security.Cryptography
+{
+ internal sealed class RsaPaddingProcessor
+ {
+ private static readonly byte[] s_eightZeros = new byte[8];
+
+ private static readonly ConcurrentDictionary<HashAlgorithmName, RsaPaddingProcessor> s_lookup =
+ new ConcurrentDictionary<HashAlgorithmName, RsaPaddingProcessor>();
+
+ private readonly HashAlgorithmName _hashAlgorithmName;
+ private readonly int _hLen;
+
+ private RsaPaddingProcessor(HashAlgorithmName hashAlgorithmName, int hLen)
+ {
+ _hashAlgorithmName = hashAlgorithmName;
+ _hLen = hLen;
+ }
+
+ internal static int BytesRequiredForBitCount(int keySizeInBits)
+ {
+ return (int)(((uint)keySizeInBits + 7) / 8);
+ }
+
+ internal int HashLength => _hLen;
+
+ internal static RsaPaddingProcessor OpenProcessor(HashAlgorithmName hashAlgorithmName)
+ {
+ return s_lookup.GetOrAdd(
+ hashAlgorithmName,
+ alg =>
+ {
+ using (IncrementalHash hasher = IncrementalHash.CreateHash(hashAlgorithmName))
+ {
+ // SHA-2-512 is the biggest we expect
+ Span<byte> stackDest = stackalloc byte[512 / 8];
+
+ if (hasher.TryGetHashAndReset(stackDest, out int bytesWritten))
+ {
+ return new RsaPaddingProcessor(hashAlgorithmName, bytesWritten);
+ }
+
+ byte[] big = hasher.GetHashAndReset();
+ return new RsaPaddingProcessor(hashAlgorithmName, big.Length);
+ }
+ });
+ }
+
+ internal static void PadPkcs1Encryption(
+ ReadOnlySpan<byte> source,
+ Span<byte> destination)
+ {
+ // https://tools.ietf.org/html/rfc3447#section-7.2.1
+
+ int mLen = source.Length;
+ int k = destination.Length;
+
+ // 1. If mLen > k - 11, fail
+ if (mLen > k - 11)
+ {
+ throw new CryptographicException(SR.Cryptography_KeyTooSmall);
+ }
+
+ // 2(b). EM is composed of 00 02 [PS] 00 [M]
+ Span<byte> mInEM = destination.Slice(destination.Length - source.Length);
+ Span<byte> ps = destination.Slice(2, destination.Length - source.Length - 3);
+ destination[0] = 0;
+ destination[1] = 2;
+ destination[ps.Length + 2] = 0;
+
+ // 2(a). Fill PS with random data from a CSPRNG, but no zero-values.
+ FillNonZeroBytes(ps);
+
+ source.CopyTo(mInEM);
+ }
+
+ internal void PadOaep(
+ ReadOnlySpan<byte> source,
+ Span<byte> destination)
+ {
+ // https://tools.ietf.org/html/rfc3447#section-7.1.1
+
+ byte[] dbMask = null;
+ Span<byte> dbMaskSpan = Span<byte>.Empty;
+
+ try
+ {
+ // Since the biggest known _hLen is 512/8 (64) and destination.Length is 0 or more,
+ // this shouldn't underflow without something having severely gone wrong.
+ int maxInput = checked(destination.Length - _hLen - _hLen - 2);
+
+ // 1(a) does not apply, we do not allow custom label values.
+
+ // 1(b)
+ if (source.Length > maxInput)
+ {
+ throw new CryptographicException(
+ SR.Format(SR.Cryptography_Encryption_MessageTooLong, maxInput));
+ }
+
+ // The final message (step 2(i)) will be
+ // 0x00 || maskedSeed (hLen long) || maskedDB (rest of the buffer)
+ Span<byte> seed = destination.Slice(1, _hLen);
+ Span<byte> db = destination.Slice(1 + _hLen);
+
+ using (IncrementalHash hasher = IncrementalHash.CreateHash(_hashAlgorithmName))
+ {
+ // DB = lHash || PS || 0x01 || M
+ Span<byte> lHash = db.Slice(0, _hLen);
+ Span<byte> mDest = db.Slice(db.Length - source.Length);
+ Span<byte> ps = db.Slice(_hLen, db.Length - _hLen - 1 - mDest.Length);
+ Span<byte> psEnd = db.Slice(_hLen + ps.Length, 1);
+
+ // 2(a) lHash = Hash(L), where L is the empty string.
+ if (!hasher.TryGetHashAndReset(lHash, out int hLen2) || hLen2 != _hLen)
+ {
+ Debug.Fail("TryGetHashAndReset failed with exact-size destination");
+ throw new CryptographicException();
+ }
+
+ // 2(b) generate a padding string of all zeros equal to the amount of unused space.
+ ps.Clear();
+
+ // 2(c)
+ psEnd[0] = 0x01;
+
+ // still 2(c)
+ source.CopyTo(mDest);
+
+ // 2(d)
+ RandomNumberGenerator.Fill(seed);
+
+ // 2(e)
+ dbMask = ArrayPool<byte>.Shared.Rent(db.Length);
+ dbMaskSpan = new Span<byte>(dbMask, 0, db.Length);
+ Mgf1(hasher, seed, dbMaskSpan);
+
+ // 2(f)
+ Xor(db, dbMaskSpan);
+
+ // 2(g)
+ Span<byte> seedMask = stackalloc byte[_hLen];
+ Mgf1(hasher, db, seedMask);
+
+ // 2(h)
+ Xor(seed, seedMask);
+
+ // 2(i)
+ destination[0] = 0;
+ }
+ }
+ catch (Exception e) when (!(e is CryptographicException))
+ {
+ Debug.Fail("Bad exception produced from OAEP padding: " + e);
+ throw new CryptographicException();
+ }
+ finally
+ {
+ if (dbMask != null)
+ {
+ dbMaskSpan.Clear();
+ ArrayPool<byte>.Shared.Return(dbMask);
+ }
+ }
+ }
+
+ internal bool DepadOaep(
+ ReadOnlySpan<byte> source,
+ Span<byte> destination,
+ out int bytesWritten)
+ {
+ // https://tools.ietf.org/html/rfc3447#section-7.1.2
+ using (IncrementalHash hasher = IncrementalHash.CreateHash(_hashAlgorithmName))
+ {
+ Span<byte> lHash = stackalloc byte[_hLen];
+
+ if (!hasher.TryGetHashAndReset(lHash, out int hLen2) || hLen2 != _hLen)
+ {
+ Debug.Fail("TryGetHashAndReset failed with exact-size destination");
+ throw new CryptographicException();
+ }
+
+ int y = source[0];
+ ReadOnlySpan<byte> maskedSeed = source.Slice(1, _hLen);
+ ReadOnlySpan<byte> maskedDB = source.Slice(1 + _hLen);
+
+ Span<byte> seed = stackalloc byte[_hLen];
+ // seedMask = MGF(maskedDB, hLen)
+ Mgf1(hasher, maskedDB, seed);
+
+ // seed = seedMask XOR maskedSeed
+ Xor(seed, maskedSeed);
+
+ byte[] tmp = ArrayPool<byte>.Shared.Rent(source.Length);
+
+ try
+ {
+ Span<byte> dbMask = new Span<byte>(tmp, 0, maskedDB.Length);
+ // dbMask = MGF(seed, k - hLen - 1)
+ Mgf1(hasher, seed, dbMask);
+
+ // DB = dbMask XOR maskedDB
+ Xor(dbMask, maskedDB);
+
+ ReadOnlySpan<byte> lHashPrime = dbMask.Slice(0, _hLen);
+
+ int separatorPos = int.MaxValue;
+
+ for (int i = dbMask.Length - 1; i >= _hLen; i--)
+ {
+ // if dbMask[i] is 1, val is 0. otherwise val is [01,FF]
+ byte dbMinus1 = (byte)(dbMask[i] - 1);
+ int val = dbMinus1;
+
+ // if val is 0: FFFFFFFF & FFFFFFFF => FFFFFFFF
+ // if val is any other byte value, val-1 will be in the range 00000000 to 000000FE,
+ // and so the high bit will not be set.
+ val = (~val & (val - 1)) >> 31;
+
+ // if val is 0: separator = (0 & i) | (~0 & separator) => separator
+ // else: separator = (~0 & i) | (0 & separator) => i
+ //
+ // Net result: non-branching "if (dbMask[i] == 1) separatorPos = i;"
+ separatorPos = (val & i) | (~val & separatorPos);
+ }
+
+ bool lHashMatches = CryptographicOperations.FixedTimeEquals(lHash, lHashPrime);
+ bool yIsZero = y == 0;
+ bool separatorMadeSense = separatorPos < dbMask.Length;
+
+ // This intentionally uses non-short-circuiting operations to hide the timing
+ // differential between the three failure cases
+ bool shouldContinue = lHashMatches & yIsZero & separatorMadeSense;
+
+ if (!shouldContinue)
+ {
+ throw new CryptographicException(SR.Cryptography_OAEP_Decryption_Failed);
+ }
+
+ Span<byte> message = dbMask.Slice(separatorPos + 1);
+
+ if (message.Length <= destination.Length)
+ {
+ message.CopyTo(destination);
+ bytesWritten = message.Length;
+ return true;
+ }
+ else
+ {
+ bytesWritten = 0;
+ return false;
+ }
+ }
+ finally
+ {
+ Array.Clear(tmp, 0, source.Length);
+ ArrayPool<byte>.Shared.Return(tmp);
+ }
+ }
+ }
+
+ internal void EncodePss(ReadOnlySpan<byte> mHash, Span<byte> destination, int keySize)
+ {
+ // https://tools.ietf.org/html/rfc3447#section-9.1.1
+ int emBits = keySize - 1;
+ int emLen = BytesRequiredForBitCount(emBits);
+
+ if (mHash.Length != _hLen)
+ {
+ throw new CryptographicException(SR.Cryptography_SignHash_WrongSize);
+ }
+
+ // In this implementation, sLen is restricted to the length of the input hash.
+ int sLen = _hLen;
+
+ // 3. if emLen < hLen + sLen + 2, encoding error.
+ //
+ // sLen = hLen in this implementation.
+
+ if (emLen < 2 + _hLen + sLen)
+ {
+ throw new CryptographicException(SR.Cryptography_KeyTooSmall);
+ }
+
+ // Set any leading bytes to zero, since that will be required for the pending
+ // RSA operation.
+ destination.Slice(0, destination.Length - emLen).Clear();
+
+ // 12. Let EM = maskedDB || H || 0xbc (H has length hLen)
+ Span<byte> em = destination.Slice(destination.Length - emLen, emLen);
+
+ int dbLen = emLen - _hLen - 1;
+
+ Span<byte> db = em.Slice(0, dbLen);
+ Span<byte> hDest = em.Slice(dbLen, _hLen);
+ em[emLen - 1] = 0xBC;
+
+ byte[] dbMaskRented = ArrayPool<byte>.Shared.Rent(dbLen);
+ Span<byte> dbMask = new Span<byte>(dbMaskRented, 0, dbLen);
+
+ using (IncrementalHash hasher = IncrementalHash.CreateHash(_hashAlgorithmName))
+ {
+ // 4. Generate a random salt of length sLen
+ Span<byte> salt = stackalloc byte[sLen];
+ RandomNumberGenerator.Fill(salt);
+
+ // 5. Let M' = an octet string of 8 zeros concat mHash concat salt
+ // 6. Let H = Hash(M')
+
+ hasher.AppendData(s_eightZeros);
+ hasher.AppendData(mHash);
+ hasher.AppendData(salt);
+
+ if (!hasher.TryGetHashAndReset(hDest, out int hLen2) || hLen2 != _hLen)
+ {
+ Debug.Fail("TryGetHashAndReset failed with exact-size destination");
+ throw new CryptographicException();
+ }
+
+ // 7. Generate PS as zero-valued bytes of length emLen - sLen - hLen - 2.
+ // 8. Let DB = PS || 0x01 || salt
+ int psLen = emLen - sLen - _hLen - 2;
+ db.Slice(0, psLen).Clear();
+ db[psLen] = 0x01;
+ salt.CopyTo(db.Slice(psLen + 1));
+
+ // 9. Let dbMask = MGF(H, emLen - hLen - 1)
+ Mgf1(hasher, hDest, dbMask);
+
+ // 10. Let maskedDB = DB XOR dbMask
+ Xor(db, dbMask);
+
+ // 11. Set the "unused" bits in the leftmost byte of maskedDB to 0.
+ int unusedBits = 8 * emLen - emBits;
+
+ if (unusedBits != 0)
+ {
+ byte mask = (byte)(0xFF >> unusedBits);
+ db[0] &= mask;
+ }
+ }
+
+ dbMask.Clear();
+ ArrayPool<byte>.Shared.Return(dbMaskRented);
+ }
+
+ internal bool VerifyPss(ReadOnlySpan<byte> mHash, ReadOnlySpan<byte> em, int keySize)
+ {
+ // https://tools.ietf.org/html/rfc3447#section-9.1.2
+
+ int emBits = keySize - 1;
+ int emLen = BytesRequiredForBitCount(emBits);
+
+ if (mHash.Length != _hLen)
+ {
+ return false;
+ }
+
+ Debug.Assert(em.Length >= emLen);
+
+ // In this implementation, sLen is restricted to hLen.
+ int sLen = _hLen;
+
+ // 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop.
+ if (emLen < _hLen + sLen + 2)
+ {
+ return false;
+ }
+
+ // 4. If the last byte is not 0xBC, output "inconsistent" and stop.
+ if (em[em.Length - 1] != 0xBC)
+ {
+ return false;
+ }
+
+ // 5. maskedDB is the leftmost emLen - hLen -1 bytes, H is the next hLen bytes.
+ int dbLen = emLen - _hLen - 1;
+
+ ReadOnlySpan<byte> maskedDb = em.Slice(0, dbLen);
+ ReadOnlySpan<byte> h = em.Slice(dbLen, _hLen);
+
+ // 6. If the unused bits aren't zero, output "inconsistent" and stop.
+ int unusedBits = 8 * emLen - emBits;
+ byte usedBitsMask = (byte)(0xFF >> unusedBits);
+
+ if ((maskedDb[0] & usedBitsMask) != maskedDb[0])
+ {
+ return false;
+ }
+
+ // 7. dbMask = MGF(H, emLen - hLen - 1)
+ byte[] dbMaskRented = ArrayPool<byte>.Shared.Rent(maskedDb.Length);
+ Span<byte> dbMask = new Span<byte>(dbMaskRented, 0, maskedDb.Length);
+
+ try
+ {
+ using (IncrementalHash hasher = IncrementalHash.CreateHash(_hashAlgorithmName))
+ {
+ Mgf1(hasher, h, dbMask);
+
+ // 8. DB = maskedDB XOR dbMask
+ Xor(dbMask, maskedDb);
+
+ // 9. Set the unused bits of DB to 0
+ dbMask[0] &= usedBitsMask;
+
+ // 10 ("a"): If the emLen - hLen - sLen - 2 leftmost bytes are not 0,
+ // output "inconsistent" and stop.
+ //
+ // Since signature verification is a public key operation there's no need to
+ // use fixed time equality checking here.
+ for (int i = emLen - _hLen - sLen - 2 - 1; i >= 0; --i)
+ {
+ if (dbMask[i] != 0)
+ {
+ return false;
+ }
+ }
+
+ // 10 ("b") If the octet at position emLen - hLen - sLen - 1 (under a 1-indexed scheme)
+ // is not 0x01, output "inconsistent" and stop.
+ if (dbMask[emLen - _hLen - sLen - 2] != 0x01)
+ {
+ return false;
+ }
+
+ // 11. Let salt be the last sLen octets of DB.
+ ReadOnlySpan<byte> salt = dbMask.Slice(dbMask.Length - sLen);
+
+ // 12/13. Let H' = Hash(eight zeros || mHash || salt)
+ hasher.AppendData(s_eightZeros);
+ hasher.AppendData(mHash);
+ hasher.AppendData(salt);
+
+ Span<byte> hPrime = stackalloc byte[_hLen];
+
+ if (!hasher.TryGetHashAndReset(hPrime, out int hLen2) || hLen2 != _hLen)
+ {
+ Debug.Fail("TryGetHashAndReset failed with exact-size destination");
+ throw new CryptographicException();
+ }
+
+ // 14. If H = H' output "consistent". Otherwise, output "inconsistent"
+ //
+ // Since this is a public key operation, no need to provide fixed time
+ // checking.
+ return h.SequenceEqual(hPrime);
+ }
+ }
+ finally
+ {
+ dbMask.Clear();
+ ArrayPool<byte>.Shared.Return(dbMaskRented);
+ }
+ }
+
+ // https://tools.ietf.org/html/rfc3447#appendix-B.2.1
+ private void Mgf1(IncrementalHash hasher, ReadOnlySpan<byte> mgfSeed, Span<byte> mask)
+ {
+ Span<byte> writePtr = mask;
+ int count = 0;
+ Span<byte> bigEndianCount = stackalloc byte[sizeof(int)];
+
+ while (writePtr.Length > 0)
+ {
+ hasher.AppendData(mgfSeed);
+ BinaryPrimitives.WriteInt32BigEndian(bigEndianCount, count);
+ hasher.AppendData(bigEndianCount);
+
+ if (writePtr.Length >= _hLen)
+ {
+ if (!hasher.TryGetHashAndReset(writePtr, out int bytesWritten))
+ {
+ Debug.Fail($"TryGetHashAndReset failed with sufficient space");
+ throw new CryptographicException();
+ }
+
+ Debug.Assert(bytesWritten == _hLen);
+ writePtr = writePtr.Slice(bytesWritten);
+ }
+ else
+ {
+ Span<byte> tmp = stackalloc byte[_hLen];
+
+ if (!hasher.TryGetHashAndReset(tmp, out int bytesWritten))
+ {
+ Debug.Fail($"TryGetHashAndReset failed with sufficient space");
+ throw new CryptographicException();
+ }
+
+ Debug.Assert(bytesWritten == _hLen);
+ tmp.Slice(0, writePtr.Length).CopyTo(writePtr);
+ break;
+ }
+
+ count++;
+ }
+ }
+
+ // This is a copy of RandomNumberGeneratorImplementation.GetNonZeroBytes, but adapted
+ // to the object-less RandomNumberGenerator.Fill.
+ private static void FillNonZeroBytes(Span<byte> data)
+ {
+ while (data.Length > 0)
+ {
+ // Fill the remaining portion of the span with random bytes.
+ RandomNumberGenerator.Fill(data);
+
+ // Find the first zero in the remaining portion.
+ int indexOfFirst0Byte = data.Length;
+ for (int i = 0; i < data.Length; i++)
+ {
+ if (data[i] == 0)
+ {
+ indexOfFirst0Byte = i;
+ break;
+ }
+ }
+
+ // If there were any zeros, shift down all non-zeros.
+ for (int i = indexOfFirst0Byte + 1; i < data.Length; i++)
+ {
+ if (data[i] != 0)
+ {
+ data[indexOfFirst0Byte++] = data[i];
+ }
+ }
+
+ // Request new random bytes if necessary; dont re-use
+ // existing bytes since they were shifted down.
+ data = data.Slice(indexOfFirst0Byte);
+ }
+ }
+
+ /// <summary>
+ /// Bitwise XOR of <paramref name="b"/> into <paramref name="a"/>.
+ /// </summary>
+ private static void Xor(Span<byte> a, ReadOnlySpan<byte> b)
+ {
+ if (a.Length != b.Length)
+ {
+ throw new InvalidOperationException();
+ }
+
+ for (int i = 0; i < b.Length; i++)
+ {
+ a[i] ^= b[i];
+ }
+ }
+ }
+}
diff --git a/src/Common/src/System/Text/ValueStringBuilder.cs b/src/Common/src/System/Text/ValueStringBuilder.cs
deleted file mode 100644
index 84e5fa8de9..0000000000
--- a/src/Common/src/System/Text/ValueStringBuilder.cs
+++ /dev/null
@@ -1,200 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Buffers;
-using System.Diagnostics;
-using System.Runtime.CompilerServices;
-
-namespace System.Text
-{
- internal ref struct ValueStringBuilder
- {
- private char[] _arrayToReturnToPool;
- private Span<char> _chars;
- private int _pos;
-
- public ValueStringBuilder(Span<char> initialBuffer)
- {
- _arrayToReturnToPool = null;
- _chars = initialBuffer;
- _pos = 0;
- }
-
- public int Length
- {
- get => _pos;
- set
- {
- int delta = value - _pos;
- if (delta > 0)
- {
- Append('\0', delta);
- }
- else
- {
- _pos = value;
- }
- }
- }
-
- public override string ToString()
- {
- var s = new string(_chars.Slice(0, _pos));
- Clear();
- return s;
- }
-
- public bool TryCopyTo(Span<char> destination, out int charsWritten)
- {
- if (_chars.Slice(0, _pos).TryCopyTo(destination))
- {
- charsWritten = _pos;
- Clear();
- return true;
- }
- else
- {
- charsWritten = 0;
- Clear();
- return false;
- }
- }
-
- public void Insert(int index, char value, int count)
- {
- if (_pos > _chars.Length - count)
- {
- Grow(count);
- }
-
- int remaining = _pos - index;
- _chars.Slice(index, remaining).CopyTo(_chars.Slice(index + count));
- _chars.Slice(index, count).Fill(value);
- _pos += count;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Append(char c)
- {
- int pos = _pos;
- if (pos < _chars.Length)
- {
- _chars[pos] = c;
- _pos = pos + 1;
- }
- else
- {
- GrowAndAppend(c);
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Append(string s)
- {
- int pos = _pos;
- if (s.Length == 1 && pos < _chars.Length) // very common case, e.g. appending strings from NumberFormatInfo like separators, percent symbols, etc.
- {
- _chars[pos] = s[0];
- _pos = pos + 1;
- }
- else
- {
- AppendSlow(s);
- }
- }
-
- private void AppendSlow(string s)
- {
- int pos = _pos;
- if (pos > _chars.Length - s.Length)
- {
- Grow(s.Length);
- }
-
- bool copied = s.AsReadOnlySpan().TryCopyTo(_chars.Slice(pos));
- Debug.Assert(copied, "Grow should have made enough room to successfully copy");
- _pos += s.Length;
- }
-
- public void Append(char c, int count)
- {
- if (_pos > _chars.Length - count)
- {
- Grow(count);
- }
-
- Span<char> dst = _chars.Slice(_pos, count);
- for (int i = 0; i < dst.Length; i++)
- {
- dst[i] = c;
- }
- _pos += count;
- }
-
- public unsafe void Append(char* value, int length)
- {
- int pos = _pos;
- if (pos > _chars.Length - length)
- {
- Grow(length);
- }
-
- Span<char> dst = _chars.Slice(_pos, length);
- for (int i = 0; i < dst.Length; i++)
- {
- dst[i] = *value++;
- }
- _pos += length;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Span<char> AppendSpan(int length)
- {
- int origPos = _pos;
- if (origPos > _chars.Length - length)
- {
- Grow(length);
- }
-
- _pos = origPos + length;
- return _chars.Slice(origPos, length);
- }
-
- [MethodImpl(MethodImplOptions.NoInlining)]
- private void GrowAndAppend(char c)
- {
- Grow(1);
- Append(c);
- }
-
- [MethodImpl(MethodImplOptions.NoInlining)]
- private void Grow(int requiredAdditionalCapacity)
- {
- Debug.Assert(requiredAdditionalCapacity > _chars.Length - _pos);
-
- char[] poolArray = ArrayPool<char>.Shared.Rent(Math.Max(_pos + requiredAdditionalCapacity, _chars.Length * 2));
-
- bool success = _chars.TryCopyTo(poolArray);
- Debug.Assert(success);
-
- char[] toReturn = _arrayToReturnToPool;
- _chars = _arrayToReturnToPool = poolArray;
- if (toReturn != null)
- {
- ArrayPool<char>.Shared.Return(toReturn);
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void Clear()
- {
- char[] toReturn = _arrayToReturnToPool;
- this = default; // for safety, to avoid using pooled array if this instance is erroneously appended to again
- if (toReturn != null)
- {
- ArrayPool<char>.Shared.Return(toReturn);
- }
- }
- }
-}
diff --git a/src/Common/src/System/Text/ValueUtf8Converter.cs b/src/Common/src/System/Text/ValueUtf8Converter.cs
new file mode 100644
index 0000000000..3a2ba294db
--- /dev/null
+++ b/src/Common/src/System/Text/ValueUtf8Converter.cs
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+
+namespace System.Text
+{
+ /// <summary>
+ /// Helper to allow utilizing stack buffer for conversion to UTF-8. Will
+ /// switch to ArrayPool if not given enough memory. As such, make sure to
+ /// call Clear() to return any potentially rented buffer after conversion.
+ /// </summary>
+ internal ref struct ValueUtf8Converter
+ {
+ private byte[] _arrayToReturnToPool;
+ private Span<byte> _bytes;
+
+ public ValueUtf8Converter(Span<byte> initialBuffer)
+ {
+ _arrayToReturnToPool = null;
+ _bytes = initialBuffer;
+ }
+
+ public Span<byte> ConvertAndTerminateString(ReadOnlySpan<char> value)
+ {
+ int maxSize = Encoding.UTF8.GetMaxByteCount(value.Length) + 1;
+ if (_bytes.Length < maxSize)
+ {
+ Dispose();
+ _arrayToReturnToPool = ArrayPool<byte>.Shared.Rent(maxSize);
+ _bytes = new Span<byte>(_arrayToReturnToPool);
+ }
+
+ // Grab the bytes and null terminate
+ int byteCount = Encoding.UTF8.GetBytes(value, _bytes);
+ _bytes[byteCount] = 0;
+ return _bytes.Slice(0, byteCount + 1);
+ }
+
+ public void Dispose()
+ {
+ byte[] toReturn = _arrayToReturnToPool;
+ if (toReturn != null)
+ {
+ _arrayToReturnToPool = null;
+ ArrayPool<byte>.Shared.Return(toReturn);
+ }
+ }
+ }
+}
diff --git a/src/Common/tests/Common.Tests.csproj b/src/Common/tests/Common.Tests.csproj
index e5c4206d4f..f6432215a2 100644
--- a/src/Common/tests/Common.Tests.csproj
+++ b/src/Common/tests/Common.Tests.csproj
@@ -38,9 +38,6 @@
<Compile Include="$(CommonPath)\System\Collections\Generic\LargeArrayBuilder.cs">
<Link>Common\System\Collections\Generic\LargeArrayBuilder.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\IO\PathInternal.cs">
- <Link>Common\System\IO\PathInternal.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\System\IO\PathInternal.CaseSensitivity.cs">
<Link>Common\System\IO\PathInternal.CaseSensitivity.cs</Link>
</Compile>
@@ -62,25 +59,28 @@
<Compile Include="$(CommonPath)\System\Text\ReusableTextReader.cs">
<Link>Common\System\Text\ReusableTextReader.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Text\ValueStringBuilder.cs">
- <Link>Common\System\Text\ValueStringBuilder.cs</Link>
+ <Compile Include="$(CommonPath)\CoreLib\System\Text\ValueStringBuilder.cs">
+ <Link>Common\CoreLib\System\Text\ValueStringBuilder.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Security\IdentityHelper.cs">
<Link>Common\System\Security\IdentityHelper.cs</Link>
</Compile>
+ <Compile Include="..\src\System\PasteArguments.cs">
+ <Link>Common\System\PasteArguments.cs</Link>
+ </Compile>
<Compile Include="Tests\Interop\procfsTests.cs" />
<Compile Include="Tests\System\AssertExtensionTests.cs" />
<Compile Include="Tests\System\CharArrayHelpersTests.cs" />
+ <Compile Include="Tests\System\IO\PathInternal.Tests.cs" />
<Compile Include="Tests\System\IO\StringParserTests.cs" />
<Compile Include="Tests\System\MarvinTests.cs" />
+ <Compile Include="Tests\System\PasteArgumentsTests.cs" />
<Compile Include="Tests\System\Security\IdentityHelperTests.cs" />
<Compile Include="Tests\System\Text\ValueStringBuilderTests.cs" />
<Compile Include="Tests\System\StringExtensions.Tests.cs" />
<Compile Include="Tests\System\Collections\Generic\ArrayBuilderTests.cs" />
<Compile Include="Tests\System\Collections\Generic\LargeArrayBuilderTests.cs" />
- <Compile Include="Tests\System\IO\PathInternal_Unix_Tests.cs" />
<Compile Include="Tests\System\IO\RowConfigReaderTests.cs" />
- <Compile Include="Tests\System\IO\PathInternal.Tests.cs" />
<Compile Include="Tests\System\Net\HttpKnownHeaderNamesTests.cs" />
<Compile Include="System\Net\Sockets\Fletcher32.cs">
<Link>System\Net\Sockets\Fletcher32.cs</Link>
@@ -96,10 +96,13 @@
<Compile Include="$(CommonPath)\System\Threading\Tasks\TaskToApm.cs">
<Link>ProductionCode\Common\System\Threading\Tasks\TaskToApm.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\CoreLib\System\IO\PathInternal.cs">
+ <Link>Common\CoreLib\System\IO\PathInternal.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup Condition="'$(TargetsWindows)'=='true'">
- <Compile Include="$(CommonPath)\System\IO\PathInternal.Windows.cs">
- <Link>Common\System\IO\PathInternal.Windows.cs</Link>
+ <Compile Include="$(CommonPath)\CoreLib\System\IO\PathInternal.Windows.cs">
+ <Link>Common\CoreLib\System\IO\PathInternal.Windows.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\Interop.Libraries.cs">
<Link>Common\Interop\Windows\Interop.Libraries.cs</Link>
@@ -114,14 +117,18 @@
<Compile Include="$(CommonPath)\Interop\Windows\Interop.Errors.cs">
<Link>Common\Interop\Windows\Interop.Errors.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\IO\Win32Marshal.cs">
- <Link>Common\System\IO\Win32Marshal.cs</Link>
+ <Compile Include="$(CommonPath)\CoreLib\System\IO\Win32Marshal.cs">
+ <Link>Common\CoreLib\System\IO\Win32Marshal.cs</Link>
</Compile>
<Compile Include="Tests\System\IO\Win32Marshal.Tests.cs" />
+ <Compile Include="..\src\System\PasteArguments.Windows.cs">
+ <Link>Common\System\PasteArguments.Windows.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup Condition="'$(TargetsUnix)'=='true'">
- <Compile Include="..\src\System\IO\PathInternal.Unix.cs">
- <Link>Common\System\IO\PathInternal.Unix.cs</Link>
+ <Compile Include="Tests\System\IO\PathInternal.Unix.Tests.cs" />
+ <Compile Include="$(CommonPath)\CoreLib\System\IO\PathInternal.Unix.cs">
+ <Link>Common\CoreLib\System\IO\PathInternal.Unix.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.PathConf.cs">
<Link>Common\Interop\Unix\Interop.PathConf.cs</Link>
@@ -129,11 +136,15 @@
<Compile Include="$(CommonPath)\Interop\Unix\Interop.Libraries.cs">
<Link>Common\Interop\Unix\Interop.Libraries.cs</Link>
</Compile>
+ <Compile Include="..\src\System\PasteArguments.Unix.cs">
+ <Link>Common\System\PasteArguments.Unix.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup>
<Folder Include="CommonTest\System\" />
+ <Folder Include="Common\System\Security\Cryptography\" />
<Folder Include="System\Net\Sockets\" />
<Folder Include="System\Net\VirtualNetwork\" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project>
+</Project> \ No newline at end of file
diff --git a/src/Common/tests/Resources/Strings.resx b/src/Common/tests/Resources/Strings.resx
index 0cc24f087d..12dadae384 100644
--- a/src/Common/tests/Resources/Strings.resx
+++ b/src/Common/tests/Resources/Strings.resx
@@ -156,4 +156,7 @@
<data name="IO_PathTooLong_Path" xml:space="preserve">
<value>IO_PathTooLong_Path {0}</value>
</data>
+ <data name="Arg_InvalidSearchPattern" xml:space="preserve">
+ <value>Arg_InvalidSearchPattern {0}</value>
+ </data>
</root> \ No newline at end of file
diff --git a/src/Common/tests/System/Buffers/NativeOwnedMemory.cs b/src/Common/tests/System/Buffers/NativeOwnedMemory.cs
index f68a70e074..9e2c501cbf 100644
--- a/src/Common/tests/System/Buffers/NativeOwnedMemory.cs
+++ b/src/Common/tests/System/Buffers/NativeOwnedMemory.cs
@@ -53,10 +53,10 @@ namespace System.Buffers
public override unsafe Span<byte> Span => new Span<byte>((void*)_ptr, _length);
- public override unsafe MemoryHandle Pin(int offset = 0)
+ public override unsafe MemoryHandle Pin(int byteOffset = 0)
{
- if (offset < 0 || offset > _length) throw new ArgumentOutOfRangeException(nameof(offset));
- void* pointer = (void*)((byte*)_ptr + offset);
+ if (byteOffset < 0 || byteOffset > _length) throw new ArgumentOutOfRangeException(nameof(byteOffset));
+ void* pointer = (void*)((byte*)_ptr + byteOffset);
return new MemoryHandle(this, pointer);
}
@@ -106,9 +106,9 @@ namespace System.Buffers
}
}
- protected override bool TryGetArray(out ArraySegment<byte> arraySegment)
+ protected override bool TryGetArray(out ArraySegment<byte> segment)
{
- arraySegment = default(ArraySegment<byte>);
+ segment = default(ArraySegment<byte>);
return false;
}
}
diff --git a/src/Common/tests/System/Collections/TestBase.Generic.cs b/src/Common/tests/System/Collections/TestBase.Generic.cs
index 8d15dd06d1..de77894bdd 100644
--- a/src/Common/tests/System/Collections/TestBase.Generic.cs
+++ b/src/Common/tests/System/Collections/TestBase.Generic.cs
@@ -101,6 +101,8 @@ namespace System.Collections.Tests
return CreateSortedSet(enumerableToMatchTo, count, numberOfMatchingElements);
case EnumerableType.Queue:
return CreateQueue(enumerableToMatchTo, count, numberOfMatchingElements, numberOfDuplicateElements);
+ case EnumerableType.Lazy:
+ return CreateLazyEnumerable(enumerableToMatchTo, count, numberOfMatchingElements, numberOfDuplicateElements);
default:
Debug.Assert(false, "Check that the 'EnumerableType' Enum returns only types that are special-cased in the CreateEnumerable function within the Iset_Generic_Tests class");
return null;
@@ -289,6 +291,12 @@ namespace System.Collections.Tests
return set;
}
+ protected IEnumerable<T> CreateLazyEnumerable(IEnumerable<T> enumerableToMatchTo, int count, int numberOfMatchingElements, int numberOfDuplicateElements)
+ {
+ IEnumerable<T> list = CreateList(enumerableToMatchTo, count, numberOfMatchingElements, numberOfDuplicateElements);
+ return list.Select(item => item);
+ }
+
#endregion
}
}
diff --git a/src/Common/tests/System/Collections/TestBase.NonGeneric.cs b/src/Common/tests/System/Collections/TestBase.NonGeneric.cs
index 3184d85c19..9bd31862fa 100644
--- a/src/Common/tests/System/Collections/TestBase.NonGeneric.cs
+++ b/src/Common/tests/System/Collections/TestBase.NonGeneric.cs
@@ -25,7 +25,8 @@ namespace System.Collections.Tests
HashSet,
SortedSet,
List,
- Queue
+ Queue,
+ Lazy,
};
#endregion
diff --git a/src/Common/tests/System/IO/Compression/CompressionStreamPerfTestBase.cs b/src/Common/tests/System/IO/Compression/CompressionStreamPerfTestBase.cs
index 43af3eb4df..aaba317858 100644
--- a/src/Common/tests/System/IO/Compression/CompressionStreamPerfTestBase.cs
+++ b/src/Common/tests/System/IO/Compression/CompressionStreamPerfTestBase.cs
@@ -10,52 +10,34 @@ namespace System.IO.Compression
{
public abstract class CompressionStreamPerfTestBase : CompressionStreamTestBase
{
- public static IEnumerable<object[]> CanterburyCorpus_WithCompressionLevel()
+ public static IEnumerable<object[]> UncompressedTestFiles_WithCompressionLevel()
{
foreach (CompressionLevel compressionLevel in Enum.GetValues(typeof(CompressionLevel)))
{
- foreach (object[] canterburyWithoutLevel in CanterburyCorpus())
+ foreach (object[] testFile in UncompressedTestFiles())
{
- yield return new object[] { canterburyWithoutLevel[0], canterburyWithoutLevel[1], compressionLevel };
+ yield return new object[] { testFile[0], compressionLevel };
}
}
}
- public static IEnumerable<object[]> CanterburyCorpus()
- {
- foreach (int innerIterations in new int[] { 1, 10 })
- {
- foreach (var fileName in UncompressedTestFiles())
- {
- yield return new object[] { innerIterations, fileName[0] };
- }
- }
- }
-
-
/// <summary>
/// Benchmark tests to measure the performance of individually compressing each file in the
/// Canterbury Corpus
/// </summary>
- [Benchmark]
- [MemberData(nameof(CanterburyCorpus_WithCompressionLevel))]
- public void Compress_Canterbury(int innerIterations, string uncompressedFileName, CompressionLevel compressLevel)
+ [Benchmark(InnerIterationCount=10)] // limits the max iterations to 100
+ [MemberData(nameof(UncompressedTestFiles_WithCompressionLevel))]
+ public void Compress_Canterbury(string uncompressedFileName, CompressionLevel compressLevel)
{
byte[] bytes = File.ReadAllBytes(uncompressedFileName);
- MemoryStream[] compressedDataStreams = new MemoryStream[innerIterations];
foreach (var iteration in Benchmark.Iterations)
{
// resizing a memory stream during compression will throw off our results, so pre-size it to the
// size of our input
- for (int i = 0; i < innerIterations; i++)
- compressedDataStreams[i] = new MemoryStream(bytes.Length);
+ using (MemoryStream compressedDataStream = new MemoryStream(bytes.Length))
using (iteration.StartMeasurement())
- for (int i = 0; i < innerIterations; i++)
- using (Stream compressor = CreateStream(compressedDataStreams[i], compressLevel))
- compressor.Write(bytes, 0, bytes.Length);
-
- for (int i = 0; i < innerIterations; i++)
- compressedDataStreams[i].Dispose();
+ using (Stream compressor = CreateStream(compressedDataStream, compressLevel))
+ compressor.Write(bytes, 0, bytes.Length);
}
}
@@ -63,10 +45,11 @@ namespace System.IO.Compression
/// Benchmark tests to measure the performance of individually compressing each file in the
/// Canterbury Corpus
/// </summary>
- [Benchmark]
- [MemberData(nameof(CanterburyCorpus))]
- public void Decompress_Canterbury(int innerIterations, string uncompressedFilePath)
+ [Benchmark(InnerIterationCount=100)]
+ [MemberData(nameof(UncompressedTestFiles))]
+ public void Decompress_Canterbury(string uncompressedFilePath)
{
+ int innerIterations = (int)Benchmark.InnerIterationCount;
string compressedFilePath = CompressedTestFile(uncompressedFilePath);
byte[] outputRead = new byte[new FileInfo(uncompressedFilePath).Length];
MemoryStream[] memories = new MemoryStream[innerIterations];
diff --git a/src/Common/tests/System/IO/Compression/CompressionStreamUnitTestBase.cs b/src/Common/tests/System/IO/Compression/CompressionStreamUnitTestBase.cs
index e6585de33a..1a82bdf9e4 100644
--- a/src/Common/tests/System/IO/Compression/CompressionStreamUnitTestBase.cs
+++ b/src/Common/tests/System/IO/Compression/CompressionStreamUnitTestBase.cs
@@ -178,48 +178,6 @@ namespace System.IO.Compression
}
[Fact]
- public virtual void Dispose_WithUnfinishedWriteAsync()
- {
- byte[] buffer = new byte[100000];
- Random rand = new Random();
- rand.NextBytes(buffer);
-
- using (var writeStream = new ManualSyncMemoryStream(false))
- {
- var compressor = CreateStream(writeStream, CompressionMode.Compress, leaveOpen: true);
- compressor.Write(buffer, 0, buffer.Length);
- int writesBeingFlushed = 2;
- Task task = null;
- try
- {
- // Write needs to be big enough to trigger a write to the underlying base stream so the WriteAsync call doesn't immediately complete.
- task = compressor.WriteAsync(buffer, 0, buffer.Length);
- while (task.IsCompleted)
- {
- rand.NextBytes(buffer);
- task = compressor.WriteAsync(buffer, 0, buffer.Length);
- writesBeingFlushed++;
- }
-
- // WriteAsync will be blocked on writing the output to the underlying stream. Calling Dispose will trigger a Finish call with unwritten output
- // still available.
- Assert.InRange(writeStream.Length, 0, buffer.Length);
- compressor.Dispose();
- Assert.InRange(writeStream.Length, 0, buffer.Length * writesBeingFlushed);
- Assert.False(task.IsCompleted);
- }
- finally
- {
- // Unblock Async operations
- writeStream.manualResetEvent.Set();
- // WriteAsync call will return to the compression stream's WriteAsync which will attempt to
- // access members of the now disposed stream.
- Assert.Throws<AggregateException>(() => task.Wait(1000));
- }
- }
- }
-
- [Fact]
public virtual async Task Dispose_WithUnfinishedReadAsync()
{
string compressedPath = CompressedTestFile(UncompressedTestFile());
@@ -1360,7 +1318,7 @@ namespace System.IO.Compression
}
#if STREAM_MEMORY_OVERLOADS_AVAILABLE
- public override async ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken)
+ public override async ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken)
{
ReadHit = true;
@@ -1372,10 +1330,10 @@ namespace System.IO.Compression
{
await Task.Run(() => manualResetEvent.Wait(cancellationToken)).ConfigureAwait(false);
}
- return await base.ReadAsync(destination, cancellationToken);
+ return await base.ReadAsync(buffer, cancellationToken);
}
- public override async Task WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken)
+ public override async ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken)
{
WriteHit = true;
@@ -1388,7 +1346,7 @@ namespace System.IO.Compression
await Task.Run(() => manualResetEvent.Wait(cancellationToken)).ConfigureAwait(false);
}
- await base.WriteAsync(source, cancellationToken);
+ await base.WriteAsync(buffer, cancellationToken);
}
#endif
}
diff --git a/src/Common/tests/System/Net/Configuration.Certificates.cs b/src/Common/tests/System/Net/Configuration.Certificates.cs
index b8793be938..3407926342 100644
--- a/src/Common/tests/System/Net/Configuration.Certificates.cs
+++ b/src/Common/tests/System/Net/Configuration.Certificates.cs
@@ -19,7 +19,7 @@ namespace System.Net.Test.Common
private const string CertificatePassword = "testcertificate";
private const string TestDataFolder = "TestData";
- private static Mutex m;
+ private static readonly Mutex m;
private const int MutexTimeout = 120 * 1000;
static Certificates()
@@ -57,12 +57,11 @@ namespace System.Net.Test.Common
private static X509Certificate2Collection GetCertificateCollection(string certificateFileName)
{
- // On Windows, .Net Core applications should not import PFX files in parallel to avoid a known system-level race condition.
+ // On Windows, .NET Core applications should not import PFX files in parallel to avoid a known system-level race condition.
// This bug results in corrupting the X509Certificate2 certificate state.
+ Assert.True(m.WaitOne(MutexTimeout), "Cannot acquire the global certificate mutex.");
try
{
- Assert.True(m.WaitOne(MutexTimeout), "Cannot acquire the global certificate mutex.");
-
var certCollection = new X509Certificate2Collection();
certCollection.Import(Path.Combine(TestDataFolder, certificateFileName), CertificatePassword, X509KeyStorageFlags.DefaultKeySet);
diff --git a/src/Common/tests/System/Net/Configuration.Http.cs b/src/Common/tests/System/Net/Configuration.Http.cs
index 94c2c31f23..81961a637e 100644
--- a/src/Common/tests/System/Net/Configuration.Http.cs
+++ b/src/Common/tests/System/Net/Configuration.Http.cs
@@ -8,14 +8,14 @@ namespace System.Net.Test.Common
{
public static partial class Http
{
- private static readonly string DefaultAzureServer = "corefx-net.cloudapp.net";
+ private static readonly string DefaultAzureServer = "corefx-net.cloudapp.net";
public static string Host => GetValue("COREFX_HTTPHOST", DefaultAzureServer);
public static string SecureHost => GetValue("COREFX_SECUREHTTPHOST", DefaultAzureServer);
public static string Http2Host => GetValue("COREFX_HTTP2HOST", "http2.akamai.com");
-
+
// This server doesn't use HTTP/2 server push (push promise) feature. Some HttpClient implementations
// don't support servers that use push right now.
public static string Http2NoPushHost => GetValue("COREFX_HTTP2NOPUSHHOST", "www.microsoft.com");
@@ -26,8 +26,6 @@ namespace System.Net.Test.Common
public static string DomainJoinedProxyPort => GetValue("COREFX_DOMAINJOINED_PROXYPORT");
- public static bool StressEnabled => GetValue("COREFX_STRESS_HTTP", "0") == "1";
-
public static string SSLv2RemoteServer => GetValue("COREFX_HTTPHOST_SSL2", "https://www.ssllabs.com:10200/");
public static string SSLv3RemoteServer => GetValue("COREFX_HTTPHOST_SSL3", "https://www.ssllabs.com:10300/");
public static string TLSv10RemoteServer => GetValue("COREFX_HTTPHOST_TLS10", "https://www.ssllabs.com:10301/");
@@ -139,7 +137,7 @@ namespace System.Net.Test.Common
statusCode,
destination);
}
-
+
return new Uri(uriString);
}
@@ -147,14 +145,14 @@ namespace System.Net.Test.Common
{
Uri destinationUri = BasicAuthUriForCreds(secure, userName, password);
string destination = Uri.EscapeDataString(destinationUri.AbsoluteUri);
-
+
return new Uri(string.Format("{0}://{1}/{2}?statuscode={3}&uri={4}",
secure ? HttpsScheme : HttpScheme,
Host,
RedirectHandler,
statusCode,
destination));
- }
+ }
}
}
}
diff --git a/src/Common/tests/System/Net/Configuration.WebSockets.cs b/src/Common/tests/System/Net/Configuration.WebSockets.cs
index a6752c9417..f549a9d56f 100644
--- a/src/Common/tests/System/Net/Configuration.WebSockets.cs
+++ b/src/Common/tests/System/Net/Configuration.WebSockets.cs
@@ -8,6 +8,8 @@ namespace System.Net.Test.Common
{
public static partial class WebSockets
{
+ public static string ProxyServerUri => GetValue("COREFX_WEBSOCKETPROXYSERVERURI");
+
public static string Host => GetValue("COREFX_WEBSOCKETHOST", DefaultAzureServer);
public static string SecureHost => GetValue("COREFX_SECUREWEBSOCKETHOST", DefaultAzureServer);
diff --git a/src/Common/tests/System/Net/Http/LoopbackServer.AuthenticationHelpers.cs b/src/Common/tests/System/Net/Http/LoopbackServer.AuthenticationHelpers.cs
new file mode 100644
index 0000000000..6f19c6d769
--- /dev/null
+++ b/src/Common/tests/System/Net/Http/LoopbackServer.AuthenticationHelpers.cs
@@ -0,0 +1,305 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace System.Net.Test.Common
+{
+ public sealed partial class LoopbackServer
+ {
+ internal enum AuthenticationProtocols
+ {
+ Basic,
+ Digest,
+ None
+ }
+
+ public async Task<List<string>> AcceptConnectionPerformAuthenticationAndCloseAsync(string authenticateHeaders)
+ {
+ List<string> lines = null;
+ await AcceptConnectionAsync(async connection =>
+ {
+ string headerName = _options.IsProxy ? "Proxy-Authorization" : "Authorization";
+ lines = await connection.ReadRequestHeaderAsync();
+ if (GetRequestHeaderValue(lines, headerName) == null)
+ {
+ await connection.SendResponseAsync( _options.IsProxy ?
+ HttpStatusCode.ProxyAuthenticationRequired : HttpStatusCode.Unauthorized, authenticateHeaders);
+
+ lines = await connection.ReadRequestHeaderAsync();
+ }
+ Debug.Assert(lines.Count > 0);
+
+ int index = lines[0] != null ? lines[0].IndexOf(' ') : -1;
+ string requestMethod = null;
+ if (index != -1)
+ {
+ requestMethod = lines[0].Substring(0, index);
+ }
+
+ // Read the authorization header from client.
+ AuthenticationProtocols protocol = AuthenticationProtocols.None;
+ string clientResponse = null;
+ for (int i = 1; i < lines.Count; i++)
+ {
+ if (lines[i].StartsWith(headerName))
+ {
+ clientResponse = lines[i];
+ if (lines[i].Contains(nameof(AuthenticationProtocols.Basic)))
+ {
+ protocol = AuthenticationProtocols.Basic;
+ break;
+ }
+ else if (lines[i].Contains(nameof(AuthenticationProtocols.Digest)))
+ {
+ protocol = AuthenticationProtocols.Digest;
+ break;
+ }
+ }
+ }
+
+ bool success = false;
+ switch (protocol)
+ {
+ case AuthenticationProtocols.Basic:
+ success = IsBasicAuthTokenValid(clientResponse, _options);
+ break;
+
+ case AuthenticationProtocols.Digest:
+ // Read the request content.
+ success = IsDigestAuthTokenValid(clientResponse, requestMethod, _options);
+ break;
+ }
+
+ if (success)
+ {
+ await connection.SendResponseAsync();
+ }
+ else
+ {
+ await connection.SendResponseAsync(HttpStatusCode.Unauthorized, authenticateHeaders);
+ }
+ });
+
+ return lines;
+ }
+
+ internal static bool IsBasicAuthTokenValid(string clientResponse, LoopbackServer.Options options)
+ {
+ string clientHash = clientResponse.Substring(clientResponse.IndexOf(nameof(AuthenticationProtocols.Basic), StringComparison.OrdinalIgnoreCase) +
+ nameof(AuthenticationProtocols.Basic).Length).Trim();
+ string userPass = string.IsNullOrEmpty(options.Domain) ? options.Username + ":" + options.Password : options.Domain + "\\" + options.Username + ":" + options.Password;
+ return clientHash == Convert.ToBase64String(Encoding.UTF8.GetBytes(userPass));
+ }
+
+ internal static bool IsDigestAuthTokenValid(string clientResponse, string requestMethod, LoopbackServer.Options options)
+ {
+ string clientHash = clientResponse.Substring(clientResponse.IndexOf(nameof(AuthenticationProtocols.Digest), StringComparison.OrdinalIgnoreCase) +
+ nameof(AuthenticationProtocols.Digest).Length).Trim();
+ string[] values = clientHash.Split(',');
+
+ string username = null, uri = null, realm = null, nonce = null, response = null, algorithm = null, cnonce = null, opaque = null, qop = null, nc = null;
+ bool userhash = false;
+ for (int i = 0; i < values.Length; i++)
+ {
+ string trimmedValue = values[i].Trim();
+ if (trimmedValue.Contains(nameof(username)))
+ {
+ // Username is a quoted string.
+ int startIndex = trimmedValue.IndexOf('"');
+
+ if (startIndex != -1)
+ {
+ startIndex += 1;
+ username = trimmedValue.Substring(startIndex, trimmedValue.Length - startIndex - 1);
+ }
+
+ // Username is mandatory.
+ if (string.IsNullOrEmpty(username))
+ return false;
+ }
+ else if (trimmedValue.Contains(nameof(userhash)) && trimmedValue.Contains("true"))
+ {
+ userhash = true;
+ }
+ else if (trimmedValue.Contains(nameof(uri)))
+ {
+ int startIndex = trimmedValue.IndexOf('"');
+ if (startIndex != -1)
+ {
+ startIndex += 1;
+ uri = trimmedValue.Substring(startIndex, trimmedValue.Length - startIndex - 1);
+ }
+
+ // Request uri is mandatory.
+ if (string.IsNullOrEmpty(uri))
+ return false;
+ }
+ else if (trimmedValue.Contains(nameof(realm)))
+ {
+ // Realm is a quoted string.
+ int startIndex = trimmedValue.IndexOf('"');
+ if (startIndex != -1)
+ {
+ startIndex += 1;
+ realm = trimmedValue.Substring(startIndex, trimmedValue.Length - startIndex - 1);
+ }
+
+ // Realm is mandatory.
+ if (string.IsNullOrEmpty(realm))
+ return false;
+ }
+ else if (trimmedValue.Contains(nameof(cnonce)))
+ {
+ // CNonce is a quoted string.
+ int startIndex = trimmedValue.IndexOf('"');
+ if (startIndex != -1)
+ {
+ startIndex += 1;
+ cnonce = trimmedValue.Substring(startIndex, trimmedValue.Length - startIndex - 1);
+ }
+ }
+ else if (trimmedValue.Contains(nameof(nonce)))
+ {
+ // Nonce is a quoted string.
+ int startIndex = trimmedValue.IndexOf('"');
+ if (startIndex != -1)
+ {
+ startIndex += 1;
+ nonce = trimmedValue.Substring(startIndex, trimmedValue.Length - startIndex - 1);
+ }
+
+ // Nonce is mandatory.
+ if (string.IsNullOrEmpty(nonce))
+ return false;
+ }
+ else if (trimmedValue.Contains(nameof(response)))
+ {
+ // response is a quoted string.
+ int startIndex = trimmedValue.IndexOf('"');
+ if (startIndex != -1)
+ {
+ startIndex += 1;
+ response = trimmedValue.Substring(startIndex, trimmedValue.Length - startIndex - 1);
+ }
+
+ // Response is mandatory.
+ if (string.IsNullOrEmpty(response))
+ return false;
+ }
+ else if (trimmedValue.Contains(nameof(algorithm)))
+ {
+ int startIndex = trimmedValue.IndexOf('=');
+ if (startIndex != -1)
+ {
+ startIndex += 1;
+ algorithm = trimmedValue.Substring(startIndex, trimmedValue.Length - startIndex).Trim();
+ }
+ }
+ else if (trimmedValue.Contains(nameof(opaque)))
+ {
+ // Opaque is a quoted string.
+ int startIndex = trimmedValue.IndexOf('"');
+ if (startIndex != -1)
+ {
+ startIndex += 1;
+ opaque = trimmedValue.Substring(startIndex, trimmedValue.Length - startIndex - 1);
+ }
+ }
+ else if (trimmedValue.Contains(nameof(qop)))
+ {
+ int startIndex = trimmedValue.IndexOf('"');
+ if (startIndex != -1)
+ {
+ startIndex += 1;
+ qop = trimmedValue.Substring(startIndex, trimmedValue.Length - startIndex - 1);
+ }
+ else if ((startIndex = trimmedValue.IndexOf('=')) != -1)
+ {
+ startIndex += 1;
+ qop = trimmedValue.Substring(startIndex, trimmedValue.Length - startIndex).Trim();
+ }
+ }
+ else if (trimmedValue.Contains(nameof(nc)))
+ {
+ int startIndex = trimmedValue.IndexOf('=');
+ if (startIndex != -1)
+ {
+ startIndex += 1;
+ nc = trimmedValue.Substring(startIndex, trimmedValue.Length - startIndex).Trim();
+ }
+ }
+ }
+
+ // Verify username.
+ if (userhash && ComputeHash(options.Username + ":" + realm, algorithm) != username)
+ {
+ return false;
+ }
+
+ if (!userhash && options.Username != username)
+ {
+ return false;
+ }
+
+ if (string.IsNullOrEmpty(algorithm))
+ algorithm = "sha-256";
+
+ // Calculate response and compare with the client response hash.
+ string a1 = options.Username + ":" + realm + ":" + options.Password;
+ if (algorithm.Contains("sess"))
+ {
+ a1 = ComputeHash(a1, algorithm) + ":" + nonce;
+
+ if (cnonce != null)
+ a1 += ":" + cnonce;
+ }
+
+ string a2 = requestMethod + ":" + uri;
+ if (!string.IsNullOrEmpty(qop) && qop.Equals("auth-int"))
+ {
+ // Request content is empty.
+ a2 = a2 + ":" + ComputeHash(string.Empty, algorithm);
+ }
+
+ string serverResponseHash = ComputeHash(a1, algorithm) + ":" + nonce + ":";
+
+ if (nc != null)
+ serverResponseHash += nc + ":";
+
+ if (cnonce != null)
+ serverResponseHash += cnonce + ":";
+
+ if (qop != null)
+ serverResponseHash += qop + ":";
+
+ serverResponseHash += ComputeHash(a2, algorithm);
+ serverResponseHash = ComputeHash(serverResponseHash, algorithm);
+
+ return response == serverResponseHash;
+ }
+
+ private static string ComputeHash(string data, string algorithm)
+ {
+ // Disable MD5 insecure warning.
+#pragma warning disable CA5351
+ using (HashAlgorithm hash = algorithm.Contains("SHA-256") ? SHA256.Create() : (HashAlgorithm)MD5.Create())
+#pragma warning restore CA5351
+ {
+ Encoding enc = Encoding.UTF8;
+ byte[] result = hash.ComputeHash(enc.GetBytes(data));
+
+ StringBuilder sb = new StringBuilder(result.Length * 2);
+ foreach (byte b in result)
+ sb.Append(b.ToString("x2"));
+
+ return sb.ToString();
+ }
+ }
+ }
+}
diff --git a/src/Common/tests/System/Net/Http/LoopbackServer.cs b/src/Common/tests/System/Net/Http/LoopbackServer.cs
index af905435de..b8f692ef0c 100644
--- a/src/Common/tests/System/Net/Http/LoopbackServer.cs
+++ b/src/Common/tests/System/Net/Http/LoopbackServer.cs
@@ -3,263 +3,399 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
+using System.Diagnostics;
using System.IO;
using System.Linq;
-using System.Net.Http;
-using System.Net.NetworkInformation;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Security.Cryptography;
-using System.Security.Cryptography.X509Certificates;
using System.Text;
-using System.Threading;
using System.Threading.Tasks;
namespace System.Net.Test.Common
{
- public class LoopbackServer
+ public sealed partial class LoopbackServer : IDisposable
{
- public static Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> AllowAllCertificates = (_, __, ___, ____) => true;
+ private Socket _listenSocket;
+ private Options _options;
+ private Uri _uri;
- public class Options
+ // Use CreateServerAsync or similar to create
+ private LoopbackServer(Socket listenSocket, Options options)
{
- public IPAddress Address { get; set; } = IPAddress.Loopback;
- public int ListenBacklog { get; set; } = 1;
- public bool UseSsl { get; set; } = false;
- public SslProtocols SslProtocols { get; set; } = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12;
- public bool WebSocketEndpoint { get; set; } = false;
- public Func<Stream, Stream> ResponseStreamWrapper { get; set; }
- }
+ _listenSocket = listenSocket;
+ _options = options;
- public static Task CreateServerAsync(Func<Socket, Uri, Task> funcAsync, Options options = null)
- {
- IPEndPoint ignored;
- return CreateServerAsync(funcAsync, out ignored, options);
- }
+ var localEndPoint = (IPEndPoint)listenSocket.LocalEndPoint;
+ string host = options.Address.AddressFamily == AddressFamily.InterNetworkV6 ?
+ $"[{localEndPoint.Address}]" :
+ localEndPoint.Address.ToString();
- public static Task CreateServerAsync(Func<Socket, Uri, Task> funcAsync, out IPEndPoint localEndPoint, Options options = null)
- {
- options = options ?? new Options();
- try
+ string scheme = options.UseSsl ? "https" : "http";
+ if (options.WebSocketEndpoint)
{
- var server = new Socket(options.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
-
- server.Bind(new IPEndPoint(options.Address, 0));
- server.Listen(options.ListenBacklog);
-
- localEndPoint = (IPEndPoint)server.LocalEndPoint;
- string host = options.Address.AddressFamily == AddressFamily.InterNetworkV6 ?
- $"[{localEndPoint.Address}]" :
- localEndPoint.Address.ToString();
-
- string scheme = options.UseSsl ? "https" : "http";
- if (options.WebSocketEndpoint)
- {
- scheme = options.UseSsl ? "wss" : "ws";
- }
-
- var url = new Uri($"{scheme}://{host}:{localEndPoint.Port}/");
-
- return funcAsync(server, url).ContinueWith(t =>
- {
- server.Dispose();
- t.GetAwaiter().GetResult();
- }, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Default);
+ scheme = options.UseSsl ? "wss" : "ws";
}
- catch (Exception e)
- {
- localEndPoint = null;
- return Task.FromException(e);
- }
- }
- public static string DefaultHttpResponse => $"HTTP/1.1 200 OK\r\nDate: {DateTimeOffset.UtcNow:R}\r\nContent-Length: 0\r\n\r\n";
-
- public static IPAddress GetIPv6LinkLocalAddress() =>
- NetworkInterface
- .GetAllNetworkInterfaces()
- .SelectMany(i => i.GetIPProperties().UnicastAddresses)
- .Select(a => a.Address)
- .Where(a => a.IsIPv6LinkLocal)
- .FirstOrDefault();
-
- public static Task<List<string>> ReadRequestAndSendResponseAsync(Socket server, string response = null, Options options = null)
- {
- return AcceptSocketAsync(server, (s, stream, reader, writer) => ReadWriteAcceptedAsync(s, reader, writer, response), options);
+ _uri = new Uri($"{scheme}://{host}:{localEndPoint.Port}/");
}
- public static async Task<List<string>> ReadWriteAcceptedAsync(Socket s, StreamReader reader, StreamWriter writer, string response = null)
+ public void Dispose()
{
- // Read request line and headers. Skip any request body.
- var lines = new List<string>();
- string line;
- while (!string.IsNullOrEmpty(line = await reader.ReadLineAsync().ConfigureAwait(false)))
+ if (_listenSocket != null)
{
- lines.Add(line);
+ _listenSocket.Dispose();
+ _listenSocket = null;
}
-
- await writer.WriteAsync(response ?? DefaultHttpResponse).ConfigureAwait(false);
-
- return lines;
}
- public static async Task<bool> WebSocketHandshakeAsync(Socket s, StreamReader reader, StreamWriter writer)
+ public Socket ListenSocket => _listenSocket;
+ public Uri Uri => _uri;
+
+ public static async Task CreateServerAsync(Func<LoopbackServer, Task> funcAsync, Options options = null)
{
- string serverResponse = null;
- string currentRequestLine;
- while (!string.IsNullOrEmpty(currentRequestLine = await reader.ReadLineAsync().ConfigureAwait(false)))
+ options = options ?? new Options();
+
+ using (var listenSocket = new Socket(options.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp))
{
- string[] tokens = currentRequestLine.Split(new char[] { ':' }, 2);
- if (tokens.Length == 2)
+ listenSocket.Bind(new IPEndPoint(options.Address, 0));
+ listenSocket.Listen(options.ListenBacklog);
+
+ using (var server = new LoopbackServer(listenSocket, options))
{
- string headerName = tokens[0];
- if (headerName == "Sec-WebSocket-Key")
- {
- string headerValue = tokens[1].Trim();
- string responseSecurityAcceptValue = ComputeWebSocketHandshakeSecurityAcceptValue(headerValue);
- serverResponse =
- "HTTP/1.1 101 Switching Protocols\r\n" +
- "Upgrade: websocket\r\n" +
- "Connection: Upgrade\r\n" +
- "Sec-WebSocket-Accept: " + responseSecurityAcceptValue + "\r\n\r\n";
- }
+ await funcAsync(server);
}
}
+ }
- if (serverResponse != null)
- {
- // We received a valid WebSocket opening handshake. Send the appropriate response.
- await writer.WriteAsync(serverResponse).ConfigureAwait(false);
- return true;
- }
-
- return false;
+ public static Task CreateServerAsync(Func<LoopbackServer, Uri, Task> funcAsync, Options options = null)
+ {
+ return CreateServerAsync(server => funcAsync(server, server.Uri), options);
}
- private static string ComputeWebSocketHandshakeSecurityAcceptValue(string secWebSocketKey)
+ public static Task CreateClientAndServerAsync(Func<Uri, Task> clientFunc, Func<LoopbackServer, Task> serverFunc, Options options = null)
{
- // GUID specified by RFC 6455.
- const string Rfc6455Guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
- string combinedKey = secWebSocketKey + Rfc6455Guid;
-
- // Use of SHA1 hash is required by RFC 6455.
- SHA1 sha1Provider = new SHA1CryptoServiceProvider();
- byte[] sha1Hash = sha1Provider.ComputeHash(Encoding.UTF8.GetBytes(combinedKey));
- return Convert.ToBase64String(sha1Hash);
+ return CreateServerAsync(async server =>
+ {
+ Task clientTask = clientFunc(server.Uri);
+ Task serverTask = serverFunc(server);
+
+ await new Task[] { clientTask, serverTask }.WhenAllOrAnyFailed();
+ }, options);
}
- public static async Task<List<string>> AcceptSocketAsync(Socket server, Func<Socket, Stream, StreamReader, StreamWriter, Task<List<string>>> funcAsync, Options options = null)
+ public async Task AcceptConnectionAsync(Func<Connection, Task> funcAsync)
{
- options = options ?? new Options();
- Socket s = await server.AcceptAsync().ConfigureAwait(false);
- try
+ using (Socket s = await _listenSocket.AcceptAsync().ConfigureAwait(false))
{
+ s.NoDelay = true;
+
Stream stream = new NetworkStream(s, ownsSocket: false);
- if (options.UseSsl)
+ if (_options.UseSsl)
{
- var sslStream = new SslStream(stream, false, delegate { return true; });
+ var sslStream = new SslStream(stream, false, delegate
+ { return true; });
using (var cert = Configuration.Certificates.GetServerCertificate())
{
await sslStream.AuthenticateAsServerAsync(
cert,
clientCertificateRequired: true, // allowed but not required
- enabledSslProtocols: options.SslProtocols,
+ enabledSslProtocols: _options.SslProtocols,
checkCertificateRevocation: false).ConfigureAwait(false);
}
stream = sslStream;
}
- using (var reader = new StreamReader(stream, Encoding.ASCII))
- using (var writer = new StreamWriter(options?.ResponseStreamWrapper?.Invoke(stream) ?? stream, Encoding.ASCII) { AutoFlush = true })
+ if (_options.StreamWrapper != null)
{
- return await funcAsync(s, stream, reader, writer).ConfigureAwait(false);
+ stream = _options.StreamWrapper(stream);
}
- }
- finally
- {
- try
+
+ using (var connection = new Connection(s, stream))
{
- s.Shutdown(SocketShutdown.Send);
- s.Dispose();
+ await funcAsync(connection);
}
- catch (ObjectDisposedException)
+ }
+ }
+
+ public async Task<List<string>> AcceptConnectionSendCustomResponseAndCloseAsync(string response)
+ {
+ List<string> lines = null;
+
+ // Note, we assume there's no request body.
+ // We'll close the connection after reading the request header and sending the response.
+ await AcceptConnectionAsync(async connection =>
+ {
+ lines = await connection.ReadRequestHeaderAndSendCustomResponseAsync(response);
+ });
+
+ return lines;
+ }
+
+ public async Task<List<string>> AcceptConnectionSendResponseAndCloseAsync(HttpStatusCode statusCode = HttpStatusCode.OK, string additionalHeaders = null, string content = null)
+ {
+ List<string> lines = null;
+
+ // Note, we assume there's no request body.
+ // We'll close the connection after reading the request header and sending the response.
+ await AcceptConnectionAsync(async connection =>
+ {
+ lines = await connection.ReadRequestHeaderAndSendResponseAsync(statusCode, additionalHeaders, content);
+ });
+
+ return lines;
+ }
+
+ public static string GetRequestHeaderValue(List<string> headers, string name)
+ {
+ var sep = new char[] { ':' };
+ foreach (string line in headers)
+ {
+ string[] tokens = line.Split(sep , 2);
+ if (name.Equals(tokens[0], StringComparison.InvariantCultureIgnoreCase))
{
- // In case the test itself disposes of the socket
+ return tokens[1].Trim();
}
}
+ return null;
}
- public enum TransferType
+ public static string GetRequestMethod(List<string> headers)
{
- None = 0,
- ContentLength,
- Chunked
+
+ if (headers != null && headers.Count > 1)
+ {
+ return headers[0].Split()[1].Trim();
+ }
+ return null;
}
- public enum TransferError
+ // Stolen from HttpStatusDescription code in the product code
+ private static string GetStatusDescription(HttpStatusCode code)
{
- None = 0,
- ContentLengthTooLarge,
- ChunkSizeTooLarge,
- MissingChunkTerminator
+ switch ((int)code)
+ {
+ case 100:
+ return "Continue";
+ case 101:
+ return "Switching Protocols";
+ case 102:
+ return "Processing";
+
+ case 200:
+ return "OK";
+ case 201:
+ return "Created";
+ case 202:
+ return "Accepted";
+ case 203:
+ return "Non-Authoritative Information";
+ case 204:
+ return "No Content";
+ case 205:
+ return "Reset Content";
+ case 206:
+ return "Partial Content";
+ case 207:
+ return "Multi-Status";
+
+ case 300:
+ return "Multiple Choices";
+ case 301:
+ return "Moved Permanently";
+ case 302:
+ return "Found";
+ case 303:
+ return "See Other";
+ case 304:
+ return "Not Modified";
+ case 305:
+ return "Use Proxy";
+ case 307:
+ return "Temporary Redirect";
+
+ case 400:
+ return "Bad Request";
+ case 401:
+ return "Unauthorized";
+ case 402:
+ return "Payment Required";
+ case 403:
+ return "Forbidden";
+ case 404:
+ return "Not Found";
+ case 405:
+ return "Method Not Allowed";
+ case 406:
+ return "Not Acceptable";
+ case 407:
+ return "Proxy Authentication Required";
+ case 408:
+ return "Request Timeout";
+ case 409:
+ return "Conflict";
+ case 410:
+ return "Gone";
+ case 411:
+ return "Length Required";
+ case 412:
+ return "Precondition Failed";
+ case 413:
+ return "Request Entity Too Large";
+ case 414:
+ return "Request-Uri Too Long";
+ case 415:
+ return "Unsupported Media Type";
+ case 416:
+ return "Requested Range Not Satisfiable";
+ case 417:
+ return "Expectation Failed";
+ case 422:
+ return "Unprocessable Entity";
+ case 423:
+ return "Locked";
+ case 424:
+ return "Failed Dependency";
+ case 426:
+ return "Upgrade Required"; // RFC 2817
+
+ case 500:
+ return "Internal Server Error";
+ case 501:
+ return "Not Implemented";
+ case 502:
+ return "Bad Gateway";
+ case 503:
+ return "Service Unavailable";
+ case 504:
+ return "Gateway Timeout";
+ case 505:
+ return "Http Version Not Supported";
+ case 507:
+ return "Insufficient Storage";
+ }
+ return null;
+ }
+
+ public static string GetHttpResponse(HttpStatusCode statusCode = HttpStatusCode.OK, string additionalHeaders = null, string content = null) =>
+ $"HTTP/1.1 {(int)statusCode} {GetStatusDescription(statusCode)}\r\n" +
+ $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
+ $"Content-Length: {(content == null ? 0 : content.Length)}\r\n" +
+ additionalHeaders +
+ "\r\n" +
+ content;
+
+ public static string GetSingleChunkHttpResponse(HttpStatusCode statusCode = HttpStatusCode.OK, string additionalHeaders = null, string content = null) =>
+ $"HTTP/1.1 {(int)statusCode} {GetStatusDescription(statusCode)}\r\n" +
+ $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
+ "Transfer-Encoding: chunked\r\n" +
+ additionalHeaders +
+ "\r\n" +
+ (string.IsNullOrEmpty(content) ? "" :
+ $"{content.Length:X}\r\n" +
+ $"{content}\r\n") +
+ $"0\r\n" +
+ $"\r\n";
+
+ public static string GetBytePerChunkHttpResponse(HttpStatusCode statusCode = HttpStatusCode.OK, string additionalHeaders = null, string content = null) =>
+ $"HTTP/1.1 {(int)statusCode} {GetStatusDescription(statusCode)}\r\n" +
+ $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
+ "Transfer-Encoding: chunked\r\n" +
+ additionalHeaders +
+ "\r\n" +
+ (string.IsNullOrEmpty(content) ? "" : string.Concat(content.Select(c => $"1\r\n{c}\r\n"))) +
+ $"0\r\n" +
+ $"\r\n";
+
+ public class Options
+ {
+ public IPAddress Address { get; set; } = IPAddress.Loopback;
+ public int ListenBacklog { get; set; } = 1;
+ public bool UseSsl { get; set; } = false;
+ public SslProtocols SslProtocols { get; set; } = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12;
+ public bool WebSocketEndpoint { get; set; } = false;
+ public Func<Stream, Stream> StreamWrapper { get; set; }
+ public string Username { get; set; }
+ public string Domain { get; set; }
+ public string Password { get; set; }
+ public bool IsProxy { get; set; } = false;
}
- public static Task StartTransferTypeAndErrorServer(
- TransferType transferType,
- TransferError transferError,
- out IPEndPoint localEndPoint)
+ public sealed class Connection : IDisposable
{
- return CreateServerAsync((server, url) => AcceptSocketAsync(server, async (client, stream, reader, writer) =>
+ private Socket _socket;
+ private Stream _stream;
+ private StreamReader _reader;
+ private StreamWriter _writer;
+
+ public Connection(Socket socket, Stream stream)
{
- // Read past request headers.
- string line;
- while (!string.IsNullOrEmpty(line = reader.ReadLine())) ;
+ _socket = socket;
+ _stream = stream;
- // Determine response transfer headers.
- string transferHeader = null;
- string content = "This is some response content.";
- if (transferType == TransferType.ContentLength)
- {
- transferHeader = transferError == TransferError.ContentLengthTooLarge ?
- $"Content-Length: {content.Length + 42}\r\n" :
- $"Content-Length: {content.Length}\r\n";
- }
- else if (transferType == TransferType.Chunked)
- {
- transferHeader = "Transfer-Encoding: chunked\r\n";
- }
+ _reader = new StreamReader(stream, Encoding.ASCII);
+ _writer = new StreamWriter(stream, Encoding.ASCII) { AutoFlush = true };
+ }
- // Write response header
- await writer.WriteAsync("HTTP/1.1 200 OK\r\n").ConfigureAwait(false);
- await writer.WriteAsync($"Date: {DateTimeOffset.UtcNow:R}\r\n").ConfigureAwait(false);
- await writer.WriteAsync("Content-Type: text/plain\r\n").ConfigureAwait(false);
- if (!string.IsNullOrEmpty(transferHeader))
+ public Socket Socket => _socket;
+ public Stream Stream => _stream;
+ public StreamReader Reader => _reader;
+ public StreamWriter Writer => _writer;
+
+ public void Dispose()
+ {
+ try
{
- await writer.WriteAsync(transferHeader).ConfigureAwait(false);
+ // Try to shutdown the send side of the socket.
+ // This seems to help avoid connection reset issues caused by buffered data
+ // that has not been sent/acked when the graceful shutdown timeout expires.
+ // This may throw if the socket was already closed, so eat any exception.
+ _socket.Shutdown(SocketShutdown.Send);
}
- await writer.WriteAsync("\r\n").ConfigureAwait(false);
+ catch (Exception) { }
- // Write response body
- if (transferType == TransferType.Chunked)
+ _reader.Dispose();
+ _writer.Dispose();
+ _stream.Dispose();
+ _socket.Dispose();
+ }
+
+ public async Task<List<string>> ReadRequestHeaderAsync()
+ {
+ var lines = new List<string>();
+ string line;
+ while (!string.IsNullOrEmpty(line = await _reader.ReadLineAsync().ConfigureAwait(false)))
{
- string chunkSizeInHex = string.Format(
- "{0:x}\r\n",
- content.Length + (transferError == TransferError.ChunkSizeTooLarge ? 42 : 0));
- await writer.WriteAsync(chunkSizeInHex).ConfigureAwait(false);
- await writer.WriteAsync($"{content}\r\n").ConfigureAwait(false);
- if (transferError != TransferError.MissingChunkTerminator)
- {
- await writer.WriteAsync("0\r\n\r\n").ConfigureAwait(false);
- }
+ lines.Add(line);
}
- else
+
+ if (line == null)
{
- await writer.WriteAsync($"{content}\r\n").ConfigureAwait(false);
+ throw new Exception("Unexpected EOF trying to read request header");
}
- return null;
- }), out localEndPoint);
- }
+ return lines;
+ }
+
+ public async Task SendResponseAsync(HttpStatusCode statusCode = HttpStatusCode.OK, string additionalHeaders = null, string content = null)
+ {
+ await _writer.WriteAsync(GetHttpResponse(statusCode, additionalHeaders, content));
+ }
+
+ public async Task<List<string>> ReadRequestHeaderAndSendCustomResponseAsync(string response)
+ {
+ List<string> lines = await ReadRequestHeaderAsync().ConfigureAwait(false);
+ await _writer.WriteAsync(response);
+ return lines;
+ }
+
+ public async Task<List<string>> ReadRequestHeaderAndSendResponseAsync(HttpStatusCode statusCode = HttpStatusCode.OK, string additionalHeaders = null, string content = null)
+ {
+ List<string> lines = await ReadRequestHeaderAsync().ConfigureAwait(false);
+ await SendResponseAsync(statusCode, additionalHeaders, content);
+ return lines;
+ }
+ }
}
}
diff --git a/src/Common/tests/System/RandomExtensions.cs b/src/Common/tests/System/RandomExtensions.cs
new file mode 100644
index 0000000000..8acd35be5d
--- /dev/null
+++ b/src/Common/tests/System/RandomExtensions.cs
@@ -0,0 +1,23 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace Common.System
+{
+ internal static class RandomExtensions
+ {
+ public static void Shuffle<T>(this Random random, T[] array)
+ {
+ int n = array.Length;
+ while (n > 1)
+ {
+ int k = random.Next(n--);
+ T temp = array[n];
+ array[n] = array[k];
+ array[k] = temp;
+ }
+ }
+ }
+}
diff --git a/src/System.Runtime.Serialization.Xml/tests/Utils.cs b/src/Common/tests/System/Runtime/Serialization/Utils.cs
index 080b693df6..080b693df6 100644
--- a/src/System.Runtime.Serialization.Xml/tests/Utils.cs
+++ b/src/Common/tests/System/Runtime/Serialization/Utils.cs
diff --git a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/CurveDef.cs b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/CurveDef.cs
index 7aaf35ac84..29b03579ca 100644
--- a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/CurveDef.cs
+++ b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/CurveDef.cs
@@ -2,7 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-namespace System.Security.Cryptography.EcDsa.Tests
+namespace System.Security.Cryptography.Tests
{
public class CurveDef
{
@@ -21,8 +21,8 @@ namespace System.Security.Cryptography.EcDsa.Tests
{
// Assume curve is valid if required; tests will fail if not present
return RequiredOnPlatform ||
- (Curve.IsNamed && ECDsaFactory.IsCurveValid(Curve.Oid)) ||
- (Curve.IsExplicit && ECDsaFactory.ExplicitCurvesSupported);
+ (Curve.IsNamed && (EcDsa.Tests.ECDsaFactory.IsCurveValid(Curve.Oid) || EcDiffieHellman.Tests.ECDiffieHellmanFactory.IsCurveValid(Curve.Oid))) ||
+ (Curve.IsExplicit && (EcDsa.Tests.ECDsaFactory.ExplicitCurvesSupported || EcDiffieHellman.Tests.ECDiffieHellmanFactory.ExplicitCurvesSupported));
}
}
diff --git a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/EccTestBase.cs b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/EccTestBase.cs
new file mode 100644
index 0000000000..c5fc9f0ed5
--- /dev/null
+++ b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/EccTestBase.cs
@@ -0,0 +1,235 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Cryptography.Tests;
+using Test.Cryptography;
+using Xunit;
+
+namespace System.Security.Cryptography.Tests
+{
+ /// <summary>
+ /// Input and helper methods for EC classes
+ /// </summary>
+ public abstract class EccTestBase
+ {
+#if netcoreapp
+ internal const string ECDSA_P224_OID_VALUE = "1.3.132.0.33"; // Also called nistP224 or secP224r1
+ internal const string ECDSA_P256_OID_VALUE = "1.2.840.10045.3.1.7"; // Also called nistP256, secP256r1 or prime256v1(OpenSsl)
+ internal const string ECDSA_P384_OID_VALUE = "1.3.132.0.34"; // Also called nistP384 or secP384r1
+ internal const string ECDSA_P521_OID_VALUE = "1.3.132.0.35"; // Also called nistP521 or secP521r1
+ internal const string ECDSA_Sect193r1_OID_VALUE = "1.3.132.0.24"; //Char-2 curve
+
+ public static IEnumerable<object[]> TestCurvesFull
+ {
+ get
+ {
+ var curveDefs =
+ from curveDef in TestCurvesRaw
+ where curveDef.IsCurveValidOnPlatform == true
+ select curveDef;
+
+ foreach (CurveDef cd in curveDefs)
+ yield return new[] { cd };
+
+ // return again with IncludePrivate = true
+ foreach (CurveDef cd in curveDefs)
+ {
+ cd.IncludePrivate = true;
+ yield return new[] { cd };
+ }
+ }
+ }
+
+ public static IEnumerable<object[]> TestCurves
+ {
+ get
+ {
+ var curveDefs =
+ from curveDef in TestCurvesRaw
+ where curveDef.IsCurveValidOnPlatform == true
+ select curveDef;
+
+ foreach (CurveDef curveDef in curveDefs)
+ yield return new[] { curveDef };
+ }
+ }
+
+ public static IEnumerable<object[]> TestInvalidCurves
+ {
+ get
+ {
+ var curveDefs =
+ from curveDef in TestCurvesRaw
+ where curveDef.IsCurveValidOnPlatform == false
+ select curveDef;
+
+ foreach (CurveDef curveDef in curveDefs)
+ yield return new[] { curveDef };
+ }
+ }
+
+ public static IEnumerable<object[]> TestNewCurves
+ {
+ get
+ {
+ var curveDefs =
+ from curveDef in TestCurvesRaw
+ where
+ curveDef.IsCurveValidOnPlatform == true &&
+ curveDef.RequiredOnPlatform == false
+ select curveDef;
+
+ foreach (CurveDef curveDef in curveDefs)
+ yield return new[] { curveDef };
+ }
+ }
+
+ private static IEnumerable<CurveDef> TestCurvesRaw
+ {
+ get
+ {
+ // nistP* curves
+ yield return new CurveDef()
+ {
+ Curve = ECCurve.NamedCurves.nistP256, // also secp256r1
+ KeySize = 256,
+ CurveType = ECCurve.ECCurveType.PrimeShortWeierstrass,
+ RequiredOnPlatform = true,
+ };
+ yield return new CurveDef()
+ {
+ Curve = ECCurve.NamedCurves.nistP384, // also secp384r1
+ KeySize = 384,
+ CurveType = ECCurve.ECCurveType.PrimeMontgomery,
+ RequiredOnPlatform = true,
+ };
+ yield return new CurveDef()
+ {
+ Curve = ECCurve.NamedCurves.nistP521, // also secp521r1
+ KeySize = 521,
+ CurveType = ECCurve.ECCurveType.PrimeShortWeierstrass,
+ RequiredOnPlatform = true,
+ };
+ yield return new CurveDef()
+ {
+ Curve = ECCurve.NamedCurves.brainpoolP160r1,
+ KeySize = 160,
+ CurveType = ECCurve.ECCurveType.PrimeShortWeierstrass
+ };
+ yield return new CurveDef()
+ {
+ Curve = ECCurve.CreateFromOid(new Oid("1.3.132.0.24", "")), // sect193r1
+ KeySize = 193,
+ CurveType = ECCurve.ECCurveType.Characteristic2,
+ };
+ yield return new CurveDef()
+ {
+ Curve = ECCurve.CreateFromOid(new Oid("1.2.840.10045.3.0.1", "")), // c2pnb163v1
+ KeySize = 163,
+ CurveType = ECCurve.ECCurveType.Characteristic2,
+ };
+ yield return new CurveDef()
+ {
+ Curve = ECCurve.CreateFromOid(new Oid("1.3.132.0.16", "")), // sect283k1
+ KeySize = 283,
+ CurveType = ECCurve.ECCurveType.Characteristic2,
+ };
+ yield return new CurveDef()
+ {
+ Curve = ECCurve.CreateFromOid(new Oid("1.3.132.0.17", "")), // sect283r1
+ KeySize = 283,
+ CurveType = ECCurve.ECCurveType.Characteristic2,
+ };
+ yield return new CurveDef()
+ {
+ Curve = ECCurve.CreateFromOid(new Oid("", "wap-wsg-idm-ecid-wtls7")),
+ KeySize = 160,
+ CurveType = ECCurve.ECCurveType.PrimeMontgomery,
+ };
+ yield return new CurveDef()
+ {
+ Curve = ECCurve.CreateFromOid(new Oid("invalid", "invalid")),
+ KeySize = 160,
+ CurveType = ECCurve.ECCurveType.PrimeShortWeierstrass,
+ };
+ yield return new CurveDef
+ {
+ Curve = EccTestData.GetNistP256ExplicitCurve(),
+ KeySize = 256,
+ CurveType = ECCurve.ECCurveType.PrimeShortWeierstrass,
+ DisplayName = "NIST P-256",
+ };
+ }
+ }
+
+ internal static void AssertEqual(ECParameters p1, ECParameters p2)
+ {
+ ComparePrivateKey(p1, p2);
+ ComparePublicKey(p1.Q, p2.Q);
+ CompareCurve(p1.Curve, p2.Curve);
+ }
+
+ internal static void ComparePrivateKey(ECParameters p1, ECParameters p2, bool isEqual = true)
+ {
+ if (isEqual)
+ {
+ Assert.Equal(p1.D, p2.D);
+ }
+ else
+ {
+ Assert.NotEqual(p1.D, p2.D);
+ }
+ }
+
+ internal static void ComparePublicKey(ECPoint q1, ECPoint q2, bool isEqual = true)
+ {
+ if (isEqual)
+ {
+ Assert.Equal(q1.X, q2.X);
+ Assert.Equal(q1.Y, q2.Y);
+ }
+ else
+ {
+ Assert.NotEqual(q1.X, q2.X);
+ Assert.NotEqual(q1.Y, q2.Y);
+ }
+ }
+
+ internal static void CompareCurve(ECCurve c1, ECCurve c2)
+ {
+ if (c1.IsNamed)
+ {
+ Assert.True(c2.IsNamed);
+ Assert.Equal(c1.Oid.FriendlyName, c2.Oid.FriendlyName);
+ }
+ else if (c1.IsExplicit)
+ {
+ Assert.True(c2.IsExplicit);
+ Assert.Equal(c1.A, c2.A);
+ Assert.Equal(c1.B, c2.B);
+ Assert.Equal(c1.CurveType, c2.CurveType);
+ Assert.Equal(c1.G.X, c2.G.X);
+ Assert.Equal(c1.G.Y, c2.G.Y);
+ Assert.Equal(c1.Cofactor, c2.Cofactor);
+ Assert.Equal(c1.Order, c2.Order);
+ Assert.Equal(c1.Seed, c2.Seed);
+ Assert.Equal(c1.Hash, c2.Hash);
+
+ if (c1.IsPrime)
+ {
+ Assert.True(c2.IsPrime);
+ Assert.Equal(c1.Prime, c2.Prime);
+ }
+ else if (c1.IsCharacteristic2)
+ {
+ Assert.True(c2.IsCharacteristic2);
+ Assert.Equal(c1.Polynomial, c2.Polynomial);
+ }
+ }
+ }
+#endif // netcoreapp
+ }
+}
diff --git a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTestData.cs b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/EccTestData.cs
index 4b86628cae..6fca55ae59 100644
--- a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTestData.cs
+++ b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/EC/EccTestData.cs
@@ -5,7 +5,7 @@
using System;
using Test.Cryptography;
-namespace System.Security.Cryptography.EcDsa.Tests
+namespace System.Security.Cryptography.Tests
{
// Note to contributors:
// Keys contained in this file should be randomly generated for the purpose of inclusion here,
@@ -15,7 +15,7 @@ namespace System.Security.Cryptography.EcDsa.Tests
// Note to readers:
// The keys contained in this file should all be treated as compromised. That means that you
// absolutely SHOULD NOT use these keys on anything that you actually want to be protected.
- internal static class ECDsaTestData
+ internal static class EccTestData
{
internal static readonly byte[] s_hashSha512 =
("a232cec7be26319e53db0d48470232d37793b06b99e8ed82fac1996b3d1596449087769927d64af657cce62d853c4cf7ff4c"
@@ -109,7 +109,7 @@ namespace System.Security.Cryptography.EcDsa.Tests
internal static ECParameters GetNistP256ExplicitTestData()
{
- // explicit values for s_ECDsa256Key (nistP256)
+ // explicit values for s_Ecc256Key (nistP256)
ECParameters p = new ECParameters();
p.Q = new ECPoint
{
diff --git a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanFactory.cs b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanFactory.cs
new file mode 100644
index 0000000000..2952086206
--- /dev/null
+++ b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanFactory.cs
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Security.Cryptography.EcDiffieHellman.Tests
+{
+ public interface IECDiffieHellmanProvider
+ {
+ ECDiffieHellman Create();
+ ECDiffieHellman Create(int keySize);
+#if netcoreapp
+ ECDiffieHellman Create(ECCurve curve);
+#endif
+ bool IsCurveValid(Oid oid);
+ bool ExplicitCurvesSupported { get; }
+ }
+
+ public static partial class ECDiffieHellmanFactory
+ {
+ public static ECDiffieHellman Create()
+ {
+ return s_provider.Create();
+ }
+
+ public static ECDiffieHellman Create(int keySize)
+ {
+ return s_provider.Create(keySize);
+ }
+
+#if netcoreapp
+ public static ECDiffieHellman Create(ECCurve curve)
+ {
+ return s_provider.Create(curve);
+ }
+#endif
+
+ public static bool IsCurveValid(Oid oid)
+ {
+ return s_provider.IsCurveValid(oid);
+ }
+
+ public static bool ExplicitCurvesSupported => s_provider.ExplicitCurvesSupported;
+ }
+}
diff --git a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.Hash.cs b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.Hash.cs
new file mode 100644
index 0000000000..cb9e1919fd
--- /dev/null
+++ b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.Hash.cs
@@ -0,0 +1,287 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using Test.Cryptography;
+using Xunit;
+
+namespace System.Security.Cryptography.EcDiffieHellman.Tests
+{
+ public partial class ECDiffieHellmanTests
+ {
+ [Fact]
+ public static void HashDerivation_OtherKeyRequired()
+ {
+ using (ECDiffieHellman ecdh = ECDiffieHellmanFactory.Create())
+ {
+ Assert.Throws<ArgumentNullException>(
+ () => ecdh.DeriveKeyFromHash(null, HashAlgorithmName.SHA512));
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(MismatchedKeysizes))]
+ public static void HashDerivation_SameSizeOtherKeyRequired(int aliceSize, int bobSize)
+ {
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create(aliceSize))
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create(bobSize))
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ Assert.ThrowsAny<ArgumentException>(
+ () => alice.DeriveKeyFromHash(bobPublic, HashAlgorithmName.SHA512));
+ }
+ }
+
+ [Fact]
+ public static void HashDerivation_AlgorithmRequired()
+ {
+ using (ECDiffieHellman ecdh = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellmanPublicKey publicKey = ecdh.PublicKey)
+ {
+ Assert.Throws<ArgumentException>(
+ () => ecdh.DeriveKeyFromHash(publicKey, new HashAlgorithmName("")));
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(EveryKeysize))]
+ public static void HashDerivation(int keySize)
+ {
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create(keySize))
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create(keySize))
+ using (ECDiffieHellmanPublicKey alicePublic = alice.PublicKey)
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ byte[] aliceDerived = alice.DeriveKeyFromHash(bobPublic, HashAlgorithmName.SHA512);
+ byte[] bobDerived = bob.DeriveKeyFromHash(alicePublic, HashAlgorithmName.SHA512);
+
+ Assert.Equal(aliceDerived, bobDerived);
+ }
+ }
+
+ [Fact]
+ public static void HashDerivationVariesOnPublicKey()
+ {
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellmanPublicKey alicePublic = alice.PublicKey)
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ byte[] aliceDerived = alice.DeriveKeyFromHash(bobPublic, HashAlgorithmName.SHA512);
+ byte[] aliceSelfDerived = alice.DeriveKeyFromHash(alicePublic, HashAlgorithmName.SHA512);
+
+ // Alice and Alice is HASH(aaG) != HASH(abG)
+ // (Except for the fantastically small chance that Alice == Bob)
+ Assert.NotEqual(aliceDerived, aliceSelfDerived);
+ }
+ }
+
+ [Fact]
+ public static void HashDerivationVariesOnAlgorithm()
+ {
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellmanPublicKey alicePublic = alice.PublicKey)
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ byte[] aliceDerived = alice.DeriveKeyFromHash(bobPublic, HashAlgorithmName.SHA512);
+ byte[] bobDerived = bob.DeriveKeyFromHash(alicePublic, HashAlgorithmName.SHA384);
+
+ Assert.NotEqual(aliceDerived, bobDerived);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(EveryKeysize))]
+ public static void SymmetricDerivation_HashPrepend(int keySize)
+ {
+ byte[] prefix = new byte[10];
+
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create(keySize))
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create(keySize))
+ using (ECDiffieHellmanPublicKey alicePublic = alice.PublicKey)
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ byte[] aliceDerived = alice.DeriveKeyFromHash(bobPublic, HashAlgorithmName.SHA512, prefix, null);
+ byte[] bobDerived = bob.DeriveKeyFromHash(alicePublic, HashAlgorithmName.SHA512, prefix, null);
+
+ Assert.Equal(aliceDerived, bobDerived);
+ }
+ }
+
+ [Fact]
+ public static void HashDerivationVariesOnPrepend()
+ {
+ byte[] alicePrefix = new byte[10];
+ byte[] bobPrefix = new byte[alicePrefix.Length];
+ bobPrefix[0] = 0xFF;
+
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellmanPublicKey alicePublic = alice.PublicKey)
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ byte[] aliceDerived = alice.DeriveKeyFromHash(bobPublic, HashAlgorithmName.SHA512, alicePrefix, null);
+ byte[] bobDerived = alice.DeriveKeyFromHash(alicePublic, HashAlgorithmName.SHA512, bobPrefix, null);
+
+ Assert.NotEqual(aliceDerived, bobDerived);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(EveryKeysize))]
+ public static void SymmetricDerivation_HashAppend(int keySize)
+ {
+ byte[] suffix = new byte[10];
+
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create(keySize))
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create(keySize))
+ using (ECDiffieHellmanPublicKey alicePublic = alice.PublicKey)
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ byte[] aliceDerived = alice.DeriveKeyFromHash(bobPublic, HashAlgorithmName.SHA512, null, suffix);
+ byte[] bobDerived = bob.DeriveKeyFromHash(alicePublic, HashAlgorithmName.SHA512, null, suffix);
+
+ Assert.Equal(aliceDerived, bobDerived);
+ }
+ }
+
+ [Fact]
+ public static void HashDerivationVariesOnAppend()
+ {
+ byte[] aliceSuffix = new byte[10];
+ byte[] bobSuffix = new byte[aliceSuffix.Length];
+ bobSuffix[0] = 0xFF;
+
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellmanPublicKey alicePublic = alice.PublicKey)
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ byte[] aliceDerived = alice.DeriveKeyFromHash(bobPublic, HashAlgorithmName.SHA512, null, aliceSuffix);
+ byte[] bobDerived = alice.DeriveKeyFromHash(alicePublic, HashAlgorithmName.SHA512, null, bobSuffix);
+
+ Assert.NotEqual(aliceDerived, bobDerived);
+ }
+ }
+
+ [Fact]
+ public static void HashDerivationIsStable()
+ {
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ byte[] aliceDerived = alice.DeriveKeyFromHash(bobPublic, HashAlgorithmName.SHA512);
+ byte[] aliceDerivedAgain = alice.DeriveKeyFromHash(bobPublic, HashAlgorithmName.SHA512);
+
+ Assert.Equal(aliceDerived, aliceDerivedAgain);
+ }
+ }
+
+ [Fact]
+ public static void SimpleHashMethodForwardsNull()
+ {
+ using (ECDiffieHellman ecdh = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellmanPublicKey publicKey = ecdh.PublicKey)
+ {
+ byte[] simple = ecdh.DeriveKeyFromHash(publicKey, HashAlgorithmName.SHA512);
+ byte[] nulls = ecdh.DeriveKeyFromHash(publicKey, HashAlgorithmName.SHA512, null, null);
+
+ Assert.Equal(simple, nulls);
+ }
+ }
+
+ [Fact]
+ public static void DeriveKeyMaterialEquivalentToDeriveKeyFromHash()
+ {
+ using (ECDiffieHellman ecdh = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellmanPublicKey publicKey = ecdh.PublicKey)
+ {
+ byte[] simple = ecdh.DeriveKeyMaterial(publicKey);
+ byte[] nulls = ecdh.DeriveKeyFromHash(publicKey, HashAlgorithmName.SHA256, null, null);
+
+ Assert.Equal(simple, nulls);
+ }
+ }
+
+ public static IEnumerable<object[]> HashDerivationTestCases()
+ {
+ return new object[][]
+ {
+ new object[]
+ {
+ HashAlgorithmName.SHA256,
+ null,
+ null,
+ "595B71C33D9D40ACD9CA847C47267DAEE7498EEF0B553482FAA45791418AC679",
+ },
+
+ new object[]
+ {
+ HashAlgorithmName.SHA1,
+ null,
+ null,
+ "25E464FAC33F4A5F8786627FB3685F4C31B26327",
+ },
+
+ new object[]
+ {
+ HashAlgorithmName.SHA256,
+ "02040608",
+ null,
+ "D0F4C42D61E794E508A079822F3069C9F89D9E3385C8E090425FF38927798017",
+ },
+
+ new object[]
+ {
+ HashAlgorithmName.SHA256,
+ null,
+ "010305",
+ "20DCB58E2AC4E70B1BF47362B0D1C8B728E27D6575EA9B85106CBE05E1F7D6DB",
+ },
+
+ new object[]
+ {
+ HashAlgorithmName.SHA256,
+ "02040608",
+ "010305",
+ "EFC758D39896E9DE96C120B0A74FB751F140BD7F3F4FC3777DC2A530145E01EC",
+ },
+
+ new object[]
+ {
+ HashAlgorithmName.SHA256,
+ "010305",
+ "02040608",
+ "7DB5520A5D6351595FC286CD53509D964FBB152C289F072581CB5E16EBF319E8",
+ },
+ };
+ }
+
+#if netcoreapp
+ [Theory]
+ [MemberData(nameof(HashDerivationTestCases))]
+ public static void HashDerivation_KnownResults(
+ HashAlgorithmName hashAlgorithm,
+ string prependBytes,
+ string appendBytes,
+ string answerBytes)
+ {
+ byte[] prepend = prependBytes?.HexToByteArray();
+ byte[] append = appendBytes?.HexToByteArray();
+ byte[] answer = answerBytes.HexToByteArray();
+ byte[] output;
+
+ using (ECDiffieHellman ecdh = OpenKnownKey())
+ using (ECDiffieHellmanPublicKey publicKey = ecdh.PublicKey)
+ {
+ output = ecdh.DeriveKeyFromHash(publicKey, hashAlgorithm, prepend, append);
+ }
+
+ Assert.Equal(answer, output);
+ }
+#endif
+ }
+}
diff --git a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.Hmac.cs b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.Hmac.cs
new file mode 100644
index 0000000000..a060b240fb
--- /dev/null
+++ b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.Hmac.cs
@@ -0,0 +1,345 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Security.Cryptography;
+using Test.Cryptography;
+using Xunit;
+
+namespace System.Security.Cryptography.EcDiffieHellman.Tests
+{
+ public partial class ECDiffieHellmanTests
+ {
+ private static readonly byte[] s_sampleHmacKey = { 0, 1, 2, 3, 4, 5 };
+
+ [Fact]
+ public static void HmacDerivation_OtherKeyRequired()
+ {
+ using (ECDiffieHellman ecdh = ECDiffieHellmanFactory.Create())
+ {
+ Assert.Throws<ArgumentNullException>(
+ () => ecdh.DeriveKeyFromHmac(null, HashAlgorithmName.SHA512, null));
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(MismatchedKeysizes))]
+ public static void HmacDerivation_SameSizeOtherKeyRequired(int aliceSize, int bobSize)
+ {
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create(aliceSize))
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create(bobSize))
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ Assert.ThrowsAny<ArgumentException>(
+ () => alice.DeriveKeyFromHmac(bobPublic, HashAlgorithmName.SHA512, null));
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(EveryKeysize))]
+ public static void SymmetricDerivation_Hmac(int keySize)
+ {
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create(keySize))
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create(keySize))
+ using (ECDiffieHellmanPublicKey alicePublic = alice.PublicKey)
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ byte[] aliceDerived = alice.DeriveKeyFromHmac(bobPublic, HashAlgorithmName.SHA512, s_sampleHmacKey);
+ byte[] bobDerived = bob.DeriveKeyFromHmac(alicePublic, HashAlgorithmName.SHA512, s_sampleHmacKey);
+
+ Assert.Equal(aliceDerived, bobDerived);
+ }
+ }
+
+ [Fact]
+ public static void HmacDerivationVariesOnPublicKey()
+ {
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellmanPublicKey alicePublic = alice.PublicKey)
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ byte[] aliceDerived = alice.DeriveKeyFromHmac(bobPublic, HashAlgorithmName.SHA512, s_sampleHmacKey);
+ byte[] aliceSelfDerived = alice.DeriveKeyFromHmac(alicePublic, HashAlgorithmName.SHA512, s_sampleHmacKey);
+
+ // Alice and Alice is HASH(aaG) != HASH(abG)
+ // (Except for the fantastically small chance that Alice == Bob)
+ Assert.NotEqual(aliceDerived, aliceSelfDerived);
+ }
+ }
+
+ [Fact]
+ public static void HmacDerivationVariesOnAlgorithm()
+ {
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellmanPublicKey alicePublic = alice.PublicKey)
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ byte[] aliceDerived = alice.DeriveKeyFromHmac(bobPublic, HashAlgorithmName.SHA512, s_sampleHmacKey);
+ byte[] bobDerived = bob.DeriveKeyFromHmac(alicePublic, HashAlgorithmName.SHA384, s_sampleHmacKey);
+
+ Assert.NotEqual(aliceDerived, bobDerived);
+ }
+ }
+
+ [Fact]
+ public static void HmacDerivationVariesOnKey()
+ {
+ byte[] hmacKeyAlice = { 0, 1, 2, 3, 4, 5 };
+ byte[] hmacKeyBob = { 10, 1, 2, 3, 4, 5 };
+
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellmanPublicKey alicePublic = alice.PublicKey)
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ byte[] aliceDerived = alice.DeriveKeyFromHmac(bobPublic, HashAlgorithmName.SHA512, hmacKeyAlice);
+ byte[] bobDerived = bob.DeriveKeyFromHmac(alicePublic, HashAlgorithmName.SHA512, hmacKeyBob);
+
+ Assert.NotEqual(aliceDerived, bobDerived);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(EveryKeysize))]
+ public static void SymmetricDerivation_HmacPrepend(int keySize)
+ {
+ byte[] prefix = new byte[10];
+
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create(keySize))
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create(keySize))
+ using (ECDiffieHellmanPublicKey alicePublic = alice.PublicKey)
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ byte[] aliceDerived = alice.DeriveKeyFromHmac(bobPublic, HashAlgorithmName.SHA512, s_sampleHmacKey, prefix, null);
+ byte[] bobDerived = bob.DeriveKeyFromHmac(alicePublic, HashAlgorithmName.SHA512, s_sampleHmacKey, prefix, null);
+
+ Assert.Equal(aliceDerived, bobDerived);
+ }
+ }
+
+ [Fact]
+ public static void HmacDerivationVariesOnPrepend()
+ {
+ byte[] alicePrefix = new byte[10];
+ byte[] bobPrefix = new byte[alicePrefix.Length];
+ bobPrefix[0] = 0xFF;
+
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellmanPublicKey alicePublic = alice.PublicKey)
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ byte[] aliceDerived = alice.DeriveKeyFromHmac(bobPublic, HashAlgorithmName.SHA512, s_sampleHmacKey, alicePrefix, null);
+ byte[] bobDerived = bob.DeriveKeyFromHmac(alicePublic, HashAlgorithmName.SHA512, s_sampleHmacKey, bobPrefix, null);
+
+ Assert.NotEqual(aliceDerived, bobDerived);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(EveryKeysize))]
+ public static void SymmetricDerivation_HmacAppend(int keySize)
+ {
+ byte[] suffix = new byte[10];
+
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create(keySize))
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create(keySize))
+ using (ECDiffieHellmanPublicKey alicePublic = alice.PublicKey)
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ byte[] aliceDerived = alice.DeriveKeyFromHmac(bobPublic, HashAlgorithmName.SHA512, s_sampleHmacKey, null, suffix);
+ byte[] bobDerived = bob.DeriveKeyFromHmac(alicePublic, HashAlgorithmName.SHA512, s_sampleHmacKey, null, suffix);
+
+ Assert.Equal(aliceDerived, bobDerived);
+ }
+ }
+
+ [Fact]
+ public static void HmacDerivationVariesOnAppend()
+ {
+ byte[] aliceSuffix = new byte[10];
+ byte[] bobSuffix = new byte[aliceSuffix.Length];
+ bobSuffix[0] = 0xFF;
+
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellmanPublicKey alicePublic = alice.PublicKey)
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ byte[] aliceDerived = alice.DeriveKeyFromHmac(bobPublic, HashAlgorithmName.SHA512, s_sampleHmacKey, null, aliceSuffix);
+ byte[] bobDerived = bob.DeriveKeyFromHmac(alicePublic, HashAlgorithmName.SHA512, s_sampleHmacKey, null, bobSuffix);
+
+ Assert.NotEqual(aliceDerived, bobDerived);
+ }
+ }
+
+ [Fact]
+ public static void HmacDerivationIsStable()
+ {
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ byte[] aliceDerived = alice.DeriveKeyFromHmac(bobPublic, HashAlgorithmName.SHA512, s_sampleHmacKey);
+ byte[] aliceDerivedAgain = alice.DeriveKeyFromHmac(bobPublic, HashAlgorithmName.SHA512, s_sampleHmacKey);
+
+ Assert.Equal(aliceDerived, aliceDerivedAgain);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(EveryKeysize))]
+ public static void SymmetricDerivation_HmacNullKey(int keySize)
+ {
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create(keySize))
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create(keySize))
+ using (ECDiffieHellmanPublicKey alicePublic = alice.PublicKey)
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ byte[] aliceDerived = alice.DeriveKeyFromHmac(bobPublic, HashAlgorithmName.SHA512, null);
+ byte[] bobDerived = bob.DeriveKeyFromHmac(alicePublic, HashAlgorithmName.SHA512, null);
+
+ Assert.Equal(aliceDerived, bobDerived);
+ }
+ }
+
+ [Fact]
+ public static void HmacNullKeyDerivationIsStable()
+ {
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ byte[] aliceDerived = alice.DeriveKeyFromHmac(bobPublic, HashAlgorithmName.SHA512, null);
+ byte[] aliceDerivedAgain = alice.DeriveKeyFromHmac(bobPublic, HashAlgorithmName.SHA512, null);
+
+ Assert.Equal(aliceDerived, aliceDerivedAgain);
+ }
+ }
+
+ [Fact]
+ public static void SimpleHmacMethodForwardsNull()
+ {
+ using (ECDiffieHellman ecdh = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellmanPublicKey publicKey = ecdh.PublicKey)
+ {
+ byte[] simple = ecdh.DeriveKeyFromHmac(publicKey, HashAlgorithmName.SHA512, s_sampleHmacKey);
+ byte[] nulls = ecdh.DeriveKeyFromHmac(publicKey, HashAlgorithmName.SHA512, s_sampleHmacKey, null, null);
+
+ Assert.Equal(simple, nulls);
+ }
+ }
+
+ [Fact]
+ public static void SimpleHmacNullKeyForwardsNull()
+ {
+ using (ECDiffieHellman ecdh = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellmanPublicKey publicKey = ecdh.PublicKey)
+ {
+ byte[] simple = ecdh.DeriveKeyFromHmac(publicKey, HashAlgorithmName.SHA512, null);
+ byte[] nulls = ecdh.DeriveKeyFromHmac(publicKey, HashAlgorithmName.SHA512, null, null, null);
+
+ Assert.Equal(simple, nulls);
+ }
+ }
+
+ public static IEnumerable<object[]> HmacDerivationTestCases()
+ {
+ return new object[][]
+ {
+ new object[]
+ {
+ HashAlgorithmName.SHA256,
+ null,
+ null,
+ null,
+ "6D7D15C9A08FD47DFDABD3541BE3BBAF93B15FC65D30E6012CCC0B23ED5C43FF",
+ },
+
+ new object[]
+ {
+ HashAlgorithmName.SHA1,
+ null,
+ null,
+ null,
+ "39D4B035BC1A1E4108B965689E27BA98ACED8449",
+ },
+
+ new object[]
+ {
+ HashAlgorithmName.SHA256,
+ "030609",
+ null,
+ null,
+ "7A4F81BF065CC521AFB162DB4A45CEFC78227178A58632EA53D3E367AB7D1979",
+ },
+
+ new object[]
+ {
+ HashAlgorithmName.SHA256,
+ null,
+ "02040608",
+ "010305",
+ "DB39A6AC9334701D2DCD508C401C65BC69348F684C85EDDE506950F049668842",
+ },
+
+ new object[]
+ {
+ HashAlgorithmName.SHA256,
+ null,
+ "010305",
+ "02040608",
+ "66471DE2655DF9404636F9076F845F0B71A04DDA2BA6F1469EB0F2E9EF57DC33",
+ },
+
+ new object[]
+ {
+ HashAlgorithmName.SHA256,
+ "030609",
+ "02040608",
+ "010305",
+ "2F7A31FF9118A6BBF92E268568C634A9F1E244CA8C1A74C864DECC50727B7DEE",
+ },
+
+ new object[]
+ {
+ HashAlgorithmName.SHA256,
+ "030609",
+ "010305",
+ "02040608",
+ "AE3CD974F262B199B0859D9F933207D2F6E3E04434D60089FE0BE801ED38D370",
+ },
+ };
+ }
+
+#if netcoreapp
+ [Theory]
+ [MemberData(nameof(HmacDerivationTestCases))]
+ public static void HmacDerivation_KnownResults(
+ HashAlgorithmName hashAlgorithm,
+ string hmacKeyBytes,
+ string prependBytes,
+ string appendBytes,
+ string answerBytes)
+ {
+ byte[] hmacKey = hmacKeyBytes?.HexToByteArray();
+ byte[] prepend = prependBytes?.HexToByteArray();
+ byte[] append = appendBytes?.HexToByteArray();
+ byte[] answer = answerBytes.HexToByteArray();
+ byte[] output;
+
+ using (ECDiffieHellman ecdh = OpenKnownKey())
+ using (ECDiffieHellmanPublicKey publicKey = ecdh.PublicKey)
+ {
+ output = ecdh.DeriveKeyFromHmac(publicKey, hashAlgorithm, hmacKey, prepend, append);
+ }
+
+ Assert.Equal(answer, output);
+ }
+#endif
+ }
+}
diff --git a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.ImportExport.cs b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.ImportExport.cs
new file mode 100644
index 0000000000..d35f3db6e5
--- /dev/null
+++ b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.ImportExport.cs
@@ -0,0 +1,440 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Security.Cryptography.Tests;
+using Test.Cryptography;
+using Xunit;
+
+namespace System.Security.Cryptography.EcDiffieHellman.Tests
+{
+#if netcoreapp
+ public partial class ECDiffieHellmanTests
+ {
+ // On CentOS, secp224r1 (also called nistP224) appears to be disabled. To prevent test failures on that platform,
+ // probe for this capability before depending on it.
+ internal static bool ECDsa224Available =>
+ ECDiffieHellmanFactory.IsCurveValid(new Oid(ECDSA_P224_OID_VALUE));
+
+ [Theory, MemberData(nameof(TestCurvesFull))]
+ public static void TestNamedCurves(CurveDef curveDef)
+ {
+ if (!curveDef.Curve.IsNamed)
+ return;
+
+ using (ECDiffieHellman ec1 = ECDiffieHellmanFactory.Create(curveDef.Curve))
+ {
+ ECParameters param1 = ec1.ExportParameters(curveDef.IncludePrivate);
+ VerifyNamedCurve(param1, ec1, curveDef.KeySize, curveDef.IncludePrivate);
+
+ using (ECDiffieHellman ec2 = ECDiffieHellmanFactory.Create())
+ {
+ ec2.ImportParameters(param1);
+ ECParameters param2 = ec2.ExportParameters(curveDef.IncludePrivate);
+ VerifyNamedCurve(param2, ec2, curveDef.KeySize, curveDef.IncludePrivate);
+
+ AssertEqual(param1, param2);
+ }
+ }
+ }
+
+ [Theory, MemberData(nameof(TestInvalidCurves))]
+ public static void TestNamedCurvesNegative(CurveDef curveDef)
+ {
+ if (!curveDef.Curve.IsNamed)
+ return;
+
+ // An exception may be thrown during Create() if the Oid is bad, or later during native calls
+ Assert.Throws<PlatformNotSupportedException>(
+ () => ECDiffieHellmanFactory.Create(curveDef.Curve).ExportParameters(false));
+ }
+
+ [Theory, MemberData(nameof(TestCurvesFull))]
+ public static void TestExplicitCurves(CurveDef curveDef)
+ {
+ if (!ECDiffieHellmanFactory.ExplicitCurvesSupported)
+ {
+ return;
+ }
+
+ using (ECDiffieHellman ec1 = ECDiffieHellmanFactory.Create(curveDef.Curve))
+ {
+ ECParameters param1 = ec1.ExportExplicitParameters(curveDef.IncludePrivate);
+ VerifyExplicitCurve(param1, ec1, curveDef);
+
+ using (ECDiffieHellman ec2 = ECDiffieHellmanFactory.Create())
+ {
+ ec2.ImportParameters(param1);
+ ECParameters param2 = ec2.ExportExplicitParameters(curveDef.IncludePrivate);
+ VerifyExplicitCurve(param1, ec1, curveDef);
+
+ AssertEqual(param1, param2);
+ }
+ }
+ }
+
+ [Theory, MemberData(nameof(TestCurves))]
+ public static void TestExplicitCurvesKeyAgree(CurveDef curveDef)
+ {
+ if (!ECDiffieHellmanFactory.ExplicitCurvesSupported)
+ {
+ return;
+ }
+
+ using (ECDiffieHellman ecdh1Named = ECDiffieHellmanFactory.Create(curveDef.Curve))
+ {
+ ECParameters ecdh1ExplicitParameters = ecdh1Named.ExportExplicitParameters(true);
+
+ using (ECDiffieHellman ecdh1Explicit = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellman ecdh2 = ECDiffieHellmanFactory.Create(ecdh1ExplicitParameters.Curve))
+ {
+ ecdh1Explicit.ImportParameters(ecdh1ExplicitParameters);
+
+ using (ECDiffieHellmanPublicKey ecdh1NamedPub = ecdh1Named.PublicKey)
+ using (ECDiffieHellmanPublicKey ecdh1ExplicitPub = ecdh1Explicit.PublicKey)
+ using (ECDiffieHellmanPublicKey ecdh2Pub = ecdh2.PublicKey)
+ {
+ HashAlgorithmName hash = HashAlgorithmName.SHA256;
+
+ byte[] ech1Named_ecdh1Named = ecdh1Named.DeriveKeyFromHash(ecdh1NamedPub, hash);
+ byte[] ech1Named_ecdh1Named2 = ecdh1Named.DeriveKeyFromHash(ecdh1NamedPub, hash);
+ byte[] ech1Named_ecdh1Explicit = ecdh1Named.DeriveKeyFromHash(ecdh1ExplicitPub, hash);
+ byte[] ech1Named_ecdh2Explicit = ecdh1Named.DeriveKeyFromHash(ecdh2Pub, hash);
+
+ byte[] ecdh1Explicit_ecdh1Named = ecdh1Explicit.DeriveKeyFromHash(ecdh1NamedPub, hash);
+ byte[] ecdh1Explicit_ecdh1Explicit = ecdh1Explicit.DeriveKeyFromHash(ecdh1ExplicitPub, hash);
+ byte[] ecdh1Explicit_ecdh1Explicit2 = ecdh1Explicit.DeriveKeyFromHash(ecdh1ExplicitPub, hash);
+ byte[] ecdh1Explicit_ecdh2Explicit = ecdh1Explicit.DeriveKeyFromHash(ecdh2Pub, hash);
+
+ byte[] ecdh2_ecdh1Named = ecdh2.DeriveKeyFromHash(ecdh1NamedPub, hash);
+ byte[] ecdh2_ecdh1Explicit = ecdh2.DeriveKeyFromHash(ecdh1ExplicitPub, hash);
+ byte[] ecdh2_ecdh2Explicit = ecdh2.DeriveKeyFromHash(ecdh2Pub, hash);
+ byte[] ecdh2_ecdh2Explicit2 = ecdh2.DeriveKeyFromHash(ecdh2Pub, hash);
+
+ Assert.Equal(ech1Named_ecdh1Named, ech1Named_ecdh1Named2);
+ Assert.Equal(ech1Named_ecdh1Explicit, ecdh1Explicit_ecdh1Named);
+ Assert.Equal(ech1Named_ecdh2Explicit, ecdh2_ecdh1Named);
+
+ Assert.Equal(ecdh1Explicit_ecdh1Explicit, ecdh1Explicit_ecdh1Explicit2);
+ Assert.Equal(ecdh1Explicit_ecdh2Explicit, ecdh2_ecdh1Explicit);
+
+ Assert.Equal(ecdh2_ecdh2Explicit, ecdh2_ecdh2Explicit2);
+ }
+ }
+ }
+ }
+
+ [Fact]
+ public static void TestNamedCurveNegative()
+ {
+ Assert.Throws<PlatformNotSupportedException>(
+ () => ECDiffieHellmanFactory.Create(ECCurve.CreateFromFriendlyName("Invalid")).ExportExplicitParameters(false));
+
+ Assert.Throws<PlatformNotSupportedException>(
+ () => ECDiffieHellmanFactory.Create(ECCurve.CreateFromValue("Invalid")).ExportExplicitParameters(false));
+ }
+
+ [Fact]
+ public static void TestKeySizeCreateKey()
+ {
+ using (ECDiffieHellman ec = ECDiffieHellmanFactory.Create(ECCurve.NamedCurves.nistP256))
+ {
+ // Ensure the handle is created
+ Assert.Equal(256, ec.KeySize);
+ ec.Exercise();
+
+ ec.KeySize = 521; //nistP521
+ Assert.Equal(521, ec.KeySize);
+ ec.Exercise();
+
+ Assert.ThrowsAny<CryptographicException>(() => ec.KeySize = 9999);
+ }
+ }
+
+ [Fact]
+ public static void TestExplicitImportValidationNegative()
+ {
+ if (!ECDiffieHellmanFactory.ExplicitCurvesSupported)
+ {
+ return;
+ }
+
+ unchecked
+ {
+ using (ECDiffieHellman ec = ECDiffieHellmanFactory.Create())
+ {
+ ECParameters p = EccTestData.GetNistP256ExplicitTestData();
+ Assert.True(p.Curve.IsPrime);
+ ec.ImportParameters(p);
+
+ ECParameters temp = p;
+ temp.Q.X = null; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+ temp.Q.X = new byte[] { }; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+ temp.Q.X = new byte[1] { 0x10 }; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+ temp.Q.X = (byte[])p.Q.X.Clone(); --temp.Q.X[0]; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+
+ temp = p;
+ temp.Q.Y = null; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+ temp.Q.Y = new byte[] { }; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+ temp.Q.Y = new byte[1] { 0x10 }; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+ temp.Q.Y = (byte[])p.Q.Y.Clone(); --temp.Q.Y[0]; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+
+ temp = p;
+ temp.Curve.A = null; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+ temp.Curve.A = new byte[] { }; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+ temp.Curve.A = new byte[1] { 0x10 }; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+ temp.Curve.A = (byte[])p.Curve.A.Clone(); --temp.Curve.A[0]; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+
+ temp = p;
+ temp.Curve.B = null; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+ temp.Curve.B = new byte[] { }; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+ temp.Curve.B = new byte[1] { 0x10 }; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+ temp.Curve.B = (byte[])p.Curve.B.Clone(); --temp.Curve.B[0]; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+
+ temp = p;
+ temp.Curve.Order = null; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+ temp.Curve.Order = new byte[] { }; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+
+ temp = p;
+ temp.Curve.Prime = null; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+ temp.Curve.Prime = new byte[] { }; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+ temp.Curve.Prime = new byte[1] { 0x10 }; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+ temp.Curve.Prime = (byte[])p.Curve.Prime.Clone(); --temp.Curve.Prime[0]; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+ }
+ }
+ }
+
+ [Fact]
+ public static void ImportExplicitWithSeedButNoHash()
+ {
+ if (!ECDiffieHellmanFactory.ExplicitCurvesSupported)
+ {
+ return;
+ }
+
+ using (ECDiffieHellman ec = ECDiffieHellmanFactory.Create())
+ {
+ ECCurve curve = EccTestData.GetNistP256ExplicitCurve();
+ Assert.NotNull(curve.Hash);
+ ec.GenerateKey(curve);
+
+ ECParameters parameters = ec.ExportExplicitParameters(true);
+ Assert.NotNull(parameters.Curve.Seed);
+ parameters.Curve.Hash = null;
+
+ ec.ImportParameters(parameters);
+ ec.Exercise();
+ }
+ }
+
+ [Fact]
+ [PlatformSpecific(TestPlatforms.Windows/* "parameters.Curve.Hash doesn't round trip on Unix." */)]
+ public static void ImportExplicitWithHashButNoSeed()
+ {
+ if (!ECDiffieHellmanFactory.ExplicitCurvesSupported)
+ {
+ return;
+ }
+
+ using (ECDiffieHellman ec = ECDiffieHellmanFactory.Create())
+ {
+ ECCurve curve = EccTestData.GetNistP256ExplicitCurve();
+ Assert.NotNull(curve.Hash);
+ ec.GenerateKey(curve);
+
+ ECParameters parameters = ec.ExportExplicitParameters(true);
+ Assert.NotNull(parameters.Curve.Hash);
+ parameters.Curve.Seed = null;
+
+ ec.ImportParameters(parameters);
+ ec.Exercise();
+ }
+ }
+
+ [ConditionalFact(nameof(ECDsa224Available))]
+ public static void TestNamedImportValidationNegative()
+ {
+ if (!ECDiffieHellmanFactory.ExplicitCurvesSupported)
+ {
+ return;
+ }
+
+ unchecked
+ {
+ using (ECDiffieHellman ec = ECDiffieHellmanFactory.Create())
+ {
+ ECParameters p = EccTestData.GetNistP224KeyTestData();
+ Assert.True(p.Curve.IsNamed);
+ var q = p.Q;
+ var c = p.Curve;
+ ec.ImportParameters(p);
+
+ ECParameters temp = p;
+ temp.Q.X = null; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+ temp.Q.X = new byte[] { }; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+ temp.Q.X = new byte[1] { 0x10 }; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+ temp.Q.X = (byte[])p.Q.X.Clone(); temp.Q.X[0]--; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+
+ temp = p;
+ temp.Q.Y = null; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+ temp.Q.Y = new byte[] { }; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+ temp.Q.Y = new byte[1] { 0x10 }; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+ temp.Q.Y = (byte[])p.Q.Y.Clone(); temp.Q.Y[0]--; Assert.ThrowsAny<CryptographicException>(() => ec.ImportParameters(temp));
+
+ temp = p; temp.Curve = ECCurve.CreateFromOid(new Oid("Invalid", "Invalid")); Assert.ThrowsAny<PlatformNotSupportedException>(() => ec.ImportParameters(temp));
+ }
+ }
+ }
+
+ [Fact]
+ public static void TestGeneralExportWithExplicitParameters()
+ {
+ if (!ECDiffieHellmanFactory.ExplicitCurvesSupported)
+ {
+ return;
+ }
+
+ using (ECDiffieHellman ecdsa = ECDiffieHellmanFactory.Create())
+ {
+ ECParameters param = EccTestData.GetNistP256ExplicitTestData();
+ param.Validate();
+ ecdsa.ImportParameters(param);
+ Assert.True(param.Curve.IsExplicit);
+
+ param = ecdsa.ExportParameters(false);
+ param.Validate();
+
+ // We should have explicit values, not named, as this curve has no name.
+ Assert.True(param.Curve.IsExplicit);
+ }
+ }
+
+ [Fact]
+ public static void TestExplicitCurveImportOnUnsupportedPlatform()
+ {
+ if (ECDiffieHellmanFactory.ExplicitCurvesSupported)
+ {
+ return;
+ }
+
+ using (ECDiffieHellman ecdh = ECDiffieHellmanFactory.Create())
+ {
+ ECParameters param = EccTestData.GetNistP256ExplicitTestData();
+
+ Assert.Throws<PlatformNotSupportedException>(
+ () =>
+ {
+ try
+ {
+ ecdh.ImportParameters(param);
+ }
+ catch (CryptographicException e)
+ {
+ throw new PlatformNotSupportedException("Converting exception", e);
+ }
+ });
+ }
+ }
+
+ [ConditionalFact(nameof(ECDsa224Available))]
+ public static void TestNamedCurveWithExplicitKey()
+ {
+ if (!ECDiffieHellmanFactory.ExplicitCurvesSupported)
+ {
+ return;
+ }
+
+ using (ECDiffieHellman ec = ECDiffieHellmanFactory.Create())
+ {
+ ECParameters parameters = EccTestData.GetNistP224KeyTestData();
+ ec.ImportParameters(parameters);
+ VerifyNamedCurve(parameters, ec, 224, true);
+ }
+ }
+
+ [Fact]
+ public static void ExportIncludingPrivateOnPublicOnlyKey()
+ {
+ ECParameters iutParameters = new ECParameters
+ {
+ Curve = ECCurve.NamedCurves.nistP521,
+ Q =
+ {
+ X = "00d45615ed5d37fde699610a62cd43ba76bedd8f85ed31005fe00d6450fbbd101291abd96d4945a8b57bc73b3fe9f4671105309ec9b6879d0551d930dac8ba45d255".HexToByteArray(),
+ Y = "01425332844e592b440c0027972ad1526431c06732df19cd46a242172d4dd67c2c8c99dfc22e49949a56cf90c6473635ce82f25b33682fb19bc33bd910ed8ce3a7fa".HexToByteArray(),
+ },
+ D = "00816f19c1fb10ef94d4a1d81c156ec3d1de08b66761f03f06ee4bb9dcebbbfe1eaa1ed49a6a990838d8ed318c14d74cc872f95d05d07ad50f621ceb620cd905cfb8".HexToByteArray(),
+ };
+
+ using (ECDiffieHellman iut = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellman cavs = ECDiffieHellmanFactory.Create())
+ {
+ iut.ImportParameters(iutParameters);
+ cavs.ImportParameters(iut.ExportParameters(false));
+
+ Assert.ThrowsAny<CryptographicException>(() => cavs.ExportParameters(true));
+
+ if (ECDiffieHellmanFactory.ExplicitCurvesSupported)
+ {
+ Assert.ThrowsAny<CryptographicException>(() => cavs.ExportExplicitParameters(true));
+ }
+
+ using (ECDiffieHellmanPublicKey iutPublic = iut.PublicKey)
+ {
+ Assert.ThrowsAny<CryptographicException>(() => cavs.DeriveKeyFromHash(iutPublic, HashAlgorithmName.SHA256));
+ }
+ }
+ }
+
+ private static void VerifyNamedCurve(ECParameters parameters, ECDiffieHellman ec, int keySize, bool includePrivate)
+ {
+ parameters.Validate();
+ Assert.True(parameters.Curve.IsNamed);
+ Assert.Equal(keySize, ec.KeySize);
+ Assert.True(
+ includePrivate && parameters.D.Length > 0 ||
+ !includePrivate && parameters.D == null);
+
+ if (includePrivate)
+ ec.Exercise();
+
+ // Ensure the key doesn't get regenerated after export
+ ECParameters paramSecondExport = ec.ExportParameters(includePrivate);
+ paramSecondExport.Validate();
+ AssertEqual(parameters, paramSecondExport);
+ }
+
+ private static void VerifyExplicitCurve(ECParameters parameters, ECDiffieHellman ec, CurveDef curveDef)
+ {
+ Assert.True(parameters.Curve.IsExplicit);
+ ECCurve curve = parameters.Curve;
+
+
+ Assert.True(curveDef.IsCurveTypeEqual(curve.CurveType));
+ Assert.True(
+ curveDef.IncludePrivate && parameters.D.Length > 0 ||
+ !curveDef.IncludePrivate && parameters.D == null);
+ Assert.Equal(curveDef.KeySize, ec.KeySize);
+
+ Assert.Equal(curve.A.Length, parameters.Q.X.Length);
+ Assert.Equal(curve.A.Length, parameters.Q.Y.Length);
+ Assert.Equal(curve.A.Length, curve.B.Length);
+ Assert.Equal(curve.A.Length, curve.G.X.Length);
+ Assert.Equal(curve.A.Length, curve.G.Y.Length);
+ Assert.True(curve.Seed == null || curve.Seed.Length > 0);
+ Assert.True(curve.Order == null || curve.Order.Length > 0);
+ if (curve.IsPrime)
+ {
+ Assert.Equal(curve.A.Length, curve.Prime.Length);
+ }
+
+ if (curveDef.IncludePrivate)
+ ec.Exercise();
+
+ // Ensure the key doesn't get regenerated after export
+ ECParameters paramSecondExport = ec.ExportExplicitParameters(curveDef.IncludePrivate);
+ AssertEqual(parameters, paramSecondExport);
+ }
+ }
+#endif
+}
diff --git a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.NistValidation.cs b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.NistValidation.cs
new file mode 100644
index 0000000000..2eddcda17e
--- /dev/null
+++ b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.NistValidation.cs
@@ -0,0 +1,233 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Tests;
+using Test.Cryptography;
+using Xunit;
+
+namespace System.Security.Cryptography.EcDiffieHellman.Tests
+{
+#if netcoreapp
+ // These test cases are from http://csrc.nist.gov/groups/STM/cavp/component-testing.html#test-vectors
+ // SP 800-56A ECCCDH Primitive test vectors
+ // ecccdhtestvectors.zip
+ // KAS_ECC_CDH_PrimitiveTest.txt
+ public partial class ECDiffieHellmanTests
+ {
+ [Fact]
+ public static void ValidateNistP256_0()
+ {
+ Verify(
+ ECCurve.NamedCurves.nistP256,
+ EccTestData.GetNistP256ExplicitCurve(),
+ "700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287",
+ "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac",
+ "7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534",
+ "ead218590119e8876b29146ff89ca61770c4edbbf97d38ce385ed281d8a6b230",
+ "28af61281fd35e2fa7002523acc85a429cb06ee6648325389f59edfce1405141",
+ "46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b");
+ }
+
+ [Fact]
+ public static void ValidateNistP256_1()
+ {
+ Verify(
+ ECCurve.NamedCurves.nistP256,
+ EccTestData.GetNistP256ExplicitCurve(),
+ "809f04289c64348c01515eb03d5ce7ac1a8cb9498f5caa50197e58d43a86a7ae",
+ "b29d84e811197f25eba8f5194092cb6ff440e26d4421011372461f579271cda3",
+ "38f65d6dce47676044d58ce5139582d568f64bb16098d179dbab07741dd5caf5",
+ "119f2f047902782ab0c9e27a54aff5eb9b964829ca99c06b02ddba95b0a3f6d0",
+ "8f52b726664cac366fc98ac7a012b2682cbd962e5acb544671d41b9445704d1d",
+ "057d636096cb80b67a8c038c890e887d1adfa4195e9b3ce241c8a778c59cda67");
+ }
+
+ [Fact]
+ public static void ValidateNistP384_0()
+ {
+ Verify(
+ ECCurve.NamedCurves.nistP384,
+ EccTestData.GetNistP384ExplicitCurve(),
+ "a7c76b970c3b5fe8b05d2838ae04ab47697b9eaf52e764592efda27fe7513272734466b400091adbf2d68c58e0c50066",
+ "ac68f19f2e1cb879aed43a9969b91a0839c4c38a49749b661efedf243451915ed0905a32b060992b468c64766fc8437a",
+ "3cc3122a68f0d95027ad38c067916ba0eb8c38894d22e1b15618b6818a661774ad463b205da88cf699ab4d43c9cf98a1",
+ "9803807f2f6d2fd966cdd0290bd410c0190352fbec7ff6247de1302df86f25d34fe4a97bef60cff548355c015dbb3e5f",
+ "ba26ca69ec2f5b5d9dad20cc9da711383a9dbe34ea3fa5a2af75b46502629ad54dd8b7d73a8abb06a3a3be47d650cc99",
+ "5f9d29dc5e31a163060356213669c8ce132e22f57c9a04f40ba7fcead493b457e5621e766c40a2e3d4d6a04b25e533f1");
+ }
+
+ [Fact]
+ public static void ValidateNistP384_1()
+ {
+ Verify(
+ ECCurve.NamedCurves.nistP384,
+ EccTestData.GetNistP384ExplicitCurve(),
+ "30f43fcf2b6b00de53f624f1543090681839717d53c7c955d1d69efaf0349b7363acb447240101cbb3af6641ce4b88e0",
+ "25e46c0c54f0162a77efcc27b6ea792002ae2ba82714299c860857a68153ab62e525ec0530d81b5aa15897981e858757",
+ "92860c21bde06165f8e900c687f8ef0a05d14f290b3f07d8b3a8cc6404366e5d5119cd6d03fb12dc58e89f13df9cd783",
+ "ea4018f5a307c379180bf6a62fd2ceceebeeb7d4df063a66fb838aa35243419791f7e2c9d4803c9319aa0eb03c416b66",
+ "68835a91484f05ef028284df6436fb88ffebabcdd69ab0133e6735a1bcfb37203d10d340a8328a7b68770ca75878a1a6",
+ "a23742a2c267d7425fda94b93f93bbcc24791ac51cd8fd501a238d40812f4cbfc59aac9520d758cf789c76300c69d2ff");
+ }
+
+ [Fact]
+ public static void ValidateNistP521_0()
+ {
+ Verify(
+ ECCurve.NamedCurves.nistP521,
+ EccTestData.GetNistP521ExplicitCurve(),
+ "00685a48e86c79f0f0875f7bc18d25eb5fc8c0b07e5da4f4370f3a9490340854334b1e1b87fa395464c60626124a4e70d0f785601d37c09870ebf176666877a2046d",
+ "01ba52c56fc8776d9e8f5db4f0cc27636d0b741bbe05400697942e80b739884a83bde99e0f6716939e632bc8986fa18dccd443a348b6c3e522497955a4f3c302f676",
+ "017eecc07ab4b329068fba65e56a1f8890aa935e57134ae0ffcce802735151f4eac6564f6ee9974c5e6887a1fefee5743ae2241bfeb95d5ce31ddcb6f9edb4d6fc47",
+ "00602f9d0cf9e526b29e22381c203c48a886c2b0673033366314f1ffbcba240ba42f4ef38a76174635f91e6b4ed34275eb01c8467d05ca80315bf1a7bbd945f550a5",
+ "01b7c85f26f5d4b2d7355cf6b02117659943762b6d1db5ab4f1dbc44ce7b2946eb6c7de342962893fd387d1b73d7a8672d1f236961170b7eb3579953ee5cdc88cd2d",
+ "005fc70477c3e63bc3954bd0df3ea0d1f41ee21746ed95fc5e1fdf90930d5e136672d72cc770742d1711c3c3a4c334a0ad9759436a4d3c5bf6e74b9578fac148c831");
+ }
+
+ [Fact]
+ public static void ValidateNistP521_1()
+ {
+ Verify(
+ ECCurve.NamedCurves.nistP521,
+ EccTestData.GetNistP521ExplicitCurve(),
+ "01df277c152108349bc34d539ee0cf06b24f5d3500677b4445453ccc21409453aafb8a72a0be9ebe54d12270aa51b3ab7f316aa5e74a951c5e53f74cd95fc29aee7a",
+ "013d52f33a9f3c14384d1587fa8abe7aed74bc33749ad9c570b471776422c7d4505d9b0a96b3bfac041e4c6a6990ae7f700e5b4a6640229112deafa0cd8bb0d089b0",
+ "00816f19c1fb10ef94d4a1d81c156ec3d1de08b66761f03f06ee4bb9dcebbbfe1eaa1ed49a6a990838d8ed318c14d74cc872f95d05d07ad50f621ceb620cd905cfb8",
+ "00d45615ed5d37fde699610a62cd43ba76bedd8f85ed31005fe00d6450fbbd101291abd96d4945a8b57bc73b3fe9f4671105309ec9b6879d0551d930dac8ba45d255",
+ "01425332844e592b440c0027972ad1526431c06732df19cd46a242172d4dd67c2c8c99dfc22e49949a56cf90c6473635ce82f25b33682fb19bc33bd910ed8ce3a7fa",
+ "000b3920ac830ade812c8f96805da2236e002acbbf13596a9ab254d44d0e91b6255ebf1229f366fb5a05c5884ef46032c26d42189273ca4efa4c3db6bd12a6853759");
+ }
+
+ private static void Verify(
+ ECCurve namedCurve,
+ ECCurve explicitCurve,
+ string cavsQx,
+ string cavsQy,
+ string iutD,
+ string iutQx,
+ string iutQy,
+ string iutZ)
+ {
+ Assert.True(namedCurve.IsNamed, "namedCurve.IsNamed");
+ Assert.True(explicitCurve.IsExplicit, "explicitCurve.IsExplicit");
+
+ ECParameters iutParameters = new ECParameters
+ {
+ Curve = namedCurve,
+ Q =
+ {
+ X = iutQx.HexToByteArray(),
+ Y = iutQy.HexToByteArray(),
+ },
+ D = iutD.HexToByteArray(),
+ };
+
+ ECParameters cavsParameters = new ECParameters
+ {
+ Curve = namedCurve,
+ Q =
+ {
+ X = cavsQx.HexToByteArray(),
+ Y = cavsQy.HexToByteArray(),
+ },
+ };
+
+ Verify(ref iutParameters, ref cavsParameters, explicitCurve, iutZ.HexToByteArray());
+ }
+
+ private static void Verify(
+ ref ECParameters iutParameters,
+ ref ECParameters cavsParameters,
+ ECCurve explicitCurve,
+ byte[] iutZ)
+ {
+ using (ECDiffieHellman iut = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellman cavs = ECDiffieHellmanFactory.Create())
+ {
+ iut.ImportParameters(iutParameters);
+ cavs.ImportParameters(cavsParameters);
+
+ using (ECDiffieHellmanPublicKey cavsPublic = cavs.PublicKey)
+ using (HashAlgorithm sha256 = SHA256.Create())
+ using (HashAlgorithm sha384 = SHA384.Create())
+ {
+ Verify(iut, cavsPublic, sha256, HashAlgorithmName.SHA256, iutZ);
+ Verify(iut, cavsPublic, sha384, HashAlgorithmName.SHA384, iutZ);
+ }
+
+ if (ECDiffieHellmanFactory.ExplicitCurvesSupported)
+ {
+ iutParameters.Curve = explicitCurve;
+ iut.ImportParameters(iutParameters);
+
+ // IUT is explicit, CAVS is named, but they're the same key.
+ // If this test ever starts throwing CryptographicException we can guard it.
+ // Support is entirely left up to the library.
+ // It was kind of surprising that it worked.
+ using (ECDiffieHellmanPublicKey cavsPublic = cavs.PublicKey)
+ using (HashAlgorithm sha256 = SHA256.Create())
+ using (HashAlgorithm sha512 = SHA512.Create())
+ {
+ bool trySecondCase = true;
+
+ try
+ {
+ Verify(iut, cavsPublic, sha256, HashAlgorithmName.SHA256, iutZ);
+ }
+ catch (CryptographicException)
+ {
+ // This is expected to work on Windows.
+ // On Linux (via OpenSSL) it is less predictable, since it fails with
+ // EVP_PKEY_derive_set_peer:different parameters if one key uses
+ // the GFp_simple routines and another uses GFp_nist or GFp_mont (or,
+ // one presumes, something custom from an HSM) even if they actually
+ // represent the same curve.
+ //
+ // secp256r1 and secp521r1 both succeed this block, secp384r1 fails.
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ throw;
+ }
+
+ trySecondCase = false;
+ }
+
+ // If the first one failed, don't try the second.
+ // If the first one passed, the second should, too.
+ if (trySecondCase)
+ {
+ Verify(iut, cavsPublic, sha512, HashAlgorithmName.SHA512, iutZ);
+ }
+ }
+
+ cavsParameters.Curve = explicitCurve;
+ cavs.ImportParameters(cavsParameters);
+
+ // Explicit, explicit; over the same curve.
+ using (ECDiffieHellmanPublicKey cavsPublic = cavs.PublicKey)
+ using (HashAlgorithm sha384 = SHA384.Create())
+ using (HashAlgorithm sha512 = SHA512.Create())
+ {
+ Verify(iut, cavsPublic, sha384, HashAlgorithmName.SHA384, iutZ);
+ Verify(iut, cavsPublic, sha512, HashAlgorithmName.SHA512, iutZ);
+ }
+ }
+ }
+ }
+
+ private static void Verify(
+ ECDiffieHellman iut,
+ ECDiffieHellmanPublicKey cavsPublic,
+ HashAlgorithm zHasher,
+ HashAlgorithmName zHashAlgorithm,
+ byte[] iutZ)
+ {
+ byte[] result = iut.DeriveKeyFromHash(cavsPublic, zHashAlgorithm);
+ byte[] hashedZ = zHasher.ComputeHash(iutZ);
+ Assert.Equal(hashedZ.ByteArrayToHex(), result.ByteArrayToHex());
+ }
+ }
+#endif
+}
diff --git a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.Tls.cs b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.Tls.cs
new file mode 100644
index 0000000000..c11badb5d0
--- /dev/null
+++ b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.Tls.cs
@@ -0,0 +1,213 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Text;
+using Test.Cryptography;
+using Xunit;
+
+namespace System.Security.Cryptography.EcDiffieHellman.Tests
+{
+ public partial class ECDiffieHellmanTests
+ {
+ private static readonly byte[] s_fourByteLabel = new byte[4];
+ private static readonly byte[] s_emptySeed = new byte[64];
+
+ [Fact]
+ public static void TlsDerivation_OtherKeyRequired()
+ {
+ using (ECDiffieHellman ecdh = ECDiffieHellmanFactory.Create())
+ {
+ Assert.Throws<ArgumentNullException>(
+ () => ecdh.DeriveKeyTls(null, s_fourByteLabel, s_emptySeed));
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(MismatchedKeysizes))]
+ public static void TlsDerivation_SameSizeOtherKeyRequired(int aliceSize, int bobSize)
+ {
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create(aliceSize))
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create(bobSize))
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ Assert.ThrowsAny<ArgumentException>(
+ () => alice.DeriveKeyTls(bobPublic, s_fourByteLabel, s_emptySeed));
+ }
+ }
+
+ [Fact]
+ public static void TlsRequiresLabel()
+ {
+ using (ECDiffieHellman ecdh = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellmanPublicKey publicKey = ecdh.PublicKey)
+ {
+ Assert.Throws<ArgumentNullException>(
+ () => ecdh.DeriveKeyTls(publicKey, null, s_emptySeed));
+ }
+ }
+
+ [Fact]
+ public static void TlsRequiresSeed()
+ {
+ using (ECDiffieHellman ecdh = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellmanPublicKey publicKey = ecdh.PublicKey)
+ {
+ Assert.Throws<ArgumentNullException>(
+ () => ecdh.DeriveKeyTls(publicKey, s_fourByteLabel, null));
+ }
+ }
+
+ [Theory]
+ [InlineData(0)]
+ [InlineData(63)]
+ [InlineData(65)]
+ public static void TlsRequiresSeed64(int seedSize)
+ {
+ byte[] seed = new byte[seedSize];
+
+ using (ECDiffieHellman ecdh = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellmanPublicKey publicKey = ecdh.PublicKey)
+ {
+ Assert.ThrowsAny<CryptographicException>(
+ () => ecdh.DeriveKeyTls(publicKey, s_fourByteLabel, seed));
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(EveryKeysize))]
+ public static void SymmetricDerivation_TlsPrf(int keySize)
+ {
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create(keySize))
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create(keySize))
+ using (ECDiffieHellmanPublicKey alicePublic = alice.PublicKey)
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ byte[] aliceDerived = alice.DeriveKeyTls(bobPublic, s_fourByteLabel, s_emptySeed);
+ byte[] bobDerived = bob.DeriveKeyTls(alicePublic, s_fourByteLabel, s_emptySeed);
+
+ Assert.Equal(aliceDerived, bobDerived);
+ }
+ }
+
+ [Fact]
+ public static void TlsPrfDerivationIsStable()
+ {
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ byte[] aliceDerived = alice.DeriveKeyTls(bobPublic, s_fourByteLabel, s_emptySeed);
+ byte[] aliceDerivedAgain = alice.DeriveKeyTls(bobPublic, s_fourByteLabel, s_emptySeed);
+
+ Assert.Equal(aliceDerived, aliceDerivedAgain);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(EveryKeysize))]
+ public static void TlsPrfOutputIs48Bytes(int keySize)
+ {
+ using (ECDiffieHellman ecdh = ECDiffieHellmanFactory.Create(keySize))
+ using (ECDiffieHellmanPublicKey publicKey = ecdh.PublicKey)
+ {
+ byte[] derived = ecdh.DeriveKeyTls(publicKey, s_fourByteLabel, s_emptySeed);
+
+ Assert.Equal(48, derived.Length);
+ }
+ }
+
+ [Fact]
+ public static void TlsPrfVariesOnOtherKey()
+ {
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellmanPublicKey alicePublic = alice.PublicKey)
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ byte[] aliceDerived = alice.DeriveKeyTls(bobPublic, s_fourByteLabel, s_emptySeed);
+ byte[] aliceSelfDerived = alice.DeriveKeyTls(alicePublic, s_fourByteLabel, s_emptySeed);
+
+ // Alice and Alice is HASH(aaG) != HASH(abG)
+ // (Except for the fantastically small chance that Alice == Bob)
+ Assert.NotEqual(aliceDerived, aliceSelfDerived);
+ }
+ }
+
+ [Fact]
+ public static void TlsPrfVariesOnLabel()
+ {
+ byte[] aliceLabel = s_fourByteLabel;
+ byte[] bobLabel = new byte[5];
+
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellmanPublicKey alicePublic = alice.PublicKey)
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ byte[] aliceDerived = alice.DeriveKeyTls(bobPublic, aliceLabel, s_emptySeed);
+ byte[] bobDerived = bob.DeriveKeyTls(alicePublic, bobLabel, s_emptySeed);
+
+ Assert.NotEqual(aliceDerived, bobDerived);
+ }
+ }
+
+ [Fact]
+ public static void TlsPrfVariesOnSeed()
+ {
+ byte[] aliceSeed = s_emptySeed;
+ byte[] bobSeed = new byte[64];
+ bobSeed[0] = 0x81;
+
+ using (ECDiffieHellman alice = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellman bob = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellmanPublicKey alicePublic = alice.PublicKey)
+ using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
+ {
+ byte[] aliceDerived = alice.DeriveKeyTls(bobPublic, s_fourByteLabel, aliceSeed);
+ byte[] bobDerived = bob.DeriveKeyTls(alicePublic, s_fourByteLabel, bobSeed);
+
+ Assert.NotEqual(aliceDerived, bobDerived);
+ }
+ }
+
+ public static IEnumerable<object[]> TlsDerivationTestCases()
+ {
+ return new object[][]
+ {
+ new object[]
+ {
+ "slithy toves",
+ "3D5DCEF2B35E73523C34802175875CC241A966D2DEB89041540650478D300A70F822AF7F9D70A31BA4B67D100F4A1620",
+ },
+
+ new object[]
+ {
+ "Hello, World!",
+ "ED83A7CF14C6F1577FE7AD90F1D78D36AFF5D2612B78A70E5FD000660E4A3B00DFF9B7C118C29A3D32536A89A5481C00",
+ },
+ };
+ }
+
+#if netcoreapp
+ [Theory]
+ [MemberData(nameof(TlsDerivationTestCases))]
+ public static void TlsDerivation_KnownResults(string labelText, string answerHex)
+ {
+ byte[] label = Encoding.ASCII.GetBytes(labelText);
+ byte[] output;
+
+ using (ECDiffieHellman ecdh = OpenKnownKey())
+ {
+ using (ECDiffieHellmanPublicKey publicKey = ecdh.PublicKey)
+ {
+ output = ecdh.DeriveKeyTls(publicKey, label, s_emptySeed);
+ }
+ }
+
+ Assert.Equal(answerHex, output.ByteArrayToHex());
+ }
+#endif
+ }
+}
diff --git a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.Xml.cs b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.Xml.cs
new file mode 100644
index 0000000000..b16d3fdd98
--- /dev/null
+++ b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.Xml.cs
@@ -0,0 +1,21 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.Security.Cryptography.EcDiffieHellman.Tests
+{
+ public partial class ECDiffieHellmanTests
+ {
+ [Fact]
+ public static void TestNotImplementedException()
+ {
+ using (ECDiffieHellman ec = ECDiffieHellmanFactory.Create())
+ {
+ Assert.Throws<NotImplementedException>(() => ec.FromXmlString(null));
+ Assert.Throws<NotImplementedException>(() => ec.ToXmlString(true));
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.cs b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.cs
new file mode 100644
index 0000000000..56760dc886
--- /dev/null
+++ b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.cs
@@ -0,0 +1,158 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Security.Cryptography.Tests;
+
+using Xunit;
+using Test.Cryptography;
+
+namespace System.Security.Cryptography.EcDiffieHellman.Tests
+{
+ public partial class ECDiffieHellmanTests : EccTestBase
+ {
+ private static List<object[]> s_everyKeysize;
+ private static List<object[]> s_mismatchedKeysizes;
+
+ public static IEnumerable<object[]> EveryKeysize()
+ {
+ if (s_everyKeysize == null)
+ {
+ List<object[]> everyKeysize = new List<object[]>();
+
+ using (ECDiffieHellman defaultKeysize = ECDiffieHellmanFactory.Create())
+ {
+ foreach (KeySizes keySizes in defaultKeysize.LegalKeySizes)
+ {
+ for (int size = keySizes.MinSize; size <= keySizes.MaxSize; size += keySizes.SkipSize)
+ {
+ everyKeysize.Add(new object[] { size });
+
+ if (keySizes.SkipSize == 0)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ s_everyKeysize = everyKeysize;
+ }
+
+ return s_everyKeysize;
+ }
+
+ public static IEnumerable<object[]> MismatchedKeysizes()
+ {
+ if (s_mismatchedKeysizes == null)
+ {
+ int firstSize = -1;
+ List<object[]> mismatchedKeysizes = new List<object[]>();
+
+ using (ECDiffieHellman defaultKeysize = ECDiffieHellmanFactory.Create())
+ {
+ foreach (KeySizes keySizes in defaultKeysize.LegalKeySizes)
+ {
+ for (int size = keySizes.MinSize; size <= keySizes.MaxSize; size += keySizes.SkipSize)
+ {
+ if (firstSize == -1)
+ {
+ firstSize = size;
+ }
+ else if (size != firstSize)
+ {
+ mismatchedKeysizes.Add(new object[] { firstSize, size });
+ }
+
+ if (keySizes.SkipSize == 0)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ s_mismatchedKeysizes = mismatchedKeysizes;
+ }
+
+ return s_mismatchedKeysizes;
+ }
+
+ [Theory]
+ [MemberData(nameof(EveryKeysize))]
+ public static void SupportsKeysize(int keySize)
+ {
+ using (ECDiffieHellman ecdh = ECDiffieHellmanFactory.Create(keySize))
+ {
+ Assert.Equal(keySize, ecdh.KeySize);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(EveryKeysize))]
+ public static void PublicKey_NotNull(int keySize)
+ {
+ using (ECDiffieHellman ecdh = ECDiffieHellmanFactory.Create(keySize))
+ using (ECDiffieHellmanPublicKey ecdhPubKey = ecdh.PublicKey)
+ {
+ Assert.NotNull(ecdhPubKey);
+ }
+ }
+
+ [Fact]
+ public static void PublicKeyIsFactory()
+ {
+ using (ECDiffieHellman ecdh = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellmanPublicKey publicKey1 = ecdh.PublicKey)
+ using (ECDiffieHellmanPublicKey publicKey2 = ecdh.PublicKey)
+ {
+ Assert.NotSame(publicKey1, publicKey2);
+ }
+ }
+
+#if netcoreapp
+ private static ECDiffieHellman OpenKnownKey()
+ {
+ ECParameters ecParams = new ECParameters
+ {
+ Curve = ECCurve.NamedCurves.nistP521,
+
+ Q =
+ {
+ X = (
+ "014AACFCDA18F77EBF11DC0A2D394D3032E86C3AC0B5F558916361163EA6AD3DB27" +
+ "F6476D6C6E5D9C4A77BCCC5C0069D481718DACA3B1B13035AF5D246C4DC0CE0EA").HexToByteArray(),
+
+ Y = (
+ "00CA500F75537C782E027DE568F148334BF56F7E24C3830792236B5D20F7A33E998" +
+ "62B1744D2413E4C4AC29DBA42FC48D23AE5B916BED73997EC69B3911C686C5164").HexToByteArray(),
+ },
+
+ D = (
+ "00202F9F5480723D1ACF15372CE0B99B6CC3E8772FFDDCF828EEEB314B3EAA35B19" +
+ "886AAB1E6871E548C261C7708BF561A4C373D3EED13F0749851F57B86DC049D71").HexToByteArray(),
+ };
+
+ ECDiffieHellman ecdh = ECDiffieHellmanFactory.Create();
+ ecdh.ImportParameters(ecParams);
+ return ecdh;
+ }
+#endif
+ }
+
+ internal static class EcdhTestExtensions
+ {
+ internal static void Exercise(this ECDiffieHellman e)
+ {
+ // Make a few calls on this to ensure we aren't broken due to bad/prematurely released handles.
+ int keySize = e.KeySize;
+
+ using (ECDiffieHellmanPublicKey publicKey = e.PublicKey)
+ {
+ byte[] negotiated = e.DeriveKeyFromHash(publicKey, HashAlgorithmName.SHA256);
+ Assert.Equal(256 / 8, negotiated.Length);
+ }
+ }
+ }
+}
diff --git a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaImportExport.cs b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaImportExport.cs
index 2703972da9..d8d0967c9e 100644
--- a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaImportExport.cs
+++ b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaImportExport.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using Xunit;
+using System.Security.Cryptography.Tests;
using Test.Cryptography;
namespace System.Security.Cryptography.EcDsa.Tests
@@ -13,7 +14,7 @@ namespace System.Security.Cryptography.EcDsa.Tests
[Fact]
public static void DiminishedCoordsRoundtrip()
{
- ECParameters toImport = ECDsaTestData.GetNistP521DiminishedCoordsParameters();
+ ECParameters toImport = EccTestData.GetNistP521DiminishedCoordsParameters();
ECParameters privateParams;
ECParameters publicParams;
@@ -29,6 +30,30 @@ namespace System.Security.Cryptography.EcDsa.Tests
ComparePublicKey(toImport.Q, publicParams.Q);
Assert.Null(publicParams.D);
}
+
+ [Fact]
+ [PlatformSpecific(TestPlatforms.Windows/* "parameters.Curve.Hash doesn't round trip on Unix." */)]
+ public static void ImportExplicitWithHashButNoSeed()
+ {
+ if (!ECDsaFactory.ExplicitCurvesSupported)
+ {
+ return;
+ }
+
+ using (ECDsa ec = ECDsaFactory.Create())
+ {
+ ECCurve curve = EccTestData.GetNistP256ExplicitCurve();
+ Assert.NotNull(curve.Hash);
+ ec.GenerateKey(curve);
+
+ ECParameters parameters = ec.ExportExplicitParameters(true);
+ Assert.NotNull(parameters.Curve.Hash);
+ parameters.Curve.Seed = null;
+
+ ec.ImportParameters(parameters);
+ ec.Exercise();
+ }
+ }
[Theory]
[MemberData(nameof(TestCurvesFull))]
@@ -166,7 +191,7 @@ namespace System.Security.Cryptography.EcDsa.Tests
{
using (ECDsa ec = ECDsaFactory.Create())
{
- ECParameters p = ECDsaTestData.GetNistP256ExplicitTestData();
+ ECParameters p = EccTestData.GetNistP256ExplicitTestData();
Assert.True(p.Curve.IsPrime);
ec.ImportParameters(p);
@@ -214,7 +239,7 @@ namespace System.Security.Cryptography.EcDsa.Tests
{
using(ECDsa ec = ECDsaFactory.Create())
{
- ECParameters p = ECDsaTestData.GetNistP224KeyTestData();
+ ECParameters p = EccTestData.GetNistP224KeyTestData();
Assert.True(p.Curve.IsNamed);
var q = p.Q;
var c = p.Curve;
@@ -242,7 +267,7 @@ namespace System.Security.Cryptography.EcDsa.Tests
{
using (ECDsa ecdsa = ECDsaFactory.Create())
{
- ECParameters param = ECDsaTestData.GetNistP256ExplicitTestData();
+ ECParameters param = EccTestData.GetNistP256ExplicitTestData();
param.Validate();
ecdsa.ImportParameters(param);
Assert.True(param.Curve.IsExplicit);
@@ -260,13 +285,13 @@ namespace System.Security.Cryptography.EcDsa.Tests
{
using (ECDsa ec = ECDsaFactory.Create())
{
- ECParameters parameters = ECDsaTestData.GetNistP224KeyTestData();
+ ECParameters parameters = EccTestData.GetNistP224KeyTestData();
ec.ImportParameters(parameters);
VerifyNamedCurve(parameters, ec, 224, true);
}
}
- [ConditionalFact(nameof(ECExplicitCurvesSupported))]
+ [Fact]
public static void ExportIncludingPrivateOnPublicOnlyKey()
{
ECParameters iutParameters = new ECParameters
@@ -286,9 +311,12 @@ namespace System.Security.Cryptography.EcDsa.Tests
iut.ImportParameters(iutParameters);
cavs.ImportParameters(iut.ExportParameters(false));
- // Linux throws an Interop.Crypto.OpenSslCryptographicException : CryptographicException
- Assert.ThrowsAny<CryptographicException>(() => cavs.ExportExplicitParameters(true));
Assert.ThrowsAny<CryptographicException>(() => cavs.ExportParameters(true));
+
+ if (ECExplicitCurvesSupported)
+ {
+ Assert.ThrowsAny<CryptographicException>(() => cavs.ExportExplicitParameters(true));
+ }
}
}
diff --git a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTests.NistValidation.cs b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTests.NistValidation.cs
index 4156395a51..3fc5629526 100644
--- a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTests.NistValidation.cs
+++ b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTests.NistValidation.cs
@@ -2,13 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using Xunit;
-
+using System.Security.Cryptography.Tests;
using Test.Cryptography;
+using Xunit;
namespace System.Security.Cryptography.EcDsa.Tests
{
@@ -49,7 +45,7 @@ namespace System.Security.Cryptography.EcDsa.Tests
Validate(
parameters,
- ECDsaTestData.GetNistP256ExplicitCurve(),
+ EccTestData.GetNistP256ExplicitCurve(),
msg,
signature,
HashAlgorithmName.SHA256);
@@ -85,7 +81,7 @@ namespace System.Security.Cryptography.EcDsa.Tests
Validate(
parameters,
- ECDsaTestData.GetNistP256ExplicitCurve(),
+ EccTestData.GetNistP256ExplicitCurve(),
msg,
signature,
HashAlgorithmName.SHA384);
@@ -124,7 +120,7 @@ namespace System.Security.Cryptography.EcDsa.Tests
Validate(
parameters,
- ECDsaTestData.GetNistP384ExplicitCurve(),
+ EccTestData.GetNistP384ExplicitCurve(),
msg,
signature,
HashAlgorithmName.SHA256);
@@ -163,7 +159,7 @@ namespace System.Security.Cryptography.EcDsa.Tests
Validate(
parameters,
- ECDsaTestData.GetNistP384ExplicitCurve(),
+ EccTestData.GetNistP384ExplicitCurve(),
msg,
signature,
HashAlgorithmName.SHA512);
@@ -204,7 +200,7 @@ namespace System.Security.Cryptography.EcDsa.Tests
Validate(
parameters,
- ECDsaTestData.GetNistP521ExplicitCurve(),
+ EccTestData.GetNistP521ExplicitCurve(),
msg,
signature,
HashAlgorithmName.SHA384);
@@ -245,7 +241,7 @@ namespace System.Security.Cryptography.EcDsa.Tests
Validate(
parameters,
- ECDsaTestData.GetNistP521ExplicitCurve(),
+ EccTestData.GetNistP521ExplicitCurve(),
msg,
signature,
HashAlgorithmName.SHA512);
diff --git a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTests.cs b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTests.cs
index d0111b23f3..899b90716f 100644
--- a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTests.cs
+++ b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTests.cs
@@ -35,8 +35,8 @@ namespace System.Security.Cryptography.EcDsa.Tests
AssertExtensions.Throws<ArgumentException>("hashAlgorithm", () => ecdsa.SignData(new byte[0], 0, 0, default(HashAlgorithmName)));
AssertExtensions.Throws<ArgumentException>("hashAlgorithm", () => ecdsa.SignData(new byte[10], 0, 10, new HashAlgorithmName("")));
- Assert.Throws<CryptographicException>(() => ecdsa.SignData(new byte[0], new HashAlgorithmName(Guid.NewGuid().ToString("N"))));
- Assert.Throws<CryptographicException>(() => ecdsa.SignData(new byte[0], 0, 0, new HashAlgorithmName(Guid.NewGuid().ToString("N"))));
+ Assert.ThrowsAny<CryptographicException>(() => ecdsa.SignData(new byte[0], new HashAlgorithmName(Guid.NewGuid().ToString("N"))));
+ Assert.ThrowsAny<CryptographicException>(() => ecdsa.SignData(new byte[0], 0, 0, new HashAlgorithmName(Guid.NewGuid().ToString("N"))));
}
[Theory, MemberData(nameof(RealImplementations))]
@@ -59,8 +59,8 @@ namespace System.Security.Cryptography.EcDsa.Tests
AssertExtensions.Throws<ArgumentException>("hashAlgorithm", () => ecdsa.VerifyData(new byte[10], new byte[0], new HashAlgorithmName("")));
AssertExtensions.Throws<ArgumentException>("hashAlgorithm", () => ecdsa.VerifyData(new byte[10], 0, 10, new byte[0], new HashAlgorithmName("")));
- Assert.Throws<CryptographicException>(() => ecdsa.VerifyData(new byte[0], new byte[0], new HashAlgorithmName(Guid.NewGuid().ToString("N"))));
- Assert.Throws<CryptographicException>(() => ecdsa.VerifyData(new byte[0], 0, 0, new byte[0], new HashAlgorithmName(Guid.NewGuid().ToString("N"))));
+ Assert.ThrowsAny<CryptographicException>(() => ecdsa.VerifyData(new byte[0], new byte[0], new HashAlgorithmName(Guid.NewGuid().ToString("N"))));
+ Assert.ThrowsAny<CryptographicException>(() => ecdsa.VerifyData(new byte[0], 0, 0, new byte[0], new HashAlgorithmName(Guid.NewGuid().ToString("N"))));
}
[Theory, MemberData(nameof(RealImplementations))]
@@ -100,7 +100,7 @@ namespace System.Security.Cryptography.EcDsa.Tests
{
AssertExtensions.Throws<ArgumentNullException>("data", () => ecdsa.SignData((Stream)null, default(HashAlgorithmName)));
AssertExtensions.Throws<ArgumentException>("hashAlgorithm", () => ecdsa.SignData(new MemoryStream(), default(HashAlgorithmName)));
- Assert.Throws<CryptographicException>(() => ecdsa.SignData(new MemoryStream(), new HashAlgorithmName(Guid.NewGuid().ToString("N"))));
+ Assert.ThrowsAny<CryptographicException>(() => ecdsa.SignData(new MemoryStream(), new HashAlgorithmName(Guid.NewGuid().ToString("N"))));
}
[Theory, MemberData(nameof(RealImplementations))]
@@ -110,7 +110,7 @@ namespace System.Security.Cryptography.EcDsa.Tests
AssertExtensions.Throws<ArgumentNullException>("signature", () => ecdsa.VerifyData(new MemoryStream(), null, default(HashAlgorithmName)));
AssertExtensions.Throws<ArgumentException>("hashAlgorithm", () => ecdsa.VerifyData(new MemoryStream(), new byte[0], default(HashAlgorithmName)));
AssertExtensions.Throws<ArgumentException>("hashAlgorithm", () => ecdsa.VerifyData(new MemoryStream(), new byte[0], new HashAlgorithmName("")));
- Assert.Throws<CryptographicException>(() => ecdsa.VerifyData(new MemoryStream(), new byte[0], new HashAlgorithmName(Guid.NewGuid().ToString("N"))));
+ Assert.ThrowsAny<CryptographicException>(() => ecdsa.VerifyData(new MemoryStream(), new byte[0], new HashAlgorithmName(Guid.NewGuid().ToString("N"))));
}
}
diff --git a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTests.netcoreapp.cs b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTests.netcoreapp.cs
index 9b464840e5..acf3da9ec5 100644
--- a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTests.netcoreapp.cs
+++ b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTests.netcoreapp.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Security.Cryptography.Tests;
using Xunit;
namespace System.Security.Cryptography.EcDsa.Tests
@@ -19,7 +20,7 @@ namespace System.Security.Cryptography.EcDsa.Tests
{
AssertExtensions.Throws<ArgumentException>("hashAlgorithm", () => ecdsa.TrySignData(ReadOnlySpan<byte>.Empty, Span<byte>.Empty, new HashAlgorithmName(null), out int bytesWritten));
AssertExtensions.Throws<ArgumentException>("hashAlgorithm", () => ecdsa.TrySignData(ReadOnlySpan<byte>.Empty, Span<byte>.Empty, new HashAlgorithmName(""), out int bytesWritten));
- Assert.Throws<CryptographicException>(() => ecdsa.TrySignData(ReadOnlySpan<byte>.Empty, Span<byte>.Empty, new HashAlgorithmName(Guid.NewGuid().ToString("N")), out int bytesWritten));
+ Assert.ThrowsAny<CryptographicException>(() => ecdsa.TrySignData(ReadOnlySpan<byte>.Empty, Span<byte>.Empty, new HashAlgorithmName(Guid.NewGuid().ToString("N")), out int bytesWritten));
}
[Theory, MemberData(nameof(RealImplementations))]
@@ -27,7 +28,7 @@ namespace System.Security.Cryptography.EcDsa.Tests
{
AssertExtensions.Throws<ArgumentException>("hashAlgorithm", () => ecdsa.VerifyData(ReadOnlySpan<byte>.Empty, ReadOnlySpan<byte>.Empty, new HashAlgorithmName(null)));
AssertExtensions.Throws<ArgumentException>("hashAlgorithm", () => ecdsa.VerifyData(ReadOnlySpan<byte>.Empty, ReadOnlySpan<byte>.Empty, new HashAlgorithmName("")));
- Assert.Throws<CryptographicException>(() => ecdsa.VerifyData(ReadOnlySpan<byte>.Empty, Span<byte>.Empty, new HashAlgorithmName(Guid.NewGuid().ToString("N"))));
+ Assert.ThrowsAny<CryptographicException>(() => ecdsa.VerifyData(ReadOnlySpan<byte>.Empty, Span<byte>.Empty, new HashAlgorithmName(Guid.NewGuid().ToString("N"))));
}
private static byte[] TryWithOutputArray(Func<byte[], (bool, int)> func)
@@ -247,7 +248,7 @@ namespace System.Security.Cryptography.EcDsa.Tests
{
using (ECDsa ecdsa = ECDsaFactory.Create())
{
- ecdsa.ImportParameters(ECDsaTestData.GetNistP256ExplicitTestData());
+ ecdsa.ImportParameters(EccTestData.GetNistP256ExplicitTestData());
Verify256(ecdsa, true);
}
}
diff --git a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTestsBase.cs b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTestsBase.cs
index 9be0ff93e3..eb8d3833b2 100644
--- a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTestsBase.cs
+++ b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTestsBase.cs
@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Linq;
+using System.Security.Cryptography.Tests;
using Test.Cryptography;
using Xunit;
@@ -12,229 +13,14 @@ namespace System.Security.Cryptography.EcDsa.Tests
/// <summary>
/// Input and helper methods for ECDsa
/// </summary>
- public abstract class ECDsaTestsBase
+ public abstract class ECDsaTestsBase : EccTestBase
{
#if netcoreapp
- internal const string ECDSA_P224_OID_VALUE = "1.3.132.0.33"; // Also called nistP224 or secP224r1
- internal const string ECDSA_P256_OID_VALUE = "1.2.840.10045.3.1.7"; // Also called nistP256, secP256r1 or prime256v1(OpenSsl)
- internal const string ECDSA_P384_OID_VALUE = "1.3.132.0.34"; // Also called nistP384 or secP384r1
- internal const string ECDSA_P521_OID_VALUE = "1.3.132.0.35"; // Also called nistP521 or secP521r1
- internal const string ECDSA_Sect193r1_OID_VALUE = "1.3.132.0.24"; //Char-2 curve
-
- public static IEnumerable<object[]> TestCurvesFull
- {
- get
- {
- var curveDefs =
- from curveDef in TestCurvesRaw
- where curveDef.IsCurveValidOnPlatform == true
- select curveDef;
-
- foreach (CurveDef cd in curveDefs)
- yield return new[] { cd };
-
- // return again with IncludePrivate = true
- foreach (CurveDef cd in curveDefs)
- {
- cd.IncludePrivate = true;
- yield return new[] { cd };
- }
- }
- }
-
- public static IEnumerable<object[]> TestCurves
- {
- get
- {
- var curveDefs =
- from curveDef in TestCurvesRaw
- where curveDef.IsCurveValidOnPlatform == true
- select curveDef;
-
- foreach (CurveDef curveDef in curveDefs)
- yield return new[] { curveDef };
- }
- }
-
- public static IEnumerable<object[]> TestInvalidCurves
- {
- get
- {
- var curveDefs =
- from curveDef in TestCurvesRaw
- where curveDef.IsCurveValidOnPlatform == false
- select curveDef;
-
- foreach (CurveDef curveDef in curveDefs)
- yield return new[] { curveDef };
- }
- }
-
- public static IEnumerable<object[]> TestNewCurves
- {
- get
- {
- var curveDefs =
- from curveDef in TestCurvesRaw
- where
- curveDef.IsCurveValidOnPlatform == true &&
- curveDef.RequiredOnPlatform == false
- select curveDef;
-
- foreach (CurveDef curveDef in curveDefs)
- yield return new[] { curveDef };
- }
- }
-
- private static IEnumerable<CurveDef> TestCurvesRaw
- {
- get
- {
- // nistP* curves
- yield return new CurveDef()
- {
- Curve = ECCurve.NamedCurves.nistP256, // also secp256r1
- KeySize = 256,
- CurveType = ECCurve.ECCurveType.PrimeShortWeierstrass,
- RequiredOnPlatform = true,
- };
- yield return new CurveDef()
- {
- Curve = ECCurve.NamedCurves.nistP384, // also secp384r1
- KeySize = 384,
- CurveType = ECCurve.ECCurveType.PrimeMontgomery,
- RequiredOnPlatform = true,
- };
- yield return new CurveDef()
- {
- Curve = ECCurve.NamedCurves.nistP521, // also secp521r1
- KeySize = 521,
- CurveType = ECCurve.ECCurveType.PrimeShortWeierstrass,
- RequiredOnPlatform = true,
- };
- yield return new CurveDef()
- {
- Curve = ECCurve.NamedCurves.brainpoolP160r1,
- KeySize = 160,
- CurveType = ECCurve.ECCurveType.PrimeShortWeierstrass
- };
- yield return new CurveDef()
- {
- Curve = ECCurve.CreateFromOid(new Oid("1.3.132.0.24", "")), // sect193r1
- KeySize = 193,
- CurveType = ECCurve.ECCurveType.Characteristic2,
- };
- yield return new CurveDef()
- {
- Curve = ECCurve.CreateFromOid(new Oid("1.2.840.10045.3.0.1", "")), // c2pnb163v1
- KeySize = 163,
- CurveType = ECCurve.ECCurveType.Characteristic2,
- };
- yield return new CurveDef()
- {
- Curve = ECCurve.CreateFromOid(new Oid("1.3.132.0.16", "")), // sect283k1
- KeySize = 283,
- CurveType = ECCurve.ECCurveType.Characteristic2,
- };
- yield return new CurveDef()
- {
- Curve = ECCurve.CreateFromOid(new Oid("1.3.132.0.17", "")), // sect283r1
- KeySize = 283,
- CurveType = ECCurve.ECCurveType.Characteristic2,
- };
- yield return new CurveDef()
- {
- Curve = ECCurve.CreateFromOid(new Oid("", "wap-wsg-idm-ecid-wtls7")),
- KeySize = 160,
- CurveType = ECCurve.ECCurveType.PrimeMontgomery,
- };
- yield return new CurveDef()
- {
- Curve = ECCurve.CreateFromOid(new Oid("invalid", "invalid")),
- KeySize = 160,
- CurveType = ECCurve.ECCurveType.PrimeShortWeierstrass,
- };
- yield return new CurveDef
- {
- Curve = ECDsaTestData.GetNistP256ExplicitCurve(),
- KeySize = 256,
- CurveType = ECCurve.ECCurveType.PrimeShortWeierstrass,
- DisplayName = "NIST P-256",
- };
- }
- }
-
- internal static void AssertEqual(ECParameters p1, ECParameters p2)
- {
- ComparePrivateKey(p1, p2);
- ComparePublicKey(p1.Q, p2.Q);
- CompareCurve(p1.Curve, p2.Curve);
- }
-
- internal static void ComparePrivateKey(ECParameters p1, ECParameters p2, bool isEqual = true)
- {
- if (isEqual)
- {
- Assert.Equal(p1.D, p2.D);
- }
- else
- {
- Assert.NotEqual(p1.D, p2.D);
- }
- }
-
- internal static void ComparePublicKey(ECPoint q1, ECPoint q2, bool isEqual = true)
- {
- if (isEqual)
- {
- Assert.Equal(q1.X, q2.X);
- Assert.Equal(q1.Y, q2.Y);
- }
- else
- {
- Assert.NotEqual(q1.X, q2.X);
- Assert.NotEqual(q1.Y, q2.Y);
- }
- }
-
- internal static void CompareCurve(ECCurve c1, ECCurve c2)
- {
- if (c1.IsNamed)
- {
- Assert.True(c2.IsNamed);
- Assert.Equal(c1.Oid.FriendlyName, c2.Oid.FriendlyName);
- }
- else if (c1.IsExplicit)
- {
- Assert.True(c2.IsExplicit);
- Assert.Equal(c1.A, c2.A);
- Assert.Equal(c1.B, c2.B);
- Assert.Equal(c1.CurveType, c2.CurveType);
- Assert.Equal(c1.G.X, c2.G.X);
- Assert.Equal(c1.G.Y, c2.G.Y);
- Assert.Equal(c1.Cofactor, c2.Cofactor);
- Assert.Equal(c1.Order, c2.Order);
- Assert.Equal(c1.Seed, c2.Seed);
- Assert.Equal(c1.Hash, c2.Hash);
-
- if (c1.IsPrime)
- {
- Assert.True(c2.IsPrime);
- Assert.Equal(c1.Prime, c2.Prime);
- }
- else if (c1.IsCharacteristic2)
- {
- Assert.True(c2.IsCharacteristic2);
- Assert.Equal(c1.Polynomial, c2.Polynomial);
- }
- }
- }
-
internal static void Verify256(ECDsa e, bool expected)
{
byte[] sig = ("998791331eb2e1f4259297f5d9cb82fa20dec98e1cb0900e6b8f014a406c3d02cbdbf5238bde471c3155fc25565524301429"
+ "d8713dad9a67eb0a5c355e9e23dc").HexToByteArray();
- bool verified = e.VerifyHash(ECDsaTestData.s_hashSha512, sig);
+ bool verified = e.VerifyHash(EccTestData.s_hashSha512, sig);
Assert.Equal(expected, verified);
}
diff --git a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/EncryptDecrypt.cs b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/EncryptDecrypt.cs
index b47b8df020..ecc0622b34 100644
--- a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/EncryptDecrypt.cs
+++ b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/EncryptDecrypt.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using Test.Cryptography;
using Xunit;
namespace System.Security.Cryptography.Rsa.Tests
@@ -26,6 +27,7 @@ namespace System.Security.Cryptography.Rsa.Tests
public abstract class EncryptDecrypt
{
+ public static bool SupportsSha2Oaep => RSAFactory.SupportsSha2Oaep;
private static bool EphemeralKeysAreExportable => !PlatformDetection.IsFullFramework || PlatformDetection.IsNetfx462OrNewer;
protected abstract byte[] Encrypt(RSA rsa, byte[] data, RSAEncryptionPadding padding);
@@ -36,8 +38,8 @@ namespace System.Security.Cryptography.Rsa.Tests
{
using (RSA rsa = RSAFactory.Create())
{
- AssertExtensions.Throws<ArgumentNullException>("padding", () => Encrypt(rsa, new byte[1], null));
- AssertExtensions.Throws<ArgumentNullException>("padding", () => Decrypt(rsa, new byte[1], null));
+ AssertExtensions.Throws<ArgumentNullException>("padding", () => Encrypt(rsa, TestData.HelloBytes, null));
+ AssertExtensions.Throws<ArgumentNullException>("padding", () => Decrypt(rsa, TestData.HelloBytes, null));
}
}
@@ -115,6 +117,41 @@ namespace System.Security.Cryptography.Rsa.Tests
}
[Fact]
+ public void DecryptSavedAnswer_OaepSHA256()
+ {
+ byte[] cipherBytes = (
+ "3ED1D2DCFBD1778D1B1F20C2CC4FD364D7236ACB6DBD7109CE9C44F6DA8D47A4" +
+ "53C36A3D4E8E87168CD1E5427A6C261F87CDC5A62507AF6127D1C5D274D5EECD" +
+ "50DC53C559FC85624D9FB999ADDD9BE5652926440A3DE32CA27554F524C30A7A" +
+ "E66215FE725F5998FB2AFD2E1E5F06F2944B61502A27272660A21363F35C3DC8" +
+ "8ED072096391B27D27BE5E1775F949A3A5C9C2903794090CE8D9DFE7003A4745" +
+ "E7029B0D4C0F6FD28E9886227E05B56D6BB0BA2933126C808EE0D972054A26DB" +
+ "2CA97B09967B2B6D7592F2563302111DE2FC42ED442522CD83A1AE9E8C3F0B1A" +
+ "9D50A4A89008D2135E0D8BC859F81CEF76166834432B4AE9BAAD1FC08E4C2C70").HexToByteArray();
+
+ byte[] output;
+
+ using (RSA rsa = RSAFactory.Create())
+ {
+ rsa.ImportParameters(TestData.RSA2048Params);
+
+ if (RSAFactory.SupportsSha2Oaep)
+ {
+ output = Decrypt(rsa, cipherBytes, RSAEncryptionPadding.OaepSHA256);
+ }
+ else
+ {
+ Assert.ThrowsAny<CryptographicException>(
+ () => Decrypt(rsa, cipherBytes, RSAEncryptionPadding.OaepSHA256));
+
+ return;
+ }
+ }
+
+ Assert.Equal(TestData.RSA2048Params.InverseQ, output);
+ }
+
+ [Fact]
public void DecryptSavedAnswer_OaepSHA384()
{
byte[] cipherBytes =
@@ -176,6 +213,41 @@ namespace System.Security.Cryptography.Rsa.Tests
}
[Fact]
+ public void DecryptSavedAnswer_OaepSHA512()
+ {
+ byte[] cipherBytes = (
+ "7F0598C7257433FCDEF3F6C0AE69517D3AA6B4FD67D7F4C25F9A5996D20843AF" +
+ "E14C21D35D4D289CE4E720A1C9D998C9F95AFB73E523F5EA4B54D0BAE9B5665C" +
+ "B0A5F5719F5466A491FDB5B323F6B741CF7E0C263D1274959AD87B64B789F7EC" +
+ "6E52085954B59F7A3EBE6295EB7F168E8DADB49F166B4CB753F0D2774370D3E2" +
+ "D5B9F6493D7EEA65AA7BD8867313C13850CB2F2D7CCF46E553BEBDADA6060C14" +
+ "CC43AE238410167BC42FDE9DA07D135C0D2DB48537299DC067A808CCBA2B0B0A" +
+ "7A741705DA98872A7416610939DE4E2D4C387662ABD74D80E33502AFF1D571DB" +
+ "B874CA25CC54CEE69B6252B33BA92119873E0F8B5CCE0496324904A7847D73FB").HexToByteArray();
+
+ byte[] output;
+
+ using (RSA rsa = RSAFactory.Create())
+ {
+ rsa.ImportParameters(TestData.RSA2048Params);
+
+ if (RSAFactory.SupportsSha2Oaep)
+ {
+ output = Decrypt(rsa, cipherBytes, RSAEncryptionPadding.OaepSHA512);
+ }
+ else
+ {
+ Assert.ThrowsAny<CryptographicException>(
+ () => Decrypt(rsa, cipherBytes, RSAEncryptionPadding.OaepSHA512));
+
+ return;
+ }
+ }
+
+ Assert.Equal(TestData.RSA1032Parameters.DQ, output);
+ }
+
+ [Fact]
public void DecryptSavedAnswerUnusualExponent()
{
byte[] cipherBytes =
@@ -210,21 +282,249 @@ namespace System.Security.Cryptography.Rsa.Tests
}
[Fact]
- public void RsaCryptRoundtrip()
+ public void RsaCryptRoundtrip_OaepSHA1() => RsaCryptRoundtrip(RSAEncryptionPadding.OaepSHA1);
+
+ [Fact]
+ public void RsaCryptRoundtrip_OaepSHA256() =>
+ RsaCryptRoundtrip(RSAEncryptionPadding.OaepSHA256, RSAFactory.SupportsSha2Oaep);
+
+ [Fact]
+ public void RsaCryptRoundtrip_OaepSHA384() =>
+ RsaCryptRoundtrip(RSAEncryptionPadding.OaepSHA384, RSAFactory.SupportsSha2Oaep);
+
+ [Fact]
+ public void RsaCryptRoundtrip_OaepSHA512() =>
+ RsaCryptRoundtrip(RSAEncryptionPadding.OaepSHA512, RSAFactory.SupportsSha2Oaep);
+
+ private void RsaCryptRoundtrip(RSAEncryptionPadding paddingMode, bool expectSuccess=true)
{
byte[] crypt;
byte[] output;
- using (RSA rsa = RSAFactory.Create())
+ using (RSA rsa = RSAFactory.Create(2048))
{
- crypt = Encrypt(rsa, TestData.HelloBytes, RSAEncryptionPadding.OaepSHA1);
- output = Decrypt(rsa, crypt, RSAEncryptionPadding.OaepSHA1);
+ if (!expectSuccess)
+ {
+ Assert.ThrowsAny<CryptographicException>(
+ () => Encrypt(rsa, TestData.HelloBytes, paddingMode));
+
+ return;
+ }
+
+ crypt = Encrypt(rsa, TestData.HelloBytes, paddingMode);
+ output = Decrypt(rsa, crypt, paddingMode);
}
Assert.NotEqual(crypt, output);
Assert.Equal(TestData.HelloBytes, output);
}
+ [Fact]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void RoundtripEmptyArray()
+ {
+ using (RSA rsa = RSAFactory.Create(TestData.RSA2048Params))
+ {
+ void RoundtripEmpty(RSAEncryptionPadding paddingMode)
+ {
+ byte[] encrypted = Encrypt(rsa, Array.Empty<byte>(), paddingMode);
+ byte[] decrypted = Decrypt(rsa, encrypted, paddingMode);
+
+ Assert.Equal(Array.Empty<byte>(), decrypted);
+ }
+
+ RoundtripEmpty(RSAEncryptionPadding.Pkcs1);
+ RoundtripEmpty(RSAEncryptionPadding.OaepSHA1);
+
+ if (RSAFactory.SupportsSha2Oaep)
+ {
+ RoundtripEmpty(RSAEncryptionPadding.OaepSHA256);
+ RoundtripEmpty(RSAEncryptionPadding.OaepSHA384);
+ RoundtripEmpty(RSAEncryptionPadding.OaepSHA512);
+ }
+ }
+ }
+
+ [Fact]
+ public void RsaPkcsEncryptMaxSize()
+ {
+ RSAParameters rsaParameters = TestData.RSA2048Params;
+
+ using (RSA rsa = RSAFactory.Create(rsaParameters))
+ {
+ RSAEncryptionPadding paddingMode1 = RSAEncryptionPadding.Pkcs1;
+ // The overhead required is 8 + 3 => 11.
+
+ const int Pkcs1Overhead = 11;
+ int maxSize = rsaParameters.Modulus.Length - Pkcs1Overhead;
+
+ byte[] data = new byte[maxSize];
+ byte[] encrypted = Encrypt(rsa, data, paddingMode1);
+ byte[] decrypted = Decrypt(rsa, encrypted, paddingMode1);
+
+ Assert.Equal(data.ByteArrayToHex(), decrypted.ByteArrayToHex());
+
+ data = new byte[maxSize + 1];
+
+ Assert.ThrowsAny<CryptographicException>(
+ () => Encrypt(rsa, data, paddingMode1));
+ }
+ }
+
+ [Fact]
+ public void RsaOaepMaxSize()
+ {
+ RSAParameters rsaParameters = TestData.RSA2048Params;
+
+ using (RSA rsa = RSAFactory.Create(rsaParameters))
+ {
+ void Test(RSAEncryptionPadding paddingMode, int hashSizeInBits)
+ {
+ // The overhead required is hLen + hLen + 2.
+ int hLen = (hashSizeInBits + 7) / 8;
+ int overhead = hLen + hLen + 2;
+ int maxSize = rsaParameters.Modulus.Length - overhead;
+
+ byte[] data = new byte[maxSize];
+ byte[] encrypted = Encrypt(rsa, data, paddingMode);
+ byte[] decrypted = Decrypt(rsa, encrypted, paddingMode);
+
+ Assert.Equal(data.ByteArrayToHex(), decrypted.ByteArrayToHex());
+
+ data = new byte[maxSize + 1];
+
+ Assert.ThrowsAny<CryptographicException>(
+ () => Encrypt(rsa, data, paddingMode));
+ }
+
+ Test(RSAEncryptionPadding.OaepSHA1, 160);
+
+ if (RSAFactory.SupportsSha2Oaep)
+ {
+ Test(RSAEncryptionPadding.OaepSHA256, 256);
+ Test(RSAEncryptionPadding.OaepSHA384, 384);
+ Test(RSAEncryptionPadding.OaepSHA512, 512);
+ }
+ }
+ }
+
+ [Fact]
+ public void RsaDecryptOaep_ExpectFailure()
+ {
+ // This particular byte pattern, when decrypting under OAEP-SHA-2-384 has
+ // an 0x01 in the correct range, and y=0, but lHash and lHashPrime do not agree
+ byte[] encrypted = (
+ "2A1914D11E2F6B9E286DAC9D76F32A008EC31457522CEA058D7C48C85085899F" +
+ "E9C2DBD4FCA5FAD936F2B747E0BEF131217F8521FA921DF807A83C1B34DB1547" +
+ "8D637EDFED222B6411C80D465332B2EE5208F87D4F8D1736FEBC291E14E77C4B" +
+ "75A1F06B5124F225F310BFFA83BCA9F11101BA67A64109C37F52BF00B84FFD9A" +
+ "D39282AD2BA9EEADADA0FE38998755B556B152EE8974F2C8158ACFA5F509DD4A" +
+ "BFE72218C0DF596DFF02C332F45ECC04280455F5D2666E93A3522BB8B41FC92E" +
+ "0176AFB1D3A5AE474B708B882ACA88447046E13D44E5EA8D66421DFC177A683B" +
+ "7B395F18886AAFD9CED072079739ED1D390354976D188C50A29AAD58784886E6").HexToByteArray();
+
+ using (RSA rsa = RSAFactory.Create(TestData.RSA2048Params))
+ {
+ Assert.ThrowsAny<CryptographicException>(
+ () => Decrypt(rsa, encrypted, RSAEncryptionPadding.OaepSHA384));
+ }
+ }
+
+ [ConditionalFact(nameof(SupportsSha2Oaep))]
+ public void RsaDecryptOaepWrongAlgorithm()
+ {
+ using (RSA rsa = RSAFactory.Create(TestData.RSA2048Params))
+ {
+ byte[] data = TestData.HelloBytes;
+ byte[] encrypted = Encrypt(rsa, data, RSAEncryptionPadding.OaepSHA256);
+
+ Assert.ThrowsAny<CryptographicException>(
+ () => Decrypt(rsa, encrypted, RSAEncryptionPadding.OaepSHA384));
+ }
+ }
+
+ [Fact]
+ public void RsaDecryptOaepWrongData()
+ {
+ using (RSA rsa = RSAFactory.Create(TestData.RSA2048Params))
+ {
+ byte[] data = TestData.HelloBytes;
+ byte[] encrypted = Encrypt(rsa, data, RSAEncryptionPadding.OaepSHA1);
+ encrypted[1] ^= 0xFF;
+
+ Assert.ThrowsAny<CryptographicException>(
+ () => Decrypt(rsa, encrypted, RSAEncryptionPadding.OaepSHA1));
+
+ if (RSAFactory.SupportsSha2Oaep)
+ {
+ encrypted = Encrypt(rsa, data, RSAEncryptionPadding.OaepSHA256);
+ encrypted[1] ^= 0xFF;
+
+ Assert.ThrowsAny<CryptographicException>(
+ () => Decrypt(rsa, encrypted, RSAEncryptionPadding.OaepSHA256));
+ }
+ }
+ }
+
+ [Fact]
+ public void RsaDecryptPkcs1WrongDataLength()
+ {
+ using (RSA rsa = RSAFactory.Create(TestData.RSA2048Params))
+ {
+ byte[] data = TestData.HelloBytes;
+
+ byte[] encrypted = Encrypt(rsa, data, RSAEncryptionPadding.Pkcs1);
+ Array.Resize(ref encrypted, encrypted.Length + 1);
+
+ // Baseline/exempt a NetFx difference for RSACng
+ if (!PlatformDetection.IsFullFramework ||
+ rsa.GetType().Assembly.GetName().Name != "System.Core")
+ {
+ Assert.ThrowsAny<CryptographicException>(
+ () => Decrypt(rsa, encrypted, RSAEncryptionPadding.Pkcs1));
+ }
+
+ Array.Resize(ref encrypted, encrypted.Length - 2);
+
+ Assert.ThrowsAny<CryptographicException>(
+ () => Decrypt(rsa, encrypted, RSAEncryptionPadding.Pkcs1));
+ }
+ }
+
+ [Fact]
+ public void RsaDecryptOaepWrongDataLength()
+ {
+ using (RSA rsa = RSAFactory.Create(TestData.RSA2048Params))
+ {
+ byte[] data = TestData.HelloBytes;
+
+ byte[] encrypted = Encrypt(rsa, data, RSAEncryptionPadding.OaepSHA1);
+ Array.Resize(ref encrypted, encrypted.Length + 1);
+
+ Assert.ThrowsAny<CryptographicException>(
+ () => Decrypt(rsa, encrypted, RSAEncryptionPadding.OaepSHA1));
+
+ Array.Resize(ref encrypted, encrypted.Length - 2);
+
+ Assert.ThrowsAny<CryptographicException>(
+ () => Decrypt(rsa, encrypted, RSAEncryptionPadding.OaepSHA1));
+
+ if (RSAFactory.SupportsSha2Oaep)
+ {
+ encrypted = Encrypt(rsa, data, RSAEncryptionPadding.OaepSHA256);
+ Array.Resize(ref encrypted, encrypted.Length + 1);
+
+ Assert.ThrowsAny<CryptographicException>(
+ () => Decrypt(rsa, encrypted, RSAEncryptionPadding.OaepSHA256));
+
+ Array.Resize(ref encrypted, encrypted.Length - 2);
+
+ Assert.ThrowsAny<CryptographicException>(
+ () => Decrypt(rsa, encrypted, RSAEncryptionPadding.OaepSHA256));
+ }
+ }
+ }
+
[ConditionalFact(nameof(EphemeralKeysAreExportable))]
public void RsaDecryptAfterExport()
{
diff --git a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/EncryptDecrypt.netcoreapp.cs b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/EncryptDecrypt.netcoreapp.cs
index 9f53f53c3e..e1a234c6d3 100644
--- a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/EncryptDecrypt.netcoreapp.cs
+++ b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/EncryptDecrypt.netcoreapp.cs
@@ -64,7 +64,7 @@ namespace System.Security.Cryptography.Rsa.Tests
actual = new byte[TestData.HelloBytes.Length + 1000];
Assert.True(rsa.TryDecrypt(cipherBytes, actual, RSAEncryptionPadding.OaepSHA1, out bytesWritten));
Assert.Equal(TestData.HelloBytes.Length, bytesWritten);
- Assert.Equal<byte>(TestData.HelloBytes, actual.AsSpan().Slice(0, TestData.HelloBytes.Length).ToArray());
+ Assert.Equal<byte>(TestData.HelloBytes, actual.AsSpan(0, TestData.HelloBytes.Length).ToArray());
}
}
diff --git a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/RSAFactory.cs b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/RSAFactory.cs
index a34642a234..9dd006457d 100644
--- a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/RSAFactory.cs
+++ b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/RSAFactory.cs
@@ -10,6 +10,7 @@ namespace System.Security.Cryptography.Rsa.Tests
RSA Create(int keySize);
bool Supports384PrivateKey { get; }
bool SupportsSha2Oaep { get; }
+ bool SupportsPss { get; }
bool SupportsDecryptingIntoExactSpaceRequired { get; }
}
@@ -25,10 +26,19 @@ namespace System.Security.Cryptography.Rsa.Tests
return s_provider.Create(keySize);
}
+ public static RSA Create(RSAParameters rsaParameters)
+ {
+ RSA rsa = Create();
+ rsa.ImportParameters(rsaParameters);
+ return rsa;
+ }
+
public static bool Supports384PrivateKey => s_provider.Supports384PrivateKey;
public static bool SupportsSha2Oaep => s_provider.SupportsSha2Oaep;
+ public static bool SupportsPss => s_provider.SupportsPss;
+
public static bool SupportsDecryptingIntoExactSpaceRequired => s_provider.SupportsDecryptingIntoExactSpaceRequired;
}
}
diff --git a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs
index 557d3a020b..dbb516b9ba 100644
--- a/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs
+++ b/src/Common/tests/System/Security/Cryptography/AlgorithmImplementations/RSA/SignVerify.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.IO;
+using Test.Cryptography;
using Test.IO.Streams;
using Xunit;
@@ -38,6 +39,7 @@ namespace System.Security.Cryptography.Rsa.Tests
public abstract class SignVerify
{
+ public static bool SupportsPss => RSAFactory.SupportsPss;
public static bool BadKeyFormatDoesntThrow => !PlatformDetection.IsFullFramework || PlatformDetection.IsNetfx462OrNewer;
public static bool InvalidKeySizeDoesntThrow => !PlatformDetection.IsFullFramework || PlatformDetection.IsNetfx462OrNewer;
@@ -546,6 +548,29 @@ namespace System.Security.Cryptography.Rsa.Tests
}
[Fact]
+ public void PkcsSignHash_MismatchedHashSize()
+ {
+ RSASignaturePadding padding = RSASignaturePadding.Pkcs1;
+
+ using (RSA rsa = RSAFactory.Create(TestData.RSA2048Params))
+ {
+ byte[] data152 = new byte[152 / 8];
+ byte[] data168 = new byte[168 / 8];
+
+ Assert.ThrowsAny<CryptographicException>(
+ () => SignHash(rsa, data152, HashAlgorithmName.SHA1, padding));
+
+ Assert.ThrowsAny<CryptographicException>(
+ () => SignHash(rsa, data168, HashAlgorithmName.SHA1, padding));
+
+ byte[] data160 = new byte[160 / 8];
+
+ Assert.ThrowsAny<CryptographicException>(
+ () => SignHash(rsa, data160, HashAlgorithmName.SHA256, padding));
+ }
+ }
+
+ [Fact]
public void ExpectedHashSignature_SHA1_2048()
{
byte[] expectedHashSignature = new byte[]
@@ -807,6 +832,340 @@ namespace System.Security.Cryptography.Rsa.Tests
VerifyHashSignature(hashSignature, dataHash, "SHA256", TestData.RSA2048Params);
}
+ [Theory]
+ [InlineData("SHA256")]
+ [InlineData("SHA384")]
+ [InlineData("SHA512")]
+ [InlineData("MD5")]
+ [InlineData("SHA1")]
+ public void PssRoundtrip(string hashAlgorithmName)
+ {
+ RSAParameters privateParameters = TestData.RSA2048Params;
+ RSAParameters publicParameters = new RSAParameters
+ {
+ Modulus = privateParameters.Modulus,
+ Exponent = privateParameters.Exponent,
+ };
+
+ using (RSA privateKey = RSAFactory.Create())
+ using (RSA publicKey = RSAFactory.Create())
+ {
+ privateKey.ImportParameters(privateParameters);
+ publicKey.ImportParameters(publicParameters);
+
+ byte[] data = TestData.RsaBigExponentParams.Modulus;
+ HashAlgorithmName hashAlgorithm = new HashAlgorithmName(hashAlgorithmName);
+ RSASignaturePadding padding = RSASignaturePadding.Pss;
+
+ if (RSAFactory.SupportsPss)
+ {
+ byte[] signature = SignData(privateKey, data, hashAlgorithm, padding);
+
+ Assert.NotNull(signature);
+ Assert.Equal(publicParameters.Modulus.Length, signature.Length);
+
+ Assert.True(VerifyData(publicKey, data, signature, hashAlgorithm, padding));
+ }
+ else
+ {
+ Assert.ThrowsAny<CryptographicException>(
+ () => SignData(privateKey, data, hashAlgorithm, padding));
+
+ byte[] signature = new byte[privateParameters.Modulus.Length];
+
+ Assert.ThrowsAny<CryptographicException>(
+ () => VerifyData(privateKey, data, signature, hashAlgorithm, padding));
+ }
+ }
+ }
+
+ [Fact]
+ public void VerifyExpectedSignature_PssSha256_RSA2048()
+ {
+ byte[] modulus2048Signature = (
+ "460CA7273FF6CC02DD57F07CB18E65E5AF23B0285E26122B810EC6D2F4EE7E1A" +
+ "1B01A203623E800C9940CE827614B2F1DC7C7B1CC3A976D27F82517EB64AC90B" +
+ "9A97D1CC17FB4731C63CA02C9F46B57A4A03981D73265CDB36E28EF08FCA77ED" +
+ "FAB34EE91FE6AABF00045489ACEB631FB004438344EA7997ADE2191C1A70E9F9" +
+ "2BA809FEFB4EFA0DBC1075A7EBBBCF57747DA8D0B3467BD3DAC5EA8B47F76F07" +
+ "7043497E7459A83349FE74320E77D471008CB7B43707561FA8DC9251F8EAE531" +
+ "5AC1894C4F9E6B7BECF993C146C5D6CF0DB60992A297F358A0895831965887C4" +
+ "B9153B96771C998CD61DA0C487D63555AE66F917F1BFDF509BFFEB21440F6A3C").HexToByteArray();
+
+ VerifyExpectedSignature_Pss(
+ TestData.RSA2048Params,
+ HashAlgorithmName.SHA256,
+ TestData.RSA2048Params.Modulus,
+ modulus2048Signature);
+ }
+
+ [Fact]
+ public void VerifyExpectedSignature_PssSha256_RSA16384()
+ {
+ byte[] modulus2048Signature = (
+ "1D92D529567F6922866FFDE4BF44C427FA511BF5EDF163ED51A0D14ADECD98FB" +
+ "C6A61A61532404AF74C3AB65119BB1358855A68362FBABAED7D8E56403EE9AFA" +
+ "33C8D73E35880066556A7304F8E8A3EBF981C8318958AC867B32F3A01F085F53" +
+ "B0885781DFCF4DE4183805B7B26C4718E58031FF8D0B82B38D958BF0147C263F" +
+ "A4012FE29E8B3D7EA18780C3A6B01E15D81387C4367AFB35FF4868309928C112" +
+ "86F030AFED02B2C8CED24C527B8EAA126076B268F469427E70D0ACFC4C3E007D" +
+ "05F84E2F3D3DC3028674DA38026F9054F54636FBED099CD528782F60F1882045" +
+ "E2F297B467496F01AE566EC80C384A5E775481EECEA713D0F35C75CBFDB33F52" +
+ "FC4699EDBEB1F938368AA2B261402634BEE548F38821E6FCBFE7C26C0C44EB1D" +
+ "58D215500E11EA400AE44B349727BE28A62188770393863B0F9BCC6C82717C35" +
+ "34334205B931BDD6FEA4FDCC681566BCB2AF80266D692007E027682535BFD265" +
+ "3E8D906D3531575975F2BB77457378FA84A34F2F064F6E5B986D48FBFD9F8BF8" +
+ "BD3CDFDA21C624A315C8246764841C811939B60BC73AB4CD15B141A1C3D063B6" +
+ "9529FB4B4342B1064650272CECE2B0A398A5F9B5FD2D107A9FE84781CA11D29F" +
+ "00986BEE1850BC5E46570FDFD54DBD15C6C8BA12AC0CA7825765009346AB7E95" +
+ "848F95928368E65AFDCB8AA058B0EE31320584248327F4D22017480BAB38BA47" +
+ "4FFCBBE68C5A24582AB9594EAD26ACE67170319B1BA9FB514070A5051744EAB3" +
+ "BDC1C131A8AF580CE5B11B23B50FF66D4DC6F6064C7FBA88D8CB74A3A85A51EB" +
+ "C344F7226871286109B0B9D33B7137B223FDC152EDD1BA0641D906A22F91D146" +
+ "8B39EAC8261EB05CA7757AEA46051599087CE92A9962D1DEF8DAF910F10169E0" +
+ "A0F8F864C0E4B29DC12958B06E8E4225C90CFEB6D7367DFEB7F8DF2891D50DCC" +
+ "89F435466A3D25B676BD06C69D39EDE7EDD639703C262B7C0257C88BD197542F" +
+ "0CE25F8E317037C1DC4380E2AA43CB4FBBA078AF83CDCA8DD8A8545267E3F853" +
+ "8DE7A897269E492A1400715FC3BABF2E30D2696216F51FD30FC3BE67FB9813CA" +
+ "DAEE3E4CB779A5F8A10DBCA11927CBC50721A5412680E490A68CA3DFF74B9E2A" +
+ "774DCC32B84B9D5B253268465A911A6CF3D189F51D21DDEF30006F929C151402" +
+ "E821F4097A8514192F95CA8B9ABFD0B7C7C86AAC5B0FDAECB02EABBC3B1F8442" +
+ "2A1921AE0B4BC01B6C037038DF382DC130843B15F5F042A98053578248E8DB02" +
+ "A1B5FC702B59FEAD99C32F6DAF15308A53CA139E408CE0F45DEC48FF1E5DB77B" +
+ "0305196F16598A21AF92603F77BA061A2A12B5D6F69B19F2EBDDE47578DD3895" +
+ "8D36D15D88015F5E51AA818669B6A65DE40C264CAD22B8E25D4866E8BBC0A64E" +
+ "59E0D95C69DF925BB9B9C88AB0542E53C6034DDE4FB5763D21C62765FA7A39AA" +
+ "B50652F20D464652710162EBBE7ECFEFF255864B459A0DD83DD3E7DD88EA1271" +
+ "442D70A944106A47EF22ADF67AD9D7CC24FC47C66B5D9B15E3D0104491D8C060" +
+ "A6E46F96A8E0C11A7D25211E2206B1CE272143B4B369D7B07645CB1E94668C43" +
+ "3D412A4600364122F22D7EC6B79227FA215CD230E3D09D0AA5BE3B291C4BE343" +
+ "808582C7F6EE20D7457DE1955F9E7E40A4C9EF55C5A5A0D3D125D8F53E69477B" +
+ "F0D91BD8B3401ECEEFE9D94382F836ACFB81814DFEF86F614406B02B6001E90E" +
+ "E84DA2BD0441BB943A6295F530AA7B7F375CD91EBA4CA83A0CF35FCBCA9F9915" +
+ "3BA0C28D1DA762D6257C99378F21FD6D890C31B9606BB6238CD3B0DBD4012649" +
+ "602E5352D20DA067576A94DB21E323B7902885F8892C844411027C3F4ED1F28B" +
+ "DBFB929E986DA6AF15F552975705C9C2C5500CE52F90903EF4BD53B145FB713B" +
+ "8A62FA292E608438A1CBF663FCCCEC99489CE9D709BF92AA9260F3950B058618" +
+ "B4EED63DD02376057460AF3854976C6A9C605148B0882F337253AD8AE8FA3AA6" +
+ "4194EF462A403D8198F1FBEFCC2ECAAE6B3C3A52AC79F5311F60B3EF2B281FE1" +
+ "C22E2C820570C687A1B5C7A1BB5013844DEE5AD720BE9D186B14EF38EA2FCB12" +
+ "4358CF552BEB3B9A0B36FB298FE527EEE2CD428680C4D6C55CCBFCE6F8E81162" +
+ "32198584267DF41CF50BDDBA22C601ADCA005A2187FC0097DC0B6AF0552B3034" +
+ "BA6E432DD0D7D6F3D58DDA91AC4756D2CFFC28DCF0A7EEE2D2A6CC23C77A2E2F" +
+ "9DD26143AAD7062093D7592C282A02FABC3815DD285064F6F5F0848294D781B3" +
+ "20C3F2DA3C26E1CCF6DB171908D5AFABA1A7BABC6D3F31FD7B566B7321AF6297" +
+ "F3EE652ABD11DD4FFF39D77B4FE06A838412B85C4877534369D115C65FA36BA3" +
+ "DDFF9B50C95B2AD649A5C814C9183ED743FA5CB23F65C5216C0F61B16CB73409" +
+ "D105EE6321C7D210C4DABC7A80C63B383178669FA9E79DCDD3DB1C175EED5199" +
+ "9F51BBAC06C90794B77491D0BC2FED10199EE322B7B23DB5B63B6C6B85E39ED3" +
+ "D145BC070EA912820C2E59FE9ED3670D8FBC44B9B2D6FAEEF95154972BA509CC" +
+ "96F83328DD7243DB11F9CDD5D8013DB8C7DD5ED58DEEFAC7FD282085715A063E" +
+ "320B167C904A65761233361B8232DAE539A8B5B38D9506ABBA9844E24D64E2DA" +
+ "ACD1E4F22546959282B721ACDA8289AE92C5FE0775F59A4EA10C732EE22FA01C" +
+ "E6556E8CCA94E6DD87F3A50EDF6FFDC4D10B07B3FBC55111DF62088A1AFCE2B6" +
+ "C6CF4C18CAA3BA05E7117368546B241236DDE91DF9CE30AE691C6044F30EA85A" +
+ "F169F0B64C353A40BC4AFF467C4B304B70751248B1B09F3781DDB84087B972FD" +
+ "0C92C6ABE141D38327BD810F87F0E058098B6E8A538E236C40955005AC4A232D" +
+ "22F7F9B479D0C093F18C4C4756B06F80132980E30716A3282306D1352CBBCD31").HexToByteArray();
+
+ VerifyExpectedSignature_Pss(
+ TestData.RSA16384Params,
+ HashAlgorithmName.SHA256,
+ TestData.RSA2048Params.Modulus,
+ modulus2048Signature);
+ }
+
+ [Fact]
+ public void VerifyExpectedSignature_PssSha384()
+ {
+ byte[] bigModulusSignature = (
+ "70F48CA4E8640701369DB986C4D09C91E4C197DB1BE4F32C3F37A67AEC4BA95D" +
+ "733EAACAE139B7B9C8E66C5BC82629971C3BEBF93A949CB81763FECDF96B73DA" +
+ "7D5929A15DFEF58B51E6D43F46238FC1121AAA3A5F3DF6B56E0FE2B6205192AB" +
+ "BA9752FC9CFD3000B08E3A823514A93FD90871FD09A005DA191431487DAF6364" +
+ "22").HexToByteArray();
+
+ VerifyExpectedSignature_Pss(
+ TestData.RSA1032Parameters,
+ HashAlgorithmName.SHA384,
+ TestData.RSA16384Params.Modulus,
+ bigModulusSignature);
+ }
+
+ [Fact]
+ public void VerifyExpectedSignature_PssSha512()
+ {
+ byte[] helloSignature = (
+ "60678D68816149206AD33F7153FFBAA1043FF7ABC539D6C88E5D2C94BCC10CF4" +
+ "E66A6F0F08DEA15781B8FA06F9E27D0B01347DAAA4B760D8978EC2EF87B508A2" +
+ "680FBE59F8BCC8A6AF413A1CB2373DFF32C4217542A9EE86179083DD316485FB" +
+ "E496EEF0EBE3E4A2793C888E988962C5EAF35136172E74B02724770863D10B19" +
+ "AACDE7D31CE77BE96EA54DE7A2409648AB3105FAC1003B00E32FAE4527284352" +
+ "A859C17F4C7D611DE4C451291A3096A0D6230EE2699B79CD571DE6D441CB372A" +
+ "9D6E46080AB8041D45D4B9475CBE6B48D10F4332910869D8C3931133224475D9" +
+ "BA1E0B92161BB2C17A96F92432F2BA1AEBAD8C7CD33D79F5C6EFB9BF6F192205").HexToByteArray();
+
+ VerifyExpectedSignature_Pss(
+ TestData.RSA2048Params,
+ HashAlgorithmName.SHA512,
+ TestData.HelloBytes,
+ helloSignature);
+ }
+
+ private void VerifyExpectedSignature_Pss(
+ RSAParameters keyParameters,
+ HashAlgorithmName hashAlgorithm,
+ byte[] data,
+ byte[] signature,
+ [System.Runtime.CompilerServices.CallerMemberName] string callerName = null)
+ {
+ RSAParameters publicParameters = new RSAParameters
+ {
+ Modulus = keyParameters.Modulus,
+ Exponent = keyParameters.Exponent,
+ };
+
+ RSASignaturePadding padding = RSASignaturePadding.Pss;
+
+ using (RSA rsaPublic = RSAFactory.Create())
+ using (RSA rsaPrivate = RSAFactory.Create())
+ {
+ try
+ {
+ rsaPublic.ImportParameters(publicParameters);
+ }
+ catch (CryptographicException)
+ {
+ // The key didn't load, not anything else this test can do.
+ return;
+ }
+
+ rsaPrivate.ImportParameters(keyParameters);
+
+ // Generator for new tests.
+ if (signature == null)
+ {
+ signature = SignData(rsaPrivate, data, hashAlgorithm, padding);
+ Console.WriteLine($"{callerName}: {signature.ByteArrayToHex()}");
+ }
+
+ if (RSAFactory.SupportsPss)
+ {
+ Assert.True(
+ VerifyData(rsaPublic, data, signature, hashAlgorithm, padding),
+ "Public key verified the signature");
+
+ Assert.True(
+ VerifyData(rsaPrivate, data, signature, hashAlgorithm, padding),
+ "Private key verified the signature");
+ }
+ else
+ {
+ Assert.ThrowsAny<CryptographicException>(
+ () => VerifyData(rsaPublic, data, signature, hashAlgorithm, padding));
+
+ Assert.ThrowsAny<CryptographicException>(
+ () => VerifyData(rsaPrivate, data, signature, hashAlgorithm, padding));
+ }
+ }
+ }
+
+ [ConditionalFact(nameof(SupportsPss))]
+ public void PssSignature_WrongHashAlgorithm()
+ {
+ RSASignaturePadding padding = RSASignaturePadding.Pss;
+ byte[] data = TestData.HelloBytes;
+
+ using (RSA rsa = RSAFactory.Create(TestData.RSA2048Params))
+ {
+ byte[] signature = SignData(rsa, data, HashAlgorithmName.SHA256, padding);
+ Assert.False(VerifyData(rsa, data, signature, HashAlgorithmName.SHA384, padding));
+ }
+ }
+
+ [ConditionalFact(nameof(SupportsPss))]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void PssVerifyHash_MismatchedHashSize()
+ {
+ // This is a legal SHA-1 value, which we're going to use with SHA-2-256 instead.
+ byte[] hash = "75ED7E627DB9AECBD870E27EED49ED7D9AEB2F52".HexToByteArray();
+
+ byte[] sig = (
+ "837A17C13618030A6C0C17551D8A34CA5AE4BB1D45A5DAD091F4016C630E0838" +
+ "5F9D9F1F75EF4CCBBE723C0630AC699C43587D81BD16AFBD2F797215F68F8062" +
+ "87A352BB269FB9D042DA4D9D664172E4B3B39FC3457879C8DBDD56FAB44F2515" +
+ "71E2E607A964CB548CB36198004ACD8D3E3B80D10917CE582710BB65513C0310" +
+ "4A0A82C63D2B8898F5BAF97618B5EBE5F3B0824561C059FD7FC949B12837E8B1" +
+ "E86380E9A68F6D7E8E8BD5C57B04E831DBBDBDCA20403EC988635F62D4B48382" +
+ "56E2AF4213FDCA6BF801C06AF6381DAC61288C13B08806A323B3E956A13BCB29" +
+ "680F62CCA9880A8A1FD1A2CA61DCFE008AC7FC55E98ACCE9B7BE010E5BCB836A").HexToByteArray();
+
+ using (RSA rsa = RSAFactory.Create(TestData.RSA2048Params))
+ {
+ Assert.False(VerifyHash(rsa, hash, sig, HashAlgorithmName.SHA256, RSASignaturePadding.Pss));
+ }
+ }
+
+ [ConditionalFact(nameof(SupportsPss))]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void PssSignHash_MismatchedHashSize()
+ {
+ RSASignaturePadding padding = RSASignaturePadding.Pss;
+
+ using (RSA rsa = RSAFactory.Create(TestData.RSA2048Params))
+ {
+ byte[] data152 = new byte[152 / 8];
+ byte[] data168 = new byte[168 / 8];
+
+ Assert.ThrowsAny<CryptographicException>(
+ () => SignHash(rsa, data152, HashAlgorithmName.SHA1, padding));
+
+ Assert.ThrowsAny<CryptographicException>(
+ () => SignHash(rsa, data168, HashAlgorithmName.SHA1, padding));
+
+ byte[] data160 = new byte[160 / 8];
+
+ Assert.ThrowsAny<CryptographicException>(
+ () => SignHash(rsa, data160, HashAlgorithmName.SHA256, padding));
+ }
+ }
+
+ [ConditionalFact(nameof(SupportsPss))]
+ public void PssSignature_WrongData()
+ {
+ RSASignaturePadding padding = RSASignaturePadding.Pss;
+ byte[] dataCopy = (byte[])TestData.HelloBytes.Clone();
+ HashAlgorithmName hashAlgorithmName = HashAlgorithmName.SHA256;
+
+ using (RSA rsa = RSAFactory.Create(TestData.RSA2048Params))
+ {
+ byte[] signature = SignData(rsa, dataCopy, hashAlgorithmName, padding);
+ dataCopy[0] ^= 0xFF;
+ Assert.False(VerifyData(rsa, dataCopy, signature, hashAlgorithmName, padding));
+ }
+ }
+
+ [ConditionalFact(nameof(SupportsPss))]
+ public void PssSignature_WrongLength()
+ {
+ RSASignaturePadding padding = RSASignaturePadding.Pss;
+ byte[] data = TestData.HelloBytes;
+ HashAlgorithmName hashAlgorithmName = HashAlgorithmName.SHA256;
+
+ using (RSA rsa = RSAFactory.Create(TestData.RSA2048Params))
+ {
+ byte[] signature = SignData(rsa, data, hashAlgorithmName, padding);
+
+ // Too long by a byte
+ Array.Resize(ref signature, signature.Length + 1);
+ Assert.False(VerifyData(rsa, data, signature, hashAlgorithmName, padding));
+
+ // Net too short by a byte
+ Array.Resize(ref signature, signature.Length - 2);
+ Assert.False(VerifyData(rsa, data, signature, hashAlgorithmName, padding));
+ }
+ }
+
private void ExpectSignature(
byte[] expectedSignature,
byte[] data,
diff --git a/src/Common/tests/System/Security/Cryptography/ByteUtils.cs b/src/Common/tests/System/Security/Cryptography/ByteUtils.cs
index f39df0409f..be8a1d5f9b 100644
--- a/src/Common/tests/System/Security/Cryptography/ByteUtils.cs
+++ b/src/Common/tests/System/Security/Cryptography/ByteUtils.cs
@@ -37,7 +37,7 @@ namespace Test.Cryptography
internal static string ByteArrayToHex(this byte[] bytes)
{
- return ByteArrayToHex(bytes.AsReadOnlySpan());
+ return ByteArrayToHex((ReadOnlySpan<byte>)bytes);
}
internal static string ByteArrayToHex(this Span<byte> bytes)
diff --git a/src/Common/tests/System/Threading/Tasks/TaskTimeoutExtensions.cs b/src/Common/tests/System/Threading/Tasks/TaskTimeoutExtensions.cs
index 3a72628f6e..a6eab1b64d 100644
--- a/src/Common/tests/System/Threading/Tasks/TaskTimeoutExtensions.cs
+++ b/src/Common/tests/System/Threading/Tasks/TaskTimeoutExtensions.cs
@@ -13,10 +13,10 @@ namespace System.Threading.Tasks
{
var cts = new CancellationTokenSource();
- if (task == await Task.WhenAny(task, Task.Delay(millisecondsTimeout, cts.Token)))
+ if (task == await Task.WhenAny(task, Task.Delay(millisecondsTimeout, cts.Token)).ConfigureAwait(false))
{
cts.Cancel();
- await task;
+ await task.ConfigureAwait(false);
}
else
{
@@ -28,10 +28,10 @@ namespace System.Threading.Tasks
{
var cts = new CancellationTokenSource();
- if (task == await Task<TResult>.WhenAny(task, Task<TResult>.Delay(millisecondsTimeout, cts.Token)))
+ if (task == await Task<TResult>.WhenAny(task, Task<TResult>.Delay(millisecondsTimeout, cts.Token)).ConfigureAwait(false))
{
cts.Cancel();
- return await task;
+ return await task.ConfigureAwait(false);
}
else
{
@@ -46,7 +46,7 @@ namespace System.Threading.Tasks
if (task == await Task.WhenAny(task, Task.Delay(millisecondsTimeout, cts.Token)).ConfigureAwait(false))
{
cts.Cancel();
- await task;
+ await task.ConfigureAwait(false);
}
else
{
diff --git a/src/Common/tests/Tests/System/IO/PathInternal.Tests.cs b/src/Common/tests/Tests/System/IO/PathInternal.Tests.cs
index 4435fb8830..3f33936e0c 100644
--- a/src/Common/tests/Tests/System/IO/PathInternal.Tests.cs
+++ b/src/Common/tests/Tests/System/IO/PathInternal.Tests.cs
@@ -1,39 +1,16 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System;
using System.IO;
using System.Text;
using Xunit;
namespace Tests.System.IO
{
- public class PathInternalTests
+ public class PathInternal_Windows_Tests
{
[Theory,
- InlineData("Foo", "Foos"),
- InlineData("Foo", null)]
- public void StartsWithOrdinal_NegativeCases(string source, string value)
- {
- Assert.False(PathInternal.StartsWithOrdinal(source, value));
- Assert.False(PathInternal.StartsWithOrdinal(new StringBuilder(source), value));
- }
-
- [Theory,
- InlineData("FOO", "foo", false),
- InlineData("FOO", "FOO", true),
- InlineData("FOO", "fo", false),
- InlineData("FOO", "FO", true),
- InlineData("FOO", "oo", false),
- InlineData("FOO", "OO", false)]
- public void StartsWithOrdinal_PositiveCases(string source, string value, bool expected)
- {
- Assert.Equal(expected, PathInternal.StartsWithOrdinal(source, value));
- Assert.Equal(expected, PathInternal.StartsWithOrdinal(new StringBuilder(source), value));
- }
-
- [Theory,
InlineData("", "", true, 0),
InlineData("", "", false, 0),
InlineData("a", "", true, 0),
@@ -87,5 +64,345 @@ namespace Tests.System.IO
{
Assert.Equal(expected, PathInternal.GetCommonPathLength(first, second, ignoreCase));
}
+
+ public static TheoryData<string, int, string> RemoveRelativeSegmentsData => new TheoryData<string, int, string>
+ {
+ { @"C:\git\corefx", 2, @"C:\git\corefx"},
+ { @"C:\\git\corefx", 2, @"C:\git\corefx"},
+ { @"C:\git\\corefx", 2, @"C:\git\corefx"},
+ { @"C:\git\.\corefx\.\\", 2, @"C:\git\corefx\"},
+ { @"C:\git\corefx", 2, @"C:\git\corefx"},
+ { @"C:\git\..\corefx", 2, @"C:\corefx"},
+ { @"C:\git\corefx\..\", 2, @"C:\git\"},
+ { @"C:\git\corefx\..\..\..\", 2, @"C:\"},
+ { @"C:\git\corefx\..\..\.\", 2, @"C:\"},
+ { @"C:\git\..\.\corefx\temp\..", 2, @"C:\corefx"},
+ { @"C:\git\..\\\.\..\corefx", 2, @"C:\corefx"},
+ { @"C:\git\corefx\", 2, @"C:\git\corefx\"},
+ { @"C:\git\temp\..\corefx\", 2, @"C:\git\corefx\"},
+
+ { @"C:\.", 3, @"C:\"},
+ { @"C:\..", 3, @"C:\"},
+ { @"C:\..\..", 3, @"C:\"},
+ { @"C:\.", 2, @"C:"},
+ { @"C:\..", 2, @"C:"},
+ { @"C:\..\..", 2, @"C:"},
+ { @"C:A\.", 2, @"C:A"},
+ { @"C:A\..", 2, @"C:"},
+ { @"C:A\..\..", 2, @"C:"},
+ { @"C:A\..\..\..", 2, @"C:"},
+
+ { @"C:\tmp\home", 3, @"C:\tmp\home" },
+ { @"C:\tmp\..", 3, @"C:\" },
+ { @"C:\tmp\home\..\.\.\", 3, @"C:\tmp\" },
+ { @"C:\tmp\..\..\..\", 3, @"C:\" },
+ { @"C:\tmp\\home", 3, @"C:\tmp\home" },
+ { @"C:\.\tmp\\home", 3, @"C:\tmp\home" },
+ { @"C:\..\tmp\home", 3, @"C:\tmp\home" },
+ { @"C:\..\..\..\tmp\.\home", 3, @"C:\tmp\home" },
+ { @"C:\\tmp\\\home", 3, @"C:\tmp\home" },
+ { @"C:\tmp\home\git\.\..\.\git\corefx\..\", 3, @"C:\tmp\home\git\" },
+ { @"C:\.\tmp\home", 3, @"C:\tmp\home" },
+
+ { @"C:\tmp\home", 6, @"C:\tmp\home" },
+ { @"C:\tmp\..", 6, @"C:\tmp" },
+ { @"C:\tmp\home\..\.\.\", 5, @"C:\tmp\" },
+ { @"C:\tmp\..\..\..\", 6, @"C:\tmp\" },
+ { @"C:\tmp\\home", 5, @"C:\tmp\home" },
+ { @"C:\.\tmp\\home", 4, @"C:\.\tmp\home" },
+ { @"C:\..\tmp\home", 5, @"C:\..\tmp\home" },
+ { @"C:\..\..\..\tmp\.\home", 6, @"C:\..\tmp\home" },
+ { @"C:\\tmp\\\home", 7, @"C:\\tmp\home" },
+ { @"C:\tmp\home\git\.\..\.\git\corefx\..\", 7, @"C:\tmp\home\git\" },
+ { @"C:\.\tmp\home", 5, @"C:\.\tmp\home" },
+
+ { @"C:\tmp\..", 2, @"C:\" },
+ { @"C:\tmp\home\..\..\.\", 2, @"C:\" },
+ { @"C:\tmp\..\..\..\", 2, @"C:\" },
+ { @"C:\tmp\\home", 2, @"C:\tmp\home" },
+ { @"C:\.\tmp\\home", 2, @"C:\tmp\home" },
+ { @"C:\..\tmp\home", 2, @"C:\tmp\home" },
+ { @"C:\..\..\..\tmp\.\home", 2, @"C:\tmp\home" },
+ { @"C:\\tmp\\\home", 2, @"C:\tmp\home" },
+ { @"C:\tmp\home\git\.\..\.\git\corefx\..\", 2, @"C:\tmp\home\git\" },
+ { @"C:\.\tmp\home", 2, @"C:\tmp\home" },
+
+ { @"C:\tmp\..\..\", 10, @"C:\tmp\..\" },
+ { @"C:\tmp\home\..\.\.\", 12, @"C:\tmp\home\" },
+ { @"C:\tmp\..\..\..\", 10, @"C:\tmp\..\" },
+ { @"C:\tmp\\home\..\.\\", 13, @"C:\tmp\\home\" },
+ { @"C:\.\tmp\\home\git\git", 9, @"C:\.\tmp\home\git\git" },
+ { @"C:\..\tmp\.\home", 10, @"C:\..\tmp\home" },
+ { @"C:\..\..\..\tmp\.\home", 10, @"C:\..\..\..\tmp\home" },
+ { @"C:\\tmp\\\home\..", 7, @"C:\\tmp\" },
+ { @"C:\tmp\home\git\.\..\.\git\corefx\..\", 18, @"C:\tmp\home\git\.\git\" },
+ { @"C:\.\tmp\home\.\.\", 9, @"C:\.\tmp\home\" },
+ };
+
+ public static TheoryData<string, int, string> RemoveRelativeSegmentsFirstRelativeSegment => new TheoryData<string, int, string>
+ {
+ { @"C:\\git\corefx", 2, @"C:\git\corefx"},
+ { @"C:\.\git\corefx", 2, @"C:\git\corefx"},
+ { @"C:\\.\git\.\corefx", 2, @"C:\git\corefx"},
+ { @"C:\..\git\corefx", 2, @"C:\git\corefx"},
+ { @"C:\.\git\..\corefx", 2, @"C:\corefx"},
+ { @"C:\.\git\corefx\..\", 2, @"C:\git\"},
+ { @"C:\.\git\corefx\..\..\..\", 2, @"C:\"},
+ { @"C:\.\git\corefx\..\..\.\", 2, @"C:\"},
+ { @"C:\.\git\..\.\corefx\temp\..", 2, @"C:\corefx"},
+ { @"C:\.\git\..\\\.\..\corefx", 2, @"C:\corefx"},
+ { @"C:\.\git\corefx\", 2, @"C:\git\corefx\"},
+ { @"C:\.\git\temp\..\corefx\", 2, @"C:\git\corefx\"},
+ { @"C:\\..\..", 3, @"C:\"}
+ };
+
+ public static TheoryData<string, int, string> RemoveRelativeSegmentsSkipAboveRoot => new TheoryData<string, int, string>
+ {
+ { @"C:\temp\..\" , 7, @"C:\temp\" },
+ { @"C:\temp\..\git" , 7, @"C:\temp\git" },
+ { @"C:\temp\..\git" , 8, @"C:\temp\git" },
+ { @"C:\temp\..\.\" , 8, @"C:\temp\" },
+ { @"C:\temp\..\" , 9, @"C:\temp\..\" },
+ { @"C:\temp\..\git" , 9, @"C:\temp\..\git" },
+ { @"C:\git\..\temp\..\" , 15, @"C:\git\..\temp\" },
+ { @"C:\\\.\..\..\temp\..\" , 17, @"C:\\\.\..\..\temp\" },
+ };
+
+ public static TheoryData<string, int, string> RemoveRelativeSegmentsFirstRelativeSegmentRoot => new TheoryData<string, int, string>
+ {
+ { @"C:\\git\corefx", 3, @"C:\git\corefx"},
+ { @"C:\.\git\corefx", 3, @"C:\git\corefx"},
+ { @"C:\\.\git\.\corefx", 3, @"C:\git\corefx"},
+ { @"C:\..\git\corefx", 3, @"C:\git\corefx"},
+ { @"C:\.\git\..\corefx", 3, @"C:\corefx"},
+ { @"C:\.\git\corefx\..\", 3, @"C:\git\"},
+ { @"C:\.\git\corefx\..\..\..\", 3, @"C:\"},
+ { @"C:\.\git\corefx\..\..\.\", 3, @"C:\"},
+ { @"C:\.\git\..\.\corefx\temp\..", 3, @"C:\corefx"},
+ { @"C:\.\git\..\\\.\..\corefx", 3, @"C:\corefx"},
+ { @"C:\.\git\corefx\", 3, @"C:\git\corefx\"},
+ { @"C:\.\git\temp\..\corefx\", 3, @"C:\git\corefx\"},
+ };
+
+ [Theory,
+ MemberData(nameof(RemoveRelativeSegmentsData)),
+ MemberData(nameof(RemoveRelativeSegmentsFirstRelativeSegment)),
+ MemberData(nameof(RemoveRelativeSegmentsFirstRelativeSegmentRoot)),
+ MemberData(nameof(RemoveRelativeSegmentsSkipAboveRoot))]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void RemoveRelativeSegmentsTest(string path, int skip, string expected)
+ {
+ Assert.Equal(expected, PathInternal.RemoveRelativeSegments(path, skip));
+ Assert.Equal(@"\\.\" + expected, PathInternal.RemoveRelativeSegments(@"\\.\" + path, skip + 4));
+ Assert.Equal(@"\\?\" + expected, PathInternal.RemoveRelativeSegments(@"\\?\" + path, skip + 4));
+ }
+
+ public static TheoryData<string, int, string> RemoveRelativeSegmentsUncData => new TheoryData<string, int, string>
+ {
+ { @"Server\Share\git\corefx", 12, @"Server\Share\git\corefx"},
+ { @"Server\Share\\git\corefx", 12, @"Server\Share\git\corefx"},
+ { @"Server\Share\git\\corefx", 12, @"Server\Share\git\corefx"},
+ { @"Server\Share\git\.\corefx\.\\", 12, @"Server\Share\git\corefx\"},
+ { @"Server\Share\git\corefx", 12, @"Server\Share\git\corefx"},
+ { @"Server\Share\git\..\corefx", 12, @"Server\Share\corefx"},
+ { @"Server\Share\git\corefx\..\", 12, @"Server\Share\git\"},
+ { @"Server\Share\git\corefx\..\..\..\", 12, @"Server\Share\"},
+ { @"Server\Share\git\corefx\..\..\.\", 12, @"Server\Share\"},
+ { @"Server\Share\git\..\.\corefx\temp\..", 12, @"Server\Share\corefx"},
+ { @"Server\Share\git\..\\\.\..\corefx", 12, @"Server\Share\corefx"},
+ { @"Server\Share\git\corefx\", 12, @"Server\Share\git\corefx\"},
+ { @"Server\Share\git\temp\..\corefx\", 12, @"Server\Share\git\corefx\"},
+ };
+
+ [Theory,
+ MemberData(nameof(RemoveRelativeSegmentsUncData))]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void RemoveRelativeSegmentsUncTest(string path, int skip, string expected)
+ {
+ Assert.Equal(@"\\" + expected, PathInternal.RemoveRelativeSegments(@"\\" + path, skip + 2));
+ Assert.Equal(@"\\.\UNC\" + expected, PathInternal.RemoveRelativeSegments(@"\\.\UNC\" + path, skip + 8));
+ Assert.Equal(@"\\?\UNC\" + expected, PathInternal.RemoveRelativeSegments(@"\\?\UNC\" + path, skip + 8));
+ }
+
+ public static TheoryData<string, int, string> RemoveRelativeSegmentsDeviceData => new TheoryData<string, int, string>
+ {
+ { @"\\.\git\corefx", 7, @"\\.\git\corefx"},
+ { @"\\.\git\corefx", 7, @"\\.\git\corefx"},
+ { @"\\.\git\\corefx", 7, @"\\.\git\corefx"},
+ { @"\\.\git\.\corefx\.\\", 7, @"\\.\git\corefx\"},
+ { @"\\.\git\corefx", 7, @"\\.\git\corefx"},
+ { @"\\.\git\..\corefx", 7, @"\\.\git\corefx"},
+ { @"\\.\git\corefx\..\", 7, @"\\.\git\"},
+ { @"\\.\git\corefx\..\..\..\", 7, @"\\.\git\"},
+ { @"\\.\git\corefx\..\..\.\", 7, @"\\.\git\"},
+ { @"\\.\git\..\.\corefx\temp\..", 7, @"\\.\git\corefx"},
+ { @"\\.\git\..\\\.\..\corefx", 7, @"\\.\git\corefx"},
+ { @"\\.\git\corefx\", 7, @"\\.\git\corefx\"},
+ { @"\\.\git\temp\..\corefx\", 7, @"\\.\git\corefx\"},
+
+ { @"\\.\.\corefx", 5, @"\\.\.\corefx"},
+ { @"\\.\.\corefx", 5, @"\\.\.\corefx"},
+ { @"\\.\.\\corefx", 5, @"\\.\.\corefx"},
+ { @"\\.\.\.\corefx\.\\", 5, @"\\.\.\corefx\"},
+ { @"\\.\.\corefx", 5, @"\\.\.\corefx"},
+ { @"\\.\.\..\corefx", 5, @"\\.\.\corefx"},
+ { @"\\.\.\corefx\..\", 5, @"\\.\.\"},
+ { @"\\.\.\corefx\..\..\..\", 5, @"\\.\.\"},
+ { @"\\.\.\corefx\..\..\.\", 5, @"\\.\.\"},
+ { @"\\.\.\..\.\corefx\temp\..", 5, @"\\.\.\corefx"},
+ { @"\\.\.\..\\\.\..\corefx", 5, @"\\.\.\corefx"},
+ { @"\\.\.\corefx\", 5, @"\\.\.\corefx\"},
+ { @"\\.\.\temp\..\corefx\", 5, @"\\.\.\corefx\"},
+
+ { @"\\.\..\corefx", 6, @"\\.\..\corefx"},
+ { @"\\.\..\corefx", 6, @"\\.\..\corefx"},
+ { @"\\.\..\\corefx", 6, @"\\.\..\corefx"},
+ { @"\\.\..\.\corefx\.\\", 6, @"\\.\..\corefx\"},
+ { @"\\.\..\corefx", 6, @"\\.\..\corefx"},
+ { @"\\.\..\..\corefx", 6, @"\\.\..\corefx"},
+ { @"\\.\..\corefx\..\", 6, @"\\.\..\"},
+ { @"\\.\..\corefx\..\..\..\", 6, @"\\.\..\"},
+ { @"\\.\..\corefx\..\..\.\", 6, @"\\.\..\"},
+ { @"\\.\..\..\.\corefx\temp\..", 6, @"\\.\..\corefx"},
+ { @"\\.\..\..\\\.\..\corefx", 6, @"\\.\..\corefx"},
+ { @"\\.\..\corefx\", 6, @"\\.\..\corefx\"},
+ { @"\\.\..\temp\..\corefx\", 6, @"\\.\..\corefx\"},
+
+ { @"\\.\\corefx", 4, @"\\.\corefx"},
+ { @"\\.\\corefx", 4, @"\\.\corefx"},
+ { @"\\.\\\corefx", 4, @"\\.\corefx"},
+ { @"\\.\\.\corefx\.\\", 4, @"\\.\corefx\"},
+ { @"\\.\\corefx", 4, @"\\.\corefx"},
+ { @"\\.\\..\corefx", 4, @"\\.\corefx"},
+ { @"\\.\\corefx\..\", 4, @"\\.\"},
+ { @"\\.\\corefx\..\..\..\", 4, @"\\.\"},
+ { @"\\.\\corefx\..\..\.\", 4, @"\\.\"},
+ { @"\\.\\..\.\corefx\temp\..", 4, @"\\.\corefx"},
+ { @"\\.\\..\\\.\..\corefx", 4, @"\\.\corefx"},
+ { @"\\.\\corefx\", 4, @"\\.\corefx\"},
+ { @"\\.\\temp\..\corefx\", 4, @"\\.\corefx\"},
+ };
+
+ public static TheoryData<string, int, string> RemoveRelativeSegmentsDeviceRootData => new TheoryData<string, int, string>
+ {
+ { @"\\.\git\corefx", 8, @"\\.\git\corefx"},
+ { @"\\.\git\corefx", 8, @"\\.\git\corefx"},
+ { @"\\.\git\\corefx", 8, @"\\.\git\corefx"},
+ { @"\\.\git\.\corefx\.\\", 8, @"\\.\git\corefx\"},
+ { @"\\.\git\corefx", 8, @"\\.\git\corefx"},
+ { @"\\.\git\..\corefx", 8, @"\\.\git\corefx"},
+ { @"\\.\git\corefx\..\", 8, @"\\.\git\"},
+ { @"\\.\git\corefx\..\..\..\", 8, @"\\.\git\"},
+ { @"\\.\git\corefx\..\..\.\", 8, @"\\.\git\"},
+ { @"\\.\git\..\.\corefx\temp\..", 8, @"\\.\git\corefx"},
+ { @"\\.\git\..\\\.\..\corefx", 8, @"\\.\git\corefx"},
+ { @"\\.\git\corefx\", 8, @"\\.\git\corefx\"},
+ { @"\\.\git\temp\..\corefx\", 8, @"\\.\git\corefx\"},
+
+ { @"\\.\.\corefx", 6, @"\\.\.\corefx"},
+ { @"\\.\.\corefx", 6, @"\\.\.\corefx"},
+ { @"\\.\.\\corefx", 6, @"\\.\.\corefx"},
+ { @"\\.\.\.\corefx\.\\", 6, @"\\.\.\corefx\"},
+ { @"\\.\.\corefx", 6, @"\\.\.\corefx"},
+ { @"\\.\.\..\corefx", 6, @"\\.\.\corefx"},
+ { @"\\.\.\corefx\..\", 6, @"\\.\.\"},
+ { @"\\.\.\corefx\..\..\..\", 6, @"\\.\.\"},
+ { @"\\.\.\corefx\..\..\.\", 6, @"\\.\.\"},
+ { @"\\.\.\..\.\corefx\temp\..", 6, @"\\.\.\corefx"},
+ { @"\\.\.\..\\\.\..\corefx", 6, @"\\.\.\corefx"},
+ { @"\\.\.\corefx\", 6, @"\\.\.\corefx\"},
+ { @"\\.\.\temp\..\corefx\", 6, @"\\.\.\corefx\"},
+
+ { @"\\.\..\corefx", 7, @"\\.\..\corefx"},
+ { @"\\.\..\corefx", 7, @"\\.\..\corefx"},
+ { @"\\.\..\\corefx", 7, @"\\.\..\corefx"},
+ { @"\\.\..\.\corefx\.\\", 7, @"\\.\..\corefx\"},
+ { @"\\.\..\corefx", 7, @"\\.\..\corefx"},
+ { @"\\.\..\..\corefx", 7, @"\\.\..\corefx"},
+ { @"\\.\..\corefx\..\", 7, @"\\.\..\"},
+ { @"\\.\..\corefx\..\..\..\", 7, @"\\.\..\"},
+ { @"\\.\..\corefx\..\..\.\", 7, @"\\.\..\"},
+ { @"\\.\..\..\.\corefx\temp\..", 7, @"\\.\..\corefx"},
+ { @"\\.\..\..\\\.\..\corefx", 7, @"\\.\..\corefx"},
+ { @"\\.\..\corefx\", 7, @"\\.\..\corefx\"},
+ { @"\\.\..\temp\..\corefx\", 7, @"\\.\..\corefx\"},
+
+ { @"\\.\\corefx", 5, @"\\.\\corefx"},
+ { @"\\.\\corefx", 5, @"\\.\\corefx"},
+ { @"\\.\\\corefx", 5, @"\\.\\corefx"},
+ { @"\\.\\.\corefx\.\\", 5, @"\\.\\corefx\"},
+ { @"\\.\\corefx", 5, @"\\.\\corefx"},
+ { @"\\.\\..\corefx", 5, @"\\.\\corefx"},
+ { @"\\.\\corefx\..\", 5, @"\\.\\"},
+ { @"\\.\\corefx\..\..\..\", 5, @"\\.\\"},
+ { @"\\.\\corefx\..\..\.\", 5, @"\\.\\"},
+ { @"\\.\\..\.\corefx\temp\..", 5, @"\\.\\corefx"},
+ { @"\\.\\..\\\.\..\corefx", 5, @"\\.\\corefx"},
+ { @"\\.\\corefx\", 5, @"\\.\\corefx\"},
+ { @"\\.\\temp\..\corefx\", 5, @"\\.\\corefx\"},
+ };
+
+ [Theory,
+ MemberData(nameof(RemoveRelativeSegmentsDeviceData)),
+ MemberData(nameof(RemoveRelativeSegmentsDeviceRootData))]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void RemoveRelativeSegmentsDeviceTest(string path, int skip, string expected)
+ {
+ Assert.Equal(expected, PathInternal.RemoveRelativeSegments(path, skip));
+ StringBuilder sb = new StringBuilder(expected);
+ sb.Replace('.', '?', 0, 4);
+ expected = sb.ToString();
+
+ sb = new StringBuilder(path);
+ sb.Replace('.', '?', 0, 4);
+ path = sb.ToString();
+ Assert.Equal(expected, PathInternal.RemoveRelativeSegments(path, skip));
+ }
+
+ public static TheoryData<string, int, string> RemoveRelativeSegmentUnixData => new TheoryData<string, int, string>
+ {
+ { "/tmp/home", 1, "/tmp/home" },
+ { "/tmp/..", 1, "/" },
+ { "/tmp/home/../././", 1, "/tmp/" },
+ { "/tmp/../../../", 1, "/" },
+ { "/tmp//home", 1, "/tmp/home" },
+ { "/./tmp//home", 1, "/tmp/home" },
+ { "/../tmp/home", 1, "/tmp/home" },
+ { "/../../../tmp/./home", 1, "/tmp/home" },
+ { "//tmp///home", 1, "/tmp/home" },
+ { "/tmp/home/git/./.././git/corefx/../", 1, "/tmp/home/git/" },
+ { "/./tmp/home", 1, "/tmp/home" },
+
+ { "/tmp/home", 4, "/tmp/home" },
+ { "/tmp/..", 4, "/tmp" },
+ { "/tmp/home/../././", 4, "/tmp/" },
+ { "/tmp/../../../", 4, "/tmp/" },
+ { "/tmp//home", 4, "/tmp/home" },
+ { "/./tmp//home", 2, "/./tmp/home" },
+ { "/../tmp/home", 3, "/../tmp/home" },
+ { "/../../../tmp/./home", 4, "/../tmp/home" },
+ { "//tmp///home", 5, "//tmp/home" },
+ { "/tmp/home/git/./.././git/corefx/../", 5, "/tmp/home/git/" },
+ { "/./tmp/home", 3, "/./tmp/home" },
+
+ { "/tmp/../../", 8, "/tmp/../" },
+ { "/tmp/home/../././", 10, "/tmp/home/" },
+ { "/tmp/../../../", 8, "/tmp/../" },
+ { "/tmp//home/.././/", 11, "/tmp//home/" },
+ { "/./tmp//home/git/git", 7, "/./tmp/home/git/git" },
+ { "/../tmp/./home", 8, "/../tmp/home" },
+ { "/../../../tmp/./home", 8, "/../../../tmp/home" },
+ { "//tmp///home/..", 5, "//tmp/" },
+ { "/tmp/home/git/./.././git/corefx/../", 16, "/tmp/home/git/./git/" },
+ { "/./tmp/home/././", 7, "/./tmp/home/" },
+ };
+
+ [Theory,
+ MemberData(nameof(RemoveRelativeSegmentUnixData))]
+ [PlatformSpecific(TestPlatforms.AnyUnix)]
+ public void RemoveRelativeSegmentsUnix(string path, int skip, string expected)
+ {
+ Assert.Equal(expected, PathInternal.RemoveRelativeSegments(path, skip));
+ }
}
}
diff --git a/src/Common/tests/Tests/System/IO/PathInternal.Unix.Tests.cs b/src/Common/tests/Tests/System/IO/PathInternal.Unix.Tests.cs
new file mode 100644
index 0000000000..31b50266ca
--- /dev/null
+++ b/src/Common/tests/Tests/System/IO/PathInternal.Unix.Tests.cs
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.IO;
+using Xunit;
+
+namespace Tests.System.IO
+{
+ [PlatformSpecific(TestPlatforms.AnyUnix)]
+ public class PathInternalTests_Unix
+ {
+ [Theory,
+ InlineData(@"", @""),
+ InlineData(null, null),
+ InlineData(@"/", @"/"),
+ InlineData(@"//", @"/"),
+ InlineData(@"///", @"/"),
+ InlineData(@"\", @"\"),
+ InlineData(@"\\", @"\\"),
+ InlineData(@"\\\", @"\\\"),
+ InlineData(@"\/", @"\/"),
+ InlineData(@"\/\", @"\/\"),
+
+ InlineData(@"a/a", @"a/a"),
+ InlineData(@"a//a", @"a/a"),
+ InlineData(@"a\\a", @"a\\a"),
+ InlineData(@"/a", @"/a"),
+ InlineData(@"//a", @"/a"),
+ InlineData(@"\\a", @"\\a"),
+ InlineData(@"a/", @"a/"),
+ InlineData(@"a//", @"a/"),
+ InlineData(@"a\\", @"a\\"),
+ ]
+ [PlatformSpecific(TestPlatforms.AnyUnix)]
+ public void NormalizeDirectorySeparatorTests(string path, string expected)
+ {
+ string result = PathInternal.NormalizeDirectorySeparators(path);
+ Assert.Equal(expected, result);
+ if (string.Equals(path, expected, StringComparison.Ordinal))
+ Assert.Same(path, result);
+ }
+
+ [Fact]
+ [PlatformSpecific(TestPlatforms.OSX)]
+ public void IsCaseInsensitive_OSX()
+ {
+ // There have been reports of casing handling not being appropriate on MacOS
+ // https://github.com/dotnet/corefx/issues/26797
+ Assert.False(PathInternal.IsCaseSensitive);
+ }
+ }
+}
diff --git a/src/Common/tests/Tests/System/IO/PathInternal.Windows.Tests.cs b/src/Common/tests/Tests/System/IO/PathInternal.Windows.Tests.cs
index 799dfc8d89..87609e92e8 100644
--- a/src/Common/tests/Tests/System/IO/PathInternal.Windows.Tests.cs
+++ b/src/Common/tests/Tests/System/IO/PathInternal.Windows.Tests.cs
@@ -4,179 +4,259 @@
using System;
using System.IO;
-using System.Runtime.InteropServices;
using Xunit;
-public class PathInternal_Windows_Tests
+namespace Tests.System.IO
{
- [Theory,
- InlineData(@"\\?\", false),
- InlineData(@"\\?\?", true),
- InlineData(@"//?/", false),
- InlineData(@"//?/*", true),
- InlineData(@"\\.\>", true),
- InlineData(@"C:\", false),
- InlineData(@"C:\<", true),
- InlineData("\"MyFile\"", true)
- ]
[PlatformSpecific(TestPlatforms.Windows)]
- public void HasWildcardCharacters(string path, bool expected)
+ public class PathInternalTests_Windows
{
- Assert.Equal(expected, PathInternal.HasWildCardCharacters(path));
- }
+ [Theory,
+ InlineData(@"\\?\", @"\\?\"),
+ InlineData(@"Foo", @"Foo"),
+ InlineData(@"C:\Foo", @"\\?\C:\Foo"),
+ InlineData(@"\\.\Foo", @"\\.\Foo"),
+ InlineData(@"\\?\Foo", @"\\?\Foo"),
+ InlineData(@"\??\Foo", @"\??\Foo"),
+ InlineData(@"//?/Foo", @"//?/Foo"),
+ InlineData(@"\\Server\Share", PathInternal.UncExtendedPathPrefix + @"Server\Share")
+ ]
+ public void EnsureExtendedPrefixTest(string path, string expected)
+ {
+ Assert.Equal(expected, PathInternal.EnsureExtendedPrefix(path));
+ }
- [Theory,
- InlineData(PathInternal.ExtendedPathPrefix, PathInternal.ExtendedPathPrefix),
- InlineData(@"Foo", @"Foo"),
- InlineData(@"C:\Foo", @"\\?\C:\Foo"),
- InlineData(@"\\.\Foo", @"\\.\Foo"),
- InlineData(@"\\?\Foo", @"\\?\Foo"),
- InlineData(@"\??\Foo", @"\??\Foo"),
- InlineData(@"//?/Foo", @"//?/Foo"),
- InlineData(@"\\Server\Share", PathInternal.UncExtendedPathPrefix + @"Server\Share")
- ]
- [PlatformSpecific(TestPlatforms.Windows)]
- public void EnsureExtendedPrefixTest(string path, string expected)
- {
- Assert.Equal(expected, PathInternal.EnsureExtendedPrefix(path));
- }
+ [Theory,
+ InlineData(@"", false),
+ InlineData(@"\\?\", true),
+ InlineData(@"\??\", true),
+ InlineData(@"\\.\", false),
+ InlineData(@"\\?", false),
+ InlineData(@"\??", false),
+ InlineData(@"//?/", false),
+ InlineData(@"/??/", false)
+ ]
+ public void IsExtendedTest(string path, bool expected)
+ {
+ Assert.Equal(expected, PathInternal.IsExtended(path));
+ }
- [Theory,
- InlineData(@"", false),
- InlineData(@"\\?\", true),
- InlineData(@"\??\", true),
- InlineData(@"\\.\", false),
- InlineData(@"\\?", false),
- InlineData(@"\??", false),
- InlineData(@"//?/", false),
- InlineData(@"/??/", false)
- ]
- [PlatformSpecific(TestPlatforms.Windows)]
- public void IsExtendedTest(string path, bool expected)
- {
- Assert.Equal(expected, PathInternal.IsExtended(path));
- }
+ [Theory,
+ InlineData(@"", false),
+ InlineData(@"\\?\", true),
+ InlineData(@"\??\", true),
+ InlineData(@"\\.\", true),
+ InlineData(@"\\?", false),
+ InlineData(@"\??", false),
+ InlineData(@"//?/", true),
+ InlineData(@"/??/", false)
+ ]
+ public void IsDeviceTest(string path, bool expected)
+ {
+ Assert.Equal(expected, PathInternal.IsDevice(path));
+ }
- [Theory,
- InlineData(@"", false),
- InlineData(@"\\?\", true),
- InlineData(@"\??\", true),
- InlineData(@"\\.\", true),
- InlineData(@"\\?", false),
- InlineData(@"\??", false),
- InlineData(@"//?/", true),
- InlineData(@"/??/", false)
- ]
- [PlatformSpecific(TestPlatforms.Windows)]
- public void IsDeviceTest(string path, bool expected)
- {
- Assert.Equal(expected, PathInternal.IsDevice(path));
- }
+ [Theory,
+ InlineData("", true),
+ InlineData("C:", true),
+ InlineData("**", true),
+ InlineData(@"\\.\path", false),
+ InlineData(@"\\?\path", false),
+ InlineData(@"\\.", false),
+ InlineData(@"\\?", false),
+ InlineData(@"\?", false),
+ InlineData(@"/?", false),
+ InlineData(@"\\", false),
+ InlineData(@"//", false),
+ InlineData(@"\a", true),
+ InlineData(@"/a", true),
+ InlineData(@"\", true),
+ InlineData(@"/", true),
+ InlineData(@"C:Path", true),
+ InlineData(@"C:\Path", false),
+ InlineData(@"\\?\C:\Path", false),
+ InlineData(@"Path", true),
+ InlineData(@"X", true)
+ ]
+ public void IsPartiallyQualifiedTest(string path, bool expected)
+ {
+ Assert.Equal(expected, PathInternal.IsPartiallyQualified(path));
+ }
- [Theory,
- InlineData("", true),
- InlineData("C:", true),
- InlineData("**", true),
- InlineData(@"\\.\path", false),
- InlineData(@"\\?\path", false),
- InlineData(@"\\.", false),
- InlineData(@"\\?", false),
- InlineData(@"\?", false),
- InlineData(@"/?", false),
- InlineData(@"\\", false),
- InlineData(@"//", false),
- InlineData(@"\a", true),
- InlineData(@"/a", true),
- InlineData(@"\", true),
- InlineData(@"/", true),
- InlineData(@"C:Path", true),
- InlineData(@"C:\Path", false),
- InlineData(@"\\?\C:\Path", false),
- InlineData(@"Path", true),
- InlineData(@"X", true)
- ]
- [PlatformSpecific(TestPlatforms.Windows)]
- public void IsPartiallyQualifiedTest(string path, bool expected)
- {
- Assert.Equal(expected, PathInternal.IsPartiallyQualified(path));
- }
+ [Theory,
+ InlineData(@"", @""),
+ InlineData(null, null),
+ InlineData(@"\", @"\"),
+ InlineData(@"/", @"\"),
+ InlineData(@"\\", @"\\"),
+ InlineData(@"\\\", @"\\"),
+ InlineData(@"//", @"\\"),
+ InlineData(@"///", @"\\"),
+ InlineData(@"\/", @"\\"),
+ InlineData(@"\/\", @"\\"),
- [Theory,
- InlineData(@"", 0),
- InlineData(@" :", 0),
- InlineData(@" C:", 2),
- InlineData(@" C:\", 3),
- InlineData(@"C:\", 0),
- InlineData(@" ", 0),
- InlineData(@" \", 2),
- InlineData(@" 8:", 0),
- InlineData(@" \\", 4),
- InlineData(@"\\", 0)
- ]
- [PlatformSpecific(TestPlatforms.Windows)]
- public void PathStartSkipTest(string path, int expected)
- {
- Assert.Equal(expected, PathInternal.PathStartSkip(path));
- }
+ InlineData(@"a\a", @"a\a"),
+ InlineData(@"a\\a", @"a\a"),
+ InlineData(@"a/a", @"a\a"),
+ InlineData(@"a//a", @"a\a"),
+ InlineData(@"a\", @"a\"),
+ InlineData(@"a\\", @"a\"),
+ InlineData(@"a/", @"a\"),
+ InlineData(@"a//", @"a\"),
+ InlineData(@"\a", @"\a"),
+ InlineData(@"\\a", @"\\a"),
+ InlineData(@"/a", @"\a"),
+ InlineData(@"//a", @"\\a"),
- [Theory,
- InlineData(@"", @""),
- InlineData(null, null),
- InlineData(@"\", @"\"),
- InlineData(@"/", @"\"),
- InlineData(@"\\", @"\\"),
- InlineData(@"\\\", @"\\"),
- InlineData(@"//", @"\\"),
- InlineData(@"///", @"\\"),
- InlineData(@"\/", @"\\"),
- InlineData(@"\/\", @"\\"),
-
- InlineData(@"a\a", @"a\a"),
- InlineData(@"a\\a", @"a\a"),
- InlineData(@"a/a", @"a\a"),
- InlineData(@"a//a", @"a\a"),
- InlineData(@"a\", @"a\"),
- InlineData(@"a\\", @"a\"),
- InlineData(@"a/", @"a\"),
- InlineData(@"a//", @"a\"),
- InlineData(@"\a", @"\a"),
- InlineData(@"\\a", @"\\a"),
- InlineData(@"/a", @"\a"),
- InlineData(@"//a", @"\\a"),
-
- // Skip tests
- InlineData(@" :", @" :"),
- InlineData(@" C:", @"C:"),
- InlineData(@" C:\", @"C:\"),
- InlineData(@" C:/", @"C:\"),
- InlineData(@" ", @" "),
- InlineData(@" \", @"\"),
- InlineData(@" /", @"\"),
- InlineData(@" 8:", @" 8:"),
- InlineData(@" \\", @"\\"),
- InlineData(@" //", @"\\")
- ]
- [PlatformSpecific(TestPlatforms.Windows)]
- public void NormalizeDirectorySeparatorTests(string path, string expected)
- {
- string result = PathInternal.NormalizeDirectorySeparators(path);
- Assert.Equal(expected, result);
- if (string.Equals(path, expected, StringComparison.Ordinal))
- Assert.Same(path, result);
- }
-
- [Theory,
- InlineData(@"", @"", StringComparison.OrdinalIgnoreCase, true),
- InlineData(@"", @"", StringComparison.Ordinal, true),
- InlineData(@"A", @"a", StringComparison.OrdinalIgnoreCase, true),
- InlineData(@"A", @"a", StringComparison.Ordinal, true),
- InlineData(@"C:\", @"c:\", StringComparison.OrdinalIgnoreCase, true),
- InlineData(@"C:\", @"c:\", StringComparison.Ordinal, false)
- ]
- [PlatformSpecific(TestPlatforms.Windows)]
- public void AreRootsEqual(string first, string second, StringComparison comparisonType, bool expected)
- {
- Assert.Equal(expected, PathInternal.AreRootsEqual(first, second, comparisonType));
- }
+ // Skip tests
+ InlineData(@" :", @" :"),
+ InlineData(@" C:", @" C:"),
+ InlineData(@"C:\", @"C:\"),
+ InlineData(@"C:/", @"C:\"),
+ InlineData(@" ", @" "),
+ InlineData(@" \", @" \"),
+ InlineData(@" /", @" \"),
+ InlineData(@" 8:", @" 8:"),
+ InlineData(@" \\", @" \"),
+ InlineData(@" //", @" \")
+ ]
+ public void NormalizeDirectorySeparatorTests(string path, string expected)
+ {
+ string result = PathInternal.NormalizeDirectorySeparators(path);
+ Assert.Equal(expected, result);
+ if (string.Equals(path, expected, StringComparison.Ordinal))
+ Assert.Same(path, result);
+ }
+
+ [Theory,
+ InlineData(@"", @"", StringComparison.OrdinalIgnoreCase, true),
+ InlineData(@"", @"", StringComparison.Ordinal, true),
+ InlineData(@"A", @"a", StringComparison.OrdinalIgnoreCase, true),
+ InlineData(@"A", @"a", StringComparison.Ordinal, true),
+ InlineData(@"C:\", @"c:\", StringComparison.OrdinalIgnoreCase, true),
+ InlineData(@"C:\", @"c:\", StringComparison.Ordinal, false)
+ ]
+ public void AreRootsEqual(string first, string second, StringComparison comparisonType, bool expected)
+ {
+ Assert.Equal(expected, PathInternal.AreRootsEqual(first, second, comparisonType));
+ }
+
+ public static TheoryData<string, int, int> GetRootLength_Data => new TheoryData<string, int, int>
+ {
+ { @"C:\git\corefx", 3, 7 },
+ { @"C:\git\.\", 3, 7 },
+ { @"C:\git\..\", 3, 7 },
+ { @"C:\git\..\..\", 3, 7 },
+ { @"C:\..\", 3, 7 },
+ { @"C:\", 3, 7 },
+ { @"C:\\", 3, 7 },
+
+ // With drive relative paths, the length changes with device syntax. There is no
+ // concept of non-resolved "\\?\" paths. "\\?\C:git\" is not rooted at "\\?\C:",
+ // it is rooted at "\\?\C:git\". While "\\.\" paths are resolved by Win32 (via
+ // GetFullPathName), they also are not recognized as drive relative. Rather than
+ // muddy the waters we'll consider the full segment as the root volume there
+ // as well, even though GetFullPathName would eat to the prefix. We don't want
+ // a conceptual model where device paths can resolve themselves out of the "volume".
+ { @"C:", 2, 6},
+ { @"C:git\", 2, 10},
+ { @"C:git\\", 2, 10},
+ { @"C:git", 2, 9},
+ { @"C:git\corefx", 2, 10},
+ { @"C:git\.\", 2, 10},
+ { @"C:git\\.\", 2, 10},
+ { @"C:git\..\", 2, 10},
+ { @"C:..\", 2, 9},
+ };
+ public static TheoryData<string, int> GetRootLengthRooted => new TheoryData<string, int>
+ {
+ { @"\tmp", 1},
+ { @"\.", 1},
+ { @"\..", 1},
+ { @"\tmp\..\..", 1},
+ { @"\\", 2},
+ };
+
+ [Theory,
+ MemberData(nameof(GetRootLength_Data))]
+ public void GetRootLength(string path, int length, int deviceLength)
+ {
+ Assert.Equal(length, PathInternal.GetRootLength(path));
+ Assert.Equal(deviceLength, PathInternal.GetRootLength(@"\\?\" + path));
+ Assert.Equal(deviceLength, PathInternal.GetRootLength(@"\\.\" + path));
+ }
+
+ [Theory,
+ MemberData(nameof(GetRootLengthRooted))]
+ public void GetRootLength_Rooted(string path, int length)
+ {
+ Assert.Equal(length, PathInternal.GetRootLength(path));
+ }
+
+ public static TheoryData<string, int> GetRootLength_UNCData => new TheoryData<string, int>
+ {
+ // Historically we've never included the separator after a UNC with GetPathRoot()
+ // We'll continue to do so.
+ { @"a\b\git\corefx", 3},
+ { @"Server\Share\git\corefx", 12},
+ { @"Server\Share\git\.\", 12},
+ { @"Server\Share\git\..\", 12},
+ { @"Server\Share\git\..\..\", 12},
+ { @"Server\Share\..\", 12},
+ { @"Server\Share\", 12},
+ { @"Server\Share\\", 12},
+ { @"Server\Share", 12},
+ { @"Server\Share\", 12},
+ { @"Server\Share\\git", 12},
+
+ // Degenerate paths.
+ //
+ // We expect paths to be well formed up to the root. If you have "\\Server\\Share"
+ // instead of "\\Server\Share", all bets are off. We'll test them here to make
+ // sure we don't choke.
+ { @"\a\b\git\corefx", 2},
+ { @"a\\b\git\corefx", 2},
+ };
+
+ [Theory,
+ MemberData(nameof(GetRootLength_UNCData))]
+ public void GetRootLengthUnc(string path, int length)
+ {
+ Assert.Equal(length + 2, PathInternal.GetRootLength(@"\\" + path));
+ Assert.Equal(length + PathInternal.UncExtendedPrefixLength, PathInternal.GetRootLength(@"\\?\UNC\" + path));
+ Assert.Equal(length + PathInternal.UncExtendedPrefixLength, PathInternal.GetRootLength(@"\\.\UNC\" + path));
+ }
+
+ public static TheoryData<string, int> GetRootLength_DeviceData => new TheoryData<string, int>
+ {
+ { @"..\", 3},
+ { @"..\..\", 3},
+ { @"..\.\", 3},
+ { @"...\", 4},
+ { @".\", 2},
+ { @".\..\", 2},
+ { @"..\", 3},
+ { @"\.\", 0},
+ { @"\..\", 0},
+ { @"\\..", 0},
+ { @"foo\..", 4},
+ { @".", 1},
+ { @"..", 2},
+ { @"foo", 3},
+ { @"foo\", 4},
+ { @"foo\\", 4},
+ { @"..\foo", 3},
+ { @"\\\.\", 0},
+ { @"\\.\", 0},
+ };
+
+ [Theory,
+ MemberData(nameof(GetRootLength_DeviceData))]
+ public void GetRootLengthDevice(string path, int length)
+ {
+ Assert.Equal(length + PathInternal.ExtendedPathPrefix.Length, PathInternal.GetRootLength(@"\\?\" + path));
+ Assert.Equal(length + PathInternal.ExtendedPathPrefix.Length, PathInternal.GetRootLength(@"\\.\" + path));
+ }
+ }
}
diff --git a/src/Common/tests/Tests/System/IO/PathInternal_Unix_Tests.cs b/src/Common/tests/Tests/System/IO/PathInternal_Unix_Tests.cs
deleted file mode 100644
index 5eac9168c3..0000000000
--- a/src/Common/tests/Tests/System/IO/PathInternal_Unix_Tests.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.IO;
-using System.Text;
-using Xunit;
-
-public class PathInternal_Unix_Tests
-{
- [Theory,
- InlineData(@"", @""),
- InlineData(null, null),
- InlineData(@"/", @"/"),
- InlineData(@"//", @"/"),
- InlineData(@"///", @"/"),
- InlineData(@"\", @"\"),
- InlineData(@"\\", @"\\"),
- InlineData(@"\\\", @"\\\"),
- InlineData(@"\/", @"\/"),
- InlineData(@"\/\", @"\/\"),
-
- InlineData(@"a/a", @"a/a"),
- InlineData(@"a//a", @"a/a"),
- InlineData(@"a\\a", @"a\\a"),
- InlineData(@"/a", @"/a"),
- InlineData(@"//a", @"/a"),
- InlineData(@"\\a", @"\\a"),
- InlineData(@"a/", @"a/"),
- InlineData(@"a//", @"a/"),
- InlineData(@"a\\", @"a\\"),
- ]
- [PlatformSpecific(TestPlatforms.AnyUnix)]
- public void NormalizeDirectorySeparatorTests(string path, string expected)
- {
- string result = PathInternal.NormalizeDirectorySeparators(path);
- Assert.Equal(expected, result);
- if (string.Equals(path, expected, StringComparison.Ordinal))
- Assert.Same(path, result);
- }
-}
diff --git a/src/Common/tests/Tests/System/PasteArgumentsTests.cs b/src/Common/tests/Tests/System/PasteArgumentsTests.cs
new file mode 100644
index 0000000000..592455ffb5
--- /dev/null
+++ b/src/Common/tests/Tests/System/PasteArgumentsTests.cs
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+using Xunit;
+
+namespace Tests.System
+{
+ public class PasteArgumentsTests
+ {
+ [Theory]
+ [InlineData(@"app.exe arg1 arg2", new[] {"app.exe", "arg1", "arg2"})]
+ [InlineData(@"""app name.exe"" arg1 arg2", new[] {"app name.exe", "arg1", "arg2"})]
+ [InlineData(@"app.exe \\ arg2", new[] {"app.exe", @"\\", "arg2"})]
+ [InlineData(@"app.exe ""\"""" arg2", new[] {"app.exe", @"""", "arg2"})] // literal double quotation mark character
+ [InlineData(@"app.exe ""\\\"""" arg2", new[] {"app.exe", @"\""", "arg2"})] // 2N+1 backslashes before quote rule
+ [InlineData(@"app.exe ""\\\\\"""" arg2", new[] {"app.exe", @"\\""", "arg2"})] // 2N backslashes before quote rule
+ public void Pastes(string pasteExpected, string[] arguments)
+ {
+ Assert.Equal(pasteExpected, PasteArguments.Paste(arguments, pasteFirstArgumentUsingArgV0Rules: true));
+ }
+
+ [Theory]
+ [InlineData(@"""dir/app\""name.exe""", new[] {@"dir/app""name.exe"})] // no throwing on quotes, escaping quotes
+ [InlineData(@"""dir/app\\\""name.exe""", new[] {@"dir/app\""name.exe"})] // escaping a backslash
+ [InlineData(@"""dir/app\\\\\""name.exe""", new[] {@"dir/app\\""name.exe"})] // escaping backslashes
+ [PlatformSpecific(TestPlatforms.AnyUnix)]
+ public void Paste_Argv0Rules_Ignored_onUnix(string pasteExpected, string[] arguments)
+ {
+ Assert.Equal(pasteExpected, PasteArguments.Paste(arguments, pasteFirstArgumentUsingArgV0Rules: true));
+ }
+
+ [Theory]
+ [InlineData(@"dir/app""name.exe")] // throws
+ [InlineData(@"dir/app\""name.exe")] // throws and ignores a backslash
+ [InlineData(@"dir/app\\""name.exe")] // throws and ignores backslashes
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void Paste_Argv0Rules_ThrowsIfQuotes_OnWindows(string argv0)
+ {
+ Assert.Throws<ApplicationException>(() => PasteArguments.Paste(new []{argv0}, pasteFirstArgumentUsingArgV0Rules: true));
+ }
+ }
+}
diff --git a/src/Common/tests/Tests/System/Text/ValueStringBuilderTests.cs b/src/Common/tests/Tests/System/Text/ValueStringBuilderTests.cs
index d7878e8f55..e5155e540a 100644
--- a/src/Common/tests/Tests/System/Text/ValueStringBuilderTests.cs
+++ b/src/Common/tests/Tests/System/Text/ValueStringBuilderTests.cs
@@ -127,7 +127,7 @@ namespace System.Text.Tests
Span<char> span = vsb.AppendSpan(s.Length);
Assert.Equal(sb.Length, vsb.Length);
- s.AsReadOnlySpan().CopyTo(span);
+ s.AsSpan().CopyTo(span);
}
Assert.Equal(sb.Length, vsb.Length);
@@ -214,31 +214,16 @@ namespace System.Text.Tests
}
[Fact]
- public unsafe void Length_Growing_SetsNulls()
+ public unsafe void Indexer()
{
const string Text1 = "foobar";
var vsb = new ValueStringBuilder();
- // Shrink then grow within capacity
vsb.Append(Text1);
- Assert.Equal(Text1.Length, vsb.Length);
- vsb.Length = 3;
- Assert.Equal(3, vsb.Length);
- vsb.Length = 6;
- Assert.Equal(6, vsb.Length);
- Assert.Equal("foo\0\0\0", vsb.ToString());
-
- // Grow over capacity
- const string Text2 = "bar";
- Span<char> stackSpace = stackalloc char[Text2.Length];
- var vsb2 = new ValueStringBuilder(stackSpace);
- Assert.Equal(0, vsb2.Length);
- vsb2.Append(Text2);
- Assert.True(Text2.AsReadOnlySpan().SequenceEqual(stackSpace), "existing stack buffer should have been used");
- Assert.Equal(Text2.Length, vsb2.Length);
- vsb2.Length = 6;
- Assert.Equal(6, vsb2.Length);
- Assert.Equal("bar\0\0\0", vsb2.ToString());
+
+ Assert.Equal(vsb[3], 'b');
+ vsb[3] = 'c';
+ Assert.Equal(vsb[3], 'c');
}
}
}
diff --git a/src/CoreFx.Private.TestUtilities/dir.props b/src/CoreFx.Private.TestUtilities/dir.props
index 04794ecf65..6a80fe26a1 100644
--- a/src/CoreFx.Private.TestUtilities/dir.props
+++ b/src/CoreFx.Private.TestUtilities/dir.props
@@ -4,5 +4,7 @@
<PropertyGroup>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<AssemblyKey>Test</AssemblyKey>
+ <!-- DO NOT ship this as stable for .NET Core 2.0. -->
+ <BlockStable>true</BlockStable>
</PropertyGroup>
</Project> \ No newline at end of file
diff --git a/src/CoreFx.Private.TestUtilities/pkg/CoreFx.Private.TestUtilities.pkgproj b/src/CoreFx.Private.TestUtilities/pkg/CoreFx.Private.TestUtilities.pkgproj
new file mode 100644
index 0000000000..2f9f2405ba
--- /dev/null
+++ b/src/CoreFx.Private.TestUtilities/pkg/CoreFx.Private.TestUtilities.pkgproj
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <ItemGroup>
+ <ProjectReference Include="..\ref\CoreFx.Private.TestUtilities.csproj">
+ <SupportedFramework>uap10.0.16299;netcoreapp2.0;net461;$(AllXamarinFrameworks)</SupportedFramework>
+ </ProjectReference>
+ <ProjectReference Include="..\src\CoreFx.Private.TestUtilities.csproj"/>
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/src/CoreFx.Private.TestUtilities/ref/CoreFx.Private.TestUtilities.cs b/src/CoreFx.Private.TestUtilities/ref/CoreFx.Private.TestUtilities.cs
index 36e3c2430e..8ec7c9555a 100644
--- a/src/CoreFx.Private.TestUtilities/ref/CoreFx.Private.TestUtilities.cs
+++ b/src/CoreFx.Private.TestUtilities/ref/CoreFx.Private.TestUtilities.cs
@@ -42,6 +42,7 @@ namespace System
public static bool ClientWebSocketPartialMessagesSupported { get { throw null; } }
public static bool HasWindowsShell { get { throw null; } }
public static bool IsArmProcess { get { throw null; } }
+ public static bool IsAlpine { get { throw null; } }
public static bool IsCentos6 { get { throw null; } }
public static bool IsDebian { get { throw null; } }
public static bool IsDebian8 { get { throw null; } }
@@ -87,6 +88,8 @@ namespace System
public static bool IsUbuntu1604 { get { throw null; } }
public static bool IsUbuntu1704 { get { throw null; } }
public static bool IsUbuntu1710 { get { throw null; } }
+ public static bool IsUbuntu1710OrHigher { get { throw null; } }
+ public static bool IsUbuntu1804 { get { throw null; } }
public static bool IsWindows { get { throw null; } }
public static bool IsWindows10Version1607OrGreater { get { throw null; } } // >= Windows 10 Anniversary Update
public static bool IsWindows10Version1703OrGreater { get { throw null; } } // >= Windows 10 Creators Update
@@ -101,6 +104,8 @@ namespace System
public static bool IsInAppContainer { get { throw null; } }
public static bool IsWinRTSupported { get { throw null; } }
public static bool IsXmlDsigXsltTransformSupported { get { throw null; } }
+ public static string LibcRelease { get { throw null; } }
+ public static string LibcVersion { get { throw null; } }
public static System.Version OSXVersion { get { throw null; } }
public static int WindowsVersion { get { throw null; } }
public static string GetDistroVersionString() { throw null; }
@@ -112,6 +117,10 @@ namespace System
[CLSCompliant(false)]
public static Xunit.TheoryData ToTheoryData<T>(this System.Collections.Generic.IEnumerable<T> data) { throw null; }
}
+ public static partial class TestEnvironment
+ {
+ public static bool IsStressModeEnabled { get { throw null; } }
+ }
}
namespace System.Diagnostics
{
@@ -132,12 +141,14 @@ namespace System.Diagnostics
public static System.Diagnostics.RemoteExecutorTestBase.RemoteInvokeHandle RemoteInvoke(System.Func<string, string, string, string, string, int> method, string arg1, string arg2, string arg3, string arg4, string arg5, System.Diagnostics.RemoteInvokeOptions options = null) { throw null; }
public static System.Diagnostics.RemoteExecutorTestBase.RemoteInvokeHandle RemoteInvoke(System.Func<System.Threading.Tasks.Task<int>> method, System.Diagnostics.RemoteInvokeOptions options = null) { throw null; }
public static System.Diagnostics.RemoteExecutorTestBase.RemoteInvokeHandle RemoteInvoke(System.Func<string, System.Threading.Tasks.Task<int>> method, string arg, System.Diagnostics.RemoteInvokeOptions options = null) { throw null; }
+ public static System.Diagnostics.RemoteExecutorTestBase.RemoteInvokeHandle RemoteInvoke(System.Func<string, string, System.Threading.Tasks.Task<int>> method, string arg1, string arg2, System.Diagnostics.RemoteInvokeOptions options = null) { throw null; }
public static System.Diagnostics.RemoteExecutorTestBase.RemoteInvokeHandle RemoteInvokeRaw(System.Delegate method, string unparsedArg, System.Diagnostics.RemoteInvokeOptions options = null) { throw null; }
public sealed partial class RemoteInvokeHandle : System.IDisposable
{
- public RemoteInvokeHandle(System.Diagnostics.Process process, System.Diagnostics.RemoteInvokeOptions options) { }
+ public RemoteInvokeHandle(System.Diagnostics.Process process, System.Diagnostics.RemoteInvokeOptions options, string assemblyName, string className, string methodName) { }
+ public int ExitCode { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public System.Diagnostics.RemoteInvokeOptions Options { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
- public System.Diagnostics.Process Process { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
+ public System.Diagnostics.Process Process { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public void Dispose() { }
}
}
@@ -149,6 +160,7 @@ namespace System.Diagnostics
public string ExceptionFile { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public int ExpectedExitCode { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public bool Start { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
+ public bool RunAsSudo { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public System.Diagnostics.ProcessStartInfo StartInfo { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public int TimeOut { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
}
diff --git a/src/CoreFx.Private.TestUtilities/src/Configurations.props b/src/CoreFx.Private.TestUtilities/src/Configurations.props
index c25540e032..44eaf2eca4 100644
--- a/src/CoreFx.Private.TestUtilities/src/Configurations.props
+++ b/src/CoreFx.Private.TestUtilities/src/Configurations.props
@@ -2,11 +2,14 @@
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildConfigurations>
+ netstandard;
uapaot-Windows_NT;
uap-Windows_NT;
netfx-Windows_NT;
netcoreapp-Windows_NT;
netcoreapp-Unix;
+ netcoreapp2.0-Windows_NT;
+ netcoreapp2.0-Unix;
</BuildConfigurations>
</PropertyGroup>
</Project> \ No newline at end of file
diff --git a/src/CoreFx.Private.TestUtilities/src/CoreFx.Private.TestUtilities.csproj b/src/CoreFx.Private.TestUtilities/src/CoreFx.Private.TestUtilities.csproj
index 038d20d89c..01906227b1 100644
--- a/src/CoreFx.Private.TestUtilities/src/CoreFx.Private.TestUtilities.csproj
+++ b/src/CoreFx.Private.TestUtilities/src/CoreFx.Private.TestUtilities.csproj
@@ -9,23 +9,32 @@
<ShouldWriteSigningRequired>false</ShouldWriteSigningRequired>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<EnablePInvokeAnalyzer>false</EnablePInvokeAnalyzer>
- </PropertyGroup>
+ <NoWarn Condition="'$(TargetGroup)' == 'netstandard'">$(NoWarn);CS3021</NoWarn>
+ <GeneratePlatformNotSupportedAssemblyMessage Condition="'$(TargetGroup)' == 'netstandard'">Test Utilities are not supported on this platform</GeneratePlatformNotSupportedAssemblyMessage>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Unix-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Unix-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uapaot-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uapaot-Windows_NT-Release|AnyCPU'" />
- <ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)' != 'netstandard'">
<Compile Include="System\AdminHelpers.cs" />
<Compile Include="System\IO\FileCleanupTestBase.cs" />
<Compile Include="System\Diagnostics\RemoteExecutorTestBase.cs" />
<Compile Include="System\Net\PlatformDetection.Networking.cs" />
- <Compile Condition="'$(TargetGroup)' == 'netcoreapp'" Include="System\Diagnostics\RemoteExecutorTestBase.netcore.cs" />
+ <Compile Include="System\TestEnvironment.cs" />
+ <Compile Condition="'$(TargetGroup)' == 'netcoreapp' OR '$(TargetGroup)' == 'netcoreapp2.0'" Include="System\Diagnostics\RemoteExecutorTestBase.netcore.cs" />
<Compile Condition="'$(TargetGroup)' == 'netfx'" Include="System\Diagnostics\RemoteExecutorTestBase.netfx.cs" />
<Compile Condition="'$(TargetGroup)' != 'uap'" Include="System\Diagnostics\RemoteExecutorTestBase.Process.cs" />
<Compile Condition="'$(TargetGroup)' == 'uap'" Include="System\Diagnostics\RemoteExecutorTestBase.uap.cs" />
@@ -70,6 +79,9 @@
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.GetCurrentProcess_IntPtr.cs">
<Link>Common\Interop\Windows\kernel32\Interop.GetCurrentProcess_IntPtr.cs</Link>
</Compile>
+ <Compile Include="..\..\Common\src\System\PasteArguments.Windows.cs">
+ <Link>Common\System\PasteArguments.Windows.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\Interop\Windows\advapi32\Interop.OpenProcessToken_SafeAccessTokenHandle.cs">
<Link>Common\Interop\Windows\advapi32\Interop.OpenProcessToken_SafeAccessTokenHandle.cs</Link>
</Compile>
@@ -97,6 +109,9 @@
<Compile Include="$(CommonPath)\Interop\Unix\System.Security.Cryptography.Native\Interop.OpenSslVersion.cs">
<Link>Common\Interop\Unix\System.Security.Cryptography.Native\Interop.OpenSslVersion.cs</Link>
</Compile>
+ <Compile Include="..\..\Common\src\System\PasteArguments.Unix.cs">
+ <Link>Common\System\PasteArguments.Unix.cs</Link>
+ </Compile>
<Compile Include="System\AdminHelpers.Unix.cs" />
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.GetEUid.cs">
<Link>Common\Interop\Unix\Interop.GetEUid.cs</Link>
@@ -115,7 +130,7 @@
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
- <ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)' != 'netstandard'">
<EmbeddedResource Include="Resources\$(AssemblyName).rd.xml" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
diff --git a/src/CoreFx.Private.TestUtilities/src/System/Diagnostics/RemoteExecutorTestBase.Process.cs b/src/CoreFx.Private.TestUtilities/src/System/Diagnostics/RemoteExecutorTestBase.Process.cs
index 0e3bc9fa38..c608daafe4 100644
--- a/src/CoreFx.Private.TestUtilities/src/System/Diagnostics/RemoteExecutorTestBase.Process.cs
+++ b/src/CoreFx.Private.TestUtilities/src/System/Diagnostics/RemoteExecutorTestBase.Process.cs
@@ -58,13 +58,23 @@ namespace System.Diagnostics
if (!File.Exists(HostRunner))
throw new IOException($"{HostRunner} test app isn't present in the test runtime directory.");
- psi.FileName = HostRunner;
- psi.Arguments = testConsoleAppArgs;
+ if (options.RunAsSudo)
+ {
+ psi.FileName = "sudo";
+ psi.Arguments = HostRunner + " " + testConsoleAppArgs;
+ }
+ else
+ {
+ psi.FileName = HostRunner;
+ psi.Arguments = testConsoleAppArgs;
+ }
// Return the handle to the process, which may or not be started
return new RemoteInvokeHandle(options.Start ?
Process.Start(psi) :
- new Process() { StartInfo = psi }, options);
+ new Process() { StartInfo = psi }, options,
+ a.FullName, t.FullName, method.Name
+ );
}
}
}
diff --git a/src/CoreFx.Private.TestUtilities/src/System/Diagnostics/RemoteExecutorTestBase.cs b/src/CoreFx.Private.TestUtilities/src/System/Diagnostics/RemoteExecutorTestBase.cs
index b70b606df2..ac039bd592 100644
--- a/src/CoreFx.Private.TestUtilities/src/System/Diagnostics/RemoteExecutorTestBase.cs
+++ b/src/CoreFx.Private.TestUtilities/src/System/Diagnostics/RemoteExecutorTestBase.cs
@@ -40,7 +40,7 @@ namespace System.Diagnostics
/// <param name="method">The method to invoke.</param>
/// <param name="options">Options to use for the invocation.</param>
public static RemoteInvokeHandle RemoteInvoke(
- Func<int> method,
+ Func<int> method,
RemoteInvokeOptions options = null)
{
return RemoteInvoke(GetMethodInfo(method), Array.Empty<string>(), options);
@@ -58,6 +58,7 @@ namespace System.Diagnostics
/// <summary>Invokes the method from this assembly in another process using the specified arguments.</summary>
/// <param name="method">The method to invoke.</param>
+ /// <param name="arg">The argument to pass to the method.</param>
/// <param name="options">Options to use for the invocation.</param>
public static RemoteInvokeHandle RemoteInvoke(
Func<string, Task<int>> method,
@@ -70,10 +71,23 @@ namespace System.Diagnostics
/// <summary>Invokes the method from this assembly in another process using the specified arguments.</summary>
/// <param name="method">The method to invoke.</param>
/// <param name="arg1">The first argument to pass to the method.</param>
+ /// <param name="arg2">The second argument to pass to the method.</param>
+ /// <param name="options">Options to use for the invocation.</param>
+ public static RemoteInvokeHandle RemoteInvoke(
+ Func<string, string, Task<int>> method,
+ string arg1, string arg2,
+ RemoteInvokeOptions options = null)
+ {
+ return RemoteInvoke(GetMethodInfo(method), new[] { arg1, arg2 }, options);
+ }
+
+ /// <summary>Invokes the method from this assembly in another process using the specified arguments.</summary>
+ /// <param name="method">The method to invoke.</param>
+ /// <param name="arg">The argument to pass to the method.</param>
/// <param name="options">Options to use for the invocation.</param>
public static RemoteInvokeHandle RemoteInvoke(
- Func<string, int> method,
- string arg,
+ Func<string, int> method,
+ string arg,
RemoteInvokeOptions options = null)
{
return RemoteInvoke(GetMethodInfo(method), new[] { arg }, options);
@@ -85,8 +99,8 @@ namespace System.Diagnostics
/// <param name="arg2">The second argument to pass to the method.</param>
/// <param name="options">Options to use for the invocation.</param>
public static RemoteInvokeHandle RemoteInvoke(
- Func<string, string, int> method,
- string arg1, string arg2,
+ Func<string, string, int> method,
+ string arg1, string arg2,
RemoteInvokeOptions options = null)
{
return RemoteInvoke(GetMethodInfo(method), new[] { arg1, arg2 }, options);
@@ -99,8 +113,8 @@ namespace System.Diagnostics
/// <param name="arg3">The third argument to pass to the method.</param>
/// <param name="options">Options to use for the invocation.</param>
public static RemoteInvokeHandle RemoteInvoke(
- Func<string, string, string, int> method,
- string arg1, string arg2, string arg3,
+ Func<string, string, string, int> method,
+ string arg1, string arg2, string arg3,
RemoteInvokeOptions options = null)
{
return RemoteInvoke(GetMethodInfo(method), new[] { arg1, arg2, arg3 }, options);
@@ -114,8 +128,8 @@ namespace System.Diagnostics
/// <param name="arg4">The fourth argument to pass to the method.</param>
/// <param name="options">Options to use for the invocation.</param>
public static RemoteInvokeHandle RemoteInvoke(
- Func<string, string, string, string, int> method,
- string arg1, string arg2, string arg3, string arg4,
+ Func<string, string, string, string, int> method,
+ string arg1, string arg2, string arg3, string arg4,
RemoteInvokeOptions options = null)
{
return RemoteInvoke(GetMethodInfo(method), new[] { arg1, arg2, arg3, arg4 }, options);
@@ -130,8 +144,8 @@ namespace System.Diagnostics
/// <param name="arg5">The fifth argument to pass to the method.</param>
/// <param name="options">Options to use for the invocation.</param>
public static RemoteInvokeHandle RemoteInvoke(
- Func<string, string, string, string, string, int> method,
- string arg1, string arg2, string arg3, string arg4, string arg5,
+ Func<string, string, string, string, string, int> method,
+ string arg1, string arg2, string arg3, string arg4, string arg5,
RemoteInvokeOptions options = null)
{
return RemoteInvoke(GetMethodInfo(method), new[] { arg1, arg2, arg3, arg4, arg5 }, options);
@@ -172,17 +186,52 @@ namespace System.Diagnostics
/// <summary>A cleanup handle to the Process created for the remote invocation.</summary>
public sealed class RemoteInvokeHandle : IDisposable
{
- public RemoteInvokeHandle(Process process, RemoteInvokeOptions options)
+ public RemoteInvokeHandle(Process process, RemoteInvokeOptions options, string assemblyName = null, string className = null, string methodName = null)
{
Process = process;
Options = options;
+ AssemblyName = assemblyName;
+ ClassName = className;
+ MethodName = methodName;
}
- public Process Process { get; private set; }
+ private int _exitCode;
+ public int ExitCode
+ {
+ get
+ {
+ if (!PlatformDetection.IsUap)
+ {
+ Process.WaitForExit();
+ return Process.ExitCode;
+ }
+ return _exitCode;
+ }
+ internal set
+ {
+ if (!PlatformDetection.IsUap)
+ {
+ throw new PlatformNotSupportedException("ExitCode property can only be set in UWP");
+ }
+ _exitCode = value;
+ }
+ }
+ public Process Process { get; set; }
public RemoteInvokeOptions Options { get; private set; }
+ public string AssemblyName { get; private set; }
+ public string ClassName { get; private set; }
+ public string MethodName { get; private set; }
public void Dispose()
{
+ GC.SuppressFinalize(this); // before Dispose(true) in case the Dispose call throws
+ Dispose(disposing: true);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ Assert.True(disposing, $"A test {AssemblyName}!{ClassName}.{MethodName} forgot to Dispose() the result of RemoteInvoke()");
+
if (Process != null)
{
// A bit unorthodox to do throwing operations in a Dispose, but by doing it here we avoid
@@ -222,6 +271,13 @@ namespace System.Diagnostics
}
}
+ ~RemoteInvokeHandle()
+ {
+ // Finalizer flags tests that omitted the explicit Dispose() call; they must have it, or they aren't
+ // waiting on the remote execution
+ Dispose(disposing: false);
+ }
+
private sealed class RemoteExecutionException : XunitException
{
internal RemoteExecutionException(string stackTrace) : base("Remote process failed with an unhandled exception.", stackTrace) { }
@@ -232,6 +288,8 @@ namespace System.Diagnostics
/// <summary>Options used with RemoteInvoke.</summary>
public sealed class RemoteInvokeOptions
{
+ private bool _runAsSudo;
+
public bool Start { get; set; } = true;
public ProcessStartInfo StartInfo { get; set; } = new ProcessStartInfo();
public bool EnableProfiling { get; set; } = true;
@@ -240,5 +298,22 @@ namespace System.Diagnostics
public int TimeOut {get; set; } = RemoteExecutorTestBase.FailWaitTimeoutMilliseconds;
public int ExpectedExitCode { get; set; } = RemoteExecutorTestBase.SuccessExitCode;
public string ExceptionFile { get; } = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
+
+ public bool RunAsSudo
+ {
+ get
+ {
+ return _runAsSudo;
+ }
+ set
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ _runAsSudo = value;
+ }
+ }
}
}
diff --git a/src/CoreFx.Private.TestUtilities/src/System/Diagnostics/RemoteExecutorTestBase.uap.cs b/src/CoreFx.Private.TestUtilities/src/System/Diagnostics/RemoteExecutorTestBase.uap.cs
index 85649a6aba..a90e0c3270 100644
--- a/src/CoreFx.Private.TestUtilities/src/System/Diagnostics/RemoteExecutorTestBase.uap.cs
+++ b/src/CoreFx.Private.TestUtilities/src/System/Diagnostics/RemoteExecutorTestBase.uap.cs
@@ -36,6 +36,7 @@ namespace System.Diagnostics
// that the method to invoke is available because we're already running in this assembly.
Type t = method.DeclaringType;
Assembly a = t.GetTypeInfo().Assembly;
+ int exitCode;
using (AppServiceConnection remoteExecutionService = new AppServiceConnection())
{
@@ -65,12 +66,13 @@ namespace System.Diagnostics
AppServiceResponse response = remoteExecutionService.SendMessageAsync(message).GetAwaiter().GetResult();
Assert.True(response.Status == AppServiceResponseStatus.Success, $"response.Status = {response.Status}");
- int res = (int)response.Message["Results"];
- Assert.True(!options.CheckExitCode || res == options.ExpectedExitCode, (string)response.Message["Log"] + Environment.NewLine + $"Returned Error code: {res}");
+ exitCode = (int)response.Message["Results"];
+ Assert.True(!options.CheckExitCode || exitCode == options.ExpectedExitCode, (string)response.Message["Log"] + Environment.NewLine + $"Returned Error code: {exitCode}");
}
-
// RemoteInvokeHandle is not really needed in the UAP scenario but we use it just to have consistent interface as non UAP
- return new RemoteInvokeHandle(null, options);
+ var handle = new RemoteInvokeHandle(null, options, null, null, null);
+ handle.ExitCode = exitCode;
+ return handle;
}
}
}
diff --git a/src/CoreFx.Private.TestUtilities/src/System/PlatformDetection.NetFx.cs b/src/CoreFx.Private.TestUtilities/src/System/PlatformDetection.NetFx.cs
index 6fb51b99ec..8074805ba1 100644
--- a/src/CoreFx.Private.TestUtilities/src/System/PlatformDetection.NetFx.cs
+++ b/src/CoreFx.Private.TestUtilities/src/System/PlatformDetection.NetFx.cs
@@ -24,6 +24,9 @@ namespace System
public static bool IsNetfx471OrNewer => GetFrameworkVersion() >= new Version(4, 7, 1);
+ public static string LibcRelease => "";
+ public static string LibcVersion => "";
+
// To get the framework version we can do it throught the registry key and getting the Release value under the .NET Framework key.
// the mapping to each version can be found in: https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed
// everytime we ship a new version this method should be updated to include the new framework version.
diff --git a/src/CoreFx.Private.TestUtilities/src/System/PlatformDetection.NonNetFx.cs b/src/CoreFx.Private.TestUtilities/src/System/PlatformDetection.NonNetFx.cs
index 087f2cf9a0..8d5f5be0d2 100644
--- a/src/CoreFx.Private.TestUtilities/src/System/PlatformDetection.NonNetFx.cs
+++ b/src/CoreFx.Private.TestUtilities/src/System/PlatformDetection.NonNetFx.cs
@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
+using System.Runtime.InteropServices;
using Xunit;
namespace System
@@ -12,5 +14,50 @@ namespace System
public static bool IsNetfx462OrNewer => false;
public static bool IsNetfx470OrNewer => false;
public static bool IsNetfx471OrNewer => false;
+
+
+ [DllImport("libc", ExactSpelling = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
+ private static extern IntPtr gnu_get_libc_release();
+
+ [DllImport("libc", ExactSpelling = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
+ private static extern IntPtr gnu_get_libc_version();
+
+ /// <summary>
+ /// If gnulibc is available, returns the release, such as "stable".
+ /// Otherwise (eg., Windows, musl) returns "glibc_not_found".
+ /// </summary>
+ public static string LibcRelease
+ {
+ get
+ {
+ try
+ {
+ return Marshal.PtrToStringUTF8(gnu_get_libc_release());
+ }
+ catch (Exception e) when (e is DllNotFoundException || e is EntryPointNotFoundException)
+ {
+ return "glibc_not_found";
+ }
+ }
+ }
+
+ /// <summary>
+ /// If gnulibc is available, returns the version, such as "2.22".
+ /// Otherwise (eg., Windows, musl) returns "glibc_not_found". (In future could run "ldd -version" for musl)
+ /// </summary>
+ public static string LibcVersion
+ {
+ get
+ {
+ try
+ {
+ return Marshal.PtrToStringUTF8(gnu_get_libc_version());
+ }
+ catch (Exception e) when (e is DllNotFoundException || e is EntryPointNotFoundException)
+ {
+ return "glibc_not_found";
+ }
+ }
+ }
}
}
diff --git a/src/CoreFx.Private.TestUtilities/src/System/PlatformDetection.Unix.cs b/src/CoreFx.Private.TestUtilities/src/System/PlatformDetection.Unix.cs
index 505aa371de..4829b0549e 100644
--- a/src/CoreFx.Private.TestUtilities/src/System/PlatformDetection.Unix.cs
+++ b/src/CoreFx.Private.TestUtilities/src/System/PlatformDetection.Unix.cs
@@ -25,6 +25,7 @@ namespace System
public static int WindowsVersion => -1;
public static bool IsCentos6 => IsDistroAndVersion("centos", 6);
+ public static bool IsAlpine => IsDistroAndVersion("alpine");
public static bool IsOpenSUSE => IsDistroAndVersion("opensuse");
public static bool IsUbuntu => IsDistroAndVersion("ubuntu");
public static bool IsDebian => IsDistroAndVersion("debian");
@@ -33,6 +34,8 @@ namespace System
public static bool IsUbuntu1604 => IsDistroAndVersion("ubuntu", 16, 4);
public static bool IsUbuntu1704 => IsDistroAndVersion("ubuntu", 17, 4);
public static bool IsUbuntu1710 => IsDistroAndVersion("ubuntu", 17, 10);
+ public static bool IsUbuntu1710OrHigher => IsDistroAndVersionOrHigher("ubuntu", 17, 10);
+ public static bool IsUbuntu1804 => IsDistroAndVersion("ubuntu", 18, 04);
public static bool IsTizen => IsDistroAndVersion("tizen");
public static bool IsFedora => IsDistroAndVersion("fedora");
public static bool IsWindowsNanoServer => false;
@@ -109,7 +112,18 @@ namespace System
/// <returns>Whether the OS platform matches the given Linux distro and optional version.</returns>
private static bool IsDistroAndVersion(string distroId, int major = -1, int minor = -1, int build = -1, int revision = -1)
{
- return IsDistroAndVersion((distro) => distro == distroId, major, minor, build, revision);
+ return IsDistroAndVersion(distro => (distro == distroId), major, minor, build, revision);
+ }
+
+ /// <summary>
+ /// Get whether the OS platform matches the given Linux distro and optional version is same or higher.
+ /// </summary>
+ /// <param name="distroId">The distribution id.</param>
+ /// <param name="versionId">The distro version. If omitted, compares the distro only.</param>
+ /// <returns>Whether the OS platform matches the given Linux distro and optional version is same or higher.</returns>
+ private static bool IsDistroAndVersionOrHigher(string distroId, int major = -1, int minor = -1, int build = -1, int revision = -1)
+ {
+ return IsDistroAndVersionOrHigher(distro => (distro == distroId), major, minor, build, revision);
}
private static bool IsDistroAndVersion(Predicate<string> distroPredicate, int major = -1, int minor = -1, int build = -1, int revision = -1)
@@ -117,7 +131,21 @@ namespace System
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
DistroInfo v = GetDistroInfo();
- if (distroPredicate(v.Id) && VersionEquivalentWith(major, minor, build, revision, v.VersionId))
+ if (distroPredicate(v.Id) && VersionEquivalentTo(major, minor, build, revision, v.VersionId))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static bool IsDistroAndVersionOrHigher(Predicate<string> distroPredicate, int major = -1, int minor = -1, int build = -1, int revision = -1)
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ DistroInfo v = GetDistroInfo();
+ if (distroPredicate(v.Id) && VersionEquivalentToOrHigher(major, minor, build, revision, v.VersionId))
{
return true;
}
@@ -126,7 +154,7 @@ namespace System
return false;
}
- private static bool VersionEquivalentWith(int major, int minor, int build, int revision, Version actualVersionId)
+ private static bool VersionEquivalentTo(int major, int minor, int build, int revision, Version actualVersionId)
{
return (major == -1 || major == actualVersionId.Major)
&& (minor == -1 || minor == actualVersionId.Minor)
@@ -134,6 +162,17 @@ namespace System
&& (revision == -1 || revision == actualVersionId.Revision);
}
+ private static bool VersionEquivalentToOrHigher(int major, int minor, int build, int revision, Version actualVersionId)
+ {
+ return
+ VersionEquivalentTo(major, minor, build, revision, actualVersionId) ||
+ (actualVersionId.Major > major ||
+ (actualVersionId.Major == major && actualVersionId.Minor > minor ||
+ (actualVersionId.Minor == minor && actualVersionId.Build > build ||
+ (actualVersionId.Build == build && actualVersionId.Revision > revision ||
+ (actualVersionId.Revision == revision)))));
+ }
+
private static Version GetOSXProductVersion()
{
try
diff --git a/src/CoreFx.Private.TestUtilities/src/System/PlatformDetection.Windows.cs b/src/CoreFx.Private.TestUtilities/src/System/PlatformDetection.Windows.cs
index 0267fa2145..1bd78e27a5 100644
--- a/src/CoreFx.Private.TestUtilities/src/System/PlatformDetection.Windows.cs
+++ b/src/CoreFx.Private.TestUtilities/src/System/PlatformDetection.Windows.cs
@@ -21,11 +21,14 @@ namespace System
public static bool IsOpenSUSE => false;
public static bool IsUbuntu => false;
public static bool IsDebian => false;
+ public static bool IsAlpine => false;
public static bool IsDebian8 => false;
public static bool IsUbuntu1404 => false;
public static bool IsUbuntu1604 => false;
public static bool IsUbuntu1704 => false;
public static bool IsUbuntu1710 => false;
+ public static bool IsUbuntu1710OrHigher => false;
+ public static bool IsUbuntu1804 => false;
public static bool IsTizen => false;
public static bool IsNotFedoraOrRedHatFamily => true;
public static bool IsFedora => false;
@@ -69,7 +72,7 @@ namespace System
public static bool IsWindows7 => GetWindowsVersion() == 6 && GetWindowsMinorVersion() == 1;
public static bool IsWindows8x => GetWindowsVersion() == 6 && (GetWindowsMinorVersion() == 2 || GetWindowsMinorVersion() == 3);
- public static string GetDistroVersionString() { return "ProductType=" + GetWindowsProductType() + "InstallationType=" + GetInstallationType(); }
+ public static string GetDistroVersionString() { return "WindowsProductType=" + GetWindowsProductType() + " WindowsInstallationType=" + GetInstallationType(); }
private static int s_isInAppContainer = -1;
diff --git a/src/CoreFx.Private.TestUtilities/src/System/PlatformDetection.cs b/src/CoreFx.Private.TestUtilities/src/System/PlatformDetection.cs
index 23d2309c69..9161a05894 100644
--- a/src/CoreFx.Private.TestUtilities/src/System/PlatformDetection.cs
+++ b/src/CoreFx.Private.TestUtilities/src/System/PlatformDetection.cs
@@ -18,7 +18,7 @@ namespace System
// do it in a way that failures don't cascade.
//
- public static bool HasWindowsShell => IsNotWindowsServerCore && IsNotWindowsNanoServer && IsNotWindowsIoTCore;
+ public static bool HasWindowsShell => IsWindows && IsNotWindowsServerCore && IsNotWindowsNanoServer && IsNotWindowsIoTCore;
public static bool IsUap => IsInAppContainer || IsNetNative;
public static bool IsFullFramework => RuntimeInformation.FrameworkDescription.StartsWith(".NET Framework", StringComparison.OrdinalIgnoreCase);
public static bool IsNetNative => RuntimeInformation.FrameworkDescription.StartsWith(".NET Native", StringComparison.OrdinalIgnoreCase);
diff --git a/src/CoreFx.Private.TestUtilities/src/System/TestEnvironment.cs b/src/CoreFx.Private.TestUtilities/src/System/TestEnvironment.cs
new file mode 100644
index 0000000000..ca7ad96583
--- /dev/null
+++ b/src/CoreFx.Private.TestUtilities/src/System/TestEnvironment.cs
@@ -0,0 +1,25 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using Xunit;
+
+namespace System
+{
+ public static partial class TestEnvironment
+ {
+ /// <summary>
+ /// Check if the stress mode is enabled.
+ /// </summary>
+ /// <value> true if the environment variable COREFX_STRESS set to '1' or 'true'. returns false otherwise</value>
+ public static bool IsStressModeEnabled
+ {
+ get
+ {
+ string value = Environment.GetEnvironmentVariable("COREFX_STRESS");
+ return value != null && (value == "1" || value.Equals("true", StringComparison.OrdinalIgnoreCase));
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.CSharp/Microsoft.CSharp.sln b/src/Microsoft.CSharp/Microsoft.CSharp.sln
index 15f386abe3..9291b8607b 100644
--- a/src/Microsoft.CSharp/Microsoft.CSharp.sln
+++ b/src/Microsoft.CSharp/Microsoft.CSharp.sln
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27004.2009
+# Visual Studio 14
+VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CSharp.Tests", "tests\Microsoft.CSharp.Tests.csproj", "{82B54697-0251-47A1-8546-FC507D0F3B08}"
ProjectSection(ProjectDependencies) = postProject
@@ -47,7 +47,4 @@ Global
{96AA2060-C846-4E56-9509-E8CB9C114C8F} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD}
{1427906B-FF3D-422A-8278-F2B7E89DE12A} = {2E666815-2EDB-464B-9DF6-380BF4789AD4}
EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {699239FB-3677-4369-9E97-09ED5E232491}
- EndGlobalSection
EndGlobal
diff --git a/src/Microsoft.CSharp/pkg/Microsoft.CSharp.pkgproj b/src/Microsoft.CSharp/pkg/Microsoft.CSharp.pkgproj
index eb6c2fe98f..45d2d8dd31 100644
--- a/src/Microsoft.CSharp/pkg/Microsoft.CSharp.pkgproj
+++ b/src/Microsoft.CSharp/pkg/Microsoft.CSharp.pkgproj
@@ -19,7 +19,7 @@
<AsFrameworkReference>true</AsFrameworkReference>
</InboxOnTargetFramework>
<InboxOnTargetFramework Include="netcoreapp2.0" />
- <InboxOnTargetFramework Include="$(UAPvNextTFM)" />
+ <InboxOnTargetFramework Include="uap10.0.16299" />
<InboxOnTargetFramework Include="win8" />
<InboxOnTargetFramework Include="wp80" />
<InboxOnTargetFramework Include="wpa81" />
diff --git a/src/Microsoft.CSharp/src/Microsoft.CSharp.csproj b/src/Microsoft.CSharp/src/Microsoft.CSharp.csproj
index 1390478839..c54a1d2e80 100644
--- a/src/Microsoft.CSharp/src/Microsoft.CSharp.csproj
+++ b/src/Microsoft.CSharp/src/Microsoft.CSharp.csproj
@@ -48,7 +48,6 @@
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\BindingContext.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\BindingFlag.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Binding\Better.cs" />
- <Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Binding\ErrorReporting.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\BinOpArgInfo.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\BinOpKind.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\BinOpSig.cs" />
@@ -57,7 +56,6 @@
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Conversion.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Conversions.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\COperators.cs" />
- <Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Declarations\AggregateDeclaration.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\ExplicitConversion.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\ExpressionBinder.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\ExpressionKind.cs" />
@@ -65,7 +63,6 @@
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\ExprFactory.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\EXPRFLAG.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\FundamentalTypes.cs" />
- <Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\GlobalSymbolContext.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\GroupToArgsBinder.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\GroupToArgsBinderResult.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\ImplicitConversion.cs" />
@@ -95,9 +92,8 @@
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Symbols\Symbol.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Symbols\SymbolKind.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Symbols\SymbolLoader.cs" />
- <Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Symbols\SymbolManagerBase.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Symbols\SymbolMask.cs" />
- <Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Symbols\SymbolTable.cs" />
+ <Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Symbols\SymbolStore.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Symbols\SymFactory.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Symbols\TypeParameterSymbol.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Symbols\VariableSymbol.cs" />
@@ -119,7 +115,6 @@
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Tree\ExprWithType.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Tree\Field.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Tree\FieldInfo.cs" />
- <Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Tree\IExprWithObject.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Tree\List.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Tree\LocalVariable.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Tree\MemberGroup.cs" />
@@ -147,14 +142,12 @@
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Types\PredefinedTypes.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Types\Type.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Types\TypeArray.cs" />
- <Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Types\TypeFactory.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Types\TypeKind.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Types\TypeManager.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Types\TypeParameterType.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Types\TypeTable.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\Types\VoidType.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\UnaOpSig.cs" />
- <Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\UtilityTypeExtensions.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\Semantics\WithType.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\SpecialNames.cs" />
<Compile Include="Microsoft\CSharp\RuntimeBinder\SymbolTable.cs" />
@@ -188,4 +181,4 @@
<Reference Include="System.Threading" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/BinderHelper.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/BinderHelper.cs
index 4d114c3ea0..2123aeaa7a 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/BinderHelper.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/BinderHelper.cs
@@ -19,7 +19,7 @@ namespace Microsoft.CSharp.RuntimeBinder
private static MethodInfo s_SingleIsNaN;
internal static DynamicMetaObject Bind(
- DynamicMetaObjectBinder action,
+ ICSharpBinder action,
RuntimeBinder binder,
DynamicMetaObject[] args,
IEnumerable<CSharpArgumentInfo> arginfos,
@@ -89,8 +89,7 @@ namespace Microsoft.CSharp.RuntimeBinder
// Get the bound expression.
try
{
- DynamicMetaObject deferredBinding;
- Expression expression = binder.Bind(action, parameters, args, out deferredBinding);
+ Expression expression = binder.Bind(action, parameters, args, out DynamicMetaObject deferredBinding);
if (deferredBinding != null)
{
@@ -282,7 +281,7 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
- private static Expression ConvertResult(Expression binding, DynamicMetaObjectBinder action)
+ private static Expression ConvertResult(Expression binding, ICSharpBinder action)
{
// Need to handle the following cases:
// (1) Call to a constructor: no conversions.
@@ -292,25 +291,21 @@ namespace Microsoft.CSharp.RuntimeBinder
// In all other cases, binding.Type should be equivalent or
// reference assignable to resultType.
- var invokeConstructor = action as CSharpInvokeConstructorBinder;
- if (invokeConstructor != null)
+ // No conversions needed for , the call site has the correct type.
+ if (action is CSharpInvokeConstructorBinder)
{
- // No conversions needed, the call site has the correct type.
return binding;
}
if (binding.Type == typeof(void))
{
- var invoke = action as ICSharpInvokeOrInvokeMemberBinder;
- if (invoke != null && invoke.ResultDiscarded)
+ if (action is ICSharpInvokeOrInvokeMemberBinder invoke && invoke.ResultDiscarded)
{
Debug.Assert(action.ReturnType == typeof(object));
return Expression.Block(binding, Expression.Default(action.ReturnType));
}
- else
- {
- throw Error.BindToVoidMethodButExpectResult();
- }
+
+ throw Error.BindToVoidMethodButExpectResult();
}
if (binding.Type.IsValueType && !action.ReturnType.IsValueType)
@@ -324,7 +319,7 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
- private static Type GetTypeForErrorMetaObject(DynamicMetaObjectBinder action, DynamicMetaObject[] args)
+ private static Type GetTypeForErrorMetaObject(ICSharpBinder action, DynamicMetaObject[] args)
{
// This is similar to ConvertResult but has fewer things to worry about.
@@ -341,13 +336,9 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
- private static bool IsIncrementOrDecrementActionOnLocal(DynamicMetaObjectBinder action)
- {
- CSharpUnaryOperationBinder operatorPayload = action as CSharpUnaryOperationBinder;
-
- return operatorPayload != null &&
- (operatorPayload.Operation == ExpressionType.Increment || operatorPayload.Operation == ExpressionType.Decrement);
- }
+ private static bool IsIncrementOrDecrementActionOnLocal(ICSharpBinder action) =>
+ action is CSharpUnaryOperationBinder operatorPayload
+ && (operatorPayload.Operation == ExpressionType.Increment || operatorPayload.Operation == ExpressionType.Decrement);
/////////////////////////////////////////////////////////////////////////////////
@@ -497,9 +488,9 @@ namespace Microsoft.CSharp.RuntimeBinder
return SpecialNames.CLR_False;
case ExpressionType.Increment:
- return SpecialNames.CLR_PreIncrement;
+ return SpecialNames.CLR_Increment;
case ExpressionType.Decrement:
- return SpecialNames.CLR_PreDecrement;
+ return SpecialNames.CLR_Decrement;
}
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpBinaryOperationBinder.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpBinaryOperationBinder.cs
index 36f2d39fb9..3f4222965b 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpBinaryOperationBinder.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpBinaryOperationBinder.cs
@@ -13,7 +13,7 @@ using Microsoft.CSharp.RuntimeBinder.Semantics;
namespace Microsoft.CSharp.RuntimeBinder
{
/// <summary>
- /// Represents a dynamic binary operation in C#, providing the binding semantics and the details about the operation.
+ /// Represents a dynamic binary operation in C#, providing the binding semantics and the details about the operation.
/// Instances of this class are generated by the C# compiler.
/// </summary>
internal sealed class CSharpBinaryOperationBinder : BinaryOperationBinder, ICSharpBinder
@@ -33,24 +33,20 @@ namespace Microsoft.CSharp.RuntimeBinder
public Expr DispatchPayload(RuntimeBinder runtimeBinder, ArgumentObject[] arguments, LocalVariableSymbol[] locals)
=> runtimeBinder.BindBinaryOperation(this, arguments, locals);
- public void PopulateSymbolTableWithName(SymbolTable symbolTable, Type callingType, ArgumentObject[] arguments)
+ public void PopulateSymbolTableWithName(Type callingType, ArgumentObject[] arguments)
{
string name = Operation.GetCLROperatorName();
Debug.Assert(name != null);
- symbolTable.PopulateSymbolTableWithName(name, null, arguments[0].Type);
- symbolTable.PopulateSymbolTableWithName(name, null, arguments[1].Type);
+ SymbolTable.PopulateSymbolTableWithName(name, null, arguments[0].Type);
+ SymbolTable.PopulateSymbolTableWithName(name, null, arguments[1].Type);
}
public bool IsBinderThatCanHaveRefReceiver => false;
- public bool IsChecked { get; }
-
internal bool IsLogicalOperation => (_binopFlags & CSharpBinaryOperationFlags.LogicalOperation) != 0;
private readonly CSharpBinaryOperationFlags _binopFlags;
- public Type CallingContext { get; }
-
private readonly CSharpArgumentInfo[] _argumentInfo;
CSharpArgumentInfo ICSharpBinder.GetArgumentInfo(int index) => _argumentInfo[index];
@@ -63,7 +59,7 @@ namespace Microsoft.CSharp.RuntimeBinder
/// Initializes a new instance of the <see cref="CSharpBinaryOperationBinder"/> class.
/// </summary>
/// <param name="operation">The binary operation kind.</param>
- /// <param name="isChecked">True if the operation is defined in a checked context; otherwise false.</param>
+ /// <param name="isChecked">True if the operation is defined in a checked context; otherwise false.</param>
/// <param name="binaryOperationFlags">The flags associated with this binary operation.</param>
/// <param name="callingContext">The <see cref="Type"/> that indicates where this operation is defined.</param>
/// <param name="argumentInfo">The sequence of <see cref="CSharpArgumentInfo"/> instances for the arguments to this operation.</param>
@@ -75,12 +71,10 @@ namespace Microsoft.CSharp.RuntimeBinder
IEnumerable<CSharpArgumentInfo> argumentInfo) :
base(operation)
{
- IsChecked = isChecked;
_binopFlags = binaryOperationFlags;
- CallingContext = callingContext;
_argumentInfo = BinderHelper.ToArray(argumentInfo);
Debug.Assert(_argumentInfo.Length == 2);
- _binder = RuntimeBinder.GetInstance();
+ _binder = new RuntimeBinder(callingContext, isChecked);
}
/// <summary>
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpConvertBinder.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpConvertBinder.cs
index a45684eac3..56993a48f3 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpConvertBinder.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpConvertBinder.cs
@@ -11,7 +11,7 @@ using Microsoft.CSharp.RuntimeBinder.Semantics;
namespace Microsoft.CSharp.RuntimeBinder
{
/// <summary>
- /// Represents a dynamic conversion in C#, providing the binding semantics and the details about the operation.
+ /// Represents a dynamic conversion in C#, providing the binding semantics and the details about the operation.
/// Instances of this class are generated by the C# compiler.
/// </summary>
internal sealed class CSharpConvertBinder : ConvertBinder, ICSharpBinder
@@ -36,11 +36,11 @@ namespace Microsoft.CSharp.RuntimeBinder
: runtimeBinder.BindImplicitConversion(arguments, Type, locals, ConversionKind == CSharpConversionKind.ArrayCreationConversion);
}
- public void PopulateSymbolTableWithName(SymbolTable symbolTable, Type callingType, ArgumentObject[] arguments)
+ public void PopulateSymbolTableWithName(Type callingType, ArgumentObject[] arguments)
{
// Conversions don't need to do anything, since they're just conversions!
// After we add payload information, we add conversions for all argument
- // types anyway, so that will get handled there.
+ // types anyway, so that will get handled there.
}
public bool IsBinderThatCanHaveRefReceiver => false;
@@ -49,10 +49,6 @@ namespace Microsoft.CSharp.RuntimeBinder
private CSharpConversionKind ConversionKind { get; }
- public bool IsChecked { get; }
-
- public Type CallingContext { get; }
-
private readonly RuntimeBinder _binder;
/// <summary>
@@ -70,9 +66,7 @@ namespace Microsoft.CSharp.RuntimeBinder
base(type, conversionKind == CSharpConversionKind.ExplicitConversion)
{
ConversionKind = conversionKind;
- IsChecked = isChecked;
- CallingContext = callingContext;
- _binder = RuntimeBinder.GetInstance();
+ _binder = new RuntimeBinder(callingContext, isChecked);
}
/// <summary>
@@ -83,13 +77,13 @@ namespace Microsoft.CSharp.RuntimeBinder
/// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
public override DynamicMetaObject FallbackConvert(DynamicMetaObject target, DynamicMetaObject errorSuggestion)
{
-#if ENABLECOMBINDER
+#if ENABLECOMBINDER
DynamicMetaObject com;
if (!BinderHelper.IsWindowsRuntimeObject(target) && ComBinder.TryConvert(this, target, out com))
{
return com;
}
-#endif
+#endif
BinderHelper.ValidateBindArgument(target, nameof(target));
return BinderHelper.Bind(this, _binder, new[] { target }, null, errorSuggestion);
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpGetIndexBinder.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpGetIndexBinder.cs
index be3f82853f..2a1aa6c1f7 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpGetIndexBinder.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpGetIndexBinder.cs
@@ -10,7 +10,7 @@ using Microsoft.CSharp.RuntimeBinder.Semantics;
namespace Microsoft.CSharp.RuntimeBinder
{
/// <summary>
- /// Represents a dynamic indexer access in C#, providing the binding semantics and the details about the operation.
+ /// Represents a dynamic indexer access in C#, providing the binding semantics and the details about the operation.
/// Instances of this class are generated by the C# compiler.
/// </summary>
internal sealed class CSharpGetIndexBinder : GetIndexBinder, ICSharpBinder
@@ -25,15 +25,11 @@ namespace Microsoft.CSharp.RuntimeBinder
return runtimeBinder.BindProperty(this, arguments[0], locals[0], indexerArguments);
}
- public void PopulateSymbolTableWithName(SymbolTable symbolTable, Type callingType, ArgumentObject[] arguments)
- => symbolTable.PopulateSymbolTableWithName(SpecialNames.Indexer, null, arguments[0].Type);
+ public void PopulateSymbolTableWithName(Type callingType, ArgumentObject[] arguments)
+ => SymbolTable.PopulateSymbolTableWithName(SpecialNames.Indexer, null, arguments[0].Type);
public bool IsBinderThatCanHaveRefReceiver => true;
- public Type CallingContext { get; }
-
- public bool IsChecked => false;
-
private readonly CSharpArgumentInfo[] _argumentInfo;
CSharpArgumentInfo ICSharpBinder.GetArgumentInfo(int index) => _argumentInfo[index];
@@ -50,9 +46,8 @@ namespace Microsoft.CSharp.RuntimeBinder
IEnumerable<CSharpArgumentInfo> argumentInfo) :
base(BinderHelper.CreateCallInfo(ref argumentInfo, 1)) // discard 1 argument: the target object
{
- CallingContext = callingContext;
_argumentInfo = argumentInfo as CSharpArgumentInfo[];
- _binder = RuntimeBinder.GetInstance();
+ _binder = new RuntimeBinder(callingContext);
}
/// <summary>
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpGetMemberBinder.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpGetMemberBinder.cs
index 19290ddfc3..8bccb1e9a1 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpGetMemberBinder.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpGetMemberBinder.cs
@@ -11,7 +11,7 @@ using Microsoft.CSharp.RuntimeBinder.Semantics;
namespace Microsoft.CSharp.RuntimeBinder
{
/// <summary>
- /// Represents a dynamic property access in C#, providing the binding semantics and the details about the operation.
+ /// Represents a dynamic property access in C#, providing the binding semantics and the details about the operation.
/// Instances of this class are generated by the C# compiler.
/// </summary>
internal sealed class CSharpGetMemberBinder : GetMemberBinder, IInvokeOnGetBinder, ICSharpBinder
@@ -24,15 +24,11 @@ namespace Microsoft.CSharp.RuntimeBinder
return runtimeBinder.BindProperty(this, arguments[0], locals[0], null);
}
- public void PopulateSymbolTableWithName(SymbolTable symbolTable, Type callingType, ArgumentObject[] arguments)
- => symbolTable.PopulateSymbolTableWithName(Name, null, arguments[0].Type);
+ public void PopulateSymbolTableWithName(Type callingType, ArgumentObject[] arguments)
+ => SymbolTable.PopulateSymbolTableWithName(Name, null, arguments[0].Type);
public bool IsBinderThatCanHaveRefReceiver => false;
- public Type CallingContext { get; }
-
- public bool IsChecked => false;
-
private readonly CSharpArgumentInfo[] _argumentInfo;
CSharpArgumentInfo ICSharpBinder.GetArgumentInfo(int index) => _argumentInfo[index];
@@ -58,9 +54,8 @@ namespace Microsoft.CSharp.RuntimeBinder
base(name, false /*caseInsensitive*/)
{
ResultIndexed = resultIndexed;
- CallingContext = callingContext;
_argumentInfo = BinderHelper.ToArray(argumentInfo);
- _binder = RuntimeBinder.GetInstance();
+ _binder = new RuntimeBinder(callingContext);
}
/// <summary>
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpInvokeBinder.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpInvokeBinder.cs
index 4a7fa730bd..ca1842e5f2 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpInvokeBinder.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpInvokeBinder.cs
@@ -10,7 +10,7 @@ using Microsoft.CSharp.RuntimeBinder.Semantics;
namespace Microsoft.CSharp.RuntimeBinder
{
/// <summary>
- /// Represents a dynamic delegate-like call in C#, providing the binding semantics and the details about the operation.
+ /// Represents a dynamic delegate-like call in C#, providing the binding semantics and the details about the operation.
/// Instances of this class are generated by the C# compiler.
/// </summary>
internal sealed class CSharpInvokeBinder : InvokeBinder, ICSharpInvokeOrInvokeMemberBinder
@@ -20,8 +20,8 @@ namespace Microsoft.CSharp.RuntimeBinder
public Expr DispatchPayload(RuntimeBinder runtimeBinder, ArgumentObject[] arguments, LocalVariableSymbol[] locals)
=> runtimeBinder.DispatchPayload(this, arguments, locals);
- public void PopulateSymbolTableWithName(SymbolTable symbolTable, Type callingType, ArgumentObject[] arguments)
- => RuntimeBinder.PopulateSymbolTableWithPayloadInformation(symbolTable, this, callingType, arguments);
+ public void PopulateSymbolTableWithName(Type callingType, ArgumentObject[] arguments)
+ => RuntimeBinder.PopulateSymbolTableWithPayloadInformation(this, callingType, arguments);
public bool IsBinderThatCanHaveRefReceiver => true;
@@ -35,10 +35,6 @@ namespace Microsoft.CSharp.RuntimeBinder
private readonly CSharpCallFlags _flags;
- public Type CallingContext { get; }
-
- public bool IsChecked => false;
-
private readonly CSharpArgumentInfo[] _argumentInfo;
CSharpArgumentInfo ICSharpBinder.GetArgumentInfo(int index) => _argumentInfo[index];
@@ -60,9 +56,8 @@ namespace Microsoft.CSharp.RuntimeBinder
base(BinderHelper.CreateCallInfo(ref argumentInfo, 1)) // discard 1 argument: the target object (even if static, arg is type)
{
_flags = flags;
- CallingContext = callingContext;
_argumentInfo = argumentInfo as CSharpArgumentInfo[];
- _binder = RuntimeBinder.GetInstance();
+ _binder = new RuntimeBinder(callingContext);
}
/// <summary>
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpInvokeConstructorBinder.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpInvokeConstructorBinder.cs
index 5d61c0cfc6..ebac399ae1 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpInvokeConstructorBinder.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpInvokeConstructorBinder.cs
@@ -16,17 +16,13 @@ namespace Microsoft.CSharp.RuntimeBinder
public Expr DispatchPayload(RuntimeBinder runtimeBinder, ArgumentObject[] arguments, LocalVariableSymbol[] locals)
=> runtimeBinder.DispatchPayload(this, arguments, locals);
- public void PopulateSymbolTableWithName(SymbolTable symbolTable, Type callingType, ArgumentObject[] arguments)
- => RuntimeBinder.PopulateSymbolTableWithPayloadInformation(symbolTable, this, callingType, arguments);
+ public void PopulateSymbolTableWithName(Type callingType, ArgumentObject[] arguments)
+ => RuntimeBinder.PopulateSymbolTableWithPayloadInformation(this, callingType, arguments);
public bool IsBinderThatCanHaveRefReceiver => true;
public CSharpCallFlags Flags { get; }
- public Type CallingContext { get; }
-
- public bool IsChecked => false;
-
private readonly CSharpArgumentInfo[] _argumentInfo;
CSharpArgumentInfo ICSharpBinder.GetArgumentInfo(int index) => _argumentInfo[index];
@@ -47,9 +43,8 @@ namespace Microsoft.CSharp.RuntimeBinder
IEnumerable<CSharpArgumentInfo> argumentInfo)
{
Flags = flags;
- CallingContext = callingContext;
_argumentInfo = BinderHelper.ToArray(argumentInfo);
- _binder = RuntimeBinder.GetInstance();
+ _binder = new RuntimeBinder(callingContext);
}
public override DynamicMetaObject Bind(DynamicMetaObject target, DynamicMetaObject[] args)
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpInvokeMemberBinder.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpInvokeMemberBinder.cs
index b5fbbd0d3d..2c00860571 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpInvokeMemberBinder.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpInvokeMemberBinder.cs
@@ -11,7 +11,7 @@ using Microsoft.CSharp.RuntimeBinder.Semantics;
namespace Microsoft.CSharp.RuntimeBinder
{
/// <summary>
- /// Represents a dynamic method call in C#, providing the binding semantics and the details about the operation.
+ /// Represents a dynamic method call in C#, providing the binding semantics and the details about the operation.
/// Instances of this class are generated by the C# compiler.
/// </summary>
internal sealed class CSharpInvokeMemberBinder : InvokeMemberBinder, ICSharpInvokeOrInvokeMemberBinder
@@ -21,8 +21,8 @@ namespace Microsoft.CSharp.RuntimeBinder
public Expr DispatchPayload(RuntimeBinder runtimeBinder, ArgumentObject[] arguments, LocalVariableSymbol[] locals)
=> runtimeBinder.DispatchPayload(this, arguments, locals);
- public void PopulateSymbolTableWithName(SymbolTable symbolTable, Type callingType, ArgumentObject[] arguments)
- => RuntimeBinder.PopulateSymbolTableWithPayloadInformation(symbolTable, this, callingType, arguments);
+ public void PopulateSymbolTableWithName(Type callingType, ArgumentObject[] arguments)
+ => RuntimeBinder.PopulateSymbolTableWithPayloadInformation(this, callingType, arguments);
public bool IsBinderThatCanHaveRefReceiver => true;
@@ -32,8 +32,6 @@ namespace Microsoft.CSharp.RuntimeBinder
public Type CallingContext { get; }
- public bool IsChecked => false;
-
public Type[] TypeArguments { get; }
private readonly CSharpArgumentInfo[] _argumentInfo;
@@ -71,7 +69,7 @@ namespace Microsoft.CSharp.RuntimeBinder
CallingContext = callingContext;
TypeArguments = BinderHelper.ToArray(typeArguments);
_argumentInfo = BinderHelper.ToArray(argumentInfo);
- _binder = RuntimeBinder.GetInstance();
+ _binder = new RuntimeBinder(callingContext);
}
/// <summary>
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpIsEventBinder.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpIsEventBinder.cs
index 742588018e..dfb0eba671 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpIsEventBinder.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpIsEventBinder.cs
@@ -18,8 +18,8 @@ namespace Microsoft.CSharp.RuntimeBinder
public Expr DispatchPayload(RuntimeBinder runtimeBinder, ArgumentObject[] arguments, LocalVariableSymbol[] locals)
=> runtimeBinder.BindIsEvent(this, arguments, locals);
- public void PopulateSymbolTableWithName(SymbolTable symbolTable, Type callingType, ArgumentObject[] arguments)
- => symbolTable.PopulateSymbolTableWithName(Name, null, arguments[0].Info.IsStaticType ? arguments[0].Value as Type : arguments[0].Type);
+ public void PopulateSymbolTableWithName(Type callingType, ArgumentObject[] arguments)
+ => SymbolTable.PopulateSymbolTableWithName(Name, null, arguments[0].Info.IsStaticType ? arguments[0].Value as Type : arguments[0].Type);
public bool IsBinderThatCanHaveRefReceiver => false;
@@ -27,10 +27,6 @@ namespace Microsoft.CSharp.RuntimeBinder
public string Name { get; }
- public Type CallingContext { get; }
-
- public bool IsChecked => false;
-
private readonly RuntimeBinder _binder;
/// <summary>
@@ -43,8 +39,7 @@ namespace Microsoft.CSharp.RuntimeBinder
Type callingContext)
{
Name = name;
- CallingContext = callingContext;
- _binder = RuntimeBinder.GetInstance();
+ _binder = new RuntimeBinder(callingContext);
}
/// <summary>
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpSetIndexBinder.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpSetIndexBinder.cs
index 37bd58aba4..6e36118766 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpSetIndexBinder.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpSetIndexBinder.cs
@@ -10,7 +10,7 @@ using Microsoft.CSharp.RuntimeBinder.Semantics;
namespace Microsoft.CSharp.RuntimeBinder
{
/// <summary>
- /// Represents a dynamic indexer access in C#, providing the binding semantics and the details about the operation.
+ /// Represents a dynamic indexer access in C#, providing the binding semantics and the details about the operation.
/// Instances of this class are generated by the C# compiler.
/// </summary>
internal sealed class CSharpSetIndexBinder : SetIndexBinder, ICSharpBinder
@@ -22,17 +22,13 @@ namespace Microsoft.CSharp.RuntimeBinder
public Expr DispatchPayload(RuntimeBinder runtimeBinder, ArgumentObject[] arguments, LocalVariableSymbol[] locals)
=> runtimeBinder.BindAssignment(this, arguments, locals);
- public void PopulateSymbolTableWithName(SymbolTable symbolTable, Type callingType, ArgumentObject[] arguments)
- => symbolTable.PopulateSymbolTableWithName(SpecialNames.Indexer, null, arguments[0].Type);
+ public void PopulateSymbolTableWithName(Type callingType, ArgumentObject[] arguments)
+ => SymbolTable.PopulateSymbolTableWithName(SpecialNames.Indexer, null, arguments[0].Type);
public bool IsBinderThatCanHaveRefReceiver => true;
internal bool IsCompoundAssignment { get; }
- public bool IsChecked { get; }
-
- public Type CallingContext { get; }
-
private readonly CSharpArgumentInfo[] _argumentInfo;
CSharpArgumentInfo ICSharpBinder.GetArgumentInfo(int index) => _argumentInfo[index];
@@ -56,10 +52,8 @@ namespace Microsoft.CSharp.RuntimeBinder
base(BinderHelper.CreateCallInfo(ref argumentInfo, 2)) // discard 2 arguments: the target object and the value
{
IsCompoundAssignment = isCompoundAssignment;
- IsChecked = isChecked;
- CallingContext = callingContext;
_argumentInfo = argumentInfo as CSharpArgumentInfo[];
- _binder = RuntimeBinder.GetInstance();
+ _binder = new RuntimeBinder(callingContext, isChecked);
}
/// <summary>
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpSetMemberBinder.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpSetMemberBinder.cs
index ddf4611e0f..fb0ea5fe0c 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpSetMemberBinder.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpSetMemberBinder.cs
@@ -10,7 +10,7 @@ using Microsoft.CSharp.RuntimeBinder.Semantics;
namespace Microsoft.CSharp.RuntimeBinder
{
/// <summary>
- /// Represents a dynamic property access in C#, providing the binding semantics and the details about the operation.
+ /// Represents a dynamic property access in C#, providing the binding semantics and the details about the operation.
/// Instances of this class are generated by the C# compiler.
/// </summary>
internal sealed class CSharpSetMemberBinder : SetMemberBinder, ICSharpBinder
@@ -20,17 +20,13 @@ namespace Microsoft.CSharp.RuntimeBinder
public Expr DispatchPayload(RuntimeBinder runtimeBinder, ArgumentObject[] arguments, LocalVariableSymbol[] locals)
=> runtimeBinder.BindAssignment(this, arguments, locals);
- public void PopulateSymbolTableWithName(SymbolTable symbolTable, Type callingType, ArgumentObject[] arguments)
- => symbolTable.PopulateSymbolTableWithName(Name, null, arguments[0].Type);
+ public void PopulateSymbolTableWithName(Type callingType, ArgumentObject[] arguments)
+ => SymbolTable.PopulateSymbolTableWithName(Name, null, arguments[0].Type);
public bool IsBinderThatCanHaveRefReceiver => false;
internal bool IsCompoundAssignment { get; }
- public bool IsChecked { get; }
-
- public Type CallingContext { get; }
-
private readonly CSharpArgumentInfo[] _argumentInfo;
CSharpArgumentInfo ICSharpBinder.GetArgumentInfo(int index) => _argumentInfo[index];
@@ -57,10 +53,8 @@ namespace Microsoft.CSharp.RuntimeBinder
base(name, false)
{
IsCompoundAssignment = isCompoundAssignment;
- IsChecked = isChecked;
- CallingContext = callingContext;
_argumentInfo = BinderHelper.ToArray(argumentInfo);
- _binder = RuntimeBinder.GetInstance();
+ _binder = new RuntimeBinder(callingContext, isChecked);
}
/// <summary>
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpUnaryOperationBinder.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpUnaryOperationBinder.cs
index 2b94e5c122..b9d477b569 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpUnaryOperationBinder.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpUnaryOperationBinder.cs
@@ -13,7 +13,7 @@ using Microsoft.CSharp.RuntimeBinder.Semantics;
namespace Microsoft.CSharp.RuntimeBinder
{
/// <summary>
- /// Represents a dynamic unary operation in C#, providing the binding semantics and the details about the operation.
+ /// Represents a dynamic unary operation in C#, providing the binding semantics and the details about the operation.
/// Instances of this class are generated by the C# compiler.
/// </summary>
internal sealed class CSharpUnaryOperationBinder : UnaryOperationBinder, ICSharpBinder
@@ -34,15 +34,11 @@ namespace Microsoft.CSharp.RuntimeBinder
public Expr DispatchPayload(RuntimeBinder runtimeBinder, ArgumentObject[] arguments, LocalVariableSymbol[] locals)
=> runtimeBinder.BindUnaryOperation(this, arguments, locals);
- public void PopulateSymbolTableWithName(SymbolTable symbolTable, Type callingType, ArgumentObject[] arguments)
- => symbolTable.PopulateSymbolTableWithName(Operation.GetCLROperatorName(), null, arguments[0].Type);
+ public void PopulateSymbolTableWithName(Type callingType, ArgumentObject[] arguments)
+ => SymbolTable.PopulateSymbolTableWithName(Operation.GetCLROperatorName(), null, arguments[0].Type);
public bool IsBinderThatCanHaveRefReceiver => false;
- public bool IsChecked { get; }
-
- public Type CallingContext { get; }
-
private readonly CSharpArgumentInfo[] _argumentInfo;
CSharpArgumentInfo ICSharpBinder.GetArgumentInfo(int index) => _argumentInfo[index];
@@ -63,11 +59,9 @@ namespace Microsoft.CSharp.RuntimeBinder
IEnumerable<CSharpArgumentInfo> argumentInfo) :
base(operation)
{
- IsChecked = isChecked;
- CallingContext = callingContext;
_argumentInfo = BinderHelper.ToArray(argumentInfo);
Debug.Assert(_argumentInfo.Length == 1);
- _binder = RuntimeBinder.GetInstance();
+ _binder = new RuntimeBinder(callingContext, isChecked);
}
/// <summary>
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Error.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Error.cs
index 34e6a16154..b9968e57e2 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Error.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Error.cs
@@ -50,7 +50,5 @@ namespace Microsoft.CSharp.RuntimeBinder
internal static Exception DynamicArgumentNeedsValue(string paramName) =>
new ArgumentException(SR.DynamicArgumentNeedsValue, paramName);
-
- internal static Exception BindingNameCollision() => new RuntimeBinderException(SR.BindingNameCollision);
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Errors/ErrorCode.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Errors/ErrorCode.cs
index c762ace62d..d0003f4cd5 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Errors/ErrorCode.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Errors/ErrorCode.cs
@@ -16,7 +16,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
ERR_AmbigBinaryOps = 34,
ERR_AmbigUnaryOp = 35,
ERR_ValueCantBeNull = 37,
- ERR_WrongNestedThis = 38,
ERR_NoSuchMember = 117,
ERR_ObjectRequired = 120,
ERR_AmbigCall = 121,
@@ -59,9 +58,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
ERR_BindToBogusProp1 = 1546,
ERR_BadDelArgCount = 1593,
ERR_BadDelArgTypes = 1594,
- ERR_ReturnNotLValue = 1612,
- ERR_AssgReadonly2 = 1648,
- ERR_AssgReadonlyStatic2 = 1650,
ERR_BadCtorArgCount = 1729,
ERR_BadNamedArgument = 1739,
ERR_DuplicateNamedArgument = 1740,
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Errors/ErrorFacts.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Errors/ErrorFacts.cs
index 81c4f736d2..44faf2f157 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Errors/ErrorFacts.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Errors/ErrorFacts.cs
@@ -44,9 +44,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
case ErrorCode.ERR_ValueCantBeNull:
codeStr = SR.ValueCantBeNull;
break;
- case ErrorCode.ERR_WrongNestedThis:
- codeStr = SR.WrongNestedThis;
- break;
case ErrorCode.ERR_NoSuchMember:
codeStr = SR.NoSuchMember;
break;
@@ -173,15 +170,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
case ErrorCode.ERR_BadDelArgTypes:
codeStr = SR.BadDelArgTypes;
break;
- case ErrorCode.ERR_ReturnNotLValue:
- codeStr = SR.ReturnNotLValue;
- break;
- case ErrorCode.ERR_AssgReadonly2:
- codeStr = SR.AssgReadonly2;
- break;
- case ErrorCode.ERR_AssgReadonlyStatic2:
- codeStr = SR.AssgReadonlyStatic2;
- break;
case ErrorCode.ERR_BadCtorArgCount:
codeStr = SR.BadCtorArgCount;
break;
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Errors/ErrorHandling.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Errors/ErrorHandling.cs
index ded6351a7f..d7f95036ea 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Errors/ErrorHandling.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Errors/ErrorHandling.cs
@@ -9,16 +9,9 @@ using Microsoft.CSharp.RuntimeBinder.Semantics;
namespace Microsoft.CSharp.RuntimeBinder.Errors
{
- internal sealed class ErrorHandling
+ internal static class ErrorHandling
{
- private readonly UserStringBuilder _userStringBuilder;
-
- public ErrorHandling(GlobalSymbolContext globalSymbols)
- {
- _userStringBuilder = new UserStringBuilder(globalSymbols);
- }
-
- public RuntimeBinderException Error(ErrorCode id, params ErrArg[] args)
+ public static RuntimeBinderException Error(ErrorCode id, params ErrArg[] args)
{
// Create an argument array manually using the type information in the ErrArgs.
string[] prgpsz = new string[args.Length];
@@ -28,6 +21,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
int piarg = 0;
int cargUnique = 0;
+ UserStringBuilder builder = new UserStringBuilder();
+
for (int iarg = 0; iarg < args.Length; iarg++)
{
ErrArg arg = args[iarg];
@@ -37,7 +32,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
continue;
- if (!_userStringBuilder.ErrArgToString(out prgpsz[ppsz], arg, out bool fUserStrings))
+ if (!builder.ErrArgToString(out prgpsz[ppsz], arg, out bool fUserStrings))
{
if (arg.eak == ErrArgKind.Int)
{
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Errors/UserStringBuilder.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Errors/UserStringBuilder.cs
index ffa7518cb9..ba0b90b163 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Errors/UserStringBuilder.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Errors/UserStringBuilder.cs
@@ -10,36 +10,28 @@ using Microsoft.CSharp.RuntimeBinder.Syntax;
namespace Microsoft.CSharp.RuntimeBinder.Errors
{
- internal sealed class UserStringBuilder
+ internal struct UserStringBuilder
{
- private bool m_buildingInProgress;
- private GlobalSymbolContext m_globalSymbols;
- private StringBuilder m_strBuilder;
-
- public UserStringBuilder(
- GlobalSymbolContext globalSymbols)
- {
- Debug.Assert(globalSymbols != null);
- m_buildingInProgress = false;
- m_globalSymbols = globalSymbols;
- }
+ private StringBuilder _strBuilder;
private void BeginString()
{
- Debug.Assert(!m_buildingInProgress);
- m_buildingInProgress = true;
- m_strBuilder = new StringBuilder();
+ Debug.Assert(_strBuilder == null || _strBuilder.Length == 0);
+ if(_strBuilder == null)
+ {
+ _strBuilder = new StringBuilder();
+ }
}
- private void EndString(out string s)
+ private string EndString()
{
- Debug.Assert(m_buildingInProgress);
- m_buildingInProgress = false;
- s = m_strBuilder.ToString();
- m_strBuilder = null;
+ Debug.Assert(_strBuilder != null);
+ string s = _strBuilder.ToString();
+ _strBuilder.Clear();
+ return s;
}
- private void ErrSK(out string psz, SYMKIND sk)
+ private static string ErrSK(SYMKIND sk)
{
MessageID id;
switch (sk)
@@ -74,7 +66,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
break;
}
- ErrId(out psz, id);
+ return ErrId(id);
}
/*
* Create a fill-in string describing a parameter list.
@@ -105,12 +97,12 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
private void ErrAppendString(string str)
{
- m_strBuilder.Append(str);
+ _strBuilder.Append(str);
}
private void ErrAppendChar(char ch)
{
- m_strBuilder.Append(ch);
+ _strBuilder.Append(ch);
}
private void ErrAppendPrintf(string format, params object[] args)
@@ -141,9 +133,9 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
return;
}
- if (pctx != null && !pctx.FNop() && parent is AggregateSymbol agg && 0 != agg.GetTypeVarsAll().Count)
+ if (pctx != null && !pctx.IsNop && parent is AggregateSymbol agg && 0 != agg.GetTypeVarsAll().Count)
{
- CType pType = GetTypeManager().SubstType(agg.getThisType(), pctx);
+ CType pType = TypeManager.SubstType(agg.getThisType(), pctx);
ErrAppendType(pType, null);
}
else
@@ -153,7 +145,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
ErrAppendChar('.');
}
- private void ErrAppendTypeParameters(TypeArray @params, SubstContext pctx, bool forClass)
+ private void ErrAppendTypeParameters(TypeArray @params, SubstContext pctx)
{
if (@params != null && @params.Count != 0)
{
@@ -175,100 +167,108 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
ErrAppendParentSym(meth, pctx);
// Get the type args from the explicit impl type and substitute using pctx (if there is one).
- SubstContext ctx = new SubstContext(GetTypeManager().SubstType(meth.swtSlot.GetType(), pctx));
+ SubstContext ctx = new SubstContext(TypeManager.SubstType(meth.swtSlot.GetType(), pctx));
ErrAppendSym(meth.swtSlot.Sym, ctx, fArgs);
// args already added
return;
}
- if (meth.isPropertyAccessor())
+ MethodKindEnum methodKind = meth.MethKind;
+ switch (methodKind)
{
- PropertySymbol prop = meth.getProperty();
+ case MethodKindEnum.PropAccessor:
+ PropertySymbol prop = meth.getProperty();
- // this includes the parent class
- ErrAppendSym(prop, pctx);
+ // this includes the parent class
+ ErrAppendSym(prop, pctx);
- // add accessor name
- if (prop.GetterMethod == meth)
- {
- ErrAppendString(".get");
- }
- else
- {
- Debug.Assert(meth == prop.SetterMethod);
- ErrAppendString(".set");
- }
+ // add accessor name
+ if (prop.GetterMethod == meth)
+ {
+ ErrAppendString(".get");
+ }
+ else
+ {
+ Debug.Assert(meth == prop.SetterMethod);
+ ErrAppendString(".set");
+ }
- // args already added
- return;
- }
+ // args already added
+ return;
- if (meth.isEventAccessor())
- {
- EventSymbol @event = meth.getEvent();
+ case MethodKindEnum.EventAccessor:
+ EventSymbol @event = meth.getEvent();
- // this includes the parent class
- ErrAppendSym(@event, pctx);
+ // this includes the parent class
+ ErrAppendSym(@event, pctx);
- // add accessor name
- if (@event.methAdd == meth)
- {
- ErrAppendString(".add");
- }
- else
- {
- Debug.Assert(meth == @event.methRemove);
- ErrAppendString(".remove");
- }
+ // add accessor name
+ if (@event.methAdd == meth)
+ {
+ ErrAppendString(".add");
+ }
+ else
+ {
+ Debug.Assert(meth == @event.methRemove);
+ ErrAppendString(".remove");
+ }
- // args already added
- return;
+ // args already added
+ return;
}
ErrAppendParentSym(meth, pctx);
- if (meth.IsConstructor())
+ switch (methodKind)
{
- // Use the name of the parent class instead of the name "<ctor>".
- ErrAppendName(meth.getClass().name);
- }
- else if (meth.IsDestructor())
- {
- // Use the name of the parent class instead of the name "Finalize".
- ErrAppendChar('~');
- ErrAppendName(meth.getClass().name);
- }
- else if (meth.isConversionOperator())
- {
- // implicit/explicit
- ErrAppendString(meth.isImplicit() ? "implicit" : "explicit");
- ErrAppendString(" operator ");
+ case MethodKindEnum.Constructor:
+ // Use the name of the parent class instead of the name "<ctor>".
+ ErrAppendName(meth.getClass().name);
+ break;
- // destination type name
- ErrAppendType(meth.RetType, pctx);
- }
- else if (meth.isOperator)
- {
- // handle user defined operators
- // map from CLS predefined names to "operator <X>"
- ErrAppendString("operator ");
- ErrAppendString(Operators.OperatorOfMethodName(meth.name));
- }
- else if (!meth.IsExpImpl())
- {
- // regular method
- ErrAppendName(meth.name);
+ case MethodKindEnum.Destructor:
+ // Use the name of the parent class instead of the name "Finalize".
+ ErrAppendChar('~');
+ goto case MethodKindEnum.Constructor;
+
+ case MethodKindEnum.ExplicitConv:
+ ErrAppendString("explicit");
+ goto convOperatorName;
+
+ case MethodKindEnum.ImplicitConv:
+ ErrAppendString("implicit");
+
+ convOperatorName:
+ ErrAppendString(" operator ");
+
+ // destination type name
+ ErrAppendType(meth.RetType, pctx);
+ break;
+
+ default:
+ if (meth.isOperator)
+ {
+ // handle user defined operators
+ // map from CLS predefined names to "operator <X>"
+ ErrAppendString("operator ");
+ ErrAppendString(Operators.OperatorOfMethodName(meth.name));
+ }
+ else if (!meth.IsExpImpl())
+ {
+ // regular method
+ ErrAppendName(meth.name);
+ }
+
+ break;
}
- ErrAppendTypeParameters(meth.typeVars, pctx, false);
+ ErrAppendTypeParameters(meth.typeVars, pctx);
if (fArgs)
{
// append argument types
ErrAppendChar('(');
-
- ErrAppendParamList(GetTypeManager().SubstTypeArray(meth.Params, pctx), meth.isParamArray);
-
+ ErrAppendParamList(TypeManager.SubstTypeArray(meth.Params, pctx), meth.isParamArray);
ErrAppendChar(')');
}
}
@@ -276,7 +276,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
private void ErrAppendIndexer(IndexerSymbol indexer, SubstContext pctx)
{
ErrAppendString("this[");
- ErrAppendParamList(GetTypeManager().SubstTypeArray(indexer.Params, pctx), indexer.isParamArray);
+ ErrAppendParamList(TypeManager.SubstTypeArray(indexer.Params, pctx), indexer.isParamArray);
ErrAppendChar(']');
}
private void ErrAppendProperty(PropertySymbol prop, SubstContext pctx)
@@ -286,7 +286,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
{
if (prop.swtSlot.Sym != null)
{
- SubstContext ctx = new SubstContext(GetTypeManager().SubstType(prop.swtSlot.GetType(), pctx));
+ SubstContext ctx = new SubstContext(TypeManager.SubstType(prop.swtSlot.GetType(), pctx));
ErrAppendSym(prop.swtSlot.Sym, ctx);
}
else if (prop is IndexerSymbol indexer)
@@ -305,16 +305,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
}
}
- private void ErrAppendEvent(EventSymbol @event, SubstContext pctx)
- {
- }
-
- private void ErrAppendId(MessageID id)
- {
- string str;
- ErrId(out str, id);
- ErrAppendString(str);
- }
+ private void ErrAppendId(MessageID id) => ErrAppendString(ErrId(id));
/*
* Create a fill-in string describing a symbol.
@@ -328,10 +319,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
{
switch (sym.getKind())
{
- case SYMKIND.SK_AggregateDeclaration:
- ErrAppendSym(((AggregateDeclaration)sym).Agg(), pctx);
- break;
-
case SYMKIND.SK_AggregateSymbol:
{
// Check for a predefined class with a special "nice" name for
@@ -346,7 +333,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
{
ErrAppendParentSym(sym, pctx);
ErrAppendName(sym.name);
- ErrAppendTypeParameters(((AggregateSymbol)sym).GetTypeVars(), pctx, true);
+ ErrAppendTypeParameters(((AggregateSymbol)sym).GetTypeVars(), pctx);
}
break;
}
@@ -360,7 +347,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
break;
case SYMKIND.SK_EventSymbol:
- ErrAppendEvent((EventSymbol)sym, pctx);
break;
case SYMKIND.SK_NamespaceSymbol:
@@ -406,24 +392,14 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
}
}
- private void ErrAppendType(CType pType, SubstContext pCtx)
- {
- ErrAppendType(pType, pCtx, true);
- }
-
- private void ErrAppendType(CType pType, SubstContext pctx, bool fArgs)
+ private void ErrAppendType(CType pType, SubstContext pctx)
{
- if (pctx != null)
+ if (pctx != null && !pctx.IsNop)
{
- if (!pctx.FNop())
- {
- pType = GetTypeManager().SubstType(pType, pctx);
- }
- // We shouldn't use the SubstContext again so set it to NULL.
- pctx = null;
+ pType = TypeManager.SubstType(pType, pctx);
}
- switch (pType.GetTypeKind())
+ switch (pType.TypeKind)
{
case TypeKind.TK_AggregateType:
{
@@ -431,7 +407,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
// Check for a predefined class with a special "nice" name for
// error reported.
- string text = PredefinedTypes.GetNiceName(pAggType.getAggregate());
+ string text = PredefinedTypes.GetNiceName(pAggType.OwningAggregate);
if (text != null)
{
// Found a nice name.
@@ -439,38 +415,42 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
}
else
{
- if (pAggType.outerType != null)
+ if (pAggType.OuterType != null)
{
- ErrAppendType(pAggType.outerType, pctx);
+ ErrAppendType(pAggType.OuterType, null);
ErrAppendChar('.');
}
else
{
// In a namespace.
- ErrAppendParentSym(pAggType.getAggregate(), pctx);
+ ErrAppendParentSym(pAggType.OwningAggregate, null);
}
- ErrAppendName(pAggType.getAggregate().name);
+
+ ErrAppendName(pAggType.OwningAggregate.name);
}
- ErrAppendTypeParameters(pAggType.GetTypeArgsThis(), pctx, true);
+
+ ErrAppendTypeParameters(pAggType.TypeArgsThis, null);
break;
}
case TypeKind.TK_TypeParameterType:
- if (null == pType.GetName())
+ TypeParameterType tpType = (TypeParameterType)pType;
+ if (null == tpType.Name)
{
- var tpType = (TypeParameterType)pType;
// It's a standard type variable.
- if (tpType.IsMethodTypeParameter())
+ if (tpType.IsMethodTypeParameter)
{
ErrAppendChar('!');
}
+
ErrAppendChar('!');
- ErrAppendPrintf("{0}", tpType.GetIndexInTotalParameters());
+ ErrAppendPrintf("{0}", tpType.IndexInTotalParameters);
}
else
{
- ErrAppendName(pType.GetName());
+ ErrAppendName(tpType.Name);
}
+
break;
case TypeKind.TK_NullType:
@@ -488,21 +468,17 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
case TypeKind.TK_ArrayType:
{
- CType elementType = ((ArrayType)pType).GetBaseElementType();
+ CType elementType = ((ArrayType)pType).BaseElementType;
- if (null == elementType)
- {
- Debug.Assert(false, "No element type");
- break;
- }
+ Debug.Assert(elementType != null, "No element type");
- ErrAppendType(elementType, pctx);
+ ErrAppendType(elementType, null);
for (elementType = pType;
elementType is ArrayType arrType;
- elementType = arrType.GetElementType())
+ elementType = arrType.ElementType)
{
- int rank = arrType.rank;
+ int rank = arrType.Rank;
// Add [] with (rank-1) commas inside
ErrAppendChar('[');
@@ -535,15 +511,15 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
case TypeKind.TK_ParameterModifierType:
ParameterModifierType mod = (ParameterModifierType)pType;
// add ref or out
- ErrAppendString(mod.isOut ? "out " : "ref ");
+ ErrAppendString(mod.IsOut ? "out " : "ref ");
// add base type name
- ErrAppendType(mod.GetParameterType(), pctx);
+ ErrAppendType(mod.ParameterType, null);
break;
case TypeKind.TK_PointerType:
// Generate the base type.
- ErrAppendType(((PointerType)pType).GetReferentType(), pctx);
+ ErrAppendType(((PointerType)pType).ReferentType, null);
{
// add the trailing *
ErrAppendChar('*');
@@ -551,7 +527,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
break;
case TypeKind.TK_NullableType:
- ErrAppendType(((NullableType)pType).GetUnderlyingType(), pctx);
+ ErrAppendType(((NullableType)pType).UnderlyingType, null);
ErrAppendChar('?');
break;
@@ -572,18 +548,18 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
switch (parg.eak)
{
case ErrArgKind.SymKind:
- ErrSK(out psz, parg.sk);
+ psz = ErrSK(parg.sk);
break;
case ErrArgKind.Type:
BeginString();
ErrAppendType(parg.pType, null);
- EndString(out psz);
+ psz = EndString();
fUserStrings = true;
break;
case ErrArgKind.Sym:
BeginString();
ErrAppendSym(parg.sym, null);
- EndString(out psz);
+ psz = EndString();
fUserStrings = true;
break;
case ErrArgKind.Name:
@@ -605,7 +581,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
SubstContext ctx = new SubstContext(parg.swtMemo.ats, null);
BeginString();
ErrAppendSym(parg.swtMemo.sym, ctx, true);
- EndString(out psz);
+ psz = EndString();
fUserStrings = true;
break;
}
@@ -615,7 +591,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
SubstContext ctx = new SubstContext(parg.mpwiMemo.ats, parg.mpwiMemo.typeArgs);
BeginString();
ErrAppendSym(parg.mpwiMemo.sym, ctx, true);
- EndString(out psz);
+ psz = EndString();
fUserStrings = true;
break;
}
@@ -627,14 +603,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Errors
return result;
}
- private TypeManager GetTypeManager()
- {
- return m_globalSymbols.GetTypes();
- }
-
- private void ErrId(out string s, MessageID id)
- {
- s = ErrorFacts.GetMessage(id);
- }
+ private static string ErrId(MessageID id) => ErrorFacts.GetMessage(id);
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ExpressionTreeCallRewriter.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ExpressionTreeCallRewriter.cs
index e2274d1bc3..0cbde82943 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ExpressionTreeCallRewriter.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ExpressionTreeCallRewriter.cs
@@ -29,25 +29,23 @@ namespace Microsoft.CSharp.RuntimeBinder
private readonly Dictionary<ExprCall, Expression> _DictionaryOfParameters;
private readonly Expression[] _ListOfParameters;
- private readonly TypeManager _typeManager;
- // Counts how many EXPRSAVEs we've encountered so we know which index into the
+ // Counts how many EXPRSAVEs we've encountered so we know which index into the
// parameter list we should be taking.
private int _currentParameterIndex;
/////////////////////////////////////////////////////////////////////////////////
- private ExpressionTreeCallRewriter(TypeManager typeManager, Expression[] listOfParameters)
+ private ExpressionTreeCallRewriter(Expression[] listOfParameters)
{
- _typeManager = typeManager;
_DictionaryOfParameters = new Dictionary<ExprCall, Expression>();
_ListOfParameters = listOfParameters;
}
/////////////////////////////////////////////////////////////////////////////////
- public static Expression Rewrite(TypeManager typeManager, ExprBinOp binOp, Expression[] listOfParameters)
+ public static Expression Rewrite(ExprBinOp binOp, Expression[] listOfParameters)
{
- ExpressionTreeCallRewriter rewriter = new ExpressionTreeCallRewriter(typeManager, listOfParameters);
+ ExpressionTreeCallRewriter rewriter = new ExpressionTreeCallRewriter(listOfParameters);
// We should have a ExprBinOp that's an EK_SEQUENCE. The RHS of our sequence
// should be a call to PM_EXPRESSION_LAMBDA. The LHS of our sequence is the
@@ -260,7 +258,7 @@ namespace Microsoft.CSharp.RuntimeBinder
}
Expression obj = null;
- MethodInfo m = GetMethodInfoFromExpr(methinfo);
+ MethodInfo m = methinfo.MethodInfo;
Expression[] arguments = GetArgumentsFromArrayInit(arrinit);
if (m == null)
@@ -333,7 +331,7 @@ namespace Microsoft.CSharp.RuntimeBinder
}
Debug.Assert((pExpr.Flags & EXPRFLAG.EXF_UNBOXRUNTIME) == 0);
- MethodInfo m = GetMethodInfoFromExpr((ExprMethodInfo)list2.OptionalNextListNode);
+ MethodInfo m = ((ExprMethodInfo)list2.OptionalNextListNode).MethodInfo;
if (pm == PREDEFMETH.PM_EXPRESSION_CONVERT_USER_DEFINED)
{
@@ -395,7 +393,7 @@ namespace Microsoft.CSharp.RuntimeBinder
arguments = null;
}
- PropertyInfo p = GetPropertyInfoFromExpr(propinfo);
+ PropertyInfo p = propinfo.PropertyInfo;
if (p == null)
{
@@ -455,20 +453,19 @@ namespace Microsoft.CSharp.RuntimeBinder
{
ExprList list = (ExprList)pExpr.OptionalArguments;
- var constructor = GetConstructorInfoFromExpr(list.OptionalElement as ExprMethodInfo);
- var arguments = GetArgumentsFromArrayInit(list.OptionalNextListNode as ExprArrayInit);
+ ConstructorInfo constructor = ((ExprMethodInfo)list.OptionalElement).ConstructorInfo;
+ Expression[] arguments = GetArgumentsFromArrayInit(list.OptionalNextListNode as ExprArrayInit);
return Expression.New(constructor, arguments);
}
/////////////////////////////////////////////////////////////////////////////////
- private Expression GenerateConstantType(ExprCall pExpr)
+ private static Expression GenerateConstantType(ExprCall pExpr)
{
ExprList list = (ExprList)pExpr.OptionalArguments;
return Expression.Constant(
- GetObject(list.OptionalElement),
- ((ExprTypeOf)list.OptionalNextListNode).SourceType.AssociatedSystemType);
+ list.OptionalElement.Object, ((ExprTypeOf)list.OptionalNextListNode).SourceType.AssociatedSystemType);
}
/////////////////////////////////////////////////////////////////////////////////
@@ -560,11 +557,11 @@ namespace Microsoft.CSharp.RuntimeBinder
ExprConstant isLifted = (ExprConstant)next.OptionalElement;
Debug.Assert(isLifted != null);
bIsLifted = isLifted.Val.Int32Val == 1;
- methodInfo = GetMethodInfoFromExpr((ExprMethodInfo)next.OptionalNextListNode);
+ methodInfo = ((ExprMethodInfo)next.OptionalNextListNode).MethodInfo;
}
else
{
- methodInfo = GetMethodInfoFromExpr((ExprMethodInfo)list.OptionalNextListNode);
+ methodInfo = ((ExprMethodInfo)list.OptionalNextListNode).MethodInfo;
}
switch (pExpr.PredefinedMethod)
@@ -651,7 +648,7 @@ namespace Microsoft.CSharp.RuntimeBinder
PREDEFMETH pm = pExpr.PredefinedMethod;
ExprList list = (ExprList)pExpr.OptionalArguments;
Expression arg = GetExpression(list.OptionalElement);
- MethodInfo methodInfo = GetMethodInfoFromExpr((ExprMethodInfo)list.OptionalNextListNode);
+ MethodInfo methodInfo = ((ExprMethodInfo)list.OptionalNextListNode).MethodInfo;
switch (pm)
{
@@ -871,105 +868,6 @@ namespace Microsoft.CSharp.RuntimeBinder
}
}
- /////////////////////////////////////////////////////////////////////////////////
-
- private object GetObject(Expr pExpr)
- {
- for (;;)
- {
- if (pExpr is ExprCast cast)
- {
- pExpr = cast.Argument;
- }
- else if (pExpr is ExprTypeOf typeOf)
- {
- return typeOf.SourceType.AssociatedSystemType;
- }
- else if (pExpr is ExprMethodInfo methodInfo)
- {
- return GetMethodInfoFromExpr(methodInfo);
- }
- else if (pExpr is ExprConstant constant)
- {
- ConstVal val = constant.Val;
- CType underlyingType = pExpr.Type;
- object objval;
-
- if (pExpr.Type is NullType)
- {
- return null;
- }
-
- if (pExpr.Type.isEnumType())
- {
- underlyingType = underlyingType.getAggregate().GetUnderlyingType();
- }
-
- switch (Type.GetTypeCode(underlyingType.AssociatedSystemType))
- {
- case TypeCode.Boolean:
- objval = val.BooleanVal;
- break;
- case TypeCode.SByte:
- objval = val.SByteVal;
- break;
- case TypeCode.Byte:
- objval = val.ByteVal;
- break;
- case TypeCode.Int16:
- objval = val.Int16Val;
- break;
- case TypeCode.UInt16:
- objval = val.UInt16Val;
- break;
- case TypeCode.Int32:
- objval = val.Int32Val;
- break;
- case TypeCode.UInt32:
- objval = val.UInt32Val;
- break;
- case TypeCode.Int64:
- objval = val.Int64Val;
- break;
- case TypeCode.UInt64:
- objval = val.UInt64Val;
- break;
- case TypeCode.Single:
- objval = val.SingleVal;
- break;
- case TypeCode.Double:
- objval = val.DoubleVal;
- break;
- case TypeCode.Decimal:
- objval = val.DecimalVal;
- break;
- case TypeCode.Char:
- objval = val.CharVal;
- break;
- case TypeCode.String:
- objval = val.StringVal;
- break;
- default:
- objval = val.ObjectVal;
- break;
- }
-
- return pExpr.Type.isEnumType() ? Enum.ToObject(pExpr.Type.AssociatedSystemType, objval) : objval;
- }
- else if (pExpr is ExprZeroInit zeroInit)
- {
- return Activator.CreateInstance(zeroInit.Type.AssociatedSystemType);
- }
- else
- {
- Debug.Assert(false, "Invalid Expr in GetObject");
- throw Error.InternalCompilerError();
- }
- }
- }
-
- /////////////////////////////////////////////////////////////////////////////////
-
private Expression[] GetArgumentsFromArrayInit(ExprArrayInit arrinit)
{
List<Expression> expressions = new List<Expression>();
@@ -1000,202 +898,6 @@ namespace Microsoft.CSharp.RuntimeBinder
return expressions.ToArray();
}
- /////////////////////////////////////////////////////////////////////////////////
-
- private MethodInfo GetMethodInfoFromExpr(ExprMethodInfo methinfo)
- {
- // To do this, we need to construct a type array of the parameter types,
- // get the parent constructed type, and get the method from it.
-
- AggregateType aggType = methinfo.Method.Ats;
- MethodSymbol methSym = methinfo.Method.Meth();
-
- TypeArray genericParams = _typeManager.SubstTypeArray(methSym.Params, aggType, methSym.typeVars);
- CType genericReturn = _typeManager.SubstType(methSym.RetType, aggType, methSym.typeVars);
-
- Type type = aggType.AssociatedSystemType;
- MethodInfo methodInfo = methSym.AssociatedMemberInfo as MethodInfo;
-
- // This is to ensure that for embedded nopia types, we have the
- // appropriate local type from the member itself; this is possible
- // because nopia types are not generic or nested.
- if (!type.IsGenericType && !type.IsNested)
- {
- type = methodInfo.DeclaringType;
- }
-
- // We need to find the associated methodinfo on the instantiated type.
- foreach (MethodInfo m in type.GetRuntimeMethods())
- {
-#if UNSUPPORTEDAPI
- if ((m.MetadataToken != methodInfo.MetadataToken) || (m.Module != methodInfo.Module))
-#else
- if (!m.HasSameMetadataDefinitionAs(methodInfo))
-#endif
- {
- continue;
- }
-
- Debug.Assert((m.Name == methodInfo.Name) &&
- (m.GetParameters().Length == genericParams.Count) &&
- (TypesAreEqual(m.ReturnType, genericReturn.AssociatedSystemType)));
-
- bool bMatch = true;
- ParameterInfo[] parameters = m.GetParameters();
- for (int i = 0; i < genericParams.Count; i++)
- {
- if (!TypesAreEqual(parameters[i].ParameterType, genericParams[i].AssociatedSystemType))
- {
- bMatch = false;
- break;
- }
- }
- if (bMatch)
- {
- if (m.IsGenericMethod)
- {
- int size = methinfo.Method.TypeArgs?.Count ?? 0;
- Type[] typeArgs = new Type[size];
- if (size > 0)
- {
- for (int i = 0; i < methinfo.Method.TypeArgs.Count; i++)
- {
- typeArgs[i] = methinfo.Method.TypeArgs[i].AssociatedSystemType;
- }
- }
- return m.MakeGenericMethod(typeArgs);
- }
-
- return m;
- }
- }
-
- Debug.Assert(false, "Could not find matching method");
- throw Error.InternalCompilerError();
- }
-
- /////////////////////////////////////////////////////////////////////////////////
-
- private ConstructorInfo GetConstructorInfoFromExpr(ExprMethodInfo methinfo)
- {
- // To do this, we need to construct a type array of the parameter types,
- // get the parent constructed type, and get the method from it.
-
- AggregateType aggType = methinfo.Method.Ats;
- MethodSymbol methSym = methinfo.Method.Meth();
-
- TypeArray genericInstanceParams = _typeManager.SubstTypeArray(methSym.Params, aggType);
- Type type = aggType.AssociatedSystemType;
- ConstructorInfo ctorInfo = (ConstructorInfo)methSym.AssociatedMemberInfo;
-
- // This is to ensure that for embedded nopia types, we have the
- // appropriate local type from the member itself; this is possible
- // because nopia types are not generic or nested.
- if (!type.IsGenericType && !type.IsNested)
- {
- type = ctorInfo.DeclaringType;
- }
-
- foreach (ConstructorInfo c in type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
- {
-#if UNSUPPORTEDAPI
- if ((c.MetadataToken != ctorInfo.MetadataToken) || (c.Module != ctorInfo.Module))
-#else
- if (!c.HasSameMetadataDefinitionAs(ctorInfo))
-#endif
- {
- continue;
- }
- Debug.Assert(c.GetParameters() == null || c.GetParameters().Length == genericInstanceParams.Count);
-
- bool bMatch = true;
- ParameterInfo[] parameters = c.GetParameters();
- for (int i = 0; i < genericInstanceParams.Count; i++)
- {
- if (!TypesAreEqual(parameters[i].ParameterType, genericInstanceParams[i].AssociatedSystemType))
- {
- bMatch = false;
- break;
- }
- }
- if (bMatch)
- {
- return c;
- }
- }
-
- Debug.Assert(false, "Could not find matching constructor");
- throw Error.InternalCompilerError();
- }
-
- /////////////////////////////////////////////////////////////////////////////////
-
- private PropertyInfo GetPropertyInfoFromExpr(ExprPropertyInfo propinfo)
- {
- // To do this, we need to construct a type array of the parameter types,
- // get the parent constructed type, and get the property from it.
-
- AggregateType aggType = propinfo.Property.Ats;
- PropertySymbol propSym = propinfo.Property.Prop();
-
- TypeArray genericInstanceParams = _typeManager.SubstTypeArray(propSym.Params, aggType, null);
-
- Type type = aggType.AssociatedSystemType;
- PropertyInfo propertyInfo = propSym.AssociatedPropertyInfo;
-
- // This is to ensure that for embedded nopia types, we have the
- // appropriate local type from the member itself; this is possible
- // because nopia types are not generic or nested.
- if (!type.IsGenericType && !type.IsNested)
- {
- type = propertyInfo.DeclaringType;
- }
-
- foreach (PropertyInfo p in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
- {
-#if UNSUPPORTEDAPI
- if ((p.MetadataToken != propertyInfo.MetadataToken) || (p.Module != propertyInfo.Module))
-#else
- if (!p.HasSameMetadataDefinitionAs(propertyInfo))
- {
-#endif
- continue;
- }
- Debug.Assert((p.Name == propertyInfo.Name) &&
- (p.GetIndexParameters() == null || p.GetIndexParameters().Length == genericInstanceParams.Count));
-
- bool bMatch = true;
- ParameterInfo[] parameters = p.GetSetMethod(true) != null ?
- p.GetSetMethod(true).GetParameters() : p.GetGetMethod(true).GetParameters();
- for (int i = 0; i < genericInstanceParams.Count; i++)
- {
- if (!TypesAreEqual(parameters[i].ParameterType, genericInstanceParams[i].AssociatedSystemType))
- {
- bMatch = false;
- break;
- }
- }
- if (bMatch)
- {
- return p;
- }
- }
-
- Debug.Assert(false, "Could not find matching property");
- throw Error.InternalCompilerError();
- }
-
- /////////////////////////////////////////////////////////////////////////////////
-
- private bool TypesAreEqual(Type t1, Type t2)
- {
- if (t1 == t2)
- {
- return true;
- }
-
- return t1.IsEquivalentTo(t2);
- }
#endregion
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ICSharpBinder.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ICSharpBinder.cs
index e48f760fc2..84b60abb91 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ICSharpBinder.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ICSharpBinder.cs
@@ -10,19 +10,21 @@ namespace Microsoft.CSharp.RuntimeBinder
internal interface ICSharpBinder
{
CSharpArgumentInfo GetArgumentInfo(int index);
- Type CallingContext { get; }
- bool IsChecked { get; }
- // This is true for any binder that is eligible to take value type receiver
+ // This is true for any binder that is eligible to take value type receiver
// objects as a ref (for mutable operations). Such as calls ("v.M(d)"),
// and indexers ("v[d] = v[d]"). Note that properties are not here because they
// are only dispatched dynamically when the receiver is dynamic, and hence boxed.
bool IsBinderThatCanHaveRefReceiver { get; }
- void PopulateSymbolTableWithName(SymbolTable symbolTable, Type callingType, ArgumentObject[] arguments);
+ void PopulateSymbolTableWithName(Type callingType, ArgumentObject[] arguments);
Expr DispatchPayload(RuntimeBinder runtimeBinder, ArgumentObject[] arguments, LocalVariableSymbol[] locals);
+
BindingFlag BindingFlags { get; }
+
string Name { get; }
+
+ Type ReturnType { get; }
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/RuntimeBinder.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/RuntimeBinder.cs
index bb248567e0..af0014f80e 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/RuntimeBinder.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/RuntimeBinder.cs
@@ -14,72 +14,31 @@ using Microsoft.CSharp.RuntimeBinder.Syntax;
namespace Microsoft.CSharp.RuntimeBinder
{
- internal sealed class RuntimeBinder
+ internal readonly struct RuntimeBinder
{
- #region Singleton Implementation
+ private static readonly object s_bindLock = new object();
- private static readonly Lazy<RuntimeBinder> s_lazyInstance = new Lazy<RuntimeBinder>(() => new RuntimeBinder());
+ private readonly ExpressionBinder _binder;
- public static RuntimeBinder GetInstance()
+ public RuntimeBinder(Type contextType, bool isChecked = false)
{
- return s_lazyInstance.Value;
- }
-
- #endregion
-
- /////////////////////////////////////////////////////////////////////////////////
- // Members
-
- private SymbolTable _symbolTable;
- private CSemanticChecker _semanticChecker;
- private SymbolLoader SymbolLoader => _semanticChecker.SymbolLoader;
-
- private ExprFactory _exprFactory;
- private BindingContext _bindingContext;
- private ExpressionBinder _binder;
-
- private readonly object _bindLock = new object();
-
- /////////////////////////////////////////////////////////////////////////////////
- // Methods
-
- #region BookKeeping
- private RuntimeBinder()
- {
- Reset();
- }
+ AggregateSymbol context;
+ if (contextType != null)
+ {
+ lock (s_bindLock)
+ {
+ context = ((AggregateType)SymbolTable.GetCTypeFromType(contextType)).OwningAggregate;
+ }
+ }
+ else
+ {
+ context = null;
+ }
- private void Reset()
- {
- _semanticChecker = new CSemanticChecker();
-
- BSYMMGR bsymmgr = _semanticChecker.getBSymmgr();
-
- _symbolTable = new SymbolTable(
- bsymmgr.GetSymbolTable(),
- bsymmgr.GetSymFactory(),
- _semanticChecker.GetTypeManager(),
- bsymmgr,
- _semanticChecker);
- _semanticChecker.getPredefTypes().Init(_symbolTable);
- _semanticChecker.GetTypeManager().InitTypeFactory(_symbolTable);
- SymbolLoader.getPredefinedMembers().RuntimeBinderSymbolTable = _symbolTable;
- SymbolLoader.SetSymbolTable(_symbolTable);
-
- _exprFactory = new ExprFactory(_semanticChecker.SymbolLoader.GetGlobalSymbolContext());
- _bindingContext = new BindingContext(_semanticChecker, _exprFactory);
- _binder = new ExpressionBinder(_bindingContext);
+ _binder = new ExpressionBinder(new BindingContext(context, isChecked));
}
- #endregion
-
- /////////////////////////////////////////////////////////////////////////////////
-
- public Expression Bind(
- DynamicMetaObjectBinder payload,
- Expression[] parameters,
- DynamicMetaObject[] args,
- out DynamicMetaObject deferredBinding)
+ public Expression Bind(ICSharpBinder payload, Expression[] parameters, DynamicMetaObject[] args, out DynamicMetaObject deferredBinding)
{
// The lock is here to protect this instance of the binder from itself
// when called on multiple threads. The cost in time of a single lock
@@ -98,12 +57,9 @@ namespace Microsoft.CSharp.RuntimeBinder
// ...subsequent calls that were cache hits, i.e., already bound, took less
// than 1/1000 sec for the whole 4000 of them.
- ICSharpBinder binder = payload as ICSharpBinder;
- Debug.Assert(binder != null);
-
- lock (_bindLock)
+ lock (s_bindLock)
{
- return BindCore(binder, parameters, args, out deferredBinding);
+ return BindCore(payload, parameters, args, out deferredBinding);
}
}
@@ -115,26 +71,25 @@ namespace Microsoft.CSharp.RuntimeBinder
{
Debug.Assert(args.Length >= 1);
- InitializeCallingContext(payload);
ArgumentObject[] arguments = CreateArgumentArray(payload, parameters, args);
// On any given bind call, we populate the symbol table with any new
// conversions that we find for any of the types specified. We keep a
- // running SymbolTable so that we don't have to reflect over types if
+ // running SymbolTable so that we don't have to reflect over types if
// we've seen them already in the table.
//
// Once we've loaded all the standard conversions into the symbol table,
// we can call into the binder to bind the actual call.
- payload.PopulateSymbolTableWithName(_symbolTable, arguments[0].Type, arguments);
+ payload.PopulateSymbolTableWithName(arguments[0].Type, arguments);
AddConversionsForArguments(arguments);
// When we do any bind, we perform the following steps:
//
// 1) Create a local variable scope which contains local variable symbols
// for each of the parameters, and the instance argument.
- // 2) If we have operators, then we don't need to do lookup. Otherwise,
- // look for the name and switch on the result - dispatch according to
+ // 2) If we have operators, then we don't need to do lookup. Otherwise,
+ // look for the name and switch on the result - dispatch according to
// the symbol kind. This results in an Expr being bound that is the expression.
// 3) Create the EXPRRETURN which returns the call and wrap it in
// an EXPRBOUNDLAMBDA which uses the local variable scope
@@ -145,7 +100,7 @@ namespace Microsoft.CSharp.RuntimeBinder
// Linq expression tree for the whole thing and return it.
// (1) - Create the locals
- Scope pScope = _semanticChecker.GetGlobalSymbolFactory().CreateScope();
+ Scope pScope = SymFactory.CreateScope();
LocalVariableSymbol[] locals = PopulateLocalScope(payload, pScope, arguments, parameters);
// (1.5) - Check to see if we need to defer.
@@ -163,6 +118,13 @@ namespace Microsoft.CSharp.RuntimeBinder
#region Helpers
+ [ConditionalAttribute("DEBUG")]
+ internal static void EnsureLockIsTaken()
+ {
+ // Make sure that the binder lock is taken
+ Debug.Assert(System.Threading.Monitor.IsEntered(s_bindLock));
+ }
+
private bool DeferBinding(
ICSharpBinder payload,
ArgumentObject[] arguments,
@@ -175,7 +137,7 @@ namespace Microsoft.CSharp.RuntimeBinder
// (1) InvokeMember deferral.
//
- // This is the deferral for the d.Foo() scenario where Foo actually binds to a
+ // This is the deferral for the d.Foo() scenario where Foo actually binds to a
// field or property, and not a method group that is invocable. We defer to
// the standard GetMember/Invoke pattern.
@@ -186,10 +148,10 @@ namespace Microsoft.CSharp.RuntimeBinder
MemberLookup mem = new MemberLookup();
Expr callingObject = CreateCallingObjectForCall(callPayload, arguments, locals);
- SymWithType swt = _symbolTable.LookupMember(
+ SymWithType swt = SymbolTable.LookupMember(
callPayload.Name,
callingObject,
- _bindingContext.ContextForMemberLookup,
+ _binder.Context.ContextForMemberLookup,
arity,
mem,
(callPayload.Flags & CSharpCallFlags.EventHookup) != 0,
@@ -218,42 +180,16 @@ namespace Microsoft.CSharp.RuntimeBinder
return false;
}
- private void InitializeCallingContext(ICSharpBinder payload)
- {
- // Set the context if the payload specifies it. Currently we only use this for calls.
- Type t = payload.CallingContext;
- BindingContext bindingContext = _bindingContext;
-
- if (t != null)
- {
- AggregateSymbol agg = ((AggregateType)_symbolTable.GetCTypeFromType(t)).GetOwningAggregate();
- bindingContext.ContextForMemberLookup = _semanticChecker.GetGlobalSymbolFactory().CreateAggregateDecl(agg, null);
- }
- else
- {
- // The binding context lives across invocations! If we don't reset this, then later calls might
- // bind in a previous call's context.
- bindingContext.ContextForMemberLookup = null;
- }
-
- bindingContext.Checked = payload.IsChecked;
- }
-
- /////////////////////////////////////////////////////////////////////////////////
-
- private Expression CreateExpressionTreeFromResult(
- Expression[] parameters,
- Scope pScope,
- Expr pResult)
+ private static Expression CreateExpressionTreeFromResult(Expression[] parameters, Scope pScope, Expr pResult)
{
// (3) - Place the result in a return statement and create the ExprBoundLambda.
ExprBoundLambda boundLambda = GenerateBoundLambda(pScope, pResult);
// (4) - Rewrite the ExprBoundLambda into an expression tree.
- ExprBinOp exprTree = ExpressionTreeRewriter.Rewrite(boundLambda, _exprFactory, SymbolLoader);
+ ExprBinOp exprTree = ExpressionTreeRewriter.Rewrite(boundLambda);
// (5) - Create the actual Expression Tree
- Expression e = ExpressionTreeCallRewriter.Rewrite(SymbolLoader.GetTypeManager(), exprTree, parameters);
+ Expression e = ExpressionTreeCallRewriter.Rewrite(exprTree, parameters);
return e;
}
@@ -265,7 +201,7 @@ namespace Microsoft.CSharp.RuntimeBinder
if (argInfo.IsByRefOrOut)
{
// If we have a ref our an out parameter, make the byref type.
- // If we have the receiver of a call or invoke that is ref, it must be because of
+ // If we have the receiver of a call or invoke that is ref, it must be because of
// a struct caller. Don't persist the ref for that.
if (!(index == 0 && p.IsBinderThatCanHaveRefReceiver))
{
@@ -281,17 +217,13 @@ namespace Microsoft.CSharp.RuntimeBinder
// This ensures that the type we pick is something that the user could have written.
- CType actualType = _symbolTable.GetCTypeFromType(t);
- CType bestType;
-
- bool res = _semanticChecker.GetTypeManager().GetBestAccessibleType(_semanticChecker, _bindingContext, actualType, out bestType);
-
// Since the actual type of these arguments are never going to be pointer
// types or ref/out types (they are in fact boxed into an object), we have
// a guarantee that we will always be able to find a best accessible type
// (which, in the worst case, may be object).
- Debug.Assert(res, "Unexpected failure of GetBestAccessibleType in construction of argument array");
+ CType actualType = SymbolTable.GetCTypeFromType(t);
+ CType bestType = TypeManager.GetBestAccessibleType(_binder.Context.ContextForMemberLookup, actualType);
t = bestType.AssociatedSystemType;
}
@@ -323,8 +255,7 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
internal static void PopulateSymbolTableWithPayloadInformation(
- SymbolTable symbolTable, ICSharpInvokeOrInvokeMemberBinder callOrInvoke, Type callingType,
- ArgumentObject[] arguments)
+ ICSharpInvokeOrInvokeMemberBinder callOrInvoke, Type callingType, ArgumentObject[] arguments)
{
Type type;
@@ -340,18 +271,19 @@ namespace Microsoft.CSharp.RuntimeBinder
{
type = callingType;
}
- symbolTable.PopulateSymbolTableWithName(
+
+ SymbolTable.PopulateSymbolTableWithName(
callOrInvoke.Name,
callOrInvoke.TypeArguments,
type);
// If it looks like we're invoking a get_ or a set_, load the property as well.
- // This is because we need COM indexed properties called via method calls to
+ // This is because we need COM indexed properties called via method calls to
// work the same as it used to.
if (callOrInvoke.Name.StartsWith("set_", StringComparison.Ordinal) ||
callOrInvoke.Name.StartsWith("get_", StringComparison.Ordinal))
{
- symbolTable.PopulateSymbolTableWithName(
+ SymbolTable.PopulateSymbolTableWithName(
callOrInvoke.Name.Substring(4), //remove prefix
callOrInvoke.TypeArguments,
type);
@@ -360,11 +292,11 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
- private void AddConversionsForArguments(ArgumentObject[] arguments)
+ private static void AddConversionsForArguments(ArgumentObject[] arguments)
{
foreach (ArgumentObject arg in arguments)
{
- _symbolTable.AddConversionsForType(arg.Type);
+ SymbolTable.AddConversionsForType(arg.Type);
}
}
@@ -374,29 +306,29 @@ namespace Microsoft.CSharp.RuntimeBinder
BindCall(payload, CreateCallingObjectForCall(payload, arguments, locals), arguments, locals);
/////////////////////////////////////////////////////////////////////////////////
- // We take the ArgumentObjects to verify - if the parameter expression tells us
+ // We take the ArgumentObjects to verify - if the parameter expression tells us
// we have a ref parameter, but the argument object tells us we're not passed by ref,
// then it means it was a ref that the compiler had to insert. This is used when
- // we have a call off of a struct for example. If thats the case, don't treat the
+ // we have a call off of a struct for example. If thats the case, don't treat the
// local as a ref type.
- private LocalVariableSymbol[] PopulateLocalScope(
+ private static LocalVariableSymbol[] PopulateLocalScope(
ICSharpBinder payload,
Scope pScope,
ArgumentObject[] arguments,
Expression[] parameterExpressions)
{
- // We use the compile time types for the local variables, and then
+ // We use the compile time types for the local variables, and then
// cast them to the runtime types for the expression tree.
LocalVariableSymbol[] locals = new LocalVariableSymbol[parameterExpressions.Length];
for (int i = 0; i < parameterExpressions.Length; i++)
{
Expression parameter = parameterExpressions[i];
- CType type = _symbolTable.GetCTypeFromType(parameter.Type);
+ CType type = SymbolTable.GetCTypeFromType(parameter.Type);
// Make sure we're not setting ref for the receiver of a call - the argument
- // will be marked as ref if we're calling off a struct, but we don't want
+ // will be marked as ref if we're calling off a struct, but we don't want
// to persist that in our system.
// If we're the first param of a call or invoke, and we're ref, it must be
// because of structs. Don't persist the parameter modifier type.
@@ -409,13 +341,12 @@ namespace Microsoft.CSharp.RuntimeBinder
CSharpArgumentInfo info = arguments[i].Info;
if (info.IsByRefOrOut)
{
- type = _semanticChecker.GetTypeManager().GetParameterModifier(type, info.IsOut);
+ type = TypeManager.GetParameterModifier(type, info.IsOut);
}
}
}
LocalVariableSymbol local =
- _semanticChecker.GetGlobalSymbolFactory()
- .CreateLocalVar(NameManager.Add("p" + i), pScope, type);
+ SymFactory.CreateLocalVar(NameManager.Add("p" + i), pScope, type);
locals[i] = local;
}
@@ -424,37 +355,38 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
- private ExprBoundLambda GenerateBoundLambda(
- Scope pScope,
- Expr call)
+ private static ExprBoundLambda GenerateBoundLambda(Scope pScope, Expr call)
{
// We don't actually need the real delegate type here - we just need SOME delegate type.
// This is because we never attempt any conversions on the lambda itself.
- AggregateType delegateType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_FUNC);
- return _exprFactory.CreateAnonymousMethod(delegateType, pScope, call);
+ AggregateType delegateType = SymbolLoader.GetPredefindType(PredefinedType.PT_FUNC);
+ return ExprFactory.CreateAnonymousMethod(delegateType, pScope, call);
}
#region ExprCreation
/////////////////////////////////////////////////////////////////////////////////
- private Expr CreateLocal(Type type, bool bIsOut, LocalVariableSymbol local)
+ private Expr CreateLocal(Type type, bool isOut, LocalVariableSymbol local)
{
- CType ctype = _symbolTable.GetCTypeFromType(type);
- if (bIsOut)
+ CType ctype;
+ if (isOut)
{
- Debug.Assert(ctype is ParameterModifierType);
- ctype = _semanticChecker.GetTypeManager()
- .GetParameterModifier(((ParameterModifierType)ctype).GetParameterType(), true);
+ // We need to record the out state, but GetCTypeFromType will only determine that
+ // it should be some sort of ParameterType but not be able to deduce that it needs
+ // IsOut to be true. So do that logic here rather than create a ref type to then
+ // throw away.
+ Debug.Assert(type.IsByRef);
+ ctype = TypeManager.GetParameterModifier(SymbolTable.GetCTypeFromType(type.GetElementType()), true);
}
-
- // If we can convert, do that. If not, cast it.
- ExprLocal exprLocal = _exprFactory.CreateLocal(local);
- Expr result = _binder.tryConvert(exprLocal, ctype);
- if (result == null)
+ else
{
- result = _binder.mustCast(exprLocal, ctype);
+ ctype = SymbolTable.GetCTypeFromType(type);
}
+
+ // If we can convert, do that. If not, cast it.
+ ExprLocal exprLocal = ExprFactory.CreateLocal(local);
+ Expr result = _binder.tryConvert(exprLocal, ctype) ?? _binder.mustCast(exprLocal, ctype);
result.Flags |= EXPRFLAG.EXF_LVALUE;
return result;
}
@@ -485,7 +417,7 @@ namespace Microsoft.CSharp.RuntimeBinder
else
{
// Lists are right-heavy.
- _exprFactory.AppendItemToList(arg, ref args, ref last);
+ ExprFactory.AppendItemToList(arg, ref args, ref last);
}
}
}
@@ -503,16 +435,16 @@ namespace Microsoft.CSharp.RuntimeBinder
{
if (argument.Info.UseCompileTimeType)
{
- arg = _exprFactory.CreateConstant(_symbolTable.GetCTypeFromType(argument.Type), default(ConstVal));
+ arg = ExprFactory.CreateConstant(SymbolTable.GetCTypeFromType(argument.Type), default(ConstVal));
}
else
{
- arg = _exprFactory.CreateNull();
+ arg = ExprFactory.CreateNull();
}
}
else
{
- arg = _exprFactory.CreateConstant(_symbolTable.GetCTypeFromType(argument.Type), ConstVal.Get(argument.Value));
+ arg = ExprFactory.CreateConstant(SymbolTable.GetCTypeFromType(argument.Type), ConstVal.Get(argument.Value));
}
}
else
@@ -522,7 +454,7 @@ namespace Microsoft.CSharp.RuntimeBinder
if (!argument.Info.UseCompileTimeType && argument.Value == null)
{
- arg = _exprFactory.CreateNull();
+ arg = ExprFactory.CreateNull();
}
else
{
@@ -534,7 +466,7 @@ namespace Microsoft.CSharp.RuntimeBinder
if (argument.Info.NamedArgument)
{
Debug.Assert(argument.Info.Name != null);
- arg = _exprFactory.CreateNamedArgumentSpecification(NameManager.Add(argument.Info.Name), arg);
+ arg = ExprFactory.CreateNamedArgumentSpecification(NameManager.Add(argument.Info.Name), arg);
}
// If we have an object that was "dynamic" at compile time, we need
@@ -555,7 +487,7 @@ namespace Microsoft.CSharp.RuntimeBinder
if (!argument.Info.UseCompileTimeType && argument.Value != null)
{
arg.RuntimeObject = argument.Value;
- arg.RuntimeObjectActualType = _symbolTable.GetCTypeFromType(argument.Value.GetType());
+ arg.RuntimeObjectActualType = SymbolTable.GetCTypeFromType(argument.Value.GetType());
}
return arg;
@@ -563,7 +495,7 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
- private ExprMemberGroup CreateMemberGroupEXPR(
+ private static ExprMemberGroup CreateMemberGroupExpr(
string Name,
Type[] typeArguments,
Expr callingObject,
@@ -575,7 +507,7 @@ namespace Microsoft.CSharp.RuntimeBinder
CType callingObjectType = callingObject.Type;
if (callingObjectType is ArrayType)
{
- callingType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_ARRAY);
+ callingType = SymbolLoader.GetPredefindType(PredefinedType.PT_ARRAY);
}
else if (callingObjectType is NullableType callingNub)
{
@@ -618,7 +550,7 @@ namespace Microsoft.CSharp.RuntimeBinder
bool bIsConstructor = name == NameManager.GetPredefinedName(PredefinedName.PN_CTOR);
foreach(AggregateType t in callingType.TypeHierarchy)
{
- if (_symbolTable.AggregateContainsMethod(t.GetOwningAggregate(), Name, mask) && distinctCallingTypes.Add(t))
+ if (SymbolTable.AggregateContainsMethod(t.OwningAggregate, Name, mask) && distinctCallingTypes.Add(t))
{
callingTypes.Add(t);
}
@@ -630,13 +562,13 @@ namespace Microsoft.CSharp.RuntimeBinder
}
}
- // If this is a WinRT type we have to add all collection interfaces that have this method
+ // If this is a WinRT type we have to add all collection interfaces that have this method
// as well so that overload resolution can find them.
- if (callingType.IsWindowsRuntimeType())
+ if (callingType.IsWindowsRuntimeType)
{
- foreach (AggregateType t in callingType.GetWinRTCollectionIfacesAll(SymbolLoader).Items)
+ foreach (AggregateType t in callingType.WinRTCollectionIfacesAll.Items)
{
- if (_symbolTable.AggregateContainsMethod(t.GetOwningAggregate(), Name, mask) && distinctCallingTypes.Add(t))
+ if (SymbolTable.AggregateContainsMethod(t.OwningAggregate, Name, mask) && distinctCallingTypes.Add(t))
{
callingTypes.Add(t);
}
@@ -645,7 +577,7 @@ namespace Microsoft.CSharp.RuntimeBinder
EXPRFLAG flags = EXPRFLAG.EXF_USERCALLABLE;
// If its a delegate, mark that on the memgroup.
- if (Name == SpecialNames.Invoke && callingObject.Type.isDelegateType())
+ if (Name == SpecialNames.Invoke && callingObject.Type.IsDelegateType)
{
flags |= EXPRFLAG.EXF_DELEGATE;
}
@@ -662,16 +594,13 @@ namespace Microsoft.CSharp.RuntimeBinder
flags |= EXPRFLAG.EXF_INDEXER;
}
- TypeArray typeArgumentsAsTypeArray = BSYMMGR.EmptyTypeArray();
- if (typeArguments != null && typeArguments.Length > 0)
- {
- typeArgumentsAsTypeArray = _semanticChecker.getBSymmgr().AllocParams(
- _symbolTable.GetCTypeArrayFromTypes(typeArguments));
- }
- ExprMemberGroup memgroup = _exprFactory.CreateMemGroup(// Tree
- flags, name, typeArgumentsAsTypeArray, kind, callingType, null, null, new CMemberLookupResults(
- _semanticChecker.getBSymmgr().AllocParams(callingTypes.Count, callingTypes.ToArray()),
- name));
+ TypeArray typeArgumentsAsTypeArray = typeArguments?.Length > 0
+ ? TypeArray.Allocate(SymbolTable.GetCTypeArrayFromTypes(typeArguments))
+ : TypeArray.Empty;
+
+ ExprMemberGroup memgroup = ExprFactory.CreateMemGroup( // Tree
+ flags, name, typeArgumentsAsTypeArray, kind, callingType, null,
+ new CMemberLookupResults(TypeArray.Allocate(callingTypes.ToArray()), name));
if (callingObject is ExprClass)
{
memgroup.OptionalLHS = callingObject;
@@ -696,7 +625,7 @@ namespace Microsoft.CSharp.RuntimeBinder
PropertySymbol property = swt.Prop();
AggregateType propertyType = swt.GetType();
PropWithType pwt = new PropWithType(property, propertyType);
- ExprMemberGroup pMemGroup = CreateMemberGroupEXPR(property.name.Text, null, callingObject, SYMKIND.SK_PropertySymbol);
+ ExprMemberGroup pMemGroup = CreateMemberGroupExpr(property.name.Text, null, callingObject, SYMKIND.SK_PropertySymbol);
return _binder.BindToProperty(// For a static property instance, don't set the object.
callingObject is ExprClass ? null : callingObject, pwt, flags, null, pMemGroup);
@@ -707,7 +636,7 @@ namespace Microsoft.CSharp.RuntimeBinder
private ExprWithArgs CreateIndexer(SymWithType swt, Expr callingObject, Expr arguments, BindingFlag bindFlags)
{
IndexerSymbol index = swt.Sym as IndexerSymbol;
- ExprMemberGroup memgroup = CreateMemberGroupEXPR(index.name.Text, null, callingObject, SYMKIND.SK_PropertySymbol);
+ ExprMemberGroup memgroup = CreateMemberGroupExpr(index.name.Text, null, callingObject, SYMKIND.SK_PropertySymbol);
ExprWithArgs result = _binder.BindMethodGroupToArguments(bindFlags, memgroup, arguments);
ReorderArgumentsForNamedAndOptional(callingObject, result);
return result;
@@ -758,7 +687,7 @@ namespace Microsoft.CSharp.RuntimeBinder
Type t = arguments[0].Value as Type;
Debug.Assert(t != null); // Would have thrown in PopulateSymbolTableWithPayloadInformation already
- callingObject = _exprFactory.CreateClass(_symbolTable.GetCTypeFromType(t));
+ callingObject = ExprFactory.CreateClass(SymbolTable.GetCTypeFromType(t));
}
else
{
@@ -770,7 +699,7 @@ namespace Microsoft.CSharp.RuntimeBinder
callingObject = _binder.mustConvert(
CreateArgumentEXPR(arguments[0], locals[0]),
- _symbolTable.GetCTypeFromType(arguments[0].Type));
+ SymbolTable.GetCTypeFromType(arguments[0].Type));
if (arguments[0].Type.IsValueType && callingObject is ExprCast)
{
@@ -789,7 +718,7 @@ namespace Microsoft.CSharp.RuntimeBinder
ArgumentObject[] arguments,
LocalVariableSymbol[] locals)
{
- if (payload is InvokeBinder && !callingObject.Type.isDelegateType())
+ if (payload is InvokeBinder && !callingObject.Type.IsDelegateType)
{
throw Error.BindInvokeFailedNonDelegate();
}
@@ -797,10 +726,10 @@ namespace Microsoft.CSharp.RuntimeBinder
int arity = payload.TypeArguments?.Length ?? 0;
MemberLookup mem = new MemberLookup();
- SymWithType swt = _symbolTable.LookupMember(
+ SymWithType swt = SymbolTable.LookupMember(
payload.Name,
callingObject,
- _bindingContext.ContextForMemberLookup,
+ _binder.Context.ContextForMemberLookup,
arity,
mem,
(payload.Flags & CSharpCallFlags.EventHookup) != 0,
@@ -826,11 +755,11 @@ namespace Microsoft.CSharp.RuntimeBinder
//
// Our caller takes care of the rest.
- // First we need to check the sym that we got back. If we got back a static
+ // First we need to check the sym that we got back. If we got back a static
// method, then we may be in the situation where the user called the method
// via a simple name call through the phantom overload. If thats the case,
// then we want to sub in a type instead of the object.
- ExprMemberGroup memGroup = CreateMemberGroupEXPR(payload.Name, payload.TypeArguments, callingObject, swt.Sym.getKind());
+ ExprMemberGroup memGroup = CreateMemberGroupExpr(payload.Name, payload.TypeArguments, callingObject, swt.Sym.getKind());
if ((payload.Flags & CSharpCallFlags.SimpleNameCall) != 0)
{
callingObject.Flags |= EXPRFLAG.EXF_SIMPLENAME;
@@ -839,10 +768,10 @@ namespace Microsoft.CSharp.RuntimeBinder
if ((payload.Flags & CSharpCallFlags.EventHookup) != 0)
{
mem = new MemberLookup();
- SymWithType swtEvent = _symbolTable.LookupMember(
+ SymWithType swtEvent = SymbolTable.LookupMember(
payload.Name.Split('_')[1],
callingObject,
- _bindingContext.ContextForMemberLookup,
+ _binder.Context.ContextForMemberLookup,
arity,
mem,
(payload.Flags & CSharpCallFlags.EventHookup) != 0,
@@ -862,7 +791,7 @@ namespace Microsoft.CSharp.RuntimeBinder
eventCType = swtEvent.Event().type;
}
- Type eventType = SymbolLoader.GetTypeManager().SubstType(eventCType, swtEvent.Ats).AssociatedSystemType;
+ Type eventType = TypeManager.SubstType(eventCType, swtEvent.Ats).AssociatedSystemType;
if (eventType != null)
{
@@ -911,11 +840,11 @@ namespace Microsoft.CSharp.RuntimeBinder
// Get new Action<EventRegistrationToken>(x.remove_foo)
MethPropWithInst removemwi = new MethPropWithInst(ewt.Event().methRemove, ewt.Ats);
- ExprMemberGroup removeMethGrp = _exprFactory.CreateMemGroup(callingObject, removemwi);
+ ExprMemberGroup removeMethGrp = ExprFactory.CreateMemGroup(callingObject, removemwi);
removeMethGrp.Flags &= ~EXPRFLAG.EXF_USERCALLABLE;
Type eventRegistrationTokenType = SymbolTable.EventRegistrationTokenType;
Type actionType = Expression.GetActionType(eventRegistrationTokenType);
- Expr removeMethArg = _binder.mustConvert(removeMethGrp, _symbolTable.GetCTypeFromType(actionType));
+ Expr removeMethArg = _binder.mustConvert(removeMethGrp, SymbolTable.GetCTypeFromType(actionType));
// The value
Expr delegateVal = CreateArgumentEXPR(arguments[1], locals[1]);
@@ -926,25 +855,25 @@ namespace Microsoft.CSharp.RuntimeBinder
{
// Get new Func<delegType, EventRegistrationToken>(x.add_foo)
MethPropWithInst addmwi = new MethPropWithInst(ewt.Event().methAdd, ewt.Ats);
- ExprMemberGroup addMethGrp = _exprFactory.CreateMemGroup(callingObject, addmwi);
+ ExprMemberGroup addMethGrp = ExprFactory.CreateMemGroup(callingObject, addmwi);
addMethGrp.Flags &= ~EXPRFLAG.EXF_USERCALLABLE;
Type funcType = Expression.GetFuncType(evtType, eventRegistrationTokenType);
- Expr addMethArg = _binder.mustConvert(addMethGrp, _symbolTable.GetCTypeFromType(funcType));
+ Expr addMethArg = _binder.mustConvert(addMethGrp, SymbolTable.GetCTypeFromType(funcType));
- args = _exprFactory.CreateList(addMethArg, removeMethArg, delegateVal);
+ args = ExprFactory.CreateList(addMethArg, removeMethArg, delegateVal);
methodName = NameManager.GetPredefinedName(PredefinedName.PN_ADDEVENTHANDLER).Text;
}
else
{
- args = _exprFactory.CreateList(removeMethArg, delegateVal);
+ args = ExprFactory.CreateList(removeMethArg, delegateVal);
methodName = NameManager.GetPredefinedName(PredefinedName.PN_REMOVEEVENTHANDLER).Text;
}
// WindowsRuntimeMarshal.Add\RemoveEventHandler(...)
Type windowsRuntimeMarshalType = SymbolTable.WindowsRuntimeMarshalType;
- _symbolTable.PopulateSymbolTableWithName(methodName, new List<Type> { evtType }, windowsRuntimeMarshalType);
- ExprClass marshalClass = _exprFactory.CreateClass(_symbolTable.GetCTypeFromType(windowsRuntimeMarshalType));
- ExprMemberGroup addEventGrp = CreateMemberGroupEXPR(methodName, new [] { evtType }, marshalClass, SYMKIND.SK_MethodSymbol);
+ SymbolTable.PopulateSymbolTableWithName(methodName, new List<Type> { evtType }, windowsRuntimeMarshalType);
+ ExprClass marshalClass = ExprFactory.CreateClass(SymbolTable.GetCTypeFromType(windowsRuntimeMarshalType));
+ ExprMemberGroup addEventGrp = CreateMemberGroupExpr(methodName, new [] { evtType }, marshalClass, SYMKIND.SK_MethodSymbol);
return _binder.BindMethodGroupToArguments(
BindingFlag.BIND_RVALUEREQUIRED | BindingFlag.BIND_STMTEXPRONLY,
addEventGrp,
@@ -990,49 +919,33 @@ namespace Microsoft.CSharp.RuntimeBinder
{
carg = ExpressionBinder.CountArguments(arguments)
};
- _binder.FillInArgInfoFromArgList(argInfo, arguments);
+ ExpressionBinder.FillInArgInfoFromArgList(argInfo, arguments);
// We need to substitute type parameters BEFORE getting the most derived one because
- // we're binding against the base method, and the derived method may change the
- // generic arguments.
- TypeArray parameters = SymbolLoader.GetTypeManager().SubstTypeArray(methprop.Params, type, typeArgs);
- methprop = ExpressionBinder.GroupToArgsBinder.FindMostDerivedMethod(SymbolLoader, methprop, callingObject.Type);
+ // we're binding against the base method, and the derived method may change the
+ // generic arguments.
+ TypeArray parameters = TypeManager.SubstTypeArray(methprop.Params, type, typeArgs);
+ methprop = ExpressionBinder.GroupToArgsBinder.FindMostDerivedMethod(methprop, callingObject.Type);
ExpressionBinder.GroupToArgsBinder.ReOrderArgsForNamedArguments(
- methprop,
- parameters,
- type,
- memgroup,
- argInfo,
- _semanticChecker.GetTypeManager(),
- _exprFactory,
- SymbolLoader);
- {
- Expr pList = null;
+ methprop, parameters, type, memgroup, argInfo);
+ Expr pList = null;
- // We reordered, so make a new list of them and set them on the constructor.
- // Go backwards cause lists are right-flushed.
- // Also perform the conversions to the right types.
- for (int i = argInfo.carg - 1; i >= 0; i--)
- {
- Expr pArg = argInfo.prgexpr[i];
+ // We reordered, so make a new list of them and set them on the constructor.
+ // Go backwards cause lists are right-flushed.
+ // Also perform the conversions to the right types.
+ for (int i = argInfo.carg - 1; i >= 0; i--)
+ {
+ Expr pArg = argInfo.prgexpr[i];
- // Strip the name-ness away, since we don't need it.
- pArg = StripNamedArgument(pArg);
+ // Strip the name-ness away, since we don't need it.
+ pArg = StripNamedArgument(pArg);
- // Perform the correct conversion.
- pArg = _binder.tryConvert(pArg, parameters[i]);
- if (pList == null)
- {
- pList = pArg;
- }
- else
- {
- pList = _exprFactory.CreateList(pArg, pList);
- }
- }
-
- result.OptionalArguments = pList;
+ // Perform the correct conversion.
+ pArg = _binder.tryConvert(pArg, parameters[i]);
+ pList = pList == null ? pArg : ExprFactory.CreateList(pArg, pList);
}
+
+ result.OptionalArguments = pList;
}
private Expr StripNamedArgument(Expr pArg)
@@ -1099,20 +1012,15 @@ namespace Microsoft.CSharp.RuntimeBinder
result = _binder.BindStandardUnaryOperator(OperatorKind.OP_LOGNOT, result);
}
- if (result == null)
- {
- result = _binder.bindUDUnop(op == OperatorKind.OP_TRUE ? ExpressionKind.True : ExpressionKind.False, arg1);
- }
+ return result
+ ?? _binder.bindUDUnop(op == OperatorKind.OP_TRUE ? ExpressionKind.True : ExpressionKind.False, arg1)
+ // If the result is STILL null, then that means theres no implicit conversion to bool,
+ // and no user-defined operators for true and false. Just do a must convert to report
+ // the error.
+ ?? _binder.mustConvert(arg1, SymbolLoader.GetPredefindType(PredefinedType.PT_BOOL));
- // If the result is STILL null, then that means theres no implicit conversion to bool,
- // and no user-defined operators for true and false. Just do a must convert to report
- // the error.
- if (result == null)
- {
- result = _binder.mustConvert(arg1, SymbolLoader.GetPredefindType(PredefinedType.PT_BOOL));
- }
- return result;
}
+
return _binder.BindStandardUnaryOperator(op, arg1);
}
#endregion
@@ -1251,7 +1159,7 @@ namespace Microsoft.CSharp.RuntimeBinder
{
// If our argument is a static type, then we're calling a static property.
Expr callingObject = argument.Info.IsStaticType ?
- _exprFactory.CreateClass(_symbolTable.GetCTypeFromType(argument.Value as Type)) :
+ ExprFactory.CreateClass(SymbolTable.GetCTypeFromType(argument.Value as Type)) :
CreateLocal(argument.Type, argument.Info.IsOut, local);
if (!argument.Info.UseCompileTimeType && argument.Value == null)
@@ -1269,7 +1177,7 @@ namespace Microsoft.CSharp.RuntimeBinder
BindingFlag bindFlags = payload.BindingFlags;
MemberLookup mem = new MemberLookup();
- SymWithType swt = _symbolTable.LookupMember(name, callingObject, _bindingContext.ContextForMemberLookup, 0, mem, false, false);
+ SymWithType swt = SymbolTable.LookupMember(name, callingObject, _binder.Context.ContextForMemberLookup, 0, mem, false, false);
if (swt == null)
{
if (optionalIndexerArguments != null)
@@ -1282,9 +1190,9 @@ namespace Microsoft.CSharp.RuntimeBinder
{
if (type.IsArray && type.GetArrayRank() != numIndexArguments)
{
- throw _semanticChecker.ErrorContext.Error(ErrorCode.ERR_BadIndexCount, type.GetArrayRank());
+ throw ErrorHandling.Error(ErrorCode.ERR_BadIndexCount, type.GetArrayRank());
}
-
+
Debug.Assert(callingObject.Type is ArrayType);
return CreateArray(callingObject, optionalIndexerArguments);
}
@@ -1335,10 +1243,10 @@ namespace Microsoft.CSharp.RuntimeBinder
Debug.Assert(arguments.Length == 1);
// Load the conversions on the target.
- _symbolTable.AddConversionsForType(returnType);
+ SymbolTable.AddConversionsForType(returnType);
Expr argument = CreateArgumentEXPR(arguments[0], locals[0]);
- CType destinationType = _symbolTable.GetCTypeFromType(returnType);
+ CType destinationType = SymbolTable.GetCTypeFromType(returnType);
if (bIsArrayCreationConversion)
{
@@ -1369,10 +1277,10 @@ namespace Microsoft.CSharp.RuntimeBinder
Debug.Assert(arguments.Length == 1);
// Load the conversions on the target.
- _symbolTable.AddConversionsForType(returnType);
+ SymbolTable.AddConversionsForType(returnType);
Expr argument = CreateArgumentEXPR(arguments[0], locals[0]);
- CType destinationType = _symbolTable.GetCTypeFromType(returnType);
+ CType destinationType = SymbolTable.GetCTypeFromType(returnType);
return _binder.mustCast(argument, destinationType);
}
@@ -1409,7 +1317,8 @@ namespace Microsoft.CSharp.RuntimeBinder
indexerArguments = null;
bIsCompound = (payload as CSharpSetMemberBinder).IsCompoundAssignment;
}
- _symbolTable.PopulateSymbolTableWithName(name, null, arguments[0].Type);
+
+ SymbolTable.PopulateSymbolTableWithName(name, null, arguments[0].Type);
Expr lhs = BindProperty(payload, arguments[0], locals[0], indexerArguments);
int indexOfLast = arguments.Length - 1;
@@ -1426,7 +1335,7 @@ namespace Microsoft.CSharp.RuntimeBinder
ArgumentObject[] arguments,
LocalVariableSymbol[] locals)
{
- // The IsEvent binder will never be called without an instance object. This
+ // The IsEvent binder will never be called without an instance object. This
// is because the compiler only gen's this code for dynamic dots.
Expr callingObject = CreateLocal(arguments[0].Type, false, locals[0]);
@@ -1439,10 +1348,10 @@ namespace Microsoft.CSharp.RuntimeBinder
throw Error.NullReferenceOnMemberException();
}
- SymWithType swt = _symbolTable.LookupMember(
+ SymWithType swt = SymbolTable.LookupMember(
binder.Name,
callingObject,
- _bindingContext.ContextForMemberLookup,
+ _binder.Context.ContextForMemberLookup,
0,
mem,
false,
@@ -1466,7 +1375,7 @@ namespace Microsoft.CSharp.RuntimeBinder
}
}
- return _exprFactory.CreateConstant(boolType, ConstVal.Get(result));
+ return ExprFactory.CreateConstant(boolType, ConstVal.Get(result));
}
#endregion
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/BinOpArgInfo.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/BinOpArgInfo.cs
index 17e1f6d029..ce1b858616 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/BinOpArgInfo.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/BinOpArgInfo.cs
@@ -7,7 +7,7 @@ using Microsoft.CSharp.RuntimeBinder.Syntax;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
- internal sealed partial class ExpressionBinder
+ internal readonly partial struct ExpressionBinder
{
private sealed class BinOpArgInfo
{
@@ -21,10 +21,10 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
type2 = arg2.Type;
typeRaw1 = type1.StripNubs();
typeRaw2 = type2.StripNubs();
- pt1 = type1.isPredefined() ? type1.getPredefType() : PredefinedType.PT_COUNT;
- pt2 = type2.isPredefined() ? type2.getPredefType() : PredefinedType.PT_COUNT;
- ptRaw1 = typeRaw1.isPredefined() ? typeRaw1.getPredefType() : PredefinedType.PT_COUNT;
- ptRaw2 = typeRaw2.isPredefined() ? typeRaw2.getPredefType() : PredefinedType.PT_COUNT;
+ pt1 = type1.IsPredefined ? type1.PredefinedType : PredefinedType.PT_COUNT;
+ pt2 = type2.IsPredefined ? type2.PredefinedType : PredefinedType.PT_COUNT;
+ ptRaw1 = typeRaw1.IsPredefined ? typeRaw1.PredefinedType : PredefinedType.PT_COUNT;
+ ptRaw2 = typeRaw2.IsPredefined ? typeRaw2.PredefinedType : PredefinedType.PT_COUNT;
}
public Expr arg1;
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/BinOpSig.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/BinOpSig.cs
index db41f04f30..6a4efe072f 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/BinOpSig.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/BinOpSig.cs
@@ -7,7 +7,7 @@ using Microsoft.CSharp.RuntimeBinder.Syntax;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
- internal sealed partial class ExpressionBinder
+ internal readonly partial struct ExpressionBinder
{
private class BinOpSig
{
@@ -85,8 +85,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
this.grfos = bos.grfos;
this.fnkind = bos.fnkind;
- _type1 = pt1 != PredefinedType.PT_UNDEFINEDINDEX ? fnc.GetPredefindType(pt1) : null;
- _type2 = pt2 != PredefinedType.PT_UNDEFINEDINDEX ? fnc.GetPredefindType(pt2) : null;
+ _type1 = pt1 != PredefinedType.PT_UNDEFINEDINDEX ? GetPredefindType(pt1) : null;
+ _type2 = pt2 != PredefinedType.PT_UNDEFINEDINDEX ? GetPredefindType(pt2) : null;
_grflt = LiftFlags.None;
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Binding/Better.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Binding/Better.cs
index 6fe31c29fd..de077e9f4b 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Binding/Better.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Binding/Better.cs
@@ -9,7 +9,7 @@ using Microsoft.CSharp.RuntimeBinder.Syntax;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
- internal sealed partial class ExpressionBinder
+ internal readonly partial struct ExpressionBinder
{
////////////////////////////////////////////////////////////////////////////////
// This table is used to implement the last set of 'better' conversion rules
@@ -38,7 +38,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
new byte[] /* OBJECT*/ {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}
};
- private BetterType WhichMethodIsBetterTieBreaker(
+ private static BetterType WhichMethodIsBetterTieBreaker(
CandidateFunctionMember node1,
CandidateFunctionMember node2,
CType pTypeThrough,
@@ -83,7 +83,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
// See if one's parameter types (un-instantiated) are more specific.
- BetterType nT = GetGlobalSymbols().CompareTypes(
+ BetterType nT = CompareTypes(
RearrangeNamedArguments(mpwi1.MethProp().Params, mpwi1, pTypeThrough, args),
RearrangeNamedArguments(mpwi2.MethProp().Params, mpwi2, pTypeThrough, args));
if (nT == BetterType.Left || nT == BetterType.Right)
@@ -101,6 +101,79 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return BetterType.Neither;
}
+ private static BetterType CompareTypes(TypeArray ta1, TypeArray ta2)
+ {
+ if (ta1 == ta2)
+ {
+ return BetterType.Same;
+ }
+
+ if (ta1.Count != ta2.Count)
+ {
+ // The one with more parameters is more specific.
+ return ta1.Count > ta2.Count ? BetterType.Left : BetterType.Right;
+ }
+
+ BetterType nTot = BetterType.Neither;
+
+ for (int i = 0; i < ta1.Count; i++)
+ {
+ CType type1 = ta1[i];
+ CType type2 = ta2[i];
+ BetterType nParam = BetterType.Neither;
+
+LAgain:
+ if (type1.TypeKind != type2.TypeKind)
+ {
+ if (type1 is TypeParameterType)
+ {
+ nParam = BetterType.Right;
+ }
+ else if (type2 is TypeParameterType)
+ {
+ nParam = BetterType.Left;
+ }
+ }
+ else
+ {
+ switch (type1.TypeKind)
+ {
+ default:
+ Debug.Assert(false, "Bad kind in CompareTypes");
+ break;
+ case TypeKind.TK_TypeParameterType:
+ break;
+
+ case TypeKind.TK_PointerType:
+ case TypeKind.TK_ParameterModifierType:
+ case TypeKind.TK_ArrayType:
+ case TypeKind.TK_NullableType:
+ type1 = type1.BaseOrParameterOrElementType;
+ type2 = type2.BaseOrParameterOrElementType;
+ goto LAgain;
+
+ case TypeKind.TK_AggregateType:
+ nParam = CompareTypes(((AggregateType)type1).TypeArgsAll, ((AggregateType)type2).TypeArgsAll);
+ break;
+ }
+ }
+
+ if (nParam == BetterType.Right || nParam == BetterType.Left)
+ {
+ if (nTot == BetterType.Same || nTot == BetterType.Neither)
+ {
+ nTot = nParam;
+ }
+ else if (nParam != nTot)
+ {
+ return BetterType.Neither;
+ }
+ }
+ }
+
+ return nTot;
+ }
+
////////////////////////////////////////////////////////////////////////////////
// Find the index of a name on a list.
@@ -126,8 +199,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// By rearranging the arguments as such we make sure that any specified named arguments appear in the same position for both
// methods and we also maintain the relative order of the other parameters (the type long appears after int in the above example)
- private TypeArray RearrangeNamedArguments(TypeArray pta, MethPropWithInst mpwi,
- CType pTypeThrough, ArgInfos args)
+ private static TypeArray RearrangeNamedArguments(TypeArray pta, MethPropWithInst mpwi, CType pTypeThrough, ArgInfos args)
{
#if DEBUG
// We never have a named argument that is in a position in the argument
@@ -147,7 +219,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
CType type = pTypeThrough != null ? pTypeThrough : mpwi.GetType();
CType[] typeList = new CType[pta.Count];
- MethodOrPropertySymbol methProp = GroupToArgsBinder.FindMostDerivedMethod(GetSymbolLoader(), mpwi.MethProp(), type);
+ MethodOrPropertySymbol methProp = GroupToArgsBinder.FindMostDerivedMethod(mpwi.MethProp(), type);
// We initialize the new type array with the parameters for the method.
for (int iParam = 0; iParam < pta.Count; iParam++)
@@ -179,7 +251,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
}
- return GetSymbolLoader().getBSymmgr().AllocParams(pta.Count, typeList);
+ return TypeArray.Allocate(typeList);
}
////////////////////////////////////////////////////////////////////////////////
@@ -386,12 +458,12 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return a2b ? BetterType.Left : BetterType.Right;
}
- if (p1.isPredefined() && p2.isPredefined())
+ if (p1.IsPredefined && p2.IsPredefined)
{
- PredefinedType pt1 = p1.getPredefType();
+ PredefinedType pt1 = p1.PredefinedType;
if (pt1 <= PredefinedType.PT_OBJECT)
{
- PredefinedType pt2 = p2.getPredefType();
+ PredefinedType pt2 = p2.PredefinedType;
if (pt2 <= PredefinedType.PT_OBJECT)
{
return (BetterType)s_betterConversionTable[(int)pt1][(int)pt2];
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Binding/ErrorReporting.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Binding/ErrorReporting.cs
deleted file mode 100644
index b697f078b5..0000000000
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Binding/ErrorReporting.cs
+++ /dev/null
@@ -1,107 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Diagnostics;
-using Microsoft.CSharp.RuntimeBinder.Errors;
-
-namespace Microsoft.CSharp.RuntimeBinder.Semantics
-{
- internal sealed partial class ExpressionBinder
- {
- private RuntimeBinderException ReportReadOnlyError(ExprField field, bool isNested)
- {
- Debug.Assert(field != null);
-
- FieldWithType fieldWithType = field.FieldWithType;
- bool isStatic = fieldWithType.Field().isStatic;
- ErrArg[] args;
- ErrorCode err;
- if (isNested)
- {
- args = new ErrArg[]{ fieldWithType };
- err = isStatic ? ErrorCode.ERR_AssgReadonlyStatic2 : ErrorCode.ERR_AssgReadonly2;
- }
- else
- {
- args = Array.Empty<ErrArg>();
- err = isStatic ? ErrorCode.ERR_AssgReadonlyStatic : ErrorCode.ERR_AssgReadonly;
- }
-
- return ErrorContext.Error(err, args);
- }
-
- private void TryReportLvalueFailure(Expr expr, CheckLvalueKind kind)
- {
- Debug.Assert(expr != null);
- Debug.Assert(!(expr is ExprLocal));
-
- // We have a lvalue failure. Was the reason because this field
- // was marked readonly? Give special messages for this case.
-
- bool isNested = false; // Did we recurse on a field or property to give a better error?
-
- while (true)
- {
- Debug.Assert(expr != null);
-
- Expr pObject = null;
-
- if (expr is ExprProperty prop)
- {
- // We've already reported read-only-property errors.
- Debug.Assert(prop.MethWithTypeSet != null);
- pObject = prop.MemberGroup.OptionalObject;
- }
- else if (expr is ExprField field)
- {
- if (field.FieldWithType.Field().isReadOnly)
- {
- throw ReportReadOnlyError(field, isNested);
- }
- if (!field.FieldWithType.Field().isStatic)
- {
- pObject = field.OptionalObject;
- }
- }
-
- if (pObject != null && pObject.Type.isStructOrEnum())
- {
- if (pObject is ExprWithArgs withArgs)
- {
- // assigning to RHS of method or property getter returning a value-type on the stack or
- // passing RHS of method or property getter returning a value-type on the stack, as ref or out
- throw ErrorContext.Error(ErrorCode.ERR_ReturnNotLValue, withArgs.GetSymWithType());
- }
- if (pObject is ExprCast)
- {
- // An unboxing conversion.
- //
- // In the static compiler, we give the following error here:
- // ErrorContext.Error(pObject.GetTree(), ErrorCode.ERR_UnboxNotLValue);
- //
- // But in the runtime, we allow this - mark that we're doing an
- // unbox here, so that we gen the correct expression tree for it.
- pObject.Flags |= EXPRFLAG.EXF_UNBOXRUNTIME;
- return;
- }
- }
-
- // everything else
- if (pObject != null && !pObject.isLvalue() && (expr is ExprField || !isNested))
- {
- Debug.Assert(pObject.Type.isStructOrEnum());
- Debug.Assert(!(pObject is ExprLocal));
- expr = pObject;
- }
- else
- {
- throw ErrorContext.Error(GetStandardLvalueError(kind));
- }
-
- isNested = true;
- }
- }
- }
-}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/BindingContext.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/BindingContext.cs
index 18783d2792..cfbdee42ae 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/BindingContext.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/BindingContext.cs
@@ -2,8 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Diagnostics;
-
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
// ----------------------------------------------------------------------------
@@ -11,36 +9,23 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// consumed by the StatementBinder.
// ----------------------------------------------------------------------------
- internal sealed class BindingContext
+ internal readonly struct BindingContext
{
- public BindingContext(CSemanticChecker semanticChecker, ExprFactory exprFactory)
+ public BindingContext(AggregateSymbol context, bool isChecked)
{
- Debug.Assert(semanticChecker != null);
- ExprFactory = exprFactory;
- SemanticChecker = semanticChecker;
- SymbolLoader = semanticChecker.SymbolLoader;
+ ContextForMemberLookup = context;
+ Checked = isChecked;
}
public BindingContext(BindingContext parent)
- : this(parent.SemanticChecker, parent.ExprFactory)
{
// We copy the context object, but leave checking false.
ContextForMemberLookup = parent.ContextForMemberLookup;
+ Checked = false;
}
- //The SymbolLoader can be retrieved from SemanticChecker,
- //but that is a virtual call that is showing up on the profiler. Retrieve
- //the SymbolLoader once at construction and return a cached copy.
-
- // PERFORMANCE: Is this cache still necessary?
- public SymbolLoader SymbolLoader { get; }
-
- public AggregateDeclaration ContextForMemberLookup { get; set; }
-
- public CSemanticChecker SemanticChecker { get; }
-
- public ExprFactory ExprFactory { get; }
+ public AggregateSymbol ContextForMemberLookup { get; }
- public bool Checked { get; set; }
+ public bool Checked { get; }
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Conversion.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Conversion.cs
index 584a151650..4d7771f698 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Conversion.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Conversion.cs
@@ -40,7 +40,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Neither = 3,
}
- internal sealed partial class ExpressionBinder
+ internal readonly partial struct ExpressionBinder
{
private delegate bool ConversionFunc(
Expr pSourceExpr,
@@ -259,11 +259,11 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
return BetterType.Same;
}
- if (typeGiven.isPredefType(pt1))
+ if (typeGiven.IsPredefType(pt1))
{
return BetterType.Left;
}
- if (typeGiven.isPredefType(pt2))
+ if (typeGiven.IsPredefType(pt2))
{
return BetterType.Right;
}
@@ -312,14 +312,14 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
if (!(type1 is NullableType nub1) || !(type2 is NullableType nub2) ||
- !nub1.UnderlyingType.isPredefined() ||
- !nub2.UnderlyingType.isPredefined())
+ !nub1.UnderlyingType.IsPredefined ||
+ !nub2.UnderlyingType.IsPredefined)
{
return BetterType.Neither;
}
- PredefinedType pt1 = (type1 as NullableType).UnderlyingType.getPredefType();
- PredefinedType pt2 = (type2 as NullableType).UnderlyingType.getPredefType();
+ PredefinedType pt1 = (type1 as NullableType).UnderlyingType.PredefinedType;
+ PredefinedType pt2 = (type2 as NullableType).UnderlyingType.PredefinedType;
if ((int)pt1 < NUM_EXT_TYPES && (int)pt2 < NUM_EXT_TYPES)
{
@@ -351,8 +351,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (BindImplicitConversion(expr, expr.Type, dest, out Expr exprResult, flags))
{
// Conversion works.
- checkUnsafe(expr.Type); // added to the binder so we don't bind to pointer ops
- checkUnsafe(dest); // added to the binder so we don't bind to pointer ops
+ CheckUnsafe(expr.Type); // added to the binder so we don't bind to pointer ops
+ CheckUnsafe(dest); // added to the binder so we don't bind to pointer ops
return exprResult;
}
@@ -360,29 +360,29 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// For certain situations, try to give a better error.
- FUNDTYPE ftSrc = expr.Type.fundType();
- FUNDTYPE ftDest = dest.fundType();
+ FUNDTYPE ftSrc = expr.Type.FundamentalType;
+ FUNDTYPE ftDest = dest.FundamentalType;
if (expr is ExprConstant constant &&
- expr.Type.isSimpleType() && dest.isSimpleType())
+ expr.Type.IsSimpleType && dest.IsSimpleType)
{
if ((ftSrc == FUNDTYPE.FT_I4 && (ftDest <= FUNDTYPE.FT_LASTNONLONG || ftDest == FUNDTYPE.FT_U8)) ||
(ftSrc == FUNDTYPE.FT_I8 && ftDest == FUNDTYPE.FT_U8))
{
// Failed because value was out of range. Report nifty error message.
string value = constant.Int64Value.ToString(CultureInfo.InvariantCulture);
- throw ErrorContext.Error(ErrorCode.ERR_ConstOutOfRange, value, dest);
+ throw ErrorHandling.Error(ErrorCode.ERR_ConstOutOfRange, value, dest);
}
}
- if (expr.Type is NullType && dest.fundType() != FUNDTYPE.FT_REF)
+ if (expr.Type is NullType && dest.FundamentalType != FUNDTYPE.FT_REF)
{
- throw ErrorContext.Error(ErrorCode.ERR_ValueCantBeNull, dest);
+ throw ErrorHandling.Error(ErrorCode.ERR_ValueCantBeNull, dest);
}
// canCast => can't convert, but explicit exists and can be specified by the user (no anonymous types).
// !canCast => Generic "can't convert" error.
- throw ErrorContext.Error(canCast(expr.Type, dest, flags) ? ErrorCode.ERR_NoImplicitConvCast : ErrorCode.ERR_NoImplicitConv, new ErrArg(expr.Type, ErrArgFlags.Unique), new ErrArg(dest, ErrArgFlags.Unique));
+ throw ErrorHandling.Error(canCast(expr.Type, dest, flags) ? ErrorCode.ERR_NoImplicitConvCast : ErrorCode.ERR_NoImplicitConv, new ErrArg(expr.Type, ErrArgFlags.Unique), new ErrArg(dest, ErrArgFlags.Unique));
}
// performs an implicit conversion if its possible. otherwise returns null. flags is an optional parameter.
@@ -400,8 +400,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
if (BindImplicitConversion(expr, expr.Type, dest, out Expr exprResult, flags))
{
- checkUnsafe(expr.Type); // added to the binder so we don't bind to pointer ops
- checkUnsafe(dest); // added to the binder so we don't bind to pointer ops
+ CheckUnsafe(expr.Type); // added to the binder so we don't bind to pointer ops
+ CheckUnsafe(dest); // added to the binder so we don't bind to pointer ops
// Conversion works.
return exprResult;
}
@@ -425,29 +425,28 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Debug.Assert(!(expr is ExprMemberGroup));
Debug.Assert(dest != null);
- SemanticChecker.CheckForStaticClass(null, dest, ErrorCode.ERR_ConvertToStaticClass);
+ CSemanticChecker.CheckForStaticClass(dest);
if (BindExplicitConversion(expr, expr.Type, dest, out Expr exprResult, flags))
{
// Conversion works.
- checkUnsafe(expr.Type); // added to the binder so we don't bind to pointer ops
- checkUnsafe(dest); // added to the binder so we don't bind to pointer ops
+ CheckUnsafe(expr.Type); // added to the binder so we don't bind to pointer ops
+ CheckUnsafe(dest); // added to the binder so we don't bind to pointer ops
return exprResult;
}
// For certain situations, try to give a better error.
Expr exprConst = expr.GetConst();
- bool simpleConstToSimpleDestination = exprConst != null && expr.Type.isSimpleOrEnum() &&
- dest.isSimpleOrEnum();
+ bool simpleConstToSimpleDestination = exprConst != null && expr.Type.IsSimpleOrEnum && dest.IsSimpleOrEnum;
if (simpleConstToSimpleDestination)
{
- FUNDTYPE exprType = expr.Type.fundType();
+ FUNDTYPE exprType = expr.Type.FundamentalType;
if (exprType == FUNDTYPE.FT_STRUCT)
{
// We have a constant decimal that is out of range of the destination type.
// In both checked and unchecked contexts we issue an error. No need to recheck conversion in unchecked context.
// Decimal is a SimpleType represented in a FT_STRUCT
- throw ErrorContext.Error(
+ throw ErrorHandling.Error(
ErrorCode.ERR_ConstOutOfRange,
((ExprConstant)exprConst).Val.DecimalVal.ToString(CultureInfo.InvariantCulture), dest);
}
@@ -455,53 +454,60 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (Context.Checked)
{
// check if we failed because we are in checked mode...
- if (!canExplicitConversionBeBoundInUncheckedContext(expr, expr.Type, dest, flags | CONVERTTYPE.NOUDC))
+ if (!CanExplicitConversionBeBoundInUncheckedContext(expr, expr.Type, dest, flags | CONVERTTYPE.NOUDC))
{
throw CantConvert(expr, dest);
}
// Failed because value was out of range. Report nifty error message.
string value;
- if (exprType <= FUNDTYPE.FT_LASTINTEGRAL)
+ switch (exprType)
{
- value = expr.Type.isUnsigned()
- ? ((ulong)((ExprConstant)exprConst).Int64Value).ToString(CultureInfo.InvariantCulture)
- : ((ExprConstant)exprConst).Int64Value.ToString(CultureInfo.InvariantCulture);
- }
- else
- {
- Debug.Assert(exprType <= FUNDTYPE.FT_LASTNUMERIC, "Error in constant conversion logic!");
- value = ((ExprConstant)exprConst).Val.DoubleVal.ToString(CultureInfo.InvariantCulture);
+ case FUNDTYPE.FT_U1:
+ case FUNDTYPE.FT_U2:
+ case FUNDTYPE.FT_U4:
+ case FUNDTYPE.FT_U8:
+ value = ((ulong)((ExprConstant)exprConst).Int64Value).ToString(CultureInfo.InvariantCulture);
+ break;
+
+ case FUNDTYPE.FT_I1:
+ case FUNDTYPE.FT_I2:
+ case FUNDTYPE.FT_I4:
+ case FUNDTYPE.FT_I8:
+ value = ((ExprConstant)exprConst).Int64Value.ToString(CultureInfo.InvariantCulture);
+ break;
+
+ default:
+ Debug.Assert(exprType <= FUNDTYPE.FT_LASTNUMERIC, "Error in constant conversion logic!");
+ value = ((ExprConstant)exprConst).Val.DoubleVal.ToString(CultureInfo.InvariantCulture);
+ break;
}
- throw ErrorContext.Error(ErrorCode.ERR_ConstOutOfRangeChecked, value, dest);
+ throw ErrorHandling.Error(ErrorCode.ERR_ConstOutOfRangeChecked, value, dest);
}
}
- if (expr.Type is NullType && dest.fundType() != FUNDTYPE.FT_REF)
+ if (expr.Type is NullType && dest.FundamentalType != FUNDTYPE.FT_REF)
{
- throw ErrorContext.Error(ErrorCode.ERR_ValueCantBeNull, dest);
+ throw ErrorHandling.Error(ErrorCode.ERR_ValueCantBeNull, dest);
}
throw CantConvert(expr, dest);
}
- private RuntimeBinderException CantConvert(Expr expr, CType dest)
+ private static RuntimeBinderException CantConvert(Expr expr, CType dest)
{
// Generic "can't convert" error.
Debug.Assert(expr.Type != null);
- return ErrorContext.Error(ErrorCode.ERR_NoExplicitConv, new ErrArg(expr.Type, ErrArgFlags.Unique), new ErrArg(dest, ErrArgFlags.Unique));
+ return ErrorHandling.Error(ErrorCode.ERR_NoExplicitConv, new ErrArg(expr.Type, ErrArgFlags.Unique), new ErrArg(dest, ErrArgFlags.Unique));
}
public Expr mustCast(Expr expr, CType dest) => mustCast(expr, dest, 0);
public Expr mustCast(Expr expr, CType dest, CONVERTTYPE flags) => mustCastCore(expr, dest, flags);
- private Expr mustCastInUncheckedContext(Expr expr, CType dest, CONVERTTYPE flags)
- {
- BindingContext ctx = new BindingContext(Context);
- return (new ExpressionBinder(ctx)).mustCast(expr, dest, flags);
- }
+ private Expr MustCastInUncheckedContext(Expr expr, CType dest, CONVERTTYPE flags) =>
+ new ExpressionBinder(new BindingContext(Context)).mustCast(expr, dest, flags);
// returns true if an explicit conversion exists from source type to dest type. flags is an optional parameter.
private bool canCast(CType src, CType dest, CONVERTTYPE flags) => BindExplicitConversion(null, src, dest, flags);
@@ -595,8 +601,11 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Debug.Assert(exprSrc == null || exprSrc.Type == typeSrc);
// If either type is an interface we should never employ a UD conversion.
- if (typeSrc == null || typeDst == null || typeSrc.isInterfaceType() || typeDst.isInterfaceType())
+ if (typeSrc == null || typeDst == null || typeSrc.IsInterfaceType || typeDst.IsInterfaceType)
+ {
return false;
+ }
+
CType typeSrcBase = typeSrc.StripNubs();
CType typeDstBase = typeDst.StripNubs();
@@ -604,7 +613,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// true exactly when both the source and destination types are nullable.
bool fLiftSrc = typeSrcBase != typeSrc;
bool fLiftDst = typeDstBase != typeDst;
- bool fDstHasNull = fLiftDst || typeDst.IsRefType() || typeDst is PointerType;
+ bool fDstHasNull = fLiftDst || typeDst.IsReferenceType || typeDst is PointerType;
AggregateType[] rgats = new AggregateType[2];
int cats = 0;
@@ -618,21 +627,21 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
bool fIntPtrOverride2 = false;
// Get the list of operators from the source.
- if (typeSrcBase is AggregateType atSrcBase && atSrcBase.getAggregate().HasConversion(GetSymbolLoader()))
+ if (typeSrcBase is AggregateType atSrcBase && atSrcBase.OwningAggregate.HasConversion())
{
rgats[cats++] = atSrcBase;
- fIntPtrOverride2 = atSrcBase.isPredefType(PredefinedType.PT_INTPTR) || atSrcBase.isPredefType(PredefinedType.PT_UINTPTR);
+ fIntPtrOverride2 = atSrcBase.IsPredefType(PredefinedType.PT_INTPTR) || atSrcBase.IsPredefType(PredefinedType.PT_UINTPTR);
}
// Get the list of operators from the destination.
if (typeDstBase is AggregateType atDstBase)
{
- if (typeDstBase.getAggregate().HasConversion(GetSymbolLoader()))
+ if (atDstBase.OwningAggregate.HasConversion())
{
rgats[cats++] = atDstBase;
}
- if (fIntPtrOverride2 && !typeDstBase.isPredefType(PredefinedType.PT_LONG) && !typeDstBase.isPredefType(PredefinedType.PT_ULONG))
+ if (fIntPtrOverride2 && !typeDstBase.IsPredefType(PredefinedType.PT_LONG) && !typeDstBase.IsPredefType(PredefinedType.PT_ULONG))
{
fIntPtrOverride2 = false;
}
@@ -660,9 +669,9 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// In the first pass if we find types that are non-comparable, keep one of the types and keep going.
for (int iats = 0; iats < cats; iats++)
{
- for (AggregateType atsCur = rgats[iats]; atsCur != null && atsCur.getAggregate().HasConversion(GetSymbolLoader()); atsCur = atsCur.GetBaseClass())
+ for (AggregateType atsCur = rgats[iats]; atsCur != null && atsCur.OwningAggregate.HasConversion(); atsCur = atsCur.BaseClass)
{
- AggregateSymbol aggCur = atsCur.getAggregate();
+ AggregateSymbol aggCur = atsCur.OwningAggregate;
// We need to replicate behavior that allows non-standard conversions with these guys.
PredefinedType aggPredefType = aggCur.GetPredefType();
@@ -687,8 +696,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
continue;
// Get the substituted src and dst types.
- typeFrom = GetTypes().SubstType(convCur.Params[0], atsCur);
- typeTo = GetTypes().SubstType(convCur.RetType, atsCur);
+ typeFrom = TypeManager.SubstType(convCur.Params[0], atsCur);
+ typeTo = TypeManager.SubstType(convCur.RetType, atsCur);
bool fNeedImplicit = fImplicitOnly;
@@ -705,8 +714,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
FUNDTYPE ftFrom;
FUNDTYPE ftTo;
- if ((ftTo = typeTo.fundType()) <= FUNDTYPE.FT_LASTNUMERIC && ftTo > FUNDTYPE.FT_NONE &&
- (ftFrom = typeFrom.fundType()) <= FUNDTYPE.FT_LASTNUMERIC && ftFrom > FUNDTYPE.FT_NONE)
+ if ((ftTo = typeTo.FundamentalType) <= FUNDTYPE.FT_LASTNUMERIC && ftTo > FUNDTYPE.FT_NONE &&
+ (ftFrom = typeFrom.FundamentalType) <= FUNDTYPE.FT_LASTNUMERIC && ftFrom > FUNDTYPE.FT_NONE)
{
continue;
}
@@ -714,14 +723,14 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// Ignore the IntPtr/UIntPtr -> int/uint conversion in favor of
// the IntPtr/UIntPtr -> long/ulong conversion.
- if (fIntPtrOverride2 && (typeTo.isPredefType(PredefinedType.PT_INT) || typeTo.isPredefType(PredefinedType.PT_UINT)))
+ if (fIntPtrOverride2 && (typeTo.IsPredefType(PredefinedType.PT_INT) || typeTo.IsPredefType(PredefinedType.PT_UINT)))
continue;
// Lift the conversion if needed.
- if (fLiftSrc && (fDstHasNull || !fNeedImplicit) && typeFrom.IsNonNubValType())
- typeFrom = GetTypes().GetNullable(typeFrom);
- if (fLiftDst && typeTo.IsNonNubValType())
- typeTo = GetTypes().GetNullable(typeTo);
+ if (fLiftSrc && (fDstHasNull || !fNeedImplicit) && typeFrom.IsNonNullableValueType)
+ typeFrom = TypeManager.GetNullable(typeFrom);
+ if (fLiftDst && typeTo.IsNonNullableValueType)
+ typeTo = TypeManager.GetNullable(typeTo);
// Check for applicability.
bool fFromImplicit = exprSrc != null ? canConvert(exprSrc, typeFrom, CONVERTTYPE.STANDARDANDNOUDC) : canConvert(typeSrc, typeFrom, CONVERTTYPE.STANDARDANDNOUDC);
@@ -742,7 +751,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
continue;
}
- if (isConvInTable(prguci, convCur, atsCur, fFromImplicit, fToImplicit))
+ if (IsConvInTable(prguci, convCur, atsCur, fFromImplicit, fToImplicit))
{
// VSWhidbey 579325: duplicate conversions in the convInfo table cause false ambiguity:
// If a user defined implicit conversion exists in a generic base type,
@@ -763,11 +772,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// The conversion is applicable so it affects the best types.
- prguci.Add(new UdConvInfo());
- prguci[prguci.Count - 1].mwt = new MethWithType();
- prguci[prguci.Count - 1].mwt.Set(convCur, atsCur);
- prguci[prguci.Count - 1].fSrcImplicit = fFromImplicit;
- prguci[prguci.Count - 1].fDstImplicit = fToImplicit;
+ prguci.Add(new UdConvInfo(new MethWithType(convCur, atsCur), fFromImplicit, fToImplicit));
if (!fBestSrcExact)
{
@@ -788,7 +793,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
else if (typeBestSrc != typeFrom)
{
Debug.Assert(0 <= iuciBestSrc && iuciBestSrc < prguci.Count - 1);
- int n = CompareSrcTypesBased(typeBestSrc, prguci[iuciBestSrc].fSrcImplicit, typeFrom, fFromImplicit);
+ int n = CompareSrcTypesBased(typeBestSrc, prguci[iuciBestSrc].SrcImplicit, typeFrom, fFromImplicit);
if (n > 0)
{
typeBestSrc = typeFrom;
@@ -815,7 +820,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
else if (typeBestDst != typeTo)
{
Debug.Assert(0 <= iuciBestDst && iuciBestDst < prguci.Count - 1);
- int n = CompareDstTypesBased(typeBestDst, prguci[iuciBestDst].fDstImplicit, typeTo, fToImplicit);
+ int n = CompareDstTypesBased(typeBestDst, prguci[iuciBestDst].DstImplicit, typeTo, fToImplicit);
if (n > 0)
{
typeBestDst = typeTo;
@@ -847,20 +852,21 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
UdConvInfo uci = prguci[iuci];
// Get the substituted src and dst types.
- typeFrom = GetTypes().SubstType(uci.mwt.Meth().Params[0], uci.mwt.GetType());
- typeTo = GetTypes().SubstType(uci.mwt.Meth().RetType, uci.mwt.GetType());
+ typeFrom = TypeManager.SubstType(uci.Meth.Meth().Params[0], uci.Meth.GetType());
+ typeTo = TypeManager.SubstType(uci.Meth.Meth().RetType, uci.Meth.GetType());
int ctypeLift = 0;
// Lift the conversion if needed.
- if (fLiftSrc && typeFrom.IsNonNubValType())
+ if (fLiftSrc && typeFrom.IsNonNullableValueType)
{
- typeFrom = GetTypes().GetNullable(typeFrom);
+ typeFrom = TypeManager.GetNullable(typeFrom);
ctypeLift++;
}
- if (fLiftDst && typeTo.IsNonNubValType())
+
+ if (fLiftDst && typeTo.IsNonNullableValueType)
{
- typeTo = GetTypes().GetNullable(typeTo);
+ typeTo = TypeManager.GetNullable(typeTo);
ctypeLift++;
}
@@ -903,7 +909,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// convertible to each other (eg, int? and int??) and hence not distinguishable by CompareXxxTypesBase.
if (!fBestSrcExact && typeFrom != typeBestSrc)
{
- int n = CompareSrcTypesBased(typeBestSrc, prguci[iuciBestSrc].fSrcImplicit, typeFrom, uci.fSrcImplicit);
+ int n = CompareSrcTypesBased(typeBestSrc, prguci[iuciBestSrc].SrcImplicit, typeFrom, uci.SrcImplicit);
Debug.Assert(n <= 0);
if (n >= 0)
{
@@ -917,7 +923,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
if (!fBestDstExact && typeTo != typeBestDst)
{
- int n = CompareDstTypesBased(typeBestDst, prguci[iuciBestDst].fDstImplicit, typeTo, uci.fDstImplicit);
+ int n = CompareDstTypesBased(typeBestDst, prguci[iuciBestDst].DstImplicit, typeTo, uci.DstImplicit);
Debug.Assert(n <= 0);
if (n >= 0)
{
@@ -943,12 +949,12 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
throw HandleAmbiguity(typeSrc, typeDst, prguci, iuciBest, iuciAmbig);
}
- MethWithInst mwiBest = new MethWithInst(prguci[iuciBest].mwt.Meth(), prguci[iuciBest].mwt.GetType(), null);
+ MethWithInst mwiBest = new MethWithInst(prguci[iuciBest].Meth.Meth(), prguci[iuciBest].Meth.GetType(), null);
Debug.Assert(ctypeLiftBest <= 2);
- typeFrom = GetTypes().SubstType(mwiBest.Meth().Params[0], mwiBest.GetType());
- typeTo = GetTypes().SubstType(mwiBest.Meth().RetType, mwiBest.GetType());
+ typeFrom = TypeManager.SubstType(mwiBest.Meth().Params[0], mwiBest.GetType());
+ typeTo = TypeManager.SubstType(mwiBest.Meth().RetType, mwiBest.GetType());
Expr exprDst;
Expr pTransformedArgument = exprSrc;
@@ -980,7 +986,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (typeFrom != typeSrcBase)
{
// There is an intermediate conversion.
- NullableType pConversionNubSourceType = SymbolLoader.GetTypeManager().GetNullable(typeFrom);
+ NullableType pConversionNubSourceType = TypeManager.GetNullable(typeFrom);
pConversionArgument = mustCast(exprSrc, pConversionNubSourceType);
MarkAsIntermediateConversion(pConversionArgument);
}
@@ -1018,14 +1024,14 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return true;
}
- private RuntimeBinderException HandleAmbiguity(CType typeSrc, CType typeDst, List<UdConvInfo> prguci, int iuciBestSrc, int iuciBestDst)
+ private static RuntimeBinderException HandleAmbiguity(CType typeSrc, CType typeDst, List<UdConvInfo> prguci, int iuciBestSrc, int iuciBestDst)
{
Debug.Assert(0 <= iuciBestSrc && iuciBestSrc < prguci.Count);
Debug.Assert(0 <= iuciBestDst && iuciBestDst < prguci.Count);
- return ErrorContext.Error(ErrorCode.ERR_AmbigUDConv, prguci[iuciBestSrc].mwt, prguci[iuciBestDst].mwt, typeSrc, typeDst);
+ return ErrorHandling.Error(ErrorCode.ERR_AmbigUDConv, prguci[iuciBestSrc].Meth, prguci[iuciBestDst].Meth, typeSrc, typeDst);
}
- private void MarkAsIntermediateConversion(Expr pExpr)
+ private static void MarkAsIntermediateConversion(Expr pExpr)
{
for (;;)
{
@@ -1081,8 +1087,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
pexprDest = null;
long valueInt = 0;
double valueFlt = 0;
- FUNDTYPE ftSrc = exprSrc.Type.fundType();
- FUNDTYPE ftDest = typeDest.fundType();
+ FUNDTYPE ftSrc = exprSrc.Type.FundamentalType;
+ FUNDTYPE ftDest = typeDest.FundamentalType;
bool srcIntegral = (ftSrc <= FUNDTYPE.FT_LASTINTEGRAL);
bool srcNumeric = (ftSrc <= FUNDTYPE.FT_LASTNUMERIC);
@@ -1091,7 +1097,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (ftSrc == FUNDTYPE.FT_STRUCT || ftDest == FUNDTYPE.FT_STRUCT)
{
// Do constant folding involving decimal constants.
- Expr expr = bindDecimalConstCast(typeDest, exprSrc.Type, constSrc);
+ Expr expr = BindDecimalConstCast(typeDest, exprSrc.Type, constSrc);
if (expr == null)
{
@@ -1120,7 +1126,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// Get the source constant value into valueInt or valueFlt.
if (srcIntegral)
{
- if (constSrc.Type.fundType() == FUNDTYPE.FT_U8)
+ if (constSrc.Type.FundamentalType == FUNDTYPE.FT_U8)
{
// If we're going from ulong to something, make sure we can fit.
if (ftDest == FUNDTYPE.FT_U8)
@@ -1333,7 +1339,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
/*
* Bind a constant cast to or from decimal. Return null if cast can't be done.
*/
- private Expr bindDecimalConstCast(CType destType, CType srcType, ExprConstant src)
+ private static Expr BindDecimalConstCast(CType destType, CType srcType, ExprConstant src)
{
CType typeDecimal = SymbolLoader.GetPredefindType(PredefinedType.PT_DECIMAL);
ConstVal cv;
@@ -1345,7 +1351,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
// Casting to decimal.
- FUNDTYPE ftSrc = srcType.fundType();
+ FUNDTYPE ftSrc = srcType.FundamentalType;
decimal result;
switch (ftSrc)
@@ -1387,7 +1393,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// Casting from decimal
decimal decTrunc = 0;
- FUNDTYPE ftDest = destType.fundType();
+ FUNDTYPE ftDest = destType.FundamentalType;
try
{
if (ftDest != FUNDTYPE.FT_R4 && ftDest != FUNDTYPE.FT_R8)
@@ -1438,14 +1444,14 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// Create the cast that was the original tree for this thing.
return exprConst;
}
+
return null;
}
- private bool canExplicitConversionBeBoundInUncheckedContext(Expr exprSrc, CType typeSrc, CType typeDest, CONVERTTYPE flags)
+ private bool CanExplicitConversionBeBoundInUncheckedContext(Expr exprSrc, CType typeSrc, CType typeDest, CONVERTTYPE flags)
{
- BindingContext ctx = new BindingContext(Context);
Debug.Assert(typeDest != null);
- return (new ExpressionBinder(ctx)).BindExplicitConversion(exprSrc, typeSrc, typeDest, flags);
+ return new ExpressionBinder(new BindingContext(Context)).BindExplicitConversion(exprSrc, typeSrc, typeDest, flags);
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Conversions.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Conversions.cs
index 07114602cc..f9b91e0a8e 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Conversions.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Conversions.cs
@@ -24,10 +24,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
when the source is a reference type and the destination is a base type of the source. Note
that typeDst.IsRefType() may still return false (when both are type parameters).
***************************************************************************************************/
- public static bool FImpRefConv(SymbolLoader loader, CType typeSrc, CType typeDst)
- {
- return typeSrc.IsRefType() && loader.HasIdentityOrImplicitReferenceConversion(typeSrc, typeDst);
- }
+ public static bool FImpRefConv(CType typeSrc, CType typeDst) =>
+ typeSrc.IsReferenceType && SymbolLoader.HasIdentityOrImplicitReferenceConversion(typeSrc, typeDst);
/***************************************************************************************************
Determine whether there is an explicit or implicit reference conversion (or identity conversion)
@@ -73,16 +71,16 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
The latter two cases can happen with type variables even though the other type variable is not
a reference type.
***************************************************************************************************/
- public static bool FExpRefConv(SymbolLoader loader, CType typeSrc, CType typeDst)
+ public static bool FExpRefConv(CType typeSrc, CType typeDst)
{
Debug.Assert(typeSrc != null);
Debug.Assert(typeDst != null);
- if (typeSrc.IsRefType() && typeDst.IsRefType())
+ if (typeSrc.IsReferenceType && typeDst.IsReferenceType)
{
// is there an implicit reference conversion in either direction?
// this handles the bulk of the cases ...
- if (loader.HasIdentityOrImplicitReferenceConversion(typeSrc, typeDst) ||
- loader.HasIdentityOrImplicitReferenceConversion(typeDst, typeSrc))
+ if (SymbolLoader.HasIdentityOrImplicitReferenceConversion(typeSrc, typeDst) ||
+ SymbolLoader.HasIdentityOrImplicitReferenceConversion(typeDst, typeSrc))
{
return true;
}
@@ -90,11 +88,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// For a type-parameter T that is known to be a reference type (§25.7), the following explicit reference conversions exist:
// • From any interface-type to T.
// • From T to any interface-type I provided there isn’t already an implicit reference conversion from T to I.
- if (typeSrc.isInterfaceType() && typeDst is TypeParameterType)
- {
- return true;
- }
- if (typeSrc is TypeParameterType && typeDst.isInterfaceType())
+ if (typeSrc.IsInterfaceType && typeDst is TypeParameterType || typeSrc is TypeParameterType && typeDst.IsInterfaceType)
{
return true;
}
@@ -104,8 +98,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// * From any interface-type S to any interface-type T, provided S is not derived from T.
if (typeSrc is AggregateType atSrc && typeDst is AggregateType atDst)
{
- AggregateSymbol aggSrc = atSrc.getAggregate();
- AggregateSymbol aggDest = atDst.getAggregate();
+ AggregateSymbol aggSrc = atSrc.OwningAggregate;
+ AggregateSymbol aggDest = atDst.OwningAggregate;
if ((aggSrc.IsClass() && !aggSrc.IsSealed() && aggDest.IsInterface()) ||
(aggSrc.IsInterface() && aggDest.IsClass() && !aggDest.IsSealed()) ||
@@ -122,45 +116,44 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// o An explicit reference conversion exists from SE to TE.
if (typeDst is ArrayType arrDst)
{
- return arrSrc.rank == arrDst.rank
+ return arrSrc.Rank == arrDst.Rank
&& arrSrc.IsSZArray == arrDst.IsSZArray
- && FExpRefConv(loader, arrSrc.GetElementType(), arrDst.GetElementType());
+ && FExpRefConv(arrSrc.ElementType, arrDst.ElementType);
}
// * From a one-dimensional array-type S[] to System.Collections.Generic.IList<T>, System.Collections.Generic.IReadOnlyList<T>
// and their base interfaces, provided there is an explicit reference conversion from S to T.
- if (!arrSrc.IsSZArray ||
- !typeDst.isInterfaceType())
+ if (!arrSrc.IsSZArray || !typeDst.IsInterfaceType)
{
return false;
}
AggregateType aggDst = (AggregateType)typeDst;
- TypeArray typeArgsAll = aggDst.GetTypeArgsAll();
+ TypeArray typeArgsAll = aggDst.TypeArgsAll;
if (typeArgsAll.Count != 1)
{
return false;
}
- AggregateSymbol aggIList = loader.GetPredefAgg(PredefinedType.PT_G_ILIST);
- AggregateSymbol aggIReadOnlyList = loader.GetPredefAgg(PredefinedType.PT_G_IREADONLYLIST);
+ AggregateSymbol aggIList = SymbolLoader.GetPredefAgg(PredefinedType.PT_G_ILIST);
+ AggregateSymbol aggIReadOnlyList = SymbolLoader.GetPredefAgg(PredefinedType.PT_G_IREADONLYLIST);
if ((aggIList == null ||
- !SymbolLoader.IsBaseAggregate(aggIList, aggDst.getAggregate())) &&
+ !SymbolLoader.IsBaseAggregate(aggIList, aggDst.OwningAggregate)) &&
(aggIReadOnlyList == null ||
- !SymbolLoader.IsBaseAggregate(aggIReadOnlyList, aggDst.getAggregate())))
+ !SymbolLoader.IsBaseAggregate(aggIReadOnlyList, aggDst.OwningAggregate)))
{
return false;
}
- return FExpRefConv(loader, arrSrc.GetElementType(), typeArgsAll[0]);
+ return FExpRefConv(arrSrc.ElementType, typeArgsAll[0]);
}
if (typeDst is ArrayType arrayDest && typeSrc is AggregateType aggtypeSrc)
{
// * From System.Array and the interfaces it implements, to any array-type.
- if (loader.HasIdentityOrImplicitReferenceConversion(loader.GetPredefindType(PredefinedType.PT_ARRAY), typeSrc))
+ if (SymbolLoader.HasIdentityOrImplicitReferenceConversion(SymbolLoader.GetPredefindType(PredefinedType.PT_ARRAY), typeSrc))
{
return true;
}
@@ -169,45 +162,44 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// one-dimensional array-type S[], provided there is an implicit or explicit reference conversion from S[] to
// System.Collections.Generic.IList<T> or System.Collections.Generic.IReadOnlyList<T>. This is precisely when either S and T
// are the same type or there is an implicit or explicit reference conversion from S to T.
- if (!arrayDest.IsSZArray || !typeSrc.isInterfaceType() ||
- aggtypeSrc.GetTypeArgsAll().Count != 1)
+ if (!arrayDest.IsSZArray || !typeSrc.IsInterfaceType || aggtypeSrc.TypeArgsAll.Count != 1)
{
return false;
}
- AggregateSymbol aggIList = loader.GetPredefAgg(PredefinedType.PT_G_ILIST);
- AggregateSymbol aggIReadOnlyList = loader.GetPredefAgg(PredefinedType.PT_G_IREADONLYLIST);
+ AggregateSymbol aggIList = SymbolLoader.GetPredefAgg(PredefinedType.PT_G_ILIST);
+ AggregateSymbol aggIReadOnlyList = SymbolLoader.GetPredefAgg(PredefinedType.PT_G_IREADONLYLIST);
if ((aggIList == null ||
- !SymbolLoader.IsBaseAggregate(aggIList, aggtypeSrc.getAggregate())) &&
+ !SymbolLoader.IsBaseAggregate(aggIList, aggtypeSrc.OwningAggregate)) &&
(aggIReadOnlyList == null ||
- !SymbolLoader.IsBaseAggregate(aggIReadOnlyList, aggtypeSrc.getAggregate())))
+ !SymbolLoader.IsBaseAggregate(aggIReadOnlyList, aggtypeSrc.OwningAggregate)))
{
return false;
}
- CType typeArr = arrayDest.GetElementType();
- CType typeLst = aggtypeSrc.GetTypeArgsAll()[0];
+ CType typeArr = arrayDest.ElementType;
+ CType typeLst = aggtypeSrc.TypeArgsAll[0];
Debug.Assert(!(typeArr is MethodGroupType));
- return typeArr == typeLst || FExpRefConv(loader, typeArr, typeLst);
+ return typeArr == typeLst || FExpRefConv(typeArr, typeLst);
}
- if (HasGenericDelegateExplicitReferenceConversion(loader, typeSrc, typeDst))
+ if (HasGenericDelegateExplicitReferenceConversion(typeSrc, typeDst))
{
return true;
}
}
- else if (typeSrc.IsRefType())
+ else if (typeSrc.IsReferenceType)
{
// conversion of T . U, where T : class, U
// .. these constraints implies where U : class
- return loader.HasIdentityOrImplicitReferenceConversion(typeSrc, typeDst);
+ return SymbolLoader.HasIdentityOrImplicitReferenceConversion(typeSrc, typeDst);
}
- else if (typeDst.IsRefType())
+ else if (typeDst.IsReferenceType)
{
// conversion of T . U, where U : class, T
// .. these constraints implies where T : class
- return loader.HasIdentityOrImplicitReferenceConversion(typeDst, typeSrc);
+ return SymbolLoader.HasIdentityOrImplicitReferenceConversion(typeDst, typeSrc);
}
return false;
}
@@ -224,19 +216,23 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
o If type parameter Xi is declared to be contravariant ("in") then either Si must be identical to Ti,
or Si and Ti must both be reference types.
***************************************************************************************************/
- public static bool HasGenericDelegateExplicitReferenceConversion(SymbolLoader loader, CType pSource, CType pTarget)
+ public static bool HasGenericDelegateExplicitReferenceConversion(CType source, CType target) =>
+ target is AggregateType aggTarget && HasGenericDelegateExplicitReferenceConversion(source, aggTarget);
+
+ public static bool HasGenericDelegateExplicitReferenceConversion(CType pSource, AggregateType pTarget)
{
- if (!pSource.isDelegateType() ||
- !pTarget.isDelegateType() ||
- pSource.getAggregate() != pTarget.getAggregate() ||
- loader.HasIdentityOrImplicitReferenceConversion(pSource, pTarget))
+ if (!(pSource is AggregateType aggSrc) ||
+ !aggSrc.IsDelegateType ||
+ !pTarget.IsDelegateType ||
+ aggSrc.OwningAggregate != pTarget.OwningAggregate ||
+ SymbolLoader.HasIdentityOrImplicitReferenceConversion(aggSrc, pTarget))
{
return false;
}
- TypeArray pTypeParams = pSource.getAggregate().GetTypeVarsAll();
- TypeArray pSourceArgs = ((AggregateType)pSource).GetTypeArgsAll();
- TypeArray pTargetArgs = ((AggregateType)pTarget).GetTypeArgsAll();
+ TypeArray pTypeParams = aggSrc.OwningAggregate.GetTypeVarsAll();
+ TypeArray pSourceArgs = aggSrc.TypeArgsAll;
+ TypeArray pTargetArgs = pTarget.TypeArgsAll;
Debug.Assert(pTypeParams.Count == pSourceArgs.Count);
Debug.Assert(pTypeParams.Count == pTargetArgs.Count);
@@ -261,19 +257,20 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (pParam.Covariant)
{
- if (!FExpRefConv(loader, pSourceArg, pTargetArg))
+ if (!FExpRefConv(pSourceArg, pTargetArg))
{
return false;
}
}
else if (pParam.Contravariant)
{
- if (!pSourceArg.IsRefType() || !pTargetArg.IsRefType())
+ if (!pSourceArg.IsReferenceType || !pTargetArg.IsReferenceType)
{
return false;
}
}
}
+
return true;
}
@@ -322,10 +319,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
* The term wrapping denotes the process of packaging a value, of type T, in an instance of type T?.
A value x of type T is wrapped to type T? by evaluating the expression new T?(x).
***************************************************************************************************/
- public static bool FWrappingConv(CType typeSrc, CType typeDst)
- {
- return typeDst is NullableType nubDst && typeSrc == nubDst.GetUnderlyingType();
- }
+ public static bool FWrappingConv(CType typeSrc, CType typeDst) => typeDst is NullableType nubDst && typeSrc == nubDst.UnderlyingType;
/***************************************************************************************************
Determines whether there is a unwrapping conversion from typeSrc to typeDst
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Declarations/AggregateDeclaration.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Declarations/AggregateDeclaration.cs
deleted file mode 100644
index 8dbc7213c6..0000000000
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Declarations/AggregateDeclaration.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Reflection;
-
-namespace Microsoft.CSharp.RuntimeBinder.Semantics
-{
- // ----------------------------------------------------------------------------
- //
- // AggregateDeclaration
- //
- // AggregateDeclaration - represents a declaration of an aggregate type. With partial classes,
- // an aggregate type might be declared in multiple places. This symbol represents
- // on of the declarations.
- //
- // parent is the containing Declaration.
- // ----------------------------------------------------------------------------
-
- // Either a ClassNode or a DelegateNode
- internal sealed class AggregateDeclaration : ParentSymbol
- {
- public NamespaceOrAggregateSymbol bag;
-
- public AggregateDeclaration declNext;
-
- public AggregateSymbol Agg()
- {
- return bag as AggregateSymbol;
- }
-
- public Assembly GetAssembly()
- {
- return Agg().AssociatedAssembly;
- }
- }
-}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/EXPRExtensions.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/EXPRExtensions.cs
index d22c42d33d..5cc75809b2 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/EXPRExtensions.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/EXPRExtensions.cs
@@ -10,20 +10,21 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
internal static class EXPRExtensions
{
- public static Expr Map(this Expr expr, ExprFactory factory, Func<Expr, Expr> f)
+ public static Expr Map(this Expr expr, Func<Expr, Expr> f)
{
Debug.Assert(f != null);
- Debug.Assert(factory != null);
if (expr == null)
- return f(expr);
+ {
+ return f(null);
+ }
Expr result = null;
Expr tail = null;
foreach (Expr item in expr.ToEnumerable())
{
Expr mappedItem = f(item);
- factory.AppendItemToList(mappedItem, ref result, ref tail);
+ ExprFactory.AppendItemToList(mappedItem, ref result, ref tail);
}
return result;
}
@@ -61,7 +62,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
public static bool isNull(this Expr expr)
- => expr is ExprConstant constant && expr.Type.fundType() == FUNDTYPE.FT_REF && constant.Val.IsNullRef;
+ => expr is ExprConstant constant && expr.Type.FundamentalType == FUNDTYPE.FT_REF && constant.Val.IsNullRef;
public static bool IsZero(this Expr expr) => expr is ExprConstant constant && constant.IsZero;
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ExplicitConversion.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ExplicitConversion.cs
index 53ab82cefb..a4f419bf68 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ExplicitConversion.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ExplicitConversion.cs
@@ -7,7 +7,7 @@ using Microsoft.CSharp.RuntimeBinder.Syntax;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
- internal sealed partial class ExpressionBinder
+ internal readonly partial struct ExpressionBinder
{
// ----------------------------------------------------------------------------
// BindExplicitConversion
@@ -127,10 +127,10 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// But it failed, and so we know that the constant is not in range
- switch (_typeDest.GetTypeKind())
+ switch (_typeDest.TypeKind)
{
default:
- Debug.Fail($"Bad type kind: {_typeDest.GetTypeKind()}");
+ Debug.Fail($"Bad type kind: {_typeDest.TypeKind}");
return false;
case TypeKind.TK_VoidType:
@@ -189,14 +189,14 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// If S and T are value types and there is a builtin conversion from S => T then there is an
// explicit conversion from S? => T that throws on null.
- if (_typeDest.IsValType() && _binder.BindExplicitConversion(null, _typeSrc.StripNubs(), _typeDest, _flags | CONVERTTYPE.NOUDC))
+ if (_typeDest.IsValueType && _binder.BindExplicitConversion(null, _typeSrc.StripNubs(), _typeDest, _flags | CONVERTTYPE.NOUDC))
{
if (_needsExprDest)
{
Expr valueSrc = _exprSrc;
if (valueSrc.Type is NullableType)
{
- valueSrc = _binder.BindNubValue(valueSrc);
+ valueSrc = BindNubValue(valueSrc);
}
Debug.Assert(valueSrc.Type == _typeSrc.StripNubs());
@@ -233,26 +233,26 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Debug.Assert(_typeDest != null);
if (!(_typeSrc is ArrayType arrSrc) || !arrSrc.IsSZArray || !(_typeDest is AggregateType aggDest)
- || !aggDest.isInterfaceType() || aggDest.GetTypeArgsAll().Count != 1)
+ || !aggDest.IsInterfaceType || aggDest.TypeArgsAll.Count != 1)
{
return false;
}
- AggregateSymbol aggIList = GetSymbolLoader().GetPredefAgg(PredefinedType.PT_G_ILIST);
- AggregateSymbol aggIReadOnlyList = GetSymbolLoader().GetPredefAgg(PredefinedType.PT_G_IREADONLYLIST);
+ AggregateSymbol aggIList = SymbolLoader.GetPredefAgg(PredefinedType.PT_G_ILIST);
+ AggregateSymbol aggIReadOnlyList = SymbolLoader.GetPredefAgg(PredefinedType.PT_G_IREADONLYLIST);
if ((aggIList == null ||
- !SymbolLoader.IsBaseAggregate(aggIList, aggDest.getAggregate())) &&
+ !SymbolLoader.IsBaseAggregate(aggIList, aggDest.OwningAggregate)) &&
(aggIReadOnlyList == null ||
- !SymbolLoader.IsBaseAggregate(aggIReadOnlyList, aggDest.getAggregate())))
+ !SymbolLoader.IsBaseAggregate(aggIReadOnlyList, aggDest.OwningAggregate)))
{
return false;
}
- CType typeArr = arrSrc.GetElementType();
- CType typeLst = aggDest.GetTypeArgsAll()[0];
+ CType typeArr = arrSrc.ElementType;
+ CType typeLst = aggDest.TypeArgsAll[0];
- if (!CConversions.FExpRefConv(GetSymbolLoader(), typeArr, typeLst))
+ if (!CConversions.FExpRefConv(typeArr, typeLst))
{
return false;
}
@@ -273,28 +273,27 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// S[] to System.Collections.Generic.IList<T> or System.Collections.Generic.IReadOnlyList<T>. This is precisely when either S and T
// are the same type or there is an implicit or explicit reference conversion from S to T.
- if (!arrayDest.IsSZArray || !(_typeSrc is AggregateType aggSrc) || !aggSrc.isInterfaceType() ||
- aggSrc.GetTypeArgsAll().Count != 1)
+ if (!arrayDest.IsSZArray || !(_typeSrc is AggregateType aggSrc) || !aggSrc.IsInterfaceType || aggSrc.TypeArgsAll.Count != 1)
{
return false;
}
- AggregateSymbol aggIList = GetSymbolLoader().GetPredefAgg(PredefinedType.PT_G_ILIST);
- AggregateSymbol aggIReadOnlyList = GetSymbolLoader().GetPredefAgg(PredefinedType.PT_G_IREADONLYLIST);
+ AggregateSymbol aggIList = SymbolLoader.GetPredefAgg(PredefinedType.PT_G_ILIST);
+ AggregateSymbol aggIReadOnlyList = SymbolLoader.GetPredefAgg(PredefinedType.PT_G_IREADONLYLIST);
if ((aggIList == null ||
- !SymbolLoader.IsBaseAggregate(aggIList, aggSrc.getAggregate())) &&
+ !SymbolLoader.IsBaseAggregate(aggIList, aggSrc.OwningAggregate)) &&
(aggIReadOnlyList == null ||
- !SymbolLoader.IsBaseAggregate(aggIReadOnlyList, aggSrc.getAggregate())))
+ !SymbolLoader.IsBaseAggregate(aggIReadOnlyList, aggSrc.OwningAggregate)))
{
return false;
}
- CType typeArr = arrayDest.GetElementType();
- CType typeLst = aggSrc.GetTypeArgsAll()[0];
+ CType typeArr = arrayDest.ElementType;
+ CType typeLst = aggSrc.TypeArgsAll[0];
Debug.Assert(!(typeArr is MethodGroupType));
- if (typeArr != typeLst && !CConversions.FExpRefConv(GetSymbolLoader(), typeArr, typeLst))
+ if (typeArr != typeLst && !CConversions.FExpRefConv(typeArr, typeLst))
{
return false;
}
@@ -317,15 +316,18 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
//
// * An explicit reference conversion exists from SE to TE.
- if (arraySrc.rank != arrayDest.rank || arraySrc.IsSZArray != arrayDest.IsSZArray)
+ if (arraySrc.Rank != arrayDest.Rank || arraySrc.IsSZArray != arrayDest.IsSZArray)
{
return false; // Ranks do not match.
}
- if (CConversions.FExpRefConv(GetSymbolLoader(), arraySrc.GetElementType(), arrayDest.GetElementType()))
+ if (CConversions.FExpRefConv(arraySrc.ElementType, arrayDest.ElementType))
{
if (_needsExprDest)
+ {
_binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, EXPRFLAG.EXF_REFCHECK);
+ }
+
return true;
}
@@ -353,7 +355,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
//
// * From System.Array and the interfaces it implements, to any array-type.
- if (_binder.canConvert(_binder.GetPredefindType(PredefinedType.PT_ARRAY), _typeSrc, CONVERTTYPE.NOUDC))
+ if (_binder.canConvert(GetPredefindType(PredefinedType.PT_ARRAY), _typeSrc, CONVERTTYPE.NOUDC))
{
if (_needsExprDest)
_binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, EXPRFLAG.EXF_REFCHECK);
@@ -372,7 +374,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// * From any pointer-type to any other pointer-type.
// * From sbyte, byte, short, ushort, int, uint, long, or ulong to any pointer-type.
- if (_typeSrc is PointerType || _typeSrc.fundType() <= FUNDTYPE.FT_LASTINTEGRAL && _typeSrc.isNumericType())
+ if (_typeSrc is PointerType || _typeSrc.FundamentalType <= FUNDTYPE.FT_LASTINTEGRAL && _typeSrc.IsNumericType)
{
if (_needsExprDest)
_binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest);
@@ -402,19 +404,19 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Debug.Assert(_typeSrc != null);
Debug.Assert(aggTypeDest != null);
- if (!_typeSrc.isEnumType())
+ if (!_typeSrc.IsEnumType)
{
return AggCastResult.Failure;
}
- AggregateSymbol aggDest = aggTypeDest.getAggregate();
+ AggregateSymbol aggDest = aggTypeDest.OwningAggregate;
if (aggDest.isPredefAgg(PredefinedType.PT_DECIMAL))
{
return bindExplicitConversionFromEnumToDecimal(aggTypeDest);
}
- if (!aggDest.getThisType().isNumericType() &&
+ if (!aggDest.getThisType().IsNumericType &&
!aggDest.IsEnum() &&
!(aggDest.IsPredefined() && aggDest.GetPredefType() == PredefinedType.PT_CHAR))
{
@@ -442,7 +444,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
private AggCastResult bindExplicitConversionFromDecimalToEnum(AggregateType aggTypeDest)
{
Debug.Assert(_typeSrc != null);
- Debug.Assert(_typeSrc.isPredefType(PredefinedType.PT_DECIMAL));
+ Debug.Assert(_typeSrc.IsPredefType(PredefinedType.PT_DECIMAL));
+ Debug.Assert(aggTypeDest.IsEnumType);
// There is an explicit conversion from decimal to all integral types.
if (_exprSrc.GetConst() != null)
@@ -467,7 +470,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// According the language, this is a standard conversion, but it is implemented
// through a user-defined conversion. Because it's a standard conversion, we don't
// test the CONVERTTYPE.NOUDC flag here.
- CType underlyingType = aggTypeDest.underlyingType();
+ CType underlyingType = aggTypeDest.UnderlyingEnumType;
bIsConversionOK = _binder.bindUserDefinedConversion(_exprSrc, _typeSrc, underlyingType, _needsExprDest, out _exprDest, false);
if (bIsConversionOK)
@@ -483,9 +486,10 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
Debug.Assert(_typeSrc != null);
Debug.Assert(aggTypeDest != null);
- Debug.Assert(aggTypeDest.isPredefType(PredefinedType.PT_DECIMAL));
+ Debug.Assert(aggTypeDest.IsPredefType(PredefinedType.PT_DECIMAL));
+ Debug.Assert(_typeSrc.IsEnumType);
- AggregateType underlyingType = _typeSrc.underlyingType() as AggregateType;
+ AggregateType underlyingType = _typeSrc.UnderlyingEnumType;
// Need to first cast the source expr to its underlying type.
@@ -536,18 +540,18 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Debug.Assert(_typeSrc != null);
Debug.Assert(aggTypeDest != null);
- AggregateSymbol aggDest = aggTypeDest.getAggregate();
+ AggregateSymbol aggDest = aggTypeDest.OwningAggregate;
if (!aggDest.IsEnum())
{
return AggCastResult.Failure;
}
- if (_typeSrc.isPredefType(PredefinedType.PT_DECIMAL))
+ if (_typeSrc.IsPredefType(PredefinedType.PT_DECIMAL))
{
return bindExplicitConversionFromDecimalToEnum(aggTypeDest);
}
- if (_typeSrc.isNumericType() || (_typeSrc.isPredefined() && _typeSrc.getPredefType() == PredefinedType.PT_CHAR))
+ if (_typeSrc.IsNumericType || _typeSrc.IsPredefined && _typeSrc.PredefinedType == PredefinedType.PT_CHAR)
{
// Transform constant to constant.
if (_exprSrc.GetConst() != null)
@@ -566,8 +570,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
_binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest);
return AggCastResult.Success;
}
- else if (_typeSrc.isPredefined() &&
- (_typeSrc.isPredefType(PredefinedType.PT_OBJECT) || _typeSrc.isPredefType(PredefinedType.PT_VALUE) || _typeSrc.isPredefType(PredefinedType.PT_ENUM)))
+ else if (_typeSrc.IsPredefined &&
+ (_typeSrc.IsPredefType(PredefinedType.PT_OBJECT) || _typeSrc.IsPredefType(PredefinedType.PT_VALUE) || _typeSrc.IsPredefType(PredefinedType.PT_ENUM)))
{
if (_needsExprDest)
_binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, EXPRFLAG.EXF_UNBOX);
@@ -587,16 +591,16 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Debug.Assert(_typeSrc != null);
Debug.Assert(aggTypeDest != null);
- if (!_typeSrc.isSimpleType() || !aggTypeDest.isSimpleType())
+ if (!_typeSrc.IsSimpleType || !aggTypeDest.IsSimpleType)
{
return AggCastResult.Failure;
}
- AggregateSymbol aggDest = aggTypeDest.getAggregate();
+ AggregateSymbol aggDest = aggTypeDest.OwningAggregate;
- Debug.Assert(_typeSrc.isPredefined() && aggDest.IsPredefined());
+ Debug.Assert(_typeSrc.IsPredefined && aggDest.IsPredefined());
- PredefinedType ptSrc = _typeSrc.getPredefType();
+ PredefinedType ptSrc = _typeSrc.PredefinedType;
PredefinedType ptDest = aggDest.GetPredefType();
Debug.Assert((int)ptSrc < NUM_SIMPLE_TYPES && (int)ptDest < NUM_SIMPLE_TYPES);
@@ -666,29 +670,27 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return AggCastResult.Failure;
}
- AggregateSymbol aggSrc = atSrc.getAggregate();
- AggregateSymbol aggDest = aggTypeDest.getAggregate();
+ AggregateSymbol aggSrc = atSrc.OwningAggregate;
+ AggregateSymbol aggDest = aggTypeDest.OwningAggregate;
- if (GetSymbolLoader().HasBaseConversion(aggTypeDest, atSrc))
+ if (SymbolLoader.HasBaseConversion(aggTypeDest, atSrc))
{
if (_needsExprDest)
{
- if (aggDest.IsValueType() && aggSrc.getThisType().fundType() == FUNDTYPE.FT_REF)
- {
- _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, EXPRFLAG.EXF_UNBOX);
- }
- else
- {
- _binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, EXPRFLAG.EXF_REFCHECK | (_exprSrc?.Flags & EXPRFLAG.EXF_CANTBENULL ?? 0));
- }
+ _binder.bindSimpleCast(
+ _exprSrc, _typeDest, out _exprDest,
+ aggDest.IsValueType() && aggSrc.getThisType().FundamentalType == FUNDTYPE.FT_REF
+ ? EXPRFLAG.EXF_UNBOX
+ : EXPRFLAG.EXF_REFCHECK | (_exprSrc?.Flags & EXPRFLAG.EXF_CANTBENULL ?? 0));
}
+
return AggCastResult.Success;
}
if ((aggSrc.IsClass() && !aggSrc.IsSealed() && aggDest.IsInterface()) ||
(aggSrc.IsInterface() && aggDest.IsClass() && !aggDest.IsSealed()) ||
(aggSrc.IsInterface() && aggDest.IsInterface()) ||
- CConversions.HasGenericDelegateExplicitReferenceConversion(GetSymbolLoader(), _typeSrc, aggTypeDest))
+ CConversions.HasGenericDelegateExplicitReferenceConversion(_typeSrc, aggTypeDest))
{
if (_needsExprDest)
_binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, EXPRFLAG.EXF_REFCHECK | (_exprSrc?.Flags & EXPRFLAG.EXF_CANTBENULL ?? 0));
@@ -705,7 +707,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
//
// * From any pointer-type to sbyte, byte, short, ushort, int, uint, long, or ulong.
- if (!(_typeSrc is PointerType) || aggTypeDest.fundType() > FUNDTYPE.FT_LASTINTEGRAL || !aggTypeDest.isNumericType())
+ if (!(_typeSrc is PointerType) || aggTypeDest.FundamentalType > FUNDTYPE.FT_LASTINTEGRAL || !aggTypeDest.IsNumericType)
{
return AggCastResult.Failure;
}
@@ -758,16 +760,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return AggCastResult.Failure;
}
-
- private SymbolLoader GetSymbolLoader()
- {
- return _binder.GetSymbolLoader();
- }
-
- private ExprFactory GetExprFactory()
- {
- return _binder.GetExprFactory();
- }
}
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ExprFactory.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ExprFactory.cs
index 846de0e004..83465b882a 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ExprFactory.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ExprFactory.cs
@@ -8,90 +8,72 @@ using Microsoft.CSharp.RuntimeBinder.Syntax;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
- internal sealed class ExprFactory
+ internal static class ExprFactory
{
- private readonly GlobalSymbolContext _globalSymbolContext;
-
- public ExprFactory(GlobalSymbolContext globalSymbolContext)
- {
- Debug.Assert(globalSymbolContext != null);
- _globalSymbolContext = globalSymbolContext;
- }
- private TypeManager Types => _globalSymbolContext.GetTypes();
-
- private BSYMMGR GlobalSymbols => _globalSymbolContext.GetGlobalSymbols();
-
- public ExprCall CreateCall(EXPRFLAG flags, CType type, Expr arguments, ExprMemberGroup memberGroup, MethWithInst method) =>
+ public static ExprCall CreateCall(EXPRFLAG flags, CType type, Expr arguments, ExprMemberGroup memberGroup, MethWithInst method) =>
new ExprCall(type, flags, arguments, memberGroup, method);
- public ExprField CreateField(CType type, Expr optionalObject, FieldWithType field, bool isLValue) =>
- new ExprField(type, optionalObject, field, isLValue);
+ public static ExprField CreateField(CType type, Expr optionalObject, FieldWithType field) =>
+ new ExprField(type, optionalObject, field);
- public ExprArrayInit CreateArrayInit(CType type, Expr arguments, Expr argumentDimensions, int[] dimSizes, int dimSize) =>
+ public static ExprArrayInit CreateArrayInit(CType type, Expr arguments, Expr argumentDimensions, int[] dimSizes, int dimSize) =>
new ExprArrayInit(type, arguments, argumentDimensions, dimSizes, dimSize);
- public ExprProperty CreateProperty(CType type, Expr optionalObjectThrough, Expr arguments, ExprMemberGroup memberGroup, PropWithType property, MethWithType setMethod) =>
+ public static ExprProperty CreateProperty(CType type, Expr optionalObjectThrough, Expr arguments, ExprMemberGroup memberGroup, PropWithType property, MethWithType setMethod) =>
new ExprProperty(type, optionalObjectThrough, arguments, memberGroup, property, setMethod);
- public ExprMemberGroup CreateMemGroup(EXPRFLAG flags, Name name, TypeArray typeArgs, SYMKIND symKind, CType parentType, MethodOrPropertySymbol memberSymbol, Expr obj, CMemberLookupResults memberLookupResults) =>
- new ExprMemberGroup(Types.GetMethGrpType(), flags, name, typeArgs, symKind, parentType, memberSymbol, obj, memberLookupResults);
+ public static ExprMemberGroup CreateMemGroup(EXPRFLAG flags, Name name, TypeArray typeArgs, SYMKIND symKind, CType parentType, Expr obj, CMemberLookupResults memberLookupResults) =>
+ new ExprMemberGroup(flags, name, typeArgs, symKind, parentType, obj, memberLookupResults);
- public ExprMemberGroup CreateMemGroup(Expr obj, MethPropWithInst method)
+ public static ExprMemberGroup CreateMemGroup(Expr obj, MethPropWithInst method)
{
Name name = method.Sym?.name;
- MethodOrPropertySymbol methProp = method.MethProp();
-
- CType type = method.GetType();
-
return CreateMemGroup(
- 0, name, method.TypeArgs, methProp?.getKind() ?? SYMKIND.SK_MethodSymbol, method.GetType(), methProp,
- obj, new CMemberLookupResults(GlobalSymbols.AllocParams(1, new[] {type}), name));
+ 0, name, method.TypeArgs, method.MethProp()?.getKind() ?? SYMKIND.SK_MethodSymbol, method.GetType(),
+ obj, new CMemberLookupResults(TypeArray.Allocate((CType)method.GetType()), name));
}
- public ExprUserDefinedConversion CreateUserDefinedConversion(Expr arg, Expr call, MethWithInst method) =>
+ public static ExprUserDefinedConversion CreateUserDefinedConversion(Expr arg, Expr call, MethWithInst method) =>
new ExprUserDefinedConversion(arg, call, method);
- public ExprCast CreateCast(CType type, Expr argument) => CreateCast(0, type, argument);
+ public static ExprCast CreateCast(CType type, Expr argument) => CreateCast(0, type, argument);
- public ExprCast CreateCast(EXPRFLAG flags, CType type, Expr argument) => new ExprCast(flags, type, argument);
+ public static ExprCast CreateCast(EXPRFLAG flags, CType type, Expr argument) => new ExprCast(flags, type, argument);
- public ExprLocal CreateLocal(LocalVariableSymbol local) => new ExprLocal(local);
+ public static ExprLocal CreateLocal(LocalVariableSymbol local) => new ExprLocal(local);
- public ExprBoundLambda CreateAnonymousMethod(AggregateType delegateType, Scope argumentScope, Expr expression) =>
+ public static ExprBoundLambda CreateAnonymousMethod(AggregateType delegateType, Scope argumentScope, Expr expression) =>
new ExprBoundLambda(delegateType, argumentScope, expression);
- public ExprMethodInfo CreateMethodInfo(MethPropWithInst mwi) =>
+ public static ExprMethodInfo CreateMethodInfo(MethPropWithInst mwi) =>
CreateMethodInfo(mwi.Meth(), mwi.GetType(), mwi.TypeArgs);
- public ExprMethodInfo CreateMethodInfo(MethodSymbol method, AggregateType methodType, TypeArray methodParameters)
- {
- return new ExprMethodInfo(
- Types.GetPredefAgg(method.IsConstructor() ? PredefinedType.PT_CONSTRUCTORINFO : PredefinedType.PT_METHODINFO).getThisType(),
+ public static ExprMethodInfo CreateMethodInfo(MethodSymbol method, AggregateType methodType, TypeArray methodParameters) =>
+ new ExprMethodInfo(
+ TypeManager.GetPredefAgg(method.IsConstructor() ? PredefinedType.PT_CONSTRUCTORINFO : PredefinedType.PT_METHODINFO).getThisType(),
method, methodType, methodParameters);
- }
- public ExprPropertyInfo CreatePropertyInfo(PropertySymbol prop, AggregateType propertyType) =>
- new ExprPropertyInfo(Types.GetPredefAgg(PredefinedType.PT_PROPERTYINFO).getThisType(), prop, propertyType);
+ public static ExprPropertyInfo CreatePropertyInfo(PropertySymbol prop, AggregateType propertyType) =>
+ new ExprPropertyInfo(TypeManager.GetPredefAgg(PredefinedType.PT_PROPERTYINFO).getThisType(), prop, propertyType);
- public ExprFieldInfo CreateFieldInfo(FieldSymbol field, AggregateType fieldType) =>
- new ExprFieldInfo(field, fieldType, Types.GetPredefAgg(PredefinedType.PT_FIELDINFO).getThisType());
+ public static ExprFieldInfo CreateFieldInfo(FieldSymbol field, AggregateType fieldType) =>
+ new ExprFieldInfo(field, fieldType, TypeManager.GetPredefAgg(PredefinedType.PT_FIELDINFO).getThisType());
- public ExprTypeOf CreateTypeOf(CType sourceType) =>
- new ExprTypeOf(Types.GetPredefAgg(PredefinedType.PT_TYPE).getThisType(), sourceType);
+ public static ExprTypeOf CreateTypeOf(CType sourceType) =>
+ new ExprTypeOf(TypeManager.GetPredefAgg(PredefinedType.PT_TYPE).getThisType(), sourceType);
-
- public ExprUserLogicalOp CreateUserLogOp(CType type, Expr trueFalseCall, ExprCall operatorCall) =>
+ public static ExprUserLogicalOp CreateUserLogOp(CType type, Expr trueFalseCall, ExprCall operatorCall) =>
new ExprUserLogicalOp(type, trueFalseCall, operatorCall);
- public ExprConcat CreateConcat(Expr first, Expr second) => new ExprConcat(first, second);
+ public static ExprConcat CreateConcat(Expr first, Expr second) => new ExprConcat(first, second);
- public ExprConstant CreateStringConstant(string str) =>
- CreateConstant(Types.GetPredefAgg(PredefinedType.PT_STRING).getThisType(), ConstVal.Get(str));
+ public static ExprConstant CreateStringConstant(string str) =>
+ CreateConstant(TypeManager.GetPredefAgg(PredefinedType.PT_STRING).getThisType(), ConstVal.Get(str));
- public ExprMultiGet CreateMultiGet(EXPRFLAG flags, CType type, ExprMulti multi) =>
+ public static ExprMultiGet CreateMultiGet(EXPRFLAG flags, CType type, ExprMulti multi) =>
new ExprMultiGet(type, flags, multi);
- public ExprMulti CreateMulti(EXPRFLAG flags, CType type, Expr left, Expr op) =>
+ public static ExprMulti CreateMulti(EXPRFLAG flags, CType type, Expr left, Expr op) =>
new ExprMulti(type, flags, left, op);
////////////////////////////////////////////////////////////////////////////////
@@ -102,20 +84,20 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
//
// This returns a null for reference types and an EXPRZEROINIT for all others.
- public Expr CreateZeroInit(CType type)
+ public static Expr CreateZeroInit(CType type)
{
Debug.Assert(type != null);
- if (type.isEnumType())
+ if (type.IsEnumType)
{
// For enum types, we create a constant that has the default value
// as an object pointer.
return CreateConstant(type, ConstVal.Get(Activator.CreateInstance(type.AssociatedSystemType)));
}
- Debug.Assert(type.fundType() > FUNDTYPE.FT_NONE);
- Debug.Assert(type.fundType() < FUNDTYPE.FT_COUNT);
- switch (type.fundType())
+ Debug.Assert(type.FundamentalType > FUNDTYPE.FT_NONE);
+ Debug.Assert(type.FundamentalType < FUNDTYPE.FT_COUNT);
+ switch (type.FundamentalType)
{
case FUNDTYPE.FT_PTR:
{
@@ -124,7 +106,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
case FUNDTYPE.FT_STRUCT:
- if (type.isPredefType(PredefinedType.PT_DECIMAL))
+ if (type.IsPredefType(PredefinedType.PT_DECIMAL))
{
goto default;
}
@@ -135,28 +117,28 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return new ExprZeroInit(type);
default:
- return CreateConstant(type, ConstVal.GetDefaultValue(type.constValKind()));
+ return CreateConstant(type, ConstVal.GetDefaultValue(type.ConstValKind));
}
}
- public ExprConstant CreateConstant(CType type, ConstVal constVal) => new ExprConstant(type, constVal);
+ public static ExprConstant CreateConstant(CType type, ConstVal constVal) => new ExprConstant(type, constVal);
- public ExprConstant CreateIntegerConstant(int x) =>
- CreateConstant(Types.GetPredefAgg(PredefinedType.PT_INT).getThisType(), ConstVal.Get(x));
+ public static ExprConstant CreateIntegerConstant(int x) =>
+ CreateConstant(TypeManager.GetPredefAgg(PredefinedType.PT_INT).getThisType(), ConstVal.Get(x));
- public ExprConstant CreateBoolConstant(bool b) =>
- CreateConstant(Types.GetPredefAgg(PredefinedType.PT_BOOL).getThisType(), ConstVal.Get(b));
+ public static ExprConstant CreateBoolConstant(bool b) =>
+ CreateConstant(TypeManager.GetPredefAgg(PredefinedType.PT_BOOL).getThisType(), ConstVal.Get(b));
- public ExprArrayIndex CreateArrayIndex(CType type, Expr array, Expr index) =>
+ public static ExprArrayIndex CreateArrayIndex(CType type, Expr array, Expr index) =>
new ExprArrayIndex(type, array, index);
- public ExprBinOp CreateBinop(ExpressionKind exprKind, CType type, Expr left, Expr right) =>
+ public static ExprBinOp CreateBinop(ExpressionKind exprKind, CType type, Expr left, Expr right) =>
new ExprBinOp(exprKind, type, left, right);
- public ExprUnaryOp CreateUnaryOp(ExpressionKind exprKind, CType type, Expr operand) =>
+ public static ExprUnaryOp CreateUnaryOp(ExpressionKind exprKind, CType type, Expr operand) =>
new ExprUnaryOp(exprKind, type, operand);
- public ExprOperator CreateOperator(ExpressionKind exprKind, CType type, Expr arg1, Expr arg2)
+ public static ExprOperator CreateOperator(ExpressionKind exprKind, CType type, Expr arg1, Expr arg2)
{
Debug.Assert(arg1 != null);
Debug.Assert(exprKind.IsUnaryOperator() == (arg2 == null));
@@ -165,15 +147,14 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
: CreateBinop(exprKind, type, arg1, arg2);
}
-
- public ExprBinOp CreateUserDefinedBinop(ExpressionKind exprKind, CType type, Expr left, Expr right, Expr call, MethPropWithInst userMethod) =>
+ public static ExprBinOp CreateUserDefinedBinop(ExpressionKind exprKind, CType type, Expr left, Expr right, Expr call, MethPropWithInst userMethod) =>
new ExprBinOp(exprKind, type, left, right, call, userMethod);
// The call may be lifted, but we do not mark the outer binop as lifted.
- public ExprUnaryOp CreateUserDefinedUnaryOperator(ExpressionKind exprKind, CType type, Expr operand, ExprCall call, MethPropWithInst userMethod) =>
+ public static ExprUnaryOp CreateUserDefinedUnaryOperator(ExpressionKind exprKind, CType type, Expr operand, ExprCall call, MethPropWithInst userMethod) =>
new ExprUnaryOp(exprKind, type, operand, call, userMethod);
- public ExprUnaryOp CreateNeg(EXPRFLAG flags, Expr operand)
+ public static ExprUnaryOp CreateNeg(EXPRFLAG flags, Expr operand)
{
Debug.Assert(operand != null);
ExprUnaryOp unary = CreateUnaryOp(ExpressionKind.Negate, operand.Type, operand);
@@ -184,22 +165,22 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
////////////////////////////////////////////////////////////////////////////////
// Create a node that evaluates the first, evaluates the second, results in the second.
- public ExprBinOp CreateSequence(Expr first, Expr second) =>
+ public static ExprBinOp CreateSequence(Expr first, Expr second) =>
CreateBinop(ExpressionKind.Sequence, second.Type, first, second);
////////////////////////////////////////////////////////////////////////////////
// Create a node that evaluates the first, evaluates the second, results in the first.
- public ExprAssignment CreateAssignment(Expr left, Expr right) => new ExprAssignment(left, right);
+ public static ExprAssignment CreateAssignment(Expr left, Expr right) => new ExprAssignment(left, right);
////////////////////////////////////////////////////////////////////////////////
- public ExprNamedArgumentSpecification CreateNamedArgumentSpecification(Name name, Expr value) =>
+ public static ExprNamedArgumentSpecification CreateNamedArgumentSpecification(Name name, Expr value) =>
new ExprNamedArgumentSpecification(name, value);
- public ExprWrap CreateWrap(Expr expression) => new ExprWrap(expression);
+ public static ExprWrap CreateWrap(Expr expression) => new ExprWrap(expression);
- public ExprBinOp CreateSave(ExprWrap wrap)
+ public static ExprBinOp CreateSave(ExprWrap wrap)
{
Debug.Assert(wrap != null);
ExprBinOp expr = CreateBinop(ExpressionKind.Save, wrap.Type, wrap.OptionalExpression, wrap);
@@ -207,13 +188,9 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return expr;
}
- public ExprConstant CreateNull() => CreateConstant(Types.GetNullType(), default(ConstVal));
+ public static ExprConstant CreateNull() => CreateConstant(NullType.Instance, default);
- public void AppendItemToList(
- Expr newItem,
- ref Expr first,
- ref Expr last
- )
+ public static void AppendItemToList(Expr newItem, ref Expr first, ref Expr last)
{
if (newItem == null)
{
@@ -241,14 +218,14 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
last = list.OptionalNextListNode;
}
- public ExprList CreateList(Expr op1, Expr op2) => new ExprList(op1, op2);
+ public static ExprList CreateList(Expr op1, Expr op2) => new ExprList(op1, op2);
- public ExprList CreateList(Expr op1, Expr op2, Expr op3) => CreateList(op1, CreateList(op2, op3));
+ public static ExprList CreateList(Expr op1, Expr op2, Expr op3) => CreateList(op1, CreateList(op2, op3));
- public ExprList CreateList(Expr op1, Expr op2, Expr op3, Expr op4) =>
+ public static ExprList CreateList(Expr op1, Expr op2, Expr op3, Expr op4) =>
CreateList(op1, CreateList(op2, CreateList(op3, op4)));
- public ExprClass CreateClass(CType type) => new ExprClass(type);
+ public static ExprClass CreateClass(CType type) => new ExprClass(type);
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ExpressionBinder.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ExpressionBinder.cs
index 00ca1e2c6b..79fe57db28 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ExpressionBinder.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ExpressionBinder.cs
@@ -12,11 +12,18 @@ using Microsoft.CSharp.RuntimeBinder.Syntax;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
// Used by bindUserDefinedConversion
- internal sealed class UdConvInfo
+ internal readonly struct UdConvInfo
{
- public MethWithType mwt;
- public bool fSrcImplicit;
- public bool fDstImplicit;
+ public readonly MethWithType Meth;
+ public readonly bool SrcImplicit;
+ public readonly bool DstImplicit;
+
+ public UdConvInfo(MethWithType mwt, bool srcImplicit, bool dstImplicit)
+ {
+ Meth = mwt;
+ SrcImplicit = srcImplicit;
+ DstImplicit = dstImplicit;
+ }
}
//////////////////////////////////////////////////////////////////////////////////////////////
@@ -136,7 +143,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
None
}
- internal sealed partial class ExpressionBinder
+ internal readonly partial struct ExpressionBinder
{
// ExpressionBinder - General Rules
//
@@ -253,118 +260,23 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// Factory method sets the "Do Children have Errors?" bit - not done manually.
// Once constructed Expression trees are not mutated - doesn't work easily for statements unfortunately.
- private delegate Expr PfnBindBinOp(ExpressionKind ek, EXPRFLAG flags, Expr op1, Expr op2);
- private delegate Expr PfnBindUnaOp(ExpressionKind ek, EXPRFLAG flags, Expr op);
+ private delegate Expr PfnBindBinOp(ExpressionBinder binder, ExpressionKind ek, EXPRFLAG flags, Expr op1, Expr op2);
+ private delegate Expr PfnBindUnaOp(ExpressionBinder binder, ExpressionKind ek, EXPRFLAG flags, Expr op);
- private BindingContext Context;
- public BindingContext GetContext() { return Context; }
- private CNullable m_nullable;
+ public BindingContext Context { get; }
public ExpressionBinder(BindingContext context)
{
Context = context;
- m_nullable = new CNullable(GetSymbolLoader(), GetErrorContext(), GetExprFactory());
- g_binopSignatures = new BinOpSig[]
- {
- new BinOpSig (PredefinedType.PT_INT, PredefinedType.PT_INT, BinOpMask.Integer, 8, BindIntBinOp, OpSigFlags.Value, BinOpFuncKind.IntBinOp ),
- new BinOpSig (PredefinedType.PT_UINT, PredefinedType.PT_UINT, BinOpMask.Integer, 7, BindIntBinOp, OpSigFlags.Value, BinOpFuncKind.IntBinOp ),
- new BinOpSig (PredefinedType.PT_LONG, PredefinedType.PT_LONG, BinOpMask.Integer, 6, BindIntBinOp, OpSigFlags.Value, BinOpFuncKind.IntBinOp ),
- new BinOpSig (PredefinedType.PT_ULONG, PredefinedType.PT_ULONG, BinOpMask.Integer, 5, BindIntBinOp, OpSigFlags.Value, BinOpFuncKind.IntBinOp ),
- /* ERROR */
- new BinOpSig (PredefinedType.PT_ULONG, PredefinedType.PT_LONG, BinOpMask.Integer, 4, null, OpSigFlags.Value, BinOpFuncKind.None ),
- /* ERROR */
- new BinOpSig (PredefinedType.PT_LONG, PredefinedType.PT_ULONG, BinOpMask.Integer, 3, null, OpSigFlags.Value, BinOpFuncKind.None ),
- new BinOpSig (PredefinedType.PT_FLOAT, PredefinedType.PT_FLOAT, BinOpMask.Real, 1, BindRealBinOp, OpSigFlags.Value, BinOpFuncKind.RealBinOp ),
- new BinOpSig (PredefinedType.PT_DOUBLE, PredefinedType.PT_DOUBLE, BinOpMask.Real, 0, BindRealBinOp, OpSigFlags.Value, BinOpFuncKind.RealBinOp ),
- new BinOpSig (PredefinedType.PT_DECIMAL, PredefinedType.PT_DECIMAL, BinOpMask.Real, 0, BindDecBinOp, OpSigFlags.Value, BinOpFuncKind.DecBinOp ),
- new BinOpSig (PredefinedType.PT_STRING, PredefinedType.PT_STRING, BinOpMask.Equal, 0, BindStrCmpOp, OpSigFlags.Reference, BinOpFuncKind.StrCmpOp ),
- new BinOpSig (PredefinedType.PT_STRING, PredefinedType.PT_STRING, BinOpMask.Add, 2, BindStrBinOp, OpSigFlags.Reference, BinOpFuncKind.StrBinOp ),
- new BinOpSig (PredefinedType.PT_STRING, PredefinedType.PT_OBJECT, BinOpMask.Add, 1, BindStrBinOp, OpSigFlags.Reference, BinOpFuncKind.StrBinOp ),
- new BinOpSig (PredefinedType.PT_OBJECT, PredefinedType.PT_STRING, BinOpMask.Add, 0, BindStrBinOp, OpSigFlags.Reference, BinOpFuncKind.StrBinOp ),
- new BinOpSig (PredefinedType.PT_INT, PredefinedType.PT_INT, BinOpMask.Shift, 3, BindShiftOp, OpSigFlags.Value, BinOpFuncKind.ShiftOp ),
- new BinOpSig (PredefinedType.PT_UINT, PredefinedType.PT_INT, BinOpMask.Shift, 2, BindShiftOp, OpSigFlags.Value, BinOpFuncKind.ShiftOp ),
- new BinOpSig (PredefinedType.PT_LONG, PredefinedType.PT_INT, BinOpMask.Shift, 1, BindShiftOp, OpSigFlags.Value, BinOpFuncKind.ShiftOp ),
- new BinOpSig (PredefinedType.PT_ULONG, PredefinedType.PT_INT, BinOpMask.Shift, 0, BindShiftOp, OpSigFlags.Value, BinOpFuncKind.ShiftOp ),
- new BinOpSig (PredefinedType.PT_BOOL, PredefinedType.PT_BOOL, BinOpMask.BoolNorm, 0, BindBoolBinOp, OpSigFlags.Value, BinOpFuncKind.BoolBinOp ),
- // Make boolean logical operators liftable so that they don't give funny short circuiting semantics.
- // This is for DDBugs 677075.
- new BinOpSig (PredefinedType.PT_BOOL, PredefinedType.PT_BOOL, BinOpMask.Logical, 0, BindBoolBinOp, OpSigFlags.BoolBit, BinOpFuncKind.BoolBinOp ),
- new BinOpSig (PredefinedType.PT_BOOL, PredefinedType.PT_BOOL, BinOpMask.Bitwise, 0, BindLiftedBoolBitwiseOp, OpSigFlags.BoolBit, BinOpFuncKind.BoolBitwiseOp ),
- };
- g_rguos = new UnaOpSig[]
- {
- new UnaOpSig( PredefinedType.PT_INT, UnaOpMask.Signed, 7, BindIntUnaOp, UnaOpFuncKind.IntUnaOp ),
- new UnaOpSig( PredefinedType.PT_UINT, UnaOpMask.Unsigned, 6, BindIntUnaOp, UnaOpFuncKind.IntUnaOp ),
- new UnaOpSig( PredefinedType.PT_LONG, UnaOpMask.Signed, 5, BindIntUnaOp, UnaOpFuncKind.IntUnaOp ),
- new UnaOpSig( PredefinedType.PT_ULONG, UnaOpMask.Unsigned, 4, BindIntUnaOp, UnaOpFuncKind.IntUnaOp ),
- /* ERROR */
- new UnaOpSig( PredefinedType.PT_ULONG, UnaOpMask.Minus, 3, null, UnaOpFuncKind.None ),
- new UnaOpSig( PredefinedType.PT_FLOAT, UnaOpMask.Real, 1, BindRealUnaOp, UnaOpFuncKind.RealUnaOp ),
- new UnaOpSig( PredefinedType.PT_DOUBLE, UnaOpMask.Real, 0, BindRealUnaOp, UnaOpFuncKind.RealUnaOp ),
- new UnaOpSig( PredefinedType.PT_DECIMAL, UnaOpMask.Real, 0, BindDecUnaOp, UnaOpFuncKind.DecUnaOp ),
- new UnaOpSig( PredefinedType.PT_BOOL, UnaOpMask.Bool, 0, BindBoolUnaOp, UnaOpFuncKind.BoolUnaOp ),
- new UnaOpSig( PredefinedType.PT_INT, UnaOpMask.IncDec, 6, null, UnaOpFuncKind.None ),
- new UnaOpSig( PredefinedType.PT_UINT, UnaOpMask.IncDec, 5, null, UnaOpFuncKind.None ),
- new UnaOpSig( PredefinedType.PT_LONG, UnaOpMask.IncDec, 4, null, UnaOpFuncKind.None ),
- new UnaOpSig( PredefinedType.PT_ULONG, UnaOpMask.IncDec, 3, null, UnaOpFuncKind.None ),
- new UnaOpSig( PredefinedType.PT_FLOAT, UnaOpMask.IncDec, 1, null, UnaOpFuncKind.None ),
- new UnaOpSig( PredefinedType.PT_DOUBLE, UnaOpMask.IncDec, 0, null, UnaOpFuncKind.None ),
- new UnaOpSig( PredefinedType.PT_DECIMAL, UnaOpMask.IncDec, 0, null, UnaOpFuncKind.None ),
- };
}
- private SymbolLoader GetSymbolLoader() { return SymbolLoader; }
-
- private SymbolLoader SymbolLoader
- {
- get
- {
- return Context.SymbolLoader;
- }
- }
-
- private CSemanticChecker SemanticChecker
- {
- get
- {
- return Context.SemanticChecker;
- }
- }
- public CSemanticChecker GetSemanticChecker() { return SemanticChecker; }
-
- private ErrorHandling ErrorContext
- {
- get
- {
- return SymbolLoader.ErrorContext;
- }
- }
- private ErrorHandling GetErrorContext() { return ErrorContext; }
-
- private BSYMMGR GetGlobalSymbols()
- {
- return GetSymbolLoader().getBSymmgr();
- }
-
- private TypeManager GetTypes() { return TypeManager; }
-
- private TypeManager TypeManager { get { return SymbolLoader.TypeManager; } }
-
- private ExprFactory GetExprFactory() { return ExprFactory; }
-
- private ExprFactory ExprFactory { get { return Context.ExprFactory; } }
-
- private AggregateType GetPredefindType(PredefinedType pt)
+ private static AggregateType GetPredefindType(PredefinedType pt)
{
Debug.Assert(pt != PredefinedType.PT_VOID); // use getVoidType()
- return GetSymbolLoader().GetPredefindType(pt);
+ return SymbolLoader.GetPredefindType(pt);
}
- private CType VoidType { get { return GetSymbolLoader().GetTypeManager().GetVoid(); } }
-
- private CType getVoidType() { return VoidType; }
-
private Expr GenerateAssignmentConversion(Expr op1, Expr op2, bool allowExplicit) =>
allowExplicit ? mustCastCore(op2, op1.Type, 0) : mustConvertCore(op2, op1.Type);
@@ -391,24 +303,25 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
ArrayType pArrayType = pOp1.Type as ArrayType;
Debug.Assert(pArrayType != null);
- CType elementType = pArrayType.GetElementType();
- checkUnsafe(elementType); // added to the binder so we don't bind to pointer ops
+ CType elementType = pArrayType.ElementType;
+ CheckUnsafe(elementType); // added to the binder so we don't bind to pointer ops
// Check the rank of the array against the number of indices provided, and
// convert the indexes to ints
CType pDestType = ChooseArrayIndexType(pOp2);
- Expr transformedIndices = pOp2.Map(GetExprFactory(),
+ ExpressionBinder binder = this;
+ Expr transformedIndices = pOp2.Map(
x =>
{
- Expr pTemp = mustConvert(x, pDestType);
+ Expr pTemp = binder.mustConvert(x, pDestType);
return pDestType == pIntType
? pTemp
- : GetExprFactory().CreateCast(EXPRFLAG.EXF_INDEXEXPR, pDestType, pTemp);
+ : ExprFactory.CreateCast(EXPRFLAG.EXF_INDEXEXPR, pDestType, pTemp);
});
// Allocate a new expression, the type is the element type of the array.
// Array index operations are always lvalues.
- return GetExprFactory().CreateArrayIndex(elementType, pOp1, transformedIndices);
+ return ExprFactory.CreateArrayIndex(elementType, pOp1, transformedIndices);
}
////////////////////////////////////////////////////////////////////////////////
@@ -427,7 +340,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// Make the cast expr anyway, and if we find that we have a constant, then set the cast expr
// as the original tree for the constant. Otherwise, return the cast expr.
- ExprCast exprCast = GetExprFactory().CreateCast(exprFlags, typeDest, exprSrc);
+ ExprCast exprCast = ExprFactory.CreateCast(exprFlags, typeDest, exprSrc);
if (Context.Checked)
{
exprCast.Flags |= EXPRFLAG.EXF_CHECKOVERFLOW;
@@ -437,10 +350,10 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// original tree to the cast.
if (exprConst is ExprConstant constant && exprFlags == 0 &&
- exprSrc.Type.fundType() == typeDest.fundType() &&
- (!exprSrc.Type.isPredefType(PredefinedType.PT_STRING) || constant.Val.IsNullRef))
+ exprSrc.Type.FundamentalType == typeDest.FundamentalType &&
+ (!exprSrc.Type.IsPredefType(PredefinedType.PT_STRING) || constant.Val.IsNullRef))
{
- ExprConstant expr = GetExprFactory().CreateConstant(typeDest, constant.Val);
+ ExprConstant expr = ExprFactory.CreateConstant(typeDest, constant.Val);
pexprDest = expr;
return;
}
@@ -463,11 +376,10 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Debug.Assert(mwi.Sym is MethodSymbol && (!mwi.Meth().isOverride || mwi.Meth().isHideByName));
Debug.Assert(pMemGroup != null);
- bool fConstrained;
Expr pObject = pMemGroup.OptionalObject;
CType callingObjectType = pObject?.Type;
PostBindMethod(mwi);
- pObject = AdjustMemberObject(mwi, pObject, out fConstrained);
+ pObject = AdjustMemberObject(mwi, pObject);
pMemGroup.OptionalObject = pObject;
CType pReturnType;
@@ -477,10 +389,10 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
else
{
- pReturnType = GetTypes().SubstType(mwi.Meth().RetType, mwi.GetType(), mwi.TypeArgs);
+ pReturnType = TypeManager.SubstType(mwi.Meth().RetType, mwi.GetType(), mwi.TypeArgs);
}
- ExprCall pResult = GetExprFactory().CreateCall(0, pReturnType, pArguments, pMemGroup, mwi);
+ ExprCall pResult = ExprFactory.CreateCall(0, pReturnType, pArguments, pMemGroup, mwi);
// Set the return type and flags for constructors.
if ((flags & MemLookFlags.Ctor) != 0)
@@ -491,18 +403,11 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
else
{
- Debug.Assert(pResult.Type == getVoidType());
+ Debug.Assert(pResult.Type == VoidType.Instance);
}
}
- if (fConstrained && pObject != null)
- {
- // Use the constrained prefix.
- pResult.Flags |= EXPRFLAG.EXF_CONSTRAINED;
- }
-
verifyMethodArgs(pResult, callingObjectType);
-
return pResult;
}
@@ -512,21 +417,24 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
internal Expr BindToField(Expr pOptionalObject, FieldWithType fwt, BindingFlag bindFlags)
{
- Debug.Assert(fwt.GetType() != null && fwt.Field().getClass() == fwt.GetType().getAggregate());
+ Debug.Assert(fwt.GetType() != null && fwt.Field().getClass() == fwt.GetType().OwningAggregate);
- CType pFieldType = GetTypes().SubstType(fwt.Field().GetType(), fwt.GetType());
- pOptionalObject = AdjustMemberObject(fwt, pOptionalObject, out _);
+ CType pFieldType = TypeManager.SubstType(fwt.Field().GetType(), fwt.GetType());
+ pOptionalObject = AdjustMemberObject(fwt, pOptionalObject);
- checkUnsafe(pFieldType); // added to the binder so we don't bind to pointer ops
+ CheckUnsafe(pFieldType); // added to the binder so we don't bind to pointer ops
// lvalue if the object is an lvalue (or it's static) and the field is not readonly.
- bool isLValue = objectIsLvalue(pOptionalObject) && !fwt.Field().isReadOnly;
+ // Since dynamic objects for fields come from locals or casts/conversions on locals
+ // (never properties) and hence always have EXF_LVALUE set, the first part of this is
+ // always true, leaving the rest to be determined by the field ctor
+ AssertObjectIsLvalue(pOptionalObject);
AggregateType fieldType = null;
// If this field is the backing field of a WindowsRuntime event then we need to bind to its
// invocationlist property which is a delegate containing all the handlers.
- if (fwt.Field().isEvent && fwt.Field().getEvent(GetSymbolLoader()) != null
- && fwt.Field().getEvent(GetSymbolLoader()).IsWindowsRuntimeEvent)
+ if (fwt.Field().isEvent && fwt.Field().getEvent() != null
+ && fwt.Field().getEvent().IsWindowsRuntimeEvent)
{
fieldType = fwt.Field().GetType() as AggregateType;
if (fieldType != null)
@@ -534,12 +442,11 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// Access event backing field (EventRegistrationTokenTable<T>) using
// EventRegistrationTokenTable<T>.GetOrCreateEventRegistrationTokenTable()
// to ensure non-null
- pFieldType = GetTypes().GetParameterModifier(pFieldType, false);
+ pFieldType = TypeManager.GetParameterModifier(pFieldType, false);
}
}
- ExprField pResult = GetExprFactory()
- .CreateField(pFieldType, pOptionalObject, fwt, isLValue);
+ ExprField pResult = ExprFactory.CreateField(pFieldType, pOptionalObject, fwt);
Debug.Assert(BindingFlag.BIND_MEMBERSET == (BindingFlag)EXPRFLAG.EXF_MEMBERSET);
pResult.Flags |= (EXPRFLAG)(bindFlags & BindingFlag.BIND_MEMBERSET);
@@ -548,34 +455,29 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
Name getOrCreateMethodName =
NameManager.GetPredefinedName(PredefinedName.PN_GETORCREATEEVENTREGISTRATIONTOKENTABLE);
- GetSymbolLoader()
- .RuntimeBinderSymbolTable.PopulateSymbolTableWithName(
- getOrCreateMethodName.Text, null, fieldType.AssociatedSystemType);
+ SymbolTable.PopulateSymbolTableWithName(
+ getOrCreateMethodName.Text, null, fieldType.AssociatedSystemType);
MethodSymbol getOrCreateMethod =
- GetSymbolLoader()
- .LookupAggMember(getOrCreateMethodName, fieldType.getAggregate(), symbmask_t.MASK_MethodSymbol)
+ SymbolLoader.LookupAggMember(getOrCreateMethodName, fieldType.OwningAggregate, symbmask_t.MASK_MethodSymbol)
as MethodSymbol;
MethPropWithInst getOrCreatempwi = new MethPropWithInst(getOrCreateMethod, fieldType);
- ExprMemberGroup getOrCreateGrp = GetExprFactory().CreateMemGroup(null, getOrCreatempwi);
+ ExprMemberGroup getOrCreateGrp = ExprFactory.CreateMemGroup(null, getOrCreatempwi);
Expr getOrCreateCall = BindToMethod(
new MethWithInst(getOrCreatempwi), pResult, getOrCreateGrp, (MemLookFlags)MemLookFlags.None);
- AggregateSymbol fieldTypeSymbol = fieldType.GetOwningAggregate();
+ AggregateSymbol fieldTypeSymbol = fieldType.OwningAggregate;
Name invocationListName = NameManager.GetPredefinedName(PredefinedName.PN_INVOCATIONLIST);
// InvocationList might not be populated in the symbol table as no one would have called it.
- GetSymbolLoader()
- .RuntimeBinderSymbolTable.PopulateSymbolTableWithName(
- invocationListName.Text, null, fieldType.AssociatedSystemType);
+ SymbolTable.PopulateSymbolTableWithName(invocationListName.Text, null, fieldType.AssociatedSystemType);
PropertySymbol invocationList =
- GetSymbolLoader()
- .LookupAggMember(invocationListName, fieldTypeSymbol, symbmask_t.MASK_PropertySymbol)
+ SymbolLoader.LookupAggMember(invocationListName, fieldTypeSymbol, symbmask_t.MASK_PropertySymbol)
as PropertySymbol;
MethPropWithInst mpwi = new MethPropWithInst(invocationList, fieldType);
- ExprMemberGroup memGroup = GetExprFactory().CreateMemGroup(getOrCreateCall, mpwi);
+ ExprMemberGroup memGroup = ExprFactory.CreateMemGroup(getOrCreateCall, mpwi);
PropWithType pwt = new PropWithType(invocationList, fieldType);
Expr propertyExpr = BindToProperty(getOrCreateCall, pwt, bindFlags, null, memGroup);
@@ -591,38 +493,36 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
Debug.Assert(pwt.Sym is PropertySymbol &&
pwt.GetType() != null &&
- pwt.Prop().getClass() == pwt.GetType().getAggregate());
+ pwt.Prop().getClass() == pwt.GetType().OwningAggregate);
Debug.Assert(pwt.Prop().Params.Count == 0 || pwt.Prop() is IndexerSymbol);
- bool fConstrained;
-
// We keep track of the type of the pObject which we're doing the call through so that we can report
// protection access errors later, either below when binding the get, or later when checking that
// the setter is actually an lvalue.
Expr pObjectThrough = pObject;
- PostBindProperty(pwt, pObject, out MethWithType mwtGet, out MethWithType mwtSet);
+ PostBindProperty(pwt, out MethWithType mwtGet, out MethWithType mwtSet);
if (mwtGet &&
(!mwtSet ||
mwtSet.GetType() == mwtGet.GetType() ||
- GetSymbolLoader().HasBaseConversion(mwtGet.GetType(), mwtSet.GetType())
+ SymbolLoader.HasBaseConversion(mwtGet.GetType(), mwtSet.GetType())
)
)
{
- pObject = AdjustMemberObject(mwtGet, pObject, out fConstrained);
+ pObject = AdjustMemberObject(mwtGet, pObject);
}
else if (mwtSet)
{
- pObject = AdjustMemberObject(mwtSet, pObject, out fConstrained);
+ pObject = AdjustMemberObject(mwtSet, pObject);
}
else
{
- pObject = AdjustMemberObject(pwt, pObject, out fConstrained);
+ pObject = AdjustMemberObject(pwt, pObject);
}
pMemGroup.OptionalObject = pObject;
- CType pReturnType = GetTypes().SubstType(pwt.Prop().RetType, pwt.GetType());
+ CType pReturnType = TypeManager.SubstType(pwt.Prop().RetType, pwt.GetType());
// if we are doing a get on this thing, and there is no get, and
// most importantly, we are not leaving the arguments to be bound by the array index
@@ -631,7 +531,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
if (!mwtGet)
{
- throw ErrorContext.Error(ErrorCode.ERR_PropertyLacksGet, pwt);
+ throw ErrorHandling.Error(ErrorCode.ERR_PropertyLacksGet, pwt);
}
CType type = null;
@@ -640,54 +540,45 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
type = pObjectThrough.Type;
}
- ACCESSERROR error = SemanticChecker.CheckAccess2(mwtGet.Meth(), mwtGet.GetType(), ContextForMemberLookup(), type);
+ ACCESSERROR error = CSemanticChecker.CheckAccess2(mwtGet.Meth(), mwtGet.GetType(), ContextForMemberLookup, type);
if (error != ACCESSERROR.ACCESSERROR_NOERROR)
{
// if the get exists, but is not accessible, give an error.
if (error == ACCESSERROR.ACCESSERROR_NOACCESSTHRU)
{
- throw ErrorContext.Error(ErrorCode.ERR_BadProtectedAccess, pwt, type, ContextForMemberLookup());
+ throw ErrorHandling.Error(ErrorCode.ERR_BadProtectedAccess, pwt, type, ContextForMemberLookup);
}
- throw ErrorContext.Error(ErrorCode.ERR_InaccessibleGetter, pwt);
+ throw ErrorHandling.Error(ErrorCode.ERR_InaccessibleGetter, pwt);
}
}
- ExprProperty result = GetExprFactory().CreateProperty(pReturnType, pObjectThrough, args, pMemGroup, pwt, mwtSet);
- if (fConstrained && pObject != null)
- {
- // Use the constrained prefix.
- result.Flags |= EXPRFLAG.EXF_CONSTRAINED;
- }
-
+ ExprProperty result = ExprFactory.CreateProperty(pReturnType, pObjectThrough, args, pMemGroup, pwt, mwtSet);
if (result.OptionalArguments != null)
{
verifyMethodArgs(result, pObjectThrough?.Type);
}
- if (mwtSet && objectIsLvalue(result.MemberGroup.OptionalObject))
- {
- result.Flags |= EXPRFLAG.EXF_LVALUE;
- }
+ AssertObjectIsLvalue(result.MemberGroup.OptionalObject);
return result;
}
internal Expr bindUDUnop(ExpressionKind ek, Expr arg)
{
- Name pName = ekName(ek);
+ Name pName = ExpressionKindName(ek);
Debug.Assert(pName != null);
CType typeSrc = arg.Type;
LAgain:
- switch (typeSrc.GetTypeKind())
+ switch (typeSrc.TypeKind)
{
case TypeKind.TK_NullableType:
typeSrc = typeSrc.StripNubs();
goto LAgain;
case TypeKind.TK_AggregateType:
- if (!typeSrc.isClassType() && !typeSrc.isStructType() || ((AggregateType)typeSrc).getAggregate().IsSkipUDOps())
+ if (!typeSrc.IsClassType && !typeSrc.IsStructType || ((AggregateType)typeSrc).OwningAggregate.IsSkipUDOps())
return null;
break;
default:
@@ -703,49 +594,58 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
MethodSymbol methCur = null;
AggregateType atsCur = (AggregateType)typeSrc;
- for (; ;)
+ for (;;)
{
// Find the next operator.
- methCur = methCur == null
- ? GetSymbolLoader().LookupAggMember(pName, atsCur.getAggregate(), symbmask_t.MASK_MethodSymbol) as MethodSymbol
- : SymbolLoader.LookupNextSym(methCur, atsCur.getAggregate(), symbmask_t.MASK_MethodSymbol) as MethodSymbol;
+ methCur = (methCur == null
+ ? SymbolLoader.LookupAggMember(pName, atsCur.OwningAggregate, symbmask_t.MASK_MethodSymbol)
+ : methCur.LookupNext(symbmask_t.MASK_MethodSymbol)) as MethodSymbol;
if (methCur == null)
{
// Find the next type.
// If we've found some applicable methods in a class then we don't need to look any further.
if (!methFirstList.IsEmpty())
+ {
break;
- atsCur = atsCur.GetBaseClass();
+ }
+
+ atsCur = atsCur.BaseClass;
if (atsCur == null)
+ {
break;
+ }
+
continue;
}
// Only look at operators with 1 args.
if (!methCur.isOperator || methCur.Params.Count != 1)
+ {
continue;
+ }
+
Debug.Assert(methCur.typeVars.Count == 0);
- TypeArray paramsCur = GetTypes().SubstTypeArray(methCur.Params, atsCur);
+ TypeArray paramsCur = TypeManager.SubstTypeArray(methCur.Params, atsCur);
CType typeParam = paramsCur[0];
NullableType nubParam;
if (canConvert(arg, typeParam))
{
methFirstList.Add(new CandidateFunctionMember(
- new MethPropWithInst(methCur, atsCur, BSYMMGR.EmptyTypeArray()),
+ new MethPropWithInst(methCur, atsCur, TypeArray.Empty),
paramsCur,
0,
false));
}
- else if (typeParam.IsNonNubValType() &&
- GetTypes().SubstType(methCur.RetType, atsCur).IsNonNubValType() &&
- canConvert(arg, nubParam = GetTypes().GetNullable(typeParam)))
+ else if (typeParam.IsNonNullableValueType &&
+ TypeManager.SubstType(methCur.RetType, atsCur).IsNonNullableValueType &&
+ canConvert(arg, nubParam = TypeManager.GetNullable(typeParam)))
{
methFirstList.Add(new CandidateFunctionMember(
- new MethPropWithInst(methCur, atsCur, BSYMMGR.EmptyTypeArray()),
- GetGlobalSymbols().AllocParams(1, new CType[] { nubParam }),
+ new MethPropWithInst(methCur, atsCur, TypeArray.Empty),
+ TypeArray.Allocate(nubParam),
1,
false));
}
@@ -761,7 +661,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (pmethBest == null)
{
// No winner, so its an ambiguous call...
- throw ErrorContext.Error(ErrorCode.ERR_AmbigCall, pmethAmbig1.mpwi, pmethAmbig2.mpwi);
+ throw ErrorHandling.Error(ErrorCode.ERR_AmbigCall, pmethAmbig1.mpwi, pmethAmbig2.mpwi);
}
ExprCall call;
@@ -775,7 +675,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
call = BindUDUnopCall(arg, pmethBest.@params[0], pmethBest.mpwi);
}
- return GetExprFactory().CreateUserDefinedUnaryOperator(ek, call.Type, arg, call, pmethBest.mpwi);
+ return ExprFactory.CreateUserDefinedUnaryOperator(ek, call.Type, arg, call, pmethBest.mpwi);
}
private ExprCall BindLiftedUDUnop(Expr arg, CType typeArg, MethPropWithInst mpwi)
@@ -788,18 +688,18 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
Debug.Assert(arg.Type is NullableType);
- CType typeRet = GetTypes().SubstType(mpwi.Meth().RetType, mpwi.GetType());
+ CType typeRet = TypeManager.SubstType(mpwi.Meth().RetType, mpwi.GetType());
if (!(typeRet is NullableType))
{
- typeRet = GetTypes().GetNullable(typeRet);
+ typeRet = TypeManager.GetNullable(typeRet);
}
// First bind the non-lifted version for errors.
Expr nonLiftedArg = mustCast(arg, typeRaw);
ExprCall nonLiftedResult = BindUDUnopCall(nonLiftedArg, typeRaw, mpwi);
- ExprMemberGroup pMemGroup = GetExprFactory().CreateMemGroup(null, mpwi);
- ExprCall call = GetExprFactory().CreateCall(0, typeRet, arg, pMemGroup, null);
+ ExprMemberGroup pMemGroup = ExprFactory.CreateMemGroup(null, mpwi);
+ ExprCall call = ExprFactory.CreateCall(0, typeRet, arg, pMemGroup, null);
call.MethWithInst = new MethWithInst(mpwi);
call.CastOfNonLiftedResultToLiftedType = mustCast(nonLiftedResult, typeRet, 0);
call.NullableCallLiftKind = NullableCallLiftKind.Operator;
@@ -808,10 +708,10 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
private ExprCall BindUDUnopCall(Expr arg, CType typeArg, MethPropWithInst mpwi)
{
- CType typeRet = GetTypes().SubstType(mpwi.Meth().RetType, mpwi.GetType());
- checkUnsafe(typeRet); // added to the binder so we don't bind to pointer ops
- ExprMemberGroup pMemGroup = GetExprFactory().CreateMemGroup(null, mpwi);
- ExprCall call = GetExprFactory().CreateCall(0, typeRet, mustConvert(arg, typeArg), pMemGroup, null);
+ CType typeRet = TypeManager.SubstType(mpwi.Meth().RetType, mpwi.GetType());
+ CheckUnsafe(typeRet); // added to the binder so we don't bind to pointer ops
+ ExprMemberGroup pMemGroup = ExprFactory.CreateMemGroup(null, mpwi);
+ ExprCall call = ExprFactory.CreateCall(0, typeRet, mustConvert(arg, typeArg), pMemGroup, null);
call.MethWithInst = new MethWithInst(mpwi);
verifyMethodArgs(call, mpwi.GetType());
return call;
@@ -917,7 +817,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
////////////////////////////////////////////////////////////////////////////////
// Report a bad operator types error to the user.
- private RuntimeBinderException BadOperatorTypesError(Expr pOperand1, Expr pOperand2)
+ private static RuntimeBinderException BadOperatorTypesError(Expr pOperand1, Expr pOperand2)
{
// This is a hack, but we need to store the operation somewhere... the first argument's as
// good a place as any.
@@ -929,10 +829,10 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (pOperand2 != null)
{
Debug.Assert(pOperand2.Type != null);
- return ErrorContext.Error(ErrorCode.ERR_BadBinaryOps, strOp, pOperand1.Type, pOperand2.Type);
+ return ErrorHandling.Error(ErrorCode.ERR_BadBinaryOps, strOp, pOperand1.Type, pOperand2.Type);
}
- return ErrorContext.Error(ErrorCode.ERR_BadUnaryOp, strOp, pOperand1.Type);
+ return ErrorHandling.Error(ErrorCode.ERR_BadUnaryOp, strOp, pOperand1.Type);
}
private static ErrorCode GetStandardLvalueError(CheckLvalueKind kind)
@@ -961,12 +861,12 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
private void CheckPropertyAccess(MethWithType mwt, PropWithType pwtSlot, CType type)
{
- switch (SemanticChecker.CheckAccess2(mwt.Meth(), mwt.GetType(), ContextForMemberLookup(), type))
+ switch (CSemanticChecker.CheckAccess2(mwt.Meth(), mwt.GetType(), ContextForMemberLookup, type))
{
case ACCESSERROR.ACCESSERROR_NOACCESSTHRU:
- throw ErrorContext.Error(ErrorCode.ERR_BadProtectedAccess, pwtSlot, type, ContextForMemberLookup());
+ throw ErrorHandling.Error(ErrorCode.ERR_BadProtectedAccess, pwtSlot, type, ContextForMemberLookup);
case ACCESSERROR.ACCESSERROR_NOACCESS:
- throw ErrorContext.Error(mwt.Meth().isSetAccessor() ? ErrorCode.ERR_InaccessibleSetter : ErrorCode.ERR_InaccessibleGetter, pwtSlot);
+ throw ErrorHandling.Error(mwt.Meth().isSetAccessor() ? ErrorCode.ERR_InaccessibleSetter : ErrorCode.ERR_InaccessibleGetter, pwtSlot);
}
}
@@ -982,7 +882,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
CheckLvalueProp(prop);
}
- markFieldAssigned(expr);
return;
}
@@ -993,94 +892,83 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
case ExpressionKind.Property:
ExprProperty prop = (ExprProperty)expr;
- if (!prop.MethWithTypeSet)
- {
- // Assigning to a property without a setter.
- // If we have
- // bool? b = true; (bool)b = false;
- // then this is realized immediately as
- // b.Value = false;
- // and no ExpressionKind.EK_CAST is generated. We'd rather not give a "you're writing
- // to a read-only property" error in the case where the property access
- // is not explicit in the source code. Fortunately in this case the
- // cast is still hanging around in the parse tree, so we can look for it.
-
- // POSSIBLE ERROR: It would be nice to also give this error for other situations
- // POSSIBLE ERROR: in which the user is attempting to assign to a value, such as
- // POSSIBLE ERROR: an explicit (bool)b.Value = false;
- // POSSIBLE ERROR: Unfortunately we cannot use this trick in that situation because
- // POSSIBLE ERROR: we've already discarded the OperatorKind.OP_CAST node. (This is an SyntaxKind.Dot).
-
- // SPEC VIOLATION: More generally:
- // SPEC VIOLATION: The spec states that the result of any cast is a value, not a
- // SPEC VIOLATION: variable. Unfortunately we do not correctly implement this
- // SPEC VIOLATION: and we probably should not start implementing it because this
- // SPEC VIOLATION: would be a breaking change. We currently discard "no op" casts
- // SPEC VIOLATION: very aggressively rather than generating an ExpressionKind.EK_CAST node.
-
- throw ErrorContext.Error(ErrorCode.ERR_AssgReadonlyProp, prop.PropWithTypeSlot);
- }
- break;
+ Debug.Assert(!prop.MethWithTypeSet);
+ // Assigning to a property without a setter.
+ // If we have
+ // bool? b = true; (bool)b = false;
+ // then this is realized immediately as
+ // b.Value = false;
+ // and no ExpressionKind.EK_CAST is generated. We'd rather not give a "you're writing
+ // to a read-only property" error in the case where the property access
+ // is not explicit in the source code. Fortunately in this case the
+ // cast is still hanging around in the parse tree, so we can look for it.
+
+ // POSSIBLE ERROR: It would be nice to also give this error for other situations
+ // POSSIBLE ERROR: in which the user is attempting to assign to a value, such as
+ // POSSIBLE ERROR: an explicit (bool)b.Value = false;
+ // POSSIBLE ERROR: Unfortunately we cannot use this trick in that situation because
+ // POSSIBLE ERROR: we've already discarded the OperatorKind.OP_CAST node. (This is an SyntaxKind.Dot).
+
+ // SPEC VIOLATION: More generally:
+ // SPEC VIOLATION: The spec states that the result of any cast is a value, not a
+ // SPEC VIOLATION: variable. Unfortunately we do not correctly implement this
+ // SPEC VIOLATION: and we probably should not start implementing it because this
+ // SPEC VIOLATION: would be a breaking change. We currently discard "no op" casts
+ // SPEC VIOLATION: very aggressively rather than generating an ExpressionKind.EK_CAST node.
+
+ throw ErrorHandling.Error(ErrorCode.ERR_AssgReadonlyProp, prop.PropWithTypeSlot);
+
+ case ExpressionKind.Field:
+ ExprField field = (ExprField)expr;
+ Debug.Assert(field.FieldWithType.Field().isReadOnly);
+ throw ErrorHandling.Error(
+ field.FieldWithType.Field().isStatic
+ ? ErrorCode.ERR_AssgReadonlyStatic
+ : ErrorCode.ERR_AssgReadonly);
- case ExpressionKind.BoundLambda:
- case ExpressionKind.Constant:
- throw ErrorContext.Error(GetStandardLvalueError(kind));
+ default:
+ throw ErrorHandling.Error(GetStandardLvalueError(kind));
}
-
- TryReportLvalueFailure(expr, kind);
}
- private void PostBindMethod(MethWithInst pMWI)
+ private static void PostBindMethod(MethWithInst pMWI)
{
MethodSymbol meth = pMWI.Meth();
if (meth.RetType != null)
{
- checkUnsafe(meth.RetType);
+ CheckUnsafe(meth.RetType);
// We need to check unsafe on the parameters as well, since we cannot check in conversion.
foreach (CType type in meth.Params.Items)
{
- checkUnsafe(type);
+ CheckUnsafe(type);
}
}
}
- private void PostBindProperty(PropWithType pwt, Expr pObject, out MethWithType pmwtGet, out MethWithType pmwtSet)
+ private static void PostBindProperty(PropWithType pwt, out MethWithType pmwtGet, out MethWithType pmwtSet)
{
- pmwtGet = new MethWithType();
- pmwtSet = new MethWithType();
+ PropertySymbol prop = pwt.Prop();
+ Debug.Assert(prop != null);
// Get the accessors.
- if (pwt.Prop().GetterMethod != null)
- {
- pmwtGet.Set(pwt.Prop().GetterMethod, pwt.GetType());
- }
- else
- {
- pmwtGet.Clear();
- }
-
- if (pwt.Prop().SetterMethod != null)
- {
- pmwtSet.Set(pwt.Prop().SetterMethod, pwt.GetType());
- }
- else
- {
- pmwtSet.Clear();
- }
+ pmwtGet = prop.GetterMethod != null
+ ? new MethWithType(prop.GetterMethod, pwt.GetType())
+ : new MethWithType();
+ pmwtSet = prop.SetterMethod != null
+ ? new MethWithType(prop.SetterMethod, pwt.GetType())
+ : new MethWithType();
- if (pwt.Prop().RetType != null)
+ if (prop.RetType != null)
{
- checkUnsafe(pwt.Prop().RetType);
+ CheckUnsafe(prop.RetType);
}
}
- private Expr AdjustMemberObject(SymWithType swt, Expr pObject, out bool pfConstrained)
+ private Expr AdjustMemberObject(SymWithType swt, Expr pObject)
{
// Assert that the type is present and is an instantiation of the member's parent.
- Debug.Assert(swt.GetType() != null && swt.GetType().getAggregate() == swt.Sym.parent as AggregateSymbol);
+ Debug.Assert(swt.GetType() != null && swt.GetType().OwningAggregate == swt.Sym.parent as AggregateSymbol);
bool bIsMatchingStatic = IsMatchingStatic(swt, pObject);
- pfConstrained = false;
-
bool isStatic = swt.Sym.isStatic;
// If our static doesn't match, bail out of here.
@@ -1096,10 +984,10 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return null;
}
- throw ErrorContext.Error(ErrorCode.ERR_ObjectProhibited, swt);
+ throw ErrorHandling.Error(ErrorCode.ERR_ObjectProhibited, swt);
}
- throw ErrorContext.Error(ErrorCode.ERR_ObjectRequired, swt);
+ throw ErrorHandling.Error(ErrorCode.ERR_ObjectRequired, swt);
}
// At this point, all errors for static invocations have been reported, and
@@ -1131,44 +1019,17 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (typeObj is TypeParameterType || typeObj is AggregateType)
{
AggregateSymbol aggCalled = swt.Sym.parent as AggregateSymbol;
- Debug.Assert(swt.GetType().getAggregate() == aggCalled);
-
- // If we're invoking code on a struct-valued field, mark the struct as assigned (to
- // avoid warning CS0649).
- if (pObject is ExprField field && !field.FieldWithType.Field().isAssigned && !(swt.Sym is FieldSymbol) &&
- typeObj.isStructType() && !typeObj.isPredefined())
- {
- field.FieldWithType.Field().isAssigned = true;
- }
-
- if (pfConstrained &&
- (typeObj is TypeParameterType ||
- typeObj.isStructType() && swt.GetType().IsRefType() && swt.Sym.IsVirtual()))
- {
- // For calls on type parameters or virtual calls on struct types (not enums),
- // use the constrained prefix.
- pfConstrained = true;
- }
+ Debug.Assert(swt.GetType().OwningAggregate == aggCalled);
- Expr objNew = tryConvert(pObject, swt.GetType(), CONVERTTYPE.NOUDC);
-
- // This check ensures that we do not bind to methods in an outer class
- // which are visible, but whose this pointer is of an incorrect type...
- // ... also handles case of calling an pObject method on a RefAny value.
- // WE don't give a great message for this, but it'll do.
- if (objNew == null)
- {
- throw ErrorContext.Error(ErrorCode.ERR_WrongNestedThis, swt.GetType(), pObject.Type);
- }
-
- pObject = objNew;
+ pObject = tryConvert(pObject, swt.GetType(), CONVERTTYPE.NOUDC);
+ Debug.Assert(pObject != null);
}
return pObject;
}
/////////////////////////////////////////////////////////////////////////////////
- private bool IsMatchingStatic(SymWithType swt, Expr pObject)
+ private static bool IsMatchingStatic(SymWithType swt, Expr pObject)
{
Symbol pSym = swt.Sym;
@@ -1205,16 +1066,16 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
////////////////////////////////////////////////////////////////////////////////
// this determines whether the expression as an pObject of a prop or field is an
// lvalue
-
- private bool objectIsLvalue(Expr pObject)
+ [Conditional("DEBUG")]
+ private static void AssertObjectIsLvalue(Expr pObject)
{
- return (
+ Debug.Assert (
pObject == null || // statics are always lvalues
(((pObject.Flags & EXPRFLAG.EXF_LVALUE) != 0) && (pObject.Kind != ExpressionKind.Property)) ||
// things marked as lvalues have props/fields which are lvalues, with one exception: props of structs
// do not have fields/structs as lvalues
- !pObject.Type.isStructOrEnum()
+ !pObject.Type.IsStructOrEnum
// non-struct types are lvalues (such as non-struct method returns)
);
}
@@ -1238,7 +1099,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
newArgs = null;
Expr newArgsTail = null;
- MethodOrPropertySymbol mostDerivedMethod = GroupToArgsBinder.FindMostDerivedMethod(GetSymbolLoader(), mp, callingObjectType);
+ MethodOrPropertySymbol mostDerivedMethod = GroupToArgsBinder.FindMostDerivedMethod(mp, callingObjectType);
int paramCount = mp.Params.Count;
TypeArray @params = mp.Params;
@@ -1267,7 +1128,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
if (paramCount != 0)
paramCount--;
- GetExprFactory().AppendItemToList(indir, ref newArgs, ref newArgsTail);
+ ExprFactory.AppendItemToList(indir, ref newArgs, ref newArgsTail);
}
else if (paramCount != 0)
{
@@ -1294,7 +1155,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
Debug.Assert(index != mp.Params.Count);
- CType substDestType = GetTypes().SubstType(@params[index], type, pTypeArgs);
+ CType substDestType = TypeManager.SubstType(@params[index], type, pTypeArgs);
// If we cant convert the argument and we're the param array argument, then deal with it.
if (!canConvert(named.Value, substDestType) &&
@@ -1308,10 +1169,10 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// void Foo(int y, params int[] x);
// ...
// Foo(x:1, y:1);
- CType arrayType = (ArrayType)GetTypes().SubstType(mp.Params[mp.Params.Count - 1], type, pTypeArgs);
+ CType arrayType = (ArrayType)TypeManager.SubstType(mp.Params[mp.Params.Count - 1], type, pTypeArgs);
// Use an EK_ARRINIT even in the empty case so empty param arrays in attributes work.
- ExprArrayInit arrayInit = GetExprFactory().CreateArrayInit(arrayType, null, null, new[] { 0 }, 1);
+ ExprArrayInit arrayInit = ExprFactory.CreateArrayInit(arrayType, null, null, new[] { 0 }, 1);
arrayInit.GeneratedForParamArray = true;
arrayInit.OptionalArguments = named.Value;
@@ -1327,7 +1188,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
else
{
- CType substDestType = GetTypes().SubstType(@params[iDst], type, pTypeArgs);
+ CType substDestType = TypeManager.SubstType(@params[iDst], type, pTypeArgs);
rval = tryConvert(indir, substDestType);
}
@@ -1349,7 +1210,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
Debug.Assert(rval != null);
indir = rval;
- GetExprFactory().AppendItemToList(rval, ref newArgs, ref newArgsTail);
+ ExprFactory.AppendItemToList(rval, ref newArgs, ref newArgsTail);
paramCount--;
}
// note that destype might not be valid if we are in varargs, but then we won't ever use it...
@@ -1375,7 +1236,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
// we need to create an array and put it as the last arg...
- CType substitutedArrayType = GetTypes().SubstType(mp.Params[mp.Params.Count - 1], type, pTypeArgs);
+ CType substitutedArrayType = TypeManager.SubstType(mp.Params[mp.Params.Count - 1], type, pTypeArgs);
if (!(substitutedArrayType is ArrayType subArr) || !subArr.IsSZArray)
{
// Invalid type for params array parameter. Happens in LAF scenarios, e.g.
@@ -1386,10 +1247,10 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return;
}
- CType elementType = subArr.GetElementType();
+ CType elementType = subArr.ElementType;
// Use an EK_ARRINIT even in the empty case so empty param arrays in attributes work.
- ExprArrayInit exprArrayInit = GetExprFactory().CreateArrayInit(substitutedArrayType, null, null, new[] { 0 }, 1);
+ ExprArrayInit exprArrayInit = ExprFactory.CreateArrayInit(substitutedArrayType, null, null, new[] { 0 }, 1);
exprArrayInit.GeneratedForParamArray = true;
if (it.AtEnd())
@@ -1403,9 +1264,9 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
else
{
- argsPtr = GetExprFactory().CreateList(argsPtr, exprArrayInit);
+ argsPtr = ExprFactory.CreateList(argsPtr, exprArrayInit);
}
- GetExprFactory().AppendItemToList(exprArrayInit, ref newArgs, ref newArgsTail);
+ ExprFactory.AppendItemToList(exprArrayInit, ref newArgs, ref newArgsTail);
}
else
{
@@ -1427,31 +1288,13 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
expr = tryConvert(expr, elementType);
}
- GetExprFactory().AppendItemToList(expr, ref newList, ref newListTail);
+ ExprFactory.AppendItemToList(expr, ref newList, ref newListTail);
}
exprArrayInit.DimensionSize = count;
exprArrayInit.DimensionSizes[0] = count;
exprArrayInit.OptionalArguments = newList;
- GetExprFactory().AppendItemToList(exprArrayInit, ref newArgs, ref newArgsTail);
- }
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // Sets the isAssigned bit
-
- private void markFieldAssigned(Expr expr)
- {
- if (0 != (expr.Flags & EXPRFLAG.EXF_LVALUE) && expr is ExprField field)
- {
- FieldSymbol symbol;
- do
- {
- symbol = field.FieldWithType.Field();
- symbol.isAssigned = true;
- expr = field.OptionalObject;
- }
- while (symbol.getClass().IsStruct() && !symbol.isStatic && expr != null && (field = expr as ExprField) != null);
+ ExprFactory.AppendItemToList(exprArrayInit, ref newArgs, ref newArgsTail);
}
}
@@ -1463,8 +1306,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
PredefinedType.PT_ULONG
};
-
-
internal CType ChooseArrayIndexType(Expr args)
{
// first, select the allowable types
@@ -1489,7 +1330,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return GetPredefindType(PredefinedType.PT_INT);
}
- internal void FillInArgInfoFromArgList(ArgInfos argInfo, Expr args)
+ internal static void FillInArgInfoFromArgList(ArgInfos argInfo, Expr args)
{
CType[] prgtype = new CType[argInfo.carg];
argInfo.prgexpr = new List<Expr>();
@@ -1517,10 +1358,10 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
Debug.Assert(iarg <= argInfo.carg);
- argInfo.types = GetGlobalSymbols().AllocParams(iarg, prgtype);
+ argInfo.types = TypeArray.Allocate(prgtype);
}
- private bool TryGetExpandedParams(TypeArray @params, int count, out TypeArray ppExpandedParams)
+ private static bool TryGetExpandedParams(TypeArray @params, int count, out TypeArray ppExpandedParams)
{
CType[] prgtype;
if (count < @params.Count - 1)
@@ -1530,7 +1371,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// case that all the parameters are optional.
prgtype = new CType[@params.Count - 1];
@params.CopyItems(0, @params.Count - 1, prgtype);
- ppExpandedParams = GetGlobalSymbols().AllocParams(@params.Count - 1, prgtype);
+ ppExpandedParams = TypeArray.Allocate(prgtype);
return true;
}
@@ -1547,14 +1388,14 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
// At this point, we have an array sym.
- CType elementType = arr.GetElementType();
+ CType elementType = arr.ElementType;
for (int itype = @params.Count - 1; itype < count; itype++)
{
prgtype[itype] = elementType;
}
- ppExpandedParams = GetGlobalSymbols().AllocParams(prgtype);
+ ppExpandedParams = TypeArray.Allocate(prgtype);
return true;
}
@@ -1567,18 +1408,19 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return (!sym.isOverride || sym.isHideByName) && (!requireUC || sym.isUserCallable());
}
- private bool isConvInTable(List<UdConvInfo> convTable, MethodSymbol meth, AggregateType ats, bool fSrc, bool fDst)
+ private static bool IsConvInTable(List<UdConvInfo> convTable, MethodSymbol meth, AggregateType ats, bool fSrc, bool fDst)
{
foreach (UdConvInfo conv in convTable)
{
- if (conv.mwt.Meth() == meth &&
- conv.mwt.GetType() == ats &&
- conv.fSrcImplicit == fSrc &&
- conv.fDstImplicit == fDst)
+ if (conv.Meth.Meth() == meth &&
+ conv.Meth.GetType() == ats &&
+ conv.SrcImplicit == fSrc &&
+ conv.DstImplicit == fDst)
{
return true;
}
}
+
return false;
}
@@ -1592,8 +1434,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
private static bool isConstantInRange(ExprConstant exprSrc, CType typeDest, bool realsOk)
{
- FUNDTYPE ftSrc = exprSrc.Type.fundType();
- FUNDTYPE ftDest = typeDest.fundType();
+ FUNDTYPE ftSrc = exprSrc.Type.FundamentalType;
+ FUNDTYPE ftDest = typeDest.FundamentalType;
if (ftSrc > FUNDTYPE.FT_LASTINTEGRAL || ftDest > FUNDTYPE.FT_LASTINTEGRAL)
{
@@ -1780,35 +1622,25 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
PredefinedName.PN_OPRIGHTSHIFT,
};
- private Name ekName(ExpressionKind ek)
+ private static Name ExpressionKindName(ExpressionKind ek)
{
Debug.Assert(ek >= ExpressionKind.FirstOp && (ek - ExpressionKind.FirstOp) < (int)s_EK2NAME.Length);
return NameManager.GetPredefinedName(s_EK2NAME[ek - ExpressionKind.FirstOp]);
}
- private void checkUnsafe(CType type)
+ private static void CheckUnsafe(CType type)
{
- if (type == null || type.isUnsafe())
+ if (type == null || type.IsUnsafe())
{
- throw ErrorContext.Error(ErrorCode.ERR_UnsafeNeeded);
+ throw ErrorHandling.Error(ErrorCode.ERR_UnsafeNeeded);
}
}
- ////////////////////////////////////////////////////////////////////////////////
- private AggregateDeclaration ContextForMemberLookup()
- {
- return Context.ContextForMemberLookup;
- }
+ private AggregateSymbol ContextForMemberLookup => Context.ContextForMemberLookup;
- private ExprWrap WrapShortLivedExpression(Expr expr)
- {
- return GetExprFactory().CreateWrap(expr);
- }
+ private static ExprWrap WrapShortLivedExpression(Expr expr) => ExprFactory.CreateWrap(expr);
- private ExprAssignment GenerateOptimizedAssignment(Expr op1, Expr op2)
- {
- return GetExprFactory().CreateAssignment(op1, op2);
- }
+ private static ExprAssignment GenerateOptimizedAssignment(Expr op1, Expr op2) => ExprFactory.CreateAssignment(op1, op2);
internal static int CountArguments(Expr args)
{
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/GlobalSymbolContext.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/GlobalSymbolContext.cs
deleted file mode 100644
index 5648093d61..0000000000
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/GlobalSymbolContext.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using Microsoft.CSharp.RuntimeBinder.Syntax;
-
-namespace Microsoft.CSharp.RuntimeBinder.Semantics
-{
- /*****************************************************************************
- A GlobalSymbolContext represents the global symbol tables for a compilation.
- This includes symbols, types, declarations.
- *****************************************************************************/
-
- internal sealed class GlobalSymbolContext
- {
- private readonly PredefinedTypes _predefTypes;
-
- public GlobalSymbolContext()
- {
- GlobalSymbols = new BSYMMGR();
- _predefTypes = new PredefinedTypes(GlobalSymbols);
- TypeManager = new TypeManager(GlobalSymbols, _predefTypes);
- }
-
- public TypeManager TypeManager { get; }
- public TypeManager GetTypes() { return TypeManager; }
- private BSYMMGR GlobalSymbols { get; }
- public BSYMMGR GetGlobalSymbols() { return GlobalSymbols; }
- public PredefinedTypes GetPredefTypes() { return _predefTypes; }
-
- public SymFactory GetGlobalSymbolFactory()
- {
- return GetGlobalSymbols().GetSymFactory();
- }
- }
-}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/GroupToArgsBinder.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/GroupToArgsBinder.cs
index ca14129b71..aa9ccbd587 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/GroupToArgsBinder.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/GroupToArgsBinder.cs
@@ -16,7 +16,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// to the best applicable method in the group.
// ----------------------------------------------------------------------------
- internal sealed partial class ExpressionBinder
+ internal readonly partial struct ExpressionBinder
{
internal sealed class GroupToArgsBinder
{
@@ -60,7 +60,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
public GroupToArgsBinder(ExpressionBinder exprBinder, BindingFlag bindFlags, ExprMemberGroup grp, ArgInfos args, ArgInfos originalArgs, NamedArgumentsKind namedArgumentsKind)
{
Debug.Assert(grp != null);
- Debug.Assert(exprBinder != null);
Debug.Assert(args != null);
_pExprBinder = exprBinder;
@@ -100,28 +99,12 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
}
- public GroupToArgsBinderResult GetResultsOfBind()
- {
- return _results;
- }
+ public GroupToArgsBinderResult GetResultsOfBind() => _results;
- private SymbolLoader GetSymbolLoader()
- {
- return _pExprBinder.GetSymbolLoader();
- }
- private CSemanticChecker GetSemanticChecker()
- {
- return _pExprBinder.GetSemanticChecker();
- }
- private ErrorHandling GetErrorContext()
- {
- return _pExprBinder.GetErrorContext();
- }
private static CType GetTypeQualifier(ExprMemberGroup pGroup)
{
Debug.Assert(pGroup != null);
-
return (pGroup.Flags & EXPRFLAG.EXF_CTOR) != 0 ? pGroup.ParentType : pGroup.OptionalObject?.Type;
}
@@ -137,7 +120,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// iterator will only return propsyms (or methsyms, or whatever)
symbmask_t mask = (symbmask_t)(1 << (int)_pGroup.SymKind);
- CMemberLookupResults.CMethodIterator iterator = _pGroup.MemberLookupResults.GetMethodIterator(GetSemanticChecker(), GetSymbolLoader(), GetTypeQualifier(_pGroup), _pExprBinder.ContextForMemberLookup(), _pGroup.TypeArgs.Count, _pGroup.Flags, mask, _namedArgumentsKind == NamedArgumentsKind.NonTrailing ? _pOriginalArguments : null);
+ CMemberLookupResults.CMethodIterator iterator = _pGroup.MemberLookupResults.GetMethodIterator(GetTypeQualifier(_pGroup), _pExprBinder.ContextForMemberLookup, _pGroup.TypeArgs.Count, _pGroup.Flags, mask, _namedArgumentsKind == NamedArgumentsKind.NonTrailing ? _pOriginalArguments : null);
while (true)
{
bool bFoundExpanded;
@@ -283,19 +266,16 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// When we find a method, we check if the type has interfaces. If so, mark the other interfaces
// as hidden, and object as well.
- if (_pCurrentType.isInterfaceType())
+ if (_pCurrentType.IsInterfaceType)
{
- TypeArray ifaces = _pCurrentType.GetIfacesAll();
- for (int i = 0; i < ifaces.Count; i++)
+ foreach (AggregateType type in _pCurrentType.IfacesAll.Items)
{
- AggregateType type = ifaces[i] as AggregateType;
-
- Debug.Assert(type.isInterfaceType());
+ Debug.Assert(type.IsInterfaceType);
_HiddenTypes.Add(type);
}
// Mark object.
- AggregateType typeObject = GetSymbolLoader().GetPredefindType(PredefinedType.PT_OBJECT);
+ AggregateType typeObject = SymbolLoader.GetPredefindType(PredefinedType.PT_OBJECT);
_HiddenTypes.Add(typeObject);
}
}
@@ -314,7 +294,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
}
- private void CopyArgInfos(ArgInfos src, ArgInfos dst)
+ private static void CopyArgInfos(ArgInfos src, ArgInfos dst)
{
dst.carg = src.carg;
dst.types = src.types;
@@ -352,11 +332,11 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
pAmbig1.mpwi.GetType() != pAmbig2.mpwi.GetType() ||
pAmbig1.mpwi.MethProp().Params == pAmbig2.mpwi.MethProp().Params)
{
- throw GetErrorContext().Error(ErrorCode.ERR_AmbigCall, pAmbig1.mpwi, pAmbig2.mpwi);
+ throw ErrorHandling.Error(ErrorCode.ERR_AmbigCall, pAmbig1.mpwi, pAmbig2.mpwi);
}
// The two signatures are identical so don't use the type args in the error message.
- throw GetErrorContext().Error(ErrorCode.ERR_AmbigCall, pAmbig1.mpwi.MethProp(), pAmbig2.mpwi.MethProp());
+ throw ErrorHandling.Error(ErrorCode.ERR_AmbigCall, pAmbig1.mpwi.MethProp(), pAmbig2.mpwi.MethProp());
}
}
@@ -410,26 +390,12 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
_bArgumentsChangedForNamedOrOptionalArguments = ReOrderArgsForNamedArguments(
- methprop,
- _pCurrentParameters,
- _pCurrentType,
- _pGroup,
- _pArguments,
- _pExprBinder.GetTypes(),
- _pExprBinder.GetExprFactory(),
- GetSymbolLoader());
+ methprop, _pCurrentParameters, _pCurrentType, _pGroup, _pArguments);
return _bArgumentsChangedForNamedOrOptionalArguments;
}
internal static bool ReOrderArgsForNamedArguments(
- MethodOrPropertySymbol methprop,
- TypeArray pCurrentParameters,
- AggregateType pCurrentType,
- ExprMemberGroup pGroup,
- ArgInfos pArguments,
- TypeManager typeManager,
- ExprFactory exprFactory,
- SymbolLoader symbolLoader)
+ MethodOrPropertySymbol methprop, TypeArray pCurrentParameters, AggregateType pCurrentType, ExprMemberGroup pGroup, ArgInfos pArguments)
{
// We use the param count from pCurrentParameters because they may have been resized
// for param arrays.
@@ -441,7 +407,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// set, then for the remainder, look for a named argument with a matching name.
int index = 0;
Expr paramArrayArgument = null;
- TypeArray @params = typeManager.SubstTypeArray(
+ TypeArray @params = TypeManager.SubstTypeArray(
pCurrentParameters,
pCurrentType,
pGroup.TypeArgs);
@@ -480,7 +446,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
if (methprop.IsParameterOptional(index))
{
- pNewArg = GenerateOptionalArgument(symbolLoader, exprFactory, methprop, @params[index], index);
+ pNewArg = GenerateOptionalArgument(methprop, @params[index], index);
}
else if (paramArrayArgument != null && index == methprop.Params.Count - 1)
{
@@ -511,18 +477,13 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
prgTypes[i] = pArguments.prgexpr[i].Type;
}
pArguments.carg = pCurrentParameters.Count;
- pArguments.types = symbolLoader.getBSymmgr().AllocParams(pCurrentParameters.Count, prgTypes);
+ pArguments.types = TypeArray.Allocate(prgTypes);
return true;
}
/////////////////////////////////////////////////////////////////////////////////
- private static Expr GenerateOptionalArgument(
- SymbolLoader symbolLoader,
- ExprFactory exprFactory,
- MethodOrPropertySymbol methprop,
- CType type,
- int index)
+ private static Expr GenerateOptionalArgument(MethodOrPropertySymbol methprop, CType type, int index)
{
CType pParamType = type;
CType pRawParamType = type.StripNubs();
@@ -533,16 +494,16 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
CType pConstValType = methprop.GetDefaultParameterValueConstValType(index);
ConstVal cv = methprop.GetDefaultParameterValue(index);
- if (pConstValType.isPredefType(PredefinedType.PT_DATETIME) &&
- (pRawParamType.isPredefType(PredefinedType.PT_DATETIME) || pRawParamType.isPredefType(PredefinedType.PT_OBJECT) || pRawParamType.isPredefType(PredefinedType.PT_VALUE)))
+ if (pConstValType.IsPredefType(PredefinedType.PT_DATETIME) &&
+ (pRawParamType.IsPredefType(PredefinedType.PT_DATETIME) || pRawParamType.IsPredefType(PredefinedType.PT_OBJECT) || pRawParamType.IsPredefType(PredefinedType.PT_VALUE)))
{
// This is the specific case where we want to create a DateTime
// but the constval that stores it is a long.
- AggregateType dateTimeType = symbolLoader.GetPredefindType(PredefinedType.PT_DATETIME);
- optionalArgument = exprFactory.CreateConstant(dateTimeType, ConstVal.Get(DateTime.FromBinary(cv.Int64Val)));
+ AggregateType dateTimeType = SymbolLoader.GetPredefindType(PredefinedType.PT_DATETIME);
+ optionalArgument = ExprFactory.CreateConstant(dateTimeType, ConstVal.Get(DateTime.FromBinary(cv.Int64Val)));
}
- else if (pConstValType.isSimpleOrEnumOrString())
+ else if (pConstValType.IsSimpleOrEnumOrString)
{
// In this case, the constval is a simple type (all the numerics, including
// decimal), or an enum or a string. This covers all the substantial values,
@@ -551,20 +512,17 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// For enum parameters, we create a constant of the enum type. For everything
// else, we create the appropriate constant.
- if (pRawParamType.isEnumType() && pConstValType == pRawParamType.underlyingType())
- {
- optionalArgument = exprFactory.CreateConstant(pRawParamType, cv);
- }
- else
- {
- optionalArgument = exprFactory.CreateConstant(pConstValType, cv);
- }
+ optionalArgument = ExprFactory.CreateConstant(
+ pRawParamType.IsEnumType && pConstValType == pRawParamType.UnderlyingEnumType
+ ? pRawParamType
+ : pConstValType,
+ cv);
}
- else if ((pParamType.IsRefType() || pParamType is NullableType) && cv.IsNullRef)
+ else if ((pParamType.IsReferenceType || pParamType is NullableType) && cv.IsNullRef)
{
// We have an "= null" default value with a reference type or a nullable type.
- optionalArgument = exprFactory.CreateNull();
+ optionalArgument = ExprFactory.CreateNull();
}
else
{
@@ -572,7 +530,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// interpreted as default(something). For instance, the pParamType could be
// a type parameter type or a non-simple value type.
- optionalArgument = exprFactory.CreateZeroInit(pParamType);
+ optionalArgument = ExprFactory.CreateZeroInit(pParamType);
}
}
else
@@ -580,25 +538,25 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// There was no default parameter specified, so generally use default(T),
// except for some cases when the parameter type in metatdata is object.
- if (pParamType.isPredefType(PredefinedType.PT_OBJECT))
+ if (pParamType.IsPredefType(PredefinedType.PT_OBJECT))
{
if (methprop.MarshalAsObject(index))
{
// For [opt] parameters of type object, if we have marshal(iunknown),
// marshal(idispatch), or marshal(interface), then we emit a null.
- optionalArgument = exprFactory.CreateNull();
+ optionalArgument = ExprFactory.CreateNull();
}
else
{
// Otherwise, we generate Type.Missing
- AggregateSymbol agg = symbolLoader.GetPredefAgg(PredefinedType.PT_MISSING);
+ AggregateSymbol agg = SymbolLoader.GetPredefAgg(PredefinedType.PT_MISSING);
Name name = NameManager.GetPredefinedName(PredefinedName.PN_CAP_VALUE);
- FieldSymbol field = symbolLoader.LookupAggMember(name, agg, symbmask_t.MASK_FieldSymbol) as FieldSymbol;
+ FieldSymbol field = SymbolLoader.LookupAggMember(name, agg, symbmask_t.MASK_FieldSymbol) as FieldSymbol;
FieldWithType fwt = new FieldWithType(field, agg.getThisType());
- ExprField exprField = exprFactory.CreateField(agg.getThisType(), null, fwt, false);
- optionalArgument = exprFactory.CreateCast(type, exprField);
+ ExprField exprField = ExprFactory.CreateField(agg.getThisType(), null, fwt);
+ optionalArgument = ExprFactory.CreateCast(type, exprField);
}
}
else
@@ -606,7 +564,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// Every type aside from object that doesn't have a default value gets
// its default value.
- optionalArgument = exprFactory.CreateZeroInit(pParamType);
+ optionalArgument = ExprFactory.CreateZeroInit(pParamType);
}
}
@@ -615,21 +573,10 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return optionalArgument;
}
- /////////////////////////////////////////////////////////////////////////////////
-
- private MethodOrPropertySymbol FindMostDerivedMethod(
- MethodOrPropertySymbol pMethProp,
- Expr pObject)
- {
- return FindMostDerivedMethod(GetSymbolLoader(), pMethProp, pObject?.Type);
- }
-
- /////////////////////////////////////////////////////////////////////////////////
+ private static MethodOrPropertySymbol FindMostDerivedMethod(MethodOrPropertySymbol pMethProp, Expr pObject) =>
+ FindMostDerivedMethod(pMethProp, pObject?.Type);
- public static MethodOrPropertySymbol FindMostDerivedMethod(
- SymbolLoader symbolLoader,
- MethodOrPropertySymbol pMethProp,
- CType pType)
+ public static MethodOrPropertySymbol FindMostDerivedMethod(MethodOrPropertySymbol pMethProp, CType pType)
{
bool bIsIndexer = false;
@@ -664,13 +611,13 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return method;
}
- for (AggregateSymbol pAggregate = agg.GetOwningAggregate();
+ for (AggregateSymbol pAggregate = agg.OwningAggregate;
pAggregate?.GetBaseAgg() != null;
pAggregate = pAggregate.GetBaseAgg())
{
- for (MethodOrPropertySymbol meth = symbolLoader.LookupAggMember(method.name, pAggregate, symbmask_t.MASK_MethodSymbol | symbmask_t.MASK_PropertySymbol) as MethodOrPropertySymbol;
+ for (MethodOrPropertySymbol meth = SymbolLoader.LookupAggMember(method.name, pAggregate, symbmask_t.MASK_MethodSymbol | symbmask_t.MASK_PropertySymbol) as MethodOrPropertySymbol;
meth != null;
- meth = SymbolLoader.LookupNextSym(meth, pAggregate, symbmask_t.MASK_MethodSymbol | symbmask_t.MASK_PropertySymbol) as MethodOrPropertySymbol)
+ meth = meth.LookupNext(symbmask_t.MASK_MethodSymbol | symbmask_t.MASK_PropertySymbol) as MethodOrPropertySymbol)
{
if (!meth.isOverride)
{
@@ -732,7 +679,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// just generate defaults for every missing argument.
int i = _pArguments.carg;
int index = 0;
- TypeArray @params = _pExprBinder.GetTypes().SubstTypeArray(
+ TypeArray @params = TypeManager.SubstTypeArray(
_pCurrentParameters,
_pCurrentType,
_pGroup.TypeArgs);
@@ -745,7 +692,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return false;
}
- pArguments[index] = GenerateOptionalArgument(GetSymbolLoader(), _pExprBinder.GetExprFactory(), methprop, @params[i], i);
+ pArguments[index] = GenerateOptionalArgument(methprop, @params[i], i);
}
// Success. Lets copy them in now.
@@ -758,7 +705,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
prgTypes[n] = _pArguments.prgexpr[n].Type;
}
- _pArguments.types = GetSymbolLoader().getBSymmgr().AllocParams(@params.Count, prgTypes);
+ _pArguments.types = TypeArray.Allocate(prgTypes);
_pArguments.carg = @params.Count;
_bArgumentsChangedForNamedOrOptionalArguments = true;
return true;
@@ -852,7 +799,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (_pCurrentType != type &&
_pCurrentType != null &&
!_methList.IsEmpty() &&
- !_methList.Head().mpwi.GetType().isInterfaceType())
+ !_methList.Head().mpwi.GetType().IsInterfaceType)
{
return false;
}
@@ -911,7 +858,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Debug.Assert(_methList.IsEmpty() || _methList.Head().mpwi.MethProp() != _pCurrentSym);
// Construct the expanded params.
- return _pExprBinder.TryGetExpandedParams(_pCurrentSym.Params, _pArguments.carg, out _pCurrentParameters);
+ return TryGetExpandedParams(_pCurrentSym.Params, _pArguments.carg, out _pCurrentParameters);
}
private Result DetermineCurrentTypeArgs()
@@ -938,8 +885,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// error sym to go to any type.
bool inferenceSucceeded = MethodTypeInferrer.Infer(
- _pExprBinder, GetSymbolLoader(), methSym, _pCurrentParameters, _pArguments,
- out _pCurrentTypeArgs);
+ _pExprBinder, methSym, _pCurrentParameters, _pArguments, out _pCurrentTypeArgs);
if (!inferenceSucceeded)
{
@@ -974,7 +920,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
for (int ivar = 0; ivar < _pArguments.carg; ivar++)
{
CType var = _pCurrentParameters[ivar];
- bool constraintErrors = !TypeBind.CheckConstraints(GetSemanticChecker(), GetErrorContext(), var, CheckConstraintsFlags.NoErrors);
+ bool constraintErrors = !TypeBind.CheckConstraints(var, CheckConstraintsFlags.NoErrors);
if (constraintErrors && !DoesTypeArgumentsContainErrorSym(var))
{
_mpwiParamTypeConstraints.Set(_pCurrentSym, _pCurrentType, _pCurrentTypeArgs);
@@ -1017,8 +963,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// (think ErrorType != ErrorType)
// See if they just differ in out / ref.
CType argStripped = _pArguments.types[ivar] is ParameterModifierType modArg ?
- modArg.GetParameterType() : _pArguments.types[ivar];
- CType varStripped = var is ParameterModifierType modVar ? modVar.GetParameterType() : var;
+ modArg.ParameterType : _pArguments.types[ivar];
+ CType varStripped = var is ParameterModifierType modVar ? modVar.ParameterType : var;
if (argStripped == varStripped)
{
@@ -1054,7 +1000,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// Parameter types might have changed as a result of
// method type inference.
- _pCurrentParameters = _pExprBinder.GetTypes().SubstTypeArray(
+ _pCurrentParameters = TypeManager.SubstTypeArray(
_pCurrentParameters, _pCurrentType, _pCurrentTypeArgs);
// It is also possible that an optional argument has changed its value
@@ -1092,19 +1038,19 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Debug.Assert(pMethod != null);
}
Debug.Assert(pMethod.IsParameterOptional(iParam));
- Expr pArgumentNew = GenerateOptionalArgument(GetSymbolLoader(), _pExprBinder.GetExprFactory(), pMethod, _pCurrentParameters[iParam], iParam);
+ Expr pArgumentNew = GenerateOptionalArgument(pMethod, _pCurrentParameters[iParam], iParam);
_pArguments.prgexpr[iParam] = pArgumentNew;
}
}
- private bool DoesTypeArgumentsContainErrorSym(CType var)
+ private static bool DoesTypeArgumentsContainErrorSym(CType var)
{
if (!(var is AggregateType varAgg))
{
return false;
}
- TypeArray typeVars = varAgg.GetTypeArgsAll();
+ TypeArray typeVars = varAgg.TypeArgsAll;
for (int i = 0; i < typeVars.Count; i++)
{
CType type = typeVars[i];
@@ -1141,7 +1087,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (_results.BestResult.TypeArgs.Count > 0)
{
// Check method type variable constraints.
- TypeBind.CheckMethConstraints(GetSemanticChecker(), GetErrorContext(), new MethWithInst(_results.BestResult));
+ TypeBind.CheckMethConstraints(new MethWithInst(_results.BestResult));
}
}
}
@@ -1151,7 +1097,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// First and foremost, report if the user specified a name more than once.
if (_pDuplicateSpecifiedName != null)
{
- return GetErrorContext().Error(ErrorCode.ERR_DuplicateNamedArgument, _pDuplicateSpecifiedName);
+ return ErrorHandling.Error(ErrorCode.ERR_DuplicateNamedArgument, _pDuplicateSpecifiedName);
}
Debug.Assert(_methList.IsEmpty());
@@ -1159,7 +1105,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (_results.InaccessibleResult)
{
// We might have called this, but it is inaccessible...
- return GetSemanticChecker().ReportAccessError(_results.InaccessibleResult, _pExprBinder.ContextForMemberLookup(), GetTypeQualifier(_pGroup));
+ return CSemanticChecker.ReportAccessError(_results.InaccessibleResult, _pExprBinder.ContextForMemberLookup, GetTypeQualifier(_pGroup));
}
if (_misnamed)
@@ -1184,7 +1130,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// We have the bad name. Is it misplaced or absent?
if (paramNames.Contains(name))
{
- return GetErrorContext().Error(ErrorCode.ERR_BadNonTrailingNamedArgument, name);
+ return ErrorHandling.Error(ErrorCode.ERR_BadNonTrailingNamedArgument, name);
}
// Let this be handled by _pInvalidSpecifiedName handling.
@@ -1197,22 +1143,21 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
else if (_mpwiBogus)
{
// We might have called this, but it is bogus...
- return GetErrorContext().Error(ErrorCode.ERR_BindToBogus, _mpwiBogus);
+ return ErrorHandling.Error(ErrorCode.ERR_BindToBogus, _mpwiBogus);
}
bool bUseDelegateErrors = false;
Name nameErr = _pGroup.Name;
// Check for an invoke.
- if (_pGroup.OptionalObject != null &&
- _pGroup.OptionalObject.Type != null &&
- _pGroup.OptionalObject.Type.isDelegateType() &&
- _pGroup.Name == NameManager.GetPredefinedName(PredefinedName.PN_INVOKE))
+ if (_pGroup.OptionalObject?.Type != null &&
+ _pGroup.OptionalObject.Type.IsDelegateType &&
+ _pGroup.Name == NameManager.GetPredefinedName(PredefinedName.PN_INVOKE))
{
Debug.Assert(!_results.BestResult || _results.BestResult.MethProp().getClass().IsDelegate());
- Debug.Assert(!_results.BestResult || _results.BestResult.GetType().getAggregate().IsDelegate());
+ Debug.Assert(!_results.BestResult || _results.BestResult.GetType().OwningAggregate.IsDelegate());
bUseDelegateErrors = true;
- nameErr = _pGroup.OptionalObject.Type.getAggregate().name;
+ nameErr = ((AggregateType)_pGroup.OptionalObject.Type).OwningAggregate.name;
}
if (_results.BestResult)
@@ -1230,21 +1175,20 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
Debug.Assert(_results.UninferableResult.Sym is MethodSymbol);
- MethWithType mwtCantInfer = new MethWithType();
- mwtCantInfer.Set(_results.UninferableResult.Meth(), _results.UninferableResult.GetType());
- return GetErrorContext().Error(ErrorCode.ERR_CantInferMethTypeArgs, mwtCantInfer);
+ MethWithType mwtCantInfer = new MethWithType(_results.UninferableResult.Meth(), _results.UninferableResult.GetType());
+ return ErrorHandling.Error(ErrorCode.ERR_CantInferMethTypeArgs, mwtCantInfer);
}
if (_mwtBadArity)
{
int cvar = _mwtBadArity.Meth().typeVars.Count;
- return GetErrorContext().Error(cvar > 0 ? ErrorCode.ERR_BadArity : ErrorCode.ERR_HasNoTypeVars, _mwtBadArity, new ErrArgSymKind(_mwtBadArity.Meth()), _pArguments.carg);
+ return ErrorHandling.Error(cvar > 0 ? ErrorCode.ERR_BadArity : ErrorCode.ERR_HasNoTypeVars, _mwtBadArity, new ErrArgSymKind(_mwtBadArity.Meth()), _pArguments.carg);
}
if (_mpwiParamTypeConstraints)
{
// This will always report an error
- TypeBind.CheckMethConstraints(GetSemanticChecker(), GetErrorContext(), new MethWithInst(_mpwiParamTypeConstraints));
+ TypeBind.CheckMethConstraints(new MethWithInst(_mpwiParamTypeConstraints));
Debug.Fail("Unreachable");
return null;
}
@@ -1252,39 +1196,38 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (_pInvalidSpecifiedName != null)
{
// Give a better message for delegate invoke.
- return _pGroup.OptionalObject != null && _pGroup.OptionalObject.Type is AggregateType agg
- && agg.GetOwningAggregate().IsDelegate()
- ? GetErrorContext().Error(
- ErrorCode.ERR_BadNamedArgumentForDelegateInvoke, agg.GetOwningAggregate().name,
+ return _pGroup.OptionalObject?.Type is AggregateType agg && agg.OwningAggregate.IsDelegate()
+ ? ErrorHandling.Error(
+ ErrorCode.ERR_BadNamedArgumentForDelegateInvoke, agg.OwningAggregate.name,
_pInvalidSpecifiedName)
- : GetErrorContext().Error(ErrorCode.ERR_BadNamedArgument, _pGroup.Name, _pInvalidSpecifiedName);
+ : ErrorHandling.Error(ErrorCode.ERR_BadNamedArgument, _pGroup.Name, _pInvalidSpecifiedName);
}
if (_pNameUsedInPositionalArgument != null)
{
- return GetErrorContext().Error(ErrorCode.ERR_NamedArgumentUsedInPositional, _pNameUsedInPositionalArgument);
+ return ErrorHandling.Error(ErrorCode.ERR_NamedArgumentUsedInPositional, _pNameUsedInPositionalArgument);
}
// The number of arguments must be wrong.
if (_fCandidatesUnsupported)
{
- return GetErrorContext().Error(ErrorCode.ERR_BindToBogus, nameErr);
+ return ErrorHandling.Error(ErrorCode.ERR_BindToBogus, nameErr);
}
if (bUseDelegateErrors)
{
Debug.Assert(0 == (_pGroup.Flags & EXPRFLAG.EXF_CTOR));
- return GetErrorContext().Error(ErrorCode.ERR_BadDelArgCount, nameErr, _pArguments.carg);
+ return ErrorHandling.Error(ErrorCode.ERR_BadDelArgCount, nameErr, _pArguments.carg);
}
if (0 != (_pGroup.Flags & EXPRFLAG.EXF_CTOR))
{
Debug.Assert(!(_pGroup.ParentType is TypeParameterType));
- return GetErrorContext().Error(ErrorCode.ERR_BadCtorArgCount, _pGroup.ParentType, _pArguments.carg);
+ return ErrorHandling.Error(ErrorCode.ERR_BadCtorArgCount, _pGroup.ParentType, _pArguments.carg);
}
- return GetErrorContext().Error(ErrorCode.ERR_BadArgCount, nameErr, _pArguments.carg);
+ return ErrorHandling.Error(ErrorCode.ERR_BadArgCount, nameErr, _pArguments.carg);
}
private RuntimeBinderException ReportErrorsForBestMatching(bool bUseDelegateErrors)
@@ -1292,10 +1235,10 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (bUseDelegateErrors)
{
// Point to the Delegate, not the Invoke method
- return GetErrorContext().Error(ErrorCode.ERR_BadDelArgTypes, _results.BestResult.GetType());
+ return ErrorHandling.Error(ErrorCode.ERR_BadDelArgTypes, _results.BestResult.GetType());
}
- return GetErrorContext().Error(ErrorCode.ERR_BadArgTypes, _results.BestResult);
+ return ErrorHandling.Error(ErrorCode.ERR_BadArgTypes, _results.BestResult);
}
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/GroupToArgsBinderResult.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/GroupToArgsBinderResult.cs
index d6574fb85b..2e5b417e0d 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/GroupToArgsBinderResult.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/GroupToArgsBinderResult.cs
@@ -6,7 +6,7 @@ using System.Collections.Generic;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
- internal sealed partial class ExpressionBinder
+ internal readonly partial struct ExpressionBinder
{
// ----------------------------------------------------------------------------
// This class takes an EXPRMEMGRP and a set of arguments and binds the arguments
@@ -59,11 +59,11 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
if (pTypeArgs1[i] is AggregateType aggArg1)
{
- leftErrors += NumberOfErrorTypes(aggArg1.GetTypeArgsAll());
+ leftErrors += NumberOfErrorTypes(aggArg1.TypeArgsAll);
}
if (pTypeArgs2[i] is AggregateType aggArg2)
{
- rightErrors += NumberOfErrorTypes(aggArg2.GetTypeArgsAll());
+ rightErrors += NumberOfErrorTypes(aggArg2.TypeArgsAll);
}
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ImplicitConversion.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ImplicitConversion.cs
index 9d82a2f05f..17269e40d0 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ImplicitConversion.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ImplicitConversion.cs
@@ -7,7 +7,7 @@ using Microsoft.CSharp.RuntimeBinder.Syntax;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
- internal sealed partial class ExpressionBinder
+ internal readonly partial struct ExpressionBinder
{
// ----------------------------------------------------------------------------
// BindImplicitConversion
@@ -87,7 +87,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Debug.Assert(_exprSrc == null || _typeSrc == _exprSrc.Type); // type of source should be correct if source supplied
Debug.Assert(!_needsExprDest || _exprSrc != null); // need source expr to create dest expr
- switch (_typeDest.GetTypeKind())
+ switch (_typeDest.TypeKind)
{
case TypeKind.TK_NullType:
// Can only convert to the null type if src is null.
@@ -114,7 +114,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// such that an entity that already has a required type can be said to be convertible to that type.
if (_typeSrc == _typeDest &&
- ((_flags & CONVERTTYPE.ISEXPLICIT) == 0 || (!_typeSrc.isPredefType(PredefinedType.PT_FLOAT) && !_typeSrc.isPredefType(PredefinedType.PT_DOUBLE))))
+ ((_flags & CONVERTTYPE.ISEXPLICIT) == 0 || (!_typeSrc.IsPredefType(PredefinedType.PT_FLOAT) && !_typeSrc.IsPredefType(PredefinedType.PT_DOUBLE))))
{
if (_needsExprDest)
{
@@ -139,13 +139,13 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
// Get the fundamental types of destination.
- FUNDTYPE ftDest = _typeDest.fundType();
+ FUNDTYPE ftDest = _typeDest.FundamentalType;
Debug.Assert(ftDest != FUNDTYPE.FT_NONE || _typeDest is ParameterModifierType);
- switch (_typeSrc.GetTypeKind())
+ switch (_typeSrc.TypeKind)
{
default:
- Debug.Fail($"Bad type symbol kind: {_typeSrc.GetTypeKind()}");
+ Debug.Fail($"Bad type symbol kind: {_typeSrc.TypeKind}");
break;
case TypeKind.TK_VoidType:
case TypeKind.TK_ParameterModifierType:
@@ -191,7 +191,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
object srcRuntimeObject = _exprSrc?.RuntimeObject;
if (srcRuntimeObject != null
&& _typeDest.AssociatedSystemType.IsInstanceOfType(srcRuntimeObject)
- && _binder.GetSemanticChecker().CheckTypeAccess(_typeDest, _binder.Context.ContextForMemberLookup))
+ && CSemanticChecker.CheckTypeAccess(_typeDest, _binder.Context.ContextForMemberLookup))
{
if (_needsExprDest)
{
@@ -270,7 +270,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
AggregateType atsDst = nubDst.GetAts();
// Check for the unboxing conversion. This takes precedence over the wrapping conversions.
- if (GetSymbolLoader().HasBaseConversion(nubDst.GetUnderlyingType(), _typeSrc) && !CConversions.FWrappingConv(_typeSrc, nubDst))
+ if (SymbolLoader.HasBaseConversion(nubDst.UnderlyingType, _typeSrc) && !CConversions.FWrappingConv(_typeSrc, nubDst))
{
// These should be different! Fix the caller if typeSrc is an AggregateType of Nullable.
Debug.Assert(atsDst != _typeSrc);
@@ -310,8 +310,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (_needsExprDest)
{
_exprDest = _exprSrc is ExprConstant
- ? GetExprFactory().CreateZeroInit(nubDst)
- : GetExprFactory().CreateCast(_typeDest, _exprSrc);
+ ? ExprFactory.CreateZeroInit(nubDst)
+ : ExprFactory.CreateCast(_typeDest, _exprSrc);
}
return true;
}
@@ -331,7 +331,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (dstWasNullable)
{
- ExprCall call = _binder.BindNubNew(exprTmp);
+ ExprCall call = BindNubNew(exprTmp);
exprTmp = call;
call.NullableCallLiftKind = NullableCallLiftKind.NullableConversionConstructor;
}
@@ -363,8 +363,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (_needsExprDest)
{
MethWithInst mwi = new MethWithInst(null, null);
- ExprMemberGroup pMemGroup = GetExprFactory().CreateMemGroup(null, mwi);
- ExprCall exprDst = GetExprFactory().CreateCall(0, nubDst, _exprSrc, pMemGroup, null);
+ ExprMemberGroup pMemGroup = ExprFactory.CreateMemGroup(null, mwi);
+ ExprCall exprDst = ExprFactory.CreateCall(0, nubDst, _exprSrc, pMemGroup, null);
// Here we want to first check whether or not the conversions work on the base types.
@@ -395,10 +395,10 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// null type can be implicitly converted to any reference type or pointer type or type
// variable with reference-type constraint.
- FUNDTYPE ftDest = _typeDest.fundType();
+ FUNDTYPE ftDest = _typeDest.FundamentalType;
if (ftDest != FUNDTYPE.FT_REF && ftDest != FUNDTYPE.FT_PTR &&
// null is convertible to System.Nullable<T>.
- !_typeDest.isPredefType(PredefinedType.PT_G_OPTIONAL))
+ !_typeDest.IsPredefType(PredefinedType.PT_G_OPTIONAL))
{
return false;
}
@@ -408,8 +408,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// Otherwise, bind this as a cast to the destination type. In a later
// rewrite pass we will rewrite the cast as SEQ(side effects, ZEROINIT).
_exprDest = _exprSrc is ExprConstant
- ? GetExprFactory().CreateZeroInit(_typeDest)
- : GetExprFactory().CreateCast(_typeDest, _exprSrc);
+ ? ExprFactory.CreateZeroInit(_typeDest)
+ : ExprFactory.CreateCast(_typeDest, _exprSrc);
}
return true;
}
@@ -440,12 +440,12 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
return true;
}
- if (GetSymbolLoader().HasBaseConversion(nubSrc.GetUnderlyingType(), _typeDest) && !CConversions.FUnwrappingConv(nubSrc, _typeDest))
+ if (SymbolLoader.HasBaseConversion(nubSrc.UnderlyingType, _typeDest) && !CConversions.FUnwrappingConv(nubSrc, _typeDest))
{
if (_needsExprDest)
{
_binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, EXPRFLAG.EXF_BOX);
- if (!_typeDest.isPredefType(PredefinedType.PT_OBJECT))
+ if (!_typeDest.IsPredefType(PredefinedType.PT_OBJECT))
{
// The base type of a nullable is always a non-nullable value type,
// therefore so is typeDest unless typeDest is PT_OBJECT. In this case the conversion
@@ -475,7 +475,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// * From any array-type to System.Array.
// * From any array-type to any interface implemented by System.Array.
- if (!GetSymbolLoader().HasBaseConversion(_typeSrc, _typeDest))
+ if (!SymbolLoader.HasBaseConversion(_typeSrc, _typeDest))
{
return false;
}
@@ -486,9 +486,9 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// and the non-generic versions.
if ((_typeDest is ArrayType ||
- (_typeDest is AggregateType aggDest && aggDest.isInterfaceType() &&
- aggDest.GetTypeArgsAll().Count == 1 &&
- ((aggDest.GetTypeArgsAll()[0] != ((ArrayType)_typeSrc).GetElementType()) ||
+ (_typeDest is AggregateType aggDest && aggDest.IsInterfaceType &&
+ aggDest.TypeArgsAll.Count == 1 &&
+ (aggDest.TypeArgsAll[0] != ((ArrayType)_typeSrc).ElementType ||
0 != (_flags & CONVERTTYPE.FORCECAST))))
&&
(0 != (_flags & CONVERTTYPE.FORCECAST) ||
@@ -513,12 +513,16 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
//
// * From any pointer-type to the type void*.
- if (_typeDest is PointerType ptDest && ptDest.GetReferentType() == _binder.getVoidType())
+ if (_typeDest is PointerType ptDest && ptDest.ReferentType == VoidType.Instance)
{
if (_needsExprDest)
+ {
_binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest);
+ }
+
return true;
}
+
return false;
}
@@ -529,13 +533,13 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// below. They could be relevant if we had user-defined conversions on
// generic types.
- AggregateSymbol aggSrc = aggTypeSrc.getAggregate();
+ AggregateSymbol aggSrc = aggTypeSrc.OwningAggregate;
if (aggSrc.IsEnum())
{
return bindImplicitConversionFromEnum(aggTypeSrc);
}
- if (_typeDest.isEnumType())
+ if (_typeDest.IsEnumType)
{
if (bindImplicitConversionToEnum(aggTypeSrc))
{
@@ -544,7 +548,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// Even though enum is sealed, a class can derive from enum in LAF scenarios --
// continue testing for derived to base conversions below.
}
- else if (aggSrc.getThisType().isSimpleType() && _typeDest.isSimpleType())
+ else if (aggSrc.getThisType().IsSimpleType && _typeDest.IsSimpleType)
{
if (bindImplicitConversionBetweenSimpleTypes(aggTypeSrc))
{
@@ -567,12 +571,12 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// * From any delegate-type to System.Delegate.
// * From any delegate-type to System.ICloneable.
- if (!(_typeDest is AggregateType) || !GetSymbolLoader().HasBaseConversion(pSource, _typeDest))
+ if (!(_typeDest is AggregateType) || !SymbolLoader.HasBaseConversion(pSource, _typeDest))
{
return false;
}
EXPRFLAG flags = 0x00;
- if (pSource.getAggregate().IsStruct() && _typeDest.fundType() == FUNDTYPE.FT_REF)
+ if (pSource.OwningAggregate.IsStruct() && _typeDest.FundamentalType == FUNDTYPE.FT_REF)
{
flags = EXPRFLAG.EXF_BOX | EXPRFLAG.EXF_CANTBENULL;
}
@@ -597,7 +601,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// base class for all enums (21.4). A struct or enum can be boxed to the type System.ValueType,
// since that is the direct base class for all structs (18.3.2) and a base class for all enums.
- if (_typeDest is AggregateType aggDest && GetSymbolLoader().HasBaseConversion(aggTypeSrc, aggDest))
+ if (_typeDest is AggregateType aggDest && SymbolLoader.HasBaseConversion(aggTypeSrc, aggDest))
{
if (_needsExprDest)
_binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest, EXPRFLAG.EXF_BOX | EXPRFLAG.EXF_CANTBENULL);
@@ -630,10 +634,10 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// Note: Don't use GetConst here since the conversion only applies to bona-fide compile time constants.
if (
- aggTypeSrc.getAggregate().GetPredefType() != PredefinedType.PT_BOOL &&
+ aggTypeSrc.OwningAggregate.GetPredefType() != PredefinedType.PT_BOOL &&
_exprSrc != null &&
_exprSrc.IsZero() &&
- _exprSrc.Type.isNumericType() &&
+ _exprSrc.Type.IsNumericType &&
/*(exprSrc.flags & EXF_LITERALCONST) &&*/
0 == (_flags & CONVERTTYPE.STANDARD))
{
@@ -644,7 +648,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// into a constant here - we should move this to a later pass.
if (_needsExprDest)
{
- _exprDest = GetExprFactory().CreateConstant(_typeDest, ConstVal.GetDefaultValue(_typeDest.constValKind()));
+ _exprDest = ExprFactory.CreateConstant(_typeDest, ConstVal.GetDefaultValue(_typeDest.ConstValKind));
}
return true;
}
@@ -653,13 +657,13 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
private bool bindImplicitConversionBetweenSimpleTypes(AggregateType aggTypeSrc)
{
- AggregateSymbol aggSrc = aggTypeSrc.getAggregate();
- Debug.Assert(aggSrc.getThisType().isSimpleType());
- Debug.Assert(_typeDest.isSimpleType());
+ AggregateSymbol aggSrc = aggTypeSrc.OwningAggregate;
+ Debug.Assert(aggSrc.getThisType().IsSimpleType);
+ Debug.Assert(_typeDest.IsSimpleType);
- Debug.Assert(aggSrc.IsPredefined() && _typeDest.isPredefined());
+ Debug.Assert(aggSrc.IsPredefined() && _typeDest.IsPredefined);
PredefinedType ptSrc = aggSrc.GetPredefType();
- PredefinedType ptDest = _typeDest.getPredefType();
+ PredefinedType ptDest = _typeDest.PredefinedType;
ConvKind convertKind;
Debug.Assert((int)ptSrc < NUM_SIMPLE_TYPES && (int)ptDest < NUM_SIMPLE_TYPES);
@@ -726,15 +730,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
_binder.bindSimpleCast(_exprSrc, _typeDest, out _exprDest);
return true;
}
-
- private SymbolLoader GetSymbolLoader()
- {
- return _binder.GetSymbolLoader();
- }
- private ExprFactory GetExprFactory()
- {
- return _binder.GetExprFactory();
- }
}
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/MemberLookup.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/MemberLookup.cs
index 748580e702..53a477a182 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/MemberLookup.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/MemberLookup.cs
@@ -38,10 +38,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
internal sealed class MemberLookup
{
// The inputs to Lookup.
- private CSemanticChecker _pSemanticChecker;
- private SymbolLoader _pSymbolLoader;
private CType _typeSrc;
- private Expr _obj;
private CType _typeQual;
private ParentSymbol _symWhere;
private Name _name;
@@ -107,50 +104,30 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// Make sure this type is accessible. It may not be due to private inheritance
// or friend assemblies.
- bool fInaccess = !GetSemanticChecker().CheckTypeAccess(typeCur, _symWhere);
+ bool fInaccess = !CSemanticChecker.CheckTypeAccess(typeCur, _symWhere);
if (fInaccess && (_csym != 0 || _swtInaccess != null))
return false;
// Loop through symbols.
Symbol symCur;
- for (symCur = GetSymbolLoader().LookupAggMember(_name, typeCur.getAggregate(), symbmask_t.MASK_ALL);
+ for (symCur = SymbolLoader.LookupAggMember(_name, typeCur.OwningAggregate, symbmask_t.MASK_Member);
symCur != null;
- symCur = SymbolLoader.LookupNextSym(symCur, typeCur.getAggregate(), symbmask_t.MASK_ALL))
+ symCur = symCur.LookupNext(symbmask_t.MASK_Member))
{
+ Debug.Assert(!(symCur is AggregateSymbol));
// Check for arity.
- switch (symCur.getKind())
+ // For non-zero arity, only methods of the correct arity are considered.
+ // For zero arity, don't filter out any methods since we do type argument
+ // inferencing.
+ // All others are only considered when arity is zero.
+ if (_arity > 0 && (!(symCur is MethodSymbol curMeth) || curMeth.typeVars.Count != _arity))
{
- case SYMKIND.SK_MethodSymbol:
- // For non-zero arity, only methods of the correct arity are considered.
- // For zero arity, don't filter out any methods since we do type argument
- // inferencing.
- if (_arity > 0 && ((MethodSymbol)symCur).typeVars.Count != _arity)
- {
- if (!_swtBadArity)
- _swtBadArity.Set(symCur, typeCur);
- continue;
- }
- break;
-
- case SYMKIND.SK_AggregateSymbol:
- // For types, always filter on arity.
- if (((AggregateSymbol)symCur).GetTypeVars().Count != _arity)
- {
- if (!_swtBadArity)
- _swtBadArity.Set(symCur, typeCur);
- continue;
- }
- break;
+ if (!_swtBadArity)
+ {
+ _swtBadArity.Set(symCur, typeCur);
+ }
- default:
- // All others are only considered when arity is zero.
- if (_arity > 0)
- {
- if (!_swtBadArity)
- _swtBadArity.Set(symCur, typeCur);
- continue;
- }
- break;
+ continue;
}
// Check for user callability.
@@ -164,20 +141,22 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (methProp != null && (_flags & MemLookFlags.UserCallable) != 0 && !methProp.isUserCallable())
{
// If its an indexed property method symbol, let it through.
- if (meth != null &&
- meth.isPropertyAccessor() &&
- ((symCur.name.Text.StartsWith("set_", StringComparison.Ordinal) && meth.Params.Count > 1) ||
- (symCur.name.Text.StartsWith("get_", StringComparison.Ordinal) && meth.Params.Count > 0)))
+ // This is too liberal, but maintained for compatibility.
+ if (meth == null ||
+ !meth.isPropertyAccessor() ||
+ (!symCur.name.Text.StartsWith("set_", StringComparison.Ordinal) || meth.Params.Count <= 1) &&
+ (!symCur.name.Text.StartsWith("get_", StringComparison.Ordinal) || meth.Params.Count <= 0))
{
if (!_swtInaccess)
{
_swtInaccess.Set(symCur, typeCur);
}
+
continue;
}
}
- if (fInaccess || !GetSemanticChecker().CheckAccess(symCur, typeCur, _symWhere, _typeQual))
+ if (fInaccess || !CSemanticChecker.CheckAccess(symCur, typeCur, _symWhere, _typeQual))
{
// Not accessible so get the next sym.
if (!_swtInaccess)
@@ -243,7 +222,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (_swtFirst)
{
- if (!typeCur.isInterfaceType())
+ if (!typeCur.IsInterfaceType)
{
// Non-interface case.
Debug.Assert(_fMulti || typeCur == _prgtype[0]);
@@ -297,7 +276,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
else if (_swtFirst.Sym.getKind() != symCur.getKind())
{
- if (!typeCur.fDiffHidden)
+ if (!typeCur.DiffHidden)
{
// Give method groups priority.
if (!(_swtFirst.Sym is MethodSymbol))
@@ -329,12 +308,12 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return true;
}
- private bool IsDynamicMember(Symbol sym)
+ private static bool IsDynamicMember(Symbol sym)
{
System.Runtime.CompilerServices.DynamicAttribute da = null;
if (sym is FieldSymbol field)
{
- if (!field.getType().isPredefType(PredefinedType.PT_OBJECT))
+ if (!field.getType().IsPredefType(PredefinedType.PT_OBJECT))
{
return false;
}
@@ -348,7 +327,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
Debug.Assert(sym is PropertySymbol);
PropertySymbol prop = (PropertySymbol)sym;
- if (!prop.getType().isPredefType(PredefinedType.PT_OBJECT))
+ if (!prop.getType().IsPredefType(PredefinedType.PT_OBJECT))
{
return false;
}
@@ -378,15 +357,15 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
private bool LookupInClass(AggregateType typeStart, ref AggregateType ptypeEnd)
{
Debug.Assert(!_swtFirst || _fMulti);
- Debug.Assert(typeStart != null && !typeStart.isInterfaceType() && (ptypeEnd == null || typeStart != ptypeEnd));
+ Debug.Assert(typeStart != null && !typeStart.IsInterfaceType && (ptypeEnd == null || typeStart != ptypeEnd));
AggregateType typeEnd = ptypeEnd;
AggregateType typeCur;
// Loop through types. Loop until we hit typeEnd (object or null).
- for (typeCur = typeStart; typeCur != typeEnd && typeCur != null; typeCur = typeCur.GetBaseClass())
+ for (typeCur = typeStart; typeCur != typeEnd && typeCur != null; typeCur = typeCur.BaseClass)
{
- Debug.Assert(!typeCur.isInterfaceType());
+ Debug.Assert(!typeCur.IsInterfaceType);
SearchSingleType(typeCur, out bool fHideByName);
@@ -422,23 +401,23 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
private bool LookupInInterfaces(AggregateType typeStart, TypeArray types)
{
Debug.Assert(!_swtFirst || _fMulti);
- Debug.Assert(typeStart == null || typeStart.isInterfaceType());
+ Debug.Assert(typeStart == null || typeStart.IsInterfaceType);
Debug.Assert(typeStart != null || types.Count != 0);
// Clear all the hidden flags. Anything found in a class hides any other
// kind of member in all the interfaces.
if (typeStart != null)
{
- typeStart.fAllHidden = false;
- typeStart.fDiffHidden = (_swtFirst != null);
+ typeStart.AllHidden = false;
+ typeStart.DiffHidden = (_swtFirst != null);
}
for (int i = 0; i < types.Count; i++)
{
AggregateType type = (AggregateType)types[i];
- Debug.Assert(type.isInterfaceType());
- type.fAllHidden = false;
- type.fDiffHidden = !!_swtFirst;
+ Debug.Assert(type.IsInterfaceType);
+ type.AllHidden = false;
+ type.DiffHidden = !!_swtFirst;
}
bool fHideObject = false;
@@ -454,60 +433,58 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// Loop through the interfaces.
for (; ;)
{
- Debug.Assert(typeCur != null && typeCur.isInterfaceType());
+ Debug.Assert(typeCur != null && typeCur.IsInterfaceType);
- if (!typeCur.fAllHidden && SearchSingleType(typeCur, out bool fHideByName))
+ if (!typeCur.AllHidden && SearchSingleType(typeCur, out bool fHideByName))
{
fHideByName |= !_fMulti;
// Mark base interfaces appropriately.
- TypeArray ifaces = typeCur.GetIfacesAll();
- for (int i = 0; i < ifaces.Count; i++)
+ foreach (AggregateType type in typeCur.IfacesAll.Items)
{
- AggregateType type = (AggregateType)ifaces[i];
- Debug.Assert(type.isInterfaceType());
+ Debug.Assert(type.IsInterfaceType);
if (fHideByName)
- type.fAllHidden = true;
- type.fDiffHidden = true;
+ {
+ type.AllHidden = true;
+ }
+
+ type.DiffHidden = true;
}
// If we hide all base types, that includes object!
if (fHideByName)
+ {
fHideObject = true;
+ }
}
if (itypeNext >= types.Count)
+ {
return !fHideObject;
+ }
// Substitution has already been done.
typeCur = types[itypeNext++] as AggregateType;
}
}
- private SymbolLoader GetSymbolLoader() { return _pSymbolLoader; }
- private CSemanticChecker GetSemanticChecker() { return _pSemanticChecker; }
- private ErrorHandling GetErrorContext() { return GetSymbolLoader().GetErrorContext(); }
-
- private RuntimeBinderException ReportBogus(SymWithType swt)
+ private static RuntimeBinderException ReportBogus(SymWithType swt)
{
Debug.Assert(CSemanticChecker.CheckBogus(swt.Sym));
MethodSymbol meth1 = swt.Prop().GetterMethod;
MethodSymbol meth2 = swt.Prop().SetterMethod;
Debug.Assert((meth1 ?? meth2) != null);
return meth1 == null | meth2 == null
- ? GetErrorContext().Error(
+ ? ErrorHandling.Error(
ErrorCode.ERR_BindToBogusProp1, swt.Sym.name, new SymWithType(meth1 ?? meth2, swt.GetType()),
new ErrArgRefOnly(swt.Sym))
- : GetErrorContext().Error(
+ : ErrorHandling.Error(
ErrorCode.ERR_BindToBogusProp2, swt.Sym.name, new SymWithType(meth1, swt.GetType()),
new SymWithType(meth2, swt.GetType()), new ErrArgRefOnly(swt.Sym));
}
- private bool IsDelegateType(CType pSrcType, AggregateType pAggType)
- {
- CType pInstantiatedType = GetSymbolLoader().GetTypeManager().SubstType(pSrcType, pAggType, pAggType.GetTypeArgsAll());
- return pInstantiatedType.isDelegateType();
- }
+ private static bool IsDelegateType(CType pSrcType, AggregateType pAggType) =>
+ TypeManager.SubstType(pSrcType, pAggType, pAggType.TypeArgsAll).IsDelegateType;
/////////////////////////////////////////////////////////////////////////////////
// Public methods.
@@ -541,20 +518,16 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
flags - See MemLookFlags.
TypeVarsAllowed only applies to the most derived type (not base types).
***************************************************************************************************/
- public bool Lookup(CSemanticChecker checker, CType typeSrc, Expr obj, ParentSymbol symWhere, Name name, int arity, MemLookFlags flags)
+ public bool Lookup(CType typeSrc, Expr obj, ParentSymbol symWhere, Name name, int arity, MemLookFlags flags)
{
Debug.Assert((flags & ~MemLookFlags.All) == 0);
Debug.Assert(obj == null || obj.Type != null);
Debug.Assert(typeSrc is AggregateType);
- Debug.Assert(checker != null);
_prgtype = _rgtypeStart;
// Save the inputs for error handling, etc.
- _pSemanticChecker = checker;
- _pSymbolLoader = checker.SymbolLoader;
_typeSrc = typeSrc;
- _obj = obj is ExprClass ? null : obj;
_symWhere = symWhere;
_name = name;
_arity = arity;
@@ -563,30 +536,27 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
_typeQual = (_flags & MemLookFlags.Ctor) != 0 ? _typeSrc : obj?.Type;
// Determine what to search.
- AggregateType typeCls1 = null;
- AggregateType typeIface = null;
- TypeArray ifaces = BSYMMGR.EmptyTypeArray();
- AggregateType typeCls2 = null;
+ AggregateType typeCls1;
+ AggregateType typeIface;
+ TypeArray ifaces;
- if (!typeSrc.isInterfaceType())
+ if (typeSrc.IsInterfaceType)
{
- typeCls1 = (AggregateType)typeSrc;
-
- if (typeCls1.IsWindowsRuntimeType())
- {
- ifaces = typeCls1.GetWinRTCollectionIfacesAll(GetSymbolLoader());
- }
+ Debug.Assert((_flags & (MemLookFlags.Ctor | MemLookFlags.NewObj | MemLookFlags.Operator | MemLookFlags.BaseCall)) == 0);
+ typeCls1 = null;
+ typeIface = (AggregateType)typeSrc;
+ ifaces = typeIface.IfacesAll;
}
else
{
- Debug.Assert(typeSrc.isInterfaceType());
- Debug.Assert((_flags & (MemLookFlags.Ctor | MemLookFlags.NewObj | MemLookFlags.Operator | MemLookFlags.BaseCall)) == 0);
- typeIface = (AggregateType)typeSrc;
- ifaces = typeIface.GetIfacesAll();
+ typeCls1 = (AggregateType)typeSrc;
+ typeIface = null;
+ ifaces = typeCls1.IsWindowsRuntimeType ? typeCls1.WinRTCollectionIfacesAll : TypeArray.Empty;
}
- if (typeIface != null || ifaces.Count > 0)
- typeCls2 = GetSymbolLoader().GetPredefindType(PredefinedType.PT_OBJECT);
+ AggregateType typeCls2 = typeIface != null || ifaces.Count > 0
+ ? SymbolLoader.GetPredefindType(PredefinedType.PT_OBJECT)
+ : null;
// Search the class first (except possibly object).
if (typeCls1 == null || LookupInClass(typeCls1, ref typeCls2))
@@ -595,7 +565,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if ((typeIface != null || ifaces.Count > 0) && LookupInInterfaces(typeIface, ifaces) && typeCls2 != null)
{
// Search object last.
- Debug.Assert(typeCls2 != null && typeCls2.isPredefType(PredefinedType.PT_OBJECT));
+ Debug.Assert(typeCls2 != null && typeCls2.IsPredefType(PredefinedType.PT_OBJECT));
AggregateType result = null;
LookupInClass(typeCls2, ref result);
@@ -612,36 +582,11 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
// The first symbol found.
- public Symbol SymFirst()
- {
- return _swtFirst.Sym;
- }
public SymWithType SwtFirst()
{
return _swtFirst;
}
- public Expr GetObject()
- {
- return _obj;
- }
-
- public CType GetSourceType()
- {
- return _typeSrc;
- }
-
- public MemLookFlags GetFlags()
- {
- return _flags;
- }
-
- // Put all the types in a type array.
- private TypeArray GetAllTypes()
- {
- return GetSymbolLoader().getBSymmgr().AllocParams(_prgtype.Count, _prgtype.ToArray());
- }
-
/******************************************************************************
Reports errors. Only call this if FError() is true.
******************************************************************************/
@@ -656,36 +601,37 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (_swtFirst)
{
// Ambiguous lookup.
- return GetErrorContext().Error(ErrorCode.ERR_AmbigMember, _swtFirst, _swtAmbig);
+ return ErrorHandling.Error(ErrorCode.ERR_AmbigMember, _swtFirst, _swtAmbig);
}
if (_swtInaccess)
{
return !_swtInaccess.Sym.isUserCallable() && ((_flags & MemLookFlags.UserCallable) != 0)
- ? GetErrorContext().Error(ErrorCode.ERR_CantCallSpecialMethod, _swtInaccess)
- : GetSemanticChecker().ReportAccessError(_swtInaccess, _symWhere, _typeQual);
+ ? ErrorHandling.Error(ErrorCode.ERR_CantCallSpecialMethod, _swtInaccess)
+ : CSemanticChecker.ReportAccessError(_swtInaccess, _symWhere, _typeQual);
}
if ((_flags & MemLookFlags.Ctor) != 0)
{
+ Debug.Assert(_typeSrc is AggregateType);
return _arity > 0
- ? GetErrorContext().Error(ErrorCode.ERR_BadCtorArgCount, _typeSrc.getAggregate(), _arity)
- : GetErrorContext().Error(ErrorCode.ERR_NoConstructors, _typeSrc.getAggregate());
+ ? ErrorHandling.Error(ErrorCode.ERR_BadCtorArgCount, ((AggregateType)_typeSrc).OwningAggregate, _arity)
+ : ErrorHandling.Error(ErrorCode.ERR_NoConstructors, ((AggregateType)_typeSrc).OwningAggregate);
}
if ((_flags & MemLookFlags.Operator) != 0)
{
- return GetErrorContext().Error(ErrorCode.ERR_NoSuchMember, _typeSrc, _name);
+ return ErrorHandling.Error(ErrorCode.ERR_NoSuchMember, _typeSrc, _name);
}
if ((_flags & MemLookFlags.Indexer) != 0)
{
- return GetErrorContext().Error(ErrorCode.ERR_BadIndexLHS, _typeSrc);
+ return ErrorHandling.Error(ErrorCode.ERR_BadIndexLHS, _typeSrc);
}
if (_swtBad)
{
- return GetErrorContext().Error((_flags & MemLookFlags.MustBeInvocable) != 0 ? ErrorCode.ERR_NonInvocableMemberCalled : ErrorCode.ERR_CantCallSpecialMethod, _swtBad);
+ return ErrorHandling.Error((_flags & MemLookFlags.MustBeInvocable) != 0 ? ErrorCode.ERR_NonInvocableMemberCalled : ErrorCode.ERR_CantCallSpecialMethod, _swtBad);
}
if (_swtBogus)
@@ -695,26 +641,18 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (_swtBadArity)
{
- int cvar;
-
- switch (_swtBadArity.Sym.getKind())
+ Debug.Assert(_arity != 0);
+ Debug.Assert(!(_swtBadArity.Sym is AggregateSymbol));
+ if (_swtBadArity.Sym is MethodSymbol badMeth)
{
- case SYMKIND.SK_MethodSymbol:
- Debug.Assert(_arity != 0);
- cvar = ((MethodSymbol)_swtBadArity.Sym).typeVars.Count;
- return GetErrorContext().Error(cvar > 0 ? ErrorCode.ERR_BadArity : ErrorCode.ERR_HasNoTypeVars, _swtBadArity, new ErrArgSymKind(_swtBadArity.Sym), cvar);
-
- case SYMKIND.SK_AggregateSymbol:
- cvar = ((AggregateSymbol)_swtBadArity.Sym).GetTypeVars().Count;
- return GetErrorContext().Error(cvar > 0 ? ErrorCode.ERR_BadArity : ErrorCode.ERR_HasNoTypeVars, _swtBadArity, new ErrArgSymKind(_swtBadArity.Sym), cvar);
-
- default:
- Debug.Assert(_arity != 0);
- return GetErrorContext().Error(ErrorCode.ERR_TypeArgsNotAllowed, _swtBadArity, new ErrArgSymKind(_swtBadArity.Sym));
+ int cvar = badMeth.typeVars.Count;
+ return ErrorHandling.Error(cvar > 0 ? ErrorCode.ERR_BadArity : ErrorCode.ERR_HasNoTypeVars, _swtBadArity, new ErrArgSymKind(_swtBadArity.Sym), cvar);
}
+
+ return ErrorHandling.Error(ErrorCode.ERR_TypeArgsNotAllowed, _swtBadArity, new ErrArgSymKind(_swtBadArity.Sym));
}
- return GetErrorContext().Error(ErrorCode.ERR_NoSuchMember, _typeSrc, _name);
+ return ErrorHandling.Error(ErrorCode.ERR_NoSuchMember, _typeSrc, _name);
}
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/MemberLookupResults.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/MemberLookupResults.cs
index 045a6cd9e8..7c21f1487d 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/MemberLookupResults.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/MemberLookupResults.cs
@@ -29,15 +29,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
public CMethodIterator GetMethodIterator(
- CSemanticChecker pChecker, SymbolLoader pSymLoader, CType pQualifyingType, AggregateDeclaration pContext, int arity, EXPRFLAG flags, symbmask_t mask, ArgInfos nonTrailingNamedArguments)
- {
- Debug.Assert(pSymLoader != null);
- CMethodIterator iterator = new CMethodIterator(pChecker, pSymLoader, _pName, ContainingTypes, pQualifyingType, pContext, arity, flags, mask, nonTrailingNamedArguments);
- return iterator;
- }
-
- public partial class CMethodIterator
- {
- }
+ CType qualifyingType, AggregateSymbol context, int arity, EXPRFLAG flags, symbmask_t mask, ArgInfos nonTrailingNamedArguments) =>
+ new CMethodIterator(_pName, ContainingTypes, qualifyingType, context, arity, flags, mask, nonTrailingNamedArguments);
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/MethodIterator.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/MethodIterator.cs
index 4e86ea7448..be5d2a5599 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/MethodIterator.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/MethodIterator.cs
@@ -10,12 +10,10 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
internal partial class CMemberLookupResults
{
- public partial class CMethodIterator
+ public class CMethodIterator
{
- private readonly SymbolLoader _symbolLoader;
- private readonly CSemanticChecker _semanticChecker;
// Inputs.
- private readonly AggregateDeclaration _context;
+ private readonly AggregateSymbol _context;
private readonly TypeArray _containingTypes;
private readonly CType _qualifyingType;
private readonly Name _name;
@@ -26,15 +24,12 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// Internal state.
private int _currentTypeIndex;
- public CMethodIterator(CSemanticChecker checker, SymbolLoader symLoader, Name name, TypeArray containingTypes, CType qualifyingType, AggregateDeclaration context, int arity, EXPRFLAG flags, symbmask_t mask, ArgInfos nonTrailingNamedArguments)
+ public CMethodIterator(Name name, TypeArray containingTypes, CType qualifyingType, AggregateSymbol context, int arity, EXPRFLAG flags, symbmask_t mask, ArgInfos nonTrailingNamedArguments)
{
Debug.Assert(name != null);
- Debug.Assert(symLoader != null);
- Debug.Assert(checker != null);
Debug.Assert(containingTypes != null);
Debug.Assert(containingTypes.Count != 0);
- _semanticChecker = checker;
- _symbolLoader = symLoader;
+
_name = name;
_containingTypes = containingTypes;
_qualifyingType = qualifyingType;
@@ -87,7 +82,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
// Check access. If Sym is not accessible, then let it through and mark it.
- IsCurrentSymbolInaccessible = !_semanticChecker.CheckAccess(CurrentSymbol, CurrentType, _context, _qualifyingType);
+ IsCurrentSymbolInaccessible = !CSemanticChecker.CheckAccess(CurrentSymbol, CurrentType, _context, _qualifyingType);
// Check bogus. If Sym is bogus, then let it through and mark it.
IsCurrentSymbolBogus = CSemanticChecker.CheckBogus(CurrentSymbol);
@@ -104,7 +99,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (args != null)
{
List<Name> paramNames = ExpressionBinder.GroupToArgsBinder
- .FindMostDerivedMethod(_symbolLoader, CurrentSymbol, _qualifyingType)
+ .FindMostDerivedMethod(CurrentSymbol, _qualifyingType)
.ParameterNames;
List<Expr> argExpressions = args.prgexpr;
@@ -129,8 +124,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
for (;;)
{
CurrentSymbol = (CurrentSymbol == null
- ? _symbolLoader.LookupAggMember(_name, CurrentType.getAggregate(), _mask)
- : SymbolLoader.LookupNextSym(CurrentSymbol, CurrentType.getAggregate(), _mask)) as MethodOrPropertySymbol;
+ ? SymbolLoader.LookupAggMember(_name, CurrentType.OwningAggregate, _mask)
+ : CurrentSymbol.LookupNext(_mask)) as MethodOrPropertySymbol;
// If we couldn't find a sym, we look up the type chain and get the next type.
if (CurrentSymbol == null)
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/MethodTypeInferrer.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/MethodTypeInferrer.cs
index 5e70a5c7f6..01353f5a63 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/MethodTypeInferrer.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/MethodTypeInferrer.cs
@@ -27,7 +27,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
DependsMask = 0x10,
Indirect = 0x12
}
- private readonly SymbolLoader _symbolLoader;
+
private readonly ExpressionBinder _binder;
private readonly TypeArray _pMethodTypeParameters;
private readonly TypeArray _pMethodFormalParameterTypes;
@@ -81,7 +81,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
public static bool Infer(
ExpressionBinder binder,
- SymbolLoader symbolLoader,
MethodSymbol pMethod,
TypeArray pMethodFormalParameterTypes,
ArgInfos pMethodArguments,
@@ -99,9 +98,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Debug.Assert(pMethodFormalParameterTypes != null);
Debug.Assert(pMethodArguments.carg <= pMethodFormalParameterTypes.Count);
- var inferrer = new MethodTypeInferrer(binder, symbolLoader,
- pMethodFormalParameterTypes, pMethodArguments,
- pMethod.typeVars);
+ var inferrer = new MethodTypeInferrer(
+ binder, pMethodFormalParameterTypes, pMethodArguments, pMethod.typeVars);
bool success = inferrer.InferTypeArgs();
ppInferredTypeArguments = inferrer.GetResults();
@@ -118,12 +116,9 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// SPEC: with an empty set of bounds.
private MethodTypeInferrer(
- ExpressionBinder exprBinder, SymbolLoader symLoader,
- TypeArray pMethodFormalParameterTypes, ArgInfos pMethodArguments,
- TypeArray pMethodTypeParameters)
+ ExpressionBinder exprBinder, TypeArray pMethodFormalParameterTypes, ArgInfos pMethodArguments, TypeArray pMethodTypeParameters)
{
_binder = exprBinder;
- _symbolLoader = symLoader;
_pMethodFormalParameterTypes = pMethodFormalParameterTypes;
_pMethodArguments = pMethodArguments;
_pMethodTypeParameters = pMethodTypeParameters;
@@ -142,7 +137,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
////////////////////////////////////////////////////////////////////////////////
- private TypeArray GetResults() => GetGlobalSymbols().AllocParams(_pFixedResults);
+ private TypeArray GetResults() => TypeArray.Allocate(_pFixedResults);
////////////////////////////////////////////////////////////////////////////////
@@ -158,8 +153,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
private bool IsUnfixed(TypeParameterType pParam)
{
Debug.Assert(pParam != null);
- Debug.Assert(pParam.IsMethodTypeParameter());
- int iParam = pParam.GetIndexInTotalParameters();
+ Debug.Assert(pParam.IsMethodTypeParameter);
+ int iParam = pParam.IndexInTotalParameters;
Debug.Assert(_pMethodTypeParameters[iParam] == pParam);
return IsUnfixed(iParam);
}
@@ -183,7 +178,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
private void AddLowerBound(TypeParameterType pParam, CType pBound)
{
Debug.Assert(IsUnfixed(pParam));
- int iParam = pParam.GetIndexInTotalParameters();
+ int iParam = pParam.IndexInTotalParameters;
if (!_pLowerBounds[iParam].Contains(pBound))
{
_pLowerBounds[iParam].Add(pBound);
@@ -195,7 +190,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
private void AddUpperBound(TypeParameterType pParam, CType pBound)
{
Debug.Assert(IsUnfixed(pParam));
- int iParam = pParam.GetIndexInTotalParameters();
+ int iParam = pParam.IndexInTotalParameters;
if (!_pUpperBounds[iParam].Contains(pBound))
{
_pUpperBounds[iParam].Add(pBound);
@@ -207,7 +202,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
private void AddExactBound(TypeParameterType pParam, CType pBound)
{
Debug.Assert(IsUnfixed(pParam));
- int iParam = pParam.GetIndexInTotalParameters();
+ int iParam = pParam.IndexInTotalParameters;
if (!_pExactBounds[iParam].Contains(pBound))
{
_pExactBounds[iParam].Add(pBound);
@@ -296,13 +291,15 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
bool wasOutOrRef = false;
if (pDest is ParameterModifierType modDest)
{
- pDest = modDest.GetParameterType();
+ pDest = modDest.ParameterType;
wasOutOrRef = true;
}
+
if (pSource is ParameterModifierType modSource)
{
- pSource = modSource.GetParameterType();
+ pSource = modSource.ParameterType;
}
+
// If the argument is a TYPEORNAMESPACEERROR and the pSource is an
// error CType, then we want to set it to the generic error CType
// that has no name text. This is because of the following scenario:
@@ -796,7 +793,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// SPEC: for Xi.
if (pDest is TypeParameterType pTPType)
{
- if (pTPType.IsMethodTypeParameter() && IsUnfixed(pTPType))
+ if (pTPType.IsMethodTypeParameter && IsUnfixed(pTPType))
{
AddExactBound(pTPType, pSource);
return true;
@@ -816,12 +813,12 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return false;
}
- if (pArraySource.rank != pArrayDest.rank || pArraySource.IsSZArray != pArrayDest.IsSZArray)
+ if (pArraySource.Rank != pArrayDest.Rank || pArraySource.IsSZArray != pArrayDest.IsSZArray)
{
return false;
}
- ExactInference(pArraySource.GetElementType(), pArrayDest.GetElementType());
+ ExactInference(pArraySource.ElementType, pArrayDest.ElementType);
return true;
}
@@ -836,7 +833,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return false;
}
- ExactInference(nubSource.GetUnderlyingType(), nubDest.GetUnderlyingType());
+ ExactInference(nubSource.UnderlyingType, nubDest.UnderlyingType);
return true;
}
@@ -849,7 +846,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// SPEC: is made from each Ui to the corresponding Vi.
if (!(pSource is AggregateType pConstructedSource) || !(pDest is AggregateType pConstructedDest)
- || pConstructedSource.GetOwningAggregate() != pConstructedDest.GetOwningAggregate())
+ || pConstructedSource.OwningAggregate != pConstructedDest.OwningAggregate)
{
return false;
}
@@ -866,10 +863,10 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
Debug.Assert(pSource != null);
Debug.Assert(pDest != null);
- Debug.Assert(pSource.GetOwningAggregate() == pDest.GetOwningAggregate());
+ Debug.Assert(pSource.OwningAggregate == pDest.OwningAggregate);
- TypeArray pSourceArgs = pSource.GetTypeArgsAll();
- TypeArray pDestArgs = pDest.GetTypeArgsAll();
+ TypeArray pSourceArgs = pSource.TypeArgsAll;
+ TypeArray pDestArgs = pDest.TypeArgsAll;
Debug.Assert(pSourceArgs != null);
Debug.Assert(pDestArgs != null);
@@ -961,7 +958,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// SPEC: for Xi.
if (pDest is TypeParameterType pTPType)
{
- if (pTPType.IsMethodTypeParameter() && IsUnfixed(pTPType))
+ if (pTPType.IsMethodTypeParameter && IsUnfixed(pTPType))
{
AddLowerBound(pTPType, pSource);
return true;
@@ -995,36 +992,37 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return false;
}
- CType pElementSource = pArraySource.GetElementType();
+ CType pElementSource = pArraySource.ElementType;
CType pElementDest;
if (pDest is ArrayType pArrayDest)
{
- if (pArrayDest.rank != pArraySource.rank || pArrayDest.IsSZArray != pArraySource.IsSZArray)
+ if (pArrayDest.Rank != pArraySource.Rank || pArrayDest.IsSZArray != pArraySource.IsSZArray)
{
return false;
}
- pElementDest = pArrayDest.GetElementType();
+
+ pElementDest = pArrayDest.ElementType;
}
- else if (pDest.isPredefType(PredefinedType.PT_G_IENUMERABLE) ||
- pDest.isPredefType(PredefinedType.PT_G_ICOLLECTION) ||
- pDest.isPredefType(PredefinedType.PT_G_ILIST) ||
- pDest.isPredefType(PredefinedType.PT_G_IREADONLYCOLLECTION) ||
- pDest.isPredefType(PredefinedType.PT_G_IREADONLYLIST))
+ else if (pDest.IsPredefType(PredefinedType.PT_G_IENUMERABLE) ||
+ pDest.IsPredefType(PredefinedType.PT_G_ICOLLECTION) ||
+ pDest.IsPredefType(PredefinedType.PT_G_ILIST) ||
+ pDest.IsPredefType(PredefinedType.PT_G_IREADONLYCOLLECTION) ||
+ pDest.IsPredefType(PredefinedType.PT_G_IREADONLYLIST))
{
if (!pArraySource.IsSZArray)
{
return false;
}
AggregateType pAggregateDest = (AggregateType)pDest;
- pElementDest = pAggregateDest.GetTypeArgsThis()[0];
+ pElementDest = pAggregateDest.TypeArgsThis[0];
}
else
{
return false;
}
- if (pElementSource.IsRefType())
+ if (pElementSource.IsReferenceType)
{
LowerBoundInference(pElementSource, pElementDest);
}
@@ -1032,6 +1030,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
ExactInference(pElementSource, pElementDest);
}
+
return true;
}
@@ -1051,7 +1050,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
return false;
}
- ExactInference(pSource, pDest.AsNullableType().GetUnderlyingType());
+ ExactInference(pSource, pDest.AsNullableType().UnderlyingType);
return true;
}
* */
@@ -1065,7 +1064,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return false;
}
- TypeArray pDestArgs = pConstructedDest.GetTypeArgsAll();
+ TypeArray pDestArgs = pConstructedDest.TypeArgsAll;
if (pDestArgs.Count == 0)
{
return false;
@@ -1080,10 +1079,9 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// SPEC: lower bound inference or upper bound inference
// SPEC: is made from each Ui to the corresponding Vi.
- if (pSource is AggregateType aggSource &&
- aggSource.GetOwningAggregate() == pConstructedDest.GetOwningAggregate())
+ if (pSource is AggregateType aggSource && aggSource.OwningAggregate == pConstructedDest.OwningAggregate)
{
- if (aggSource.isInterfaceType() || aggSource.isDelegateType())
+ if (aggSource.IsInterfaceType || aggSource.IsDelegateType)
{
LowerBoundTypeArgumentInference(aggSource, pConstructedDest);
}
@@ -1091,6 +1089,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
ExactTypeArgumentInference(aggSource, pConstructedDest);
}
+
return true;
}
@@ -1122,7 +1121,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
private bool LowerBoundClassInference(CType pSource, AggregateType pDest)
{
- if (!pDest.isClassType())
+ if (!pDest.IsClassType)
{
return false;
}
@@ -1140,20 +1139,22 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
AggregateType pSourceBase = null;
- if (pSource.isClassType())
+ if (pSource.IsClassType)
{
- pSourceBase = (pSource as AggregateType).GetBaseClass();
+ pSourceBase = (pSource as AggregateType).BaseClass;
}
while (pSourceBase != null)
{
- if (pSourceBase.GetOwningAggregate() == pDest.GetOwningAggregate())
+ if (pSourceBase.OwningAggregate == pDest.OwningAggregate)
{
ExactTypeArgumentInference(pSourceBase, pDest);
return true;
}
- pSourceBase = pSourceBase.GetBaseClass();
+
+ pSourceBase = pSourceBase.BaseClass;
}
+
return false;
}
@@ -1161,7 +1162,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
private bool LowerBoundInterfaceInference(CType pSource, AggregateType pDest)
{
- if (!pDest.isInterfaceType())
+ if (!pDest.IsInterfaceType)
{
return false;
}
@@ -1175,38 +1176,34 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
//TypeArray pInterfaces = null;
- if (!pSource.isStructType() && !pSource.isClassType() &&
- !pSource.isInterfaceType() && !(pSource is TypeParameterType))
+ if (pSource is AggregateType sourceAts && (sourceAts.IsStructType || sourceAts.IsClassType || sourceAts.IsInterfaceType))
{
- return false;
- }
-
- var interfaces = pSource.AllPossibleInterfaces();
- AggregateType pInterface = null;
- foreach (AggregateType pCurrent in interfaces)
- {
- if (pCurrent.GetOwningAggregate() == pDest.GetOwningAggregate())
+ AggregateType iface = null;
+ foreach (AggregateType current in sourceAts.IfacesAll.Items)
{
- if (pInterface == null)
- {
- pInterface = pCurrent;
- }
- else if (pInterface != pCurrent)
+ if (current.OwningAggregate == pDest.OwningAggregate)
{
- // Not unique. Bail out.
- return false;
+ if (iface == null)
+ {
+ iface = current;
+ }
+ else if (iface != current)
+ {
+ // Not unique. Bail out.
+ return false;
+ }
}
}
+
+ if (iface != null)
+ {
+ LowerBoundTypeArgumentInference(iface, pDest);
+ return true;
+ }
}
- if (pInterface == null)
- {
- return false;
- }
- LowerBoundTypeArgumentInference(pInterface, pDest);
- return true;
- }
- ////////////////////////////////////////////////////////////////////////////////
+ return false;
+ }
private void LowerBoundTypeArgumentInference(
AggregateType pSource, AggregateType pDest)
@@ -1222,11 +1219,11 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Debug.Assert(pSource != null);
Debug.Assert(pDest != null);
- Debug.Assert(pSource.GetOwningAggregate() == pDest.GetOwningAggregate());
+ Debug.Assert(pSource.OwningAggregate == pDest.OwningAggregate);
- TypeArray pTypeParams = pSource.GetOwningAggregate().GetTypeVarsAll();
- TypeArray pSourceArgs = pSource.GetTypeArgsAll();
- TypeArray pDestArgs = pDest.GetTypeArgsAll();
+ TypeArray pTypeParams = pSource.OwningAggregate.GetTypeVarsAll();
+ TypeArray pSourceArgs = pSource.TypeArgsAll;
+ TypeArray pDestArgs = pDest.TypeArgsAll;
Debug.Assert(pTypeParams != null);
Debug.Assert(pSourceArgs != null);
@@ -1241,18 +1238,22 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
CType pSourceArg = pSourceArgs[arg];
CType pDestArg = pDestArgs[arg];
- if (pSourceArg.IsRefType() && pTypeParam.Covariant)
- {
- LowerBoundInference(pSourceArg, pDestArg);
- }
- else if (pSourceArg.IsRefType() && pTypeParam.Contravariant)
- {
- UpperBoundInference(pSourceArgs[arg], pDestArgs[arg]);
- }
- else
+ if (pSourceArg.IsReferenceType)
{
- ExactInference(pSourceArgs[arg], pDestArgs[arg]);
+ if (pTypeParam.Covariant)
+ {
+ LowerBoundInference(pSourceArg, pDestArg);
+ continue;
+ }
+
+ if (pTypeParam.Contravariant)
+ {
+ UpperBoundInference(pSourceArgs[arg], pDestArgs[arg]);
+ continue;
+ }
}
+
+ ExactInference(pSourceArgs[arg], pDestArgs[arg]);
}
}
@@ -1310,7 +1311,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// SPEC: for Xi.
if (pDest is TypeParameterType pTPType)
{
- if (pTPType.IsMethodTypeParameter() && IsUnfixed(pTPType))
+ if (pTPType.IsMethodTypeParameter && IsUnfixed(pTPType))
{
AddUpperBound(pTPType, pSource);
return true;
@@ -1336,36 +1337,37 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return false;
}
- CType pElementDest = pArrayDest.GetElementType();
+ CType pElementDest = pArrayDest.ElementType;
CType pElementSource;
if (pSource is ArrayType pArraySource)
{
- if (pArrayDest.rank != pArraySource.rank || pArrayDest.IsSZArray != pArraySource.IsSZArray)
+ if (pArrayDest.Rank != pArraySource.Rank || pArrayDest.IsSZArray != pArraySource.IsSZArray)
{
return false;
}
- pElementSource = pArraySource.GetElementType();
+
+ pElementSource = pArraySource.ElementType;
}
- else if (pSource.isPredefType(PredefinedType.PT_G_IENUMERABLE) ||
- pSource.isPredefType(PredefinedType.PT_G_ICOLLECTION) ||
- pSource.isPredefType(PredefinedType.PT_G_ILIST) ||
- pSource.isPredefType(PredefinedType.PT_G_IREADONLYLIST) ||
- pSource.isPredefType(PredefinedType.PT_G_IREADONLYCOLLECTION))
+ else if (pSource.IsPredefType(PredefinedType.PT_G_IENUMERABLE) ||
+ pSource.IsPredefType(PredefinedType.PT_G_ICOLLECTION) ||
+ pSource.IsPredefType(PredefinedType.PT_G_ILIST) ||
+ pSource.IsPredefType(PredefinedType.PT_G_IREADONLYLIST) ||
+ pSource.IsPredefType(PredefinedType.PT_G_IREADONLYCOLLECTION))
{
if (!pArrayDest.IsSZArray)
{
return false;
}
AggregateType pAggregateSource = (AggregateType)pSource;
- pElementSource = pAggregateSource.GetTypeArgsThis()[0];
+ pElementSource = pAggregateSource.TypeArgsThis[0];
}
else
{
return false;
}
- if (pElementSource.IsRefType())
+ if (pElementSource.IsReferenceType)
{
UpperBoundInference(pElementSource, pElementDest);
}
@@ -1373,6 +1375,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
ExactInference(pElementSource, pElementDest);
}
+
return true;
}
@@ -1385,7 +1388,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return false;
}
- TypeArray pSourceArgs = pConstructedSource.GetTypeArgsAll();
+ TypeArray pSourceArgs = pConstructedSource.TypeArgsAll;
if (pSourceArgs.Count == 0)
{
return false;
@@ -1396,10 +1399,9 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// SPEC: lower bound inference or upper bound inference
// SPEC: is made from each Ui to the corresponding Vi.
- if (pDest is AggregateType aggDest &&
- pConstructedSource.GetOwningAggregate() == aggDest.GetOwningAggregate())
+ if (pDest is AggregateType aggDest && pConstructedSource.OwningAggregate == aggDest.OwningAggregate)
{
- if (aggDest.isInterfaceType() || aggDest.isDelegateType())
+ if (aggDest.IsInterfaceType || aggDest.IsDelegateType)
{
UpperBoundTypeArgumentInference(pConstructedSource, aggDest);
}
@@ -1407,6 +1409,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
ExactTypeArgumentInference(pConstructedSource, aggDest);
}
+
return true;
}
@@ -1435,7 +1438,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
private bool UpperBoundClassInference(AggregateType pSource, CType pDest)
{
- if (!pSource.isClassType() || !pDest.isClassType())
+ if (!pSource.IsClassType || !pDest.IsClassType)
{
return false;
}
@@ -1444,17 +1447,19 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// SPEC: inherits directly or indirectly from C<V1...Vk> then an exact
// SPEC: inference is made from each Ui to the corresponding Vi.
- AggregateType pDestBase = ((AggregateType)pDest).GetBaseClass();
+ AggregateType pDestBase = ((AggregateType)pDest).BaseClass;
while (pDestBase != null)
{
- if (pDestBase.GetOwningAggregate() == pSource.GetOwningAggregate())
+ if (pDestBase.OwningAggregate == pSource.OwningAggregate)
{
ExactTypeArgumentInference(pSource, pDestBase);
return true;
}
- pDestBase = pDestBase.GetBaseClass();
+
+ pDestBase = pDestBase.BaseClass;
}
+
return false;
}
@@ -1462,7 +1467,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
private bool UpperBoundInterfaceInference(AggregateType pSource, CType pDest)
{
- if (!pSource.isInterfaceType())
+ if (!pSource.IsInterfaceType)
{
return false;
}
@@ -1472,38 +1477,34 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// SPEC: or indirectly implements C<V1...Vk> then an exact ...
// SPEC: ... and U is an interface CType ...
- if (!pDest.isStructType() && !pDest.isClassType() &&
- !pDest.isInterfaceType())
+ if (pDest is AggregateType destAts && (destAts.IsStructType || destAts.IsClassType || destAts.IsInterfaceType))
{
- return false;
- }
-
- var interfaces = pDest.AllPossibleInterfaces();
- AggregateType pInterface = null;
- foreach (AggregateType pCurrent in interfaces)
- {
- if (pCurrent.GetOwningAggregate() == pSource.GetOwningAggregate())
+ AggregateType iface = null;
+ foreach (AggregateType current in destAts.IfacesAll.Items)
{
- if (pInterface == null)
+ if (current.OwningAggregate == pSource.OwningAggregate)
{
- pInterface = pCurrent;
- }
- else if (pInterface != pCurrent)
- {
- // Not unique. Bail out.
- return false;
+ if (iface == null)
+ {
+ iface = current;
+ }
+ else if (iface != current)
+ {
+ // Not unique. Bail out.
+ return false;
+ }
}
}
+
+ if (iface != null)
+ {
+ UpperBoundTypeArgumentInference(iface, pDest as AggregateType);
+ return true;
+ }
}
- if (pInterface == null)
- {
- return false;
- }
- UpperBoundTypeArgumentInference(pInterface, pDest as AggregateType);
- return true;
- }
- ////////////////////////////////////////////////////////////////////////////////
+ return false;
+ }
private void UpperBoundTypeArgumentInference(
AggregateType pSource, AggregateType pDest)
@@ -1519,11 +1520,11 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Debug.Assert(pSource != null);
Debug.Assert(pDest != null);
- Debug.Assert(pSource.GetOwningAggregate() == pDest.GetOwningAggregate());
+ Debug.Assert(pSource.OwningAggregate == pDest.OwningAggregate);
- TypeArray pTypeParams = pSource.GetOwningAggregate().GetTypeVarsAll();
- TypeArray pSourceArgs = pSource.GetTypeArgsAll();
- TypeArray pDestArgs = pDest.GetTypeArgsAll();
+ TypeArray pTypeParams = pSource.OwningAggregate.GetTypeVarsAll();
+ TypeArray pSourceArgs = pSource.TypeArgsAll;
+ TypeArray pDestArgs = pDest.TypeArgsAll;
Debug.Assert(pTypeParams != null);
Debug.Assert(pSourceArgs != null);
@@ -1538,18 +1539,22 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
CType pSourceArg = pSourceArgs[arg];
CType pDestArg = pDestArgs[arg];
- if (pSourceArg.IsRefType() && pTypeParam.Covariant)
- {
- UpperBoundInference(pSourceArg, pDestArg);
- }
- else if (pSourceArg.IsRefType() && pTypeParam.Contravariant)
+ if (pSourceArg.IsReferenceType)
{
- LowerBoundInference(pSourceArgs[arg], pDestArgs[arg]);
- }
- else
- {
- ExactInference(pSourceArgs[arg], pDestArgs[arg]);
+ if (pTypeParam.Covariant)
+ {
+ UpperBoundInference(pSourceArg, pDestArg);
+ continue;
+ }
+
+ if (pTypeParam.Contravariant)
+ {
+ LowerBoundInference(pSourceArgs[arg], pDestArgs[arg]);
+ continue;
+ }
}
+
+ ExactInference(pSourceArgs[arg], pDestArgs[arg]);
}
}
@@ -1688,60 +1693,18 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// used to alter the types at the beginning of binding. that
// way we get an accessible type, and if it so happens that
// the selected type is inappropriate (for conversions) then
- // we let overload resolution sort it out.
+ // we let overload resolution sort it out.
//
// since we can never infer ref/out or pointer types here, we
- // are more or less guaranteed a best accessible type. However,
- // in the interest of safety, if it becomes impossible to
- // choose a "best accessible" type, then we will fail type
- // inference so we do not try to pass the inaccessible type
- // back to overload resolution.
-
- CType pBestAccessible;
- if (GetTypeManager().GetBestAccessibleType(_binder.GetSemanticChecker(), _binder.GetContext(), pBest, out pBestAccessible))
- {
- pBest = pBestAccessible;
- }
- else
- {
- Debug.Assert(false, "Method type inference could not find an accessible type over the best candidate in fixed");
- return false;
- }
+ // are guaranteed a best accessible type.
+ _pFixedResults[iParam] = TypeManager.GetBestAccessibleType(_binder.Context.ContextForMemberLookup, pBest);
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// END RUNTIME BINDER ONLY CHANGE
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- _pFixedResults[iParam] = pBest;
UpdateDependenciesAfterFix(iParam);
return true;
}
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Helper methods
- //
-
- ////////////////////////////////////////////////////////////////////////////////
-
-
- private SymbolLoader GetSymbolLoader()
- {
- return _symbolLoader;
- }
-
- ////////////////////////////////////////////////////////////////////////////////
-
- private TypeManager GetTypeManager()
- {
- return GetSymbolLoader().GetTypeManager();
- }
-
- ////////////////////////////////////////////////////////////////////////////////
-
- private BSYMMGR GetGlobalSymbols()
- {
- return GetSymbolLoader().getBSymmgr();
- }
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Nullable.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Nullable.cs
index 4c514fbe59..425e9102c4 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Nullable.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Nullable.cs
@@ -3,29 +3,11 @@
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
-using Microsoft.CSharp.RuntimeBinder.Errors;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
- internal sealed class CNullable
+ internal readonly partial struct ExpressionBinder
{
- private readonly SymbolLoader _pSymbolLoader;
- private readonly ExprFactory _exprFactory;
- private readonly ErrorHandling _pErrorContext;
-
- private SymbolLoader GetSymbolLoader()
- {
- return _pSymbolLoader;
- }
- private ExprFactory GetExprFactory()
- {
- return _exprFactory;
- }
- private ErrorHandling GetErrorContext()
- {
- return _pErrorContext;
- }
-
private static bool IsNullableConstructor(Expr expr, out ExprCall call)
{
Debug.Assert(expr != null);
@@ -41,7 +23,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return false;
}
- public static Expr StripNullableConstructor(Expr pExpr)
+ private static Expr StripNullableConstructor(Expr pExpr)
{
while (IsNullableConstructor(pExpr, out ExprCall call))
{
@@ -52,75 +34,40 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return pExpr;
}
- // Value
- public Expr BindValue(Expr exprSrc)
+ // Create an expr for exprSrc.Value where exprSrc.type is a NullableType.
+ private static Expr BindNubValue(Expr exprSrc)
{
Debug.Assert(exprSrc != null && exprSrc.Type is NullableType);
// For new T?(x), the answer is x.
if (IsNullableConstructor(exprSrc, out ExprCall call))
{
- var args = call.OptionalArguments;
+ Expr args = call.OptionalArguments;
Debug.Assert(args != null && !(args is ExprList));
return args;
}
NullableType nubSrc = (NullableType)exprSrc.Type;
- CType typeBase = nubSrc.GetUnderlyingType();
+ CType typeBase = nubSrc.UnderlyingType;
AggregateType ats = nubSrc.GetAts();
- PropertySymbol prop = GetSymbolLoader().getBSymmgr().propNubValue;
- if (prop == null)
- {
- prop = GetSymbolLoader().getPredefinedMembers().GetProperty(PREDEFPROP.PP_G_OPTIONAL_VALUE);
- Debug.Assert(prop != null);
- GetSymbolLoader().getBSymmgr().propNubValue = prop;
- }
-
+ PropertySymbol prop = PredefinedMembers.GetProperty(PREDEFPROP.PP_G_OPTIONAL_VALUE);
PropWithType pwt = new PropWithType(prop, ats);
MethPropWithInst mpwi = new MethPropWithInst(prop, ats);
- ExprMemberGroup pMemGroup = GetExprFactory().CreateMemGroup(exprSrc, mpwi);
- return GetExprFactory().CreateProperty(typeBase, null, null, pMemGroup, pwt, null);
+ ExprMemberGroup pMemGroup = ExprFactory.CreateMemGroup(exprSrc, mpwi);
+ return ExprFactory.CreateProperty(typeBase, null, null, pMemGroup, pwt, null);
}
- public ExprCall BindNew(Expr pExprSrc)
+ // Create an expr for new T?(exprSrc) where T is exprSrc.type.
+ private static ExprCall BindNubNew(Expr exprSrc)
{
- Debug.Assert(pExprSrc != null);
-
- NullableType pNubSourceType = GetSymbolLoader().GetTypeManager().GetNullable(pExprSrc.Type);
+ Debug.Assert(exprSrc != null);
+ NullableType pNubSourceType = TypeManager.GetNullable(exprSrc.Type);
AggregateType pSourceType = pNubSourceType.GetAts();
- MethodSymbol meth = GetSymbolLoader().getBSymmgr().methNubCtor;
- if (meth == null)
- {
- meth = GetSymbolLoader().getPredefinedMembers().GetMethod(PREDEFMETH.PM_G_OPTIONAL_CTOR);
- Debug.Assert(meth != null);
- GetSymbolLoader().getBSymmgr().methNubCtor = meth;
- }
-
- MethWithInst methwithinst = new MethWithInst(meth, pSourceType, BSYMMGR.EmptyTypeArray());
- ExprMemberGroup memgroup = GetExprFactory().CreateMemGroup(null, methwithinst);
- return GetExprFactory().CreateCall(EXPRFLAG.EXF_NEWOBJCALL | EXPRFLAG.EXF_CANTBENULL, pNubSourceType, pExprSrc, memgroup, methwithinst);
- }
- public CNullable(SymbolLoader symbolLoader, ErrorHandling errorContext, ExprFactory exprFactory)
- {
- _pSymbolLoader = symbolLoader;
- _pErrorContext = errorContext;
- _exprFactory = exprFactory;
- }
- }
-
- internal sealed partial class ExpressionBinder
- {
- // Create an expr for exprSrc.Value where exprSrc.type is a NullableType.
- private Expr BindNubValue(Expr exprSrc)
- {
- return m_nullable.BindValue(exprSrc);
- }
-
- // Create an expr for new T?(exprSrc) where T is exprSrc.type.
- private ExprCall BindNubNew(Expr exprSrc)
- {
- return m_nullable.BindNew(exprSrc);
+ MethodSymbol meth = PredefinedMembers.GetMethod(PREDEFMETH.PM_G_OPTIONAL_CTOR);
+ MethWithInst methwithinst = new MethWithInst(meth, pSourceType, TypeArray.Empty);
+ ExprMemberGroup memgroup = ExprFactory.CreateMemGroup(null, methwithinst);
+ return ExprFactory.CreateCall(EXPRFLAG.EXF_NEWOBJCALL | EXPRFLAG.EXF_CANTBENULL, pNubSourceType, exprSrc, memgroup, methwithinst);
}
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Operators.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Operators.cs
index 5c0f280419..ff6f1a66ae 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Operators.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Operators.cs
@@ -10,7 +10,7 @@ using Microsoft.CSharp.RuntimeBinder.Syntax;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
- internal sealed partial class ExpressionBinder
+ internal readonly partial struct ExpressionBinder
{
/*
These are the predefined binary operator signatures
@@ -80,16 +80,60 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// Method pointers must be in the order of the corresponding enums. We check this when the full signature is set.
// When the binding method is looked up in these arrays we ASSERT
// if the array is out of bounds of the corresponding array.
-
- private readonly BinOpSig[] g_binopSignatures;
+ private static readonly BinOpSig[] s_binopSignatures =
+ {
+ new BinOpSig (PredefinedType.PT_INT, PredefinedType.PT_INT, BinOpMask.Integer, 8, BindIntBinOp, OpSigFlags.Value, BinOpFuncKind.IntBinOp ),
+ new BinOpSig (PredefinedType.PT_UINT, PredefinedType.PT_UINT, BinOpMask.Integer, 7, BindIntBinOp, OpSigFlags.Value, BinOpFuncKind.IntBinOp ),
+ new BinOpSig (PredefinedType.PT_LONG, PredefinedType.PT_LONG, BinOpMask.Integer, 6, BindIntBinOp, OpSigFlags.Value, BinOpFuncKind.IntBinOp ),
+ new BinOpSig (PredefinedType.PT_ULONG, PredefinedType.PT_ULONG, BinOpMask.Integer, 5, BindIntBinOp, OpSigFlags.Value, BinOpFuncKind.IntBinOp ),
+ /* ERROR */
+ new BinOpSig (PredefinedType.PT_ULONG, PredefinedType.PT_LONG, BinOpMask.Integer, 4, null, OpSigFlags.Value, BinOpFuncKind.None ),
+ /* ERROR */
+ new BinOpSig (PredefinedType.PT_LONG, PredefinedType.PT_ULONG, BinOpMask.Integer, 3, null, OpSigFlags.Value, BinOpFuncKind.None ),
+ new BinOpSig (PredefinedType.PT_FLOAT, PredefinedType.PT_FLOAT, BinOpMask.Real, 1, BindRealBinOp, OpSigFlags.Value, BinOpFuncKind.RealBinOp ),
+ new BinOpSig (PredefinedType.PT_DOUBLE, PredefinedType.PT_DOUBLE, BinOpMask.Real, 0, BindRealBinOp, OpSigFlags.Value, BinOpFuncKind.RealBinOp ),
+ new BinOpSig (PredefinedType.PT_DECIMAL, PredefinedType.PT_DECIMAL, BinOpMask.Real, 0, BindDecBinOp, OpSigFlags.Value, BinOpFuncKind.DecBinOp ),
+ new BinOpSig (PredefinedType.PT_STRING, PredefinedType.PT_STRING, BinOpMask.Equal, 0, BindStrCmpOp, OpSigFlags.Reference, BinOpFuncKind.StrCmpOp ),
+ new BinOpSig (PredefinedType.PT_STRING, PredefinedType.PT_STRING, BinOpMask.Add, 2, BindStrBinOp, OpSigFlags.Reference, BinOpFuncKind.StrBinOp ),
+ new BinOpSig (PredefinedType.PT_STRING, PredefinedType.PT_OBJECT, BinOpMask.Add, 1, BindStrBinOp, OpSigFlags.Reference, BinOpFuncKind.StrBinOp ),
+ new BinOpSig (PredefinedType.PT_OBJECT, PredefinedType.PT_STRING, BinOpMask.Add, 0, BindStrBinOp, OpSigFlags.Reference, BinOpFuncKind.StrBinOp ),
+ new BinOpSig (PredefinedType.PT_INT, PredefinedType.PT_INT, BinOpMask.Shift, 3, BindShiftOp, OpSigFlags.Value, BinOpFuncKind.ShiftOp ),
+ new BinOpSig (PredefinedType.PT_UINT, PredefinedType.PT_INT, BinOpMask.Shift, 2, BindShiftOp, OpSigFlags.Value, BinOpFuncKind.ShiftOp ),
+ new BinOpSig (PredefinedType.PT_LONG, PredefinedType.PT_INT, BinOpMask.Shift, 1, BindShiftOp, OpSigFlags.Value, BinOpFuncKind.ShiftOp ),
+ new BinOpSig (PredefinedType.PT_ULONG, PredefinedType.PT_INT, BinOpMask.Shift, 0, BindShiftOp, OpSigFlags.Value, BinOpFuncKind.ShiftOp ),
+ new BinOpSig (PredefinedType.PT_BOOL, PredefinedType.PT_BOOL, BinOpMask.BoolNorm, 0, BindBoolBinOp, OpSigFlags.Value, BinOpFuncKind.BoolBinOp ),
+ // Make boolean logical operators liftable so that they don't give funny short circuiting semantics.
+ // This is for DDBugs 677075.
+ new BinOpSig (PredefinedType.PT_BOOL, PredefinedType.PT_BOOL, BinOpMask.Logical, 0, BindBoolBinOp, OpSigFlags.BoolBit, BinOpFuncKind.BoolBinOp ),
+ new BinOpSig (PredefinedType.PT_BOOL, PredefinedType.PT_BOOL, BinOpMask.Bitwise, 0, BindLiftedBoolBitwiseOp, OpSigFlags.BoolBit, BinOpFuncKind.BoolBitwiseOp ),
+ };
// We want unary minus to bind to "operator -(ulong)" and then we
// produce an error (since there is no pfn). We can't let - bind to a floating point type,
// since they lose precision. See the language spec.
// Increment and decrement operators are special.
+ private static readonly UnaOpSig[] s_rguos =
+ {
+ new UnaOpSig( PredefinedType.PT_INT, UnaOpMask.Signed, 7, BindIntUnaOp, UnaOpFuncKind.IntUnaOp ),
+ new UnaOpSig( PredefinedType.PT_UINT, UnaOpMask.Unsigned, 6, BindIntUnaOp, UnaOpFuncKind.IntUnaOp ),
+ new UnaOpSig( PredefinedType.PT_LONG, UnaOpMask.Signed, 5, BindIntUnaOp, UnaOpFuncKind.IntUnaOp ),
+ new UnaOpSig( PredefinedType.PT_ULONG, UnaOpMask.Unsigned, 4, BindIntUnaOp, UnaOpFuncKind.IntUnaOp ),
+ /* ERROR */
+ new UnaOpSig( PredefinedType.PT_ULONG, UnaOpMask.Minus, 3, null, UnaOpFuncKind.None ),
+ new UnaOpSig( PredefinedType.PT_FLOAT, UnaOpMask.Real, 1, BindRealUnaOp, UnaOpFuncKind.RealUnaOp ),
+ new UnaOpSig( PredefinedType.PT_DOUBLE, UnaOpMask.Real, 0, BindRealUnaOp, UnaOpFuncKind.RealUnaOp ),
+ new UnaOpSig( PredefinedType.PT_DECIMAL, UnaOpMask.Real, 0, BindDecUnaOp, UnaOpFuncKind.DecUnaOp ),
+ new UnaOpSig( PredefinedType.PT_BOOL, UnaOpMask.Bool, 0, BindBoolUnaOp, UnaOpFuncKind.BoolUnaOp ),
+ new UnaOpSig( PredefinedType.PT_INT, UnaOpMask.IncDec, 6, null, UnaOpFuncKind.None ),
+ new UnaOpSig( PredefinedType.PT_UINT, UnaOpMask.IncDec, 5, null, UnaOpFuncKind.None ),
+ new UnaOpSig( PredefinedType.PT_LONG, UnaOpMask.IncDec, 4, null, UnaOpFuncKind.None ),
+ new UnaOpSig( PredefinedType.PT_ULONG, UnaOpMask.IncDec, 3, null, UnaOpFuncKind.None ),
+ new UnaOpSig( PredefinedType.PT_FLOAT, UnaOpMask.IncDec, 1, null, UnaOpFuncKind.None ),
+ new UnaOpSig( PredefinedType.PT_DOUBLE, UnaOpMask.IncDec, 0, null, UnaOpFuncKind.None ),
+ new UnaOpSig( PredefinedType.PT_DECIMAL, UnaOpMask.IncDec, 0, null, UnaOpFuncKind.None ),
+ };
- private readonly UnaOpSig[] g_rguos;
private ExprBinOp BindUserDefinedBinOp(ExpressionKind ek, BinOpArgInfo info)
{
@@ -122,7 +166,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return null;
}
- return GetExprFactory().CreateUserDefinedBinop(ek, expr.Type, info.arg1, info.arg2, expr, pmpwi);
+ return ExprFactory.CreateUserDefinedBinop(ek, expr.Type, info.arg1, info.arg2, expr, pmpwi);
}
// Adds special signatures to the candidate list. If we find an exact match
@@ -147,9 +191,9 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Debug.Assert(rgbofs != null);
int ibosMinLift = 0;
- for (int ibos = 0; ibos < g_binopSignatures.Length; ibos++)
+ for (int ibos = 0; ibos < s_binopSignatures.Length; ibos++)
{
- BinOpSig bos = g_binopSignatures[ibos];
+ BinOpSig bos = s_binopSignatures[ibos];
if ((bos.mask & info.mask) == 0)
{
continue;
@@ -189,9 +233,9 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
continue;
}
- Debug.Assert(typeSig1.IsValType());
+ Debug.Assert(typeSig1.IsValueType);
- typeSig1 = GetSymbolLoader().GetTypeManager().GetNullable(typeSig1);
+ typeSig1 = TypeManager.GetNullable(typeSig1);
if (!canConvert(constant, typeSig1))
{
continue;
@@ -216,9 +260,9 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
continue;
}
- Debug.Assert(typeSig1.IsValType());
+ Debug.Assert(typeSig1.IsValueType);
- typeSig1 = GetSymbolLoader().GetTypeManager().GetNullable(typeSig1);
+ typeSig1 = TypeManager.GetNullable(typeSig1);
if (!canConvert(info.arg1, typeSig1))
{
continue;
@@ -273,9 +317,9 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
continue;
}
- Debug.Assert(typeSig2.IsValType());
+ Debug.Assert(typeSig2.IsValueType);
- typeSig2 = GetSymbolLoader().GetTypeManager().GetNullable(typeSig2);
+ typeSig2 = TypeManager.GetNullable(typeSig2);
if (!canConvert(constant, typeSig2))
{
continue;
@@ -301,9 +345,9 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
continue;
}
- Debug.Assert(typeSig2.IsValType());
+ Debug.Assert(typeSig2.IsValueType);
- typeSig2 = GetSymbolLoader().GetTypeManager().GetNullable(typeSig2);
+ typeSig2 = TypeManager.GetNullable(typeSig2);
if (!canConvert(info.arg2, typeSig2))
{
continue;
@@ -401,7 +445,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return bestSignature;
}
- private ExprBinOp bindNullEqualityComparison(ExpressionKind ek, BinOpArgInfo info)
+ private static ExprBinOp BindNullEqualityComparison(ExpressionKind ek, BinOpArgInfo info)
{
Expr arg1 = info.arg1;
Expr arg2 = info.arg2;
@@ -411,13 +455,13 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
ExprBinOp exprRes = null;
if (info.type1 is NullableType && info.type2 is NullType)
{
- arg2 = GetExprFactory().CreateZeroInit(info.type1);
- exprRes = GetExprFactory().CreateBinop(ek, typeBool, arg1, arg2);
+ arg2 = ExprFactory.CreateZeroInit(info.type1);
+ exprRes = ExprFactory.CreateBinop(ek, typeBool, arg1, arg2);
}
if (info.type1 is NullType && info.type2 is NullableType)
{
- arg1 = GetExprFactory().CreateZeroInit(info.type2);
- exprRes = GetExprFactory().CreateBinop(ek, typeBool, arg1, arg2);
+ arg1 = ExprFactory.CreateZeroInit(info.type2);
+ exprRes = ExprFactory.CreateBinop(ek, typeBool, arg1, arg2);
}
if (exprRes != null)
{
@@ -481,7 +525,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
// If we got no matches then it's possible that we're in the case
// x == null, where x is nullable.
- return bindNullEqualityComparison(ek, info);
+ return BindNullEqualityComparison(ek, info);
}
else
{
@@ -494,7 +538,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
// Ambiguous.
- throw AmbiguousOperatorError(ek, arg1, arg2);
+ throw AmbiguousOperatorError(arg1, arg2);
}
}
@@ -523,11 +567,13 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
expr1 = mustConvert(expr1, bofs.Type1());
expr2 = mustConvert(expr2, bofs.Type2());
}
+
if (bofs.fnkind == BinOpFuncKind.BoolBitwiseOp)
{
- return BindBoolBitwiseOp(ek, flags, expr1, expr2, bofs);
+ return BindBoolBitwiseOp(ek, flags, expr1, expr2);
}
- return bofs.pfn(ek, flags, expr1, expr2);
+
+ return bofs.pfn(this, ek, flags, expr1, expr2);
}
Debug.Assert(bofs.fnkind != BinOpFuncKind.BoolBitwiseOp);
if (IsEnumArithmeticBinOp(ek, info))
@@ -567,7 +613,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
// Only compute the method if theres no nulls. If there are, we'll special case it
// later, since operations with a null operand are null.
- nonLiftedResult = bofs.pfn(ek, flags, nonLiftedArg1, nonLiftedArg2);
+ nonLiftedResult = bofs.pfn(this, ek, flags, nonLiftedArg1, nonLiftedArg2);
}
// Check if we have a comparison. If so, set the result type to bool.
@@ -584,11 +630,11 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (!(resultType is NullableType))
{
- resultType = GetSymbolLoader().GetTypeManager().GetNullable(resultType);
+ resultType = TypeManager.GetNullable(resultType);
}
}
- ExprBinOp exprRes = GetExprFactory().CreateBinop(ek, resultType, pArgument1, pArgument2);
+ ExprBinOp exprRes = ExprFactory.CreateBinop(ek, resultType, pArgument1, pArgument2);
mustCast(nonLiftedResult, resultType, 0);
exprRes.IsLifted = true;
exprRes.Flags |= flags;
@@ -615,7 +661,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
pNonLiftedArgument = mustCast(pNonLiftedArgument, pParameterType);
}
- pNonLiftedArgument = mustCast(pNonLiftedArgument, paramNub.GetUnderlyingType());
+ pNonLiftedArgument = mustCast(pNonLiftedArgument, paramNub.UnderlyingType);
if (bConvertBeforeLift)
{
MarkAsIntermediateConversion(pNonLiftedArgument);
@@ -635,11 +681,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
*/
private bool GetDelBinOpSigs(List<BinOpFullSig> prgbofs, BinOpArgInfo info)
{
- if (!info.ValidForDelegate())
- {
- return false;
- }
- if (!info.type1.isDelegateType() && !info.type2.isDelegateType())
+ if (!info.ValidForDelegate() || !info.type1.IsDelegateType && !info.type2.IsDelegateType)
{
return false;
}
@@ -655,8 +697,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// for this binary operator. It's possible that we add two candidates, in which case they will compete
// in overload resolution. Or we could add no candidates.
- bool t1tot2 = info.type2.isDelegateType() && canConvert(info.arg1, info.type2);
- bool t2tot1 = info.type1.isDelegateType() && canConvert(info.arg2, info.type1);
+ bool t1tot2 = info.type2.IsDelegateType && canConvert(info.arg1, info.type2);
+ bool t2tot1 = info.type1.IsDelegateType && canConvert(info.arg2, info.type1);
if (t1tot2)
{
@@ -688,7 +730,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
else
{
pgrflt = LiftFlags.None;
- typeDst = GetSymbolLoader().GetTypeManager().GetNullable(typeDst);
+ typeDst = TypeManager.GetNullable(typeDst);
if (!canConvert(info.arg1, typeDst))
return false;
pgrflt = LiftFlags.Convert1;
@@ -698,7 +740,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (info.type2 is NullableType)
{
pgrflt = pgrflt | LiftFlags.Lift2;
- ptypeSig2 = GetSymbolLoader().GetTypeManager().GetNullable(info.typeRaw2);
+ ptypeSig2 = TypeManager.GetNullable(info.typeRaw2);
}
else
ptypeSig2 = info.typeRaw2;
@@ -722,7 +764,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
else
{
pgrflt = LiftFlags.None;
- typeDst = GetSymbolLoader().GetTypeManager().GetNullable(typeDst);
+ typeDst = TypeManager.GetNullable(typeDst);
if (!canConvert(info.arg2, typeDst))
return false;
pgrflt = LiftFlags.Convert2;
@@ -732,7 +774,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (info.type1 is NullableType)
{
pgrflt = pgrflt | LiftFlags.Lift1;
- ptypeSig1 = GetSymbolLoader().GetTypeManager().GetNullable(info.typeRaw1);
+ ptypeSig1 = TypeManager.GetNullable(info.typeRaw1);
}
else
ptypeSig1 = info.typeRaw1;
@@ -745,7 +787,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Record the appropriate binary operator full signature from the given BinOpArgInfo. This assumes
that any NullableType valued args should be lifted.
*/
- private void RecordBinOpSigFromArgs(List<BinOpFullSig> prgbofs, BinOpArgInfo info)
+ private static void RecordBinOpSigFromArgs(List<BinOpFullSig> prgbofs, BinOpArgInfo info)
{
LiftFlags grflt = LiftFlags.None;
CType typeSig1;
@@ -755,19 +797,23 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
Debug.Assert(info.type1 is NullableType);
grflt = grflt | LiftFlags.Lift1;
- typeSig1 = GetSymbolLoader().GetTypeManager().GetNullable(info.typeRaw1);
+ typeSig1 = TypeManager.GetNullable(info.typeRaw1);
}
else
+ {
typeSig1 = info.typeRaw1;
+ }
if (info.type2 != info.typeRaw2)
{
Debug.Assert(info.type2 is NullableType);
grflt = grflt | LiftFlags.Lift2;
- typeSig2 = GetSymbolLoader().GetTypeManager().GetNullable(info.typeRaw2);
+ typeSig2 = TypeManager.GetNullable(info.typeRaw2);
}
else
+ {
typeSig2 = info.typeRaw2;
+ }
prgbofs.Add(new BinOpFullSig(typeSig1, typeSig2, BindEnumBinOp, OpSigFlags.Value, grflt, BinOpFuncKind.EnumBinOp));
}
@@ -778,7 +824,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
*/
private bool GetEnumBinOpSigs(List<BinOpFullSig> prgbofs, BinOpArgInfo info)
{
- if (!info.typeRaw1.isEnumType() && !info.typeRaw2.isEnumType())
+ if (!info.typeRaw1.IsEnumType && !info.typeRaw2.IsEnumType)
{
return false;
}
@@ -797,20 +843,14 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
return false;
}
+
RecordBinOpSigFromArgs(prgbofs, info);
return true;
}
- bool isValidForEnum;
-
- if (info.typeRaw1.isEnumType())
- {
- isValidForEnum = (info.typeRaw2 == info.typeRaw1.underlyingEnumType() && info.ValidForEnumAndUnderlyingType());
- }
- else
- {
- isValidForEnum = (info.typeRaw1 == info.typeRaw2.underlyingEnumType() && info.ValidForUnderlyingTypeAndEnum());
- }
+ bool isValidForEnum = info.typeRaw1.IsEnumType
+ ? info.typeRaw2 == info.typeRaw1.UnderlyingEnumType && info.ValidForEnumAndUnderlyingType()
+ : info.typeRaw1 == info.typeRaw2.UnderlyingEnumType && info.ValidForUnderlyingTypeAndEnum();
if (isValidForEnum)
{
@@ -821,15 +861,15 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// Now deal with the conversion cases. Since there are no conversions from enum types to other
// enum types we never need to do both cases.
- if (info.typeRaw1.isEnumType())
+ if (info.typeRaw1.IsEnumType)
{
isValidForEnum = info.ValidForEnum() && CanConvertArg2(info, info.typeRaw1, out grflt, out typeSig1, out typeSig2) ||
- info.ValidForEnumAndUnderlyingType() && CanConvertArg2(info, info.typeRaw1.underlyingEnumType(), out grflt, out typeSig1, out typeSig2);
+ info.ValidForEnumAndUnderlyingType() && CanConvertArg2(info, info.typeRaw1.UnderlyingEnumType, out grflt, out typeSig1, out typeSig2);
}
else
{
isValidForEnum = info.ValidForEnum() && CanConvertArg1(info, info.typeRaw2, out grflt, out typeSig1, out typeSig2) ||
- info.ValidForEnumAndUnderlyingType() && CanConvertArg1(info, info.typeRaw2.underlyingEnumType(), out grflt, out typeSig1, out typeSig2);
+ info.ValidForEnumAndUnderlyingType() && CanConvertArg1(info, info.typeRaw2.UnderlyingEnumType, out grflt, out typeSig1, out typeSig2);
}
if (isValidForEnum)
@@ -839,14 +879,14 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return false;
}
- private bool IsEnumArithmeticBinOp(ExpressionKind ek, BinOpArgInfo info)
+ private static bool IsEnumArithmeticBinOp(ExpressionKind ek, BinOpArgInfo info)
{
switch (ek)
{
case ExpressionKind.Add:
- return info.typeRaw1.isEnumType() ^ info.typeRaw2.isEnumType();
+ return info.typeRaw1.IsEnumType ^ info.typeRaw2.IsEnumType;
case ExpressionKind.Subtract:
- return info.typeRaw1.isEnumType() | info.typeRaw2.isEnumType();
+ return info.typeRaw1.IsEnumType | info.typeRaw2.IsEnumType;
}
return false;
@@ -886,8 +926,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// Check for: operator ==(System.Delegate, System.Delegate).
CType typeDel = GetPredefindType(PredefinedType.PT_DELEGATE);
- if (canConvert(info.arg1, typeDel) && canConvert(info.arg2, typeDel) && !type1.isDelegateType()
- && !type2.isDelegateType())
+ if (canConvert(info.arg1, typeDel) && canConvert(info.arg2, typeDel) && !type1.IsDelegateType && !type2.IsDelegateType)
{
prgbofs.Add(
new BinOpFullSig(
@@ -896,8 +935,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
// The reference type equality operators only handle reference types.
- Debug.Assert(type1.fundType() != FUNDTYPE.FT_VAR);
- if (type1.fundType() != FUNDTYPE.FT_REF)
+ Debug.Assert(type1.FundamentalType != FUNDTYPE.FT_VAR);
+ if (type1.FundamentalType != FUNDTYPE.FT_REF)
{
return false;
}
@@ -912,8 +951,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
else
{
- Debug.Assert(type2.fundType() != FUNDTYPE.FT_VAR);
- if (type2.fundType() != FUNDTYPE.FT_REF)
+ Debug.Assert(type2.FundamentalType != FUNDTYPE.FT_VAR);
+ if (type2.FundamentalType != FUNDTYPE.FT_REF)
{
return false;
}
@@ -931,32 +970,32 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (!canCast(type1, type2, CONVERTTYPE.NOUDC) && !canCast(type2, type1, CONVERTTYPE.NOUDC))
return false;
- if (type1.isInterfaceType() || type1.isPredefType(PredefinedType.PT_STRING)
- || GetSymbolLoader().HasBaseConversion(type1, typeDel))
+ if (type1.IsInterfaceType || type1.IsPredefType(PredefinedType.PT_STRING)
+ || SymbolLoader.HasBaseConversion(type1, typeDel))
type1 = typeObj;
else if (type1 is ArrayType)
type1 = GetPredefindType(PredefinedType.PT_ARRAY);
- else if (!type1.isClassType())
+ else if (!type1.IsClassType)
return false;
- if (type2.isInterfaceType() || type2.isPredefType(PredefinedType.PT_STRING)
- || GetSymbolLoader().HasBaseConversion(type2, typeDel))
+ if (type2.IsInterfaceType || type2.IsPredefType(PredefinedType.PT_STRING)
+ || SymbolLoader.HasBaseConversion(type2, typeDel))
type2 = typeObj;
else if (type2 is ArrayType)
type2 = GetPredefindType(PredefinedType.PT_ARRAY);
- else if (!type2.isClassType())
+ else if (!type2.IsClassType)
return false;
Debug.Assert(
- type1.isClassType() && !type1.isPredefType(PredefinedType.PT_STRING)
- && !type1.isPredefType(PredefinedType.PT_DELEGATE));
+ type1.IsClassType && !type1.IsPredefType(PredefinedType.PT_STRING)
+ && !type1.IsPredefType(PredefinedType.PT_DELEGATE));
Debug.Assert(
- type2.isClassType() && !type2.isPredefType(PredefinedType.PT_STRING)
- && !type2.isPredefType(PredefinedType.PT_DELEGATE));
+ type2.IsClassType && !type2.IsPredefType(PredefinedType.PT_STRING)
+ && !type2.IsPredefType(PredefinedType.PT_DELEGATE));
- if (GetSymbolLoader().HasBaseConversion(type2, type1))
+ if (SymbolLoader.HasBaseConversion(type2, type1))
typeCls = type1;
- else if (GetSymbolLoader().HasBaseConversion(type1, type2))
+ else if (SymbolLoader.HasBaseConversion(type1, type2))
typeCls = type2;
}
@@ -1120,10 +1159,10 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (type is NullableType nub)
{
CType nonNub = nub.UnderlyingType;
- if (nonNub.isEnumType())
+ if (nonNub.IsEnumType)
{
PredefinedType ptOp;
- switch (nonNub.fundType())
+ switch (nonNub.FundamentalType)
{
case FUNDTYPE.FT_U4:
ptOp = PredefinedType.PT_UINT;
@@ -1145,7 +1184,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return mustCast(
BindStandardUnaryOperator(
- op, mustCast(pArgument, GetTypes().GetNullable(GetPredefindType(ptOp)))), nub);
+ op, mustCast(pArgument, TypeManager.GetNullable(GetPredefindType(ptOp)))), nub);
}
}
@@ -1207,7 +1246,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (nBestSignature < 0)
{
// Ambiguous.
- throw AmbiguousOperatorError(ek, pArgument, null);
+ throw AmbiguousOperatorError(pArgument, null);
}
// Verify that our answer works.
@@ -1219,7 +1258,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
if (WhichUofsIsBetter(pSignatures[nBestSignature], pSignatures[iuofs], type) >= 0)
{
- throw AmbiguousOperatorError(ek, pArgument, null);
+ throw AmbiguousOperatorError(pArgument, null);
}
}
}
@@ -1262,7 +1301,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
arg = mustCast(pArgument, uofs.GetType(), CONVERTTYPE.NOUDC);
}
- return uofs.pfn(ek, flags, arg);
+
+ return uofs.pfn(this, ek, flags, arg);
}
/////////////////////////////////////////////////////////////////////////////////
@@ -1276,7 +1316,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
ppResult = null;
CType pArgumentType = pArgument.Type;
CType pRawType = pArgumentType.StripNubs();
- PredefinedType ptRaw = pRawType.isPredefined() ? pRawType.getPredefType() : PredefinedType.PT_COUNT;
+ PredefinedType ptRaw = pRawType.IsPredefined ? pRawType.PredefinedType : PredefinedType.PT_COUNT;
// Find all applicable operator signatures.
// First check for special ones (enum, ptr) and check for user defined ops.
@@ -1284,7 +1324,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (ptRaw > PredefinedType.PT_ULONG)
{
// Enum types are special in that they carry a set of "predefined" operators (~ and inc/dec).
- if (pRawType.isEnumType())
+ if (pRawType.IsEnumType)
{
// Nullable enums are dealt with already.
Debug.Assert(pRawType == pArgumentType);
@@ -1295,7 +1335,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (unaryOpKind == UnaOpKind.Tilde)
{
pSignatures.Add(new UnaOpFullSig(
- pArgumentType.getAggregate().GetUnderlyingType(),
+ ((AggregateType)pArgumentType).OwningAggregate.GetUnderlyingType(),
BindEnumUnaOp,
LiftFlags.None,
UnaOpFuncKind.EnumUnaOp));
@@ -1305,7 +1345,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// For enums, we want to add the signature as the underlying type so that we'll
// perform the conversions to and from the enum type.
pSignatures.Add(new UnaOpFullSig(
- pArgumentType.getAggregate().GetUnderlyingType(),
+ ((AggregateType)pArgumentType).OwningAggregate.GetUnderlyingType(),
null,
LiftFlags.None,
UnaOpFuncKind.None));
@@ -1319,7 +1359,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Debug.Assert(!(pArgumentType is PointerType));
// Check for user defined inc/dec
- ExprMultiGet exprGet = GetExprFactory().CreateMultiGet(0, pArgumentType, null);
+ ExprMultiGet exprGet = ExprFactory.CreateMultiGet(0, pArgumentType, null);
Expr exprVal = bindUDUnop((ExpressionKind)(exprKind - ExpressionKind.Add + ExpressionKind.Inc), exprGet);
if (exprVal != null)
@@ -1330,7 +1370,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
Debug.Assert(pArgument != null);
- ExprMulti exprMulti = GetExprFactory().CreateMulti(EXPRFLAG.EXF_ASSGOP | flags, pArgumentType, pArgument, exprVal);
+ ExprMulti exprMulti = ExprFactory.CreateMulti(EXPRFLAG.EXF_ASSGOP | flags, pArgumentType, pArgument, exprVal);
exprGet.OptionalMulti = exprMulti;
// Check whether Lvalue can be assigned.
@@ -1370,18 +1410,18 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
CType pArgumentType = pArgument.Type;
CType pRawType = pArgumentType.StripNubs();
- PredefinedType pt = pArgumentType.isPredefined() ? pArgumentType.getPredefType() : PredefinedType.PT_COUNT;
- PredefinedType ptRaw = pRawType.isPredefined() ? pRawType.getPredefType() : PredefinedType.PT_COUNT;
+ PredefinedType pt = pArgumentType.IsPredefined ? pArgumentType.PredefinedType : PredefinedType.PT_COUNT;
+ PredefinedType ptRaw = pRawType.IsPredefined ? pRawType.PredefinedType : PredefinedType.PT_COUNT;
- for (int index = 0; index < g_rguos.Length; index++)
+ for (int index = 0; index < s_rguos.Length; index++)
{
- UnaOpSig uos = g_rguos[index];
+ UnaOpSig uos = s_rguos[index];
if ((uos.grfuom & unaryOpMask) == 0)
{
continue;
}
- ConvKind cv = GetConvKind(pt, g_rguos[index].pt);
+ ConvKind cv = GetConvKind(pt, s_rguos[index].pt);
CType typeSig = null;
switch (cv)
@@ -1407,7 +1447,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
continue;
}
- typeSig = GetSymbolLoader().GetTypeManager().GetNullable(typeSig);
+ typeSig = TypeManager.GetNullable(typeSig);
if (!canConvert(pArgument, typeSig))
{
continue;
@@ -1423,7 +1463,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
continue;
}
- typeSig = GetSymbolLoader().GetTypeManager().GetNullable(typeSig);
+ typeSig = TypeManager.GetNullable(typeSig);
if (!canConvert(pArgument, typeSig))
{
continue;
@@ -1494,8 +1534,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
LiftArgument(arg, uofs.GetType(), uofs.Convert(), out Expr pArgument, out Expr nonLiftedArg);
// Now call the function with the non lifted arguments to report errors.
- Expr nonLiftedResult = uofs.pfn(ek, flags, nonLiftedArg);
- ExprUnaryOp exprRes = GetExprFactory().CreateUnaryOp(ek, type, pArgument);
+ Expr nonLiftedResult = uofs.pfn(this, ek, flags, nonLiftedArg);
+ ExprUnaryOp exprRes = ExprFactory.CreateUnaryOp(ek, type, pArgument);
mustCast(nonLiftedResult, type, 0);
exprRes.Flags |= flags;
@@ -1536,40 +1576,40 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
/*
Handles standard binary integer based operators.
*/
- private ExprOperator BindIntBinOp(ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2)
+ private static ExprOperator BindIntBinOp(ExpressionBinder binder, ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2)
{
- Debug.Assert(arg1.Type.isPredefined() && arg2.Type.isPredefined() && arg1.Type.getPredefType() == arg2.Type.getPredefType());
- return BindIntOp(ek, flags, arg1, arg2, arg1.Type.getPredefType());
+ Debug.Assert(arg1.Type.IsPredefined && arg2.Type.IsPredefined && arg1.Type.PredefinedType == arg2.Type.PredefinedType);
+ return binder.BindIntOp(ek, flags, arg1, arg2, arg1.Type.PredefinedType);
}
/*
Handles standard unary integer based operators.
*/
- private ExprOperator BindIntUnaOp(ExpressionKind ek, EXPRFLAG flags, Expr arg)
+ private static ExprOperator BindIntUnaOp(ExpressionBinder binder, ExpressionKind ek, EXPRFLAG flags, Expr arg)
{
- Debug.Assert(arg.Type.isPredefined());
- return BindIntOp(ek, flags, arg, null, arg.Type.getPredefType());
+ Debug.Assert(arg.Type.IsPredefined);
+ return binder.BindIntOp(ek, flags, arg, null, arg.Type.PredefinedType);
}
/*
Handles standard binary floating point (float, double) based operators.
*/
- private ExprOperator BindRealBinOp(ExpressionKind ek, EXPRFLAG _, Expr arg1, Expr arg2)
+ private static ExprOperator BindRealBinOp(ExpressionBinder binder, ExpressionKind ek, EXPRFLAG _, Expr arg1, Expr arg2)
{
- Debug.Assert(arg1.Type.isPredefined() && arg2.Type.isPredefined() && arg1.Type.getPredefType() == arg2.Type.getPredefType());
- return bindFloatOp(ek, arg1, arg2);
+ Debug.Assert(arg1.Type.IsPredefined && arg2.Type.IsPredefined && arg1.Type.PredefinedType == arg2.Type.PredefinedType);
+ return BindFloatOp(ek, arg1, arg2);
}
/*
Handles standard unary floating point (float, double) based operators.
*/
- private ExprOperator BindRealUnaOp(ExpressionKind ek, EXPRFLAG _, Expr arg)
+ private static ExprOperator BindRealUnaOp(ExpressionBinder binder, ExpressionKind ek, EXPRFLAG _, Expr arg)
{
- Debug.Assert(arg.Type.isPredefined());
- return bindFloatOp(ek, arg, null);
+ Debug.Assert(arg.Type.IsPredefined);
+ return BindFloatOp(ek, arg, null);
}
@@ -1583,7 +1623,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
CheckLvalue(arg, CheckLvalueKind.Increment);
CType typeRaw = uofs.GetType().StripNubs();
- FUNDTYPE ft = typeRaw.fundType();
+ FUNDTYPE ft = typeRaw.FundamentalType;
if (ft == FUNDTYPE.FT_R8 || ft == FUNDTYPE.FT_R4)
{
flags &= ~EXPRFLAG.EXF_CHECKOVERFLOW;
@@ -1604,17 +1644,17 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Debug.Assert(ek == ExpressionKind.Add || ek == ExpressionKind.Subtract);
ConstVal cv;
- if (type.isEnumType() && type.fundType() > FUNDTYPE.FT_LASTINTEGRAL)
+ if (type.IsEnumType && type.FundamentalType > FUNDTYPE.FT_LASTINTEGRAL)
{
// This is an error case when enum derives from an illegal type. Just treat it as an int.
type = GetPredefindType(PredefinedType.PT_INT);
}
- Debug.Assert(type.fundType() != FUNDTYPE.FT_PTR); // Can't have a pointer.
- switch (type.fundType())
+ Debug.Assert(type.FundamentalType != FUNDTYPE.FT_PTR); // Can't have a pointer.
+ switch (type.FundamentalType)
{
default:
- Debug.Assert(type.isPredefType(PredefinedType.PT_DECIMAL));
+ Debug.Assert(type.IsPredefType(PredefinedType.PT_DECIMAL));
PREDEFMETH predefMeth;
if (ek == ExpressionKind.Add)
{
@@ -1659,12 +1699,12 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
private Expr LScalar(ExpressionKind ek, EXPRFLAG flags, Expr exprVal, CType type, ConstVal cv, CType typeTmp)
{
CType typeOne = type;
- if (typeOne.isEnumType())
+ if (typeOne.IsEnumType)
{
- typeOne = typeOne.underlyingEnumType();
+ typeOne = typeOne.UnderlyingEnumType;
}
- ExprBinOp pExprResult = GetExprFactory().CreateBinop(ek, typeTmp, exprVal, GetExprFactory().CreateConstant(typeOne, cv));
+ ExprBinOp pExprResult = ExprFactory.CreateBinop(ek, typeTmp, exprVal, ExprFactory.CreateConstant(typeOne, cv));
pExprResult.Flags |= flags;
return typeTmp != type ? mustCast(pExprResult, type, CONVERTTYPE.NOUDC) : pExprResult;
}
@@ -1675,7 +1715,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Debug.Assert(!uofs.isLifted());
Debug.Assert(arg != null);
- ExprMultiGet exprGet = GetExprFactory().CreateMultiGet(EXPRFLAG.EXF_ASSGOP, arg.Type, null);
+ ExprMultiGet exprGet = ExprFactory.CreateMultiGet(EXPRFLAG.EXF_ASSGOP, arg.Type, null);
Expr exprVal = exprGet;
CType type = uofs.GetType();
Debug.Assert(!(type is NullableType));
@@ -1690,7 +1730,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
exprVal = BindIncOpCore(ek, flags, exprVal, type);
Expr op = mustCast(exprVal, arg.Type, CONVERTTYPE.NOUDC);
- ExprMulti exprMulti = GetExprFactory().CreateMulti(EXPRFLAG.EXF_ASSGOP | flags, arg.Type, arg, op);
+ ExprMulti exprMulti = ExprFactory.CreateMulti(EXPRFLAG.EXF_ASSGOP | flags, arg.Type, arg, op);
exprGet.OptionalMulti = exprMulti;
return exprMulti;
}
@@ -1703,21 +1743,21 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
NullableType type = uofs.GetType() as NullableType;
Debug.Assert(arg != null);
- ExprMultiGet exprGet = GetExprFactory().CreateMultiGet(EXPRFLAG.EXF_ASSGOP, arg.Type, null);
+ ExprMultiGet exprGet = ExprFactory.CreateMultiGet(EXPRFLAG.EXF_ASSGOP, arg.Type, null);
Expr exprVal = exprGet;
Expr nonLiftedArg = exprVal;
// We want to give the lifted argument as the binop, but use the non-lifted argument as the
// argument of the call.
//Debug.Assert(uofs.LiftArg() || type.IsValType());
- nonLiftedArg = mustCast(nonLiftedArg, type.GetUnderlyingType());
- Expr nonLiftedResult = BindIncOpCore(ek, flags, nonLiftedArg, type.GetUnderlyingType());
+ nonLiftedArg = mustCast(nonLiftedArg, type.UnderlyingType);
+ Expr nonLiftedResult = BindIncOpCore(ek, flags, nonLiftedArg, type.UnderlyingType);
exprVal = mustCast(exprVal, type);
- ExprUnaryOp exprRes = GetExprFactory().CreateUnaryOp((ek == ExpressionKind.Add) ? ExpressionKind.Inc : ExpressionKind.Dec, arg.Type/* type */, exprVal);
+ ExprUnaryOp exprRes = ExprFactory.CreateUnaryOp((ek == ExpressionKind.Add) ? ExpressionKind.Inc : ExpressionKind.Dec, arg.Type/* type */, exprVal);
mustCast(mustCast(nonLiftedResult, type), arg.Type);
exprRes.Flags |= flags;
- ExprMulti exprMulti = GetExprFactory().CreateMulti(EXPRFLAG.EXF_ASSGOP | flags, arg.Type, arg, exprRes);
+ ExprMulti exprMulti = ExprFactory.CreateMulti(EXPRFLAG.EXF_ASSGOP | flags, arg.Type, arg, exprRes);
exprGet.OptionalMulti = exprMulti;
return exprMulti;
}
@@ -1727,9 +1767,9 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
This function is called twice by the EE for every binary operator it evaluates
Here is how it works.
*/
- private ExprBinOp BindDecBinOp(ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2)
+ private static ExprBinOp BindDecBinOp(ExpressionBinder _, ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2)
{
- Debug.Assert(arg1.Type.isPredefType(PredefinedType.PT_DECIMAL) && arg2.Type.isPredefType(PredefinedType.PT_DECIMAL));
+ Debug.Assert(arg1.Type.IsPredefType(PredefinedType.PT_DECIMAL) && arg2.Type.IsPredefType(PredefinedType.PT_DECIMAL));
CType typeDec = GetPredefindType(PredefinedType.PT_DECIMAL);
Debug.Assert(typeDec != null);
@@ -1759,16 +1799,16 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
break;
}
- return GetExprFactory().CreateBinop(ek, typeRet, arg1, arg2);
+ return ExprFactory.CreateBinop(ek, typeRet, arg1, arg2);
}
/*
Handles standard unary decimal based operators.
*/
- private ExprUnaryOp BindDecUnaOp(ExpressionKind ek, EXPRFLAG flags, Expr arg)
+ private static ExprUnaryOp BindDecUnaOp(ExpressionBinder _, ExpressionKind ek, EXPRFLAG flags, Expr arg)
{
- Debug.Assert(arg.Type.isPredefType(PredefinedType.PT_DECIMAL));
+ Debug.Assert(arg.Type.IsPredefType(PredefinedType.PT_DECIMAL));
Debug.Assert(ek == ExpressionKind.Negate || ek == ExpressionKind.UnaryPlus);
CType typeDec = GetPredefindType(PredefinedType.PT_DECIMAL);
@@ -1779,18 +1819,18 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
PREDEFMETH predefMeth = PREDEFMETH.PM_DECIMAL_OPUNARYMINUS;
return CreateUnaryOpForPredefMethodCall(ExpressionKind.DecimalNegate, predefMeth, typeDec, arg);
}
- return GetExprFactory().CreateUnaryOp(ExpressionKind.UnaryPlus, typeDec, arg);
+ return ExprFactory.CreateUnaryOp(ExpressionKind.UnaryPlus, typeDec, arg);
}
/*
Handles string concatenation.
*/
- private Expr BindStrBinOp(ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2)
+ private static Expr BindStrBinOp(ExpressionBinder _, ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2)
{
Debug.Assert(ek == ExpressionKind.Add);
- Debug.Assert(arg1.Type.isPredefType(PredefinedType.PT_STRING) || arg2.Type.isPredefType(PredefinedType.PT_STRING));
- return bindStringConcat(arg1, arg2);
+ Debug.Assert(arg1.Type.IsPredefType(PredefinedType.PT_STRING) || arg2.Type.IsPredefType(PredefinedType.PT_STRING));
+ return BindStringConcat(arg1, arg2);
}
@@ -1798,55 +1838,55 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Bind a shift operator: <<, >>. These can have integer or long first operands,
and second operand must be int.
*/
- private ExprBinOp BindShiftOp(ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2)
+ private static ExprBinOp BindShiftOp(ExpressionBinder _, ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2)
{
Debug.Assert(ek == ExpressionKind.LeftShirt || ek == ExpressionKind.RightShift);
- Debug.Assert(arg1.Type.isPredefined());
- Debug.Assert(arg2.Type.isPredefType(PredefinedType.PT_INT));
+ Debug.Assert(arg1.Type.IsPredefined);
+ Debug.Assert(arg2.Type.IsPredefType(PredefinedType.PT_INT));
- PredefinedType ptOp = arg1.Type.getPredefType();
+ PredefinedType ptOp = arg1.Type.PredefinedType;
Debug.Assert(ptOp == PredefinedType.PT_INT || ptOp == PredefinedType.PT_UINT || ptOp == PredefinedType.PT_LONG || ptOp == PredefinedType.PT_ULONG);
- return GetExprFactory().CreateBinop(ek, arg1.Type, arg1, arg2);
+ return ExprFactory.CreateBinop(ek, arg1.Type, arg1, arg2);
}
/*
Bind a bool binary operator: ==, !=, &&, ||, , |, ^. If both operands are constant, the
result will be a constant also.
*/
- private ExprBinOp BindBoolBinOp(ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2)
+ private static ExprBinOp BindBoolBinOp(ExpressionBinder _, ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2)
{
Debug.Assert(arg1 != null);
Debug.Assert(arg2 != null);
- Debug.Assert(arg1.Type.isPredefType(PredefinedType.PT_BOOL) || (arg1.Type is NullableType argNubType1 && argNubType1.GetUnderlyingType().isPredefType(PredefinedType.PT_BOOL)));
- Debug.Assert(arg2.Type.isPredefType(PredefinedType.PT_BOOL) || (arg2.Type is NullableType argNubType2 && argNubType2.GetUnderlyingType().isPredefType(PredefinedType.PT_BOOL)));
+ Debug.Assert(arg1.Type.IsPredefType(PredefinedType.PT_BOOL) || arg1.Type is NullableType argNubType1 && argNubType1.UnderlyingType.IsPredefType(PredefinedType.PT_BOOL));
+ Debug.Assert(arg2.Type.IsPredefType(PredefinedType.PT_BOOL) || arg2.Type is NullableType argNubType2 && argNubType2.UnderlyingType.IsPredefType(PredefinedType.PT_BOOL));
- return GetExprFactory().CreateBinop(ek, GetPredefindType(PredefinedType.PT_BOOL), arg1, arg2);
+ return ExprFactory.CreateBinop(ek, GetPredefindType(PredefinedType.PT_BOOL), arg1, arg2);
}
- private ExprOperator BindBoolBitwiseOp(ExpressionKind ek, EXPRFLAG flags, Expr expr1, Expr expr2, BinOpFullSig bofs)
+ private ExprOperator BindBoolBitwiseOp(ExpressionKind ek, EXPRFLAG flags, Expr expr1, Expr expr2)
{
Debug.Assert(ek == ExpressionKind.BitwiseAnd || ek == ExpressionKind.BitwiseOr);
- Debug.Assert(expr1.Type.isPredefType(PredefinedType.PT_BOOL) || expr1.Type is NullableType expNubType1 && expNubType1.GetUnderlyingType().isPredefType(PredefinedType.PT_BOOL));
- Debug.Assert(expr2.Type.isPredefType(PredefinedType.PT_BOOL) || expr2.Type is NullableType expNubType2 && expNubType2.GetUnderlyingType().isPredefType(PredefinedType.PT_BOOL));
+ Debug.Assert(expr1.Type.IsPredefType(PredefinedType.PT_BOOL) || expr1.Type is NullableType expNubType1 && expNubType1.UnderlyingType.IsPredefType(PredefinedType.PT_BOOL));
+ Debug.Assert(expr2.Type.IsPredefType(PredefinedType.PT_BOOL) || expr2.Type is NullableType expNubType2 && expNubType2.UnderlyingType.IsPredefType(PredefinedType.PT_BOOL));
if (expr1.Type is NullableType || expr2.Type is NullableType)
{
CType typeBool = GetPredefindType(PredefinedType.PT_BOOL);
- CType typeRes = GetSymbolLoader().GetTypeManager().GetNullable(typeBool);
+ CType typeRes = TypeManager.GetNullable(typeBool);
// Get the non-lifted result.
- Expr nonLiftedArg1 = CNullable.StripNullableConstructor(expr1);
- Expr nonLiftedArg2 = CNullable.StripNullableConstructor(expr2);
+ Expr nonLiftedArg1 = StripNullableConstructor(expr1);
+ Expr nonLiftedArg2 = StripNullableConstructor(expr2);
Expr nonLiftedResult = null;
if (!(nonLiftedArg1.Type is NullableType) && !(nonLiftedArg2.Type is NullableType))
{
- nonLiftedResult = BindBoolBinOp(ek, flags, nonLiftedArg1, nonLiftedArg2);
+ nonLiftedResult = BindBoolBinOp(this, ek, flags, nonLiftedArg1, nonLiftedArg2);
}
// Make the binop and set that its lifted.
- ExprBinOp exprRes = GetExprFactory().CreateBinop(ek, typeRes, expr1, expr2);
+ ExprBinOp exprRes = ExprFactory.CreateBinop(ek, typeRes, expr1, expr2);
if (nonLiftedResult != null)
{
// Bitwise operators can have null non-lifted results if we have a nub sym somewhere.
@@ -1857,21 +1897,18 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Debug.Assert((exprRes.Flags & EXPRFLAG.EXF_LVALUE) == 0);
return exprRes;
}
- return BindBoolBinOp(ek, flags, expr1, expr2);
- }
- private Expr BindLiftedBoolBitwiseOp(ExpressionKind ek, EXPRFLAG flags, Expr expr1, Expr expr2)
- {
- return null;
+ return BindBoolBinOp(this, ek, flags, expr1, expr2);
}
+ private static Expr BindLiftedBoolBitwiseOp(ExpressionBinder _, ExpressionKind ek, EXPRFLAG flags, Expr expr1, Expr expr2) => null;
/*
Handles boolean unary operator (!).
*/
- private Expr BindBoolUnaOp(ExpressionKind ek, EXPRFLAG flags, Expr arg)
+ private static Expr BindBoolUnaOp(ExpressionBinder _, ExpressionKind ek, EXPRFLAG flags, Expr arg)
{
- Debug.Assert(arg.Type.isPredefType(PredefinedType.PT_BOOL));
+ Debug.Assert(arg.Type.IsPredefType(PredefinedType.PT_BOOL));
Debug.Assert(ek == ExpressionKind.LogicalNot);
// Get the result type and operand type.
@@ -1883,19 +1920,19 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Expr argConst = arg.GetConst();
if (argConst == null)
- return GetExprFactory().CreateUnaryOp(ExpressionKind.LogicalNot, typeBool, arg);
+ return ExprFactory.CreateUnaryOp(ExpressionKind.LogicalNot, typeBool, arg);
- return GetExprFactory().CreateConstant(typeBool, ConstVal.Get(((ExprConstant)argConst).Val.Int32Val == 0));
+ return ExprFactory.CreateConstant(typeBool, ConstVal.Get(((ExprConstant)argConst).Val.Int32Val == 0));
}
/*
Handles string equality.
*/
- private ExprBinOp BindStrCmpOp(ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2)
+ private static ExprBinOp BindStrCmpOp(ExpressionBinder _, ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2)
{
Debug.Assert(ek == ExpressionKind.Eq || ek == ExpressionKind.NotEq);
- Debug.Assert(arg1.Type.isPredefType(PredefinedType.PT_STRING) && arg2.Type.isPredefType(PredefinedType.PT_STRING));
+ Debug.Assert(arg1.Type.IsPredefType(PredefinedType.PT_STRING) && arg2.Type.IsPredefType(PredefinedType.PT_STRING));
// Get the predefined method for string comparison, and then stash it in the Expr so we can
// transform it later.
@@ -1909,25 +1946,25 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
/*
Handles reference equality operators. Type variables come through here.
*/
- private ExprBinOp BindRefCmpOp(ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2)
+ private static ExprBinOp BindRefCmpOp(ExpressionBinder binder, ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2)
{
Debug.Assert(ek == ExpressionKind.Eq || ek == ExpressionKind.NotEq);
// Must box type variables for the verifier.
- arg1 = mustConvert(arg1, GetPredefindType(PredefinedType.PT_OBJECT), CONVERTTYPE.NOUDC);
- arg2 = mustConvert(arg2, GetPredefindType(PredefinedType.PT_OBJECT), CONVERTTYPE.NOUDC);
+ arg1 = binder.mustConvert(arg1, GetPredefindType(PredefinedType.PT_OBJECT), CONVERTTYPE.NOUDC);
+ arg2 = binder.mustConvert(arg2, GetPredefindType(PredefinedType.PT_OBJECT), CONVERTTYPE.NOUDC);
- return GetExprFactory().CreateBinop(ek, GetPredefindType(PredefinedType.PT_BOOL), arg1, arg2);
+ return ExprFactory.CreateBinop(ek, GetPredefindType(PredefinedType.PT_BOOL), arg1, arg2);
}
/*
Handles delegate binary operators.
*/
- private Expr BindDelBinOp(ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2)
+ private static Expr BindDelBinOp(ExpressionBinder _, ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2)
{
Debug.Assert(ek == ExpressionKind.Add || ek == ExpressionKind.Subtract || ek == ExpressionKind.Eq || ek == ExpressionKind.NotEq);
- Debug.Assert(arg1.Type == arg2.Type && (arg1.Type.isDelegateType() || arg1.Type.isPredefType(PredefinedType.PT_DELEGATE)));
+ Debug.Assert(arg1.Type == arg2.Type && (arg1.Type.IsDelegateType || arg1.Type.IsPredefType(PredefinedType.PT_DELEGATE)));
PREDEFMETH predefMeth = (PREDEFMETH)0;
CType RetType = null;
@@ -1964,14 +2001,14 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
/*
Handles enum binary operators.
*/
- private Expr BindEnumBinOp(ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2)
+ private static Expr BindEnumBinOp(ExpressionBinder binder, ExpressionKind ek, EXPRFLAG flags, Expr arg1, Expr arg2)
{
AggregateType typeDst = GetEnumBinOpType(ek, arg1.Type, arg2.Type, out AggregateType typeEnum);
Debug.Assert(typeEnum != null);
PredefinedType ptOp;
- switch (typeEnum.fundType())
+ switch (typeEnum.FundamentalType)
{
default:
// Promote all smaller types to int.
@@ -1989,15 +2026,15 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
CType typeOp = GetPredefindType(ptOp);
- arg1 = mustCast(arg1, typeOp, CONVERTTYPE.NOUDC);
- arg2 = mustCast(arg2, typeOp, CONVERTTYPE.NOUDC);
+ arg1 = binder.mustCast(arg1, typeOp, CONVERTTYPE.NOUDC);
+ arg2 = binder.mustCast(arg2, typeOp, CONVERTTYPE.NOUDC);
- Expr exprRes = BindIntOp(ek, flags, arg1, arg2, ptOp);
+ Expr exprRes = binder.BindIntOp(ek, flags, arg1, arg2, ptOp);
if (exprRes.Type != typeDst)
{
- Debug.Assert(!typeDst.isPredefType(PredefinedType.PT_BOOL));
- exprRes = mustCast(exprRes, typeDst, CONVERTTYPE.NOUDC);
+ Debug.Assert(!typeDst.IsPredefType(PredefinedType.PT_BOOL));
+ exprRes = binder.mustCast(exprRes, typeDst, CONVERTTYPE.NOUDC);
}
return exprRes;
@@ -2010,20 +2047,19 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
CType nonNullableType2 = arg2.Type is NullableType arg2NubType ? arg2NubType.UnderlyingType : arg2.Type;
if (nonNullableType1 is NullType)
{
- nonNullableType1 = nonNullableType2.underlyingEnumType();
+ nonNullableType1 = nonNullableType2.UnderlyingEnumType;
}
else if (nonNullableType2 is NullType)
{
- nonNullableType2 = nonNullableType1.underlyingEnumType();
+ nonNullableType2 = nonNullableType1.UnderlyingEnumType;
}
- AggregateType typeEnum;
- NullableType typeDst = GetTypes().GetNullable(GetEnumBinOpType(ek, nonNullableType1, nonNullableType2, out typeEnum));
+ NullableType typeDst = TypeManager.GetNullable(GetEnumBinOpType(ek, nonNullableType1, nonNullableType2, out AggregateType typeEnum));
Debug.Assert(typeEnum != null);
PredefinedType ptOp;
- switch (typeEnum.fundType())
+ switch (typeEnum.FundamentalType)
{
default:
// Promote all smaller types to int.
@@ -2040,11 +2076,11 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
break;
}
- NullableType typeOp = GetTypes().GetNullable(GetPredefindType(ptOp));
+ NullableType typeOp = TypeManager.GetNullable(GetPredefindType(ptOp));
arg1 = mustCast(arg1, typeOp, CONVERTTYPE.NOUDC);
arg2 = mustCast(arg2, typeOp, CONVERTTYPE.NOUDC);
- ExprBinOp exprRes = GetExprFactory().CreateBinop(ek, typeOp, arg1, arg2);
+ ExprBinOp exprRes = ExprFactory.CreateBinop(ek, typeOp, arg1, arg2);
exprRes.IsLifted = true;
exprRes.Flags |= flags;
Debug.Assert((exprRes.Flags & EXPRFLAG.EXF_LVALUE) == 0);
@@ -2061,16 +2097,16 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
/*
Handles enum unary operator (~).
*/
- private Expr BindEnumUnaOp(ExpressionKind ek, EXPRFLAG flags, Expr arg)
+ private static Expr BindEnumUnaOp(ExpressionBinder binder, ExpressionKind ek, EXPRFLAG flags, Expr arg)
{
Debug.Assert(ek == ExpressionKind.BitwiseNot);
Debug.Assert((ExprCast)arg != null);
- Debug.Assert(((ExprCast)arg).Argument.Type.isEnumType());
+ Debug.Assert(((ExprCast)arg).Argument.Type.IsEnumType);
PredefinedType ptOp;
CType typeEnum = ((ExprCast)arg).Argument.Type;
- switch (typeEnum.fundType())
+ switch (typeEnum.FundamentalType)
{
default:
// Promote all smaller types to int.
@@ -2088,10 +2124,10 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
CType typeOp = GetPredefindType(ptOp);
- arg = mustCast(arg, typeOp, CONVERTTYPE.NOUDC);
+ arg = binder.mustCast(arg, typeOp, CONVERTTYPE.NOUDC);
- Expr exprRes = BindIntOp(ek, flags, arg, null, ptOp);
- return mustCastInUncheckedContext(exprRes, typeEnum, CONVERTTYPE.NOUDC);
+ Expr exprRes = binder.BindIntOp(ek, flags, arg, null, ptOp);
+ return binder.MustCastInUncheckedContext(exprRes, typeEnum, CONVERTTYPE.NOUDC);
}
/*
@@ -2189,7 +2225,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
CType typeDest = kind.IsRelational() ? GetPredefindType(PredefinedType.PT_BOOL) : typeOp;
- ExprOperator exprRes = GetExprFactory().CreateOperator(kind, typeDest, op1, op2);
+ ExprOperator exprRes = ExprFactory.CreateOperator(kind, typeDest, op1, op2);
exprRes.Flags |= flags;
Debug.Assert((exprRes.Flags & EXPRFLAG.EXF_LVALUE) == 0);
return exprRes;
@@ -2237,12 +2273,12 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
throw BadOperatorTypesError(op, null);
}
- if (ptOp == PredefinedType.PT_UINT && op.Type.fundType() == FUNDTYPE.FT_U4)
+ if (ptOp == PredefinedType.PT_UINT && op.Type.FundamentalType == FUNDTYPE.FT_U4)
{
op = mustConvertCore(op, GetPredefindType(PredefinedType.PT_LONG), CONVERTTYPE.NOUDC);
}
- ExprOperator exprRes = GetExprFactory().CreateNeg(flags, op);
+ ExprOperator exprRes = ExprFactory.CreateNeg(flags, op);
Debug.Assert(0 == (exprRes.Flags & EXPRFLAG.EXF_LVALUE));
return exprRes;
}
@@ -2252,22 +2288,22 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
will be a constant also. op2 can be null for a unary operator. The operands are assumed
to be already converted to the correct type.
*/
- private ExprOperator bindFloatOp(ExpressionKind kind, Expr op1, Expr op2)
+ private static ExprOperator BindFloatOp(ExpressionKind kind, Expr op1, Expr op2)
{
//Debug.Assert(kind.isRelational() || kind.isArithmetic());
Debug.Assert(op2 == null || op1.Type == op2.Type);
- Debug.Assert(op1.Type.isPredefType(PredefinedType.PT_FLOAT) || op1.Type.isPredefType(PredefinedType.PT_DOUBLE));
+ Debug.Assert(op1.Type.IsPredefType(PredefinedType.PT_FLOAT) || op1.Type.IsPredefType(PredefinedType.PT_DOUBLE));
// Allocate the result expression.
CType typeDest = kind.IsRelational() ? GetPredefindType(PredefinedType.PT_BOOL) : op1.Type;
- ExprOperator exprRes = GetExprFactory().CreateOperator(kind, typeDest, op1, op2);
+ ExprOperator exprRes = ExprFactory.CreateOperator(kind, typeDest, op1, op2);
exprRes.Flags &= ~EXPRFLAG.EXF_CHECKOVERFLOW;
return exprRes;
}
- private ExprConcat bindStringConcat(Expr op1, Expr op2)
+ private static ExprConcat BindStringConcat(Expr op1, Expr op2)
{
// If the concatenation consists solely of two constants then we must
// realize the concatenation into a single constant node at this time.
@@ -2287,13 +2323,13 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Debug.Assert(op1 != null);
Debug.Assert(op2 != null);
- return GetExprFactory().CreateConcat(op1, op2);
+ return ExprFactory.CreateConcat(op1, op2);
}
/*
Report an ambiguous operator types error.
*/
- private RuntimeBinderException AmbiguousOperatorError(ExpressionKind ek, Expr op1, Expr op2)
+ private static RuntimeBinderException AmbiguousOperatorError(Expr op1, Expr op2)
{
Debug.Assert(op1 != null);
@@ -2303,8 +2339,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// Bad arg types - report error to user.
return op2 != null
- ? GetErrorContext().Error(ErrorCode.ERR_AmbigBinaryOps, strOp, op1.Type, op2.Type)
- : GetErrorContext().Error(ErrorCode.ERR_AmbigUnaryOp, strOp, op1.Type);
+ ? ErrorHandling.Error(ErrorCode.ERR_AmbigBinaryOps, strOp, op1.Type, op2.Type)
+ : ErrorHandling.Error(ErrorCode.ERR_AmbigUnaryOp, strOp, op1.Type);
}
private Expr BindUserBoolOp(ExpressionKind kind, ExprCall pCall)
@@ -2317,10 +2353,10 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
CType typeRet = pCall.Type;
Debug.Assert(pCall.MethWithInst.Meth().Params.Count == 2);
- if (!GetTypes().SubstEqualTypes(typeRet, pCall.MethWithInst.Meth().Params[0], typeRet) ||
- !GetTypes().SubstEqualTypes(typeRet, pCall.MethWithInst.Meth().Params[1], typeRet))
+ if (!TypeManager.SubstEqualTypes(typeRet, pCall.MethWithInst.Meth().Params[0], typeRet) ||
+ !TypeManager.SubstEqualTypes(typeRet, pCall.MethWithInst.Meth().Params[1], typeRet))
{
- throw GetErrorContext().Error(ErrorCode.ERR_BadBoolOp, pCall.MethWithInst);
+ throw ErrorHandling.Error(ErrorCode.ERR_BadBoolOp, pCall.MethWithInst);
}
ExprList list = (ExprList)pCall.OptionalArguments;
@@ -2331,45 +2367,38 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
list.OptionalElement = pExprWrap;
// Reflection load the true and false methods.
- SymbolLoader.RuntimeBinderSymbolTable.PopulateSymbolTableWithName(SpecialNames.CLR_True, null, pExprWrap.Type.AssociatedSystemType);
- SymbolLoader.RuntimeBinderSymbolTable.PopulateSymbolTableWithName(SpecialNames.CLR_False, null, pExprWrap.Type.AssociatedSystemType);
+ SymbolTable.PopulateSymbolTableWithName(SpecialNames.CLR_True, null, pExprWrap.Type.AssociatedSystemType);
+ SymbolTable.PopulateSymbolTableWithName(SpecialNames.CLR_False, null, pExprWrap.Type.AssociatedSystemType);
Expr pCallT = bindUDUnop(ExpressionKind.True, pExprWrap);
Expr pCallF = bindUDUnop(ExpressionKind.False, pExprWrap);
if (pCallT == null || pCallF == null)
{
- throw GetErrorContext().Error(ErrorCode.ERR_MustHaveOpTF, typeRet);
+ throw ErrorHandling.Error(ErrorCode.ERR_MustHaveOpTF, typeRet);
}
pCallT = mustConvert(pCallT, GetPredefindType(PredefinedType.PT_BOOL));
pCallF = mustConvert(pCallF, GetPredefindType(PredefinedType.PT_BOOL));
- return GetExprFactory().CreateUserLogOp(typeRet, kind == ExpressionKind.LogicalAnd ? pCallF : pCallT, pCall);
+ return ExprFactory.CreateUserLogOp(typeRet, kind == ExpressionKind.LogicalAnd ? pCallF : pCallT, pCall);
}
- private AggregateType GetUserDefinedBinopArgumentType(CType type)
+ private static AggregateType GetUserDefinedBinopArgumentType(CType type)
{
- for (; ;)
+ if (type is NullableType nt)
{
- switch (type.GetTypeKind())
- {
- case TypeKind.TK_NullableType:
- type = type.StripNubs();
- break;
- case TypeKind.TK_AggregateType:
- AggregateType ats = (AggregateType)type;
- if ((ats.isClassType() || ats.isStructType()) && !ats.getAggregate().IsSkipUDOps())
- {
- return ats;
- }
- return null;
- default:
- return null;
- }
+ type = nt.UnderlyingType;
+ }
+
+ if (type is AggregateType ats && (ats.IsClassType || ats.IsStructType) && !ats.OwningAggregate.IsSkipUDOps())
+ {
+ return ats;
}
+
+ return null;
}
- private int GetUserDefinedBinopArgumentTypes(CType type1, CType type2, AggregateType[] rgats)
+ private static int GetUserDefinedBinopArgumentTypes(CType type1, CType type2, AggregateType[] rgats)
{
int cats = 0;
rgats[0] = GetUserDefinedBinopArgumentType(type1);
@@ -2390,27 +2419,25 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return cats;
}
- private bool UserDefinedBinaryOperatorCanBeLifted(ExpressionKind ek, MethodSymbol method, AggregateType ats,
+ private static bool UserDefinedBinaryOperatorCanBeLifted(ExpressionKind ek, MethodSymbol method, AggregateType ats,
TypeArray Params)
{
- if (!Params[0].IsNonNubValType())
- {
- return false;
- }
- if (!Params[1].IsNonNubValType())
+ if (!Params[0].IsNonNullableValueType || !Params[1].IsNonNullableValueType)
{
return false;
}
- CType typeRet = GetTypes().SubstType(method.RetType, ats);
- if (!typeRet.IsNonNubValType())
+
+ CType typeRet = TypeManager.SubstType(method.RetType, ats);
+ if (!typeRet.IsNonNullableValueType)
{
return false;
}
+
switch (ek)
{
case ExpressionKind.Eq:
case ExpressionKind.NotEq:
- if (!typeRet.isPredefType(PredefinedType.PT_BOOL))
+ if (!typeRet.IsPredefType(PredefinedType.PT_BOOL))
{
return false;
}
@@ -2423,7 +2450,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
case ExpressionKind.GreaterThanOrEqual:
case ExpressionKind.LessThan:
case ExpressionKind.LessThanOrEqual:
- if (!typeRet.isPredefType(PredefinedType.PT_BOOL))
+ if (!typeRet.IsPredefType(PredefinedType.PT_BOOL))
{
return false;
}
@@ -2443,11 +2470,11 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return false;
}
Debug.Assert(method.typeVars.Count == 0);
- TypeArray paramsCur = GetTypes().SubstTypeArray(method.Params, ats);
+ TypeArray paramsCur = TypeManager.SubstTypeArray(method.Params, ats);
if (canConvert(arg1, paramsCur[0]) && canConvert(arg2, paramsCur[1]))
{
candidateList.Add(new CandidateFunctionMember(
- new MethPropWithInst(method, ats, BSYMMGR.EmptyTypeArray()),
+ new MethPropWithInst(method, ats, TypeArray.Empty),
paramsCur,
0, // No lifted arguments
false));
@@ -2458,15 +2485,15 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return false;
}
CType[] rgtype = new CType[2];
- rgtype[0] = GetTypes().GetNullable(paramsCur[0]);
- rgtype[1] = GetTypes().GetNullable(paramsCur[1]);
+ rgtype[0] = TypeManager.GetNullable(paramsCur[0]);
+ rgtype[1] = TypeManager.GetNullable(paramsCur[1]);
if (!canConvert(arg1, rgtype[0]) || !canConvert(arg2, rgtype[1]))
{
return false;
}
candidateList.Add(new CandidateFunctionMember(
- new MethPropWithInst(method, ats, BSYMMGR.EmptyTypeArray()),
- GetGlobalSymbols().AllocParams(2, rgtype),
+ new MethPropWithInst(method, ats, TypeArray.Empty),
+ TypeArray.Allocate(rgtype),
2, // two lifted arguments
false));
return true;
@@ -2476,12 +2503,12 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
List<CandidateFunctionMember> candidateList, ExpressionKind ek, AggregateType type,
Expr arg1, Expr arg2, bool fDontLift)
{
- Name name = ekName(ek);
+ Name name = ExpressionKindName(ek);
Debug.Assert(name != null);
bool foundSome = false;
- for (MethodSymbol methCur = GetSymbolLoader().LookupAggMember(name, type.getAggregate(), symbmask_t.MASK_MethodSymbol) as MethodSymbol;
+ for (MethodSymbol methCur = SymbolLoader.LookupAggMember(name, type.OwningAggregate, symbmask_t.MASK_MethodSymbol) as MethodSymbol;
methCur != null;
- methCur = SymbolLoader.LookupNextSym(methCur, type.getAggregate(), symbmask_t.MASK_MethodSymbol) as MethodSymbol)
+ methCur = methCur.LookupNext(symbmask_t.MASK_MethodSymbol) as MethodSymbol)
{
if (UserDefinedBinaryOperatorIsApplicable(candidateList, ek, methCur, type, arg1, arg2, fDontLift))
{
@@ -2495,13 +2522,14 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
List<CandidateFunctionMember> candidateList, ExpressionKind ek, AggregateType type,
Expr arg1, Expr arg2, bool fDontLift, AggregateType atsStop)
{
- for (AggregateType atsCur = type; atsCur != null && atsCur != atsStop; atsCur = atsCur.GetBaseClass())
+ for (AggregateType atsCur = type; atsCur != null && atsCur != atsStop; atsCur = atsCur.BaseClass)
{
if (GetApplicableUserDefinedBinaryOperatorCandidates(candidateList, ek, atsCur, arg1, arg2, fDontLift))
{
return atsCur;
}
}
+
return null;
}
@@ -2535,7 +2563,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return null;
}
- ExprList args = GetExprFactory().CreateList(arg1, arg2);
+ ExprList args = ExprFactory.CreateList(arg1, arg2);
ArgInfos info = new ArgInfos();
info.carg = 2;
FillInArgInfoFromArgList(info, args);
@@ -2546,7 +2574,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (pmethBest == null)
{
// No winner, so its an ambiguous call...
- throw GetErrorContext().Error(ErrorCode.ERR_AmbigCall, pmethAmbig1.mpwi, pmethAmbig2.mpwi);
+ throw ErrorHandling.Error(ErrorCode.ERR_AmbigCall, pmethAmbig1.mpwi, pmethAmbig2.mpwi);
}
ppmpwi = pmethBest.mpwi;
@@ -2558,7 +2586,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return BindLiftedUDBinop(ek, arg1, arg2, pmethBest.@params, pmethBest.mpwi);
}
- CType typeRetRaw = GetTypes().SubstType(pmethBest.mpwi.Meth().RetType, pmethBest.mpwi.GetType());
+ CType typeRetRaw = TypeManager.SubstType(pmethBest.mpwi.Meth().RetType, pmethBest.mpwi.GetType());
return BindUDBinopCall(arg1, arg2, pmethBest.@params, typeRetRaw, pmethBest.mpwi);
}
@@ -2567,15 +2595,15 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
arg1 = mustConvert(arg1, Params[0]);
arg2 = mustConvert(arg2, Params[1]);
- ExprList args = GetExprFactory().CreateList(arg1, arg2);
+ ExprList args = ExprFactory.CreateList(arg1, arg2);
- checkUnsafe(arg1.Type); // added to the binder so we don't bind to pointer ops
- checkUnsafe(arg2.Type); // added to the binder so we don't bind to pointer ops
- checkUnsafe(typeRet); // added to the binder so we don't bind to pointer ops
+ CheckUnsafe(arg1.Type); // added to the binder so we don't bind to pointer ops
+ CheckUnsafe(arg2.Type); // added to the binder so we don't bind to pointer ops
+ CheckUnsafe(typeRet); // added to the binder so we don't bind to pointer ops
- ExprMemberGroup pMemGroup = GetExprFactory().CreateMemGroup(null, mpwi);
- ExprCall call = GetExprFactory().CreateCall(0, typeRet, args, pMemGroup, null);
+ ExprMemberGroup pMemGroup = ExprFactory.CreateMemGroup(null, mpwi);
+ ExprCall call = ExprFactory.CreateCall(0, typeRet, args, pMemGroup, null);
call.MethWithInst = new MethWithInst(mpwi);
verifyMethodArgs(call, mpwi.GetType());
return call;
@@ -2586,7 +2614,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Expr exprVal1 = arg1;
Expr exprVal2 = arg2;
CType typeRet;
- CType typeRetRaw = GetTypes().SubstType(mpwi.Meth().RetType, mpwi.GetType());
+ CType typeRetRaw = TypeManager.SubstType(mpwi.Meth().RetType, mpwi.GetType());
// This is a lifted user defined operator. We know that both arguments
// go to the nullable formal parameter types, and that at least one
@@ -2598,10 +2626,10 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// argument to the nullable formal parameter type first, before we then
// do the cast for the non-nullable call.
- TypeArray paramsRaw = GetTypes().SubstTypeArray(mpwi.Meth().Params, mpwi.GetType());
+ TypeArray paramsRaw = TypeManager.SubstTypeArray(mpwi.Meth().Params, mpwi.GetType());
Debug.Assert(Params != paramsRaw);
- Debug.Assert(paramsRaw[0] == Params[0].GetBaseOrParameterOrElementType());
- Debug.Assert(paramsRaw[1] == Params[1].GetBaseOrParameterOrElementType());
+ Debug.Assert(paramsRaw[0] == Params[0].BaseOrParameterOrElementType);
+ Debug.Assert(paramsRaw[1] == Params[1].BaseOrParameterOrElementType);
if (!canConvert(arg1.Type.StripNubs(), paramsRaw[0], CONVERTTYPE.NOUDC))
{
@@ -2616,12 +2644,12 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
switch (ek)
{
default:
- typeRet = GetTypes().GetNullable(typeRetRaw);
+ typeRet = TypeManager.GetNullable(typeRetRaw);
break;
case ExpressionKind.Eq:
case ExpressionKind.NotEq:
Debug.Assert(paramsRaw[0] == paramsRaw[1]);
- Debug.Assert(typeRetRaw.isPredefType(PredefinedType.PT_BOOL));
+ Debug.Assert(typeRetRaw.IsPredefType(PredefinedType.PT_BOOL));
// These ones don't lift the return type. Instead, if either side is null, the result is false.
typeRet = typeRetRaw;
break;
@@ -2629,7 +2657,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
case ExpressionKind.GreaterThanOrEqual:
case ExpressionKind.LessThan:
case ExpressionKind.LessThanOrEqual:
- Debug.Assert(typeRetRaw.isPredefType(PredefinedType.PT_BOOL));
+ Debug.Assert(typeRetRaw.IsPredefType(PredefinedType.PT_BOOL));
// These ones don't lift the return type. Instead, if either side is null, the result is false.
typeRet = typeRetRaw;
break;
@@ -2641,9 +2669,9 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
ExprCall nonLiftedResult = BindUDBinopCall(nonLiftedArg1, nonLiftedArg2, paramsRaw, typeRetRaw, mpwi);
- ExprList args = GetExprFactory().CreateList(exprVal1, exprVal2);
- ExprMemberGroup pMemGroup = GetExprFactory().CreateMemGroup(null, mpwi);
- ExprCall call = GetExprFactory().CreateCall(0, typeRet, args, pMemGroup, null);
+ ExprList args = ExprFactory.CreateList(exprVal1, exprVal2);
+ ExprMemberGroup pMemGroup = ExprFactory.CreateMemGroup(null, mpwi);
+ ExprCall call = ExprFactory.CreateCall(0, typeRet, args, pMemGroup, null);
call.MethWithInst = new MethWithInst(mpwi);
switch (ek)
@@ -2665,17 +2693,17 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return call;
}
- private AggregateType GetEnumBinOpType(ExpressionKind ek, CType argType1, CType argType2, out AggregateType ppEnumType)
+ private static AggregateType GetEnumBinOpType(ExpressionKind ek, CType argType1, CType argType2, out AggregateType ppEnumType)
{
- Debug.Assert(argType1.isEnumType() || argType2.isEnumType());
+ Debug.Assert(argType1.IsEnumType || argType2.IsEnumType);
AggregateType type1 = argType1 as AggregateType;
AggregateType type2 = argType2 as AggregateType;
- AggregateType typeEnum = type1.isEnumType() ? type1 : type2;
+ AggregateType typeEnum = type1.IsEnumType ? type1 : type2;
- Debug.Assert(type1 == typeEnum || type1 == typeEnum.underlyingEnumType());
- Debug.Assert(type2 == typeEnum || type2 == typeEnum.underlyingEnumType());
+ Debug.Assert(type1 == typeEnum || type1 == typeEnum.UnderlyingEnumType);
+ Debug.Assert(type2 == typeEnum || type2 == typeEnum.UnderlyingEnumType);
AggregateType typeDst = typeEnum;
@@ -2693,7 +2721,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
case ExpressionKind.Subtract:
if (type1 == type2)
- typeDst = typeEnum.underlyingEnumType();
+ typeDst = typeEnum.UnderlyingEnumType;
break;
default:
@@ -2706,29 +2734,29 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return typeDst;
}
- private ExprBinOp CreateBinopForPredefMethodCall(ExpressionKind ek, PREDEFMETH predefMeth, CType RetType, Expr arg1, Expr arg2)
+ private static ExprBinOp CreateBinopForPredefMethodCall(ExpressionKind ek, PREDEFMETH predefMeth, CType RetType, Expr arg1, Expr arg2)
{
- MethodSymbol methSym = GetSymbolLoader().getPredefinedMembers().GetMethod(predefMeth);
+ MethodSymbol methSym = PredefinedMembers.GetMethod(predefMeth);
Debug.Assert(methSym != null);
- ExprBinOp binop = GetExprFactory().CreateBinop(ek, RetType, arg1, arg2);
+ ExprBinOp binop = ExprFactory.CreateBinop(ek, RetType, arg1, arg2);
// Set the predefined method to call.
AggregateSymbol agg = methSym.getClass();
- AggregateType callingType = GetTypes().GetAggregate(agg, BSYMMGR.EmptyTypeArray());
+ AggregateType callingType = TypeManager.GetAggregate(agg, TypeArray.Empty);
binop.PredefinedMethodToCall = new MethWithInst(methSym, callingType, null);
binop.UserDefinedCallMethod = binop.PredefinedMethodToCall;
return binop;
}
- private ExprUnaryOp CreateUnaryOpForPredefMethodCall(ExpressionKind ek, PREDEFMETH predefMeth, CType pRetType, Expr pArg)
+ private static ExprUnaryOp CreateUnaryOpForPredefMethodCall(ExpressionKind ek, PREDEFMETH predefMeth, CType pRetType, Expr pArg)
{
- MethodSymbol methSym = GetSymbolLoader().getPredefinedMembers().GetMethod(predefMeth);
+ MethodSymbol methSym = PredefinedMembers.GetMethod(predefMeth);
Debug.Assert(methSym != null);
- ExprUnaryOp pUnaryOp = GetExprFactory().CreateUnaryOp(ek, pRetType, pArg);
+ ExprUnaryOp pUnaryOp = ExprFactory.CreateUnaryOp(ek, pRetType, pArg);
// Set the predefined method to call.
AggregateSymbol pAgg = methSym.getClass();
- AggregateType pCallingType = GetTypes().GetAggregate(pAgg, BSYMMGR.EmptyTypeArray());
+ AggregateType pCallingType = TypeManager.GetAggregate(pAgg, TypeArray.Empty);
pUnaryOp.PredefinedMethodToCall = new MethWithInst(methSym, pCallingType, null);
pUnaryOp.UserDefinedCallMethod = pUnaryOp.PredefinedMethodToCall;
return pUnaryOp;
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/PredefinedMembers.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/PredefinedMembers.cs
index 5c0d7b43cb..39a4c22ca2 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/PredefinedMembers.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/PredefinedMembers.cs
@@ -3,7 +3,6 @@
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
-using Microsoft.CSharp.RuntimeBinder.Errors;
using Microsoft.CSharp.RuntimeBinder.Syntax;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
@@ -190,40 +189,22 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
this.name = name;
this.getter = getter;
}
- };
+ }
// Loads and caches predefined members.
// Also finds constructors on delegate types.
- internal sealed class PredefinedMembers
+ internal static class PredefinedMembers
{
- private readonly SymbolLoader _loader;
- internal SymbolTable RuntimeBinderSymbolTable;
- private readonly MethodSymbol[] _methods = new MethodSymbol[(int)PREDEFMETH.PM_COUNT];
- private readonly PropertySymbol[] _properties = new PropertySymbol[(int)PREDEFPROP.PP_COUNT];
-
- private Name GetMethName(PREDEFMETH method)
- {
- return GetPredefName(GetMethPredefName(method));
- }
-
- private AggregateSymbol GetMethParent(PREDEFMETH method)
- {
- return GetPredefAgg(GetMethPredefType(method));
- }
+ private static readonly MethodSymbol[] _methods = new MethodSymbol[(int)PREDEFMETH.PM_COUNT];
+ private static readonly PropertySymbol[] _properties = new PropertySymbol[(int)PREDEFPROP.PP_COUNT];
- private PropertySymbol LoadProperty(PREDEFPROP property)
+ private static PropertySymbol LoadProperty(PREDEFPROP property)
{
- return LoadProperty(
- property,
- GetPropName(property),
- GetPropGetter(property));
+ PredefinedPropertyInfo info = GetPropInfo(property);
+ return LoadProperty(property, NameManager.GetPredefinedName(info.name), info.getter);
}
- private Name GetPropName(PREDEFPROP property)
- {
- return GetPredefName(GetPropPredefName(property));
- }
- private PropertySymbol LoadProperty(
+ private static PropertySymbol LoadProperty(
PREDEFPROP predefProp,
Name propertyName,
PREDEFMETH propertyGetter)
@@ -231,7 +212,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Debug.Assert(propertyName != null);
Debug.Assert(propertyGetter >= 0 && propertyGetter < PREDEFMETH.PM_COUNT);
- RuntimeBinderSymbolTable.AddPredefinedPropertyToSymbolTable(
+ SymbolTable.AddPredefinedPropertyToSymbolTable(
GetPredefAgg(GetPropPredefType(predefProp)), propertyName);
MethodSymbol getter = GetMethod(propertyGetter);
@@ -241,35 +222,9 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return property;
}
- private SymbolLoader GetSymbolLoader()
- {
- Debug.Assert(_loader != null);
+ private static AggregateSymbol GetPredefAgg(PredefinedType pt) => SymbolLoader.GetPredefAgg(pt);
- return _loader;
- }
- private ErrorHandling GetErrorContext()
- {
- return GetSymbolLoader().GetErrorContext();
- }
- private TypeManager GetTypeManager()
- {
- return GetSymbolLoader().GetTypeManager();
- }
- private BSYMMGR getBSymmgr()
- {
- return GetSymbolLoader().getBSymmgr();
- }
-
- private Name GetPredefName(PredefinedName pn)
- {
- return NameManager.GetPredefinedName(pn);
- }
- private AggregateSymbol GetPredefAgg(PredefinedType pt)
- {
- return GetSymbolLoader().GetPredefAgg(pt);
- }
-
- private CType LoadTypeFromSignature(int[] signature, ref int indexIntoSignatures, TypeArray classTyVars)
+ private static CType LoadTypeFromSignature(int[] signature, ref int indexIntoSignatures, TypeArray classTyVars)
{
Debug.Assert(signature != null);
@@ -279,17 +234,16 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
switch (current)
{
case MethodSignatureEnum.SIG_SZ_ARRAY:
- return GetTypeManager()
- .GetArray(LoadTypeFromSignature(signature, ref indexIntoSignatures, classTyVars), 1, true);
+ return TypeManager.GetArray(LoadTypeFromSignature(signature, ref indexIntoSignatures, classTyVars), 1, true);
case MethodSignatureEnum.SIG_METH_TYVAR:
- return GetTypeManager().GetStdMethTypeVar(signature[indexIntoSignatures++]);
+ return TypeManager.GetStdMethTypeVar(signature[indexIntoSignatures++]);
case MethodSignatureEnum.SIG_CLASS_TYVAR:
return classTyVars[signature[indexIntoSignatures++]];
case (MethodSignatureEnum)PredefinedType.PT_VOID:
- return GetTypeManager().GetVoid();
+ return VoidType.Instance;
default:
Debug.Assert(current >= 0 && (int)current < (int)PredefinedType.PT_COUNT);
@@ -297,7 +251,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
int typeCount = agg.GetTypeVars().Count;
if (typeCount == 0)
{
- return GetTypeManager().GetAggregate(agg, BSYMMGR.EmptyTypeArray());
+ return TypeManager.GetAggregate(agg, TypeArray.Empty);
}
CType[] typeArgs = new CType[typeCount];
@@ -306,11 +260,11 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
typeArgs[iTypeArg] = LoadTypeFromSignature(signature, ref indexIntoSignatures, classTyVars);
}
- return GetTypeManager().GetAggregate(agg, getBSymmgr().AllocParams(typeArgs));
+ return TypeManager.GetAggregate(agg, TypeArray.Allocate(typeArgs));
}
}
- private TypeArray LoadTypeArrayFromSignature(int[] signature, ref int indexIntoSignatures, TypeArray classTyVars)
+ private static TypeArray LoadTypeArrayFromSignature(int[] signature, ref int indexIntoSignatures, TypeArray classTyVars)
{
Debug.Assert(signature != null);
@@ -325,18 +279,12 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
ptypes[i] = LoadTypeFromSignature(signature, ref indexIntoSignatures, classTyVars);
}
- return getBSymmgr().AllocParams(count, ptypes);
+ return TypeArray.Allocate(ptypes);
}
- public PredefinedMembers(SymbolLoader loader)
- {
- _loader = loader;
- Debug.Assert(_loader != null);
-
- _methods = new MethodSymbol[(int)PREDEFMETH.PM_COUNT];
- _properties = new PropertySymbol[(int)PREDEFPROP.PP_COUNT];
-
#if DEBUG
+ static PredefinedMembers()
+ {
// validate the tables
for (int i = 0; i < (int)PREDEFMETH.PM_COUNT; i++)
{
@@ -346,22 +294,22 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
Debug.Assert((int)GetPropInfo((PREDEFPROP)i).property == i);
}
-#endif
}
+#endif
- public PropertySymbol GetProperty(PREDEFPROP property)
+ public static PropertySymbol GetProperty(PREDEFPROP property)
{
Debug.Assert(property >= 0 && property < PREDEFPROP.PP_COUNT);
return _properties[(int)property] ?? (_properties[(int)property] = LoadProperty(property));
}
- public MethodSymbol GetMethod(PREDEFMETH method)
+ public static MethodSymbol GetMethod(PREDEFMETH method)
{
Debug.Assert(method >= 0 && method < PREDEFMETH.PM_COUNT);
return _methods[(int)method] ?? (_methods[(int)method] = LoadMethod(method));
}
- private MethodSymbol LoadMethod(
+ private static MethodSymbol LoadMethod(
AggregateSymbol type,
int[] signature,
int cMethodTyVars,
@@ -388,17 +336,17 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (ret == null)
{
- RuntimeBinderSymbolTable.AddPredefinedMethodToSymbolTable(type, methodName);
+ SymbolTable.AddPredefinedMethodToSymbolTable(type, methodName);
ret = LookupMethodWhileLoading(type, cMethodTyVars, methodName, methodAccess, isStatic, isVirtual, returnType, argumentTypes);
}
return ret;
}
- private MethodSymbol LookupMethodWhileLoading(AggregateSymbol type, int cMethodTyVars, Name methodName, ACCESS methodAccess, bool isStatic, bool isVirtual, CType returnType, TypeArray argumentTypes)
+ private static MethodSymbol LookupMethodWhileLoading(AggregateSymbol type, int cMethodTyVars, Name methodName, ACCESS methodAccess, bool isStatic, bool isVirtual, CType returnType, TypeArray argumentTypes)
{
- for (Symbol sym = GetSymbolLoader().LookupAggMember(methodName, type, symbmask_t.MASK_ALL);
+ for (Symbol sym = SymbolLoader.LookupAggMember(methodName, type, symbmask_t.MASK_ALL);
sym != null;
- sym = SymbolLoader.LookupNextSym(sym, type, symbmask_t.MASK_ALL))
+ sym = sym.LookupNext(symbmask_t.MASK_ALL))
{
if (sym is MethodSymbol methsym)
{
@@ -406,9 +354,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
methsym.isStatic == isStatic &&
methsym.isVirtual == isVirtual &&
methsym.typeVars.Count == cMethodTyVars &&
- GetTypeManager().SubstEqualTypes(methsym.RetType, returnType, null, methsym.typeVars, SubstTypeFlags.DenormMeth) &&
- GetTypeManager().SubstEqualTypeArrays(methsym.Params, argumentTypes, (TypeArray)null,
- methsym.typeVars, SubstTypeFlags.DenormMeth))
+ TypeManager.SubstEqualTypes(methsym.RetType, returnType, null, methsym.typeVars, true) &&
+ TypeManager.SubstEqualTypeArrays(methsym.Params, argumentTypes, null, methsym.typeVars))
{
return methsym;
}
@@ -417,21 +364,17 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return null;
}
- private MethodSymbol LoadMethod(PREDEFMETH method)
+ private static MethodSymbol LoadMethod(PREDEFMETH method)
{
+ PredefinedMethodInfo info = GetMethInfo(method);
return LoadMethod(
- GetMethParent(method),
- GetMethSignature(method),
- GetMethTyVars(method),
- GetMethName(method),
- GetMethAccess(method),
- IsMethStatic(method),
- IsMethVirtual(method));
- }
-
- private static PredefinedName GetPropPredefName(PREDEFPROP property)
- {
- return GetPropInfo(property).name;
+ GetPredefAgg(info.type),
+ info.signature,
+ info.cTypeVars,
+ NameManager.GetPredefinedName(info.name),
+ info.access,
+ info.callingConvention == MethodCallingConventionEnum.Static,
+ info.callingConvention == MethodCallingConventionEnum.Virtual);
}
private static PREDEFMETH GetPropGetter(PREDEFPROP property)
@@ -471,41 +414,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return s_predefinedMethods[(int)method];
}
- private static PredefinedName GetMethPredefName(PREDEFMETH method)
- {
- return GetMethInfo(method).name;
- }
-
- private static PredefinedType GetMethPredefType(PREDEFMETH method)
- {
- return GetMethInfo(method).type;
- }
-
- private static bool IsMethStatic(PREDEFMETH method)
- {
- return GetMethInfo(method).callingConvention == MethodCallingConventionEnum.Static;
- }
-
- private static bool IsMethVirtual(PREDEFMETH method)
- {
- return GetMethInfo(method).callingConvention == MethodCallingConventionEnum.Virtual;
- }
-
- private static ACCESS GetMethAccess(PREDEFMETH method)
- {
- return GetMethInfo(method).access;
- }
-
- private static int GetMethTyVars(PREDEFMETH method)
- {
- return GetMethInfo(method).cTypeVars;
- }
-
- private static int[] GetMethSignature(PREDEFMETH method)
- {
- return GetMethInfo(method).signature;
- }
-
// the list of predefined method definitions.
// This list must be in the same order as the PREDEFMETH enum.
private static readonly PredefinedMethodInfo[] s_predefinedMethods = new PredefinedMethodInfo[(int)PREDEFMETH.PM_COUNT] {
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/SemanticChecker.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/SemanticChecker.cs
index 1a8c941a44..1d30a8304c 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/SemanticChecker.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/SemanticChecker.cs
@@ -18,21 +18,21 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
//
// Semantic check methods on SymbolLoader
//
- internal sealed class CSemanticChecker
+ internal static class CSemanticChecker
{
// Generate an error if CType is static.
- public void CheckForStaticClass(Symbol symCtx, CType CType, ErrorCode err)
+ public static void CheckForStaticClass(CType type)
{
- if (CType.isStaticClass())
+ if (type.IsStaticClass)
{
- throw ReportStaticClassError(symCtx, CType, err);
+ throw ErrorHandling.Error(ErrorCode.ERR_ConvertToStaticClass, type);
}
}
- public ACCESSERROR CheckAccess2(Symbol symCheck, AggregateType atsCheck, Symbol symWhere, CType typeThru)
+ public static ACCESSERROR CheckAccess2(Symbol symCheck, AggregateType atsCheck, Symbol symWhere, CType typeThru)
{
Debug.Assert(symCheck != null);
- Debug.Assert(atsCheck == null || symCheck.parent == atsCheck.getAggregate());
+ Debug.Assert(atsCheck == null || symCheck.parent == atsCheck.OwningAggregate);
Debug.Assert(typeThru == null ||
typeThru is AggregateType ||
typeThru is TypeParameterType ||
@@ -60,8 +60,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
// Check the accessibility of the return CType.
- CType CType = symCheck.getType();
- if (CType == null)
+ CType type = symCheck.getType();
+ if (type == null)
{
return ACCESSERROR.ACCESSERROR_NOERROR;
}
@@ -70,14 +70,15 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Debug.Assert(atsCheck != null);
// Substitute on the CType.
- if (atsCheck.GetTypeArgsAll().Count > 0)
+ if (atsCheck.TypeArgsAll.Count > 0)
{
- CType = SymbolLoader.GetTypeManager().SubstType(CType, atsCheck);
+ type = TypeManager.SubstType(type, atsCheck);
}
- return CheckTypeAccess(CType, symWhere) ? ACCESSERROR.ACCESSERROR_NOERROR : ACCESSERROR.ACCESSERROR_NOACCESS;
+ return CheckTypeAccess(type, symWhere) ? ACCESSERROR.ACCESSERROR_NOERROR : ACCESSERROR.ACCESSERROR_NOACCESS;
}
- public bool CheckTypeAccess(CType type, Symbol symWhere)
+
+ public static bool CheckTypeAccess(CType type, Symbol symWhere)
{
Debug.Assert(type != null);
@@ -92,15 +93,15 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
do
{
- if (ACCESSERROR.ACCESSERROR_NOERROR != CheckAccessCore(ats.GetOwningAggregate(), ats.outerType, symWhere, null))
+ if (ACCESSERROR.ACCESSERROR_NOERROR != CheckAccessCore(ats.OwningAggregate, ats.OuterType, symWhere, null))
{
return false;
}
- ats = ats.outerType;
+ ats = ats.OuterType;
} while(ats != null);
- TypeArray typeArgs = ((AggregateType)type).GetTypeArgsAll();
+ TypeArray typeArgs = ((AggregateType)type).TypeArgsAll;
for (int i = 0; i < typeArgs.Count; i++)
{
if (!CheckTypeAccess(typeArgs[i], symWhere))
@@ -110,36 +111,10 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return true;
}
- // Generates an error for static classes
- public RuntimeBinderException ReportStaticClassError(Symbol symCtx, CType CType, ErrorCode err) =>
- ErrorContext.Error(err, symCtx != null ? new []{CType, new ErrArg(symCtx)} : new ErrArg[]{CType});
-
- public SymbolLoader SymbolLoader { get; } = new SymbolLoader();
-
- /////////////////////////////////////////////////////////////////////////////////
- // SymbolLoader forwarders (begin)
- //
-
- public ErrorHandling ErrorContext => SymbolLoader.ErrorContext;
-
- public TypeManager GetTypeManager() { return SymbolLoader.GetTypeManager(); }
- public BSYMMGR getBSymmgr() { return SymbolLoader.getBSymmgr(); }
- public SymFactory GetGlobalSymbolFactory() { return SymbolLoader.GetGlobalSymbolFactory(); }
-
- //protected CompilerPhase GetCompPhase() { return SymbolLoader.CompPhase(); }
- //protected void SetCompPhase(CompilerPhase compPhase) { SymbolLoader.compPhase = compPhase; }
- public PredefinedTypes getPredefTypes() { return SymbolLoader.GetPredefindTypes(); }
- //
- // SymbolLoader forwarders (end)
- /////////////////////////////////////////////////////////////////////////////////
-
- //
- // Utility methods
- //
- private ACCESSERROR CheckAccessCore(Symbol symCheck, AggregateType atsCheck, Symbol symWhere, CType typeThru)
+ private static ACCESSERROR CheckAccessCore(Symbol symCheck, AggregateType atsCheck, Symbol symWhere, CType typeThru)
{
Debug.Assert(symCheck != null);
- Debug.Assert(atsCheck == null || symCheck.parent == atsCheck.getAggregate());
+ Debug.Assert(atsCheck == null || symCheck.parent == atsCheck.OwningAggregate);
Debug.Assert(typeThru == null ||
typeThru is AggregateType ||
typeThru is TypeParameterType ||
@@ -202,11 +177,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
aggWhere = aggSym;
break;
}
- if (symT is AggregateDeclaration aggDec)
- {
- aggWhere = aggDec.Agg();
- break;
- }
}
if (aggWhere == null)
@@ -245,7 +215,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (typeThru != null && !symCheck.isStatic)
{
- atsThru = SymbolLoader.GetAggTypeSym(typeThru);
+ atsThru = typeThru.GetAts();
}
// Look for aggCheck among the base classes of aggWhere and outer aggs.
@@ -263,7 +233,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// agg or a CType derived from an instantiation of agg. In this case
// all that matters is that agg is in the base AggregateSymbol chain of atsThru. The
// actual AGGTYPESYMs involved don't matter.
- if (atsThru == null || atsThru.getAggregate().FindBaseAgg(agg))
+ if (atsThru == null || atsThru.OwningAggregate.FindBaseAgg(agg))
{
return ACCESSERROR.ACCESSERROR_NOERROR;
}
@@ -275,25 +245,20 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return found ? ACCESSERROR.ACCESSERROR_NOACCESSTHRU : ACCESSERROR.ACCESSERROR_NOACCESS;
}
- public static bool CheckBogus(Symbol sym)
- {
- return (sym as PropertySymbol)?.Bogus ?? false;
- }
+ public static bool CheckBogus(Symbol sym) => (sym as PropertySymbol)?.Bogus ?? false;
- public RuntimeBinderException ReportAccessError(SymWithType swtBad, Symbol symWhere, CType typeQual)
+ public static RuntimeBinderException ReportAccessError(SymWithType swtBad, Symbol symWhere, CType typeQual)
{
Debug.Assert(!CheckAccess(swtBad.Sym, swtBad.GetType(), symWhere, typeQual) ||
!CheckTypeAccess(swtBad.GetType(), symWhere));
return CheckAccess2(swtBad.Sym, swtBad.GetType(), symWhere, typeQual)
== ACCESSERROR.ACCESSERROR_NOACCESSTHRU
- ? ErrorContext.Error(ErrorCode.ERR_BadProtectedAccess, swtBad, typeQual, symWhere)
- : ErrorContext.Error(ErrorCode.ERR_BadAccess, swtBad);
+ ? ErrorHandling.Error(ErrorCode.ERR_BadProtectedAccess, swtBad, typeQual, symWhere)
+ : ErrorHandling.Error(ErrorCode.ERR_BadAccess, swtBad);
}
- public bool CheckAccess(Symbol symCheck, AggregateType atsCheck, Symbol symWhere, CType typeThru)
- {
- return CheckAccess2(symCheck, atsCheck, symWhere, typeThru) == ACCESSERROR.ACCESSERROR_NOERROR;
- }
+ public static bool CheckAccess(Symbol symCheck, AggregateType atsCheck, Symbol symWhere, CType typeThru) =>
+ CheckAccess2(symCheck, atsCheck, symWhere, typeThru) == ACCESSERROR.ACCESSERROR_NOERROR;
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/SubstitutionContext.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/SubstitutionContext.cs
index 18768926c6..6422e9599e 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/SubstitutionContext.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/SubstitutionContext.cs
@@ -6,95 +6,36 @@ using System;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
- // Used to specify whether and which type variables should be normalized.
- [Flags]
- internal enum SubstTypeFlags
- {
- NormNone = 0x00,
- NormClass = 0x01, // Replace class type variables with the normalized (standard) ones.
- NormMeth = 0x02, // Replace method type variables with the normalized (standard) ones.
- NormAll = NormClass | NormMeth,
- DenormClass = 0x04, // Replace normalized (standard) class type variables with the given class type args.
- DenormMeth = 0x08, // Replace normalized (standard) method type variables with the given method type args.
- DenormAll = DenormClass | DenormMeth,
- NoRefOutDifference = 0x10
- }
-
internal sealed class SubstContext
{
- public CType[] prgtypeCls;
- public int ctypeCls;
- public CType[] prgtypeMeth;
- public int ctypeMeth;
- public SubstTypeFlags grfst;
+ public readonly CType[] ClassTypes;
+ public readonly CType[] MethodTypes;
+ public readonly bool DenormMeth;
- public SubstContext(TypeArray typeArgsCls, TypeArray typeArgsMeth, SubstTypeFlags grfst)
+ public SubstContext(TypeArray typeArgsCls, TypeArray typeArgsMeth, bool denormMeth)
{
- Init(typeArgsCls, typeArgsMeth, grfst);
+ typeArgsCls?.AssertValid();
+ ClassTypes = typeArgsCls?.Items ?? Array.Empty<CType>();
+ typeArgsMeth?.AssertValid();
+ MethodTypes = typeArgsMeth?.Items ?? Array.Empty<CType>();
+ DenormMeth = denormMeth;
}
public SubstContext(AggregateType type)
- : this(type, null, SubstTypeFlags.NormNone)
+ : this(type, null, false)
{
}
public SubstContext(AggregateType type, TypeArray typeArgsMeth)
- : this(type, typeArgsMeth, SubstTypeFlags.NormNone)
- {
- }
-
- private SubstContext(AggregateType type, TypeArray typeArgsMeth, SubstTypeFlags grfst)
- {
- Init(type?.GetTypeArgsAll(), typeArgsMeth, grfst);
- }
-
- public SubstContext(CType[] prgtypeCls, int ctypeCls, CType[] prgtypeMeth, int ctypeMeth)
- : this(prgtypeCls, ctypeCls, prgtypeMeth, ctypeMeth, SubstTypeFlags.NormNone)
- {
- }
-
- private SubstContext(CType[] prgtypeCls, int ctypeCls, CType[] prgtypeMeth, int ctypeMeth, SubstTypeFlags grfst)
+ : this(type, typeArgsMeth, false)
{
- this.prgtypeCls = prgtypeCls;
- this.ctypeCls = ctypeCls;
- this.prgtypeMeth = prgtypeMeth;
- this.ctypeMeth = ctypeMeth;
- this.grfst = grfst;
}
- public bool FNop()
+ private SubstContext(AggregateType type, TypeArray typeArgsMeth, bool denormMeth)
+ : this(type?.TypeArgsAll, typeArgsMeth, denormMeth)
{
- return 0 == ctypeCls && 0 == ctypeMeth && 0 == (grfst & SubstTypeFlags.NormAll);
}
- // Initializes a substitution context. Returns false iff no substitutions will ever be performed.
- private void Init(TypeArray typeArgsCls, TypeArray typeArgsMeth, SubstTypeFlags grfst)
- {
- if (typeArgsCls != null)
- {
- typeArgsCls.AssertValid();
- ctypeCls = typeArgsCls.Count;
- prgtypeCls = typeArgsCls.Items;
- }
- else
- {
- ctypeCls = 0;
- prgtypeCls = null;
- }
-
- if (typeArgsMeth != null)
- {
- typeArgsMeth.AssertValid();
- ctypeMeth = typeArgsMeth.Count;
- prgtypeMeth = typeArgsMeth.Items;
- }
- else
- {
- ctypeMeth = 0;
- prgtypeMeth = null;
- }
-
- this.grfst = grfst;
- }
+ public bool IsNop => ClassTypes.Length == 0 & MethodTypes.Length == 0;
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/AggregateSymbol.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/AggregateSymbol.cs
index 68bebea493..8c6a189410 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/AggregateSymbol.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/AggregateSymbol.cs
@@ -32,8 +32,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
private TypeArray _typeVarsThis; // Type variables for this generic class, as declarations.
private TypeArray _typeVarsAll; // The type variables for this generic class and all containing classes.
- private TypeManager _pTypeManager; // This is so AGGTYPESYMs can instantiate their baseClass and ifacesAll members on demand.
-
// First UD conversion operator. This chain is for this type only (not base types).
// The hasConversion flag indicates whether this or any base types have UD conversions.
private MethodSymbol _pConvFirst;
@@ -78,7 +76,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
public AggregateSymbol GetBaseAgg()
{
- return _pBaseClass?.getAggregate();
+ return _pBaseClass?.OwningAggregate;
}
public AggregateType getThisType()
@@ -89,7 +87,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
AggregateType pOuterType = isNested() ? GetOuterAgg().getThisType() : null;
- _atsInst = _pTypeManager.GetAggregate(this, pOuterType, GetTypeVars());
+ _atsInst = TypeManager.GetAggregate(this, pOuterType, GetTypeVars());
}
//Debug.Assert(GetTypeVars().Size == atsInst.GenericArguments.Count);
@@ -223,16 +221,16 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
////////////////////////////////////////////////////////////////////////////////
- public bool HasConversion(SymbolLoader pLoader)
+ public bool HasConversion()
{
- pLoader.RuntimeBinderSymbolTable.AddConversionsForType(AssociatedSystemType);
+ SymbolTable.AddConversionsForType(AssociatedSystemType);
if (!_hasConversion.HasValue)
{
// ok, we tried defining all the conversions, and we didn't get anything
// for this type. However, we will still think this type has conversions
// if it's base type has conversions.
- _hasConversion = GetBaseAgg() != null && GetBaseAgg().HasConversion(pLoader);
+ _hasConversion = GetBaseAgg() != null && GetBaseAgg().HasConversion();
}
return _hasConversion.Value;
@@ -291,11 +289,11 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
else
{
- outerTypeVars = BSYMMGR.EmptyTypeArray();
+ outerTypeVars = TypeArray.Empty;
}
_typeVarsThis = typeVars;
- _typeVarsAll = _pTypeManager.ConcatenateTypeArrays(outerTypeVars, typeVars);
+ _typeVarsAll = TypeArray.Concat(outerTypeVars, typeVars);
}
}
@@ -344,16 +342,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
_ifacesAll = ifacesAll;
}
- public TypeManager GetTypeManager()
- {
- return _pTypeManager;
- }
-
- public void SetTypeManager(TypeManager typeManager)
- {
- _pTypeManager = typeManager;
- }
-
public MethodSymbol GetFirstUDConversion()
{
return _pConvFirst;
@@ -364,9 +352,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
_pConvFirst = conv;
}
- public bool InternalsVisibleTo(Assembly assembly)
- {
- return _pTypeManager.InternalsVisibleTo(AssociatedAssembly, assembly);
- }
+ public bool InternalsVisibleTo(Assembly assembly) => TypeManager.InternalsVisibleTo(AssociatedAssembly, assembly);
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/FieldSymbol.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/FieldSymbol.cs
index f8f72a97e1..996a1cc8d7 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/FieldSymbol.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/FieldSymbol.cs
@@ -21,14 +21,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
public new bool isStatic; // Static member?
public bool isReadOnly; // Can only be changed from within constructor.
public bool isEvent; // This field is the implementation for an event.
-
- public bool isAssigned; // Has this ever been assigned by the user?
- // Set if the field's ibit (for definite assignment checking) varies depending on the generic
- // instantiation of the containing type. For example:
- // struct S<T> { T x; int y; }
- // The ibit value for y depends on what T is bound to. For S<Point>, y's ibit is 2. For S<int>, y's
- // ibit is 1. This flag is set the first time a calculated ibit for the member is found to not
- // match the return result of GetIbitInst().
public FieldInfo AssociatedFieldInfo;
// If fixedAgg is non-null, the ant of the fixed buffer length
@@ -45,10 +37,10 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
public AggregateSymbol getClass() => parent as AggregateSymbol;
- public EventSymbol getEvent(SymbolLoader symbolLoader)
+ public EventSymbol getEvent()
{
Debug.Assert(isEvent);
- return symbolLoader.LookupAggMember(name, getClass(), symbmask_t.MASK_EventSymbol) as EventSymbol;
+ return SymbolLoader.LookupAggMember(name, getClass(), symbmask_t.MASK_EventSymbol) as EventSymbol;
}
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/MethodSymbol.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/MethodSymbol.cs
index 6745b9af16..95f374bb21 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/MethodSymbol.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/MethodSymbol.cs
@@ -62,10 +62,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return false;
}
- public MethodKindEnum MethKind()
- {
- return _methKind;
- }
+ public MethodKindEnum MethKind => _methKind;
public bool IsConstructor()
{
@@ -80,11 +77,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
IsConstructor();
}
- public bool IsDestructor() // Is a destructor
- {
- return _methKind == MethodKindEnum.Destructor;
- }
-
public bool isPropertyAccessor() // true if this method is a property set or get method
{
return _methKind == MethodKindEnum.PropAccessor;
@@ -95,21 +87,11 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return _methKind == MethodKindEnum.EventAccessor;
}
- private bool isExplicit() // is user defined explicit conversion operator
- {
- return _methKind == MethodKindEnum.ExplicitConv;
- }
-
public bool isImplicit() // is user defined implicit conversion operator
{
return _methKind == MethodKindEnum.ImplicitConv;
}
- public bool isInvoke() // Invoke method on a delegate - isn't user callable
- {
- return _methKind == MethodKindEnum.Invoke;
- }
-
public void SetMethKind(MethodKindEnum mk)
{
_methKind = mk;
@@ -117,14 +99,14 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
public MethodSymbol ConvNext()
{
- Debug.Assert(isImplicit() || isExplicit());
+ AssertIsConversionOperator();
return _convNext;
}
public void SetConvNext(MethodSymbol conv)
{
- Debug.Assert(isImplicit() || isExplicit());
- Debug.Assert(conv == null || conv.isImplicit() || conv.isExplicit());
+ AssertIsConversionOperator();
+ conv?.AssertIsConversionOperator();
_convNext = conv;
}
@@ -152,9 +134,10 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
_evt = evt;
}
- public bool isConversionOperator()
+ [Conditional("DEBUG")]
+ private void AssertIsConversionOperator()
{
- return (isExplicit() || isImplicit());
+ Debug.Assert(MethKind == MethodKindEnum.ExplicitConv || MethKind == MethodKindEnum.ImplicitConv);
}
public new bool isUserCallable()
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/NamespaceOrAggregateSymbol.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/NamespaceOrAggregateSymbol.cs
index 2f9a029fcf..d1d235fc4d 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/NamespaceOrAggregateSymbol.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/NamespaceOrAggregateSymbol.cs
@@ -16,46 +16,5 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
internal abstract class NamespaceOrAggregateSymbol : ParentSymbol
{
- private AggregateDeclaration _declFirst;
- private AggregateDeclaration _declLast;
-
- // ----------------------------------------------------------------------------
- // NamespaceOrAggregateSymbol
- // ----------------------------------------------------------------------------
-
- // Compare to ParentSymbol::AddToChildList
- public void AddDecl(AggregateDeclaration decl)
- {
- Debug.Assert(decl != null);
- Debug.Assert(this is AggregateSymbol);
- Debug.Assert(decl is AggregateDeclaration);
-
- // If parent is set it should be set to us!
- Debug.Assert(decl.bag == null || decl.bag == this);
- // There shouldn't be a declNext.
- Debug.Assert(decl.declNext == null);
-
- if (_declLast == null)
- {
- Debug.Assert(_declFirst == null);
- _declFirst = _declLast = decl;
- }
- else
- {
- _declLast.declNext = decl;
- _declLast = decl;
-
-#if DEBUG
- // Validate our chain.
- AggregateDeclaration pdecl;
- for (pdecl = _declFirst; pdecl?.declNext != null; pdecl = pdecl.declNext)
- { }
- Debug.Assert(pdecl == null || (pdecl == _declLast && pdecl.declNext == null));
-#endif
- }
-
- decl.declNext = null;
- decl.bag = this;
- }
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymFactory.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymFactory.cs
index e684b73e48..a59b513efe 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymFactory.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymFactory.cs
@@ -7,16 +7,9 @@ using Microsoft.CSharp.RuntimeBinder.Syntax;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
- internal sealed class SymFactory
+ internal static class SymFactory
{
- private readonly SYMTBL _symbolTable;
-
- public SymFactory(SYMTBL symtable)
- {
- _symbolTable = symtable;
- }
-
- private Symbol NewBasicSymbol(
+ private static Symbol NewBasicSymbol(
SYMKIND kind,
Name name,
ParentSymbol parent)
@@ -32,10 +25,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
sym = new AggregateSymbol();
sym.name = name;
break;
- case SYMKIND.SK_AggregateDeclaration:
- sym = new AggregateDeclaration();
- sym.name = name;
- break;
case SYMKIND.SK_TypeParameterSymbol:
sym = new TypeParameterSymbol();
sym.name = name;
@@ -78,32 +67,29 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
// Set the parent element of the child symbol.
parent.AddToChildList(sym);
- _symbolTable.InsertChild(parent, sym);
+ SymbolStore.InsertChild(parent, sym);
}
- return (sym);
+ return sym;
}
// Namespace
- public NamespaceSymbol CreateNamespace(Name name, NamespaceSymbol parent)
+ public static NamespaceSymbol CreateNamespace(Name name, NamespaceSymbol parent)
{
NamespaceSymbol sym = (NamespaceSymbol)NewBasicSymbol(SYMKIND.SK_NamespaceSymbol, name, parent);
sym.SetAccess(ACCESS.ACC_PUBLIC);
- return (sym);
+ return sym;
}
/////////////////////////////////////////////////////////////////////////////////
- public AggregateSymbol CreateAggregate(Name name, NamespaceOrAggregateSymbol parent, TypeManager typeManager)
+ public static AggregateSymbol CreateAggregate(Name name, NamespaceOrAggregateSymbol parent)
{
- if (name == null || parent == null || typeManager == null)
- {
- throw Error.InternalCompilerError();
- }
+ Debug.Assert(name != null);
+ Debug.Assert(parent != null);
AggregateSymbol sym = (AggregateSymbol)NewBasicSymbol(SYMKIND.SK_AggregateSymbol, name, parent);
sym.name = name;
- sym.SetTypeManager(typeManager);
sym.SetSealed(false);
sym.SetAccess(ACCESS.ACC_UNKNOWN);
sym.SetIfaces(null);
@@ -113,33 +99,18 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return sym;
}
- public AggregateDeclaration CreateAggregateDecl(AggregateSymbol agg, AggregateDeclaration declOuter)
- {
- Debug.Assert(agg != null);
- //Debug.Assert(declOuter == null || declOuter.Bag() == agg.Parent);
-
- // DECLSYMs are not parented like named symbols.
- AggregateDeclaration sym = NewBasicSymbol(SYMKIND.SK_AggregateDeclaration, agg.name, null) as AggregateDeclaration;
-
- declOuter?.AddToChildList(sym);
- agg.AddDecl(sym);
-
- Debug.Assert(sym != null);
- return (sym);
- }
-
// Members of aggs
- public FieldSymbol CreateMemberVar(Name name, AggregateSymbol parent)
+ public static FieldSymbol CreateMemberVar(Name name, AggregateSymbol parent)
{
Debug.Assert(name != null);
FieldSymbol sym = NewBasicSymbol(SYMKIND.SK_FieldSymbol, name, parent) as FieldSymbol;
Debug.Assert(sym != null);
- return (sym);
+ return sym;
}
- public LocalVariableSymbol CreateLocalVar(Name name, Scope parent, CType type)
+ public static LocalVariableSymbol CreateLocalVar(Name name, Scope parent, CType type)
{
LocalVariableSymbol sym = (LocalVariableSymbol)NewBasicSymbol(SYMKIND.SK_LocalVariableSymbol, name, parent);
sym.SetType(type);
@@ -149,25 +120,25 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return sym;
}
- public MethodSymbol CreateMethod(Name name, AggregateSymbol parent) =>
+ public static MethodSymbol CreateMethod(Name name, AggregateSymbol parent) =>
NewBasicSymbol(SYMKIND.SK_MethodSymbol, name, parent) as MethodSymbol;
- public PropertySymbol CreateProperty(Name name, AggregateSymbol parent)
+ public static PropertySymbol CreateProperty(Name name, AggregateSymbol parent)
{
PropertySymbol sym = NewBasicSymbol(SYMKIND.SK_PropertySymbol, name, parent) as PropertySymbol;
Debug.Assert(sym != null);
- return (sym);
+ return sym;
}
- public EventSymbol CreateEvent(Name name, AggregateSymbol parent)
+ public static EventSymbol CreateEvent(Name name, AggregateSymbol parent)
{
EventSymbol sym = NewBasicSymbol(SYMKIND.SK_EventSymbol, name, parent) as EventSymbol;
Debug.Assert(sym != null);
- return (sym);
+ return sym;
}
- public TypeParameterSymbol CreateMethodTypeParameter(Name pName, MethodSymbol pParent, int index, int indexTotal)
+ public static TypeParameterSymbol CreateMethodTypeParameter(Name pName, MethodSymbol pParent, int index, int indexTotal)
{
TypeParameterSymbol pResult = (TypeParameterSymbol)NewBasicSymbol(SYMKIND.SK_TypeParameterSymbol, pName, pParent);
pResult.SetIndexInOwnParameters(index);
@@ -179,7 +150,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return pResult;
}
- public TypeParameterSymbol CreateClassTypeParameter(Name pName, AggregateSymbol pParent, int index, int indexTotal)
+ public static TypeParameterSymbol CreateClassTypeParameter(Name pName, AggregateSymbol pParent, int index, int indexTotal)
{
TypeParameterSymbol pResult = (TypeParameterSymbol)NewBasicSymbol(SYMKIND.SK_TypeParameterSymbol, pName, pParent);
pResult.SetIndexInOwnParameters(index);
@@ -191,9 +162,9 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return pResult;
}
- public Scope CreateScope() => (Scope)NewBasicSymbol(SYMKIND.SK_Scope, null, null);
+ public static Scope CreateScope() => (Scope)NewBasicSymbol(SYMKIND.SK_Scope, null, null);
- public IndexerSymbol CreateIndexer(Name name, ParentSymbol parent, Name realName)
+ public static IndexerSymbol CreateIndexer(Name name, ParentSymbol parent)
{
IndexerSymbol sym = (IndexerSymbol)NewBasicSymbol(SYMKIND.SK_IndexerSymbol, name, parent);
sym.setKind(SYMKIND.SK_PropertySymbol);
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/Symbol.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/Symbol.cs
index e9f0380145..6686640d4b 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/Symbol.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/Symbol.cs
@@ -68,6 +68,19 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
public Symbol nextChild; // next child of this parent
public Symbol nextSameName; // next child of this parent with same name.
+ public Symbol LookupNext(symbmask_t kindmask)
+ {
+ // Keep traversing the list of symbols with same name and parent.
+ for (Symbol sym = nextSameName; sym != null; sym = sym.nextSameName)
+ {
+ if ((kindmask & sym.mask()) != 0)
+ {
+ return sym;
+ }
+ }
+
+ return null;
+ }
public ACCESS GetAccess()
{
@@ -149,10 +162,9 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
case SYMKIND.SK_TypeParameterSymbol:
return ((AggregateSymbol)parent).AssociatedAssembly;
- case SYMKIND.SK_AggregateDeclaration:
- return ((AggregateDeclaration)this).GetAssembly();
case SYMKIND.SK_AggregateSymbol:
return ((AggregateSymbol)this).AssociatedAssembly;
+
default:
// Should never call this with any other kind.
Debug.Assert(false, "GetAssemblyID called on bad sym kind");
@@ -174,8 +186,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
case SYMKIND.SK_TypeParameterSymbol:
return ((AggregateSymbol)parent).InternalsVisibleTo(assembly);
- case SYMKIND.SK_AggregateDeclaration:
- return ((AggregateDeclaration)this).Agg().InternalsVisibleTo(assembly);
case SYMKIND.SK_AggregateSymbol:
return ((AggregateSymbol)this).InternalsVisibleTo(assembly);
default:
@@ -191,28 +201,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return assem == sym.GetAssembly() || sym.InternalsVisibleTo(assem);
}
- /* Returns if the symbol is virtual. */
- public bool IsVirtual()
- {
- switch (_kind)
- {
- case SYMKIND.SK_MethodSymbol:
- return ((MethodSymbol)this).isVirtual;
-
- case SYMKIND.SK_EventSymbol:
- MethodSymbol methAdd = ((EventSymbol)this).methAdd;
- return methAdd != null && methAdd.isVirtual;
-
- case SYMKIND.SK_PropertySymbol:
- PropertySymbol prop = ((PropertySymbol)this);
- MethodSymbol meth = prop.GetterMethod ?? prop.SetterMethod;
- return meth != null && meth.isVirtual;
-
- default:
- return false;
- }
- }
-
public bool IsOverride()
{
switch (_kind)
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymbolKind.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymbolKind.cs
index a512d7ab0d..57bc070885 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymbolKind.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymbolKind.cs
@@ -8,7 +8,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
SK_NamespaceSymbol,
SK_AggregateSymbol,
- SK_AggregateDeclaration,
SK_TypeParameterSymbol,
SK_FieldSymbol,
SK_LocalVariableSymbol,
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymbolLoader.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymbolLoader.cs
index 103678206c..cc441dbc4e 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymbolLoader.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymbolLoader.cs
@@ -3,133 +3,35 @@
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
-using Microsoft.CSharp.RuntimeBinder.Errors;
using Microsoft.CSharp.RuntimeBinder.Syntax;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
- internal sealed class SymbolLoader
+ internal static class SymbolLoader
{
- private PredefinedMembers PredefinedMembers { get; }
- private GlobalSymbolContext GlobalSymbolContext { get; }
- public ErrorHandling ErrorContext { get; }
- public SymbolTable RuntimeBinderSymbolTable { get; private set; }
+ public static AggregateSymbol GetPredefAgg(PredefinedType pt) => TypeManager.GetPredefAgg(pt);
- public SymbolLoader()
- {
- GlobalSymbolContext globalSymbols = new GlobalSymbolContext();
- PredefinedMembers = new PredefinedMembers(this);
- ErrorContext = new ErrorHandling(globalSymbols);
- GlobalSymbolContext = globalSymbols;
- Debug.Assert(GlobalSymbolContext != null);
- }
-
- public ErrorHandling GetErrorContext()
- {
- return ErrorContext;
- }
-
- public GlobalSymbolContext GetGlobalSymbolContext()
- {
- return GlobalSymbolContext;
- }
-
- public MethodSymbol LookupInvokeMeth(AggregateSymbol pAggDel)
- {
- Debug.Assert(pAggDel.AggKind() == AggKindEnum.Delegate);
- for (Symbol pSym = LookupAggMember(NameManager.GetPredefinedName(PredefinedName.PN_INVOKE), pAggDel, symbmask_t.MASK_ALL);
- pSym != null;
- pSym = LookupNextSym(pSym, pAggDel, symbmask_t.MASK_ALL))
- {
- if (pSym is MethodSymbol meth && meth.isInvoke())
- {
- return meth;
- }
- }
- return null;
- }
-
- public PredefinedTypes GetPredefindTypes()
- {
- return GlobalSymbolContext.GetPredefTypes();
- }
-
- public TypeManager GetTypeManager()
- {
- return TypeManager;
- }
-
- public TypeManager TypeManager
- {
- get { return GlobalSymbolContext.TypeManager; }
- }
-
- public PredefinedMembers getPredefinedMembers()
- {
- return PredefinedMembers;
- }
-
- public BSYMMGR getBSymmgr()
- {
- return GlobalSymbolContext.GetGlobalSymbols();
- }
-
- public SymFactory GetGlobalSymbolFactory()
- {
- return GlobalSymbolContext.GetGlobalSymbolFactory();
- }
-
- public AggregateSymbol GetPredefAgg(PredefinedType pt) => GetTypeManager().GetPredefAgg(pt);
-
- public AggregateType GetPredefindType(PredefinedType pt) => GetPredefAgg(pt).getThisType();
-
- public Symbol LookupAggMember(Name name, AggregateSymbol agg, symbmask_t mask)
- {
- return getBSymmgr().LookupAggMember(name, agg, mask);
- }
+ public static AggregateType GetPredefindType(PredefinedType pt) => GetPredefAgg(pt).getThisType();
- public static Symbol LookupNextSym(Symbol sym, ParentSymbol parent, symbmask_t kindmask)
- => BSYMMGR.LookupNextSym(sym, parent, kindmask);
-
- // It would be nice to make this a virtual method on typeSym.
- public AggregateType GetAggTypeSym(CType typeSym)
- {
- Debug.Assert(typeSym != null);
- Debug.Assert(typeSym is AggregateType ||
- typeSym is ArrayType ||
- typeSym is NullableType);
-
- switch (typeSym.GetTypeKind())
- {
- case TypeKind.TK_AggregateType:
- return (AggregateType)typeSym;
- case TypeKind.TK_ArrayType:
- return GetPredefindType(PredefinedType.PT_ARRAY);
- case TypeKind.TK_NullableType:
- return ((NullableType)typeSym).GetAts();
- }
- Debug.Assert(false, "Bad typeSym!");
- return null;
- }
+ public static Symbol LookupAggMember(Name name, AggregateSymbol agg, symbmask_t mask) => SymbolStore.LookupSym(name, agg, mask);
private static bool IsBaseInterface(AggregateType atsDer, AggregateType pBase)
{
Debug.Assert(atsDer != null);
Debug.Assert(pBase != null);
- if (pBase.isInterfaceType())
+ if (pBase.IsInterfaceType)
{
while (atsDer != null)
{
- TypeArray ifacesAll = atsDer.GetIfacesAll();
- for (int i = 0; i < ifacesAll.Count; i++)
+ foreach (CType iface in atsDer.IfacesAll.Items)
{
- if (AreTypesEqualForConversion(ifacesAll[i], pBase))
+ if (AreTypesEqualForConversion(iface, pBase))
{
return true;
}
}
- atsDer = atsDer.GetBaseClass();
+ atsDer = atsDer.BaseClass;
}
}
@@ -141,13 +43,9 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Debug.Assert(pDerived != null);
Debug.Assert(pBase != null);
- // This checks to see whether derived is a class, and if so,
+ // This checks to see whether derived is a class, and if so,
// if base is a base class of derived.
- if (!pDerived.isClassType())
- {
- return false;
- }
- return IsBaseClass(pDerived, pBase);
+ return pDerived.IsClassType && IsBaseClass(pDerived, pBase);
}
private static bool IsBaseClass(CType pDerived, CType pBase)
@@ -156,44 +54,49 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Debug.Assert(pBase != null);
// A base class has got to be a class. The derived type might be a struct.
- if (!(pBase is AggregateType atsBase && atsBase.isClassType()))
+ if (!(pBase is AggregateType atsBase && atsBase.IsClassType))
{
return false;
}
- if (pDerived is NullableType derivedNub)
- {
- pDerived = derivedNub.GetAts();
- }
if (!(pDerived is AggregateType atsDer))
{
- return false;
+ if (pDerived is NullableType derivedNub)
+ {
+ atsDer = derivedNub.GetAts();
+ }
+ else
+ {
+ return false;
+ }
}
- AggregateType atsCur = atsDer.GetBaseClass();
+ AggregateType atsCur = atsDer.BaseClass;
while (atsCur != null)
{
if (atsCur == atsBase)
{
return true;
}
- atsCur = atsCur.GetBaseClass();
+
+ atsCur = atsCur.BaseClass;
}
+
return false;
}
- private bool HasCovariantArrayConversion(ArrayType pSource, ArrayType pDest)
+ private static bool HasCovariantArrayConversion(ArrayType pSource, ArrayType pDest)
{
Debug.Assert(pSource != null);
Debug.Assert(pDest != null);
// * S and T differ only in element type. In other words, S and T have the same number of dimensions.
// * Both SE and TE are reference types.
// * An implicit reference conversion exists from SE to TE.
- return (pSource.rank == pDest.rank) && pSource.IsSZArray == pDest.IsSZArray &&
- HasImplicitReferenceConversion(pSource.GetElementType(), pDest.GetElementType());
+ return pSource.Rank == pDest.Rank && pSource.IsSZArray == pDest.IsSZArray &&
+ HasImplicitReferenceConversion(pSource.ElementType, pDest.ElementType);
}
- public bool HasIdentityOrImplicitReferenceConversion(CType pSource, CType pDest)
+ public static bool HasIdentityOrImplicitReferenceConversion(CType pSource, CType pDest)
{
Debug.Assert(pSource != null);
Debug.Assert(pDest != null);
@@ -207,15 +110,11 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
private static bool AreTypesEqualForConversion(CType pType1, CType pType2) => pType1.Equals(pType2);
- private bool HasArrayConversionToInterface(ArrayType pSource, CType pDest)
+ private static bool HasArrayConversionToInterface(ArrayType pSource, CType pDest)
{
Debug.Assert(pSource != null);
Debug.Assert(pDest != null);
- if (!pSource.IsSZArray)
- {
- return false;
- }
- if (!pDest.isInterfaceType())
+ if (!pSource.IsSZArray || !pDest.IsInterfaceType)
{
return false;
}
@@ -231,13 +130,13 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// * The base interface of IReadOnlyList<T> is IReadOnlyCollection<T>.
// * The base interface of IReadOnlyCollection<T> is IEnumerable<T>.
- if (pDest.isPredefType(PredefinedType.PT_IENUMERABLE))
+ if (pDest.IsPredefType(PredefinedType.PT_IENUMERABLE))
{
return true;
}
AggregateType atsDest = (AggregateType)pDest;
- AggregateSymbol aggDest = atsDest.getAggregate();
+ AggregateSymbol aggDest = atsDest.OwningAggregate;
if (!aggDest.isPredefAgg(PredefinedType.PT_G_ILIST) &&
!aggDest.isPredefAgg(PredefinedType.PT_G_ICOLLECTION) &&
!aggDest.isPredefAgg(PredefinedType.PT_G_IENUMERABLE) &&
@@ -247,14 +146,12 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return false;
}
- Debug.Assert(atsDest.GetTypeArgsAll().Count == 1);
+ Debug.Assert(atsDest.TypeArgsAll.Count == 1);
- CType pSourceElement = pSource.GetElementType();
- CType pDestTypeArgument = atsDest.GetTypeArgsAll()[0];
- return HasIdentityOrImplicitReferenceConversion(pSourceElement, pDestTypeArgument);
+ return HasIdentityOrImplicitReferenceConversion(pSource.ElementType, atsDest.TypeArgsAll[0]);
}
- private bool HasImplicitReferenceConversion(CType pSource, CType pDest)
+ private static bool HasImplicitReferenceConversion(CType pSource, CType pDest)
{
Debug.Assert(pSource != null);
Debug.Assert(pDest != null);
@@ -262,7 +159,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// The implicit reference conversions are:
// * From any reference type to Object.
- if (pSource.IsRefType() && pDest.isPredefType(PredefinedType.PT_OBJECT))
+ if (pSource.IsReferenceType && pDest.IsPredefType(PredefinedType.PT_OBJECT))
{
return true;
}
@@ -271,10 +168,10 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
if (pDest is AggregateType aggDest)
{
- switch (aggSource.GetOwningAggregate().AggKind())
+ switch (aggSource.OwningAggregate.AggKind())
{
case AggKindEnum.Class:
- switch (aggDest.GetOwningAggregate().AggKind())
+ switch (aggDest.OwningAggregate.AggKind())
{
case AggKindEnum.Class:
// * From any class type S to any class type T provided S is derived from T.
@@ -298,7 +195,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// convertible to T.
// * From any interface type S to any interface type T provided S implements an interface
// convertible to T.
- // * From any interface type S to any interface type T provided S is not T and S is
+ // * From any interface type S to any interface type T provided S is not T and S is
// an interface convertible to T.
return HasAnyBaseInterfaceConversion(aggSource, aggDest);
@@ -307,10 +204,9 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
break;
case AggKindEnum.Interface:
- if (aggDest.isInterfaceType())
+ if (aggDest.IsInterfaceType)
{
- return HasAnyBaseInterfaceConversion(aggSource, aggDest)
- || HasInterfaceConversion(aggSource, aggDest);
+ return HasAnyBaseInterfaceConversion(aggSource, aggDest) || HasInterfaceConversion(aggSource, aggDest);
}
break;
@@ -322,11 +218,11 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
//
// The spec should actually say
//
- // * From any delegate type to System.Delegate
+ // * From any delegate type to System.Delegate
// * From any delegate type to System.MulticastDelegate
// * From any delegate type to any interface implemented by System.MulticastDelegate
- if (aggDest.isPredefType(PredefinedType.PT_MULTIDEL)
- || aggDest.isPredefType(PredefinedType.PT_DELEGATE) || IsBaseInterface(
+ if (aggDest.IsPredefType(PredefinedType.PT_MULTIDEL)
+ || aggDest.IsPredefType(PredefinedType.PT_DELEGATE) || IsBaseInterface(
GetPredefindType(PredefinedType.PT_MULTIDEL), aggDest))
{
return true;
@@ -335,7 +231,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// VARIANCE EXTENSION:
// * From any delegate type S to a delegate type T provided S is not T and
// S is a delegate convertible to T
- return pDest.isDelegateType() && HasDelegateConversion(aggSource, aggDest);
+ return pDest.IsDelegateType && HasDelegateConversion(aggSource, aggDest);
}
}
}
@@ -354,7 +250,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (pDest is AggregateType aggDest)
{
// * From any array type to System.Array or any interface implemented by System.Array.
- if (aggDest.isPredefType(PredefinedType.PT_ARRAY)
+ if (aggDest.IsPredefType(PredefinedType.PT_ARRAY)
|| IsBaseInterface(GetPredefindType(PredefinedType.PT_ARRAY), aggDest))
{
return true;
@@ -375,19 +271,15 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// implementations have a "null type" which some expressions other than the
// null literal may have. (For example, (null??null), which is also an
// extension to the specification.)
- return pDest.IsRefType() || pDest is NullableType;
+ return pDest.IsReferenceType || pDest is NullableType;
}
return false;
}
- private bool HasAnyBaseInterfaceConversion(CType pDerived, CType pBase)
+ private static bool HasAnyBaseInterfaceConversion(CType pDerived, CType pBase)
{
- if (!pBase.isInterfaceType())
- {
- return false;
- }
- if (!(pDerived is AggregateType atsDer))
+ if (!pBase.IsInterfaceType || !(pDerived is AggregateType atsDer))
{
return false;
}
@@ -395,7 +287,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
AggregateType atsBase = (AggregateType)pBase;
while (atsDer != null)
{
- foreach (AggregateType iface in atsDer.GetIfacesAll().Items)
+ foreach (AggregateType iface in atsDer.IfacesAll.Items)
{
if (HasInterfaceConversion(iface, atsBase))
{
@@ -403,7 +295,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
}
- atsDer = atsDer.GetBaseClass();
+ atsDer = atsDer.BaseClass;
}
return false;
@@ -412,7 +304,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
////////////////////////////////////////////////////////////////////////////////
// The rules for variant interface and delegate conversions are the same:
//
- // An interface/delegate type S is convertible to an interface/delegate type T
+ // An interface/delegate type S is convertible to an interface/delegate type T
// if and only if T is U<S1, ... Sn> and T is U<T1, ... Tn> such that for all
// parameters of U:
//
@@ -422,25 +314,25 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// * if the ith parameter of U is contravariant then either Si is exactly
// equal to Ti, or there is an implicit reference conversion from Ti to Si.
- private bool HasInterfaceConversion(AggregateType pSource, AggregateType pDest)
+ private static bool HasInterfaceConversion(AggregateType pSource, AggregateType pDest)
{
- Debug.Assert(pSource != null && pSource.isInterfaceType());
- Debug.Assert(pDest != null && pDest.isInterfaceType());
+ Debug.Assert(pSource != null && pSource.IsInterfaceType);
+ Debug.Assert(pDest != null && pDest.IsInterfaceType);
return HasVariantConversion(pSource, pDest);
}
//////////////////////////////////////////////////////////////////////////////
- private bool HasDelegateConversion(AggregateType pSource, AggregateType pDest)
+ private static bool HasDelegateConversion(AggregateType pSource, AggregateType pDest)
{
- Debug.Assert(pSource != null && pSource.isDelegateType());
- Debug.Assert(pDest != null && pDest.isDelegateType());
+ Debug.Assert(pSource != null && pSource.IsDelegateType);
+ Debug.Assert(pDest != null && pDest.IsDelegateType);
return HasVariantConversion(pSource, pDest);
}
//////////////////////////////////////////////////////////////////////////////
- private bool HasVariantConversion(AggregateType pSource, AggregateType pDest)
+ private static bool HasVariantConversion(AggregateType pSource, AggregateType pDest)
{
Debug.Assert(pSource != null);
Debug.Assert(pDest != null);
@@ -448,15 +340,16 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
return true;
}
- AggregateSymbol pAggSym = pSource.getAggregate();
- if (pAggSym != pDest.getAggregate())
+
+ AggregateSymbol pAggSym = pSource.OwningAggregate;
+ if (pAggSym != pDest.OwningAggregate)
{
return false;
}
TypeArray pTypeParams = pAggSym.GetTypeVarsAll();
- TypeArray pSourceArgs = pSource.GetTypeArgsAll();
- TypeArray pDestArgs = pDest.GetTypeArgsAll();
+ TypeArray pSourceArgs = pSource.TypeArgsAll;
+ TypeArray pDestArgs = pDest.TypeArgsAll;
Debug.Assert(pTypeParams.Count == pSourceArgs.Count);
Debug.Assert(pTypeParams.Count == pDestArgs.Count);
@@ -493,7 +386,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return true;
}
- private bool HasImplicitBoxingConversion(CType pSource, CType pDest)
+ private static bool HasImplicitBoxingConversion(CType pSource, CType pDest)
{
Debug.Assert(pSource != null);
Debug.Assert(pDest != null);
@@ -502,7 +395,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// The rest of the boxing conversions only operate when going from a value type
// to a reference type.
- if (!pDest.IsRefType())
+ if (!pDest.IsReferenceType)
{
return false;
}
@@ -513,7 +406,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
pSource = nubSource.UnderlyingType; // pSource.IsValType() known to be true.
}
- else if (!pSource.IsValType())
+ else if (!pSource.IsValueType)
{
return false;
}
@@ -530,7 +423,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return IsBaseClass(pSource, pDest) || HasAnyBaseInterfaceConversion(pSource, pDest);
}
- public bool HasBaseConversion(CType pSource, CType pDest)
+ public static bool HasBaseConversion(CType pSource, CType pDest)
{
// By a "base conversion" we mean:
//
@@ -541,9 +434,9 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
//
// In other words, these are conversions that can be made to a base
// class, base interface or co/contravariant type without any change in
- // representation other than boxing. A conversion from, say, int to double,
+ // representation other than boxing. A conversion from, say, int to double,
// is NOT a "base conversion", because representation is changed. A conversion
- // from, say, lambda to expression tree is not a "base conversion" because
+ // from, say, lambda to expression tree is not a "base conversion" because
// do not have a type.
//
// The existence of a base conversion depends solely upon the source and
@@ -551,7 +444,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
//
// This notion is not found in the spec but it is useful in the implementation.
- if (pSource is AggregateType && pDest.isPredefType(PredefinedType.PT_OBJECT))
+ if (pSource is AggregateType && pDest.IsPredefType(PredefinedType.PT_OBJECT))
{
// If we are going from any aggregate type (class, struct, interface, enum or delegate)
// to object, we immediately return true. This may seem like a mere optimization --
@@ -591,9 +484,12 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
foreach (AggregateType iface in derived.GetIfacesAll().Items)
{
- if (iface.getAggregate() == @base)
+ if (iface.OwningAggregate == @base)
+ {
return true;
+ }
}
+
derived = derived.GetBaseAgg();
}
@@ -604,17 +500,14 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
while (derived.GetBaseClass() != null)
{
- derived = derived.GetBaseClass().getAggregate();
+ derived = derived.GetBaseClass().OwningAggregate;
if (derived == @base)
+ {
return true;
+ }
}
- return false;
- }
- internal void SetSymbolTable(SymbolTable symbolTable)
- {
- RuntimeBinderSymbolTable = symbolTable;
+ return false;
}
}
}
-
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymbolManagerBase.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymbolManagerBase.cs
deleted file mode 100644
index 92ee054047..0000000000
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymbolManagerBase.cs
+++ /dev/null
@@ -1,304 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
-using System.Globalization;
-using Microsoft.CSharp.RuntimeBinder.Syntax;
-
-namespace Microsoft.CSharp.RuntimeBinder.Semantics
-{
- internal sealed class BSYMMGR
- {
- // Special nullable members.
- public PropertySymbol propNubValue;
- public MethodSymbol methNubCtor;
-
- private readonly SymFactory _symFactory;
-
- private SYMTBL tableGlobal;
-
- // The hash table for type arrays.
- private Dictionary<TypeArrayKey, TypeArray> tableTypeArrays;
-
- private static readonly TypeArray s_taEmpty = new TypeArray(Array.Empty<CType>());
-
- public BSYMMGR()
- {
- this.tableGlobal = new SYMTBL();
- _symFactory = new SymFactory(this.tableGlobal);
-
- this.tableTypeArrays = new Dictionary<TypeArrayKey, TypeArray>();
-
- ////////////////////////////////////////////////////////////////////////////////
- // Build the data structures needed to make FPreLoad fast. Make sure the
- // namespaces are created. Compute and sort hashes of the NamespaceSymbol * value and type
- // name (sans arity indicator).
-
- for (int i = 0; i < (int)PredefinedType.PT_COUNT; ++i)
- {
- NamespaceSymbol ns = NamespaceSymbol.Root;
- string name = PredefinedTypeFacts.GetName((PredefinedType)i);
- int start = 0;
- while (start < name.Length)
- {
- int iDot = name.IndexOf('.', start);
- if (iDot == -1)
- break;
- string sub = (iDot > start) ? name.Substring(start, iDot - start) : name.Substring(start);
- Name nm = NameManager.Add(sub);
- ns = LookupGlobalSymCore(nm, ns, symbmask_t.MASK_NamespaceSymbol) as NamespaceSymbol ?? _symFactory.CreateNamespace(nm, ns);
- start += sub.Length + 1;
- }
- }
- }
-
- public SYMTBL GetSymbolTable()
- {
- return tableGlobal;
- }
-
- public static TypeArray EmptyTypeArray()
- {
- return s_taEmpty;
- }
-
- public BetterType CompareTypes(TypeArray ta1, TypeArray ta2)
- {
- if (ta1 == ta2)
- {
- return BetterType.Same;
- }
- if (ta1.Count != ta2.Count)
- {
- // The one with more parameters is more specific.
- return ta1.Count > ta2.Count ? BetterType.Left : BetterType.Right;
- }
-
- BetterType nTot = BetterType.Neither;
-
- for (int i = 0; i < ta1.Count; i++)
- {
- CType type1 = ta1[i];
- CType type2 = ta2[i];
- BetterType nParam = BetterType.Neither;
-
- LAgain:
- if (type1.GetTypeKind() != type2.GetTypeKind())
- {
- if (type1 is TypeParameterType)
- {
- nParam = BetterType.Right;
- }
- else if (type2 is TypeParameterType)
- {
- nParam = BetterType.Left;
- }
- }
- else
- {
- switch (type1.GetTypeKind())
- {
- default:
- Debug.Assert(false, "Bad kind in CompareTypes");
- break;
- case TypeKind.TK_TypeParameterType:
- break;
-
- case TypeKind.TK_PointerType:
- case TypeKind.TK_ParameterModifierType:
- case TypeKind.TK_ArrayType:
- case TypeKind.TK_NullableType:
- type1 = type1.GetBaseOrParameterOrElementType();
- type2 = type2.GetBaseOrParameterOrElementType();
- goto LAgain;
-
- case TypeKind.TK_AggregateType:
- nParam = CompareTypes(((AggregateType)type1).GetTypeArgsAll(), ((AggregateType)type2).GetTypeArgsAll());
- break;
- }
- }
-
- if (nParam == BetterType.Right || nParam == BetterType.Left)
- {
- if (nTot == BetterType.Same || nTot == BetterType.Neither)
- {
- nTot = nParam;
- }
- else if (nParam != nTot)
- {
- return BetterType.Neither;
- }
- }
- }
-
- return nTot;
- }
-
- public SymFactory GetSymFactory()
- {
- return _symFactory;
- }
-
- public Symbol LookupGlobalSymCore(Name name, ParentSymbol parent, symbmask_t kindmask)
- {
- return tableGlobal.LookupSym(name, parent, kindmask);
- }
-
- public Symbol LookupAggMember(Name name, AggregateSymbol agg, symbmask_t mask)
- {
- return tableGlobal.LookupSym(name, agg, mask);
- }
-
- public static Symbol LookupNextSym(Symbol sym, ParentSymbol parent, symbmask_t kindmask)
- {
- Debug.Assert(sym.parent == parent);
-
- sym = sym.nextSameName;
- Debug.Assert(sym == null || sym.parent == parent);
-
- // Keep traversing the list of symbols with same name and parent.
- while (sym != null)
- {
- if ((kindmask & sym.mask()) > 0)
- return sym;
-
- sym = sym.nextSameName;
- Debug.Assert(sym == null || sym.parent == parent);
- }
-
- return null;
- }
-
- ////////////////////////////////////////////////////////////////////////////////
- // Allocate a type array; used to represent a parameter list.
- // We use a hash table to make sure that allocating the same type array twice
- // returns the same value. This does two things:
- //
- // 1) Save a lot of memory.
- // 2) Make it so parameter lists can be compared by a simple pointer comparison
- // 3) Allow us to associate a token with each signature for faster metadata emit
-
- private readonly struct TypeArrayKey : IEquatable<TypeArrayKey>
- {
- private readonly CType[] _types;
- private readonly int _hashCode;
-
- public TypeArrayKey(CType[] types)
- {
- _types = types;
- int hashCode = 0x162A16FE;
- foreach (CType type in types)
- {
- hashCode = (hashCode << 5) - hashCode;
- if (type != null)
- {
- hashCode ^= type.GetHashCode();
- }
- }
-
- _hashCode = hashCode;
- }
-
- public bool Equals(TypeArrayKey other)
- {
- CType[] types = _types;
- CType[] otherTypes = other._types;
- if (otherTypes == types)
- {
- return true;
- }
-
- if (other._hashCode != _hashCode || otherTypes.Length != types.Length)
- {
- return false;
- }
-
- for (int i = 0; i < types.Length; i++)
- {
- if (types[i] != otherTypes[i])
- {
- return false;
- }
- }
-
- return true;
- }
-
-#if DEBUG
- [ExcludeFromCodeCoverage] // Typed overload should always be the method called.
-#endif
- public override bool Equals(object obj)
- {
- Debug.Fail("Sub-optimal overload called. Check if this can be avoided.");
- return obj is TypeArrayKey && Equals((TypeArrayKey)obj);
- }
-
- public override int GetHashCode()
- {
- return _hashCode;
- }
- }
-
- public TypeArray AllocParams(int ctype, CType[] prgtype)
- {
- if (ctype == 0)
- {
- return s_taEmpty;
- }
- Debug.Assert(ctype == prgtype.Length);
- return AllocParams(prgtype);
- }
-
- public TypeArray AllocParams(int ctype, TypeArray array, int offset)
- {
- if (ctype == 0)
- {
- return s_taEmpty;
- }
-
- if (ctype == array.Count)
- {
- return array;
- }
-
- CType[] types = array.Items;
- CType[] newTypes = new CType[ctype];
- Array.ConstrainedCopy(types, offset, newTypes, 0, ctype);
- return AllocParams(newTypes);
- }
-
- public TypeArray AllocParams(params CType[] types)
- {
- if (types == null || types.Length == 0)
- {
- return s_taEmpty;
- }
- TypeArrayKey key = new TypeArrayKey(types);
- TypeArray result;
- if (!tableTypeArrays.TryGetValue(key, out result))
- {
- result = new TypeArray(types);
- tableTypeArrays.Add(key, result);
- }
- return result;
- }
-
- private TypeArray ConcatParams(CType[] prgtype1, CType[] prgtype2)
- {
- CType[] combined = new CType[prgtype1.Length + prgtype2.Length];
- Array.Copy(prgtype1, 0, combined, 0, prgtype1.Length);
- Array.Copy(prgtype2, 0, combined, prgtype1.Length, prgtype2.Length);
- return AllocParams(combined);
- }
-
- public TypeArray ConcatParams(TypeArray pta1, TypeArray pta2)
- {
- return ConcatParams(pta1.Items, pta2.Items);
- }
- }
-}
-
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymbolMask.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymbolMask.cs
index bda131b546..b8b74eedf2 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymbolMask.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymbolMask.cs
@@ -17,5 +17,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
MASK_PropertySymbol = 1 << SYMKIND.SK_PropertySymbol,
MASK_EventSymbol = 1 << SYMKIND.SK_EventSymbol,
MASK_ALL = ~0,
+ MASK_Member = MASK_FieldSymbol | MASK_MethodSymbol | MASK_PropertySymbol | MASK_EventSymbol
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymbolTable.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymbolStore.cs
index 5ec3c3b050..dcd4a4992e 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymbolTable.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Symbols/SymbolStore.cs
@@ -13,30 +13,18 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// A symbol table is a helper class used by the symbol manager. There are
// two symbol tables; a global and a local.
- internal sealed class SYMTBL
+ internal static class SymbolStore
{
- /////////////////////////////////////////////////////////////////////////////////
- // Public
+ // The RuntimeBinder uses a global lock when Binding that keeps this dictionary safe.
+ private static readonly Dictionary<Key, Symbol> s_dictionary = new Dictionary<Key, Symbol>();
- public SYMTBL()
+ public static Symbol LookupSym(Name name, ParentSymbol parent, symbmask_t kindmask)
{
- _dictionary = new Dictionary<Key, Symbol>();
+ RuntimeBinder.EnsureLockIsTaken();
+ return s_dictionary.TryGetValue(new Key(name, parent), out Symbol sym) ? FindCorrectKind(sym, kindmask) : null;
}
-
- public Symbol LookupSym(Name name, ParentSymbol parent, symbmask_t kindmask)
- {
- Key k = new Key(name, parent);
- Symbol sym;
-
- if (_dictionary.TryGetValue(k, out sym))
- {
- return FindCorrectKind(sym, kindmask);
- }
-
- return null;
- }
-
- public void InsertChild(ParentSymbol parent, Symbol child)
+
+ public static void InsertChild(ParentSymbol parent, Symbol child)
{
Debug.Assert(child.nextSameName == null);
Debug.Assert(child.parent == null || child.parent == parent);
@@ -46,7 +34,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
InsertChildNoGrow(child);
}
- private void InsertChildNoGrow(Symbol child)
+ private static void InsertChildNoGrow(Symbol child)
{
switch (child.getKind())
{
@@ -55,10 +43,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return;
}
- Key k = new Key(child.name, child.parent);
- Symbol sym;
-
- if (_dictionary.TryGetValue(k, out sym))
+ RuntimeBinder.EnsureLockIsTaken();
+ if (s_dictionary.TryGetValue(new Key(child.name, child.parent), out Symbol sym))
{
// Link onto the end of the symbol chain here.
while (sym?.nextSameName != null)
@@ -71,7 +57,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
else
{
- _dictionary.Add(k, child);
+ s_dictionary.Add(new Key(child.name, child.parent), child);
}
}
@@ -83,15 +69,14 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
return sym;
}
+
sym = sym.nextSameName;
} while (sym != null);
return null;
}
- private readonly Dictionary<Key, Symbol> _dictionary;
-
- private sealed class Key : IEquatable<Key>
+ private readonly struct Key : IEquatable<Key>
{
private readonly Name _name;
private readonly ParentSymbol _parent;
@@ -102,21 +87,18 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
_parent = parent;
}
- public bool Equals(Key other) => other != null && _name.Equals(other._name) && _parent.Equals(other._parent);
+ public bool Equals(Key other) => _name == other._name && _parent == other._parent;
-#if DEBUG
+#if DEBUG
[ExcludeFromCodeCoverage] // Typed overload should always be the method called.
#endif
public override bool Equals(object obj)
{
Debug.Fail("Sub-optimal overload called. Check if this can be avoided.");
- return Equals(obj as Key);
+ return obj is Key key && Equals(key);
}
- public override int GetHashCode()
- {
- return _name.GetHashCode() ^ _parent.GetHashCode();
- }
+ public override int GetHashCode() => _name.GetHashCode() ^ _parent.GetHashCode();
}
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/BoundAnonymousFunction.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/BoundAnonymousFunction.cs
index e5de6dadc3..5fdaac504e 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/BoundAnonymousFunction.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/BoundAnonymousFunction.cs
@@ -12,7 +12,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
: base(ExpressionKind.BoundLambda, type)
{
Debug.Assert(type != null);
- Debug.Assert(type.isDelegateType());
+ Debug.Assert(type.IsDelegateType);
Debug.Assert(argumentScope != null);
ArgumentScope = argumentScope;
Expression = expression;
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Cast.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Cast.cs
index eed4a2b3b8..fc4c67f40b 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Cast.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Cast.cs
@@ -20,5 +20,19 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
public Expr Argument { get; set; }
public bool IsBoxingCast => (Flags & (EXPRFLAG.EXF_BOX | EXPRFLAG.EXF_FORCE_BOX)) != 0;
+
+ public override object Object
+ {
+ get
+ {
+ Expr arg = Argument;
+ while (arg is ExprCast castArg)
+ {
+ arg = castArg.Argument;
+ }
+
+ return arg.Object;
+ }
+ }
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Concatenate.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Concatenate.cs
index 0d94074549..4a379a9e95 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Concatenate.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Concatenate.cs
@@ -14,7 +14,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
Debug.Assert(first?.Type != null);
Debug.Assert(second?.Type != null);
- Debug.Assert(first.Type.isPredefType(PredefinedType.PT_STRING) || second.Type.isPredefType(PredefinedType.PT_STRING));
+ Debug.Assert(first.Type.IsPredefType(PredefinedType.PT_STRING) || second.Type.IsPredefType(PredefinedType.PT_STRING));
FirstArgument = first;
SecondArgument = second;
}
@@ -22,12 +22,12 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
private static CType TypeFromOperands(Expr first, Expr second)
{
CType type = first.Type;
- if (type.isPredefType(PredefinedType.PT_STRING))
+ if (type.IsPredefType(PredefinedType.PT_STRING))
{
return type;
}
- Debug.Assert(second.Type.isPredefType(PredefinedType.PT_STRING));
+ Debug.Assert(second.Type.IsPredefType(PredefinedType.PT_STRING));
return second.Type;
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Constant.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Constant.cs
index 6a115a5f66..0454d3908d 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Constant.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Constant.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
using System.Diagnostics;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
@@ -16,7 +17,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
public Expr OptionalConstructorCall { get; set; }
- public bool IsZero => Val.IsZero(Type.constValKind());
+ public bool IsZero => Val.IsZero(Type.ConstValKind);
public ConstVal Val { get; }
@@ -26,23 +27,85 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
get
{
- switch (Type.fundType())
+ switch (Type.FundamentalType)
{
case FUNDTYPE.FT_I8:
case FUNDTYPE.FT_U8:
return Val.Int64Val;
+
case FUNDTYPE.FT_U4:
return Val.UInt32Val;
- case FUNDTYPE.FT_I1:
- case FUNDTYPE.FT_I2:
- case FUNDTYPE.FT_I4:
- case FUNDTYPE.FT_U1:
- case FUNDTYPE.FT_U2:
+
+ default:
+ Debug.Assert(
+ Type.FundamentalType == FUNDTYPE.FT_I1 || Type.FundamentalType == FUNDTYPE.FT_I2
+ || Type.FundamentalType == FUNDTYPE.FT_I4 || Type.FundamentalType == FUNDTYPE.FT_U1
+ || Type.FundamentalType == FUNDTYPE.FT_U2, "Bad fundType in getI64Value");
return Val.Int32Val;
+ }
+ }
+ }
+
+ public override object Object
+ {
+ get
+ {
+ if (Type is NullType)
+ {
+ return null;
+ }
+
+ object objval;
+ switch (System.Type.GetTypeCode(Type.AssociatedSystemType))
+ {
+ case TypeCode.Boolean:
+ objval = Val.BooleanVal;
+ break;
+ case TypeCode.SByte:
+ objval = Val.SByteVal;
+ break;
+ case TypeCode.Byte:
+ objval = Val.ByteVal;
+ break;
+ case TypeCode.Int16:
+ objval = Val.Int16Val;
+ break;
+ case TypeCode.UInt16:
+ objval = Val.UInt16Val;
+ break;
+ case TypeCode.Int32:
+ objval = Val.Int32Val;
+ break;
+ case TypeCode.UInt32:
+ objval = Val.UInt32Val;
+ break;
+ case TypeCode.Int64:
+ objval = Val.Int64Val;
+ break;
+ case TypeCode.UInt64:
+ objval = Val.UInt64Val;
+ break;
+ case TypeCode.Single:
+ objval = Val.SingleVal;
+ break;
+ case TypeCode.Double:
+ objval = Val.DoubleVal;
+ break;
+ case TypeCode.Decimal:
+ objval = Val.DecimalVal;
+ break;
+ case TypeCode.Char:
+ objval = Val.CharVal;
+ break;
+ case TypeCode.String:
+ objval = Val.StringVal;
+ break;
default:
- Debug.Assert(false, "Bad fundType in getI64Value");
- return 0;
+ objval = Val.ObjectVal;
+ break;
}
+
+ return Type.IsEnumType ? Enum.ToObject(Type.AssociatedSystemType, objval) : objval;
}
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/EXPR.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/EXPR.cs
index eb7223b6fc..f1ef38f58b 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/EXPR.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/EXPR.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
@@ -37,5 +38,15 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
protected set { _type = value; }
}
+
+ [ExcludeFromCodeCoverage] // Should only be called through override.
+ public virtual object Object
+ {
+ get
+ {
+ Debug.Fail("Invalid Expr in GetObject");
+ throw Error.InternalCompilerError();
+ }
+ }
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/ExprWithArgs.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/ExprWithArgs.cs
index eb81fcb9e3..a91db12b24 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/ExprWithArgs.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/ExprWithArgs.cs
@@ -4,7 +4,7 @@
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
- internal abstract class ExprWithArgs : ExprWithType, IExprWithObject
+ internal abstract class ExprWithArgs : ExprWithType
{
protected ExprWithArgs(ExpressionKind kind, CType type)
: base(kind, type)
@@ -13,12 +13,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
public ExprMemberGroup MemberGroup { get; set; }
- public Expr OptionalObject
- {
- get => MemberGroup.OptionalObject;
- set => MemberGroup.OptionalObject = value;
- }
-
public Expr OptionalArguments { get; set; }
public abstract SymWithType GetSymWithType();
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/ExprWithType.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/ExprWithType.cs
index f9ac7c1719..cdc7871d79 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/ExprWithType.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/ExprWithType.cs
@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
+
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
internal abstract class ExprWithType : Expr
@@ -11,5 +13,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
Type = type;
}
+
+ protected static bool TypesAreEqual(Type t1, Type t2) => t1 == t2 || t1.IsEquivalentTo(t2);
}
-} \ No newline at end of file
+}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Field.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Field.cs
index b7d9df12a5..057ac3a4e0 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Field.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Field.cs
@@ -4,12 +4,12 @@
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
- internal sealed class ExprField : ExprWithType, IExprWithObject
+ internal sealed class ExprField : ExprWithType
{
- public ExprField(CType type, Expr optionalObject, FieldWithType field, bool isLValue)
+ public ExprField(CType type, Expr optionalObject, FieldWithType field)
: base(ExpressionKind.Field, type)
{
- Flags = isLValue ? EXPRFLAG.EXF_LVALUE : 0;
+ Flags = field.Field().isReadOnly ? 0 : EXPRFLAG.EXF_LVALUE;
OptionalObject = optionalObject;
FieldWithType = field;
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/MemberGroup.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/MemberGroup.cs
index cc5980acdf..bb946d1d22 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/MemberGroup.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/MemberGroup.cs
@@ -7,10 +7,10 @@ using Microsoft.CSharp.RuntimeBinder.Syntax;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
- internal sealed class ExprMemberGroup : ExprWithType, IExprWithObject
+ internal sealed class ExprMemberGroup : ExprWithType
{
- public ExprMemberGroup(CType type, EXPRFLAG flags, Name name, TypeArray typeArgs, SYMKIND symKind, CType parentType, MethodOrPropertySymbol pMPS, Expr optionalObject, CMemberLookupResults memberLookupResults)
- : base(ExpressionKind.MemberGroup, type)
+ public ExprMemberGroup(EXPRFLAG flags, Name name, TypeArray typeArgs, SYMKIND symKind, CType parentType, Expr optionalObject, CMemberLookupResults memberLookupResults)
+ : base(ExpressionKind.MemberGroup, MethodGroupType.Instance)
{
Debug.Assert(
(flags & ~(EXPRFLAG.EXF_CTOR | EXPRFLAG.EXF_INDEXER | EXPRFLAG.EXF_OPERATOR | EXPRFLAG.EXF_NEWOBJCALL
@@ -18,7 +18,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
| EXPRFLAG.EXF_MASK_ANY)) == 0);
Flags = flags;
Name = name;
- TypeArgs = typeArgs ?? BSYMMGR.EmptyTypeArray();
+ TypeArgs = typeArgs ?? TypeArray.Empty;
SymKind = symKind;
ParentType = parentType;
OptionalObject = optionalObject;
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/MethodInfo.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/MethodInfo.cs
index 4f166c4e6a..b2db9fdc30 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/MethodInfo.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/MethodInfo.cs
@@ -2,7 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
using System.Diagnostics;
+using System.Reflection;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
@@ -17,5 +19,137 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
public MethWithInst Method { get; }
+
+ public MethodInfo MethodInfo
+ {
+ get
+ {
+ // To do this, we need to construct a type array of the parameter types,
+ // get the parent constructed type, and get the method from it.
+ AggregateType aggType = Method.Ats;
+ MethodSymbol methSym = Method.Meth();
+
+ TypeArray genericParams = TypeManager.SubstTypeArray(methSym.Params, aggType, methSym.typeVars);
+ CType genericReturn = TypeManager.SubstType(methSym.RetType, aggType, methSym.typeVars);
+
+ Type type = aggType.AssociatedSystemType;
+ MethodInfo methodInfo = methSym.AssociatedMemberInfo as MethodInfo;
+
+ // This is to ensure that for embedded nopia types, we have the
+ // appropriate local type from the member itself; this is possible
+ // because nopia types are not generic or nested.
+ if (!type.IsGenericType && !type.IsNested)
+ {
+ type = methodInfo.DeclaringType;
+ }
+
+ // We need to find the associated methodinfo on the instantiated type.
+ foreach (MethodInfo m in type.GetRuntimeMethods())
+ {
+#if UNSUPPORTEDAPI
+ if ((m.MetadataToken != methodInfo.MetadataToken) || (m.Module != methodInfo.Module))
+#else
+ if (!m.HasSameMetadataDefinitionAs(methodInfo))
+#endif
+ {
+ continue;
+ }
+
+ Debug.Assert(m.Name == methodInfo.Name &&
+ m.GetParameters().Length == genericParams.Count &&
+ TypesAreEqual(m.ReturnType, genericReturn.AssociatedSystemType));
+
+ bool match = true;
+ ParameterInfo[] parameters = m.GetParameters();
+ for (int i = 0; i < genericParams.Count; i++)
+ {
+ if (!TypesAreEqual(parameters[i].ParameterType, genericParams[i].AssociatedSystemType))
+ {
+ match = false;
+ break;
+ }
+ }
+
+ if (match)
+ {
+ if (m.IsGenericMethod)
+ {
+ int size = Method.TypeArgs?.Count ?? 0;
+ Type[] typeArgs = new Type[size];
+ if (size > 0)
+ {
+ for (int i = 0; i < Method.TypeArgs.Count; i++)
+ {
+ typeArgs[i] = Method.TypeArgs[i].AssociatedSystemType;
+ }
+ }
+
+ return m.MakeGenericMethod(typeArgs);
+ }
+
+ return m;
+ }
+ }
+
+ throw Error.InternalCompilerError();
+ }
+ }
+
+ public ConstructorInfo ConstructorInfo
+ {
+ get
+ {
+ // To do this, we need to construct a type array of the parameter types,
+ // get the parent constructed type, and get the method from it.
+ AggregateType aggType = Method.Ats;
+ MethodSymbol methSym = Method.Meth();
+
+ TypeArray genericInstanceParams = TypeManager.SubstTypeArray(methSym.Params, aggType);
+ Type type = aggType.AssociatedSystemType;
+ ConstructorInfo ctorInfo = (ConstructorInfo)methSym.AssociatedMemberInfo;
+
+ // This is to ensure that for embedded nopia types, we have the
+ // appropriate local type from the member itself; this is possible
+ // because nopia types are not generic or nested.
+ if (!type.IsGenericType && !type.IsNested)
+ {
+ type = ctorInfo.DeclaringType;
+ }
+
+ foreach (ConstructorInfo c in type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
+ {
+#if UNSUPPORTEDAPI
+ if ((c.MetadataToken != ctorInfo.MetadataToken) || (c.Module != ctorInfo.Module))
+#else
+ if (!c.HasSameMetadataDefinitionAs(ctorInfo))
+#endif
+ {
+ continue;
+ }
+
+ Debug.Assert(c.GetParameters() == null || c.GetParameters().Length == genericInstanceParams.Count);
+
+ bool match = true;
+ ParameterInfo[] parameters = c.GetParameters();
+ for (int i = 0; i < genericInstanceParams.Count; i++)
+ {
+ if (!TypesAreEqual(parameters[i].ParameterType, genericInstanceParams[i].AssociatedSystemType))
+ {
+ match = false;
+ break;
+ }
+ }
+
+ if (match)
+ {
+ return c;
+ }
+ }
+
+ throw Error.InternalCompilerError();
+ }
+ }
+
+ public override object Object => MethodInfo;
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Property.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Property.cs
index 1d119647d0..0328e85160 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Property.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Property.cs
@@ -29,6 +29,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (mwtSet != null)
{
MethWithTypeSet = mwtSet;
+ Flags = EXPRFLAG.EXF_LVALUE;
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/PropertyInfo.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/PropertyInfo.cs
index 755228aa0d..5b439c1708 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/PropertyInfo.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/PropertyInfo.cs
@@ -2,7 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
using System.Diagnostics;
+using System.Reflection;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
@@ -17,5 +19,62 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
public PropWithType Property { get; }
+
+ public PropertyInfo PropertyInfo
+ {
+ get
+ {
+ // To do this, we need to construct a type array of the parameter types,
+ // get the parent constructed type, and get the property from it.
+ AggregateType aggType = Property.Ats;
+ PropertySymbol propSym = Property.Prop();
+
+ TypeArray genericInstanceParams = TypeManager.SubstTypeArray(propSym.Params, aggType, null);
+
+ Type type = aggType.AssociatedSystemType;
+ PropertyInfo propertyInfo = propSym.AssociatedPropertyInfo;
+
+ // This is to ensure that for embedded nopia types, we have the
+ // appropriate local type from the member itself; this is possible
+ // because nopia types are not generic or nested.
+ if (!type.IsGenericType && !type.IsNested)
+ {
+ type = propertyInfo.DeclaringType;
+ }
+
+ foreach (PropertyInfo p in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
+ {
+#if UNSUPPORTEDAPI
+ if ((p.MetadataToken != propertyInfo.MetadataToken) || (p.Module != propertyInfo.Module))
+#else
+ if (!p.HasSameMetadataDefinitionAs(propertyInfo))
+ {
+#endif
+ continue;
+ }
+ Debug.Assert((p.Name == propertyInfo.Name) &&
+ (p.GetIndexParameters() == null || p.GetIndexParameters().Length == genericInstanceParams.Count));
+
+ bool match = true;
+ ParameterInfo[] parameters = p.GetSetMethod(true) != null ?
+ p.GetSetMethod(true).GetParameters() : p.GetGetMethod(true).GetParameters();
+ for (int i = 0; i < genericInstanceParams.Count; i++)
+ {
+ if (!TypesAreEqual(parameters[i].ParameterType, genericInstanceParams[i].AssociatedSystemType))
+ {
+ match = false;
+ break;
+ }
+ }
+
+ if (match)
+ {
+ return p;
+ }
+ }
+
+ throw Error.InternalCompilerError();
+ }
+ }
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/TypeOf.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/TypeOf.cs
index 8e4bbe19fb..2ab3e131c6 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/TypeOf.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/TypeOf.cs
@@ -14,5 +14,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
public CType SourceType { get; }
+
+ public override object Object => SourceType.AssociatedSystemType;
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Visitors/ExprVisitorBase.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Visitors/ExprVisitorBase.cs
index 99991ef719..677bbad1c3 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Visitors/ExprVisitorBase.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Visitors/ExprVisitorBase.cs
@@ -8,34 +8,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
internal abstract class ExprVisitorBase
{
- public Expr Visit(Expr pExpr)
- {
- if (pExpr == null)
- {
- return null;
- }
-
- Expr pResult;
- if (IsCachedExpr(pExpr, out pResult))
- {
- return pResult;
- }
-
- return CacheExprMapping(pExpr, Dispatch(pExpr));
- }
-
- private bool IsCachedExpr(Expr pExpr, out Expr pTransformedExpr)
- {
- pTransformedExpr = null;
- return false;
- }
-
- /////////////////////////////////////////////////////////////////////////////////
-
- private Expr CacheExprMapping(Expr pExpr, Expr pTransformedExpr)
- {
- return pTransformedExpr;
- }
+ protected Expr Visit(Expr pExpr) => pExpr == null ? null : Dispatch(pExpr);
protected virtual Expr Dispatch(Expr pExpr)
{
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Visitors/ExpressionTreeRewriter.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Visitors/ExpressionTreeRewriter.cs
index f85ed2595a..58d8e39b40 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Visitors/ExpressionTreeRewriter.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/Visitors/ExpressionTreeRewriter.cs
@@ -9,21 +9,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
internal sealed class ExpressionTreeRewriter : ExprVisitorBase
{
- public static ExprBinOp Rewrite(ExprBoundLambda expr, ExprFactory expressionFactory, SymbolLoader symbolLoader) =>
- new ExpressionTreeRewriter(expressionFactory, symbolLoader).VisitBoundLambda(expr);
-
- private ExprFactory expressionFactory;
- private SymbolLoader symbolLoader;
-
- private ExprFactory GetExprFactory() { return expressionFactory; }
-
- private SymbolLoader GetSymbolLoader() { return symbolLoader; }
-
- private ExpressionTreeRewriter(ExprFactory expressionFactory, SymbolLoader symbolLoader)
- {
- this.expressionFactory = expressionFactory;
- this.symbolLoader = symbolLoader;
- }
+ public static ExprBinOp Rewrite(ExprBoundLambda expr) => new ExpressionTreeRewriter().VisitBoundLambda(expr);
protected override Expr Dispatch(Expr expr)
{
@@ -60,7 +46,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
//
// The LHS becomes Expression.Property(instance, indexerInfo, arguments).
Expr instance = Visit(prop.MemberGroup.OptionalObject);
- Expr propInfo = GetExprFactory().CreatePropertyInfo(prop.PropWithTypeSlot.Prop(), prop.PropWithTypeSlot.Ats);
+ Expr propInfo = ExprFactory.CreatePropertyInfo(prop.PropWithTypeSlot.Prop(), prop.PropWithTypeSlot.Ats);
Expr arguments = GenerateParamsArray(
GenerateArgsList(prop.OptionalArguments),
PredefinedType.PT_EXPRESSION);
@@ -96,8 +82,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
MethodSymbol lambdaMethod = GetPreDefMethod(PREDEFMETH.PM_EXPRESSION_LAMBDA);
AggregateType delegateType = anonmeth.DelegateType;
- TypeArray lambdaTypeParams = GetSymbolLoader().getBSymmgr().AllocParams(1, new CType[] { delegateType });
- AggregateType expressionType = GetSymbolLoader().GetPredefindType(PredefinedType.PT_EXPRESSION);
+ TypeArray lambdaTypeParams = TypeArray.Allocate(delegateType);
+ AggregateType expressionType = SymbolLoader.GetPredefindType(PredefinedType.PT_EXPRESSION);
MethWithInst mwi = new MethWithInst(lambdaMethod, expressionType, lambdaTypeParams);
Expr createParameters = CreateWraps(anonmeth);
Debug.Assert(createParameters != null);
@@ -105,12 +91,12 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Expr body = Visit(anonmeth.Expression);
Debug.Assert(anonmeth.ArgumentScope.nextChild == null);
Expr parameters = GenerateParamsArray(null, PredefinedType.PT_PARAMETEREXPRESSION);
- Expr args = GetExprFactory().CreateList(body, parameters);
- CType typeRet = GetSymbolLoader().GetTypeManager().SubstType(mwi.Meth().RetType, mwi.GetType(), mwi.TypeArgs);
- ExprMemberGroup pMemGroup = GetExprFactory().CreateMemGroup(null, mwi);
- ExprCall call = GetExprFactory().CreateCall(0, typeRet, args, pMemGroup, mwi);
+ Expr args = ExprFactory.CreateList(body, parameters);
+ CType typeRet = TypeManager.SubstType(mwi.Meth().RetType, mwi.GetType(), mwi.TypeArgs);
+ ExprMemberGroup pMemGroup = ExprFactory.CreateMemGroup(null, mwi);
+ ExprCall call = ExprFactory.CreateCall(0, typeRet, args, pMemGroup, mwi);
call.PredefinedMethod = PREDEFMETH.PM_EXPRESSION_LAMBDA;
- return GetExprFactory().CreateSequence(createParameters, call);
+ return ExprFactory.CreateSequence(createParameters, call);
}
protected override Expr VisitCONSTANT(ExprConstant expr)
{
@@ -129,13 +115,13 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Expr pObject;
if (expr.OptionalObject== null)
{
- pObject = GetExprFactory().CreateNull();
+ pObject = ExprFactory.CreateNull();
}
else
{
pObject = Visit(expr.OptionalObject);
}
- ExprFieldInfo pFieldInfo = GetExprFactory().CreateFieldInfo(expr.FieldWithType.Field(), expr.FieldWithType.GetType());
+ ExprFieldInfo pFieldInfo = ExprFactory.CreateFieldInfo(expr.FieldWithType.Field(), expr.FieldWithType.GetType());
return GenerateCall(PREDEFMETH.PM_EXPRESSION_FIELD, pObject, pFieldInfo);
}
protected override Expr VisitUSERDEFINEDCONVERSION(ExprUserDefinedConversion expr)
@@ -153,7 +139,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// we can omit the cast.
if (pArgument.Type == pExpr.Type ||
SymbolLoader.IsBaseClassOfClass(pArgument.Type, pExpr.Type) ||
- CConversions.FImpRefConv(GetSymbolLoader(), pArgument.Type, pExpr.Type))
+ CConversions.FImpRefConv(pArgument.Type, pExpr.Type))
{
return Visit(pArgument);
}
@@ -161,7 +147,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// If we have a cast to PredefinedType.PT_G_EXPRESSION and the thing that we're casting is
// a EXPRBOUNDLAMBDA that is an expression tree, then just visit the expression tree.
if (pExpr.Type != null &&
- pExpr.Type.isPredefType(PredefinedType.PT_G_EXPRESSION) &&
+ pExpr.Type.IsPredefType(PredefinedType.PT_G_EXPRESSION) &&
pArgument is ExprBoundLambda)
{
return Visit(pArgument);
@@ -179,7 +165,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
Debug.Assert(expr != null);
PREDEFMETH pdm;
- if (expr.FirstArgument.Type.isPredefType(PredefinedType.PT_STRING) && expr.SecondArgument.Type.isPredefType(PredefinedType.PT_STRING))
+ if (expr.FirstArgument.Type.IsPredefType(PredefinedType.PT_STRING) && expr.SecondArgument.Type.IsPredefType(PredefinedType.PT_STRING))
{
pdm = PREDEFMETH.PM_STRING_CONCAT_STRING_2;
}
@@ -190,7 +176,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Expr p1 = Visit(expr.FirstArgument);
Expr p2 = Visit(expr.SecondArgument);
MethodSymbol method = GetPreDefMethod(pdm);
- Expr methodInfo = GetExprFactory().CreateMethodInfo(method, GetSymbolLoader().GetPredefindType(PredefinedType.PT_STRING), null);
+ Expr methodInfo = ExprFactory.CreateMethodInfo(method, SymbolLoader.GetPredefindType(PredefinedType.PT_STRING), null);
return GenerateCall(PREDEFMETH.PM_EXPRESSION_ADD_USER_DEFINED, p1, p2, methodInfo);
}
protected override Expr VisitBINOP(ExprBinOp expr)
@@ -260,7 +246,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Expr pObject;
if (expr.MethWithInst.Meth().isStatic || expr.MemberGroup.OptionalObject== null)
{
- pObject = GetExprFactory().CreateNull();
+ pObject = ExprFactory.CreateNull();
}
else
{
@@ -285,7 +271,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
pObject = Visit(pObject);
}
- Expr methodInfo = GetExprFactory().CreateMethodInfo(expr.MethWithInst);
+ Expr methodInfo = ExprFactory.CreateMethodInfo(expr.MethWithInst);
Expr args = GenerateArgsList(expr.OptionalArguments);
Expr Params = GenerateParamsArray(args, PredefinedType.PT_EXPRESSION);
PREDEFMETH pdm = PREDEFMETH.PM_EXPRESSION_CALL;
@@ -299,13 +285,13 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Expr pObject;
if (expr.PropWithTypeSlot.Prop().isStatic || expr.MemberGroup.OptionalObject== null)
{
- pObject = GetExprFactory().CreateNull();
+ pObject = ExprFactory.CreateNull();
}
else
{
pObject = Visit(expr.MemberGroup.OptionalObject);
}
- Expr propInfo = GetExprFactory().CreatePropertyInfo(expr.PropWithTypeSlot.Prop(), expr.PropWithTypeSlot.GetType());
+ Expr propInfo = ExprFactory.CreatePropertyInfo(expr.PropWithTypeSlot.Prop(), expr.PropWithTypeSlot.GetType());
if (expr.OptionalArguments != null)
{
// It is an indexer property. Turn it into a virtual method call.
@@ -319,7 +305,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
Debug.Assert(expr != null);
// POSSIBLE ERROR: Multi-d should be an error?
- Expr pTypeOf = CreateTypeOf(((ArrayType)expr.Type).GetElementType());
+ Expr pTypeOf = CreateTypeOf(((ArrayType)expr.Type).ElementType);
Expr args = GenerateArgsList(expr.OptionalArguments);
Expr Params = GenerateParamsArray(args, PredefinedType.PT_EXPRESSION);
return GenerateCall(PREDEFMETH.PM_EXPRESSION_NEWARRAYINIT, pTypeOf, Params);
@@ -399,32 +385,32 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
CType convertL = null;
CType convertR = null;
- if (typeL.isEnumType())
+ if (typeL.IsEnumType)
{
// We have already inserted casts if not lifted, so we should never see an enum.
Debug.Assert(expr.IsLifted);
- convertL = GetSymbolLoader().GetTypeManager().GetNullable(typeL.underlyingEnumType());
+ convertL = TypeManager.GetNullable(typeL.UnderlyingEnumType);
typeL = convertL;
didEnumConversion = true;
}
- else if (typeL is NullableType nubL && nubL.UnderlyingType.isEnumType())
+ else if (typeL is NullableType nubL && nubL.UnderlyingType.IsEnumType)
{
Debug.Assert(expr.IsLifted);
- convertL = GetSymbolLoader().GetTypeManager().GetNullable(nubL.UnderlyingType.underlyingEnumType());
+ convertL = TypeManager.GetNullable(nubL.UnderlyingType.UnderlyingEnumType);
typeL = convertL;
didEnumConversion = true;
}
- if (typeR.isEnumType())
+ if (typeR.IsEnumType)
{
Debug.Assert(expr.IsLifted);
- convertR = GetSymbolLoader().GetTypeManager().GetNullable(typeR.underlyingEnumType());
+ convertR = TypeManager.GetNullable(typeR.UnderlyingEnumType);
typeR = convertR;
didEnumConversion = true;
}
- else if (typeR is NullableType nubR && nubR.UnderlyingType.isEnumType())
+ else if (typeR is NullableType nubR && nubR.UnderlyingType.IsEnumType)
{
Debug.Assert(expr.IsLifted);
- convertR = GetSymbolLoader().GetTypeManager().GetNullable(nubR.UnderlyingType.underlyingEnumType());
+ convertR = TypeManager.GetNullable(nubR.UnderlyingType.UnderlyingEnumType);
typeR = convertR;
didEnumConversion = true;
}
@@ -448,7 +434,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Expr call = GenerateCall(pdm, newL, newR);
- if (didEnumConversion && expr.Type.StripNubs().isEnumType())
+ if (didEnumConversion && expr.Type.StripNubs().IsEnumType)
{
call = GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, call, CreateTypeOf(expr.Type));
}
@@ -475,7 +461,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Expr origOp = expr.Child;
// Such operations are always already casts on operations on casts.
- Debug.Assert(!(origOp.Type is NullableType nub) || !nub.UnderlyingType.isEnumType());
+ Debug.Assert(!(origOp.Type is NullableType nub) || !nub.UnderlyingType.IsEnumType);
return GenerateCall(pdm, Visit(origOp));
}
@@ -546,7 +532,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
p1 = Visit(p1);
p2 = Visit(p2);
FixLiftedUserDefinedBinaryOperators(expr, ref p1, ref p2);
- Expr methodInfo = GetExprFactory().CreateMethodInfo(expr.UserDefinedCallMethod);
+ Expr methodInfo = ExprFactory.CreateMethodInfo(expr.UserDefinedCallMethod);
Expr call = GenerateCall(pdm, p1, p2, methodInfo);
// Delegate add/subtract generates a call to Combine/Remove, which returns System.Delegate,
// not the operand delegate CType. We must cast to the delegate CType.
@@ -598,7 +584,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
throw Error.InternalCompilerError();
}
Expr op = Visit(arg);
- Expr methodInfo = GetExprFactory().CreateMethodInfo(expr.UserDefinedCallMethod);
+ Expr methodInfo = ExprFactory.CreateMethodInfo(expr.UserDefinedCallMethod);
if (expr.Kind == ExpressionKind.Inc || expr.Kind == ExpressionKind.Dec ||
expr.Kind == ExpressionKind.DecimalInc || expr.Kind == ExpressionKind.DecimalDec)
@@ -642,17 +628,15 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
p1 = Visit(p1);
p2 = Visit(p2);
FixLiftedUserDefinedBinaryOperators(expr, ref p1, ref p2);
- Expr lift = GetExprFactory().CreateBoolConstant(false); // We never lift to null in C#.
- Expr methodInfo = GetExprFactory().CreateMethodInfo(expr.UserDefinedCallMethod);
+ Expr lift = ExprFactory.CreateBoolConstant(false); // We never lift to null in C#.
+ Expr methodInfo = ExprFactory.CreateMethodInfo(expr.UserDefinedCallMethod);
return GenerateCall(pdm, p1, p2, lift, methodInfo);
}
- private Expr GenerateConversion(Expr arg, CType CType, bool bChecked)
- {
- return GenerateConversionWithSource(Visit(arg), CType, bChecked || arg.isChecked());
- }
+ private Expr GenerateConversion(Expr arg, CType CType, bool bChecked) =>
+ GenerateConversionWithSource(Visit(arg), CType, bChecked || arg.isChecked());
- private Expr GenerateConversionWithSource(Expr pTarget, CType pType, bool bChecked)
+ private static Expr GenerateConversionWithSource(Expr pTarget, CType pType, bool bChecked)
{
PREDEFMETH pdm = bChecked ? PREDEFMETH.PM_EXPRESSION_CONVERTCHECKED : PREDEFMETH.PM_EXPRESSION_CONVERT;
Expr pTypeOf = CreateTypeOf(pType);
@@ -673,7 +657,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return GenerateUserDefinedConversion(arg, type, target, method);
}
- private Expr GenerateUserDefinedConversion(Expr arg, CType CType, Expr target, MethWithInst method)
+ private static Expr GenerateUserDefinedConversion(Expr arg, CType CType, Expr target, MethWithInst method)
{
// The user-defined explicit conversion from enum? to decimal or decimal? requires
// that we convert the enum? to its nullable underlying CType.
@@ -685,8 +669,8 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// represented in the Expr tree so that this is more transparent.
// converting an enum to its underlying CType never fails, so no need to check it.
- CType underlyingType = arg.Type.StripNubs().underlyingEnumType();
- CType nullableType = GetSymbolLoader().GetTypeManager().GetNullable(underlyingType);
+ CType underlyingType = arg.Type.StripNubs().UnderlyingEnumType;
+ CType nullableType = TypeManager.GetNullable(underlyingType);
Expr typeofNubEnum = CreateTypeOf(nullableType);
target = GenerateCall(PREDEFMETH.PM_EXPRESSION_CONVERT, target, typeofNubEnum);
}
@@ -696,12 +680,12 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// e.g. if we have a user-defined conversion from int to S? and we have (S)myint, then we need to generate
// Convert(Convert(myint, typeof(S?), op_implicit), typeof(S))
- CType pMethodReturnType = GetSymbolLoader().GetTypeManager().SubstType(method.Meth().RetType,
+ CType pMethodReturnType = TypeManager.SubstType(method.Meth().RetType,
method.GetType(), method.TypeArgs);
bool fDontLiftReturnType = (pMethodReturnType == CType || (IsNullableValueType(arg.Type) && IsNullableValueType(CType)));
Expr typeofInner = CreateTypeOf(fDontLiftReturnType ? CType : pMethodReturnType);
- Expr methodInfo = GetExprFactory().CreateMethodInfo(method);
+ Expr methodInfo = ExprFactory.CreateMethodInfo(method);
PREDEFMETH pdmInner = arg.isChecked() ? PREDEFMETH.PM_EXPRESSION_CONVERTCHECKED_USER_DEFINED : PREDEFMETH.PM_EXPRESSION_CONVERT_USER_DEFINED;
Expr callUserDefinedConversion = GenerateCall(pdmInner, target, typeofInner, methodInfo);
@@ -763,25 +747,19 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return GenerateUserDefinedConversion(pCastArgument, pExpr.Type, pConversionSource, pExpr.UserDefinedCallMethod);
}
- private Expr GenerateParameter(string name, CType CType)
+ private static Expr GenerateParameter(string name, CType CType)
{
- GetSymbolLoader().GetPredefindType(PredefinedType.PT_STRING); // force an ensure state
- ExprConstant nameString = GetExprFactory().CreateStringConstant(name);
+ SymbolLoader.GetPredefindType(PredefinedType.PT_STRING); // force an ensure state
+ ExprConstant nameString = ExprFactory.CreateStringConstant(name);
ExprTypeOf pTypeOf = CreateTypeOf(CType);
return GenerateCall(PREDEFMETH.PM_EXPRESSION_PARAMETER, pTypeOf, nameString);
}
- private MethodSymbol GetPreDefMethod(PREDEFMETH pdm)
- {
- return GetSymbolLoader().getPredefinedMembers().GetMethod(pdm);
- }
+ private static MethodSymbol GetPreDefMethod(PREDEFMETH pdm) => PredefinedMembers.GetMethod(pdm);
- private ExprTypeOf CreateTypeOf(CType CType)
- {
- return GetExprFactory().CreateTypeOf(CType);
- }
+ private static ExprTypeOf CreateTypeOf(CType type) => ExprFactory.CreateTypeOf(type);
- private Expr CreateWraps(ExprBoundLambda anonmeth)
+ private static Expr CreateWraps(ExprBoundLambda anonmeth)
{
Expr sequence = null;
for (Symbol sym = anonmeth.ArgumentScope.firstChild; sym != null; sym = sym.nextChild)
@@ -793,15 +771,15 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Debug.Assert(anonmeth.Expression != null);
Expr create = GenerateParameter(local.name.Text, local.GetType());
- local.wrap = GetExprFactory().CreateWrap(create);
- Expr save = GetExprFactory().CreateSave(local.wrap);
+ local.wrap = ExprFactory.CreateWrap(create);
+ Expr save = ExprFactory.CreateSave(local.wrap);
if (sequence == null)
{
sequence = save;
}
else
{
- sequence = GetExprFactory().CreateSequence(sequence, save);
+ sequence = ExprFactory.CreateSequence(sequence, save);
}
}
@@ -812,7 +790,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
Debug.Assert(expr != null);
Debug.Assert(expr.MethWithInst.Meth().IsConstructor());
- Expr constructorInfo = GetExprFactory().CreateMethodInfo(expr.MethWithInst);
+ Expr constructorInfo = ExprFactory.CreateMethodInfo(expr.MethWithInst);
Expr args = GenerateArgsList(expr.OptionalArguments);
Expr Params = GenerateParamsArray(args, PredefinedType.PT_EXPRESSION);
return GenerateCall(PREDEFMETH.PM_EXPRESSION_NEW, constructorInfo, Params);
@@ -825,14 +803,14 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
for (ExpressionIterator it = new ExpressionIterator(oldArgs); !it.AtEnd(); it.MoveNext())
{
Expr oldArg = it.Current();
- GetExprFactory().AppendItemToList(Visit(oldArg), ref newArgs, ref newArgsTail);
+ ExprFactory.AppendItemToList(Visit(oldArg), ref newArgs, ref newArgsTail);
}
return newArgs;
}
private Expr GenerateIndexList(Expr oldIndices)
{
- CType intType = symbolLoader.GetPredefindType(PredefinedType.PT_INT);
+ CType intType = SymbolLoader.GetPredefindType(PredefinedType.PT_INT);
Expr newIndices = null;
Expr newIndicesTail = newIndices;
@@ -841,20 +819,20 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Expr newIndex = it.Current();
if (newIndex.Type != intType)
{
- newIndex = expressionFactory.CreateCast(EXPRFLAG.EXF_INDEXEXPR, intType, newIndex);
+ newIndex = ExprFactory.CreateCast(EXPRFLAG.EXF_INDEXEXPR, intType, newIndex);
newIndex.Flags |= EXPRFLAG.EXF_CHECKOVERFLOW;
}
Expr rewrittenIndex = Visit(newIndex);
- expressionFactory.AppendItemToList(rewrittenIndex, ref newIndices, ref newIndicesTail);
+ ExprFactory.AppendItemToList(rewrittenIndex, ref newIndices, ref newIndicesTail);
}
return newIndices;
}
- private Expr GenerateConstant(Expr expr)
+ private static Expr GenerateConstant(Expr expr)
{
EXPRFLAG flags = 0;
- AggregateType pObject = GetSymbolLoader().GetPredefindType(PredefinedType.PT_OBJECT);
+ AggregateType pObject = SymbolLoader.GetPredefindType(PredefinedType.PT_OBJECT);
if (expr.Type is NullType)
{
@@ -862,85 +840,85 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return GenerateCall(PREDEFMETH.PM_EXPRESSION_CONSTANT_OBJECT_TYPE, expr, pTypeOf);
}
- AggregateType stringType = GetSymbolLoader().GetPredefindType(PredefinedType.PT_STRING);
+ AggregateType stringType = SymbolLoader.GetPredefindType(PredefinedType.PT_STRING);
if (expr.Type != stringType)
{
flags = EXPRFLAG.EXF_BOX;
}
- ExprCast cast = GetExprFactory().CreateCast(flags, pObject, expr);
+ ExprCast cast = ExprFactory.CreateCast(flags, pObject, expr);
ExprTypeOf pTypeOf2 = CreateTypeOf(expr.Type);
return GenerateCall(PREDEFMETH.PM_EXPRESSION_CONSTANT_OBJECT_TYPE, cast, pTypeOf2);
}
- private ExprCall GenerateCall(PREDEFMETH pdm, Expr arg1)
+ private static ExprCall GenerateCall(PREDEFMETH pdm, Expr arg1)
{
MethodSymbol method = GetPreDefMethod(pdm);
// this should be enforced in an earlier pass and the transform pass should not
// be handling this error
if (method == null)
return null;
- AggregateType expressionType = GetSymbolLoader().GetPredefindType(PredefinedType.PT_EXPRESSION);
+ AggregateType expressionType = SymbolLoader.GetPredefindType(PredefinedType.PT_EXPRESSION);
MethWithInst mwi = new MethWithInst(method, expressionType);
- ExprMemberGroup pMemGroup = GetExprFactory().CreateMemGroup(null, mwi);
- ExprCall call = GetExprFactory().CreateCall(0, mwi.Meth().RetType, arg1, pMemGroup, mwi);
+ ExprMemberGroup pMemGroup = ExprFactory.CreateMemGroup(null, mwi);
+ ExprCall call = ExprFactory.CreateCall(0, mwi.Meth().RetType, arg1, pMemGroup, mwi);
call.PredefinedMethod = pdm;
return call;
}
- private ExprCall GenerateCall(PREDEFMETH pdm, Expr arg1, Expr arg2)
+ private static ExprCall GenerateCall(PREDEFMETH pdm, Expr arg1, Expr arg2)
{
MethodSymbol method = GetPreDefMethod(pdm);
if (method == null)
return null;
- AggregateType expressionType = GetSymbolLoader().GetPredefindType(PredefinedType.PT_EXPRESSION);
- Expr args = GetExprFactory().CreateList(arg1, arg2);
+ AggregateType expressionType = SymbolLoader.GetPredefindType(PredefinedType.PT_EXPRESSION);
+ Expr args = ExprFactory.CreateList(arg1, arg2);
MethWithInst mwi = new MethWithInst(method, expressionType);
- ExprMemberGroup pMemGroup = GetExprFactory().CreateMemGroup(null, mwi);
- ExprCall call = GetExprFactory().CreateCall(0, mwi.Meth().RetType, args, pMemGroup, mwi);
+ ExprMemberGroup pMemGroup = ExprFactory.CreateMemGroup(null, mwi);
+ ExprCall call = ExprFactory.CreateCall(0, mwi.Meth().RetType, args, pMemGroup, mwi);
call.PredefinedMethod = pdm;
return call;
}
- private ExprCall GenerateCall(PREDEFMETH pdm, Expr arg1, Expr arg2, Expr arg3)
+ private static ExprCall GenerateCall(PREDEFMETH pdm, Expr arg1, Expr arg2, Expr arg3)
{
MethodSymbol method = GetPreDefMethod(pdm);
if (method == null)
return null;
- AggregateType expressionType = GetSymbolLoader().GetPredefindType(PredefinedType.PT_EXPRESSION);
- Expr args = GetExprFactory().CreateList(arg1, arg2, arg3);
+ AggregateType expressionType = SymbolLoader.GetPredefindType(PredefinedType.PT_EXPRESSION);
+ Expr args = ExprFactory.CreateList(arg1, arg2, arg3);
MethWithInst mwi = new MethWithInst(method, expressionType);
- ExprMemberGroup pMemGroup = GetExprFactory().CreateMemGroup(null, mwi);
- ExprCall call = GetExprFactory().CreateCall(0, mwi.Meth().RetType, args, pMemGroup, mwi);
+ ExprMemberGroup pMemGroup = ExprFactory.CreateMemGroup(null, mwi);
+ ExprCall call = ExprFactory.CreateCall(0, mwi.Meth().RetType, args, pMemGroup, mwi);
call.PredefinedMethod = pdm;
return call;
}
- private ExprCall GenerateCall(PREDEFMETH pdm, Expr arg1, Expr arg2, Expr arg3, Expr arg4)
+ private static ExprCall GenerateCall(PREDEFMETH pdm, Expr arg1, Expr arg2, Expr arg3, Expr arg4)
{
MethodSymbol method = GetPreDefMethod(pdm);
if (method == null)
return null;
- AggregateType expressionType = GetSymbolLoader().GetPredefindType(PredefinedType.PT_EXPRESSION);
- Expr args = GetExprFactory().CreateList(arg1, arg2, arg3, arg4);
+ AggregateType expressionType = SymbolLoader.GetPredefindType(PredefinedType.PT_EXPRESSION);
+ Expr args = ExprFactory.CreateList(arg1, arg2, arg3, arg4);
MethWithInst mwi = new MethWithInst(method, expressionType);
- ExprMemberGroup pMemGroup = GetExprFactory().CreateMemGroup(null, mwi);
- ExprCall call = GetExprFactory().CreateCall(0, mwi.Meth().RetType, args, pMemGroup, mwi);
+ ExprMemberGroup pMemGroup = ExprFactory.CreateMemGroup(null, mwi);
+ ExprCall call = ExprFactory.CreateCall(0, mwi.Meth().RetType, args, pMemGroup, mwi);
call.PredefinedMethod = pdm;
return call;
}
- private ExprArrayInit GenerateParamsArray(Expr args, PredefinedType pt)
+ private static ExprArrayInit GenerateParamsArray(Expr args, PredefinedType pt)
{
int parameterCount = ExpressionIterator.Count(args);
- AggregateType paramsArrayElementType = GetSymbolLoader().GetPredefindType(pt);
- ArrayType paramsArrayType = GetSymbolLoader().GetTypeManager().GetArray(paramsArrayElementType, 1, true);
- ExprConstant paramsArrayArg = GetExprFactory().CreateIntegerConstant(parameterCount);
- return GetExprFactory().CreateArrayInit(paramsArrayType, args, paramsArrayArg, new int[] { parameterCount }, parameterCount);
+ AggregateType paramsArrayElementType = SymbolLoader.GetPredefindType(pt);
+ ArrayType paramsArrayType = TypeManager.GetArray(paramsArrayElementType, 1, true);
+ ExprConstant paramsArrayArg = ExprFactory.CreateIntegerConstant(parameterCount);
+ return ExprFactory.CreateArrayInit(paramsArrayType, args, paramsArrayArg, new int[] { parameterCount }, parameterCount);
}
- private void FixLiftedUserDefinedBinaryOperators(ExprBinOp expr, ref Expr pp1, ref Expr pp2)
+ private static void FixLiftedUserDefinedBinaryOperators(ExprBinOp expr, ref Expr pp1, ref Expr pp2)
{
// If we have lifted T1 op T2 to T1? op T2?, and we have an expression T1 op T2? or T1? op T2 then
// we need to ensure that the unlifted actual arguments are promoted to their nullable CType.
@@ -961,15 +939,15 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
CType aatype2 = orig2.Type;
// Is the operator even a candidate for lifting?
if (!(fptype1 is AggregateType fat1)
- || !fat1.getAggregate().IsValueType()
+ || !fat1.OwningAggregate.IsValueType()
|| !(fptype2 is AggregateType fat2)
- || !fat2.getAggregate().IsValueType())
+ || !fat2.OwningAggregate.IsValueType())
{
return;
}
- CType nubfptype1 = GetSymbolLoader().GetTypeManager().GetNullable(fptype1);
- CType nubfptype2 = GetSymbolLoader().GetTypeManager().GetNullable(fptype2);
+ CType nubfptype1 = TypeManager.GetNullable(fptype1);
+ CType nubfptype2 = TypeManager.GetNullable(fptype2);
// If we have null op X, or T1 op T2?, or T1 op null, lift first arg to T1?
if (aatype1 is NullType || aatype1 == fptype1 && (aatype2 == nubfptype2 || aatype2 is NullType))
{
@@ -985,16 +963,16 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
pp2 = new2;
}
- private bool IsNullableValueType(CType pType) =>
- pType is NullableType && pType.StripNubs() is AggregateType agg && agg.getAggregate().IsValueType();
+ private static bool IsNullableValueType(CType pType) =>
+ pType is NullableType && pType.StripNubs() is AggregateType agg && agg.OwningAggregate.IsValueType();
- private bool IsNullableValueAccess(Expr pExpr, Expr pObject)
+ private static bool IsNullableValueAccess(Expr pExpr, Expr pObject)
{
Debug.Assert(pExpr != null);
return pExpr is ExprProperty prop && prop.MemberGroup.OptionalObject == pObject && pObject.Type is NullableType;
}
private static bool isEnumToDecimalConversion(CType argtype, CType desttype) =>
- argtype.StripNubs().isEnumType() && desttype.StripNubs().isPredefType(PredefinedType.PT_DECIMAL);
+ argtype.StripNubs().IsEnumType && desttype.StripNubs().IsPredefType(PredefinedType.PT_DECIMAL);
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/ZeroInitialize.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/ZeroInitialize.cs
index 66051b6ce2..4bff9bdeb6 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/ZeroInitialize.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Tree/ZeroInitialize.cs
@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
+
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
internal sealed class ExprZeroInit : ExprWithType
@@ -10,5 +12,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
: base(ExpressionKind.ZeroInit, type)
{
}
+
+ public override object Object => Activator.CreateInstance(Type.AssociatedSystemType);
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/TypeBind.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/TypeBind.cs
index 40a3ac8ef6..3f21c176e2 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/TypeBind.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/TypeBind.cs
@@ -18,7 +18,6 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
None = 0x00,
Outer = 0x01,
- NoDupErrors = 0x02,
NoErrors = 0x04,
}
@@ -33,134 +32,150 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
internal static class TypeBind
{
// Check the constraints of any type arguments in the given Type.
- public static bool CheckConstraints(CSemanticChecker checker, ErrorHandling errHandling, CType type, CheckConstraintsFlags flags)
+ public static bool CheckConstraints(CType type, CheckConstraintsFlags flags)
{
type = type.GetNakedType(false);
- if (type is NullableType nub)
+ if (!(type is AggregateType ats))
{
- type = nub.GetAts();
+ if (type is NullableType nub)
+ {
+ ats = nub.GetAts();
+ }
+ else
+ {
+ return true;
+ }
}
- if (!(type is AggregateType ats))
- return true;
-
- if (ats.GetTypeArgsAll().Count == 0)
+ if (ats.TypeArgsAll.Count == 0)
{
// Common case: there are no type vars, so there are no constraints.
- ats.fConstraintsChecked = true;
- ats.fConstraintError = false;
+ ats.ConstraintError = false;
return true;
}
- if (ats.fConstraintsChecked)
+ // Already checked.
+ if (ats.ConstraintError.HasValue)
{
- // Already checked.
- if (!ats.fConstraintError || (flags & CheckConstraintsFlags.NoDupErrors) != 0)
+ // No errors
+ if (!ats.ConstraintError.GetValueOrDefault())
+ {
+ return true;
+ }
+
+ // We want the result, not an exception.
+ if ((flags & CheckConstraintsFlags.NoErrors) != 0)
{
- // No errors or no need to report errors again.
- return !ats.fConstraintError;
+ return false;
}
}
- TypeArray typeVars = ats.getAggregate().GetTypeVars();
- TypeArray typeArgsThis = ats.GetTypeArgsThis();
- TypeArray typeArgsAll = ats.GetTypeArgsAll();
+ TypeArray typeVars = ats.OwningAggregate.GetTypeVars();
+ TypeArray typeArgsThis = ats.TypeArgsThis;
+ TypeArray typeArgsAll = ats.TypeArgsAll;
Debug.Assert(typeVars.Count == typeArgsThis.Count);
- if (!ats.fConstraintsChecked)
- {
- ats.fConstraintsChecked = true;
- ats.fConstraintError = false;
- }
-
// Check the outer type first. If CheckConstraintsFlags.Outer is not specified and the
// outer type has already been checked then don't bother checking it.
- if (ats.outerType != null && ((flags & CheckConstraintsFlags.Outer) != 0 || !ats.outerType.fConstraintsChecked))
+ if (ats.OuterType != null && ((flags & CheckConstraintsFlags.Outer) != 0 || !ats.OuterType.ConstraintError.HasValue))
{
- CheckConstraints(checker, errHandling, ats.outerType, flags);
- ats.fConstraintError |= ats.outerType.fConstraintError;
+ if (!CheckConstraints(ats.OuterType, flags))
+ {
+ ats.ConstraintError = true;
+ return false;
+ }
}
if (typeVars.Count > 0)
- ats.fConstraintError |= !CheckConstraintsCore(checker, errHandling, ats.getAggregate(), typeVars, typeArgsThis, typeArgsAll, null, (flags & CheckConstraintsFlags.NoErrors));
+ {
+ if (!CheckConstraintsCore(ats.OwningAggregate, typeVars, typeArgsThis, typeArgsAll, null, flags & CheckConstraintsFlags.NoErrors))
+ {
+ ats.ConstraintError = true;
+ return false;
+ }
+ }
// Now check type args themselves.
for (int i = 0; i < typeArgsThis.Count; i++)
{
CType arg = typeArgsThis[i].GetNakedType(true);
- if (arg is AggregateType atArg && !atArg.fConstraintsChecked)
+ if (arg is AggregateType atArg && !atArg.ConstraintError.HasValue)
{
- CheckConstraints(checker, errHandling, atArg, flags | CheckConstraintsFlags.Outer);
- if (atArg.fConstraintError)
- ats.fConstraintError = true;
+ CheckConstraints(atArg, flags | CheckConstraintsFlags.Outer);
+ if (atArg.ConstraintError.GetValueOrDefault())
+ {
+ ats.ConstraintError = true;
+ return false;
+ }
}
}
- return !ats.fConstraintError;
+
+ ats.ConstraintError = false;
+ return true;
}
////////////////////////////////////////////////////////////////////////////////
// Check the constraints on the method instantiation.
- public static void CheckMethConstraints(CSemanticChecker checker, ErrorHandling errCtx, MethWithInst mwi)
+ public static void CheckMethConstraints(MethWithInst mwi)
{
Debug.Assert(mwi.Meth() != null && mwi.GetType() != null && mwi.TypeArgs != null);
Debug.Assert(mwi.Meth().typeVars.Count == mwi.TypeArgs.Count);
- Debug.Assert(mwi.GetType().getAggregate() == mwi.Meth().getClass());
+ Debug.Assert(mwi.GetType().OwningAggregate == mwi.Meth().getClass());
if (mwi.TypeArgs.Count > 0)
{
- CheckConstraintsCore(checker, errCtx, mwi.Meth(), mwi.Meth().typeVars, mwi.TypeArgs, mwi.GetType().GetTypeArgsAll(), mwi.TypeArgs, CheckConstraintsFlags.None);
+ CheckConstraintsCore(mwi.Meth(), mwi.Meth().typeVars, mwi.TypeArgs, mwi.GetType().TypeArgsAll, mwi.TypeArgs, CheckConstraintsFlags.None);
}
}
+
////////////////////////////////////////////////////////////////////////////////
// Check whether typeArgs satisfies the constraints of typeVars. The
// typeArgsCls and typeArgsMeth are used for substitution on the bounds. The
// tree and symErr are used for error reporting.
-
- private static bool CheckConstraintsCore(CSemanticChecker checker, ErrorHandling errHandling, Symbol symErr, TypeArray typeVars, TypeArray typeArgs, TypeArray typeArgsCls, TypeArray typeArgsMeth, CheckConstraintsFlags flags)
+ private static bool CheckConstraintsCore(Symbol symErr, TypeArray typeVars, TypeArray typeArgs, TypeArray typeArgsCls, TypeArray typeArgsMeth, CheckConstraintsFlags flags)
{
Debug.Assert(typeVars.Count == typeArgs.Count);
Debug.Assert(typeVars.Count > 0);
Debug.Assert(flags == CheckConstraintsFlags.None || flags == CheckConstraintsFlags.NoErrors);
- bool fError = false;
-
for (int i = 0; i < typeVars.Count; i++)
{
// Empty bounds should be set to object.
TypeParameterType var = (TypeParameterType)typeVars[i];
CType arg = typeArgs[i];
- bool fOK = CheckSingleConstraint(checker, errHandling, symErr, var, arg, typeArgsCls, typeArgsMeth, flags);
- fError |= !fOK;
+ if (!CheckSingleConstraint(symErr, var, arg, typeArgsCls, typeArgsMeth, flags))
+ {
+ return false;
+ }
}
- return !fError;
+ return true;
}
- private static bool CheckSingleConstraint(CSemanticChecker checker, ErrorHandling errHandling, Symbol symErr, TypeParameterType var, CType arg, TypeArray typeArgsCls, TypeArray typeArgsMeth, CheckConstraintsFlags flags)
+ private static bool CheckSingleConstraint(Symbol symErr, TypeParameterType var, CType arg, TypeArray typeArgsCls, TypeArray typeArgsMeth, CheckConstraintsFlags flags)
{
Debug.Assert(!(arg is PointerType));
- Debug.Assert(!arg.isStaticClass());
+ Debug.Assert(!arg.IsStaticClass);
bool fReportErrors = 0 == (flags & CheckConstraintsFlags.NoErrors);
- bool fError = false;
- if (var.HasRefConstraint() && !arg.IsRefType())
+ if (var.HasRefConstraint && !arg.IsReferenceType)
{
if (fReportErrors)
{
- throw errHandling.Error(ErrorCode.ERR_RefConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg);
+ throw ErrorHandling.Error(ErrorCode.ERR_RefConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg);
}
- fError = true;
+ return false;
}
- TypeArray bnds = checker.SymbolLoader.GetTypeManager().SubstTypeArray(var.GetBounds(), typeArgsCls, typeArgsMeth);
+ TypeArray bnds = TypeManager.SubstTypeArray(var.Bounds, typeArgsCls, typeArgsMeth);
int itypeMin = 0;
- if (var.HasValConstraint())
+ if (var.HasValConstraint)
{
// If we have a type variable that is constrained to a value type, then we
// want to check if its a nullable type, so that we can report the
@@ -170,18 +185,18 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// To check whether or not its a nullable type, we need to get the resolved
// bound from the type argument and check against that.
- if (!arg.IsValType() || arg is NullableType)
+ if (!arg.IsNonNullableValueType)
{
if (fReportErrors)
{
- throw errHandling.Error(ErrorCode.ERR_ValConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg);
+ throw ErrorHandling.Error(ErrorCode.ERR_ValConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg);
}
- fError = true;
+ return false;
}
// Since FValCon() is set it is redundant to check System.ValueType as well.
- if (bnds.Count != 0 && bnds[0].isPredefType(PredefinedType.PT_VALUE))
+ if (bnds.Count != 0 && bnds[0].IsPredefType(PredefinedType.PT_VALUE))
{
itypeMin = 1;
}
@@ -190,7 +205,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
for (int j = itypeMin; j < bnds.Count; j++)
{
CType typeBnd = bnds[j];
- if (!SatisfiesBound(checker, arg, typeBnd))
+ if (!SatisfiesBound(arg, typeBnd))
{
if (fReportErrors)
{
@@ -205,17 +220,17 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// and b) Nullable is one funky type, and user's can use all the help they can get
// when using it.
ErrorCode error;
- if (arg.IsRefType())
+ if (arg.IsReferenceType)
{
// A reference type can only satisfy bounds to types
// to which they have an implicit reference conversion
error = ErrorCode.ERR_GenericConstraintNotSatisfiedRefType;
}
- else if (arg is NullableType nubArg && checker.SymbolLoader.HasBaseConversion(nubArg.GetUnderlyingType(), typeBnd)) // This is inlining FBoxingConv
+ else if (arg is NullableType nubArg && SymbolLoader.HasBaseConversion(nubArg.UnderlyingType, typeBnd)) // This is inlining FBoxingConv
{
// nullable types do not satisfy bounds to every type that they are boxable to
// They only satisfy bounds of object and ValueType
- if (typeBnd.isPredefType(PredefinedType.PT_ENUM) || nubArg.GetUnderlyingType() == typeBnd)
+ if (typeBnd.IsPredefType(PredefinedType.PT_ENUM) || nubArg.UnderlyingType == typeBnd)
{
// Nullable types don't satisfy bounds of EnumType, or the underlying type of the enum
// even though the conversion from Nullable to these types is a boxing conversion
@@ -231,7 +246,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// even when there is a boxing conversion from the Nullable type to
// the interface type. This will be a relatively common scenario
// so we cal it out separately from the previous case.
- Debug.Assert(typeBnd.isInterfaceType());
+ Debug.Assert(typeBnd.IsInterfaceType);
error = ErrorCode.ERR_GenericConstraintNotSatisfiedNullableInterface;
}
}
@@ -242,38 +257,38 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
error = ErrorCode.ERR_GenericConstraintNotSatisfiedValType;
}
- throw errHandling.Error(error, new ErrArg(symErr), new ErrArg(typeBnd, ErrArgFlags.Unique), var, new ErrArg(arg, ErrArgFlags.Unique));
+ throw ErrorHandling.Error(error, new ErrArg(symErr), new ErrArg(typeBnd, ErrArgFlags.Unique), var, new ErrArg(arg, ErrArgFlags.Unique));
}
- fError = true;
+ return false;
}
}
// Check the newable constraint.
- if (!var.HasNewConstraint() || arg.IsValType())
+ if (!var.HasNewConstraint || arg.IsValueType)
{
- return !fError;
+ return true;
}
- if (arg.isClassType())
+ if (arg.IsClassType)
{
- AggregateSymbol agg = ((AggregateType)arg).getAggregate();
+ AggregateSymbol agg = ((AggregateType)arg).OwningAggregate;
// Due to late binding nature of IDE created symbols, the AggregateSymbol might not
// have all the information necessary yet, if it is not fully bound.
// by calling LookupAggMember, it will ensure that we will update all the
// information necessary at least for the given method.
- checker.SymbolLoader.LookupAggMember(NameManager.GetPredefinedName(PredefinedName.PN_CTOR), agg, symbmask_t.MASK_ALL);
+ SymbolLoader.LookupAggMember(NameManager.GetPredefinedName(PredefinedName.PN_CTOR), agg, symbmask_t.MASK_ALL);
if (agg.HasPubNoArgCtor() && !agg.IsAbstract())
{
- return !fError;
+ return true;
}
}
if (fReportErrors)
{
- throw errHandling.Error(ErrorCode.ERR_NewConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg);
+ throw ErrorHandling.Error(ErrorCode.ERR_NewConstraintNotSatisfied, symErr, new ErrArgNoRef(var), arg);
}
return false;
@@ -284,12 +299,12 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// typeBnd could be just about any type (since we added naked type parameter
// constraints).
- private static bool SatisfiesBound(CSemanticChecker checker, CType arg, CType typeBnd)
+ private static bool SatisfiesBound(CType arg, CType typeBnd)
{
if (typeBnd == arg)
return true;
- switch (typeBnd.GetTypeKind())
+ switch (typeBnd.TypeKind)
{
default:
Debug.Assert(false, "Unexpected type.");
@@ -313,7 +328,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
Debug.Assert(typeBnd is AggregateType || typeBnd is TypeParameterType || typeBnd is ArrayType);
- switch (arg.GetTypeKind())
+ switch (arg.TypeKind)
{
default:
return false;
@@ -326,7 +341,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
case TypeKind.TK_TypeParameterType:
case TypeKind.TK_ArrayType:
case TypeKind.TK_AggregateType:
- return checker.SymbolLoader.HasBaseConversion(arg, typeBnd);
+ return SymbolLoader.HasBaseConversion(arg, typeBnd);
}
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/AggregateType.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/AggregateType.cs
index cdc7501642..6934cae864 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/AggregateType.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/AggregateType.cs
@@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using Microsoft.CSharp.RuntimeBinder.Syntax;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
@@ -17,84 +18,114 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
internal sealed class AggregateType : CType
{
- private TypeArray _pTypeArgsThis;
- private TypeArray _pTypeArgsAll; // includes args from outer types
- private AggregateSymbol _pOwningAggregate;
-
private AggregateType _baseType; // This is the result of calling SubstTypeArray on the aggregate's baseClass.
private TypeArray _ifacesAll; // This is the result of calling SubstTypeArray on the aggregate's ifacesAll.
private TypeArray _winrtifacesAll; //This is the list of collection interfaces implemented by a WinRT object.
+ private Type _associatedSystemType;
- public bool fConstraintsChecked; // Have the constraints been checked yet?
- public bool fConstraintError; // Did the constraints check produce an error?
+ public AggregateType(AggregateSymbol parent, TypeArray typeArgsThis, AggregateType outerType)
+ : base(TypeKind.TK_AggregateType)
+ {
- // These two flags are used to track hiding within interfaces.
- // Their use and validity is always localized. See e.g. MemberLookup::LookupInInterfaces.
- public bool fAllHidden; // All members are hidden by a derived interface member.
- public bool fDiffHidden; // Members other than a specific kind are hidden by a derived interface member or class member.
+ Debug.Assert(typeArgsThis != null);
+ OuterType = outerType;
+ OwningAggregate = parent;
+ TypeArgsThis = typeArgsThis;
- public AggregateType outerType; // the outer type if this is a nested type
+ // Here we need to check our current type args. If we have an open placeholder,
+ // then we need to have all open placeholders, and we want to flush
+ // our outer type args so that they're open placeholders.
+ //
+ // This is because of the following scenario:
+ //
+ // class B<T>
+ // {
+ // class C<U>
+ // {
+ // }
+ // class D
+ // {
+ // void Foo()
+ // {
+ // Type T = typeof(C<>);
+ // }
+ // }
+ // }
+ //
+ // The outer type will be B<T>, but the inner type will be C<>. However,
+ // this will eventually be represented in IL as B<>.C<>. As such, we should
+ // keep our data structures clear - if we have one open type argument, then
+ // all of them must be open type arguments.
+ //
+ // Ensure that invariant here.
- public void SetOwningAggregate(AggregateSymbol agg)
- {
- _pOwningAggregate = agg;
+ Debug.Assert(outerType == null || outerType.TypeArgsAll != null);
+ TypeArgsAll = outerType != null ? TypeArray.Concat(outerType.TypeArgsAll, typeArgsThis) : typeArgsThis;
}
- public AggregateSymbol GetOwningAggregate()
- {
- return _pOwningAggregate;
- }
+ public bool? ConstraintError; // Did the constraints check produce an error?
+
+ // These two flags are used to track hiding within interfaces.
+ // Their use and validity is always localized. See e.g. MemberLookup::LookupInInterfaces.
+ public bool AllHidden; // All members are hidden by a derived interface member.
+ public bool DiffHidden; // Members other than a specific kind are hidden by a derived interface member or class member.
+
+ public AggregateType OuterType { get; } // the outer type if this is a nested type
- public AggregateType GetBaseClass()
+ public AggregateSymbol OwningAggregate { get; }
+
+ public AggregateType BaseClass
{
- if (_baseType == null)
+ get
{
- Type baseSysType = AssociatedSystemType.BaseType;
- if (baseSysType == null)
+ if (_baseType == null)
{
- return null;
+ Type baseSysType = AssociatedSystemType.BaseType;
+ if (baseSysType == null)
+ {
+ return null;
+ }
+
+ // If we have a generic type definition, then we need to set the
+ // base class to be our current base type, and use that to calculate
+ // our agg type and its base, then set it to be the generic version of the
+ // base type. This is because:
+ //
+ // Suppose we have Foo<T> : IFoo<T>
+ //
+ // Initially, the BaseType will be IFoo<Foo.T>, which gives us the substitution
+ // that we want to use for our agg type's base type. However, in the Symbol chain,
+ // we want the base type to be IFoo<IFoo.T>. So we need to substitute.
+ //
+ // If we don't have a generic type definition, then we just need to set our base
+ // class. This is so that if we have a base type that's generic, we'll be
+ // getting the correctly instantiated base type.
+ AggregateType baseClass = SymbolTable.GetCTypeFromType(baseSysType) as AggregateType;
+ Debug.Assert(baseClass != null);
+ _baseType = TypeManager.SubstType(baseClass, TypeArgsAll);
}
- // If we have a generic type definition, then we need to set the
- // base class to be our current base type, and use that to calculate
- // our agg type and its base, then set it to be the generic version of the
- // base type. This is because:
- //
- // Suppose we have Foo<T> : IFoo<T>
- //
- // Initially, the BaseType will be IFoo<Foo.T>, which gives us the substitution
- // that we want to use for our agg type's base type. However, in the Symbol chain,
- // we want the base type to be IFoo<IFoo.T>. So we need to substitute.
- //
- // If we don't have a generic type definition, then we just need to set our base
- // class. This is so that if we have a base type that's generic, we'll be
- // getting the correctly instantiated base type.
- TypeManager manager = GetOwningAggregate().GetTypeManager();
- AggregateType baseClass = manager.SymbolTable.GetCTypeFromType(baseSysType) as AggregateType;
- Debug.Assert(baseClass != null);
- _baseType = manager.SubstType(baseClass, GetTypeArgsAll());
+ return _baseType;
}
-
- return _baseType;
}
public IEnumerable<AggregateType> TypeHierarchy
{
get
{
- if (isInterfaceType())
+ if (IsInterfaceType)
{
yield return this;
- foreach (AggregateType iface in GetIfacesAll().Items)
+ foreach (AggregateType iface in IfacesAll.Items)
{
yield return iface;
}
- yield return getAggregate().GetTypeManager().ObjectAggregateType;
+ yield return PredefinedTypes.GetPredefinedAggregate(PredefinedType.PT_OBJECT).getThisType();
}
else
{
- for (AggregateType agg = this; agg != null; agg = agg.GetBaseClass())
+ for (AggregateType agg = this; agg != null; agg = agg.BaseClass)
{
yield return agg;
}
@@ -102,102 +133,259 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
}
- public void SetTypeArgsThis(TypeArray pTypeArgsThis)
+ public TypeArray TypeArgsThis { get; }
+
+ public TypeArray TypeArgsAll { get; }
+
+ public TypeArray IfacesAll => _ifacesAll ?? (_ifacesAll = TypeManager.SubstTypeArray(OwningAggregate.GetIfacesAll(), TypeArgsAll));
+
+ private bool IsCollectionType
{
- TypeArray pOuterTypeArgs;
- if (outerType != null)
+ get
{
- Debug.Assert(outerType.GetTypeArgsThis() != null);
- Debug.Assert(outerType.GetTypeArgsAll() != null);
+ Type sysType = AssociatedSystemType;
+ if (sysType.IsGenericType)
+ {
+ Type genType = sysType.GetGenericTypeDefinition();
+ return genType == typeof(IList<>)
+ || genType == typeof(ICollection<>)
+ || genType == typeof(IEnumerable<>)
+ || genType == typeof(IReadOnlyList<>)
+ || genType == typeof(IReadOnlyCollection<>)
+ || genType == typeof(IDictionary<,>)
+ || genType == typeof(IReadOnlyDictionary<,>);
+ }
- pOuterTypeArgs = outerType.GetTypeArgsAll();
+ return sysType == typeof(System.Collections.IList)
+ || sysType == typeof(System.Collections.ICollection)
+ || sysType == typeof(System.Collections.IEnumerable)
+ || sysType == typeof(System.Collections.Specialized.INotifyCollectionChanged)
+ || sysType == typeof(System.ComponentModel.INotifyPropertyChanged);
}
- else
+ }
+
+ public TypeArray WinRTCollectionIfacesAll
+ {
+ get
{
- pOuterTypeArgs = BSYMMGR.EmptyTypeArray();
+ if (_winrtifacesAll == null)
+ {
+ List<CType> typeList = new List<CType>();
+ foreach (AggregateType type in IfacesAll.Items)
+ {
+ Debug.Assert(type.IsInterfaceType);
+ if (type.IsCollectionType)
+ {
+ typeList.Add(type);
+ }
+ }
+
+ _winrtifacesAll = TypeArray.Allocate(typeList.ToArray());
+ }
+
+ return _winrtifacesAll;
}
+ }
+
+ public override bool IsReferenceType => OwningAggregate.IsRefType();
+
+ public override bool IsNonNullableValueType => IsValueType;
+
+ public override bool IsValueType => OwningAggregate.IsValueType();
- Debug.Assert(pTypeArgsThis != null);
- _pTypeArgsThis = pTypeArgsThis;
- SetTypeArgsAll(pOuterTypeArgs);
+ public override bool IsStaticClass => OwningAggregate.IsStatic();
+
+ public override bool IsPredefined => OwningAggregate.IsPredefined();
+
+ public override PredefinedType PredefinedType
+ {
+ get
+ {
+ Debug.Assert(IsPredefined);
+ return OwningAggregate.GetPredefType();
+ }
}
- private void SetTypeArgsAll(TypeArray outerTypeArgs)
+ public override bool IsPredefType(PredefinedType pt)
{
- Debug.Assert(_pTypeArgsThis != null);
+ AggregateSymbol agg = OwningAggregate;
+ return agg.IsPredefined() && agg.GetPredefType() == pt;
+ }
- // Here we need to check our current type args. If we have an open placeholder,
- // then we need to have all open placeholders, and we want to flush
- // our outer type args so that they're open placeholders.
- //
- // This is because of the following scenario:
- //
- // class B<T>
- // {
- // class C<U>
- // {
- // }
- // class D
- // {
- // void Foo()
- // {
- // Type T = typeof(C<>);
- // }
- // }
- // }
- //
- // The outer type will be B<T>, but the inner type will be C<>. However,
- // this will eventually be represented in IL as B<>.C<>. As such, we should
- // keep our data structures clear - if we have one open type argument, then
- // all of them must be open type arguments.
- //
- // Ensure that invariant here.
+ public override bool IsDelegateType => OwningAggregate.IsDelegate();
+
+ public override bool IsSimpleType
+ {
+ get
+ {
+ AggregateSymbol agg = OwningAggregate;
+ return agg.IsPredefined() && PredefinedTypeFacts.IsSimpleType(agg.GetPredefType());
+ }
+ }
- TypeArray pCheckedOuterTypeArgs = outerTypeArgs;
- TypeManager pTypeManager = getAggregate().GetTypeManager();
- _pTypeArgsAll = pTypeManager.ConcatenateTypeArrays(pCheckedOuterTypeArgs, _pTypeArgsThis);
+ public override bool IsSimpleOrEnum
+ {
+ get
+ {
+ AggregateSymbol agg = OwningAggregate;
+ return agg.IsPredefined() ? PredefinedTypeFacts.IsSimpleType(agg.GetPredefType()) : agg.IsEnum();
+ }
}
- public TypeArray GetTypeArgsThis()
+ public override bool IsSimpleOrEnumOrString
{
- return _pTypeArgsThis;
+ get
+ {
+ AggregateSymbol agg = OwningAggregate;
+ if (agg.IsPredefined())
+ {
+ PredefinedType pt = agg.GetPredefType();
+ return PredefinedTypeFacts.IsSimpleType(pt) || pt == PredefinedType.PT_STRING;
+ }
+
+ return agg.IsEnum();
+ }
}
- public TypeArray GetTypeArgsAll()
+ public override bool IsNumericType
{
- return _pTypeArgsAll;
+ get
+ {
+ AggregateSymbol agg = OwningAggregate;
+ return agg.IsPredefined() && PredefinedTypeFacts.IsNumericType(agg.GetPredefType());
+ }
}
- public TypeArray GetIfacesAll()
+ public override bool IsStructOrEnum
{
- if (_ifacesAll == null)
+ get
{
- _ifacesAll = getAggregate().GetTypeManager().SubstTypeArray(getAggregate().GetIfacesAll(), GetTypeArgsAll());
+ AggregateSymbol agg = OwningAggregate;
+ return agg.IsStruct() || agg.IsEnum();
}
- return _ifacesAll;
}
- public TypeArray GetWinRTCollectionIfacesAll(SymbolLoader pSymbolLoader)
+ public override bool IsStructType => OwningAggregate.IsStruct();
+
+ public override bool IsEnumType => OwningAggregate.IsEnum();
+
+ public override bool IsInterfaceType => OwningAggregate.IsInterface();
+
+ public override bool IsClassType => OwningAggregate.IsClass();
+
+ public override AggregateType UnderlyingEnumType
{
- if (_winrtifacesAll == null)
+ get
{
- TypeArray ifaces = GetIfacesAll();
- System.Collections.Generic.List<CType> typeList = new System.Collections.Generic.List<CType>();
+ Debug.Assert(IsEnumType);
+ return OwningAggregate.GetUnderlyingType();
+ }
+ }
- for (int i = 0; i < ifaces.Count; i++)
- {
- AggregateType type = ifaces[i] as AggregateType;
- Debug.Assert(type.isInterfaceType());
+ public override Type AssociatedSystemType => _associatedSystemType ?? (_associatedSystemType = CalculateAssociatedSystemType());
- if (type.IsCollectionType())
+ private Type CalculateAssociatedSystemType()
+ {
+ Type uninstantiatedType = OwningAggregate.AssociatedSystemType;
+ if (uninstantiatedType.IsGenericType)
+ {
+ // Get each type arg.
+ TypeArray typeArgs = TypeArgsAll;
+ Type[] systemTypeArgs = new Type[typeArgs.Count];
+ for (int i = 0; i < systemTypeArgs.Length; i++)
+ {
+ // Unnamed type parameter types are just placeholders.
+ CType typeArg = typeArgs[i];
+ if (typeArg is TypeParameterType typeParamArg && typeParamArg.Symbol.name == null)
{
- typeList.Add(type);
+ return null;
}
+
+ systemTypeArgs[i] = typeArg.AssociatedSystemType;
+ }
+
+ try
+ {
+ return uninstantiatedType.MakeGenericType(systemTypeArgs);
+ }
+ catch (ArgumentException)
+ {
+ // If the constraints don't work, just return the type without substituting it.
}
- _winrtifacesAll = pSymbolLoader.getBSymmgr().AllocParams(typeList.Count, typeList.ToArray());
}
- return _winrtifacesAll;
+
+ return uninstantiatedType;
}
+
+ public override FUNDTYPE FundamentalType
+ {
+ get
+ {
+ AggregateSymbol sym = OwningAggregate;
+
+ // Treat enums like their underlying types.
+ if (sym.IsEnum())
+ {
+ sym = sym.GetUnderlyingType().OwningAggregate;
+ }
+ else if (!sym.IsStruct())
+ {
+ return FUNDTYPE.FT_REF; // Interfaces, classes, delegates are reference types.
+ }
+
+ // Struct type could be predefined (int, long, etc.) or some other struct.
+ return sym.IsPredefined() ? PredefinedTypeFacts.GetFundType(sym.GetPredefType()) : FUNDTYPE.FT_STRUCT;
+ }
+ }
+
+ public override ConstValKind ConstValKind
+ {
+ get
+ {
+ if (IsPredefType(PredefinedType.PT_INTPTR) || IsPredefType(PredefinedType.PT_UINTPTR))
+ {
+ return ConstValKind.IntPtr;
+ }
+
+ switch (FundamentalType)
+ {
+ case FUNDTYPE.FT_I8:
+ case FUNDTYPE.FT_U8:
+ return ConstValKind.Long;
+
+ case FUNDTYPE.FT_STRUCT:
+
+ // Here we can either have a decimal type, or an enum
+ // whose fundamental type is decimal.
+ Debug.Assert(
+ OwningAggregate.IsEnum() && OwningAggregate.GetUnderlyingType().PredefinedType == PredefinedType.PT_DECIMAL
+ || IsPredefined && PredefinedType == PredefinedType.PT_DATETIME
+ || IsPredefined && PredefinedType == PredefinedType.PT_DECIMAL);
+
+ return IsPredefined && PredefinedType == PredefinedType.PT_DATETIME
+ ? ConstValKind.Long
+ : ConstValKind.Decimal;
+
+ case FUNDTYPE.FT_REF:
+ return IsPredefined && PredefinedType == PredefinedType.PT_STRING
+ ? ConstValKind.String
+ : ConstValKind.IntPtr;
+
+ case FUNDTYPE.FT_R4:
+ return ConstValKind.Float;
+
+ case FUNDTYPE.FT_R8:
+ return ConstValKind.Double;
+
+ case FUNDTYPE.FT_I1:
+ return ConstValKind.Boolean;
+
+ default:
+ return ConstValKind.Int;
+ }
+ }
+ }
+
+ public override AggregateType GetAts() => this;
}
}
-
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/ArgumentListType.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/ArgumentListType.cs
index 860792294c..7c176163f9 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/ArgumentListType.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/ArgumentListType.cs
@@ -10,5 +10,12 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// ----------------------------------------------------------------------------
internal sealed class ArgumentListType : CType
- { };
+ {
+ public static readonly ArgumentListType Instance = new ArgumentListType();
+
+ private ArgumentListType()
+ : base(TypeKind.TK_ArgumentListType)
+ {
+ }
+ }
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/ArrayType.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/ArrayType.cs
index 3546c27a51..75ba3ac07e 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/ArrayType.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/ArrayType.cs
@@ -2,6 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
+using Microsoft.CSharp.RuntimeBinder.Syntax;
+
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
// ----------------------------------------------------------------------------
@@ -10,27 +13,54 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
internal sealed class ArrayType : CType
{
- // rank of the array. zero means unknown rank int [?].
- public int rank;
+ public ArrayType(CType elementType, int rank, bool isSZArray)
+ : base(TypeKind.TK_ArrayType)
+ {
+ Rank = rank;
+ IsSZArray = isSZArray;
+ ElementType = elementType;
+ }
+
+ public int Rank { get; }
- public bool IsSZArray { get; set; }
+ public bool IsSZArray { get; }
- public CType GetElementType() { return _pElementType; }
- public void SetElementType(CType pType) { _pElementType = pType; }
+ public CType ElementType { get; }
// Returns the first non-array type in the parent chain.
- public CType GetBaseElementType()
+ public CType BaseElementType
{
- CType type = GetElementType();
- while (type is ArrayType arr)
+ get
{
- type = arr.GetElementType();
+ CType type = ElementType;
+ while (type is ArrayType arr)
+ {
+ type = arr.ElementType;
+ }
+
+ return type;
}
+ }
+
+ public override bool IsReferenceType => true;
+
+ public override bool IsUnsafe() => BaseElementType is PointerType;
- return type;
+ public override Type AssociatedSystemType
+ {
+ get
+ {
+ Type elementType = ElementType.AssociatedSystemType;
+ return IsSZArray ? elementType.MakeArrayType() : elementType.MakeArrayType(Rank);
+ }
}
- private CType _pElementType;
+ public override CType BaseOrParameterOrElementType => ElementType;
+
+ public override FUNDTYPE FundamentalType => FUNDTYPE.FT_REF;
+
+ public override ConstValKind ConstValKind => ConstValKind.IntPtr;
+
+ public override AggregateType GetAts() => SymbolLoader.GetPredefindType(PredefinedType.PT_ARRAY);
}
}
-
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/MethodGroupType.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/MethodGroupType.cs
index 71ed798070..8a75eb32ce 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/MethodGroupType.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/MethodGroupType.cs
@@ -10,5 +10,12 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// ----------------------------------------------------------------------------
internal sealed class MethodGroupType : CType
- { };
+ {
+ public static readonly MethodGroupType Instance = new MethodGroupType();
+
+ private MethodGroupType()
+ : base(TypeKind.TK_MethodGroupType)
+ {
+ }
+ }
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/NullType.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/NullType.cs
index 1490197951..35e1215cbb 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/NullType.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/NullType.cs
@@ -10,5 +10,17 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
internal sealed class NullType : CType
{
+ public static readonly NullType Instance = new NullType();
+
+ private NullType()
+ : base(TypeKind.TK_NullType)
+ {
+ }
+
+ public override bool IsReferenceType => true;
+
+ public override FUNDTYPE FundamentalType => FUNDTYPE.FT_REF;
+
+ public override ConstValKind ConstValKind => ConstValKind.IntPtr;
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/NullableType.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/NullableType.cs
index 089b2b5cf6..d0fab063df 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/NullableType.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/NullableType.cs
@@ -2,7 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using Microsoft.CSharp.RuntimeBinder.Errors;
+using System;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
@@ -16,24 +18,16 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
internal sealed class NullableType : CType
{
- private AggregateType ats;
- public BSYMMGR symmgr;
- public TypeManager typeManager;
+ private AggregateType _ats;
- public AggregateType GetAts()
+ public NullableType(CType underlyingType)
+ : base(TypeKind.TK_NullableType)
{
- if (ats == null)
- {
- AggregateSymbol aggNullable = typeManager.GetNullable();
- CType typePar = GetUnderlyingType();
- CType[] typeParArray = { typePar };
- TypeArray ta = symmgr.AllocParams(1, typeParArray);
- ats = typeManager.GetAggregate(aggNullable, ta);
- }
-
- return ats;
+ UnderlyingType = underlyingType;
}
- public CType GetUnderlyingType() { return UnderlyingType; }
+
+ public override AggregateType GetAts() =>
+ _ats ?? (_ats = TypeManager.GetAggregate(TypeManager.GetNullable(), TypeArray.Allocate(UnderlyingType)));
public override CType StripNubs() => UnderlyingType;
@@ -43,8 +37,28 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return UnderlyingType;
}
- public void SetUnderlyingType(CType pType) { UnderlyingType = pType; }
+ public CType UnderlyingType { get; }
+
+ public override bool IsValueType => true;
+
+ public override bool IsStructOrEnum => true;
+
+ public override bool IsStructType => true;
- public CType UnderlyingType;
+ public override Type AssociatedSystemType => typeof(Nullable<>).MakeGenericType(UnderlyingType.AssociatedSystemType);
+
+ public override CType BaseOrParameterOrElementType => UnderlyingType;
+
+ public override FUNDTYPE FundamentalType => FUNDTYPE.FT_STRUCT;
+
+ [ExcludeFromCodeCoverage] // Should be unreachable. Overload exists just to catch it being hit during debug.
+ public override ConstValKind ConstValKind
+ {
+ get
+ {
+ Debug.Fail("Constant nullable?");
+ return ConstValKind.Decimal; // Equivalent to previous code, so least change for this unreachable branch.
+ }
+ }
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/ParameterModifierType.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/ParameterModifierType.cs
index 7bf3ab81ef..cac1fcf372 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/ParameterModifierType.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/ParameterModifierType.cs
@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
+
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
// ----------------------------------------------------------------------------
@@ -15,11 +17,19 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
internal sealed class ParameterModifierType : CType
{
- public bool isOut; // True for out parameter, false for ref parameter.
+ public ParameterModifierType(CType parameterType, bool isOut)
+ : base(TypeKind.TK_ParameterModifierType)
+ {
+ ParameterType = parameterType;
+ IsOut = isOut;
+ }
+
+ public bool IsOut { get; } // True for out parameter, false for ref parameter.
+
+ public CType ParameterType { get; }
- public CType GetParameterType() { return _pParameterType; }
- public void SetParameterType(CType pType) { _pParameterType = pType; }
+ public override Type AssociatedSystemType => ParameterType.AssociatedSystemType.MakeByRefType();
- private CType _pParameterType;
+ public override CType BaseOrParameterOrElementType => ParameterType;
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/PointerType.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/PointerType.cs
index a3e6a4ddb6..5298048603 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/PointerType.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/PointerType.cs
@@ -2,12 +2,38 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
internal sealed class PointerType : CType
{
- public CType GetReferentType() { return _pReferentType; }
- public void SetReferentType(CType pType) { _pReferentType = pType; }
- private CType _pReferentType;
+ public PointerType(CType referentType)
+ : base(TypeKind.TK_PointerType)
+ {
+ ReferentType = referentType;
+ }
+
+ public CType ReferentType { get; }
+
+ public override bool IsUnsafe() => true;
+
+ public override Type AssociatedSystemType => ReferentType.AssociatedSystemType.MakePointerType();
+
+ public override CType BaseOrParameterOrElementType => ReferentType;
+
+ public override FUNDTYPE FundamentalType => FUNDTYPE.FT_PTR;
+
+ [ExcludeFromCodeCoverage] // Technically correct, but we can't have constant pointers in dynamically dispatched code.
+ public override ConstValKind ConstValKind
+ {
+ get
+ {
+ Debug.Fail("Constant of pointer in dynamic code?");
+ return ConstValKind.IntPtr;
+ }
+ }
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/PredefinedTypes.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/PredefinedTypes.cs
index 437a150b1f..7a80b8f26d 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/PredefinedTypes.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/PredefinedTypes.cs
@@ -9,23 +9,15 @@ using Microsoft.CSharp.RuntimeBinder.Syntax;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
- internal sealed class PredefinedTypes
+ internal static class PredefinedTypes
{
- private SymbolTable _runtimeBinderSymbolTable;
- private readonly BSYMMGR _symbolManager;
- private AggregateSymbol[] _predefSyms; // array of predefined symbol types.
-
- public PredefinedTypes(BSYMMGR symbolManager)
- {
- _symbolManager = symbolManager;
- _runtimeBinderSymbolTable = null;
- }
+ private static readonly AggregateSymbol[] s_predefSymbols = new AggregateSymbol[(int)PredefinedType.PT_COUNT];
// We want to delay load the predefined symbols as needed.
- private AggregateSymbol DelayLoadPredefSym(PredefinedType pt)
+ private static AggregateSymbol DelayLoadPredefSym(PredefinedType pt)
{
- CType type = _runtimeBinderSymbolTable.GetCTypeFromType(PredefinedTypeFacts.GetAssociatedSystemType(pt));
- AggregateSymbol sym = type.getAggregate();
+ AggregateType type = (AggregateType)SymbolTable.GetCTypeFromType(PredefinedTypeFacts.GetAssociatedSystemType(pt));
+ AggregateSymbol sym = type.OwningAggregate;
return InitializePredefinedType(sym, pt);
}
@@ -38,35 +30,22 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return sym;
}
- public void Init(SymbolTable symtable)
- {
- _runtimeBinderSymbolTable = symtable;
- Debug.Assert(_symbolManager != null);
- Debug.Assert(_predefSyms == null);
-
- _predefSyms = new AggregateSymbol[(int)PredefinedType.PT_COUNT];
- }
-
- public AggregateSymbol GetPredefinedAggregate(PredefinedType pt) =>
- _predefSyms[(int)pt] ?? (_predefSyms[(int)pt] = DelayLoadPredefSym(pt));
+ public static AggregateSymbol GetPredefinedAggregate(PredefinedType pt) =>
+ s_predefSymbols[(int)pt] ?? (s_predefSymbols[(int)pt] = DelayLoadPredefSym(pt));
////////////////////////////////////////////////////////////////////////////////
// Some of the predefined types have built-in names, like "int" or "string" or
- // "object". This return the nice name if one exists; otherwise null is
+ // "object". This return the nice name if one exists; otherwise null is
// returned.
private static string GetNiceName(PredefinedType pt) => PredefinedTypeFacts.GetNiceName(pt);
public static string GetNiceName(AggregateSymbol type) =>
type.IsPredefined() ? GetNiceName(type.GetPredefType()) : null;
-
- public static string GetFullName(PredefinedType pt) => PredefinedTypeFacts.GetName(pt);
}
internal static class PredefinedTypeFacts
{
- internal static string GetName(PredefinedType type) => s_types[(int)type].Name;
-
internal static FUNDTYPE GetFundType(PredefinedType type) => s_types[(int)type].FundType;
internal static Type GetAssociatedSystemType(PredefinedType type) => s_types[(int)type].AssociatedSystemType;
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/Type.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/Type.cs
index 71477ffff7..d8a7386e23 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/Type.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/Type.cs
@@ -3,8 +3,8 @@
// See the LICENSE file in the project root for more information.
using System;
-using System.Collections.Generic;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using Microsoft.CSharp.RuntimeBinder.Syntax;
@@ -12,167 +12,19 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
internal abstract class CType
{
- private TypeKind _typeKind;
- private Name _pName;
-
- public bool IsWindowsRuntimeType()
- {
- return (AssociatedSystemType.Attributes & TypeAttributes.WindowsRuntime) == TypeAttributes.WindowsRuntime;
- }
-
- public bool IsCollectionType()
- {
- if ((AssociatedSystemType.IsGenericType &&
- (AssociatedSystemType.GetGenericTypeDefinition() == typeof(IList<>) ||
- AssociatedSystemType.GetGenericTypeDefinition() == typeof(ICollection<>) ||
- AssociatedSystemType.GetGenericTypeDefinition() == typeof(IEnumerable<>) ||
- AssociatedSystemType.GetGenericTypeDefinition() == typeof(IReadOnlyList<>) ||
- AssociatedSystemType.GetGenericTypeDefinition() == typeof(IReadOnlyCollection<>) ||
- AssociatedSystemType.GetGenericTypeDefinition() == typeof(IDictionary<,>) ||
- AssociatedSystemType.GetGenericTypeDefinition() == typeof(IReadOnlyDictionary<,>))) ||
- AssociatedSystemType == typeof(System.Collections.IList) ||
- AssociatedSystemType == typeof(System.Collections.ICollection) ||
- AssociatedSystemType == typeof(System.Collections.IEnumerable) ||
- AssociatedSystemType == typeof(System.Collections.Specialized.INotifyCollectionChanged) ||
- AssociatedSystemType == typeof(System.ComponentModel.INotifyPropertyChanged))
- {
- return true;
- }
- return false;
- }
-
- private Type _associatedSystemType;
- public Type AssociatedSystemType
- {
- get
- {
- if (_associatedSystemType == null)
- {
- _associatedSystemType = CalculateAssociatedSystemType(this);
- }
-
- return _associatedSystemType;
- }
- }
-
- private static Type CalculateAssociatedSystemType(CType src)
- {
- Type result = null;
-
- switch (src.GetTypeKind())
- {
- case TypeKind.TK_ArrayType:
- ArrayType a = (ArrayType)src;
- Type elementType = a.GetElementType().AssociatedSystemType;
- result = a.IsSZArray ? elementType.MakeArrayType() : elementType.MakeArrayType(a.rank);
- break;
-
- case TypeKind.TK_NullableType:
- NullableType n = (NullableType)src;
- Type underlyingType = n.GetUnderlyingType().AssociatedSystemType;
- result = typeof(Nullable<>).MakeGenericType(underlyingType);
- break;
-
- case TypeKind.TK_PointerType:
- PointerType p = (PointerType)src;
- Type referentType = p.GetReferentType().AssociatedSystemType;
- result = referentType.MakePointerType();
- break;
-
- case TypeKind.TK_ParameterModifierType:
- ParameterModifierType r = (ParameterModifierType)src;
- Type parameterType = r.GetParameterType().AssociatedSystemType;
- result = parameterType.MakeByRefType();
- break;
-
- case TypeKind.TK_AggregateType:
- result = CalculateAssociatedSystemTypeForAggregate((AggregateType)src);
- break;
-
- case TypeKind.TK_TypeParameterType:
- TypeParameterType t = (TypeParameterType)src;
- if (t.IsMethodTypeParameter())
- {
- MethodInfo meth = ((MethodSymbol)t.GetOwningSymbol()).AssociatedMemberInfo as MethodInfo;
- result = meth.GetGenericArguments()[t.GetIndexInOwnParameters()];
- }
- else
- {
- Type parentType = ((AggregateSymbol)t.GetOwningSymbol()).AssociatedSystemType;
- result = parentType.GetGenericArguments()[t.GetIndexInOwnParameters()];
- }
- break;
- }
-
- Debug.Assert(result != null || src.GetTypeKind() == TypeKind.TK_AggregateType);
- return result;
- }
-
- private static Type CalculateAssociatedSystemTypeForAggregate(AggregateType aggtype)
+ private protected CType(TypeKind kind)
{
- AggregateSymbol agg = aggtype.GetOwningAggregate();
- TypeArray typeArgs = aggtype.GetTypeArgsAll();
-
- List<Type> list = new List<Type>();
-
- // Get each type arg.
- for (int i = 0; i < typeArgs.Count; i++)
- {
- // Unnamed type parameter types are just placeholders.
- if (typeArgs[i] is TypeParameterType typeParamArg && typeParamArg.GetTypeParameterSymbol().name == null)
- {
- return null;
- }
- list.Add(typeArgs[i].AssociatedSystemType);
- }
-
- Type[] systemTypeArgs = list.ToArray();
- Type uninstantiatedType = agg.AssociatedSystemType;
-
- if (uninstantiatedType.IsGenericType)
- {
- try
- {
- return uninstantiatedType.MakeGenericType(systemTypeArgs);
- }
- catch (ArgumentException)
- {
- // If the constraints don't work, just return the type without substituting it.
- return uninstantiatedType;
- }
- }
- return uninstantiatedType;
+ TypeKind = kind;
}
- public TypeKind GetTypeKind() { return _typeKind; }
- public void SetTypeKind(TypeKind kind) { _typeKind = kind; }
+ public bool IsWindowsRuntimeType => (AssociatedSystemType.Attributes & TypeAttributes.WindowsRuntime) != 0;
- public Name GetName() { return _pName; }
- public void SetName(Name pName) { _pName = pName; }
+ [ExcludeFromCodeCoverage] // Should only be called through override.
+ public virtual Type AssociatedSystemType => throw Error.InternalCompilerError();
- // This call switches on the kind and dispatches accordingly. This should really only be
- // used when dereferencing TypeArrays. We should consider refactoring our code to not
- // need this type of thing - strongly typed handling of TypeArrays would be much better.
- public CType GetBaseOrParameterOrElementType()
- {
- switch (GetTypeKind())
- {
- case TypeKind.TK_ArrayType:
- return ((ArrayType)this).GetElementType();
-
- case TypeKind.TK_PointerType:
- return ((PointerType)this).GetReferentType();
-
- case TypeKind.TK_ParameterModifierType:
- return ((ParameterModifierType)this).GetParameterType();
-
- case TypeKind.TK_NullableType:
- return ((NullableType)this).GetUnderlyingType();
+ public TypeKind TypeKind { get; }
- default:
- return null;
- }
- }
+ public virtual CType BaseOrParameterOrElementType => null;
////////////////////////////////////////////////////////////////////////////////
// Given a symbol, determine its fundamental type. This is the type that
@@ -181,97 +33,9 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// one of the integral/float types (includes enums with that underlying type)
// reference type
// struct/value type
- public FUNDTYPE fundType()
- {
- switch (GetTypeKind())
- {
- case TypeKind.TK_AggregateType:
- {
- AggregateSymbol sym = ((AggregateType)this).getAggregate();
-
- // Treat enums like their underlying types.
- if (sym.IsEnum())
- {
- sym = sym.GetUnderlyingType().getAggregate();
- }
-
- if (sym.IsStruct())
- {
- // Struct type could be predefined (int, long, etc.) or some other struct.
- if (sym.IsPredefined())
- return PredefinedTypeFacts.GetFundType(sym.GetPredefType());
- return FUNDTYPE.FT_STRUCT;
- }
- return FUNDTYPE.FT_REF; // Interfaces, classes, delegates are reference types.
- }
-
- case TypeKind.TK_TypeParameterType:
- return FUNDTYPE.FT_VAR;
-
- case TypeKind.TK_ArrayType:
- case TypeKind.TK_NullType:
- return FUNDTYPE.FT_REF;
-
- case TypeKind.TK_PointerType:
- return FUNDTYPE.FT_PTR;
-
- case TypeKind.TK_NullableType:
- return FUNDTYPE.FT_STRUCT;
+ public virtual FUNDTYPE FundamentalType => FUNDTYPE.FT_NONE;
- default:
- return FUNDTYPE.FT_NONE;
- }
- }
- public ConstValKind constValKind()
- {
- if (isPointerLike())
- {
- return ConstValKind.IntPtr;
- }
-
- switch (fundType())
- {
- case FUNDTYPE.FT_I8:
- case FUNDTYPE.FT_U8:
- return ConstValKind.Long;
- case FUNDTYPE.FT_STRUCT:
- // Here we can either have a decimal type, or an enum
- // whose fundamental type is decimal.
- Debug.Assert((getAggregate().IsEnum() && getAggregate().GetUnderlyingType().getPredefType() == PredefinedType.PT_DECIMAL)
- || (isPredefined() && getPredefType() == PredefinedType.PT_DATETIME)
- || (isPredefined() && getPredefType() == PredefinedType.PT_DECIMAL));
-
- if (isPredefined() && getPredefType() == PredefinedType.PT_DATETIME)
- {
- return ConstValKind.Long;
- }
- return ConstValKind.Decimal;
-
- case FUNDTYPE.FT_REF:
- if (isPredefined() && getPredefType() == PredefinedType.PT_STRING)
- {
- return ConstValKind.String;
- }
- else
- {
- return ConstValKind.IntPtr;
- }
- case FUNDTYPE.FT_R4:
- return ConstValKind.Float;
- case FUNDTYPE.FT_R8:
- return ConstValKind.Double;
- case FUNDTYPE.FT_I1:
- return ConstValKind.Boolean;
- default:
- return ConstValKind.Int;
- }
- }
- public CType underlyingType()
- {
- if (this is AggregateType && getAggregate().IsEnum())
- return getAggregate().GetUnderlyingType();
- return this;
- }
+ public virtual ConstValKind ConstValKind => ConstValKind.Int;
////////////////////////////////////////////////////////////////////////////////
// Strips off ArrayType, ParameterModifierType, PointerType, PinnedType and optionally NullableType
@@ -280,37 +44,27 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
for (CType type = this; ;)
{
- switch (type.GetTypeKind())
+ switch (type.TypeKind)
{
default:
return type;
case TypeKind.TK_NullableType:
if (!fStripNub)
- return type;
- type = type.GetBaseOrParameterOrElementType();
- break;
+ {
+ goto default;
+ }
+
+ goto case TypeKind.TK_ArrayType;
+
case TypeKind.TK_ArrayType:
case TypeKind.TK_ParameterModifierType:
case TypeKind.TK_PointerType:
- type = type.GetBaseOrParameterOrElementType();
+ type = type.BaseOrParameterOrElementType;
break;
}
}
}
- public AggregateSymbol GetNakedAgg()
- {
- return GetNakedAgg(false);
- }
-
- private AggregateSymbol GetNakedAgg(bool fStripNub) =>
- (GetNakedType(fStripNub) as AggregateType)?.getAggregate();
-
- public AggregateSymbol getAggregate()
- {
- Debug.Assert(this is AggregateType);
- return ((AggregateType)this).GetOwningAggregate();
- }
public virtual CType StripNubs() => this;
@@ -320,177 +74,61 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return this;
}
- public bool isDelegateType()
- {
- return this is AggregateType && getAggregate().IsDelegate();
- }
+ public virtual bool IsDelegateType => false;
////////////////////////////////////////////////////////////////////////////////
// A few types are considered "simple" types for purposes of conversions and so
// on. They are the fundamental types the compiler knows about for operators and
// conversions.
- public bool isSimpleType()
- {
- return (isPredefined() &&
- PredefinedTypeFacts.IsSimpleType(getPredefType()));
- }
- public bool isSimpleOrEnum()
- {
- return isSimpleType() || isEnumType();
- }
- public bool isSimpleOrEnumOrString()
- {
- return isSimpleType() || isPredefType(PredefinedType.PT_STRING) || isEnumType();
- }
+ public virtual bool IsSimpleType => false;
- private bool isPointerLike()
- {
- return this is PointerType || isPredefType(PredefinedType.PT_INTPTR) || isPredefType(PredefinedType.PT_UINTPTR);
- }
+ public virtual bool IsSimpleOrEnum => false;
+
+ public virtual bool IsSimpleOrEnumOrString => false;
////////////////////////////////////////////////////////////////////////////////
// A few types are considered "numeric" types. They are the fundamental number
// types the compiler knows about for operators and conversions.
- public bool isNumericType()
- {
- return (isPredefined() &&
- PredefinedTypeFacts.IsNumericType(getPredefType()));
- }
- public bool isStructOrEnum()
- {
- return this is AggregateType && (getAggregate().IsStruct() || getAggregate().IsEnum()) || this is NullableType;
- }
- public bool isStructType()
- {
- return this is AggregateType && getAggregate().IsStruct() || this is NullableType;
- }
- public bool isEnumType()
- {
- return this is AggregateType && getAggregate().IsEnum();
- }
- public bool isInterfaceType()
- {
- return this is AggregateType && getAggregate().IsInterface();
- }
- public bool isClassType()
- {
- return this is AggregateType && getAggregate().IsClass();
- }
- public AggregateType underlyingEnumType()
- {
- Debug.Assert(isEnumType());
- return getAggregate().GetUnderlyingType();
- }
- public bool isUnsigned()
- {
- if (this is AggregateType sym)
- {
- if (sym.isEnumType())
- {
- sym = sym.underlyingEnumType();
- }
- if (sym.isPredefined())
- {
- PredefinedType pt = sym.getPredefType();
- return pt == PredefinedType.PT_UINTPTR || pt == PredefinedType.PT_BYTE || (pt >= PredefinedType.PT_USHORT && pt <= PredefinedType.PT_ULONG);
- }
- else
- {
- return false;
- }
- }
- else
- {
- return this is PointerType;
- }
- }
- public bool isUnsafe()
- {
- // Pointer types are the only unsafe types.
- // Note that generics may not be instantiated with pointer types
- return this is PointerType || this is ArrayType arr && arr.GetElementType().isUnsafe();
- }
- public bool isPredefType(PredefinedType pt)
- {
- if (this is AggregateType ats)
- return ats.getAggregate().IsPredefined() && ats.getAggregate().GetPredefType() == pt;
- return (this is VoidType && pt == PredefinedType.PT_VOID);
- }
- public bool isPredefined()
- {
- return this is AggregateType && getAggregate().IsPredefined();
- }
- public PredefinedType getPredefType()
- {
- //ASSERT(isPredefined());
- return getAggregate().GetPredefType();
- }
+ public virtual bool IsNumericType => false;
- public bool isStaticClass()
- {
- AggregateSymbol agg = GetNakedAgg(false);
- if (agg == null)
- return false;
+ public virtual bool IsStructOrEnum => false;
- if (!agg.IsStatic())
- return false;
+ public virtual bool IsStructType => false;
- return true;
- }
+ public virtual bool IsEnumType => false;
- public CType GetDelegateTypeOfPossibleExpression()
- {
- if (isPredefType(PredefinedType.PT_G_EXPRESSION))
- {
- return ((AggregateType)this).GetTypeArgsThis()[0];
- }
+ public virtual bool IsInterfaceType => false;
- return this;
- }
+ public virtual bool IsClassType => false;
+
+ [ExcludeFromCodeCoverage] // Should only be called through override.
+ public virtual AggregateType UnderlyingEnumType => throw Error.InternalCompilerError();
+
+ // Pointer types (or arrays of them) are the only unsafe types.
+ // Note that generics may not be instantiated with pointer types
+ public virtual bool IsUnsafe() => false;
+
+ public virtual bool IsPredefType(PredefinedType pt) => false;
+
+ public virtual bool IsPredefined => false;
+
+ [ExcludeFromCodeCoverage] // Should only be called through override.
+ public virtual PredefinedType PredefinedType => throw Error.InternalCompilerError();
+
+ public virtual bool IsStaticClass => false;
// These check for AGGTYPESYMs, TYVARSYMs and others as appropriate.
- public bool IsValType()
- {
- switch (GetTypeKind())
- {
- case TypeKind.TK_TypeParameterType:
- return ((TypeParameterType)this).IsValueType();
- case TypeKind.TK_AggregateType:
- return ((AggregateType)this).getAggregate().IsValueType();
- case TypeKind.TK_NullableType:
- return true;
- default:
- return false;
- }
- }
- public bool IsNonNubValType()
- {
- switch (GetTypeKind())
- {
- case TypeKind.TK_TypeParameterType:
- return ((TypeParameterType)this).IsNonNullableValueType();
- case TypeKind.TK_AggregateType:
- return ((AggregateType)this).getAggregate().IsValueType();
- case TypeKind.TK_NullableType:
- return false;
- default:
- return false;
- }
- }
- public bool IsRefType()
+ public virtual bool IsValueType => false;
+
+ public virtual bool IsNonNullableValueType => false;
+
+ public virtual bool IsReferenceType => false;
+
+ [ExcludeFromCodeCoverage] // Should only be called through override.
+ public virtual AggregateType GetAts()
{
- switch (GetTypeKind())
- {
- case TypeKind.TK_ArrayType:
- case TypeKind.TK_NullType:
- return true;
- case TypeKind.TK_TypeParameterType:
- return ((TypeParameterType)this).IsReferenceType();
- case TypeKind.TK_AggregateType:
- return ((AggregateType)this).getAggregate().IsRefType();
- default:
- return false;
- }
+ Debug.Fail("Bad type for AsAggregateType");
+ return null;
}
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/TypeArray.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/TypeArray.cs
index 414a895e91..bd36a6f3c6 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/TypeArray.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/TypeArray.cs
@@ -3,7 +3,9 @@
// See the LICENSE file in the project root for more information.
using System;
+using System.Collections.Generic;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
@@ -13,7 +15,77 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
internal sealed class TypeArray
{
- public TypeArray(CType[] types)
+ ////////////////////////////////////////////////////////////////////////////////
+ // Allocate a type array; used to represent a parameter list.
+ // We use a hash table to make sure that allocating the same type array twice
+ // returns the same value. This does two things:
+ //
+ // 1) Save a lot of memory.
+ // 2) Make it so parameter lists can be compared by a simple pointer comparison
+
+ private readonly struct TypeArrayKey : IEquatable<TypeArrayKey>
+ {
+ private readonly CType[] _types;
+ private readonly int _hashCode;
+
+ public TypeArrayKey(CType[] types)
+ {
+ _types = types;
+ int hashCode = 0x162A16FE;
+ foreach (CType type in types)
+ {
+ hashCode = (hashCode << 5) - hashCode;
+ if (type != null)
+ {
+ hashCode ^= type.GetHashCode();
+ }
+ }
+
+ _hashCode = hashCode;
+ }
+
+ public bool Equals(TypeArrayKey other)
+ {
+ CType[] types = _types;
+ CType[] otherTypes = other._types;
+ if (otherTypes == types)
+ {
+ return true;
+ }
+
+ if (other._hashCode != _hashCode || otherTypes.Length != types.Length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i < types.Length; i++)
+ {
+ if (types[i] != otherTypes[i])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ [ExcludeFromCodeCoverage] // Typed overload should always be the method called.
+ public override bool Equals(object obj)
+ {
+ Debug.Fail("Sub-optimal overload called. Check if this can be avoided.");
+ return obj is TypeArrayKey key && Equals(key);
+ }
+
+ public override int GetHashCode() => _hashCode;
+ }
+
+ // The RuntimeBinder uses a global lock when Binding that keeps this dictionary safe.
+ private static readonly Dictionary<TypeArrayKey, TypeArray> s_tableTypeArrays =
+ new Dictionary<TypeArrayKey, TypeArray>();
+
+ public static readonly TypeArray Empty = new TypeArray(Array.Empty<CType>());
+
+ private TypeArray(CType[] types)
{
Debug.Assert(types != null);
Items = types;
@@ -33,5 +105,61 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
}
public void CopyItems(int i, int c, CType[] dest) => Array.Copy(Items, i, dest, 0, c);
+
+ public static TypeArray Allocate(int ctype, TypeArray array, int offset)
+ {
+ if (ctype == 0)
+ {
+ return Empty;
+ }
+
+ if (ctype == array.Count)
+ {
+ return array;
+ }
+
+ CType[] types = array.Items;
+ CType[] newTypes = new CType[ctype];
+ Array.ConstrainedCopy(types, offset, newTypes, 0, ctype);
+ return Allocate(newTypes);
+ }
+
+ public static TypeArray Allocate(params CType[] types)
+ {
+ if (types?.Length > 0)
+ {
+ RuntimeBinder.EnsureLockIsTaken();
+ TypeArrayKey key = new TypeArrayKey(types);
+ if (!s_tableTypeArrays.TryGetValue(key, out TypeArray result))
+ {
+ result = new TypeArray(types);
+ s_tableTypeArrays.Add(key, result);
+ }
+
+ return result;
+ }
+
+ return Empty;
+ }
+
+ public static TypeArray Concat(TypeArray pta1, TypeArray pta2)
+ {
+ CType[] prgtype1 = pta1.Items;
+ if (prgtype1.Length == 0)
+ {
+ return pta2;
+ }
+
+ CType[] prgtype2 = pta2.Items;
+ if (prgtype2.Length == 0)
+ {
+ return pta1;
+ }
+
+ CType[] combined = new CType[prgtype1.Length + prgtype2.Length];
+ Array.Copy(prgtype1, 0, combined, 0, prgtype1.Length);
+ Array.Copy(prgtype2, 0, combined, prgtype1.Length, prgtype2.Length);
+ return Allocate(combined);
+ }
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/TypeFactory.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/TypeFactory.cs
deleted file mode 100644
index bca41ac99f..0000000000
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/TypeFactory.cs
+++ /dev/null
@@ -1,115 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-using Microsoft.CSharp.RuntimeBinder.Syntax;
-
-namespace Microsoft.CSharp.RuntimeBinder.Semantics
-{
- internal sealed class TypeFactory
- {
- // Aggregate
- public AggregateType CreateAggregateType(
- AggregateSymbol parent,
- TypeArray typeArgsThis,
- AggregateType outerType)
- {
- AggregateType type = new AggregateType();
-
- type.outerType = outerType;
- type.SetOwningAggregate(parent);
- type.SetTypeArgsThis(typeArgsThis);
- type.SetTypeKind(TypeKind.TK_AggregateType);
- return type;
- }
-
- // TypeParameter
- public TypeParameterType CreateTypeParameter(TypeParameterSymbol pSymbol)
- {
- TypeParameterType type = new TypeParameterType();
- type.SetTypeParameterSymbol(pSymbol);
- type.SetName(pSymbol.name);
- Debug.Assert(pSymbol.GetTypeParameterType() == null);
- pSymbol.SetTypeParameterType(type);
-
- type.SetTypeKind(TypeKind.TK_TypeParameterType);
- return type;
- }
-
- // Primitives
- public VoidType CreateVoid()
- {
- VoidType type = new VoidType();
- type.SetTypeKind(TypeKind.TK_VoidType);
- return type;
- }
-
- public NullType CreateNull()
- {
- NullType type = new NullType();
- type.SetTypeKind(TypeKind.TK_NullType);
- return type;
- }
-
- public MethodGroupType CreateMethodGroup()
- {
- MethodGroupType type = new MethodGroupType();
- type.SetTypeKind(TypeKind.TK_MethodGroupType);
- return type;
- }
-
- public ArgumentListType CreateArgList()
- {
- ArgumentListType type = new ArgumentListType();
- type.SetTypeKind(TypeKind.TK_ArgumentListType);
- return type;
- }
-
- // Derived types - parent is base type
- public ArrayType CreateArray(Name name, CType pElementType, int rank, bool isSZArray)
- {
- ArrayType type = new ArrayType();
-
- type.SetName(name);
- type.rank = rank;
- type.IsSZArray = isSZArray;
- type.SetElementType(pElementType);
-
- type.SetTypeKind(TypeKind.TK_ArrayType);
- return type;
- }
-
- public PointerType CreatePointer(Name name, CType pReferentType)
- {
- PointerType type = new PointerType();
- type.SetName(name);
- type.SetReferentType(pReferentType);
-
- type.SetTypeKind(TypeKind.TK_PointerType);
- return type;
- }
-
- public ParameterModifierType CreateParameterModifier(Name name, CType pParameterType)
- {
- ParameterModifierType type = new ParameterModifierType();
- type.SetName(name);
- type.SetParameterType(pParameterType);
-
- type.SetTypeKind(TypeKind.TK_ParameterModifierType);
- return type;
- }
-
- public NullableType CreateNullable(Name name, CType pUnderlyingType, BSYMMGR symmgr, TypeManager typeManager)
- {
- NullableType type = new NullableType();
- type.SetName(name);
- type.SetUnderlyingType(pUnderlyingType);
- type.symmgr = symmgr;
- type.typeManager = typeManager;
-
- type.SetTypeKind(TypeKind.TK_NullableType);
- return type;
- }
- }
-}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/TypeManager.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/TypeManager.cs
index b0fdce88ea..f041688a4b 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/TypeManager.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/TypeManager.cs
@@ -8,51 +8,18 @@ using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
+using System.Security;
using Microsoft.CSharp.RuntimeBinder.Syntax;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
- internal sealed class TypeManager
+ internal static class TypeManager
{
- private BSYMMGR _BSymmgr;
- private PredefinedTypes _predefTypes;
+ // The RuntimeBinder uses a global lock when Binding that keeps this dictionary safe.
+ private static readonly Dictionary<(Assembly, Assembly), bool> s_internalsVisibleToCache =
+ new Dictionary<(Assembly, Assembly), bool>();
- private readonly TypeFactory _typeFactory;
- private readonly TypeTable _typeTable;
- private SymbolTable _symbolTable;
-
- // Special types
- private readonly VoidType _voidType;
- private readonly NullType _nullType;
- private readonly MethodGroupType _typeMethGrp;
- private readonly ArgumentListType _argListType;
-
- private readonly StdTypeVarColl _stvcMethod;
- private readonly StdTypeVarColl _stvcClass;
-
- public TypeManager(BSYMMGR bsymmgr, PredefinedTypes predefTypes)
- {
- _typeFactory = new TypeFactory();
- _typeTable = new TypeTable();
-
- // special types with their own symbol kind.
- _voidType = _typeFactory.CreateVoid();
- _nullType = _typeFactory.CreateNull();
- _typeMethGrp = _typeFactory.CreateMethodGroup();
- _argListType = _typeFactory.CreateArgList();
-
- _stvcMethod = new StdTypeVarColl();
- _stvcClass = new StdTypeVarColl();
- _BSymmgr = bsymmgr;
- _predefTypes = predefTypes;
- }
-
- public void InitTypeFactory(SymbolTable table)
- {
- _symbolTable = table;
- }
-
- public SymbolTable SymbolTable => _symbolTable;
+ private static readonly StdTypeVarColl s_stvcMethod = new StdTypeVarColl();
private sealed class StdTypeVarColl
{
@@ -74,104 +41,80 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// comparison when binding. The standard method type variables are useful during
// binding for signature comparison.
- public TypeParameterType GetTypeVarSym(int iv, TypeManager pTypeManager, bool fMeth)
+ public TypeParameterType GetTypeVarSym(int iv, bool fMeth)
{
Debug.Assert(iv >= 0);
TypeParameterType tpt;
- if (iv >= this.prgptvs.Count)
+ if (iv >= prgptvs.Count)
{
TypeParameterSymbol pTypeParameter = new TypeParameterSymbol();
pTypeParameter.SetIsMethodTypeParameter(fMeth);
pTypeParameter.SetIndexInOwnParameters(iv);
pTypeParameter.SetIndexInTotalParameters(iv);
pTypeParameter.SetAccess(ACCESS.ACC_PRIVATE);
- tpt = pTypeManager.GetTypeParameter(pTypeParameter);
- this.prgptvs.Add(tpt);
+ tpt = GetTypeParameter(pTypeParameter);
+ prgptvs.Add(tpt);
}
else
{
- tpt = this.prgptvs[iv];
+ tpt = prgptvs[iv];
}
Debug.Assert(tpt != null);
return tpt;
}
}
- public ArrayType GetArray(CType elementType, int args, bool isSZArray)
+ public static ArrayType GetArray(CType elementType, int args, bool isSZArray)
{
- Name name;
-
Debug.Assert(args > 0 && args < 32767);
Debug.Assert(args == 1 || !isSZArray);
- switch (args)
- {
- case 1:
- if (isSZArray)
- {
- goto case 2;
- }
- else
- {
- goto default;
- }
- case 2:
- name = NameManager.GetPredefinedName(PredefinedName.PN_ARRAY0 + args);
- break;
- default:
- name = NameManager.Add("[X" + args + 1);
- break;
- }
+ int rankNum = isSZArray ? 0 : args;
// See if we already have an array type of this element type and rank.
- ArrayType pArray = _typeTable.LookupArray(name, elementType);
+ ArrayType pArray = TypeTable.LookupArray(elementType, rankNum);
if (pArray == null)
{
// No existing array symbol. Create a new one.
- pArray = _typeFactory.CreateArray(name, elementType, args, isSZArray);
- _typeTable.InsertArray(name, elementType, pArray);
+ pArray = new ArrayType(elementType, args, isSZArray);
+ TypeTable.InsertArray(elementType, rankNum, pArray);
}
- Debug.Assert(pArray.rank == args);
- Debug.Assert(pArray.GetElementType() == elementType);
+ Debug.Assert(pArray.Rank == args);
+ Debug.Assert(pArray.ElementType == elementType);
return pArray;
}
- public AggregateType GetAggregate(AggregateSymbol agg, AggregateType atsOuter, TypeArray typeArgs)
+ public static AggregateType GetAggregate(AggregateSymbol agg, AggregateType atsOuter, TypeArray typeArgs)
{
- Debug.Assert(agg.GetTypeManager() == this);
- Debug.Assert(atsOuter == null || atsOuter.getAggregate() == agg.Parent, "");
+ Debug.Assert(atsOuter == null || atsOuter.OwningAggregate == agg.Parent, "");
if (typeArgs == null)
{
- typeArgs = BSYMMGR.EmptyTypeArray();
+ typeArgs = TypeArray.Empty;
}
Debug.Assert(agg.GetTypeVars().Count == typeArgs.Count);
- AggregateType pAggregate = _typeTable.LookupAggregate(agg, atsOuter, typeArgs);
+ AggregateType pAggregate = TypeTable.LookupAggregate(agg, atsOuter, typeArgs);
if (pAggregate == null)
{
- pAggregate = _typeFactory.CreateAggregateType(
- agg,
- typeArgs,
- atsOuter
- );
+ pAggregate = new AggregateType(agg, typeArgs, atsOuter);
- Debug.Assert(!pAggregate.fConstraintsChecked && !pAggregate.fConstraintError);
+ Debug.Assert(!pAggregate.ConstraintError.HasValue);
- _typeTable.InsertAggregate(agg, atsOuter, typeArgs, pAggregate);
+ TypeTable.InsertAggregate(agg, atsOuter, typeArgs, pAggregate);
}
- Debug.Assert(pAggregate.getAggregate() == agg);
- Debug.Assert(pAggregate.GetTypeArgsThis() != null && pAggregate.GetTypeArgsAll() != null);
- Debug.Assert(pAggregate.GetTypeArgsThis() == typeArgs);
+ Debug.Assert(pAggregate.OwningAggregate == agg);
+ Debug.Assert(pAggregate.TypeArgsThis != null && pAggregate.TypeArgsAll != null);
+ Debug.Assert(pAggregate.TypeArgsThis == typeArgs);
return pAggregate;
}
- public AggregateType GetAggregate(AggregateSymbol agg, TypeArray typeArgsAll)
+ public static AggregateType GetAggregate(AggregateSymbol agg, TypeArray typeArgsAll)
{
Debug.Assert(typeArgsAll != null && typeArgsAll.Count == agg.GetTypeVarsAll().Count);
@@ -186,127 +129,80 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
int cvarOuter = aggOuter.GetTypeVarsAll().Count;
Debug.Assert(cvarOuter <= typeArgsAll.Count);
- TypeArray typeArgsOuter = _BSymmgr.AllocParams(cvarOuter, typeArgsAll, 0);
- TypeArray typeArgsInner = _BSymmgr.AllocParams(agg.GetTypeVars().Count, typeArgsAll, cvarOuter);
+ TypeArray typeArgsOuter = TypeArray.Allocate(cvarOuter, typeArgsAll, 0);
+ TypeArray typeArgsInner = TypeArray.Allocate(agg.GetTypeVars().Count, typeArgsAll, cvarOuter);
AggregateType atsOuter = GetAggregate(aggOuter, typeArgsOuter);
return GetAggregate(agg, atsOuter, typeArgsInner);
}
- public PointerType GetPointer(CType baseType)
+ public static PointerType GetPointer(CType baseType)
{
- PointerType pPointer = _typeTable.LookupPointer(baseType);
+ PointerType pPointer = TypeTable.LookupPointer(baseType);
if (pPointer == null)
{
// No existing type. Create a new one.
- Name namePtr = NameManager.GetPredefinedName(PredefinedName.PN_PTR);
-
- pPointer = _typeFactory.CreatePointer(namePtr, baseType);
- _typeTable.InsertPointer(baseType, pPointer);
+ pPointer = new PointerType(baseType);
+ TypeTable.InsertPointer(baseType, pPointer);
}
- Debug.Assert(pPointer.GetReferentType() == baseType);
+ Debug.Assert(pPointer.ReferentType == baseType);
return pPointer;
}
- public NullableType GetNullable(CType pUnderlyingType)
+ public static NullableType GetNullable(CType pUnderlyingType)
{
- if (pUnderlyingType is NullableType nt)
- {
- Debug.Fail("Attempt to make nullable of nullable");
- return nt;
- }
+ Debug.Assert(!(pUnderlyingType is NullableType), "Attempt to make nullable of nullable");
- NullableType pNullableType = _typeTable.LookupNullable(pUnderlyingType);
+ NullableType pNullableType = TypeTable.LookupNullable(pUnderlyingType);
if (pNullableType == null)
{
- Name pName = NameManager.GetPredefinedName(PredefinedName.PN_NUB);
-
- pNullableType = _typeFactory.CreateNullable(pName, pUnderlyingType, _BSymmgr, this);
- _typeTable.InsertNullable(pUnderlyingType, pNullableType);
+ pNullableType = new NullableType(pUnderlyingType);
+ TypeTable.InsertNullable(pUnderlyingType, pNullableType);
}
return pNullableType;
}
- public NullableType GetNubFromNullable(AggregateType ats)
+ public static ParameterModifierType GetParameterModifier(CType paramType, bool isOut)
{
- Debug.Assert(ats.isPredefType(PredefinedType.PT_G_OPTIONAL));
- return GetNullable(ats.GetTypeArgsAll()[0]);
- }
-
- public ParameterModifierType GetParameterModifier(CType paramType, bool isOut)
- {
- Name name = NameManager.GetPredefinedName(isOut ? PredefinedName.PN_OUTPARAM : PredefinedName.PN_REFPARAM);
- ParameterModifierType pParamModifier = _typeTable.LookupParameterModifier(name, paramType);
-
+ ParameterModifierType pParamModifier = TypeTable.LookupParameterModifier(paramType, isOut);
if (pParamModifier == null)
{
// No existing parammod symbol. Create a new one.
- pParamModifier = _typeFactory.CreateParameterModifier(name, paramType);
- pParamModifier.isOut = isOut;
- _typeTable.InsertParameterModifier(name, paramType, pParamModifier);
+ pParamModifier = new ParameterModifierType(paramType, isOut);
+ TypeTable.InsertParameterModifier(paramType, isOut, pParamModifier);
}
- Debug.Assert(pParamModifier.GetParameterType() == paramType);
+ Debug.Assert(pParamModifier.ParameterType == paramType);
return pParamModifier;
}
- public VoidType GetVoid()
- {
- return _voidType;
- }
-
- public NullType GetNullType()
- {
- return _nullType;
- }
-
- public MethodGroupType GetMethGrpType()
- {
- return _typeMethGrp;
- }
-
- public ArgumentListType GetArgListType()
- {
- return _argListType;
- }
+ public static AggregateSymbol GetNullable() => GetPredefAgg(PredefinedType.PT_G_OPTIONAL);
- public AggregateSymbol GetNullable() => GetPredefAgg(PredefinedType.PT_G_OPTIONAL);
-
- private CType SubstType(CType typeSrc, TypeArray typeArgsCls, TypeArray typeArgsMeth, SubstTypeFlags grfst)
+ private static CType SubstType(CType typeSrc, TypeArray typeArgsCls, TypeArray typeArgsMeth, bool denormMeth)
{
- if (typeSrc == null)
- return null;
-
- var ctx = new SubstContext(typeArgsCls, typeArgsMeth, grfst);
- return ctx.FNop() ? typeSrc : SubstTypeCore(typeSrc, ctx);
+ Debug.Assert(typeSrc != null);
+ SubstContext ctx = new SubstContext(typeArgsCls, typeArgsMeth, denormMeth);
+ return ctx.IsNop ? typeSrc : SubstTypeCore(typeSrc, ctx);
}
- public AggregateType SubstType(AggregateType typeSrc, TypeArray typeArgsCls)
+ public static AggregateType SubstType(AggregateType typeSrc, TypeArray typeArgsCls)
{
- if (typeSrc != null)
- {
- SubstContext ctx = new SubstContext(typeArgsCls, null, SubstTypeFlags.NormNone);
- if (!ctx.FNop())
- {
- return SubstTypeCore(typeSrc, ctx);
- }
- }
+ Debug.Assert(typeSrc != null);
- return typeSrc;
+ SubstContext ctx = new SubstContext(typeArgsCls, null, false);
+ return ctx.IsNop ? typeSrc : SubstTypeCore(typeSrc, ctx);
}
- private CType SubstType(CType typeSrc, TypeArray typeArgsCls, TypeArray typeArgsMeth)
- {
- return SubstType(typeSrc, typeArgsCls, typeArgsMeth, SubstTypeFlags.NormNone);
- }
+ private static CType SubstType(CType typeSrc, TypeArray typeArgsCls, TypeArray typeArgsMeth) =>
+ SubstType(typeSrc, typeArgsCls, typeArgsMeth, false);
- public TypeArray SubstTypeArray(TypeArray taSrc, SubstContext ctx)
+ public static TypeArray SubstTypeArray(TypeArray taSrc, SubstContext ctx)
{
- if (taSrc != null && taSrc.Count != 0 && ctx != null && !ctx.FNop())
+ if (taSrc != null && taSrc.Count != 0 && ctx != null && !ctx.IsNop)
{
CType[] srcs = taSrc.Items;
for (int i = 0; i < srcs.Length; i++)
@@ -323,7 +219,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
dsts[i] = SubstTypeCore(srcs[i], ctx);
}
- return _BSymmgr.AllocParams(dsts);
+ return TypeArray.Allocate(dsts);
}
}
}
@@ -331,34 +227,34 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return taSrc;
}
- public TypeArray SubstTypeArray(TypeArray taSrc, TypeArray typeArgsCls, TypeArray typeArgsMeth)
+ public static TypeArray SubstTypeArray(TypeArray taSrc, TypeArray typeArgsCls, TypeArray typeArgsMeth)
=> taSrc == null || taSrc.Count == 0
? taSrc
- : SubstTypeArray(taSrc, new SubstContext(typeArgsCls, typeArgsMeth, SubstTypeFlags.NormNone));
+ : SubstTypeArray(taSrc, new SubstContext(typeArgsCls, typeArgsMeth, false));
- public TypeArray SubstTypeArray(TypeArray taSrc, TypeArray typeArgsCls) => SubstTypeArray(taSrc, typeArgsCls, null);
+ public static TypeArray SubstTypeArray(TypeArray taSrc, TypeArray typeArgsCls) => SubstTypeArray(taSrc, typeArgsCls, null);
- private AggregateType SubstTypeCore(AggregateType type, SubstContext ctx)
+ private static AggregateType SubstTypeCore(AggregateType type, SubstContext ctx)
{
- TypeArray args = type.GetTypeArgsAll();
+ TypeArray args = type.TypeArgsAll;
if (args.Count > 0)
{
TypeArray typeArgs = SubstTypeArray(args, ctx);
if (args != typeArgs)
{
- return GetAggregate(type.getAggregate(), typeArgs);
+ return GetAggregate(type.OwningAggregate, typeArgs);
}
}
return type;
}
- private CType SubstTypeCore(CType type, SubstContext pctx)
+ private static CType SubstTypeCore(CType type, SubstContext pctx)
{
CType typeSrc;
CType typeDst;
- switch (type.GetTypeKind())
+ switch (type.TypeKind)
{
default:
Debug.Assert(false);
@@ -372,20 +268,20 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
case TypeKind.TK_ParameterModifierType:
ParameterModifierType mod = (ParameterModifierType)type;
- typeDst = SubstTypeCore(typeSrc = mod.GetParameterType(), pctx);
- return (typeDst == typeSrc) ? type : GetParameterModifier(typeDst, mod.isOut);
+ typeDst = SubstTypeCore(typeSrc = mod.ParameterType, pctx);
+ return (typeDst == typeSrc) ? type : GetParameterModifier(typeDst, mod.IsOut);
case TypeKind.TK_ArrayType:
var arr = (ArrayType)type;
- typeDst = SubstTypeCore(typeSrc = arr.GetElementType(), pctx);
- return (typeDst == typeSrc) ? type : GetArray(typeDst, arr.rank, arr.IsSZArray);
+ typeDst = SubstTypeCore(typeSrc = arr.ElementType, pctx);
+ return (typeDst == typeSrc) ? type : GetArray(typeDst, arr.Rank, arr.IsSZArray);
case TypeKind.TK_PointerType:
- typeDst = SubstTypeCore(typeSrc = ((PointerType)type).GetReferentType(), pctx);
+ typeDst = SubstTypeCore(typeSrc = ((PointerType)type).ReferentType, pctx);
return (typeDst == typeSrc) ? type : GetPointer(typeDst);
case TypeKind.TK_NullableType:
- typeDst = SubstTypeCore(typeSrc = ((NullableType)type).GetUnderlyingType(), pctx);
+ typeDst = SubstTypeCore(typeSrc = ((NullableType)type).UnderlyingType, pctx);
return (typeDst == typeSrc) ? type : GetNullable(typeDst);
case TypeKind.TK_AggregateType:
@@ -393,45 +289,44 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
case TypeKind.TK_TypeParameterType:
{
- TypeParameterSymbol tvs = ((TypeParameterType)type).GetTypeParameterSymbol();
+ TypeParameterSymbol tvs = ((TypeParameterType)type).Symbol;
int index = tvs.GetIndexInTotalParameters();
if (tvs.IsMethodTypeParameter())
{
- if ((pctx.grfst & SubstTypeFlags.DenormMeth) != 0 && tvs.parent != null)
- return type;
- Debug.Assert(tvs.GetIndexInOwnParameters() == tvs.GetIndexInTotalParameters());
- if (index < pctx.ctypeMeth)
+ if (pctx.DenormMeth && tvs.parent != null)
{
- Debug.Assert(pctx.prgtypeMeth != null);
- return pctx.prgtypeMeth[index];
+ return type;
}
- else
+
+ Debug.Assert(tvs.GetIndexInOwnParameters() == tvs.GetIndexInTotalParameters());
+ if (index < pctx.MethodTypes.Length)
{
- return ((pctx.grfst & SubstTypeFlags.NormMeth) != 0 ? GetStdMethTypeVar(index) : type);
+ Debug.Assert(pctx.MethodTypes != null);
+ return pctx.MethodTypes[index];
}
- }
- if ((pctx.grfst & SubstTypeFlags.DenormClass) != 0 && tvs.parent != null)
+
return type;
- return index < pctx.ctypeCls ? pctx.prgtypeCls[index] :
- ((pctx.grfst & SubstTypeFlags.NormClass) != 0 ? GetStdClsTypeVar(index) : type);
+ }
+
+ return index < pctx.ClassTypes.Length ? pctx.ClassTypes[index] : type;
}
}
}
- public bool SubstEqualTypes(CType typeDst, CType typeSrc, TypeArray typeArgsCls, TypeArray typeArgsMeth, SubstTypeFlags grfst)
+ public static bool SubstEqualTypes(CType typeDst, CType typeSrc, TypeArray typeArgsCls, TypeArray typeArgsMeth, bool denormMeth)
{
if (typeDst.Equals(typeSrc))
{
- Debug.Assert(typeDst.Equals(SubstType(typeSrc, typeArgsCls, typeArgsMeth, grfst)));
+ Debug.Assert(typeDst.Equals(SubstType(typeSrc, typeArgsCls, typeArgsMeth, denormMeth)));
return true;
}
- var ctx = new SubstContext(typeArgsCls, typeArgsMeth, grfst);
+ SubstContext ctx = new SubstContext(typeArgsCls, typeArgsMeth, denormMeth);
- return !ctx.FNop() && SubstEqualTypesCore(typeDst, typeSrc, ctx);
+ return !ctx.IsNop && SubstEqualTypesCore(typeDst, typeSrc, ctx);
}
- public bool SubstEqualTypeArrays(TypeArray taDst, TypeArray taSrc, TypeArray typeArgsCls, TypeArray typeArgsMeth, SubstTypeFlags grfst)
+ public static bool SubstEqualTypeArrays(TypeArray taDst, TypeArray taSrc, TypeArray typeArgsCls, TypeArray typeArgsMeth)
{
// Handle the simple common cases first.
if (taDst == taSrc || (taDst != null && taDst.Equals(taSrc)))
@@ -449,10 +344,12 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (taDst.Count == 0)
return true;
- var ctx = new SubstContext(typeArgsCls, typeArgsMeth, grfst);
+ var ctx = new SubstContext(typeArgsCls, typeArgsMeth, true);
- if (ctx.FNop())
+ if (ctx.IsNop)
+ {
return false;
+ }
for (int i = 0; i < taDst.Count; i++)
{
@@ -463,7 +360,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return true;
}
- private bool SubstEqualTypesCore(CType typeDst, CType typeSrc, SubstContext pctx)
+ private static bool SubstEqualTypesCore(CType typeDst, CType typeSrc, SubstContext pctx)
{
LRecurse: // Label used for "tail" recursion.
@@ -472,7 +369,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
return true;
}
- switch (typeSrc.GetTypeKind())
+ switch (typeSrc.TypeKind)
{
default:
Debug.Assert(false, "Bad Symbol kind in SubstEqualTypesCore");
@@ -481,29 +378,30 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
case TypeKind.TK_NullType:
case TypeKind.TK_VoidType:
// There should only be a single instance of these.
- Debug.Assert(typeDst.GetTypeKind() != typeSrc.GetTypeKind());
+ Debug.Assert(typeDst.TypeKind != typeSrc.TypeKind);
return false;
case TypeKind.TK_ArrayType:
ArrayType arrSrc = (ArrayType)typeSrc;
- if (!(typeDst is ArrayType arrDst) || arrDst.rank != arrSrc.rank || arrDst.IsSZArray != arrSrc.IsSZArray)
+ if (!(typeDst is ArrayType arrDst) || arrDst.Rank != arrSrc.Rank || arrDst.IsSZArray != arrSrc.IsSZArray)
return false;
goto LCheckBases;
case TypeKind.TK_ParameterModifierType:
- if (!(typeDst is ParameterModifierType modDest) ||
- ((pctx.grfst & SubstTypeFlags.NoRefOutDifference) == 0 &&
- modDest.isOut != ((ParameterModifierType)typeSrc).isOut))
+ if (!(typeDst is ParameterModifierType modDest) || modDest.IsOut != ((ParameterModifierType)typeSrc).IsOut)
+ {
return false;
+ }
+
goto LCheckBases;
case TypeKind.TK_PointerType:
case TypeKind.TK_NullableType:
- if (typeDst.GetTypeKind() != typeSrc.GetTypeKind())
+ if (typeDst.TypeKind != typeSrc.TypeKind)
return false;
LCheckBases:
- typeSrc = typeSrc.GetBaseOrParameterOrElementType();
- typeDst = typeDst.GetBaseOrParameterOrElementType();
+ typeSrc = typeSrc.BaseOrParameterOrElementType;
+ typeDst = typeDst.BaseOrParameterOrElementType;
goto LRecurse;
case TypeKind.TK_AggregateType:
@@ -512,15 +410,15 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{ // BLOCK
AggregateType atsSrc = (AggregateType)typeSrc;
- if (atsSrc.getAggregate() != atsDst.getAggregate())
+ if (atsSrc.OwningAggregate != atsDst.OwningAggregate)
return false;
- Debug.Assert(atsSrc.GetTypeArgsAll().Count == atsDst.GetTypeArgsAll().Count);
+ Debug.Assert(atsSrc.TypeArgsAll.Count == atsDst.TypeArgsAll.Count);
// All the args must unify.
- for (int i = 0; i < atsSrc.GetTypeArgsAll().Count; i++)
+ for (int i = 0; i < atsSrc.TypeArgsAll.Count; i++)
{
- if (!SubstEqualTypesCore(atsDst.GetTypeArgsAll()[i], atsSrc.GetTypeArgsAll()[i], pctx))
+ if (!SubstEqualTypesCore(atsDst.TypeArgsAll[i], atsSrc.TypeArgsAll[i], pctx))
return false;
}
}
@@ -528,41 +426,32 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
case TypeKind.TK_TypeParameterType:
{ // BLOCK
- TypeParameterSymbol tvs = ((TypeParameterType)typeSrc).GetTypeParameterSymbol();
+ TypeParameterSymbol tvs = ((TypeParameterType)typeSrc).Symbol;
int index = tvs.GetIndexInTotalParameters();
if (tvs.IsMethodTypeParameter())
{
- if ((pctx.grfst & SubstTypeFlags.DenormMeth) != 0 && tvs.parent != null)
+ if (pctx.DenormMeth && tvs.parent != null)
{
// typeDst == typeSrc was handled above.
Debug.Assert(typeDst != typeSrc);
return false;
}
- Debug.Assert(tvs.GetIndexInOwnParameters() == tvs.GetIndexInTotalParameters());
- Debug.Assert(pctx.prgtypeMeth == null || tvs.GetIndexInTotalParameters() < pctx.ctypeMeth);
- if (index < pctx.ctypeMeth && pctx.prgtypeMeth != null)
- {
- return typeDst == pctx.prgtypeMeth[index];
- }
- if ((pctx.grfst & SubstTypeFlags.NormMeth) != 0)
+
+ Debug.Assert(tvs.GetIndexInOwnParameters() == index);
+ Debug.Assert(tvs.GetIndexInTotalParameters() < pctx.MethodTypes.Length);
+ if (index < pctx.MethodTypes.Length)
{
- return typeDst == GetStdMethTypeVar(index);
+ return typeDst == pctx.MethodTypes[index];
}
}
else
{
- if ((pctx.grfst & SubstTypeFlags.DenormClass) != 0 && tvs.parent != null)
+ Debug.Assert(index < pctx.ClassTypes.Length);
+ if (index < pctx.ClassTypes.Length)
{
- // typeDst == typeSrc was handled above.
- Debug.Assert(typeDst != typeSrc);
- return false;
+ return typeDst == pctx.ClassTypes[index];
}
- Debug.Assert(pctx.prgtypeCls == null || tvs.GetIndexInTotalParameters() < pctx.ctypeCls);
- if (index < pctx.ctypeCls)
- return typeDst == pctx.prgtypeCls[index];
- if ((pctx.grfst & SubstTypeFlags.NormClass) != 0)
- return typeDst == GetStdClsTypeVar(index);
}
}
return false;
@@ -576,7 +465,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
if (type == typeFind || type.Equals(typeFind))
return true;
- switch (type.GetTypeKind())
+ switch (type.TypeKind)
{
default:
Debug.Assert(false, "Bad Symbol kind in TypeContainsType");
@@ -585,23 +474,23 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
case TypeKind.TK_NullType:
case TypeKind.TK_VoidType:
// There should only be a single instance of these.
- Debug.Assert(typeFind.GetTypeKind() != type.GetTypeKind());
+ Debug.Assert(typeFind.TypeKind != type.TypeKind);
return false;
case TypeKind.TK_ArrayType:
case TypeKind.TK_NullableType:
case TypeKind.TK_ParameterModifierType:
case TypeKind.TK_PointerType:
- type = type.GetBaseOrParameterOrElementType();
+ type = type.BaseOrParameterOrElementType;
goto LRecurse;
case TypeKind.TK_AggregateType:
{ // BLOCK
AggregateType ats = (AggregateType)type;
- for (int i = 0; i < ats.GetTypeArgsAll().Count; i++)
+ for (int i = 0; i < ats.TypeArgsAll.Count; i++)
{
- if (TypeContainsType(ats.GetTypeArgsAll()[i], typeFind))
+ if (TypeContainsType(ats.TypeArgsAll[i], typeFind))
return true;
}
}
@@ -615,7 +504,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
public static bool TypeContainsTyVars(CType type, TypeArray typeVars)
{
LRecurse: // Label used for "tail" recursion.
- switch (type.GetTypeKind())
+ switch (type.TypeKind)
{
default:
Debug.Assert(false, "Bad Symbol kind in TypeContainsTyVars");
@@ -630,16 +519,16 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
case TypeKind.TK_NullableType:
case TypeKind.TK_ParameterModifierType:
case TypeKind.TK_PointerType:
- type = type.GetBaseOrParameterOrElementType();
+ type = type.BaseOrParameterOrElementType;
goto LRecurse;
case TypeKind.TK_AggregateType:
{ // BLOCK
AggregateType ats = (AggregateType)type;
- for (int i = 0; i < ats.GetTypeArgsAll().Count; i++)
+ for (int i = 0; i < ats.TypeArgsAll.Count; i++)
{
- if (TypeContainsTyVars(ats.GetTypeArgsAll()[i], typeVars))
+ if (TypeContainsTyVars(ats.TypeArgsAll[i], typeVars))
{
return true;
}
@@ -650,117 +539,53 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
case TypeKind.TK_TypeParameterType:
if (typeVars != null && typeVars.Count > 0)
{
- int ivar = ((TypeParameterType)type).GetIndexInTotalParameters();
+ int ivar = ((TypeParameterType)type).IndexInTotalParameters;
return ivar < typeVars.Count && type == typeVars[ivar];
}
return true;
}
}
- public static bool ParametersContainTyVar(TypeArray @params, TypeParameterType typeFind)
- {
- Debug.Assert(@params != null);
- Debug.Assert(typeFind != null);
- for (int p = 0; p < @params.Count; p++)
- {
- CType sym = @params[p];
- if (TypeContainsType(sym, typeFind))
- {
- return true;
- }
- }
- return false;
- }
+ public static AggregateSymbol GetPredefAgg(PredefinedType pt) => PredefinedTypes.GetPredefinedAggregate(pt);
- public AggregateSymbol GetPredefAgg(PredefinedType pt) => _predefTypes.GetPredefinedAggregate(pt);
+ public static AggregateType SubstType(AggregateType typeSrc, SubstContext ctx) =>
+ ctx == null || ctx.IsNop ? typeSrc : SubstTypeCore(typeSrc, ctx);
- public TypeArray ConcatenateTypeArrays(TypeArray pTypeArray1, TypeArray pTypeArray2)
- {
- return _BSymmgr.ConcatParams(pTypeArray1, pTypeArray2);
- }
+ public static CType SubstType(CType typeSrc, SubstContext pctx) =>
+ pctx == null || pctx.IsNop ? typeSrc : SubstTypeCore(typeSrc, pctx);
- public TypeArray GetStdMethTyVarArray(int cTyVars)
- {
- TypeParameterType[] prgvar = new TypeParameterType[cTyVars];
+ public static CType SubstType(CType typeSrc, AggregateType atsCls) => SubstType(typeSrc, atsCls, null);
- for (int ivar = 0; ivar < cTyVars; ivar++)
- {
- prgvar[ivar] = GetStdMethTypeVar(ivar);
- }
+ public static CType SubstType(CType typeSrc, AggregateType atsCls, TypeArray typeArgsMeth) =>
+ SubstType(typeSrc, atsCls?.TypeArgsAll, typeArgsMeth);
- return _BSymmgr.AllocParams(cTyVars, (CType[])prgvar);
- }
+ public static CType SubstType(CType typeSrc, CType typeCls, TypeArray typeArgsMeth) =>
+ SubstType(typeSrc, (typeCls as AggregateType)?.TypeArgsAll, typeArgsMeth);
- public AggregateType SubstType(AggregateType typeSrc, SubstContext ctx) =>
- ctx == null || ctx.FNop() ? typeSrc : SubstTypeCore(typeSrc, ctx);
+ public static TypeArray SubstTypeArray(TypeArray taSrc, AggregateType atsCls, TypeArray typeArgsMeth) =>
+ SubstTypeArray(taSrc, atsCls?.TypeArgsAll, typeArgsMeth);
- public CType SubstType(CType typeSrc, SubstContext pctx)
- {
- return (pctx == null || pctx.FNop()) ? typeSrc : SubstTypeCore(typeSrc, pctx);
- }
+ public static TypeArray SubstTypeArray(TypeArray taSrc, AggregateType atsCls) => SubstTypeArray(taSrc, atsCls, null);
- public CType SubstType(CType typeSrc, AggregateType atsCls)
- {
- return SubstType(typeSrc, atsCls, (TypeArray)null);
- }
+ private static bool SubstEqualTypes(CType typeDst, CType typeSrc, CType typeCls, TypeArray typeArgsMeth) =>
+ SubstEqualTypes(typeDst, typeSrc, (typeCls as AggregateType)?.TypeArgsAll, typeArgsMeth, false);
- public CType SubstType(CType typeSrc, AggregateType atsCls, TypeArray typeArgsMeth)
- {
- return SubstType(typeSrc, atsCls?.GetTypeArgsAll(), typeArgsMeth);
- }
+ public static bool SubstEqualTypes(CType typeDst, CType typeSrc, CType typeCls) => SubstEqualTypes(typeDst, typeSrc, typeCls, null);
- public CType SubstType(CType typeSrc, CType typeCls, TypeArray typeArgsMeth)
- {
- return SubstType(typeSrc, (typeCls as AggregateType)?.GetTypeArgsAll(), typeArgsMeth);
- }
-
- public TypeArray SubstTypeArray(TypeArray taSrc, AggregateType atsCls, TypeArray typeArgsMeth)
- {
- return SubstTypeArray(taSrc, atsCls?.GetTypeArgsAll(), typeArgsMeth);
- }
-
- public TypeArray SubstTypeArray(TypeArray taSrc, AggregateType atsCls)
- {
- return this.SubstTypeArray(taSrc, atsCls, (TypeArray)null);
- }
-
- private bool SubstEqualTypes(CType typeDst, CType typeSrc, CType typeCls, TypeArray typeArgsMeth)
- {
- return SubstEqualTypes(typeDst, typeSrc, (typeCls as AggregateType)?.GetTypeArgsAll(), typeArgsMeth, SubstTypeFlags.NormNone);
- }
-
- public bool SubstEqualTypes(CType typeDst, CType typeSrc, CType typeCls)
- {
- return SubstEqualTypes(typeDst, typeSrc, typeCls, (TypeArray)null);
- }
-
- //public bool SubstEqualTypeArrays(TypeArray taDst, TypeArray taSrc, AggregateType atsCls, TypeArray typeArgsMeth)
- //{
- // return SubstEqualTypeArrays(taDst, taSrc, atsCls != null ? atsCls.GetTypeArgsAll() : (TypeArray)null, typeArgsMeth, SubstTypeFlags.NormNone);
- //}
-
- public TypeParameterType GetStdMethTypeVar(int iv)
- {
- return _stvcMethod.GetTypeVarSym(iv, this, true);
- }
-
- private TypeParameterType GetStdClsTypeVar(int iv)
- {
- return _stvcClass.GetTypeVarSym(iv, this, false);
- }
+ public static TypeParameterType GetStdMethTypeVar(int iv) => s_stvcMethod.GetTypeVarSym(iv, true);
// These are singletons for each.
- public TypeParameterType GetTypeParameter(TypeParameterSymbol pSymbol)
+ public static TypeParameterType GetTypeParameter(TypeParameterSymbol pSymbol)
{
Debug.Assert(pSymbol.GetTypeParameterType() == null); // Should have been checked first before creating
- return _typeFactory.CreateTypeParameter(pSymbol);
+ return new TypeParameterType(pSymbol);
}
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// RUNTIME BINDER ONLY CHANGE
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- internal bool GetBestAccessibleType(CSemanticChecker semanticChecker, BindingContext bindingContext, CType typeSrc, out CType typeDst)
+ internal static CType GetBestAccessibleType(AggregateSymbol context, CType typeSrc)
{
// This method implements the "best accessible type" algorithm for determining the type
// of untyped arguments in the runtime binder. It is also used in method type inference
@@ -768,200 +593,162 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
// The new type is returned in an out parameter. The result will be true (and the out param
// non-null) only when the algorithm could find a suitable accessible type.
-
- Debug.Assert(semanticChecker != null);
- Debug.Assert(bindingContext != null);
Debug.Assert(typeSrc != null);
+ Debug.Assert(!(typeSrc is ParameterModifierType));
+ Debug.Assert(!(typeSrc is PointerType));
- typeDst = null;
-
- if (semanticChecker.CheckTypeAccess(typeSrc, bindingContext.ContextForMemberLookup))
+ if (CSemanticChecker.CheckTypeAccess(typeSrc, context))
{
- // If we already have an accessible type, then use it. This is the terminal point of the recursion.
- typeDst = typeSrc;
- return true;
+ // If we already have an accessible type, then use it.
+ return typeSrc;
}
// These guys have no accessibility concerns.
Debug.Assert(!(typeSrc is VoidType) && !(typeSrc is TypeParameterType));
- if (typeSrc is ParameterModifierType || typeSrc is PointerType)
- {
- // We cannot vary these.
- return false;
- }
-
- CType intermediateType;
- if (typeSrc is AggregateType aggSrc && (aggSrc.isInterfaceType() || aggSrc.isDelegateType()) && TryVarianceAdjustmentToGetAccessibleType(semanticChecker, bindingContext, aggSrc, out intermediateType))
+ if (typeSrc is AggregateType aggSrc)
{
- // If we have an interface or delegate type, then it can potentially be varied by its type arguments
- // to produce an accessible type, and if that's the case, then return that.
- // Example: IEnumerable<PrivateConcreteFoo> --> IEnumerable<PublicAbstractFoo>
- typeDst = intermediateType;
+ for (;;)
+ {
+ if ((aggSrc.IsInterfaceType || aggSrc.IsDelegateType) && TryVarianceAdjustmentToGetAccessibleType(context, aggSrc, out CType typeDst))
+ {
+ // If we have an interface or delegate type, then it can potentially be varied by its type arguments
+ // to produce an accessible type, and if that's the case, then return that.
+ // Example: IEnumerable<PrivateConcreteFoo> --> IEnumerable<PublicAbstractFoo>
+ Debug.Assert(CSemanticChecker.CheckTypeAccess(typeDst, context));
+ return typeDst;
+ }
- Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup));
- return true;
- }
+ // We have an AggregateType, so recurse on its base class.
+ AggregateType baseType = aggSrc.BaseClass;
+ if (baseType == null)
+ {
+ // This happens with interfaces, for instance. But in that case, the
+ // conversion to object does exist, is an implicit reference conversion,
+ // and is guaranteed to be accessible, so we will use it.
+ return GetPredefAgg(PredefinedType.PT_OBJECT).getThisType();
+ }
- if (typeSrc is ArrayType arrSrc && TryArrayVarianceAdjustmentToGetAccessibleType(semanticChecker, bindingContext, arrSrc, out intermediateType))
- {
- // Similarly to the interface and delegate case, arrays are covariant in their element type and
- // so we can potentially produce an array type that is accessible.
- // Example: PrivateConcreteFoo[] --> PublicAbstractFoo[]
- typeDst = intermediateType;
+ if (CSemanticChecker.CheckTypeAccess(baseType, context))
+ {
+ return baseType;
+ }
- Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup));
- return true;
+ // baseType is always an AggregateType, so no need for logic of other types.
+ aggSrc = baseType;
+ }
}
- if (typeSrc is NullableType)
+ if (typeSrc is ArrayType arrSrc)
{
- // We have an inaccessible nullable type, which means that the best we can do is System.ValueType.
- typeDst = GetPredefAgg(PredefinedType.PT_VALUE).getThisType();
-
- Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup));
- return true;
- }
+ if (TryArrayVarianceAdjustmentToGetAccessibleType(context, arrSrc, out CType typeDst))
+ {
+ // Similarly to the interface and delegate case, arrays are covariant in their element type and
+ // so we can potentially produce an array type that is accessible.
+ // Example: PrivateConcreteFoo[] --> PublicAbstractFoo[]
+ Debug.Assert(CSemanticChecker.CheckTypeAccess(typeDst, context));
+ return typeDst;
+ }
- if (typeSrc is ArrayType)
- {
// We have an inaccessible array type for which we could not earlier find a better array type
// with a covariant conversion, so the best we can do is System.Array.
- typeDst = GetPredefAgg(PredefinedType.PT_ARRAY).getThisType();
-
- Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup));
- return true;
+ return GetPredefAgg(PredefinedType.PT_ARRAY).getThisType();
}
- Debug.Assert(typeSrc is AggregateType);
-
- if (typeSrc is AggregateType aggType)
- {
- // We have an AggregateType, so recurse on its base class.
- AggregateType baseType = aggType.GetBaseClass();
-
- if (baseType == null)
- {
- // This happens with interfaces, for instance. But in that case, the
- // conversion to object does exist, is an implicit reference conversion,
- // and so we will use it.
- baseType = GetPredefAgg(PredefinedType.PT_OBJECT).getThisType();
- }
-
- return GetBestAccessibleType(semanticChecker, bindingContext, baseType, out typeDst);
- }
+ Debug.Assert(typeSrc is NullableType);
- return false;
+ // We have an inaccessible nullable type, which means that the best we can do is System.ValueType.
+ return GetPredefAgg(PredefinedType.PT_VALUE).getThisType();
}
- private bool TryVarianceAdjustmentToGetAccessibleType(CSemanticChecker semanticChecker, BindingContext bindingContext, AggregateType typeSrc, out CType typeDst)
+ private static bool TryVarianceAdjustmentToGetAccessibleType(AggregateSymbol context, AggregateType typeSrc, out CType typeDst)
{
Debug.Assert(typeSrc != null);
- Debug.Assert(typeSrc.isInterfaceType() || typeSrc.isDelegateType());
+ Debug.Assert(typeSrc.IsInterfaceType || typeSrc.IsDelegateType);
typeDst = null;
- AggregateSymbol aggSym = typeSrc.GetOwningAggregate();
+ AggregateSymbol aggSym = typeSrc.OwningAggregate;
AggregateType aggOpenType = aggSym.getThisType();
- if (!semanticChecker.CheckTypeAccess(aggOpenType, bindingContext.ContextForMemberLookup))
+ if (!CSemanticChecker.CheckTypeAccess(aggOpenType, context))
{
// if the aggregate symbol itself is not accessible, then forget it, there is no
// variance that will help us arrive at an accessible type.
return false;
}
- TypeArray typeArgs = typeSrc.GetTypeArgsThis();
- TypeArray typeParams = aggOpenType.GetTypeArgsThis();
+ TypeArray typeArgs = typeSrc.TypeArgsThis;
+ TypeArray typeParams = aggOpenType.TypeArgsThis;
CType[] newTypeArgsTemp = new CType[typeArgs.Count];
- for (int i = 0; i < typeArgs.Count; i++)
+ for (int i = 0; i < newTypeArgsTemp.Length; i++)
{
- if (semanticChecker.CheckTypeAccess(typeArgs[i], bindingContext.ContextForMemberLookup))
+ CType typeArg = typeArgs[i];
+ if (CSemanticChecker.CheckTypeAccess(typeArg, context))
{
// we have an accessible argument, this position is not a problem.
- newTypeArgsTemp[i] = typeArgs[i];
+ newTypeArgsTemp[i] = typeArg;
continue;
}
- if (!typeArgs[i].IsRefType() || !((TypeParameterType)typeParams[i]).Covariant)
+ if (!typeArg.IsReferenceType || !((TypeParameterType)typeParams[i]).Covariant)
{
// This guy is inaccessible, and we are not going to be able to vary him, so we need to fail.
return false;
}
- CType intermediateTypeArg;
- if (GetBestAccessibleType(semanticChecker, bindingContext, typeArgs[i], out intermediateTypeArg))
- {
- // now we either have a value type (which must be accessible due to the above
- // check, OR we have an inaccessible type (which must be a ref type). In either
- // case, the recursion worked out and we are OK to vary this argument.
- newTypeArgsTemp[i] = intermediateTypeArg;
- continue;
- }
- else
- {
- Debug.Assert(false, "GetBestAccessibleType unexpectedly failed on a type that was used as a type parameter");
- return false;
- }
+ newTypeArgsTemp[i] = GetBestAccessibleType(context, typeArg);
+
+ // now we either have a value type (which must be accessible due to the above
+ // check, OR we have an inaccessible type (which must be a ref type). In either
+ // case, the recursion worked out and we are OK to vary this argument.
}
- TypeArray newTypeArgs = semanticChecker.getBSymmgr().AllocParams(typeArgs.Count, newTypeArgsTemp);
- CType intermediateType = this.GetAggregate(aggSym, typeSrc.outerType, newTypeArgs);
+ TypeArray newTypeArgs = TypeArray.Allocate(newTypeArgsTemp);
+ CType intermediateType = GetAggregate(aggSym, typeSrc.OuterType, newTypeArgs);
// All type arguments were varied successfully, which means now we must be accessible. But we could
// have violated constraints. Let's check that out.
- if (!TypeBind.CheckConstraints(semanticChecker, null/*ErrorHandling*/, intermediateType, CheckConstraintsFlags.NoErrors))
+ if (!TypeBind.CheckConstraints(intermediateType, CheckConstraintsFlags.NoErrors))
{
return false;
}
typeDst = intermediateType;
- Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup));
+ Debug.Assert(CSemanticChecker.CheckTypeAccess(typeDst, context));
return true;
}
- private bool TryArrayVarianceAdjustmentToGetAccessibleType(CSemanticChecker semanticChecker, BindingContext bindingContext, ArrayType typeSrc, out CType typeDst)
+ private static bool TryArrayVarianceAdjustmentToGetAccessibleType(AggregateSymbol context, ArrayType typeSrc, out CType typeDst)
{
Debug.Assert(typeSrc != null);
- typeDst = null;
-
// We are here because we have an array type with an inaccessible element type. If possible,
// we should create a new array type that has an accessible element type for which a
// conversion exists.
- CType elementType = typeSrc.GetElementType();
- if (!elementType.IsRefType())
- {
- // Covariant array conversions exist for reference types only.
- return false;
- }
-
- CType intermediateType;
- if (GetBestAccessibleType(semanticChecker, bindingContext, elementType, out intermediateType))
+ CType elementType = typeSrc.ElementType;
+ // Covariant array conversions exist for reference types only.
+ if (elementType.IsReferenceType)
{
- typeDst = this.GetArray(intermediateType, typeSrc.rank, typeSrc.IsSZArray);
+ CType destElement = GetBestAccessibleType(context, elementType);
+ typeDst = GetArray(destElement, typeSrc.Rank, typeSrc.IsSZArray);
- Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup));
+ Debug.Assert(CSemanticChecker.CheckTypeAccess(typeDst, context));
return true;
}
+ typeDst = null;
return false;
}
- public AggregateType ObjectAggregateType => (AggregateType)_symbolTable.GetCTypeFromType(typeof(object));
-
- private readonly Dictionary<Tuple<Assembly, Assembly>, bool> _internalsVisibleToCalculated
- = new Dictionary<Tuple<Assembly, Assembly>, bool>();
-
- internal bool InternalsVisibleTo(Assembly assemblyThatDefinesAttribute, Assembly assemblyToCheck)
+ internal static bool InternalsVisibleTo(Assembly assemblyThatDefinesAttribute, Assembly assemblyToCheck)
{
- bool result;
-
- var key = Tuple.Create(assemblyThatDefinesAttribute, assemblyToCheck);
- if (!_internalsVisibleToCalculated.TryGetValue(key, out result))
+ RuntimeBinder.EnsureLockIsTaken();
+ (Assembly, Assembly) key = (assemblyThatDefinesAttribute, assemblyToCheck);
+ if (!s_internalsVisibleToCache.TryGetValue(key, out bool result))
{
AssemblyName assyName;
@@ -972,20 +759,17 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
try
{
assyName = assemblyToCheck.GetName();
+ result = assemblyThatDefinesAttribute.GetCustomAttributes()
+ .OfType<InternalsVisibleToAttribute>()
+ .Select(ivta => new AssemblyName(ivta.AssemblyName))
+ .Any(an => AssemblyName.ReferenceMatchesDefinition(an, assyName));
}
- catch (System.Security.SecurityException)
+ catch (SecurityException)
{
result = false;
- goto SetMemo;
}
- result = assemblyThatDefinesAttribute.GetCustomAttributes()
- .OfType<InternalsVisibleToAttribute>()
- .Select(ivta => new AssemblyName(ivta.AssemblyName))
- .Any(an => AssemblyName.ReferenceMatchesDefinition(an, assyName));
-
- SetMemo:
- _internalsVisibleToCalculated[key] = result;
+ s_internalsVisibleToCache[key] = result;
}
return result;
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/TypeParameterType_.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/TypeParameterType_.cs
index 8d684daca4..aabc64e2ff 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/TypeParameterType_.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/TypeParameterType_.cs
@@ -2,7 +2,10 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
using System.Diagnostics;
+using System.Reflection;
+using Microsoft.CSharp.RuntimeBinder.Syntax;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
@@ -10,26 +13,54 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
internal sealed class TypeParameterType : CType
{
- public TypeParameterSymbol GetTypeParameterSymbol() { return _pTypeParameterSymbol; }
- public void SetTypeParameterSymbol(TypeParameterSymbol pTypePArameterSymbol) { _pTypeParameterSymbol = pTypePArameterSymbol; }
+ public TypeParameterType(TypeParameterSymbol symbol)
+ : base(TypeKind.TK_TypeParameterType)
+ {
+ Debug.Assert(symbol.GetTypeParameterType() == null);
+ Symbol = symbol;
+ symbol.SetTypeParameterType(this);
+ }
- public ParentSymbol GetOwningSymbol() { return _pTypeParameterSymbol.parent; }
+ public TypeParameterSymbol Symbol { get; }
// Forward calls into the symbol.
- public bool Covariant { get { return _pTypeParameterSymbol.Covariant; } }
- public bool Invariant { get { return _pTypeParameterSymbol.Invariant; } }
- public bool Contravariant { get { return _pTypeParameterSymbol.Contravariant; } }
- public bool IsValueType() { return _pTypeParameterSymbol.IsValueType(); }
- public bool IsReferenceType() { return _pTypeParameterSymbol.IsReferenceType(); }
- public bool IsNonNullableValueType() { return _pTypeParameterSymbol.IsNonNullableValueType(); }
- public bool HasNewConstraint() { return _pTypeParameterSymbol.HasNewConstraint(); }
- public bool HasRefConstraint() { return _pTypeParameterSymbol.HasRefConstraint(); }
- public bool HasValConstraint() { return _pTypeParameterSymbol.HasValConstraint(); }
- public bool IsMethodTypeParameter() { return _pTypeParameterSymbol.IsMethodTypeParameter(); }
- public int GetIndexInOwnParameters() { return _pTypeParameterSymbol.GetIndexInOwnParameters(); }
- public int GetIndexInTotalParameters() { return _pTypeParameterSymbol.GetIndexInTotalParameters(); }
- public TypeArray GetBounds() { return _pTypeParameterSymbol.GetBounds(); }
-
- private TypeParameterSymbol _pTypeParameterSymbol;
+
+ public ParentSymbol OwningSymbol => Symbol.parent;
+
+ public Name Name => Symbol.name;
+
+ public bool Covariant => Symbol.Covariant;
+
+ public bool Invariant => Symbol.Invariant;
+
+ public bool Contravariant => Symbol.Contravariant;
+
+ public override bool IsValueType => Symbol.IsValueType();
+
+ public override bool IsReferenceType => Symbol.IsReferenceType();
+
+ public override bool IsNonNullableValueType => Symbol.IsNonNullableValueType();
+
+ public bool HasNewConstraint => Symbol.HasNewConstraint();
+
+ public bool HasRefConstraint => Symbol.HasRefConstraint();
+
+ public bool HasValConstraint => Symbol.HasValConstraint();
+
+ public bool IsMethodTypeParameter => Symbol.IsMethodTypeParameter();
+
+ public int IndexInOwnParameters => Symbol.GetIndexInOwnParameters();
+
+ public int IndexInTotalParameters => Symbol.GetIndexInTotalParameters();
+
+ public TypeArray Bounds => Symbol.GetBounds();
+
+ public override Type AssociatedSystemType =>
+ (IsMethodTypeParameter
+ ? ((MethodInfo)((MethodSymbol)OwningSymbol).AssociatedMemberInfo).GetGenericArguments()
+ : ((AggregateSymbol)OwningSymbol).AssociatedSystemType.GetGenericArguments()
+ )[IndexInOwnParameters];
+
+ public override FUNDTYPE FundamentalType => FUNDTYPE.FT_VAR;
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/TypeTable.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/TypeTable.cs
index 0540f983ff..00b13acb21 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/TypeTable.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/TypeTable.cs
@@ -6,145 +6,130 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
-using Microsoft.CSharp.RuntimeBinder.Syntax;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
- internal readonly struct KeyPair<Key1, Key2> : IEquatable<KeyPair<Key1, Key2>>
+ internal static class TypeTable
{
- private readonly Key1 _pKey1;
- private readonly Key2 _pKey2;
-
- public KeyPair(Key1 pKey1, Key2 pKey2)
+ private readonly struct KeyPair<TKey1, TKey2> : IEquatable<KeyPair<TKey1, TKey2>>
{
- _pKey1 = pKey1;
- _pKey2 = pKey2;
- }
+ private readonly TKey1 _pKey1;
+ private readonly TKey2 _pKey2;
- public bool Equals(KeyPair<Key1, Key2> other)
- {
- return EqualityComparer<Key1>.Default.Equals(_pKey1, other._pKey1)
- && EqualityComparer<Key2>.Default.Equals(_pKey2, other._pKey2);
- }
+ public KeyPair(TKey1 pKey1, TKey2 pKey2)
+ {
+ _pKey1 = pKey1;
+ _pKey2 = pKey2;
+ }
+
+ public bool Equals(KeyPair<TKey1, TKey2> other) =>
+ EqualityComparer<TKey1>.Default.Equals(_pKey1, other._pKey1)
+ && EqualityComparer<TKey2>.Default.Equals(_pKey2, other._pKey2);
-#if DEBUG
- [ExcludeFromCodeCoverage] // Typed overload should always be the method called.
+#if DEBUG
+ [ExcludeFromCodeCoverage] // Typed overload should always be the method called.
#endif
- public override bool Equals(object obj)
- {
- Debug.Fail("Sub-optimal overload called. Check if this can be avoided.");
- if (!(obj is KeyPair<Key1, Key2>)) return false;
- return Equals((KeyPair<Key1, Key2>)obj);
- }
+ public override bool Equals(object obj)
+ {
+ Debug.Fail("Sub-optimal overload called. Check if this can be avoided.");
+ if (!(obj is KeyPair<TKey1, TKey2>))
+ {
+ return false;
+ }
- public override int GetHashCode()
- {
- int hash = _pKey1 == null ? 0 : _pKey1.GetHashCode();
- return (hash << 5) - hash + (_pKey2 == null ? 0 : _pKey2.GetHashCode());
- }
- }
+ return Equals((KeyPair<TKey1, TKey2>)obj);
+ }
- internal sealed class TypeTable
- {
+ public override int GetHashCode()
+ {
+ int hash = _pKey1 == null ? 0 : _pKey1.GetHashCode();
+ return (hash << 5) - hash + (_pKey2 == null ? 0 : _pKey2.GetHashCode());
+ }
+ }
+
+ // The RuntimeBinder uses a global lock when Binding that keeps these dictionary safe.
// Two way hashes
- private readonly Dictionary<KeyPair<AggregateSymbol, KeyPair<AggregateType, TypeArray>>, AggregateType> _aggregateTable;
- private readonly Dictionary<KeyPair<CType, Name>, ArrayType> _pArrayTable;
- private readonly Dictionary<KeyPair<CType, Name>, ParameterModifierType> _pParameterModifierTable;
+ private static readonly Dictionary<KeyPair<AggregateSymbol, KeyPair<AggregateType, TypeArray>>, AggregateType> s_aggregateTable =
+ new Dictionary<KeyPair<AggregateSymbol, KeyPair<AggregateType, TypeArray>>, AggregateType>();
- // One way hashes
- private readonly Dictionary<CType, PointerType> _pPointerTable;
- private readonly Dictionary<CType, NullableType> _pNullableTable;
+ private static readonly Dictionary<KeyPair<CType, int>, ArrayType> s_arrayTable =
+ new Dictionary<KeyPair<CType, int>, ArrayType>();
- public TypeTable()
- {
- _aggregateTable = new Dictionary<KeyPair<AggregateSymbol, KeyPair<AggregateType, TypeArray>>, AggregateType>();
- _pArrayTable = new Dictionary<KeyPair<CType, Name>, ArrayType>();
- _pParameterModifierTable = new Dictionary<KeyPair<CType, Name>, ParameterModifierType>();
- _pPointerTable = new Dictionary<CType, PointerType>();
- _pNullableTable = new Dictionary<CType, NullableType>();
- }
+ private static readonly Dictionary<KeyPair<CType, bool>, ParameterModifierType> s_parameterModifierTable =
+ new Dictionary<KeyPair<CType, bool>, ParameterModifierType>();
+
+ // One way hashes
+ private static readonly Dictionary<CType, PointerType> s_pointerTable = new Dictionary<CType, PointerType>();
+ private static readonly Dictionary<CType, NullableType> s_nullableTable = new Dictionary<CType, NullableType>();
private static KeyPair<TKey1, TKey2> MakeKey<TKey1, TKey2>(TKey1 key1, TKey2 key2) =>
new KeyPair<TKey1, TKey2>(key1, key2);
- public AggregateType LookupAggregate(AggregateSymbol aggregate, AggregateType outer, TypeArray args)
+ public static AggregateType LookupAggregate(AggregateSymbol aggregate, AggregateType outer, TypeArray args)
{
- _aggregateTable.TryGetValue(MakeKey(aggregate, MakeKey(outer, args)), out AggregateType result);
+ RuntimeBinder.EnsureLockIsTaken();
+ s_aggregateTable.TryGetValue(MakeKey(aggregate, MakeKey(outer, args)), out AggregateType result);
return result;
}
- public void InsertAggregate(
- AggregateSymbol aggregate, AggregateType outer, TypeArray args, AggregateType pAggregate)
+ public static void InsertAggregate(AggregateSymbol aggregate, AggregateType outer, TypeArray args, AggregateType ats)
{
+ RuntimeBinder.EnsureLockIsTaken();
Debug.Assert(LookupAggregate(aggregate, outer, args) == null);
- _aggregateTable.Add(MakeKey(aggregate, MakeKey(outer, args)), pAggregate);
+ s_aggregateTable.Add(MakeKey(aggregate, MakeKey(outer, args)), ats);
}
- public ArrayType LookupArray(Name pName, CType pElementType)
+ // rankNum is 0 for SZ arrays, equal to rank otherwise.
+ public static ArrayType LookupArray(CType elementType, int rankNum)
{
- var key = new KeyPair<CType, Name>(pElementType, pName);
- ArrayType result;
- if (_pArrayTable.TryGetValue(key, out result))
- {
- return result;
- }
- return null;
+ RuntimeBinder.EnsureLockIsTaken();
+ s_arrayTable.TryGetValue(new KeyPair<CType, int>(elementType, rankNum), out ArrayType result);
+ return result;
}
- public void InsertArray(Name pName, CType pElementType, ArrayType pArray)
+ public static void InsertArray(CType elementType, int rankNum, ArrayType pArray)
{
- Debug.Assert(LookupArray(pName, pElementType) == null);
- _pArrayTable.Add(new KeyPair<CType, Name>(pElementType, pName), pArray);
+ RuntimeBinder.EnsureLockIsTaken();
+ Debug.Assert(LookupArray(elementType, rankNum) == null);
+ s_arrayTable.Add(new KeyPair<CType, int>(elementType, rankNum), pArray);
}
- public ParameterModifierType LookupParameterModifier(Name pName, CType pElementType)
+ public static ParameterModifierType LookupParameterModifier(CType elementType, bool isOut)
{
- var key = new KeyPair<CType, Name>(pElementType, pName);
- ParameterModifierType result;
- if (_pParameterModifierTable.TryGetValue(key, out result))
- {
- return result;
- }
- return null;
+ RuntimeBinder.EnsureLockIsTaken();
+ s_parameterModifierTable.TryGetValue(new KeyPair<CType, bool>(elementType, isOut), out ParameterModifierType result);
+ return result;
}
- public void InsertParameterModifier(
- Name pName,
- CType pElementType,
- ParameterModifierType pParameterModifier)
+ public static void InsertParameterModifier(CType elementType, bool isOut, ParameterModifierType parameterModifier)
{
- Debug.Assert(LookupParameterModifier(pName, pElementType) == null);
- _pParameterModifierTable.Add(new KeyPair<CType, Name>(pElementType, pName), pParameterModifier);
+ RuntimeBinder.EnsureLockIsTaken();
+ Debug.Assert(LookupParameterModifier(elementType, isOut) == null);
+ s_parameterModifierTable.Add(new KeyPair<CType, bool>(elementType, isOut), parameterModifier);
}
- public PointerType LookupPointer(CType pElementType)
+ public static PointerType LookupPointer(CType elementType)
{
- PointerType result;
- if (_pPointerTable.TryGetValue(pElementType, out result))
- {
- return result;
- }
- return null;
+ s_pointerTable.TryGetValue(elementType, out PointerType result);
+ return result;
}
- public void InsertPointer(CType pElementType, PointerType pPointer)
+ public static void InsertPointer(CType elementType, PointerType pointer)
{
- _pPointerTable.Add(pElementType, pPointer);
+ Debug.Assert(LookupPointer(elementType) == null);
+ s_pointerTable.Add(elementType, pointer);
}
- public NullableType LookupNullable(CType pUnderlyingType)
+ public static NullableType LookupNullable(CType underlyingType)
{
- NullableType result;
- if (_pNullableTable.TryGetValue(pUnderlyingType, out result))
- {
- return result;
- }
- return null;
+ s_nullableTable.TryGetValue(underlyingType, out NullableType result);
+ return result;
}
- public void InsertNullable(CType pUnderlyingType, NullableType pNullable)
+ public static void InsertNullable(CType underlyingType, NullableType nullable)
{
- _pNullableTable.Add(pUnderlyingType, pNullable);
+ Debug.Assert(LookupNullable(underlyingType) == null);
+ s_nullableTable.Add(underlyingType, nullable);
}
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/VoidType.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/VoidType.cs
index 082a45801c..9c57aa1904 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/VoidType.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/Types/VoidType.cs
@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using Microsoft.CSharp.RuntimeBinder.Syntax;
+
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
// ----------------------------------------------------------------------------
@@ -10,5 +12,13 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
internal sealed class VoidType : CType
{
+ public static readonly VoidType Instance = new VoidType();
+
+ private VoidType()
+ : base(TypeKind.TK_VoidType)
+ {
+ }
+
+ public override bool IsPredefType(PredefinedType pt) => pt == PredefinedType.PT_VOID;
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/UnaOpSig.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/UnaOpSig.cs
index 0542d12c84..9e5567538a 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/UnaOpSig.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/UnaOpSig.cs
@@ -7,7 +7,7 @@ using Microsoft.CSharp.RuntimeBinder.Syntax;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
- internal sealed partial class ExpressionBinder
+ internal readonly partial struct ExpressionBinder
{
private class UnaOpSig
{
@@ -58,7 +58,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
this.pfn = uos.pfn;
this.fnkind = uos.fnkind;
Debug.Assert(pt != PredefinedType.PT_UNDEFINEDINDEX);
- _type = pt != PredefinedType.PT_UNDEFINEDINDEX ? fnc.GetPredefindType(pt) : null;
+ _type = pt != PredefinedType.PT_UNDEFINEDINDEX ? GetPredefindType(pt) : null;
_grflt = LiftFlags.None;
}
public bool FPreDef()
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/UtilityTypeExtensions.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/UtilityTypeExtensions.cs
deleted file mode 100644
index dc015c394a..0000000000
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/UtilityTypeExtensions.cs
+++ /dev/null
@@ -1,45 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-
-namespace Microsoft.CSharp.RuntimeBinder.Semantics
-{
- internal static class UtilityTypeExtensions
- {
-
- private static IEnumerable<AggregateType> TypeAndBaseClasses(this AggregateType type)
- {
- Debug.Assert(type != null);
- AggregateType t = type;
- while (t != null)
- {
- yield return t;
- t = t.GetBaseClass();
- }
- }
-
- private static IEnumerable<AggregateType> TypeAndBaseClassInterfaces(this AggregateType type)
- {
- Debug.Assert(type != null);
- foreach (AggregateType b in type.TypeAndBaseClasses())
- foreach (AggregateType t in b.GetIfacesAll().Items)
- yield return t;
- }
-
- public static IEnumerable<AggregateType> AllPossibleInterfaces(this CType type)
- {
- Debug.Assert(type != null);
- if (type is AggregateType ats)
- {
- return ats.TypeAndBaseClassInterfaces();
- }
-
- Debug.Assert(type is NullableType); // Is even this case possible?
- return Array.Empty<AggregateType>();
- }
- }
-}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/WithType.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/WithType.cs
index 41c5d9944c..e9a431a326 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/WithType.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/WithType.cs
@@ -129,7 +129,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
if (sym == null)
ats = null;
- Debug.Assert(ats == null || sym.parent == ats.getAggregate());
+ Debug.Assert(ats == null || sym.parent == ats.OwningAggregate);
_sym = sym;
_ats = ats;
}
@@ -231,7 +231,7 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics
ats = null;
typeArgs = null;
}
- Debug.Assert(ats == null || mps != null && mps.getClass() == ats.getAggregate());
+ Debug.Assert(ats == null || mps != null && mps.getClass() == ats.OwningAggregate);
base.Set(mps, ats);
TypeArgs = typeArgs;
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/SpecialNames.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/SpecialNames.cs
index a787b8af94..d56b95ab29 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/SpecialNames.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/SpecialNames.cs
@@ -50,9 +50,7 @@ namespace Microsoft.CSharp.RuntimeBinder
public const string CLR_True = "op_True";
public const string CLR_False = "op_False";
- public const string CLR_PreIncrement = "op_Increment";
- public const string CLR_PostIncrement = "op_Increment";
- public const string CLR_PreDecrement = "op_Decrement";
- public const string CLR_PostDecrement = "op_Decrement";
+ public const string CLR_Increment = "op_Increment";
+ public const string CLR_Decrement = "op_Decrement";
}
}
diff --git a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/SymbolTable.cs b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/SymbolTable.cs
index af53592265..066d75f8af 100644
--- a/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/SymbolTable.cs
+++ b/src/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/SymbolTable.cs
@@ -15,72 +15,37 @@ using Microsoft.CSharp.RuntimeBinder.Syntax;
namespace Microsoft.CSharp.RuntimeBinder
{
- internal sealed class SymbolTable
+ internal static class SymbolTable
{
- /////////////////////////////////////////////////////////////////////////////////
- // Members
- private readonly HashSet<Type> _typesWithConversionsLoaded = new HashSet<Type>();
- private readonly HashSet<NameHashKey> _namesLoadedForEachType = new HashSet<NameHashKey>();
-
- // Members from the managed binder.
- private readonly SYMTBL _symbolTable;
- private readonly SymFactory _symFactory;
- private readonly TypeManager _typeManager;
- private readonly BSYMMGR _bsymmgr;
- private readonly CSemanticChecker _semanticChecker;
+ private static readonly HashSet<Type> s_typesWithConversionsLoaded = new HashSet<Type>();
+ private static readonly HashSet<NameHashKey> s_namesLoadedForEachType = new HashSet<NameHashKey>();
- /////////////////////////////////////////////////////////////////////////////////
-
- private sealed class NameHashKey : IEquatable<NameHashKey>
+ private readonly struct NameHashKey : IEquatable<NameHashKey>
{
- internal readonly Type type;
- internal readonly string name;
+ internal Type Type { get; }
+ internal string Name { get; }
public NameHashKey(Type type, string name)
{
- this.type = type;
- this.name = name;
+ Type = type;
+ Name = name;
}
- public bool Equals(NameHashKey other) => other != null && type.Equals(other.type) && name.Equals(other.name);
+ public bool Equals(NameHashKey other) => Type.Equals(other.Type) && Name.Equals(other.Name);
-#if DEBUG
+#if DEBUG
[ExcludeFromCodeCoverage] // Typed overload should always be the method called.
#endif
public override bool Equals(object obj)
{
Debug.Fail("Sub-optimal overload called. Check if this can be avoided.");
- return Equals(obj as NameHashKey);
+ return obj is NameHashKey key && Equals(key);
}
- public override int GetHashCode()
- {
- return type.GetHashCode() ^ name.GetHashCode();
- }
+ public override int GetHashCode() => Type.GetHashCode() ^ Name.GetHashCode();
}
- /////////////////////////////////////////////////////////////////////////////////
-
- internal SymbolTable(
- SYMTBL symTable,
- SymFactory symFactory,
- TypeManager typeManager,
- BSYMMGR bsymmgr,
- CSemanticChecker semanticChecker)
- {
- _symbolTable = symTable;
- _symFactory = symFactory;
- _typeManager = typeManager;
- _bsymmgr = bsymmgr;
- _semanticChecker = semanticChecker;
-
- // Now populate object.
- LoadSymbolsFromType(typeof(object));
- }
-
- /////////////////////////////////////////////////////////////////////////////////
-
- internal void PopulateSymbolTableWithName(
+ internal static void PopulateSymbolTableWithName(
string name,
IEnumerable<Type> typeArguments,
Type callingType)
@@ -101,7 +66,7 @@ namespace Microsoft.CSharp.RuntimeBinder
NameHashKey key = new NameHashKey(callingType, name);
// If we've already populated this name/type pair, then just leave.
- if (_namesLoadedForEachType.Contains(key))
+ if (s_namesLoadedForEachType.Contains(key))
{
return;
}
@@ -121,7 +86,7 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
- internal SymWithType LookupMember(
+ internal static SymWithType LookupMember(
string name,
Expr callingObject,
ParentSymbol context,
@@ -134,7 +99,7 @@ namespace Microsoft.CSharp.RuntimeBinder
if (type is ArrayType)
{
- type = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_ARRAY);
+ type = SymbolLoader.GetPredefindType(PredefinedType.PT_ARRAY);
}
if (type is NullableType nub)
{
@@ -142,7 +107,6 @@ namespace Microsoft.CSharp.RuntimeBinder
}
if (!mem.Lookup(
- _semanticChecker,
type,
callingObject,
context,
@@ -158,7 +122,7 @@ namespace Microsoft.CSharp.RuntimeBinder
return mem.SwtFirst();
}
- private void AddParameterConversions(MethodBase method)
+ private static void AddParameterConversions(MethodBase method)
{
foreach (ParameterInfo param in method.GetParameters())
{
@@ -167,20 +131,20 @@ namespace Microsoft.CSharp.RuntimeBinder
}
#region InheritanceHierarchy
- private void AddNamesOnType(NameHashKey key)
+ private static void AddNamesOnType(NameHashKey key)
{
- Debug.Assert(!_namesLoadedForEachType.Contains(key));
+ Debug.Assert(!s_namesLoadedForEachType.Contains(key));
// We need to declare all of its inheritance hierarchy.
- List<Type> inheritance = CreateInheritanceHierarchyList(key.type);
+ List<Type> inheritance = CreateInheritanceHierarchyList(key.Type);
// Now add every method as it appears in the inheritance hierarchy.
- AddNamesInInheritanceHierarchy(key.name, inheritance);
+ AddNamesInInheritanceHierarchy(key.Name, inheritance);
}
/////////////////////////////////////////////////////////////////////////////////
- private void AddNamesInInheritanceHierarchy(string name, List<Type> inheritance)
+ private static void AddNamesInInheritanceHierarchy(string name, List<Type> inheritance)
{
for (int i = inheritance.Count - 1; i >= 0; --i)
{
@@ -190,7 +154,7 @@ namespace Microsoft.CSharp.RuntimeBinder
type = type.GetGenericTypeDefinition();
}
- if (!_namesLoadedForEachType.Add(new NameHashKey(type, name)))
+ if (!s_namesLoadedForEachType.Add(new NameHashKey(type, name)))
{
continue;
}
@@ -206,7 +170,7 @@ namespace Microsoft.CSharp.RuntimeBinder
CType cType = GetCTypeFromType(type);
if (!(cType is AggregateType aggType))
continue;
- AggregateSymbol aggregate = aggType.getAggregate();
+ AggregateSymbol aggregate = aggType.OwningAggregate;
FieldSymbol addedField = null;
// We need to add fields before the actual events, so do the first iteration
@@ -275,7 +239,7 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
- private List<Type> CreateInheritanceHierarchyList(Type type)
+ private static List<Type> CreateInheritanceHierarchyList(Type type)
{
List<Type> list;
if (type.IsInterface)
@@ -313,14 +277,11 @@ namespace Microsoft.CSharp.RuntimeBinder
// If we have a WinRT type then we should load the members of it's collection interfaces
// as well as those members are on this type as far as the user is concerned.
CType ctype = GetCTypeFromType(type);
- if (ctype.IsWindowsRuntimeType())
+ if (ctype.IsWindowsRuntimeType)
{
- TypeArray collectioniFaces = ((AggregateType)ctype).GetWinRTCollectionIfacesAll(_semanticChecker.SymbolLoader);
-
- for (int i = 0; i < collectioniFaces.Count; i++)
+ foreach (CType collectionType in ((AggregateType)ctype).WinRTCollectionIfacesAll.Items)
{
- CType collectionType = collectioniFaces[i];
- Debug.Assert(collectionType.isInterfaceType());
+ Debug.Assert(collectionType.IsInterfaceType);
// Insert into our list of Types.
list.Add(collectionType.AssociatedSystemType);
@@ -333,14 +294,11 @@ namespace Microsoft.CSharp.RuntimeBinder
#region GetName
/////////////////////////////////////////////////////////////////////////////////
- private Name GetName(string p)
- {
- return NameManager.Add(p ?? "");
- }
+ private static Name GetName(string p) => NameManager.Add(p ?? "");
/////////////////////////////////////////////////////////////////////////////////
- private Name GetName(Type type)
+ private static Name GetName(Type type)
{
string name = type.Name;
if (type.IsGenericType)
@@ -360,7 +318,7 @@ namespace Microsoft.CSharp.RuntimeBinder
#region TypeParameters
/////////////////////////////////////////////////////////////////////////////////
- private TypeArray GetMethodTypeParameters(MethodInfo method, MethodSymbol parent)
+ private static TypeArray GetMethodTypeParameters(MethodInfo method, MethodSymbol parent)
{
if (method.IsGenericMethod)
{
@@ -376,18 +334,18 @@ namespace Microsoft.CSharp.RuntimeBinder
for (int i = 0; i < genericArguments.Length; i++)
{
Type t = genericArguments[i];
- ((TypeParameterType)ctypes[i]).GetTypeParameterSymbol().SetBounds(
- _bsymmgr.AllocParams(
- GetCTypeArrayFromTypes(t.GetGenericParameterConstraints())));
+ ((TypeParameterType)ctypes[i]).Symbol.SetBounds(TypeArray.Allocate(GetCTypeArrayFromTypes(t.GetGenericParameterConstraints())));
}
- return _bsymmgr.AllocParams(ctypes.Length, ctypes);
+
+ return TypeArray.Allocate(ctypes);
}
- return BSYMMGR.EmptyTypeArray();
+
+ return TypeArray.Empty;
}
/////////////////////////////////////////////////////////////////////////////////
- private TypeArray GetAggregateTypeParameters(Type type, AggregateSymbol agg)
+ private static TypeArray GetAggregateTypeParameters(Type type, AggregateSymbol agg)
{
if (type.IsGenericType)
{
@@ -430,26 +388,28 @@ namespace Microsoft.CSharp.RuntimeBinder
// We check to make sure we own the type parameter - this is because we're
// currently calculating TypeArgsThis, NOT TypeArgsAll.
- if (((TypeParameterType)ctype).GetOwningSymbol() == agg)
+ if (((TypeParameterType)ctype).OwningSymbol == agg)
{
ctypes.Add(ctype);
}
}
- return _bsymmgr.AllocParams(ctypes.Count, ctypes.ToArray());
+
+ return TypeArray.Allocate(ctypes.ToArray());
}
- return BSYMMGR.EmptyTypeArray();
+
+ return TypeArray.Empty;
}
/////////////////////////////////////////////////////////////////////////////////
- private TypeParameterType LoadClassTypeParameter(AggregateSymbol parent, Type t)
+ private static TypeParameterType LoadClassTypeParameter(AggregateSymbol parent, Type t)
{
for (AggregateSymbol p = parent; p != null; p = p.parent as AggregateSymbol)
{
- for (TypeParameterSymbol typeParam = _bsymmgr.LookupAggMember(
+ for (TypeParameterSymbol typeParam = SymbolStore.LookupSym(
GetName(t), p, symbmask_t.MASK_TypeParameterSymbol) as TypeParameterSymbol;
typeParam != null;
- typeParam = BSYMMGR.LookupNextSym(typeParam, p, symbmask_t.MASK_TypeParameterSymbol) as TypeParameterSymbol)
+ typeParam = typeParam.LookupNext(symbmask_t.MASK_TypeParameterSymbol) as TypeParameterSymbol)
{
if (AreTypeParametersEquivalent(typeParam.GetTypeParameterType().AssociatedSystemType, t))
{
@@ -462,7 +422,7 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
- private bool AreTypeParametersEquivalent(Type t1, Type t2)
+ private static bool AreTypeParametersEquivalent(Type t1, Type t2)
{
Debug.Assert(t1.IsGenericParameter && t2.IsGenericParameter);
@@ -512,7 +472,7 @@ namespace Microsoft.CSharp.RuntimeBinder
// return the type parameter type given if it is in a method, we do not try to
// generalize these occurrences for reference equality.
//
- private Type GetOriginalTypeParameterType(Type t)
+ private static Type GetOriginalTypeParameterType(Type t)
{
Debug.Assert(t.IsGenericParameter);
@@ -555,19 +515,17 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
- private TypeParameterType LoadMethodTypeParameter(MethodSymbol parent, Type t)
+ private static TypeParameterType LoadMethodTypeParameter(MethodSymbol parent, Type t)
{
for (Symbol sym = parent.firstChild; sym != null; sym = sym.nextChild)
{
- if (!(sym is TypeParameterSymbol parSym))
+ if (sym is TypeParameterSymbol parSym)
{
- continue;
- }
-
- TypeParameterType type = parSym.GetTypeParameterType();
- if (AreTypeParametersEquivalent(type.AssociatedSystemType, t))
- {
- return type;
+ TypeParameterType type = parSym.GetTypeParameterType();
+ if (AreTypeParametersEquivalent(type.AssociatedSystemType, t))
+ {
+ return type;
+ }
}
}
@@ -576,7 +534,7 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
- private TypeParameterType AddTypeParameterToSymbolTable(
+ private static TypeParameterType AddTypeParameterToSymbolTable(
AggregateSymbol agg,
MethodSymbol meth,
Type t,
@@ -587,7 +545,7 @@ namespace Microsoft.CSharp.RuntimeBinder
TypeParameterSymbol typeParam;
if (bIsAggregate)
{
- typeParam = _symFactory.CreateClassTypeParameter(
+ typeParam = SymFactory.CreateClassTypeParameter(
GetName(t),
agg,
t.GenericParameterPosition,
@@ -595,7 +553,7 @@ namespace Microsoft.CSharp.RuntimeBinder
}
else
{
- typeParam = _symFactory.CreateMethodTypeParameter(
+ typeParam = SymFactory.CreateMethodTypeParameter(
GetName(t),
meth,
t.GenericParameterPosition,
@@ -628,7 +586,7 @@ namespace Microsoft.CSharp.RuntimeBinder
typeParam.SetConstraints(cons);
typeParam.SetAccess(ACCESS.ACC_PUBLIC);
- TypeParameterType typeParamType = _typeManager.GetTypeParameter(typeParam);
+ TypeParameterType typeParamType = TypeManager.GetTypeParameter(typeParam);
return typeParamType;
}
@@ -638,7 +596,7 @@ namespace Microsoft.CSharp.RuntimeBinder
#region LoadTypeChain
/////////////////////////////////////////////////////////////////////////////////
- private CType LoadSymbolsFromType(Type type)
+ private static CType LoadSymbolsFromType(Type type)
{
List<object> declarationChain = BuildDeclarationChain(type);
@@ -653,11 +611,11 @@ namespace Microsoft.CSharp.RuntimeBinder
{
if (t.IsNullableType())
{
- return _typeManager.GetNullable(GetCTypeFromType(t.GetGenericArguments()[0]));
+ return TypeManager.GetNullable(GetCTypeFromType(t.GetGenericArguments()[0]));
}
AggregateSymbol next = FindSymForType(
- _symbolTable.LookupSym(GetName(t), current, symbmask_t.MASK_AggregateSymbol), t);
+ SymbolStore.LookupSym(GetName(t), current, symbmask_t.MASK_AggregateSymbol), t);
// If we haven't found this type yet, then add it to our symbol table.
if (next == null)
@@ -702,7 +660,7 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
- private TypeParameterType ProcessMethodTypeParameter(MethodInfo methinfo, Type t, AggregateSymbol parent)
+ private static TypeParameterType ProcessMethodTypeParameter(MethodInfo methinfo, Type t, AggregateSymbol parent)
{
MethodSymbol meth = FindMatchingMethod(methinfo, parent);
if (meth == null)
@@ -715,12 +673,13 @@ namespace Microsoft.CSharp.RuntimeBinder
// type parameter on it.
Debug.Assert(meth != null);
}
+
return LoadMethodTypeParameter(meth, t);
}
/////////////////////////////////////////////////////////////////////////////////
- private CType GetConstructedType(Type type, AggregateSymbol agg)
+ private static CType GetConstructedType(Type type, AggregateSymbol agg)
{
// We've found the one we want, so return it.
if (type.IsGenericType)
@@ -733,8 +692,8 @@ namespace Microsoft.CSharp.RuntimeBinder
types.Add(GetCTypeFromType(argument));
}
- TypeArray typeArray = _bsymmgr.AllocParams(types.ToArray());
- AggregateType aggType = _typeManager.GetAggregate(agg, typeArray);
+ TypeArray typeArray = TypeArray.Allocate(types.ToArray());
+ AggregateType aggType = TypeManager.GetAggregate(agg, typeArray);
return aggType;
}
CType ctype = agg.getThisType();
@@ -743,7 +702,7 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
- private CType ProcessSpecialTypeInChain(NamespaceOrAggregateSymbol parent, Type t)
+ private static CType ProcessSpecialTypeInChain(NamespaceOrAggregateSymbol parent, Type t)
{
if (t.IsGenericParameter)
{
@@ -755,7 +714,7 @@ namespace Microsoft.CSharp.RuntimeBinder
if (t.IsArray)
{
// Now we return an array of nesting level corresponding to the rank.
- return _typeManager.GetArray(
+ return TypeManager.GetArray(
GetCTypeFromType(t.GetElementType()),
t.GetArrayRank(),
#if netcoreapp
@@ -769,7 +728,7 @@ namespace Microsoft.CSharp.RuntimeBinder
if (t.IsPointer)
{
// Now we return the pointer type that we want.
- return _typeManager.GetPointer(GetCTypeFromType(t.GetElementType()));
+ return TypeManager.GetPointer(GetCTypeFromType(t.GetElementType()));
}
return null;
@@ -841,7 +800,7 @@ namespace Microsoft.CSharp.RuntimeBinder
// to lookup names of types for real (only names of members).
// For either case, move onto the next symbol in the chain, and check again for appropriate type.
- private AggregateSymbol FindSymForType(Symbol sym, Type t)
+ private static AggregateSymbol FindSymForType(Symbol sym, Type t)
{
while (sym != null)
{
@@ -858,18 +817,18 @@ namespace Microsoft.CSharp.RuntimeBinder
return null;
}
- private NamespaceSymbol AddNamespaceToSymbolTable(NamespaceOrAggregateSymbol parent, string sz)
+ private static NamespaceSymbol AddNamespaceToSymbolTable(NamespaceOrAggregateSymbol parent, string sz)
{
Name name = GetName(sz);
- return _symbolTable.LookupSym(name, parent, symbmask_t.MASK_NamespaceSymbol) as NamespaceSymbol
- ?? _symFactory.CreateNamespace(name, parent as NamespaceSymbol);
+ return SymbolStore.LookupSym(name, parent, symbmask_t.MASK_NamespaceSymbol) as NamespaceSymbol
+ ?? SymFactory.CreateNamespace(name, parent as NamespaceSymbol);
}
#endregion
#region CTypeFromType
/////////////////////////////////////////////////////////////////////////////////
- internal CType[] GetCTypeArrayFromTypes(Type[] types)
+ internal static CType[] GetCTypeArrayFromTypes(Type[] types)
{
Debug.Assert(types != null);
@@ -892,8 +851,8 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
- internal CType GetCTypeFromType(Type type) => type.IsByRef
- ? _typeManager.GetParameterModifier(LoadSymbolsFromType(type.GetElementType()), false)
+ internal static CType GetCTypeFromType(Type type) => type.IsByRef
+ ? TypeManager.GetParameterModifier(LoadSymbolsFromType(type.GetElementType()), false)
: LoadSymbolsFromType(type);
#endregion
@@ -901,11 +860,11 @@ namespace Microsoft.CSharp.RuntimeBinder
#region Aggregates
/////////////////////////////////////////////////////////////////////////////////
- private AggregateSymbol AddAggregateToSymbolTable(
+ private static AggregateSymbol AddAggregateToSymbolTable(
NamespaceOrAggregateSymbol parent,
Type type)
{
- AggregateSymbol agg = _symFactory.CreateAggregate(GetName(type), parent, _typeManager);
+ AggregateSymbol agg = SymFactory.CreateAggregate(GetName(type), parent);
agg.AssociatedSystemType = type.IsGenericType ? type.GetGenericTypeDefinition() : type;
agg.AssociatedAssembly = type.Assembly;
@@ -943,7 +902,7 @@ namespace Microsoft.CSharp.RuntimeBinder
}
}
agg.SetAggKind(kind);
- agg.SetTypeVars(BSYMMGR.EmptyTypeArray());
+ agg.SetTypeVars(TypeArray.Empty);
ACCESS access;
if (type.IsPublic)
@@ -1002,9 +961,7 @@ namespace Microsoft.CSharp.RuntimeBinder
Type t = genericArguments[i];
if (agg.GetTypeVars()[i] is TypeParameterType typeVar)
{
- typeVar.GetTypeParameterSymbol().SetBounds(
- _bsymmgr.AllocParams(
- GetCTypeArrayFromTypes(t.GetGenericParameterConstraints())));
+ typeVar.Symbol.SetBounds(TypeArray.Allocate(GetCTypeArrayFromTypes(t.GetGenericParameterConstraints())));
}
}
}
@@ -1038,7 +995,7 @@ namespace Microsoft.CSharp.RuntimeBinder
}
agg.SetBaseClass((AggregateType)GetCTypeFromType(t));
}
- agg.SetTypeManager(_typeManager);
+
agg.SetFirstUDConversion(null);
SetInterfacesOnAggregate(agg, type);
agg.SetHasPubNoArgCtor(type.GetConstructor(Type.EmptyTypes) != null);
@@ -1055,7 +1012,7 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
- private void SetInterfacesOnAggregate(AggregateSymbol aggregate, Type type)
+ private static void SetInterfacesOnAggregate(AggregateSymbol aggregate, Type type)
{
if (type.IsGenericType)
{
@@ -1071,7 +1028,7 @@ namespace Microsoft.CSharp.RuntimeBinder
// we don't really care where they've come from as long as we know the overall
// set of IfacesAll.
- aggregate.SetIfaces(_bsymmgr.AllocParams(interfaces.Length, GetCTypeArrayFromTypes(interfaces)));
+ aggregate.SetIfaces(TypeArray.Allocate(GetCTypeArrayFromTypes(interfaces)));
aggregate.SetIfacesAll(aggregate.GetIfaces());
}
#endregion
@@ -1079,9 +1036,9 @@ namespace Microsoft.CSharp.RuntimeBinder
#region Field
/////////////////////////////////////////////////////////////////////////////////
- private FieldSymbol AddFieldToSymbolTable(FieldInfo fieldInfo, AggregateSymbol aggregate)
+ private static FieldSymbol AddFieldToSymbolTable(FieldInfo fieldInfo, AggregateSymbol aggregate)
{
- FieldSymbol field = _symbolTable.LookupSym(
+ FieldSymbol field = SymbolStore.LookupSym(
GetName(fieldInfo.Name),
aggregate,
symbmask_t.MASK_FieldSymbol) as FieldSymbol;
@@ -1090,7 +1047,7 @@ namespace Microsoft.CSharp.RuntimeBinder
return field;
}
- field = _symFactory.CreateMemberVar(GetName(fieldInfo.Name), aggregate);
+ field = SymFactory.CreateMemberVar(GetName(fieldInfo.Name), aggregate);
field.AssociatedFieldInfo = fieldInfo;
field.isStatic = fieldInfo.IsStatic;
@@ -1123,7 +1080,6 @@ namespace Microsoft.CSharp.RuntimeBinder
field.SetAccess(access);
field.isReadOnly = fieldInfo.IsInitOnly;
field.isEvent = false;
- field.isAssigned = true;
field.SetType(GetCTypeFromType(fieldInfo.FieldType));
return field;
@@ -1165,7 +1121,9 @@ namespace Microsoft.CSharp.RuntimeBinder
private static Type GetTypeByName(ref Type cachedResult, string name)
{
+#pragma warning disable 252
if ((object)cachedResult == s_Sentinel)
+#pragma warning restore 252
{
System.Threading.Interlocked.CompareExchange(ref cachedResult, Type.GetType(name, throwOnError: false), s_Sentinel);
}
@@ -1173,9 +1131,9 @@ namespace Microsoft.CSharp.RuntimeBinder
return cachedResult;
}
- private void AddEventToSymbolTable(EventInfo eventInfo, AggregateSymbol aggregate, FieldSymbol addedField)
+ private static void AddEventToSymbolTable(EventInfo eventInfo, AggregateSymbol aggregate, FieldSymbol addedField)
{
- EventSymbol ev = _symbolTable.LookupSym(
+ EventSymbol ev = SymbolStore.LookupSym(
GetName(eventInfo.Name),
aggregate,
symbmask_t.MASK_EventSymbol) as EventSymbol;
@@ -1185,7 +1143,7 @@ namespace Microsoft.CSharp.RuntimeBinder
return;
}
- ev = _symFactory.CreateEvent(GetName(eventInfo.Name), aggregate);
+ ev = SymFactory.CreateEvent(GetName(eventInfo.Name), aggregate);
ev.AssociatedEventInfo = eventInfo;
// EventSymbol
@@ -1250,7 +1208,7 @@ namespace Microsoft.CSharp.RuntimeBinder
#region Properties
/////////////////////////////////////////////////////////////////////////////////
- internal void AddPredefinedPropertyToSymbolTable(AggregateSymbol type, Name property)
+ internal static void AddPredefinedPropertyToSymbolTable(AggregateSymbol type, Name property)
{
AggregateType aggtype = type.getThisType();
Type t = aggtype.AssociatedSystemType;
@@ -1265,7 +1223,7 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
- private void AddPropertyToSymbolTable(PropertyInfo property, AggregateSymbol aggregate)
+ private static void AddPropertyToSymbolTable(PropertyInfo property, AggregateSymbol aggregate)
{
Name name;
bool isIndexer = property.GetIndexParameters().Length != 0
@@ -1280,7 +1238,7 @@ namespace Microsoft.CSharp.RuntimeBinder
{
name = GetName(property.Name);
}
- PropertySymbol prop = _symbolTable.LookupSym(
+ PropertySymbol prop = SymbolStore.LookupSym(
name,
aggregate,
symbmask_t.MASK_PropertySymbol) as PropertySymbol;
@@ -1301,7 +1259,7 @@ namespace Microsoft.CSharp.RuntimeBinder
}
prevProp = prop;
- prop = SymbolLoader.LookupNextSym(prop, prop.parent, symbmask_t.MASK_PropertySymbol) as PropertySymbol;
+ prop = prop.LookupNext(symbmask_t.MASK_PropertySymbol) as PropertySymbol;
}
prop = prevProp;
@@ -1330,13 +1288,13 @@ namespace Microsoft.CSharp.RuntimeBinder
{
if (isIndexer)
{
- prop = _semanticChecker.SymbolLoader.GetGlobalSymbolFactory().CreateIndexer(name, aggregate, GetName(property.Name));
+ prop = SymFactory.CreateIndexer(name, aggregate);
prop.Params = CreateParameterArray(null, property.GetIndexParameters());
}
else
{
- prop = _symFactory.CreateProperty(GetName(property.Name), aggregate);
- prop.Params = BSYMMGR.EmptyTypeArray();
+ prop = SymFactory.CreateProperty(GetName(property.Name), aggregate);
+ prop.Params = TypeArray.Empty;
}
}
prop.AssociatedPropertyInfo = property;
@@ -1414,7 +1372,7 @@ namespace Microsoft.CSharp.RuntimeBinder
#region Methods
/////////////////////////////////////////////////////////////////////////////////
- internal void AddPredefinedMethodToSymbolTable(AggregateSymbol type, Name methodName)
+ internal static void AddPredefinedMethodToSymbolTable(AggregateSymbol type, Name methodName)
{
Type t = type.getThisType().AssociatedSystemType;
@@ -1447,7 +1405,7 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
- private MethodSymbol AddMethodToSymbolTable(MethodBase member, AggregateSymbol callingAggregate, MethodKindEnum kind)
+ private static MethodSymbol AddMethodToSymbolTable(MethodBase member, AggregateSymbol callingAggregate, MethodKindEnum kind)
{
MethodInfo method = member as MethodInfo;
@@ -1478,7 +1436,7 @@ namespace Microsoft.CSharp.RuntimeBinder
ParameterInfo[] parameters = member.GetParameters();
// First create the method.
- methodSymbol = _symFactory.CreateMethod(GetName(member.Name), callingAggregate);
+ methodSymbol = SymFactory.CreateMethod(GetName(member.Name), callingAggregate);
methodSymbol.AssociatedMemberInfo = member;
methodSymbol.SetMethKind(kind);
if (kind == MethodKindEnum.ExplicitConv || kind == MethodKindEnum.ImplicitConv)
@@ -1529,11 +1487,11 @@ namespace Microsoft.CSharp.RuntimeBinder
}
else
{
- methodSymbol.typeVars = BSYMMGR.EmptyTypeArray();
+ methodSymbol.typeVars = TypeArray.Empty;
methodSymbol.isOverride = false;
methodSymbol.isOperator = false;
methodSymbol.swtSlot = null;
- methodSymbol.RetType = _typeManager.GetVoid();
+ methodSymbol.RetType = VoidType.Instance;
}
methodSymbol.modOptCount = GetCountOfModOpts(parameters);
@@ -1550,7 +1508,7 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
- private void SetParameterDataForMethProp(MethodOrPropertySymbol methProp, ParameterInfo[] parameters)
+ private static void SetParameterDataForMethProp(MethodOrPropertySymbol methProp, ParameterInfo[] parameters)
{
if (parameters.Length > 0)
{
@@ -1573,7 +1531,7 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
- private void SetParameterAttributes(MethodOrPropertySymbol methProp, ParameterInfo[] parameters, int i)
+ private static void SetParameterAttributes(MethodOrPropertySymbol methProp, ParameterInfo[] parameters, int i)
{
ParameterInfo parameter = parameters[i];
if ((parameter.Attributes & ParameterAttributes.Optional) != 0 && !parameter.ParameterType.IsByRef)
@@ -1598,7 +1556,7 @@ namespace Microsoft.CSharp.RuntimeBinder
{
// Get DateTimeConstant
ConstVal cv = ConstVal.Get(((DateTime)dateAttr.Value).Ticks);
- CType cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_DATETIME);
+ CType cvType = SymbolLoader.GetPredefindType(PredefinedType.PT_DATETIME);
methProp.SetDefaultParameterValue(i, cvType, cv);
}
else
@@ -1608,7 +1566,7 @@ namespace Microsoft.CSharp.RuntimeBinder
{
// Get DecimalConstant
ConstVal cv = ConstVal.Get(decAttr.Value);
- CType cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_DECIMAL);
+ CType cvType = SymbolLoader.GetPredefindType(PredefinedType.PT_DECIMAL);
methProp.SetDefaultParameterValue(i, cvType, cv);
}
else if ((parameter.Attributes & ParameterAttributes.HasDefault) != 0 && !parameter.ParameterType.IsByRef)
@@ -1617,7 +1575,7 @@ namespace Microsoft.CSharp.RuntimeBinder
// looking at isn't a by ref type or a type parameter.
ConstVal cv = default(ConstVal);
- CType cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_OBJECT);
+ CType cvType = SymbolLoader.GetPredefindType(PredefinedType.PT_OBJECT);
// We need to use RawDefaultValue, because DefaultValue is too clever.
#if UNSUPPORTEDAPI
@@ -1635,67 +1593,67 @@ namespace Microsoft.CSharp.RuntimeBinder
case TypeCode.Byte:
cv = ConstVal.Get((byte)defValue);
- cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_BYTE);
+ cvType = SymbolLoader.GetPredefindType(PredefinedType.PT_BYTE);
break;
case TypeCode.Int16:
cv = ConstVal.Get((short)defValue);
- cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_SHORT);
+ cvType = SymbolLoader.GetPredefindType(PredefinedType.PT_SHORT);
break;
case TypeCode.Int32:
cv = ConstVal.Get((int)defValue);
- cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_INT);
+ cvType = SymbolLoader.GetPredefindType(PredefinedType.PT_INT);
break;
case TypeCode.Int64:
cv = ConstVal.Get((long)defValue);
- cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_LONG);
+ cvType = SymbolLoader.GetPredefindType(PredefinedType.PT_LONG);
break;
case TypeCode.Single:
cv = ConstVal.Get((float)defValue);
- cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_FLOAT);
+ cvType = SymbolLoader.GetPredefindType(PredefinedType.PT_FLOAT);
break;
case TypeCode.Double:
cv = ConstVal.Get((double)defValue);
- cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_DOUBLE);
+ cvType = SymbolLoader.GetPredefindType(PredefinedType.PT_DOUBLE);
break;
case TypeCode.Char:
cv = ConstVal.Get((char)defValue);
- cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_CHAR);
+ cvType = SymbolLoader.GetPredefindType(PredefinedType.PT_CHAR);
break;
case TypeCode.Boolean:
cv = ConstVal.Get((bool)defValue);
- cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_BOOL);
+ cvType = SymbolLoader.GetPredefindType(PredefinedType.PT_BOOL);
break;
case TypeCode.SByte:
cv = ConstVal.Get((sbyte)defValue);
- cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_SBYTE);
+ cvType = SymbolLoader.GetPredefindType(PredefinedType.PT_SBYTE);
break;
case TypeCode.UInt16:
cv = ConstVal.Get((ushort)defValue);
- cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_USHORT);
+ cvType = SymbolLoader.GetPredefindType(PredefinedType.PT_USHORT);
break;
case TypeCode.UInt32:
cv = ConstVal.Get((uint)defValue);
- cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_UINT);
+ cvType = SymbolLoader.GetPredefindType(PredefinedType.PT_UINT);
break;
case TypeCode.UInt64:
cv = ConstVal.Get((ulong)defValue);
- cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_ULONG);
+ cvType = SymbolLoader.GetPredefindType(PredefinedType.PT_ULONG);
break;
case TypeCode.String:
cv = ConstVal.Get((string)defValue);
- cvType = _semanticChecker.SymbolLoader.GetPredefindType(PredefinedType.PT_STRING);
+ cvType = SymbolLoader.GetPredefindType(PredefinedType.PT_STRING);
break;
}
@@ -1710,23 +1668,25 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
- private MethodSymbol FindMatchingMethod(MemberInfo method, AggregateSymbol callingAggregate)
+ private static MethodSymbol FindMatchingMethod(MemberInfo method, AggregateSymbol callingAggregate)
{
- MethodSymbol meth = _bsymmgr.LookupAggMember(GetName(method.Name), callingAggregate, symbmask_t.MASK_MethodSymbol) as MethodSymbol;
+ MethodSymbol meth = SymbolStore.LookupSym(GetName(method.Name), callingAggregate, symbmask_t.MASK_MethodSymbol) as MethodSymbol;
while (meth != null)
{
if (meth.AssociatedMemberInfo.IsEquivalentTo(method))
{
return meth;
}
- meth = BSYMMGR.LookupNextSym(meth, callingAggregate, symbmask_t.MASK_MethodSymbol) as MethodSymbol;
+
+ meth = meth.LookupNext(symbmask_t.MASK_MethodSymbol) as MethodSymbol;
}
+
return null;
}
/////////////////////////////////////////////////////////////////////////////////
- private uint GetCountOfModOpts(ParameterInfo[] parameters)
+ private static uint GetCountOfModOpts(ParameterInfo[] parameters)
{
uint count = 0;
#if UNSUPPORTEDAPI
@@ -1743,26 +1703,27 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
- private TypeArray CreateParameterArray(MemberInfo associatedInfo, ParameterInfo[] parameters)
+ private static TypeArray CreateParameterArray(MemberInfo associatedInfo, ParameterInfo[] parameters)
{
- List<CType> types = new List<CType>();
+ bool isVarArg = associatedInfo is MethodBase mb && (mb.CallingConvention & CallingConventions.VarArgs) != 0;
+ CType[] types = new CType[isVarArg ? parameters.Length + 1 : parameters.Length];
- foreach (ParameterInfo p in parameters)
+ for (int i = 0; i < parameters.Length; i++)
{
- types.Add(GetTypeOfParameter(p, associatedInfo));
+ types[i] = GetTypeOfParameter(parameters[i], associatedInfo);
}
- if (associatedInfo is MethodBase mb && (mb.CallingConvention & CallingConventions.VarArgs) != 0)
+ if (isVarArg)
{
- types.Add(_typeManager.GetArgListType());
+ types[types.Length - 1] = ArgumentListType.Instance;
}
- return _bsymmgr.AllocParams(types.Count, types.ToArray());
+ return TypeArray.Allocate(types);
}
/////////////////////////////////////////////////////////////////////////////////
- private CType GetTypeOfParameter(ParameterInfo p, MemberInfo m)
+ private static CType GetTypeOfParameter(ParameterInfo p, MemberInfo m)
{
Type t = p.ParameterType;
CType ctype;
@@ -1779,8 +1740,8 @@ namespace Microsoft.CSharp.RuntimeBinder
// Check if we have an out parameter.
if (ctype is ParameterModifierType mod && p.IsOut && !p.IsIn)
{
- CType parameterType = mod.GetParameterType();
- ctype = _typeManager.GetParameterModifier(parameterType, true);
+ CType parameterType = mod.ParameterType;
+ ctype = TypeManager.GetParameterModifier(parameterType, true);
}
return ctype;
@@ -1788,7 +1749,7 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
- private bool DoesMethodHaveParameterArray(ParameterInfo[] parameters)
+ private static bool DoesMethodHaveParameterArray(ParameterInfo[] parameters)
{
if (parameters.Length == 0)
{
@@ -1810,7 +1771,7 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
- private SymWithType GetSlotForOverride(MethodInfo method)
+ private static SymWithType GetSlotForOverride(MethodInfo method)
{
if (method.IsVirtual && method.IsHideBySig)
{
@@ -1826,7 +1787,7 @@ namespace Microsoft.CSharp.RuntimeBinder
// the methods in order. As such, our parent methods should be in the
// symbol table at this point.
- AggregateSymbol aggregate = GetCTypeFromType(baseMethodInfo.DeclaringType).getAggregate();
+ AggregateSymbol aggregate = ((AggregateType)GetCTypeFromType(baseMethodInfo.DeclaringType)).OwningAggregate;
MethodSymbol baseMethod = FindMethodFromMemberInfo(baseMethodInfo);
Debug.Assert(baseMethod != null);
return new SymWithType(baseMethod, aggregate.getThisType());
@@ -1837,20 +1798,20 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
- private MethodSymbol FindMethodFromMemberInfo(MemberInfo baseMemberInfo)
+ private static MethodSymbol FindMethodFromMemberInfo(MemberInfo baseMemberInfo)
{
CType t = GetCTypeFromType(baseMemberInfo.DeclaringType);
Debug.Assert(t is AggregateType);
- AggregateSymbol aggregate = t.getAggregate();
+ AggregateSymbol aggregate = ((AggregateType)t).OwningAggregate;
Debug.Assert(aggregate != null);
- MethodSymbol meth = _semanticChecker.SymbolLoader.LookupAggMember(
+ MethodSymbol meth = SymbolLoader.LookupAggMember(
GetName(baseMemberInfo.Name),
aggregate,
symbmask_t.MASK_MethodSymbol) as MethodSymbol;
for (;
meth != null && !meth.AssociatedMemberInfo.IsEquivalentTo(baseMemberInfo);
- meth = SymbolLoader.LookupNextSym(meth, aggregate, symbmask_t.MASK_MethodSymbol) as MethodSymbol)
+ meth = meth.LookupNext(symbmask_t.MASK_MethodSymbol) as MethodSymbol)
;
return meth;
@@ -1858,16 +1819,15 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
- internal bool AggregateContainsMethod(AggregateSymbol agg, string szName, symbmask_t mask)
- {
- return _semanticChecker.SymbolLoader.LookupAggMember(GetName(szName), agg, mask) != null;
- }
+ internal static bool AggregateContainsMethod(AggregateSymbol agg, string szName, symbmask_t mask) =>
+ SymbolLoader.LookupAggMember(GetName(szName), agg, mask) != null;
+
#endregion
#region Conversions
/////////////////////////////////////////////////////////////////////////////////
- internal void AddConversionsForType(Type type)
+ internal static void AddConversionsForType(Type type)
{
if (type.IsInterface)
{
@@ -1881,14 +1841,14 @@ namespace Microsoft.CSharp.RuntimeBinder
/////////////////////////////////////////////////////////////////////////////////
- private void AddConversionsForOneType(Type type)
+ private static void AddConversionsForOneType(Type type)
{
if (type.IsGenericType)
{
type = type.GetGenericTypeDefinition();
}
- if (!_typesWithConversionsLoaded.Add(type))
+ if (!s_typesWithConversionsLoaded.Add(type))
{
return;
}
@@ -1900,7 +1860,7 @@ namespace Microsoft.CSharp.RuntimeBinder
if (!(t is AggregateType))
{
CType endT;
- while ((endT = t.GetBaseOrParameterOrElementType()) != null)
+ while ((endT = t.BaseOrParameterOrElementType) != null)
{
t = endT;
}
@@ -1909,7 +1869,7 @@ namespace Microsoft.CSharp.RuntimeBinder
if (t is TypeParameterType paramType)
{
// Add conversions for the bounds.
- foreach (CType bound in paramType.GetBounds().Items)
+ foreach (CType bound in paramType.Bounds.Items)
{
AddConversionsForType(bound.AssociatedSystemType);
}
@@ -1917,7 +1877,7 @@ namespace Microsoft.CSharp.RuntimeBinder
}
Debug.Assert(t is AggregateType);
- AggregateSymbol aggregate = ((AggregateType)t).getAggregate();
+ AggregateSymbol aggregate = ((AggregateType)t).OwningAggregate;
// Now find all the conversions and make them.
foreach (MethodInfo conversion in type.GetRuntimeMethods())
@@ -1977,8 +1937,8 @@ namespace Microsoft.CSharp.RuntimeBinder
case SpecialNames.CLR_OnesComplement:
case SpecialNames.CLR_True:
case SpecialNames.CLR_False:
- case SpecialNames.CLR_PreIncrement:
- case SpecialNames.CLR_PreDecrement:
+ case SpecialNames.CLR_Increment:
+ case SpecialNames.CLR_Decrement:
return true;
}
}
diff --git a/src/Microsoft.CSharp/src/Resources/Strings.de.resx b/src/Microsoft.CSharp/src/Resources/Strings.de.resx
index 0b9a2ff9f1..38d09851f4 100644
--- a/src/Microsoft.CSharp/src/Resources/Strings.de.resx
+++ b/src/Microsoft.CSharp/src/Resources/Strings.de.resx
@@ -81,9 +81,6 @@
<data name="ValueCantBeNull" xml:space="preserve">
<value>NULL kann nicht in {0} konvertiert werden, da dieser Werttyp nicht auf NULL festgelegt werden kann.</value>
</data>
- <data name="WrongNestedThis" xml:space="preserve">
- <value>Auf einen nicht statischen Member des äußeren {0}-Typs kann nicht über den geschachtelten {1}-Typ zugegriffen werden.</value>
- </data>
<data name="NoSuchMember" xml:space="preserve">
<value>{0} enthält keine Definition für {1}.</value>
</data>
diff --git a/src/Microsoft.CSharp/src/Resources/Strings.es.resx b/src/Microsoft.CSharp/src/Resources/Strings.es.resx
index b50227d36d..2ecf6454cb 100644
--- a/src/Microsoft.CSharp/src/Resources/Strings.es.resx
+++ b/src/Microsoft.CSharp/src/Resources/Strings.es.resx
@@ -81,9 +81,6 @@
<data name="ValueCantBeNull" xml:space="preserve">
<value>No se puede convertir NULL en '{0}' porque es un tipo de valor que no acepta valores NULL.</value>
</data>
- <data name="WrongNestedThis" xml:space="preserve">
- <value>No se puede obtener acceso a un miembro no estático de tipo externo '{0}' mediante el tipo anidado '{1}'.</value>
- </data>
<data name="NoSuchMember" xml:space="preserve">
<value>'{0}' no contiene una definición para '{1}'.</value>
</data>
diff --git a/src/Microsoft.CSharp/src/Resources/Strings.fr.resx b/src/Microsoft.CSharp/src/Resources/Strings.fr.resx
index e31fb94aab..4879b314dc 100644
--- a/src/Microsoft.CSharp/src/Resources/Strings.fr.resx
+++ b/src/Microsoft.CSharp/src/Resources/Strings.fr.resx
@@ -81,9 +81,6 @@
<data name="ValueCantBeNull" xml:space="preserve">
<value>Impossible de convertir null en '{0}', car il s'agit d'un type valeur qui n'autorise pas les valeurs null</value>
</data>
- <data name="WrongNestedThis" xml:space="preserve">
- <value>Impossible d'accéder à un membre non statique de type externe '{0}' par l'intermédiaire du type imbriqué '{1}'</value>
- </data>
<data name="NoSuchMember" xml:space="preserve">
<value>'{0}' ne contient pas de définition pour '{1}'</value>
</data>
diff --git a/src/Microsoft.CSharp/src/Resources/Strings.it.resx b/src/Microsoft.CSharp/src/Resources/Strings.it.resx
index 7ca475533f..4c215fcd65 100644
--- a/src/Microsoft.CSharp/src/Resources/Strings.it.resx
+++ b/src/Microsoft.CSharp/src/Resources/Strings.it.resx
@@ -81,9 +81,6 @@
<data name="ValueCantBeNull" xml:space="preserve">
<value>Impossibile convertire Null in '{0}' perché è un tipo di valore non nullable</value>
</data>
- <data name="WrongNestedThis" xml:space="preserve">
- <value>Impossibile accedere a un membro non statico di tipo outer '{0}' tramite il tipo annidato '{1}'</value>
- </data>
<data name="NoSuchMember" xml:space="preserve">
<value>'{0}' non contiene una definizione per '{1}'</value>
</data>
diff --git a/src/Microsoft.CSharp/src/Resources/Strings.ja.resx b/src/Microsoft.CSharp/src/Resources/Strings.ja.resx
index 861002fe0a..3807dae995 100644
--- a/src/Microsoft.CSharp/src/Resources/Strings.ja.resx
+++ b/src/Microsoft.CSharp/src/Resources/Strings.ja.resx
@@ -81,9 +81,6 @@
<data name="ValueCantBeNull" xml:space="preserve">
<value>Null 非許容の値型であるため、Null を '{0}' に変換できません</value>
</data>
- <data name="WrongNestedThis" xml:space="preserve">
- <value>入れ子にされた型 '{1}' を経由して、外の型 '{0}' の静的でないメンバーにアクセスすることはできません</value>
- </data>
<data name="NoSuchMember" xml:space="preserve">
<value>'{0}' に '{1}' の定義がありません</value>
</data>
diff --git a/src/Microsoft.CSharp/src/Resources/Strings.ko.resx b/src/Microsoft.CSharp/src/Resources/Strings.ko.resx
index a2a6b1bf15..609342acc1 100644
--- a/src/Microsoft.CSharp/src/Resources/Strings.ko.resx
+++ b/src/Microsoft.CSharp/src/Resources/Strings.ko.resx
@@ -81,9 +81,6 @@
<data name="ValueCantBeNull" xml:space="preserve">
<value>'{0}'은(는) null을 허용하지 않는 값 형식이므로 null을 이 형식으로 변환할 수 없습니다.</value>
</data>
- <data name="WrongNestedThis" xml:space="preserve">
- <value>중첩 형식 '{1}'을(를) 통해 외부 형식 '{0}'의 static이 아닌 멤버에 액세스할 수 없습니다.</value>
- </data>
<data name="NoSuchMember" xml:space="preserve">
<value>'{0}'에 '{1}'에 대한 정의가 없습니다.</value>
</data>
diff --git a/src/Microsoft.CSharp/src/Resources/Strings.resx b/src/Microsoft.CSharp/src/Resources/Strings.resx
index 462e5c137e..35d607622e 100644
--- a/src/Microsoft.CSharp/src/Resources/Strings.resx
+++ b/src/Microsoft.CSharp/src/Resources/Strings.resx
@@ -109,9 +109,6 @@
<data name="ValueCantBeNull" xml:space="preserve">
<value>Cannot convert null to '{0}' because it is a non-nullable value type</value>
</data>
- <data name="WrongNestedThis" xml:space="preserve">
- <value>Cannot access a non-static member of outer type '{0}' via nested type '{1}'</value>
- </data>
<data name="NoSuchMember" xml:space="preserve">
<value>'{0}' does not contain a definition for '{1}'</value>
</data>
@@ -238,15 +235,6 @@
<data name="BadDelArgTypes" xml:space="preserve">
<value>Delegate '{0}' has some invalid arguments</value>
</data>
- <data name="ReturnNotLValue" xml:space="preserve">
- <value>Cannot modify the return value of '{0}' because it is not a variable</value>
- </data>
- <data name="AssgReadonly2" xml:space="preserve">
- <value>Members of readonly field '{0}' cannot be modified (except in a constructor or a variable initializer)</value>
- </data>
- <data name="AssgReadonlyStatic2" xml:space="preserve">
- <value>Fields of static readonly field '{0}' cannot be assigned to (except in a static constructor or a variable initializer)</value>
- </data>
<data name="BadCtorArgCount" xml:space="preserve">
<value>'{0}' does not contain a constructor that takes '{1}' arguments</value>
</data>
@@ -271,9 +259,6 @@
<data name="DynamicArgumentNeedsValue" xml:space="preserve">
<value>The runtime binder cannot bind a metaobject without a value</value>
</data>
- <data name="BindingNameCollision" xml:space="preserve">
- <value>More than one type in the binding has the same full name.</value>
- </data>
<data name="BadNonTrailingNamedArgument" xml:space="preserve">
<value>Named argument '{0}' is used out-of-position but is followed by an unnamed argument</value>
</data>
diff --git a/src/Microsoft.CSharp/src/Resources/Strings.ru.resx b/src/Microsoft.CSharp/src/Resources/Strings.ru.resx
index 9c982cc8df..78b66c55fb 100644
--- a/src/Microsoft.CSharp/src/Resources/Strings.ru.resx
+++ b/src/Microsoft.CSharp/src/Resources/Strings.ru.resx
@@ -81,9 +81,6 @@
<data name="ValueCantBeNull" xml:space="preserve">
<value>Cannot convert null to "{0}" because it is a non-nullable value type</value>
</data>
- <data name="WrongNestedThis" xml:space="preserve">
- <value>Невозможно получить доступ к нестатическому члену внешнего типа "{0}" через вложенный тип "{1}"</value>
- </data>
<data name="NoSuchMember" xml:space="preserve">
<value>"{0}" не содержит определения для "{1}"</value>
</data>
diff --git a/src/Microsoft.CSharp/src/Resources/Strings.zh-Hans.resx b/src/Microsoft.CSharp/src/Resources/Strings.zh-Hans.resx
index c4f57cf06a..65ecb7fc02 100644
--- a/src/Microsoft.CSharp/src/Resources/Strings.zh-Hans.resx
+++ b/src/Microsoft.CSharp/src/Resources/Strings.zh-Hans.resx
@@ -81,9 +81,6 @@
<data name="ValueCantBeNull" xml:space="preserve">
<value>无法将 null 转换为“{0}”,因为后者是不可以为 null 的值类型</value>
</data>
- <data name="WrongNestedThis" xml:space="preserve">
- <value>无法通过嵌套类型“{1}”来访问外部类型“{0}”的非静态成员</value>
- </data>
<data name="NoSuchMember" xml:space="preserve">
<value>“{0}”未包含“{1}”的定义</value>
</data>
diff --git a/src/Microsoft.CSharp/src/Resources/Strings.zh-Hant.resx b/src/Microsoft.CSharp/src/Resources/Strings.zh-Hant.resx
index 55ec74b0d6..0517ad500e 100644
--- a/src/Microsoft.CSharp/src/Resources/Strings.zh-Hant.resx
+++ b/src/Microsoft.CSharp/src/Resources/Strings.zh-Hant.resx
@@ -81,9 +81,6 @@
<data name="ValueCantBeNull" xml:space="preserve">
<value>無法將 null 轉換成 '{0}',因為它是不可為 null 的實值型別</value>
</data>
- <data name="WrongNestedThis" xml:space="preserve">
- <value>無法透過巢狀型別 '{1}' 存取外部型別 '{0}' 的非靜態成員</value>
- </data>
<data name="NoSuchMember" xml:space="preserve">
<value>'{0}' 不包含 '{1}' 的定義</value>
</data>
diff --git a/src/Microsoft.CSharp/tests/AccessTests.cs b/src/Microsoft.CSharp/tests/AccessTests.cs
new file mode 100644
index 0000000000..4fa3516cd7
--- /dev/null
+++ b/src/Microsoft.CSharp/tests/AccessTests.cs
@@ -0,0 +1,294 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using Xunit;
+
+namespace Microsoft.CSharp.RuntimeBinder.Tests
+{
+ public partial class AccessTests
+ {
+ public abstract class PublicReferenceType
+ {
+ public abstract int IntValueProperty { get; }
+ }
+
+ public interface ITestIFace
+ {
+ }
+
+ public interface ITestIFaceCons<out T> where T : ITestIFace
+ {
+ }
+
+ private class Container
+ {
+ private abstract class ReferenceTypeIntermediary : PublicReferenceType
+ {
+ }
+
+ private class ReferenceType : ReferenceTypeIntermediary, ITestIFace
+ {
+ public override int IntValueProperty => 23;
+ }
+
+ private struct PrivateValueType
+ {
+ }
+
+ private protected struct PrivateProtectedValueType
+ {
+ }
+
+ internal struct InternalValueType
+ {
+ }
+
+ protected internal struct ProtectedInternalValueType
+ {
+ }
+
+ private interface IPrivateInterface
+ {
+ }
+
+ public static dynamic GetReferenceType() => new ReferenceType();
+
+ public static dynamic TenReferenceTypesArray() => new ReferenceType[10];
+
+ public static dynamic TenReferenceTypesRepeat() => Enumerable.Repeat(new ReferenceType(), 10);
+
+ public static dynamic ReferenceTypeDelegate() =>
+ (Func<int, IEnumerable<ReferenceType>>)(i => Enumerable.Repeat(new ReferenceType(), i));
+
+ public static dynamic ValueTypeArray() => new PrivateValueType[2];
+
+ public static dynamic PrivateProtectedValueTypeArray() => new PrivateProtectedValueType[2];
+
+ public static dynamic InternalValueTypeArray() => new InternalValueType[2];
+
+ public static dynamic ProtectedInternalValueTypeArray() => new ProtectedInternalValueType[2];
+
+ private delegate int PrivateFunc<T>(T arg);
+
+ public static dynamic PrivateDelegateType() => (PrivateFunc<ReferenceType>)(r => r.IntValueProperty);
+
+ public static dynamic ValueTypeDelegate() => (Func<PrivateValueType>)(() => new PrivateValueType());
+
+ public unsafe static dynamic PointerArray() => new PrivateValueType*[4];
+
+ public static dynamic PrivateInterfaceDelegate() => (Func<IPrivateInterface>)(() => null);
+
+ public static dynamic PrivateConstraintInterfaceDelegate() => (Func<ITestIFaceCons<ReferenceType>>)(() => null);
+
+ public static dynamic PrivateProtectedInstance() => PrivateProtectedValueTypeArray()[1];
+ }
+
+ private class TypeWithFields
+ {
+ public int Public;
+ protected int Protected;
+ internal int Internal;
+ protected internal int ProtectedInternal;
+ private protected int PrivateProtected;
+#pragma warning disable 414
+ private int Private;
+#pragma warning restore 414
+
+ public TypeWithFields()
+ {
+ Public = 1;
+ Protected = 2;
+ Internal = 3;
+ ProtectedInternal = 4;
+ PrivateProtected = 5;
+ Private = 6;
+ }
+ }
+
+ private class TypeWithFieldsDerived : TypeWithFields
+ {
+ public void AccessibleFields()
+ {
+ dynamic d = this;
+ Assert.Equal(1, d.Public);
+ Assert.Equal(2, d.Protected);
+ Assert.Equal(3, d.Internal);
+ Assert.Equal(4, d.ProtectedInternal);
+ Assert.Equal(5, d.PrivateProtected);
+ }
+
+ public void InAccessibleFields()
+ {
+ dynamic d = this;
+ Assert.Throws<RuntimeBinderException>(() => d.Private);
+ }
+ }
+
+ [Fact]
+ public void CanGetAccessibleBaseOfInaccessibleType() => Assert.Equal(23, Container.GetReferenceType().IntValueProperty);
+
+ [Fact]
+ public void AccessibleArray() => Assert.Equal(10, Enumerable.Count(Container.TenReferenceTypesArray()));
+
+ [Fact]
+ public void AccessibleInterface() => Assert.Equal(10, Enumerable.Count(Container.TenReferenceTypesRepeat()));
+
+ [Fact]
+ public void AccessCovariantDelegate()
+ {
+ IEnumerable<PublicReferenceType> prts = Container.ReferenceTypeDelegate()(4);
+ Assert.Equal(4, prts.Count());
+ foreach (PublicReferenceType prt in prts)
+ {
+ Assert.Equal(23, prt.IntValueProperty);
+ }
+ }
+
+ [Fact]
+ public void NonCovariantArrayToArrayType() => Assert.Equal(2, Container.ValueTypeArray().Length);
+
+ [Fact]
+ public void NonCovariantArrayNotCastToIndexableType()
+ {
+ dynamic array = Container.ValueTypeArray();
+ Assert.Throws<RuntimeBinderException>(() => array[0]);
+ }
+
+ [Fact]
+ public void PointerArrayToArrayType() => Assert.Equal(4, Container.PointerArray().Length);
+
+ [Fact]
+ public void PointerArrayNotCastToIndexableType()
+ {
+ dynamic array = Container.PointerArray();
+ Assert.Throws<RuntimeBinderException>(() => array[0]);
+ }
+
+ [Fact]
+ public void PrivateDelegateType()
+ {
+ dynamic d = Container.PrivateDelegateType();
+ dynamic a = Container.GetReferenceType();
+ Assert.Throws<RuntimeBinderException>(() => d(a));
+ d.DynamicInvoke(a); // Can use as MulticastDelegate.
+ }
+
+ [Fact]
+ public void PrivateValueTypeDelegateType()
+ {
+ dynamic d = Container.ValueTypeDelegate();
+ Assert.Throws<RuntimeBinderException>(() => d());
+ ValueType result = d.DynamicInvoke(); // Can use as MulticastDelegate.
+ }
+
+ [Fact]
+ public void PrivateIFaceDelegateType()
+ {
+ dynamic d = Container.PrivateInterfaceDelegate();
+ Assert.Null(d());
+ }
+
+ [Fact]
+ public void PrivateInterfaceConstraint()
+ {
+ // Casting Func<ITestIFaceCons<ReferenceType>> to Func<ITestIFaceCons<PublicReferenceType>>
+ // would be illegal because ITestIFaceCons<PublicReferenceType> violates the ITestIFaceCons
+ // constraints, so the binder has to detect that, and cast to Func<object>.
+ dynamic d = Container.PrivateConstraintInterfaceDelegate();
+ Assert.Null(d());
+ }
+
+ private struct SomeValueType
+ {
+ public override string ToString() => "test";
+ }
+
+ [Fact]
+ public void NullableOfInaccessible()
+ {
+ // ValueType members work without access to the type.
+ CallSite<Func<CallSite, SomeValueType?, object>> site =
+ CallSite<Func<CallSite, SomeValueType?, object>>.Create(
+ Binder.InvokeMember(
+ CSharpBinderFlags.None, "ToString", null, null,
+ new[]
+ {
+ CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
+ }));
+ Func<CallSite, SomeValueType?, object> target = site.Target;
+ Assert.Equal("test", target(site, new SomeValueType()));
+
+ // Nullable<T> members work with access to the type.
+ site = CallSite<Func<CallSite, SomeValueType?, object>>.Create(
+ Binder.InvokeMember(
+ CSharpBinderFlags.None, "GetValueOrDefault", null, GetType(),
+ new[]
+ {
+ CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
+ }));
+ target = site.Target;
+ Assert.Equal(new SomeValueType(), target(site, new SomeValueType()));
+
+ // Nullable<T> members don't work without access to the type.
+ site = CallSite<Func<CallSite, SomeValueType?, object>>.Create(
+ Binder.InvokeMember(
+ CSharpBinderFlags.None, "GetValueOrDefault", null, null,
+ new[]
+ {
+ CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
+ }));
+ target = site.Target;
+ Assert.Throws<RuntimeBinderException>(() => target(site, new SomeValueType()));
+ }
+
+ [Fact]
+ public void AccessNestedInternalOnlySameAssembly()
+ {
+ Assert.NotNull(Container.InternalValueTypeArray()[1]);
+ Assert.NotNull(Container.ProtectedInternalValueTypeArray()[1]);
+ }
+
+ [Fact]
+ public void AccessNestedPrivateProtectedAssembly()
+ {
+ dynamic d = Container.PrivateProtectedValueTypeArray();
+ Assert.Throws<RuntimeBinderException>(() => d[1]);
+ Assert.NotNull(Container.PrivateProtectedInstance());
+ }
+
+ [Fact]
+ public void AccessibleFields()
+ {
+ dynamic d = new TypeWithFields();
+ Assert.Equal(1, d.Public);
+ Assert.Equal(3, d.Internal);
+ Assert.Equal(4, d.ProtectedInternal);
+ }
+
+ [Fact]
+ public void InaccessibleFields()
+ {
+ dynamic d = new TypeWithFields();
+ Assert.Throws<RuntimeBinderException>(() => d.Protected);
+ Assert.Throws<RuntimeBinderException>(() => d.PrivateProtected);
+ Assert.Throws<RuntimeBinderException>(() => d.Private);
+ }
+
+ [Fact]
+ public void AccessibleToDerivedFields()
+ {
+ new TypeWithFieldsDerived().AccessibleFields();
+ }
+
+ [Fact]
+ public void InaccessibleToDerivedFields()
+ {
+ new TypeWithFieldsDerived().AccessibleFields();
+ }
+ }
+}
diff --git a/src/Microsoft.CSharp/tests/AccessTests.netcoreapp.cs b/src/Microsoft.CSharp/tests/AccessTests.netcoreapp.cs
index a7cfdf6ec6..9e62a92c45 100644
--- a/src/Microsoft.CSharp/tests/AccessTests.netcoreapp.cs
+++ b/src/Microsoft.CSharp/tests/AccessTests.netcoreapp.cs
@@ -10,7 +10,7 @@ using Xunit;
namespace Microsoft.CSharp.RuntimeBinder.Tests
{
- public class AccessTests
+ public partial class AccessTests
{
private readonly Type _baseType;
private readonly Type _siblingType;
diff --git a/src/Microsoft.CSharp/tests/BindingErrors.cs b/src/Microsoft.CSharp/tests/BindingErrors.cs
index 2a0a3abae0..34e7e73b2d 100644
--- a/src/Microsoft.CSharp/tests/BindingErrors.cs
+++ b/src/Microsoft.CSharp/tests/BindingErrors.cs
@@ -8,9 +8,11 @@ using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
+using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
+using System.Threading;
using Xunit;
namespace Microsoft.CSharp.RuntimeBinder.Tests
@@ -425,5 +427,136 @@ namespace Microsoft.CSharp.RuntimeBinder.Tests
dynamic d = new object();
Assert.Throws<RuntimeBinderException>(() => DoStuff(d));
}
+
+ public class Outer
+ {
+ public class Inner
+ {
+ public void DoNothing()
+ {
+ }
+ }
+ }
+
+ [Fact]
+ public void TryInvokeOrAccessNestedClassAsMember()
+ {
+ dynamic dFirst = new Outer.Inner();
+ dFirst.DoNothing();
+ dynamic d = new Outer();
+ Assert.Throws<RuntimeBinderException>(() => d.Inner<int>());
+ Assert.Throws<RuntimeBinderException>(() => d.Inner());
+ Assert.Throws<RuntimeBinderException>(() => d.Inner = 2);
+ Assert.Throws<RuntimeBinderException>(
+ () =>
+ {
+ int i = d.Inner<int>();
+ });
+ }
+
+ [Fact]
+ public void TryInvokeTypeParameterAsMember()
+ {
+ dynamic d = new List<int>();
+ Assert.Throws<RuntimeBinderException>(() => d.T);
+ Assert.Throws<RuntimeBinderException>(() => d.T());
+ Assert.Throws<RuntimeBinderException>(() => d.T<int>());
+ Assert.Throws<RuntimeBinderException>(() =>
+ {
+ int i = d.T;
+ });
+ }
+
+ public class BaseForOuterWithMethod
+ {
+ public int Inner() => 42;
+ }
+
+ public class DerivedOuterHidingMethod : BaseForOuterWithMethod
+ {
+ public new class Inner
+ {
+ public void DoNothing()
+ {
+ }
+ }
+ }
+
+ [Fact]
+ public void AccessMethodHiddenByNested()
+ {
+ dynamic dFirst = new DerivedOuterHidingMethod.Inner();
+ dFirst.DoNothing();
+ dynamic d = new DerivedOuterHidingMethod();
+ Assert.Equal(42, d.Inner());
+ }
+
+ public class BaseForOuterWithNested
+ {
+ public class Inner
+ {
+ public void DoNothing()
+ {
+ }
+ }
+ }
+
+ public class DerivedOuterHidingNested : BaseForOuterWithNested
+ {
+ public new int Inner() => 42;
+ }
+
+ [Fact]
+ public void AccessMethodHidingNested()
+ {
+ dynamic dFirst = new BaseForOuterWithNested.Inner();
+ dFirst.DoNothing();
+ dynamic d = new DerivedOuterHidingNested();
+ Assert.Equal(42, d.Inner());
+ }
+
+ [Fact]
+ public void CannotCallOperatorDirectly()
+ {
+ CultureInfo prev = CultureInfo.CurrentCulture;
+ Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
+ dynamic d = "";
+ RuntimeBinderException e = Assert.Throws<RuntimeBinderException>(() => d.op_Equality("", ""));
+ Assert.Equal("'string.operator ==(string, string)': cannot explicitly call operator or accessor", e.Message);
+ Thread.CurrentThread.CurrentCulture = prev;
+ }
+
+ [Fact]
+ public void CannotCallAccessorDirectly()
+ {
+ CultureInfo prev = CultureInfo.CurrentCulture;
+ Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
+ dynamic d = "";
+ RuntimeBinderException e = Assert.Throws<RuntimeBinderException>(() => d.get_Length());
+ Assert.Equal("'string.Length.get': cannot explicitly call operator or accessor", e.Message);
+ Thread.CurrentThread.CurrentCulture = prev;
+ }
+
+ [Fact]
+ public void AllowIndexerAccess()
+ {
+ // Indexers' accessors can be accessed directly. This is against the C# rules, which only allow
+ // direct access of indexer accessors when they are not the default member as C# has no other
+ // way to express such access, but being stricter would be a breaking change.
+ List<int> list = new List<int> { 1, 2, 3 };
+ dynamic d = list;
+ d.set_Item(2, 4);
+ dynamic e = d.get_Item(2);
+ Assert.Equal(4, e);
+ Assert.Equal(4, list[2]);
+ }
+
+ [Fact]
+ public void AllowStringIndexerAccess()
+ {
+ dynamic d = "abcd";
+ char c = d.get_Chars(2);
+ Assert.Equal('c', c);
+ }
}
}
diff --git a/src/Microsoft.CSharp/tests/Microsoft.CSharp.Tests.csproj b/src/Microsoft.CSharp/tests/Microsoft.CSharp.Tests.csproj
index db08891f7e..320b4ef75c 100644
--- a/src/Microsoft.CSharp/tests/Microsoft.CSharp.Tests.csproj
+++ b/src/Microsoft.CSharp/tests/Microsoft.CSharp.Tests.csproj
@@ -3,12 +3,14 @@
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
<ProjectGuid>{82B54697-0251-47A1-8546-FC507D0F3B08}</ProjectGuid>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
<ItemGroup>
+ <Compile Include="AccessTests.cs" />
<Compile Include="ArrayHandling.cs" />
<Compile Include="AssignmentTests.cs" />
<Compile Include="BindingErrors.cs" />
diff --git a/src/Microsoft.Diagnostics.Tracing.EventSource.Redist/dir.props b/src/Microsoft.Diagnostics.Tracing.EventSource.Redist/dir.props
index 727f85c06a..a3c4bdc3d8 100644
--- a/src/Microsoft.Diagnostics.Tracing.EventSource.Redist/dir.props
+++ b/src/Microsoft.Diagnostics.Tracing.EventSource.Redist/dir.props
@@ -2,8 +2,8 @@
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\dir.props" />
<PropertyGroup>
- <PackageVersion>2.0.0</PackageVersion>
- <AssemblyVersion>2.0.0.0</AssemblyVersion>
+ <PackageVersion>2.0.1</PackageVersion>
+ <AssemblyVersion>2.0.1.0</AssemblyVersion>
<AssemblyKey>Open</AssemblyKey>
</PropertyGroup>
</Project> \ No newline at end of file
diff --git a/src/Microsoft.Diagnostics.Tracing.EventSource.Redist/pkg/Microsoft.Diagnostics.Tracing.EventSource.Redist.pkgproj b/src/Microsoft.Diagnostics.Tracing.EventSource.Redist/pkg/Microsoft.Diagnostics.Tracing.EventSource.Redist.pkgproj
index 7c96c63275..3379276bae 100644
--- a/src/Microsoft.Diagnostics.Tracing.EventSource.Redist/pkg/Microsoft.Diagnostics.Tracing.EventSource.Redist.pkgproj
+++ b/src/Microsoft.Diagnostics.Tracing.EventSource.Redist/pkg/Microsoft.Diagnostics.Tracing.EventSource.Redist.pkgproj
@@ -9,6 +9,7 @@
</ItemGroup>
<PropertyGroup>
+ <HarvestStablePackage>false</HarvestStablePackage>
<SkipPackageFileCheck>true</SkipPackageFileCheck>
</PropertyGroup>
diff --git a/src/Microsoft.VisualBasic/pkg/Microsoft.VisualBasic.pkgproj b/src/Microsoft.VisualBasic/pkg/Microsoft.VisualBasic.pkgproj
index cdca494df9..5a8b968b56 100644
--- a/src/Microsoft.VisualBasic/pkg/Microsoft.VisualBasic.pkgproj
+++ b/src/Microsoft.VisualBasic/pkg/Microsoft.VisualBasic.pkgproj
@@ -13,7 +13,7 @@
<HarvestIncludePaths Include="ref/netstandard1.1" />
<HarvestIncludePaths Include="lib/netstandard1.3" />
<InboxOnTargetFramework Include="netcoreapp2.0" />
- <InboxOnTargetFramework Include="$(UAPvNextTFM)" />
+ <InboxOnTargetFramework Include="uap10.0.16299" />
<InboxOnTargetFramework Include="win8" />
<InboxOnTargetFramework Include="wpa81" />
<InboxOnTargetFramework Include="portable-net45+win8+wpa81" />
diff --git a/src/Microsoft.VisualBasic/src/MatchingRefApiCompatBaseline.netstandard.txt b/src/Microsoft.VisualBasic/src/MatchingRefApiCompatBaseline.netstandard.txt
new file mode 100644
index 0000000000..11a2bf0209
--- /dev/null
+++ b/src/Microsoft.VisualBasic/src/MatchingRefApiCompatBaseline.netstandard.txt
@@ -0,0 +1,41 @@
+Compat issues with assembly Microsoft.VisualBasic:
+TypesMustExist : Type 'Microsoft.VisualBasic.ControlChars' does not exist in the implementation but it does exist in the contract.
+CannotSealType : Type 'Microsoft.VisualBasic.HideModuleNameAttribute' is sealed in the implementation but not sealed in the contract.
+TypesMustExist : Type 'Microsoft.VisualBasic.Interaction' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'Microsoft.VisualBasic.Strings.Left(System.String, System.Int32)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.Conversions.FallbackUserDefinedConversion(System.Object, System.Type)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.Conversions.GetCultureInfo()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.Conversions.IsHexOrOctValue(System.String, System.Int64)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.Conversions.IsHexOrOctValue(System.String, System.UInt64)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.Conversions.ToHalfwidthNumbers(System.String, System.Globalization.CultureInfo)' does not exist in the implementation but it does exist in the contract.
+CannotSealType : Type 'Microsoft.VisualBasic.CompilerServices.DesignerGeneratedAttribute' is sealed in the implementation but not sealed in the contract.
+CannotSealType : Type 'Microsoft.VisualBasic.CompilerServices.IncompleteInitialization' is sealed in the implementation but not sealed in the contract.
+TypesMustExist : Type 'Microsoft.VisualBasic.CompilerServices.InternalErrorException' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.NewLateBinding.FallbackCall(System.Object, System.String, System.Object[], System.String[], System.Boolean)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.NewLateBinding.FallbackGet(System.Object, System.String, System.Object[], System.String[])' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.NewLateBinding.FallbackIndexSet(System.Object, System.Object[], System.String[])' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.NewLateBinding.FallbackIndexSetComplex(System.Object, System.Object[], System.String[], System.Boolean, System.Boolean)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.NewLateBinding.FallbackInvokeDefault1(System.Object, System.Object[], System.String[], System.Boolean)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.NewLateBinding.FallbackInvokeDefault2(System.Object, System.Object[], System.String[], System.Boolean)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.NewLateBinding.FallbackSet(System.Object, System.String, System.Object[])' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.NewLateBinding.FallbackSetComplex(System.Object, System.String, System.Object[], System.Boolean, System.Boolean)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateCallInvokeDefault(System.Object, System.Object[], System.String[], System.Boolean)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateCanEvaluate(System.Object, System.Type, System.String, System.Object[], System.Boolean, System.Boolean)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateGetInvokeDefault(System.Object, System.Object[], System.String[], System.Boolean)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.Operators.CompareObject(System.Object, System.Object, System.Boolean)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.Operators.FallbackInvokeUserDefinedOperator(System.Object, System.Object[])' does not exist in the implementation but it does exist in the contract.
+CannotSealType : Type 'Microsoft.VisualBasic.CompilerServices.OptionCompareAttribute' is sealed in the implementation but not sealed in the contract.
+CannotSealType : Type 'Microsoft.VisualBasic.CompilerServices.OptionTextAttribute' is sealed in the implementation but not sealed in the contract.
+TypesMustExist : Type 'Microsoft.VisualBasic.CompilerServices.SiteDelegate0' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'Microsoft.VisualBasic.CompilerServices.SiteDelegate1' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'Microsoft.VisualBasic.CompilerServices.SiteDelegate2' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'Microsoft.VisualBasic.CompilerServices.SiteDelegate3' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'Microsoft.VisualBasic.CompilerServices.SiteDelegate4' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'Microsoft.VisualBasic.CompilerServices.SiteDelegate5' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'Microsoft.VisualBasic.CompilerServices.SiteDelegate6' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'Microsoft.VisualBasic.CompilerServices.SiteDelegate7' does not exist in the implementation but it does exist in the contract.
+CannotSealType : Type 'Microsoft.VisualBasic.CompilerServices.StandardModuleAttribute' is sealed in the implementation but not sealed in the contract.
+CannotSealType : Type 'Microsoft.VisualBasic.CompilerServices.StaticLocalInitFlag' is sealed in the implementation but not sealed in the contract.
+MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.Utils.GetResourceString(System.String, System.String[])' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'Microsoft.VisualBasic.CompilerServices.Utils.MethodToString(System.Reflection.MethodBase)' does not exist in the implementation but it does exist in the contract.
+Total Issues: 39
diff --git a/src/Microsoft.VisualBasic/tests/ConversionsTests.cs b/src/Microsoft.VisualBasic/tests/ConversionsTests.cs
new file mode 100644
index 0000000000..0483459de2
--- /dev/null
+++ b/src/Microsoft.VisualBasic/tests/ConversionsTests.cs
@@ -0,0 +1,87 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using Microsoft.VisualBasic.CompilerServices;
+using Xunit;
+
+namespace Microsoft.VisualBasic.Tests
+{
+ public class ConversionsTests
+ {
+ public static IEnumerable<object[]> ToBoolean_String_ReturnsExpected_TestData()
+ {
+ yield return new object[] { 5.5.ToString(CultureInfo.CurrentCulture), true };
+ yield return new object[] { 0.0.ToString(CultureInfo.CurrentCulture), false };
+ }
+
+ [Theory]
+ [InlineData("true", true)]
+ [InlineData("false", false)]
+ [InlineData("5", true)]
+ [InlineData("0", false)]
+ [InlineData("&h5", true)]
+ [InlineData("&h0", false)]
+ [InlineData("&o5", true)]
+ [InlineData("&o0", false)]
+ [MemberData(nameof(ToBoolean_String_ReturnsExpected_TestData))]
+ public void ToBoolean_String_ReturnsExpected(string str, bool expected)
+ {
+ Assert.Equal(expected, Conversions.ToBoolean(str));
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("yes")]
+ [InlineData("contoso")]
+ public void ToBoolean_String_ThrowsOnInvalidFormat(string str)
+ {
+ Assert.Throws<InvalidCastException>(() => Conversions.ToBoolean(str));
+ }
+
+ public static IEnumerable<object[]> ToBoolean_Object_ReturnsExpected_TestData()
+ {
+ yield return new object[] { null, false };
+ yield return new object[] { false, false };
+ yield return new object[] { true, true };
+ yield return new object[] { (sbyte)0, false };
+ yield return new object[] { (sbyte)42, true };
+ yield return new object[] { (byte)0, false };
+ yield return new object[] { (byte)42, true };
+ yield return new object[] { (System.Int16)0, false };
+ yield return new object[] { (System.Int16)42, true };
+ yield return new object[] { (System.UInt16)0, false };
+ yield return new object[] { (System.UInt16)42, true };
+ yield return new object[] { (System.Int32)0, false };
+ yield return new object[] { (System.Int32)42, true };
+ yield return new object[] { (System.UInt32)0, false };
+ yield return new object[] { (System.UInt32)42, true };
+ yield return new object[] { (System.Int64)0, false };
+ yield return new object[] { (System.Int64)42, true };
+ yield return new object[] { (System.UInt64)0, false };
+ yield return new object[] { (System.UInt64)42, true };
+ yield return new object[] { 0.0m, false };
+ yield return new object[] { 0.42m, true };
+ yield return new object[] { (float)0.0, false };
+ yield return new object[] { (float)0.42, true };
+ yield return new object[] { (double)0.0, false };
+ yield return new object[] { (double)0.42, true };
+ }
+
+ [Theory]
+ [MemberData(nameof(ToBoolean_Object_ReturnsExpected_TestData))]
+ public void ToBoolean_Object_ReturnsExpected(object obj, bool expected)
+ {
+ Assert.Equal(expected, Conversions.ToBoolean(obj));
+ }
+
+ [Fact]
+ public void ToBoolean_Object_ThrowsOn_List()
+ {
+ Assert.Throws<InvalidCastException>(() => Conversions.ToBoolean(new List<string>()));
+ }
+ }
+}
diff --git a/src/Microsoft.VisualBasic/tests/Microsoft.VisualBasic.Tests.csproj b/src/Microsoft.VisualBasic/tests/Microsoft.VisualBasic.Tests.csproj
index 3e0bee673b..00bba036ce 100644
--- a/src/Microsoft.VisualBasic/tests/Microsoft.VisualBasic.Tests.csproj
+++ b/src/Microsoft.VisualBasic/tests/Microsoft.VisualBasic.Tests.csproj
@@ -7,6 +7,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
<ItemGroup>
+ <Compile Include="ConversionsTests.cs" />
<Compile Include="OperatorsTests.cs" />
<Compile Include="UtilsTests.cs" />
<Compile Include="StringsTests.cs" />
@@ -18,4 +19,4 @@
<EmbeddedResource Include="Resources\$(AssemblyName).rd.xml" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project>
+</Project> \ No newline at end of file
diff --git a/src/Microsoft.Win32.Primitives/src/Microsoft.Win32.Primitives.csproj b/src/Microsoft.Win32.Primitives/src/Microsoft.Win32.Primitives.csproj
index a3eafffcc5..c58d29a0c0 100644
--- a/src/Microsoft.Win32.Primitives/src/Microsoft.Win32.Primitives.csproj
+++ b/src/Microsoft.Win32.Primitives/src/Microsoft.Win32.Primitives.csproj
@@ -36,6 +36,7 @@
</Compile>
</ItemGroup>
<ItemGroup>
+ <Reference Include="System.Memory" />
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.InteropServices" />
</ItemGroup>
diff --git a/src/Microsoft.Win32.Registry/src/Configurations.props b/src/Microsoft.Win32.Registry/src/Configurations.props
index 2e410e6ec3..dc73220035 100644
--- a/src/Microsoft.Win32.Registry/src/Configurations.props
+++ b/src/Microsoft.Win32.Registry/src/Configurations.props
@@ -2,9 +2,9 @@
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PackageConfigurations>
+ netstandard-Windows_NT;
+ netstandard-Unix;
netstandard;
- netcoreapp2.0-Windows_NT;
- netcoreapp2.0-Unix;
netfx-Windows_NT;
</PackageConfigurations>
<BuildConfigurations>
diff --git a/src/Microsoft.Win32.Registry/src/Microsoft.Win32.Registry.csproj b/src/Microsoft.Win32.Registry/src/Microsoft.Win32.Registry.csproj
index 97327470bc..a377e21de2 100644
--- a/src/Microsoft.Win32.Registry/src/Microsoft.Win32.Registry.csproj
+++ b/src/Microsoft.Win32.Registry/src/Microsoft.Win32.Registry.csproj
@@ -8,17 +8,13 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefineConstants>$(DefineConstants);REGISTRY_ASSEMBLY</DefineConstants>
<IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'netfx'">true</IsPartialFacadeAssembly>
- <GeneratePlatformNotSupportedAssemblyMessage Condition="'$(TargetGroup)' == 'netstandard'">SR.PlatformNotSupported_Registry</GeneratePlatformNotSupportedAssemblyMessage>
+ <GeneratePlatformNotSupportedAssemblyMessage Condition="'$(OSGroup)' == 'AnyOS' AND '$(TargetGroup)' == 'netstandard'">SR.PlatformNotSupported_Registry</GeneratePlatformNotSupportedAssemblyMessage>
<!--
Temporarily necessary as this is only being built for UWP due to an unwanted dependency on it
https://github.com/dotnet/corefx/issues/15966
-->
<EnablePinvokeUWPAnalyzer>false</EnablePinvokeUWPAnalyzer>
</PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Unix-Debug|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Unix-Release|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Windows_NT-Debug|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
@@ -27,7 +23,11 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
- <ItemGroup Condition="$(TargetGroup.StartsWith('netcoreapp'))">
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Unix-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Unix-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Windows_NT-Release|AnyCPU'" />
+ <ItemGroup Condition="'$(TargetGroup)' != 'netfx' AND '$(OSGroup)' != 'AnyOS'">
<Compile Include="$(CommonPath)\Interop\Windows\advapi32\Interop.RegistryOptions.cs">
<Link>Common\Interop\Windows\Interop.RegistryOptions.cs</Link>
</Compile>
@@ -44,7 +44,7 @@
<Compile Include="System\Security\AccessControl\RegistryRights.cs" />
<Compile Include="System\Security\AccessControl\RegistrySecurity.cs" />
</ItemGroup>
- <ItemGroup Condition="$(TargetGroup.StartsWith('netcoreapp')) AND '$(TargetsWindows)' == 'true'">
+ <ItemGroup Condition="'$(TargetGroup)' != 'netfx' AND '$(TargetsWindows)' == 'true'">
<Compile Include="$(CommonPath)\Interop\Windows\Interop.Libraries.cs">
<Link>Common\Interop\Windows\Interop.Libraries.cs</Link>
</Compile>
@@ -113,6 +113,7 @@
<Reference Include="System.Collections" />
<Reference Include="System.Diagnostics.Debug" />
<Reference Include="System.Diagnostics.Tools" />
+ <Reference Include="System.Memory" />
<Reference Include="System.Resources.ResourceManager" />
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.Extensions" />
diff --git a/src/Microsoft.Win32.SystemEvents/Microsoft.Win32.SystemEvents.sln b/src/Microsoft.Win32.SystemEvents/Microsoft.Win32.SystemEvents.sln
new file mode 100644
index 0000000000..8be4944c49
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/Microsoft.Win32.SystemEvents.sln
@@ -0,0 +1,50 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.25420.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Win32.SystemEvents.Tests", "tests\Microsoft.Win32.SystemEvents.Tests.csproj", "{8B21F7AD-928E-474C-875A-83D753BB8A28}"
+ ProjectSection(ProjectDependencies) = postProject
+ {91DD22C6-521E-49F9-84E8-1D65BAB97776} = {91DD22C6-521E-49F9-84E8-1D65BAB97776}
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Win32.SystemEvents", "src\Microsoft.Win32.SystemEvents.csproj", "{91DD22C6-521E-49F9-84E8-1D65BAB97776}"
+ ProjectSection(ProjectDependencies) = postProject
+ {90BAFB3A-C396-4323-AC4F-5F968230AD22} = {90BAFB3A-C396-4323-AC4F-5F968230AD22}
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Win32.SystemEvents", "ref\Microsoft.Win32.SystemEvents.csproj", "{90BAFB3A-C396-4323-AC4F-5F968230AD22}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{1A2F9F4A-A032-433E-B914-ADD5992BB178}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E107E9C1-E893-4E87-987E-04EF0DCEAEFD}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{2E666815-2EDB-464B-9DF6-380BF4789AD4}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {8B21F7AD-928E-474C-875A-83D753BB8A28}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU
+ {8B21F7AD-928E-474C-875A-83D753BB8A28}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
+ {8B21F7AD-928E-474C-875A-83D753BB8A28}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
+ {8B21F7AD-928E-474C-875A-83D753BB8A28}.Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU
+ {91DD22C6-521E-49F9-84E8-1D65BAB97776}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU
+ {91DD22C6-521E-49F9-84E8-1D65BAB97776}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
+ {91DD22C6-521E-49F9-84E8-1D65BAB97776}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
+ {91DD22C6-521E-49F9-84E8-1D65BAB97776}.Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU
+ {90BAFB3A-C396-4323-AC4F-5F968230AD22}.Debug|Any CPU.ActiveCfg = netstandard-Debug|Any CPU
+ {90BAFB3A-C396-4323-AC4F-5F968230AD22}.Debug|Any CPU.Build.0 = netstandard-Debug|Any CPU
+ {90BAFB3A-C396-4323-AC4F-5F968230AD22}.Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
+ {90BAFB3A-C396-4323-AC4F-5F968230AD22}.Release|Any CPU.Build.0 = netstandard-Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {8B21F7AD-928E-474C-875A-83D753BB8A28} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
+ {91DD22C6-521E-49F9-84E8-1D65BAB97776} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD}
+ {90BAFB3A-C396-4323-AC4F-5F968230AD22} = {2E666815-2EDB-464B-9DF6-380BF4789AD4}
+ EndGlobalSection
+EndGlobal
diff --git a/src/System.Runtime.Intrinsics/dir.props b/src/Microsoft.Win32.SystemEvents/dir.props
index 37b9ee82d7..4356decc45 100644
--- a/src/System.Runtime.Intrinsics/dir.props
+++ b/src/Microsoft.Win32.SystemEvents/dir.props
@@ -3,7 +3,6 @@
<Import Project="..\dir.props" />
<PropertyGroup>
<AssemblyVersion>4.0.0.0</AssemblyVersion>
- <IsNETCoreApp>true</IsNETCoreApp>
<AssemblyKey>Open</AssemblyKey>
</PropertyGroup>
</Project> \ No newline at end of file
diff --git a/src/Microsoft.Win32.SystemEvents/pkg/Microsoft.Win32.SystemEvents.pkgproj b/src/Microsoft.Win32.SystemEvents/pkg/Microsoft.Win32.SystemEvents.pkgproj
new file mode 100644
index 0000000000..22c2e1d90d
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/pkg/Microsoft.Win32.SystemEvents.pkgproj
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <ItemGroup>
+ <ProjectReference Include="..\ref\Microsoft.Win32.SystemEvents.csproj">
+ <SupportedFramework>uap10.0.16299;net461;netcoreapp2.0;$(AllXamarinFrameworks)</SupportedFramework>
+ </ProjectReference>
+ <ProjectReference Include="..\src\Microsoft.Win32.SystemEvents.csproj" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project> \ No newline at end of file
diff --git a/src/Microsoft.Win32.SystemEvents/ref/Configurations.props b/src/Microsoft.Win32.SystemEvents/ref/Configurations.props
new file mode 100644
index 0000000000..d9777d8275
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/ref/Configurations.props
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <BuildConfigurations>
+ netstandard;
+ netfx;
+ </BuildConfigurations>
+ </PropertyGroup>
+</Project> \ No newline at end of file
diff --git a/src/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.cs b/src/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.cs
new file mode 100644
index 0000000000..11015adb6d
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.cs
@@ -0,0 +1,117 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ------------------------------------------------------------------------------
+// Changes to this file must follow the http://aka.ms/api-review process.
+// ------------------------------------------------------------------------------
+
+namespace Microsoft.Win32
+{
+ public partial class PowerModeChangedEventArgs : System.EventArgs
+ {
+ public PowerModeChangedEventArgs(Microsoft.Win32.PowerModes mode) { }
+ public Microsoft.Win32.PowerModes Mode { get { throw null; } }
+ }
+ public delegate void PowerModeChangedEventHandler(object sender, Microsoft.Win32.PowerModeChangedEventArgs e);
+ public enum PowerModes
+ {
+ Resume = 1,
+ StatusChange = 2,
+ Suspend = 3,
+ }
+ public partial class SessionEndedEventArgs : System.EventArgs
+ {
+ public SessionEndedEventArgs(Microsoft.Win32.SessionEndReasons reason) { }
+ public Microsoft.Win32.SessionEndReasons Reason { get { throw null; } }
+ }
+ public delegate void SessionEndedEventHandler(object sender, Microsoft.Win32.SessionEndedEventArgs e);
+ public partial class SessionEndingEventArgs : System.EventArgs
+ {
+ public SessionEndingEventArgs(Microsoft.Win32.SessionEndReasons reason) { }
+ public bool Cancel { get { throw null; } set { } }
+ public Microsoft.Win32.SessionEndReasons Reason { get { throw null; } }
+ }
+ public delegate void SessionEndingEventHandler(object sender, Microsoft.Win32.SessionEndingEventArgs e);
+ public enum SessionEndReasons
+ {
+ Logoff = 1,
+ SystemShutdown = 2,
+ }
+ public partial class SessionSwitchEventArgs : System.EventArgs
+ {
+ public SessionSwitchEventArgs(Microsoft.Win32.SessionSwitchReason reason) { }
+ public Microsoft.Win32.SessionSwitchReason Reason { get { throw null; } }
+ }
+ public delegate void SessionSwitchEventHandler(object sender, Microsoft.Win32.SessionSwitchEventArgs e);
+ public enum SessionSwitchReason
+ {
+ ConsoleConnect = 1,
+ ConsoleDisconnect = 2,
+ RemoteConnect = 3,
+ RemoteDisconnect = 4,
+ SessionLock = 7,
+ SessionLogoff = 6,
+ SessionLogon = 5,
+ SessionRemoteControl = 9,
+ SessionUnlock = 8,
+ }
+ public sealed partial class SystemEvents
+ {
+ internal SystemEvents() { }
+ public static event System.EventHandler DisplaySettingsChanged { add { } remove { } }
+ public static event System.EventHandler DisplaySettingsChanging { add { } remove { } }
+ public static event System.EventHandler EventsThreadShutdown { add { } remove { } }
+ public static event System.EventHandler InstalledFontsChanged { add { } remove { } }
+ [System.ComponentModel.BrowsableAttribute(false)]
+ [System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
+ [System.ObsoleteAttribute("This event has been deprecated. http://go.microsoft.com/fwlink/?linkid=14202")]
+ public static event System.EventHandler LowMemory { add { } remove { } }
+ public static event System.EventHandler PaletteChanged { add { } remove { } }
+ public static event Microsoft.Win32.PowerModeChangedEventHandler PowerModeChanged { add { } remove { } }
+ public static event Microsoft.Win32.SessionEndedEventHandler SessionEnded { add { } remove { } }
+ public static event Microsoft.Win32.SessionEndingEventHandler SessionEnding { add { } remove { } }
+ public static event Microsoft.Win32.SessionSwitchEventHandler SessionSwitch { add { } remove { } }
+ public static event System.EventHandler TimeChanged { add { } remove { } }
+ public static event Microsoft.Win32.TimerElapsedEventHandler TimerElapsed { add { } remove { } }
+ public static event Microsoft.Win32.UserPreferenceChangedEventHandler UserPreferenceChanged { add { } remove { } }
+ public static event Microsoft.Win32.UserPreferenceChangingEventHandler UserPreferenceChanging { add { } remove { } }
+ public static System.IntPtr CreateTimer(int interval) { throw null; }
+ public static void InvokeOnEventsThread(System.Delegate method) { }
+ public static void KillTimer(System.IntPtr timerId) { }
+ }
+ public partial class TimerElapsedEventArgs : System.EventArgs
+ {
+ public TimerElapsedEventArgs(System.IntPtr timerId) { }
+ public System.IntPtr TimerId { get { throw null; } }
+ }
+ public delegate void TimerElapsedEventHandler(object sender, Microsoft.Win32.TimerElapsedEventArgs e);
+ public enum UserPreferenceCategory
+ {
+ Accessibility = 1,
+ Color = 2,
+ Desktop = 3,
+ General = 4,
+ Icon = 5,
+ Keyboard = 6,
+ Locale = 13,
+ Menu = 7,
+ Mouse = 8,
+ Policy = 9,
+ Power = 10,
+ Screensaver = 11,
+ VisualStyle = 14,
+ Window = 12,
+ }
+ public partial class UserPreferenceChangedEventArgs : System.EventArgs
+ {
+ public UserPreferenceChangedEventArgs(Microsoft.Win32.UserPreferenceCategory category) { }
+ public Microsoft.Win32.UserPreferenceCategory Category { get { throw null; } }
+ }
+ public delegate void UserPreferenceChangedEventHandler(object sender, Microsoft.Win32.UserPreferenceChangedEventArgs e);
+ public partial class UserPreferenceChangingEventArgs : System.EventArgs
+ {
+ public UserPreferenceChangingEventArgs(Microsoft.Win32.UserPreferenceCategory category) { }
+ public Microsoft.Win32.UserPreferenceCategory Category { get { throw null; } }
+ }
+ public delegate void UserPreferenceChangingEventHandler(object sender, Microsoft.Win32.UserPreferenceChangingEventArgs e);
+}
diff --git a/src/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.csproj b/src/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.csproj
new file mode 100644
index 0000000000..e9c9002353
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.csproj
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <ProjectGuid>{90BAFB3A-C396-4323-AC4F-5F968230AD22}</ProjectGuid>
+ <IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'netfx'">true</IsPartialFacadeAssembly>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Release|AnyCPU'" />
+ <ItemGroup>
+ <Compile Include="Microsoft.Win32.SystemEvents.cs" />
+ </ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)' == 'netfx'">
+ <Reference Include="mscorlib" />
+ <Reference Include="System" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project> \ No newline at end of file
diff --git a/src/Microsoft.Win32.SystemEvents/src/Configurations.props b/src/Microsoft.Win32.SystemEvents/src/Configurations.props
new file mode 100644
index 0000000000..c31d0d7816
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/src/Configurations.props
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <PackageConfigurations>
+ netstandard;
+ netcoreapp2.0-Windows_NT;
+ netfx;
+ </PackageConfigurations>
+ <BuildConfigurations>
+ $(PackageConfigurations);
+ netcoreapp-Windows_NT;
+ </BuildConfigurations>
+ </PropertyGroup>
+</Project> \ No newline at end of file
diff --git a/src/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj b/src/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj
new file mode 100644
index 0000000000..1a7aabe1ba
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj
@@ -0,0 +1,178 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <ProjectGuid>{91DD22C6-521E-49F9-84E8-1D65BAB97776}</ProjectGuid>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'netfx'">true</IsPartialFacadeAssembly>
+ <GeneratePlatformNotSupportedAssemblyMessage Condition="'$(TargetGroup)' == 'netstandard' AND '$(OSGroup)' == 'AnyOS'">SR.PlatformNotSupported_SystemEvents</GeneratePlatformNotSupportedAssemblyMessage>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Windows_NT-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
+ <ItemGroup Condition="'$(TargetsWindows)' == 'true' ">
+ <Compile Include="$(CommonPath)\Interop\Windows\Interop.Libraries.cs">
+ <Link>Common\Interop\Windows\Interop.Libraries.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\Interop.Errors.cs">
+ <Link>Common\Interop\Windows\Interop.Errors.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.Constants.cs">
+ <Link>Common\Interop\Windows\user32\Interop.Constants.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.CreateWindowEx.cs">
+ <Link>Common\Interop\Windows\user32\Interop.CreateWindowEx.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.DefWindowProc.cs">
+ <Link>Common\Interop\Windows\user32\Interop.DefWindowProc.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.DestroyWindow.cs">
+ <Link>Common\Interop\Windows\user32\Interop.DestroyWindow.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.DispatchMessage.cs">
+ <Link>Common\Interop\Windows\user32\Interop.DispatchMessage.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.GetClassInfo.cs">
+ <Link>Common\Interop\Windows\user32\Interop.GetClassInfo.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.GetProcessWindowStation.cs">
+ <Link>Common\Interop\Windows\user32\Interop.GetProcessWindowStation.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.GetUserObjectInformation.cs">
+ <Link>Common\Interop\Windows\user32\Interop.GetUserObjectInformation.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.GetWindowThreadProcessId.cs">
+ <Link>Common\Interop\Windows\user32\Interop.GetWindowThreadProcessId.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.IsWindow.cs">
+ <Link>Common\Interop\Windows\user32\Interop.IsWindow.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.KillTimer.cs">
+ <Link>Common\Interop\Windows\user32\Interop.KillTimer.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.MSG.cs">
+ <Link>Common\Interop\Windows\user32\Interop.MSG.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.MsgWaitForMultipleObjectsEx.cs">
+ <Link>Common\Interop\Windows\user32\Interop.MsgWaitForMultipleObjectsEx.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.PeekMessage.cs">
+ <Link>Common\Interop\Windows\user32\Interop.PeekMessage.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.PostMessage.cs">
+ <Link>Common\Interop\Windows\user32\Interop.PostMessage.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.RegisterClass.cs">
+ <Link>Common\Interop\Windows\user32\Interop.RegisterClass.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.RegisterWindowMessage.cs">
+ <Link>Common\Interop\Windows\user32\Interop.RegisterWindowMessage.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.SendMessage.cs">
+ <Link>Common\Interop\Windows\user32\Interop.SendMessage.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.SetClassLong.cs">
+ <Link>Common\Interop\Windows\user32\Interop.SetClassLong.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.SetClassLongPtr.cs">
+ <Link>Common\Interop\Windows\user32\Interop.SetClassLongPtr.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.SetTimer.cs">
+ <Link>Common\Interop\Windows\user32\Interop.SetTimer.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.SetWindowLong.cs">
+ <Link>Common\Interop\Windows\user32\Interop.SetWindowLong.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.SetWindowLongPtr.cs">
+ <Link>Common\Interop\Windows\user32\Interop.SetWindowLongPtr.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.TranslateMessage.cs">
+ <Link>Common\Interop\Windows\user32\Interop.TranslateMessage.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.UnregisterClass.cs">
+ <Link>Common\Interop\Windows\user32\Interop.UnregisterClass.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.USEROBJECTFLAGS.cs">
+ <Link>Common\Interop\Windows\user32\Interop.USEROBJECTFLAGS.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.WNDCLASS.cs">
+ <Link>Common\Interop\Windows\user32\Interop.WNDCLASS.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.WndProc.cs">
+ <Link>Common\Interop\Windows\user32\Interop.WndProc.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.GetCurrentThreadId.cs">
+ <Link>Common\Interop\Windows\kernel32\Interop.GetCurrentThreadId.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.GetModuleHandle.cs">
+ <Link>Common\Interop\Windows\kernel32\Interop.GetModuleHandle.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.GetProcAddress.cs">
+ <Link>Common\Interop\Windows\kernel32\Interop.GetProcAddress.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.LoadLibrary.cs">
+ <Link>Common\Interop\Windows\kernel32\Interop.LoadLibrary.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.FreeLibrary.cs">
+ <Link>Common\Interop\Windows\kernel32\Interop.FreeLibrary.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.SetConsoleCtrlHandler.cs">
+ <Link>Common\Interop\Windows\kernel32\Interop.SetConsoleCtrlHandler.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\wtsapi32\Interop.Constants.cs">
+ <Link>Common\Interop\Windows\wtsapi32\Interop.Constants.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\wtsapi32\Interop.WTSRegisterSessionNotification.cs">
+ <Link>Common\Interop\Windows\wtsapi32\Interop.WTSRegisterSessionNotification.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\wtsapi32\Interop.WTSUnRegisterSessionNotification.cs">
+ <Link>Common\Interop\Windows\wtsapi32\Interop.WTSUnRegisterSessionNotification.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeLibraryHandle.cs">
+ <Link>Common\Microsoft\Win32\SafeHandles\SafeLibraryHandle.cs</Link>
+ </Compile>
+ <Compile Include="Microsoft\Win32\PowerModeChangedEventArgs.cs" />
+ <Compile Include="Microsoft\Win32\PowerModeChangedEventHandler.cs" />
+ <Compile Include="Microsoft\Win32\PowerModes.cs" />
+ <Compile Include="Microsoft\Win32\SessionEndedEventArgs.cs" />
+ <Compile Include="Microsoft\Win32\SessionEndedEventHandler.cs" />
+ <Compile Include="Microsoft\Win32\SessionEndingEventArgs.cs" />
+ <Compile Include="Microsoft\Win32\SessionEndingEventHandler.cs" />
+ <Compile Include="Microsoft\Win32\SessionEndReasons.cs" />
+ <Compile Include="Microsoft\Win32\SessionSwitchEventArgs.cs" />
+ <Compile Include="Microsoft\Win32\SessionSwitchEventHandler.cs" />
+ <Compile Include="Microsoft\Win32\SessionSwitchReason.cs" />
+ <Compile Include="Microsoft\Win32\SystemEvents.cs" />
+ <Compile Include="Microsoft\Win32\TimerElapsedEventArgs.cs" />
+ <Compile Include="Microsoft\Win32\TimerElapsedEventHandler.cs" />
+ <Compile Include="Microsoft\Win32\UserPreferenceCategories.cs" />
+ <Compile Include="Microsoft\Win32\UserPreferenceChangedEventArgs.cs" />
+ <Compile Include="Microsoft\Win32\UserPreferenceChangedEventHandler.cs" />
+ <Compile Include="Microsoft\Win32\UserPreferenceChangingEventArgs.cs" />
+ <Compile Include="Microsoft\Win32\UserPreferenceChangingEventHandler.cs" />
+ </ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)' == 'netfx'">
+ <Reference Include="mscorlib" />
+ <Reference Include="System" />
+ </ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp' OR '$(TargetGroup)' == 'netcoreapp2.0'">
+ <Reference Include="System.Collections" />
+ <Reference Include="System.ComponentModel.EventBasedAsync" />
+ <Reference Include="System.ComponentModel.Primitives" />
+ <Reference Include="System.ComponentModel.TypeConverter" />
+ <Reference Include="System.Diagnostics.Debug" />
+ <Reference Include="System.Diagnostics.Tools" />
+ <Reference Include="System.Resources.ResourceManager" />
+ <Reference Include="System.Runtime" />
+ <Reference Include="System.Runtime.Extensions" />
+ <Reference Include="System.Runtime.InteropServices" />
+ <Reference Include="System.Threading" />
+ <Reference Include="System.Threading.Thread" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project> \ No newline at end of file
diff --git a/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/PowerModeChangedEventArgs.cs b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/PowerModeChangedEventArgs.cs
new file mode 100644
index 0000000000..6a8703f5e3
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/PowerModeChangedEventArgs.cs
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace Microsoft.Win32
+{
+ /// <devdoc>
+ /// <para>Provides data for the <see cref='Microsoft.Win32.SystemEvents.PowerModeChanged'/> event.</para>
+ /// </devdoc>
+ public class PowerModeChangedEventArgs : EventArgs
+ {
+ private readonly PowerModes _mode;
+
+ /// <devdoc>
+ /// <para>Initializes a new instance of the <see cref='Microsoft.Win32.PowerModeChangedEventArgs'/> class.</para>
+ /// </devdoc>
+ public PowerModeChangedEventArgs(PowerModes mode)
+ {
+ _mode = mode;
+ }
+
+ /// <devdoc>
+ /// <para>Gets the power mode.</para>
+ /// </devdoc>
+ public PowerModes Mode
+ {
+ get
+ {
+ return _mode;
+ }
+ }
+ }
+}
+
diff --git a/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/PowerModeChangedEventHandler.cs b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/PowerModeChangedEventHandler.cs
new file mode 100644
index 0000000000..18407c4902
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/PowerModeChangedEventHandler.cs
@@ -0,0 +1,12 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.Win32
+{
+ /// <devdoc>
+ /// <para>Represents the method that will handle the <see cref='Microsoft.Win32.SystemEvents.PowerModeChanged'/> event.</para>
+ /// </devdoc>
+ public delegate void PowerModeChangedEventHandler(object sender, PowerModeChangedEventArgs e);
+}
+
diff --git a/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/PowerModes.cs b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/PowerModes.cs
new file mode 100644
index 0000000000..2a1b8b853a
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/PowerModes.cs
@@ -0,0 +1,32 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.Win32
+{
+ /// <devdoc>
+ /// <para> Specifies how the system
+ /// power mode changes.</para>
+ /// </devdoc>
+ public enum PowerModes
+ {
+ /// <devdoc>
+ /// <para> The system is about to resume.</para>
+ /// </devdoc>
+ Resume = 1,
+
+ /// <devdoc>
+ /// The power mode status has changed. This may
+ /// indicate a weak or charging battery, a transition
+ /// from AC power from battery, or other change in the
+ /// status of the system power supply.
+ /// </devdoc>
+ StatusChange = 2,
+
+ /// <devdoc>
+ /// The system is about to be suspended.
+ /// </devdoc>
+ Suspend = 3,
+ }
+}
+
diff --git a/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionEndReasons.cs b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionEndReasons.cs
new file mode 100644
index 0000000000..62b1039c26
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionEndReasons.cs
@@ -0,0 +1,26 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.Win32
+{
+ /// <devdoc>
+ /// <para> Specifies how the current
+ /// logon session is ending.</para>
+ /// </devdoc>
+ public enum SessionEndReasons
+ {
+ /// <devdoc>
+ /// The user is logging off. The system may continue
+ /// running but the user who started this application
+ /// is logging off.
+ /// </devdoc>
+ Logoff = 1,
+
+ /// <devdoc>
+ /// The system is shutting down.
+ /// </devdoc>
+ SystemShutdown = 2,
+ }
+}
+
diff --git a/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionEndedEventArgs.cs b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionEndedEventArgs.cs
new file mode 100644
index 0000000000..5b674420e3
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionEndedEventArgs.cs
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace Microsoft.Win32
+{
+ /// <devdoc>
+ /// <para>Provides data for the <see cref='Microsoft.Win32.SystemEvents.SessionEnded'/> event.</para>
+ /// </devdoc>
+ public class SessionEndedEventArgs : EventArgs
+ {
+ private readonly SessionEndReasons _reason;
+
+ /// <devdoc>
+ /// <para>Initializes a new instance of the <see cref='Microsoft.Win32.SessionEndedEventArgs'/> class.</para>
+ /// </devdoc>
+ public SessionEndedEventArgs(SessionEndReasons reason)
+ {
+ _reason = reason;
+ }
+
+ /// <devdoc>
+ /// <para>Gets how the session ended.</para>
+ /// </devdoc>
+ public SessionEndReasons Reason
+ {
+ get
+ {
+ return _reason;
+ }
+ }
+ }
+}
+
diff --git a/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionEndedEventHandler.cs b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionEndedEventHandler.cs
new file mode 100644
index 0000000000..715e8d59b3
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionEndedEventHandler.cs
@@ -0,0 +1,12 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.Win32
+{
+ /// <devdoc>
+ /// <para>Represents the method that will handle the <see cref='Microsoft.Win32.SystemEvents.SessionEnded'/> event.</para>
+ /// </devdoc>
+ public delegate void SessionEndedEventHandler(object sender, SessionEndedEventArgs e);
+}
+
diff --git a/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionEndingEventArgs.cs b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionEndingEventArgs.cs
new file mode 100644
index 0000000000..27d42bc3ab
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionEndingEventArgs.cs
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace Microsoft.Win32
+{
+ /// <devdoc>
+ /// <para>Provides data for the <see cref='Microsoft.Win32.SystemEvents.SessionEnding'/> event.</para>
+ /// </devdoc>
+ public class SessionEndingEventArgs : EventArgs
+ {
+ private bool _cancel;
+ private readonly SessionEndReasons _reason;
+
+ /// <devdoc>
+ /// <para>Initializes a new instance of the <see cref='Microsoft.Win32.SessionEndingEventArgs'/> class.</para>
+ /// </devdoc>
+ public SessionEndingEventArgs(SessionEndReasons reason)
+ {
+ _reason = reason;
+ }
+
+ /// <devdoc>
+ /// <para>Gets or sets a value indicating whether to cancel the user request to end the session.</para>
+ /// </devdoc>
+ public bool Cancel
+ {
+ get
+ {
+ return _cancel;
+ }
+ set
+ {
+ _cancel = value;
+ }
+ }
+
+ /// <devdoc>
+ /// <para>Gets how the session is ending.</para>
+ /// </devdoc>
+ public SessionEndReasons Reason
+ {
+ get
+ {
+ return _reason;
+ }
+ }
+ }
+}
+
diff --git a/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionEndingEventHandler.cs b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionEndingEventHandler.cs
new file mode 100644
index 0000000000..44f8645aee
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionEndingEventHandler.cs
@@ -0,0 +1,12 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.Win32
+{
+ /// <devdoc>
+ /// <para>Represents the method that will handle the <see cref='Microsoft.Win32.SystemEvents.SessionEnding'/> event.</para>
+ /// </devdoc>
+ public delegate void SessionEndingEventHandler(object sender, SessionEndingEventArgs e);
+}
+
diff --git a/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionSwitchEventArgs.cs b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionSwitchEventArgs.cs
new file mode 100644
index 0000000000..4d26786b91
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionSwitchEventArgs.cs
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace Microsoft.Win32
+{
+ /// <devdoc>
+ /// <para>Provides data for the <see cref='Microsoft.Win32.SystemEvents.SessionSwitch'/> event.</para>
+ /// </devdoc>
+ public class SessionSwitchEventArgs : EventArgs
+ {
+ private readonly SessionSwitchReason _reason;
+
+ /// <devdoc>
+ /// <para>Initializes a new instance of the <see cref='Microsoft.Win32.SessionSwitchEventArgs'/> class.</para>
+ /// </devdoc>
+ public SessionSwitchEventArgs(SessionSwitchReason reason)
+ {
+ _reason = reason;
+ }
+
+ /// <devdoc>
+ /// <para>Gets the reason for the session switch.</para>
+ /// </devdoc>
+ public SessionSwitchReason Reason
+ {
+ get
+ {
+ return _reason;
+ }
+ }
+ }
+}
+
diff --git a/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionSwitchEventHandler.cs b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionSwitchEventHandler.cs
new file mode 100644
index 0000000000..e0362c5d95
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionSwitchEventHandler.cs
@@ -0,0 +1,12 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.Win32
+{
+ /// <devdoc>
+ /// <para>Represents the method that will handle the <see cref='Microsoft.Win32.SystemEvents.SessionSwitch'/> event.</para>
+ /// </devdoc>
+ public delegate void SessionSwitchEventHandler(object sender, SessionSwitchEventArgs e);
+}
+
diff --git a/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionSwitchReason.cs b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionSwitchReason.cs
new file mode 100644
index 0000000000..1e36503cf3
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SessionSwitchReason.cs
@@ -0,0 +1,61 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System;
+
+namespace Microsoft.Win32
+{
+ /// <devdoc>
+ /// <para> Specifies the reason for the session switch</para>
+ /// </devdoc>
+ public enum SessionSwitchReason
+ {
+ /// <devdoc>
+ /// A session was connected to the console session.
+ /// </devdoc>
+ ConsoleConnect = Interop.Wtsapi32.WTS_CONSOLE_CONNECT,
+
+ /// <devdoc>
+ /// A session was disconnected from the console session.
+ /// </devdoc>
+ ConsoleDisconnect = Interop.Wtsapi32.WTS_CONSOLE_DISCONNECT,
+
+ /// <devdoc>
+ /// A session was connected to the remote session.
+ /// </devdoc>
+ RemoteConnect = Interop.Wtsapi32.WTS_REMOTE_CONNECT,
+
+ /// <devdoc>
+ /// A session was disconnected from the remote session.
+ /// </devdoc>
+ RemoteDisconnect = Interop.Wtsapi32.WTS_REMOTE_DISCONNECT,
+
+ /// <devdoc>
+ /// A user has logged on to the session.
+ /// </devdoc>
+ SessionLogon = Interop.Wtsapi32.WTS_SESSION_LOGON,
+
+ /// <devdoc>
+ /// A user has logged off the session.
+ /// </devdoc>
+ SessionLogoff = Interop.Wtsapi32.WTS_SESSION_LOGOFF,
+
+ /// <devdoc>
+ /// A session has been locked.
+ /// </devdoc>
+ SessionLock = Interop.Wtsapi32.WTS_SESSION_LOCK,
+
+ /// <devdoc>
+ /// A session has been unlocked.
+ /// </devdoc>
+ SessionUnlock = Interop.Wtsapi32.WTS_SESSION_UNLOCK,
+
+ /// <devdoc>
+ /// A session has changed its remote controlled status.
+ /// </devdoc>
+ SessionRemoteControl = Interop.Wtsapi32.WTS_SESSION_REMOTE_CONTROL
+ }
+}
+
diff --git a/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs
new file mode 100644
index 0000000000..321785e686
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs
@@ -0,0 +1,1485 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.Win32
+{
+ using System;
+ using System.Diagnostics;
+ using System.Security;
+ using System.Security.Permissions;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.ComponentModel;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Reflection;
+ using System.Runtime.ConstrainedExecution;
+ using System.Runtime.InteropServices;
+ using System.Runtime.Versioning;
+ using System.Text;
+ using System.Threading;
+
+ /// <devdoc>
+ /// <para>
+ /// Provides a
+ /// set of global system events to callers. This
+ /// class cannot be inherited.</para>
+ /// </devdoc>
+ [SuppressMessage("Microsoft.Design", "CA1049:TypesThatOwnNativeResourcesShouldBeDisposable")]
+ public sealed class SystemEvents
+ {
+ // Almost all of our data is static. We keep a single instance of
+ // SystemEvents around so we can bind delegates to it.
+ // Non-static methods in this class will only be called through
+ // one of the delegates.
+ private static readonly object s_eventLockObject = new object();
+ private static readonly object s_procLockObject = new object();
+ private static volatile SystemEvents s_systemEvents;
+ private static volatile Thread s_windowThread;
+ private static volatile ManualResetEvent s_eventWindowReady;
+ private static Random s_randomTimerId = new Random();
+ private static volatile bool s_registeredSessionNotification = false;
+ private static volatile int s_domainQualifier;
+ private static volatile Interop.User32.WNDCLASS s_staticwndclass;
+ [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
+ private static volatile IntPtr s_defWindowProc;
+
+ private static volatile string s_className = null;
+
+ // cross-thread marshaling
+ private static volatile Queue<Delegate> s_threadCallbackList; // list of Delegates
+ private static volatile int s_threadCallbackMessage = 0;
+ private static volatile ManualResetEvent s_eventThreadTerminated;
+
+ // Per-instance data that is isolated to the window thread.
+ private volatile IntPtr _windowHandle;
+ private Interop.User32.WndProc _windowProc;
+ private Interop.Kernel32.ConsoleCtrlHandlerRoutine _consoleHandler;
+
+ // The set of events we respond to.
+ private static readonly object s_onUserPreferenceChangingEvent = new object();
+ private static readonly object s_onUserPreferenceChangedEvent = new object();
+ private static readonly object s_onSessionEndingEvent = new object();
+ private static readonly object s_onSessionEndedEvent = new object();
+ private static readonly object s_onPowerModeChangedEvent = new object();
+ private static readonly object s_onLowMemoryEvent = new object();
+ private static readonly object s_onDisplaySettingsChangingEvent = new object();
+ private static readonly object s_onDisplaySettingsChangedEvent = new object();
+ private static readonly object s_onInstalledFontsChangedEvent = new object();
+ private static readonly object s_onTimeChangedEvent = new object();
+ private static readonly object s_onTimerElapsedEvent = new object();
+ private static readonly object s_onPaletteChangedEvent = new object();
+ private static readonly object s_onEventsThreadShutdownEvent = new object();
+ private static readonly object s_onSessionSwitchEvent = new object();
+
+
+ // Our list of handler information. This is a lookup of the above keys and objects that
+ // match a delegate with a SyncronizationContext so we can fire on the proper thread.
+ private static Dictionary<object, List<SystemEventInvokeInfo>> s_handlers;
+
+
+ /// <devdoc>
+ /// This class is static, there is no need to ever create it.
+ /// </devdoc>
+ private SystemEvents()
+ {
+ }
+
+
+ // stole from SystemInformation... if we get SystemInformation moved
+ // to somewhere that we can use it... rip this!
+ [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
+ private static volatile IntPtr s_processWinStation = IntPtr.Zero;
+ private static volatile bool s_isUserInteractive = false;
+ private static bool UserInteractive
+ {
+ get
+ {
+ if (Environment.OSVersion.Platform == System.PlatformID.Win32NT)
+ {
+ IntPtr hwinsta = IntPtr.Zero;
+
+ hwinsta = Interop.User32.GetProcessWindowStation();
+ if (hwinsta != IntPtr.Zero && s_processWinStation != hwinsta)
+ {
+ s_isUserInteractive = true;
+
+ int lengthNeeded = 0;
+ Interop.User32.USEROBJECTFLAGS flags = new Interop.User32.USEROBJECTFLAGS();
+
+ if (Interop.User32.GetUserObjectInformationW(hwinsta, Interop.User32.UOI_FLAGS, flags, Marshal.SizeOf(flags), ref lengthNeeded))
+ {
+ if ((flags.dwFlags & Interop.User32.WSF_VISIBLE) == 0)
+ {
+ s_isUserInteractive = false;
+ }
+ }
+ s_processWinStation = hwinsta;
+ }
+ }
+ else
+ {
+ s_isUserInteractive = true;
+ }
+ return s_isUserInteractive;
+ }
+ }
+
+
+ /// <devdoc>
+ /// <para>Occurs when the display settings are changing.</para>
+ /// </devdoc>
+ public static event EventHandler DisplaySettingsChanging
+ {
+ add
+ {
+ AddEventHandler(s_onDisplaySettingsChangingEvent, value);
+ }
+ remove
+ {
+ RemoveEventHandler(s_onDisplaySettingsChangingEvent, value);
+ }
+ }
+
+
+ /// <devdoc>
+ /// <para>Occurs when the user changes the display settings.</para>
+ /// </devdoc>
+ public static event EventHandler DisplaySettingsChanged
+ {
+ add
+ {
+ AddEventHandler(s_onDisplaySettingsChangedEvent, value);
+ }
+ remove
+ {
+ RemoveEventHandler(s_onDisplaySettingsChangedEvent, value);
+ }
+ }
+
+
+ /// <devdoc>
+ /// <para>Occurs before the thread that listens for system events is terminated.
+ /// Delegates will be invoked on the events thread.</para>
+ /// </devdoc>
+ public static event EventHandler EventsThreadShutdown
+ {
+ // Really only here for GDI+ initialization and shut down
+ add
+ {
+ AddEventHandler(s_onEventsThreadShutdownEvent, value);
+ }
+ remove
+ {
+ RemoveEventHandler(s_onEventsThreadShutdownEvent, value);
+ }
+ }
+
+
+ /// <devdoc>
+ /// <para>Occurs when the user adds fonts to or removes fonts from the system.</para>
+ /// </devdoc>
+ public static event EventHandler InstalledFontsChanged
+ {
+ add
+ {
+ AddEventHandler(s_onInstalledFontsChangedEvent, value);
+ }
+ remove
+ {
+ RemoveEventHandler(s_onInstalledFontsChangedEvent, value);
+ }
+ }
+
+
+ /// <devdoc>
+ /// <para>Occurs when the system is running out of available RAM.</para>
+ /// </devdoc>
+ [Obsolete("This event has been deprecated. http://go.microsoft.com/fwlink/?linkid=14202")]
+ [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
+ public static event EventHandler LowMemory
+ {
+ add
+ {
+ EnsureSystemEvents(true, true);
+ AddEventHandler(s_onLowMemoryEvent, value);
+ }
+ remove
+ {
+ RemoveEventHandler(s_onLowMemoryEvent, value);
+ }
+ }
+
+
+ /// <devdoc>
+ /// <para>Occurs when the user switches to an application that uses a different
+ /// palette.</para>
+ /// </devdoc>
+ public static event EventHandler PaletteChanged
+ {
+ add
+ {
+ AddEventHandler(s_onPaletteChangedEvent, value);
+ }
+ remove
+ {
+ RemoveEventHandler(s_onPaletteChangedEvent, value);
+ }
+ }
+
+
+ /// <devdoc>
+ /// <para>Occurs when the user suspends or resumes the system.</para>
+ /// </devdoc>
+ public static event PowerModeChangedEventHandler PowerModeChanged
+ {
+ add
+ {
+ EnsureSystemEvents(true, true);
+ AddEventHandler(s_onPowerModeChangedEvent, value);
+ }
+ remove
+ {
+ RemoveEventHandler(s_onPowerModeChangedEvent, value);
+ }
+ }
+
+
+ /// <devdoc>
+ /// <para>Occurs when the user is logging off or shutting down the system.</para>
+ /// </devdoc>
+ public static event SessionEndedEventHandler SessionEnded
+ {
+ add
+ {
+ EnsureSystemEvents(true, false);
+ AddEventHandler(s_onSessionEndedEvent, value);
+ }
+ remove
+ {
+ RemoveEventHandler(s_onSessionEndedEvent, value);
+ }
+ }
+
+
+ /// <devdoc>
+ /// <para>Occurs when the user is trying to log off or shutdown the system.</para>
+ /// </devdoc>
+ public static event SessionEndingEventHandler SessionEnding
+ {
+ add
+ {
+ EnsureSystemEvents(true, false);
+ AddEventHandler(s_onSessionEndingEvent, value);
+ }
+ remove
+ {
+ RemoveEventHandler(s_onSessionEndingEvent, value);
+ }
+ }
+
+ /// <devdoc>
+ /// <para>Occurs when a user session switches.</para>
+ /// </devdoc>
+ public static event SessionSwitchEventHandler SessionSwitch
+ {
+ add
+ {
+ EnsureSystemEvents(true, true);
+ EnsureRegisteredSessionNotification();
+ AddEventHandler(s_onSessionSwitchEvent, value);
+ }
+ remove
+ {
+ RemoveEventHandler(s_onSessionSwitchEvent, value);
+ }
+ }
+
+
+ /// <devdoc>
+ /// <para>Occurs when the user changes the time on the system clock.</para>
+ /// </devdoc>
+ public static event EventHandler TimeChanged
+ {
+ add
+ {
+ EnsureSystemEvents(true, false);
+ AddEventHandler(s_onTimeChangedEvent, value);
+ }
+ remove
+ {
+ RemoveEventHandler(s_onTimeChangedEvent, value);
+ }
+ }
+
+
+ /// <devdoc>
+ /// <para>Occurs when a windows timer interval has expired.</para>
+ /// </devdoc>
+ public static event TimerElapsedEventHandler TimerElapsed
+ {
+ add
+ {
+ EnsureSystemEvents(true, false);
+ AddEventHandler(s_onTimerElapsedEvent, value);
+ }
+ remove
+ {
+ RemoveEventHandler(s_onTimerElapsedEvent, value);
+ }
+ }
+
+
+ /// <devdoc>
+ /// <para>Occurs when a user preference has changed.</para>
+ /// </devdoc>
+ public static event UserPreferenceChangedEventHandler UserPreferenceChanged
+ {
+ add
+ {
+ AddEventHandler(s_onUserPreferenceChangedEvent, value);
+ }
+ remove
+ {
+ RemoveEventHandler(s_onUserPreferenceChangedEvent, value);
+ }
+ }
+
+ /// <devdoc>
+ /// <para>Occurs when a user preference is changing.</para>
+ /// </devdoc>
+ public static event UserPreferenceChangingEventHandler UserPreferenceChanging
+ {
+ add
+ {
+ AddEventHandler(s_onUserPreferenceChangingEvent, value);
+ }
+ remove
+ {
+ RemoveEventHandler(s_onUserPreferenceChangingEvent, value);
+ }
+ }
+
+ private static void AddEventHandler(object key, Delegate value)
+ {
+ lock (s_eventLockObject)
+ {
+ if (s_handlers == null)
+ {
+ s_handlers = new Dictionary<object, List<SystemEventInvokeInfo>>();
+ EnsureSystemEvents(false, false);
+ }
+
+ List<SystemEventInvokeInfo> invokeItems;
+
+ if (!s_handlers.TryGetValue(key, out invokeItems))
+ {
+ invokeItems = new List<SystemEventInvokeInfo>();
+ s_handlers[key] = invokeItems;
+ }
+ else
+ {
+ invokeItems = s_handlers[key];
+ }
+
+ invokeItems.Add(new SystemEventInvokeInfo(value));
+ }
+ }
+
+ /// <devdoc>
+ /// Console handler we add in case we are a console application or a service.
+ /// Without this we will not get end session events.
+ /// </devdoc>
+ private bool ConsoleHandlerProc(int signalType)
+ {
+ switch (signalType)
+ {
+ case Interop.User32.CTRL_LOGOFF_EVENT:
+ OnSessionEnded((IntPtr)1, (IntPtr)Interop.User32.ENDSESSION_LOGOFF);
+ break;
+
+ case Interop.User32.CTRL_SHUTDOWN_EVENT:
+ OnSessionEnded((IntPtr)1, (IntPtr)0);
+ break;
+ }
+
+ return false;
+ }
+
+ private Interop.User32.WNDCLASS WndClass
+ {
+ get
+ {
+ if (s_staticwndclass == null)
+ {
+ const string classNameFormat = ".NET-BroadcastEventWindow.{0}.{1}";
+
+ IntPtr hInstance = Interop.Kernel32.GetModuleHandle(null);
+
+ s_className = string.Format(System.Globalization.CultureInfo.InvariantCulture,
+ classNameFormat,
+ Convert.ToString(AppDomain.CurrentDomain.GetHashCode(), 16),
+ s_domainQualifier);
+
+ Interop.User32.WNDCLASS tempwndclass = new Interop.User32.WNDCLASS();
+ tempwndclass.hbrBackground = (IntPtr)(Interop.User32.COLOR_WINDOW + 1);
+ tempwndclass.style = 0;
+
+ _windowProc = new Interop.User32.WndProc(this.WindowProc);
+ tempwndclass.lpszClassName = s_className;
+ tempwndclass.lpfnWndProc = _windowProc;
+ tempwndclass.hInstance = hInstance;
+ s_staticwndclass = tempwndclass;
+ }
+ return s_staticwndclass;
+ }
+ }
+
+ private IntPtr DefWndProc
+ {
+ get
+ {
+ if (s_defWindowProc == IntPtr.Zero)
+ {
+ s_defWindowProc = Interop.Kernel32.GetProcAddress(Interop.Kernel32.GetModuleHandle("user32.dll"), "DefWindowProcW");
+ }
+ return s_defWindowProc;
+ }
+ }
+
+ [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "Only called on a single thread")]
+ private void BumpQualifier()
+ {
+ s_staticwndclass = null;
+ s_domainQualifier++;
+ }
+
+ /// <include file='doc\SystemEvents.uex' path='docs/doc[@for="SystemEvents.CreateBroadcastWindow"]/*' />
+ /// <devdoc>
+ /// Goes through the work to register and create a window.
+ /// </devdoc>
+ private IntPtr CreateBroadcastWindow()
+ {
+ // Register the window class.
+ Interop.User32.WNDCLASS_I wndclassi = new Interop.User32.WNDCLASS_I();
+ IntPtr hInstance = Interop.Kernel32.GetModuleHandle(null);
+
+ if (!Interop.User32.GetClassInfoW(hInstance, WndClass.lpszClassName, wndclassi))
+ {
+ if (Interop.User32.RegisterClassW(WndClass) == 0)
+ {
+ _windowProc = null;
+ Debug.WriteLine("Unable to register broadcast window class: {0}", Marshal.GetLastWin32Error());
+ return IntPtr.Zero;
+ }
+ }
+ else
+ {
+ // lets double check the wndproc returned by getclassinfo for sentinel value defwndproc.
+ if (wndclassi.lpfnWndProc == DefWndProc)
+ {
+ // if we are in there, it means className belongs to an unloaded appdomain.
+ short atom = 0;
+
+ // try to unregister it.
+ if (0 != Interop.User32.UnregisterClassW(WndClass.lpszClassName, Interop.Kernel32.GetModuleHandle(null)))
+ {
+ atom = Interop.User32.RegisterClassW(WndClass);
+ }
+
+ if (atom == 0)
+ {
+ do
+ {
+ BumpQualifier();
+ atom = Interop.User32.RegisterClassW(WndClass);
+ } while (atom == 0 && Marshal.GetLastWin32Error() == Interop.Errors.ERROR_CLASS_ALREADY_EXISTS);
+ }
+ }
+ }
+
+ // And create an instance of the window.
+ IntPtr hwnd = Interop.User32.CreateWindowExW(
+ 0,
+ WndClass.lpszClassName,
+ WndClass.lpszClassName,
+ Interop.User32.WS_POPUP,
+ 0, 0, 0, 0, IntPtr.Zero, IntPtr.Zero,
+ hInstance, IntPtr.Zero);
+ return hwnd;
+ }
+
+ /// <internalonly/>
+ /// <devdoc>
+ /// <para>Creates a new window timer asociated with the
+ /// system events window.</para>
+ /// </devdoc>
+ public static IntPtr CreateTimer(int interval)
+ {
+ if (interval <= 0)
+ {
+ throw new ArgumentException(SR.Format(SR.InvalidLowBoundArgument, "interval", interval.ToString(System.Threading.Thread.CurrentThread.CurrentCulture), "0"));
+ }
+
+ EnsureSystemEvents(true, true);
+ IntPtr timerId = Interop.User32.SendMessageW(new HandleRef(s_systemEvents, s_systemEvents._windowHandle),
+ Interop.User32.WM_CREATETIMER, (IntPtr)interval, IntPtr.Zero);
+
+ if (timerId == IntPtr.Zero)
+ {
+ throw new ExternalException(SR.ErrorCreateTimer);
+ }
+ return timerId;
+ }
+
+ private void Dispose()
+ {
+ if (_windowHandle != IntPtr.Zero)
+ {
+ if (s_registeredSessionNotification)
+ {
+ Interop.Wtsapi32.WTSUnRegisterSessionNotification(new HandleRef(s_systemEvents, s_systemEvents._windowHandle));
+ }
+
+ IntPtr handle = _windowHandle;
+ _windowHandle = IntPtr.Zero;
+
+ // we check IsWindow because Application may have rudely destroyed our broadcast window.
+ // if this were true, we want to unregister the class.
+ if (Interop.User32.IsWindow(handle) && DefWndProc != IntPtr.Zero)
+ {
+ // set our sentinel value that we will look for upon initialization to indicate
+ // the window class belongs to an unloaded appdomain and therefore should not be used.
+ if (IntPtr.Size == 4)
+ {
+ // In a 32-bit process we must call the non-'ptr' version of these APIs
+ Interop.User32.SetWindowLongW(handle, Interop.User32.GWL_WNDPROC, DefWndProc);
+ Interop.User32.SetClassLongW(handle, Interop.User32.GCL_WNDPROC, DefWndProc);
+ }
+ else
+ {
+ Interop.User32.SetWindowLongPtrW(handle, Interop.User32.GWL_WNDPROC, DefWndProc);
+ Interop.User32.SetClassLongPtrW(handle, Interop.User32.GCL_WNDPROC, DefWndProc);
+ }
+ }
+
+ // If DestroyWindow failed, it is because we're being
+ // shutdown from another thread. In this case, locate the
+ // DefWindowProc call in User32, set the window proc to call it,
+ // and post a WM_CLOSE. This will close the window from
+ // the correct thread without relying on managed code executing.
+ if (Interop.User32.IsWindow(handle) && !Interop.User32.DestroyWindow(handle))
+ {
+ Interop.User32.PostMessageW(handle, Interop.User32.WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
+ }
+ else
+ {
+ IntPtr hInstance = Interop.Kernel32.GetModuleHandle(null);
+ Interop.User32.UnregisterClassW(s_className, hInstance);
+ }
+ }
+
+ if (_consoleHandler != null)
+ {
+ Interop.Kernel32.SetConsoleCtrlHandler(_consoleHandler, false);
+ _consoleHandler = null;
+ }
+ }
+
+ /// <devdoc>
+ /// Creates the static resources needed by
+ /// system events.
+ /// </devdoc>
+ private static void EnsureSystemEvents(bool requireHandle, bool throwOnRefusal)
+ {
+ // The secondary check here is to detect asp.net. Asp.net uses multiple
+ // app domains to field requests and we do not want to gobble up an
+ // additional thread per domain. So under this scenario SystemEvents
+ // becomes a nop.
+ if (s_systemEvents == null)
+ {
+ lock (s_procLockObject)
+ {
+ if (s_systemEvents == null)
+ {
+ if (Thread.GetDomain().GetData(".appDomain") != null)
+ {
+ if (throwOnRefusal)
+ {
+ throw new InvalidOperationException(SR.ErrorSystemEventsNotSupported);
+ }
+ return;
+ }
+
+ // If we are creating system events on a thread declared as STA, then
+ // just share the thread.
+ if (!UserInteractive || Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)
+ {
+ SystemEvents systemEvents = new SystemEvents();
+ systemEvents.Initialize();
+
+ // ensure this is initialized last as that will force concurrent threads calling
+ // this method to block until after we've initialized.
+ s_systemEvents = systemEvents;
+ }
+ else
+ {
+ s_eventWindowReady = new ManualResetEvent(false);
+ SystemEvents systemEvents = new SystemEvents();
+ s_windowThread = new Thread(new ThreadStart(systemEvents.WindowThreadProc));
+ s_windowThread.IsBackground = true;
+ s_windowThread.Name = ".NET SystemEvents";
+ s_windowThread.Start();
+ s_eventWindowReady.WaitOne();
+
+ // ensure this is initialized last as that will force concurrent threads calling
+ // this method to block until after we've initialized.
+ s_systemEvents = systemEvents;
+ }
+
+ if (requireHandle && s_systemEvents._windowHandle == IntPtr.Zero)
+ {
+ // In theory, it's not the end of the world that
+ // we don't get system events. Unfortunately, the main reason windowHandle == 0
+ // is CreateWindowEx failed for mysterious reasons, and when that happens,
+ // subsequent (and more important) CreateWindowEx calls also fail.
+ throw new ExternalException(SR.ErrorCreateSystemEvents);
+ }
+ }
+ }
+ }
+ }
+
+ private static void EnsureRegisteredSessionNotification()
+ {
+ if (!s_registeredSessionNotification)
+ {
+ IntPtr retval = Interop.Kernel32.LoadLibrary(Interop.Libraries.Wtsapi32);
+
+ if (retval != IntPtr.Zero)
+ {
+ Interop.Wtsapi32.WTSRegisterSessionNotification(new HandleRef(s_systemEvents, s_systemEvents._windowHandle), Interop.Wtsapi32.NOTIFY_FOR_THIS_SESSION);
+ s_registeredSessionNotification = true;
+ Interop.Kernel32.FreeLibrary(retval);
+ }
+ }
+ }
+
+ private UserPreferenceCategory GetUserPreferenceCategory(int msg, IntPtr wParam, IntPtr lParam)
+ {
+ UserPreferenceCategory pref = UserPreferenceCategory.General;
+
+ if (msg == Interop.User32.WM_SETTINGCHANGE)
+ {
+ if (lParam != IntPtr.Zero && Marshal.PtrToStringUni(lParam).Equals("Policy"))
+ {
+ pref = UserPreferenceCategory.Policy;
+ }
+ else if (lParam != IntPtr.Zero && Marshal.PtrToStringUni(lParam).Equals("intl"))
+ {
+ pref = UserPreferenceCategory.Locale;
+ }
+ else
+ {
+ switch ((int)wParam)
+ {
+ case Interop.User32.SPI_SETACCESSTIMEOUT:
+ case Interop.User32.SPI_SETFILTERKEYS:
+ case Interop.User32.SPI_SETHIGHCONTRAST:
+ case Interop.User32.SPI_SETMOUSEKEYS:
+ case Interop.User32.SPI_SETSCREENREADER:
+ case Interop.User32.SPI_SETSERIALKEYS:
+ case Interop.User32.SPI_SETSHOWSOUNDS:
+ case Interop.User32.SPI_SETSOUNDSENTRY:
+ case Interop.User32.SPI_SETSTICKYKEYS:
+ case Interop.User32.SPI_SETTOGGLEKEYS:
+ pref = UserPreferenceCategory.Accessibility;
+ break;
+
+ case Interop.User32.SPI_SETDESKWALLPAPER:
+ case Interop.User32.SPI_SETFONTSMOOTHING:
+ case Interop.User32.SPI_SETCURSORS:
+ case Interop.User32.SPI_SETDESKPATTERN:
+ case Interop.User32.SPI_SETGRIDGRANULARITY:
+ case Interop.User32.SPI_SETWORKAREA:
+ pref = UserPreferenceCategory.Desktop;
+ break;
+
+ case Interop.User32.SPI_ICONHORIZONTALSPACING:
+ case Interop.User32.SPI_ICONVERTICALSPACING:
+ case Interop.User32.SPI_SETICONMETRICS:
+ case Interop.User32.SPI_SETICONS:
+ case Interop.User32.SPI_SETICONTITLELOGFONT:
+ case Interop.User32.SPI_SETICONTITLEWRAP:
+ pref = UserPreferenceCategory.Icon;
+ break;
+
+ case Interop.User32.SPI_SETDOUBLECLICKTIME:
+ case Interop.User32.SPI_SETDOUBLECLKHEIGHT:
+ case Interop.User32.SPI_SETDOUBLECLKWIDTH:
+ case Interop.User32.SPI_SETMOUSE:
+ case Interop.User32.SPI_SETMOUSEBUTTONSWAP:
+ case Interop.User32.SPI_SETMOUSEHOVERHEIGHT:
+ case Interop.User32.SPI_SETMOUSEHOVERTIME:
+ case Interop.User32.SPI_SETMOUSESPEED:
+ case Interop.User32.SPI_SETMOUSETRAILS:
+ case Interop.User32.SPI_SETSNAPTODEFBUTTON:
+ case Interop.User32.SPI_SETWHEELSCROLLLINES:
+ case Interop.User32.SPI_SETCURSORSHADOW:
+ case Interop.User32.SPI_SETHOTTRACKING:
+ case Interop.User32.SPI_SETTOOLTIPANIMATION:
+ case Interop.User32.SPI_SETTOOLTIPFADE:
+ pref = UserPreferenceCategory.Mouse;
+ break;
+
+ case Interop.User32.SPI_SETKEYBOARDDELAY:
+ case Interop.User32.SPI_SETKEYBOARDPREF:
+ case Interop.User32.SPI_SETKEYBOARDSPEED:
+ case Interop.User32.SPI_SETLANGTOGGLE:
+ pref = UserPreferenceCategory.Keyboard;
+ break;
+
+ case Interop.User32.SPI_SETMENUDROPALIGNMENT:
+ case Interop.User32.SPI_SETMENUFADE:
+ case Interop.User32.SPI_SETMENUSHOWDELAY:
+ case Interop.User32.SPI_SETMENUANIMATION:
+ case Interop.User32.SPI_SETSELECTIONFADE:
+ pref = UserPreferenceCategory.Menu;
+ break;
+
+ case Interop.User32.SPI_SETLOWPOWERACTIVE:
+ case Interop.User32.SPI_SETLOWPOWERTIMEOUT:
+ case Interop.User32.SPI_SETPOWEROFFACTIVE:
+ case Interop.User32.SPI_SETPOWEROFFTIMEOUT:
+ pref = UserPreferenceCategory.Power;
+ break;
+
+ case Interop.User32.SPI_SETSCREENSAVEACTIVE:
+ case Interop.User32.SPI_SETSCREENSAVERRUNNING:
+ case Interop.User32.SPI_SETSCREENSAVETIMEOUT:
+ pref = UserPreferenceCategory.Screensaver;
+ break;
+
+ case Interop.User32.SPI_SETKEYBOARDCUES:
+ case Interop.User32.SPI_SETCOMBOBOXANIMATION:
+ case Interop.User32.SPI_SETLISTBOXSMOOTHSCROLLING:
+ case Interop.User32.SPI_SETGRADIENTCAPTIONS:
+ case Interop.User32.SPI_SETUIEFFECTS:
+ case Interop.User32.SPI_SETACTIVEWINDOWTRACKING:
+ case Interop.User32.SPI_SETACTIVEWNDTRKZORDER:
+ case Interop.User32.SPI_SETACTIVEWNDTRKTIMEOUT:
+ case Interop.User32.SPI_SETANIMATION:
+ case Interop.User32.SPI_SETBORDER:
+ case Interop.User32.SPI_SETCARETWIDTH:
+ case Interop.User32.SPI_SETDRAGFULLWINDOWS:
+ case Interop.User32.SPI_SETDRAGHEIGHT:
+ case Interop.User32.SPI_SETDRAGWIDTH:
+ case Interop.User32.SPI_SETFOREGROUNDFLASHCOUNT:
+ case Interop.User32.SPI_SETFOREGROUNDLOCKTIMEOUT:
+ case Interop.User32.SPI_SETMINIMIZEDMETRICS:
+ case Interop.User32.SPI_SETNONCLIENTMETRICS:
+ case Interop.User32.SPI_SETSHOWIMEUI:
+ pref = UserPreferenceCategory.Window;
+ break;
+ }
+ }
+ }
+ else if (msg == Interop.User32.WM_SYSCOLORCHANGE)
+ {
+ pref = UserPreferenceCategory.Color;
+ }
+ else
+ {
+ Debug.Fail("Unrecognized message passed to UserPreferenceCategory");
+ }
+
+ return pref;
+ }
+
+ private void Initialize()
+ {
+ _consoleHandler = new Interop.Kernel32.ConsoleCtrlHandlerRoutine(ConsoleHandlerProc);
+ if (!Interop.Kernel32.SetConsoleCtrlHandler(_consoleHandler, true))
+ {
+ Debug.Fail("Failed to install console handler.");
+ _consoleHandler = null;
+ }
+
+ _windowHandle = CreateBroadcastWindow();
+ Debug.WriteLineIf(_windowHandle == IntPtr.Zero, "CreateBroadcastWindow failed");
+
+ AppDomain.CurrentDomain.ProcessExit += new EventHandler(SystemEvents.Shutdown);
+ AppDomain.CurrentDomain.DomainUnload += new EventHandler(SystemEvents.Shutdown);
+ }
+
+ /// <devdoc>
+ /// Called on the control's owning thread to perform the actual callback.
+ /// This empties this control's callback queue, propagating any excpetions
+ /// back as needed.
+ /// </devdoc>
+ [SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")]
+ [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
+ private void InvokeMarshaledCallbacks()
+ {
+ Debug.Assert(s_threadCallbackList != null, "Invoking marshaled callbacks before there are any");
+
+ Delegate current = null;
+ lock (s_threadCallbackList)
+ {
+ if (s_threadCallbackList.Count > 0)
+ {
+ current = (Delegate)s_threadCallbackList.Dequeue();
+ }
+ }
+
+ // Now invoke on all the queued items.
+ while (current != null)
+ {
+ try
+ {
+ // Optimize a common case of using EventHandler. This allows us to invoke
+ // early bound, which is a bit more efficient.
+ EventHandler c = current as EventHandler;
+ if (c != null)
+ {
+ c(null, EventArgs.Empty);
+ }
+ else
+ {
+ current.DynamicInvoke(new object[0]);
+ }
+ }
+ catch (Exception t)
+ {
+ Debug.Fail("SystemEvents marshaled callback failed:" + t);
+ }
+ lock (s_threadCallbackList)
+ {
+ if (s_threadCallbackList.Count > 0)
+ {
+ current = (Delegate)s_threadCallbackList.Dequeue();
+ }
+ else
+ {
+ current = null;
+ }
+ }
+ }
+ }
+
+ /// <devdoc>
+ /// Executes the given delegate asynchronously on the thread that listens for system events. Similar to Control.BeginInvoke().
+ /// </devdoc>
+ public static void InvokeOnEventsThread(Delegate method)
+ {
+ // This method is really only here for GDI+ initialization/shutdown
+ EnsureSystemEvents(true, true);
+
+#if DEBUG
+ int pid;
+ int thread = Interop.User32.GetWindowThreadProcessId(new HandleRef(s_systemEvents, s_systemEvents._windowHandle), out pid);
+ Debug.Assert(s_windowThread == null || thread != Interop.Kernel32.GetCurrentThreadId(), "Don't call MarshaledInvoke on the system events thread");
+#endif
+
+ if (s_threadCallbackList == null)
+ {
+ lock (s_eventLockObject)
+ {
+ if (s_threadCallbackList == null)
+ {
+ s_threadCallbackMessage = Interop.User32.RegisterWindowMessageW("SystemEventsThreadCallbackMessage");
+ s_threadCallbackList = new Queue<Delegate>();
+ }
+ }
+ }
+
+ Debug.Assert(s_threadCallbackMessage != 0, "threadCallbackList initialized but threadCallbackMessage not?");
+
+ lock (s_threadCallbackList)
+ {
+ s_threadCallbackList.Enqueue(method);
+ }
+
+ Interop.User32.PostMessageW(new HandleRef(s_systemEvents, s_systemEvents._windowHandle), s_threadCallbackMessage, IntPtr.Zero, IntPtr.Zero);
+ }
+
+ /// <internalonly/>
+ /// <devdoc>
+ /// <para>Kills the timer specified by the given id.</para>
+ /// </devdoc>
+ public static void KillTimer(IntPtr timerId)
+ {
+ EnsureSystemEvents(true, true);
+ if (s_systemEvents._windowHandle != IntPtr.Zero)
+ {
+ int res = (int)Interop.User32.SendMessageW(new HandleRef(s_systemEvents, s_systemEvents._windowHandle),
+ Interop.User32.WM_KILLTIMER, timerId, IntPtr.Zero);
+
+ if (res == 0)
+ throw new ExternalException(SR.ErrorKillTimer);
+ }
+ }
+
+ /// <devdoc>
+ /// Callback that handles the create timer
+ /// user message.
+ /// </devdoc>
+ private IntPtr OnCreateTimer(IntPtr wParam)
+ {
+ IntPtr timerId = (IntPtr)s_randomTimerId.Next();
+ IntPtr res = Interop.User32.SetTimer(_windowHandle, timerId, (int)wParam, IntPtr.Zero);
+ return (res == IntPtr.Zero ? IntPtr.Zero : timerId);
+ }
+
+ /// <devdoc>
+ /// Handler that raises the DisplaySettings changing event
+ /// </devdoc>
+ private void OnDisplaySettingsChanging()
+ {
+ RaiseEvent(s_onDisplaySettingsChangingEvent, this, EventArgs.Empty);
+ }
+
+ /// <devdoc>
+ /// Handler that raises the DisplaySettings changed event
+ /// </devdoc>
+ private void OnDisplaySettingsChanged()
+ {
+ RaiseEvent(s_onDisplaySettingsChangedEvent, this, EventArgs.Empty);
+ }
+
+ /// <devdoc>
+ /// Handler for any event that fires a standard EventHandler delegate.
+ /// </devdoc>
+ private void OnGenericEvent(object eventKey)
+ {
+ RaiseEvent(eventKey, this, EventArgs.Empty);
+ }
+
+ private void OnShutdown(object eventKey)
+ {
+ RaiseEvent(false, eventKey, this, EventArgs.Empty);
+ }
+
+ /// <devdoc>
+ /// Callback that handles the KillTimer
+ /// user message.
+ /// </devdoc>
+ private bool OnKillTimer(IntPtr wParam)
+ {
+ bool res = Interop.User32.KillTimer(_windowHandle, wParam);
+ return res;
+ }
+
+ /// <devdoc>
+ /// Handler for WM_POWERBROADCAST.
+ /// </devdoc>
+ private void OnPowerModeChanged(IntPtr wParam)
+ {
+ PowerModes mode;
+
+ switch ((int)wParam)
+ {
+ case Interop.User32.PBT_APMSUSPEND:
+ case Interop.User32.PBT_APMSTANDBY:
+ mode = PowerModes.Suspend;
+ break;
+
+ case Interop.User32.PBT_APMRESUMECRITICAL:
+ case Interop.User32.PBT_APMRESUMESUSPEND:
+ case Interop.User32.PBT_APMRESUMESTANDBY:
+ mode = PowerModes.Resume;
+ break;
+
+ case Interop.User32.PBT_APMBATTERYLOW:
+ case Interop.User32.PBT_APMPOWERSTATUSCHANGE:
+ case Interop.User32.PBT_APMOEMEVENT:
+ mode = PowerModes.StatusChange;
+ break;
+
+ default:
+ return;
+ }
+
+ RaiseEvent(s_onPowerModeChangedEvent, this, new PowerModeChangedEventArgs(mode));
+ }
+
+ /// <devdoc>
+ /// Handler for WM_ENDSESSION.
+ /// </devdoc>
+ private void OnSessionEnded(IntPtr wParam, IntPtr lParam)
+ {
+ // wParam will be nonzero if the session is actually ending. If
+ // it was canceled then we do not want to raise the event.
+ if (wParam != (IntPtr)0)
+ {
+ SessionEndReasons reason = SessionEndReasons.SystemShutdown;
+
+ if (((unchecked((int)(long)lParam)) & Interop.User32.ENDSESSION_LOGOFF) != 0)
+ {
+ reason = SessionEndReasons.Logoff;
+ }
+
+ SessionEndedEventArgs endEvt = new SessionEndedEventArgs(reason);
+
+ RaiseEvent(s_onSessionEndedEvent, this, endEvt);
+ }
+ }
+
+ /// <devdoc>
+ /// Handler for WM_QUERYENDSESSION.
+ /// </devdoc>
+ private int OnSessionEnding(IntPtr lParam)
+ {
+ int endOk = 1;
+
+ SessionEndReasons reason = SessionEndReasons.SystemShutdown;
+
+ // Casting to (int) is bad if we're 64-bit; casting to (long) is ok whether we're 64- or 32-bit.
+ if ((((long)lParam) & Interop.User32.ENDSESSION_LOGOFF) != 0)
+ {
+ reason = SessionEndReasons.Logoff;
+ }
+
+ SessionEndingEventArgs endEvt = new SessionEndingEventArgs(reason);
+
+ RaiseEvent(s_onSessionEndingEvent, this, endEvt);
+ endOk = (endEvt.Cancel ? 0 : 1);
+
+ return endOk;
+ }
+
+ private void OnSessionSwitch(int wParam)
+ {
+ SessionSwitchEventArgs switchEventArgs = new SessionSwitchEventArgs((SessionSwitchReason)wParam);
+
+ RaiseEvent(s_onSessionSwitchEvent, this, switchEventArgs);
+ }
+
+ /// <devdoc>
+ /// Handler for WM_THEMECHANGED
+ /// Whidbey note: Before Whidbey, we used to fire UserPreferenceChanged with category
+ /// set to Window. In Whidbey, we support visual styles and need a new category Theme
+ /// since Window is too general. We fire UserPreferenceChanged with this category, but
+ /// for backward compat, we also fire it with category set to Window.
+ /// </devdoc>
+ private void OnThemeChanged()
+ {
+ // we need to fire a changing event handler for Themes.
+ // note that it needs to be documented that accessing theme information during the changing event is forbidden.
+ RaiseEvent(s_onUserPreferenceChangingEvent, this, new UserPreferenceChangingEventArgs(UserPreferenceCategory.VisualStyle));
+
+ UserPreferenceCategory pref = UserPreferenceCategory.Window;
+
+ RaiseEvent(s_onUserPreferenceChangedEvent, this, new UserPreferenceChangedEventArgs(pref));
+
+ pref = UserPreferenceCategory.VisualStyle;
+
+ RaiseEvent(s_onUserPreferenceChangedEvent, this, new UserPreferenceChangedEventArgs(pref));
+ }
+
+ /// <devdoc>
+ /// Handler for WM_SETTINGCHANGE and WM_SYSCOLORCHANGE.
+ /// </devdoc>
+ private void OnUserPreferenceChanged(int msg, IntPtr wParam, IntPtr lParam)
+ {
+ UserPreferenceCategory pref = GetUserPreferenceCategory(msg, wParam, lParam);
+
+ RaiseEvent(s_onUserPreferenceChangedEvent, this, new UserPreferenceChangedEventArgs(pref));
+ }
+
+ private void OnUserPreferenceChanging(int msg, IntPtr wParam, IntPtr lParam)
+ {
+ UserPreferenceCategory pref = GetUserPreferenceCategory(msg, wParam, lParam);
+
+ RaiseEvent(s_onUserPreferenceChangingEvent, this, new UserPreferenceChangingEventArgs(pref));
+ }
+
+ /// <devdoc>
+ /// Handler for WM_TIMER.
+ /// </devdoc>
+ private void OnTimerElapsed(IntPtr wParam)
+ {
+ RaiseEvent(s_onTimerElapsedEvent, this, new TimerElapsedEventArgs(wParam));
+ }
+
+ private static void RaiseEvent(object key, params object[] args)
+ {
+ RaiseEvent(true, key, args);
+ }
+
+ [SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")]
+ [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
+ private static void RaiseEvent(bool checkFinalization, object key, params object[] args)
+ {
+ // If the AppDomain's unloading, we shouldn't fire SystemEvents other than Shutdown.
+ if (checkFinalization && AppDomain.CurrentDomain.IsFinalizingForUnload())
+ {
+ return;
+ }
+
+ SystemEventInvokeInfo[] invokeItemArray = null;
+
+ lock (s_eventLockObject)
+ {
+ if (s_handlers != null && s_handlers.ContainsKey(key))
+ {
+ List<SystemEventInvokeInfo> invokeItems = s_handlers[key];
+
+ // clone the list so we don't have this type locked and cause
+ // a deadlock if someone tries to modify handlers during an invoke.
+ if (invokeItems != null)
+ {
+ invokeItemArray = invokeItems.ToArray();
+ }
+ }
+ }
+
+ if (invokeItemArray != null)
+ {
+ for (int i = 0; i < invokeItemArray.Length; i++)
+ {
+ try
+ {
+ SystemEventInvokeInfo info = invokeItemArray[i];
+ info.Invoke(checkFinalization, args);
+ invokeItemArray[i] = null; // clear it if it's valid
+ }
+ catch (Exception)
+ {
+ // Eat exceptions (Everett compat)
+ }
+ }
+
+ // clean out any that are dead.
+ lock (s_eventLockObject)
+ {
+ List<SystemEventInvokeInfo> invokeItems = null;
+
+ for (int i = 0; i < invokeItemArray.Length; i++)
+ {
+ SystemEventInvokeInfo info = invokeItemArray[i];
+ if (info != null)
+ {
+ if (invokeItems == null)
+ {
+ if (!s_handlers.TryGetValue(key, out invokeItems))
+ {
+ // weird. just to be safe.
+ return;
+ }
+ }
+
+ invokeItems.Remove(info);
+ }
+ }
+ }
+ }
+ }
+
+ private static void RemoveEventHandler(object key, Delegate value)
+ {
+ lock (s_eventLockObject)
+ {
+ if (s_handlers != null && s_handlers.ContainsKey(key))
+ {
+ List<SystemEventInvokeInfo> invokeItems = (List<SystemEventInvokeInfo>)s_handlers[key];
+
+ invokeItems.Remove(new SystemEventInvokeInfo(value));
+ }
+ }
+ }
+
+ private static void Shutdown()
+ {
+ if (s_systemEvents != null && s_systemEvents._windowHandle != IntPtr.Zero)
+ {
+ lock (s_procLockObject)
+ {
+ if (s_systemEvents != null)
+ {
+ // If we are using system events from another thread, request that it terminate
+ if (s_windowThread != null)
+ {
+ s_eventThreadTerminated = new ManualResetEvent(false);
+
+#if DEBUG
+ int pid;
+ int thread = Interop.User32.GetWindowThreadProcessId(new HandleRef(s_systemEvents, s_systemEvents._windowHandle), out pid);
+ Debug.Assert(thread != Interop.Kernel32.GetCurrentThreadId(), "Don't call Shutdown on the system events thread");
+#endif
+ Interop.User32.PostMessageW(new HandleRef(s_systemEvents, s_systemEvents._windowHandle), Interop.User32.WM_QUIT, IntPtr.Zero, IntPtr.Zero);
+
+ s_eventThreadTerminated.WaitOne();
+ s_windowThread.Join(); // avoids an AppDomainUnloaded exception on our background thread.
+ }
+ else
+ {
+ s_systemEvents.Dispose();
+ s_systemEvents = null;
+ }
+ }
+ }
+ }
+ }
+
+ [PrePrepareMethod]
+ private static void Shutdown(object sender, EventArgs e)
+ {
+ Shutdown();
+ }
+
+ /// <devdoc>
+ /// A standard Win32 window proc for our broadcast window.
+ /// </devdoc>
+ [SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")]
+ [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
+ private IntPtr WindowProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam)
+ {
+ switch (msg)
+ {
+ case Interop.User32.WM_SETTINGCHANGE:
+ string newString;
+ IntPtr newStringPtr = lParam;
+ if (lParam != IntPtr.Zero)
+ {
+ newString = Marshal.PtrToStringUni(lParam);
+ if (newString != null)
+ {
+ newStringPtr = Marshal.StringToHGlobalUni(newString);
+ }
+ }
+ Interop.User32.PostMessageW(_windowHandle, Interop.User32.WM_REFLECT + msg, wParam, newStringPtr);
+ break;
+ case Interop.User32.WM_WTSSESSION_CHANGE:
+ OnSessionSwitch((int)wParam);
+ break;
+ case Interop.User32.WM_SYSCOLORCHANGE:
+ case Interop.User32.WM_COMPACTING:
+ case Interop.User32.WM_DISPLAYCHANGE:
+ case Interop.User32.WM_FONTCHANGE:
+ case Interop.User32.WM_PALETTECHANGED:
+ case Interop.User32.WM_TIMECHANGE:
+ case Interop.User32.WM_TIMER:
+ case Interop.User32.WM_THEMECHANGED:
+ Interop.User32.PostMessageW(_windowHandle, Interop.User32.WM_REFLECT + msg, wParam, lParam);
+ break;
+
+ case Interop.User32.WM_CREATETIMER:
+ return OnCreateTimer(wParam);
+
+ case Interop.User32.WM_KILLTIMER:
+ return (IntPtr)(OnKillTimer(wParam) ? 1 : 0);
+
+ case Interop.User32.WM_REFLECT + Interop.User32.WM_SETTINGCHANGE:
+ try
+ {
+ OnUserPreferenceChanging(msg - Interop.User32.WM_REFLECT, wParam, lParam);
+ OnUserPreferenceChanged(msg - Interop.User32.WM_REFLECT, wParam, lParam);
+ }
+ finally
+ {
+ try
+ {
+ if (lParam != IntPtr.Zero)
+ {
+ Marshal.FreeHGlobal(lParam);
+ }
+ }
+ catch (Exception e)
+ {
+ Debug.Assert(false, "Exception occurred while freeing memory: " + e.ToString());
+ }
+ }
+ break;
+
+ case Interop.User32.WM_REFLECT + Interop.User32.WM_SYSCOLORCHANGE:
+ OnUserPreferenceChanging(msg - Interop.User32.WM_REFLECT, wParam, lParam);
+ OnUserPreferenceChanged(msg - Interop.User32.WM_REFLECT, wParam, lParam);
+ break;
+
+ case Interop.User32.WM_REFLECT + Interop.User32.WM_THEMECHANGED:
+ OnThemeChanged();
+ break;
+
+ case Interop.User32.WM_QUERYENDSESSION:
+ return (IntPtr)OnSessionEnding(lParam);
+
+ case Interop.User32.WM_ENDSESSION:
+ OnSessionEnded(wParam, lParam);
+ break;
+
+ case Interop.User32.WM_POWERBROADCAST:
+ OnPowerModeChanged(wParam);
+ break;
+
+ // WM_HIBERNATE on WinCE
+ case Interop.User32.WM_REFLECT + Interop.User32.WM_COMPACTING:
+ OnGenericEvent(s_onLowMemoryEvent);
+ break;
+
+ case Interop.User32.WM_REFLECT + Interop.User32.WM_DISPLAYCHANGE:
+ OnDisplaySettingsChanging();
+ OnDisplaySettingsChanged();
+ break;
+
+ case Interop.User32.WM_REFLECT + Interop.User32.WM_FONTCHANGE:
+ OnGenericEvent(s_onInstalledFontsChangedEvent);
+ break;
+
+ case Interop.User32.WM_REFLECT + Interop.User32.WM_PALETTECHANGED:
+ OnGenericEvent(s_onPaletteChangedEvent);
+ break;
+
+ case Interop.User32.WM_REFLECT + Interop.User32.WM_TIMECHANGE:
+ OnGenericEvent(s_onTimeChangedEvent);
+ break;
+
+ case Interop.User32.WM_REFLECT + Interop.User32.WM_TIMER:
+ OnTimerElapsed(wParam);
+ break;
+
+ default:
+ // If we received a thread execute message, then execute it.
+ if (msg == s_threadCallbackMessage && msg != 0)
+ {
+ InvokeMarshaledCallbacks();
+ return IntPtr.Zero;
+ }
+ break;
+ }
+
+ return Interop.User32.DefWindowProcW(hWnd, msg, wParam, lParam);
+ }
+
+ /// <devdoc>
+ /// This is the method that runs our window thread. This method
+ /// creates a window and spins up a message loop. The window
+ /// is made visible with a size of 0, 0, so that it will trap
+ /// global broadcast messages.
+ /// </devdoc>
+ [SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")]
+ [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
+ private void WindowThreadProc()
+ {
+ try
+ {
+ Initialize();
+ s_eventWindowReady.Set();
+
+ if (_windowHandle != IntPtr.Zero)
+ {
+ Interop.User32.MSG msg = new Interop.User32.MSG();
+
+ bool keepRunning = true;
+
+ // Blocking on a GetMessage() call prevents the EE from being able to unwind
+ // this thread properly (e.g. during AppDomainUnload). So, we use PeekMessage()
+ // and sleep so we always block in managed code instead.
+ while (keepRunning)
+ {
+ int ret = Interop.User32.MsgWaitForMultipleObjectsEx(0, IntPtr.Zero, 100, Interop.User32.QS_ALLINPUT, Interop.User32.MWMO_INPUTAVAILABLE);
+
+ if (ret == Interop.User32.WAIT_TIMEOUT)
+ {
+ Thread.Sleep(1);
+ }
+ else
+ {
+ while (Interop.User32.PeekMessageW(ref msg, IntPtr.Zero, 0, 0, Interop.User32.PM_REMOVE))
+ {
+ if (msg.message == Interop.User32.WM_QUIT)
+ {
+ keepRunning = false;
+ break;
+ }
+
+ Interop.User32.TranslateMessage(ref msg);
+ Interop.User32.DispatchMessageW(ref msg);
+ }
+ }
+ }
+ }
+
+ OnShutdown(s_onEventsThreadShutdownEvent);
+ }
+ catch (Exception e)
+ {
+ // In case something very very wrong happend during the creation action.
+ // This will unblock the calling thread.
+ s_eventWindowReady.Set();
+
+ if (!((e is ThreadInterruptedException) || (e is ThreadAbortException)))
+ {
+ Debug.Fail("Unexpected thread exception in system events window thread proc", e.ToString());
+ }
+ }
+
+ Dispose();
+ if (s_eventThreadTerminated != null)
+ {
+ s_eventThreadTerminated.Set();
+ }
+ }
+
+ // A class that helps fire events on the right thread.
+ private class SystemEventInvokeInfo
+ {
+ private SynchronizationContext _syncContext; // the context that we'll use to fire against.
+ private Delegate _delegate; // the delegate we'll fire. This is a weak ref so we don't hold object in memory.
+ public SystemEventInvokeInfo(Delegate d)
+ {
+ _delegate = d;
+ _syncContext = AsyncOperationManager.SynchronizationContext;
+ }
+
+ // fire the given event with the given params.
+ public void Invoke(bool checkFinalization, params object[] args)
+ {
+ try
+ {
+ // If we didn't get call back invoke directly.
+ if (_syncContext == null)
+ {
+ InvokeCallback(args);
+ }
+ else
+ {
+ // otherwise tell the context to do it for us.
+ _syncContext.Send(new SendOrPostCallback(InvokeCallback), args);
+ }
+ }
+ catch (InvalidAsynchronousStateException)
+ {
+ // if the synch context is invalid -- do the invoke directly for app compat.
+ // If the app's shutting down, don't fire the event (unless it's shutdown).
+ if (!checkFinalization || !AppDomain.CurrentDomain.IsFinalizingForUnload())
+ {
+ InvokeCallback(args);
+ }
+ }
+ }
+
+ // our delegate method that the SyncContext will call on.
+ private void InvokeCallback(object arg)
+ {
+ _delegate.DynamicInvoke((object[])arg);
+ }
+
+ public override bool Equals(object other)
+ {
+ SystemEventInvokeInfo otherInvoke = other as SystemEventInvokeInfo;
+
+ if (otherInvoke == null)
+ {
+ return false;
+ }
+ return otherInvoke._delegate.Equals(_delegate);
+ }
+
+ public override int GetHashCode()
+ {
+ return base.GetHashCode();
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/TimerElapsedEventArgs.cs b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/TimerElapsedEventArgs.cs
new file mode 100644
index 0000000000..3065057173
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/TimerElapsedEventArgs.cs
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace Microsoft.Win32
+{
+ /// <devdoc>
+ /// <para>Provides data for the <see cref='Microsoft.Win32.SystemEvents.TimerElapsed'/> event.</para>
+ /// </devdoc>
+ public class TimerElapsedEventArgs : EventArgs
+ {
+ private readonly IntPtr _timerId;
+
+ /// <devdoc>
+ /// <para>Initializes a new instance of the <see cref='Microsoft.Win32.TimerElapsedEventArgs'/> class.</para>
+ /// </devdoc>
+ public TimerElapsedEventArgs(IntPtr timerId)
+ {
+ _timerId = timerId;
+ }
+
+ /// <devdoc>
+ /// <para>Gets the ID number for the timer.</para>
+ /// </devdoc>
+ public IntPtr TimerId
+ {
+ get
+ {
+ return _timerId;
+ }
+ }
+ }
+}
+
diff --git a/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/TimerElapsedEventHandler.cs b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/TimerElapsedEventHandler.cs
new file mode 100644
index 0000000000..1d3f248ce9
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/TimerElapsedEventHandler.cs
@@ -0,0 +1,12 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.Win32
+{
+ /// <devdoc>
+ /// <para>Represents the method that will handle the <see cref='Microsoft.Win32.SystemEvents.TimerElapsed'/> event.</para>
+ /// </devdoc>
+ public delegate void TimerElapsedEventHandler(object sender, TimerElapsedEventArgs e);
+}
+
diff --git a/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/UserPreferenceCategories.cs b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/UserPreferenceCategories.cs
new file mode 100644
index 0000000000..02f6cc4b31
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/UserPreferenceCategories.cs
@@ -0,0 +1,110 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.Win32
+{
+ /// <devdoc>
+ /// <para> Identifies areas of user preferences that
+ /// have changed.</para>
+ /// </devdoc>
+ public enum UserPreferenceCategory
+ {
+ /// <devdoc>
+ /// <para> Specifies user
+ /// preferences associated with accessibility
+ /// of the system for users with disabilities.</para>
+ /// </devdoc>
+ Accessibility = 1,
+
+ /// <devdoc>
+ /// <para> Specifies user preferences
+ /// associated with system colors, such as the
+ /// default color of windows or menus.</para>
+ /// </devdoc>
+ Color = 2,
+
+ /// <devdoc>
+ /// <para> Specifies user
+ /// preferences associated with the system desktop.
+ /// This may reflect a change in desktop background
+ /// images, or desktop layout.</para>
+ /// </devdoc>
+ Desktop = 3,
+
+ /// <devdoc>
+ /// <para> Specifies user preferences
+ /// that are not associated with any other category.</para>
+ /// </devdoc>
+ General = 4,
+
+ /// <devdoc>
+ /// <para> Specifies
+ /// user preferences for icon settings. This includes
+ /// icon height and spacing.</para>
+ /// </devdoc>
+ Icon = 5,
+
+ /// <devdoc>
+ /// <para>
+ /// Specifies user preferences for keyboard settings,
+ /// such as the keyboard repeat rate.</para>
+ /// </devdoc>
+ Keyboard = 6,
+
+ /// <devdoc>
+ /// <para> Specifies user preferences
+ /// for menu settings, such as menu delays and
+ /// text alignment.</para>
+ /// </devdoc>
+ Menu = 7,
+
+ /// <devdoc>
+ /// <para> Specifies user preferences
+ /// for mouse settings, such as double click
+ /// time and mouse sensitivity.</para>
+ /// </devdoc>
+ Mouse = 8,
+
+ /// <devdoc>
+ /// <para> Specifies user preferences
+ /// for policy settings, such as user rights and
+ /// access levels.</para>
+ /// </devdoc>
+ Policy = 9,
+
+ /// <devdoc>
+ /// <para> Specifies user preferences
+ /// for system power settings. An example of a
+ /// power setting is the time required for the
+ /// system to automatically enter low power mode.</para>
+ /// </devdoc>
+ Power = 10,
+
+ /// <devdoc>
+ /// <para> Specifies user preferences
+ /// associated with the screensaver.</para>
+ /// </devdoc>
+ Screensaver = 11,
+
+ /// <devdoc>
+ /// <para> Specifies user preferences
+ /// associated with the dimensions and characteristics
+ /// of windows on the system.</para>
+ /// </devdoc>
+ Window = 12,
+
+ /// <devdoc>
+ /// <para> Specifies user preferences
+ /// associated with the locale of the system.</para>
+ /// </devdoc>
+ Locale = 13,
+
+ /// <devdoc>
+ /// <para> Specifies user preferences
+ /// associated with the visual style.</para>
+ /// </devdoc>
+ VisualStyle = 14,
+ }
+}
+
diff --git a/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/UserPreferenceChangedEventArgs.cs b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/UserPreferenceChangedEventArgs.cs
new file mode 100644
index 0000000000..9e265f231c
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/UserPreferenceChangedEventArgs.cs
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace Microsoft.Win32
+{
+ /// <devdoc>
+ /// <para>Provides data for the <see cref='Microsoft.Win32.SystemEvents.UserPreferenceChanged'/> event.</para>
+ /// </devdoc>
+ public class UserPreferenceChangedEventArgs : EventArgs
+ {
+ private readonly UserPreferenceCategory _category;
+
+ /// <devdoc>
+ /// <para>Initializes a new instance of the <see cref='Microsoft.Win32.UserPreferenceChangedEventArgs'/> class.</para>
+ /// </devdoc>
+ public UserPreferenceChangedEventArgs(UserPreferenceCategory category)
+ {
+ _category = category;
+ }
+
+ /// <devdoc>
+ /// <para>Gets the category of user preferences that has changed.</para>
+ /// </devdoc>
+ public UserPreferenceCategory Category
+ {
+ get
+ {
+ return _category;
+ }
+ }
+ }
+}
+
diff --git a/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/UserPreferenceChangedEventHandler.cs b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/UserPreferenceChangedEventHandler.cs
new file mode 100644
index 0000000000..f46be3bd02
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/UserPreferenceChangedEventHandler.cs
@@ -0,0 +1,11 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.Win32
+{
+ /// <devdoc>
+ /// <para>Represents the method that will handle the <see cref='Microsoft.Win32.SystemEvents.UserPreferenceChanged'/> event.</para>
+ /// </devdoc>
+ public delegate void UserPreferenceChangedEventHandler(object sender, UserPreferenceChangedEventArgs e);
+}
diff --git a/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/UserPreferenceChangingEventArgs.cs b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/UserPreferenceChangingEventArgs.cs
new file mode 100644
index 0000000000..ecdc58f90a
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/UserPreferenceChangingEventArgs.cs
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace Microsoft.Win32
+{
+ /// <devdoc>
+ /// <para>Provides data for the <see cref='Microsoft.Win32.SystemEvents.UserPreferenceChanging'/> event.</para>
+ /// </devdoc>
+ public class UserPreferenceChangingEventArgs : EventArgs
+ {
+ private readonly UserPreferenceCategory _category;
+
+ /// <devdoc>
+ /// <para>Initializes a new instance of the <see cref='Microsoft.Win32.UserPreferenceChangingEventArgs'/> class.</para>
+ /// </devdoc>
+ public UserPreferenceChangingEventArgs(UserPreferenceCategory category)
+ {
+ _category = category;
+ }
+
+ /// <devdoc>
+ /// <para>Gets the category of user preferences that has Changing.</para>
+ /// </devdoc>
+ public UserPreferenceCategory Category
+ {
+ get
+ {
+ return _category;
+ }
+ }
+ }
+}
+
diff --git a/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/UserPreferenceChangingEventHandler.cs b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/UserPreferenceChangingEventHandler.cs
new file mode 100644
index 0000000000..a36b08e117
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/UserPreferenceChangingEventHandler.cs
@@ -0,0 +1,11 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.Win32
+{
+ /// <devdoc>
+ /// <para>Represents the method that will handle the <see cref='Microsoft.Win32.SystemEvents.UserPreferenceChanging'/> event.</para>
+ /// </devdoc>
+ public delegate void UserPreferenceChangingEventHandler(object sender, UserPreferenceChangingEventArgs e);
+}
diff --git a/src/Microsoft.Win32.SystemEvents/src/PinvokeAnalyzerExceptionList.analyzerdata b/src/Microsoft.Win32.SystemEvents/src/PinvokeAnalyzerExceptionList.analyzerdata
new file mode 100644
index 0000000000..cfa190d52b
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/src/PinvokeAnalyzerExceptionList.analyzerdata
@@ -0,0 +1,27 @@
+kernel32.dll!GetModuleHandleW
+kernel32.dll!LoadLibrary
+user32.dll!CreateWindowExW
+user32.dll!DefWindowProcW
+user32.dll!DestroyWindow
+user32.dll!DispatchMessageW
+user32.dll!GetClassInfoW
+user32.dll!GetProcessWindowStation
+user32.dll!GetUserObjectInformationW
+user32.dll!GetWindowThreadProcessId
+user32.dll!IsWindow
+user32.dll!KillTimer
+user32.dll!MsgWaitForMultipleObjectsEx
+user32.dll!PeekMessageW
+user32.dll!PostMessageW
+user32.dll!RegisterClassW
+user32.dll!RegisterWindowMessageW
+user32.dll!SendMessageW
+user32.dll!SetClassLongPtrW
+user32.dll!SetClassLongW
+user32.dll!SetTimer
+user32.dll!SetWindowLongPtrW
+user32.dll!SetWindowLongW
+user32.dll!TranslateMessage
+user32.dll!UnregisterClassW
+wtsapi32.dll!WTSRegisterSessionNotification
+wtsapi32.dll!WTSUnRegisterSessionNotification
diff --git a/src/System.Globalization.Extensions/src/Resources/Strings.resx b/src/Microsoft.Win32.SystemEvents/src/Resources/Strings.resx
index 9891a3c007..99fcf24d20 100644
--- a/src/System.Globalization.Extensions/src/Resources/Strings.resx
+++ b/src/Microsoft.Win32.SystemEvents/src/Resources/Strings.resx
@@ -117,7 +117,25 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
- <data name="Argument_InvalidFlag" xml:space="preserve">
- <value>Value of flags is invalid.</value>
+ <data name="ErrorCreateSystemEvents" xml:space="preserve">
+ <value>Failed to create system events window thread.</value>
+ </data>
+ <data name="ErrorCreateTimer" xml:space="preserve">
+ <value>Cannot create timer.</value>
+ </data>
+ <data name="ErrorGetTempPath" xml:space="preserve">
+ <value>Cannot get temporary file name</value>
+ </data>
+ <data name="ErrorKillTimer" xml:space="preserve">
+ <value>Cannot end timer.</value>
+ </data>
+ <data name="ErrorSystemEventsNotSupported" xml:space="preserve">
+ <value>System event notifications are not supported under the current context. Server processes, for example, may not support global system event notifications.</value>
+ </data>
+ <data name="InvalidLowBoundArgument" xml:space="preserve">
+ <value>'{1}' is not a valid value for '{0}'. '{0}' must be greater than {2}.</value>
+ </data>
+ <data name="PlatformNotSupported_SystemEvents" xml:space="preserve">
+ <value>SystemEvents is not supported on this platform.</value>
</data>
</root> \ No newline at end of file
diff --git a/src/Microsoft.Win32.SystemEvents/tests/Configurations.props b/src/Microsoft.Win32.SystemEvents/tests/Configurations.props
new file mode 100644
index 0000000000..0390988544
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/tests/Configurations.props
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <BuildConfigurations>
+ netcoreapp-Windows_NT;
+ netfx-Windows_NT;
+ </BuildConfigurations>
+ </PropertyGroup>
+</Project>
diff --git a/src/Microsoft.Win32.SystemEvents/tests/GenericEventTests.cs b/src/Microsoft.Win32.SystemEvents/tests/GenericEventTests.cs
new file mode 100644
index 0000000000..8a5098b196
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/tests/GenericEventTests.cs
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Threading;
+using Xunit;
+using static Interop;
+
+namespace Microsoft.Win32.SystemEventsTests
+{
+ public abstract class GenericEventTests : SystemEventsTest
+ {
+ protected abstract int MessageId { get; }
+
+ protected abstract event EventHandler Event;
+
+ private void SendMessage()
+ {
+ SendMessage(MessageId, IntPtr.Zero, IntPtr.Zero);
+ }
+ private void SendReflectedMessage()
+ {
+ SendMessage(User32.WM_REFLECT + MessageId, IntPtr.Zero, IntPtr.Zero);
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))]
+ public void SignalsEventsAsynchronouslyOnMessage()
+ {
+ var signal = new AutoResetEvent(false);
+ EventHandler signaledHandler = (o, e) => signal.Set();
+
+ Event += signaledHandler;
+
+ try
+ {
+ SendMessage();
+ Assert.True(signal.WaitOne(PostMessageWait));
+ }
+ finally
+ {
+ Event -= signaledHandler;
+ signal.Dispose();
+ }
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))]
+ public void SignalsEventsSynchronouslyOnReflectedMessage()
+ {
+ bool signal = false;
+ EventHandler signaledHandler = (o, e) => signal = true;
+
+ Event += signaledHandler;
+
+ try
+ {
+ SendReflectedMessage();
+ Assert.True(signal);
+ }
+ finally
+ {
+ Event -= signaledHandler;
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.Win32.SystemEvents/tests/Microsoft.Win32.SystemEvents.Tests.csproj b/src/Microsoft.Win32.SystemEvents/tests/Microsoft.Win32.SystemEvents.Tests.csproj
new file mode 100644
index 0000000000..8a8cb9520a
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/tests/Microsoft.Win32.SystemEvents.Tests.csproj
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <ProjectGuid>{8B21F7AD-928E-474C-875A-83D753BB8A28}</ProjectGuid>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Release|AnyCPU'" />
+ <ItemGroup>
+ <Compile Include="$(CommonPath)\Interop\Windows\Interop.Libraries.cs">
+ <Link>Common\Interop\Windows\Interop.Libraries.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.Constants.cs">
+ <Link>Common\Interop\Windows\user32\Interop.Constants.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.FindWindow.cs">
+ <Link>Common\Interop\Windows\user32\Interop.FindWindow.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\user32\Interop.SendMessage.cs">
+ <Link>Common\Interop\Windows\user32\Interop.SendMessage.cs</Link>
+ </Compile>
+ <Compile Include="GenericEventTests.cs" />
+ <Compile Include="SystemEvents.InvokeOnEventsThread.cs" />
+ <Compile Include="SystemEvents.UserPreference.cs" />
+ <Compile Include="SystemEvents.InstalledFontsChanged.cs" />
+ <Compile Include="SystemEvents.LowMemory.cs" />
+ <Compile Include="SystemEvents.PaletteChanged.cs" />
+ <Compile Include="SystemEvents.SessionEnded.cs" />
+ <Compile Include="SystemEvents.SessionEnding.cs" />
+ <Compile Include="SystemEvents.SessionSwitch.cs" />
+ <Compile Include="SystemEvents.PowerMode.cs" />
+ <Compile Include="SystemEvents.TimeChanged.cs" />
+ <Compile Include="SystemEventsTest.cs" />
+ <Compile Include="SystemEvents.DisplaySettings.cs" />
+ <Compile Include="SystemEvents.CreateTimer.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project> \ No newline at end of file
diff --git a/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.CreateTimer.cs b/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.CreateTimer.cs
new file mode 100644
index 0000000000..75b5f69f6c
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.CreateTimer.cs
@@ -0,0 +1,170 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Threading;
+using Xunit;
+
+namespace Microsoft.Win32.SystemEventsTests
+{
+ public class CreateTimerTests
+ {
+ /// <summary>
+ /// Minimum permitted interval
+ /// </summary>
+ public const int TimerInterval = 10;
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))]
+ public void CreateTimerInvalidInterval()
+ {
+ Assert.Throws<ArgumentException>(() => SystemEvents.CreateTimer(0));
+ Assert.Throws<ArgumentException>(() => SystemEvents.CreateTimer(-1));
+ Assert.Throws<ArgumentException>(() => SystemEvents.CreateTimer(int.MinValue));
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))]
+ public void TimerElapsedSignaled()
+ {
+ var elapsed = new AutoResetEvent(false);
+
+ object elapsedSender = null;
+ IntPtr timer = IntPtr.Zero;
+
+ TimerElapsedEventHandler handler = (sender, args) =>
+ {
+ if (args?.TimerId == timer)
+ {
+ elapsedSender = sender;
+ elapsed.Set();
+ }
+ };
+
+ SystemEvents.TimerElapsed += handler;
+ try
+ {
+ if (PlatformDetection.IsFullFramework)
+ {
+ // desktop has a bug where it will allow EnsureSystemEvents to proceed without actually creating the HWND
+ SystemEventsTest.WaitForSystemEventsWindow();
+ }
+
+ timer = SystemEvents.CreateTimer(TimerInterval);
+
+ Assert.True(elapsed.WaitOne(TimerInterval * SystemEventsTest.ExpectedEventMultiplier));
+ Assert.IsType<SystemEvents>(elapsedSender);
+
+ // Timer should fire more than once
+ Assert.True(elapsed.WaitOne(TimerInterval * SystemEventsTest.ExpectedEventMultiplier));
+
+ SystemEvents.KillTimer(timer);
+ elapsed.Reset();
+
+ // Timer should not fire once killed
+ Assert.False(elapsed.WaitOne(TimerInterval * SystemEventsTest.UnexpectedEventMultiplier));
+ }
+ finally
+ {
+ SystemEvents.TimerElapsed -= handler;
+ elapsed.Dispose();
+ }
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))]
+ public void ConcurrentTimers()
+ {
+ const int NumConcurrentTimers = 10;
+ var timersSignalled = new Dictionary<IntPtr, bool>();
+ int numSignaled = 0;
+ var elapsed = new AutoResetEvent(false);
+
+ TimerElapsedEventHandler handler = (sender, args) =>
+ {
+ bool signaled = false;
+ if (timersSignalled.TryGetValue(args.TimerId, out signaled) && !signaled)
+ {
+ timersSignalled[args.TimerId] = true;
+
+ if (Interlocked.Increment(ref numSignaled) == NumConcurrentTimers)
+ {
+ elapsed.Set();
+ }
+ }
+ };
+
+ SystemEvents.TimerElapsed += handler;
+ try
+ {
+ if (PlatformDetection.IsFullFramework)
+ {
+ // desktop has a bug where it will allow EnsureSystemEvents to proceed without actually creating the HWND
+ SystemEventsTest.WaitForSystemEventsWindow();
+ }
+
+ for (int i = 0; i < NumConcurrentTimers; i++)
+ {
+ timersSignalled[SystemEvents.CreateTimer(TimerInterval)] = false;
+ }
+
+ Assert.True(elapsed.WaitOne(TimerInterval * SystemEventsTest.ExpectedEventMultiplier));
+
+ foreach (var timer in timersSignalled.Keys.ToArray())
+ {
+ Assert.True(timersSignalled[timer]);
+ SystemEvents.KillTimer(timer);
+ }
+ }
+ finally
+ {
+ SystemEvents.TimerElapsed -= handler;
+ elapsed.Dispose();
+ }
+ }
+
+ [OuterLoop]
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))]
+ [InlineData(500)] // .5s
+ [InlineData(1000)] // 1s
+ [InlineData(2000)] // 2s
+ [InlineData(10000)] // 10s
+ [InlineData(30000)] // 30s
+ public void TimerElapsedIsRoughlyEquivalentToInterval(int interval)
+ {
+ const double permittedProportionUnder = -0.1;
+ const double permittedProportionOver = 0.5;
+ var elapsed = new AutoResetEvent(false);
+ IntPtr timer = IntPtr.Zero;
+ var stopwatch = new Stopwatch();
+
+ TimerElapsedEventHandler handler = (sender, args) =>
+ {
+ if (args?.TimerId == timer)
+ {
+ stopwatch.Stop();
+ elapsed.Set();
+ }
+ };
+
+ SystemEvents.TimerElapsed += handler;
+ try
+ {
+ timer = SystemEvents.CreateTimer(interval);
+ stopwatch.Start();
+ Assert.True(elapsed.WaitOne(interval * SystemEventsTest.ExpectedEventMultiplier));
+
+ var proportionDifference = (double)(stopwatch.ElapsedMilliseconds - interval) / interval;
+ Assert.True(permittedProportionUnder < proportionDifference && proportionDifference < permittedProportionOver,
+ $"Timer should fire less than {permittedProportionUnder * 100.0}% before and less than {permittedProportionOver * 100.0}% after expected interval {interval}, actual: {stopwatch.ElapsedMilliseconds}, difference: {proportionDifference * 100.0}%");
+ }
+ finally
+ {
+ SystemEvents.TimerElapsed -= handler;
+ SystemEvents.KillTimer(timer);
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.DisplaySettings.cs b/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.DisplaySettings.cs
new file mode 100644
index 0000000000..1628a83f20
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.DisplaySettings.cs
@@ -0,0 +1,72 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Threading;
+using Xunit;
+using static Interop;
+
+namespace Microsoft.Win32.SystemEventsTests
+{
+ public class DisplaySettingsTests : SystemEventsTest
+ {
+ private void SendMessage()
+ {
+ SendMessage(User32.WM_DISPLAYCHANGE, IntPtr.Zero, IntPtr.Zero);
+ }
+ private void SendReflectedMessage()
+ {
+ SendMessage(User32.WM_REFLECT + User32.WM_DISPLAYCHANGE, IntPtr.Zero, IntPtr.Zero);
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))]
+ public void SignalsDisplayEventsAsynchronouslyOnDISPLAYCHANGE()
+ {
+ var changing = new AutoResetEvent(false);
+ var changed = new AutoResetEvent(false);
+ EventHandler changedHandler = (o, e) => changed.Set();
+ EventHandler changingHandler = (o, e) => changing.Set();
+
+ SystemEvents.DisplaySettingsChanged += changedHandler;
+ SystemEvents.DisplaySettingsChanging += changingHandler;
+
+ try
+ {
+ SendMessage();
+ Assert.True(changing.WaitOne(PostMessageWait));
+ Assert.True(changed.WaitOne(PostMessageWait));
+ }
+ finally
+ {
+ SystemEvents.DisplaySettingsChanged -= changedHandler;
+ SystemEvents.DisplaySettingsChanging -= changingHandler;
+ changing.Dispose();
+ changed.Dispose();
+ }
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))]
+ public void SignalsDisplayEventsSynchronouslyOnREFLECTDISPLAYCHANGE()
+ {
+ bool changing = false, changed = false;
+ EventHandler changedHandler = (o, e) => changed = true;
+ EventHandler changingHandler = (o, e) => changing = true;
+
+ SystemEvents.DisplaySettingsChanged += changedHandler;
+ SystemEvents.DisplaySettingsChanging += changingHandler;
+
+ try
+ {
+ SendReflectedMessage();
+ Assert.True(changing);
+ Assert.True(changed);
+ }
+ finally
+ {
+ SystemEvents.DisplaySettingsChanged -= changedHandler;
+ SystemEvents.DisplaySettingsChanging -= changingHandler;
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.InstalledFontsChanged.cs b/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.InstalledFontsChanged.cs
new file mode 100644
index 0000000000..8d5dd6801d
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.InstalledFontsChanged.cs
@@ -0,0 +1,26 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using static Interop;
+
+namespace Microsoft.Win32.SystemEventsTests
+{
+ public class InstalledFontsChangedTests : GenericEventTests
+ {
+ protected override int MessageId => User32.WM_FONTCHANGE;
+
+ protected override event EventHandler Event
+ {
+ add
+ {
+ SystemEvents.InstalledFontsChanged += value;
+ }
+ remove
+ {
+ SystemEvents.InstalledFontsChanged -= value;
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.InvokeOnEventsThread.cs b/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.InvokeOnEventsThread.cs
new file mode 100644
index 0000000000..9eb595e79a
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.InvokeOnEventsThread.cs
@@ -0,0 +1,57 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Threading;
+using Xunit;
+using static Interop;
+
+namespace Microsoft.Win32.SystemEventsTests
+{
+ public class InvokeOnEventsThreadTests : SystemEventsTest
+ {
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))]
+ public void InvokeOnEventsThreadRunsAsynchronously()
+ {
+ var invoked = new AutoResetEvent(false);
+ SystemEvents.InvokeOnEventsThread(new Action(() => invoked.Set()));
+ Assert.True(invoked.WaitOne(PostMessageWait));
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))]
+ public void InvokeOnEventsThreadRunsOnSameThreadAsOtherEvents()
+ {
+ int expectedThreadId = -1, actualThreadId = -1;
+ var invoked = new AutoResetEvent(false);
+ EventHandler handler = (sender, args) =>
+ {
+ expectedThreadId = Thread.CurrentThread.ManagedThreadId;
+ };
+
+ try
+ {
+ // force a TimeChanged event to get the event thread ID
+ SystemEvents.TimeChanged += handler;
+ SendMessage(User32.WM_REFLECT + User32.WM_TIMECHANGE, IntPtr.Zero, IntPtr.Zero);
+ Assert.NotEqual(-1, expectedThreadId);
+
+ SystemEvents.InvokeOnEventsThread(new Action(() =>
+ {
+ actualThreadId = Thread.CurrentThread.ManagedThreadId;
+ invoked.Set();
+ }));
+ Assert.True(invoked.WaitOne(PostMessageWait));
+ Assert.Equal(expectedThreadId, actualThreadId);
+ }
+ finally
+ {
+ SystemEvents.TimeChanged -= handler;
+ invoked.Dispose();
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.LowMemory.cs b/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.LowMemory.cs
new file mode 100644
index 0000000000..7cdb1e5770
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.LowMemory.cs
@@ -0,0 +1,28 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using static Interop;
+
+namespace Microsoft.Win32.SystemEventsTests
+{
+ public class LowMemoryTests : GenericEventTests
+ {
+ protected override int MessageId => User32.WM_COMPACTING;
+
+ protected override event EventHandler Event
+ {
+#pragma warning disable CS0618 // Type or member is obsolete
+ add
+ {
+ SystemEvents.LowMemory += value;
+ }
+ remove
+ {
+ SystemEvents.LowMemory -= value;
+ }
+#pragma warning restore CS0618 // Type or member is obsolete
+ }
+ }
+}
diff --git a/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.PaletteChanged.cs b/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.PaletteChanged.cs
new file mode 100644
index 0000000000..d28c713175
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.PaletteChanged.cs
@@ -0,0 +1,26 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using static Interop;
+
+namespace Microsoft.Win32.SystemEventsTests
+{
+ public class PaletteChangedTests : GenericEventTests
+ {
+ protected override int MessageId => User32.WM_PALETTECHANGED;
+
+ protected override event EventHandler Event
+ {
+ add
+ {
+ SystemEvents.PaletteChanged += value;
+ }
+ remove
+ {
+ SystemEvents.PaletteChanged -= value;
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.PowerMode.cs b/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.PowerMode.cs
new file mode 100644
index 0000000000..857310692d
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.PowerMode.cs
@@ -0,0 +1,80 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using Xunit;
+using static Interop;
+
+namespace Microsoft.Win32.SystemEventsTests
+{
+ public class PowerModeTests : SystemEventsTest
+ {
+ private void SendMessage(int pmEvent)
+ {
+ SendMessage(User32.WM_POWERBROADCAST, (IntPtr)pmEvent, IntPtr.Zero);
+ }
+
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))]
+ [InlineData(User32.PBT_APMBATTERYLOW, PowerModes.StatusChange)]
+ [InlineData(User32.PBT_APMOEMEVENT, PowerModes.StatusChange)]
+ [InlineData(User32.PBT_APMPOWERSTATUSCHANGE, PowerModes.StatusChange)]
+ [InlineData(User32.PBT_APMRESUMECRITICAL, PowerModes.Resume)]
+ [InlineData(User32.PBT_APMRESUMESUSPEND, PowerModes.Resume)]
+ [InlineData(User32.PBT_APMRESUMESTANDBY, PowerModes.Resume)]
+ [InlineData(User32.PBT_APMSUSPEND, PowerModes.Suspend)]
+ [InlineData(User32.PBT_APMSTANDBY, PowerModes.Suspend)]
+ public void SignalsPowerModeChanged(int pmEvent, PowerModes powerMode)
+ {
+ bool changed = false;
+ PowerModeChangedEventArgs args = null;
+ PowerModeChangedEventHandler changedHandler = (o, e) =>
+ {
+ changed = true;
+ args = e;
+ };
+
+ SystemEvents.PowerModeChanged += changedHandler;
+
+ try
+ {
+ SendMessage(pmEvent);
+ Assert.True(changed);
+ Assert.NotNull(args);
+ Assert.Equal(powerMode, args.Mode);
+ }
+ finally
+ {
+ SystemEvents.PowerModeChanged -= changedHandler;
+ }
+ }
+
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))]
+ [InlineData(User32.PBT_APMQUERYSTANDBY)]
+ [InlineData(User32.PBT_APMQUERYSTANDBYFAILED)]
+ [InlineData(User32.PBT_APMQUERYSUSPEND)]
+ [InlineData(User32.PBT_APMQUERYSUSPENDFAILED)]
+ [InlineData(int.MaxValue)]
+ [InlineData(-1)]
+ public void DoesNotSignalPowerModeChanged(int pmEvent)
+ {
+ bool changed = false;
+ PowerModeChangedEventHandler changedHandler = (o, e) =>
+ {
+ changed = true;
+ };
+
+ SystemEvents.PowerModeChanged += changedHandler;
+
+ try
+ {
+ SendMessage(pmEvent);
+ Assert.False(changed);
+ }
+ finally
+ {
+ SystemEvents.PowerModeChanged -= changedHandler;
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.SessionEnded.cs b/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.SessionEnded.cs
new file mode 100644
index 0000000000..5443f0a265
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.SessionEnded.cs
@@ -0,0 +1,74 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using Xunit;
+using static Interop;
+
+namespace Microsoft.Win32.SystemEventsTests
+{
+ public class SessionEndedTests : SystemEventsTest
+ {
+ private IntPtr SendMessage(bool ended, int lParam)
+ {
+ return SendMessage(User32.WM_ENDSESSION, ended ? (IntPtr)1 : (IntPtr)0, (IntPtr)lParam);
+ }
+
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))]
+ [InlineData(User32.ENDSESSION_LOGOFF, SessionEndReasons.Logoff)]
+ [InlineData(User32.ENDSESSION_LOGOFF | User32.ENDSESSION_CRITICAL, SessionEndReasons.Logoff)]
+ [InlineData(User32.ENDSESSION_LOGOFF | User32.ENDSESSION_CLOSEAPP, SessionEndReasons.Logoff)]
+ [InlineData(User32.ENDSESSION_LOGOFF | User32.ENDSESSION_CRITICAL | User32.ENDSESSION_CLOSEAPP, SessionEndReasons.Logoff)]
+ [InlineData(0, SessionEndReasons.SystemShutdown)]
+ [InlineData(User32.ENDSESSION_CRITICAL, SessionEndReasons.SystemShutdown)]
+ [InlineData(User32.ENDSESSION_CLOSEAPP, SessionEndReasons.SystemShutdown)]
+ [InlineData(User32.ENDSESSION_CRITICAL | User32.ENDSESSION_CLOSEAPP, SessionEndReasons.SystemShutdown)]
+ public void SignalsSessionEnded(int lParam, SessionEndReasons reason)
+ {
+ bool signaled = false;
+ SessionEndedEventArgs args = null;
+ SessionEndedEventHandler endedHandler = (o, e) =>
+ {
+ signaled = true;
+ args = e;
+ };
+
+ SystemEvents.SessionEnded += endedHandler;
+
+ try
+ {
+ SendMessage(true, lParam);
+ Assert.True(signaled);
+ Assert.NotNull(args);
+ Assert.Equal(reason, args.Reason);
+ }
+ finally
+ {
+ SystemEvents.SessionEnded -= endedHandler;
+ }
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))]
+ public void DoesNotSignalSessionEnded()
+ {
+ bool signaled = false;
+ SessionEndedEventHandler endedHandler = (o, e) =>
+ {
+ signaled = true;
+ };
+
+ SystemEvents.SessionEnded += endedHandler;
+
+ try
+ {
+ SendMessage(false, 0);
+ Assert.False(signaled);
+ }
+ finally
+ {
+ SystemEvents.SessionEnded -= endedHandler;
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.SessionEnding.cs b/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.SessionEnding.cs
new file mode 100644
index 0000000000..5156dcf61d
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.SessionEnding.cs
@@ -0,0 +1,74 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using Xunit;
+using static Interop;
+
+namespace Microsoft.Win32.SystemEventsTests
+{
+ public class SessionEndingTests : SystemEventsTest
+ {
+ private IntPtr SendMessage(int lParam)
+ {
+ return SendMessage(User32.WM_QUERYENDSESSION, IntPtr.Zero, (IntPtr)lParam);
+ }
+
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))]
+ [InlineData(User32.ENDSESSION_LOGOFF, SessionEndReasons.Logoff)]
+ [InlineData(User32.ENDSESSION_LOGOFF | User32.ENDSESSION_CRITICAL, SessionEndReasons.Logoff)]
+ [InlineData(User32.ENDSESSION_LOGOFF | User32.ENDSESSION_CLOSEAPP, SessionEndReasons.Logoff)]
+ [InlineData(User32.ENDSESSION_LOGOFF | User32.ENDSESSION_CRITICAL | User32.ENDSESSION_CLOSEAPP, SessionEndReasons.Logoff)]
+ [InlineData(0, SessionEndReasons.SystemShutdown)]
+ [InlineData(User32.ENDSESSION_CRITICAL, SessionEndReasons.SystemShutdown)]
+ [InlineData(User32.ENDSESSION_CLOSEAPP, SessionEndReasons.SystemShutdown)]
+ [InlineData(User32.ENDSESSION_CRITICAL | User32.ENDSESSION_CLOSEAPP, SessionEndReasons.SystemShutdown)]
+ public void SignalsSessionEnding(int lParam, SessionEndReasons reason)
+ {
+ bool signaled = false;
+ SessionEndingEventArgs args = null;
+ SessionEndingEventHandler endingHandler = (o, e) =>
+ {
+ signaled = true;
+ args = e;
+ };
+
+ SystemEvents.SessionEnding += endingHandler;
+
+ try
+ {
+ SendMessage(lParam);
+ Assert.True(signaled);
+ Assert.NotNull(args);
+ Assert.Equal(reason, args.Reason);
+ }
+ finally
+ {
+ SystemEvents.SessionEnding -= endingHandler;
+ }
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))]
+ public void CancelSessionEnding()
+ {
+ bool shouldCancel = false;
+ SessionEndingEventHandler endingHandler = (o, e) =>
+ {
+ e.Cancel = shouldCancel;
+ };
+
+ SystemEvents.SessionEnding += endingHandler;
+ try
+ {
+ Assert.Equal((IntPtr)1, SendMessage(0));
+ shouldCancel = true;
+ Assert.Equal((IntPtr)0, SendMessage(0));
+ }
+ finally
+ {
+ SystemEvents.SessionEnding -= endingHandler;
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.SessionSwitch.cs b/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.SessionSwitch.cs
new file mode 100644
index 0000000000..3be4c3f344
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.SessionSwitch.cs
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Xunit;
+using static Interop;
+
+namespace Microsoft.Win32.SystemEventsTests
+{
+ public class SessionSwitchTests : SystemEventsTest
+ {
+ private void SendMessage(SessionSwitchReason reason)
+ {
+ SendMessage(User32.WM_WTSSESSION_CHANGE, (IntPtr)reason, IntPtr.Zero);
+ }
+
+ public static IEnumerable<object[]> SessionSwitchReasons() => Enum.GetValues(typeof(SessionSwitchReason))
+ .Cast<SessionSwitchReason>()
+ .Select(x => new object[] { x });
+
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))]
+ [MemberData(nameof(SessionSwitchReasons))]
+ public void SignalsSessionSwitch(SessionSwitchReason reason)
+ {
+ bool signaled = false;
+ SessionSwitchEventArgs args = null;
+ SessionSwitchEventHandler switchHandler = (o, e) =>
+ {
+ signaled = true;
+ args = e;
+ };
+
+ SystemEvents.SessionSwitch += switchHandler;
+
+ try
+ {
+ SendMessage(reason);
+ Assert.True(signaled);
+ Assert.NotNull(args);
+ Assert.Equal(reason, args.Reason);
+ }
+ finally
+ {
+ SystemEvents.SessionSwitch -= switchHandler;
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.TimeChanged.cs b/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.TimeChanged.cs
new file mode 100644
index 0000000000..fde0ceb546
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.TimeChanged.cs
@@ -0,0 +1,26 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using static Interop;
+
+namespace Microsoft.Win32.SystemEventsTests
+{
+ public class TimeChangedTests : GenericEventTests
+ {
+ protected override int MessageId => User32.WM_TIMECHANGE;
+
+ protected override event EventHandler Event
+ {
+ add
+ {
+ SystemEvents.TimeChanged += value;
+ }
+ remove
+ {
+ SystemEvents.TimeChanged -= value;
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.UserPreference.cs b/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.UserPreference.cs
new file mode 100644
index 0000000000..d031ba6a32
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/tests/SystemEvents.UserPreference.cs
@@ -0,0 +1,327 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Threading;
+using Xunit;
+using static Interop;
+
+namespace Microsoft.Win32.SystemEventsTests
+{
+ public class UserPreferenceTests : SystemEventsTest
+ {
+
+ private void SendMessage(int message, int uiAction, string area, bool freeMemory = true)
+ {
+ var areaPtr = Marshal.StringToHGlobalUni(area);
+ try
+ {
+ SendMessage((int)message, (IntPtr)uiAction, areaPtr);
+ }
+ finally
+ {
+ if (freeMemory)
+ {
+ Marshal.FreeHGlobal(areaPtr);
+ }
+ }
+ }
+
+ private void SendReflectedMessage(int message, int uiAction, string area)
+ {
+ // WM_REFLECT is an internal message where the SystemEvents WndProc will copy
+ // the lParam and pass it back in a posted message. In that case it expects
+ // to be the source of the message and will free the memory itself.
+ SendMessage(User32.WM_REFLECT + message, uiAction, area, freeMemory:false);
+ }
+
+ public static IEnumerable<object[]> PreferenceChangingCases() =>
+ new List<object[]>()
+ {
+ new object[] { User32.WM_SETTINGCHANGE, 0, "Policy", UserPreferenceCategory.Policy },
+ new object[] { User32.WM_SETTINGCHANGE, 0, "intl", UserPreferenceCategory.Locale },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETACCESSTIMEOUT, null, UserPreferenceCategory.Accessibility },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETFILTERKEYS, null, UserPreferenceCategory.Accessibility },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETHIGHCONTRAST, null, UserPreferenceCategory.Accessibility },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETMOUSEKEYS, null, UserPreferenceCategory.Accessibility },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETSCREENREADER, null, UserPreferenceCategory.Accessibility },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETSERIALKEYS, null, UserPreferenceCategory.Accessibility },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETSHOWSOUNDS, null, UserPreferenceCategory.Accessibility },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETSOUNDSENTRY, null, UserPreferenceCategory.Accessibility },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETSTICKYKEYS, null, UserPreferenceCategory.Accessibility },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETTOGGLEKEYS, null, UserPreferenceCategory.Accessibility },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETDESKWALLPAPER, null, UserPreferenceCategory.Desktop },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETFONTSMOOTHING, null, UserPreferenceCategory.Desktop },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETCURSORS, null, UserPreferenceCategory.Desktop },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETDESKPATTERN, null, UserPreferenceCategory.Desktop },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETGRIDGRANULARITY, null, UserPreferenceCategory.Desktop },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETWORKAREA, null, UserPreferenceCategory.Desktop },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_ICONHORIZONTALSPACING, null, UserPreferenceCategory.Icon },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_ICONVERTICALSPACING, null, UserPreferenceCategory.Icon },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETICONMETRICS, null, UserPreferenceCategory.Icon },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETICONS, null, UserPreferenceCategory.Icon },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETICONTITLELOGFONT, null, UserPreferenceCategory.Icon },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETICONTITLEWRAP, null, UserPreferenceCategory.Icon },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETDOUBLECLICKTIME, null, UserPreferenceCategory.Mouse },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETDOUBLECLKHEIGHT, null, UserPreferenceCategory.Mouse },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETDOUBLECLKWIDTH, null, UserPreferenceCategory.Mouse },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETMOUSE, null, UserPreferenceCategory.Mouse },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETMOUSEBUTTONSWAP, null, UserPreferenceCategory.Mouse },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETMOUSEHOVERHEIGHT, null, UserPreferenceCategory.Mouse },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETMOUSEHOVERTIME, null, UserPreferenceCategory.Mouse },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETMOUSESPEED, null, UserPreferenceCategory.Mouse },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETMOUSETRAILS, null, UserPreferenceCategory.Mouse },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETSNAPTODEFBUTTON, null, UserPreferenceCategory.Mouse },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETWHEELSCROLLLINES, null, UserPreferenceCategory.Mouse },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETCURSORSHADOW, null, UserPreferenceCategory.Mouse },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETHOTTRACKING, null, UserPreferenceCategory.Mouse },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETTOOLTIPANIMATION, null, UserPreferenceCategory.Mouse },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETTOOLTIPFADE, null, UserPreferenceCategory.Mouse },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETKEYBOARDDELAY, null, UserPreferenceCategory.Keyboard },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETKEYBOARDPREF, null, UserPreferenceCategory.Keyboard },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETKEYBOARDSPEED, null, UserPreferenceCategory.Keyboard },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETLANGTOGGLE, null, UserPreferenceCategory.Keyboard },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETMENUDROPALIGNMENT, null, UserPreferenceCategory.Menu },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETMENUFADE, null, UserPreferenceCategory.Menu },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETMENUSHOWDELAY, null, UserPreferenceCategory.Menu },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETMENUANIMATION, null, UserPreferenceCategory.Menu },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETSELECTIONFADE, null, UserPreferenceCategory.Menu },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETLOWPOWERACTIVE, null, UserPreferenceCategory.Power },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETLOWPOWERTIMEOUT, null, UserPreferenceCategory.Power },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETPOWEROFFACTIVE, null, UserPreferenceCategory.Power },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETPOWEROFFTIMEOUT, null, UserPreferenceCategory.Power },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETSCREENSAVEACTIVE, null, UserPreferenceCategory.Screensaver },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETSCREENSAVERRUNNING, null, UserPreferenceCategory.Screensaver },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETSCREENSAVETIMEOUT, null, UserPreferenceCategory.Screensaver },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETKEYBOARDCUES, null, UserPreferenceCategory.Window },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETCOMBOBOXANIMATION, null, UserPreferenceCategory.Window },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETLISTBOXSMOOTHSCROLLING, null, UserPreferenceCategory.Window },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETGRADIENTCAPTIONS, null, UserPreferenceCategory.Window },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETUIEFFECTS, null, UserPreferenceCategory.Window },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETACTIVEWINDOWTRACKING, null, UserPreferenceCategory.Window },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETACTIVEWNDTRKZORDER, null, UserPreferenceCategory.Window },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETACTIVEWNDTRKTIMEOUT, null, UserPreferenceCategory.Window },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETANIMATION, null, UserPreferenceCategory.Window },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETBORDER, null, UserPreferenceCategory.Window },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETCARETWIDTH, null, UserPreferenceCategory.Window },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETDRAGFULLWINDOWS, null, UserPreferenceCategory.Window },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETDRAGHEIGHT, null, UserPreferenceCategory.Window },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETDRAGWIDTH, null, UserPreferenceCategory.Window },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETFOREGROUNDFLASHCOUNT, null, UserPreferenceCategory.Window },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETFOREGROUNDLOCKTIMEOUT, null, UserPreferenceCategory.Window },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETMINIMIZEDMETRICS, null, UserPreferenceCategory.Window },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETNONCLIENTMETRICS, null, UserPreferenceCategory.Window },
+ new object[] { User32.WM_SETTINGCHANGE, User32.SPI_SETSHOWIMEUI, null, UserPreferenceCategory.Window },
+ new object[] { User32.WM_SYSCOLORCHANGE, 0, null, UserPreferenceCategory.Color },
+ };
+
+
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))]
+ [MemberData(nameof(PreferenceChangingCases))]
+ public void SignalsUserPreferenceEventsAsynchronously(int message, int uiAction, string area, UserPreferenceCategory expectedCategory)
+ {
+ var changing = new AutoResetEvent(false);
+ var changed = new AutoResetEvent(false);
+
+ UserPreferenceChangingEventArgs changingArgs = null;
+ UserPreferenceChangingEventHandler changingHandler = (o, e) =>
+ {
+ changingArgs = e;
+ changing.Set();
+ };
+
+ UserPreferenceChangedEventArgs changedArgs = null;
+ UserPreferenceChangingEventArgs changingDuringChanged = null;
+ UserPreferenceChangedEventHandler changedHandler = (o, e) =>
+ {
+ changedArgs = e;
+ changingDuringChanged = changingArgs;
+ changed.Set();
+ };
+
+ SystemEvents.UserPreferenceChanging += changingHandler;
+ SystemEvents.UserPreferenceChanged += changedHandler;
+
+ try
+ {
+ SendMessage(message, uiAction, area);
+ Assert.True(changing.WaitOne(PostMessageWait));
+ Assert.NotNull(changingArgs);
+ Assert.Equal(expectedCategory, changingArgs.Category);
+
+ Assert.True(changed.WaitOne(PostMessageWait));
+ Assert.NotNull(changedArgs);
+ Assert.Equal(expectedCategory, changedArgs.Category);
+
+ // changed must follow changing for the same category
+ Assert.NotNull(changingDuringChanged);
+ Assert.Equal(expectedCategory, changingDuringChanged.Category);
+
+ }
+ finally
+ {
+ SystemEvents.UserPreferenceChanging -= changingHandler;
+ SystemEvents.UserPreferenceChanged -= changedHandler;
+ changing.Dispose();
+ changed.Dispose();
+ }
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))]
+ public void SignalsUserPreferenceEventsAsynchronouslyOnThemeChanged()
+ {
+ var changing = new AutoResetEvent(false);
+ var changed = new AutoResetEvent(false);
+
+ UserPreferenceChangingEventArgs changingArgs = null;
+ UserPreferenceChangingEventHandler changingHandler = (o, e) =>
+ {
+ changingArgs = e;
+ changing.Set();
+ };
+
+ List<UserPreferenceChangedEventArgs> changedArgs = new List<UserPreferenceChangedEventArgs>();
+ UserPreferenceChangingEventArgs changingDuringChanged = null;
+ UserPreferenceChangedEventHandler changedHandler = (o, e) =>
+ {
+ changedArgs.Add(e);
+ changingDuringChanged = changingArgs;
+ // signal test to continue after two events were recieved
+ if (changedArgs.Count > 1)
+ {
+ changed.Set();
+ }
+ };
+
+ SystemEvents.UserPreferenceChanging += changingHandler;
+ SystemEvents.UserPreferenceChanged += changedHandler;
+
+ try
+ {
+ SendMessage(User32.WM_THEMECHANGED, 0, null);
+ Assert.True(changing.WaitOne(PostMessageWait));
+ Assert.NotNull(changingArgs);
+ Assert.Equal(UserPreferenceCategory.VisualStyle, changingArgs.Category);
+
+ Assert.True(changed.WaitOne(PostMessageWait));
+ Assert.Equal(2, changedArgs.Count);
+ Assert.NotNull(changedArgs[0]);
+ Assert.Equal(UserPreferenceCategory.Window, changedArgs[0].Category);
+ Assert.NotNull(changedArgs[1]);
+ Assert.Equal(UserPreferenceCategory.VisualStyle, changedArgs[1].Category);
+
+ // changed must follow changing for VisualStyle
+ Assert.NotNull(changingDuringChanged);
+ Assert.Equal(UserPreferenceCategory.VisualStyle, changingDuringChanged.Category);
+
+ }
+ finally
+ {
+ SystemEvents.UserPreferenceChanging -= changingHandler;
+ SystemEvents.UserPreferenceChanged -= changedHandler;
+ changing.Dispose();
+ changed.Dispose();
+ }
+ }
+
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))]
+ [MemberData(nameof(PreferenceChangingCases))]
+ public void SignalsUserPreferenceEventsSynchronously(int message, int uiAction, string area, UserPreferenceCategory expectedCategory)
+ {
+ bool changing = false, changed = false;
+
+ UserPreferenceChangingEventArgs changingArgs = null;
+ UserPreferenceChangingEventHandler changingHandler = (o, e) =>
+ {
+ changingArgs = e;
+ changing = true;
+ };
+
+ UserPreferenceChangedEventArgs changedArgs = null;
+ UserPreferenceChangingEventArgs changingDuringChanged = null;
+ UserPreferenceChangedEventHandler changedHandler = (o, e) =>
+ {
+ changedArgs = e;
+ changingDuringChanged = changingArgs;
+ changed = true;
+ };
+
+ SystemEvents.UserPreferenceChanging += changingHandler;
+ SystemEvents.UserPreferenceChanged += changedHandler;
+
+
+ try
+ {
+ SendReflectedMessage(message, uiAction, area);
+ Assert.True(changing);
+ Assert.NotNull(changingArgs);
+ Assert.Equal(expectedCategory, changingArgs.Category);
+
+ Assert.True(changed);
+ Assert.NotNull(changedArgs);
+ Assert.Equal(expectedCategory, changedArgs.Category);
+
+ // changed must follow changing for the same category
+ Assert.NotNull(changingDuringChanged);
+ Assert.Equal(expectedCategory, changingDuringChanged.Category);
+ }
+ finally
+ {
+ SystemEvents.UserPreferenceChanging -= changingHandler;
+ SystemEvents.UserPreferenceChanged -= changedHandler;
+ }
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))]
+ public void SignalsUserPreferenceEventsSynchronouslyOnReflectedThemeChanged()
+ {
+ bool changing = false, changed = false;
+
+ UserPreferenceChangingEventArgs changingArgs = null;
+ UserPreferenceChangingEventHandler changingHandler = (o, e) =>
+ {
+ changingArgs = e;
+ changing = true;
+ };
+
+ List<UserPreferenceChangedEventArgs> changedArgs = new List<UserPreferenceChangedEventArgs>();
+ UserPreferenceChangingEventArgs changingDuringChanged = null;
+ UserPreferenceChangedEventHandler changedHandler = (o, e) =>
+ {
+ changedArgs.Add(e);
+ changingDuringChanged = changingArgs;
+ changed = true;
+ };
+
+ SystemEvents.UserPreferenceChanging += changingHandler;
+ SystemEvents.UserPreferenceChanged += changedHandler;
+
+ try
+ {
+ SendReflectedMessage(User32.WM_THEMECHANGED, 0, null);
+ Assert.True(changing);
+ Assert.NotNull(changingArgs);
+ Assert.Equal(UserPreferenceCategory.VisualStyle, changingArgs.Category);
+
+ Assert.True(changed);
+ Assert.Equal(2, changedArgs.Count);
+ Assert.NotNull(changedArgs[0]);
+ Assert.Equal(UserPreferenceCategory.Window, changedArgs[0].Category);
+ Assert.NotNull(changedArgs[1]);
+ Assert.Equal(UserPreferenceCategory.VisualStyle, changedArgs[1].Category);
+
+ // changed must follow changing for VisualStyle
+ Assert.NotNull(changingDuringChanged);
+ Assert.Equal(UserPreferenceCategory.VisualStyle, changingDuringChanged.Category);
+ }
+ finally
+ {
+ SystemEvents.UserPreferenceChanging -= changingHandler;
+ SystemEvents.UserPreferenceChanged -= changedHandler;
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.Win32.SystemEvents/tests/SystemEventsTest.cs b/src/Microsoft.Win32.SystemEvents/tests/SystemEventsTest.cs
new file mode 100644
index 0000000000..f3df79a5ec
--- /dev/null
+++ b/src/Microsoft.Win32.SystemEvents/tests/SystemEventsTest.cs
@@ -0,0 +1,63 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Threading;
+using Xunit;
+using static Interop;
+
+namespace Microsoft.Win32.SystemEventsTests
+{
+ public abstract class SystemEventsTest
+ {
+ IntPtr s_hwnd = IntPtr.Zero;
+
+ public const int PostMessageWait = 10000;
+ public const int ExpectedEventMultiplier = 1000;
+ public const int UnexpectedEventMultiplier = 10;
+
+ protected IntPtr SendMessage(int msg, IntPtr wParam, IntPtr lParam)
+ {
+ EnsureHwnd();
+ return User32.SendMessageW(s_hwnd, msg, wParam, lParam);
+ }
+
+ private void EnsureHwnd()
+ {
+ if (s_hwnd == IntPtr.Zero)
+ {
+ if (PlatformDetection.IsFullFramework)
+ {
+ // desktop has a bug where it will allow EnsureSystemEvents to proceed without actually creating the HWND
+ WaitForSystemEventsWindow();
+ }
+
+ // locate the hwnd used by SystemEvents in this domain
+ var windowClassNameField = typeof(SystemEvents).GetField("s_className", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic) ?? // corefx
+ typeof(SystemEvents).GetField("className", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic); // desktop
+ Assert.NotNull(windowClassNameField);
+ var windowClassName = windowClassNameField.GetValue(null) as string;
+ Assert.NotNull(windowClassName);
+
+ s_hwnd = User32.FindWindowW(windowClassName, null);
+ Assert.NotEqual(s_hwnd, IntPtr.Zero);
+ }
+ }
+
+ internal static void WaitForSystemEventsWindow()
+ {
+ // wait for the window to be created
+ var windowReadyField = typeof(SystemEvents).GetField("s_eventWindowReady", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic) ?? // corefx
+ typeof(SystemEvents).GetField("eventWindowReady", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic); // desktop
+ Assert.NotNull(windowReadyField);
+ var windowReadyEvent = windowReadyField.GetValue(null) as ManualResetEvent;
+ if (windowReadyEvent != null)
+ {
+ // on an STA thread the HWND is created in the same thread synchronously when attaching to an event handler
+ // if we're on an MTA thread, a new thread is created to handle events and that thread creates the window, wait for it to complete.
+ Assert.True(windowReadyEvent.WaitOne(PostMessageWait * ExpectedEventMultiplier));
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.XmlSerializer.Generator/dir.props b/src/Microsoft.XmlSerializer.Generator/dir.props
index 96d567877b..66b1e87a74 100644
--- a/src/Microsoft.XmlSerializer.Generator/dir.props
+++ b/src/Microsoft.XmlSerializer.Generator/dir.props
@@ -2,10 +2,9 @@
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\dir.props" />
<PropertyGroup>
- <PreReleaseLabel>preview1</PreReleaseLabel>
- <PackageVersion>1.1.0</PackageVersion>
+ <PackageVersion>2.0.0</PackageVersion>
<SkipValidatePackage>true</SkipValidatePackage>
- <AssemblyVersion>1.0.0.0</AssemblyVersion>
+ <AssemblyVersion>2.0.0.0</AssemblyVersion>
<AssemblyFileVersion>$(AssemblyVersion)</AssemblyFileVersion>
<AssemblyKey>Open</AssemblyKey>
</PropertyGroup>
diff --git a/src/Microsoft.XmlSerializer.Generator/pkg/build/Microsoft.XmlSerializer.Generator.targets b/src/Microsoft.XmlSerializer.Generator/pkg/build/Microsoft.XmlSerializer.Generator.targets
index d1ae79fec1..d439baaae1 100644
--- a/src/Microsoft.XmlSerializer.Generator/pkg/build/Microsoft.XmlSerializer.Generator.targets
+++ b/src/Microsoft.XmlSerializer.Generator/pkg/build/Microsoft.XmlSerializer.Generator.targets
@@ -4,7 +4,7 @@
<_SerializerDllIntermediateFolder>$(IntermediateOutputPath)$(_SerializationAssemblyName).dll</_SerializerDllIntermediateFolder>
<_SerializerPdbIntermediateFolder>$(IntermediateOutputPath)$(_SerializationAssemblyName).pdb</_SerializerPdbIntermediateFolder>
<_SerializerCsIntermediateFolder>$(IntermediateOutputPath)$(_SerializationAssemblyName).cs</_SerializerCsIntermediateFolder>
- <_SGenWarningText>SGEN : warning SGEN1: Fail to generate the serializer for $(AssemblyName)$(TargetExt). Please follow the instructions at https://go.microsoft.com/fwlink/?linkid=858594 and try again.</_SGenWarningText>
+ <_SGenWarningText>SGEN: Fail to generate the serializer for $(AssemblyName)$(TargetExt). Please follow the instructions at https://go.microsoft.com/fwlink/?linkid=858594 and try again.</_SGenWarningText>
<_SerializationAssemblyDisabledWarnings>$(NoWarn);219;162;$(SerializationAssemblyDisabledWarnings)</_SerializationAssemblyDisabledWarnings>
</PropertyGroup>
<Target Name="GenerateSerializationAssembly" AfterTargets="Build">
@@ -12,7 +12,7 @@
<Delete Condition="Exists('$(_SerializerPdbIntermediateFolder)') == 'true'" Files="$(_SerializerPdbIntermediateFolder)" ContinueOnError="true"/>
<Delete Condition="Exists('$(_SerializerCsIntermediateFolder)') == 'true'" Files="$(_SerializerCsIntermediateFolder)" ContinueOnError="true"/>
<Message Text="Running Serialization Tool" Importance="normal" />
- <Exec Command="dotnet Microsoft.XmlSerializer.Generator $(IntermediateOutputPath)$(AssemblyName)$(TargetExt) /force /quiet" ContinueOnError="true"/>
+ <Exec Command="dotnet Microsoft.XmlSerializer.Generator $(IntermediateOutputPath)$(AssemblyName)$(TargetExt) --force --quiet --reference @(Reference)" ContinueOnError="true"/>
<Warning Condition="Exists('$(_SerializerCsIntermediateFolder)') != 'true'" Text="$(_SGenWarningText)" />
<Csc Condition="Exists('$(_SerializerCsIntermediateFolder)') == 'true'" ContinueOnError="true" OutputAssembly="$(_SerializerDllIntermediateFolder)" References="@(ReferencePath);@(IntermediateAssembly)" EmitDebugInformation="$(DebugSymbols)" Sources="$(_SerializerCsIntermediateFolder)" TargetType="Library" ToolExe="$(CscToolExe)" ToolPath="$(CscToolPath)" DisabledWarnings="$(_SerializationAssemblyDisabledWarnings)"/>
<Warning Condition="Exists('$(_SerializerDllIntermediateFolder)') != 'true' And Exists('$(_SerializerCsIntermediateFolder)') == 'true'" Text="$(_SGenWarningText)"/>
@@ -43,10 +43,10 @@
<Delete Files="%(_ReferenceSerializerIntermediateFolder.Identity).cs" ContinueOnError="true"/>
<Delete Files="%(_ReferenceSerializerIntermediateFolder.Identity).pdb" ContinueOnError="true"/>
<Message Text="Running Serialization Tool for Reference Assembly" Importance="normal" />
- <Exec Command="dotnet Microsoft.XmlSerializer.Generator /force /quiet /assembly:%(_TargetSerializationAssembly.Identity) /type:%(_TargetSerializationAssembly.SerializationTypes) /out:$(IntermediateOutputPath)" ContinueOnError="true" />
- <Warning Condition="Exists('$(IntermediateOutputPath)%(_ReferenceSerializationAssemblyName.Identity).cs') != 'true'" Text="SGEN : warning SGEN1: Fail to generate %(_ReferenceSerializationAssemblyName.Identity)'. Please follow the instructions at https://go.microsoft.com/fwlink/?linkid=858594 and try again." />
+ <Exec Command="dotnet Microsoft.XmlSerializer.Generator --force --quiet --reference @(Reference) --assembly %(_TargetSerializationAssembly.Identity) --type %(_TargetSerializationAssembly.SerializationTypes) --out $(IntermediateOutputPath)" ContinueOnError="true" />
+ <Warning Condition="Exists('$(IntermediateOutputPath)%(_ReferenceSerializationAssemblyName.Identity).cs') != 'true'" Text="SGEN: Fail to generate %(_ReferenceSerializationAssemblyName.Identity)'. Please follow the instructions at https://go.microsoft.com/fwlink/?linkid=858594 and try again." />
<Csc Condition="Exists('$(IntermediateOutputPath)%(_ReferenceSerializationAssemblyName.Identity).cs') == 'true'" ContinueOnError="true" OutputAssembly="$(IntermediateOutputPath)%(_ReferenceSerializationAssemblyName.Identity).dll" References="@(ReferencePath);@(IntermediateAssembly)" EmitDebugInformation="$(DebugSymbols)" Sources="$(IntermediateOutputPath)%(_ReferenceSerializationAssemblyName.Identity).cs" TargetType="Library" ToolExe="$(CscToolExe)" ToolPath="$(CscToolPath)" DisabledWarnings="$(_SerializationAssemblyDisabledWarnings)"/>
- <Warning Condition="Exists('$(IntermediateOutputPath)%(_ReferenceSerializationAssemblyName.Identity).dll') != 'true' And Exists('$(IntermediateOutputPath)%(_ReferenceSerializationAssemblyName.Identity).cs') == 'true'" Text="SGEN : warning SGEN1: Fail to compile %(_ReferenceSerializationAssemblyName.Identity).cs. Please follow the instructions at https://go.microsoft.com/fwlink/?linkid=858594 and try again." />
+ <Warning Condition="Exists('$(IntermediateOutputPath)%(_ReferenceSerializationAssemblyName.Identity).dll') != 'true' And Exists('$(IntermediateOutputPath)%(_ReferenceSerializationAssemblyName.Identity).cs') == 'true'" Text="SGEN: Fail to compile %(_ReferenceSerializationAssemblyName.Identity).cs. Please follow the instructions at https://go.microsoft.com/fwlink/?linkid=858594 and try again." />
<Copy Condition="Exists('%(_ReferenceSerializerIntermediateFolder.Identity).dll') == 'true'" SourceFiles="%(_ReferenceSerializerIntermediateFolder.Identity).dll" DestinationFolder="$(OutputPath)" />
</Target>
@@ -58,4 +58,4 @@
<Target Name="CopySerializerForReferenceAssemblies" AfterTargets="PrepareForPublish" Condition="@(SerializationAssembly)!=''">
<Copy Condition="Exists('$(OutputPath)%(SerializationAssembly.Identity).XmlSerializers.dll') == 'true'" SourceFiles="$(OutputPath)%(SerializationAssembly.Identity).XmlSerializers.dll" DestinationFolder="$(PublishDir)" SkipUnchangedFiles="false" />
</Target>
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/Microsoft.XmlSerializer.Generator/src/Microsoft.XmlSerializer.Generator.csproj b/src/Microsoft.XmlSerializer.Generator/src/Microsoft.XmlSerializer.Generator.csproj
index 71e1efe5da..b999bf2a1a 100644
--- a/src/Microsoft.XmlSerializer.Generator/src/Microsoft.XmlSerializer.Generator.csproj
+++ b/src/Microsoft.XmlSerializer.Generator/src/Microsoft.XmlSerializer.Generator.csproj
@@ -8,7 +8,7 @@
<StringResourcesPath>..\..\System.Private.Xml\src\Resources\Strings.resx</StringResourcesPath>
<OutputType>Exe</OutputType>
<TargetExt>.dll</TargetExt>
- <NoWarn>$(NoWarn);0169;0414;0649</NoWarn>
+
</PropertyGroup>
<!-- Default configurations to help VS understand the options -->
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
diff --git a/src/Microsoft.XmlSerializer.Generator/src/Sgen.cs b/src/Microsoft.XmlSerializer.Generator/src/Sgen.cs
index 281ce4db31..7e75a55b72 100644
--- a/src/Microsoft.XmlSerializer.Generator/src/Sgen.cs
+++ b/src/Microsoft.XmlSerializer.Generator/src/Sgen.cs
@@ -21,6 +21,9 @@ namespace Microsoft.XmlSerializer.Generator
return sgen.Run(args);
}
+ private static string s_references = string.Empty;
+ private static Dictionary<string, string> s_referencedic = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+
private int Run(string[] args)
{
string assembly = null;
@@ -35,27 +38,15 @@ namespace Microsoft.XmlSerializer.Generator
bool silent = false;
bool warnings = false;
+ AppDomain.CurrentDomain.AssemblyResolve += SgenAssemblyResolver;
+
try
{
for (int i = 0; i < args.Length; i++)
{
string arg = args[i];
- string value = string.Empty;
-
- if (arg.StartsWith("/") || arg.StartsWith("-"))
- {
- int colonPos = arg.IndexOf(":");
- if (colonPos != -1)
- {
- value = arg.Substring(colonPos + 1).Trim();
- arg = arg.Substring(0, colonPos).Trim();
- }
- }
-
- string originalArg = arg;
- arg = arg.ToLower(CultureInfo.InvariantCulture);
-
- if (ArgumentMatch(arg, "?") || ArgumentMatch(arg, "help"))
+
+ if (ArgumentMatch(arg, "help") || ShortNameArgumentMatch(arg, "h"))
{
WriteHeader();
WriteHelp();
@@ -69,34 +60,45 @@ namespace Microsoft.XmlSerializer.Generator
{
proxyOnly = true;
}
- else if (ArgumentMatch(arg, "out"))
+ else if (ArgumentMatch(arg, "out") || ShortNameArgumentMatch(arg, "o"))
{
- if (codePath != null)
+ i++;
+ if(i >= args.Length || codePath != null )
+ {
+ errs.Add(SR.Format(SR.ErrInvalidArgument, arg));
+ }
+ else
{
- errs.Add(SR.Format(SR.ErrInvalidArgument, "/out", arg));
+ codePath = args[i];
}
-
- codePath = value;
}
else if (ArgumentMatch(arg, "type"))
{
- if (value != string.Empty)
+ i++;
+ if (i >= args.Length)
+ {
+ errs.Add(SR.Format(SR.ErrInvalidArgument, arg));
+ }
+ else
{
- string[] typelist = value.Split(';');
+ string[] typelist = args[i].Split(';');
foreach (var type in typelist)
{
types.Add(type);
}
}
}
- else if (ArgumentMatch(arg, "assembly"))
+ else if (ArgumentMatch(arg, "assembly") || ShortNameArgumentMatch(arg, "a"))
{
- if (assembly != null)
+ i++;
+ if (i >= args.Length || assembly != null)
{
- errs.Add(SR.Format(SR.ErrInvalidArgument, "/assembly", arg));
+ errs.Add(SR.Format(SR.ErrInvalidArgument, arg));
+ }
+ else
+ {
+ assembly = args[i];
}
-
- assembly = value;
}
else if (ArgumentMatch(arg, "quiet"))
{
@@ -118,16 +120,32 @@ namespace Microsoft.XmlSerializer.Generator
{
warnings = true;
}
+ else if (ArgumentMatch(arg, "reference"))
+ {
+ i++;
+ if (i >= args.Length)
+ {
+ errs.Add(SR.Format(SR.ErrInvalidArgument, arg));
+ }
+ else
+ {
+ s_references = args[i];
+ if (!string.IsNullOrEmpty(s_references))
+ {
+ ParseReferences();
+ }
+ }
+ }
else
{
- if (arg.EndsWith(".dll") || arg.EndsWith(".exe"))
+ if (arg.EndsWith(".dll", StringComparison.InvariantCultureIgnoreCase) || arg.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase))
{
if (assembly != null)
{
- errs.Add(SR.Format(SR.ErrInvalidArgument, "/assembly", arg));
+ errs.Add(SR.Format(SR.ErrInvalidArgument, arg));
}
- assembly = originalArg;
+ assembly = arg;
}
else
{
@@ -232,23 +250,37 @@ namespace Microsoft.XmlSerializer.Generator
{
Type type = types[i];
- if (type != null)
+ try
{
- bool isObsolete = false;
- object[] obsoleteAttributes = type.GetCustomAttributes(typeof(ObsoleteAttribute), false);
- foreach (object attribute in obsoleteAttributes)
+ if (type != null)
{
- if (((ObsoleteAttribute)attribute).IsError)
+ bool isObsolete = false;
+ object[] obsoleteAttributes = type.GetCustomAttributes(typeof(ObsoleteAttribute), false);
+ foreach (object attribute in obsoleteAttributes)
+ {
+ if (((ObsoleteAttribute)attribute).IsError)
+ {
+ isObsolete = true;
+ break;
+ }
+ }
+
+ if (isObsolete)
{
- isObsolete = true;
- break;
+ continue;
}
}
-
- if (isObsolete)
+ }
+ //Ignore the FileNotFoundException when call GetCustomAttributes e.g. if the type uses the attributes defined in a different assembly
+ catch (FileNotFoundException e)
+ {
+ if (warnings)
{
- continue;
+ Console.Out.WriteLine(FormatMessage(parsableerrors, true, SR.Format(SR.InfoIgnoreType, type.FullName)));
+ WriteWarning(e, parsableerrors);
}
+
+ continue;
}
if (!proxyOnly)
@@ -338,16 +370,27 @@ namespace Microsoft.XmlSerializer.Generator
}
}
- // assumes all same case.
+
private bool ArgumentMatch(string arg, string formal)
{
- if (arg[0] != '/' && arg[0] != '-')
+ // Full name format, eg: --assembly
+ if (arg.Length < 3 || arg[0] != '-' || arg[1] != '-' )
{
return false;
}
+ arg = arg.Substring(2);
+ return arg.Equals(formal, StringComparison.InvariantCultureIgnoreCase);
+ }
+ public bool ShortNameArgumentMatch(string arg, string shortName)
+ {
+ // Short name format, eg: -a
+ if (arg.Length < 2 || arg[0] != '-')
+ {
+ return false;
+ }
arg = arg.Substring(1);
- return (arg == formal || (arg.Length == 1 && arg[0] == formal[0]));
+ return arg.Equals(shortName, StringComparison.InvariantCultureIgnoreCase);
}
private void ImportType(Type type, ArrayList mappings, ArrayList importedTypes, bool verbose, XmlReflectionImporter importer, bool parsableerrors)
@@ -404,16 +447,16 @@ namespace Microsoft.XmlSerializer.Generator
private void WriteHelp()
{
Console.Out.WriteLine(SR.Format(SR.HelpDescription));
- Console.Out.WriteLine(SR.Format(SR.HelpUsage, this.GetType().Assembly.GetName().Name));
+ Console.Out.WriteLine(SR.Format(SR.HelpUsage, this.GetType().Assembly.GetName().Name.Substring("dotnet-".Length)));
Console.Out.WriteLine(SR.Format(SR.HelpDevOptions));
- Console.Out.WriteLine(SR.Format(SR.HelpAssembly, "/assembly:", "/a:"));
- Console.Out.WriteLine(SR.Format(SR.HelpType, "/type:", "/t:"));
- Console.Out.WriteLine(SR.Format(SR.HelpProxy, "/proxytypes", "/p"));
- Console.Out.WriteLine(SR.Format(SR.HelpForce, "/force", "/f"));
- Console.Out.WriteLine(SR.Format(SR.HelpOut, "/out:", "/o:"));
+ Console.Out.WriteLine(SR.Format(SR.HelpAssembly, "-a", "--assembly"));
+ Console.Out.WriteLine(SR.Format(SR.HelpType, "--type"));
+ Console.Out.WriteLine(SR.Format(SR.HelpProxy, "--proxytypes"));
+ Console.Out.WriteLine(SR.Format(SR.HelpForce, "--force"));
+ Console.Out.WriteLine(SR.Format(SR.HelpOut, "-o", "--out"));
Console.Out.WriteLine(SR.Format(SR.HelpMiscOptions));
- Console.Out.WriteLine(SR.Format(SR.HelpHelp, "/?", "/help"));
+ Console.Out.WriteLine(SR.Format(SR.HelpHelp, "-h", "--help"));
}
private static string FormatMessage(bool parsableerrors, bool warning, string message)
@@ -467,5 +510,76 @@ namespace Microsoft.XmlSerializer.Generator
{
return parent.Name + ".XmlSerializers" + (ns == null || ns.Length == 0 ? "" : "." + ns.GetHashCode());
}
+
+ private static void ParseReferences()
+ {
+ var referencelist = new List<string>();
+ if (s_references.Length > 0)
+ {
+ foreach(var entry in s_references.Split(';'))
+ {
+ string trimentry = entry.Trim();
+ if (string.IsNullOrEmpty(trimentry))
+ continue;
+ referencelist.Add(trimentry);
+ }
+ }
+
+ foreach (var reference in referencelist)
+ {
+ if (reference.EndsWith(".dll") || reference.EndsWith(".exe"))
+ {
+ if (File.Exists(reference))
+ {
+ string filename = Path.GetFileNameWithoutExtension(reference);
+ if (!string.IsNullOrEmpty(filename))
+ {
+ s_referencedic.Add(filename, reference);
+ }
+ }
+ }
+
+ }
+ }
+
+ private static Assembly SgenAssemblyResolver(object source, ResolveEventArgs e)
+ {
+ try
+ {
+ if (string.IsNullOrEmpty(e.Name) || e.Name.Split(',').Length == 0)
+ {
+ return null;
+ }
+
+ string assemblyname = e.Name.Split(',')[0];
+ if (string.IsNullOrEmpty(assemblyname))
+ {
+ return null;
+ }
+
+ if(s_referencedic.ContainsKey(assemblyname))
+ {
+ string reference = s_referencedic[assemblyname];
+ if (!string.IsNullOrEmpty(reference))
+ {
+ if (File.Exists(reference))
+ {
+ return Assembly.LoadFrom(reference);
+ }
+ }
+ }
+ }
+ catch (Exception exp)
+ {
+ if (exp is ThreadAbortException || exp is StackOverflowException || exp is OutOfMemoryException)
+ {
+ throw;
+ }
+
+ WriteWarning(exp, true);
+ }
+
+ return null;
+ }
}
}
diff --git a/src/Microsoft.XmlSerializer.Generator/tests/Microsoft.XmlSerializer.Generator.Tests.csproj b/src/Microsoft.XmlSerializer.Generator/tests/Microsoft.XmlSerializer.Generator.Tests.csproj
index 3eaed25e3a..8f54fc98c2 100644
--- a/src/Microsoft.XmlSerializer.Generator/tests/Microsoft.XmlSerializer.Generator.Tests.csproj
+++ b/src/Microsoft.XmlSerializer.Generator/tests/Microsoft.XmlSerializer.Generator.Tests.csproj
@@ -30,7 +30,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
<ItemGroup Condition=" '$(SkipTestsOnPlatform)' != 'true' ">
<Compile Include=".\SGenTests.cs" />
- <Compile Include="$(TestSourceFolder)..\..\System.Runtime.Serialization.Xml\tests\Utils.cs" />
+ <Compile Include="$(CommonTestPath)\System\Runtime\Serialization\Utils.cs" />
<Compile Include="$(TestSourceFolder)..\..\System.Runtime.Serialization.Xml\tests\SerializationTypes.cs" />
<Compile Include="$(TestSourceFolder)..\..\System.Private.Xml\tests\XmlSerializer\XmlSerializerTests.cs" />
</ItemGroup>
@@ -56,9 +56,9 @@
<SerializerName>$(AssemblyName).XmlSerializers</SerializerName>
</PropertyGroup>
<Message Text="Running Serialization Tool" Importance="normal" />
- <Exec Command="$(GeneratorCliPath)dotnet $(OutputPath)dotnet-Microsoft.XmlSerializer.Generator.dll $(OutputPath)Microsoft.XmlSerializer.Generator.Tests.dll /force /quiet" />
+ <Exec Command="$(GeneratorCliPath)dotnet $(OutputPath)dotnet-Microsoft.XmlSerializer.Generator.dll $(OutputPath)Microsoft.XmlSerializer.Generator.Tests.dll --force --quiet" />
<Warning Condition="Exists('$(OutputPath)$(SerializerName).cs') != 'true'" Text="Fail to generate $(OutputPath)$(SerializerName).cs"/>
- <Csc Condition="Exists('$(OutputPath)$(SerializerName).cs') == 'true' AND '$(MSBuildRuntimeType)' != 'core'"
+ <Csc Condition="Exists('$(OutputPath)$(SerializerName).cs') == 'true'"
OutputAssembly="$(OutputPath)$(SerializerName).dll"
References="@(ReferencePath);@(IntermediateAssembly)"
EmitDebugInformation="$(DebugSymbols)"
@@ -69,19 +69,6 @@
ToolPath="$(CscToolPath)"
DisabledWarnings="$(NoWarn), 219"
UseSharedCompilation="true" />
- <!-- when building on core CSC requires the OverrideToolHost parameter, but this is not supported by desktop csc -->
- <Csc Condition="Exists('$(OutputPath)$(SerializerName).cs') == 'true' AND '$(MSBuildRuntimeType)' == 'core'"
- OutputAssembly="$(OutputPath)$(SerializerName).dll"
- References="@(ReferencePath);@(IntermediateAssembly)"
- EmitDebugInformation="$(DebugSymbols)"
- DebugType="$(DebugType)"
- Sources="$(OutputPath)$(SerializerName).cs"
- TargetType="Library"
- ToolExe="$(CscToolExe)"
- ToolPath="$(CscToolPath)"
- OverrideToolHost="$(OverrideToolHost)"
- DisabledWarnings="$(NoWarn), 219"
- UseSharedCompilation="true" />
<Warning Condition="Exists('$(OutputPath)$(SerializerName).dll') != 'true'" Text="Fail to generate $(OutputPath)$(SerializerName).dll"/>
<ItemGroup>
diff --git a/src/Microsoft.XmlSerializer.Generator/tests/SGenTests.cs b/src/Microsoft.XmlSerializer.Generator/tests/SGenTests.cs
index 639429dc47..e2737c6aa6 100644
--- a/src/Microsoft.XmlSerializer.Generator/tests/SGenTests.cs
+++ b/src/Microsoft.XmlSerializer.Generator/tests/SGenTests.cs
@@ -19,7 +19,7 @@ namespace Microsoft.XmlSerializer.Generator.Tests
string codefile = "Microsoft.XmlSerializer.Generator.Tests.XmlSerializers.cs";
var type = Type.GetType("Microsoft.XmlSerializer.Generator.Sgen, dotnet-Microsoft.XmlSerializer.Generator");
MethodInfo md = type.GetMethod("Main", BindingFlags.Static | BindingFlags.Public);
- string[] args = new string[] { "Microsoft.XmlSerializer.Generator.Tests.dll", "/force", "/quiet" };
+ string[] args = new string[] { "Microsoft.XmlSerializer.Generator.Tests.dll", "--force", "--quiet" };
int n = (int)md.Invoke(null, new object[] { args });
Assert.Equal(0, n);
Assert.True(File.Exists(codefile), string.Format("Fail to generate {0}.", codefile));
diff --git a/src/Native/Unix/CMakeLists.txt b/src/Native/Unix/CMakeLists.txt
index c3e9bffeaf..7d804a1e54 100644
--- a/src/Native/Unix/CMakeLists.txt
+++ b/src/Native/Unix/CMakeLists.txt
@@ -148,6 +148,18 @@ if(CMAKE_SYSTEM_NAME STREQUAL SunOS)
set(CLR_CMAKE_PLATFORM_UNIX 1)
endif(CMAKE_SYSTEM_NAME STREQUAL SunOS)
+# CLR_ADDITIONAL_LINKER_FLAGS - used for passing additional arguments to linker
+# CLR_ADDITIONAL_COMPILER_OPTIONS - used for passing additional arguments to compiler
+#
+# For example:
+# ./build-native.sh cmakeargs -DCLR_ADDITIONAL_COMPILER_OPTIONS=<...> cmakeargs -DCLR_ADDITIONAL_LINKER_FLAGS=<...>
+#
+if(CLR_CMAKE_PLATFORM_UNIX)
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${CLR_ADDITIONAL_LINKER_FLAGS}")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${CLR_ADDITIONAL_LINKER_FLAGS}" )
+ add_compile_options(${CLR_ADDITIONAL_COMPILER_OPTIONS})
+endif(CLR_CMAKE_PLATFORM_UNIX)
+
if (NOT WIN32)
if (CMAKE_SYSTEM_NAME STREQUAL Darwin)
# Ensure that dsymutil and strip are present
@@ -247,6 +259,9 @@ add_subdirectory(System.IO.Compression.Native)
add_compile_options(-Weverything)
add_compile_options(-Wno-c++98-compat-pedantic)
+if (HAVE_ZERO_AS_NULL_POINTER_CONSTANT_FLAG)
+ add_compile_options(-Wno-zero-as-null-pointer-constant)
+endif()
add_subdirectory(System.Native)
add_subdirectory(System.Net.Http.Native)
diff --git a/src/Native/Unix/Common/pal_config.h.in b/src/Native/Unix/Common/pal_config.h.in
index 354726fd3c..6099d2f32c 100644
--- a/src/Native/Unix/Common/pal_config.h.in
+++ b/src/Native/Unix/Common/pal_config.h.in
@@ -38,12 +38,9 @@
#cmakedefine01 HAVE_SENDFILE_4
#cmakedefine01 HAVE_SENDFILE_6
#cmakedefine01 HAVE_FCOPYFILE
-#cmakedefine01 HAVE_GETHOSTBYNAME_R
-#cmakedefine01 HAVE_GETHOSTBYADDR_R
#cmakedefine01 HAVE_GETNAMEINFO_SIGNED_FLAGS
#cmakedefine01 HAVE_GETPEEREID
#cmakedefine01 HAVE_SUPPORT_FOR_DUAL_MODE_IPV4_PACKET_INFO
-#cmakedefine01 HAVE_THREAD_SAFE_GETHOSTBYNAME_AND_GETHOSTBYADDR
#cmakedefine01 HAVE_TCGETATTR
#cmakedefine01 HAVE_TCSETATTR
#cmakedefine01 HAVE_ECHO
@@ -62,7 +59,7 @@
#cmakedefine01 HAVE_MACH_ABSOLUTE_TIME
#cmakedefine01 HAVE_MACH_TIMEBASE_INFO
#cmakedefine01 HAVE_CURLM_ADDED_ALREADY
-#cmakedefine01 HAVE_CURL_HTTP_VERSION_2_0
+#cmakedefine01 HAVE_CURL_HTTP_VERSION_2TLS
#cmakedefine01 HAVE_CURLPIPE_MULTIPLEX
#cmakedefine01 HAVE_CURL_SSLVERSION_TLSv1_012
#cmakedefine01 HAVE_TCP_H_TCPSTATE_ENUM
diff --git a/src/Native/Unix/System.Native/CMakeLists.txt b/src/Native/Unix/System.Native/CMakeLists.txt
index 9b36d9ae51..00ad9410e1 100644
--- a/src/Native/Unix/System.Native/CMakeLists.txt
+++ b/src/Native/Unix/System.Native/CMakeLists.txt
@@ -14,6 +14,7 @@ set(NATIVE_SOURCES
pal_random.cpp
pal_runtimeinformation.cpp
pal_runtimeextensions.cpp
+ pal_signal.c
pal_string.cpp
pal_tcpstate.c
pal_time.cpp
diff --git a/src/Native/Unix/System.Native/pal_console.cpp b/src/Native/Unix/System.Native/pal_console.cpp
index 2a7454e7a2..0bb51d2606 100644
--- a/src/Native/Unix/System.Native/pal_console.cpp
+++ b/src/Native/Unix/System.Native/pal_console.cpp
@@ -4,14 +4,12 @@
#include "pal_config.h"
#include "pal_console.h"
-#include "pal_io.h"
#include "pal_utilities.h"
+#include "pal_signal.h"
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
-#include <pthread.h>
-#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -80,8 +78,11 @@ static struct termios g_initTermios = {}; // the initial attributes captured
static struct termios g_preReadTermios = {}; // the original attributes captured before a read; valid if g_readInProgress is true
static struct termios g_currTermios = {}; // the current attributes set during a read; valid if g_readInProgress is true
-static void UninitializeConsole()
+void UninitializeConsole()
{
+ // pal_signal.cpp calls this on SIGQUIT/SIGINT.
+ // This can happen when SystemNative_InitializeConsole was not called.
+
// Put the attributes back to what they were when the console was initially initialized.
// We only do so, however, if we have explicitly modified the termios; doing so always
// can result in problems if the app is in the background, as then attempting to call
@@ -107,7 +108,7 @@ static void IncorporateBreak(struct termios *termios, int32_t signalForBreak)
termios->c_lflag &= static_cast<uint32_t>(~ISIG);
}
-// In order to support Console.ReadKey(intecept: true), we need to disable echo and canonical mode.
+// In order to support Console.ReadKey(intercept: true), we need to disable echo and canonical mode.
// We have two main choices: do so for the entire app, or do so only while in the Console.ReadKey(true).
// The former has a huge downside: the terminal is in a non-echo state, so anything else that runs
// in the same terminal won't echo even if it expects to, e.g. using Process.Start to launch an interactive,
@@ -300,36 +301,11 @@ extern "C" int32_t SystemNative_SetSignalForBreak(int32_t signalForBreak)
return 0;
}
-static struct sigaction g_origSigIntHandler, g_origSigQuitHandler; // saved signal handlers for ctrl handling
-static struct sigaction g_origSigContHandler, g_origSigChldHandler; // saved signal handlers for reinitialization
-static volatile CtrlCallback g_ctrlCallback = nullptr; // Callback invoked for SIGINT/SIGQUIT
-static int g_signalPipe[2] = {-1, -1}; // Pipe used between signal handler and worker
-
-// Signal handler for signals where we want our background thread to do the real processing.
-// It simply writes the signal code to a pipe that's read by the thread.
-static void TransferSignalToHandlerLoop(int sig, siginfo_t* siginfo, void* context)
-{
- (void)siginfo; // unused
- (void)context; // unused
-
- // Write the signal code to the pipe
- uint8_t signalCodeByte = static_cast<uint8_t>(sig);
- ssize_t writtenBytes;
- while (CheckInterrupted(writtenBytes = write(g_signalPipe[1], &signalCodeByte, 1)));
-
- if (writtenBytes != 1)
- {
- abort(); // fatal error
- }
-}
-
-static void HandleSignalForReinitialize(int sig, siginfo_t* siginfo, void* context)
+void ReinitializeConsole()
{
- // SIGCONT will be sent when we're resumed after suspension, at which point
- // we need to set the terminal back up. Similarly, SIGCHLD will be sent after
- // a child process completes, and that child could have left things in a bad state,
- // so we similarly need to reinitialize.
- assert(sig == SIGCONT || sig == SIGCHLD);
+ // pal_signal.cpp calls this on SIGCONT/SIGCHLD.
+ // This can happen when SystemNative_InitializeConsole was not called.
+ // This gets called on a signal handler, we may only use async-signal-safe functions.
// If the process was suspended while reading, we need to
// re-initialize the console for the read, as the attributes
@@ -342,172 +318,15 @@ static void HandleSignalForReinitialize(int sig, siginfo_t* siginfo, void* conte
// "Application mode" will also have been reset and needs to be redone.
WriteKeypadXmit();
-
- // Delegate to any saved handler we may have
- struct sigaction origHandler = sig == SIGCONT ? g_origSigContHandler : g_origSigChldHandler;
- if (origHandler.sa_sigaction != nullptr &&
- reinterpret_cast<void*>(origHandler.sa_sigaction) != reinterpret_cast<void*>(SIG_DFL) &&
- reinterpret_cast<void*>(origHandler.sa_sigaction) != reinterpret_cast<void*>(SIG_IGN))
- {
- origHandler.sa_sigaction(sig, siginfo, context);
- }
}
-// Entrypoint for the thread that handles signals where our handling
-// isn't signal-safe. Those signal handlers write the signal to a pipe,
-// which this loop reads and processes.
-void* SignalHandlerLoop(void* arg)
-{
- // Passed in argument is a ptr to the file descriptor
- // for the read end of the pipe.
- assert(arg != nullptr);
- int pipeFd = *reinterpret_cast<int*>(arg);
- free(arg);
- assert(pipeFd >= 0);
-
- // Continually read a signal code from the signal pipe and process it,
- // until the pipe is closed.
- while (true)
- {
- // Read the next signal, trying again if we were interrupted
- uint8_t signalCode;
- ssize_t bytesRead;
- while (CheckInterrupted(bytesRead = read(pipeFd, &signalCode, 1)));
-
- if (bytesRead <= 0)
- {
- // Write end of pipe was closed or another error occurred.
- // Regardless, no more data is available, so we close the read
- // end of the pipe and exit.
- close(pipeFd);
- return nullptr;
- }
-
- assert_msg(signalCode == SIGQUIT || signalCode == SIGINT, "invalid signalCode", static_cast<int>(signalCode));
-
- // We're now handling SIGQUIT and SIGINT. Invoke the callback, if we have one.
- CtrlCallback callback = g_ctrlCallback;
- int rv = callback != nullptr ? callback(signalCode == SIGQUIT ? Break : Interrupt) : 0;
- if (rv == 0) // callback removed or was invoked and didn't handle the signal
- {
- // In general, we now want to remove our handler and reissue the signal to
- // be picked up by the previously registered handler. In the most common case,
- // this will be the default handler, causing the process to be torn down.
- // It could also be a custom handle registered by other code before us.
-
- if (signalCode == SIGINT)
- {
- UninitializeConsole();
- sigaction(SIGINT, &g_origSigIntHandler, NULL);
- kill(getpid(), SIGINT);
- }
- else if (signalCode == SIGQUIT)
- {
- UninitializeConsole();
- sigaction(SIGQUIT, &g_origSigQuitHandler, NULL);
- kill(getpid(), SIGQUIT);
- }
-
- }
- }
-}
-
-static void CloseSignalHandlingPipe()
-{
- assert(g_signalPipe[0] >= 0);
- assert(g_signalPipe[1] >= 0);
- close(g_signalPipe[0]);
- close(g_signalPipe[1]);
- g_signalPipe[0] = -1;
- g_signalPipe[1] = -1;
-}
-
-static bool InitializeSignalHandling()
+extern "C" int32_t SystemNative_InitializeConsole()
{
- // Create a pipe we'll use to communicate with our worker
- // thread. We can't do anything interesting in the signal handler,
- // so we instead send a message to another thread that'll do
- // the handling work.
- if (SystemNative_Pipe(g_signalPipe, PAL_O_CLOEXEC) != 0)
- {
- return false;
- }
- assert(g_signalPipe[0] >= 0);
- assert(g_signalPipe[1] >= 0);
-
- // Create a small object to pass the read end of the pipe to the worker.
- int* readFdPtr = reinterpret_cast<int*>(malloc(sizeof(int)));
- if (readFdPtr == nullptr)
- {
- CloseSignalHandlingPipe();
- errno = ENOMEM;
- return false;
- }
- *readFdPtr = g_signalPipe[0];
-
- // The pipe is created. Create the worker thread.
- pthread_t handlerThread;
- if (pthread_create(&handlerThread, nullptr, SignalHandlerLoop, readFdPtr) != 0)
+ if (!InitializeSignalHandling())
{
- int err = errno;
- free(readFdPtr);
- CloseSignalHandlingPipe();
- errno = err;
- return false;
+ return 0;
}
- // Finally, register our signal handlers
- struct sigaction newAction;
- memset(&newAction, 0, sizeof(struct sigaction));
- newAction.sa_flags = SA_RESTART | SA_SIGINFO;
-
- sigemptyset(&newAction.sa_mask);
- int rv;
-
- // Hook up signal handlers for use with ctrl-C / ctrl-Break handling
- // We don't handle ignored signals. If we'd setup a handler, our child processes
- // would reset to the default on exec causing them to terminate on these signals.
- newAction.sa_sigaction = &TransferSignalToHandlerLoop;
- rv = sigaction(SIGINT, NULL, &g_origSigIntHandler);
- assert(rv == 0);
- if (reinterpret_cast<void*>(g_origSigIntHandler.sa_sigaction) != reinterpret_cast<void*>(SIG_IGN))
- {
- rv = sigaction(SIGINT, &newAction, NULL);
- assert(rv == 0);
- }
- rv = sigaction(SIGQUIT, NULL, &g_origSigQuitHandler);
- assert(rv == 0);
- if (reinterpret_cast<void*>(g_origSigQuitHandler.sa_sigaction) != reinterpret_cast<void*>(SIG_IGN))
- {
- rv = sigaction(SIGQUIT, &newAction, NULL);
- assert(rv == 0);
- }
-
- // Hook up signal handlers for use with signals that require us to reinitialize the terminal
- newAction.sa_sigaction = &HandleSignalForReinitialize;
- rv = sigaction(SIGCONT, &newAction, &g_origSigContHandler);
- assert(rv == 0);
- rv = sigaction(SIGCHLD, &newAction, &g_origSigChldHandler);
- assert(rv == 0);
-
- return true;
-}
-
-extern "C" void SystemNative_RegisterForCtrl(CtrlCallback callback)
-{
- assert(callback != nullptr);
- assert(g_ctrlCallback == nullptr);
- g_ctrlCallback = callback;
-}
-
-extern "C" void SystemNative_UnregisterForCtrl()
-{
- assert(g_ctrlCallback != nullptr);
- g_ctrlCallback = nullptr;
-}
-
-extern "C" int32_t SystemNative_InitializeConsole()
-{
if (tcgetattr(STDIN_FILENO, &g_initTermios) >= 0)
{
g_haveInitTermios = true;
@@ -520,7 +339,5 @@ extern "C" int32_t SystemNative_InitializeConsole()
}
atexit(UninitializeConsole);
- // Do all initialization needed for the console. Right now that's just
- // initializing the signal handling thread.
- return InitializeSignalHandling() ? 1 : 0;
+ return 1;
}
diff --git a/src/Native/Unix/System.Native/pal_console.h b/src/Native/Unix/System.Native/pal_console.h
index 2417ae7055..81b10008bb 100644
--- a/src/Native/Unix/System.Native/pal_console.h
+++ b/src/Native/Unix/System.Native/pal_console.h
@@ -4,6 +4,10 @@
#pragma once
+#include "pal_compiler.h"
+
+BEGIN_EXTERN_C
+
#include "pal_types.h"
/**
@@ -46,7 +50,7 @@ struct WinSize
*
* Returns 0 on success; otherwise, returns errorNo.
*/
-extern "C" int32_t SystemNative_GetWindowSize(WinSize* windowsSize);
+int32_t SystemNative_GetWindowSize(struct WinSize* windowsSize);
/**
* Gets whether the specified file descriptor is for a terminal.
@@ -54,14 +58,14 @@ extern "C" int32_t SystemNative_GetWindowSize(WinSize* windowsSize);
* Returns 1 if the file descriptor is referring to a terminal;
* otherwise returns 0 and sets errno.
*/
-extern "C" int32_t SystemNative_IsATty(intptr_t fd);
+int32_t SystemNative_IsATty(intptr_t fd);
/**
* Initializes the console for use by System.Console.
*
* Returns 1 on success; otherwise returns 0 and sets errno.
*/
-extern "C" int32_t SystemNative_InitializeConsole();
+int32_t SystemNative_InitializeConsole(void);
/**
* Stores the string that can be written to stdout to transition
@@ -69,7 +73,7 @@ extern "C" int32_t SystemNative_InitializeConsole();
*
* Returns 1 on success; otherwise returns 0 and sets errno.
*/
-extern "C" void SystemNative_SetKeypadXmit(const char* terminfoString);
+void SystemNative_SetKeypadXmit(const char* terminfoString);
/**
* Gets the special control character codes for the requested control characters.
@@ -79,35 +83,35 @@ extern "C" void SystemNative_SetKeypadXmit(const char* terminfoString);
* or 0 if a particular name is unsupported or disabled. posixDisableValue is the special sentinel used in the output
* controlCharacterValues array to indicate no value is available.
*/
-extern "C" void SystemNative_GetControlCharacters(
+void SystemNative_GetControlCharacters(
int32_t* controlCharacterNames, uint8_t* controlCharacterValues, int32_t controlCharacterLength,
uint8_t* posixDisableValue);
/**
* Returns 1 if any input is waiting on stdin; otherwise, 0.
*/
-extern "C" int32_t SystemNative_StdinReady();
+int32_t SystemNative_StdinReady(void);
/**
* Initializes the terminal in preparation for a read operation.
*/
-extern "C" void SystemNative_InitializeConsoleBeforeRead(uint8_t minChars, uint8_t decisecondsTimeout);
+void SystemNative_InitializeConsoleBeforeRead(uint8_t minChars, uint8_t decisecondsTimeout);
/**
* Restores the terminal's attributes to what they were before InitializeConsoleBeforeRead was called.
*/
-extern "C" void SystemNative_UninitializeConsoleAfterRead();
+void SystemNative_UninitializeConsoleAfterRead(void);
/**
* Reads the number of bytes specified into the provided buffer from stdin.
* Returns the number of bytes read on success; otherwise, -1 is returned an errno is set.
*/
-extern "C" int32_t SystemNative_ReadStdin(void* buffer, int32_t bufferSize);
+int32_t SystemNative_ReadStdin(void* buffer, int32_t bufferSize);
/**
* Gets the terminal's break mode.
*/
-extern "C" int32_t SystemNative_GetSignalForBreak();
+int32_t SystemNative_GetSignalForBreak(void);
/**
* Configures the terminal's break mode.
@@ -116,34 +120,23 @@ extern "C" int32_t SystemNative_GetSignalForBreak();
*
* Returns 1 on success, 0 on failure, in which case errno is set.
*/
-extern "C" int32_t SystemNative_SetSignalForBreak(int32_t signalForBreak);
+int32_t SystemNative_SetSignalForBreak(int32_t signalForBreak);
-enum CtrlCode : int32_t
+enum CtrlCode
{
Interrupt = 0,
Break = 1
};
-typedef int32_t (*CtrlCallback)(CtrlCode signalCode);
-
+typedef int32_t (*CtrlCallback)(enum CtrlCode signalCode);
/**
- * Hooks up the specified callback for notifications when SIGINT or SIGQUIT is received.
- *
- * Not thread safe. Caller must provide its owns synchronization to ensure RegisterForCtrl
- * is not called concurrently with itself or with UnregisterForCtrl.
- *
- * Should only be called when a callback is not currently registered.
+ * Called by pal_signal.cpp to reinitialize the console on SIGCONT/SIGCHLD.
*/
-extern "C" void SystemNative_RegisterForCtrl(CtrlCallback callback);
+void ReinitializeConsole(void);
/**
- * Unregisters the previously registered ctrlCCallback.
- *
- * Not thread safe. Caller must provide its owns synchronization to ensure UnregisterForCtrl
- * is not called concurrently with itself or with RegisterForCtrl.
- *
- * Should only be called when a callback is currently registered. The pointer
- * previously registered must remain valid until all ctrl handling activity
- * has quiesced.
+ * Called by pal_signal.cpp to uninitialize the console on SIGINT/SIGQUIT.
*/
-extern "C" void SystemNative_UnregisterForCtrl();
+void UninitializeConsole(void);
+
+END_EXTERN_C
diff --git a/src/Native/Unix/System.Native/pal_networking.c b/src/Native/Unix/System.Native/pal_networking.c
index 297830c124..eb79842288 100644
--- a/src/Native/Unix/System.Native/pal_networking.c
+++ b/src/Native/Unix/System.Native/pal_networking.c
@@ -7,6 +7,7 @@
#include "pal_io.h"
#include "pal_safecrt.h"
#include "pal_utilities.h"
+#include <fcntl.h>
#include <stdlib.h>
#include <limits.h>
@@ -43,6 +44,10 @@
#elif HAVE_SENDFILE_6
#include <sys/uio.h>
#endif
+#if !HAVE_IN_PKTINFO
+#include <net/if.h>
+#include <ifaddrs.h>
+#endif
#if HAVE_KQUEUE
#if KEVENT_HAS_VOID_UDATA
@@ -123,12 +128,6 @@ enum
enum
{
- HOST_ENTRY_HANDLE_ADDRINFO = 1,
- HOST_ENTRY_HANDLE_HOSTENT = 2,
-};
-
-enum
-{
INET6_ADDRSTRLEN_MANAGED = 65 // Managed code has a longer max IPv6 string length
};
@@ -236,9 +235,8 @@ int32_t SystemNative_GetHostEntryForName(const uint8_t* address, struct HostEntr
entry->CanonicalName = NULL;
entry->Aliases = NULL;
- entry->AddressListHandle = (void*)info;
- entry->IPAddressCount = 0;
- entry->HandleType = HOST_ENTRY_HANDLE_ADDRINFO;
+ entry->AddressListHandle = info;
+ entry->IPAddressCount = 0;
// Find the canonical name for this host (if any) and count the number of IP end points.
for (struct addrinfo* ai = info; ai != NULL; ai = ai->ai_next)
@@ -258,325 +256,6 @@ int32_t SystemNative_GetHostEntryForName(const uint8_t* address, struct HostEntr
return GetAddrInfoErrorFlags_EAI_SUCCESS;
}
-static int ConvertGetHostErrorPlatformToPal(int error)
-{
- switch (error)
- {
- case HOST_NOT_FOUND:
- return GetHostErrorCodes_HOST_NOT_FOUND;
-
- case TRY_AGAIN:
- return GetHostErrorCodes_TRY_AGAIN;
-
- case NO_RECOVERY:
- return GetHostErrorCodes_NO_RECOVERY;
-
- case NO_DATA:
- return GetHostErrorCodes_NO_DATA;
-
- default:
- assert_err(0, "Unknown gethostbyname/gethostbyaddr error code", error);
- return GetHostErrorCodes_HOST_NOT_FOUND;
- }
-}
-
-static void ConvertHostEntPlatformToPal(struct HostEntry* hostEntry, struct hostent* entry)
-{
- hostEntry->CanonicalName = (uint8_t*)entry->h_name;
- hostEntry->Aliases = (uint8_t**)entry->h_aliases;
- hostEntry->AddressListHandle = (void*)entry;
- hostEntry->IPAddressCount = 0;
- hostEntry->HandleType = HOST_ENTRY_HANDLE_HOSTENT;
-
- for (int i = 0; entry->h_addr_list[i] != NULL; i++)
- {
- hostEntry->IPAddressCount++;
- }
-}
-
-#if !HAVE_THREAD_SAFE_GETHOSTBYNAME_AND_GETHOSTBYADDR
-#if !HAVE_GETHOSTBYNAME_R
-static int copy_hostent(struct hostent* from, struct hostent* to,
- char* buffer, size_t buflen)
-{
- // FIXME: the implementation done for this function in https://github.com/dotnet/corefx/commit/6a99b74
- // requires testing when managed assemblies are built and tested on NetBSD. Until that time,
- // return an error code.
- (void)from; // unused arg
- (void)to; // unused arg
- (void)buffer; // unused arg
- (void)buflen; // unused arg
- return ENOSYS;
-}
-
-/*
-Note: we're assuming that all access to these functions are going through these shims on the platforms, which do not provide
- thread-safe functions to get host name or address. If that is not the case (which is very likely) race condition is
- possible, for instance; if other libs (such as libcurl) call gethostby[name/addr] simultaneously.
-*/
-static pthread_mutex_t lock_hostbyx_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static int gethostbyname_r(char const* hostname, struct hostent* result,
- char* buffer, size_t buflen, struct hostent** entry, int* error)
-{
- assert(hostname != NULL);
- assert(result != NULL);
- assert(buffer != NULL);
- assert(entry != NULL);
- assert(error != NULL);
-
- if (hostname == NULL || entry == NULL || error == NULL || buffer == NULL || result == NULL)
- {
- if (error != NULL)
- {
- *error = GetHostErrorCodes_BAD_ARG;
- }
-
- return GetHostErrorCodes_BAD_ARG;
- }
-
- pthread_mutex_lock(&lock_hostbyx_mutex);
-
- *entry = gethostbyname(hostname);
- if ((!(*entry)) || ((*entry)->h_addrtype != AF_INET) || ((*entry)->h_length != 4))
- {
- *error = h_errno;
- *entry = NULL;
- }
- else
- {
- h_errno = copy_hostent(*entry, result, buffer, buflen);
- *entry = (h_errno == 0) ? result : NULL;
- }
-
- pthread_mutex_unlock(&lock_hostbyx_mutex);
-
- return h_errno;
-}
-
-static int gethostbyaddr_r(const uint8_t* addr, const socklen_t len, int type, struct hostent* result,
- char* buffer, size_t buflen, struct hostent** entry, int* error)
-{
- assert(addr != NULL);
- assert(result != NULL);
- assert(buffer != NULL);
- assert(entry != NULL);
- assert(error != NULL);
-
- if (addr == NULL || entry == NULL || buffer == NULL || result == NULL)
- {
- if (error != NULL)
- {
- *error = GetHostErrorCodes_BAD_ARG;
- }
-
- return GetHostErrorCodes_BAD_ARG;
- }
-
- pthread_mutex_lock(&lock_hostbyx_mutex);
-
- *entry = gethostbyaddr((const char*)addr, (unsigned int)len, type);
- if ((!(*entry)) || ((*entry)->h_addrtype != AF_INET) || ((*entry)->h_length != 4))
- {
- *error = h_errno;
- *entry = NULL;
- }
- else
- {
- h_errno = copy_hostent(*entry, result, buffer, buflen);
- *entry = (h_errno == 0) ? result : NULL;
- }
-
- pthread_mutex_unlock(&lock_hostbyx_mutex);
-
- return h_errno;
-}
-#undef HAVE_GETHOSTBYNAME_R
-#undef HAVE_GETHOSTBYADDR_R
-#define HAVE_GETHOSTBYNAME_R 1
-#define HAVE_GETHOSTBYADDR_R 1
-#endif /* !HAVE_GETHOSTBYNAME_R */
-
-#if HAVE_GETHOSTBYNAME_R
-static int GetHostByNameHelper(const uint8_t* hostname, struct hostent** entry)
-{
- assert(hostname != NULL);
- assert(entry != NULL);
-
- size_t scratchLen = 512;
-
- for (;;)
- {
- size_t bufferSize;
- uint8_t* buffer;
- if (!add_s(sizeof(struct hostent), scratchLen, &bufferSize) ||
- (buffer = (uint8_t*)malloc(bufferSize)) == NULL)
- {
- return GetHostErrorCodes_NO_MEM;
- }
-
- struct hostent* result = (struct hostent*)buffer;
- char* scratch = (char*)&buffer[sizeof(struct hostent)];
-
- int getHostErrno = 0;
- int err = gethostbyname_r((const char*)hostname, result, scratch, scratchLen, entry, &getHostErrno);
- if (!err && *entry != NULL)
- {
- assert(*entry == result);
- return 0;
- }
- else if (err == ERANGE)
- {
- free(buffer);
- size_t tmpScratchLen;
- if (!multiply_s(scratchLen, (size_t)2, &tmpScratchLen))
- {
- *entry = NULL;
- return GetHostErrorCodes_NO_MEM;
- }
- scratchLen = tmpScratchLen;
- }
- else
- {
- free(buffer);
- *entry = NULL;
- return getHostErrno ? getHostErrno : HOST_NOT_FOUND;
- }
- }
-}
-#endif /* HAVE_GETHOSTBYNAME_R */
-#endif /* !HAVE_THREAD_SAFE_GETHOSTBYNAME_AND_GETHOSTBYADDR */
-
-int32_t SystemNative_GetHostByName(const uint8_t* hostname, struct HostEntry* entry)
-{
- if (hostname == NULL || entry == NULL)
- {
- return GetHostErrorCodes_BAD_ARG;
- }
-
- struct hostent* hostEntry = NULL;
- int error = 0;
-
-#if HAVE_THREAD_SAFE_GETHOSTBYNAME_AND_GETHOSTBYADDR
- hostEntry = gethostbyname((const char*)hostname);
- error = h_errno;
-#elif HAVE_GETHOSTBYNAME_R
- error = GetHostByNameHelper(hostname, &hostEntry);
-#else
-#error Platform does not provide thread-safe gethostbyname
-#endif
-
- if (hostEntry == NULL)
- {
- return ConvertGetHostErrorPlatformToPal(error);
- }
-
- ConvertHostEntPlatformToPal(entry, hostEntry);
- return Error_SUCCESS;
-}
-
-#if !HAVE_THREAD_SAFE_GETHOSTBYNAME_AND_GETHOSTBYADDR && HAVE_GETHOSTBYADDR_R
-static int GetHostByAddrHelper(const uint8_t* addr, const socklen_t addrLen, int type, struct hostent** entry)
-{
- assert(addr != NULL);
- assert(addrLen >= 0);
- assert(entry != NULL);
-
- size_t scratchLen = 512;
-
- for (;;)
- {
- size_t bufferSize;
- uint8_t* buffer;
- if (!add_s(sizeof(struct hostent), scratchLen, &bufferSize) ||
- (buffer = (uint8_t*)malloc(bufferSize)) == NULL)
- {
- return GetHostErrorCodes_NO_MEM;
- }
-
- struct hostent* result = (struct hostent*)buffer;
- char* scratch = (char*)&buffer[sizeof(struct hostent)];
-
- int getHostErrno = 0;
- int err = gethostbyaddr_r(addr, addrLen, type, result, scratch, scratchLen, entry, &getHostErrno);
- if (!err && *entry != NULL)
- {
- assert(*entry == result);
- return 0;
- }
- else if (err == ERANGE)
- {
- free(buffer);
- size_t tmpScratchLen;
- if (!multiply_s(scratchLen, (size_t)2, &tmpScratchLen))
- {
- *entry = NULL;
- return GetHostErrorCodes_NO_MEM;
- }
- scratchLen = tmpScratchLen;
- }
- else
- {
- free(buffer);
- *entry = NULL;
- return getHostErrno ? getHostErrno : HOST_NOT_FOUND;
- }
- }
-}
-#endif /* !HAVE_THREAD_SAFE_GETHOSTBYNAME_AND_GETHOSTBYADDR && HAVE_GETHOSTBYADDR_R */
-
-int32_t SystemNative_GetHostByAddress(const struct IPAddress* address, struct HostEntry* entry)
-{
- if (address == NULL || entry == NULL)
- {
- return GetHostErrorCodes_BAD_ARG;
- }
-
- uint8_t* addr = NULL;
- socklen_t addrLen = 0;
- int type = AF_UNSPEC;
-
- struct in_addr inAddr;
- memset(&inAddr, 0, sizeof(struct in_addr));
- struct in6_addr in6Addr;
- memset(&in6Addr, 0, sizeof(struct in6_addr));
-
- if (!address->IsIPv6)
- {
- ConvertByteArrayToInAddr(&inAddr, address->Address, NUM_BYTES_IN_IPV4_ADDRESS);
- addr = (uint8_t*)&inAddr;
- addrLen = sizeof(inAddr);
- type = AF_INET;
- }
- else
- {
- ConvertByteArrayToIn6Addr(&in6Addr, address->Address, NUM_BYTES_IN_IPV6_ADDRESS);
- addr = (uint8_t*)&in6Addr;
- addrLen = sizeof(in6Addr);
- type = AF_INET6;
- }
-
- struct hostent* hostEntry = NULL;
- int error = 0;
-
-#if HAVE_THREAD_SAFE_GETHOSTBYNAME_AND_GETHOSTBYADDR
- hostEntry = gethostbyaddr(addr, addrLen, type);
- error = h_errno;
-#elif HAVE_GETHOSTBYADDR_R
- error = GetHostByAddrHelper(addr, addrLen, type, &hostEntry);
-#else
-#error Platform does not provide thread-safe gethostbyname
-#endif
-
- if (hostEntry == NULL)
- {
- return ConvertGetHostErrorPlatformToPal(error);
- }
-
- ConvertHostEntPlatformToPal(entry, hostEntry);
- return Error_SUCCESS;
-}
-
static int32_t GetNextIPAddressFromAddrInfo(struct addrinfo** info, struct IPAddress* endPoint)
{
assert(info != NULL);
@@ -617,90 +296,21 @@ static int32_t GetNextIPAddressFromAddrInfo(struct addrinfo** info, struct IPAdd
return GetAddrInfoErrorFlags_EAI_NOMORE;
}
-static int32_t GetNextIPAddressFromHostEnt(struct hostent** hostEntry, struct IPAddress* address)
-{
- assert(hostEntry != NULL);
- assert(address != NULL);
-
- struct hostent* entry = *hostEntry;
- if (*entry->h_addr_list == NULL)
- {
- return GetAddrInfoErrorFlags_EAI_NOMORE;
- }
-
- switch (entry->h_addrtype)
- {
- case AF_INET:
- {
- struct in_addr* inAddr = (struct in_addr*)entry->h_addr_list[0];
-
- ConvertInAddrToByteArray(address->Address, NUM_BYTES_IN_IPV4_ADDRESS, inAddr);
- address->IsIPv6 = 0;
- break;
- }
-
- case AF_INET6:
- {
- struct in6_addr* in6Addr = (struct in6_addr*)entry->h_addr_list[0];
-
- ConvertIn6AddrToByteArray(address->Address, NUM_BYTES_IN_IPV6_ADDRESS, in6Addr);
- address->IsIPv6 = 1;
- address->ScopeId = 0;
- break;
- }
-
- default:
- return GetAddrInfoErrorFlags_EAI_NOMORE;
- }
-
- entry->h_addr_list = &entry->h_addr_list[1];
- return GetAddrInfoErrorFlags_EAI_SUCCESS;
-}
-
-int32_t SystemNative_GetNextIPAddress(const struct HostEntry* hostEntry, void** addressListHandle, struct IPAddress* endPoint)
+int32_t SystemNative_GetNextIPAddress(const struct HostEntry* hostEntry, struct addrinfo** addressListHandle, struct IPAddress* endPoint)
{
if (hostEntry == NULL || addressListHandle == NULL || endPoint == NULL)
{
return GetAddrInfoErrorFlags_EAI_BADARG;
}
-
- switch (hostEntry->HandleType)
- {
- case HOST_ENTRY_HANDLE_ADDRINFO:
- return GetNextIPAddressFromAddrInfo((struct addrinfo**)addressListHandle, endPoint);
-
- case HOST_ENTRY_HANDLE_HOSTENT:
- return GetNextIPAddressFromHostEnt((struct hostent**)addressListHandle, endPoint);
-
- default:
- return GetAddrInfoErrorFlags_EAI_BADARG;
- }
+
+ return GetNextIPAddressFromAddrInfo(addressListHandle, endPoint);
}
void SystemNative_FreeHostEntry(struct HostEntry* entry)
{
if (entry != NULL)
- {
- switch (entry->HandleType)
- {
- case HOST_ENTRY_HANDLE_ADDRINFO:
- {
- struct addrinfo* ai = (struct addrinfo*)entry->AddressListHandle;
- freeaddrinfo(ai);
- break;
- }
-
- case HOST_ENTRY_HANDLE_HOSTENT:
- {
-#if !HAVE_THREAD_SAFE_GETHOSTBYNAME_AND_GETHOSTBYADDR
- free(entry->AddressListHandle);
-#endif
- break;
- }
-
- default:
- break;
- }
+ {
+ freeaddrinfo(entry->AddressListHandle);
}
}
@@ -1173,11 +783,23 @@ static int32_t GetIPv4PacketInformation(struct cmsghdr* controlMessage, struct I
#if HAVE_IN_PKTINFO
packetInfo->InterfaceIndex = (int32_t)pktinfo->ipi_ifindex;
#else
- // TODO (#7855): Figure out how to get interface index with in_addr.
- // One option is http://www.unix.com/man-page/freebsd/3/if_nametoindex
- // which requires interface name to be known.
- // Meanwhile:
packetInfo->InterfaceIndex = 0;
+
+ struct ifaddrs* addrs;
+ if (getifaddrs(&addrs) == 0)
+ {
+ struct ifaddrs* addrs_head = addrs;
+ while (addrs != NULL)
+ {
+ if (addrs->ifa_addr->sa_family == AF_INET && ((struct sockaddr_in*)addrs->ifa_addr)->sin_addr.s_addr == pktinfo->ipi_addr.s_addr)
+ {
+ packetInfo->InterfaceIndex = (int32_t)if_nametoindex(addrs->ifa_name);
+ break;
+ }
+ addrs = addrs->ifa_next;
+ }
+ freeifaddrs(addrs_head);
+ }
#endif
return 1;
@@ -1207,13 +829,12 @@ struct cmsghdr* GET_CMSG_NXTHDR(struct msghdr* mhdr, struct cmsghdr* cmsg)
#ifndef __GLIBC__
// Tracking issue: #6312
// In musl-libc, CMSG_NXTHDR typecasts char* to struct cmsghdr* which causes
-// clang to throw cast-align warning. This is to suppress the warning
+// clang to throw sign-compare warning. This is to suppress the warning
// inline.
// There is also a problem in the CMSG_NXTHDR macro in musl-libc.
// It compares signed and unsigned value and clang warns about that.
// So we suppress the warning inline too.
#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wcast-align"
#pragma clang diagnostic ignored "-Wsign-compare"
#endif
return CMSG_NXTHDR(mhdr, cmsg);
@@ -1650,6 +1271,29 @@ int32_t SystemNative_Accept(intptr_t socket, uint8_t* socketAddress, int32_t* so
while ((accepted = accept4(fd, (struct sockaddr*)socketAddress, &addrLen, SOCK_CLOEXEC)) < 0 && errno == EINTR);
#else
while ((accepted = accept(fd, (struct sockaddr*)socketAddress, &addrLen)) < 0 && errno == EINTR);
+#if defined(FD_CLOEXEC)
+ // macOS does not have accept4 but it can set _CLOEXEC on descriptor.
+ // Unlike accept4 it is not atomic and the fd can leak child process.
+ if ((accepted != -1) && fcntl(accepted, F_SETFD, FD_CLOEXEC) != 0)
+ {
+ // Preserve and return errno from fcntl. close() may reset errno to OK.
+ int oldErrno = errno;
+ close(accepted);
+ accepted = -1;
+ errno = oldErrno;
+ }
+#endif
+#endif
+#if !defined(__linux__)
+ // On macOS and FreeBSD new socket inherits flags from accepting fd.
+ // Our socket code expects new socket to be in blocking mode by default.
+ if ((accepted != -1) && SystemNative_FcntlSetIsNonBlocking(accepted, 0) != 0)
+ {
+ int oldErrno = errno;
+ close(accepted);
+ accepted = -1;
+ errno = oldErrno;
+ }
#endif
if (accepted == -1)
{
@@ -2802,7 +2446,7 @@ int32_t SystemNative_SendFile(intptr_t out_fd, intptr_t in_fd, int64_t offset, i
return SystemNative_ConvertErrorPlatformToPal(errno);
}
-#else
+#else
// If we ever need to run on a platform that doesn't have sendfile,
// we can implement this with a simple read/send loop. For now,
// we just mark it as not supported.
diff --git a/src/Native/Unix/System.Native/pal_networking.h b/src/Native/Unix/System.Native/pal_networking.h
index d5fb40b392..29f7c1ebba 100644
--- a/src/Native/Unix/System.Native/pal_networking.h
+++ b/src/Native/Unix/System.Native/pal_networking.h
@@ -239,9 +239,8 @@ struct HostEntry
{
uint8_t* CanonicalName; // Canonical name of the host
uint8_t** Aliases; // List of aliases for the host
- void* AddressListHandle; // Handle for host socket addresses
+ struct addrinfo* AddressListHandle; // Handle for host socket addresses
int32_t IPAddressCount; // Number of IP end points in the list
- int32_t HandleType; // Indicates the type of the handle. Opaque to managed code.
};
struct IPPacketInformation
@@ -299,11 +298,7 @@ struct SocketEvent
int32_t SystemNative_GetHostEntryForName(const uint8_t* address, struct HostEntry* entry);
-int32_t SystemNative_GetHostByName(const uint8_t* hostname, struct HostEntry* entry);
-
-int32_t SystemNative_GetHostByAddress(const struct IPAddress* address, struct HostEntry* entry);
-
-int32_t SystemNative_GetNextIPAddress(const struct HostEntry* entry, void** addressListHandle, struct IPAddress* endPoint);
+int32_t SystemNative_GetNextIPAddress(const struct HostEntry* entry, struct addrinfo** addressListHandle, struct IPAddress* endPoint);
void SystemNative_FreeHostEntry(struct HostEntry* entry);
diff --git a/src/Native/Unix/System.Native/pal_process.cpp b/src/Native/Unix/System.Native/pal_process.cpp
index c98bad7036..4e12950113 100644
--- a/src/Native/Unix/System.Native/pal_process.cpp
+++ b/src/Native/Unix/System.Native/pal_process.cpp
@@ -32,10 +32,6 @@
// Validate that our Signals enum values are correct for the platform
static_assert(PAL_SIGKILL == SIGKILL, "");
-// Validate that our WaitPidOptions enum values are correct for the platform
-static_assert(PAL_WNOHANG == WNOHANG, "");
-static_assert(PAL_WUNTRACED == WUNTRACED, "");
-
// Validate that our SysLogPriority values are correct for the platform
static_assert(PAL_LOG_EMERG == LOG_EMERG, "");
static_assert(PAL_LOG_ALERT == LOG_ALERT, "");
@@ -151,6 +147,9 @@ extern "C" int32_t SystemNative_ForkAndExecProcess(const char* filename,
int32_t redirectStdin,
int32_t redirectStdout,
int32_t redirectStderr,
+ int32_t setCredentials,
+ uint32_t userId,
+ uint32_t groupId,
int32_t* childPid,
int32_t* stdinFd,
int32_t* stdoutFd,
@@ -170,7 +169,7 @@ extern "C" int32_t SystemNative_ForkAndExecProcess(const char* filename,
goto done;
}
- if ((redirectStdin & ~1) != 0 || (redirectStdout & ~1) != 0 || (redirectStderr & ~1) != 0)
+ if ((redirectStdin & ~1) != 0 || (redirectStdout & ~1) != 0 || (redirectStderr & ~1) != 0 || (setCredentials & ~1) != 0)
{
assert(false && "Boolean redirect* inputs must be 0 or 1.");
errno = EINVAL;
@@ -233,6 +232,14 @@ extern "C" int32_t SystemNative_ForkAndExecProcess(const char* filename,
ExitChild(waitForChildToExecPipe[WRITE_END_OF_PIPE], errno);
}
+ if (setCredentials)
+ {
+ if (setgid(groupId) == -1 || setuid(userId) == -1)
+ {
+ ExitChild(waitForChildToExecPipe[WRITE_END_OF_PIPE], errno);
+ }
+ }
+
// Change to the designated working directory, if one was specified
if (nullptr != cwd)
{
@@ -290,6 +297,13 @@ done:
CloseIfOpen(stdoutFds[READ_END_OF_PIPE]);
CloseIfOpen(stderrFds[READ_END_OF_PIPE]);
+ // Reap child
+ if (processId > 0)
+ {
+ int status;
+ waitpid(processId, &status, 0);
+ }
+
*stdinFd = -1;
*stdoutFd = -1;
*stderrFd = -1;
@@ -431,35 +445,38 @@ extern "C" void SystemNative_SysLog(SysLogPriority priority, const char* message
syslog(static_cast<int>(priority), message, arg1);
}
-extern "C" int32_t SystemNative_WaitPid(int32_t pid, int32_t* status, WaitPidOptions options)
+extern "C" int32_t SystemNative_WaitIdExitedNoHang(int32_t pid, int32_t* exitCode, int32_t keepWaitable)
{
- assert(status != nullptr);
+ assert(exitCode != nullptr);
+ siginfo_t siginfo;
int32_t result;
- while (CheckInterrupted(result = waitpid(pid, status, static_cast<int>(options))));
+ idtype_t idtype = pid == -1 ? P_ALL : P_PID;
+ int options = WEXITED | WNOHANG;
+ if (keepWaitable != 0)
+ {
+ options |= WNOWAIT;
+ }
+ while (CheckInterrupted(result = waitid(idtype, static_cast<id_t>(pid), &siginfo, options)));
+ if (idtype == P_ALL && result == -1 && errno == ECHILD)
+ {
+ result = 0;
+ }
+ else if (result == 0 && siginfo.si_signo == SIGCHLD)
+ {
+ if (siginfo.si_code == CLD_EXITED)
+ {
+ *exitCode = siginfo.si_status;
+ }
+ else
+ {
+ *exitCode = 128 + siginfo.si_status;
+ }
+ result = siginfo.si_pid;
+ }
return result;
}
-extern "C" int32_t SystemNative_WExitStatus(int32_t status)
-{
- return WEXITSTATUS(status);
-}
-
-extern "C" int32_t SystemNative_WIfExited(int32_t status)
-{
- return WIFEXITED(status);
-}
-
-extern "C" int32_t SystemNative_WIfSignaled(int32_t status)
-{
- return WIFSIGNALED(status);
-}
-
-extern "C" int32_t SystemNative_WTermSig(int32_t status)
-{
- return WTERMSIG(status);
-}
-
extern "C" int64_t SystemNative_PathConf(const char* path, PathConfName name)
{
int32_t confValue = -1;
diff --git a/src/Native/Unix/System.Native/pal_process.h b/src/Native/Unix/System.Native/pal_process.h
index cfa2ff423f..55b30accb5 100644
--- a/src/Native/Unix/System.Native/pal_process.h
+++ b/src/Native/Unix/System.Native/pal_process.h
@@ -26,6 +26,9 @@ SystemNative_ForkAndExecProcess(const char* filename, // filename argument to
int32_t redirectStdin, // whether to redirect standard input from the parent
int32_t redirectStdout, // whether to redirect standard output to the parent
int32_t redirectStderr, // whether to redirect standard error to the parent
+ int32_t setCredentials, // whether to set the userId and groupId for the child process
+ uint32_t userId, // the user id under which the child process should run
+ uint32_t groupId, // the group id under which the child process should run
int32_t* childPid, // [out] the child process' id
int32_t* stdinFd, // [out] if redirectStdin, the parent's fd for the child's stdin
int32_t* stdoutFd, // [out] if redirectStdout, the parent's fd for the child's stdout
@@ -71,15 +74,6 @@ enum Signals : int32_t
};
/**
- * Constants for passing to waitpid determining how waitpid behaves
- */
-enum WaitPidOptions : int32_t
-{
- PAL_WNOHANG = 1, /* don't block waiting */
- PAL_WUNTRACED = 2, /* report status of stopped children */
-};
-
-/**
* Constants for passing to the first parameter of syslog.
* These are a combination of flags where the lower bits are
* the priority and the higher bits are the facility. The lower
@@ -212,26 +206,13 @@ extern "C" int32_t SystemNative_GetSid(int32_t pid);
extern "C" void SystemNative_SysLog(SysLogPriority priority, const char* message, const char* arg1);
/**
- * Waits for child process(s) or gathers resource utilization information about child processes
+ * Waits for terminated child processes.
*
- * The return value from WaitPid can very greatly.
- * 1) returns the process id of a terminating or stopped child process
- * 2) if no children are waiting, -1 is returned and errno is set to ECHILD
- * 3) if WNOHANG is specified and there are no stopped or exited children, 0 is returned
- * 4) on error, -1 is returned and errno is set
+ * 1) returns the process id of a terminated child process
+ * 2) if no children are waiting, 0 is returned
+ * 3) on error, -1 is returned
*/
-extern "C" int32_t SystemNative_WaitPid(int32_t pid, int32_t* status, WaitPidOptions options);
-
-/**
- * The four functions below are wrappers around the platform-specific macros of the same name.
- */
-extern "C" int32_t SystemNative_WExitStatus(int32_t status);
-
-extern "C" int32_t SystemNative_WIfExited(int32_t status);
-
-extern "C" int32_t SystemNative_WIfSignaled(int32_t status);
-
-extern "C" int32_t SystemNative_WTermSig(int32_t status);
+extern "C" int32_t SystemNative_WaitIdExitedNoHang(int32_t pid, int32_t* exitCode, int32_t keepWaitable);
/**
* Gets the configurable limit or variable for system path or file descriptor options.
diff --git a/src/Native/Unix/System.Native/pal_random.cpp b/src/Native/Unix/System.Native/pal_random.cpp
index 74ad5c5674..e6bda4490a 100644
--- a/src/Native/Unix/System.Native/pal_random.cpp
+++ b/src/Native/Unix/System.Native/pal_random.cpp
@@ -20,72 +20,57 @@ extern "C" void SystemNative_GetNonCryptographicallySecureRandomBytes(uint8_t* b
{
assert(buffer != NULL);
- int rand_des;
- char buf;
+ static volatile int rand_des = -1;
long num = 0;
-
- static bool sMissingDevRandom;
static bool sMissingDevURandom;
static bool sInitializedMRand;
- int i = 0;
-
- if (i < bufferLength && !sMissingDevRandom)
+ if (!sMissingDevURandom)
{
- // request non-blocking access to avoid hangs if the /dev/random is exhausted
- // or just simply broken
- if ((rand_des = open("/dev/random", O_RDONLY | O_NONBLOCK)) == -1)
+ if (rand_des == -1)
{
- if (errno == ENOENT)
+ int fd;
+
+ do
{
- sMissingDevRandom = true;
+ fd = open("/dev/urandom", O_RDONLY, O_CLOEXEC);
}
+ while ((fd == -1) && (errno == EINTR));
- // Back off and try /dev/urandom.
- }
- else
- {
- for( ; i < bufferLength; i++)
+ if (fd != -1)
{
- if (read(rand_des, &buf, 1) < 1)
+ if (!__sync_bool_compare_and_swap(&rand_des, -1, fd))
{
- // the /dev/random pool has been exhausted. Fall back
- // to /dev/urandom for the remainder of the buffer.
- break;
+ // Another thread has already set the rand_des
+ close(fd);
}
-
- *(buffer + i) ^= buf;
}
-
- close(rand_des);
- }
- }
-
- if (i < bufferLength && !sMissingDevURandom)
- {
- if ((rand_des = open("/dev/urandom", O_RDONLY, 0)) == -1)
- {
- if (errno == ENOENT)
+ else if (errno == ENOENT)
{
sMissingDevURandom = true;
}
-
- // Back off and try mrand48.
}
- else
+
+ if (rand_des != -1)
{
- for( ; i < bufferLength; i++)
+ int32_t offset = 0;
+ do
{
- if (read(rand_des, &buf, 1) < 1)
+ ssize_t n = read(rand_des, buffer + offset , (size_t)(bufferLength - offset));
+ if (n == -1)
{
- // Fall back to srand48 for the remainder of the buffer.
+ if (errno == EINTR)
+ {
+ continue;
+ }
+
+ assert(false && "read from /dev/urandom has failed");
break;
}
- *(buffer + i) ^= buf;
+ offset += n;
}
-
- close(rand_des);
+ while (offset != bufferLength);
}
}
@@ -96,9 +81,9 @@ extern "C" void SystemNative_GetNonCryptographicallySecureRandomBytes(uint8_t* b
}
// always xor srand48 over the whole buffer to get some randomness
- // in case /dev/random is not really random
+ // in case /dev/urandom is not really random
- for(i = 0; i < bufferLength; i++)
+ for (int i = 0; i < bufferLength; i++)
{
if (i % 4 == 0)
{
diff --git a/src/Native/Unix/System.Native/pal_signal.c b/src/Native/Unix/System.Native/pal_signal.c
new file mode 100644
index 0000000000..00cc220cd2
--- /dev/null
+++ b/src/Native/Unix/System.Native/pal_signal.c
@@ -0,0 +1,291 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "pal_config.h"
+#include "pal_console.h"
+#include "pal_signal.h"
+#include "pal_io.h"
+#include "pal_utilities.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+static struct sigaction g_origSigIntHandler, g_origSigQuitHandler; // saved signal handlers for ctrl handling
+static struct sigaction g_origSigContHandler, g_origSigChldHandler; // saved signal handlers for reinitialization
+static volatile CtrlCallback g_ctrlCallback = NULL; // Callback invoked for SIGINT/SIGQUIT
+static volatile SigChldCallback g_sigChldCallback = NULL; // Callback invoked for SIGCHLD
+static int g_signalPipe[2] = {-1, -1}; // Pipe used between signal handler and worker
+
+static struct sigaction* OrigActionFor(int sig)
+{
+ switch (sig)
+ {
+ case SIGINT: return &g_origSigIntHandler;
+ case SIGQUIT: return &g_origSigQuitHandler;
+ case SIGCONT: return &g_origSigContHandler;
+ case SIGCHLD: return &g_origSigChldHandler;
+ }
+
+ assert(false);
+ return NULL;
+}
+
+static void SignalHandler(int sig, siginfo_t* siginfo, void* context)
+{
+ if (sig == SIGCONT || sig == SIGCHLD)
+ {
+ // SIGCONT will be sent when we're resumed after suspension, at which point
+ // we need to set the terminal back up. Similarly, SIGCHLD will be sent after
+ // a child process completes, and that child could have left things in a bad state,
+ // so we similarly need to reinitialize.
+ ReinitializeConsole();
+ }
+
+ // Signal handler for signals where we want our background thread to do the real processing.
+ // It simply writes the signal code to a pipe that's read by the thread.
+ if (sig == SIGQUIT || sig == SIGINT || sig == SIGCHLD)
+ {
+ // Write the signal code to the pipe
+ uint8_t signalCodeByte = (uint8_t)sig;
+ ssize_t writtenBytes;
+ while ((writtenBytes = write(g_signalPipe[1], &signalCodeByte, 1)) < 0 && errno == EINTR);
+
+ if (writtenBytes != 1)
+ {
+ abort(); // fatal error
+ }
+ }
+
+ // Delegate to any saved handler we may have
+ // We assume the original SIGCHLD handler will not reap our children.
+ if (sig == SIGCONT || sig == SIGCHLD)
+ {
+ struct sigaction* origHandler = OrigActionFor(sig);
+ if (origHandler->sa_sigaction != NULL &&
+ (void*)origHandler->sa_sigaction != (void*)SIG_DFL &&
+ (void*)origHandler->sa_sigaction != (void*)SIG_IGN)
+ {
+ origHandler->sa_sigaction(sig, siginfo, context);
+ }
+ }
+}
+
+// Entrypoint for the thread that handles signals where our handling
+// isn't signal-safe. Those signal handlers write the signal to a pipe,
+// which this loop reads and processes.
+void* SignalHandlerLoop(void* arg)
+{
+ // Passed in argument is a ptr to the file descriptor
+ // for the read end of the pipe.
+ assert(arg != NULL);
+ int pipeFd = *(int*)arg;
+ free(arg);
+ assert(pipeFd >= 0);
+
+ // Continually read a signal code from the signal pipe and process it,
+ // until the pipe is closed.
+ while (true)
+ {
+ // Read the next signal, trying again if we were interrupted
+ uint8_t signalCode;
+ ssize_t bytesRead;
+ while ((bytesRead = read(pipeFd, &signalCode, 1)) < 0 && errno == EINTR);
+
+ if (bytesRead <= 0)
+ {
+ // Write end of pipe was closed or another error occurred.
+ // Regardless, no more data is available, so we close the read
+ // end of the pipe and exit.
+ close(pipeFd);
+ return NULL;
+ }
+
+ if (signalCode == SIGQUIT || signalCode == SIGINT)
+ {
+ // We're now handling SIGQUIT and SIGINT. Invoke the callback, if we have one.
+ CtrlCallback callback = g_ctrlCallback;
+ int rv = callback != NULL ? callback(signalCode == SIGQUIT ? Break : Interrupt) : 0;
+ if (rv == 0) // callback removed or was invoked and didn't handle the signal
+ {
+ // In general, we now want to remove our handler and reissue the signal to
+ // be picked up by the previously registered handler. In the most common case,
+ // this will be the default handler, causing the process to be torn down.
+ // It could also be a custom handler registered by other code before us.
+ UninitializeConsole();
+ sigaction(signalCode, OrigActionFor(signalCode), NULL);
+ kill(getpid(), signalCode);
+ }
+ }
+ else if (signalCode == SIGCHLD)
+ {
+ // When the original disposition is SIG_IGN, children that terminated did not become zombies.
+ // Since we overwrote the disposition, we have become responsible for reaping those processes.
+ bool reapAll = (void*)OrigActionFor(signalCode)->sa_sigaction == (void*)SIG_IGN;
+ SigChldCallback callback = g_sigChldCallback;
+
+ // double-checked locking
+ if (callback == NULL && reapAll)
+ {
+ // avoid race with SystemNative_RegisterForSigChld
+ pthread_mutex_lock(&lock);
+ {
+ callback = g_sigChldCallback;
+ if (callback == NULL)
+ {
+ pid_t pid;
+ do
+ {
+ int status;
+ while ((pid = waitpid(-1, &status, WNOHANG)) < 0 && errno == EINTR);
+ } while (pid > 0);
+ }
+ }
+ }
+
+ if (callback != NULL)
+ {
+ callback(reapAll ? 1 : 0);
+ }
+ }
+ else
+ {
+ assert_msg(false, "invalid signalCode", (int)signalCode);
+ }
+ }
+}
+
+static void CloseSignalHandlingPipe()
+{
+ assert(g_signalPipe[0] >= 0);
+ assert(g_signalPipe[1] >= 0);
+ close(g_signalPipe[0]);
+ close(g_signalPipe[1]);
+ g_signalPipe[0] = -1;
+ g_signalPipe[1] = -1;
+}
+
+void SystemNative_RegisterForCtrl(CtrlCallback callback)
+{
+ assert(callback != NULL);
+ assert(g_ctrlCallback == NULL);
+ g_ctrlCallback = callback;
+}
+
+void SystemNative_UnregisterForCtrl()
+{
+ assert(g_ctrlCallback != NULL);
+ g_ctrlCallback = NULL;
+}
+
+uint32_t SystemNative_RegisterForSigChld(SigChldCallback callback)
+{
+ if (!InitializeSignalHandling())
+ {
+ return 0;
+ }
+
+ assert(callback != NULL);
+ assert(g_sigChldCallback == NULL);
+
+ pthread_mutex_lock(&lock);
+ {
+ g_sigChldCallback = callback;
+ }
+ pthread_mutex_unlock(&lock);
+
+ return 1;
+}
+
+static void InstallSignalHandler(int sig, bool skipWhenSigIgn)
+{
+ int rv;
+ struct sigaction* orig = OrigActionFor(sig);
+
+ if (skipWhenSigIgn)
+ {
+ rv = sigaction(sig, NULL, orig);
+ assert(rv == 0);
+ if ((void*)orig->sa_sigaction == (void*)SIG_IGN)
+ {
+ return;
+ }
+ }
+
+ struct sigaction newAction;
+ memset(&newAction, 0, sizeof(struct sigaction));
+ newAction.sa_flags = SA_RESTART | SA_SIGINFO;
+ sigemptyset(&newAction.sa_mask);
+ newAction.sa_sigaction = &SignalHandler;
+
+ rv = sigaction(sig, &newAction, orig);
+ assert(rv == 0);
+}
+
+static bool InitializeSignalHandlingCore()
+{
+ // Create a pipe we'll use to communicate with our worker
+ // thread. We can't do anything interesting in the signal handler,
+ // so we instead send a message to another thread that'll do
+ // the handling work.
+ if (SystemNative_Pipe(g_signalPipe, PAL_O_CLOEXEC) != 0)
+ {
+ return false;
+ }
+ assert(g_signalPipe[0] >= 0);
+ assert(g_signalPipe[1] >= 0);
+
+ // Create a small object to pass the read end of the pipe to the worker.
+ int* readFdPtr = (int*)malloc(sizeof(int));
+ if (readFdPtr == NULL)
+ {
+ CloseSignalHandlingPipe();
+ errno = ENOMEM;
+ return false;
+ }
+ *readFdPtr = g_signalPipe[0];
+
+ // The pipe is created. Create the worker thread.
+ pthread_t handlerThread;
+ if (pthread_create(&handlerThread, NULL, SignalHandlerLoop, readFdPtr) != 0)
+ {
+ int err = errno;
+ free(readFdPtr);
+ CloseSignalHandlingPipe();
+ errno = err;
+ return false;
+ }
+
+ // Finally, register our signal handlers
+ // We don't handle ignored SIGINT/SIGQUIT signals. If we'd setup a handler, our child
+ // processes would reset to the default on exec causing them to terminate on these signals.
+ InstallSignalHandler(SIGINT , /* skipWhenSigIgn */ true);
+ InstallSignalHandler(SIGQUIT, /* skipWhenSigIgn */ true);
+ InstallSignalHandler(SIGCONT, /* skipWhenSigIgn */ false);
+ InstallSignalHandler(SIGCHLD, /* skipWhenSigIgn */ false);
+
+ return true;
+}
+
+uint32_t InitializeSignalHandling()
+{
+ static bool initialized = false;
+
+ pthread_mutex_lock(&lock);
+ {
+ if (!initialized)
+ {
+ initialized = InitializeSignalHandlingCore();
+ }
+ }
+ pthread_mutex_unlock(&lock);
+
+ return initialized ? 1 : 0;
+}
diff --git a/src/Native/Unix/System.Native/pal_signal.h b/src/Native/Unix/System.Native/pal_signal.h
new file mode 100644
index 0000000000..b31e2087da
--- /dev/null
+++ b/src/Native/Unix/System.Native/pal_signal.h
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#pragma once
+
+#include "pal_compiler.h"
+
+BEGIN_EXTERN_C
+
+#include "pal_types.h"
+
+/**
+ * Initializes the signal handling for use by System.Console and System.Process.
+ *
+ * Returns 1 on success; otherwise returns 0 and sets errno.
+ */
+uint32_t InitializeSignalHandling(void);
+
+/**
+ * Hooks up the specified callback for notifications when SIGINT or SIGQUIT is received.
+ *
+ * Not thread safe. Caller must provide its owns synchronization to ensure RegisterForCtrl
+ * is not called concurrently with itself or with UnregisterForCtrl.
+ *
+ * Should only be called when a callback is not currently registered.
+ */
+void SystemNative_RegisterForCtrl(CtrlCallback callback);
+
+/**
+ * Unregisters the previously registered ctrlCCallback.
+ *
+ * Not thread safe. Caller must provide its owns synchronization to ensure UnregisterForCtrl
+ * is not called concurrently with itself or with RegisterForCtrl.
+ *
+ * Should only be called when a callback is currently registered. The pointer
+ * previously registered must remain valid until all ctrl handling activity
+ * has quiesced.
+ */
+void SystemNative_UnregisterForCtrl(void);
+
+typedef void (*SigChldCallback)(int reapAll);
+
+/**
+ * Hooks up the specified callback for notifications when SIGCHLD is received.
+ *
+ * Not thread safe. Caller must provide its owns synchronization to ensure RegisterForSigChld
+ * is not called concurrently with itself.
+ *
+ * Should only be called when a callback is not currently registered.
+ */
+uint32_t SystemNative_RegisterForSigChld(SigChldCallback callback);
+
+END_EXTERN_C
diff --git a/src/Native/Unix/System.Native/pal_uid.cpp b/src/Native/Unix/System.Native/pal_uid.cpp
index 1738ab00a6..7de1a8eeb5 100644
--- a/src/Native/Unix/System.Native/pal_uid.cpp
+++ b/src/Native/Unix/System.Native/pal_uid.cpp
@@ -13,20 +13,8 @@
#include <sys/types.h>
#include <pwd.h>
-extern "C" int32_t SystemNative_GetPwUidR(uint32_t uid, Passwd* pwd, char* buf, int32_t buflen)
+static int32_t ConvertNativePasswdToPalPasswd(int error, struct passwd* nativePwd, struct passwd* result, Passwd* pwd)
{
- assert(pwd != nullptr);
- assert(buf != nullptr);
- assert(buflen >= 0);
-
- if (buflen < 0)
- return EINVAL;
-
- struct passwd nativePwd;
- struct passwd* result;
- int error;
- while ((error = getpwuid_r(uid, &nativePwd, buf, UnsignedCast(buflen), &result)) == EINTR);
-
// positive error number returned -> failure other than entry-not-found
if (error != 0)
{
@@ -43,17 +31,51 @@ extern "C" int32_t SystemNative_GetPwUidR(uint32_t uid, Passwd* pwd, char* buf,
}
// 0 returned with non-null result (guaranteed to be set to pwd arg) -> success
- assert(result == &nativePwd);
- pwd->Name = nativePwd.pw_name;
- pwd->Password = nativePwd.pw_passwd;
- pwd->UserId = nativePwd.pw_uid;
- pwd->GroupId = nativePwd.pw_gid;
- pwd->UserInfo = nativePwd.pw_gecos;
- pwd->HomeDirectory = nativePwd.pw_dir;
- pwd->Shell = nativePwd.pw_shell;
+ assert(result == nativePwd);
+ pwd->Name = nativePwd->pw_name;
+ pwd->Password = nativePwd->pw_passwd;
+ pwd->UserId = nativePwd->pw_uid;
+ pwd->GroupId = nativePwd->pw_gid;
+ pwd->UserInfo = nativePwd->pw_gecos;
+ pwd->HomeDirectory = nativePwd->pw_dir;
+ pwd->Shell = nativePwd->pw_shell;
return 0;
}
+extern "C" int32_t SystemNative_GetPwUidR(uint32_t uid, Passwd* pwd, char* buf, int32_t buflen)
+{
+ assert(pwd != nullptr);
+ assert(buf != nullptr);
+ assert(buflen >= 0);
+
+ if (buflen < 0)
+ return EINVAL;
+
+ struct passwd nativePwd;
+ struct passwd* result;
+ int error;
+ while ((error = getpwuid_r(uid, &nativePwd, buf, UnsignedCast(buflen), &result)) == EINTR);
+
+ return ConvertNativePasswdToPalPasswd(error, &nativePwd, result, pwd);
+}
+
+extern "C" int32_t SystemNative_GetPwNamR(const char* name, Passwd* pwd, char* buf, int32_t buflen)
+{
+ assert(pwd != nullptr);
+ assert(buf != nullptr);
+ assert(buflen >= 0);
+
+ if (buflen < 0)
+ return EINVAL;
+
+ struct passwd nativePwd;
+ struct passwd* result;
+ int error;
+ while ((error = getpwnam_r(name, &nativePwd, buf, UnsignedCast(buflen), &result)) == EINTR);
+
+ return ConvertNativePasswdToPalPasswd(error, &nativePwd, result, pwd);
+}
+
extern "C" uint32_t SystemNative_GetEUid()
{
return geteuid();
diff --git a/src/Native/Unix/System.Native/pal_uid.h b/src/Native/Unix/System.Native/pal_uid.h
index 1c7af67440..63482bd702 100644
--- a/src/Native/Unix/System.Native/pal_uid.h
+++ b/src/Native/Unix/System.Native/pal_uid.h
@@ -32,6 +32,15 @@ struct Passwd
extern "C" int32_t SystemNative_GetPwUidR(uint32_t uid, Passwd* pwd, char* buf, int32_t buflen);
/**
+* Gets a password structure for the given user name.
+* Implemented as shim to getpwnam_r(3).
+*
+* Returns 0 for success, -1 if no entry found, positive error
+* number for any other failure.
+*/
+extern "C" int32_t SystemNative_GetPwNamR(const char* name, Passwd* pwd, char* buf, int32_t buflen);
+
+/**
* Gets and returns the effective user's identity.
* Implemented as shim to geteuid(2).
*
diff --git a/src/Native/Unix/System.Net.Http.Native/pal_easy.cpp b/src/Native/Unix/System.Net.Http.Native/pal_easy.cpp
index f0d3469914..4ccbd8f661 100644
--- a/src/Native/Unix/System.Net.Http.Native/pal_easy.cpp
+++ b/src/Native/Unix/System.Net.Http.Native/pal_easy.cpp
@@ -26,6 +26,7 @@ static_assert(PAL_CURLOPT_NOSIGNAL == CURLOPT_NOSIGNAL, "");
static_assert(PAL_CURLOPT_PROXYTYPE == CURLOPT_PROXYTYPE, "");
static_assert(PAL_CURLOPT_HTTPAUTH == CURLOPT_HTTPAUTH, "");
static_assert(PAL_CURLOPT_TCP_NODELAY == CURLOPT_TCP_NODELAY, "");
+static_assert(PAL_CURLOPT_TCP_KEEPALIVE == CURLOPT_TCP_KEEPALIVE, "");
static_assert(PAL_CURLOPT_CONNECTTIMEOUT_MS == CURLOPT_CONNECTTIMEOUT_MS, "");
static_assert(PAL_CURLOPT_ADDRESS_SCOPE == CURLOPT_ADDRESS_SCOPE, "");
static_assert(PAL_CURLOPT_PROTOCOLS == CURLOPT_PROTOCOLS, "");
@@ -69,8 +70,8 @@ static_assert(PAL_CURLE_SEND_FAIL_REWIND == CURLE_SEND_FAIL_REWIND, "");
static_assert(PAL_CURL_HTTP_VERSION_NONE == CURL_HTTP_VERSION_NONE, "");
static_assert(PAL_CURL_HTTP_VERSION_1_0 == CURL_HTTP_VERSION_1_0, "");
static_assert(PAL_CURL_HTTP_VERSION_1_1 == CURL_HTTP_VERSION_1_1, "");
-#if HAVE_CURL_HTTP_VERSION_2_0
-static_assert(PAL_CURL_HTTP_VERSION_2_0 == CURL_HTTP_VERSION_2_0, "");
+#if HAVE_CURL_HTTP_VERSION_2TLS
+static_assert(PAL_CURL_HTTP_VERSION_2TLS == CURL_HTTP_VERSION_2TLS, "");
#endif
static_assert(PAL_CURL_SSLVERSION_TLSv1 == CURL_SSLVERSION_TLSv1, "");
diff --git a/src/Native/Unix/System.Net.Http.Native/pal_easy.h b/src/Native/Unix/System.Net.Http.Native/pal_easy.h
index e86a8ca44e..18298c1532 100644
--- a/src/Native/Unix/System.Net.Http.Native/pal_easy.h
+++ b/src/Native/Unix/System.Net.Http.Native/pal_easy.h
@@ -35,6 +35,7 @@ enum PAL_CURLoption : int32_t
PAL_CURLOPT_PROXYTYPE = CurlOptionLongBase + 101,
PAL_CURLOPT_HTTPAUTH = CurlOptionLongBase + 107,
PAL_CURLOPT_TCP_NODELAY = CurlOptionLongBase + 121,
+ PAL_CURLOPT_TCP_KEEPALIVE = CurlOptionLongBase + 213,
PAL_CURLOPT_CONNECTTIMEOUT_MS = CurlOptionLongBase + 156,
PAL_CURLOPT_ADDRESS_SCOPE = CurlOptionLongBase + 171,
PAL_CURLOPT_PROTOCOLS = CurlOptionLongBase + 181,
@@ -93,7 +94,7 @@ enum PAL_CURL_HTTP_VERSION
PAL_CURL_HTTP_VERSION_NONE = 0,
PAL_CURL_HTTP_VERSION_1_0 = 1,
PAL_CURL_HTTP_VERSION_1_1 = 2,
- PAL_CURL_HTTP_VERSION_2_0 = 3
+ PAL_CURL_HTTP_VERSION_2TLS = 4
};
enum PAL_CURL_SSLVERSION
diff --git a/src/Native/Unix/System.Security.Cryptography.Native.Apple/CMakeLists.txt b/src/Native/Unix/System.Security.Cryptography.Native.Apple/CMakeLists.txt
index 4cf90cf68f..0ed02c6e9d 100644
--- a/src/Native/Unix/System.Security.Cryptography.Native.Apple/CMakeLists.txt
+++ b/src/Native/Unix/System.Security.Cryptography.Native.Apple/CMakeLists.txt
@@ -12,6 +12,7 @@ set(NATIVECRYPTO_SOURCES
pal_digest.cpp
pal_ecc.cpp
pal_hmac.cpp
+ pal_keyagree.cpp
pal_keychain.cpp
pal_random.cpp
pal_rsa.cpp
diff --git a/src/Native/Unix/System.Security.Cryptography.Native.Apple/pal_keyagree.cpp b/src/Native/Unix/System.Security.Cryptography.Native.Apple/pal_keyagree.cpp
new file mode 100644
index 0000000000..12561d0265
--- /dev/null
+++ b/src/Native/Unix/System.Security.Cryptography.Native.Apple/pal_keyagree.cpp
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "pal_keyagree.h"
+
+extern "C" int32_t
+AppleCryptoNative_EcdhKeyAgree(SecKeyRef privateKey, SecKeyRef publicKey, CFDataRef* pAgreeOut, CFErrorRef* pErrorOut)
+{
+ if (pAgreeOut != nullptr)
+ *pAgreeOut = nullptr;
+ if (pErrorOut != nullptr)
+ *pErrorOut = nullptr;
+
+ if (privateKey == nullptr || publicKey == nullptr)
+ return kErrorBadInput;
+
+ CFDictionaryRef dict = nullptr;
+
+ *pAgreeOut =
+ SecKeyCopyKeyExchangeResult(privateKey, kSecKeyAlgorithmECDHKeyExchangeStandard, publicKey, dict, pErrorOut);
+
+ if (*pErrorOut != nullptr)
+ return kErrorSeeError;
+
+ return *pAgreeOut != nullptr;
+}
diff --git a/src/Native/Unix/System.Security.Cryptography.Native.Apple/pal_keyagree.h b/src/Native/Unix/System.Security.Cryptography.Native.Apple/pal_keyagree.h
new file mode 100644
index 0000000000..fcb2097618
--- /dev/null
+++ b/src/Native/Unix/System.Security.Cryptography.Native.Apple/pal_keyagree.h
@@ -0,0 +1,17 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#pragma once
+
+#include "pal_seckey.h"
+
+#include <Security/Security.h>
+
+/*
+Perform the EC Diffie-Hellman key agreement between the provided keys.
+
+Follows pal_seckey return conventions.
+*/
+extern "C" int32_t
+AppleCryptoNative_EcdhKeyAgree(SecKeyRef privateKey, SecKeyRef publicKey, CFDataRef* pAgreeOut, CFErrorRef* pErrorOut);
diff --git a/src/Native/Unix/System.Security.Cryptography.Native.Apple/pal_rsa.cpp b/src/Native/Unix/System.Security.Cryptography.Native.Apple/pal_rsa.cpp
index e273175fe8..d4c321fc6f 100644
--- a/src/Native/Unix/System.Security.Cryptography.Native.Apple/pal_rsa.cpp
+++ b/src/Native/Unix/System.Security.Cryptography.Native.Apple/pal_rsa.cpp
@@ -267,3 +267,76 @@ cleanup:
return ret;
}
+
+static int32_t RsaPrimitive(SecKeyRef key,
+ uint8_t* pbData,
+ int32_t cbData,
+ CFDataRef* pDataOut,
+ CFErrorRef* pErrorOut,
+ SecKeyAlgorithm algorithm,
+ CFDataRef func(SecKeyRef, SecKeyAlgorithm, CFDataRef, CFErrorRef*))
+{
+ if (pDataOut != nullptr)
+ *pDataOut = nullptr;
+ if (pErrorOut != nullptr)
+ *pErrorOut = nullptr;
+
+ if (key == nullptr || pbData == nullptr || cbData < 0 || pDataOut == nullptr || pErrorOut == nullptr)
+ {
+ return kErrorBadInput;
+ }
+
+ assert(func != nullptr);
+
+ CFDataRef input = CFDataCreateWithBytesNoCopy(nullptr, pbData, cbData, kCFAllocatorNull);
+ CFDataRef output = func(key, algorithm, input, pErrorOut);
+
+ if (*pErrorOut != nullptr)
+ {
+ if (output != nullptr)
+ {
+ CFRelease(output);
+ output = nullptr;
+ }
+
+ return kErrorSeeError;
+ }
+
+ if (output == nullptr)
+ {
+ return kErrorUnknownState;
+ }
+
+ *pDataOut = output;
+ return 1;
+}
+
+extern "C" int32_t AppleCryptoNative_RsaSignaturePrimitive(
+ SecKeyRef privateKey, uint8_t* pbData, int32_t cbData, CFDataRef* pDataOut, CFErrorRef* pErrorOut)
+{
+ return RsaPrimitive(
+ privateKey, pbData, cbData, pDataOut, pErrorOut, kSecKeyAlgorithmRSASignatureRaw, SecKeyCreateSignature);
+}
+
+extern "C" int32_t AppleCryptoNative_RsaDecryptionPrimitive(
+ SecKeyRef privateKey, uint8_t* pbData, int32_t cbData, CFDataRef* pDataOut, CFErrorRef* pErrorOut)
+{
+ return RsaPrimitive(
+ privateKey, pbData, cbData, pDataOut, pErrorOut, kSecKeyAlgorithmRSAEncryptionRaw, SecKeyCreateDecryptedData);
+}
+
+extern "C" int32_t AppleCryptoNative_RsaEncryptionPrimitive(
+ SecKeyRef publicKey, uint8_t* pbData, int32_t cbData, CFDataRef* pDataOut, CFErrorRef* pErrorOut)
+{
+ return RsaPrimitive(
+ publicKey, pbData, cbData, pDataOut, pErrorOut, kSecKeyAlgorithmRSAEncryptionRaw, SecKeyCreateEncryptedData);
+}
+
+extern "C" int32_t AppleCryptoNative_RsaVerificationPrimitive(
+ SecKeyRef publicKey, uint8_t* pbData, int32_t cbData, CFDataRef* pDataOut, CFErrorRef* pErrorOut)
+{
+ // Since there's not an API which will give back the still-padded signature block with
+ // kSecAlgorithmRSASignatureRaw, use the encryption primitive to achieve the same result.
+ return RsaPrimitive(
+ publicKey, pbData, cbData, pDataOut, pErrorOut, kSecKeyAlgorithmRSAEncryptionRaw, SecKeyCreateEncryptedData);
+}
diff --git a/src/Native/Unix/System.Security.Cryptography.Native.Apple/pal_rsa.h b/src/Native/Unix/System.Security.Cryptography.Native.Apple/pal_rsa.h
index cdc6b5c6e4..7ffae7b8ad 100644
--- a/src/Native/Unix/System.Security.Cryptography.Native.Apple/pal_rsa.h
+++ b/src/Native/Unix/System.Security.Cryptography.Native.Apple/pal_rsa.h
@@ -59,3 +59,35 @@ Follows pal_seckey return conventions.
*/
extern "C" int32_t AppleCryptoNative_RsaEncryptPkcs(
SecKeyRef publicKey, uint8_t* pbData, int32_t cbData, CFDataRef* pEncryptedOut, CFErrorRef* pErrorOut);
+
+/*
+Apply an RSA private key to a signing operation on data which was already padded.
+
+Follows pal_seckey return conventions.
+*/
+extern "C" int32_t AppleCryptoNative_RsaSignaturePrimitive(
+ SecKeyRef privateKey, uint8_t* pbData, int32_t cbData, CFDataRef* pDataOut, CFErrorRef* pErrorOut);
+
+/*
+Apply an RSA private key to an encryption operation to emit data which is still padded.
+
+Follows pal_seckey return conventions.
+*/
+extern "C" int32_t AppleCryptoNative_RsaDecryptionPrimitive(
+ SecKeyRef privateKey, uint8_t* pbData, int32_t cbData, CFDataRef* pDataOut, CFErrorRef* pErrorOut);
+
+/*
+Apply an RSA public key to an encryption operation on data which was already padded.
+
+Follows pal_seckey return conventions.
+*/
+extern "C" int32_t AppleCryptoNative_RsaEncryptionPrimitive(
+ SecKeyRef publicKey, uint8_t* pbData, int32_t cbData, CFDataRef* pDataOut, CFErrorRef* pErrorOut);
+
+/*
+Apply an RSA public key to a signing operation to emit data which is still padded.
+
+Follows pal_seckey return conventions.
+*/
+extern "C" int32_t AppleCryptoNative_RsaVerificationPrimitive(
+ SecKeyRef publicKey, uint8_t* pbData, int32_t cbData, CFDataRef* pDataOut, CFErrorRef* pErrorOut);
diff --git a/src/Native/Unix/System.Security.Cryptography.Native/CMakeLists.txt b/src/Native/Unix/System.Security.Cryptography.Native/CMakeLists.txt
index cb1eafa115..352f456d07 100644
--- a/src/Native/Unix/System.Security.Cryptography.Native/CMakeLists.txt
+++ b/src/Native/Unix/System.Security.Cryptography.Native/CMakeLists.txt
@@ -29,6 +29,7 @@ set(NATIVECRYPTO_SOURCES
pal_evp.cpp
pal_evp_pkey.cpp
pal_evp_pkey_dsa.cpp
+ pal_evp_pkey_ecdh.cpp
pal_evp_pkey_eckey.cpp
pal_evp_pkey_rsa.cpp
pal_evp_cipher.cpp
diff --git a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.cpp b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.cpp
index 6be0546b81..f4e1cb71cb 100644
--- a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.cpp
+++ b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.cpp
@@ -13,24 +13,48 @@
FOR_ALL_OPENSSL_FUNCTIONS
#undef PER_FUNCTION_BLOCK
+// x.x.x, considering the max number of decimal digits for each component
+static const int MaxVersionStringLength = 32;
+#define SONAME_BASE "libssl.so."
+
static void* libssl = nullptr;
bool OpenLibrary()
{
- // First try the default versioned so naming as described in the OpenSSL doc
- libssl = dlopen("libssl.so.1.0.0", RTLD_LAZY);
- if (libssl == nullptr)
+ // If there is an override of the version specified using the CLR_OPENSSL_VERSION_OVERRIDE
+ // env variable, try to load that first.
+ // The format of the value in the env variable is expected to be the version numbers,
+ // like 1.0.0, 1.0.2 etc.
+ char* versionOverride = getenv("CLR_OPENSSL_VERSION_OVERRIDE");
+
+ if ((versionOverride != nullptr) && strnlen(versionOverride, MaxVersionStringLength + 1) <= MaxVersionStringLength)
{
- // Fedora derived distros use different naming for the version 1.0.0
- libssl = dlopen("libssl.so.10", RTLD_LAZY);
+ char soName[sizeof(SONAME_BASE) + MaxVersionStringLength] = SONAME_BASE;
+
+ strcat(soName, versionOverride);
+ libssl = dlopen(soName, RTLD_LAZY);
}
if (libssl == nullptr)
{
- // Debian 9 has dropped support for SSLv3 and so they have bumped their soname
+ // Debian 9 has dropped support for SSLv3 and so they have bumped their soname. Let's try it
+ // before trying the version 1.0.0 to make it less probable that some of our other dependencies
+ // end up loading conflicting version of libssl.
libssl = dlopen("libssl.so.1.0.2", RTLD_LAZY);
}
+ if (libssl == nullptr)
+ {
+ // Now try the default versioned so naming as described in the OpenSSL doc
+ libssl = dlopen("libssl.so.1.0.0", RTLD_LAZY);
+ }
+
+ if (libssl == nullptr)
+ {
+ // Fedora derived distros use different naming for the version 1.0.0
+ libssl = dlopen("libssl.so.10", RTLD_LAZY);
+ }
+
return libssl != nullptr;
}
diff --git a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h
index 3771d614c2..afb2559d12 100644
--- a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h
+++ b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h
@@ -192,6 +192,11 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi
PER_FUNCTION_BLOCK(EVP_MD_CTX_create, true) \
PER_FUNCTION_BLOCK(EVP_MD_CTX_destroy, true) \
PER_FUNCTION_BLOCK(EVP_MD_size, true) \
+ PER_FUNCTION_BLOCK(EVP_PKEY_CTX_free, true) \
+ PER_FUNCTION_BLOCK(EVP_PKEY_CTX_new, true) \
+ PER_FUNCTION_BLOCK(EVP_PKEY_derive_set_peer, true) \
+ PER_FUNCTION_BLOCK(EVP_PKEY_derive_init, true) \
+ PER_FUNCTION_BLOCK(EVP_PKEY_derive, true) \
PER_FUNCTION_BLOCK(EVP_PKEY_free, true) \
PER_FUNCTION_BLOCK(EVP_PKEY_get1_DSA, true) \
PER_FUNCTION_BLOCK(EVP_PKEY_get1_EC_KEY, true) \
@@ -229,6 +234,7 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi
PER_FUNCTION_BLOCK(OBJ_txt2nid, true) \
PER_FUNCTION_BLOCK(OBJ_txt2obj, true) \
PER_FUNCTION_BLOCK(OPENSSL_add_all_algorithms_conf, true) \
+ PER_FUNCTION_BLOCK(OPENSSL_cleanse, true) \
PER_FUNCTION_BLOCK(PEM_read_bio_PKCS7, true) \
PER_FUNCTION_BLOCK(PEM_read_bio_X509_AUX, true) \
PER_FUNCTION_BLOCK(PEM_read_bio_X509_CRL, true) \
@@ -248,6 +254,8 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi
PER_FUNCTION_BLOCK(RSA_get_method, true) \
PER_FUNCTION_BLOCK(RSA_new, true) \
PER_FUNCTION_BLOCK(RSA_private_decrypt, true) \
+ PER_FUNCTION_BLOCK(RSA_private_encrypt, true) \
+ PER_FUNCTION_BLOCK(RSA_public_decrypt, true) \
PER_FUNCTION_BLOCK(RSA_public_encrypt, true) \
PER_FUNCTION_BLOCK(RSA_sign, true) \
PER_FUNCTION_BLOCK(RSA_size, true) \
@@ -484,6 +492,11 @@ FOR_ALL_OPENSSL_FUNCTIONS
#define EVP_MD_CTX_create EVP_MD_CTX_create_ptr
#define EVP_MD_CTX_destroy EVP_MD_CTX_destroy_ptr
#define EVP_MD_size EVP_MD_size_ptr
+#define EVP_PKEY_CTX_free EVP_PKEY_CTX_free_ptr
+#define EVP_PKEY_CTX_new EVP_PKEY_CTX_new_ptr
+#define EVP_PKEY_derive_set_peer EVP_PKEY_derive_set_peer_ptr
+#define EVP_PKEY_derive_init EVP_PKEY_derive_init_ptr
+#define EVP_PKEY_derive EVP_PKEY_derive_ptr
#define EVP_PKEY_free EVP_PKEY_free_ptr
#define EVP_PKEY_get1_DSA EVP_PKEY_get1_DSA_ptr
#define EVP_PKEY_get1_EC_KEY EVP_PKEY_get1_EC_KEY_ptr
@@ -521,6 +534,7 @@ FOR_ALL_OPENSSL_FUNCTIONS
#define OBJ_txt2nid OBJ_txt2nid_ptr
#define OBJ_txt2obj OBJ_txt2obj_ptr
#define OPENSSL_add_all_algorithms_conf OPENSSL_add_all_algorithms_conf_ptr
+#define OPENSSL_cleanse OPENSSL_cleanse_ptr
#define PEM_read_bio_PKCS7 PEM_read_bio_PKCS7_ptr
#define PEM_read_bio_X509_AUX PEM_read_bio_X509_AUX_ptr
#define PEM_read_bio_X509_CRL PEM_read_bio_X509_CRL_ptr
@@ -540,6 +554,8 @@ FOR_ALL_OPENSSL_FUNCTIONS
#define RSA_get_method RSA_get_method_ptr
#define RSA_new RSA_new_ptr
#define RSA_private_decrypt RSA_private_decrypt_ptr
+#define RSA_private_encrypt RSA_private_encrypt_ptr
+#define RSA_public_decrypt RSA_public_decrypt_ptr
#define RSA_public_encrypt RSA_public_encrypt_ptr
#define RSA_sign RSA_sign_ptr
#define RSA_size RSA_size_ptr
diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_ecdh.cpp b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_ecdh.cpp
new file mode 100644
index 0000000000..1b696096b2
--- /dev/null
+++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_ecdh.cpp
@@ -0,0 +1,64 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "pal_evp_pkey_ecdh.h"
+
+extern "C" EVP_PKEY_CTX* CryptoNative_EvpPKeyCtxCreate(EVP_PKEY* pkey, EVP_PKEY* peerkey, uint32_t* secretLength)
+{
+ if (secretLength != nullptr)
+ *secretLength = 0;
+
+ if (pkey == nullptr || peerkey == nullptr || secretLength == nullptr)
+ {
+ return nullptr;
+ }
+
+ /* Create the context for the shared secret derivation */
+ EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pkey, NULL);
+
+ if (ctx == nullptr)
+ {
+ return nullptr;
+ }
+
+ size_t tmpLength = 0;
+
+ /* Initialize, provide the peer public key, and determine the buffer size */
+ if (1 != EVP_PKEY_derive_init(ctx) || 1 != EVP_PKEY_derive_set_peer(ctx, peerkey) ||
+ 1 != EVP_PKEY_derive(ctx, NULL, &tmpLength))
+ {
+ EVP_PKEY_CTX_free(ctx);
+ return nullptr;
+ }
+
+ *secretLength = (uint32_t)tmpLength;
+ return ctx;
+}
+
+extern "C" int32_t CryptoNative_EvpPKeyDeriveSecretAgreement(uint8_t* secret, uint32_t secretLength, EVP_PKEY_CTX* ctx)
+{
+ size_t tmpSize = (size_t)secretLength;
+ int ret = 0;
+
+ if (secret != nullptr && ctx != nullptr)
+ {
+ ret = EVP_PKEY_derive(ctx, secret, &tmpSize);
+
+ if (ret == 1 && tmpSize != (size_t)secretLength)
+ {
+ OPENSSL_cleanse(secret, secretLength);
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
+extern "C" void CryptoNative_EvpPKeyCtxDestroy(EVP_PKEY_CTX* ctx)
+{
+ if (ctx != nullptr)
+ {
+ EVP_PKEY_CTX_free(ctx);
+ }
+}
diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_ecdh.h b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_ecdh.h
new file mode 100644
index 0000000000..59052a15ab
--- /dev/null
+++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_ecdh.h
@@ -0,0 +1,12 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "opensslshim.h"
+#include "pal_types.h"
+
+extern "C" EVP_PKEY_CTX* CryptoNative_EvpPKeyCtxCreate(EVP_PKEY* pkey, EVP_PKEY* peerkey, uint32_t* secretLength);
+
+extern "C" int32_t CryptoNative_EvpPKeyDeriveSecretAgreement(uint8_t* secret, uint32_t secretLength, EVP_PKEY_CTX* ctx);
+
+extern "C" void CryptoNative_EvpPKeyCtxDestroy(EVP_PKEY_CTX* ctx);
diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.cpp b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.cpp
index 18d687bd3d..7b3f56bed6 100644
--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.cpp
+++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.cpp
@@ -35,9 +35,17 @@ extern "C" RSA* CryptoNative_DecodeRsaPublicKey(const uint8_t* buf, int32_t len)
static int GetOpenSslPadding(RsaPadding padding)
{
- assert(padding == Pkcs1 || padding == OaepSHA1);
+ assert(padding == Pkcs1 || padding == OaepSHA1 || padding == NoPadding);
- return padding == Pkcs1 ? RSA_PKCS1_PADDING : RSA_PKCS1_OAEP_PADDING;
+ switch (padding)
+ {
+ case Pkcs1:
+ return RSA_PKCS1_PADDING;
+ case OaepSHA1:
+ return RSA_PKCS1_OAEP_PADDING;
+ case NoPadding:
+ return RSA_NO_PADDING;
+ }
}
static int HasNoPrivateKey(RSA* rsa)
@@ -51,7 +59,7 @@ static int HasNoPrivateKey(RSA* rsa)
// The method has descibed itself as having the private key external to the structure.
// That doesn't mean it's actually present, but we can't tell.
if (meth->flags & RSA_FLAG_EXT_PKEY)
- return 0;
+ return 0;
// In the event that there's a middle-ground where we report failure when success is expected,
// one could do something like check if the RSA_METHOD intercepts all private key operations:
@@ -93,6 +101,22 @@ CryptoNative_RsaPrivateDecrypt(int32_t flen, const uint8_t* from, uint8_t* to, R
return RSA_private_decrypt(flen, from, to, rsa, openSslPadding);
}
+extern "C" int32_t CryptoNative_RsaSignPrimitive(int32_t flen, const uint8_t* from, uint8_t* to, RSA* rsa)
+{
+ if (HasNoPrivateKey(rsa))
+ {
+ ERR_PUT_error(ERR_LIB_RSA, RSA_F_RSA_PRIVATE_ENCRYPT, RSA_R_VALUE_MISSING, __FILE__, __LINE__);
+ return -1;
+ }
+
+ return RSA_private_encrypt(flen, from, to, rsa, RSA_NO_PADDING);
+}
+
+extern "C" int32_t CryptoNative_RsaVerificationPrimitive(int32_t flen, const uint8_t* from, uint8_t* to, RSA* rsa)
+{
+ return RSA_public_decrypt(flen, from, to, rsa, RSA_NO_PADDING);
+}
+
extern "C" int32_t CryptoNative_RsaSize(RSA* rsa)
{
return RSA_size(rsa);
diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h
index 45a4ad6303..162f21ef5c 100644
--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h
+++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h
@@ -2,8 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-#include "pal_types.h"
#include "opensslshim.h"
+#include "pal_types.h"
/*
Padding options for RsaPublicEncrypt and RsaPrivateDecrypt.
@@ -13,6 +13,7 @@ enum RsaPadding : int32_t
{
Pkcs1 = 0,
OaepSHA1 = 1,
+ NoPadding = 2,
};
/*
@@ -62,6 +63,22 @@ extern "C" int32_t
CryptoNative_RsaPrivateDecrypt(int32_t flen, const uint8_t* from, uint8_t* to, RSA* rsa, RsaPadding padding);
/*
+Shims RSA_private_encrypt with a fixed value of RSA_NO_PADDING.
+
+Requires that the input be the size of the key.
+Returns the number of bytes written (which should be flen), or -1 on error.
+*/
+extern "C" int32_t CryptoNative_RsaSignPrimitive(int32_t flen, const uint8_t* from, uint8_t* to, RSA* rsa);
+
+/*
+Shims RSA_public_decrypt with a fixed value of RSA_NO_PADDING.
+
+Requires that the input be the size of the key.
+Returns the number of bytes written (which should be flen), or -1 on error.
+*/
+extern "C" int32_t CryptoNative_RsaVerificationPrimitive(int32_t flen, const uint8_t* from, uint8_t* to, RSA* rsa);
+
+/*
Shims the RSA_size method.
Returns the RSA modulus size in bytes.
diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.cpp b/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.cpp
index 3e40d6cb98..7489aff1a0 100644
--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.cpp
+++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.cpp
@@ -609,6 +609,6 @@ extern "C" void CryptoNative_SslGet0AlpnSelected(SSL* ssl, const uint8_t** proto
extern "C" int32_t CryptoNative_SslSetTlsExtHostName(SSL* ssl, const uint8_t* name)
{
- return static_cast<int32_t>(SSL_set_tlsext_host_name(ssl, name));
+ return static_cast<int32_t>(SSL_set_tlsext_host_name(ssl, const_cast<unsigned char*>(name)));
}
diff --git a/src/Native/Unix/configure.cmake b/src/Native/Unix/configure.cmake
index 497dc21738..7b885239bd 100644
--- a/src/Native/Unix/configure.cmake
+++ b/src/Native/Unix/configure.cmake
@@ -1,3 +1,4 @@
+include(CheckCXXCompilerFlag)
include(CheckCXXSourceCompiles)
include(CheckCXXSourceRuns)
include(CheckCSourceCompiles)
@@ -27,7 +28,16 @@ else ()
endif ()
# We compile with -Werror, so we need to make sure these code fragments compile without warnings.
-set(CMAKE_REQUIRED_FLAGS -Werror)
+# Older CMake versions (3.8) do not assign the result of their tests, causing unused-value errors
+# which are not distinguished from the test failing. So no error for that one.
+set(CMAKE_REQUIRED_FLAGS "-Werror -Wno-error=unused-value")
+
+# This compiler warning will fail code as innocuous as:
+# static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+# Check if the compiler knows about this warning so we can disable it
+check_cxx_compiler_flag(
+ -Wzero-as-null-pointer-constant
+ HAVE_ZERO_AS_NULL_POINTER_CONSTANT_FLAG)
# in_pktinfo: Find whether this struct exists
check_include_files(
@@ -221,7 +231,7 @@ check_c_source_compiles(
int main()
{
char buffer[1];
- char* c = strerror_r(0, buffer, 0);
+ char c = *strerror_r(0, buffer, 0);
return 0;
}
"
@@ -300,46 +310,6 @@ check_function_exists(
kqueue
HAVE_KQUEUE)
-check_c_source_compiles(
- "
- #include <sys/types.h>
- #include <netdb.h>
-
- int main()
- {
- const void* addr;
- socklen_t len;
- int type;
- struct hostent* result;
- char* buffer;
- size_t buflen;
- struct hostent** entry;
- int* error;
- gethostbyaddr_r(addr, len, type, result, buffer, buflen, entry, error);
- return 0;
- }
- "
- HAVE_GETHOSTBYADDR_R)
-
-check_c_source_compiles(
- "
- #include <sys/types.h>
- #include <netdb.h>
-
- int main()
- {
- const char* hostname;
- struct hostent* result;
- char* buffer;
- size_t buflen;
- struct hostent** entry;
- int* error;
- gethostbyname_r(hostname, result, buffer, buflen, entry, error);
- return 0;
- }
- "
- HAVE_GETHOSTBYNAME_R)
-
set(CMAKE_REQUIRED_FLAGS "-Werror -Wsign-conversion")
check_c_source_compiles(
"
@@ -363,7 +333,6 @@ check_c_source_compiles(
set(CMAKE_REQUIRED_FLAGS -Werror)
set(HAVE_SUPPORT_FOR_DUAL_MODE_IPV4_PACKET_INFO 0)
-set(HAVE_THREAD_SAFE_GETHOSTBYNAME_AND_GETHOSTBYADDR 0)
if (CMAKE_SYSTEM_NAME STREQUAL Linux)
if (NOT CLR_CMAKE_PLATFORM_ANDROID)
@@ -371,12 +340,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL Linux)
endif ()
set(HAVE_SUPPORT_FOR_DUAL_MODE_IPV4_PACKET_INFO 1)
-
- if (CLR_CMAKE_PLATFORM_ANDROID)
- set(HAVE_THREAD_SAFE_GETHOSTBYNAME_AND_GETHOSTBYADDR 1)
- endif()
-elseif (CMAKE_SYSTEM_NAME STREQUAL Darwin)
- set(HAVE_THREAD_SAFE_GETHOSTBYNAME_AND_GETHOSTBYADDR 1)
+
endif ()
check_cxx_source_runs(
@@ -657,9 +621,9 @@ check_cxx_source_compiles(
check_cxx_source_compiles(
"
#include <curl/multi.h>
- int main() { int i = CURL_HTTP_VERSION_2_0; return 0; }
+ int main() { int i = CURL_HTTP_VERSION_2TLS; return 0; }
"
- HAVE_CURL_HTTP_VERSION_2_0)
+ HAVE_CURL_HTTP_VERSION_2TLS)
check_cxx_source_compiles(
"
diff --git a/src/System.Buffers/pkg/System.Buffers.pkgproj b/src/System.Buffers/pkg/System.Buffers.pkgproj
index 6794eed7f5..cb2771fe58 100644
--- a/src/System.Buffers/pkg/System.Buffers.pkgproj
+++ b/src/System.Buffers/pkg/System.Buffers.pkgproj
@@ -2,8 +2,11 @@
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
+ <HarvestIncludePath Include="ref\netstandard1.1;ref\netstandard2.0">
+ <SupportedFramework>netcore45;netcoreapp1.0;wpa81;$(AllXamarinFrameworks)</SupportedFramework>
+ </HarvestIncludePath>
<ProjectReference Include="..\ref\System.Buffers.csproj">
- <SupportedFramework>net45;netcore45;netcoreapp1.0;wpa81;$(AllXamarinFrameworks)</SupportedFramework>
+ <SupportedFramework>net45</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\src\System.Buffers.csproj" />
@@ -11,14 +14,8 @@
therefore it cannot reference NETStandard.Library -->
<SuppressMetaPackage Include="NETStandard.Library" />
- <!-- Since UAP and .NETCoreApp are package based we still want to enable
- OOBing libraries that happen to overlap with their framework package.
- This avoids us having to lock the API in our NuGet packages just
- to match what shipped inbox: since we can provide a new library
- we can update it to add API without raising the netstandard version. -->
- <ValidatePackageSuppression Include="TreatAsOutOfBox">
- <Value>.NETCoreApp;UAP</Value>
- </ValidatePackageSuppression>
+ <InboxOnTargetFramework Include="netcoreapp2.0" />
+ <InboxOnTargetFramework Include="uap10.0.16299" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.Buffers/ref/Configurations.props b/src/System.Buffers/ref/Configurations.props
index a66f1edba4..feebf8aa9e 100644
--- a/src/System.Buffers/ref/Configurations.props
+++ b/src/System.Buffers/ref/Configurations.props
@@ -1,9 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
- <BuildConfigurations>
+ <PackageConfigurations>
netstandard;
netstandard1.1;
+ net45;
+ </PackageConfigurations>
+ <BuildConfigurations>
+ $(PackageConfigurations);
+ uap;
+ netfx;
</BuildConfigurations>
</PropertyGroup>
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Buffers/ref/System.Buffers.csproj b/src/System.Buffers/ref/System.Buffers.csproj
index 4add92447c..1a81944093 100644
--- a/src/System.Buffers/ref/System.Buffers.csproj
+++ b/src/System.Buffers/ref/System.Buffers.csproj
@@ -3,16 +3,31 @@
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
<ProjectGuid>{11AE73F7-3532-47B9-8FF6-B4F22D76456C}</ProjectGuid>
+ <!-- Must match version supported by frameworks which support 4.0.* inbox.
+ Can be removed when API is added and this assembly is versioned to 4.1.* -->
+ <AssemblyVersion Condition="'$(TargetsNetFx)' != 'true'">4.0.2.0</AssemblyVersion>
</PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'net45-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'net45-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.1-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.1-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="System.Buffers.cs" />
</ItemGroup>
- <ItemGroup Condition="'$(TargetGroup)' == 'netstandard1.1'">
+ <ItemGroup Condition="'$(TargetGroup)' == 'netstandard1.1' Or '$(TargetGroup)' == 'uap10.0.16299'">
<Reference Include="System.Runtime" />
</ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)' == 'uap'">
+ <ProjectReference Include="..\..\System.Runtime\ref\System.Runtime.csproj" />
+ </ItemGroup>
+ <ItemGroup Condition="'$(TargetsNetFx)' == 'true'">
+ <Reference Include="mscorlib" />
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.Buffers/src/Configurations.props b/src/System.Buffers/src/Configurations.props
index 6544913df5..f8eca1e4fa 100644
--- a/src/System.Buffers/src/Configurations.props
+++ b/src/System.Buffers/src/Configurations.props
@@ -4,15 +4,13 @@
<PackageConfigurations>
netstandard1.1;
netstandard;
- netcoreapp2.0-Windows_NT;
- netcoreapp2.0-Unix;
- uap-Windows_NT;
- uapaot-Windows_NT;
</PackageConfigurations>
<BuildConfigurations>
$(PackageConfigurations);
netcoreapp-Windows_NT;
netcoreapp-Unix;
+ uap-Windows_NT;
+ uapaot-Windows_NT;
</BuildConfigurations>
</PropertyGroup>
</Project>
diff --git a/src/System.Buffers/src/System.Buffers.csproj b/src/System.Buffers/src/System.Buffers.csproj
index 315b84e360..0ac14425d5 100644
--- a/src/System.Buffers/src/System.Buffers.csproj
+++ b/src/System.Buffers/src/System.Buffers.csproj
@@ -5,17 +5,13 @@
<ProjectGuid>{2ADDB484-6F57-4D71-A3FE-A57EC6329A2B}</ProjectGuid>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>$(OutputPath)$(MSBuildProjectName).xml</DocumentationFile>
- <IsPartialFacadeAssembly Condition="'$(TargetGroup)' != 'netstandard' and '$(TargetGroup)' != 'netstandard1.1'">true</IsPartialFacadeAssembly>
+ <IsPartialFacadeAssembly Condition="'$(TargetGroup)' != 'netstandard' and '$(TargetGroup)' != 'netstandard1.1' and '$(TargetGroup)' != 'uap10.0.16299'">true</IsPartialFacadeAssembly>
<ExcludeResourcesImport Condition="'$(IsPartialFacadeAssembly)'=='true'">true</ExcludeResourcesImport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Unix-Debug|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Unix-Release|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Windows_NT-Debug|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.1-Debug|AnyCPU'" />
@@ -42,4 +38,4 @@
<Reference Include="System.Threading" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Buffers/src/System/Buffers/ArrayPoolEventSource.cs b/src/System.Buffers/src/System/Buffers/ArrayPoolEventSource.cs
index 908229a832..da4fcea6ff 100644
--- a/src/System.Buffers/src/System/Buffers/ArrayPoolEventSource.cs
+++ b/src/System.Buffers/src/System/Buffers/ArrayPoolEventSource.cs
@@ -34,14 +34,26 @@ namespace System.Buffers
internal unsafe void BufferRented(int bufferId, int bufferSize, int poolId, int bucketId)
{
EventData* payload = stackalloc EventData[4];
- payload[0].Size = sizeof(int);
- payload[0].DataPointer = ((IntPtr)(&bufferId));
- payload[1].Size = sizeof(int);
- payload[1].DataPointer = ((IntPtr)(&bufferSize));
- payload[2].Size = sizeof(int);
- payload[2].DataPointer = ((IntPtr)(&poolId));
- payload[3].Size = sizeof(int);
- payload[3].DataPointer = ((IntPtr)(&bucketId));
+ payload[0] = new EventData
+ {
+ Size = sizeof(int),
+ DataPointer = ((IntPtr)(&bufferId))
+ };
+ payload[1] = new EventData
+ {
+ Size = sizeof(int),
+ DataPointer = ((IntPtr)(&bufferSize))
+ };
+ payload[2] = new EventData
+ {
+ Size = sizeof(int),
+ DataPointer = ((IntPtr)(&poolId))
+ };
+ payload[3] = new EventData
+ {
+ Size = sizeof(int),
+ DataPointer = ((IntPtr)(&bucketId))
+ };
WriteEventCore(1, 4, payload);
}
@@ -54,16 +66,31 @@ namespace System.Buffers
internal unsafe void BufferAllocated(int bufferId, int bufferSize, int poolId, int bucketId, BufferAllocatedReason reason)
{
EventData* payload = stackalloc EventData[5];
- payload[0].Size = sizeof(int);
- payload[0].DataPointer = ((IntPtr)(&bufferId));
- payload[1].Size = sizeof(int);
- payload[1].DataPointer = ((IntPtr)(&bufferSize));
- payload[2].Size = sizeof(int);
- payload[2].DataPointer = ((IntPtr)(&poolId));
- payload[3].Size = sizeof(int);
- payload[3].DataPointer = ((IntPtr)(&bucketId));
- payload[4].Size = sizeof(BufferAllocatedReason);
- payload[4].DataPointer = ((IntPtr)(&reason));
+ payload[0] = new EventData
+ {
+ Size = sizeof(int),
+ DataPointer = ((IntPtr)(&bufferId))
+ };
+ payload[1] = new EventData
+ {
+ Size = sizeof(int),
+ DataPointer = ((IntPtr)(&bufferSize))
+ };
+ payload[2] = new EventData
+ {
+ Size = sizeof(int),
+ DataPointer = ((IntPtr)(&poolId))
+ };
+ payload[3] = new EventData
+ {
+ Size = sizeof(int),
+ DataPointer = ((IntPtr)(&bucketId))
+ };
+ payload[4] = new EventData
+ {
+ Size = sizeof(BufferAllocatedReason),
+ DataPointer = ((IntPtr)(&reason))
+ };
WriteEventCore(2, 5, payload);
}
diff --git a/src/System.CodeDom/tests/CSharpCodeGenerationTests.cs b/src/System.CodeDom/tests/CSharpCodeGenerationTests.cs
index 01442cc94b..054fcffdfa 100644
--- a/src/System.CodeDom/tests/CSharpCodeGenerationTests.cs
+++ b/src/System.CodeDom/tests/CSharpCodeGenerationTests.cs
@@ -4,6 +4,7 @@
using System.CodeDom.Compiler;
using System.Collections.Generic;
+using System.Globalization;
using System.Reflection;
using Microsoft.CSharp;
using Xunit;
@@ -614,213 +615,218 @@ namespace System.CodeDom.Tests
[Fact]
public void MetadataAttributes()
{
- var cu = new CodeCompileUnit();
+ RemoteInvoke(() =>
+ {
+ CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture;
- var ns = new CodeNamespace();
- ns.Name = "MyNamespace";
- ns.Imports.Add(new CodeNamespaceImport("System"));
- ns.Imports.Add(new CodeNamespaceImport("System.Drawing"));
- ns.Imports.Add(new CodeNamespaceImport("System.Windows.Forms"));
- ns.Imports.Add(new CodeNamespaceImport("System.ComponentModel"));
- cu.Namespaces.Add(ns);
-
- var attrs = cu.AssemblyCustomAttributes;
- attrs.Add(new CodeAttributeDeclaration("System.Reflection.AssemblyTitle", new CodeAttributeArgument(new CodePrimitiveExpression("MyAssembly"))));
- attrs.Add(new CodeAttributeDeclaration("System.Reflection.AssemblyVersion", new CodeAttributeArgument(new CodePrimitiveExpression("1.0.6.2"))));
- attrs.Add(new CodeAttributeDeclaration("System.CLSCompliantAttribute", new CodeAttributeArgument(new CodePrimitiveExpression(false))));
-
- var class1 = new CodeTypeDeclaration() { Name = "MyClass" };
- class1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Serializable"));
- class1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Obsolete", new CodeAttributeArgument(new CodePrimitiveExpression("Don't use this Class"))));
- ns.Types.Add(class1);
+ var cu = new CodeCompileUnit();
- var nestedClass = new CodeTypeDeclaration("NestedClass") { IsClass = true, TypeAttributes = TypeAttributes.NestedPublic };
- nestedClass.CustomAttributes.Add(new CodeAttributeDeclaration("System.Serializable"));
- class1.Members.Add(nestedClass);
-
- var method1 = new CodeMemberMethod() { Name = "MyMethod" };
- method1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Obsolete", new CodeAttributeArgument(new CodePrimitiveExpression("Don't use this Method"))));
- method1.CustomAttributes.Add(new CodeAttributeDeclaration("System.ComponentModel.Editor", new CodeAttributeArgument(new CodePrimitiveExpression("This")), new CodeAttributeArgument(new CodePrimitiveExpression("That"))));
- var param1 = new CodeParameterDeclarationExpression(typeof(string), "blah");
- param1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Xml.Serialization.XmlElementAttribute",
- new CodeAttributeArgument("Form", new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("System.Xml.Schema.XmlSchemaForm"), "Unqualified")),
- new CodeAttributeArgument("IsNullable", new CodePrimitiveExpression(false))));
- method1.Parameters.Add(param1);
- var param2 = new CodeParameterDeclarationExpression(typeof(int[]), "arrayit");
- param2.CustomAttributes.Add(
- new CodeAttributeDeclaration("System.Xml.Serialization.XmlElementAttribute",
- new CodeAttributeArgument("Form", new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("System.Xml.Schema.XmlSchemaForm"), "Unqualified")),
- new CodeAttributeArgument("IsNullable", new CodePrimitiveExpression(false))));
- method1.Parameters.Add(param2);
- class1.Members.Add(method1);
-
- var function1 = new CodeMemberMethod();
- function1.Name = "MyFunction";
- function1.ReturnType = new CodeTypeReference(typeof(string));
- function1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Obsolete", new CodeAttributeArgument(new CodePrimitiveExpression("Don't use this Function"))));
- function1.ReturnTypeCustomAttributes.Add(new CodeAttributeDeclaration("System.Xml.Serialization.XmlIgnoreAttribute"));
- function1.ReturnTypeCustomAttributes.Add(new CodeAttributeDeclaration("System.Xml.Serialization.XmlRootAttribute", new
- CodeAttributeArgument("Namespace", new CodePrimitiveExpression("Namespace Value")), new
- CodeAttributeArgument("ElementName", new CodePrimitiveExpression("Root, hehehe"))));
- function1.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression("Return")));
- class1.Members.Add(function1);
-
- CodeMemberMethod function2 = new CodeMemberMethod();
- function2.Name = "GlobalKeywordFunction";
- function2.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(ObsoleteAttribute), CodeTypeReferenceOptions.GlobalReference), new
- CodeAttributeArgument(new CodePrimitiveExpression("Don't use this Function"))));
- CodeTypeReference typeRef = new CodeTypeReference("System.Xml.Serialization.XmlIgnoreAttribute", CodeTypeReferenceOptions.GlobalReference);
- CodeAttributeDeclaration codeAttrib = new CodeAttributeDeclaration(typeRef);
- function2.ReturnTypeCustomAttributes.Add(codeAttrib);
- class1.Members.Add(function2);
-
- CodeMemberField field1 = new CodeMemberField();
- field1.Name = "myField";
- field1.Type = new CodeTypeReference(typeof(string));
- field1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Xml.Serialization.XmlElementAttribute"));
- field1.InitExpression = new CodePrimitiveExpression("hi!");
- class1.Members.Add(field1);
+ var ns = new CodeNamespace();
+ ns.Name = "MyNamespace";
+ ns.Imports.Add(new CodeNamespaceImport("System"));
+ ns.Imports.Add(new CodeNamespaceImport("System.Drawing"));
+ ns.Imports.Add(new CodeNamespaceImport("System.Windows.Forms"));
+ ns.Imports.Add(new CodeNamespaceImport("System.ComponentModel"));
+ cu.Namespaces.Add(ns);
- CodeMemberProperty prop1 = new CodeMemberProperty();
- prop1.Name = "MyProperty";
- prop1.Type = new CodeTypeReference(typeof(string));
- prop1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Obsolete", new CodeAttributeArgument(new CodePrimitiveExpression("Don't use this Property"))));
- prop1.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "myField")));
- class1.Members.Add(prop1);
+ var attrs = cu.AssemblyCustomAttributes;
+ attrs.Add(new CodeAttributeDeclaration("System.Reflection.AssemblyTitle", new CodeAttributeArgument(new CodePrimitiveExpression("MyAssembly"))));
+ attrs.Add(new CodeAttributeDeclaration("System.Reflection.AssemblyVersion", new CodeAttributeArgument(new CodePrimitiveExpression("1.0.6.2"))));
+ attrs.Add(new CodeAttributeDeclaration("System.CLSCompliantAttribute", new CodeAttributeArgument(new CodePrimitiveExpression(false))));
- CodeConstructor const1 = new CodeConstructor();
- const1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Obsolete", new CodeAttributeArgument(new CodePrimitiveExpression("Don't use this Constructor"))));
- class1.Members.Add(const1);
+ var class1 = new CodeTypeDeclaration() { Name = "MyClass" };
+ class1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Serializable"));
+ class1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Obsolete", new CodeAttributeArgument(new CodePrimitiveExpression("Don't use this Class"))));
+ ns.Types.Add(class1);
- class1 = new CodeTypeDeclaration("Test");
- class1.IsClass = true;
- class1.BaseTypes.Add(new CodeTypeReference("Form"));
- ns.Types.Add(class1);
+ var nestedClass = new CodeTypeDeclaration("NestedClass") { IsClass = true, TypeAttributes = TypeAttributes.NestedPublic };
+ nestedClass.CustomAttributes.Add(new CodeAttributeDeclaration("System.Serializable"));
+ class1.Members.Add(nestedClass);
- CodeMemberField mfield = new CodeMemberField(new CodeTypeReference("Button"), "b");
- mfield.InitExpression = new CodeObjectCreateExpression(new CodeTypeReference("Button"));
- class1.Members.Add(mfield);
-
- CodeConstructor ctor = new CodeConstructor();
- ctor.Attributes = MemberAttributes.Public;
- ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(),
- "Size"), new CodeObjectCreateExpression(new CodeTypeReference("Size"),
- new CodePrimitiveExpression(600), new CodePrimitiveExpression(600))));
- ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("b"),
- "Text"), new CodePrimitiveExpression("Test")));
- ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("b"),
- "TabIndex"), new CodePrimitiveExpression(0)));
- ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("b"),
- "Location"), new CodeObjectCreateExpression(new CodeTypeReference("Point"),
- new CodePrimitiveExpression(400), new CodePrimitiveExpression(525))));
- ctor.Statements.Add(new CodeAttachEventStatement(new CodeEventReferenceExpression(new
- CodeThisReferenceExpression(), "MyEvent"), new CodeDelegateCreateExpression(new CodeTypeReference("EventHandler")
- , new CodeThisReferenceExpression(), "b_Click")));
- class1.Members.Add(ctor);
-
- CodeMemberEvent evt = new CodeMemberEvent();
- evt.Name = "MyEvent";
- evt.Type = new CodeTypeReference("System.EventHandler");
- evt.Attributes = MemberAttributes.Public;
- evt.CustomAttributes.Add(new CodeAttributeDeclaration("System.CLSCompliantAttribute", new CodeAttributeArgument(new CodePrimitiveExpression(false))));
- class1.Members.Add(evt);
+ var method1 = new CodeMemberMethod() { Name = "MyMethod" };
+ method1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Obsolete", new CodeAttributeArgument(new CodePrimitiveExpression("Don't use this Method"))));
+ method1.CustomAttributes.Add(new CodeAttributeDeclaration("System.ComponentModel.Editor", new CodeAttributeArgument(new CodePrimitiveExpression("This")), new CodeAttributeArgument(new CodePrimitiveExpression("That"))));
+ var param1 = new CodeParameterDeclarationExpression(typeof(string), "blah");
+ param1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Xml.Serialization.XmlElementAttribute",
+ new CodeAttributeArgument("Form", new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("System.Xml.Schema.XmlSchemaForm"), "Unqualified")),
+ new CodeAttributeArgument("IsNullable", new CodePrimitiveExpression(false))));
+ method1.Parameters.Add(param1);
+ var param2 = new CodeParameterDeclarationExpression(typeof(int[]), "arrayit");
+ param2.CustomAttributes.Add(
+ new CodeAttributeDeclaration("System.Xml.Serialization.XmlElementAttribute",
+ new CodeAttributeArgument("Form", new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("System.Xml.Schema.XmlSchemaForm"), "Unqualified")),
+ new CodeAttributeArgument("IsNullable", new CodePrimitiveExpression(false))));
+ method1.Parameters.Add(param2);
+ class1.Members.Add(method1);
+
+ var function1 = new CodeMemberMethod();
+ function1.Name = "MyFunction";
+ function1.ReturnType = new CodeTypeReference(typeof(string));
+ function1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Obsolete", new CodeAttributeArgument(new CodePrimitiveExpression("Don't use this Function"))));
+ function1.ReturnTypeCustomAttributes.Add(new CodeAttributeDeclaration("System.Xml.Serialization.XmlIgnoreAttribute"));
+ function1.ReturnTypeCustomAttributes.Add(new CodeAttributeDeclaration("System.Xml.Serialization.XmlRootAttribute", new
+ CodeAttributeArgument("Namespace", new CodePrimitiveExpression("Namespace Value")), new
+ CodeAttributeArgument("ElementName", new CodePrimitiveExpression("Root, hehehe"))));
+ function1.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression("Return")));
+ class1.Members.Add(function1);
+
+ CodeMemberMethod function2 = new CodeMemberMethod();
+ function2.Name = "GlobalKeywordFunction";
+ function2.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(ObsoleteAttribute), CodeTypeReferenceOptions.GlobalReference), new
+ CodeAttributeArgument(new CodePrimitiveExpression("Don't use this Function"))));
+ CodeTypeReference typeRef = new CodeTypeReference("System.Xml.Serialization.XmlIgnoreAttribute", CodeTypeReferenceOptions.GlobalReference);
+ CodeAttributeDeclaration codeAttrib = new CodeAttributeDeclaration(typeRef);
+ function2.ReturnTypeCustomAttributes.Add(codeAttrib);
+ class1.Members.Add(function2);
+
+ CodeMemberField field1 = new CodeMemberField();
+ field1.Name = "myField";
+ field1.Type = new CodeTypeReference(typeof(string));
+ field1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Xml.Serialization.XmlElementAttribute"));
+ field1.InitExpression = new CodePrimitiveExpression("hi!");
+ class1.Members.Add(field1);
+
+ CodeMemberProperty prop1 = new CodeMemberProperty();
+ prop1.Name = "MyProperty";
+ prop1.Type = new CodeTypeReference(typeof(string));
+ prop1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Obsolete", new CodeAttributeArgument(new CodePrimitiveExpression("Don't use this Property"))));
+ prop1.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "myField")));
+ class1.Members.Add(prop1);
+
+ CodeConstructor const1 = new CodeConstructor();
+ const1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Obsolete", new CodeAttributeArgument(new CodePrimitiveExpression("Don't use this Constructor"))));
+ class1.Members.Add(const1);
- var cmm = new CodeMemberMethod();
- cmm.Name = "b_Click";
- cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "sender"));
- cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(EventArgs), "e"));
- class1.Members.Add(cmm);
+ class1 = new CodeTypeDeclaration("Test");
+ class1.IsClass = true;
+ class1.BaseTypes.Add(new CodeTypeReference("Form"));
+ ns.Types.Add(class1);
- AssertEqual(cu,
- @"//------------------------------------------------------------------------------
- // <auto-generated>
- // This code was generated by a tool.
- // Runtime Version:4.0.30319.42000
- //
- // Changes to this file may cause incorrect behavior and will be lost if
- // the code is regenerated.
- // </auto-generated>
- //------------------------------------------------------------------------------
-
- [assembly: System.Reflection.AssemblyTitle(""MyAssembly"")]
- [assembly: System.Reflection.AssemblyVersion(""1.0.6.2"")]
- [assembly: System.CLSCompliantAttribute(false)]
-
- namespace MyNamespace
- {
- using System;
- using System.Drawing;
- using System.Windows.Forms;
- using System.ComponentModel;
-
- [System.Serializable()]
- [System.Obsolete(""Don\'t use this Class"")]
- public class MyClass
+ CodeMemberField mfield = new CodeMemberField(new CodeTypeReference("Button"), "b");
+ mfield.InitExpression = new CodeObjectCreateExpression(new CodeTypeReference("Button"));
+ class1.Members.Add(mfield);
+
+ CodeConstructor ctor = new CodeConstructor();
+ ctor.Attributes = MemberAttributes.Public;
+ ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(),
+ "Size"), new CodeObjectCreateExpression(new CodeTypeReference("Size"),
+ new CodePrimitiveExpression(600), new CodePrimitiveExpression(600))));
+ ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("b"),
+ "Text"), new CodePrimitiveExpression("Test")));
+ ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("b"),
+ "TabIndex"), new CodePrimitiveExpression(0)));
+ ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("b"),
+ "Location"), new CodeObjectCreateExpression(new CodeTypeReference("Point"),
+ new CodePrimitiveExpression(400), new CodePrimitiveExpression(525))));
+ ctor.Statements.Add(new CodeAttachEventStatement(new CodeEventReferenceExpression(new
+ CodeThisReferenceExpression(), "MyEvent"), new CodeDelegateCreateExpression(new CodeTypeReference("EventHandler")
+ , new CodeThisReferenceExpression(), "b_Click")));
+ class1.Members.Add(ctor);
+
+ CodeMemberEvent evt = new CodeMemberEvent();
+ evt.Name = "MyEvent";
+ evt.Type = new CodeTypeReference("System.EventHandler");
+ evt.Attributes = MemberAttributes.Public;
+ evt.CustomAttributes.Add(new CodeAttributeDeclaration("System.CLSCompliantAttribute", new CodeAttributeArgument(new CodePrimitiveExpression(false))));
+ class1.Members.Add(evt);
+
+ var cmm = new CodeMemberMethod();
+ cmm.Name = "b_Click";
+ cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "sender"));
+ cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(EventArgs), "e"));
+ class1.Members.Add(cmm);
+
+ AssertEqual(cu,
+ @"//------------------------------------------------------------------------------
+ // <auto-generated>
+ // This code was generated by a tool.
+ // Runtime Version:4.0.30319.42000
+ //
+ // Changes to this file may cause incorrect behavior and will be lost if
+ // the code is regenerated.
+ // </auto-generated>
+ //------------------------------------------------------------------------------
+
+ [assembly: System.Reflection.AssemblyTitle(""MyAssembly"")]
+ [assembly: System.Reflection.AssemblyVersion(""1.0.6.2"")]
+ [assembly: System.CLSCompliantAttribute(false)]
+
+ namespace MyNamespace
{
- [System.Xml.Serialization.XmlElementAttribute()]
- private string myField = ""hi!"";
-
- [System.Obsolete(""Don\'t use this Constructor"")]
- private MyClass()
+ using System;
+ using System.Drawing;
+ using System.Windows.Forms;
+ using System.ComponentModel;
+
+ [System.Serializable()]
+ [System.Obsolete(""Don\'t use this Class"")]
+ public class MyClass
{
- }
+ [System.Xml.Serialization.XmlElementAttribute()]
+ private string myField = ""hi!"";
- [System.Obsolete(""Don\'t use this Property"")]
- private string MyProperty
- {
- get
+ [System.Obsolete(""Don\'t use this Constructor"")]
+ private MyClass()
{
- return this.myField;
}
- }
- [System.Obsolete(""Don\'t use this Method"")]
- [System.ComponentModel.Editor(""This"", ""That"")]
- private void MyMethod([System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=false)] string blah, [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=false)] int[] arrayit)
- {
- }
+ [System.Obsolete(""Don\'t use this Property"")]
+ private string MyProperty
+ {
+ get
+ {
+ return this.myField;
+ }
+ }
- [System.Obsolete(""Don\'t use this Function"")]
- [return: System.Xml.Serialization.XmlIgnoreAttribute()]
- [return: System.Xml.Serialization.XmlRootAttribute(Namespace=""Namespace Value"", ElementName=""Root, hehehe"")]
- private string MyFunction()
- {
- return ""Return"";
- }
+ [System.Obsolete(""Don\'t use this Method"")]
+ [System.ComponentModel.Editor(""This"", ""That"")]
+ private void MyMethod([System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=false)] string blah, [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=false)] int[] arrayit)
+ {
+ }
- [global::System.ObsoleteAttribute(""Don\'t use this Function"")]
- [return: global::System.Xml.Serialization.XmlIgnoreAttribute()]
- private void GlobalKeywordFunction()
- {
- }
+ [System.Obsolete(""Don\'t use this Function"")]
+ [return: System.Xml.Serialization.XmlIgnoreAttribute()]
+ [return: System.Xml.Serialization.XmlRootAttribute(Namespace=""Namespace Value"", ElementName=""Root, hehehe"")]
+ private string MyFunction()
+ {
+ return ""Return"";
+ }
- [System.Serializable()]
- public class NestedClass
- {
- }
- }
+ [global::System.ObsoleteAttribute(""Don\'t use this Function"")]
+ [return: global::System.Xml.Serialization.XmlIgnoreAttribute()]
+ private void GlobalKeywordFunction()
+ {
+ }
- public class Test : Form
- {
- private Button b = new Button();
+ [System.Serializable()]
+ public class NestedClass
+ {
+ }
+ }
- public Test()
+ public class Test : Form
{
- this.Size = new Size(600, 600);
- b.Text = ""Test"";
- b.TabIndex = 0;
- b.Location = new Point(400, 525);
- this.MyEvent += new EventHandler(this.b_Click);
- }
+ private Button b = new Button();
- [System.CLSCompliantAttribute(false)]
- public event System.EventHandler MyEvent;
+ public Test()
+ {
+ this.Size = new Size(600, 600);
+ b.Text = ""Test"";
+ b.TabIndex = 0;
+ b.Location = new Point(400, 525);
+ this.MyEvent += new EventHandler(this.b_Click);
+ }
- private void b_Click(object sender, System.EventArgs e)
- {
+ [System.CLSCompliantAttribute(false)]
+ public event System.EventHandler MyEvent;
+
+ private void b_Click(object sender, System.EventArgs e)
+ {
+ }
}
- }
- }");
+ }");
+ }).Dispose();
}
[Fact]
@@ -1446,296 +1452,301 @@ namespace System.CodeDom.Tests
[Fact]
public void RegionsSnippetsAndLinePragmas()
{
- var cu = new CodeCompileUnit();
- CodeNamespace ns = new CodeNamespace("Namespace1");
+ RemoteInvoke(() =>
+ {
+ CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture;
- cu.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Compile Unit Region"));
- cu.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+ var cu = new CodeCompileUnit();
+ CodeNamespace ns = new CodeNamespace("Namespace1");
- cu.Namespaces.Add(ns);
+ cu.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Compile Unit Region"));
+ cu.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
- var cd = new CodeTypeDeclaration("Class1");
- ns.Types.Add(cd);
+ cu.Namespaces.Add(ns);
- cd.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Outer Type Region"));
- cd.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+ var cd = new CodeTypeDeclaration("Class1");
+ ns.Types.Add(cd);
- cd.Comments.Add(new CodeCommentStatement("Outer Type Comment"));
+ cd.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Outer Type Region"));
+ cd.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
- CodeMemberField field1 = new CodeMemberField(typeof(String), "field1");
- CodeMemberField field2 = new CodeMemberField(typeof(String), "field2");
- field1.Comments.Add(new CodeCommentStatement("Field 1 Comment"));
- field2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Field Region"));
- field2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+ cd.Comments.Add(new CodeCommentStatement("Outer Type Comment"));
- CodeMemberEvent evt1 = new CodeMemberEvent();
- evt1.Name = "Event1";
- evt1.Type = new CodeTypeReference(typeof(System.EventHandler));
- evt1.Attributes = (evt1.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
+ CodeMemberField field1 = new CodeMemberField(typeof(String), "field1");
+ CodeMemberField field2 = new CodeMemberField(typeof(String), "field2");
+ field1.Comments.Add(new CodeCommentStatement("Field 1 Comment"));
+ field2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Field Region"));
+ field2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
- CodeMemberEvent evt2 = new CodeMemberEvent();
- evt2.Name = "Event2";
- evt2.Type = new CodeTypeReference(typeof(System.EventHandler));
- evt2.Attributes = (evt2.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
+ CodeMemberEvent evt1 = new CodeMemberEvent();
+ evt1.Name = "Event1";
+ evt1.Type = new CodeTypeReference(typeof(System.EventHandler));
+ evt1.Attributes = (evt1.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
- evt2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Event Region"));
- evt2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+ CodeMemberEvent evt2 = new CodeMemberEvent();
+ evt2.Name = "Event2";
+ evt2.Type = new CodeTypeReference(typeof(System.EventHandler));
+ evt2.Attributes = (evt2.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
- CodeMemberMethod method1 = new CodeMemberMethod();
- method1.Name = "Method1";
- method1.Attributes = (method1.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
- method1.Statements.Add(
- new CodeDelegateInvokeExpression(
- new CodeEventReferenceExpression(new CodeThisReferenceExpression(), "Event1"),
- new CodeExpression[] {
- new CodeThisReferenceExpression(),
- new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("System.EventArgs"), "Empty")
- }));
-
- CodeMemberMethod method2 = new CodeMemberMethod();
- method2.Name = "Method2";
- method2.Attributes = (method2.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
- method2.Statements.Add(
- new CodeDelegateInvokeExpression(
- new CodeEventReferenceExpression(new CodeThisReferenceExpression(), "Event2"),
- new CodeExpression[] {
- new CodeThisReferenceExpression(),
- new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("System.EventArgs"), "Empty")
- }));
- method2.LinePragma = new CodeLinePragma("MethodLinePragma.txt", 500);
- method2.Comments.Add(new CodeCommentStatement("Method 2 Comment"));
-
- method2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Method Region"));
- method2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
-
- CodeMemberProperty property1 = new CodeMemberProperty();
- property1.Name = "Property1";
- property1.Type = new CodeTypeReference(typeof(string));
- property1.Attributes = (property1.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
- property1.GetStatements.Add(
- new CodeMethodReturnStatement(
- new CodeFieldReferenceExpression(
- new CodeThisReferenceExpression(),
- "field1")));
+ evt2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Event Region"));
+ evt2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
- CodeMemberProperty property2 = new CodeMemberProperty();
- property2.Name = "Property2";
- property2.Type = new CodeTypeReference(typeof(string));
- property2.Attributes = (property2.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
- property2.GetStatements.Add(
- new CodeMethodReturnStatement(
- new CodeFieldReferenceExpression(
+ CodeMemberMethod method1 = new CodeMemberMethod();
+ method1.Name = "Method1";
+ method1.Attributes = (method1.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
+ method1.Statements.Add(
+ new CodeDelegateInvokeExpression(
+ new CodeEventReferenceExpression(new CodeThisReferenceExpression(), "Event1"),
+ new CodeExpression[] {
+ new CodeThisReferenceExpression(),
+ new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("System.EventArgs"), "Empty")
+ }));
+
+ CodeMemberMethod method2 = new CodeMemberMethod();
+ method2.Name = "Method2";
+ method2.Attributes = (method2.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
+ method2.Statements.Add(
+ new CodeDelegateInvokeExpression(
+ new CodeEventReferenceExpression(new CodeThisReferenceExpression(), "Event2"),
+ new CodeExpression[] {
new CodeThisReferenceExpression(),
- "field2")));
-
- property2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Property Region"));
- property2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
-
- CodeConstructor constructor1 = new CodeConstructor();
- constructor1.Attributes = (constructor1.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
- CodeStatement conState1 = new CodeAssignStatement(
- new CodeFieldReferenceExpression(
- new CodeThisReferenceExpression(),
- "field1"),
- new CodePrimitiveExpression("value1"));
- conState1.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Statements Region"));
- constructor1.Statements.Add(conState1);
- CodeStatement conState2 = new CodeAssignStatement(
- new CodeFieldReferenceExpression(
- new CodeThisReferenceExpression(),
- "field2"),
- new CodePrimitiveExpression("value2"));
- conState2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
- constructor1.Statements.Add(conState2);
-
- constructor1.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Constructor Region"));
- constructor1.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
-
- CodeConstructor constructor2 = new CodeConstructor();
- constructor2.Attributes = (constructor2.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
- constructor2.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "value1"));
- constructor2.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "value2"));
-
- CodeTypeConstructor typeConstructor2 = new CodeTypeConstructor();
-
- typeConstructor2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Type Constructor Region"));
- typeConstructor2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
-
- CodeEntryPointMethod methodMain = new CodeEntryPointMethod();
-
- CodeTypeDeclaration nestedClass1 = new CodeTypeDeclaration("NestedClass1");
- CodeTypeDeclaration nestedClass2 = new CodeTypeDeclaration("NestedClass2");
- nestedClass2.LinePragma = new CodeLinePragma("NestedTypeLinePragma.txt", 400);
- nestedClass2.Comments.Add(new CodeCommentStatement("Nested Type Comment"));
+ new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("System.EventArgs"), "Empty")
+ }));
+ method2.LinePragma = new CodeLinePragma("MethodLinePragma.txt", 500);
+ method2.Comments.Add(new CodeCommentStatement("Method 2 Comment"));
+
+ method2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Method Region"));
+ method2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+
+ CodeMemberProperty property1 = new CodeMemberProperty();
+ property1.Name = "Property1";
+ property1.Type = new CodeTypeReference(typeof(string));
+ property1.Attributes = (property1.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
+ property1.GetStatements.Add(
+ new CodeMethodReturnStatement(
+ new CodeFieldReferenceExpression(
+ new CodeThisReferenceExpression(),
+ "field1")));
+
+ CodeMemberProperty property2 = new CodeMemberProperty();
+ property2.Name = "Property2";
+ property2.Type = new CodeTypeReference(typeof(string));
+ property2.Attributes = (property2.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
+ property2.GetStatements.Add(
+ new CodeMethodReturnStatement(
+ new CodeFieldReferenceExpression(
+ new CodeThisReferenceExpression(),
+ "field2")));
+
+ property2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Property Region"));
+ property2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+
+ CodeConstructor constructor1 = new CodeConstructor();
+ constructor1.Attributes = (constructor1.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
+ CodeStatement conState1 = new CodeAssignStatement(
+ new CodeFieldReferenceExpression(
+ new CodeThisReferenceExpression(),
+ "field1"),
+ new CodePrimitiveExpression("value1"));
+ conState1.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Statements Region"));
+ constructor1.Statements.Add(conState1);
+ CodeStatement conState2 = new CodeAssignStatement(
+ new CodeFieldReferenceExpression(
+ new CodeThisReferenceExpression(),
+ "field2"),
+ new CodePrimitiveExpression("value2"));
+ conState2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+ constructor1.Statements.Add(conState2);
+
+ constructor1.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Constructor Region"));
+ constructor1.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+
+ CodeConstructor constructor2 = new CodeConstructor();
+ constructor2.Attributes = (constructor2.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
+ constructor2.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "value1"));
+ constructor2.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "value2"));
+
+ CodeTypeConstructor typeConstructor2 = new CodeTypeConstructor();
+
+ typeConstructor2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Type Constructor Region"));
+ typeConstructor2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+
+ CodeEntryPointMethod methodMain = new CodeEntryPointMethod();
+
+ CodeTypeDeclaration nestedClass1 = new CodeTypeDeclaration("NestedClass1");
+ CodeTypeDeclaration nestedClass2 = new CodeTypeDeclaration("NestedClass2");
+ nestedClass2.LinePragma = new CodeLinePragma("NestedTypeLinePragma.txt", 400);
+ nestedClass2.Comments.Add(new CodeCommentStatement("Nested Type Comment"));
+
+ nestedClass2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Nested Type Region"));
+ nestedClass2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+
+ CodeTypeDelegate delegate1 = new CodeTypeDelegate();
+ delegate1.Name = "nestedDelegate1";
+ delegate1.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference("System.Object"), "sender"));
+ delegate1.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference("System.EventArgs"), "e"));
+
+ CodeTypeDelegate delegate2 = new CodeTypeDelegate();
+ delegate2.Name = "nestedDelegate2";
+ delegate2.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference("System.Object"), "sender"));
+ delegate2.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference("System.EventArgs"), "e"));
+
+ delegate2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Delegate Region"));
+ delegate2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+
+ var snippet1 = new CodeSnippetTypeMember();
+ var snippet2 = new CodeSnippetTypeMember();
+
+ CodeRegionDirective regionStart = new CodeRegionDirective(CodeRegionMode.End, "");
+ regionStart.RegionText = "Snippet Region";
+ regionStart.RegionMode = CodeRegionMode.Start;
+ snippet2.StartDirectives.Add(regionStart);
+ snippet2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+
+ cd.Members.Add(field1);
+ cd.Members.Add(method1);
+ cd.Members.Add(constructor1);
+ cd.Members.Add(property1);
+ cd.Members.Add(methodMain);
- nestedClass2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Nested Type Region"));
- nestedClass2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+ cd.Members.Add(evt1);
+ cd.Members.Add(nestedClass1);
+ cd.Members.Add(delegate1);
- CodeTypeDelegate delegate1 = new CodeTypeDelegate();
- delegate1.Name = "nestedDelegate1";
- delegate1.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference("System.Object"), "sender"));
- delegate1.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference("System.EventArgs"), "e"));
+ cd.Members.Add(snippet1);
- CodeTypeDelegate delegate2 = new CodeTypeDelegate();
- delegate2.Name = "nestedDelegate2";
- delegate2.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference("System.Object"), "sender"));
- delegate2.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference("System.EventArgs"), "e"));
+ cd.Members.Add(field2);
+ cd.Members.Add(method2);
+ cd.Members.Add(constructor2);
+ cd.Members.Add(property2);
- delegate2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Delegate Region"));
- delegate2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+ cd.Members.Add(typeConstructor2);
+ cd.Members.Add(evt2);
+ cd.Members.Add(nestedClass2);
+ cd.Members.Add(delegate2);
+ cd.Members.Add(snippet2);
- var snippet1 = new CodeSnippetTypeMember();
- var snippet2 = new CodeSnippetTypeMember();
+ AssertEqual(cu,
+ @"#region Compile Unit Region
+ //------------------------------------------------------------------------------
+ // <auto-generated>
+ // This code was generated by a tool.
+ // Runtime Version:4.0.30319.42000
+ //
+ // Changes to this file may cause incorrect behavior and will be lost if
+ // the code is regenerated.
+ // </auto-generated>
+ //------------------------------------------------------------------------------
- CodeRegionDirective regionStart = new CodeRegionDirective(CodeRegionMode.End, "");
- regionStart.RegionText = "Snippet Region";
- regionStart.RegionMode = CodeRegionMode.Start;
- snippet2.StartDirectives.Add(regionStart);
- snippet2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+ namespace Namespace1 {
- cd.Members.Add(field1);
- cd.Members.Add(method1);
- cd.Members.Add(constructor1);
- cd.Members.Add(property1);
- cd.Members.Add(methodMain);
- cd.Members.Add(evt1);
- cd.Members.Add(nestedClass1);
- cd.Members.Add(delegate1);
+ #region Outer Type Region
+ // Outer Type Comment
+ public class Class1 {
- cd.Members.Add(snippet1);
+ // Field 1 Comment
+ private string field1;
- cd.Members.Add(field2);
- cd.Members.Add(method2);
- cd.Members.Add(constructor2);
- cd.Members.Add(property2);
+ #region Field Region
+ private string field2;
+ #endregion
- cd.Members.Add(typeConstructor2);
- cd.Members.Add(evt2);
- cd.Members.Add(nestedClass2);
- cd.Members.Add(delegate2);
- cd.Members.Add(snippet2);
-
- AssertEqual(cu,
- @"#region Compile Unit Region
- //------------------------------------------------------------------------------
- // <auto-generated>
- // This code was generated by a tool.
- // Runtime Version:4.0.30319.42000
- //
- // Changes to this file may cause incorrect behavior and will be lost if
- // the code is regenerated.
- // </auto-generated>
- //------------------------------------------------------------------------------
-
- namespace Namespace1 {
-
-
- #region Outer Type Region
- // Outer Type Comment
- public class Class1 {
- // Field 1 Comment
- private string field1;
+ #region Snippet Region
+ #endregion
- #region Field Region
- private string field2;
- #endregion
+ #region Type Constructor Region
+ static Class1() {
+ }
+ #endregion
+
+ #region Constructor Region
+ public Class1() {
+ #region Statements Region
+ this.field1 = ""value1"";
+ this.field2 = ""value2"";
+ #endregion
+ }
+ #endregion
- #region Snippet Region
- #endregion
+ public Class1(string value1, string value2)
+ {
+ }
+ public string Property1
+ {
+ get
+ {
+ return this.field1;
+ }
+ }
- #region Type Constructor Region
- static Class1() {
- }
- #endregion
+ #region Property Region
+ public string Property2
+ {
+ get
+ {
+ return this.field2;
+ }
+ }
+ #endregion
- #region Constructor Region
- public Class1() {
- #region Statements Region
- this.field1 = ""value1"";
- this.field2 = ""value2"";
- #endregion
- }
- #endregion
+ public event System.EventHandler Event1;
- public Class1(string value1, string value2)
- {
- }
+ #region Event Region
+ public event System.EventHandler Event2;
+ #endregion
- public string Property1
- {
- get
+ public void Method1()
{
- return this.field1;
+ this.Event1(this, System.EventArgs.Empty);
}
- }
- #region Property Region
- public string Property2
- {
- get
+ public static void Main()
{
- return this.field2;
}
- }
- #endregion
- public event System.EventHandler Event1;
+ #region Method Region
+ // Method 2 Comment
- #region Event Region
- public event System.EventHandler Event2;
- #endregion
-
- public void Method1()
- {
- this.Event1(this, System.EventArgs.Empty);
- }
-
- public static void Main()
- {
- }
+ #line 500 ""MethodLinePragma.txt""
+ public void Method2()
+ {
+ this.Event2(this, System.EventArgs.Empty);
+ }
- #region Method Region
- // Method 2 Comment
+ #line default
+ #line hidden
+ #endregion
- #line 500 ""MethodLinePragma.txt""
- public void Method2()
- {
- this.Event2(this, System.EventArgs.Empty);
- }
+ public class NestedClass1
+ {
+ }
- #line default
- #line hidden
- #endregion
+ public delegate void nestedDelegate1(object sender, System.EventArgs e);
- public class NestedClass1
- {
- }
+ #region Nested Type Region
+ // Nested Type Comment
- public delegate void nestedDelegate1(object sender, System.EventArgs e);
+ #line 400 ""NestedTypeLinePragma.txt""
+ public class NestedClass2
+ {
+ }
- #region Nested Type Region
- // Nested Type Comment
+ #line default
+ #line hidden
+ #endregion
- #line 400 ""NestedTypeLinePragma.txt""
- public class NestedClass2
- {
+ #region Delegate Region
+ public delegate void nestedDelegate2(object sender, System.EventArgs e);
+ #endregion
}
-
- #line default
- #line hidden
- #endregion
-
- #region Delegate Region
- public delegate void nestedDelegate2(object sender, System.EventArgs e);
- #endregion
+ #endregion
}
- #endregion
- }
- #endregion");
+ #endregion");
+ }).Dispose();
}
[Fact]
@@ -2563,794 +2574,799 @@ namespace System.CodeDom.Tests
[Fact]
public void ProviderSupports()
{
- CodeDomProvider provider = GetProvider();
-
- var cu = new CodeCompileUnit();
- var nspace = new CodeNamespace("NSPC");
- nspace.Imports.Add(new CodeNamespaceImport("System"));
- nspace.Imports.Add(new CodeNamespaceImport("System.Drawing"));
- nspace.Imports.Add(new CodeNamespaceImport("System.Windows.Forms"));
- nspace.Imports.Add(new CodeNamespaceImport("System.ComponentModel"));
- cu.Namespaces.Add(nspace);
-
- var cd = new CodeTypeDeclaration("TEST");
- cd.IsClass = true;
- nspace.Types.Add(cd);
-
- // Arrays of Arrays
- var cmm = new CodeMemberMethod();
- cmm.Name = "ArraysOfArrays";
- cmm.ReturnType = new CodeTypeReference(typeof(int));
- cmm.Attributes = MemberAttributes.Final | MemberAttributes.Public;
- if (provider.Supports(GeneratorSupport.ArraysOfArrays))
+ RemoteInvoke(() =>
{
- cmm.Statements.Add(new CodeVariableDeclarationStatement(new CodeTypeReference(typeof(int[][])),
- "arrayOfArrays", new CodeArrayCreateExpression(typeof(int[][]),
- new CodeArrayCreateExpression(typeof(int[]), new CodePrimitiveExpression(3), new CodePrimitiveExpression(4)),
- new CodeArrayCreateExpression(typeof(int[]), new CodeExpression[] { new CodePrimitiveExpression(1) }))));
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodeArrayIndexerExpression(
- new CodeArrayIndexerExpression(new CodeVariableReferenceExpression("arrayOfArrays"), new CodePrimitiveExpression(0))
- , new CodePrimitiveExpression(1))));
- }
- else
- {
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(0)));
- }
- cd.Members.Add(cmm);
+ CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture;
- // assembly attributes
- if (provider.Supports(GeneratorSupport.AssemblyAttributes))
- {
- CodeAttributeDeclarationCollection attrs = cu.AssemblyCustomAttributes;
- attrs.Add(new CodeAttributeDeclaration("System.Reflection.AssemblyTitle", new
- CodeAttributeArgument(new CodePrimitiveExpression("MyAssembly"))));
- attrs.Add(new CodeAttributeDeclaration("System.Reflection.AssemblyVersion", new
- CodeAttributeArgument(new CodePrimitiveExpression("1.0.6.2"))));
- }
+ CodeDomProvider provider = GetProvider();
- CodeTypeDeclaration class1 = new CodeTypeDeclaration();
- if (provider.Supports(GeneratorSupport.ChainedConstructorArguments))
- {
- class1.Name = "Test2";
- class1.IsClass = true;
- nspace.Types.Add(class1);
-
- class1.Members.Add(new CodeMemberField(new CodeTypeReference(typeof(String)), "stringField"));
- CodeMemberProperty prop = new CodeMemberProperty();
- prop.Name = "accessStringField";
- prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
- prop.Type = new CodeTypeReference(typeof(String));
- prop.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(),
- "stringField")));
- prop.SetStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new
- CodeThisReferenceExpression(), "stringField"),
- new CodePropertySetValueReferenceExpression()));
- class1.Members.Add(prop);
-
- CodeConstructor cctor = new CodeConstructor();
- cctor.Attributes = MemberAttributes.Public;
- cctor.ChainedConstructorArgs.Add(new CodePrimitiveExpression("testingString"));
- cctor.ChainedConstructorArgs.Add(new CodePrimitiveExpression(null));
- cctor.ChainedConstructorArgs.Add(new CodePrimitiveExpression(null));
- class1.Members.Add(cctor);
-
- CodeConstructor cc = new CodeConstructor();
- cc.Attributes = MemberAttributes.Public | MemberAttributes.Overloaded;
- cc.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "p1"));
- cc.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "p2"));
- cc.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "p3"));
- cc.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression()
- , "stringField"), new CodeVariableReferenceExpression("p1")));
- class1.Members.Add(cc);
- // verify chained constructors work
- cmm = new CodeMemberMethod();
- cmm.Name = "ChainedConstructorUse";
- cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
- cmm.ReturnType = new CodeTypeReference(typeof(String));
- // utilize constructor
- cmm.Statements.Add(new CodeVariableDeclarationStatement("Test2", "t", new CodeObjectCreateExpression("Test2")));
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodeMethodReferenceExpression(
- new CodeVariableReferenceExpression("t"), "accessStringField")));
- cd.Members.Add(cmm);
- }
+ var cu = new CodeCompileUnit();
+ var nspace = new CodeNamespace("NSPC");
+ nspace.Imports.Add(new CodeNamespaceImport("System"));
+ nspace.Imports.Add(new CodeNamespaceImport("System.Drawing"));
+ nspace.Imports.Add(new CodeNamespaceImport("System.Windows.Forms"));
+ nspace.Imports.Add(new CodeNamespaceImport("System.ComponentModel"));
+ cu.Namespaces.Add(nspace);
- // complex expressions
- if (provider.Supports(GeneratorSupport.ComplexExpressions))
- {
- cmm = new CodeMemberMethod();
- cmm.Name = "ComplexExpressions";
+ var cd = new CodeTypeDeclaration("TEST");
+ cd.IsClass = true;
+ nspace.Types.Add(cd);
+
+ // Arrays of Arrays
+ var cmm = new CodeMemberMethod();
+ cmm.Name = "ArraysOfArrays";
cmm.ReturnType = new CodeTypeReference(typeof(int));
cmm.Attributes = MemberAttributes.Final | MemberAttributes.Public;
- cmm.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(int)), "i"));
- cmm.Statements.Add(new CodeAssignStatement(new CodeVariableReferenceExpression("i"),
- new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.Multiply,
- new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.Add,
- new CodePrimitiveExpression(3)))));
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("i")));
+ if (provider.Supports(GeneratorSupport.ArraysOfArrays))
+ {
+ cmm.Statements.Add(new CodeVariableDeclarationStatement(new CodeTypeReference(typeof(int[][])),
+ "arrayOfArrays", new CodeArrayCreateExpression(typeof(int[][]),
+ new CodeArrayCreateExpression(typeof(int[]), new CodePrimitiveExpression(3), new CodePrimitiveExpression(4)),
+ new CodeArrayCreateExpression(typeof(int[]), new CodeExpression[] { new CodePrimitiveExpression(1) }))));
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodeArrayIndexerExpression(
+ new CodeArrayIndexerExpression(new CodeVariableReferenceExpression("arrayOfArrays"), new CodePrimitiveExpression(0))
+ , new CodePrimitiveExpression(1))));
+ }
+ else
+ {
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(0)));
+ }
cd.Members.Add(cmm);
- }
- if (provider.Supports(GeneratorSupport.DeclareEnums))
- {
- CodeTypeDeclaration ce = new CodeTypeDeclaration("DecimalEnum");
- ce.IsEnum = true;
- nspace.Types.Add(ce);
+ // assembly attributes
+ if (provider.Supports(GeneratorSupport.AssemblyAttributes))
+ {
+ CodeAttributeDeclarationCollection attrs = cu.AssemblyCustomAttributes;
+ attrs.Add(new CodeAttributeDeclaration("System.Reflection.AssemblyTitle", new
+ CodeAttributeArgument(new CodePrimitiveExpression("MyAssembly"))));
+ attrs.Add(new CodeAttributeDeclaration("System.Reflection.AssemblyVersion", new
+ CodeAttributeArgument(new CodePrimitiveExpression("1.0.6.2"))));
+ }
- // things to enumerate
- for (int k = 0; k < 5; k++)
+ CodeTypeDeclaration class1 = new CodeTypeDeclaration();
+ if (provider.Supports(GeneratorSupport.ChainedConstructorArguments))
{
- CodeMemberField Field = new CodeMemberField("System.Int32", "Num" + (k).ToString());
- Field.InitExpression = new CodePrimitiveExpression(k);
- ce.Members.Add(Field);
+ class1.Name = "Test2";
+ class1.IsClass = true;
+ nspace.Types.Add(class1);
+
+ class1.Members.Add(new CodeMemberField(new CodeTypeReference(typeof(String)), "stringField"));
+ CodeMemberProperty prop = new CodeMemberProperty();
+ prop.Name = "accessStringField";
+ prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
+ prop.Type = new CodeTypeReference(typeof(String));
+ prop.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(),
+ "stringField")));
+ prop.SetStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new
+ CodeThisReferenceExpression(), "stringField"),
+ new CodePropertySetValueReferenceExpression()));
+ class1.Members.Add(prop);
+
+ CodeConstructor cctor = new CodeConstructor();
+ cctor.Attributes = MemberAttributes.Public;
+ cctor.ChainedConstructorArgs.Add(new CodePrimitiveExpression("testingString"));
+ cctor.ChainedConstructorArgs.Add(new CodePrimitiveExpression(null));
+ cctor.ChainedConstructorArgs.Add(new CodePrimitiveExpression(null));
+ class1.Members.Add(cctor);
+
+ CodeConstructor cc = new CodeConstructor();
+ cc.Attributes = MemberAttributes.Public | MemberAttributes.Overloaded;
+ cc.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "p1"));
+ cc.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "p2"));
+ cc.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "p3"));
+ cc.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression()
+ , "stringField"), new CodeVariableReferenceExpression("p1")));
+ class1.Members.Add(cc);
+ // verify chained constructors work
+ cmm = new CodeMemberMethod();
+ cmm.Name = "ChainedConstructorUse";
+ cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
+ cmm.ReturnType = new CodeTypeReference(typeof(String));
+ // utilize constructor
+ cmm.Statements.Add(new CodeVariableDeclarationStatement("Test2", "t", new CodeObjectCreateExpression("Test2")));
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodeMethodReferenceExpression(
+ new CodeVariableReferenceExpression("t"), "accessStringField")));
+ cd.Members.Add(cmm);
}
- cmm = new CodeMemberMethod();
- cmm.Name = "OutputDecimalEnumVal";
- cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
- CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression(typeof(int), "i");
- cmm.Parameters.Add(param);
- CodeBinaryOperatorExpression eq = new CodeBinaryOperatorExpression(
- new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.ValueEquality,
- new CodePrimitiveExpression(3));
- CodeMethodReturnStatement truestmt = new CodeMethodReturnStatement(
- new CodeCastExpression(typeof(int),
- new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("DecimalEnum"), "Num3")));
- CodeConditionStatement condstmt = new CodeConditionStatement(eq, truestmt);
- cmm.Statements.Add(condstmt);
-
- eq = new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"),
- CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(4));
- truestmt = new CodeMethodReturnStatement(new CodeCastExpression(typeof(int),
- new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("DecimalEnum"), "Num4")));
- condstmt = new CodeConditionStatement(eq, truestmt);
- cmm.Statements.Add(condstmt);
- eq = new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"),
- CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(2));
- truestmt = new CodeMethodReturnStatement(new CodeCastExpression(typeof(int),
- new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("DecimalEnum"), "Num2")));
- condstmt = new CodeConditionStatement(eq, truestmt);
- cmm.Statements.Add(condstmt);
-
- eq = new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"),
- CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(1));
- truestmt = new CodeMethodReturnStatement(new CodeCastExpression(typeof(int),
- new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("DecimalEnum"), "Num1")));
- condstmt = new CodeConditionStatement(eq, truestmt);
- cmm.Statements.Add(condstmt);
-
- eq = new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"),
- CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(0));
- truestmt = new CodeMethodReturnStatement(new CodeCastExpression(typeof(int),
- new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("DecimalEnum"), "Num0")));
- condstmt = new CodeConditionStatement(eq, truestmt);
- cmm.Statements.Add(condstmt);
-
- cmm.ReturnType = new CodeTypeReference("System.int32");
-
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodeBinaryOperatorExpression(
- new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.Add, new CodePrimitiveExpression(10))));
- cd.Members.Add(cmm);
- }
- if (provider.Supports(GeneratorSupport.DeclareInterfaces))
- {
- cmm = new CodeMemberMethod();
- cmm.Name = "TestSingleInterface";
- cmm.ReturnType = new CodeTypeReference(typeof(int));
- cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "i"));
- cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
- cmm.Statements.Add(new CodeVariableDeclarationStatement("TestSingleInterfaceImp", "t", new CodeObjectCreateExpression("TestSingleInterfaceImp")));
- CodeMethodInvokeExpression methodinvoke = new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("t")
- , "InterfaceMethod");
- methodinvoke.Parameters.Add(new CodeVariableReferenceExpression("i"));
- cmm.Statements.Add(new CodeMethodReturnStatement(methodinvoke));
- cd.Members.Add(cmm);
+ // complex expressions
+ if (provider.Supports(GeneratorSupport.ComplexExpressions))
+ {
+ cmm = new CodeMemberMethod();
+ cmm.Name = "ComplexExpressions";
+ cmm.ReturnType = new CodeTypeReference(typeof(int));
+ cmm.Attributes = MemberAttributes.Final | MemberAttributes.Public;
+ cmm.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(int)), "i"));
+ cmm.Statements.Add(new CodeAssignStatement(new CodeVariableReferenceExpression("i"),
+ new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.Multiply,
+ new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.Add,
+ new CodePrimitiveExpression(3)))));
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("i")));
+ cd.Members.Add(cmm);
+ }
- class1 = new CodeTypeDeclaration("InterfaceA");
- class1.IsInterface = true;
- nspace.Types.Add(class1);
- cmm = new CodeMemberMethod();
- cmm.Attributes = MemberAttributes.Public;
- cmm.Name = "InterfaceMethod";
- cmm.ReturnType = new CodeTypeReference(typeof(int));
- cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "a"));
- class1.Members.Add(cmm);
+ if (provider.Supports(GeneratorSupport.DeclareEnums))
+ {
+ CodeTypeDeclaration ce = new CodeTypeDeclaration("DecimalEnum");
+ ce.IsEnum = true;
+ nspace.Types.Add(ce);
+
+ // things to enumerate
+ for (int k = 0; k < 5; k++)
+ {
+ CodeMemberField Field = new CodeMemberField("System.Int32", "Num" + (k).ToString());
+ Field.InitExpression = new CodePrimitiveExpression(k);
+ ce.Members.Add(Field);
+ }
+ cmm = new CodeMemberMethod();
+ cmm.Name = "OutputDecimalEnumVal";
+ cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
+ CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression(typeof(int), "i");
+ cmm.Parameters.Add(param);
+ CodeBinaryOperatorExpression eq = new CodeBinaryOperatorExpression(
+ new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.ValueEquality,
+ new CodePrimitiveExpression(3));
+ CodeMethodReturnStatement truestmt = new CodeMethodReturnStatement(
+ new CodeCastExpression(typeof(int),
+ new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("DecimalEnum"), "Num3")));
+ CodeConditionStatement condstmt = new CodeConditionStatement(eq, truestmt);
+ cmm.Statements.Add(condstmt);
+
+ eq = new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"),
+ CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(4));
+ truestmt = new CodeMethodReturnStatement(new CodeCastExpression(typeof(int),
+ new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("DecimalEnum"), "Num4")));
+ condstmt = new CodeConditionStatement(eq, truestmt);
+ cmm.Statements.Add(condstmt);
+ eq = new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"),
+ CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(2));
+ truestmt = new CodeMethodReturnStatement(new CodeCastExpression(typeof(int),
+ new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("DecimalEnum"), "Num2")));
+ condstmt = new CodeConditionStatement(eq, truestmt);
+ cmm.Statements.Add(condstmt);
+
+ eq = new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"),
+ CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(1));
+ truestmt = new CodeMethodReturnStatement(new CodeCastExpression(typeof(int),
+ new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("DecimalEnum"), "Num1")));
+ condstmt = new CodeConditionStatement(eq, truestmt);
+ cmm.Statements.Add(condstmt);
+
+ eq = new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"),
+ CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(0));
+ truestmt = new CodeMethodReturnStatement(new CodeCastExpression(typeof(int),
+ new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("DecimalEnum"), "Num0")));
+ condstmt = new CodeConditionStatement(eq, truestmt);
+ cmm.Statements.Add(condstmt);
+
+ cmm.ReturnType = new CodeTypeReference("System.int32");
+
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodeBinaryOperatorExpression(
+ new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.Add, new CodePrimitiveExpression(10))));
+ cd.Members.Add(cmm);
+ }
- if (provider.Supports(GeneratorSupport.MultipleInterfaceMembers))
+ if (provider.Supports(GeneratorSupport.DeclareInterfaces))
{
- CodeTypeDeclaration classDecl = new CodeTypeDeclaration("InterfaceB");
- classDecl.IsInterface = true;
- nspace.Types.Add(classDecl);
cmm = new CodeMemberMethod();
- cmm.Name = "InterfaceMethod";
+ cmm.Name = "TestSingleInterface";
+ cmm.ReturnType = new CodeTypeReference(typeof(int));
+ cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "i"));
+ cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
+ cmm.Statements.Add(new CodeVariableDeclarationStatement("TestSingleInterfaceImp", "t", new CodeObjectCreateExpression("TestSingleInterfaceImp")));
+ CodeMethodInvokeExpression methodinvoke = new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("t")
+ , "InterfaceMethod");
+ methodinvoke.Parameters.Add(new CodeVariableReferenceExpression("i"));
+ cmm.Statements.Add(new CodeMethodReturnStatement(methodinvoke));
+ cd.Members.Add(cmm);
+
+ class1 = new CodeTypeDeclaration("InterfaceA");
+ class1.IsInterface = true;
+ nspace.Types.Add(class1);
+ cmm = new CodeMemberMethod();
cmm.Attributes = MemberAttributes.Public;
+ cmm.Name = "InterfaceMethod";
cmm.ReturnType = new CodeTypeReference(typeof(int));
cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "a"));
- classDecl.Members.Add(cmm);
-
- CodeTypeDeclaration class2 = new CodeTypeDeclaration("TestMultipleInterfaceImp");
- class2.BaseTypes.Add(new CodeTypeReference("System.Object"));
- class2.BaseTypes.Add(new CodeTypeReference("InterfaceB"));
- class2.BaseTypes.Add(new CodeTypeReference("InterfaceA"));
- class2.IsClass = true;
- nspace.Types.Add(class2);
+ class1.Members.Add(cmm);
+
+ if (provider.Supports(GeneratorSupport.MultipleInterfaceMembers))
+ {
+ CodeTypeDeclaration classDecl = new CodeTypeDeclaration("InterfaceB");
+ classDecl.IsInterface = true;
+ nspace.Types.Add(classDecl);
+ cmm = new CodeMemberMethod();
+ cmm.Name = "InterfaceMethod";
+ cmm.Attributes = MemberAttributes.Public;
+ cmm.ReturnType = new CodeTypeReference(typeof(int));
+ cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "a"));
+ classDecl.Members.Add(cmm);
+
+ CodeTypeDeclaration class2 = new CodeTypeDeclaration("TestMultipleInterfaceImp");
+ class2.BaseTypes.Add(new CodeTypeReference("System.Object"));
+ class2.BaseTypes.Add(new CodeTypeReference("InterfaceB"));
+ class2.BaseTypes.Add(new CodeTypeReference("InterfaceA"));
+ class2.IsClass = true;
+ nspace.Types.Add(class2);
+ cmm = new CodeMemberMethod();
+ cmm.ImplementationTypes.Add(new CodeTypeReference("InterfaceA"));
+ cmm.ImplementationTypes.Add(new CodeTypeReference("InterfaceB"));
+ cmm.Name = "InterfaceMethod";
+ cmm.ReturnType = new CodeTypeReference(typeof(int));
+ cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "a"));
+ cmm.Attributes = MemberAttributes.Public | MemberAttributes.Final;
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("a")));
+ class2.Members.Add(cmm);
+
+ cmm = new CodeMemberMethod();
+ cmm.Name = "TestMultipleInterfaces";
+ cmm.ReturnType = new CodeTypeReference(typeof(int));
+ cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "i"));
+ cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
+ cmm.Statements.Add(new CodeVariableDeclarationStatement("TestMultipleInterfaceImp", "t", new CodeObjectCreateExpression("TestMultipleInterfaceImp")));
+ cmm.Statements.Add(new CodeVariableDeclarationStatement("InterfaceA", "interfaceAobject", new CodeCastExpression("InterfaceA",
+ new CodeVariableReferenceExpression("t"))));
+ cmm.Statements.Add(new CodeVariableDeclarationStatement("InterfaceB", "interfaceBobject", new CodeCastExpression("InterfaceB",
+ new CodeVariableReferenceExpression("t"))));
+ methodinvoke = new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("interfaceAobject")
+ , "InterfaceMethod");
+ methodinvoke.Parameters.Add(new CodeVariableReferenceExpression("i"));
+ CodeMethodInvokeExpression methodinvoke2 = new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("interfaceBobject")
+ , "InterfaceMethod");
+ methodinvoke2.Parameters.Add(new CodeVariableReferenceExpression("i"));
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodeBinaryOperatorExpression(
+ methodinvoke,
+ CodeBinaryOperatorType.Subtract, methodinvoke2)));
+ cd.Members.Add(cmm);
+ }
+
+ class1 = new CodeTypeDeclaration("TestSingleInterfaceImp");
+ class1.BaseTypes.Add(new CodeTypeReference("System.Object"));
+ class1.BaseTypes.Add(new CodeTypeReference("InterfaceA"));
+ class1.IsClass = true;
+ nspace.Types.Add(class1);
cmm = new CodeMemberMethod();
cmm.ImplementationTypes.Add(new CodeTypeReference("InterfaceA"));
- cmm.ImplementationTypes.Add(new CodeTypeReference("InterfaceB"));
cmm.Name = "InterfaceMethod";
cmm.ReturnType = new CodeTypeReference(typeof(int));
cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "a"));
- cmm.Attributes = MemberAttributes.Public | MemberAttributes.Final;
+ cmm.Attributes = MemberAttributes.Public;
cmm.Statements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("a")));
- class2.Members.Add(cmm);
+ class1.Members.Add(cmm);
+ }
+ if (provider.Supports(GeneratorSupport.DeclareValueTypes))
+ {
+ CodeTypeDeclaration structA = new CodeTypeDeclaration("structA");
+ structA.IsStruct = true;
+
+ CodeTypeDeclaration structB = new CodeTypeDeclaration("structB");
+ structB.Attributes = MemberAttributes.Public;
+ structB.IsStruct = true;
+
+ CodeMemberField firstInt = new CodeMemberField(typeof(int), "int1");
+ firstInt.Attributes = MemberAttributes.Public;
+ structB.Members.Add(firstInt);
+
+ CodeMemberField innerStruct = new CodeMemberField("structB", "innerStruct");
+ innerStruct.Attributes = MemberAttributes.Public;
+
+ structA.Members.Add(structB);
+ structA.Members.Add(innerStruct);
+ nspace.Types.Add(structA);
+
+ CodeMemberMethod nestedStructMethod = new CodeMemberMethod();
+ nestedStructMethod.Name = "NestedStructMethod";
+ nestedStructMethod.ReturnType = new CodeTypeReference(typeof(int));
+ nestedStructMethod.Attributes = MemberAttributes.Public | MemberAttributes.Static;
+ CodeVariableDeclarationStatement varStructA = new CodeVariableDeclarationStatement("structA", "varStructA");
+ nestedStructMethod.Statements.Add(varStructA);
+ nestedStructMethod.Statements.Add
+ (
+ new CodeAssignStatement
+ (
+ /* Expression1 */ new CodeFieldReferenceExpression(new CodeFieldReferenceExpression(new CodeVariableReferenceExpression("varStructA"), "innerStruct"), "int1"),
+ /* Expression1 */ new CodePrimitiveExpression(3)
+ )
+ );
+ nestedStructMethod.Statements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeFieldReferenceExpression(new CodeVariableReferenceExpression("varStructA"), "innerStruct"), "int1")));
+ cd.Members.Add(nestedStructMethod);
+ }
+ if (provider.Supports(GeneratorSupport.EntryPointMethod))
+ {
+ CodeEntryPointMethod cep = new CodeEntryPointMethod();
+ cd.Members.Add(cep);
+ }
+ // goto statements
+ if (provider.Supports(GeneratorSupport.GotoStatements))
+ {
cmm = new CodeMemberMethod();
- cmm.Name = "TestMultipleInterfaces";
+ cmm.Name = "GoToMethod";
cmm.ReturnType = new CodeTypeReference(typeof(int));
+ cmm.Attributes = MemberAttributes.Public | MemberAttributes.Final;
+ CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression(typeof(int), "i");
+ cmm.Parameters.Add(param);
+ CodeConditionStatement condstmt = new CodeConditionStatement(new CodeBinaryOperatorExpression(
+ new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.LessThan, new CodePrimitiveExpression(1)),
+ new CodeGotoStatement("comehere"));
+ cmm.Statements.Add(condstmt);
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(6)));
+ cmm.Statements.Add(new CodeLabeledStatement("comehere",
+ new CodeMethodReturnStatement(new CodePrimitiveExpression(7))));
+ cd.Members.Add(cmm);
+ }
+ if (provider.Supports(GeneratorSupport.NestedTypes))
+ {
+ cmm = new CodeMemberMethod();
+ cmm.Name = "CallingPublicNestedScenario";
cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "i"));
+ cmm.ReturnType = new CodeTypeReference(typeof(int));
cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
- cmm.Statements.Add(new CodeVariableDeclarationStatement("TestMultipleInterfaceImp", "t", new CodeObjectCreateExpression("TestMultipleInterfaceImp")));
- cmm.Statements.Add(new CodeVariableDeclarationStatement("InterfaceA", "interfaceAobject", new CodeCastExpression("InterfaceA",
- new CodeVariableReferenceExpression("t"))));
- cmm.Statements.Add(new CodeVariableDeclarationStatement("InterfaceB", "interfaceBobject", new CodeCastExpression("InterfaceB",
- new CodeVariableReferenceExpression("t"))));
- methodinvoke = new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("interfaceAobject")
- , "InterfaceMethod");
- methodinvoke.Parameters.Add(new CodeVariableReferenceExpression("i"));
- CodeMethodInvokeExpression methodinvoke2 = new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("interfaceBobject")
- , "InterfaceMethod");
- methodinvoke2.Parameters.Add(new CodeVariableReferenceExpression("i"));
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodeBinaryOperatorExpression(
- methodinvoke,
- CodeBinaryOperatorType.Subtract, methodinvoke2)));
+ cmm.Statements.Add(new CodeVariableDeclarationStatement(new CodeTypeReference
+ ("PublicNestedClassA+PublicNestedClassB2+PublicNestedClassC"), "t",
+ new CodeObjectCreateExpression(new CodeTypeReference
+ ("PublicNestedClassA+PublicNestedClassB2+PublicNestedClassC"))));
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("t"),
+ "publicNestedClassesMethod",
+ new CodeVariableReferenceExpression("i"))));
cd.Members.Add(cmm);
- }
- class1 = new CodeTypeDeclaration("TestSingleInterfaceImp");
- class1.BaseTypes.Add(new CodeTypeReference("System.Object"));
- class1.BaseTypes.Add(new CodeTypeReference("InterfaceA"));
- class1.IsClass = true;
- nspace.Types.Add(class1);
- cmm = new CodeMemberMethod();
- cmm.ImplementationTypes.Add(new CodeTypeReference("InterfaceA"));
- cmm.Name = "InterfaceMethod";
- cmm.ReturnType = new CodeTypeReference(typeof(int));
- cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "a"));
- cmm.Attributes = MemberAttributes.Public;
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("a")));
- class1.Members.Add(cmm);
- }
+ class1 = new CodeTypeDeclaration("PublicNestedClassA");
+ class1.IsClass = true;
+ nspace.Types.Add(class1);
+ CodeTypeDeclaration nestedClass = new CodeTypeDeclaration("PublicNestedClassB1");
+ nestedClass.IsClass = true;
+ nestedClass.TypeAttributes = TypeAttributes.NestedPublic;
+ class1.Members.Add(nestedClass);
+ nestedClass = new CodeTypeDeclaration("PublicNestedClassB2");
+ nestedClass.TypeAttributes = TypeAttributes.NestedPublic;
+ nestedClass.IsClass = true;
+ class1.Members.Add(nestedClass);
+ CodeTypeDeclaration innerNestedClass = new CodeTypeDeclaration("PublicNestedClassC");
+ innerNestedClass.TypeAttributes = TypeAttributes.NestedPublic;
+ innerNestedClass.IsClass = true;
+ nestedClass.Members.Add(innerNestedClass);
+ cmm = new CodeMemberMethod();
+ cmm.Name = "publicNestedClassesMethod";
+ cmm.ReturnType = new CodeTypeReference(typeof(int));
+ cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "a"));
+ cmm.Attributes = MemberAttributes.Public | MemberAttributes.Final;
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("a")));
+ innerNestedClass.Members.Add(cmm);
+ }
+ // Parameter Attributes
+ if (provider.Supports(GeneratorSupport.ParameterAttributes))
+ {
+ CodeMemberMethod method1 = new CodeMemberMethod();
+ method1.Name = "MyMethod";
+ method1.Attributes = MemberAttributes.Public | MemberAttributes.Final;
+ CodeParameterDeclarationExpression param1 = new CodeParameterDeclarationExpression(typeof(string), "blah");
+ param1.CustomAttributes.Add(
+ new CodeAttributeDeclaration(
+ "System.Xml.Serialization.XmlElementAttribute",
+ new CodeAttributeArgument(
+ "Form",
+ new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("System.Xml.Schema.XmlSchemaForm"), "Unqualified")),
+ new CodeAttributeArgument(
+ "IsNullable",
+ new CodePrimitiveExpression(false))));
+ method1.Parameters.Add(param1);
+ cd.Members.Add(method1);
+ }
+ // public static members
+ if (provider.Supports(GeneratorSupport.PublicStaticMembers))
+ {
+ cmm = new CodeMemberMethod();
+ cmm.Name = "PublicStaticMethod";
+ cmm.ReturnType = new CodeTypeReference(typeof(int));
+ cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(16)));
+ cd.Members.Add(cmm);
+ }
+ // reference parameters
+ if (provider.Supports(GeneratorSupport.ReferenceParameters))
+ {
+ cmm = new CodeMemberMethod();
+ cmm.Name = "Work";
+ cmm.ReturnType = new CodeTypeReference("System.void");
+ cmm.Attributes = MemberAttributes.Static;
+ // add parameter with ref direction
+ CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression(typeof(int), "i");
+ param.Direction = FieldDirection.Ref;
+ cmm.Parameters.Add(param);
+ // add parameter with out direction
+ param = new CodeParameterDeclarationExpression(typeof(int), "j");
+ param.Direction = FieldDirection.Out;
+ cmm.Parameters.Add(param);
+ cmm.Statements.Add(new CodeAssignStatement(new CodeArgumentReferenceExpression("i"),
+ new CodeBinaryOperatorExpression(new CodeArgumentReferenceExpression("i"),
+ CodeBinaryOperatorType.Add, new CodePrimitiveExpression(4))));
+ cmm.Statements.Add(new CodeAssignStatement(new CodeArgumentReferenceExpression("j"),
+ new CodePrimitiveExpression(5)));
+ cd.Members.Add(cmm);
- if (provider.Supports(GeneratorSupport.DeclareValueTypes))
- {
- CodeTypeDeclaration structA = new CodeTypeDeclaration("structA");
- structA.IsStruct = true;
-
- CodeTypeDeclaration structB = new CodeTypeDeclaration("structB");
- structB.Attributes = MemberAttributes.Public;
- structB.IsStruct = true;
-
- CodeMemberField firstInt = new CodeMemberField(typeof(int), "int1");
- firstInt.Attributes = MemberAttributes.Public;
- structB.Members.Add(firstInt);
-
- CodeMemberField innerStruct = new CodeMemberField("structB", "innerStruct");
- innerStruct.Attributes = MemberAttributes.Public;
-
- structA.Members.Add(structB);
- structA.Members.Add(innerStruct);
- nspace.Types.Add(structA);
-
- CodeMemberMethod nestedStructMethod = new CodeMemberMethod();
- nestedStructMethod.Name = "NestedStructMethod";
- nestedStructMethod.ReturnType = new CodeTypeReference(typeof(int));
- nestedStructMethod.Attributes = MemberAttributes.Public | MemberAttributes.Static;
- CodeVariableDeclarationStatement varStructA = new CodeVariableDeclarationStatement("structA", "varStructA");
- nestedStructMethod.Statements.Add(varStructA);
- nestedStructMethod.Statements.Add
- (
- new CodeAssignStatement
- (
- /* Expression1 */ new CodeFieldReferenceExpression(new CodeFieldReferenceExpression(new CodeVariableReferenceExpression("varStructA"), "innerStruct"), "int1"),
- /* Expression1 */ new CodePrimitiveExpression(3)
- )
- );
- nestedStructMethod.Statements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeFieldReferenceExpression(new CodeVariableReferenceExpression("varStructA"), "innerStruct"), "int1")));
- cd.Members.Add(nestedStructMethod);
- }
- if (provider.Supports(GeneratorSupport.EntryPointMethod))
- {
- CodeEntryPointMethod cep = new CodeEntryPointMethod();
- cd.Members.Add(cep);
- }
- // goto statements
- if (provider.Supports(GeneratorSupport.GotoStatements))
- {
- cmm = new CodeMemberMethod();
- cmm.Name = "GoToMethod";
- cmm.ReturnType = new CodeTypeReference(typeof(int));
- cmm.Attributes = MemberAttributes.Public | MemberAttributes.Final;
- CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression(typeof(int), "i");
- cmm.Parameters.Add(param);
- CodeConditionStatement condstmt = new CodeConditionStatement(new CodeBinaryOperatorExpression(
- new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.LessThan, new CodePrimitiveExpression(1)),
- new CodeGotoStatement("comehere"));
- cmm.Statements.Add(condstmt);
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(6)));
- cmm.Statements.Add(new CodeLabeledStatement("comehere",
- new CodeMethodReturnStatement(new CodePrimitiveExpression(7))));
- cd.Members.Add(cmm);
- }
- if (provider.Supports(GeneratorSupport.NestedTypes))
- {
- cmm = new CodeMemberMethod();
- cmm.Name = "CallingPublicNestedScenario";
- cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "i"));
- cmm.ReturnType = new CodeTypeReference(typeof(int));
- cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
- cmm.Statements.Add(new CodeVariableDeclarationStatement(new CodeTypeReference
- ("PublicNestedClassA+PublicNestedClassB2+PublicNestedClassC"), "t",
- new CodeObjectCreateExpression(new CodeTypeReference
- ("PublicNestedClassA+PublicNestedClassB2+PublicNestedClassC"))));
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("t"),
- "publicNestedClassesMethod",
- new CodeVariableReferenceExpression("i"))));
- cd.Members.Add(cmm);
+ cmm = new CodeMemberMethod();
+ cmm.Name = "CallingWork";
+ cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
+ CodeParameterDeclarationExpression parames = new CodeParameterDeclarationExpression(typeof(int), "a");
+ cmm.Parameters.Add(parames);
+ cmm.ReturnType = new CodeTypeReference("System.int32");
+ cmm.Statements.Add(new CodeAssignStatement(new CodeVariableReferenceExpression("a"),
+ new CodePrimitiveExpression(10)));
+ cmm.Statements.Add(new CodeVariableDeclarationStatement(typeof(int), "b"));
+ // invoke the method called "work"
+ CodeMethodInvokeExpression methodinvoked = new CodeMethodInvokeExpression(new CodeMethodReferenceExpression
+ (new CodeTypeReferenceExpression("TEST"), "Work"));
+ // add parameter with ref direction
+ CodeDirectionExpression parameter = new CodeDirectionExpression(FieldDirection.Ref,
+ new CodeVariableReferenceExpression("a"));
+ methodinvoked.Parameters.Add(parameter);
+ // add parameter with out direction
+ parameter = new CodeDirectionExpression(FieldDirection.Out, new CodeVariableReferenceExpression("b"));
+ methodinvoked.Parameters.Add(parameter);
+ cmm.Statements.Add(methodinvoked);
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodeBinaryOperatorExpression
+ (new CodeVariableReferenceExpression("a"), CodeBinaryOperatorType.Add, new CodeVariableReferenceExpression("b"))));
+ cd.Members.Add(cmm);
+ }
+ if (provider.Supports(GeneratorSupport.ReturnTypeAttributes))
+ {
+ CodeMemberMethod function1 = new CodeMemberMethod();
+ function1.Name = "MyFunction";
+ function1.ReturnType = new CodeTypeReference(typeof(string));
+ function1.Attributes = MemberAttributes.Public | MemberAttributes.Final;
+ function1.ReturnTypeCustomAttributes.Add(new
+ CodeAttributeDeclaration("System.Xml.Serialization.XmlIgnoreAttribute"));
+ function1.ReturnTypeCustomAttributes.Add(new CodeAttributeDeclaration("System.Xml.Serialization.XmlRootAttribute", new
+ CodeAttributeArgument("Namespace", new CodePrimitiveExpression("Namespace Value")), new
+ CodeAttributeArgument("ElementName", new CodePrimitiveExpression("Root, hehehe"))));
+ function1.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression("Return")));
+ cd.Members.Add(function1);
+ }
+ if (provider.Supports(GeneratorSupport.StaticConstructors))
+ {
+ cmm = new CodeMemberMethod();
+ cmm.Name = "TestStaticConstructor";
+ cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
+ cmm.ReturnType = new CodeTypeReference(typeof(int));
+ CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression(typeof(int), "a");
+ cmm.Parameters.Add(param);
+ // utilize constructor
+ cmm.Statements.Add(new CodeVariableDeclarationStatement("Test4", "t", new CodeObjectCreateExpression("Test4")));
+ // set then get number
+ cmm.Statements.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(new CodeVariableReferenceExpression("t"), "i")
+ , new CodeVariableReferenceExpression("a")));
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodeMethodReferenceExpression(
+ new CodeVariableReferenceExpression("t"), "i")));
+ cd.Members.Add(cmm);
- class1 = new CodeTypeDeclaration("PublicNestedClassA");
- class1.IsClass = true;
- nspace.Types.Add(class1);
- CodeTypeDeclaration nestedClass = new CodeTypeDeclaration("PublicNestedClassB1");
- nestedClass.IsClass = true;
- nestedClass.TypeAttributes = TypeAttributes.NestedPublic;
- class1.Members.Add(nestedClass);
- nestedClass = new CodeTypeDeclaration("PublicNestedClassB2");
- nestedClass.TypeAttributes = TypeAttributes.NestedPublic;
- nestedClass.IsClass = true;
- class1.Members.Add(nestedClass);
- CodeTypeDeclaration innerNestedClass = new CodeTypeDeclaration("PublicNestedClassC");
- innerNestedClass.TypeAttributes = TypeAttributes.NestedPublic;
- innerNestedClass.IsClass = true;
- nestedClass.Members.Add(innerNestedClass);
- cmm = new CodeMemberMethod();
- cmm.Name = "publicNestedClassesMethod";
- cmm.ReturnType = new CodeTypeReference(typeof(int));
- cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "a"));
- cmm.Attributes = MemberAttributes.Public | MemberAttributes.Final;
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("a")));
- innerNestedClass.Members.Add(cmm);
- }
- // Parameter Attributes
- if (provider.Supports(GeneratorSupport.ParameterAttributes))
- {
- CodeMemberMethod method1 = new CodeMemberMethod();
- method1.Name = "MyMethod";
- method1.Attributes = MemberAttributes.Public | MemberAttributes.Final;
- CodeParameterDeclarationExpression param1 = new CodeParameterDeclarationExpression(typeof(string), "blah");
- param1.CustomAttributes.Add(
- new CodeAttributeDeclaration(
- "System.Xml.Serialization.XmlElementAttribute",
- new CodeAttributeArgument(
- "Form",
- new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("System.Xml.Schema.XmlSchemaForm"), "Unqualified")),
- new CodeAttributeArgument(
- "IsNullable",
- new CodePrimitiveExpression(false))));
- method1.Parameters.Add(param1);
- cd.Members.Add(method1);
- }
- // public static members
- if (provider.Supports(GeneratorSupport.PublicStaticMembers))
- {
- cmm = new CodeMemberMethod();
- cmm.Name = "PublicStaticMethod";
- cmm.ReturnType = new CodeTypeReference(typeof(int));
- cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(16)));
- cd.Members.Add(cmm);
- }
- // reference parameters
- if (provider.Supports(GeneratorSupport.ReferenceParameters))
- {
- cmm = new CodeMemberMethod();
- cmm.Name = "Work";
- cmm.ReturnType = new CodeTypeReference("System.void");
- cmm.Attributes = MemberAttributes.Static;
- // add parameter with ref direction
- CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression(typeof(int), "i");
- param.Direction = FieldDirection.Ref;
- cmm.Parameters.Add(param);
- // add parameter with out direction
- param = new CodeParameterDeclarationExpression(typeof(int), "j");
- param.Direction = FieldDirection.Out;
- cmm.Parameters.Add(param);
- cmm.Statements.Add(new CodeAssignStatement(new CodeArgumentReferenceExpression("i"),
- new CodeBinaryOperatorExpression(new CodeArgumentReferenceExpression("i"),
- CodeBinaryOperatorType.Add, new CodePrimitiveExpression(4))));
- cmm.Statements.Add(new CodeAssignStatement(new CodeArgumentReferenceExpression("j"),
- new CodePrimitiveExpression(5)));
- cd.Members.Add(cmm);
+ class1 = new CodeTypeDeclaration();
+ class1.Name = "Test4";
+ class1.IsClass = true;
+ nspace.Types.Add(class1);
+
+ class1.Members.Add(new CodeMemberField(new CodeTypeReference(typeof(int)), "number"));
+ CodeMemberProperty prop = new CodeMemberProperty();
+ prop.Name = "i";
+ prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
+ prop.Type = new CodeTypeReference(typeof(int));
+ prop.GetStatements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("number")));
+ prop.SetStatements.Add(new CodeAssignStatement(new CodeVariableReferenceExpression("number"),
+ new CodePropertySetValueReferenceExpression()));
+ class1.Members.Add(prop);
+ CodeTypeConstructor ctc = new CodeTypeConstructor();
+ class1.Members.Add(ctc);
+ }
+ if (provider.Supports(GeneratorSupport.TryCatchStatements))
+ {
+ cmm = new CodeMemberMethod();
+ cmm.Name = "TryCatchMethod";
+ cmm.ReturnType = new CodeTypeReference(typeof(int));
+ cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
+ CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression(typeof(int), "a");
+ cmm.Parameters.Add(param);
+
+ CodeTryCatchFinallyStatement tcfstmt = new CodeTryCatchFinallyStatement();
+ tcfstmt.FinallyStatements.Add(new CodeAssignStatement(new CodeVariableReferenceExpression("a"), new
+ CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("a"), CodeBinaryOperatorType.Add,
+ new CodePrimitiveExpression(5))));
+ cmm.Statements.Add(tcfstmt);
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("a")));
+ cd.Members.Add(cmm);
+ }
+ if (provider.Supports(GeneratorSupport.DeclareEvents))
+ {
+ CodeNamespace ns = new CodeNamespace();
+ ns.Name = "MyNamespace";
+ ns.Imports.Add(new CodeNamespaceImport("System"));
+ ns.Imports.Add(new CodeNamespaceImport("System.Drawing"));
+ ns.Imports.Add(new CodeNamespaceImport("System.Windows.Forms"));
+ ns.Imports.Add(new CodeNamespaceImport("System.ComponentModel"));
+ cu.Namespaces.Add(ns);
+ class1 = new CodeTypeDeclaration("Test");
+ class1.IsClass = true;
+ class1.BaseTypes.Add(new CodeTypeReference("Form"));
+ ns.Types.Add(class1);
+
+ CodeMemberField mfield = new CodeMemberField(new CodeTypeReference("Button"), "b");
+ mfield.InitExpression = new CodeObjectCreateExpression(new CodeTypeReference("Button"));
+ class1.Members.Add(mfield);
+
+ CodeConstructor ctor = new CodeConstructor();
+ ctor.Attributes = MemberAttributes.Public;
+ ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(),
+ "Size"), new CodeObjectCreateExpression(new CodeTypeReference("Size"),
+ new CodePrimitiveExpression(600), new CodePrimitiveExpression(600))));
+ ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("b"),
+ "Text"), new CodePrimitiveExpression("Test")));
+ ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("b"),
+ "TabIndex"), new CodePrimitiveExpression(0)));
+ ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("b"),
+ "Location"), new CodeObjectCreateExpression(new CodeTypeReference("Point"),
+ new CodePrimitiveExpression(400), new CodePrimitiveExpression(525))));
+ ctor.Statements.Add(new CodeAttachEventStatement(new CodeEventReferenceExpression(new
+ CodeThisReferenceExpression(), "MyEvent"), new CodeDelegateCreateExpression(new CodeTypeReference("EventHandler")
+ , new CodeThisReferenceExpression(), "b_Click")));
+ class1.Members.Add(ctor);
+
+ CodeMemberEvent evt = new CodeMemberEvent();
+ evt.Name = "MyEvent";
+ evt.Type = new CodeTypeReference("System.EventHandler");
+ evt.Attributes = MemberAttributes.Public;
+ class1.Members.Add(evt);
- cmm = new CodeMemberMethod();
- cmm.Name = "CallingWork";
- cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
- CodeParameterDeclarationExpression parames = new CodeParameterDeclarationExpression(typeof(int), "a");
- cmm.Parameters.Add(parames);
- cmm.ReturnType = new CodeTypeReference("System.int32");
- cmm.Statements.Add(new CodeAssignStatement(new CodeVariableReferenceExpression("a"),
- new CodePrimitiveExpression(10)));
- cmm.Statements.Add(new CodeVariableDeclarationStatement(typeof(int), "b"));
- // invoke the method called "work"
- CodeMethodInvokeExpression methodinvoked = new CodeMethodInvokeExpression(new CodeMethodReferenceExpression
- (new CodeTypeReferenceExpression("TEST"), "Work"));
- // add parameter with ref direction
- CodeDirectionExpression parameter = new CodeDirectionExpression(FieldDirection.Ref,
- new CodeVariableReferenceExpression("a"));
- methodinvoked.Parameters.Add(parameter);
- // add parameter with out direction
- parameter = new CodeDirectionExpression(FieldDirection.Out, new CodeVariableReferenceExpression("b"));
- methodinvoked.Parameters.Add(parameter);
- cmm.Statements.Add(methodinvoked);
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodeBinaryOperatorExpression
- (new CodeVariableReferenceExpression("a"), CodeBinaryOperatorType.Add, new CodeVariableReferenceExpression("b"))));
- cd.Members.Add(cmm);
- }
- if (provider.Supports(GeneratorSupport.ReturnTypeAttributes))
- {
- CodeMemberMethod function1 = new CodeMemberMethod();
- function1.Name = "MyFunction";
- function1.ReturnType = new CodeTypeReference(typeof(string));
- function1.Attributes = MemberAttributes.Public | MemberAttributes.Final;
- function1.ReturnTypeCustomAttributes.Add(new
- CodeAttributeDeclaration("System.Xml.Serialization.XmlIgnoreAttribute"));
- function1.ReturnTypeCustomAttributes.Add(new CodeAttributeDeclaration("System.Xml.Serialization.XmlRootAttribute", new
- CodeAttributeArgument("Namespace", new CodePrimitiveExpression("Namespace Value")), new
- CodeAttributeArgument("ElementName", new CodePrimitiveExpression("Root, hehehe"))));
- function1.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression("Return")));
- cd.Members.Add(function1);
- }
- if (provider.Supports(GeneratorSupport.StaticConstructors))
- {
- cmm = new CodeMemberMethod();
- cmm.Name = "TestStaticConstructor";
- cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
- cmm.ReturnType = new CodeTypeReference(typeof(int));
- CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression(typeof(int), "a");
- cmm.Parameters.Add(param);
- // utilize constructor
- cmm.Statements.Add(new CodeVariableDeclarationStatement("Test4", "t", new CodeObjectCreateExpression("Test4")));
- // set then get number
- cmm.Statements.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(new CodeVariableReferenceExpression("t"), "i")
- , new CodeVariableReferenceExpression("a")));
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodeMethodReferenceExpression(
- new CodeVariableReferenceExpression("t"), "i")));
- cd.Members.Add(cmm);
+ cmm = new CodeMemberMethod();
+ cmm.Name = "b_Click";
+ cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "sender"));
+ cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(EventArgs), "e"));
+ class1.Members.Add(cmm);
+ }
- class1 = new CodeTypeDeclaration();
- class1.Name = "Test4";
- class1.IsClass = true;
- nspace.Types.Add(class1);
-
- class1.Members.Add(new CodeMemberField(new CodeTypeReference(typeof(int)), "number"));
- CodeMemberProperty prop = new CodeMemberProperty();
- prop.Name = "i";
- prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
- prop.Type = new CodeTypeReference(typeof(int));
- prop.GetStatements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("number")));
- prop.SetStatements.Add(new CodeAssignStatement(new CodeVariableReferenceExpression("number"),
- new CodePropertySetValueReferenceExpression()));
- class1.Members.Add(prop);
- CodeTypeConstructor ctc = new CodeTypeConstructor();
- class1.Members.Add(ctc);
- }
- if (provider.Supports(GeneratorSupport.TryCatchStatements))
- {
- cmm = new CodeMemberMethod();
- cmm.Name = "TryCatchMethod";
- cmm.ReturnType = new CodeTypeReference(typeof(int));
- cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
- CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression(typeof(int), "a");
- cmm.Parameters.Add(param);
-
- CodeTryCatchFinallyStatement tcfstmt = new CodeTryCatchFinallyStatement();
- tcfstmt.FinallyStatements.Add(new CodeAssignStatement(new CodeVariableReferenceExpression("a"), new
- CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("a"), CodeBinaryOperatorType.Add,
- new CodePrimitiveExpression(5))));
- cmm.Statements.Add(tcfstmt);
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("a")));
- cd.Members.Add(cmm);
- }
- if (provider.Supports(GeneratorSupport.DeclareEvents))
- {
- CodeNamespace ns = new CodeNamespace();
- ns.Name = "MyNamespace";
- ns.Imports.Add(new CodeNamespaceImport("System"));
- ns.Imports.Add(new CodeNamespaceImport("System.Drawing"));
- ns.Imports.Add(new CodeNamespaceImport("System.Windows.Forms"));
- ns.Imports.Add(new CodeNamespaceImport("System.ComponentModel"));
- cu.Namespaces.Add(ns);
- class1 = new CodeTypeDeclaration("Test");
- class1.IsClass = true;
- class1.BaseTypes.Add(new CodeTypeReference("Form"));
- ns.Types.Add(class1);
+ AssertEqual(cu,
+ @"//------------------------------------------------------------------------------
+ // <auto-generated>
+ // This code was generated by a tool.
+ // Runtime Version:4.0.30319.42000
+ //
+ // Changes to this file may cause incorrect behavior and will be lost if
+ // the code is regenerated.
+ // </auto-generated>
+ //------------------------------------------------------------------------------
+
+ [assembly: System.Reflection.AssemblyTitle(""MyAssembly"")]
+ [assembly: System.Reflection.AssemblyVersion(""1.0.6.2"")]
+
+ namespace NSPC {
+ using System;
+ using System.Drawing;
+ using System.Windows.Forms;
+ using System.ComponentModel;
+
+ public class TEST {
+
+ public int ArraysOfArrays() {
+ int[][] arrayOfArrays = new int[][] {
+ new int[] { 3, 4},
+ new int[] { 1}};
+ return arrayOfArrays[0][1];
+ }
- CodeMemberField mfield = new CodeMemberField(new CodeTypeReference("Button"), "b");
- mfield.InitExpression = new CodeObjectCreateExpression(new CodeTypeReference("Button"));
- class1.Members.Add(mfield);
+ public static string ChainedConstructorUse() {
+ Test2 t = new Test2();
+ return t.accessStringField;
+ }
- CodeConstructor ctor = new CodeConstructor();
- ctor.Attributes = MemberAttributes.Public;
- ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(),
- "Size"), new CodeObjectCreateExpression(new CodeTypeReference("Size"),
- new CodePrimitiveExpression(600), new CodePrimitiveExpression(600))));
- ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("b"),
- "Text"), new CodePrimitiveExpression("Test")));
- ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("b"),
- "TabIndex"), new CodePrimitiveExpression(0)));
- ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("b"),
- "Location"), new CodeObjectCreateExpression(new CodeTypeReference("Point"),
- new CodePrimitiveExpression(400), new CodePrimitiveExpression(525))));
- ctor.Statements.Add(new CodeAttachEventStatement(new CodeEventReferenceExpression(new
- CodeThisReferenceExpression(), "MyEvent"), new CodeDelegateCreateExpression(new CodeTypeReference("EventHandler")
- , new CodeThisReferenceExpression(), "b_Click")));
- class1.Members.Add(ctor);
+ public int ComplexExpressions(int i) {
+ i = (i * (i + 3));
+ return i;
+ }
- CodeMemberEvent evt = new CodeMemberEvent();
- evt.Name = "MyEvent";
- evt.Type = new CodeTypeReference("System.EventHandler");
- evt.Attributes = MemberAttributes.Public;
- class1.Members.Add(evt);
+ public static int OutputDecimalEnumVal(int i) {
+ if ((i == 3)) {
+ return ((int)(DecimalEnum.Num3));
+ }
+ if ((i == 4)) {
+ return ((int)(DecimalEnum.Num4));
+ }
+ if ((i == 2)) {
+ return ((int)(DecimalEnum.Num2));
+ }
+ if ((i == 1)) {
+ return ((int)(DecimalEnum.Num1));
+ }
+ if ((i == 0)) {
+ return ((int)(DecimalEnum.Num0));
+ }
+ return (i + 10);
+ }
- cmm = new CodeMemberMethod();
- cmm.Name = "b_Click";
- cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "sender"));
- cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(EventArgs), "e"));
- class1.Members.Add(cmm);
- }
+ public static int TestSingleInterface(int i) {
+ TestSingleInterfaceImp t = new TestSingleInterfaceImp();
+ return t.InterfaceMethod(i);
+ }
- AssertEqual(cu,
- @"//------------------------------------------------------------------------------
- // <auto-generated>
- // This code was generated by a tool.
- // Runtime Version:4.0.30319.42000
- //
- // Changes to this file may cause incorrect behavior and will be lost if
- // the code is regenerated.
- // </auto-generated>
- //------------------------------------------------------------------------------
-
- [assembly: System.Reflection.AssemblyTitle(""MyAssembly"")]
- [assembly: System.Reflection.AssemblyVersion(""1.0.6.2"")]
-
- namespace NSPC {
- using System;
- using System.Drawing;
- using System.Windows.Forms;
- using System.ComponentModel;
+ public static int TestMultipleInterfaces(int i) {
+ TestMultipleInterfaceImp t = new TestMultipleInterfaceImp();
+ InterfaceA interfaceAobject = ((InterfaceA)(t));
+ InterfaceB interfaceBobject = ((InterfaceB)(t));
+ return (interfaceAobject.InterfaceMethod(i) - interfaceBobject.InterfaceMethod(i));
+ }
- public class TEST {
+ public static int NestedStructMethod() {
+ structA varStructA;
+ varStructA.innerStruct.int1 = 3;
+ return varStructA.innerStruct.int1;
+ }
- public int ArraysOfArrays() {
- int[][] arrayOfArrays = new int[][] {
- new int[] { 3, 4},
- new int[] { 1}};
- return arrayOfArrays[0][1];
- }
+ public static void Main() { }
- public static string ChainedConstructorUse() {
- Test2 t = new Test2();
- return t.accessStringField;
- }
+ public int GoToMethod(int i) {
+ if ((i < 1)) {
+ goto comehere;
+ }
+ return 6;
+ comehere:
+ return 7;
+ }
- public int ComplexExpressions(int i) {
- i = (i * (i + 3));
- return i;
- }
+ public static int CallingPublicNestedScenario(int i) {
+ PublicNestedClassA.PublicNestedClassB2.PublicNestedClassC t = new PublicNestedClassA.PublicNestedClassB2.PublicNestedClassC();
+ return t.publicNestedClassesMethod(i);
+ }
- public static int OutputDecimalEnumVal(int i) {
- if ((i == 3)) {
- return ((int)(DecimalEnum.Num3));
+ public void MyMethod([System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=false)] string blah) {
}
- if ((i == 4)) {
- return ((int)(DecimalEnum.Num4));
+
+ public static int PublicStaticMethod() {
+ return 16;
}
- if ((i == 2)) {
- return ((int)(DecimalEnum.Num2));
+
+ static void Work(ref int i, out int j) {
+ i = (i + 4);
+ j = 5;
}
- if ((i == 1)) {
- return ((int)(DecimalEnum.Num1));
+
+ public static int CallingWork(int a) {
+ a = 10;
+ int b;
+ TEST.Work(ref a, out b);
+ return (a + b);
}
- if ((i == 0)) {
- return ((int)(DecimalEnum.Num0));
+
+ [return: System.Xml.Serialization.XmlIgnoreAttribute()]
+ [return: System.Xml.Serialization.XmlRootAttribute(Namespace=""Namespace Value"", ElementName=""Root, hehehe"")]
+ public string MyFunction() {
+ return ""Return"";
}
- return (i + 10);
- }
- public static int TestSingleInterface(int i) {
- TestSingleInterfaceImp t = new TestSingleInterfaceImp();
- return t.InterfaceMethod(i);
- }
+ public static int TestStaticConstructor(int a) {
+ Test4 t = new Test4();
+ t.i = a;
+ return t.i;
+ }
- public static int TestMultipleInterfaces(int i) {
- TestMultipleInterfaceImp t = new TestMultipleInterfaceImp();
- InterfaceA interfaceAobject = ((InterfaceA)(t));
- InterfaceB interfaceBobject = ((InterfaceB)(t));
- return (interfaceAobject.InterfaceMethod(i) - interfaceBobject.InterfaceMethod(i));
+ public static int TryCatchMethod(int a) {
+ try {
+ }
+ finally {
+ a = (a + 5);
+ }
+ return a;
+ }
}
- public static int NestedStructMethod() {
- structA varStructA;
- varStructA.innerStruct.int1 = 3;
- return varStructA.innerStruct.int1;
- }
+ public class Test2 {
- public static void Main() { }
+ private string stringField;
- public int GoToMethod(int i) {
- if ((i < 1)) {
- goto comehere;
+ public Test2() :
+ this(""testingString"", null, null) {
}
- return 6;
- comehere:
- return 7;
- }
-
- public static int CallingPublicNestedScenario(int i) {
- PublicNestedClassA.PublicNestedClassB2.PublicNestedClassC t = new PublicNestedClassA.PublicNestedClassB2.PublicNestedClassC();
- return t.publicNestedClassesMethod(i);
- }
- public void MyMethod([System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=false)] string blah) {
- }
+ public Test2(string p1, string p2, string p3) {
+ this.stringField = p1;
+ }
- public static int PublicStaticMethod() {
- return 16;
+ public string accessStringField {
+ get {
+ return this.stringField;
+ }
+ set {
+ this.stringField = value;
+ }
+ }
}
- static void Work(ref int i, out int j) {
- i = (i + 4);
- j = 5;
+ public enum DecimalEnum {
+ Num0 = 0,
+ Num1 = 1,
+ Num2 = 2,
+ Num3 = 3,
+ Num4 = 4,
}
- public static int CallingWork(int a) {
- a = 10;
- int b;
- TEST.Work(ref a, out b);
- return (a + b);
+ public interface InterfaceA {
+ int InterfaceMethod(int a);
}
- [return: System.Xml.Serialization.XmlIgnoreAttribute()]
- [return: System.Xml.Serialization.XmlRootAttribute(Namespace=""Namespace Value"", ElementName=""Root, hehehe"")]
- public string MyFunction() {
- return ""Return"";
+ public interface InterfaceB {
+ int InterfaceMethod(int a);
}
- public static int TestStaticConstructor(int a) {
- Test4 t = new Test4();
- t.i = a;
- return t.i;
- }
-
- public static int TryCatchMethod(int a) {
- try {
- }
- finally {
- a = (a + 5);
+ public class TestMultipleInterfaceImp : object, InterfaceB, InterfaceA {
+ public int InterfaceMethod(int a) {
+ return a;
}
- return a;
- }
- }
-
- public class Test2 {
-
- private string stringField;
-
- public Test2() :
- this(""testingString"", null, null) {
}
- public Test2(string p1, string p2, string p3) {
- this.stringField = p1;
- }
-
- public string accessStringField {
- get {
- return this.stringField;
+ public class TestSingleInterfaceImp : object, InterfaceA {
+ public virtual int InterfaceMethod(int a) {
+ return a;
}
- set {
- this.stringField = value;
- }
- }
- }
-
- public enum DecimalEnum {
- Num0 = 0,
- Num1 = 1,
- Num2 = 2,
- Num3 = 3,
- Num4 = 4,
- }
-
- public interface InterfaceA {
- int InterfaceMethod(int a);
- }
-
- public interface InterfaceB {
- int InterfaceMethod(int a);
- }
-
- public class TestMultipleInterfaceImp : object, InterfaceB, InterfaceA {
- public int InterfaceMethod(int a) {
- return a;
}
- }
-
- public class TestSingleInterfaceImp : object, InterfaceA {
- public virtual int InterfaceMethod(int a) {
- return a;
- }
- }
- public struct structA {
- public structB innerStruct;
+ public struct structA {
+ public structB innerStruct;
- public struct structB {
- public int int1;
+ public struct structB {
+ public int int1;
+ }
}
- }
- public class PublicNestedClassA {
+ public class PublicNestedClassA {
- public class PublicNestedClassB1 { }
+ public class PublicNestedClassB1 { }
- public class PublicNestedClassB2 {
- public class PublicNestedClassC {
- public int publicNestedClassesMethod(int a) {
- return a;
+ public class PublicNestedClassB2 {
+ public class PublicNestedClassC {
+ public int publicNestedClassesMethod(int a) {
+ return a;
+ }
}
}
}
- }
-
- public class Test4 {
- private int number;
+ public class Test4 {
- static Test4() {
- }
+ private int number;
- public int i {
- get {
- return number;
+ static Test4() {
}
- set {
- number = value;
+
+ public int i {
+ get {
+ return number;
+ }
+ set {
+ number = value;
+ }
}
}
}
- }
- namespace MyNamespace {
- using System;
- using System.Drawing;
- using System.Windows.Forms;
- using System.ComponentModel;
-
- public class Test : Form {
- private Button b = new Button();
-
- public Test() {
- this.Size = new Size(600, 600);
- b.Text = ""Test"";
- b.TabIndex = 0;
- b.Location = new Point(400, 525);
- this.MyEvent += new EventHandler(this.b_Click);
- }
+ namespace MyNamespace {
+ using System;
+ using System.Drawing;
+ using System.Windows.Forms;
+ using System.ComponentModel;
+
+ public class Test : Form {
+ private Button b = new Button();
+
+ public Test() {
+ this.Size = new Size(600, 600);
+ b.Text = ""Test"";
+ b.TabIndex = 0;
+ b.Location = new Point(400, 525);
+ this.MyEvent += new EventHandler(this.b_Click);
+ }
- public event System.EventHandler MyEvent;
+ public event System.EventHandler MyEvent;
- private void b_Click(object sender, System.EventArgs e) {
+ private void b_Click(object sender, System.EventArgs e) {
+ }
}
- }
- }");
+ }");
+ }).Dispose();
}
[Fact]
diff --git a/src/System.CodeDom/tests/CodeGenerationTests.cs b/src/System.CodeDom/tests/CodeGenerationTests.cs
index 79749310f6..0683de03a8 100644
--- a/src/System.CodeDom/tests/CodeGenerationTests.cs
+++ b/src/System.CodeDom/tests/CodeGenerationTests.cs
@@ -5,6 +5,7 @@
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.ComponentModel;
+using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Tests;
@@ -13,7 +14,7 @@ using Xunit;
namespace System.CodeDom.Tests
{
- public abstract class CodeGenerationTests
+ public abstract class CodeGenerationTests : RemoteExecutorTestBase
{
[Fact]
public void Roundtrip_Extension()
diff --git a/src/System.CodeDom/tests/System.CodeDom.Tests.csproj b/src/System.CodeDom/tests/System.CodeDom.Tests.csproj
index c0c0a2802f..72822c276a 100644
--- a/src/System.CodeDom/tests/System.CodeDom.Tests.csproj
+++ b/src/System.CodeDom/tests/System.CodeDom.Tests.csproj
@@ -107,5 +107,11 @@
<Link>Common\System\Collections\TestBase.NonGeneric.cs</Link>
</Compile>
</ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="$(CommonTestPath)\System\Diagnostics\RemoteExecutorConsoleApp\RemoteExecutorConsoleApp.csproj">
+ <Project>{69e46a6f-9966-45a5-8945-2559fe337827}</Project>
+ <Name>RemoteExecutorConsoleApp</Name>
+ </ProjectReference>
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
diff --git a/src/System.CodeDom/tests/VBCodeGenerationTests.cs b/src/System.CodeDom/tests/VBCodeGenerationTests.cs
index c5dbb6995a..619c2cb9ba 100644
--- a/src/System.CodeDom/tests/VBCodeGenerationTests.cs
+++ b/src/System.CodeDom/tests/VBCodeGenerationTests.cs
@@ -4,6 +4,7 @@
using System.CodeDom.Compiler;
using System.Collections.Generic;
+using System.Globalization;
using System.Reflection;
using Microsoft.VisualBasic;
using Xunit;
@@ -580,206 +581,211 @@ namespace System.CodeDom.Tests
[Fact]
public void MetadataAttributes()
{
- var cu = new CodeCompileUnit();
-
- var ns = new CodeNamespace();
- ns.Name = "MyNamespace";
- ns.Imports.Add(new CodeNamespaceImport("System"));
- ns.Imports.Add(new CodeNamespaceImport("System.Drawing"));
- ns.Imports.Add(new CodeNamespaceImport("System.Windows.Forms"));
- ns.Imports.Add(new CodeNamespaceImport("System.ComponentModel"));
- cu.Namespaces.Add(ns);
-
- var attrs = cu.AssemblyCustomAttributes;
- attrs.Add(new CodeAttributeDeclaration("System.Reflection.AssemblyTitle", new CodeAttributeArgument(new CodePrimitiveExpression("MyAssembly"))));
- attrs.Add(new CodeAttributeDeclaration("System.Reflection.AssemblyVersion", new CodeAttributeArgument(new CodePrimitiveExpression("1.0.6.2"))));
- attrs.Add(new CodeAttributeDeclaration("System.CLSCompliantAttribute", new CodeAttributeArgument(new CodePrimitiveExpression(false))));
-
- var class1 = new CodeTypeDeclaration() { Name = "MyClass" };
- class1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Serializable"));
- class1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Obsolete", new CodeAttributeArgument(new CodePrimitiveExpression("Don't use this Class"))));
- ns.Types.Add(class1);
+ RemoteInvoke(() =>
+ {
+ CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture;
- var nestedClass = new CodeTypeDeclaration("NestedClass") { IsClass = true, TypeAttributes = TypeAttributes.NestedPublic };
- nestedClass.CustomAttributes.Add(new CodeAttributeDeclaration("System.Serializable"));
- class1.Members.Add(nestedClass);
-
- var method1 = new CodeMemberMethod() { Name = "MyMethod" };
- method1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Obsolete", new CodeAttributeArgument(new CodePrimitiveExpression("Don't use this Method"))));
- method1.CustomAttributes.Add(new CodeAttributeDeclaration("System.ComponentModel.Editor", new CodeAttributeArgument(new CodePrimitiveExpression("This")), new CodeAttributeArgument(new CodePrimitiveExpression("That"))));
- var param1 = new CodeParameterDeclarationExpression(typeof(string), "blah");
- param1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Xml.Serialization.XmlElementAttribute",
- new CodeAttributeArgument("Form", new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("System.Xml.Schema.XmlSchemaForm"), "Unqualified")),
- new CodeAttributeArgument("IsNullable", new CodePrimitiveExpression(false))));
- method1.Parameters.Add(param1);
- var param2 = new CodeParameterDeclarationExpression(typeof(int[]), "arrayit");
- param2.CustomAttributes.Add(
- new CodeAttributeDeclaration("System.Xml.Serialization.XmlElementAttribute",
- new CodeAttributeArgument("Form", new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("System.Xml.Schema.XmlSchemaForm"), "Unqualified")),
- new CodeAttributeArgument("IsNullable", new CodePrimitiveExpression(false))));
- method1.Parameters.Add(param2);
- class1.Members.Add(method1);
-
- var function1 = new CodeMemberMethod();
- function1.Name = "MyFunction";
- function1.ReturnType = new CodeTypeReference(typeof(string));
- function1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Obsolete", new CodeAttributeArgument(new CodePrimitiveExpression("Don't use this Function"))));
- function1.ReturnTypeCustomAttributes.Add(new CodeAttributeDeclaration("System.Xml.Serialization.XmlIgnoreAttribute"));
- function1.ReturnTypeCustomAttributes.Add(new CodeAttributeDeclaration("System.Xml.Serialization.XmlRootAttribute", new
- CodeAttributeArgument("Namespace", new CodePrimitiveExpression("Namespace Value")), new
- CodeAttributeArgument("ElementName", new CodePrimitiveExpression("Root, hehehe"))));
- function1.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression("Return")));
- class1.Members.Add(function1);
-
- CodeMemberMethod function2 = new CodeMemberMethod();
- function2.Name = "GlobalKeywordFunction";
- function2.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(ObsoleteAttribute), CodeTypeReferenceOptions.GlobalReference), new
- CodeAttributeArgument(new CodePrimitiveExpression("Don't use this Function"))));
- CodeTypeReference typeRef = new CodeTypeReference("System.Xml.Serialization.XmlIgnoreAttribute", CodeTypeReferenceOptions.GlobalReference);
- CodeAttributeDeclaration codeAttrib = new CodeAttributeDeclaration(typeRef);
- function2.ReturnTypeCustomAttributes.Add(codeAttrib);
- class1.Members.Add(function2);
-
- CodeMemberField field1 = new CodeMemberField();
- field1.Name = "myField";
- field1.Type = new CodeTypeReference(typeof(string));
- field1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Xml.Serialization.XmlElementAttribute"));
- field1.InitExpression = new CodePrimitiveExpression("hi!");
- class1.Members.Add(field1);
+ var cu = new CodeCompileUnit();
- CodeMemberProperty prop1 = new CodeMemberProperty();
- prop1.Name = "MyProperty";
- prop1.Type = new CodeTypeReference(typeof(string));
- prop1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Obsolete", new CodeAttributeArgument(new CodePrimitiveExpression("Don't use this Property"))));
- prop1.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "myField")));
- class1.Members.Add(prop1);
+ var ns = new CodeNamespace();
+ ns.Name = "MyNamespace";
+ ns.Imports.Add(new CodeNamespaceImport("System"));
+ ns.Imports.Add(new CodeNamespaceImport("System.Drawing"));
+ ns.Imports.Add(new CodeNamespaceImport("System.Windows.Forms"));
+ ns.Imports.Add(new CodeNamespaceImport("System.ComponentModel"));
+ cu.Namespaces.Add(ns);
- CodeConstructor const1 = new CodeConstructor();
- const1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Obsolete", new CodeAttributeArgument(new CodePrimitiveExpression("Don't use this Constructor"))));
- class1.Members.Add(const1);
+ var attrs = cu.AssemblyCustomAttributes;
+ attrs.Add(new CodeAttributeDeclaration("System.Reflection.AssemblyTitle", new CodeAttributeArgument(new CodePrimitiveExpression("MyAssembly"))));
+ attrs.Add(new CodeAttributeDeclaration("System.Reflection.AssemblyVersion", new CodeAttributeArgument(new CodePrimitiveExpression("1.0.6.2"))));
+ attrs.Add(new CodeAttributeDeclaration("System.CLSCompliantAttribute", new CodeAttributeArgument(new CodePrimitiveExpression(false))));
- class1 = new CodeTypeDeclaration("Test");
- class1.IsClass = true;
- class1.BaseTypes.Add(new CodeTypeReference("Form"));
- ns.Types.Add(class1);
+ var class1 = new CodeTypeDeclaration() { Name = "MyClass" };
+ class1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Serializable"));
+ class1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Obsolete", new CodeAttributeArgument(new CodePrimitiveExpression("Don't use this Class"))));
+ ns.Types.Add(class1);
- CodeMemberField mfield = new CodeMemberField(new CodeTypeReference("Button"), "b");
- mfield.InitExpression = new CodeObjectCreateExpression(new CodeTypeReference("Button"));
- class1.Members.Add(mfield);
-
- CodeConstructor ctor = new CodeConstructor();
- ctor.Attributes = MemberAttributes.Public;
- ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(),
- "Size"), new CodeObjectCreateExpression(new CodeTypeReference("Size"),
- new CodePrimitiveExpression(600), new CodePrimitiveExpression(600))));
- ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("b"),
- "Text"), new CodePrimitiveExpression("Test")));
- ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("b"),
- "TabIndex"), new CodePrimitiveExpression(0)));
- ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("b"),
- "Location"), new CodeObjectCreateExpression(new CodeTypeReference("Point"),
- new CodePrimitiveExpression(400), new CodePrimitiveExpression(525))));
- ctor.Statements.Add(new CodeAttachEventStatement(new CodeEventReferenceExpression(new
- CodeThisReferenceExpression(), "MyEvent"), new CodeDelegateCreateExpression(new CodeTypeReference("EventHandler")
- , new CodeThisReferenceExpression(), "b_Click")));
- class1.Members.Add(ctor);
-
- CodeMemberEvent evt = new CodeMemberEvent();
- evt.Name = "MyEvent";
- evt.Type = new CodeTypeReference("System.EventHandler");
- evt.Attributes = MemberAttributes.Public;
- evt.CustomAttributes.Add(new CodeAttributeDeclaration("System.CLSCompliantAttribute", new CodeAttributeArgument(new CodePrimitiveExpression(false))));
- class1.Members.Add(evt);
+ var nestedClass = new CodeTypeDeclaration("NestedClass") { IsClass = true, TypeAttributes = TypeAttributes.NestedPublic };
+ nestedClass.CustomAttributes.Add(new CodeAttributeDeclaration("System.Serializable"));
+ class1.Members.Add(nestedClass);
- CodeMemberMethod cmm = new CodeMemberMethod();
- cmm.Name = "b_Click";
- cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "sender"));
- cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(EventArgs), "e"));
- class1.Members.Add(cmm);
+ var method1 = new CodeMemberMethod() { Name = "MyMethod" };
+ method1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Obsolete", new CodeAttributeArgument(new CodePrimitiveExpression("Don't use this Method"))));
+ method1.CustomAttributes.Add(new CodeAttributeDeclaration("System.ComponentModel.Editor", new CodeAttributeArgument(new CodePrimitiveExpression("This")), new CodeAttributeArgument(new CodePrimitiveExpression("That"))));
+ var param1 = new CodeParameterDeclarationExpression(typeof(string), "blah");
+ param1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Xml.Serialization.XmlElementAttribute",
+ new CodeAttributeArgument("Form", new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("System.Xml.Schema.XmlSchemaForm"), "Unqualified")),
+ new CodeAttributeArgument("IsNullable", new CodePrimitiveExpression(false))));
+ method1.Parameters.Add(param1);
+ var param2 = new CodeParameterDeclarationExpression(typeof(int[]), "arrayit");
+ param2.CustomAttributes.Add(
+ new CodeAttributeDeclaration("System.Xml.Serialization.XmlElementAttribute",
+ new CodeAttributeArgument("Form", new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("System.Xml.Schema.XmlSchemaForm"), "Unqualified")),
+ new CodeAttributeArgument("IsNullable", new CodePrimitiveExpression(false))));
+ method1.Parameters.Add(param2);
+ class1.Members.Add(method1);
+
+ var function1 = new CodeMemberMethod();
+ function1.Name = "MyFunction";
+ function1.ReturnType = new CodeTypeReference(typeof(string));
+ function1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Obsolete", new CodeAttributeArgument(new CodePrimitiveExpression("Don't use this Function"))));
+ function1.ReturnTypeCustomAttributes.Add(new CodeAttributeDeclaration("System.Xml.Serialization.XmlIgnoreAttribute"));
+ function1.ReturnTypeCustomAttributes.Add(new CodeAttributeDeclaration("System.Xml.Serialization.XmlRootAttribute", new
+ CodeAttributeArgument("Namespace", new CodePrimitiveExpression("Namespace Value")), new
+ CodeAttributeArgument("ElementName", new CodePrimitiveExpression("Root, hehehe"))));
+ function1.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression("Return")));
+ class1.Members.Add(function1);
+
+ CodeMemberMethod function2 = new CodeMemberMethod();
+ function2.Name = "GlobalKeywordFunction";
+ function2.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(ObsoleteAttribute), CodeTypeReferenceOptions.GlobalReference), new
+ CodeAttributeArgument(new CodePrimitiveExpression("Don't use this Function"))));
+ CodeTypeReference typeRef = new CodeTypeReference("System.Xml.Serialization.XmlIgnoreAttribute", CodeTypeReferenceOptions.GlobalReference);
+ CodeAttributeDeclaration codeAttrib = new CodeAttributeDeclaration(typeRef);
+ function2.ReturnTypeCustomAttributes.Add(codeAttrib);
+ class1.Members.Add(function2);
+
+ CodeMemberField field1 = new CodeMemberField();
+ field1.Name = "myField";
+ field1.Type = new CodeTypeReference(typeof(string));
+ field1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Xml.Serialization.XmlElementAttribute"));
+ field1.InitExpression = new CodePrimitiveExpression("hi!");
+ class1.Members.Add(field1);
+
+ CodeMemberProperty prop1 = new CodeMemberProperty();
+ prop1.Name = "MyProperty";
+ prop1.Type = new CodeTypeReference(typeof(string));
+ prop1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Obsolete", new CodeAttributeArgument(new CodePrimitiveExpression("Don't use this Property"))));
+ prop1.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "myField")));
+ class1.Members.Add(prop1);
+
+ CodeConstructor const1 = new CodeConstructor();
+ const1.CustomAttributes.Add(new CodeAttributeDeclaration("System.Obsolete", new CodeAttributeArgument(new CodePrimitiveExpression("Don't use this Constructor"))));
+ class1.Members.Add(const1);
- AssertEqual(cu,
- @"'------------------------------------------------------------------------------
- ' <auto-generated>
- ' This code was generated by a tool.
- ' Runtime Version:4.0.30319.42000
- '
- ' Changes to this file may cause incorrect behavior and will be lost if
- ' the code is regenerated.
- ' </auto-generated>
- '------------------------------------------------------------------------------
-
- Option Strict Off
- Option Explicit On
-
- Imports System
- Imports System.ComponentModel
- Imports System.Drawing
- Imports System.Windows.Forms
- <Assembly: System.Reflection.AssemblyTitle(""MyAssembly""), _
- Assembly: System.Reflection.AssemblyVersion(""1.0.6.2""), _
- Assembly: System.CLSCompliantAttribute(false)>
-
- Namespace MyNamespace
-
- <System.Serializable(), _
- System.Obsolete(""Don't use this Class"")> _
- Public Class [MyClass]
-
- <System.Xml.Serialization.XmlElementAttribute()> _
- Private myField As String = ""hi!""
-
- <System.Obsolete(""Don't use this Constructor"")> _
- Private Sub New()
- MyBase.New
- End Sub
+ class1 = new CodeTypeDeclaration("Test");
+ class1.IsClass = true;
+ class1.BaseTypes.Add(new CodeTypeReference("Form"));
+ ns.Types.Add(class1);
- <System.Obsolete(""Don't use this Property"")> _
- Private ReadOnly Property MyProperty() As String
- Get
- Return Me.myField
- End Get
- End Property
+ CodeMemberField mfield = new CodeMemberField(new CodeTypeReference("Button"), "b");
+ mfield.InitExpression = new CodeObjectCreateExpression(new CodeTypeReference("Button"));
+ class1.Members.Add(mfield);
- <System.Obsolete(""Don't use this Method""), _
- System.ComponentModel.Editor(""This"", ""That"")> _
- Private Sub MyMethod(<System.Xml.Serialization.XmlElementAttribute(Form:=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable:=false)> ByVal blah As String, <System.Xml.Serialization.XmlElementAttribute(Form:=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable:=false)> ByVal arrayit() As Integer)
- End Sub
+ CodeConstructor ctor = new CodeConstructor();
+ ctor.Attributes = MemberAttributes.Public;
+ ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(),
+ "Size"), new CodeObjectCreateExpression(new CodeTypeReference("Size"),
+ new CodePrimitiveExpression(600), new CodePrimitiveExpression(600))));
+ ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("b"),
+ "Text"), new CodePrimitiveExpression("Test")));
+ ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("b"),
+ "TabIndex"), new CodePrimitiveExpression(0)));
+ ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("b"),
+ "Location"), new CodeObjectCreateExpression(new CodeTypeReference("Point"),
+ new CodePrimitiveExpression(400), new CodePrimitiveExpression(525))));
+ ctor.Statements.Add(new CodeAttachEventStatement(new CodeEventReferenceExpression(new
+ CodeThisReferenceExpression(), "MyEvent"), new CodeDelegateCreateExpression(new CodeTypeReference("EventHandler")
+ , new CodeThisReferenceExpression(), "b_Click")));
+ class1.Members.Add(ctor);
- <System.Obsolete(""Don't use this Function"")> _
- Private Function MyFunction() As <System.Xml.Serialization.XmlIgnoreAttribute(), System.Xml.Serialization.XmlRootAttribute([Namespace]:=""Namespace Value"", ElementName:=""Root, hehehe"")> String
- Return ""Return""
- End Function
+ CodeMemberEvent evt = new CodeMemberEvent();
+ evt.Name = "MyEvent";
+ evt.Type = new CodeTypeReference("System.EventHandler");
+ evt.Attributes = MemberAttributes.Public;
+ evt.CustomAttributes.Add(new CodeAttributeDeclaration("System.CLSCompliantAttribute", new CodeAttributeArgument(new CodePrimitiveExpression(false))));
+ class1.Members.Add(evt);
- <Global.System.ObsoleteAttribute(""Don't use this Function"")> _
- Private Sub GlobalKeywordFunction()
- End Sub
+ CodeMemberMethod cmm = new CodeMemberMethod();
+ cmm.Name = "b_Click";
+ cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "sender"));
+ cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(EventArgs), "e"));
+ class1.Members.Add(cmm);
- <System.Serializable()> _
- Public Class NestedClass
+ AssertEqual(cu,
+ @"'------------------------------------------------------------------------------
+ ' <auto-generated>
+ ' This code was generated by a tool.
+ ' Runtime Version:4.0.30319.42000
+ '
+ ' Changes to this file may cause incorrect behavior and will be lost if
+ ' the code is regenerated.
+ ' </auto-generated>
+ '------------------------------------------------------------------------------
+
+ Option Strict Off
+ Option Explicit On
+
+ Imports System
+ Imports System.ComponentModel
+ Imports System.Drawing
+ Imports System.Windows.Forms
+ <Assembly: System.Reflection.AssemblyTitle(""MyAssembly""), _
+ Assembly: System.Reflection.AssemblyVersion(""1.0.6.2""), _
+ Assembly: System.CLSCompliantAttribute(false)>
+
+ Namespace MyNamespace
+
+ <System.Serializable(), _
+ System.Obsolete(""Don't use this Class"")> _
+ Public Class [MyClass]
+
+ <System.Xml.Serialization.XmlElementAttribute()> _
+ Private myField As String = ""hi!""
+
+ <System.Obsolete(""Don't use this Constructor"")> _
+ Private Sub New()
+ MyBase.New
+ End Sub
+
+ <System.Obsolete(""Don't use this Property"")> _
+ Private ReadOnly Property MyProperty() As String
+ Get
+ Return Me.myField
+ End Get
+ End Property
+
+ <System.Obsolete(""Don't use this Method""), _
+ System.ComponentModel.Editor(""This"", ""That"")> _
+ Private Sub MyMethod(<System.Xml.Serialization.XmlElementAttribute(Form:=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable:=false)> ByVal blah As String, <System.Xml.Serialization.XmlElementAttribute(Form:=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable:=false)> ByVal arrayit() As Integer)
+ End Sub
+
+ <System.Obsolete(""Don't use this Function"")> _
+ Private Function MyFunction() As <System.Xml.Serialization.XmlIgnoreAttribute(), System.Xml.Serialization.XmlRootAttribute([Namespace]:=""Namespace Value"", ElementName:=""Root, hehehe"")> String
+ Return ""Return""
+ End Function
+
+ <Global.System.ObsoleteAttribute(""Don't use this Function"")> _
+ Private Sub GlobalKeywordFunction()
+ End Sub
+
+ <System.Serializable()> _
+ Public Class NestedClass
+ End Class
End Class
- End Class
- Public Class Test
- Inherits Form
+ Public Class Test
+ Inherits Form
- Private b As Button = New Button()
+ Private b As Button = New Button()
- Public Sub New()
- MyBase.New
- Me.Size = New Size(600, 600)
- b.Text = ""Test""
- b.TabIndex = 0
- b.Location = New Point(400, 525)
- AddHandler MyEvent, AddressOf Me.b_Click
- End Sub
+ Public Sub New()
+ MyBase.New
+ Me.Size = New Size(600, 600)
+ b.Text = ""Test""
+ b.TabIndex = 0
+ b.Location = New Point(400, 525)
+ AddHandler MyEvent, AddressOf Me.b_Click
+ End Sub
- <System.CLSCompliantAttribute(false)> _
- Public Event MyEvent As System.EventHandler
+ <System.CLSCompliantAttribute(false)> _
+ Public Event MyEvent As System.EventHandler
- Private Sub b_Click(ByVal sender As Object, ByVal e As System.EventArgs)
- End Sub
- End Class
- End Namespace");
+ Private Sub b_Click(ByVal sender As Object, ByVal e As System.EventArgs)
+ End Sub
+ End Class
+ End Namespace");
+ }).Dispose();
}
[Fact]
@@ -1396,260 +1402,265 @@ namespace System.CodeDom.Tests
[Fact]
public void RegionsSnippetsAndLinePragmas()
{
- CodeCompileUnit cu = new CodeCompileUnit();
- CodeNamespace ns = new CodeNamespace("Namespace1");
-
- cu.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Compile Unit Region"));
- cu.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+ RemoteInvoke(() =>
+ {
+ CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture;
- cu.Namespaces.Add(ns);
+ CodeCompileUnit cu = new CodeCompileUnit();
+ CodeNamespace ns = new CodeNamespace("Namespace1");
- CodeTypeDeclaration cd = new CodeTypeDeclaration("Class1");
- ns.Types.Add(cd);
+ cu.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Compile Unit Region"));
+ cu.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
- cd.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Outer Type Region"));
- cd.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+ cu.Namespaces.Add(ns);
- cd.Comments.Add(new CodeCommentStatement("Outer Type Comment"));
+ CodeTypeDeclaration cd = new CodeTypeDeclaration("Class1");
+ ns.Types.Add(cd);
- CodeMemberField field1 = new CodeMemberField(typeof(String), "field1");
- CodeMemberField field2 = new CodeMemberField(typeof(String), "field2");
- field1.Comments.Add(new CodeCommentStatement("Field 1 Comment"));
- field2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Field Region"));
- field2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+ cd.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Outer Type Region"));
+ cd.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
- CodeMemberEvent evt1 = new CodeMemberEvent();
- evt1.Name = "Event1";
- evt1.Type = new CodeTypeReference(typeof(System.EventHandler));
- evt1.Attributes = (evt1.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
+ cd.Comments.Add(new CodeCommentStatement("Outer Type Comment"));
- CodeMemberEvent evt2 = new CodeMemberEvent();
- evt2.Name = "Event2";
- evt2.Type = new CodeTypeReference(typeof(System.EventHandler));
- evt2.Attributes = (evt2.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
+ CodeMemberField field1 = new CodeMemberField(typeof(String), "field1");
+ CodeMemberField field2 = new CodeMemberField(typeof(String), "field2");
+ field1.Comments.Add(new CodeCommentStatement("Field 1 Comment"));
+ field2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Field Region"));
+ field2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
- evt2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Event Region"));
- evt2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+ CodeMemberEvent evt1 = new CodeMemberEvent();
+ evt1.Name = "Event1";
+ evt1.Type = new CodeTypeReference(typeof(System.EventHandler));
+ evt1.Attributes = (evt1.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
- CodeMemberMethod method1 = new CodeMemberMethod();
- method1.Name = "Method1";
- method1.Attributes = (method1.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
- method1.Statements.Add(
- new CodeDelegateInvokeExpression(
- new CodeEventReferenceExpression(new CodeThisReferenceExpression(), "Event1"),
- new CodeExpression[] {
- new CodeThisReferenceExpression(),
- new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("System.EventArgs"), "Empty")
- }));
+ CodeMemberEvent evt2 = new CodeMemberEvent();
+ evt2.Name = "Event2";
+ evt2.Type = new CodeTypeReference(typeof(System.EventHandler));
+ evt2.Attributes = (evt2.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
- CodeMemberMethod method2 = new CodeMemberMethod();
- method2.Name = "Method2";
- method2.Attributes = (method2.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
- method2.Statements.Add(
- new CodeDelegateInvokeExpression(
- new CodeEventReferenceExpression(new CodeThisReferenceExpression(), "Event2"),
- new CodeExpression[] {
- new CodeThisReferenceExpression(),
- new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("System.EventArgs"), "Empty")
- }));
- method2.LinePragma = new CodeLinePragma("MethodLinePragma.txt", 500);
- method2.Comments.Add(new CodeCommentStatement("Method 2 Comment"));
-
- method2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Method Region"));
- method2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
-
- CodeMemberProperty property1 = new CodeMemberProperty();
- property1.Name = "Property1";
- property1.Type = new CodeTypeReference(typeof(string));
- property1.Attributes = (property1.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
- property1.GetStatements.Add(
- new CodeMethodReturnStatement(
- new CodeFieldReferenceExpression(
- new CodeThisReferenceExpression(),
- "field1")));
+ evt2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Event Region"));
+ evt2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
- CodeMemberProperty property2 = new CodeMemberProperty();
- property2.Name = "Property2";
- property2.Type = new CodeTypeReference(typeof(string));
- property2.Attributes = (property2.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
- property2.GetStatements.Add(
- new CodeMethodReturnStatement(
- new CodeFieldReferenceExpression(
+ CodeMemberMethod method1 = new CodeMemberMethod();
+ method1.Name = "Method1";
+ method1.Attributes = (method1.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
+ method1.Statements.Add(
+ new CodeDelegateInvokeExpression(
+ new CodeEventReferenceExpression(new CodeThisReferenceExpression(), "Event1"),
+ new CodeExpression[] {
+ new CodeThisReferenceExpression(),
+ new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("System.EventArgs"), "Empty")
+ }));
+
+ CodeMemberMethod method2 = new CodeMemberMethod();
+ method2.Name = "Method2";
+ method2.Attributes = (method2.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
+ method2.Statements.Add(
+ new CodeDelegateInvokeExpression(
+ new CodeEventReferenceExpression(new CodeThisReferenceExpression(), "Event2"),
+ new CodeExpression[] {
new CodeThisReferenceExpression(),
- "field2")));
-
- property2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Property Region"));
- property2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
-
- CodeConstructor constructor1 = new CodeConstructor();
- constructor1.Attributes = (constructor1.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
- CodeStatement conState1 = new CodeAssignStatement(
- new CodeFieldReferenceExpression(
- new CodeThisReferenceExpression(),
- "field1"),
- new CodePrimitiveExpression("value1"));
- conState1.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Statements Region"));
- constructor1.Statements.Add(conState1);
- CodeStatement conState2 = new CodeAssignStatement(
- new CodeFieldReferenceExpression(
- new CodeThisReferenceExpression(),
- "field2"),
- new CodePrimitiveExpression("value2"));
- conState2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
- constructor1.Statements.Add(conState2);
-
- constructor1.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Constructor Region"));
- constructor1.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
-
- CodeConstructor constructor2 = new CodeConstructor();
- constructor2.Attributes = (constructor2.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
- constructor2.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "value1"));
- constructor2.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "value2"));
-
- CodeTypeConstructor typeConstructor2 = new CodeTypeConstructor();
-
- typeConstructor2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Type Constructor Region"));
- typeConstructor2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
-
- CodeEntryPointMethod methodMain = new CodeEntryPointMethod();
-
- CodeTypeDeclaration nestedClass1 = new CodeTypeDeclaration("NestedClass1");
- CodeTypeDeclaration nestedClass2 = new CodeTypeDeclaration("NestedClass2");
- nestedClass2.LinePragma = new CodeLinePragma("NestedTypeLinePragma.txt", 400);
- nestedClass2.Comments.Add(new CodeCommentStatement("Nested Type Comment"));
-
- nestedClass2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Nested Type Region"));
- nestedClass2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
-
- CodeTypeDelegate delegate1 = new CodeTypeDelegate();
- delegate1.Name = "nestedDelegate1";
- delegate1.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference("System.Object"), "sender"));
- delegate1.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference("System.EventArgs"), "e"));
-
- CodeTypeDelegate delegate2 = new CodeTypeDelegate();
- delegate2.Name = "nestedDelegate2";
- delegate2.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference("System.Object"), "sender"));
- delegate2.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference("System.EventArgs"), "e"));
-
- delegate2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Delegate Region"));
- delegate2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
-
- var snippet1 = new CodeSnippetTypeMember();
- var snippet2 = new CodeSnippetTypeMember();
-
- CodeRegionDirective regionStart = new CodeRegionDirective(CodeRegionMode.End, "");
- regionStart.RegionText = "Snippet Region";
- regionStart.RegionMode = CodeRegionMode.Start;
- snippet2.StartDirectives.Add(regionStart);
- snippet2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
-
- cd.Members.Add(field1);
- cd.Members.Add(method1);
- cd.Members.Add(constructor1);
- cd.Members.Add(property1);
- cd.Members.Add(methodMain);
-
- cd.Members.Add(evt1);
- cd.Members.Add(nestedClass1);
- cd.Members.Add(delegate1);
-
- cd.Members.Add(snippet1);
-
- cd.Members.Add(field2);
- cd.Members.Add(method2);
- cd.Members.Add(constructor2);
- cd.Members.Add(property2);
-
- cd.Members.Add(typeConstructor2);
- cd.Members.Add(evt2);
- cd.Members.Add(nestedClass2);
- cd.Members.Add(delegate2);
- cd.Members.Add(snippet2);
-
- AssertEqual(cu,
- @"#Region ""Compile Unit Region""
- '------------------------------------------------------------------------------
- ' <auto-generated>
- ' This code was generated by a tool.
- ' Runtime Version:4.0.30319.42000
- '
- ' Changes to this file may cause incorrect behavior and will be lost if
- ' the code is regenerated.
- ' </auto-generated>
- '------------------------------------------------------------------------------
- Option Strict Off
- Option Explicit On
- Namespace Namespace1
- #Region ""Outer Type Region""
- 'Outer Type Comment
- Public Class Class1
- 'Field 1 Comment
- Private field1 As String
- #Region ""Field Region""
- Private field2 As String
- #End Region
- #Region ""Snippet Region""
- #End Region
- #Region ""Type Constructor Region""
- Shared Sub New()
- End Sub
- #End Region
- #Region ""Constructor Region""
- Public Sub New()
- MyBase.New
- Me.field1 = ""value1""
- Me.field2 = ""value2""
- End Sub
- #End Region
- Public Sub New(ByVal value1 As String, ByVal value2 As String)
- MyBase.New
- End Sub
- Public ReadOnly Property Property1() As String
- Get
- Return Me.field1
- End Get
- End Property
- #Region ""Property Region""
- Public ReadOnly Property Property2() As String
- Get
- Return Me.field2
- End Get
- End Property
- #End Region
- Public Event Event1 As System.EventHandler
- #Region ""Event Region""
- Public Event Event2 As System.EventHandler
- #End Region
- Public Sub Method1()
- RaiseEvent Event1(Me, System.EventArgs.Empty)
- End Sub
- Public Shared Sub Main()
- End Sub
- #Region ""Method Region""
- 'Method 2 Comment
- #ExternalSource(""MethodLinePragma.txt"",500)
- Public Sub Method2()
- RaiseEvent Event2(Me, System.EventArgs.Empty)
- End Sub
- #End ExternalSource
- #End Region
- Public Class NestedClass1
- End Class
- Public Delegate Sub nestedDelegate1(ByVal sender As Object, ByVal e As System.EventArgs)
- #Region ""Nested Type Region""
- 'Nested Type Comment
- #ExternalSource(""NestedTypeLinePragma.txt"",400)
- Public Class NestedClass2
+ new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("System.EventArgs"), "Empty")
+ }));
+ method2.LinePragma = new CodeLinePragma("MethodLinePragma.txt", 500);
+ method2.Comments.Add(new CodeCommentStatement("Method 2 Comment"));
+
+ method2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Method Region"));
+ method2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+
+ CodeMemberProperty property1 = new CodeMemberProperty();
+ property1.Name = "Property1";
+ property1.Type = new CodeTypeReference(typeof(string));
+ property1.Attributes = (property1.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
+ property1.GetStatements.Add(
+ new CodeMethodReturnStatement(
+ new CodeFieldReferenceExpression(
+ new CodeThisReferenceExpression(),
+ "field1")));
+
+ CodeMemberProperty property2 = new CodeMemberProperty();
+ property2.Name = "Property2";
+ property2.Type = new CodeTypeReference(typeof(string));
+ property2.Attributes = (property2.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
+ property2.GetStatements.Add(
+ new CodeMethodReturnStatement(
+ new CodeFieldReferenceExpression(
+ new CodeThisReferenceExpression(),
+ "field2")));
+
+ property2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Property Region"));
+ property2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+
+ CodeConstructor constructor1 = new CodeConstructor();
+ constructor1.Attributes = (constructor1.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
+ CodeStatement conState1 = new CodeAssignStatement(
+ new CodeFieldReferenceExpression(
+ new CodeThisReferenceExpression(),
+ "field1"),
+ new CodePrimitiveExpression("value1"));
+ conState1.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Statements Region"));
+ constructor1.Statements.Add(conState1);
+ CodeStatement conState2 = new CodeAssignStatement(
+ new CodeFieldReferenceExpression(
+ new CodeThisReferenceExpression(),
+ "field2"),
+ new CodePrimitiveExpression("value2"));
+ conState2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+ constructor1.Statements.Add(conState2);
+
+ constructor1.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Constructor Region"));
+ constructor1.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+
+ CodeConstructor constructor2 = new CodeConstructor();
+ constructor2.Attributes = (constructor2.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Public;
+ constructor2.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "value1"));
+ constructor2.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "value2"));
+
+ CodeTypeConstructor typeConstructor2 = new CodeTypeConstructor();
+
+ typeConstructor2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Type Constructor Region"));
+ typeConstructor2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+
+ CodeEntryPointMethod methodMain = new CodeEntryPointMethod();
+
+ CodeTypeDeclaration nestedClass1 = new CodeTypeDeclaration("NestedClass1");
+ CodeTypeDeclaration nestedClass2 = new CodeTypeDeclaration("NestedClass2");
+ nestedClass2.LinePragma = new CodeLinePragma("NestedTypeLinePragma.txt", 400);
+ nestedClass2.Comments.Add(new CodeCommentStatement("Nested Type Comment"));
+
+ nestedClass2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Nested Type Region"));
+ nestedClass2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+
+ CodeTypeDelegate delegate1 = new CodeTypeDelegate();
+ delegate1.Name = "nestedDelegate1";
+ delegate1.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference("System.Object"), "sender"));
+ delegate1.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference("System.EventArgs"), "e"));
+
+ CodeTypeDelegate delegate2 = new CodeTypeDelegate();
+ delegate2.Name = "nestedDelegate2";
+ delegate2.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference("System.Object"), "sender"));
+ delegate2.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference("System.EventArgs"), "e"));
+
+ delegate2.StartDirectives.Add(new CodeRegionDirective(CodeRegionMode.Start, "Delegate Region"));
+ delegate2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+
+ var snippet1 = new CodeSnippetTypeMember();
+ var snippet2 = new CodeSnippetTypeMember();
+
+ CodeRegionDirective regionStart = new CodeRegionDirective(CodeRegionMode.End, "");
+ regionStart.RegionText = "Snippet Region";
+ regionStart.RegionMode = CodeRegionMode.Start;
+ snippet2.StartDirectives.Add(regionStart);
+ snippet2.EndDirectives.Add(new CodeRegionDirective(CodeRegionMode.End, string.Empty));
+
+ cd.Members.Add(field1);
+ cd.Members.Add(method1);
+ cd.Members.Add(constructor1);
+ cd.Members.Add(property1);
+ cd.Members.Add(methodMain);
+
+ cd.Members.Add(evt1);
+ cd.Members.Add(nestedClass1);
+ cd.Members.Add(delegate1);
+
+ cd.Members.Add(snippet1);
+
+ cd.Members.Add(field2);
+ cd.Members.Add(method2);
+ cd.Members.Add(constructor2);
+ cd.Members.Add(property2);
+
+ cd.Members.Add(typeConstructor2);
+ cd.Members.Add(evt2);
+ cd.Members.Add(nestedClass2);
+ cd.Members.Add(delegate2);
+ cd.Members.Add(snippet2);
+
+ AssertEqual(cu,
+ @"#Region ""Compile Unit Region""
+ '------------------------------------------------------------------------------
+ ' <auto-generated>
+ ' This code was generated by a tool.
+ ' Runtime Version:4.0.30319.42000
+ '
+ ' Changes to this file may cause incorrect behavior and will be lost if
+ ' the code is regenerated.
+ ' </auto-generated>
+ '------------------------------------------------------------------------------
+ Option Strict Off
+ Option Explicit On
+ Namespace Namespace1
+ #Region ""Outer Type Region""
+ 'Outer Type Comment
+ Public Class Class1
+ 'Field 1 Comment
+ Private field1 As String
+ #Region ""Field Region""
+ Private field2 As String
+ #End Region
+ #Region ""Snippet Region""
+ #End Region
+ #Region ""Type Constructor Region""
+ Shared Sub New()
+ End Sub
+ #End Region
+ #Region ""Constructor Region""
+ Public Sub New()
+ MyBase.New
+ Me.field1 = ""value1""
+ Me.field2 = ""value2""
+ End Sub
+ #End Region
+ Public Sub New(ByVal value1 As String, ByVal value2 As String)
+ MyBase.New
+ End Sub
+ Public ReadOnly Property Property1() As String
+ Get
+ Return Me.field1
+ End Get
+ End Property
+ #Region ""Property Region""
+ Public ReadOnly Property Property2() As String
+ Get
+ Return Me.field2
+ End Get
+ End Property
+ #End Region
+ Public Event Event1 As System.EventHandler
+ #Region ""Event Region""
+ Public Event Event2 As System.EventHandler
+ #End Region
+ Public Sub Method1()
+ RaiseEvent Event1(Me, System.EventArgs.Empty)
+ End Sub
+ Public Shared Sub Main()
+ End Sub
+ #Region ""Method Region""
+ 'Method 2 Comment
+ #ExternalSource(""MethodLinePragma.txt"",500)
+ Public Sub Method2()
+ RaiseEvent Event2(Me, System.EventArgs.Empty)
+ End Sub
+ #End ExternalSource
+ #End Region
+ Public Class NestedClass1
+ End Class
+ Public Delegate Sub nestedDelegate1(ByVal sender As Object, ByVal e As System.EventArgs)
+ #Region ""Nested Type Region""
+ 'Nested Type Comment
+ #ExternalSource(""NestedTypeLinePragma.txt"",400)
+ Public Class NestedClass2
+ End Class
+ #End ExternalSource
+ #End Region
+ #Region ""Delegate Region""
+ Public Delegate Sub nestedDelegate2(ByVal sender As Object, ByVal e As System.EventArgs)
+ #End Region
End Class
- #End ExternalSource
#End Region
- #Region ""Delegate Region""
- Public Delegate Sub nestedDelegate2(ByVal sender As Object, ByVal e As System.EventArgs)
- #End Region
- End Class
- #End Region
- End Namespace
- #End Region");
+ End Namespace
+ #End Region");
+ }).Dispose();
}
[Fact]
@@ -2354,823 +2365,828 @@ namespace System.CodeDom.Tests
[Fact]
public void ProviderSupports()
{
- CodeDomProvider provider = GetProvider();
-
- CodeCompileUnit cu = new CodeCompileUnit();
- CodeNamespace nspace = new CodeNamespace("NSPC");
- nspace.Imports.Add(new CodeNamespaceImport("System"));
- nspace.Imports.Add(new CodeNamespaceImport("System.Drawing"));
- nspace.Imports.Add(new CodeNamespaceImport("System.Windows.Forms"));
- nspace.Imports.Add(new CodeNamespaceImport("System.ComponentModel"));
- cu.Namespaces.Add(nspace);
-
- CodeTypeDeclaration cd = new CodeTypeDeclaration("TEST");
- cd.IsClass = true;
- nspace.Types.Add(cd);
-
- // Arrays of Arrays
- CodeMemberMethod cmm = new CodeMemberMethod();
- cmm.Name = "ArraysOfArrays";
- cmm.ReturnType = new CodeTypeReference(typeof(int));
- cmm.Attributes = MemberAttributes.Final | MemberAttributes.Public;
- if (provider.Supports(GeneratorSupport.ArraysOfArrays))
- {
- cmm.Statements.Add(new CodeVariableDeclarationStatement(new CodeTypeReference(typeof(int[][])),
- "arrayOfArrays", new CodeArrayCreateExpression(typeof(int[][]),
- new CodeArrayCreateExpression(typeof(int[]), new CodePrimitiveExpression(3), new CodePrimitiveExpression(4)),
- new CodeArrayCreateExpression(typeof(int[]), new CodeExpression[] { new CodePrimitiveExpression(1) }))));
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodeArrayIndexerExpression(
- new CodeArrayIndexerExpression(new CodeVariableReferenceExpression("arrayOfArrays"), new CodePrimitiveExpression(0))
- , new CodePrimitiveExpression(1))));
- }
- else
+ RemoteInvoke(() =>
{
- throw new Exception("not supported");
- }
- cd.Members.Add(cmm);
+ CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture;
- // assembly attributes
- if (provider.Supports(GeneratorSupport.AssemblyAttributes))
- {
- CodeAttributeDeclarationCollection attrs = cu.AssemblyCustomAttributes;
- attrs.Add(new CodeAttributeDeclaration("System.Reflection.AssemblyTitle", new
- CodeAttributeArgument(new CodePrimitiveExpression("MyAssembly"))));
- attrs.Add(new CodeAttributeDeclaration("System.Reflection.AssemblyVersion", new
- CodeAttributeArgument(new CodePrimitiveExpression("1.0.6.2"))));
- }
+ CodeDomProvider provider = GetProvider();
- CodeTypeDeclaration class1 = new CodeTypeDeclaration();
- if (provider.Supports(GeneratorSupport.ChainedConstructorArguments))
- {
- class1.Name = "Test2";
- class1.IsClass = true;
- nspace.Types.Add(class1);
-
- class1.Members.Add(new CodeMemberField(new CodeTypeReference(typeof(String)), "stringField"));
- CodeMemberProperty prop = new CodeMemberProperty();
- prop.Name = "accessStringField";
- prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
- prop.Type = new CodeTypeReference(typeof(String));
- prop.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(),
- "stringField")));
- prop.SetStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new
- CodeThisReferenceExpression(), "stringField"),
- new CodePropertySetValueReferenceExpression()));
- class1.Members.Add(prop);
-
- CodeConstructor cctor = new CodeConstructor();
- cctor.Attributes = MemberAttributes.Public;
- cctor.ChainedConstructorArgs.Add(new CodePrimitiveExpression("testingString"));
- cctor.ChainedConstructorArgs.Add(new CodePrimitiveExpression(null));
- cctor.ChainedConstructorArgs.Add(new CodePrimitiveExpression(null));
- class1.Members.Add(cctor);
-
- CodeConstructor cc = new CodeConstructor();
- cc.Attributes = MemberAttributes.Public | MemberAttributes.Overloaded;
- cc.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "p1"));
- cc.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "p2"));
- cc.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "p3"));
- cc.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression()
- , "stringField"), new CodeVariableReferenceExpression("p1")));
- class1.Members.Add(cc);
- // verify chained constructors work
- cmm = new CodeMemberMethod();
- cmm.Name = "ChainedConstructorUse";
- cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
- cmm.ReturnType = new CodeTypeReference(typeof(String));
- // utilize constructor
- cmm.Statements.Add(new CodeVariableDeclarationStatement("Test2", "t", new CodeObjectCreateExpression("Test2")));
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodeMethodReferenceExpression(
- new CodeVariableReferenceExpression("t"), "accessStringField")));
- cd.Members.Add(cmm);
- }
+ CodeCompileUnit cu = new CodeCompileUnit();
+ CodeNamespace nspace = new CodeNamespace("NSPC");
+ nspace.Imports.Add(new CodeNamespaceImport("System"));
+ nspace.Imports.Add(new CodeNamespaceImport("System.Drawing"));
+ nspace.Imports.Add(new CodeNamespaceImport("System.Windows.Forms"));
+ nspace.Imports.Add(new CodeNamespaceImport("System.ComponentModel"));
+ cu.Namespaces.Add(nspace);
- // complex expressions
- if (provider.Supports(GeneratorSupport.ComplexExpressions))
- {
- cmm = new CodeMemberMethod();
- cmm.Name = "ComplexExpressions";
+ CodeTypeDeclaration cd = new CodeTypeDeclaration("TEST");
+ cd.IsClass = true;
+ nspace.Types.Add(cd);
+
+ // Arrays of Arrays
+ CodeMemberMethod cmm = new CodeMemberMethod();
+ cmm.Name = "ArraysOfArrays";
cmm.ReturnType = new CodeTypeReference(typeof(int));
cmm.Attributes = MemberAttributes.Final | MemberAttributes.Public;
- cmm.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(int)), "i"));
- cmm.Statements.Add(new CodeAssignStatement(new CodeVariableReferenceExpression("i"),
- new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.Multiply,
- new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.Add,
- new CodePrimitiveExpression(3)))));
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("i")));
+ if (provider.Supports(GeneratorSupport.ArraysOfArrays))
+ {
+ cmm.Statements.Add(new CodeVariableDeclarationStatement(new CodeTypeReference(typeof(int[][])),
+ "arrayOfArrays", new CodeArrayCreateExpression(typeof(int[][]),
+ new CodeArrayCreateExpression(typeof(int[]), new CodePrimitiveExpression(3), new CodePrimitiveExpression(4)),
+ new CodeArrayCreateExpression(typeof(int[]), new CodeExpression[] { new CodePrimitiveExpression(1) }))));
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodeArrayIndexerExpression(
+ new CodeArrayIndexerExpression(new CodeVariableReferenceExpression("arrayOfArrays"), new CodePrimitiveExpression(0))
+ , new CodePrimitiveExpression(1))));
+ }
+ else
+ {
+ throw new Exception("not supported");
+ }
cd.Members.Add(cmm);
- }
- if (provider.Supports(GeneratorSupport.DeclareEnums))
- {
- CodeTypeDeclaration ce = new CodeTypeDeclaration("DecimalEnum");
- ce.IsEnum = true;
- nspace.Types.Add(ce);
+ // assembly attributes
+ if (provider.Supports(GeneratorSupport.AssemblyAttributes))
+ {
+ CodeAttributeDeclarationCollection attrs = cu.AssemblyCustomAttributes;
+ attrs.Add(new CodeAttributeDeclaration("System.Reflection.AssemblyTitle", new
+ CodeAttributeArgument(new CodePrimitiveExpression("MyAssembly"))));
+ attrs.Add(new CodeAttributeDeclaration("System.Reflection.AssemblyVersion", new
+ CodeAttributeArgument(new CodePrimitiveExpression("1.0.6.2"))));
+ }
+
+ CodeTypeDeclaration class1 = new CodeTypeDeclaration();
+ if (provider.Supports(GeneratorSupport.ChainedConstructorArguments))
+ {
+ class1.Name = "Test2";
+ class1.IsClass = true;
+ nspace.Types.Add(class1);
+
+ class1.Members.Add(new CodeMemberField(new CodeTypeReference(typeof(String)), "stringField"));
+ CodeMemberProperty prop = new CodeMemberProperty();
+ prop.Name = "accessStringField";
+ prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
+ prop.Type = new CodeTypeReference(typeof(String));
+ prop.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(),
+ "stringField")));
+ prop.SetStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new
+ CodeThisReferenceExpression(), "stringField"),
+ new CodePropertySetValueReferenceExpression()));
+ class1.Members.Add(prop);
+
+ CodeConstructor cctor = new CodeConstructor();
+ cctor.Attributes = MemberAttributes.Public;
+ cctor.ChainedConstructorArgs.Add(new CodePrimitiveExpression("testingString"));
+ cctor.ChainedConstructorArgs.Add(new CodePrimitiveExpression(null));
+ cctor.ChainedConstructorArgs.Add(new CodePrimitiveExpression(null));
+ class1.Members.Add(cctor);
+
+ CodeConstructor cc = new CodeConstructor();
+ cc.Attributes = MemberAttributes.Public | MemberAttributes.Overloaded;
+ cc.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "p1"));
+ cc.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "p2"));
+ cc.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), "p3"));
+ cc.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression()
+ , "stringField"), new CodeVariableReferenceExpression("p1")));
+ class1.Members.Add(cc);
+ // verify chained constructors work
+ cmm = new CodeMemberMethod();
+ cmm.Name = "ChainedConstructorUse";
+ cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
+ cmm.ReturnType = new CodeTypeReference(typeof(String));
+ // utilize constructor
+ cmm.Statements.Add(new CodeVariableDeclarationStatement("Test2", "t", new CodeObjectCreateExpression("Test2")));
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodeMethodReferenceExpression(
+ new CodeVariableReferenceExpression("t"), "accessStringField")));
+ cd.Members.Add(cmm);
+ }
- // things to enumerate
- for (int k = 0; k < 5; k++)
+ // complex expressions
+ if (provider.Supports(GeneratorSupport.ComplexExpressions))
{
- CodeMemberField Field = new CodeMemberField("System.Int32", "Num" + (k).ToString());
- Field.InitExpression = new CodePrimitiveExpression(k);
- ce.Members.Add(Field);
+ cmm = new CodeMemberMethod();
+ cmm.Name = "ComplexExpressions";
+ cmm.ReturnType = new CodeTypeReference(typeof(int));
+ cmm.Attributes = MemberAttributes.Final | MemberAttributes.Public;
+ cmm.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(int)), "i"));
+ cmm.Statements.Add(new CodeAssignStatement(new CodeVariableReferenceExpression("i"),
+ new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.Multiply,
+ new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.Add,
+ new CodePrimitiveExpression(3)))));
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("i")));
+ cd.Members.Add(cmm);
}
- cmm = new CodeMemberMethod();
- cmm.Name = "OutputDecimalEnumVal";
- cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
- CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression(typeof(int), "i");
- cmm.Parameters.Add(param);
- CodeBinaryOperatorExpression eq = new CodeBinaryOperatorExpression(
- new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.ValueEquality,
- new CodePrimitiveExpression(3));
- CodeMethodReturnStatement truestmt = new CodeMethodReturnStatement(
- new CodeCastExpression(typeof(int),
- new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("DecimalEnum"), "Num3")));
- CodeConditionStatement condstmt = new CodeConditionStatement(eq, truestmt);
- cmm.Statements.Add(condstmt);
-
- eq = new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"),
- CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(4));
- truestmt = new CodeMethodReturnStatement(new CodeCastExpression(typeof(int),
- new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("DecimalEnum"), "Num4")));
- condstmt = new CodeConditionStatement(eq, truestmt);
- cmm.Statements.Add(condstmt);
- eq = new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"),
- CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(2));
- truestmt = new CodeMethodReturnStatement(new CodeCastExpression(typeof(int),
- new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("DecimalEnum"), "Num2")));
- condstmt = new CodeConditionStatement(eq, truestmt);
- cmm.Statements.Add(condstmt);
-
- eq = new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"),
- CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(1));
- truestmt = new CodeMethodReturnStatement(new CodeCastExpression(typeof(int),
- new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("DecimalEnum"), "Num1")));
- condstmt = new CodeConditionStatement(eq, truestmt);
- cmm.Statements.Add(condstmt);
-
- eq = new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"),
- CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(0));
- truestmt = new CodeMethodReturnStatement(new CodeCastExpression(typeof(int),
- new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("DecimalEnum"), "Num0")));
- condstmt = new CodeConditionStatement(eq, truestmt);
- cmm.Statements.Add(condstmt);
-
- cmm.ReturnType = new CodeTypeReference("System.int32");
-
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodeBinaryOperatorExpression(
- new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.Add, new CodePrimitiveExpression(10))));
- cd.Members.Add(cmm);
- }
- if (provider.Supports(GeneratorSupport.DeclareInterfaces))
- {
- cmm = new CodeMemberMethod();
- cmm.Name = "TestSingleInterface";
- cmm.ReturnType = new CodeTypeReference(typeof(int));
- cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "i"));
- cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
- cmm.Statements.Add(new CodeVariableDeclarationStatement("TestSingleInterfaceImp", "t", new CodeObjectCreateExpression("TestSingleInterfaceImp")));
- CodeMethodInvokeExpression methodinvoke = new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("t")
- , "InterfaceMethod");
- methodinvoke.Parameters.Add(new CodeVariableReferenceExpression("i"));
- cmm.Statements.Add(new CodeMethodReturnStatement(methodinvoke));
- cd.Members.Add(cmm);
+ if (provider.Supports(GeneratorSupport.DeclareEnums))
+ {
+ CodeTypeDeclaration ce = new CodeTypeDeclaration("DecimalEnum");
+ ce.IsEnum = true;
+ nspace.Types.Add(ce);
+
+ // things to enumerate
+ for (int k = 0; k < 5; k++)
+ {
+ CodeMemberField Field = new CodeMemberField("System.Int32", "Num" + (k).ToString());
+ Field.InitExpression = new CodePrimitiveExpression(k);
+ ce.Members.Add(Field);
+ }
+ cmm = new CodeMemberMethod();
+ cmm.Name = "OutputDecimalEnumVal";
+ cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
+ CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression(typeof(int), "i");
+ cmm.Parameters.Add(param);
+ CodeBinaryOperatorExpression eq = new CodeBinaryOperatorExpression(
+ new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.ValueEquality,
+ new CodePrimitiveExpression(3));
+ CodeMethodReturnStatement truestmt = new CodeMethodReturnStatement(
+ new CodeCastExpression(typeof(int),
+ new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("DecimalEnum"), "Num3")));
+ CodeConditionStatement condstmt = new CodeConditionStatement(eq, truestmt);
+ cmm.Statements.Add(condstmt);
+
+ eq = new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"),
+ CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(4));
+ truestmt = new CodeMethodReturnStatement(new CodeCastExpression(typeof(int),
+ new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("DecimalEnum"), "Num4")));
+ condstmt = new CodeConditionStatement(eq, truestmt);
+ cmm.Statements.Add(condstmt);
+ eq = new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"),
+ CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(2));
+ truestmt = new CodeMethodReturnStatement(new CodeCastExpression(typeof(int),
+ new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("DecimalEnum"), "Num2")));
+ condstmt = new CodeConditionStatement(eq, truestmt);
+ cmm.Statements.Add(condstmt);
+
+ eq = new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"),
+ CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(1));
+ truestmt = new CodeMethodReturnStatement(new CodeCastExpression(typeof(int),
+ new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("DecimalEnum"), "Num1")));
+ condstmt = new CodeConditionStatement(eq, truestmt);
+ cmm.Statements.Add(condstmt);
+
+ eq = new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"),
+ CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(0));
+ truestmt = new CodeMethodReturnStatement(new CodeCastExpression(typeof(int),
+ new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("DecimalEnum"), "Num0")));
+ condstmt = new CodeConditionStatement(eq, truestmt);
+ cmm.Statements.Add(condstmt);
+
+ cmm.ReturnType = new CodeTypeReference("System.int32");
- class1 = new CodeTypeDeclaration("InterfaceA");
- class1.IsInterface = true;
- nspace.Types.Add(class1);
- cmm = new CodeMemberMethod();
- cmm.Attributes = MemberAttributes.Public;
- cmm.Name = "InterfaceMethod";
- cmm.ReturnType = new CodeTypeReference(typeof(int));
- cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "a"));
- class1.Members.Add(cmm);
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodeBinaryOperatorExpression(
+ new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.Add, new CodePrimitiveExpression(10))));
+ cd.Members.Add(cmm);
+ }
- if (provider.Supports(GeneratorSupport.MultipleInterfaceMembers))
+ if (provider.Supports(GeneratorSupport.DeclareInterfaces))
{
- CodeTypeDeclaration classDecl = new CodeTypeDeclaration("InterfaceB");
- classDecl.IsInterface = true;
- nspace.Types.Add(classDecl);
cmm = new CodeMemberMethod();
- cmm.Name = "InterfaceMethod";
+ cmm.Name = "TestSingleInterface";
+ cmm.ReturnType = new CodeTypeReference(typeof(int));
+ cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "i"));
+ cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
+ cmm.Statements.Add(new CodeVariableDeclarationStatement("TestSingleInterfaceImp", "t", new CodeObjectCreateExpression("TestSingleInterfaceImp")));
+ CodeMethodInvokeExpression methodinvoke = new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("t")
+ , "InterfaceMethod");
+ methodinvoke.Parameters.Add(new CodeVariableReferenceExpression("i"));
+ cmm.Statements.Add(new CodeMethodReturnStatement(methodinvoke));
+ cd.Members.Add(cmm);
+
+ class1 = new CodeTypeDeclaration("InterfaceA");
+ class1.IsInterface = true;
+ nspace.Types.Add(class1);
+ cmm = new CodeMemberMethod();
cmm.Attributes = MemberAttributes.Public;
+ cmm.Name = "InterfaceMethod";
cmm.ReturnType = new CodeTypeReference(typeof(int));
cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "a"));
- classDecl.Members.Add(cmm);
-
- CodeTypeDeclaration class2 = new CodeTypeDeclaration("TestMultipleInterfaceImp");
- class2.BaseTypes.Add(new CodeTypeReference("System.Object"));
- class2.BaseTypes.Add(new CodeTypeReference("InterfaceB"));
- class2.BaseTypes.Add(new CodeTypeReference("InterfaceA"));
- class2.IsClass = true;
- nspace.Types.Add(class2);
+ class1.Members.Add(cmm);
+
+ if (provider.Supports(GeneratorSupport.MultipleInterfaceMembers))
+ {
+ CodeTypeDeclaration classDecl = new CodeTypeDeclaration("InterfaceB");
+ classDecl.IsInterface = true;
+ nspace.Types.Add(classDecl);
+ cmm = new CodeMemberMethod();
+ cmm.Name = "InterfaceMethod";
+ cmm.Attributes = MemberAttributes.Public;
+ cmm.ReturnType = new CodeTypeReference(typeof(int));
+ cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "a"));
+ classDecl.Members.Add(cmm);
+
+ CodeTypeDeclaration class2 = new CodeTypeDeclaration("TestMultipleInterfaceImp");
+ class2.BaseTypes.Add(new CodeTypeReference("System.Object"));
+ class2.BaseTypes.Add(new CodeTypeReference("InterfaceB"));
+ class2.BaseTypes.Add(new CodeTypeReference("InterfaceA"));
+ class2.IsClass = true;
+ nspace.Types.Add(class2);
+ cmm = new CodeMemberMethod();
+ cmm.ImplementationTypes.Add(new CodeTypeReference("InterfaceA"));
+ cmm.ImplementationTypes.Add(new CodeTypeReference("InterfaceB"));
+ cmm.Name = "InterfaceMethod";
+ cmm.ReturnType = new CodeTypeReference(typeof(int));
+ cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "a"));
+ cmm.Attributes = MemberAttributes.Public | MemberAttributes.Final;
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("a")));
+ class2.Members.Add(cmm);
+
+ cmm = new CodeMemberMethod();
+ cmm.Name = "TestMultipleInterfaces";
+ cmm.ReturnType = new CodeTypeReference(typeof(int));
+ cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "i"));
+ cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
+ cmm.Statements.Add(new CodeVariableDeclarationStatement("TestMultipleInterfaceImp", "t", new CodeObjectCreateExpression("TestMultipleInterfaceImp")));
+ cmm.Statements.Add(new CodeVariableDeclarationStatement("InterfaceA", "interfaceAobject", new CodeCastExpression("InterfaceA",
+ new CodeVariableReferenceExpression("t"))));
+ cmm.Statements.Add(new CodeVariableDeclarationStatement("InterfaceB", "interfaceBobject", new CodeCastExpression("InterfaceB",
+ new CodeVariableReferenceExpression("t"))));
+ methodinvoke = new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("interfaceAobject")
+ , "InterfaceMethod");
+ methodinvoke.Parameters.Add(new CodeVariableReferenceExpression("i"));
+ CodeMethodInvokeExpression methodinvoke2 = new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("interfaceBobject")
+ , "InterfaceMethod");
+ methodinvoke2.Parameters.Add(new CodeVariableReferenceExpression("i"));
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodeBinaryOperatorExpression(
+ methodinvoke,
+ CodeBinaryOperatorType.Subtract, methodinvoke2)));
+ cd.Members.Add(cmm);
+ }
+
+ class1 = new CodeTypeDeclaration("TestSingleInterfaceImp");
+ class1.BaseTypes.Add(new CodeTypeReference("System.Object"));
+ class1.BaseTypes.Add(new CodeTypeReference("InterfaceA"));
+ class1.IsClass = true;
+ nspace.Types.Add(class1);
cmm = new CodeMemberMethod();
cmm.ImplementationTypes.Add(new CodeTypeReference("InterfaceA"));
- cmm.ImplementationTypes.Add(new CodeTypeReference("InterfaceB"));
cmm.Name = "InterfaceMethod";
cmm.ReturnType = new CodeTypeReference(typeof(int));
cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "a"));
- cmm.Attributes = MemberAttributes.Public | MemberAttributes.Final;
+ cmm.Attributes = MemberAttributes.Public;
cmm.Statements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("a")));
- class2.Members.Add(cmm);
+ class1.Members.Add(cmm);
+ }
+
+ if (provider.Supports(GeneratorSupport.DeclareValueTypes))
+ {
+ CodeTypeDeclaration structA = new CodeTypeDeclaration("structA");
+ structA.IsStruct = true;
+
+ CodeTypeDeclaration structB = new CodeTypeDeclaration("structB");
+ structB.Attributes = MemberAttributes.Public;
+ structB.IsStruct = true;
+
+ CodeMemberField firstInt = new CodeMemberField(typeof(int), "int1");
+ firstInt.Attributes = MemberAttributes.Public;
+ structB.Members.Add(firstInt);
+
+ CodeMemberField innerStruct = new CodeMemberField("structB", "innerStruct");
+ innerStruct.Attributes = MemberAttributes.Public;
+
+ structA.Members.Add(structB);
+ structA.Members.Add(innerStruct);
+ nspace.Types.Add(structA);
+
+ CodeMemberMethod nestedStructMethod = new CodeMemberMethod();
+ nestedStructMethod.Name = "NestedStructMethod";
+ nestedStructMethod.ReturnType = new CodeTypeReference(typeof(int));
+ nestedStructMethod.Attributes = MemberAttributes.Public | MemberAttributes.Static;
+ CodeVariableDeclarationStatement varStructA = new CodeVariableDeclarationStatement("structA", "varStructA");
+ nestedStructMethod.Statements.Add(varStructA);
+ nestedStructMethod.Statements.Add
+ (
+ new CodeAssignStatement
+ (
+ /* Expression1 */ new CodeFieldReferenceExpression(new CodeFieldReferenceExpression(new CodeVariableReferenceExpression("varStructA"), "innerStruct"), "int1"),
+ /* Expression1 */ new CodePrimitiveExpression(3)
+ )
+ );
+ nestedStructMethod.Statements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeFieldReferenceExpression(new CodeVariableReferenceExpression("varStructA"), "innerStruct"), "int1")));
+ cd.Members.Add(nestedStructMethod);
+ }
+
+ if (provider.Supports(GeneratorSupport.EntryPointMethod))
+ {
+ CodeEntryPointMethod cep = new CodeEntryPointMethod();
+ cd.Members.Add(cep);
+ }
+ // goto statements
+ if (provider.Supports(GeneratorSupport.GotoStatements))
+ {
cmm = new CodeMemberMethod();
- cmm.Name = "TestMultipleInterfaces";
+ cmm.Name = "GoToMethod";
cmm.ReturnType = new CodeTypeReference(typeof(int));
- cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "i"));
- cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
- cmm.Statements.Add(new CodeVariableDeclarationStatement("TestMultipleInterfaceImp", "t", new CodeObjectCreateExpression("TestMultipleInterfaceImp")));
- cmm.Statements.Add(new CodeVariableDeclarationStatement("InterfaceA", "interfaceAobject", new CodeCastExpression("InterfaceA",
- new CodeVariableReferenceExpression("t"))));
- cmm.Statements.Add(new CodeVariableDeclarationStatement("InterfaceB", "interfaceBobject", new CodeCastExpression("InterfaceB",
- new CodeVariableReferenceExpression("t"))));
- methodinvoke = new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("interfaceAobject")
- , "InterfaceMethod");
- methodinvoke.Parameters.Add(new CodeVariableReferenceExpression("i"));
- CodeMethodInvokeExpression methodinvoke2 = new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("interfaceBobject")
- , "InterfaceMethod");
- methodinvoke2.Parameters.Add(new CodeVariableReferenceExpression("i"));
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodeBinaryOperatorExpression(
- methodinvoke,
- CodeBinaryOperatorType.Subtract, methodinvoke2)));
+ cmm.Attributes = MemberAttributes.Public | MemberAttributes.Final;
+ CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression(typeof(int), "i");
+ cmm.Parameters.Add(param);
+ CodeConditionStatement condstmt = new CodeConditionStatement(new CodeBinaryOperatorExpression(
+ new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.LessThan, new CodePrimitiveExpression(1)),
+ new CodeGotoStatement("comehere"));
+ cmm.Statements.Add(condstmt);
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(6)));
+ cmm.Statements.Add(new CodeLabeledStatement("comehere",
+ new CodeMethodReturnStatement(new CodePrimitiveExpression(7))));
cd.Members.Add(cmm);
}
- class1 = new CodeTypeDeclaration("TestSingleInterfaceImp");
- class1.BaseTypes.Add(new CodeTypeReference("System.Object"));
- class1.BaseTypes.Add(new CodeTypeReference("InterfaceA"));
- class1.IsClass = true;
- nspace.Types.Add(class1);
- cmm = new CodeMemberMethod();
- cmm.ImplementationTypes.Add(new CodeTypeReference("InterfaceA"));
- cmm.Name = "InterfaceMethod";
- cmm.ReturnType = new CodeTypeReference(typeof(int));
- cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "a"));
- cmm.Attributes = MemberAttributes.Public;
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("a")));
- class1.Members.Add(cmm);
- }
-
- if (provider.Supports(GeneratorSupport.DeclareValueTypes))
- {
- CodeTypeDeclaration structA = new CodeTypeDeclaration("structA");
- structA.IsStruct = true;
-
- CodeTypeDeclaration structB = new CodeTypeDeclaration("structB");
- structB.Attributes = MemberAttributes.Public;
- structB.IsStruct = true;
-
- CodeMemberField firstInt = new CodeMemberField(typeof(int), "int1");
- firstInt.Attributes = MemberAttributes.Public;
- structB.Members.Add(firstInt);
-
- CodeMemberField innerStruct = new CodeMemberField("structB", "innerStruct");
- innerStruct.Attributes = MemberAttributes.Public;
-
- structA.Members.Add(structB);
- structA.Members.Add(innerStruct);
- nspace.Types.Add(structA);
-
- CodeMemberMethod nestedStructMethod = new CodeMemberMethod();
- nestedStructMethod.Name = "NestedStructMethod";
- nestedStructMethod.ReturnType = new CodeTypeReference(typeof(int));
- nestedStructMethod.Attributes = MemberAttributes.Public | MemberAttributes.Static;
- CodeVariableDeclarationStatement varStructA = new CodeVariableDeclarationStatement("structA", "varStructA");
- nestedStructMethod.Statements.Add(varStructA);
- nestedStructMethod.Statements.Add
- (
- new CodeAssignStatement
- (
- /* Expression1 */ new CodeFieldReferenceExpression(new CodeFieldReferenceExpression(new CodeVariableReferenceExpression("varStructA"), "innerStruct"), "int1"),
- /* Expression1 */ new CodePrimitiveExpression(3)
- )
- );
- nestedStructMethod.Statements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeFieldReferenceExpression(new CodeVariableReferenceExpression("varStructA"), "innerStruct"), "int1")));
- cd.Members.Add(nestedStructMethod);
- }
-
- if (provider.Supports(GeneratorSupport.EntryPointMethod))
- {
- CodeEntryPointMethod cep = new CodeEntryPointMethod();
- cd.Members.Add(cep);
- }
-
- // goto statements
- if (provider.Supports(GeneratorSupport.GotoStatements))
- {
- cmm = new CodeMemberMethod();
- cmm.Name = "GoToMethod";
- cmm.ReturnType = new CodeTypeReference(typeof(int));
- cmm.Attributes = MemberAttributes.Public | MemberAttributes.Final;
- CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression(typeof(int), "i");
- cmm.Parameters.Add(param);
- CodeConditionStatement condstmt = new CodeConditionStatement(new CodeBinaryOperatorExpression(
- new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.LessThan, new CodePrimitiveExpression(1)),
- new CodeGotoStatement("comehere"));
- cmm.Statements.Add(condstmt);
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(6)));
- cmm.Statements.Add(new CodeLabeledStatement("comehere",
- new CodeMethodReturnStatement(new CodePrimitiveExpression(7))));
- cd.Members.Add(cmm);
- }
-
- if (provider.Supports(GeneratorSupport.NestedTypes))
- {
- cmm = new CodeMemberMethod();
- cmm.Name = "CallingPublicNestedScenario";
- cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "i"));
- cmm.ReturnType = new CodeTypeReference(typeof(int));
- cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
- cmm.Statements.Add(new CodeVariableDeclarationStatement(new CodeTypeReference
- ("PublicNestedClassA+PublicNestedClassB2+PublicNestedClassC"), "t",
- new CodeObjectCreateExpression(new CodeTypeReference
- ("PublicNestedClassA+PublicNestedClassB2+PublicNestedClassC"))));
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("t"),
- "publicNestedClassesMethod",
- new CodeVariableReferenceExpression("i"))));
- cd.Members.Add(cmm);
-
- class1 = new CodeTypeDeclaration("PublicNestedClassA");
- class1.IsClass = true;
- nspace.Types.Add(class1);
- CodeTypeDeclaration nestedClass = new CodeTypeDeclaration("PublicNestedClassB1");
- nestedClass.IsClass = true;
- nestedClass.TypeAttributes = TypeAttributes.NestedPublic;
- class1.Members.Add(nestedClass);
- nestedClass = new CodeTypeDeclaration("PublicNestedClassB2");
- nestedClass.TypeAttributes = TypeAttributes.NestedPublic;
- nestedClass.IsClass = true;
- class1.Members.Add(nestedClass);
- CodeTypeDeclaration innerNestedClass = new CodeTypeDeclaration("PublicNestedClassC");
- innerNestedClass.TypeAttributes = TypeAttributes.NestedPublic;
- innerNestedClass.IsClass = true;
- nestedClass.Members.Add(innerNestedClass);
- cmm = new CodeMemberMethod();
- cmm.Name = "publicNestedClassesMethod";
- cmm.ReturnType = new CodeTypeReference(typeof(int));
- cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "a"));
- cmm.Attributes = MemberAttributes.Public | MemberAttributes.Final;
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("a")));
- innerNestedClass.Members.Add(cmm);
- }
-
- // Parameter Attributes
- if (provider.Supports(GeneratorSupport.ParameterAttributes))
- {
- CodeMemberMethod method1 = new CodeMemberMethod();
- method1.Name = "MyMethod";
- method1.Attributes = MemberAttributes.Public | MemberAttributes.Final;
- CodeParameterDeclarationExpression param1 = new CodeParameterDeclarationExpression(typeof(string), "blah");
- param1.CustomAttributes.Add(
- new CodeAttributeDeclaration(
- "System.Xml.Serialization.XmlElementAttribute",
- new CodeAttributeArgument(
- "Form",
- new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("System.Xml.Schema.XmlSchemaForm"), "Unqualified")),
- new CodeAttributeArgument(
- "IsNullable",
- new CodePrimitiveExpression(false))));
- method1.Parameters.Add(param1);
- cd.Members.Add(method1);
- }
-
- // public static members
- if (provider.Supports(GeneratorSupport.PublicStaticMembers))
- {
- cmm = new CodeMemberMethod();
- cmm.Name = "PublicStaticMethod";
- cmm.ReturnType = new CodeTypeReference(typeof(int));
- cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(16)));
- cd.Members.Add(cmm);
- }
-
- // reference parameters
- if (provider.Supports(GeneratorSupport.ReferenceParameters))
- {
- cmm = new CodeMemberMethod();
- cmm.Name = "Work";
- cmm.ReturnType = new CodeTypeReference("System.void");
- cmm.Attributes = MemberAttributes.Static;
- // add parameter with ref direction
- CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression(typeof(int), "i");
- param.Direction = FieldDirection.Ref;
- cmm.Parameters.Add(param);
- // add parameter with out direction
- param = new CodeParameterDeclarationExpression(typeof(int), "j");
- param.Direction = FieldDirection.Out;
- cmm.Parameters.Add(param);
- cmm.Statements.Add(new CodeAssignStatement(new CodeArgumentReferenceExpression("i"),
- new CodeBinaryOperatorExpression(new CodeArgumentReferenceExpression("i"),
- CodeBinaryOperatorType.Add, new CodePrimitiveExpression(4))));
- cmm.Statements.Add(new CodeAssignStatement(new CodeArgumentReferenceExpression("j"),
- new CodePrimitiveExpression(5)));
- cd.Members.Add(cmm);
-
- cmm = new CodeMemberMethod();
- cmm.Name = "CallingWork";
- cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
- CodeParameterDeclarationExpression parames = new CodeParameterDeclarationExpression(typeof(int), "a");
- cmm.Parameters.Add(parames);
- cmm.ReturnType = new CodeTypeReference("System.int32");
- cmm.Statements.Add(new CodeAssignStatement(new CodeVariableReferenceExpression("a"),
- new CodePrimitiveExpression(10)));
- cmm.Statements.Add(new CodeVariableDeclarationStatement(typeof(int), "b"));
- // invoke the method called "work"
- CodeMethodInvokeExpression methodinvoked = new CodeMethodInvokeExpression(new CodeMethodReferenceExpression
- (new CodeTypeReferenceExpression("TEST"), "Work"));
- // add parameter with ref direction
- CodeDirectionExpression parameter = new CodeDirectionExpression(FieldDirection.Ref,
- new CodeVariableReferenceExpression("a"));
- methodinvoked.Parameters.Add(parameter);
- // add parameter with out direction
- parameter = new CodeDirectionExpression(FieldDirection.Out, new CodeVariableReferenceExpression("b"));
- methodinvoked.Parameters.Add(parameter);
- cmm.Statements.Add(methodinvoked);
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodeBinaryOperatorExpression
- (new CodeVariableReferenceExpression("a"), CodeBinaryOperatorType.Add, new CodeVariableReferenceExpression("b"))));
- cd.Members.Add(cmm);
- }
-
- if (provider.Supports(GeneratorSupport.ReturnTypeAttributes))
- {
- CodeMemberMethod function1 = new CodeMemberMethod();
- function1.Name = "MyFunction";
- function1.ReturnType = new CodeTypeReference(typeof(string));
- function1.Attributes = MemberAttributes.Public | MemberAttributes.Final;
- function1.ReturnTypeCustomAttributes.Add(new
- CodeAttributeDeclaration("System.Xml.Serialization.XmlIgnoreAttribute"));
- function1.ReturnTypeCustomAttributes.Add(new CodeAttributeDeclaration("System.Xml.Serialization.XmlRootAttribute", new
- CodeAttributeArgument("Namespace", new CodePrimitiveExpression("Namespace Value")), new
- CodeAttributeArgument("ElementName", new CodePrimitiveExpression("Root, hehehe"))));
- function1.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression("Return")));
- cd.Members.Add(function1);
- }
-
- if (provider.Supports(GeneratorSupport.StaticConstructors))
- {
- cmm = new CodeMemberMethod();
- cmm.Name = "TestStaticConstructor";
- cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
- cmm.ReturnType = new CodeTypeReference(typeof(int));
- CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression(typeof(int), "a");
- cmm.Parameters.Add(param);
- // utilize constructor
- cmm.Statements.Add(new CodeVariableDeclarationStatement("Test4", "t", new CodeObjectCreateExpression("Test4")));
- // set then get number
- cmm.Statements.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(new CodeVariableReferenceExpression("t"), "i")
- , new CodeVariableReferenceExpression("a")));
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodeMethodReferenceExpression(
- new CodeVariableReferenceExpression("t"), "i")));
- cd.Members.Add(cmm);
-
- class1 = new CodeTypeDeclaration();
- class1.Name = "Test4";
- class1.IsClass = true;
- nspace.Types.Add(class1);
-
- class1.Members.Add(new CodeMemberField(new CodeTypeReference(typeof(int)), "number"));
- CodeMemberProperty prop = new CodeMemberProperty();
- prop.Name = "i";
- prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
- prop.Type = new CodeTypeReference(typeof(int));
- prop.GetStatements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("number")));
- prop.SetStatements.Add(new CodeAssignStatement(new CodeVariableReferenceExpression("number"),
- new CodePropertySetValueReferenceExpression()));
- class1.Members.Add(prop);
- CodeTypeConstructor ctc = new CodeTypeConstructor();
- class1.Members.Add(ctc);
- }
-
- if (provider.Supports(GeneratorSupport.TryCatchStatements))
- {
- cmm = new CodeMemberMethod();
- cmm.Name = "TryCatchMethod";
- cmm.ReturnType = new CodeTypeReference(typeof(int));
- cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
- CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression(typeof(int), "a");
- cmm.Parameters.Add(param);
-
- CodeTryCatchFinallyStatement tcfstmt = new CodeTryCatchFinallyStatement();
- tcfstmt.FinallyStatements.Add(new CodeAssignStatement(new CodeVariableReferenceExpression("a"), new
- CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("a"), CodeBinaryOperatorType.Add,
- new CodePrimitiveExpression(5))));
- cmm.Statements.Add(tcfstmt);
- cmm.Statements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("a")));
- cd.Members.Add(cmm);
- }
-
- if (provider.Supports(GeneratorSupport.DeclareEvents))
- {
- CodeNamespace ns = new CodeNamespace();
- ns.Name = "MyNamespace";
- ns.Imports.Add(new CodeNamespaceImport("System"));
- ns.Imports.Add(new CodeNamespaceImport("System.Drawing"));
- ns.Imports.Add(new CodeNamespaceImport("System.Windows.Forms"));
- ns.Imports.Add(new CodeNamespaceImport("System.ComponentModel"));
- cu.Namespaces.Add(ns);
- class1 = new CodeTypeDeclaration("Test");
- class1.IsClass = true;
- class1.BaseTypes.Add(new CodeTypeReference("Form"));
- ns.Types.Add(class1);
-
- CodeMemberField mfield = new CodeMemberField(new CodeTypeReference("Button"), "b");
- mfield.InitExpression = new CodeObjectCreateExpression(new CodeTypeReference("Button"));
- class1.Members.Add(mfield);
-
- CodeConstructor ctor = new CodeConstructor();
- ctor.Attributes = MemberAttributes.Public;
- ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(),
- "Size"), new CodeObjectCreateExpression(new CodeTypeReference("Size"),
- new CodePrimitiveExpression(600), new CodePrimitiveExpression(600))));
- ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("b"),
- "Text"), new CodePrimitiveExpression("Test")));
- ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("b"),
- "TabIndex"), new CodePrimitiveExpression(0)));
- ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("b"),
- "Location"), new CodeObjectCreateExpression(new CodeTypeReference("Point"),
- new CodePrimitiveExpression(400), new CodePrimitiveExpression(525))));
- ctor.Statements.Add(new CodeAttachEventStatement(new CodeEventReferenceExpression(new
- CodeThisReferenceExpression(), "MyEvent"), new CodeDelegateCreateExpression(new CodeTypeReference("EventHandler")
- , new CodeThisReferenceExpression(), "b_Click")));
- class1.Members.Add(ctor);
-
- CodeMemberEvent evt = new CodeMemberEvent();
- evt.Name = "MyEvent";
- evt.Type = new CodeTypeReference("System.EventHandler");
- evt.Attributes = MemberAttributes.Public;
- class1.Members.Add(evt);
-
- cmm = new CodeMemberMethod();
- cmm.Name = "b_Click";
- cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "sender"));
- cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(EventArgs), "e"));
- class1.Members.Add(cmm);
- }
-
- AssertEqual(cu,
- @"'------------------------------------------------------------------------------
- ' <auto-generated>
- ' This code was generated by a tool.
- ' Runtime Version:4.0.30319.42000
- '
- ' Changes to this file may cause incorrect behavior and will be lost if
- ' the code is regenerated.
- ' </auto-generated>
- '------------------------------------------------------------------------------
-
- Option Strict Off
- Option Explicit On
-
- Imports System
- Imports System.ComponentModel
- Imports System.Drawing
- Imports System.Windows.Forms
- <Assembly: System.Reflection.AssemblyTitle(""MyAssembly""), _
- Assembly: System.Reflection.AssemblyVersion(""1.0.6.2"")>
-
- Namespace NSPC
-
- Public Class TEST
-
- Public Function ArraysOfArrays() As Integer
- Dim arrayOfArrays()() As Integer = New Integer()() {New Integer() {3, 4}, New Integer() {1}}
- Return arrayOfArrays(0)(1)
- End Function
-
- Public Shared Function ChainedConstructorUse() As String
- Dim t As Test2 = New Test2()
- Return t.accessStringField
- End Function
-
- Public Function ComplexExpressions(ByVal i As Integer) As Integer
- i = (i _
- * (i + 3))
- Return i
- End Function
-
- Public Shared Function OutputDecimalEnumVal(ByVal i As Integer) As Integer
- If (i = 3) Then
- Return CType(DecimalEnum.Num3,Integer)
- End If
- If (i = 4) Then
- Return CType(DecimalEnum.Num4,Integer)
- End If
- If (i = 2) Then
- Return CType(DecimalEnum.Num2,Integer)
- End If
- If (i = 1) Then
- Return CType(DecimalEnum.Num1,Integer)
- End If
- If (i = 0) Then
- Return CType(DecimalEnum.Num0,Integer)
- End If
- Return (i + 10)
- End Function
-
- Public Shared Function TestSingleInterface(ByVal i As Integer) As Integer
- Dim t As TestSingleInterfaceImp = New TestSingleInterfaceImp()
- Return t.InterfaceMethod(i)
- End Function
+ if (provider.Supports(GeneratorSupport.NestedTypes))
+ {
+ cmm = new CodeMemberMethod();
+ cmm.Name = "CallingPublicNestedScenario";
+ cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "i"));
+ cmm.ReturnType = new CodeTypeReference(typeof(int));
+ cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
+ cmm.Statements.Add(new CodeVariableDeclarationStatement(new CodeTypeReference
+ ("PublicNestedClassA+PublicNestedClassB2+PublicNestedClassC"), "t",
+ new CodeObjectCreateExpression(new CodeTypeReference
+ ("PublicNestedClassA+PublicNestedClassB2+PublicNestedClassC"))));
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("t"),
+ "publicNestedClassesMethod",
+ new CodeVariableReferenceExpression("i"))));
+ cd.Members.Add(cmm);
- Public Shared Function TestMultipleInterfaces(ByVal i As Integer) As Integer
- Dim t As TestMultipleInterfaceImp = New TestMultipleInterfaceImp()
- Dim interfaceAobject As InterfaceA = CType(t,InterfaceA)
- Dim interfaceBobject As InterfaceB = CType(t,InterfaceB)
- Return (interfaceAobject.InterfaceMethod(i) - interfaceBobject.InterfaceMethod(i))
- End Function
+ class1 = new CodeTypeDeclaration("PublicNestedClassA");
+ class1.IsClass = true;
+ nspace.Types.Add(class1);
+ CodeTypeDeclaration nestedClass = new CodeTypeDeclaration("PublicNestedClassB1");
+ nestedClass.IsClass = true;
+ nestedClass.TypeAttributes = TypeAttributes.NestedPublic;
+ class1.Members.Add(nestedClass);
+ nestedClass = new CodeTypeDeclaration("PublicNestedClassB2");
+ nestedClass.TypeAttributes = TypeAttributes.NestedPublic;
+ nestedClass.IsClass = true;
+ class1.Members.Add(nestedClass);
+ CodeTypeDeclaration innerNestedClass = new CodeTypeDeclaration("PublicNestedClassC");
+ innerNestedClass.TypeAttributes = TypeAttributes.NestedPublic;
+ innerNestedClass.IsClass = true;
+ nestedClass.Members.Add(innerNestedClass);
+ cmm = new CodeMemberMethod();
+ cmm.Name = "publicNestedClassesMethod";
+ cmm.ReturnType = new CodeTypeReference(typeof(int));
+ cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int), "a"));
+ cmm.Attributes = MemberAttributes.Public | MemberAttributes.Final;
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("a")));
+ innerNestedClass.Members.Add(cmm);
+ }
- Public Shared Function NestedStructMethod() As Integer
- Dim varStructA As structA
- varStructA.innerStruct.int1 = 3
- Return varStructA.innerStruct.int1
- End Function
+ // Parameter Attributes
+ if (provider.Supports(GeneratorSupport.ParameterAttributes))
+ {
+ CodeMemberMethod method1 = new CodeMemberMethod();
+ method1.Name = "MyMethod";
+ method1.Attributes = MemberAttributes.Public | MemberAttributes.Final;
+ CodeParameterDeclarationExpression param1 = new CodeParameterDeclarationExpression(typeof(string), "blah");
+ param1.CustomAttributes.Add(
+ new CodeAttributeDeclaration(
+ "System.Xml.Serialization.XmlElementAttribute",
+ new CodeAttributeArgument(
+ "Form",
+ new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("System.Xml.Schema.XmlSchemaForm"), "Unqualified")),
+ new CodeAttributeArgument(
+ "IsNullable",
+ new CodePrimitiveExpression(false))));
+ method1.Parameters.Add(param1);
+ cd.Members.Add(method1);
+ }
- Public Shared Sub Main()
- End Sub
+ // public static members
+ if (provider.Supports(GeneratorSupport.PublicStaticMembers))
+ {
+ cmm = new CodeMemberMethod();
+ cmm.Name = "PublicStaticMethod";
+ cmm.ReturnType = new CodeTypeReference(typeof(int));
+ cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(16)));
+ cd.Members.Add(cmm);
+ }
- Public Function GoToMethod(ByVal i As Integer) As Integer
- If (i < 1) Then
- goto comehere
- End If
- Return 6
- comehere:
- Return 7
- End Function
+ // reference parameters
+ if (provider.Supports(GeneratorSupport.ReferenceParameters))
+ {
+ cmm = new CodeMemberMethod();
+ cmm.Name = "Work";
+ cmm.ReturnType = new CodeTypeReference("System.void");
+ cmm.Attributes = MemberAttributes.Static;
+ // add parameter with ref direction
+ CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression(typeof(int), "i");
+ param.Direction = FieldDirection.Ref;
+ cmm.Parameters.Add(param);
+ // add parameter with out direction
+ param = new CodeParameterDeclarationExpression(typeof(int), "j");
+ param.Direction = FieldDirection.Out;
+ cmm.Parameters.Add(param);
+ cmm.Statements.Add(new CodeAssignStatement(new CodeArgumentReferenceExpression("i"),
+ new CodeBinaryOperatorExpression(new CodeArgumentReferenceExpression("i"),
+ CodeBinaryOperatorType.Add, new CodePrimitiveExpression(4))));
+ cmm.Statements.Add(new CodeAssignStatement(new CodeArgumentReferenceExpression("j"),
+ new CodePrimitiveExpression(5)));
+ cd.Members.Add(cmm);
- Public Shared Function CallingPublicNestedScenario(ByVal i As Integer) As Integer
- Dim t As PublicNestedClassA.PublicNestedClassB2.PublicNestedClassC = New PublicNestedClassA.PublicNestedClassB2.PublicNestedClassC()
- Return t.publicNestedClassesMethod(i)
- End Function
+ cmm = new CodeMemberMethod();
+ cmm.Name = "CallingWork";
+ cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
+ CodeParameterDeclarationExpression parames = new CodeParameterDeclarationExpression(typeof(int), "a");
+ cmm.Parameters.Add(parames);
+ cmm.ReturnType = new CodeTypeReference("System.int32");
+ cmm.Statements.Add(new CodeAssignStatement(new CodeVariableReferenceExpression("a"),
+ new CodePrimitiveExpression(10)));
+ cmm.Statements.Add(new CodeVariableDeclarationStatement(typeof(int), "b"));
+ // invoke the method called "work"
+ CodeMethodInvokeExpression methodinvoked = new CodeMethodInvokeExpression(new CodeMethodReferenceExpression
+ (new CodeTypeReferenceExpression("TEST"), "Work"));
+ // add parameter with ref direction
+ CodeDirectionExpression parameter = new CodeDirectionExpression(FieldDirection.Ref,
+ new CodeVariableReferenceExpression("a"));
+ methodinvoked.Parameters.Add(parameter);
+ // add parameter with out direction
+ parameter = new CodeDirectionExpression(FieldDirection.Out, new CodeVariableReferenceExpression("b"));
+ methodinvoked.Parameters.Add(parameter);
+ cmm.Statements.Add(methodinvoked);
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodeBinaryOperatorExpression
+ (new CodeVariableReferenceExpression("a"), CodeBinaryOperatorType.Add, new CodeVariableReferenceExpression("b"))));
+ cd.Members.Add(cmm);
+ }
- Public Sub MyMethod(<System.Xml.Serialization.XmlElementAttribute(Form:=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable:=false)> ByVal blah As String)
- End Sub
+ if (provider.Supports(GeneratorSupport.ReturnTypeAttributes))
+ {
+ CodeMemberMethod function1 = new CodeMemberMethod();
+ function1.Name = "MyFunction";
+ function1.ReturnType = new CodeTypeReference(typeof(string));
+ function1.Attributes = MemberAttributes.Public | MemberAttributes.Final;
+ function1.ReturnTypeCustomAttributes.Add(new
+ CodeAttributeDeclaration("System.Xml.Serialization.XmlIgnoreAttribute"));
+ function1.ReturnTypeCustomAttributes.Add(new CodeAttributeDeclaration("System.Xml.Serialization.XmlRootAttribute", new
+ CodeAttributeArgument("Namespace", new CodePrimitiveExpression("Namespace Value")), new
+ CodeAttributeArgument("ElementName", new CodePrimitiveExpression("Root, hehehe"))));
+ function1.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression("Return")));
+ cd.Members.Add(function1);
+ }
- Public Shared Function PublicStaticMethod() As Integer
- Return 16
- End Function
+ if (provider.Supports(GeneratorSupport.StaticConstructors))
+ {
+ cmm = new CodeMemberMethod();
+ cmm.Name = "TestStaticConstructor";
+ cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
+ cmm.ReturnType = new CodeTypeReference(typeof(int));
+ CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression(typeof(int), "a");
+ cmm.Parameters.Add(param);
+ // utilize constructor
+ cmm.Statements.Add(new CodeVariableDeclarationStatement("Test4", "t", new CodeObjectCreateExpression("Test4")));
+ // set then get number
+ cmm.Statements.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(new CodeVariableReferenceExpression("t"), "i")
+ , new CodeVariableReferenceExpression("a")));
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodeMethodReferenceExpression(
+ new CodeVariableReferenceExpression("t"), "i")));
+ cd.Members.Add(cmm);
- Shared Sub Work(ByRef i As Integer, ByRef j As Integer)
- i = (i + 4)
- j = 5
- End Sub
+ class1 = new CodeTypeDeclaration();
+ class1.Name = "Test4";
+ class1.IsClass = true;
+ nspace.Types.Add(class1);
+
+ class1.Members.Add(new CodeMemberField(new CodeTypeReference(typeof(int)), "number"));
+ CodeMemberProperty prop = new CodeMemberProperty();
+ prop.Name = "i";
+ prop.Attributes = MemberAttributes.Public | MemberAttributes.Final;
+ prop.Type = new CodeTypeReference(typeof(int));
+ prop.GetStatements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("number")));
+ prop.SetStatements.Add(new CodeAssignStatement(new CodeVariableReferenceExpression("number"),
+ new CodePropertySetValueReferenceExpression()));
+ class1.Members.Add(prop);
+ CodeTypeConstructor ctc = new CodeTypeConstructor();
+ class1.Members.Add(ctc);
+ }
- Public Shared Function CallingWork(ByVal a As Integer) As Integer
- a = 10
- Dim b As Integer
- TEST.Work(a, b)
- Return (a + b)
- End Function
+ if (provider.Supports(GeneratorSupport.TryCatchStatements))
+ {
+ cmm = new CodeMemberMethod();
+ cmm.Name = "TryCatchMethod";
+ cmm.ReturnType = new CodeTypeReference(typeof(int));
+ cmm.Attributes = MemberAttributes.Public | MemberAttributes.Static;
+ CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression(typeof(int), "a");
+ cmm.Parameters.Add(param);
+
+ CodeTryCatchFinallyStatement tcfstmt = new CodeTryCatchFinallyStatement();
+ tcfstmt.FinallyStatements.Add(new CodeAssignStatement(new CodeVariableReferenceExpression("a"), new
+ CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("a"), CodeBinaryOperatorType.Add,
+ new CodePrimitiveExpression(5))));
+ cmm.Statements.Add(tcfstmt);
+ cmm.Statements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("a")));
+ cd.Members.Add(cmm);
+ }
- Public Function MyFunction() As <System.Xml.Serialization.XmlIgnoreAttribute(), System.Xml.Serialization.XmlRootAttribute([Namespace]:=""Namespace Value"", ElementName:=""Root, hehehe"")> String
- Return ""Return""
- End Function
+ if (provider.Supports(GeneratorSupport.DeclareEvents))
+ {
+ CodeNamespace ns = new CodeNamespace();
+ ns.Name = "MyNamespace";
+ ns.Imports.Add(new CodeNamespaceImport("System"));
+ ns.Imports.Add(new CodeNamespaceImport("System.Drawing"));
+ ns.Imports.Add(new CodeNamespaceImport("System.Windows.Forms"));
+ ns.Imports.Add(new CodeNamespaceImport("System.ComponentModel"));
+ cu.Namespaces.Add(ns);
+ class1 = new CodeTypeDeclaration("Test");
+ class1.IsClass = true;
+ class1.BaseTypes.Add(new CodeTypeReference("Form"));
+ ns.Types.Add(class1);
+
+ CodeMemberField mfield = new CodeMemberField(new CodeTypeReference("Button"), "b");
+ mfield.InitExpression = new CodeObjectCreateExpression(new CodeTypeReference("Button"));
+ class1.Members.Add(mfield);
+
+ CodeConstructor ctor = new CodeConstructor();
+ ctor.Attributes = MemberAttributes.Public;
+ ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(),
+ "Size"), new CodeObjectCreateExpression(new CodeTypeReference("Size"),
+ new CodePrimitiveExpression(600), new CodePrimitiveExpression(600))));
+ ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("b"),
+ "Text"), new CodePrimitiveExpression("Test")));
+ ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("b"),
+ "TabIndex"), new CodePrimitiveExpression(0)));
+ ctor.Statements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("b"),
+ "Location"), new CodeObjectCreateExpression(new CodeTypeReference("Point"),
+ new CodePrimitiveExpression(400), new CodePrimitiveExpression(525))));
+ ctor.Statements.Add(new CodeAttachEventStatement(new CodeEventReferenceExpression(new
+ CodeThisReferenceExpression(), "MyEvent"), new CodeDelegateCreateExpression(new CodeTypeReference("EventHandler")
+ , new CodeThisReferenceExpression(), "b_Click")));
+ class1.Members.Add(ctor);
+
+ CodeMemberEvent evt = new CodeMemberEvent();
+ evt.Name = "MyEvent";
+ evt.Type = new CodeTypeReference("System.EventHandler");
+ evt.Attributes = MemberAttributes.Public;
+ class1.Members.Add(evt);
- Public Shared Function TestStaticConstructor(ByVal a As Integer) As Integer
- Dim t As Test4 = New Test4()
- t.i = a
- Return t.i
- End Function
+ cmm = new CodeMemberMethod();
+ cmm.Name = "b_Click";
+ cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "sender"));
+ cmm.Parameters.Add(new CodeParameterDeclarationExpression(typeof(EventArgs), "e"));
+ class1.Members.Add(cmm);
+ }
- Public Shared Function TryCatchMethod(ByVal a As Integer) As Integer
- Try
- Finally
- a = (a + 5)
- End Try
- Return a
- End Function
- End Class
+ AssertEqual(cu,
+ @"'------------------------------------------------------------------------------
+ ' <auto-generated>
+ ' This code was generated by a tool.
+ ' Runtime Version:4.0.30319.42000
+ '
+ ' Changes to this file may cause incorrect behavior and will be lost if
+ ' the code is regenerated.
+ ' </auto-generated>
+ '------------------------------------------------------------------------------
+
+ Option Strict Off
+ Option Explicit On
+
+ Imports System
+ Imports System.ComponentModel
+ Imports System.Drawing
+ Imports System.Windows.Forms
+ <Assembly: System.Reflection.AssemblyTitle(""MyAssembly""), _
+ Assembly: System.Reflection.AssemblyVersion(""1.0.6.2"")>
+
+ Namespace NSPC
+
+ Public Class TEST
+
+ Public Function ArraysOfArrays() As Integer
+ Dim arrayOfArrays()() As Integer = New Integer()() {New Integer() {3, 4}, New Integer() {1}}
+ Return arrayOfArrays(0)(1)
+ End Function
+
+ Public Shared Function ChainedConstructorUse() As String
+ Dim t As Test2 = New Test2()
+ Return t.accessStringField
+ End Function
+
+ Public Function ComplexExpressions(ByVal i As Integer) As Integer
+ i = (i _
+ * (i + 3))
+ Return i
+ End Function
+
+ Public Shared Function OutputDecimalEnumVal(ByVal i As Integer) As Integer
+ If (i = 3) Then
+ Return CType(DecimalEnum.Num3,Integer)
+ End If
+ If (i = 4) Then
+ Return CType(DecimalEnum.Num4,Integer)
+ End If
+ If (i = 2) Then
+ Return CType(DecimalEnum.Num2,Integer)
+ End If
+ If (i = 1) Then
+ Return CType(DecimalEnum.Num1,Integer)
+ End If
+ If (i = 0) Then
+ Return CType(DecimalEnum.Num0,Integer)
+ End If
+ Return (i + 10)
+ End Function
+
+ Public Shared Function TestSingleInterface(ByVal i As Integer) As Integer
+ Dim t As TestSingleInterfaceImp = New TestSingleInterfaceImp()
+ Return t.InterfaceMethod(i)
+ End Function
+
+ Public Shared Function TestMultipleInterfaces(ByVal i As Integer) As Integer
+ Dim t As TestMultipleInterfaceImp = New TestMultipleInterfaceImp()
+ Dim interfaceAobject As InterfaceA = CType(t,InterfaceA)
+ Dim interfaceBobject As InterfaceB = CType(t,InterfaceB)
+ Return (interfaceAobject.InterfaceMethod(i) - interfaceBobject.InterfaceMethod(i))
+ End Function
+
+ Public Shared Function NestedStructMethod() As Integer
+ Dim varStructA As structA
+ varStructA.innerStruct.int1 = 3
+ Return varStructA.innerStruct.int1
+ End Function
+
+ Public Shared Sub Main()
+ End Sub
+
+ Public Function GoToMethod(ByVal i As Integer) As Integer
+ If (i < 1) Then
+ goto comehere
+ End If
+ Return 6
+ comehere:
+ Return 7
+ End Function
+
+ Public Shared Function CallingPublicNestedScenario(ByVal i As Integer) As Integer
+ Dim t As PublicNestedClassA.PublicNestedClassB2.PublicNestedClassC = New PublicNestedClassA.PublicNestedClassB2.PublicNestedClassC()
+ Return t.publicNestedClassesMethod(i)
+ End Function
+
+ Public Sub MyMethod(<System.Xml.Serialization.XmlElementAttribute(Form:=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable:=false)> ByVal blah As String)
+ End Sub
+
+ Public Shared Function PublicStaticMethod() As Integer
+ Return 16
+ End Function
+
+ Shared Sub Work(ByRef i As Integer, ByRef j As Integer)
+ i = (i + 4)
+ j = 5
+ End Sub
+
+ Public Shared Function CallingWork(ByVal a As Integer) As Integer
+ a = 10
+ Dim b As Integer
+ TEST.Work(a, b)
+ Return (a + b)
+ End Function
+
+ Public Function MyFunction() As <System.Xml.Serialization.XmlIgnoreAttribute(), System.Xml.Serialization.XmlRootAttribute([Namespace]:=""Namespace Value"", ElementName:=""Root, hehehe"")> String
+ Return ""Return""
+ End Function
+
+ Public Shared Function TestStaticConstructor(ByVal a As Integer) As Integer
+ Dim t As Test4 = New Test4()
+ t.i = a
+ Return t.i
+ End Function
+
+ Public Shared Function TryCatchMethod(ByVal a As Integer) As Integer
+ Try
+ Finally
+ a = (a + 5)
+ End Try
+ Return a
+ End Function
+ End Class
- Public Class Test2
+ Public Class Test2
- Private stringField As String
+ Private stringField As String
- Public Sub New()
- Me.New(""testingString"", Nothing, Nothing)
- End Sub
+ Public Sub New()
+ Me.New(""testingString"", Nothing, Nothing)
+ End Sub
- Public Sub New(ByVal p1 As String, ByVal p2 As String, ByVal p3 As String)
- MyBase.New
- Me.stringField = p1
- End Sub
+ Public Sub New(ByVal p1 As String, ByVal p2 As String, ByVal p3 As String)
+ MyBase.New
+ Me.stringField = p1
+ End Sub
- Public Property accessStringField() As String
- Get
- Return Me.stringField
- End Get
- Set
- Me.stringField = value
- End Set
- End Property
- End Class
+ Public Property accessStringField() As String
+ Get
+ Return Me.stringField
+ End Get
+ Set
+ Me.stringField = value
+ End Set
+ End Property
+ End Class
- Public Enum DecimalEnum
+ Public Enum DecimalEnum
- Num0 = 0
+ Num0 = 0
- Num1 = 1
+ Num1 = 1
- Num2 = 2
+ Num2 = 2
- Num3 = 3
+ Num3 = 3
- Num4 = 4
- End Enum
+ Num4 = 4
+ End Enum
- Public Interface InterfaceA
+ Public Interface InterfaceA
- Function InterfaceMethod(ByVal a As Integer) As Integer
- End Interface
+ Function InterfaceMethod(ByVal a As Integer) As Integer
+ End Interface
- Public Interface InterfaceB
+ Public Interface InterfaceB
- Function InterfaceMethod(ByVal a As Integer) As Integer
- End Interface
+ Function InterfaceMethod(ByVal a As Integer) As Integer
+ End Interface
- Public Class TestMultipleInterfaceImp
- Inherits Object
- Implements InterfaceB, InterfaceA
+ Public Class TestMultipleInterfaceImp
+ Inherits Object
+ Implements InterfaceB, InterfaceA
- Public Function InterfaceMethod(ByVal a As Integer) As Integer Implements InterfaceA.InterfaceMethod , InterfaceB.InterfaceMethod
- Return a
- End Function
- End Class
+ Public Function InterfaceMethod(ByVal a As Integer) As Integer Implements InterfaceA.InterfaceMethod , InterfaceB.InterfaceMethod
+ Return a
+ End Function
+ End Class
- Public Class TestSingleInterfaceImp
- Inherits Object
- Implements InterfaceA
+ Public Class TestSingleInterfaceImp
+ Inherits Object
+ Implements InterfaceA
- Public Overridable Function InterfaceMethod(ByVal a As Integer) As Integer Implements InterfaceA.InterfaceMethod
- Return a
- End Function
- End Class
+ Public Overridable Function InterfaceMethod(ByVal a As Integer) As Integer Implements InterfaceA.InterfaceMethod
+ Return a
+ End Function
+ End Class
- Public Structure structA
+ Public Structure structA
- Public innerStruct As structB
+ Public innerStruct As structB
- Public Structure structB
+ Public Structure structB
- Public int1 As Integer
+ Public int1 As Integer
+ End Structure
End Structure
- End Structure
- Public Class PublicNestedClassA
+ Public Class PublicNestedClassA
- Public Class PublicNestedClassB1
- End Class
+ Public Class PublicNestedClassB1
+ End Class
- Public Class PublicNestedClassB2
+ Public Class PublicNestedClassB2
- Public Class PublicNestedClassC
+ Public Class PublicNestedClassC
- Public Function publicNestedClassesMethod(ByVal a As Integer) As Integer
- Return a
- End Function
+ Public Function publicNestedClassesMethod(ByVal a As Integer) As Integer
+ Return a
+ End Function
+ End Class
End Class
End Class
- End Class
- Public Class Test4
+ Public Class Test4
- Private number As Integer
+ Private number As Integer
- Shared Sub New()
- End Sub
+ Shared Sub New()
+ End Sub
- Public Property i() As Integer
- Get
- Return number
- End Get
- Set
- number = value
- End Set
- End Property
- End Class
- End Namespace
+ Public Property i() As Integer
+ Get
+ Return number
+ End Get
+ Set
+ number = value
+ End Set
+ End Property
+ End Class
+ End Namespace
- Namespace MyNamespace
+ Namespace MyNamespace
- Public Class Test
- Inherits Form
+ Public Class Test
+ Inherits Form
- Private b As Button = New Button()
+ Private b As Button = New Button()
- Public Sub New()
- MyBase.New
- Me.Size = New Size(600, 600)
- b.Text = ""Test""
- b.TabIndex = 0
- b.Location = New Point(400, 525)
- AddHandler MyEvent, AddressOf Me.b_Click
- End Sub
+ Public Sub New()
+ MyBase.New
+ Me.Size = New Size(600, 600)
+ b.Text = ""Test""
+ b.TabIndex = 0
+ b.Location = New Point(400, 525)
+ AddHandler MyEvent, AddressOf Me.b_Click
+ End Sub
- Public Event MyEvent As System.EventHandler
+ Public Event MyEvent As System.EventHandler
- Private Sub b_Click(ByVal sender As Object, ByVal e As System.EventArgs)
- End Sub
- End Class
- End Namespace");
+ Private Sub b_Click(ByVal sender As Object, ByVal e As System.EventArgs)
+ End Sub
+ End Class
+ End Namespace");
+ }).Dispose();
}
[Fact]
diff --git a/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.Builder.cs b/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.Builder.cs
index 34c0e004a9..482215723c 100644
--- a/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.Builder.cs
+++ b/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray_1.Builder.cs
@@ -127,6 +127,8 @@ namespace System.Collections.Immutable
}
}
+ private static void ThrowIndexOutOfRangeException() => throw new IndexOutOfRangeException();
+
/// <summary>
/// Gets or sets the element at the specified index.
/// </summary>
@@ -140,7 +142,7 @@ namespace System.Collections.Immutable
{
if (index >= this.Count)
{
- throw new IndexOutOfRangeException();
+ ThrowIndexOutOfRangeException();
}
return _elements[index];
@@ -150,7 +152,7 @@ namespace System.Collections.Immutable
{
if (index >= this.Count)
{
- throw new IndexOutOfRangeException();
+ ThrowIndexOutOfRangeException();
}
_elements[index] = value;
@@ -169,7 +171,7 @@ namespace System.Collections.Immutable
{
if (index >= this.Count)
{
- throw new IndexOutOfRangeException();
+ ThrowIndexOutOfRangeException();
}
return ref this._elements[index];
@@ -247,8 +249,10 @@ namespace System.Collections.Immutable
/// <param name="item">The object to add to the <see cref="ICollection{T}"/>.</param>
public void Add(T item)
{
- this.EnsureCapacity(this.Count + 1);
- _elements[_count++] = item;
+ int newCount = _count + 1;
+ this.EnsureCapacity(newCount);
+ _elements[_count] = item;
+ _count = newCount;
}
/// <summary>
diff --git a/src/System.Collections.Immutable/src/System/Linq/ImmutableArrayExtensions.cs b/src/System.Collections.Immutable/src/System/Linq/ImmutableArrayExtensions.cs
index 4d7e56ab27..c141463d0b 100644
--- a/src/System.Collections.Immutable/src/System/Linq/ImmutableArrayExtensions.cs
+++ b/src/System.Collections.Immutable/src/System/Linq/ImmutableArrayExtensions.cs
@@ -608,7 +608,7 @@ namespace System.Linq
{
Requires.NotNull(keySelector, nameof(keySelector));
- var result = new Dictionary<TKey, T>(comparer);
+ var result = new Dictionary<TKey, T>(immutableArray.Length, comparer);
foreach (var v in immutableArray)
{
result.Add(keySelector(v), v);
diff --git a/src/System.Collections.Specialized/src/MatchingRefApiCompatBaseline.txt b/src/System.Collections.Specialized/src/MatchingRefApiCompatBaseline.txt
new file mode 100644
index 0000000000..98aeadefc3
--- /dev/null
+++ b/src/System.Collections.Specialized/src/MatchingRefApiCompatBaseline.txt
@@ -0,0 +1,2 @@
+# Type exposed publicly in implementation only for serialization purposes
+TypesMustExist : Type 'System.Collections.Specialized.ListDictionary.DictionaryNode' does not exist in the implementation but it does exist in the contract.
diff --git a/src/System.Collections/ref/System.Collections.cs b/src/System.Collections/ref/System.Collections.cs
index e8d4934236..5fad22d437 100644
--- a/src/System.Collections/ref/System.Collections.cs
+++ b/src/System.Collections/ref/System.Collections.cs
@@ -90,11 +90,14 @@ namespace System.Collections.Generic
public void Clear() { }
public bool ContainsKey(TKey key) { throw null; }
public bool ContainsValue(TValue value) { throw null; }
+ public int EnsureCapacity(int capacity) { throw null; }
public System.Collections.Generic.Dictionary<TKey, TValue>.Enumerator GetEnumerator() { throw null; }
public virtual void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }
public virtual void OnDeserialization(object sender) { }
public bool Remove(TKey key) { throw null; }
public bool Remove(TKey key, out TValue value) { throw null; }
+ public void TrimExcess(int capacity) { }
+ public void TrimExcess() { }
public bool TryAdd(TKey key, TValue value) { throw null; }
void System.Collections.Generic.ICollection<System.Collections.Generic.KeyValuePair<TKey, TValue>>.Add(System.Collections.Generic.KeyValuePair<TKey, TValue> keyValuePair) { }
bool System.Collections.Generic.ICollection<System.Collections.Generic.KeyValuePair<TKey, TValue>>.Contains(System.Collections.Generic.KeyValuePair<TKey, TValue> keyValuePair) { throw null; }
@@ -201,6 +204,7 @@ namespace System.Collections.Generic
public void CopyTo(T[] array, int arrayIndex) { }
public void CopyTo(T[] array, int arrayIndex, int count) { }
public static IEqualityComparer<HashSet<T>> CreateSetComparer() { throw null; }
+ public int EnsureCapacity(int capacity) { throw null; }
public void ExceptWith(System.Collections.Generic.IEnumerable<T> other) { }
public System.Collections.Generic.HashSet<T>.Enumerator GetEnumerator() { throw null; }
public virtual void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }
diff --git a/src/System.Collections/src/Resources/Strings.resx b/src/System.Collections/src/Resources/Strings.resx
index e25845e8fe..8f035d63c2 100644
--- a/src/System.Collections/src/Resources/Strings.resx
+++ b/src/System.Collections/src/Resources/Strings.resx
@@ -79,6 +79,9 @@
<data name="Argument_AddingDuplicate" xml:space="preserve">
<value>An item with the same key has already been added. Key: {0}</value>
</data>
+ <data name="InvalidOperation_ConcurrentOperationsNotSupported" xml:space="preserve">
+ <value>Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's state is no longer correct.</value>
+ </data>
<data name="InvalidOperation_EmptyQueue" xml:space="preserve">
<value>Queue empty.</value>
</data>
diff --git a/src/System.Collections/src/System.Collections.csproj b/src/System.Collections/src/System.Collections.csproj
index 3bec193e50..498b244520 100644
--- a/src/System.Collections/src/System.Collections.csproj
+++ b/src/System.Collections/src/System.Collections.csproj
@@ -7,7 +7,6 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<IsPartialFacadeAssembly>true</IsPartialFacadeAssembly>
</PropertyGroup>
- <!-- Default configurations to help VS understand the options -->
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
@@ -16,6 +15,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uapaot-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uapaot-Windows_NT-Release|AnyCPU'" />
+ <!-- Default configurations to help VS understand the options -->
<ItemGroup>
<ProjectReference Include="..\..\System.Runtime\src\System.Runtime.csproj" />
<ProjectReference Include="..\..\System.Diagnostics.Debug\src\System.Diagnostics.Debug.csproj" />
diff --git a/src/System.Collections/src/System/Collections/Generic/HashSet.cs b/src/System.Collections/src/System/Collections/Generic/HashSet.cs
index 2e8c4a44f4..a78da2f3bb 100644
--- a/src/System.Collections/src/System/Collections/Generic/HashSet.cs
+++ b/src/System.Collections/src/System/Collections/Generic/HashSet.cs
@@ -259,14 +259,23 @@ namespace System.Collections.Generic
{
if (_buckets != null)
{
+ int collisionCount = 0;
int hashCode = InternalGetHashCode(item);
+ Slot[] slots = _slots;
// see note at "HashSet" level describing why "- 1" appears in for loop
- for (int i = _buckets[hashCode % _buckets.Length] - 1; i >= 0; i = _slots[i].next)
+ for (int i = _buckets[hashCode % _buckets.Length] - 1; i >= 0; i = slots[i].next)
{
- if (_slots[i].hashCode == hashCode && _comparer.Equals(_slots[i].value, item))
+ if (slots[i].hashCode == hashCode && _comparer.Equals(slots[i].value, item))
{
return true;
}
+
+ if (collisionCount >= slots.Length)
+ {
+ // The chain of entries forms a loop, which means a concurrent update has happened.
+ throw new InvalidOperationException(SR.InvalidOperation_ConcurrentOperationsNotSupported);
+ }
+ collisionCount++;
}
}
// either _buckets is null or wasn't found
@@ -295,26 +304,28 @@ namespace System.Collections.Generic
int hashCode = InternalGetHashCode(item);
int bucket = hashCode % _buckets.Length;
int last = -1;
- for (int i = _buckets[bucket] - 1; i >= 0; last = i, i = _slots[i].next)
+ int collisionCount = 0;
+ Slot[] slots = _slots;
+ for (int i = _buckets[bucket] - 1; i >= 0; last = i, i = slots[i].next)
{
- if (_slots[i].hashCode == hashCode && _comparer.Equals(_slots[i].value, item))
+ if (slots[i].hashCode == hashCode && _comparer.Equals(slots[i].value, item))
{
if (last < 0)
{
// first iteration; update buckets
- _buckets[bucket] = _slots[i].next + 1;
+ _buckets[bucket] = slots[i].next + 1;
}
else
{
// subsequent iterations; update 'next' pointers
- _slots[last].next = _slots[i].next;
+ slots[last].next = slots[i].next;
}
- _slots[i].hashCode = -1;
+ slots[i].hashCode = -1;
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
{
- _slots[i].value = default(T);
+ slots[i].value = default(T);
}
- _slots[i].next = _freeList;
+ slots[i].next = _freeList;
_count--;
_version++;
@@ -329,6 +340,13 @@ namespace System.Collections.Generic
}
return true;
}
+
+ if (collisionCount >= slots.Length)
+ {
+ // The chain of entries forms a loop, which means a concurrent update has happened.
+ throw new InvalidOperationException(SR.InvalidOperation_ConcurrentOperationsNotSupported);
+ }
+ collisionCount++;
}
}
// either _buckets is null or wasn't found
@@ -1031,6 +1049,24 @@ namespace System.Collections.Generic
}
/// <summary>
+ /// Ensures that the hash set can hold up to 'capacity' entries without any further expansion of its backing storage.
+ /// </summary>
+ public int EnsureCapacity(int capacity)
+ {
+ if (capacity < 0)
+ throw new ArgumentOutOfRangeException(nameof(capacity));
+ int currentCapacity = _slots == null ? 0 : _slots.Length;
+ if (currentCapacity >= capacity)
+ return currentCapacity;
+ if (_buckets == null)
+ return Initialize(capacity);
+
+ int newSize = HashHelpers.GetPrime(capacity);
+ SetCapacity(newSize);
+ return newSize;
+ }
+
+ /// <summary>
/// Sets the capacity of this list to the size of the list (rounded up to nearest prime),
/// unless count is 0, in which case we release references.
///
@@ -1107,7 +1143,7 @@ namespace System.Collections.Generic
/// greater than or equal to capacity.
/// </summary>
/// <param name="capacity"></param>
- private void Initialize(int capacity)
+ private int Initialize(int capacity)
{
Debug.Assert(_buckets == null, "Initialize was called but _buckets was non-null");
@@ -1115,6 +1151,7 @@ namespace System.Collections.Generic
_buckets = new int[size];
_slots = new Slot[size];
+ return size;
}
/// <summary>
@@ -1145,6 +1182,7 @@ namespace System.Collections.Generic
/// </summary>
private void SetCapacity(int newSize)
{
+ Debug.Assert(HashHelpers.IsPrime(newSize), "New size is not prime!");
Debug.Assert(_buckets != null, "SetCapacity called on a set with no elements");
Slot[] newSlots = new Slot[newSize];
@@ -1179,35 +1217,44 @@ namespace System.Collections.Generic
int hashCode = InternalGetHashCode(value);
int bucket = hashCode % _buckets.Length;
-
- for (int i = _buckets[bucket] - 1; i >= 0; i = _slots[i].next)
+ int collisionCount = 0;
+ Slot[] slots = _slots;
+ for (int i = _buckets[bucket] - 1; i >= 0; i = slots[i].next)
{
- if (_slots[i].hashCode == hashCode && _comparer.Equals(_slots[i].value, value))
+ if (slots[i].hashCode == hashCode && _comparer.Equals(slots[i].value, value))
{
return false;
}
+
+ if (collisionCount >= slots.Length)
+ {
+ // The chain of entries forms a loop, which means a concurrent update has happened.
+ throw new InvalidOperationException(SR.InvalidOperation_ConcurrentOperationsNotSupported);
+ }
+ collisionCount++;
}
int index;
if (_freeList >= 0)
{
index = _freeList;
- _freeList = _slots[index].next;
+ _freeList = slots[index].next;
}
else
{
- if (_lastIndex == _slots.Length)
+ if (_lastIndex == slots.Length)
{
IncreaseCapacity();
// this will change during resize
+ slots = _slots;
bucket = hashCode % _buckets.Length;
}
index = _lastIndex;
_lastIndex++;
}
- _slots[index].hashCode = hashCode;
- _slots[index].value = value;
- _slots[index].next = _buckets[bucket] - 1;
+ slots[index].hashCode = hashCode;
+ slots[index].value = value;
+ slots[index].next = _buckets[bucket] - 1;
_buckets[bucket] = index + 1;
_count++;
_version++;
@@ -1359,13 +1406,22 @@ namespace System.Collections.Generic
{
Debug.Assert(_buckets != null, "_buckets was null; callers should check first");
+ int collisionCount = 0;
int hashCode = InternalGetHashCode(item);
- for (int i = _buckets[hashCode % _buckets.Length] - 1; i >= 0; i = _slots[i].next)
+ Slot[] slots = _slots;
+ for (int i = _buckets[hashCode % _buckets.Length] - 1; i >= 0; i = slots[i].next)
{
- if ((_slots[i].hashCode) == hashCode && _comparer.Equals(_slots[i].value, item))
+ if ((slots[i].hashCode) == hashCode && _comparer.Equals(slots[i].value, item))
{
return i;
}
+
+ if (collisionCount >= slots.Length)
+ {
+ // The chain of entries forms a loop, which means a concurrent update has happened.
+ throw new InvalidOperationException(SR.InvalidOperation_ConcurrentOperationsNotSupported);
+ }
+ collisionCount++;
}
// wasn't found
return -1;
@@ -1483,34 +1539,44 @@ namespace System.Collections.Generic
int hashCode = InternalGetHashCode(value);
int bucket = hashCode % _buckets.Length;
- for (int i = _buckets[bucket] - 1; i >= 0; i = _slots[i].next)
+ int collisionCount = 0;
+ Slot[] slots = _slots;
+ for (int i = _buckets[bucket] - 1; i >= 0; i = slots[i].next)
{
- if (_slots[i].hashCode == hashCode && _comparer.Equals(_slots[i].value, value))
+ if (slots[i].hashCode == hashCode && _comparer.Equals(slots[i].value, value))
{
location = i;
return false; //already present
}
+
+ if (collisionCount >= slots.Length)
+ {
+ // The chain of entries forms a loop, which means a concurrent update has happened.
+ throw new InvalidOperationException(SR.InvalidOperation_ConcurrentOperationsNotSupported);
+ }
+ collisionCount++;
}
int index;
if (_freeList >= 0)
{
index = _freeList;
- _freeList = _slots[index].next;
+ _freeList = slots[index].next;
}
else
{
- if (_lastIndex == _slots.Length)
+ if (_lastIndex == slots.Length)
{
IncreaseCapacity();
// this will change during resize
+ slots = _slots;
bucket = hashCode % _buckets.Length;
}
index = _lastIndex;
_lastIndex++;
}
- _slots[index].hashCode = hashCode;
- _slots[index].value = value;
- _slots[index].next = _buckets[bucket] - 1;
+ slots[index].hashCode = hashCode;
+ slots[index].value = value;
+ slots[index].next = _buckets[bucket] - 1;
_buckets[bucket] = index + 1;
_count++;
_version++;
diff --git a/src/System.Collections/src/System/Collections/Generic/Queue.cs b/src/System.Collections/src/System/Collections/Generic/Queue.cs
index 547df798df..24735d8e53 100644
--- a/src/System.Collections/src/System/Collections/Generic/Queue.cs
+++ b/src/System.Collections/src/System/Collections/Generic/Queue.cs
@@ -236,15 +236,18 @@ namespace System.Collections.Generic
// InvalidOperationException.
public T Dequeue()
{
+ int head = _head;
+ T[] array = _array;
+
if (_size == 0)
{
ThrowForEmptyQueue();
}
- T removed = _array[_head];
+ T removed = array[head];
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
{
- _array[_head] = default(T);
+ array[head] = default;
}
MoveNext(ref _head);
_size--;
@@ -254,16 +257,19 @@ namespace System.Collections.Generic
public bool TryDequeue(out T result)
{
+ int head = _head;
+ T[] array = _array;
+
if (_size == 0)
{
- result = default(T);
+ result = default;
return false;
}
- result = _array[_head];
+ result = array[head];
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
{
- _array[_head] = default(T);
+ array[head] = default;
}
MoveNext(ref _head);
_size--;
@@ -369,10 +375,15 @@ namespace System.Collections.Generic
// Increments the index wrapping it if necessary.
private void MoveNext(ref int index)
{
- // It is tempting to use the remainder operator here but it is actually much slower
- // than a simple comparison and a rarely taken branch.
+ // It is tempting to use the remainder operator here but it is actually much slower
+ // than a simple comparison and a rarely taken branch.
+ // JIT produces better code than with ternary operator ?:
int tmp = index + 1;
- index = (tmp == _array.Length) ? 0 : tmp;
+ if (tmp == _array.Length)
+ {
+ tmp = 0;
+ }
+ index = tmp;
}
private void ThrowForEmptyQueue()
diff --git a/src/System.Collections/src/System/Collections/Generic/Stack.cs b/src/System.Collections/src/System/Collections/Generic/Stack.cs
index 38c5bbb07b..48b33a18e8 100644
--- a/src/System.Collections/src/System/Collections/Generic/Stack.cs
+++ b/src/System.Collections/src/System/Collections/Generic/Stack.cs
@@ -204,22 +204,28 @@ namespace System.Collections.Generic
// is empty, Peek throws an InvalidOperationException.
public T Peek()
{
- if (_size == 0)
+ int size = _size - 1;
+ T[] array = _array;
+
+ if ((uint)size >= (uint)array.Length)
{
ThrowForEmptyStack();
}
- return _array[_size - 1];
+ return array[size];
}
public bool TryPeek(out T result)
{
- if (_size == 0)
+ int size = _size - 1;
+ T[] array = _array;
+
+ if ((uint)size >= (uint)array.Length)
{
- result = default(T);
+ result = default;
return false;
}
- result = _array[_size - 1];
+ result = array[size];
return true;
}
@@ -227,33 +233,44 @@ namespace System.Collections.Generic
// throws an InvalidOperationException.
public T Pop()
{
- if (_size == 0)
+ int size = _size - 1;
+ T[] array = _array;
+
+ // if (_size == 0) is equivalent to if (size == -1), and this case
+ // is covered with (uint)size, thus allowing bounds check elimination
+ // https://github.com/dotnet/coreclr/pull/9773
+ if ((uint)size >= (uint)array.Length)
{
ThrowForEmptyStack();
}
_version++;
- T item = _array[--_size];
+ _size = size;
+ T item = array[size];
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
{
- _array[_size] = default(T); // Free memory quicker.
+ array[size] = default; // Free memory quicker.
}
return item;
}
public bool TryPop(out T result)
{
- if (_size == 0)
+ int size = _size - 1;
+ T[] array = _array;
+
+ if ((uint)size >= (uint)array.Length)
{
- result = default(T);
+ result = default;
return false;
}
_version++;
- result = _array[--_size];
+ _size = size;
+ result = array[size];
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
{
- _array[_size] = default(T); // Free memory quicker.
+ array[size] = default; // Free memory quicker.
}
return true;
}
@@ -261,12 +278,29 @@ namespace System.Collections.Generic
// Pushes an item to the top of the stack.
public void Push(T item)
{
- if (_size == _array.Length)
+ int size = _size;
+ T[] array = _array;
+
+ if ((uint)size < (uint)array.Length)
{
- Array.Resize(ref _array, (_array.Length == 0) ? DefaultCapacity : 2 * _array.Length);
+ array[size] = item;
+ _version++;
+ _size = size + 1;
}
- _array[_size++] = item;
+ else
+ {
+ PushWithResize(item);
+ }
+ }
+
+ // Non-inline from Stack.Push to improve its code quality as uncommon path
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private void PushWithResize(T item)
+ {
+ Array.Resize(ref _array, (_array.Length == 0) ? DefaultCapacity : 2 * _array.Length);
+ _array[_size] = item;
_version++;
+ _size++;
}
// Copies the Stack to an array, in the same order Pop would return the items.
diff --git a/src/System.Collections/tests/Generic/Dictionary/Dictionary.Generic.Tests.cs b/src/System.Collections/tests/Generic/Dictionary/Dictionary.Generic.Tests.cs
index 3298856b6c..eb8e70f83d 100644
--- a/src/System.Collections/tests/Generic/Dictionary/Dictionary.Generic.Tests.cs
+++ b/src/System.Collections/tests/Generic/Dictionary/Dictionary.Generic.Tests.cs
@@ -43,8 +43,7 @@ namespace System.Collections.Tests
IDictionary<TKey, TValue> source = GenericIDictionaryFactory(count);
Dictionary<TKey, TValue> copied = new Dictionary<TKey, TValue>(source, comparer);
Assert.Equal(source, copied);
- if (typeof(TKey) != typeof(string) || comparer != EqualityComparer<TKey>.Default) // Dictionary special-cases the default comparer when TKEy=string
- Assert.Equal(comparer, copied.Comparer);
+ Assert.Equal(comparer, copied.Comparer);
}
[Theory]
@@ -55,8 +54,7 @@ namespace System.Collections.Tests
IDictionary<TKey, TValue> source = GenericIDictionaryFactory(count);
Dictionary<TKey, TValue> copied = new Dictionary<TKey, TValue>(source, comparer);
Assert.Equal(source, copied);
- if (typeof(TKey) != typeof(string) || comparer != EqualityComparer<TKey>.Default) // Dictionary special-cases the default comparer when TKEy=string
- Assert.Equal(comparer, copied.Comparer);
+ Assert.Equal(comparer, copied.Comparer);
}
[Theory]
@@ -74,9 +72,7 @@ namespace System.Collections.Tests
IEqualityComparer<TKey> comparer = GetKeyIEqualityComparer();
Dictionary<TKey, TValue> dictionary = new Dictionary<TKey, TValue>(count, comparer);
Assert.Equal(0, dictionary.Count);
- // Dictionary with TKey string when
- if (typeof(TKey) != typeof(string) || comparer != EqualityComparer<TKey>.Default) // Dictionary special-cases the default comparer when TKEy=string
- Assert.Equal(comparer, dictionary.Comparer);
+ Assert.Equal(comparer, dictionary.Comparer);
}
#endregion
diff --git a/src/System.Collections/tests/Generic/Dictionary/Dictionary.Generic.Tests.netcoreapp.cs b/src/System.Collections/tests/Generic/Dictionary/Dictionary.Generic.Tests.netcoreapp.cs
index 991dc5b8ae..9a3b698228 100644
--- a/src/System.Collections/tests/Generic/Dictionary/Dictionary.Generic.Tests.netcoreapp.cs
+++ b/src/System.Collections/tests/Generic/Dictionary/Dictionary.Generic.Tests.netcoreapp.cs
@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Linq;
+using Common.System;
using Xunit;
namespace System.Collections.Tests
@@ -84,5 +85,338 @@ namespace System.Collections.Tests
}
#endregion
+
+ #region EnsureCapacity
+
+ [Theory]
+ [MemberData(nameof(ValidCollectionSizes))]
+ public void EnsureCapacity_Generic_RequestingLargerCapacity_DoesNotInvalidateEnumeration(int count)
+ {
+ var dictionary = (Dictionary<TKey, TValue>)(GenericIDictionaryFactory(count));
+ var capacity = dictionary.EnsureCapacity(0);
+ IEnumerator keysEnum = dictionary.Keys.GetEnumerator();
+ IEnumerator valuesEnum = dictionary.Values.GetEnumerator();
+ IEnumerator keysListEnum = new List<TKey>(dictionary.Keys).GetEnumerator();
+ IEnumerator valuesListEnum = new List<TValue>(dictionary.Values).GetEnumerator();
+
+ dictionary.EnsureCapacity(capacity + 1); // Verify EnsureCapacity does not invalidate enumeration
+
+ while(keysEnum.MoveNext())
+ {
+ valuesEnum.MoveNext();
+ keysListEnum.MoveNext();
+ valuesListEnum.MoveNext();
+ Assert.Equal(keysListEnum.Current, keysEnum.Current);
+ Assert.Equal(valuesListEnum.Current, valuesEnum.Current);
+ }
+ }
+
+ [Fact]
+ public void EnsureCapacity_Generic_NegativeCapacityRequested_Throws()
+ {
+ var dictionary = new Dictionary<TKey, TValue>();
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("capacity", () => dictionary.EnsureCapacity(-1));
+ }
+
+ [Fact]
+ public void EnsureCapacity_Generic_DictionaryNotInitialized_RequestedZero_ReturnsZero()
+ {
+ var dictionary = new Dictionary<TKey, TValue>();
+ Assert.Equal(0, dictionary.EnsureCapacity(0));
+ }
+
+ [Theory]
+ [InlineData(1)]
+ [InlineData(2)]
+ [InlineData(3)]
+ [InlineData(4)]
+ public void EnsureCapacity_Generic_DictionaryNotInitialized_RequestedNonZero_CapacityIsSetToAtLeastTheRequested(int requestedCapacity)
+ {
+ var dictionary = new Dictionary<TKey, TValue>();
+ Assert.InRange(dictionary.EnsureCapacity(requestedCapacity), requestedCapacity, int.MaxValue);
+ }
+
+ [Theory]
+ [InlineData(3)]
+ [InlineData(7)]
+ public void EnsureCapacity_Generic_RequestedCapacitySmallerThanCurrent_CapacityUnchanged(int currentCapacity)
+ {
+ Dictionary<TKey, TValue> dictionary;
+
+ // assert capacity remains the same when ensuring a capacity smaller or equal than existing
+ for (int i = 0; i <= currentCapacity; i++)
+ {
+ dictionary = new Dictionary<TKey, TValue>(currentCapacity);
+ Assert.Equal(currentCapacity, dictionary.EnsureCapacity(i));
+ }
+ }
+
+ [Theory]
+ [InlineData(7)]
+ public void EnsureCapacity_Generic_ExistingCapacityRequested_SameValueReturned(int capacity)
+ {
+ var dictionary = new Dictionary<TKey, TValue>(capacity);
+ Assert.Equal(capacity, dictionary.EnsureCapacity(capacity));
+
+ dictionary = (Dictionary<TKey, TValue>)GenericIDictionaryFactory(capacity);
+ Assert.Equal(capacity, dictionary.EnsureCapacity(capacity));
+ }
+
+ [Theory]
+ [InlineData(0)]
+ [InlineData(1)]
+ [InlineData(2)]
+ [InlineData(3)]
+ [InlineData(4)]
+ public void EnsureCapacity_Generic_EnsureCapacityCalledTwice_ReturnsSameValue(int count)
+ {
+ var dictionary = (Dictionary<TKey, TValue>)GenericIDictionaryFactory(count);
+ int capacity = dictionary.EnsureCapacity(0);
+ Assert.Equal(capacity, dictionary.EnsureCapacity(0));
+
+ dictionary = (Dictionary<TKey, TValue>)GenericIDictionaryFactory(count);
+ capacity = dictionary.EnsureCapacity(count);
+ Assert.Equal(capacity, dictionary.EnsureCapacity(count));
+
+ dictionary = (Dictionary<TKey, TValue>)GenericIDictionaryFactory(count);
+ capacity = dictionary.EnsureCapacity(count + 1);
+ Assert.Equal(capacity, dictionary.EnsureCapacity(count + 1));
+ }
+
+ [Theory]
+ [InlineData(1)]
+ [InlineData(5)]
+ [InlineData(7)]
+ public void EnsureCapacity_Generic_DictionaryNotEmpty_RequestedSmallerThanCount_ReturnsAtLeastSizeOfCount(int count)
+ {
+ var dictionary = (Dictionary<TKey, TValue>)GenericIDictionaryFactory(count);
+ Assert.InRange(dictionary.EnsureCapacity(count - 1), count, int.MaxValue);
+ }
+
+ [Theory]
+ [InlineData(7)]
+ [InlineData(20)]
+ public void EnsureCapacity_Generic_DictionaryNotEmpty_SetsToAtLeastTheRequested(int count)
+ {
+ var dictionary = (Dictionary<TKey, TValue>)GenericIDictionaryFactory(count);
+
+ // get current capacity
+ int currentCapacity = dictionary.EnsureCapacity(0);
+
+ // assert we can update to a larger capacity
+ int newCapacity = dictionary.EnsureCapacity(currentCapacity * 2);
+ Assert.InRange(newCapacity, currentCapacity * 2, int.MaxValue);
+ }
+
+ [Fact]
+ public void EnsureCapacity_Generic_CapacityIsSetToPrimeNumberLargerOrEqualToRequested()
+ {
+ var dictionary = new Dictionary<TKey, TValue>();
+ Assert.Equal(17, dictionary.EnsureCapacity(17));
+
+ dictionary = new Dictionary<TKey, TValue>();
+ Assert.Equal(17, dictionary.EnsureCapacity(15));
+
+ dictionary = new Dictionary<TKey, TValue>();
+ Assert.Equal(17, dictionary.EnsureCapacity(13));
+ }
+
+ #endregion
+
+ #region TrimExcess
+
+ [Fact]
+ public void TrimExcess_Generic_NegativeCapacity_Throw()
+ {
+ var dictionary = new Dictionary<TKey, TValue>();
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("capacity", () => dictionary.TrimExcess(-1));
+ }
+
+ [Theory]
+ [InlineData(20)]
+ [InlineData(23)]
+ public void TrimExcess_Generic_CapacitySmallerThanCount_Throws(int suggestedCapacity)
+ {
+ var dictionary = new Dictionary<TKey, TValue>();
+ dictionary.Add(GetNewKey(dictionary), CreateTValue(0));
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("capacity", () => dictionary.TrimExcess(0));
+
+ dictionary = new Dictionary<TKey, TValue>(suggestedCapacity);
+ dictionary.Add(GetNewKey(dictionary), CreateTValue(0));
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("capacity", () => dictionary.TrimExcess(0));
+ }
+
+ [Fact]
+ public void TrimExcess_Generic_LargeInitialCapacity_TrimReducesSize()
+ {
+ var dictionary = new Dictionary<TKey, TValue>(20);
+ dictionary.TrimExcess(7);
+ Assert.Equal(7, dictionary.EnsureCapacity(0));
+ }
+
+ [Theory]
+ [InlineData(20)]
+ [InlineData(23)]
+ public void TrimExcess_Generic_TrimToLargerThanExistingCapacity_DoesNothing(int suggestedCapacity)
+ {
+ var dictionary = new Dictionary<TKey, TValue>();
+ int capacity = dictionary.EnsureCapacity(0);
+ dictionary.TrimExcess(suggestedCapacity);
+ Assert.Equal(capacity, dictionary.EnsureCapacity(0));
+
+ dictionary = new Dictionary<TKey, TValue>(suggestedCapacity/2);
+ capacity = dictionary.EnsureCapacity(0);
+ dictionary.TrimExcess(suggestedCapacity);
+ Assert.Equal(capacity, dictionary.EnsureCapacity(0));
+ }
+
+ [Fact]
+ public void TrimExcess_Generic_DictionaryNotInitialized_CapacityRemainsAsMinPossible()
+ {
+ var dictionary = new Dictionary<TKey, TValue>();
+ Assert.Equal(0, dictionary.EnsureCapacity(0));
+ dictionary.TrimExcess();
+ Assert.Equal(0, dictionary.EnsureCapacity(0));
+ }
+
+ [Theory]
+ [InlineData(1)]
+ [InlineData(85)]
+ [InlineData(89)]
+ public void TrimExcess_Generic_ClearThenTrimNonEmptyDictionary_SetsCapacityTo3(int count)
+ {
+ Dictionary<TKey, TValue> dictionary = (Dictionary<TKey, TValue>)GenericIDictionaryFactory(count);
+ Assert.Equal(count, dictionary.Count);
+ // The smallest possible capacity size after clearing a dictionary is 3
+ dictionary.Clear();
+ dictionary.TrimExcess();
+ Assert.Equal(3, dictionary.EnsureCapacity(0));
+ }
+
+ [Theory]
+ [InlineData(85)]
+ [InlineData(89)]
+ public void TrimExcess_NoArguments_TrimsToAtLeastCount(int count)
+ {
+ var dictionary = new Dictionary<int, int>(20);
+ for (int i = 0; i < count; i++)
+ {
+ dictionary.Add(i, 0);
+ }
+ dictionary.TrimExcess();
+ Assert.InRange(dictionary.EnsureCapacity(0), count, int.MaxValue);
+ }
+
+ [Theory]
+ [InlineData(85)]
+ [InlineData(89)]
+ public void TrimExcess_WithArguments_OnDictionaryWithManyElementsRemoved_TrimsToAtLeastRequested(int finalCount)
+ {
+ const int InitToFinalRatio = 10;
+ int initialCount = InitToFinalRatio * finalCount;
+ var dictionary = new Dictionary<int, int>(initialCount);
+ Assert.InRange(dictionary.EnsureCapacity(0), initialCount, int.MaxValue);
+ for (int i = 0; i < initialCount; i++)
+ {
+ dictionary.Add(i, 0);
+ }
+ for (int i = 0; i < initialCount - finalCount; i++)
+ {
+ dictionary.Remove(i);
+ }
+ for (int i = InitToFinalRatio; i > 0; i--)
+ {
+ dictionary.TrimExcess(i * finalCount);
+ Assert.InRange(dictionary.EnsureCapacity(0), i * finalCount, int.MaxValue);
+ }
+ }
+
+ [Theory]
+ [InlineData(1000, 900, 5000, 85, 89)]
+ [InlineData(1000, 400, 5000, 85, 89)]
+ [InlineData(1000, 900, 500, 85, 89)]
+ [InlineData(1000, 400, 500, 85, 89)]
+ [InlineData(1000, 400, 500, 1, 3)]
+ public void TrimExcess_NoArgument_TrimAfterEachBulkAddOrRemove_TrimsToAtLeastCount(int initialCount, int numRemove, int numAdd, int newCount, int newCapacity)
+ {
+ Random random = new Random(32);
+ var dictionary = new Dictionary<int, int>();
+ dictionary.TrimExcess();
+ Assert.InRange(dictionary.EnsureCapacity(0), dictionary.Count, int.MaxValue);
+
+ var initialKeys = new int[initialCount];
+ for (int i = 0; i < initialCount; i++)
+ {
+ initialKeys[i] = i;
+ }
+ random.Shuffle(initialKeys);
+ foreach (var key in initialKeys)
+ {
+ dictionary.Add(key, 0);
+ }
+ dictionary.TrimExcess();
+ Assert.InRange(dictionary.EnsureCapacity(0), dictionary.Count, int.MaxValue);
+
+ random.Shuffle(initialKeys);
+ for (int i = 0; i < numRemove; i++)
+ {
+ dictionary.Remove(initialKeys[i]);
+ }
+ dictionary.TrimExcess();
+ Assert.InRange(dictionary.EnsureCapacity(0), dictionary.Count, int.MaxValue);
+
+ var moreKeys = new int[numAdd];
+ for (int i = 0; i < numAdd; i++)
+ {
+ moreKeys[i] = i + initialCount;
+ }
+ random.Shuffle(moreKeys);
+ foreach (var key in moreKeys)
+ {
+ dictionary.Add(key, 0);
+ }
+ int currentCount = dictionary.Count;
+ dictionary.TrimExcess();
+ Assert.InRange(dictionary.EnsureCapacity(0), currentCount, int.MaxValue);
+
+ int[] existingKeys = new int[currentCount];
+ Array.Copy(initialKeys, numRemove, existingKeys, 0, initialCount - numRemove);
+ Array.Copy(moreKeys, 0, existingKeys, initialCount - numRemove, numAdd);
+ random.Shuffle(existingKeys);
+ for (int i = 0; i < currentCount - newCount; i++)
+ {
+ dictionary.Remove(existingKeys[i]);
+ }
+ dictionary.TrimExcess();
+ int finalCapacity = dictionary.EnsureCapacity(0);
+ Assert.InRange(finalCapacity, newCount, initialCount);
+ Assert.Equal(newCapacity, finalCapacity);
+ }
+
+ [Fact]
+ public void TrimExcess_DictionaryHasElementsChainedWithSameHashcode_Success()
+ {
+ var dictionary = new Dictionary<string, int>(7);
+ for (int i = 0; i < 4; i++)
+ {
+ dictionary.Add(i.ToString(), 0);
+ }
+ var s_64bit = new string[] { "95e85f8e-67a3-4367-974f-dd24d8bb2ca2", "eb3d6fe9-de64-43a9-8f58-bddea727b1ca" };
+ var s_32bit = new string[] { "25b1f130-7517-48e3-96b0-9da44e8bfe0e", "ba5a3625-bc38-4bf1-a707-a3cfe2158bae" };
+ string[] chained = (Environment.Is64BitProcess ? s_64bit : s_32bit).ToArray();
+ dictionary.Add(chained[0], 0);
+ dictionary.Add(chained[1], 0);
+ for (int i = 0; i < 4; i++)
+ {
+ dictionary.Remove(i.ToString());
+ }
+ dictionary.TrimExcess(3);
+ Assert.Equal(2, dictionary.Count);
+ int val;
+ Assert.True(dictionary.TryGetValue(chained[0], out val));
+ Assert.True(dictionary.TryGetValue(chained[1], out val));
+ }
+
+ #endregion
}
}
diff --git a/src/System.Collections/tests/Generic/HashSet/HashSet.Generic.Tests.netcoreapp.cs b/src/System.Collections/tests/Generic/HashSet/HashSet.Generic.Tests.netcoreapp.cs
index 6d254360c1..2f9226db0b 100644
--- a/src/System.Collections/tests/Generic/HashSet/HashSet.Generic.Tests.netcoreapp.cs
+++ b/src/System.Collections/tests/Generic/HashSet/HashSet.Generic.Tests.netcoreapp.cs
@@ -31,6 +31,18 @@ namespace System.Collections.Tests
}
[Fact]
+ public void HashSet_Generic_Constructor_Capacity_ToNextPrimeNumber()
+ {
+ // Highest pre-computed number + 1.
+ const int Capacity = 7199370;
+ var set = new HashSet<T>(Capacity);
+
+ // Assert that the HashTable's capacity is set to the descendant prime number of the given one.
+ const int NextPrime = 7199371;
+ Assert.Equal(NextPrime, set.EnsureCapacity(0));
+ }
+
+ [Fact]
public void HashSet_Generic_Constructor_int_Negative_ThrowsArgumentOutOfRangeException()
{
AssertExtensions.Throws<ArgumentOutOfRangeException>("capacity", () => new HashSet<T>(-1));
@@ -127,5 +139,139 @@ namespace System.Collections.Tests
}
#endregion
+
+ #region EnsureCapacity
+
+ [Theory]
+ [MemberData(nameof(ValidCollectionSizes))]
+ public void EnsureCapacity_Generic_RequestingLargerCapacity_DoesNotInvalidateEnumeration(int setLength)
+ {
+ HashSet<T> set = (HashSet<T>)(GenericISetFactory(setLength));
+ var capacity = set.EnsureCapacity(0);
+ IEnumerator valuesEnum = set.GetEnumerator();
+ IEnumerator valuesListEnum = new List<T>(set).GetEnumerator();
+
+ set.EnsureCapacity(capacity + 1); // Verify EnsureCapacity does not invalidate enumeration
+
+ while (valuesEnum.MoveNext())
+ {
+ valuesListEnum.MoveNext();
+ Assert.Equal(valuesListEnum.Current, valuesEnum.Current);
+ }
+ }
+
+ [Fact]
+ public void EnsureCapacity_Generic_NegativeCapacityRequested_Throws()
+ {
+ var set = new HashSet<T>();
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("capacity", () => set.EnsureCapacity(-1));
+ }
+
+ [Fact]
+ public void EnsureCapacity_Generic_HashsetNotInitialized_RequestedZero_ReturnsZero()
+ {
+ var set = new HashSet<T>();
+ Assert.Equal(0, set.EnsureCapacity(0));
+ }
+
+ [Theory]
+ [InlineData(1)]
+ [InlineData(2)]
+ [InlineData(3)]
+ [InlineData(4)]
+ public void EnsureCapacity_Generic_HashsetNotInitialized_RequestedNonZero_CapacityIsSetToAtLeastTheRequested(int requestedCapacity)
+ {
+ var set = new HashSet<T>();
+ Assert.InRange(set.EnsureCapacity(requestedCapacity), requestedCapacity, int.MaxValue);
+ }
+
+ [Theory]
+ [InlineData(3)]
+ [InlineData(7)]
+ public void EnsureCapacity_Generic_RequestedCapacitySmallerThanCurrent_CapacityUnchanged(int currentCapacity)
+ {
+ HashSet<T> set;
+
+ // assert capacity remains the same when ensuring a capacity smaller or equal than existing
+ for (int i = 0; i <= currentCapacity; i++)
+ {
+ set = new HashSet<T>(currentCapacity);
+ Assert.Equal(currentCapacity, set.EnsureCapacity(i));
+ }
+ }
+
+ [Theory]
+ [InlineData(7)]
+ [InlineData(89)]
+ public void EnsureCapacity_Generic_ExistingCapacityRequested_SameValueReturned(int capacity)
+ {
+ var set = new HashSet<T>(capacity);
+ Assert.Equal(capacity, set.EnsureCapacity(capacity));
+
+ set = (HashSet<T>)GenericISetFactory(capacity);
+ Assert.Equal(capacity, set.EnsureCapacity(capacity));
+ }
+
+ [Theory]
+ [InlineData(0)]
+ [InlineData(1)]
+ [InlineData(2)]
+ [InlineData(3)]
+ [InlineData(4)]
+ public void EnsureCapacity_Generic_EnsureCapacityCalledTwice_ReturnsSameValue(int setLength)
+ {
+ HashSet<T> set = (HashSet<T>)GenericISetFactory(setLength);
+ int capacity = set.EnsureCapacity(0);
+ Assert.Equal(capacity, set.EnsureCapacity(0));
+
+ set = (HashSet<T>)GenericISetFactory(setLength);
+ capacity = set.EnsureCapacity(setLength);
+ Assert.Equal(capacity, set.EnsureCapacity(setLength));
+
+ set = (HashSet<T>)GenericISetFactory(setLength);
+ capacity = set.EnsureCapacity(setLength + 1);
+ Assert.Equal(capacity, set.EnsureCapacity(setLength + 1));
+ }
+
+ [Theory]
+ [InlineData(1)]
+ [InlineData(5)]
+ [InlineData(7)]
+ [InlineData(8)]
+ public void EnsureCapacity_Generic_HashsetNotEmpty_RequestedSmallerThanCount_ReturnsAtLeastSizeOfCount(int setLength)
+ {
+ HashSet<T> set = (HashSet<T>)GenericISetFactory(setLength);
+ Assert.InRange(set.EnsureCapacity(setLength - 1), setLength, int.MaxValue);
+ }
+
+ [Theory]
+ [InlineData(7)]
+ [InlineData(20)]
+ public void EnsureCapacity_Generic_HashsetNotEmpty_SetsToAtLeastTheRequested(int setLength)
+ {
+ HashSet<T> set = (HashSet<T>)GenericISetFactory(setLength);
+
+ // get current capacity
+ int currentCapacity = set.EnsureCapacity(0);
+
+ // assert we can update to a larger capacity
+ int newCapacity = set.EnsureCapacity(currentCapacity * 2);
+ Assert.InRange(newCapacity, currentCapacity * 2, int.MaxValue);
+ }
+
+ [Fact]
+ public void EnsureCapacity_Generic_CapacityIsSetToPrimeNumberLargerOrEqualToRequested()
+ {
+ var set = new HashSet<T>();
+ Assert.Equal(17, set.EnsureCapacity(17));
+
+ set = new HashSet<T>();
+ Assert.Equal(17, set.EnsureCapacity(15));
+
+ set = new HashSet<T>();
+ Assert.Equal(17, set.EnsureCapacity(13));
+ }
+
+ #endregion
}
}
diff --git a/src/System.Collections/tests/Generic/List/List.Generic.Tests.Misc.cs b/src/System.Collections/tests/Generic/List/List.Generic.Tests.Misc.cs
index 1b183d0583..cc18704768 100644
--- a/src/System.Collections/tests/Generic/List/List.Generic.Tests.Misc.cs
+++ b/src/System.Collections/tests/Generic/List/List.Generic.Tests.Misc.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
+using System.Linq;
using Xunit;
namespace System.Collections.Tests
@@ -14,6 +15,18 @@ namespace System.Collections.Tests
{
internal class Driver<T>
{
+ public Func<T[], IEnumerable<T>>[] CollectionGenerators { get; }
+
+ public Driver()
+ {
+ CollectionGenerators = new Func<T[], IEnumerable<T>>[]
+ {
+ ConstructTestList,
+ ConstructTestEnumerable,
+ ConstructLazyTestEnumerable,
+ };
+ }
+
#region Insert
public void BasicInsert(T[] items, T item, int index, int repeat)
@@ -103,7 +116,7 @@ namespace System.Collections.Tests
#region InsertRange
- public void InsertRangeICollection(T[] itemsX, T[] itemsY, int index, int repeat, Func<T[], IEnumerable<T>> constructIEnumerable)
+ public void InsertRangeIEnumerable(T[] itemsX, T[] itemsY, int index, int repeat, Func<T[], IEnumerable<T>> constructIEnumerable)
{
List<T> list = new List<T>(constructIEnumerable(itemsX));
@@ -159,37 +172,6 @@ namespace System.Collections.Tests
}
}
- public void InsertRangeList(T[] itemsX, T[] itemsY, int index, int repeat, Func<T[], IEnumerable<T>> constructIEnumerable)
- {
- List<T> list = new List<T>(constructIEnumerable(itemsX));
-
- for (int i = 0; i < repeat; i++)
- {
- list.InsertRange(index, new List<T>(constructIEnumerable(itemsY)));
- }
-
- foreach (T item in itemsY)
- {
- Assert.True(list.Contains(item)); //"Should contain the item."
- }
- Assert.Equal(list.Count, itemsX.Length + (itemsY.Length * repeat)); //"Should have the same result."
-
- for (int i = 0; i < index; i++)
- {
- Assert.Equal(list[i], itemsX[i]); //"Should have the same result."
- }
-
- for (int i = index; i < index + (itemsY.Length * repeat); i++)
- {
- Assert.Equal(list[i], itemsY[(i - index) % itemsY.Length]); //"Should have the same result."
- }
-
- for (int i = index + (itemsY.Length * repeat); i < list.Count; i++)
- {
- Assert.Equal(list[i], itemsX[i - (itemsY.Length * repeat)]); //"Should have the same result."
- }
- }
-
public void InsertRangeValidations(T[] items, Func<T[], IEnumerable<T>> constructIEnumerable)
{
List<T> list = new List<T>(constructIEnumerable(items));
@@ -202,11 +184,22 @@ namespace System.Collections.Tests
Assert.Throws<ArgumentNullException>(() => list.InsertRange(0, null)); //"ArgumentNullException expected."
}
- public IEnumerable<T> ConstructTestCollection(T[] items)
+ public IEnumerable<T> ConstructTestEnumerable(T[] items)
{
return items;
}
+ public IEnumerable<T> ConstructLazyTestEnumerable(T[] items)
+ {
+ return ConstructTestEnumerable(items)
+ .Select(item => item);
+ }
+
+ public IEnumerable<T> ConstructTestList(T[] items)
+ {
+ return items.ToList();
+ }
+
#endregion
#region GetRange
@@ -795,13 +788,15 @@ namespace System.Collections.Tests
intArr2[i] = i + 100;
}
- IntDriver.InsertRangeICollection(new int[0], intArr1, 0, 1, IntDriver.ConstructTestCollection);
- IntDriver.InsertRangeICollection(intArr1, intArr2, 0, 1, IntDriver.ConstructTestCollection);
- IntDriver.InsertRangeICollection(intArr1, intArr2, 1, 1, IntDriver.ConstructTestCollection);
- IntDriver.InsertRangeICollection(intArr1, intArr2, 99, 1, IntDriver.ConstructTestCollection);
- IntDriver.InsertRangeICollection(intArr1, intArr2, 100, 1, IntDriver.ConstructTestCollection);
- IntDriver.InsertRangeICollection(intArr1, intArr2, 50, 50, IntDriver.ConstructTestCollection);
- IntDriver.InsertRangeList(intArr1, intArr2, 0, 1, IntDriver.ConstructTestCollection);
+ foreach (Func<int[], IEnumerable<int>> collectionGenerator in IntDriver.CollectionGenerators)
+ {
+ IntDriver.InsertRangeIEnumerable(new int[0], intArr1, 0, 1, collectionGenerator);
+ IntDriver.InsertRangeIEnumerable(intArr1, intArr2, 0, 1, collectionGenerator);
+ IntDriver.InsertRangeIEnumerable(intArr1, intArr2, 1, 1, collectionGenerator);
+ IntDriver.InsertRangeIEnumerable(intArr1, intArr2, 99, 1, collectionGenerator);
+ IntDriver.InsertRangeIEnumerable(intArr1, intArr2, 100, 1, collectionGenerator);
+ IntDriver.InsertRangeIEnumerable(intArr1, intArr2, 50, 50, collectionGenerator);
+ }
Driver<string> StringDriver = new Driver<string>();
string[] stringArr1 = new string[100];
@@ -811,17 +806,19 @@ namespace System.Collections.Tests
for (int i = 0; i < 10; i++)
stringArr2[i] = "SomeTestString" + (i + 100).ToString();
- StringDriver.InsertRangeICollection(new string[0], stringArr1, 0, 1, StringDriver.ConstructTestCollection);
- StringDriver.InsertRangeICollection(stringArr1, stringArr2, 0, 1, StringDriver.ConstructTestCollection);
- StringDriver.InsertRangeICollection(stringArr1, stringArr2, 1, 1, StringDriver.ConstructTestCollection);
- StringDriver.InsertRangeICollection(stringArr1, stringArr2, 99, 1, StringDriver.ConstructTestCollection);
- StringDriver.InsertRangeICollection(stringArr1, stringArr2, 100, 1, StringDriver.ConstructTestCollection);
- StringDriver.InsertRangeICollection(stringArr1, stringArr2, 50, 50, StringDriver.ConstructTestCollection);
- StringDriver.InsertRangeICollection(new string[] { null, null, null, null }, stringArr2, 0, 1, StringDriver.ConstructTestCollection);
- StringDriver.InsertRangeICollection(new string[] { null, null, null, null }, stringArr2, 4, 1, StringDriver.ConstructTestCollection);
- StringDriver.InsertRangeICollection(new string[] { null, null, null, null }, new string[] { null, null, null, null }, 0, 1, StringDriver.ConstructTestCollection);
- StringDriver.InsertRangeICollection(new string[] { null, null, null, null }, new string[] { null, null, null, null }, 4, 50, StringDriver.ConstructTestCollection);
- StringDriver.InsertRangeList(stringArr1, stringArr2, 0, 1, StringDriver.ConstructTestCollection);
+ foreach (Func<string[], IEnumerable<string>> collectionGenerator in StringDriver.CollectionGenerators)
+ {
+ StringDriver.InsertRangeIEnumerable(new string[0], stringArr1, 0, 1, collectionGenerator);
+ StringDriver.InsertRangeIEnumerable(stringArr1, stringArr2, 0, 1, collectionGenerator);
+ StringDriver.InsertRangeIEnumerable(stringArr1, stringArr2, 1, 1, collectionGenerator);
+ StringDriver.InsertRangeIEnumerable(stringArr1, stringArr2, 99, 1, collectionGenerator);
+ StringDriver.InsertRangeIEnumerable(stringArr1, stringArr2, 100, 1, collectionGenerator);
+ StringDriver.InsertRangeIEnumerable(stringArr1, stringArr2, 50, 50, collectionGenerator);
+ StringDriver.InsertRangeIEnumerable(new string[] { null, null, null, null }, stringArr2, 0, 1, collectionGenerator);
+ StringDriver.InsertRangeIEnumerable(new string[] { null, null, null, null }, stringArr2, 4, 1, collectionGenerator);
+ StringDriver.InsertRangeIEnumerable(new string[] { null, null, null, null }, new string[] { null, null, null, null }, 0, 1, collectionGenerator);
+ StringDriver.InsertRangeIEnumerable(new string[] { null, null, null, null }, new string[] { null, null, null, null }, 4, 50, collectionGenerator);
+ }
}
[Fact]
@@ -836,8 +833,8 @@ namespace System.Collections.Tests
for (int i = 0; i < 100; i++)
stringArr1[i] = "SomeTestString" + i.ToString();
- IntDriver.InsertRangeValidations(intArr1, IntDriver.ConstructTestCollection);
- StringDriver.InsertRangeValidations(stringArr1, StringDriver.ConstructTestCollection);
+ IntDriver.InsertRangeValidations(intArr1, IntDriver.ConstructTestEnumerable);
+ StringDriver.InsertRangeValidations(stringArr1, StringDriver.ConstructTestEnumerable);
}
[Fact]
diff --git a/src/System.Collections/tests/System.Collections.Tests.csproj b/src/System.Collections/tests/System.Collections.Tests.csproj
index 6ad8dfb2db..40039d447f 100644
--- a/src/System.Collections/tests/System.Collections.Tests.csproj
+++ b/src/System.Collections/tests/System.Collections.Tests.csproj
@@ -67,11 +67,14 @@
<Compile Include="$(CommonTestPath)\System\ObjectCloner.cs">
<Link>Common\System\ObjectCloner.cs</Link>
</Compile>
+ <Compile Include="$(CommonTestPath)\System\RandomExtensions.cs">
+ <Link>Common\System\RandomExtensions.cs</Link>
+ </Compile>
<Compile Include="$(CommonTestPath)\System\Collections\DictionaryExtensions.cs" Condition="'$(TargetGroup)'!='netcoreapp'">
<Link>Common\System\Collections\DictionaryExtensions.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)\System\Runtime\Serialization\Formatters\BinaryFormatterHelpers.cs">
- <Link>System\Runtime\Serialization\Formatters\BinaryFormatterHelpers.cs</Link>
+ <Link>Common\System\Runtime\Serialization\Formatters\BinaryFormatterHelpers.cs</Link>
</Compile>
<!-- Generic tests -->
<Compile Include="Generic\Dictionary\Dictionary.Generic.Tests.netcoreapp.cs" Condition="'$(TargetGroup)' == 'netcoreapp'" />
@@ -163,4 +166,4 @@
<EmbeddedResource Include="Resources\$(AssemblyName).rd.xml" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.ComponentModel.Annotations/pkg/System.ComponentModel.Annotations.pkgproj b/src/System.ComponentModel.Annotations/pkg/System.ComponentModel.Annotations.pkgproj
index 6a31e5cf40..b2cddb4f68 100644
--- a/src/System.ComponentModel.Annotations/pkg/System.ComponentModel.Annotations.pkgproj
+++ b/src/System.ComponentModel.Annotations/pkg/System.ComponentModel.Annotations.pkgproj
@@ -16,7 +16,7 @@
<FrameworkReference>System.ComponentModel.DataAnnotations</FrameworkReference>
</InboxOnTargetFramework>
<InboxOnTargetFramework Include="netcoreapp2.0" />
- <InboxOnTargetFramework Include="$(UAPvNextTFM)" />
+ <InboxOnTargetFramework Include="uap10.0.16299" />
<InboxOnTargetFramework Include="win8" />
<InboxOnTargetFramework Include="portable-net45+win8" />
<InboxOnTargetFramework Include="xamarinios10" />
diff --git a/src/System.ComponentModel.Annotations/ref/System.ComponentModel.Annotations.cs b/src/System.ComponentModel.Annotations/ref/System.ComponentModel.Annotations.cs
index a6ef6b4734..52a440c34a 100644
--- a/src/System.ComponentModel.Annotations/ref/System.ComponentModel.Annotations.cs
+++ b/src/System.ComponentModel.Annotations/ref/System.ComponentModel.Annotations.cs
@@ -204,9 +204,11 @@ namespace System.ComponentModel.DataAnnotations
public RangeAttribute(double minimum, double maximum) { }
public RangeAttribute(int minimum, int maximum) { }
public RangeAttribute(System.Type type, string minimum, string maximum) { }
+ public bool ConvertValueInInvariantCulture { get { throw null; } set { } }
public object Maximum { get { throw null; } }
public object Minimum { get { throw null; } }
public System.Type OperandType { get { throw null; } }
+ public bool ParseLimitsInInvariantCulture { get { throw null; } set { } }
public override string FormatErrorMessage(string name) { throw null; }
public override bool IsValid(object value) { throw null; }
}
diff --git a/src/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/RangeAttribute.cs b/src/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/RangeAttribute.cs
index 4e210c4e37..bc74c78baf 100644
--- a/src/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/RangeAttribute.cs
+++ b/src/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/RangeAttribute.cs
@@ -70,6 +70,21 @@ namespace System.ComponentModel.DataAnnotations
/// </summary>
public Type OperandType { get; }
+ /// <summary>
+ /// Determines whether string values for <see cref="Minimum"/> and <see cref="Maximum"/> are parsed in the invariant
+ /// culture rather than the current culture in effect at the time of the validation.
+ /// </summary>
+ public bool ParseLimitsInInvariantCulture { get; set; }
+
+ /// <summary>
+ /// Determines whether any conversions necessary from the value being validated to <see cref="OperandType"/> as set
+ /// by the <c>type</c> parameter of the <see cref="RangeAttribute(Type, string, string)"/> constructor are carried
+ /// out in the invariant culture rather than the current culture in effect at the time of the validation.
+ /// </summary>
+ /// <remarks>This property has no effects with the constructors with <see cref="int"/> or <see cref="double"/>
+ /// parameters, for which the invariant culture is always used for any conversions of the validated value.</remarks>
+ public bool ConvertValueInInvariantCulture { get; set; }
+
private Func<object, object> Conversion { get; set; }
private void Initialize(IComparable minimum, IComparable maximum, Func<object, object> conversion)
@@ -192,10 +207,25 @@ namespace System.ComponentModel.DataAnnotations
}
TypeConverter converter = TypeDescriptor.GetConverter(type);
- IComparable min = (IComparable)converter.ConvertFromString((string)minimum);
- IComparable max = (IComparable)converter.ConvertFromString((string)maximum);
+ IComparable min = (IComparable)(ParseLimitsInInvariantCulture
+ ? converter.ConvertFromInvariantString((string)minimum)
+ : converter.ConvertFromString((string)minimum));
+ IComparable max = (IComparable)(ParseLimitsInInvariantCulture
+ ? converter.ConvertFromInvariantString((string)maximum)
+ : converter.ConvertFromString((string)maximum));
+
+ Func<object, object> conversion;
+ if (ConvertValueInInvariantCulture)
+ {
+ conversion = value => value?.GetType() == type
+ ? value
+ : converter.ConvertFrom(null, CultureInfo.InvariantCulture, value);
+ }
+ else
+ {
+ conversion = value => value?.GetType() == type ? value : converter.ConvertFrom(value);
+ }
- Func<object, object> conversion = value => (value != null && value.GetType() == type) ? value : converter.ConvertFrom(value);
Initialize(min, max, conversion);
}
}
diff --git a/src/System.ComponentModel.Annotations/tests/RangeAttributeTests.cs b/src/System.ComponentModel.Annotations/tests/RangeAttributeTests.cs
index 0a524a49c0..01e263d3ae 100644
--- a/src/System.ComponentModel.Annotations/tests/RangeAttributeTests.cs
+++ b/src/System.ComponentModel.Annotations/tests/RangeAttributeTests.cs
@@ -3,6 +3,8 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
+using System.Globalization;
+using System.Threading;
using Xunit;
namespace System.ComponentModel.DataAnnotations.Tests
@@ -85,6 +87,667 @@ namespace System.ComponentModel.DataAnnotations.Tests
yield return new TestCase(stringDoubleRange, new IConvertibleImplementor() { DoubleThrow = new NotSupportedException() });
}
+ public static IEnumerable<object[]> DotDecimalRanges()
+ {
+ yield return new object[] {typeof(decimal), "1.0", "3.0"};
+ yield return new object[] {typeof(double), "1.0", "3.0"};
+ }
+
+ public static IEnumerable<object[]> CommaDecimalRanges()
+ {
+ yield return new object[] { typeof(decimal), "1,0", "3,0" };
+ yield return new object[] { typeof(double), "1,0", "3,0" };
+ }
+
+ public static IEnumerable<object[]> DotDecimalValidValues()
+ {
+ yield return new object[] { typeof(decimal), "1.0", "3.0", "1.0" };
+ yield return new object[] { typeof(decimal), "1.0", "3.0", "3.0" };
+ yield return new object[] { typeof(decimal), "1.0", "3.0", "2.9999999999999999999999999999999999999999999" };
+ yield return new object[] { typeof(decimal), "1.0", "3.0", "2.9999999999999999999999999999" };
+ yield return new object[] { typeof(double), "1.0", "3.0", "1.0" };
+ yield return new object[] { typeof(double), "1.0", "3.0", "3.0" };
+ yield return new object[] { typeof(double), "1.0", "3.0", "2.9999999999999999999999999999999999999999999" };
+ yield return new object[] { typeof(double), "1.0", "3.0", "2.99999999999999" };
+ }
+
+ public static IEnumerable<object[]> CommaDecimalValidValues()
+ {
+ yield return new object[] { typeof(decimal), "1,0", "3,0", "1,0" };
+ yield return new object[] { typeof(decimal), "1,0", "3,0", "3,0" };
+ yield return new object[] { typeof(decimal), "1,0", "3,0", "2,9999999999999999999999999999999999999999999" };
+ yield return new object[] { typeof(decimal), "1,0", "3,0", "2,9999999999999999999999999999" };
+ yield return new object[] { typeof(double), "1,0", "3,0", "1,0" };
+ yield return new object[] { typeof(double), "1,0", "3,0", "3,0" };
+ yield return new object[] { typeof(double), "1,0", "3,0", "2,99999999999999" };
+ }
+
+ public static IEnumerable<object[]> DotDecimalInvalidValues()
+ {
+ yield return new object[] { typeof(decimal), "1.0", "3.0", "9.0" };
+ yield return new object[] { typeof(decimal), "1.0", "3.0", "0.1" };
+ yield return new object[] { typeof(decimal), "1.0", "3.0", "3.9999999999999999999999999999999999999999999" };
+ yield return new object[] { typeof(decimal), "1.0", "3.0", "3.9999999999999999999999999999" };
+ yield return new object[] { typeof(double), "1.0", "3.0", "9.0" };
+ yield return new object[] { typeof(double), "1.0", "3.0", "0.1" };
+ yield return new object[] { typeof(double), "1.0", "3.0", "3.9999999999999999999999999999999999999999999" };
+ yield return new object[] { typeof(double), "1.0", "3.0", "3.99999999999999" };
+ }
+
+ public static IEnumerable<object[]> CommaDecimalInvalidValues()
+ {
+ yield return new object[] { typeof(decimal), "1,0", "3,0", "9,0" };
+ yield return new object[] { typeof(decimal), "1,0", "3,0", "0,1" };
+ yield return new object[] { typeof(decimal), "1,0", "3,0", "3,9999999999999999999999999999999999999999999" };
+ yield return new object[] { typeof(decimal), "1,0", "3,0", "3,9999999999999999999999999999" };
+ yield return new object[] { typeof(double), "1,0", "3,0", "9,0" };
+ yield return new object[] { typeof(double), "1,0", "3,0", "0,1" };
+ yield return new object[] { typeof(double), "1,0", "3,0", "3,9999999999999999999999999999999999999999999" };
+ yield return new object[] { typeof(double), "1,0", "3,0", "3,99999999999999" };
+ }
+
+ public static IEnumerable<object[]> DotDecimalNonStringValidValues()
+ {
+ yield return new object[] { typeof(decimal), "1.0", "3.0", 1.0m };
+ yield return new object[] { typeof(decimal), "1.0", "3.0", 3.0m };
+ yield return new object[] { typeof(decimal), "1.0", "3.0", 2.9999999999999999999999999999m };
+ yield return new object[] { typeof(double), "1.0", "3.0", 1.0 };
+ yield return new object[] { typeof(double), "1.0", "3.0", 3.0 };
+ yield return new object[] { typeof(double), "1.0", "3.0", 2.99999999999999 };
+ }
+
+ public static IEnumerable<object[]> CommaDecimalNonStringValidValues()
+ {
+ yield return new object[] { typeof(decimal), "1,0", "3,0", 1.0m };
+ yield return new object[] { typeof(decimal), "1,0", "3,0", 3.0m };
+ yield return new object[] { typeof(decimal), "1,0", "3,0", 2.9999999999999999999999999999m };
+ yield return new object[] { typeof(double), "1,0", "3,0", 1.0 };
+ yield return new object[] { typeof(double), "1,0", "3,0", 3.0 };
+ yield return new object[] { typeof(double), "1,0", "3,0", 2.99999999999999 };
+ }
+
+ private class TempCulture : IDisposable
+ {
+ private CultureInfo _original;
+
+ public TempCulture(string culture)
+ {
+ Thread currentThread = Thread.CurrentThread;
+ _original = currentThread.CurrentCulture;
+ currentThread.CurrentCulture = CultureInfo.GetCultureInfoByIetfLanguageTag(culture);
+ }
+
+ public void Dispose()
+ {
+ Thread.CurrentThread.CurrentCulture = _original;
+ }
+ }
+
+ [Theory, MemberData(nameof(DotDecimalRanges)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void ParseDotSeparatorExtremaInCommaSeparatorCultures(Type type, string min, string max)
+ {
+ using (new TempCulture("en-US"))
+ {
+ Assert.True(new RangeAttribute(type, min, max).IsValid(null));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max);
+ Assert.Throws<ArgumentException>(() => range.IsValid(null));
+ }
+ }
+
+ [Theory, MemberData(nameof(DotDecimalRanges)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void ParseDotSeparatorInvariantExtremaInCommaSeparatorCultures(Type type, string min, string max)
+ {
+ using (new TempCulture("en-US"))
+ {
+ Assert.True(
+ new RangeAttribute(type, min, max)
+ {
+ ParseLimitsInInvariantCulture = true
+ }.IsValid(null));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ Assert.True(
+ new RangeAttribute(type, min, max)
+ {
+ ParseLimitsInInvariantCulture = true
+ }.IsValid(null));
+ }
+ }
+
+ [Theory, MemberData(nameof(CommaDecimalRanges)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void ParseCommaSeparatorExtremaInCommaSeparatorCultures(Type type, string min, string max)
+ {
+ using (new TempCulture("en-US"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max);
+ Assert.Throws<ArgumentException>(() => range.IsValid(null));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ Assert.True(new RangeAttribute(type, min, max).IsValid(null));
+ }
+ }
+
+ [Theory, MemberData(nameof(CommaDecimalRanges)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void ParseCommaSeparatorInvariantExtremaInCommaSeparatorCultures(Type type, string min, string max)
+ {
+ using (new TempCulture("en-US"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max);
+ Assert.Throws<ArgumentException>(() => range.IsValid(null));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ Assert.True(new RangeAttribute(type, min, max).IsValid(null));
+ }
+ }
+
+ [Theory, MemberData(nameof(DotDecimalValidValues)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void DotDecimalExtremaAndValues(Type type, string min, string max, string value)
+ {
+ using (new TempCulture("en-US"))
+ {
+ Assert.True(new RangeAttribute(type, min, max).IsValid(value));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max);
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+ }
+
+ [Theory, MemberData(nameof(DotDecimalValidValues)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void DotDecimalExtremaAndValuesInvariantParse(Type type, string min, string max, string value)
+ {
+ using (new TempCulture("en-US"))
+ {
+ Assert.True(
+ new RangeAttribute(type, min, max)
+ {
+ ParseLimitsInInvariantCulture = true
+ }.IsValid(value));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max)
+ {
+ ParseLimitsInInvariantCulture = true
+ };
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+ }
+
+ [Theory, MemberData(nameof(DotDecimalValidValues)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void DotDecimalExtremaAndValuesInvariantConvert(Type type, string min, string max, string value)
+ {
+ using (new TempCulture("en-US"))
+ {
+ Assert.True(
+ new RangeAttribute(type, min, max)
+ {
+ ConvertValueInInvariantCulture = true
+ }.IsValid(value));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max)
+ {
+ ConvertValueInInvariantCulture = true
+ };
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+ }
+
+ [Theory, MemberData(nameof(DotDecimalValidValues)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void DotDecimalExtremaAndValuesInvariantBoth(Type type, string min, string max, string value)
+ {
+ using (new TempCulture("en-US"))
+ {
+ Assert.True(
+ new RangeAttribute(type, min, max)
+ {
+ ConvertValueInInvariantCulture = true,
+ ParseLimitsInInvariantCulture = true
+ }.IsValid(value));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ Assert.True(
+ new RangeAttribute(type, min, max)
+ {
+ ConvertValueInInvariantCulture = true,
+ ParseLimitsInInvariantCulture = true
+ }.IsValid(value));
+ }
+ }
+
+ [Theory, MemberData(nameof(DotDecimalNonStringValidValues)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void DotDecimalExtremaAndNonStringValues(Type type, string min, string max, object value)
+ {
+ using (new TempCulture("en-US"))
+ {
+ Assert.True(new RangeAttribute(type, min, max).IsValid(value));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max);
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+ }
+
+ [Theory, MemberData(nameof(DotDecimalNonStringValidValues)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void DotDecimalExtremaAndNonStringValuesInvariantParse(Type type, string min, string max, object value)
+ {
+ using (new TempCulture("en-US"))
+ {
+ Assert.True(
+ new RangeAttribute(type, min, max)
+ {
+ ParseLimitsInInvariantCulture = true
+ }.IsValid(value));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ Assert.True(
+ new RangeAttribute(type, min, max)
+ {
+ ParseLimitsInInvariantCulture = true
+ }.IsValid(value));
+ }
+ }
+
+ [Theory, MemberData(nameof(DotDecimalNonStringValidValues)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void DotDecimalExtremaAndNonStringValuesInvariantConvert(Type type, string min, string max, object value)
+ {
+ using (new TempCulture("en-US"))
+ {
+ Assert.True(
+ new RangeAttribute(type, min, max)
+ {
+ ConvertValueInInvariantCulture = true
+ }.IsValid(value));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max)
+ {
+ ConvertValueInInvariantCulture = true
+ };
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+ }
+
+ [Theory, MemberData(nameof(DotDecimalNonStringValidValues)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void DotDecimalExtremaAndNonStringValuesInvariantBoth(Type type, string min, string max, object value)
+ {
+ using (new TempCulture("en-US"))
+ {
+ Assert.True(
+ new RangeAttribute(type, min, max)
+ {
+ ConvertValueInInvariantCulture = true,
+ ParseLimitsInInvariantCulture = true
+ }.IsValid(value));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ Assert.True(
+ new RangeAttribute(type, min, max)
+ {
+ ConvertValueInInvariantCulture = true,
+ ParseLimitsInInvariantCulture = true
+ }.IsValid(value));
+ }
+ }
+
+ [Theory, MemberData(nameof(CommaDecimalNonStringValidValues)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void CommaDecimalExtremaAndNonStringValues(Type type, string min, string max, object value)
+ {
+ using (new TempCulture("en-US"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max);
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ Assert.True(new RangeAttribute(type, min, max).IsValid(value));
+ }
+ }
+
+ [Theory, MemberData(nameof(CommaDecimalNonStringValidValues)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void CommaDecimalExtremaAndNonStringValuesInvariantParse(Type type, string min, string max, object value)
+ {
+ using (new TempCulture("en-US"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max)
+ {
+ ParseLimitsInInvariantCulture = true
+ };
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max)
+ {
+ ParseLimitsInInvariantCulture = true
+ };
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+ }
+
+ [Theory, MemberData(nameof(CommaDecimalNonStringValidValues)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void CommaDecimalExtremaAndNonStringValuesInvariantConvert(Type type, string min, string max, object value)
+ {
+ using (new TempCulture("en-US"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max)
+ {
+ ConvertValueInInvariantCulture = true
+ };
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ Assert.True(
+ new RangeAttribute(type, min, max)
+ {
+ ConvertValueInInvariantCulture = true
+ }.IsValid(value));
+ }
+ }
+
+ [Theory, MemberData(nameof(CommaDecimalNonStringValidValues)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void CommaDecimalExtremaAndNonStringValuesInvariantBoth(Type type, string min, string max, object value)
+ {
+ using (new TempCulture("en-US"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max)
+ {
+ ConvertValueInInvariantCulture = true,
+ ParseLimitsInInvariantCulture = true
+ };
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max)
+ {
+ ConvertValueInInvariantCulture = true,
+ ParseLimitsInInvariantCulture = true
+ };
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+ }
+
+ [Theory, MemberData(nameof(DotDecimalInvalidValues)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void DotDecimalExtremaAndInvalidValues(Type type, string min, string max, string value)
+ {
+ using (new TempCulture("en-US"))
+ {
+ Assert.False(new RangeAttribute(type, min, max).IsValid(value));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max);
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+ }
+
+ [Theory, MemberData(nameof(DotDecimalInvalidValues)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void DotDecimalExtremaAndInvalidValuesInvariantParse(Type type, string min, string max, string value)
+ {
+ using (new TempCulture("en-US"))
+ {
+ Assert.False(
+ new RangeAttribute(type, min, max)
+ {
+ ParseLimitsInInvariantCulture = true
+ }.IsValid(value));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max)
+ {
+ ParseLimitsInInvariantCulture = true
+ };
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+ }
+
+ [Theory, MemberData(nameof(DotDecimalInvalidValues)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void DotDecimalExtremaAndInvalidValuesInvariantConvert(Type type, string min, string max, string value)
+ {
+ using (new TempCulture("en-US"))
+ {
+ Assert.False(
+ new RangeAttribute(type, min, max)
+ {
+ ConvertValueInInvariantCulture = true
+ }.IsValid(value));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max)
+ {
+ ConvertValueInInvariantCulture = true
+ };
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+ }
+
+ [Theory, MemberData(nameof(DotDecimalInvalidValues)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void DotDecimalExtremaAndInvalidValuesInvariantBoth(Type type, string min, string max, string value)
+ {
+ using (new TempCulture("en-US"))
+ {
+ Assert.False(
+ new RangeAttribute(type, min, max)
+ {
+ ConvertValueInInvariantCulture = true,
+ ParseLimitsInInvariantCulture = true
+ }.IsValid(value));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ Assert.False(
+ new RangeAttribute(type, min, max)
+ {
+ ConvertValueInInvariantCulture = true,
+ ParseLimitsInInvariantCulture = true
+ }.IsValid(value));
+ }
+ }
+
+ [Theory, MemberData(nameof(CommaDecimalValidValues)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void CommaDecimalExtremaAndValues(Type type, string min, string max, string value)
+ {
+ using (new TempCulture("en-US"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max);
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ Assert.True(new RangeAttribute(type, min, max).IsValid(value));
+ }
+ }
+
+ [Theory, MemberData(nameof(CommaDecimalValidValues)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void CommaDecimalExtremaAndValuesInvariantParse(Type type, string min, string max, string value)
+ {
+ using (new TempCulture("en-US"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max)
+ {
+ ParseLimitsInInvariantCulture = true
+ };
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max)
+ {
+ ParseLimitsInInvariantCulture = true
+ };
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+ }
+
+ [Theory, MemberData(nameof(CommaDecimalValidValues)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void CommaDecimalExtremaAndValuesInvariantConvert(Type type, string min, string max, string value)
+ {
+ using (new TempCulture("en-US"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max)
+ {
+ ConvertValueInInvariantCulture = true
+ };
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max)
+ {
+ ConvertValueInInvariantCulture = true
+ };
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+ }
+
+ [Theory, MemberData(nameof(CommaDecimalValidValues)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void CommaDecimalExtremaAndValuesInvariantBoth(Type type, string min, string max, string value)
+ {
+ using (new TempCulture("en-US"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max)
+ {
+ ConvertValueInInvariantCulture = true,
+ ParseLimitsInInvariantCulture = true
+ };
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max)
+ {
+ ConvertValueInInvariantCulture = true,
+ ParseLimitsInInvariantCulture = true
+ };
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+ }
+
+ [Theory, MemberData(nameof(CommaDecimalInvalidValues)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void CommaDecimalExtremaAndInvalidValues(Type type, string min, string max, string value)
+ {
+ using (new TempCulture("en-US"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max);
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ Assert.False(new RangeAttribute(type, min, max).IsValid(value));
+ }
+ }
+
+ [Theory, MemberData(nameof(CommaDecimalInvalidValues)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void CommaDecimalExtremaAndInvalidValuesInvariantParse(Type type, string min, string max, string value)
+ {
+ using (new TempCulture("en-US"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max)
+ {
+ ParseLimitsInInvariantCulture = true
+ };
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max)
+ {
+ ParseLimitsInInvariantCulture = true
+ };
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+ }
+
+ [Theory, MemberData(nameof(CommaDecimalInvalidValues)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void CommaDecimalExtremaAndInvalidValuesInvariantConvert(Type type, string min, string max, string value)
+ {
+ using (new TempCulture("en-US"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max)
+ {
+ ConvertValueInInvariantCulture = true
+ };
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max)
+ {
+ ConvertValueInInvariantCulture = true
+ };
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+ }
+
+ [Theory, MemberData(nameof(CommaDecimalInvalidValues)), SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "2648 not fixed on NetFX")]
+ public static void CommaDecimalExtremaAndInvalidValuesInvariantBoth(Type type, string min, string max, string value)
+ {
+ using (new TempCulture("en-US"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max)
+ {
+ ConvertValueInInvariantCulture = true,
+ ParseLimitsInInvariantCulture = true
+ };
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+
+ using (new TempCulture("fr-FR"))
+ {
+ RangeAttribute range = new RangeAttribute(type, min, max)
+ {
+ ConvertValueInInvariantCulture = true,
+ ParseLimitsInInvariantCulture = true
+ };
+ Assert.Throws<ArgumentException>(() => range.IsValid(value));
+ }
+ }
+
[Theory]
[InlineData(typeof(int), "1", "3")]
[InlineData(typeof(double), "1", "3")]
diff --git a/src/System.ComponentModel.Annotations/tests/ValidatorTests.cs b/src/System.ComponentModel.Annotations/tests/ValidatorTests.cs
index 1997edbcda..c820e38fc8 100644
--- a/src/System.ComponentModel.Annotations/tests/ValidatorTests.cs
+++ b/src/System.ComponentModel.Annotations/tests/ValidatorTests.cs
@@ -229,7 +229,7 @@ namespace System.ComponentModel.DataAnnotations.Tests
var results = new List<ValidationResult>();
Assert.False(Validator.TryValidateObject(instance, context, results));
- Assert.Equal("The Required field is required.", Assert.Single(results).ErrorMessage);
+ Assert.Contains("Required", Assert.Single(results).ErrorMessage);
}
public class RequiredFailure
diff --git a/src/System.ComponentModel.Composition/System.ComponentModel.Composition.sln b/src/System.ComponentModel.Composition/System.ComponentModel.Composition.sln
index 8bfa5e8779..98f7b86c61 100644
--- a/src/System.ComponentModel.Composition/System.ComponentModel.Composition.sln
+++ b/src/System.ComponentModel.Composition/System.ComponentModel.Composition.sln
@@ -7,6 +7,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.ComponentModel.Compo
{2D694AC8-A12F-4622-9405-74E20EC40C3A} = {2D694AC8-A12F-4622-9405-74E20EC40C3A}
EndProjectSection
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.ComponentModel.Composition.Noop.Assembly", "tests\System.ComponentModel.Composition.Noop.Assembly\System.ComponentModel.Composition.Noop.Assembly.csproj", "{396D6EBF-60BD-4DAF-8783-FB403E070A56}"
+ ProjectSection(ProjectDependencies) = postProject
+ {2D694AC8-A12F-4622-9405-74E20EC40C3A} = {2D694AC8-A12F-4622-9405-74E20EC40C3A}
+ EndProjectSection
+EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.ComponentModel.Composition", "src\System.ComponentModel.Composition.csproj", "{2D694AC8-A12F-4622-9405-74E20EC40C3A}"
ProjectSection(ProjectDependencies) = postProject
{DD3B8052-CE03-4159-8311-1CE1382C51B0} = {DD3B8052-CE03-4159-8311-1CE1382C51B0}
@@ -30,6 +35,10 @@ Global
{59F4682D-C41D-45A7-9798-16C75525BB1D}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
{59F4682D-C41D-45A7-9798-16C75525BB1D}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
{59F4682D-C41D-45A7-9798-16C75525BB1D}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
+ {396D6EBF-60BD-4DAF-8783-FB403E070A56}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
+ {396D6EBF-60BD-4DAF-8783-FB403E070A56}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
+ {396D6EBF-60BD-4DAF-8783-FB403E070A56}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
+ {396D6EBF-60BD-4DAF-8783-FB403E070A56}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
{2D694AC8-A12F-4622-9405-74E20EC40C3A}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
{2D694AC8-A12F-4622-9405-74E20EC40C3A}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
{2D694AC8-A12F-4622-9405-74E20EC40C3A}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
@@ -44,6 +53,7 @@ Global
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{59F4682D-C41D-45A7-9798-16C75525BB1D} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
+ {396D6EBF-60BD-4DAF-8783-FB403E070A56} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
{2D694AC8-A12F-4622-9405-74E20EC40C3A} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD}
{DD3B8052-CE03-4159-8311-1CE1382C51B0} = {2E666815-2EDB-464B-9DF6-380BF4789AD4}
EndGlobalSection
diff --git a/src/System.ComponentModel.Composition/dir.props b/src/System.ComponentModel.Composition/dir.props
index 55b60149d2..95204c770a 100644
--- a/src/System.ComponentModel.Composition/dir.props
+++ b/src/System.ComponentModel.Composition/dir.props
@@ -3,6 +3,6 @@
<Import Project="..\dir.props" />
<PropertyGroup>
<AssemblyVersion>4.0.0.0</AssemblyVersion>
- <AssemblyKey>MSFT</AssemblyKey>
+ <AssemblyKey>ECMA</AssemblyKey>
</PropertyGroup>
</Project>
diff --git a/src/System.ComponentModel.Composition/pkg/System.ComponentModel.Composition.pkgproj b/src/System.ComponentModel.Composition/pkg/System.ComponentModel.Composition.pkgproj
index 36f9f8d5f9..8b79a972cc 100644
--- a/src/System.ComponentModel.Composition/pkg/System.ComponentModel.Composition.pkgproj
+++ b/src/System.ComponentModel.Composition/pkg/System.ComponentModel.Composition.pkgproj
@@ -3,16 +3,14 @@
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<ProjectReference Include="..\ref\System.ComponentModel.Composition.csproj">
- <SupportedFramework>netcoreapp2.0;net45;$(AllXamarinFrameworks)</SupportedFramework>
+ <SupportedFramework>uap10.0.16299;netcoreapp2.0;net45;$(AllXamarinFrameworks)</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\src\System.ComponentModel.Composition.csproj" />
<InboxOnTargetFramework Include="net45">
<AsFrameworkReference>true</AsFrameworkReference>
</InboxOnTargetFramework>
+ <InboxOnTargetFramework Include="uap10.0.16299" />
<InboxOnTargetFramework Include="$(AllXamarinFrameworks)" />
- <File Include="$(PlaceHolderFile)">
- <TargetPath>runtimes/win/lib/net45</TargetPath>
- </File>
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
diff --git a/src/System.ComponentModel.Composition/ref/Configurations.props b/src/System.ComponentModel.Composition/ref/Configurations.props
index fc9ef9822c..a83fe20d89 100644
--- a/src/System.ComponentModel.Composition/ref/Configurations.props
+++ b/src/System.ComponentModel.Composition/ref/Configurations.props
@@ -3,6 +3,7 @@
<PropertyGroup>
<BuildConfigurations>
netstandard;
+ _netfx;
</BuildConfigurations>
</PropertyGroup>
</Project>
diff --git a/src/System.ComponentModel.Composition/ref/System.ComponentModel.Composition.cs b/src/System.ComponentModel.Composition/ref/System.ComponentModel.Composition.cs
index aadd04f683..7266b54f08 100644
--- a/src/System.ComponentModel.Composition/ref/System.ComponentModel.Composition.cs
+++ b/src/System.ComponentModel.Composition/ref/System.ComponentModel.Composition.cs
@@ -5,6 +5,8 @@
// Changes to this file must follow the http://aka.ms/api-review process.
// ------------------------------------------------------------------------------
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(destination: typeof(System.Lazy<,>))]
+
namespace System.ComponentModel.Composition
{
public static partial class AdaptationConstants
diff --git a/src/System.ComponentModel.Composition/src/Configurations.props b/src/System.ComponentModel.Composition/src/Configurations.props
index 43f172907f..884be53cf0 100644
--- a/src/System.ComponentModel.Composition/src/Configurations.props
+++ b/src/System.ComponentModel.Composition/src/Configurations.props
@@ -7,6 +7,7 @@
</PackageConfigurations>
<BuildConfigurations>
$(PackageConfigurations);
+ _netfx;
netcoreapp;
uap;
</BuildConfigurations>
diff --git a/src/System.ComponentModel.Composition/src/System.ComponentModel.Composition.csproj b/src/System.ComponentModel.Composition/src/System.ComponentModel.Composition.csproj
index a69aa4f1f2..cc460628fc 100644
--- a/src/System.ComponentModel.Composition/src/System.ComponentModel.Composition.csproj
+++ b/src/System.ComponentModel.Composition/src/System.ComponentModel.Composition.csproj
@@ -15,6 +15,9 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
+ <ItemGroup>
+ <Compile Include="TypeForwards.cs" />
+ </ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' != 'netstandard'">
<Compile Include="Microsoft\Internal\AdaptationHelpers.cs" />
<Compile Include="Microsoft\Internal\AttributeServices.cs" />
diff --git a/src/System.ComponentModel.Composition/src/System/ComponentModel/Composition/Hosting/AssemblyCatalog.cs b/src/System.ComponentModel.Composition/src/System/ComponentModel/Composition/Hosting/AssemblyCatalog.cs
index d501f5c850..f05d654ce2 100644
--- a/src/System.ComponentModel.Composition/src/System/ComponentModel/Composition/Hosting/AssemblyCatalog.cs
+++ b/src/System.ComponentModel.Composition/src/System/ComponentModel/Composition/Hosting/AssemblyCatalog.cs
@@ -8,6 +8,7 @@ using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using System.Globalization;
+using System.IO;
using System.Reflection;
using System.Threading;
using Microsoft.Internal;
@@ -566,7 +567,15 @@ namespace System.ComponentModel.Composition.Hosting
assemblyName.CodeBase = codeBase;
}
- return Assembly.Load(assemblyName);
+ try
+ {
+ return Assembly.Load(assemblyName);
+ }
+ //fallback attempt issue https://github.com/dotnet/corefx/issues/27433
+ catch (FileNotFoundException)
+ {
+ return Assembly.LoadFrom(codeBase);
+ }
}
}
}
diff --git a/src/System.ComponentModel.Composition/src/System/ComponentModel/Composition/Hosting/CompositionContainer.cs b/src/System.ComponentModel.Composition/src/System/ComponentModel/Composition/Hosting/CompositionContainer.cs
index 69375e8066..fcd18d14c8 100644
--- a/src/System.ComponentModel.Composition/src/System/ComponentModel/Composition/Hosting/CompositionContainer.cs
+++ b/src/System.ComponentModel.Composition/src/System/ComponentModel/Composition/Hosting/CompositionContainer.cs
@@ -11,8 +11,6 @@ using System.Diagnostics.Contracts;
using System.Threading;
using Microsoft.Internal;
-[assembly: System.Runtime.CompilerServices.TypeForwardedTo(destination: typeof(System.Lazy<,>))]
-
namespace System.ComponentModel.Composition.Hosting
{
public partial class CompositionContainer : ExportProvider, ICompositionService, IDisposable
diff --git a/src/System.ComponentModel.Composition/src/TypeForwards.cs b/src/System.ComponentModel.Composition/src/TypeForwards.cs
new file mode 100644
index 0000000000..75d9fb1a81
--- /dev/null
+++ b/src/System.ComponentModel.Composition/src/TypeForwards.cs
@@ -0,0 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+[assembly: System.Runtime.CompilerServices.TypeForwardedTo(destination: typeof(System.Lazy<,>))] \ No newline at end of file
diff --git a/src/System.ComponentModel.Composition/tests/Configurations.props b/src/System.ComponentModel.Composition/tests/Configurations.props
index 02721ef2a9..e81ce94290 100644
--- a/src/System.ComponentModel.Composition/tests/Configurations.props
+++ b/src/System.ComponentModel.Composition/tests/Configurations.props
@@ -4,6 +4,7 @@
<BuildConfigurations>
netcoreapp;
uap;
+ _netfx;
</BuildConfigurations>
</PropertyGroup>
</Project>
diff --git a/src/System.ComponentModel.Composition/tests/System.ComponentModel.Composition.Noop.Assembly/Configurations.props b/src/System.ComponentModel.Composition/tests/System.ComponentModel.Composition.Noop.Assembly/Configurations.props
new file mode 100644
index 0000000000..77a4b65bc9
--- /dev/null
+++ b/src/System.ComponentModel.Composition/tests/System.ComponentModel.Composition.Noop.Assembly/Configurations.props
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <BuildConfigurations>
+ netstandard;
+ netcoreapp;
+ </BuildConfigurations>
+ </PropertyGroup>
+</Project> \ No newline at end of file
diff --git a/src/System.ComponentModel.Composition/tests/System.ComponentModel.Composition.Noop.Assembly/System.ComponentModel.Composition.Noop.Assembly.csproj b/src/System.ComponentModel.Composition/tests/System.ComponentModel.Composition.Noop.Assembly/System.ComponentModel.Composition.Noop.Assembly.csproj
new file mode 100644
index 0000000000..12c34c5bbb
--- /dev/null
+++ b/src/System.ComponentModel.Composition/tests/System.ComponentModel.Composition.Noop.Assembly/System.ComponentModel.Composition.Noop.Assembly.csproj
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <ProjectGuid>{396D6EBF-60BD-4DAF-8783-FB403E070A56}</ProjectGuid>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
+ <ItemGroup>
+ <Compile Include="TestClass.cs" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project> \ No newline at end of file
diff --git a/src/System.IO.FileSystem/src/System/IO/FindTransform.cs b/src/System.ComponentModel.Composition/tests/System.ComponentModel.Composition.Noop.Assembly/TestClass.cs
index c1b6b71972..75e7475012 100644
--- a/src/System.IO.FileSystem/src/System/IO/FindTransform.cs
+++ b/src/System.ComponentModel.Composition/tests/System.ComponentModel.Composition.Noop.Assembly/TestClass.cs
@@ -2,10 +2,10 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-namespace System.IO
+namespace System.ComponentModel.Composition.Noop.Assembly
{
- /// <summary>
- /// Delegate for transforming raw find data into a result.
- /// </summary>
- internal delegate T FindTransform<T>(ref RawFindData findData);
+ [Export]
+ public class TestClass
+ {
+ }
}
diff --git a/src/System.ComponentModel.Composition/tests/System.ComponentModel.Composition.Tests.csproj b/src/System.ComponentModel.Composition/tests/System.ComponentModel.Composition.Tests.csproj
index 72fe4fde46..4fa3445ffb 100644
--- a/src/System.ComponentModel.Composition/tests/System.ComponentModel.Composition.Tests.csproj
+++ b/src/System.ComponentModel.Composition/tests/System.ComponentModel.Composition.Tests.csproj
@@ -187,5 +187,15 @@
<Compile Include="TestAssembly.cs" />
<Compile Include="TransparentTestCase.cs" />
</ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="System.ComponentModel.Composition.Noop.Assembly/System.ComponentModel.Composition.Noop.Assembly.csproj">
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ <OutputItemType>content</OutputItemType>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </ProjectReference>
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/CompositionContainerTests.cs b/src/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/CompositionContainerTests.cs
index 6c53aba881..b993820041 100644
--- a/src/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/CompositionContainerTests.cs
+++ b/src/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/CompositionContainerTests.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
+using System.Collections.ObjectModel;
using System.ComponentModel.Composition.Factories;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;
@@ -3022,6 +3023,23 @@ namespace System.ComponentModel.Composition
Assert.Null(container.GetExportedValue<string>("Property"));
}
+ [Fact]
+ public void TestExportedValueUsingWhereClause_ExportSuccessful()
+ {
+ CompositionContainer container = new CompositionContainer(new TypeCatalog(typeof(MefCollection<,>)));
+ IMefCollection<DerivedClass, BaseClass> actualValue = container.GetExportedValue<IMefCollection<DerivedClass, BaseClass>>("UsingWhereClause");
+ Assert.NotNull(actualValue);
+ Assert.IsType<MefCollection<DerivedClass, BaseClass>>(actualValue);
+ }
+
+ public interface IMefCollection { }
+ public interface IMefCollection<TC, TP> : IList<TC>, IMefCollection where TC : TP { }
+ public class BaseClass { }
+ public class DerivedClass : BaseClass { }
+
+ [Export("UsingWhereClause", typeof(IMefCollection<,>))]
+ public class MefCollection<TC, TP> : ObservableCollection<TC>, IMefCollection<TC, TP> where TC : TP { }
+
public class ExportsMutableProperty
{
[Export("Property")]
diff --git a/src/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/CompositionExceptionTests.cs b/src/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/CompositionExceptionTests.cs
index 0504111f91..6556d3c75c 100644
--- a/src/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/CompositionExceptionTests.cs
+++ b/src/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/CompositionExceptionTests.cs
@@ -400,6 +400,10 @@ namespace System.ComponentModel.Composition
private void AssertMessage(CompositionException exception, int rootCauseCount, CultureInfo culture)
{
+ if (PlatformDetection.IsNetNative)
+ {
+ return;
+ }
using (StringReader reader = new StringReader(exception.Message))
{
string line = reader.ReadLine();
@@ -420,6 +424,10 @@ namespace System.ComponentModel.Composition
private void AssertMessage(CompositionException exception, string[] expected)
{
+ if (PlatformDetection.IsNetNative)
+ {
+ return;
+ }
using (StringReader reader = new StringReader(exception.Message))
{
// Skip header
diff --git a/src/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/Hosting/AssemblyCatalogTests.cs b/src/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/Hosting/AssemblyCatalogTests.cs
index b3d0ff6e98..b5e8d4cb9e 100644
--- a/src/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/Hosting/AssemblyCatalogTests.cs
+++ b/src/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/Hosting/AssemblyCatalogTests.cs
@@ -78,35 +78,35 @@ namespace System.ComponentModel.Composition
string filename = Path.GetTempFileName();
using (FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.None))
{
- Assert.Throws<FileLoadException>(() =>
+ if (PlatformDetection.IsWindows) // File locking is Windows specific.
{
- var catalog = catalogCreator(filename);
- });
+ Assert.Throws<FileLoadException>(() => catalogCreator(filename));
+ }
+ else
+ {
+ Assert.Throws<BadImageFormatException>(() => catalogCreator(filename));
+ }
}
}
public static void Constructor_NullFileNameAsCodeBaseArgument_ShouldThrowArgumentNull(Func<string, AssemblyCatalog> catalogCreator)
{
- Assert.Throws<ArgumentNullException>("codeBase", () =>
- {
- var catalog = catalogCreator((string)null);
- });
+ Assert.Throws<ArgumentNullException>("codeBase", () => catalogCreator(null));
}
public static void Constructor_EmptyFileNameAsCodeBaseArgument_ShouldThrowArgument(Func<string, AssemblyCatalog> catalogCreator)
{
- Assert.Throws<ArgumentException>("codeBase", () =>
- {
- var catalog = catalogCreator("");
- });
+ Assert.Throws<ArgumentException>("codeBase", () => catalogCreator(""));
}
public static void Constructor_InvalidFileNameAsCodeBaseArgument_ShouldThrowArgument(Func<string, AssemblyCatalog> catalogCreator)
{
- Assert.Throws<ArgumentException>(() =>
- {
- var catalog = catalogCreator("??||>");
- });
+ Assert.Throws<ArgumentException>(() => catalogCreator("??||>"));
+ }
+
+ public static void Constructor_InvalidFileNameAsCodeBaseArgument_ShouldThrowIO(Func<string, AssemblyCatalog> catalogCreator)
+ {
+ Assert.ThrowsAny<IOException>(() => catalogCreator("??||>"));
}
public static void Constructor_DirectoryAsCodeBaseArgument_ShouldThrowFileLoad(Func<string, AssemblyCatalog> catalogCreator)
@@ -114,35 +114,24 @@ namespace System.ComponentModel.Composition
string directory = Environment.GetFolderPath(Environment.SpecialFolder.System);
Assert.True(Directory.Exists(directory));
- Assert.Throws<FileLoadException>(() =>
- {
- var catalog = catalogCreator(directory);
- });
+ Assert.Throws<FileLoadException>(() => catalogCreator(directory));
}
public static void Constructor_TooLongFileNameAsCodeBaseArgument_ShouldThrowPathTooLong(Func<string, AssemblyCatalog> catalogCreator)
{
Assert.Throws<PathTooLongException>(() =>
- {
- var catalog = catalogCreator(@"c:\This is a very long path\And Just to make sure\We will continue to make it very long\This is a very long path\And Just to make sure\We will continue to make it very long\This is a very long path\And Just to make sure\We will continue to make it very long\myassembly.dll");
- });
+ catalogCreator(@"c:\This is a very long path\And Just to make sure\We will continue to make it very long\This is a very long path\And Just to make sure\We will continue to make it very long\This is a very long path\And Just to make sure\We will continue to make it very long\myassembly.dll"));
}
public static void Constructor_NonAssemblyFileNameAsCodeBaseArgument_ShouldThrowBadImageFormat(Func<string, AssemblyCatalog> catalogCreator)
{
string filename = Path.GetTempFileName();
- Assert.Throws<BadImageFormatException>(() =>
- {
- var catalog = catalogCreator(filename);
- });
+ Assert.Throws<BadImageFormatException>(() => catalogCreator(filename));
}
public static void Constructor_NonExistentFileNameAsCodeBaseArgument_ShouldThrowFileNotFound(Func<string, AssemblyCatalog> catalogCreator)
{
- Assert.Throws<FileNotFoundException>(() =>
- {
- var catalog = catalogCreator(@"FileThat should not ever exist");
- });
+ Assert.Throws<FileNotFoundException>(() => catalogCreator(@"FileThat should not ever exist"));
}
// Test Assembly variant of the APIs
@@ -160,18 +149,12 @@ namespace System.ComponentModel.Composition
public static void Constructor_NullReflectionContextArgument_ShouldThrowArgumentNull(Func<ReflectionContext, AssemblyCatalog> catalogCreator)
{
- AssertExtensions.Throws<ArgumentNullException>("reflectionContext", () =>
- {
- var catalog = catalogCreator(null);
- });
+ AssertExtensions.Throws<ArgumentNullException>("reflectionContext", () => catalogCreator(null));
}
public static void Constructor_NullDefinitionOriginArgument_ShouldThrowArgumentNull(Func<ICompositionElement, AssemblyCatalog> catalogCreator)
{
- AssertExtensions.Throws<ArgumentNullException>("definitionOrigin", () =>
- {
- var catalog = catalogCreator(null);
- });
+ AssertExtensions.Throws<ArgumentNullException>("definitionOrigin", () => catalogCreator(null));
}
//=========================================================================================================================================
@@ -215,8 +198,8 @@ namespace System.ComponentModel.Composition
}
[Fact]
- [ActiveIssue(25498, TestPlatforms.AnyUnix)]
- public void Constructor1_InvalidFileNameAsCodeBaseArgument_ShouldThrowArgument()
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)]
+ public void Constructor1_InvalidFileNameAsCodeBaseArgument_ShouldThrowArgument_Desktop()
{
AssemblyCatalogConstructorTests.Constructor_InvalidFileNameAsCodeBaseArgument_ShouldThrowArgument((s) =>
{
@@ -225,6 +208,17 @@ namespace System.ComponentModel.Composition
}
[Fact]
+ [ActiveIssue(25498)] // Also see https://github.com/dotnet/corefx/issues/27269
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void Constructor1_InvalidFileNameAsCodeBaseArgument_ShouldThrowIO_Core()
+ {
+ AssemblyCatalogConstructorTests.Constructor_InvalidFileNameAsCodeBaseArgument_ShouldThrowIO((s) =>
+ {
+ return new AssemblyCatalog(s);
+ });
+ }
+
+ [Fact]
[ActiveIssue(25498)]
public void Constructor1_DirectoryAsCodeBaseArgument_ShouldThrowFileLoad()
{
@@ -314,8 +308,8 @@ namespace System.ComponentModel.Composition
}
[Fact]
- [ActiveIssue(25498, TestPlatforms.AnyUnix)]
- public void Constructor2_InvalidFileNameAsCodeBaseArgument_ShouldThrowArgument()
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)]
+ public void Constructor2_InvalidFileNameAsCodeBaseArgument_ShouldThrowArgument_Desktop()
{
AssemblyCatalogConstructorTests.Constructor_InvalidFileNameAsCodeBaseArgument_ShouldThrowArgument((s) =>
{
@@ -324,6 +318,17 @@ namespace System.ComponentModel.Composition
}
[Fact]
+ [ActiveIssue(25498)] // Also see https://github.com/dotnet/corefx/issues/27269
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void Constructor2_InvalidFileNameAsCodeBaseArgument_ShouldThrowArgument()
+ {
+ AssemblyCatalogConstructorTests.Constructor_InvalidFileNameAsCodeBaseArgument_ShouldThrowIO((s) =>
+ {
+ return new AssemblyCatalog(s, new AssemblyCatalogTestsReflectionContext());
+ });
+ }
+
+ [Fact]
[ActiveIssue(25498)]
public void Constructor2_DirectoryAsCodeBaseArgument_ShouldThrowFileLoad()
{
@@ -412,7 +417,7 @@ namespace System.ComponentModel.Composition
}
[Fact]
- [ActiveIssue(25498, TestPlatforms.AnyUnix)]
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)]
public void Constructor3_InvalidFileNameAsCodeBaseArgument_ShouldThrowArgument()
{
AssemblyCatalogConstructorTests.Constructor_InvalidFileNameAsCodeBaseArgument_ShouldThrowArgument((s) =>
@@ -422,6 +427,17 @@ namespace System.ComponentModel.Composition
}
[Fact]
+ [ActiveIssue(25498)] // // Also see https://github.com/dotnet/corefx/issues/27269
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void Constructor3_InvalidFileNameAsCodeBaseArgument_ShouldThrowIO_Core()
+ {
+ AssemblyCatalogConstructorTests.Constructor_InvalidFileNameAsCodeBaseArgument_ShouldThrowIO((s) =>
+ {
+ return new AssemblyCatalog(s, (ICompositionElement)new AssemblyCatalog(s));
+ });
+ }
+
+ [Fact]
[ActiveIssue(25498)]
public void Constructor3_DirectoryAsCodeBaseArgument_ShouldThrowFileLoad()
{
@@ -509,8 +525,8 @@ namespace System.ComponentModel.Composition
}
[Fact]
- [ActiveIssue(25498, TestPlatforms.AnyUnix)]
- public void Constructor4_InvalidFileNameAsCodeBaseArgument_ShouldThrowArgument()
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)]
+ public void Constructor4_InvalidFileNameAsCodeBaseArgument_ShouldThrowArgument_Desktop()
{
AssemblyCatalogConstructorTests.Constructor_InvalidFileNameAsCodeBaseArgument_ShouldThrowArgument((s) =>
{
@@ -519,6 +535,17 @@ namespace System.ComponentModel.Composition
}
[Fact]
+ [ActiveIssue(25498)] // Also see https://github.com/dotnet/corefx/issues/27269
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void Constructor4_InvalidFileNameAsCodeBaseArgument_ShouldThrowIO_Core()
+ {
+ AssemblyCatalogConstructorTests.Constructor_InvalidFileNameAsCodeBaseArgument_ShouldThrowIO((s) =>
+ {
+ return new AssemblyCatalog(s, new AssemblyCatalogTestsReflectionContext(), (ICompositionElement)new AssemblyCatalog(s));
+ });
+ }
+
+ [Fact]
[ActiveIssue(25498)]
public void Constructor4_DirectoryAsCodeBaseArgument_ShouldThrowFileLoad()
{
@@ -780,10 +807,7 @@ namespace System.ComponentModel.Composition
catalog.Dispose();
var definition = ImportDefinitionFactory.Create();
- ExceptionAssert.ThrowsDisposed(catalog, () =>
- {
- catalog.GetExports(definition);
- });
+ ExceptionAssert.ThrowsDisposed(catalog, () => catalog.GetExports(definition));
}
[Fact]
@@ -792,10 +816,7 @@ namespace System.ComponentModel.Composition
{
var catalog = CreateAssemblyCatalog();
- AssertExtensions.Throws<ArgumentNullException>("definition", () =>
- {
- catalog.GetExports((ImportDefinition)null);
- });
+ AssertExtensions.Throws<ArgumentNullException>("definition", () => catalog.GetExports(null));
}
[Fact]
@@ -1060,5 +1081,18 @@ namespace System.ComponentModel.Composition
Assert.Equal(catalog.DisplayName, catalog.ToString());
}
}
+
+ [Fact]
+ public void NonStaticallyReferencedAssembly()
+ {
+ string testAssembly = "System.ComponentModel.Composition.Noop.Assembly.dll";
+ var directory = TemporaryFileCopier.GetNewTemporaryDirectory();
+ Directory.CreateDirectory(directory);
+ var finalPath = Path.Combine(directory, testAssembly);
+ var sourcePath = Path.Combine(Directory.GetCurrentDirectory(), testAssembly);
+ File.Copy(sourcePath, finalPath);
+ var assemblyCatalog = new AssemblyCatalog(finalPath);
+ Assert.NotEmpty(assemblyCatalog);
+ }
}
}
diff --git a/src/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/Hosting/DirectoryCatalogTests.cs b/src/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/Hosting/DirectoryCatalogTests.cs
index 794e77943c..5d7613c369 100644
--- a/src/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/Hosting/DirectoryCatalogTests.cs
+++ b/src/System.ComponentModel.Composition/tests/System/ComponentModel/Composition/Hosting/DirectoryCatalogTests.cs
@@ -229,16 +229,6 @@ namespace System.ComponentModel.Composition
}
[Fact]
- [ActiveIssue(25498, TestPlatforms.AnyUnix)] // typeof(System.IO.DirectoryNotFoundException): Could not find a part of the path '/HOME/HELIXBOT/DOTNETBUILD/WORK/E77C2FB6-5244-4437-8E27-6DD709101152/WORK/D9EBA0EA-A511-4F42-AC8B-AC8054AAF606/UNZIP/HTTP:/MICROSOFT.COM/MYASSEMBLY.DLL'.
- public void AddAssembly1_NonExistentUriAsAssemblyFileNameArgument_ShouldNotSupportedException()
- {
- Assert.Throws<NotSupportedException>(() =>
- {
- var catalog = new DirectoryCatalog("http://microsoft.com/myassembly.dll");
- });
- }
-
- [Fact]
public void AddAssembly1_NullPathArgument_ShouldThrowArugmentNull()
{
Assert.Throws<ArgumentNullException>(() =>
@@ -253,16 +243,6 @@ namespace System.ComponentModel.Composition
}
[Fact]
- [ActiveIssue(25498, TestPlatforms.AnyUnix)] // typeof(System.IO.DirectoryNotFoundException): Could not find a part of the path '/HOME/HELIXBOT/DOTNETBUILD/WORK/E77C2FB6-5244-4437-8E27-6DD709101152/WORK/D9EBA0EA-A511-4F42-AC8B-AC8054AAF606/UNZIP/*'.
- public void AddAssembly1_InvalidPathName_ShouldThrowDirectoryNotFound()
- {
- Assert.Throws<ArgumentException>(() =>
- {
- var c1 = new DirectoryCatalog("*");
- });
- }
-
- [Fact]
[ActiveIssue(25498)]
public void AddAssembly1_TooLongPathNameArgument_ShouldThrowPathTooLongException()
{
@@ -364,6 +344,19 @@ namespace System.ComponentModel.Composition
}
[Fact]
+ public void LoadedFiles_NonStaticallyReferencedAssembly()
+ {
+ string testAssembly = "System.ComponentModel.Composition.Noop.Assembly.dll";
+ var directory = TemporaryFileCopier.GetNewTemporaryDirectory();
+ Directory.CreateDirectory(directory);
+ var finalPath = Path.Combine(directory, testAssembly);
+ var sourcePath = Path.Combine(Directory.GetCurrentDirectory(), testAssembly);
+ File.Copy(sourcePath, finalPath);
+ var catalog = new DirectoryCatalog(directory, "*.dll");
+ Assert.NotEmpty(catalog);
+ }
+
+ [Fact]
public void Constructor_InvalidAssembly_ShouldBeFine()
{
using (File.CreateText(Path.Combine(TemporaryFileCopier.GetTemporaryDirectory(), "Test.dll"))) { }
diff --git a/src/System.ComponentModel.Primitives/src/FxCopBaseline.cs b/src/System.ComponentModel.Primitives/src/FxCopBaseline.cs
index b702751c5d..4175d27701 100644
--- a/src/System.ComponentModel.Primitives/src/FxCopBaseline.cs
+++ b/src/System.ComponentModel.Primitives/src/FxCopBaseline.cs
@@ -1,3 +1,7 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.ComponentModel.Component.#Dispose(System.Boolean)")]
diff --git a/src/System.ComponentModel.TypeConverter/src/System.ComponentModel.TypeConverter.csproj b/src/System.ComponentModel.TypeConverter/src/System.ComponentModel.TypeConverter.csproj
index 2d7b02cd61..8ab0533cdf 100644
--- a/src/System.ComponentModel.TypeConverter/src/System.ComponentModel.TypeConverter.csproj
+++ b/src/System.ComponentModel.TypeConverter/src/System.ComponentModel.TypeConverter.csproj
@@ -7,8 +7,6 @@
<AssemblyName>System.ComponentModel.TypeConverter</AssemblyName>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<IsPartialFacadeAssembly>true</IsPartialFacadeAssembly>
- <!-- TODO: RE-ENABLE THIS -->
- <EnablePInvokeAnalyzer>false</EnablePInvokeAnalyzer>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
diff --git a/src/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesignerOptionService.cs b/src/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesignerOptionService.cs
index 9088ef3fd6..4e4358ed03 100644
--- a/src/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesignerOptionService.cs
+++ b/src/System.ComponentModel.TypeConverter/src/System/ComponentModel/Design/DesignerOptionService.cs
@@ -154,6 +154,7 @@ namespace System.ComponentModel.Design
if (Parent != null)
{
+ parent._properties = null;
if (Parent._children == null)
{
Parent._children = new ArrayList(1);
diff --git a/src/System.ComponentModel.TypeConverter/src/System/ComponentModel/MemberDescriptor.cs b/src/System.ComponentModel.TypeConverter/src/System/ComponentModel/MemberDescriptor.cs
index 73122b15dc..9ab50a171b 100644
--- a/src/System.ComponentModel.TypeConverter/src/System/ComponentModel/MemberDescriptor.cs
+++ b/src/System.ComponentModel.TypeConverter/src/System/ComponentModel/MemberDescriptor.cs
@@ -377,16 +377,20 @@ namespace System.ComponentModel
list = new List<Attribute>(_attributes);
}
- var set = new HashSet<object>();
+ var map = new Dictionary<object, int>();
for (int i = 0; i < list.Count;)
{
- if (set.Add(list[i].TypeId))
+ int savedIndex = -1;
+ object typeId = list[i].TypeId;
+ if (!map.TryGetValue(typeId, out savedIndex))
{
- ++i;
+ map.Add(typeId, i);
+ i++;
}
else
{
+ list[savedIndex] = list[i];
list.RemoveAt(i);
}
}
diff --git a/src/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs b/src/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs
index 13607f0031..cc4987c190 100644
--- a/src/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs
+++ b/src/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs
@@ -1916,7 +1916,7 @@ namespace System.ComponentModel
}
catch (InvalidCastException)
{
- throw new ArgumentException(SR.GetResourceString(SR.TypeDescriptorExpectedElementType, typeof(Attribute).FullName));
+ throw new ArgumentException(SR.Format(SR.TypeDescriptorExpectedElementType, typeof(Attribute).FullName));
}
cacheValue = new AttributeCollection(attrArray);
break;
@@ -1929,7 +1929,7 @@ namespace System.ComponentModel
}
catch (InvalidCastException)
{
- throw new ArgumentException(SR.GetResourceString(SR.TypeDescriptorExpectedElementType, typeof(PropertyDescriptor).FullName));
+ throw new ArgumentException(SR.Format(SR.TypeDescriptorExpectedElementType, typeof(PropertyDescriptor).FullName));
}
cacheValue = new PropertyDescriptorCollection(propArray, true);
break;
@@ -1942,7 +1942,7 @@ namespace System.ComponentModel
}
catch (InvalidCastException)
{
- throw new ArgumentException(SR.GetResourceString(SR.TypeDescriptorExpectedElementType, typeof(EventDescriptor).FullName));
+ throw new ArgumentException(SR.Format(SR.TypeDescriptorExpectedElementType, typeof(EventDescriptor).FullName));
}
cacheValue = new EventDescriptorCollection(eventArray, true);
break;
diff --git a/src/System.ComponentModel.TypeConverter/src/System/ComponentModel/UInt16Converter.cs b/src/System.ComponentModel.TypeConverter/src/System/ComponentModel/UInt16Converter.cs
index d18a2555e6..0f01295f89 100644
--- a/src/System.ComponentModel.TypeConverter/src/System/ComponentModel/UInt16Converter.cs
+++ b/src/System.ComponentModel.TypeConverter/src/System/ComponentModel/UInt16Converter.cs
@@ -15,7 +15,7 @@ namespace System.ComponentModel
/// <summary>
/// The Type this converter is targeting (e.g. Int16, UInt32, etc.)
/// </summary>
- internal override Type TargetType => typeof(short);
+ internal override Type TargetType => typeof(ushort);
/// <summary>
/// Convert the given value to a string using the given radix
diff --git a/src/System.ComponentModel.TypeConverter/tests/ArrayConverterTests.cs b/src/System.ComponentModel.TypeConverter/tests/ArrayConverterTests.cs
index ca0ca8285e..19e987903e 100644
--- a/src/System.ComponentModel.TypeConverter/tests/ArrayConverterTests.cs
+++ b/src/System.ComponentModel.TypeConverter/tests/ArrayConverterTests.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Globalization;
using Xunit;
namespace System.ComponentModel.Tests
@@ -11,11 +12,16 @@ namespace System.ComponentModel.Tests
[Fact]
public static void ConvertTo_WithContext()
{
- ConvertTo_WithContext(new object[1, 3]
- {
- { new int[2] { 1, 2 }, "Int32[] Array", null }
- },
- new ArrayConverter());
+ RemoteInvoke(() =>
+ {
+ CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture;
+
+ ConvertTo_WithContext(new object[1, 3]
+ {
+ { new int[2] { 1, 2 }, "Int32[] Array", null }
+ },
+ new ArrayConverter());
+ }).Dispose();
}
}
}
diff --git a/src/System.ComponentModel.TypeConverter/tests/CollectionConverterTests.cs b/src/System.ComponentModel.TypeConverter/tests/CollectionConverterTests.cs
index 74799c5c6e..535464e92d 100644
--- a/src/System.ComponentModel.TypeConverter/tests/CollectionConverterTests.cs
+++ b/src/System.ComponentModel.TypeConverter/tests/CollectionConverterTests.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Globalization;
using Xunit;
namespace System.ComponentModel.Tests
@@ -13,11 +14,16 @@ namespace System.ComponentModel.Tests
[Fact]
public static void ConvertTo_WithContext()
{
- ConvertTo_WithContext(new object[1, 3]
- {
- { new Collection1(), "(Collection)", null }
- },
- CollectionConverterTests.s_converter);
+ RemoteInvoke(() =>
+ {
+ CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture;
+
+ ConvertTo_WithContext(new object[1, 3]
+ {
+ { new Collection1(), "(Collection)", null }
+ },
+ CollectionConverterTests.s_converter);
+ }).Dispose();
}
}
}
diff --git a/src/System.ComponentModel.TypeConverter/tests/CultureInfoConverterTests.cs b/src/System.ComponentModel.TypeConverter/tests/CultureInfoConverterTests.cs
index 5581e52c23..f6196037db 100644
--- a/src/System.ComponentModel.TypeConverter/tests/CultureInfoConverterTests.cs
+++ b/src/System.ComponentModel.TypeConverter/tests/CultureInfoConverterTests.cs
@@ -11,19 +11,16 @@
//
using System.ComponentModel.Design.Serialization;
+using System.Diagnostics;
using System.Globalization;
+using System.Runtime.InteropServices;
using Xunit;
namespace System.ComponentModel.Tests
{
- public class CultureInfoConverterTest
+ public class CultureInfoConverterTest : RemoteExecutorTestBase
{
- private CultureInfoConverter converter;
-
- public CultureInfoConverterTest()
- {
- converter = new CultureInfoConverter();
- }
+ private CultureInfoConverter converter => new CultureInfoConverter();
[Fact]
public void CanConvertFrom()
@@ -153,13 +150,18 @@ namespace System.ComponentModel.Tests
[Fact]
public void ConvertFrom_Value_Null()
{
- NotSupportedException ex = Assert.Throws<NotSupportedException>(() => converter.ConvertFrom(null, CultureInfo.InvariantCulture, (string)null));
- // CultureInfoConverter cannot convert from (null)
- Assert.Equal(typeof(NotSupportedException), ex.GetType());
- Assert.Null(ex.InnerException);
- Assert.NotNull(ex.Message);
- Assert.True(ex.Message.IndexOf(typeof(CultureInfoConverter).Name) != -1);
- Assert.True(ex.Message.IndexOf("(null)") != -1);
+ RemoteInvoke(() =>
+ {
+ CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture;
+
+ NotSupportedException ex = Assert.Throws<NotSupportedException>(() => converter.ConvertFrom(null, CultureInfo.InvariantCulture, (string)null));
+ // CultureInfoConverter cannot convert from (null)
+ Assert.Equal(typeof(NotSupportedException), ex.GetType());
+ Assert.Null(ex.InnerException);
+ Assert.NotNull(ex.Message);
+ Assert.True(ex.Message.IndexOf(typeof(CultureInfoConverter).Name) != -1);
+ Assert.True(ex.Message.IndexOf("(null)") != -1);
+ }).Dispose();
}
[Fact]
diff --git a/src/System.ComponentModel.TypeConverter/tests/DateTimeConverterTests.cs b/src/System.ComponentModel.TypeConverter/tests/DateTimeConverterTests.cs
index 349f945b4e..0ae2640a47 100644
--- a/src/System.ComponentModel.TypeConverter/tests/DateTimeConverterTests.cs
+++ b/src/System.ComponentModel.TypeConverter/tests/DateTimeConverterTests.cs
@@ -66,7 +66,7 @@ namespace System.ComponentModel.Tests
DateTimeConverterTests.s_converter);
return SuccessExitCode;
- });
+ }).Dispose();
}
}
}
diff --git a/src/System.ComponentModel.TypeConverter/tests/DateTimeOffsetConverterTests.cs b/src/System.ComponentModel.TypeConverter/tests/DateTimeOffsetConverterTests.cs
index 2c4712185b..3bea6a9766 100644
--- a/src/System.ComponentModel.TypeConverter/tests/DateTimeOffsetConverterTests.cs
+++ b/src/System.ComponentModel.TypeConverter/tests/DateTimeOffsetConverterTests.cs
@@ -68,7 +68,7 @@ namespace System.ComponentModel.Tests
DateTimeOffsetConverterTests.s_converter);
return SuccessExitCode;
- });
+ }).Dispose();
}
}
}
diff --git a/src/System.ComponentModel.TypeConverter/tests/Design/DesignerOptionServiceTests.cs b/src/System.ComponentModel.TypeConverter/tests/Design/DesignerOptionServiceTests.cs
index b44922d2a7..1fb189afaa 100644
--- a/src/System.ComponentModel.TypeConverter/tests/Design/DesignerOptionServiceTests.cs
+++ b/src/System.ComponentModel.TypeConverter/tests/Design/DesignerOptionServiceTests.cs
@@ -4,12 +4,14 @@
using System.Collections;
using System.ComponentModel.DataAnnotations;
+using System.Diagnostics;
+using System.Globalization;
using System.Linq;
using Xunit;
namespace System.ComponentModel.Design.Tests
{
- public class DesignerOptionServiceTests
+ public class DesignerOptionServiceTests : RemoteExecutorTestBase
{
[Fact]
public void CreateOptionCollection_CreateMultipleTimes_ReturnsExpected()
@@ -180,13 +182,14 @@ namespace System.ComponentModel.Design.Tests
}
[Fact]
- public void Properties_GetBeforeAddingChild_ReturnsEmpty()
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void Properties_GetBeforeAddingChild_ReturnsNonEmpty()
{
var service = new TestDesignerOptionService();
Assert.Empty(service.Options.Properties);
DesignerOptionService.DesignerOptionCollection options = service.DoCreateOptionCollection(service.Options, "name", "value");
- Assert.Empty(service.Options.Properties);
+ Assert.NotEmpty(service.Options.Properties);
}
[Fact]
@@ -265,8 +268,13 @@ namespace System.ComponentModel.Design.Tests
[Fact]
public void DesignerOptionConverter_ConvertToString_ReturnsExpected()
{
- TypeConverter converter = TypeDescriptor.GetConverter(typeof(DesignerOptionService.DesignerOptionCollection));
- Assert.Equal("(Collection)", converter.ConvertToString(null));
+ RemoteInvoke(() =>
+ {
+ CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture;
+
+ TypeConverter converter = TypeDescriptor.GetConverter(typeof(DesignerOptionService.DesignerOptionCollection));
+ Assert.Equal("(Collection)", converter.ConvertToString(null));
+ }).Dispose();
}
[Fact]
diff --git a/src/System.ComponentModel.TypeConverter/tests/MultilineStringConverterTests.cs b/src/System.ComponentModel.TypeConverter/tests/MultilineStringConverterTests.cs
index 038f3af1fb..a357b88603 100644
--- a/src/System.ComponentModel.TypeConverter/tests/MultilineStringConverterTests.cs
+++ b/src/System.ComponentModel.TypeConverter/tests/MultilineStringConverterTests.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Globalization;
using Xunit;
namespace System.ComponentModel.Tests
@@ -11,11 +12,16 @@ namespace System.ComponentModel.Tests
[Fact]
public static void ConvertTo_WithContext()
{
- ConvertTo_WithContext(new object[1, 3]
- {
- { "any string", "(Text)", null }
- },
- new MultilineStringConverter());
+ RemoteInvoke(() =>
+ {
+ CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture;
+
+ ConvertTo_WithContext(new object[1, 3]
+ {
+ { "any string", "(Text)", null }
+ },
+ new MultilineStringConverter());
+ }).Dispose();
}
}
}
diff --git a/src/System.ComponentModel.TypeConverter/tests/ReferenceConverterTests.cs b/src/System.ComponentModel.TypeConverter/tests/ReferenceConverterTests.cs
index 24b49ef60f..1acbae7708 100644
--- a/src/System.ComponentModel.TypeConverter/tests/ReferenceConverterTests.cs
+++ b/src/System.ComponentModel.TypeConverter/tests/ReferenceConverterTests.cs
@@ -33,11 +33,13 @@
using System.Collections.Generic;
using System.ComponentModel.Design;
+using System.Diagnostics;
+using System.Globalization;
using Xunit;
namespace System.ComponentModel.Tests
{
- public class ReferenceConverterTest
+ public class ReferenceConverterTest : RemoteExecutorTestBase
{
class TestReferenceService : IReferenceService
@@ -197,11 +199,16 @@ namespace System.ComponentModel.Tests
[Fact]
public void ConvertTo()
{
- ReferenceConverter converter = new ReferenceConverter(typeof(ITestInterface));
- string referenceName = "reference name";
+ RemoteInvoke(() =>
+ {
+ CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture;
- Assert.Equal("(none)", (string)converter.ConvertTo(null, null, null, typeof(string)));
+ ReferenceConverter remoteConverter = new ReferenceConverter(typeof(ITestInterface));
+ Assert.Equal("(none)", (string)remoteConverter.ConvertTo(null, null, null, typeof(string)));
+ }).Dispose();
+ ReferenceConverter converter = new ReferenceConverter(typeof(ITestInterface));
+ string referenceName = "reference name";
TestComponent component = new TestComponent();
// no context
diff --git a/src/System.ComponentModel.TypeConverter/tests/TypeConverterTests.cs b/src/System.ComponentModel.TypeConverter/tests/TypeConverterTests.cs
index 51041e28e9..781d5dca61 100644
--- a/src/System.ComponentModel.TypeConverter/tests/TypeConverterTests.cs
+++ b/src/System.ComponentModel.TypeConverter/tests/TypeConverterTests.cs
@@ -110,7 +110,7 @@ namespace System.ComponentModel.Tests
Assert.NotNull(s);
Assert.Equal(FormattableClass.Token, s);
return SuccessExitCode;
- });
+ }).Dispose();
}
[Fact]
diff --git a/src/System.ComponentModel.TypeConverter/tests/TypeDescriptorTests.cs b/src/System.ComponentModel.TypeConverter/tests/TypeDescriptorTests.cs
index 9c78e5ed3a..ef7efcb5a8 100644
--- a/src/System.ComponentModel.TypeConverter/tests/TypeDescriptorTests.cs
+++ b/src/System.ComponentModel.TypeConverter/tests/TypeDescriptorTests.cs
@@ -160,6 +160,13 @@ namespace System.ComponentModel.Tests
Assert.NotEqual(firstAssociatedObject, firstAssociation);
}
+ [Fact]
+ public void DerivedPropertyAttribute() {
+ PropertyDescriptor property = TypeDescriptor.GetProperties(typeof(FooBarDerived))["Value"];
+ var descriptionAttribute = (DescriptionAttribute)property.Attributes[typeof(DescriptionAttribute)];
+ Assert.Equal("Derived", descriptionAttribute.Description);
+ }
+
private class InvocationRecordingTypeDescriptionProvider : TypeDescriptionProvider
{
public bool ReceivedCall { get; private set; } = false;
@@ -221,6 +228,18 @@ namespace System.ComponentModel.Tests
}
}
+ class FooBarBase
+ {
+ [Description("Base")]
+ public virtual int Value { get; set; }
+ }
+
+ class FooBarDerived : FooBarBase
+ {
+ [Description("Derived")]
+ public override int Value { get; set; }
+ }
+
private static Tuple<Type, Type>[] s_typesWithConverters =
{
new Tuple<Type, Type> (typeof(bool), typeof(BooleanConverter)),
diff --git a/src/System.ComponentModel.TypeConverter/tests/TypeListConverterTests.cs b/src/System.ComponentModel.TypeConverter/tests/TypeListConverterTests.cs
index 208bc4fc03..4940f7c0cb 100644
--- a/src/System.ComponentModel.TypeConverter/tests/TypeListConverterTests.cs
+++ b/src/System.ComponentModel.TypeConverter/tests/TypeListConverterTests.cs
@@ -36,12 +36,17 @@ namespace System.ComponentModel.Tests
[Fact]
public static void ConvertTo_WithContext()
{
- ConvertTo_WithContext(new object[2, 3]
- {
- { typeof(char), "System.Char", null }, // the base class is not verifying if this type is not in the list
- { null, "(none)", CultureInfo.InvariantCulture }
- },
- TypeListConverterTests.s_converter);
+ RemoteInvoke(() =>
+ {
+ CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture;
+
+ ConvertTo_WithContext(new object[2, 3]
+ {
+ { typeof(char), "System.Char", null }, // the base class is not verifying if this type is not in the list
+ { null, "(none)", CultureInfo.InvariantCulture }
+ },
+ TypeListConverterTests.s_converter);
+ }).Dispose();
}
[Fact]
diff --git a/src/System.ComponentModel.TypeConverter/tests/UInt16ConverterTests.cs b/src/System.ComponentModel.TypeConverter/tests/UInt16ConverterTests.cs
index 6f2ac18a0b..3747b525ba 100644
--- a/src/System.ComponentModel.TypeConverter/tests/UInt16ConverterTests.cs
+++ b/src/System.ComponentModel.TypeConverter/tests/UInt16ConverterTests.cs
@@ -41,5 +41,12 @@ namespace System.ComponentModel.Tests
},
UInt16ConverterTests.s_converter);
}
+
+ [Fact]
+ public static void ConvertFrom_InvalidValue_ExceptionMessageContainsTypeName()
+ {
+ Exception e = Assert.ThrowsAny<Exception>(() => s_converter.ConvertFrom("badvalue"));
+ Assert.Contains(typeof(ushort).Name, e.Message);
+ }
}
}
diff --git a/src/System.Composition.Runtime/src/System/Composition/CompositionContext.cs b/src/System.Composition.Runtime/src/System/Composition/CompositionContext.cs
index 1c1fc29b14..7498e135ac 100644
--- a/src/System.Composition.Runtime/src/System/Composition/CompositionContext.cs
+++ b/src/System.Composition.Runtime/src/System/Composition/CompositionContext.cs
@@ -34,7 +34,7 @@ namespace System.Composition
/// <exception cref="CompositionFailedException" />
public TExport GetExport<TExport>()
{
- return GetExport<TExport>((string)null);
+ return GetExport<TExport>(null);
}
/// <summary>
@@ -55,13 +55,12 @@ namespace System.Composition
/// <see cref="CompositionContext"/>.
/// </summary>
/// <param name="exportType">The type of the export to retrieve.</param>
- /// <param name="contractName">Optionally, a discriminator that constrains the selection of the export.</param>
/// <returns>An instance of the export.</returns>
/// <param name="export">The export if available, otherwise, null.</param>
/// <exception cref="CompositionFailedException" />
- public bool TryGetExport(Type exportType, string contractName, out object export)
+ public bool TryGetExport(Type exportType, out object export)
{
- return TryGetExport(new CompositionContract(exportType, contractName), out export);
+ return TryGetExport(exportType, null, out export);
}
/// <summary>
@@ -69,12 +68,17 @@ namespace System.Composition
/// <see cref="CompositionContext"/>.
/// </summary>
/// <param name="exportType">The type of the export to retrieve.</param>
+ /// <param name="contractName">Optionally, a discriminator that constrains the selection of the export.</param>
/// <returns>An instance of the export.</returns>
/// <param name="export">The export if available, otherwise, null.</param>
/// <exception cref="CompositionFailedException" />
- public bool TryGetExport(Type exportType, out object export)
+ public bool TryGetExport(Type exportType, string contractName, out object export)
{
- return TryGetExport(exportType, null, out export);
+ if (TryGetExport(new CompositionContract(exportType, contractName), out export))
+ return true;
+
+ export = default;
+ return false;
}
/// <summary>
@@ -87,7 +91,7 @@ namespace System.Composition
/// <exception cref="CompositionFailedException" />
public bool TryGetExport<TExport>(out TExport export)
{
- return TryGetExport<TExport>(null, out export);
+ return TryGetExport(null, out export);
}
/// <summary>
@@ -101,10 +105,9 @@ namespace System.Composition
/// <exception cref="CompositionFailedException" />
public bool TryGetExport<TExport>(string contractName, out TExport export)
{
- object untypedExport;
- if (!TryGetExport(typeof(TExport), contractName, out untypedExport))
+ if (!TryGetExport(typeof(TExport), contractName, out object untypedExport))
{
- export = default(TExport);
+ export = default;
return false;
}
@@ -121,7 +124,7 @@ namespace System.Composition
/// <exception cref="CompositionFailedException" />
public object GetExport(Type exportType)
{
- return GetExport(exportType, (string)null);
+ return GetExport(exportType, null);
}
/// <summary>
@@ -146,12 +149,10 @@ namespace System.Composition
/// <exception cref="CompositionFailedException" />
public object GetExport(CompositionContract contract)
{
- object export;
- if (!TryGetExport(contract, out export))
- throw new CompositionFailedException(
- string.Format(SR.CompositionContext_NoExportFoundForContract, contract));
+ if (TryGetExport(contract, out object export))
+ return export;
- return export;
+ throw new CompositionFailedException(SR.Format(SR.CompositionContext_NoExportFoundForContract, contract));
}
/// <summary>
@@ -162,7 +163,7 @@ namespace System.Composition
/// <exception cref="CompositionFailedException" />
public IEnumerable<object> GetExports(Type exportType)
{
- return GetExports(exportType, (string)null);
+ return GetExports(exportType, null);
}
/// <summary>
@@ -192,7 +193,7 @@ namespace System.Composition
/// <exception cref="CompositionFailedException" />
public IEnumerable<TExport> GetExports<TExport>()
{
- return GetExports<TExport>((string)null);
+ return GetExports<TExport>(null);
}
/// <summary>
diff --git a/src/System.Composition.Runtime/tests/CompositionContextTests.cs b/src/System.Composition.Runtime/tests/CompositionContextTests.cs
index 9455b69591..9e13a77402 100644
--- a/src/System.Composition.Runtime/tests/CompositionContextTests.cs
+++ b/src/System.Composition.Runtime/tests/CompositionContextTests.cs
@@ -61,9 +61,8 @@ namespace System.Composition.Tests
Assert.False(context.TryGetExport(out int export1));
Assert.Equal(0, export1);
- // Failure leaks through.
Assert.False(context.TryGetExport(typeof(int), out object export2));
- Assert.Equal(10, export2);
+ Assert.Equal(null, export2);
}
else
{
@@ -73,9 +72,8 @@ namespace System.Composition.Tests
Assert.False(context.TryGetExport(contractName, out int export1));
Assert.Equal(0, export1);
- // Failure leaks through.
Assert.False(context.TryGetExport(typeof(int), contractName, out object export2));
- Assert.Equal(10, export2);
+ Assert.Equal(null, export2);
}
}
}
diff --git a/src/System.Composition/tests/ConstraintTests.cs b/src/System.Composition/tests/ConstraintTests.cs
index ef26d31153..fd0012a12c 100644
--- a/src/System.Composition/tests/ConstraintTests.cs
+++ b/src/System.Composition/tests/ConstraintTests.cs
@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
using System.Linq;
using Xunit;
@@ -10,6 +12,8 @@ namespace System.Composition.UnitTests
public class ConstraintTests : ContainerTests
{
public interface IThing { }
+ public interface IUnrelatedThings<TC, TP> : IList<TC>, IThing { }
+ public interface IInheritedThings<TC, TP> : IList<TC>, IThing where TC : TP { }
public interface ICar : IThing { }
public interface IBook : IThing { }
public interface IHandler<T> where T : IThing { }
@@ -26,6 +30,17 @@ namespace System.Composition.UnitTests
{
}
+ [Export(typeof(IInheritedThings<,>))]
+ public class InheritedThings<TC, TP> : ObservableCollection<TC>, IInheritedThings<TC, TP>
+ where TC : TP
+ {
+ }
+
+ [Export(typeof(IUnrelatedThings<,>))]
+ public class UnrelatedThings<TC, TP> : ObservableCollection<TC>, IUnrelatedThings<TC, TP>
+ {
+ }
+
[Fact]
[ActiveIssue(24903, TargetFrameworkMonikers.NetFramework)]
public void GenericPartDiscoveryIgnoresAPartAndDoesntThrowAnExceptionWhenItsConstraintOnTypeParameterIsNotAssignableFromTheExportTarget()
@@ -50,5 +65,30 @@ namespace System.Composition.UnitTests
Assert.Contains<Type>(typeof(ThingHandler<IBook>), handlerTypes);
Assert.Contains<Type>(typeof(BookHandler<IBook>), handlerTypes);
}
+
+ [Fact]
+ [ActiveIssue(24903, TargetFrameworkMonikers.NetFramework)]
+ public void GetExport_ComplexConstraint_ExportSuccessful()
+ {
+ CompositionContext container = CreateContainer(typeof(UnrelatedThings<,>));
+ var exports = container.GetExports<IUnrelatedThings<IBook, ICar>>();
+ var types = exports.Select(h => h.GetType());
+
+ Assert.Equal(1, exports.Count());
+ Assert.Contains(typeof(UnrelatedThings<IBook, ICar>), types);
+ }
+
+ [Fact]
+ [ActiveIssue(23607)]
+ [ActiveIssue(24903, TargetFrameworkMonikers.NetFramework)]
+ public void GetExport_WhereClause_ExportSuccessful()
+ {
+ CompositionContext container = CreateContainer(typeof(InheritedThings<,>));
+ var exports = container.GetExports<IInheritedThings<IBook, IThing>>();
+ var types = exports.Select(h => h.GetType());
+
+ Assert.Equal(1, exports.Count());
+ Assert.Contains(typeof(InheritedThings<IBook, IThing>), types);
+ }
}
}
diff --git a/src/System.Configuration.ConfigurationManager/ref/System.Configuration.ConfigurationManager.csproj b/src/System.Configuration.ConfigurationManager/ref/System.Configuration.ConfigurationManager.csproj
index 948dd3bedd..df12ccf73f 100644
--- a/src/System.Configuration.ConfigurationManager/ref/System.Configuration.ConfigurationManager.csproj
+++ b/src/System.Configuration.ConfigurationManager/ref/System.Configuration.ConfigurationManager.csproj
@@ -3,8 +3,6 @@
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
<ProjectGuid>{FD6AA2B9-56DB-4BCC-85E0-7727506562B0}</ProjectGuid>
- <!-- UAPvNext is not yet mapped to netstandard2.0, manually duplicate this ref -->
- <PackageTargetFramework Condition="'$(TargetGroup)' == 'netstandard'">netstandard2.0;$(UAPvNextTFM)</PackageTargetFramework>
<IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'netfx'">true</IsPartialFacadeAssembly>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Debug|AnyCPU'" />
@@ -12,9 +10,11 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
<ItemGroup>
- <SuppressPackageTargetFrameworkCompatibility Include="$(UAPvNextTFM)" />
<Compile Include="System.Configuration.cs" />
</ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\System.Security.Permissions\ref\System.Security.Permissions.csproj" />
+ </ItemGroup>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' == 'true'">
<Reference Include="mscorlib" />
<Reference Include="System" />
diff --git a/src/System.Configuration.ConfigurationManager/ref/System.Configuration.cs b/src/System.Configuration.ConfigurationManager/ref/System.Configuration.cs
index 5124846c60..df2016a813 100644
--- a/src/System.Configuration.ConfigurationManager/ref/System.Configuration.cs
+++ b/src/System.Configuration.ConfigurationManager/ref/System.Configuration.cs
@@ -1403,9 +1403,13 @@ namespace System.Configuration.Internal
public virtual string GetConfigPathFromLocationSubPath(string configPath, string locationSubPath) { throw null; }
public virtual System.Type GetConfigType(string typeName, bool throwOnError) { throw null; }
public virtual string GetConfigTypeName(System.Type t) { throw null; }
+ public virtual void GetRestrictedPermissions(IInternalConfigRecord configRecord, out System.Security.PermissionSet permissionSet, out bool isHostReady) { throw null; }
public virtual string GetStreamName(string configPath) { throw null; }
public virtual string GetStreamNameForConfigSource(string streamName, string configSource) { throw null; }
public virtual object GetStreamVersion(string streamName) { throw null; }
+ public virtual bool HasLocalConfig { get; }
+ public virtual bool HasRoamingConfig { get; }
+ public virtual bool IsAppConfigHttp { get; }
public virtual System.IDisposable Impersonate() { throw null; }
public virtual void Init(System.Configuration.Internal.IInternalConfigRoot configRoot, params object[] hostInitParams) { }
public virtual void InitForConfiguration(ref string locationSubPath, out string configPath, out string locationConfigPath, System.Configuration.Internal.IInternalConfigRoot configRoot, params object[] hostInitConfigurationParams) { configPath = default(string); locationConfigPath = default(string); }
@@ -1425,6 +1429,7 @@ namespace System.Configuration.Internal
public virtual bool PrefetchAll(string configPath, string streamName) { throw null; }
public virtual bool PrefetchSection(string sectionGroupName, string sectionName) { throw null; }
public virtual void RequireCompleteInit(System.Configuration.Internal.IInternalConfigRecord configRecord) { }
+ public virtual void RefreshConfigPaths() { }
public virtual object StartMonitoringStreamForChanges(string streamName, System.Configuration.Internal.StreamChangeCallback callback) { throw null; }
public virtual void StopMonitoringStreamForChanges(string streamName, System.Configuration.Internal.StreamChangeCallback callback) { }
public virtual void VerifyDefinitionAllowed(string configPath, System.Configuration.ConfigurationAllowDefinition allowDefinition, System.Configuration.ConfigurationAllowExeDefinition allowExeDefinition, System.Configuration.Internal.IConfigErrorInfo errorInfo) { }
@@ -1489,6 +1494,7 @@ namespace System.Configuration.Internal
string GetConfigPathFromLocationSubPath(string configPath, string locationSubPath);
System.Type GetConfigType(string typeName, bool throwOnError);
string GetConfigTypeName(System.Type t);
+ void GetRestrictedPermissions(IInternalConfigRecord configRecord, out System.Security.PermissionSet permissionSet, out bool isHostReady);
string GetStreamName(string configPath);
string GetStreamNameForConfigSource(string streamName, string configSource);
object GetStreamVersion(string streamName);
diff --git a/src/System.Configuration.ConfigurationManager/src/ApiCompatBaseline.netfx.txt b/src/System.Configuration.ConfigurationManager/src/ApiCompatBaseline.netfx.txt
deleted file mode 100644
index f6e50ce077..0000000000
--- a/src/System.Configuration.ConfigurationManager/src/ApiCompatBaseline.netfx.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Compat issues with assembly System.Configuration.ConfigurationManager:
-InterfacesShouldHaveSameMembers : Implementation interface member 'System.Configuration.Internal.IInternalConfigHost.GetRestrictedPermissions(System.Configuration.Internal.IInternalConfigRecord, System.Security.PermissionSet, System.Boolean)' is not in the contract.
-Total Issues: 1
diff --git a/src/System.Configuration.ConfigurationManager/src/MatchingRefApiCompatBaseline.netstandard.txt b/src/System.Configuration.ConfigurationManager/src/MatchingRefApiCompatBaseline.netstandard.txt
new file mode 100644
index 0000000000..2e6dadcd82
--- /dev/null
+++ b/src/System.Configuration.ConfigurationManager/src/MatchingRefApiCompatBaseline.netstandard.txt
@@ -0,0 +1,5 @@
+Compat issues with assembly System.Configuration.ConfigurationManager:
+# Cannot remove the serialization constructors because they are needed for serialization
+MembersMustExist : Member 'System.Configuration.SettingsAttributeDictionary..ctor(System.Runtime.Serialization.SerializationInfo, System.Runtime.Serialization.StreamingContext)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Configuration.SettingsContext..ctor(System.Runtime.Serialization.SerializationInfo, System.Runtime.Serialization.StreamingContext)' does not exist in the implementation but it does exist in the contract.
+Total Issues: 2
diff --git a/src/System.Configuration.ConfigurationManager/src/System.Configuration.ConfigurationManager.csproj b/src/System.Configuration.ConfigurationManager/src/System.Configuration.ConfigurationManager.csproj
index 6b9ff6aebd..03f10a290a 100644
--- a/src/System.Configuration.ConfigurationManager/src/System.Configuration.ConfigurationManager.csproj
+++ b/src/System.Configuration.ConfigurationManager/src/System.Configuration.ConfigurationManager.csproj
@@ -258,6 +258,7 @@
</ItemGroup>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true'">
<Reference Include="System.Security.Cryptography.ProtectedData" />
+ <Reference Include="System.Security.Permissions" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\$(AssemblyName).rd.xml" />
diff --git a/src/System.Configuration.ConfigurationManager/src/System/Configuration/ConfigurationSettings.cs b/src/System.Configuration.ConfigurationManager/src/System/Configuration/ConfigurationSettings.cs
index d52e6bdeb3..7ea7cd5d86 100644
--- a/src/System.Configuration.ConfigurationManager/src/System/Configuration/ConfigurationSettings.cs
+++ b/src/System.Configuration.ConfigurationManager/src/System/Configuration/ConfigurationSettings.cs
@@ -8,7 +8,7 @@ namespace System.Configuration
{
public sealed class ConfigurationSettings
{
- public ConfigurationSettings() { }
+ internal ConfigurationSettings() { }
[Obsolete("This method is obsolete, it has been replaced by System.Configuration!System.Configuration.ConfigurationManager.AppSettings")]
public static NameValueCollection AppSettings
diff --git a/src/System.Configuration.ConfigurationManager/src/System/Configuration/DateTimeConfigurationCollection.cs b/src/System.Configuration.ConfigurationManager/src/System/Configuration/DateTimeConfigurationCollection.cs
index 8753785c1a..0587bb3345 100644
--- a/src/System.Configuration.ConfigurationManager/src/System/Configuration/DateTimeConfigurationCollection.cs
+++ b/src/System.Configuration.ConfigurationManager/src/System/Configuration/DateTimeConfigurationCollection.cs
@@ -5,7 +5,7 @@
namespace System.Configuration
{
[ConfigurationCollection(typeof(DateTimeConfigurationElement))]
- public sealed class DateTimeConfigurationCollection : ConfigurationElementCollection
+ internal sealed class DateTimeConfigurationCollection : ConfigurationElementCollection
{
private static readonly ConfigurationPropertyCollection s_properties;
diff --git a/src/System.Configuration.ConfigurationManager/src/System/Configuration/Internal/DelegatingConfigHost.cs b/src/System.Configuration.ConfigurationManager/src/System/Configuration/Internal/DelegatingConfigHost.cs
index 5d45e6c097..05557ca5a4 100644
--- a/src/System.Configuration.ConfigurationManager/src/System/Configuration/Internal/DelegatingConfigHost.cs
+++ b/src/System.Configuration.ConfigurationManager/src/System/Configuration/Internal/DelegatingConfigHost.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.IO;
+using System.Security;
namespace System.Configuration.Internal
{
@@ -230,5 +231,11 @@ namespace System.Configuration.Internal
public virtual bool IsFullTrustSectionWithoutAptcaAllowed(IInternalConfigRecord configRecord) => true;
public virtual IDisposable Impersonate() => new DummyDisposable();
+
+ public virtual void GetRestrictedPermissions(IInternalConfigRecord configRecord, out PermissionSet permissionSet, out bool isHostReady)
+ {
+ permissionSet = new PermissionSet(null);
+ isHostReady = true;
+ }
}
-} \ No newline at end of file
+}
diff --git a/src/System.Configuration.ConfigurationManager/src/System/Configuration/Internal/IInternalConfigHost.cs b/src/System.Configuration.ConfigurationManager/src/System/Configuration/Internal/IInternalConfigHost.cs
index fd9de2e209..b45bc31da2 100644
--- a/src/System.Configuration.ConfigurationManager/src/System/Configuration/Internal/IInternalConfigHost.cs
+++ b/src/System.Configuration.ConfigurationManager/src/System/Configuration/Internal/IInternalConfigHost.cs
@@ -4,6 +4,7 @@
using System.IO;
using System.Runtime.InteropServices;
+using System.Security;
namespace System.Configuration.Internal
{
@@ -102,5 +103,7 @@ namespace System.Configuration.Internal
bool IsFullTrustSectionWithoutAptcaAllowed(IInternalConfigRecord configRecord);
IDisposable Impersonate();
+
+ void GetRestrictedPermissions(IInternalConfigRecord configRecord, out PermissionSet permissionSet, out bool isHostReady);
}
-} \ No newline at end of file
+}
diff --git a/src/System.Configuration.ConfigurationManager/src/System/Configuration/Internal/IInternalConfigHostPaths.cs b/src/System.Configuration.ConfigurationManager/src/System/Configuration/Internal/IInternalConfigHostPaths.cs
index 0bec91956a..d76aedbd3e 100644
--- a/src/System.Configuration.ConfigurationManager/src/System/Configuration/Internal/IInternalConfigHostPaths.cs
+++ b/src/System.Configuration.ConfigurationManager/src/System/Configuration/Internal/IInternalConfigHostPaths.cs
@@ -6,7 +6,7 @@ using System.Runtime.InteropServices;
namespace System.Configuration.Internal
{
- public interface IInternalConfigHostPaths
+ internal interface IInternalConfigHostPaths
{
void RefreshConfigPaths();
bool HasLocalConfig { get; }
diff --git a/src/System.Configuration.ConfigurationManager/src/System/Configuration/Internal/InternalConfigHost.cs b/src/System.Configuration.ConfigurationManager/src/System/Configuration/Internal/InternalConfigHost.cs
index 4fee40ea59..d8cff7ff8e 100644
--- a/src/System.Configuration.ConfigurationManager/src/System/Configuration/Internal/InternalConfigHost.cs
+++ b/src/System.Configuration.ConfigurationManager/src/System/Configuration/Internal/InternalConfigHost.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.IO;
+using System.Security;
namespace System.Configuration.Internal
{
@@ -303,5 +304,11 @@ namespace System.Configuration.Internal
public bool IsFullTrustSectionWithoutAptcaAllowed(IInternalConfigRecord configRecord) => true;
public IDisposable Impersonate() => new DummyDisposable();
+
+ public void GetRestrictedPermissions(IInternalConfigRecord configRecord, out PermissionSet permissionSet, out bool isHostReady)
+ {
+ permissionSet = new PermissionSet(null);
+ isHostReady = true;
+ }
}
-} \ No newline at end of file
+}
diff --git a/src/System.Configuration.ConfigurationManager/src/System/Configuration/SectionInformation.cs b/src/System.Configuration.ConfigurationManager/src/System/Configuration/SectionInformation.cs
index 334dc9174f..a19fa80032 100644
--- a/src/System.Configuration.ConfigurationManager/src/System/Configuration/SectionInformation.cs
+++ b/src/System.Configuration.ConfigurationManager/src/System/Configuration/SectionInformation.cs
@@ -584,7 +584,7 @@ namespace System.Configuration
// fail silently so that app code can easily loop through sections
// and declare all of them?
if (force && BaseConfigurationRecord.IsImplicitSection(SectionName))
- throw new ConfigurationErrorsException(SR.Cannot_declare_or_remove_implicit_section);
+ throw new ConfigurationErrorsException(SR.Format(SR.Cannot_declare_or_remove_implicit_section, SectionName));
if (force && _flags[FlagIsUndeclared])
{
@@ -681,4 +681,4 @@ namespace System.Configuration
_configRecord.RevertToParent(_configurationSection);
}
}
-} \ No newline at end of file
+}
diff --git a/src/System.Configuration.ConfigurationManager/src/System/Configuration/SettingValueElement.cs b/src/System.Configuration.ConfigurationManager/src/System/Configuration/SettingValueElement.cs
index 61cd3692a1..8268f68e6f 100644
--- a/src/System.Configuration.ConfigurationManager/src/System/Configuration/SettingValueElement.cs
+++ b/src/System.Configuration.ConfigurationManager/src/System/Configuration/SettingValueElement.cs
@@ -53,7 +53,7 @@ namespace System.Configuration
public override int GetHashCode()
{
- return ValueXml.GetHashCode();
+ return ValueXml?.GetHashCode() ?? 0;
}
protected internal override bool IsModified()
diff --git a/src/System.Configuration.ConfigurationManager/src/System/Configuration/TypeUtil.cs b/src/System.Configuration.ConfigurationManager/src/System/Configuration/TypeUtil.cs
index 8c83e42adb..67f16d23b6 100644
--- a/src/System.Configuration.ConfigurationManager/src/System/Configuration/TypeUtil.cs
+++ b/src/System.Configuration.ConfigurationManager/src/System/Configuration/TypeUtil.cs
@@ -33,16 +33,6 @@ namespace System.Configuration
"mscorlib",
"System",
-
- // TODO: ISSUE #14528
- // System facade isn't currently part of the framework
- // package. Once it is added the following locations can
- // be removed. There are tests for types from each of
- // these locations.
- "System.Runtime",
- "System.Collections",
- "System.Collections.Concurrent",
- "System.Collections.Specialized",
};
/// <summary>
@@ -187,4 +177,4 @@ namespace System.Configuration
return null;
}
}
-} \ No newline at end of file
+}
diff --git a/src/System.Configuration.ConfigurationManager/tests/System.Configuration.ConfigurationManager.Tests.csproj b/src/System.Configuration.ConfigurationManager/tests/System.Configuration.ConfigurationManager.Tests.csproj
index b74cdf5517..1ef4b09630 100644
--- a/src/System.Configuration.ConfigurationManager/tests/System.Configuration.ConfigurationManager.Tests.csproj
+++ b/src/System.Configuration.ConfigurationManager/tests/System.Configuration.ConfigurationManager.Tests.csproj
@@ -90,6 +90,7 @@
<Compile Include="System\Configuration\LocalFileSettingsProviderTests.cs" />
<Compile Include="System\Configuration\NameValueConfigurationCollectionTests.cs" />
<Compile Include="System\Configuration\SectionGroupsTests.cs" />
+ <Compile Include="System\Configuration\SettingElementTests.cs" />
<Compile Include="System\Configuration\SmokeTest.cs" />
<Compile Include="System\Configuration\StringUtilTests.cs" />
<Compile Include="System\Configuration\TempConfig.cs" />
diff --git a/src/System.Configuration.ConfigurationManager/tests/System/Configuration/SettingElementTests.cs b/src/System.Configuration.ConfigurationManager/tests/System/Configuration/SettingElementTests.cs
new file mode 100644
index 0000000000..0e50a98f99
--- /dev/null
+++ b/src/System.Configuration.ConfigurationManager/tests/System/Configuration/SettingElementTests.cs
@@ -0,0 +1,80 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.Configuration.Tests
+{
+ public class SettingElementTests
+ {
+ [Fact]
+ public void TestForInequality()
+ {
+ var ElementOne = new SettingElement("NotEqualOne", SettingsSerializeAs.String);
+ var ElementTwo = new SettingElement("NotEqualTwo", SettingsSerializeAs.String);
+ Assert.False(ElementOne.Equals(ElementTwo));
+ }
+
+ [Fact]
+ public void TestForEquality()
+ {
+ var ElementOne = new SettingElement("TheExactSameName", SettingsSerializeAs.String);
+ var ElementTwo = new SettingElement("TheExactSameName", SettingsSerializeAs.String);
+ Assert.True(ElementOne.Equals(ElementTwo));
+ }
+
+ [Fact]
+ public void DefaultSettingSerializationIsString()
+ {
+ var Element = new SettingElement();
+ Assert.Equal(SettingsSerializeAs.String, Element.SerializeAs);
+ }
+
+ [Fact]
+ public void DefaultNameIsEmptyString()
+ {
+ var Element = new SettingElement();
+ Assert.Equal(string.Empty, Element.Name);
+ }
+
+ [Fact]
+ public void DefaultValueIsNull()
+ {
+ var Element = new SettingElement();
+ Assert.Equal(null, Element.Value.CurrentConfiguration);
+ }
+
+ [Fact]
+ public void DefaultConstructorEquality()
+ {
+ var ElementOne = new SettingElement();
+ var ElementTwo = new SettingElement();
+ Assert.True(ElementOne.Equals(ElementTwo));
+ }
+
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Full framework does not have the fix for #27875")]
+ [Fact]
+ public void DefaultConstructorEqualHashCodes()
+ {
+ var ElementOne = new SettingElement();
+ var ElementTwo = new SettingElement();
+ Assert.Equal(ElementOne.GetHashCode(), ElementTwo.GetHashCode());
+ }
+
+ [Fact]
+ public void NonDefaultValueHasNonNullHashCode()
+ {
+ var Element = new SettingElement("Test", SettingsSerializeAs.Xml)
+ {
+ Value = new SettingValueElement
+ {
+ ValueXml = new ConfigXmlDocument
+ {
+ }
+ }
+ };
+ Assert.NotNull(Element.GetHashCode());
+ }
+ }
+}
diff --git a/src/System.Configuration.ConfigurationManager/tests/System/Configuration/TypeUtilTests.cs b/src/System.Configuration.ConfigurationManager/tests/System/Configuration/TypeUtilTests.cs
index 86e9d98b10..4309355d6c 100644
--- a/src/System.Configuration.ConfigurationManager/tests/System/Configuration/TypeUtilTests.cs
+++ b/src/System.Configuration.ConfigurationManager/tests/System/Configuration/TypeUtilTests.cs
@@ -8,6 +8,7 @@ using System.Collections.Specialized;
using System.Configuration;
using System.Configuration.Internal;
using System.IO;
+using System.Security;
using Xunit;
namespace System.ConfigurationTests
@@ -299,6 +300,11 @@ namespace System.ConfigurationTests
{
throw new NotImplementedException();
}
+
+ void IInternalConfigHost.GetRestrictedPermissions(IInternalConfigRecord configRecord, out PermissionSet permissionSet, out bool isHostReady)
+ {
+ throw new NotImplementedException();
+ }
}
}
}
diff --git a/src/System.Console/src/FxCopBaseline.cs b/src/System.Console/src/FxCopBaseline.cs
index c49b860f9b..fd02c4dea9 100644
--- a/src/System.Console/src/FxCopBaseline.cs
+++ b/src/System.Console/src/FxCopBaseline.cs
@@ -1,3 +1,7 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information
+
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.IO.SyncTextReader.#Dispose(System.Boolean)")]
@@ -48,4 +52,4 @@ using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.ConsolePal.#EnsureInitializedCore()")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.ConsolePal.#WriteStdoutAnsiString(System.String)")]
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.ConsolePal.#ForegroundColor")]
-[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.ConsolePal.#BackgroundColor")] \ No newline at end of file
+[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.ConsolePal.#BackgroundColor")]
diff --git a/src/System.Console/src/Resources/Strings.resx b/src/System.Console/src/Resources/Strings.resx
index a094a27e1a..fe296c62fc 100644
--- a/src/System.Console/src/Resources/Strings.resx
+++ b/src/System.Console/src/Resources/Strings.resx
@@ -258,4 +258,7 @@
<data name="IO_PathTooLong_Path" xml:space="preserve">
<value>The path '{0}' is too long, or a component of the specified path is too long.</value>
</data>
+ <data name="IO_TermInfoInvalidMagicNumber" xml:space="preserve">
+ <value>The terminfo database has an invalid magic number: '{0}'.</value>
+ </data>
</root> \ No newline at end of file
diff --git a/src/System.Console/src/System.Console.csproj b/src/System.Console/src/System.Console.csproj
index 27638b70f8..fbff23093b 100644
--- a/src/System.Console/src/System.Console.csproj
+++ b/src/System.Console/src/System.Console.csproj
@@ -167,8 +167,8 @@
<Compile Include="$(CommonPath)\System\Text\EncodingHelper.Windows.cs">
<Link>Common\System\IO\EncodingHelper.Windows.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\IO\Win32Marshal.cs">
- <Link>Common\System\IO\Win32Marshal.cs</Link>
+ <Compile Include="$(CommonPath)\CoreLib\System\IO\Win32Marshal.cs">
+ <Link>Common\CoreLib\System\IO\Win32Marshal.cs</Link>
</Compile>
</ItemGroup>
<!-- Unix -->
@@ -275,6 +275,7 @@
<Reference Include="System.Collections" />
<Reference Include="System.Diagnostics.Debug" />
<Reference Include="System.Diagnostics.Tools" />
+ <Reference Include="System.Memory" />
<Reference Include="System.Resources.ResourceManager" />
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.Extensions" />
@@ -282,6 +283,7 @@
<Reference Include="System.Text.Encoding.Extensions" />
<Reference Include="System.Threading" />
<Reference Include="System.Threading.Tasks" />
+ <Reference Include="Microsoft.Win32.Primitives" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
diff --git a/src/System.Console/src/System/Console.cs b/src/System.Console/src/System/Console.cs
index 9452d64372..77194f3e9a 100644
--- a/src/System.Console/src/System/Console.cs
+++ b/src/System.Console/src/System/Console.cs
@@ -22,8 +22,8 @@ namespace System
private static bool s_isOutTextWriterRedirected = false;
private static bool s_isErrorTextWriterRedirected = false;
- private static ConsoleCancelEventHandler _cancelCallbacks;
- private static ConsolePal.ControlCHandlerRegistrar _registrar;
+ private static ConsoleCancelEventHandler s_cancelCallbacks;
+ private static ConsolePal.ControlCHandlerRegistrar s_registrar;
internal static T EnsureInitialized<T>(ref T field, Func<T> initializer) where T : class =>
LazyInitializer.EnsureInitialized(ref field, ref InternalSyncObject, initializer);
@@ -334,13 +334,13 @@ namespace System
{
lock (InternalSyncObject)
{
- _cancelCallbacks += value;
+ s_cancelCallbacks += value;
// If we haven't registered our control-C handler, do it.
- if (_registrar == null)
+ if (s_registrar == null)
{
- _registrar = new ConsolePal.ControlCHandlerRegistrar();
- _registrar.Register();
+ s_registrar = new ConsolePal.ControlCHandlerRegistrar();
+ s_registrar.Register();
}
}
}
@@ -348,11 +348,11 @@ namespace System
{
lock (InternalSyncObject)
{
- _cancelCallbacks -= value;
- if (_registrar != null && _cancelCallbacks == null)
+ s_cancelCallbacks -= value;
+ if (s_registrar != null && s_cancelCallbacks == null)
{
- _registrar.Unregister();
- _registrar = null;
+ s_registrar.Unregister();
+ s_registrar = null;
}
}
}
@@ -688,68 +688,17 @@ namespace System
Out.Write(value);
}
- private sealed class ControlCDelegateData
- {
- private readonly ConsoleSpecialKey _controlKey;
- private readonly ConsoleCancelEventHandler _cancelCallbacks;
-
- internal bool Cancel;
- internal bool DelegateStarted;
-
- internal ControlCDelegateData(ConsoleSpecialKey controlKey, ConsoleCancelEventHandler cancelCallbacks)
- {
- _controlKey = controlKey;
- _cancelCallbacks = cancelCallbacks;
- }
-
- // This is the worker delegate that is called on the Threadpool thread to fire the actual events. It sets the DelegateStarted flag so
- // the thread that queued the work to the threadpool knows it has started (since it does not want to block indefinitely on the task
- // to start).
- internal void HandleBreakEvent()
- {
- DelegateStarted = true;
- var args = new ConsoleCancelEventArgs(_controlKey);
- _cancelCallbacks(null, args);
- Cancel = args.Cancel;
- }
- }
-
internal static bool HandleBreakEvent(ConsoleSpecialKey controlKey)
{
- // The thread that this gets called back on has a very small stack on some systems. There is
- // not enough space to handle a managed exception being caught and thrown. So, run a task
- // on the threadpool for the actual event callback.
-
- // To avoid the race condition between remove handler and raising the event
- ConsoleCancelEventHandler cancelCallbacks = Console._cancelCallbacks;
- if (cancelCallbacks == null)
- {
- return false;
- }
-
- var delegateData = new ControlCDelegateData(controlKey, cancelCallbacks);
- Task callBackTask = Task.Factory.StartNew(
- d => ((ControlCDelegateData)d).HandleBreakEvent(),
- delegateData,
- CancellationToken.None,
- TaskCreationOptions.DenyChildAttach,
- TaskScheduler.Default);
-
- // Block until the delegate is done. We need to be robust in the face of the task not executing
- // but we also want to get control back immediately after it is done and we don't want to give the
- // handler a fixed time limit in case it needs to display UI. Wait on the task twice, once with a
- // timeout and a second time without if we are sure that the handler actually started.
- TimeSpan controlCWaitTime = new TimeSpan(0, 0, 30); // 30 seconds
- callBackTask.Wait(controlCWaitTime);
-
- if (!delegateData.DelegateStarted)
+ ConsoleCancelEventHandler handler = s_cancelCallbacks;
+ if (handler == null)
{
- Debug.Assert(false, "The task to execute the handler did not start within 30 seconds.");
return false;
}
- callBackTask.Wait();
- return delegateData.Cancel;
+ var args = new ConsoleCancelEventArgs(controlKey);
+ handler(null, args);
+ return args.Cancel;
}
}
}
diff --git a/src/System.Console/src/System/ConsolePal.Unix.cs b/src/System.Console/src/System/ConsolePal.Unix.cs
index 7be909bab5..495296b4d8 100644
--- a/src/System.Console/src/System/ConsolePal.Unix.cs
+++ b/src/System.Console/src/System/ConsolePal.Unix.cs
@@ -4,6 +4,7 @@
using Microsoft.Win32.SafeHandles;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Text;
@@ -98,6 +99,16 @@ namespace System
bool previouslyProcessed;
ConsoleKeyInfo keyInfo = StdInReader.ReadKey(out previouslyProcessed);
+
+ // Replace the '\n' char for Enter by '\r' to match Windows behavior.
+ if (keyInfo.Key == ConsoleKey.Enter && keyInfo.KeyChar == '\n')
+ {
+ bool shift = (keyInfo.Modifiers & ConsoleModifiers.Shift) != 0;
+ bool alt = (keyInfo.Modifiers & ConsoleModifiers.Alt) != 0;
+ bool control = (keyInfo.Modifiers & ConsoleModifiers.Control) != 0;
+ keyInfo = new ConsoleKeyInfo('\r', keyInfo.Key, shift, alt, control);
+ }
+
if (!intercept && !previouslyProcessed) Console.Write(keyInfo.KeyChar);
return keyInfo;
}
@@ -666,7 +677,7 @@ namespace System
// signal handlers, etc.
if (!Interop.Sys.InitializeConsole())
{
- throw Interop.GetExceptionForIoErrno(Interop.Sys.GetLastErrorInfo());
+ throw new Win32Exception();
}
// Provide the native lib with the correct code from the terminfo to transition us into
@@ -1115,6 +1126,5 @@ namespace System
Interop.Sys.UnregisterForCtrl();
}
}
-
}
}
diff --git a/src/System.Console/src/System/ConsolePal.Windows.cs b/src/System.Console/src/System/ConsolePal.Windows.cs
index 2f07290e00..b023652103 100644
--- a/src/System.Console/src/System/ConsolePal.Windows.cs
+++ b/src/System.Console/src/System/ConsolePal.Windows.cs
@@ -963,14 +963,14 @@ namespace System
if (csbi.dwSize.X < csbi.srWindow.Left + width)
{
if (csbi.srWindow.Left >= short.MaxValue - width)
- throw new ArgumentOutOfRangeException(nameof(width), SR.ArgumentOutOfRange_ConsoleWindowBufferSize);
+ throw new ArgumentOutOfRangeException(nameof(width), SR.Format(SR.ArgumentOutOfRange_ConsoleWindowBufferSize, short.MaxValue - width));
size.X = (short)(csbi.srWindow.Left + width);
resizeBuffer = true;
}
if (csbi.dwSize.Y < csbi.srWindow.Top + height)
{
if (csbi.srWindow.Top >= short.MaxValue - height)
- throw new ArgumentOutOfRangeException(nameof(height), SR.ArgumentOutOfRange_ConsoleWindowBufferSize);
+ throw new ArgumentOutOfRangeException(nameof(height), SR.Format(SR.ArgumentOutOfRange_ConsoleWindowBufferSize, short.MaxValue - height));
size.Y = (short)(csbi.srWindow.Top + height);
resizeBuffer = true;
}
diff --git a/src/System.Console/src/System/TermInfo.cs b/src/System.Console/src/System/TermInfo.cs
index c84aaf9d03..ffccbf650e 100644
--- a/src/System.Console/src/System/TermInfo.cs
+++ b/src/System.Console/src/System/TermInfo.cs
@@ -107,6 +107,10 @@ namespace System
private readonly int _stringSectionNumOffsets;
/// <summary>The number of bytes in the strings table of the database.</summary>
private readonly int _stringTableNumBytes;
+ /// <summary>Whether or not to read the number section as 32-bit integers.</summary>
+ private readonly bool _readAs32Bit;
+ /// <summary>The size of the integers on the number section.</summary>
+ private readonly int _sizeOfInt;
/// <summary>Extended / user-defined entries in the terminfo database.</summary>
private readonly Dictionary<string, string> _extendedStrings;
@@ -119,11 +123,14 @@ namespace System
_term = term;
_data = data;
- // See "man term" for the file format.
- if (ReadInt16(data, 0) != 0x11A) // magic number octal 0432
- {
- throw new InvalidOperationException(SR.IO_TermInfoInvalid);
- }
+ const int MagicLegacyNumber = 0x11A; // magic number octal 0432 for legacy ncurses terminfo
+ const int Magic32BitNumber = 0x21E; // magic number octal 01036 for new ncruses terminfo
+ short magic = ReadInt16(data, 0);
+ _readAs32Bit =
+ magic == MagicLegacyNumber ? false :
+ magic == Magic32BitNumber ? true :
+ throw new InvalidOperationException(SR.Format(SR.IO_TermInfoInvalidMagicNumber, String.Concat("O" + Convert.ToString(magic, 8)))); // magic number was not recognized. Printing the magic number in octal.
+ _sizeOfInt = (_readAs32Bit) ? 4 : 2;
_nameSectionNumBytes = ReadInt16(data, 2);
_boolSectionNumBytes = ReadInt16(data, 4);
@@ -147,7 +154,7 @@ namespace System
// (Note that the extended section also includes other Booleans and numbers, but we don't
// have any need for those now, so we don't parse them.)
int extendedBeginning = RoundUpToEven(StringsTableOffset + _stringTableNumBytes);
- _extendedStrings = ParseExtendedStrings(data, extendedBeginning) ?? new Dictionary<string, string>();
+ _extendedStrings = ParseExtendedStrings(data, extendedBeginning, _readAs32Bit) ?? new Dictionary<string, string>();
}
/// <summary>The name of the associated terminfo, if any.</summary>
@@ -278,7 +285,7 @@ namespace System
/// The offset into data where the string offsets section begins. We index into this section
/// to find the location within the strings table where a string value exists.
/// </summary>
- private int StringOffsetsOffset { get { return NumbersOffset + (_numberSectionNumShorts * 2); } }
+ private int StringOffsetsOffset { get { return NumbersOffset + (_numberSectionNumShorts * _sizeOfInt); } }
/// <summary>The offset into data where the string table exists.</summary>
private int StringsTableOffset { get { return StringOffsetsOffset + (_stringSectionNumOffsets * 2); } }
@@ -346,9 +353,10 @@ namespace System
/// defined as the earlier portions, and may not even exist, the parsing is more lenient about
/// errors, returning an empty collection rather than throwing.
/// </returns>
- private static Dictionary<string, string> ParseExtendedStrings(byte[] data, int extendedBeginning)
+ private static Dictionary<string, string> ParseExtendedStrings(byte[] data, int extendedBeginning, bool readAs32Bit)
{
const int ExtendedHeaderSize = 10;
+ int sizeOfIntValuesInBytes = (readAs32Bit) ? 4 : 2;
if (extendedBeginning + ExtendedHeaderSize >= data.Length)
{
// Exit out as there's no extended information.
@@ -357,10 +365,10 @@ namespace System
// Read in extended counts, and exit out if we got any incorrect info
int extendedBoolCount = ReadInt16(data, extendedBeginning);
- int extendedNumberCount = ReadInt16(data, extendedBeginning + 2);
- int extendedStringCount = ReadInt16(data, extendedBeginning + 4);
- int extendedStringNumOffsets = ReadInt16(data, extendedBeginning + 6);
- int extendedStringTableByteSize = ReadInt16(data, extendedBeginning + 8);
+ int extendedNumberCount = ReadInt16(data, extendedBeginning + (2 * 1));
+ int extendedStringCount = ReadInt16(data, extendedBeginning + (2 * 2));
+ int extendedStringNumOffsets = ReadInt16(data, extendedBeginning + (2 * 3));
+ int extendedStringTableByteSize = ReadInt16(data, extendedBeginning + (2 * 4));
if (extendedBoolCount < 0 ||
extendedNumberCount < 0 ||
extendedStringCount < 0 ||
@@ -380,7 +388,7 @@ namespace System
extendedBeginning + // go past the normal data
ExtendedHeaderSize + // and past the extended header
RoundUpToEven(extendedBoolCount) + // and past all of the extended Booleans
- (extendedNumberCount * 2); // and past all of the extended numbers
+ (extendedNumberCount * sizeOfIntValuesInBytes); // and past all of the extended numbers
// Get the location where the extended string table begins. This area contains
// null-terminated strings.
@@ -447,6 +455,14 @@ namespace System
private static int RoundUpToEven(int i) { return i % 2 == 1 ? i + 1 : i; }
+ /// <summary>Read a 16-bit or 32-bit value from the buffer starting at the specified position.</summary>
+ /// <param name="buffer">The buffer from which to read.</param>
+ /// <param name="pos">The position at which to read.</param>
+ /// <param name="readAs32Bit">Whether or not to read value as 32-bit. Will read as 16-bit if set to false.</param>
+ /// <returns>The value read.</returns>
+ private static int ReadInt(byte[] buffer, int pos, bool readAs32Bit) =>
+ readAs32Bit ? ReadInt32(buffer, pos) : ReadInt16(buffer, pos);
+
/// <summary>Read a 16-bit value from the buffer starting at the specified position.</summary>
/// <param name="buffer">The buffer from which to read.</param>
/// <param name="pos">The position at which to read.</param>
@@ -458,6 +474,18 @@ namespace System
((int)buffer[pos] & 0xff)));
}
+ /// <summary>Read a 32-bit value from the buffer starting at the specified position.</summary>
+ /// <param name="buffer">The buffer from which to read.</param>
+ /// <param name="pos">The position at which to read.</param>
+ /// <returns>The 32-bit value read.</returns>
+ private static int ReadInt32(byte[] buffer, int pos)
+ {
+ return (int)((buffer[pos] & 0xff) |
+ buffer[pos + 1] << 8 |
+ buffer[pos + 2] << 16 |
+ buffer[pos + 3] << 24);
+ }
+
/// <summary>Reads a string from the buffer starting at the specified position.</summary>
/// <param name="buffer">The buffer from which to read.</param>
/// <param name="pos">The position at which to read.</param>
diff --git a/src/System.Console/tests/System.Console.Tests.csproj b/src/System.Console/tests/System.Console.Tests.csproj
index f78bd81fcf..f53566710c 100644
--- a/src/System.Console/tests/System.Console.Tests.csproj
+++ b/src/System.Console/tests/System.Console.Tests.csproj
@@ -36,6 +36,11 @@
</Compile>
<Compile Include="WindowAndCursorProps.cs" />
</ItemGroup>
+ <ItemGroup>
+ <SupplementalTestData Include="$(MSBuildThisFileDirectory)TestData\**\*.*">
+ <Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
+ </SupplementalTestData>
+ </ItemGroup>
<ItemGroup Condition="'$(TargetsWindows)' == 'true'">
<Compile Include="ConsoleEncoding.Windows.cs" />
</ItemGroup>
@@ -55,5 +60,11 @@
<Name>RemoteExecutorConsoleApp</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <ItemGroup>
+ <Folder Include="ncursesFormats\" />
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.Console/tests/TermInfo.cs b/src/System.Console/tests/TermInfo.cs
index f5f5945c34..fe5185ad15 100644
--- a/src/System.Console/tests/TermInfo.cs
+++ b/src/System.Console/tests/TermInfo.cs
@@ -58,6 +58,15 @@ public class TermInfo
Assert.True(foundAtLeastOne, "Didn't find any terminfo files");
}
+ [Fact]
+ [PlatformSpecific(TestPlatforms.AnyUnix)] // Tests TermInfo
+ public void VerifyTermInfoSupportsNewAndLegacyNcurses()
+ {
+ MethodInfo readDbMethod = typeof(Console).GetTypeInfo().Assembly.GetType(TerminfoDatabaseType).GetTypeInfo().GetDeclaredMethods(ReadDatabaseMethod).Where(m => m.GetParameters().Count() == 2).Single();
+ readDbMethod.Invoke(null, new object[] { "xterm", "ncursesFormats" }); // This will throw InvalidOperationException in case we don't support the legacy format
+ readDbMethod.Invoke(null, new object[] { "screen-256color", "ncursesFormats" }); // This will throw InvalidOperationException if we can't parse the new format
+ }
+
[Theory]
[PlatformSpecific(TestPlatforms.AnyUnix)] // Tests TermInfo
[InlineData("xterm-256color", "\u001B\u005B\u00330m", "\u001B\u005B\u00340m", 0)]
diff --git a/src/System.Console/tests/TestData/ncursesFormats/s/screen-256color b/src/System.Console/tests/TestData/ncursesFormats/s/screen-256color
new file mode 100644
index 0000000000..75c536ea2c
--- /dev/null
+++ b/src/System.Console/tests/TestData/ncursesFormats/s/screen-256color
Binary files differ
diff --git a/src/System.Console/tests/TestData/ncursesFormats/x/xterm b/src/System.Console/tests/TestData/ncursesFormats/x/xterm
new file mode 100644
index 0000000000..f63104055e
--- /dev/null
+++ b/src/System.Console/tests/TestData/ncursesFormats/x/xterm
Binary files differ
diff --git a/src/System.Data.Common/ref/System.Data.Common.cs b/src/System.Data.Common/ref/System.Data.Common.cs
index 64dd4c072a..ce1f1c68e2 100644
--- a/src/System.Data.Common/ref/System.Data.Common.cs
+++ b/src/System.Data.Common/ref/System.Data.Common.cs
@@ -1781,9 +1781,7 @@ namespace System.Data.Common
{
protected DbConnection() { }
[System.ComponentModel.DefaultValueAttribute("")]
-#pragma warning disable 0618
[System.ComponentModel.RecommendedAsConfigurableAttribute(true)]
-#pragma warning restore 0618
[System.ComponentModel.RefreshPropertiesAttribute((System.ComponentModel.RefreshProperties)(1))]
[System.ComponentModel.SettingsBindableAttribute(true)]
public abstract string ConnectionString { get; set; }
@@ -2204,6 +2202,12 @@ namespace System.Data.Common
public static System.Data.Common.DbProviderFactory GetFactory(System.Data.DataRow providerRow) { throw null; }
public static System.Data.Common.DbProviderFactory GetFactory(string providerInvariantName) { throw null; }
public static System.Data.DataTable GetFactoryClasses() { throw null; }
+ public static System.Collections.Generic.IEnumerable<string> GetProviderInvariantNames() { throw null; }
+ public static void RegisterFactory(string providerInvariantName, System.Data.Common.DbProviderFactory factory) { }
+ public static void RegisterFactory(string providerInvariantName, string factoryTypeAssemblyQualifiedName) { }
+ public static void RegisterFactory(string providerInvariantName, System.Type providerFactoryClass) { }
+ public static bool TryGetFactory(string providerInvariantName, out System.Data.Common.DbProviderFactory factory) { throw null; }
+ public static bool UnregisterFactory(string providerInvariantName) { throw null; }
}
public abstract partial class DbProviderFactory
{
diff --git a/src/System.Data.Common/ref/System.Data.Common.csproj b/src/System.Data.Common/ref/System.Data.Common.csproj
index 6dc2f123b3..688a56740c 100644
--- a/src/System.Data.Common/ref/System.Data.Common.csproj
+++ b/src/System.Data.Common/ref/System.Data.Common.csproj
@@ -3,7 +3,7 @@
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
<ProjectGuid>{D2DB0D6F-F65E-4174-B31E-27DC03137118}</ProjectGuid>
- <IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'netfx'">true</IsPartialFacadeAssembly>
+ <NoWarn>$(NoWarn);0618</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
@@ -12,17 +12,7 @@
<ItemGroup>
<Compile Include="System.Data.Common.cs" />
</ItemGroup>
- <ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp'">
- <Compile Include="System.Data.Common.netcoreapp.cs"/>
- </ItemGroup>
- <ItemGroup Condition="'$(TargetGroup)' == 'netfx'">
- <Reference Include="mscorlib" />
- <Reference Include="System" />
- <Reference Include="System.Data" />
- <Reference Include="System.Transactions" />
- <Reference Include="System.Xml" />
- </ItemGroup>
- <ItemGroup Condition="'$(TargetGroup)' != 'netfx'">
+ <ItemGroup>
<ProjectReference Include="..\..\System.Collections.NonGeneric\ref\System.Collections.NonGeneric.csproj" />
<ProjectReference Include="..\..\System.ComponentModel\ref\System.ComponentModel.csproj" />
<ProjectReference Include="..\..\System.ComponentModel.Primitives\ref\System.ComponentModel.Primitives.csproj" />
diff --git a/src/System.Data.Common/ref/System.Data.Common.netcoreapp.cs b/src/System.Data.Common/ref/System.Data.Common.netcoreapp.cs
deleted file mode 100644
index 94df2006ad..0000000000
--- a/src/System.Data.Common/ref/System.Data.Common.netcoreapp.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-// ------------------------------------------------------------------------------
-// Changes to this file must follow the http://aka.ms/api-review process.
-// ------------------------------------------------------------------------------
-
-using System.Collections.Generic;
-
-namespace System.Data.Common
-{
- public static partial class DbProviderFactories
- {
- public static void RegisterFactory(string providerInvariantName, string factoryTypeAssemblyQualifiedName) { throw null; }
- public static void RegisterFactory(string providerInvariantName, Type factoryType) { throw null; }
- public static void RegisterFactory(string providerInvariantName, DbProviderFactory factory) { throw null; }
- public static bool TryGetFactory(string providerInvariantName, out DbProviderFactory factory) { throw null; }
- public static bool UnregisterFactory(string providerInvariantName) { throw null; }
- public static IEnumerable<string> GetProviderInvariantNames() { throw null; }
- }
-}
diff --git a/src/System.Data.Common/src/MatchingRefApiCompatBaseline.uapaot.txt b/src/System.Data.Common/src/MatchingRefApiCompatBaseline.uapaot.txt
new file mode 100644
index 0000000000..a3f04a7468
--- /dev/null
+++ b/src/System.Data.Common/src/MatchingRefApiCompatBaseline.uapaot.txt
@@ -0,0 +1,2 @@
+#Exposed publicly in only in uapaot implementation to enable reflection on this type
+TypesMustExist : Type 'System.Data.DataCommonEventSource' does not exist in the implementation but it does exist in the contract.
diff --git a/src/System.Data.Common/src/System/Data/Common/NameValuePermission.cs b/src/System.Data.Common/src/System/Data/Common/NameValuePermission.cs
index 1deeb5140d..fa091e2b41 100644
--- a/src/System.Data.Common/src/System/Data/Common/NameValuePermission.cs
+++ b/src/System.Data.Common/src/System/Data/Common/NameValuePermission.cs
@@ -1,6 +1,6 @@
-//// Licensed to the .NET Foundation under one or more agreements.
-//// The .NET Foundation licenses this file to you under the MIT license.
-//// See the LICENSE file in the project root for more information.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
//namespace System.Data.Common
//{
diff --git a/src/System.Data.Common/src/System/Data/Common/SqlUDTStorage.cs b/src/System.Data.Common/src/System/Data/Common/SqlUDTStorage.cs
index 1ce6e1bf55..20f61490a7 100644
--- a/src/System.Data.Common/src/System/Data/Common/SqlUDTStorage.cs
+++ b/src/System.Data.Common/src/System/Data/Common/SqlUDTStorage.cs
@@ -7,9 +7,10 @@ using System.Xml;
using System.IO;
using System.Xml.Serialization;
using System.Collections;
-using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
+using System.Collections.Concurrent;
+using System.Reflection;
namespace System.Data.Common
{
@@ -19,7 +20,7 @@ namespace System.Data.Common
private readonly bool _implementsIXmlSerializable = false;
private readonly bool _implementsIComparable = false;
- private static readonly Dictionary<Type, object> s_typeToNull = new Dictionary<Type, object>();
+ private static readonly ConcurrentDictionary<Type, object> s_typeToNull = new ConcurrentDictionary<Type, object>();
public SqlUdtStorage(DataColumn column, Type type)
: this(column, type, GetStaticNullForUdtType(type))
@@ -34,36 +35,22 @@ namespace System.Data.Common
}
// to support oracle types and other INUllable types that have static Null as field
- internal static object GetStaticNullForUdtType(Type type)
+ internal static object GetStaticNullForUdtType(Type type) => s_typeToNull.GetOrAdd(type, t =>
{
- object value;
- if (!s_typeToNull.TryGetValue(type, out value))
+ PropertyInfo propInfo = type.GetProperty("Null", BindingFlags.Public | BindingFlags.Static);
+ if (propInfo != null)
{
- System.Reflection.PropertyInfo propInfo = type.GetProperty("Null", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
- if (propInfo != null)
- value = propInfo.GetValue(null, null);
- else
- {
- System.Reflection.FieldInfo fieldInfo = type.GetField("Null", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
- if (fieldInfo != null)
- {
- value = fieldInfo.GetValue(null);
- }
- else
- {
- throw ExceptionBuilder.INullableUDTwithoutStaticNull(type.AssemblyQualifiedName);
- }
- }
- lock (s_typeToNull)
- {
- //if(50 < TypeToNull.Count) {
- // TypeToNull.Clear();
- //}
- s_typeToNull[type] = value;
- }
+ return propInfo.GetValue(null, null);
}
- return value;
- }
+
+ FieldInfo fieldInfo = type.GetField("Null", BindingFlags.Public | BindingFlags.Static);
+ if (fieldInfo != null)
+ {
+ return fieldInfo.GetValue(null);
+ }
+
+ throw ExceptionBuilder.INullableUDTwithoutStaticNull(type.AssemblyQualifiedName);
+ });
public override bool IsNull(int record)
{
diff --git a/src/System.Data.Common/src/System/Data/DataTable.cs b/src/System.Data.Common/src/System/Data/DataTable.cs
index 3079e9ab6f..622bd1e282 100644
--- a/src/System.Data.Common/src/System/Data/DataTable.cs
+++ b/src/System.Data.Common/src/System/Data/DataTable.cs
@@ -374,8 +374,7 @@ namespace System.Data
info.AddValue(string.Format(formatProvider, "DataTable.DataColumn_{0}.DefaultValue", i), Columns[i].DefaultValue);
info.AddValue(string.Format(formatProvider, "DataTable.DataColumn_{0}.ReadOnly", i), Columns[i].ReadOnly);
info.AddValue(string.Format(formatProvider, "DataTable.DataColumn_{0}.MaxLength", i), Columns[i].MaxLength);
- info.AddValue(string.Format(formatProvider, "DataTable.DataColumn_{0}.DataType", i), Columns[i].DataType);
-
+ info.AddValue(string.Format(formatProvider, "DataTable.DataColumn_{0}.DataType_AssemblyQualifiedName", i), Columns[i].DataType.AssemblyQualifiedName);
info.AddValue(string.Format(formatProvider, "DataTable.DataColumn_{0}.XmlDataType", i), Columns[i].XmlDataType);
info.AddValue(string.Format(formatProvider, "DataTable.DataColumn_{0}.SimpleType", i), Columns[i].SimpleType);
@@ -444,7 +443,8 @@ namespace System.Data
dc._columnUri = info.GetString(string.Format(formatProvider, "DataTable.DataColumn_{0}.Namespace", i));
dc.Prefix = info.GetString(string.Format(formatProvider, "DataTable.DataColumn_{0}.Prefix", i));
- dc.DataType = (Type)info.GetValue(string.Format(formatProvider, "DataTable.DataColumn_{0}.DataType", i), typeof(Type));
+ string typeName = (string)info.GetValue(string.Format(formatProvider, "DataTable.DataColumn_{0}.DataType_AssemblyQualifiedName", i), typeof(string));
+ dc.DataType = Type.GetType(typeName, throwOnError: true);
dc.XmlDataType = (string)info.GetValue(string.Format(formatProvider, "DataTable.DataColumn_{0}.XmlDataType", i), typeof(string));
dc.SimpleType = (SimpleType)info.GetValue(string.Format(formatProvider, "DataTable.DataColumn_{0}.SimpleType", i), typeof(SimpleType));
diff --git a/src/System.Data.Common/tests/System/Data/DataColumnTest.cs b/src/System.Data.Common/tests/System/Data/DataColumnTest.cs
index dcdbbee6c7..24e50cb707 100644
--- a/src/System.Data.Common/tests/System/Data/DataColumnTest.cs
+++ b/src/System.Data.Common/tests/System/Data/DataColumnTest.cs
@@ -958,6 +958,32 @@ namespace System.Data.Tests
c2.Expression = "SUBSTRING(ISNULL(c1,' '), 1, 10)";
}
+ [Fact]
+ public void NonSqlNullableType_RequiresPublicStaticNull()
+ {
+ var t = new DataTable();
+ var c1 = t.Columns.Add("c1", typeof(NullableTypeWithNullProperty));
+ var c2 = t.Columns.Add("c2", typeof(NullableTypeWithNullField));
+ Assert.Throws<ArgumentException>(() => t.Columns.Add("c3", typeof(NullableTypeWithoutNullMember)));
+ }
+
+ private sealed class NullableTypeWithNullProperty : INullable
+ {
+ public bool IsNull => true;
+ public static NullableTypeWithNullProperty Null { get; } = new NullableTypeWithNullProperty();
+ }
+
+ private sealed class NullableTypeWithNullField : INullable
+ {
+ public bool IsNull => true;
+ public static readonly NullableTypeWithNullField Null = new NullableTypeWithNullField();
+ }
+
+ private sealed class NullableTypeWithoutNullMember : INullable
+ {
+ public bool IsNull => true;
+ }
+
private DataColumn MakeColumn(string col, string test)
{
return new DataColumn()
diff --git a/src/System.Data.Common/tests/System/Data/DataTableReadXmlSchemaTest.cs b/src/System.Data.Common/tests/System/Data/DataTableReadXmlSchemaTest.cs
index 54b6234667..2669ee9ed0 100644
--- a/src/System.Data.Common/tests/System/Data/DataTableReadXmlSchemaTest.cs
+++ b/src/System.Data.Common/tests/System/Data/DataTableReadXmlSchemaTest.cs
@@ -485,7 +485,7 @@ namespace System.Data.Tests
Assert.Contains(@"AutoIncrementStep=""-2""", rawSchemaXML);
Assert.DoesNotContain("()1", rawSchemaXML);
Assert.DoesNotContain("()2", rawSchemaXML);
- });
+ }).Dispose();
}
[Fact]
@@ -600,7 +600,7 @@ namespace System.Data.Tests
DataColumn rowIDColumn = table.Columns["RowID"];
Assert.Equal(-1, rowIDColumn.AutoIncrementSeed);
Assert.Equal(-2, rowIDColumn.AutoIncrementStep);
- });
+ }).Dispose();
}
[Fact]
diff --git a/src/System.Data.Common/tests/System/Data/DataTableTest.cs b/src/System.Data.Common/tests/System/Data/DataTableTest.cs
index 92f507d88a..605b1e1b80 100644
--- a/src/System.Data.Common/tests/System/Data/DataTableTest.cs
+++ b/src/System.Data.Common/tests/System/Data/DataTableTest.cs
@@ -32,6 +32,7 @@ using System.Data.SqlTypes;
using System.Diagnostics;
using System.Globalization;
using System.IO;
+using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Formatters.Tests;
using System.Xml;
using Xunit;
@@ -389,6 +390,25 @@ namespace System.Data.Tests
}
[Fact]
+ public void DataColumnTypeSerialization()
+ {
+ DataTable dt = new DataTable("MyTable");
+ DataColumn dc = new DataColumn("dc", typeof(int));
+ dt.Columns.Add(dc);
+ dt.RemotingFormat = SerializationFormat.Binary;
+
+ DataTable dtDeserialized;
+ using (MemoryStream ms = new MemoryStream())
+ {
+ BinaryFormatter bf = new BinaryFormatter();
+ bf.Serialize(ms, dt);
+ ms.Seek(0, SeekOrigin.Begin);
+ dtDeserialized = (DataTable)bf.Deserialize(ms);
+ }
+ Assert.Equal(dc.DataType, dtDeserialized.Columns[0].DataType);
+ }
+
+ [Fact]
public void SelectExceptions()
{
DataTable T = new DataTable("test");
diff --git a/src/System.Data.DataSetExtensions/dir.props b/src/System.Data.DataSetExtensions/dir.props
index 09d2f14f39..9e190a7dde 100644
--- a/src/System.Data.DataSetExtensions/dir.props
+++ b/src/System.Data.DataSetExtensions/dir.props
@@ -3,6 +3,6 @@
<Import Project="..\dir.props" />
<PropertyGroup>
<AssemblyVersion>4.0.0.0</AssemblyVersion>
- <AssemblyKey>MSFT</AssemblyKey>
+ <AssemblyKey>ECMA</AssemblyKey>
</PropertyGroup>
</Project> \ No newline at end of file
diff --git a/src/System.Data.DataSetExtensions/pkg/System.Data.DataSetExtensions.pkgproj b/src/System.Data.DataSetExtensions/pkg/System.Data.DataSetExtensions.pkgproj
index ec640ad906..878933ade5 100644
--- a/src/System.Data.DataSetExtensions/pkg/System.Data.DataSetExtensions.pkgproj
+++ b/src/System.Data.DataSetExtensions/pkg/System.Data.DataSetExtensions.pkgproj
@@ -3,7 +3,7 @@
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<ProjectReference Include="..\ref\System.Data.DataSetExtensions.csproj">
- <SupportedFramework>netcoreapp2.0;net45;$(AllXamarinFrameworks)</SupportedFramework>
+ <SupportedFramework>uap10.0.16299;netcoreapp2.0;net45;$(AllXamarinFrameworks)</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\src\System.Data.DataSetExtensions.csproj" />
<InboxOnTargetFramework Include="net45">
diff --git a/src/System.Data.DataSetExtensions/src/Configurations.props b/src/System.Data.DataSetExtensions/src/Configurations.props
index c398e42e89..77e29493b0 100644
--- a/src/System.Data.DataSetExtensions/src/Configurations.props
+++ b/src/System.Data.DataSetExtensions/src/Configurations.props
@@ -3,6 +3,7 @@
<PropertyGroup>
<BuildConfigurations>
netstandard;
+ _netfx;
</BuildConfigurations>
</PropertyGroup>
</Project> \ No newline at end of file
diff --git a/src/System.Data.Odbc/pkg/System.Data.Odbc.pkgproj b/src/System.Data.Odbc/pkg/System.Data.Odbc.pkgproj
index c0232ef4ea..e4959eab6e 100644
--- a/src/System.Data.Odbc/pkg/System.Data.Odbc.pkgproj
+++ b/src/System.Data.Odbc/pkg/System.Data.Odbc.pkgproj
@@ -3,7 +3,7 @@
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<ProjectReference Include="..\ref\System.Data.Odbc.csproj">
- <SupportedFramework>net461;netcoreapp2.0;$(AllXamarinFrameworks)</SupportedFramework>
+ <SupportedFramework>uap10.0.16299;net461;netcoreapp2.0;$(AllXamarinFrameworks)</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\src\System.Data.Odbc.csproj" />
</ItemGroup>
diff --git a/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbConnectionClosed.cs b/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbConnectionClosed.cs
index 635d3d6b78..619341d2bf 100644
--- a/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbConnectionClosed.cs
+++ b/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbConnectionClosed.cs
@@ -3,165 +3,13 @@
// See the LICENSE file in the project root for more information.
using System.Data.Common;
-using System.Diagnostics;
-using System.Threading.Tasks;
namespace System.Data.ProviderBase
{
- internal abstract class DbConnectionClosed : DbConnectionInternal
+ internal abstract partial class DbConnectionClosed : DbConnectionInternal
{
- // Construct an "empty" connection
- protected DbConnectionClosed(ConnectionState state, bool hidePassword, bool allowSetConnectionString) : base(state, hidePassword, allowSetConnectionString)
- {
- }
+ protected override void Activate() => throw ADP.ClosedConnectionError();
- public override string ServerVersion
- {
- get
- {
- throw ADP.ClosedConnectionError();
- }
- }
-
- protected override void Activate()
- {
- throw ADP.ClosedConnectionError();
- }
-
- public override DbTransaction BeginTransaction(IsolationLevel il)
- {
- throw ADP.ClosedConnectionError();
- }
-
- public override void ChangeDatabase(string database)
- {
- throw ADP.ClosedConnectionError();
- }
-
- internal override void CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory)
- {
- // not much to do here...
- }
-
- protected override void Deactivate()
- {
- throw ADP.ClosedConnectionError();
- }
-
-
- protected override DbReferenceCollection CreateReferenceCollection()
- {
- throw ADP.ClosedConnectionError();
- }
-
- internal override bool TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
- {
- return base.TryOpenConnectionInternal(outerConnection, connectionFactory, retry, userOptions);
- }
- }
-
- internal abstract class DbConnectionBusy : DbConnectionClosed
- {
- protected DbConnectionBusy(ConnectionState state) : base(state, true, false)
- {
- }
-
- internal override bool TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
- {
- throw ADP.ConnectionAlreadyOpen(State);
- }
- }
-
- internal sealed class DbConnectionClosedBusy : DbConnectionBusy
- {
- // Closed Connection, Currently Busy - changing connection string
- internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionClosedBusy(); // singleton object
-
- private DbConnectionClosedBusy() : base(ConnectionState.Closed)
- {
- }
- }
-
- internal sealed class DbConnectionOpenBusy : DbConnectionBusy
- {
- // Open Connection, Currently Busy - closing connection
- internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionOpenBusy(); // singleton object
-
- private DbConnectionOpenBusy() : base(ConnectionState.Open)
- {
- }
- }
-
- internal sealed class DbConnectionClosedConnecting : DbConnectionBusy
- {
- // Closed Connection, Currently Connecting
-
- internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionClosedConnecting(); // singleton object
-
- private DbConnectionClosedConnecting() : base(ConnectionState.Connecting)
- {
- }
-
- internal override void CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory)
- {
- connectionFactory.SetInnerConnectionTo(owningObject, DbConnectionClosedPreviouslyOpened.SingletonInstance);
- }
-
- internal override bool TryReplaceConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
- {
- return TryOpenConnection(outerConnection, connectionFactory, retry, userOptions);
- }
-
- internal override bool TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
- {
- if (retry == null || !retry.Task.IsCompleted)
- {
- // retry is null if this is a synchronous call
-
- // if someone calls Open or OpenAsync while in this state,
- // then the retry task will not be completed
-
- throw ADP.ConnectionAlreadyOpen(State);
- }
-
- // we are completing an asynchronous open
- Debug.Assert(retry.Task.Status == TaskStatus.RanToCompletion, "retry task must be completed successfully");
- DbConnectionInternal openConnection = retry.Task.Result;
- if (null == openConnection)
- {
- connectionFactory.SetInnerConnectionTo(outerConnection, this);
- throw ADP.InternalConnectionError(ADP.ConnectionError.GetConnectionReturnsNull);
- }
- connectionFactory.SetInnerConnectionEvent(outerConnection, openConnection);
-
- return true;
- }
}
- internal sealed class DbConnectionClosedNeverOpened : DbConnectionClosed
- {
- // Closed Connection, Has Never Been Opened
-
- internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionClosedNeverOpened(); // singleton object
-
- private DbConnectionClosedNeverOpened() : base(ConnectionState.Closed, false, true)
- {
- }
- }
-
- internal sealed class DbConnectionClosedPreviouslyOpened : DbConnectionClosed
- {
- // Closed Connection, Has Previously Been Opened
-
- internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionClosedPreviouslyOpened(); // singleton object
-
- private DbConnectionClosedPreviouslyOpened() : base(ConnectionState.Closed, true, true)
- {
- }
-
- internal override bool TryReplaceConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
- {
- return TryOpenConnection(outerConnection, connectionFactory, retry, userOptions);
- }
- }
}
diff --git a/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbConnectionFactory.cs b/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbConnectionFactory.cs
index cdc19e2681..d7d43f4c55 100644
--- a/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbConnectionFactory.cs
+++ b/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbConnectionFactory.cs
@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Collections.Generic;
using System.Diagnostics;
using System.Data.Common;
using System.Threading;
@@ -10,143 +9,8 @@ using System.Threading.Tasks;
namespace System.Data.ProviderBase
{
- internal abstract class DbConnectionFactory
+ internal abstract partial class DbConnectionFactory
{
- private Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> _connectionPoolGroups;
- private readonly List<DbConnectionPool> _poolsToRelease;
- private readonly List<DbConnectionPoolGroup> _poolGroupsToRelease;
- private readonly Timer _pruningTimer;
-
- private const int PruningDueTime = 4 * 60 * 1000; // 4 minutes
- private const int PruningPeriod = 30 * 1000; // thirty seconds
-
-
- // s_pendingOpenNonPooled is an array of tasks used to throttle creation of non-pooled connections to
- // a maximum of Environment.ProcessorCount at a time.
- private static uint s_pendingOpenNonPooledNext = 0;
- private static Task<DbConnectionInternal>[] s_pendingOpenNonPooled = new Task<DbConnectionInternal>[Environment.ProcessorCount];
- private static Task<DbConnectionInternal> s_completedTask;
-
- protected DbConnectionFactory()
- {
- _connectionPoolGroups = new Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup>();
- _poolsToRelease = new List<DbConnectionPool>();
- _poolGroupsToRelease = new List<DbConnectionPoolGroup>();
- _pruningTimer = CreatePruningTimer();
- }
-
-
- public abstract DbProviderFactory ProviderFactory
- {
- get;
- }
-
-
- public void ClearAllPools()
- {
- Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> connectionPoolGroups = _connectionPoolGroups;
- foreach (KeyValuePair<DbConnectionPoolKey, DbConnectionPoolGroup> entry in connectionPoolGroups)
- {
- DbConnectionPoolGroup poolGroup = entry.Value;
- if (null != poolGroup)
- {
- poolGroup.Clear();
- }
- }
- }
-
- public void ClearPool(DbConnection connection)
- {
- ADP.CheckArgumentNull(connection, nameof(connection));
-
- DbConnectionPoolGroup poolGroup = GetConnectionPoolGroup(connection);
- if (null != poolGroup)
- {
- poolGroup.Clear();
- }
- }
-
- public void ClearPool(DbConnectionPoolKey key)
- {
- Debug.Assert(key != null, "key cannot be null");
- ADP.CheckArgumentNull(key.ConnectionString, nameof(key) + "." + nameof(key.ConnectionString));
-
- DbConnectionPoolGroup poolGroup;
- Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> connectionPoolGroups = _connectionPoolGroups;
- if (connectionPoolGroups.TryGetValue(key, out poolGroup))
- {
- poolGroup.Clear();
- }
- }
-
- internal virtual DbConnectionPoolProviderInfo CreateConnectionPoolProviderInfo(DbConnectionOptions connectionOptions)
- {
- return null;
- }
-
-
- internal DbConnectionInternal CreateNonPooledConnection(DbConnection owningConnection, DbConnectionPoolGroup poolGroup, DbConnectionOptions userOptions)
- {
- Debug.Assert(null != owningConnection, "null owningConnection?");
- Debug.Assert(null != poolGroup, "null poolGroup?");
-
- DbConnectionOptions connectionOptions = poolGroup.ConnectionOptions;
- DbConnectionPoolGroupProviderInfo poolGroupProviderInfo = poolGroup.ProviderInfo;
- DbConnectionPoolKey poolKey = poolGroup.PoolKey;
-
- DbConnectionInternal newConnection = CreateConnection(connectionOptions, poolKey, poolGroupProviderInfo, null, owningConnection, userOptions);
- if (null != newConnection)
- {
- newConnection.MakeNonPooledObject(owningConnection);
- }
- return newConnection;
- }
-
- internal DbConnectionInternal CreatePooledConnection(DbConnectionPool pool, DbConnection owningObject, DbConnectionOptions options, DbConnectionPoolKey poolKey, DbConnectionOptions userOptions)
- {
- Debug.Assert(null != pool, "null pool?");
- DbConnectionPoolGroupProviderInfo poolGroupProviderInfo = pool.PoolGroup.ProviderInfo;
-
- DbConnectionInternal newConnection = CreateConnection(options, poolKey, poolGroupProviderInfo, pool, owningObject, userOptions);
- if (null != newConnection)
- {
- newConnection.MakePooledConnection(pool);
- }
- return newConnection;
- }
-
- internal virtual DbConnectionPoolGroupProviderInfo CreateConnectionPoolGroupProviderInfo(DbConnectionOptions connectionOptions)
- {
- return null;
- }
-
- private Timer CreatePruningTimer()
- {
- TimerCallback callback = new TimerCallback(PruneConnectionPoolGroups);
- return new Timer(callback, null, PruningDueTime, PruningPeriod);
- }
-
- protected DbConnectionOptions FindConnectionOptions(DbConnectionPoolKey key)
- {
- Debug.Assert(key != null, "key cannot be null");
- if (!string.IsNullOrEmpty(key.ConnectionString))
- {
- DbConnectionPoolGroup connectionPoolGroup;
- Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> connectionPoolGroups = _connectionPoolGroups;
- if (connectionPoolGroups.TryGetValue(key, out connectionPoolGroup))
- {
- return connectionPoolGroup.ConnectionOptions;
- }
- }
- return null;
- }
-
- private static Task<DbConnectionInternal> GetCompletedTask()
- {
- Debug.Assert(Monitor.IsEntered(s_pendingOpenNonPooled), $"Expected {nameof(s_pendingOpenNonPooled)} lock to be held.");
- return s_completedTask ?? (s_completedTask = Task.FromResult<DbConnectionInternal>(null));
- }
-
internal bool TryGetConnection(DbConnection owningConnection, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, out DbConnectionInternal connection)
{
Debug.Assert(null != owningConnection, "null owningConnection?");
@@ -309,254 +173,6 @@ namespace System.Data.ProviderBase
return true;
}
-
- private DbConnectionPool GetConnectionPool(DbConnection owningObject, DbConnectionPoolGroup connectionPoolGroup)
- {
- // if poolgroup is disabled, it will be replaced with a new entry
-
- Debug.Assert(null != owningObject, "null owningObject?");
- Debug.Assert(null != connectionPoolGroup, "null connectionPoolGroup?");
-
- // It is possible that while the outer connection object has
- // been sitting around in a closed and unused state in some long
- // running app, the pruner may have come along and remove this
- // the pool entry from the master list. If we were to use a
- // pool entry in this state, we would create "unmanaged" pools,
- // which would be bad. To avoid this problem, we automagically
- // re-create the pool entry whenever it's disabled.
-
- // however, don't rebuild connectionOptions if no pooling is involved - let new connections do that work
- if (connectionPoolGroup.IsDisabled && (null != connectionPoolGroup.PoolGroupOptions))
- {
- // reusing existing pool option in case user originally used SetConnectionPoolOptions
- DbConnectionPoolGroupOptions poolOptions = connectionPoolGroup.PoolGroupOptions;
-
- // get the string to hash on again
- DbConnectionOptions connectionOptions = connectionPoolGroup.ConnectionOptions;
- Debug.Assert(null != connectionOptions, "prevent expansion of connectionString");
-
- connectionPoolGroup = GetConnectionPoolGroup(connectionPoolGroup.PoolKey, poolOptions, ref connectionOptions);
- Debug.Assert(null != connectionPoolGroup, "null connectionPoolGroup?");
- SetConnectionPoolGroup(owningObject, connectionPoolGroup);
- }
- DbConnectionPool connectionPool = connectionPoolGroup.GetConnectionPool(this);
- return connectionPool;
- }
-
- internal DbConnectionPoolGroup GetConnectionPoolGroup(DbConnectionPoolKey key, DbConnectionPoolGroupOptions poolOptions, ref DbConnectionOptions userConnectionOptions)
- {
- if (string.IsNullOrEmpty(key.ConnectionString))
- {
- return (DbConnectionPoolGroup)null;
- }
-
- DbConnectionPoolGroup connectionPoolGroup;
- Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> connectionPoolGroups = _connectionPoolGroups;
- if (!connectionPoolGroups.TryGetValue(key, out connectionPoolGroup) || (connectionPoolGroup.IsDisabled && (null != connectionPoolGroup.PoolGroupOptions)))
- {
- // If we can't find an entry for the connection string in
- // our collection of pool entries, then we need to create a
- // new pool entry and add it to our collection.
-
- DbConnectionOptions connectionOptions = CreateConnectionOptions(key.ConnectionString, userConnectionOptions);
- if (null == connectionOptions)
- {
- throw ADP.InternalConnectionError(ADP.ConnectionError.ConnectionOptionsMissing);
- }
-
- if (null == userConnectionOptions)
- { // we only allow one expansion on the connection string
- userConnectionOptions = connectionOptions;
- }
-
- // We don't support connection pooling on Win9x
- if (null == poolOptions)
- {
- if (null != connectionPoolGroup)
- {
- // reusing existing pool option in case user originally used SetConnectionPoolOptions
- poolOptions = connectionPoolGroup.PoolGroupOptions;
- }
- else
- {
- // Note: may return null for non-pooled connections
- poolOptions = CreateConnectionPoolGroupOptions(connectionOptions);
- }
- }
-
-
- DbConnectionPoolGroup newConnectionPoolGroup = new DbConnectionPoolGroup(connectionOptions, key, poolOptions);
- newConnectionPoolGroup.ProviderInfo = CreateConnectionPoolGroupProviderInfo(connectionOptions);
-
- lock (this)
- {
- connectionPoolGroups = _connectionPoolGroups;
- if (!connectionPoolGroups.TryGetValue(key, out connectionPoolGroup))
- {
- // build new dictionary with space for new connection string
- Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> newConnectionPoolGroups = new Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup>(1 + connectionPoolGroups.Count);
- foreach (KeyValuePair<DbConnectionPoolKey, DbConnectionPoolGroup> entry in connectionPoolGroups)
- {
- newConnectionPoolGroups.Add(entry.Key, entry.Value);
- }
-
- // lock prevents race condition with PruneConnectionPoolGroups
- newConnectionPoolGroups.Add(key, newConnectionPoolGroup);
- connectionPoolGroup = newConnectionPoolGroup;
- _connectionPoolGroups = newConnectionPoolGroups;
- }
- else
- {
- Debug.Assert(!connectionPoolGroup.IsDisabled, "Disabled pool entry discovered");
- }
- }
- Debug.Assert(null != connectionPoolGroup, "how did we not create a pool entry?");
- Debug.Assert(null != userConnectionOptions, "how did we not have user connection options?");
- }
- else if (null == userConnectionOptions)
- {
- userConnectionOptions = connectionPoolGroup.ConnectionOptions;
- }
- return connectionPoolGroup;
- }
-
-
- private void PruneConnectionPoolGroups(object state)
- {
- // First, walk the pool release list and attempt to clear each
- // pool, when the pool is finally empty, we dispose of it. If the
- // pool isn't empty, it's because there are active connections or
- // distributed transactions that need it.
- lock (_poolsToRelease)
- {
- if (0 != _poolsToRelease.Count)
- {
- DbConnectionPool[] poolsToRelease = _poolsToRelease.ToArray();
- foreach (DbConnectionPool pool in poolsToRelease)
- {
- if (null != pool)
- {
- pool.Clear();
-
- if (0 == pool.Count)
- {
- _poolsToRelease.Remove(pool);
- }
- }
- }
- }
- }
-
- // Next, walk the pool entry release list and dispose of each
- // pool entry when it is finally empty. If the pool entry isn't
- // empty, it's because there are active pools that need it.
- lock (_poolGroupsToRelease)
- {
- if (0 != _poolGroupsToRelease.Count)
- {
- DbConnectionPoolGroup[] poolGroupsToRelease = _poolGroupsToRelease.ToArray();
- foreach (DbConnectionPoolGroup poolGroup in poolGroupsToRelease)
- {
- if (null != poolGroup)
- {
- int poolsLeft = poolGroup.Clear(); // may add entries to _poolsToRelease
-
- if (0 == poolsLeft)
- {
- _poolGroupsToRelease.Remove(poolGroup);
- }
- }
- }
- }
- }
-
- // Finally, we walk through the collection of connection pool entries
- // and prune each one. This will cause any empty pools to be put
- // into the release list.
- lock (this)
- {
- Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> connectionPoolGroups = _connectionPoolGroups;
- Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> newConnectionPoolGroups = new Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup>(connectionPoolGroups.Count);
-
- foreach (KeyValuePair<DbConnectionPoolKey, DbConnectionPoolGroup> entry in connectionPoolGroups)
- {
- if (null != entry.Value)
- {
- Debug.Assert(!entry.Value.IsDisabled, "Disabled pool entry discovered");
-
- // entries start active and go idle during prune if all pools are gone
- // move idle entries from last prune pass to a queue for pending release
- // otherwise process entry which may move it from active to idle
- if (entry.Value.Prune())
- { // may add entries to _poolsToRelease
- QueuePoolGroupForRelease(entry.Value);
- }
- else
- {
- newConnectionPoolGroups.Add(entry.Key, entry.Value);
- }
- }
- }
- _connectionPoolGroups = newConnectionPoolGroups;
- }
- }
-
- internal void QueuePoolForRelease(DbConnectionPool pool, bool clearing)
- {
- // Queue the pool up for release -- we'll clear it out and dispose
- // of it as the last part of the pruning timer callback so we don't
- // do it with the pool entry or the pool collection locked.
- Debug.Assert(null != pool, "null pool?");
-
- // set the pool to the shutdown state to force all active
- // connections to be automatically disposed when they
- // are returned to the pool
- pool.Shutdown();
-
- lock (_poolsToRelease)
- {
- if (clearing)
- {
- pool.Clear();
- }
- _poolsToRelease.Add(pool);
- }
- }
-
- internal void QueuePoolGroupForRelease(DbConnectionPoolGroup poolGroup)
- {
- Debug.Assert(null != poolGroup, "null poolGroup?");
-
- lock (_poolGroupsToRelease)
- {
- _poolGroupsToRelease.Add(poolGroup);
- }
- }
-
- protected virtual DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions)
- {
- return CreateConnection(options, poolKey, poolGroupProviderInfo, pool, owningConnection);
- }
-
- protected abstract DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection);
-
- protected abstract DbConnectionOptions CreateConnectionOptions(string connectionString, DbConnectionOptions previous);
-
- protected abstract DbConnectionPoolGroupOptions CreateConnectionPoolGroupOptions(DbConnectionOptions options);
-
- internal abstract DbConnectionPoolGroup GetConnectionPoolGroup(DbConnection connection);
-
- internal abstract DbConnectionInternal GetInnerConnection(DbConnection connection);
-
-
- internal abstract void PermissionDemand(DbConnection outerConnection);
-
- internal abstract void SetConnectionPoolGroup(DbConnection outerConnection, DbConnectionPoolGroup poolGroup);
-
- internal abstract void SetInnerConnectionEvent(DbConnection owningObject, DbConnectionInternal to);
-
- internal abstract bool SetInnerConnectionFrom(DbConnection owningObject, DbConnectionInternal to, DbConnectionInternal from);
-
- internal abstract void SetInnerConnectionTo(DbConnection owningObject, DbConnectionInternal to);
+
}
}
diff --git a/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbConnectionInternal.cs b/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbConnectionInternal.cs
index d58b31ba40..9fd4a2ebce 100644
--- a/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbConnectionInternal.cs
+++ b/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbConnectionInternal.cs
@@ -9,168 +9,9 @@ using System.Threading.Tasks;
namespace System.Data.ProviderBase
{
- internal abstract class DbConnectionInternal
+ internal abstract partial class DbConnectionInternal
{
- internal static readonly StateChangeEventArgs StateChangeClosed = new StateChangeEventArgs(ConnectionState.Open, ConnectionState.Closed);
- internal static readonly StateChangeEventArgs StateChangeOpen = new StateChangeEventArgs(ConnectionState.Closed, ConnectionState.Open);
-
- private readonly bool _allowSetConnectionString;
- private readonly bool _hidePassword;
- private readonly ConnectionState _state;
-
- private readonly WeakReference _owningObject = new WeakReference(null, false); // [usage must be thread safe] the owning object, when not in the pool. (both Pooled and Non-Pooled connections)
-
- private DbConnectionPool _connectionPool; // the pooler that the connection came from (Pooled connections only)
- private DbReferenceCollection _referenceCollection; // collection of objects that we need to notify in some way when we're being deactivated
- private int _pooledCount; // [usage must be thread safe] the number of times this object has been pushed into the pool less the number of times it's been popped (0 != inPool)
-
- private bool _connectionIsDoomed; // true when the connection should no longer be used.
- private bool _cannotBePooled; // true when the connection should no longer be pooled.
-
- private DateTime _createTime; // when the connection was created.
-
-
-#if DEBUG
- private int _activateCount; // debug only counter to verify activate/deactivates are in sync.
-#endif //DEBUG
-
- protected DbConnectionInternal() : this(ConnectionState.Open, true, false)
- {
- }
-
- // Constructor for internal connections
- internal DbConnectionInternal(ConnectionState state, bool hidePassword, bool allowSetConnectionString)
- {
- _allowSetConnectionString = allowSetConnectionString;
- _hidePassword = hidePassword;
- _state = state;
- }
-
- internal bool AllowSetConnectionString
- {
- get
- {
- return _allowSetConnectionString;
- }
- }
-
- internal bool CanBePooled
- {
- get
- {
- bool flag = (!_connectionIsDoomed && !_cannotBePooled && !_owningObject.IsAlive);
- return flag;
- }
- }
-
-
- protected internal bool IsConnectionDoomed
- {
- get
- {
- return _connectionIsDoomed;
- }
- }
-
- internal bool IsEmancipated
- {
- get
- {
- // NOTE: There are race conditions between PrePush, PostPop and this
- // property getter -- only use this while this object is locked;
- // (DbConnectionPool.Clear and ReclaimEmancipatedObjects
- // do this for us)
-
- // The functionality is as follows:
- //
- // _pooledCount is incremented when the connection is pushed into the pool
- // _pooledCount is decremented when the connection is popped from the pool
- // _pooledCount is set to -1 when the connection is not pooled (just in case...)
- //
- // That means that:
- //
- // _pooledCount > 1 connection is in the pool multiple times (This should not happen)
- // _pooledCount == 1 connection is in the pool
- // _pooledCount == 0 connection is out of the pool
- // _pooledCount == -1 connection is not a pooled connection; we shouldn't be here for non-pooled connections.
- // _pooledCount < -1 connection out of the pool multiple times
- //
- // Now, our job is to return TRUE when the connection is out
- // of the pool and it's owning object is no longer around to
- // return it.
-
- bool value = (_pooledCount < 1) && !_owningObject.IsAlive;
- return value;
- }
- }
-
- internal bool IsInPool
- {
- get
- {
- Debug.Assert(_pooledCount <= 1 && _pooledCount >= -1, "Pooled count for object is invalid");
- return (_pooledCount == 1);
- }
- }
-
-
- protected internal object Owner
- {
- // We use a weak reference to the owning object so we can identify when
- // it has been garbage collected without thowing exceptions.
- get
- {
- return _owningObject.Target;
- }
- }
-
- internal DbConnectionPool Pool
- {
- get
- {
- return _connectionPool;
- }
- }
-
-
- protected internal DbReferenceCollection ReferenceCollection
- {
- get
- {
- return _referenceCollection;
- }
- }
-
- public abstract string ServerVersion
- {
- get;
- }
-
- // this should be abstract but until it is added to all the providers virtual will have to do
- public virtual string ServerVersionNormalized
- {
- get
- {
- throw ADP.NotSupported();
- }
- }
-
- public bool ShouldHidePassword
- {
- get
- {
- return _hidePassword;
- }
- }
-
- public ConnectionState State
- {
- get
- {
- return _state;
- }
- }
-
+
protected abstract void Activate();
internal void ActivateConnection()
@@ -187,26 +28,6 @@ namespace System.Data.ProviderBase
Activate();
}
- internal void AddWeakReference(object value, int tag)
- {
- if (null == _referenceCollection)
- {
- _referenceCollection = CreateReferenceCollection();
- if (null == _referenceCollection)
- {
- throw ADP.InternalError(ADP.InternalErrorCode.CreateReferenceCollectionReturnedNull);
- }
- }
- _referenceCollection.Add(value, tag);
- }
-
- public abstract DbTransaction BeginTransaction(IsolationLevel il);
-
- public virtual void ChangeDatabase(string value)
- {
- throw ADP.MethodNotImplemented();
- }
-
internal virtual void CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory)
{
// The implementation here is the implementation required for the
@@ -304,245 +125,10 @@ namespace System.Data.ProviderBase
}
}
- internal virtual void PrepareForReplaceConnection()
- {
- // By default, there is no preparation required
- }
-
- protected virtual void PrepareForCloseConnection()
- {
- // By default, there is no preparation required
- }
-
- protected virtual object ObtainAdditionalLocksForClose()
- {
- return null; // no additional locks in default implementation
- }
-
- protected virtual void ReleaseAdditionalLocksForClose(object lockToken)
- {
- // no additional locks in default implementation
- }
-
- protected virtual DbReferenceCollection CreateReferenceCollection()
- {
- throw ADP.InternalError(ADP.InternalErrorCode.AttemptingToConstructReferenceCollectionOnStaticObject);
- }
-
- protected abstract void Deactivate();
-
- internal void DeactivateConnection()
- {
- // Internal method called from the connection pooler so we don't expose
- // the Deactivate method publicly.
-
-#if DEBUG
- int activateCount = Interlocked.Decrement(ref _activateCount);
- Debug.Assert(0 == activateCount, "activated multiple times?");
-#endif // DEBUG
-
-
- if (!_connectionIsDoomed && Pool.UseLoadBalancing)
- {
- // If we're not already doomed, check the connection's lifetime and
- // doom it if it's lifetime has elapsed.
-
- DateTime now = DateTime.UtcNow;
- if ((now.Ticks - _createTime.Ticks) > Pool.LoadBalanceTimeout.Ticks)
- {
- DoNotPoolThisConnection();
- }
- }
- Deactivate();
- }
-
-
public virtual void Dispose()
{
_connectionPool = null;
_connectionIsDoomed = true;
}
-
- protected internal void DoNotPoolThisConnection()
- {
- _cannotBePooled = true;
- }
-
- /// <devdoc>Ensure that this connection cannot be put back into the pool.</devdoc>
- protected internal void DoomThisConnection()
- {
- _connectionIsDoomed = true;
- }
-
-
- internal void MakeNonPooledObject(object owningObject)
- {
- // Used by DbConnectionFactory to indicate that this object IS NOT part of
- // a connection pool.
-
- _connectionPool = null;
- _owningObject.Target = owningObject;
- _pooledCount = -1;
- }
-
- internal void MakePooledConnection(DbConnectionPool connectionPool)
- {
- // Used by DbConnectionFactory to indicate that this object IS part of
- // a connection pool.
- _createTime = DateTime.UtcNow;
-
- _connectionPool = connectionPool;
- }
-
- internal void NotifyWeakReference(int message)
- {
- DbReferenceCollection referenceCollection = ReferenceCollection;
- if (null != referenceCollection)
- {
- referenceCollection.Notify(message);
- }
- }
-
- internal virtual void OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
- {
- if (!TryOpenConnection(outerConnection, connectionFactory, null, null))
- {
- throw ADP.InternalError(ADP.InternalErrorCode.SynchronousConnectReturnedPending);
- }
- }
-
- /// <devdoc>The default implementation is for the open connection objects, and
- /// it simply throws. Our private closed-state connection objects
- /// override this and do the correct thing.</devdoc>
- // User code should either override DbConnectionInternal.Activate when it comes out of the pool
- // or override DbConnectionFactory.CreateConnection when the connection is created for non-pooled connections
- internal virtual bool TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
- {
- throw ADP.ConnectionAlreadyOpen(State);
- }
-
- internal virtual bool TryReplaceConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
- {
- throw ADP.MethodNotImplemented();
- }
-
- protected bool TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
- {
- // ?->Connecting: prevent set_ConnectionString during Open
- if (connectionFactory.SetInnerConnectionFrom(outerConnection, DbConnectionClosedConnecting.SingletonInstance, this))
- {
- DbConnectionInternal openConnection = null;
- try
- {
- connectionFactory.PermissionDemand(outerConnection);
- if (!connectionFactory.TryGetConnection(outerConnection, retry, userOptions, this, out openConnection))
- {
- return false;
- }
- }
- catch
- {
- // This should occur for all exceptions, even ADP.UnCatchableExceptions.
- connectionFactory.SetInnerConnectionTo(outerConnection, this);
- throw;
- }
- if (null == openConnection)
- {
- connectionFactory.SetInnerConnectionTo(outerConnection, this);
- throw ADP.InternalConnectionError(ADP.ConnectionError.GetConnectionReturnsNull);
- }
- connectionFactory.SetInnerConnectionEvent(outerConnection, openConnection);
- }
-
- return true;
- }
-
- internal void PrePush(object expectedOwner)
- {
- // Called by DbConnectionPool when we're about to be put into it's pool, we
- // take this opportunity to ensure ownership and pool counts are legit.
-
- // IMPORTANT NOTE: You must have taken a lock on the object before
- // you call this method to prevent race conditions with Clear and
- // ReclaimEmancipatedObjects.
-
- //3 // The following tests are retail assertions of things we can't allow to happen.
- if (null == expectedOwner)
- {
- if (null != _owningObject.Target)
- {
- throw ADP.InternalError(ADP.InternalErrorCode.UnpooledObjectHasOwner); // new unpooled object has an owner
- }
- }
- else if (_owningObject.Target != expectedOwner)
- {
- throw ADP.InternalError(ADP.InternalErrorCode.UnpooledObjectHasWrongOwner); // unpooled object has incorrect owner
- }
- if (0 != _pooledCount)
- {
- throw ADP.InternalError(ADP.InternalErrorCode.PushingObjectSecondTime); // pushing object onto stack a second time
- }
- _pooledCount++;
- _owningObject.Target = null; // NOTE: doing this and checking for InternalError.PooledObjectHasOwner degrades the close by 2%
- }
-
- internal void PostPop(object newOwner)
- {
- // Called by DbConnectionPool right after it pulls this from it's pool, we
- // take this opportunity to ensure ownership and pool counts are legit.
-
- Debug.Assert(!IsEmancipated, "pooled object not in pool");
-
- // When another thread is clearing this pool, it
- // will doom all connections in this pool without prejudice which
- // causes the following assert to fire, which really mucks up stress
- // against checked bits. The assert is benign, so we're commenting
- // it out.
- //Debug.Assert(CanBePooled, "pooled object is not poolable");
-
- // IMPORTANT NOTE: You must have taken a lock on the object before
- // you call this method to prevent race conditions with Clear and
- // ReclaimEmancipatedObjects.
-
- if (null != _owningObject.Target)
- {
- throw ADP.InternalError(ADP.InternalErrorCode.PooledObjectHasOwner); // pooled connection already has an owner!
- }
- _owningObject.Target = newOwner;
- _pooledCount--;
- //3 // The following tests are retail assertions of things we can't allow to happen.
- if (null != Pool)
- {
- if (0 != _pooledCount)
- {
- throw ADP.InternalError(ADP.InternalErrorCode.PooledObjectInPoolMoreThanOnce); // popping object off stack with multiple pooledCount
- }
- }
- else if (-1 != _pooledCount)
- {
- throw ADP.InternalError(ADP.InternalErrorCode.NonPooledObjectUsedMoreThanOnce); // popping object off stack with multiple pooledCount
- }
- }
-
- internal void RemoveWeakReference(object value)
- {
- DbReferenceCollection referenceCollection = ReferenceCollection;
- if (null != referenceCollection)
- {
- referenceCollection.Remove(value);
- }
- }
-
-
- /// <summary>
- /// When overridden in a derived class, will check if the underlying connection is still actually alive
- /// </summary>
- /// <param name="throwOnException">If true an exception will be thrown if the connection is dead instead of returning true\false
- /// (this allows the caller to have the real reason that the connection is not alive (e.g. network error, etc))</param>
- /// <returns>True if the connection is still alive, otherwise false (If not overridden, then always true)</returns>
- internal virtual bool IsConnectionAlive(bool throwOnException = false)
- {
- return true;
- }
}
}
diff --git a/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbConnectionPool.cs b/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbConnectionPool.cs
index 6ee71c12e0..6dec8d24b5 100644
--- a/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbConnectionPool.cs
+++ b/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbConnectionPool.cs
@@ -382,9 +382,11 @@ namespace System.Data.ProviderBase
}
private Timer CreateCleanupTimer()
- {
- return (new Timer(new TimerCallback(this.CleanupCallback), null, _cleanupWait, _cleanupWait));
- }
+ => ADP.UnsafeCreateTimer(
+ new TimerCallback(CleanupCallback),
+ null,
+ _cleanupWait,
+ _cleanupWait);
private DbConnectionInternal CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
{
diff --git a/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbConnectionPoolGroup.cs b/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbConnectionPoolGroup.cs
deleted file mode 100644
index 9e0a10c200..0000000000
--- a/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbConnectionPoolGroup.cs
+++ /dev/null
@@ -1,302 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Concurrent;
-using System.Data.Common;
-using System.Diagnostics;
-
-namespace System.Data.ProviderBase
-{
- // set_ConnectionString calls DbConnectionFactory.GetConnectionPoolGroup
- // when not found a new pool entry is created and potentially added
- // DbConnectionPoolGroup starts in the Active state
-
- // Open calls DbConnectionFactory.GetConnectionPool
- // if the existing pool entry is Disabled, GetConnectionPoolGroup is called for a new entry
- // DbConnectionFactory.GetConnectionPool calls DbConnectionPoolGroup.GetConnectionPool
-
- // DbConnectionPoolGroup.GetConnectionPool will return pool for the current identity
- // or null if identity is restricted or pooling is disabled or state is disabled at time of add
- // state changes are Active->Active, Idle->Active
-
- // DbConnectionFactory.PruneConnectionPoolGroups calls Prune
- // which will QueuePoolForRelease on all empty pools
- // and once no pools remain, change state from Active->Idle->Disabled
- // Once Disabled, factory can remove its reference to the pool entry
-
- internal sealed class DbConnectionPoolGroup
- {
- private readonly DbConnectionOptions _connectionOptions;
- private readonly DbConnectionPoolKey _poolKey;
- private readonly DbConnectionPoolGroupOptions _poolGroupOptions;
- private ConcurrentDictionary<DbConnectionPoolIdentity, DbConnectionPool> _poolCollection;
-
- private int _state; // see PoolGroupState* below
-
- private DbConnectionPoolGroupProviderInfo _providerInfo;
-
- // always lock this before changing _state, we don't want to move out of the 'Disabled' state
- // PoolGroupStateUninitialized = 0;
- private const int PoolGroupStateActive = 1; // initial state, GetPoolGroup from cache, connection Open
- private const int PoolGroupStateIdle = 2; // all pools are pruned via Clear
- private const int PoolGroupStateDisabled = 4; // factory pool entry pruning method
-
- internal DbConnectionPoolGroup(DbConnectionOptions connectionOptions, DbConnectionPoolKey key, DbConnectionPoolGroupOptions poolGroupOptions)
- {
- Debug.Assert(null != connectionOptions, "null connection options");
-
- _connectionOptions = connectionOptions;
- _poolKey = key;
- _poolGroupOptions = poolGroupOptions;
-
- // always lock this object before changing state
- // HybridDictionary does not create any sub-objects until add
- // so it is safe to use for non-pooled connection as long as
- // we check _poolGroupOptions first
- _poolCollection = new ConcurrentDictionary<DbConnectionPoolIdentity, DbConnectionPool>();
- _state = PoolGroupStateActive;
- }
-
- internal DbConnectionOptions ConnectionOptions
- {
- get
- {
- return _connectionOptions;
- }
- }
-
- internal DbConnectionPoolKey PoolKey
- {
- get
- {
- return _poolKey;
- }
- }
-
- internal DbConnectionPoolGroupProviderInfo ProviderInfo
- {
- get
- {
- return _providerInfo;
- }
- set
- {
- _providerInfo = value;
- if (null != value)
- {
- _providerInfo.PoolGroup = this;
- }
- }
- }
-
- internal bool IsDisabled
- {
- get
- {
- return (PoolGroupStateDisabled == _state);
- }
- }
-
-
- internal DbConnectionPoolGroupOptions PoolGroupOptions
- {
- get
- {
- return _poolGroupOptions;
- }
- }
-
-
- internal int Clear()
- {
- // must be multi-thread safe with competing calls by Clear and Prune via background thread
- // will return the number of connections in the group after clearing has finished
-
- // First, note the old collection and create a new collection to be used
- ConcurrentDictionary<DbConnectionPoolIdentity, DbConnectionPool> oldPoolCollection = null;
- lock (this)
- {
- if (_poolCollection.Count > 0)
- {
- oldPoolCollection = _poolCollection;
- _poolCollection = new ConcurrentDictionary<DbConnectionPoolIdentity, DbConnectionPool>();
- }
- }
-
- // Then, if a new collection was created, release the pools from the old collection
- if (oldPoolCollection != null)
- {
- foreach (var entry in oldPoolCollection)
- {
- DbConnectionPool pool = entry.Value;
- if (pool != null)
- {
- DbConnectionFactory connectionFactory = pool.ConnectionFactory;
- connectionFactory.QueuePoolForRelease(pool, true);
- }
- }
- }
-
- // Finally, return the pool collection count - this may be non-zero if something was added while we were clearing
- return _poolCollection.Count;
- }
-
- internal DbConnectionPool GetConnectionPool(DbConnectionFactory connectionFactory)
- {
- // When this method returns null it indicates that the connection
- // factory should not use pooling.
-
- // We don't support connection pooling on Win9x;
- // PoolGroupOptions will only be null when we're not supposed to pool
- // connections.
- DbConnectionPool pool = null;
- if (null != _poolGroupOptions)
- {
- DbConnectionPoolIdentity currentIdentity = DbConnectionPoolIdentity.NoIdentity;
-
- if (_poolGroupOptions.PoolByIdentity)
- {
- // if we're pooling by identity (because integrated security is
- // being used for these connections) then we need to go out and
- // search for the connectionPool that matches the current identity.
-
- currentIdentity = DbConnectionPoolIdentity.GetCurrent();
-
- // If the current token is restricted in some way, then we must
- // not attempt to pool these connections.
- if (currentIdentity.IsRestricted)
- {
- currentIdentity = null;
- }
- }
- if (null != currentIdentity)
- {
- if (!_poolCollection.TryGetValue(currentIdentity, out pool))
- { // find the pool
- DbConnectionPoolProviderInfo connectionPoolProviderInfo = connectionFactory.CreateConnectionPoolProviderInfo(this.ConnectionOptions);
-
- // optimistically create pool, but its callbacks are delayed until after actual add
- DbConnectionPool newPool = new DbConnectionPool(connectionFactory, this, currentIdentity, connectionPoolProviderInfo);
-
- lock (this)
- {
- // Did someone already add it to the list?
- if (!_poolCollection.TryGetValue(currentIdentity, out pool))
- {
- if (MarkPoolGroupAsActive())
- {
- // If we get here, we know for certain that we there isn't
- // a pool that matches the current identity, so we have to
- // add the optimistically created one
- newPool.Startup(); // must start pool before usage
- bool addResult = _poolCollection.TryAdd(currentIdentity, newPool);
- Debug.Assert(addResult, "No other pool with current identity should exist at this point");
- pool = newPool;
- newPool = null;
- }
- else
- {
- // else pool entry has been disabled so don't create new pools
- Debug.Assert(PoolGroupStateDisabled == _state, "state should be disabled");
- }
- }
- else
- {
- // else found an existing pool to use instead
- Debug.Assert(PoolGroupStateActive == _state, "state should be active since a pool exists and lock holds");
- }
- }
-
- if (null != newPool)
- {
- // don't need to call connectionFactory.QueuePoolForRelease(newPool) because
- // pool callbacks were delayed and no risk of connections being created
- newPool.Shutdown();
- }
- }
- // the found pool could be in any state
- }
- }
-
- if (null == pool)
- {
- lock (this)
- {
- // keep the pool entry state active when not pooling
- MarkPoolGroupAsActive();
- }
- }
- return pool;
- }
-
- private bool MarkPoolGroupAsActive()
- {
- // when getting a connection, make the entry active if it was idle (but not disabled)
- // must always lock this before calling
-
- if (PoolGroupStateIdle == _state)
- {
- _state = PoolGroupStateActive;
- }
- return (PoolGroupStateActive == _state);
- }
-
- internal bool Prune()
- {
- // must only call from DbConnectionFactory.PruneConnectionPoolGroups on background timer thread
- // must lock(DbConnectionFactory._connectionPoolGroups.SyncRoot) before calling ReadyToRemove
- // to avoid conflict with DbConnectionFactory.CreateConnectionPoolGroup replacing pool entry
- lock (this)
- {
- if (_poolCollection.Count > 0)
- {
- var newPoolCollection = new ConcurrentDictionary<DbConnectionPoolIdentity, DbConnectionPool>();
-
- foreach (var entry in _poolCollection)
- {
- DbConnectionPool pool = entry.Value;
- if (pool != null)
- {
- // Actually prune the pool if there are no connections in the pool and no errors occurred.
- // Empty pool during pruning indicates zero or low activity, but
- // an error state indicates the pool needs to stay around to
- // throttle new connection attempts.
- if ((!pool.ErrorOccurred) && (0 == pool.Count))
- {
- // Order is important here. First we remove the pool
- // from the collection of pools so no one will try
- // to use it while we're processing and finally we put the
- // pool into a list of pools to be released when they
- // are completely empty.
- DbConnectionFactory connectionFactory = pool.ConnectionFactory;
-
- connectionFactory.QueuePoolForRelease(pool, false);
- }
- else
- {
- newPoolCollection.TryAdd(entry.Key, entry.Value);
- }
- }
- }
- _poolCollection = newPoolCollection;
- }
-
- // must be pruning thread to change state and no connections
- // otherwise pruning thread risks making entry disabled soon after user calls ClearPool
- if (0 == _poolCollection.Count)
- {
- if (PoolGroupStateActive == _state)
- {
- _state = PoolGroupStateIdle;
- }
- else if (PoolGroupStateIdle == _state)
- {
- _state = PoolGroupStateDisabled;
- }
- }
- return (PoolGroupStateDisabled == _state);
- }
- }
- }
-}
diff --git a/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbMetaDataFactory.cs b/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbMetaDataFactory.cs
deleted file mode 100644
index 8c941a5a67..0000000000
--- a/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbMetaDataFactory.cs
+++ /dev/null
@@ -1,583 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Data.Common;
-using System.Diagnostics;
-using System.Globalization;
-using System.IO;
-
-namespace System.Data.ProviderBase
-{
- internal class DbMetaDataFactory
- { // V1.2.3300
- private DataSet _metaDataCollectionsDataSet;
- private string _normalizedServerVersion;
- private string _serverVersionString;
- // well known column names
- private const string _collectionName = "CollectionName";
- private const string _populationMechanism = "PopulationMechanism";
- private const string _populationString = "PopulationString";
- private const string _maximumVersion = "MaximumVersion";
- private const string _minimumVersion = "MinimumVersion";
- private const string _dataSourceProductVersionNormalized = "DataSourceProductVersionNormalized";
- private const string _dataSourceProductVersion = "DataSourceProductVersion";
- private const string _restrictionDefault = "RestrictionDefault";
- private const string _restrictionNumber = "RestrictionNumber";
- private const string _numberOfRestrictions = "NumberOfRestrictions";
- private const string _restrictionName = "RestrictionName";
- private const string _parameterName = "ParameterName";
-
- // population mechanisms
- private const string _dataTable = "DataTable";
- private const string _sqlCommand = "SQLCommand";
- private const string _prepareCollection = "PrepareCollection";
-
-
- public DbMetaDataFactory(Stream xmlStream, string serverVersion, string normalizedServerVersion)
- {
- ADP.CheckArgumentNull(xmlStream, "xmlStream");
- ADP.CheckArgumentNull(serverVersion, "serverVersion");
- ADP.CheckArgumentNull(normalizedServerVersion, "normalizedServerVersion");
-
- LoadDataSetFromXml(xmlStream);
-
- _serverVersionString = serverVersion;
- _normalizedServerVersion = normalizedServerVersion;
- }
-
- protected DataSet CollectionDataSet
- {
- get
- {
- return _metaDataCollectionsDataSet;
- }
- }
-
- protected string ServerVersion
- {
- get
- {
- return _serverVersionString;
- }
- }
-
-
- protected string ServerVersionNormalized
- {
- get
- {
- return _normalizedServerVersion;
- }
- }
-
- protected DataTable CloneAndFilterCollection(string collectionName, string[] hiddenColumnNames)
- {
- DataTable sourceTable;
- DataTable destinationTable;
- DataColumn[] filteredSourceColumns;
- DataColumnCollection destinationColumns;
- DataRow newRow;
-
- sourceTable = _metaDataCollectionsDataSet.Tables[collectionName];
-
- if ((sourceTable == null) || (collectionName != sourceTable.TableName))
- {
- throw ADP.DataTableDoesNotExist(collectionName);
- }
-
- destinationTable = new DataTable(collectionName);
- destinationTable.Locale = CultureInfo.InvariantCulture;
- destinationColumns = destinationTable.Columns;
-
- filteredSourceColumns = FilterColumns(sourceTable, hiddenColumnNames, destinationColumns);
-
- foreach (DataRow row in sourceTable.Rows)
- {
- if (SupportedByCurrentVersion(row) == true)
- {
- newRow = destinationTable.NewRow();
- for (int i = 0; i < destinationColumns.Count; i++)
- {
- newRow[destinationColumns[i]] = row[filteredSourceColumns[i], DataRowVersion.Current];
- }
- destinationTable.Rows.Add(newRow);
- newRow.AcceptChanges();
- }
- }
-
- return destinationTable;
- }
-
- public void Dispose()
- {
- Dispose(true);
- }
-
- protected virtual void Dispose(bool disposing)
- {
- if (disposing)
- {
- _normalizedServerVersion = null;
- _serverVersionString = null;
- _metaDataCollectionsDataSet.Dispose();
- }
- }
-
- private DataTable ExecuteCommand(DataRow requestedCollectionRow, String[] restrictions, DbConnection connection)
- {
- DataTable metaDataCollectionsTable = _metaDataCollectionsDataSet.Tables[DbMetaDataCollectionNames.MetaDataCollections];
- DataColumn populationStringColumn = metaDataCollectionsTable.Columns[_populationString];
- DataColumn numberOfRestrictionsColumn = metaDataCollectionsTable.Columns[_numberOfRestrictions];
- DataColumn collectionNameColumn = metaDataCollectionsTable.Columns[_collectionName];
- //DataColumn restrictionNameColumn = metaDataCollectionsTable.Columns[_restrictionName];
-
- DataTable resultTable = null;
- DbCommand command = null;
- DataTable schemaTable = null;
-
- Debug.Assert(requestedCollectionRow != null);
- String sqlCommand = requestedCollectionRow[populationStringColumn, DataRowVersion.Current] as string;
- int numberOfRestrictions = (int)requestedCollectionRow[numberOfRestrictionsColumn, DataRowVersion.Current];
- String collectionName = requestedCollectionRow[collectionNameColumn, DataRowVersion.Current] as string;
-
- if ((restrictions != null) && (restrictions.Length > numberOfRestrictions))
- {
- throw ADP.TooManyRestrictions(collectionName);
- }
-
- command = connection.CreateCommand();
- command.CommandText = sqlCommand;
- command.CommandTimeout = System.Math.Max(command.CommandTimeout, 180);
-
- for (int i = 0; i < numberOfRestrictions; i++)
- {
- DbParameter restrictionParameter = command.CreateParameter();
-
-
- if ((restrictions != null) && (restrictions.Length > i) && (restrictions[i] != null))
- {
- restrictionParameter.Value = restrictions[i];
- }
- else
- {
- // This is where we have to assign null to the value of the parameter.
- restrictionParameter.Value = DBNull.Value;
- }
-
- restrictionParameter.ParameterName = GetParameterName(collectionName, i + 1);
- restrictionParameter.Direction = ParameterDirection.Input;
- command.Parameters.Add(restrictionParameter);
- }
-
- DbDataReader reader = null;
- try
- {
- try
- {
- reader = command.ExecuteReader();
- }
- catch (Exception e)
- {
- if (!ADP.IsCatchableExceptionType(e))
- {
- throw;
- }
- throw ADP.QueryFailed(collectionName, e);
- }
-
- //
-
- // Build a DataTable from the reader
- resultTable = new DataTable(collectionName);
- resultTable.Locale = CultureInfo.InvariantCulture;
-
- schemaTable = reader.GetSchemaTable();
- foreach (DataRow row in schemaTable.Rows)
- {
- resultTable.Columns.Add(row["ColumnName"] as string, (Type)row["DataType"] as Type);
- }
- object[] values = new object[resultTable.Columns.Count];
- while (reader.Read())
- {
- reader.GetValues(values);
- resultTable.Rows.Add(values);
- }
- }
- finally
- {
- if (reader != null)
- {
- reader.Dispose();
- reader = null;
- }
- }
- return resultTable;
- }
-
- private DataColumn[] FilterColumns(DataTable sourceTable, string[] hiddenColumnNames, DataColumnCollection destinationColumns)
- {
- DataColumn newDestinationColumn;
- int currentColumn;
- DataColumn[] filteredSourceColumns = null;
-
- int columnCount = 0;
- foreach (DataColumn sourceColumn in sourceTable.Columns)
- {
- if (IncludeThisColumn(sourceColumn, hiddenColumnNames) == true)
- {
- columnCount++;
- }
- }
-
- if (columnCount == 0)
- {
- throw ADP.NoColumns();
- }
-
- currentColumn = 0;
- filteredSourceColumns = new DataColumn[columnCount];
-
- foreach (DataColumn sourceColumn in sourceTable.Columns)
- {
- if (IncludeThisColumn(sourceColumn, hiddenColumnNames) == true)
- {
- newDestinationColumn = new DataColumn(sourceColumn.ColumnName, sourceColumn.DataType);
- destinationColumns.Add(newDestinationColumn);
- filteredSourceColumns[currentColumn] = sourceColumn;
- currentColumn++;
- }
- }
- return filteredSourceColumns;
- }
-
- internal DataRow FindMetaDataCollectionRow(string collectionName)
- {
- bool versionFailure;
- bool haveExactMatch;
- bool haveMultipleInexactMatches;
- string candidateCollectionName;
-
- DataTable metaDataCollectionsTable = _metaDataCollectionsDataSet.Tables[DbMetaDataCollectionNames.MetaDataCollections];
- if (metaDataCollectionsTable == null)
- {
- throw ADP.InvalidXml();
- }
-
- DataColumn collectionNameColumn = metaDataCollectionsTable.Columns[DbMetaDataColumnNames.CollectionName];
-
- if ((null == collectionNameColumn) || (typeof(System.String) != collectionNameColumn.DataType))
- {
- throw ADP.InvalidXmlMissingColumn(DbMetaDataCollectionNames.MetaDataCollections, DbMetaDataColumnNames.CollectionName);
- }
-
- DataRow requestedCollectionRow = null;
- String exactCollectionName = null;
-
- // find the requested collection
- versionFailure = false;
- haveExactMatch = false;
- haveMultipleInexactMatches = false;
-
- foreach (DataRow row in metaDataCollectionsTable.Rows)
- {
- candidateCollectionName = row[collectionNameColumn, DataRowVersion.Current] as string;
- if (string.IsNullOrEmpty(candidateCollectionName))
- {
- throw ADP.InvalidXmlInvalidValue(DbMetaDataCollectionNames.MetaDataCollections, DbMetaDataColumnNames.CollectionName);
- }
-
- if (ADP.CompareInsensitiveInvariant(candidateCollectionName, collectionName))
- {
- if (SupportedByCurrentVersion(row) == false)
- {
- versionFailure = true;
- }
- else
- {
- if (collectionName == candidateCollectionName)
- {
- if (haveExactMatch == true)
- {
- throw ADP.CollectionNameIsNotUnique(collectionName);
- }
- requestedCollectionRow = row;
- exactCollectionName = candidateCollectionName;
- haveExactMatch = true;
- }
- else
- {
- // have an inexact match - ok only if it is the only one
- if (exactCollectionName != null)
- {
- // can't fail here becasue we may still find an exact match
- haveMultipleInexactMatches = true;
- }
- requestedCollectionRow = row;
- exactCollectionName = candidateCollectionName;
- }
- }
- }
- }
-
- if (requestedCollectionRow == null)
- {
- if (versionFailure == false)
- {
- throw ADP.UndefinedCollection(collectionName);
- }
- else
- {
- throw ADP.UnsupportedVersion(collectionName);
- }
- }
-
- if ((haveExactMatch == false) && (haveMultipleInexactMatches == true))
- {
- throw ADP.AmbigousCollectionName(collectionName);
- }
-
- return requestedCollectionRow;
- }
-
- private void FixUpVersion(DataTable dataSourceInfoTable)
- {
- Debug.Assert(dataSourceInfoTable.TableName == DbMetaDataCollectionNames.DataSourceInformation);
- DataColumn versionColumn = dataSourceInfoTable.Columns[_dataSourceProductVersion];
- DataColumn normalizedVersionColumn = dataSourceInfoTable.Columns[_dataSourceProductVersionNormalized];
-
- if ((versionColumn == null) || (normalizedVersionColumn == null))
- {
- throw ADP.MissingDataSourceInformationColumn();
- }
-
- if (dataSourceInfoTable.Rows.Count != 1)
- {
- throw ADP.IncorrectNumberOfDataSourceInformationRows();
- }
-
- DataRow dataSourceInfoRow = dataSourceInfoTable.Rows[0];
-
- dataSourceInfoRow[versionColumn] = _serverVersionString;
- dataSourceInfoRow[normalizedVersionColumn] = _normalizedServerVersion;
- dataSourceInfoRow.AcceptChanges();
- }
-
-
- private string GetParameterName(string neededCollectionName, int neededRestrictionNumber)
- {
- DataTable restrictionsTable = null;
- DataColumnCollection restrictionColumns = null;
- DataColumn collectionName = null;
- DataColumn parameterName = null;
- DataColumn restrictionName = null;
- DataColumn restrictionNumber = null; ;
- string result = null;
-
- restrictionsTable = _metaDataCollectionsDataSet.Tables[DbMetaDataCollectionNames.Restrictions];
- if (restrictionsTable != null)
- {
- restrictionColumns = restrictionsTable.Columns;
- if (restrictionColumns != null)
- {
- collectionName = restrictionColumns[_collectionName];
- parameterName = restrictionColumns[_parameterName];
- restrictionName = restrictionColumns[_restrictionName];
- restrictionNumber = restrictionColumns[_restrictionNumber];
- }
- }
-
- if ((parameterName == null) || (collectionName == null) || (restrictionName == null) || (restrictionNumber == null))
- {
- throw ADP.MissingRestrictionColumn();
- }
-
- foreach (DataRow restriction in restrictionsTable.Rows)
- {
- if (((string)restriction[collectionName] == neededCollectionName) &&
- ((int)restriction[restrictionNumber] == neededRestrictionNumber) &&
- (SupportedByCurrentVersion(restriction)))
- {
- result = (string)restriction[parameterName];
- break;
- }
- }
-
- if (result == null)
- {
- throw ADP.MissingRestrictionRow();
- }
-
- return result;
- }
-
- public virtual DataTable GetSchema(DbConnection connection, string collectionName, string[] restrictions)
- {
- Debug.Assert(_metaDataCollectionsDataSet != null);
-
- //
- DataTable metaDataCollectionsTable = _metaDataCollectionsDataSet.Tables[DbMetaDataCollectionNames.MetaDataCollections];
- DataColumn populationMechanismColumn = metaDataCollectionsTable.Columns[_populationMechanism];
- DataColumn collectionNameColumn = metaDataCollectionsTable.Columns[DbMetaDataColumnNames.CollectionName];
- DataRow requestedCollectionRow = null;
- DataTable requestedSchema = null;
- string[] hiddenColumns;
- string exactCollectionName = null;
-
- requestedCollectionRow = FindMetaDataCollectionRow(collectionName);
- exactCollectionName = requestedCollectionRow[collectionNameColumn, DataRowVersion.Current] as string;
-
- if (ADP.IsEmptyArray(restrictions) == false)
- {
- for (int i = 0; i < restrictions.Length; i++)
- {
- if ((restrictions[i] != null) && (restrictions[i].Length > 4096))
- {
- // use a non-specific error because no new beta 2 error messages are allowed
- //
- throw ADP.NotSupported();
- }
- }
- }
-
- string populationMechanism = requestedCollectionRow[populationMechanismColumn, DataRowVersion.Current] as string;
- switch (populationMechanism)
- {
- case _dataTable:
- if (exactCollectionName == DbMetaDataCollectionNames.MetaDataCollections)
- {
- hiddenColumns = new string[2];
- hiddenColumns[0] = _populationMechanism;
- hiddenColumns[1] = _populationString;
- }
- else
- {
- hiddenColumns = null;
- }
- // none of the datatable collections support restrictions
- if (ADP.IsEmptyArray(restrictions) == false)
- {
- throw ADP.TooManyRestrictions(exactCollectionName);
- }
-
-
- requestedSchema = CloneAndFilterCollection(exactCollectionName, hiddenColumns);
-
- //
-
- // for the data source infomation table we need to fix up the version columns at run time
- // since the version is determined at run time
- if (exactCollectionName == DbMetaDataCollectionNames.DataSourceInformation)
- {
- FixUpVersion(requestedSchema);
- }
- break;
-
- case _sqlCommand:
- requestedSchema = ExecuteCommand(requestedCollectionRow, restrictions, connection);
- break;
-
- case _prepareCollection:
- requestedSchema = PrepareCollection(exactCollectionName, restrictions, connection);
- break;
-
- default:
- throw ADP.UndefinedPopulationMechanism(populationMechanism);
- }
-
- return requestedSchema;
- }
-
- private bool IncludeThisColumn(DataColumn sourceColumn, string[] hiddenColumnNames)
- {
- bool result = true;
- string sourceColumnName = sourceColumn.ColumnName;
-
- switch (sourceColumnName)
- {
- case _minimumVersion:
- case _maximumVersion:
- result = false;
- break;
-
- default:
- if (hiddenColumnNames == null)
- {
- break;
- }
- for (int i = 0; i < hiddenColumnNames.Length; i++)
- {
- if (hiddenColumnNames[i] == sourceColumnName)
- {
- result = false;
- break;
- }
- }
- break;
- }
-
- return result;
- }
-
- private void LoadDataSetFromXml(Stream XmlStream)
- {
- _metaDataCollectionsDataSet = new DataSet();
- _metaDataCollectionsDataSet.Locale = System.Globalization.CultureInfo.InvariantCulture;
- _metaDataCollectionsDataSet.ReadXml(XmlStream);
- }
-
- protected virtual DataTable PrepareCollection(String collectionName, String[] restrictions, DbConnection connection)
- {
- throw ADP.NotSupported();
- }
-
- private bool SupportedByCurrentVersion(DataRow requestedCollectionRow)
- {
- bool result = true;
- DataColumnCollection tableColumns = requestedCollectionRow.Table.Columns;
- DataColumn versionColumn;
- Object version;
-
- // check the minimum version first
- versionColumn = tableColumns[_minimumVersion];
- if (versionColumn != null)
- {
- version = requestedCollectionRow[versionColumn];
- if (version != null)
- {
- if (version != DBNull.Value)
- {
- if (0 > string.Compare(_normalizedServerVersion, (string)version, StringComparison.OrdinalIgnoreCase))
- {
- result = false;
- }
- }
- }
- }
-
- // if the minmum version was ok what about the maximum version
- if (result == true)
- {
- versionColumn = tableColumns[_maximumVersion];
- if (versionColumn != null)
- {
- version = requestedCollectionRow[versionColumn];
- if (version != null)
- {
- if (version != DBNull.Value)
- {
- if (0 < string.Compare(_normalizedServerVersion, (string)version, StringComparison.OrdinalIgnoreCase))
- {
- result = false;
- }
- }
- }
- }
- }
-
- return result;
- }
- }
-}
-
-
diff --git a/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbReferenceCollection.cs b/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbReferenceCollection.cs
deleted file mode 100644
index 442ca95301..0000000000
--- a/src/System.Data.Odbc/src/Common/System/Data/ProviderBase/DbReferenceCollection.cs
+++ /dev/null
@@ -1,282 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-using System.Threading;
-
-namespace System.Data.ProviderBase
-{
- internal abstract class DbReferenceCollection
- {
- private struct CollectionEntry
- {
- private int _tag; // information about the reference
- private WeakReference _weak; // the reference itself.
-
- public void NewTarget(int tag, object target)
- {
- Debug.Assert(!HasTarget, "Entry already has a valid target");
- Debug.Assert(tag != 0, "Bad tag");
- Debug.Assert(target != null, "Invalid target");
-
- if (_weak == null)
- {
- _weak = new WeakReference(target, false);
- }
- else
- {
- _weak.Target = target;
- }
- _tag = tag;
- }
-
- public void RemoveTarget()
- {
- _tag = 0;
- }
-
- public bool HasTarget
- {
- get
- {
- return ((_tag != 0) && (_weak.IsAlive));
- }
- }
-
- public int Tag
- {
- get
- {
- return _tag;
- }
- }
-
- public object Target
- {
- get
- {
- return (_tag == 0 ? null : _weak.Target);
- }
- }
- }
-
- private const int LockPollTime = 100; // Time to wait (in ms) between attempting to get the _itemLock
- private const int DefaultCollectionSize = 20; // Default size for the collection, and the amount to grow every time the collection is full
- private CollectionEntry[] _items; // The collection of items we are keeping track of
- private readonly object _itemLock; // Used to synchronize access to the _items collection
- private int _optimisticCount; // (#ItemsAdded - #ItemsRemoved) - This estimates the number of items that we *should* have (but doesn't take into account item targets being GC'd)
- private int _lastItemIndex; // Location of the last item in _items
- private volatile bool _isNotifying; // Indicates that the collection is currently being notified (and, therefore, about to be cleared)
-
- protected DbReferenceCollection()
- {
- _items = new CollectionEntry[DefaultCollectionSize];
- _itemLock = new object();
- _optimisticCount = 0;
- _lastItemIndex = 0;
- }
-
- public abstract void Add(object value, int tag);
-
- protected void AddItem(object value, int tag)
- {
- Debug.Assert(null != value && 0 != tag, "AddItem with null value or 0 tag");
- bool itemAdded = false;
-
- lock (_itemLock)
- {
- // Try to find a free spot
- for (int i = 0; i <= _lastItemIndex; ++i)
- {
- if (_items[i].Tag == 0)
- {
- _items[i].NewTarget(tag, value);
- Debug.Assert(_items[i].HasTarget, "missing expected target");
- itemAdded = true;
- break;
- }
- }
-
- // No free spots, can we just add on to the end?
- if ((!itemAdded) && (_lastItemIndex + 1 < _items.Length))
- {
- _lastItemIndex++;
- _items[_lastItemIndex].NewTarget(tag, value);
- itemAdded = true;
- }
-
- // If no free spots and no space at the end, try to find a dead item
- if (!itemAdded)
- {
- for (int i = 0; i <= _lastItemIndex; ++i)
- {
- if (!_items[i].HasTarget)
- {
- _items[i].NewTarget(tag, value);
- Debug.Assert(_items[i].HasTarget, "missing expected target");
- itemAdded = true;
- break;
- }
- }
- }
-
- // If nothing was free, then resize and add to the end
- if (!itemAdded)
- {
- Array.Resize<CollectionEntry>(ref _items, _items.Length * 2);
- _lastItemIndex++;
- _items[_lastItemIndex].NewTarget(tag, value);
- }
-
- _optimisticCount++;
- }
- }
-
- internal T FindItem<T>(int tag, Func<T, bool> filterMethod) where T : class
- {
- bool lockObtained = false;
- try
- {
- TryEnterItemLock(ref lockObtained);
- if (lockObtained)
- {
- if (_optimisticCount > 0)
- {
- // Loop through the items
- for (int counter = 0; counter <= _lastItemIndex; counter++)
- {
- // Check tag (should be easiest and quickest)
- if (_items[counter].Tag == tag)
- {
- // NOTE: Check if the returned value is null twice may seem wasteful, but this if for performance
- // Since checking for null twice is cheaper than calling both HasTarget and Target OR always attempting to typecast
- object value = _items[counter].Target;
- if (value != null)
- {
- // Make sure the item has the correct type and passes the filtering
- T tempItem = value as T;
- if ((tempItem != null) && (filterMethod(tempItem)))
- {
- return tempItem;
- }
- }
- }
- }
- }
- }
- }
- finally
- {
- ExitItemLockIfNeeded(lockObtained);
- }
-
- // If we got to here, then no item was found, so return null
- return null;
- }
-
- public void Notify(int message)
- {
- bool lockObtained = false;
- try
- {
- TryEnterItemLock(ref lockObtained);
- if (lockObtained)
- {
- try
- {
- _isNotifying = true;
-
- // Loop through each live item and notify it
- if (_optimisticCount > 0)
- {
- for (int index = 0; index <= _lastItemIndex; ++index)
- {
- object value = _items[index].Target; // checks tag & gets target
- if (null != value)
- {
- NotifyItem(message, _items[index].Tag, value);
- _items[index].RemoveTarget();
- }
- Debug.Assert(!_items[index].HasTarget, "Unexpected target after notifying");
- }
- _optimisticCount = 0;
- }
-
- // Shrink collection (if needed)
- if (_items.Length > 100)
- {
- _lastItemIndex = 0;
- _items = new CollectionEntry[DefaultCollectionSize];
- }
- }
- finally
- {
- _isNotifying = false;
- }
- }
- }
- finally
- {
- ExitItemLockIfNeeded(lockObtained);
- }
- }
-
- protected abstract void NotifyItem(int message, int tag, object value);
-
- public abstract void Remove(object value);
-
- protected void RemoveItem(object value)
- {
- Debug.Assert(null != value, "RemoveItem with null");
-
- bool lockObtained = false;
- try
- {
- TryEnterItemLock(ref lockObtained);
-
- if (lockObtained)
- {
- // Find the value, and then remove the target from our collection
- if (_optimisticCount > 0)
- {
- for (int index = 0; index <= _lastItemIndex; ++index)
- {
- if (value == _items[index].Target)
- { // checks tag & gets target
- _items[index].RemoveTarget();
- _optimisticCount--;
- break;
- }
- }
- }
- }
- }
- finally
- {
- ExitItemLockIfNeeded(lockObtained);
- }
- }
-
- // This is polling lock that will abandon getting the lock if _isNotifying is set to true
- private void TryEnterItemLock(ref bool lockObtained)
- {
- // Assume that we couldn't take the lock
- lockObtained = false;
- // Keep trying to take the lock until either we've taken it, or the collection is being notified
- while ((!_isNotifying) && (!lockObtained))
- {
- Monitor.TryEnter(_itemLock, LockPollTime, ref lockObtained);
- }
- }
-
- private void ExitItemLockIfNeeded(bool lockObtained)
- {
- if (lockObtained)
- {
- Monitor.Exit(_itemLock);
- }
- }
- }
-}
-
diff --git a/src/System.Data.Odbc/src/MatchingRefApiCompatBaseline.txt b/src/System.Data.Odbc/src/MatchingRefApiCompatBaseline.txt
new file mode 100644
index 0000000000..871e84a2eb
--- /dev/null
+++ b/src/System.Data.Odbc/src/MatchingRefApiCompatBaseline.txt
@@ -0,0 +1,6 @@
+# Exposed publicly only in implementation for serialization compat
+TypesMustExist : Type 'System.Data.Odbc.ODBC32' does not exist in the implementation but it does exist in the contract.
+
+# Cannot be exposed in the ref yet as it is new API that doesn't exist in netfx
+MembersMustExist : Member 'System.Data.Odbc.OdbcParameter.Offset.get()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Data.Odbc.OdbcParameter.Offset.set(System.Int32)' does not exist in the implementation but it does exist in the contract.
diff --git a/src/System.Data.Odbc/src/Resources/System.Data.Odbc.OdbcMetaData.xml b/src/System.Data.Odbc/src/Resources/System.Data.Odbc.OdbcMetaData.xml
new file mode 100644
index 0000000000..122abae606
--- /dev/null
+++ b/src/System.Data.Odbc/src/Resources/System.Data.Odbc.OdbcMetaData.xml
@@ -0,0 +1,1013 @@
+<?xml version="1.0" standalone="yes"?>
+<!-- edited with XMLSPY v5 rel. 4 U (http://www.xmlspy.com) by Carl Perry (Microsoft) -->
+<NewDataSet>
+ <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xs:element name="NewDataSet" msdata:IsDataSet="true">
+ <xs:complexType>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="MetaDataCollections" msdata:MinimumCapacity="9">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="CollectionName" type="xs:string" minOccurs="0"/>
+ <xs:element name="NumberOfRestrictions" type="xs:int" minOccurs="0"/>
+ <xs:element name="NumberOfIdentifierParts" type="xs:int" minOccurs="0"/>
+ <xs:element name="PopulationMechanism" type="xs:string" minOccurs="0"/>
+ <xs:element name="PopulationString" type="xs:string" minOccurs="0"/>
+ <xs:element name="MinimumVersion" type="xs:string" minOccurs="0"/>
+ <xs:element name="MaximumVersion" type="xs:string" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="Restrictions" msdata:MinimumCapacity="3">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="CollectionName" type="xs:string" minOccurs="0"/>
+ <xs:element name="RestrictionName" type="xs:string" minOccurs="0"/>
+ <xs:element name="RestrictionDefault" type="xs:string" minOccurs="0"/>
+ <xs:element name="RestrictionNumber" type="xs:int" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="DataSourceInformation" msdata:MinimumCapacity="17">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="CompositeIdentifierSeparatorPattern" type="xs:string" minOccurs="0"/>
+ <xs:element name="DataSourceProductName" type="xs:string" minOccurs="0"/>
+ <xs:element name="DataSourceProductVersion" type="xs:string" minOccurs="0"/>
+ <xs:element name="DataSourceProductVersionNormalized" type="xs:string" minOccurs="0"/>
+ <xs:element name="GroupByBehavior" msdata:DataType="System.Data.Common.GroupByBehavior, System.Data, Version=1.2.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" type="xs:string" minOccurs="0"/>
+ <xs:element name="IdentifierPattern" type="xs:string" minOccurs="0"/>
+ <xs:element name="IdentifierCase" msdata:DataType="System.Data.Common.IdentifierCase, System.Data, Version=1.2.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" type="xs:string" minOccurs="0"/>
+ <xs:element name="OrderByColumnsInSelect" type="xs:boolean" minOccurs="0"/>
+ <xs:element name="ParameterMarkerFormat" type="xs:string" minOccurs="0"/>
+ <xs:element name="ParameterMarkerPattern" type="xs:string" minOccurs="0"/>
+ <xs:element name="ParameterNameMaxLength" type="xs:int" minOccurs="0"/>
+ <xs:element name="ParameterNamePattern" type="xs:string" minOccurs="0"/>
+ <xs:element name="QuotedIdentifierPattern" type="xs:string" minOccurs="0"/>
+ <xs:element name="QuotedIdentifierCase" msdata:DataType="System.Data.Common.IdentifierCase, System.Data, Version=1.2.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" type="xs:string" minOccurs="0"/>
+ <xs:element name="StatementSeparatorPattern" type="xs:string" minOccurs="0"/>
+ <xs:element name="StringLiteralPattern" type="xs:string" minOccurs="0"/>
+ <xs:element name="SupportedJoinOperators" msdata:DataType="System.Data.Common.SupportedJoinOperators, System.Data, Version=1.2.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" type="xs:string" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="ReservedWords" msdata:MinimumCapacity="3">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="ReservedWord" type="xs:string" minOccurs="0"/>
+ <xs:element name="MaximumVersion" type="xs:string" minOccurs="0"/>
+ <xs:element name="MinimumVersion" type="xs:string" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ <xs:element name="DataTypes" msdata:MinimumCapacity="18">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="TypeName" type="xs:string" minOccurs="0"/>
+ <xs:element name="ProviderDbType" type="xs:int" minOccurs="0"/>
+ <xs:element name="ColumnSize" type="xs:long" minOccurs="0"/>
+ <xs:element name="CreateFormat" type="xs:string" minOccurs="0"/>
+ <xs:element name="CreateParameters" type="xs:string" minOccurs="0"/>
+ <xs:element name="DataType" type="xs:string" minOccurs="0"/>
+ <xs:element name="IsAutoIncrementable" type="xs:boolean" minOccurs="0"/>
+ <xs:element name="IsBestMatch" type="xs:boolean" minOccurs="0"/>
+ <xs:element name="IsCaseSensitive" type="xs:boolean" minOccurs="0"/>
+ <xs:element name="IsFixedLength" type="xs:boolean" minOccurs="0"/>
+ <xs:element name="IsFixedPrecisionScale" type="xs:boolean" minOccurs="0"/>
+ <xs:element name="IsLong" type="xs:boolean" minOccurs="0"/>
+ <xs:element name="IsNullable" type="xs:boolean" minOccurs="0"/>
+ <xs:element name="IsSearchable" type="xs:boolean" minOccurs="0"/>
+ <xs:element name="IsSearchableWithLike" type="xs:boolean" minOccurs="0"/>
+ <xs:element name="IsUnsigned" type="xs:boolean" minOccurs="0"/>
+ <xs:element name="MaximumScale" type="xs:short" minOccurs="0"/>
+ <xs:element name="MinimumScale" type="xs:short" minOccurs="0"/>
+ <xs:element name="IsConcurrencyType" type="xs:boolean" minOccurs="0" />
+ <xs:element name="MaximumVersion" type="xs:string" minOccurs="0"/>
+ <xs:element name="MinimumVersion" type="xs:string" minOccurs="0"/>
+ <xs:element name="IsLiteralSupported" type="xs:boolean" minOccurs="0"/>
+ <xs:element name="LiteralPrefix" type="xs:string" minOccurs="0"/>
+ <xs:element name="LiteralSuffix" type="xs:string" minOccurs="0"/>
+ <xs:element name="SQLType" type="xs:short" minOccurs="0" />
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:choice>
+ </xs:complexType>
+ </xs:element>
+ </xs:schema>
+ <MetaDataCollections>
+ <CollectionName>MetaDataCollections</CollectionName>
+ <NumberOfRestrictions>0</NumberOfRestrictions>
+ <NumberOfIdentifierParts>0</NumberOfIdentifierParts>
+ <PopulationMechanism>DataTable</PopulationMechanism>
+ <PopulationString>MetaDataCollections</PopulationString>
+ </MetaDataCollections>
+ <MetaDataCollections>
+ <CollectionName>DataSourceInformation</CollectionName>
+ <NumberOfRestrictions>0</NumberOfRestrictions>
+ <NumberOfIdentifierParts>0</NumberOfIdentifierParts>
+ <PopulationMechanism>PrepareCollection</PopulationMechanism>
+ <PopulationString>DataSourceInformation</PopulationString>
+ </MetaDataCollections>
+ <MetaDataCollections>
+ <CollectionName>DataTypes</CollectionName>
+ <NumberOfRestrictions>0</NumberOfRestrictions>
+ <NumberOfIdentifierParts>0</NumberOfIdentifierParts>
+ <PopulationMechanism>PrepareCollection</PopulationMechanism>
+ <PopulationString>DataTypes</PopulationString>
+ </MetaDataCollections>
+ <MetaDataCollections>
+ <CollectionName>Restrictions</CollectionName>
+ <NumberOfRestrictions>0</NumberOfRestrictions>
+ <NumberOfIdentifierParts>0</NumberOfIdentifierParts>
+ <PopulationMechanism>DataTable</PopulationMechanism>
+ <PopulationString>Restrictions</PopulationString>
+ </MetaDataCollections>
+ <MetaDataCollections>
+ <CollectionName>ReservedWords</CollectionName>
+ <NumberOfRestrictions>0</NumberOfRestrictions>
+ <NumberOfIdentifierParts>0</NumberOfIdentifierParts>
+ <PopulationMechanism>PrepareCollection</PopulationMechanism>
+ <PopulationString>ReservedWords</PopulationString>
+ </MetaDataCollections>
+ <MetaDataCollections>
+ <CollectionName>Columns</CollectionName>
+ <NumberOfRestrictions>4</NumberOfRestrictions>
+ <NumberOfIdentifierParts>4</NumberOfIdentifierParts>
+ <PopulationMechanism>PrepareCollection</PopulationMechanism>
+ </MetaDataCollections>
+ <MetaDataCollections>
+ <CollectionName>Indexes</CollectionName>
+ <NumberOfRestrictions>4</NumberOfRestrictions>
+ <NumberOfIdentifierParts>4</NumberOfIdentifierParts>
+ <PopulationMechanism>PrepareCollection</PopulationMechanism>
+ </MetaDataCollections>
+ <MetaDataCollections>
+ <CollectionName>Procedures</CollectionName>
+ <NumberOfRestrictions>4</NumberOfRestrictions>
+ <NumberOfIdentifierParts>3</NumberOfIdentifierParts>
+ <PopulationMechanism>PrepareCollection</PopulationMechanism>
+ </MetaDataCollections>
+ <MetaDataCollections>
+ <CollectionName>ProcedureColumns</CollectionName>
+ <NumberOfRestrictions>4</NumberOfRestrictions>
+ <NumberOfIdentifierParts>4</NumberOfIdentifierParts>
+ <PopulationMechanism>PrepareCollection</PopulationMechanism>
+ </MetaDataCollections>
+ <MetaDataCollections>
+ <CollectionName>ProcedureParameters</CollectionName>
+ <NumberOfRestrictions>4</NumberOfRestrictions>
+ <NumberOfIdentifierParts>4</NumberOfIdentifierParts>
+ <PopulationMechanism>PrepareCollection</PopulationMechanism>
+ </MetaDataCollections>
+ <MetaDataCollections>
+ <CollectionName>Tables</CollectionName>
+ <NumberOfRestrictions>3</NumberOfRestrictions>
+ <NumberOfIdentifierParts>3</NumberOfIdentifierParts>
+ <PopulationMechanism>PrepareCollection</PopulationMechanism>
+ </MetaDataCollections>
+ <MetaDataCollections>
+ <CollectionName>Views</CollectionName>
+ <NumberOfRestrictions>3</NumberOfRestrictions>
+ <NumberOfIdentifierParts>3</NumberOfIdentifierParts>
+ <PopulationMechanism>PrepareCollection</PopulationMechanism>
+ </MetaDataCollections>
+ <Restrictions>
+ <CollectionName>Columns</CollectionName>
+ <RestrictionName>TABLE_CAT</RestrictionName>
+ <RestrictionNumber>1</RestrictionNumber>
+ </Restrictions>
+ <Restrictions>
+ <CollectionName>Columns</CollectionName>
+ <RestrictionName>TABLE_SCHEM</RestrictionName>
+ <RestrictionNumber>2</RestrictionNumber>
+ </Restrictions>
+ <Restrictions>
+ <CollectionName>Columns</CollectionName>
+ <RestrictionName>TABLE_NAME</RestrictionName>
+ <RestrictionNumber>3</RestrictionNumber>
+ </Restrictions>
+ <Restrictions>
+ <CollectionName>Columns</CollectionName>
+ <RestrictionName>COLUMN_NAME</RestrictionName>
+ <RestrictionNumber>4</RestrictionNumber>
+ </Restrictions>
+ <Restrictions>
+ <CollectionName>Indexes</CollectionName>
+ <RestrictionName>TABLE_CAT</RestrictionName>
+ <RestrictionNumber>1</RestrictionNumber>
+ </Restrictions>
+ <Restrictions>
+ <CollectionName>Indexes</CollectionName>
+ <RestrictionName>TABLE_SCHEM</RestrictionName>
+ <RestrictionNumber>2</RestrictionNumber>
+ </Restrictions>
+ <Restrictions>
+ <CollectionName>Indexes</CollectionName>
+ <RestrictionName>TABLE_NAME</RestrictionName>
+ <RestrictionNumber>3</RestrictionNumber>
+ </Restrictions>
+ <Restrictions>
+ <CollectionName>Indexes</CollectionName>
+ <RestrictionName>INDEX_NAME</RestrictionName>
+ <RestrictionNumber>4</RestrictionNumber>
+ </Restrictions>
+ <Restrictions>
+ <CollectionName>Procedures</CollectionName>
+ <RestrictionName>PROCEDURE_CAT</RestrictionName>
+ <RestrictionNumber>1</RestrictionNumber>
+ </Restrictions>
+ <Restrictions>
+ <CollectionName>Procedures</CollectionName>
+ <RestrictionName>PROCEDURE_SCHEM</RestrictionName>
+ <RestrictionNumber>2</RestrictionNumber>
+ </Restrictions>
+ <Restrictions>
+ <CollectionName>Procedures</CollectionName>
+ <RestrictionName>PROCEDURE_NAME</RestrictionName>
+ <RestrictionNumber>3</RestrictionNumber>
+ </Restrictions>
+ <Restrictions>
+ <CollectionName>Procedures</CollectionName>
+ <RestrictionName>PROCEDURE_TYPE</RestrictionName>
+ <RestrictionNumber>4</RestrictionNumber>
+ </Restrictions>
+ <Restrictions>
+ <CollectionName>ProcedureColumns</CollectionName>
+ <RestrictionName>PROCEDURE_CAT</RestrictionName>
+ <RestrictionNumber>1</RestrictionNumber>
+ </Restrictions>
+ <Restrictions>
+ <CollectionName>ProcedureColumns</CollectionName>
+ <RestrictionName>PROCEDURE_SCHE</RestrictionName>
+ <RestrictionNumber>2</RestrictionNumber>
+ </Restrictions>
+ <Restrictions>
+ <CollectionName>ProcedureColumns</CollectionName>
+ <RestrictionName>PROCEDURE_NAME</RestrictionName>
+ <RestrictionNumber>3</RestrictionNumber>
+ </Restrictions>
+ <Restrictions>
+ <CollectionName>ProcedureColumns</CollectionName>
+ <RestrictionName>COLUMN_NAME</RestrictionName>
+ <RestrictionNumber>4</RestrictionNumber>
+ </Restrictions>
+ <Restrictions>
+ <CollectionName>ProcedureParameters</CollectionName>
+ <RestrictionName>PROCEDURE_CAT</RestrictionName>
+ <RestrictionNumber>1</RestrictionNumber>
+ </Restrictions>
+ <Restrictions>
+ <CollectionName>ProcedureParameters</CollectionName>
+ <RestrictionName>PROCEDURE_SCHEM</RestrictionName>
+ <RestrictionNumber>2</RestrictionNumber>
+ </Restrictions>
+ <Restrictions>
+ <CollectionName>ProcedureParameters</CollectionName>
+ <RestrictionName>PROCEDURE_NAME</RestrictionName>
+ <RestrictionNumber>3</RestrictionNumber>
+ </Restrictions>
+ <Restrictions>
+ <CollectionName>ProcedureParameters</CollectionName>
+ <RestrictionName>COLUMN_NAME</RestrictionName>
+ <RestrictionNumber>4</RestrictionNumber>
+ </Restrictions>
+ <Restrictions>
+ <CollectionName>Tables</CollectionName>
+ <RestrictionName>TABLE_CAT</RestrictionName>
+ <RestrictionNumber>1</RestrictionNumber>
+ </Restrictions>
+ <Restrictions>
+ <CollectionName>Tables</CollectionName>
+ <RestrictionName>TABLE_SCHEM</RestrictionName>
+ <RestrictionNumber>2</RestrictionNumber>
+ </Restrictions>
+ <Restrictions>
+ <CollectionName>Tables</CollectionName>
+ <RestrictionName>TABLE_NAME</RestrictionName>
+ <RestrictionNumber>3</RestrictionNumber>
+ </Restrictions>
+ <Restrictions>
+ <CollectionName>Views</CollectionName>
+ <RestrictionName>TABLE_CAT</RestrictionName>
+ <RestrictionNumber>1</RestrictionNumber>
+ </Restrictions>
+ <Restrictions>
+ <CollectionName>Views</CollectionName>
+ <RestrictionName>TABLE_SCHEM</RestrictionName>
+ <RestrictionNumber>2</RestrictionNumber>
+ </Restrictions>
+ <Restrictions>
+ <CollectionName>Views</CollectionName>
+ <RestrictionName>TABLE_NAME</RestrictionName>
+ <RestrictionNumber>3</RestrictionNumber>
+ </Restrictions>
+ <DataSourceInformation>
+ </DataSourceInformation>
+
+ <ReservedWords>
+ <ReservedWord>ABSOLUTE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>ACTION</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>ADA</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>ADD</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>ALL</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>ALLOCATE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>ALTER</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>AND</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>ANY</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>ARE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>AS</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>ASC</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>ASSERTION</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>AT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>AUTHORIZATION</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>AVG</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>BEGIN</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>BETWEEN</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>BIT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>BIT_LENGTH</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>BOTH</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>BY</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>CASCADE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>CASCADED</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>CASE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>CAST</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>CATALOG</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>CHAR</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>CHAR_LENGTH</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>CHARACTER</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>CHARACTER_LENGTH</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>CHECK</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>CLOSE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>COALESCE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>COLLATE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>COLLATION</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>COLUMN</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>COMMIT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>CONNECT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>CONNECTION</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>CONSTRAINT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>CONSTRAINTS</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>CONTINUE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>CONVERT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>CORRESPONDING</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>COUNT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>CREATE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>CROSS</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>CURRENT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>CURRENT_DATE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>CURRENT_TIME</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>CURRENT_TIMESTAMP</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>CURRENT_USER</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>CURSOR</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>DATE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>DAY</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>DEALLOCATE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>DEC</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>DECIMAL</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>DECLARE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>DEFAULT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>DEFERRABLE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>DEFERRED</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>DELETE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>DESC</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>DESCRIBE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>DESCRIPTOR</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>DIAGNOSTICS</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>DISCONNECT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>DISTINCT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>DOMAIN</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>DOUBLE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>DROP</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>ELSE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>END</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>END-EXEC</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>ESCAPE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>EXCEPT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>EXCEPTION</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>EXEC</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>EXECUTE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>EXISTS</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>EXTERNAL</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>EXTRACT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>FALSE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>FETCH</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>FIRST</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>FLOAT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>FOR</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>FOREIGN</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>FORTRAN</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>FOUND</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>FROM</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>FULL</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>GET</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>GLOBAL</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>GO</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>GOTO</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>GRANT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>GROUP</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>HAVING</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>HOUR</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>IDENTITY</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>IMMEDIATE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>IN</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>INCLUDE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>INDEX</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>INDICATOR</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>INITIALLY</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>INNER</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>INPUT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>INSENSITIVE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>INSERT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>INT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>INTEGER</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>INTERSECT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>INTERVAL</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>INTO</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>IS</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>ISOLATION</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>JOIN</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>KEY</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>LANGUAGE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>LAST</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>LEADING</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>LEFT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>LEVEL</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>LIKE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>LOCAL</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>LOWER</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>MATCH</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>MAX</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>MIN</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>MINUTE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>MODULE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>MONTH</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>NAMES</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>NATIONAL</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>NATURAL</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>NCHAR</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>NEXT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>NO</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>NONE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>NOT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>NULL</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>NULLIF</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>NUMERIC</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>OCTET_LENGTH</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>OF</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>ON</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>ONLY</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>OPEN</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>OPTION</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>OR</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>ORDER</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>OUTER</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>OUTPUT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>OVERLAPS</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>PAD</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>PARTIAL</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>PASCAL</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>POSITION</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>PRECISION</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>PREPARE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>PRESERVE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>PRIMARY</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>PRIOR</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>PRIVILEGES</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>PROCEDURE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>PUBLIC</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>READ</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>REAL</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>REFERENCES</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>RELATIVE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>RESTRICT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>REVOKE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>RIGHT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>ROLLBACK</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>ROWS</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>SCHEMA</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>SCROLL</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>SECOND</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>SECTION</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>SELECT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>SESSION</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>SESSION_USER</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>SET</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>SIZE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>SMALLINT</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>SOME</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>SPACE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>SQL</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>SQLCA</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>SQLCODE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>SQLERROR</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>SQLSTATE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>SQLWARNING</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>SUBSTRING</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>SUM</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>SYSTEM_USER</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>TABLE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>TEMPORARY</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>THEN</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>TIME</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>TIMESTAMP</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>TIMEZONE_HOUR</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>TIMEZONE_MINUTE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>TO</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>TRAILING</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>TRANSACTION</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>TRANSLATE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>TRANSLATION</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>TRIM</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>TRUE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>UNION</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>UNIQUE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>UNKNOWN</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>UPDATE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>UPPER</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>USAGE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>USER</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>USING</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>VALUE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>VALUES</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>VARCHAR</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>VARYING</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>VIEW</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>WHEN</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>WHENEVER</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>WHERE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>WITH</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>WORK</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>WRITE</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>YEAR</ReservedWord>
+ </ReservedWords>
+ <ReservedWords>
+ <ReservedWord>ZONE</ReservedWord>
+ </ReservedWords>
+</NewDataSet>
diff --git a/src/System.Data.Odbc/src/System.Data.Odbc.csproj b/src/System.Data.Odbc/src/System.Data.Odbc.csproj
index 9f9a3db2aa..2a3f098d98 100644
--- a/src/System.Data.Odbc/src/System.Data.Odbc.csproj
+++ b/src/System.Data.Odbc/src/System.Data.Odbc.csproj
@@ -32,6 +32,9 @@
<Compile Include="$(CommonPath)\System\Data\Common\AdapterUtil.cs">
<Link>Common\System\Data\Common\AdapterUtil.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Data\Common\AdapterUtil.Drivers.cs">
+ <Link>System\Data\Common\AdapterUtil.Drivers.cs</Link>
+ </Compile>
<Compile Include="Common\System\Data\Common\AdapterUtil.Odbc.cs" />
<Compile Include="Common\System\Data\Common\DbConnectionOptions.cs" />
<Compile Include="$(CommonPath)\System\Data\Common\DbConnectionOptions.Common.cs">
@@ -49,24 +52,41 @@
<Compile Include="Common\System\Data\Common\SafeNativeMethods.cs" />
<Compile Include="Common\System\Data\DataStorage.cs" />
<Compile Include="Common\System\Data\ProviderBase\DbBuffer.cs" />
- <Compile Include="Common\System\Data\ProviderBase\DbMetaDataFactory.cs" />
- <Compile Include="Common\System\Data\ProviderBase\TimeoutTimer.cs" />
<Compile Include="$(CommonPath)\System\Data\Common\FieldNameLookup.cs">
<Link>Common\System\Data\ProviderBase\FieldNameLookup.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Data\Common\BasicFieldNameLookup.cs">
<Link>Common\System\Data\ProviderBase\BasicFieldNameLookup.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Data\ProviderBase\DbConnectionInternal.cs">
+ <Link>System\Data\ProviderBase\DbConnectionInternal.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Data\ProviderBase\DbConnectionFactory.cs">
+ <Link>System\Data\ProviderBase\DbConnectionFactory.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Data\ProviderBase\DbConnectionPoolGroup.cs">
+ <Link>System\Data\ProviderBase\DbConnectionPoolGroup.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Data\ProviderBase\TimeoutTimer.cs">
+ <Link>System\Data\ProviderBase\TimeoutTimer.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Data\ProviderBase\DbReferenceCollection.cs">
+ <Link>System\Data\ProviderBase\DbReferenceCollection.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Data\ProviderBase\DbMetaDataFactory.cs">
+ <Link>System\Data\ProviderBase\DbMetaDataFactory.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Data\ProviderBase\DbConnectionClosed.cs">
+ <Link>System\Data\ProviderBase\DbConnectionClosed.cs</Link>
+ </Compile>
<Compile Include="Common\System\Data\ProviderBase\DbConnectionClosed.cs" />
<Compile Include="Common\System\Data\ProviderBase\DbConnectionFactory.cs" />
<Compile Include="Common\System\Data\ProviderBase\DbConnectionInternal.cs" />
<Compile Include="Common\System\Data\ProviderBase\DbConnectionPool.cs" />
- <Compile Include="Common\System\Data\ProviderBase\DbConnectionPoolGroup.cs" />
<Compile Include="Common\System\Data\ProviderBase\DbConnectionPoolGroupProviderInfo.cs" />
<Compile Include="Common\System\Data\ProviderBase\DbConnectionPoolIdentity.cs" />
<Compile Include="Common\System\Data\ProviderBase\DbConnectionPoolOptions.cs" />
<Compile Include="Common\System\Data\ProviderBase\DbConnectionPoolProviderInfo.cs" />
- <Compile Include="Common\System\Data\ProviderBase\DbReferenceCollection.cs" />
<Compile Include="System\Data\Odbc\DbDataRecord.cs" />
<Compile Include="System\Data\Odbc\Odbc32.cs" />
<Compile Include="System\Data\Odbc\OdbcCommand.cs">
@@ -180,6 +200,11 @@
<Reference Include="System.Transactions.Local" />
</ItemGroup>
<ItemGroup>
+ <EmbeddedResource Include="Resources\System.Data.Odbc.OdbcMetaData.xml">
+ <LogicalName>System.Data.Odbc.OdbcMetaData.xml</LogicalName>
+ </EmbeddedResource>
+ </ItemGroup>
+ <ItemGroup>
<None Include="DatabaseSetupInstructions.md" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
diff --git a/src/System.Data.Odbc/src/System/Data/Odbc/OdbcConnectionFactory.cs b/src/System.Data.Odbc/src/System/Data/Odbc/OdbcConnectionFactory.cs
index 9d910e748d..1287c54033 100644
--- a/src/System.Data.Odbc/src/System/Data/Odbc/OdbcConnectionFactory.cs
+++ b/src/System.Data.Odbc/src/System/Data/Odbc/OdbcConnectionFactory.cs
@@ -2,9 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Collections.Specialized;
using System.Data.Common;
using System.Data.ProviderBase;
using System.Diagnostics;
+using System.IO;
namespace System.Data.Odbc
{
@@ -50,6 +52,36 @@ namespace System.Data.Odbc
return new OdbcConnectionPoolGroupProviderInfo();
}
+ protected override DbMetaDataFactory CreateMetaDataFactory(DbConnectionInternal internalConnection, out bool cacheMetaDataFactory)
+ {
+ Debug.Assert(internalConnection != null, "internalConnection may not be null.");
+ cacheMetaDataFactory = false;
+
+ OdbcConnection odbcOuterConnection = ((OdbcConnectionOpen)internalConnection).OuterConnection;
+ Debug.Assert(odbcOuterConnection != null, "outer connection may not be null.");
+
+ // get the DBMS Name
+ object driverName = null;
+ string stringValue = odbcOuterConnection.GetInfoStringUnhandled(ODBC32.SQL_INFO.DRIVER_NAME);
+ if (stringValue != null)
+ {
+ driverName = stringValue;
+ }
+
+ Stream XMLStream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("System.Data.Odbc.OdbcMetaData.xml");
+ cacheMetaDataFactory = true;
+
+
+ Debug.Assert(XMLStream != null, "XMLstream may not be null.");
+
+ String versionString = odbcOuterConnection.GetInfoStringUnhandled(ODBC32.SQL_INFO.DBMS_VER);
+
+ return new OdbcMetaDataFactory(XMLStream,
+ versionString,
+ versionString,
+ odbcOuterConnection);
+ }
+
internal override DbConnectionPoolGroup GetConnectionPoolGroup(DbConnection connection)
{
OdbcConnection c = (connection as OdbcConnection);
diff --git a/src/System.Data.Odbc/src/System/Data/Odbc/OdbcConnectionHelper.cs b/src/System.Data.Odbc/src/System/Data/Odbc/OdbcConnectionHelper.cs
index 481e9e4373..6927b92369 100644
--- a/src/System.Data.Odbc/src/System/Data/Odbc/OdbcConnectionHelper.cs
+++ b/src/System.Data.Odbc/src/System/Data/Odbc/OdbcConnectionHelper.cs
@@ -175,6 +175,22 @@ namespace System.Data.Odbc
partial void RepairInnerConnection();
+ override public DataTable GetSchema()
+ {
+ return this.GetSchema(DbMetaDataCollectionNames.MetaDataCollections, null);
+ }
+
+ override public DataTable GetSchema(string collectionName)
+ {
+ return this.GetSchema(collectionName, null);
+ }
+
+ override public DataTable GetSchema(string collectionName, string[] restrictionValues)
+ {
+ // NOTE: This is virtual because not all providers may choose to support
+ // returning schema data
+ return InnerConnection.GetSchema(ConnectionFactory, PoolGroup, this, collectionName, restrictionValues);
+ }
internal void NotifyWeakReference(int message)
{
diff --git a/src/System.Data.Odbc/tests/Helpers.cs b/src/System.Data.Odbc/tests/Helpers.cs
index 0ab71a1910..126b8657fc 100644
--- a/src/System.Data.Odbc/tests/Helpers.cs
+++ b/src/System.Data.Odbc/tests/Helpers.cs
@@ -2,12 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Threading.Tasks;
namespace System.Data.Odbc.Tests
{
diff --git a/src/System.Data.Odbc/tests/OdbcConnectionSchemaTests.cs b/src/System.Data.Odbc/tests/OdbcConnectionSchemaTests.cs
new file mode 100644
index 0000000000..caf10e3415
--- /dev/null
+++ b/src/System.Data.Odbc/tests/OdbcConnectionSchemaTests.cs
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.Data.Odbc.Tests
+{
+ public class OdbcConnectionSchemaTests
+ {
+ [CheckConnStrSetupFact]
+ public void TestConnectionSchemaOnOpenConnection()
+ {
+ string connectionString = DataTestUtility.OdbcConnStr;
+
+ using (OdbcConnection connection = new OdbcConnection(connectionString))
+ {
+ connection.GetSchema();
+ connection.Open();
+ DataTable schema = connection.GetSchema();
+ Assert.NotNull(schema);
+
+ DataTable tableSchema = connection.GetSchema("Tables");
+ Assert.NotNull(tableSchema);
+ }
+ }
+
+ [Fact]
+ public void TestConnectionSchemaOnNonOpenConnection()
+ {
+ using (OdbcConnection connection = new OdbcConnection(string.Empty))
+ {
+ Assert.Throws<InvalidOperationException>(() => connection.GetSchema());
+ }
+ }
+ }
+}
diff --git a/src/System.Data.Odbc/tests/System.Data.Odbc.Tests.csproj b/src/System.Data.Odbc/tests/System.Data.Odbc.Tests.csproj
index 287eec667c..361e88a376 100644
--- a/src/System.Data.Odbc/tests/System.Data.Odbc.Tests.csproj
+++ b/src/System.Data.Odbc/tests/System.Data.Odbc.Tests.csproj
@@ -16,6 +16,7 @@
<Compile Include="Helpers.cs" />
<Compile Include="IntegrationTestBase.cs" />
<Compile Include="CommandBuilderTests.cs" />
+ <Compile Include="OdbcConnectionSchemaTests.cs" />
<Compile Include="ReaderTests.cs" />
<Compile Include="SmokeTest.cs" />
<Compile Include="TestCommon\DataTestUtility.cs" />
@@ -50,4 +51,4 @@
<Compile Include="ConnectionStrings.Unix.cs" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project>
+</Project> \ No newline at end of file
diff --git a/src/System.Data.SqlClient/pkg/System.Data.SqlClient.pkgproj b/src/System.Data.SqlClient/pkg/System.Data.SqlClient.pkgproj
index f02abb8b86..d44c77ed26 100644
--- a/src/System.Data.SqlClient/pkg/System.Data.SqlClient.pkgproj
+++ b/src/System.Data.SqlClient/pkg/System.Data.SqlClient.pkgproj
@@ -6,9 +6,9 @@
<SupportedFramework>net461;netcoreapp2.0;$(UAPvNextTFM);$(AllXamarinFrameworks)</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\src\System.Data.SqlClient.csproj" />
- <InboxOnTargetFramework Include="$(UAPvNextTFM)" />
+ <InboxOnTargetFramework Include="uap10.0.16299" />
<File Include="$(PlaceHolderFile)">
- <TargetPath>runtimes/win/lib/$(UAPvNextTFM)</TargetPath>
+ <TargetPath>runtimes/win/lib/uap10.0.16299</TargetPath>
</File>
<HarvestIncludePaths Include="ref/net451;lib/net451;runtimes/win/lib/net451" />
<HarvestIncludePaths Include="ref/net46;lib/net46;runtimes/win/lib/net46" />
diff --git a/src/System.Data.SqlClient/ref/System.Data.SqlClient.cs b/src/System.Data.SqlClient/ref/System.Data.SqlClient.cs
index f84f25ce4f..ffe8d62b62 100644
--- a/src/System.Data.SqlClient/ref/System.Data.SqlClient.cs
+++ b/src/System.Data.SqlClient/ref/System.Data.SqlClient.cs
@@ -158,7 +158,11 @@ namespace Microsoft.SqlServer.Server
public SqlMetaData(string name, System.Data.SqlDbType dbType, long maxLength, long locale, System.Data.SqlTypes.SqlCompareOptions compareOptions, bool useServerDefault, bool isUniqueKey, System.Data.SqlClient.SortOrder columnSortOrder, int sortOrdinal) { }
public SqlMetaData(string name, System.Data.SqlDbType dbType, string database, string owningSchema, string objectName) { }
public SqlMetaData(string name, System.Data.SqlDbType dbType, string database, string owningSchema, string objectName, bool useServerDefault, bool isUniqueKey, System.Data.SqlClient.SortOrder columnSortOrder, int sortOrdinal) { }
+ public SqlMetaData(string name, System.Data.SqlDbType dbType, System.Type userDefinedType, string serverTypeName) { }
+ public SqlMetaData(string name, System.Data.SqlDbType dbType, System.Type userDefinedType, string serverTypeName, bool useServerDefault, bool isUniqueKey, System.Data.SqlClient.SortOrder columnSortOrder, int sortOrdinal) { }
+
public System.Data.SqlTypes.SqlCompareOptions CompareOptions { get { throw null; } }
+ public System.Data.DbType DbType { get { throw null; } }
public bool IsUniqueKey { get { throw null; } }
public long LocaleId { get { throw null; } }
public static long Max { get { throw null; } }
@@ -169,6 +173,7 @@ namespace Microsoft.SqlServer.Server
public System.Data.SqlClient.SortOrder SortOrder { get { throw null; } }
public int SortOrdinal { get { throw null; } }
public System.Data.SqlDbType SqlDbType { get { throw null; } }
+ public System.Type Type{ get { throw null; } }
public string TypeName { get { throw null; } }
public bool UseServerDefault { get { throw null; } }
public string XmlSchemaCollectionDatabase { get { throw null; } }
@@ -416,6 +421,9 @@ namespace System.Data.SqlClient
public System.Xml.XmlReader ExecuteXmlReader() { throw null; }
public System.Threading.Tasks.Task<System.Xml.XmlReader> ExecuteXmlReaderAsync() { throw null; }
public System.Threading.Tasks.Task<System.Xml.XmlReader> ExecuteXmlReaderAsync(System.Threading.CancellationToken cancellationToken) { throw null; }
+ public System.IAsyncResult BeginExecuteXmlReader() { throw null; }
+ public System.IAsyncResult BeginExecuteXmlReader(System.AsyncCallback callback, object stateObject) { throw null; }
+ public System.Xml.XmlReader EndExecuteXmlReader(System.IAsyncResult asyncResult) { throw null; }
public override void Prepare() { }
public System.Data.Sql.SqlNotificationRequest Notification { get { throw null; } set { } }
public void ResetCommandTimeout() { }
@@ -451,6 +459,7 @@ namespace System.Data.SqlClient
{
public SqlConnection() { }
public SqlConnection(string connectionString) { }
+ public SqlConnection(string connectionString, System.Data.SqlClient.SqlCredential credential) { }
public System.Guid ClientConnectionId { get { throw null; } }
object ICloneable.Clone() { throw null; }
public override string ConnectionString { get { throw null; } set { } }
@@ -463,6 +472,7 @@ namespace System.Data.SqlClient
public override System.Data.ConnectionState State { get { throw null; } }
public bool StatisticsEnabled { get { throw null; } set { } }
public string WorkstationId { get { throw null; } }
+ public System.Data.SqlClient.SqlCredential Credential { get { throw null; } set { } }
public event System.Data.SqlClient.SqlInfoMessageEventHandler InfoMessage { add { } remove { } }
protected override System.Data.Common.DbTransaction BeginDbTransaction(System.Data.IsolationLevel isolationLevel) { throw null; }
public new System.Data.SqlClient.SqlTransaction BeginTransaction() { throw null; }
@@ -475,10 +485,16 @@ namespace System.Data.SqlClient
public override void Close() { }
public new System.Data.SqlClient.SqlCommand CreateCommand() { throw null; }
protected override System.Data.Common.DbCommand CreateDbCommand() { throw null; }
+ public override System.Data.DataTable GetSchema() { throw null; }
+ public override System.Data.DataTable GetSchema(string collectionName) { throw null; }
+ public override System.Data.DataTable GetSchema(string collectionName, string[] restrictionValues) { throw null; }
public override void Open() { }
public override System.Threading.Tasks.Task OpenAsync(System.Threading.CancellationToken cancellationToken) { throw null; }
public void ResetStatistics() { }
public System.Collections.IDictionary RetrieveStatistics() { throw null; }
+ public static void ChangePassword(string connectionString, string newPassword) { throw null; }
+ public static void ChangePassword(string connectionString, System.Data.SqlClient.SqlCredential credential, System.Security.SecureString newPassword) { throw null; }
+
}
public sealed partial class SqlConnectionStringBuilder : System.Data.Common.DbConnectionStringBuilder
{
@@ -678,6 +694,7 @@ namespace System.Data.SqlClient
public virtual object GetSqlValue(int i) { throw null; }
public virtual int GetSqlValues(object[] values) { throw null; }
public virtual System.Data.SqlTypes.SqlXml GetSqlXml(int i) { throw null; }
+ public override System.Data.DataTable GetSchemaTable() { throw null; }
public override System.IO.Stream GetStream(int i) { throw null; }
public override string GetString(int i) { throw null; }
public override System.IO.TextReader GetTextReader(int i) { throw null; }
@@ -686,6 +703,7 @@ namespace System.Data.SqlClient
public override int GetValues(object[] values) { throw null; }
public virtual System.Xml.XmlReader GetXmlReader(int i) { throw null; }
public override bool IsDBNull(int i) { throw null; }
+ protected internal bool IsCommandBehavior(System.Data.CommandBehavior condition) { throw null; }
public override System.Threading.Tasks.Task<bool> IsDBNullAsync(int i, System.Threading.CancellationToken cancellationToken) { throw null; }
public override bool NextResult() { throw null; }
public override System.Threading.Tasks.Task<bool> NextResultAsync(System.Threading.CancellationToken cancellationToken) { throw null; }
@@ -779,6 +797,8 @@ namespace System.Data.SqlClient
{
internal SqlParameterCollection() { }
public override int Count { get { throw null; } }
+ public override bool IsFixedSize { get { throw null; } }
+ public override bool IsReadOnly { get { throw null; } }
public new System.Data.SqlClient.SqlParameter this[int index] { get { throw null; } set { } }
public new System.Data.SqlClient.SqlParameter this[string parameterName] { get { throw null; } set { } }
public override object SyncRoot { get { throw null; } }
@@ -830,6 +850,13 @@ namespace System.Data.SqlClient
public void Rollback(string transactionName) { }
public void Save(string savePointName) { }
}
+
+ public sealed class SqlCredential
+ {
+ public SqlCredential(string userId, System.Security.SecureString password) { }
+ public string UserId { get { throw null; } }
+ public System.Security.SecureString Password { get { throw null; } }
+ }
}
namespace System.Data
{
diff --git a/src/System.Data.SqlClient/src/MatchingRefApiCompatBaseline.txt b/src/System.Data.SqlClient/src/MatchingRefApiCompatBaseline.txt
new file mode 100644
index 0000000000..94d2d3a69f
--- /dev/null
+++ b/src/System.Data.SqlClient/src/MatchingRefApiCompatBaseline.txt
@@ -0,0 +1,5 @@
+Compat issues with assembly System.Data.SqlClient:
+MembersMustExist : Member 'Microsoft.SqlServer.Server.SqlMetaData..ctor(System.String, System.Data.SqlDbType, System.Type)' does not exist in the implementation but it does exist in the contract.
+CannotRemoveBaseTypeOrInterface : Type 'System.Data.SqlClient.SqlDataReader' does not implement interface 'System.Data.Common.IDbColumnSchemaGenerator' in the implementation but it does in the contract.
+MembersMustExist : Member 'System.Data.SqlClient.SqlDataReader.GetColumnSchema()' does not exist in the implementation but it does exist in the contract.
+Total Issues: 3
diff --git a/src/System.Data.SqlClient/src/Microsoft/SqlServer/Server/SqlDataRecord.cs b/src/System.Data.SqlClient/src/Microsoft/SqlServer/Server/SqlDataRecord.cs
index 241e7450f6..869033de29 100644
--- a/src/System.Data.SqlClient/src/Microsoft/SqlServer/Server/SqlDataRecord.cs
+++ b/src/System.Data.SqlClient/src/Microsoft/SqlServer/Server/SqlDataRecord.cs
@@ -729,7 +729,7 @@ namespace Microsoft.SqlServer.Server
}
}
- IDataReader System.Data.IDataRecord.GetData (int ordinal)
+ IDataReader System.Data.IDataRecord.GetData(int ordinal)
{
throw ADP.NotSupported();
}
diff --git a/src/System.Data.SqlClient/src/Resources/Strings.resx b/src/System.Data.SqlClient/src/Resources/Strings.resx
index cbac126e53..15c8125816 100644
--- a/src/System.Data.SqlClient/src/Resources/Strings.resx
+++ b/src/System.Data.SqlClient/src/Resources/Strings.resx
@@ -1,5 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
@@ -431,7 +490,7 @@
<value>Failed to generate SSPI context.</value>
</data>
<data name="SQL_KerberosTicketMissingError" xml:space="preserve">
- <value>Cannot access Kerberos ticket. Ensure Kerberos has been initialized with 'kinit'.</value>
+ <value>Cannot authenticate using Kerberos. Ensure Kerberos has been initialized on the client with 'kinit' and a Service Principal Name has been registered for the SQL Server to allow Kerberos authentication.</value>
</data>
<data name="SQL_SqlServerBrowserNotAccessible" xml:space="preserve">
<value>Cannot connect to SQL Server Browser. Ensure SQL Server Browser has been started.</value>
@@ -1091,7 +1150,7 @@
<value>TCP Provider</value>
</data>
<data name="SNI_PN8" xml:space="preserve">
- <value></value>
+ <value />
</data>
<data name="SNI_PN9" xml:space="preserve">
<value>SQL Network Interfaces</value>
@@ -1165,32 +1224,32 @@
<data name="SqlProvider_InvalidDataColumnMaxLength" xml:space="preserve">
<value>The size of column '{0}' is not supported. The size is {1}.</value>
</data>
- <data name="MDF_InvalidXmlInvalidValue" xml:space="preserve">
+ <data name="MDF_InvalidXmlInvalidValue" xml:space="preserve">
<value>The metadata XML is invalid. The {1} column of the {0} collection must contain a non-empty string.</value>
</data>
- <data name="MDF_CollectionNameISNotUnique" xml:space="preserve">
+ <data name="MDF_CollectionNameISNotUnique" xml:space="preserve">
<value>There are multiple collections named '{0}'.</value>
</data>
- <data name="MDF_InvalidXmlMissingColumn" xml:space="preserve">
+ <data name="MDF_InvalidXmlMissingColumn" xml:space="preserve">
<value>The metadata XML is invalid. The {0} collection must contain a {1} column and it must be a string column.</value>
</data>
- <data name="MDF_InvalidXml" xml:space="preserve">
+ <data name="MDF_InvalidXml" xml:space="preserve">
<value>The metadata XML is invalid.</value>
</data>
- <data name="MDF_NoColumns" xml:space="preserve">
+ <data name="MDF_NoColumns" xml:space="preserve">
<value>The schema table contains no columns.</value>
</data>
- <data name="MDF_QueryFailed" xml:space="preserve">
+ <data name="MDF_QueryFailed" xml:space="preserve">
<value>Unable to build the '{0}' collection because execution of the SQL query failed. See the inner exception for details.</value>
</data>
- <data name="MDF_TooManyRestrictions" xml:space="preserve">
+ <data name="MDF_TooManyRestrictions" xml:space="preserve">
<value>More restrictions were provided than the requested schema ('{0}') supports.</value>
</data>
- <data name="MDF_DataTableDoesNotExist" xml:space="preserve">
+ <data name="MDF_DataTableDoesNotExist" xml:space="preserve">
<value>The collection '{0}' is missing from the metadata XML.</value>
</data>
- <data name="MDF_UndefinedCollection" xml:space="preserve">
- <value>The requested collection ({0}) is not defined.</value>
+ <data name="MDF_UndefinedCollection" xml:space="preserve">
+ <value>The requested collection ({0}) is not defined.</value>
</data>
<data name="MDF_UnsupportedVersion" xml:space="preserve">
<value> requested collection ({0}) is not supported by this version of the provider.</value>
@@ -1213,4 +1272,28 @@
<data name="MDF_UnableToBuildCollection" xml:space="preserve">
<value>Unable to build schema collection '{0}';</value>
</data>
+ <data name="ADP_InvalidArgumentLength" xml:space="preserve">
+ <value>The length of argument '{0}' exceeds its limit of '{1}'.</value>
+ </data>
+ <data name="ADP_MustBeReadOnly" xml:space="preserve">
+ <value>{0} must be marked as read only.</value>
+ </data>
+ <data name="ADP_InvalidMixedUsageOfSecureAndClearCredential" xml:space="preserve">
+ <value>Cannot use Credential with UserID, UID, Password, or PWD connection string keywords.</value>
+ </data>
+ <data name="ADP_InvalidMixedUsageOfSecureCredentialAndIntegratedSecurity" xml:space="preserve">
+ <value>Cannot use Credential with Integrated Security connection string keyword.</value>
+ </data>
+ <data name="SQL_ChangePasswordArgumentMissing" xml:space="preserve">
+ <value>The '{0}' argument must not be null or empty.</value>
+ </data>
+ <data name="SQL_ChangePasswordConflictsWithSSPI" xml:space="preserve">
+ <value>ChangePassword can only be used with SQL authentication, not with integrated security.</value>
+ </data>
+ <data name="SQL_ChangePasswordRequiresYukon" xml:space="preserve">
+ <value>ChangePassword requires SQL Server 9.0 or later.</value>
+ </data>
+ <data name="SQL_ChangePasswordUseOfUnallowedKey" xml:space="preserve">
+ <value>The keyword '{0}' must not be specified in the connectionString argument to ChangePassword.</value>
+ </data>
</root> \ No newline at end of file
diff --git a/src/System.Data.SqlClient/src/System.Data.SqlClient.csproj b/src/System.Data.SqlClient/src/System.Data.SqlClient.csproj
index 86915fc824..7e2717d7ac 100644
--- a/src/System.Data.SqlClient/src/System.Data.SqlClient.csproj
+++ b/src/System.Data.SqlClient/src/System.Data.SqlClient.csproj
@@ -55,6 +55,9 @@
<Compile Include="$(CommonPath)\System\Data\Common\AdapterUtil.cs">
<Link>System\Data\Common\AdapterUtil.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Data\Common\AdapterUtil.Drivers.cs">
+ <Link>System\Data\Common\AdapterUtil.Drivers.cs</Link>
+ </Compile>
<Compile Include="System\Data\Common\AdapterUtil.SqlClient.cs" />
<Compile Include="System\Data\Common\SR.cs" />
<Compile Include="System\Data\Common\DbConnectionOptions.cs" />
@@ -77,18 +80,35 @@
<Compile Include="$(CommonPath)\System\Data\Common\NameValuePair.cs">
<Link>System\Data\Common\NameValuePair.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Data\ProviderBase\DbConnectionInternal.cs">
+ <Link>Common\System\Data\ProviderBase\DbConnectionInternal.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Data\ProviderBase\DbConnectionFactory.cs">
+ <Link>Common\System\Data\ProviderBase\DbConnectionFactory.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Data\ProviderBase\DbConnectionPoolGroup.cs">
+ <Link>Common\System\Data\ProviderBase\DbConnectionPoolGroup.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Data\ProviderBase\TimeoutTimer.cs">
+ <Link>Common\System\Data\ProviderBase\TimeoutTimer.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Data\ProviderBase\DbReferenceCollection.cs">
+ <Link>Common\System\Data\ProviderBase\DbReferenceCollection.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Data\ProviderBase\DbMetaDataFactory.cs">
+ <Link>Common\System\Data\ProviderBase\DbMetaDataFactory.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Data\ProviderBase\DbConnectionClosed.cs">
+ <Link>Common\System\Data\ProviderBase\DbConnectionClosed.cs</Link>
+ </Compile>
<Compile Include="System\Data\ProviderBase\DbConnectionClosed.cs" />
<Compile Include="System\Data\ProviderBase\DbConnectionFactory.cs" />
<Compile Include="System\Data\ProviderBase\DbConnectionInternal.cs" />
<Compile Include="System\Data\ProviderBase\DbConnectionPool.cs" />
- <Compile Include="System\Data\ProviderBase\DbConnectionPoolGroup.cs" />
<Compile Include="System\Data\ProviderBase\DbConnectionPoolGroupProviderInfo.cs" />
<Compile Include="System\Data\ProviderBase\DbConnectionPoolIdentity.cs" />
<Compile Include="System\Data\ProviderBase\DbConnectionPoolOptions.cs" />
<Compile Include="System\Data\ProviderBase\DbConnectionPoolProviderInfo.cs" />
- <Compile Include="System\Data\ProviderBase\DbMetaDataFactory.cs" />
- <Compile Include="System\Data\ProviderBase\DbReferenceCollection.cs" />
- <Compile Include="System\Data\ProviderBase\TimeoutTimer.cs" />
<Compile Include="System\Data\Sql\IBinarySerialize.cs" />
<Compile Include="System\Data\Sql\InvalidUdtException.cs" />
<Compile Include="System\Data\Sql\SqlFunctionAttribute.cs" />
@@ -198,6 +218,7 @@
<Compile Include="System\Data\SqlClient\SNI\SSRP.cs" />
<Compile Include="System\Data\SqlClient\TdsParserStateObjectManaged.cs" />
<Compile Include="Interop\SNINativeMethodWrapper.Common.cs" />
+ <Compile Include="System\Data\SqlClient\SqlCredential.cs" />
</ItemGroup>
<!-- Manage the SNI toggle for Windows netstandard and UWP -->
<ItemGroup Condition="'$(TargetGroup)' == 'netstandard' AND '$(TargetsWindows)' == 'true'">
@@ -420,6 +441,7 @@
</ItemGroup>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true' AND '$(OSGroup)' != 'AnyOS'">
<Reference Include="Microsoft.Win32.Primitives" />
+ <Reference Include="System.Buffers" />
<Reference Include="System.Collections" />
<Reference Include="System.Collections.Concurrent" />
<Reference Include="System.ComponentModel" />
diff --git a/src/System.Data.SqlClient/src/System/Data/Common/AdapterUtil.SqlClient.cs b/src/System.Data.SqlClient/src/System/Data/Common/AdapterUtil.SqlClient.cs
index 8b52cac677..103ba8caec 100644
--- a/src/System.Data.SqlClient/src/System/Data/Common/AdapterUtil.SqlClient.cs
+++ b/src/System.Data.SqlClient/src/System/Data/Common/AdapterUtil.SqlClient.cs
@@ -880,5 +880,35 @@ namespace System.Data.Common
TraceExceptionAsReturnValue(e);
return e;
}
+
+ internal static ArgumentException InvalidArgumentLength(string argumentName, int limit)
+ {
+ return Argument(SR.GetString(SR.ADP_InvalidArgumentLength, argumentName, limit));
+ }
+
+ internal static ArgumentException MustBeReadOnly(string argumentName)
+ {
+ return Argument(SR.GetString(SR.ADP_MustBeReadOnly, argumentName));
+ }
+
+ internal static InvalidOperationException InvalidMixedUsageOfSecureAndClearCredential()
+ {
+ return InvalidOperation(SR.GetString(SR.ADP_InvalidMixedUsageOfSecureAndClearCredential));
+ }
+
+ internal static ArgumentException InvalidMixedArgumentOfSecureAndClearCredential()
+ {
+ return Argument(SR.GetString(SR.ADP_InvalidMixedUsageOfSecureAndClearCredential));
+ }
+
+ internal static InvalidOperationException InvalidMixedUsageOfSecureCredentialAndIntegratedSecurity()
+ {
+ return InvalidOperation(SR.GetString(SR.ADP_InvalidMixedUsageOfSecureCredentialAndIntegratedSecurity));
+ }
+
+ internal static ArgumentException InvalidMixedArgumentOfSecureCredentialAndIntegratedSecurity()
+ {
+ return Argument(SR.GetString(SR.ADP_InvalidMixedUsageOfSecureCredentialAndIntegratedSecurity));
+ }
}
-} \ No newline at end of file
+}
diff --git a/src/System.Data.SqlClient/src/System/Data/ProviderBase/DbConnectionClosed.cs b/src/System.Data.SqlClient/src/System/Data/ProviderBase/DbConnectionClosed.cs
index 3faa50d468..74f48b852f 100644
--- a/src/System.Data.SqlClient/src/System/Data/ProviderBase/DbConnectionClosed.cs
+++ b/src/System.Data.SqlClient/src/System/Data/ProviderBase/DbConnectionClosed.cs
@@ -2,176 +2,15 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-
-
-//------------------------------------------------------------------------------
-
using System.Data.Common;
-using System.Diagnostics;
-using System.Threading.Tasks;
using System.Transactions;
-
namespace System.Data.ProviderBase
{
- abstract internal class DbConnectionClosed : DbConnectionInternal
- {
- // Construct an "empty" connection
- protected DbConnectionClosed(ConnectionState state, bool hidePassword, bool allowSetConnectionString) : base(state, hidePassword, allowSetConnectionString)
- {
- }
-
- public override string ServerVersion
- {
- get
- {
- throw ADP.ClosedConnectionError();
- }
- }
-
- protected override void Activate(Transaction transaction)
- {
- throw ADP.ClosedConnectionError();
- }
-
- public override DbTransaction BeginTransaction(IsolationLevel il)
- {
- throw ADP.ClosedConnectionError();
- }
-
- public override void ChangeDatabase(string database)
- {
- throw ADP.ClosedConnectionError();
- }
-
- internal override void CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory)
- {
- // not much to do here...
- }
-
- protected override void Deactivate()
- {
- throw ADP.ClosedConnectionError();
- }
-
- public override void EnlistTransaction(Transaction transaction)
- {
- throw ADP.ClosedConnectionError();
- }
-
- protected override DbReferenceCollection CreateReferenceCollection()
- {
- throw ADP.ClosedConnectionError();
- }
-
- internal override bool TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
- {
- return base.TryOpenConnectionInternal(outerConnection, connectionFactory, retry, userOptions);
- }
- }
-
- abstract internal class DbConnectionBusy : DbConnectionClosed
- {
- protected DbConnectionBusy(ConnectionState state) : base(state, true, false)
- {
- }
-
- internal override bool TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
- {
- throw ADP.ConnectionAlreadyOpen(State);
- }
- }
-
- sealed internal class DbConnectionClosedBusy : DbConnectionBusy
- {
- // Closed Connection, Currently Busy - changing connection string
- internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionClosedBusy(); // singleton object
-
- private DbConnectionClosedBusy() : base(ConnectionState.Closed)
- {
- }
- }
-
- sealed internal class DbConnectionOpenBusy : DbConnectionBusy
+ internal abstract partial class DbConnectionClosed : DbConnectionInternal
{
- // Open Connection, Currently Busy - closing connection
- internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionOpenBusy(); // singleton object
-
- private DbConnectionOpenBusy() : base(ConnectionState.Open)
- {
- }
- }
-
- sealed internal class DbConnectionClosedConnecting : DbConnectionBusy
- {
- // Closed Connection, Currently Connecting
-
- internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionClosedConnecting(); // singleton object
-
- private DbConnectionClosedConnecting() : base(ConnectionState.Connecting)
- {
- }
-
- internal override void CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory)
- {
- connectionFactory.SetInnerConnectionTo(owningObject, DbConnectionClosedPreviouslyOpened.SingletonInstance);
- }
-
- internal override bool TryReplaceConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
- {
- return TryOpenConnection(outerConnection, connectionFactory, retry, userOptions);
- }
-
- internal override bool TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
- {
- if (retry == null || !retry.Task.IsCompleted)
- {
- // retry is null if this is a synchronous call
-
- // if someone calls Open or OpenAsync while in this state,
- // then the retry task will not be completed
-
- throw ADP.ConnectionAlreadyOpen(State);
- }
-
- // we are completing an asynchronous open
- Debug.Assert(retry.Task.Status == TaskStatus.RanToCompletion, "retry task must be completed successfully");
- DbConnectionInternal openConnection = retry.Task.Result;
- if (null == openConnection)
- {
- connectionFactory.SetInnerConnectionTo(outerConnection, this);
- throw ADP.InternalConnectionError(ADP.ConnectionError.GetConnectionReturnsNull);
- }
- connectionFactory.SetInnerConnectionEvent(outerConnection, openConnection);
-
- return true;
- }
- }
-
- sealed internal class DbConnectionClosedNeverOpened : DbConnectionClosed
- {
- // Closed Connection, Has Never Been Opened
-
- internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionClosedNeverOpened(); // singleton object
-
- private DbConnectionClosedNeverOpened() : base(ConnectionState.Closed, false, true)
- {
- }
- }
-
- sealed internal class DbConnectionClosedPreviouslyOpened : DbConnectionClosed
- {
- // Closed Connection, Has Previously Been Opened
-
- internal static readonly DbConnectionInternal SingletonInstance = new DbConnectionClosedPreviouslyOpened(); // singleton object
-
- private DbConnectionClosedPreviouslyOpened() : base(ConnectionState.Closed, true, true)
- {
- }
+ protected override void Activate(Transaction transaction) => throw ADP.ClosedConnectionError();
- internal override bool TryReplaceConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
- {
- return TryOpenConnection(outerConnection, connectionFactory, retry, userOptions);
- }
+ public override void EnlistTransaction(Transaction transaction) => throw ADP.ClosedConnectionError();
}
}
diff --git a/src/System.Data.SqlClient/src/System/Data/ProviderBase/DbConnectionFactory.cs b/src/System.Data.SqlClient/src/System/Data/ProviderBase/DbConnectionFactory.cs
index cf6c3f673a..c343a914db 100644
--- a/src/System.Data.SqlClient/src/System/Data/ProviderBase/DbConnectionFactory.cs
+++ b/src/System.Data.SqlClient/src/System/Data/ProviderBase/DbConnectionFactory.cs
@@ -2,11 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-
-
-//------------------------------------------------------------------------------
-
-using System.Collections.Generic;
using System.Diagnostics;
using System.Data.Common;
using System.Threading;
@@ -14,141 +9,8 @@ using System.Threading.Tasks;
namespace System.Data.ProviderBase
{
- internal abstract class DbConnectionFactory
+ internal abstract partial class DbConnectionFactory
{
- private Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> _connectionPoolGroups;
- private readonly List<DbConnectionPool> _poolsToRelease;
- private readonly List<DbConnectionPoolGroup> _poolGroupsToRelease;
- private readonly Timer _pruningTimer;
- private const int PruningDueTime = 4 * 60 * 1000; // 4 minutes
- private const int PruningPeriod = 30 * 1000; // thirty seconds
-
-
- // s_pendingOpenNonPooled is an array of tasks used to throttle creation of non-pooled connections to
- // a maximum of Environment.ProcessorCount at a time.
- private static uint s_pendingOpenNonPooledNext = 0;
- private static Task<DbConnectionInternal>[] s_pendingOpenNonPooled = new Task<DbConnectionInternal>[Environment.ProcessorCount];
- private static Task<DbConnectionInternal> s_completedTask;
-
- protected DbConnectionFactory()
- {
- _connectionPoolGroups = new Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup>();
- _poolsToRelease = new List<DbConnectionPool>();
- _poolGroupsToRelease = new List<DbConnectionPoolGroup>();
- _pruningTimer = CreatePruningTimer();
- }
-
-
- abstract public DbProviderFactory ProviderFactory
- {
- get;
- }
-
-
- public void ClearAllPools()
- {
- Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> connectionPoolGroups = _connectionPoolGroups;
- foreach (KeyValuePair<DbConnectionPoolKey, DbConnectionPoolGroup> entry in connectionPoolGroups)
- {
- DbConnectionPoolGroup poolGroup = entry.Value;
- if (null != poolGroup)
- {
- poolGroup.Clear();
- }
- }
- }
-
- public void ClearPool(DbConnection connection)
- {
- ADP.CheckArgumentNull(connection, nameof(connection));
-
- DbConnectionPoolGroup poolGroup = GetConnectionPoolGroup(connection);
- if (null != poolGroup)
- {
- poolGroup.Clear();
- }
- }
-
- public void ClearPool(DbConnectionPoolKey key)
- {
- Debug.Assert(key != null, "key cannot be null");
- ADP.CheckArgumentNull(key.ConnectionString, nameof(key) + "." + nameof(key.ConnectionString));
-
- DbConnectionPoolGroup poolGroup;
- Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> connectionPoolGroups = _connectionPoolGroups;
- if (connectionPoolGroups.TryGetValue(key, out poolGroup))
- {
- poolGroup.Clear();
- }
- }
-
- internal virtual DbConnectionPoolProviderInfo CreateConnectionPoolProviderInfo(DbConnectionOptions connectionOptions)
- {
- return null;
- }
-
-
- internal DbConnectionInternal CreateNonPooledConnection(DbConnection owningConnection, DbConnectionPoolGroup poolGroup, DbConnectionOptions userOptions)
- {
- Debug.Assert(null != owningConnection, "null owningConnection?");
- Debug.Assert(null != poolGroup, "null poolGroup?");
-
- DbConnectionOptions connectionOptions = poolGroup.ConnectionOptions;
- DbConnectionPoolGroupProviderInfo poolGroupProviderInfo = poolGroup.ProviderInfo;
- DbConnectionPoolKey poolKey = poolGroup.PoolKey;
-
- DbConnectionInternal newConnection = CreateConnection(connectionOptions, poolKey, poolGroupProviderInfo, null, owningConnection, userOptions);
- if (null != newConnection)
- {
- newConnection.MakeNonPooledObject(owningConnection);
- }
- return newConnection;
- }
-
- internal DbConnectionInternal CreatePooledConnection(DbConnectionPool pool, DbConnection owningObject, DbConnectionOptions options, DbConnectionPoolKey poolKey, DbConnectionOptions userOptions)
- {
- Debug.Assert(null != pool, "null pool?");
- DbConnectionPoolGroupProviderInfo poolGroupProviderInfo = pool.PoolGroup.ProviderInfo;
-
- DbConnectionInternal newConnection = CreateConnection(options, poolKey, poolGroupProviderInfo, pool, owningObject, userOptions);
- if (null != newConnection)
- {
- newConnection.MakePooledConnection(pool);
- }
- return newConnection;
- }
-
- virtual internal DbConnectionPoolGroupProviderInfo CreateConnectionPoolGroupProviderInfo(DbConnectionOptions connectionOptions)
- {
- return null;
- }
-
- private Timer CreatePruningTimer()
- {
- TimerCallback callback = new TimerCallback(PruneConnectionPoolGroups);
- return new Timer(callback, null, PruningDueTime, PruningPeriod);
- }
-
- protected DbConnectionOptions FindConnectionOptions(DbConnectionPoolKey key)
- {
- Debug.Assert(key != null, "key cannot be null");
- if (!string.IsNullOrEmpty(key.ConnectionString))
- {
- DbConnectionPoolGroup connectionPoolGroup;
- Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> connectionPoolGroups = _connectionPoolGroups;
- if (connectionPoolGroups.TryGetValue(key, out connectionPoolGroup))
- {
- return connectionPoolGroup.ConnectionOptions;
- }
- }
- return null;
- }
-
- private static Task<DbConnectionInternal> GetCompletedTask()
- {
- Debug.Assert(Monitor.IsEntered(s_pendingOpenNonPooled), $"Expected {nameof(s_pendingOpenNonPooled)} lock to be held.");
- return s_completedTask ?? (s_completedTask = Task.FromResult<DbConnectionInternal>(null));
- }
internal bool TryGetConnection(DbConnection owningConnection, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, out DbConnectionInternal connection)
{
@@ -320,283 +182,5 @@ namespace System.Data.ProviderBase
return true;
}
-
- private DbConnectionPool GetConnectionPool(DbConnection owningObject, DbConnectionPoolGroup connectionPoolGroup)
- {
- // if poolgroup is disabled, it will be replaced with a new entry
-
- Debug.Assert(null != owningObject, "null owningObject?");
- Debug.Assert(null != connectionPoolGroup, "null connectionPoolGroup?");
-
- // It is possible that while the outer connection object has
- // been sitting around in a closed and unused state in some long
- // running app, the pruner may have come along and remove this
- // the pool entry from the master list. If we were to use a
- // pool entry in this state, we would create "unmanaged" pools,
- // which would be bad. To avoid this problem, we automagically
- // re-create the pool entry whenever it's disabled.
-
- // however, don't rebuild connectionOptions if no pooling is involved - let new connections do that work
- if (connectionPoolGroup.IsDisabled && (null != connectionPoolGroup.PoolGroupOptions))
- {
- // reusing existing pool option in case user originally used SetConnectionPoolOptions
- DbConnectionPoolGroupOptions poolOptions = connectionPoolGroup.PoolGroupOptions;
-
- // get the string to hash on again
- DbConnectionOptions connectionOptions = connectionPoolGroup.ConnectionOptions;
- Debug.Assert(null != connectionOptions, "prevent expansion of connectionString");
-
- connectionPoolGroup = GetConnectionPoolGroup(connectionPoolGroup.PoolKey, poolOptions, ref connectionOptions);
- Debug.Assert(null != connectionPoolGroup, "null connectionPoolGroup?");
- SetConnectionPoolGroup(owningObject, connectionPoolGroup);
- }
- DbConnectionPool connectionPool = connectionPoolGroup.GetConnectionPool(this);
- return connectionPool;
- }
-
- internal DbConnectionPoolGroup GetConnectionPoolGroup(DbConnectionPoolKey key, DbConnectionPoolGroupOptions poolOptions, ref DbConnectionOptions userConnectionOptions)
- {
- if (string.IsNullOrEmpty(key.ConnectionString))
- {
- return (DbConnectionPoolGroup)null;
- }
-
- DbConnectionPoolGroup connectionPoolGroup;
- Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> connectionPoolGroups = _connectionPoolGroups;
- if (!connectionPoolGroups.TryGetValue(key, out connectionPoolGroup) || (connectionPoolGroup.IsDisabled && (null != connectionPoolGroup.PoolGroupOptions)))
- {
- // If we can't find an entry for the connection string in
- // our collection of pool entries, then we need to create a
- // new pool entry and add it to our collection.
-
- DbConnectionOptions connectionOptions = CreateConnectionOptions(key.ConnectionString, userConnectionOptions);
- if (null == connectionOptions)
- {
- throw ADP.InternalConnectionError(ADP.ConnectionError.ConnectionOptionsMissing);
- }
-
- if (null == userConnectionOptions)
- { // we only allow one expansion on the connection string
- userConnectionOptions = connectionOptions;
- }
-
- // We don't support connection pooling on Win9x
- if (null == poolOptions)
- {
- if (null != connectionPoolGroup)
- {
- // reusing existing pool option in case user originally used SetConnectionPoolOptions
- poolOptions = connectionPoolGroup.PoolGroupOptions;
- }
- else
- {
- // Note: may return null for non-pooled connections
- poolOptions = CreateConnectionPoolGroupOptions(connectionOptions);
- }
- }
-
- lock (this)
- {
- connectionPoolGroups = _connectionPoolGroups;
- if (!connectionPoolGroups.TryGetValue(key, out connectionPoolGroup))
- {
- DbConnectionPoolGroup newConnectionPoolGroup = new DbConnectionPoolGroup(connectionOptions, key, poolOptions);
- newConnectionPoolGroup.ProviderInfo = CreateConnectionPoolGroupProviderInfo(connectionOptions);
-
- // build new dictionary with space for new connection string
- Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> newConnectionPoolGroups = new Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup>(1 + connectionPoolGroups.Count);
- foreach (KeyValuePair<DbConnectionPoolKey, DbConnectionPoolGroup> entry in connectionPoolGroups)
- {
- newConnectionPoolGroups.Add(entry.Key, entry.Value);
- }
-
- // lock prevents race condition with PruneConnectionPoolGroups
- newConnectionPoolGroups.Add(key, newConnectionPoolGroup);
- connectionPoolGroup = newConnectionPoolGroup;
- _connectionPoolGroups = newConnectionPoolGroups;
- }
- else
- {
- Debug.Assert(!connectionPoolGroup.IsDisabled, "Disabled pool entry discovered");
- }
- }
- Debug.Assert(null != connectionPoolGroup, "how did we not create a pool entry?");
- Debug.Assert(null != userConnectionOptions, "how did we not have user connection options?");
- }
- else if (null == userConnectionOptions)
- {
- userConnectionOptions = connectionPoolGroup.ConnectionOptions;
- }
- return connectionPoolGroup;
- }
-
-
- private void PruneConnectionPoolGroups(object state)
- {
- // First, walk the pool release list and attempt to clear each
- // pool, when the pool is finally empty, we dispose of it. If the
- // pool isn't empty, it's because there are active connections or
- // distributed transactions that need it.
- lock (_poolsToRelease)
- {
- if (0 != _poolsToRelease.Count)
- {
- DbConnectionPool[] poolsToRelease = _poolsToRelease.ToArray();
- foreach (DbConnectionPool pool in poolsToRelease)
- {
- if (null != pool)
- {
- pool.Clear();
-
- if (0 == pool.Count)
- {
- _poolsToRelease.Remove(pool);
- }
- }
- }
- }
- }
-
- // Next, walk the pool entry release list and dispose of each
- // pool entry when it is finally empty. If the pool entry isn't
- // empty, it's because there are active pools that need it.
- lock (_poolGroupsToRelease)
- {
- if (0 != _poolGroupsToRelease.Count)
- {
- DbConnectionPoolGroup[] poolGroupsToRelease = _poolGroupsToRelease.ToArray();
- foreach (DbConnectionPoolGroup poolGroup in poolGroupsToRelease)
- {
- if (null != poolGroup)
- {
- int poolsLeft = poolGroup.Clear(); // may add entries to _poolsToRelease
-
- if (0 == poolsLeft)
- {
- _poolGroupsToRelease.Remove(poolGroup);
- }
- }
- }
- }
- }
-
- // Finally, we walk through the collection of connection pool entries
- // and prune each one. This will cause any empty pools to be put
- // into the release list.
- lock (this)
- {
- Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> connectionPoolGroups = _connectionPoolGroups;
- Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup> newConnectionPoolGroups = new Dictionary<DbConnectionPoolKey, DbConnectionPoolGroup>(connectionPoolGroups.Count);
-
- foreach (KeyValuePair<DbConnectionPoolKey, DbConnectionPoolGroup> entry in connectionPoolGroups)
- {
- if (null != entry.Value)
- {
- Debug.Assert(!entry.Value.IsDisabled, "Disabled pool entry discovered");
-
- // entries start active and go idle during prune if all pools are gone
- // move idle entries from last prune pass to a queue for pending release
- // otherwise process entry which may move it from active to idle
- if (entry.Value.Prune())
- { // may add entries to _poolsToRelease
- QueuePoolGroupForRelease(entry.Value);
- }
- else
- {
- newConnectionPoolGroups.Add(entry.Key, entry.Value);
- }
- }
- }
- _connectionPoolGroups = newConnectionPoolGroups;
- }
- }
-
- internal void QueuePoolForRelease(DbConnectionPool pool, bool clearing)
- {
- // Queue the pool up for release -- we'll clear it out and dispose
- // of it as the last part of the pruning timer callback so we don't
- // do it with the pool entry or the pool collection locked.
- Debug.Assert(null != pool, "null pool?");
-
- // set the pool to the shutdown state to force all active
- // connections to be automatically disposed when they
- // are returned to the pool
- pool.Shutdown();
-
- lock (_poolsToRelease)
- {
- if (clearing)
- {
- pool.Clear();
- }
- _poolsToRelease.Add(pool);
- }
- }
-
- internal void QueuePoolGroupForRelease(DbConnectionPoolGroup poolGroup)
- {
- Debug.Assert(null != poolGroup, "null poolGroup?");
-
- lock (_poolGroupsToRelease)
- {
- _poolGroupsToRelease.Add(poolGroup);
- }
- }
-
- virtual protected DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions)
- {
- return CreateConnection(options, poolKey, poolGroupProviderInfo, pool, owningConnection);
- }
-
- internal DbMetaDataFactory GetMetaDataFactory(DbConnectionPoolGroup connectionPoolGroup, DbConnectionInternal internalConnection)
- {
- Debug.Assert(connectionPoolGroup != null, "connectionPoolGroup may not be null.");
-
- // get the matadatafactory from the pool entry. If it does not already have one
- // create one and save it on the pool entry
- DbMetaDataFactory metaDataFactory = connectionPoolGroup.MetaDataFactory;
-
- // consider serializing this so we don't construct multiple metadata factories
- // if two threads happen to hit this at the same time. One will be GC'd
- if (metaDataFactory == null)
- {
- bool allowCache = false;
- metaDataFactory = CreateMetaDataFactory(internalConnection, out allowCache);
- if (allowCache)
- {
- connectionPoolGroup.MetaDataFactory = metaDataFactory;
- }
- }
- return metaDataFactory;
- }
-
- protected virtual DbMetaDataFactory CreateMetaDataFactory(DbConnectionInternal internalConnection, out bool cacheMetaDataFactory)
- {
- // providers that support GetSchema must override this with a method that creates a meta data
- // factory appropriate for them.
- cacheMetaDataFactory = false;
- throw ADP.NotSupported();
- }
-
- abstract protected DbConnectionInternal CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection);
-
- abstract protected DbConnectionOptions CreateConnectionOptions(string connectionString, DbConnectionOptions previous);
-
- abstract protected DbConnectionPoolGroupOptions CreateConnectionPoolGroupOptions(DbConnectionOptions options);
-
- abstract internal DbConnectionPoolGroup GetConnectionPoolGroup(DbConnection connection);
-
- abstract internal DbConnectionInternal GetInnerConnection(DbConnection connection);
-
-
- abstract internal void PermissionDemand(DbConnection outerConnection);
-
- abstract internal void SetConnectionPoolGroup(DbConnection outerConnection, DbConnectionPoolGroup poolGroup);
-
- abstract internal void SetInnerConnectionEvent(DbConnection owningObject, DbConnectionInternal to);
-
- abstract internal bool SetInnerConnectionFrom(DbConnection owningObject, DbConnectionInternal to, DbConnectionInternal from);
-
- abstract internal void SetInnerConnectionTo(DbConnection owningObject, DbConnectionInternal to);
}
}
diff --git a/src/System.Data.SqlClient/src/System/Data/ProviderBase/DbConnectionInternal.cs b/src/System.Data.SqlClient/src/System/Data/ProviderBase/DbConnectionInternal.cs
index 3ac471cac9..0b08a9c102 100644
--- a/src/System.Data.SqlClient/src/System/Data/ProviderBase/DbConnectionInternal.cs
+++ b/src/System.Data.SqlClient/src/System/Data/ProviderBase/DbConnectionInternal.cs
@@ -3,40 +3,18 @@
// See the LICENSE file in the project root for more information.
-
-//------------------------------------------------------------------------------
-
using System.Data.Common;
-using System.Data.SqlClient;
using System.Diagnostics;
using System.Threading;
-using System.Threading.Tasks;
using System.Transactions;
namespace System.Data.ProviderBase
{
- internal abstract class DbConnectionInternal
+ internal abstract partial class DbConnectionInternal
{
- internal static readonly StateChangeEventArgs StateChangeClosed = new StateChangeEventArgs(ConnectionState.Open, ConnectionState.Closed);
- internal static readonly StateChangeEventArgs StateChangeOpen = new StateChangeEventArgs(ConnectionState.Closed, ConnectionState.Open);
-
- private readonly bool _allowSetConnectionString;
- private readonly bool _hidePassword;
- private readonly ConnectionState _state;
-
- private readonly WeakReference _owningObject = new WeakReference(null, false); // [usage must be thread safe] the owning object, when not in the pool. (both Pooled and Non-Pooled connections)
-
- private DbConnectionPool _connectionPool; // the pooler that the connection came from (Pooled connections only)
- private DbReferenceCollection _referenceCollection; // collection of objects that we need to notify in some way when we're being deactivated
- private int _pooledCount; // [usage must be thread safe] the number of times this object has been pushed into the pool less the number of times it's been popped (0 != inPool)
-
- private bool _connectionIsDoomed; // true when the connection should no longer be used.
- private bool _cannotBePooled; // true when the connection should no longer be pooled.
private bool _isInStasis;
- private DateTime _createTime; // when the connection was created.
-
private Transaction _enlistedTransaction; // [usage must be thread-safe] the transaction that we're enlisted in, either manually or automatically
// _enlistedTransaction is a clone, so that transaction information can be queried even if the original transaction object is disposed.
@@ -45,39 +23,6 @@ namespace System.Data.ProviderBase
// Also, this reference should not be disposed, since we aren't taking ownership of it.
private Transaction _enlistedTransactionOriginal;
-#if DEBUG
- private int _activateCount; // debug only counter to verify activate/deactivates are in sync.
-#endif //DEBUG
-
- protected DbConnectionInternal() : this(ConnectionState.Open, true, false)
- {
- }
-
- // Constructor for internal connections
- internal DbConnectionInternal(ConnectionState state, bool hidePassword, bool allowSetConnectionString)
- {
- _allowSetConnectionString = allowSetConnectionString;
- _hidePassword = hidePassword;
- _state = state;
- }
-
- internal bool AllowSetConnectionString
- {
- get
- {
- return _allowSetConnectionString;
- }
- }
-
- internal bool CanBePooled
- {
- get
- {
- bool flag = (!_connectionIsDoomed && !_cannotBePooled && !_owningObject.IsAlive);
- return flag;
- }
- }
-
protected internal Transaction EnlistedTransaction
{
get
@@ -237,74 +182,6 @@ namespace System.Data.ProviderBase
}
}
- protected internal bool IsConnectionDoomed
- {
- get
- {
- return _connectionIsDoomed;
- }
- }
-
- internal bool IsEmancipated
- {
- get
- {
- // NOTE: There are race conditions between PrePush, PostPop and this
- // property getter -- only use this while this object is locked;
- // (DbConnectionPool.Clear and ReclaimEmancipatedObjects
- // do this for us)
-
- // The functionality is as follows:
- //
- // _pooledCount is incremented when the connection is pushed into the pool
- // _pooledCount is decremented when the connection is popped from the pool
- // _pooledCount is set to -1 when the connection is not pooled (just in case...)
- //
- // That means that:
- //
- // _pooledCount > 1 connection is in the pool multiple times (This should not happen)
- // _pooledCount == 1 connection is in the pool
- // _pooledCount == 0 connection is out of the pool
- // _pooledCount == -1 connection is not a pooled connection; we shouldn't be here for non-pooled connections.
- // _pooledCount < -1 connection out of the pool multiple times
- //
- // Now, our job is to return TRUE when the connection is out
- // of the pool and it's owning object is no longer around to
- // return it.
-
- bool value = (_pooledCount < 1) && !_owningObject.IsAlive;
- return value;
- }
- }
-
- internal bool IsInPool
- {
- get
- {
- Debug.Assert(_pooledCount <= 1 && _pooledCount >= -1, "Pooled count for object is invalid");
- return (_pooledCount == 1);
- }
- }
-
-
- protected internal object Owner
- {
- // We use a weak reference to the owning object so we can identify when
- // it has been garbage collected without thowing exceptions.
- get
- {
- return _owningObject.Target;
- }
- }
-
- internal DbConnectionPool Pool
- {
- get
- {
- return _connectionPool;
- }
- }
-
virtual protected bool ReadyToPrepareTransaction
{
get
@@ -313,44 +190,6 @@ namespace System.Data.ProviderBase
}
}
- protected internal DbReferenceCollection ReferenceCollection
- {
- get
- {
- return _referenceCollection;
- }
- }
-
- abstract public string ServerVersion
- {
- get;
- }
-
- // this should be abstract but until it is added to all the providers virtual will have to do
- virtual public string ServerVersionNormalized
- {
- get
- {
- throw ADP.NotSupported();
- }
- }
-
- public bool ShouldHidePassword
- {
- get
- {
- return _hidePassword;
- }
- }
-
- public ConnectionState State
- {
- get
- {
- return _state;
- }
- }
-
abstract protected void Activate(Transaction transaction);
internal void ActivateConnection(Transaction transaction)
@@ -361,26 +200,6 @@ namespace System.Data.ProviderBase
Activate(transaction);
}
- internal void AddWeakReference(object value, int tag)
- {
- if (null == _referenceCollection)
- {
- _referenceCollection = CreateReferenceCollection();
- if (null == _referenceCollection)
- {
- throw ADP.InternalError(ADP.InternalErrorCode.CreateReferenceCollectionReturnedNull);
- }
- }
- _referenceCollection.Add(value, tag);
- }
-
- abstract public DbTransaction BeginTransaction(IsolationLevel il);
-
- virtual public void ChangeDatabase(string value)
- {
- throw ADP.MethodNotImplemented();
- }
-
internal virtual void CloseConnection(DbConnection owningObject, DbConnectionFactory connectionFactory)
{
// The implementation here is the implementation required for the
@@ -487,57 +306,6 @@ namespace System.Data.ProviderBase
}
}
- virtual internal void PrepareForReplaceConnection()
- {
- // By default, there is no preparation required
- }
-
- virtual protected void PrepareForCloseConnection()
- {
- // By default, there is no preparation required
- }
-
- virtual protected object ObtainAdditionalLocksForClose()
- {
- return null; // no additional locks in default implementation
- }
-
- virtual protected void ReleaseAdditionalLocksForClose(object lockToken)
- {
- // no additional locks in default implementation
- }
-
- virtual protected DbReferenceCollection CreateReferenceCollection()
- {
- throw ADP.InternalError(ADP.InternalErrorCode.AttemptingToConstructReferenceCollectionOnStaticObject);
- }
-
- abstract protected void Deactivate();
-
- internal void DeactivateConnection()
- {
- // Internal method called from the connection pooler so we don't expose
- // the Deactivate method publicly.
-
-#if DEBUG
- int activateCount = Interlocked.Decrement(ref _activateCount);
-#endif // DEBUG
-
-
- if (!_connectionIsDoomed && Pool.UseLoadBalancing)
- {
- // If we're not already doomed, check the connection's lifetime and
- // doom it if it's lifetime has elapsed.
-
- DateTime now = DateTime.UtcNow;
- if ((now.Ticks - _createTime.Ticks) > Pool.LoadBalanceTimeout.Ticks)
- {
- DoNotPoolThisConnection();
- }
- }
- Deactivate();
- }
-
virtual internal void DelegatedTransactionEnded()
{
// Called by System.Transactions when the delegated transaction has
@@ -604,188 +372,9 @@ namespace System.Data.ProviderBase
enlistedTransaction.Dispose();
}
}
-
- protected internal void DoNotPoolThisConnection()
- {
- _cannotBePooled = true;
- }
-
- /// <devdoc>Ensure that this connection cannot be put back into the pool.</devdoc>
- protected internal void DoomThisConnection()
- {
- _connectionIsDoomed = true;
- }
-
+
abstract public void EnlistTransaction(Transaction transaction);
- protected internal virtual DataTable GetSchema(DbConnectionFactory factory, DbConnectionPoolGroup poolGroup, DbConnection outerConnection, string collectionName, string[] restrictions)
- {
- Debug.Assert(outerConnection != null, "outerConnection may not be null.");
-
- DbMetaDataFactory metaDataFactory = factory.GetMetaDataFactory(poolGroup, this);
- Debug.Assert(metaDataFactory != null, "metaDataFactory may not be null.");
-
- return metaDataFactory.GetSchema(outerConnection, collectionName, restrictions);
- }
-
- internal void MakeNonPooledObject(object owningObject)
- {
- // Used by DbConnectionFactory to indicate that this object IS NOT part of
- // a connection pool.
-
- _connectionPool = null;
- _owningObject.Target = owningObject;
- _pooledCount = -1;
- }
-
- internal void MakePooledConnection(DbConnectionPool connectionPool)
- {
- // Used by DbConnectionFactory to indicate that this object IS part of
- // a connection pool.
- _createTime = DateTime.UtcNow;
-
- _connectionPool = connectionPool;
- }
-
- internal void NotifyWeakReference(int message)
- {
- DbReferenceCollection referenceCollection = ReferenceCollection;
- if (null != referenceCollection)
- {
- referenceCollection.Notify(message);
- }
- }
-
- internal virtual void OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
- {
- if (!TryOpenConnection(outerConnection, connectionFactory, null, null))
- {
- throw ADP.InternalError(ADP.InternalErrorCode.SynchronousConnectReturnedPending);
- }
- }
-
- /// <devdoc>The default implementation is for the open connection objects, and
- /// it simply throws. Our private closed-state connection objects
- /// override this and do the correct thing.</devdoc>
- // User code should either override DbConnectionInternal.Activate when it comes out of the pool
- // or override DbConnectionFactory.CreateConnection when the connection is created for non-pooled connections
- internal virtual bool TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
- {
- throw ADP.ConnectionAlreadyOpen(State);
- }
-
- internal virtual bool TryReplaceConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
- {
- throw ADP.MethodNotImplemented();
- }
-
- protected bool TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource<DbConnectionInternal> retry, DbConnectionOptions userOptions)
- {
- // ?->Connecting: prevent set_ConnectionString during Open
- if (connectionFactory.SetInnerConnectionFrom(outerConnection, DbConnectionClosedConnecting.SingletonInstance, this))
- {
- DbConnectionInternal openConnection = null;
- try
- {
- connectionFactory.PermissionDemand(outerConnection);
- if (!connectionFactory.TryGetConnection(outerConnection, retry, userOptions, this, out openConnection))
- {
- return false;
- }
- }
- catch
- {
- // This should occur for all exceptions, even ADP.UnCatchableExceptions.
- connectionFactory.SetInnerConnectionTo(outerConnection, this);
- throw;
- }
- if (null == openConnection)
- {
- connectionFactory.SetInnerConnectionTo(outerConnection, this);
- throw ADP.InternalConnectionError(ADP.ConnectionError.GetConnectionReturnsNull);
- }
- connectionFactory.SetInnerConnectionEvent(outerConnection, openConnection);
- }
-
- return true;
- }
-
- internal void PrePush(object expectedOwner)
- {
- // Called by DbConnectionPool when we're about to be put into it's pool, we
- // take this opportunity to ensure ownership and pool counts are legit.
-
- // IMPORTANT NOTE: You must have taken a lock on the object before
- // you call this method to prevent race conditions with Clear and
- // ReclaimEmancipatedObjects.
-
- //3 // The following tests are retail assertions of things we can't allow to happen.
- if (null == expectedOwner)
- {
- if (null != _owningObject.Target)
- {
- throw ADP.InternalError(ADP.InternalErrorCode.UnpooledObjectHasOwner); // new unpooled object has an owner
- }
- }
- else if (_owningObject.Target != expectedOwner)
- {
- throw ADP.InternalError(ADP.InternalErrorCode.UnpooledObjectHasWrongOwner); // unpooled object has incorrect owner
- }
- if (0 != _pooledCount)
- {
- throw ADP.InternalError(ADP.InternalErrorCode.PushingObjectSecondTime); // pushing object onto stack a second time
- }
- _pooledCount++;
- _owningObject.Target = null; // NOTE: doing this and checking for InternalError.PooledObjectHasOwner degrades the close by 2%
- }
-
- internal void PostPop(object newOwner)
- {
- // Called by DbConnectionPool right after it pulls this from it's pool, we
- // take this opportunity to ensure ownership and pool counts are legit.
-
- Debug.Assert(!IsEmancipated, "pooled object not in pool");
-
- // When another thread is clearing this pool, it
- // will doom all connections in this pool without prejudice which
- // causes the following assert to fire, which really mucks up stress
- // against checked bits. The assert is benign, so we're commenting
- // it out.
- //Debug.Assert(CanBePooled, "pooled object is not poolable");
-
- // IMPORTANT NOTE: You must have taken a lock on the object before
- // you call this method to prevent race conditions with Clear and
- // ReclaimEmancipatedObjects.
-
- if (null != _owningObject.Target)
- {
- throw ADP.InternalError(ADP.InternalErrorCode.PooledObjectHasOwner); // pooled connection already has an owner!
- }
- _owningObject.Target = newOwner;
- _pooledCount--;
- //3 // The following tests are retail assertions of things we can't allow to happen.
- if (null != Pool)
- {
- if (0 != _pooledCount)
- {
- throw ADP.InternalError(ADP.InternalErrorCode.PooledObjectInPoolMoreThanOnce); // popping object off stack with multiple pooledCount
- }
- }
- else if (-1 != _pooledCount)
- {
- throw ADP.InternalError(ADP.InternalErrorCode.NonPooledObjectUsedMoreThanOnce); // popping object off stack with multiple pooledCount
- }
- }
-
- internal void RemoveWeakReference(object value)
- {
- DbReferenceCollection referenceCollection = ReferenceCollection;
- if (null != referenceCollection)
- {
- referenceCollection.Remove(value);
- }
- }
-
// Cleanup connection's transaction-specific structures (currently used by Delegated transaction).
// This is a separate method because cleanup can be triggered in multiple ways for a delegated
// transaction.
@@ -876,16 +465,5 @@ namespace System.Data.ProviderBase
{
_isInStasis = false;
}
-
- /// <summary>
- /// When overridden in a derived class, will check if the underlying connection is still actually alive
- /// </summary>
- /// <param name="throwOnException">If true an exception will be thrown if the connection is dead instead of returning true\false
- /// (this allows the caller to have the real reason that the connection is not alive (e.g. network error, etc))</param>
- /// <returns>True if the connection is still alive, otherwise false (If not overridden, then always true)</returns>
- internal virtual bool IsConnectionAlive(bool throwOnException = false)
- {
- return true;
- }
}
}
diff --git a/src/System.Data.SqlClient/src/System/Data/ProviderBase/DbConnectionPool.cs b/src/System.Data.SqlClient/src/System/Data/ProviderBase/DbConnectionPool.cs
index 99830b6370..ee93b888be 100644
--- a/src/System.Data.SqlClient/src/System/Data/ProviderBase/DbConnectionPool.cs
+++ b/src/System.Data.SqlClient/src/System/Data/ProviderBase/DbConnectionPool.cs
@@ -413,10 +413,7 @@ namespace System.Data.ProviderBase
_objectList = new List<DbConnectionInternal>(MaxPoolSize);
- if (ADP.IsPlatformNT5)
- {
- _transactedConnectionPool = new TransactedConnectionPool(this);
- }
+ _transactedConnectionPool = new TransactedConnectionPool(this); // initialize irrespective of platform
_poolCreateRequest = new WaitCallback(PoolCreateRequest); // used by CleanupCallback
_state = State.Running;
@@ -664,10 +661,12 @@ namespace System.Data.ProviderBase
ReclaimEmancipatedObjects();
}
- private Timer CreateCleanupTimer()
- {
- return (new Timer(new TimerCallback(this.CleanupCallback), null, _cleanupWait, _cleanupWait));
- }
+ private Timer CreateCleanupTimer() =>
+ ADP.UnsafeCreateTimer(
+ new TimerCallback(CleanupCallback),
+ null,
+ _cleanupWait,
+ _cleanupWait);
private DbConnectionInternal CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
{
@@ -728,6 +727,7 @@ namespace System.Data.ProviderBase
// timer allocation has to be done out of CER block
Timer t = new Timer(new TimerCallback(this.ErrorCallback), null, Timeout.Infinite, Timeout.Infinite);
+
bool timerIsNotDisposed;
try { }
finally
@@ -1373,9 +1373,19 @@ namespace System.Data.ProviderBase
{
while (NeedToReplenish)
{
- // Don't specify any user options because there is no outer connection associated with the new connection
- newObj = CreateObject(owningObject: null, userOptions: null, oldConnection: null);
-
+ try
+ {
+ // Don't specify any user options because there is no outer connection associated with the new connection
+ newObj = CreateObject(owningObject: null, userOptions: null, oldConnection: null);
+ }
+ catch
+ {
+ // Catch all the exceptions occuring during CreateObject so that they
+ // don't emerge as unhandled on the thread pool and don't crash applications
+ // The error is handled in CreateObject and surfaced to the caller of the Connection Pool
+ // using the ErrorEvent. Hence it is OK to swallow all exceptions here.
+ break;
+ }
// We do not need to check error flag here, since we know if
// CreateObject returned null, we are in error case.
if (null != newObj)
diff --git a/src/System.Data.SqlClient/src/System/Data/ProviderBase/TimeoutTimer.cs b/src/System.Data.SqlClient/src/System/Data/ProviderBase/TimeoutTimer.cs
deleted file mode 100644
index 969f399d34..0000000000
--- a/src/System.Data.SqlClient/src/System/Data/ProviderBase/TimeoutTimer.cs
+++ /dev/null
@@ -1,170 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-//
-// Class used to manage timeouts in complex system operations.
-//
-
-using System.Data.Common;
-using System.Diagnostics;
-
-namespace System.Data.ProviderBase
-{
- // Purpose:
- // Manages determining and tracking timeouts
- //
- // Intended use:
- // Call StartXXXXTimeout() to get a timer with the given expiration point
- // Get remaining time in appropriate format to pass to subsystem timeouts
- // Check for timeout via IsExpired for checks in managed code.
- // Simply abandon to GC when done.
- internal class TimeoutTimer
- {
- //-------------------
- // Fields
- //-------------------
- private long _timerExpire;
- private bool _isInfiniteTimeout;
-
- //-------------------
- // Timeout-setting methods
- //-------------------
-
- // Get a new timer that will expire in the given number of seconds
- // For input, a value of zero seconds indicates infinite timeout
- internal static TimeoutTimer StartSecondsTimeout(int seconds)
- {
- //--------------------
- // Preconditions: None (seconds must conform to SetTimeoutSeconds requirements)
-
- //--------------------
- // Method body
- var timeout = new TimeoutTimer();
- timeout.SetTimeoutSeconds(seconds);
-
- //---------------------
- // Postconditions
- Debug.Assert(timeout != null); // Need a valid timeouttimer if no error
-
- return timeout;
- }
-
- // Get a new timer that will expire in the given number of milliseconds
- // No current need to support infinite milliseconds timeout
- internal static TimeoutTimer StartMillisecondsTimeout(long milliseconds)
- {
- //--------------------
- // Preconditions
- Debug.Assert(0 <= milliseconds);
-
- //--------------------
- // Method body
- var timeout = new TimeoutTimer();
- timeout._timerExpire = checked(ADP.TimerCurrent() + (milliseconds * TimeSpan.TicksPerMillisecond));
- timeout._isInfiniteTimeout = false;
-
- //---------------------
- // Postconditions
- Debug.Assert(timeout != null); // Need a valid timeouttimer if no error
-
- return timeout;
- }
-
- //-------------------
- // Methods for changing timeout
- //-------------------
-
- internal void SetTimeoutSeconds(int seconds)
- {
- //--------------------
- // Preconditions
- Debug.Assert(0 <= seconds || InfiniteTimeout == seconds); // no need to support negative seconds at present
-
- //--------------------
- // Method body
- if (InfiniteTimeout == seconds)
- {
- _isInfiniteTimeout = true;
- }
- else
- {
- // Stash current time + timeout
- _timerExpire = checked(ADP.TimerCurrent() + ADP.TimerFromSeconds(seconds));
- _isInfiniteTimeout = false;
- }
- //---------------------
- // Postconditions:None
- }
-
- //-------------------
- // Timeout info properties
- //-------------------
-
- // Indicator for infinite timeout when starting a timer
- internal static readonly long InfiniteTimeout = 0;
-
- // Is this timer in an expired state?
- internal bool IsExpired
- {
- get
- {
- return !IsInfinite && ADP.TimerHasExpired(_timerExpire);
- }
- }
-
- // is this an infinite-timeout timer?
- internal bool IsInfinite
- {
- get
- {
- return _isInfiniteTimeout;
- }
- }
-
- // Special accessor for TimerExpire for use when thunking to legacy timeout methods.
- internal long LegacyTimerExpire
- {
- get
- {
- return (_isInfiniteTimeout) ? Int64.MaxValue : _timerExpire;
- }
- }
-
- // Returns milliseconds remaining trimmed to zero for none remaining
- // and long.MaxValue for infinite
- // This method should be preferred for internal calculations that are not
- // yet common enough to code into the TimeoutTimer class itself.
- internal long MillisecondsRemaining
- {
- get
- {
- //-------------------
- // Preconditions: None
-
- //-------------------
- // Method Body
- long milliseconds;
- if (_isInfiniteTimeout)
- {
- milliseconds = long.MaxValue;
- }
- else
- {
- milliseconds = ADP.TimerRemainingMilliseconds(_timerExpire);
- if (0 > milliseconds)
- {
- milliseconds = 0;
- }
- }
-
- //--------------------
- // Postconditions
- Debug.Assert(0 <= milliseconds); // This property guarantees no negative return values
-
- return milliseconds;
- }
- }
- }
-}
-
diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIHandle.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIHandle.cs
index dcfedc841d..b38cb24116 100644
--- a/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIHandle.cs
+++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIHandle.cs
@@ -41,7 +41,7 @@ namespace System.Data.SqlClient.SNI
/// <param name="packet">SNI packet</param>
/// <param name="callback">Completion callback</param>
/// <returns>SNI error code</returns>
- public abstract uint SendAsync(SNIPacket packet, SNIAsyncCallback callback = null);
+ public abstract uint SendAsync(SNIPacket packet, bool disposePacketAfterSendAsync, SNIAsyncCallback callback = null);
/// <summary>
/// Receive a packet synchronously
diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIMarsConnection.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIMarsConnection.cs
index b0fe68403c..a98dedfbc8 100644
--- a/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIMarsConnection.cs
+++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIMarsConnection.cs
@@ -95,7 +95,7 @@ namespace System.Data.SqlClient.SNI
{
lock (this)
{
- return _lowerHandle.SendAsync(packet, callback);
+ return _lowerHandle.SendAsync(packet, false, callback);
}
}
@@ -207,8 +207,7 @@ namespace System.Data.SqlClient.SNI
};
_dataBytesLeft = (int)_currentHeader.length;
- _currentPacket = new SNIPacket(null);
- _currentPacket.Allocate((int)_currentHeader.length);
+ _currentPacket = new SNIPacket((int)_currentHeader.length);
}
currentHeader = _currentHeader;
diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIMarsHandle.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIMarsHandle.cs
index d3f10192dc..4d079f6ad0 100644
--- a/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIMarsHandle.cs
+++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIMarsHandle.cs
@@ -100,7 +100,7 @@ namespace System.Data.SqlClient.SNI
GetSMUXHeaderBytes(0, (byte)flags, ref headerBytes);
}
- SNIPacket packet = new SNIPacket(null);
+ SNIPacket packet = new SNIPacket();
packet.SetData(headerBytes, SNISMUXHeader.HEADER_LENGTH);
_connection.Send(packet);
@@ -143,9 +143,8 @@ namespace System.Data.SqlClient.SNI
byte[] headerBytes = null;
GetSMUXHeaderBytes(packet.Length, (byte)SNISMUXFlags.SMUX_DATA, ref headerBytes);
- SNIPacket smuxPacket = new SNIPacket(null);
+ SNIPacket smuxPacket = new SNIPacket(16 + packet.Length);
smuxPacket.Description = string.Format("({0}) SMUX packet {1}", packet.Description == null ? "" : packet.Description, xSequenceNumber);
- smuxPacket.Allocate(16 + packet.Length);
smuxPacket.AppendData(headerBytes, 16);
smuxPacket.AppendPacket(packet);
@@ -257,7 +256,7 @@ namespace System.Data.SqlClient.SNI
/// <param name="packet">SNI packet</param>
/// <param name="callback">Completion callback</param>
/// <returns>SNI error code</returns>
- public override uint SendAsync(SNIPacket packet, SNIAsyncCallback callback = null)
+ public override uint SendAsync(SNIPacket packet, bool disposePacketAfterSendAsync, SNIAsyncCallback callback = null)
{
lock (this)
{
diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNINpHandle.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNINpHandle.cs
index 657518f1a1..67581e8d32 100644
--- a/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNINpHandle.cs
+++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNINpHandle.cs
@@ -22,9 +22,7 @@ namespace System.Data.SqlClient.SNI
private readonly string _targetServer;
private readonly object _callbackObject;
- private readonly TaskScheduler _writeScheduler;
- private readonly TaskFactory _writeTaskFactory;
-
+
private Stream _stream;
private NamedPipeClientStream _pipeStream;
private SslOverTdsStream _sslOverTdsStream;
@@ -41,8 +39,6 @@ namespace System.Data.SqlClient.SNI
{
_targetServer = serverName;
_callbackObject = callbackObject;
- _writeScheduler = new ConcurrentExclusiveSchedulerPair().ExclusiveScheduler;
- _writeTaskFactory = new TaskFactory(_writeScheduler);
try
{
@@ -154,8 +150,7 @@ namespace System.Data.SqlClient.SNI
packet = null;
try
{
- packet = new SNIPacket(null);
- packet.Allocate(_bufferSize);
+ packet = new SNIPacket(_bufferSize);
packet.ReadFromStream(_stream);
if (packet.Length == 0)
@@ -179,24 +174,20 @@ namespace System.Data.SqlClient.SNI
public override uint ReceiveAsync(ref SNIPacket packet)
{
- lock (this)
+ packet = new SNIPacket(_bufferSize);
+
+ try
{
- packet = new SNIPacket(null);
- packet.Allocate(_bufferSize);
-
- try
- {
- packet.ReadFromStreamAsync(_stream, _receiveCallback);
- return TdsEnums.SNI_SUCCESS_IO_PENDING;
- }
- catch (ObjectDisposedException ode)
- {
- return ReportErrorAndReleasePacket(packet, ode);
- }
- catch (IOException ioe)
- {
- return ReportErrorAndReleasePacket(packet, ioe);
- }
+ packet.ReadFromStreamAsync(_stream, _receiveCallback);
+ return TdsEnums.SNI_SUCCESS_IO_PENDING;
+ }
+ catch (ObjectDisposedException ode)
+ {
+ return ReportErrorAndReleasePacket(packet, ode);
+ }
+ catch (IOException ioe)
+ {
+ return ReportErrorAndReleasePacket(packet, ioe);
}
}
@@ -220,45 +211,10 @@ namespace System.Data.SqlClient.SNI
}
}
- public override uint SendAsync(SNIPacket packet, SNIAsyncCallback callback = null)
+ public override uint SendAsync(SNIPacket packet, bool disposePacketAfterSendAsync, SNIAsyncCallback callback = null)
{
- SNIPacket newPacket = packet;
-
- _writeTaskFactory.StartNew(() =>
- {
- try
- {
- lock (this)
- {
- packet.WriteToStream(_stream);
- }
- }
- catch (Exception e)
- {
- SNICommon.ReportSNIError(SNIProviders.NP_PROV, SNICommon.InternalExceptionError, e);
-
- if (callback != null)
- {
- callback(packet, TdsEnums.SNI_ERROR);
- }
- else
- {
- _sendCallback(packet, TdsEnums.SNI_ERROR);
- }
-
- return;
- }
-
- if (callback != null)
- {
- callback(packet, TdsEnums.SNI_SUCCESS);
- }
- else
- {
- _sendCallback(packet, TdsEnums.SNI_SUCCESS);
- }
- });
-
+ SNIAsyncCallback cb = callback ?? _sendCallback;
+ packet.WriteToStreamAsync(_stream, cb, SNIProviders.NP_PROV, disposePacketAfterSendAsync);
return TdsEnums.SNI_SUCCESS_IO_PENDING;
}
@@ -356,4 +312,4 @@ namespace System.Data.SqlClient.SNI
}
#endif
}
-} \ No newline at end of file
+}
diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIPacket.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIPacket.cs
index 44a8bc63fd..84a47740fa 100644
--- a/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIPacket.cs
+++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIPacket.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Buffers;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
@@ -20,13 +21,14 @@ namespace System.Data.SqlClient.SNI
private string _description;
private SNIAsyncCallback _completionCallback;
- /// <summary>
- /// Constructor
- /// </summary>
- /// <param name="handle">Owning SNI handle</param>
- public SNIPacket(SNIHandle handle)
+ private ArrayPool<byte> _arrayPool = ArrayPool<byte>.Shared;
+ private bool _isBufferFromArrayPool = false;
+
+ public SNIPacket() { }
+
+ public SNIPacket(int capacity)
{
- _offset = 0;
+ Allocate(capacity);
}
/// <summary>
@@ -46,46 +48,26 @@ namespace System.Data.SqlClient.SNI
}
/// <summary>
- /// Data left to process
+ /// Length of data left to process
/// </summary>
- public int DataLeft
- {
- get
- {
- return _length - _offset;
- }
- }
+ public int DataLeft => (_length - _offset);
/// <summary>
/// Length of data
/// </summary>
- public int Length
- {
- get
- {
- return _length;
- }
- }
+ public int Length => _length;
/// <summary>
/// Packet validity
/// </summary>
- public bool IsInvalid
- {
- get
- {
- return _data == null;
- }
- }
+ public bool IsInvalid => (_data == null);
/// <summary>
/// Packet data
/// </summary>
public void Dispose()
{
- _data = null;
- _length = 0;
- _capacity = 0;
+ Release();
}
/// <summary>
@@ -109,11 +91,27 @@ namespace System.Data.SqlClient.SNI
/// <summary>
/// Allocate space for data
/// </summary>
- /// <param name="capacity">Bytes to allocate</param>
+ /// <param name="capacity">Length of byte array to be allocated</param>
public void Allocate(int capacity)
{
+ if (_data != null && _data.Length < capacity)
+ {
+ if (_isBufferFromArrayPool)
+ {
+ _arrayPool.Return(_data);
+ }
+ _data = null;
+ }
+
+ if (_data == null)
+ {
+ _data = _arrayPool.Rent(capacity);
+ _isBufferFromArrayPool = true;
+ }
+
_capacity = capacity;
- _data = new Byte[capacity];
+ _length = 0;
+ _offset = 0;
}
/// <summary>
@@ -122,10 +120,11 @@ namespace System.Data.SqlClient.SNI
/// <returns>Cloned packet</returns>
public SNIPacket Clone()
{
- SNIPacket packet = new SNIPacket(null);
- packet._data = new byte[_length];
- Buffer.BlockCopy(_data, 0, packet._data, 0, _length);
+ SNIPacket packet = new SNIPacket(_capacity);
+ Buffer.BlockCopy(_data, 0, packet._data, 0, _capacity);
packet._length = _length;
+ packet._description = _description;
+ packet._completionCallback = _completionCallback;
return packet;
}
@@ -133,7 +132,7 @@ namespace System.Data.SqlClient.SNI
/// <summary>
/// Get packet data
/// </summary>
- /// <param name="inBuff">Buffer</param>
+ /// <param name="buffer">Buffer</param>
/// <param name="dataSize">Data in packet</param>
public void GetData(byte[] buffer, ref int dataSize)
{
@@ -150,8 +149,9 @@ namespace System.Data.SqlClient.SNI
{
_data = data;
_length = length;
- _capacity = length;
+ _capacity = data.Length;
_offset = 0;
+ _isBufferFromArrayPool = false;
}
/// <summary>
@@ -208,7 +208,7 @@ namespace System.Data.SqlClient.SNI
}
Buffer.BlockCopy(_data, _offset, buffer, dataOffset, size);
- _offset = _offset + size;
+ _offset += size;
return size;
}
@@ -217,9 +217,16 @@ namespace System.Data.SqlClient.SNI
/// </summary>
public void Release()
{
- _length = 0;
- _capacity = 0;
- _data = null;
+ if (_data != null)
+ {
+ if(_isBufferFromArrayPool)
+ {
+ _arrayPool.Return(_data);
+ }
+ _data = null;
+ _capacity = 0;
+ }
+ Reset();
}
/// <summary>
@@ -228,7 +235,9 @@ namespace System.Data.SqlClient.SNI
public void Reset()
{
_length = 0;
- _data = new byte[_capacity];
+ _offset = 0;
+ _description = null;
+ _completionCallback = null;
}
/// <summary>
@@ -239,10 +248,10 @@ namespace System.Data.SqlClient.SNI
public void ReadFromStreamAsync(Stream stream, SNIAsyncCallback callback)
{
bool error = false;
-
- stream.ReadAsync(_data, 0, _capacity).ContinueWith(t =>
+
+ stream.ReadAsync(_data, 0, _capacity, CancellationToken.None).ContinueWith(t =>
{
- Exception e = t.Exception != null ? t.Exception.InnerException : null;
+ Exception e = t.Exception?.InnerException;
if (e != null)
{
SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.TCP_PROV, SNICommon.InternalExceptionError, e);
@@ -261,13 +270,13 @@ namespace System.Data.SqlClient.SNI
if (error)
{
- this.Release();
+ Release();
}
callback(this, error ? TdsEnums.SNI_ERROR : TdsEnums.SNI_SUCCESS);
},
CancellationToken.None,
- TaskContinuationOptions.DenyChildAttach | TaskContinuationOptions.LongRunning,
+ TaskContinuationOptions.DenyChildAttach,
TaskScheduler.Default);
}
@@ -290,6 +299,30 @@ namespace System.Data.SqlClient.SNI
}
/// <summary>
+ /// Write data to a stream asynchronously
+ /// </summary>
+ /// <param name="stream">Stream to write to</param>
+ public async void WriteToStreamAsync(Stream stream, SNIAsyncCallback callback, SNIProviders provider, bool disposeAfterWriteAsync = false)
+ {
+ uint status = TdsEnums.SNI_SUCCESS;
+ try
+ {
+ await stream.WriteAsync(_data, 0, _length, CancellationToken.None).ConfigureAwait(false);
+ }
+ catch (Exception e)
+ {
+ SNILoadHandle.SingletonInstance.LastError = new SNIError(provider, SNICommon.InternalExceptionError, e);
+ status = TdsEnums.SNI_ERROR;
+ }
+ callback(this, status);
+
+ if (disposeAfterWriteAsync)
+ {
+ Dispose();
+ }
+ }
+
+ /// <summary>
/// Get hash code
/// </summary>
/// <returns>Hash code</returns>
@@ -324,7 +357,7 @@ namespace System.Data.SqlClient.SNI
{
if (packet != null)
{
- return object.ReferenceEquals(packet, this);
+ return ReferenceEquals(packet, this);
}
return false;
diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIProxy.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIProxy.cs
index a93ff8a044..e0cd0a3dec 100644
--- a/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIProxy.cs
+++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIProxy.cs
@@ -189,11 +189,11 @@ namespace System.Data.SqlClient.SNI
}
/// <summary>
- /// Get packet data
+ /// Copies data in SNIPacket to given byte array parameter
/// </summary>
- /// <param name="packet">SNI packet</param>
- /// <param name="inBuff">Buffer</param>
- /// <param name="dataSize">Data size</param>
+ /// <param name="packet">SNIPacket object containing data packets</param>
+ /// <param name="inBuff">Destination byte array where data packets are copied to</param>
+ /// <param name="dataSize">Length of data packets</param>
/// <returns>SNI error status</returns>
public uint PacketGetData(SNIPacket packet, byte[] inBuff, ref uint dataSize)
{
@@ -238,14 +238,19 @@ namespace System.Data.SqlClient.SNI
/// <returns>SNI error status</returns>
public uint WritePacket(SNIHandle handle, SNIPacket packet, bool sync)
{
+ SNIPacket clonedPacket = packet.Clone();
+ uint result;
if (sync)
{
- return handle.Send(packet.Clone());
+ result = handle.Send(clonedPacket);
+ clonedPacket.Dispose();
}
else
{
- return handle.SendAsync(packet.Clone());
+ result = handle.SendAsync(clonedPacket, true);
}
+
+ return result;
}
/// <summary>
@@ -339,8 +344,22 @@ namespace System.Data.SqlClient.SNI
private static byte[] GetSqlServerSPN(string hostNameOrAddress, string portOrInstanceName)
{
Debug.Assert(!string.IsNullOrWhiteSpace(hostNameOrAddress));
- IPHostEntry hostEntry = Dns.GetHostEntry(hostNameOrAddress);
- string fullyQualifiedDomainName = hostEntry.HostName;
+ IPHostEntry hostEntry = null;
+ string fullyQualifiedDomainName;
+ try
+ {
+ hostEntry = Dns.GetHostEntry(hostNameOrAddress);
+ }
+ catch (SocketException)
+ {
+ // A SocketException can occur while resolving the hostname.
+ // We will fallback on using hostname from the connection string in the finally block
+ }
+ finally
+ {
+ // If the DNS lookup failed, then resort to using the user provided hostname to construct the SPN.
+ fullyQualifiedDomainName = hostEntry?.HostName ?? hostNameOrAddress;
+ }
string serverSpn = SqlServerSpnHeader + "/" + fullyQualifiedDomainName;
if (!string.IsNullOrWhiteSpace(portOrInstanceName))
{
@@ -426,8 +445,7 @@ namespace System.Data.SqlClient.SNI
/// <returns>SNI error status</returns>
public uint ReadAsync(SNIHandle handle, out SNIPacket packet)
{
- packet = new SNIPacket(null);
-
+ packet = null;
return handle.ReceiveAsync(ref packet);
}
diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNITcpHandle.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNITcpHandle.cs
index 47613bf014..11ea8d0eaf 100644
--- a/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNITcpHandle.cs
+++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNITcpHandle.cs
@@ -4,13 +4,11 @@
using System.Collections.Generic;
using System.ComponentModel;
-using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
@@ -27,9 +25,7 @@ namespace System.Data.SqlClient.SNI
private readonly object _callbackObject;
private readonly Socket _socket;
private NetworkStream _tcpStream;
- private readonly TaskScheduler _writeScheduler;
- private readonly TaskFactory _writeTaskFactory;
-
+
private Stream _stream;
private SslStream _sslStream;
private SslOverTdsStream _sslOverTdsStream;
@@ -104,8 +100,6 @@ namespace System.Data.SqlClient.SNI
/// <param name="callbackObject">Callback object</param>
public SNITCPHandle(string serverName, int port, long timerExpire, object callbackObject, bool parallel)
{
- _writeScheduler = new ConcurrentExclusiveSchedulerPair().ExclusiveScheduler;
- _writeTaskFactory = new TaskFactory(_writeScheduler);
_callbackObject = callbackObject;
_targetServer = serverName;
@@ -399,7 +393,6 @@ namespace System.Data.SqlClient.SNI
_sslStream = null;
_sslOverTdsStream.Dispose();
_sslOverTdsStream = null;
-
_stream = _tcpStream;
}
@@ -487,8 +480,7 @@ namespace System.Data.SqlClient.SNI
return TdsEnums.SNI_WAIT_TIMEOUT;
}
- packet = new SNIPacket(null);
- packet.Allocate(_bufferSize);
+ packet = new SNIPacket(_bufferSize);
packet.ReadFromStream(_stream);
if (packet.Length == 0)
@@ -542,45 +534,13 @@ namespace System.Data.SqlClient.SNI
/// <param name="packet">SNI packet</param>
/// <param name="callback">Completion callback</param>
/// <returns>SNI error code</returns>
- public override uint SendAsync(SNIPacket packet, SNIAsyncCallback callback = null)
+ public override uint SendAsync(SNIPacket packet, bool disposePacketAfterSendAsync, SNIAsyncCallback callback = null)
{
- SNIPacket newPacket = packet;
-
- _writeTaskFactory.StartNew(() =>
+ SNIAsyncCallback cb = callback ?? _sendCallback;
+ lock (this)
{
- try
- {
- lock (this)
- {
- packet.WriteToStream(_stream);
- }
- }
- catch (Exception e)
- {
- SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.TCP_PROV, SNICommon.InternalExceptionError, e);
-
- if (callback != null)
- {
- callback(packet, TdsEnums.SNI_ERROR);
- }
- else
- {
- _sendCallback(packet, TdsEnums.SNI_ERROR);
- }
-
- return;
- }
-
- if (callback != null)
- {
- callback(packet, TdsEnums.SNI_SUCCESS);
- }
- else
- {
- _sendCallback(packet, TdsEnums.SNI_SUCCESS);
- }
- });
-
+ packet.WriteToStreamAsync(_stream, cb, SNIProviders.TCP_PROV, disposePacketAfterSendAsync);
+ }
return TdsEnums.SNI_SUCCESS_IO_PENDING;
}
@@ -591,28 +551,16 @@ namespace System.Data.SqlClient.SNI
/// <returns>SNI error code</returns>
public override uint ReceiveAsync(ref SNIPacket packet)
{
- lock (this)
- {
- packet = new SNIPacket(null);
- packet.Allocate(_bufferSize);
+ packet = new SNIPacket(_bufferSize);
- try
- {
- packet.ReadFromStreamAsync(_stream, _receiveCallback);
- return TdsEnums.SNI_SUCCESS_IO_PENDING;
- }
- catch (ObjectDisposedException ode)
- {
- return ReportErrorAndReleasePacket(packet, ode);
- }
- catch (SocketException se)
- {
- return ReportErrorAndReleasePacket(packet, se);
- }
- catch (IOException ioe)
- {
- return ReportErrorAndReleasePacket(packet, ioe);
- }
+ try
+ {
+ packet.ReadFromStreamAsync(_stream, _receiveCallback);
+ return TdsEnums.SNI_SUCCESS_IO_PENDING;
+ }
+ catch (Exception e) when (e is ObjectDisposedException || e is SocketException || e is IOException)
+ {
+ return ReportErrorAndReleasePacket(packet, e);
}
}
@@ -680,6 +628,6 @@ namespace System.Data.SqlClient.SNI
{
_socket.Shutdown(SocketShutdown.Both);
}
-#endif
+#endif
}
}
diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SslOverTdsStream.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SslOverTdsStream.cs
index 4d9d9c72e1..cb274689ff 100644
--- a/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SslOverTdsStream.cs
+++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SslOverTdsStream.cs
@@ -4,6 +4,8 @@
using System.IO;
using System.IO.Pipes;
+using System.Threading;
+using System.Threading.Tasks;
namespace System.Data.SqlClient.SNI
{
@@ -47,7 +49,44 @@ namespace System.Data.SqlClient.SNI
/// <param name="offset">Offset</param>
/// <param name="count">Byte count</param>
/// <returns>Bytes read</returns>
- public override int Read(byte[] buffer, int offset, int count)
+ public override int Read(byte[] buffer, int offset, int count) =>
+ ReadInternal(buffer, offset, count, CancellationToken.None, async: false).GetAwaiter().GetResult();
+
+ /// <summary>
+ /// Write Buffer
+ /// </summary>
+ /// <param name="buffer"></param>
+ /// <param name="offset"></param>
+ /// <param name="count"></param>
+ public override void Write(byte[] buffer, int offset, int count)
+ => WriteInternal(buffer, offset, count, CancellationToken.None, async: false).Wait();
+
+ /// <summary>
+ /// Write Buffer Asynchronosly
+ /// </summary>
+ /// <param name="buffer"></param>
+ /// <param name="offset"></param>
+ /// <param name="count"></param>
+ /// <param name="token"></param>
+ /// <returns></returns>
+ public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken token)
+ => WriteInternal(buffer, offset, count, token, async: true);
+
+ /// <summary>
+ /// Read Buffer Asynchronosly
+ /// </summary>
+ /// <param name="buffer"></param>
+ /// <param name="offset"></param>
+ /// <param name="count"></param>
+ /// <param name="token"></param>
+ /// <returns></returns>
+ public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken token)
+ => ReadInternal(buffer, offset, count, token, async: true);
+
+ /// <summary>
+ /// Read Internal is called synchronosly when async is false
+ /// </summary>
+ private async Task<int> ReadInternal(byte[] buffer, int offset, int count, CancellationToken token, bool async)
{
int readBytes = 0;
byte[] packetData = new byte[count < TdsEnums.HEADER_LEN ? TdsEnums.HEADER_LEN : count];
@@ -59,7 +98,9 @@ namespace System.Data.SqlClient.SNI
// Account for split packets
while (readBytes < TdsEnums.HEADER_LEN)
{
- readBytes += _stream.Read(packetData, readBytes, TdsEnums.HEADER_LEN - readBytes);
+ readBytes += async ?
+ await _stream.ReadAsync(packetData, readBytes, TdsEnums.HEADER_LEN - readBytes, token).ConfigureAwait(false) :
+ _stream.Read(packetData, readBytes, TdsEnums.HEADER_LEN - readBytes);
}
_packetBytes = (packetData[TdsEnums.HEADER_LEN_FIELD_OFFSET] << 8) | packetData[TdsEnums.HEADER_LEN_FIELD_OFFSET + 1];
@@ -72,7 +113,9 @@ namespace System.Data.SqlClient.SNI
}
}
- readBytes = _stream.Read(packetData, 0, count);
+ readBytes = async ?
+ await _stream.ReadAsync(packetData, 0, count, token).ConfigureAwait(false) :
+ _stream.Read(packetData, 0, count);
if (_encapsulate)
{
@@ -84,12 +127,9 @@ namespace System.Data.SqlClient.SNI
}
/// <summary>
- /// Write buffer
+ /// The internal write method calls Sync APIs when Async flag is false
/// </summary>
- /// <param name="buffer">Buffer</param>
- /// <param name="offset">Offset</param>
- /// <param name="count">Byte count</param>
- public override void Write(byte[] buffer, int offset, int count)
+ private async Task WriteInternal(byte[] buffer, int offset, int count, CancellationToken token, bool async)
{
int currentCount = 0;
int currentOffset = offset;
@@ -127,22 +167,44 @@ namespace System.Data.SqlClient.SNI
combinedBuffer[6] = 0;
combinedBuffer[7] = 0;
- for(int i = TdsEnums.HEADER_LEN; i < combinedBuffer.Length; i++)
+ for (int i = TdsEnums.HEADER_LEN; i < combinedBuffer.Length; i++)
{
combinedBuffer[i] = buffer[currentOffset + (i - TdsEnums.HEADER_LEN)];
}
- _stream.Write(combinedBuffer, 0, combinedBuffer.Length);
+ if (async)
+ {
+ await _stream.WriteAsync(combinedBuffer, 0, combinedBuffer.Length, token).ConfigureAwait(false);
+ }
+ else
+ {
+ _stream.Write(combinedBuffer, 0, combinedBuffer.Length);
+ }
}
else
{
currentCount = count;
count = 0;
- _stream.Write(buffer, currentOffset, currentCount);
+ if (async)
+ {
+ await _stream.WriteAsync(buffer, currentOffset, currentCount, token).ConfigureAwait(false);
+ }
+ else
+ {
+ _stream.Write(buffer, currentOffset, currentCount);
+ }
+ }
+
+ if (async)
+ {
+ await _stream.FlushAsync().ConfigureAwait(false);
+ }
+ else
+ {
+ _stream.Flush();
}
- _stream.Flush();
currentOffset += currentCount;
}
}
diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlBulkCopy.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlBulkCopy.cs
index e1d89c9d2a..09a61eaf52 100644
--- a/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlBulkCopy.cs
+++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlBulkCopy.cs
@@ -1871,16 +1871,22 @@ namespace System.Data.SqlClient
finishedSynchronously = false;
return resultTask.ContinueWith((t) =>
{
- AbortTransaction(); // If there is one, on success transactions will be committed.
- _isBulkCopyingInProgress = false;
- if (_parser != null)
+ try
{
- _parser._asyncWrite = false;
+ AbortTransaction(); // If there is one, on success transactions will be committed.
}
- if (_parserLock != null)
+ finally
{
- _parserLock.Release();
- _parserLock = null;
+ _isBulkCopyingInProgress = false;
+ if (_parser != null)
+ {
+ _parser._asyncWrite = false;
+ }
+ if (_parserLock != null)
+ {
+ _parserLock.Release();
+ _parserLock = null;
+ }
}
return t;
}, TaskScheduler.Default).Unwrap();
@@ -1907,16 +1913,22 @@ namespace System.Data.SqlClient
_columnMappings.ReadOnly = false;
if (finishedSynchronously)
{
- AbortTransaction(); // If there is one, on success transactions will be committed.
- _isBulkCopyingInProgress = false;
- if (_parser != null)
+ try
{
- _parser._asyncWrite = false;
+ AbortTransaction(); // If there is one, on success transactions will be committed.
}
- if (_parserLock != null)
+ finally
{
- _parserLock.Release();
- _parserLock = null;
+ _isBulkCopyingInProgress = false;
+ if (_parser != null)
+ {
+ _parser._asyncWrite = false;
+ }
+ if (_parserLock != null)
+ {
+ _parserLock.Release();
+ _parserLock = null;
+ }
}
}
}
diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlCommand.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlCommand.cs
index eb3ea56a8b..40a20092f6 100644
--- a/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlCommand.cs
+++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlCommand.cs
@@ -1222,6 +1222,12 @@ namespace System.Data.SqlClient
}
}
+
+ public IAsyncResult BeginExecuteXmlReader()
+ {
+ return BeginExecuteXmlReader(null, null);
+ }
+
public IAsyncResult BeginExecuteXmlReader(AsyncCallback callback, object stateObject)
{
// Reset _pendingCancel upon entry into any Execute - used to synchronize state
diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlConnection.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlConnection.cs
index b2c20ecf28..cde4bb707a 100644
--- a/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlConnection.cs
+++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlConnection.cs
@@ -14,6 +14,7 @@ using Microsoft.SqlServer.Server;
using System.Reflection;
using System.IO;
using System.Globalization;
+using System.Security;
namespace System.Data.SqlClient
{
@@ -30,6 +31,7 @@ namespace System.Data.SqlClient
// root task associated with current async invocation
private Tuple<TaskCompletionSource<DbConnectionInternal>, Task> _currentCompletion;
+ private SqlCredential _credential;
private string _connectionString;
private int _connectRetryCount;
@@ -57,11 +59,43 @@ namespace System.Data.SqlClient
CacheConnectionStringProperties();
}
+ public SqlConnection(string connectionString, SqlCredential credential) : this()
+ {
+ ConnectionString = connectionString;
+ if (credential != null)
+ {
+ // The following checks are necessary as setting Credential property will call CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential
+ // CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential it will throw InvalidOperationException rather than Arguemtn exception
+ // Need to call setter on Credential property rather than setting _credential directly as pool groups need to be checked
+ SqlConnectionString connectionOptions = (SqlConnectionString)ConnectionOptions;
+ if (UsesClearUserIdOrPassword(connectionOptions))
+ {
+ throw ADP.InvalidMixedArgumentOfSecureAndClearCredential();
+ }
+
+ if (UsesIntegratedSecurity(connectionOptions))
+ {
+ throw ADP.InvalidMixedArgumentOfSecureCredentialAndIntegratedSecurity();
+ }
+ Credential = credential;
+ }
+ // else
+ // credential == null: we should not set "Credential" as this will do additional validation check and
+ // checking pool groups which is not necessary. All necessary operation is already done by calling "ConnectionString = connectionString"
+ CacheConnectionStringProperties();
+ }
+
private SqlConnection(SqlConnection connection)
{
GC.SuppressFinalize(this);
CopyFrom(connection);
_connectionString = connection._connectionString;
+ if (connection._credential != null)
+ {
+ SecureString password = connection._credential.Password.Copy();
+ password.MakeReadOnly();
+ _credential = new SqlCredential(connection._credential.UserId, password);
+ }
CacheConnectionStringProperties();
}
@@ -143,6 +177,23 @@ namespace System.Data.SqlClient
set => _AsyncCommandInProgress = value;
}
+ // Does this connection use Integrated Security?
+ private bool UsesIntegratedSecurity(SqlConnectionString opt)
+ {
+ return opt != null ? opt.IntegratedSecurity : false;
+ }
+
+ // Does this connection use old style of clear userID or Password in connection string?
+ private bool UsesClearUserIdOrPassword(SqlConnectionString opt)
+ {
+ bool result = false;
+ if (null != opt)
+ {
+ result = (!string.IsNullOrEmpty(opt.UserID) || !string.IsNullOrEmpty(opt.Password));
+ }
+ return result;
+ }
+
internal SqlConnectionString.TransactionBindingEnum TransactionBinding
{
get => ((SqlConnectionString)ConnectionOptions).TransactionBinding;
@@ -171,7 +222,12 @@ namespace System.Data.SqlClient
}
set
{
- ConnectionString_Set(new SqlConnectionPoolKey(value));
+ if (_credential != null)
+ {
+ SqlConnectionString connectionOptions = new SqlConnectionString(value);
+ CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential(connectionOptions);
+ }
+ ConnectionString_Set(new SqlConnectionPoolKey(value, _credential));
_connectionString = value; // Change _connectionString value only after value is validated
CacheConnectionStringProperties();
}
@@ -306,11 +362,66 @@ namespace System.Data.SqlClient
// Note: In Longhorn you'll be able to rename a machine without
// rebooting. Therefore, don't cache this machine name.
SqlConnectionString constr = (SqlConnectionString)ConnectionOptions;
- string result = ((null != constr) ? constr.WorkstationId : string.Empty);
+ string result = constr?.WorkstationId ?? Environment.MachineName;
return result;
}
}
+ public SqlCredential Credential
+ {
+ get
+ {
+ SqlCredential result = _credential;
+
+ // When a connection is connecting or is ever opened, make credential available only if "Persist Security Info" is set to true
+ // otherwise, return null
+ SqlConnectionString connectionOptions = (SqlConnectionString)UserConnectionOptions;
+ if (InnerConnection.ShouldHidePassword && connectionOptions != null && !connectionOptions.PersistSecurityInfo)
+ {
+ result = null;
+ }
+
+ return result;
+ }
+
+ set
+ {
+ // If a connection is connecting or is ever opened, user id/password cannot be set
+ if (!InnerConnection.AllowSetConnectionString)
+ {
+ throw ADP.OpenConnectionPropertySet(nameof(Credential), InnerConnection.State);
+ }
+
+ // check if the usage of credential has any conflict with the keys used in connection string
+ if (value != null)
+ {
+ CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential((SqlConnectionString)ConnectionOptions);
+ }
+
+ _credential = value;
+
+ // Need to call ConnectionString_Set to do proper pool group check
+ ConnectionString_Set(new SqlConnectionPoolKey(_connectionString, _credential));
+ }
+ }
+
+ // CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential: check if the usage of credential has any conflict
+ // with the keys used in connection string
+ // If there is any conflict, it throws InvalidOperationException
+ // This is used in the setter of ConnectionString and Credential properties.
+ private void CheckAndThrowOnInvalidCombinationOfConnectionStringAndSqlCredential(SqlConnectionString connectionOptions)
+ {
+ if (UsesClearUserIdOrPassword(connectionOptions))
+ {
+ throw ADP.InvalidMixedUsageOfSecureAndClearCredential();
+ }
+
+ if (UsesIntegratedSecurity(connectionOptions))
+ {
+ throw ADP.InvalidMixedUsageOfSecureCredentialAndIntegratedSecurity();
+ }
+ }
+
protected override DbProviderFactory DbProviderFactory
{
get => SqlClientFactory.Instance;
@@ -542,6 +653,8 @@ namespace System.Data.SqlClient
private void DisposeMe(bool disposing)
{
+ _credential = null;
+
if (!disposing)
{
// For non-pooled connections we need to make sure that if the SqlConnection was not closed,
@@ -1231,6 +1344,108 @@ namespace System.Data.SqlClient
}
}
+
+ public static void ChangePassword(string connectionString, string newPassword)
+ {
+ if (string.IsNullOrEmpty(connectionString))
+ {
+ throw SQL.ChangePasswordArgumentMissing(nameof(newPassword));
+ }
+ if (string.IsNullOrEmpty(newPassword))
+ {
+ throw SQL.ChangePasswordArgumentMissing(nameof(newPassword));
+ }
+ if (TdsEnums.MAXLEN_NEWPASSWORD < newPassword.Length)
+ {
+ throw ADP.InvalidArgumentLength(nameof(newPassword), TdsEnums.MAXLEN_NEWPASSWORD);
+ }
+
+ SqlConnectionPoolKey key = new SqlConnectionPoolKey(connectionString, credential: null);
+
+ SqlConnectionString connectionOptions = SqlConnectionFactory.FindSqlConnectionOptions(key);
+ if (connectionOptions.IntegratedSecurity)
+ {
+ throw SQL.ChangePasswordConflictsWithSSPI();
+ }
+ if (!string.IsNullOrEmpty(connectionOptions.AttachDBFilename))
+ {
+ throw SQL.ChangePasswordUseOfUnallowedKey(SqlConnectionString.KEY.AttachDBFilename);
+ }
+
+ ChangePassword(connectionString, connectionOptions, null, newPassword, null);
+ }
+
+ public static void ChangePassword(string connectionString, SqlCredential credential, SecureString newSecurePassword)
+ {
+ if (string.IsNullOrEmpty(connectionString))
+ {
+ throw SQL.ChangePasswordArgumentMissing(nameof(connectionString));
+ }
+
+ // check credential; not necessary to check the length of password in credential as the check is done by SqlCredential class
+ if (credential == null)
+ {
+ throw SQL.ChangePasswordArgumentMissing(nameof(credential));
+ }
+
+ if (newSecurePassword == null || newSecurePassword.Length == 0)
+ {
+ throw SQL.ChangePasswordArgumentMissing(nameof(newSecurePassword));
+ }
+
+ if (!newSecurePassword.IsReadOnly())
+ {
+ throw ADP.MustBeReadOnly(nameof(newSecurePassword));
+ }
+
+ if (TdsEnums.MAXLEN_NEWPASSWORD < newSecurePassword.Length)
+ {
+ throw ADP.InvalidArgumentLength(nameof(newSecurePassword), TdsEnums.MAXLEN_NEWPASSWORD);
+ }
+
+ SqlConnectionPoolKey key = new SqlConnectionPoolKey(connectionString, credential);
+
+ SqlConnectionString connectionOptions = SqlConnectionFactory.FindSqlConnectionOptions(key);
+
+ // Check for connection string values incompatible with SqlCredential
+ if (!string.IsNullOrEmpty(connectionOptions.UserID) || !string.IsNullOrEmpty(connectionOptions.Password))
+ {
+ throw ADP.InvalidMixedArgumentOfSecureAndClearCredential();
+ }
+
+ if (connectionOptions.IntegratedSecurity)
+ {
+ throw SQL.ChangePasswordConflictsWithSSPI();
+ }
+
+ if (!string.IsNullOrEmpty(connectionOptions.AttachDBFilename))
+ {
+ throw SQL.ChangePasswordUseOfUnallowedKey(SqlConnectionString.KEY.AttachDBFilename);
+ }
+
+ ChangePassword(connectionString, connectionOptions, credential, null, newSecurePassword);
+ }
+
+ private static void ChangePassword(string connectionString, SqlConnectionString connectionOptions, SqlCredential credential, string newPassword, SecureString newSecurePassword)
+ {
+ // note: This is the only case where we directly construct the internal connection, passing in the new password.
+ // Normally we would simply create a regular connection and open it, but there is no other way to pass the
+ // new password down to the constructor. This would have an unwanted impact on the connection pool.
+ SqlInternalConnectionTds con = null;
+ try
+ {
+ con = new SqlInternalConnectionTds(null, connectionOptions, credential, null, newPassword, newSecurePassword, false);
+ }
+ finally
+ {
+ if (con != null)
+ con.Dispose();
+ }
+ SqlConnectionPoolKey key = new SqlConnectionPoolKey(connectionString, credential);
+
+ SqlConnectionFactory.SingletonInstance.ClearPool(key);
+ }
+
//
// SQL DEBUGGING SUPPORT
//
diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlConnectionFactory.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlConnectionFactory.cs
index d99413f48f..4f82668bf7 100644
--- a/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlConnectionFactory.cs
+++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlConnectionFactory.cs
@@ -95,7 +95,7 @@ namespace System.Data.SqlClient
// This first connection is established to SqlExpress to get the instance name
// of the UserInstance.
SqlConnectionString sseopt = new SqlConnectionString(opt, opt.DataSource, userInstance: true, setEnlistValue: false);
- sseConnection = new SqlInternalConnectionTds(identity, sseopt, null, false, applyTransientFaultHandling: applyTransientFaultHandling);
+ sseConnection = new SqlInternalConnectionTds(identity, sseopt, key.Credential, null, "", null, false, applyTransientFaultHandling: applyTransientFaultHandling);
// NOTE: Retrieve <UserInstanceName> here. This user instance name will be used below to connect to the Sql Express User Instance.
instanceName = sseConnection.InstanceName;
@@ -132,7 +132,7 @@ namespace System.Data.SqlClient
opt = new SqlConnectionString(opt, instanceName, userInstance: false, setEnlistValue: null);
poolGroupProviderInfo = null; // null so we do not pass to constructor below...
}
- result = new SqlInternalConnectionTds(identity, opt, poolGroupProviderInfo, redirectedUserInstance, userOpt, recoverySessionData, applyTransientFaultHandling: applyTransientFaultHandling);
+ result = new SqlInternalConnectionTds(identity, opt, key.Credential, poolGroupProviderInfo, "", null, redirectedUserInstance, userOpt, recoverySessionData, applyTransientFaultHandling: applyTransientFaultHandling);
return result;
}
diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlConnectionPoolKey.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlConnectionPoolKey.cs
index 6f1eda32b6..17b542e28f 100644
--- a/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlConnectionPoolKey.cs
+++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlConnectionPoolKey.cs
@@ -15,14 +15,17 @@ namespace System.Data.SqlClient
internal class SqlConnectionPoolKey : DbConnectionPoolKey
{
private int _hashValue;
+ private SqlCredential _credential;
- internal SqlConnectionPoolKey(string connectionString) : base(connectionString)
+ internal SqlConnectionPoolKey(string connectionString, SqlCredential credential) : base(connectionString)
{
+ _credential = credential;
CalculateHashCode();
}
private SqlConnectionPoolKey(SqlConnectionPoolKey key) : base(key)
{
+ _credential = key.Credential;
CalculateHashCode();
}
@@ -45,13 +48,14 @@ namespace System.Data.SqlClient
}
}
-
+ internal SqlCredential Credential => _credential;
public override bool Equals(object obj)
{
SqlConnectionPoolKey key = obj as SqlConnectionPoolKey;
return (key != null &&
- ConnectionString == key.ConnectionString);
+ ConnectionString == key.ConnectionString &&
+ Credential == key.Credential);
}
public override int GetHashCode()
@@ -62,6 +66,14 @@ namespace System.Data.SqlClient
private void CalculateHashCode()
{
_hashValue = base.GetHashCode();
+
+ if (_credential != null)
+ {
+ unchecked
+ {
+ _hashValue = _hashValue * 17 + _credential.GetHashCode();
+ }
+ }
}
}
}
diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlCredential.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlCredential.cs
new file mode 100644
index 0000000000..2f69e23937
--- /dev/null
+++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlCredential.cs
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Data.Common;
+using System.Security;
+
+namespace System.Data.SqlClient
+{
+ public sealed class SqlCredential
+ {
+ string _userId;
+ SecureString _password;
+
+ public SqlCredential(string userId, SecureString password)
+ {
+ if (userId == null)
+ {
+ throw ADP.ArgumentNull(nameof(userId));
+ }
+
+ if (userId.Length > TdsEnums.MAXLEN_USERNAME)
+ {
+ throw ADP.InvalidArgumentLength(nameof(userId), TdsEnums.MAXLEN_USERNAME);
+ }
+
+ if (password == null)
+ {
+ throw ADP.ArgumentNull(nameof(password));
+ }
+
+ if (password.Length > TdsEnums.MAXLEN_PASSWORD)
+ {
+ throw ADP.InvalidArgumentLength(nameof(password), TdsEnums.MAXLEN_PASSWORD);
+ }
+
+ if (!password.IsReadOnly())
+ {
+ throw ADP.MustBeReadOnly(nameof(password));
+ }
+
+ _userId = userId;
+ _password = password;
+ }
+
+ public string UserId => _userId;
+
+ public SecureString Password => _password;
+
+ }
+}
diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlDependencyListener.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlDependencyListener.cs
index ce30233356..682f1e0748 100644
--- a/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlDependencyListener.cs
+++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlDependencyListener.cs
@@ -612,7 +612,12 @@ internal class SqlDependencyProcessDispatcher : MarshalByRefObject
_timeoutParam.Value = _defaultWaitforTimeout; // If success, reset to default for re-queue.
AsynchronouslyQueryServiceBrokerQueue();
_errorState = false;
- _retryTimer = null;
+ Timer retryTimer = _retryTimer;
+ if (retryTimer != null)
+ {
+ _retryTimer = null;
+ retryTimer.Dispose();
+ }
}
}
@@ -1470,4 +1475,4 @@ internal class SqlDependencyProcessDispatcher : MarshalByRefObject
return stopped;
}
-} \ No newline at end of file
+}
diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlDependencyUtils.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlDependencyUtils.cs
index a2b2ffffef..5f5663c298 100644
--- a/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlDependencyUtils.cs
+++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlDependencyUtils.cs
@@ -80,7 +80,11 @@ namespace System.Data.SqlClient
_notificationIdToDependenciesHash = new Dictionary<string, DependencyList>();
_commandHashToNotificationId = new Dictionary<string, string>();
- _timeoutTimer = new Timer(new TimerCallback(TimeoutTimerCallback), null, Timeout.Infinite, Timeout.Infinite);
+ _timeoutTimer = ADP.UnsafeCreateTimer(
+ new TimerCallback(TimeoutTimerCallback),
+ null,
+ Timeout.Infinite,
+ Timeout.Infinite);
SubscribeToAppDomainUnload();
}
diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlInternalConnectionTds.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlInternalConnectionTds.cs
index f5c03bb81c..f75a1a28c6 100644
--- a/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlInternalConnectionTds.cs
+++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlInternalConnectionTds.cs
@@ -15,6 +15,7 @@ using System.Threading;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using System.Transactions;
+using System.Security;
namespace System.Data.SqlClient
{
@@ -104,6 +105,7 @@ namespace System.Data.SqlClient
private readonly SqlConnectionPoolGroupProviderInfo _poolGroupProviderInfo; // will only be null when called for ChangePassword, or creating SSE User Instance
private TdsParser _parser;
private SqlLoginAck _loginAck;
+ private SqlCredential _credential;
// Connection Resiliency
private bool _sessionRecoveryRequested;
@@ -301,7 +303,10 @@ namespace System.Data.SqlClient
internal SqlInternalConnectionTds(
DbConnectionPoolIdentity identity,
SqlConnectionString connectionOptions,
+ SqlCredential credential,
object providerInfo,
+ string newPassword,
+ SecureString newSecurePassword,
bool redirectedUserInstance,
SqlConnectionString userConnectionOptions = null, // NOTE: userConnectionOptions may be different to connectionOptions if the connection string has been expanded (see SqlConnectionString.Expand)
SessionData reconnectSessionData = null,
@@ -332,6 +337,10 @@ namespace System.Data.SqlClient
_identity = identity;
+ Debug.Assert(newSecurePassword != null || newPassword != null, "cannot have both new secure change password and string based change password to be null");
+ Debug.Assert(credential == null || (string.IsNullOrEmpty(connectionOptions.UserID) && string.IsNullOrEmpty(connectionOptions.Password)), "cannot mix the new secure password system and the connection string based password");
+
+ Debug.Assert(credential == null || !connectionOptions.IntegratedSecurity, "Cannot use SqlCredential and Integrated Security");
_poolGroupProviderInfo = (SqlConnectionPoolGroupProviderInfo)providerInfo;
_fResetConnection = connectionOptions.ConnectionReset;
@@ -342,6 +351,7 @@ namespace System.Data.SqlClient
}
_timeoutErrorInternal = new SqlConnectionTimeoutErrorInternal();
+ _credential = credential;
_parserLock.Wait(canReleaseFromAnyThread: false);
ThreadHasParserLockForClose = true; // In case of error, let ourselves know that we already own the parser lock
@@ -356,7 +366,8 @@ namespace System.Data.SqlClient
{
try
{
- OpenLoginEnlist(timeout, connectionOptions, redirectedUserInstance);
+ OpenLoginEnlist(timeout, connectionOptions, credential, newPassword, newSecurePassword, redirectedUserInstance);
+
break;
}
catch (SqlException sqlex)
@@ -1053,7 +1064,7 @@ namespace System.Data.SqlClient
_parser._physicalStateObj.SniContext = SniContext.Snix_Login;
}
- private void Login(ServerInfo server, TimeoutTimer timeout)
+ private void Login(ServerInfo server, TimeoutTimer timeout, string newPassword, SecureString newSecurePassword)
{
// create a new login record
SqlLogin login = new SqlLogin();
@@ -1099,7 +1110,13 @@ namespace System.Data.SqlClient
login.useReplication = ConnectionOptions.Replication;
login.useSSPI = ConnectionOptions.IntegratedSecurity;
login.packetSize = _currentPacketSize;
+ login.newPassword = newPassword;
login.readOnlyIntent = ConnectionOptions.ApplicationIntent == ApplicationIntent.ReadOnly;
+ login.credential = _credential;
+ if (newSecurePassword != null)
+ {
+ login.newSecurePassword = newSecurePassword;
+ }
TdsEnums.FeatureExtension requestedFeatures = TdsEnums.FeatureExtension.None;
if (ConnectionOptions.ConnectRetryCount > 0)
@@ -1127,6 +1144,9 @@ namespace System.Data.SqlClient
private void OpenLoginEnlist(TimeoutTimer timeout,
SqlConnectionString connectionOptions,
+ SqlCredential credential,
+ string newPassword,
+ SecureString newSecurePassword,
bool redirectedUserInstance)
{
bool useFailoverPartner; // should we use primary or secondary first
@@ -1160,8 +1180,11 @@ namespace System.Data.SqlClient
useFailoverPartner,
dataSource,
failoverPartner,
+ newPassword,
+ newSecurePassword,
redirectedUserInstance,
connectionOptions,
+ credential,
timeout);
}
else
@@ -1169,8 +1192,11 @@ namespace System.Data.SqlClient
_timeoutErrorInternal.SetFailoverScenario(false); // not a failover scenario
LoginNoFailover(
dataSource,
+ newPassword,
+ newSecurePassword,
redirectedUserInstance,
connectionOptions,
+ credential,
timeout);
}
_timeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.PostLogin);
@@ -1210,9 +1236,12 @@ namespace System.Data.SqlClient
// Changes to either one should be examined to see if they need to be reflected in the other
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
private void LoginNoFailover(ServerInfo serverInfo,
- bool redirectedUserInstance,
- SqlConnectionString connectionOptions,
- TimeoutTimer timeout)
+ string newPassword,
+ SecureString newSecurePassword,
+ bool redirectedUserInstance,
+ SqlConnectionString connectionOptions,
+ SqlCredential credential,
+ TimeoutTimer timeout)
{
Debug.Assert(object.ReferenceEquals(connectionOptions, this.ConnectionOptions), "ConnectionOptions argument and property must be the same"); // consider removing the argument
int routingAttempts = 0;
@@ -1273,8 +1302,10 @@ namespace System.Data.SqlClient
try
{
AttemptOneLogin(serverInfo,
+ newPassword,
+ newSecurePassword,
!connectionOptions.MultiSubnetFailover, // ignore timeout for SniOpen call unless MSF
- connectionOptions.MultiSubnetFailover ? intervalTimer : timeout);
+ connectionOptions.MultiSubnetFailover ? intervalTimer : timeout);
if (connectionOptions.MultiSubnetFailover && null != ServerProvidedFailOverPartner)
{
@@ -1353,9 +1384,12 @@ namespace System.Data.SqlClient
true, // start by using failover partner, since we already failed to connect to the primary
serverInfo,
ServerProvidedFailOverPartner,
- redirectedUserInstance,
+ newPassword,
+ newSecurePassword,
+ redirectedUserInstance,
connectionOptions,
- timeout);
+ credential,
+ timeout);
return; // LoginWithFailover successfully connected and handled entire connection setup
}
@@ -1395,9 +1429,12 @@ namespace System.Data.SqlClient
bool useFailoverHost,
ServerInfo primaryServerInfo,
string failoverHost,
- bool redirectedUserInstance,
+ string newPassword,
+ SecureString newSecurePassword,
+ bool redirectedUserInstance,
SqlConnectionString connectionOptions,
- TimeoutTimer timeout
+ SqlCredential credential,
+ TimeoutTimer timeout
)
{
Debug.Assert(!connectionOptions.MultiSubnetFailover, "MultiSubnetFailover should not be set if failover partner is used");
@@ -1475,7 +1512,9 @@ namespace System.Data.SqlClient
// Attempt login. Use timerInterval for attempt timeout unless infinite timeout was requested.
AttemptOneLogin(
currentServerInfo,
- false, // Use timeout in SniOpen
+ newPassword,
+ newSecurePassword,
+ false, // Use timeout in SniOpen
intervalTimer,
withFailover: true
);
@@ -1561,10 +1600,13 @@ namespace System.Data.SqlClient
}
// Common code path for making one attempt to establish a connection and log in to server.
- private void AttemptOneLogin(ServerInfo serverInfo,
+ private void AttemptOneLogin(
+ ServerInfo serverInfo,
+ string newPassword,
+ SecureString newSecurePassword,
bool ignoreSniOpenTimeout,
- TimeoutTimer timeout,
- bool withFailover = false)
+ TimeoutTimer timeout,
+ bool withFailover = false)
{
_routingInfo = null; // forget routing information
@@ -1583,7 +1625,7 @@ namespace System.Data.SqlClient
_timeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.LoginBegin);
_parser._physicalStateObj.SniContext = SniContext.Snix_Login;
- this.Login(serverInfo, timeout);
+ this.Login(serverInfo, timeout, newPassword, newSecurePassword);
_timeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.ProcessConnectionAuth);
_timeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.PostLogin);
diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlParameterCollection.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlParameterCollection.cs
index 78d0e009a9..75691359df 100644
--- a/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlParameterCollection.cs
+++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlParameterCollection.cs
@@ -30,7 +30,8 @@ namespace System.Data.SqlClient
_isDirty = value;
}
}
-
+ public override bool IsFixedSize => ((System.Collections.IList)InnerList).IsFixedSize;
+ public override bool IsReadOnly => ((System.Collections.IList)InnerList).IsReadOnly;
new public SqlParameter this[int index]
{
get
diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlUtil.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlUtil.cs
index 8b9470bd97..a649b9eae2 100644
--- a/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlUtil.cs
+++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlUtil.cs
@@ -204,6 +204,22 @@ namespace System.Data.SqlClient
{
return ADP.InvalidOperation(SR.GetString(SR.SQL_InstanceFailure));
}
+ internal static Exception ChangePasswordArgumentMissing(string argumentName)
+ {
+ return ADP.ArgumentNull(SR.GetString(SR.SQL_ChangePasswordArgumentMissing, argumentName));
+ }
+ internal static Exception ChangePasswordConflictsWithSSPI()
+ {
+ return ADP.Argument(SR.GetString(SR.SQL_ChangePasswordConflictsWithSSPI));
+ }
+ internal static Exception ChangePasswordRequiresYukon()
+ {
+ return ADP.InvalidOperation(SR.GetString(SR.SQL_ChangePasswordRequiresYukon));
+ }
+ static internal Exception ChangePasswordUseOfUnallowedKey(string key)
+ {
+ return ADP.InvalidOperation(SR.GetString(SR.SQL_ChangePasswordUseOfUnallowedKey, key));
+ }
//
// Global Transactions.
diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParser.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParser.cs
index 16e03ce992..eb9067b8e2 100644
--- a/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParser.cs
+++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParser.cs
@@ -193,7 +193,6 @@ namespace System.Data.SqlClient
}
}
-
internal bool IsKatmaiOrNewer
{
get
@@ -2499,9 +2498,6 @@ namespace System.Data.SqlClient
ushort status;
int count;
- // Can't retry TryProcessDone
- stateObj._syncOverAsync = true;
-
// status
// command
// rowcount (valid only if DONE_COUNT bit is set)
@@ -5989,8 +5985,13 @@ namespace System.Data.SqlClient
Debug.Assert(TdsEnums.MAXLEN_HOSTNAME >= rec.hostName.Length, "_workstationId.Length exceeds the max length for this value");
Debug.Assert(rec.userName == null || (rec.userName != null && TdsEnums.MAXLEN_USERNAME >= rec.userName.Length), "_userID.Length exceeds the max length for this value");
+ Debug.Assert(rec.credential == null || (rec.credential != null && TdsEnums.MAXLEN_USERNAME >= rec.credential.UserId.Length), "_credential.UserId.Length exceeds the max length for this value");
Debug.Assert(rec.password == null || (rec.password != null && TdsEnums.MAXLEN_PASSWORD >= rec.password.Length), "_password.Length exceeds the max length for this value");
+ Debug.Assert(rec.credential == null || (rec.credential != null && TdsEnums.MAXLEN_PASSWORD >= rec.credential.Password.Length), "_credential.Password.Length exceeds the max length for this value");
+
+ Debug.Assert(rec.credential != null || rec.userName != null || rec.password != null, "cannot mix the new secure password system and the connection string based password");
+ Debug.Assert(rec.newSecurePassword != null || rec.newPassword != null, "cannot have both new secure change password and string based change password");
Debug.Assert(TdsEnums.MAXLEN_APPNAME >= rec.applicationName.Length, "_applicationName.Length exceeds the max length for this value");
Debug.Assert(TdsEnums.MAXLEN_SERVERNAME >= rec.serverName.Length, "_dataSource.Length exceeds the max length for this value");
Debug.Assert(TdsEnums.MAXLEN_LANGUAGE >= rec.language.Length, "_currentLanguage .Length exceeds the max length for this value");
@@ -6003,15 +6004,34 @@ namespace System.Data.SqlClient
// get the password up front to use in sspi logic below
byte[] encryptedPassword = null;
+ byte[] encryptedChangePassword = null;
int encryptedPasswordLengthInBytes;
+ int encryptedChangePasswordLengthInBytes;
bool useFeatureExt = (requestedFeatures != TdsEnums.FeatureExtension.None);
string userName;
- userName = rec.userName;
- encryptedPassword = TdsParserStaticMethods.ObfuscatePassword(rec.password);
- encryptedPasswordLengthInBytes = encryptedPassword.Length; // password in clear text is already encrypted and its length is in byte
+ if (rec.credential != null)
+ {
+ userName = rec.credential.UserId;
+ encryptedPasswordLengthInBytes = rec.credential.Password.Length * 2;
+ }
+ else
+ {
+ userName = rec.userName;
+ encryptedPassword = TdsParserStaticMethods.ObfuscatePassword(rec.password);
+ encryptedPasswordLengthInBytes = encryptedPassword.Length; // password in clear text is already encrypted and its length is in byte
+ }
+ if (rec.newSecurePassword != null)
+ {
+ encryptedChangePasswordLengthInBytes = rec.newSecurePassword.Length * 2;
+ }
+ else
+ {
+ encryptedChangePassword = TdsParserStaticMethods.ObfuscatePassword(rec.newPassword);
+ encryptedChangePasswordLengthInBytes = encryptedChangePassword.Length;
+ }
// set the message type
_physicalStateObj._outputMessageType = TdsEnums.MT_LOGIN7;
@@ -6045,7 +6065,8 @@ namespace System.Data.SqlClient
{
checked
{
- length += (userName.Length * 2) + encryptedPasswordLengthInBytes;
+ length += (userName.Length * 2) + encryptedPasswordLengthInBytes
+ + encryptedChangePasswordLengthInBytes;
}
}
else
@@ -6161,6 +6182,10 @@ namespace System.Data.SqlClient
}
// 4th one
+ if (!string.IsNullOrEmpty(rec.newPassword) || (rec.newSecurePassword != null && rec.newSecurePassword.Length != 0))
+ {
+ log7Flags |= 1 << 24;
+ }
if (rec.userInstance)
{
log7Flags |= 1 << 26;
@@ -6259,7 +6284,7 @@ namespace System.Data.SqlClient
offset += rec.attachDBFilename.Length * 2;
WriteShort(offset, _physicalStateObj); // reset password offset
- WriteShort(0, _physicalStateObj);
+ WriteShort(encryptedChangePasswordLengthInBytes / 2, _physicalStateObj);
WriteInt(0, _physicalStateObj); // reserved for chSSPI
@@ -6272,6 +6297,11 @@ namespace System.Data.SqlClient
{
WriteString(userName, _physicalStateObj);
+ if (rec.credential != null)
+ {
+ _physicalStateObj.WriteSecureString(rec.credential.Password);
+ }
+ else
{
_physicalStateObj.WriteByteArray(encryptedPassword, encryptedPasswordLengthInBytes, 0);
}
@@ -6295,6 +6325,19 @@ namespace System.Data.SqlClient
_physicalStateObj.WriteByteArray(outSSPIBuff, (int)outSSPILength, 0);
WriteString(rec.attachDBFilename, _physicalStateObj);
+
+ if (!rec.useSSPI)
+ {
+ if (rec.newSecurePassword != null)
+ {
+ _physicalStateObj.WriteSecureString(rec.newSecurePassword);
+ }
+ else
+ {
+ _physicalStateObj.WriteByteArray(encryptedChangePassword, encryptedChangePasswordLengthInBytes, 0);
+ }
+ }
+
if (useFeatureExt)
{
if ((requestedFeatures & TdsEnums.FeatureExtension.SessionRecovery) != 0)
@@ -6321,6 +6364,7 @@ namespace System.Data.SqlClient
}
_physicalStateObj.WritePacket(TdsEnums.HARDFLUSH);
+ _physicalStateObj.ResetSecurePasswordsInformation();
_physicalStateObj._pendingData = true;
_physicalStateObj._messageStatus = 0;
}// tdsLogin
diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserHelperClasses.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserHelperClasses.cs
index c41adc358a..dc6379b66c 100644
--- a/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserHelperClasses.cs
+++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserHelperClasses.cs
@@ -11,6 +11,7 @@ using System.Collections.ObjectModel;
using System.Data.Common;
using System.Data.SqlTypes;
using System.Diagnostics;
+using System.Security;
using System.Text;
using Microsoft.SqlServer.Server;
@@ -250,9 +251,12 @@ namespace System.Data.SqlClient
internal string database = ""; // initial database
internal string attachDBFilename = ""; // DB filename to be attached
internal bool useReplication = false; // user login for replication
+ internal string newPassword = ""; // new password for reset password
internal bool useSSPI = false; // use integrated security
internal int packetSize = SqlConnectionString.DEFAULT.Packet_Size; // packet size
internal bool readOnlyIntent = false; // read-only intent
+ internal SqlCredential credential; // user id and password in SecureString
+ internal SecureString newSecurePassword;
}
sealed internal class SqlLoginAck
diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserStateObject.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserStateObject.cs
index 157df9ce5a..50d0f964ef 100644
--- a/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserStateObject.cs
+++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserStateObject.cs
@@ -10,6 +10,8 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Text;
+using System.Security;
+using System.Runtime.InteropServices;
namespace System.Data.SqlClient
{
@@ -90,6 +92,10 @@ namespace System.Data.SqlClient
private readonly LastIOTimer _lastSuccessfulIOTimer;
+ // secure password information to be stored
+ // At maximum number of secure string that need to be stored is two; one for login password and the other for new change password
+ private SecureString[] _securePasswords = new SecureString[2] { null, null };
+ private int[] _securePasswordOffsetsInBuffer = new int[2];
// This variable is used to track whether another thread has requested a cancel. The
// synchronization points are
@@ -757,7 +763,7 @@ namespace System.Data.SqlClient
internal abstract bool IsPacketEmpty(object readPacket);
- internal abstract object ReadSyncOverAsync(int timeoutRemaining, bool isMarsOn, out uint error);
+ internal abstract object ReadSyncOverAsync(int timeoutRemaining, out uint error);
internal abstract object ReadAsync(out uint error, ref object handle);
@@ -2073,7 +2079,7 @@ namespace System.Data.SqlClient
Interlocked.Increment(ref _readingCount);
shouldDecrement = true;
- readPacket = ReadSyncOverAsync(GetTimeoutRemaining(), false, out error);
+ readPacket = ReadSyncOverAsync(GetTimeoutRemaining(), out error);
Interlocked.Decrement(ref _readingCount);
shouldDecrement = false;
@@ -2295,7 +2301,11 @@ namespace System.Data.SqlClient
if (_networkPacketTimeout == null)
{
- _networkPacketTimeout = new Timer(OnTimeout, null, Timeout.Infinite, Timeout.Infinite);
+ _networkPacketTimeout = ADP.UnsafeCreateTimer(
+ new TimerCallback(OnTimeout),
+ null,
+ Timeout.Infinite,
+ Timeout.Infinite);
}
// -1 == Infinite
@@ -2510,7 +2520,7 @@ namespace System.Data.SqlClient
Interlocked.Increment(ref _readingCount);
shouldDecrement = true;
- syncReadPacket = ReadSyncOverAsync(stateObj.GetTimeoutRemaining(), _parser.MARSOn, out error);
+ syncReadPacket = ReadSyncOverAsync(stateObj.GetTimeoutRemaining(), out error);
Interlocked.Decrement(ref _readingCount);
shouldDecrement = false;
@@ -2647,6 +2657,32 @@ namespace System.Data.SqlClient
}
}
+ private void SetBufferSecureStrings()
+ {
+ if (_securePasswords != null)
+ {
+ for (int i = 0; i < _securePasswords.Length; i++)
+ {
+ if (_securePasswords[i] != null)
+ {
+ IntPtr str = IntPtr.Zero;
+ try
+ {
+ str = Marshal.SecureStringToBSTR(_securePasswords[i]);
+ byte[] data = new byte[_securePasswords[i].Length * 2];
+ Marshal.Copy(str, data, 0, _securePasswords[i].Length * 2);
+ TdsParserStaticMethods.ObfuscatePassword(data);
+ data.CopyTo(_outBuff, _securePasswordOffsetsInBuffer[i]);
+ }
+ finally
+ {
+ Marshal.ZeroFreeBSTR(str);
+ }
+ }
+ }
+ }
+ }
+
public void ReadAsyncCallback<T>(T packet, UInt32 error)
{
ReadAsyncCallback(IntPtr.Zero, packet, error);
@@ -2872,7 +2908,34 @@ namespace System.Data.SqlClient
// Network/Packet Writing & Processing //
/////////////////////////////////////////
+ internal void WriteSecureString(SecureString secureString)
+ {
+ Debug.Assert(_securePasswords[0] == null || _securePasswords[1] == null, "There are more than two secure passwords");
+
+ int index = _securePasswords[0] != null ? 1 : 0;
+
+ _securePasswords[index] = secureString;
+ _securePasswordOffsetsInBuffer[index] = _outBytesUsed;
+
+ // loop through and write the entire array
+ int lengthInBytes = secureString.Length * 2;
+
+ // It is guaranteed both secure password and secure change password should fit into the first packet
+ // Given current TDS format and implementation it is not possible that one of secure string is the last item and exactly fill up the output buffer
+ // if this ever happens and it is correct situation, the packet needs to be written out after _outBytesUsed is update
+ Debug.Assert((_outBytesUsed + lengthInBytes) < _outBuff.Length, "Passwords cannot be splited into two different packet or the last item which fully fill up _outBuff!!!");
+
+ _outBytesUsed += lengthInBytes;
+ }
+ internal void ResetSecurePasswordsInformation()
+ {
+ for (int i = 0; i < _securePasswords.Length; ++i)
+ {
+ _securePasswords[i] = null;
+ _securePasswordOffsetsInBuffer[i] = 0;
+ }
+ }
internal Task WaitForAccumulatedWrites()
{
@@ -3162,15 +3225,16 @@ namespace System.Data.SqlClient
// Add packet to the pending list (since the callback can happen any time after we call SNIWritePacket)
packetPointer = AddPacketToPendingList(packet);
}
+
// Async operation completion may be delayed (success pending).
try
{
}
finally
{
-
sniError = WritePacket(packet, sync);
}
+
if (sniError == TdsEnums.SNI_SUCCESS_IO_PENDING)
{
Debug.Assert(!sync, "Completion should be handled in SniManagedWwrapper");
@@ -3343,6 +3407,7 @@ namespace System.Data.SqlClient
// Prepare packet, and write to packet.
object packet = GetResetWritePacket();
+ SetBufferSecureStrings();
SetPacketData(packet, _outBuff, _outBytesUsed);
uint sniError;
diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserStateObjectManaged.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserStateObjectManaged.cs
index 50d03824fb..02c6602633 100644
--- a/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserStateObjectManaged.cs
+++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserStateObjectManaged.cs
@@ -125,17 +125,13 @@ namespace System.Data.SqlClient.SNI
internal override bool IsFailedHandle() => _sessionHandle.Status != TdsEnums.SNI_SUCCESS;
- internal override object ReadSyncOverAsync(int timeoutRemaining, bool isMarsOn, out uint error)
+ internal override object ReadSyncOverAsync(int timeoutRemaining, out uint error)
{
SNIHandle handle = Handle;
if (handle == null)
{
throw ADP.ClosedConnectionError();
}
- if (isMarsOn)
- {
- IncrementPendingCallbacks();
- }
SNIPacket packet = null;
error = SNIProxy.Singleton.ReadSyncOverAsync(handle, out packet, timeoutRemaining);
return packet;
@@ -166,10 +162,13 @@ namespace System.Data.SqlClient.SNI
internal override object CreateAndSetAttentionPacket()
{
- SNIPacket attnPacket = new SNIPacket(Handle);
- _sniAsyncAttnPacket = attnPacket;
- SetPacketData(attnPacket, SQL.AttentionHeader, TdsEnums.HEADER_LEN);
- return attnPacket;
+ if (_sniAsyncAttnPacket == null)
+ {
+ SNIPacket attnPacket = new SNIPacket();
+ SetPacketData(attnPacket, SQL.AttentionHeader, TdsEnums.HEADER_LEN);
+ _sniAsyncAttnPacket = attnPacket;
+ }
+ return _sniAsyncAttnPacket;
}
internal override uint WritePacket(object packet, bool sync)
@@ -268,7 +267,7 @@ namespace System.Data.SqlClient.SNI
else
{
// Failed to take a packet - create a new one
- packet = new SNIPacket(sniHandle);
+ packet = new SNIPacket();
}
return packet;
}
diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserStateObjectNative.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserStateObjectNative.cs
index bebd574324..01cf8b68d6 100644
--- a/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserStateObjectNative.cs
+++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserStateObjectNative.cs
@@ -169,7 +169,7 @@ namespace System.Data.SqlClient
internal override bool IsFailedHandle() => _sessionHandle.Status != TdsEnums.SNI_SUCCESS;
- internal override object ReadSyncOverAsync(int timeoutRemaining, bool isMarsOn, out uint error)
+ internal override object ReadSyncOverAsync(int timeoutRemaining, out uint error)
{
SNIHandle handle = Handle;
if (handle == null)
diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserStaticMethods.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserStaticMethods.cs
index d62e63218f..9740bb693d 100644
--- a/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserStaticMethods.cs
+++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/TdsParserStaticMethods.cs
@@ -41,6 +41,20 @@ namespace System.Data.SqlClient
return bObfuscated;
}
+ internal static byte[] ObfuscatePassword(byte[] password)
+ {
+ byte bLo;
+ byte bHi;
+
+ for (int i = 0; i < password.Length; i++)
+ {
+ bLo = (byte)(password[i] & 0x0f);
+ bHi = (byte)(password[i] & 0xf0);
+ password[i] = (Byte)(((bHi >> 4) | (bLo << 4)) ^ 0xa5);
+ }
+ return password;
+ }
+
private const int NoProcessId = -1;
private static int s_currentProcessId = NoProcessId;
internal static int GetCurrentProcessIdForTdsLoginOnly()
diff --git a/src/System.Data.SqlClient/tests/FunctionalTests/DiagnosticTest.cs b/src/System.Data.SqlClient/tests/FunctionalTests/DiagnosticTest.cs
index d04c326aaf..ed78353c34 100644
--- a/src/System.Data.SqlClient/tests/FunctionalTests/DiagnosticTest.cs
+++ b/src/System.Data.SqlClient/tests/FunctionalTests/DiagnosticTest.cs
@@ -18,7 +18,6 @@ using System.Runtime.CompilerServices;
namespace System.Data.SqlClient.Tests
{
- [ActiveIssue("dotnet/corefx #17925", TestPlatforms.Any)]
public class DiagnosticTest : RemoteExecutorTestBase
{
private const string BadConnectionString = "data source = bad; initial catalog = bad; uid = bad; password = bad; connection timeout = 1;";
@@ -27,7 +26,7 @@ namespace System.Data.SqlClient.Tests
public static bool IsConnectionStringConfigured() => s_tcpConnStr != string.Empty;
[Fact]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot)] // Internals reflection not supported on uapaot
+ [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot | TargetFrameworkMonikers.NetFramework, "Internals reflection not supported on UapAot | Feature not available on Framework")]
public void ExecuteScalarTest()
{
RemoteInvoke(() =>
@@ -49,7 +48,7 @@ namespace System.Data.SqlClient.Tests
}
[Fact]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot)] // Internals reflection not supported on uapaot
+ [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot | TargetFrameworkMonikers.NetFramework, "Internals reflection not supported on UapAot | Feature not available on Framework")]
public void ExecuteScalarErrorTest()
{
RemoteInvoke(() =>
@@ -73,7 +72,7 @@ namespace System.Data.SqlClient.Tests
}
[Fact]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot)] // Internals reflection not supported on uapaot
+ [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot | TargetFrameworkMonikers.NetFramework, "Internals reflection not supported on UapAot | Feature not available on Framework")]
public void ExecuteNonQueryTest()
{
RemoteInvoke(() =>
@@ -95,7 +94,7 @@ namespace System.Data.SqlClient.Tests
}
[Fact]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot)] // Internals reflection not supported on uapaot
+ [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot | TargetFrameworkMonikers.NetFramework, "Internals reflection not supported on UapAot | Feature not available on Framework")]
public void ExecuteNonQueryErrorTest()
{
RemoteInvoke(() =>
@@ -133,7 +132,7 @@ namespace System.Data.SqlClient.Tests
}
[Fact]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot)] // Internals reflection not supported on uapaot
+ [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot | TargetFrameworkMonikers.NetFramework, "Internals reflection not supported on UapAot | Feature not available on Framework")]
public void ExecuteReaderTest()
{
RemoteInvoke(() =>
@@ -156,7 +155,7 @@ namespace System.Data.SqlClient.Tests
}
[Fact]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot)] // Internals reflection not supported on uapaot
+ [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot | TargetFrameworkMonikers.NetFramework, "Internals reflection not supported on UapAot | Feature not available on Framework")]
public void ExecuteReaderErrorTest()
{
RemoteInvoke(() =>
@@ -182,7 +181,7 @@ namespace System.Data.SqlClient.Tests
}
[Fact]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot)] // Internals reflection not supported on uapaot
+ [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot | TargetFrameworkMonikers.NetFramework, "Internals reflection not supported on UapAot | Feature not available on Framework")]
public void ExecuteReaderWithCommandBehaviorTest()
{
RemoteInvoke(() =>
@@ -205,7 +204,7 @@ namespace System.Data.SqlClient.Tests
}
[ConditionalFact(nameof(IsConnectionStringConfigured))]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot)] // Internals reflection not supported on uapaot
+ [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot | TargetFrameworkMonikers.NetFramework, "Internals reflection not supported on UapAot | Feature not available on Framework")]
public void ExecuteXmlReaderTest()
{
RemoteInvoke(cs =>
@@ -228,7 +227,7 @@ namespace System.Data.SqlClient.Tests
}
[Fact]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot)] // Internals reflection not supported on uapaot
+ [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot | TargetFrameworkMonikers.NetFramework, "Internals reflection not supported on UapAot | Feature not available on Framework")]
public void ExecuteXmlReaderErrorTest()
{
RemoteInvoke(() =>
@@ -254,7 +253,7 @@ namespace System.Data.SqlClient.Tests
}
[Fact]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot)] // Internals reflection not supported on uapaot
+ [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot | TargetFrameworkMonikers.NetFramework, "Internals reflection not supported on UapAot | Feature not available on Framework")]
public void ExecuteScalarAsyncTest()
{
RemoteInvoke(() =>
@@ -276,7 +275,7 @@ namespace System.Data.SqlClient.Tests
}
[Fact]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot)] // Internals reflection not supported on uapaot
+ [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot | TargetFrameworkMonikers.NetFramework, "Internals reflection not supported on UapAot | Feature not available on Framework")]
public void ExecuteScalarAsyncErrorTest()
{
RemoteInvoke(() =>
@@ -300,7 +299,7 @@ namespace System.Data.SqlClient.Tests
}
[Fact]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot)] // Internals reflection not supported on uapaot
+ [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot | TargetFrameworkMonikers.NetFramework, "Internals reflection not supported on UapAot | Feature not available on Framework")]
public void ExecuteNonQueryAsyncTest()
{
RemoteInvoke(() =>
@@ -322,7 +321,7 @@ namespace System.Data.SqlClient.Tests
}
[Fact]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot)] // Internals reflection not supported on uapaot
+ [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot | TargetFrameworkMonikers.NetFramework, "Internals reflection not supported on UapAot | Feature not available on Framework")]
public void ExecuteNonQueryAsyncErrorTest()
{
RemoteInvoke(() =>
@@ -345,7 +344,7 @@ namespace System.Data.SqlClient.Tests
}
[Fact]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot)] // Internals reflection not supported on uapaot
+ [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot | TargetFrameworkMonikers.NetFramework, "Internals reflection not supported on UapAot | Feature not available on Framework")]
public void ExecuteReaderAsyncTest()
{
RemoteInvoke(() =>
@@ -368,7 +367,7 @@ namespace System.Data.SqlClient.Tests
}
[Fact]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot)] // Internals reflection not supported on uapaot
+ [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot | TargetFrameworkMonikers.NetFramework, "Internals reflection not supported on UapAot | Feature not available on Framework")]
public void ExecuteReaderAsyncErrorTest()
{
RemoteInvoke(() =>
@@ -394,7 +393,7 @@ namespace System.Data.SqlClient.Tests
}
[ConditionalFact(nameof(IsConnectionStringConfigured))]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot)] // Internals reflection not supported on uapaot
+ [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot | TargetFrameworkMonikers.NetFramework, "Internals reflection not supported on UapAot | Feature not available on Framework")]
public void ExecuteXmlReaderAsyncTest()
{
RemoteInvoke(cs =>
@@ -417,7 +416,7 @@ namespace System.Data.SqlClient.Tests
}
[ConditionalFact(nameof(IsConnectionStringConfigured))]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot)] // Internals reflection not supported on uapaot
+ [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot | TargetFrameworkMonikers.NetFramework, "Internals reflection not supported on UapAot | Feature not available on Framework")]
public void ExecuteXmlReaderAsyncErrorTest()
{
RemoteInvoke(cs =>
@@ -443,7 +442,7 @@ namespace System.Data.SqlClient.Tests
}
[Fact]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot)] // Internals reflection not supported on uapaot
+ [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot | TargetFrameworkMonikers.NetFramework, "Internals reflection not supported on UapAot | Feature not available on Framework")]
public void ConnectionOpenTest()
{
RemoteInvoke(() =>
@@ -464,7 +463,7 @@ namespace System.Data.SqlClient.Tests
}
[Fact]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot)] // Internals reflection not supported on uapaot
+ [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot | TargetFrameworkMonikers.NetFramework, "Internals reflection not supported on UapAot | Feature not available on Framework")]
public void ConnectionOpenErrorTest()
{
RemoteInvoke(() =>
@@ -481,7 +480,7 @@ namespace System.Data.SqlClient.Tests
}
[Fact]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot)] // Internals reflection not supported on uapaot
+ [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot | TargetFrameworkMonikers.NetFramework, "Internals reflection not supported on UapAot | Feature not available on Framework")]
public void ConnectionOpenAsyncTest()
{
RemoteInvoke(() =>
@@ -498,7 +497,7 @@ namespace System.Data.SqlClient.Tests
}
[Fact]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot)] // Internals reflection not supported on uapaot
+ [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot | TargetFrameworkMonikers.NetFramework, "Internals reflection not supported on UapAot | Feature not available on Framework")]
public void ConnectionOpenAsyncErrorTest()
{
RemoteInvoke(() =>
diff --git a/src/System.Data.SqlClient/tests/FunctionalTests/SqlConnectionBasicTests.cs b/src/System.Data.SqlClient/tests/FunctionalTests/SqlConnectionBasicTests.cs
index 381a5ec6cd..91716293e9 100644
--- a/src/System.Data.SqlClient/tests/FunctionalTests/SqlConnectionBasicTests.cs
+++ b/src/System.Data.SqlClient/tests/FunctionalTests/SqlConnectionBasicTests.cs
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Data.Common;
using System.Diagnostics;
using System.Reflection;
+using System.Security;
using System.Threading;
using Xunit;
@@ -14,7 +15,6 @@ namespace System.Data.SqlClient.Tests
public class SqlConnectionBasicTests
{
[Fact]
- [ActiveIssue("dotnet/corefx #23435", TestPlatforms.Any)]
public void ConnectionTest()
{
using (TestTdsServer server = TestTdsServer.StartTestServer())
@@ -27,7 +27,6 @@ namespace System.Data.SqlClient.Tests
}
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer), nameof(PlatformDetection.IsNotArmProcess))]
- [ActiveIssue("dotnet/corefx #23435", TestPlatforms.Any)]
[PlatformSpecific(TestPlatforms.Windows)]
public void IntegratedAuthConnectionTest()
{
@@ -83,6 +82,32 @@ namespace System.Data.SqlClient.Tests
}
[Fact]
+ public void ClosedConnectionSchemaRetrieval()
+ {
+ using (SqlConnection connection = new SqlConnection(string.Empty))
+ {
+ Assert.Throws<InvalidOperationException>(() => connection.GetSchema());
+ }
+ }
+
+ [Theory]
+ [InlineData("RandomStringForTargetServer", false, true)]
+ [InlineData("RandomStringForTargetServer", true, false)]
+ [InlineData(null, false, false)]
+ [InlineData("", false, false)]
+ public void RetrieveWorkstationId(string workstation, bool withDispose, bool shouldMatchSetWorkstationId)
+ {
+ string connectionString = $"Workstation Id={workstation}";
+ SqlConnection conn = new SqlConnection(connectionString);
+ if(withDispose)
+ {
+ conn.Dispose();
+ }
+ string expected = shouldMatchSetWorkstationId ? workstation : Environment.MachineName;
+ Assert.Equal(expected, conn.WorkstationId);
+ }
+
+ [Fact]
public void ConnectionTimeoutTestWithThread()
{
int timeoutSec = 5;
@@ -111,6 +136,66 @@ namespace System.Data.SqlClient.Tests
Console.WriteLine($"ConnectionTimeoutTestWithThread: Elapsed Time {theMax} and threshold {threshold}");
}
+ [OuterLoop("Can take up to 4 seconds")]
+ [Fact]
+ public void ExceptionsWithMinPoolSizeCanBeHandled()
+ {
+ string connectionString = $"Data Source={Guid.NewGuid().ToString()};uid=random;pwd=asd;Connect Timeout=2; Min Pool Size=3";
+ for (int i = 0; i < 2; i++)
+ {
+ using (SqlConnection connection = new SqlConnection(connectionString))
+ {
+ Exception exception = Record.Exception(() => connection.Open());
+ Assert.True(exception is InvalidOperationException || exception is SqlException, $"Unexpected exception: {exception}");
+ }
+ }
+ }
+
+ [Fact]
+ public void ConnectionTestInvalidCredentialCombination()
+ {
+ var cleartextCredsConnStr = "User=test;Password=test;";
+ var sspiConnStr = "Integrated Security=true;";
+ var testPassword = new SecureString();
+ testPassword.MakeReadOnly();
+ var sqlCredential = new SqlCredential(string.Empty, testPassword);
+
+ // Verify that SSPI and cleartext username/password are not in the connection string.
+ Assert.Throws<ArgumentException>(() => { new SqlConnection(cleartextCredsConnStr, sqlCredential); });
+
+ Assert.Throws<ArgumentException>(() => { new SqlConnection(sspiConnStr, sqlCredential); });
+
+ // Verify that credential may not be set with cleartext username/password or SSPI.
+ using (var conn = new SqlConnection(cleartextCredsConnStr))
+ {
+ Assert.Throws<InvalidOperationException>(() => { conn.Credential = sqlCredential; });
+ }
+
+ using (var conn = new SqlConnection(sspiConnStr))
+ {
+ Assert.Throws<InvalidOperationException>(() => { conn.Credential = sqlCredential; });
+ }
+
+ // Verify that connection string with username/password or SSPI may not be set with credential present.
+ using (var conn = new SqlConnection(string.Empty, sqlCredential))
+ {
+ Assert.Throws<InvalidOperationException>(() => { conn.ConnectionString = cleartextCredsConnStr; });
+
+ Assert.Throws<InvalidOperationException>(() => { conn.ConnectionString = sspiConnStr; });
+ }
+ }
+
+ [Fact]
+ public void ConnectionTestValidCredentialCombination()
+ {
+ var testPassword = new SecureString();
+ testPassword.MakeReadOnly();
+ var sqlCredential = new SqlCredential(string.Empty, testPassword);
+ var conn = new SqlConnection(string.Empty, sqlCredential);
+
+ Assert.Equal(sqlCredential, conn.Credential);
+ }
+
public class ConnectionWorker
{
private static ManualResetEventSlim startEvent = new ManualResetEventSlim(false);
diff --git a/src/System.Data.SqlClient/tests/FunctionalTests/SqlCredentialTest.cs b/src/System.Data.SqlClient/tests/FunctionalTests/SqlCredentialTest.cs
new file mode 100644
index 0000000000..9194a6594b
--- /dev/null
+++ b/src/System.Data.SqlClient/tests/FunctionalTests/SqlCredentialTest.cs
@@ -0,0 +1,74 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Data.SqlClient;
+using System.Linq;
+using System.Security;
+using System.Text;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.Data.SqlClient.Tests
+{
+ public static class SqlCredentialTest
+ {
+ [Fact]
+ public static void Test_SqlCredential_Password_Requirements()
+ {
+ var userId = "user";
+
+ // Create password with value longer than max allowed length
+ var longPassword = new SecureString();
+
+ var genPassword = string.Empty.PadLeft(129, '0');
+ genPassword.ToCharArray().ToList().ForEach(c => longPassword.AppendChar(c));
+ longPassword.MakeReadOnly();
+
+ // Verify non-null password requirement
+ Assert.Throws<ArgumentNullException>(() => new SqlCredential(userId, null));
+
+ // Verify max length requirement
+ Assert.Throws<ArgumentException>(() => new SqlCredential(userId, longPassword));
+
+ // Verify read only password requirement
+ Assert.Throws<ArgumentException>(() => new SqlCredential(userId, new SecureString()));
+
+ }
+
+ [Fact]
+ public static void Test_SqlCredential_UserId_Requirements()
+ {
+ var password = new SecureString();
+ password.MakeReadOnly();
+
+ // Create userId longer than max allowed length
+ var userId = string.Empty.PadLeft(129, '0');
+
+ // Verify max length requirement
+ Assert.Throws<ArgumentException>(() => new SqlCredential(userId, password));
+
+ // Verify non-null userId requirement
+ Assert.Throws<ArgumentNullException>(() => new SqlCredential(null, password));
+
+ }
+
+ [Fact]
+ public static void Test_SqlCredential_Properties()
+ {
+ var userId = "user";
+ var password = new SecureString();
+ password.AppendChar('0');
+ password.MakeReadOnly();
+
+ var credential = new SqlCredential(userId, password);
+
+ Assert.Equal(userId, credential.UserId);
+ Assert.Equal(password, credential.Password);
+
+ }
+
+ }
+}
diff --git a/src/System.Data.SqlClient/tests/FunctionalTests/SqlDataRecordTest.cs b/src/System.Data.SqlClient/tests/FunctionalTests/SqlDataRecordTest.cs
index 30e1a9c8a7..6ccfd29094 100644
--- a/src/System.Data.SqlClient/tests/FunctionalTests/SqlDataRecordTest.cs
+++ b/src/System.Data.SqlClient/tests/FunctionalTests/SqlDataRecordTest.cs
@@ -3,6 +3,8 @@
// See the LICENSE file in the project root for more information.
+using System.Collections;
+using System.Collections.Generic;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using Xunit;
@@ -136,6 +138,260 @@ namespace System.Data.SqlClient.Tests
Assert.Equal(DBNull.Value, record.GetValue(i));
}
}
+ [Fact]
+ public void GetDataTypeName_ReturnsMetaDataTypeIfUdtType()
+ {
+ SqlMetaData[] metaData = new SqlMetaData[]
+ {
+ new SqlMetaData("col1", SqlDbType.Udt, typeof(TestUdt), "sql_TestUdt")
+ };
+
+ SqlDataRecord record = new SqlDataRecord(metaData);
+
+ Assert.Equal("System.Data.SqlClient.Tests.TestUdt", record.GetDataTypeName(0));
+ }
+
+ [Fact]
+ public void GetDataTypeName_ReturnsTypeFromMetaTypeIfNotUdt()
+ {
+ SqlMetaData[] metaData = new SqlMetaData[]
+ {
+ new SqlMetaData("col1", SqlDbType.NVarChar, 50)
+ };
+
+ SqlDataRecord record = new SqlDataRecord(metaData);
+
+ Assert.Equal("nvarchar", record.GetDataTypeName(0));
+ }
+ [Fact]
+ public void GetFieldType_ReturnMetaTypeClassType()
+ {
+ SqlMetaData[] metaData = new SqlMetaData[]
+ {
+ new SqlMetaData("col1", SqlDbType.NVarChar, 50)
+ };
+
+ SqlDataRecord record = new SqlDataRecord(metaData);
+
+ Assert.Equal(typeof(string), record.GetFieldType(0));
+ }
+
+ [Fact]
+ public void GetValues_ThrowsIfNull()
+ {
+ SqlMetaData[] metaData = new SqlMetaData[]
+ {
+ new SqlMetaData("col1", SqlDbType.NVarChar, 50)
+ };
+
+ SqlDataRecord record = new SqlDataRecord(metaData);
+
+ Assert.Throws<ArgumentNullException>(() => record.GetValues(null));
+ }
+
+ [Fact]
+ public void GetValues_IfValuesBiggerThanColumnCount_LastArrayItemKeptEmpty()
+ {
+ SqlMetaData[] metaData = new SqlMetaData[]
+ {
+ new SqlMetaData("col1", SqlDbType.NVarChar, 50),
+ new SqlMetaData("col2", SqlDbType.Int)
+ };
+ SqlDataRecord record = new SqlDataRecord(metaData);
+ record.SetString(0, "test");
+ record.SetSqlInt32(1, 2);
+
+ object[] values = new object[5];
+ int columnCount = record.GetValues(values);
+
+ for (int i = 2; i < 5; i++)
+ {
+ Assert.Null(values[i]);
+ }
+ Assert.Equal(2, columnCount);
+ }
+
+ [Fact]
+ public void GetValues_IfValuesShorterThanColumnCount_FillOnlyFirstColumn()
+ {
+ SqlMetaData[] metaData = new SqlMetaData[]
+ {
+ new SqlMetaData("col1", SqlDbType.NVarChar, 50),
+ new SqlMetaData("col2", SqlDbType.Int)
+ };
+ SqlDataRecord record = new SqlDataRecord(metaData);
+ record.SetString(0, "test");
+ record.SetSqlInt32(1, 2);
+
+ object[] values = new object[1];
+ int columnCount = record.GetValues(values);
+
+ Assert.Equal("test", values[0]);
+ Assert.Equal(1, columnCount);
+ }
+
+ [Fact]
+ public void GetValues_FillsArrayAndRespectColumnOrder()
+ {
+ SqlMetaData[] metaData = new SqlMetaData[]
+ {
+ new SqlMetaData("col1", SqlDbType.NVarChar, 50),
+ new SqlMetaData("col2", SqlDbType.Int)
+ };
+ SqlDataRecord record = new SqlDataRecord(metaData);
+ record.SetString(0, "test");
+ record.SetSqlInt32(1, 2);
+
+ object[] values = new object[2];
+ int columnCount = record.GetValues(values);
+
+ Assert.Equal("test", values[0]);
+ Assert.Equal(2, values[1]);
+ Assert.Equal(2, columnCount);
+ }
+
+ [Fact]
+ public void GetOrdinal_ThrowsAgumentNull_IfNameIsNull()
+ {
+ SqlMetaData[] metaData = new SqlMetaData[]
+ {
+ new SqlMetaData("col1", SqlDbType.NVarChar, 50),
+ new SqlMetaData("col2", SqlDbType.Int)
+ };
+ SqlDataRecord record = new SqlDataRecord(metaData);
+
+ Assert.Throws<ArgumentNullException>(() => record.GetOrdinal(null));
+ }
+
+ [Fact]
+ public void GetOrdinal_ThrowsOutOfRange_IfNameIsNotAColumn()
+ {
+ SqlMetaData[] metaData = new SqlMetaData[]
+ {
+ new SqlMetaData("col1", SqlDbType.NVarChar, 50),
+ new SqlMetaData("col2", SqlDbType.Int)
+ };
+ SqlDataRecord record = new SqlDataRecord(metaData);
+
+
+ Assert.Throws<IndexOutOfRangeException>(() => record.GetOrdinal("outofrange"));
+
+ Assert.Throws<IndexOutOfRangeException>(() => record.GetOrdinal("col1 "));
+
+ }
+
+ [Fact]
+ public void GetOrdinal_ReturnsIndexOfColumn()
+ {
+ SqlMetaData[] metaData = new SqlMetaData[]
+ {
+ new SqlMetaData("col1", SqlDbType.NVarChar, 50),
+ new SqlMetaData("col2", SqlDbType.Int)
+ };
+ SqlDataRecord record = new SqlDataRecord(metaData);
+
+ Assert.Equal(1, record.GetOrdinal("col2"));
+ }
+ [Fact]
+ public void GetOrdinal_ReturnsIndexOfColumn_CaseInsensitive()
+ {
+ SqlMetaData[] metaData = new SqlMetaData[]
+ {
+ new SqlMetaData("col1", SqlDbType.NVarChar, 50),
+ new SqlMetaData("col2", SqlDbType.Int)
+ };
+ SqlDataRecord record = new SqlDataRecord(metaData);
+
+ Assert.Equal(1, record.GetOrdinal("Col2"));
+ }
+
+ [Fact]
+ public void GetChar_ThrowsNotSupported()
+ {
+ SqlMetaData[] metaData = new SqlMetaData[]
+ {
+ new SqlMetaData("col1", SqlDbType.Char, 100)
+ };
+ SqlDataRecord record = new SqlDataRecord(metaData);
+ record.SetValue(0, 'c');
+ Assert.Throws<NotSupportedException>(() => record.GetChar(0));
+ }
+
+ [Theory]
+ [ClassData(typeof(GetXXXBadTypeTestData))]
+ public void GetXXX_ThrowsIfBadType(Func<SqlDataRecord, object> getXXX)
+ {
+ SqlMetaData[] metaData = new SqlMetaData[]
+ {
+ new SqlMetaData("col1", SqlDbType.NVarChar, 1)
+ };
+ SqlDataRecord record = new SqlDataRecord(metaData);
+ record.SetValue(0, "a");
+ Assert.Throws<InvalidCastException>(() => getXXX(record));
+
+ }
+
+ [Theory]
+ [ClassData(typeof(GetXXXCheckValueTestData))]
+ public void GetXXX_ReturnValue(SqlDbType dbType, object value, Func<SqlDataRecord, object> getXXX)
+ {
+ SqlMetaData[] metaData = new SqlMetaData[]
+ {
+ new SqlMetaData("col1", dbType)
+ };
+ SqlDataRecord record = new SqlDataRecord(metaData);
+ record.SetValue(0, value);
+ Assert.Equal(value, getXXX(record));
+
+ }
+ }
+
+ public class GetXXXBadTypeTestData : IEnumerable<object[]>
+ {
+ public IEnumerator<object[]> GetEnumerator()
+ {
+ yield return new object[] { new Func<SqlDataRecord, object>(r => r.GetGuid(0)) };
+ yield return new object[] { new Func<SqlDataRecord, object>(r => r.GetInt16(0)) };
+ yield return new object[] { new Func<SqlDataRecord, object>(r => r.GetInt32(0)) };
+ yield return new object[] { new Func<SqlDataRecord, object>(r => r.GetInt64(0)) };
+ yield return new object[] { new Func<SqlDataRecord, object>(r => r.GetFloat(0)) };
+ yield return new object[] { new Func<SqlDataRecord, object>(r => r.GetDouble(0)) };
+ yield return new object[] { new Func<SqlDataRecord, object>(r => r.GetDecimal(0)) };
+ yield return new object[] { new Func<SqlDataRecord, object>(r => r.GetDateTime(0)) };
+ yield return new object[] { new Func<SqlDataRecord, object>(r => r.GetDateTimeOffset(0)) };
+ yield return new object[] { new Func<SqlDataRecord, object>(r => r.GetTimeSpan(0)) };
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+ }
+
+ public class GetXXXCheckValueTestData : IEnumerable<object[]>
+ {
+ public IEnumerator<object[]> GetEnumerator()
+ {
+ yield return new object[] { SqlDbType.UniqueIdentifier, Guid.NewGuid(), new Func<SqlDataRecord, object>(r => r.GetGuid(0)) };
+ yield return new object[] { SqlDbType.SmallInt, (Int16)123, new Func<SqlDataRecord, object>(r => r.GetInt16(0)) };
+ yield return new object[] { SqlDbType.Int, 123456, new Func<SqlDataRecord, object>(r => r.GetInt32(0)) };
+ yield return new object[] { SqlDbType.BigInt, (Int64)123456789, new Func<SqlDataRecord, object>(r => r.GetInt64(0)) };
+ yield return new object[] { SqlDbType.Float, (Double)1.2, new Func<SqlDataRecord, object>(r => r.GetDouble(0)) };
+ yield return new object[] { SqlDbType.Real, (Single)1.2, new Func<SqlDataRecord, object>(r => r.GetFloat(0)) };
+ yield return new object[] { SqlDbType.Decimal, 1.2m, new Func<SqlDataRecord, object>(r => r.GetDecimal(0)) };
+ yield return new object[] { SqlDbType.DateTime, DateTime.Now, new Func<SqlDataRecord, object>(r => r.GetDateTime(0)) };
+ yield return new object[] { SqlDbType.DateTimeOffset, new DateTimeOffset(DateTime.Now), new Func<SqlDataRecord, object>(r => r.GetDateTimeOffset(0)) };
+ yield return new object[] { SqlDbType.Time, TimeSpan.FromHours(1), new Func<SqlDataRecord, object>(r => r.GetTimeSpan(0)) };
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+ }
+ [SqlUserDefinedType(Format.UserDefined)]
+ public class TestUdt
+ {
}
}
diff --git a/src/System.Data.SqlClient/tests/FunctionalTests/SqlMetaDataTest.cs b/src/System.Data.SqlClient/tests/FunctionalTests/SqlMetaDataTest.cs
new file mode 100644
index 0000000000..e3d6ed6b74
--- /dev/null
+++ b/src/System.Data.SqlClient/tests/FunctionalTests/SqlMetaDataTest.cs
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.SqlServer.Server;
+using Xunit;
+
+namespace System.Data.SqlClient.Tests
+{
+ public class SqlMetaDataTest
+ {
+
+ // Test UDT constrtuctor without tvp extended properties
+ [Fact]
+ public void UdtConstructorTest()
+ {
+ Address address = Address.Parse("123 baker st || Redmond");
+ SqlMetaData metaData = new SqlMetaData("col1", SqlDbType.Udt, typeof(Address), "UdtTestDb.dbo.Address");
+ Assert.Equal("col1", metaData.Name);
+ Assert.Equal(SqlDbType.Udt, metaData.SqlDbType);
+ Assert.Equal(address.GetType(), metaData.Type);
+ Assert.Equal("UdtTestDb.dbo.Address", metaData.TypeName);
+ Assert.False(metaData.UseServerDefault);
+ Assert.False(metaData.IsUniqueKey);
+ Assert.Equal(SortOrder.Unspecified, metaData.SortOrder);
+ Assert.Equal(-1, metaData.SortOrdinal);
+ }
+
+
+ // Test UDT constrtuctor with tvp extended properties
+ [Fact]
+ public void UdtConstructorWithTvpTest()
+ {
+ Address address = Address.Parse("123 baker st || Redmond");
+ SqlMetaData metaData = new SqlMetaData("col2", SqlDbType.Udt, typeof(Address), "UdtTestDb.dbo.Address", true, true, SortOrder.Ascending, 0);
+ Assert.Equal("col2", metaData.Name);
+ Assert.Equal(SqlDbType.Udt, metaData.SqlDbType);
+ Assert.Equal(address.GetType(), metaData.Type);
+ Assert.Equal("UdtTestDb.dbo.Address", metaData.TypeName);
+ Assert.True(metaData.UseServerDefault);
+ Assert.True(metaData.IsUniqueKey);
+ Assert.Equal(SortOrder.Ascending, metaData.SortOrder);
+ Assert.Equal(0, metaData.SortOrdinal);
+ }
+ }
+}
diff --git a/src/System.Data.SqlClient/tests/FunctionalTests/System.Data.SqlClient.Tests.csproj b/src/System.Data.SqlClient/tests/FunctionalTests/System.Data.SqlClient.Tests.csproj
index 2c4c8a0225..8e60f464cd 100644
--- a/src/System.Data.SqlClient/tests/FunctionalTests/System.Data.SqlClient.Tests.csproj
+++ b/src/System.Data.SqlClient/tests/FunctionalTests/System.Data.SqlClient.Tests.csproj
@@ -14,12 +14,14 @@
<Compile Include="BaseProviderAsyncTest\MockCommand.cs" />
<Compile Include="BaseProviderAsyncTest\MockConnection.cs" />
<Compile Include="BaseProviderAsyncTest\MockDataReader.cs" />
+ <Compile Include="SqlCredentialTest.cs" />
<Compile Include="DiagnosticTest.cs" />
<Compile Include="AmbientTransactionFailureTest.cs" />
<Compile Include="ExceptionTest.cs" />
<Compile Include="FakeDiagnosticListenerObserver.cs" />
<Compile Include="SqlBulkCopyColumnMappingCollectionTest.cs" />
<Compile Include="SqlDataRecordTest.cs" />
+ <Compile Include="SqlMetaDataTest.cs" />
<Compile Include="SqlParameterTest.cs" />
<Compile Include="SqlClientFactoryTest.cs" />
<Compile Include="SqlConnectionTest.RetrieveStatistics.cs" />
@@ -30,6 +32,10 @@
<Compile Include="..\ManualTests\DataCommon\DataTestUtility.cs" />
</ItemGroup>
<ItemGroup>
+ <ProjectReference Include="..\ManualTests\SQL\UdtTest\UDTs\Address\Address.csproj">
+ <Project>{d1392b54-998a-4f27-bc17-4ce149117bcc}</Project>
+ <Name>Address</Name>
+ </ProjectReference>
<ProjectReference Include="..\Tools\TDS\TDS.Servers\TDS.Servers.csproj">
<Name>TDS.Servers</Name>
</ProjectReference>
diff --git a/src/System.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs b/src/System.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs
index 2426927935..2d43534479 100644
--- a/src/System.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs
+++ b/src/System.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs
@@ -60,19 +60,9 @@ namespace System.Data.SqlClient.ManualTesting.Tests
return name;
}
- public static bool IsLocalDBInstalled()
- {
- string localDBInstallationFlag = Environment.GetEnvironmentVariable("TEST_LOCALDB_INSTALLED");
- if (!string.IsNullOrWhiteSpace(localDBInstallationFlag))
- {
- int result;
- if (int.TryParse(localDBInstallationFlag.Trim(), out result))
- {
- return result == 1;
- }
- }
- return false;
- }
+ public static bool IsLocalDBInstalled() => int.TryParse(Environment.GetEnvironmentVariable("TEST_LOCALDB_INSTALLED"), out int result) ? result == 1 : false;
+
+ public static bool IsIntegratedSecuritySetup() => int.TryParse(Environment.GetEnvironmentVariable("TEST_INTEGRATEDSECURITY_SETUP"), out int result) ? result == 1 : false;
private static bool CheckException<TException>(Exception ex, string exceptionMessage, bool innerExceptionMustBeNull) where TException : Exception
{
@@ -151,7 +141,7 @@ namespace System.Data.SqlClient.ManualTesting.Tests
return ex;
}
- public static TException ExpectFailure<TException>(Action actionThatFails, string exceptionMessage = null, bool innerExceptionMustBeNull = false, Func<TException, bool> customExceptionVerifier = null) where TException : Exception
+ public static TException ExpectFailure<TException>(Action actionThatFails, string[] exceptionMessages, bool innerExceptionMustBeNull = false, Func<TException, bool> customExceptionVerifier = null) where TException : Exception
{
try
{
@@ -161,14 +151,14 @@ namespace System.Data.SqlClient.ManualTesting.Tests
}
catch (Exception ex)
{
- if ((CheckException<TException>(ex, exceptionMessage, innerExceptionMustBeNull)) && ((customExceptionVerifier == null) || (customExceptionVerifier(ex as TException))))
+ foreach (string exceptionMessage in exceptionMessages)
{
- return (ex as TException);
- }
- else
- {
- throw;
+ if ((CheckException<TException>(ex, exceptionMessage, innerExceptionMustBeNull)) && ((customExceptionVerifier == null) || (customExceptionVerifier(ex as TException))))
+ {
+ return (ex as TException);
+ }
}
+ throw;
}
}
diff --git a/src/System.Data.SqlClient/tests/ManualTests/SQL/AdapterTest/AdapterTest.cs b/src/System.Data.SqlClient/tests/ManualTests/SQL/AdapterTest/AdapterTest.cs
index 50784553dd..10a590dffe 100644
--- a/src/System.Data.SqlClient/tests/ManualTests/SQL/AdapterTest/AdapterTest.cs
+++ b/src/System.Data.SqlClient/tests/ManualTests/SQL/AdapterTest/AdapterTest.cs
@@ -18,6 +18,8 @@ namespace System.Data.SqlClient.ManualTesting.Tests
// data value and server consts
private const string MagicName = "Magic";
+ // Use a union statement so that Identity columns don't carry over
+ private const string _createTableQuery = "select * into {0} from Employees where EmployeeID < 3 union all (select * from Employees where 1 = 0)";
private string _tempTable;
private string _tempKey;
@@ -567,20 +569,20 @@ namespace System.Data.SqlClient.ManualTesting.Tests
[CheckConnStrSetupFact]
public void UpdateTest()
{
- try
+ using (SqlConnection conn = new SqlConnection(DataTestUtility.TcpConnStr))
+ using (SqlCommand cmd = conn.CreateCommand())
+ using (SqlDataAdapter adapter = new SqlDataAdapter())
+ using (SqlDataAdapter adapterVerify = new SqlDataAdapter())
{
- using (SqlConnection conn = new SqlConnection(DataTestUtility.TcpConnStr))
- using (SqlCommand cmd = conn.CreateCommand())
- using (SqlDataAdapter adapter = new SqlDataAdapter())
- using (SqlDataAdapter adapterVerify = new SqlDataAdapter())
- {
- conn.Open();
+ conn.Open();
- cmd.CommandText = string.Format("SELECT EmployeeID, LastName, FirstName, Title, Address, City, Region, PostalCode, Country into {0} from Employees where EmployeeID < 3", _tempTable);
- cmd.ExecuteNonQuery();
- cmd.CommandText = "alter table " + _tempTable + " add constraint " + _tempKey + " primary key (EmployeeID)";
- cmd.ExecuteNonQuery();
+ cmd.CommandText = string.Format(_createTableQuery, _tempTable);
+ cmd.ExecuteNonQuery();
+ cmd.CommandText = "alter table " + _tempTable + " add constraint " + _tempKey + " primary key (EmployeeID)";
+ cmd.ExecuteNonQuery();
+ try
+ {
PrepareUpdateCommands(adapter, conn, _tempTable);
adapter.SelectCommand = new SqlCommand(string.Format("SELECT EmployeeID, LastName, FirstName, Title, Address, City, Region, PostalCode, Country from {0} where EmployeeID < 3", _tempTable), conn);
@@ -639,10 +641,10 @@ namespace System.Data.SqlClient.ManualTesting.Tests
dataSet.AcceptChanges();
}
- }
- finally
- {
- ExecuteNonQueryCommand("DROP TABLE " + _tempTable);
+ finally
+ {
+ ExecuteNonQueryCommand("DROP TABLE " + _tempTable);
+ }
}
}
@@ -656,15 +658,15 @@ namespace System.Data.SqlClient.ManualTesting.Tests
using (SqlDataAdapter adapter = new SqlDataAdapter())
using (SqlDataAdapter adapterVerify = new SqlDataAdapter())
{
- try
- {
- conn.Open();
+ conn.Open();
- cmd.CommandText = "SELECT EmployeeID, LastName, FirstName, Title, Address, City, Region, PostalCode, Country into " + _tempTable + " from Employees where EmployeeID < 3";
- cmd.ExecuteNonQuery();
- cmd.CommandText = "alter table " + _tempTable + " add constraint " + _tempKey + " primary key (EmployeeID)";
- cmd.ExecuteNonQuery();
+ cmd.CommandText = string.Format(_createTableQuery, _tempTable);
+ cmd.ExecuteNonQuery();
+ cmd.CommandText = "alter table " + _tempTable + " add constraint " + _tempKey + " primary key (EmployeeID)";
+ cmd.ExecuteNonQuery();
+ try
+ {
PrepareUpdateCommands(adapter, conn, _tempTable);
adapter.SelectCommand = new SqlCommand("SELECT EmployeeID, LastName, FirstName, Title, Address, City, Region, PostalCode, Country FROM " + _tempTable + " WHERE EmployeeID < 3", conn);
@@ -762,16 +764,16 @@ namespace System.Data.SqlClient.ManualTesting.Tests
string spDropInsert = "DROP PROCEDURE sp_insert" + _tempTable;
bool dropSP = false;
- try
+
+ using (SqlDataAdapter adapter = new SqlDataAdapter())
+ using (SqlConnection conn = new SqlConnection(DataTestUtility.TcpConnStr))
+ using (SqlCommand cmd = new SqlCommand(null, conn))
+ using (SqlCommand temp = new SqlCommand("SELECT id, LastName, FirstName into " + _tempTable + " from ident", conn))
+ using (SqlCommand tableClean = new SqlCommand("", conn))
{
- using (SqlDataAdapter adapter = new SqlDataAdapter())
- using (SqlConnection conn = new SqlConnection(DataTestUtility.TcpConnStr))
- using (SqlCommand cmd = new SqlCommand(null, conn))
- using (SqlCommand temp = new SqlCommand("SELECT id, LastName, FirstName into " + _tempTable + " from ident", conn))
- using (SqlCommand tableClean = new SqlCommand("", conn))
+ ExecuteNonQueryCommand(createIdentTable);
+ try
{
- ExecuteNonQueryCommand(createIdentTable);
-
adapter.InsertCommand = new SqlCommand()
{
CommandText = "sp_insert" + _tempTable,
@@ -827,15 +829,15 @@ namespace System.Data.SqlClient.ManualTesting.Tests
(i1 != 0) && (i2 != 0) && (i2 == (i1 + 1)),
string.Format("FAILED: UpdateRefresh, i2 should equal (i1 + 1). i1: {0}. i2: {1}.", i1, i2));
}
- }
- finally
- {
- if (dropSP)
+ finally
{
- ExecuteNonQueryCommand(spDropInsert);
- ExecuteNonQueryCommand("DROP TABLE " + _tempTable);
+ if (dropSP)
+ {
+ ExecuteNonQueryCommand(spDropInsert);
+ ExecuteNonQueryCommand("DROP TABLE " + _tempTable);
+ }
+ ExecuteNonQueryCommand("DROP TABLE ident");
}
- ExecuteNonQueryCommand("DROP TABLE ident");
}
}
@@ -979,21 +981,20 @@ namespace System.Data.SqlClient.ManualTesting.Tests
[CheckConnStrSetupFact]
public void AutoGenUpdateTest()
{
- try
+ using (SqlConnection conn = new SqlConnection(DataTestUtility.TcpConnStr))
+ using (SqlCommand cmd = conn.CreateCommand())
+ using (SqlDataAdapter adapter = new SqlDataAdapter())
+ using (SqlDataAdapter adapterVerify = new SqlDataAdapter())
{
- using (SqlConnection conn = new SqlConnection(DataTestUtility.TcpConnStr))
- using (SqlCommand cmd = conn.CreateCommand())
- using (SqlDataAdapter adapter = new SqlDataAdapter())
- using (SqlDataAdapter adapterVerify = new SqlDataAdapter())
- {
- conn.Open();
-
- cmd.CommandText = string.Format("SELECT EmployeeID, LastName, FirstName, Title, Address, City, Region, PostalCode, Country into {0} from Employees where EmployeeID < 3", _tempTable);
- cmd.ExecuteNonQuery();
+ conn.Open();
- cmd.CommandText = "alter table " + _tempTable + " add constraint " + _tempKey + " primary key (EmployeeID)";
- cmd.ExecuteNonQuery();
+ cmd.CommandText = string.Format(_createTableQuery, _tempTable);
+ cmd.ExecuteNonQuery();
+ cmd.CommandText = "alter table " + _tempTable + " add constraint " + _tempKey + " primary key (EmployeeID)";
+ cmd.ExecuteNonQuery();
+ try
+ {
adapter.SelectCommand = new SqlCommand(string.Format("SELECT EmployeeID, LastName, FirstName, Title, Address, City, Region, PostalCode, Country from {0} where EmployeeID < 3", _tempTable), conn);
adapterVerify.SelectCommand = new SqlCommand("SELECT LastName, FirstName FROM " + _tempTable + " where FirstName='" + MagicName + "'", conn);
@@ -1041,10 +1042,10 @@ namespace System.Data.SqlClient.ManualTesting.Tests
// Verify that set is empty
VerifyUpdateRow(adapterVerify, dataSetVerify, 0, _tempTable);
}
- }
- finally
- {
- ExecuteNonQueryCommand("DROP TABLE " + _tempTable);
+ finally
+ {
+ ExecuteNonQueryCommand("DROP TABLE " + _tempTable);
+ }
}
}
@@ -1100,16 +1101,15 @@ namespace System.Data.SqlClient.ManualTesting.Tests
using (SqlDataAdapter adapter = new SqlDataAdapter())
using (SqlDataAdapter adapterVerify = new SqlDataAdapter())
{
- try
- {
- conn.Open();
-
- cmd.CommandText = "SELECT EmployeeID, LastName, FirstName, Title, Address, City, Region, PostalCode, Country into " + _tempTable + " from Employees where EmployeeID < 3";
- cmd.ExecuteNonQuery();
+ conn.Open();
- cmd.CommandText = "alter table " + _tempTable + " add constraint " + _tempKey + " primary key (EmployeeID)";
- cmd.ExecuteNonQuery();
+ cmd.CommandText = string.Format(_createTableQuery, _tempTable);
+ cmd.ExecuteNonQuery();
+ cmd.CommandText = "alter table " + _tempTable + " add constraint " + _tempKey + " primary key (EmployeeID)";
+ cmd.ExecuteNonQuery();
+ try
+ {
adapter.SelectCommand = new SqlCommand("SELECT EmployeeID, LastName, FirstName, Title, Address, City, Region, PostalCode, Country FROM " + _tempTable + " WHERE EmployeeID < 3", conn);
adapterVerify.SelectCommand = new SqlCommand("SELECT LastName, FirstName FROM " + _tempTable + " where FirstName='" + MagicName + "'", conn);
diff --git a/src/System.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncTest.cs b/src/System.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncTest.cs
index d96fcf493a..1c47a5cd32 100644
--- a/src/System.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncTest.cs
+++ b/src/System.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/AsyncTest.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Diagnostics;
using System.Threading.Tasks;
using Xunit;
@@ -9,87 +10,96 @@ namespace System.Data.SqlClient.ManualTesting.Tests
{
public static class AsyncTest
{
- private const int TaskTimeout = 5000;
-
[CheckConnStrSetupFact]
- public static void ExecuteTest()
+ public static void TestReadAsyncTimeConsumed()
{
- SqlCommand com = new SqlCommand("select * from Orders");
- SqlConnection con = new SqlConnection(DataTestUtility.TcpConnStr);
-
- com.Connection = con;
-
- con.Open();
-
- Task<SqlDataReader> readerTask = com.ExecuteReaderAsync();
- bool taskCompleted = readerTask.Wait(TaskTimeout);
- Assert.True(taskCompleted, "FAILED: ExecuteReaderAsync Task did not complete successfully.");
-
- SqlDataReader reader = readerTask.Result;
-
- int rows;
- for (rows = 0; reader.Read(); rows++) ;
-
- Assert.True(rows == 830, string.Format("FAILED: ExecuteTest reader had wrong number of rows. Expected: {0}. Actual: {1}", 830, rows));
-
- reader.Dispose();
- con.Close();
+ const string sql = "SET NOCOUNT ON"
+ + " SELECT 'a'"
+ + " DECLARE @t DATETIME = SYSDATETIME()"
+ + " WHILE DATEDIFF(s, @t, SYSDATETIME()) < 20 BEGIN"
+ + " SELECT 2 x INTO #y"
+ + " DROP TABLE #y"
+ + " END"
+ + " SELECT 'b'";
+ Task<double> t = RunReadAsync(sql);
+ double elapsedSync = RunReadSync(sql);
+ t.Wait();
+ double elapsedAsync = t.Result;
+ Assert.True(elapsedAsync < elapsedSync, "Asynchronous operation should be finished quicker than synchronous one");
+ int limit = 100;
+ Assert.True(elapsedAsync < limit, $"Asynchronous operation should be finished within {limit}ms");
}
- [CheckConnStrSetupFact]
- public static void FailureTest()
+ private static async Task<double> RunReadAsync(string sql)
{
- bool failure = false;
- bool taskCompleted = false;
-
- SqlCommand com = new SqlCommand("select * from Orders");
- SqlConnection con = new SqlConnection((new SqlConnectionStringBuilder(DataTestUtility.TcpConnStr) { Pooling = false }).ConnectionString);
- com.Connection = con;
- con.Open();
-
- Task<int> nonQueryTask = com.ExecuteNonQueryAsync();
- try
+ double maxElapsedTimeMillisecond = 0;
+ using (SqlConnection connection = new SqlConnection(DataTestUtility.TcpConnStr))
{
- com.ExecuteNonQueryAsync().Wait(TaskTimeout);
- }
- catch (AggregateException agrEx)
- {
- agrEx.Handle(
- (ex) =>
+ await connection.OpenAsync();
+ using (SqlCommand command = connection.CreateCommand())
+ {
+ command.CommandText = sql;
+ using (SqlDataReader reader = await command.ExecuteReaderAsync())
{
- Assert.True(ex is InvalidOperationException, "FAILED: Thrown exception for ExecuteNonQueryAsync was not an InvalidOperationException");
- failure = true;
- return true;
- });
+ Task<bool> t;
+ Stopwatch stopwatch = new Stopwatch();
+ do
+ {
+ do
+ {
+ stopwatch.Start();
+ t = reader.ReadAsync();
+ stopwatch.Stop();
+ double elased = stopwatch.Elapsed.TotalMilliseconds;
+ if (maxElapsedTimeMillisecond < elased)
+ {
+ maxElapsedTimeMillisecond = elased;
+ }
+ }
+ while (await t);
+ }
+ while (reader.NextResult());
+ }
+ }
}
- Assert.True(failure, "FAILED: No exception thrown after trying second ExecuteNonQueryAsync.");
- failure = false;
- taskCompleted = nonQueryTask.Wait(TaskTimeout);
- Assert.True(taskCompleted, "FAILED: ExecuteNonQueryAsync Task did not complete successfully.");
+ return maxElapsedTimeMillisecond;
+ }
- Task<SqlDataReader> readerTask = com.ExecuteReaderAsync();
- try
- {
- com.ExecuteReaderAsync().Wait(TaskTimeout);
- }
- catch (AggregateException agrEx)
+ private static double RunReadSync(string sql)
+ {
+ double maxElapsedTimeMillisecond = 0;
+ using (SqlConnection connection = new SqlConnection(DataTestUtility.TcpConnStr))
{
- agrEx.Handle(
- (ex) =>
+ connection.Open();
+ using (SqlCommand command = connection.CreateCommand())
+ {
+ command.CommandText = sql;
+ using (SqlDataReader reader = command.ExecuteReader())
{
- Assert.True(ex is InvalidOperationException, "FAILED: Thrown exception for ExecuteReaderAsync was not an InvalidOperationException: " + ex);
- failure = true;
- return true;
- });
+ bool result;
+ Stopwatch stopwatch = new Stopwatch();
+ do
+ {
+ do
+ {
+ stopwatch.Start();
+ result = reader.Read();
+ stopwatch.Stop();
+ double elased = stopwatch.Elapsed.TotalMilliseconds;
+ if (maxElapsedTimeMillisecond < elased)
+ {
+ maxElapsedTimeMillisecond = elased;
+ }
+ }
+ while (result);
+ }
+ while (reader.NextResult());
+ }
+ }
}
- Assert.True(failure, "FAILED: No exception thrown after trying second ExecuteReaderAsync.");
-
- taskCompleted = readerTask.Wait(TaskTimeout);
- Assert.True(taskCompleted, "FAILED: ExecuteReaderAsync Task did not complete successfully.");
- readerTask.Result.Dispose();
- con.Close();
+ return maxElapsedTimeMillisecond;
}
}
} \ No newline at end of file
diff --git a/src/System.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/BeginExecAsyncTest.cs b/src/System.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/BeginExecAsyncTest.cs
index a73ccfaacc..79863b5719 100644
--- a/src/System.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/BeginExecAsyncTest.cs
+++ b/src/System.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/BeginExecAsyncTest.cs
@@ -2,31 +2,41 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Threading.Tasks;
using Xunit;
namespace System.Data.SqlClient.ManualTesting.Tests
{
public static class BeginExecAsyncTest
{
- private static string commandText =
- "INSERT INTO[dbo].[Shippers] " +
- "([CompanyName] " +
- ",[Phone]) " +
- "VALUES " +
- "('Acme Inc.' " +
- ",'555-1212'); " +
- "WAITFOR DELAY '0:0:3';" +
- "DELETE FROM dbo.Shippers WHERE ShipperID > 3;";
-
+ private static string GenerateCommandText()
+ {
+ int suffix = (new Random()).Next(5000);
+
+ string commandText =
+ $"CREATE TABLE #Shippers{suffix}(" +
+ $"[ShipperID][int] NULL," +
+ $"[CompanyName] [nvarchar] (40) NOT NULL," +
+ $"[Phone] [nvarchar] (24) NULL )" +
+ $"INSERT INTO #Shippers{suffix}" +
+ $"([CompanyName] " +
+ $",[Phone])" +
+ $"VALUES " +
+ $"('Acme Inc.' " +
+ $",'555-1212'); " +
+ $"WAITFOR DELAY '0:0:3'; " +
+ $"DELETE FROM #Shippers{suffix} WHERE ShipperID > 3;";
+
+ return commandText;
+ }
+
[CheckConnStrSetupFact]
public static void ExecuteTest()
{
using (SqlConnection connection = new SqlConnection(DataTestUtility.TcpConnStr))
{
try
- {
- SqlCommand command = new SqlCommand(commandText, connection);
+ {
+ SqlCommand command = new SqlCommand(GenerateCommandText(), connection);
connection.Open();
IAsyncResult result = command.BeginExecuteNonQuery();
@@ -63,7 +73,7 @@ namespace System.Data.SqlClient.ManualTesting.Tests
using (SqlConnection connection = new SqlConnection(DataTestUtility.TcpConnStr))
{
bool caughtException = false;
- SqlCommand command = new SqlCommand(commandText, connection);
+ SqlCommand command = new SqlCommand(GenerateCommandText(), connection);
connection.Open();
//Try to execute a synchronous query on same command
diff --git a/src/System.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/XmlReaderAsyncTest.cs b/src/System.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/XmlReaderAsyncTest.cs
new file mode 100644
index 0000000000..0c6c723cd5
--- /dev/null
+++ b/src/System.Data.SqlClient/tests/ManualTests/SQL/AsyncTest/XmlReaderAsyncTest.cs
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Xml;
+using Xunit;
+
+namespace System.Data.SqlClient.ManualTesting.Tests
+{
+ public static class XmlReaderAsyncTest
+ {
+ private static string commandText =
+ "SELECT * from dbo.Customers FOR XML AUTO, XMLDATA;";
+
+ [CheckConnStrSetupFact]
+ public static void ExecuteTest()
+ {
+ using (SqlConnection connection = new SqlConnection(DataTestUtility.TcpConnStr))
+ {
+ SqlCommand command = new SqlCommand(commandText, connection);
+ connection.Open();
+
+ IAsyncResult result = command.BeginExecuteXmlReader();
+ while (!result.IsCompleted)
+ {
+ System.Threading.Thread.Sleep(100);
+ }
+
+ XmlReader reader = command.EndExecuteXmlReader(result);
+
+ reader.ReadToDescendant("dbo.Customers");
+ Assert.Equal("ALFKI", reader["CustomerID"]);
+ }
+ }
+
+ [CheckConnStrSetupFact]
+ public static void ExceptionTest()
+ {
+ using (SqlConnection connection = new SqlConnection(DataTestUtility.TcpConnStr))
+ {
+ SqlCommand command = new SqlCommand(commandText, connection);
+ connection.Open();
+
+ //Try to execute a synchronous query on same command
+ IAsyncResult result = command.BeginExecuteXmlReader();
+
+ Assert.Throws<InvalidOperationException>( delegate { command.ExecuteXmlReader(); });
+
+ while (!result.IsCompleted)
+ {
+ System.Threading.Thread.Sleep(100);
+ }
+
+ XmlReader reader = command.EndExecuteXmlReader(result);
+
+ reader.ReadToDescendant("dbo.Customers");
+ Assert.Equal("ALFKI", reader["CustomerID"]);
+ }
+ }
+ }
+}
diff --git a/src/System.Data.SqlClient/tests/ManualTests/SQL/CommandCancelTest/CommandCancelTest.cs b/src/System.Data.SqlClient/tests/ManualTests/SQL/CommandCancelTest/CommandCancelTest.cs
index 17a28e53ee..1fb522e991 100644
--- a/src/System.Data.SqlClient/tests/ManualTests/SQL/CommandCancelTest/CommandCancelTest.cs
+++ b/src/System.Data.SqlClient/tests/ManualTests/SQL/CommandCancelTest/CommandCancelTest.cs
@@ -125,16 +125,17 @@ namespace System.Data.SqlClient.ManualTesting.Tests
var command = con.CreateCommand();
command.CommandText = "select * from orders; waitfor delay '00:00:08'; select * from customers";
- Thread rThread1 = new Thread(ExecuteCommandCancelExpected);
- Thread rThread2 = new Thread(CancelSharedCommand);
Barrier threadsReady = new Barrier(2);
object state = new Tuple<bool, SqlCommand, Barrier>(async, command, threadsReady);
- rThread1.Start(state);
- rThread2.Start(state);
- rThread1.Join();
- rThread2.Join();
+ Task[] tasks = new Task[2];
+ tasks[0] = new Task(ExecuteCommandCancelExpected, state);
+ tasks[1] = new Task(CancelSharedCommand, state);
+ tasks[0].Start();
+ tasks[1].Start();
+ Task.WaitAll(tasks, 15 * 1000);
+
CommandCancelTest.VerifyConnection(command);
}
}
@@ -149,7 +150,7 @@ namespace System.Data.SqlClient.ManualTesting.Tests
cmd.CommandText = "WAITFOR DELAY '00:00:30';select * from Customers";
string errorMessage = SystemDataResourceManager.Instance.SQL_Timeout;
- DataTestUtility.ExpectFailure<SqlException>(() => cmd.ExecuteReader(), errorMessage);
+ DataTestUtility.ExpectFailure<SqlException>(() => cmd.ExecuteReader(), new string[] { errorMessage });
VerifyConnection(cmd);
}
@@ -208,6 +209,8 @@ namespace System.Data.SqlClient.ManualTesting.Tests
Barrier threadsReady = stateTuple.Item3;
string errorMessage = SystemDataResourceManager.Instance.SQL_OperationCancelled;
+ string errorMessageSevereFailure = SystemDataResourceManager.Instance.SQL_SevereError;
+
DataTestUtility.ExpectFailure<SqlException>(() =>
{
threadsReady.SignalAndWait();
@@ -220,7 +223,8 @@ namespace System.Data.SqlClient.ManualTesting.Tests
}
} while (r.NextResult());
}
- }, errorMessage);
+ }, new string[] { errorMessage, errorMessageSevereFailure });
+
}
private static void CancelSharedCommand(object state)
diff --git a/src/System.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ExceptionTest.cs b/src/System.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ExceptionTest.cs
index fedaf7b403..01388e1051 100644
--- a/src/System.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ExceptionTest.cs
+++ b/src/System.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ExceptionTest.cs
@@ -47,7 +47,22 @@ namespace System.Data.SqlClient.ManualTesting.Tests
}
}
- [CheckConnStrSetupFact]
+ private static bool EmployeesTableHasFullTextIndex()
+ {
+ if (DataTestUtility.TcpConnStr == null)
+ return false;
+
+ using (SqlConnection conn = new SqlConnection(DataTestUtility.TcpConnStr))
+ using (SqlCommand cmd = conn.CreateCommand())
+ {
+ conn.Open();
+ cmd.CommandText = "SELECT object_id FROM sys.fulltext_indexes WHERE object_id = object_id('Northwind.dbo.Employees')";
+
+ return (cmd.ExecuteScalar() != null);
+ }
+ }
+
+ [ConditionalFact(nameof(EmployeesTableHasFullTextIndex))]
public static void WarningsBeforeRowsTest()
{
bool hitWarnings = false;
diff --git a/src/System.Data.SqlClient/tests/ManualTests/SQL/IntegratedAuthenticationTest/IntegratedAuthenticationTest.cs b/src/System.Data.SqlClient/tests/ManualTests/SQL/IntegratedAuthenticationTest/IntegratedAuthenticationTest.cs
index 7c72323407..ad5919b696 100644
--- a/src/System.Data.SqlClient/tests/ManualTests/SQL/IntegratedAuthenticationTest/IntegratedAuthenticationTest.cs
+++ b/src/System.Data.SqlClient/tests/ManualTests/SQL/IntegratedAuthenticationTest/IntegratedAuthenticationTest.cs
@@ -15,7 +15,11 @@ namespace System.Data.SqlClient.ManualTesting.Tests
{
public static class IntegratedAuthenticationTest
{
- [CheckConnStrSetupFact]
+ private static bool IsIntegratedSecurityEnvironmentSet() => DataTestUtility.IsIntegratedSecuritySetup();
+ private static bool AreConnectionStringsSetup() => DataTestUtility.AreConnStringsSetup();
+
+
+ [ConditionalFact(nameof(IsIntegratedSecurityEnvironmentSet),nameof(AreConnectionStringsSetup))]
public static void IntegratedAuthenticationTestWithConnectionPooling()
{
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(DataTestUtility.TcpConnStr);
@@ -24,7 +28,7 @@ namespace System.Data.SqlClient.ManualTesting.Tests
TryOpenConnectionWithIntegratedAuthentication(builder.ConnectionString);
}
- [CheckConnStrSetupFact]
+ [ConditionalFact(nameof(IsIntegratedSecurityEnvironmentSet), nameof(AreConnectionStringsSetup))]
public static void IntegratedAuthenticationTestWithOutConnectionPooling()
{
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(DataTestUtility.TcpConnStr);
diff --git a/src/System.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/SqlParameterTest_DebugMode.bsl b/src/System.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/SqlParameterTest_DebugMode.bsl
index 92456fd6a2..44ce911eca 100644
--- a/src/System.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/SqlParameterTest_DebugMode.bsl
+++ b/src/System.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/SqlParameterTest_DebugMode.bsl
@@ -483,30 +483,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 1 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -515,30 +499,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 2 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -547,26 +515,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 28
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 3 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -575,28 +531,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 4 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -605,28 +547,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 5 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -635,26 +563,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 28
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 6 ++++++++
SqlException creating objects: 1701
@@ -666,26 +582,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 28
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 8 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -694,26 +598,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 28
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 9 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -722,30 +614,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 10 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -754,30 +630,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 11 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -786,26 +646,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 28
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 12 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -814,28 +662,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 13 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -844,28 +678,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 14 ++++++++
SqlException creating objects: 1701
@@ -880,26 +700,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 28
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 17 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -908,26 +716,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 28
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 18 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -936,30 +732,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 19 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -968,30 +748,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 20 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -1001,19 +765,13 @@ Matches = 168
------DataTables---------
Matches = 14
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
Matches = 28
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
Matches = 14
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 21 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -1023,23 +781,13 @@ Matches = 168
------DataTables---------
Matches = 14
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 22 ++++++++
SqlException creating objects: 1701
@@ -1092,29 +840,15 @@ Mismatch: Source = 1/1/1753 12:00:00 AM, result = , metadata=SteAttributeKey=Sma
Row=9, Column=5
Matches = 162
------DataTables---------
-SqlException: The conversion of a datetime2 data type to a smalldatetime data type resulted in an out-of-range value.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 242
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 28
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 26 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -1123,26 +857,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 28
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 27 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -1210,36 +932,16 @@ Mismatch: Source = 922337203685477.5807, result = , metadata=SteAttributeKey=Sma
Row=11, Column=9
Matches = 158
------DataTables---------
-SqlException: The conversion of a datetime2 data type to a smalldatetime data type resulted in an out-of-range value.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: Arithmetic overflow error converting numeric to data type smallmoney.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 242
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8115
------- Sort order + uniqueness #1: simple -------
-------------
0 Z-value 3/1/2000 12:00:00 AM 5
diff --git a/src/System.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/SqlParameterTest_ReleaseMode.bsl b/src/System.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/SqlParameterTest_ReleaseMode.bsl
index 9ab83a0dfc..c28acb4270 100644
--- a/src/System.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/SqlParameterTest_ReleaseMode.bsl
+++ b/src/System.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/SqlParameterTest_ReleaseMode.bsl
@@ -22,30 +22,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 1 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -54,30 +38,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 2 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -86,26 +54,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 28
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 3 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -114,28 +70,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 4 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -144,28 +86,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 5 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -174,26 +102,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 28
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 6 ++++++++
SqlException creating objects: 1701
@@ -205,26 +121,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 28
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 8 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -233,26 +137,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 28
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 9 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -261,30 +153,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 10 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -293,30 +169,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 11 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -325,26 +185,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 28
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 12 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -353,28 +201,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 13 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -383,28 +217,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 14 ++++++++
SqlException creating objects: 1701
@@ -419,26 +239,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 28
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 17 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -447,26 +255,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 28
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 18 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -475,30 +271,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 19 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -507,30 +287,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 20 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -540,19 +304,13 @@ Matches = 168
------DataTables---------
Matches = 14
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
Matches = 28
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
Matches = 14
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 21 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -562,23 +320,13 @@ Matches = 168
------DataTables---------
Matches = 14
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 22 ++++++++
SqlException creating objects: 1701
@@ -631,29 +379,15 @@ Mismatch: Source = 1/1/1753 12:00:00 AM, result = , metadata=SteAttributeKey=Sma
Row=9, Column=5
Matches = 162
------DataTables---------
-SqlException: The conversion of a datetime2 data type to a smalldatetime data type resulted in an out-of-range value.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 242
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 28
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 26 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -662,26 +396,14 @@ Matches = 168
Matches = 168
------DataTables---------
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 28
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
Matches = 14
+++++++ Iteration 27 ++++++++
------IEnumerable<SqlDataRecord>---------
@@ -749,36 +471,16 @@ Mismatch: Source = 922337203685477.5807, result = , metadata=SteAttributeKey=Sma
Row=11, Column=9
Matches = 158
------DataTables---------
-SqlException: The conversion of a datetime2 data type to a smalldatetime data type resulted in an out-of-range value.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: String or binary data would be truncated.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
-SqlException: Arithmetic overflow error converting numeric to data type smallmoney.
-The data for table-valued parameter "@tvp" doesn't conform to the table type of the parameter.
-The statement has been terminated.
+SqlException. Error Code: 242
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8152
+SqlException. Error Code: 8115
------- Sort order + uniqueness #1: simple -------
-------------
0 Z-value 3/1/2000 12:00:00 AM 5
diff --git a/src/System.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/TvpTest.cs b/src/System.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/TvpTest.cs
index ec33af81f7..d8bf2d542a 100644
--- a/src/System.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/TvpTest.cs
+++ b/src/System.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/TvpTest.cs
@@ -41,6 +41,7 @@ namespace System.Data.SqlClient.ManualTesting.Tests
// data value and server consts
private string _connStr;
+ [ActiveIssue(27858, TestPlatforms.AnyUnix)]
[CheckConnStrSetupFact]
public void TestMain()
{
@@ -1115,7 +1116,7 @@ namespace System.Data.SqlClient.ManualTesting.Tests
}
catch (SqlException se)
{
- Console.WriteLine("SqlException: {0}", se.Message);
+ Console.WriteLine("SqlException. Error Code: {0}", se.Number);
}
catch (InvalidOperationException ioe)
{
@@ -1625,4 +1626,4 @@ namespace System.Data.SqlClient.ManualTesting.Tests
}
}
-} \ No newline at end of file
+}
diff --git a/src/System.Data.SqlClient/tests/ManualTests/SQL/SqlCredentialTest/SqlCredentialTest.cs b/src/System.Data.SqlClient/tests/ManualTests/SQL/SqlCredentialTest/SqlCredentialTest.cs
new file mode 100644
index 0000000000..4856ae5552
--- /dev/null
+++ b/src/System.Data.SqlClient/tests/ManualTests/SQL/SqlCredentialTest/SqlCredentialTest.cs
@@ -0,0 +1,157 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Data.SqlClient;
+using System.Data.SqlClient.ManualTesting.Tests;
+using System.Linq;
+using System.Security;
+using System.Text;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.Data.SqlClient.ManualTesting.Tests
+{
+ public static class SqlCredentialTest
+ {
+
+ [CheckConnStrSetupFact]
+ public static void CreateSqlConnectionWithCredential()
+ {
+ var user = "u" + Guid.NewGuid().ToString().Replace("-", "");
+ var passStr = "Pax561O$T5K#jD";
+
+ try
+ {
+ createTestUser(user, passStr);
+
+ var csb = new SqlConnectionStringBuilder(DataTestUtility.TcpConnStr);
+ csb.Remove("User ID");
+ csb.Remove("Password");
+ csb.IntegratedSecurity = false;
+
+ var password = new SecureString();
+ passStr.ToCharArray().ToList().ForEach(x => password.AppendChar(x));
+ password.MakeReadOnly();
+
+ using (var conn = new SqlConnection(csb.ConnectionString, new SqlCredential(user, password)))
+ using (var cmd = new SqlCommand("SELECT 1;", conn))
+ {
+ conn.Open();
+ Assert.Equal(1, cmd.ExecuteScalar());
+ }
+ }
+ finally
+ {
+ dropTestUser(user);
+ }
+ }
+
+ [CheckConnStrSetupFact]
+ public static void SqlConnectionChangePasswordPlaintext()
+ {
+ var user = "u" + Guid.NewGuid().ToString().Replace("-", "");
+ var pass = "!21Ja3Ims7LI&n";
+ var newPass = "fmVCNf@24Dg*8j";
+
+ try
+ {
+ createTestUser(user, pass);
+
+ var csb = new SqlConnectionStringBuilder(DataTestUtility.TcpConnStr);
+ csb.UserID = user;
+ csb.Password = pass;
+ csb.IntegratedSecurity = false;
+
+ // Change password and try opening connection.
+ SqlConnection.ChangePassword(csb.ConnectionString, newPass);
+ csb.Password = newPass;
+
+ using (var conn = new SqlConnection(csb.ConnectionString))
+ using (var cmd = new SqlCommand("SELECT 1;", conn))
+ {
+ conn.Open();
+ Assert.Equal(1, cmd.ExecuteScalar());
+ }
+ }
+ finally
+ {
+ dropTestUser(user);
+ }
+ }
+
+ [CheckConnStrSetupFact]
+ public static void SqlConnectionChangePasswordSecureString()
+ {
+ var user = "u" + Guid.NewGuid().ToString().Replace("-", "");
+ var passStr = "tcM0qB^izt%3u7";
+ var newPassStr = "JSG2e(Vp0WCXE&";
+
+ try
+ {
+ createTestUser(user, passStr);
+
+ var csb = new SqlConnectionStringBuilder(DataTestUtility.TcpConnStr);
+ csb.Remove("User ID");
+ csb.Remove("Password");
+ csb.IntegratedSecurity = false;
+
+ var password = new SecureString();
+ passStr.ToCharArray().ToList().ForEach(x => password.AppendChar(x));
+ password.MakeReadOnly();
+
+ var newPassword = new SecureString();
+ newPassStr.ToCharArray().ToList().ForEach(x => newPassword.AppendChar(x));
+ newPassword.MakeReadOnly();
+
+ // Change password and try opening connection.
+ SqlConnection.ChangePassword(csb.ConnectionString, new SqlCredential(user, password), newPassword);
+
+ using (var conn = new SqlConnection(csb.ConnectionString, new SqlCredential(user, newPassword)))
+ using (var cmd = new SqlCommand("SELECT 1;", conn))
+ {
+ conn.Open();
+ Assert.Equal(1, cmd.ExecuteScalar());
+ }
+ }
+ finally
+ {
+ dropTestUser(user);
+ }
+ }
+
+ private static void createTestUser(string username, string password)
+ {
+ // Creates a test user with read permissions.
+ string createUserCmd = $"CREATE LOGIN {username} WITH PASSWORD = '{password}', CHECK_POLICY=OFF;"
+ + $"EXEC sp_adduser '{username}', '{username}', 'db_datareader';";
+
+ using (var conn = new SqlConnection(DataTestUtility.TcpConnStr))
+ using (var cmd = new SqlCommand(createUserCmd, conn))
+ {
+ conn.Open();
+ cmd.ExecuteNonQuery();
+ }
+ }
+
+ private static void dropTestUser(string username)
+ {
+ // Removes a created test user.
+ string dropUserCmd = $"IF EXISTS (SELECT * FROM sys.schemas WHERE name = '{username}') BEGIN DROP SCHEMA {username} END;"
+ + $"IF EXISTS (SELECT * FROM sys.database_principals WHERE type = 'S' AND name = '{username}') BEGIN DROP USER {username} END;"
+ + $"DROP LOGIN {username}";
+
+ // Pool must be cleared to prevent DROP LOGIN failure.
+ SqlConnection.ClearAllPools();
+
+ using (var conn = new SqlConnection(DataTestUtility.TcpConnStr))
+ using (var cmd = new SqlCommand(dropUserCmd, conn))
+ {
+ conn.Open();
+ cmd.ExecuteNonQuery();
+ }
+ }
+ }
+}
diff --git a/src/System.Data.SqlClient/tests/ManualTests/SQL/SqlNotificationTest/SqlNotificationTest.cs b/src/System.Data.SqlClient/tests/ManualTests/SQL/SqlNotificationTest/SqlNotificationTest.cs
index 44625e1f56..1c8a3d2783 100644
--- a/src/System.Data.SqlClient/tests/ManualTests/SQL/SqlNotificationTest/SqlNotificationTest.cs
+++ b/src/System.Data.SqlClient/tests/ManualTests/SQL/SqlNotificationTest/SqlNotificationTest.cs
@@ -13,9 +13,9 @@ namespace System.Data.SqlClient.ManualTesting.Tests
private const int CALLBACK_TIMEOUT = 5000; // milliseconds
// Database schema
- private readonly string _tableName = "dbo.[SQLDEP_" + Guid.NewGuid().ToString() + "]";
- private readonly string _queueName = "SQLDEP_" + Guid.NewGuid().ToString();
- private readonly string _serviceName = "SQLDEP_" + Guid.NewGuid().ToString();
+ private readonly string _tableName = $"dbo.[SQLDEP_{Guid.NewGuid().ToString()}]";
+ private readonly string _queueName = $"SQLDEP_{Guid.NewGuid().ToString()}";
+ private readonly string _serviceName = $"SQLDEP_{Guid.NewGuid().ToString()}";
private readonly string _schemaQueue;
// Connection information used by all tests
@@ -27,15 +27,7 @@ namespace System.Data.SqlClient.ManualTesting.Tests
_startConnectionString = DataTestUtility.TcpConnStr;
_execConnectionString = DataTestUtility.TcpConnStr;
- var startBuilder = new SqlConnectionStringBuilder(_startConnectionString);
- if (startBuilder.IntegratedSecurity)
- {
- _schemaQueue = string.Format("[{0}]", _queueName);
- }
- else
- {
- _schemaQueue = string.Format("[{0}].[{1}]", startBuilder.UserID, _queueName);
- }
+ _schemaQueue = $"[{_queueName}]";
Setup();
}
diff --git a/src/System.Data.SqlClient/tests/ManualTests/System.Data.SqlClient.ManualTesting.Tests.csproj b/src/System.Data.SqlClient/tests/ManualTests/System.Data.SqlClient.ManualTesting.Tests.csproj
index 7daecb14b6..cdf01ffc9f 100644
--- a/src/System.Data.SqlClient/tests/ManualTests/System.Data.SqlClient.ManualTesting.Tests.csproj
+++ b/src/System.Data.SqlClient/tests/ManualTests/System.Data.SqlClient.ManualTesting.Tests.csproj
@@ -13,6 +13,7 @@
<Compile Include="DataCommon\CheckConnStrSetupFactAttribute.cs" />
<Compile Include="SQL\AdapterTest\AdapterTest.cs" />
<Compile Include="SQL\AsyncTest\BeginExecAsyncTest.cs" />
+ <Compile Include="SQL\AsyncTest\XmlReaderAsyncTest.cs" />
<Compile Include="SQL\Common\AsyncDebugScope.cs" />
<Compile Include="SQL\Common\ConnectionPoolWrapper.cs" />
<Compile Include="SQL\Common\InternalConnectionWrapper.cs" />
@@ -59,6 +60,7 @@
<Compile Include="SQL\MARSTest\MARSTest.cs" />
<Compile Include="SQL\MirroringTest\ConnectionOnMirroringTest.cs" />
<Compile Include="SQL\ParallelTransactionsTest\ParallelTransactionsTest.cs" />
+ <Compile Include="SQL\SqlCredentialTest\SqlCredentialTest.cs" />
<Compile Include="SQL\SqlSchemaInfoTest\SqlSchemaInfoTest.cs" />
<Compile Include="SQL\SqlBulkCopyTest\AdjustPrecScaleForBulkCopy.cs" />
<Compile Include="SQL\SqlBulkCopyTest\ErrorOnRowsMarkedAsDeleted.cs" />
diff --git a/src/System.Diagnostics.Debug/tests/DebugTests.cs b/src/System.Diagnostics.Debug/tests/DebugTests.cs
index 9af77fd658..192891d2b8 100644
--- a/src/System.Diagnostics.Debug/tests/DebugTests.cs
+++ b/src/System.Diagnostics.Debug/tests/DebugTests.cs
@@ -201,13 +201,13 @@ namespace System.Diagnostics.Tests
}
FieldInfo writeCoreHook = typeof(Debug).GetField("s_WriteCore", BindingFlags.Static | BindingFlags.NonPublic);
- FieldInfo showAssertDialogHook = typeof(Debug).GetField("s_ShowAssertDialog", BindingFlags.Static | BindingFlags.NonPublic);
+ FieldInfo showDialogHook = typeof(Debug).GetField("s_ShowDialog", BindingFlags.Static | BindingFlags.NonPublic);
var originalWriteCoreHook = writeCoreHook.GetValue(null);
writeCoreHook.SetValue(null, new Action<string>(WriteLogger.s_instance.WriteCore));
- var originalShowAssertDialogHook = showAssertDialogHook.GetValue(null);
- showAssertDialogHook.SetValue(null, new Action<string, string, string>(WriteLogger.s_instance.ShowAssertDialog));
+ var originalShowDialogHook = showDialogHook.GetValue(null);
+ showDialogHook.SetValue(null, new Action<string, string, string, string>(WriteLogger.s_instance.ShowDialog));
try
{
@@ -228,7 +228,7 @@ namespace System.Diagnostics.Tests
finally
{
writeCoreHook.SetValue(null, originalWriteCoreHook);
- showAssertDialogHook.SetValue(null, originalShowAssertDialogHook);
+ showDialogHook.SetValue(null, originalShowDialogHook);
}
}
@@ -248,9 +248,9 @@ namespace System.Diagnostics.Tests
AssertUIOutput = string.Empty;
}
- public void ShowAssertDialog(string stackTrace, string message, string detailMessage)
+ public void ShowDialog(string stackTrace, string message, string detailMessage, string errorSource)
{
- AssertUIOutput += stackTrace + message + detailMessage;
+ AssertUIOutput += stackTrace + message + detailMessage + errorSource;
}
public void WriteCore(string message)
diff --git a/src/System.Diagnostics.DiagnosticSource/pkg/System.Diagnostics.DiagnosticSource.pkgproj b/src/System.Diagnostics.DiagnosticSource/pkg/System.Diagnostics.DiagnosticSource.pkgproj
index 9217e74da3..93ce39ab4a 100644
--- a/src/System.Diagnostics.DiagnosticSource/pkg/System.Diagnostics.DiagnosticSource.pkgproj
+++ b/src/System.Diagnostics.DiagnosticSource/pkg/System.Diagnostics.DiagnosticSource.pkgproj
@@ -1,10 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
- <PropertyGroup>
- <!-- we need to be supported on pre-nuget-3 platforms (Dev12, Dev11, etc) -->
- <MinClientVersion>2.8.6</MinClientVersion>
- </PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\src\System.Diagnostics.DiagnosticSource.csproj">
<SupportedFramework>net46;net45;netcore45;netcoreapp1.0;wpa81;$(AllXamarinFrameworks)</SupportedFramework>
diff --git a/src/System.Diagnostics.DiagnosticSource/ref/Configurations.props b/src/System.Diagnostics.DiagnosticSource/ref/Configurations.props
index a036c05185..7b5f53ade5 100644
--- a/src/System.Diagnostics.DiagnosticSource/ref/Configurations.props
+++ b/src/System.Diagnostics.DiagnosticSource/ref/Configurations.props
@@ -2,7 +2,8 @@
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PackageConfigurations>
- netstandard1.0;
+ netstandard1.1;
+ netstandard1.3;
net45;
</PackageConfigurations>
<BuildConfigurations>
diff --git a/src/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSource.csproj b/src/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSource.csproj
index 130bbaa2b8..ccd74d8b13 100644
--- a/src/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSource.csproj
+++ b/src/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSource.csproj
@@ -13,18 +13,20 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.0-Debug|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.0-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.1-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.1-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.3-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.3-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="System.Diagnostics.DiagnosticSource.cs" />
</ItemGroup>
- <ItemGroup Condition="'$(TargetGroup)' != 'netstandard1.0'">
+ <ItemGroup Condition="'$(TargetGroup)' != 'netstandard1.1'">
<Compile Include="System.Diagnostics.DiagnosticSourceActivity.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' == 'net45' OR '$(TargetGroup)' == 'netfx'">
<Reference Include="mscorlib" />
</ItemGroup>
- <ItemGroup Condition="'$(TargetGroup)' == 'netstandard1.0'">
+ <ItemGroup Condition="'$(TargetGroup)' == 'netstandard1.1' or '$(TargetGroup)' == 'netstandard1.3'">
<Reference Include="System.Runtime" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
diff --git a/src/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.DateTime.netfx.cs b/src/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.DateTime.netfx.cs
index 7093027a7a..f9ecdc0065 100644
--- a/src/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.DateTime.netfx.cs
+++ b/src/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.DateTime.netfx.cs
@@ -42,6 +42,32 @@ namespace System.Diagnostics
private static TimeSync timeSync = new TimeSync();
// sync DateTime and Stopwatch ticks every 2 hours
- private static Timer syncTimeUpdater = new Timer(s => { Sync(); }, null, 0, 7200000);
+ private static Timer syncTimeUpdater = InitalizeSyncTimer();
+
+ [System.Security.SecuritySafeCritical]
+ private static Timer InitalizeSyncTimer()
+ {
+ Timer timer;
+ // Don't capture the current ExecutionContext and its AsyncLocals onto the timer causing them to live forever
+ bool restoreFlow = false;
+ try
+ {
+ if (!ExecutionContext.IsFlowSuppressed())
+ {
+ ExecutionContext.SuppressFlow();
+ restoreFlow = true;
+ }
+
+ timer = new Timer(s => { Sync(); }, null, 0, 7200000);
+ }
+ finally
+ {
+ // Restore the current ExecutionContext
+ if (restoreFlow)
+ ExecutionContext.RestoreFlow();
+ }
+
+ return timer;
+ }
}
-} \ No newline at end of file
+}
diff --git a/src/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs b/src/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs
index acf3ba61ae..7f7744376e 100644
--- a/src/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs
+++ b/src/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs
@@ -431,6 +431,7 @@ namespace System.Diagnostics.Tests
}
[Fact]
+ [OuterLoop] // Slighly flaky - https://github.com/dotnet/corefx/issues/23072
public void DiagnosticSourceStartStop()
{
using (DiagnosticListener listener = new DiagnosticListener("Testing"))
diff --git a/src/System.Diagnostics.EventLog/pkg/System.Diagnostics.EventLog.pkgproj b/src/System.Diagnostics.EventLog/pkg/System.Diagnostics.EventLog.pkgproj
index b744ffe9d8..f5c4342a14 100644
--- a/src/System.Diagnostics.EventLog/pkg/System.Diagnostics.EventLog.pkgproj
+++ b/src/System.Diagnostics.EventLog/pkg/System.Diagnostics.EventLog.pkgproj
@@ -3,7 +3,7 @@
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<ProjectReference Include="..\ref\System.Diagnostics.EventLog.csproj">
- <SupportedFramework>net461;netcoreapp2.0;$(AllXamarinFrameworks)</SupportedFramework>
+ <SupportedFramework>uap10.0.16299;net461;netcoreapp2.0;$(AllXamarinFrameworks)</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\src\System.Diagnostics.EventLog.csproj" />
</ItemGroup>
diff --git a/src/System.Diagnostics.EventLog/src/System/Diagnostics/EventLog.cs b/src/System.Diagnostics.EventLog/src/System/Diagnostics/EventLog.cs
index b8eb8292c4..6a7ab185d8 100644
--- a/src/System.Diagnostics.EventLog/src/System/Diagnostics/EventLog.cs
+++ b/src/System.Diagnostics.EventLog/src/System/Diagnostics/EventLog.cs
@@ -374,7 +374,7 @@ namespace System.Diagnostics
public static void Delete(string logName, string machineName)
{
if (!SyntaxCheck.CheckMachineName(machineName))
- throw new ArgumentException(SR.InvalidParameterFormat, nameof(machineName));
+ throw new ArgumentException(SR.Format(SR.InvalidParameterFormat, nameof(machineName)), nameof(machineName));
if (logName == null || logName.Length == 0)
throw new ArgumentException(SR.NoLogName);
if (!ValidLogName(logName, false))
@@ -656,7 +656,7 @@ namespace System.Diagnostics
throw new ArgumentException(SR.Format(SR.InvalidParameter, nameof(machineName), machineName));
}
- string[] logNames = new string[0];
+ string[] logNames = null;
RegistryKey eventkey = null;
try
@@ -814,7 +814,7 @@ namespace System.Diagnostics
}
// If you pass in an empty array UnsafeTryFormatMessage will just pull out the message.
- string formatString = UnsafeTryFormatMessage(hModule, messageNum, new string[0]);
+ string formatString = UnsafeTryFormatMessage(hModule, messageNum, Array.Empty<string>());
if (formatString == null)
{
diff --git a/src/System.Diagnostics.EventLog/src/System/Diagnostics/EventLogInternal.cs b/src/System.Diagnostics.EventLog/src/System/Diagnostics/EventLogInternal.cs
index 0e466d2fea..f7f8501219 100644
--- a/src/System.Diagnostics.EventLog/src/System/Diagnostics/EventLogInternal.cs
+++ b/src/System.Diagnostics.EventLog/src/System/Diagnostics/EventLogInternal.cs
@@ -677,7 +677,7 @@ namespace System.Diagnostics
return null;
if (insertionStrings == null)
- insertionStrings = new string[0];
+ insertionStrings = Array.Empty<string>();
string[] listDll = dllNameList.Split(';');
@@ -1398,7 +1398,7 @@ namespace System.Diagnostics
{
// check arguments
if (strings == null)
- strings = new string[0];
+ strings = Array.Empty<string>();
if (strings.Length >= 256)
throw new ArgumentException(SR.TooManyReplacementStrings);
@@ -1413,7 +1413,7 @@ namespace System.Diagnostics
throw new ArgumentException(SR.LogEntryTooLong);
}
if (rawData == null)
- rawData = new byte[0];
+ rawData = Array.Empty<byte>();
if (Source.Length == 0)
throw new ArgumentException(SR.NeedSourceToWrite);
diff --git a/src/System.Diagnostics.EventLog/tests/EventLogTests/EventLogTests.cs b/src/System.Diagnostics.EventLog/tests/EventLogTests/EventLogTests.cs
index 6bf0ff5293..37af67cdcd 100644
--- a/src/System.Diagnostics.EventLog/tests/EventLogTests/EventLogTests.cs
+++ b/src/System.Diagnostics.EventLog/tests/EventLogTests/EventLogTests.cs
@@ -80,7 +80,9 @@ namespace System.Diagnostics.Tests
{
using (EventLog eventLog = new EventLog("Application"))
{
- Assert.Equal("Application", eventLog.LogDisplayName);
+ Assert.False(string.IsNullOrEmpty(eventLog.LogDisplayName));
+ if (CultureInfo.CurrentCulture.Name.Split('-')[0] == "en" )
+ Assert.Equal("Application", eventLog.LogDisplayName);
}
}
@@ -109,7 +111,10 @@ namespace System.Diagnostics.Tests
using (EventLog eventLog = new EventLog())
{
eventLog.Log = "Application";
- Assert.Equal("Application", eventLog.LogDisplayName);
+
+ Assert.False(string.IsNullOrEmpty(eventLog.LogDisplayName));
+ if (CultureInfo.CurrentCulture.Name.Split('-')[0] == "en" )
+ Assert.Equal("Application", eventLog.LogDisplayName);
}
}
diff --git a/src/System.Diagnostics.PerformanceCounter/pkg/System.Diagnostics.PerformanceCounter.pkgproj b/src/System.Diagnostics.PerformanceCounter/pkg/System.Diagnostics.PerformanceCounter.pkgproj
index ba710f6838..fad9022c63 100644
--- a/src/System.Diagnostics.PerformanceCounter/pkg/System.Diagnostics.PerformanceCounter.pkgproj
+++ b/src/System.Diagnostics.PerformanceCounter/pkg/System.Diagnostics.PerformanceCounter.pkgproj
@@ -3,7 +3,7 @@
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<ProjectReference Include="..\ref\System.Diagnostics.PerformanceCounter.csproj">
- <SupportedFramework>net461;netcoreapp2.0;$(AllXamarinFrameworks)</SupportedFramework>
+ <SupportedFramework>uap10.0.16299;net461;netcoreapp2.0;$(AllXamarinFrameworks)</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\src\System.Diagnostics.PerformanceCounter.csproj" />
</ItemGroup>
diff --git a/src/System.Diagnostics.PerformanceCounter/src/System.Diagnostics.PerformanceCounter.csproj b/src/System.Diagnostics.PerformanceCounter/src/System.Diagnostics.PerformanceCounter.csproj
index 02ec8e70a2..138d77ac21 100644
--- a/src/System.Diagnostics.PerformanceCounter/src/System.Diagnostics.PerformanceCounter.csproj
+++ b/src/System.Diagnostics.PerformanceCounter/src/System.Diagnostics.PerformanceCounter.csproj
@@ -165,6 +165,7 @@
<Reference Include="System.Diagnostics.Tools" />
<Reference Include="System.IO.FileSystem" />
<Reference Include="System.IO.MemoryMappedFiles" />
+ <Reference Include="System.Memory" />
<Reference Include="System.Resources.ResourceManager" />
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.Extensions" />
diff --git a/src/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PerformanceCounterLib.cs b/src/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PerformanceCounterLib.cs
index f9c6c51e6b..7c52419dc5 100644
--- a/src/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PerformanceCounterLib.cs
+++ b/src/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PerformanceCounterLib.cs
@@ -50,8 +50,9 @@ namespace System.Diagnostics
private string _machineName;
private string _perfLcid;
- private Hashtable _customCategoryTable;
+
private static volatile Hashtable s_libraryTable;
+ private Hashtable _customCategoryTable;
private Hashtable _categoryTable;
private Hashtable _nameTable;
private Hashtable _helpTable;
@@ -299,10 +300,17 @@ namespace System.Diagnostics
{
if (s_libraryTable != null)
{
- foreach (PerformanceCounterLib library in s_libraryTable.Values)
- library.Close();
+ //race with GetPerformanceCounterLib
+ lock (InternalSyncObject)
+ {
+ if (s_libraryTable != null)
+ {
+ foreach (PerformanceCounterLib library in s_libraryTable.Values)
+ library.Close();
- s_libraryTable = null;
+ s_libraryTable = null;
+ }
+ }
}
}
@@ -638,14 +646,14 @@ namespace System.Diagnostics
RegistryKey baseKey = null;
categoryType = PerformanceCounterCategoryType.Unknown;
- if (_customCategoryTable == null)
- {
- Interlocked.CompareExchange(ref _customCategoryTable, new Hashtable(StringComparer.OrdinalIgnoreCase), null);
- }
+ Hashtable table =
+ _customCategoryTable ??
+ Interlocked.CompareExchange(ref _customCategoryTable, new Hashtable(StringComparer.OrdinalIgnoreCase), null) ??
+ _customCategoryTable;
- if (_customCategoryTable.ContainsKey(category))
+ if (table.ContainsKey(category))
{
- categoryType = (PerformanceCounterCategoryType)_customCategoryTable[category];
+ categoryType = (PerformanceCounterCategoryType)table[category];
return true;
}
else
@@ -674,7 +682,10 @@ namespace System.Diagnostics
// In this case we return an 'Unknown' category type and 'false' to indicate the category is *not* custom.
//
categoryType = PerformanceCounterCategoryType.Unknown;
- _customCategoryTable[category] = categoryType;
+ lock (table)
+ {
+ table[category] = categoryType;
+ }
return false;
}
}
@@ -702,8 +713,10 @@ namespace System.Diagnostics
if (objectID != null)
{
int firstID = (int)objectID;
-
- _customCategoryTable[category] = categoryType;
+ lock (table)
+ {
+ table[category] = categoryType;
+ }
return true;
}
}
@@ -717,6 +730,7 @@ namespace System.Diagnostics
baseKey.Close();
}
}
+
return false;
}
@@ -974,24 +988,22 @@ namespace System.Diagnostics
machineName = (machineName == "." ? ComputerName : machineName).ToLowerInvariant();
- if (PerformanceCounterLib.s_libraryTable == null)
+ //race with CloseAllLibraries
+ lock (InternalSyncObject)
{
- lock (InternalSyncObject)
+ if (PerformanceCounterLib.s_libraryTable == null)
+ PerformanceCounterLib.s_libraryTable = new Hashtable();
+
+ string libraryKey = machineName + ":" + lcidString;
+ if (PerformanceCounterLib.s_libraryTable.Contains(libraryKey))
+ return (PerformanceCounterLib)PerformanceCounterLib.s_libraryTable[libraryKey];
+ else
{
- if (PerformanceCounterLib.s_libraryTable == null)
- PerformanceCounterLib.s_libraryTable = new Hashtable();
+ PerformanceCounterLib library = new PerformanceCounterLib(machineName, lcidString);
+ PerformanceCounterLib.s_libraryTable[libraryKey] = library;
+ return library;
}
}
-
- string libraryKey = machineName + ":" + lcidString;
- if (PerformanceCounterLib.s_libraryTable.Contains(libraryKey))
- return (PerformanceCounterLib)PerformanceCounterLib.s_libraryTable[libraryKey];
- else
- {
- PerformanceCounterLib library = new PerformanceCounterLib(machineName, lcidString);
- PerformanceCounterLib.s_libraryTable[libraryKey] = library;
- return library;
- }
}
internal byte[] GetPerformanceData(string item)
diff --git a/src/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PrivilegedConfigurationManager.cs b/src/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PrivilegedConfigurationManager.cs
index 8cad71ca62..546c6d29f3 100644
--- a/src/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PrivilegedConfigurationManager.cs
+++ b/src/System.Diagnostics.PerformanceCounter/src/System/Diagnostics/PrivilegedConfigurationManager.cs
@@ -1,9 +1,6 @@
-//------------------------------------------------------------------------------
-// <copyright file="PrivilegedConfigurationManager.cs" company="Microsoft">
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// </copyright>
-//------------------------------------------------------------------------------
-
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
namespace System.Configuration {
diff --git a/src/System.Diagnostics.Process/System.Diagnostics.Process.sln b/src/System.Diagnostics.Process/System.Diagnostics.Process.sln
index 5a6ce0aeb1..37b8311026 100644
--- a/src/System.Diagnostics.Process/System.Diagnostics.Process.sln
+++ b/src/System.Diagnostics.Process/System.Diagnostics.Process.sln
@@ -31,10 +31,10 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {E1114510-844C-4BB2-BBAD-8595BD16E24B}.Debug|Any CPU.ActiveCfg = netstandard-Windows_NT-Debug|Any CPU
- {E1114510-844C-4BB2-BBAD-8595BD16E24B}.Debug|Any CPU.Build.0 = netstandard-Windows_NT-Debug|Any CPU
- {E1114510-844C-4BB2-BBAD-8595BD16E24B}.Release|Any CPU.ActiveCfg = netstandard-Windows_NT-Release|Any CPU
- {E1114510-844C-4BB2-BBAD-8595BD16E24B}.Release|Any CPU.Build.0 = netstandard-Windows_NT-Release|Any CPU
+ {E1114510-844C-4BB2-BBAD-8595BD16E24B}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU
+ {E1114510-844C-4BB2-BBAD-8595BD16E24B}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
+ {E1114510-844C-4BB2-BBAD-8595BD16E24B}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
+ {E1114510-844C-4BB2-BBAD-8595BD16E24B}.Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU
{4E05E43A-1DC9-47C7-8280-13CF4EF741EA}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
{4E05E43A-1DC9-47C7-8280-13CF4EF741EA}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
{4E05E43A-1DC9-47C7-8280-13CF4EF741EA}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
diff --git a/src/System.Diagnostics.Process/ref/System.Diagnostics.Process.cs b/src/System.Diagnostics.Process/ref/System.Diagnostics.Process.cs
index 83f600a4f4..a63a5c19a3 100644
--- a/src/System.Diagnostics.Process/ref/System.Diagnostics.Process.cs
+++ b/src/System.Diagnostics.Process/ref/System.Diagnostics.Process.cs
@@ -158,6 +158,7 @@ namespace System.Diagnostics
public ProcessStartInfo(string fileName) { }
public ProcessStartInfo(string fileName, string arguments) { }
public string Arguments { get { throw null; } set { } }
+ public System.Collections.ObjectModel.Collection<string> ArgumentList { get { throw null; } }
public bool CreateNoWindow { get { throw null; } set { } }
public string Domain { get { throw null; } set { } }
[System.ComponentModel.DefaultValueAttribute(null)]
diff --git a/src/System.Diagnostics.Process/src/FxCopBaseline.cs b/src/System.Diagnostics.Process/src/FxCopBaseline.cs
index 2fed8d3a21..2e370b51d3 100644
--- a/src/System.Diagnostics.Process/src/FxCopBaseline.cs
+++ b/src/System.Diagnostics.Process/src/FxCopBaseline.cs
@@ -1,3 +1,7 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.Diagnostics.Process.#EnsureWatchingForExit()")]
diff --git a/src/System.Diagnostics.Process/src/Resources/Strings.resx b/src/System.Diagnostics.Process/src/Resources/Strings.resx
index d83dfb7010..59e578f4b2 100644
--- a/src/System.Diagnostics.Process/src/Resources/Strings.resx
+++ b/src/System.Diagnostics.Process/src/Resources/Strings.resx
@@ -312,4 +312,10 @@
<data name="StandardInputEncodingNotAllowed" xml:space="preserve">
<value>StandardInputEncoding is only supported when standard input is redirected.</value>
</data>
+ <data name="UserDoesNotExist" xml:space="preserve">
+ <value>User with name '{0}' was not found.</value>
+ </data>
+ <data name="ArgumentAndArgumentListInitialized" xml:space="preserve">
+ <value>Only one of Arguments or ArgumentList may be used.</value>
+ </data>
</root> \ No newline at end of file
diff --git a/src/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj b/src/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj
index 108615fe09..c8de23462b 100644
--- a/src/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj
+++ b/src/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj
@@ -47,6 +47,9 @@
<Compile Include="System\Diagnostics\ThreadWaitReason.cs" />
<Compile Include="System\Diagnostics\MonitoringDescriptionAttribute.cs" />
<Compile Include="System\Collections\Specialized\StringDictionaryWrapper.cs" />
+ <Compile Include="..\..\Common\src\System\PasteArguments.cs">
+ <Link>Common\System\PasteArguments.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup Condition=" '$(TargetsWindows)' == 'true' and '$(TargetGroup)' != 'uap'">
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.EnumProcessModules.cs">
@@ -318,6 +321,9 @@
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.GetPid.cs">
<Link>Common\Interop\Unix\Interop.GetPid.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.GetPwUid.cs">
+ <Link>Common\Interop\Unix\Interop.GetPwUid.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.GetSetPriority.cs">
<Link>Common\Interop\Unix\Interop.GetSetPriority.cs</Link>
</Compile>
@@ -330,6 +336,9 @@
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.ReadLink.cs">
<Link>Common\Interop\Unix\Interop.ReadLink.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.RegisterForSigChld.cs">
+ <Link>Common\Interop\Unix\Interop.RegisterForRegisterForSigChld.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.ResourceLimits.cs">
<Link>Common\Interop\Unix\Interop.ResourceLimits.cs</Link>
</Compile>
@@ -339,8 +348,8 @@
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.POpen.cs">
<Link>Common\Interop\Unix\Interop.POpen.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.WaitPid.cs">
- <Link>Common\Interop\Unix\Interop.WaitPid.cs</Link>
+ <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.WaitId.cs">
+ <Link>Common\Interop\Unix\Interop.WaitId.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup Condition=" '$(TargetsLinux)' == 'true'">
@@ -353,15 +362,6 @@
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.SchedGetSetAffinity.cs">
<Link>Common\Interop\Linux\Interop.SchedGetSetAffinity.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Collections\Generic\ArrayBuilder.cs">
- <Link>Common\System\Collections\Generic\ArrayBuilder.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\System\Collections\Generic\EnumerableHelpers.cs">
- <Link>Common\System\Collections\Generic\EnumerableHelpers.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\System\Collections\Generic\LargeArrayBuilder.cs">
- <Link>Common\System\Collections\Generic\LargeArrayBuilder.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\System\Text\ReusableTextReader.cs">
<Link>Common\System\Text\ReusableTextReader.cs</Link>
</Compile>
@@ -436,6 +436,7 @@
<Reference Include="System.Diagnostics.FileVersionInfo" />
<Reference Include="System.Diagnostics.Tools" />
<Reference Include="System.IO.FileSystem" />
+ <Reference Include="System.Linq" />
<Reference Include="System.Memory" />
<Reference Include="System.Resources.ResourceManager" />
<Reference Include="System.Runtime" />
diff --git a/src/System.Diagnostics.Process/src/System/Diagnostics/AsyncStreamReader.cs b/src/System.Diagnostics.Process/src/System/Diagnostics/AsyncStreamReader.cs
index 3e5ba46044..a86002e2d1 100644
--- a/src/System.Diagnostics.Process/src/System/Diagnostics/AsyncStreamReader.cs
+++ b/src/System.Diagnostics.Process/src/System/Diagnostics/AsyncStreamReader.cs
@@ -90,7 +90,7 @@ namespace System.Diagnostics
{
try
{
- int bytesRead = await _stream.ReadAsync(_byteBuffer, 0, _byteBuffer.Length, _cts.Token).ConfigureAwait(false);
+ int bytesRead = await _stream.ReadAsync(new Memory<byte>(_byteBuffer), _cts.Token).ConfigureAwait(false);
if (bytesRead == 0)
break;
diff --git a/src/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs b/src/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs
index 030c5c50eb..829ea2e9f0 100644
--- a/src/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs
+++ b/src/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs
@@ -64,34 +64,39 @@ namespace System.Diagnostics
/// <returns>The converted time.</returns>
internal static DateTime BootTimeToDateTime(TimeSpan timespanAfterBoot)
{
- // Use the uptime and the current time to determine the absolute boot time.
- DateTime bootTime = DateTime.UtcNow - Uptime;
-
// And use that to determine the absolute time for timespan.
- DateTime dt = bootTime + timespanAfterBoot;
+ DateTime dt = BootTime + timespanAfterBoot;
// The return value is expected to be in the local time zone.
// It is converted here (rather than starting with DateTime.Now) to avoid DST issues.
return dt.ToLocalTime();
}
- /// <summary>Gets the elapsed time since the system was booted.</summary>
- private static TimeSpan Uptime
+ /// <summary>Gets the system boot time.</summary>
+ private static DateTime BootTime
{
get
{
- // '/proc/uptime' accounts time a device spends in sleep mode.
- const string UptimeFile = Interop.procfs.ProcUptimeFilePath;
- string text = File.ReadAllText(UptimeFile);
-
- double uptimeSeconds = 0;
- int length = text.IndexOf(' ');
- if (length != -1)
+ // '/proc/stat -> btime' gets the boot time.
+ // btime is the time of system boot in seconds since the Unix epoch.
+ // It includes suspended time and is updated based on the system time (settimeofday).
+ const string StatFile = Interop.procfs.ProcStatFilePath;
+ string text = File.ReadAllText(StatFile);
+ int btimeLineStart = text.IndexOf("\nbtime ");
+ if (btimeLineStart >= 0)
{
- Double.TryParse(text.AsReadOnlySpan().Slice(0, length), NumberStyles.AllowDecimalPoint, NumberFormatInfo.InvariantInfo, out uptimeSeconds);
+ int btimeStart = btimeLineStart + "\nbtime ".Length;
+ int btimeEnd = text.IndexOf('\n', btimeStart);
+ if (btimeEnd > btimeStart)
+ {
+ if (Int64.TryParse(text.AsSpan(btimeStart, btimeEnd - btimeStart), out long bootTimeSeconds))
+ {
+ return DateTime.UnixEpoch + TimeSpan.FromSeconds(bootTimeSeconds);
+ }
+ }
}
- return TimeSpan.FromSeconds(uptimeSeconds);
+ return DateTime.UtcNow;
}
}
@@ -191,7 +196,7 @@ namespace System.Diagnostics
ulong rsslim = GetStat().rsslim;
// rsslim is a ulong, but maxWorkingSet is an IntPtr, so we need to cap rsslim
- // at the max size of IntPtr. This often happens when there is no configured
+ // at the max size of IntPtr. This often happens when there is no configured
// rsslim other than ulong.MaxValue, which without these checks would show up
// as a maxWorkingSet == -1.
switch (IntPtr.Size)
diff --git a/src/System.Diagnostics.Process/src/System/Diagnostics/Process.Unix.cs b/src/System.Diagnostics.Process/src/System/Diagnostics/Process.Unix.cs
index 7790e8c5fe..82800ac9ac 100644
--- a/src/System.Diagnostics.Process/src/System/Diagnostics/Process.Unix.cs
+++ b/src/System.Diagnostics.Process/src/System/Diagnostics/Process.Unix.cs
@@ -18,6 +18,10 @@ namespace System.Diagnostics
{
private static readonly UTF8Encoding s_utf8NoBom =
new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
+ private static volatile bool s_sigchildHandlerRegistered = false;
+ private static readonly object s_sigchildGate = new object();
+ private static readonly Interop.Sys.SigChldCallback s_sigChildHandler = OnSigChild;
+ private static readonly ReaderWriterLockSlim s_processStartLock = new ReaderWriterLockSlim();
/// <summary>
/// Puts a Process component in state to interact with operating system processes that run in a
@@ -106,6 +110,8 @@ namespace System.Diagnostics
}
catch
{
+ _waitHandle?.Dispose();
+ _waitHandle = null;
_watchingForExit = false;
throw;
}
@@ -257,6 +263,8 @@ namespace System.Diagnostics
/// <param name="startInfo">The start info with which to start the process.</param>
private bool StartCore(ProcessStartInfo startInfo)
{
+ EnsureSigChildHandler();
+
string filename;
string[] argv;
@@ -293,21 +301,44 @@ namespace System.Diagnostics
throw new Win32Exception(Interop.Error.ENOENT.Info().RawErrno);
}
- // Invoke the shim fork/execve routine. It will create pipes for all requested
- // redirects, fork a child process, map the pipe ends onto the appropriate stdin/stdout/stderr
- // descriptors, and execve to execute the requested process. The shim implementation
- // is used to fork/execve as executing managed code in a forked process is not safe (only
- // the calling thread will transfer, thread IDs aren't stable across the fork, etc.)
- Interop.Sys.ForkAndExecProcess(
+ bool setCredentials = !string.IsNullOrEmpty(startInfo.UserName);
+ uint userId = 0;
+ uint groupId = 0;
+ if (setCredentials)
+ {
+ (userId, groupId) = GetUserAndGroupIds(startInfo);
+ }
+
+ // Lock to avoid races with OnSigChild
+ // By using a ReaderWriterLock we allow multiple processes to start concurrently.
+ s_processStartLock.EnterReadLock();
+ try
+ {
+ // Invoke the shim fork/execve routine. It will create pipes for all requested
+ // redirects, fork a child process, map the pipe ends onto the appropriate stdin/stdout/stderr
+ // descriptors, and execve to execute the requested process. The shim implementation
+ // is used to fork/execve as executing managed code in a forked process is not safe (only
+ // the calling thread will transfer, thread IDs aren't stable across the fork, etc.)
+ Interop.Sys.ForkAndExecProcess(
filename, argv, envp, cwd,
startInfo.RedirectStandardInput, startInfo.RedirectStandardOutput, startInfo.RedirectStandardError,
+ setCredentials, userId, groupId,
out childPid,
out stdinFd, out stdoutFd, out stderrFd);
- // Store the child's information into this Process object.
- Debug.Assert(childPid >= 0);
- SetProcessId(childPid);
- SetProcessHandle(new SafeProcessHandle(childPid));
+ // Ensure we'll reap this process.
+ // note: SetProcessId will set this if we don't set it first.
+ _waitStateHolder = new ProcessWaitState.Holder(childPid, isNewChild: true);
+
+ // Store the child's information into this Process object.
+ Debug.Assert(childPid >= 0);
+ SetProcessId(childPid);
+ SetProcessHandle(new SafeProcessHandle(childPid));
+ }
+ finally
+ {
+ s_processStartLock.ExitReadLock();
+ }
// Configure the parent's ends of the redirection streams.
// We use UTF8 encoding without BOM by-default(instead of Console encoding as on Windows)
@@ -345,7 +376,6 @@ namespace System.Diagnostics
/// <summary>Size to use for redirect streams and stream readers/writers.</summary>
private const int StreamBufferSize = 4096;
-
/// <summary>Converts the filename and arguments information from a ProcessStartInfo into an argv array.</summary>
/// <param name="psi">The ProcessStartInfo.</param>
/// <param name="alternativePath">alternative resolved path to use as first argument</param>
@@ -353,7 +383,7 @@ namespace System.Diagnostics
private static string[] ParseArgv(ProcessStartInfo psi, string alternativePath = null)
{
string argv0 = psi.FileName; // when no alternative path exists, pass filename (instead of resolved path) as argv[0], to match what caller supplied
- if (string.IsNullOrEmpty(psi.Arguments) && string.IsNullOrEmpty(alternativePath))
+ if (string.IsNullOrEmpty(psi.Arguments) && string.IsNullOrEmpty(alternativePath) && psi.ArgumentList.Count == 0)
{
return new string[] { argv0 };
}
@@ -367,8 +397,16 @@ namespace System.Diagnostics
argvList.Add("openURL"); // kfmclient needs OpenURL
}
}
+
argvList.Add(argv0);
- ParseArgumentsIntoList(psi.Arguments, argvList);
+ if (!string.IsNullOrEmpty(psi.Arguments))
+ {
+ ParseArgumentsIntoList(psi.Arguments, argvList);
+ }
+ else
+ {
+ argvList.AddRange(psi.ArgumentList);
+ }
return argvList.ToArray();
}
@@ -597,6 +635,94 @@ namespace System.Diagnostics
return _waitStateHolder._state;
}
+ private static (uint userId, uint groupId) GetUserAndGroupIds(ProcessStartInfo startInfo)
+ {
+ Debug.Assert(!string.IsNullOrEmpty(startInfo.UserName));
+
+ (uint? userId, uint? groupId) = GetUserAndGroupIds(startInfo.UserName);
+
+ Debug.Assert(userId.HasValue == groupId.HasValue, "userId and groupId both need to have values, or both need to be null.");
+ if (!userId.HasValue)
+ {
+ throw new Win32Exception(SR.Format(SR.UserDoesNotExist, startInfo.UserName));
+ }
+
+ return (userId.Value, groupId.Value);
+ }
+
+ private unsafe static (uint? userId, uint? groupId) GetUserAndGroupIds(string userName)
+ {
+ Interop.Sys.Passwd? passwd;
+ // First try with a buffer that should suffice for 99% of cases.
+ // Note: on CentOS/RedHat 7.1 systems, getpwnam_r returns 'user not found' if the buffer is too small
+ // see https://bugs.centos.org/view.php?id=7324
+ const int BufLen = Interop.Sys.Passwd.InitialBufferSize;
+ byte* stackBuf = stackalloc byte[BufLen];
+ if (TryGetPasswd(userName, stackBuf, BufLen, out passwd))
+ {
+ if (passwd == null)
+ {
+ return (null, null);
+ }
+ return (passwd.Value.UserId, passwd.Value.GroupId);
+ }
+
+ // Fallback to heap allocations if necessary, growing the buffer until
+ // we succeed. TryGetPasswd will throw if there's an unexpected error.
+ int lastBufLen = BufLen;
+ while (true)
+ {
+ lastBufLen *= 2;
+ byte[] heapBuf = new byte[lastBufLen];
+ fixed (byte* buf = &heapBuf[0])
+ {
+ if (TryGetPasswd(userName, buf, heapBuf.Length, out passwd))
+ {
+ if (passwd == null)
+ {
+ return (null, null);
+ }
+ return (passwd.Value.UserId, passwd.Value.GroupId);
+ }
+ }
+ }
+ }
+
+ private static unsafe bool TryGetPasswd(string name, byte* buf, int bufLen, out Interop.Sys.Passwd? passwd)
+ {
+ // Call getpwnam_r to get the passwd struct
+ Interop.Sys.Passwd tempPasswd;
+ int error = Interop.Sys.GetPwNamR(name, out tempPasswd, buf, bufLen);
+
+ // If the call succeeds, give back the passwd retrieved
+ if (error == 0)
+ {
+ passwd = tempPasswd;
+ return true;
+ }
+
+ // If the current user's entry could not be found, give back null,
+ // but still return true as false indicates the buffer was too small.
+ if (error == -1)
+ {
+ passwd = null;
+ return true;
+ }
+
+ var errorInfo = new Interop.ErrorInfo(error);
+
+ // If the call failed because the buffer was too small, return false to
+ // indicate the caller should try again with a larger buffer.
+ if (errorInfo.Error == Interop.Error.ERANGE)
+ {
+ passwd = null;
+ return false;
+ }
+
+ // Otherwise, fail.
+ throw new Win32Exception(errorInfo.RawErrno, errorInfo.GetErrorMessage());
+ }
+
public IntPtr MainWindowHandle => IntPtr.Zero;
private bool CloseMainWindowCore() => false;
@@ -606,5 +732,41 @@ namespace System.Diagnostics
public bool Responding => true;
private bool WaitForInputIdleCore(int milliseconds) => throw new InvalidOperationException(SR.InputIdleUnkownError);
+
+ private static void EnsureSigChildHandler()
+ {
+ if (s_sigchildHandlerRegistered)
+ {
+ return;
+ }
+
+ lock (s_sigchildGate)
+ {
+ if (!s_sigchildHandlerRegistered)
+ {
+ // Ensure signal handling is setup and register our callback.
+ if (!Interop.Sys.RegisterForSigChld(s_sigChildHandler))
+ {
+ throw new Win32Exception();
+ }
+
+ s_sigchildHandlerRegistered = true;
+ }
+ }
+ }
+
+ private static void OnSigChild(bool reapAll)
+ {
+ // Lock to avoid races with Process.Start
+ s_processStartLock.EnterWriteLock();
+ try
+ {
+ ProcessWaitState.CheckChildren(reapAll);
+ }
+ finally
+ {
+ s_processStartLock.ExitWriteLock();
+ }
+ }
}
}
diff --git a/src/System.Diagnostics.Process/src/System/Diagnostics/Process.Win32.cs b/src/System.Diagnostics.Process/src/System/Diagnostics/Process.Win32.cs
index ddde5fc6bc..f2f4746546 100644
--- a/src/System.Diagnostics.Process/src/System/Diagnostics/Process.Win32.cs
+++ b/src/System.Diagnostics.Process/src/System/Diagnostics/Process.Win32.cs
@@ -46,9 +46,21 @@ namespace System.Diagnostics
if (startInfo._environmentVariables != null)
throw new InvalidOperationException(SR.CantUseEnvVars);
+ string arguments;
+ if (startInfo.ArgumentList.Count > 0)
+ {
+ StringBuilder sb = new StringBuilder();
+ Process.AppendArguments(sb, startInfo.ArgumentList);
+ arguments = sb.ToString();
+ }
+ else
+ {
+ arguments = startInfo.Arguments;
+ }
+
fixed (char* fileName = startInfo.FileName.Length > 0 ? startInfo.FileName : null)
fixed (char* verb = startInfo.Verb.Length > 0 ? startInfo.Verb : null)
- fixed (char* parameters = startInfo.Arguments.Length > 0 ? startInfo.Arguments : null)
+ fixed (char* parameters = arguments.Length > 0 ? arguments : null)
fixed (char* directory = startInfo.WorkingDirectory.Length > 0 ? startInfo.WorkingDirectory : null)
{
Interop.Shell32.SHELLEXECUTEINFO shellExecuteInfo = new Interop.Shell32.SHELLEXECUTEINFO()
@@ -258,7 +270,7 @@ namespace System.Diagnostics
return false;
}
- Interop.User32.PostMessage(mainWindowHandle, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
+ Interop.User32.PostMessageW(mainWindowHandle, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
return true;
}
diff --git a/src/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs b/src/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs
index 1b70bc7347..d3bc24b578 100644
--- a/src/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs
+++ b/src/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs
@@ -437,7 +437,7 @@ namespace System.Diagnostics
/// <summary>Starts the process using the supplied start info.</summary>
/// <param name="startInfo">The start info with which to start the process.</param>
- private bool StartWithCreateProcess(ProcessStartInfo startInfo)
+ private unsafe bool StartWithCreateProcess(ProcessStartInfo startInfo)
{
// See knowledge base article Q190351 for an explanation of the following code. Noteworthy tricky points:
// * The handles are duplicated as non-inheritable before they are passed to CreateProcess so
@@ -445,54 +445,61 @@ namespace System.Diagnostics
// * CreateProcess allows you to redirect all or none of the standard IO handles, so we use
// GetStdHandle for the handles that are not being redirected
- StringBuilder commandLine = BuildCommandLine(startInfo.FileName, startInfo.Arguments);
-
+ StringBuilder commandLine = BuildCommandLine(startInfo.FileName, StartInfo.Arguments);
+ Process.AppendArguments(commandLine, StartInfo.ArgumentList);
+
Interop.Kernel32.STARTUPINFO startupInfo = new Interop.Kernel32.STARTUPINFO();
Interop.Kernel32.PROCESS_INFORMATION processInfo = new Interop.Kernel32.PROCESS_INFORMATION();
Interop.Kernel32.SECURITY_ATTRIBUTES unused_SecAttrs = new Interop.Kernel32.SECURITY_ATTRIBUTES();
SafeProcessHandle procSH = new SafeProcessHandle();
SafeThreadHandle threadSH = new SafeThreadHandle();
- bool retVal;
- int errorCode = 0;
// handles used in parent process
- SafeFileHandle standardInputWritePipeHandle = null;
- SafeFileHandle standardOutputReadPipeHandle = null;
- SafeFileHandle standardErrorReadPipeHandle = null;
- GCHandle environmentHandle = new GCHandle();
+ SafeFileHandle parentInputPipeHandle = null;
+ SafeFileHandle childInputPipeHandle = null;
+ SafeFileHandle parentOutputPipeHandle = null;
+ SafeFileHandle childOutputPipeHandle = null;
+ SafeFileHandle parentErrorPipeHandle = null;
+ SafeFileHandle childErrorPipeHandle = null;
lock (s_createProcessLock)
{
try
{
+ startupInfo.cb = sizeof(Interop.Kernel32.STARTUPINFO);
+
// set up the streams
if (startInfo.RedirectStandardInput || startInfo.RedirectStandardOutput || startInfo.RedirectStandardError)
{
if (startInfo.RedirectStandardInput)
{
- CreatePipe(out standardInputWritePipeHandle, out startupInfo.hStdInput, true);
+ CreatePipe(out parentInputPipeHandle, out childInputPipeHandle, true);
}
else
{
- startupInfo.hStdInput = new SafeFileHandle(Interop.Kernel32.GetStdHandle(Interop.Kernel32.HandleTypes.STD_INPUT_HANDLE), false);
+ childInputPipeHandle = new SafeFileHandle(Interop.Kernel32.GetStdHandle(Interop.Kernel32.HandleTypes.STD_INPUT_HANDLE), false);
}
if (startInfo.RedirectStandardOutput)
{
- CreatePipe(out standardOutputReadPipeHandle, out startupInfo.hStdOutput, false);
+ CreatePipe(out parentOutputPipeHandle, out childOutputPipeHandle, false);
}
else
{
- startupInfo.hStdOutput = new SafeFileHandle(Interop.Kernel32.GetStdHandle(Interop.Kernel32.HandleTypes.STD_OUTPUT_HANDLE), false);
+ childOutputPipeHandle = new SafeFileHandle(Interop.Kernel32.GetStdHandle(Interop.Kernel32.HandleTypes.STD_OUTPUT_HANDLE), false);
}
if (startInfo.RedirectStandardError)
{
- CreatePipe(out standardErrorReadPipeHandle, out startupInfo.hStdError, false);
+ CreatePipe(out parentErrorPipeHandle, out childErrorPipeHandle, false);
}
else
{
- startupInfo.hStdError = new SafeFileHandle(Interop.Kernel32.GetStdHandle(Interop.Kernel32.HandleTypes.STD_ERROR_HANDLE), false);
+ childErrorPipeHandle = new SafeFileHandle(Interop.Kernel32.GetStdHandle(Interop.Kernel32.HandleTypes.STD_ERROR_HANDLE), false);
}
+ startupInfo.hStdInput = childInputPipeHandle.DangerousGetHandle();
+ startupInfo.hStdOutput = childOutputPipeHandle.DangerousGetHandle();
+ startupInfo.hStdError = childErrorPipeHandle.DangerousGetHandle();
+
startupInfo.dwFlags = Interop.Advapi32.StartupInfoOptions.STARTF_USESTDHANDLES;
}
@@ -501,18 +508,19 @@ namespace System.Diagnostics
if (startInfo.CreateNoWindow) creationFlags |= Interop.Advapi32.StartupInfoOptions.CREATE_NO_WINDOW;
// set up the environment block parameter
- IntPtr environmentPtr = (IntPtr)0;
+ string environmentBlock = null;
if (startInfo._environmentVariables != null)
{
creationFlags |= Interop.Advapi32.StartupInfoOptions.CREATE_UNICODE_ENVIRONMENT;
- byte[] environmentBytes = EnvironmentVariablesToByteArray(startInfo._environmentVariables);
- environmentHandle = GCHandle.Alloc(environmentBytes, GCHandleType.Pinned);
- environmentPtr = environmentHandle.AddrOfPinnedObject();
+ environmentBlock = GetEnvironmentVariablesBlock(startInfo._environmentVariables);
}
string workingDirectory = startInfo.WorkingDirectory;
if (workingDirectory == string.Empty)
workingDirectory = Directory.GetCurrentDirectory();
+ bool retVal;
+ int errorCode = 0;
+
if (startInfo.UserName.Length != 0)
{
if (startInfo.Password != null && startInfo.PasswordInClearText != null)
@@ -526,138 +534,105 @@ namespace System.Diagnostics
logonFlags = Interop.Advapi32.LogonFlags.LOGON_WITH_PROFILE;
}
- if (startInfo.Password != null)
+ fixed (char* passwordInClearTextPtr = startInfo.PasswordInClearText ?? string.Empty)
+ fixed (char* environmentBlockPtr = environmentBlock)
{
- IntPtr passwordPtr = Marshal.SecureStringToGlobalAllocUnicode(startInfo.Password);
+ IntPtr passwordPtr = (startInfo.Password != null) ?
+ Marshal.SecureStringToGlobalAllocUnicode(startInfo.Password) : IntPtr.Zero;
+
try
{
retVal = Interop.Advapi32.CreateProcessWithLogonW(
startInfo.UserName,
startInfo.Domain,
- passwordPtr,
+ (passwordPtr != IntPtr.Zero) ? passwordPtr : (IntPtr)passwordInClearTextPtr,
logonFlags,
null, // we don't need this since all the info is in commandLine
commandLine,
creationFlags,
- environmentPtr,
+ (IntPtr)environmentBlockPtr,
workingDirectory,
- startupInfo, // pointer to STARTUPINFO
- processInfo // pointer to PROCESS_INFORMATION
+ ref startupInfo, // pointer to STARTUPINFO
+ ref processInfo // pointer to PROCESS_INFORMATION
);
-
if (!retVal)
errorCode = Marshal.GetLastWin32Error();
}
- finally { Marshal.ZeroFreeGlobalAllocUnicode(passwordPtr); }
- }
- else
- {
- unsafe
- {
- fixed (char* passwordPtr = startInfo.PasswordInClearText ?? string.Empty)
- {
- retVal = Interop.Advapi32.CreateProcessWithLogonW(
- startInfo.UserName,
- startInfo.Domain,
- (IntPtr)passwordPtr,
- logonFlags,
- null, // we don't need this since all the info is in commandLine
- commandLine,
- creationFlags,
- environmentPtr,
- workingDirectory,
- startupInfo, // pointer to STARTUPINFO
- processInfo // pointer to PROCESS_INFORMATION
- );
-
- }
- }
- if (!retVal)
- errorCode = Marshal.GetLastWin32Error();
- }
- if (processInfo.hProcess != IntPtr.Zero && processInfo.hProcess != (IntPtr)INVALID_HANDLE_VALUE)
- procSH.InitialSetHandle(processInfo.hProcess);
- if (processInfo.hThread != IntPtr.Zero && processInfo.hThread != (IntPtr)INVALID_HANDLE_VALUE)
- threadSH.InitialSetHandle(processInfo.hThread);
- if (!retVal)
- {
- if (errorCode == Interop.Errors.ERROR_BAD_EXE_FORMAT || errorCode == Interop.Errors.ERROR_EXE_MACHINE_TYPE_MISMATCH)
+ finally
{
- throw new Win32Exception(errorCode, SR.InvalidApplication);
+ if (passwordPtr != IntPtr.Zero)
+ Marshal.ZeroFreeGlobalAllocUnicode(passwordPtr);
}
- throw new Win32Exception(errorCode);
}
}
else
{
- retVal = Interop.Kernel32.CreateProcess(
+ fixed (char* environmentBlockPtr = environmentBlock)
+ {
+ retVal = Interop.Kernel32.CreateProcess(
null, // we don't need this since all the info is in commandLine
commandLine, // pointer to the command line string
ref unused_SecAttrs, // address to process security attributes, we don't need to inherit the handle
ref unused_SecAttrs, // address to thread security attributes.
true, // handle inheritance flag
creationFlags, // creation flags
- environmentPtr, // pointer to new environment block
+ (IntPtr)environmentBlockPtr, // pointer to new environment block
workingDirectory, // pointer to current directory name
- startupInfo, // pointer to STARTUPINFO
- processInfo // pointer to PROCESS_INFORMATION
+ ref startupInfo, // pointer to STARTUPINFO
+ ref processInfo // pointer to PROCESS_INFORMATION
);
- if (!retVal)
- errorCode = Marshal.GetLastWin32Error();
- if (processInfo.hProcess != (IntPtr)0 && processInfo.hProcess != (IntPtr)INVALID_HANDLE_VALUE)
- procSH.InitialSetHandle(processInfo.hProcess);
- if (processInfo.hThread != (IntPtr)0 && processInfo.hThread != (IntPtr)INVALID_HANDLE_VALUE)
- threadSH.InitialSetHandle(processInfo.hThread);
-
- if (!retVal)
+ if (!retVal)
+ errorCode = Marshal.GetLastWin32Error();
+ }
+ }
+
+ if (processInfo.hProcess != IntPtr.Zero && processInfo.hProcess != (IntPtr)INVALID_HANDLE_VALUE)
+ procSH.InitialSetHandle(processInfo.hProcess);
+ if (processInfo.hThread != IntPtr.Zero && processInfo.hThread != (IntPtr)INVALID_HANDLE_VALUE)
+ threadSH.InitialSetHandle(processInfo.hThread);
+
+ if (!retVal)
+ {
+ if (errorCode == Interop.Errors.ERROR_BAD_EXE_FORMAT || errorCode == Interop.Errors.ERROR_EXE_MACHINE_TYPE_MISMATCH)
{
- if (errorCode == Interop.Errors.ERROR_BAD_EXE_FORMAT || errorCode == Interop.Errors.ERROR_EXE_MACHINE_TYPE_MISMATCH)
- {
- throw new Win32Exception(errorCode, SR.InvalidApplication);
- }
- throw new Win32Exception(errorCode);
+ throw new Win32Exception(errorCode, SR.InvalidApplication);
}
+ throw new Win32Exception(errorCode);
}
}
finally
{
- // free environment block
- if (environmentHandle.IsAllocated)
- {
- environmentHandle.Free();
- }
+ childInputPipeHandle?.Dispose();
+ childOutputPipeHandle?.Dispose();
+ childErrorPipeHandle?.Dispose();
- startupInfo.Dispose();
+ threadSH?.Dispose();
}
}
if (startInfo.RedirectStandardInput)
{
Encoding enc = startInfo.StandardInputEncoding ?? GetEncoding((int)Interop.Kernel32.GetConsoleCP());
- _standardInput = new StreamWriter(new FileStream(standardInputWritePipeHandle, FileAccess.Write, 4096, false), enc, 4096);
+ _standardInput = new StreamWriter(new FileStream(parentInputPipeHandle, FileAccess.Write, 4096, false), enc, 4096);
_standardInput.AutoFlush = true;
}
if (startInfo.RedirectStandardOutput)
{
Encoding enc = startInfo.StandardOutputEncoding ?? GetEncoding((int)Interop.Kernel32.GetConsoleOutputCP());
- _standardOutput = new StreamReader(new FileStream(standardOutputReadPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096);
+ _standardOutput = new StreamReader(new FileStream(parentOutputPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096);
}
if (startInfo.RedirectStandardError)
{
Encoding enc = startInfo.StandardErrorEncoding ?? GetEncoding((int)Interop.Kernel32.GetConsoleOutputCP());
- _standardError = new StreamReader(new FileStream(standardErrorReadPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096);
+ _standardError = new StreamReader(new FileStream(parentErrorPipeHandle, FileAccess.Read, 4096, false), enc, true, 4096);
}
- bool ret = false;
- if (!procSH.IsInvalid)
- {
- SetProcessHandle(procSH);
- SetProcessId((int)processInfo.dwProcessId);
- threadSH.Dispose();
- ret = true;
- }
+ if (procSH.IsInvalid)
+ return false;
- return ret;
+ SetProcessHandle(procSH);
+ SetProcessId((int)processInfo.dwProcessId);
+ return true;
}
private static Encoding GetEncoding(int codePage)
@@ -900,11 +875,10 @@ namespace System.Diagnostics
}
}
- private static byte[] EnvironmentVariablesToByteArray(IDictionary<string, string> sd)
+ private static string GetEnvironmentVariablesBlock(IDictionary<string, string> sd)
{
// get the keys
string[] keys = new string[sd.Count];
- byte[] envBlock = null;
sd.Keys.CopyTo(keys, 0);
// sort both by the keys
@@ -925,10 +899,8 @@ namespace System.Diagnostics
stringBuff.Append(sd[keys[i]]);
stringBuff.Append('\0');
}
- // an extra null at the end indicates end of list.
- stringBuff.Append('\0');
- envBlock = Encoding.Unicode.GetBytes(stringBuff.ToString());
- return envBlock;
+ // an extra null at the end that indicates end of list will come from the string.
+ return stringBuff.ToString();
}
}
}
diff --git a/src/System.Diagnostics.Process/src/System/Diagnostics/Process.cs b/src/System.Diagnostics.Process/src/System/Diagnostics/Process.cs
index 1509b48003..2f647de698 100644
--- a/src/System.Diagnostics.Process/src/System/Diagnostics/Process.cs
+++ b/src/System.Diagnostics.Process/src/System/Diagnostics/Process.cs
@@ -3,11 +3,10 @@
// See the LICENSE file in the project root for more information.
using Microsoft.Win32.SafeHandles;
-using System.Collections.Generic;
+using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.IO;
-using System.Security;
using System.Text;
using System.Threading;
@@ -1198,6 +1197,10 @@ namespace System.Diagnostics
{
throw new InvalidOperationException(SR.StandardErrorEncodingNotAllowed);
}
+ if (!string.IsNullOrEmpty(startInfo.Arguments) && startInfo.ArgumentList.Count > 0)
+ {
+ throw new InvalidOperationException(SR.ArgumentAndArgumentListInitialized);
+ }
//Cannot start a new process and store its handle if the object has been disposed, since finalization has been suppressed.
if (_disposed)
@@ -1467,6 +1470,17 @@ namespace System.Diagnostics
}
}
+ private static void AppendArguments(StringBuilder stringBuilder, Collection<string> argumentList)
+ {
+ if (argumentList.Count > 0)
+ {
+ foreach (string argument in argumentList)
+ {
+ PasteArguments.AppendArgument(stringBuilder, argument);
+ }
+ }
+ }
+
/// <summary>
/// This enum defines the operation mode for redirected process stream.
/// We don't support switching between synchronous mode and asynchronous mode.
diff --git a/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Linux.cs b/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Linux.cs
index 61e1d1f2e5..69800f10b0 100644
--- a/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Linux.cs
+++ b/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Linux.cs
@@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Globalization;
using System.IO;
+using System.Linq;
using System.Text;
namespace System.Diagnostics
@@ -14,7 +15,7 @@ namespace System.Diagnostics
/// <summary>Gets the IDs of all processes on the current machine.</summary>
public static int[] GetProcessIds()
{
- return EnumerableHelpers.ToArray(EnumerateProcessIds());
+ return EnumerateProcessIds().ToArray();
}
/// <summary>Gets process infos for each process on the specified machine.</summary>
@@ -207,6 +208,8 @@ namespace System.Diagnostics
/// <returns></returns>
private static ThreadState ProcFsStateToThreadState(char c)
{
+ // Information on these in fs/proc/array.c
+ // `man proc` does not document them all
switch (c)
{
case 'R': // Running
@@ -228,6 +231,9 @@ namespace System.Diagnostics
case 'K': // Wakekill
return ThreadState.Transition;
+ case 'I': // Idle
+ return ThreadState.Ready;
+
default:
Debug.Fail($"Unexpected status character: {c}");
return ThreadState.Unknown;
diff --git a/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Windows.cs b/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Windows.cs
index 0498f97fef..5139615db9 100644
--- a/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Windows.cs
+++ b/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Windows.cs
@@ -758,7 +758,7 @@ namespace System.Diagnostics
// get the threads for current process
processInfos[processInfo.ProcessId] = processInfo;
- currentPtr = (IntPtr)((long)currentPtr + Marshal.SizeOf(pi));
+ currentPtr = (IntPtr)((long)currentPtr + sizeof(SystemProcessInformation));
int i = 0;
while (i < pi.NumberOfThreads)
{
@@ -774,7 +774,7 @@ namespace System.Diagnostics
threadInfo._threadWaitReason = NtProcessManager.GetThreadWaitReason((int)ti.WaitReason);
processInfo._threadInfoList.Add(threadInfo);
- currentPtr = (IntPtr)((long)currentPtr + Marshal.SizeOf(ti));
+ currentPtr = (IntPtr)((long)currentPtr + sizeof(SystemThreadInformation));
i++;
}
}
diff --git a/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.Unix.cs b/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.Unix.cs
index 2969b6c89b..d94163318d 100644
--- a/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.Unix.cs
+++ b/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.Unix.cs
@@ -14,12 +14,6 @@ namespace System.Diagnostics
{
private const bool CaseSensitiveEnvironmentVariables = true;
- public string UserName
- {
- get { throw new PlatformNotSupportedException(SR.ProcessStartIdentityNotSupported); }
- set { throw new PlatformNotSupportedException(SR.ProcessStartIdentityNotSupported); }
- }
-
public string PasswordInClearText
{
get { throw new PlatformNotSupportedException(SR.ProcessStartIdentityNotSupported); }
diff --git a/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.Windows.cs b/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.Windows.cs
index b504587ee4..53fd3df862 100644
--- a/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.Windows.cs
+++ b/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.Windows.cs
@@ -8,17 +8,10 @@ namespace System.Diagnostics
{
public sealed partial class ProcessStartInfo
{
- private string _userName;
private string _domain;
private const bool CaseSensitiveEnvironmentVariables = false;
- public string UserName
- {
- get => _userName ?? string.Empty;
- set => _userName = value;
- }
-
public string PasswordInClearText { get; set; }
public string Domain
diff --git a/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.cs b/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.cs
index d07ade0453..e88549a1a4 100644
--- a/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.cs
+++ b/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.cs
@@ -4,6 +4,7 @@
using System.Collections;
using System.Collections.Generic;
+using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Text;
@@ -20,7 +21,9 @@ namespace System.Diagnostics
private string _fileName;
private string _arguments;
private string _directory;
+ private string _userName;
private string _verb;
+ private Collection<string> _argumentList;
private ProcessWindowStyle _windowStyle;
internal DictionaryWrapper _environmentVariables;
@@ -60,6 +63,18 @@ namespace System.Diagnostics
set => _arguments = value;
}
+ public Collection<string> ArgumentList
+ {
+ get
+ {
+ if (_argumentList == null)
+ {
+ _argumentList = new Collection<string>();
+ }
+ return _argumentList;
+ }
+ }
+
public bool CreateNoWindow { get; set; }
public StringDictionary EnvironmentVariables => new StringDictionaryWrapper(Environment as DictionaryWrapper);
@@ -125,6 +140,12 @@ namespace System.Diagnostics
public bool ErrorDialog { get; set; }
public IntPtr ErrorDialogParentHandle { get; set; }
+ public string UserName
+ {
+ get => _userName ?? string.Empty;
+ set => _userName = value;
+ }
+
[DefaultValue("")]
public string Verb
{
diff --git a/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessWaitHandle.Unix.cs b/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessWaitHandle.Unix.cs
index 24b6a0a82c..2f9270e175 100644
--- a/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessWaitHandle.Unix.cs
+++ b/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessWaitHandle.Unix.cs
@@ -34,6 +34,8 @@ namespace System.Diagnostics
protected override void Dispose(bool explicitDisposing)
{
+ // ProcessWaitState will dispose the handle
+ this.SafeWaitHandle = null;
if (explicitDisposing)
{
if (_waitStateHolder != null)
diff --git a/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessWaitState.Unix.cs b/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessWaitState.Unix.cs
index cb3d491047..b2d689c300 100644
--- a/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessWaitState.Unix.cs
+++ b/src/System.Diagnostics.Process/src/System/Diagnostics/ProcessWaitState.Unix.cs
@@ -63,9 +63,9 @@ namespace System.Diagnostics
{
internal ProcessWaitState _state;
- internal Holder(int processId)
+ internal Holder(int processId, bool isNewChild = false)
{
- _state = ProcessWaitState.AddRef(processId);
+ _state = ProcessWaitState.AddRef(processId, isNewChild);
}
~Holder()
@@ -90,28 +90,50 @@ namespace System.Diagnostics
}
/// <summary>
- /// Global table that maps process IDs to the associated shared wait state information.
+ /// Global table that maps process IDs of non-child Processes to the associated shared wait state information.
/// </summary>
private static readonly Dictionary<int, ProcessWaitState> s_processWaitStates =
new Dictionary<int, ProcessWaitState>();
/// <summary>
+ /// Global table that maps process IDs of child Processes to the associated shared wait state information.
+ /// </summary>
+ private static readonly Dictionary<int, ProcessWaitState> s_childProcessWaitStates =
+ new Dictionary<int, ProcessWaitState>();
+
+ /// <summary>
/// Ensures that the mapping table contains an entry for the process ID,
/// increments its ref count, and returns it.
/// </summary>
/// <param name="processId">The process ID for which we need wait state.</param>
/// <returns>The wait state object.</returns>
- internal static ProcessWaitState AddRef(int processId)
+ internal static ProcessWaitState AddRef(int processId, bool isNewChild)
{
- lock (s_processWaitStates)
+ lock (s_childProcessWaitStates)
{
ProcessWaitState pws;
- if (!s_processWaitStates.TryGetValue(processId, out pws))
+ if (isNewChild)
{
- pws = new ProcessWaitState(processId);
- s_processWaitStates.Add(processId, pws);
+ pws = new ProcessWaitState(processId, isChild: true);
+ s_childProcessWaitStates.Add(processId, pws);
+ pws._outstandingRefCount++; // For Holder
+ pws._outstandingRefCount++; // Decremented in CheckChildren
+ }
+ else
+ {
+ lock (s_processWaitStates)
+ {
+ // We are referencing an existing process.
+ // This may be a child process, so we check s_childProcessWaitStates too.
+ if (!s_childProcessWaitStates.TryGetValue(processId, out pws) &&
+ !s_processWaitStates.TryGetValue(processId, out pws))
+ {
+ pws = new ProcessWaitState(processId, isChild: false);
+ s_processWaitStates.Add(processId, pws);
+ }
+ pws._outstandingRefCount++;
+ }
}
- pws._outstandingRefCount++;
return pws;
}
}
@@ -120,19 +142,22 @@ namespace System.Diagnostics
/// Decrements the ref count on the wait state object, and if it's the last one,
/// removes it from the table.
/// </summary>
- internal void ReleaseRef()
+ internal bool ReleaseRef()
{
ProcessWaitState pws;
- lock (ProcessWaitState.s_processWaitStates)
+ Dictionary<int, ProcessWaitState> waitStates = _isChild ? s_childProcessWaitStates : s_processWaitStates;
+ bool removed = false;
+ lock (waitStates)
{
- bool foundState = ProcessWaitState.s_processWaitStates.TryGetValue(_processId, out pws);
+ bool foundState = waitStates.TryGetValue(_processId, out pws);
Debug.Assert(foundState);
if (foundState)
{
--pws._outstandingRefCount;
if (pws._outstandingRefCount == 0)
{
- s_processWaitStates.Remove(_processId);
+ waitStates.Remove(_processId);
+ removed = true;
}
else
{
@@ -141,6 +166,7 @@ namespace System.Diagnostics
}
}
pws?.Dispose();
+ return removed;
}
/// <summary>
@@ -151,6 +177,8 @@ namespace System.Diagnostics
private readonly object _gate = new object();
/// <summary>ID of the associated process.</summary>
private readonly int _processId;
+ /// <summary>Associated process is a child process.</summary>
+ private readonly bool _isChild;
/// <summary>If a wait operation is in progress, the Task that represents it; otherwise, null.</summary>
private Task _waitInProgress;
@@ -171,10 +199,11 @@ namespace System.Diagnostics
/// <summary>Initialize the wait state object.</summary>
/// <param name="processId">The associated process' ID.</param>
- private ProcessWaitState(int processId)
+ private ProcessWaitState(int processId, bool isChild)
{
Debug.Assert(processId >= 0);
_processId = processId;
+ _isChild = isChild;
}
/// <summary>Releases managed resources used by the ProcessWaitState.</summary>
@@ -218,13 +247,16 @@ namespace System.Diagnostics
_exitedEvent = new ManualResetEvent(initialState: _exited);
if (!_exited)
{
- // If we haven't exited, we need to spin up an asynchronous operation that
- // will completed the exitedEvent when the other process exits. If there's already
- // another operation underway, then we'll just tack ours onto the end of it.
- _waitInProgress = _waitInProgress == null ?
- WaitForExitAsync() :
- _waitInProgress.ContinueWith((_, state) => ((ProcessWaitState)state).WaitForExitAsync(),
- this, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Default).Unwrap();
+ if (!_isChild)
+ {
+ // If we haven't exited, we need to spin up an asynchronous operation that
+ // will completed the exitedEvent when the other process exits. If there's already
+ // another operation underway, then we'll just tack ours onto the end of it.
+ _waitInProgress = _waitInProgress == null ?
+ WaitForExitAsync() :
+ _waitInProgress.ContinueWith((_, state) => ((ProcessWaitState)state).WaitForExitAsync(),
+ this, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Default).Unwrap();
+ }
}
}
return _exitedEvent;
@@ -264,7 +296,7 @@ namespace System.Diagnostics
}
// Is another wait operation in progress? If so, then we haven't exited,
- // and that task owns the right to call CheckForExit.
+ // and that task owns the right to call CheckForNonChildExit.
if (_waitInProgress != null)
{
exitCode = null;
@@ -273,7 +305,7 @@ namespace System.Diagnostics
// We don't know if we've exited, but no one else is currently
// checking, so check.
- CheckForExit();
+ CheckForNonChildExit();
// We now have an up-to-date snapshot for whether we've exited,
// and if we have, what the exit code is (if we were able to find out).
@@ -282,78 +314,40 @@ namespace System.Diagnostics
}
}
- private void CheckForExit(bool blockingAllowed = false)
+ private void CheckForNonChildExit()
{
Debug.Assert(Monitor.IsEntered(_gate));
- Debug.Assert(!blockingAllowed); // see "PERF NOTE" comment in WaitForExit
-
- // Try to get the state of the (child) process
- int status;
- int waitResult = Interop.Sys.WaitPid(_processId, out status,
- blockingAllowed ? Interop.Sys.WaitPidOptions.None : Interop.Sys.WaitPidOptions.WNOHANG);
-
- if (waitResult == _processId)
+ if (!_isChild)
{
- // Process has exited
- if (Interop.Sys.WIfExited(status))
+ // We won't be able to get an exit code, but we'll at least be able to determine if the process is
+ // still running.
+ int killResult = Interop.Sys.Kill(_processId, Interop.Sys.Signals.None); // None means don't send a signal
+ if (killResult == 0)
{
- _exitCode = Interop.Sys.WExitStatus(status);
+ // Process is still running. This could also be a defunct process that has completed
+ // its work but still has an entry in the processes table due to its parent not yet
+ // having waited on it to clean it up.
+ return;
}
- else if (Interop.Sys.WIfSignaled(status))
+ else // error from kill
{
- const int ExitCodeSignalOffset = 128;
- _exitCode = ExitCodeSignalOffset + Interop.Sys.WTermSig(status);
- }
- SetExited();
- return;
- }
- else if (waitResult == 0)
- {
- // Process is still running
- return;
- }
- else if (waitResult == -1)
- {
- // Something went wrong, e.g. it's not a child process,
- // or waitpid was already called for this child, or
- // that the call was interrupted by a signal.
- Interop.Error errno = Interop.Sys.GetLastError();
- if (errno == Interop.Error.ECHILD)
- {
- // waitpid was used with a non-child process. We won't be
- // able to get an exit code, but we'll at least be able
- // to determine if the process is still running (assuming
- // there's not a race on its id).
- int killResult = Interop.Sys.Kill(_processId, Interop.Sys.Signals.None); // None means don't send a signal
- if (killResult == 0)
+ Interop.Error errno = Interop.Sys.GetLastError();
+ if (errno == Interop.Error.ESRCH)
{
- // Process is still running. This could also be a defunct process that has completed
- // its work but still has an entry in the processes table due to its parent not yet
- // having waited on it to clean it up.
+ // Couldn't find the process; assume it's exited
+ SetExited();
return;
}
- else // error from kill
+ else if (errno == Interop.Error.EPERM)
{
- errno = Interop.Sys.GetLastError();
- if (errno == Interop.Error.ESRCH)
- {
- // Couldn't find the process; assume it's exited
- SetExited();
- return;
- }
- else if (errno == Interop.Error.EPERM)
- {
- // Don't have permissions to the process; assume it's alive
- return;
- }
- else Debug.Fail("Unexpected errno value from kill");
+ // Don't have permissions to the process; assume it's alive
+ return;
}
+ else Debug.Fail("Unexpected errno value from kill");
}
- else Debug.Fail("Unexpected errno value from waitpid");
- }
- else Debug.Fail("Unexpected process ID from waitpid.");
- SetExited();
+ SetExited();
+ }
}
/// <summary>Waits for the associated process to exit.</summary>
@@ -363,21 +357,8 @@ namespace System.Diagnostics
{
Debug.Assert(!Monitor.IsEntered(_gate));
- // Track the time the we start waiting.
- long startTime = Stopwatch.GetTimestamp();
-
- // Polling loop
- while (true)
+ if (_isChild)
{
- bool createdTask = false;
- CancellationTokenSource cts = null;
- Task waitTask;
-
- // We're in a polling loop... determine how much time remains
- int remainingTimeout = millisecondsTimeout == Timeout.Infinite ?
- Timeout.Infinite :
- (int)Math.Max(millisecondsTimeout - ((Stopwatch.GetTimestamp() - startTime) / (double)Stopwatch.Frequency * 1000), 0);
-
lock (_gate)
{
// If we already know that the process exited, we're done.
@@ -385,75 +366,93 @@ namespace System.Diagnostics
{
return true;
}
+ }
+ ManualResetEvent exitEvent = EnsureExitedEvent();
+ return exitEvent.WaitOne(millisecondsTimeout);
+ }
+ else
+ {
+ // Track the time the we start waiting.
+ long startTime = Stopwatch.GetTimestamp();
+
+ // Polling loop
+ while (true)
+ {
+ bool createdTask = false;
+ CancellationTokenSource cts = null;
+ Task waitTask;
+
+ // We're in a polling loop... determine how much time remains
+ int remainingTimeout = millisecondsTimeout == Timeout.Infinite ?
+ Timeout.Infinite :
+ (int)Math.Max(millisecondsTimeout - ((Stopwatch.GetTimestamp() - startTime) / (double)Stopwatch.Frequency * 1000), 0);
- // If a timeout of 0 was supplied, then we simply need to poll
- // to see if the process has already exited.
- if (remainingTimeout == 0)
+ lock (_gate)
{
- // If there's currently a wait-in-progress, then we know the other process
- // hasn't exited (barring races and the polling interval).
- if (_waitInProgress != null)
+ // If we already know that the process exited, we're done.
+ if (_exited)
{
- return false;
+ return true;
}
- // No one else is checking for the process' exit... so check.
- // We're currently holding the _gate lock, so we don't want to
- // allow CheckForExit to block indefinitely.
- CheckForExit();
- return _exited;
- }
+ // If a timeout of 0 was supplied, then we simply need to poll
+ // to see if the process has already exited.
+ if (remainingTimeout == 0)
+ {
+ // If there's currently a wait-in-progress, then we know the other process
+ // hasn't exited (barring races and the polling interval).
+ if (_waitInProgress != null)
+ {
+ return false;
+ }
+
+ // No one else is checking for the process' exit... so check.
+ // We're currently holding the _gate lock, so we don't want to
+ // allow CheckForNonChildExit to block indefinitely.
+ CheckForNonChildExit();
+ return _exited;
+ }
+
+ // The process has not yet exited (or at least we don't know it yet)
+ // so we need to wait for it to exit, outside of the lock.
+ // If there's already a wait in progress, we'll do so later
+ // by waiting on that existing task. Otherwise, we'll spin up
+ // such a task.
+ if (_waitInProgress != null)
+ {
+ waitTask = _waitInProgress;
+ }
+ else
+ {
+ createdTask = true;
+ CancellationToken token = remainingTimeout == Timeout.Infinite ?
+ CancellationToken.None :
+ (cts = new CancellationTokenSource(remainingTimeout)).Token;
+ waitTask = WaitForExitAsync(token);
+ }
+ } // lock(_gate)
- // The process has not yet exited (or at least we don't know it yet)
- // so we need to wait for it to exit, outside of the lock.
- // If there's already a wait in progress, we'll do so later
- // by waiting on that existing task. Otherwise, we'll spin up
- // such a task.
- if (_waitInProgress != null)
+ if (createdTask)
{
- waitTask = _waitInProgress;
+ // We created this task, and it'll get canceled automatically after our timeout.
+ // This Wait should only wake up when either the process has exited or the timeout
+ // has expired. Either way, we'll loop around again; if the process exited, that'll
+ // be caught first thing in the loop where we check _exited, and if it didn't exit,
+ // our remaining time will be zero, so we'll do a quick remaining check and bail.
+ waitTask.Wait();
+ cts?.Dispose();
}
else
{
- createdTask = true;
- CancellationToken token = remainingTimeout == Timeout.Infinite ?
- CancellationToken.None :
- (cts = new CancellationTokenSource(remainingTimeout)).Token;
- waitTask = WaitForExitAsync(token);
-
- // PERF NOTE:
- // At the moment, we never call CheckForExit(true) (which in turn allows
- // waitpid to block until the child has completed) because we currently call it while
- // holding the _gate lock. This is probably unnecessary in some situations, and in particular
- // here if remainingTimeout == Timeout.Infinite. In that case, we should be able to set
- // _waitInProgress to be a TaskCompletionSource task, and then below outside of the lock
- // we could do a CheckForExit(blockingAllowed:true) and complete the TaskCompletionSource
- // after that. We would just need to make sure that there's no risk of the other state
- // on this instance experiencing torn reads.
+ // It's someone else's task. We'll wait for it to complete. This could complete
+ // either because our remainingTimeout expired or because the task completed,
+ // which could happen because the process exited or because whoever created
+ // that task gave it a timeout. In any case, we'll loop around again, and the loop
+ // will catch these cases, potentially issuing another wait to make up any
+ // remaining time.
+ waitTask.Wait(remainingTimeout);
}
- } // lock(_gate)
-
- if (createdTask)
- {
- // We created this task, and it'll get canceled automatically after our timeout.
- // This Wait should only wake up when either the process has exited or the timeout
- // has expired. Either way, we'll loop around again; if the process exited, that'll
- // be caught first thing in the loop where we check _exited, and if it didn't exit,
- // our remaining time will be zero, so we'll do a quick remaining check and bail.
- waitTask.Wait();
- cts?.Dispose();
- }
- else
- {
- // It's someone else's task. We'll wait for it to complete. This could complete
- // either because our remainingTimeout expired or because the task completed,
- // which could happen because the process exited or because whoever created
- // that task gave it a timeout. In any case, we'll loop around again, and the loop
- // will catch these cases, potentially issuing another wait to make up any
- // remaining time.
- waitTask.Wait(remainingTimeout);
}
-
}
}
@@ -464,8 +463,9 @@ namespace System.Diagnostics
{
Debug.Assert(Monitor.IsEntered(_gate));
Debug.Assert(_waitInProgress == null);
+ Debug.Assert(!_isChild);
- return _waitInProgress = Task.Run(async delegate // Task.Run used because of potential blocking in CheckForExit
+ return _waitInProgress = Task.Run(async delegate // Task.Run used because of potential blocking in CheckForNonChildExit
{
// Arbitrary values chosen to balance delays with polling overhead. Start with fast polling
// to handle quickly completing processes, but fall back to longer polling to minimize
@@ -483,9 +483,9 @@ namespace System.Diagnostics
{
if (!_exited)
{
- CheckForExit();
+ CheckForNonChildExit();
}
- if (_exited) // may have been updated by CheckForExit
+ if (_exited) // may have been updated by CheckForNonChildExit
{
return;
}
@@ -511,5 +511,132 @@ namespace System.Diagnostics
});
}
+ private bool TryReapChild()
+ {
+ lock (_gate)
+ {
+ if (_exited)
+ {
+ return false;
+ }
+
+ // Try to get the state of the child process
+ int exitCode;
+ int waitResult = Interop.Sys.WaitIdExitedNoHang(_processId, out exitCode, keepWaitable: false);
+
+ if (waitResult == _processId)
+ {
+ _exitCode = exitCode;
+
+ SetExited();
+ return true;
+ }
+ else if (waitResult == 0)
+ {
+ // Process is still running
+ }
+ else
+ {
+ // Unexpected.
+ int errorCode = Marshal.GetLastWin32Error();
+ Environment.FailFast("Error while reaping child. errno = " + errorCode);
+ }
+ return false;
+ }
+ }
+
+ internal static void CheckChildren(bool reapAll)
+ {
+ // This is called on SIGCHLD from a native thread.
+ // A lock in Process ensures no new processes are spawned while we are checking.
+ lock (s_childProcessWaitStates)
+ {
+ bool checkAll = false;
+
+ // Check terminated processes.
+ int pid;
+ do
+ {
+ // Find a process that terminated without reaping it yet.
+ int exitCode;
+ pid = Interop.Sys.WaitIdExitedNoHang(-1, out exitCode, keepWaitable: true);
+ if (pid > 0)
+ {
+ if (s_childProcessWaitStates.TryGetValue(pid, out ProcessWaitState pws))
+ {
+ // Known Process.
+ if (pws.TryReapChild())
+ {
+ pws.ReleaseRef();
+ }
+ }
+ else
+ {
+ // unlikely: This is not a managed Process, so we are not responsible for reaping.
+ // Fall back to checking all Processes.
+ checkAll = true;
+ break;
+ }
+ }
+ else if (pid == 0)
+ {
+ // No more terminated children.
+ }
+ else
+ {
+ // Unexpected.
+ int errorCode = Marshal.GetLastWin32Error();
+ Environment.FailFast("Error while checking for terminated children. errno = " + errorCode);
+ }
+ } while (pid > 0);
+
+ if (checkAll)
+ {
+ // We track things to unref so we don't invalidate our iterator by changing s_childProcessWaitStates.
+ ProcessWaitState firstToRemove = null;
+ List<ProcessWaitState> additionalToRemove = null;
+ foreach (KeyValuePair<int, ProcessWaitState> kv in s_childProcessWaitStates)
+ {
+ ProcessWaitState pws = kv.Value;
+ if (pws.TryReapChild())
+ {
+ if (firstToRemove == null)
+ {
+ firstToRemove = pws;
+ }
+ else
+ {
+ if (additionalToRemove == null)
+ {
+ additionalToRemove = new List<ProcessWaitState>();
+ }
+ additionalToRemove.Add(pws);
+ }
+ }
+ }
+
+ if (firstToRemove != null)
+ {
+ firstToRemove.ReleaseRef();
+ if (additionalToRemove != null)
+ {
+ foreach (ProcessWaitState pws in additionalToRemove)
+ {
+ pws.ReleaseRef();
+ }
+ }
+ }
+ }
+
+ if (reapAll)
+ {
+ do
+ {
+ int exitCode;
+ pid = Interop.Sys.WaitIdExitedNoHang(-1, out exitCode, keepWaitable: false);
+ } while (pid > 0);
+ }
+ }
+ }
}
}
diff --git a/src/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs b/src/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs
index d028b3828f..ac99b1825d 100644
--- a/src/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs
+++ b/src/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs
@@ -346,7 +346,7 @@ namespace System.Diagnostics.Tests
public void TestWorkingDirectoryProperty()
{
CreateDefaultProcess();
-
+
// check defaults
Assert.Equal(string.Empty, _process.StartInfo.WorkingDirectory);
@@ -498,7 +498,7 @@ namespace System.Diagnostics.Tests
Assert.Equal("NewValue", kvpaOrdered[2].Value);
psi.EnvironmentVariables.Remove("NewKey3");
- Assert.False(psi.Environment.Contains(new KeyValuePair<string,string>("NewKey3", "NewValue3")));
+ Assert.False(psi.Environment.Contains(new KeyValuePair<string, string>("NewKey3", "NewValue3")));
}
[Fact]
@@ -603,7 +603,7 @@ namespace System.Diagnostics.Tests
// modify the registry.
return;
}
-
+
tempKey.Key.SetValue("", 123);
var info = new ProcessStartInfo { FileName = FileName };
@@ -626,7 +626,7 @@ namespace System.Diagnostics.Tests
// modify the registry.
return;
}
-
+
tempKey.Key.SetValue("", "nosuchshell");
var info = new ProcessStartInfo { FileName = FileName };
@@ -653,7 +653,7 @@ namespace System.Diagnostics.Tests
}
extensionKey.Key.SetValue("", SubKeyValue);
-
+
shellKey.Key.CreateSubKey("verb1");
shellKey.Key.CreateSubKey("NEW");
shellKey.Key.CreateSubKey("new");
@@ -746,7 +746,7 @@ namespace System.Diagnostics.Tests
Assert.Throws<KeyNotFoundException>(() =>
{
string stringout = environmentVariables["NewKey99"];
- });
+ });
//Exception not thrown with invalid key
Assert.Throws<ArgumentNullException>(() =>
@@ -887,22 +887,12 @@ namespace System.Diagnostics.Tests
[InlineData(null)]
[InlineData("")]
[InlineData("domain")]
- [PlatformSpecific(TestPlatforms.Windows)]
- public void UserName_SetWindows_GetReturnsExpected(string userName)
+ public void UserName_Set_GetReturnsExpected(string userName)
{
var info = new ProcessStartInfo { UserName = userName };
Assert.Equal(userName ?? string.Empty, info.UserName);
}
- [Fact]
- [PlatformSpecific(TestPlatforms.AnyUnix)]
- public void UserName_GetSetUnix_ThrowsPlatformNotSupportedException()
- {
- var info = new ProcessStartInfo();
- Assert.Throws<PlatformNotSupportedException>(() => info.UserName);
- Assert.Throws<PlatformNotSupportedException>(() => info.UserName = "username");
- }
-
[Theory]
[InlineData(null)]
[InlineData("")]
@@ -954,7 +944,10 @@ namespace System.Diagnostics.Tests
FileName = @"http://www.microsoft.com"
};
- Process.Start(info); // Returns null after navigating browser
+ using (var p = Process.Start(info))
+ {
+ Assert.NotNull(p);
+ }
}
[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))] // No Notepad on Nano
@@ -994,6 +987,7 @@ namespace System.Diagnostics.Tests
}
}
}
+
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer), // Nano does not support UseShellExecute
nameof(PlatformDetection.IsNotWindows8x))] // https://github.com/dotnet/corefx/issues/20388
[OuterLoop("Launches notepad")]
@@ -1085,7 +1079,6 @@ namespace System.Diagnostics.Tests
return sb.ToString();
}
-
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsWindowsNanoServer))]
public void ShellExecute_Nano_Fails_Start()
{
@@ -1118,6 +1111,7 @@ namespace System.Diagnostics.Tests
private const int ERROR_FILE_NOT_FOUND = 0x2;
private const int ERROR_BAD_EXE_FORMAT = 0xC1;
+ [Theory]
[MemberData(nameof(UseShellExecute))]
[PlatformSpecific(TestPlatforms.Windows)]
public void StartInfo_BadVerb(bool useShellExecute)
@@ -1132,6 +1126,7 @@ namespace System.Diagnostics.Tests
Assert.Equal(ERROR_FILE_NOT_FOUND, Assert.Throws<Win32Exception>(() => Process.Start(info)).NativeErrorCode);
}
+ [Theory]
[MemberData(nameof(UseShellExecute))]
[PlatformSpecific(TestPlatforms.Windows)]
public void StartInfo_BadExe(bool useShellExecute)
diff --git a/src/System.Diagnostics.Process/tests/ProcessStartInfoTests.netcoreapp.cs b/src/System.Diagnostics.Process/tests/ProcessStartInfoTests.netcoreapp.cs
new file mode 100644
index 0000000000..3d730f4152
--- /dev/null
+++ b/src/System.Diagnostics.Process/tests/ProcessStartInfoTests.netcoreapp.cs
@@ -0,0 +1,74 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.IO;
+using Xunit;
+
+namespace System.Diagnostics.Tests
+{
+ public partial class ProcessStartInfoTests
+ {
+ [Fact]
+ public void UnintializedArgumentList()
+ {
+ ProcessStartInfo psi = new ProcessStartInfo();
+ Assert.Equal(0, psi.ArgumentList.Count);
+
+ psi = new ProcessStartInfo("filename", "-arg1 -arg2");
+ Assert.Equal(0, psi.ArgumentList.Count);
+ }
+
+ [Fact]
+ public void InitializeWithArgumentList()
+ {
+ ProcessStartInfo psi = new ProcessStartInfo("filename");
+ psi.ArgumentList.Add("arg1");
+ psi.ArgumentList.Add("arg2");
+
+ Assert.Equal(2, psi.ArgumentList.Count);
+ Assert.Equal("arg1", psi.ArgumentList[0]);
+ Assert.Equal("arg2", psi.ArgumentList[1]);
+ }
+
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))] // No Notepad on Nano
+ [MemberData(nameof(UseShellExecute))]
+ [OuterLoop("Launches notepad")]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "WaitForInputIdle, ProcessName, and MainWindowTitle are not supported on UAP")]
+ public void StartInfo_NotepadWithContent_withArgumentList(bool useShellExecute)
+ {
+ string tempFile = GetTestFilePath() + ".txt";
+ File.WriteAllText(tempFile, $"StartInfo_NotepadWithContent({useShellExecute})");
+
+ ProcessStartInfo info = new ProcessStartInfo
+ {
+ UseShellExecute = useShellExecute,
+ FileName = @"notepad.exe",
+ Arguments = null,
+ WindowStyle = ProcessWindowStyle.Minimized
+ };
+
+ info.ArgumentList.Add(tempFile);
+
+ using (var process = Process.Start(info))
+ {
+ Assert.True(process != null, $"Could not start {info.FileName} {info.Arguments} UseShellExecute={info.UseShellExecute}");
+
+ try
+ {
+ process.WaitForInputIdle(); // Give the file a chance to load
+ Assert.Equal("notepad", process.ProcessName);
+
+ // On some Windows versions, the file extension is not included in the title
+ Assert.StartsWith(Path.GetFileNameWithoutExtension(tempFile), process.MainWindowTitle);
+ }
+ finally
+ {
+ if (process != null && !process.HasExited)
+ process.Kill();
+ }
+ }
+ }
+ }
+}
diff --git a/src/System.Diagnostics.Process/tests/ProcessTestBase.NonUap.cs b/src/System.Diagnostics.Process/tests/ProcessTestBase.NonUap.cs
index 3af496e8d1..3ce842e0e5 100644
--- a/src/System.Diagnostics.Process/tests/ProcessTestBase.NonUap.cs
+++ b/src/System.Diagnostics.Process/tests/ProcessTestBase.NonUap.cs
@@ -15,7 +15,12 @@ namespace System.Diagnostics.Tests
protected Process CreateProcessLong()
{
- return CreateProcess(RemotelyInvokable.LongWait);
+ return CreateSleepProcess(RemotelyInvokable.WaitInMS);
+ }
+
+ protected Process CreateSleepProcess(int durationMs)
+ {
+ return CreateProcess(RemotelyInvokable.Sleep, durationMs.ToString());
}
protected Process CreateProcessPortable(Func<int> func)
diff --git a/src/System.Diagnostics.Process/tests/ProcessTestBase.Uap.cs b/src/System.Diagnostics.Process/tests/ProcessTestBase.Uap.cs
index 7b38bce3c5..b8f32f9360 100644
--- a/src/System.Diagnostics.Process/tests/ProcessTestBase.Uap.cs
+++ b/src/System.Diagnostics.Process/tests/ProcessTestBase.Uap.cs
@@ -16,7 +16,12 @@ namespace System.Diagnostics.Tests
protected Process CreateProcessLong()
{
- return CreateProcessForUap(RemotelyInvokable.LongWait);
+ return CreateSleepProcess(RemotelyInvokable.WaitInMS);
+ }
+
+ protected Process CreateSleepProcess(int durationMs)
+ {
+ return CreateProcessForUap(RemotelyInvokable.Sleep, durationMs.ToString());
}
protected Process CreateProcessPortable(Func<int> func)
@@ -60,9 +65,9 @@ namespace System.Diagnostics.Tests
throw new Exception($"Method needs to be defined in {nameof(RemotelyInvokable)} class.");
}
- if (method.Name == nameof(RemotelyInvokable.LongWait))
+ if (method.Name == nameof(RemotelyInvokable.Sleep))
{
- return CreateLongWaitingProcess();
+ return CreateSleepProcess(int.Parse(args[0]));
}
MethodInfo uapMethod = GetMethodForUap(method);
@@ -80,21 +85,5 @@ namespace System.Diagnostics.Tests
AddProcessForDispose(p);
return p;
}
-
- private Process CreateLongWaitingProcess()
- {
- // timeout.exe does not work as expected on uap
- var p = new Process()
- {
- StartInfo = new ProcessStartInfo()
- {
- FileName = RunnerName,
- Arguments = "/K"
- }
- };
-
- AddProcessForDispose(p);
- return p;
- }
}
}
diff --git a/src/System.Diagnostics.Process/tests/ProcessTestBase.cs b/src/System.Diagnostics.Process/tests/ProcessTestBase.cs
index 55dd145af3..7ed082dd5d 100644
--- a/src/System.Diagnostics.Process/tests/ProcessTestBase.cs
+++ b/src/System.Diagnostics.Process/tests/ProcessTestBase.cs
@@ -51,14 +51,24 @@ namespace System.Diagnostics.Tests
protected Process CreateProcess(Func<int> method = null)
{
- Process p = RemoteInvoke(method ?? (() => SuccessExitCode), new RemoteInvokeOptions { Start = false }).Process;
+ Process p = null;
+ using (RemoteInvokeHandle handle = RemoteInvoke(method ?? (() => SuccessExitCode), new RemoteInvokeOptions { Start = false }))
+ {
+ p = handle.Process;
+ handle.Process = null;
+ }
AddProcessForDispose(p);
return p;
}
protected Process CreateProcess(Func<string, int> method, string arg)
{
- Process p = RemoteInvoke(method, arg, new RemoteInvokeOptions { Start = false }).Process;
+ Process p = null;
+ using (RemoteInvokeHandle handle = RemoteInvoke(method, arg, new RemoteInvokeOptions { Start = false }))
+ {
+ p = handle.Process;
+ handle.Process = null;
+ }
AddProcessForDispose(p);
return p;
}
diff --git a/src/System.Diagnostics.Process/tests/ProcessTests.Unix.cs b/src/System.Diagnostics.Process/tests/ProcessTests.Unix.cs
index e6ccb41268..479e593601 100644
--- a/src/System.Diagnostics.Process/tests/ProcessTests.Unix.cs
+++ b/src/System.Diagnostics.Process/tests/ProcessTests.Unix.cs
@@ -2,12 +2,15 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
+using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
+using System.Threading.Tasks;
using System.Security;
using Xunit;
using Xunit.NetCore.Extensions;
@@ -101,6 +104,25 @@ namespace System.Diagnostics.Tests
}
}
+ [Fact]
+ [OuterLoop]
+ public void ProcessStart_UseShellExecute_OnUnix_OpenMissingFile_DoesNotThrow()
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) &&
+ s_allowedProgramsToRun.FirstOrDefault(program => IsProgramInstalled(program)) == null)
+ {
+ return;
+ }
+ string fileToOpen = Path.Combine(Environment.CurrentDirectory, "_no_such_file.TXT");
+ using (var px = Process.Start(new ProcessStartInfo { UseShellExecute = true, FileName = fileToOpen }))
+ {
+ Assert.NotNull(px);
+ px.Kill();
+ px.WaitForExit();
+ Assert.True(px.HasExited);
+ }
+ }
+
[Theory, InlineData(true), InlineData(false)]
[OuterLoop("Opens program")]
public void ProcessStart_UseShellExecute_OnUnix_SuccessWhenProgramInstalled(bool isFolder)
@@ -156,6 +178,31 @@ namespace System.Diagnostics.Tests
}
}
+ [Theory, InlineData("nano"), InlineData("vi")]
+ [PlatformSpecific(TestPlatforms.Linux)]
+ [OuterLoop("Opens program")]
+ public void ProcessStart_OpenFileOnLinux_UsesSpecifiedProgramUsingArgumentList(string programToOpenWith)
+ {
+ if (IsProgramInstalled(programToOpenWith))
+ {
+ string fileToOpen = GetTestFilePath() + ".txt";
+ File.WriteAllText(fileToOpen, $"{nameof(ProcessStart_OpenFileOnLinux_UsesSpecifiedProgram)}");
+ ProcessStartInfo psi = new ProcessStartInfo(programToOpenWith);
+ psi.ArgumentList.Add(fileToOpen);
+ using (var px = Process.Start(psi))
+ {
+ Assert.Equal(programToOpenWith, px.ProcessName);
+ px.Kill();
+ px.WaitForExit();
+ Assert.True(px.HasExited);
+ }
+ }
+ else
+ {
+ Console.WriteLine($"Program specified to open file with {programToOpenWith} is not installed on this machine.");
+ }
+ }
+
[Theory, InlineData("/usr/bin/open"), InlineData("/usr/bin/nano")]
[PlatformSpecific(TestPlatforms.OSX)]
[OuterLoop("Opens program")]
@@ -202,6 +249,34 @@ namespace System.Diagnostics.Tests
}
}
+ public static TheoryData<string[]> StartOSXProcessWithArgumentList => new TheoryData<string[]>
+ {
+ { new string[] { "-a", "Safari" } },
+ { new string[] { "-a", "\"Google Chrome\"" } }
+ };
+
+ [Theory,
+ MemberData(nameof(StartOSXProcessWithArgumentList))]
+ [PlatformSpecific(TestPlatforms.OSX)]
+ [OuterLoop("Opens browser")]
+ public void ProcessStart_UseShellExecuteTrue_OpenUrl_SuccessfullyReadsArgument(string[] argumentList)
+ {
+ var startInfo = new ProcessStartInfo { UseShellExecute = true, FileName = "https://github.com/dotnet/corefx"};
+
+ foreach (string item in argumentList)
+ {
+ startInfo.ArgumentList.Add(item);
+ }
+
+ using (var px = Process.Start(startInfo))
+ {
+ Assert.NotNull(px);
+ px.Kill();
+ px.WaitForExit();
+ Assert.True(px.HasExited);
+ }
+ }
+
[Fact]
[Trait(XunitConstants.Category, XunitConstants.RequiresElevation)]
public void TestPriorityClassUnix()
@@ -304,9 +379,293 @@ namespace System.Diagnostics.Tests
}
}
+ [Fact]
+ public void TestStartWithNonExistingUserThrows()
+ {
+ Process p = CreateProcessPortable(RemotelyInvokable.Dummy);
+ p.StartInfo.UserName = "DoesNotExist";
+ Assert.Throws<Win32Exception>(() => p.Start());
+ }
+
+ /// <summary>
+ /// Tests when running as a normal user and starting a new process as the same user
+ /// works as expected.
+ /// </summary>
+ [Fact]
+ public void TestStartWithNormalUser()
+ {
+ TestStartWithUserName(GetCurrentRealUserName());
+ }
+
+ /// <summary>
+ /// Tests when running as root and starting a new process as a normal user,
+ /// the new process doesn't have elevated privileges.
+ /// </summary>
+ [Fact]
+ [OuterLoop("Needs sudo access")]
+ [Trait(XunitConstants.Category, XunitConstants.RequiresElevation)]
+ public void TestStartWithRootUser()
+ {
+ RunTestAsSudo(TestStartWithUserName, GetCurrentRealUserName());
+ }
+
+ public static int TestStartWithUserName(string realUserName)
+ {
+ Assert.NotNull(realUserName);
+ Assert.NotEqual("root", realUserName);
+
+ using (ProcessTests testObject = new ProcessTests())
+ {
+ using (Process p = testObject.CreateProcessPortable(GetCurrentEffectiveUserId))
+ {
+ p.StartInfo.UserName = realUserName;
+ Assert.True(p.Start());
+
+ p.WaitForExit();
+
+ // since the process was started with the current real user, even if this test
+ // was run with 'sudo', the child process will be run as the normal real user.
+ // Assert that the effective user of the child process was never 'root'
+ // and was the real user of this process.
+ Assert.NotEqual(0, p.ExitCode);
+ }
+
+ return 0;
+ }
+ }
+
+ public static int GetCurrentEffectiveUserId()
+ {
+ return (int)geteuid();
+ }
+
+ private static string GetCurrentRealUserName()
+ {
+ string realUserName = geteuid() == 0 ?
+ Environment.GetEnvironmentVariable("SUDO_USER") :
+ Environment.UserName;
+
+ Assert.NotNull(realUserName);
+ Assert.NotEqual("root", realUserName);
+
+ return realUserName;
+ }
+
+ /// <summary>
+ /// Tests when running as root and starting a new process as a normal user,
+ /// the new process can't elevate back to root.
+ /// </summary>
+ [Fact]
+ [OuterLoop("Needs sudo access")]
+ [Trait(XunitConstants.Category, XunitConstants.RequiresElevation)]
+ public void TestStartWithRootUserCannotElevate()
+ {
+ RunTestAsSudo(TestStartWithUserNameCannotElevate, GetCurrentRealUserName());
+ }
+
+ /// <summary>
+ /// Tests whether child processes are reaped (cleaning up OS resources)
+ /// when they terminate.
+ /// </summary>
+ [Fact]
+ [PlatformSpecific(TestPlatforms.Linux)] // Test uses Linux specific '/proc' filesystem
+ public async Task TestChildProcessCleanup()
+ {
+ using (Process process = CreateShortProcess())
+ {
+ process.Start();
+ bool processReaped = await TryWaitProcessReapedAsync(process.Id, timeoutMs: 30000);
+ Assert.True(processReaped);
+ }
+ }
+
+ /// <summary>
+ /// Tests whether child processes are reaped (cleaning up OS resources)
+ /// when they terminate after the Process was Disposed.
+ /// </summary>
+ [Theory]
+ [InlineData(false, false)]
+ [InlineData(false, true)]
+ [InlineData(true, false)]
+ [InlineData(true, true)]
+ [PlatformSpecific(TestPlatforms.Linux)] // Test uses Linux specific '/proc' filesystem
+ public async Task TestChildProcessCleanupAfterDispose(bool shortProcess, bool enableEvents)
+ {
+ // We test using a long and short process. The long process will terminate after Dispose,
+ // The short process will terminate at the same time, possibly revealing race conditions.
+ int processId = -1;
+ using (Process process = shortProcess ? CreateShortProcess() : CreateSleepProcess(durationMs: 500))
+ {
+ process.Start();
+ processId = process.Id;
+ if (enableEvents)
+ {
+ // Dispose will disable the Exited event.
+ // We enable it to check this doesn't cause issues for process reaping.
+ process.EnableRaisingEvents = true;
+ }
+ }
+ bool processReaped = await TryWaitProcessReapedAsync(processId, timeoutMs: 30000);
+ Assert.True(processReaped);
+ }
+
+ private static Process CreateShortProcess()
+ {
+ Process process = new Process();
+ process.StartInfo.FileName = "uname";
+ return process;
+ }
+
+ private static async Task<bool> TryWaitProcessReapedAsync(int pid, int timeoutMs)
+ {
+ const int SleepTimeMs = 50;
+ // When the process is reaped, the '/proc/<pid>' directory to disappears.
+ bool procPidExists = true;
+ for (int attempt = 0; attempt < (timeoutMs / SleepTimeMs); attempt++)
+ {
+ procPidExists = Directory.Exists("/proc/" + pid);
+ if (procPidExists)
+ {
+ await Task.Delay(SleepTimeMs);
+ }
+ else
+ {
+ break;
+ }
+ }
+ return !procPidExists;
+ }
+
+ /// <summary>
+ /// Tests the ProcessWaitState reference count drops to zero.
+ /// </summary>
+ [Fact]
+ [PlatformSpecific(TestPlatforms.AnyUnix)] // Test validates Unix implementation
+ public async Task TestProcessWaitStateReferenceCount()
+ {
+ using (var exitedEventSemaphore = new SemaphoreSlim(0, 1))
+ {
+ object waitState = null;
+ int processId = -1;
+ // Process takes a reference
+ using (var process = CreateShortProcess())
+ {
+ process.EnableRaisingEvents = true;
+ // Exited event takes a reference
+ process.Exited += (o,e) => exitedEventSemaphore.Release();
+ process.Start();
+
+ processId = process.Id;
+ waitState = GetProcessWaitState(process);
+
+ process.WaitForExit();
+
+ Assert.False(GetWaitStateDictionary(childDictionary: false).Contains(processId));
+ Assert.True(GetWaitStateDictionary(childDictionary: true).Contains(processId));
+ }
+ exitedEventSemaphore.Wait();
+
+ // Child reaping holds a reference too
+ int referenceCount = -1;
+ const int SleepTimeMs = 50;
+ for (int i = 0; i < (30000 / SleepTimeMs); i++)
+ {
+ referenceCount = GetWaitStateReferenceCount(waitState);
+ if (referenceCount == 0)
+ {
+ break;
+ }
+ else
+ {
+ // Process was reaped but ProcessWaitState not unrefed yet
+ await Task.Delay(SleepTimeMs);
+ }
+ }
+ Assert.Equal(0, referenceCount);
+
+ Assert.Equal(0, GetWaitStateReferenceCount(waitState));
+ Assert.False(GetWaitStateDictionary(childDictionary: false).Contains(processId));
+ Assert.False(GetWaitStateDictionary(childDictionary: true).Contains(processId));
+ }
+ }
+
+ private static IDictionary GetWaitStateDictionary(bool childDictionary)
+ {
+ Assembly assembly = typeof(Process).Assembly;
+ Type waitStateType = assembly.GetType("System.Diagnostics.ProcessWaitState");
+ FieldInfo dictionaryField = waitStateType.GetField(childDictionary ? "s_childProcessWaitStates" : "s_processWaitStates", BindingFlags.NonPublic | BindingFlags.Static);
+ return (IDictionary)dictionaryField.GetValue(null);
+ }
+
+ private static object GetProcessWaitState(Process p)
+ {
+ MethodInfo getWaitState = typeof(Process).GetMethod("GetWaitState", BindingFlags.NonPublic | BindingFlags.Instance);
+ return getWaitState.Invoke(p, null);
+ }
+
+ private static int GetWaitStateReferenceCount(object waitState)
+ {
+ FieldInfo referenCountField = waitState.GetType().GetField("_outstandingRefCount", BindingFlags.NonPublic | BindingFlags.Instance);
+ return (int)referenCountField.GetValue(waitState);
+ }
+
+ public static int TestStartWithUserNameCannotElevate(string realUserName)
+ {
+ Assert.NotNull(realUserName);
+ Assert.NotEqual("root", realUserName);
+
+ using (ProcessTests testObject = new ProcessTests())
+ {
+ using (Process p = testObject.CreateProcessPortable(SetEffectiveUserIdToRoot))
+ {
+ p.StartInfo.UserName = realUserName;
+ Assert.True(p.Start());
+
+ p.WaitForExit();
+
+ // seteuid(0) should not have succeeded, thus the exit code should be non-zero
+ Assert.NotEqual(0, p.ExitCode);
+ }
+
+ return 0;
+ }
+ }
+
+ public static int SetEffectiveUserIdToRoot()
+ {
+ return seteuid(0);
+ }
+
+ private void RunTestAsSudo(Func<string, int> testMethod, string arg)
+ {
+ RemoteInvokeOptions options = new RemoteInvokeOptions()
+ {
+ Start = false,
+ RunAsSudo = true
+ };
+ Process p = null;
+ using (RemoteInvokeHandle handle = RemoteInvoke(testMethod, arg, options))
+ {
+ p = handle.Process;
+ handle.Process = null;
+ }
+ AddProcessForDispose(p);
+
+ p.Start();
+ p.WaitForExit();
+
+ Assert.Equal(0, p.ExitCode);
+ }
+
[DllImport("libc")]
private static extern int chmod(string path, int mode);
- private readonly string[] s_allowedProgramsToRun = new string[] { "xdg-open", "gnome-open", "kfmclient" };
+ [DllImport("libc")]
+ private static extern uint geteuid();
+
+ [DllImport("libc")]
+ private static extern int seteuid(uint euid);
+
+ private static readonly string[] s_allowedProgramsToRun = new string[] { "xdg-open", "gnome-open", "kfmclient" };
}
}
diff --git a/src/System.Diagnostics.Process/tests/ProcessTests.cs b/src/System.Diagnostics.Process/tests/ProcessTests.cs
index 1dbd3f5385..aa94bfd54b 100644
--- a/src/System.Diagnostics.Process/tests/ProcessTests.cs
+++ b/src/System.Diagnostics.Process/tests/ProcessTests.cs
@@ -122,19 +122,19 @@ namespace System.Diagnostics.Tests
[Fact]
public void ProcessStart_TryExitCommandAsFileName_ThrowsWin32Exception()
{
- Win32Exception e = Assert.Throws<Win32Exception>(() => Process.Start(new ProcessStartInfo { UseShellExecute = false, FileName = "exit", Arguments = "42" }));
+ Assert.Throws<Win32Exception>(() => Process.Start(new ProcessStartInfo { UseShellExecute = false, FileName = "exit", Arguments = "42" }));
}
[Fact]
public void ProcessStart_UseShellExecuteFalse_FilenameIsUrl_ThrowsWin32Exception()
{
- Win32Exception e = Assert.Throws<Win32Exception>(() => Process.Start(new ProcessStartInfo { UseShellExecute = false, FileName = "https://www.github.com/corefx" }));
+ Assert.Throws<Win32Exception>(() => Process.Start(new ProcessStartInfo { UseShellExecute = false, FileName = "https://www.github.com/corefx" }));
}
[Fact]
public void ProcessStart_TryOpenFolder_UseShellExecuteIsFalse_ThrowsWin32Exception()
{
- Win32Exception e = Assert.Throws<Win32Exception>(() => Process.Start(new ProcessStartInfo { UseShellExecute = false, FileName = Path.GetTempPath() }));
+ Assert.Throws<Win32Exception>(() => Process.Start(new ProcessStartInfo { UseShellExecute = false, FileName = Path.GetTempPath() }));
}
[Fact]
@@ -176,13 +176,12 @@ namespace System.Diagnostics.Tests
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.HasWindowsShell))]
[SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "not supported on UAP")]
[OuterLoop("Launches File Explorer")]
- public void ProcessStart_UseShellExecuteTrue_OpenMissingFile_Throws()
+ public void ProcessStart_UseShellExecute_OnWindows_OpenMissingFile_Throws()
{
string fileToOpen = Path.Combine(Environment.CurrentDirectory, "_no_such_file.TXT");
- Win32Exception e = Assert.Throws<Win32Exception>(() => Process.Start(new ProcessStartInfo { UseShellExecute = true, FileName = fileToOpen }));
+ Assert.Throws<Win32Exception>(() => Process.Start(new ProcessStartInfo { UseShellExecute = true, FileName = fileToOpen }));
}
- [PlatformSpecific(TestPlatforms.Windows)]
[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.HasWindowsShell))]
[InlineData(true)]
[InlineData(false)]
@@ -686,7 +685,7 @@ namespace System.Diagnostics.Tests
[Fact]
public void TestProcessStartTime()
{
- TimeSpan allowedWindow = TimeSpan.FromSeconds(1);
+ TimeSpan allowedWindow = TimeSpan.FromSeconds(3);
for (int i = 0; i < 2; i++)
{
@@ -717,6 +716,20 @@ namespace System.Diagnostics.Tests
}
[Fact]
+ [PlatformSpecific(~TestPlatforms.OSX)]
+ public void ProcessStartTime_Deterministic_Across_Instances()
+ {
+ CreateDefaultProcess();
+ for (int i = 0; i < 10; ++i)
+ {
+ using (var p = Process.GetProcessById(_process.Id))
+ {
+ Assert.Equal(_process.StartTime, p.StartTime);
+ }
+ }
+ }
+
+ [Fact]
public void ExitTime_GetNotStarted_ThrowsInvalidOperationException()
{
var process = new Process();
@@ -922,9 +935,11 @@ namespace System.Diagnostics.Tests
}
[Fact]
+ [ActiveIssue(26720, TargetFrameworkMonikers.Uap)]
public void GetProcesses_InvalidMachineName_ThrowsInvalidOperationException()
{
- Assert.Throws<InvalidOperationException>(() => Process.GetProcesses(Guid.NewGuid().ToString()));
+ Type exceptionType = PlatformDetection.IsWindows ? typeof(InvalidOperationException) : typeof(PlatformNotSupportedException);
+ Assert.Throws(exceptionType, () => Process.GetProcesses(Guid.NewGuid().ToString()));
}
[Fact]
@@ -1614,14 +1629,15 @@ namespace System.Diagnostics.Tests
string domain = "thisDomain";
SecureString password = AsSecureString("Value");
- Process p = Process.Start(currentProcessName, userName, password, domain); // This writes junk to the Console but with this overload, we can't prevent that.
- Assert.NotNull(p);
- Assert.Equal(currentProcessName, p.StartInfo.FileName);
- Assert.Equal(userName, p.StartInfo.UserName);
- Assert.Same(password, p.StartInfo.Password);
- Assert.Equal(domain, p.StartInfo.Domain);
-
- Assert.True(p.WaitForExit(WaitInMS));
+ using (Process p = Process.Start(currentProcessName, userName, password, domain)) // This writes junk to the Console but with this overload, we can't prevent that.
+ {
+ Assert.NotNull(p);
+ Assert.Equal(currentProcessName, p.StartInfo.FileName);
+ Assert.Equal(userName, p.StartInfo.UserName);
+ Assert.Same(password, p.StartInfo.Password);
+ Assert.Equal(domain, p.StartInfo.Domain);
+ Assert.True(p.WaitForExit(WaitInMS));
+ }
password.Dispose();
}
@@ -1635,15 +1651,16 @@ namespace System.Diagnostics.Tests
string domain = Environment.UserDomainName;
string arguments = "-xml testResults.xml";
SecureString password = AsSecureString("Value");
-
- Process p = Process.Start(currentProcessName, arguments, userName, password, domain);
- Assert.NotNull(p);
- Assert.Equal(currentProcessName, p.StartInfo.FileName);
- Assert.Equal(arguments, p.StartInfo.Arguments);
- Assert.Equal(userName, p.StartInfo.UserName);
- Assert.Same(password, p.StartInfo.Password);
- Assert.Equal(domain, p.StartInfo.Domain);
- p.Kill();
+ using (Process p = Process.Start(currentProcessName, arguments, userName, password, domain))
+ {
+ Assert.NotNull(p);
+ Assert.Equal(currentProcessName, p.StartInfo.FileName);
+ Assert.Equal(arguments, p.StartInfo.Arguments);
+ Assert.Equal(userName, p.StartInfo.UserName);
+ Assert.Same(password, p.StartInfo.Password);
+ Assert.Equal(domain, p.StartInfo.Domain);
+ p.Kill();
+ }
password.Dispose();
}
diff --git a/src/System.Diagnostics.Process/tests/ProcessTests.netcoreapp.cs b/src/System.Diagnostics.Process/tests/ProcessTests.netcoreapp.cs
index 9ef9cbdd4e..f0bbd00d17 100644
--- a/src/System.Diagnostics.Process/tests/ProcessTests.netcoreapp.cs
+++ b/src/System.Diagnostics.Process/tests/ProcessTests.netcoreapp.cs
@@ -2,11 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System;
-using System.Collections.Generic;
-using System.Linq;
using System.Text;
-using System.Threading.Tasks;
using Xunit;
namespace System.Diagnostics.Tests
@@ -40,5 +36,88 @@ namespace System.Diagnostics.Tests
Assert.Same(encoding, process.StandardInput.Encoding);
}
+
+ [Fact]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void StartProcessWithArgumentList()
+ {
+ ProcessStartInfo psi = new ProcessStartInfo(GetCurrentProcessName());
+ psi.ArgumentList.Add("arg1");
+ psi.ArgumentList.Add("arg2");
+
+ Process testProcess = CreateProcess();
+ testProcess.StartInfo = psi;
+
+ try
+ {
+ testProcess.Start();
+ Assert.Equal(string.Empty, testProcess.StartInfo.Arguments);
+ }
+ finally
+ {
+ if (!testProcess.HasExited)
+ testProcess.Kill();
+
+ Assert.True(testProcess.WaitForExit(WaitInMS));
+ }
+ }
+
+ [Fact]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void StartProcessWithSameArgumentList()
+ {
+ ProcessStartInfo psi = new ProcessStartInfo(GetCurrentProcessName());
+ psi.ArgumentList.Add("arg1");
+ psi.ArgumentList.Add("arg2");
+
+ Process testProcess = CreateProcess();
+ Process secondTestProcess = CreateProcess();
+ testProcess.StartInfo = psi;
+ try
+ {
+ testProcess.Start();
+ Assert.Equal(string.Empty, testProcess.StartInfo.Arguments);
+ secondTestProcess.StartInfo = psi;
+ secondTestProcess.Start();
+ Assert.Equal(string.Empty, secondTestProcess.StartInfo.Arguments);
+ }
+ finally
+ {
+ if (!testProcess.HasExited)
+ testProcess.Kill();
+
+ Assert.True(testProcess.WaitForExit(WaitInMS));
+
+ if (!secondTestProcess.HasExited)
+ secondTestProcess.Kill();
+
+ Assert.True(testProcess.WaitForExit(WaitInMS));
+ }
+ }
+
+ [Fact]
+ public void BothArgumentCtorAndArgumentListSet()
+ {
+ ProcessStartInfo psi = new ProcessStartInfo(GetCurrentProcessName(), "arg3");
+ psi.ArgumentList.Add("arg1");
+ psi.ArgumentList.Add("arg2");
+
+ Process testProcess = CreateProcess();
+ testProcess.StartInfo = psi;
+ Assert.Throws<InvalidOperationException>(() => testProcess.Start());
+ }
+
+ [Fact]
+ public void BothArgumentSetAndArgumentListSet()
+ {
+ ProcessStartInfo psi = new ProcessStartInfo(GetCurrentProcessName());
+ psi.Arguments = "arg3";
+ psi.ArgumentList.Add("arg1");
+ psi.ArgumentList.Add("arg2");
+
+ Process testProcess = CreateProcess();
+ testProcess.StartInfo = psi;
+ Assert.Throws<InvalidOperationException>(() => testProcess.Start());
+ }
}
}
diff --git a/src/System.Diagnostics.Process/tests/RemotelyInvokable.cs b/src/System.Diagnostics.Process/tests/RemotelyInvokable.cs
index 4d0ba8d3d5..0b0b93991a 100644
--- a/src/System.Diagnostics.Process/tests/RemotelyInvokable.cs
+++ b/src/System.Diagnostics.Process/tests/RemotelyInvokable.cs
@@ -35,9 +35,9 @@ namespace System.Diagnostics.Tests
return SuccessExitCode;
}
- public static int LongWait()
+ public static int Sleep(string duration)
{
- Thread.Sleep(WaitInMS);
+ Thread.Sleep(int.Parse(duration));
return SuccessExitCode;
}
diff --git a/src/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csproj b/src/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csproj
index fd381bccd9..c427fd0ddc 100644
--- a/src/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csproj
+++ b/src/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csproj
@@ -6,6 +6,10 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefineConstants Condition="'$(TargetsWindows)' == 'true'">$(DefineConstants);TargetsWindows</DefineConstants>
</PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Unix-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Windows_NT-Debug|AnyCPU'" />
@@ -45,6 +49,7 @@
<Compile Include="XunitAssemblyAttributes.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp' or '$(TargetGroup)' == 'uap'">
+ <Compile Include="ProcessStartInfoTests.netcoreapp.cs" />
<Compile Include="ProcessStreamReadTests.netcoreapp.cs" />
<Compile Include="ProcessTests.netcoreapp.cs" />
</ItemGroup>
@@ -54,5 +59,17 @@
<Name>RemoteExecutorConsoleApp</Name>
</ProjectReference>
</ItemGroup>
+ <!-- WINDOWS: Shared CoreCLR and .NET Native -->
+ <ItemGroup Condition="'$(TargetsWindows)' == 'true'">
+ <Compile Include="..\..\Common\src\System\PasteArguments.Windows.cs">
+ <Link>Common\System\PasteArguments.Windows.cs</Link>
+ </Compile>
+ </ItemGroup>
+ <!-- UNIX -->
+ <ItemGroup Condition=" '$(TargetsUnix)' == 'true' ">
+ <Compile Include="..\..\Common\src\System\PasteArguments.Unix.cs">
+ <Link>Common\System\PasteArguments.Unix.cs</Link>
+ </Compile>
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.Diagnostics.StackTrace/tests/StackTraceTests.cs b/src/System.Diagnostics.StackTrace/tests/StackTraceTests.cs
index fcd19de108..d703b1c79b 100644
--- a/src/System.Diagnostics.StackTrace/tests/StackTraceTests.cs
+++ b/src/System.Diagnostics.StackTrace/tests/StackTraceTests.cs
@@ -274,20 +274,20 @@ namespace System.Diagnostics.Tests
{
// Debug mode and Release mode give different results.
#if DEBUG
- yield return new object[] { new StackTrace(InvokeException()), " at System.Diagnostics.Tests.StackTraceTests.ThrowException()" };
+ yield return new object[] { new StackTrace(InvokeException()), "System.Diagnostics.Tests.StackTraceTests.ThrowException()" };
yield return new object[] { new StackTrace(new Exception()), "" };
- yield return new object[] { NoParameters(), " at System.Diagnostics.Tests.StackTraceTests.NoParameters()" };
- yield return new object[] { OneParameter(1), " at System.Diagnostics.Tests.StackTraceTests.OneParameter(Int32 x)" };
- yield return new object[] { TwoParameters(1, null), " at System.Diagnostics.Tests.StackTraceTests.TwoParameters(Int32 x, String y)" };
- yield return new object[] { Generic<int>(), " at System.Diagnostics.Tests.StackTraceTests.Generic[T]()" };
- yield return new object[] { Generic<int, string>(), " at System.Diagnostics.Tests.StackTraceTests.Generic[T,U]()" };
- yield return new object[] { new ClassWithConstructor().StackTrace, " at System.Diagnostics.Tests.StackTraceTests.ClassWithConstructor..ctor()" };
+ yield return new object[] { NoParameters(), "System.Diagnostics.Tests.StackTraceTests.NoParameters()" };
+ yield return new object[] { OneParameter(1), "System.Diagnostics.Tests.StackTraceTests.OneParameter(Int32 x)" };
+ yield return new object[] { TwoParameters(1, null), "System.Diagnostics.Tests.StackTraceTests.TwoParameters(Int32 x, String y)" };
+ yield return new object[] { Generic<int>(), "System.Diagnostics.Tests.StackTraceTests.Generic[T]()" };
+ yield return new object[] { Generic<int, string>(), "System.Diagnostics.Tests.StackTraceTests.Generic[T,U]()" };
+ yield return new object[] { new ClassWithConstructor().StackTrace, "System.Diagnostics.Tests.StackTraceTests.ClassWithConstructor..ctor()" };
// Methods belonging to the System.Diagnostics namespace are ignored.
- yield return new object[] { InvokeIgnoredMethod(), " at System.Diagnostics.Tests.StackTraceTests.InvokeIgnoredMethod()" };
+ yield return new object[] { InvokeIgnoredMethod(), "System.Diagnostics.Tests.StackTraceTests.InvokeIgnoredMethod()" };
#endif
- yield return new object[] { InvokeIgnoredMethodWithException(), " at System.Diagnostics.Ignored.MethodWithException()" };
+ yield return new object[] { InvokeIgnoredMethodWithException(), "System.Diagnostics.Ignored.MethodWithException()" };
}
[Fact]
@@ -309,7 +309,7 @@ namespace System.Diagnostics.Tests
else
{
string toString = stackTrace.ToString();
- Assert.StartsWith(expectedToString, toString);
+ Assert.Contains(expectedToString, toString);
Assert.EndsWith(Environment.NewLine, toString);
string[] frames = toString.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
diff --git a/src/System.Diagnostics.TextWriterTraceListener/src/FxCopBaseline.cs b/src/System.Diagnostics.TextWriterTraceListener/src/FxCopBaseline.cs
index 9be0eb534a..d7c7e4f0a4 100644
--- a/src/System.Diagnostics.TextWriterTraceListener/src/FxCopBaseline.cs
+++ b/src/System.Diagnostics.TextWriterTraceListener/src/FxCopBaseline.cs
@@ -1,3 +1,7 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.Diagnostics.DelimitedListTraceListener.#set_Delimiter(System.String)")]
diff --git a/src/System.Diagnostics.TraceSource/src/FxCopBaseline.cs b/src/System.Diagnostics.TraceSource/src/FxCopBaseline.cs
index 8a2b79b4a3..89cdfb87de 100644
--- a/src/System.Diagnostics.TraceSource/src/FxCopBaseline.cs
+++ b/src/System.Diagnostics.TraceSource/src/FxCopBaseline.cs
@@ -1,3 +1,7 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "System.Diagnostics.TraceInternal.#Flush()")]
diff --git a/src/System.Diagnostics.TraceSource/tests/TraceClassTests.cs b/src/System.Diagnostics.TraceSource/tests/TraceClassTests.cs
index c5d6b9b926..d6b2787ee0 100644
--- a/src/System.Diagnostics.TraceSource/tests/TraceClassTests.cs
+++ b/src/System.Diagnostics.TraceSource/tests/TraceClassTests.cs
@@ -354,7 +354,16 @@ namespace System.Diagnostics.TraceSourceTests
[Fact]
public void TraceTest02()
{
+ String newLine = Environment.NewLine;
var textTL = new TestTextTraceListener();
+ Trace.Listeners.Clear();
+ Trace.Listeners.Add(textTL);
+ Trace.IndentLevel = 0;
+ Trace.Fail("");
+ textTL.Flush();
+ var fail = textTL.Output.TrimEnd(newLine.ToCharArray());
+
+ textTL = new TestTextTraceListener();
// We have to clear the listeners list on Trace since there is a trace listener by default with AssertUiEnabled = true in Desktop and that will pop up an assert window with Trace.Fail
Trace.Listeners.Clear();
Trace.Listeners.Add(textTL);
@@ -377,8 +386,8 @@ namespace System.Diagnostics.TraceSourceTests
Trace.Unindent();
Trace.WriteLine("Message end.");
textTL.Flush();
- String newLine = Environment.NewLine;
- var expected = "Message start." + newLine + " This message should be indented.This should not be indented." + newLine + " Fail: This failure is reported with a detailed message" + newLine + " Fail: " + newLine + " Fail: This assert is reported" + newLine + "Message end." + newLine;
+ newLine = Environment.NewLine;
+ var expected = "Message start." + newLine + " This message should be indented.This should not be indented." + newLine + " " + fail + "This failure is reported with a detailed message" + newLine + " " + fail + newLine + " " + fail + "This assert is reported" + newLine + "Message end." + newLine;
Assert.Equal(expected, textTL.Output);
}
}
diff --git a/src/System.Diagnostics.TraceSource/tests/TraceEventCacheClassTests.cs b/src/System.Diagnostics.TraceSource/tests/TraceEventCacheClassTests.cs
index 2ff2864e5e..832ba7208c 100644
--- a/src/System.Diagnostics.TraceSource/tests/TraceEventCacheClassTests.cs
+++ b/src/System.Diagnostics.TraceSource/tests/TraceEventCacheClassTests.cs
@@ -60,7 +60,7 @@ namespace System.Diagnostics.TraceSourceTests
public void CallstackTest_ContainsExpectedFrames()
{
var cache = new TraceEventCache();
- Assert.Contains("at System.Environment.get_StackTrace()", cache.Callstack);
+ Assert.Contains("System.Environment.get_StackTrace()", cache.Callstack);
}
[Fact]
diff --git a/src/System.Diagnostics.Tracing/System.Diagnostics.Tracing.sln b/src/System.Diagnostics.Tracing/System.Diagnostics.Tracing.sln
index f8890b0fe9..5c15363217 100644
--- a/src/System.Diagnostics.Tracing/System.Diagnostics.Tracing.sln
+++ b/src/System.Diagnostics.Tracing/System.Diagnostics.Tracing.sln
@@ -26,10 +26,10 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {7E0E1B11-FF70-461E-99F7-C0AF252C0C60}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
- {7E0E1B11-FF70-461E-99F7-C0AF252C0C60}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
- {7E0E1B11-FF70-461E-99F7-C0AF252C0C60}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
- {7E0E1B11-FF70-461E-99F7-C0AF252C0C60}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
+ {7E0E1B11-FF70-461E-99F7-C0AF252C0C60}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU
+ {7E0E1B11-FF70-461E-99F7-C0AF252C0C60}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
+ {7E0E1B11-FF70-461E-99F7-C0AF252C0C60}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
+ {7E0E1B11-FF70-461E-99F7-C0AF252C0C60}.Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU
{EB880FDC-326D-42B3-A3FD-0CD3BA29A7F4}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU
{EB880FDC-326D-42B3-A3FD-0CD3BA29A7F4}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
{EB880FDC-326D-42B3-A3FD-0CD3BA29A7F4}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
diff --git a/src/System.Diagnostics.Tracing/src/System/Diagnostics/Tracing/EventCounter.cs b/src/System.Diagnostics.Tracing/src/System/Diagnostics/Tracing/EventCounter.cs
index 88ab685723..fdc05c5c69 100644
--- a/src/System.Diagnostics.Tracing/src/System/Diagnostics/Tracing/EventCounter.cs
+++ b/src/System.Diagnostics.Tracing/src/System/Diagnostics/Tracing/EventCounter.cs
@@ -407,7 +407,24 @@ namespace System.Diagnostics.Tracing
_pollingIntervalInMilliseconds = (int)(pollingIntervalInSeconds * 1000);
DisposeTimer();
_timeStampSinceCollectionStarted = DateTime.UtcNow;
- _pollingTimer = new Timer(OnTimer, null, _pollingIntervalInMilliseconds, _pollingIntervalInMilliseconds);
+ // Don't capture the current ExecutionContext and its AsyncLocals onto the timer causing them to live forever
+ bool restoreFlow = false;
+ try
+ {
+ if (!ExecutionContext.IsFlowSuppressed())
+ {
+ ExecutionContext.SuppressFlow();
+ restoreFlow = true;
+ }
+
+ _pollingTimer = new Timer(s => ((EventCounterGroup)s).OnTimer(null), this, _pollingIntervalInMilliseconds, _pollingIntervalInMilliseconds);
+ }
+ finally
+ {
+ // Restore the current ExecutionContext
+ if (restoreFlow)
+ ExecutionContext.RestoreFlow();
+ }
}
// Always fire the timer event (so you see everything up to this time).
OnTimer(null);
diff --git a/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/FuzzyTests.cs b/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/FuzzyTests.cs
index bb586b47b4..d149194d01 100644
--- a/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/FuzzyTests.cs
+++ b/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/FuzzyTests.cs
@@ -13,7 +13,7 @@ using Microsoft.Diagnostics.Tracing;
using System.Diagnostics.Tracing;
#endif
using Xunit;
-#if USE_ETW // TODO: Enable when TraceEvent is available on CoreCLR. GitHub issue #4864.
+#if USE_ETW
using Microsoft.Diagnostics.Tracing.Session;
#endif
@@ -2747,11 +2747,13 @@ namespace BasicEventSourceTests
Assert.Equal("FWKFKXHDFY", evt.EventName);
}));
- // Run tests for ETW
-#if USE_ETW // TODO: Enable when TraceEvent is available on CoreCLR. GitHub issue #4864.
- using (var listener = new EtwListener())
+#if USE_ETW
+ if(TestUtilities.IsProcessElevated)
{
- EventTestHarness.RunTests(tests, listener, logger);
+ using (var listener = new EtwListener())
+ {
+ EventTestHarness.RunTests(tests, listener, logger);
+ }
}
#endif // USE_ETW
using (var listener = new EventListenerListener())
diff --git a/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/Harness/EventTestHarness.cs b/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/Harness/EventTestHarness.cs
index fc1b1de920..70af9720f3 100644
--- a/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/Harness/EventTestHarness.cs
+++ b/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/Harness/EventTestHarness.cs
@@ -141,7 +141,7 @@ namespace BasicEventSourceTests
}
catch (Exception e)
{
- if (e is EventSourceException)
+ if ((e is EventSourceException) && (e.InnerException != null))
e = e.InnerException;
LogWriteLine("Exception thrown: {0}", e.Message);
diff --git a/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/Harness/Listeners.cs b/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/Harness/Listeners.cs
index e56fc8b2b2..061dc25f00 100644
--- a/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/Harness/Listeners.cs
+++ b/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/Harness/Listeners.cs
@@ -2,7 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-#if USE_ETW // TODO: Enable when TraceEvent is available on CoreCLR. GitHub issue #4864.
+#if USE_ETW
+using Microsoft.Diagnostics.Tracing;
using Microsoft.Diagnostics.Tracing.Session;
#endif
using System;
@@ -136,14 +137,14 @@ namespace BasicEventSourceTests
{
if (i != 0)
sb.Append(',');
- sb.Append(PayloadString(i, null));
+ sb.Append(PayloadString(i, PayloadNames[i]));
}
sb.Append(')');
return sb.ToString();
}
}
-#if USE_ETW // TODO: Enable when TraceEvent is available on CoreCLR. GitHub issue #4864.
+#if USE_ETW
/**************************************************************************/
/* Concrete implementation of the Listener abstraction */
@@ -165,7 +166,7 @@ namespace BasicEventSourceTests
// Today you have to be Admin to turn on ETW events (anyone can write ETW events).
if (TraceEventSession.IsElevated() != true)
{
- throw new ApplicationException("Need to be elevated to run. ");
+ throw new Exception("Need to be elevated to run. ");
}
if (dataFileName == null)
@@ -214,6 +215,12 @@ namespace BasicEventSourceTests
public override void Dispose()
{
+ if(_disposed)
+ {
+ return;
+ }
+
+ _disposed = true;
_session.Flush();
Thread.Sleep(1010); // Let it drain.
_session.Dispose(); // This also will kill the real time thread
@@ -225,7 +232,6 @@ namespace BasicEventSourceTests
Debug.WriteLine("Processing data file " + Path.GetFullPath(_dataFileName));
// Parse all the events as best we can, and also send unhandled events there as well.
- traceEventSource.Registered.All += OnEventHelper;
traceEventSource.Dynamic.All += OnEventHelper;
traceEventSource.UnhandledEvents += OnEventHelper;
// Process all the events in the file.
@@ -238,12 +244,23 @@ namespace BasicEventSourceTests
#region private
private void OnEventHelper(TraceEvent data)
{
+ // Ignore EventTrace events.
+ if (data.ProviderGuid == EventTraceProviderID)
+ return;
+
+ // Ignore kernel events.
+ if (data.ProviderGuid == KernelProviderID)
+ return;
+
// Ignore manifest events.
if ((int)data.ID == 0xFFFE)
return;
this.OnEvent(new EtwEvent(data));
}
+ private static readonly Guid EventTraceProviderID = new Guid("9e814aad-3204-11d2-9a82-006008a86939");
+ private static readonly Guid KernelProviderID = new Guid("9e814aad-3204-11d2-9a82-006008a86939");
+
/// <summary>
/// EtwEvent implements the 'Event' abstraction for ETW events (it has a TraceEvent in it)
/// </summary>
@@ -273,6 +290,7 @@ namespace BasicEventSourceTests
#endregion
}
+ private bool _disposed;
private string _dataFileName;
private volatile TraceEventSession _session;
#endregion
@@ -334,6 +352,12 @@ namespace BasicEventSourceTests
public override void Dispose()
{
+ if (_disposed)
+ {
+ return;
+ }
+
+ _disposed = true;
EventTestHarness.LogWriteLine("Disposing Listener");
_listener.Dispose();
}
@@ -438,5 +462,7 @@ namespace BasicEventSourceTests
return _data.Payload[propertyIndex];
}
}
+
+ private bool _disposed;
}
}
diff --git a/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/LoudListener.cs b/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/LoudListener.cs
index 7f26da5868..88801bccda 100644
--- a/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/LoudListener.cs
+++ b/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/LoudListener.cs
@@ -30,5 +30,10 @@ namespace BasicEventSourceTests
Debug.Write(string.Format(" (activity {0}{1}) ", eventData.ActivityId, eventData.RelatedActivityId != null ? "->" + eventData.RelatedActivityId : ""));
Debug.WriteLine(string.Format(" ({0}).", eventData.Payload != null ? string.Join(", ", eventData.Payload) : ""));
}
+
+ public static EventWrittenEventArgs LastEvent
+ {
+ get { return t_lastEvent; }
+ }
}
}
diff --git a/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestEventCounter.cs b/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestEventCounter.cs
index cbd86c5e84..f8396e2c69 100644
--- a/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestEventCounter.cs
+++ b/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestEventCounter.cs
@@ -8,7 +8,7 @@ using Microsoft.Diagnostics.Tracing;
#else
using System.Diagnostics.Tracing;
#endif
-#if USE_ETW // TODO: Enable when TraceEvent is available on CoreCLR. GitHub issue https://github.com/dotnet/corefx/issues/4864
+#if USE_ETW
using Microsoft.Diagnostics.Tracing.Session;
#endif
using Xunit;
@@ -25,6 +25,12 @@ namespace BasicEventSourceTests
{
public class TestEventCounter
{
+#if USE_ETW
+ // Specifies whether the process is elevated or not.
+ private static readonly Lazy<bool> s_isElevated = new Lazy<bool>(() => AdminHelpers.IsProcessElevated());
+ private static bool IsProcessElevated => s_isElevated.Value;
+#endif // USE_ETW
+
private sealed class MyEventSource : EventSource
{
private EventCounter _requestCounter;
@@ -52,6 +58,7 @@ namespace BasicEventSourceTests
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, reason: "https://github.com/dotnet/corefx/issues/23661")]
#endif
[ActiveIssue("https://github.com/dotnet/corefx/issues/22791", TargetFrameworkMonikers.UapAot)]
+ [ActiveIssue("https://github.com/dotnet/corefx/issues/25029")]
public void Test_Write_Metric_EventListener()
{
using (var listener = new EventListenerListener())
@@ -61,7 +68,8 @@ namespace BasicEventSourceTests
}
#if USE_ETW
- [Fact]
+ [ConditionalFact(nameof(IsProcessElevated))]
+ [ActiveIssue("https://github.com/dotnet/corefx/issues/27106")]
public void Test_Write_Metric_ETW()
{
diff --git a/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestShutdown.cs b/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestShutdown.cs
index b88408d1cd..d02791f070 100644
--- a/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestShutdown.cs
+++ b/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestShutdown.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@@ -13,7 +14,8 @@ using Microsoft.Diagnostics.Tracing;
using System.Diagnostics.Tracing;
#endif
using Xunit;
-#if USE_ETW // TODO: Enable when TraceEvent is available on CoreCLR. GitHub issue #4864.
+#if USE_ETW
+using Microsoft.Diagnostics.Tracing;
using Microsoft.Diagnostics.Tracing.Session;
#endif
using System.IO;
@@ -23,7 +25,9 @@ namespace BasicEventSourceTests
{
public class TestShutdown
{
-#if USE_ETW // TODO: Enable when TraceEvent is available on CoreCLR. GitHub issue #4864.
+
+ // TODO: Depends on desktop APIs (AppDomainSetup and Evidence).
+#if USE_ETW && FALSE
/// <summary>
/// Test for manifest event being logged during AD/Process shutdown during EventSource Dispose(bool) method.
/// </summary>
@@ -89,7 +93,6 @@ namespace BasicEventSourceTests
};
// Parse all the events as best we can, and also send unhandled events there as well.
- traceEventSource.Registered.All += onEvent;
traceEventSource.Dynamic.All += onEvent;
traceEventSource.UnhandledEvent += onEvent;
traceEventSource.Process();
diff --git a/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestUtilities.cs b/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestUtilities.cs
index 42970594d2..8ef33bc161 100644
--- a/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestUtilities.cs
+++ b/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestUtilities.cs
@@ -15,6 +15,10 @@ namespace BasicEventSourceTests
{
internal class TestUtilities
{
+ // Specifies whether the process is elevated or not.
+ private static readonly Lazy<bool> s_isElevated = new Lazy<bool>(() => AdminHelpers.IsProcessElevated());
+ internal static bool IsProcessElevated => s_isElevated.Value;
+
/// <summary>
/// Confirms that there are no EventSources running.
/// </summary>
diff --git a/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsManifestNegative.cs b/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsManifestNegative.cs
index 922168d8b8..a23f456437 100644
--- a/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsManifestNegative.cs
+++ b/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsManifestNegative.cs
@@ -104,9 +104,9 @@ namespace BasicEventSourceTests
() => EventSource.GenerateManifest(typeof(Sdt.TooManyChannelsEventSource), string.Empty));
#endif
-#if USE_ETW // TODO: Enable when TraceEvent is available on CoreCLR. GitHub issue #4864.
- e = AssertExtensions.Throws<ArgumentException>(GetResourceString("EventSource_EventWithAdminChannelMustHaveMessage", "WriteInteger", "Admin"),
- () => EventSource.GenerateManifest(typeof(Sdt.EventWithAdminChannelNoMessageEventSource), string.Empty, strictOptions));
+#if USE_ETW
+ e = AssertExtensions.Throws<ArgumentException>(null, () => EventSource.GenerateManifest(typeof(Sdt.EventWithAdminChannelNoMessageEventSource), string.Empty, strictOptions));
+ AsserExceptionStringsEqual(() => GetResourceString("EventSource_EventWithAdminChannelMustHaveMessage", "WriteInteger", "Admin"), e);
#endif // USE_ETW
e = AssertExtensions.Throws<ArgumentException>(null, () => EventSource.GenerateManifest(typeof(Sdt.ReservedOpcodeEventSource), string.Empty, strictOptions));
diff --git a/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsUserErrors.cs b/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsUserErrors.cs
index 046b5e4935..5070cf7900 100644
--- a/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsUserErrors.cs
+++ b/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsUserErrors.cs
@@ -74,35 +74,39 @@ namespace BasicEventSourceTests
[SkipOnTargetFramework(TargetFrameworkMonikers.UapAot, "Depends on inspecting IL at runtime.")]
public void Test_BadEventSource_MismatchedIds()
{
-#if USE_ETW // TODO: Enable when TraceEvent is available on CoreCLR. GitHub issue #4864.
+#if USE_ETW
// We expect only one session to be on when running the test but if a ETW session was left
- // hanging, it will confuse the EventListener tests.
- EtwListener.EnsureStopped();
+ // hanging, it will confuse the EventListener tests.
+ if(TestUtilities.IsProcessElevated)
+ {
+ EtwListener.EnsureStopped();
+ }
#endif // USE_ETW
TestUtilities.CheckNoEventSourcesRunning("Start");
var onStartups = new bool[] { false, true };
-
- var listenerGenerators = new Func<Listener>[]
- {
- () => new EventListenerListener(),
-#if USE_ETW // TODO: Enable when TraceEvent is available on CoreCLR. GitHub issue #4864.
- () => new EtwListener()
+
+ var listenerGenerators = new List<Func<Listener>>();
+ listenerGenerators.Add(() => new EventListenerListener());
+#if USE_ETW
+ if(TestUtilities.IsProcessElevated)
+ {
+ listenerGenerators.Add(() => new EtwListener());
+ }
#endif // USE_ETW
- };
- var settings = new EventSourceSettings[] { EventSourceSettings.Default, EventSourceSettings.EtwSelfDescribingEventFormat };
+ var settings = new EventSourceSettings[] { EventSourceSettings.Default, EventSourceSettings.EtwSelfDescribingEventFormat };
- // For every interesting combination, run the test and see that we get a nice failure message.
- foreach (bool onStartup in onStartups)
+ // For every interesting combination, run the test and see that we get a nice failure message.
+ foreach (bool onStartup in onStartups)
+ {
+ foreach (Func<Listener> listenerGenerator in listenerGenerators)
+ {
+ foreach (EventSourceSettings setting in settings)
{
- foreach (Func<Listener> listenerGenerator in listenerGenerators)
- {
- foreach (EventSourceSettings setting in settings)
- {
- Test_Bad_EventSource_Startup(onStartup, listenerGenerator(), setting);
- }
- }
+ Test_Bad_EventSource_Startup(onStartup, listenerGenerator(), setting);
+ }
+ }
}
TestUtilities.CheckNoEventSourcesRunning("Stop");
diff --git a/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWrite.cs b/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWrite.cs
index 5743bbe8d8..e7c037bed7 100644
--- a/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWrite.cs
+++ b/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWrite.cs
@@ -13,7 +13,7 @@ using Microsoft.Diagnostics.Tracing;
using System.Diagnostics.Tracing;
#endif
using Xunit;
-#if USE_ETW // TODO: Enable when TraceEvent is available on CoreCLR. GitHub issue #4864.
+#if USE_ETW
using Microsoft.Diagnostics.Tracing.Session;
#endif
using System.Diagnostics;
@@ -32,6 +32,12 @@ namespace BasicEventSourceTests
public class TestsWrite
{
+#if USE_ETW
+ // Specifies whether the process is elevated or not.
+ private static readonly Lazy<bool> s_isElevated = new Lazy<bool>(() => AdminHelpers.IsProcessElevated());
+ private static bool IsProcessElevated => s_isElevated.Value;
+#endif // USE_ETW
+
[EventData]
private struct PartB_UserInfo
{
@@ -63,12 +69,12 @@ namespace BasicEventSourceTests
Test_Write_T(new EventListenerListener(true));
}
-#if USE_ETW // TODO: Enable when TraceEvent is available on CoreCLR. GitHub issue #4864.
+#if USE_ETW
/// <summary>
/// Tests the EventSource.Write[T] method (can only use the self-describing mechanism).
/// Tests the ETW code path
/// </summary>
- [Fact]
+ [ConditionalFact(nameof(IsProcessElevated))]
public void Test_Write_T_ETW()
{
using (var listener = new EtwListener())
@@ -380,6 +386,27 @@ namespace BasicEventSourceTests
Assert.Equal(evt.PayloadValue(1, "b"), "");
}));
+#if USE_ETW
+ // This test only applies to ETW and will fail on EventListeners due to different behavior
+ // for strings with embedded NULL characters.
+ if (listener is EtwListener)
+ {
+ tests.Add(new SubTest("Write/Basic/WriteOfTWithEmbeddedNullString",
+ delegate ()
+ {
+ string nullString = null;
+ logger.Write("EmbeddedNullStringEvent", new { a = "Hello" + '\0' + "World!", b = nullString });
+ },
+ delegate (Event evt)
+ {
+ Assert.Equal(logger.Name, evt.ProviderName);
+ Assert.Equal("EmbeddedNullStringEvent", evt.EventName);
+ Assert.Equal(evt.PayloadValue(0, "a"), "Hello");
+ Assert.Equal(evt.PayloadValue(1, "b"), "");
+ }));
+ }
+#endif // USE_ETW
+
Guid activityId = new Guid("00000000-0000-0000-0000-000000000001");
Guid relActivityId = new Guid("00000000-0000-0000-0000-000000000002");
tests.Add(new SubTest("Write/Basic/WriteOfTWithOptios",
@@ -414,21 +441,25 @@ namespace BasicEventSourceTests
/// </summary>
[Fact]
[ActiveIssue("dotnet/corefx #18806", TargetFrameworkMonikers.NetFramework)]
+ [ActiveIssue("https://github.com/dotnet/corefx/issues/27106")]
public void Test_Write_T_In_Manifest_Serialization()
{
using (var eventListener = new EventListenerListener())
{
-#if USE_ETW // TODO: Enable when TraceEvent is available on CoreCLR. GitHub issue #4864.
- using (var etwListener = new EtwListener())
+#if USE_ETW
+ EtwListener etwListener = null;
#endif
+ try
{
- var listenerGenerators = new Func<Listener>[]
+ var listenerGenerators = new List<Func<Listener>>();
+ listenerGenerators.Add(() => eventListener);
+#if USE_ETW
+ if(IsProcessElevated)
{
- () => eventListener,
-#if USE_ETW // TODO: Enable when TraceEvent is available on CoreCLR. GitHub issue #4864.
- () => etwListener
+ etwListener = new EtwListener();
+ listenerGenerators.Add(() => etwListener);
+ }
#endif // USE_ETW
- };
foreach (Func<Listener> listenerGenerator in listenerGenerators)
{
@@ -453,6 +484,15 @@ namespace BasicEventSourceTests
Assert.Equal("hi", (string)_event.PayloadValue(1, "arg2"));
}
}
+ finally
+ {
+#if USE_ETW
+ if(etwListener != null)
+ {
+ etwListener.Dispose();
+ }
+#endif // USE_ETW
+ }
}
}
diff --git a/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWriteEvent.cs b/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWriteEvent.cs
index 080f6d7242..173fa3eb9a 100644
--- a/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWriteEvent.cs
+++ b/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWriteEvent.cs
@@ -24,12 +24,16 @@ namespace BasicEventSourceTests
{
public class TestsWriteEvent
{
-#if USE_ETW // TODO: Enable when TraceEvent is available on CoreCLR. GitHub issue #4864.
+#if USE_ETW
+ // Specifies whether the process is elevated or not.
+ private static readonly Lazy<bool> s_isElevated = new Lazy<bool>(() => AdminHelpers.IsProcessElevated());
+ private static bool IsProcessElevated => s_isElevated.Value;
+
/// <summary>
/// Tests WriteEvent using the manifest based mechanism.
/// Tests the ETW path.
/// </summary>
- [Fact]
+ [ConditionalFact(nameof(IsProcessElevated))]
public void Test_WriteEvent_Manifest_ETW()
{
using (var listener = new EtwListener())
@@ -62,12 +66,12 @@ namespace BasicEventSourceTests
{
Test_WriteEvent(new EventListenerListener(true), false);
}
-#if USE_ETW // TODO: Enable when TraceEvent is available on CoreCLR. GitHub issue #4864.
+#if USE_ETW
/// <summary>
/// Tests WriteEvent using the self-describing mechanism.
/// Tests both the ETW and TraceListener paths.
/// </summary>
- [Fact]
+ [ConditionalFact(nameof(IsProcessElevated))]
public void Test_WriteEvent_SelfDescribing_ETW()
{
using (var listener = new EtwListener())
@@ -156,23 +160,26 @@ namespace BasicEventSourceTests
Assert.Equal(evt.PayloadValue(0, "arg1"), "one");
Assert.Equal(evt.PayloadValue(1, "arg2"), "two");
}));
-#if USE_ETW // TODO: Enable when TraceEvent is available on CoreCLR. GitHub issue #4864.
+#if USE_ETW
/*************************************************************************/
- tests.Add(new SubTest("Write/Basic/EventWithManyTypeArgs",
- delegate ()
- {
- logger.EventWithManyTypeArgs("Hello", 1, 2, 3, 'a', 4, 5, 6, 7,
- (float)10.0, (double)11.0, logger.Guid);
- },
- delegate (Event evt)
- {
- Assert.Equal(logger.Name, evt.ProviderName);
- Assert.Equal("EventWithManyTypeArgs", evt.EventName);
- Assert.Equal("Hello", evt.PayloadValue(0, "msg"));
- Assert.Equal((float)10.0, evt.PayloadValue(9, "f"));
- Assert.Equal((double)11.0, evt.PayloadValue(10, "d"));
- Assert.Equal(logger.Guid, evt.PayloadValue(11, "guid"));
- }));
+ if(IsProcessElevated)
+ {
+ tests.Add(new SubTest("Write/Basic/EventWithManyTypeArgs",
+ delegate ()
+ {
+ logger.EventWithManyTypeArgs("Hello", 1, 2, 3, 'a', 4, 5, 6, 7,
+ (float)10.0, (double)11.0, logger.Guid);
+ },
+ delegate (Event evt)
+ {
+ Assert.Equal(logger.Name, evt.ProviderName);
+ Assert.Equal("EventWithManyTypeArgs", evt.EventName);
+ Assert.Equal("Hello", evt.PayloadValue(0, "msg"));
+ Assert.Equal((float)10.0, evt.PayloadValue(9, "f"));
+ Assert.Equal((double)11.0, evt.PayloadValue(10, "d"));
+ Assert.Equal(logger.Guid, evt.PayloadValue(11, "guid"));
+ }));
+ }
#endif // USE_ETW
/*************************************************************************/
tests.Add(new SubTest("Write/Basic/EventWith7Strings",
@@ -200,29 +207,32 @@ namespace BasicEventSourceTests
Assert.Equal("s0", (string)evt.PayloadValue(0, "s0"));
Assert.Equal("s8", (string)evt.PayloadValue(8, "s8"));
}));
-#if USE_ETW // TODO: Enable when TraceEvent is available on CoreCLR. GitHub issue #4864.
+#if USE_ETW
/*************************************************************************/
- tests.Add(new SubTest("Write/Activity/EventWithXferWeirdArgs",
- delegate ()
- {
- var actid = Guid.NewGuid();
- logger.EventWithXferWeirdArgs(actid,
- (IntPtr)128,
- true,
- SdtEventSources.MyLongEnum.LongVal1);
- },
- delegate (Event evt)
- {
- Assert.Equal(logger.Name, evt.ProviderName);
+ if(IsProcessElevated)
+ {
+ tests.Add(new SubTest("Write/Activity/EventWithXferWeirdArgs",
+ delegate ()
+ {
+ var actid = Guid.NewGuid();
+ logger.EventWithXferWeirdArgs(actid,
+ (IntPtr)128,
+ true,
+ SdtEventSources.MyLongEnum.LongVal1);
+ },
+ delegate (Event evt)
+ {
+ Assert.Equal(logger.Name, evt.ProviderName);
- // We log EventWithXferWeirdArgs in one case and
- // WorkWeirdArgs/Send in the other
- Assert.True(evt.EventName.Contains("WeirdArgs"));
+ // We log EventWithXferWeirdArgs in one case and
+ // WorkWeirdArgs/Send in the other
+ Assert.True(evt.EventName.Contains("WeirdArgs"));
- Assert.Equal("128", evt.PayloadValue(0, "iptr").ToString());
- Assert.Equal(true, (bool)evt.PayloadValue(1, "b"));
- Assert.Equal((long)SdtEventSources.MyLongEnum.LongVal1, (long)evt.PayloadValue(2, "le"));
- }));
+ Assert.Equal("128", evt.PayloadValue(0, "iptr").ToString());
+ Assert.Equal(true, (bool)evt.PayloadValue(1, "b"));
+ Assert.Equal((long)SdtEventSources.MyLongEnum.LongVal1, ((IConvertible)evt.PayloadValue(2, "le")).ToInt64(null));
+ }));
+ }
#endif // USE_ETW
/*************************************************************************/
/*************************** ENUM TESTING *******************************/
@@ -239,7 +249,7 @@ namespace BasicEventSourceTests
Assert.Equal(logger.Name, evt.ProviderName);
Assert.Equal("EventEnum", evt.EventName);
- Assert.Equal(1, (int)evt.PayloadValue(0, "x"));
+ Assert.Equal(1, ((IConvertible)evt.PayloadValue(0, "x")).ToInt32(null));
if (evt.IsEtw && !useSelfDescribingEvents)
Assert.Equal("Blue", evt.PayloadString(0, "x"));
}));
@@ -254,7 +264,7 @@ namespace BasicEventSourceTests
Assert.Equal(logger.Name, evt.ProviderName);
Assert.Equal("EventEnum1", evt.EventName);
- Assert.Equal(1, (int)evt.PayloadValue(0, "x"));
+ Assert.Equal(1, ((IConvertible)evt.PayloadValue(0, "x")).ToInt32(null));
if (evt.IsEtw && !useSelfDescribingEvents)
Assert.Equal("Blue", evt.PayloadString(0, "x"));
}));
@@ -363,7 +373,12 @@ namespace BasicEventSourceTests
Assert.Equal("", evt.PayloadValue(2, null));
}));
- if (useSelfDescribingEvents)
+ // Self-describing ETW does not support NULL arguments.
+ if (useSelfDescribingEvents
+#if USE_ETW
+ && !(listener is EtwListener)
+#endif // USE_ETW
+ )
{
tests.Add(new SubTest("WriteEvent/Basic/EventVarArgsWithString",
delegate () { logger.EventVarArgsWithString(1, 2, 12, null); },
@@ -430,12 +445,12 @@ namespace BasicEventSourceTests
}
}
-#if USE_ETW // TODO: Enable when TraceEvent is available on CoreCLR. GitHub issue #4864.
+#if USE_ETW
/// <summary>
/// Tests sending complex data (class, arrays etc) from WriteEvent
/// Tests the EventListener case
/// </summary>
- [Fact]
+ [ConditionalFact(nameof(IsProcessElevated))]
public void Test_WriteEvent_ComplexData_SelfDescribing_ETW()
{
using (var listener = new EtwListener())
@@ -519,13 +534,13 @@ namespace BasicEventSourceTests
Test_WriteEvent_ByteArray(false, new EventListenerListener(true));
}
-#if USE_ETW // TODO: Enable when TraceEvent is available on CoreCLR. GitHub issue #4864.
+#if USE_ETW
/// <summary>
/// Tests sending complex data (class, arrays etc) from WriteEvent
/// Uses Manifest format
/// Tests the EventListener case
/// </summary>
- [Fact]
+ [ConditionalFact(nameof(IsProcessElevated))]
public void Test_WriteEvent_ByteArray_Manifest_ETW()
{
using (var listener = new EtwListener())
@@ -549,13 +564,13 @@ namespace BasicEventSourceTests
}
}
-#if USE_ETW // TODO: Enable when TraceEvent is available on CoreCLR. GitHub issue #4864.
+#if USE_ETW
/// <summary>
/// Tests sending complex data (class, arrays etc) from WriteEvent
/// Uses Self-Describing format
/// Tests the EventListener case
/// </summary>
- [Fact]
+ [ConditionalFact(nameof(IsProcessElevated))]
public void Test_WriteEvent_ByteArray_SelfDescribing_ETW()
{
using (var listener = new EtwListener())
@@ -647,6 +662,8 @@ namespace BasicEventSourceTests
Assert.Equal(1000, (long)evt.PayloadValue(1, "lng"));
}));
+ /* TODO: NULL byte array does not seem to be supported.
+ * An EventSourceMessage event is written for this case.
tests.Add(new SubTest("Write/Array/EventWithNullByteArray",
delegate ()
{
@@ -664,6 +681,7 @@ namespace BasicEventSourceTests
Assert.Equal(0, (int)evt.PayloadValue(1, "n"));
}
}));
+ */
tests.Add(new SubTest("Write/Array/EventWithEmptyByteArray",
delegate ()
diff --git a/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWriteEventToListener.cs b/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWriteEventToListener.cs
index 4cbc1c20d1..3278fe67b7 100644
--- a/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWriteEventToListener.cs
+++ b/src/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWriteEventToListener.cs
@@ -19,6 +19,12 @@ namespace BasicEventSourceTests
{
public class TestsWriteEventToListener
{
+#if USE_ETW
+ // Specifies whether the process is elevated or not.
+ private static readonly Lazy<bool> s_isElevated = new Lazy<bool>(() => AdminHelpers.IsProcessElevated());
+ private static bool IsProcessElevated => s_isElevated.Value;
+#endif // USE_ETW
+
[Fact]
[ActiveIssue("dotnet/corefx #19462", TargetFrameworkMonikers.NetFramework)]
public void Test_WriteEvent_ArgsBasicTypes()
@@ -38,7 +44,7 @@ namespace BasicEventSourceTests
Assert.Equal(1, LoudListener.t_lastEvent.EventId);
Assert.Equal(0, LoudListener.t_lastEvent.Payload.Count);
- #region Validate "int" arguments
+#region Validate "int" arguments
log.EventI(10);
Assert.Equal(2, LoudListener.t_lastEvent.EventId);
Assert.Equal(1, LoudListener.t_lastEvent.Payload.Count);
@@ -56,9 +62,9 @@ namespace BasicEventSourceTests
Assert.Equal(10, (int)LoudListener.t_lastEvent.Payload[0]);
Assert.Equal(11, (int)LoudListener.t_lastEvent.Payload[1]);
Assert.Equal(12, (int)LoudListener.t_lastEvent.Payload[2]);
- #endregion
+#endregion
- #region Validate "long" arguments
+#region Validate "long" arguments
log.EventL(10);
Assert.Equal(5, LoudListener.t_lastEvent.EventId);
Assert.Equal(1, LoudListener.t_lastEvent.Payload.Count);
@@ -77,9 +83,9 @@ namespace BasicEventSourceTests
Assert.Equal(11, (long)LoudListener.t_lastEvent.Payload[1]);
Assert.Equal(12, (long)LoudListener.t_lastEvent.Payload[2]);
- #endregion
+#endregion
- #region Validate "string" arguments
+#region Validate "string" arguments
log.EventS("10");
Assert.Equal(8, LoudListener.t_lastEvent.EventId);
Assert.Equal(1, LoudListener.t_lastEvent.Payload.Count);
@@ -97,17 +103,17 @@ namespace BasicEventSourceTests
Assert.Equal("10", (string)LoudListener.t_lastEvent.Payload[0]);
Assert.Equal("11", (string)LoudListener.t_lastEvent.Payload[1]);
Assert.Equal("12", (string)LoudListener.t_lastEvent.Payload[2]);
- #endregion
+#endregion
- #region Validate byte array arguments
+#region Validate byte array arguments
byte[] arr = new byte[20];
log.EventWithByteArray(arr);
Assert.Equal(52, LoudListener.t_lastEvent.EventId);
Assert.Equal(1, LoudListener.t_lastEvent.Payload.Count);
Assert.Equal(arr.Length, ((byte[])LoudListener.t_lastEvent.Payload[0]).Length);
- #endregion
+#endregion
- #region Validate mixed type arguments
+#region Validate mixed type arguments
log.EventSI("10", 11);
Assert.Equal(11, LoudListener.t_lastEvent.EventId);
Assert.Equal(2, LoudListener.t_lastEvent.Payload.Count);
@@ -126,9 +132,9 @@ namespace BasicEventSourceTests
Assert.Equal("10", (string)LoudListener.t_lastEvent.Payload[0]);
Assert.Equal(11, (int)LoudListener.t_lastEvent.Payload[1]);
Assert.Equal(12, (int)LoudListener.t_lastEvent.Payload[2]);
- #endregion
+#endregion
- #region Validate enums/flags
+#region Validate enums/flags
log.EventEnum(MyColor.Blue);
Assert.Equal(19, LoudListener.t_lastEvent.EventId);
Assert.Equal(1, LoudListener.t_lastEvent.Payload.Count);
@@ -148,16 +154,16 @@ namespace BasicEventSourceTests
Assert.Equal(22, LoudListener.t_lastEvent.EventId);
Assert.Equal(1, LoudListener.t_lastEvent.Payload.Count);
Assert.Equal(MyFlags.Flag1, (MyFlags)LoudListener.t_lastEvent.Payload[0]);
- #endregion
+#endregion
-#if USE_ETW // TODO: Enable when TraceEvent is available on CoreCLR. GitHub issue #4864.
- #region Validate DateTime
+#if USE_ETW
+#region Validate DateTime
DateTime now = DateTime.Now;
log.EventDateTime(now);
Assert.Equal(24, LoudListener.LastEvent.EventId);
Assert.Equal(1, LoudListener.LastEvent.Payload.Count);
Assert.Equal((DateTime)LoudListener.LastEvent.Payload[0], now);
- #endregion
+#endregion
#endif // USE_ETW
}
}
@@ -178,7 +184,7 @@ namespace BasicEventSourceTests
EventSource.SendCommand(log, EventCommand.SendManifest, options);
Guid guid = Guid.NewGuid();
-#if USE_ETW // TODO: Enable when TraceEvent is available on CoreCLR. GitHub issue #4864.
+#if USE_ETW
log.EventWithManyTypeArgs("Hello", 0, 0, 0, 'a', 0, 0, 0, 0, (float)10.0, (double)11.0, guid);
Assert.Equal(25, LoudListener.LastEvent.EventId);
Assert.Equal(12, LoudListener.LastEvent.Payload.Count);
@@ -206,7 +212,7 @@ namespace BasicEventSourceTests
Assert.Equal(9, LoudListener.t_lastEvent.Payload.Count);
Assert.Equal("s0", (string)LoudListener.t_lastEvent.Payload[0]);
Assert.Equal("s8", (string)LoudListener.t_lastEvent.Payload[8]);
-#if USE_ETW // TODO: Enable when TraceEvent is available on CoreCLR. GitHub issue #4864.
+#if USE_ETW
log.EventWithWeirdArgs(IntPtr.Zero, true, MyLongEnum.LongVal1 /*, 9999999999999999999999999999m*/);
Assert.Equal(30, LoudListener.LastEvent.EventId);
Assert.Equal(3 /*4*/, LoudListener.LastEvent.Payload.Count);
@@ -255,14 +261,14 @@ namespace BasicEventSourceTests
TestUtilities.CheckNoEventSourcesRunning("Stop");
}
-#if USE_ETW // TODO: Enable when TraceEvent is available on CoreCLR. GitHub issue #4864.
- [Fact]
+#if USE_ETW
+ [ConditionalFact(nameof(IsProcessElevated))]
public void Test_WriteEvent_TransferEvents()
{
TestUtilities.CheckNoEventSourcesRunning("Start");
using (var log = new EventSourceTest())
{
- using (var el = new LoudListener())
+ using (var el = new LoudListener(log))
{
Guid actid = Guid.NewGuid();
log.LogTaskScheduled(actid, "Hello from a test");
@@ -352,7 +358,7 @@ namespace BasicEventSourceTests
TestUtilities.CheckNoEventSourcesRunning("Stop");
}
-#if FEATURE_ETLEVENTS
+#if FEATURE_ETLEVENTS
[Fact]
public void Test_EventSourceCreatedEvents_BeforeListener()
{
diff --git a/src/System.Diagnostics.Tracing/tests/Configurations.props b/src/System.Diagnostics.Tracing/tests/Configurations.props
index 8b803e0772..1040c9ba37 100644
--- a/src/System.Diagnostics.Tracing/tests/Configurations.props
+++ b/src/System.Diagnostics.Tracing/tests/Configurations.props
@@ -2,8 +2,8 @@
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildConfigurations>
- netcoreapp;
- netstandard;
+ netcoreapp-Windows_NT;
+ netcoreapp-Unix;
</BuildConfigurations>
</PropertyGroup>
</Project> \ No newline at end of file
diff --git a/src/System.Diagnostics.Tracing/tests/CustomEventSources/EventSourceTest.cs b/src/System.Diagnostics.Tracing/tests/CustomEventSources/EventSourceTest.cs
index 6261ab7a4a..725a8d831b 100644
--- a/src/System.Diagnostics.Tracing/tests/CustomEventSources/EventSourceTest.cs
+++ b/src/System.Diagnostics.Tracing/tests/CustomEventSources/EventSourceTest.cs
@@ -137,13 +137,12 @@ namespace SdtEventSources
public void EventDateTime(DateTime dt) { WriteEvent(24, dt); }
[Event(25, Keywords = Keywords.HasNoArgs, Level = EventLevel.Informational)]
- public void EventWithManyTypeArgs(string msg, long l, uint ui, UInt64 ui64,
+ public void EventWithManyTypeArgs(string msg, long l, uint ui, UInt64 ui64, char c,
byte b, sbyte sb, short sh, ushort ush,
float f, double d, Guid guid)
{
if (IsEnabled(EventLevel.Informational, Keywords.HasNoArgs))
- // 4.5 EventSource does not support "Char" type
- WriteEvent(25, msg, l, ui, ui64, b, sb, sh, ush, f, d, guid);
+ WriteEvent(25, msg, l, ui, ui64, c, b, sb, sh, ush, f, d, guid);
}
[Event(26)]
diff --git a/src/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj b/src/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj
index 5974d34e8f..a91cb646a1 100644
--- a/src/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj
+++ b/src/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj
@@ -5,12 +5,13 @@
<ProjectGuid>{7E0E1B11-FF70-461E-99F7-C0AF252C0C60}</ProjectGuid>
<DefineConstants Condition="'$(TargetGroup)' == 'netcoreapp'">$(DefineConstants);FEATURE_ETLEVENTS</DefineConstants>
<DefineConstants Condition="'$(TargetGroup)' == 'netcoreapp'">$(DefineConstants);FEATURE_EVENTCOUNTER_DISPOSE</DefineConstants>
+ <DefineConstants Condition="'$(TargetGroup)' == 'netcoreapp' And '$(TargetsWindows)' == 'true'">$(DefineConstants);USE_ETW</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="BasicEventSourceTest\Harness\EventTestHarness.cs" />
<Compile Include="BasicEventSourceTest\FuzzyTests.cs" />
@@ -39,6 +40,9 @@
<Compile Include="CustomEventSources\UseInterfaceEventSource.cs" />
</ItemGroup>
<ItemGroup>
+ <ReferenceFromRuntime Include="Microsoft.Diagnostics.Tracing.TraceEvent" />
+ </ItemGroup>
+ <ItemGroup>
<EmbeddedResource Include="Resources\$(AssemblyName).rd.xml" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
diff --git a/src/System.DirectoryServices.AccountManagement/pkg/System.DirectoryServices.AccountManagement.pkgproj b/src/System.DirectoryServices.AccountManagement/pkg/System.DirectoryServices.AccountManagement.pkgproj
index 4850709dd0..52501241de 100644
--- a/src/System.DirectoryServices.AccountManagement/pkg/System.DirectoryServices.AccountManagement.pkgproj
+++ b/src/System.DirectoryServices.AccountManagement/pkg/System.DirectoryServices.AccountManagement.pkgproj
@@ -3,7 +3,7 @@
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<ProjectReference Include="..\ref\System.DirectoryServices.AccountManagement.csproj">
- <SupportedFramework>netcoreapp2.0;net45;$(AllXamarinFrameworks)</SupportedFramework>
+ <SupportedFramework>uap10.0.16299;netcoreapp2.0;net45;$(AllXamarinFrameworks)</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\src\System.DirectoryServices.AccountManagement.csproj" />
<InboxOnTargetFramework Include="net45">
diff --git a/src/System.DirectoryServices.AccountManagement/src/Configurations.props b/src/System.DirectoryServices.AccountManagement/src/Configurations.props
index 94ac07fdab..e322371832 100644
--- a/src/System.DirectoryServices.AccountManagement/src/Configurations.props
+++ b/src/System.DirectoryServices.AccountManagement/src/Configurations.props
@@ -8,6 +8,7 @@
<BuildConfigurations>
$(PackageConfigurations);
netcoreapp-Windows_NT;
+ _netfx;
</BuildConfigurations>
</PropertyGroup>
</Project>
diff --git a/src/System.DirectoryServices.AccountManagement/src/Resources/Strings.resx b/src/System.DirectoryServices.AccountManagement/src/Resources/Strings.resx
index 204ccbc8ad..7c6023b69c 100644
--- a/src/System.DirectoryServices.AccountManagement/src/Resources/Strings.resx
+++ b/src/System.DirectoryServices.AccountManagement/src/Resources/Strings.resx
@@ -447,9 +447,6 @@
<data name="InvalidStringValueForStore" xml:space="preserve">
<value>Empty string is not supported by the property {0} for this store type.</value>
</data>
- <data name="InvalidNullArgument" xml:space="preserve">
- <value>{0} cannot be null or empty.</value>
- </data>
<data name="ServerDown" xml:space="preserve">
<value>The server could not be contacted.</value>
</data>
@@ -499,6 +496,6 @@
<value>Unknown error (0x{0})</value>
</data>
<data name="DirectoryServicesAccountManagement_PlatformNotSupported" xml:space="preserve">
- <value>System.DirectoryServices.AccountManagement is not supported on this platform.</value>
+ <value>System.DirectoryServices.AccountManagement is not supported on this platform.</value>
</data>
</root> \ No newline at end of file
diff --git a/src/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/Principal.cs b/src/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/Principal.cs
index 20b17a6762..c49b628d79 100644
--- a/src/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/Principal.cs
+++ b/src/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/Principal.cs
@@ -125,7 +125,7 @@ namespace System.DirectoryServices.AccountManagement
set
{
if (null == value || 0 == value.Length)
- throw new ArgumentNullException(String.Format(CultureInfo.CurrentCulture, SR.InvalidNullArgument, PropertyNames.PrincipalSamAccountName));
+ throw new ArgumentNullException(PropertyNames.PrincipalSamAccountName);
if (!GetStoreCtxToUse().IsValidProperty(this, PropertyNames.PrincipalSamAccountName))
throw new InvalidOperationException(SR.InvalidPropertyForStore);
@@ -245,7 +245,7 @@ namespace System.DirectoryServices.AccountManagement
set
{
if (null == value || 0 == value.Length)
- throw new ArgumentNullException(String.Format(CultureInfo.CurrentCulture, SR.InvalidNullArgument, PropertyNames.PrincipalName));
+ throw new ArgumentNullException(PropertyNames.PrincipalName);
if (!GetStoreCtxToUse().IsValidProperty(this, PropertyNames.PrincipalName))
throw new InvalidOperationException(SR.InvalidPropertyForStore);
@@ -635,7 +635,7 @@ namespace System.DirectoryServices.AccountManagement
}
else if (this.unpersisted)
{
- return new object[0];
+ return Array.Empty<object>();
}
else
{
@@ -645,7 +645,7 @@ namespace System.DirectoryServices.AccountManagement
int valCount = de.Properties[attribute].Count;
if (valCount == 0)
- return new object[0];
+ return Array.Empty<object>();
else
{
object[] objectArray = new object[valCount];
diff --git a/src/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/PrincipalSearcher.cs b/src/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/PrincipalSearcher.cs
index 7f8c9b3e05..cadd51de0a 100644
--- a/src/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/PrincipalSearcher.cs
+++ b/src/System.DirectoryServices.AccountManagement/src/System/DirectoryServices/AccountManagement/PrincipalSearcher.cs
@@ -23,7 +23,7 @@ namespace System.DirectoryServices.AccountManagement
public PrincipalSearcher(Principal queryFilter)
{
if (null == queryFilter)
- throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, SR.InvalidNullArgument, "queryFilter"));
+ throw new ArgumentException(nameof(queryFilter));
_ctx = queryFilter.Context;
this.QueryFilter = queryFilter; // use property to enforce "no persisted principals" check
@@ -56,7 +56,7 @@ namespace System.DirectoryServices.AccountManagement
set
{
if (null == value)
- throw new ArgumentNullException(String.Format(CultureInfo.CurrentCulture, SR.InvalidNullArgument, "queryFilter"));
+ throw new ArgumentNullException(nameof(QueryFilter));
CheckDisposed();
Debug.Assert(value.Context != null);
diff --git a/src/System.DirectoryServices.AccountManagement/tests/ComputerPrincipalTest.cs b/src/System.DirectoryServices.AccountManagement/tests/ComputerPrincipalTest.cs
index c5a9230b84..092441335a 100644
--- a/src/System.DirectoryServices.AccountManagement/tests/ComputerPrincipalTest.cs
+++ b/src/System.DirectoryServices.AccountManagement/tests/ComputerPrincipalTest.cs
@@ -35,7 +35,7 @@ namespace System.DirectoryServices.AccountManagement.Tests
public void Ctor_EmptySamAccountName_ThrowsArgumentNullException()
{
var context = new PrincipalContext(ContextType.Machine);
- AssertExtensions.Throws<ArgumentNullException>("Principal.SamAccountName cannot be null or empty.", () => new ComputerPrincipal(context, string.Empty, "password", enabled: true));
+ AssertExtensions.Throws<ArgumentNullException>("Principal.SamAccountName", null, () => new ComputerPrincipal(context, string.Empty, "password", enabled: true));
}
[Fact]
diff --git a/src/System.DirectoryServices.AccountManagement/tests/Configurations.props b/src/System.DirectoryServices.AccountManagement/tests/Configurations.props
index d88b0bf51e..51d1fc2309 100644
--- a/src/System.DirectoryServices.AccountManagement/tests/Configurations.props
+++ b/src/System.DirectoryServices.AccountManagement/tests/Configurations.props
@@ -3,6 +3,7 @@
<PropertyGroup>
<BuildConfigurations>
netcoreapp-Windows_NT;
+ netfx;
</BuildConfigurations>
</PropertyGroup>
</Project>
diff --git a/src/System.DirectoryServices.AccountManagement/tests/System.DirectoryServices.AccountManagement.Tests.csproj b/src/System.DirectoryServices.AccountManagement/tests/System.DirectoryServices.AccountManagement.Tests.csproj
index abacbd2f86..bdad4811ed 100644
--- a/src/System.DirectoryServices.AccountManagement/tests/System.DirectoryServices.AccountManagement.Tests.csproj
+++ b/src/System.DirectoryServices.AccountManagement/tests/System.DirectoryServices.AccountManagement.Tests.csproj
@@ -6,6 +6,8 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="ComputerPrincipalTest.cs" />
<Compile Include="ExtendedUserPrincipal.cs" />
@@ -14,18 +16,14 @@
<Compile Include="PrincipalContextTests.cs" />
<Compile Include="UserPrincipalTest.cs" />
<Compile Include="AccountManagementTests.cs" />
-
- <Compile Include="$(CommonTestPath)\System\DirectoryServices\LdapConfiguration.cs">
+ <Compile Include="$(CommonTestPath)\System\DirectoryServices\LdapConfiguration.cs">
<Link>Common\DirectoryServices\LdapConfiguration.cs</Link>
</Compile>
-
</ItemGroup>
-
<ItemGroup>
<None Include="LDAP.Configuration.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
-
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.DirectoryServices.AccountManagement/tests/testobj.cs b/src/System.DirectoryServices.AccountManagement/tests/testobj.cs
index 71eb00ea01..6ca7ceb45a 100644
--- a/src/System.DirectoryServices.AccountManagement/tests/testobj.cs
+++ b/src/System.DirectoryServices.AccountManagement/tests/testobj.cs
@@ -1,6 +1,8 @@
-/*++
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
-Copyright (c) 2004 Microsoft Corporation
+/*++
Module Name:
@@ -11,10 +13,6 @@ Abstract:
Exposes test hooks.
Only present in TESTHOOK builds.
-
-History:
-
- 06-May-2004 MattRim Created
--*/
diff --git a/src/System.DirectoryServices.Protocols/pkg/System.DirectoryServices.Protocols.pkgproj b/src/System.DirectoryServices.Protocols/pkg/System.DirectoryServices.Protocols.pkgproj
index 7f056cb3a0..55c341f2ad 100644
--- a/src/System.DirectoryServices.Protocols/pkg/System.DirectoryServices.Protocols.pkgproj
+++ b/src/System.DirectoryServices.Protocols/pkg/System.DirectoryServices.Protocols.pkgproj
@@ -3,7 +3,7 @@
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<ProjectReference Include="..\ref\System.DirectoryServices.Protocols.csproj">
- <SupportedFramework>netcoreapp2.0;net45;$(AllXamarinFrameworks)</SupportedFramework>
+ <SupportedFramework>uap10.0.16299;netcoreapp2.0;net45;$(AllXamarinFrameworks)</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\src\System.DirectoryServices.Protocols.csproj" />
diff --git a/src/System.DirectoryServices.Protocols/src/Configurations.props b/src/System.DirectoryServices.Protocols/src/Configurations.props
index 94ac07fdab..e322371832 100644
--- a/src/System.DirectoryServices.Protocols/src/Configurations.props
+++ b/src/System.DirectoryServices.Protocols/src/Configurations.props
@@ -8,6 +8,7 @@
<BuildConfigurations>
$(PackageConfigurations);
netcoreapp-Windows_NT;
+ _netfx;
</BuildConfigurations>
</PropertyGroup>
</Project>
diff --git a/src/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/BerConverter.cs b/src/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/BerConverter.cs
index 42a2ca8d01..354170ec3d 100644
--- a/src/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/BerConverter.cs
+++ b/src/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/BerConverter.cs
@@ -22,7 +22,7 @@ namespace System.DirectoryServices.Protocols
byte[] encodingResult = null;
// value is allowed to be null in certain scenario, so if it is null, just set it to empty array.
if (value == null)
- value = new object[0];
+ value = Array.Empty<object>();
Debug.WriteLine("Begin encoding\n");
@@ -235,7 +235,7 @@ namespace System.DirectoryServices.Protocols
if (binaryValue == null || binaryValue.bv_len == 0)
{
- encodingResult = new byte[0];
+ encodingResult = Array.Empty<byte>();
}
else
{
diff --git a/src/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/DirectoryControl.cs b/src/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/DirectoryControl.cs
index 679a970f21..0ef7370eb9 100644
--- a/src/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/DirectoryControl.cs
+++ b/src/System.DirectoryServices.Protocols/src/System/DirectoryServices/Protocols/common/DirectoryControl.cs
@@ -634,7 +634,7 @@ namespace System.DirectoryServices.Protocols
public class SortRequestControl : DirectoryControl
{
- private SortKey[] _keys = new SortKey[0];
+ private SortKey[] _keys = Array.Empty<SortKey>();
public SortRequestControl(params SortKey[] sortKeys) : base("1.2.840.113556.1.4.473", null, true, true)
{
if (sortKeys == null)
diff --git a/src/System.DirectoryServices.Protocols/tests/Configurations.props b/src/System.DirectoryServices.Protocols/tests/Configurations.props
index d8cd9ec843..808952d28a 100644
--- a/src/System.DirectoryServices.Protocols/tests/Configurations.props
+++ b/src/System.DirectoryServices.Protocols/tests/Configurations.props
@@ -3,6 +3,7 @@
<PropertyGroup>
<BuildConfigurations>
netcoreapp-Windows_NT;
+ netfx;
</BuildConfigurations>
</PropertyGroup>
</Project>
diff --git a/src/System.DirectoryServices.Protocols/tests/System.DirectoryServices.Protocols.Tests.csproj b/src/System.DirectoryServices.Protocols/tests/System.DirectoryServices.Protocols.Tests.csproj
index 9d293444d1..7351989446 100644
--- a/src/System.DirectoryServices.Protocols/tests/System.DirectoryServices.Protocols.Tests.csproj
+++ b/src/System.DirectoryServices.Protocols/tests/System.DirectoryServices.Protocols.Tests.csproj
@@ -6,6 +6,8 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="BerConverterTests.cs" />
<Compile Include="LdapSessionOptionsTests.cs" />
@@ -50,7 +52,6 @@
<Compile Include="BerConversionExceptionTests.cs" />
<Compile Include="AsqRequestControlTests.cs" />
<Compile Include="AddRequestTests.cs" />
-
<Compile Include="DirectoryServicesProtocolsTests.cs" />
<Compile Include="$(CommonTestPath)\System\DirectoryServices\LdapConfiguration.cs">
<Link>Common\DirectoryServices\LdapConfiguration.cs</Link>
diff --git a/src/System.DirectoryServices/pkg/System.DirectoryServices.pkgproj b/src/System.DirectoryServices/pkg/System.DirectoryServices.pkgproj
index c750a9d9c5..989e59c013 100644
--- a/src/System.DirectoryServices/pkg/System.DirectoryServices.pkgproj
+++ b/src/System.DirectoryServices/pkg/System.DirectoryServices.pkgproj
@@ -3,7 +3,7 @@
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<ProjectReference Include="..\ref\System.DirectoryServices.csproj">
- <SupportedFramework>netcoreapp2.0;net45;$(AllXamarinFrameworks)</SupportedFramework>
+ <SupportedFramework>uap10.0.16299;netcoreapp2.0;net45;$(AllXamarinFrameworks)</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\src\System.DirectoryServices.csproj" />
diff --git a/src/System.DirectoryServices/src/Configurations.props b/src/System.DirectoryServices/src/Configurations.props
index 94ac07fdab..e322371832 100644
--- a/src/System.DirectoryServices/src/Configurations.props
+++ b/src/System.DirectoryServices/src/Configurations.props
@@ -8,6 +8,7 @@
<BuildConfigurations>
$(PackageConfigurations);
netcoreapp-Windows_NT;
+ _netfx;
</BuildConfigurations>
</PropertyGroup>
</Project>
diff --git a/src/System.DirectoryServices/src/System/DirectoryServices/DirectorySearcher.cs b/src/System.DirectoryServices/src/System/DirectoryServices/DirectorySearcher.cs
index 8895609a8d..6f94c2f87a 100644
--- a/src/System.DirectoryServices/src/System/DirectoryServices/DirectorySearcher.cs
+++ b/src/System.DirectoryServices/src/System/DirectoryServices/DirectorySearcher.cs
@@ -671,7 +671,7 @@ namespace System.DirectoryServices
else
{
adsSearch.ExecuteSearch(Filter, null, -1, out resultsHandle);
- properties = new string[0];
+ properties = Array.Empty<string>();
}
SearchResultCollection result = new SearchResultCollection(clonedRoot, resultsHandle, properties, this);
diff --git a/src/System.DirectoryServices/src/System/DirectoryServices/DirectorySynchronization.cs b/src/System.DirectoryServices/src/System/DirectoryServices/DirectorySynchronization.cs
index 7f0a090b59..d8adadad2b 100644
--- a/src/System.DirectoryServices/src/System/DirectoryServices/DirectorySynchronization.cs
+++ b/src/System.DirectoryServices/src/System/DirectoryServices/DirectorySynchronization.cs
@@ -9,7 +9,7 @@ namespace System.DirectoryServices
public class DirectorySynchronization
{
private DirectorySynchronizationOptions _option = DirectorySynchronizationOptions.None;
- private byte[] _cookie = new byte[0];
+ private byte[] _cookie = Array.Empty<byte>();
public DirectorySynchronization()
{
diff --git a/src/System.DirectoryServices/src/System/DirectoryServices/DirectoryVirtualListViewContext.cs b/src/System.DirectoryServices/src/System/DirectoryServices/DirectoryVirtualListViewContext.cs
index b3c239367b..a25af4d769 100644
--- a/src/System.DirectoryServices/src/System/DirectoryServices/DirectoryVirtualListViewContext.cs
+++ b/src/System.DirectoryServices/src/System/DirectoryServices/DirectoryVirtualListViewContext.cs
@@ -8,7 +8,7 @@ namespace System.DirectoryServices
{
internal readonly byte[] _context;
- public DirectoryVirtualListViewContext() : this(new byte[0])
+ public DirectoryVirtualListViewContext() : this(null)
{
}
@@ -16,7 +16,7 @@ namespace System.DirectoryServices
{
if (context == null)
{
- _context = new byte[0];
+ _context = Array.Empty<byte>();
}
else
{
diff --git a/src/System.DirectoryServices/src/System/DirectoryServices/ResultPropertyCollection.cs b/src/System.DirectoryServices/src/System/DirectoryServices/ResultPropertyCollection.cs
index 7e93bb160b..7ed4132e11 100644
--- a/src/System.DirectoryServices/src/System/DirectoryServices/ResultPropertyCollection.cs
+++ b/src/System.DirectoryServices/src/System/DirectoryServices/ResultPropertyCollection.cs
@@ -30,7 +30,7 @@ namespace System.DirectoryServices
}
else
{
- return new ResultPropertyValueCollection(new object[0]);
+ return new ResultPropertyValueCollection(Array.Empty<object>());
}
}
}
diff --git a/src/System.DirectoryServices/src/System/DirectoryServices/SchemaNameCollection.cs b/src/System.DirectoryServices/src/System/DirectoryServices/SchemaNameCollection.cs
index 4b1d26e5c3..7097d57c60 100644
--- a/src/System.DirectoryServices/src/System/DirectoryServices/SchemaNameCollection.cs
+++ b/src/System.DirectoryServices/src/System/DirectoryServices/SchemaNameCollection.cs
@@ -103,8 +103,7 @@ namespace System.DirectoryServices
/// </devdoc>
public void Clear()
{
- object[] newValues = new object[0];
- _propSetter(newValues);
+ _propSetter(Array.Empty<object>());
}
/// <devdoc>
@@ -128,7 +127,7 @@ namespace System.DirectoryServices
{
object value = _propGetter();
if (value == null)
- return new object[0];
+ return Array.Empty<object>();
else
return (object[])value;
}
diff --git a/src/System.DirectoryServices/tests/Configurations.props b/src/System.DirectoryServices/tests/Configurations.props
index d8cd9ec843..808952d28a 100644
--- a/src/System.DirectoryServices/tests/Configurations.props
+++ b/src/System.DirectoryServices/tests/Configurations.props
@@ -3,6 +3,7 @@
<PropertyGroup>
<BuildConfigurations>
netcoreapp-Windows_NT;
+ netfx;
</BuildConfigurations>
</PropertyGroup>
</Project>
diff --git a/src/System.DirectoryServices/tests/System.DirectoryServices.Tests.csproj b/src/System.DirectoryServices/tests/System.DirectoryServices.Tests.csproj
index 3d0cd83653..d0ab8c21b0 100644
--- a/src/System.DirectoryServices/tests/System.DirectoryServices.Tests.csproj
+++ b/src/System.DirectoryServices/tests/System.DirectoryServices.Tests.csproj
@@ -7,6 +7,8 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="System\DirectoryServices\ActiveDirectorySecurityTests.cs" />
<Compile Include="System\DirectoryServices\ActiveDirectory\DomainControllerTests.cs" />
@@ -21,7 +23,6 @@
<Compile Include="System\DirectoryServices\ActiveDirectory\DirectoryContextTests.cs" />
<Compile Include="System\DirectoryServices\ActiveDirectory\ForestTests.cs" />
<Compile Include="System\DirectoryServices\ActiveDirectory\ActiveDirectoryTests.cs" />
-
<Compile Include="$(CommonTestPath)\System\DirectoryServices\LdapConfiguration.cs">
<Link>Common\DirectoryServices\LdapConfiguration.cs</Link>
</Compile>
@@ -31,11 +32,9 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
-
- <ItemGroup Condition="'$(TargetsWindows)' == 'true'" >
+ <ItemGroup Condition="'$(TargetsWindows)' == 'true'">
<Compile Include="System\DirectoryServices\DirectoryServicesTests.Windows.cs" />
<Compile Include="System\DirectoryServices\ActiveDirectoryComInterop.cs" />
</ItemGroup>
-
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.DirectoryServices/tests/System/DirectoryServices/ActiveDirectory/ForestTests.cs b/src/System.DirectoryServices/tests/System/DirectoryServices/ActiveDirectory/ForestTests.cs
index 3b4cbacfae..1cf2af3eb5 100644
--- a/src/System.DirectoryServices/tests/System/DirectoryServices/ActiveDirectory/ForestTests.cs
+++ b/src/System.DirectoryServices/tests/System/DirectoryServices/ActiveDirectory/ForestTests.cs
@@ -64,6 +64,7 @@ namespace System.DirectoryServices.ActiveDirectory.Tests
exception is ActiveDirectoryOperationException,
$"We got unrecognized exception {exception}");
+
// The result of validation is cached, so repeat this to make sure it's cached properly.
exception = Record.Exception(() => Forest.GetForest(context));
Assert.NotNull(exception);
diff --git a/src/System.DirectoryServices/tests/System/DirectoryServices/PropertyCollectionTests.cs b/src/System.DirectoryServices/tests/System/DirectoryServices/PropertyCollectionTests.cs
index 53948ea064..5443754207 100644
--- a/src/System.DirectoryServices/tests/System/DirectoryServices/PropertyCollectionTests.cs
+++ b/src/System.DirectoryServices/tests/System/DirectoryServices/PropertyCollectionTests.cs
@@ -82,8 +82,8 @@ namespace System.DirectoryServices.Tests
using (var entry = new DirectoryEntry())
{
PropertyCollection properties = entry.Properties;
- AssertExtensions.Throws<ArgumentOutOfRangeException>("Number was less than the array's lower bound in the first dimension.", () => properties.CopyTo(new PropertyValueCollection[0], -1));
- AssertExtensions.Throws<ArgumentOutOfRangeException>("Number was less than the array's lower bound in the first dimension.", () => ((ICollection)properties).CopyTo(new PropertyValueCollection[0], -1));
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("Number was less than the array's lower bound in the first dimension.", null, () => properties.CopyTo(new PropertyValueCollection[0], -1));
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("Number was less than the array's lower bound in the first dimension.", null, () => ((ICollection)properties).CopyTo(new PropertyValueCollection[0], -1));
}
}
diff --git a/src/System.Drawing.Common/pkg/System.Drawing.Common.pkgproj b/src/System.Drawing.Common/pkg/System.Drawing.Common.pkgproj
index 1fe84ed429..a0f5151c08 100644
--- a/src/System.Drawing.Common/pkg/System.Drawing.Common.pkgproj
+++ b/src/System.Drawing.Common/pkg/System.Drawing.Common.pkgproj
@@ -3,7 +3,7 @@
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<ProjectReference Include="..\ref\System.Drawing.Common.csproj">
- <SupportedFramework>net461;netcoreapp2.0;$(AllXamarinFrameworks)</SupportedFramework>
+ <SupportedFramework>uap10.0.16299;net461;netcoreapp2.0;$(AllXamarinFrameworks)</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\src\System.Drawing.Common.csproj" />
diff --git a/src/System.Drawing.Common/ref/System.Drawing.Common.cs b/src/System.Drawing.Common/ref/System.Drawing.Common.cs
index 715ca992e7..a9a2334312 100644
--- a/src/System.Drawing.Common/ref/System.Drawing.Common.cs
+++ b/src/System.Drawing.Common/ref/System.Drawing.Common.cs
@@ -238,9 +238,8 @@ namespace System.Drawing
public static bool operator ==(System.Drawing.CharacterRange cr1, System.Drawing.CharacterRange cr2) { throw null; }
public static bool operator !=(System.Drawing.CharacterRange cr1, System.Drawing.CharacterRange cr2) { throw null; }
}
- public sealed partial class ColorTranslator
+ public static partial class ColorTranslator
{
- internal ColorTranslator() { }
public static System.Drawing.Color FromHtml(string htmlColor) { throw null; }
public static System.Drawing.Color FromOle(int oleColor) { throw null; }
public static System.Drawing.Color FromWin32(int win32Color) { throw null; }
diff --git a/src/System.Drawing.Common/src/PinvokeAnalyzerExceptionList.analyzerdata b/src/System.Drawing.Common/src/PinvokeAnalyzerExceptionList.analyzerdata
new file mode 100644
index 0000000000..4147d127f5
--- /dev/null
+++ b/src/System.Drawing.Common/src/PinvokeAnalyzerExceptionList.analyzerdata
@@ -0,0 +1,65 @@
+comdlg32.dll!PrintDlg
+comdlg32.dll!PrintDlg
+gdi32.dll!AbortDoc
+gdi32.dll!AddFontResourceEx
+gdi32.dll!BitBlt
+gdi32.dll!CombineRgn
+gdi32.dll!CreateCompatibleBitmap
+gdi32.dll!CreateCompatibleDC
+gdi32.dll!CreateCompatibleDC
+gdi32.dll!CreateDC
+gdi32.dll!CreateDIBSection
+gdi32.dll!CreateFontIndirect
+gdi32.dll!CreateIC
+gdi32.dll!CreateRectRgn
+gdi32.dll!CreateRectRgn
+gdi32.dll!DeleteDC
+gdi32.dll!DeleteDC
+gdi32.dll!DeleteObject
+gdi32.dll!DeleteObject
+gdi32.dll!EndDoc
+gdi32.dll!EndPage
+gdi32.dll!ExtEscape
+gdi32.dll!ExtEscape
+gdi32.dll!GetClipRgn
+gdi32.dll!GetClipRgn
+gdi32.dll!GetCurrentObject
+gdi32.dll!GetDeviceCaps
+gdi32.dll!GetDIBits
+gdi32.dll!GetObject
+gdi32.dll!GetObject
+gdi32.dll!GetObjectType
+gdi32.dll!GetPaletteEntries
+gdi32.dll!GetRgnBox
+gdi32.dll!GetStockObject
+gdi32.dll!IntersectClipRect
+gdi32.dll!OffsetViewportOrgEx
+gdi32.dll!ResetDC
+gdi32.dll!RestoreDC
+gdi32.dll!SaveDC
+gdi32.dll!SelectClipRgn
+gdi32.dll!SelectClipRgn
+gdi32.dll!SelectObject
+gdi32.dll!StartDoc
+gdi32.dll!StartPage
+kernel32.dll!RtlMoveMemory
+shell32.dll!ExtractAssociatedIcon
+user32.dll!CopyImage
+user32.dll!CreateIconFromResourceEx
+user32.dll!DestroyIcon
+user32.dll!DrawIconEx
+user32.dll!GetDC
+user32.dll!GetDC
+user32.dll!GetIconInfo
+user32.dll!GetSysColor
+user32.dll!GetSystemMetrics
+user32.dll!LoadIcon
+user32.dll!ReleaseDC
+user32.dll!ReleaseDC
+user32.dll!SystemParametersInfo
+user32.dll!SystemParametersInfo
+user32.dll!WindowFromDC
+winspool.drv!DeviceCapabilities
+winspool.drv!DocumentProperties
+winspool.drv!DocumentProperties
+winspool.drv!EnumPrinters
diff --git a/src/System.Drawing.Common/src/System.Drawing.Common.csproj b/src/System.Drawing.Common/src/System.Drawing.Common.csproj
index 0fddb02bd9..220c41fc08 100644
--- a/src/System.Drawing.Common/src/System.Drawing.Common.csproj
+++ b/src/System.Drawing.Common/src/System.Drawing.Common.csproj
@@ -6,11 +6,10 @@
<ProjectGuid>{191B3618-FECD-4ABD-9D6B-5AC90DC33621}</ProjectGuid>
<DefineConstants>$(DefineConstants);DRAWING_NAMESPACE</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
- <!-- TODO: RE-ENABLE THIS -->
- <EnablePInvokeAnalyzer>false</EnablePInvokeAnalyzer>
<WarningsNotAsErrors>CS0618</WarningsNotAsErrors>
- <DefineConstants Condition="'$(TargetsWindows)' == 'true'">$(DefineConstants);FEATURE_WINDOWS_SYSTEM_COLORS</DefineConstants>
+ <DefineConstants Condition="'$(TargetsWindows)' == 'true'">$(DefineConstants);FEATURE_WINDOWS_SYSTEM_COLORS;FEATURE_SYSTEM_EVENTS</DefineConstants>
<DefineConstants Condition="'$(TargetsUnix)' == 'true'">$(DefineConstants);CORECLR;NETCORE</DefineConstants>
+ <DefineConstants Condition="'$(TargetGroup)' == 'netcoreapp2.0'">$(DefineConstants);netcoreapp20</DefineConstants>
<IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'netfx'">true</IsPartialFacadeAssembly>
<GeneratePlatformNotSupportedAssemblyMessage Condition="'$(TargetGroup)' == 'netstandard'">SR.PlatformNotSupported_Drawing</GeneratePlatformNotSupportedAssemblyMessage>
</PropertyGroup>
@@ -36,10 +35,12 @@
<Compile Include="System\Drawing\ColorTranslator.cs" />
<Compile Include="System\Drawing\ContentAlignment.cs" />
<Compile Include="System\Drawing\IDeviceContext.cs" />
- <Compile Include="System\Drawing\Image.cs" />
<Compile Include="System\Drawing\GdiplusNative.cs" />
<Compile Include="System\Drawing\Graphics.cs" />
<Compile Include="System\Drawing\GraphicsUnit.cs" />
+ <Compile Include="System\Drawing\Icon.NotSerializable.cs" />
+ <Compile Include="System\Drawing\Image.NotSerializable.cs" />
+ <Compile Include="System\Drawing\Image.cs" />
<Compile Include="System\Drawing\ImageType.cs" />
<Compile Include="System\Drawing\Pen.cs" />
<Compile Include="System\Drawing\Pens.cs" />
@@ -51,7 +52,6 @@
<Compile Include="System\Drawing\Printing\PrinterUnit.cs" />
<Compile Include="System\Drawing\Printing\PreviewPageInfo.cs" />
<Compile Include="System\Drawing\Printing\PrintEventHandler.cs" />
- <Compile Include="System\Drawing\Printing\PrintingPermissionLevel.cs" />
<Compile Include="System\Drawing\Printing\PrintAction.cs" />
<Compile Include="System\Drawing\Printing\PrintPageEventHandler.cs" />
<Compile Include="System\Drawing\Printing\QueryPageSettingsEventArgs.cs" />
@@ -133,7 +133,9 @@
<Compile Include="System\Drawing\Internal\GPPOINTF.cs" />
<Compile Include="System\Drawing\Internal\GPRECT.cs" />
<Compile Include="System\Drawing\Internal\GPRECTF.cs" />
+ <Compile Include="System\Drawing\Internal\ISystemEventTracker.cs" />
<Compile Include="System\Drawing\Brush.cs" />
+ <Compile Include="System\Drawing\Font.NotSerializable.cs" />
<Compile Include="System\Drawing\FontFamily.cs" />
<Compile Include="System\Drawing\SolidBrush.cs" />
<Compile Include="System\Drawing\SystemBrushes.cs" />
@@ -212,14 +214,11 @@
<Compile Include="System\Drawing\Drawing2D\CustomLineCap.Windows.cs" />
<Compile Include="System\Drawing\Drawing2D\GraphicsPath.Windows.cs" />
<Compile Include="System\Drawing\Font.Windows.cs" />
- <Compile Include="System\Drawing\Font.NotSerializable.cs" />
<Compile Include="System\Drawing\GdiplusNative.Windows.cs" />
<Compile Include="System\Drawing\Graphics.Windows.cs" />
<Compile Include="System\Drawing\GraphicsContext.cs" />
<Compile Include="System\Drawing\Icon.Windows.cs" />
- <Compile Include="System\Drawing\Icon.NotSerializable.cs" />
<Compile Include="System\Drawing\Image.Windows.cs" />
- <Compile Include="System\Drawing\Image.NotSerializable.cs" />
<Compile Include="System\Drawing\ImageAnimator.Windows.cs" />
<Compile Include="System\Drawing\ImageInfo.cs" />
<Compile Include="System\Drawing\Imaging\BitmapData.Windows.cs" />
@@ -227,6 +226,7 @@
<Compile Include="System\Drawing\Imaging\MetafileHeader.Windows.cs" />
<Compile Include="System\Drawing\Imaging\MetaHeader.Windows.cs" />
<Compile Include="System\Drawing\Internal\GPStream.cs" />
+ <Compile Include="System\Drawing\Internal\SystemColorTracker.cs" />
<Compile Include="System\Drawing\LocalAppContextSwitches.cs" />
<Compile Include="System\Drawing\Pen.Windows.cs" />
<Compile Include="System\Drawing\Printing\DefaultPrintController.cs" />
@@ -293,7 +293,6 @@
<!-- Unix-specific -->
<Compile Include="System\Drawing\Graphics.Unix.cs" />
<Compile Include="System\Drawing\Icon.Unix.cs" />
- <Compile Include="System\Drawing\Icon.NotSerializable.cs" />
<Compile Include="System\Drawing\SystemFonts.Unix.cs" />
<Compile Include="System\Drawing\Imaging\BitmapData.Unix.cs" />
<Compile Include="System\Drawing\Imaging\Metafile.Unix.cs" />
@@ -351,6 +350,7 @@
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' != 'netfx'">
<Reference Include="Microsoft.Win32.Primitives" />
+ <Reference Condition="'$(TargetsWindows)' == 'true'" Include="Microsoft.Win32.SystemEvents" />
<Reference Include="System.Collections" />
<Reference Include="System.Collections.NonGeneric" />
<Reference Include="System.Collections.Specialized" />
@@ -377,4 +377,4 @@
<Reference Include="System.Drawing" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Drawing.Common/src/System/Drawing/Bitmap.Unix.cs b/src/System.Drawing.Common/src/System/Drawing/Bitmap.Unix.cs
index ab4b8742ff..7900600148 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Bitmap.Unix.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Bitmap.Unix.cs
@@ -46,7 +46,6 @@ using System.ComponentModel;
namespace System.Drawing
{
- [Serializable]
#if !NETCORE
[Editor ("System.Drawing.Design.BitmapEditor, " + Consts.AssemblySystem_Drawing_Design, typeof (System.Drawing.Design.UITypeEditor))]
#endif
@@ -86,11 +85,6 @@ namespace System.Drawing
nativeImage = InitFromStream(s);
}
-
- private Bitmap(SerializationInfo info, StreamingContext context)
- : base(info, context)
- {
- }
#endregion
private void ValidateBitmap(IntPtr bitmap)
diff --git a/src/System.Drawing.Common/src/System/Drawing/BufferedGraphicsManager.Unix.cs b/src/System.Drawing.Common/src/System/Drawing/BufferedGraphicsManager.Unix.cs
index 60f9abc8d9..7f194df6ea 100644
--- a/src/System.Drawing.Common/src/System/Drawing/BufferedGraphicsManager.Unix.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/BufferedGraphicsManager.Unix.cs
@@ -31,7 +31,7 @@
namespace System.Drawing
{
- public sealed class BufferedGraphicsManager
+ public static class BufferedGraphicsManager
{
private static BufferedGraphicsContext graphics_context;
@@ -40,10 +40,6 @@ namespace System.Drawing
graphics_context = new BufferedGraphicsContext();
}
- private BufferedGraphicsManager()
- {
- }
-
public static BufferedGraphicsContext Current
{
get { return graphics_context; }
diff --git a/src/System.Drawing.Common/src/System/Drawing/ColorConverter.cs b/src/System.Drawing.Common/src/System/Drawing/ColorConverter.cs
index decb4ee064..88242805d1 100644
--- a/src/System.Drawing.Common/src/System/Drawing/ColorConverter.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/ColorConverter.cs
@@ -1,11 +1,7 @@
-//------------------------------------------------------------------------------
-// <copyright file="ColorConverter.cs" company="Microsoft">
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// </copyright>
-//------------------------------------------------------------------------------
-
-/*
- */
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
namespace System.Drawing {
using System.Runtime.Serialization.Formatters;
using System.Runtime.InteropServices;
diff --git a/src/System.Drawing.Common/src/System/Drawing/ColorTranslator.cs b/src/System.Drawing.Common/src/System/Drawing/ColorTranslator.cs
index 8bf006b9d2..fe45c4fbd1 100644
--- a/src/System.Drawing.Common/src/System/Drawing/ColorTranslator.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/ColorTranslator.cs
@@ -10,7 +10,7 @@ namespace System.Drawing
/// <summary>
/// Translates colors to and from GDI+ <see cref='Color'/> objects.
/// </summary>
- public sealed class ColorTranslator
+ public static class ColorTranslator
{
private const int Win32RedShift = 0;
private const int Win32GreenShift = 8;
diff --git a/src/System.Drawing.Common/src/System/Drawing/Design/IPropertyValueUIService.cs b/src/System.Drawing.Common/src/System/Drawing/Design/IPropertyValueUIService.cs
index 062e900e5e..d1234c1695 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Design/IPropertyValueUIService.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Design/IPropertyValueUIService.cs
@@ -1,11 +1,7 @@
-//------------------------------------------------------------------------------
-// <copyright file="IPropertyValueUIService.cs" company="Microsoft">
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// </copyright>
-//------------------------------------------------------------------------------
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
-/*
- */
namespace System.Drawing.Design {
using System.Diagnostics;
diff --git a/src/System.Drawing.Common/src/System/Drawing/Design/IToolboxItemProvider.cs b/src/System.Drawing.Common/src/System/Drawing/Design/IToolboxItemProvider.cs
index 15aa59a514..2dfebabdc0 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Design/IToolboxItemProvider.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Design/IToolboxItemProvider.cs
@@ -1,8 +1,6 @@
-//------------------------------------------------------------------------------
-// <copyright file="IToolboxItemProvider.cs" company="Microsoft">
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// </copyright>
-//------------------------------------------------------------------------------
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
namespace System.Drawing.Design {
diff --git a/src/System.Drawing.Common/src/System/Drawing/Design/IToolboxService.cs b/src/System.Drawing.Common/src/System/Drawing/Design/IToolboxService.cs
index b8ff1bdd2b..d3894a7459 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Design/IToolboxService.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Design/IToolboxService.cs
@@ -1,8 +1,6 @@
-//------------------------------------------------------------------------------
-// <copyright file="IToolboxService.cs" company="Microsoft">
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// </copyright>
-//------------------------------------------------------------------------------
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
/*
*/
diff --git a/src/System.Drawing.Common/src/System/Drawing/Design/IToolboxUser.cs b/src/System.Drawing.Common/src/System/Drawing/Design/IToolboxUser.cs
index 7d2cb9de3b..b804d7a1dc 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Design/IToolboxUser.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Design/IToolboxUser.cs
@@ -1,8 +1,6 @@
-//------------------------------------------------------------------------------
-// <copyright file="IToolboxUser.cs" company="Microsoft">
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// </copyright>
-//------------------------------------------------------------------------------
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
/*
*/
diff --git a/src/System.Drawing.Common/src/System/Drawing/Design/PaintValueEventArgs.cs b/src/System.Drawing.Common/src/System/Drawing/Design/PaintValueEventArgs.cs
index 5c45524e23..958d7119bf 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Design/PaintValueEventArgs.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Design/PaintValueEventArgs.cs
@@ -1,8 +1,6 @@
-//------------------------------------------------------------------------------
-// <copyright file="PaintValueEventArgs.cs" company="Microsoft">
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// </copyright>
-//------------------------------------------------------------------------------
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
/*
*/
diff --git a/src/System.Drawing.Common/src/System/Drawing/Design/PropertyValueUIHandler.cs b/src/System.Drawing.Common/src/System/Drawing/Design/PropertyValueUIHandler.cs
index a7c3621adf..1d630336e3 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Design/PropertyValueUIHandler.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Design/PropertyValueUIHandler.cs
@@ -1,8 +1,6 @@
-//------------------------------------------------------------------------------
-// <copyright file="PropertyValueUIHandler.cs" company="Microsoft">
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// </copyright>
-//------------------------------------------------------------------------------
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
/*
*/
diff --git a/src/System.Drawing.Common/src/System/Drawing/Design/PropertyValueUIItem.cs b/src/System.Drawing.Common/src/System/Drawing/Design/PropertyValueUIItem.cs
index 298f7a73a1..9854a00310 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Design/PropertyValueUIItem.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Design/PropertyValueUIItem.cs
@@ -1,8 +1,6 @@
-//------------------------------------------------------------------------------
-// <copyright file="PropertyValueUIItem.cs" company="Microsoft">
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// </copyright>
-//------------------------------------------------------------------------------
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
/*
*/
diff --git a/src/System.Drawing.Common/src/System/Drawing/Design/PropertyValueUIItemInvokeHandler.cs b/src/System.Drawing.Common/src/System/Drawing/Design/PropertyValueUIItemInvokeHandler.cs
index 62a44bd40a..d70b799534 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Design/PropertyValueUIItemInvokeHandler.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Design/PropertyValueUIItemInvokeHandler.cs
@@ -1,8 +1,6 @@
-//------------------------------------------------------------------------------
-// <copyright file="PropertyValueUIItemInvokeHandler.cs" company="Microsoft">
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// </copyright>
-//------------------------------------------------------------------------------
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
/*
*/
diff --git a/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxComponentsCreatedEventArgs.cs b/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxComponentsCreatedEventArgs.cs
index f21ce8ba14..f79373e834 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxComponentsCreatedEventArgs.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxComponentsCreatedEventArgs.cs
@@ -1,8 +1,6 @@
-//------------------------------------------------------------------------------
-// <copyright file="ToolboxComponentsCreatedEventArgs.cs" company="Microsoft">
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// </copyright>
-//------------------------------------------------------------------------------
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
namespace System.Drawing.Design {
using System;
diff --git a/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxComponentsCreatedEventHandler.cs b/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxComponentsCreatedEventHandler.cs
index fa34f68446..183923cfe0 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxComponentsCreatedEventHandler.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxComponentsCreatedEventHandler.cs
@@ -1,8 +1,6 @@
-//------------------------------------------------------------------------------
-// <copyright file="ToolboxComponentsCreatedEventHandler.cs" company="Microsoft">
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// </copyright>
-//------------------------------------------------------------------------------
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
namespace System.Drawing.Design {
using System;
diff --git a/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxComponentsCreatingEventArgs.cs b/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxComponentsCreatingEventArgs.cs
index 12247e2ae5..6e2ccd8261 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxComponentsCreatingEventArgs.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxComponentsCreatingEventArgs.cs
@@ -1,8 +1,6 @@
-//------------------------------------------------------------------------------
-// <copyright file="ToolboxComponentsCreatingEventArgs.cs" company="Microsoft">
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// </copyright>
-//------------------------------------------------------------------------------
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
namespace System.Drawing.Design {
using System;
diff --git a/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxComponentsCreatingEventHandler.cs b/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxComponentsCreatingEventHandler.cs
index 6c5ddef5a6..573951d9b6 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxComponentsCreatingEventHandler.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxComponentsCreatingEventHandler.cs
@@ -1,8 +1,6 @@
-//------------------------------------------------------------------------------
-// <copyright file="ToolboxComponentsCreatingEventHandler.cs" company="Microsoft">
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// </copyright>
-//------------------------------------------------------------------------------
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
namespace System.Drawing.Design {
using System;
diff --git a/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxItem.cs b/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxItem.cs
index 8fde796ad4..ecac2d25bf 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxItem.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxItem.cs
@@ -1,11 +1,7 @@
-//------------------------------------------------------------------------------
-// <copyright file="ToolboxItem.cs" company="Microsoft">
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// </copyright>
-//------------------------------------------------------------------------------
-
-/*
- */
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
namespace System.Drawing.Design {
using System.Configuration.Assemblies;
using System.Runtime.InteropServices;
diff --git a/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxItemCollection.cs b/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxItemCollection.cs
index 3cfd526cb1..a076399bd2 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxItemCollection.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxItemCollection.cs
@@ -1,9 +1,7 @@
-// ------------------------------------------------------------------------------
-// <copyright file="ToolboxItemCollection.cs" company="Microsoft">
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// </copyright>
-// ------------------------------------------------------------------------------
-//
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
namespace System.Drawing.Design {
using System;
diff --git a/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxItemCreatorCallback.cs b/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxItemCreatorCallback.cs
index 077759427e..ef11d48406 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxItemCreatorCallback.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Design/ToolboxItemCreatorCallback.cs
@@ -1,11 +1,7 @@
-//------------------------------------------------------------------------------
-// <copyright file="ToolboxItemCreatorCallback.cs" company="Microsoft">
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// </copyright>
-//------------------------------------------------------------------------------
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
-/*
- */
namespace System.Drawing.Design {
/// <include file='doc\ToolboxItemCreatorCallback.uex' path='docs/doc[@for="ToolboxItemCreatorCallback"]/*' />
diff --git a/src/System.Drawing.Common/src/System/Drawing/Design/UITypeEditor.cs b/src/System.Drawing.Common/src/System/Drawing/Design/UITypeEditor.cs
index 4d1498c604..18defcfd05 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Design/UITypeEditor.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Design/UITypeEditor.cs
@@ -1,11 +1,7 @@
-//------------------------------------------------------------------------------
-// <copyright file="UITypeEditor.cs" company="Microsoft">
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// </copyright>
-//------------------------------------------------------------------------------
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
-/*
- */
namespace System.Drawing.Design {
using System.Runtime.InteropServices;
using System.ComponentModel;
diff --git a/src/System.Drawing.Common/src/System/Drawing/Design/UITypeEditorEditStyle.cs b/src/System.Drawing.Common/src/System/Drawing/Design/UITypeEditorEditStyle.cs
index 49a3f6cd80..8667cc902d 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Design/UITypeEditorEditStyle.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Design/UITypeEditorEditStyle.cs
@@ -1,11 +1,7 @@
-//------------------------------------------------------------------------------
-// <copyright file="UITypeEditorEditStyle.cs" company="Microsoft">
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// </copyright>
-//------------------------------------------------------------------------------
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
-/*
- */
namespace System.Drawing.Design {
using System.Diagnostics;
diff --git a/src/System.Drawing.Common/src/System/Drawing/Drawing2D/AdjustableArrowCap.Unix.cs b/src/System.Drawing.Common/src/System/Drawing/Drawing2D/AdjustableArrowCap.Unix.cs
index f265fe244a..318d4ccbe1 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Drawing2D/AdjustableArrowCap.Unix.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Drawing2D/AdjustableArrowCap.Unix.cs
@@ -8,7 +8,7 @@ namespace System.Drawing.Drawing2D
{
public sealed partial class AdjustableArrowCap : CustomLineCap
{
- public override object Clone()
+ internal override object CoreClone()
{
IntPtr clonedCap;
int status = SafeNativeMethods.Gdip.GdipCloneCustomLineCap(new HandleRef(this, nativeCap), out clonedCap);
diff --git a/src/System.Drawing.Common/src/System/Drawing/Drawing2D/CustomLineCap.cs b/src/System.Drawing.Common/src/System/Drawing/Drawing2D/CustomLineCap.cs
index a9c75acd0f..f449be7b39 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Drawing2D/CustomLineCap.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Drawing2D/CustomLineCap.cs
@@ -74,7 +74,12 @@ namespace System.Drawing.Drawing2D
~CustomLineCap() => Dispose(false);
- public virtual object Clone()
+ public object Clone()
+ {
+ return CoreClone();
+ }
+
+ internal virtual object CoreClone()
{
IntPtr clonedCap;
int status = SafeNativeMethods.Gdip.GdipCloneCustomLineCap(new HandleRef(this, nativeCap), out clonedCap);
diff --git a/src/System.Drawing.Common/src/System/Drawing/Drawing2D/GraphicsPath.Unix.cs b/src/System.Drawing.Common/src/System/Drawing/Drawing2D/GraphicsPath.Unix.cs
index 1260c98a5c..bcc999cbe6 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Drawing2D/GraphicsPath.Unix.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Drawing2D/GraphicsPath.Unix.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information.
//
// System.Drawing.Drawing2D.GraphicsPath.cs
//
diff --git a/src/System.Drawing.Common/src/System/Drawing/Font.Unix.cs b/src/System.Drawing.Common/src/System/Drawing/Font.Unix.cs
index 56ff789861..322b8f129b 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Font.Unix.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Font.Unix.cs
@@ -40,12 +40,11 @@ using System.ComponentModel;
namespace System.Drawing
{
- [Serializable]
#if !NETCORE
[Editor ("System.Drawing.Design.FontEditor, " + Consts.AssemblySystem_Drawing_Design, typeof (System.Drawing.Design.UITypeEditor))]
[TypeConverter (typeof (FontConverter))]
#endif
- public sealed class Font : MarshalByRefObject, ISerializable, ICloneable, IDisposable
+ public sealed partial class Font : MarshalByRefObject, ISerializable, ICloneable, IDisposable
{
private IntPtr fontObject = IntPtr.Zero;
private string systemFontName;
@@ -79,29 +78,6 @@ namespace System.Drawing
SafeNativeMethods.Gdip.CheckStatus(status);
}
- private Font(SerializationInfo info, StreamingContext context)
- {
- string name;
- float size;
- FontStyle style;
- GraphicsUnit unit;
-
- name = (string)info.GetValue("Name", typeof(string));
- size = (float)info.GetValue("Size", typeof(float));
- style = (FontStyle)info.GetValue("Style", typeof(FontStyle));
- unit = (GraphicsUnit)info.GetValue("Unit", typeof(GraphicsUnit));
-
- CreateFont(name, size, style, unit, DefaultCharSet, false);
- }
-
- void ISerializable.GetObjectData(SerializationInfo si, StreamingContext context)
- {
- si.AddValue("Name", Name);
- si.AddValue("Size", Size);
- si.AddValue("Style", Style);
- si.AddValue("Unit", Unit);
- }
-
~Font()
{
Dispose();
diff --git a/src/System.Drawing.Common/src/System/Drawing/Graphics.Unix.cs b/src/System.Drawing.Common/src/System/Drawing/Graphics.Unix.cs
index 1392545af8..c7d8c1caf5 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Graphics.Unix.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Graphics.Unix.cs
@@ -1777,7 +1777,7 @@ namespace System.Drawing
public Region[] MeasureCharacterRanges(string text, Font font, RectangleF layoutRect, StringFormat stringFormat)
{
if ((text == null) || (text.Length == 0))
- return new Region[0];
+ return Array.Empty<Region>();
if (font == null)
throw new ArgumentNullException("font");
@@ -1787,7 +1787,7 @@ namespace System.Drawing
int regcount = stringFormat.GetMeasurableCharacterRangeCount();
if (regcount == 0)
- return new Region[0];
+ return Array.Empty<Region>();
IntPtr[] native_regions = new IntPtr[regcount];
Region[] regions = new Region[regcount];
diff --git a/src/System.Drawing.Common/src/System/Drawing/Icon.Unix.cs b/src/System.Drawing.Common/src/System/Drawing/Icon.Unix.cs
index 119dcaef77..f6dc345738 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Icon.Unix.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Icon.Unix.cs
@@ -466,7 +466,7 @@ namespace System.Drawing
IconImage ii = new IconImage();
ii.iconHeader = bih;
- ii.iconColors = new uint[0]; // no palette
+ ii.iconColors = Array.Empty<uint>(); // no palette
int xor_size = (((bih.biBitCount * bitmap.Width + 31) & ~31) >> 3) * bitmap.Height;
ii.iconXOR = new byte[xor_size];
int p = 0;
diff --git a/src/System.Drawing.Common/src/System/Drawing/Image.Unix.cs b/src/System.Drawing.Common/src/System/Drawing/Image.Unix.cs
index 5771f95371..45bd3b1fce 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Image.Unix.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Image.Unix.cs
@@ -44,7 +44,6 @@ using System.Reflection;
namespace System.Drawing
{
- [Serializable]
#if !NETCORE
[Editor ("System.Drawing.Design.ImageEditor, " + Consts.AssemblySystem_Drawing_Design, typeof (System.Drawing.Design.UITypeEditor))]
[TypeConverter (typeof(ImageConverter))]
@@ -61,45 +60,6 @@ namespace System.Drawing
{
}
-#if NETCORE
- protected Image(SerializationInfo info, StreamingContext context)
-#else
- internal Image (SerializationInfo info, StreamingContext context)
-#endif
- {
- foreach (SerializationEntry serEnum in info)
- {
- if (String.Compare(serEnum.Name, "Data", true) == 0)
- {
- byte[] bytes = (byte[])serEnum.Value;
-
- if (bytes != null)
- {
- MemoryStream ms = new MemoryStream(bytes);
- nativeImage = InitFromStream(ms);
- }
- }
- }
- }
-
- // FIXME - find out how metafiles (another decoder-only codec) are handled
- void ISerializable.GetObjectData(SerializationInfo si, StreamingContext context)
- {
- using (MemoryStream ms = new MemoryStream())
- {
- // Icon is a decoder-only codec
- if (RawFormat.Equals(ImageFormat.Icon))
- {
- Save(ms, ImageFormat.Png);
- }
- else
- {
- Save(ms, RawFormat);
- }
- si.AddValue("Data", ms.ToArray());
- }
- }
-
// public methods
// static
public static Image FromFile(string filename)
diff --git a/src/System.Drawing.Common/src/System/Drawing/Image.Windows.cs b/src/System.Drawing.Common/src/System/Drawing/Image.Windows.cs
index c0b8f1a69c..1e4ed87891 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Image.Windows.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Image.Windows.cs
@@ -866,7 +866,7 @@ namespace System.Drawing
Debug.Assert(count >= 0, "FrameDimensionsList returns bad count");
if (count <= 0)
{
- return new Guid[0];
+ return Array.Empty<Guid>();
}
int size = (int)Marshal.SizeOf(typeof(Guid));
@@ -1059,7 +1059,7 @@ namespace System.Drawing
throw SafeNativeMethods.Gdip.StatusException(status);
if (size == 0 || count == 0)
- return new PropertyItem[0];
+ return Array.Empty<PropertyItem>();
IntPtr propdata = Marshal.AllocHGlobal(size);
try
diff --git a/src/System.IO.FileSystem/src/System/IO/FileSystemInfo.Win32.cs b/src/System.Drawing.Common/src/System/Drawing/Internal/ISystemEventTracker.cs
index da72a66f64..9e2f7b9c2a 100644
--- a/src/System.IO.FileSystem/src/System/IO/FileSystemInfo.Win32.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Internal/ISystemEventTracker.cs
@@ -2,13 +2,10 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-namespace System.IO
+namespace System.Drawing.Internal
{
- partial class FileSystemInfo
+ internal interface ISystemColorTracker
{
- internal void Invalidate()
- {
- _dataInitialized = -1;
- }
+ void OnSystemColorChanged();
}
}
diff --git a/src/System.Drawing.Common/src/System/Drawing/Internal/SystemColorTracker.cs b/src/System.Drawing.Common/src/System/Drawing/Internal/SystemColorTracker.cs
new file mode 100644
index 0000000000..3353700afb
--- /dev/null
+++ b/src/System.Drawing.Common/src/System/Drawing/Internal/SystemColorTracker.cs
@@ -0,0 +1,152 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+using Microsoft.Win32;
+
+namespace System.Drawing.Internal
+{
+ // Keeps track of objects that need to be notified of system color change events.
+ // Mostly this means maintaining a list of weak references.
+ internal static class SystemColorTracker
+ {
+ // when I tried the self host, it went over 500 but never over 1000.
+ private static int INITIAL_SIZE = 200;
+ // If it gets this big, I seriously miscalculated the performance of this object.
+ private static int WARNING_SIZE = 100000;
+ private static float EXPAND_THRESHOLD = 0.75f;
+ private static int EXPAND_FACTOR = 2;
+
+ private static WeakReference[] list = new WeakReference[INITIAL_SIZE];
+ private static int count = 0;
+ private static bool addedTracker;
+ private static object lockObject = new object();
+
+ internal static void Add(ISystemColorTracker obj)
+ {
+ lock (lockObject)
+ {
+ Debug.Assert(list != null, "List is null");
+ Debug.Assert(list.Length > 0, "INITIAL_SIZE was initialized after list");
+
+ if (list.Length == count)
+ {
+ GarbageCollectList();
+ }
+
+ if (!addedTracker)
+ {
+ addedTracker = true;
+ SystemEvents.UserPreferenceChanged += new UserPreferenceChangedEventHandler(OnUserPreferenceChanged);
+ }
+
+ // Strictly speaking, we should grab a lock on this class. But since the chances
+ // of a problem are so low, the consequences so minimal (something will get accidentally dropped
+ // from the list), and the performance of locking so lousy, we'll risk it.
+ int index = count;
+ count++;
+
+ // COM+ takes forever to Finalize() weak references, so it pays to reuse them.
+ if (list[index] == null)
+ list[index] = new WeakReference(obj);
+ else
+ {
+ Debug.Assert(list[index].Target == null, "Trying to reuse a weak reference that isn't broken yet: list[" + index + "], length =" + list.Length);
+ list[index].Target = obj;
+ }
+ }
+ }
+
+ private static void CleanOutBrokenLinks()
+ {
+ // Partition the list -- valid references in the low indices, broken references in the high indices.
+ // This is taken straight out of Sedgewick (p. 118 on quicksort).
+
+ // Basic idea is to find a broken reference on the left side of the list, and swap it with
+ // a valid reference on the right
+ int right = list.Length - 1;
+ int left = 0;
+
+ int length = list.Length;
+
+ // Loop invariant: everything to the left of "left" is a valid reference,
+ // and anything to the right of "right" is broken.
+ for (;;)
+ {
+ while (left < length && list[left].Target != null)
+ left++;
+ while (right >= 0 && list[right].Target == null)
+ right--;
+
+ if (left >= right)
+ {
+ count = left;
+ break;
+ }
+
+ WeakReference temp = list[left];
+ list[left] = list[right];
+ list[right] = temp;
+
+ left++;
+ right--;
+ }
+
+ Debug.Assert(count >= 0 && count <= list.Length, "count not a legal index into list");
+
+#if DEBUG
+ // Check loop invariant.
+
+ // We'd like to assert that any index < count contains a valid pointer,
+ // but since garbage collection can happen at any time, it may have been broken
+ // after we partitioned it.
+ //
+ // for (int i = 0; i < count; i++) {
+ // Debug.Assert(list[i].Target != null, "Null found on the left side of the list");
+ // }
+
+ for (int i = count; i < list.Length; i++)
+ {
+ Debug.Assert(list[i].Target == null, "Partitioning didn't work");
+ }
+#endif
+ }
+
+ private static void GarbageCollectList()
+ {
+ CleanOutBrokenLinks();
+
+ if (count / (float)list.Length > EXPAND_THRESHOLD)
+ {
+ WeakReference[] newList = new WeakReference[list.Length * EXPAND_FACTOR];
+ list.CopyTo(newList, 0);
+ list = newList;
+
+ Debug.Assert(list.Length < WARNING_SIZE, "SystemColorTracker is using way more memory than expected.");
+ }
+ }
+
+ private static void OnUserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e)
+ {
+
+ // Update pens and brushes
+ if (e.Category == UserPreferenceCategory.Color)
+ {
+ for (int i = 0; i < count; i++)
+ {
+ Debug.Assert(list[i] != null, "null value in active part of list");
+ ISystemColorTracker tracker = (ISystemColorTracker)list[i].Target;
+ if (tracker != null)
+ {
+ // If object still around
+ tracker.OnSystemColorChanged();
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/System.Drawing.Common/src/System/Drawing/Pen.cs b/src/System.Drawing.Common/src/System/Drawing/Pen.cs
index 16cc0071da..bdafdab046 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Pen.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Pen.cs
@@ -15,6 +15,9 @@ namespace System.Drawing
/// Defines an object used to draw lines and curves.
/// </summary>
public sealed partial class Pen : MarshalByRefObject, ICloneable, IDisposable
+#if FEATURE_SYSTEM_EVENTS
+ , ISystemColorTracker
+#endif
{
#if FINALIZATION_WATCH
private string allocationSite = Graphics.GetAllocationStack();
@@ -60,6 +63,13 @@ namespace System.Drawing
SafeNativeMethods.Gdip.CheckStatus(status);
SetNativePen(pen);
+
+#if FEATURE_SYSTEM_EVENTS
+ if (ColorUtil.IsSystemColor(_color))
+ {
+ SystemColorTracker.Add(this);
+ }
+#endif
}
/// <summary>
@@ -570,6 +580,15 @@ namespace System.Drawing
Color oldColor = _color;
_color = value;
InternalSetColor(value);
+
+#if FEATURE_SYSTEM_EVENTS
+ // NOTE: We never remove pens from the active list, so if someone is
+ // changing their pen colors a lot, this could be a problem.
+ if (ColorUtil.IsSystemColor(value) && !ColorUtil.IsSystemColor(oldColor))
+ {
+ SystemColorTracker.Add(this);
+ }
+#endif
}
}
}
@@ -748,7 +767,7 @@ namespace System.Drawing
}
else if (DashStyle == DashStyle.Solid)
{
- pattern = new float[0];
+ pattern = Array.Empty<float>();
}
else
{
@@ -838,5 +857,15 @@ namespace System.Drawing
SafeNativeMethods.Gdip.CheckStatus(status);
}
}
+
+#if FEATURE_SYSTEM_EVENTS
+ void ISystemColorTracker.OnSystemColorChanged()
+ {
+ if (NativePen != IntPtr.Zero)
+ {
+ InternalSetColor(_color);
+ }
+ }
+#endif
}
}
diff --git a/src/System.Drawing.Common/src/System/Drawing/PointConverter.cs b/src/System.Drawing.Common/src/System/Drawing/PointConverter.cs
index 5fad16e358..016f25933b 100644
--- a/src/System.Drawing.Common/src/System/Drawing/PointConverter.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/PointConverter.cs
@@ -1,11 +1,7 @@
-//------------------------------------------------------------------------------
-// <copyright file="PointConverter.cs" company="Microsoft">
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// </copyright>
-//------------------------------------------------------------------------------
-
-/*
- */
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
namespace System.Drawing {
using System.Runtime.Serialization.Formatters;
using System.Runtime.InteropServices;
diff --git a/src/System.Drawing.Common/src/System/Drawing/Printing/PrinterSettings.Windows.cs b/src/System.Drawing.Common/src/System/Drawing/Printing/PrinterSettings.Windows.cs
index ccc03bea84..8e1084b911 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Printing/PrinterSettings.Windows.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Printing/PrinterSettings.Windows.cs
@@ -1079,7 +1079,7 @@ namespace System.Drawing.Printing
int count = FastDeviceCapabilities(SafeNativeMethods.DC_PAPERNAMES, IntPtr.Zero, -1, printerName);
if (count == -1)
- return new PaperSize[0];
+ return Array.Empty<PaperSize>();
int stringSize = Marshal.SystemDefaultCharSize * 64;
IntPtr namesBuffer = Marshal.AllocCoTaskMem(checked(stringSize * count));
FastDeviceCapabilities(SafeNativeMethods.DC_PAPERNAMES, namesBuffer, -1, printerName);
@@ -1123,7 +1123,7 @@ namespace System.Drawing.Printing
int count = FastDeviceCapabilities(SafeNativeMethods.DC_BINNAMES, IntPtr.Zero, -1, printerName);
if (count == -1)
- return new PaperSource[0];
+ return Array.Empty<PaperSource>();
// Contrary to documentation, DeviceCapabilities returns char[count, 24],
// not char[count][24]
diff --git a/src/System.Drawing.Common/src/System/Drawing/Printing/PrintingPermission.cs b/src/System.Drawing.Common/src/System/Drawing/Printing/PrintingPermission.cs
deleted file mode 100644
index f20f1b2a93..0000000000
--- a/src/System.Drawing.Common/src/System/Drawing/Printing/PrintingPermission.cs
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright (c) 2000 Microsoft Corporation. All Rights Reserved.
- * Microsoft Confidential.
- */
-
-namespace System.Drawing.Printing {
- using System;
- using System.Security;
- using System.Security.Permissions;
- using System.IO;
- using System.Runtime.Serialization;
- using System.Reflection;
- using System.Collections;
- using System.Globalization;
- using System.Diagnostics.CodeAnalysis;
-
- /// <include file='doc\PrintingPermission.uex' path='docs/doc[@for="PrintingPermission"]/*' />
- /// <devdoc>
- /// <para> Controls the ability to use the printer. This class cannot be inherited.</para>
- /// </devdoc>
- [Serializable]
- public sealed class PrintingPermission : CodeAccessPermission, IUnrestrictedPermission {
- private PrintingPermissionLevel printingLevel;
-
- /// <include file='doc\PrintingPermission.uex' path='docs/doc[@for="PrintingPermission.PrintingPermission"]/*' />
- /// <devdoc>
- /// <para>Initializes a new instance of the PrintingPermission class with either fully restricted
- /// or unrestricted access, as specified.</para>
- /// </devdoc>
- public PrintingPermission(PermissionState state) {
- if (state == PermissionState.Unrestricted) {
- printingLevel = PrintingPermissionLevel.AllPrinting;
- }
- else if (state == PermissionState.None) {
- printingLevel = PrintingPermissionLevel.NoPrinting;
- }
- else {
- throw new ArgumentException(SR.Format(SR.InvalidPermissionState));
- }
- }
-
- /// <include file='doc\PrintingPermission.uex' path='docs/doc[@for="PrintingPermission.PrintingPermission1"]/*' />
- /// <devdoc>
- /// <para>[To be supplied.]</para>
- /// </devdoc>
- public PrintingPermission(PrintingPermissionLevel printingLevel) {
- VerifyPrintingLevel(printingLevel);
-
- this.printingLevel = printingLevel;
- }
-
- /// <include file='doc\PrintingPermission.uex' path='docs/doc[@for="PrintingPermission.Level"]/*' />
- /// <devdoc>
- /// <para>[To be supplied.]</para>
- /// </devdoc>
- public PrintingPermissionLevel Level {
- get {
- return printingLevel;
- }
-
- set {
- VerifyPrintingLevel(value);
- printingLevel = value;
- }
- }
-
- private static void VerifyPrintingLevel(PrintingPermissionLevel level) {
- if (level < PrintingPermissionLevel.NoPrinting || level > PrintingPermissionLevel.AllPrinting) {
- throw new ArgumentException(SR.Format(SR.InvalidPermissionLevel));
- }
- }
-
-
- //------------------------------------------------------
- //
- // CODEACCESSPERMISSION IMPLEMENTATION
- //
- //------------------------------------------------------
-
- /// <include file='doc\PrintingPermission.uex' path='docs/doc[@for="PrintingPermission.IsUnrestricted"]/*' />
- /// <devdoc>
- /// <para> Gets a
- /// value indicating whether permission is unrestricted.</para>
- /// </devdoc>
- public bool IsUnrestricted() {
- return printingLevel == PrintingPermissionLevel.AllPrinting;
- }
-
- //------------------------------------------------------
- //
- // IPERMISSION IMPLEMENTATION
- //
- //------------------------------------------------------
-
- /// <include file='doc\PrintingPermission.uex' path='docs/doc[@for="PrintingPermission.IsSubsetOf"]/*' />
- /// <devdoc>
- /// <para>Determines whether the current permission object is a subset of
- /// the specified permission.</para>
- /// </devdoc>
- public override bool IsSubsetOf(IPermission target) {
- if (target == null) {
- return printingLevel == PrintingPermissionLevel.NoPrinting;
- }
-
- PrintingPermission operand = target as PrintingPermission;
- if(operand == null) {
- throw new ArgumentException(SR.Format(SR.TargetNotPrintingPermission));
- }
- return this.printingLevel <= operand.printingLevel;
- }
-
- /// <include file='doc\PrintingPermission.uex' path='docs/doc[@for="PrintingPermission.Intersect"]/*' />
- /// <devdoc>
- /// <para>Creates and returns a permission that is the intersection of the current
- /// permission object and a target permission object.</para>
- /// </devdoc>
- public override IPermission Intersect(IPermission target) {
- if (target == null) {
- return null;
- }
-
- PrintingPermission operand = target as PrintingPermission;
- if(operand == null) {
- throw new ArgumentException(SR.Format(SR.TargetNotPrintingPermission));
- }
- PrintingPermissionLevel isectLevels = printingLevel < operand.printingLevel ? printingLevel : operand.printingLevel;
- if (isectLevels == PrintingPermissionLevel.NoPrinting)
- return null;
- else
- return new PrintingPermission(isectLevels);
- }
-
- /// <include file='doc\PrintingPermission.uex' path='docs/doc[@for="PrintingPermission.Union"]/*' />
- /// <devdoc>
- /// <para>Creates a permission that is the union of the permission object
- /// and the target parameter permission object.</para>
- /// </devdoc>
- public override IPermission Union(IPermission target) {
- if (target == null) {
- return this.Copy();
- }
-
- PrintingPermission operand = target as PrintingPermission;
- if(operand == null) {
- throw new ArgumentException(SR.Format(SR.TargetNotPrintingPermission));
- }
- PrintingPermissionLevel isectLevels = printingLevel > operand.printingLevel ? printingLevel : operand.printingLevel;
- if (isectLevels == PrintingPermissionLevel.NoPrinting)
- return null;
- else
- return new PrintingPermission(isectLevels);
- }
-
- /// <include file='doc\PrintingPermission.uex' path='docs/doc[@for="PrintingPermission.Copy"]/*' />
- /// <devdoc>
- /// <para>Creates and returns an identical copy of the current permission
- /// object.</para>
- /// </devdoc>
- [SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity")]
- public override IPermission Copy() {
- return new PrintingPermission(this.printingLevel);
- }
-
-
- /// <include file='doc\PrintingPermission.uex' path='docs/doc[@for="PrintingPermission.ToXml"]/*' />
- /// <devdoc>
- /// <para>Creates an XML encoding of the security object and its current
- /// state.</para>
- /// </devdoc>
- public override SecurityElement ToXml() {
- SecurityElement securityElement = new SecurityElement("IPermission");
-
- securityElement.AddAttribute("class", this.GetType().FullName + ", " + this.GetType().Module.Assembly.FullName.Replace('\"', '\''));
- securityElement.AddAttribute("version", "1");
- if (!IsUnrestricted()) {
- securityElement.AddAttribute("Level", Enum.GetName(typeof(PrintingPermissionLevel), printingLevel));
- }
- else {
- securityElement.AddAttribute("Unrestricted", "true");
- }
- return securityElement;
- }
-
- /// <include file='doc\PrintingPermission.uex' path='docs/doc[@for="PrintingPermission.FromXml"]/*' />
- /// <devdoc>
- /// <para>Reconstructs a security object with a specified state from an XML
- /// encoding.</para>
- /// </devdoc>
- [SuppressMessage("Microsoft.Performance", "CA1808:AvoidCallsThatBoxValueTypes")]
- public override void FromXml(SecurityElement esd) {
- if (esd == null) {
- throw new ArgumentNullException("esd");
- }
-
- String className = esd.Attribute("class");
-
- if (className == null || className.IndexOf(this.GetType().FullName) == -1) {
- throw new ArgumentException(SR.Format(SR.InvalidClassName));
- }
-
- String unrestricted = esd.Attribute("Unrestricted");
-
- if (unrestricted != null && String.Equals(unrestricted, "true", StringComparison.OrdinalIgnoreCase))
- {
- printingLevel = PrintingPermissionLevel.AllPrinting;
- return;
- }
-
- printingLevel = PrintingPermissionLevel.NoPrinting;
-
- String printing = esd.Attribute("Level");
-
- if (printing != null)
- {
- printingLevel = (PrintingPermissionLevel)Enum.Parse(typeof(PrintingPermissionLevel), printing);
- }
- }
- }
-}
-
diff --git a/src/System.Drawing.Common/src/System/Drawing/Printing/PrintingPermissionAttribute.cs b/src/System.Drawing.Common/src/System/Drawing/Printing/PrintingPermissionAttribute.cs
deleted file mode 100644
index bef5b5502b..0000000000
--- a/src/System.Drawing.Common/src/System/Drawing/Printing/PrintingPermissionAttribute.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2000 Microsoft Corporation. All Rights Reserved.
- * Microsoft Confidential.
- */
-
-namespace System.Drawing.Printing {
- using System;
- using System.Security;
- using System.Security.Permissions;
- using System.IO;
- using System.Runtime.Serialization;
- using System.Reflection;
- using System.Collections;
- using System.Diagnostics.CodeAnalysis;
-
- /// <include file='doc\PrintingPermissionAttribute.uex' path='docs/doc[@for="PrintingPermissionAttribute"]/*' />
- [AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
- public sealed class PrintingPermissionAttribute : CodeAccessSecurityAttribute {
- PrintingPermissionLevel level;
-
- /// <include file='doc\PrintingPermissionAttribute.uex' path='docs/doc[@for="PrintingPermissionAttribute.PrintingPermissionAttribute"]/*' />
- public PrintingPermissionAttribute(SecurityAction action) : base(action) {
- }
-
-
- /// <include file='doc\PrintingPermissionAttribute.uex' path='docs/doc[@for="PrintingPermissionAttribute.Level"]/*' />
- public PrintingPermissionLevel Level {
- get {
- return level;
- }
-
- set {
- if (value < PrintingPermissionLevel.NoPrinting || value > PrintingPermissionLevel.AllPrinting) {
- throw new ArgumentException(SR.Format(SR.PrintingPermissionAttributeInvalidPermissionLevel), "value");
- }
- level = value;
- }
- }
-
- /// <include file='doc\PrintingPermissionAttribute.uex' path='docs/doc[@for="PrintingPermissionAttribute.CreatePermission"]/*' />
- [SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity")]
- public override IPermission CreatePermission() {
- if (Unrestricted) {
- return new PrintingPermission(PermissionState.Unrestricted);
- }
- else {
- return new PrintingPermission(level);
- }
- }
- }
-}
diff --git a/src/System.Drawing.Common/src/System/Drawing/Printing/PrintingPermissionLevel.cs b/src/System.Drawing.Common/src/System/Drawing/Printing/PrintingPermissionLevel.cs
deleted file mode 100644
index 971074cec4..0000000000
--- a/src/System.Drawing.Common/src/System/Drawing/Printing/PrintingPermissionLevel.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * PrintingPermission.cool
- *
- * Copyright (c) 2000 Microsoft Corporation. All Rights Reserved.
- * Microsoft Confidential.
- */
-
-namespace System.Drawing.Printing {
- using System;
-
- /// <include file='doc\PrintingPermissionLevel.uex' path='docs/doc[@for="PrintingPermissionLevel"]/*' />
- /// <devdoc>
- /// <para>Specifies the type of printing that code is allowed to do.</para>
- /// </devdoc>
- [Serializable]
- public enum PrintingPermissionLevel {
- /**
- * No printing use allowed at all.
- */
- /// <include file='doc\PrintingPermissionLevel.uex' path='docs/doc[@for="PrintingPermissionLevel.NoPrinting"]/*' />
- /// <devdoc>
- /// <para>Users have no ability to use any printers.</para>
- /// </devdoc>
- NoPrinting = 0x0,
-
- /**
- * Only allow safe printing use.
- */
- /// <include file='doc\PrintingPermissionLevel.uex' path='docs/doc[@for="PrintingPermissionLevel.SafePrinting"]/*' />
- /// <devdoc>
- /// <para>Users can only use safe printing to print from a restricted dialog box.</para>
- /// </devdoc>
- SafePrinting = 0x01,
-
- /**
- * Use of the default printer allowed.
- */
- /// <include file='doc\PrintingPermissionLevel.uex' path='docs/doc[@for="PrintingPermissionLevel.DefaultPrinting"]/*' />
- /// <devdoc>
- /// <para>Users can print programmically to the default printer along with safe printing through
- /// a less restricted dialog box.</para>
- /// </devdoc>
- DefaultPrinting = 0x02,
-
- /**
- * All windows and all event may be used.
- */
- /// <include file='doc\PrintingPermissionLevel.uex' path='docs/doc[@for="PrintingPermissionLevel.AllPrinting"]/*' />
- /// <devdoc>
- /// <para>
- /// Users have full access to all printers on the network.
- /// </para>
- /// </devdoc>
- AllPrinting = 0x03,
-
- }
-}
-
diff --git a/src/System.Drawing.Common/src/System/Drawing/RectangleConverter.cs b/src/System.Drawing.Common/src/System/Drawing/RectangleConverter.cs
index 32746ca795..d2d9790070 100644
--- a/src/System.Drawing.Common/src/System/Drawing/RectangleConverter.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/RectangleConverter.cs
@@ -1,11 +1,7 @@
-//------------------------------------------------------------------------------
-// <copyright file="RectangleConverter.cs" company="Microsoft">
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// </copyright>
-//------------------------------------------------------------------------------
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
-/*
- */
namespace System.Drawing {
using System.Runtime.Serialization.Formatters;
using System.Runtime.InteropServices;
diff --git a/src/System.Drawing.Common/src/System/Drawing/SizeConverter.cs b/src/System.Drawing.Common/src/System/Drawing/SizeConverter.cs
index ba37bc593d..de0ce315c7 100644
--- a/src/System.Drawing.Common/src/System/Drawing/SizeConverter.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/SizeConverter.cs
@@ -1,11 +1,7 @@
-//------------------------------------------------------------------------------
-// <copyright file="SizeConverter.cs" company="Microsoft">
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// </copyright>
-//------------------------------------------------------------------------------
-
-/*
- */
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
namespace System.Drawing {
using System.Runtime.Serialization.Formatters;
using System.Runtime.InteropServices;
diff --git a/src/System.Drawing.Common/src/System/Drawing/SolidBrush.cs b/src/System.Drawing.Common/src/System/Drawing/SolidBrush.cs
index 4922d7c1dd..6c3e1365aa 100644
--- a/src/System.Drawing.Common/src/System/Drawing/SolidBrush.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/SolidBrush.cs
@@ -7,7 +7,14 @@ using System.Runtime.InteropServices;
namespace System.Drawing
{
+#if FEATURE_SYSTEM_EVENTS
+ using System.Drawing.Internal;
+#endif
+
public sealed class SolidBrush : Brush
+#if FEATURE_SYSTEM_EVENTS
+ , ISystemColorTracker
+#endif
{
// GDI+ doesn't understand system colors, so we need to cache the value here.
private Color _color = Color.Empty;
@@ -22,6 +29,13 @@ namespace System.Drawing
SafeNativeMethods.Gdip.CheckStatus(status);
SetNativeBrushInternal(nativeBrush);
+
+#if FEATURE_SYSTEM_EVENTS
+ if (ColorUtil.IsSystemColor(_color))
+ {
+ SystemColorTracker.Add(this);
+ }
+#endif
}
internal SolidBrush(Color color, bool immutable) : this(color)
@@ -87,6 +101,15 @@ namespace System.Drawing
{
Color oldColor = _color;
InternalSetColor(value);
+
+#if FEATURE_SYSTEM_EVENTS
+ // NOTE: We never remove brushes from the active list, so if someone is
+ // changing their brush colors a lot, this could be a problem.
+ if (ColorUtil.IsSystemColor(value) && !ColorUtil.IsSystemColor(oldColor))
+ {
+ SystemColorTracker.Add(this);
+ }
+#endif
}
}
}
@@ -99,6 +122,16 @@ namespace System.Drawing
_color = value;
}
+
+#if FEATURE_SYSTEM_EVENTS
+ void ISystemColorTracker.OnSystemColorChanged()
+ {
+ if (NativeBrush != IntPtr.Zero)
+ {
+ InternalSetColor(_color);
+ }
+ }
+#endif
}
}
diff --git a/src/System.Drawing.Common/src/System/Drawing/SystemIcons.Unix.cs b/src/System.Drawing.Common/src/System/Drawing/SystemIcons.Unix.cs
index 2516f81bfa..b9108ef632 100644
--- a/src/System.Drawing.Common/src/System/Drawing/SystemIcons.Unix.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/SystemIcons.Unix.cs
@@ -36,7 +36,7 @@ namespace System.Drawing
// LAME: I don't see why the "old" (win 2.x) names were exposed in the fx :|
- public sealed class SystemIcons
+ public static class SystemIcons
{
static Icon[] icons;
@@ -70,10 +70,6 @@ namespace System.Drawing
#endif
}
- private SystemIcons()
- {
- }
-
// note: same as WinLogo (for Mono)
public static Icon Application
{
diff --git a/src/System.Drawing.Common/tests/BitmapTests.cs b/src/System.Drawing.Common/tests/BitmapTests.cs
index fee3341b55..51af0ba368 100644
--- a/src/System.Drawing.Common/tests/BitmapTests.cs
+++ b/src/System.Drawing.Common/tests/BitmapTests.cs
@@ -322,7 +322,7 @@ namespace System.Drawing.Tests
[ConditionalFact(Helpers.GdiplusIsAvailable)]
public void Ctor_NullGraphics_ThrowsArgumentNullException()
{
- AssertExtensions.Throws<ArgumentNullException>("g", "Value of 'null' is not valid for 'g'.", () => new Bitmap(1, 1, null));
+ AssertExtensions.Throws<ArgumentNullException>("g", null, () => new Bitmap(1, 1, null));
}
[ConditionalFact(Helpers.GdiplusIsAvailable)]
diff --git a/src/System.Drawing.Common/tests/FontFamilyTests.cs b/src/System.Drawing.Common/tests/FontFamilyTests.cs
index ad60729124..71c9f0063a 100644
--- a/src/System.Drawing.Common/tests/FontFamilyTests.cs
+++ b/src/System.Drawing.Common/tests/FontFamilyTests.cs
@@ -3,7 +3,6 @@
using System.Collections.Generic;
using System.Drawing.Text;
-using System.Globalization;
using Xunit;
namespace System.Drawing.Tests
@@ -57,7 +56,6 @@ namespace System.Drawing.Tests
[ActiveIssue(20884, TestPlatforms.AnyUnix)]
[ConditionalTheory(Helpers.GdiplusIsAvailable)]
[InlineData(null)]
- [InlineData("")]
[InlineData("NoSuchFont")]
[InlineData("Serif")]
public void Ctor_NoSuchFontName_ThrowsArgumentException(string name)
diff --git a/src/System.Drawing.Common/tests/FontTests.cs b/src/System.Drawing.Common/tests/FontTests.cs
index e742cedcf1..da541f5297 100644
--- a/src/System.Drawing.Common/tests/FontTests.cs
+++ b/src/System.Drawing.Common/tests/FontTests.cs
@@ -302,20 +302,6 @@ namespace System.Drawing.Tests
}
}
- [ActiveIssue(20884, TestPlatforms.AnyUnix)]
- [ConditionalTheory(Helpers.GdiplusIsAvailable)]
- [InlineData(null)]
- [InlineData("")]
- [InlineData("NoSuchFont")]
- [InlineData("Serif")]
- public void Ctor_NoSuchFamilyName_SetsFamilyToGenericSansSerif(string familyName)
- {
- using (var font = new Font(familyName, 10))
- {
- Assert.Equal("Microsoft Sans Serif", font.FontFamily.Name);
- }
- }
-
[ConditionalFact(Helpers.GdiplusIsAvailable)]
public void Ctor_NullFont_ThrowsNullReferenceException()
{
diff --git a/src/System.Drawing.Common/tests/Imaging/EncoderParameterTests.cs b/src/System.Drawing.Common/tests/Imaging/EncoderParameterTests.cs
index b59d2b309e..03893ce999 100644
--- a/src/System.Drawing.Common/tests/Imaging/EncoderParameterTests.cs
+++ b/src/System.Drawing.Common/tests/Imaging/EncoderParameterTests.cs
@@ -318,7 +318,7 @@ namespace System.Drawing.Imaging.Tests
[InlineData(int.MinValue)]
public void Ctor_Encoder_NegativeNumberOfValues_Type_Value_OutOfMemoryException(int numberOfValues)
{
- if (numberOfValues == -1 && PlatformDetection.IsUbuntu1710) // [ActiveIssue(24274)]
+ if (numberOfValues == -1 && PlatformDetection.IsUbuntu1710OrHigher) // [ActiveIssue(24274)]
return;
IntPtr anyValue = IntPtr.Zero;
diff --git a/src/System.Drawing.Common/tests/Imaging/MetafileTests.cs b/src/System.Drawing.Common/tests/Imaging/MetafileTests.cs
index 443a4df835..283784291a 100644
--- a/src/System.Drawing.Common/tests/Imaging/MetafileTests.cs
+++ b/src/System.Drawing.Common/tests/Imaging/MetafileTests.cs
@@ -90,7 +90,7 @@ namespace System.Drawing.Imaging.Tests
[ActiveIssue(20884, TestPlatforms.AnyUnix)]
[ConditionalTheory(Helpers.GdiplusIsAvailable)]
- [InlineData(@"fileNo*-//\\#@(found")]
+ [InlineData("bad\0name")]
[InlineData("")]
public void Ctor_InvalidPath_ThrowsArgumentException(string path)
{
@@ -464,7 +464,7 @@ namespace System.Drawing.Imaging.Tests
[ActiveIssue(20884, TestPlatforms.AnyUnix)]
[ConditionalTheory(Helpers.GdiplusIsAvailable)]
- [InlineData(@"fileNo*-//\\#@(found")]
+ [InlineData("bad\0path")]
[InlineData("")]
public void Ctor_InvalidPathI_ThrowsArgumentException(string fileName)
{
@@ -749,7 +749,7 @@ namespace System.Drawing.Imaging.Tests
[ActiveIssue(20884, TestPlatforms.AnyUnix)]
[ConditionalTheory(Helpers.GdiplusIsAvailable)]
- [InlineData(@"fileNo*-//\\#@(found")]
+ [InlineData("bad\0path")]
[InlineData("")]
public void Ctor_InvalidPathII_ThrowsArgumentException(string fileName)
{
@@ -940,7 +940,7 @@ namespace System.Drawing.Imaging.Tests
[ActiveIssue(20884, TestPlatforms.AnyUnix)]
[ConditionalTheory(Helpers.GdiplusIsAvailable)]
- [InlineData(@"fileNo*-//\\#@(found")]
+ [InlineData("bad\0path")]
[InlineData("")]
public void Static_GetMetafileHeader_InvalidPath_ThrowsArgumentException(string fileName)
{
diff --git a/src/System.Drawing.Common/tests/Printing/PrintDocumentTests.cs b/src/System.Drawing.Common/tests/Printing/PrintDocumentTests.cs
index de604b044b..aa8e61f48c 100644
--- a/src/System.Drawing.Common/tests/Printing/PrintDocumentTests.cs
+++ b/src/System.Drawing.Common/tests/Printing/PrintDocumentTests.cs
@@ -256,8 +256,6 @@ namespace System.Drawing.Printing.Tests
break;
}
- Assert.False(pageSettings.Landscape);
- Assert.Equal(PaperSourceKind.FormSource, pageSettings.PaperSource.Kind);
Assert.Equal(PrinterResolutionKind.Custom, pageSettings.PrinterResolution.Kind);
Assert.True(pageSettings.PrinterSettings.IsDefaultPrinter);
}
diff --git a/src/System.Drawing.Common/tests/Printing/PrinterSettingsTests.cs b/src/System.Drawing.Common/tests/Printing/PrinterSettingsTests.cs
index 9569246895..ec6ab61f6b 100644
--- a/src/System.Drawing.Common/tests/Printing/PrinterSettingsTests.cs
+++ b/src/System.Drawing.Common/tests/Printing/PrinterSettingsTests.cs
@@ -55,7 +55,7 @@ namespace System.Drawing.Printing.Tests
public void Copies_Default_ReturnsExpected()
{
var printerSettings = new PrinterSettings();
- Assert.Equal(1, printerSettings.Copies);
+ int copies = printerSettings.Copies;
}
[ConditionalTheory(Helpers.GdiplusIsAvailable)]
@@ -396,7 +396,7 @@ namespace System.Drawing.Printing.Tests
public void IsDirectPrintingSupported_ImageFormatSupported_ReturnsExpected(ImageFormat imageFormat)
{
var printerSettings = new PrinterSettings();
- Assert.Equal(true, printerSettings.IsDirectPrintingSupported(imageFormat));
+ bool supported = printerSettings.IsDirectPrintingSupported(imageFormat);
}
public static IEnumerable<object[]> IsDirectPrintingSupported_ImageFormatNotSupported_TestData()
@@ -436,7 +436,7 @@ namespace System.Drawing.Printing.Tests
public void SupportsColor_ReturnsExpected()
{
var printerSettings = new PrinterSettings();
- Assert.Equal(true, printerSettings.SupportsColor);
+ bool supportsColor = printerSettings.SupportsColor;
}
[Theory]
@@ -579,11 +579,13 @@ namespace System.Drawing.Printing.Tests
}
[ActiveIssue(20884, TestPlatforms.AnyUnix)]
- [ConditionalFact(Helpers.GdiplusIsAvailable)]
+ [ConditionalFact(typeof(PrinterSettingsTests), nameof(CanTestSetHdevmode_IntPtr_Success))]
public void SetHdevmode_IntPtr_Success()
{
- var printerSettings = new PrinterSettings() { Copies = 3 };
- var newPrinterSettings = new PrinterSettings() { Copies = 6 };
+ string printerName = GetNameOfTestPrinterSuitableForDevModeTesting();
+ var printerSettings = new PrinterSettings() { PrinterName = printerName, Copies = 3 };
+ var newPrinterSettings = new PrinterSettings() { PrinterName = printerName, Copies = 6 };
+
IntPtr handle = printerSettings.GetHdevmode();
newPrinterSettings.SetHdevmode(handle);
Assert.Equal(printerSettings.Copies, newPrinterSettings.Copies);
@@ -591,6 +593,28 @@ namespace System.Drawing.Printing.Tests
Assert.Equal(printerSettings.Duplex, newPrinterSettings.Duplex);
}
+ public static bool CanTestSetHdevmode_IntPtr_Success => Helpers.GetGdiplusIsAvailable() && GetNameOfTestPrinterSuitableForDevModeTesting() != null;
+
+ private static string GetNameOfTestPrinterSuitableForDevModeTesting()
+ {
+ foreach (string candidate in s_TestPrinterNames)
+ {
+ PrinterSettings printerSettings = new PrinterSettings() { PrinterName = candidate };
+ if (printerSettings.IsValid)
+ return candidate;
+ }
+ return null;
+ }
+
+ private static readonly string[] s_TestPrinterNames =
+ {
+ // Our method of testing this api requires a printer that supports multi-copy printing, collating and duplex settings. Not all printers
+ // support these so rather than trust the machine running the test to have configured such a printer as the default, use the name of
+ // a known compliant printer that ships with Windows 10.
+ "Microsoft Print to PDF",
+ "Microsoft XPS Document Writer", // Backup for older Windows
+ };
+
[ActiveIssue(20884, TestPlatforms.AnyUnix)]
[ConditionalFact(Helpers.GdiplusIsAvailable)]
public void GetHdevmode_Zero_ThrowsArgumentException()
diff --git a/src/System.Drawing.Primitives/src/PinvokeAnalyzerExceptionList.analyzerdata b/src/System.Drawing.Primitives/src/PinvokeAnalyzerExceptionList.analyzerdata
new file mode 100644
index 0000000000..f34a4770cf
--- /dev/null
+++ b/src/System.Drawing.Primitives/src/PinvokeAnalyzerExceptionList.analyzerdata
@@ -0,0 +1 @@
+user32.dll!GetSysColor
diff --git a/src/System.Drawing.Primitives/src/System.Drawing.Primitives.csproj b/src/System.Drawing.Primitives/src/System.Drawing.Primitives.csproj
index fdc487ae3b..032f8247d1 100644
--- a/src/System.Drawing.Primitives/src/System.Drawing.Primitives.csproj
+++ b/src/System.Drawing.Primitives/src/System.Drawing.Primitives.csproj
@@ -7,8 +7,6 @@
<AssemblyName>System.Drawing.Primitives</AssemblyName>
<ProjectGuid>{8F472B93-574C-4AEC-9D28-6C2360A55BBF}</ProjectGuid>
<DefineConstants Condition="'$(TargetsWindows)' == 'true' And '$(TargetGroup)' != 'uap'">$(DefineConstants);FEATURE_WINDOWS_SYSTEM_COLORS</DefineConstants>
- <!-- This library contains PInvokes that cannot be used on OneCore. -->
- <EnablePInvokeAnalyzer>false</EnablePInvokeAnalyzer>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
diff --git a/src/System.Drawing.Primitives/tests/DataContractSerializerTests.cs b/src/System.Drawing.Primitives/tests/DataContractSerializerTests.cs
new file mode 100644
index 0000000000..86fe8d44a0
--- /dev/null
+++ b/src/System.Drawing.Primitives/tests/DataContractSerializerTests.cs
@@ -0,0 +1,146 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Xunit;
+using System.Runtime.Serialization.Tests;
+using System.Drawing;
+
+namespace System.Drawing.Primitives.Tests
+{
+ public class DataContractSerializerTests
+ {
+ [Fact]
+ public static void DCS_Point()
+ {
+ var objs = new Point[]
+ {
+ new Point(0,0),
+ new Point(1,2),
+ new Point(new Size(1,2))
+ };
+ var serializedStrings = new string[]
+ {
+ @"<Point xmlns=""http://schemas.datacontract.org/2004/07/System.Drawing"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""><x>0</x><y>0</y></Point>",
+ @"<Point xmlns=""http://schemas.datacontract.org/2004/07/System.Drawing"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""><x>1</x><y>2</y></Point>",
+ @"<Point xmlns=""http://schemas.datacontract.org/2004/07/System.Drawing"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""><x>1</x><y>2</y></Point>"
+ };
+ for (int i = 0; i < objs.Length; i++)
+ {
+ Assert.StrictEqual(DataContractSerializerHelper.SerializeAndDeserialize<Point>(objs[i], serializedStrings[i]), objs[i]);
+ }
+ }
+
+ [Fact]
+ public static void DCS_PointF()
+ {
+ var objs = new PointF[]
+ {
+ new PointF(0, 0),
+ new PointF(1,2),
+ new PointF(1.5000f,-1.5000f)
+ };
+ var serializedStrings = new string[]
+ {
+ @"<PointF xmlns=""http://schemas.datacontract.org/2004/07/System.Drawing"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""><x>0</x><y>0</y></PointF>",
+ @"<PointF xmlns=""http://schemas.datacontract.org/2004/07/System.Drawing"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""><x>1</x><y>2</y></PointF>",
+ @"<PointF xmlns=""http://schemas.datacontract.org/2004/07/System.Drawing"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""><x>1.5</x><y>-1.5</y></PointF>"
+ };
+ for (int i = 0; i < objs.Length; i++)
+ {
+ Assert.StrictEqual(DataContractSerializerHelper.SerializeAndDeserialize<PointF>(objs[i], serializedStrings[i]), objs[i]);
+ }
+ }
+
+ [Fact]
+ public static void DCS_Rectangle()
+ {
+ var objs = new Rectangle[]
+ {
+ new Rectangle(0, 0, 0, 0),
+ new Rectangle(1, 2, 1, 2),
+ new Rectangle(new Point(1,2), new Size(1,2)),
+ new Rectangle(1, -2, 1, -2)
+ };
+ var serializedStrings = new string[]
+ {
+ @"<Rectangle xmlns=""http://schemas.datacontract.org/2004/07/System.Drawing"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""><height>0</height><width>0</width><x>0</x><y>0</y></Rectangle>",
+ @"<Rectangle xmlns=""http://schemas.datacontract.org/2004/07/System.Drawing"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""><height>2</height><width>1</width><x>1</x><y>2</y></Rectangle>",
+ @"<Rectangle xmlns=""http://schemas.datacontract.org/2004/07/System.Drawing"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""><height>2</height><width>1</width><x>1</x><y>2</y></Rectangle>",
+ @"<Rectangle xmlns=""http://schemas.datacontract.org/2004/07/System.Drawing"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""><height>-2</height><width>1</width><x>1</x><y>-2</y></Rectangle>"
+ };
+ for (int i = 0; i < objs.Length; i++)
+ {
+ Assert.StrictEqual(DataContractSerializerHelper.SerializeAndDeserialize<Rectangle>(objs[i], serializedStrings[i]), objs[i]);
+ }
+ }
+
+ [Fact]
+ public static void DCS_RectangleF()
+ {
+ var objs = new RectangleF[]
+ {
+ new RectangleF(0, 0, 0, 0),
+ new RectangleF(new PointF(1.5000f,2.5000f), new SizeF(1.5000f,2.5000f)),
+ new RectangleF(1.50001f, -2.5000f, 1.5000f, -2.5000f)
+ };
+ var serializedStrings = new string[]
+ {
+ @"<RectangleF xmlns=""http://schemas.datacontract.org/2004/07/System.Drawing"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""><height>0</height><width>0</width><x>0</x><y>0</y></RectangleF>",
+ @"<RectangleF xmlns=""http://schemas.datacontract.org/2004/07/System.Drawing"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""><height>2.5</height><width>1.5</width><x>1.5</x><y>2.5</y></RectangleF>",
+ @"<RectangleF xmlns=""http://schemas.datacontract.org/2004/07/System.Drawing"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""><height>-2.5</height><width>1.5</width><x>1.50001</x><y>-2.5</y></RectangleF>"
+ };
+ for (int i = 0; i < objs.Length; i++)
+ {
+ Assert.StrictEqual(DataContractSerializerHelper.SerializeAndDeserialize<RectangleF>(objs[i], serializedStrings[i]), objs[i]);
+ }
+ }
+
+ [Fact]
+ public static void DCS_Size()
+ {
+ var objs = new Size[]
+ {
+ new Size(0,0),
+ new Size(new Point(1,2)),
+ new Size(1,2)
+ };
+ var serializedStrings = new string[]
+ {
+ @"<Size xmlns=""http://schemas.datacontract.org/2004/07/System.Drawing"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""><height>0</height><width>0</width></Size>",
+ @"<Size xmlns=""http://schemas.datacontract.org/2004/07/System.Drawing"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""><height>2</height><width>1</width></Size>",
+ @"<Size xmlns=""http://schemas.datacontract.org/2004/07/System.Drawing"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""><height>2</height><width>1</width></Size>"
+ };
+ for (int i = 0; i < objs.Length; i++)
+ {
+ Assert.StrictEqual(DataContractSerializerHelper.SerializeAndDeserialize<Size>(objs[i], serializedStrings[i]), objs[i]);
+ }
+ }
+
+ [Fact]
+ public static void DCS_SizeF()
+ {
+ var objs = new SizeF[]
+ {
+ new SizeF(0,0),
+ new SizeF(new PointF(1.5000f,-2.5000f)),
+ new SizeF(1.5000f,-2.5000f)
+ };
+ var serializedStrings = new string[]
+ {
+ @"<SizeF xmlns=""http://schemas.datacontract.org/2004/07/System.Drawing"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""><height>0</height><width>0</width></SizeF>",
+ @"<SizeF xmlns=""http://schemas.datacontract.org/2004/07/System.Drawing"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""><height>-2.5</height><width>1.5</width></SizeF>",
+ @"<SizeF xmlns=""http://schemas.datacontract.org/2004/07/System.Drawing"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""><height>-2.5</height><width>1.5</width></SizeF>"
+ };
+ for (int i = 0; i < objs.Length; i++)
+ {
+ Assert.StrictEqual(DataContractSerializerHelper.SerializeAndDeserialize<SizeF>(objs[i], serializedStrings[i]), objs[i]);
+ }
+ }
+ }
+}
diff --git a/src/System.Drawing.Primitives/tests/System.Drawing.Primitives.Tests.csproj b/src/System.Drawing.Primitives/tests/System.Drawing.Primitives.Tests.csproj
index 3349020d86..a22538b184 100644
--- a/src/System.Drawing.Primitives/tests/System.Drawing.Primitives.Tests.csproj
+++ b/src/System.Drawing.Primitives/tests/System.Drawing.Primitives.Tests.csproj
@@ -11,6 +11,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Release|AnyCPU'" />
<ItemGroup>
+ <Compile Include="DataContractSerializerTests.cs" />
<Compile Include="PointFTests.cs" />
<Compile Include="PointTests.cs" />
<Compile Include="RectangleFTests.cs" />
@@ -21,6 +22,8 @@
<Compile Include="$(CommonTestPath)\System\Diagnostics\DebuggerAttributes.cs">
<Link>Common\System\Diagnostics\DebuggerAttributes.cs</Link>
</Compile>
+ <Compile Include="$(CommonTestPath)\System\Runtime\Serialization\DataContractSerializerHelper.cs" />
+ <Compile Include="$(CommonTestPath)\System\Runtime\Serialization\Utils.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)'=='netcoreapp'">
<Compile Include="SizeFTests.netcoreapp.cs" />
diff --git a/src/System.Globalization.Calendars/tests/CalendarHelpers.cs b/src/System.Globalization.Calendars/tests/CalendarHelpers.cs
index 3551a4ad03..6f6d6eecc0 100644
--- a/src/System.Globalization.Calendars/tests/CalendarHelpers.cs
+++ b/src/System.Globalization.Calendars/tests/CalendarHelpers.cs
@@ -344,7 +344,7 @@ namespace System.Globalization.Tests
// Day is invalid
Assert.Throws<ArgumentOutOfRangeException>(() => calendar.ToDateTime(year, month, -1, hour, minute, second, millisecond, era));
Assert.Throws<ArgumentOutOfRangeException>(() => calendar.ToDateTime(year, month, 0, hour, minute, second, millisecond, era));
- Assert.Throws<ArgumentOutOfRangeException>(() => calendar.ToDateTime(year, month, calendar.GetDaysInMonth(year, month, era) + 1, minute, second, millisecond, era));
+ Assert.Throws<ArgumentOutOfRangeException>(() => calendar.ToDateTime(year, month, calendar.GetDaysInMonth(year, month, era) + 1, hour, minute, second, millisecond, era));
// Hour is invalid
Assert.Throws<ArgumentOutOfRangeException>(() => calendar.ToDateTime(year, month, day, -1, minute, second, millisecond, era));
diff --git a/src/System.Globalization.Calendars/tests/JapaneseCalendar/JapaneseCalendarEras.cs b/src/System.Globalization.Calendars/tests/JapaneseCalendar/JapaneseCalendarEras.cs
index f1d99090fa..18804c16f3 100644
--- a/src/System.Globalization.Calendars/tests/JapaneseCalendar/JapaneseCalendarEras.cs
+++ b/src/System.Globalization.Calendars/tests/JapaneseCalendar/JapaneseCalendarEras.cs
@@ -11,7 +11,17 @@ namespace System.Globalization.Tests
[Fact]
public void Eras()
{
- Assert.Equal(new int[] { 4, 3, 2, 1 }, new JapaneseCalendar().Eras);
+ int[] eras = new JapaneseCalendar().Eras;
+ int noOfEras = eras.Length;
+
+ Assert.True(noOfEras >= 4);
+
+ // eras should be [ noOfEras, noOfEras - 1, ..., 1 ]
+ Assert.Equal(noOfEras, eras[0]);
+ for (int i = 0; i < noOfEras; i++)
+ {
+ Assert.Equal(noOfEras - i, eras[i]);
+ }
}
}
}
diff --git a/src/System.Globalization.Calendars/tests/Misc/MiscCalendars.cs b/src/System.Globalization.Calendars/tests/Misc/MiscCalendars.cs
index 1db11ee247..ba37f53920 100644
--- a/src/System.Globalization.Calendars/tests/Misc/MiscCalendars.cs
+++ b/src/System.Globalization.Calendars/tests/Misc/MiscCalendars.cs
@@ -40,7 +40,7 @@ namespace System.Globalization.Tests
public static void JapaneseTest()
{
JapaneseCalendar jCal = new JapaneseCalendar();
- DateTime dTest = jCal.ToDateTime(1, 1, 8, 0, 0, 0, 0);
+ DateTime dTest = jCal.ToDateTime(1, 1, 8, 0, 0, 0, 0, 4);
Assert.Equal(dTest, new DateTime(1989, 1, 8));
}
}
diff --git a/src/System.Globalization.Extensions/ref/System.Globalization.Extensions.csproj b/src/System.Globalization.Extensions/ref/System.Globalization.Extensions.csproj
index 286fca0138..d54d23056b 100644
--- a/src/System.Globalization.Extensions/ref/System.Globalization.Extensions.csproj
+++ b/src/System.Globalization.Extensions/ref/System.Globalization.Extensions.csproj
@@ -8,19 +8,12 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Release|AnyCPU'" />
- <ItemGroup Condition="'$(TargetGroup)' != 'netfx'">
+ <ItemGroup>
<Compile Include="System.Globalization.Extensions.Forwards.cs" />
</ItemGroup>
- <ItemGroup Condition="'$(TargetGroup)' == 'netfx'">
- <Compile Include="System.Globalization.Extensions.netfx.cs" />
- </ItemGroup>
- <ItemGroup Condition="'$(TargetGroup)' != 'netfx'">
+ <ItemGroup>
<ProjectReference Include="..\..\System.Runtime\ref\System.Runtime.csproj" />
<ProjectReference Include="..\..\System.Runtime.Extensions\ref\System.Runtime.Extensions.csproj" />
- <ProjectReference Include="..\..\System.Globalization\ref\System.Globalization.csproj" />
- </ItemGroup>
- <ItemGroup Condition="'$(TargetGroup)' == 'netfx'">
- <Reference Include="mscorlib" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.Globalization.Extensions/ref/System.Globalization.Extensions.netfx.cs b/src/System.Globalization.Extensions/ref/System.Globalization.Extensions.netfx.cs
deleted file mode 100644
index bdb68e8d21..0000000000
--- a/src/System.Globalization.Extensions/ref/System.Globalization.Extensions.netfx.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Text.NormalizationForm))]
-[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Globalization.IdnMapping))]
-
-namespace System
-{
- public static class StringNormalizationExtensions
- {
- public static bool IsNormalized(this string value) { return default(bool); }
- public static bool IsNormalized(this string value, System.Text.NormalizationForm normalizationForm) { return default(bool); }
- public static String Normalize(this string value) { return default(string); }
- public static String Normalize(this string value, System.Text.NormalizationForm normalizationForm) { return default(string); }
- }
-}
-
-namespace System.Globalization
-{
- public static partial class GlobalizationExtensions
- {
- public static StringComparer GetStringComparer(this CompareInfo compareInfo, CompareOptions options) { return default(StringComparer); }
- }
-}
diff --git a/src/System.Globalization.Extensions/src/ApiCompatBaseline.netfx.txt b/src/System.Globalization.Extensions/src/ApiCompatBaseline.netfx.txt
deleted file mode 100644
index 00cbe9f3a4..0000000000
--- a/src/System.Globalization.Extensions/src/ApiCompatBaseline.netfx.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-# This one is needed because when ApiCompat looks for the type, it will first check the v4.6.x targetting pack and find the System.Runtime.Extensions file
-# which is not the latest (the one we just built) and it will load that instead of the one built inside CoreFx.
-TypesMustExist : Type 'System.StringNormalizationExtensions' does not exist in the implementation but it does exist in the contract.
-TypesMustExist : Type 'System.Globalization.GlobalizationExtensions' does not exist in the implementation but it does exist in the contract.
diff --git a/src/System.Globalization.Extensions/src/System.Globalization.Extensions.csproj b/src/System.Globalization.Extensions/src/System.Globalization.Extensions.csproj
index f8bf84548b..5422665637 100644
--- a/src/System.Globalization.Extensions/src/System.Globalization.Extensions.csproj
+++ b/src/System.Globalization.Extensions/src/System.Globalization.Extensions.csproj
@@ -9,7 +9,6 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ProjectGuid>{2B96AA10-84C0-4927-8611-8D2474B990E8}</ProjectGuid>
<IsPartialFacadeAssembly>true</IsPartialFacadeAssembly>
- <OmitResources Condition="'$(TargetGroup)' != 'netfx'">true</OmitResources>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
@@ -17,21 +16,9 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Release|AnyCPU'" />
- <ItemGroup Condition="'$(TargetGroup)' == 'netfx'">
- <Compile Include="System\Globalization\Extensions.cs" />
- <Compile Include="System\StringNormalizationExtensions.netfx.cs" />
- </ItemGroup>
- <ItemGroup Condition="'$(TargetGroup)' != 'netfx'">
- <Reference Include="System.Diagnostics.Debug" />
- <Reference Include="System.Diagnostics.Tools" />
- <Reference Include="System.Resources.ResourceManager" />
+ <ItemGroup>
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.Extensions" />
- <Reference Include="System.Runtime.InteropServices" />
- </ItemGroup>
- <ItemGroup Condition="'$(TargetGroup)' == 'netfx'">
- <Reference Include="mscorlib" />
- <Reference Include="System" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.Globalization.Extensions/src/System/Globalization/Extensions.cs b/src/System.Globalization.Extensions/src/System/Globalization/Extensions.cs
deleted file mode 100644
index bf48d06e06..0000000000
--- a/src/System.Globalization.Extensions/src/System/Globalization/Extensions.cs
+++ /dev/null
@@ -1,98 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Diagnostics;
-
-namespace System.Globalization
-{
- public static class GlobalizationExtensions
- {
- public static StringComparer GetStringComparer(this CompareInfo compareInfo, CompareOptions options)
- {
- if (compareInfo == null)
- {
- throw new ArgumentNullException(nameof(compareInfo));
- }
-
- if (options == CompareOptions.Ordinal)
- {
- return StringComparer.Ordinal;
- }
-
- if (options == CompareOptions.OrdinalIgnoreCase)
- {
- return StringComparer.OrdinalIgnoreCase;
- }
-
- if ((options & CultureAwareComparer.ValidCompareMaskOffFlags) != 0)
- {
- throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options));
- }
-
- return new CultureAwareComparer(compareInfo, options);
- }
- }
-
- [Serializable]
- internal sealed class CultureAwareComparer : StringComparer
- {
- internal const CompareOptions ValidCompareMaskOffFlags =
- ~(CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols | CompareOptions.IgnoreNonSpace |
- CompareOptions.IgnoreWidth | CompareOptions.IgnoreKanaType | CompareOptions.StringSort);
-
- private readonly CompareInfo _compareInfo;
- private readonly CompareOptions _options;
-
- internal CultureAwareComparer(CompareInfo compareInfo, CompareOptions options)
- {
- Debug.Assert((options & ValidCompareMaskOffFlags) == 0);
- _compareInfo = compareInfo;
- _options = options;
- }
-
- public override int Compare(string x, string y)
- {
- if (Object.ReferenceEquals(x, y)) return 0;
- if (x == null) return -1;
- if (y == null) return 1;
- return _compareInfo.Compare(x, y, _options);
- }
-
- public override bool Equals(string x, string y)
- {
- if (Object.ReferenceEquals(x, y)) return true;
- if (x == null || y == null) return false;
-
- return (_compareInfo.Compare(x, y, _options) == 0);
- }
-
- public override int GetHashCode(string obj)
- {
- if (obj == null)
- {
- throw new ArgumentNullException(nameof(obj));
- }
-
- // StringSort used in compare operation and not with the hashing
- return _compareInfo.GetHashCode(obj, _options & (~CompareOptions.StringSort));
- }
-
- // Equals method for the comparer itself.
- public override bool Equals(object obj)
- {
- CultureAwareComparer comparer = obj as CultureAwareComparer;
- return
- comparer != null &&
- _options == comparer._options &&
- _compareInfo.Equals(comparer._compareInfo);
- }
-
- public override int GetHashCode()
- {
- return _compareInfo.GetHashCode() ^ ((int)_options & 0x7FFFFFFF);
- }
- }
-}
-
diff --git a/src/System.Globalization.Extensions/src/System/StringNormalizationExtensions.netfx.cs b/src/System.Globalization.Extensions/src/System/StringNormalizationExtensions.netfx.cs
deleted file mode 100644
index 02cfa407ae..0000000000
--- a/src/System.Globalization.Extensions/src/System/StringNormalizationExtensions.netfx.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-namespace System
-{
- public static class StringNormalizationExtensions
- {
- public static bool IsNormalized(this string value)
- {
- return value.IsNormalized();
- }
-
- public static bool IsNormalized(this string value, System.Text.NormalizationForm normalizationForm)
- {
- return value.IsNormalized(normalizationForm);
- }
-
- public static String Normalize(this string value)
- {
- return value.Normalize();
- }
-
- public static String Normalize(this string value, System.Text.NormalizationForm normalizationForm)
- {
- return value.Normalize(normalizationForm);
- }
- }
-}
diff --git a/src/System.Globalization/System.Globalization.sln b/src/System.Globalization/System.Globalization.sln
index 8b0c64a0bd..5fc9a81913 100644
--- a/src/System.Globalization/System.Globalization.sln
+++ b/src/System.Globalization/System.Globalization.sln
@@ -36,10 +36,10 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {484C92C6-6D2C-45BC-A5E2-4A12BA228E1E}.Debug|Any CPU.ActiveCfg = netstandard-Debug|Any CPU
- {484C92C6-6D2C-45BC-A5E2-4A12BA228E1E}.Debug|Any CPU.Build.0 = netstandard-Debug|Any CPU
- {484C92C6-6D2C-45BC-A5E2-4A12BA228E1E}.Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
- {484C92C6-6D2C-45BC-A5E2-4A12BA228E1E}.Release|Any CPU.Build.0 = netstandard-Release|Any CPU
+ {484C92C6-6D2C-45BC-A5E2-4A12BA228E1E}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
+ {484C92C6-6D2C-45BC-A5E2-4A12BA228E1E}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
+ {484C92C6-6D2C-45BC-A5E2-4A12BA228E1E}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
+ {484C92C6-6D2C-45BC-A5E2-4A12BA228E1E}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
{9A8926D9-1D4C-4069-8965-A626F6CA8C29}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
{9A8926D9-1D4C-4069-8965-A626F6CA8C29}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
{9A8926D9-1D4C-4069-8965-A626F6CA8C29}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
diff --git a/src/System.Globalization/tests/CharUnicodeInfo/CharUnicodeInfoTestData.cs b/src/System.Globalization/tests/CharUnicodeInfo/CharUnicodeInfoTestData.cs
index 51d5a3714e..a71c4d9cd4 100644
--- a/src/System.Globalization/tests/CharUnicodeInfo/CharUnicodeInfoTestData.cs
+++ b/src/System.Globalization/tests/CharUnicodeInfo/CharUnicodeInfoTestData.cs
@@ -30,7 +30,7 @@ namespace System.Globalization.Tests
private static int s_rangeMinCodePoint;
private static void Parse(List<CharUnicodeInfoTestCase> testCases, string line)
{
- // Data is in the format:
+ // Data is in the format:
// code-value;
// character-name;
// general-category;
@@ -48,7 +48,7 @@ namespace System.Globalization.Tests
int codePoint = int.Parse(charValueString, NumberStyles.HexNumber);
Parse(testCases, codePoint, charCategoryString, numericValueString);
-
+
if (charName.EndsWith("First>"))
{
s_rangeMinCodePoint = codePoint;
@@ -110,7 +110,8 @@ namespace System.Globalization.Tests
{
Utf32CodeValue = codeValueRepresentation,
GeneralCategory = generalCategory,
- NumericValue = numericValue
+ NumericValue = numericValue,
+ CodePoint = codePoint
});
}
@@ -144,6 +145,7 @@ namespace System.Globalization.Tests
public class CharUnicodeInfoTestCase
{
public string Utf32CodeValue { get; set; }
+ public int CodePoint { get; set; }
public UnicodeCategory GeneralCategory { get; set; }
public double NumericValue { get; set; }
}
diff --git a/src/System.Globalization/tests/CharUnicodeInfo/CharUnicodeInfoTests.cs b/src/System.Globalization/tests/CharUnicodeInfo/CharUnicodeInfoTests.cs
index 8cbe2f920a..74f09fac2f 100644
--- a/src/System.Globalization/tests/CharUnicodeInfo/CharUnicodeInfoTests.cs
+++ b/src/System.Globalization/tests/CharUnicodeInfo/CharUnicodeInfoTests.cs
@@ -20,6 +20,9 @@ namespace System.Globalization.Tests
}
// Test the string overload for a surrogate pair or a single char
GetUnicodeCategory(testCase.Utf32CodeValue, new UnicodeCategory[] { testCase.GeneralCategory });
+#if netcoreapp
+ Assert.Equal(testCase.GeneralCategory, CharUnicodeInfo.GetUnicodeCategory(testCase.CodePoint));
+#endif // netcoreapp
}
}
@@ -123,65 +126,65 @@ namespace System.Globalization.Tests
return $"CodeValue: {((int)ch).ToString("X")}; Expected: {expected}; Actual: {actual}";
}
- public static string s_numericsCodepoints =
+ public static string s_numericsCodepoints =
"\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039" +
- "\u0660\u0661\u0662\u0663\u0664\u0665\u0666\u0667\u0668\u0669" +
+ "\u0660\u0661\u0662\u0663\u0664\u0665\u0666\u0667\u0668\u0669" +
"\u06f0\u06f1\u06f2\u06f3\u06f4\u06f5\u06f6\u06f7\u06f8\u06f9" +
- "\u07c0\u07c1\u07c2\u07c3\u07c4\u07c5\u07c6\u07c7\u07c8\u07c9" +
+ "\u07c0\u07c1\u07c2\u07c3\u07c4\u07c5\u07c6\u07c7\u07c8\u07c9" +
"\u0966\u0967\u0968\u0969\u096a\u096b\u096c\u096d\u096e\u096f" +
- "\u09e6\u09e7\u09e8\u09e9\u09ea\u09eb\u09ec\u09ed\u09ee\u09ef" +
- "\u0a66\u0a67\u0a68\u0a69\u0a6a\u0a6b\u0a6c\u0a6d\u0a6e\u0a6f" +
- "\u0ae6\u0ae7\u0ae8\u0ae9\u0aea\u0aeb\u0aec\u0aed\u0aee\u0aef" +
- "\u0b66\u0b67\u0b68\u0b69\u0b6a\u0b6b\u0b6c\u0b6d\u0b6e\u0b6f" +
- "\u0be6\u0be7\u0be8\u0be9\u0bea\u0beb\u0bec\u0bed\u0bee\u0bef" +
- "\u0c66\u0c67\u0c68\u0c69\u0c6a\u0c6b\u0c6c\u0c6d\u0c6e\u0c6f" +
- "\u0ce6\u0ce7\u0ce8\u0ce9\u0cea\u0ceb\u0cec\u0ced\u0cee\u0cef" +
- "\u0d66\u0d67\u0d68\u0d69\u0d6a\u0d6b\u0d6c\u0d6d\u0d6e\u0d6f" +
- "\u0e50\u0e51\u0e52\u0e53\u0e54\u0e55\u0e56\u0e57\u0e58\u0e59" +
- "\u0ed0\u0ed1\u0ed2\u0ed3\u0ed4\u0ed5\u0ed6\u0ed7\u0ed8\u0ed9" +
- "\u0f20\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\u0f29" +
- "\u1040\u1041\u1042\u1043\u1044\u1045\u1046\u1047\u1048\u1049" +
- "\u1090\u1091\u1092\u1093\u1094\u1095\u1096\u1097\u1098\u1099" +
- "\u17e0\u17e1\u17e2\u17e3\u17e4\u17e5\u17e6\u17e7\u17e8\u17e9" +
- "\u1810\u1811\u1812\u1813\u1814\u1815\u1816\u1817\u1818\u1819" +
- "\u1946\u1947\u1948\u1949\u194a\u194b\u194c\u194d\u194e\u194f" +
- "\u19d0\u19d1\u19d2\u19d3\u19d4\u19d5\u19d6\u19d7\u19d8\u19d9" +
- "\u1a80\u1a81\u1a82\u1a83\u1a84\u1a85\u1a86\u1a87\u1a88\u1a89" +
- "\u1a90\u1a91\u1a92\u1a93\u1a94\u1a95\u1a96\u1a97\u1a98\u1a99" +
- "\u1b50\u1b51\u1b52\u1b53\u1b54\u1b55\u1b56\u1b57\u1b58\u1b59" +
- "\u1bb0\u1bb1\u1bb2\u1bb3\u1bb4\u1bb5\u1bb6\u1bb7\u1bb8\u1bb9" +
- "\u1c40\u1c41\u1c42\u1c43\u1c44\u1c45\u1c46\u1c47\u1c48\u1c49" +
- "\u1c50\u1c51\u1c52\u1c53\u1c54\u1c55\u1c56\u1c57\u1c58\u1c59" +
- "\ua620\ua621\ua622\ua623\ua624\ua625\ua626\ua627\ua628\ua629" +
- "\ua8d0\ua8d1\ua8d2\ua8d3\ua8d4\ua8d5\ua8d6\ua8d7\ua8d8\ua8d9" +
- "\ua900\ua901\ua902\ua903\ua904\ua905\ua906\ua907\ua908\ua909" +
- "\ua9d0\ua9d1\ua9d2\ua9d3\ua9d4\ua9d5\ua9d6\ua9d7\ua9d8\ua9d9" +
- "\uaa50\uaa51\uaa52\uaa53\uaa54\uaa55\uaa56\uaa57\uaa58\uaa59" +
- "\uabf0\uabf1\uabf2\uabf3\uabf4\uabf5\uabf6\uabf7\uabf8\uabf9" +
+ "\u09e6\u09e7\u09e8\u09e9\u09ea\u09eb\u09ec\u09ed\u09ee\u09ef" +
+ "\u0a66\u0a67\u0a68\u0a69\u0a6a\u0a6b\u0a6c\u0a6d\u0a6e\u0a6f" +
+ "\u0ae6\u0ae7\u0ae8\u0ae9\u0aea\u0aeb\u0aec\u0aed\u0aee\u0aef" +
+ "\u0b66\u0b67\u0b68\u0b69\u0b6a\u0b6b\u0b6c\u0b6d\u0b6e\u0b6f" +
+ "\u0be6\u0be7\u0be8\u0be9\u0bea\u0beb\u0bec\u0bed\u0bee\u0bef" +
+ "\u0c66\u0c67\u0c68\u0c69\u0c6a\u0c6b\u0c6c\u0c6d\u0c6e\u0c6f" +
+ "\u0ce6\u0ce7\u0ce8\u0ce9\u0cea\u0ceb\u0cec\u0ced\u0cee\u0cef" +
+ "\u0d66\u0d67\u0d68\u0d69\u0d6a\u0d6b\u0d6c\u0d6d\u0d6e\u0d6f" +
+ "\u0e50\u0e51\u0e52\u0e53\u0e54\u0e55\u0e56\u0e57\u0e58\u0e59" +
+ "\u0ed0\u0ed1\u0ed2\u0ed3\u0ed4\u0ed5\u0ed6\u0ed7\u0ed8\u0ed9" +
+ "\u0f20\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\u0f29" +
+ "\u1040\u1041\u1042\u1043\u1044\u1045\u1046\u1047\u1048\u1049" +
+ "\u1090\u1091\u1092\u1093\u1094\u1095\u1096\u1097\u1098\u1099" +
+ "\u17e0\u17e1\u17e2\u17e3\u17e4\u17e5\u17e6\u17e7\u17e8\u17e9" +
+ "\u1810\u1811\u1812\u1813\u1814\u1815\u1816\u1817\u1818\u1819" +
+ "\u1946\u1947\u1948\u1949\u194a\u194b\u194c\u194d\u194e\u194f" +
+ "\u19d0\u19d1\u19d2\u19d3\u19d4\u19d5\u19d6\u19d7\u19d8\u19d9" +
+ "\u1a80\u1a81\u1a82\u1a83\u1a84\u1a85\u1a86\u1a87\u1a88\u1a89" +
+ "\u1a90\u1a91\u1a92\u1a93\u1a94\u1a95\u1a96\u1a97\u1a98\u1a99" +
+ "\u1b50\u1b51\u1b52\u1b53\u1b54\u1b55\u1b56\u1b57\u1b58\u1b59" +
+ "\u1bb0\u1bb1\u1bb2\u1bb3\u1bb4\u1bb5\u1bb6\u1bb7\u1bb8\u1bb9" +
+ "\u1c40\u1c41\u1c42\u1c43\u1c44\u1c45\u1c46\u1c47\u1c48\u1c49" +
+ "\u1c50\u1c51\u1c52\u1c53\u1c54\u1c55\u1c56\u1c57\u1c58\u1c59" +
+ "\ua620\ua621\ua622\ua623\ua624\ua625\ua626\ua627\ua628\ua629" +
+ "\ua8d0\ua8d1\ua8d2\ua8d3\ua8d4\ua8d5\ua8d6\ua8d7\ua8d8\ua8d9" +
+ "\ua900\ua901\ua902\ua903\ua904\ua905\ua906\ua907\ua908\ua909" +
+ "\ua9d0\ua9d1\ua9d2\ua9d3\ua9d4\ua9d5\ua9d6\ua9d7\ua9d8\ua9d9" +
+ "\uaa50\uaa51\uaa52\uaa53\uaa54\uaa55\uaa56\uaa57\uaa58\uaa59" +
+ "\uabf0\uabf1\uabf2\uabf3\uabf4\uabf5\uabf6\uabf7\uabf8\uabf9" +
"\uff10\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18\uff19";
- public static string s_nonNumericsCodepoints =
+ public static string s_nonNumericsCodepoints =
"abcdefghijklmnopqrstuvwxyz" +
- "\u1369\u136a\u136b\u136c\u136d\u136e\u136f\u1370\u1371\u1372\u1373" +
+ "\u1369\u136a\u136b\u136c\u136d\u136e\u136f\u1370\u1371\u1372\u1373" +
"\u1374\u1375\u1376\u1377\u1378\u1379\u137a\u137b\u137c\u137d";
public static string s_numericNonDecimalCodepoints =
- "\u00b2\u00b3\u00b9\u1369\u136a\u136b\u136c\u136d\u136e\u136f\u1370" +
- "\u1371\u19da\u2070\u2074\u2075\u2076\u2077\u2078\u2079\u2080\u2081" +
- "\u2082\u2083\u2084\u2085\u2086\u2087\u2088\u2089\u2460\u2461\u2462" +
- "\u2463\u2464\u2465\u2466\u2467\u2468\u2474\u2475\u2476\u2477\u2478" +
- "\u2479\u247a\u247b\u247c\u2488\u2489\u248a\u248b\u248c\u248d\u248e" +
- "\u248f\u2490\u24ea\u24f5\u24f6\u24f7\u24f8\u24f9\u24fa\u24fb\u24fc" +
+ "\u00b2\u00b3\u00b9\u1369\u136a\u136b\u136c\u136d\u136e\u136f\u1370" +
+ "\u1371\u19da\u2070\u2074\u2075\u2076\u2077\u2078\u2079\u2080\u2081" +
+ "\u2082\u2083\u2084\u2085\u2086\u2087\u2088\u2089\u2460\u2461\u2462" +
+ "\u2463\u2464\u2465\u2466\u2467\u2468\u2474\u2475\u2476\u2477\u2478" +
+ "\u2479\u247a\u247b\u247c\u2488\u2489\u248a\u248b\u248c\u248d\u248e" +
+ "\u248f\u2490\u24ea\u24f5\u24f6\u24f7\u24f8\u24f9\u24fa\u24fb\u24fc" +
"\u24fd\u24ff\u2776\u2777\u2778\u2779\u277a\u277b\u277c\u277d\u277e" +
"\u2780\u2781\u2782\u2783\u2784\u2785\u2786\u2787\u2788\u278a\u278b" +
"\u278c\u278d\u278e\u278f\u2790\u2791\u2792";
public static int [] s_numericNonDecimalValues = new int []
- {
- 2, 3, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 0, 4, 5, 6, 7, 8, 9, 0, 1, 2,
- 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7,
- 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1,
- 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6,
+ {
+ 2, 3, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 0, 4, 5, 6, 7, 8, 9, 0, 1, 2,
+ 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1,
+ 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6,
7, 8, 9
};
@@ -195,7 +198,7 @@ namespace System.Globalization.Tests
{
Assert.Equal(j, CharUnicodeInfo.GetDecimalDigitValue(s_numericsCodepoints[i + j]));
Assert.Equal(j, CharUnicodeInfo.GetDecimalDigitValue(s_numericsCodepoints, i + j));
- }
+ }
}
}
diff --git a/src/System.Globalization/tests/Configurations.props b/src/System.Globalization/tests/Configurations.props
index ee7fd3a3db..d4273b555c 100644
--- a/src/System.Globalization/tests/Configurations.props
+++ b/src/System.Globalization/tests/Configurations.props
@@ -3,6 +3,7 @@
<PropertyGroup>
<BuildConfigurations>
netstandard;
+ netcoreapp;
uap-Windows_NT;
</BuildConfigurations>
</PropertyGroup>
diff --git a/src/System.Globalization/tests/CultureInfo/CultureInfoAll.cs b/src/System.Globalization/tests/CultureInfo/CultureInfoAll.cs
index 4975ebb041..6da81e6eee 100644
--- a/src/System.Globalization/tests/CultureInfo/CultureInfoAll.cs
+++ b/src/System.Globalization/tests/CultureInfo/CultureInfoAll.cs
@@ -629,7 +629,6 @@ namespace System.Globalization.Tests
}
[Fact]
- [ActiveIssue("TFS 444333 - Should ExceptionMiniaturizer exempt CultureNotFoundException.InvalidCultureName from being optimized away?", TargetFrameworkMonikers.UapAot)]
public void CultureNotFoundExceptionTest()
{
AssertExtensions.Throws<CultureNotFoundException>("name", () => new CultureInfo("!@#$%^&*()"));
diff --git a/src/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoTests.cs b/src/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoTests.cs
index accea71829..45273ca420 100644
--- a/src/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoTests.cs
+++ b/src/System.Globalization/tests/DateTimeFormatInfo/DateTimeFormatInfoTests.cs
@@ -59,12 +59,12 @@ namespace System.Globalization.Tests
expectedFormattedString = formattedTime.Replace(timeSep, dtfi.TimeSeparator);
Assert.Equal(expectedFormattedString, d.ToString("HH:mm:ss", dtfi));
}
-
+
[Theory]
[MemberData(nameof(DateTimeFormatInfo_TestData))]
public void NativeCalendarNameTest(DateTimeFormatInfo dtfi, Calendar calendar, string nativeCalendarName)
{
- try
+ try
{
dtfi.Calendar = calendar;
Assert.Equal(nativeCalendarName, dtfi.NativeCalendarName);
@@ -77,8 +77,8 @@ namespace System.Globalization.Tests
Assert.True(calendar is PersianCalendar, "Exception can occur only with PersianCalendar");
}
else // !PlatformDetection.IsWindows
- {
- Assert.True(calendar is HijriCalendar || calendar is UmAlQuraCalendar || calendar is ThaiBuddhistCalendar ||
+ {
+ Assert.True(calendar is HijriCalendar || calendar is UmAlQuraCalendar || calendar is ThaiBuddhistCalendar ||
calendar is HebrewCalendar || calendar is KoreanCalendar, "failed to set the calendar on DTFI");
}
}
@@ -131,7 +131,35 @@ namespace System.Globalization.Tests
for (DayOfWeek day=DayOfWeek.Sunday; day <= DayOfWeek.Saturday; day++)
{
Assert.Equal(shortestDayNames[(int) day], dtfi.GetShortestDayName(day));
- }
+ }
+ }
+
+ [Fact]
+ public void TestHebrewMonths()
+ {
+ CultureInfo ci = new CultureInfo("he-IL");
+ ci.DateTimeFormat.Calendar = new HebrewCalendar();
+
+ Assert.Equal(13, ci.DateTimeFormat.MonthNames.Length);
+ Assert.Equal(13, ci.DateTimeFormat.MonthGenitiveNames.Length);
+ Assert.Equal(13, ci.DateTimeFormat.AbbreviatedMonthNames.Length);
+ Assert.Equal(13, ci.DateTimeFormat.AbbreviatedMonthGenitiveNames.Length);
+
+ DateTime dt = ci.DateTimeFormat.Calendar.ToDateTime(5779, 1, 1, 0, 0, 0, 0); // leap year
+ for (int i = 0; i < 13; i++)
+ {
+ string formatted = dt.ToString(ci.DateTimeFormat.LongDatePattern, ci);
+ Assert.Equal(dt, DateTime.ParseExact(formatted, ci.DateTimeFormat.LongDatePattern, ci));
+ dt = ci.DateTimeFormat.Calendar.AddMonths(dt, 1);
+ }
+
+ dt = ci.DateTimeFormat.Calendar.ToDateTime(5778, 1, 1, 0, 0, 0, 0); // non leap year
+ for (int i = 0; i < 12; i++)
+ {
+ string formatted = dt.ToString(ci.DateTimeFormat.LongDatePattern, ci);
+ Assert.Equal(dt, DateTime.ParseExact(formatted, ci.DateTimeFormat.LongDatePattern, ci));
+ dt = ci.DateTimeFormat.Calendar.AddMonths(dt, 1);
+ }
}
}
}
diff --git a/src/System.Globalization/tests/Invariant/InvariantMode.cs b/src/System.Globalization/tests/Invariant/InvariantMode.cs
index ed232637c2..a6c4854f81 100644
--- a/src/System.Globalization/tests/Invariant/InvariantMode.cs
+++ b/src/System.Globalization/tests/Invariant/InvariantMode.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
+using System.Collections;
using System.Text;
using Xunit;
@@ -71,7 +72,7 @@ namespace System.Globalization.Tests
yield return new object[] { "a", "A", 0, 1, CompareOptions.Ordinal, -1 };
yield return new object[] { "abc", "aBc", 0, 3, CompareOptions.Ordinal, -1 };
- // Ordinal with numbers and
+ // Ordinal with numbers and
yield return new object[] { "a", "1", 0, 1, CompareOptions.Ordinal, -1 };
yield return new object[] { "1", "1", 0, 1, CompareOptions.Ordinal, 0 };
yield return new object[] { "1", "!", 0, 1, CompareOptions.Ordinal, -1 };
@@ -144,7 +145,7 @@ namespace System.Globalization.Tests
yield return new object[] { "foobardzsdzs", "rddzs", 11, 12, CompareOptions.None, -1 };
yield return new object[] { "foobardzsdzs", "rddzs", 11, 12, CompareOptions.Ordinal, -1 };
- // Turkish
+ // Turkish
yield return new object[] { "Hi", "I", 1, 2, CompareOptions.None, -1 };
yield return new object[] { "Hi", "I", 1, 2, CompareOptions.IgnoreCase, 1 };
yield return new object[] { "Hi", "\u0130", 1, 2, CompareOptions.None, -1 };
@@ -190,7 +191,7 @@ namespace System.Globalization.Tests
yield return new object[] { "dzsdzsfoobar", "ddzsf", CompareOptions.Ordinal, false };
yield return new object[] { "dzsdzsfoobar", "ddzsf", CompareOptions.Ordinal, false };
- // Turkish
+ // Turkish
yield return new object[] { "interesting", "I", CompareOptions.None, false };
yield return new object[] { "interesting", "I", CompareOptions.IgnoreCase, true };
yield return new object[] { "interesting", "\u0130", CompareOptions.None, false };
@@ -227,7 +228,7 @@ namespace System.Globalization.Tests
yield return new object[] { "foobardzsdzs", "rddzs", CompareOptions.Ordinal, false };
yield return new object[] { "foobardzsdzs", "rddzs", CompareOptions.None, false };
- // Turkish
+ // Turkish
yield return new object[] { "Hi", "I", CompareOptions.None, false };
yield return new object[] { "Hi", "I", CompareOptions.IgnoreCase, true };
yield return new object[] { "Hi", "\u0130", CompareOptions.None, false };
@@ -245,7 +246,7 @@ namespace System.Globalization.Tests
yield return new object[] { "More Test's", "Tests", CompareOptions.IgnoreSymbols, false };
yield return new object[] { "More Test's", "Tests", CompareOptions.None, false };
- // Platform differences
+ // Platform differences
yield return new object[] { "foobardzsdzs", "rddzs", CompareOptions.None, false };
}
@@ -374,10 +375,10 @@ namespace System.Globalization.Tests
yield return new object[] { "this \t HaS \t somE \t TABS", "THIS \t HAS \t SOME \t TABS", true };
yield return new object[] { "embedded\0NuLL\0Byte\0", "EMBEDDED\0NULL\0BYTE\0", true };
-
+
// LATIN SMALL LETTER O WITH ACUTE, which has an upper case variant.
yield return new object[] { "\u00F3", "\u00D3", false };
-
+
// SNOWMAN, which does not have an upper case variant.
yield return new object[] { "\u2603", "\u2603", true };
@@ -438,7 +439,7 @@ namespace System.Globalization.Tests
{
yield return new object[] { "xn--yda", 0, 7, "\u0101" };
yield return new object[] { "axn--ydab", 1, 7, "\u0101" };
-
+
yield return new object[] { "xn--aa-cla", 0, 10, "\u0101\u0061a" };
yield return new object[] { "xn--ab-dla", 0, 10, "\u0061\u0101\u0062" };
yield return new object[] { "xn--ab-ela", 0, 10, "\u0061\u0062\u0101" };
@@ -453,10 +454,10 @@ namespace System.Globalization.Tests
yield return new object[] { "abc.xn--d9juau41awczczp.xn--de-jg4avhby1noc0d", 0, 45, "\u0061\u0062\u0063.\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067.\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0" }; // Fully qualified domain name
// Embedded domain name conversion (NLS + only)(Priority 1)
- // Per the spec [7], "The index and count parameters (when provided) allow the
- // conversion to be done on a larger string where the domain name is embedded
- // (such as a URI or IRI). The output string is only the converted FQDN or
- // label, not the whole input string (if the input string contains more
+ // Per the spec [7], "The index and count parameters (when provided) allow the
+ // conversion to be done on a larger string where the domain name is embedded
+ // (such as a URI or IRI). The output string is only the converted FQDN or
+ // label, not the whole input string (if the input string contains more
// character than the substring to convert)."
// Fully Qualified Domain Name (Label1.Label2.Label3)
yield return new object[] { "abc.xn--d9juau41awczczp.xn--de-jg4avhby1noc0d", 0, 45, "\u0061\u0062\u0063.\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067.\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0" };
@@ -476,7 +477,7 @@ namespace System.Globalization.Tests
//
// DateTimeInfo
- //
+ //
Assert.Equal(CultureInfo.InvariantCulture.DateTimeFormat.AbbreviatedDayNames, ci.DateTimeFormat.AbbreviatedDayNames);
Assert.Equal(CultureInfo.InvariantCulture.DateTimeFormat.AbbreviatedMonthGenitiveNames, ci.DateTimeFormat.AbbreviatedMonthGenitiveNames);
@@ -523,7 +524,7 @@ namespace System.Globalization.Tests
//
// Culture data
- //
+ //
Assert.True(ci.Calendar is GregorianCalendar);
@@ -692,7 +693,7 @@ namespace System.Globalization.Tests
}
}
-
+
[Theory]
[MemberData(nameof(Compare_TestData))]
public void TestCompare(string source, string value, CompareOptions options, int result)
@@ -784,5 +785,14 @@ namespace System.Globalization.Tests
}
Assert.Equal(expected, new IdnMapping().GetUnicode(ascii, index, count));
}
+
+ [Fact]
+ public void TestHashing()
+ {
+ StringComparer cultureComparer = StringComparer.Create(CultureInfo.GetCultureInfo("tr-TR"), true);
+ StringComparer ordinalComparer = StringComparer.OrdinalIgnoreCase;
+ string turkishString = "i\u0130";
+ Assert.Equal(ordinalComparer.GetHashCode(turkishString), cultureComparer.GetHashCode(turkishString));
+ }
}
} \ No newline at end of file
diff --git a/src/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoCurrencyNegativePattern.cs b/src/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoCurrencyNegativePattern.cs
index c6960c612a..1e436d29c5 100644
--- a/src/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoCurrencyNegativePattern.cs
+++ b/src/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoCurrencyNegativePattern.cs
@@ -13,7 +13,7 @@ namespace System.Globalization.Tests
public static IEnumerable<object[]> CurrencyNegativePattern_TestData()
{
yield return new object[] { NumberFormatInfo.InvariantInfo, new int[] { 0 } };
- yield return new object[] { CultureInfo.GetCultureInfo("bg-BG").NumberFormat, new int[] { 8 } };
+ yield return new object[] { CultureInfo.GetCultureInfo("bg-BG").NumberFormat, new int[] { 0, 8 } };
}
[Theory]
diff --git a/src/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoData.cs b/src/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoData.cs
index 675de22d56..e6500c9741 100644
--- a/src/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoData.cs
+++ b/src/System.Globalization/tests/NumberFormatInfo/NumberFormatInfoData.cs
@@ -39,10 +39,14 @@ namespace System.Globalization.Tests
{
return (PlatformDetection.WindowsVersion < 10) ? new int[] { 3 } : new int[] { 6, 3 };
}
- if (PlatformDetection.ICUVersion.Major >= 59)
+ if (PlatformDetection.ICUVersion.Major == 59 || PlatformDetection.ICUVersion.Major == 58)
{
return new int[] { 8 };
}
+ else if (PlatformDetection.ICUVersion.Major > 59)
+ {
+ return new int[] { 1 };
+ }
else
{
return new int[] { 1, 0 };
diff --git a/src/System.Globalization/tests/RegionInfo/RegionInfoTests.Properties.cs b/src/System.Globalization/tests/RegionInfo/RegionInfoTests.Properties.cs
index f3f607da1c..b88677a39a 100644
--- a/src/System.Globalization/tests/RegionInfo/RegionInfoTests.Properties.cs
+++ b/src/System.Globalization/tests/RegionInfo/RegionInfoTests.Properties.cs
@@ -101,22 +101,22 @@ namespace System.Globalization.Tests
yield return new object[] { 0x409, 244, "US Dollar", "US Dollar", "\u0055\u0053\u0020\u0044\u006f\u006c\u006c\u0061\u0072", "USA", "USA" };
yield return new object[] { 0x411, 122, "Japanese Yen", "Japanese Yen", PlatformDetection.IsWindows ? "\u5186" : "\u65e5\u672c\u5186", "JPN", "JPN" };
yield return new object[] { 0x804, 45, "Chinese Yuan", "PRC Yuan Renminbi", "\u4eba\u6c11\u5e01", "CHN", "CHN" };
- yield return new object[] { 0x401, 205, "Saudi Riyal", "Saudi Riyal", PlatformDetection.IsWindows ?
- "\u0631\u064a\u0627\u0644\u00a0\u0633\u0639\u0648\u062f\u064a" :
- "\u0631\u064a\u0627\u0644\u0020\u0633\u0639\u0648\u062f\u064a",
+ yield return new object[] { 0x401, 205, "Saudi Riyal", "Saudi Riyal", PlatformDetection.IsWindows ?
+ "\u0631\u064a\u0627\u0644\u00a0\u0633\u0639\u0648\u062f\u064a" :
+ "\u0631\u064a\u0627\u0644\u0020\u0633\u0639\u0648\u062f\u064a",
"SAU", "SAU" };
yield return new object[] { 0x412, 134, "South Korean Won", "Korean Won", PlatformDetection.IsWindows ? "\uc6d0" : "\ub300\ud55c\ubbfc\uad6d\u0020\uc6d0", "KOR", "KOR" };
- yield return new object[] { 0x40d, 117, "Israeli New Shekel", "Israeli New Sheqel",
- PlatformDetection.IsWindows || PlatformDetection.ICUVersion.Major >= 59 ? "\u05e9\u05e7\u05dc\u0020\u05d7\u05d3\u05e9" : "\u05e9\u05f4\u05d7", "ISR", "ISR" };
+ yield return new object[] { 0x40d, 117, "Israeli New Shekel", "Israeli New Sheqel",
+ PlatformDetection.IsWindows || PlatformDetection.ICUVersion.Major >= 58 ? "\u05e9\u05e7\u05dc\u0020\u05d7\u05d3\u05e9" : "\u05e9\u05f4\u05d7", "ISR", "ISR" };
}
-
+
[Theory]
[MemberData(nameof(RegionInfo_TestData))]
public void MiscTest(int lcid, int geoId, string currencyEnglishName, string alternativeCurrencyEnglishName, string currencyNativeName, string threeLetterISORegionName, string threeLetterWindowsRegionName)
{
RegionInfo ri = new RegionInfo(lcid); // create it with lcid
Assert.Equal(geoId, ri.GeoId);
- Assert.True(currencyEnglishName.Equals(ri.CurrencyEnglishName) ||
+ Assert.True(currencyEnglishName.Equals(ri.CurrencyEnglishName) ||
alternativeCurrencyEnglishName.Equals(ri.CurrencyEnglishName), "Wrong currency English Name");
Assert.Equal(currencyNativeName, ri.CurrencyNativeName);
Assert.Equal(threeLetterISORegionName, ri.ThreeLetterISORegionName);
diff --git a/src/System.Globalization/tests/System.Globalization.Tests.csproj b/src/System.Globalization/tests/System.Globalization.Tests.csproj
index c2d018ce07..370125fa28 100644
--- a/src/System.Globalization/tests/System.Globalization.Tests.csproj
+++ b/src/System.Globalization/tests/System.Globalization.Tests.csproj
@@ -5,9 +5,12 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ProjectGuid>{484C92C6-6D2C-45BC-A5E2-4A12BA228E1E}</ProjectGuid>
<DefineConstants Condition="'$(TargetGroup)' == 'uap'">$(DefineConstants);uap</DefineConstants>
+ <DefineConstants Condition="'$(TargetGroup)' == 'netcoreapp'">$(DefineConstants);netcoreapp</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Release|AnyCPU'" />
<ItemGroup>
diff --git a/src/System.IO.Compression.Brotli/System.IO.Compression.Brotli.sln b/src/System.IO.Compression.Brotli/System.IO.Compression.Brotli.sln
index 3ed36c84f9..6f2cf74076 100644
--- a/src/System.IO.Compression.Brotli/System.IO.Compression.Brotli.sln
+++ b/src/System.IO.Compression.Brotli/System.IO.Compression.Brotli.sln
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27019.1
+# Visual Studio 14
+VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.IO.Compression.Brotli.Tests", "tests\System.IO.Compression.Brotli.Tests.csproj", "{BC2E1649-291D-412E-9529-EDDA94FA7AD6}"
ProjectSection(ProjectDependencies) = postProject
@@ -35,10 +35,10 @@ Global
{BC2E1649-291D-412E-9529-EDDA94FA7AD6}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
{BC2E1649-291D-412E-9529-EDDA94FA7AD6}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
{BC2E1649-291D-412E-9529-EDDA94FA7AD6}.Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU
- {1341F8C8-637A-49A1-BE0F-13867A634929}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
- {1341F8C8-637A-49A1-BE0F-13867A634929}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
- {1341F8C8-637A-49A1-BE0F-13867A634929}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
- {1341F8C8-637A-49A1-BE0F-13867A634929}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
+ {1341F8C8-637A-49A1-BE0F-13867A634929}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU
+ {1341F8C8-637A-49A1-BE0F-13867A634929}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
+ {1341F8C8-637A-49A1-BE0F-13867A634929}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
+ {1341F8C8-637A-49A1-BE0F-13867A634929}.Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU
{5471BFE8-8071-466F-838E-5ADAA779E742}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU
{5471BFE8-8071-466F-838E-5ADAA779E742}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
{5471BFE8-8071-466F-838E-5ADAA779E742}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
@@ -57,7 +57,4 @@ Global
{5471BFE8-8071-466F-838E-5ADAA779E742} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD}
{4ADD9456-A929-4254-B8A2-16FC628ABFDA} = {2E666815-2EDB-464B-9DF6-380BF4789AD4}
EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {75F1E532-877F-4DA2-A21D-C8C20EBAD777}
- EndGlobalSection
EndGlobal
diff --git a/src/System.IO.Compression.Brotli/ref/System.IO.Compression.Brotli.cs b/src/System.IO.Compression.Brotli/ref/System.IO.Compression.Brotli.cs
index 4c4b0b407e..dd1990703e 100644
--- a/src/System.IO.Compression.Brotli/ref/System.IO.Compression.Brotli.cs
+++ b/src/System.IO.Compression.Brotli/ref/System.IO.Compression.Brotli.cs
@@ -39,13 +39,13 @@ namespace System.IO.Compression
public override void Flush() { }
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState) { throw null; }
public override int EndRead(IAsyncResult asyncResult) { throw null; }
- public override int Read(byte[] array, int offset, int count) { throw null; }
- public override System.Threading.Tasks.Task<int> ReadAsync(byte[] array, int offset, int count, System.Threading.CancellationToken cancellationToken) { throw null; }
+ public override int Read(byte[] buffer, int offset, int count) { throw null; }
+ public override System.Threading.Tasks.Task<int> ReadAsync(byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) { throw null; }
public override long Seek(long offset, System.IO.SeekOrigin origin) { throw null; }
public override void SetLength(long value) { }
- public override IAsyncResult BeginWrite(byte[] array, int offset, int count, AsyncCallback asyncCallback, object asyncState) { throw null; }
+ public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState) { throw null; }
public override void EndWrite(IAsyncResult asyncResult) { }
- public override void Write(byte[] array, int offset, int count) { }
- public override System.Threading.Tasks.Task WriteAsync(byte[] array, int offset, int count, System.Threading.CancellationToken cancellationToken) { throw null; }
+ public override void Write(byte[] buffer, int offset, int count) { }
+ public override System.Threading.Tasks.Task WriteAsync(byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) { throw null; }
}
}
diff --git a/src/System.IO.Compression.Brotli/src/System/IO/Compression/dec/BrotliStream.Decompress.cs b/src/System.IO.Compression.Brotli/src/System/IO/Compression/dec/BrotliStream.Decompress.cs
index 4e15f1c625..efed64e712 100644
--- a/src/System.IO.Compression.Brotli/src/System/IO/Compression/dec/BrotliStream.Decompress.cs
+++ b/src/System.IO.Compression.Brotli/src/System/IO/Compression/dec/BrotliStream.Decompress.cs
@@ -18,7 +18,7 @@ namespace System.IO.Compression
return Read(new Span<byte>(buffer, offset, count));
}
- public override int Read(Span<byte> destination)
+ public override int Read(Span<byte> buffer)
{
if (_mode != CompressionMode.Decompress)
throw new InvalidOperationException(SR.BrotliStream_Compress_UnsupportedOperation);
@@ -27,7 +27,7 @@ namespace System.IO.Compression
Span<byte> source = Span<byte>.Empty;
OperationStatus lastResult = OperationStatus.DestinationTooSmall;
// We want to continue calling Decompress until we're either out of space for output or until Decompress indicates it is finished.
- while (destination.Length > 0 && lastResult != OperationStatus.Done)
+ while (buffer.Length > 0 && lastResult != OperationStatus.Done)
{
int bytesConsumed = 0;
int bytesWritten = 0;
@@ -53,7 +53,7 @@ namespace System.IO.Compression
source = new Span<byte>(_buffer, 0, readBytes);
}
- lastResult = _decoder.Decompress(source, destination, out bytesConsumed, out bytesWritten);
+ lastResult = _decoder.Decompress(source, buffer, out bytesConsumed, out bytesWritten);
if (lastResult == OperationStatus.InvalidData)
throw new InvalidOperationException(SR.BrotliStream_Decompress_InvalidData);
if (bytesConsumed > 0)
@@ -61,7 +61,7 @@ namespace System.IO.Compression
if (bytesWritten > 0)
{
totalWritten += bytesWritten;
- destination = destination.Slice(bytesWritten);
+ buffer = buffer.Slice(bytesWritten);
}
}
@@ -74,13 +74,13 @@ namespace System.IO.Compression
public override int EndRead(IAsyncResult asyncResult) =>
TaskToApm.End<int>(asyncResult);
- public override Task<int> ReadAsync(byte[] array, int offset, int count, CancellationToken cancellationToken)
+ public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
- ValidateParameters(array, offset, count);
- return ReadAsync(new Memory<byte>(array, offset, count), cancellationToken).AsTask();
+ ValidateParameters(buffer, offset, count);
+ return ReadAsync(new Memory<byte>(buffer, offset, count), cancellationToken).AsTask();
}
- public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken = default(CancellationToken))
+ public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default(CancellationToken))
{
if (_mode != CompressionMode.Decompress)
throw new InvalidOperationException(SR.BrotliStream_Compress_UnsupportedOperation);
@@ -91,10 +91,10 @@ namespace System.IO.Compression
{
return new ValueTask<int>(Task.FromCanceled<int>(cancellationToken));
}
- return FinishReadAsyncMemory(destination, cancellationToken);
+ return FinishReadAsyncMemory(buffer, cancellationToken);
}
- private async ValueTask<int> FinishReadAsyncMemory(Memory<byte> destination, CancellationToken cancellationToken)
+ private async ValueTask<int> FinishReadAsyncMemory(Memory<byte> buffer, CancellationToken cancellationToken)
{
AsyncOperationStarting();
try
@@ -103,7 +103,7 @@ namespace System.IO.Compression
Memory<byte> source = Memory<byte>.Empty;
OperationStatus lastResult = OperationStatus.DestinationTooSmall;
// We want to continue calling Decompress until we're either out of space for output or until Decompress indicates it is finished.
- while (destination.Length > 0 && lastResult != OperationStatus.Done)
+ while (buffer.Length > 0 && lastResult != OperationStatus.Done)
{
int bytesConsumed = 0;
@@ -113,7 +113,7 @@ namespace System.IO.Compression
{
int readBytes = 0;
int iter = 0;
- while (readBytes < _buffer.Length && ((iter = await _stream.ReadAsync(_buffer, readBytes, _buffer.Length - readBytes, cancellationToken).ConfigureAwait(false)) > 0))
+ while (readBytes < _buffer.Length && ((iter = await _stream.ReadAsync(new Memory<byte>(_buffer, readBytes, _buffer.Length - readBytes), cancellationToken).ConfigureAwait(false)) > 0))
{
readBytes += iter;
if (readBytes > _buffer.Length)
@@ -131,7 +131,7 @@ namespace System.IO.Compression
}
cancellationToken.ThrowIfCancellationRequested();
- lastResult = _decoder.Decompress(source, destination, out bytesConsumed, out bytesWritten);
+ lastResult = _decoder.Decompress(source, buffer, out bytesConsumed, out bytesWritten);
if (lastResult == OperationStatus.InvalidData)
throw new InvalidOperationException(SR.BrotliStream_Decompress_InvalidData);
if (bytesConsumed > 0)
@@ -139,7 +139,7 @@ namespace System.IO.Compression
if (bytesWritten > 0)
{
totalWritten += bytesWritten;
- destination = destination.Slice(bytesWritten);
+ buffer = buffer.Slice(bytesWritten);
}
}
diff --git a/src/System.IO.Compression.Brotli/src/System/IO/Compression/enc/BrotliStream.Compress.cs b/src/System.IO.Compression.Brotli/src/System/IO/Compression/enc/BrotliStream.Compress.cs
index 5f2ecd1b6b..0770c46989 100644
--- a/src/System.IO.Compression.Brotli/src/System/IO/Compression/enc/BrotliStream.Compress.cs
+++ b/src/System.IO.Compression.Brotli/src/System/IO/Compression/enc/BrotliStream.Compress.cs
@@ -24,12 +24,12 @@ namespace System.IO.Compression
WriteCore(new ReadOnlySpan<byte>(buffer, offset, count));
}
- public override void Write(ReadOnlySpan<byte> source)
+ public override void Write(ReadOnlySpan<byte> buffer)
{
- WriteCore(source);
+ WriteCore(buffer);
}
- internal void WriteCore(ReadOnlySpan<byte> source, bool isFinalBlock = false)
+ internal void WriteCore(ReadOnlySpan<byte> buffer, bool isFinalBlock = false)
{
if (_mode != CompressionMode.Compress)
throw new InvalidOperationException(SR.BrotliStream_Decompress_UnsupportedOperation);
@@ -41,41 +41,41 @@ namespace System.IO.Compression
{
int bytesConsumed = 0;
int bytesWritten = 0;
- lastResult = _encoder.Compress(source, output, out bytesConsumed, out bytesWritten, isFinalBlock);
+ lastResult = _encoder.Compress(buffer, output, out bytesConsumed, out bytesWritten, isFinalBlock);
if (lastResult == OperationStatus.InvalidData)
throw new InvalidOperationException(SR.BrotliStream_Compress_InvalidData);
if (bytesWritten > 0)
_stream.Write(output.Slice(0, bytesWritten));
if (bytesConsumed > 0)
- source = source.Slice(bytesConsumed);
+ buffer = buffer.Slice(bytesConsumed);
}
}
- public override IAsyncResult BeginWrite(byte[] array, int offset, int count, AsyncCallback asyncCallback, object asyncState) =>
- TaskToApm.Begin(WriteAsync(array, offset, count, CancellationToken.None), asyncCallback, asyncState);
+ public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState) =>
+ TaskToApm.Begin(WriteAsync(buffer, offset, count, CancellationToken.None), asyncCallback, asyncState);
public override void EndWrite(IAsyncResult asyncResult) =>
TaskToApm.End(asyncResult);
- public override Task WriteAsync(byte[] array, int offset, int count, CancellationToken cancellationToken)
+ public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
- ValidateParameters(array, offset, count);
- return WriteAsync(new ReadOnlyMemory<byte>(array, offset, count), cancellationToken);
+ ValidateParameters(buffer, offset, count);
+ return WriteAsync(new ReadOnlyMemory<byte>(buffer, offset, count), cancellationToken).AsTask();
}
- public override Task WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken = default(CancellationToken))
+ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default(CancellationToken))
{
if (_mode != CompressionMode.Compress)
throw new InvalidOperationException(SR.BrotliStream_Decompress_UnsupportedOperation);
EnsureNoActiveAsyncOperation();
EnsureNotDisposed();
- return cancellationToken.IsCancellationRequested ?
+ return new ValueTask(cancellationToken.IsCancellationRequested ?
Task.FromCanceled<int>(cancellationToken) :
- WriteAsyncMemoryCore(source, cancellationToken);
+ WriteAsyncMemoryCore(buffer, cancellationToken));
}
- private async Task WriteAsyncMemoryCore(ReadOnlyMemory<byte> source, CancellationToken cancellationToken)
+ private async Task WriteAsyncMemoryCore(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken)
{
AsyncOperationStarting();
try
@@ -86,13 +86,13 @@ namespace System.IO.Compression
Memory<byte> output = new Memory<byte>(_buffer);
int bytesConsumed = 0;
int bytesWritten = 0;
- lastResult = _encoder.Compress(source, output, out bytesConsumed, out bytesWritten, isFinalBlock: false);
+ lastResult = _encoder.Compress(buffer, output, out bytesConsumed, out bytesWritten, isFinalBlock: false);
if (lastResult == OperationStatus.InvalidData)
throw new InvalidOperationException(SR.BrotliStream_Compress_InvalidData);
if (bytesConsumed > 0)
- source = source.Slice(bytesConsumed);
+ buffer = buffer.Slice(bytesConsumed);
if (bytesWritten > 0)
- await _stream.WriteAsync(_buffer, 0, bytesWritten, cancellationToken).ConfigureAwait(false);
+ await _stream.WriteAsync(new ReadOnlyMemory<byte>(_buffer, 0, bytesWritten), cancellationToken).ConfigureAwait(false);
}
}
finally
diff --git a/src/System.IO.Compression.Brotli/tests/CompressionStreamUnitTests.Brotli.cs b/src/System.IO.Compression.Brotli/tests/CompressionStreamUnitTests.Brotli.cs
index e7323ff936..84db45dc53 100644
--- a/src/System.IO.Compression.Brotli/tests/CompressionStreamUnitTests.Brotli.cs
+++ b/src/System.IO.Compression.Brotli/tests/CompressionStreamUnitTests.Brotli.cs
@@ -34,10 +34,6 @@ namespace System.IO.Compression
}
[Fact]
- [OuterLoop("Test takes ~12 seconds to run")]
- public override void Dispose_WithUnfinishedWriteAsync() { base.Dispose_WithUnfinishedWriteAsync(); }
-
- [Fact]
[OuterLoop("Test takes ~6 seconds to run")]
public override void FlushAsync_DuringWriteAsync() { base.FlushAsync_DuringWriteAsync(); }
diff --git a/src/System.IO.Compression.Brotli/tests/Performance/BrotliPerfTests.cs b/src/System.IO.Compression.Brotli/tests/Performance/BrotliPerfTests.cs
index f0ee2b7d22..410b6cc14b 100644
--- a/src/System.IO.Compression.Brotli/tests/Performance/BrotliPerfTests.cs
+++ b/src/System.IO.Compression.Brotli/tests/Performance/BrotliPerfTests.cs
@@ -12,67 +12,48 @@ namespace System.IO.Compression
{
protected override string CompressedTestFile(string uncompressedPath) => Path.Combine("BrotliTestData", Path.GetFileName(uncompressedPath) + ".br");
- public static IEnumerable<object[]> CanterburyCorpus_WithCompressionLevel()
+ public static IEnumerable<object[]> UncompressedTestFiles_WithCompressionLevel()
{
foreach (CompressionLevel compressionLevel in Enum.GetValues(typeof(CompressionLevel)))
{
- foreach (object[] canterburyWithoutLevel in CanterburyCorpus())
+ foreach (object[] testFile in UncompressedTestFiles())
{
- yield return new object[] { canterburyWithoutLevel[0], canterburyWithoutLevel[1], compressionLevel };
+ yield return new object[] { testFile[0], compressionLevel };
}
}
}
- public static IEnumerable<object[]> CanterburyCorpus()
- {
- foreach (int innerIterations in new int[] { 1, 10 })
- {
- foreach (var fileName in UncompressedTestFiles())
- {
- yield return new object[] { innerIterations, fileName[0] };
- }
- }
- }
-
- [Benchmark]
- [MemberData(nameof(CanterburyCorpus_WithCompressionLevel))]
- public void Compress_Canterbury_WithState(int innerIterations, string uncompressedFileName, CompressionLevel compressLevel)
+ [Benchmark(InnerIterationCount=10)] // limits the max iterations to 100
+ [MemberData(nameof(UncompressedTestFiles_WithCompressionLevel))]
+ public void Compress_Canterbury_WithState(string uncompressedFileName, CompressionLevel compressLevel)
{
byte[] bytes = File.ReadAllBytes(uncompressedFileName);
ReadOnlySpan<byte> uncompressedData = new ReadOnlySpan<byte>(bytes);
int maxCompressedSize = BrotliEncoder.GetMaxCompressedLength(bytes.Length);
- List<byte[]> compressedDataArrays = new List<byte[]>(innerIterations);
+ byte[] compressedDataArray = new byte[maxCompressedSize];
foreach (var iteration in Benchmark.Iterations)
{
- for (int i = 0; i < innerIterations; i++)
- {
- compressedDataArrays.Add(new byte[maxCompressedSize]);
- }
using (iteration.StartMeasurement())
+ using (BrotliEncoder encoder = new BrotliEncoder())
{
- for (int i = 0; i < innerIterations; i++)
+ Span<byte> output = new Span<byte>(compressedDataArray);
+ ReadOnlySpan<byte> input = uncompressedData;
+ while (!input.IsEmpty && !output.IsEmpty)
{
- using (BrotliEncoder encoder = new BrotliEncoder())
- {
- Span<byte> output = new Span<byte>(compressedDataArrays[i]);
- ReadOnlySpan<byte> input = uncompressedData;
- while (!input.IsEmpty && !output.IsEmpty)
- {
- encoder.Compress(input, output, out int bytesConsumed, out int written, isFinalBlock:false);
- input = input.Slice(bytesConsumed);
- output = output.Slice(written);
- }
- encoder.Compress(input, output, out int bytesConsumed2, out int written2, isFinalBlock: true);
- }
+ encoder.Compress(input, output, out int bytesConsumed, out int written, isFinalBlock:false);
+ input = input.Slice(bytesConsumed);
+ output = output.Slice(written);
}
+ encoder.Compress(input, output, out int bytesConsumed2, out int written2, isFinalBlock: true);
}
}
}
- [Benchmark]
- [MemberData(nameof(CanterburyCorpus))]
- public void Decompress_Canterbury_WithState(int innerIterations, string uncompressedFileName)
+ [Benchmark(InnerIterationCount=100)]
+ [MemberData(nameof(UncompressedTestFiles))]
+ public void Decompress_Canterbury_WithState(string uncompressedFileName)
{
+ int innerIterations = (int)Benchmark.InnerIterationCount;
byte[] compressedBytes = File.ReadAllBytes(CompressedTestFile(uncompressedFileName));
ReadOnlySpan<byte> compressedData = new ReadOnlySpan<byte>(compressedBytes);
List<byte[]> uncompressedDataArrays = new List<byte[]>(innerIterations);
@@ -102,27 +83,20 @@ namespace System.IO.Compression
}
}
- [Benchmark]
- [MemberData(nameof(CanterburyCorpus_WithCompressionLevel))]
- public void Compress_Canterbury_WithoutState(int innerIterations, string uncompressedFileName, CompressionLevel compressLevel)
+ [Benchmark(InnerIterationCount=10)] // limits the max iterations to 100
+ [MemberData(nameof(UncompressedTestFiles_WithCompressionLevel))]
+ public void Compress_Canterbury_WithoutState(string uncompressedFileName, CompressionLevel compressLevel)
{
byte[] bytes = File.ReadAllBytes(uncompressedFileName);
ReadOnlySpan<byte> uncompressedData = new ReadOnlySpan<byte>(bytes);
int maxCompressedSize = BrotliEncoder.GetMaxCompressedLength(bytes.Length);
- List<byte[]> compressedDataArrays = new List<byte[]>(innerIterations);
+ byte[] compressedDataArray = new byte[maxCompressedSize];
int compressLevelBrotli = compressLevel == CompressionLevel.Optimal ? 11 : compressLevel == CompressionLevel.Fastest ? 1 : 0;
foreach (var iteration in Benchmark.Iterations)
{
- for (int i = 0; i < innerIterations; i++)
- {
- compressedDataArrays.Add(new byte[maxCompressedSize]);
- }
using (iteration.StartMeasurement())
{
- for (int i = 0; i < innerIterations; i++)
- {
- Assert.True(BrotliEncoder.TryCompress(uncompressedData, compressedDataArrays[i], out int bytesWritten, compressLevelBrotli, 22));
- }
+ Assert.True(BrotliEncoder.TryCompress(uncompressedData, compressedDataArray, out int bytesWritten, compressLevelBrotli, 22));
}
}
}
@@ -131,10 +105,11 @@ namespace System.IO.Compression
/// The perf tests for the instant decompression aren't exactly indicative of real-world scenarios since they require you to know
/// either the exact figure or the upper bound of the uncompressed size of your given compressed data.
/// </summary>
- [Benchmark]
- [MemberData(nameof(CanterburyCorpus))]
- public void Decompress_Canterbury_WithoutState(int innerIterations, string uncompressedFileName)
+ [Benchmark(InnerIterationCount=100)]
+ [MemberData(nameof(UncompressedTestFiles))]
+ public void Decompress_Canterbury_WithoutState(string uncompressedFileName)
{
+ int innerIterations = (int)Benchmark.InnerIterationCount;
byte[] compressedBytes = File.ReadAllBytes(CompressedTestFile(uncompressedFileName));
ReadOnlySpan<byte> compressedData = new ReadOnlySpan<byte>(compressedBytes);
int uncompressedSize = (int)new FileInfo(uncompressedFileName).Length;
@@ -153,6 +128,6 @@ namespace System.IO.Compression
}
}
}
- }
+ }
}
}
diff --git a/src/System.IO.Compression.ZipFile/tests/ZipFileInvalidFileTests.cs b/src/System.IO.Compression.ZipFile/tests/ZipFileInvalidFileTests.cs
index 9adfacdf30..53de201339 100644
--- a/src/System.IO.Compression.ZipFile/tests/ZipFileInvalidFileTests.cs
+++ b/src/System.IO.Compression.ZipFile/tests/ZipFileInvalidFileTests.cs
@@ -243,6 +243,7 @@ namespace System.IO.Compression.Tests
/// when an attempt is made to extract them.
/// </summary>
[Theory]
+ [ActiveIssue(27269)]
[InlineData("WindowsInvalid_FromUnix", null)]
[InlineData("WindowsInvalid_FromWindows", null)]
[InlineData("NullCharFileName_FromWindows", "path")]
diff --git a/src/System.IO.Compression/System.IO.Compression.sln b/src/System.IO.Compression/System.IO.Compression.sln
index e993165139..a96259a4ec 100644
--- a/src/System.IO.Compression/System.IO.Compression.sln
+++ b/src/System.IO.Compression/System.IO.Compression.sln
@@ -2,22 +2,22 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.IO.Compression.Tests", "tests\System.IO.Compression.Tests.csproj", "{BC2E1649-291D-412E-9529-EDDA94FA7AD6}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.IO.Compression.Tests", "tests\System.IO.Compression.Tests.csproj", "{17DA7FB5-4370-4385-9A02-FFEF9F482903}"
ProjectSection(ProjectDependencies) = postProject
- {5471BFE8-8071-466F-838E-5ADAA779E742} = {5471BFE8-8071-466F-838E-5ADAA779E742}
+ {E9ED0A04-23A8-4F8B-82C1-2B18AF74C870} = {E9ED0A04-23A8-4F8B-82C1-2B18AF74C870}
EndProjectSection
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.IO.Compression.Performance.Tests", "tests\Performance\System.IO.Compression.Performance.Tests.csproj", "{1341F8C8-637A-49A1-BE0F-13867A634929}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.IO.Compression.Performance.Tests", "tests\Performance\System.IO.Compression.Performance.Tests.csproj", "{13C0F956-FB7B-4882-A411-39B8E22463D2}"
ProjectSection(ProjectDependencies) = postProject
- {5471BFE8-8071-466F-838E-5ADAA779E742} = {5471BFE8-8071-466F-838E-5ADAA779E742}
+ {E9ED0A04-23A8-4F8B-82C1-2B18AF74C870} = {E9ED0A04-23A8-4F8B-82C1-2B18AF74C870}
EndProjectSection
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.IO.Compression", "src\System.IO.Compression.csproj", "{5471BFE8-8071-466F-838E-5ADAA779E742}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.IO.Compression", "src\System.IO.Compression.csproj", "{E9ED0A04-23A8-4F8B-82C1-2B18AF74C870}"
ProjectSection(ProjectDependencies) = postProject
- {4ADD9456-A929-4254-B8A2-16FC628ABFDA} = {4ADD9456-A929-4254-B8A2-16FC628ABFDA}
+ {7CBACE0E-E07C-4ADB-A413-ADEC0CACBD43} = {7CBACE0E-E07C-4ADB-A413-ADEC0CACBD43}
EndProjectSection
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.IO.Compression", "ref\System.IO.Compression.csproj", "{4ADD9456-A929-4254-B8A2-16FC628ABFDA}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.IO.Compression", "ref\System.IO.Compression.csproj", "{7CBACE0E-E07C-4ADB-A413-ADEC0CACBD43}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{1A2F9F4A-A032-433E-B914-ADD5992BB178}"
EndProject
@@ -31,30 +31,30 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {BC2E1649-291D-412E-9529-EDDA94FA7AD6}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU
- {BC2E1649-291D-412E-9529-EDDA94FA7AD6}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
- {BC2E1649-291D-412E-9529-EDDA94FA7AD6}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
- {BC2E1649-291D-412E-9529-EDDA94FA7AD6}.Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU
- {1341F8C8-637A-49A1-BE0F-13867A634929}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
- {1341F8C8-637A-49A1-BE0F-13867A634929}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
- {1341F8C8-637A-49A1-BE0F-13867A634929}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
- {1341F8C8-637A-49A1-BE0F-13867A634929}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
- {5471BFE8-8071-466F-838E-5ADAA779E742}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU
- {5471BFE8-8071-466F-838E-5ADAA779E742}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
- {5471BFE8-8071-466F-838E-5ADAA779E742}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
- {5471BFE8-8071-466F-838E-5ADAA779E742}.Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU
- {4ADD9456-A929-4254-B8A2-16FC628ABFDA}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
- {4ADD9456-A929-4254-B8A2-16FC628ABFDA}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
- {4ADD9456-A929-4254-B8A2-16FC628ABFDA}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
- {4ADD9456-A929-4254-B8A2-16FC628ABFDA}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
+ {17DA7FB5-4370-4385-9A02-FFEF9F482903}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU
+ {17DA7FB5-4370-4385-9A02-FFEF9F482903}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
+ {17DA7FB5-4370-4385-9A02-FFEF9F482903}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
+ {17DA7FB5-4370-4385-9A02-FFEF9F482903}.Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU
+ {13C0F956-FB7B-4882-A411-39B8E22463D2}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
+ {13C0F956-FB7B-4882-A411-39B8E22463D2}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
+ {13C0F956-FB7B-4882-A411-39B8E22463D2}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
+ {13C0F956-FB7B-4882-A411-39B8E22463D2}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
+ {E9ED0A04-23A8-4F8B-82C1-2B18AF74C870}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU
+ {E9ED0A04-23A8-4F8B-82C1-2B18AF74C870}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
+ {E9ED0A04-23A8-4F8B-82C1-2B18AF74C870}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
+ {E9ED0A04-23A8-4F8B-82C1-2B18AF74C870}.Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU
+ {7CBACE0E-E07C-4ADB-A413-ADEC0CACBD43}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
+ {7CBACE0E-E07C-4ADB-A413-ADEC0CACBD43}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
+ {7CBACE0E-E07C-4ADB-A413-ADEC0CACBD43}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
+ {7CBACE0E-E07C-4ADB-A413-ADEC0CACBD43}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
- {BC2E1649-291D-412E-9529-EDDA94FA7AD6} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
- {1341F8C8-637A-49A1-BE0F-13867A634929} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
- {5471BFE8-8071-466F-838E-5ADAA779E742} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD}
- {4ADD9456-A929-4254-B8A2-16FC628ABFDA} = {2E666815-2EDB-464B-9DF6-380BF4789AD4}
+ {17DA7FB5-4370-4385-9A02-FFEF9F482903} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
+ {13C0F956-FB7B-4882-A411-39B8E22463D2} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
+ {E9ED0A04-23A8-4F8B-82C1-2B18AF74C870} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD}
+ {7CBACE0E-E07C-4ADB-A413-ADEC0CACBD43} = {2E666815-2EDB-464B-9DF6-380BF4789AD4}
EndGlobalSection
EndGlobal
diff --git a/src/System.IO.Compression/ref/System.IO.Compression.csproj b/src/System.IO.Compression/ref/System.IO.Compression.csproj
index aa2e71eca6..246b287407 100644
--- a/src/System.IO.Compression/ref/System.IO.Compression.csproj
+++ b/src/System.IO.Compression/ref/System.IO.Compression.csproj
@@ -2,7 +2,7 @@
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
- <ProjectGuid>{4ADD9456-A929-4254-B8A2-16FC628ABFDA}</ProjectGuid>
+ <ProjectGuid>{7CBACE0E-E07C-4ADB-A413-ADEC0CACBD43}</ProjectGuid>
<IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'netfx'">true</IsPartialFacadeAssembly>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
diff --git a/src/System.IO.Compression/src/MatchingRefApiCompatBaseline.txt b/src/System.IO.Compression/src/MatchingRefApiCompatBaseline.txt
new file mode 100644
index 0000000000..d6c2289aa7
--- /dev/null
+++ b/src/System.IO.Compression/src/MatchingRefApiCompatBaseline.txt
@@ -0,0 +1,2 @@
+# Exposed publicly only in implementation for serialization compat
+TypesMustExist : Type 'System.IO.Compression.ZLibException' does not exist in the implementation but it does exist in the contract.
diff --git a/src/System.IO.Compression/src/System.IO.Compression.csproj b/src/System.IO.Compression/src/System.IO.Compression.csproj
index 9cacdec02a..ea2cc95909 100644
--- a/src/System.IO.Compression/src/System.IO.Compression.csproj
+++ b/src/System.IO.Compression/src/System.IO.Compression.csproj
@@ -4,7 +4,7 @@
<PropertyGroup>
<AssemblyName>System.IO.Compression</AssemblyName>
<OutputType>Library</OutputType>
- <ProjectGuid>{5471BFE8-8071-466F-838E-5ADAA779E742}</ProjectGuid>
+ <ProjectGuid>{E9ED0A04-23A8-4F8B-82C1-2B18AF74C870}</ProjectGuid>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'netfx'">true</IsPartialFacadeAssembly>
</PropertyGroup>
@@ -58,9 +58,6 @@
<Compile Include="System\IO\Compression\ZipArchiveEntry.netcoreapp.cs" />
<Compile Include="System\IO\Compression\ZipCustomStreams.netcoreapp.cs" />
<Compile Include="System\IO\Compression\PositionPreservingWriteOnlyStreamWrapper.netcoreapp.cs" />
- <Compile Include="$(CommonPath)\System\IO\PathInternal.cs">
- <Link>Common\System\IO\PathInternal.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\System\IO\StreamHelpers.CopyValidation.cs">
<Link>Common\System\IO\StreamHelpers.CopyValidation.cs</Link>
</Compile>
diff --git a/src/System.IO.Compression/src/System/IO/Compression/DeflateZLib/DeflateStream.cs b/src/System.IO.Compression/src/System/IO/Compression/DeflateZLib/DeflateStream.cs
index b0ec44a643..853afde461 100644
--- a/src/System.IO.Compression/src/System/IO/Compression/DeflateZLib/DeflateStream.cs
+++ b/src/System.IO.Compression/src/System/IO/Compression/DeflateZLib/DeflateStream.cs
@@ -199,7 +199,7 @@ namespace System.IO.Compression
flushSuccessful = _deflater.Flush(_buffer, out compressedBytes);
if (flushSuccessful)
{
- await _stream.WriteAsync(_buffer, 0, compressedBytes, cancellationToken).ConfigureAwait(false);
+ await _stream.WriteAsync(new ReadOnlyMemory<byte>(_buffer, 0, compressedBytes), cancellationToken).ConfigureAwait(false);
}
Debug.Assert(flushSuccessful == (compressedBytes > 0));
} while (flushSuccessful);
@@ -237,22 +237,22 @@ namespace System.IO.Compression
return ReadCore(new Span<byte>(array, offset, count));
}
- public override int Read(Span<byte> destination)
+ public override int Read(Span<byte> buffer)
{
if (GetType() != typeof(DeflateStream))
{
// DeflateStream is not sealed, and a derived type may have overridden Read(byte[], int, int) prior
// to this Read(Span<byte>) overload being introduced. In that case, this Read(Span<byte>) overload
// should use the behavior of Read(byte[],int,int) overload.
- return base.Read(destination);
+ return base.Read(buffer);
}
else
{
- return ReadCore(destination);
+ return ReadCore(buffer);
}
}
- internal int ReadCore(Span<byte> destination)
+ internal int ReadCore(Span<byte> buffer)
{
EnsureDecompressionMode();
EnsureNotDisposed();
@@ -262,9 +262,9 @@ namespace System.IO.Compression
while (true)
{
- int bytesRead = _inflater.Inflate(destination.Slice(totalRead));
+ int bytesRead = _inflater.Inflate(buffer.Slice(totalRead));
totalRead += bytesRead;
- if (totalRead == destination.Length)
+ if (totalRead == buffer.Length)
{
break;
}
@@ -355,21 +355,21 @@ namespace System.IO.Compression
return ReadAsyncMemory(new Memory<byte>(array, offset, count), cancellationToken).AsTask();
}
- public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken = default(CancellationToken))
+ public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default(CancellationToken))
{
if (GetType() != typeof(DeflateStream))
{
// Ensure that existing streams derived from DeflateStream and that override ReadAsync(byte[],...)
// get their existing behaviors when the newer Memory-based overload is used.
- return base.ReadAsync(destination, cancellationToken);
+ return base.ReadAsync(buffer, cancellationToken);
}
else
{
- return ReadAsyncMemory(destination, cancellationToken);
+ return ReadAsyncMemory(buffer, cancellationToken);
}
}
- internal ValueTask<int> ReadAsyncMemory(Memory<byte> destination, CancellationToken cancellationToken)
+ internal ValueTask<int> ReadAsyncMemory(Memory<byte> buffer, CancellationToken cancellationToken)
{
EnsureDecompressionMode();
EnsureNoActiveAsyncOperation();
@@ -387,7 +387,7 @@ namespace System.IO.Compression
try
{
// Try to read decompressed data in output buffer
- int bytesRead = _inflater.Inflate(destination.Span);
+ int bytesRead = _inflater.Inflate(buffer.Span);
if (bytesRead != 0)
{
// If decompression output buffer is not empty, return immediately.
@@ -404,7 +404,7 @@ namespace System.IO.Compression
// the end of the stream, we need to get more data from the base stream
ValueTask<int> readTask = _stream.ReadAsync(_buffer, cancellationToken);
cleanup = false;
- return FinishReadAsyncMemory(readTask, destination, cancellationToken);
+ return FinishReadAsyncMemory(readTask, buffer, cancellationToken);
}
finally
{
@@ -417,7 +417,7 @@ namespace System.IO.Compression
}
private async ValueTask<int> FinishReadAsyncMemory(
- ValueTask<int> readTask, Memory<byte> destination, CancellationToken cancellationToken)
+ ValueTask<int> readTask, Memory<byte> buffer, CancellationToken cancellationToken)
{
try
{
@@ -442,7 +442,7 @@ namespace System.IO.Compression
// Feed the data from base stream into decompression engine
_inflater.SetInput(_buffer, 0, bytesRead);
- bytesRead = _inflater.Inflate(destination.Span);
+ bytesRead = _inflater.Inflate(buffer.Span);
if (bytesRead == 0 && !_inflater.Finished())
{
@@ -468,22 +468,22 @@ namespace System.IO.Compression
WriteCore(new ReadOnlySpan<byte>(array, offset, count));
}
- public override void Write(ReadOnlySpan<byte> source)
+ public override void Write(ReadOnlySpan<byte> buffer)
{
if (GetType() != typeof(DeflateStream))
{
// DeflateStream is not sealed, and a derived type may have overridden Write(byte[], int, int) prior
// to this Write(ReadOnlySpan<byte>) overload being introduced. In that case, this Write(ReadOnlySpan<byte>) overload
// should use the behavior of Write(byte[],int,int) overload.
- base.Write(source);
+ base.Write(buffer);
}
else
{
- WriteCore(source);
+ WriteCore(buffer);
}
}
- internal void WriteCore(ReadOnlySpan<byte> source)
+ internal void WriteCore(ReadOnlySpan<byte> buffer)
{
EnsureCompressionMode();
EnsureNotDisposed();
@@ -494,9 +494,9 @@ namespace System.IO.Compression
unsafe
{
// Pass new bytes through deflater and write them too:
- fixed (byte* bufferPtr = &MemoryMarshal.GetReference(source))
+ fixed (byte* bufferPtr = &MemoryMarshal.GetReference(buffer))
{
- _deflater.SetInput(bufferPtr, source.Length);
+ _deflater.SetInput(bufferPtr, buffer.Length);
WriteDeflaterOutput();
_wroteBytes = true;
}
@@ -643,35 +643,35 @@ namespace System.IO.Compression
public override Task WriteAsync(byte[] array, int offset, int count, CancellationToken cancellationToken)
{
ValidateParameters(array, offset, count);
- return WriteAsyncMemory(new ReadOnlyMemory<byte>(array, offset, count), cancellationToken);
+ return WriteAsyncMemory(new ReadOnlyMemory<byte>(array, offset, count), cancellationToken).AsTask();
}
- public override Task WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken)
+ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken)
{
if (GetType() != typeof(DeflateStream))
{
// Ensure that existing streams derived from DeflateStream and that override WriteAsync(byte[],...)
// get their existing behaviors when the newer Memory-based overload is used.
- return base.WriteAsync(source, cancellationToken);
+ return base.WriteAsync(buffer, cancellationToken);
}
else
{
- return WriteAsyncMemory(source, cancellationToken);
+ return WriteAsyncMemory(buffer, cancellationToken);
}
}
- internal Task WriteAsyncMemory(ReadOnlyMemory<byte> source, CancellationToken cancellationToken)
+ internal ValueTask WriteAsyncMemory(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken)
{
EnsureCompressionMode();
EnsureNoActiveAsyncOperation();
EnsureNotDisposed();
- return cancellationToken.IsCancellationRequested ?
+ return new ValueTask(cancellationToken.IsCancellationRequested ?
Task.FromCanceled<int>(cancellationToken) :
- WriteAsyncMemoryCore(source, cancellationToken);
+ WriteAsyncMemoryCore(buffer, cancellationToken));
}
- private async Task WriteAsyncMemoryCore(ReadOnlyMemory<byte> source, CancellationToken cancellationToken)
+ private async Task WriteAsyncMemoryCore(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken)
{
AsyncOperationStarting();
try
@@ -679,7 +679,7 @@ namespace System.IO.Compression
await WriteDeflaterOutputAsync(cancellationToken).ConfigureAwait(false);
// Pass new bytes through deflater
- _deflater.SetInput(source);
+ _deflater.SetInput(buffer);
await WriteDeflaterOutputAsync(cancellationToken).ConfigureAwait(false);
@@ -701,7 +701,7 @@ namespace System.IO.Compression
int compressedBytes = _deflater.GetDeflateOutput(_buffer);
if (compressedBytes > 0)
{
- await _stream.WriteAsync(_buffer, 0, compressedBytes, cancellationToken).ConfigureAwait(false);
+ await _stream.WriteAsync(new ReadOnlyMemory<byte>(_buffer, 0, compressedBytes), cancellationToken).ConfigureAwait(false);
}
}
}
@@ -732,7 +732,6 @@ namespace System.IO.Compression
private readonly Stream _destination;
private readonly CancellationToken _cancellationToken;
private byte[] _arrayPoolBuffer;
- private int _arrayPoolBufferHighWaterMark;
public CopyToAsyncStream(DeflateStream deflateStream, Stream destination, int bufferSize, CancellationToken cancellationToken)
{
@@ -757,8 +756,7 @@ namespace System.IO.Compression
int bytesRead = _deflateStream._inflater.Inflate(_arrayPoolBuffer, 0, _arrayPoolBuffer.Length);
if (bytesRead > 0)
{
- if (bytesRead > _arrayPoolBufferHighWaterMark) _arrayPoolBufferHighWaterMark = bytesRead;
- await _destination.WriteAsync(_arrayPoolBuffer, 0, bytesRead, _cancellationToken).ConfigureAwait(false);
+ await _destination.WriteAsync(new ReadOnlyMemory<byte>(_arrayPoolBuffer, 0, bytesRead), _cancellationToken).ConfigureAwait(false);
}
else break;
}
@@ -770,8 +768,7 @@ namespace System.IO.Compression
{
_deflateStream.AsyncOperationCompleting();
- Array.Clear(_arrayPoolBuffer, 0, _arrayPoolBufferHighWaterMark); // clear only the most we used
- ArrayPool<byte>.Shared.Return(_arrayPoolBuffer, clearArray: false);
+ ArrayPool<byte>.Shared.Return(_arrayPoolBuffer);
_arrayPoolBuffer = null;
}
}
@@ -787,7 +784,7 @@ namespace System.IO.Compression
}
else if (count > buffer.Length - offset)
{
- // The source stream is either malicious or poorly implemented and returned a number of
+ // The buffer stream is either malicious or poorly implemented and returned a number of
// bytes larger than the buffer supplied to it.
throw new InvalidDataException(SR.GenericInvalidData);
}
@@ -795,14 +792,13 @@ namespace System.IO.Compression
// Feed the data from base stream into the decompression engine.
_deflateStream._inflater.SetInput(buffer, offset, count);
- // While there's more decompressed data available, forward it to the destination stream.
+ // While there's more decompressed data available, forward it to the buffer stream.
while (true)
{
- int bytesRead = _deflateStream._inflater.Inflate(_arrayPoolBuffer, 0, _arrayPoolBuffer.Length);
+ int bytesRead = _deflateStream._inflater.Inflate(new Span<byte>(_arrayPoolBuffer));
if (bytesRead > 0)
{
- if (bytesRead > _arrayPoolBufferHighWaterMark) _arrayPoolBufferHighWaterMark = bytesRead;
- await _destination.WriteAsync(_arrayPoolBuffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);
+ await _destination.WriteAsync(new ReadOnlyMemory<byte>(_arrayPoolBuffer, 0, bytesRead), cancellationToken).ConfigureAwait(false);
}
else break;
}
diff --git a/src/System.IO.Compression/src/System/IO/Compression/DeflateZLib/Deflater.cs b/src/System.IO.Compression/src/System/IO/Compression/DeflateZLib/Deflater.cs
index fc3b8ad7aa..69c914be7d 100644
--- a/src/System.IO.Compression/src/System/IO/Compression/DeflateZLib/Deflater.cs
+++ b/src/System.IO.Compression/src/System/IO/Compression/DeflateZLib/Deflater.cs
@@ -100,7 +100,7 @@ namespace System.IO.Compression
lock (SyncLock)
{
- _inputBufferHandle = inputBuffer.Retain(pin: true);
+ _inputBufferHandle = inputBuffer.Pin();
_zlibStream.NextIn = (IntPtr)_inputBufferHandle.Pointer;
_zlibStream.AvailIn = (uint)inputBuffer.Length;
diff --git a/src/System.IO.Compression/src/System/IO/Compression/GZipStream.cs b/src/System.IO.Compression/src/System/IO/Compression/GZipStream.cs
index 4796b9b39b..6c5640db18 100644
--- a/src/System.IO.Compression/src/System/IO/Compression/GZipStream.cs
+++ b/src/System.IO.Compression/src/System/IO/Compression/GZipStream.cs
@@ -84,19 +84,19 @@ namespace System.IO.Compression
return _deflateStream.Read(array, offset, count);
}
- public override int Read(Span<byte> destination)
+ public override int Read(Span<byte> buffer)
{
if (GetType() != typeof(GZipStream))
{
// GZipStream is not sealed, and a derived type may have overridden Read(byte[], int, int) prior
// to this Read(Span<byte>) overload being introduced. In that case, this Read(Span<byte>) overload
// should use the behavior of Read(byte[],int,int) overload.
- return base.Read(destination);
+ return base.Read(buffer);
}
else
{
CheckDeflateStream();
- return _deflateStream.ReadCore(destination);
+ return _deflateStream.ReadCore(buffer);
}
}
@@ -112,19 +112,19 @@ namespace System.IO.Compression
_deflateStream.Write(array, offset, count);
}
- public override void Write(ReadOnlySpan<byte> source)
+ public override void Write(ReadOnlySpan<byte> buffer)
{
if (GetType() != typeof(GZipStream))
{
// GZipStream is not sealed, and a derived type may have overridden Write(byte[], int, int) prior
// to this Write(ReadOnlySpan<byte>) overload being introduced. In that case, this Write(ReadOnlySpan<byte>) overload
// should use the behavior of Write(byte[],int,int) overload.
- base.Write(source);
+ base.Write(buffer);
}
else
{
CheckDeflateStream();
- _deflateStream.WriteCore(source);
+ _deflateStream.WriteCore(buffer);
}
}
@@ -158,19 +158,19 @@ namespace System.IO.Compression
return _deflateStream.ReadAsync(array, offset, count, cancellationToken);
}
- public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken = default(CancellationToken))
+ public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default(CancellationToken))
{
if (GetType() != typeof(GZipStream))
{
// GZipStream is not sealed, and a derived type may have overridden ReadAsync(byte[], int, int) prior
// to this ReadAsync(Memory<byte>) overload being introduced. In that case, this ReadAsync(Memory<byte>) overload
// should use the behavior of ReadAsync(byte[],int,int) overload.
- return base.ReadAsync(destination, cancellationToken);
+ return base.ReadAsync(buffer, cancellationToken);
}
else
{
CheckDeflateStream();
- return _deflateStream.ReadAsyncMemory(destination, cancellationToken);
+ return _deflateStream.ReadAsyncMemory(buffer, cancellationToken);
}
}
@@ -180,19 +180,19 @@ namespace System.IO.Compression
return _deflateStream.WriteAsync(array, offset, count, cancellationToken);
}
- public override Task WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken = default(CancellationToken))
+ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default(CancellationToken))
{
if (GetType() != typeof(GZipStream))
{
// GZipStream is not sealed, and a derived type may have overridden WriteAsync(byte[], int, int) prior
// to this WriteAsync(ReadOnlyMemory<byte>) overload being introduced. In that case, this
// WriteAsync(ReadOnlyMemory<byte>) overload should use the behavior of Write(byte[],int,int) overload.
- return base.WriteAsync(source, cancellationToken);
+ return base.WriteAsync(buffer, cancellationToken);
}
else
{
CheckDeflateStream();
- return _deflateStream.WriteAsyncMemory(source, cancellationToken);
+ return _deflateStream.WriteAsyncMemory(buffer, cancellationToken);
}
}
diff --git a/src/System.IO.Compression/src/System/IO/Compression/PositionPreservingWriteOnlyStreamWrapper.netcoreapp.cs b/src/System.IO.Compression/src/System/IO/Compression/PositionPreservingWriteOnlyStreamWrapper.netcoreapp.cs
index 1c5aa7b6e2..c2cef7afb2 100644
--- a/src/System.IO.Compression/src/System/IO/Compression/PositionPreservingWriteOnlyStreamWrapper.netcoreapp.cs
+++ b/src/System.IO.Compression/src/System/IO/Compression/PositionPreservingWriteOnlyStreamWrapper.netcoreapp.cs
@@ -9,16 +9,16 @@ namespace System.IO.Compression
{
internal sealed partial class PositionPreservingWriteOnlyStreamWrapper : Stream
{
- public override void Write(ReadOnlySpan<byte> source)
+ public override void Write(ReadOnlySpan<byte> buffer)
{
- _position += source.Length;
- _stream.Write(source);
+ _position += buffer.Length;
+ _stream.Write(buffer);
}
- public override Task WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken = default(CancellationToken))
+ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default(CancellationToken))
{
- _position += source.Length;
- return _stream.WriteAsync(source, cancellationToken);
+ _position += buffer.Length;
+ return _stream.WriteAsync(buffer, cancellationToken);
}
}
}
diff --git a/src/System.IO.Compression/tests/CompressionStreamUnitTests.Deflate.cs b/src/System.IO.Compression/tests/CompressionStreamUnitTests.Deflate.cs
index 39e713de65..4fa26680b8 100644
--- a/src/System.IO.Compression/tests/CompressionStreamUnitTests.Deflate.cs
+++ b/src/System.IO.Compression/tests/CompressionStreamUnitTests.Deflate.cs
@@ -72,7 +72,7 @@ namespace System.IO.Compression
ms.Position = 0;
using (var compressor = new DerivedDeflateStream(ms, CompressionMode.Compress, leaveOpen: true))
{
- compressor.WriteAsync(new ReadOnlyMemory<byte>(new byte[1])).Wait();
+ compressor.WriteAsync(new ReadOnlyMemory<byte>(new byte[1])).AsTask().Wait();
Assert.True(compressor.WriteArrayInvoked);
}
}
diff --git a/src/System.IO.Compression/tests/CompressionStreamUnitTests.Gzip.cs b/src/System.IO.Compression/tests/CompressionStreamUnitTests.Gzip.cs
index 002c83cc87..387b1a87fc 100644
--- a/src/System.IO.Compression/tests/CompressionStreamUnitTests.Gzip.cs
+++ b/src/System.IO.Compression/tests/CompressionStreamUnitTests.Gzip.cs
@@ -57,7 +57,7 @@ namespace System.IO.Compression
ms.Position = 0;
using (var compressor = new DerivedGZipStream(ms, CompressionMode.Compress, leaveOpen: true))
{
- compressor.WriteAsync(new ReadOnlyMemory<byte>(new byte[1])).Wait();
+ compressor.WriteAsync(new ReadOnlyMemory<byte>(new byte[1])).AsTask().Wait();
Assert.True(compressor.WriteArrayInvoked);
}
}
diff --git a/src/System.IO.Compression/tests/Performance/System.IO.Compression.Performance.Tests.csproj b/src/System.IO.Compression/tests/Performance/System.IO.Compression.Performance.Tests.csproj
index 762e2f3a7b..12e663a783 100644
--- a/src/System.IO.Compression/tests/Performance/System.IO.Compression.Performance.Tests.csproj
+++ b/src/System.IO.Compression/tests/Performance/System.IO.Compression.Performance.Tests.csproj
@@ -4,7 +4,7 @@
<PropertyGroup>
<AssemblyName>System.IO.Compression.Performance.Tests</AssemblyName>
<IncludePerformanceTests>true</IncludePerformanceTests>
- <ProjectGuid>{1341F8C8-637A-49A1-BE0F-13867A634929}</ProjectGuid>
+ <ProjectGuid>{13C0F956-FB7B-4882-A411-39B8E22463D2}</ProjectGuid>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netcoreapp-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netcoreapp-Release|AnyCPU'" />
diff --git a/src/System.IO.Compression/tests/System.IO.Compression.Tests.csproj b/src/System.IO.Compression/tests/System.IO.Compression.Tests.csproj
index 7e69ef58b8..f04dd273bc 100644
--- a/src/System.IO.Compression/tests/System.IO.Compression.Tests.csproj
+++ b/src/System.IO.Compression/tests/System.IO.Compression.Tests.csproj
@@ -2,8 +2,8 @@
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
- <ProjectGuid>{BC2E1649-291D-412E-9529-EDDA94FA7AD6}</ProjectGuid>
- <DefineConstants Condition="'$(TargetGroup)' == 'netcoreapp' or '$(TargetGroup)' == 'uap'">$(DefineConstants);netcoreapp;STREAM_MEMORY_OVERLOADS_AVAILABLE</DefineConstants>
+ <ProjectGuid>{17DA7FB5-4370-4385-9A02-FFEF9F482903}</ProjectGuid>
+ <DefineConstants Condition="'$(TargetGroup)' == 'netcoreapp' or '$(TargetGroup)' == 'uap'">$(DefineConstants);netcoreapp;STREAM_MEMORY_OVERLOADS_AVAILABLE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
@@ -72,4 +72,4 @@
</SupplementalTestData>
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project>
+</Project> \ No newline at end of file
diff --git a/src/System.IO.FileSystem.AccessControl/pkg/System.IO.FileSystem.AccessControl.pkgproj b/src/System.IO.FileSystem.AccessControl/pkg/System.IO.FileSystem.AccessControl.pkgproj
index fdc93492c8..5802294f6d 100644
--- a/src/System.IO.FileSystem.AccessControl/pkg/System.IO.FileSystem.AccessControl.pkgproj
+++ b/src/System.IO.FileSystem.AccessControl/pkg/System.IO.FileSystem.AccessControl.pkgproj
@@ -11,6 +11,12 @@
<SupportedFramework>netcore50</SupportedFramework>
</HarvestIncludePaths>
<HarvestIncludePaths Include="runtimes/win/lib/netstandard1.3;lib/netstandard1.3" />
+
+ <!--
+ Suppress NETStandard.Library collpasing as it add more dependencies then needed in some
+ scenarios like .NET Framework which adds an unecessary amount of package dependencies to download
+ -->
+ <SuppressMetaPackage Include="NETStandard.Library" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.IO.FileSystem.AccessControl/src/Configurations.props b/src/System.IO.FileSystem.AccessControl/src/Configurations.props
index 9648129983..d8d7acfe61 100644
--- a/src/System.IO.FileSystem.AccessControl/src/Configurations.props
+++ b/src/System.IO.FileSystem.AccessControl/src/Configurations.props
@@ -3,8 +3,8 @@
<PropertyGroup>
<PackageConfigurations>
netstandard;
+ netstandard-Windows_NT;
netfx-Windows_NT;
- netcoreapp2.0-Windows_NT;
</PackageConfigurations>
<BuildConfigurations>
$(PackageConfigurations);
diff --git a/src/System.IO.FileSystem.AccessControl/src/System.IO.FileSystem.AccessControl.csproj b/src/System.IO.FileSystem.AccessControl/src/System.IO.FileSystem.AccessControl.csproj
index 1073ac3180..aeb88dbb94 100644
--- a/src/System.IO.FileSystem.AccessControl/src/System.IO.FileSystem.AccessControl.csproj
+++ b/src/System.IO.FileSystem.AccessControl/src/System.IO.FileSystem.AccessControl.csproj
@@ -7,19 +7,19 @@
<PropertyGroup>
<AssemblyName>System.IO.FileSystem.AccessControl</AssemblyName>
<ProjectGuid>{D77FBA6C-1AA6-45A4-93E2-97A370672C53}</ProjectGuid>
- <AllowUnsafeBlocks Condition="$(TargetGroup.StartsWith('netcoreapp'))">true</AllowUnsafeBlocks>
+ <AllowUnsafeBlocks Condition="'$(TargetsWindows)' == 'true'">true</AllowUnsafeBlocks>
<IsPartialFacadeAssembly Condition="'$(TargetGroup)'=='netfx'">true</IsPartialFacadeAssembly>
- <GeneratePlatformNotSupportedAssemblyMessage Condition="'$(TargetGroup)' == 'netstandard'">SR.PlatformNotSupported_AccessControl</GeneratePlatformNotSupportedAssemblyMessage>
+ <GeneratePlatformNotSupportedAssemblyMessage Condition="'$(TargetsWindows)' != 'true'">SR.PlatformNotSupported_AccessControl</GeneratePlatformNotSupportedAssemblyMessage>
</PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Windows_NT-Debug|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Windows_NT-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
- <ItemGroup Condition="$(TargetGroup.StartsWith('netcoreapp'))">
+ <ItemGroup Condition="'$(TargetsWindows)' == 'true' AND '$(TargetGroup)'!='netfx'">
<Compile Include="$(CommonPath)\Interop\Windows\Interop.Errors.cs">
<Link>Common\Interop\Windows\Interop.Errors.cs</Link>
</Compile>
diff --git a/src/System.IO.FileSystem.AccessControl/tests/DirectoryObjectSecurityTests.cs b/src/System.IO.FileSystem.AccessControl/tests/DirectoryObjectSecurityTests.cs
index 126bf39127..5cfba92691 100644
--- a/src/System.IO.FileSystem.AccessControl/tests/DirectoryObjectSecurityTests.cs
+++ b/src/System.IO.FileSystem.AccessControl/tests/DirectoryObjectSecurityTests.cs
@@ -1,5 +1,6 @@
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information
using System.DirectoryServices;
using System.Security.Principal;
@@ -172,7 +173,7 @@ namespace System.Security.AccessControl
var customObjectSecurity = new CustomDirectoryObjectSecurity(descriptor);
var objectTypeGuid = Guid.NewGuid();
- var identityReference = new NTAccount(@"NT AUTHORITY\SYSTEM");
+ var identityReference = new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount));
var customAuditRuleReadWrite = new CustomAuditRule(
identityReference, ReadWriteAccessMask, true, InheritanceFlags.None,
PropagationFlags.None, objectTypeGuid, Guid.NewGuid(), AuditFlags.Success
@@ -184,14 +185,10 @@ namespace System.Security.AccessControl
);
customObjectSecurity.AddAuditRule(customAuditRuleReadWrite);
- customObjectSecurity.RemoveAuditRuleSpecific(customAuditRuleWrite);
+ Assert.Contains(customAuditRuleReadWrite, customObjectSecurity.GetAuditRules(true, true, typeof(System.Security.Principal.NTAccount)).Cast<CustomAuditRule>());
- AuthorizationRuleCollection ruleCollection =
- customObjectSecurity
- .GetAuditRules(true, true, typeof(System.Security.Principal.NTAccount));
-
- List<CustomAuditRule> existingRules = ruleCollection.Cast<CustomAuditRule>().ToList();
- Assert.True(existingRules.Contains(customAuditRuleReadWrite));
+ customObjectSecurity.RemoveAuditRuleSpecific(customAuditRuleWrite);
+ Assert.Contains(customAuditRuleReadWrite, customObjectSecurity.GetAuditRules(true, true, typeof(System.Security.Principal.NTAccount)).Cast<CustomAuditRule>());
}
[Fact]
@@ -207,7 +204,7 @@ namespace System.Security.AccessControl
var descriptor = new CommonSecurityDescriptor(true, true, string.Empty);
var customObjectSecurity = new CustomDirectoryObjectSecurity(descriptor);
- var identity = new NTAccount(@"NT AUTHORITY\SYSTEM");
+ var identity = new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount));
var objectType = Guid.NewGuid();
var customAuditRuleWrite = new CustomAuditRule(
identity, WriteAccessMask, true, InheritanceFlags.None,
@@ -251,27 +248,23 @@ namespace System.Security.AccessControl
var customObjectSecurity = new CustomDirectoryObjectSecurity(descriptor);
var objectTypeGuid = Guid.NewGuid();
- var identityReference = new NTAccount(@"NT AUTHORITY\SYSTEM");
+ var identityReference = new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount));
var customAuditRuleReadWrite = new CustomAuditRule(
identityReference, ReadWriteAccessMask, true, InheritanceFlags.None,
PropagationFlags.None, objectTypeGuid, Guid.NewGuid(), AuditFlags.Success
);
var customAuditRuleRead = new CustomAuditRule(
- new NTAccount(@"NT AUTHORITY\SYSTEM"), ReadAccessMask, true, InheritanceFlags.None,
+ new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount)), ReadAccessMask, true, InheritanceFlags.None,
PropagationFlags.None, objectTypeGuid, Guid.NewGuid(), AuditFlags.Success
);
customObjectSecurity.AddAuditRule(customAuditRuleReadWrite);
customObjectSecurity.SetAuditRule(customAuditRuleRead);
- AuthorizationRuleCollection ruleCollection =
- customObjectSecurity
- .GetAuditRules(true, true, typeof(System.Security.Principal.NTAccount));
-
- List<CustomAuditRule> existingRules = ruleCollection.Cast<CustomAuditRule>().ToList();
- Assert.False(existingRules.Contains(customAuditRuleReadWrite));
- Assert.True(existingRules.Contains(customAuditRuleRead));
+ var existingRules = customObjectSecurity.GetAuditRules(true, true, typeof(System.Security.Principal.NTAccount)).Cast<CustomAuditRule>().ToList();
+ Assert.DoesNotContain(customAuditRuleReadWrite, existingRules);
+ Assert.Contains(customAuditRuleRead, existingRules);
}
[Fact]
@@ -288,26 +281,24 @@ namespace System.Security.AccessControl
var customObjectSecurity = new CustomDirectoryObjectSecurity(descriptor);
var customAuditRuleRead = new CustomAuditRule(
- new NTAccount(@"NT AUTHORITY\Network Service"), ReadAccessMask, true, InheritanceFlags.None,
+ new SecurityIdentifier(WellKnownSidType.NetworkServiceSid, null).Translate(typeof(NTAccount)), ReadAccessMask, true, InheritanceFlags.None,
PropagationFlags.None, Guid.NewGuid(), Guid.NewGuid(), AuditFlags.Success
);
var customAuditRuleReadAttribute = new CustomAuditRule(
- new NTAccount(@"NT AUTHORITY\SYSTEM"), ReadAttributeAccessMask, true, InheritanceFlags.None,
+ new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount)), ReadAttributeAccessMask, true, InheritanceFlags.None,
PropagationFlags.None, Guid.NewGuid(), Guid.NewGuid(), AuditFlags.Success
);
customObjectSecurity.AddAuditRule(customAuditRuleRead);
customObjectSecurity.AddAuditRule(customAuditRuleReadAttribute);
- AuthorizationRuleCollection ruleCollection =
- customObjectSecurity
- .GetAuditRules(true, true, typeof(System.Security.Principal.NTAccount));
+ AuthorizationRuleCollection ruleCollection = customObjectSecurity.GetAuditRules(true, true, typeof(System.Security.Principal.NTAccount));
Assert.NotNull(ruleCollection);
List<CustomAuditRule> addedRules = ruleCollection.Cast<CustomAuditRule>().ToList();
- Assert.True(addedRules.Contains(customAuditRuleRead));
- Assert.True(addedRules.Contains(customAuditRuleReadAttribute));
+ Assert.Contains(customAuditRuleRead, addedRules);
+ Assert.Contains(customAuditRuleReadAttribute, addedRules);
}
[Fact]
@@ -324,7 +315,7 @@ namespace System.Security.AccessControl
var customObjectSecurity = new CustomDirectoryObjectSecurity(descriptor);
var objectTypeGuid = Guid.NewGuid();
- var identityReference = new NTAccount(@"NT AUTHORITY\SYSTEM");
+ var identityReference = new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount));
var customAccessRuleReadWrite = new CustomAccessRule(
identityReference, ReadWriteAccessMask, true, InheritanceFlags.None,
@@ -340,19 +331,15 @@ namespace System.Security.AccessControl
bool result = customObjectSecurity.RemoveAccessRule(customAccessRuleWrite);
Assert.Equal(true, result);
- AuthorizationRuleCollection ruleCollection =
- customObjectSecurity
- .GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
+ AuthorizationRuleCollection ruleCollection = customObjectSecurity.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
Assert.NotNull(ruleCollection);
- List<CustomAccessRule> existingRules = ruleCollection.Cast<CustomAccessRule>().ToList();
- Assert.True(
- existingRules.Any(
- x => x.IdentityReference == identityReference &&
- x.AccessControlType == customAccessRuleReadWrite.AccessControlType &&
- x.AccessMaskValue == ReadAccessMask
- ));
+ Assert.Contains(ruleCollection.Cast<CustomAccessRule>(), x =>
+ x.IdentityReference == identityReference &&
+ x.AccessControlType == customAccessRuleReadWrite.AccessControlType &&
+ x.AccessMaskValue == ReadAccessMask
+ );
}
[Fact]
@@ -362,7 +349,7 @@ namespace System.Security.AccessControl
var customObjectSecurity = new CustomDirectoryObjectSecurity(descriptor);
int readDataAndAttribute = ReadAccessMask | ReadAttributeAccessMask;
- var identityReference = new NTAccount(@"NT AUTHORITY\SYSTEM");
+ var identityReference = new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount));
var objectTypeGuid = Guid.NewGuid();
var customAccessRuleReadDataAndAttribute = new CustomAccessRule(
identityReference, readDataAndAttribute, true, InheritanceFlags.None,
@@ -377,19 +364,14 @@ namespace System.Security.AccessControl
customObjectSecurity.AddAccessRule(customAccessRuleReadDataAndAttribute);
customObjectSecurity.RemoveAccessRule(customAccessRuleRead);
- AuthorizationRuleCollection ruleCollection =
- customObjectSecurity
- .GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
-
+ AuthorizationRuleCollection ruleCollection = customObjectSecurity.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
Assert.NotNull(ruleCollection);
- List<CustomAccessRule> existingRules = ruleCollection.Cast<CustomAccessRule>().ToList();
- Assert.True(
- existingRules.Any(
- x => x.IdentityReference == identityReference &&
- x.AccessControlType == AccessControlType.Deny &&
- x.AccessMaskValue == ReadAttributeAccessMask
- ));
+ Assert.Contains(ruleCollection.Cast<CustomAccessRule>(), x =>
+ x.IdentityReference == identityReference &&
+ x.AccessControlType == AccessControlType.Deny &&
+ x.AccessMaskValue == ReadAttributeAccessMask
+ );
}
[Fact]
@@ -431,7 +413,7 @@ namespace System.Security.AccessControl
var customObjectSecurity = new CustomDirectoryObjectSecurity(descriptor);
var objectTypeGuid = Guid.NewGuid();
- var identityReference = new NTAccount(@"NT AUTHORITY\SYSTEM");
+ var identityReference = new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount));
var customAccessRuleReadWrite = new CustomAccessRule(
identityReference, ReadWriteAccessMask, true, InheritanceFlags.None,
@@ -439,19 +421,14 @@ namespace System.Security.AccessControl
);
var customAccessRuleRead = new CustomAccessRule(
- new NTAccount(@"NT AUTHORITY\SYSTEM"), ReadAccessMask, true, InheritanceFlags.None,
+ new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount)), ReadAccessMask, true, InheritanceFlags.None,
PropagationFlags.None, objectTypeGuid, Guid.NewGuid(), AccessControlType.Deny
);
customObjectSecurity.AddAccessRule(customAccessRuleReadWrite);
customObjectSecurity.RemoveAccessRuleSpecific(customAccessRuleRead);
- AuthorizationRuleCollection ruleCollection =
- customObjectSecurity
- .GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
-
- List<CustomAccessRule> existingRules = ruleCollection.Cast<CustomAccessRule>().ToList();
- Assert.True(existingRules.Contains(customAccessRuleReadWrite));
+ Assert.Contains(customAccessRuleReadWrite, customObjectSecurity.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount)).Cast<CustomAccessRule>());
}
[Fact]
@@ -556,34 +533,35 @@ namespace System.Security.AccessControl
var customObjectSecurity = new CustomDirectoryObjectSecurity(descriptor);
var objectTypeGuid = Guid.NewGuid();
- var identityReference = new NTAccount(@"NT AUTHORITY\SYSTEM");
+ var identityReference = new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount));
var customAccessRuleReadWrite = new CustomAccessRule(
identityReference, ReadWriteAccessMask, true, InheritanceFlags.None,
PropagationFlags.None, objectTypeGuid, Guid.NewGuid(), AccessControlType.Deny
);
var customAccessRuleNetworkService = new CustomAccessRule(
- new NTAccount(@"NT AUTHORITY\NetworkService"), SynchronizeAccessMask, true, InheritanceFlags.None,
+ new SecurityIdentifier(WellKnownSidType.NetworkServiceSid, null).Translate(typeof(NTAccount)), SynchronizeAccessMask, true, InheritanceFlags.None,
PropagationFlags.None, objectTypeGuid, Guid.NewGuid(), AccessControlType.Allow
);
var customAccessRuleRead = new CustomAccessRule(
- new NTAccount(@"NT AUTHORITY\SYSTEM"), ReadAccessMask, true, InheritanceFlags.None,
+ new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount)), ReadAccessMask, true, InheritanceFlags.None,
PropagationFlags.None, objectTypeGuid, Guid.NewGuid(), AccessControlType.Allow
);
customObjectSecurity.AddAccessRule(customAccessRuleReadWrite);
- customObjectSecurity.AddAccessRule(customAccessRuleNetworkService);
- customObjectSecurity.ResetAccessRule(customAccessRuleRead);
+ Assert.Contains(customAccessRuleReadWrite, customObjectSecurity.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount)).Cast<CustomAccessRule>());
- AuthorizationRuleCollection ruleCollection =
- customObjectSecurity
- .GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
+ customObjectSecurity.AddAccessRule(customAccessRuleNetworkService);
+ List<CustomAccessRule> existingRules = customObjectSecurity.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount)).Cast<CustomAccessRule>().ToList();
+ Assert.Contains(customAccessRuleReadWrite, existingRules);
+ Assert.Contains(customAccessRuleNetworkService, existingRules);
- List<CustomAccessRule> existingRules = ruleCollection.Cast<CustomAccessRule>().ToList();
- Assert.False(existingRules.Contains(customAccessRuleReadWrite));
- Assert.False(existingRules.Contains(customAccessRuleNetworkService));
- Assert.True(existingRules.Contains(customAccessRuleRead));
+ customObjectSecurity.ResetAccessRule(customAccessRuleRead);
+ existingRules = customObjectSecurity.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount)).Cast<CustomAccessRule>().ToList();
+ Assert.DoesNotContain(customAccessRuleReadWrite, existingRules);
+ Assert.Contains(customAccessRuleNetworkService, existingRules);
+ Assert.Contains(customAccessRuleRead, existingRules);
}
[Fact]
@@ -593,34 +571,35 @@ namespace System.Security.AccessControl
var customObjectSecurity = new CustomDirectoryObjectSecurity(descriptor);
var objectTypeGuid = Guid.NewGuid();
- var identityReference = new NTAccount(@"NT AUTHORITY\SYSTEM");
+ var identityReference = new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount));
var customAccessRuleReadWrite = new CustomAccessRule(
identityReference, ReadWriteAccessMask, true, InheritanceFlags.None,
PropagationFlags.None, objectTypeGuid, Guid.NewGuid(), AccessControlType.Deny
);
var customAccessRuleNetworkService = new CustomAccessRule(
- new NTAccount(@"NT AUTHORITY\NetworkService"), SynchronizeAccessMask, true, InheritanceFlags.None,
+ new SecurityIdentifier(WellKnownSidType.NetworkServiceSid, null).Translate(typeof(NTAccount)), SynchronizeAccessMask, true, InheritanceFlags.None,
PropagationFlags.None, objectTypeGuid, Guid.NewGuid(), AccessControlType.Allow
);
var customAccessRuleWrite = new CustomAccessRule(
- new NTAccount(@"NT AUTHORITY\SYSTEM"), WriteAccessMask, true, InheritanceFlags.None,
+ new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount)), WriteAccessMask, true, InheritanceFlags.None,
PropagationFlags.None, objectTypeGuid, Guid.NewGuid(), AccessControlType.Deny
);
customObjectSecurity.AddAccessRule(customAccessRuleReadWrite);
- customObjectSecurity.AddAccessRule(customAccessRuleNetworkService);
- customObjectSecurity.ResetAccessRule(customAccessRuleWrite);
+ Assert.Contains(customAccessRuleReadWrite, customObjectSecurity.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount)).Cast<CustomAccessRule>());
- AuthorizationRuleCollection ruleCollection =
- customObjectSecurity
- .GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
+ customObjectSecurity.AddAccessRule(customAccessRuleNetworkService);
+ List<CustomAccessRule> existingRules = customObjectSecurity.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount)).Cast<CustomAccessRule>().ToList();
+ Assert.Contains(customAccessRuleReadWrite, existingRules);
+ Assert.Contains(customAccessRuleNetworkService, existingRules);
- List<CustomAccessRule> existingRules = ruleCollection.Cast<CustomAccessRule>().ToList();
- Assert.False(existingRules.Contains(customAccessRuleReadWrite));
- Assert.False(existingRules.Contains(customAccessRuleNetworkService));
- Assert.True(existingRules.Contains(customAccessRuleWrite));
+ customObjectSecurity.ResetAccessRule(customAccessRuleWrite);
+ existingRules = customObjectSecurity.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount)).Cast<CustomAccessRule>().ToList();
+ Assert.DoesNotContain(customAccessRuleReadWrite, existingRules);
+ Assert.Contains(customAccessRuleNetworkService, existingRules);
+ Assert.Contains(customAccessRuleWrite, existingRules);
}
[Fact]
@@ -637,27 +616,24 @@ namespace System.Security.AccessControl
var customObjectSecurity = new CustomDirectoryObjectSecurity(descriptor);
var objectTypeGuid = Guid.NewGuid();
- var identityReference = new NTAccount(@"NT AUTHORITY\SYSTEM");
+ var identityReference = new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount));
var customAccessRuleReadWrite = new CustomAccessRule(
identityReference, ReadWriteAccessMask, true, InheritanceFlags.None,
PropagationFlags.None, objectTypeGuid, Guid.NewGuid(), AccessControlType.Allow
);
var customAccessRuleRead = new CustomAccessRule(
- new NTAccount(@"NT AUTHORITY\SYSTEM"), ReadAccessMask, true, InheritanceFlags.None,
+ new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount)), ReadAccessMask, true, InheritanceFlags.None,
PropagationFlags.None, objectTypeGuid, Guid.NewGuid(), AccessControlType.Allow
);
customObjectSecurity.AddAccessRule(customAccessRuleReadWrite);
customObjectSecurity.SetAccessRule(customAccessRuleRead);
- AuthorizationRuleCollection ruleCollection =
- customObjectSecurity
- .GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
+ List<CustomAccessRule> existingRules = customObjectSecurity.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount)).Cast<CustomAccessRule>().ToList();
- List<CustomAccessRule> existingRules = ruleCollection.Cast<CustomAccessRule>().ToList();
- Assert.False(existingRules.Contains(customAccessRuleReadWrite));
- Assert.True(existingRules.Contains(customAccessRuleRead));
+ Assert.DoesNotContain(customAccessRuleReadWrite, existingRules);
+ Assert.Contains(customAccessRuleRead, existingRules);
}
[Fact]
@@ -667,28 +643,24 @@ namespace System.Security.AccessControl
var customObjectSecurity = new CustomDirectoryObjectSecurity(descriptor);
var objectTypeGuid = Guid.NewGuid();
- var identityReference = new NTAccount(@"NT AUTHORITY\SYSTEM");
+ var identityReference = new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount));
var customAccessRuleReadWrite = new CustomAccessRule(
identityReference, ReadWriteAccessMask, true, InheritanceFlags.None,
PropagationFlags.None, objectTypeGuid, Guid.NewGuid(), AccessControlType.Deny
);
var customAccessRuleRead = new CustomAccessRule(
- new NTAccount(@"NT AUTHORITY\SYSTEM"), ReadAccessMask, true, InheritanceFlags.None,
+ new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount)), ReadAccessMask, true, InheritanceFlags.None,
PropagationFlags.None, objectTypeGuid, Guid.NewGuid(), AccessControlType.Deny
);
customObjectSecurity.AddAccessRule(customAccessRuleReadWrite);
- customObjectSecurity.SetAccessRule(customAccessRuleRead);
-
- AuthorizationRuleCollection ruleCollection =
- customObjectSecurity
- .GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
+ Assert.Contains(customAccessRuleReadWrite, customObjectSecurity.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount)).Cast<CustomAccessRule>());
- List<CustomAccessRule> existingRules = ruleCollection.Cast<CustomAccessRule>().ToList();
-
- Assert.False(existingRules.Contains(customAccessRuleReadWrite));
- Assert.True(existingRules.Contains(customAccessRuleRead));
+ customObjectSecurity.SetAccessRule(customAccessRuleRead);
+ var existingRules = customObjectSecurity.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount)).Cast<CustomAccessRule>().ToList();
+ Assert.DoesNotContain(customAccessRuleReadWrite, existingRules);
+ Assert.Contains(customAccessRuleRead, existingRules);
}
[Fact]
@@ -705,26 +677,23 @@ namespace System.Security.AccessControl
var customObjectSecurity = new CustomDirectoryObjectSecurity(descriptor);
var customAccessRuleAllow = new CustomAccessRule(
- new NTAccount(@"NT AUTHORITY\Network Service"), ReadAccessMask, true, InheritanceFlags.None,
+ new SecurityIdentifier(WellKnownSidType.NetworkServiceSid, null).Translate(typeof(NTAccount)), ReadAccessMask, true, InheritanceFlags.None,
PropagationFlags.None, Guid.NewGuid(), Guid.NewGuid(), AccessControlType.Allow
);
var customAccessRuleDeny = new CustomAccessRule(
- new NTAccount(@"NT AUTHORITY\SYSTEM"), ReadAccessMask, true, InheritanceFlags.None,
+ new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount)), ReadAccessMask, true, InheritanceFlags.None,
PropagationFlags.None, Guid.NewGuid(), Guid.NewGuid(), AccessControlType.Deny
);
customObjectSecurity.AddAccessRule(customAccessRuleAllow);
customObjectSecurity.AddAccessRule(customAccessRuleDeny);
- AuthorizationRuleCollection ruleCollection =
- customObjectSecurity
- .GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
-
+ AuthorizationRuleCollection ruleCollection = customObjectSecurity.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
Assert.NotNull(ruleCollection);
List<CustomAccessRule> addedRules = ruleCollection.Cast<CustomAccessRule>().ToList();
- Assert.True(addedRules.Contains(customAccessRuleAllow));
- Assert.True(addedRules.Contains(customAccessRuleDeny));
+ Assert.Contains(customAccessRuleAllow, addedRules);
+ Assert.Contains(customAccessRuleDeny, addedRules);
}
private class CustomDirectoryObjectSecurity : DirectoryObjectSecurity
diff --git a/src/System.IO.FileSystem.AccessControl/tests/FileSystemAccessRuleTests.cs b/src/System.IO.FileSystem.AccessControl/tests/FileSystemAccessRuleTests.cs
index 23d8adebcb..60af70435d 100644
--- a/src/System.IO.FileSystem.AccessControl/tests/FileSystemAccessRuleTests.cs
+++ b/src/System.IO.FileSystem.AccessControl/tests/FileSystemAccessRuleTests.cs
@@ -1,5 +1,6 @@
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information
using System.Security.AccessControl;
using System.Security.Principal;
diff --git a/src/System.IO.FileSystem.AccessControl/tests/FileSystemAclExtensionsTests.cs b/src/System.IO.FileSystem.AccessControl/tests/FileSystemAclExtensionsTests.cs
index 09f663147b..db275f4b27 100644
--- a/src/System.IO.FileSystem.AccessControl/tests/FileSystemAclExtensionsTests.cs
+++ b/src/System.IO.FileSystem.AccessControl/tests/FileSystemAclExtensionsTests.cs
@@ -1,5 +1,6 @@
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information
using System.Security.AccessControl;
using Xunit;
diff --git a/src/System.IO.FileSystem.AccessControl/tests/FileSystemAuditRuleTests.cs b/src/System.IO.FileSystem.AccessControl/tests/FileSystemAuditRuleTests.cs
index 00d87a8860..afb26096ab 100644
--- a/src/System.IO.FileSystem.AccessControl/tests/FileSystemAuditRuleTests.cs
+++ b/src/System.IO.FileSystem.AccessControl/tests/FileSystemAuditRuleTests.cs
@@ -1,6 +1,6 @@
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information
using System.Security.Principal;
using Xunit;
diff --git a/src/System.IO.FileSystem.AccessControl/tests/FileSystemSecurityTests.cs b/src/System.IO.FileSystem.AccessControl/tests/FileSystemSecurityTests.cs
index 14e223b228..0d221acf8b 100644
--- a/src/System.IO.FileSystem.AccessControl/tests/FileSystemSecurityTests.cs
+++ b/src/System.IO.FileSystem.AccessControl/tests/FileSystemSecurityTests.cs
@@ -1,5 +1,6 @@
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information
using System;
using System.Collections.Generic;
@@ -32,7 +33,7 @@ namespace System.IO
fileSecurity.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
Assert.Equal(1, rules.Count);
var actualAddedRule = (FileSystemAccessRule)rules[0];
- Assert.Equal(accessRule.IdentityReference, actualAddedRule.IdentityReference);
+ Assert.Equal(new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount)), actualAddedRule.IdentityReference);
Assert.Equal(accessRule.FileSystemRights, actualAddedRule.FileSystemRights);
Assert.Equal(accessRule.AccessControlType, actualAddedRule.AccessControlType);
}
@@ -80,7 +81,7 @@ namespace System.IO
Assert.Equal(2, rules.Count);
var existingAccessRule = (FileSystemAccessRule)rules[0];
- Assert.Equal(new NTAccount(@"NT AUTHORITY\SYSTEM"), existingAccessRule.IdentityReference);
+ Assert.Equal(new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount)), existingAccessRule.IdentityReference);
existingAccessRule = (FileSystemAccessRule)rules[1];
Assert.Equal(new NTAccount(@"NT AUTHORITY\Network Service"), existingAccessRule.IdentityReference);
}
@@ -148,12 +149,12 @@ namespace System.IO
[Fact]
public void RemoveAccessRule_IdenticalRule_Succeeds()
{
- var accessRule = new FileSystemAccessRule(@"NT AUTHORITY\SYSTEM",
+ var accessRule = new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount)).Value,
FileSystemRights.Read | FileSystemRights.Write,
AccessControlType.Allow);
var fileSecurity = new FileSecurity();
fileSecurity.AddAccessRule(accessRule);
- Assert.True(fileSecurity.RemoveAccessRule(new FileSystemAccessRule(@"NT AUTHORITY\SYSTEM",
+ Assert.True(fileSecurity.RemoveAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount)).Value,
FileSystemRights.Read | FileSystemRights.Write,
AccessControlType.Allow)));
var rules = fileSecurity.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
@@ -210,7 +211,7 @@ namespace System.IO
[Fact]
public void RemoveAccessRuleSpecific_Succeeds()
{
- var accessRule = new FileSystemAccessRule(@"NT AUTHORITY\SYSTEM", FileSystemRights.AppendData
+ var accessRule = new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount)).Value, FileSystemRights.AppendData
| FileSystemRights.Write, AccessControlType.Allow);
var fileSecurity = new FileSecurity();
fileSecurity.AddAccessRule(accessRule);
@@ -255,7 +256,7 @@ namespace System.IO
Assert.Equal(2, rules.Count);
var existingAccessRule = (FileSystemAccessRule)rules[0];
- Assert.Equal(new NTAccount(@"NT AUTHORITY\SYSTEM"), existingAccessRule.IdentityReference);
+ Assert.Equal(new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount)), existingAccessRule.IdentityReference);
Assert.Equal(AccessControlType.Deny, existingAccessRule.AccessControlType);
Assert.Equal(FileSystemRights.ReadPermissions, existingAccessRule.FileSystemRights);
existingAccessRule = (FileSystemAccessRule)rules[1];
@@ -285,7 +286,7 @@ namespace System.IO
fileSecurity.GetAuditRules(true, true, typeof(System.Security.Principal.NTAccount));
Assert.Equal(1, auditRules.Count);
var actualAddedRule = (FileSystemAuditRule)auditRules[0];
- Assert.Equal(new NTAccount(@"NT AUTHORITY\SYSTEM"), actualAddedRule.IdentityReference);
+ Assert.Equal(new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount)), actualAddedRule.IdentityReference);
Assert.Equal(AuditFlags.Success, actualAddedRule.AuditFlags);
Assert.Equal(FileSystemRights.AppendData, actualAddedRule.FileSystemRights);
}
@@ -308,7 +309,7 @@ namespace System.IO
Assert.Equal(2, auditRules.Count);
var firstAuditRule = (FileSystemAuditRule)auditRules[0];
- Assert.Equal(new NTAccount(@"NT AUTHORITY\SYSTEM"), firstAuditRule.IdentityReference);
+ Assert.Equal(new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount)), firstAuditRule.IdentityReference);
Assert.Equal(AuditFlags.Success, firstAuditRule.AuditFlags);
Assert.Equal(FileSystemRights.Delete, firstAuditRule.FileSystemRights);
var secondAuditRule = (FileSystemAuditRule)auditRules[1];
@@ -336,7 +337,7 @@ namespace System.IO
var existingRule = (FileSystemAuditRule)rules[0];
Assert.Equal(FileSystemRights.Read, existingRule.FileSystemRights);
Assert.Equal(AuditFlags.Failure, existingRule.AuditFlags);
- Assert.Equal(new NTAccount(@"NT AUTHORITY\SYSTEM"), existingRule.IdentityReference);
+ Assert.Equal(new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null).Translate(typeof(NTAccount)), existingRule.IdentityReference);
}
[Fact]
diff --git a/src/System.IO.FileSystem.DriveInfo/src/System.IO.FileSystem.DriveInfo.csproj b/src/System.IO.FileSystem.DriveInfo/src/System.IO.FileSystem.DriveInfo.csproj
index 056e32b1d7..a928d8f486 100644
--- a/src/System.IO.FileSystem.DriveInfo/src/System.IO.FileSystem.DriveInfo.csproj
+++ b/src/System.IO.FileSystem.DriveInfo/src/System.IO.FileSystem.DriveInfo.csproj
@@ -20,9 +20,6 @@
<Compile Include="$(CommonPath)\System\HResults.cs">
<Link>Common\System\HResults.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\IO\PathInternal.cs">
- <Link>Common\System\IO\PathInternal.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\System\IO\PathInternal.CaseSensitivity.cs">
<Link>Common\System\IO\PathInternal.CaseSensitivity.cs</Link>
</Compile>
@@ -63,8 +60,8 @@
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.FormatMessage.cs">
<Link>Common\Interop\Windows\Interop.FormatMessage.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\IO\Win32Marshal.cs">
- <Link>Common\System\IO\Win32Marshal.cs</Link>
+ <Compile Include="$(CommonPath)\CoreLib\System\IO\Win32Marshal.cs">
+ <Link>Common\CoreLib\System\IO\Win32Marshal.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\IO\DriveInfoInternal.Win32.cs">
<Link>Common\System\IO\DriveInfoInternal.Win32.cs</Link>
@@ -101,6 +98,7 @@
<Reference Include="System.Diagnostics.Debug" />
<Reference Include="System.Diagnostics.Tools" />
<Reference Include="System.IO.FileSystem" />
+ <Reference Include="System.Memory" />
<Reference Include="System.Resources.ResourceManager" />
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.Extensions" />
diff --git a/src/System.IO.FileSystem.DriveInfo/src/System/IO/DriveInfo.Windows.cs b/src/System.IO.FileSystem.DriveInfo/src/System/IO/DriveInfo.Windows.cs
index 361cbbe601..39a84e9e6a 100644
--- a/src/System.IO.FileSystem.DriveInfo/src/System/IO/DriveInfo.Windows.cs
+++ b/src/System.IO.FileSystem.DriveInfo/src/System/IO/DriveInfo.Windows.cs
@@ -24,7 +24,7 @@ namespace System.IO
name = Path.GetPathRoot(driveName);
// Disallow null or empty drive letters and UNC paths
if (name == null || name.Length == 0 || name.StartsWith("\\\\", StringComparison.Ordinal))
- throw new ArgumentException(SR.Arg_MustBeDriveLetterOrRootDir);
+ throw new ArgumentException(SR.Arg_MustBeDriveLetterOrRootDir, nameof(driveName));
}
// We want to normalize to have a trailing backslash so we don't have two equivalent forms and
// because some Win32 API don't work without it.
@@ -37,7 +37,7 @@ namespace System.IO
// On Windows this means it's between A and Z, ignoring case.
char letter = driveName[0];
if (!((letter >= 'A' && letter <= 'Z') || (letter >= 'a' && letter <= 'z')))
- throw new ArgumentException(SR.Arg_MustBeDriveLetterOrRootDir);
+ throw new ArgumentException(SR.Arg_MustBeDriveLetterOrRootDir, nameof(driveName));
return name;
}
diff --git a/src/System.IO.FileSystem.DriveInfo/tests/DriveInfo.Windows.Tests.cs b/src/System.IO.FileSystem.DriveInfo/tests/DriveInfo.Windows.Tests.cs
index c1ff89a3b8..612e905faa 100644
--- a/src/System.IO.FileSystem.DriveInfo/tests/DriveInfo.Windows.Tests.cs
+++ b/src/System.IO.FileSystem.DriveInfo/tests/DriveInfo.Windows.Tests.cs
@@ -17,22 +17,22 @@ namespace System.IO.FileSystem.DriveInfoTests
public class DriveInfoWindowsTests
{
[Theory]
- [InlineData(":", null)]
- [InlineData("://", null)]
- [InlineData(@":\", null)]
- [InlineData(":/", null)]
- [InlineData(@":\\", null)]
- [InlineData("Az", null)]
- [InlineData("1", null)]
- [InlineData("a1", null)]
- [InlineData(@"\\share", null)]
- [InlineData(@"\\", null)]
- [InlineData("c ", null)]
- [InlineData("", "path")]
- [InlineData(" c", null)]
- public void Ctor_InvalidPath_ThrowsArgumentException(string driveName, string paramName)
+ [InlineData(":")]
+ [InlineData("://")]
+ [InlineData(@":\")]
+ [InlineData(":/")]
+ [InlineData(@":\\")]
+ [InlineData("Az")]
+ [InlineData("1")]
+ [InlineData("a1")]
+ [InlineData(@"\\share")]
+ [InlineData(@"\\")]
+ [InlineData("c ")]
+ [InlineData("")]
+ [InlineData(" c")]
+ public void Ctor_InvalidPath_ThrowsArgumentException(string driveName)
{
- AssertExtensions.Throws<ArgumentException>(paramName, null, () => new DriveInfo(driveName));
+ AssertExtensions.Throws<ArgumentException>("driveName", null, () => new DriveInfo(driveName));
}
[Fact]
diff --git a/src/System.IO.FileSystem.Watcher/src/System.IO.FileSystem.Watcher.csproj b/src/System.IO.FileSystem.Watcher/src/System.IO.FileSystem.Watcher.csproj
index 734563e601..c797318179 100644
--- a/src/System.IO.FileSystem.Watcher/src/System.IO.FileSystem.Watcher.csproj
+++ b/src/System.IO.FileSystem.Watcher/src/System.IO.FileSystem.Watcher.csproj
@@ -24,14 +24,10 @@
</Compile>
<Compile Include="System\IO\InternalBufferOverflowException.cs" />
<Compile Include="System\IO\NotifyFilters.cs" />
- <Compile Include="System\IO\PatternMatcher.cs" />
<Compile Include="System\IO\RenamedEventArgs.cs" />
<Compile Include="System\IO\RenamedEventHandler.cs" />
<Compile Include="System\IO\WatcherChangeTypes.cs" />
<Compile Include="System\IO\WaitForChangedResult.cs" />
- <Compile Include="$(CommonPath)\System\IO\PathInternal.cs">
- <Link>Common\System\IO\PathInternal.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\System\IO\PathInternal.CaseSensitivity.cs">
<Link>Common\System\IO\PathInternal.CaseSensitivity.cs</Link>
</Compile>
@@ -150,6 +146,7 @@
<Reference Include="System.Diagnostics.Debug" />
<Reference Include="System.Diagnostics.Tools" />
<Reference Include="System.IO.FileSystem" />
+ <Reference Include="System.Memory" />
<Reference Include="System.Resources.ResourceManager" />
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.Extensions" />
@@ -165,4 +162,4 @@
<Reference Include="System.Collections" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project>
+</Project> \ No newline at end of file
diff --git a/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.cs b/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.cs
index 8eff45a82a..f0f9e0a994 100644
--- a/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.cs
+++ b/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.cs
@@ -5,6 +5,7 @@
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
+using System.IO.Enumeration;
using System.Threading;
using System.Threading.Tasks;
@@ -22,7 +23,6 @@ namespace System.IO
/// Listens to the system directory change notifications and
/// raises events when a directory or file within a directory changes.
/// </devdoc>
-
public partial class FileSystemWatcher : Component, ISupportInitialize
{
/// <devdoc>
@@ -89,14 +89,14 @@ namespace System.IO
public FileSystemWatcher()
{
_directory = string.Empty;
- _filter = "*.*";
+ _filter = "*";
}
/// <devdoc>
/// Initializes a new instance of the <see cref='System.IO.FileSystemWatcher'/> class,
/// given the specified directory to monitor.
/// </devdoc>
- public FileSystemWatcher(string path) : this(path, "*.*")
+ public FileSystemWatcher(string path) : this(path, "*")
{
}
@@ -109,9 +109,6 @@ namespace System.IO
if (path == null)
throw new ArgumentNullException(nameof(path));
- if (filter == null)
- throw new ArgumentNullException(nameof(filter));
-
// Early check for directory parameter so that an exception can be thrown as early as possible.
if (path.Length == 0)
throw new ArgumentException(SR.Format(SR.InvalidDirName, path), nameof(path));
@@ -120,7 +117,10 @@ namespace System.IO
throw new ArgumentException(SR.Format(SR.InvalidDirName_NotExists, path), nameof(path));
_directory = path;
- _filter = filter;
+ _filter = filter ?? throw new ArgumentNullException(nameof(filter));
+
+ if (_filter == "*.*")
+ _filter = "*";
}
/// <devdoc>
@@ -193,13 +193,13 @@ namespace System.IO
{
if (string.IsNullOrEmpty(value))
{
- // Skip the string compare for "*.*" since it has no case-insensitive representation that differs from
+ // Skip the string compare for "*" since it has no case-insensitive representation that differs from
// the case-sensitive representation.
- _filter = "*.*";
+ _filter = "*";
}
else if (!string.Equals(_filter, value, PathInternal.StringComparison))
{
- _filter = value;
+ _filter = value == "*.*" ? "*" : value;
}
}
}
@@ -267,7 +267,7 @@ namespace System.IO
/// <devdoc>
/// Gets or sets the path of the directory to watch.
- /// </devdoc>
+ /// </devdoc>
public string Path
{
get
@@ -404,10 +404,10 @@ namespace System.IO
/// <internalonly/>
private bool MatchPattern(string relativePath)
{
- string name = System.IO.Path.GetFileName(relativePath);
- return name != null ?
- PatternMatcher.StrictMatchPattern(_filter, name) :
- false;
+ ReadOnlySpan<char> name = IO.Path.GetFileName(relativePath.AsSpan());
+ return name.Length > 0
+ ? FileSystemName.MatchesSimpleExpression(_filter, name, ignoreCase: !PathInternal.IsCaseSensitive)
+ : false;
}
/// <devdoc>
@@ -662,7 +662,6 @@ namespace System.IO
{
return _synchronizingObject;
}
-
set
{
_synchronizingObject = value;
diff --git a/src/System.IO.FileSystem.Watcher/src/System/IO/PatternMatcher.cs b/src/System.IO.FileSystem.Watcher/src/System/IO/PatternMatcher.cs
deleted file mode 100644
index 91f18a3640..0000000000
--- a/src/System.IO.FileSystem.Watcher/src/System/IO/PatternMatcher.cs
+++ /dev/null
@@ -1,505 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-namespace System.IO
-{
- internal static class PatternMatcher
- {
- /// <devdoc>
- /// Private constants (directly from C header files)
- /// </devdoc>
- private const int MATCHES_ARRAY_SIZE = 16;
- private const char ANSI_DOS_STAR = '>';
- private const char ANSI_DOS_QM = '<';
- private const char DOS_DOT = '"';
-
- /// <devdoc>
- /// Tells whether a given name matches the expression given with a strict (i.e. UNIX like)
- /// semantics. This code is a port of unmanaged code. Original code comment follows:
- ///
- /// Routine Description:
- ///
- /// This routine compares a Dbcs name and an expression and tells the caller
- /// if the name is in the language defined by the expression. The input name
- /// cannot contain wildcards, while the expression may contain wildcards.
- ///
- /// Expression wild cards are evaluated as shown in the nondeterministic
- /// finite automatons below. Note that ~* and ~? are DOS_STAR and DOS_QM.
- ///
- ///
- /// ~* is DOS_STAR, ~? is DOS_QM, and ~. is DOS_DOT
- ///
- ///
- /// S
- /// &lt;-----&lt;
- /// X | | e Y
- /// X * Y == (0)-----&gt;-(1)-&gt;-----(2)-----(3)
- ///
- ///
- /// S-.
- /// &lt;-----&lt;
- /// X | | e Y
- /// X ~* Y == (0)-----&gt;-(1)-&gt;-----(2)-----(3)
- ///
- ///
- ///
- /// X S S Y
- /// X ?? Y == (0)---(1)---(2)---(3)---(4)
- ///
- ///
- ///
- /// X . . Y
- /// X ~.~. Y == (0)---(1)----(2)------(3)---(4)
- /// | |________|
- /// | ^ |
- /// |_______________|
- /// ^EOF or .^
- ///
- ///
- /// X S-. S-. Y
- /// X ~?~? Y == (0)---(1)-----(2)-----(3)---(4)
- /// | |________|
- /// | ^ |
- /// |_______________|
- /// ^EOF or .^
- ///
- ///
- ///
- /// where S is any single character
- ///
- /// S-. is any single character except the final .
- ///
- /// e is a null character transition
- ///
- /// EOF is the end of the name string
- ///
- /// In words:
- ///
- /// * matches 0 or more characters.
- ///
- /// ? matches exactly 1 character.
- ///
- /// DOS_STAR matches 0 or more characters until encountering and matching
- /// the final . in the name.
- ///
- /// DOS_QM matches any single character, or upon encountering a period or
- /// end of name string, advances the expression to the end of the
- /// set of contiguous DOS_QMs.
- ///
- /// DOS_DOT matches either a . or zero characters beyond name string.
- ///
- /// Arguments:
- ///
- /// Expression - Supplies the input expression to check against
- ///
- /// Name - Supplies the input name to check for.
- ///
- /// Return Value:
- ///
- /// BOOLEAN - TRUE if Name is an element in the set of strings denoted
- /// by the input Expression and FALSE otherwise.
- ///
- /// </devdoc>
- public static bool StrictMatchPattern(string expression, string name)
- {
- //
- // The idea behind the algorithm is pretty simple. We keep track of
- // all possible locations in the regular expression that are matching
- // the name. If when the name has been exhausted one of the locations
- // in the expression is also just exhausted, the name is in the language
- // defined by the regular expression.
- //
-
- if (name == null || name.Length == 0 || expression == null || expression.Length == 0)
- {
- return false;
- }
-
- //
- // Special case by far the most common wild card search of * or *.*
- //
-
- if (expression.Equals("*") || expression.Equals("*.*"))
- {
- return true;
- }
-
- // If this class is ever exposed for generic use,
- // we need to make sure that name doesn't contain wildcards. Currently
- // the only component that calls this method is FileSystemWatcher and
- // it will never pass a name that contains a wildcard.
-
-
- //
- // Also special case expressions of the form *X. With this and the prior
- // case we have covered virtually all normal queries.
- //
- if (expression[0] == '*' && expression.IndexOf('*', 1) == -1)
- {
- int rightLength = expression.Length - 1;
- // if name is shorter that the stuff to the right of * in expression, we don't
- // need to do the string compare, otherwise we compare rightlength characters
- // and the end of both strings.
- if (name.Length >= rightLength &&
- string.Compare(expression, 1, name, name.Length - rightLength, rightLength, PathInternal.StringComparison) == 0)
- {
- return true;
- }
- }
-
- //
- // Walk through the name string, picking off characters. We go one
- // character beyond the end because some wild cards are able to match
- // zero characters beyond the end of the string.
- //
- // With each new name character we determine a new set of states that
- // match the name so far. We use two arrays that we swap back and forth
- // for this purpose. One array lists the possible expression states for
- // all name characters up to but not including the current one, and other
- // array is used to build up the list of states considering the current
- // name character as well. The arrays are then switched and the process
- // repeated.
- //
- // There is not a one-to-one correspondence between state number and
- // offset into the expression. This is evident from the NFAs in the
- // initial comment to this function. State numbering is not continuous.
- // This allows a simple conversion between state number and expression
- // offset. Each character in the expression can represent one or two
- // states. * and DOS_STAR generate two states: ExprOffset*2 and
- // ExprOffset*2 + 1. All other expression characters can produce only
- // a single state. Thus ExprOffset = State/2.
- //
- //
- // Here is a short description of the variables involved:
- //
- // NameOffset - The offset of the current name char being processed.
- //
- // ExprOffset - The offset of the current expression char being processed.
- //
- // SrcCount - Prior match being investigated with current name char
- //
- // DestCount - Next location to put a matching assuming current name char
- //
- // NameFinished - Allows one more iteration through the Matches array
- // after the name is exhausted (to come *s for example)
- //
- // PreviousDestCount - This is used to prevent entry duplication, see comment
- //
- // PreviousMatches - Holds the previous set of matches (the Src array)
- //
- // CurrentMatches - Holds the current set of matches (the Dest array)
- //
- // AuxBuffer, LocalBuffer - the storage for the Matches arrays
- //
-
- //
- // Set up the initial variables
- //
- int nameOffset;
- int exprOffset;
- int length;
-
- int srcCount;
- int destCount;
- int previousDestCount;
- int matchesCount;
-
- char nameChar = '\0';
- char exprChar = '\0';
-
- int[] previousMatches = new int[MATCHES_ARRAY_SIZE];
- int[] currentMatches = new int[MATCHES_ARRAY_SIZE];
-
- int maxState;
- int currentState;
-
- bool nameFinished = false;
-
- previousMatches[0] = 0;
- matchesCount = 1;
-
- nameOffset = 0;
- maxState = expression.Length * 2;
-
- while (!nameFinished)
- {
- if (nameOffset < name.Length)
- {
- nameChar = name[nameOffset];
- nameOffset++;
- }
- else
- {
- nameFinished = true;
-
- //
- // if we have already exhausted the expression, C#. Don't
- // continue.
- //
- if (previousMatches[matchesCount - 1] == maxState)
- {
- break;
- }
- }
-
- //
- // Now, for each of the previous stored expression matches, see what
- // we can do with this name character.
- //
- srcCount = 0;
- destCount = 0;
- previousDestCount = 0;
-
- while (srcCount < matchesCount)
- {
- //
- // We have to carry on our expression analysis as far as possible
- // for each character of name, so we loop here until the
- // expression stops matching. A clue here is that expression
- // cases that can match zero or more characters end with a
- // continue, while those that can accept only a single character
- // end with a break.
- //
- exprOffset = ((previousMatches[srcCount++] + 1) / 2);
- length = 0;
-
- while (true)
- {
- if (exprOffset == expression.Length)
- {
- break;
- }
-
- //
- // The first time through the loop we don't want
- // to increment ExprOffset.
- //
-
- exprOffset += length;
-
- currentState = exprOffset * 2;
-
- if (exprOffset == expression.Length)
- {
- currentMatches[destCount++] = maxState;
- break;
- }
-
- exprChar = expression[exprOffset];
- length = 1;
-
- //
- // We may be about to exhaust the local
- // space for ExpressionMatches[][], so we have to allocate
- // some pool if this is the case.
- //
-
- if (destCount >= MATCHES_ARRAY_SIZE - 2)
- {
- int newSize = currentMatches.Length * 2;
- int[] tmp = new int[newSize];
- Array.Copy(currentMatches, 0, tmp, 0, currentMatches.Length);
- currentMatches = tmp;
-
- tmp = new int[newSize];
- Array.Copy(previousMatches, 0, tmp, 0, previousMatches.Length);
- previousMatches = tmp;
- }
-
- //
- // * matches any character zero or more times.
- //
-
- if (exprChar == '*')
- {
- currentMatches[destCount++] = currentState;
- currentMatches[destCount++] = (currentState + 1);
- continue;
- }
-
- //
- // DOS_STAR matches any character except . zero or more times.
- //
-
- if (exprChar == ANSI_DOS_STAR)
- {
- bool iCanEatADot = false;
-
- //
- // If we are at a period, determine if we are allowed to
- // consume it, i.e. make sure it is not the last one.
- //
- if (!nameFinished && (nameChar == '.'))
- {
- char tmpChar;
- int offset;
-
- int nameLength = name.Length;
- for (offset = nameOffset; offset < nameLength; offset++)
- {
- tmpChar = name[offset];
- length = 1;
-
- if (tmpChar == '.')
- {
- iCanEatADot = true;
- break;
- }
- }
- }
-
- if (nameFinished || (nameChar != '.') || iCanEatADot)
- {
- currentMatches[destCount++] = currentState;
- currentMatches[destCount++] = (currentState + 1);
- continue;
- }
- else
- {
- //
- // We are at a period. We can only match zero
- // characters (i.e. the epsilon transition).
- //
- currentMatches[destCount++] = (currentState + 1);
- continue;
- }
- }
-
- //
- // The following expression characters all match by consuming
- // a character, thus force the expression, and thus state
- // forward.
- //
- currentState += length * 2;
-
- //
- // DOS_QM is the most complicated. If the name is finished,
- // we can match zero characters. If this name is a '.', we
- // don't match, but look at the next expression. Otherwise
- // we match a single character.
- //
- if (exprChar == ANSI_DOS_QM)
- {
- if (nameFinished || (nameChar == '.'))
- {
- continue;
- }
-
- currentMatches[destCount++] = currentState;
- break;
- }
-
- //
- // A DOS_DOT can match either a period, or zero characters
- // beyond the end of name.
- //
- if (exprChar == DOS_DOT)
- {
- if (nameFinished)
- {
- continue;
- }
-
- if (nameChar == '.')
- {
- currentMatches[destCount++] = currentState;
- break;
- }
- }
-
- //
- // From this point on a name character is required to even
- // continue, let alone make a match.
- //
- if (nameFinished)
- {
- break;
- }
-
- //
- // If this expression was a '?' we can match it once.
- //
- if (exprChar == '?')
- {
- currentMatches[destCount++] = currentState;
- break;
- }
-
- //
- // Finally, check if the expression char matches the name char
- //
-
- if (PathInternal.IsCaseSensitive ?
- (exprChar == nameChar) :
- (char.ToUpperInvariant(exprChar) == char.ToUpperInvariant(nameChar)))
- {
- currentMatches[destCount++] = currentState;
- break;
- }
-
- //
- // The expression didn't match so go look at the next
- // previous match.
- //
-
- break;
- }
-
-
- //
- // Prevent duplication in the destination array.
- //
- // Each of the arrays is monotonically increasing and non-
- // duplicating, thus we skip over any source element in the src
- // array if we just added the same element to the destination
- // array. This guarantees non-duplication in the dest. array.
- //
-
- if ((srcCount < matchesCount) && (previousDestCount < destCount))
- {
- while (previousDestCount < destCount)
- {
- int previousLength = previousMatches.Length;
- while ((srcCount < previousLength) && (previousMatches[srcCount] < currentMatches[previousDestCount]))
- {
- srcCount += 1;
- }
- previousDestCount += 1;
- }
- }
- }
-
- //
- // If we found no matches in the just finished iteration, it's time
- // to bail.
- //
-
- if (destCount == 0)
- {
- return false;
- }
-
- //
- // Swap the meaning the two arrays
- //
-
- {
- int[] tmp;
-
- tmp = previousMatches;
-
- previousMatches = currentMatches;
-
- currentMatches = tmp;
- }
-
- matchesCount = destCount;
- }
-
- currentState = previousMatches[matchesCount - 1];
-
- return currentState == maxState;
- }
- }
-}
diff --git a/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.unit.cs b/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.unit.cs
index 1f227a52ba..ae0e08f98a 100644
--- a/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.unit.cs
+++ b/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.unit.cs
@@ -70,8 +70,8 @@ namespace System.IO.Tests
[Fact]
public void FileSystemWatcher_ctor()
{
- string path = String.Empty;
- string pattern = "*.*";
+ string path = string.Empty;
+ string pattern = PlatformDetection.IsFullFramework ? "*.*" : "*";
using (FileSystemWatcher watcher = new FileSystemWatcher())
ValidateDefaults(watcher, path, pattern);
}
@@ -80,7 +80,7 @@ namespace System.IO.Tests
public void FileSystemWatcher_ctor_path()
{
string path = @".";
- string pattern = "*.*";
+ string pattern = PlatformDetection.IsFullFramework ? "*.*" : "*";
using (FileSystemWatcher watcher = new FileSystemWatcher(path))
ValidateDefaults(watcher, path, pattern);
}
@@ -220,14 +220,14 @@ namespace System.IO.Tests
{
FileSystemWatcher watcher = new FileSystemWatcher();
- Assert.Equal("*.*", watcher.Filter);
+ Assert.Equal(PlatformDetection.IsFullFramework ? "*.*" : "*", watcher.Filter);
- // Null and empty should be mapped to "*.*"
+ // Null and empty should be mapped to "*"
watcher.Filter = null;
- Assert.Equal("*.*", watcher.Filter);
+ Assert.Equal(PlatformDetection.IsFullFramework ? "*.*" : "*", watcher.Filter);
- watcher.Filter = String.Empty;
- Assert.Equal("*.*", watcher.Filter);
+ watcher.Filter = string.Empty;
+ Assert.Equal(PlatformDetection.IsFullFramework ? "*.*" : "*", watcher.Filter);
watcher.Filter = " ";
Assert.Equal(" ", watcher.Filter);
@@ -245,7 +245,7 @@ namespace System.IO.Tests
RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
// expect no change for OrdinalIgnoreCase-equal strings
- // it's unclear why desktop does this but preserve it for compat
+ // it's unclear why desktop does this but preserve it for compat
watcher.Filter = "ABC.DLL";
Assert.Equal("abc.dll", watcher.Filter);
}
diff --git a/src/System.IO.FileSystem/ref/System.IO.FileSystem.cs b/src/System.IO.FileSystem/ref/System.IO.FileSystem.cs
index e4ba63826d..8f0ee01b28 100644
--- a/src/System.IO.FileSystem/ref/System.IO.FileSystem.cs
+++ b/src/System.IO.FileSystem/ref/System.IO.FileSystem.cs
@@ -20,12 +20,15 @@ namespace System.IO
public static System.Collections.Generic.IEnumerable<string> EnumerateDirectories(string path) { throw null; }
public static System.Collections.Generic.IEnumerable<string> EnumerateDirectories(string path, string searchPattern) { throw null; }
public static System.Collections.Generic.IEnumerable<string> EnumerateDirectories(string path, string searchPattern, System.IO.SearchOption searchOption) { throw null; }
+ public static System.Collections.Generic.IEnumerable<string> EnumerateDirectories(string path, string searchPattern, System.IO.EnumerationOptions enumerationOptions) { throw null; }
public static System.Collections.Generic.IEnumerable<string> EnumerateFiles(string path) { throw null; }
public static System.Collections.Generic.IEnumerable<string> EnumerateFiles(string path, string searchPattern) { throw null; }
public static System.Collections.Generic.IEnumerable<string> EnumerateFiles(string path, string searchPattern, System.IO.SearchOption searchOption) { throw null; }
+ public static System.Collections.Generic.IEnumerable<string> EnumerateFiles(string path, string searchPattern, System.IO.EnumerationOptions enumerationOptions) { throw null; }
public static System.Collections.Generic.IEnumerable<string> EnumerateFileSystemEntries(string path) { throw null; }
public static System.Collections.Generic.IEnumerable<string> EnumerateFileSystemEntries(string path, string searchPattern) { throw null; }
public static System.Collections.Generic.IEnumerable<string> EnumerateFileSystemEntries(string path, string searchPattern, System.IO.SearchOption searchOption) { throw null; }
+ public static System.Collections.Generic.IEnumerable<string> EnumerateFileSystemEntries(string path, string searchPattern, System.IO.EnumerationOptions enumerationOptions) { throw null; }
public static bool Exists(string path) { throw null; }
public static System.DateTime GetCreationTime(string path) { throw null; }
public static System.DateTime GetCreationTimeUtc(string path) { throw null; }
@@ -33,13 +36,16 @@ namespace System.IO
public static string[] GetDirectories(string path) { throw null; }
public static string[] GetDirectories(string path, string searchPattern) { throw null; }
public static string[] GetDirectories(string path, string searchPattern, System.IO.SearchOption searchOption) { throw null; }
+ public static string[] GetDirectories(string path, string searchPattern, System.IO.EnumerationOptions enumerationOptions) { throw null; }
public static string GetDirectoryRoot(string path) { throw null; }
public static string[] GetFiles(string path) { throw null; }
public static string[] GetFiles(string path, string searchPattern) { throw null; }
public static string[] GetFiles(string path, string searchPattern, System.IO.SearchOption searchOption) { throw null; }
+ public static string[] GetFiles(string path, string searchPattern, System.IO.EnumerationOptions enumerationOptions) { throw null; }
public static string[] GetFileSystemEntries(string path) { throw null; }
public static string[] GetFileSystemEntries(string path, string searchPattern) { throw null; }
public static string[] GetFileSystemEntries(string path, string searchPattern, System.IO.SearchOption searchOption) { throw null; }
+ public static string[] GetFileSystemEntries(string path, string searchPattern, System.IO.EnumerationOptions enumerationOptions) { throw null; }
public static System.DateTime GetLastAccessTime(string path) { throw null; }
public static System.DateTime GetLastAccessTimeUtc(string path) { throw null; }
public static System.DateTime GetLastWriteTime(string path) { throw null; }
@@ -67,23 +73,29 @@ namespace System.IO
public override void Delete() { }
public void Delete(bool recursive) { }
public System.Collections.Generic.IEnumerable<System.IO.DirectoryInfo> EnumerateDirectories() { throw null; }
+ public System.Collections.Generic.IEnumerable<System.IO.DirectoryInfo> EnumerateDirectories(string searchPattern, System.IO.EnumerationOptions enumerationOptions) { throw null; }
+ public System.Collections.Generic.IEnumerable<System.IO.FileSystemInfo> EnumerateFileSystemInfos(string searchPattern, System.IO.EnumerationOptions enumerationOptions) { throw null; }
public System.Collections.Generic.IEnumerable<System.IO.DirectoryInfo> EnumerateDirectories(string searchPattern) { throw null; }
- public System.Collections.Generic.IEnumerable<System.IO.DirectoryInfo> EnumerateDirectories(string searchPattern, System.IO.SearchOption searchOption) { throw null; }
public System.Collections.Generic.IEnumerable<System.IO.FileInfo> EnumerateFiles() { throw null; }
public System.Collections.Generic.IEnumerable<System.IO.FileInfo> EnumerateFiles(string searchPattern) { throw null; }
public System.Collections.Generic.IEnumerable<System.IO.FileInfo> EnumerateFiles(string searchPattern, System.IO.SearchOption searchOption) { throw null; }
+ public System.Collections.Generic.IEnumerable<System.IO.FileInfo> EnumerateFiles(string searchPattern, System.IO.EnumerationOptions enumerationOptions) { throw null; }
public System.Collections.Generic.IEnumerable<System.IO.FileSystemInfo> EnumerateFileSystemInfos() { throw null; }
public System.Collections.Generic.IEnumerable<System.IO.FileSystemInfo> EnumerateFileSystemInfos(string searchPattern) { throw null; }
public System.Collections.Generic.IEnumerable<System.IO.FileSystemInfo> EnumerateFileSystemInfos(string searchPattern, System.IO.SearchOption searchOption) { throw null; }
+ public System.Collections.Generic.IEnumerable<System.IO.DirectoryInfo> EnumerateDirectories(string searchPattern, System.IO.SearchOption searchOption) { throw null; }
public System.IO.DirectoryInfo[] GetDirectories() { throw null; }
public System.IO.DirectoryInfo[] GetDirectories(string searchPattern) { throw null; }
public System.IO.DirectoryInfo[] GetDirectories(string searchPattern, System.IO.SearchOption searchOption) { throw null; }
+ public System.IO.DirectoryInfo[] GetDirectories(string searchPattern, System.IO.EnumerationOptions enumerationOptions) { throw null; }
public System.IO.FileInfo[] GetFiles() { throw null; }
public System.IO.FileInfo[] GetFiles(string searchPattern) { throw null; }
public System.IO.FileInfo[] GetFiles(string searchPattern, System.IO.SearchOption searchOption) { throw null; }
+ public System.IO.FileInfo[] GetFiles(string searchPattern, System.IO.EnumerationOptions enumerationOptions) { throw null; }
public System.IO.FileSystemInfo[] GetFileSystemInfos() { throw null; }
public System.IO.FileSystemInfo[] GetFileSystemInfos(string searchPattern) { throw null; }
public System.IO.FileSystemInfo[] GetFileSystemInfos(string searchPattern, System.IO.SearchOption searchOption) { throw null; }
+ public System.IO.FileSystemInfo[] GetFileSystemInfos(string searchPattern, System.IO.EnumerationOptions enumerationOptions) { throw null; }
public void MoveTo(string destDirName) { }
public override string ToString() { throw null; }
}
@@ -211,4 +223,83 @@ namespace System.IO
AllDirectories = 1,
TopDirectoryOnly = 0,
}
+ public enum MatchType
+ {
+ Simple,
+ Win32
+ }
+ public enum MatchCasing
+ {
+ PlatformDefault,
+ CaseSensitive,
+ CaseInsensitive
+ }
+ public class EnumerationOptions
+ {
+ public EnumerationOptions() { }
+ public bool RecurseSubdirectories { get { throw null; } set { } }
+ public bool IgnoreInaccessible { get { throw null; } set { } }
+ public int BufferSize { get { throw null; } set { } }
+ public FileAttributes AttributesToSkip { get { throw null; } set { } }
+ public MatchType MatchType { get { throw null; } set { } }
+ public MatchCasing MatchCasing { get { throw null; } set { } }
+ public bool ReturnSpecialDirectories { get { throw null; } set { } }
+ }
+}
+namespace System.IO.Enumeration
+{
+ public ref struct FileSystemEntry
+ {
+ public ReadOnlySpan<char> Directory { get { throw null; } }
+ public ReadOnlySpan<char> RootDirectory { get { throw null; } }
+ public ReadOnlySpan<char> OriginalRootDirectory { get { throw null; } }
+ public ReadOnlySpan<char> FileName { get { throw null; } }
+ public FileAttributes Attributes { get { throw null; } }
+ public long Length { get { throw null; } }
+ public DateTimeOffset CreationTimeUtc { get { throw null; } }
+ public DateTimeOffset LastAccessTimeUtc { get { throw null; } }
+ public DateTimeOffset LastWriteTimeUtc { get { throw null; } }
+ public bool IsDirectory { get { throw null; } }
+ public bool IsHidden { get { throw null; } }
+ public FileSystemInfo ToFileSystemInfo() { throw null; }
+ public string ToSpecifiedFullPath() { throw null; }
+ public string ToFullPath() { throw null; }
+ }
+ public abstract class FileSystemEnumerator<TResult> : Runtime.ConstrainedExecution.CriticalFinalizerObject, Collections.Generic.IEnumerator<TResult>
+ {
+ public FileSystemEnumerator(string directory, EnumerationOptions options = null) { }
+
+ protected virtual bool ShouldIncludeEntry(ref FileSystemEntry entry) { throw null; }
+ protected virtual bool ShouldRecurseIntoEntry(ref FileSystemEntry entry) { throw null; }
+ protected abstract TResult TransformEntry(ref FileSystemEntry entry);
+ protected virtual void OnDirectoryFinished(ReadOnlySpan<char> directory) { throw null; }
+ protected virtual bool ContinueOnError(int error) { throw null; }
+
+ public TResult Current { get { throw null; } }
+ object System.Collections.IEnumerator.Current { get { throw null; } }
+ public bool MoveNext() { throw null; }
+ public void Reset() { throw null; }
+ public void Dispose() { throw null; }
+ protected virtual void Dispose(bool disposing) { throw null; }
+ }
+ public class FileSystemEnumerable<TResult> : Collections.Generic.IEnumerable<TResult>
+ {
+ public FileSystemEnumerable(string directory, FindTransform transform, EnumerationOptions options = null) { }
+
+ public FindPredicate ShouldRecursePredicate { get { throw null; } set { } }
+ public FindPredicate ShouldIncludePredicate { get { throw null; } set { } }
+
+ public Collections.Generic.IEnumerator<TResult> GetEnumerator() { throw null; }
+ Collections.IEnumerator Collections.IEnumerable.GetEnumerator() { throw null; }
+
+
+ public delegate bool FindPredicate(ref FileSystemEntry entry);
+ public delegate TResult FindTransform(ref FileSystemEntry entry);
+ }
+ public static class FileSystemName
+ {
+ public static string TranslateWin32Expression(string expression) { throw null; }
+ public static bool MatchesWin32Expression(ReadOnlySpan<char> expression, ReadOnlySpan<char> name, bool ignoreCase = true) { throw null; }
+ public static bool MatchesSimpleExpression(ReadOnlySpan<char> expression, ReadOnlySpan<char> name, bool ignoreCase = true) { throw null; }
+ }
}
diff --git a/src/System.IO.FileSystem/src/MatchingRefApiCompatBaseline.txt b/src/System.IO.FileSystem/src/MatchingRefApiCompatBaseline.txt
new file mode 100644
index 0000000000..57008615ab
--- /dev/null
+++ b/src/System.IO.FileSystem/src/MatchingRefApiCompatBaseline.txt
@@ -0,0 +1,8 @@
+Compat issues with assembly System.IO.FileSystem:
+# These are now virtual in the implementation, which should be ok.
+CannotMakeMemberAbstract : Member 'System.IO.FileSystemInfo.Exists' is abstract in the implementation but is not abstract in the contract.
+CannotMakeMemberAbstract : Member 'System.IO.FileSystemInfo.Name' is abstract in the implementation but is not abstract in the contract.
+CannotMakeMemberAbstract : Member 'System.IO.FileSystemInfo.Exists.get()' is abstract in the implementation but is not abstract in the contract.
+CannotMakeMemberAbstract : Member 'System.IO.FileSystemInfo.Name.get()' is abstract in the implementation but is not abstract in the contract.
+# C# generates backing fields for fixed buffers as public.
+TypesMustExist : Type 'System.IO.Enumeration.FileSystemEntry.<_fileNameBuffer>e__FixedBuffer' does not exist in the implementation but it does exist in the contract. \ No newline at end of file
diff --git a/src/System.IO.FileSystem/src/Microsoft/Win32/SafeHandles/SafeFindHandle.Windows.cs b/src/System.IO.FileSystem/src/Microsoft/Win32/SafeHandles/SafeFindHandle.Windows.cs
index c9c118c1b5..dc02183f43 100644
--- a/src/System.IO.FileSystem/src/Microsoft/Win32/SafeHandles/SafeFindHandle.Windows.cs
+++ b/src/System.IO.FileSystem/src/Microsoft/Win32/SafeHandles/SafeFindHandle.Windows.cs
@@ -3,10 +3,7 @@
// See the LICENSE file in the project root for more information.
using System;
-using System.Security;
using System.Runtime.InteropServices;
-using System.Runtime.CompilerServices;
-using Microsoft.Win32;
namespace Microsoft.Win32.SafeHandles
{
diff --git a/src/System.IO.FileSystem/src/System.IO.FileSystem.csproj b/src/System.IO.FileSystem/src/System.IO.FileSystem.csproj
index 3bf4354198..35b1396e06 100644
--- a/src/System.IO.FileSystem/src/System.IO.FileSystem.csproj
+++ b/src/System.IO.FileSystem/src/System.IO.FileSystem.csproj
@@ -7,6 +7,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<IsPartialFacadeAssembly>true</IsPartialFacadeAssembly>
<UWPCompatible Condition="'$(TargetGroup)' == 'uap' or '$(TargetGroup)' == 'uapaot'">true</UWPCompatible>
+ <ILLinkClearInitLocals>true</ILLinkClearInitLocals>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetsUnix)' == 'true'">
<NoWarn>$(NoWarn);414</NoWarn>
@@ -18,63 +19,42 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Release|AnyCPU'" />
<ItemGroup>
- <Compile Include="System\IO\CharSpanExtensions.cs" />
- <Compile Include="System\IO\DosMatcher.cs" />
+ <Compile Include="System\IO\Enumeration\FileSystemEnumerable.cs" />
+ <Compile Include="System\IO\Enumeration\FileSystemEnumerableFactory.cs" />
+ <Compile Include="System\IO\Enumeration\FileSystemEnumerator.cs" />
+ <Compile Include="System\IO\Enumeration\FileSystemName.cs" />
+ <Compile Include="System\IO\MatchCasing.cs" />
+ <Compile Include="System\IO\MatchType.cs" />
<Compile Include="System\IO\Error.cs" />
<Compile Include="System\IO\Directory.cs" />
<Compile Include="System\IO\DirectoryInfo.cs" />
<Compile Include="System\IO\File.cs" />
<Compile Include="System\IO\FileInfo.cs" />
<Compile Include="System\IO\FileSystemInfo.cs" />
+ <Compile Include="System\IO\EnumerationOptions.cs" />
<Compile Include="System\IO\Iterator.cs" />
- <Compile Include="System\IO\PathHelpers.cs" />
- <Compile Include="System\IO\PathPair.cs" />
<Compile Include="System\IO\ReadLinesIterator.cs" />
<Compile Include="System\IO\SearchOption.cs" />
<Compile Include="System\IO\SearchTarget.cs" />
- <Compile Include="$(CommonPath)\System\Collections\Generic\ArrayBuilder.cs">
- <Link>Common\System\Collections\Generic\ArrayBuilder.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\System\Collections\Generic\EnumerableHelpers.cs">
- <Link>Common\System\Collections\Generic\EnumerableHelpers.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\System\Collections\Generic\LargeArrayBuilder.cs">
- <Link>Common\System\Collections\Generic\LargeArrayBuilder.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\System\IO\StringBuilderCache.cs">
- <Link>Common\System\IO\StringBuilderCache.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\System\Text\ValueStringBuilder.cs">
- <Link>Common\System\Text\ValueStringBuilder.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\System\IO\PathInternal.cs">
- <Link>Common\System\IO\PathInternal.cs</Link>
+ <Compile Include="$(CommonPath)\CoreLib\System\Text\ValueStringBuilder.cs">
+ <Link>Common\CoreLib\System\Text\ValueStringBuilder.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\IO\PathInternal.CaseSensitivity.cs">
<Link>Common\System\IO\PathInternal.CaseSensitivity.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Threading\Tasks\TaskToApm.cs">
- <Link>Common\System\Threading\Tasks\TaskToApm.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\System\IO\StreamHelpers.CopyValidation.cs">
<Link>Common\System\IO\StreamHelpers.CopyValidation.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\CoreLib\System\IO\PathInternal.cs">
+ <Link>Common\CoreLib\System\IO\PathInternal.cs</Link>
+ </Compile>
</ItemGroup>
<!-- Windows -->
<ItemGroup Condition="'$(TargetsWindows)' == 'true'">
- <Compile Include="System\IO\CharSpanExtensions.Windows.cs" />
+ <Compile Include="System\IO\Enumeration\FileSystemEnumerator.Windows.cs" />
<Compile Include="System\IO\DisableMediaInsertionPrompt.cs" />
- <Compile Include="System\IO\DirectoryInfo.Windows.cs" />
- <Compile Include="System\IO\FileInfo.Windows.cs" />
- <Compile Include="System\IO\FindEnumerable.Windows.cs" />
- <Compile Include="System\IO\FindEnumerableFactory.cs" />
- <Compile Include="System\IO\FindPredicate.cs" />
- <Compile Include="System\IO\FindTransform.cs" />
- <Compile Include="System\IO\FindPredicates.cs" />
- <Compile Include="System\IO\FindTransforms.cs" />
<Compile Include="System\IO\FileSystemInfo.Windows.cs" />
- <Compile Include="System\IO\PathHelpers.Windows.cs" />
- <Compile Include="System\IO\RawFindData.cs" />
+ <Compile Include="System\IO\Enumeration\FileSystemEntry.Windows.cs" />
<Compile Include="System\IO\FileSystem.Windows.cs" />
<Compile Include="Microsoft\Win32\SafeHandles\SafeFindHandle.Windows.cs" />
<Compile Include="$(CommonPath)\Interop\Windows\Interop.Libraries.cs">
@@ -95,11 +75,11 @@
<Compile Include="$(CommonPath)\System\IO\DriveInfoInternal.Win32.cs">
<Link>Common\System\IO\DriveInfoInternal.Win32.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\IO\PathInternal.Windows.cs">
- <Link>Common\System\IO\PathInternal.Windows.cs</Link>
+ <Compile Include="$(CommonPath)\CoreLib\System\IO\PathInternal.Windows.cs">
+ <Link>Common\CoreLib\System\IO\PathInternal.Windows.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\IO\Win32Marshal.cs">
- <Link>Common\System\IO\Win32Marshal.cs</Link>
+ <Compile Include="$(CommonPath)\CoreLib\System\IO\Win32Marshal.cs">
+ <Link>Common\CoreLib\System\IO\Win32Marshal.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\Interop.BOOL.cs">
<Link>Common\Interop\Windows\Interop.BOOL.cs</Link>
@@ -107,51 +87,9 @@
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.SECURITY_ATTRIBUTES.cs">
<Link>Common\Interop\Windows\Interop.SECURITY_ATTRIBUTES.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.SecurityOptions.cs">
- <Link>Common\Interop\Windows\Interop.SecurityOptions.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.FileTypes.cs">
- <Link>Common\Interop\Windows\Interop.FileTypes.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.GetFileType_SafeHandle.cs">
- <Link>Common\Interop\Windows\Interop.GetFileType.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.FlushFileBuffers.cs">
- <Link>Common\Interop\Windows\Interop.FlushFileBuffers.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.SetEndOfFile.cs">
- <Link>Common\Interop\Windows\Interop.SetEndOfFile.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.SetFilePointerEx.cs">
- <Link>Common\Interop\Windows\Interop.SetFilePointerEx.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.CancelIoEx.cs">
- <Link>Common\Interop\Windows\Interop.CancelIoEx.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.ReadFile_SafeHandle_NativeOverlapped.cs">
- <Link>Common\Interop\Windows\Interop.ReadFile_NativeOverlapped.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.WriteFile_SafeHandle_NativeOverlapped.cs">
- <Link>Common\Interop\Windows\Interop.WriteFile_NativeOverlapped.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.ReadFile_SafeHandle_IntPtr.cs">
- <Link>Common\Interop\Windows\Interop.ReadFile_IntPtr.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.WriteFile_SafeHandle_IntPtr.cs">
- <Link>Common\Interop\Windows\Interop.WriteFile_IntPtr.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.SetFileInformationByHandle.cs">
<Link>Common\Interop\Windows\Interop.SetFileInformationByHandle.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.GetCurrentDirectory.cs">
- <Link>Common\Interop\Windows\Interop.GetCurrentDirectory.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.SetCurrentDirectory.cs">
- <Link>Common\Interop\Windows\Interop.SetCurrentDirectory.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.GetLongPathName.cs">
- <Link>Common\Interop\Windows\Interop.GetLongPathName.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.FindNextFile.cs">
<Link>Common\Interop\Windows\Interop.FindNextFile.cs</Link>
</Compile>
@@ -188,7 +126,6 @@
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.GET_FILEEX_INFO_LEVELS.cs">
<Link>Common\Interop\Windows\Interop.GET_FILEEX_INFO_LEVELS.cs</Link>
</Compile>
- <Compile Include="System\IO\FileSystemInfo.Win32.cs" />
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.SetThreadErrorMode.cs">
<Link>Common\Interop\Windows\Interop.SetThreadErrorMode.cs</Link>
</Compile>
@@ -246,7 +183,7 @@
</ItemGroup>
<!-- Windows : Win32 only -->
<ItemGroup Condition="'$(TargetsWindows)' == 'true' and '$(UWPCompatible)' != 'true'">
- <Compile Include="System\IO\FindEnumerable.Win32.cs" />
+ <Compile Include="System\IO\Enumeration\FileSystemEnumerator.Win32.cs" />
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.CreateFile.cs">
<Link>Common\Interop\Windows\Interop.CreateFile.cs</Link>
</Compile>
@@ -262,6 +199,9 @@
<Compile Include="$(CommonPath)\Interop\Windows\NtDll\Interop.NtQueryDirectoryFile.cs">
<Link>Common\Interop\Windows\Interop.NtQueryDirectoryFile.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\NtDll\Interop.NtCreateFile.cs">
+ <Link>Common\Interop\Windows\Interop.NtCreateFile.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\Interop\Windows\NtDll\Interop.FILE_INFORMATION_CLASS.cs">
<Link>Common\Interop\Windows\Interop.FILE_INFORMATION_CLASS.cs</Link>
</Compile>
@@ -274,7 +214,7 @@
</ItemGroup>
<!-- Windows : UAP - Win32 + WinRT -->
<ItemGroup Condition="'$(TargetsWindows)' == 'true' and '$(UWPCompatible)' == 'true'">
- <Compile Include="System\IO\FindEnumerable.WinRT.cs" />
+ <Compile Include="System\IO\Enumeration\FileSystemEnumerator.WinRT.cs" />
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.CreateFile2.cs">
<Link>Common\Interop\Windows\Interop.CreateFile2.cs</Link>
</Compile>
@@ -290,9 +230,10 @@
</ItemGroup>
<!-- Unix -->
<ItemGroup Condition="'$(TargetsUnix)' == 'true'">
- <Compile Include="System\IO\CharSpanExtensions.Unix.cs" />
+ <Compile Include="System\IO\FileStatus.Unix.cs" />
+ <Compile Include="System\IO\Enumeration\FileSystemEntry.Unix.cs" />
+ <Compile Include="System\IO\Enumeration\FileSystemEnumerator.Unix.cs" />
<Compile Include="System\IO\FileSystemInfo.Unix.cs" />
- <Compile Include="System\IO\PathHelpers.Unix.cs" />
<Compile Include="System\IO\FileSystem.Unix.cs" />
<Compile Include="$(CommonPath)\Interop\Unix\Interop.Libraries.cs">
<Link>Common\Interop\Unix\Interop.Libraries.cs</Link>
@@ -306,30 +247,12 @@
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.ChMod.cs">
<Link>Common\Interop\Unix\Interop.ChMod.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.Close.cs">
- <Link>Common\Interop\Unix\Interop.Close.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.CopyFile.cs">
<Link>Common\Interop\Unix\Interop.CopyFile.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.FTruncate.cs">
- <Link>Common\Interop\Unix\Interop.FTruncate.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.GetCwd.cs">
- <Link>Common\Interop\Unix\Interop.GetCwd.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.Open.cs">
- <Link>Common\Interop\Unix\Interop.Open.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.OpenFlags.cs">
- <Link>Common\Interop\Unix\Interop.OpenFlags.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.MkDir.cs">
<Link>Common\Interop\Unix\Interop.MkDir.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.PathConf.cs">
- <Link>Common\Interop\Unix\Interop.PathConf.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.Permissions.cs">
<Link>Common\Interop\Unix\Interop.Permissions.cs</Link>
</Compile>
@@ -345,36 +268,18 @@
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.Stat.cs">
<Link>Common\Interop\Unix\Interop.Stat.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.Stat.Span.cs">
+ <Link>Common\Interop\Unix\Interop.Stat.Span.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.ReadDir.cs">
<Link>Common\Interop\Unix\Interop.ReadDir.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.Access.cs">
- <Link>Common\Interop\Unix\Interop.Access.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.ChDir.cs">
- <Link>Common\Interop\Unix\Interop.ChDir.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.FLock.cs">
- <Link>Common\Interop\Unix\Interop.FLock.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.FnMatch.cs">
- <Link>Common\Interop\Unix\Interop.FnMatch.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.FSync.cs">
- <Link>Common\Interop\Unix\Interop.FSync.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.LSeek.cs">
- <Link>Common\Interop\Unix\Interop.LSeek.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.Link.cs">
<Link>Common\Interop\Unix\Interop.Link.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.MountPoints.cs">
<Link>Common\Interop\Unix\Interop.MountPoints.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.PosixFAdvise.cs">
- <Link>Common\Interop\Unix\Interop.PosixFAdvise.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.Read.cs">
<Link>Common\Interop\Unix\Interop.Read.cs</Link>
</Compile>
@@ -384,27 +289,25 @@
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.RmDir.cs">
<Link>Common\Interop\Unix\Interop.RmDir.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.Write.cs">
- <Link>Common\Interop\Unix\Interop.Write.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.UTime.cs">
<Link>Common\Interop\Unix\Interop.UTime.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeDirectoryHandle.Unix.cs">
- <Link>Common\Microsoft\Win32\SafeHandles\SafeDirectoryHandle.Unix.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\System\IO\PathInternal.Unix.cs">
- <Link>Common\System\IO\PathInternal.Unix.cs</Link>
+ <Compile Include="$(CommonPath)\CoreLib\System\IO\PathInternal.Unix.cs">
+ <Link>Common\CoreLib\System\IO\PathInternal.Unix.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\IO\DriveInfoInternal.Unix.cs">
<Link>Common\System\IO\DriveInfoInternal.Unix.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Text\ValueUtf8Converter.cs">
+ <Link>Common\System\Text\ValueUtf8Converter.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup>
<Reference Include="System.Buffers" />
<Reference Include="System.Collections" />
<Reference Include="System.Diagnostics.Debug" />
<Reference Include="System.Diagnostics.Tools" />
+ <Reference Include="System.Linq" />
<Reference Include="System.Memory" />
<Reference Include="System.Resources.ResourceManager" />
<Reference Include="System.Runtime" />
@@ -419,4 +322,4 @@
<Reference Include="System.Threading" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project>
+</Project> \ No newline at end of file
diff --git a/src/System.IO.FileSystem/src/System/IO/CharSpanExtensions.Unix.cs b/src/System.IO.FileSystem/src/System/IO/CharSpanExtensions.Unix.cs
deleted file mode 100644
index a1fae54777..0000000000
--- a/src/System.IO.FileSystem/src/System/IO/CharSpanExtensions.Unix.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Runtime.InteropServices;
-
-namespace System.IO
-{
- internal static partial class CharSpanExtensions
- {
- internal static unsafe bool EqualsOrdinal(ReadOnlySpan<char> first, ReadOnlySpan<char> second, bool ignoreCase = false)
- {
- if (first.Length != second.Length)
- return false;
-
- if (!ignoreCase)
- return first.SequenceEqual(second);
-
- fixed (char* fp = &MemoryMarshal.GetReference(first))
- fixed (char* sp = &MemoryMarshal.GetReference(second))
- {
- char* f = fp;
- char* s = sp;
-
- for (int i = 0; i < first.Length; i++)
- {
- if (*f != *s && char.ToUpperInvariant(*f) != char.ToUpperInvariant(*s))
- return false;
- f++;
- s++;
- }
- }
-
- return true;
- }
- }
-}
diff --git a/src/System.IO.FileSystem/src/System/IO/CharSpanExtensions.Windows.cs b/src/System.IO.FileSystem/src/System/IO/CharSpanExtensions.Windows.cs
deleted file mode 100644
index 0503635038..0000000000
--- a/src/System.IO.FileSystem/src/System/IO/CharSpanExtensions.Windows.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Runtime.InteropServices;
-using System.Runtime.CompilerServices;
-
-namespace System.IO
-{
- internal static partial class CharSpanExtensions
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static unsafe int CompareOrdinal(ReadOnlySpan<char> first, ReadOnlySpan<char> second, bool ignoreCase = false)
- {
- int result = Interop.Kernel32.CompareStringOrdinal(
- ref MemoryMarshal.GetReference(first),
- first.Length,
- ref MemoryMarshal.GetReference(second),
- second.Length,
- ignoreCase);
-
- if (result == 0)
- throw Win32Marshal.GetExceptionForWin32Error(Marshal.GetLastWin32Error());
-
- // CSTR_LESS_THAN 1 // string 1 less than string 2
- // CSTR_EQUAL 2 // string 1 equal to string 2
- // CSTR_GREATER_THAN 3 // string 1 greater than string 2
-
- return result - 2;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static bool EqualsOrdinal(ReadOnlySpan<char> first, ReadOnlySpan<char> second, bool ignoreCase = false)
- {
- if (first.Length != second.Length)
- return false;
-
- if (!ignoreCase)
- return first.SequenceEqual(second);
-
- return CompareOrdinal(first, second, ignoreCase) == 0;
- }
- }
-}
diff --git a/src/System.IO.FileSystem/src/System/IO/CharSpanExtensions.cs b/src/System.IO.FileSystem/src/System/IO/CharSpanExtensions.cs
deleted file mode 100644
index 80c6ba4160..0000000000
--- a/src/System.IO.FileSystem/src/System/IO/CharSpanExtensions.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-namespace System.IO
-{
- internal static partial class CharSpanExtensions
- {
- public static bool EndsWithOrdinal(this ReadOnlySpan<char> span, ReadOnlySpan<char> value, bool ignoreCase = false)
- {
- if (value.Length == 0)
- return true;
- else if (value.Length > span.Length)
- return false;
-
- span = span.Slice(span.Length - value.Length);
-
- if (ignoreCase == false)
- return span.SequenceEqual(value);
-
- return EqualsOrdinal(span, value, ignoreCase);
- }
- }
-}
diff --git a/src/System.IO.FileSystem/src/System/IO/Directory.cs b/src/System.IO.FileSystem/src/System/IO/Directory.cs
index 5f4b32550e..93e2d57c00 100644
--- a/src/System.IO.FileSystem/src/System/IO/Directory.cs
+++ b/src/System.IO.FileSystem/src/System/IO/Directory.cs
@@ -3,8 +3,8 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
-using System.Diagnostics;
-using System.Security;
+using System.IO.Enumeration;
+using System.Linq;
namespace System.IO
{
@@ -40,26 +40,7 @@ namespace System.IO
return new DirectoryInfo(fullPath, null);
}
- // Input to this method should already be fullpath. This method will ensure that we append
- // the trailing slash only when appropriate.
- internal static string EnsureTrailingDirectorySeparator(string fullPath)
- {
- string fullPathWithTrailingDirectorySeparator;
-
- if (!PathHelpers.EndsInDirectorySeparator(fullPath))
- fullPathWithTrailingDirectorySeparator = fullPath + PathHelpers.DirectorySeparatorCharAsString;
- else
- fullPathWithTrailingDirectorySeparator = fullPath;
-
- return fullPathWithTrailingDirectorySeparator;
- }
-
-
// Tests if the given path refers to an existing DirectoryInfo on disk.
- //
- // Your application must have Read permission to the directory's
- // contents.
- //
public static bool Exists(string path)
{
try
@@ -74,8 +55,6 @@ namespace System.IO
return FileSystem.DirectoryExists(fullPath);
}
catch (ArgumentException) { }
- catch (NotSupportedException) { } // Security can throw this on ":"
- catch (SecurityException) { }
catch (IOException) { }
catch (UnauthorizedAccessException) { }
@@ -148,286 +127,94 @@ namespace System.IO
return File.GetLastAccessTimeUtc(path);
}
- // Returns an array of filenames in the DirectoryInfo specified by path
- public static string[] GetFiles(string path)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
-
- return InternalGetFiles(path, "*", SearchOption.TopDirectoryOnly);
- }
-
- // Returns an array of Files in the current DirectoryInfo matching the
- // given search pattern (i.e. "*.txt").
- public static string[] GetFiles(string path, string searchPattern)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
- if (searchPattern == null)
- throw new ArgumentNullException(nameof(searchPattern));
+ public static string[] GetFiles(string path) => GetFiles(path, "*", enumerationOptions: EnumerationOptions.Compatible);
- return InternalGetFiles(path, searchPattern, SearchOption.TopDirectoryOnly);
- }
+ public static string[] GetFiles(string path, string searchPattern) => GetFiles(path, searchPattern, enumerationOptions: EnumerationOptions.Compatible);
- // Returns an array of Files in the current DirectoryInfo matching the
- // given search pattern (i.e. "*.txt") and search option
public static string[] GetFiles(string path, string searchPattern, SearchOption searchOption)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
- if (searchPattern == null)
- throw new ArgumentNullException(nameof(searchPattern));
- if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories))
- throw new ArgumentOutOfRangeException(nameof(searchOption), SR.ArgumentOutOfRange_Enum);
-
- return InternalGetFiles(path, searchPattern, searchOption);
- }
-
- // Returns an array of Files in the current DirectoryInfo matching the
- // given search pattern (i.e. "*.txt") and search option
- private static string[] InternalGetFiles(string path, string searchPattern, SearchOption searchOption)
- {
- Debug.Assert(path != null);
- Debug.Assert(searchPattern != null);
- Debug.Assert(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
+ => GetFiles(path, searchPattern, EnumerationOptions.FromSearchOption(searchOption));
- return InternalGetFileDirectoryNames(path, path, searchPattern, true, false, searchOption);
- }
-
- // Returns an array of Directories in the current directory.
- public static string[] GetDirectories(string path)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
+ public static string[] GetFiles(string path, string searchPattern, EnumerationOptions enumerationOptions)
+ => InternalEnumeratePaths(path, searchPattern, SearchTarget.Files, enumerationOptions).ToArray();
- return InternalGetDirectories(path, "*", SearchOption.TopDirectoryOnly);
- }
-
- // Returns an array of Directories in the current DirectoryInfo matching the
- // given search criteria (i.e. "*.txt").
- public static string[] GetDirectories(string path, string searchPattern)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
- if (searchPattern == null)
- throw new ArgumentNullException(nameof(searchPattern));
+ public static string[] GetDirectories(string path) => GetDirectories(path, "*", enumerationOptions: EnumerationOptions.Compatible);
- return InternalGetDirectories(path, searchPattern, SearchOption.TopDirectoryOnly);
- }
+ public static string[] GetDirectories(string path, string searchPattern) => GetDirectories(path, searchPattern, enumerationOptions: EnumerationOptions.Compatible);
- // Returns an array of Directories in the current DirectoryInfo matching the
- // given search criteria (i.e. "*.txt").
public static string[] GetDirectories(string path, string searchPattern, SearchOption searchOption)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
- if (searchPattern == null)
- throw new ArgumentNullException(nameof(searchPattern));
- if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories))
- throw new ArgumentOutOfRangeException(nameof(searchOption), SR.ArgumentOutOfRange_Enum);
+ => GetDirectories(path, searchPattern, EnumerationOptions.FromSearchOption(searchOption));
- return InternalGetDirectories(path, searchPattern, searchOption);
- }
+ public static string[] GetDirectories(string path, string searchPattern, EnumerationOptions enumerationOptions)
+ => InternalEnumeratePaths(path, searchPattern, SearchTarget.Directories, enumerationOptions).ToArray();
- // Returns an array of Directories in the current DirectoryInfo matching the
- // given search criteria (i.e. "*.txt").
- private static string[] InternalGetDirectories(string path, string searchPattern, SearchOption searchOption)
- {
- Debug.Assert(path != null);
- Debug.Assert(searchPattern != null);
- Debug.Assert(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
+ public static string[] GetFileSystemEntries(string path) => GetFileSystemEntries(path, "*", enumerationOptions: EnumerationOptions.Compatible);
- return InternalGetFileDirectoryNames(path, path, searchPattern, false, true, searchOption);
- }
-
- // Returns an array of strongly typed FileSystemInfo entries in the path
- public static string[] GetFileSystemEntries(string path)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
-
- return InternalGetFileSystemEntries(path, "*", SearchOption.TopDirectoryOnly);
- }
+ public static string[] GetFileSystemEntries(string path, string searchPattern) => GetFileSystemEntries(path, searchPattern, enumerationOptions: EnumerationOptions.Compatible);
- // Returns an array of strongly typed FileSystemInfo entries in the path with the
- // given search criteria (i.e. "*.txt"). We disallow .. as a part of the search criteria
- public static string[] GetFileSystemEntries(string path, string searchPattern)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
- if (searchPattern == null)
- throw new ArgumentNullException(nameof(searchPattern));
+ public static string[] GetFileSystemEntries(string path, string searchPattern, SearchOption searchOption)
+ => GetFileSystemEntries(path, searchPattern, EnumerationOptions.FromSearchOption(searchOption));
- return InternalGetFileSystemEntries(path, searchPattern, SearchOption.TopDirectoryOnly);
- }
+ public static string[] GetFileSystemEntries(string path, string searchPattern, EnumerationOptions enumerationOptions)
+ => InternalEnumeratePaths(path, searchPattern, SearchTarget.Both, enumerationOptions).ToArray();
- // Returns an array of strongly typed FileSystemInfo entries in the path with the
- // given search criteria (i.e. "*.txt"). We disallow .. as a part of the search criteria
- public static string[] GetFileSystemEntries(string path, string searchPattern, SearchOption searchOption)
+ internal static IEnumerable<string> InternalEnumeratePaths(
+ string path,
+ string searchPattern,
+ SearchTarget searchTarget,
+ EnumerationOptions options)
{
if (path == null)
throw new ArgumentNullException(nameof(path));
if (searchPattern == null)
throw new ArgumentNullException(nameof(searchPattern));
- if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories))
- throw new ArgumentOutOfRangeException(nameof(searchOption), SR.ArgumentOutOfRange_Enum);
-
- return InternalGetFileSystemEntries(path, searchPattern, searchOption);
- }
- private static string[] InternalGetFileSystemEntries(string path, string searchPattern, SearchOption searchOption)
- {
- Debug.Assert(path != null);
- Debug.Assert(searchPattern != null);
- Debug.Assert(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
+ FileSystemEnumerableFactory.NormalizeInputs(ref path, ref searchPattern, options);
- return InternalGetFileDirectoryNames(path, path, searchPattern, true, true, searchOption);
- }
-
- // Returns fully qualified user path of dirs/files that matches the search parameters.
- // For recursive search this method will search through all the sub dirs and execute
- // the given search criteria against every dir.
- // For all the dirs/files returned, it will then demand path discovery permission for
- // their parent folders (it will avoid duplicate permission checks)
- internal static string[] InternalGetFileDirectoryNames(string path, string userPathOriginal, string searchPattern, bool includeFiles, bool includeDirs, SearchOption searchOption)
- {
- Debug.Assert(path != null);
- Debug.Assert(userPathOriginal != null);
- Debug.Assert(searchPattern != null);
- Debug.Assert(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
-
- IEnumerable<string> enumerable = FileSystem.EnumeratePaths(path, searchPattern, searchOption,
- (includeFiles ? SearchTarget.Files : 0) | (includeDirs ? SearchTarget.Directories : 0));
- return EnumerableHelpers.ToArray(enumerable);
- }
-
- public static IEnumerable<string> EnumerateDirectories(string path)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
-
- return InternalEnumerateDirectories(path, "*", SearchOption.TopDirectoryOnly);
+ switch (searchTarget)
+ {
+ case SearchTarget.Files:
+ return FileSystemEnumerableFactory.UserFiles(path, searchPattern, options);
+ case SearchTarget.Directories:
+ return FileSystemEnumerableFactory.UserDirectories(path, searchPattern, options);
+ case SearchTarget.Both:
+ return FileSystemEnumerableFactory.UserEntries(path, searchPattern, options);
+ default:
+ throw new ArgumentOutOfRangeException(nameof(searchTarget));
+ }
}
- public static IEnumerable<string> EnumerateDirectories(string path, string searchPattern)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
- if (searchPattern == null)
- throw new ArgumentNullException(nameof(searchPattern));
+ public static IEnumerable<string> EnumerateDirectories(string path) => EnumerateDirectories(path, "*", enumerationOptions: EnumerationOptions.Compatible);
- return InternalEnumerateDirectories(path, searchPattern, SearchOption.TopDirectoryOnly);
- }
+ public static IEnumerable<string> EnumerateDirectories(string path, string searchPattern) => EnumerateDirectories(path, searchPattern, enumerationOptions: EnumerationOptions.Compatible);
public static IEnumerable<string> EnumerateDirectories(string path, string searchPattern, SearchOption searchOption)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
- if (searchPattern == null)
- throw new ArgumentNullException(nameof(searchPattern));
- if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories))
- throw new ArgumentOutOfRangeException(nameof(searchOption), SR.ArgumentOutOfRange_Enum);
-
- return InternalEnumerateDirectories(path, searchPattern, searchOption);
- }
-
- private static IEnumerable<string> InternalEnumerateDirectories(string path, string searchPattern, SearchOption searchOption)
- {
- Debug.Assert(path != null);
- Debug.Assert(searchPattern != null);
- Debug.Assert(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
+ => EnumerateDirectories(path, searchPattern, EnumerationOptions.FromSearchOption(searchOption));
- return EnumerateFileSystemNames(path, searchPattern, searchOption, false, true);
- }
+ public static IEnumerable<string> EnumerateDirectories(string path, string searchPattern, EnumerationOptions enumerationOptions)
+ => InternalEnumeratePaths(path, searchPattern, SearchTarget.Directories, enumerationOptions);
- public static IEnumerable<string> EnumerateFiles(string path)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
-
- return InternalEnumerateFiles(path, "*", SearchOption.TopDirectoryOnly);
- }
+ public static IEnumerable<string> EnumerateFiles(string path) => EnumerateFiles(path, "*", enumerationOptions: EnumerationOptions.Compatible);
public static IEnumerable<string> EnumerateFiles(string path, string searchPattern)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
- if (searchPattern == null)
- throw new ArgumentNullException(nameof(searchPattern));
-
- return InternalEnumerateFiles(path, searchPattern, SearchOption.TopDirectoryOnly);
- }
+ => EnumerateFiles(path, searchPattern, enumerationOptions: EnumerationOptions.Compatible);
public static IEnumerable<string> EnumerateFiles(string path, string searchPattern, SearchOption searchOption)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
- if (searchPattern == null)
- throw new ArgumentNullException(nameof(searchPattern));
- if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories))
- throw new ArgumentOutOfRangeException(nameof(searchOption), SR.ArgumentOutOfRange_Enum);
+ => EnumerateFiles(path, searchPattern, EnumerationOptions.FromSearchOption(searchOption));
- return InternalEnumerateFiles(path, searchPattern, searchOption);
- }
-
- private static IEnumerable<string> InternalEnumerateFiles(string path, string searchPattern, SearchOption searchOption)
- {
- Debug.Assert(path != null);
- Debug.Assert(searchPattern != null);
- Debug.Assert(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
-
- return EnumerateFileSystemNames(path, searchPattern, searchOption, true, false);
- }
+ public static IEnumerable<string> EnumerateFiles(string path, string searchPattern, EnumerationOptions enumerationOptions)
+ => InternalEnumeratePaths(path, searchPattern, SearchTarget.Files, enumerationOptions);
public static IEnumerable<string> EnumerateFileSystemEntries(string path)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
-
- return InternalEnumerateFileSystemEntries(path, "*", SearchOption.TopDirectoryOnly);
- }
+ => EnumerateFileSystemEntries(path, "*", enumerationOptions: EnumerationOptions.Compatible);
public static IEnumerable<string> EnumerateFileSystemEntries(string path, string searchPattern)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
- if (searchPattern == null)
- throw new ArgumentNullException(nameof(searchPattern));
-
- return InternalEnumerateFileSystemEntries(path, searchPattern, SearchOption.TopDirectoryOnly);
- }
+ => EnumerateFileSystemEntries(path, searchPattern, enumerationOptions: EnumerationOptions.Compatible);
public static IEnumerable<string> EnumerateFileSystemEntries(string path, string searchPattern, SearchOption searchOption)
- {
- if (path == null)
- throw new ArgumentNullException(nameof(path));
- if (searchPattern == null)
- throw new ArgumentNullException(nameof(searchPattern));
- if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories))
- throw new ArgumentOutOfRangeException(nameof(searchOption), SR.ArgumentOutOfRange_Enum);
+ => EnumerateFileSystemEntries(path, searchPattern, EnumerationOptions.FromSearchOption(searchOption));
- return InternalEnumerateFileSystemEntries(path, searchPattern, searchOption);
- }
-
- private static IEnumerable<string> InternalEnumerateFileSystemEntries(string path, string searchPattern, SearchOption searchOption)
- {
- Debug.Assert(path != null);
- Debug.Assert(searchPattern != null);
- Debug.Assert(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
-
- return EnumerateFileSystemNames(path, searchPattern, searchOption, true, true);
- }
-
- private static IEnumerable<string> EnumerateFileSystemNames(string path, string searchPattern, SearchOption searchOption,
- bool includeFiles, bool includeDirs)
- {
- Debug.Assert(path != null);
- Debug.Assert(searchPattern != null);
- Debug.Assert(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
-
- return FileSystem.EnumeratePaths(path, searchPattern, searchOption,
- (includeFiles ? SearchTarget.Files : 0) | (includeDirs ? SearchTarget.Directories : 0));
- }
+ public static IEnumerable<string> EnumerateFileSystemEntries(string path, string searchPattern, EnumerationOptions enumerationOptions)
+ => InternalEnumeratePaths(path, searchPattern, SearchTarget.Both, enumerationOptions);
public static string GetDirectoryRoot(string path)
{
@@ -446,17 +233,7 @@ namespace System.IO
return path.Substring(0, PathInternal.GetRootLength(path));
}
- /*===============================CurrentDirectory===============================
- **Action: Provides a getter and setter for the current directory. The original
- ** current DirectoryInfo is the one from which the process was started.
- **Returns: The current DirectoryInfo (from the getter). Void from the setter.
- **Arguments: The current DirectoryInfo to which to switch to the setter.
- **Exceptions:
- ==============================================================================*/
- public static string GetCurrentDirectory()
- {
- return FileSystem.GetCurrentDirectory();
- }
+ public static string GetCurrentDirectory() => Environment.CurrentDirectory;
public static void SetCurrentDirectory(string path)
{
@@ -465,9 +242,7 @@ namespace System.IO
if (path.Length == 0)
throw new ArgumentException(SR.Argument_PathEmpty, nameof(path));
- string fulldestDirName = Path.GetFullPath(path);
-
- FileSystem.SetCurrentDirectory(fulldestDirName);
+ Environment.CurrentDirectory = Path.GetFullPath(path);
}
public static void Move(string sourceDirName, string destDirName)
@@ -483,10 +258,10 @@ namespace System.IO
throw new ArgumentException(SR.Argument_EmptyFileName, nameof(destDirName));
string fullsourceDirName = Path.GetFullPath(sourceDirName);
- string sourcePath = EnsureTrailingDirectorySeparator(fullsourceDirName);
+ string sourcePath = PathInternal.EnsureTrailingSeparator(fullsourceDirName);
string fulldestDirName = Path.GetFullPath(destDirName);
- string destPath = EnsureTrailingDirectorySeparator(fulldestDirName);
+ string destPath = PathInternal.EnsureTrailingSeparator(fulldestDirName);
StringComparison pathComparison = PathInternal.StringComparison;
diff --git a/src/System.IO.FileSystem/src/System/IO/DirectoryInfo.Windows.cs b/src/System.IO.FileSystem/src/System/IO/DirectoryInfo.Windows.cs
deleted file mode 100644
index 1c1ebd0197..0000000000
--- a/src/System.IO.FileSystem/src/System/IO/DirectoryInfo.Windows.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-
-namespace System.IO
-{
- partial class DirectoryInfo
- {
- internal unsafe DirectoryInfo(string fullPath, string fileName, ref RawFindData findData)
- : this(fullPath, fileName: fileName, isNormalized: true)
- {
- Debug.Assert(fileName.Equals(Path.GetFileName(fullPath)));
- Init(findData._info);
- }
- }
-}
diff --git a/src/System.IO.FileSystem/src/System/IO/DirectoryInfo.cs b/src/System.IO.FileSystem/src/System/IO/DirectoryInfo.cs
index 006bbc115b..9f94d2bc19 100644
--- a/src/System.IO.FileSystem/src/System/IO/DirectoryInfo.cs
+++ b/src/System.IO.FileSystem/src/System/IO/DirectoryInfo.cs
@@ -4,17 +4,17 @@
using System.Collections.Generic;
using System.Diagnostics;
+using System.IO.Enumeration;
+using System.Linq;
namespace System.IO
{
[Serializable]
public sealed partial class DirectoryInfo : FileSystemInfo
{
- private string _name;
-
public DirectoryInfo(string path)
{
- Init(originalPath: PathHelpers.ShouldReviseDirectoryPathToCurrent(path) ? "." : path,
+ Init(originalPath: path,
fullPath: Path.GetFullPath(path),
isNormalized: true);
}
@@ -30,328 +30,155 @@ namespace System.IO
OriginalPath = originalPath ?? throw new ArgumentNullException("path");
fullPath = fullPath ?? originalPath;
- Debug.Assert(!isNormalized || !PathInternal.IsPartiallyQualified(fullPath), "should be fully qualified if normalized");
fullPath = isNormalized ? fullPath : Path.GetFullPath(fullPath);
- _name = fileName ?? (PathHelpers.IsRoot(fullPath) ?
+ _name = fileName ?? (PathInternal.IsRoot(fullPath) ?
fullPath :
- Path.GetFileName(PathHelpers.TrimEndingDirectorySeparator(fullPath)));
+ Path.GetFileName(PathInternal.TrimEndingDirectorySeparator(fullPath.AsSpan()))).ToString();
FullPath = fullPath;
- DisplayPath = PathHelpers.ShouldReviseDirectoryPathToCurrent(originalPath) ? "." : originalPath;
}
- public override string Name => _name;
-
public DirectoryInfo Parent
{
get
{
- string s = FullPath;
-
- // FullPath might end in either "parent\child" or "parent\child", and in either case we want
+ // FullPath might end in either "parent\child" or "parent\child\", and in either case we want
// the parent of child, not the child. Trim off an ending directory separator if there is one,
// but don't mangle the root.
- if (!PathHelpers.IsRoot(s))
- {
- s = PathHelpers.TrimEndingDirectorySeparator(s);
- }
-
- string parentName = Path.GetDirectoryName(s);
+ string parentName = Path.GetDirectoryName(PathInternal.IsRoot(FullPath) ? FullPath : PathInternal.TrimEndingDirectorySeparator(FullPath));
return parentName != null ?
new DirectoryInfo(parentName, null) :
null;
}
}
-
public DirectoryInfo CreateSubdirectory(string path)
{
if (path == null)
throw new ArgumentNullException(nameof(path));
+ if (PathInternal.IsEffectivelyEmpty(path))
+ throw new ArgumentException(SR.Argument_PathEmpty, nameof(path));
+ if (Path.IsPathRooted(path))
+ throw new ArgumentException(SR.Arg_Path2IsRooted, nameof(path));
- return CreateSubdirectoryHelper(path);
- }
-
- private DirectoryInfo CreateSubdirectoryHelper(string path)
- {
- Debug.Assert(path != null);
-
- PathHelpers.ThrowIfEmptyOrRootedPath(path);
-
- string newDirs = Path.Combine(FullPath, path);
- string fullPath = Path.GetFullPath(newDirs);
+ string fullPath = Path.GetFullPath(Path.Combine(FullPath, path));
- if (0 != string.Compare(FullPath, 0, fullPath, 0, FullPath.Length, PathInternal.StringComparison))
+ if (fullPath.Length < FullPath.Length
+ || (fullPath.Length > FullPath.Length && !PathInternal.IsDirectorySeparator(fullPath[FullPath.Length]))
+ || string.Compare(FullPath, 0, fullPath, 0, FullPath.Length, PathInternal.StringComparison) != 0)
{
- throw new ArgumentException(SR.Format(SR.Argument_InvalidSubPath, path, DisplayPath), nameof(path));
+ throw new ArgumentException(SR.Format(SR.Argument_InvalidSubPath, path, FullPath), nameof(path));
}
FileSystem.CreateDirectory(fullPath);
-
- // Check for read permission to directory we hand back by calling this constructor.
return new DirectoryInfo(fullPath);
}
- public void Create()
- {
- FileSystem.CreateDirectory(FullPath);
- }
+ public void Create() => FileSystem.CreateDirectory(FullPath);
- // Tests if the given path refers to an existing DirectoryInfo on disk.
- //
- // Your application must have Read permission to the directory's
- // contents.
- //
- public override bool Exists
- {
- get
- {
- try
- {
- return ExistsCore;
- }
- catch
- {
- return false;
- }
- }
- }
+ // Returns an array of Files in the DirectoryInfo specified by path
+ public FileInfo[] GetFiles() => GetFiles("*", enumerationOptions: EnumerationOptions.Compatible);
// Returns an array of Files in the current DirectoryInfo matching the
// given search criteria (i.e. "*.txt").
- public FileInfo[] GetFiles(string searchPattern)
- {
- if (searchPattern == null)
- throw new ArgumentNullException(nameof(searchPattern));
+ public FileInfo[] GetFiles(string searchPattern) => GetFiles(searchPattern, enumerationOptions: EnumerationOptions.Compatible);
- return InternalGetFiles(searchPattern, SearchOption.TopDirectoryOnly);
- }
-
- // Returns an array of Files in the current DirectoryInfo matching the
- // given search criteria (i.e. "*.txt").
public FileInfo[] GetFiles(string searchPattern, SearchOption searchOption)
- {
- if (searchPattern == null)
- throw new ArgumentNullException(nameof(searchPattern));
- if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories))
- throw new ArgumentOutOfRangeException(nameof(searchOption), SR.ArgumentOutOfRange_Enum);
+ => GetFiles(searchPattern, EnumerationOptions.FromSearchOption(searchOption));
- return InternalGetFiles(searchPattern, searchOption);
- }
+ public FileInfo[] GetFiles(string searchPattern, EnumerationOptions enumerationOptions)
+ => ((IEnumerable<FileInfo>)InternalEnumerateInfos(FullPath, searchPattern, SearchTarget.Files, enumerationOptions)).ToArray();
- // Returns an array of Files in the current DirectoryInfo matching the
- // given search criteria (i.e. "*.txt").
- private FileInfo[] InternalGetFiles(string searchPattern, SearchOption searchOption)
- {
- Debug.Assert(searchPattern != null);
- Debug.Assert(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
-
- IEnumerable<FileInfo> enumerable = (IEnumerable<FileInfo>)FileSystem.EnumerateFileSystemInfos(FullPath, searchPattern, searchOption, SearchTarget.Files);
- return EnumerableHelpers.ToArray(enumerable);
- }
-
- // Returns an array of Files in the DirectoryInfo specified by path
- public FileInfo[] GetFiles()
- {
- return InternalGetFiles("*", SearchOption.TopDirectoryOnly);
- }
-
- // Returns an array of Directories in the current directory.
- public DirectoryInfo[] GetDirectories()
- {
- return InternalGetDirectories("*", SearchOption.TopDirectoryOnly);
- }
+ // Returns an array of strongly typed FileSystemInfo entries which will contain a listing
+ // of all the files and directories.
+ public FileSystemInfo[] GetFileSystemInfos() => GetFileSystemInfos("*", enumerationOptions: EnumerationOptions.Compatible);
// Returns an array of strongly typed FileSystemInfo entries in the path with the
// given search criteria (i.e. "*.txt").
public FileSystemInfo[] GetFileSystemInfos(string searchPattern)
- {
- if (searchPattern == null)
- throw new ArgumentNullException(nameof(searchPattern));
+ => GetFileSystemInfos(searchPattern, enumerationOptions: EnumerationOptions.Compatible);
- return InternalGetFileSystemInfos(searchPattern, SearchOption.TopDirectoryOnly);
- }
-
- // Returns an array of strongly typed FileSystemInfo entries in the path with the
- // given search criteria (i.e. "*.txt").
public FileSystemInfo[] GetFileSystemInfos(string searchPattern, SearchOption searchOption)
- {
- if (searchPattern == null)
- throw new ArgumentNullException(nameof(searchPattern));
- if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories))
- throw new ArgumentOutOfRangeException(nameof(searchOption), SR.ArgumentOutOfRange_Enum);
+ => GetFileSystemInfos(searchPattern, EnumerationOptions.FromSearchOption(searchOption));
- return InternalGetFileSystemInfos(searchPattern, searchOption);
- }
-
- // Returns an array of strongly typed FileSystemInfo entries in the path with the
- // given search criteria (i.e. "*.txt").
- private FileSystemInfo[] InternalGetFileSystemInfos(string searchPattern, SearchOption searchOption)
- {
- Debug.Assert(searchPattern != null);
- Debug.Assert(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
-
- IEnumerable<FileSystemInfo> enumerable = FileSystem.EnumerateFileSystemInfos(FullPath, searchPattern, searchOption, SearchTarget.Both);
- return EnumerableHelpers.ToArray(enumerable);
- }
+ public FileSystemInfo[] GetFileSystemInfos(string searchPattern, EnumerationOptions enumerationOptions)
+ => InternalEnumerateInfos(FullPath, searchPattern, SearchTarget.Both, enumerationOptions).ToArray();
- // Returns an array of strongly typed FileSystemInfo entries which will contain a listing
- // of all the files and directories.
- public FileSystemInfo[] GetFileSystemInfos()
- {
- return InternalGetFileSystemInfos("*", SearchOption.TopDirectoryOnly);
- }
+ // Returns an array of Directories in the current directory.
+ public DirectoryInfo[] GetDirectories() => GetDirectories("*", enumerationOptions: EnumerationOptions.Compatible);
// Returns an array of Directories in the current DirectoryInfo matching the
- // given search criteria (i.e. "System*" could match the System & System32
- // directories).
- public DirectoryInfo[] GetDirectories(string searchPattern)
- {
- if (searchPattern == null)
- throw new ArgumentNullException(nameof(searchPattern));
+ // given search criteria (i.e. "System*" could match the System & System32 directories).
+ public DirectoryInfo[] GetDirectories(string searchPattern) => GetDirectories(searchPattern, enumerationOptions: EnumerationOptions.Compatible);
- return InternalGetDirectories(searchPattern, SearchOption.TopDirectoryOnly);
- }
-
- // Returns an array of Directories in the current DirectoryInfo matching the
- // given search criteria (i.e. "System*" could match the System & System32
- // directories).
public DirectoryInfo[] GetDirectories(string searchPattern, SearchOption searchOption)
- {
- if (searchPattern == null)
- throw new ArgumentNullException(nameof(searchPattern));
- if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories))
- throw new ArgumentOutOfRangeException(nameof(searchOption), SR.ArgumentOutOfRange_Enum);
-
- return InternalGetDirectories(searchPattern, searchOption);
- }
-
- // Returns an array of Directories in the current DirectoryInfo matching the
- // given search criteria (i.e. "System*" could match the System & System32
- // directories).
- private DirectoryInfo[] InternalGetDirectories(string searchPattern, SearchOption searchOption)
- {
- Debug.Assert(searchPattern != null);
- Debug.Assert(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
+ => GetDirectories(searchPattern, EnumerationOptions.FromSearchOption(searchOption));
- IEnumerable<DirectoryInfo> enumerable = (IEnumerable<DirectoryInfo>)FileSystem.EnumerateFileSystemInfos(FullPath, searchPattern, searchOption, SearchTarget.Directories);
- return EnumerableHelpers.ToArray(enumerable);
- }
+ public DirectoryInfo[] GetDirectories(string searchPattern, EnumerationOptions enumerationOptions)
+ => ((IEnumerable<DirectoryInfo>)InternalEnumerateInfos(FullPath, searchPattern, SearchTarget.Directories, enumerationOptions)).ToArray();
public IEnumerable<DirectoryInfo> EnumerateDirectories()
- {
- return InternalEnumerateDirectories("*", SearchOption.TopDirectoryOnly);
- }
+ => EnumerateDirectories("*", enumerationOptions: EnumerationOptions.Compatible);
public IEnumerable<DirectoryInfo> EnumerateDirectories(string searchPattern)
- {
- if (searchPattern == null)
- throw new ArgumentNullException(nameof(searchPattern));
-
- return InternalEnumerateDirectories(searchPattern, SearchOption.TopDirectoryOnly);
- }
+ => EnumerateDirectories(searchPattern, enumerationOptions: EnumerationOptions.Compatible);
public IEnumerable<DirectoryInfo> EnumerateDirectories(string searchPattern, SearchOption searchOption)
- {
- if (searchPattern == null)
- throw new ArgumentNullException(nameof(searchPattern));
- if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories))
- throw new ArgumentOutOfRangeException(nameof(searchOption), SR.ArgumentOutOfRange_Enum);
+ => EnumerateDirectories(searchPattern, EnumerationOptions.FromSearchOption(searchOption));
- return InternalEnumerateDirectories(searchPattern, searchOption);
- }
-
- private IEnumerable<DirectoryInfo> InternalEnumerateDirectories(string searchPattern, SearchOption searchOption)
- {
- Debug.Assert(searchPattern != null);
- Debug.Assert(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
-
- return (IEnumerable<DirectoryInfo>)FileSystem.EnumerateFileSystemInfos(FullPath, searchPattern, searchOption, SearchTarget.Directories);
- }
+ public IEnumerable<DirectoryInfo> EnumerateDirectories(string searchPattern, EnumerationOptions enumerationOptions)
+ => (IEnumerable<DirectoryInfo>)InternalEnumerateInfos(FullPath, searchPattern, SearchTarget.Directories, enumerationOptions);
public IEnumerable<FileInfo> EnumerateFiles()
- {
- return InternalEnumerateFiles("*", SearchOption.TopDirectoryOnly);
- }
-
- public IEnumerable<FileInfo> EnumerateFiles(string searchPattern)
- {
- if (searchPattern == null)
- throw new ArgumentNullException(nameof(searchPattern));
+ => EnumerateFiles("*", enumerationOptions: EnumerationOptions.Compatible);
- return InternalEnumerateFiles(searchPattern, SearchOption.TopDirectoryOnly);
- }
+ public IEnumerable<FileInfo> EnumerateFiles(string searchPattern) => EnumerateFiles(searchPattern, enumerationOptions: EnumerationOptions.Compatible);
public IEnumerable<FileInfo> EnumerateFiles(string searchPattern, SearchOption searchOption)
- {
- if (searchPattern == null)
- throw new ArgumentNullException(nameof(searchPattern));
- if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories))
- throw new ArgumentOutOfRangeException(nameof(searchOption), SR.ArgumentOutOfRange_Enum);
+ => EnumerateFiles(searchPattern, EnumerationOptions.FromSearchOption(searchOption));
- return InternalEnumerateFiles(searchPattern, searchOption);
- }
-
- private IEnumerable<FileInfo> InternalEnumerateFiles(string searchPattern, SearchOption searchOption)
- {
- Debug.Assert(searchPattern != null);
- Debug.Assert(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
+ public IEnumerable<FileInfo> EnumerateFiles(string searchPattern, EnumerationOptions enumerationOptions)
+ => (IEnumerable<FileInfo>)InternalEnumerateInfos(FullPath, searchPattern, SearchTarget.Files, enumerationOptions);
- return (IEnumerable<FileInfo>)FileSystem.EnumerateFileSystemInfos(FullPath, searchPattern, searchOption, SearchTarget.Files);
- }
-
- public IEnumerable<FileSystemInfo> EnumerateFileSystemInfos()
- {
- return InternalEnumerateFileSystemInfos("*", SearchOption.TopDirectoryOnly);
- }
+ public IEnumerable<FileSystemInfo> EnumerateFileSystemInfos() => EnumerateFileSystemInfos("*", enumerationOptions: EnumerationOptions.Compatible);
public IEnumerable<FileSystemInfo> EnumerateFileSystemInfos(string searchPattern)
- {
- if (searchPattern == null)
- throw new ArgumentNullException(nameof(searchPattern));
-
- return InternalEnumerateFileSystemInfos(searchPattern, SearchOption.TopDirectoryOnly);
- }
+ => EnumerateFileSystemInfos(searchPattern, enumerationOptions: EnumerationOptions.Compatible);
public IEnumerable<FileSystemInfo> EnumerateFileSystemInfos(string searchPattern, SearchOption searchOption)
- {
- if (searchPattern == null)
- throw new ArgumentNullException(nameof(searchPattern));
- if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories))
- throw new ArgumentOutOfRangeException(nameof(searchOption), SR.ArgumentOutOfRange_Enum);
+ => EnumerateFileSystemInfos(searchPattern, EnumerationOptions.FromSearchOption(searchOption));
- return InternalEnumerateFileSystemInfos(searchPattern, searchOption);
- }
+ public IEnumerable<FileSystemInfo> EnumerateFileSystemInfos(string searchPattern, EnumerationOptions enumerationOptions)
+ => InternalEnumerateInfos(FullPath, searchPattern, SearchTarget.Both, enumerationOptions);
- private IEnumerable<FileSystemInfo> InternalEnumerateFileSystemInfos(string searchPattern, SearchOption searchOption)
+ internal static IEnumerable<FileSystemInfo> InternalEnumerateInfos(
+ string path,
+ string searchPattern,
+ SearchTarget searchTarget,
+ EnumerationOptions options)
{
- Debug.Assert(searchPattern != null);
- Debug.Assert(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
+ Debug.Assert(path != null);
+ if (searchPattern == null)
+ throw new ArgumentNullException(nameof(searchPattern));
- return FileSystem.EnumerateFileSystemInfos(FullPath, searchPattern, searchOption, SearchTarget.Both);
- }
+ FileSystemEnumerableFactory.NormalizeInputs(ref path, ref searchPattern, options);
- // Returns the root portion of the given path. The resulting string
- // consists of those rightmost characters of the path that constitute the
- // root of the path. Possible patterns for the resulting string are: An
- // empty string (a relative path on the current drive), "\" (an absolute
- // path on the current drive), "X:" (a relative path on a given drive,
- // where X is the drive letter), "X:\" (an absolute path on a given drive),
- // and "\\server\share" (a UNC path for a given server and share name).
- // The resulting string is null if path is null.
- //
-
- public DirectoryInfo Root
- {
- get
+ switch (searchTarget)
{
- string rootPath = Path.GetPathRoot(FullPath);
-
- return new DirectoryInfo(rootPath);
+ case SearchTarget.Directories:
+ return FileSystemEnumerableFactory.DirectoryInfos(path, searchPattern, options);
+ case SearchTarget.Files:
+ return FileSystemEnumerableFactory.FileInfos(path, searchPattern, options);
+ case SearchTarget.Both:
+ return FileSystemEnumerableFactory.FileSystemInfos(path, searchPattern, options);
+ default:
+ throw new ArgumentException(SR.ArgumentOutOfRange_Enum, nameof(searchTarget));
}
}
+ public DirectoryInfo Root => new DirectoryInfo(Path.GetPathRoot(FullPath));
+
public void MoveTo(string destDirName)
{
if (destDirName == null)
@@ -360,24 +187,17 @@ namespace System.IO
throw new ArgumentException(SR.Argument_EmptyFileName, nameof(destDirName));
string destination = Path.GetFullPath(destDirName);
- string destinationWithSeparator = destination;
- if (destinationWithSeparator[destinationWithSeparator.Length - 1] != Path.DirectorySeparatorChar)
- destinationWithSeparator = destinationWithSeparator + PathHelpers.DirectorySeparatorCharAsString;
-
- string fullSourcePath;
- if (FullPath.Length > 0 && FullPath[FullPath.Length - 1] == Path.DirectorySeparatorChar)
- fullSourcePath = FullPath;
- else
- fullSourcePath = FullPath + PathHelpers.DirectorySeparatorCharAsString;
-
- StringComparison pathComparison = PathInternal.StringComparison;
- if (string.Equals(fullSourcePath, destinationWithSeparator, pathComparison))
+
+ string destinationWithSeparator = PathInternal.EnsureTrailingSeparator(destination);
+ string sourceWithSeparator = PathInternal.EnsureTrailingSeparator(FullPath);
+
+ if (string.Equals(sourceWithSeparator, destinationWithSeparator, PathInternal.StringComparison))
throw new IOException(SR.IO_SourceDestMustBeDifferent);
- string sourceRoot = Path.GetPathRoot(fullSourcePath);
+ string sourceRoot = Path.GetPathRoot(sourceWithSeparator);
string destinationRoot = Path.GetPathRoot(destinationWithSeparator);
- if (!string.Equals(sourceRoot, destinationRoot, pathComparison))
+ if (!string.Equals(sourceRoot, destinationRoot, PathInternal.StringComparison))
throw new IOException(SR.IO_SourceDestMustHaveSameRoot);
// Windows will throw if the source file/directory doesn't exist, we preemptively check
@@ -385,7 +205,7 @@ namespace System.IO
if (!Exists && !FileSystem.FileExists(FullPath))
throw new DirectoryNotFoundException(SR.Format(SR.IO_PathNotFound_Path, FullPath));
- if (FileSystem.DirectoryExists(destinationWithSeparator))
+ if (FileSystem.DirectoryExists(destination))
throw new IOException(SR.Format(SR.IO_AlreadyExists_Name, destinationWithSeparator));
FileSystem.MoveDirectory(FullPath, destination);
@@ -399,22 +219,8 @@ namespace System.IO
Invalidate();
}
- public override void Delete()
- {
- FileSystem.RemoveDirectory(FullPath, false);
- }
-
- public void Delete(bool recursive)
- {
- FileSystem.RemoveDirectory(FullPath, recursive);
- }
+ public override void Delete() => FileSystem.RemoveDirectory(FullPath, recursive: false);
- /// <summary>
- /// Returns the original path. Use FullPath or Name properties for the path / directory name.
- /// </summary>
- public override string ToString()
- {
- return DisplayPath;
- }
+ public void Delete(bool recursive) => FileSystem.RemoveDirectory(FullPath, recursive);
}
}
diff --git a/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEntry.Unix.cs b/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEntry.Unix.cs
new file mode 100644
index 0000000000..e554bc8538
--- /dev/null
+++ b/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEntry.Unix.cs
@@ -0,0 +1,152 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+
+namespace System.IO.Enumeration
+{
+ /// <summary>
+ /// Lower level view of FileSystemInfo used for processing and filtering find results.
+ /// </summary>
+ public unsafe ref struct FileSystemEntry
+ {
+ private const int FileNameBufferSize = 256;
+ internal Interop.Sys.DirectoryEntry _directoryEntry;
+ private FileStatus _status;
+ private Span<char> _pathBuffer;
+ private ReadOnlySpan<char> _fullPath;
+ private ReadOnlySpan<char> _fileName;
+ private fixed char _fileNameBuffer[FileNameBufferSize];
+ private FileAttributes _initialAttributes;
+
+ internal static FileAttributes Initialize(
+ ref FileSystemEntry entry,
+ Interop.Sys.DirectoryEntry directoryEntry,
+ ReadOnlySpan<char> directory,
+ ReadOnlySpan<char> rootDirectory,
+ ReadOnlySpan<char> originalRootDirectory,
+ Span<char> pathBuffer)
+ {
+ entry._directoryEntry = directoryEntry;
+ entry.Directory = directory;
+ entry.RootDirectory = rootDirectory;
+ entry.OriginalRootDirectory = originalRootDirectory;
+ entry._pathBuffer = pathBuffer;
+ entry._fullPath = ReadOnlySpan<char>.Empty;
+ entry._fileName = ReadOnlySpan<char>.Empty;
+
+ // IMPORTANT: Attribute logic must match the logic in FileStatus
+
+ bool isDirectory = false;
+ if (directoryEntry.InodeType == Interop.Sys.NodeType.DT_DIR)
+ {
+ // We know it's a directory.
+ isDirectory = true;
+ }
+ else if ((directoryEntry.InodeType == Interop.Sys.NodeType.DT_LNK)
+ && Interop.Sys.Stat(entry.FullPath, out Interop.Sys.FileStatus targetStatus) >= 0)
+ {
+ // It's a symlink: stat to it to see if we can resolve it to a directory.
+ isDirectory = (targetStatus.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFDIR;
+ }
+
+ entry._status = default;
+ FileStatus.Initialize(ref entry._status, isDirectory);
+
+ FileAttributes attributes = default;
+ if (directoryEntry.InodeType == Interop.Sys.NodeType.DT_LNK)
+ attributes |= FileAttributes.ReparsePoint;
+ if (isDirectory)
+ attributes |= FileAttributes.Directory;
+ if (directoryEntry.Name[0] == '.')
+ attributes |= FileAttributes.Hidden;
+
+ if (attributes == default)
+ attributes = FileAttributes.Normal;
+
+ entry._initialAttributes = attributes;
+ return attributes;
+ }
+
+ private ReadOnlySpan<char> FullPath
+ {
+ get
+ {
+ if (_fullPath.Length == 0)
+ {
+ Debug.Assert(Directory.Length + FileName.Length < _pathBuffer.Length,
+ $"directory ({Directory.Length} chars) & name ({Directory.Length} chars) too long for buffer ({_pathBuffer.Length} chars)");
+ Path.TryJoin(Directory, FileName, _pathBuffer, out int charsWritten);
+ Debug.Assert(charsWritten > 0, "didn't write any chars to buffer");
+ _fullPath = _pathBuffer.Slice(0, charsWritten);
+ }
+ return _fullPath;
+ }
+ }
+
+ public ReadOnlySpan<char> FileName
+ {
+ get
+ {
+ if (_directoryEntry.NameLength != 0 && _fileName.Length == 0)
+ {
+ fixed (char* c = _fileNameBuffer)
+ {
+ Span<char> buffer = new Span<char>(c, FileNameBufferSize);
+ _fileName = _directoryEntry.GetName(buffer);
+ }
+ }
+
+ return _fileName;
+ }
+ }
+
+ /// <summary>
+ /// The full path of the directory this entry resides in.
+ /// </summary>
+ public ReadOnlySpan<char> Directory { get; private set; }
+
+ /// <summary>
+ /// The full path of the root directory used for the enumeration.
+ /// </summary>
+ public ReadOnlySpan<char> RootDirectory { get; private set; }
+
+ /// <summary>
+ /// The root directory for the enumeration as specified in the constructor.
+ /// </summary>
+ public ReadOnlySpan<char> OriginalRootDirectory { get; private set; }
+
+ // Windows never fails getting attributes, length, or time as that information comes back
+ // with the native enumeration struct. As such we must not throw here.
+
+ public FileAttributes Attributes
+ // It would be hard to rationalize if the attributes change after our initial find.
+ => _initialAttributes | (_status.IsReadOnly(FullPath, continueOnError: true) ? FileAttributes.ReadOnly : 0);
+
+ public long Length => _status.GetLength(FullPath, continueOnError: true);
+ public DateTimeOffset CreationTimeUtc => _status.GetCreationTime(FullPath, continueOnError: true);
+ public DateTimeOffset LastAccessTimeUtc => _status.GetLastAccessTime(FullPath, continueOnError: true);
+ public DateTimeOffset LastWriteTimeUtc => _status.GetLastWriteTime(FullPath, continueOnError: true);
+ public bool IsDirectory => _status.InitiallyDirectory;
+ public bool IsHidden => _directoryEntry.Name[0] == '.';
+
+ public FileSystemInfo ToFileSystemInfo()
+ {
+ string fullPath = ToFullPath();
+ return FileSystemInfo.Create(fullPath, new string(FileName), ref _status);
+ }
+
+ /// <summary>
+ /// Returns the full path for find results, based on the initially provided path.
+ /// </summary>
+ public string ToSpecifiedFullPath() =>
+ Path.Join(OriginalRootDirectory, Directory.Slice(RootDirectory.Length), FileName);
+
+ /// <summary>
+ /// Returns the full path of the find result.
+ /// </summary>
+ public string ToFullPath() =>
+ new string(FullPath);
+ }
+}
diff --git a/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEntry.Windows.cs b/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEntry.Windows.cs
new file mode 100644
index 0000000000..0ce20d52ab
--- /dev/null
+++ b/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEntry.Windows.cs
@@ -0,0 +1,90 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.IO.Enumeration
+{
+ /// <summary>
+ /// Lower level view of FileSystemInfo used for processing and filtering find results.
+ /// </summary>
+ public unsafe ref struct FileSystemEntry
+ {
+ internal static void Initialize(
+ ref FileSystemEntry entry,
+ Interop.NtDll.FILE_FULL_DIR_INFORMATION* info,
+ ReadOnlySpan<char> directory,
+ ReadOnlySpan<char> rootDirectory,
+ ReadOnlySpan<char> originalRootDirectory)
+ {
+ entry._info = info;
+ entry.Directory = directory;
+ entry.RootDirectory = rootDirectory;
+ entry.OriginalRootDirectory = originalRootDirectory;
+ }
+
+ internal unsafe Interop.NtDll.FILE_FULL_DIR_INFORMATION* _info;
+
+ /// <summary>
+ /// The full path of the directory this entry resides in.
+ /// </summary>
+ public ReadOnlySpan<char> Directory { get; private set; }
+
+ /// <summary>
+ /// The full path of the root directory used for the enumeration.
+ /// </summary>
+ public ReadOnlySpan<char> RootDirectory { get; private set; }
+
+ /// <summary>
+ /// The root directory for the enumeration as specified in the constructor.
+ /// </summary>
+ public ReadOnlySpan<char> OriginalRootDirectory { get; private set; }
+
+ /// <summary>
+ /// The file name for this entry.
+ /// </summary>
+ public ReadOnlySpan<char> FileName => _info->FileName;
+
+ /// <summary>
+ /// The attributes for this entry.
+ /// </summary>
+ public FileAttributes Attributes => _info->FileAttributes;
+
+ /// <summary>
+ /// The length of file in bytes.
+ /// </summary>
+ public long Length => _info->EndOfFile;
+
+ /// <summary>
+ /// The creation time for the entry or the oldest available time stamp if the
+ /// operating system does not support creation time stamps.
+ /// </summary>
+ public DateTimeOffset CreationTimeUtc => _info->CreationTime.ToDateTimeOffset();
+ public DateTimeOffset LastAccessTimeUtc => _info->LastAccessTime.ToDateTimeOffset();
+ public DateTimeOffset LastWriteTimeUtc => _info->LastWriteTime.ToDateTimeOffset();
+
+ /// <summary>
+ /// Returns true if this entry is a directory.
+ /// </summary>
+ public bool IsDirectory => (Attributes & FileAttributes.Directory) != 0;
+
+ /// <summary>
+ /// Returns true if the file has the hidden attribute.
+ /// </summary>
+ public bool IsHidden => (Attributes & FileAttributes.Hidden) != 0;
+
+ public FileSystemInfo ToFileSystemInfo()
+ => FileSystemInfo.Create(Path.Join(Directory, FileName), ref this);
+
+ /// <summary>
+ /// Returns the full path for find results, based on the initially provided path.
+ /// </summary>
+ public string ToSpecifiedFullPath() =>
+ Path.Join(OriginalRootDirectory, Directory.Slice(RootDirectory.Length), FileName);
+
+ /// <summary>
+ /// Returns the full path of the find result.
+ /// </summary>
+ public string ToFullPath() =>
+ Path.Join(Directory, FileName);
+ }
+}
diff --git a/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerable.cs b/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerable.cs
new file mode 100644
index 0000000000..861a8fa616
--- /dev/null
+++ b/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerable.cs
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace System.IO.Enumeration
+{
+ /// <summary>
+ /// Enumerable that allows utilizing custom filter predicates and tranform delegates.
+ /// </summary>
+ public class FileSystemEnumerable<TResult> : IEnumerable<TResult>
+ {
+ private DelegateEnumerator _enumerator;
+ private readonly FindTransform _transform;
+ private readonly EnumerationOptions _options;
+ private readonly string _directory;
+
+ public FileSystemEnumerable(string directory, FindTransform transform, EnumerationOptions options = null)
+ {
+ _directory = directory ?? throw new ArgumentNullException(nameof(directory));
+ _transform = transform ?? throw new ArgumentNullException(nameof(transform));
+ _options = options ?? EnumerationOptions.Default;
+
+ // We need to create the enumerator up front to ensure that we throw I/O exceptions for
+ // the root directory on creation of the enumerable.
+ _enumerator = new DelegateEnumerator(this);
+ }
+
+ public FindPredicate ShouldIncludePredicate { get; set; }
+ public FindPredicate ShouldRecursePredicate { get; set; }
+
+ public IEnumerator<TResult> GetEnumerator()
+ {
+ return Interlocked.Exchange(ref _enumerator, null) ?? new DelegateEnumerator(this);
+ }
+
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+
+ /// <summary>
+ /// Delegate for filtering out find results.
+ /// </summary>
+ public delegate bool FindPredicate(ref FileSystemEntry entry);
+
+ /// <summary>
+ /// Delegate for transforming raw find data into a result.
+ /// </summary>
+ public delegate TResult FindTransform(ref FileSystemEntry entry);
+
+ private sealed class DelegateEnumerator : FileSystemEnumerator<TResult>
+ {
+ private readonly FileSystemEnumerable<TResult> _enumerable;
+
+ public DelegateEnumerator(FileSystemEnumerable<TResult> enumerable)
+ : base(enumerable._directory, enumerable._options)
+ {
+ _enumerable = enumerable;
+ }
+
+ protected override TResult TransformEntry(ref FileSystemEntry entry) => _enumerable._transform(ref entry);
+ protected override bool ShouldRecurseIntoEntry(ref FileSystemEntry entry)
+ => _enumerable.ShouldRecursePredicate?.Invoke(ref entry) ?? true;
+ protected override bool ShouldIncludeEntry(ref FileSystemEntry entry)
+ => _enumerable.ShouldIncludePredicate?.Invoke(ref entry) ?? true;
+ }
+ }
+}
diff --git a/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerableFactory.cs b/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerableFactory.cs
new file mode 100644
index 0000000000..68eb97cea2
--- /dev/null
+++ b/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerableFactory.cs
@@ -0,0 +1,173 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file ref the project root for more information.
+
+using System.Collections.Generic;
+
+namespace System.IO.Enumeration
+{
+ internal static class FileSystemEnumerableFactory
+ {
+ // These all have special meaning in DOS name matching. '\' is the escaping character (which conveniently
+ // is the directory separator and cannot be part of any path segment in Windows). The other three are the
+ // special case wildcards that we'll convert some * and ? into. They're also valid as filenames on Unix,
+ // which is not true in Windows and as such we'll escape any that occur on the input string.
+ private readonly static char[] s_unixEscapeChars = { '\\', '"', '<', '>' };
+
+ internal static void NormalizeInputs(ref string directory, ref string expression, EnumerationOptions options)
+ {
+ if (Path.IsPathRooted(expression))
+ throw new ArgumentException(SR.Arg_Path2IsRooted, nameof(expression));
+
+ // We always allowed breaking the passed ref directory and filter to be separated
+ // any way the user wanted. Looking for "C:\foo\*.cs" could be passed as "C:\" and
+ // "foo\*.cs" or "C:\foo" and "*.cs", for example. As such we need to combine and
+ // split the inputs if the expression contains a directory separator.
+ //
+ // We also allowed for expression to be "foo\" which would translate to "foo\*".
+
+ ReadOnlySpan<char> directoryName = Path.GetDirectoryName(expression.AsSpan());
+
+ if (directoryName.Length != 0)
+ {
+ // Need to fix up the input paths
+ directory = Path.Join(directory, directoryName);
+ expression = expression.Substring(directoryName.Length + 1);
+ }
+
+ switch (options.MatchType)
+ {
+ case MatchType.Win32:
+ if (string.IsNullOrEmpty(expression) || expression == "." || expression == "*.*")
+ {
+ // Historically we always treated "." as "*"
+ expression = "*";
+ }
+ else
+ {
+ if (Path.DirectorySeparatorChar != '\\' && expression.IndexOfAny(s_unixEscapeChars) != -1)
+ {
+ // Backslash isn't the default separator, need to escape (e.g. Unix)
+ expression = expression.Replace("\\", "\\\\");
+
+ // Also need to escape the other special wild characters ('"', '<', and '>')
+ expression = expression.Replace("\"", "\\\"");
+ expression = expression.Replace(">", "\\>");
+ expression = expression.Replace("<", "\\<");
+ }
+
+ // Need to convert the expression to match Win32 behavior
+ expression = FileSystemName.TranslateWin32Expression(expression);
+ }
+ break;
+ case MatchType.Simple:
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(options));
+ }
+ }
+
+ private static bool MatchesPattern(string expression, ReadOnlySpan<char> name, EnumerationOptions options)
+ {
+ bool ignoreCase = (options.MatchCasing == MatchCasing.PlatformDefault && !PathInternal.IsCaseSensitive)
+ || options.MatchCasing == MatchCasing.CaseInsensitive;
+
+ switch (options.MatchType)
+ {
+ case MatchType.Simple:
+ return FileSystemName.MatchesSimpleExpression(expression, name, ignoreCase);
+ case MatchType.Win32:
+ return FileSystemName.MatchesWin32Expression(expression, name, ignoreCase);
+ default:
+ throw new ArgumentOutOfRangeException(nameof(options));
+ }
+ }
+
+ internal static IEnumerable<string> UserFiles(string directory,
+ string expression,
+ EnumerationOptions options)
+ {
+ return new FileSystemEnumerable<string>(
+ directory,
+ (ref FileSystemEntry entry) => entry.ToSpecifiedFullPath(),
+ options)
+ {
+ ShouldIncludePredicate = (ref FileSystemEntry entry) =>
+ !entry.IsDirectory && MatchesPattern(expression, entry.FileName, options)
+ };
+ }
+
+ internal static IEnumerable<string> UserDirectories(string directory,
+ string expression,
+ EnumerationOptions options)
+ {
+ return new FileSystemEnumerable<string>(
+ directory,
+ (ref FileSystemEntry entry) => entry.ToSpecifiedFullPath(),
+ options)
+ {
+ ShouldIncludePredicate = (ref FileSystemEntry entry) =>
+ entry.IsDirectory && MatchesPattern(expression, entry.FileName, options)
+ };
+ }
+
+ internal static IEnumerable<string> UserEntries(string directory,
+ string expression,
+ EnumerationOptions options)
+ {
+ return new FileSystemEnumerable<string>(
+ directory,
+ (ref FileSystemEntry entry) => entry.ToSpecifiedFullPath(),
+ options)
+ {
+ ShouldIncludePredicate = (ref FileSystemEntry entry) =>
+ MatchesPattern(expression, entry.FileName, options)
+ };
+ }
+
+ internal static IEnumerable<FileInfo> FileInfos(
+ string directory,
+ string expression,
+ EnumerationOptions options)
+ {
+ return new FileSystemEnumerable<FileInfo>(
+ directory,
+ (ref FileSystemEntry entry) => (FileInfo)entry.ToFileSystemInfo(),
+ options)
+ {
+ ShouldIncludePredicate = (ref FileSystemEntry entry) =>
+ !entry.IsDirectory && MatchesPattern(expression, entry.FileName, options)
+ };
+ }
+
+ internal static IEnumerable<DirectoryInfo> DirectoryInfos(
+ string directory,
+ string expression,
+ EnumerationOptions options)
+ {
+ return new FileSystemEnumerable<DirectoryInfo>(
+ directory,
+ (ref FileSystemEntry entry) => (DirectoryInfo)entry.ToFileSystemInfo(),
+ options)
+ {
+ ShouldIncludePredicate = (ref FileSystemEntry entry) =>
+ entry.IsDirectory && MatchesPattern(expression, entry.FileName, options)
+ };
+ }
+
+ internal static IEnumerable<FileSystemInfo> FileSystemInfos(
+ string directory,
+ string expression,
+ EnumerationOptions options)
+ {
+ return new FileSystemEnumerable<FileSystemInfo>(
+ directory,
+ (ref FileSystemEntry entry) => entry.ToFileSystemInfo(),
+ options)
+ {
+ ShouldIncludePredicate = (ref FileSystemEntry entry) =>
+ MatchesPattern(expression, entry.FileName, options)
+ };
+ }
+ }
+}
diff --git a/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.Unix.cs b/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.Unix.cs
new file mode 100644
index 0000000000..a1dde7fb2b
--- /dev/null
+++ b/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.Unix.cs
@@ -0,0 +1,224 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Collections.Generic;
+using System.Runtime.ConstrainedExecution;
+using System.Threading;
+
+namespace System.IO.Enumeration
+{
+ public unsafe abstract partial class FileSystemEnumerator<TResult> : CriticalFinalizerObject, IEnumerator<TResult>
+ {
+ // The largest supported path on Unix is 4K bytes of UTF-8 (most only support 1K)
+ private const int StandardBufferSize = 4096;
+
+ private readonly string _originalRootDirectory;
+ private readonly string _rootDirectory;
+ private readonly EnumerationOptions _options;
+
+ private readonly object _lock = new object();
+
+ private string _currentPath;
+ private IntPtr _directoryHandle;
+ private bool _lastEntryFound;
+ private Queue<string> _pending;
+
+ private Interop.Sys.DirectoryEntry _entry;
+ private TResult _current;
+
+ // Used for creating full paths
+ private char[] _pathBuffer;
+ // Used to get the raw entry data
+ private byte[] _entryBuffer;
+
+ /// <summary>
+ /// Encapsulates a find operation.
+ /// </summary>
+ /// <param name="directory">The directory to search in.</param>
+ /// <param name="options">Enumeration options to use.</param>
+ public FileSystemEnumerator(string directory, EnumerationOptions options = null)
+ {
+ _originalRootDirectory = directory ?? throw new ArgumentNullException(nameof(directory));
+ _rootDirectory = PathInternal.TrimEndingDirectorySeparator(Path.GetFullPath(directory));
+ _options = options ?? EnumerationOptions.Default;
+
+ // We need to initialize the directory handle up front to ensure
+ // we immediately throw IO exceptions for missing directory/etc.
+ _directoryHandle = CreateDirectoryHandle(_rootDirectory);
+ if (_directoryHandle == IntPtr.Zero)
+ _lastEntryFound = true;
+
+ _currentPath = _rootDirectory;
+
+ try
+ {
+ _pathBuffer = ArrayPool<char>.Shared.Rent(StandardBufferSize);
+ int size = Interop.Sys.ReadBufferSize;
+ _entryBuffer = size > 0 ? ArrayPool<byte>.Shared.Rent(size) : null;
+ }
+ catch
+ {
+ // Close the directory handle right away if we fail to allocate
+ CloseDirectoryHandle();
+ throw;
+ }
+ }
+
+ private bool InternalContinueOnError(int error)
+ => (_options.IgnoreInaccessible && IsAccessError(error)) || ContinueOnError(error);
+
+ private static bool IsAccessError(int error)
+ => error == (int)Interop.Error.EACCES || error == (int)Interop.Error.EBADF
+ || error == (int)Interop.Error.EPERM;
+
+ private IntPtr CreateDirectoryHandle(string path)
+ {
+ IntPtr handle = Interop.Sys.OpenDir(path);
+ if (handle == IntPtr.Zero)
+ {
+ Interop.ErrorInfo info = Interop.Sys.GetLastErrorInfo();
+ if (InternalContinueOnError(info.RawErrno))
+ {
+ return IntPtr.Zero;
+ }
+ throw Interop.GetExceptionForIoErrno(info, path, isDirectory: true);
+ }
+ return handle;
+ }
+
+ private void CloseDirectoryHandle()
+ {
+ IntPtr handle = Interlocked.Exchange(ref _directoryHandle, IntPtr.Zero);
+ if (handle != IntPtr.Zero)
+ Interop.Sys.CloseDir(handle);
+ }
+
+ public bool MoveNext()
+ {
+ if (_lastEntryFound)
+ return false;
+
+ FileSystemEntry entry = default;
+
+ lock (_lock)
+ {
+ if (_lastEntryFound)
+ return false;
+
+ do
+ {
+ FindNextEntry();
+ if (_lastEntryFound)
+ return false;
+
+ FileAttributes attributes = FileSystemEntry.Initialize(
+ ref entry, _entry, _currentPath, _rootDirectory, _originalRootDirectory, new Span<char>(_pathBuffer));
+ bool isDirectory = (attributes & FileAttributes.Directory) != 0;
+
+ bool isSpecialDirectory = false;
+ if (isDirectory)
+ {
+ // Subdirectory found
+ if (_entry.Name[0] == '.' && (_entry.Name[1] == 0 || (_entry.Name[1] == '.' && _entry.Name[2] == 0)))
+ {
+ // "." or "..", don't process unless the option is set
+ if (!_options.ReturnSpecialDirectories)
+ continue;
+ isSpecialDirectory = true;
+ }
+ }
+
+ if (!isSpecialDirectory && _options.AttributesToSkip != 0)
+ {
+ if ((_options.AttributesToSkip & FileAttributes.ReadOnly) != 0)
+ {
+ // ReadOnly is the only attribute that requires hitting entry.Attributes (which hits the disk)
+ attributes = entry.Attributes;
+ }
+
+ if ((_options.AttributesToSkip & attributes) != 0)
+ {
+ continue;
+ }
+ }
+
+ if (isDirectory && !isSpecialDirectory)
+ {
+ if (_options.RecurseSubdirectories && ShouldRecurseIntoEntry(ref entry))
+ {
+ // Recursion is on and the directory was accepted, Queue it
+ if (_pending == null)
+ _pending = new Queue<string>();
+ _pending.Enqueue(Path.Join(_currentPath, entry.FileName));
+ }
+ }
+
+ if (ShouldIncludeEntry(ref entry))
+ {
+ _current = TransformEntry(ref entry);
+ return true;
+ }
+ } while (true);
+ }
+ }
+
+ private unsafe void FindNextEntry()
+ {
+ Span<byte> buffer = _entryBuffer == null ? Span<byte>.Empty : new Span<byte>(_entryBuffer);
+ int result = Interop.Sys.ReadDir(_directoryHandle, buffer, ref _entry);
+ switch (result)
+ {
+ case -1:
+ // End of directory
+ DirectoryFinished();
+ break;
+ case 0:
+ // Success
+ break;
+ default:
+ // Error
+ if (InternalContinueOnError(result))
+ {
+ DirectoryFinished();
+ break;
+ }
+ else
+ {
+ throw Interop.GetExceptionForIoErrno(new Interop.ErrorInfo(result), _currentPath, isDirectory: true);
+ }
+ }
+ }
+
+ private void DequeueNextDirectory()
+ {
+ _currentPath = _pending.Dequeue();
+ _directoryHandle = CreateDirectoryHandle(_currentPath);
+ }
+
+ private void InternalDispose(bool disposing)
+ {
+ // It is possible to fail to allocate the lock, but the finalizer will still run
+ if (_lock != null)
+ {
+ lock(_lock)
+ {
+ _lastEntryFound = true;
+ _pending = null;
+
+ CloseDirectoryHandle();
+
+ if (_pathBuffer != null)
+ ArrayPool<char>.Shared.Return(_pathBuffer);
+ _pathBuffer = null;
+ if (_entryBuffer != null)
+ ArrayPool<byte>.Shared.Return(_entryBuffer);
+ _entryBuffer = null;
+ }
+ }
+
+ Dispose(disposing);
+ }
+ }
+}
diff --git a/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.Win32.cs b/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.Win32.cs
new file mode 100644
index 0000000000..3376e3f5e4
--- /dev/null
+++ b/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.Win32.cs
@@ -0,0 +1,78 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+
+namespace System.IO.Enumeration
+{
+ public partial class FileSystemEnumerator<TResult>
+ {
+ /// <returns>'true' if new data was found</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private unsafe bool GetData()
+ {
+ Debug.Assert(_directoryHandle != (IntPtr)(-1) && _directoryHandle != IntPtr.Zero && !_lastEntryFound);
+
+ int status = Interop.NtDll.NtQueryDirectoryFile(
+ FileHandle: _directoryHandle,
+ Event: IntPtr.Zero,
+ ApcRoutine: IntPtr.Zero,
+ ApcContext: IntPtr.Zero,
+ IoStatusBlock: out Interop.NtDll.IO_STATUS_BLOCK statusBlock,
+ FileInformation: _buffer,
+ Length: (uint)_buffer.Length,
+ FileInformationClass: Interop.NtDll.FILE_INFORMATION_CLASS.FileFullDirectoryInformation,
+ ReturnSingleEntry: Interop.BOOLEAN.FALSE,
+ FileName: null,
+ RestartScan: Interop.BOOLEAN.FALSE);
+
+ switch ((uint)status)
+ {
+ case Interop.StatusOptions.STATUS_NO_MORE_FILES:
+ DirectoryFinished();
+ return false;
+ case Interop.StatusOptions.STATUS_SUCCESS:
+ Debug.Assert(statusBlock.Information.ToInt64() != 0);
+ return true;
+ default:
+ int error = (int)Interop.NtDll.RtlNtStatusToDosError(status);
+
+ // Note that there are many NT status codes that convert to ERROR_ACCESS_DENIED.
+ if ((error == Interop.Errors.ERROR_ACCESS_DENIED && _options.IgnoreInaccessible) || ContinueOnError(error))
+ {
+ DirectoryFinished();
+ return false;
+ }
+ throw Win32Marshal.GetExceptionForWin32Error(error, _currentPath);
+ }
+ }
+
+ private IntPtr CreateRelativeDirectoryHandle(ReadOnlySpan<char> relativePath, string fullPath)
+ {
+ (int status, IntPtr handle) = Interop.NtDll.CreateFile(
+ relativePath,
+ _directoryHandle,
+ Interop.NtDll.CreateDisposition.FILE_OPEN,
+ Interop.NtDll.DesiredAccess.FILE_LIST_DIRECTORY | Interop.NtDll.DesiredAccess.SYNCHRONIZE,
+ createOptions: Interop.NtDll.CreateOptions.FILE_SYNCHRONOUS_IO_NONALERT | Interop.NtDll.CreateOptions.FILE_DIRECTORY_FILE
+ | Interop.NtDll.CreateOptions.FILE_OPEN_FOR_BACKUP_INTENT);
+
+ switch ((uint)status)
+ {
+ case Interop.StatusOptions.STATUS_SUCCESS:
+ return handle;
+ default:
+ int error = (int)Interop.NtDll.RtlNtStatusToDosError(status);
+
+ // Note that there are many NT status codes that convert to ERROR_ACCESS_DENIED.
+ if ((error == Interop.Errors.ERROR_ACCESS_DENIED && _options.IgnoreInaccessible) || ContinueOnError(error))
+ {
+ return IntPtr.Zero;
+ }
+ throw Win32Marshal.GetExceptionForWin32Error(error, fullPath);
+ }
+ }
+ }
+}
diff --git a/src/System.IO.FileSystem/src/System/IO/FindEnumerable.WinRT.cs b/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.WinRT.cs
index 61e8b05d4d..b2ad37fac4 100644
--- a/src/System.IO.FileSystem/src/System/IO/FindEnumerable.WinRT.cs
+++ b/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.WinRT.cs
@@ -5,12 +5,12 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-namespace System.IO
+namespace System.IO.Enumeration
{
- internal partial class FindEnumerable<TResult, TState>
+ public partial class FileSystemEnumerator<TResult>
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public unsafe bool GetData()
+ private unsafe bool GetData()
{
if (!Interop.Kernel32.GetFileInformationByHandleEx(
_directoryHandle,
@@ -24,12 +24,26 @@ namespace System.IO
case Interop.Errors.ERROR_NO_MORE_FILES:
DirectoryFinished();
return false;
- default:
- throw Win32Marshal.GetExceptionForWin32Error(error, _currentPath);
+ case Interop.Errors.ERROR_ACCESS_DENIED:
+ if (_options.IgnoreInaccessible)
+ {
+ return false;
+ }
+ break;
}
+
+ if (!ContinueOnError(error))
+ throw Win32Marshal.GetExceptionForWin32Error(error, _currentPath);
}
return true;
}
+
+ private IntPtr CreateRelativeDirectoryHandle(ReadOnlySpan<char> relativePath, string fullPath)
+ {
+ // We don't have access to any APIs that allow us to pass in a base handle in UAP,
+ // just call our "normal" handle open.
+ return CreateDirectoryHandle(fullPath);
+ }
}
}
diff --git a/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.Windows.cs b/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.Windows.cs
new file mode 100644
index 0000000000..a04e230644
--- /dev/null
+++ b/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.Windows.cs
@@ -0,0 +1,234 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Collections.Generic;
+using System.Runtime.ConstrainedExecution;
+using System.Runtime.InteropServices;
+using System.Threading;
+
+namespace System.IO.Enumeration
+{
+ public unsafe abstract partial class FileSystemEnumerator<TResult> : CriticalFinalizerObject, IEnumerator<TResult>
+ {
+ private const int StandardBufferSize = 4096;
+
+ // We need to have enough room for at least a single entry. The filename alone can be 512 bytes, we'll ensure we have
+ // a reasonable buffer for all of the other metadata as well.
+ private const int MinimumBufferSize = 1024;
+
+ private readonly string _originalRootDirectory;
+ private readonly string _rootDirectory;
+ private readonly EnumerationOptions _options;
+
+ private readonly object _lock = new object();
+
+ private Interop.NtDll.FILE_FULL_DIR_INFORMATION* _entry;
+ private TResult _current;
+
+ private byte[] _buffer;
+ private IntPtr _directoryHandle;
+ private string _currentPath;
+ private bool _lastEntryFound;
+ private Queue<(IntPtr Handle, string Path)> _pending;
+ private GCHandle _pinnedBuffer;
+
+ /// <summary>
+ /// Encapsulates a find operation.
+ /// </summary>
+ /// <param name="directory">The directory to search in.</param>
+ /// <param name="options">Enumeration options to use.</param>
+ public FileSystemEnumerator(string directory, EnumerationOptions options = null)
+ {
+ _originalRootDirectory = directory ?? throw new ArgumentNullException(nameof(directory));
+ _rootDirectory = PathInternal.TrimEndingDirectorySeparator(Path.GetFullPath(directory));
+ _options = options ?? EnumerationOptions.Default;
+
+ // We'll only suppress the media insertion prompt on the topmost directory as that is the
+ // most likely scenario and we don't want to take the perf hit for large enumerations.
+ // (We weren't consistent with how we handled this historically.)
+ using (new DisableMediaInsertionPrompt())
+ {
+ // We need to initialize the directory handle up front to ensure
+ // we immediately throw IO exceptions for missing directory/etc.
+ _directoryHandle = CreateDirectoryHandle(_rootDirectory);
+ if (_directoryHandle == IntPtr.Zero)
+ _lastEntryFound = true;
+ }
+
+ _currentPath = _rootDirectory;
+
+ int requestedBufferSize = _options.BufferSize;
+ int bufferSize = requestedBufferSize <= 0 ? StandardBufferSize
+ : Math.Max(MinimumBufferSize, requestedBufferSize);
+
+ try
+ {
+ _buffer = ArrayPool<byte>.Shared.Rent(bufferSize);
+ _pinnedBuffer = GCHandle.Alloc(_buffer, GCHandleType.Pinned);
+ }
+ catch
+ {
+ // Close the directory handle right away if we fail to allocate
+ CloseDirectoryHandle();
+ throw;
+ }
+ }
+
+ private void CloseDirectoryHandle()
+ {
+ // As handles can be reused we want to be extra careful to close handles only once
+ IntPtr handle = Interlocked.Exchange(ref _directoryHandle, IntPtr.Zero);
+ if (handle != IntPtr.Zero)
+ Interop.Kernel32.CloseHandle(handle);
+ }
+
+ /// <summary>
+ /// Simple wrapper to allow creating a file handle for an existing directory.
+ /// </summary>
+ private IntPtr CreateDirectoryHandle(string path)
+ {
+ IntPtr handle = Interop.Kernel32.CreateFile_IntPtr(
+ path,
+ Interop.Kernel32.FileOperations.FILE_LIST_DIRECTORY,
+ FileShare.ReadWrite | FileShare.Delete,
+ FileMode.Open,
+ Interop.Kernel32.FileOperations.FILE_FLAG_BACKUP_SEMANTICS);
+
+ if (handle == IntPtr.Zero || handle == (IntPtr)(-1))
+ {
+ int error = Marshal.GetLastWin32Error();
+
+ if ((error == Interop.Errors.ERROR_ACCESS_DENIED &&
+ _options.IgnoreInaccessible) || ContinueOnError(error))
+ {
+ return IntPtr.Zero;
+ }
+
+ if (error == Interop.Errors.ERROR_FILE_NOT_FOUND)
+ {
+ // Historically we throw directory not found rather than file not found
+ error = Interop.Errors.ERROR_PATH_NOT_FOUND;
+ }
+
+ throw Win32Marshal.GetExceptionForWin32Error(error, path);
+ }
+
+ return handle;
+ }
+
+ public bool MoveNext()
+ {
+ if (_lastEntryFound)
+ return false;
+
+ FileSystemEntry entry = default;
+
+ lock (_lock)
+ {
+ if (_lastEntryFound)
+ return false;
+
+ do
+ {
+ FindNextEntry();
+ if (_lastEntryFound)
+ return false;
+
+ // Calling the constructor inside the try block would create a second instance on the stack.
+ FileSystemEntry.Initialize(ref entry, _entry, _currentPath, _rootDirectory, _originalRootDirectory);
+
+ // Skip specified attributes
+ if ((_entry->FileAttributes & _options.AttributesToSkip) != 0)
+ continue;
+
+ if ((_entry->FileAttributes & FileAttributes.Directory) != 0)
+ {
+ // Subdirectory found
+ if (!(_entry->FileName.Length > 2 || _entry->FileName[0] != '.' || (_entry->FileName.Length == 2 && _entry->FileName[1] != '.')))
+ {
+ // "." or "..", don't process unless the option is set
+ if (!_options.ReturnSpecialDirectories)
+ continue;
+ }
+ else if (_options.RecurseSubdirectories && ShouldRecurseIntoEntry(ref entry))
+ {
+ // Recursion is on and the directory was accepted, Queue it
+ string subDirectory = Path.Join(_currentPath, _entry->FileName);
+ IntPtr subDirectoryHandle = CreateRelativeDirectoryHandle(_entry->FileName, subDirectory);
+ if (subDirectoryHandle != IntPtr.Zero)
+ {
+ try
+ {
+ if (_pending == null)
+ _pending = new Queue<(IntPtr, string)>();
+ _pending.Enqueue((subDirectoryHandle, subDirectory));
+ }
+ catch
+ {
+ // Couldn't queue the handle, close it and rethrow
+ Interop.Kernel32.CloseHandle(subDirectoryHandle);
+ throw;
+ }
+ }
+ }
+ }
+
+ if (ShouldIncludeEntry(ref entry))
+ {
+ _current = TransformEntry(ref entry);
+ return true;
+ }
+ } while (true);
+ }
+ }
+
+ private unsafe void FindNextEntry()
+ {
+ _entry = Interop.NtDll.FILE_FULL_DIR_INFORMATION.GetNextInfo(_entry);
+ if (_entry != null)
+ return;
+
+ // We need more data
+ if (GetData())
+ _entry = (Interop.NtDll.FILE_FULL_DIR_INFORMATION*)_pinnedBuffer.AddrOfPinnedObject();
+ }
+
+ private void DequeueNextDirectory()
+ {
+ (_directoryHandle, _currentPath) = _pending.Dequeue();
+ }
+
+ private void InternalDispose(bool disposing)
+ {
+ // It is possible to fail to allocate the lock, but the finalizer will still run
+ if (_lock != null)
+ {
+ lock (_lock)
+ {
+ _lastEntryFound = true;
+
+ CloseDirectoryHandle();
+
+ if (_pending != null)
+ {
+ while (_pending.Count > 0)
+ Interop.Kernel32.CloseHandle(_pending.Dequeue().Handle);
+ _pending = null;
+ }
+
+ if (_pinnedBuffer.IsAllocated)
+ _pinnedBuffer.Free();
+
+ if (_buffer != null)
+ ArrayPool<byte>.Shared.Return(_buffer);
+
+ _buffer = null;
+ }
+ }
+
+ Dispose(disposing);
+ }
+ }
+}
diff --git a/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.cs b/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.cs
new file mode 100644
index 0000000000..716c15d7c8
--- /dev/null
+++ b/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.cs
@@ -0,0 +1,89 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections;
+using System.Collections.Generic;
+using System.Runtime.ConstrainedExecution;
+
+namespace System.IO.Enumeration
+{
+ public unsafe abstract partial class FileSystemEnumerator<TResult> : CriticalFinalizerObject, IEnumerator<TResult>
+ {
+ /// <summary>
+ /// Return true if the given file system entry should be included in the results.
+ /// </summary>
+ protected virtual bool ShouldIncludeEntry(ref FileSystemEntry entry) => true;
+
+ /// <summary>
+ /// Return true if the directory entry given should be recursed into.
+ /// </summary>
+ protected virtual bool ShouldRecurseIntoEntry(ref FileSystemEntry entry) => true;
+
+ /// <summary>
+ /// Generate the result type from the current entry;
+ /// </summary>
+ protected abstract TResult TransformEntry(ref FileSystemEntry entry);
+
+ /// <summary>
+ /// Called whenever the end of a directory is reached.
+ /// </summary>
+ /// <param name="directory">The path of the directory that finished.</param>
+ protected virtual void OnDirectoryFinished(ReadOnlySpan<char> directory) { }
+
+ /// <summary>
+ /// Called when a native API returns an error. Return true to continue, or false
+ /// to throw the default exception for the given error.
+ /// </summary>
+ /// <param name="error">The native error code.</param>
+ protected virtual bool ContinueOnError(int error) => false;
+
+ public TResult Current => _current;
+
+ object IEnumerator.Current => Current;
+
+ private void DirectoryFinished()
+ {
+ _entry = default;
+
+ // Close the handle now that we're done
+ CloseDirectoryHandle();
+ OnDirectoryFinished(_currentPath);
+
+ if (_pending == null || _pending.Count == 0)
+ {
+ _lastEntryFound = true;
+ }
+ else
+ {
+ // Grab the next directory to parse
+ DequeueNextDirectory();
+ FindNextEntry();
+ }
+ }
+
+ public void Reset()
+ {
+ throw new NotSupportedException();
+ }
+
+ public void Dispose()
+ {
+ InternalDispose(disposing: true);
+ GC.SuppressFinalize(this);
+ }
+
+ /// <summary>
+ /// Override for any additional cleanup.
+ /// </summary>
+ /// <param name="disposing">True if called while disposing. False if called from finalizer.</param>
+ protected virtual void Dispose(bool disposing)
+ {
+ }
+
+ ~FileSystemEnumerator()
+ {
+ InternalDispose(disposing: false);
+ }
+ }
+}
diff --git a/src/System.IO.FileSystem/src/System/IO/DosMatcher.cs b/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemName.cs
index b1f677efb6..8bdb6e54ce 100644
--- a/src/System.IO.FileSystem/src/System/IO/DosMatcher.cs
+++ b/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemName.cs
@@ -5,9 +5,12 @@
using System;
using System.Text;
-namespace System.IO
+namespace System.IO.Enumeration
{
- internal static class DosMatcher
+ /// <summary>
+ /// Provides methods for matching file system names.
+ /// </summary>
+ public static class FileSystemName
{
// [MS - FSA] 2.1.4.4 Algorithm for Determining if a FileName Is in an Expression
// https://msdn.microsoft.com/en-us/library/ff469270.aspx
@@ -16,17 +19,22 @@ namespace System.IO
'\"', '<', '>', '*', '?'
};
+ private static readonly char[] s_simpleWildcardChars =
+ {
+ '*', '?'
+ };
+
/// <summary>
/// Change '*' and '?' to '&lt;', '&gt;' and '"' to match Win32 behavior. For compatibility, Windows
/// changes some wildcards to provide a closer match to historical DOS 8.3 filename matching.
/// </summary>
- internal static string TranslateExpression(string expression)
+ public static string TranslateWin32Expression(string expression)
{
if (string.IsNullOrEmpty(expression) || expression == "*" || expression == "*.*")
return "*";
bool modified = false;
- Span<char> stackSpace = stackalloc char[expression.Length];
+ Span<char> stackSpace = stackalloc char[32];
ValueStringBuilder sb = new ValueStringBuilder(stackSpace);
int length = expression.Length;
for (int i = 0; i < length; i++)
@@ -36,10 +44,9 @@ namespace System.IO
{
case '.':
modified = true;
- if (i > 1 && i == length - 1 && expression[i - 1] == '*')
+ if (i >= 1 && i == length - 1 && expression[i - 1] == '*')
{
- sb.Length--;
- sb.Append('<'); // DOS_STAR (ends in *.)
+ sb[sb.Length - 1] = '<'; // DOS_STAR (ends in *.)
}
else if (i < length - 1 && (expression[i + 1] == '?' || expression[i + 1] == '*'))
{
@@ -64,7 +71,8 @@ namespace System.IO
}
/// <summary>
- /// Return true if the given expression matches the given name.
+ /// Return true if the given expression matches the given name. Supports the following wildcards:
+ /// '*', '?', '&lt;', '&gt;', '"'. The backslash character '\' escapes.
/// </summary>
/// <param name="expression">The expression to match with, such as "*.foo".</param>
/// <param name="name">The name to check against the expression.</param>
@@ -74,16 +82,85 @@ namespace System.IO
/// of RtlIsNameInExpression, which defines the rules for matching DOS wildcards ('*', '?', '&lt;', '&gt;', '"').
///
/// Like PatternMatcher, matching will not line up with Win32 behavior unless you transform the expression
- /// using <see cref="TranslateExpression(string)"/>
+ /// using <see cref="TranslateWin32Expression(string)"/>
/// </remarks>
- internal static bool MatchPattern(string expression, ReadOnlySpan<char> name, bool ignoreCase = true)
+ public static bool MatchesWin32Expression(ReadOnlySpan<char> expression, ReadOnlySpan<char> name, bool ignoreCase = true)
+ {
+ return MatchPattern(expression, name, ignoreCase, useExtendedWildcards: true);
+ }
+
+ /// <summary>
+ /// Return true if the given expression matches the given name. '*' and '?' are wildcards, '\' escapes.
+ /// </summary>
+ public static bool MatchesSimpleExpression(ReadOnlySpan<char> expression, ReadOnlySpan<char> name, bool ignoreCase = true)
+ {
+ return MatchPattern(expression, name, ignoreCase, useExtendedWildcards: false);
+ }
+
+ // Matching routine description
+ // ============================
+ // (copied from native impl)
+ //
+ // This routine compares a Dbcs name and an expression and tells the caller
+ // if the name is in the language defined by the expression. The input name
+ // cannot contain wildcards, while the expression may contain wildcards.
+ //
+ // Expression wild cards are evaluated as shown in the nondeterministic
+ // finite automatons below. Note that ~* and ~? are DOS_STAR and DOS_QM.
+ //
+ // ~* is DOS_STAR, ~? is DOS_QM, and ~. is DOS_DOT
+ //
+ // S
+ // <-----<
+ // X | | e Y
+ // X * Y == (0)----->-(1)->-----(2)-----(3)
+ //
+ // S-.
+ // <-----<
+ // X | | e Y
+ // X ~* Y == (0)----->-(1)->-----(2)-----(3)
+ //
+ // X S S Y
+ // X ?? Y == (0)---(1)---(2)---(3)---(4)
+ //
+ // X . . Y
+ // X ~.~. Y == (0)---(1)----(2)------(3)---(4)
+ // | |________|
+ // | ^ |
+ // |_______________|
+ // ^EOF or .^
+ //
+ // X S-. S-. Y
+ // X ~?~? Y == (0)---(1)-----(2)-----(3)---(4)
+ // | |________|
+ // | ^ |
+ // |_______________|
+ // ^EOF or .^
+ //
+ // where S is any single character
+ // S-. is any single character except the final .
+ // e is a null character transition
+ // EOF is the end of the name string
+ //
+ // In words:
+ //
+ // * matches 0 or more characters.
+ // ? matches exactly 1 character.
+ // DOS_STAR matches 0 or more characters until encountering and matching
+ // the final . in the name.
+ // DOS_QM matches any single character, or upon encountering a period or
+ // end of name string, advances the expression to the end of the
+ // set of contiguous DOS_QMs.
+ // DOS_DOT matches either a . or zero characters beyond name string.
+
+ private static bool MatchPattern(ReadOnlySpan<char> expression, ReadOnlySpan<char> name, bool ignoreCase, bool useExtendedWildcards)
{
// The idea behind the algorithm is pretty simple. We keep track of all possible locations
// in the regular expression that are matching the name. When the name has been exhausted,
// if one of the locations in the expression is also just exhausted, the name is in the
// language defined by the regular expression.
- if (string.IsNullOrEmpty(expression) || name.Length == 0)
+ if (expression.Length == 0 || name.Length == 0)
return false;
if (expression[0] == '*')
@@ -92,16 +169,17 @@ namespace System.IO
if (expression.Length == 1)
return true;
- if (expression.IndexOfAny(s_wildcardChars, startIndex: 1) == -1)
+ ReadOnlySpan<char> expressionEnd = expression.Slice(1);
+ if (expressionEnd.IndexOfAny(useExtendedWildcards ? s_wildcardChars : s_simpleWildcardChars) == -1)
{
// Handle the special case of a single starting *, which essentially means "ends with"
// If the name doesn't have enough characters to match the remaining expression, it can't be a match.
- if (name.Length < expression.Length - 1)
+ if (name.Length < expressionEnd.Length)
return false;
- // See if we end with the expression (minus the *, of course)
- return name.EndsWithOrdinal(expression.AsReadOnlySpan().Slice(1), ignoreCase);
+ // See if we end with the expression
+ return name.EndsWith(expressionEnd, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
}
}
@@ -117,13 +195,34 @@ namespace System.IO
char expressionChar;
Span<int> temp = stackalloc int[0];
- Span<int> priorMatches = stackalloc int[16];
Span<int> currentMatches = stackalloc int[16];
+ Span<int> priorMatches = stackalloc int[16];
+ priorMatches[0] = 0;
int maxState = expression.Length * 2;
int currentState;
bool nameFinished = false;
+ // Walk through the name string, picking off characters. We go one
+ // character beyond the end because some wild cards are able to match
+ // zero characters beyond the end of the string.
+ //
+ // With each new name character we determine a new set of states that
+ // match the name so far. We use two arrays that we swap back and forth
+ // for this purpose. One array lists the possible expression states for
+ // all name characters up to but not including the current one, and other
+ // array is used to build up the list of states considering the current
+ // name character as well. The arrays are then switched and the process
+ // repeated.
+ //
+ // There is not a one-to-one correspondence between state number and
+ // offset into the expression. State numbering is not continuous.
+ // This allows a simple conversion between state number and expression
+ // offset. Each character in the expression can represent one or two
+ // states. * and DOS_STAR generate two states: expressionOffset * 2 and
+ // expressionOffset * 2 + 1. All other expression characters can produce
+ // only a single state. Thus expressionOffset = currentState / 2.
+
while (!nameFinished)
{
if (nameOffset < name.Length)
@@ -177,7 +276,7 @@ namespace System.IO
// '*' matches any character zero or more times.
goto MatchZeroOrMore;
}
- else if (expressionChar == '<')
+ else if (useExtendedWildcards && expressionChar == '<')
{
// '<' (DOS_STAR) matches any character except '.' zero or more times.
@@ -210,11 +309,11 @@ namespace System.IO
}
else
{
- // The following expression characters all match by consuming
- // a character, thus force the expression, and thus state forward.
+ // The remaining expression characters all match by consuming a character,
+ // so we need to force the expression and state forward.
currentState += 2;
- if (expressionChar == '>')
+ if (useExtendedWildcards && expressionChar == '>')
{
// '>' (DOS_QM) is the most complicated. If the name is finished,
// we can match zero characters. If this name is a '.', we
@@ -226,7 +325,7 @@ namespace System.IO
currentMatches[currentMatch++] = currentState;
goto ExpressionFinished;
}
- else if (expressionChar == '"')
+ else if (useExtendedWildcards && expressionChar == '"')
{
// A '"' (DOS_DOT) can match either a period, or zero characters
// beyond the end of name.
@@ -242,6 +341,19 @@ namespace System.IO
}
else
{
+ if (expressionChar == '\\')
+ {
+ // Escape character, try to move the expression forward again and match literally.
+ if (++expressionOffset == expression.Length)
+ {
+ currentMatches[currentMatch++] = maxState;
+ goto ExpressionFinished;
+ }
+
+ currentState = expressionOffset * 2 + 2;
+ expressionChar = expression[expressionOffset];
+ }
+
// From this point on a name character is required to even
// continue, let alone make a match.
if (nameFinished) goto ExpressionFinished;
@@ -259,7 +371,6 @@ namespace System.IO
currentMatches[currentMatch++] = currentState;
}
- // The expression didn't match so move to the next prior match.
goto ExpressionFinished;
}
}
diff --git a/src/System.IO.FileSystem/src/System/IO/EnumerationOptions.cs b/src/System.IO.FileSystem/src/System/IO/EnumerationOptions.cs
new file mode 100644
index 0000000000..d78e8368e3
--- /dev/null
+++ b/src/System.IO.FileSystem/src/System/IO/EnumerationOptions.cs
@@ -0,0 +1,99 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.IO
+{
+ public class EnumerationOptions
+ {
+ /// <summary>
+ /// For internal use. These are the options we want to use if calling the existing Directory/File APIs where you don't
+ /// explicitly specify EnumerationOptions.
+ /// </summary>
+ internal static EnumerationOptions Compatible { get; } = new EnumerationOptions
+ { MatchType = MatchType.Win32, AttributesToSkip = 0, IgnoreInaccessible = false };
+
+ private static EnumerationOptions CompatibleRecursive { get; } = new EnumerationOptions
+ { RecurseSubdirectories = true, MatchType = MatchType.Win32, AttributesToSkip = 0, IgnoreInaccessible = false };
+
+ /// <summary>
+ /// Internal singleton for default options.
+ /// </summary>
+ internal static EnumerationOptions Default { get; } = new EnumerationOptions();
+
+ /// <summary>
+ /// Default constructor. Constructs the options class with recommended default options.
+ /// </summary>
+ public EnumerationOptions()
+ {
+ IgnoreInaccessible = true;
+ AttributesToSkip = FileAttributes.Hidden | FileAttributes.System;
+ }
+
+ /// <summary>
+ /// Converts SearchOptions to FindOptions. Throws if undefined SearchOption.
+ /// </summary>
+ internal static EnumerationOptions FromSearchOption(SearchOption searchOption)
+ {
+ if ((searchOption != SearchOption.TopDirectoryOnly) && (searchOption != SearchOption.AllDirectories))
+ throw new ArgumentOutOfRangeException(nameof(searchOption), SR.ArgumentOutOfRange_Enum);
+
+ return searchOption == SearchOption.AllDirectories ? CompatibleRecursive : Compatible;
+ }
+
+ /// <summary>
+ /// Should we recurse into subdirectories while enumerating?
+ /// Default is false.
+ /// </summary>
+ public bool RecurseSubdirectories { get; set; }
+
+ /// <summary>
+ /// Skip files/directories when access is denied (e.g. AccessDeniedException/SecurityException).
+ /// Default is true.
+ /// </summary>
+ public bool IgnoreInaccessible { get; set; }
+
+ /// <summary>
+ /// Suggested buffer size, in bytes. Default is 0 (no suggestion).
+ /// </summary>
+ /// <remarks>
+ /// Not all platforms use user allocated buffers, and some require either fixed buffers or a
+ /// buffer that has enough space to return a full result. One scenario where this option is
+ /// useful is with remote share enumeration on Windows. Having a large buffer may result in
+ /// better performance as more results can be batched over the wire (e.g. over a network
+ /// share). A "large" buffer, for example, would be 16K. Typical is 4K.
+ ///
+ /// We will not use the suggested buffer size if it has no meaning for the native APIs on the
+ /// current platform or if it would be too small for getting at least a single result.
+ /// </remarks>
+ public int BufferSize { get; set; }
+
+ /// <summary>
+ /// Skip entries with the given attributes. Default is FileAttributes.Hidden | FileAttributes.System.
+ /// </summary>
+ public FileAttributes AttributesToSkip { get; set; }
+
+ /// <summary>
+ /// For APIs that allow specifying a match expression this will allow you to specify how
+ /// to interpret the match expression.
+ /// </summary>
+ /// <remarks>
+ /// The default is simple matching where '*' is always 0 or more characters and '?' is a single character.
+ /// </remarks>
+ public MatchType MatchType { get; set; }
+
+
+ /// <summary>
+ /// For APIs that allow specifying a match expression this will allow you to specify case matching behavior.
+ /// </summary>
+ /// <remarks>
+ /// Default is to match platform defaults, which are gleaned from the case sensitivity of the temporary folder.
+ /// </remarks>
+ public MatchCasing MatchCasing { get; set; }
+
+ /// <summary>
+ /// Set to true to return "." and ".." directory entries.
+ /// </summary>
+ public bool ReturnSpecialDirectories { get; set; }
+ }
+}
diff --git a/src/System.IO.FileSystem/src/System/IO/File.cs b/src/System.IO.FileSystem/src/System/IO/File.cs
index bb12bf26f4..d2486b8f0d 100644
--- a/src/System.IO.FileSystem/src/System/IO/File.cs
+++ b/src/System.IO.FileSystem/src/System/IO/File.cs
@@ -5,7 +5,6 @@
using System.Buffers;
using System.Collections.Generic;
using System.Diagnostics;
-using System.Security;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -16,6 +15,7 @@ namespace System.IO
// routines such as Delete, etc.
public static class File
{
+ private const int MaxByteArrayLength = 0x7FFFFFC7;
private static Encoding s_UTF8NoBOM;
internal const int DefaultBufferSize = 4096;
@@ -44,39 +44,18 @@ namespace System.IO
return new StreamWriter(path, append: true);
}
-
- // Copies an existing file to a new file. An exception is raised if the
- // destination file already exists. Use the
- // Copy(string, string, boolean) method to allow
- // overwriting an existing file.
- //
- // The caller must have certain FileIOPermissions. The caller must have
- // Read permission to sourceFileName and Create
- // and Write permissions to destFileName.
- //
+ /// <summary>
+ /// Copies an existing file to a new file.
+ /// An exception is raised if the destination file already exists.
+ /// </summary>
public static void Copy(string sourceFileName, string destFileName)
- {
- if (sourceFileName == null)
- throw new ArgumentNullException(nameof(sourceFileName), SR.ArgumentNull_FileName);
- if (destFileName == null)
- throw new ArgumentNullException(nameof(destFileName), SR.ArgumentNull_FileName);
- if (sourceFileName.Length == 0)
- throw new ArgumentException(SR.Argument_EmptyFileName, nameof(sourceFileName));
- if (destFileName.Length == 0)
- throw new ArgumentException(SR.Argument_EmptyFileName, nameof(destFileName));
+ => Copy(sourceFileName, destFileName, overwrite: false);
- InternalCopy(sourceFileName, destFileName, false);
- }
-
- // Copies an existing file to a new file. If overwrite is
- // false, then an IOException is thrown if the destination file
- // already exists. If overwrite is true, the file is
- // overwritten.
- //
- // The caller must have certain FileIOPermissions. The caller must have
- // Read permission to sourceFileName
- // and Write permissions to destFileName.
- //
+ /// <summary>
+ /// Copies an existing file to a new file.
+ /// If <paramref name="overwrite"/> is false, an exception will be
+ /// raised if the destination exists. Otherwise it will be overwritten.
+ /// </summary>
public static void Copy(string sourceFileName, string destFileName, bool overwrite)
{
if (sourceFileName == null)
@@ -88,36 +67,13 @@ namespace System.IO
if (destFileName.Length == 0)
throw new ArgumentException(SR.Argument_EmptyFileName, nameof(destFileName));
- InternalCopy(sourceFileName, destFileName, overwrite);
- }
-
- /// <devdoc>
- /// Note: This returns the fully qualified name of the destination file.
- /// </devdoc>
- internal static string InternalCopy(string sourceFileName, string destFileName, bool overwrite)
- {
- Debug.Assert(sourceFileName != null);
- Debug.Assert(destFileName != null);
- Debug.Assert(sourceFileName.Length > 0);
- Debug.Assert(destFileName.Length > 0);
-
- string fullSourceFileName = Path.GetFullPath(sourceFileName);
- string fullDestFileName = Path.GetFullPath(destFileName);
-
- FileSystem.CopyFile(fullSourceFileName, fullDestFileName, overwrite);
-
- return fullDestFileName;
+ FileSystem.CopyFile(Path.GetFullPath(sourceFileName), Path.GetFullPath(destFileName), overwrite);
}
-
// Creates a file in a particular path. If the file exists, it is replaced.
// The file is opened with ReadWrite access and cannot be opened by another
// application until it has been closed. An IOException is thrown if the
// directory specified doesn't exist.
- //
- // Your application must have Create, Read, and Write permissions to
- // the file.
- //
public static FileStream Create(string path)
{
return Create(path, DefaultBufferSize);
@@ -127,48 +83,30 @@ namespace System.IO
// The file is opened with ReadWrite access and cannot be opened by another
// application until it has been closed. An IOException is thrown if the
// directory specified doesn't exist.
- //
- // Your application must have Create, Read, and Write permissions to
- // the file.
- //
public static FileStream Create(string path, int bufferSize)
- {
- return new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None, bufferSize);
- }
+ => new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None, bufferSize);
public static FileStream Create(string path, int bufferSize, FileOptions options)
- {
- return new FileStream(path, FileMode.Create, FileAccess.ReadWrite,
- FileShare.None, bufferSize, options);
- }
+ => new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None, bufferSize, options);
// Deletes a file. The file specified by the designated path is deleted.
// If the file does not exist, Delete succeeds without throwing
// an exception.
//
- // On NT, Delete will fail for a file that is open for normal I/O
- // or a file that is memory mapped.
- //
- // Your application must have Delete permission to the target file.
- //
+ // On Windows, Delete will fail for a file that is open for normal I/O
+ // or a file that is memory mapped.
public static void Delete(string path)
{
if (path == null)
throw new ArgumentNullException(nameof(path));
- string fullPath = Path.GetFullPath(path);
-
- FileSystem.DeleteFile(fullPath);
+ FileSystem.DeleteFile(Path.GetFullPath(path));
}
-
- // Tests if a file exists. The result is true if the file
+ // Tests whether a file exists. The result is true if the file
// given by the specified path exists; otherwise, the result is
// false. Note that if path describes a directory,
// Exists will return true.
- //
- // Your application must have Read permission for the target directory.
- //
public static bool Exists(string path)
{
try
@@ -179,6 +117,7 @@ namespace System.IO
return false;
path = Path.GetFullPath(path);
+
// After normalizing, check whether path ends in directory separator.
// Otherwise, FillAttributeInfo removes it and we may return a false positive.
// GetFullPath should never return null
@@ -188,22 +127,15 @@ namespace System.IO
return false;
}
- return InternalExists(path);
+ return FileSystem.FileExists(path);
}
catch (ArgumentException) { }
- catch (NotSupportedException) { } // Security can throw this on ":"
- catch (SecurityException) { }
catch (IOException) { }
catch (UnauthorizedAccessException) { }
return false;
}
- internal static bool InternalExists(string path)
- {
- return FileSystem.FileExists(path);
- }
-
public static FileStream Open(string path, FileMode mode)
{
return Open(path, mode, (mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite), FileShare.None);
@@ -388,17 +320,20 @@ namespace System.IO
public static byte[] ReadAllBytes(string path)
{
- return InternalReadAllBytes(path);
- }
-
- private static byte[] InternalReadAllBytes(string path)
- {
// bufferSize == 1 used to avoid unnecessary buffer in FileStream
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 1))
{
long fileLength = fs.Length;
if (fileLength > int.MaxValue)
+ {
throw new IOException(SR.IO_FileTooLong2GB);
+ }
+ else if (fileLength == 0)
+ {
+ // Some file systems (e.g. procfs on Linux) return 0 for length even when there's content.
+ // Thus we need to assume 0 doesn't mean empty.
+ return ReadAllBytesUnknownLength(fs);
+ }
int index = 0;
int count = (int)fileLength;
@@ -415,6 +350,50 @@ namespace System.IO
}
}
+ private static byte[] ReadAllBytesUnknownLength(FileStream fs)
+ {
+ byte[] rentedArray = null;
+ Span<byte> buffer = stackalloc byte[512];
+ try
+ {
+ int bytesRead = 0;
+ while (true)
+ {
+ if (bytesRead == buffer.Length)
+ {
+ uint newLength = (uint)buffer.Length * 2;
+ if (newLength > MaxByteArrayLength)
+ {
+ newLength = (uint)Math.Max(MaxByteArrayLength, buffer.Length + 1);
+ }
+
+ byte[] tmp = ArrayPool<byte>.Shared.Rent((int)newLength);
+ buffer.CopyTo(tmp);
+ if (rentedArray != null)
+ {
+ ArrayPool<byte>.Shared.Return(rentedArray);
+ }
+ buffer = rentedArray = tmp;
+ }
+
+ Debug.Assert(bytesRead < buffer.Length);
+ int n = fs.Read(buffer.Slice(bytesRead));
+ if (n == 0)
+ {
+ return buffer.Slice(0, bytesRead).ToArray();
+ }
+ bytesRead += n;
+ }
+ }
+ finally
+ {
+ if (rentedArray != null)
+ {
+ ArrayPool<byte>.Shared.Return(rentedArray);
+ }
+ }
+ }
+
public static void WriteAllBytes(string path, byte[] bytes)
{
if (path == null)
@@ -643,7 +622,7 @@ namespace System.IO
string fullSourceFileName = Path.GetFullPath(sourceFileName);
string fullDestFileName = Path.GetFullPath(destFileName);
- if (!InternalExists(fullSourceFileName))
+ if (!FileSystem.FileExists(fullSourceFileName))
{
throw new FileNotFoundException(SR.Format(SR.IO_FileNotFound_FileName, fullSourceFileName), fullSourceFileName);
}
@@ -723,23 +702,21 @@ namespace System.IO
Debug.Assert(encoding != null);
char[] buffer = null;
- StringBuilder sb = null;
StreamReader sr = AsyncStreamReader(path, encoding);
try
{
cancellationToken.ThrowIfCancellationRequested();
- sb = StringBuilderCache.Acquire();
buffer = ArrayPool<char>.Shared.Rent(sr.CurrentEncoding.GetMaxCharCount(DefaultBufferSize));
+ StringBuilder sb = new StringBuilder();
for (;;)
{
- int read = await sr.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
+ int read = await sr.ReadAsync(new Memory<char>(buffer), cancellationToken).ConfigureAwait(false);
if (read == 0)
{
return sb.ToString();
}
sb.Append(buffer, 0, read);
- cancellationToken.ThrowIfCancellationRequested();
}
}
finally
@@ -749,11 +726,6 @@ namespace System.IO
{
ArrayPool<char>.Shared.Return(buffer);
}
-
- if (sb != null)
- {
- StringBuilderCache.Release(sb);
- }
}
}
@@ -790,31 +762,23 @@ namespace System.IO
return Task.FromCanceled<byte[]>(cancellationToken);
}
- FileStream fs = new FileStream(
- path, FileMode.Open, FileAccess.Read, FileShare.Read, DefaultBufferSize,
+ var fs = new FileStream(
+ path, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 1, // bufferSize == 1 used to avoid unnecessary buffer in FileStream
FileOptions.Asynchronous | FileOptions.SequentialScan);
bool returningInternalTask = false;
try
{
long fileLength = fs.Length;
- if (cancellationToken.IsCancellationRequested)
- {
- return Task.FromCanceled<byte[]>(cancellationToken);
- }
-
if (fileLength > int.MaxValue)
{
return Task.FromException<byte[]>(new IOException(SR.IO_FileTooLong2GB));
}
- if (fileLength == 0)
- {
- return Task.FromResult(Array.Empty<byte>());
- }
-
returningInternalTask = true;
- return InternalReadAllBytesAsync(fs, (int)fileLength, cancellationToken);
+ return fileLength > 0 ?
+ InternalReadAllBytesAsync(fs, (int)fileLength, cancellationToken) :
+ InternalReadAllBytesUnknownLengthAsync(fs, cancellationToken);
}
finally
{
@@ -833,7 +797,7 @@ namespace System.IO
byte[] bytes = new byte[count];
do
{
- int n = await fs.ReadAsync(bytes, index, count - index, cancellationToken).ConfigureAwait(false);
+ int n = await fs.ReadAsync(new Memory<byte>(bytes, index, count - index), cancellationToken).ConfigureAwait(false);
if (n == 0)
{
throw Error.GetEndOfFile();
@@ -846,6 +810,44 @@ namespace System.IO
}
}
+ private static async Task<byte[]> InternalReadAllBytesUnknownLengthAsync(FileStream fs, CancellationToken cancellationToken)
+ {
+ byte[] rentedArray = ArrayPool<byte>.Shared.Rent(512);
+ try
+ {
+ int bytesRead = 0;
+ while (true)
+ {
+ if (bytesRead == rentedArray.Length)
+ {
+ uint newLength = (uint)rentedArray.Length * 2;
+ if (newLength > MaxByteArrayLength)
+ {
+ newLength = (uint)Math.Max(MaxByteArrayLength, rentedArray.Length + 1);
+ }
+
+ byte[] tmp = ArrayPool<byte>.Shared.Rent((int)newLength);
+ Buffer.BlockCopy(rentedArray, 0, tmp, 0, bytesRead);
+ ArrayPool<byte>.Shared.Return(rentedArray);
+ rentedArray = tmp;
+ }
+
+ Debug.Assert(bytesRead < rentedArray.Length);
+ int n = await fs.ReadAsync(rentedArray.AsMemory(bytesRead), cancellationToken).ConfigureAwait(false);
+ if (n == 0)
+ {
+ return rentedArray.AsSpan().Slice(0, bytesRead).ToArray();
+ }
+ bytesRead += n;
+ }
+ }
+ finally
+ {
+ fs.Dispose();
+ ArrayPool<byte>.Shared.Return(rentedArray);
+ }
+ }
+
public static Task WriteAllBytesAsync(string path, byte[] bytes, CancellationToken cancellationToken = default(CancellationToken))
{
if (path == null)
@@ -867,7 +869,7 @@ namespace System.IO
using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, DefaultBufferSize, FileOptions.Asynchronous | FileOptions.SequentialScan))
{
- await fs.WriteAsync(bytes, 0, bytes.Length, cancellationToken).ConfigureAwait(false);
+ await fs.WriteAsync(new ReadOnlyMemory<byte>(bytes), cancellationToken).ConfigureAwait(false);
await fs.FlushAsync(cancellationToken).ConfigureAwait(false);
}
}
@@ -960,8 +962,7 @@ namespace System.IO
{
int batchSize = Math.Min(DefaultBufferSize, count - index);
contents.CopyTo(index, buffer, 0, batchSize);
- cancellationToken.ThrowIfCancellationRequested();
- await sw.WriteAsync(buffer, 0, batchSize).ConfigureAwait(false);
+ await sw.WriteAsync(new ReadOnlyMemory<char>(buffer, 0, batchSize), cancellationToken).ConfigureAwait(false);
index += batchSize;
}
diff --git a/src/System.IO.FileSystem/src/System/IO/FileInfo.Windows.cs b/src/System.IO.FileSystem/src/System/IO/FileInfo.Windows.cs
deleted file mode 100644
index cec962f3f4..0000000000
--- a/src/System.IO.FileSystem/src/System/IO/FileInfo.Windows.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-
-namespace System.IO
-{
- partial class FileInfo
- {
- internal unsafe FileInfo(string fullPath, string fileName, ref RawFindData findData)
- : this(fullPath, fileName: fileName, isNormalized: true)
- {
- Debug.Assert(fileName.Equals(Path.GetFileName(fullPath)));
- Init(findData._info);
- }
- }
-}
diff --git a/src/System.IO.FileSystem/src/System/IO/FileInfo.cs b/src/System.IO.FileSystem/src/System/IO/FileInfo.cs
index 45d85da99f..45b019f127 100644
--- a/src/System.IO.FileSystem/src/System/IO/FileInfo.cs
+++ b/src/System.IO.FileSystem/src/System/IO/FileInfo.cs
@@ -12,8 +12,6 @@ namespace System.IO
[Serializable]
public sealed partial class FileInfo : FileSystemInfo
{
- private string _name;
-
private FileInfo() { }
public FileInfo(string fileName)
@@ -31,12 +29,6 @@ namespace System.IO
FullPath = isNormalized ? fullPath ?? originalPath : Path.GetFullPath(fullPath);
_name = fileName ?? Path.GetFileName(originalPath);
- DisplayPath = originalPath;
- }
-
- public override string Name
- {
- get { return _name; }
}
public long Length
@@ -45,22 +37,14 @@ namespace System.IO
{
if ((Attributes & FileAttributes.Directory) == FileAttributes.Directory)
{
- throw new FileNotFoundException(SR.Format(SR.IO_FileNotFound_FileName, DisplayPath), DisplayPath);
+ throw new FileNotFoundException(SR.Format(SR.IO_FileNotFound_FileName, FullPath), FullPath);
}
return LengthCore;
}
}
- /* Returns the name of the directory that the file is in */
- public string DirectoryName
- {
- get
- {
- return Path.GetDirectoryName(FullPath);
- }
- }
+ public string DirectoryName => Path.GetDirectoryName(FullPath);
- /* Creates an instance of the parent directory */
public DirectoryInfo Directory
{
get
@@ -88,50 +72,16 @@ namespace System.IO
}
public StreamReader OpenText()
- {
- return new StreamReader(FullPath, Encoding.UTF8, detectEncodingFromByteOrderMarks: true);
- }
+ => new StreamReader(NormalizedPath, Encoding.UTF8, detectEncodingFromByteOrderMarks: true);
public StreamWriter CreateText()
- {
- return new StreamWriter(FullPath, append: false);
- }
+ => new StreamWriter(NormalizedPath, append: false);
public StreamWriter AppendText()
- {
- return new StreamWriter(FullPath, append: true);
- }
-
-
- // Copies an existing file to a new file. An exception is raised if the
- // destination file already exists. Use the
- // Copy(string, string, boolean) method to allow
- // overwriting an existing file.
- //
- // The caller must have certain FileIOPermissions. The caller must have
- // Read permission to sourceFileName
- // and Write permissions to destFileName.
- //
- public FileInfo CopyTo(string destFileName)
- {
- if (destFileName == null)
- throw new ArgumentNullException(nameof(destFileName), SR.ArgumentNull_FileName);
- if (destFileName.Length == 0)
- throw new ArgumentException(SR.Argument_EmptyFileName, nameof(destFileName));
-
- return new FileInfo(File.InternalCopy(FullPath, destFileName, false), isNormalized: true);
- }
+ => new StreamWriter(NormalizedPath, append: true);
+ public FileInfo CopyTo(string destFileName) => CopyTo(destFileName, overwrite: false);
- // Copies an existing file to a new file. If overwrite is
- // false, then an IOException is thrown if the destination file
- // already exists. If overwrite is true, the file is
- // overwritten.
- //
- // The caller must have certain FileIOPermissions. The caller must have
- // Read permission to sourceFileName and Create
- // and Write permissions to destFileName.
- //
public FileInfo CopyTo(string destFileName, bool overwrite)
{
if (destFileName == null)
@@ -139,85 +89,32 @@ namespace System.IO
if (destFileName.Length == 0)
throw new ArgumentException(SR.Argument_EmptyFileName, nameof(destFileName));
- return new FileInfo(File.InternalCopy(FullPath, destFileName, overwrite), isNormalized: true);
+ string destinationPath = Path.GetFullPath(destFileName);
+ FileSystem.CopyFile(FullPath, destinationPath, overwrite);
+ return new FileInfo(destinationPath, isNormalized: true);
}
- public FileStream Create()
- {
- return File.Create(FullPath);
- }
-
- // Deletes a file. The file specified by the designated path is deleted.
- // If the file does not exist, Delete succeeds without throwing
- // an exception.
- //
- // On NT, Delete will fail for a file that is open for normal I/O
- // or a file that is memory mapped. On Win95, the file will be
- // deleted irregardless of whether the file is being used.
- //
- // Your application must have Delete permission to the target file.
- //
- public override void Delete()
- {
- FileSystem.DeleteFile(FullPath);
- }
+ public FileStream Create() => File.Create(NormalizedPath);
- // Tests if the given file exists. The result is true if the file
- // given by the specified path exists; otherwise, the result is
- // false.
- //
- // Your application must have Read permission for the target directory.
- public override bool Exists
- {
- get
- {
- try
- {
- return ExistsCore;
- }
- catch
- {
- return false;
- }
- }
- }
+ public override void Delete() => FileSystem.DeleteFile(FullPath);
- // User must explicitly specify opening a new file or appending to one.
public FileStream Open(FileMode mode)
- {
- return Open(mode, (mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite), FileShare.None);
- }
+ => Open(mode, (mode == FileMode.Append ? FileAccess.Write : FileAccess.ReadWrite), FileShare.None);
public FileStream Open(FileMode mode, FileAccess access)
- {
- return Open(mode, access, FileShare.None);
- }
+ => Open(mode, access, FileShare.None);
public FileStream Open(FileMode mode, FileAccess access, FileShare share)
- {
- return new FileStream(FullPath, mode, access, share);
- }
+ => new FileStream(NormalizedPath, mode, access, share);
public FileStream OpenRead()
- {
- return new FileStream(FullPath, FileMode.Open, FileAccess.Read,
- FileShare.Read, 4096, false);
- }
+ => new FileStream(NormalizedPath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, false);
public FileStream OpenWrite()
- {
- return new FileStream(FullPath, FileMode.OpenOrCreate,
- FileAccess.Write, FileShare.None);
- }
+ => new FileStream(NormalizedPath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None);
// Moves a given file to a new location and potentially a new file name.
// This method does work across volumes.
- //
- // The caller must have certain FileIOPermissions. The caller must
- // have Read and Write permission to
- // sourceFileName and Write
- // permissions to destFileName.
- //
public void MoveTo(string destFileName)
{
if (destFileName == null)
@@ -231,50 +128,40 @@ namespace System.IO
// as it does on Windows.These checks can be removed if a solution to #2460 is
// found that doesn't require validity checks before making an API call.
if (!new DirectoryInfo(Path.GetDirectoryName(FullName)).Exists)
- {
throw new DirectoryNotFoundException(SR.Format(SR.IO_PathNotFound_Path, FullName));
- }
+
if (!Exists)
- {
throw new FileNotFoundException(SR.Format(SR.IO_FileNotFound_FileName, FullName), FullName);
- }
FileSystem.MoveFile(FullPath, fullDestFileName);
FullPath = fullDestFileName;
OriginalPath = destFileName;
_name = Path.GetFileName(fullDestFileName);
- DisplayPath = destFileName;
+
// Flush any cached information about the file.
Invalidate();
}
public FileInfo Replace(string destinationFileName, string destinationBackupFileName)
- {
- return Replace(destinationFileName, destinationBackupFileName, ignoreMetadataErrors: false);
- }
+ => Replace(destinationFileName, destinationBackupFileName, ignoreMetadataErrors: false);
public FileInfo Replace(string destinationFileName, string destinationBackupFileName, bool ignoreMetadataErrors)
{
- File.Replace(FullPath, destinationFileName, destinationBackupFileName, ignoreMetadataErrors);
- return new FileInfo(destinationFileName);
- }
+ if (destinationFileName == null)
+ throw new ArgumentNullException(nameof(destinationFileName));
- // Returns the display path
- public override string ToString()
- {
- return DisplayPath;
- }
+ FileSystem.ReplaceFile(
+ FullPath,
+ Path.GetFullPath(destinationFileName),
+ destinationBackupFileName != null ? Path.GetFullPath(destinationBackupFileName) : null,
+ ignoreMetadataErrors);
- public void Decrypt()
- {
- File.Decrypt(FullPath);
+ return new FileInfo(destinationFileName);
}
- public void Encrypt()
- {
- File.Encrypt(FullPath);
- }
+ public void Decrypt() => File.Decrypt(FullPath);
+ public void Encrypt() => File.Encrypt(FullPath);
}
}
diff --git a/src/System.IO.FileSystem/src/System/IO/FileStatus.Unix.cs b/src/System.IO.FileSystem/src/System/IO/FileStatus.Unix.cs
new file mode 100644
index 0000000000..1c9337b210
--- /dev/null
+++ b/src/System.IO.FileSystem/src/System/IO/FileStatus.Unix.cs
@@ -0,0 +1,277 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.IO
+{
+ internal struct FileStatus
+ {
+ private const int NanosecondsPerTick = 100;
+
+ // The last cached stat information about the file
+ private Interop.Sys.FileStatus _fileStatus;
+
+ // -1 if _fileStatus isn't initialized, 0 if _fileStatus was initialized with no
+ // errors, or the errno error code.
+ private int _fileStatusInitialized;
+
+ // We track intent of creation to know whether or not we want to (1) create a
+ // DirectoryInfo around this status struct or (2) actually are part of a DirectoryInfo.
+ internal bool InitiallyDirectory { get; private set; }
+
+ // Is a directory as of the last refresh
+ internal bool _isDirectory;
+
+ // Exists as of the last refresh
+ private bool _exists;
+
+ internal static void Initialize(
+ ref FileStatus status,
+ bool isDirectory)
+ {
+ status.InitiallyDirectory = isDirectory;
+ status._fileStatusInitialized = -1;
+ }
+
+ internal void Invalidate() => _fileStatusInitialized = -1;
+
+ internal bool IsReadOnly(ReadOnlySpan<char> path, bool continueOnError = false)
+ {
+ EnsureStatInitialized(path, continueOnError);
+ Interop.Sys.Permissions readBit, writeBit;
+ if (_fileStatus.Uid == Interop.Sys.GetEUid())
+ {
+ // User effectively owns the file
+ readBit = Interop.Sys.Permissions.S_IRUSR;
+ writeBit = Interop.Sys.Permissions.S_IWUSR;
+ }
+ else if (_fileStatus.Gid == Interop.Sys.GetEGid())
+ {
+ // User belongs to a group that effectively owns the file
+ readBit = Interop.Sys.Permissions.S_IRGRP;
+ writeBit = Interop.Sys.Permissions.S_IWGRP;
+ }
+ else
+ {
+ // Others permissions
+ readBit = Interop.Sys.Permissions.S_IROTH;
+ writeBit = Interop.Sys.Permissions.S_IWOTH;
+ }
+
+ return ((_fileStatus.Mode & (int)readBit) != 0 && // has read permission
+ (_fileStatus.Mode & (int)writeBit) == 0); // but not write permission
+ }
+
+ public FileAttributes GetAttributes(ReadOnlySpan<char> path, ReadOnlySpan<char> fileName)
+ {
+ // IMPORTANT: Attribute logic must match the logic in FileSystemEntry
+
+ EnsureStatInitialized(path);
+
+ if (!_exists)
+ return (FileAttributes)(-1);
+
+ FileAttributes attributes = default;
+
+ if (IsReadOnly(path))
+ attributes |= FileAttributes.ReadOnly;
+
+ if ((_fileStatus.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFLNK)
+ attributes |= FileAttributes.ReparsePoint;
+
+ if (_isDirectory)
+ attributes |= FileAttributes.Directory;
+
+ // If the filename starts with a period, it's hidden.
+ if (fileName.Length > 0 && fileName[0] == '.')
+ attributes |= FileAttributes.Hidden;
+
+ return attributes != default ? attributes : FileAttributes.Normal;
+ }
+
+ public void SetAttributes(string path, FileAttributes attributes)
+ {
+ // Validate that only flags from the attribute are being provided. This is an
+ // approximation for the validation done by the Win32 function.
+ const FileAttributes allValidFlags =
+ FileAttributes.Archive | FileAttributes.Compressed | FileAttributes.Device |
+ FileAttributes.Directory | FileAttributes.Encrypted | FileAttributes.Hidden |
+ FileAttributes.Hidden | FileAttributes.IntegrityStream | FileAttributes.Normal |
+ FileAttributes.NoScrubData | FileAttributes.NotContentIndexed | FileAttributes.Offline |
+ FileAttributes.ReadOnly | FileAttributes.ReparsePoint | FileAttributes.SparseFile |
+ FileAttributes.System | FileAttributes.Temporary;
+ if ((attributes & ~allValidFlags) != 0)
+ {
+ // Using constant string for argument to match historical throw
+ throw new ArgumentException(SR.Arg_InvalidFileAttrs, "Attributes");
+ }
+
+ EnsureStatInitialized(path);
+
+ if (!_exists)
+ FileSystemInfo.ThrowNotFound(path);
+
+ // The only thing we can reasonably change is whether the file object is readonly by changing permissions.
+
+ int newMode = _fileStatus.Mode;
+ if ((attributes & FileAttributes.ReadOnly) != 0)
+ {
+ // Take away all write permissions from user/group/everyone
+ newMode &= ~(int)(Interop.Sys.Permissions.S_IWUSR | Interop.Sys.Permissions.S_IWGRP | Interop.Sys.Permissions.S_IWOTH);
+ }
+ else if ((newMode & (int)Interop.Sys.Permissions.S_IRUSR) != 0)
+ {
+ // Give write permission to the owner if the owner has read permission
+ newMode |= (int)Interop.Sys.Permissions.S_IWUSR;
+ }
+
+ // Change the permissions on the file
+ if (newMode != _fileStatus.Mode)
+ {
+ Interop.CheckIo(Interop.Sys.ChMod(path, newMode), path, InitiallyDirectory);
+ }
+
+ _fileStatusInitialized = -1;
+ }
+
+ internal bool GetExists(ReadOnlySpan<char> path)
+ {
+ if (_fileStatusInitialized == -1)
+ Refresh(path);
+
+ return _exists && InitiallyDirectory == _isDirectory;
+ }
+
+ internal DateTimeOffset GetCreationTime(ReadOnlySpan<char> path, bool continueOnError = false)
+ {
+ EnsureStatInitialized(path, continueOnError);
+ if (!_exists)
+ return DateTimeOffset.FromFileTime(0);
+
+ if ((_fileStatus.Flags & Interop.Sys.FileStatusFlags.HasBirthTime) != 0)
+ return UnixTimeToDateTimeOffset(_fileStatus.BirthTime, _fileStatus.BirthTimeNsec);
+
+ // fall back to the oldest time we have in between change and modify time
+ if (_fileStatus.MTime < _fileStatus.CTime ||
+ (_fileStatus.MTime == _fileStatus.CTime && _fileStatus.MTimeNsec < _fileStatus.CTimeNsec))
+ return UnixTimeToDateTimeOffset(_fileStatus.MTime, _fileStatus.MTimeNsec);
+
+ return UnixTimeToDateTimeOffset(_fileStatus.CTime, _fileStatus.CTimeNsec);
+ }
+
+ internal void SetCreationTime(string path, DateTimeOffset time)
+ {
+ // There isn't a reliable way to set this; however, we can't just do nothing since the
+ // FileSystemWatcher specifically looks for this call to make a Metadata Change, so we
+ // should set the LastAccessTime of the file to cause the metadata change we need.
+ SetLastAccessTime(path, time);
+ }
+
+ internal DateTimeOffset GetLastAccessTime(ReadOnlySpan<char> path, bool continueOnError = false)
+ {
+ EnsureStatInitialized(path, continueOnError);
+ if (!_exists)
+ return DateTimeOffset.FromFileTime(0);
+ return UnixTimeToDateTimeOffset(_fileStatus.ATime, _fileStatus.ATimeNsec);
+ }
+
+ internal void SetLastAccessTime(string path, DateTimeOffset time)
+ => SetAccessWriteTimes(path, time.ToUnixTimeSeconds(), null);
+
+ internal DateTimeOffset GetLastWriteTime(ReadOnlySpan<char> path, bool continueOnError = false)
+ {
+ EnsureStatInitialized(path, continueOnError);
+ if (!_exists)
+ return DateTimeOffset.FromFileTime(0);
+ return UnixTimeToDateTimeOffset(_fileStatus.MTime, _fileStatus.MTimeNsec);
+ }
+
+ internal void SetLastWriteTime(string path, DateTimeOffset time)
+ => SetAccessWriteTimes(path, null, time.ToUnixTimeSeconds());
+
+ private DateTimeOffset UnixTimeToDateTimeOffset(long seconds, long nanoseconds)
+ {
+ return DateTimeOffset.FromUnixTimeSeconds(seconds).AddTicks(nanoseconds / NanosecondsPerTick).ToLocalTime();
+ }
+
+ private void SetAccessWriteTimes(string path, long? accessTime, long? writeTime)
+ {
+ // force a refresh so that we have an up-to-date times for values not being overwritten
+ _fileStatusInitialized = -1;
+ EnsureStatInitialized(path);
+ Interop.Sys.UTimBuf buf;
+ // we use utime() not utimensat() so we drop the subsecond part
+ buf.AcTime = accessTime ?? _fileStatus.ATime;
+ buf.ModTime = writeTime ?? _fileStatus.MTime;
+ Interop.CheckIo(Interop.Sys.UTime(path, ref buf), path, InitiallyDirectory);
+ _fileStatusInitialized = -1;
+ }
+
+ internal long GetLength(ReadOnlySpan<char> path, bool continueOnError = false)
+ {
+ EnsureStatInitialized(path, continueOnError);
+ return _fileStatus.Size;
+ }
+
+ public void Refresh(ReadOnlySpan<char> path)
+ {
+ // This should not throw, instead we store the result so that we can throw it
+ // when someone actually accesses a property.
+
+ // Use lstat to get the details on the object, without following symlinks.
+ // If it is a symlink, then subsequently get details on the target of the symlink,
+ // storing those results separately. We only report failure if the initial
+ // lstat fails, as a broken symlink should still report info on exists, attributes, etc.
+ _isDirectory = false;
+ path = PathInternal.TrimEndingDirectorySeparator(path);
+ int result = Interop.Sys.LStat(path, out _fileStatus);
+ if (result < 0)
+ {
+ Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo();
+
+ // This should never set the error if the file can't be found.
+ // (see the Windows refresh passing returnErrorOnNotFound: false).
+ if (errorInfo.Error == Interop.Error.ENOENT
+ || errorInfo.Error == Interop.Error.ENOTDIR)
+ {
+ _fileStatusInitialized = 0;
+ _exists = false;
+ }
+ else
+ {
+ _fileStatusInitialized = errorInfo.RawErrno;
+ }
+ return;
+ }
+
+ _exists = true;
+
+ // IMPORTANT: Is directory logic must match the logic in FileSystemEntry
+ _isDirectory = (_fileStatus.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFDIR;
+
+ // If we're a symlink, attempt to check the target to see if it is a directory
+ if ((_fileStatus.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFLNK &&
+ Interop.Sys.Stat(path, out Interop.Sys.FileStatus targetStatus) >= 0)
+ {
+ _isDirectory = (targetStatus.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFDIR;
+ }
+
+ _fileStatusInitialized = 0;
+ }
+
+ internal void EnsureStatInitialized(ReadOnlySpan<char> path, bool continueOnError = false)
+ {
+ if (_fileStatusInitialized == -1)
+ {
+ Refresh(path);
+ }
+
+ if (_fileStatusInitialized != 0 && !continueOnError)
+ {
+ int errno = _fileStatusInitialized;
+ _fileStatusInitialized = -1;
+ throw Interop.GetExceptionForIoErrno(new Interop.ErrorInfo(errno), new string(path));
+ }
+ }
+ }
+}
diff --git a/src/System.IO.FileSystem/src/System/IO/FileSystem.Unix.cs b/src/System.IO.FileSystem/src/System/IO/FileSystem.Unix.cs
index 955d568322..d272734f96 100644
--- a/src/System.IO.FileSystem/src/System/IO/FileSystem.Unix.cs
+++ b/src/System.IO.FileSystem/src/System/IO/FileSystem.Unix.cs
@@ -2,11 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
-using System.Runtime.InteropServices;
-using System.Threading;
namespace System.IO
{
@@ -104,7 +101,8 @@ namespace System.IO
if (errorInfo.Error == Interop.Error.EXDEV || // rename fails across devices / mount points
errorInfo.Error == Interop.Error.EPERM || // permissions might not allow creating hard links even if a copy would work
errorInfo.Error == Interop.Error.EOPNOTSUPP || // links aren't supported by the source file system
- errorInfo.Error == Interop.Error.EMLINK) // too many hard links to the source file
+ errorInfo.Error == Interop.Error.EMLINK || // too many hard links to the source file
+ errorInfo.Error == Interop.Error.ENOSYS) // the file system doesn't support link
{
CopyFile(sourceFullPath, destFullPath, overwrite: false);
}
@@ -163,7 +161,7 @@ namespace System.IO
// Input allows trailing separators in order to match Windows behavior
// Unix does not accept trailing separators, so must be trimmed
- if (!FileExists(PathHelpers.TrimEndingDirectorySeparator(fullPath),
+ if (!FileExists(PathInternal.TrimEndingDirectorySeparator(fullPath),
Interop.Sys.FileTypes.S_IFREG, out fileExistsError) &&
fileExistsError.Error == Interop.Error.ENOENT)
{
@@ -186,7 +184,7 @@ namespace System.IO
int length = fullPath.Length;
// We need to trim the trailing slash or the code will try to create 2 directories of the same name.
- if (length >= 2 && PathHelpers.EndsInDirectorySeparator(fullPath))
+ if (length >= 2 && PathInternal.EndsInDirectorySeparator(fullPath))
{
length--;
}
@@ -293,11 +291,11 @@ namespace System.IO
// This surfaces as a IOException, if we let it go beyond here it would
// give DirectoryNotFound.
- if (PathHelpers.EndsInDirectorySeparator(sourceFullPath))
+ if (PathInternal.EndsInDirectorySeparator(sourceFullPath))
throw new IOException(SR.Format(SR.IO_PathNotFound_Path, sourceFullPath));
// ... but it doesn't care if the destination has a trailing separator.
- destFullPath = PathHelpers.TrimEndingDirectorySeparator(destFullPath);
+ destFullPath = PathInternal.TrimEndingDirectorySeparator(destFullPath);
}
if (Interop.Sys.Rename(sourceFullPath, destFullPath) < 0)
@@ -337,7 +335,7 @@ namespace System.IO
{
try
{
- foreach (string item in EnumeratePaths(directory.FullName, "*", SearchOption.TopDirectoryOnly, SearchTarget.Both))
+ foreach (string item in Directory.EnumerateFileSystemEntries(directory.FullName))
{
if (!ShouldIgnoreDirectory(Path.GetFileName(item)))
{
@@ -416,7 +414,7 @@ namespace System.IO
// Input allows trailing separators in order to match Windows behavior
// Unix does not accept trailing separators, so must be trimmed
- return FileExists(PathHelpers.TrimEndingDirectorySeparator(fullPath), Interop.Sys.FileTypes.S_IFREG, out ignored);
+ return FileExists(PathInternal.TrimEndingDirectorySeparator(fullPath), Interop.Sys.FileTypes.S_IFREG, out ignored);
}
private static bool FileExists(string fullPath, int fileType, out Interop.ErrorInfo errorInfo)
@@ -444,249 +442,6 @@ namespace System.IO
((fileinfo.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFDIR);
}
- public static IEnumerable<string> EnumeratePaths(string path, string searchPattern, SearchOption searchOption, SearchTarget searchTarget)
- {
- return new FileSystemEnumerable<string>(path, searchPattern, searchOption, searchTarget, (p, _) => p);
- }
-
- public static IEnumerable<FileSystemInfo> EnumerateFileSystemInfos(string fullPath, string searchPattern, SearchOption searchOption, SearchTarget searchTarget)
- {
- switch (searchTarget)
- {
- case SearchTarget.Files:
- return new FileSystemEnumerable<FileInfo>(fullPath, searchPattern, searchOption, searchTarget, (path, isDir) =>
- {
- var info = new FileInfo(path, null);
- info.Refresh();
- return info;
- });
- case SearchTarget.Directories:
- return new FileSystemEnumerable<DirectoryInfo>(fullPath, searchPattern, searchOption, searchTarget, (path, isDir) =>
- {
- var info = new DirectoryInfo(path, null);
- info.Refresh();
- return info;
- });
- default:
- return new FileSystemEnumerable<FileSystemInfo>(fullPath, searchPattern, searchOption, searchTarget, (path, isDir) =>
- {
- var info = isDir ?
- (FileSystemInfo)new DirectoryInfo(path, null) :
- (FileSystemInfo)new FileInfo(path, null);
- info.Refresh();
- return info;
- });
- }
- }
-
- private sealed class FileSystemEnumerable<T> : IEnumerable<T>
- {
- private readonly PathPair _initialDirectory;
- private readonly string _searchPattern;
- private readonly SearchOption _searchOption;
- private readonly bool _includeFiles;
- private readonly bool _includeDirectories;
- private readonly Func<string, bool, T> _translateResult;
- private IEnumerator<T> _firstEnumerator;
-
- internal FileSystemEnumerable(
- string userPath, string searchPattern,
- SearchOption searchOption, SearchTarget searchTarget,
- Func<string, bool, T> translateResult)
- {
- // Basic validation of the input path
- if (userPath == null)
- {
- throw new ArgumentNullException("path");
- }
- if (string.IsNullOrEmpty(userPath))
- {
- throw new ArgumentException(SR.Argument_EmptyPath, "path");
- }
-
- // Validate and normalize the search pattern. If after doing so it's empty,
- // matching Win32 behavior we can skip all additional validation and effectively
- // return an empty enumerable.
- searchPattern = NormalizeSearchPattern(searchPattern);
- if (searchPattern.Length > 0)
- {
- PathHelpers.ThrowIfEmptyOrRootedPath(searchPattern);
-
- // If the search pattern contains any paths, make sure we factor those into
- // the user path, and then trim them off.
- int lastSlash = searchPattern.LastIndexOf(Path.DirectorySeparatorChar);
- if (lastSlash >= 0)
- {
- if (lastSlash >= 1)
- {
- userPath = Path.Combine(userPath, searchPattern.Substring(0, lastSlash));
- }
- searchPattern = searchPattern.Substring(lastSlash + 1);
- }
-
- // Typically we shouldn't see either of these cases, an upfront check is much faster
- foreach (char c in searchPattern)
- {
- if (c == '\\' || c == '[')
- {
- // We need to escape any escape characters in the search pattern
- searchPattern = searchPattern.Replace(@"\", @"\\");
-
- // And then escape '[' to prevent it being picked up as a wildcard
- searchPattern = searchPattern.Replace(@"[", @"\[");
- break;
- }
- }
-
- string fullPath = Path.GetFullPath(userPath);
-
- // Store everything for the enumerator
- _initialDirectory = new PathPair(userPath, fullPath);
- _searchPattern = searchPattern;
- _searchOption = searchOption;
- _includeFiles = (searchTarget & SearchTarget.Files) != 0;
- _includeDirectories = (searchTarget & SearchTarget.Directories) != 0;
- _translateResult = translateResult;
- }
-
- // Open the first enumerator so that any errors are propagated synchronously.
- _firstEnumerator = Enumerate();
- }
-
- public IEnumerator<T> GetEnumerator()
- {
- return Interlocked.Exchange(ref _firstEnumerator, null) ?? Enumerate();
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
-
- private IEnumerator<T> Enumerate()
- {
- return Enumerate(
- _initialDirectory.FullPath != null ?
- OpenDirectory(_initialDirectory.FullPath) :
- null);
- }
-
- private IEnumerator<T> Enumerate(Microsoft.Win32.SafeHandles.SafeDirectoryHandle dirHandle)
- {
- if (dirHandle == null)
- {
- // Empty search
- yield break;
- }
-
- Debug.Assert(!dirHandle.IsInvalid);
- Debug.Assert(!dirHandle.IsClosed);
-
- // Maintain a stack of the directories to explore, in the case of SearchOption.AllDirectories
- // Lazily-initialized only if we find subdirectories that will be explored.
- Stack<PathPair> toExplore = null;
- PathPair dirPath = _initialDirectory;
- while (dirHandle != null)
- {
- try
- {
- // Read each entry from the enumerator
- Interop.Sys.DirectoryEntry dirent;
- while (Interop.Sys.ReadDir(dirHandle, out dirent) == 0)
- {
- // Get from the dir entry whether the entry is a file or directory.
- // We classify everything as a file unless we know it to be a directory.
- bool isDir;
- if (dirent.InodeType == Interop.Sys.NodeType.DT_DIR)
- {
- // We know it's a directory.
- isDir = true;
- }
- else if (dirent.InodeType == Interop.Sys.NodeType.DT_LNK || dirent.InodeType == Interop.Sys.NodeType.DT_UNKNOWN)
- {
- // It's a symlink or unknown: stat to it to see if we can resolve it to a directory.
- // If we can't (e.g. symlink to a file, broken symlink, etc.), we'll just treat it as a file.
- Interop.ErrorInfo errnoIgnored;
- isDir = DirectoryExists(Path.Combine(dirPath.FullPath, dirent.InodeName), out errnoIgnored);
- }
- else
- {
- // Otherwise, treat it as a file. This includes regular files, FIFOs, etc.
- isDir = false;
- }
-
- // Yield the result if the user has asked for it. In the case of directories,
- // always explore it by pushing it onto the stack, regardless of whether
- // we're returning directories.
- if (isDir)
- {
- if (!ShouldIgnoreDirectory(dirent.InodeName))
- {
- string userPath = null;
- if (_searchOption == SearchOption.AllDirectories)
- {
- if (toExplore == null)
- {
- toExplore = new Stack<PathPair>();
- }
- userPath = Path.Combine(dirPath.UserPath, dirent.InodeName);
- toExplore.Push(new PathPair(userPath, Path.Combine(dirPath.FullPath, dirent.InodeName)));
- }
- if (_includeDirectories &&
- Interop.Sys.FnMatch(_searchPattern, dirent.InodeName, Interop.Sys.FnMatchFlags.FNM_NONE) == 0)
- {
- yield return _translateResult(userPath ?? Path.Combine(dirPath.UserPath, dirent.InodeName), /*isDirectory*/true);
- }
- }
- }
- else if (_includeFiles &&
- Interop.Sys.FnMatch(_searchPattern, dirent.InodeName, Interop.Sys.FnMatchFlags.FNM_NONE) == 0)
- {
- yield return _translateResult(Path.Combine(dirPath.UserPath, dirent.InodeName), /*isDirectory*/false);
- }
- }
- }
- finally
- {
- // Close the directory enumerator
- dirHandle.Dispose();
- dirHandle = null;
- }
-
- if (toExplore != null && toExplore.Count > 0)
- {
- // Open the next directory.
- dirPath = toExplore.Pop();
- dirHandle = OpenDirectory(dirPath.FullPath);
- }
- }
- }
-
- private static string NormalizeSearchPattern(string searchPattern)
- {
- if (searchPattern == "." || searchPattern == "*.*")
- {
- searchPattern = "*";
- }
- else if (PathHelpers.EndsInDirectorySeparator(searchPattern))
- {
- searchPattern += "*";
- }
-
- return searchPattern;
- }
-
- private static Microsoft.Win32.SafeHandles.SafeDirectoryHandle OpenDirectory(string fullPath)
- {
- Microsoft.Win32.SafeHandles.SafeDirectoryHandle handle = Interop.Sys.OpenDir(fullPath);
- if (handle.IsInvalid)
- {
- throw Interop.GetExceptionForIoErrno(Interop.Sys.GetLastErrorInfo(), fullPath, isDirectory: true);
- }
- return handle;
- }
- }
-
/// <summary>Determines whether the specified directory name should be ignored.</summary>
/// <param name="name">The name to evaluate.</param>
/// <returns>true if the name is "." or ".."; otherwise, false.</returns>
@@ -695,16 +450,6 @@ namespace System.IO
return name == "." || name == "..";
}
- public static string GetCurrentDirectory()
- {
- return Interop.Sys.GetCwd();
- }
-
- public static void SetCurrentDirectory(string fullPath)
- {
- Interop.CheckIo(Interop.Sys.ChDir(fullPath), fullPath, isDirectory:true);
- }
-
public static FileAttributes GetAttributes(string fullPath)
{
FileAttributes attributes = new FileInfo(fullPath, null).Attributes;
@@ -762,13 +507,6 @@ namespace System.IO
info.LastWriteTimeCore = time;
}
- public static FileSystemInfo GetFileSystemInfo(string fullPath, bool asDirectory)
- {
- return asDirectory ?
- (FileSystemInfo)new DirectoryInfo(fullPath, null) :
- (FileSystemInfo)new FileInfo(fullPath, null);
- }
-
public static string[] GetLogicalDrives()
{
return DriveInfoInternal.GetLogicalDrives();
diff --git a/src/System.IO.FileSystem/src/System/IO/FileSystem.Windows.cs b/src/System.IO.FileSystem/src/System/IO/FileSystem.Windows.cs
index 84f8e6ff87..a3e1a50d4c 100644
--- a/src/System.IO.FileSystem/src/System/IO/FileSystem.Windows.cs
+++ b/src/System.IO.FileSystem/src/System/IO/FileSystem.Windows.cs
@@ -66,7 +66,7 @@ namespace System.IO
List<string> stackDir = new List<string>();
// Attempt to figure out which directories don't exist, and only
- // create the ones we need. Note that InternalExists may fail due
+ // create the ones we need. Note that FileExists may fail due
// to Win32 ACL's preventing us from seeing a directory, and this
// isn't threadsafe.
@@ -75,7 +75,7 @@ namespace System.IO
int length = fullPath.Length;
// We need to trim the trailing slash or the code will try to create 2 directories of the same name.
- if (length >= 2 && PathHelpers.EndsInDirectorySeparator(fullPath))
+ if (length >= 2 && PathInternal.EndsInDirectorySeparator(fullPath))
length--;
int lengthRoot = PathInternal.GetRootLength(fullPath);
@@ -120,7 +120,7 @@ namespace System.IO
int currentError = Marshal.GetLastWin32Error();
// While we tried to avoid creating directories that don't
// exist above, there are at least two cases that will
- // cause us to see ERROR_ALREADY_EXISTS here. InternalExists
+ // cause us to see ERROR_ALREADY_EXISTS here. FileExists
// can fail because we didn't have permission to the
// directory. Secondly, another thread or process could
// create the directory between the time we check and the
@@ -131,7 +131,7 @@ namespace System.IO
else
{
// If there's a file in this directory's place, or if we have ERROR_ACCESS_DENIED when checking if the directory already exists throw.
- if (File.InternalExists(name) || (!DirectoryExists(name, out currentError) && currentError == Interop.Errors.ERROR_ACCESS_DENIED))
+ if (FileExists(name) || (!DirectoryExists(name, out currentError) && currentError == Interop.Errors.ERROR_ACCESS_DENIED))
{
firstError = currentError;
errorString = name;
@@ -183,38 +183,6 @@ namespace System.IO
&& ((data.dwFileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY) != 0);
}
- public static IEnumerable<string> EnumeratePaths(string fullPath, string searchPattern, SearchOption searchOption, SearchTarget searchTarget)
- {
- FindEnumerableFactory.NormalizeInputs(ref fullPath, ref searchPattern);
- switch (searchTarget)
- {
- case SearchTarget.Files:
- return FindEnumerableFactory.UserFiles(fullPath, searchPattern, searchOption == SearchOption.AllDirectories);
- case SearchTarget.Directories:
- return FindEnumerableFactory.UserDirectories(fullPath, searchPattern, searchOption == SearchOption.AllDirectories);
- case SearchTarget.Both:
- return FindEnumerableFactory.UserEntries(fullPath, searchPattern, searchOption == SearchOption.AllDirectories);
- default:
- throw new ArgumentOutOfRangeException(nameof(searchTarget));
- }
- }
-
- public static IEnumerable<FileSystemInfo> EnumerateFileSystemInfos(string fullPath, string searchPattern, SearchOption searchOption, SearchTarget searchTarget)
- {
- FindEnumerableFactory.NormalizeInputs(ref fullPath, ref searchPattern);
- switch (searchTarget)
- {
- case SearchTarget.Directories:
- return FindEnumerableFactory.DirectoryInfos(fullPath, searchPattern, searchOption == SearchOption.AllDirectories);
- case SearchTarget.Files:
- return FindEnumerableFactory.FileInfos(fullPath, searchPattern, searchOption == SearchOption.AllDirectories);
- case SearchTarget.Both:
- return FindEnumerableFactory.FileSystemInfos(fullPath, searchPattern, searchOption == SearchOption.AllDirectories);
- default:
- throw new ArgumentException(SR.ArgumentOutOfRange_Enum, nameof(searchTarget));
- }
- }
-
/// <summary>
/// Returns 0 on success, otherwise a Win32 error code. Note that
/// classes should use -1 as the uninitialized state for dataInitialized.
@@ -225,7 +193,7 @@ namespace System.IO
int errorCode = Interop.Errors.ERROR_SUCCESS;
// Neither GetFileAttributes or FindFirstFile like trailing separators
- path = path.TrimEnd(PathHelpers.DirectorySeparatorChars);
+ path = PathInternal.TrimEndingDirectorySeparator(path);
using (DisableMediaInsertionPrompt.Create())
{
@@ -291,36 +259,6 @@ namespace System.IO
return (FileAttributes)data.dwFileAttributes;
}
- public static string GetCurrentDirectory()
- {
- StringBuilder sb = StringBuilderCache.Acquire(Interop.Kernel32.MAX_PATH + 1);
- if (Interop.Kernel32.GetCurrentDirectory(sb.Capacity, sb) == 0)
- throw Win32Marshal.GetExceptionForLastWin32Error();
- string currentDirectory = sb.ToString();
- // Note that if we have somehow put our command prompt into short
- // file name mode (i.e. by running edlin or a DOS grep, etc), then
- // this will return a short file name.
- if (currentDirectory.IndexOf('~') >= 0)
- {
- int r = Interop.Kernel32.GetLongPathName(currentDirectory, sb, sb.Capacity);
- if (r == 0 || r >= Interop.Kernel32.MAX_PATH)
- {
- int errorCode = Marshal.GetLastWin32Error();
- if (r >= Interop.Kernel32.MAX_PATH)
- errorCode = Interop.Errors.ERROR_FILENAME_EXCED_RANGE;
- if (errorCode != Interop.Errors.ERROR_FILE_NOT_FOUND &&
- errorCode != Interop.Errors.ERROR_PATH_NOT_FOUND &&
- errorCode != Interop.Errors.ERROR_INVALID_FUNCTION && // by design - enough said.
- errorCode != Interop.Errors.ERROR_ACCESS_DENIED)
- throw Win32Marshal.GetExceptionForWin32Error(errorCode);
- }
- currentDirectory = sb.ToString();
- }
- StringBuilderCache.Release(sb);
-
- return currentDirectory;
- }
-
public static DateTimeOffset GetCreationTime(string fullPath)
{
Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data = new Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA();
@@ -417,9 +355,17 @@ namespace System.IO
public static void RemoveDirectory(string fullPath, bool recursive)
{
- // Do not recursively delete through reparse points.
- if (!recursive || IsReparsePoint(fullPath))
+ if (!recursive)
+ {
+ RemoveDirectoryInternal(fullPath, topLevel: true);
+ return;
+ }
+
+ Interop.Kernel32.WIN32_FIND_DATA findData = new Interop.Kernel32.WIN32_FIND_DATA();
+ GetFindData(fullPath, ref findData);
+ if (IsNameSurrogateReparsePoint(ref findData))
{
+ // Don't recurse
RemoveDirectoryInternal(fullPath, topLevel: true);
return;
}
@@ -427,24 +373,38 @@ namespace System.IO
// We want extended syntax so we can delete "extended" subdirectories and files
// (most notably ones with trailing whitespace or periods)
fullPath = PathInternal.EnsureExtendedPrefix(fullPath);
-
- Interop.Kernel32.WIN32_FIND_DATA findData = new Interop.Kernel32.WIN32_FIND_DATA();
RemoveDirectoryRecursive(fullPath, ref findData, topLevel: true);
}
- private static bool IsReparsePoint(string fullPath)
+ private static void GetFindData(string fullPath, ref Interop.Kernel32.WIN32_FIND_DATA findData)
{
- Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data = new Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA();
- int errorCode = FillAttributeInfo(fullPath, ref data, returnErrorOnNotFound: true);
- if (errorCode != Interop.Errors.ERROR_SUCCESS)
+ using (SafeFindHandle handle = Interop.Kernel32.FindFirstFile(PathInternal.TrimEndingDirectorySeparator(fullPath), ref findData))
{
- // File not found doesn't make much sense coming from a directory delete.
- if (errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND)
- errorCode = Interop.Errors.ERROR_PATH_NOT_FOUND;
- throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath);
+ if (handle.IsInvalid)
+ {
+ int errorCode = Marshal.GetLastWin32Error();
+ // File not found doesn't make much sense coming from a directory delete.
+ if (errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND)
+ errorCode = Interop.Errors.ERROR_PATH_NOT_FOUND;
+ throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath);
+ }
}
+ }
- return (((FileAttributes)data.dwFileAttributes & FileAttributes.ReparsePoint) != 0);
+ private static bool IsNameSurrogateReparsePoint(ref Interop.Kernel32.WIN32_FIND_DATA data)
+ {
+ // Name surrogates are reparse points that point to other named entities local to the file system.
+ // Reparse points can be used for other types of files, notably OneDrive placeholder files. We
+ // should treat reparse points that are not name surrogates as any other directory, e.g. recurse
+ // into them. Surrogates should just be detached.
+ //
+ // See
+ // https://github.com/dotnet/corefx/issues/24250
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365511.aspx
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365197.aspx
+
+ return ((FileAttributes)data.dwFileAttributes & FileAttributes.ReparsePoint) != 0
+ && (data.dwReserved0 & 0x20000000) != 0; // IsReparseTagNameSurrogate
}
private static void RemoveDirectoryRecursive(string fullPath, ref Interop.Kernel32.WIN32_FIND_DATA findData, bool topLevel)
@@ -452,7 +412,7 @@ namespace System.IO
int errorCode;
Exception exception = null;
- using (SafeFindHandle handle = Interop.Kernel32.FindFirstFile(Directory.EnsureTrailingDirectorySeparator(fullPath) + "*", ref findData))
+ using (SafeFindHandle handle = Interop.Kernel32.FindFirstFile(Path.Join(fullPath, "*"), ref findData))
{
if (handle.IsInvalid)
throw Win32Marshal.GetExceptionForLastWin32Error(fullPath);
@@ -481,9 +441,10 @@ namespace System.IO
continue;
string fileName = findData.cFileName.GetStringFromFixedBuffer();
- if ((findData.dwFileAttributes & (int)FileAttributes.ReparsePoint) == 0)
+
+ if (!IsNameSurrogateReparsePoint(ref findData))
{
- // Not a reparse point, recurse.
+ // Not a reparse point, or the reparse point isn't a name surrogate, recurse.
try
{
RemoveDirectoryRecursive(
@@ -499,12 +460,13 @@ namespace System.IO
}
else
{
- // Reparse point, don't recurse, just remove. (dwReserved0 is documented for this flag)
+ // Name surrogate reparse point, don't recurse, simply remove the directory.
+ // If a mount point, we have to delete the mount point first.
if (findData.dwReserved0 == Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_MOUNT_POINT)
{
// Mount point. Unmount using full path plus a trailing '\'.
// (Note: This doesn't remove the underlying directory)
- string mountPoint = Path.Combine(fullPath, fileName + PathHelpers.DirectorySeparatorCharAsString);
+ string mountPoint = Path.Join(fullPath, fileName, PathInternal.DirectorySeparatorCharAsString);
if (!Interop.Kernel32.DeleteVolumeMountPoint(mountPoint) && exception == null)
{
errorCode = Marshal.GetLastWin32Error();
@@ -594,20 +556,6 @@ namespace System.IO
}
}
- public static void SetCurrentDirectory(string fullPath)
- {
- if (!Interop.Kernel32.SetCurrentDirectory(fullPath))
- {
- // If path doesn't exist, this sets last error to 2 (File
- // not Found). LEGACY: This may potentially have worked correctly
- // on Win9x, maybe.
- int errorCode = Marshal.GetLastWin32Error();
- if (errorCode == Interop.Errors.ERROR_FILE_NOT_FOUND)
- errorCode = Interop.Errors.ERROR_PATH_NOT_FOUND;
- throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath);
- }
- }
-
public static void SetLastAccessTime(string fullPath, DateTimeOffset time, bool asDirectory)
{
using (SafeFileHandle handle = OpenHandle(fullPath, asDirectory))
diff --git a/src/System.IO.FileSystem/src/System/IO/FileSystemInfo.Unix.cs b/src/System.IO.FileSystem/src/System/IO/FileSystemInfo.Unix.cs
index 6e3733e8a8..aac479e6e1 100644
--- a/src/System.IO.FileSystem/src/System/IO/FileSystemInfo.Unix.cs
+++ b/src/System.IO.FileSystem/src/System/IO/FileSystemInfo.Unix.cs
@@ -2,329 +2,84 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Diagnostics;
+
namespace System.IO
{
partial class FileSystemInfo
{
- private const int NanosecondsPerTick = 100;
-
- /// <summary>The last cached stat information about the file.</summary>
- private Interop.Sys.FileStatus _fileStatus;
- /// <summary>true if <see cref="_fileStatus"/> represents a symlink and the target of that symlink is a directory.</summary>
- private bool _targetOfSymlinkIsDirectory;
-
- /// <summary>
- /// Exists as a path as of last refresh.
- /// </summary>
- private bool _exists;
-
- /// <summary>
- /// Whether we've successfully cached a stat structure.
- /// -1 if we need to refresh _fileStatus, 0 if we've successfully cached one,
- /// or any other value that serves as an errno error code from the
- /// last time we tried and failed to refresh _fileStatus.
- /// </summary>
- private int _fileStatusInitialized = -1;
+ private FileStatus _fileStatus;
- internal void Invalidate()
+ protected FileSystemInfo()
{
- _fileStatusInitialized = -1;
+ FileStatus.Initialize(ref _fileStatus, this is DirectoryInfo);
}
- public FileAttributes Attributes
+ internal static unsafe FileSystemInfo Create(string fullPath, string fileName, ref FileStatus fileStatus)
{
- get
- {
- EnsureStatInitialized();
-
- if (!_exists)
- return (FileAttributes)(-1);
-
- FileAttributes attrs = default(FileAttributes);
+ FileSystemInfo info = fileStatus.InitiallyDirectory
+ ? (FileSystemInfo)new DirectoryInfo(fullPath, fileName: fileName, isNormalized: true)
+ : new FileInfo(fullPath, fileName: fileName, isNormalized: true);
- if (IsDirectoryAssumesInitialized) // this is the one attribute where we follow symlinks
- {
- attrs |= FileAttributes.Directory;
- }
- if (IsReadOnlyAssumesInitialized)
- {
- attrs |= FileAttributes.ReadOnly;
- }
- if (IsSymlinkAssumesInitialized)
- {
- attrs |= FileAttributes.ReparsePoint;
- }
+ Debug.Assert(!PathInternal.IsPartiallyQualified(fullPath), $"'{fullPath}' should be fully qualified when constructed from directory enumeration");
- // If the filename starts with a period, it's hidden. Or if this is a directory ending in a slash,
- // if the directory name starts with a period, it's hidden.
- string fileName = Path.GetFileName(FullPath);
- if (string.IsNullOrEmpty(fileName))
- {
- fileName = Path.GetFileName(Path.GetDirectoryName(FullPath));
- }
- if (!string.IsNullOrEmpty(fileName) && fileName[0] == '.')
- {
- attrs |= FileAttributes.Hidden;
- }
-
- return attrs != default(FileAttributes) ?
- attrs :
- FileAttributes.Normal;
- }
- set
- {
- // Validate that only flags from the attribute are being provided. This is an
- // approximation for the validation done by the Win32 function.
- const FileAttributes allValidFlags =
- FileAttributes.Archive | FileAttributes.Compressed | FileAttributes.Device |
- FileAttributes.Directory | FileAttributes.Encrypted | FileAttributes.Hidden |
- FileAttributes.Hidden | FileAttributes.IntegrityStream | FileAttributes.Normal |
- FileAttributes.NoScrubData | FileAttributes.NotContentIndexed | FileAttributes.Offline |
- FileAttributes.ReadOnly | FileAttributes.ReparsePoint | FileAttributes.SparseFile |
- FileAttributes.System | FileAttributes.Temporary;
- if ((value & ~allValidFlags) != 0)
- {
- throw new ArgumentException(SR.Arg_InvalidFileAttrs, nameof(value));
- }
-
- // The only thing we can reasonably change is whether the file object is readonly,
- // just changing its permissions accordingly.
- EnsureStatInitialized();
-
- if (!_exists)
- {
- ThrowNotFound(FullPath);
- }
-
- IsReadOnlyAssumesInitialized = (value & FileAttributes.ReadOnly) != 0;
- _fileStatusInitialized = -1;
- }
+ info.Init(ref fileStatus);
+ return info;
}
- internal static void ThrowNotFound(string path)
- {
- // Windows distinguishes between whether the directory or the file isn't found,
- // and throws a different exception in these cases. We attempt to approximate that
- // here; there is a race condition here, where something could change between
- // when the error occurs and our checks, but it's the best we can do, and the
- // worst case in such a race condition (which could occur if the file system is
- // being manipulated concurrently with these checks) is that we throw a
- // FileNotFoundException instead of DirectoryNotFoundException.
+ internal void Invalidate() => _fileStatus.Invalidate();
- bool directoryError = !Directory.Exists(Path.GetDirectoryName(PathHelpers.TrimEndingDirectorySeparator(path)));
- throw Interop.GetExceptionForIoErrno(new Interop.ErrorInfo(Interop.Error.ENOENT), path, directoryError);
- }
-
- /// <summary>Gets whether stat reported this system object as a directory.</summary>
- private bool IsDirectoryAssumesInitialized =>
- (_fileStatus.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFDIR ||
- (IsSymlinkAssumesInitialized && _targetOfSymlinkIsDirectory);
-
- /// <summary>Gets whether stat reported this system object as a symlink.</summary>
- private bool IsSymlinkAssumesInitialized =>
- (_fileStatus.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFLNK;
-
- /// <summary>
- /// Gets or sets whether the file is read-only. This is based on the read/write/execute
- /// permissions of the object.
- /// </summary>
- private bool IsReadOnlyAssumesInitialized
+ internal unsafe void Init(ref FileStatus fileStatus)
{
- get
- {
- Interop.Sys.Permissions readBit, writeBit;
- if (_fileStatus.Uid == Interop.Sys.GetEUid()) // does the user effectively own the file?
- {
- readBit = Interop.Sys.Permissions.S_IRUSR;
- writeBit = Interop.Sys.Permissions.S_IWUSR;
- }
- else if (_fileStatus.Gid == Interop.Sys.GetEGid()) // does the user belong to a group that effectively owns the file?
- {
- readBit = Interop.Sys.Permissions.S_IRGRP;
- writeBit = Interop.Sys.Permissions.S_IWGRP;
- }
- else // everyone else
- {
- readBit = Interop.Sys.Permissions.S_IROTH;
- writeBit = Interop.Sys.Permissions.S_IWOTH;
- }
-
- return
- (_fileStatus.Mode & (int)readBit) != 0 && // has read permission
- (_fileStatus.Mode & (int)writeBit) == 0; // but not write permission
- }
- set
- {
- int newMode = _fileStatus.Mode;
- if (value) // true if going from writable to readable, false if going from readable to writable
- {
- // Take away all write permissions from user/group/everyone
- newMode &= ~(int)(Interop.Sys.Permissions.S_IWUSR | Interop.Sys.Permissions.S_IWGRP | Interop.Sys.Permissions.S_IWOTH);
- }
- else if ((newMode & (int)Interop.Sys.Permissions.S_IRUSR) != 0)
- {
- // Give write permission to the owner if the owner has read permission
- newMode |= (int)Interop.Sys.Permissions.S_IWUSR;
- }
-
- // Change the permissions on the file
- if (newMode != _fileStatus.Mode)
- {
- bool isDirectory = this is DirectoryInfo;
- Interop.CheckIo(Interop.Sys.ChMod(FullPath, newMode), FullPath, isDirectory);
- }
- }
+ _fileStatus = fileStatus;
+ _fileStatus.EnsureStatInitialized(FullPath);
}
- internal bool ExistsCore
+ public FileAttributes Attributes
{
- get
- {
- if (_fileStatusInitialized == -1)
- {
- Refresh();
- }
-
- return
- _exists &&
- (this is DirectoryInfo) == IsDirectoryAssumesInitialized;
- }
+ get => _fileStatus.GetAttributes(FullPath, Name);
+ set => _fileStatus.SetAttributes(FullPath, value);
}
+ internal bool ExistsCore => _fileStatus.GetExists(FullPath);
+
internal DateTimeOffset CreationTimeCore
{
- get
- {
- EnsureStatInitialized();
- if (!_exists)
- return DateTimeOffset.FromFileTime(0);
-
- if ((_fileStatus.Flags & Interop.Sys.FileStatusFlags.HasBirthTime) != 0)
- return UnixTimeToDateTimeOffset(_fileStatus.BirthTime, _fileStatus.BirthTimeNsec);
-
- // fall back to the oldest time we have in between change and modify time
- if (_fileStatus.MTime < _fileStatus.CTime ||
- (_fileStatus.MTime == _fileStatus.CTime && _fileStatus.MTimeNsec < _fileStatus.CTimeNsec))
- return UnixTimeToDateTimeOffset(_fileStatus.MTime, _fileStatus.MTimeNsec);
-
- return UnixTimeToDateTimeOffset(_fileStatus.CTime, _fileStatus.CTimeNsec);
- }
- set
- {
- // There isn't a reliable way to set this; however, we can't just do nothing since the
- // FileSystemWatcher specifically looks for this call to make a Metadata Change, so we
- // should set the LastAccessTime of the file to cause the metadata change we need.
- LastAccessTime = LastAccessTime;
- }
+ get => _fileStatus.GetCreationTime(FullPath);
+ set => _fileStatus.SetCreationTime(FullPath, value);
}
internal DateTimeOffset LastAccessTimeCore
{
- get
- {
- EnsureStatInitialized();
- if (!_exists)
- return DateTimeOffset.FromFileTime(0);
- return UnixTimeToDateTimeOffset(_fileStatus.ATime, _fileStatus.ATimeNsec);
- }
- set { SetAccessWriteTimes(value.ToUnixTimeSeconds(), null); }
+ get => _fileStatus.GetLastAccessTime(FullPath);
+ set => _fileStatus.SetLastAccessTime(FullPath, value);
}
internal DateTimeOffset LastWriteTimeCore
{
- get
- {
- EnsureStatInitialized();
- if (!_exists)
- return DateTimeOffset.FromFileTime(0);
- return UnixTimeToDateTimeOffset(_fileStatus.MTime, _fileStatus.MTimeNsec);
- }
- set { SetAccessWriteTimes(null, value.ToUnixTimeSeconds()); }
+ get => _fileStatus.GetLastWriteTime(FullPath);
+ set => _fileStatus.SetLastWriteTime(FullPath, value);
}
- private DateTimeOffset UnixTimeToDateTimeOffset(long seconds, long nanoseconds)
- {
- return DateTimeOffset.FromUnixTimeSeconds(seconds).AddTicks(nanoseconds / NanosecondsPerTick).ToLocalTime();
- }
+ internal long LengthCore => _fileStatus.GetLength(FullPath);
- private void SetAccessWriteTimes(long? accessTime, long? writeTime)
- {
- _fileStatusInitialized = -1; // force a refresh so that we have an up-to-date times for values not being overwritten
- EnsureStatInitialized();
- Interop.Sys.UTimBuf buf;
- // we use utime() not utimensat() so we drop the subsecond part
- buf.AcTime = accessTime ?? _fileStatus.ATime;
- buf.ModTime = writeTime ?? _fileStatus.MTime;
- bool isDirectory = this is DirectoryInfo;
- Interop.CheckIo(Interop.Sys.UTime(FullPath, ref buf), FullPath, isDirectory);
- _fileStatusInitialized = -1;
- }
-
- internal long LengthCore
- {
- get
- {
- EnsureStatInitialized();
- return _fileStatus.Size;
- }
- }
+ public void Refresh() => _fileStatus.Refresh(FullPath);
- public void Refresh()
+ internal static void ThrowNotFound(string path)
{
- // This should not throw, instead we store the result so that we can throw it
- // when someone actually accesses a property.
-
- // Use lstat to get the details on the object, without following symlinks.
- // If it is a symlink, then subsequently get details on the target of the symlink,
- // storing those results separately. We only report failure if the initial
- // lstat fails, as a broken symlink should still report info on exists, attributes, etc.
- _targetOfSymlinkIsDirectory = false;
- string path = PathHelpers.TrimEndingDirectorySeparator(FullPath);
- int result = Interop.Sys.LStat(path, out _fileStatus);
- if (result < 0)
- {
- Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo();
-
- // This should never set the error if the file can't be found.
- // (see the Windows refresh passing returnErrorOnNotFound: false).
- if (errorInfo.Error == Interop.Error.ENOENT
- || errorInfo.Error == Interop.Error.ENOTDIR)
- {
- _fileStatusInitialized = 0;
- _exists = false;
- }
- else
- {
- _fileStatusInitialized = errorInfo.RawErrno;
- }
- return;
- }
-
- _exists = true;
-
- Interop.Sys.FileStatus targetStatus;
- if ((_fileStatus.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFLNK &&
- Interop.Sys.Stat(path, out targetStatus) >= 0)
- {
- _targetOfSymlinkIsDirectory = (targetStatus.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFDIR;
- }
+ // Windows distinguishes between whether the directory or the file isn't found,
+ // and throws a different exception in these cases. We attempt to approximate that
+ // here; there is a race condition here, where something could change between
+ // when the error occurs and our checks, but it's the best we can do, and the
+ // worst case in such a race condition (which could occur if the file system is
+ // being manipulated concurrently with these checks) is that we throw a
+ // FileNotFoundException instead of DirectoryNotFoundException.
- _fileStatusInitialized = 0;
+ bool directoryError = !Directory.Exists(Path.GetDirectoryName(PathInternal.TrimEndingDirectorySeparator(path)));
+ throw Interop.GetExceptionForIoErrno(new Interop.ErrorInfo(Interop.Error.ENOENT), path, directoryError);
}
- private void EnsureStatInitialized()
- {
- if (_fileStatusInitialized == -1)
- {
- Refresh();
- }
-
- if (_fileStatusInitialized != 0)
- {
- int errno = _fileStatusInitialized;
- _fileStatusInitialized = -1;
- throw Interop.GetExceptionForIoErrno(new Interop.ErrorInfo(errno), FullPath);
- }
- }
+ // There is no special handling for Unix- see Windows code for the reason we do this
+ internal string NormalizedPath => FullPath;
}
}
diff --git a/src/System.IO.FileSystem/src/System/IO/FileSystemInfo.Windows.cs b/src/System.IO.FileSystem/src/System/IO/FileSystemInfo.Windows.cs
index 41e08650dd..01bd52e5e6 100644
--- a/src/System.IO.FileSystem/src/System/IO/FileSystemInfo.Windows.cs
+++ b/src/System.IO.FileSystem/src/System/IO/FileSystemInfo.Windows.cs
@@ -2,7 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Security;
+using System.Diagnostics;
+using System.IO.Enumeration;
namespace System.IO
{
@@ -13,10 +14,31 @@ namespace System.IO
// Cache any error retrieving the file/directory information
// We use this field in conjunction with the Refresh method which should never throw.
- // If we succeed we store a zero, on failure we store the HResult so that we can
+ // If we succeed we store a zero, on failure we store the error code so that we can
// throw an appropriate error when attempting to access the cached info.
private int _dataInitialized = -1;
+ protected FileSystemInfo()
+ {
+ }
+
+ internal static unsafe FileSystemInfo Create(string fullPath, ref FileSystemEntry findData)
+ {
+ FileSystemInfo info = findData.IsDirectory
+ ? (FileSystemInfo) new DirectoryInfo(fullPath, fileName: new string(findData.FileName), isNormalized: true)
+ : new FileInfo(fullPath, fileName: new string(findData.FileName), isNormalized: true);
+
+ Debug.Assert(!PathInternal.IsPartiallyQualified(fullPath), $"'{fullPath}' should be fully qualified when constructed from directory enumeration");
+
+ info.Init(findData._info);
+ return info;
+ }
+
+ internal void Invalidate()
+ {
+ _dataInitialized = -1;
+ }
+
internal unsafe void Init(Interop.NtDll.FILE_FULL_DIR_INFORMATION* info)
{
_data.dwFileAttributes = (int)info->FileAttributes;
@@ -128,5 +150,10 @@ namespace System.IO
// when someone actually accesses a property
_dataInitialized = FileSystem.FillAttributeInfo(FullPath, ref _data, returnErrorOnNotFound: false);
}
+
+ // If we're opened around a enumerated path that ends in a period or space we need to be able to
+ // act on the path normally (open streams/writers/etc.)
+ internal string NormalizedPath
+ => PathInternal.EndsWithPeriodOrSpace(FullPath) ? PathInternal.EnsureExtendedPrefix(FullPath) : FullPath;
}
}
diff --git a/src/System.IO.FileSystem/src/System/IO/FileSystemInfo.cs b/src/System.IO.FileSystem/src/System/IO/FileSystemInfo.cs
index 5d2e18e0df..9f243dd765 100644
--- a/src/System.IO.FileSystem/src/System/IO/FileSystemInfo.cs
+++ b/src/System.IO.FileSystem/src/System/IO/FileSystemInfo.cs
@@ -2,27 +2,18 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System;
-using System.Collections;
-using System.Security;
-using Microsoft.Win32;
-using System.Text;
-using System.Runtime.InteropServices;
using System.Runtime.Serialization;
-using System.Runtime.Versioning;
namespace System.IO
{
[Serializable]
public abstract partial class FileSystemInfo : MarshalByRefObject, ISerializable
{
+ // FullPath and OriginalPath are documented fields
protected string FullPath; // fully qualified path of the file or directory
protected string OriginalPath; // path passed in by the user
- private string _displayPath = ""; // path that can be displayed to the user
- protected FileSystemInfo()
- {
- }
+ internal string _name;
protected FileSystemInfo(SerializationInfo info, StreamingContext context)
{
@@ -35,19 +26,12 @@ namespace System.IO
}
// Full path of the directory/file
- public virtual string FullName
- {
- get
- {
- return FullPath;
- }
- }
+ public virtual string FullName => FullPath;
public string Extension
{
get
{
- // GetFullPathInternal would have already stripped out the terminating "." if present.
int length = FullPath.Length;
for (int i = length; --i >= 0;)
{
@@ -61,17 +45,22 @@ namespace System.IO
}
}
- // For files name of the file is returned, for directories the last directory in hierarchy is returned if possible,
- // otherwise the fully qualified name s returned
- public abstract string Name
- {
- get;
- }
+ public virtual string Name => _name;
// Whether a file/directory exists
- public abstract bool Exists
+ public virtual bool Exists
{
- get;
+ get
+ {
+ try
+ {
+ return ExistsCore;
+ }
+ catch
+ {
+ return false;
+ }
+ }
}
// Delete a file/directory
@@ -79,94 +68,44 @@ namespace System.IO
public DateTime CreationTime
{
- get
- {
- // depends on the security check in get_CreationTimeUtc
- return CreationTimeUtc.ToLocalTime();
- }
- set
- {
- CreationTimeUtc = value.ToUniversalTime();
- }
+ get => CreationTimeUtc.ToLocalTime();
+ set => CreationTimeUtc = value.ToUniversalTime();
}
public DateTime CreationTimeUtc
{
- get
- {
- return CreationTimeCore.UtcDateTime;
- }
-
- set
- {
- CreationTimeCore = File.GetUtcDateTimeOffset(value);
- }
+ get => CreationTimeCore.UtcDateTime;
+ set => CreationTimeCore = File.GetUtcDateTimeOffset(value);
}
public DateTime LastAccessTime
{
- get
- {
- // depends on the security check in get_LastAccessTimeUtc
- return LastAccessTimeUtc.ToLocalTime();
- }
- set
- {
- LastAccessTimeUtc = value.ToUniversalTime();
- }
+ get => LastAccessTimeUtc.ToLocalTime();
+ set => LastAccessTimeUtc = value.ToUniversalTime();
}
public DateTime LastAccessTimeUtc
{
- get
- {
- return LastAccessTimeCore.UtcDateTime;
- }
-
- set
- {
- LastAccessTimeCore = File.GetUtcDateTimeOffset(value);
- }
+ get => LastAccessTimeCore.UtcDateTime;
+ set => LastAccessTimeCore = File.GetUtcDateTimeOffset(value);
}
public DateTime LastWriteTime
{
- get
- {
- // depends on the security check in get_LastWriteTimeUtc
- return LastWriteTimeUtc.ToLocalTime();
- }
-
- set
- {
- LastWriteTimeUtc = value.ToUniversalTime();
- }
+ get => LastWriteTimeUtc.ToLocalTime();
+ set => LastWriteTimeUtc = value.ToUniversalTime();
}
public DateTime LastWriteTimeUtc
{
- get
- {
- return LastWriteTimeCore.UtcDateTime;
- }
-
- set
- {
- LastWriteTimeCore = File.GetUtcDateTimeOffset(value);
- }
+ get => LastWriteTimeCore.UtcDateTime;
+ set => LastWriteTimeCore = File.GetUtcDateTimeOffset(value);
}
- internal string DisplayPath
- {
- get
- {
- return _displayPath;
- }
- set
- {
- _displayPath = value;
- }
- }
+ /// <summary>
+ /// Returns the original path. Use FullName or Name properties for the full path or file/directory name.
+ /// </summary>
+ public override string ToString() => OriginalPath ?? string.Empty;
}
}
diff --git a/src/System.IO.FileSystem/src/System/IO/FindEnumerable.Win32.cs b/src/System.IO.FileSystem/src/System/IO/FindEnumerable.Win32.cs
deleted file mode 100644
index a978d7cb85..0000000000
--- a/src/System.IO.FileSystem/src/System/IO/FindEnumerable.Win32.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-using System.Runtime.CompilerServices;
-
-namespace System.IO
-{
- internal partial class FindEnumerable<TResult, TState>
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public unsafe bool GetData()
- {
- Debug.Assert(_directoryHandle != (IntPtr)(-1) && _directoryHandle != IntPtr.Zero && !_lastEntryFound);
-
- int status = Interop.NtDll.NtQueryDirectoryFile(
- FileHandle: _directoryHandle,
- Event: IntPtr.Zero,
- ApcRoutine: IntPtr.Zero,
- ApcContext: IntPtr.Zero,
- IoStatusBlock: out Interop.NtDll.IO_STATUS_BLOCK statusBlock,
- FileInformation: _buffer,
- Length: (uint)_buffer.Length,
- FileInformationClass: Interop.NtDll.FILE_INFORMATION_CLASS.FileFullDirectoryInformation,
- ReturnSingleEntry: Interop.BOOLEAN.FALSE,
- FileName: null,
- RestartScan: Interop.BOOLEAN.FALSE);
-
- switch ((uint)status)
- {
- case Interop.StatusOptions.STATUS_NO_MORE_FILES:
- DirectoryFinished();
- return false;
- case Interop.StatusOptions.STATUS_SUCCESS:
- Debug.Assert(statusBlock.Information.ToInt64() != 0);
- return true;
- default:
- throw Win32Marshal.GetExceptionForWin32Error((int)Interop.NtDll.RtlNtStatusToDosError(status), _currentPath);
- }
- }
- }
-}
diff --git a/src/System.IO.FileSystem/src/System/IO/FindEnumerable.Windows.cs b/src/System.IO.FileSystem/src/System/IO/FindEnumerable.Windows.cs
deleted file mode 100644
index 7e64e97373..0000000000
--- a/src/System.IO.FileSystem/src/System/IO/FindEnumerable.Windows.cs
+++ /dev/null
@@ -1,251 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Buffers;
-using System.Collections;
-using System.Collections.Generic;
-using System.Runtime.CompilerServices;
-using System.Runtime.ConstrainedExecution;
-using System.Runtime.InteropServices;
-using System.Threading;
-
-namespace System.IO
-{
- internal unsafe partial class FindEnumerable<TResult, TState> : CriticalFinalizerObject, IEnumerable<TResult>, IEnumerator<TResult>
- {
- private readonly string _originalFullPath;
- private readonly string _originalUserPath;
- private readonly bool _recursive;
- private readonly FindTransform<TResult> _transform;
- private readonly FindPredicate<TState> _predicate;
- private readonly TState _state;
-
- private object _lock = new object();
- private int _enumeratorCreated;
-
- private Interop.NtDll.FILE_FULL_DIR_INFORMATION* _info;
- private TResult _current;
-
- private byte[] _buffer;
- private IntPtr _directoryHandle;
- private string _currentPath;
- private bool _lastEntryFound;
- private Queue<(IntPtr Handle, string Path)> _pending;
- private GCHandle _pinnedBuffer;
-
- /// <summary>
- /// Encapsulates a find operation.
- /// </summary>
- /// <param name="directory">The directory to search in.</param>
- public FindEnumerable(
- string directory,
- FindTransform<TResult> transform,
- FindPredicate<TState> predicate,
- TState state = default,
- bool recursive = false)
- {
- _originalUserPath = directory;
- _originalFullPath = Path.GetFullPath(directory);
- _recursive = recursive;
- _predicate = predicate ?? throw new ArgumentNullException(nameof(predicate));
- _transform = transform ?? throw new ArgumentNullException(nameof(transform));
- _state = state;
- Initialize();
- }
-
- private FindEnumerable(
- string originalUserPath,
- string originalFullPath,
- FindTransform<TResult> transform,
- FindPredicate<TState> predicate,
- TState state,
- bool recursive)
- {
- _originalUserPath = originalUserPath;
- _originalFullPath = originalFullPath;
- _predicate = predicate;
- _transform = transform;
- _state = state;
- _recursive = recursive;
- Initialize();
- }
-
- /// <summary>
- /// Simple wrapper to allow creating a file handle for an existing directory.
- /// </summary>
- public static IntPtr CreateDirectoryHandle(string path)
- {
- IntPtr handle = Interop.Kernel32.CreateFile_IntPtr(
- path,
- Interop.Kernel32.FileOperations.FILE_LIST_DIRECTORY,
- FileShare.ReadWrite | FileShare.Delete,
- FileMode.Open,
- Interop.Kernel32.FileOperations.FILE_FLAG_BACKUP_SEMANTICS);
-
- if (handle == IntPtr.Zero || handle == (IntPtr)(-1))
- {
- // Historically we throw directory not found rather than file not found
- int error = Marshal.GetLastWin32Error();
- if (error == Interop.Errors.ERROR_FILE_NOT_FOUND)
- error = Interop.Errors.ERROR_PATH_NOT_FOUND;
-
- throw Win32Marshal.GetExceptionForWin32Error(error, path);
- }
-
- return handle;
- }
-
- public IEnumerator<TResult> GetEnumerator()
- {
- if (Interlocked.Exchange(ref _enumeratorCreated, 1) == 0)
- {
- return this;
- }
- else
- {
- return new FindEnumerable<TResult, TState>(_originalUserPath, _originalFullPath, _transform, _predicate, _state, _recursive);
- }
- }
-
- private void Initialize()
- {
- _currentPath = _originalFullPath;
- _buffer = ArrayPool<byte>.Shared.Rent(4096);
- _pinnedBuffer = GCHandle.Alloc(_buffer, GCHandleType.Pinned);
- if (_recursive)
- _pending = new Queue<(IntPtr, string)>();
- _directoryHandle = CreateDirectoryHandle(_originalFullPath);
- }
-
- IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
-
- public TResult Current => _current;
-
- object IEnumerator.Current => Current;
-
- public bool MoveNext()
- {
- if (_lastEntryFound)
- return false;
-
- lock (_lock)
- {
- if (_lastEntryFound)
- return false;
-
- RawFindData findData = default;
- do
- {
- FindNextFile();
- if (!_lastEntryFound && _info != null)
- {
- // If needed, stash any subdirectories to process later
- if (_recursive && (_info->FileAttributes & FileAttributes.Directory) != 0
- && !PathHelpers.IsDotOrDotDot(_info->FileName))
- {
- string subDirectory = PathHelpers.CombineNoChecks(_currentPath, _info->FileName);
- IntPtr subDirectoryHandle = CreateDirectoryHandle(subDirectory);
- try
- {
- // It is possible this might allocate and run out of memory
- _pending.Enqueue((subDirectoryHandle, subDirectory));
- }
- catch
- {
- Interop.Kernel32.CloseHandle(subDirectoryHandle);
- throw;
- }
- }
-
- findData = new RawFindData(_info, _currentPath, _originalFullPath, _originalUserPath);
- }
- } while (!_lastEntryFound && !_predicate(ref findData, _state));
-
- if (!_lastEntryFound)
- _current = _transform(ref findData);
-
- return !_lastEntryFound;
- }
- }
-
- private unsafe void FindNextFile()
- {
- Interop.NtDll.FILE_FULL_DIR_INFORMATION* info = _info;
- if (info != null && info->NextEntryOffset != 0)
- {
- // We're already in a buffer and have another entry
- _info = (Interop.NtDll.FILE_FULL_DIR_INFORMATION*)((byte*)info + info->NextEntryOffset);
- return;
- }
-
- // We need more data
- if (GetData())
- _info = (Interop.NtDll.FILE_FULL_DIR_INFORMATION*)_pinnedBuffer.AddrOfPinnedObject();
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void DirectoryFinished()
- {
- _info = null;
- if (_pending == null || _pending.Count == 0)
- {
- _lastEntryFound = true;
- }
- else
- {
- // Grab the next directory to parse
- Interop.Kernel32.CloseHandle(_directoryHandle);
- (_directoryHandle, _currentPath) = _pending.Dequeue();
- FindNextFile();
- }
- }
-
- public void Reset()
- {
- throw new NotSupportedException();
- }
-
- public void Dispose()
- {
- Dispose(disposing: true);
- GC.SuppressFinalize(this);
- }
-
- protected void Dispose(bool disposing)
- {
- // It is possible to fail to allocate the lock, but the finalizer will still run
- if (_lock != null)
- {
- lock (_lock)
- {
- _lastEntryFound = true;
-
- // Don't ever close a valid handle twice as they can be reused- set to zero to ensure this
- Interop.Kernel32.CloseHandle(_directoryHandle);
- _directoryHandle = IntPtr.Zero;
-
- if (_recursive && _pending != null)
- {
- while (_pending.Count > 0)
- Interop.Kernel32.CloseHandle(_pending.Dequeue().Handle);
- _pending = null;
- }
-
- if (_pinnedBuffer.IsAllocated)
- _pinnedBuffer.Free();
-
- if (_buffer != null)
- ArrayPool<byte>.Shared.Return(_buffer);
-
- _buffer = null;
- }
- }
- }
-
- ~FindEnumerable()
- {
- Dispose(disposing: false);
- }
- }
-}
diff --git a/src/System.IO.FileSystem/src/System/IO/FindEnumerableFactory.cs b/src/System.IO.FileSystem/src/System/IO/FindEnumerableFactory.cs
deleted file mode 100644
index 1202ac7372..0000000000
--- a/src/System.IO.FileSystem/src/System/IO/FindEnumerableFactory.cs
+++ /dev/null
@@ -1,138 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-namespace System.IO
-{
- internal static class FindEnumerableFactory
- {
- internal static void NormalizeInputs(ref string directory, ref string expression)
- {
- if (PathHelpers.IsPathRooted(expression))
- throw new ArgumentException(SR.Arg_Path2IsRooted, nameof(expression));
-
- // We always allowed breaking the passed in directory and filter to be separated
- // any way the user wanted. Looking for "C:\foo\*.cs" could be passed as "C:\" and
- // "foo\*.cs" or "C:\foo" and "*.cs", for example. As such we need to combine and
- // split the inputs if the expression contains a directory separator.
- //
- // We also allowed for expression to be "foo\" which would translate to "foo\*".
-
- ReadOnlySpan<char> directoryName = PathHelpers.GetDirectoryNameNoChecks(expression.AsReadOnlySpan());
-
- if (directoryName.Length != 0)
- {
- // Need to fix up the input paths
- directory = PathHelpers.CombineNoChecks(directory, directoryName);
- expression = expression.Substring(directoryName.Length + 1);
- }
-
- // Historically we always treated "." as "*"
- if (string.IsNullOrEmpty(expression) || expression == "." || expression == "*.*")
- expression = "*";
- }
-
- internal static FindEnumerable<string, string> UserFiles(string directory,
- string expression = "*",
- bool recursive = false)
- {
- return new FindEnumerable<string, string>(
- directory,
- (ref RawFindData findData) => FindTransforms.AsUserFullPath(ref findData),
- (ref RawFindData findData, string expr) =>
- {
- return FindPredicates.NotDotOrDotDot(ref findData)
- && !FindPredicates.IsDirectory(ref findData)
- && DosMatcher.MatchPattern(expr, findData.FileName, ignoreCase: true);
- },
- DosMatcher.TranslateExpression(expression),
- recursive);
- }
-
- internal static FindEnumerable<string, string> UserDirectories(string directory,
- string expression = "*",
- bool recursive = false)
- {
- return new FindEnumerable<string, string>(
- directory,
- (ref RawFindData findData) => FindTransforms.AsUserFullPath(ref findData),
- (ref RawFindData findData, string expr) =>
- {
- return FindPredicates.NotDotOrDotDot(ref findData)
- && FindPredicates.IsDirectory(ref findData)
- && DosMatcher.MatchPattern(expr, findData.FileName, ignoreCase: true);
- },
- DosMatcher.TranslateExpression(expression),
- recursive);
- }
-
- internal static FindEnumerable<string, string> UserEntries(string directory,
- string expression = "*",
- bool recursive = false)
- {
- return new FindEnumerable<string, string>(
- directory,
- (ref RawFindData findData) => FindTransforms.AsUserFullPath(ref findData),
- (ref RawFindData findData, string expr) =>
- {
- return FindPredicates.NotDotOrDotDot(ref findData)
- && DosMatcher.MatchPattern(expr, findData.FileName, ignoreCase: true);
- },
- DosMatcher.TranslateExpression(expression),
- recursive);
- }
-
- internal static FindEnumerable<FileInfo, string> FileInfos(
- string directory,
- string expression = "*",
- bool recursive = false)
- {
- return new FindEnumerable<FileInfo, string>(
- directory,
- (ref RawFindData findData) => FindTransforms.AsFileInfo(ref findData),
- (ref RawFindData findData, string expr) =>
- {
- return FindPredicates.NotDotOrDotDot(ref findData)
- && !FindPredicates.IsDirectory(ref findData)
- && DosMatcher.MatchPattern(expr, findData.FileName, ignoreCase: true);
- },
- DosMatcher.TranslateExpression(expression),
- recursive);
- }
-
- internal static FindEnumerable<DirectoryInfo, string> DirectoryInfos(
- string directory,
- string expression = "*",
- bool recursive = false)
- {
- return new FindEnumerable<DirectoryInfo, string>(
- directory,
- (ref RawFindData findData) => FindTransforms.AsDirectoryInfo(ref findData),
- (ref RawFindData findData, string expr) =>
- {
- return FindPredicates.NotDotOrDotDot(ref findData)
- && FindPredicates.IsDirectory(ref findData)
- && DosMatcher.MatchPattern(expr, findData.FileName, ignoreCase: true);
- },
- DosMatcher.TranslateExpression(expression),
- recursive);
- }
-
- internal static FindEnumerable<FileSystemInfo, string> FileSystemInfos(
- string directory,
- string expression = "*",
- bool recursive = false)
- {
- return new FindEnumerable<FileSystemInfo, string>(
- directory,
- (ref RawFindData findData) => FindTransforms.AsFileSystemInfo(ref findData),
- (ref RawFindData findData, string expr) =>
- {
- return FindPredicates.NotDotOrDotDot(ref findData)
- && DosMatcher.MatchPattern(expr, findData.FileName, ignoreCase: true);
- },
- DosMatcher.TranslateExpression(expression),
- recursive);
- }
- }
-}
diff --git a/src/System.IO.FileSystem/src/System/IO/FindPredicate.cs b/src/System.IO.FileSystem/src/System/IO/FindPredicate.cs
deleted file mode 100644
index 2e52eda3db..0000000000
--- a/src/System.IO.FileSystem/src/System/IO/FindPredicate.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-namespace System.IO
-{
- /// <summary>
- /// Interface for filtering out find results.
- /// </summary>
- internal delegate bool FindPredicate<TState>(ref RawFindData findData, TState state);
-}
diff --git a/src/System.IO.FileSystem/src/System/IO/FindPredicates.cs b/src/System.IO.FileSystem/src/System/IO/FindPredicates.cs
deleted file mode 100644
index 9d90aed377..0000000000
--- a/src/System.IO.FileSystem/src/System/IO/FindPredicates.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-namespace System.IO
-{
- internal static partial class FindPredicates
- {
- internal static bool NotDotOrDotDot(ref RawFindData findData) => !PathHelpers.IsDotOrDotDot(findData.FileName);
-
- internal static bool IsDirectory(ref RawFindData findData)
- {
- FileAttributes attributes = findData.Attributes;
- return attributes != (FileAttributes)(-1)
- && (attributes & FileAttributes.Directory) != 0;
- }
- }
-}
diff --git a/src/System.IO.FileSystem/src/System/IO/FindTransforms.cs b/src/System.IO.FileSystem/src/System/IO/FindTransforms.cs
deleted file mode 100644
index db0590a35e..0000000000
--- a/src/System.IO.FileSystem/src/System/IO/FindTransforms.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-namespace System.IO
-{
- internal static partial class FindTransforms
- {
- internal static DirectoryInfo AsDirectoryInfo(ref RawFindData findData)
- {
- string fileName = new string(findData.FileName);
- return new DirectoryInfo(PathHelpers.CombineNoChecks(findData.Directory, fileName), fileName, ref findData);
- }
-
- internal static FileInfo AsFileInfo(ref RawFindData findData)
- {
- string fileName = new string(findData.FileName);
- return new FileInfo(PathHelpers.CombineNoChecks(findData.Directory, fileName), fileName, ref findData);
- }
-
- internal static FileSystemInfo AsFileSystemInfo(ref RawFindData findData)
- {
- string fileName = new string(findData.FileName);
- string fullPath = PathHelpers.CombineNoChecks(findData.Directory, fileName);
-
- return (findData.Attributes & FileAttributes.Directory) != 0
- ? (FileSystemInfo)new DirectoryInfo(fullPath, fileName, ref findData)
- : (FileSystemInfo)new FileInfo(fullPath, fileName, ref findData);
- }
-
- /// <summary>
- /// Returns the full path for find results, based off of the initially provided path.
- /// </summary>
- internal static string AsUserFullPath(ref RawFindData findData)
- {
- ReadOnlySpan<char> subdirectory = findData.Directory.AsReadOnlySpan().Slice(findData.OriginalDirectory.Length);
- return PathHelpers.CombineNoChecks(findData.OriginalUserDirectory, subdirectory, findData.FileName);
- }
- }
-}
diff --git a/src/System.IO.FileSystem/src/System/IO/MatchCasing.cs b/src/System.IO.FileSystem/src/System/IO/MatchCasing.cs
new file mode 100644
index 0000000000..d8dfbfcc36
--- /dev/null
+++ b/src/System.IO.FileSystem/src/System/IO/MatchCasing.cs
@@ -0,0 +1,24 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.IO
+{
+ public enum MatchCasing
+ {
+ /// <summary>
+ /// Match the default casing for the given platform
+ /// </summary>
+ PlatformDefault,
+
+ /// <summary>
+ /// Match respecting character casing
+ /// </summary>
+ CaseSensitive,
+
+ /// <summary>
+ /// Match ignoring character casing
+ /// </summary>
+ CaseInsensitive
+ }
+}
diff --git a/src/System.IO.FileSystem/src/System/IO/MatchType.cs b/src/System.IO.FileSystem/src/System/IO/MatchType.cs
new file mode 100644
index 0000000000..0bdf89b3c7
--- /dev/null
+++ b/src/System.IO.FileSystem/src/System/IO/MatchType.cs
@@ -0,0 +1,20 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.IO
+{
+ public enum MatchType
+ {
+ /// <summary>
+ /// Match using '*' and '?' wildcards.
+ /// </summary>
+ Simple,
+
+ /// <summary>
+ /// Match using Win32 DOS style matching semantics. '*', '?', '&lt;', '&gt;', and '"'
+ /// are all considered wildcards.
+ /// </summary>
+ Win32
+ }
+}
diff --git a/src/System.IO.FileSystem/src/System/IO/PathHelpers.Unix.cs b/src/System.IO.FileSystem/src/System/IO/PathHelpers.Unix.cs
deleted file mode 100644
index 47dcd9b46d..0000000000
--- a/src/System.IO.FileSystem/src/System/IO/PathHelpers.Unix.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-namespace System.IO
-{
- internal static partial class PathHelpers
- {
- internal static bool ShouldReviseDirectoryPathToCurrent(string path)
- {
- // Unlike on Windows, there are no special cases on Unix where we'd want to ignore
- // user-provided path and instead automatically use the current directory.
- return false;
- }
-
- internal static string TrimEndingDirectorySeparator(string path) =>
- path.Length > 1 && PathInternal.IsDirectorySeparator(path[path.Length - 1]) ? // exclude root "/"
- path.Substring(0, path.Length - 1) :
- path;
- }
-}
diff --git a/src/System.IO.FileSystem/src/System/IO/PathHelpers.Windows.cs b/src/System.IO.FileSystem/src/System/IO/PathHelpers.Windows.cs
deleted file mode 100644
index 990527577b..0000000000
--- a/src/System.IO.FileSystem/src/System/IO/PathHelpers.Windows.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Runtime.InteropServices;
-
-namespace System.IO
-{
- internal static partial class PathInternal
- {
- internal static unsafe int GetRootLength(ReadOnlySpan<char> path)
- {
- fixed (char* p = &MemoryMarshal.GetReference(path))
- {
- return (int)GetRootLength(p, (uint)path.Length);
- }
- }
- }
-
- internal static partial class PathHelpers
- {
- internal static bool ShouldReviseDirectoryPathToCurrent(string path)
- {
- // In situations where this method is invoked, "<DriveLetter>:" should be special-cased
- // to instead go to the current directory.
- return path != null && path.Length == 2 && path[1] == ':';
- }
-
- internal static string TrimEndingDirectorySeparator(string path) =>
- EndsInDirectorySeparator(path) ?
- path.Substring(0, path.Length - 1) :
- path;
-
- public static bool IsPathRooted(string path)
- {
- // Want to avoid PathInternal.CheckInvalidPathChars on Path.IsPathRooted
-
- if (path != null)
- {
- int length = path.Length;
- if ((length >= 1 && PathInternal.IsDirectorySeparator(path[0])) ||
- (length >= 2 && PathInternal.IsValidDriveChar(path[0]) && path[1] == Path.VolumeSeparatorChar))
- return true;
- }
- return false;
- }
- }
-}
diff --git a/src/System.IO.FileSystem/src/System/IO/PathHelpers.cs b/src/System.IO.FileSystem/src/System/IO/PathHelpers.cs
deleted file mode 100644
index dc574c7833..0000000000
--- a/src/System.IO.FileSystem/src/System/IO/PathHelpers.cs
+++ /dev/null
@@ -1,192 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-namespace System.IO
-{
- // Helper methods related to paths. Some of these are copies of
- // internal members of System.IO.Path from System.Runtime.Extensions.dll.
- internal static partial class PathHelpers
- {
- // Array of the separator chars
- internal static readonly char[] DirectorySeparatorChars = new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar };
-
- // string-representation of the directory-separator character, used when appending the character to another
- // string so as to avoid the boxing of the character when calling string.Concat(..., object).
- internal static readonly string DirectorySeparatorCharAsString = Path.DirectorySeparatorChar.ToString();
-
- // System.IO.Path has both public Combine and internal InternalCombine
- // members. InternalCombine performs these extra validations on the second
- // argument. This provides a convenient helper to maintain this extra
- // validation when porting code from Path.InternalCombine to Path.Combine.
- internal static void ThrowIfEmptyOrRootedPath(string path2)
- {
- if (path2 == null)
- throw new ArgumentNullException(nameof(path2));
- if (path2.Length == 0)
- throw new ArgumentException(SR.Argument_PathEmpty, nameof(path2));
- if (Path.IsPathRooted(path2))
- throw new ArgumentException(SR.Arg_Path2IsRooted, nameof(path2));
- }
-
- internal static bool IsRoot(string path)
- {
- return path.Length == PathInternal.GetRootLength(path);
- }
-
- internal static bool EndsInDirectorySeparator(string path)
- {
- return path.Length > 0 && PathInternal.IsDirectorySeparator(path[path.Length - 1]);
- }
-
- /// <summary>
- /// Combines two paths. Does no validation of paths, only concatenates the paths
- /// and places a directory separator between them if needed.
- /// </summary>
- internal static string CombineNoChecks(string first, ReadOnlySpan<char> second)
- {
- if (string.IsNullOrEmpty(first))
- return second.Length == 0
- ? string.Empty
- : new string(second);
-
- if (second.Length == 0)
- return first;
-
- return CombineNoChecksInternal(first.AsReadOnlySpan(), second);
- }
-
- /// <summary>
- /// Combines two paths. Does no validation of paths, only concatenates the paths
- /// and places a directory separator between them if needed.
- /// </summary>
- internal static string CombineNoChecks(ReadOnlySpan<char> first, ReadOnlySpan<char> second)
- {
- if (first.Length == 0)
- return second.Length == 0
- ? string.Empty
- : new string(second);
-
- if (second.Length == 0)
- return new string(first);
-
- return CombineNoChecksInternal(first, second);
- }
-
- /// <summary>
- /// Combines three paths. Does no validation of paths, only concatenates the paths
- /// and places a directory separator between them if needed.
- /// </summary>
- internal static string CombineNoChecks(string first, ReadOnlySpan<char> second, ReadOnlySpan<char> third)
- {
- if (string.IsNullOrEmpty(first))
- return CombineNoChecks(second, third);
-
- if (second.Length == 0)
- return CombineNoChecks(first, third);
-
- if (third.Length == 0)
- return CombineNoChecks(first, second);
-
- return CombineNoChecksInternal(first.AsReadOnlySpan(), second, third);
- }
-
- /// <summary>
- /// Combines two paths. Does no validation of paths, only concatenates the paths
- /// and places a directory separator between them if needed.
- /// </summary>
- internal unsafe static string CombineNoChecks(string first, string second)
- {
- if (string.IsNullOrEmpty(first))
- return string.IsNullOrEmpty(second) ? string.Empty : second;
-
- if (string.IsNullOrEmpty(second))
- return first;
-
- return CombineNoChecksInternal(first.AsReadOnlySpan(), second.AsReadOnlySpan());
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private unsafe static string CombineNoChecksInternal(ReadOnlySpan<char> first, ReadOnlySpan<char> second)
- {
- Debug.Assert(first.Length > 0 && second.Length > 0, "should have dealt with empty paths");
-
- bool hasSeparator = PathInternal.IsDirectorySeparator(first[first.Length - 1])
- || PathInternal.IsDirectorySeparator(second[0]);
-
- fixed (char* f = &MemoryMarshal.GetReference(first), s = &MemoryMarshal.GetReference(second))
- {
- return string.Create(
- first.Length + second.Length + (hasSeparator ? 0 : 1),
- (First: (IntPtr)f, FirstLength: first.Length, Second: (IntPtr)s, SecondLength: second.Length, HasSeparator: hasSeparator),
- (destination, state) =>
- {
- new Span<char>((char*)state.First, state.FirstLength).CopyTo(destination);
- if (!state.HasSeparator)
- destination[state.FirstLength] = Path.DirectorySeparatorChar;
- new Span<char>((char*)state.Second, state.SecondLength).CopyTo(destination.Slice(state.FirstLength + (state.HasSeparator ? 0 : 1)));
- });
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private unsafe static string CombineNoChecksInternal(ReadOnlySpan<char> first, ReadOnlySpan<char> second, ReadOnlySpan<char> third)
- {
- Debug.Assert(first.Length > 0 && second.Length > 0 && third.Length > 0, "should have dealt with empty paths");
-
- bool firstHasSeparator = PathInternal.IsDirectorySeparator(first[first.Length - 1])
- || PathInternal.IsDirectorySeparator(second[0]);
- bool thirdHasSeparator = PathInternal.IsDirectorySeparator(second[second.Length - 1])
- || PathInternal.IsDirectorySeparator(third[0]);
-
- fixed (char* f = &MemoryMarshal.GetReference(first), s = &MemoryMarshal.GetReference(second), t = &MemoryMarshal.GetReference(third))
- {
- return string.Create(
- first.Length + second.Length + third.Length + (firstHasSeparator ? 0 : 1) + (thirdHasSeparator ? 0 : 1),
- (First: (IntPtr)f, FirstLength: first.Length, Second: (IntPtr)s, SecondLength: second.Length,
- Third: (IntPtr)t, ThirdLength: third.Length, FirstHasSeparator: firstHasSeparator, ThirdHasSeparator: thirdHasSeparator),
- (destination, state) =>
- {
- new Span<char>((char*)state.First, state.FirstLength).CopyTo(destination);
- if (!state.FirstHasSeparator)
- destination[state.FirstLength] = Path.DirectorySeparatorChar;
- new Span<char>((char*)state.Second, state.SecondLength).CopyTo(destination.Slice(state.FirstLength + (state.FirstHasSeparator ? 0 : 1)));
- if (!state.ThirdHasSeparator)
- destination[destination.Length - state.ThirdLength - 1] = Path.DirectorySeparatorChar;
- new Span<char>((char*)state.Third, state.ThirdLength).CopyTo(destination.Slice(destination.Length - state.ThirdLength));
- });
- }
- }
-
- /// <summary>
- /// Returns true if the file name is "." or ".."
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static unsafe bool IsDotOrDotDot(ReadOnlySpan<char> fileName)
- {
- return !(fileName.Length > 2
- || fileName[0] != '.'
- || (fileName.Length == 2 && fileName[1] != '.'));
- }
-
- public static ReadOnlySpan<char> GetDirectoryNameNoChecks(ReadOnlySpan<char> path)
- {
- if (path.Length == 0)
- return ReadOnlySpan<char>.Empty;
-
- int root = PathInternal.GetRootLength(path);
- int i = path.Length;
- if (i > root)
- {
- while (i > root && !PathInternal.IsDirectorySeparator(path[--i])) ;
- return path.Slice(0, i);
- }
-
- return ReadOnlySpan<char>.Empty;
- }
- }
-}
diff --git a/src/System.IO.FileSystem/src/System/IO/PathPair.cs b/src/System.IO.FileSystem/src/System/IO/PathPair.cs
deleted file mode 100644
index dfef1bcc11..0000000000
--- a/src/System.IO.FileSystem/src/System/IO/PathPair.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-namespace System.IO
-{
- internal readonly struct PathPair
- {
- internal readonly string UserPath;
- internal readonly string FullPath;
-
- internal PathPair(string userPath, string fullPath)
- {
- UserPath = userPath;
- FullPath = fullPath;
- }
- }
-}
diff --git a/src/System.IO.FileSystem/src/System/IO/RawFindData.cs b/src/System.IO.FileSystem/src/System/IO/RawFindData.cs
deleted file mode 100644
index 2f8ab43e42..0000000000
--- a/src/System.IO.FileSystem/src/System/IO/RawFindData.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-namespace System.IO
-{
- /// <summary>
- /// Used for processing and filtering find results.
- /// </summary>
- internal unsafe ref struct RawFindData
- {
- internal RawFindData(Interop.NtDll.FILE_FULL_DIR_INFORMATION* info, string directory, string originalDirectory, string originalUserDirectory)
- {
- _info = info;
- Directory = directory;
- OriginalDirectory = originalDirectory;
- OriginalUserDirectory = originalUserDirectory;
- }
-
- internal unsafe Interop.NtDll.FILE_FULL_DIR_INFORMATION* _info;
- public string Directory { get; private set; }
- public string OriginalDirectory { get; private set; }
- public string OriginalUserDirectory { get; private set; }
-
- public ReadOnlySpan<char> FileName => _info->FileName;
- public FileAttributes Attributes => _info->FileAttributes;
- public long Length => _info->EndOfFile;
-
- public DateTime CreationTimeUtc => _info->CreationTime.ToDateTimeUtc();
- public DateTime LastAccessTimeUtc => _info->LastAccessTime.ToDateTimeUtc();
- public DateTime LastWriteTimeUtc => _info->LastWriteTime.ToDateTimeUtc();
- }
-}
diff --git a/src/System.IO.FileSystem/tests/Base/BaseGetSetTimes.cs b/src/System.IO.FileSystem/tests/Base/BaseGetSetTimes.cs
index f650ae07f3..865cde2ad8 100644
--- a/src/System.IO.FileSystem/tests/Base/BaseGetSetTimes.cs
+++ b/src/System.IO.FileSystem/tests/Base/BaseGetSetTimes.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
+using System.Threading;
using Xunit;
namespace System.IO.Tests
@@ -15,6 +16,8 @@ namespace System.IO.Tests
public abstract T GetExistingItem();
public abstract T GetMissingItem();
+ public abstract string GetItemPath(T item);
+
public abstract IEnumerable<TimeFunction> TimeFunctions(bool requiresRoundtripping = false);
public class TimeFunction : Tuple<SetTime, GetTime, DateTimeKind>
@@ -68,19 +71,35 @@ namespace System.IO.Tests
}
[Fact]
- [ActiveIssue(26349, TestPlatforms.AnyUnix)]
- public void TimesIncludeMillisecondPart()
+ [PlatformSpecific(TestPlatforms.Linux)] // Windows tested below, and OSX does not currently support millisec granularity
+ public void TimesIncludeMillisecondPart_Linux()
{
T item = GetExistingItem();
+
+ string driveFormat = new DriveInfo(GetItemPath(item)).DriveFormat;
+
Assert.All(TimeFunctions(), (function) =>
{
var msec = 0;
- for (int i = 0; i < 3; i++)
+ for (int i = 0; i < 5; i++)
{
- msec = function.Getter(item).Millisecond;
+ DateTime time = function.Getter(item);
+ msec = time.Millisecond;
+
if (msec != 0)
break;
+ // This case should only happen 1/1000 times, unless the OS/Filesystem does
+ // not support millisecond granularity.
+
+ // If it's 1/1000, or low granularity, this may help:
+ Thread.Sleep(1234);
+
+ // If it's the OS/Filesystem often returns 0 for the millisecond part, this may
+ // help prove it. This should only be written 1/1000 runs, unless the test is going to
+ // fail.
+ Console.WriteLine($"## TimesIncludeMillisecondPart got a file time of {time.ToString("o")} on {driveFormat}");
+
item = GetExistingItem(); // try a new file/directory
}
@@ -88,6 +107,49 @@ namespace System.IO.Tests
});
}
+
+ [Fact]
+ [PlatformSpecific(TestPlatforms.Windows)] // Breaking out Windows as it passes no problem there
+ public void TimesIncludeMillisecondPart_Windows()
+ {
+ T item = GetExistingItem();
+ Assert.All(TimeFunctions(), (function) =>
+ {
+ var msec = 0;
+ for (int i = 0; i < 5; i++)
+ {
+ DateTime time = function.Getter(item);
+ msec = time.Millisecond;
+ if (msec != 0)
+ break;
+
+ // This case should only happen 1/1000 times, unless the OS/Filesystem does
+ // not support millisecond granularity.
+
+ // If it's 1/1000, or low granularity, this may help:
+ Thread.Sleep(1234);
+
+ item = GetExistingItem(); // try a new file/directory
+ }
+
+ Assert.NotEqual(0, msec);
+ });
+ }
+
+ [Fact]
+ // OSX does not currently support millisec granularity: use this test as a canary to flag
+ // if this ever changes so we can enable the actual test
+ [PlatformSpecific(TestPlatforms.OSX)]
+ public void TimesIncludeMillisecondPart_OSX()
+ {
+ T item = GetExistingItem();
+ Assert.All(TimeFunctions(), (function) =>
+ {
+ DateTime time = function.Getter(item);
+ Assert.Equal(0, time.Millisecond);
+ });
+ }
+
protected void ValidateSetTimes(T item, DateTime beforeTime, DateTime afterTime)
{
Assert.All(TimeFunctions(), (function) =>
diff --git a/src/System.IO.FileSystem/tests/Base/FileGetSetAttributes.cs b/src/System.IO.FileSystem/tests/Base/FileGetSetAttributes.cs
index bdb4cee984..59d784fbe9 100644
--- a/src/System.IO.FileSystem/tests/Base/FileGetSetAttributes.cs
+++ b/src/System.IO.FileSystem/tests/Base/FileGetSetAttributes.cs
@@ -12,12 +12,12 @@ namespace System.IO.Tests
[Theory]
[InlineData(FileAttributes.ReadOnly)]
[InlineData(FileAttributes.Normal)]
- [PlatformSpecific(TestPlatforms.AnyUnix)] // Unix valid file attributes
- public void UnixAttributeSetting(FileAttributes attr)
+ [PlatformSpecific(TestPlatforms.AnyUnix)]
+ public void SettingAttributes_Unix(FileAttributes attributes)
{
string path = CreateItem();
- SetAttributes(path, attr);
- Assert.Equal(attr, GetAttributes(path));
+ SetAttributes(path, attributes);
+ Assert.Equal(attributes, GetAttributes(path));
SetAttributes(path, 0);
}
@@ -29,12 +29,12 @@ namespace System.IO.Tests
[InlineData(FileAttributes.Normal)]
[InlineData(FileAttributes.Temporary)]
[InlineData(FileAttributes.ReadOnly | FileAttributes.Hidden)]
- [PlatformSpecific(TestPlatforms.Windows)] // Valid Windows file attribute
- public void WindowsAttributeSetting(FileAttributes attr)
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void SettingAttributes_Windows(FileAttributes attributes)
{
string path = CreateItem();
- SetAttributes(path, attr);
- Assert.Equal(attr, GetAttributes(path));
+ SetAttributes(path, attributes);
+ Assert.Equal(attributes, GetAttributes(path));
SetAttributes(path, 0);
}
@@ -44,11 +44,11 @@ namespace System.IO.Tests
[InlineData(FileAttributes.SparseFile)]
[InlineData(FileAttributes.ReparsePoint)]
[InlineData(FileAttributes.Compressed)]
- [PlatformSpecific(TestPlatforms.AnyUnix)] // Unix invalid file attributes
- public void UnixInvalidAttributes(FileAttributes attr)
+ [PlatformSpecific(TestPlatforms.AnyUnix)]
+ public void SettingInvalidAttributes_Unix(FileAttributes attributes)
{
string path = CreateItem();
- SetAttributes(path, attr);
+ SetAttributes(path, attributes);
Assert.Equal(FileAttributes.Normal, GetAttributes(path));
}
@@ -58,11 +58,36 @@ namespace System.IO.Tests
[InlineData(FileAttributes.SparseFile)]
[InlineData(FileAttributes.ReparsePoint)]
[InlineData(FileAttributes.Compressed)]
- [PlatformSpecific(TestPlatforms.Windows)] // Invalid Windows file attributes
- public void WindowsInvalidAttributes(FileAttributes attr)
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void SettingInvalidAttributes_Windows(FileAttributes attributes)
{
string path = CreateItem();
- SetAttributes(path, attr);
+ SetAttributes(path, attributes);
+ Assert.Equal(FileAttributes.Normal, GetAttributes(path));
+ }
+
+ [Theory,
+ InlineData(":bar"),
+ InlineData(":bar:$DATA")]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void GettingAndSettingAttributes_AlternateDataStream_Windows(string streamName)
+ {
+ string path = CreateItem();
+ streamName = path + streamName;
+ File.Create(streamName);
+
+ FileAttributes attributes = GetAttributes(streamName);
+ Assert.NotEqual((FileAttributes)0, attributes);
+ Assert.NotEqual((FileAttributes)(-1), attributes);
+
+ // Attributes are shared for the file and all streams
+ SetAttributes(streamName, FileAttributes.Hidden);
+ Assert.Equal(FileAttributes.Hidden, GetAttributes(streamName));
+ Assert.Equal(FileAttributes.Hidden, GetAttributes(path));
+
+ SetAttributes(path, FileAttributes.Normal);
+ Assert.Equal(FileAttributes.Normal, GetAttributes(streamName));
Assert.Equal(FileAttributes.Normal, GetAttributes(path));
}
}
diff --git a/src/System.IO.FileSystem/tests/Base/StaticGetSetTimes.cs b/src/System.IO.FileSystem/tests/Base/StaticGetSetTimes.cs
index 6444ff203f..12ee8997fd 100644
--- a/src/System.IO.FileSystem/tests/Base/StaticGetSetTimes.cs
+++ b/src/System.IO.FileSystem/tests/Base/StaticGetSetTimes.cs
@@ -10,6 +10,8 @@ namespace System.IO.Tests
{
public override string GetMissingItem() => GetTestFilePath();
+ public override string GetItemPath(string item) => item;
+
[Fact]
public void NullPath_ThrowsArgumentNullException()
{
diff --git a/src/System.IO.FileSystem/tests/Directory/CreateDirectory.cs b/src/System.IO.FileSystem/tests/Directory/CreateDirectory.cs
index bfd60bb977..021a05b949 100644
--- a/src/System.IO.FileSystem/tests/Directory/CreateDirectory.cs
+++ b/src/System.IO.FileSystem/tests/Directory/CreateDirectory.cs
@@ -34,14 +34,20 @@ namespace System.IO.Tests
}
[Theory, MemberData(nameof(PathsWithInvalidCharacters))]
- public void PathWithInvalidCharactersAsPath_ThrowsArgumentException(string invalidPath)
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)]
+ public void PathWithInvalidCharactersAsPath_Desktop(string invalidPath)
{
- if (invalidPath.Equals(@"\\?\") && !PathFeatures.IsUsingLegacyPathNormalization())
- AssertExtensions.ThrowsAny<IOException, UnauthorizedAccessException>(() => Create(invalidPath));
- else if (invalidPath.Contains(@"\\?\") && !PathFeatures.IsUsingLegacyPathNormalization())
- Assert.Throws<DirectoryNotFoundException>(() => Create(invalidPath));
+ Assert.Throws<ArgumentException>(() => Create(invalidPath));
+ }
+
+ [Theory, MemberData(nameof(PathsWithInvalidCharacters))]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void PathWithInvalidCharactersAsPath_Core(string invalidPath)
+ {
+ if (invalidPath.Contains('\0'))
+ Assert.Throws<ArgumentException>("path", () => Create(invalidPath));
else
- Assert.Throws<ArgumentException>(() => Create(invalidPath));
+ Assert.Throws<IOException>(() => Create(invalidPath));
}
[Fact]
@@ -203,11 +209,28 @@ namespace System.IO.Tests
#region PlatformSpecific
[Theory, MemberData(nameof(PathsWithInvalidColons))]
- [PlatformSpecific(TestPlatforms.Windows)] // invalid colons throws ArgumentException
- [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Versions of netfx older than 4.6.2 throw an ArgumentException instead of NotSupportedException. Until all of our machines run netfx against the actual latest version, these will fail.")]
- public void PathWithInvalidColons_ThrowsNotSupportedException(string invalidPath)
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)]
+ public void PathWithInvalidColons_ThrowsNotSupportedException_Desktop(string invalidPath)
{
- Assert.Throws<NotSupportedException>(() => Create(invalidPath));
+ if (PathFeatures.IsUsingLegacyPathNormalization())
+ {
+ Assert.Throws<ArgumentException>(() => Create(invalidPath));
+ }
+ else
+ {
+ Assert.Throws<NotSupportedException>(() => Create(invalidPath));
+ }
+ }
+
+ [Theory, MemberData(nameof(PathsWithInvalidColons))]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void PathsWithInvalidColons_ThrowIOException_Core(string invalidPath)
+ {
+ // You can't actually create a directory with a colon in it. It was a preemptive
+ // check, now we let the OS give us failures on usage.
+ Assert.ThrowsAny<IOException>(() => Create(invalidPath));
}
[ConditionalFact(nameof(AreAllLongPathsAvailable))]
@@ -308,14 +331,33 @@ namespace System.IO.Tests
}
[Theory,
- MemberData(nameof(WhiteSpace))]
- [PlatformSpecific(TestPlatforms.Windows)] // whitespace as path throws ArgumentException on Windows
- public void WindowsWhiteSpaceAsPath_ThrowsArgumentException(string path)
+ MemberData(nameof(SimpleWhiteSpace))]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void WindowsSimpleWhiteSpaceAsPath_ThrowsArgumentException(string path)
+ {
+ Assert.Throws<ArgumentException>(() => Create(path));
+ }
+
+ [Theory,
+ MemberData(nameof(ControlWhiteSpace))]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)]
+ public void WindowsControlWhiteSpaceAsPath_ThrowsArgumentException_Desktop(string path)
{
Assert.Throws<ArgumentException>(() => Create(path));
}
[Theory,
+ MemberData(nameof(ControlWhiteSpace))]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void WindowsWhiteSpaceAsPath_ThrowsIOException_Core(string path)
+ {
+ Assert.Throws<IOException>(() => Create(path));
+ }
+
+
+ [Theory,
MemberData(nameof(WhiteSpace))]
[PlatformSpecific(TestPlatforms.AnyUnix)] // whitespace as path allowed
public void UnixWhiteSpaceAsPath_Allowed(string path)
@@ -397,14 +439,24 @@ namespace System.IO.Tests
}
[Theory,
- MemberData(nameof(PathsWithAlternativeDataStreams))]
+ MemberData(nameof(PathsWithColons))]
[PlatformSpecific(TestPlatforms.Windows)] // alternate data streams
- public void PathWithAlternateDataStreams_ThrowsNotSupportedException(string path)
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)]
+ public void PathWithColons_ThrowsNotSupportedException_Desktop(string path)
{
Assert.Throws<NotSupportedException>(() => Create(path));
}
[Theory,
+ MemberData(nameof(PathsWithColons))]
+ [PlatformSpecific(TestPlatforms.Windows)] // alternate data streams
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void PathWithColons_ThrowsIOException_Core(string path)
+ {
+ Assert.ThrowsAny<IOException>(() => Create(Path.Combine(TestDirectory, path)));
+ }
+
+ [Theory,
MemberData(nameof(PathsWithReservedDeviceNames))]
[PlatformSpecific(TestPlatforms.Windows)] // device name prefixes
public void PathWithReservedDeviceNameAsPath_ThrowsDirectoryNotFoundException(string path)
@@ -424,20 +476,39 @@ namespace System.IO.Tests
[Theory,
MemberData(nameof(UncPathsWithoutShareName))]
- [PlatformSpecific(TestPlatforms.Windows)] // UNC shares
- public void UncPathWithoutShareNameAsPath_ThrowsArgumentException(string path)
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)]
+ public void UncPathWithoutShareNameAsPath_ThrowsArgumentException_Desktop(string path)
{
Assert.Throws<ArgumentException>(() => Create(path));
}
+ [Theory,
+ MemberData(nameof(UncPathsWithoutShareName))]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void UncPathWithoutShareNameAsPath_ThrowsIOException_Core(string path)
+ {
+ Assert.ThrowsAny<IOException>(() => Create(path));
+ }
+
[Fact]
- [PlatformSpecific(TestPlatforms.Windows)] // UNC shares
- public void UNCPathWithOnlySlashes()
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)]
+ public void UNCPathWithOnlySlashes_Desktop()
{
Assert.Throws<ArgumentException>(() => Create("//"));
}
[Fact]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void UNCPathWithOnlySlashes_Core()
+ {
+ Assert.ThrowsAny<IOException>(() => Create("//"));
+ }
+
+ [Fact]
[PlatformSpecific(TestPlatforms.Windows)] // drive labels
[ActiveIssue(20117, TargetFrameworkMonikers.Uap)]
public void CDriveCase()
diff --git a/src/System.IO.FileSystem/tests/Directory/Delete.cs b/src/System.IO.FileSystem/tests/Directory/Delete.cs
index 98ab80c3ef..52f5b9dfad 100644
--- a/src/System.IO.FileSystem/tests/Directory/Delete.cs
+++ b/src/System.IO.FileSystem/tests/Directory/Delete.cs
@@ -208,7 +208,7 @@ namespace System.IO.Tests
[Trait(XunitConstants.Category, XunitConstants.RequiresElevation)]
public void Unix_NotFoundDirectory_ReadOnlyVolume()
{
- if (PlatformDetection.IsRedHatFamily6)
+ if (PlatformDetection.IsRedHatFamily6 || PlatformDetection.IsAlpine)
return; // [ActiveIssue(https://github.com/dotnet/corefx/issues/21920)]
ReadOnly_FileSystemHelper(readOnlyDirectory =>
diff --git a/src/System.IO.FileSystem/tests/Directory/EnumerableTests.cs b/src/System.IO.FileSystem/tests/Directory/EnumerableTests.cs
index e9c6028c56..7d604b6f1f 100644
--- a/src/System.IO.FileSystem/tests/Directory/EnumerableTests.cs
+++ b/src/System.IO.FileSystem/tests/Directory/EnumerableTests.cs
@@ -32,6 +32,17 @@ namespace System.IO.Tests
}
}
+ [Fact]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void EnumerateDirectories_NonBreakingSpace()
+ {
+ DirectoryInfo rootDirectory = Directory.CreateDirectory(GetTestFilePath());
+ DirectoryInfo subDirectory1 = rootDirectory.CreateSubdirectory("\u00A0");
+ DirectoryInfo subDirectory2 = subDirectory1.CreateSubdirectory(GetTestFileName());
+
+ FSAssert.EqualWhenOrdered(new string[] { subDirectory1.FullName, subDirectory2.FullName }, Directory.EnumerateDirectories(rootDirectory.FullName, string.Empty, SearchOption.AllDirectories));
+ }
+
class ThreadSafeRepro
{
volatile IEnumerator<string> _enumerator;
diff --git a/src/System.IO.FileSystem/tests/Directory/GetFileSystemEntries_str.cs b/src/System.IO.FileSystem/tests/Directory/GetFileSystemEntries_str.cs
index 8a4175705a..01402a222b 100644
--- a/src/System.IO.FileSystem/tests/Directory/GetFileSystemEntries_str.cs
+++ b/src/System.IO.FileSystem/tests/Directory/GetFileSystemEntries_str.cs
@@ -11,7 +11,7 @@ namespace System.IO.Tests
{
#region Utilities
- public static TheoryData WindowsInvalidUnixValid = new TheoryData<string> { " ", " ", "\n", ">", "<", "\t" };
+
protected virtual bool TestFiles { get { return true; } } // True if the virtual GetEntries mmethod returns files
protected virtual bool TestDirectories { get { return true; } } // True if the virtual GetEntries mmethod returns Directories
@@ -175,42 +175,125 @@ namespace System.IO.Tests
}
}
+ [Fact]
+ public void HiddenFilesAreReturned()
+ {
+ // Note that APIs that take EnumerationOptions do NOT find hidden files by default
+
+ DirectoryInfo testDirectory = Directory.CreateDirectory(GetTestFilePath());
+ FileInfo fileOne = new FileInfo(Path.Combine(testDirectory.FullName, GetTestFileName()));
+
+ // Put a period in front to make it hidden on Unix
+ FileInfo fileTwo = new FileInfo(Path.Combine(testDirectory.FullName, "." + GetTestFileName()));
+ fileOne.Create().Dispose();
+ fileTwo.Create().Dispose();
+ if (PlatformDetection.IsWindows)
+ fileTwo.Attributes = fileTwo.Attributes | FileAttributes.Hidden;
+
+ if (TestFiles)
+ {
+ FSAssert.EqualWhenOrdered(new string[] { fileOne.FullName, fileTwo.FullName }, GetEntries(testDirectory.FullName));
+ }
+ else
+ {
+ Assert.Empty(GetEntries(testDirectory.FullName));
+ }
+ }
+
#endregion
#region PlatformSpecific
[Fact]
- public void InvalidPath()
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)]
+ public void InvalidPath_Desktop()
{
foreach (char invalid in Path.GetInvalidFileNameChars())
{
- if (invalid == '/' || invalid == '\\')
- {
- Assert.Throws<DirectoryNotFoundException>(() => GetEntries(Path.Combine(TestDirectory, string.Format("te{0}st", invalid.ToString()))));
- }
- else if (invalid == ':')
+ string badPath = string.Format($"{TestDirectory}{Path.DirectorySeparatorChar}te{invalid}st");
+ switch (invalid)
{
- if (FileSystemDebugInfo.IsCurrentDriveNTFS())
- Assert.Throws<NotSupportedException>(() => GetEntries(Path.Combine(TestDirectory, string.Format("te{0}st", invalid.ToString()))));
+ case '/':
+ case '\\':
+ Assert.Throws<DirectoryNotFoundException>(() => GetEntries(badPath));
+ break;
+ case ':':
+ Assert.Throws<NotSupportedException>(() => GetEntries(badPath));
+ break;
+ case '\0':
+ Assert.Throws<ArgumentException>(() => GetEntries(badPath));
+ break;
+ default:
+ Assert.Throws<ArgumentException>(() => GetEntries(badPath));
+ break;
}
- else
+ }
+ }
+
+ [Fact]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void InvalidPath_Core()
+ {
+ foreach (char invalid in Path.GetInvalidFileNameChars())
+ {
+ string badPath = string.Format($"{TestDirectory}{Path.DirectorySeparatorChar}te{invalid}st");
+ switch (invalid)
{
- Assert.Throws<ArgumentException>(() => GetEntries(Path.Combine(TestDirectory, string.Format("te{0}st", invalid.ToString()))));
+ case '/':
+ case '\\':
+ case ':':
+ Assert.Throws<DirectoryNotFoundException>(() => GetEntries(badPath));
+ break;
+ case '\0':
+ Assert.Throws<ArgumentException>(() => GetEntries(badPath));
+ break;
+ default:
+ Assert.Throws<IOException>(() => GetEntries(badPath));
+ break;
}
}
}
[Theory,
- MemberData(nameof(WindowsInvalidUnixValid))]
- [PlatformSpecific(TestPlatforms.Windows)] // Windows-only Invalid chars in path
- public void WindowsInvalidCharsPath(string invalid)
+ InlineData(" "),
+ InlineData(" ")]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void WindowsWhitespaceOnlyPath(string invalid)
+ {
+ Assert.Throws<ArgumentException>(() => GetEntries(invalid));
+ }
+
+ [Theory,
+ InlineData("\n"),
+ InlineData(">"),
+ InlineData("<"),
+ InlineData("\t")]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)]
+ public void WindowsInvalidCharsPath_Desktop(string invalid)
{
-
Assert.Throws<ArgumentException>(() => GetEntries(invalid));
}
[Theory,
- MemberData(nameof(WindowsInvalidUnixValid))]
+ InlineData("\n"),
+ InlineData(">"),
+ InlineData("<"),
+ InlineData("\t")]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void WindowsInvalidCharsPath_Core(string invalid)
+ {
+ Assert.Throws<IOException>(() => GetEntries(invalid));
+ }
+
+ [Theory,
+ InlineData(" "),
+ InlineData(" "),
+ InlineData("\n"),
+ InlineData(">"),
+ InlineData("<"),
+ InlineData("\t")]
[PlatformSpecific(TestPlatforms.AnyUnix)] // Unix-only valid chars in file path
public void UnixValidCharsFilePath(string valid)
{
@@ -226,7 +309,12 @@ namespace System.IO.Tests
}
[Theory,
- MemberData(nameof(WindowsInvalidUnixValid))]
+ InlineData(" "),
+ InlineData(" "),
+ InlineData("\n"),
+ InlineData(">"),
+ InlineData("<"),
+ InlineData("\t")]
[PlatformSpecific(TestPlatforms.AnyUnix)] // Windows-only invalid chars in directory path
public void UnixValidCharsDirectoryPath(string valid)
{
diff --git a/src/System.IO.FileSystem/tests/Directory/GetFileSystemEntries_str_str.cs b/src/System.IO.FileSystem/tests/Directory/GetFileSystemEntries_str_str.cs
index a352bf6529..e96881bc46 100644
--- a/src/System.IO.FileSystem/tests/Directory/GetFileSystemEntries_str_str.cs
+++ b/src/System.IO.FileSystem/tests/Directory/GetFileSystemEntries_str_str.cs
@@ -985,7 +985,12 @@ namespace System.IO.Tests
}
[Theory,
- MemberData(nameof(WindowsInvalidUnixValid))]
+ InlineData(" "),
+ InlineData(" "),
+ InlineData("\n"),
+ InlineData(">"),
+ InlineData("<"),
+ InlineData("\t")]
[PlatformSpecific(TestPlatforms.AnyUnix)] // Unix-valid chars in file search patterns
public void UnixSearchPatternFileValidChar(string valid)
{
@@ -999,7 +1004,12 @@ namespace System.IO.Tests
}
[Theory,
- MemberData(nameof(WindowsInvalidUnixValid))]
+ InlineData(" "),
+ InlineData(" "),
+ InlineData("\n"),
+ InlineData(">"),
+ InlineData("<"),
+ InlineData("\t")]
[PlatformSpecific(TestPlatforms.AnyUnix)] // Unix-valid chars in directory search patterns
public void UnixSearchPatternDirectoryValidChar(string valid)
{
diff --git a/src/System.IO.FileSystem/tests/Directory/Move.cs b/src/System.IO.FileSystem/tests/Directory/Move.cs
index 8c21954c03..1da296c1c3 100644
--- a/src/System.IO.FileSystem/tests/Directory/Move.cs
+++ b/src/System.IO.FileSystem/tests/Directory/Move.cs
@@ -242,8 +242,9 @@ namespace System.IO.Tests
}
[Fact]
- [PlatformSpecific(TestPlatforms.Windows)] // Wild characters in path, wild chars are normal chars on Unix
- public void WindowsWildCharacterPath()
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)]
+ public void WindowsWildCharacterPath_Desktop()
{
Assert.Throws<ArgumentException>(() => Move("*", GetTestFilePath()));
Assert.Throws<ArgumentException>(() => Move(TestDirectory, "*"));
@@ -252,6 +253,17 @@ namespace System.IO.Tests
}
[Fact]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void WindowsWildCharacterPath_Core()
+ {
+ Assert.ThrowsAny<IOException>(() => Move(Path.Combine(TestDirectory, "*"), GetTestFilePath()));
+ Assert.ThrowsAny<IOException>(() => Move(TestDirectory, Path.Combine(TestDirectory, "*")));
+ Assert.ThrowsAny<IOException>(() => Move(TestDirectory, Path.Combine(TestDirectory, "Test*t")));
+ Assert.ThrowsAny<IOException>(() => Move(TestDirectory, Path.Combine(TestDirectory, "*Test")));
+ }
+
+ [Fact]
[PlatformSpecific(TestPlatforms.AnyUnix)] // Wild characters in path are allowed
public void UnixWildCharacterPath()
{
@@ -278,17 +290,13 @@ namespace System.IO.Tests
}
[Fact]
- [PlatformSpecific(TestPlatforms.Windows)] // Whitespace path causes ArgumentException
- public void WindowsWhitespacePath()
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void WindowsEmptyPath()
{
DirectoryInfo testDir = Directory.CreateDirectory(GetTestFilePath());
Assert.Throws<ArgumentException>(() => Move(testDir.FullName, " "));
- Assert.Throws<ArgumentException>(() => Move(testDir.FullName, "\n"));
Assert.Throws<ArgumentException>(() => Move(testDir.FullName, ""));
- Assert.Throws<ArgumentException>(() => Move(testDir.FullName, ">"));
- Assert.Throws<ArgumentException>(() => Move(testDir.FullName, "<"));
Assert.Throws<ArgumentException>(() => Move(testDir.FullName, "\0"));
- Assert.Throws<ArgumentException>(() => Move(testDir.FullName, "\t"));
}
[Fact]
diff --git a/src/System.IO.FileSystem/tests/DirectoryInfo/CreateSubdirectory.cs b/src/System.IO.FileSystem/tests/DirectoryInfo/CreateSubdirectory.cs
index 6122cb1f5c..75af106c41 100644
--- a/src/System.IO.FileSystem/tests/DirectoryInfo/CreateSubdirectory.cs
+++ b/src/System.IO.FileSystem/tests/DirectoryInfo/CreateSubdirectory.cs
@@ -140,27 +140,40 @@ namespace System.IO.Tests
[Theory,
MemberData(nameof(ControlWhiteSpace))]
- [PlatformSpecific(TestPlatforms.Windows)] // Control whitespace in path throws ArgumentException
- public void WindowsControlWhiteSpace(string component)
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)]
+ public void WindowsControlWhiteSpace_Desktop(string component)
+ {
+ Assert.Throws<ArgumentException>(() => new DirectoryInfo(TestDirectory).CreateSubdirectory(component));
+ }
+
+ [Theory,
+ MemberData(nameof(ControlWhiteSpace))]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void WindowsControlWhiteSpace_Core(string component)
+ {
+ Assert.Throws<IOException>(() => new DirectoryInfo(TestDirectory).CreateSubdirectory(component));
+ }
+
+ [Theory,
+ MemberData(nameof(SimpleWhiteSpace))]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void WindowsSimpleWhiteSpaceThrowsException(string component)
{
- // CreateSubdirectory will throw when passed a path with control whitespace e.g. "\t"
- string path = IOServices.RemoveTrailingSlash(GetTestFileName());
Assert.Throws<ArgumentException>(() => new DirectoryInfo(TestDirectory).CreateSubdirectory(component));
}
[Theory,
MemberData(nameof(SimpleWhiteSpace))]
- [PlatformSpecific(TestPlatforms.Windows)] // Simple whitespace is trimmed in path
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)] // Simple whitespace is trimmed in path
public void WindowsSimpleWhiteSpace(string component)
{
- // CreateSubdirectory trims all simple whitespace, returning us the parent directory
- // that called CreateSubdirectory
- string path = IOServices.RemoveTrailingSlash(GetTestFileName());
DirectoryInfo result = new DirectoryInfo(TestDirectory).CreateSubdirectory(component);
Assert.True(Directory.Exists(result.FullName));
Assert.Equal(TestDirectory, IOServices.RemoveTrailingSlash(result.FullName));
-
}
[Theory,
@@ -170,7 +183,6 @@ namespace System.IO.Tests
{
new DirectoryInfo(TestDirectory).CreateSubdirectory(path);
Assert.True(Directory.Exists(Path.Combine(TestDirectory, path)));
-
}
[Theory,
@@ -207,6 +219,16 @@ namespace System.IO.Tests
Assert.Throws<ArgumentException>(() => testDir.CreateSubdirectory("//"));
}
+ [Fact]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void ParentDirectoryNameAsPrefixShouldThrow()
+ {
+ string randomName = GetTestFileName();
+ DirectoryInfo di = Directory.CreateDirectory(Path.Combine(TestDirectory, randomName));
+
+ Assert.Throws<ArgumentException>(() => di.CreateSubdirectory(Path.Combine("..", randomName + "abc", GetTestFileName())));
+ }
+
#endregion
}
}
diff --git a/src/System.IO.FileSystem/tests/DirectoryInfo/Exists.cs b/src/System.IO.FileSystem/tests/DirectoryInfo/Exists.cs
index d54f799cf0..be9e7e2641 100644
--- a/src/System.IO.FileSystem/tests/DirectoryInfo/Exists.cs
+++ b/src/System.IO.FileSystem/tests/DirectoryInfo/Exists.cs
@@ -38,6 +38,12 @@ namespace System.IO.Tests
}
[Fact]
+ public void Root()
+ {
+ Assert.True(new DirectoryInfo(Path.GetPathRoot(Directory.GetCurrentDirectory())).Exists);
+ }
+
+ [Fact]
public void DotPath()
{
Assert.True(new DirectoryInfo(Path.Combine(TestDirectory, ".")).Exists);
diff --git a/src/System.IO.FileSystem/tests/DirectoryInfo/GetSetTimes.cs b/src/System.IO.FileSystem/tests/DirectoryInfo/GetSetTimes.cs
index 927c770d61..779be70df6 100644
--- a/src/System.IO.FileSystem/tests/DirectoryInfo/GetSetTimes.cs
+++ b/src/System.IO.FileSystem/tests/DirectoryInfo/GetSetTimes.cs
@@ -12,6 +12,8 @@ namespace System.IO.Tests
public override DirectoryInfo GetMissingItem() => new DirectoryInfo(GetTestFilePath());
+ public override string GetItemPath(DirectoryInfo item) => item.FullName;
+
public override void InvokeCreate(DirectoryInfo item) => item.Create();
public override IEnumerable<TimeFunction> TimeFunctions(bool requiresRoundtripping = false)
diff --git a/src/System.IO.FileSystem/tests/DirectoryInfo/ToString.cs b/src/System.IO.FileSystem/tests/DirectoryInfo/ToString.cs
index 732c71ee62..de2ea39621 100644
--- a/src/System.IO.FileSystem/tests/DirectoryInfo/ToString.cs
+++ b/src/System.IO.FileSystem/tests/DirectoryInfo/ToString.cs
@@ -38,12 +38,28 @@ namespace System.IO.Tests
}
[Fact]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.Netcoreapp)]
[PlatformSpecific(TestPlatforms.Windows)] // Drive letter only
- public void DriveOnlyReturnsPeriod_Windows()
+ public void DriveOnlyReturnsPeriod_Windows_Desktop()
{
string path = @"C:";
var info = new DirectoryInfo(path);
Assert.Equal(".", info.ToString());
}
+
+ [Fact]
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.Netcoreapp)]
+ [PlatformSpecific(TestPlatforms.Windows)] // Drive letter only
+ public void DriveOnlyReturnsPeriod_Windows_Core()
+ {
+ // This was likely a limited trust hack that was strangely implemented.
+ // Getting the current directory for a specified drive relative path
+ // doesn't make a lot of sense. There is no reason to hide original paths
+ // when in full trust.
+ string path = @"C:";
+ var info = new DirectoryInfo(path);
+ Assert.Equal("C:", info.ToString());
+ }
+
}
}
diff --git a/src/System.IO.FileSystem/tests/Enumeration/AttributeTests.netcoreapp.cs b/src/System.IO.FileSystem/tests/Enumeration/AttributeTests.netcoreapp.cs
new file mode 100644
index 0000000000..2ba62dfb42
--- /dev/null
+++ b/src/System.IO.FileSystem/tests/Enumeration/AttributeTests.netcoreapp.cs
@@ -0,0 +1,141 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.IO.Enumeration;
+using Xunit;
+
+namespace System.IO.Tests.Enumeration
+{
+ public class AttributeTests : FileSystemTest
+ {
+ private class DefaultFileAttributes : FileSystemEnumerator<string>
+ {
+ public DefaultFileAttributes(string directory, EnumerationOptions options)
+ : base(directory, options)
+ {
+ }
+
+ protected override bool ContinueOnError(int error)
+ {
+ Assert.False(true, $"Should not have errored {error}");
+ return false;
+ }
+
+ protected override bool ShouldIncludeEntry(ref FileSystemEntry entry)
+ => !entry.IsDirectory;
+
+ protected override string TransformEntry(ref FileSystemEntry entry)
+ {
+ string path = entry.ToFullPath();
+ File.Delete(path);
+
+ // Attributes require a stat call on Unix- ensure that we have the right attributes
+ // even if the returned file is deleted.
+ Assert.Equal(FileAttributes.Normal, entry.Attributes);
+ Assert.Equal(path, entry.ToFullPath());
+ return new string(entry.FileName);
+ }
+ }
+
+ [Fact]
+ public void FileAttributesAreExpected()
+ {
+ DirectoryInfo testDirectory = Directory.CreateDirectory(GetTestFilePath());
+ FileInfo fileOne = new FileInfo(Path.Combine(testDirectory.FullName, GetTestFileName()));
+
+ fileOne.Create().Dispose();
+
+ if (PlatformDetection.IsWindows)
+ {
+ // Archive should always be set on a new file. Clear it and other expected flags to
+ // see that we get "Normal" as the default when enumerating.
+
+ Assert.True((fileOne.Attributes & FileAttributes.Archive) != 0);
+ fileOne.Attributes &= ~(FileAttributes.Archive | FileAttributes.NotContentIndexed);
+ }
+
+ using (var enumerator = new DefaultFileAttributes(testDirectory.FullName, new EnumerationOptions()))
+ {
+ Assert.True(enumerator.MoveNext());
+ Assert.Equal(fileOne.Name, enumerator.Current);
+ Assert.False(enumerator.MoveNext());
+ }
+ }
+
+ private class DefaultDirectoryAttributes : FileSystemEnumerator<string>
+ {
+ public DefaultDirectoryAttributes(string directory, EnumerationOptions options)
+ : base(directory, options)
+ {
+ }
+
+ protected override bool ShouldIncludeEntry(ref FileSystemEntry entry)
+ => entry.IsDirectory;
+
+ protected override bool ContinueOnError(int error)
+ {
+ Assert.False(true, $"Should not have errored {error}");
+ return false;
+ }
+
+ protected override string TransformEntry(ref FileSystemEntry entry)
+ {
+ string path = entry.ToFullPath();
+ Directory.Delete(path);
+
+ // Attributes require a stat call on Unix- ensure that we have the right attributes
+ // even if the returned directory is deleted.
+ Assert.Equal(FileAttributes.Directory, entry.Attributes);
+ Assert.Equal(path, entry.ToFullPath());
+ return new string(entry.FileName);
+ }
+ }
+
+ [Fact]
+ public void DirectoryAttributesAreExpected()
+ {
+ DirectoryInfo testDirectory = Directory.CreateDirectory(GetTestFilePath());
+ DirectoryInfo subDirectory = Directory.CreateDirectory(Path.Combine(testDirectory.FullName, GetTestFileName()));
+
+ if (PlatformDetection.IsWindows)
+ {
+ // Clear possible extra flags to see that we get Directory
+ subDirectory.Attributes &= ~FileAttributes.NotContentIndexed;
+ }
+
+ using (var enumerator = new DefaultDirectoryAttributes(testDirectory.FullName, new EnumerationOptions()))
+ {
+ Assert.True(enumerator.MoveNext());
+ Assert.Equal(subDirectory.Name, enumerator.Current);
+ Assert.False(enumerator.MoveNext());
+ }
+ }
+
+ [Fact]
+ public void IsHiddenAttribute()
+ {
+ DirectoryInfo testDirectory = Directory.CreateDirectory(GetTestFilePath());
+ FileInfo fileOne = new FileInfo(Path.Combine(testDirectory.FullName, GetTestFileName()));
+
+ // Put a period in front to make it hidden on Unix
+ FileInfo fileTwo = new FileInfo(Path.Combine(testDirectory.FullName, "." + GetTestFileName()));
+
+ fileOne.Create().Dispose();
+ fileTwo.Create().Dispose();
+ if (PlatformDetection.IsWindows)
+ fileTwo.Attributes = fileTwo.Attributes | FileAttributes.Hidden;
+
+ IEnumerable<string> enumerable = new FileSystemEnumerable<string>(
+ testDirectory.FullName,
+ (ref FileSystemEntry entry) => entry.ToFullPath(),
+ new EnumerationOptions() { AttributesToSkip = 0 })
+ {
+ ShouldIncludePredicate = (ref FileSystemEntry entry) => entry.IsHidden
+ };
+
+ Assert.Equal(new string[] { fileTwo.FullName }, enumerable);
+ }
+ }
+}
diff --git a/src/System.IO.FileSystem/tests/Enumeration/ConstructionTests.netcoreapp.cs b/src/System.IO.FileSystem/tests/Enumeration/ConstructionTests.netcoreapp.cs
new file mode 100644
index 0000000000..4f453200ee
--- /dev/null
+++ b/src/System.IO.FileSystem/tests/Enumeration/ConstructionTests.netcoreapp.cs
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.IO.Enumeration;
+using Xunit;
+
+namespace System.IO.Tests.Enumeration
+{
+ public class ConstructionTests : FileSystemTest
+ {
+ [Fact]
+ public void Enumerable_NullTransformThrows()
+ {
+ AssertExtensions.Throws<ArgumentNullException>("transform",
+ () => new FileSystemEnumerable<string>(TestDirectory, transform: null));
+ }
+
+ [Fact]
+ public void Enumerable_NullDirectoryThrows()
+ {
+ AssertExtensions.Throws<ArgumentNullException>("directory",
+ () => new FileSystemEnumerable<string>(null, null));
+ }
+
+ private class TestEnumerator : FileSystemEnumerator<string>
+ {
+ public TestEnumerator(string directory, EnumerationOptions options)
+ : base(directory, options)
+ {
+ }
+
+ protected override string TransformEntry(ref FileSystemEntry entry)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ [Fact]
+ public void Enumerator_NullDirectoryThrows()
+ {
+ AssertExtensions.Throws<ArgumentNullException>("directory",
+ () => new TestEnumerator(null, null));
+ }
+ }
+}
diff --git a/src/System.IO.FileSystem/tests/Enumeration/ErrorHandlingTests.netcoreapp.cs b/src/System.IO.FileSystem/tests/Enumeration/ErrorHandlingTests.netcoreapp.cs
new file mode 100644
index 0000000000..1414156cf3
--- /dev/null
+++ b/src/System.IO.FileSystem/tests/Enumeration/ErrorHandlingTests.netcoreapp.cs
@@ -0,0 +1,71 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.IO.Enumeration;
+using Xunit;
+
+namespace System.IO.Tests
+{
+ public class ErrorHandlingTests : FileSystemTest
+ {
+ private class IgnoreErrors : FileSystemEnumerator<string>
+ {
+ public IgnoreErrors(string directory)
+ : base(directory)
+ { }
+
+ public int ErrorCount { get; private set; }
+ public string DirectoryFinished { get; private set; }
+
+ protected override string TransformEntry(ref FileSystemEntry entry)
+ => entry.FileName.ToString();
+
+ protected override bool ContinueOnError(int error)
+ {
+ ErrorCount++;
+ return true;
+ }
+
+ protected override void OnDirectoryFinished(ReadOnlySpan<char> directory)
+ => DirectoryFinished = directory.ToString();
+ }
+
+ [Fact]
+ public void OpenErrorDoesNotHappenAgainOnMoveNext()
+ {
+ // What we're checking for here is that we don't try to enumerate when we
+ // couldn't even open the root directory (e.g. open the handle again, try
+ // to get data, etc.)
+ using (IgnoreErrors ie = new IgnoreErrors(Path.GetRandomFileName()))
+ {
+ Assert.Equal(1, ie.ErrorCount);
+ Assert.False(ie.MoveNext());
+ Assert.Equal(1, ie.ErrorCount);
+
+ // Since we didn't start, the directory shouldn't finish.
+ Assert.Null(ie.DirectoryFinished);
+ }
+ }
+
+ [Fact]
+ public void DeleteDirectoryAfterOpening()
+ {
+ // We shouldn't prevent the directory from being deleted, even though we've
+ // opened (and are holding) the handle. On Windows this means we've opened
+ // the handle with file share of delete.
+ DirectoryInfo info = Directory.CreateDirectory(GetTestFilePath());
+ using (IgnoreErrors ie = new IgnoreErrors(info.FullName))
+ {
+ Assert.Equal(0, ie.ErrorCount);
+ Directory.Delete(info.FullName);
+ Assert.False(ie.MoveNext());
+
+ // This doesn't cause an error as the directory is still valid until the
+ // the enumerator is closed (as we have an open handle)
+ Assert.Equal(0, ie.ErrorCount);
+ Assert.Equal(info.FullName, ie.DirectoryFinished);
+ }
+ }
+ }
+}
diff --git a/src/System.IO.FileSystem/tests/Enumeration/ExampleTests.netcoreapp.cs b/src/System.IO.FileSystem/tests/Enumeration/ExampleTests.netcoreapp.cs
new file mode 100644
index 0000000000..9db4f452d1
--- /dev/null
+++ b/src/System.IO.FileSystem/tests/Enumeration/ExampleTests.netcoreapp.cs
@@ -0,0 +1,141 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.IO.Enumeration;
+using System.Linq;
+using Xunit;
+
+namespace System.IO.Tests.Enumeration
+{
+ // For tests that cover examples from documentation, blog posts, etc. While these overlap with
+ // existing tests, having explicit coverage here is extra insurance we are covering the
+ // examples we've given out publicly.
+ public class ExampleTests : FileSystemTest
+ {
+ [Fact]
+ public void GetFileNamesEnumerable()
+ {
+ // https://blogs.msdn.microsoft.com/jeremykuhne/2018/03/09/custom-directory-enumeration-in-net-core-2-1/
+ DirectoryInfo testDirectory = Directory.CreateDirectory(GetTestFilePath());
+ File.Create(Path.Join(testDirectory.FullName, "one")).Dispose();
+ File.Create(Path.Join(testDirectory.FullName, "two")).Dispose();
+ Directory.CreateDirectory(Path.Join(testDirectory.FullName, "three"));
+
+ IEnumerable<string> fileNames =
+ new FileSystemEnumerable<string>(
+ testDirectory.FullName,
+ (ref FileSystemEntry entry) => entry.FileName.ToString())
+ {
+ ShouldIncludePredicate = (ref FileSystemEntry entry) => !entry.IsDirectory
+ };
+
+ FSAssert.EqualWhenOrdered(new string[] { "one", "two" }, fileNames);
+ }
+
+ private static IEnumerable<FileInfo> GetFilesWithExtensions(string directory,
+ bool recursive, params string[] extensions)
+ {
+ return new FileSystemEnumerable<FileInfo>(
+ directory,
+ (ref FileSystemEntry entry) => (FileInfo)entry.ToFileSystemInfo(),
+ new EnumerationOptions() { RecurseSubdirectories = recursive })
+ {
+ ShouldIncludePredicate = (ref FileSystemEntry entry) =>
+ {
+ if (entry.IsDirectory)
+ return false;
+ foreach (string extension in extensions)
+ {
+ if (Path.GetExtension(entry.FileName).SequenceEqual(extension))
+ return true;
+ }
+ return false;
+ }
+ };
+ }
+
+ [Fact]
+ public void TestGetFilesWithExtensions()
+ {
+ // https://blogs.msdn.microsoft.com/jeremykuhne/2018/03/09/custom-directory-enumeration-in-net-core-2-1/
+ DirectoryInfo testDirectory = Directory.CreateDirectory(GetTestFilePath());
+ File.Create(Path.Join(testDirectory.FullName, "file.one")).Dispose();
+ File.Create(Path.Join(testDirectory.FullName, "file.two")).Dispose();
+ File.Create(Path.Join(testDirectory.FullName, "file.three")).Dispose();
+ DirectoryInfo subDirectory = testDirectory.CreateSubdirectory("three.one");
+ File.Create(Path.Join(subDirectory.FullName, "subfile.one")).Dispose();
+
+ FSAssert.EqualWhenOrdered(
+ new string[] { "file.one", "file.three" },
+ GetFilesWithExtensions(testDirectory.FullName, false, ".one", ".three").Select(f => f.Name));
+
+ FSAssert.EqualWhenOrdered(
+ new string[] { "file.one", "file.three", "subfile.one" },
+ GetFilesWithExtensions(testDirectory.FullName, true, ".one", ".three").Select(f => f.Name));
+ }
+
+ private static int CountFiles(string directory, bool recursive)
+ {
+ return (new FileSystemEnumerable<int>(
+ directory,
+ (ref FileSystemEntry entry) => 1,
+ new EnumerationOptions() { RecurseSubdirectories = recursive })
+ {
+ ShouldIncludePredicate = (ref FileSystemEntry entry) => !entry.IsDirectory
+ }).Count();
+ }
+
+ [Fact]
+ public void TestCountFiles()
+ {
+ // https://blogs.msdn.microsoft.com/jeremykuhne/2018/03/09/custom-directory-enumeration-in-net-core-2-1/
+ DirectoryInfo testDirectory = Directory.CreateDirectory(GetTestFilePath());
+ File.Create(Path.Join(testDirectory.FullName, "file.one")).Dispose();
+ File.Create(Path.Join(testDirectory.FullName, "file.two")).Dispose();
+ File.Create(Path.Join(testDirectory.FullName, "file.three")).Dispose();
+ DirectoryInfo subDirectory = testDirectory.CreateSubdirectory("three.one");
+ File.Create(Path.Join(subDirectory.FullName, "subfile.one")).Dispose();
+
+ Assert.Equal(3, CountFiles(testDirectory.FullName, false));
+
+ Assert.Equal(4, CountFiles(testDirectory.FullName, true));
+ }
+
+ private static long CountFileBytes(string directory, bool recursive)
+ {
+ return (new FileSystemEnumerable<long>(
+ directory,
+ (ref FileSystemEntry entry) => entry.Length,
+ new EnumerationOptions() { RecurseSubdirectories = recursive })
+ {
+ ShouldIncludePredicate = (ref FileSystemEntry entry) => !entry.IsDirectory
+ }).Sum();
+ }
+
+ [Fact]
+ public void TestCountFileBytes()
+ {
+ // https://blogs.msdn.microsoft.com/jeremykuhne/2018/03/09/custom-directory-enumeration-in-net-core-2-1/
+ DirectoryInfo testDirectory = Directory.CreateDirectory(GetTestFilePath());
+ FileInfo firstFile = new FileInfo(Path.Join(testDirectory.FullName, "file.one"));
+ using (var writer = firstFile.CreateText())
+ {
+ for (int i = 0; i < 100; i++)
+ writer.WriteLine("The quick brown fox jumped over the lazy dog.");
+ }
+
+ firstFile.CopyTo(Path.Join(testDirectory.FullName, "file.two"));
+ firstFile.CopyTo(Path.Join(testDirectory.FullName, "file.three"));
+ DirectoryInfo subDirectory = testDirectory.CreateSubdirectory("three.one");
+ firstFile.CopyTo(Path.Join(subDirectory.FullName, "subfile.one"));
+
+ firstFile.Refresh();
+ Assert.True(firstFile.Length > 0, "The file we wrote should have a length.");
+ Assert.Equal(firstFile.Length * 3, CountFileBytes(testDirectory.FullName, false));
+
+ Assert.Equal(firstFile.Length * 4, CountFileBytes(testDirectory.FullName, true));
+ }
+ }
+}
diff --git a/src/System.IO.FileSystem/tests/Enumeration/FileSystemNameTests.netcoreapp.cs b/src/System.IO.FileSystem/tests/Enumeration/FileSystemNameTests.netcoreapp.cs
new file mode 100644
index 0000000000..a199d2c298
--- /dev/null
+++ b/src/System.IO.FileSystem/tests/Enumeration/FileSystemNameTests.netcoreapp.cs
@@ -0,0 +1,154 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.IO.Enumeration;
+using Xunit;
+
+namespace System.IO.Tests
+{
+ public class FileSystemNameTests
+ {
+ [Theory,
+ MemberData(nameof(SimpleMatchData)),
+ MemberData(nameof(EscapedSimpleMatchData)),
+ MemberData(nameof(Win32MatchData)),
+ MemberData(nameof(EscapedWin32MatchData))]
+ public static void Win32Match(string expression, string name, bool ignoreCase, bool expected)
+ {
+ Assert.Equal(expected, FileSystemName.MatchesWin32Expression(expression, name.AsSpan(), ignoreCase));
+ }
+
+ [Theory,
+ MemberData(nameof(SimpleMatchData)),
+ MemberData(nameof(EscapedSimpleMatchData))]
+ public static void SimpleMatch(string expression, string name, bool ignoreCase, bool expected)
+ {
+ Assert.Equal(expected, FileSystemName.MatchesSimpleExpression(expression, name.AsSpan(), ignoreCase));
+ }
+
+ public static TheoryData<string, string, bool, bool> EscapedSimpleMatchData => new TheoryData<string, string, bool, bool>
+ {
+ // Trailing escape matches as it is considered "invisible"
+ { "\\", "\\", false, true },
+ { "\\", "\\", true, true },
+ { "\\\\", "\\", false, true },
+ { "\\\\", "\\", true, true },
+
+ { "\\*", "a", false, false },
+ { "\\*", "a", true, false },
+ { "\\*", "*", false, true },
+ { "\\*", "*", true, true },
+ { "*\\*", "***", false, true },
+ { "*\\*", "***", true, true },
+ { "*\\*", "ABC*", false, true },
+ { "*\\*", "ABC*", true, true },
+ { "*\\*", "***A", false, false },
+ { "*\\*", "***A", true, false },
+ { "*\\*", "ABC*A", false, false },
+ { "*\\*", "ABC*A", true, false },
+ };
+
+ public static TheoryData<string, string, bool, bool> EscapedWin32MatchData => new TheoryData<string, string, bool, bool>
+ {
+ { "\\\"", "a", false, false },
+ { "\\\"", "a", true, false },
+ { "\\\"", "\"", false, true },
+ { "\\\"", "\"", true, true },
+ };
+
+ public static TheoryData<string, string, bool, bool> SimpleMatchData => new TheoryData<string, string, bool, bool>
+ {
+ { null, "", false, false },
+ { null, "", true, false },
+ { "*", "", false, false },
+ { "*", "", true, false },
+ { "*", "ab", false, true },
+ { "*", "AB", true, true },
+ { "*foo", "foo", false, true },
+ { "*foo", "foo", true, true },
+ { "*foo", "FOO", false, false },
+ { "*foo", "FOO", true, true },
+ { "*foo", "nofoo", true, true },
+ { "*foo", "NoFOO", true, true },
+ { "*foo", "noFOO", false, false },
+ { @"*", @"foo.txt", true, true },
+ { @".", @"foo.txt", true, false },
+ { @".", @"footxt", true, false },
+ { @"*.*", @"foo.txt", true, true },
+ { @"*.*", @"foo.", true, true },
+ { @"*.*", @".foo", true, true },
+ { @"*.*", @"footxt", true, false },
+ };
+
+ public static TheoryData<string, string, bool, bool> Win32MatchData => new TheoryData<string, string, bool, bool>
+ {
+ { "<\"*", @"footxt", true, true }, // DOS equivalent of *.*
+ { "<\"*", @"foo.txt", true, true }, // DOS equivalent of *.*
+ { "<\"*", @".foo", true, true }, // DOS equivalent of *.*
+ { "<\"*", @"foo.", true, true }, // DOS equivalent of *.*
+ { ">\">", @"a.b", true, true }, // DOS equivalent of ?.?
+ { ">\">", @"a.", true, true }, // DOS equivalent of ?.?
+ { ">\">", @"a", true, true }, // DOS equivalent of ?.?
+ { ">\">", @"ab", true, false }, // DOS equivalent of ?.?
+ { ">\">", @"a.bc", true, false }, // DOS equivalent of ?.?
+ { ">\">", @"ab.c", true, false }, // DOS equivalent of ?.?
+ { ">>\">>", @"a.b", true, true }, // DOS equivalent of ??.??
+ { ">>\"\">>", @"a.b", true, false }, // Not possible to do from DOS ??""??
+ { ">>\">>", @"a.bc", true, true }, // DOS equivalent of ??.??
+ { ">>\">>", @"ab.ba", true, true }, // DOS equivalent of ??.??
+ { ">>\">>", @"ab.", true, true }, // DOS equivalent of ??.??
+ { ">>\"\"\">>", @"ab.", true, true }, // Not possible to do from DOS ??"""??
+ { ">>b\">>", @"ab.ba", true, false }, // DOS equivalent of ??b.??
+ { "a>>\">>", @"ab.ba", true, true }, // DOS equivalent of a??.??
+ { ">>\">>a", @"ab.ba", true, false }, // DOS equivalent of ??.??a
+ { ">>\"b>>", @"ab.ba", true, true }, // DOS equivalent of ??.b??
+ { ">>\"b>>", @"ab.b", true, true }, // DOS equivalent of ??.b??
+ { ">>b.>>", @"ab.ba", true, false },
+ { "a>>.>>", @"ab.ba", true, true },
+ { ">>.>>a", @"ab.ba", true, false },
+ { ">>.b>>", @"ab.ba", true, true },
+ { ">>.b>>", @"ab.b", true, true },
+ { ">>\">>\">>", @"ab.ba", true, true }, // DOS equivalent of ??.??.?? (The last " is an optional period)
+ { ">>\">>\">>", @"abba", true, false }, // DOS equivalent of ??.??.?? (The first " isn't, so this doesn't match)
+ { ">>\"ab\"ba", @"ab.ba", true, false }, // DOS equivalent of ??.ab.ba
+ { "ab\"ba\">>", @"ab.ba", true, true }, // DOS equivalent of ab.ba.??
+ { "ab\">>\"ba", @"ab.ba", true, false }, // DOS equivalent of ab.??.ba
+ { ">>\">>\">>>", @"ab.ba.cab", true, true }, // DOS equivalent of ??.??.???
+ { "a>>\"b>>\"c>>>", @"ab.ba.cab", true, true }, // DOS equivalent of a??.b??.c???
+ { @"<", @"a", true, true }, // DOS equivalent of *.
+ { @"<", @"a.", true, true }, // DOS equivalent of *.
+ { @"<", @"a. ", true, false }, // DOS equivalent of *.
+ { @"<", @"a.b", true, false }, // DOS equivalent of *.
+ { @"foo<", @"foo.", true, true }, // DOS equivalent of foo*.
+ { @"foo<", @"foo. ", true, false }, // DOS equivalent of foo*.
+ { @"<<", @"a.b", true, true },
+ { @"<<", @"a.b.c", true, true },
+ { "<\"", @"a.b.c", true, false },
+ { @"<.", @"a", true, false },
+ { @"<.", @"a.", true, true },
+ { @"<.", @"a.b", true, false },
+ };
+
+ [Theory,
+ InlineData("", "*"),
+ InlineData("*.*", "*"),
+ InlineData("*", "*"),
+ InlineData(".", "."),
+ InlineData("?", ">"),
+ InlineData("*.", "<"),
+ InlineData("?.?", ">\">"),
+ InlineData("foo*.", "foo<")]
+ public void TranslateExpression(string expression, string expected)
+ {
+ Assert.Equal(expected, FileSystemName.TranslateWin32Expression(expression));
+ }
+
+ [Fact]
+ public void TranslateVeryLongExpression()
+ {
+ string longString = new string('a', 10_000_000);
+ Assert.Equal(longString, FileSystemName.TranslateWin32Expression(longString));
+ }
+ }
+}
diff --git a/src/System.IO.FileSystem/tests/Enumeration/IncludePredicateTests.netcoreapp.cs b/src/System.IO.FileSystem/tests/Enumeration/IncludePredicateTests.netcoreapp.cs
new file mode 100644
index 0000000000..0a6737e064
--- /dev/null
+++ b/src/System.IO.FileSystem/tests/Enumeration/IncludePredicateTests.netcoreapp.cs
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.IO.Enumeration;
+using System.Linq;
+using Xunit;
+
+namespace System.IO.Tests.Enumeration
+{
+ public abstract class IncludePredicateTests : FileSystemTest
+ {
+ public static IEnumerable<string> GetFileFullPathsWithExtension(string directory,
+ bool recursive, params string[] extensions)
+ {
+ return new FileSystemEnumerable<string>(
+ directory,
+ (ref FileSystemEntry entry) => entry.ToFullPath(),
+ new EnumerationOptions() { RecurseSubdirectories = recursive })
+ {
+ ShouldIncludePredicate = (ref FileSystemEntry entry) =>
+ {
+ if (entry.IsDirectory) return false;
+ foreach (string extension in extensions)
+ {
+ if (Path.GetExtension(entry.FileName).EndsWith(extension))
+ return true;
+ }
+ return false;
+ }
+ };
+ }
+
+ [Fact]
+ public void CustomExtensionMatch()
+ {
+ DirectoryInfo testDirectory = Directory.CreateDirectory(GetTestFilePath());
+ DirectoryInfo testSubdirectory = Directory.CreateDirectory(Path.Combine(testDirectory.FullName, "Subdirectory"));
+ FileInfo fileOne = new FileInfo(Path.Combine(testDirectory.FullName, "fileone.htm"));
+ FileInfo fileTwo = new FileInfo(Path.Combine(testDirectory.FullName, "filetwo.html"));
+ FileInfo fileThree = new FileInfo(Path.Combine(testSubdirectory.FullName, "filethree.doc"));
+ FileInfo fileFour = new FileInfo(Path.Combine(testSubdirectory.FullName, "filefour.docx"));
+
+ fileOne.Create().Dispose();
+ fileTwo.Create().Dispose();
+ fileThree.Create().Dispose();
+ fileFour.Create().Dispose();
+
+ string[] paths = GetFileFullPathsWithExtension(testDirectory.FullName, true, ".htm", ".doc").ToArray();
+
+ FSAssert.EqualWhenOrdered(new string[] { fileOne.FullName, fileThree.FullName }, paths);
+ }
+ }
+}
diff --git a/src/System.IO.FileSystem/tests/Enumeration/MatchCasingTests.netcoreapp.cs b/src/System.IO.FileSystem/tests/Enumeration/MatchCasingTests.netcoreapp.cs
new file mode 100644
index 0000000000..00a74055ab
--- /dev/null
+++ b/src/System.IO.FileSystem/tests/Enumeration/MatchCasingTests.netcoreapp.cs
@@ -0,0 +1,60 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.IO.Enumeration;
+using System.Linq;
+using Xunit;
+
+namespace System.IO.Tests.Enumeration
+{
+ public abstract class MatchCasingTests : FileSystemTest
+ {
+ protected abstract string[] GetPaths(string directory, string pattern, EnumerationOptions options);
+
+ [Fact]
+ public void MatchCase()
+ {
+ DirectoryInfo testDirectory = Directory.CreateDirectory(GetTestFilePath());
+ DirectoryInfo testSubdirectory = Directory.CreateDirectory(Path.Combine(testDirectory.FullName, "Subdirectory"));
+ FileInfo fileOne = new FileInfo(Path.Combine(testDirectory.FullName, "FileOne"));
+ FileInfo fileTwo = new FileInfo(Path.Combine(testDirectory.FullName, "FileTwo"));
+ FileInfo fileThree = new FileInfo(Path.Combine(testSubdirectory.FullName, "FileThree"));
+ FileInfo fileFour = new FileInfo(Path.Combine(testSubdirectory.FullName, "FileFour"));
+
+ fileOne.Create().Dispose();
+ fileTwo.Create().Dispose();
+ fileThree.Create().Dispose();
+ fileFour.Create().Dispose();
+
+ string[] paths = GetPaths(testDirectory.FullName, "file*", new EnumerationOptions { MatchCasing = MatchCasing.CaseSensitive, RecurseSubdirectories = true });
+
+ Assert.Empty(paths);
+
+ paths = GetPaths(testDirectory.FullName, "file*", new EnumerationOptions { MatchCasing = MatchCasing.CaseInsensitive, RecurseSubdirectories = true });
+ FSAssert.EqualWhenOrdered(new string[] { fileOne.FullName, fileTwo.FullName, fileThree.FullName, fileFour.FullName }, paths);
+
+ paths = GetPaths(testDirectory.FullName, "FileT*", new EnumerationOptions { MatchCasing = MatchCasing.CaseSensitive, RecurseSubdirectories = true });
+ FSAssert.EqualWhenOrdered(new string[] { fileTwo.FullName, fileThree.FullName }, paths);
+
+ paths = GetPaths(testDirectory.FullName, "File???", new EnumerationOptions { MatchCasing = MatchCasing.CaseSensitive, RecurseSubdirectories = true });
+ FSAssert.EqualWhenOrdered(new string[] { fileOne.FullName, fileTwo.FullName }, paths);
+ }
+ }
+
+ public class MatchCasingTests_Directory_GetFiles : MatchCasingTests
+ {
+ protected override string[] GetPaths(string directory, string pattern, EnumerationOptions options)
+ {
+ return Directory.GetFiles(directory, pattern, options);
+ }
+ }
+
+ public class MatchCasingTests_DirectoryInfo_GetFiles : MatchCasingTests
+ {
+ protected override string[] GetPaths(string directory, string pattern, EnumerationOptions options)
+ {
+ return new DirectoryInfo(directory).GetFiles(pattern, options).Select(i => i.FullName).ToArray();
+ }
+ }
+}
diff --git a/src/System.IO.FileSystem/tests/Enumeration/MatchTypesTests.netcoreapp.cs b/src/System.IO.FileSystem/tests/Enumeration/MatchTypesTests.netcoreapp.cs
new file mode 100644
index 0000000000..49b8e1b9e0
--- /dev/null
+++ b/src/System.IO.FileSystem/tests/Enumeration/MatchTypesTests.netcoreapp.cs
@@ -0,0 +1,80 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Linq;
+using Xunit;
+
+namespace System.IO.Tests.Enumeration
+{
+ public abstract class MatchTypesTests : FileSystemTest
+ {
+ protected abstract string[] GetPaths(string directory, string pattern, EnumerationOptions options);
+
+ [Fact]
+ public void QuestionMarkBehavior()
+ {
+ DirectoryInfo testDirectory = Directory.CreateDirectory(GetTestFilePath());
+ FileInfo fileOne = new FileInfo(Path.Combine(testDirectory.FullName, "a.one"));
+ FileInfo fileTwo = new FileInfo(Path.Combine(testDirectory.FullName, "ab.two"));
+ FileInfo fileThree = new FileInfo(Path.Combine(testDirectory.FullName, "abc.three"));
+
+ fileOne.Create().Dispose();
+ fileTwo.Create().Dispose();
+ fileThree.Create().Dispose();
+
+ // Question marks collapse to periods in Win32
+ string[] paths = GetPaths(testDirectory.FullName, "a??.*", new EnumerationOptions { MatchType = MatchType.Win32 });
+ FSAssert.EqualWhenOrdered(new string[] { fileOne.FullName, fileTwo.FullName, fileThree.FullName }, paths);
+
+ paths = GetPaths(testDirectory.FullName, "*.?????", new EnumerationOptions { MatchType = MatchType.Win32 });
+ FSAssert.EqualWhenOrdered(new string[] { fileOne.FullName, fileTwo.FullName, fileThree.FullName }, paths);
+
+ // Simple, one question mark is one character
+ paths = GetPaths(testDirectory.FullName, "a??.*", new EnumerationOptions { MatchType = MatchType.Simple });
+ FSAssert.EqualWhenOrdered(new string[] { fileThree.FullName }, paths);
+
+ paths = GetPaths(testDirectory.FullName, "*.?????", new EnumerationOptions { MatchType = MatchType.Simple });
+ FSAssert.EqualWhenOrdered(new string[] { fileThree.FullName }, paths);
+ }
+
+ [Fact]
+ public void StarDotBehavior()
+ {
+ DirectoryInfo testDirectory = Directory.CreateDirectory(GetTestFilePath());
+ FileInfo fileOne = new FileInfo(Path.Combine(testDirectory.FullName, "one"));
+ FileInfo fileTwo = new FileInfo(Path.Combine(testDirectory.FullName, "one.two"));
+ string fileThree = Path.Combine(testDirectory.FullName, "three.");
+
+ fileOne.Create().Dispose();
+ fileTwo.Create().Dispose();
+
+ // Need extended device syntax to create a name with a trailing dot.
+ File.Create(PlatformDetection.IsWindows ? @"\\?\" + fileThree : fileThree).Dispose();
+
+ // *. means any file without an extension
+ string[] paths = GetPaths(testDirectory.FullName, "*.", new EnumerationOptions { MatchType = MatchType.Win32 });
+ FSAssert.EqualWhenOrdered(new string[] { fileOne.FullName, fileThree }, paths);
+
+ // Simple, anything with a trailing period
+ paths = GetPaths(testDirectory.FullName, "*.", new EnumerationOptions { MatchType = MatchType.Simple });
+ FSAssert.EqualWhenOrdered(new string[] { fileThree }, paths);
+ }
+ }
+
+ public class MatchTypesTests_Directory_GetFiles : MatchTypesTests
+ {
+ protected override string[] GetPaths(string directory, string pattern, EnumerationOptions options)
+ {
+ return Directory.GetFiles(directory, pattern, options);
+ }
+ }
+
+ public class MatchTypesTests_DirectoryInfo_GetFiles : MatchTypesTests
+ {
+ protected override string[] GetPaths(string directory, string pattern, EnumerationOptions options)
+ {
+ return new DirectoryInfo(directory).GetFiles(pattern, options).Select(i => i.FullName).ToArray();
+ }
+ }
+}
diff --git a/src/System.IO.FileSystem/tests/Enumeration/PatternTransformTests.netcoreapp.cs b/src/System.IO.FileSystem/tests/Enumeration/PatternTransformTests.netcoreapp.cs
new file mode 100644
index 0000000000..9cb33e5853
--- /dev/null
+++ b/src/System.IO.FileSystem/tests/Enumeration/PatternTransformTests.netcoreapp.cs
@@ -0,0 +1,126 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Linq;
+using Xunit;
+
+namespace System.IO.Tests.Enumeration
+{
+ public class PatternTransformTests_Directory : FileSystemTest
+ {
+ protected virtual string[] GetFiles(string directory, string pattern)
+ {
+ return Directory.GetFiles(directory, pattern);
+ }
+
+ protected virtual string[] GetFiles(string directory, string pattern, EnumerationOptions options)
+ {
+ return Directory.GetFiles(directory, pattern, options);
+ }
+
+ [Theory,
+ InlineData("."),
+ InlineData("*.*")]
+ public void GetFiles_WildcardPatternIsTranslated(string pattern)
+ {
+ DirectoryInfo testDirectory = Directory.CreateDirectory(GetTestFilePath());
+ FileInfo fileOne = new FileInfo(Path.Combine(testDirectory.FullName, "File.One"));
+ FileInfo fileTwo = new FileInfo(Path.Combine(testDirectory.FullName, "FileTwo"));
+ fileOne.Create().Dispose();
+ fileTwo.Create().Dispose();
+ string[] results = GetFiles(testDirectory.FullName, pattern);
+ FSAssert.EqualWhenOrdered(new string[] { fileOne.FullName, fileTwo.FullName }, results);
+
+ results = GetFiles(testDirectory.FullName, pattern, new EnumerationOptions { MatchType = MatchType.Win32 });
+ FSAssert.EqualWhenOrdered(new string[] { fileOne.FullName, fileTwo.FullName }, results);
+ }
+
+ [Fact]
+ public void GetFiles_WildcardPatternIsNotTranslated()
+ {
+ DirectoryInfo testDirectory = Directory.CreateDirectory(GetTestFilePath());
+ FileInfo fileOne = new FileInfo(Path.Combine(testDirectory.FullName, "File.One"));
+ FileInfo fileTwo = new FileInfo(Path.Combine(testDirectory.FullName, "FileTwo"));
+ fileOne.Create().Dispose();
+ fileTwo.Create().Dispose();
+ string[] results = GetFiles(testDirectory.FullName, ".", new EnumerationOptions());
+ Assert.Empty(results);
+
+ results = GetFiles(testDirectory.FullName, "*.*", new EnumerationOptions());
+ Assert.Equal(new string[] { fileOne.FullName }, results);
+ }
+
+ [Fact]
+ public void GetFiles_EmptyPattern()
+ {
+ DirectoryInfo testDirectory = Directory.CreateDirectory(GetTestFilePath());
+ FileInfo fileOne = new FileInfo(Path.Combine(testDirectory.FullName, "File.One"));
+ FileInfo fileTwo = new FileInfo(Path.Combine(testDirectory.FullName, "FileTwo"));
+ fileOne.Create().Dispose();
+ fileTwo.Create().Dispose();
+
+ // We allow for expression to be "foo\" which would translate to "foo\*".
+ string[] results = GetFiles(testDirectory.Parent.FullName, testDirectory.Name + Path.DirectorySeparatorChar);
+ FSAssert.EqualWhenOrdered(new string[] { fileOne.FullName, fileTwo.FullName }, results);
+
+ results = GetFiles(testDirectory.Parent.FullName, testDirectory.Name + Path.AltDirectorySeparatorChar);
+ FSAssert.EqualWhenOrdered(new string[] { fileOne.FullName, fileTwo.FullName }, results);
+
+ results = GetFiles(testDirectory.FullName, string.Empty);
+ FSAssert.EqualWhenOrdered(new string[] { fileOne.FullName, fileTwo.FullName }, results);
+ }
+
+ [Fact]
+ [PlatformSpecific(TestPlatforms.AnyUnix)]
+ public void GetFiles_EmptyPattern_Unix()
+ {
+ DirectoryInfo testDirectory = Directory.CreateDirectory(GetTestFilePath());
+ FileInfo fileOne = new FileInfo(Path.Combine(testDirectory.FullName, "File\\One"));
+ FileInfo fileTwo = new FileInfo(Path.Combine(testDirectory.FullName, "FileTwo"));
+ fileOne.Create().Dispose();
+ fileTwo.Create().Dispose();
+
+ // We allow for expression to be "foo\" which would translate to "foo\*". On Unix we should not be
+ // considering the backslash as a directory separator.
+ string[] results = GetFiles(testDirectory.FullName, "File\\One");
+ Assert.Equal(new string[] { fileOne.FullName }, results);
+ }
+
+ [Fact]
+ [PlatformSpecific(TestPlatforms.AnyUnix)]
+ public void GetFiles_ExtendedDosWildcards_Unix()
+ {
+ // The extended wildcards ('"', '<', and '>') should not be considered on Unix, even when doing DOS style matching.
+ // Getting these behaviors requires using the FileSystemEnumerable/Enumerator directly.
+ DirectoryInfo testDirectory = Directory.CreateDirectory(GetTestFilePath());
+ FileInfo fileOne = new FileInfo(Path.Combine(testDirectory.FullName, "File\"One"));
+ FileInfo fileTwo = new FileInfo(Path.Combine(testDirectory.FullName, "File<Two"));
+ FileInfo fileThree = new FileInfo(Path.Combine(testDirectory.FullName, "File>Three"));
+ fileOne.Create().Dispose();
+ fileTwo.Create().Dispose();
+ fileThree.Create().Dispose();
+
+ string[] results = GetFiles(testDirectory.FullName, "*\"*");
+ Assert.Equal(new string[] { fileOne.FullName }, results);
+ results = GetFiles(testDirectory.FullName, "*<*");
+ Assert.Equal(new string[] { fileTwo.FullName }, results);
+ results = GetFiles(testDirectory.FullName, "*>*");
+ Assert.Equal(new string[] { fileThree.FullName }, results);
+ }
+ }
+
+ public class PatternTransformTests_DirectoryInfo : PatternTransformTests_Directory
+ {
+
+ protected override string[] GetFiles(string directory, string pattern)
+ {
+ return new DirectoryInfo(directory).GetFiles(pattern).Select(i => i.FullName).ToArray();
+ }
+
+ protected override string[] GetFiles(string directory, string pattern, EnumerationOptions options)
+ {
+ return new DirectoryInfo(directory).GetFiles(pattern, options).Select(i => i.FullName).ToArray();
+ }
+ }
+}
diff --git a/src/System.IO.FileSystem/tests/Enumeration/RootTests.netcoreapp.cs b/src/System.IO.FileSystem/tests/Enumeration/RootTests.netcoreapp.cs
new file mode 100644
index 0000000000..91b1376ede
--- /dev/null
+++ b/src/System.IO.FileSystem/tests/Enumeration/RootTests.netcoreapp.cs
@@ -0,0 +1,59 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.IO.Enumeration;
+using Xunit;
+
+namespace System.IO.Tests.Enumeration
+{
+ public class RootTests
+ {
+ private class DirectoryRecursed : FileSystemEnumerator<string>
+ {
+ public string LastDirectory { get; private set; }
+
+ public DirectoryRecursed(string directory, EnumerationOptions options)
+ : base(directory, options)
+ {
+ }
+
+ protected override bool ShouldIncludeEntry(ref FileSystemEntry entry)
+ => !entry.IsDirectory;
+
+ protected override string TransformEntry(ref FileSystemEntry entry)
+ => entry.ToFullPath();
+
+ protected override bool ShouldRecurseIntoEntry(ref FileSystemEntry entry)
+ {
+ LastDirectory = new string(entry.Directory);
+ return false;
+ }
+ }
+
+ [Fact]
+ public void CanRecurseFromRoot()
+ {
+ string root = Path.GetPathRoot(Path.GetTempPath());
+
+ using (var recursed = new DirectoryRecursed(root, new EnumerationOptions { AttributesToSkip = FileAttributes.System, RecurseSubdirectories = true }))
+ {
+ while (recursed.MoveNext())
+ {
+ if (recursed.LastDirectory != null)
+ {
+ Assert.Equal(root, recursed.LastDirectory);
+ return;
+ }
+
+ // Should start with the root and shouldn't have a separator after the root
+ Assert.StartsWith(root, recursed.Current);
+ Assert.True(recursed.Current.LastIndexOf(Path.DirectorySeparatorChar) < root.Length,
+ $"should have no separators pasth the root '{root}' in in '{recursed.Current}'");
+ }
+
+ Assert.NotNull(recursed.LastDirectory);
+ }
+ }
+ }
+}
diff --git a/src/System.IO.FileSystem/tests/Enumeration/SkipAttributeTests.netcoreapp.cs b/src/System.IO.FileSystem/tests/Enumeration/SkipAttributeTests.netcoreapp.cs
new file mode 100644
index 0000000000..39e4d84324
--- /dev/null
+++ b/src/System.IO.FileSystem/tests/Enumeration/SkipAttributeTests.netcoreapp.cs
@@ -0,0 +1,107 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.IO.Enumeration;
+using System.Linq;
+using Xunit;
+
+namespace System.IO.Tests.Enumeration
+{
+ public class SkipAttributeTests : FileSystemTest
+ {
+ protected virtual string[] GetPaths(string directory, EnumerationOptions options)
+ {
+ return new FileSystemEnumerable<string>(
+ directory,
+ (ref FileSystemEntry entry) => entry.ToFullPath(),
+ options)
+ {
+ ShouldIncludePredicate = (ref FileSystemEntry entry) => { return !entry.IsDirectory; }
+ }.ToArray();
+ }
+
+ [Fact]
+ public void SkippingHiddenFiles()
+ {
+ DirectoryInfo testDirectory = Directory.CreateDirectory(GetTestFilePath());
+ DirectoryInfo testSubdirectory = Directory.CreateDirectory(Path.Combine(testDirectory.FullName, GetTestFileName()));
+ FileInfo fileOne = new FileInfo(Path.Combine(testDirectory.FullName, GetTestFileName()));
+
+ // Put a period in front to make it hidden on Unix
+ FileInfo fileTwo = new FileInfo(Path.Combine(testDirectory.FullName, "." + GetTestFileName()));
+ FileInfo fileThree = new FileInfo(Path.Combine(testSubdirectory.FullName, GetTestFileName()));
+ FileInfo fileFour = new FileInfo(Path.Combine(testSubdirectory.FullName, "." + GetTestFileName()));
+
+ fileOne.Create().Dispose();
+ fileTwo.Create().Dispose();
+ if (PlatformDetection.IsWindows)
+ fileTwo.Attributes = fileTwo.Attributes | FileAttributes.Hidden;
+ fileThree.Create().Dispose();
+ fileFour.Create().Dispose();
+ if (PlatformDetection.IsWindows)
+ fileFour.Attributes = fileTwo.Attributes | FileAttributes.Hidden;
+
+ // Default EnumerationOptions is to skip hidden
+ string[] paths = GetPaths(testDirectory.FullName, new EnumerationOptions());
+ Assert.Equal(new string[] { fileOne.FullName }, paths);
+
+ paths = GetPaths(testDirectory.FullName, new EnumerationOptions { AttributesToSkip = 0 });
+ FSAssert.EqualWhenOrdered(new string[] { fileOne.FullName, fileTwo.FullName }, paths);
+
+ paths = GetPaths(testDirectory.FullName, new EnumerationOptions { RecurseSubdirectories = true });
+ Assert.Equal(new string[] { fileOne.FullName, fileThree.FullName }, paths);
+
+ if (PlatformDetection.IsWindows)
+ {
+ // Shouldn't recurse into the subdirectory now that it is hidden
+ testSubdirectory.Attributes = testSubdirectory.Attributes | FileAttributes.Hidden;
+ }
+ else
+ {
+ Directory.Move(testSubdirectory.FullName, Path.Combine(testDirectory.FullName, "." + testSubdirectory.Name));
+ }
+
+ paths = GetPaths(testDirectory.FullName, new EnumerationOptions { RecurseSubdirectories = true });
+ Assert.Equal(new string[] { fileOne.FullName }, paths);
+ }
+
+ [Fact]
+ public void SkipComesFirst()
+ {
+ // If skip comes first we shouldn't find ourselves recursing.
+ DirectoryInfo testDirectory = Directory.CreateDirectory(GetTestFilePath());
+ DirectoryInfo testSubdirectory = Directory.CreateDirectory(Path.Combine(testDirectory.FullName, GetTestFileName()));
+
+ FileInfo fileOne = new FileInfo(Path.Combine(testDirectory.FullName, GetTestFileName()));
+ FileInfo fileTwo = new FileInfo(Path.Combine(testDirectory.FullName, GetTestFileName()));
+
+ FileInfo fileThree = new FileInfo(Path.Combine(testSubdirectory.FullName, GetTestFileName()));
+ FileInfo fileFour = new FileInfo(Path.Combine(testSubdirectory.FullName, GetTestFileName()));
+
+ fileOne.Create().Dispose();
+ fileTwo.Create().Dispose();
+ fileThree.Create().Dispose();
+ fileFour.Create().Dispose();
+
+ string[] paths = GetPaths(testDirectory.FullName, new EnumerationOptions { AttributesToSkip = FileAttributes.Directory, RecurseSubdirectories = true });
+ FSAssert.EqualWhenOrdered(new string[] { fileOne.FullName, fileTwo.FullName }, paths);
+ }
+ }
+
+ public class SkipAttributeTests_Directory_GetFiles : SkipAttributeTests
+ {
+ protected override string[] GetPaths(string directory, EnumerationOptions options)
+ {
+ return Directory.GetFiles(directory, "*", options);
+ }
+ }
+
+ public class SkipAttributeTests_DirectoryInfo_GetFiles : SkipAttributeTests
+ {
+ protected override string[] GetPaths(string directory, EnumerationOptions options)
+ {
+ return new DirectoryInfo(directory).GetFiles("*", options).Select(i => i.FullName).ToArray();
+ }
+ }
+}
diff --git a/src/System.IO.FileSystem/tests/Enumeration/SpecialDirectoryTests.netcoreapp.cs b/src/System.IO.FileSystem/tests/Enumeration/SpecialDirectoryTests.netcoreapp.cs
new file mode 100644
index 0000000000..5043190cff
--- /dev/null
+++ b/src/System.IO.FileSystem/tests/Enumeration/SpecialDirectoryTests.netcoreapp.cs
@@ -0,0 +1,76 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.IO.Enumeration;
+using System.Linq;
+using Xunit;
+
+namespace System.IO.Tests.Enumeration
+{
+
+ public class SpecialDirectoryTests : FileSystemTest
+ {
+ private class DirectoryRecursed : FileSystemEnumerator<string>
+ {
+ public int ShouldRecurseCalls { get; private set; }
+
+ public DirectoryRecursed(string directory, EnumerationOptions options)
+ : base(directory, options)
+ {
+ }
+
+ protected override string TransformEntry(ref FileSystemEntry entry)
+ =>new string(entry.FileName);
+
+ protected override bool ShouldRecurseIntoEntry(ref FileSystemEntry entry)
+ {
+ ShouldRecurseCalls++;
+ return base.ShouldRecurseIntoEntry(ref entry);
+ }
+ }
+
+ [Fact]
+ public void SpecialDirectoriesAreNotUpForRecursion()
+ {
+ using (var recursed = new DirectoryRecursed(TestDirectory, new EnumerationOptions { ReturnSpecialDirectories = true, RecurseSubdirectories = true, AttributesToSkip = 0 }))
+ {
+ List<string> results = new List<string>();
+ while (recursed.MoveNext())
+ results.Add(recursed.Current);
+
+ Assert.Equal(0, recursed.ShouldRecurseCalls);
+ Assert.Contains("..", results);
+ }
+ }
+ }
+
+ public class SpecialDirectoryTests_Enumerable : FileSystemTest
+ {
+ protected virtual string[] GetNames(string directory, EnumerationOptions options)
+ {
+ return new FileSystemEnumerable<string>(
+ directory,
+ (ref FileSystemEntry entry) => new string(entry.FileName),
+ options).ToArray();
+ }
+
+ [Fact]
+ public void SkippingHiddenFiles()
+ {
+ // Files that begin with periods are considered hidden on Unix
+ string[] paths = GetNames(TestDirectory, new EnumerationOptions { ReturnSpecialDirectories = true, AttributesToSkip = 0 });
+ Assert.Contains(".", paths);
+ Assert.Contains("..", paths);
+ }
+ }
+
+ public class SpecialDirectoryTests_DirectoryInfo_GetDirectories : SpecialDirectoryTests_Enumerable
+ {
+ protected override string[] GetNames(string directory, EnumerationOptions options)
+ {
+ return new DirectoryInfo(directory).GetDirectories("*", options).Select(i => i.Name).ToArray();
+ }
+ }
+}
diff --git a/src/System.IO.FileSystem/tests/Enumeration/TrimmedPaths.netcoreapp.cs b/src/System.IO.FileSystem/tests/Enumeration/TrimmedPaths.netcoreapp.cs
new file mode 100644
index 0000000000..ed73117634
--- /dev/null
+++ b/src/System.IO.FileSystem/tests/Enumeration/TrimmedPaths.netcoreapp.cs
@@ -0,0 +1,284 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Linq;
+using Xunit;
+
+namespace System.IO.Tests.Enumeration
+{
+ public class TrimmedPaths : FileSystemTest
+ {
+ [Fact]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void TrimmedPathsAreFound_Windows()
+ {
+ // Trailing spaces and periods are eaten when normalizing in Windows, making them impossible
+ // to access without using the \\?\ device syntax. We should, however, be able to find them
+ // and retain the filename in the info classes and string results.
+
+ DirectoryInfo directory = Directory.CreateDirectory(GetTestFilePath());
+ File.Create(@"\\?\" + Path.Combine(directory.FullName, "Trailing space ")).Dispose();
+ File.Create(@"\\?\" + Path.Combine(directory.FullName, "Trailing period.")).Dispose();
+
+ FileInfo[] files = directory.GetFiles();
+ Assert.Equal(2, files.Count());
+ FSAssert.EqualWhenOrdered(new string[] { "Trailing space ", "Trailing period." }, files.Select(f => f.Name));
+
+ var paths = Directory.GetFiles(directory.FullName);
+ Assert.Equal(2, paths.Count());
+ FSAssert.EqualWhenOrdered(new string[] { "Trailing space ", "Trailing period." }, paths.Select(p => Path.GetFileName(p)));
+ }
+
+ [Fact]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void TrimmedPathsDeletion_Windows()
+ {
+ // Trailing spaces and periods are eaten when normalizing in Windows, making them impossible
+ // to access without using the \\?\ device syntax. We should, however, be able to delete them
+ // from the info class.
+
+ DirectoryInfo directory = Directory.CreateDirectory(GetTestFilePath());
+ File.Create(@"\\?\" + Path.Combine(directory.FullName, "Trailing space ")).Dispose();
+ File.Create(@"\\?\" + Path.Combine(directory.FullName, "Trailing period.")).Dispose();
+
+ // With just a path name, the trailing space/period will get eaten, so we
+ // can't delete without prepending- they won't "exist".
+ var paths = Directory.GetFiles(directory.FullName);
+ Assert.All(paths, p => Assert.False(File.Exists(p)));
+
+ FileInfo[] files = directory.GetFiles();
+ Assert.Equal(2, files.Count());
+ Assert.All(files, f => Assert.True(f.Exists));
+ foreach (FileInfo f in files)
+ f.Refresh();
+ Assert.All(files, f => Assert.True(f.Exists));
+ foreach (FileInfo f in files)
+ {
+ f.Delete();
+ f.Refresh();
+ }
+ Assert.All(files, f => Assert.False(f.Exists));
+
+ foreach (FileInfo f in files)
+ {
+ f.Create().Dispose();
+ f.Refresh();
+ }
+ Assert.All(files, f => Assert.True(f.Exists));
+ }
+
+ [Fact]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void TrimmedPathsOpen_Windows()
+ {
+ // Trailing spaces and periods are eaten when normalizing in Windows, making them impossible
+ // to access without using the \\?\ device syntax. We should, however, be able to open them
+ // from the info class when enumerating.
+
+ DirectoryInfo directory = Directory.CreateDirectory(GetTestFilePath());
+ string fileOne = Path.Join(directory.FullName, "Trailing space ");
+ string fileTwo = Path.Join(directory.FullName, "Trailing period.");
+ File.Create(@"\\?\" + fileOne).Dispose();
+ File.Create(@"\\?\" + fileTwo).Dispose();
+
+ FileInfo[] files = directory.GetFiles();
+ Assert.Equal(2, files.Length);
+ foreach (FileInfo fi in directory.GetFiles())
+ {
+ // Shouldn't throw hitting any of the Open overloads
+ using (FileStream stream = fi.Open(FileMode.Open))
+ { }
+ using (FileStream stream = fi.Open(FileMode.Open, FileAccess.Read))
+ { }
+ using (FileStream stream = fi.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
+ { }
+ using (FileStream stream = fi.OpenRead())
+ { }
+ using (FileStream stream = fi.OpenWrite())
+ { }
+ }
+ }
+
+ [Fact]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void TrimmedPathsText_Windows()
+ {
+ // Trailing spaces and periods are eaten when normalizing in Windows, making them impossible
+ // to access without using the \\?\ device syntax. We should, however, be able to open readers
+ // and writers from the the info class when enumerating.
+
+ DirectoryInfo directory = Directory.CreateDirectory(GetTestFilePath());
+ string fileOne = Path.Join(directory.FullName, "Trailing space ");
+ string fileTwo = Path.Join(directory.FullName, "Trailing period.");
+ File.WriteAllText(@"\\?\" + fileOne, "space");
+ File.WriteAllText(@"\\?\" + fileTwo, "period");
+
+ FileInfo[] files = directory.GetFiles();
+ Assert.Equal(2, files.Length);
+ foreach (FileInfo fi in directory.GetFiles())
+ {
+ using (StreamReader reader = fi.OpenText())
+ {
+ string content = reader.ReadToEnd();
+ if (fi.FullName.EndsWith(fileOne))
+ {
+ Assert.Equal("space", content);
+ }
+ else if (fi.FullName.EndsWith(fileTwo))
+ {
+ Assert.Equal("period", content);
+ }
+ else
+ {
+ Assert.False(true, $"Unexpected name '{fi.FullName}'");
+ }
+ }
+
+ using (StreamWriter writer = fi.CreateText())
+ {
+ writer.Write("foo");
+ }
+
+ using (StreamReader reader = fi.OpenText())
+ {
+ Assert.Equal("foo", reader.ReadToEnd());
+ }
+
+ using (StreamWriter writer = fi.AppendText())
+ {
+ writer.Write("bar");
+ }
+
+ using (StreamReader reader = fi.OpenText())
+ {
+ Assert.Equal("foobar", reader.ReadToEnd());
+ }
+ }
+ }
+
+ [Fact]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void TrimmedPathsCopyTo_Windows()
+ {
+ // Trailing spaces and periods are eaten when normalizing in Windows, making them impossible
+ // to access without using the \\?\ device syntax. We should, however, be able to copy them
+ // without the special syntax from the info class when enumerating.
+
+ DirectoryInfo directory = Directory.CreateDirectory(GetTestFilePath());
+ string fileOne = Path.Join(directory.FullName, "Trailing space ");
+ string fileTwo = Path.Join(directory.FullName, "Trailing period.");
+ File.Create(@"\\?\" + fileOne).Dispose();
+ File.Create(@"\\?\" + fileTwo).Dispose();
+
+ FileInfo[] files = directory.GetFiles();
+ Assert.Equal(2, files.Length);
+ foreach (FileInfo fi in directory.GetFiles())
+ {
+ FileInfo newInfo = fi.CopyTo(Path.Join(directory.FullName, GetTestFileName()));
+ Assert.True(newInfo.Exists);
+ FileInfo newerInfo = fi.CopyTo(Path.Join(directory.FullName, GetTestFileName()), overwrite: true);
+ Assert.True(newerInfo.Exists);
+ }
+
+ Assert.Equal(6, directory.GetFiles().Length);
+ }
+
+ [Fact]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void TrimmedPathsReplace_Windows()
+ {
+ // Trailing spaces and periods are eaten when normalizing in Windows, making them impossible
+ // to access without using the \\?\ device syntax. We should, however, be able to replace them
+ // from the info class when enumerating.
+
+ DirectoryInfo directory = Directory.CreateDirectory(GetTestFilePath());
+ string fileOne = Path.Join(directory.FullName, "Trailing space ");
+ string fileTwo = Path.Join(directory.FullName, "Trailing period.");
+ File.WriteAllText(@"\\?\" + fileOne, "space");
+ File.WriteAllText(@"\\?\" + fileTwo, "period");
+
+ FileInfo[] files = directory.GetFiles();
+ Assert.Equal(2, files.Length);
+
+ FileInfo destination = new FileInfo(Path.Join(directory.FullName, GetTestFileName()));
+ destination.Create().Dispose();
+
+ foreach (FileInfo fi in files)
+ {
+ fi.Replace(destination.FullName, null);
+ using (StreamReader reader = destination.OpenText())
+ {
+ string content = reader.ReadToEnd();
+ if (fi.FullName.EndsWith(fileOne))
+ {
+ Assert.Equal("space", content);
+ }
+ else if (fi.FullName.EndsWith(fileTwo))
+ {
+ Assert.Equal("period", content);
+ }
+ else
+ {
+ Assert.False(true, $"Unexpected name '{fi.FullName}'");
+ }
+ }
+ }
+ }
+
+ [Fact]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void TrimmedPathsMoveTo_Windows()
+ {
+ // Trailing spaces and periods are eaten when normalizing in Windows, making them impossible
+ // to access without using the \\?\ device syntax. We should, however, be able to move them
+ // without the special syntax from the info class when enumerating.
+
+ DirectoryInfo directory = Directory.CreateDirectory(GetTestFilePath());
+ DirectoryInfo spaceDirectory = Directory.CreateDirectory(Path.Join(@"\\?\", directory.FullName, "Trailing space "));
+ DirectoryInfo periodDirectory = Directory.CreateDirectory(Path.Join(@"\\?\", directory.FullName, "Trailing period."));
+ string spaceFile = Path.Join(spaceDirectory.FullName, "space");
+ string periodFile = Path.Join(periodDirectory.FullName, "period");
+ File.Create(spaceFile).Dispose();
+ File.Create(periodFile).Dispose();
+
+ DirectoryInfo[] directories = directory.GetDirectories();
+ Assert.Equal(2, directories.Length);
+ foreach (DirectoryInfo di in directories)
+ {
+ if (di.Name == "Trailing space ")
+ {
+ di.MoveTo(Path.Join(directory.FullName, "WasSpace"));
+ }
+ else if (di.Name == "Trailing period.")
+ {
+ di.MoveTo(Path.Join(directory.FullName, "WasPeriod"));
+ }
+ else
+ {
+ Assert.False(true, $"Found unexpected name '{di.Name}'");
+ }
+ }
+
+ directories = directory.GetDirectories();
+ Assert.Equal(2, directories.Length);
+ foreach (DirectoryInfo di in directories)
+ {
+ if (di.Name == "WasSpace")
+ {
+ FileInfo fi = di.GetFiles().Single();
+ Assert.Equal("space", fi.Name);
+ }
+ else if (di.Name == "WasPeriod")
+ {
+ FileInfo fi = di.GetFiles().Single();
+ Assert.Equal("period", fi.Name);
+ }
+ else
+ {
+ Assert.False(true, $"Found unexpected name '{di.Name}'");
+ }
+ }
+ }
+ }
+}
diff --git a/src/System.IO.FileSystem/tests/FSAssert.cs b/src/System.IO.FileSystem/tests/FSAssert.cs
index 9fbefaa874..10125d8537 100644
--- a/src/System.IO.FileSystem/tests/FSAssert.cs
+++ b/src/System.IO.FileSystem/tests/FSAssert.cs
@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Collections.Generic;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
@@ -62,5 +64,10 @@ namespace System.IO.Tests
Assert.NotNull(tce);
Assert.Equal(ct, tce.CancellationToken);
}
+
+ public static void EqualWhenOrdered<T>(IEnumerable<T> expected, IEnumerable<T> actual)
+ {
+ Assert.Equal(expected.OrderBy(e => e).Select(o => o), actual.OrderBy(a => a).Select(o => o));
+ }
}
}
diff --git a/src/System.IO.FileSystem/tests/File/Copy.cs b/src/System.IO.FileSystem/tests/File/Copy.cs
index 036dedae6a..1caca2aae1 100644
--- a/src/System.IO.FileSystem/tests/File/Copy.cs
+++ b/src/System.IO.FileSystem/tests/File/Copy.cs
@@ -4,23 +4,17 @@
using System.Collections.Generic;
using System.Linq;
-using System.Runtime.InteropServices;
using Xunit;
namespace System.IO.Tests
{
public partial class File_Copy_str_str : FileSystemTest
{
- #region Utilities
-
- public static TheoryData WindowsInvalidUnixValid = new TheoryData<string> { " ", " ", "\n", ">", "<", "\t" };
public virtual void Copy(string source, string dest)
{
File.Copy(source, dest);
}
- #endregion
-
#region UniversalTests
[Fact]
@@ -160,10 +154,11 @@ namespace System.IO.Tests
#region PlatformSpecific
- [Theory,
- MemberData(nameof(WindowsInvalidUnixValid))]
- [PlatformSpecific(TestPlatforms.Windows)] // Whitespace path throws ArgumentException
- public void WindowsWhitespacePath(string invalid)
+ [Theory,
+ InlineData(" "),
+ InlineData(" ")]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void WindowsAllSpacePath(string invalid)
{
string testFile = GetTestFilePath();
File.Create(testFile).Dispose();
@@ -173,24 +168,92 @@ namespace System.IO.Tests
}
[Theory,
- MemberData(nameof(WindowsInvalidUnixValid))]
- [PlatformSpecific(TestPlatforms.AnyUnix)] // Whitespace path allowed
- public void UnixWhitespacePath(string valid)
+ InlineData("\n"),
+ InlineData(">"),
+ InlineData("<"),
+ InlineData("\t")]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)]
+ public void WindowsInvalidCharsPath_Desktop(string invalid)
{
string testFile = GetTestFilePath();
File.Create(testFile).Dispose();
+ Assert.Throws<ArgumentException>(() => Copy(testFile, invalid));
+ Assert.Throws<ArgumentException>(() => Copy(invalid, testFile));
+ }
+
+ [Theory,
+ InlineData("\n"),
+ InlineData(">"),
+ InlineData("<"),
+ InlineData("\t")]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void WindowsInvalidCharsPath_Core(string invalid)
+ {
+ string testFile = GetTestFilePath();
+ File.Create(testFile).Dispose();
+
+ Assert.Throws<IOException>(() => Copy(testFile, invalid));
+ Assert.Throws<IOException>(() => Copy(invalid, testFile));
+ }
+
+ [Theory,
+ InlineData(" "),
+ InlineData(" "),
+ InlineData("\n"),
+ InlineData(">"),
+ InlineData("<"),
+ InlineData("\t")]
+ [PlatformSpecific(TestPlatforms.AnyUnix)]
+ public void UnixInvalidWindowsPaths(string valid)
+ {
+ // Unix allows whitespaces paths that aren't valid on Windows
+ string testFile = GetTestFilePath();
+ File.Create(testFile).Dispose();
+
Copy(testFile, Path.Combine(TestDirectory, valid));
Assert.True(File.Exists(testFile));
Assert.True(File.Exists(Path.Combine(TestDirectory, valid)));
}
+
+ [Theory,
+ InlineData("", ":bar"),
+ InlineData("", ":bar:$DATA"),
+ InlineData("::$DATA", ":bar"),
+ InlineData("::$DATA", ":bar:$DATA")]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void WindowsAlternateDataStream(string defaultStream, string alternateStream)
+ {
+ DirectoryInfo testDirectory = Directory.CreateDirectory(GetTestFilePath());
+ string testFile = Path.Combine(testDirectory.FullName, GetTestFileName());
+ string testFileDefaultStream = testFile + defaultStream;
+ string testFileAlternateStream = testFile + alternateStream;
+
+ // Copy the default stream into an alternate stream
+ File.WriteAllText(testFileDefaultStream, "Foo");
+ Copy(testFileDefaultStream, testFileAlternateStream);
+ Assert.Equal(testFile, testDirectory.GetFiles().Single().FullName);
+ Assert.Equal("Foo", File.ReadAllText(testFileDefaultStream));
+ Assert.Equal("Foo", File.ReadAllText(testFileAlternateStream));
+
+ // Copy another file over the alternate stream
+ string testFile2 = Path.Combine(testDirectory.FullName, GetTestFileName());
+ string testFile2DefaultStream = testFile2 + defaultStream;
+ File.WriteAllText(testFile2DefaultStream, "Bar");
+ Assert.Throws<IOException>(() => Copy(testFile2DefaultStream, testFileAlternateStream));
+
+ // This always throws as you can't copy an alternate stream out (oddly)
+ Assert.Throws<IOException>(() => Copy(testFileAlternateStream, testFile2));
+ Assert.Throws<IOException>(() => Copy(testFileAlternateStream, testFile2 + alternateStream));
+ }
#endregion
}
public class File_Copy_str_str_b : File_Copy_str_str
{
- #region Utilities
-
public override void Copy(string source, string dest)
{
File.Copy(source, dest, false);
@@ -201,10 +264,6 @@ namespace System.IO.Tests
File.Copy(source, dest, overwrite);
}
- #endregion
-
- #region UniversalTests
-
[Fact]
public void OverwriteTrue()
{
@@ -257,6 +316,38 @@ namespace System.IO.Tests
}
}
- #endregion
+ [Theory,
+ InlineData("", ":bar"),
+ InlineData("", ":bar:$DATA"),
+ InlineData("::$DATA", ":bar"),
+ InlineData("::$DATA", ":bar:$DATA")]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void WindowsAlternateDataStreamOverwrite(string defaultStream, string alternateStream)
+ {
+ DirectoryInfo testDirectory = Directory.CreateDirectory(GetTestFilePath());
+ string testFile = Path.Combine(testDirectory.FullName, GetTestFileName());
+ string testFileDefaultStream = testFile + defaultStream;
+ string testFileAlternateStream = testFile + alternateStream;
+
+ // Copy the default stream into an alternate stream
+ File.WriteAllText(testFileDefaultStream, "Foo");
+ Copy(testFileDefaultStream, testFileAlternateStream);
+ Assert.Equal(testFile, testDirectory.GetFiles().Single().FullName);
+ Assert.Equal("Foo", File.ReadAllText(testFileDefaultStream));
+ Assert.Equal("Foo", File.ReadAllText(testFileAlternateStream));
+
+ // Copy another file over the alternate stream
+ string testFile2 = Path.Combine(testDirectory.FullName, GetTestFileName());
+ string testFile2DefaultStream = testFile2 + defaultStream;
+ File.WriteAllText(testFile2DefaultStream, "Bar");
+ Copy(testFile2DefaultStream, testFileAlternateStream, overwrite: true);
+ Assert.Equal("Foo", File.ReadAllText(testFileDefaultStream));
+ Assert.Equal("Bar", File.ReadAllText(testFileAlternateStream));
+
+ // This always throws as you can't copy an alternate stream out (oddly)
+ Assert.Throws<IOException>(() => Copy(testFileAlternateStream, testFile2, overwrite: true));
+ Assert.Throws<IOException>(() => Copy(testFileAlternateStream, testFile2 + alternateStream, overwrite: true));
+ }
}
}
diff --git a/src/System.IO.FileSystem/tests/File/Create.cs b/src/System.IO.FileSystem/tests/File/Create.cs
index d53ac85512..c910e735b3 100644
--- a/src/System.IO.FileSystem/tests/File/Create.cs
+++ b/src/System.IO.FileSystem/tests/File/Create.cs
@@ -8,15 +8,11 @@ namespace System.IO.Tests
{
public class File_Create_str : FileSystemTest
{
- #region Utilities
-
public virtual FileStream Create(string path)
{
return File.Create(path);
}
- #endregion
-
#region UniversalTests
[Fact]
@@ -201,8 +197,9 @@ namespace System.IO.Tests
}
[Fact]
- [PlatformSpecific(TestPlatforms.Windows)] // Invalid file name with wildcard characters on Windows
- public void WindowsWildCharacterPath()
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)]
+ public void WindowsWildCharacterPath_Desktop()
{
DirectoryInfo testDir = Directory.CreateDirectory(GetTestFilePath());
Assert.Throws<ArgumentException>(() => Create(Path.Combine(testDir.FullName, "dls;d", "442349-0", "v443094(*)(+*$#$*", new string(Path.DirectorySeparatorChar, 3))));
@@ -211,20 +208,53 @@ namespace System.IO.Tests
Assert.Throws<ArgumentException>(() => Create(Path.Combine(testDir.FullName, "*Tes*t")));
}
+ [Fact]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void WindowsWildCharacterPath_Core()
+ {
+ DirectoryInfo testDir = Directory.CreateDirectory(GetTestFilePath());
+ Assert.ThrowsAny<IOException>(() => Create(Path.Combine(testDir.FullName, "dls;d", "442349-0", "v443094(*)(+*$#$*", new string(Path.DirectorySeparatorChar, 3))));
+ Assert.ThrowsAny<IOException>(() => Create(Path.Combine(testDir.FullName, "*")));
+ Assert.ThrowsAny<IOException>(() => Create(Path.Combine(testDir.FullName, "Test*t")));
+ Assert.ThrowsAny<IOException>(() => Create(Path.Combine(testDir.FullName, "*Tes*t")));
+ }
+
[Theory,
InlineData(" "),
- InlineData(" "),
+ InlineData(""),
+ InlineData("\0"),
+ InlineData(" ")]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void WindowsEmptyPath(string path)
+ {
+ Assert.Throws<ArgumentException>(() => Create(path));
+ }
+
+ [Theory,
InlineData("\n"),
InlineData(">"),
InlineData("<"),
- InlineData("\0"),
InlineData("\t")]
- [PlatformSpecific(TestPlatforms.Windows)] // Invalid file name with whitespace on Windows
- public void WindowsWhitespacePath(string path)
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)]
+ public void WindowsInvalidPath_Desktop(string path)
{
Assert.Throws<ArgumentException>(() => Create(path));
}
+ [Theory,
+ InlineData("\n"),
+ InlineData(">"),
+ InlineData("<"),
+ InlineData("\t")]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void WindowsInvalidPath_Core(string path)
+ {
+ Assert.ThrowsAny<IOException>(() => Create(Path.Combine(TestDirectory, path)));
+ }
+
[Fact]
[PlatformSpecific(TestPlatforms.AnyUnix)]
public void CreateNullThrows_Unix()
@@ -249,6 +279,49 @@ namespace System.IO.Tests
}
}
+ [Theory,
+ InlineData(":bar"),
+ InlineData(":bar:$DATA"),
+ InlineData("::$DATA")]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void WindowsAlternateDataStream(string streamName)
+ {
+ DirectoryInfo testDirectory = Directory.CreateDirectory(GetTestFilePath());
+ streamName = Path.Combine(testDirectory.FullName, GetTestFileName()) + streamName;
+ using (Create(streamName))
+ {
+ Assert.True(File.Exists(streamName));
+ }
+ }
+
+ [Theory,
+ InlineData(":bar"),
+ InlineData(":bar:$DATA")]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void WindowsAlternateDataStream_OnExisting(string streamName)
+ {
+ DirectoryInfo testDirectory = Directory.CreateDirectory(GetTestFilePath());
+
+ // On closed file
+ string fileName = Path.Combine(testDirectory.FullName, GetTestFileName());
+ Create(fileName).Dispose();
+ streamName = fileName + streamName;
+ using (Create(streamName))
+ {
+ Assert.True(File.Exists(streamName));
+ }
+
+ // On open file
+ fileName = Path.Combine(testDirectory.FullName, GetTestFileName());
+ using (Create(fileName))
+ using (Create(streamName))
+ {
+ Assert.True(File.Exists(streamName));
+ }
+ }
+
#endregion
}
diff --git a/src/System.IO.FileSystem/tests/File/Delete.cs b/src/System.IO.FileSystem/tests/File/Delete.cs
index 398833f102..7cd005f944 100644
--- a/src/System.IO.FileSystem/tests/File/Delete.cs
+++ b/src/System.IO.FileSystem/tests/File/Delete.cs
@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Diagnostics;
using Xunit;
using Xunit.NetCore.Extensions;
@@ -10,8 +9,6 @@ namespace System.IO.Tests
{
public class File_Delete : FileSystemTest
{
- #region Utilities
-
public virtual void Delete(string path)
{
File.Delete(path);
@@ -24,8 +21,6 @@ namespace System.IO.Tests
return ret;
}
- #endregion
-
#region UniversalTests
[Fact]
@@ -129,7 +124,7 @@ namespace System.IO.Tests
[Trait(XunitConstants.Category, XunitConstants.RequiresElevation)]
public void Unix_NonExistentPath_ReadOnlyVolume()
{
- if (PlatformDetection.IsRedHatFamily6)
+ if (PlatformDetection.IsRedHatFamily6 || PlatformDetection.IsAlpine)
return; // [ActiveIssue(https://github.com/dotnet/corefx/issues/21920)]
ReadOnly_FileSystemHelper(readOnlyDirectory =>
@@ -199,6 +194,24 @@ namespace System.IO.Tests
Assert.False(testFile.Exists);
}
+ [Theory,
+ InlineData(":bar"),
+ InlineData(":bar:$DATA")]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void WindowsDeleteAlternateDataStream(string streamName)
+ {
+ FileInfo testFile = Create(GetTestFilePath());
+ testFile.Create().Dispose();
+ streamName = testFile.FullName + streamName;
+ File.Create(streamName).Dispose();
+ Assert.True(File.Exists(streamName));
+ Delete(streamName);
+ Assert.False(File.Exists(streamName));
+ testFile.Refresh();
+ Assert.True(testFile.Exists);
+ }
+
#endregion
}
}
diff --git a/src/System.IO.FileSystem/tests/File/Exists.cs b/src/System.IO.FileSystem/tests/File/Exists.cs
index e1be14a175..24eec6c5cb 100644
--- a/src/System.IO.FileSystem/tests/File/Exists.cs
+++ b/src/System.IO.FileSystem/tests/File/Exists.cs
@@ -231,7 +231,7 @@ namespace System.IO.Tests
[Theory,
- MemberData(nameof(PathsWithAlternativeDataStreams))]
+ MemberData(nameof(PathsWithColons))]
[PlatformSpecific(TestPlatforms.Windows)] // alternate data stream
public void PathWithAlternateDataStreams_ReturnsFalse(string component)
{
diff --git a/src/System.IO.FileSystem/tests/File/GetSetAttributes.cs b/src/System.IO.FileSystem/tests/File/GetSetAttributes.cs
index d290ce7971..7a115ad80b 100644
--- a/src/System.IO.FileSystem/tests/File/GetSetAttributes.cs
+++ b/src/System.IO.FileSystem/tests/File/GetSetAttributes.cs
@@ -18,6 +18,20 @@ namespace System.IO.Tests
Assert.Throws<FileNotFoundException>(() => GetAttributes(GetTestFilePath() + trailingChar));
}
+ // Getting only throws for File, not FileInfo
+ [Theory,
+ InlineData(":bar"),
+ InlineData(":bar:$DATA")]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void GetAttributes_MissingAlternateDataStream_Windows(string streamName)
+ {
+ string path = CreateItem();
+ streamName = path + streamName;
+
+ Assert.Throws<FileNotFoundException>(() => GetAttributes(streamName));
+ }
+
[Theory, MemberData(nameof(TrailingCharacters))]
public void GetAttributes_MissingDirectory(char trailingChar)
{
diff --git a/src/System.IO.FileSystem/tests/File/Move.cs b/src/System.IO.FileSystem/tests/File/Move.cs
index bc1199e122..304094a999 100644
--- a/src/System.IO.FileSystem/tests/File/Move.cs
+++ b/src/System.IO.FileSystem/tests/File/Move.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using Xunit;
+using System.Linq;
namespace System.IO.Tests
{
@@ -44,17 +45,26 @@ namespace System.IO.Tests
}
[Theory, MemberData(nameof(PathsWithInvalidCharacters))]
- public void PathWithIllegalCharacters(string invalidPath)
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)]
+ public void PathWithIllegalCharacters_Desktop(string invalidPath)
{
FileInfo testFile = new FileInfo(GetTestFilePath());
testFile.Create().Dispose();
- // Under legacy normalization we kick \\?\ paths back as invalid with ArgumentException
- // New style we don't prevalidate \\?\ at all
- if (invalidPath.Contains(@"\\?\") && !PathFeatures.IsUsingLegacyPathNormalization())
- Assert.Throws<IOException>(() => Move(testFile.FullName, invalidPath));
- else
+ Assert.Throws<ArgumentException>(() => Move(testFile.FullName, invalidPath));
+ }
+
+ [Theory, MemberData(nameof(PathsWithInvalidCharacters))]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void PathWithIllegalCharacters_Core(string invalidPath)
+ {
+ FileInfo testFile = new FileInfo(GetTestFilePath());
+ testFile.Create().Dispose();
+
+ if (invalidPath.Contains('\0'.ToString()))
Assert.Throws<ArgumentException>(() => Move(testFile.FullName, invalidPath));
+ else
+ Assert.ThrowsAny<IOException>(() => Move(testFile.FullName, invalidPath));
}
[Fact]
@@ -225,17 +235,35 @@ namespace System.IO.Tests
[Theory, MemberData(nameof(PathsWithInvalidColons))]
[PlatformSpecific(TestPlatforms.Windows)]
- [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Versions of netfx older than 4.6.2 throw an ArgumentException instead of NotSupportedException. Until all of our machines run netfx against the actual latest version, these will fail.")]
- public void WindowsPathWithIllegalColons(string invalidPath)
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)]
+ public void WindowsPathWithIllegalColons_Desktop(string invalidPath)
+ {
+ FileInfo testFile = new FileInfo(GetTestFilePath());
+ testFile.Create().Dispose();
+ if (PathFeatures.IsUsingLegacyPathNormalization())
+ {
+ Assert.Throws<ArgumentException>(() => Move(testFile.FullName, invalidPath));
+ }
+ else
+ {
+ Assert.Throws<NotSupportedException>(() => Move(testFile.FullName, invalidPath));
+ }
+ }
+
+ [Theory, MemberData(nameof(PathsWithInvalidColons))]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void WindowsPathWithIllegalColons_Core(string invalidPath)
{
FileInfo testFile = new FileInfo(GetTestFilePath());
testFile.Create().Dispose();
- Assert.Throws<NotSupportedException>(() => Move(testFile.FullName, invalidPath));
+ Assert.ThrowsAny<IOException>(() => Move(testFile.FullName, testFile.DirectoryName + Path.DirectorySeparatorChar + invalidPath));
}
[Fact]
- [PlatformSpecific(TestPlatforms.Windows)] // Wild characters in path throw ArgumentException
- public void WindowsWildCharacterPath()
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)]
+ public void WindowsWildCharacterPath_Desktop()
{
Assert.Throws<ArgumentException>(() => Move("*", GetTestFilePath()));
Assert.Throws<ArgumentException>(() => Move(GetTestFilePath(), "*"));
@@ -244,6 +272,18 @@ namespace System.IO.Tests
}
[Fact]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void WindowsWildCharacterPath_Core()
+ {
+ Assert.Throws<FileNotFoundException>(() => Move(Path.Combine(TestDirectory, "*"), GetTestFilePath()));
+ Assert.Throws<FileNotFoundException>(() => Move(GetTestFilePath(), Path.Combine(TestDirectory, "*")));
+ Assert.Throws<FileNotFoundException>(() => Move(GetTestFilePath(), Path.Combine(TestDirectory, "Test*t")));
+ Assert.Throws<FileNotFoundException>(() => Move(GetTestFilePath(), Path.Combine(TestDirectory, "*Test")));
+ }
+
+
+ [Fact]
[PlatformSpecific(TestPlatforms.AnyUnix)] // Wild characters in path are allowed
public void UnixWildCharacterPath()
{
@@ -268,9 +308,29 @@ namespace System.IO.Tests
}
[Theory,
- MemberData(nameof(WhiteSpace))]
- [PlatformSpecific(TestPlatforms.Windows)] // Whitespace in path throws ArgumentException
- public void WindowsWhitespacePath(string whitespace)
+ MemberData(nameof(ControlWhiteSpace))]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)]
+ public void WindowsControlPath_Desktop(string whitespace)
+ {
+ FileInfo testFile = new FileInfo(GetTestFilePath());
+ Assert.Throws<ArgumentException>(() => Move(testFile.FullName, whitespace));
+ }
+
+ [Theory,
+ MemberData(nameof(ControlWhiteSpace))]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void WindowsControlPath_Core(string whitespace)
+ {
+ FileInfo testFile = new FileInfo(GetTestFilePath());
+ Assert.ThrowsAny<IOException>(() => Move(testFile.FullName, Path.Combine(TestDirectory, whitespace)));
+ }
+
+ [Theory,
+ MemberData(nameof(SimpleWhiteSpace))]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void WindowsSimpleWhitespacePath(string whitespace)
{
FileInfo testFile = new FileInfo(GetTestFilePath());
Assert.Throws<ArgumentException>(() => Move(testFile.FullName, whitespace));
@@ -289,6 +349,29 @@ namespace System.IO.Tests
}
+ [Theory,
+ InlineData("", ":bar"),
+ InlineData("", ":bar:$DATA"),
+ InlineData("::$DATA", ":bar"),
+ InlineData("::$DATA", ":bar:$DATA")]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void WindowsAlternateDataStreamMove(string defaultStream, string alternateStream)
+ {
+ DirectoryInfo testDirectory = Directory.CreateDirectory(GetTestFilePath());
+ string testFile = Path.Combine(testDirectory.FullName, GetTestFileName());
+ string testFileDefaultStream = testFile + defaultStream;
+ string testFileAlternateStream = testFile + alternateStream;
+
+ // Cannot move into an alternate stream
+ File.WriteAllText(testFileDefaultStream, "Foo");
+ Assert.Throws<IOException>(() => Move(testFileDefaultStream, testFileAlternateStream));
+
+ // Cannot move out of an alternate stream
+ File.WriteAllText(testFileAlternateStream, "Bar");
+ string testFile2 = Path.Combine(testDirectory.FullName, GetTestFileName());
+ Assert.Throws<IOException>(() => Move(testFileAlternateStream, testFile2));
+ }
#endregion
}
}
diff --git a/src/System.IO.FileSystem/tests/File/ReadWriteAllBytes.cs b/src/System.IO.FileSystem/tests/File/ReadWriteAllBytes.cs
index 7764cdfe5b..b92e5201bd 100644
--- a/src/System.IO.FileSystem/tests/File/ReadWriteAllBytes.cs
+++ b/src/System.IO.FileSystem/tests/File/ReadWriteAllBytes.cs
@@ -4,6 +4,7 @@
using System.Runtime.InteropServices;
using System.Text;
+using System.Threading.Tasks;
using Xunit;
namespace System.IO.Tests
@@ -120,5 +121,57 @@ namespace System.IO.Tests
File.SetAttributes(path, FileAttributes.Normal);
}
}
+
+ [Fact]
+ public void EmptyFile_ReturnsEmptyArray()
+ {
+ string path = GetTestFilePath();
+ File.Create(path).Dispose();
+ Assert.Equal(0, File.ReadAllBytes(path).Length);
+ }
+
+ [Theory]
+ [PlatformSpecific(TestPlatforms.Linux)]
+ [InlineData("/proc/cmdline")]
+ [InlineData("/proc/version")]
+ [InlineData("/proc/filesystems")]
+ public void ProcFs_EqualsReadAllText(string path)
+ {
+ byte[] bytes = null;
+ string text = null;
+
+ const int NumTries = 3; // some of these could theoretically change between reads, so allow retries just in case
+ for (int i = 1; i <= NumTries; i++)
+ {
+ try
+ {
+ bytes = File.ReadAllBytes(path);
+ text = File.ReadAllText(path);
+ Assert.Equal(text, Encoding.UTF8.GetString(bytes));
+ }
+ catch when (i < NumTries) { }
+ }
+ }
+
+ [Theory]
+ [PlatformSpecific(TestPlatforms.Linux)]
+ public void ReadAllBytes_ProcFs_Uptime_ContainsTwoNumbers()
+ {
+ string text = Encoding.UTF8.GetString(File.ReadAllBytes("/proc/uptime"));
+ string[] parts = text.Split(new [] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
+ Assert.Equal(2, parts.Length);
+ Assert.True(double.TryParse(parts[0].Trim(), out _));
+ Assert.True(double.TryParse(parts[1].Trim(), out _));
+ }
+
+ [Theory]
+ [PlatformSpecific(TestPlatforms.Linux)]
+ [InlineData("/proc/meminfo")]
+ [InlineData("/proc/stat")]
+ [InlineData("/proc/cpuinfo")]
+ public void ProcFs_NotEmpty(string path)
+ {
+ Assert.InRange(File.ReadAllBytes(path).Length, 1, int.MaxValue);
+ }
}
}
diff --git a/src/System.IO.FileSystem/tests/File/ReadWriteAllBytesAsync.cs b/src/System.IO.FileSystem/tests/File/ReadWriteAllBytesAsync.cs
index 47b3d71ccc..fa2a8faa7f 100644
--- a/src/System.IO.FileSystem/tests/File/ReadWriteAllBytesAsync.cs
+++ b/src/System.IO.FileSystem/tests/File/ReadWriteAllBytesAsync.cs
@@ -134,5 +134,57 @@ namespace System.IO.Tests
File.SetAttributes(path, FileAttributes.Normal);
}
}
+
+ [Fact]
+ public async Task EmptyFile_ReturnsEmptyArray()
+ {
+ string path = GetTestFilePath();
+ File.Create(path).Dispose();
+ Assert.Equal(0, (await File.ReadAllBytesAsync(path)).Length);
+ }
+
+ [Theory]
+ [PlatformSpecific(TestPlatforms.Linux)]
+ [InlineData("/proc/cmdline")]
+ [InlineData("/proc/version")]
+ [InlineData("/proc/filesystems")]
+ public async Task ProcFs_EqualsReadAllText(string path)
+ {
+ byte[] bytes = null;
+ string text = null;
+
+ const int NumTries = 3; // some of these could theoretically change between reads, so allow retries just in case
+ for (int i = 1; i <= NumTries; i++)
+ {
+ try
+ {
+ bytes = await File.ReadAllBytesAsync(path);
+ text = await File.ReadAllTextAsync(path);
+ Assert.Equal(text, Encoding.UTF8.GetString(bytes));
+ }
+ catch when (i < NumTries) { }
+ }
+ }
+
+ [Theory]
+ [PlatformSpecific(TestPlatforms.Linux)]
+ public async Task ReadAllBytes_ProcFs_Uptime_ContainsTwoNumbers()
+ {
+ string text = Encoding.UTF8.GetString(await File.ReadAllBytesAsync("/proc/uptime"));
+ string[] parts = text.Split(' ', StringSplitOptions.RemoveEmptyEntries);
+ Assert.Equal(2, parts.Length);
+ Assert.True(double.TryParse(parts[0].Trim(), out _));
+ Assert.True(double.TryParse(parts[1].Trim(), out _));
+ }
+
+ [Theory]
+ [PlatformSpecific(TestPlatforms.Linux)]
+ [InlineData("/proc/meminfo")]
+ [InlineData("/proc/stat")]
+ [InlineData("/proc/cpuinfo")]
+ public async Task ProcFs_NotEmpty(string path)
+ {
+ Assert.InRange((await File.ReadAllBytesAsync(path)).Length, 1, int.MaxValue);
+ }
}
}
diff --git a/src/System.IO.FileSystem/tests/FileInfo/GetSetTimes.cs b/src/System.IO.FileSystem/tests/FileInfo/GetSetTimes.cs
index ed38b89719..d88fa6ea00 100644
--- a/src/System.IO.FileSystem/tests/FileInfo/GetSetTimes.cs
+++ b/src/System.IO.FileSystem/tests/FileInfo/GetSetTimes.cs
@@ -19,6 +19,8 @@ namespace System.IO.Tests
public override FileInfo GetMissingItem() => new FileInfo(GetTestFilePath());
+ public override string GetItemPath(FileInfo item) => item.FullName;
+
public override void InvokeCreate(FileInfo item) => item.Create();
public override IEnumerable<TimeFunction> TimeFunctions(bool requiresRoundtripping = false)
diff --git a/src/System.IO.FileSystem/tests/FileInfo/Open.cs b/src/System.IO.FileSystem/tests/FileInfo/Open.cs
index c5df42fd5e..b9b35f51c2 100644
--- a/src/System.IO.FileSystem/tests/FileInfo/Open.cs
+++ b/src/System.IO.FileSystem/tests/FileInfo/Open.cs
@@ -13,22 +13,22 @@ namespace System.IO.Tests
return new FileInfo(path).Open(mode);
}
- [Fact]
+ [Theory, MemberData(nameof(StreamSpecifiers))]
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "FileInfo.Open(string, filemode) on netfx always uses FileAccess.ReadWrite instead of choosing a FileAccess based on the FileMode. This bug was fixed in netcoreapp.")]
- public override void FileModeAppend()
+ public override void FileModeAppend(string streamSpecifier)
{
- using (FileStream fs = CreateFileStream(GetTestFilePath(), FileMode.Append))
+ using (FileStream fs = CreateFileStream(GetTestFilePath() + streamSpecifier, FileMode.Append))
{
Assert.Equal(false, fs.CanRead);
Assert.Equal(true, fs.CanWrite);
}
}
- [Fact]
+ [Theory, MemberData(nameof(StreamSpecifiers))]
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "FileInfo.Open(string, filemode) on netfx always uses FileAccess.ReadWrite instead of choosing a FileAccess based on the FileMode. This bug was fixed in netcoreapp.")]
- public override void FileModeAppendExisting()
+ public override void FileModeAppendExisting(string streamSpecifier)
{
- string fileName = GetTestFilePath();
+ string fileName = GetTestFilePath() + streamSpecifier;
using (FileStream fs = CreateFileStream(fileName, FileMode.Create))
{
fs.WriteByte(0);
diff --git a/src/System.IO.FileSystem/tests/FileStream/Dispose.cs b/src/System.IO.FileSystem/tests/FileStream/Dispose.cs
index 026a82b910..edee857a62 100644
--- a/src/System.IO.FileSystem/tests/FileStream/Dispose.cs
+++ b/src/System.IO.FileSystem/tests/FileStream/Dispose.cs
@@ -4,6 +4,7 @@
using Microsoft.Win32.SafeHandles;
using System;
+using System.Diagnostics;
using System.IO;
using Xunit;
@@ -45,6 +46,11 @@ namespace System.IO.Tests
: base(path, mode)
{ }
+ public MyFileStream(SafeFileHandle handle, FileAccess access, Action<bool> disposeMethod) : base(handle, access)
+ {
+ DisposeMethod = disposeMethod;
+ }
+
public Action<bool> DisposeMethod { get; set; }
protected override void Dispose(bool disposing)
@@ -58,6 +64,92 @@ namespace System.IO.Tests
}
}
+
+ [Fact]
+ public void Dispose_CallsVirtualDisposeTrueArg_ThrowsDuringFlushWriteBuffer_DisposeThrows()
+ {
+ RemoteInvoke(() =>
+ {
+ string fileName = GetTestFilePath();
+ using (FileStream fscreate = new FileStream(fileName, FileMode.Create))
+ {
+ fscreate.WriteByte(0);
+ }
+ bool writeDisposeInvoked = false;
+ Action<bool> writeDisposeMethod = _ => writeDisposeInvoked = true;
+ using (var fsread = new FileStream(fileName, FileMode.Open, FileAccess.Read))
+ {
+ Action act = () => // separate method to avoid JIT lifetime-extension issues
+ {
+ using (var fswrite = new MyFileStream(fsread.SafeFileHandle, FileAccess.Write, writeDisposeMethod))
+ {
+ fswrite.WriteByte(0);
+
+ // Normal dispose should call Dispose(true). Throws due to FS trying to flush write buffer
+ Assert.Throws<UnauthorizedAccessException>(() => fswrite.Dispose());
+ Assert.True(writeDisposeInvoked, "Expected Dispose(true) to be called from Dispose()");
+ writeDisposeInvoked = false;
+
+ // Only throws on first Dispose call
+ fswrite.Dispose();
+ Assert.True(writeDisposeInvoked, "Expected Dispose(true) to be called from Dispose()");
+ writeDisposeInvoked = false;
+ }
+ Assert.True(writeDisposeInvoked, "Expected Dispose(true) to be called from Dispose() again");
+ writeDisposeInvoked = false;
+ };
+ act();
+
+ for (int i = 0; i < 2; i++)
+ {
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ }
+ Assert.False(writeDisposeInvoked, "Expected finalizer to have been suppressed");
+ }
+ return SuccessExitCode;
+ }).Dispose();
+ }
+
+ [Fact]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Missing fix for https://github.com/dotnet/coreclr/pull/16250")]
+ public void NoDispose_CallsVirtualDisposeFalseArg_ThrowsDuringFlushWriteBuffer_FinalizerWontThrow()
+ {
+ RemoteInvoke(() =>
+ {
+ string fileName = GetTestFilePath();
+ using (FileStream fscreate = new FileStream(fileName, FileMode.Create))
+ {
+ fscreate.WriteByte(0);
+ }
+ bool writeDisposeInvoked = false;
+ Action<bool> writeDisposeMethod = (disposing) =>
+ {
+ writeDisposeInvoked = true;
+ Assert.False(disposing, "Expected false arg to Dispose(bool)");
+ };
+ using (var fsread = new FileStream(fileName, FileMode.Open, FileAccess.Read))
+ {
+ Action act = () => // separate method to avoid JIT lifetime-extension issues
+ {
+ var fswrite = new MyFileStream(fsread.SafeFileHandle, FileAccess.Write, writeDisposeMethod);
+ fswrite.WriteByte(0);
+ };
+ act();
+
+ // Dispose is not getting called here.
+ // instead, make sure finalizer gets called and doesnt throw exception
+ for (int i = 0; i < 2; i++)
+ {
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ }
+ Assert.True(writeDisposeInvoked, "Expected finalizer to be invoked but not throw exception");
+ }
+ return SuccessExitCode;
+ }).Dispose();
+ }
+
[Fact]
public void Dispose_CallsVirtualDispose_TrueArg()
{
diff --git a/src/System.IO.FileSystem/tests/FileStream/Name.cs b/src/System.IO.FileSystem/tests/FileStream/Name.cs
index 88fe39c402..d4dde6ed22 100644
--- a/src/System.IO.FileSystem/tests/FileStream/Name.cs
+++ b/src/System.IO.FileSystem/tests/FileStream/Name.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System;
+using System.Globalization;
using System.IO;
using Xunit;
@@ -39,11 +40,16 @@ namespace System.IO.Tests
[Fact]
public void NameReturnsUnknownForHandle()
{
- using (FileStream fs = new FileStream(GetTestFilePath(), FileMode.Create, FileAccess.ReadWrite))
- using (FileStream fsh = new FileStream(fs.SafeFileHandle, FileAccess.ReadWrite))
+ RemoteInvoke(() =>
{
- Assert.Equal("[Unknown]", fsh.Name);
- }
+ CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture;
+
+ using (FileStream fs = new FileStream(GetTestFilePath(), FileMode.Create, FileAccess.ReadWrite))
+ using (FileStream fsh = new FileStream(fs.SafeFileHandle, FileAccess.ReadWrite))
+ {
+ Assert.Equal("[Unknown]", fsh.Name);
+ }
+ }).Dispose();
}
}
}
diff --git a/src/System.IO.FileSystem/tests/FileStream/ReadWriteSpan.netcoreapp.cs b/src/System.IO.FileSystem/tests/FileStream/ReadWriteSpan.netcoreapp.cs
index 272b19769e..0b1898d1f5 100644
--- a/src/System.IO.FileSystem/tests/FileStream/ReadWriteSpan.netcoreapp.cs
+++ b/src/System.IO.FileSystem/tests/FileStream/ReadWriteSpan.netcoreapp.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Buffers;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -188,6 +189,20 @@ namespace System.IO.Tests
}
[Fact]
+ public async Task NonEmptyFile_CustomOwnedMemory_ReadAsync_GetsExpectedData()
+ {
+ string fileName = GetTestFilePath();
+ File.WriteAllBytes(fileName, TestBuffer);
+
+ using (var fs = CreateFileStream(fileName, FileMode.Open))
+ using (var buffer = new NativeOwnedMemory(TestBuffer.Length))
+ {
+ Assert.Equal(TestBuffer.Length, await fs.ReadAsync(buffer.Memory));
+ Assert.Equal<byte>(TestBuffer, buffer.Memory.ToArray());
+ }
+ }
+
+ [Fact]
public void ReadOnly_WriteAsync_Throws()
{
string fileName = GetTestFilePath();
@@ -238,24 +253,49 @@ namespace System.IO.Tests
Assert.Equal(TestBuffer, buffer);
}
}
+
+ [Fact]
+ public async Task NonEmptyWriteAsync_CustomOwnedMemory_WritesExpectedData()
+ {
+ using (var mem = new NativeOwnedMemory(TestBuffer.Length))
+ using (var fs = CreateFileStream(GetTestFilePath(), FileMode.Create))
+ {
+ new Memory<byte>(TestBuffer).CopyTo(mem.Memory);
+
+ await fs.WriteAsync(mem.Memory);
+ Assert.Equal(TestBuffer.Length, fs.Length);
+ Assert.Equal(TestBuffer.Length, fs.Position);
+
+ fs.Position = 0;
+ var buffer = new byte[TestBuffer.Length];
+ Assert.Equal(TestBuffer.Length, await fs.ReadAsync(new Memory<byte>(buffer)));
+ Assert.Equal(TestBuffer, buffer);
+ }
+ }
}
public class Sync_FileStream_ReadWrite_Span : FileStream_ReadWrite_Span
{
protected override FileStream CreateFileStream(string path, FileMode mode, FileAccess access) =>
- new FileStream(path, mode, access, FileShare.None, 0x1000, FileOptions.None);
+ new FileStream(path, mode, access, FileShare.None, bufferSize: 0x1000, FileOptions.None);
}
public class Async_FileStream_ReadWrite_Span : FileStream_ReadWrite_Span
{
protected override FileStream CreateFileStream(string path, FileMode mode, FileAccess access) =>
- new FileStream(path, mode, access, FileShare.None, 0x1000, FileOptions.Asynchronous);
+ new FileStream(path, mode, access, FileShare.None, bufferSize: 0x1000, FileOptions.Asynchronous);
+ }
+
+ public class Async_NoBuffer_FileStream_ReadWrite_Span : FileStream_ReadWrite_Span
+ {
+ protected override FileStream CreateFileStream(string path, FileMode mode, FileAccess access) =>
+ new FileStream(path, mode, access, FileShare.None, bufferSize: 1, FileOptions.Asynchronous);
}
public sealed class Sync_DerivedFileStream_ReadWrite_Span : Sync_FileStream_ReadWrite_Span
{
protected override FileStream CreateFileStream(string path, FileMode mode, FileAccess access) =>
- new DerivedFileStream(path, mode, access, FileShare.None, 0x1000, FileOptions.None);
+ new DerivedFileStream(path, mode, access, FileShare.None, bufferSize: 0x1000, FileOptions.None);
[Fact]
public void CallSpanReadWriteOnDerivedFileStream_ArrayMethodsUsed()
@@ -299,7 +339,7 @@ namespace System.IO.Tests
public sealed class Async_DerivedFileStream_ReadWrite_Span : Async_FileStream_ReadWrite_Span
{
protected override FileStream CreateFileStream(string path, FileMode mode, FileAccess access) =>
- new DerivedFileStream(path, mode, access, FileShare.None, 0x1000, FileOptions.Asynchronous);
+ new DerivedFileStream(path, mode, access, FileShare.None, bufferSize: 0x1000, FileOptions.Asynchronous);
}
internal sealed class DerivedFileStream : FileStream
diff --git a/src/System.IO.FileSystem/tests/FileStream/WriteAsync.cs b/src/System.IO.FileSystem/tests/FileStream/WriteAsync.cs
index fa1f45095d..a80eb79fbb 100644
--- a/src/System.IO.FileSystem/tests/FileStream/WriteAsync.cs
+++ b/src/System.IO.FileSystem/tests/FileStream/WriteAsync.cs
@@ -388,35 +388,30 @@ namespace System.IO.Tests
string writeFileName = GetTestFilePath();
do
{
- // Create a new token that expires between 100-1000ms
- CancellationTokenSource tokenSource = new CancellationTokenSource();
- tokenSource.CancelAfter(rand.Next(100, 1000));
+
+ int totalBytesWritten = 0;
using (var stream = new FileStream(writeFileName, FileMode.Create, FileAccess.Write))
{
do
{
- try
+ // 20%: random write size
+ int bytesToWrite = (rand.NextDouble() < 0.2 ? rand.Next(16, MaximumWriteSize) : NormalWriteSize);
+
+ if (rand.NextDouble() < 0.1)
{
- // 20%: random write size
- int bytesToWrite = (rand.NextDouble() < 0.2 ? rand.Next(16, MaximumWriteSize) : NormalWriteSize);
-
- if (rand.NextDouble() < 0.1)
- {
- // 10%: Sync write
- stream.Write(dataToWrite, 0, bytesToWrite);
- }
- else
- {
- // 90%: Async write
- await WriteAsync(stream, dataToWrite, 0, bytesToWrite, tokenSource.Token);
- }
+ // 10%: Sync write
+ stream.Write(dataToWrite, 0, bytesToWrite);
}
- catch (TaskCanceledException)
+ else
{
- Assert.True(tokenSource.Token.IsCancellationRequested, "Received cancellation exception before token expired");
+ // 90%: Async write
+ await WriteAsync(stream, dataToWrite, 0, bytesToWrite);
}
- } while (!tokenSource.Token.IsCancellationRequested);
+
+ totalBytesWritten += bytesToWrite;
+ // Cap written bytes at 10 million to avoid writing too much to disk
+ } while (totalBytesWritten < 10_000_000);
}
} while (DateTime.UtcNow - testStartTime <= testRunTime);
}
diff --git a/src/System.IO.FileSystem/tests/FileStream/ctor_str_fm.cs b/src/System.IO.FileSystem/tests/FileStream/ctor_str_fm.cs
index 2f9655ac5e..45791fe767 100644
--- a/src/System.IO.FileSystem/tests/FileStream/ctor_str_fm.cs
+++ b/src/System.IO.FileSystem/tests/FileStream/ctor_str_fm.cs
@@ -51,17 +51,39 @@ namespace System.IO.Tests
Assert.Throws<DirectoryNotFoundException>(() => CreateFileStream(path, FileMode.Open));
}
- [Fact]
- public void FileModeCreate()
+
+ public static TheoryData<string> StreamSpecifiers
{
- using (CreateFileStream(GetTestFilePath(), FileMode.Create))
- { }
+ get
+ {
+ TheoryData<string> data = new TheoryData<string>();
+ data.Add("");
+
+ if (PlatformDetection.IsWindows && PlatformDetection.IsNetCore)
+ {
+ data.Add("::$DATA"); // Same as default stream (e.g. main file)
+ data.Add(":bar"); // $DATA isn't necessary
+ data.Add(":bar:$DATA"); // $DATA can be explicitly specified
+ }
+
+ return data;
+ }
}
- [Fact]
- public void FileModeCreateExisting()
+ [Theory, MemberData(nameof(StreamSpecifiers))]
+ public void FileModeCreate(string streamSpecifier)
{
- string fileName = GetTestFilePath();
+ string fileName = GetTestFilePath() + streamSpecifier;
+ using (CreateFileStream(fileName, FileMode.Create))
+ {
+ Assert.True(File.Exists(fileName));
+ }
+ }
+
+ [Theory, MemberData(nameof(StreamSpecifiers))]
+ public void FileModeCreateExisting(string streamSpecifier)
+ {
+ string fileName = GetTestFilePath() + streamSpecifier;
using (FileStream fs = CreateFileStream(fileName, FileMode.Create))
{
fs.WriteByte(0);
@@ -77,17 +99,20 @@ namespace System.IO.Tests
}
}
- [Fact]
- public void FileModeCreateNew()
+ [Theory, MemberData(nameof(StreamSpecifiers))]
+ public void FileModeCreateNew(string streamSpecifier)
{
- using (CreateFileStream(GetTestFilePath(), FileMode.CreateNew))
- { }
+ string fileName = GetTestFilePath() + streamSpecifier;
+ using (CreateFileStream(fileName, FileMode.CreateNew))
+ {
+ Assert.True(File.Exists(fileName));
+ }
}
- [Fact]
- public void FileModeCreateNewExistingThrows()
+ [Theory, MemberData(nameof(StreamSpecifiers))]
+ public void FileModeCreateNewExistingThrows(string streamSpecifier)
{
- string fileName = GetTestFilePath();
+ string fileName = GetTestFilePath() + streamSpecifier;
using (FileStream fs = CreateFileStream(fileName, FileMode.CreateNew))
{
fs.WriteByte(0);
@@ -98,18 +123,18 @@ namespace System.IO.Tests
Assert.Throws<IOException>(() => CreateFileStream(fileName, FileMode.CreateNew));
}
- [Fact]
- public void FileModeOpenThrows()
+ [Theory, MemberData(nameof(StreamSpecifiers))]
+ public void FileModeOpenThrows(string streamSpecifier)
{
- string fileName = GetTestFilePath();
+ string fileName = GetTestFilePath() + streamSpecifier;
FileNotFoundException fnfe = Assert.Throws<FileNotFoundException>(() => CreateFileStream(fileName, FileMode.Open));
Assert.Equal(fileName, fnfe.FileName);
}
- [Fact]
- public void FileModeOpenExisting()
+ [Theory, MemberData(nameof(StreamSpecifiers))]
+ public void FileModeOpenExisting(string streamSpecifier)
{
- string fileName = GetTestFilePath();
+ string fileName = GetTestFilePath() + streamSpecifier;
using (FileStream fs = CreateFileStream(fileName, FileMode.Create))
{
fs.WriteByte(0);
@@ -125,17 +150,20 @@ namespace System.IO.Tests
}
}
- [Fact]
- public void FileModeOpenOrCreate()
+ [Theory, MemberData(nameof(StreamSpecifiers))]
+ public void FileModeOpenOrCreate(string streamSpecifier)
{
- using (CreateFileStream(GetTestFilePath(), FileMode.OpenOrCreate))
- {}
+ string fileName = GetTestFilePath() + streamSpecifier;
+ using (CreateFileStream(fileName, FileMode.OpenOrCreate))
+ {
+ Assert.True(File.Exists(fileName));
+ }
}
- [Fact]
- public void FileModeOpenOrCreateExisting()
+ [Theory, MemberData(nameof(StreamSpecifiers))]
+ public void FileModeOpenOrCreateExisting(string streamSpecifier)
{
- string fileName = GetTestFilePath();
+ string fileName = GetTestFilePath() + streamSpecifier;
using (FileStream fs = CreateFileStream(fileName, FileMode.Create))
{
fs.WriteByte(0);
@@ -151,18 +179,18 @@ namespace System.IO.Tests
}
}
- [Fact]
- public void FileModeTruncateThrows()
+ [Theory, MemberData(nameof(StreamSpecifiers))]
+ public void FileModeTruncateThrows(string streamSpecifier)
{
- string fileName = GetTestFilePath();
+ string fileName = GetTestFilePath() + streamSpecifier;
FileNotFoundException fnfe = Assert.Throws<FileNotFoundException>(() => CreateFileStream(fileName, FileMode.Truncate));
Assert.Equal(fileName, fnfe.FileName);
}
- [Fact]
- public void FileModeTruncateExisting()
+ [Theory, MemberData(nameof(StreamSpecifiers))]
+ public void FileModeTruncateExisting(string streamSpecifier)
{
- string fileName = GetTestFilePath();
+ string fileName = GetTestFilePath() + streamSpecifier;
using (FileStream fs = CreateFileStream(fileName, FileMode.Create))
{
fs.WriteByte(0);
@@ -178,20 +206,20 @@ namespace System.IO.Tests
}
}
- [Fact]
- public virtual void FileModeAppend()
+ [Theory, MemberData(nameof(StreamSpecifiers))]
+ public virtual void FileModeAppend(string streamSpecifier)
{
- using (FileStream fs = CreateFileStream(GetTestFilePath(), FileMode.Append))
+ using (FileStream fs = CreateFileStream(GetTestFilePath() + streamSpecifier, FileMode.Append))
{
Assert.Equal(false, fs.CanRead);
Assert.Equal(true, fs.CanWrite);
}
}
- [Fact]
- public virtual void FileModeAppendExisting()
+ [Theory, MemberData(nameof(StreamSpecifiers))]
+ public virtual void FileModeAppendExisting(string streamSpecifier)
{
- string fileName = GetTestFilePath();
+ string fileName = GetTestFilePath() + streamSpecifier;
using (FileStream fs = CreateFileStream(fileName, FileMode.Create))
{
fs.WriteByte(0);
diff --git a/src/System.IO.FileSystem/tests/FileSystemTest.cs b/src/System.IO.FileSystem/tests/FileSystemTest.cs
index 4e593f27b8..6f020a00f6 100644
--- a/src/System.IO.FileSystem/tests/FileSystemTest.cs
+++ b/src/System.IO.FileSystem/tests/FileSystemTest.cs
@@ -28,7 +28,7 @@ namespace System.IO.Tests
public static TheoryData WhiteSpace = IOInputs.GetWhiteSpace().ToTheoryData();
public static TheoryData UncPathsWithoutShareName = IOInputs.GetUncPathsWithoutShareName().ToTheoryData();
public static TheoryData PathsWithReservedDeviceNames = IOInputs.GetPathsWithReservedDeviceNames().ToTheoryData();
- public static TheoryData PathsWithAlternativeDataStreams = IOInputs.GetPathsWithAlternativeDataStreams().ToTheoryData();
+ public static TheoryData PathsWithColons = IOInputs.GetPathsWithColons().ToTheoryData();
public static TheoryData PathsWithComponentLongerThanMaxComponent = IOInputs.GetPathsWithComponentLongerThanMaxComponent().ToTheoryData();
public static TheoryData ControlWhiteSpace = IOInputs.GetControlWhiteSpace().ToTheoryData();
public static TheoryData NonControlWhiteSpace = IOInputs.GetNonControlWhiteSpace().ToTheoryData();
diff --git a/src/System.IO.FileSystem/tests/Performance/Perf.Directory.cs b/src/System.IO.FileSystem/tests/Performance/Perf.Directory.cs
index 508275dc12..7a70751425 100644
--- a/src/System.IO.FileSystem/tests/Performance/Perf.Directory.cs
+++ b/src/System.IO.FileSystem/tests/Performance/Perf.Directory.cs
@@ -2,7 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Text;
using Microsoft.Xunit.Performance;
+using Xunit;
namespace System.IO.Tests
{
@@ -55,5 +57,89 @@ namespace System.IO.Tests
// Teardown
Directory.Delete(testFile);
}
+
+ public string GetTestDeepFilePath(int depth)
+ {
+ string directory = Path.DirectorySeparatorChar + "a";
+ StringBuilder sb = new StringBuilder(depth * 2);
+ for (int i = 0; i < depth; i++)
+ {
+ sb.Append(directory);
+ }
+
+ return sb.ToString();
+ }
+
+ public static TheoryData<int, int> RecursiveDepthData
+ {
+ get
+ {
+ var data = new TheoryData<int, int>();
+ data.Add(10, 100);
+
+ // Length of the path can be 260 characters on netfx.
+ if (AreAllLongPathsAvailable)
+ {
+ data.Add(100, 10);
+ // Most Unix distributions have a maximum path length of 1024 characters (1024 UTF-8 bytes).
+ if (PlatformDetection.IsWindows)
+ data.Add(1000, 1);
+ }
+
+ return data;
+ }
+ }
+
+ [Benchmark]
+ [MemberData(nameof(RecursiveDepthData))]
+ [OuterLoop("Takes a lot of time to finish")]
+ public void RecursiveCreateDirectoryTest(int depth, int times)
+ {
+ // Setup
+ string rootDirectory = GetTestFilePath();
+ string path = GetTestDeepFilePath(depth);
+
+ foreach (var iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ for (int i = 0; i < times; i++)
+ {
+ Directory.CreateDirectory(rootDirectory + Path.DirectorySeparatorChar + i + path);
+ }
+ }
+ // TearDown For each iteration
+ Directory.Delete(rootDirectory, recursive: true);
+ }
+ }
+
+ [Benchmark]
+ [MemberData(nameof(RecursiveDepthData))]
+ [OuterLoop("Takes a lot of time to finish")]
+ public void RecursiveDeleteDirectoryTest(int depth, int times)
+ {
+ // Setup
+ string rootDirectory = GetTestFilePath();
+ string path = GetTestDeepFilePath(depth);
+
+ foreach (var iteration in Benchmark.Iterations)
+ {
+ // Setup For each Iteration
+ for (int i = 0; i < times; i++)
+ {
+ Directory.CreateDirectory(rootDirectory + Path.DirectorySeparatorChar + i + path);
+ }
+
+ using (iteration.StartMeasurement())
+ {
+ for (int i = 0; i < times; i++)
+ {
+ Directory.Delete(rootDirectory + Path.DirectorySeparatorChar + i, recursive: true);
+ }
+ }
+ }
+ // TearDown
+ Directory.Delete(rootDirectory, recursive: true);
+ }
}
}
diff --git a/src/System.IO.FileSystem/tests/Performance/System.IO.FileSystem.Performance.Tests.csproj b/src/System.IO.FileSystem/tests/Performance/System.IO.FileSystem.Performance.Tests.csproj
index afcd6a3da8..4d758dda6f 100644
--- a/src/System.IO.FileSystem/tests/Performance/System.IO.FileSystem.Performance.Tests.csproj
+++ b/src/System.IO.FileSystem/tests/Performance/System.IO.FileSystem.Performance.Tests.csproj
@@ -37,5 +37,8 @@
<Name>PerfRunner</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.IO.FileSystem/tests/PortedCommon/IOInputs.cs b/src/System.IO.FileSystem/tests/PortedCommon/IOInputs.cs
index 10fbbd8138..68dfcd7fa1 100644
--- a/src/System.IO.FileSystem/tests/PortedCommon/IOInputs.cs
+++ b/src/System.IO.FileSystem/tests/PortedCommon/IOInputs.cs
@@ -152,7 +152,7 @@ internal static class IOInputs
}
}
- public static IEnumerable<string> GetPathsWithAlternativeDataStreams()
+ public static IEnumerable<string> GetPathsWithColons()
{
yield return @"AA:";
yield return @"AAA:";
diff --git a/src/System.IO.FileSystem/tests/System.IO.FileSystem.Tests.csproj b/src/System.IO.FileSystem/tests/System.IO.FileSystem.Tests.csproj
index fb99199ad1..7597996101 100644
--- a/src/System.IO.FileSystem/tests/System.IO.FileSystem.Tests.csproj
+++ b/src/System.IO.FileSystem/tests/System.IO.FileSystem.Tests.csproj
@@ -54,6 +54,19 @@
<Compile Include="File\ReadWriteAllBytesAsync.cs" />
<Compile Include="File\ReadWriteAllTextAsync.cs" />
<Compile Include="FileStream\ReadWriteSpan.netcoreapp.cs" />
+ <Compile Include="Enumeration\ConstructionTests.netcoreapp.cs" />
+ <Compile Include="Enumeration\SpecialDirectoryTests.netcoreapp.cs" />
+ <Compile Include="Enumeration\SkipAttributeTests.netcoreapp.cs" />
+ <Compile Include="Enumeration\FileSystemNameTests.netcoreapp.cs" />
+ <Compile Include="Enumeration\MatchCasingTests.netcoreapp.cs" />
+ <Compile Include="Enumeration\TrimmedPaths.netcoreapp.cs" />
+ <Compile Include="Enumeration\ErrorHandlingTests.netcoreapp.cs" />
+ <Compile Include="Enumeration\IncludePredicateTests.netcoreapp.cs" />
+ <Compile Include="Enumeration\PatternTransformTests.netcoreapp.cs" />
+ <Compile Include="Enumeration\RootTests.netcoreapp.cs" />
+ <Compile Include="Enumeration\AttributeTests.netcoreapp.cs" />
+ <Compile Include="Enumeration\MatchTypesTests.netcoreapp.cs" />
+ <Compile Include="Enumeration\ExampleTests.netcoreapp.cs" />
</ItemGroup>
<ItemGroup>
<!-- Rewritten -->
@@ -164,6 +177,9 @@
<Compile Include="FileInfo\AppendText.cs" />
<Compile Include="FileInfo\CopyTo.cs" />
<!-- Helpers -->
+ <Compile Include="$(CommonTestPath)\System\Buffers\NativeOwnedMemory.cs">
+ <Link>Common\System\Buffers\NativeOwnedMemory.cs</Link>
+ </Compile>
<Compile Include="$(CommonTestPath)\System\IO\TempFile.cs">
<Link>Common\System\IO\TempFile.cs</Link>
</Compile>
@@ -182,5 +198,8 @@
<ItemGroup>
<EmbeddedResource Include="Resources\$(AssemblyName).rd.xml" />
</ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.IO.FileSystem/tests/TestData.cs b/src/System.IO.FileSystem/tests/TestData.cs
index 3ca4af5160..69b4373bd9 100644
--- a/src/System.IO.FileSystem/tests/TestData.cs
+++ b/src/System.IO.FileSystem/tests/TestData.cs
@@ -57,25 +57,12 @@ internal static class TestData
{
get
{
- TheoryData<string> data = new TheoryData<string>();
-
- // NOTE: That I/O treats "file"/http" specially and throws ArgumentException.
- // Otherwise, it treats all other urls as alternative data streams
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // alternate data streams, drive labels, etc.
- {
- data.Add("\0");
- data.Add("middle\0path");
- data.Add("trailing\0");
- data.Add(@"\\?\");
- data.Add(@"\\?\UNC\");
- data.Add(@"\\?\UNC\LOCALHOST");
- }
- else
+ TheoryData<string> data = new TheoryData<string>
{
- data.Add("\0");
- data.Add("middle\0path");
- data.Add("trailing\0");
- }
+ "\0",
+ "middle\0path",
+ "trailing\0"
+ };
foreach (char c in s_invalidFileNameChars)
{
diff --git a/src/System.IO.IsolatedStorage/src/System/IO/IsolatedStorage/IsolatedStorage.cs b/src/System.IO.IsolatedStorage/src/System/IO/IsolatedStorage/IsolatedStorage.cs
index 9441cad2b5..c1b5b1c51d 100644
--- a/src/System.IO.IsolatedStorage/src/System/IO/IsolatedStorage/IsolatedStorage.cs
+++ b/src/System.IO.IsolatedStorage/src/System/IO/IsolatedStorage/IsolatedStorage.cs
@@ -108,7 +108,7 @@ namespace System.IO.IsolatedStorage
public IsolatedStorageScope Scope
{
- get; protected set;
+ get; private set;
}
protected virtual char SeparatorExternal
@@ -128,7 +128,7 @@ namespace System.IO.IsolatedStorage
public abstract void Remove();
- protected string IdentityHash
+ internal string IdentityHash
{
get; private set;
}
diff --git a/src/System.IO.IsolatedStorage/src/System/IO/IsolatedStorage/IsolatedStorageFileStream.cs b/src/System.IO.IsolatedStorage/src/System/IO/IsolatedStorage/IsolatedStorageFileStream.cs
index f68a2273b1..84f558894a 100644
--- a/src/System.IO.IsolatedStorage/src/System/IO/IsolatedStorage/IsolatedStorageFileStream.cs
+++ b/src/System.IO.IsolatedStorage/src/System/IO/IsolatedStorage/IsolatedStorageFileStream.cs
@@ -247,6 +247,11 @@ namespace System.IO.IsolatedStorage
return _fs.ReadAsync(buffer, offset, count, cancellationToken);
}
+ public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken)
+ {
+ return _fs.ReadAsync(buffer, cancellationToken);
+ }
+
public override int ReadByte()
{
return _fs.ReadByte();
@@ -269,6 +274,11 @@ namespace System.IO.IsolatedStorage
return _fs.WriteAsync(buffer, offset, count, cancellationToken);
}
+ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken)
+ {
+ return _fs.WriteAsync(buffer, cancellationToken);
+ }
+
public override void WriteByte(byte value)
{
_fs.WriteByte(value);
diff --git a/src/System.IO.MemoryMappedFiles/src/System.IO.MemoryMappedFiles.csproj b/src/System.IO.MemoryMappedFiles/src/System.IO.MemoryMappedFiles.csproj
index b047d4849e..ffa00defea 100644
--- a/src/System.IO.MemoryMappedFiles/src/System.IO.MemoryMappedFiles.csproj
+++ b/src/System.IO.MemoryMappedFiles/src/System.IO.MemoryMappedFiles.csproj
@@ -117,8 +117,8 @@
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.VirtualQuery.cs">
<Link>Common\Interop\Windows\Interop.VirtualQuery.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\IO\Win32Marshal.cs">
- <Link>Common\System\IO\Win32Marshal.cs</Link>
+ <Compile Include="$(CommonPath)\CoreLib\System\IO\Win32Marshal.cs">
+ <Link>Common\CoreLib\System\IO\Win32Marshal.cs</Link>
</Compile>
<Compile Include="Microsoft\Win32\SafeMemoryMappedFileHandle.Windows.cs" />
<Compile Include="Microsoft\Win32\SafeMemoryMappedViewHandle.Windows.cs" />
@@ -180,6 +180,7 @@
<Reference Include="System.Diagnostics.Debug" />
<Reference Include="System.Diagnostics.Tools" />
<Reference Include="System.IO.FileSystem" />
+ <Reference Include="System.Memory" />
<Reference Include="System.Resources.ResourceManager" />
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.Extensions" />
diff --git a/src/System.IO.Packaging/pkg/System.IO.Packaging.pkgproj b/src/System.IO.Packaging/pkg/System.IO.Packaging.pkgproj
index fe55a2b7ef..cc486349ee 100644
--- a/src/System.IO.Packaging/pkg/System.IO.Packaging.pkgproj
+++ b/src/System.IO.Packaging/pkg/System.IO.Packaging.pkgproj
@@ -6,6 +6,12 @@
<SupportedFramework>net46;netcore50;netcoreapp1.0;$(AllXamarinFrameworks)</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\src\System.IO.Packaging.csproj" />
+
+ <!--
+ Suppress NETStandard.Library collpasing as it add more dependencies then needed in some
+ scenarios like .NET Framework which adds an unecessary amount of package dependencies to download
+ -->
+ <SuppressMetaPackage Include="NETStandard.Library" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.IO.Packaging/src/System.IO.Packaging.csproj b/src/System.IO.Packaging/src/System.IO.Packaging.csproj
index 39eccd6686..bb1acf530b 100644
--- a/src/System.IO.Packaging/src/System.IO.Packaging.csproj
+++ b/src/System.IO.Packaging/src/System.IO.Packaging.csproj
@@ -7,8 +7,6 @@
<AssemblyName>System.IO.Packaging</AssemblyName>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<IsPartialFacadeAssembly Condition="'$(TargetGroup)'=='netfx' OR '$(TargetGroup)'=='net46'">true</IsPartialFacadeAssembly>
- <!-- UAPvNext is not yet mapped to netstandard2.0, manually duplicate this ref -->
- <PackageTargetFramework Condition="'$(TargetGroup)' == 'netstandard'">netstandard2.0;$(UAPvNextTFM)</PackageTargetFramework>
<DefineConstants Condition="'$(TargetGroup)' != 'netstandard1.3'">$(DefineConstants);FEATURE_SERIALIZATION</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'net46-Debug|AnyCPU'" />
@@ -19,9 +17,6 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.3-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.3-Release|AnyCPU'" />
- <ItemGroup Condition="'$(TargetGroup)' == 'netstandard'">
- <SuppressPackageTargetFrameworkCompatibility Include="$(UAPvNextTFM)" />
- </ItemGroup>
<ItemGroup Condition="'$(TargetGroup)'=='netstandard1.3'">
<Reference Include="System.Collections" />
<Reference Include="System.Diagnostics.Debug" />
diff --git a/src/System.IO.Packaging/src/System/IO/Packaging/PartBasedPackageProperties.cs b/src/System.IO.Packaging/src/System/IO/Packaging/PartBasedPackageProperties.cs
index 6ad4b12f51..895ca09476 100644
--- a/src/System.IO.Packaging/src/System/IO/Packaging/PartBasedPackageProperties.cs
+++ b/src/System.IO.Packaging/src/System/IO/Packaging/PartBasedPackageProperties.cs
@@ -313,13 +313,16 @@ namespace System.IO.Packaging
// Make sure there is a part to write to and that it contains
// the expected start markup.
- EnsureXmlWriter();
+ Stream zipStream = null;
+ EnsureXmlWriter(ref zipStream);
// Write the property elements and clear _dirty.
SerializeDirtyProperties();
// add closing markup and close the writer.
CloseXmlWriter();
+ Debug.Assert(_xmlWriter == null);
+ zipStream?.Dispose();
}
// Invoked from Package.Close.
@@ -670,14 +673,15 @@ namespace System.IO.Packaging
// Make sure there is a part to write to and that it contains
// the expected start markup.
- private void EnsureXmlWriter()
+ private void EnsureXmlWriter(ref Stream zipStream)
{
if (_xmlWriter != null)
return;
EnsurePropertyPart(); // Should succeed or throw an exception.
- Stream writerStream = new IgnoreFlushAndCloseStream(_propertyPart.GetStream(FileMode.Create, FileAccess.Write));
+ zipStream = _propertyPart.GetStream(FileMode.Create, FileAccess.Write);
+ Stream writerStream = new IgnoreFlushAndCloseStream(zipStream);
_xmlWriter = XmlWriter.Create(writerStream, new XmlWriterSettings { Encoding = System.Text.Encoding.UTF8 });
WriteXmlStartTagsForPackageProperties();
}
diff --git a/src/System.IO.Packaging/tests/Tests.cs b/src/System.IO.Packaging/tests/Tests.cs
index 00b5395c85..0988c9650f 100644
--- a/src/System.IO.Packaging/tests/Tests.cs
+++ b/src/System.IO.Packaging/tests/Tests.cs
@@ -3515,6 +3515,44 @@ namespace System.IO.Packaging.Tests
}
[Fact]
+ public void OpenPropertyStream()
+ {
+ FileInfo tempGuidFile = GetTempFileInfoWithExtension(".zip");
+
+ using (Package package = Package.Open(tempGuidFile.FullName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
+ {
+ package.PackageProperties.Subject = "Subject";
+ package.PackageProperties.Creator = "Creator";
+
+ // serialize core properties
+ package.Flush();
+
+ PackageRelationshipCollection corePropsRelations = package.GetRelationshipsByType(
+ "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties");
+
+ Assert.NotNull(corePropsRelations);
+ PackagePart corePropsPart = package.GetPart(corePropsRelations.Single().TargetUri);
+
+ string firstRead;
+
+ // If the property writer did not close out the stream properly this block will throw.
+ using (Stream stream = corePropsPart.GetStream())
+ using (var reader = new StreamReader(stream))
+ {
+ firstRead = reader.ReadToEnd();
+ }
+
+ // May as well read it another time, just to prove we can.
+ using (Stream stream = corePropsPart.GetStream())
+ using (var reader = new StreamReader(stream))
+ {
+ string secondRead = reader.ReadToEnd();
+ Assert.Equal(firstRead, secondRead);
+ }
+ }
+ }
+
+ [Fact]
public void SetEmptyPropertyToNull()
{
using (var ms = new MemoryStream())
diff --git a/src/System.IO.Pipelines/System.IO.Pipelines.sln b/src/System.IO.Pipelines/System.IO.Pipelines.sln
new file mode 100644
index 0000000000..dbce1e3723
--- /dev/null
+++ b/src/System.IO.Pipelines/System.IO.Pipelines.sln
@@ -0,0 +1,50 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.25420.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.IO.Pipelines.Tests", "tests\System.IO.Pipelines.Tests.csproj", "{9E984EB2-827E-4029-9647-FB5F8B67C553}"
+ ProjectSection(ProjectDependencies) = postProject
+ {1032D5F6-5AE7-4002-A0E4-FEBEADFEA977} = {1032D5F6-5AE7-4002-A0E4-FEBEADFEA977}
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.IO.Pipelines", "src\System.IO.Pipelines.csproj", "{1032D5F6-5AE7-4002-A0E4-FEBEADFEA977}"
+ ProjectSection(ProjectDependencies) = postProject
+ {9C524CA0-92FF-437B-B568-BCE8A794A69A} = {9C524CA0-92FF-437B-B568-BCE8A794A69A}
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.IO.Pipelines", "ref\System.IO.Pipelines.csproj", "{9C524CA0-92FF-437B-B568-BCE8A794A69A}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{1A2F9F4A-A032-433E-B914-ADD5992BB178}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E107E9C1-E893-4E87-987E-04EF0DCEAEFD}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{2E666815-2EDB-464B-9DF6-380BF4789AD4}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {9E984EB2-827E-4029-9647-FB5F8B67C553}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
+ {9E984EB2-827E-4029-9647-FB5F8B67C553}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
+ {9E984EB2-827E-4029-9647-FB5F8B67C553}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
+ {9E984EB2-827E-4029-9647-FB5F8B67C553}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
+ {1032D5F6-5AE7-4002-A0E4-FEBEADFEA977}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
+ {1032D5F6-5AE7-4002-A0E4-FEBEADFEA977}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
+ {1032D5F6-5AE7-4002-A0E4-FEBEADFEA977}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
+ {1032D5F6-5AE7-4002-A0E4-FEBEADFEA977}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
+ {9C524CA0-92FF-437B-B568-BCE8A794A69A}.Debug|Any CPU.ActiveCfg = netstandard-Debug|Any CPU
+ {9C524CA0-92FF-437B-B568-BCE8A794A69A}.Debug|Any CPU.Build.0 = netstandard-Debug|Any CPU
+ {9C524CA0-92FF-437B-B568-BCE8A794A69A}.Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
+ {9C524CA0-92FF-437B-B568-BCE8A794A69A}.Release|Any CPU.Build.0 = netstandard-Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {9E984EB2-827E-4029-9647-FB5F8B67C553} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
+ {1032D5F6-5AE7-4002-A0E4-FEBEADFEA977} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD}
+ {9C524CA0-92FF-437B-B568-BCE8A794A69A} = {2E666815-2EDB-464B-9DF6-380BF4789AD4}
+ EndGlobalSection
+EndGlobal
diff --git a/src/System.IO.Pipelines/dir.props b/src/System.IO.Pipelines/dir.props
new file mode 100644
index 0000000000..4356decc45
--- /dev/null
+++ b/src/System.IO.Pipelines/dir.props
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\dir.props" />
+ <PropertyGroup>
+ <AssemblyVersion>4.0.0.0</AssemblyVersion>
+ <AssemblyKey>Open</AssemblyKey>
+ </PropertyGroup>
+</Project> \ No newline at end of file
diff --git a/src/System.IO.Pipelines/pkg/System.IO.Pipelines.pkgproj b/src/System.IO.Pipelines/pkg/System.IO.Pipelines.pkgproj
new file mode 100644
index 0000000000..80de0bf401
--- /dev/null
+++ b/src/System.IO.Pipelines/pkg/System.IO.Pipelines.pkgproj
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <ItemGroup>
+ <ProjectReference Include="..\ref\System.IO.Pipelines.csproj">
+ <SupportedFramework>net46;netcore50;netcoreapp1.0;$(UAPvNextTFM);$(AllXamarinFrameworks)</SupportedFramework>
+ </ProjectReference>
+ <ProjectReference Include="..\src\System.IO.Pipelines.csproj" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/src/System.IO.Pipelines/ref/Configurations.props b/src/System.IO.Pipelines/ref/Configurations.props
new file mode 100644
index 0000000000..2b1f9ae5c4
--- /dev/null
+++ b/src/System.IO.Pipelines/ref/Configurations.props
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <PackageConfigurations>
+ netstandard1.3;
+ </PackageConfigurations>
+ <BuildConfigurations>
+ $(PackageConfigurations);
+ netstandard;
+ </BuildConfigurations>
+ </PropertyGroup>
+</Project>
diff --git a/src/System.IO.Pipelines/ref/System.IO.Pipelines.cs b/src/System.IO.Pipelines/ref/System.IO.Pipelines.cs
new file mode 100644
index 0000000000..7f3b7704e1
--- /dev/null
+++ b/src/System.IO.Pipelines/ref/System.IO.Pipelines.cs
@@ -0,0 +1,80 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ------------------------------------------------------------------------------
+// Changes to this file must follow the http://aka.ms/api-review process.
+// ------------------------------------------------------------------------------
+
+namespace System.IO.Pipelines
+{
+ public partial struct FlushResult
+ {
+ private int _dummy;
+ public FlushResult(bool isCanceled, bool isCompleted) { throw null; }
+ public bool IsCanceled { get { throw null; } }
+ public bool IsCompleted { get { throw null; } }
+ }
+ public partial interface IDuplexPipe
+ {
+ System.IO.Pipelines.PipeReader Input { get; }
+ System.IO.Pipelines.PipeWriter Output { get; }
+ }
+ public sealed partial class Pipe
+ {
+ public Pipe() { }
+ public Pipe(System.IO.Pipelines.PipeOptions options) { }
+ public System.IO.Pipelines.PipeReader Reader { get { throw null; } }
+ public System.IO.Pipelines.PipeWriter Writer { get { throw null; } }
+ public void Reset() { }
+ }
+ public partial class PipeOptions
+ {
+ public PipeOptions(System.Buffers.MemoryPool<byte> pool = null, System.IO.Pipelines.PipeScheduler readerScheduler = null, System.IO.Pipelines.PipeScheduler writerScheduler = null, long pauseWriterThreshold = (long)0, long resumeWriterThreshold = (long)0, int minimumSegmentSize = 2048, bool useSynchronizationContext = true) { }
+ public static System.IO.Pipelines.PipeOptions Default { get { throw null; } }
+ public int MinimumSegmentSize { get { throw null; } }
+ public long PauseWriterThreshold { get { throw null; } }
+ public System.Buffers.MemoryPool<byte> Pool { get { throw null; } }
+ public System.IO.Pipelines.PipeScheduler ReaderScheduler { get { throw null; } }
+ public long ResumeWriterThreshold { get { throw null; } }
+ public bool UseSynchronizationContext { get { throw null; } }
+ public System.IO.Pipelines.PipeScheduler WriterScheduler { get { throw null; } }
+ }
+ public abstract partial class PipeReader
+ {
+ protected PipeReader() { }
+ public abstract void AdvanceTo(System.SequencePosition consumed);
+ public abstract void AdvanceTo(System.SequencePosition consumed, System.SequencePosition examined);
+ public abstract void CancelPendingRead();
+ public abstract void Complete(System.Exception exception = null);
+ public abstract void OnWriterCompleted(System.Action<System.Exception, object> callback, object state);
+ public abstract System.Threading.Tasks.ValueTask<System.IO.Pipelines.ReadResult> ReadAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
+ public abstract bool TryRead(out System.IO.Pipelines.ReadResult result);
+ }
+ public abstract partial class PipeScheduler
+ {
+ protected PipeScheduler() { }
+ public static System.IO.Pipelines.PipeScheduler Inline { get { throw null; } }
+ public static System.IO.Pipelines.PipeScheduler ThreadPool { get { throw null; } }
+ public abstract void Schedule(System.Action<object> action, object state);
+ }
+ public abstract partial class PipeWriter : System.Buffers.IBufferWriter<byte>
+ {
+ protected PipeWriter() { }
+ public abstract void Advance(int bytes);
+ public abstract void CancelPendingFlush();
+ public abstract void Complete(System.Exception exception = null);
+ public abstract System.Threading.Tasks.ValueTask<System.IO.Pipelines.FlushResult> FlushAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken));
+ public abstract System.Memory<byte> GetMemory(int sizeHint = 0);
+ public abstract System.Span<byte> GetSpan(int sizeHint = 0);
+ public abstract void OnReaderCompleted(System.Action<System.Exception, object> callback, object state);
+ public virtual System.Threading.Tasks.ValueTask<System.IO.Pipelines.FlushResult> WriteAsync(System.ReadOnlyMemory<byte> source, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+ }
+ public partial struct ReadResult
+ {
+ private object _dummy;
+ public ReadResult(System.Buffers.ReadOnlySequence<byte> buffer, bool isCanceled, bool isCompleted) { throw null; }
+ public System.Buffers.ReadOnlySequence<byte> Buffer { get { throw null; } }
+ public bool IsCanceled { get { throw null; } }
+ public bool IsCompleted { get { throw null; } }
+ }
+}
diff --git a/src/System.IO.Pipelines/ref/System.IO.Pipelines.csproj b/src/System.IO.Pipelines/ref/System.IO.Pipelines.csproj
new file mode 100644
index 0000000000..a3dc0912f2
--- /dev/null
+++ b/src/System.IO.Pipelines/ref/System.IO.Pipelines.csproj
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <ProjectGuid>{9C524CA0-92FF-437B-B568-BCE8A794A69A}</ProjectGuid>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.3-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.3-Release|AnyCPU'" />
+ <ItemGroup>
+ <Compile Include="System.IO.Pipelines.cs" />
+ </ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)' == 'netstandard1.3'">
+ <Reference Include="System.Runtime" />
+ <Reference Include="System.Threading.Tasks" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\System.Buffers\ref\System.Buffers.csproj" />
+ <ProjectReference Include="..\..\System.Memory\ref\System.Memory.csproj" />
+ <ProjectReference Include="..\..\System.Threading.Tasks.Extensions\ref\System.Threading.Tasks.Extensions.csproj" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/src/System.IO.Pipelines/src/Configurations.props b/src/System.IO.Pipelines/src/Configurations.props
new file mode 100644
index 0000000000..7eb3ac6025
--- /dev/null
+++ b/src/System.IO.Pipelines/src/Configurations.props
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <BuildConfigurations>
+ netstandard1.3;
+ netstandard;
+ netcoreapp;
+ </BuildConfigurations>
+ </PropertyGroup>
+</Project>
diff --git a/src/System.IO.Pipelines/src/Properties/InternalsVisibleTo.cs b/src/System.IO.Pipelines/src/Properties/InternalsVisibleTo.cs
new file mode 100644
index 0000000000..9bb191bf7b
--- /dev/null
+++ b/src/System.IO.Pipelines/src/Properties/InternalsVisibleTo.cs
@@ -0,0 +1,7 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("System.IO.Pipelines.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010015c01ae1f50e8cc09ba9eac9147cf8fd9fce2cfe9f8dce4f7301c4132ca9fb50ce8cbf1df4dc18dd4d210e4345c744ecb3365ed327efdbc52603faa5e21daa11234c8c4a73e51f03bf192544581ebe107adee3a34928e39d04e524a9ce729d5090bfd7dad9d10c722c0def9ccc08ff0a03790e48bcd1f9b6c476063e1966a1c4")]
diff --git a/src/System.IO.Pipelines/src/Resources/Strings.resx b/src/System.IO.Pipelines/src/Resources/Strings.resx
new file mode 100644
index 0000000000..d923f06339
--- /dev/null
+++ b/src/System.IO.Pipelines/src/Resources/Strings.resx
@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <data name="AdvanceToInvalidCursor" xml:space="preserve">
+ <value>Pipe is already advanced past provided cursor.</value>
+ </data>
+ <data name="BackpressureDeadlock" xml:space="preserve">
+ <value>Advancing examined to the end would cause pipe to deadlock because FlushAsync is waiting.</value>
+ </data>
+ <data name="CannotAdvancePastCurrentBufferSize" xml:space="preserve">
+ <value>Can't advance past buffer size.</value>
+ </data>
+ <data name="CannotCompleteWhileReading" xml:space="preserve">
+ <value>Can't complete reader while reading.</value>
+ </data>
+ <data name="CannotCompleteWhiteWriting" xml:space="preserve">
+ <value>Can't complete writer while writing.</value>
+ </data>
+ <data name="ConcurrentOperationsNotSupported" xml:space="preserve">
+ <value>Concurrent reads or writes are not supported.</value>
+ </data>
+ <data name="GetResultBeforeCompleted" xml:space="preserve">
+ <value>Can't GetResult unless awaiter is completed.</value>
+ </data>
+ <data name="NoReadingOperationToComplete" xml:space="preserve">
+ <value>No reading operation to complete.</value>
+ </data>
+ <data name="NoWritingOperation" xml:space="preserve">
+ <value>No writing operation. Make sure GetMemory() was called.</value>
+ </data>
+ <data name="ReaderAndWriterHasToBeCompleted" xml:space="preserve">
+ <value>Both reader and writer has to be completed to be able to reset the pipe.</value>
+ </data>
+ <data name="ReadingAfterCompleted" xml:space="preserve">
+ <value>Reading is not allowed after reader was completed.</value>
+ </data>
+ <data name="ReadingIsInProgress" xml:space="preserve">
+ <value>Reading is already in progress.</value>
+ </data>
+ <data name="WritingAfterCompleted" xml:space="preserve">
+ <value>Writing is not allowed after writer was completed.</value>
+ </data>
+</root> \ No newline at end of file
diff --git a/src/System.IO.Pipelines/src/System.IO.Pipelines.csproj b/src/System.IO.Pipelines/src/System.IO.Pipelines.csproj
new file mode 100644
index 0000000000..df44a756ed
--- /dev/null
+++ b/src/System.IO.Pipelines/src/System.IO.Pipelines.csproj
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <ProjectGuid>{1032D5F6-5AE7-4002-A0E4-FEBEADFEA977}</ProjectGuid>
+ <DocumentationFile>$(OutputPath)$(MSBuildProjectName).xml</DocumentationFile>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.3-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.3-Release|AnyCPU'" />
+ <ItemGroup>
+ <Compile Include="Properties\InternalsVisibleTo.cs" />
+ <Compile Include="System\IO\Pipelines\BufferSegment.cs" />
+ <Compile Include="System\IO\Pipelines\CompletionData.cs" />
+ <Compile Include="System\IO\Pipelines\FlushResult.cs" />
+ <Compile Include="System\IO\Pipelines\InlineScheduler.cs" />
+ <Compile Include="System\IO\Pipelines\IDuplexPipe.cs" />
+ <Compile Include="System\IO\Pipelines\Pipe.DefaultPipeReader.cs" />
+ <Compile Include="System\IO\Pipelines\Pipe.DefaultPipeWriter.cs" />
+ <Compile Include="System\IO\Pipelines\Pipe.cs" />
+ <Compile Include="System\IO\Pipelines\PipeAwaitable.cs" />
+ <Compile Include="System\IO\Pipelines\PipeCompletion.cs" />
+ <Compile Include="System\IO\Pipelines\PipeCompletionCallback.cs" />
+ <Compile Include="System\IO\Pipelines\PipeCompletionCallbacks.cs" />
+ <Compile Include="System\IO\Pipelines\PipeOptions.cs" />
+ <Compile Include="System\IO\Pipelines\PipeReader.cs" />
+ <Compile Include="System\IO\Pipelines\PipeReaderState.cs" />
+ <Compile Include="System\IO\Pipelines\PipeScheduler.cs" />
+ <Compile Include="System\IO\Pipelines\PipeWriter.cs" />
+ <Compile Include="System\IO\Pipelines\ReadResult.cs" />
+ <Compile Include="System\IO\Pipelines\ResultFlags.cs" />
+ <Compile Include="System\IO\Pipelines\ThrowHelper.cs" />
+ </ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)'=='netcoreapp'">
+ <Compile Include="System\IO\Pipelines\ThreadPoolScheduler.netcoreapp.cs" />
+ </ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)'=='netstandard1.3'">
+ <Compile Include="System\IO\Pipelines\ThreadPoolScheduler.netstandard1.3.cs" />
+ </ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)'=='netstandard'">
+ <Compile Include="System\IO\Pipelines\ThreadPoolScheduler.netstandard.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Reference Include="System.Buffers" />
+ <Reference Include="System.Collections" />
+ <Reference Include="System.Diagnostics.Debug" />
+ <Reference Include="System.Memory" />
+ <Reference Include="System.Resources.ResourceManager" />
+ <Reference Include="System.Runtime" />
+ <Reference Include="System.Runtime.Extensions" />
+ <Reference Include="System.Threading" />
+ <Reference Include="System.Threading.Tasks" Condition="'$(TargetGroup)' == 'netstandard1.3'" />
+ <Reference Include="System.Threading.Tasks.Extensions" />
+ <Reference Include="System.Threading.ThreadPool" Condition="'$(TargetGroup)' != 'netstandard1.3'" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project> \ No newline at end of file
diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/BufferSegment.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/BufferSegment.cs
new file mode 100644
index 0000000000..511e327af0
--- /dev/null
+++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/BufferSegment.cs
@@ -0,0 +1,114 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Diagnostics;
+
+namespace System.IO.Pipelines
+{
+ internal sealed class BufferSegment : ReadOnlySequenceSegment<byte>
+ {
+ private OwnedMemory<byte> _ownedMemory;
+ private BufferSegment _next;
+ private int _end;
+
+ /// <summary>
+ /// The Start represents the offset into AvailableMemory where the range of "active" bytes begins. At the point when the block is leased
+ /// the Start is guaranteed to be equal to 0. The value of Start may be assigned anywhere between 0 and
+ /// AvailableMemory.Length, and must be equal to or less than End.
+ /// </summary>
+ public int Start { get; private set; }
+
+ /// <summary>
+ /// The End represents the offset into AvailableMemory where the range of "active" bytes ends. At the point when the block is leased
+ /// the End is guaranteed to be equal to Start. The value of Start may be assigned anywhere between 0 and
+ /// Buffer.Length, and must be equal to or less than End.
+ /// </summary>
+ public int End
+ {
+ get => _end;
+ set
+ {
+ Debug.Assert(value - Start <= AvailableMemory.Length);
+
+ _end = value;
+ Memory = AvailableMemory.Slice(Start, _end - Start);
+ }
+ }
+
+ /// <summary>
+ /// Reference to the next block of data when the overall "active" bytes spans multiple blocks. At the point when the block is
+ /// leased Next is guaranteed to be null. Start, End, and Next are used together in order to create a linked-list of discontiguous
+ /// working memory. The "active" memory is grown when bytes are copied in, End is increased, and Next is assigned. The "active"
+ /// memory is shrunk when bytes are consumed, Start is increased, and blocks are returned to the pool.
+ /// </summary>
+ public BufferSegment NextSegment
+ {
+ get => _next;
+ set
+ {
+ _next = value;
+ Next = value;
+ }
+ }
+
+ public void SetMemory(OwnedMemory<byte> buffer)
+ {
+ SetMemory(buffer, 0, 0);
+ }
+
+ public void SetMemory(OwnedMemory<byte> ownedMemory, int start, int end, bool readOnly = false)
+ {
+ _ownedMemory = ownedMemory;
+
+ AvailableMemory = _ownedMemory.Memory;
+
+ ReadOnly = readOnly;
+ RunningIndex = 0;
+ Start = start;
+ End = end;
+ NextSegment = null;
+ }
+
+ public void ResetMemory()
+ {
+ _ownedMemory.Release();
+ _ownedMemory = null;
+ AvailableMemory = default;
+ }
+
+ internal OwnedMemory<byte> OwnedMemory => _ownedMemory;
+
+ public Memory<byte> AvailableMemory { get; private set; }
+
+ public int Length => End - Start;
+
+ /// <summary>
+ /// If true, data should not be written into the backing block after the End offset. Data between start and end should never be modified
+ /// since this would break cloning.
+ /// </summary>
+ public bool ReadOnly { get; private set; }
+
+ /// <summary>
+ /// The amount of writable bytes in this segment. It is the amount of bytes between Length and End
+ /// </summary>
+ public int WritableBytes => AvailableMemory.Length - End;
+
+ public void SetNext(BufferSegment segment)
+ {
+ Debug.Assert(segment != null);
+ Debug.Assert(Next == null);
+
+ NextSegment = segment;
+
+ segment = this;
+
+ while (segment.Next != null)
+ {
+ segment.NextSegment.RunningIndex = segment.RunningIndex + segment.Length;
+ segment = segment.NextSegment;
+ }
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/CompletionData.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/CompletionData.cs
new file mode 100644
index 0000000000..9420eccec4
--- /dev/null
+++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/CompletionData.cs
@@ -0,0 +1,24 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading;
+
+namespace System.IO.Pipelines
+{
+ internal readonly struct CompletionData
+ {
+ public Action<object> Completion { get; }
+ public object CompletionState { get; }
+ public ExecutionContext ExecutionContext { get; }
+ public SynchronizationContext SynchronizationContext { get; }
+
+ public CompletionData(Action<object> completion, object completionState, ExecutionContext executionContext, SynchronizationContext synchronizationContext)
+ {
+ Completion = completion;
+ CompletionState = completionState;
+ ExecutionContext = executionContext;
+ SynchronizationContext = synchronizationContext;
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/FlushResult.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/FlushResult.cs
new file mode 100644
index 0000000000..5eab31c0bd
--- /dev/null
+++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/FlushResult.cs
@@ -0,0 +1,42 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.IO.Pipelines
+{
+ /// <summary>
+ /// Result returned by <see cref="PipeWriter.FlushAsync"/> call
+ /// </summary>
+ public struct FlushResult
+ {
+ internal ResultFlags _resultFlags;
+
+ /// <summary>
+ /// Creates a new instance of <see cref="FlushResult"/> setting <see cref="IsCanceled"/> and <see cref="IsCompleted"/> flags
+ /// </summary>
+ public FlushResult(bool isCanceled, bool isCompleted)
+ {
+ _resultFlags = ResultFlags.None;
+
+ if (isCanceled)
+ {
+ _resultFlags |= ResultFlags.Canceled;
+ }
+
+ if (isCompleted)
+ {
+ _resultFlags |= ResultFlags.Completed;
+ }
+ }
+
+ /// <summary>
+ /// True if the current <see cref="PipeWriter.FlushAsync"/> operation was canceled, otherwise false.
+ /// </summary>
+ public bool IsCanceled => (_resultFlags & ResultFlags.Canceled) != 0;
+
+ /// <summary>
+ /// True if the <see cref="PipeWriter"/> is complete otherwise false
+ /// </summary>
+ public bool IsCompleted => (_resultFlags & ResultFlags.Completed) != 0;
+ }
+}
diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/IDuplexPipe.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/IDuplexPipe.cs
new file mode 100644
index 0000000000..20f1e67e69
--- /dev/null
+++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/IDuplexPipe.cs
@@ -0,0 +1,22 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.IO.Pipelines
+{
+ /// <summary>
+ /// Defines a class that provides a duplex pipe from which data can be read from and written to.
+ /// </summary>
+ public interface IDuplexPipe
+ {
+ /// <summary>
+ /// Gets the <see cref="PipeReader"/> half of the duplex pipe.
+ /// </summary>
+ PipeReader Input { get; }
+
+ /// <summary>
+ /// Gets the <see cref="PipeWriter"/> half of the duplex pipe.
+ /// </summary>
+ PipeWriter Output { get; }
+ }
+}
diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/InlineScheduler.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/InlineScheduler.cs
new file mode 100644
index 0000000000..b77041c294
--- /dev/null
+++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/InlineScheduler.cs
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.IO.Pipelines
+{
+ internal sealed class InlineScheduler : PipeScheduler
+ {
+ public override void Schedule(Action<object> action, object state)
+ {
+ action(state);
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.DefaultPipeReader.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.DefaultPipeReader.cs
new file mode 100644
index 0000000000..f11b5db7d0
--- /dev/null
+++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.DefaultPipeReader.cs
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading;
+using System.Threading.Tasks;
+using System.Threading.Tasks.Sources;
+
+namespace System.IO.Pipelines
+{
+ /// <summary>
+ /// Default <see cref="PipeWriter"/> and <see cref="PipeReader"/> implementation.
+ /// </summary>
+ public sealed partial class Pipe
+ {
+ private sealed class DefaultPipeReader : PipeReader, IValueTaskSource<ReadResult>
+ {
+ private readonly Pipe _pipe;
+
+ public DefaultPipeReader(Pipe pipe)
+ {
+ _pipe = pipe;
+ }
+
+ public override bool TryRead(out ReadResult result) => _pipe.TryRead(out result);
+
+ public override ValueTask<ReadResult> ReadAsync(CancellationToken cancellationToken = default) => _pipe.ReadAsync(cancellationToken);
+
+ public override void AdvanceTo(SequencePosition consumed) => _pipe.AdvanceReader(consumed);
+
+ public override void AdvanceTo(SequencePosition consumed, SequencePosition examined) => _pipe.AdvanceReader(consumed, examined);
+
+ public override void CancelPendingRead() => _pipe.CancelPendingRead();
+
+ public override void Complete(Exception exception = null) => _pipe.CompleteReader(exception);
+
+ public override void OnWriterCompleted(Action<Exception, object> callback, object state) => _pipe.OnWriterCompleted(callback, state);
+
+ public ValueTaskSourceStatus GetStatus(short token) => _pipe.GetReadAsyncStatus();
+
+ public ReadResult GetResult(short token) => _pipe.GetReadAsyncResult();
+
+ public void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) => _pipe.OnReadAsyncCompleted(continuation, state, flags);
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.DefaultPipeWriter.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.DefaultPipeWriter.cs
new file mode 100644
index 0000000000..ca92cb718d
--- /dev/null
+++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.DefaultPipeWriter.cs
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading;
+using System.Threading.Tasks;
+using System.Threading.Tasks.Sources;
+
+namespace System.IO.Pipelines
+{
+ /// <summary>
+ /// Default <see cref="PipeWriter"/> and <see cref="PipeReader"/> implementation.
+ /// </summary>
+ public sealed partial class Pipe
+ {
+ private sealed class DefaultPipeWriter : PipeWriter, IValueTaskSource<FlushResult>
+ {
+ private readonly Pipe _pipe;
+
+ public DefaultPipeWriter(Pipe pipe)
+ {
+ _pipe = pipe;
+ }
+
+ public override void Complete(Exception exception = null) => _pipe.CompleteWriter(exception);
+
+ public override void CancelPendingFlush() => _pipe.CancelPendingFlush();
+
+ public override void OnReaderCompleted(Action<Exception, object> callback, object state) => _pipe.OnReaderCompleted(callback, state);
+
+ public override ValueTask<FlushResult> FlushAsync(CancellationToken cancellationToken = default) => _pipe.FlushAsync(cancellationToken);
+
+ public override void Advance(int bytes) => _pipe.Advance(bytes);
+
+ public override Memory<byte> GetMemory(int sizeHint = 0) => _pipe.GetMemory(sizeHint);
+
+ public override Span<byte> GetSpan(int sizeHint = 0) => _pipe.GetMemory(sizeHint).Span;
+
+ public ValueTaskSourceStatus GetStatus(short token) => _pipe.GetFlushAsyncStatus();
+
+ public FlushResult GetResult(short token) => _pipe.GetFlushAsyncResult();
+
+ public void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) => _pipe.OnFlushAsyncCompleted(continuation, state, flags);
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.cs
new file mode 100644
index 0000000000..107957c741
--- /dev/null
+++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/Pipe.cs
@@ -0,0 +1,880 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Threading.Tasks.Sources;
+
+namespace System.IO.Pipelines
+{
+ /// <summary>
+ /// Default <see cref="PipeWriter"/> and <see cref="PipeReader"/> implementation.
+ /// </summary>
+ public sealed partial class Pipe
+ {
+ internal const int SegmentPoolSize = 16;
+
+ private static readonly Action<object> s_signalReaderAwaitable = state => ((Pipe)state).ReaderCancellationRequested();
+ private static readonly Action<object> s_signalWriterAwaitable = state => ((Pipe)state).WriterCancellationRequested();
+ private static readonly Action<object> s_invokeCompletionCallbacks = state => ((PipeCompletionCallbacks)state).Execute();
+
+ // These callbacks all point to the same methods but are different delegate types
+ private static readonly ContextCallback s_executionContextCallback = ExecuteWithExecutionContext;
+ private static readonly ContextCallback s_executionContextRawCallback = ExecuteWithoutExecutionContext;
+ private static readonly SendOrPostCallback s_syncContextExecutionContextCallback = ExecuteWithExecutionContext;
+ private static readonly SendOrPostCallback s_syncContextExecuteWithoutExecutionContextCallback = ExecuteWithoutExecutionContext;
+ private static readonly Action<object> s_scheduleWithExecutionContextCallback = ExecuteWithExecutionContext;
+
+ // This sync objects protects the following state:
+ // 1. _commitHead & _commitHeadIndex
+ // 2. _length
+ // 3. _readerAwaitable & _writerAwaitable
+ private readonly object _sync = new object();
+
+ private readonly MemoryPool<byte> _pool;
+ private readonly int _minimumSegmentSize;
+ private readonly long _pauseWriterThreshold;
+ private readonly long _resumeWriterThreshold;
+
+ private readonly PipeScheduler _readerScheduler;
+ private readonly PipeScheduler _writerScheduler;
+
+ private readonly BufferSegment[] _bufferSegmentPool;
+
+ private readonly DefaultPipeReader _reader;
+ private readonly DefaultPipeWriter _writer;
+
+ private long _length;
+ private long _currentWriteLength;
+
+ private int _pooledSegmentCount;
+
+ private PipeAwaitable _readerAwaitable;
+ private PipeAwaitable _writerAwaitable;
+
+ private PipeCompletion _writerCompletion;
+ private PipeCompletion _readerCompletion;
+
+ // The read head which is the extent of the IPipelineReader's consumed bytes
+ private BufferSegment _readHead;
+ private int _readHeadIndex;
+
+ // The commit head which is the extent of the bytes available to the IPipelineReader to consume
+ private BufferSegment _commitHead;
+ private int _commitHeadIndex;
+
+ // The write head which is the extent of the IPipelineWriter's written bytes
+ private BufferSegment _writingHead;
+
+ private PipeReaderState _readingState;
+
+ private bool _disposed;
+
+ internal long Length => _length;
+
+ /// <summary>
+ /// Initializes the <see cref="Pipe"/> using <see cref="PipeOptions.Default"/> as options.
+ /// </summary>
+ public Pipe() : this(PipeOptions.Default)
+ {
+ }
+
+ /// <summary>
+ /// Initializes the <see cref="Pipe"/> with the specified <see cref="PipeOptions"/>.
+ /// </summary>
+ public Pipe(PipeOptions options)
+ {
+ if (options == null)
+ {
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.options);
+ }
+
+ _bufferSegmentPool = new BufferSegment[SegmentPoolSize];
+
+ _readingState = default;
+ _readerCompletion = default;
+ _writerCompletion = default;
+
+ _pool = options.Pool;
+ _minimumSegmentSize = options.MinimumSegmentSize;
+ _pauseWriterThreshold = options.PauseWriterThreshold;
+ _resumeWriterThreshold = options.ResumeWriterThreshold;
+ _readerScheduler = options.ReaderScheduler;
+ _writerScheduler = options.WriterScheduler;
+ var useSynchronizationContext = options.UseSynchronizationContext;
+ _readerAwaitable = new PipeAwaitable(completed: false, useSynchronizationContext);
+ _writerAwaitable = new PipeAwaitable(completed: true, useSynchronizationContext);
+ _reader = new DefaultPipeReader(this);
+ _writer = new DefaultPipeWriter(this);
+ }
+
+ private void ResetState()
+ {
+ _readerCompletion.Reset();
+ _writerCompletion.Reset();
+ _commitHeadIndex = 0;
+ _currentWriteLength = 0;
+ _length = 0;
+ }
+
+ internal Memory<byte> GetMemory(int sizeHint)
+ {
+ if (_writerCompletion.IsCompleted)
+ {
+ ThrowHelper.ThrowInvalidOperationException_NoWritingAllowed();
+ }
+
+ if (sizeHint < 0)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.minimumSize);
+ }
+
+ lock (_sync)
+ {
+ BufferSegment segment = _writingHead ?? AllocateWriteHeadUnsynchronized(sizeHint);
+
+ int bytesLeftInBuffer = segment.WritableBytes;
+
+ // If inadequate bytes left or if the segment is readonly
+ if (bytesLeftInBuffer == 0 || bytesLeftInBuffer < sizeHint || segment.ReadOnly)
+ {
+ BufferSegment nextSegment = CreateSegmentUnsynchronized();
+ nextSegment.SetMemory(_pool.Rent(GetSegmentSize(sizeHint)));
+
+ segment.SetNext(nextSegment);
+
+ _writingHead = nextSegment;
+ }
+ }
+
+ return _writingHead.AvailableMemory.Slice(_writingHead.End, _writingHead.WritableBytes);
+ }
+
+ private BufferSegment AllocateWriteHeadUnsynchronized(int sizeHint)
+ {
+ BufferSegment segment = null;
+
+ if (_commitHead != null && !_commitHead.ReadOnly)
+ {
+ // Try to return the tail so the calling code can append to it
+ int remaining = _commitHead.WritableBytes;
+
+ if (sizeHint <= remaining && remaining > 0)
+ {
+ // Free tail space of the right amount, use that
+ segment = _commitHead;
+ }
+ }
+
+ if (segment == null)
+ {
+ // No free tail space, allocate a new segment
+ segment = CreateSegmentUnsynchronized();
+ segment.SetMemory(_pool.Rent(GetSegmentSize(sizeHint)));
+ }
+
+ if (_commitHead == null)
+ {
+ // No previous writes have occurred
+ _commitHead = segment;
+ }
+ else if (segment != _commitHead && _commitHead.Next == null)
+ {
+ // Append the segment to the commit head if writes have been committed
+ // and it isn't the same segment (unused tail space)
+ _commitHead.SetNext(segment);
+ }
+
+ // Set write head to assigned segment
+ _writingHead = segment;
+
+ return segment;
+ }
+
+ private int GetSegmentSize(int sizeHint)
+ {
+ // First we need to handle case where hint is smaller than minimum segment size
+ var adjustedToMinimumSize = Math.Max(_minimumSegmentSize, sizeHint);
+ // After that adjust it to fit into pools max buffer size
+ var adjustedToMaximumSize = Math.Min(_pool.MaxBufferSize, adjustedToMinimumSize);
+ return adjustedToMaximumSize;
+ }
+
+ private BufferSegment CreateSegmentUnsynchronized()
+ {
+ if (_pooledSegmentCount > 0)
+ {
+ _pooledSegmentCount--;
+ return _bufferSegmentPool[_pooledSegmentCount];
+ }
+
+ return new BufferSegment();
+ }
+
+ private void ReturnSegmentUnsynchronized(BufferSegment segment)
+ {
+ if (_pooledSegmentCount < _bufferSegmentPool.Length)
+ {
+ _bufferSegmentPool[_pooledSegmentCount] = segment;
+ _pooledSegmentCount++;
+ }
+ }
+
+ internal void CommitUnsynchronized()
+ {
+ if (_writingHead == null)
+ {
+ // Nothing written to commit
+ return;
+ }
+
+ if (_readHead == null)
+ {
+ // Update the head to point to the head of the buffer.
+ // This happens if we called alloc(0) then write
+ _readHead = _commitHead;
+ _readHeadIndex = 0;
+ }
+
+ // Always move the commit head to the write head
+ _commitHead = _writingHead;
+ _commitHeadIndex = _writingHead.End;
+ _length += _currentWriteLength;
+
+ // Do not reset if reader is complete
+ if (_pauseWriterThreshold > 0 &&
+ _length >= _pauseWriterThreshold &&
+ !_readerCompletion.IsCompleted)
+ {
+ _writerAwaitable.Reset();
+ }
+
+ // Clear the writing state
+ _writingHead = null;
+ _currentWriteLength = 0;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void Advance(int bytesWritten)
+ {
+ if (_writingHead == null)
+ {
+ ThrowHelper.ThrowInvalidOperationException_NotWritingNoAlloc();
+ }
+
+ if (bytesWritten > 0)
+ {
+ Debug.Assert(!_writingHead.ReadOnly);
+ Debug.Assert(_writingHead.Next == null);
+
+ Memory<byte> buffer = _writingHead.AvailableMemory;
+
+ if (_writingHead.End > buffer.Length - bytesWritten)
+ {
+ ThrowHelper.ThrowInvalidOperationException_AdvancingPastBufferSize();
+ }
+
+ _writingHead.End += bytesWritten;
+ _currentWriteLength += bytesWritten;
+ }
+ else if (bytesWritten < 0)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.bytesWritten);
+ }
+
+ // and if zero, just do nothing; don't need to validate tail etc
+ }
+
+ internal ValueTask<FlushResult> FlushAsync(CancellationToken cancellationToken)
+ {
+ CompletionData completionData;
+ CancellationTokenRegistration cancellationTokenRegistration;
+ ValueTask<FlushResult> result;
+ lock (_sync)
+ {
+ CommitUnsynchronized();
+
+ // AttachToken before completing reader awaiter in case cancellationToken is already completed
+ cancellationTokenRegistration = _writerAwaitable.AttachToken(cancellationToken, s_signalWriterAwaitable, this);
+
+ _readerAwaitable.Complete(out completionData);
+
+ // If the writer is completed (which it will be most of the time) the return a completed ValueTask
+ if (_writerAwaitable.IsCompleted)
+ {
+ var flushResult = new FlushResult();
+ GetFlushResult(ref flushResult);
+ result = new ValueTask<FlushResult>(flushResult);
+ }
+ else
+ {
+ // Otherwise it's async
+ result = new ValueTask<FlushResult>(_writer, token: 0);
+ }
+ }
+
+ cancellationTokenRegistration.Dispose();
+
+ TrySchedule(_readerScheduler, completionData);
+
+ return result;
+ }
+
+ internal void CompleteWriter(Exception exception)
+ {
+ CompletionData completionData;
+ PipeCompletionCallbacks completionCallbacks;
+ bool readerCompleted;
+
+ lock (_sync)
+ {
+ // Commit any pending buffers
+ CommitUnsynchronized();
+
+ completionCallbacks = _writerCompletion.TryComplete(exception);
+ _readerAwaitable.Complete(out completionData);
+ readerCompleted = _readerCompletion.IsCompleted;
+ }
+
+ if (completionCallbacks != null)
+ {
+ TrySchedule(_readerScheduler, s_invokeCompletionCallbacks, completionCallbacks);
+ }
+
+ TrySchedule(_readerScheduler, completionData);
+
+ if (readerCompleted)
+ {
+ CompletePipe();
+ }
+ }
+
+ internal void AdvanceReader(in SequencePosition consumed)
+ {
+ AdvanceReader(consumed, consumed);
+ }
+
+ internal void AdvanceReader(in SequencePosition consumed, in SequencePosition examined)
+ {
+ // If the reader is completed
+ if (_readerCompletion.IsCompleted)
+ {
+ ThrowHelper.ThrowInvalidOperationException_NoReadingAllowed();
+ }
+
+ // TODO: Use new SequenceMarshal.TryGetReadOnlySequenceSegment to get the correct data
+ // directly casting only works because the type value in ReadOnlySequenceSegment is 0
+ AdvanceReader((BufferSegment)consumed.GetObject(), consumed.GetInteger(), (BufferSegment)examined.GetObject(), examined.GetInteger());
+ }
+
+ internal void AdvanceReader(BufferSegment consumedSegment, int consumedIndex, BufferSegment examinedSegment, int examinedIndex)
+ {
+ BufferSegment returnStart = null;
+ BufferSegment returnEnd = null;
+
+ CompletionData completionData = default;
+
+ lock (_sync)
+ {
+ var examinedEverything = false;
+ if (examinedSegment == _commitHead)
+ {
+ examinedEverything = _commitHead != null ? examinedIndex == _commitHeadIndex - _commitHead.Start : examinedIndex == 0;
+ }
+
+ if (consumedSegment != null)
+ {
+ if (_readHead == null)
+ {
+ ThrowHelper.ThrowInvalidOperationException_AdvanceToInvalidCursor();
+ return;
+ }
+
+ returnStart = _readHead;
+ returnEnd = consumedSegment;
+
+ // Check if we crossed _maximumSizeLow and complete backpressure
+ long consumedBytes = new ReadOnlySequence<byte>(returnStart, _readHeadIndex, consumedSegment, consumedIndex).Length;
+ long oldLength = _length;
+ _length -= consumedBytes;
+
+ if (oldLength >= _resumeWriterThreshold &&
+ _length < _resumeWriterThreshold)
+ {
+ _writerAwaitable.Complete(out completionData);
+ }
+
+ // Check if we consumed entire last segment
+ // if we are going to return commit head we need to check that there is no writing operation that
+ // might be using tailspace
+ if (consumedIndex == returnEnd.Length && _writingHead != returnEnd)
+ {
+ BufferSegment nextBlock = returnEnd.NextSegment;
+ if (_commitHead == returnEnd)
+ {
+ _commitHead = nextBlock;
+ _commitHeadIndex = 0;
+ }
+
+ _readHead = nextBlock;
+ _readHeadIndex = 0;
+ returnEnd = nextBlock;
+ }
+ else
+ {
+ _readHead = consumedSegment;
+ _readHeadIndex = consumedIndex;
+ }
+ }
+
+ // We reset the awaitable to not completed if we've examined everything the producer produced so far
+ // but only if writer is not completed yet
+ if (examinedEverything && !_writerCompletion.IsCompleted)
+ {
+ // Prevent deadlock where reader awaits new data and writer await backpressure
+ if (!_writerAwaitable.IsCompleted)
+ {
+ ThrowHelper.ThrowInvalidOperationException_BackpressureDeadlock();
+ }
+ _readerAwaitable.Reset();
+ }
+
+ while (returnStart != null && returnStart != returnEnd)
+ {
+ returnStart.ResetMemory();
+ ReturnSegmentUnsynchronized(returnStart);
+ returnStart = returnStart.NextSegment;
+ }
+
+ _readingState.End();
+ }
+
+ TrySchedule(_writerScheduler, completionData);
+ }
+
+ internal void CompleteReader(Exception exception)
+ {
+ PipeCompletionCallbacks completionCallbacks;
+ CompletionData completionData;
+ bool writerCompleted;
+
+ lock (_sync)
+ {
+ // If we're reading, treat clean up that state before continuting
+ if (_readingState.IsActive)
+ {
+ _readingState.End();
+ }
+
+ // REVIEW: We should consider cleaning up all of the allocated memory
+ // on the reader side now.
+
+ completionCallbacks = _readerCompletion.TryComplete(exception);
+ _writerAwaitable.Complete(out completionData);
+ writerCompleted = _writerCompletion.IsCompleted;
+ }
+
+ if (completionCallbacks != null)
+ {
+ TrySchedule(_writerScheduler, s_invokeCompletionCallbacks, completionCallbacks);
+ }
+
+ TrySchedule(_writerScheduler, completionData);
+
+ if (writerCompleted)
+ {
+ CompletePipe();
+ }
+ }
+
+ internal void OnWriterCompleted(Action<Exception, object> callback, object state)
+ {
+ if (callback == null)
+ {
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.callback);
+ }
+
+ PipeCompletionCallbacks completionCallbacks;
+ lock (_sync)
+ {
+ completionCallbacks = _writerCompletion.AddCallback(callback, state);
+ }
+
+ if (completionCallbacks != null)
+ {
+ TrySchedule(_readerScheduler, s_invokeCompletionCallbacks, completionCallbacks);
+ }
+ }
+
+ internal void CancelPendingRead()
+ {
+ CompletionData completionData;
+ lock (_sync)
+ {
+ _readerAwaitable.Cancel(out completionData);
+ }
+ TrySchedule(_readerScheduler, completionData);
+ }
+
+ internal void CancelPendingFlush()
+ {
+ CompletionData completionData;
+ lock (_sync)
+ {
+ _writerAwaitable.Cancel(out completionData);
+ }
+ TrySchedule(_writerScheduler, completionData);
+ }
+
+ internal void OnReaderCompleted(Action<Exception, object> callback, object state)
+ {
+ if (callback == null)
+ {
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.callback);
+ }
+
+ PipeCompletionCallbacks completionCallbacks;
+ lock (_sync)
+ {
+ completionCallbacks = _readerCompletion.AddCallback(callback, state);
+ }
+
+ if (completionCallbacks != null)
+ {
+ TrySchedule(_writerScheduler, s_invokeCompletionCallbacks, completionCallbacks);
+ }
+ }
+
+ internal ValueTask<ReadResult> ReadAsync(CancellationToken token)
+ {
+ CancellationTokenRegistration cancellationTokenRegistration;
+ if (_readerCompletion.IsCompleted)
+ {
+ ThrowHelper.ThrowInvalidOperationException_NoReadingAllowed();
+ }
+
+ ValueTask<ReadResult> result;
+ lock (_sync)
+ {
+ cancellationTokenRegistration = _readerAwaitable.AttachToken(token, s_signalReaderAwaitable, this);
+
+ // If the awaitable is already complete then return the value result directly
+ if (_readerAwaitable.IsCompleted)
+ {
+ var readResult = new ReadResult();
+ GetReadResult(ref readResult);
+ result = new ValueTask<ReadResult>(readResult);
+ }
+ else
+ {
+ // Otherwise it's async
+ result = new ValueTask<ReadResult>(_reader, token: 0);
+ }
+ }
+ cancellationTokenRegistration.Dispose();
+
+ return result;
+ }
+
+ internal bool TryRead(out ReadResult result)
+ {
+ lock (_sync)
+ {
+ if (_readerCompletion.IsCompleted)
+ {
+ ThrowHelper.ThrowInvalidOperationException_NoReadingAllowed();
+ }
+
+ result = new ReadResult();
+ if (_length > 0 || _readerAwaitable.IsCompleted)
+ {
+ GetReadResult(ref result);
+ return true;
+ }
+
+ if (_readerAwaitable.HasContinuation)
+ {
+ ThrowHelper.ThrowInvalidOperationException_AlreadyReading();
+ }
+ return false;
+ }
+ }
+
+ private static void TrySchedule(PipeScheduler scheduler, Action<object> action, object state)
+ {
+ if (action != null)
+ {
+ scheduler.Schedule(action, state);
+ }
+ }
+
+ private static void TrySchedule(PipeScheduler scheduler, in CompletionData completionData)
+ {
+ // Nothing to do
+ if (completionData.Completion == null)
+ {
+ return;
+ }
+
+ // Ultimately, we need to call either
+ // 1. The sync context with a delegate
+ // 2. The scheduler with a delegate
+ // That delegate and state will either be the action passed in directly
+ // or it will be that specified delegate wrapped in ExecutionContext.Run
+
+ if (completionData.SynchronizationContext == null)
+ {
+ // We don't have a SynchronizationContext so execute on the specified scheduler
+ if (completionData.ExecutionContext == null)
+ {
+ // We can run directly, this should be the default fast path
+ scheduler.Schedule(completionData.Completion, completionData.CompletionState);
+ return;
+ }
+
+ // We also have to run on the specified execution context so run the scheduler and execute the
+ // delegate on the execution context
+ scheduler.Schedule(s_scheduleWithExecutionContextCallback, completionData);
+ }
+ else
+ {
+ if (completionData.ExecutionContext == null)
+ {
+ // We need to box the struct here since there's no generic overload for state
+ completionData.SynchronizationContext.Post(s_syncContextExecuteWithoutExecutionContextCallback, completionData);
+ }
+ else
+ {
+ // We need to execute the callback with the execution context
+ completionData.SynchronizationContext.Post(s_syncContextExecutionContextCallback, completionData);
+ }
+ }
+ }
+
+ private static void ExecuteWithoutExecutionContext(object state)
+ {
+ CompletionData completionData = (CompletionData)state;
+ completionData.Completion(completionData.CompletionState);
+ }
+
+ private static void ExecuteWithExecutionContext(object state)
+ {
+ CompletionData completionData = (CompletionData)state;
+ Debug.Assert(completionData.ExecutionContext != null);
+ ExecutionContext.Run(completionData.ExecutionContext, s_executionContextRawCallback, state);
+ }
+
+ private void CompletePipe()
+ {
+ lock (_sync)
+ {
+ if (_disposed)
+ {
+ return;
+ }
+
+ _disposed = true;
+ // Return all segments
+ // if _readHead is null we need to try return _commitHead
+ // because there might be a block allocated for writing
+ BufferSegment segment = _readHead ?? _commitHead;
+ while (segment != null)
+ {
+ BufferSegment returnSegment = segment;
+ segment = segment.NextSegment;
+
+ returnSegment.ResetMemory();
+ }
+
+ _writingHead = null;
+ _readHead = null;
+ _commitHead = null;
+ }
+ }
+
+ internal ValueTaskSourceStatus GetReadAsyncStatus()
+ {
+ if (_readerAwaitable.IsCompleted)
+ {
+ if (_writerCompletion.IsFaulted)
+ {
+ return ValueTaskSourceStatus.Faulted;
+ }
+
+ return ValueTaskSourceStatus.Succeeded;
+ }
+ return ValueTaskSourceStatus.Pending;
+ }
+
+ internal void OnReadAsyncCompleted(Action<object> continuation, object state, ValueTaskSourceOnCompletedFlags flags)
+ {
+ CompletionData completionData;
+ bool doubleCompletion;
+ lock (_sync)
+ {
+ _readerAwaitable.OnCompleted(continuation, state, flags, out completionData, out doubleCompletion);
+ }
+ if (doubleCompletion)
+ {
+ Writer.Complete(ThrowHelper.CreateInvalidOperationException_NoConcurrentOperation());
+ }
+ TrySchedule(_readerScheduler, completionData);
+ }
+
+ internal ReadResult GetReadAsyncResult()
+ {
+ if (!_readerAwaitable.IsCompleted)
+ {
+ ThrowHelper.ThrowInvalidOperationException_GetResultNotCompleted();
+ }
+
+ var result = new ReadResult();
+ lock (_sync)
+ {
+ GetReadResult(ref result);
+ }
+ return result;
+ }
+
+ private void GetReadResult(ref ReadResult result)
+ {
+ if (_writerCompletion.IsCompletedOrThrow())
+ {
+ result._resultFlags |= ResultFlags.Completed;
+ }
+
+ bool isCanceled = _readerAwaitable.ObserveCancelation();
+ if (isCanceled)
+ {
+ result._resultFlags |= ResultFlags.Canceled;
+ }
+
+ // No need to read end if there is no head
+ BufferSegment head = _readHead;
+
+ if (head != null)
+ {
+ // Reading commit head shared with writer
+ result._resultBuffer = new ReadOnlySequence<byte>(head, _readHeadIndex, _commitHead, _commitHeadIndex - _commitHead.Start);
+ }
+
+ if (isCanceled)
+ {
+ _readingState.BeginTentative();
+ }
+ else
+ {
+ _readingState.Begin();
+ }
+ }
+
+ internal ValueTaskSourceStatus GetFlushAsyncStatus()
+ {
+ if (_writerAwaitable.IsCompleted)
+ {
+ if (_readerCompletion.IsFaulted)
+ {
+ return ValueTaskSourceStatus.Faulted;
+ }
+
+ return ValueTaskSourceStatus.Succeeded;
+ }
+ return ValueTaskSourceStatus.Pending;
+ }
+
+ internal FlushResult GetFlushAsyncResult()
+ {
+ var result = new FlushResult();
+ lock (_sync)
+ {
+ if (!_writerAwaitable.IsCompleted)
+ {
+ ThrowHelper.ThrowInvalidOperationException_GetResultNotCompleted();
+ }
+
+ GetFlushResult(ref result);
+ }
+
+ return result;
+ }
+
+ private void GetFlushResult(ref FlushResult result)
+ {
+ // Change the state from to be canceled -> observed
+ if (_writerAwaitable.ObserveCancelation())
+ {
+ result._resultFlags |= ResultFlags.Canceled;
+ }
+ if (_readerCompletion.IsCompletedOrThrow())
+ {
+ result._resultFlags |= ResultFlags.Completed;
+ }
+ }
+
+ internal void OnFlushAsyncCompleted(Action<object> continuation, object state, ValueTaskSourceOnCompletedFlags flags)
+ {
+ CompletionData completionData;
+ bool doubleCompletion;
+ lock (_sync)
+ {
+ _writerAwaitable.OnCompleted(continuation, state, flags, out completionData, out doubleCompletion);
+ }
+ if (doubleCompletion)
+ {
+ Reader.Complete(ThrowHelper.CreateInvalidOperationException_NoConcurrentOperation());
+ }
+ TrySchedule(_writerScheduler, completionData);
+ }
+
+ private void ReaderCancellationRequested()
+ {
+ CompletionData completionData;
+ lock (_sync)
+ {
+ _readerAwaitable.Cancel(out completionData);
+ }
+ TrySchedule(_readerScheduler, completionData);
+ }
+
+ private void WriterCancellationRequested()
+ {
+ CompletionData completionData;
+ lock (_sync)
+ {
+ _writerAwaitable.Cancel(out completionData);
+ }
+ TrySchedule(_writerScheduler, completionData);
+ }
+
+ /// <summary>
+ /// Gets the <see cref="PipeReader"/> for this pipe.
+ /// </summary>
+ public PipeReader Reader => _reader;
+
+ /// <summary>
+ /// Gets the <see cref="PipeWriter"/> for this pipe.
+ /// </summary>
+ public PipeWriter Writer => _writer;
+
+ /// <summary>
+ /// Resets the pipe
+ /// </summary>
+ public void Reset()
+ {
+ lock (_sync)
+ {
+ if (!_disposed)
+ {
+ ThrowHelper.ThrowInvalidOperationException_ResetIncompleteReaderWriter();
+ }
+
+ _disposed = false;
+ ResetState();
+ }
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeAwaitable.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeAwaitable.cs
new file mode 100644
index 0000000000..b46bc9a9f7
--- /dev/null
+++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeAwaitable.cs
@@ -0,0 +1,178 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using System.Threading.Tasks.Sources;
+
+namespace System.IO.Pipelines
+{
+ [DebuggerDisplay("CanceledState: {_canceledState}, IsCompleted: {IsCompleted}")]
+ internal struct PipeAwaitable
+ {
+ private static readonly Action<object> s_awaitableIsCompleted = _ => { };
+ private static readonly Action<object> s_awaitableIsNotCompleted = _ => { };
+
+ private CanceledState _canceledState;
+ private Action<object> _completion;
+ private object _completionState;
+ private CancellationToken _cancellationToken;
+ private CancellationTokenRegistration _cancellationTokenRegistration;
+ private SynchronizationContext _synchronizationContext;
+ private ExecutionContext _executionContext;
+ private bool _useSynchronizationContext;
+
+ public PipeAwaitable(bool completed, bool useSynchronizationContext)
+ {
+ _canceledState = CanceledState.NotCanceled;
+ _completion = completed ? s_awaitableIsCompleted : s_awaitableIsNotCompleted;
+ _completionState = null;
+ _synchronizationContext = null;
+ _executionContext = null;
+ _useSynchronizationContext = useSynchronizationContext;
+ }
+
+ public bool IsCompleted => ReferenceEquals(_completion, s_awaitableIsCompleted);
+
+ public bool HasContinuation => !ReferenceEquals(_completion, s_awaitableIsNotCompleted);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public CancellationTokenRegistration AttachToken(CancellationToken cancellationToken, Action<object> callback, object state)
+ {
+ CancellationTokenRegistration oldRegistration;
+ if (!cancellationToken.Equals(_cancellationToken))
+ {
+ oldRegistration = _cancellationTokenRegistration;
+ _cancellationToken = cancellationToken;
+ if (_cancellationToken.CanBeCanceled)
+ {
+ _cancellationToken.ThrowIfCancellationRequested();
+ _cancellationTokenRegistration = _cancellationToken.Register(callback, state);
+ }
+ }
+ return oldRegistration;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Complete(out CompletionData completionData)
+ {
+ Action<object> currentCompletion = _completion;
+ _completion = s_awaitableIsCompleted;
+
+ completionData = default;
+
+ if (!ReferenceEquals(currentCompletion, s_awaitableIsCompleted) &&
+ !ReferenceEquals(currentCompletion, s_awaitableIsNotCompleted))
+ {
+ completionData = new CompletionData(currentCompletion, _completionState, _executionContext, _synchronizationContext);
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Reset()
+ {
+ if (ReferenceEquals(_completion, s_awaitableIsCompleted) &&
+ _canceledState < CanceledState.CancellationPreRequested)
+ {
+ _completion = s_awaitableIsNotCompleted;
+ _completionState = null;
+ _synchronizationContext = null;
+ _executionContext = null;
+ }
+
+ // Change the state from observed -> not cancelled.
+ // We only want to reset the cancelled state if it was observed
+ if (_canceledState == CanceledState.CancelationObserved)
+ {
+ _canceledState = CanceledState.NotCanceled;
+ }
+ }
+
+ public void OnCompleted(Action<object> continuation, object state, ValueTaskSourceOnCompletedFlags flags, out CompletionData completionData, out bool doubleCompletion)
+ {
+ completionData = default;
+
+ doubleCompletion = false;
+ Action<object> awaitableState = _completion;
+ if (ReferenceEquals(awaitableState, s_awaitableIsNotCompleted))
+ {
+ _completion = continuation;
+ _completionState = state;
+
+ // Capture the SynchronizationContext if there's any and we're allowing capture (from pipe options)
+ if (_useSynchronizationContext && (flags & ValueTaskSourceOnCompletedFlags.UseSchedulingContext) != 0)
+ {
+ SynchronizationContext sc = SynchronizationContext.Current;
+ if (sc != null && sc.GetType() != typeof(SynchronizationContext))
+ {
+ _synchronizationContext = SynchronizationContext.Current;
+ }
+ }
+
+ // Capture the execution context
+ if ((flags & ValueTaskSourceOnCompletedFlags.FlowExecutionContext) != 0)
+ {
+ _executionContext = ExecutionContext.Capture();
+ }
+ }
+
+ if (ReferenceEquals(awaitableState, s_awaitableIsCompleted))
+ {
+ completionData = new CompletionData(continuation, state, _executionContext, _synchronizationContext);
+ return;
+ }
+
+ if (!ReferenceEquals(awaitableState, s_awaitableIsNotCompleted))
+ {
+ doubleCompletion = true;
+ completionData = new CompletionData(continuation, state, _executionContext, _synchronizationContext);
+ }
+ }
+
+ public void Cancel(out CompletionData completionData)
+ {
+ Complete(out completionData);
+ _canceledState = completionData.Completion == null ?
+ CanceledState.CancellationPreRequested :
+ CanceledState.CancellationRequested;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool ObserveCancelation()
+ {
+ if (_canceledState == CanceledState.NotCanceled)
+ {
+ return false;
+ }
+
+ bool isPrerequested = _canceledState == CanceledState.CancellationPreRequested;
+
+ if (_canceledState >= CanceledState.CancellationPreRequested)
+ {
+ _canceledState = CanceledState.CancelationObserved;
+
+ // Do not reset awaitable if we were not awaiting in the first place
+ if (!isPrerequested)
+ {
+ Reset();
+ }
+
+ _cancellationToken.ThrowIfCancellationRequested();
+
+ return true;
+ }
+
+ return false;
+ }
+
+ private enum CanceledState
+ {
+ NotCanceled = 0,
+ CancelationObserved = 1,
+ CancellationPreRequested = 2,
+ CancellationRequested = 3,
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeCompletion.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeCompletion.cs
new file mode 100644
index 0000000000..b9b582c658
--- /dev/null
+++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeCompletion.cs
@@ -0,0 +1,120 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Runtime.ExceptionServices;
+
+namespace System.IO.Pipelines
+{
+ [DebuggerDisplay("IsCompleted: {" + nameof(IsCompleted) + "}")]
+ internal struct PipeCompletion
+ {
+ private static readonly ArrayPool<PipeCompletionCallback> s_completionCallbackPool = ArrayPool<PipeCompletionCallback>.Shared;
+ private static readonly Exception s_completedNoException = new Exception();
+
+ private const int InitialCallbacksSize = 1;
+
+ private Exception _exception;
+
+ private PipeCompletionCallback[] _callbacks;
+ private int _callbackCount;
+
+ public bool IsCompleted => _exception != null;
+
+ public bool IsFaulted => IsCompleted && _exception != s_completedNoException;
+
+ public PipeCompletionCallbacks TryComplete(Exception exception = null)
+ {
+ if (_exception == null)
+ {
+ // Set the exception object to the exception passed in or a sentinel value
+ _exception = exception ?? s_completedNoException;
+ }
+ return GetCallbacks();
+ }
+
+ public PipeCompletionCallbacks AddCallback(Action<Exception, object> callback, object state)
+ {
+ if (_callbacks == null)
+ {
+ _callbacks = s_completionCallbackPool.Rent(InitialCallbacksSize);
+ }
+
+ int newIndex = _callbackCount;
+ _callbackCount++;
+
+ if (newIndex == _callbacks.Length)
+ {
+ PipeCompletionCallback[] newArray = s_completionCallbackPool.Rent(_callbacks.Length * 2);
+ Array.Copy(_callbacks, newArray, _callbacks.Length);
+ s_completionCallbackPool.Return(_callbacks, clearArray: true);
+ _callbacks = newArray;
+ }
+
+ _callbacks[newIndex].Callback = callback;
+ _callbacks[newIndex].State = state;
+
+ if (IsCompleted)
+ {
+ return GetCallbacks();
+ }
+
+ return null;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool IsCompletedOrThrow()
+ {
+ if (_exception == null)
+ {
+ return false;
+ }
+
+ if (_exception != s_completedNoException)
+ {
+ ThrowLatchedException();
+ }
+
+ return true;
+ }
+
+ private PipeCompletionCallbacks GetCallbacks()
+ {
+ Debug.Assert(IsCompleted);
+ if (_callbackCount == 0)
+ {
+ return null;
+ }
+
+ var callbacks = new PipeCompletionCallbacks(s_completionCallbackPool,
+ _callbackCount,
+ _exception == s_completedNoException ? null : _exception,
+ _callbacks);
+
+ _callbacks = null;
+ _callbackCount = 0;
+ return callbacks;
+ }
+
+ public void Reset()
+ {
+ Debug.Assert(IsCompleted);
+ Debug.Assert(_callbacks == null);
+ _exception = null;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private void ThrowLatchedException()
+ {
+ ExceptionDispatchInfo.Capture(_exception).Throw();
+ }
+
+ public override string ToString()
+ {
+ return $"{nameof(IsCompleted)}: {IsCompleted}";
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeCompletionCallback.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeCompletionCallback.cs
new file mode 100644
index 0000000000..6647ad6b39
--- /dev/null
+++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeCompletionCallback.cs
@@ -0,0 +1,12 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.IO.Pipelines
+{
+ internal struct PipeCompletionCallback
+ {
+ public Action<Exception, object> Callback;
+ public object State;
+ }
+}
diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeCompletionCallbacks.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeCompletionCallbacks.cs
new file mode 100644
index 0000000000..e8e87baf15
--- /dev/null
+++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeCompletionCallbacks.cs
@@ -0,0 +1,64 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Collections.Generic;
+
+namespace System.IO.Pipelines
+{
+ internal sealed class PipeCompletionCallbacks
+ {
+ private readonly ArrayPool<PipeCompletionCallback> _pool;
+ private readonly int _count;
+ private readonly Exception _exception;
+ private readonly PipeCompletionCallback[] _callbacks;
+
+ public PipeCompletionCallbacks(ArrayPool<PipeCompletionCallback> pool, int count, Exception exception, PipeCompletionCallback[] callbacks)
+ {
+ _pool = pool;
+ _count = count;
+ _exception = exception;
+ _callbacks = callbacks;
+ }
+
+ public void Execute()
+ {
+ if (_callbacks == null || _count == 0)
+ {
+ return;
+ }
+
+ try
+ {
+ List<Exception> exceptions = null;
+
+ for (int i = 0; i < _count; i++)
+ {
+ PipeCompletionCallback callback = _callbacks[i];
+ try
+ {
+ callback.Callback(_exception, callback.State);
+ }
+ catch (Exception ex)
+ {
+ if (exceptions == null)
+ {
+ exceptions = new List<Exception>();
+ }
+ exceptions.Add(ex);
+ }
+ }
+
+ if (exceptions != null)
+ {
+ throw new AggregateException(exceptions);
+ }
+ }
+ finally
+ {
+ _pool.Return(_callbacks, clearArray: true);
+ }
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeOptions.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeOptions.cs
new file mode 100644
index 0000000000..bddbdaaab8
--- /dev/null
+++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeOptions.cs
@@ -0,0 +1,93 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Threading;
+
+namespace System.IO.Pipelines
+{
+ /// <summary>
+ /// Represents a set of <see cref="Pipe"/> options
+ /// </summary>
+ public class PipeOptions
+ {
+ private const int DefaultMinimumSegmentSize = 2048;
+
+ private const int DefaultResumeWriterThreshold = DefaultMinimumSegmentSize * Pipe.SegmentPoolSize / 2;
+
+ private const int DefaultPauseWriterThreshold = DefaultMinimumSegmentSize * Pipe.SegmentPoolSize;
+
+ /// <summary>
+ /// Default instance of <see cref="PipeOptions"/>
+ /// </summary>
+ public static PipeOptions Default { get; } = new PipeOptions();
+
+ /// <summary>
+ /// Creates a new instance of <see cref="PipeOptions"/>
+ /// </summary>
+ public PipeOptions(
+ MemoryPool<byte> pool = null,
+ PipeScheduler readerScheduler = null,
+ PipeScheduler writerScheduler = null,
+ long pauseWriterThreshold = DefaultPauseWriterThreshold,
+ long resumeWriterThreshold = DefaultResumeWriterThreshold,
+ int minimumSegmentSize = DefaultMinimumSegmentSize,
+ bool useSynchronizationContext = true)
+ {
+ if (pauseWriterThreshold < 0)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.pauseWriterThreshold);
+ }
+
+ if (resumeWriterThreshold < 0 && resumeWriterThreshold > pauseWriterThreshold)
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.resumeWriterThreshold);
+ }
+
+ Pool = pool ?? MemoryPool<byte>.Shared;
+ ReaderScheduler = readerScheduler ?? PipeScheduler.ThreadPool;
+ WriterScheduler = writerScheduler ?? PipeScheduler.ThreadPool;
+ PauseWriterThreshold = pauseWriterThreshold;
+ ResumeWriterThreshold = resumeWriterThreshold;
+ MinimumSegmentSize = minimumSegmentSize;
+ UseSynchronizationContext = useSynchronizationContext;
+ }
+
+ /// <summary>
+ /// Gets a value that determines if asynchronous callbacks should be executed on the <see cref="SynchronizationContext" /> they were captured on.
+ /// This takes precedence over the schedulers specified in <see cref="ReaderScheduler"/> and <see cref="WriterScheduler"/>.
+ /// </summary>
+ public bool UseSynchronizationContext { get; }
+
+ /// <summary>
+ /// Gets amount of bytes in <see cref="Pipe"/> when <see cref="PipeWriter.FlushAsync"/> starts blocking
+ /// </summary>
+ public long PauseWriterThreshold { get; }
+
+ /// <summary>
+ /// Gets amount of bytes in <see cref="Pipe"/> when <see cref="PipeWriter.FlushAsync"/> stops blocking
+ /// </summary>
+ public long ResumeWriterThreshold { get; }
+
+ /// <summary>
+ /// Gets minimum size of segment requested from <see cref="Pool"/>
+ /// </summary>
+ public int MinimumSegmentSize { get; }
+
+ /// <summary>
+ /// Gets the <see cref="PipeScheduler"/> used to execute <see cref="PipeWriter"/> callbacks
+ /// </summary>
+ public PipeScheduler WriterScheduler { get; }
+
+ /// <summary>
+ /// Gets the <see cref="PipeScheduler"/> used to execute <see cref="PipeReader"/> callbacks
+ /// </summary>
+ public PipeScheduler ReaderScheduler { get; }
+
+ /// <summary>
+ /// Gets the <see cref="MemoryPool{Byte}"/> instances used for buffer management
+ /// </summary>
+ public MemoryPool<byte> Pool { get; }
+ }
+}
diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeReader.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeReader.cs
new file mode 100644
index 0000000000..90276358ca
--- /dev/null
+++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeReader.cs
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.IO.Pipelines
+{
+ /// <summary>
+ /// Defines a class that provides access to a read side of pipe.
+ /// </summary>
+ public abstract class PipeReader
+ {
+ /// <summary>
+ /// Attempt to synchronously read data the <see cref="PipeReader"/>.
+ /// </summary>
+ /// <param name="result">The <see cref="ReadResult"/></param>
+ /// <returns>True if data was available, or if the call was canceled or the writer was completed.</returns>
+ /// <remarks>If the pipe returns false, there's no need to call <see cref="AdvanceTo(SequencePosition, SequencePosition)"/>.</remarks>
+ public abstract bool TryRead(out ReadResult result);
+
+ /// <summary>
+ /// Asynchronously reads a sequence of bytes from the current <see cref="PipeReader"/>.
+ /// </summary>
+ /// <returns>A <see cref="ValueTask{T}"/> representing the asynchronous read operation.</returns>
+ public abstract ValueTask<ReadResult> ReadAsync(CancellationToken cancellationToken = default);
+
+ /// <summary>
+ /// Moves forward the pipeline's read cursor to after the consumed data.
+ /// </summary>
+ /// <param name="consumed">Marks the extent of the data that has been successfully processed.</param>
+ /// <remarks>
+ /// The memory for the consumed data will be released and no longer available.
+ /// The examined data communicates to the pipeline when it should signal more data is available.
+ /// </remarks>
+ public abstract void AdvanceTo(SequencePosition consumed);
+
+ /// <summary>
+ /// Moves forward the pipeline's read cursor to after the consumed data.
+ /// </summary>
+ /// <param name="consumed">Marks the extent of the data that has been successfully processed.</param>
+ /// <param name="examined">Marks the extent of the data that has been read and examined.</param>
+ /// <remarks>
+ /// The memory for the consumed data will be released and no longer available.
+ /// The examined data communicates to the pipeline when it should signal more data is available.
+ /// </remarks>
+ public abstract void AdvanceTo(SequencePosition consumed, SequencePosition examined);
+
+ /// <summary>
+ /// Cancel to currently pending or if none is pending next call to <see cref="ReadAsync"/>, without completing the <see cref="PipeReader"/>.
+ /// </summary>
+ public abstract void CancelPendingRead();
+
+ /// <summary>
+ /// Signal to the producer that the consumer is done reading.
+ /// </summary>
+ /// <param name="exception">Optional <see cref="Exception"/> indicating a failure that's causing the pipeline to complete.</param>
+ public abstract void Complete(Exception exception = null);
+
+ /// <summary>
+ /// Cancel the pending <see cref="ReadAsync"/> operation. If there is none, cancels next <see cref="ReadAsync"/> operation, without completing the <see cref="PipeWriter"/>.
+ /// </summary>
+ public abstract void OnWriterCompleted(Action<Exception, object> callback, object state);
+ }
+}
diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeReaderState.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeReaderState.cs
new file mode 100644
index 0000000000..caffd36437
--- /dev/null
+++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeReaderState.cs
@@ -0,0 +1,59 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+
+namespace System.IO.Pipelines
+{
+ [DebuggerDisplay("State: {_state}")]
+ internal struct PipeReaderState
+ {
+ private State _state;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Begin()
+ {
+ // Inactive and Tentative are allowed
+ if (_state == State.Active)
+ {
+ ThrowHelper.ThrowInvalidOperationException_AlreadyReading();
+ }
+
+ _state = State.Active;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void BeginTentative()
+ {
+ // Inactive and Tentative are allowed
+ if (_state == State.Active)
+ {
+ ThrowHelper.ThrowInvalidOperationException_AlreadyReading();
+ }
+
+ _state = State.Tentative;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void End()
+ {
+ if (_state == State.Inactive)
+ {
+ ThrowHelper.ThrowInvalidOperationException_NoReadToComplete();
+ }
+
+ _state = State.Inactive;
+ }
+
+ public bool IsActive => _state == State.Active;
+
+ internal enum State: byte
+ {
+ Inactive = 1,
+ Active = 2,
+ Tentative = 3
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeScheduler.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeScheduler.cs
new file mode 100644
index 0000000000..832671a4a8
--- /dev/null
+++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeScheduler.cs
@@ -0,0 +1,30 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.IO.Pipelines
+{
+ /// <summary>
+ /// Abstraction for running <see cref="PipeReader"/> and <see cref="PipeWriter"/> callbacks and continuations
+ /// </summary>
+ public abstract class PipeScheduler
+ {
+ private static readonly ThreadPoolScheduler s_threadPoolScheduler = new ThreadPoolScheduler();
+ private static readonly InlineScheduler s_inlineScheduler = new InlineScheduler();
+
+ /// <summary>
+ /// The <see cref="PipeScheduler"/> implementation that queues callbacks to thread pool
+ /// </summary>
+ public static PipeScheduler ThreadPool => s_threadPoolScheduler;
+
+ /// <summary>
+ /// The <see cref="PipeScheduler"/> implementation that runs callbacks inline
+ /// </summary>
+ public static PipeScheduler Inline => s_inlineScheduler;
+
+ /// <summary>
+ /// Requests <paramref name="action"/> to be run on scheduler with <paramref name="state"/> being passed in
+ /// </summary>
+ public abstract void Schedule(Action<object> action, object state);
+ }
+}
diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeWriter.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeWriter.cs
new file mode 100644
index 0000000000..f8d203e0c8
--- /dev/null
+++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/PipeWriter.cs
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.IO.Pipelines
+{
+ /// <summary>
+ /// Defines a class that provides a pipeline to which data can be written.
+ /// </summary>
+ public abstract class PipeWriter : IBufferWriter<byte>
+ {
+ /// <summary>
+ /// Marks the <see cref="PipeWriter"/> as being complete, meaning no more items will be written to it.
+ /// </summary>
+ /// <param name="exception">Optional <see cref="Exception"/> indicating a failure that's causing the pipeline to complete.</param>
+ public abstract void Complete(Exception exception = null);
+
+ /// <summary>
+ /// Cancel the pending <see cref="FlushAsync"/> operation. If there is none, cancels next <see cref="FlushAsync"/> operation, without completing the <see cref="PipeWriter"/>.
+ /// </summary>
+ public abstract void CancelPendingFlush();
+
+ /// <summary>
+ /// Registers a callback that gets executed when the <see cref="PipeReader"/> side of the pipe is completed
+ /// </summary>
+ public abstract void OnReaderCompleted(Action<Exception, object> callback, object state);
+
+ /// <summary>
+ /// Makes bytes written available to <see cref="PipeReader"/> and runs <see cref="PipeReader.ReadAsync"/> continuation.
+ /// </summary>
+ public abstract ValueTask<FlushResult> FlushAsync(CancellationToken cancellationToken = default);
+
+ /// <inheritdoc />
+ public abstract void Advance(int bytes);
+
+ /// <inheritdoc />
+ public abstract Memory<byte> GetMemory(int sizeHint = 0);
+
+ /// <inheritdoc />
+ public abstract Span<byte> GetSpan(int sizeHint = 0);
+
+ /// <summary>
+ /// Writes <paramref name="source"/> to the pipe and makes data accessible to <see cref="PipeReader"/>
+ /// </summary>
+ public virtual ValueTask<FlushResult> WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken = default)
+ {
+ this.Write(source.Span);
+ return FlushAsync(cancellationToken);
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/ReadResult.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/ReadResult.cs
new file mode 100644
index 0000000000..7c587f199e
--- /dev/null
+++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/ReadResult.cs
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+
+namespace System.IO.Pipelines
+{
+ /// <summary>
+ /// The result of a <see cref="PipeReader.ReadAsync"/> call.
+ /// </summary>
+ public struct ReadResult
+ {
+ internal ReadOnlySequence<byte> _resultBuffer;
+ internal ResultFlags _resultFlags;
+
+ /// <summary>
+ /// Creates a new instance of <see cref="ReadResult"/> setting <see cref="IsCanceled"/> and <see cref="IsCompleted"/> flags
+ /// </summary>
+ public ReadResult(ReadOnlySequence<byte> buffer, bool isCanceled, bool isCompleted)
+ {
+ _resultBuffer = buffer;
+ _resultFlags = ResultFlags.None;
+
+ if (isCompleted)
+ {
+ _resultFlags |= ResultFlags.Completed;
+ }
+ if (isCanceled)
+ {
+ _resultFlags |= ResultFlags.Canceled;
+ }
+ }
+
+ /// <summary>
+ /// The <see cref="ReadOnlySequence{Byte}"/> that was read
+ /// </summary>
+ public ReadOnlySequence<byte> Buffer => _resultBuffer;
+
+ /// <summary>
+ /// True if the current <see cref="PipeReader.ReadAsync"/> operation was canceled, otherwise false.
+ /// </summary>
+ public bool IsCanceled => (_resultFlags & ResultFlags.Canceled) != 0;
+
+ /// <summary>
+ /// True if the <see cref="PipeReader"/> is complete
+ /// </summary>
+ public bool IsCompleted => (_resultFlags & ResultFlags.Completed) != 0;
+ }
+}
diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/ResultFlags.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/ResultFlags.cs
new file mode 100644
index 0000000000..7a0453ccd8
--- /dev/null
+++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/ResultFlags.cs
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.IO.Pipelines
+{
+ [Flags]
+ internal enum ResultFlags : byte
+ {
+ None = 0x0,
+ Canceled = 0x1,
+ Completed = 0x2
+ }
+}
diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/ThreadPoolScheduler.netcoreapp.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/ThreadPoolScheduler.netcoreapp.cs
new file mode 100644
index 0000000000..0b2d9c74cd
--- /dev/null
+++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/ThreadPoolScheduler.netcoreapp.cs
@@ -0,0 +1,17 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.IO.Pipelines
+{
+ internal sealed class ThreadPoolScheduler : PipeScheduler
+ {
+ public override void Schedule(Action<object> action, object state)
+ {
+ System.Threading.ThreadPool.QueueUserWorkItem(action, state, preferLocal: false);
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/ThreadPoolScheduler.netstandard.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/ThreadPoolScheduler.netstandard.cs
new file mode 100644
index 0000000000..19b1885035
--- /dev/null
+++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/ThreadPoolScheduler.netstandard.cs
@@ -0,0 +1,22 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.IO.Pipelines
+{
+ internal sealed class ThreadPoolScheduler : PipeScheduler
+ {
+ public override void Schedule(Action<object> action, object state)
+ {
+ System.Threading.ThreadPool.QueueUserWorkItem(s =>
+ {
+ var tuple = (Tuple<Action<object>, object>)s;
+ tuple.Item1(tuple.Item2);
+ },
+ Tuple.Create(action, state));
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/ThreadPoolScheduler.netstandard1.3.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/ThreadPoolScheduler.netstandard1.3.cs
new file mode 100644
index 0000000000..3c22e3affc
--- /dev/null
+++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/ThreadPoolScheduler.netstandard1.3.cs
@@ -0,0 +1,17 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.IO.Pipelines
+{
+ internal sealed class ThreadPoolScheduler : PipeScheduler
+ {
+ public override void Schedule(Action<object> action, object state)
+ {
+ Task.Factory.StartNew(action, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/src/System/IO/Pipelines/ThrowHelper.cs b/src/System.IO.Pipelines/src/System/IO/Pipelines/ThrowHelper.cs
new file mode 100644
index 0000000000..7f4c7c66aa
--- /dev/null
+++ b/src/System.IO.Pipelines/src/System/IO/Pipelines/ThrowHelper.cs
@@ -0,0 +1,74 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.CompilerServices;
+
+namespace System.IO.Pipelines
+{
+ internal static class ThrowHelper
+ {
+ internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument) => throw CreateArgumentOutOfRangeException(argument);
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static Exception CreateArgumentOutOfRangeException(ExceptionArgument argument) => new ArgumentOutOfRangeException(argument.ToString());
+
+ internal static void ThrowArgumentNullException(ExceptionArgument argument) => throw CreateArgumentNullException(argument);
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static Exception CreateArgumentNullException(ExceptionArgument argument) => new ArgumentNullException(argument.ToString());
+
+ public static void ThrowInvalidOperationException_NotWritingNoAlloc() { throw CreateInvalidOperationException_NotWritingNoAlloc(); }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static Exception CreateInvalidOperationException_NotWritingNoAlloc() => new InvalidOperationException(SR.NoWritingOperation);
+
+ public static void ThrowInvalidOperationException_AlreadyReading() => throw CreateInvalidOperationException_AlreadyReading();
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static Exception CreateInvalidOperationException_AlreadyReading() => new InvalidOperationException(SR.ReadingIsInProgress);
+
+ public static void ThrowInvalidOperationException_NoReadToComplete() => throw CreateInvalidOperationException_NoReadToComplete();
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static Exception CreateInvalidOperationException_NoReadToComplete() => new InvalidOperationException(SR.NoReadingOperationToComplete);
+
+ public static void ThrowInvalidOperationException_NoConcurrentOperation() => throw CreateInvalidOperationException_NoConcurrentOperation();
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static Exception CreateInvalidOperationException_NoConcurrentOperation() => new InvalidOperationException(SR.ConcurrentOperationsNotSupported);
+
+ public static void ThrowInvalidOperationException_GetResultNotCompleted() => throw CreateInvalidOperationException_GetResultNotCompleted();
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static Exception CreateInvalidOperationException_GetResultNotCompleted() => new InvalidOperationException(SR.GetResultBeforeCompleted);
+
+ public static void ThrowInvalidOperationException_NoWritingAllowed() => throw CreateInvalidOperationException_NoWritingAllowed();
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static Exception CreateInvalidOperationException_NoWritingAllowed() => new InvalidOperationException(SR.WritingAfterCompleted);
+
+ public static void ThrowInvalidOperationException_NoReadingAllowed() => throw CreateInvalidOperationException_NoReadingAllowed();
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static Exception CreateInvalidOperationException_NoReadingAllowed() => new InvalidOperationException(SR.ReadingAfterCompleted);
+
+ public static void ThrowInvalidOperationException_AdvancingPastBufferSize() => throw CreateInvalidOperationException_AdvancingPastBufferSize();
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static Exception CreateInvalidOperationException_AdvancingPastBufferSize() => new InvalidOperationException(SR.CannotAdvancePastCurrentBufferSize);
+
+ public static void ThrowInvalidOperationException_BackpressureDeadlock() => throw CreateInvalidOperationException_BackpressureDeadlock();
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static Exception CreateInvalidOperationException_BackpressureDeadlock() => new InvalidOperationException(SR.BackpressureDeadlock);
+
+ public static void ThrowInvalidOperationException_AdvanceToInvalidCursor() => throw CreateInvalidOperationException_AdvanceToInvalidCursor();
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static Exception CreateInvalidOperationException_AdvanceToInvalidCursor() => new InvalidOperationException(SR.AdvanceToInvalidCursor);
+
+ public static void ThrowInvalidOperationException_ResetIncompleteReaderWriter() => throw CreateInvalidOperationException_ResetIncompleteReaderWriter();
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static Exception CreateInvalidOperationException_ResetIncompleteReaderWriter() => new InvalidOperationException(SR.ReaderAndWriterHasToBeCompleted);
+ }
+
+ internal enum ExceptionArgument
+ {
+ minimumSize,
+ bytesWritten,
+ callback,
+ options,
+ pauseWriterThreshold,
+ resumeWriterThreshold
+ }
+}
diff --git a/src/System.IO.Pipelines/tests/BackpressureTests.cs b/src/System.IO.Pipelines/tests/BackpressureTests.cs
new file mode 100644
index 0000000000..c35d01193b
--- /dev/null
+++ b/src/System.IO.Pipelines/tests/BackpressureTests.cs
@@ -0,0 +1,173 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.IO.Pipelines.Tests
+{
+ public class BackpressureTests : IDisposable
+ {
+ public BackpressureTests()
+ {
+ _pool = new TestMemoryPool();
+ _pipe = new Pipe(new PipeOptions(_pool, resumeWriterThreshold: 32, pauseWriterThreshold: 64, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+ }
+
+ public void Dispose()
+ {
+ _pipe.Writer.Complete();
+ _pipe.Reader.Complete();
+ _pool?.Dispose();
+ }
+
+ private readonly TestMemoryPool _pool;
+
+ private readonly Pipe _pipe;
+
+ [Fact]
+ public void AdvanceThrowsIfFlushActiveAndNotConsumedPastThreshold()
+ {
+ PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(64);
+ ValueTask<FlushResult> flushAsync = writableBuffer.FlushAsync();
+ Assert.False(flushAsync.IsCompleted);
+
+ ReadResult result = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
+ SequencePosition consumed = result.Buffer.GetPosition(31);
+ Assert.Throws<InvalidOperationException>(() => _pipe.Reader.AdvanceTo(consumed, result.Buffer.End));
+
+ _pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End);
+ }
+
+ [Fact]
+ public void FlushAsyncAwaitableCompletesWhenReaderAdvancesUnderLow()
+ {
+ PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(64);
+ ValueTask<FlushResult> flushAsync = writableBuffer.FlushAsync();
+
+ Assert.False(flushAsync.IsCompleted);
+
+ ReadResult result = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
+ SequencePosition consumed = result.Buffer.GetPosition(33);
+ _pipe.Reader.AdvanceTo(consumed, consumed);
+
+ Assert.True(flushAsync.IsCompleted);
+ FlushResult flushResult = flushAsync.GetAwaiter().GetResult();
+ Assert.False(flushResult.IsCompleted);
+ }
+
+ [Fact]
+ public void FlushAsyncAwaitableDoesNotCompletesWhenReaderAdvancesUnderHight()
+ {
+ PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(64);
+ ValueTask<FlushResult> flushAsync = writableBuffer.FlushAsync();
+
+ Assert.False(flushAsync.IsCompleted);
+
+ ReadResult result = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
+ SequencePosition consumed = result.Buffer.GetPosition(32);
+ _pipe.Reader.AdvanceTo(consumed, consumed);
+
+ Assert.False(flushAsync.IsCompleted);
+ }
+
+ [Fact]
+ public void FlushAsyncAwaitableResetsOnCommit()
+ {
+ PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(64);
+ ValueTask<FlushResult> flushAsync = writableBuffer.FlushAsync();
+
+ Assert.False(flushAsync.IsCompleted);
+
+ ReadResult result = _pipe.Reader.ReadAsync().GetAwaiter().GetResult();
+ SequencePosition consumed = result.Buffer.GetPosition(33);
+ _pipe.Reader.AdvanceTo(consumed, consumed);
+
+ Assert.True(flushAsync.IsCompleted);
+ FlushResult flushResult = flushAsync.GetAwaiter().GetResult();
+ Assert.False(flushResult.IsCompleted);
+
+ writableBuffer = _pipe.Writer.WriteEmpty(64);
+ flushAsync = writableBuffer.FlushAsync();
+
+ Assert.False(flushAsync.IsCompleted);
+ }
+
+ [Fact]
+ public void FlushAsyncReturnsCompletedIfReaderCompletes()
+ {
+ PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(64);
+ ValueTask<FlushResult> flushAsync = writableBuffer.FlushAsync();
+
+ Assert.False(flushAsync.IsCompleted);
+
+ _pipe.Reader.Complete();
+
+ Assert.True(flushAsync.IsCompleted);
+ FlushResult flushResult = flushAsync.GetAwaiter().GetResult();
+ Assert.True(flushResult.IsCompleted);
+
+ writableBuffer = _pipe.Writer.WriteEmpty(64);
+ flushAsync = writableBuffer.FlushAsync();
+ flushResult = flushAsync.GetAwaiter().GetResult();
+
+ Assert.True(flushResult.IsCompleted);
+ Assert.True(flushAsync.IsCompleted);
+ }
+
+ [Fact]
+ public async Task FlushAsyncReturnsCompletedIfReaderCompletesWithoutAdvance()
+ {
+ PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(64);
+ ValueTask<FlushResult> flushAsync = writableBuffer.FlushAsync();
+
+ Assert.False(flushAsync.IsCompleted);
+
+ ReadResult result = await _pipe.Reader.ReadAsync();
+ _pipe.Reader.Complete();
+
+ Assert.True(flushAsync.IsCompleted);
+ FlushResult flushResult = flushAsync.GetAwaiter().GetResult();
+ Assert.True(flushResult.IsCompleted);
+
+ writableBuffer = _pipe.Writer.WriteEmpty(64);
+ flushAsync = writableBuffer.FlushAsync();
+ flushResult = flushAsync.GetAwaiter().GetResult();
+
+ Assert.True(flushResult.IsCompleted);
+ Assert.True(flushAsync.IsCompleted);
+ }
+
+ [Fact]
+ public void FlushAsyncReturnsCompletedTaskWhenSizeLessThenLimit()
+ {
+ PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(32);
+ ValueTask<FlushResult> flushAsync = writableBuffer.FlushAsync();
+ Assert.True(flushAsync.IsCompleted);
+ FlushResult flushResult = flushAsync.GetAwaiter().GetResult();
+ Assert.False(flushResult.IsCompleted);
+ }
+
+ [Fact]
+ public void FlushAsyncReturnsNonCompletedSizeWhenCommitOverTheLimit()
+ {
+ PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(64);
+ ValueTask<FlushResult> flushAsync = writableBuffer.FlushAsync();
+ Assert.False(flushAsync.IsCompleted);
+ }
+
+ [Fact]
+ public async Task FlushAsyncThrowsIfReaderCompletedWithException()
+ {
+ _pipe.Reader.Complete(new InvalidOperationException("Reader failed"));
+
+ PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(64);
+ InvalidOperationException invalidOperationException =
+ await Assert.ThrowsAsync<InvalidOperationException>(async () => await writableBuffer.FlushAsync());
+ Assert.Equal("Reader failed", invalidOperationException.Message);
+ invalidOperationException = await Assert.ThrowsAsync<InvalidOperationException>(async () => await writableBuffer.FlushAsync());
+ Assert.Equal("Reader failed", invalidOperationException.Message);
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/tests/Configurations.props b/src/System.IO.Pipelines/tests/Configurations.props
new file mode 100644
index 0000000000..91e5be2dd0
--- /dev/null
+++ b/src/System.IO.Pipelines/tests/Configurations.props
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <BuildConfigurations>
+ netcoreapp;
+ netfx-Windows_NT;
+ uap-Windows_NT;
+ </BuildConfigurations>
+ </PropertyGroup>
+</Project>
diff --git a/src/System.IO.Pipelines/tests/FlushAsyncCancellationTests.cs b/src/System.IO.Pipelines/tests/FlushAsyncCancellationTests.cs
new file mode 100644
index 0000000000..8640404276
--- /dev/null
+++ b/src/System.IO.Pipelines/tests/FlushAsyncCancellationTests.cs
@@ -0,0 +1,339 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.IO.Pipelines.Tests
+{
+ public class FlushAsyncCancellationTests : PipeTest
+ {
+ [Fact]
+ public void FlushAsyncCancellationDeadlock()
+ {
+ var cts = new CancellationTokenSource();
+ var cts2 = new CancellationTokenSource();
+
+ PipeWriter buffer = Pipe.Writer.WriteEmpty(MaximumSizeHigh);
+
+ var e = new ManualResetEventSlim();
+
+ ValueTaskAwaiter<FlushResult> awaiter = buffer.FlushAsync(cts.Token).GetAwaiter();
+ awaiter.OnCompleted(
+ () => {
+ // We are on cancellation thread and need to wait untill another FlushAsync call
+ // takes pipe state lock
+ e.Wait();
+
+ // Make sure we had enough time to reach _cancellationTokenRegistration.Dispose
+ Thread.Sleep(100);
+
+ // Try to take pipe state lock
+ buffer.FlushAsync();
+ });
+
+ // Start a thread that would run cancellation calbacks
+ Task cancellationTask = Task.Run(() => cts.Cancel());
+ // Start a thread that would call FlushAsync with different token
+ // and block on _cancellationTokenRegistration.Dispose
+ Task blockingTask = Task.Run(
+ () => {
+ e.Set();
+ buffer.FlushAsync(cts2.Token);
+ });
+
+ bool completed = Task.WhenAll(cancellationTask, blockingTask).Wait(TimeSpan.FromSeconds(10));
+ Assert.True(completed);
+ }
+
+ [Fact]
+ public async Task FlushAsyncCancellationE2E()
+ {
+ var cts = new CancellationTokenSource();
+ var cancelled = false;
+
+ Func<Task> taskFunc = async () => {
+ try
+ {
+ Pipe.Writer.WriteEmpty(MaximumSizeHigh);
+ await Pipe.Writer.FlushAsync(cts.Token);
+ }
+ catch (OperationCanceledException)
+ {
+ cancelled = true;
+ await Pipe.Writer.FlushAsync();
+ }
+ };
+
+ Task task = taskFunc();
+
+ cts.Cancel();
+
+ ReadResult result = await Pipe.Reader.ReadAsync();
+ Assert.Equal(new byte[MaximumSizeHigh], result.Buffer.ToArray());
+ Pipe.Reader.AdvanceTo(result.Buffer.End);
+ await task;
+ Assert.True(cancelled);
+ }
+
+ [Fact]
+ public void FlushAsyncCompletedAfterPreCancellation()
+ {
+ PipeWriter writableBuffer = Pipe.Writer.WriteEmpty(1);
+
+ Pipe.Writer.CancelPendingFlush();
+
+ ValueTask<FlushResult> flushAsync = writableBuffer.FlushAsync();
+
+ Assert.True(flushAsync.IsCompleted);
+
+ FlushResult flushResult = flushAsync.GetAwaiter().GetResult();
+
+ Assert.True(flushResult.IsCanceled);
+
+ flushAsync = writableBuffer.FlushAsync();
+
+ Assert.True(flushAsync.IsCompleted);
+ }
+
+ [Fact]
+ public void FlushAsyncNotCompletedAfterCancellation()
+ {
+ var onCompletedCalled = false;
+ PipeWriter writableBuffer = Pipe.Writer.WriteEmpty(MaximumSizeHigh);
+
+ ValueTaskAwaiter<FlushResult> awaitable = writableBuffer.FlushAsync().GetAwaiter();
+
+ Assert.False(awaitable.IsCompleted);
+ awaitable.OnCompleted(
+ () => {
+ onCompletedCalled = true;
+ Assert.True(awaitable.IsCompleted);
+
+ FlushResult flushResult = awaitable.GetResult();
+
+ Assert.True(flushResult.IsCanceled);
+
+ awaitable = writableBuffer.FlushAsync().GetAwaiter();
+ Assert.False(awaitable.IsCompleted);
+ });
+
+ Pipe.Writer.CancelPendingFlush();
+ Assert.True(onCompletedCalled);
+ }
+
+ [Fact]
+ public void FlushAsyncNotCompletedAfterCancellationTokenCanceled()
+ {
+ var onCompletedCalled = false;
+ var cts = new CancellationTokenSource();
+ PipeWriter writableBuffer = Pipe.Writer.WriteEmpty(MaximumSizeHigh);
+
+ ValueTaskAwaiter<FlushResult> awaitable = writableBuffer.FlushAsync(cts.Token).GetAwaiter();
+
+ Assert.False(awaitable.IsCompleted);
+ awaitable.OnCompleted(
+ () => {
+ onCompletedCalled = true;
+ Assert.True(awaitable.IsCompleted);
+
+ Assert.Throws<OperationCanceledException>(() => awaitable.GetResult());
+
+ awaitable = writableBuffer.FlushAsync().GetAwaiter();
+ Assert.False(awaitable.IsCompleted);
+ });
+
+ cts.Cancel();
+ Assert.True(onCompletedCalled);
+ }
+
+ [Fact]
+ public void FlushAsyncReturnsCanceledIfCanceledBeforeFlush()
+ {
+ PipeWriter writableBuffer = Pipe.Writer.WriteEmpty(MaximumSizeHigh);
+
+ Pipe.Writer.CancelPendingFlush();
+
+ ValueTask<FlushResult> flushAsync = writableBuffer.FlushAsync();
+
+ Assert.True(flushAsync.IsCompleted);
+ FlushResult flushResult = flushAsync.GetAwaiter().GetResult();
+ Assert.True(flushResult.IsCanceled);
+ }
+
+ [Fact]
+ public void FlushAsyncReturnsCanceledIfFlushCanceled()
+ {
+ PipeWriter writableBuffer = Pipe.Writer.WriteEmpty(MaximumSizeHigh);
+ ValueTask<FlushResult> flushAsync = writableBuffer.FlushAsync();
+
+ Assert.False(flushAsync.IsCompleted);
+
+ Pipe.Writer.CancelPendingFlush();
+
+ Assert.True(flushAsync.IsCompleted);
+ FlushResult flushResult = flushAsync.GetAwaiter().GetResult();
+ Assert.True(flushResult.IsCanceled);
+ }
+
+ [Fact]
+ public void FlushAsyncReturnsIsCancelOnCancelPendingFlushAfterGetResult()
+ {
+ PipeWriter writableBuffer = Pipe.Writer.WriteEmpty(MaximumSizeHigh);
+ ValueTaskAwaiter<FlushResult> awaitable = writableBuffer.FlushAsync().GetAwaiter();
+
+ Assert.False(awaitable.IsCompleted);
+ awaitable.OnCompleted(() => { });
+
+ Pipe.Writer.CancelPendingFlush();
+ Pipe.Reader.AdvanceTo(Pipe.Reader.ReadAsync().GetAwaiter().GetResult().Buffer.End);
+
+ Assert.True(awaitable.IsCompleted);
+
+ FlushResult result = awaitable.GetResult();
+ Assert.True(result.IsCanceled);
+ }
+
+ [Fact]
+ public void FlushAsyncReturnsIsCancelOnCancelPendingFlushBeforeGetResult()
+ {
+ PipeWriter writableBuffer = Pipe.Writer.WriteEmpty(MaximumSizeHigh);
+ ValueTaskAwaiter<FlushResult> awaitable = writableBuffer.FlushAsync().GetAwaiter();
+
+ Assert.False(awaitable.IsCompleted);
+ awaitable.OnCompleted(() => { });
+
+ Pipe.Reader.AdvanceTo(Pipe.Reader.ReadAsync().GetAwaiter().GetResult().Buffer.End);
+ Pipe.Writer.CancelPendingFlush();
+
+ Assert.True(awaitable.IsCompleted);
+
+ FlushResult result = awaitable.GetResult();
+ Assert.True(result.IsCanceled);
+ }
+
+ [Fact]
+ public void FlushAsyncThrowsIfPassedCanceledCancellationToken()
+ {
+ var cancellationTokenSource = new CancellationTokenSource();
+ cancellationTokenSource.Cancel();
+
+ Assert.Throws<OperationCanceledException>(() => Pipe.Writer.FlushAsync(cancellationTokenSource.Token));
+ }
+
+ [Fact]
+ public async Task FlushAsyncWithNewCancellationTokenNotAffectedByPrevious()
+ {
+ var cancellationTokenSource1 = new CancellationTokenSource();
+ PipeWriter buffer = Pipe.Writer.WriteEmpty(10);
+ await buffer.FlushAsync(cancellationTokenSource1.Token);
+
+ cancellationTokenSource1.Cancel();
+
+ var cancellationTokenSource2 = new CancellationTokenSource();
+ buffer = Pipe.Writer.WriteEmpty(10);
+ // Verifying that ReadAsync does not throw
+ await buffer.FlushAsync(cancellationTokenSource2.Token);
+ }
+
+ [Fact]
+ public void GetResultThrowsIfFlushAsyncCanceledAfterOnCompleted()
+ {
+ var onCompletedCalled = false;
+ var cancellationTokenSource = new CancellationTokenSource();
+ PipeWriter buffer = Pipe.Writer.WriteEmpty(MaximumSizeHigh);
+
+ ValueTaskAwaiter<FlushResult> awaiter = buffer.FlushAsync(cancellationTokenSource.Token).GetAwaiter();
+
+ awaiter.OnCompleted(
+ () => {
+ onCompletedCalled = true;
+ Assert.Throws<OperationCanceledException>(() => awaiter.GetResult());
+ });
+
+ bool awaiterIsCompleted = awaiter.IsCompleted;
+
+ cancellationTokenSource.Cancel();
+
+ Assert.False(awaiterIsCompleted);
+ Assert.True(onCompletedCalled);
+ }
+
+ [Fact]
+ public void GetResultThrowsIfFlushAsyncCanceledBeforeOnCompleted()
+ {
+ var onCompletedCalled = false;
+ var cancellationTokenSource = new CancellationTokenSource();
+ PipeWriter buffer = Pipe.Writer.WriteEmpty(MaximumSizeHigh);
+
+ ValueTaskAwaiter<FlushResult> awaiter = buffer.FlushAsync(cancellationTokenSource.Token).GetAwaiter();
+ bool awaiterIsCompleted = awaiter.IsCompleted;
+
+ cancellationTokenSource.Cancel();
+
+ awaiter.OnCompleted(
+ () => {
+ onCompletedCalled = true;
+ Assert.Throws<OperationCanceledException>(() => awaiter.GetResult());
+ });
+
+ Assert.False(awaiterIsCompleted);
+ Assert.True(onCompletedCalled);
+ }
+
+ [Fact]
+ public void GetResultThrowsIfFlushAsyncTokenFiredAfterCancelPending()
+ {
+ var onCompletedCalled = false;
+ var cancellationTokenSource = new CancellationTokenSource();
+ PipeWriter buffer = Pipe.Writer.WriteEmpty(MaximumSizeHigh);
+
+ ValueTaskAwaiter<FlushResult> awaiter = buffer.FlushAsync(cancellationTokenSource.Token).GetAwaiter();
+ bool awaiterIsCompleted = awaiter.IsCompleted;
+
+ Pipe.Writer.CancelPendingFlush();
+ cancellationTokenSource.Cancel();
+
+ awaiter.OnCompleted(
+ () => {
+ onCompletedCalled = true;
+ Assert.Throws<OperationCanceledException>(() => awaiter.GetResult());
+ });
+
+ Assert.False(awaiterIsCompleted);
+ Assert.True(onCompletedCalled);
+ }
+
+ [Fact]
+ public async Task FlushAsyncThrowsIfPassedCanceledCancellationTokenAndPipeIsAbleToComplete()
+ {
+ var cancellationTokenSource = new CancellationTokenSource();
+ cancellationTokenSource.Cancel();
+
+ // AsTask is important here, it validates that we are calling completion callback
+ // and not only setting IsCompleted flag
+ var task = Pipe.Reader.ReadAsync().AsTask();
+
+ await Assert.ThrowsAsync<OperationCanceledException>(async () => await Pipe.Writer.FlushAsync(cancellationTokenSource.Token));
+
+ Pipe.Writer.Complete();
+
+ Assert.True(task.IsCompleted);
+ Assert.True(task.Result.IsCompleted);
+ }
+ }
+
+ public static class TestWriterExtensions
+ {
+ public static PipeWriter WriteEmpty(this PipeWriter writer, int count)
+ {
+ writer.GetSpan(count).Slice(0, count).Fill(0);
+ writer.Advance(count);
+ return writer;
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/tests/FlushAsyncCompletionTests.cs b/src/System.IO.Pipelines/tests/FlushAsyncCompletionTests.cs
new file mode 100644
index 0000000000..7579adc707
--- /dev/null
+++ b/src/System.IO.Pipelines/tests/FlushAsyncCompletionTests.cs
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.IO.Pipelines.Tests
+{
+ public class FlushAsyncCompletionTests : PipeTest
+ {
+ [Fact]
+ public void AwaitingFlushAsyncAwaitableTwiceCompletesReaderWithException()
+ {
+ async Task Await(ValueTask<FlushResult> a)
+ {
+ await a;
+ }
+
+ PipeWriter writeBuffer = Pipe.Writer;
+ writeBuffer.Write(new byte[MaximumSizeHigh]);
+ ValueTask<FlushResult> awaitable = writeBuffer.FlushAsync();
+
+ Task task1 = Await(awaitable);
+ Task task2 = Await(awaitable);
+
+ Assert.Equal(true, task1.IsCompleted);
+ Assert.Equal(true, task1.IsFaulted);
+ Assert.Equal("Concurrent reads or writes are not supported.", task1.Exception.InnerExceptions[0].Message);
+
+ Assert.Equal(true, task2.IsCompleted);
+ Assert.Equal(true, task2.IsFaulted);
+ Assert.Equal("Concurrent reads or writes are not supported.", task2.Exception.InnerExceptions[0].Message);
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/tests/FlushResultTests.cs b/src/System.IO.Pipelines/tests/FlushResultTests.cs
new file mode 100644
index 0000000000..50ac67edcb
--- /dev/null
+++ b/src/System.IO.Pipelines/tests/FlushResultTests.cs
@@ -0,0 +1,24 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.IO.Pipelines.Tests
+{
+ public class FlushResultTests
+ {
+ [InlineData(true, true)]
+ [InlineData(true, false)]
+ [InlineData(false, true)]
+ [InlineData(false, false)]
+ [Theory]
+ public void FlushResultCanBeConstructed(bool cancelled, bool completed)
+ {
+ var result = new FlushResult(cancelled, completed);
+
+ Assert.Equal(cancelled, result.IsCanceled);
+ Assert.Equal(completed, result.IsCompleted);
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/tests/PipeCompletionCallbacksTests.cs b/src/System.IO.Pipelines/tests/PipeCompletionCallbacksTests.cs
new file mode 100644
index 0000000000..9a23b4197f
--- /dev/null
+++ b/src/System.IO.Pipelines/tests/PipeCompletionCallbacksTests.cs
@@ -0,0 +1,487 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.IO.Pipelines.Tests
+{
+ public class PipeCompletionCallbacksTests : IDisposable
+ {
+ public PipeCompletionCallbacksTests()
+ {
+ _pool = new TestMemoryPool();
+ }
+
+ public void Dispose()
+ {
+ _pool.Dispose();
+ }
+
+ private readonly TestMemoryPool _pool;
+
+ private class TestScheduler : PipeScheduler
+ {
+ public int CallCount { get; set; }
+
+ public Exception LastException { get; set; }
+
+ public override void Schedule(Action<object> action, object state)
+ {
+ CallCount++;
+ try
+ {
+ action(state);
+ }
+ catch (Exception e)
+ {
+ LastException = e;
+ }
+ }
+ }
+
+ [Fact]
+ public void CompletingReaderFromWriterCallbackWorks()
+ {
+ var callbackRan = false;
+ var pipe = new Pipe(new PipeOptions(_pool, pauseWriterThreshold: 5, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+
+ pipe.Writer.OnReaderCompleted((exception, state) => { pipe.Writer.Complete(); }, null);
+
+ pipe.Reader.OnWriterCompleted((exception, state) => { callbackRan = true; }, null);
+
+ pipe.Reader.Complete();
+ Assert.True(callbackRan);
+ }
+
+ [Fact]
+ public void CompletingWriterFromReaderCallbackWorks()
+ {
+ var callbackRan = false;
+ var pipe = new Pipe(new PipeOptions(_pool, pauseWriterThreshold: 5, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+
+ pipe.Reader.OnWriterCompleted((exception, state) => { pipe.Reader.Complete(); }, null);
+
+ pipe.Writer.OnReaderCompleted((exception, state) => { callbackRan = true; }, null);
+
+ pipe.Writer.Complete();
+ Assert.True(callbackRan);
+ }
+
+ [Fact]
+ public void OnReaderCompletedContinuesOnException()
+ {
+ var callbackState1 = new object();
+ var callbackState2 = new object();
+ var exception1 = new Exception();
+ var exception2 = new Exception();
+
+ var counter = 0;
+
+ var pipe = new Pipe(new PipeOptions(_pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+ pipe.Writer.OnReaderCompleted(
+ (exception, state) =>
+ {
+ Assert.Equal(callbackState1, state);
+ Assert.Equal(0, counter);
+ counter++;
+ throw exception1;
+ }, callbackState1);
+
+ pipe.Writer.OnReaderCompleted(
+ (exception, state) =>
+ {
+ Assert.Equal(callbackState2, state);
+ Assert.Equal(1, counter);
+ counter++;
+ throw exception2;
+ }, callbackState2);
+
+ var aggregateException = Assert.Throws<AggregateException>(() => pipe.Reader.Complete());
+ Assert.Equal(exception1, aggregateException.InnerExceptions[0]);
+ Assert.Equal(exception2, aggregateException.InnerExceptions[1]);
+ Assert.Equal(2, counter);
+ }
+
+ [Fact]
+ public void OnReaderCompletedExceptionSurfacesToWriterScheduler()
+ {
+ var exception = new Exception();
+ var scheduler = new TestScheduler();
+ var pipe = new Pipe(new PipeOptions(_pool, writerScheduler: scheduler, readerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+ pipe.Writer.OnReaderCompleted((e, state) => throw exception, null);
+ pipe.Reader.Complete();
+
+ Assert.Equal(1, scheduler.CallCount);
+ var aggregateException = Assert.IsType<AggregateException>(scheduler.LastException);
+ Assert.Equal(aggregateException.InnerExceptions[0], exception);
+ }
+
+ [Fact]
+ public void OnReaderCompletedExecutesOnSchedulerIfCompleted()
+ {
+ var callbackRan = false;
+ var scheduler = new TestScheduler();
+ var pipe = new Pipe(new PipeOptions(_pool, writerScheduler: scheduler, readerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+ pipe.Reader.Complete();
+
+ pipe.Writer.OnReaderCompleted(
+ (exception, state) =>
+ {
+ Assert.Null(exception);
+ callbackRan = true;
+ }, null);
+
+ Assert.True(callbackRan);
+ Assert.Equal(1, scheduler.CallCount);
+ }
+
+ [Fact]
+ public void OnReaderCompletedIsDetachedDuringReset()
+ {
+ var callbackRan = false;
+ var scheduler = new TestScheduler();
+ var pipe = new Pipe(new PipeOptions(_pool, writerScheduler: scheduler, readerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+ pipe.Writer.OnReaderCompleted((exception, state) => { callbackRan = true; }, null);
+
+ pipe.Reader.Complete();
+ pipe.Writer.Complete();
+ pipe.Reset();
+
+ Assert.True(callbackRan);
+ callbackRan = false;
+
+ pipe.Reader.Complete();
+ pipe.Writer.Complete();
+
+ Assert.Equal(1, scheduler.CallCount);
+ Assert.False(callbackRan);
+ }
+
+ [Fact]
+ public void OnReaderCompletedPassesException()
+ {
+ var callbackRan = false;
+ var pipe = new Pipe(new PipeOptions(_pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+ var readerException = new Exception();
+
+ pipe.Writer.OnReaderCompleted(
+ (exception, state) =>
+ {
+ callbackRan = true;
+ Assert.Same(readerException, exception);
+ }, null);
+ pipe.Reader.Complete(readerException);
+
+ Assert.True(callbackRan);
+ }
+
+ [Fact]
+ public void OnReaderCompletedPassesState()
+ {
+ var callbackRan = false;
+ var callbackState = new object();
+ var pipe = new Pipe(new PipeOptions(_pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+ pipe.Writer.OnReaderCompleted(
+ (exception, state) =>
+ {
+ Assert.Equal(callbackState, state);
+ callbackRan = true;
+ }, callbackState);
+ pipe.Reader.Complete();
+
+ Assert.True(callbackRan);
+ }
+
+ [Fact]
+ public void OnReaderCompletedRanBeforeFlushContinuation()
+ {
+ var callbackRan = false;
+ var continuationRan = false;
+ var pipe = new Pipe(new PipeOptions(_pool, pauseWriterThreshold: 5, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+
+ pipe.Writer.OnReaderCompleted(
+ (exception, state) =>
+ {
+ Assert.False(continuationRan);
+ callbackRan = true;
+ }, null);
+
+ PipeWriter buffer = pipe.Writer.WriteEmpty(10);
+ ValueTaskAwaiter<FlushResult> awaiter = buffer.FlushAsync().GetAwaiter();
+
+ Assert.False(awaiter.IsCompleted);
+ awaiter.OnCompleted(() => { continuationRan = true; });
+ pipe.Reader.Complete();
+
+ Assert.True(callbackRan);
+ pipe.Writer.Complete();
+ }
+
+ [Fact]
+ public void OnReaderCompletedRunsInRegistrationOrder()
+ {
+ var callbackState1 = new object();
+ var callbackState2 = new object();
+ var callbackState3 = new object();
+ var counter = 0;
+
+ var pipe = new Pipe(new PipeOptions(_pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+ pipe.Writer.OnReaderCompleted(
+ (exception, state) =>
+ {
+ Assert.Equal(callbackState1, state);
+ Assert.Equal(0, counter);
+ counter++;
+ }, callbackState1);
+
+ pipe.Writer.OnReaderCompleted(
+ (exception, state) =>
+ {
+ Assert.Equal(callbackState2, state);
+ Assert.Equal(1, counter);
+ counter++;
+ }, callbackState2);
+
+ pipe.Writer.OnReaderCompleted(
+ (exception, state) =>
+ {
+ Assert.Equal(callbackState3, state);
+ Assert.Equal(2, counter);
+ counter++;
+ }, callbackState3);
+
+ pipe.Reader.Complete();
+
+ Assert.Equal(3, counter);
+ }
+
+ [Fact]
+ public void OnReaderCompletedThrowsWithNullCallback()
+ {
+ var pipe = new Pipe(new PipeOptions(_pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+
+ Assert.Throws<ArgumentNullException>(() => pipe.Writer.OnReaderCompleted(null, null));
+ }
+
+ [Fact]
+ public void OnReaderCompletedUsingWriterScheduler()
+ {
+ var callbackRan = false;
+ var scheduler = new TestScheduler();
+ var pipe = new Pipe(new PipeOptions(_pool, writerScheduler: scheduler, readerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+ pipe.Writer.OnReaderCompleted((exception, state) => { callbackRan = true; }, null);
+ pipe.Reader.Complete();
+
+ Assert.True(callbackRan);
+ Assert.Equal(1, scheduler.CallCount);
+ }
+
+ [Fact]
+ public void OnWriterCompletedContinuesOnException()
+ {
+ var callbackState1 = new object();
+ var callbackState2 = new object();
+ var exception1 = new Exception();
+ var exception2 = new Exception();
+
+ var counter = 0;
+
+ var pipe = new Pipe(new PipeOptions(_pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+ pipe.Reader.OnWriterCompleted(
+ (exception, state) =>
+ {
+ Assert.Equal(callbackState1, state);
+ Assert.Equal(0, counter);
+ counter++;
+ throw exception1;
+ }, callbackState1);
+
+ pipe.Reader.OnWriterCompleted(
+ (exception, state) =>
+ {
+ Assert.Equal(callbackState2, state);
+ Assert.Equal(1, counter);
+ counter++;
+ throw exception2;
+ }, callbackState2);
+
+ var aggregateException = Assert.Throws<AggregateException>(() => pipe.Writer.Complete());
+ Assert.Equal(exception1, aggregateException.InnerExceptions[0]);
+ Assert.Equal(exception2, aggregateException.InnerExceptions[1]);
+ Assert.Equal(2, counter);
+ }
+
+ [Fact]
+ public void OnWriterCompletedExceptionSurfacesToReaderScheduler()
+ {
+ var exception = new Exception();
+ var scheduler = new TestScheduler();
+ var pipe = new Pipe(new PipeOptions(_pool, scheduler, PipeScheduler.Inline, useSynchronizationContext: false));
+ pipe.Reader.OnWriterCompleted((e, state) => throw exception, null);
+ pipe.Writer.Complete();
+
+ Assert.Equal(1, scheduler.CallCount);
+ var aggregateException = Assert.IsType<AggregateException>(scheduler.LastException);
+ Assert.Equal(aggregateException.InnerExceptions[0], exception);
+ }
+
+ [Fact]
+ public void OnWriterCompletedExecutedSchedulerIfCompleted()
+ {
+ var callbackRan = false;
+ var scheduler = new TestScheduler();
+ var pipe = new Pipe(new PipeOptions(_pool, scheduler, PipeScheduler.Inline, useSynchronizationContext: false));
+ pipe.Writer.Complete();
+
+ pipe.Reader.OnWriterCompleted(
+ (exception, state) =>
+ {
+ Assert.Null(exception);
+ callbackRan = true;
+ }, null);
+
+ Assert.True(callbackRan);
+ Assert.Equal(1, scheduler.CallCount);
+ }
+
+ [Fact]
+ public void OnWriterCompletedIsDetachedDuringReset()
+ {
+ var callbackRan = false;
+ var scheduler = new TestScheduler();
+ var pipe = new Pipe(new PipeOptions(_pool, scheduler, PipeScheduler.Inline, useSynchronizationContext: false));
+ pipe.Reader.OnWriterCompleted((exception, state) => { callbackRan = true; }, null);
+ pipe.Reader.Complete();
+ pipe.Writer.Complete();
+ pipe.Reset();
+
+ Assert.True(callbackRan);
+ callbackRan = false;
+
+ pipe.Reader.Complete();
+ pipe.Writer.Complete();
+
+ Assert.Equal(1, scheduler.CallCount);
+ Assert.False(callbackRan);
+ }
+
+ [Fact]
+ public void OnWriterCompletedPassesException()
+ {
+ var callbackRan = false;
+ var pipe = new Pipe(new PipeOptions(_pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+ var readerException = new Exception();
+
+ pipe.Reader.OnWriterCompleted(
+ (exception, state) =>
+ {
+ callbackRan = true;
+ Assert.Same(readerException, exception);
+ }, null);
+ pipe.Writer.Complete(readerException);
+
+ Assert.True(callbackRan);
+ }
+
+ [Fact]
+ public void OnWriterCompletedPassesState()
+ {
+ var callbackRan = false;
+ var callbackState = new object();
+ var pipe = new Pipe(new PipeOptions(_pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+ pipe.Reader.OnWriterCompleted(
+ (exception, state) =>
+ {
+ Assert.Equal(callbackState, state);
+ callbackRan = true;
+ }, callbackState);
+ pipe.Writer.Complete();
+
+ Assert.True(callbackRan);
+ }
+
+ [Fact]
+ public void OnWriterCompletedRanBeforeReadContinuation()
+ {
+ var callbackRan = false;
+ var continuationRan = false;
+ var pipe = new Pipe(new PipeOptions(_pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+
+ pipe.Reader.OnWriterCompleted(
+ (exception, state) =>
+ {
+ callbackRan = true;
+ Assert.False(continuationRan);
+ }, null);
+
+ ValueTask<ReadResult> awaiter = pipe.Reader.ReadAsync();
+ Assert.False(awaiter.IsCompleted);
+ awaiter.GetAwaiter().OnCompleted(() => { continuationRan = true; });
+ pipe.Writer.Complete();
+
+ Assert.True(callbackRan);
+ }
+
+ [Fact]
+ public void OnWriterCompletedRunsInRegistrationOrder()
+ {
+ var callbackState1 = new object();
+ var callbackState2 = new object();
+ var callbackState3 = new object();
+ var counter = 0;
+
+ var pipe = new Pipe(new PipeOptions(_pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+ pipe.Reader.OnWriterCompleted(
+ (exception, state) =>
+ {
+ Assert.Equal(callbackState1, state);
+ Assert.Equal(0, counter);
+ counter++;
+ }, callbackState1);
+
+ pipe.Reader.OnWriterCompleted(
+ (exception, state) =>
+ {
+ Assert.Equal(callbackState2, state);
+ Assert.Equal(1, counter);
+ counter++;
+ }, callbackState2);
+
+ pipe.Reader.OnWriterCompleted(
+ (exception, state) =>
+ {
+ Assert.Equal(callbackState3, state);
+ Assert.Equal(2, counter);
+ counter++;
+ }, callbackState3);
+
+ pipe.Writer.Complete();
+
+ Assert.Equal(3, counter);
+ }
+
+ [Fact]
+ public void OnWriterCompletedThrowsWithNullCallback()
+ {
+ var pipe = new Pipe(new PipeOptions(_pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+
+ Assert.Throws<ArgumentNullException>(() => pipe.Reader.OnWriterCompleted(null, null));
+ }
+
+ [Fact]
+ public void OnWriterCompletedUsingReaderScheduler()
+ {
+ var callbackRan = false;
+ var scheduler = new TestScheduler();
+ var pipe = new Pipe(new PipeOptions(_pool, scheduler, PipeScheduler.Inline, useSynchronizationContext: false));
+ pipe.Reader.OnWriterCompleted((exception, state) => { callbackRan = true; }, null);
+ pipe.Writer.Complete();
+
+ Assert.True(callbackRan);
+ Assert.Equal(1, scheduler.CallCount);
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/tests/PipeLengthTests.cs b/src/System.IO.Pipelines/tests/PipeLengthTests.cs
new file mode 100644
index 0000000000..252098d20a
--- /dev/null
+++ b/src/System.IO.Pipelines/tests/PipeLengthTests.cs
@@ -0,0 +1,101 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.IO.Pipelines.Tests
+{
+ public class PipeLengthTests : IDisposable
+ {
+ public PipeLengthTests()
+ {
+ _pool = new TestMemoryPool();
+ _pipe = new Pipe(new PipeOptions(_pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, pauseWriterThreshold: 0, resumeWriterThreshold: 0, useSynchronizationContext: false));
+ }
+
+ public void Dispose()
+ {
+ _pipe.Writer.Complete();
+ _pipe.Reader.Complete();
+ _pool?.Dispose();
+ }
+
+ private readonly TestMemoryPool _pool;
+
+ private readonly Pipe _pipe;
+
+ [Fact]
+ public async Task ByteByByteTest()
+ {
+ for (var i = 1; i <= 1024 * 1024; i++)
+ {
+ _pipe.Writer.GetMemory(100);
+ _pipe.Writer.Advance(1);
+ await _pipe.Writer.FlushAsync();
+
+ Assert.Equal(i, _pipe.Length);
+ }
+
+ await _pipe.Writer.FlushAsync();
+
+ for (int i = 1024 * 1024 - 1; i >= 0; i--)
+ {
+ ReadResult result = await _pipe.Reader.ReadAsync();
+ SequencePosition consumed = result.Buffer.Slice(1).Start;
+
+ Assert.Equal(i + 1, result.Buffer.Length);
+
+ _pipe.Reader.AdvanceTo(consumed, consumed);
+
+ Assert.Equal(i, _pipe.Length);
+ }
+ }
+
+ [Fact]
+ public async Task LengthCorrectAfterAlloc0AdvanceFlush()
+ {
+ _pipe.Writer.GetMemory(0);
+ _pipe.Writer.WriteEmpty(10);
+ await _pipe.Writer.FlushAsync();
+
+ Assert.Equal(10, _pipe.Length);
+ }
+
+ [Fact]
+ public async Task LengthCorrectAfterAllocAdvanceFlush()
+ {
+ PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(10);
+ await writableBuffer.FlushAsync();
+
+ Assert.Equal(10, _pipe.Length);
+ }
+
+ [Fact]
+ public async Task LengthDecreasedAfterReadAdvanceConsume()
+ {
+ _pipe.Writer.GetMemory(100);
+ _pipe.Writer.Advance(10);
+ await _pipe.Writer.FlushAsync();
+
+ ReadResult result = await _pipe.Reader.ReadAsync();
+ SequencePosition consumed = result.Buffer.Slice(5).Start;
+ _pipe.Reader.AdvanceTo(consumed, consumed);
+
+ Assert.Equal(5, _pipe.Length);
+ }
+
+ [Fact]
+ public async Task LengthNotChangeAfterReadAdvanceExamine()
+ {
+ PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(10);
+ await writableBuffer.FlushAsync();
+
+ ReadResult result = await _pipe.Reader.ReadAsync();
+ _pipe.Reader.AdvanceTo(result.Buffer.Start, result.Buffer.End);
+
+ Assert.Equal(10, _pipe.Length);
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/tests/PipeOptionsTests.cs b/src/System.IO.Pipelines/tests/PipeOptionsTests.cs
new file mode 100644
index 0000000000..5e6202faff
--- /dev/null
+++ b/src/System.IO.Pipelines/tests/PipeOptionsTests.cs
@@ -0,0 +1,23 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.IO.Pipelines.Tests
+{
+ public class PipeOptionsTests
+ {
+ [Fact]
+ public void DefaultPauseWriterThresholdIsSet()
+ {
+ Assert.Equal(32768, PipeOptions.Default.PauseWriterThreshold);
+ }
+
+ [Fact]
+ public void DefaultResumeWriterThresholdIsSet()
+ {
+ Assert.Equal(16384, PipeOptions.Default.ResumeWriterThreshold);
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/tests/PipePoolTests.cs b/src/System.IO.Pipelines/tests/PipePoolTests.cs
new file mode 100644
index 0000000000..8e8779accc
--- /dev/null
+++ b/src/System.IO.Pipelines/tests/PipePoolTests.cs
@@ -0,0 +1,239 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.IO.Pipelines.Tests
+{
+ public class PipePoolTests
+ {
+ private class DisposeTrackingBufferPool : TestMemoryPool
+ {
+ public int ReturnedBlocks { get; set; }
+ public int DisposedBlocks { get; set; }
+ public int CurrentlyRentedBlocks { get; set; }
+
+ public override OwnedMemory<byte> Rent(int size)
+ {
+ return new DisposeTrackingOwnedMemory(new byte[size], this);
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ }
+
+ private class DisposeTrackingOwnedMemory : OwnedMemory<byte>
+ {
+ private byte[] _array;
+
+ private readonly DisposeTrackingBufferPool _bufferPool;
+
+ private int _refCount = 1;
+
+ public DisposeTrackingOwnedMemory(byte[] array, DisposeTrackingBufferPool bufferPool)
+ {
+ _array = array;
+ _bufferPool = bufferPool;
+ _bufferPool.CurrentlyRentedBlocks++;
+ }
+
+ public override int Length => _array.Length;
+
+ public override Span<byte> Span
+ {
+ get
+ {
+ if (IsDisposed)
+ throw new ObjectDisposedException(nameof(DisposeTrackingBufferPool));
+ return _array;
+ }
+ }
+
+ public override bool IsDisposed => _array == null;
+
+ protected override bool IsRetained => _refCount > 0;
+
+ public override MemoryHandle Pin(int byteOffset = 0)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override bool TryGetArray(out ArraySegment<byte> segment)
+ {
+ if (IsDisposed)
+ throw new ObjectDisposedException(nameof(DisposeTrackingBufferPool));
+ segment = new ArraySegment<byte>(_array);
+ return true;
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (IsRetained)
+ {
+ throw new InvalidOperationException();
+ }
+ _bufferPool.DisposedBlocks++;
+
+ _array = null;
+ }
+
+ public override bool Release()
+ {
+ _bufferPool.ReturnedBlocks++;
+ _bufferPool.CurrentlyRentedBlocks--;
+ _refCount--;
+ return IsRetained;
+ }
+
+ public override void Retain()
+ {
+ _refCount++;
+ }
+ }
+ }
+
+ [Fact]
+ public async Task AdvanceToEndReturnsAllBlocks()
+ {
+ var pool = new DisposeTrackingBufferPool();
+
+ var writeSize = 512;
+
+ var pipe = new Pipe(new PipeOptions(pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+ while (pool.CurrentlyRentedBlocks != 3)
+ {
+ PipeWriter writableBuffer = pipe.Writer.WriteEmpty(writeSize);
+ await writableBuffer.FlushAsync();
+ }
+
+ ReadResult readResult = await pipe.Reader.ReadAsync();
+ pipe.Reader.AdvanceTo(readResult.Buffer.End);
+
+ Assert.Equal(0, pool.CurrentlyRentedBlocks);
+ Assert.Equal(0, pool.DisposedBlocks);
+ Assert.Equal(3, pool.ReturnedBlocks);
+ }
+
+ [Fact]
+ public async Task CanWriteAfterReturningMultipleBlocks()
+ {
+ var pool = new DisposeTrackingBufferPool();
+
+ var writeSize = 512;
+
+ var pipe = new Pipe(new PipeOptions(pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+
+ // Write two blocks
+ Memory<byte> buffer = pipe.Writer.GetMemory(writeSize);
+ pipe.Writer.Advance(buffer.Length);
+ pipe.Writer.GetMemory(buffer.Length);
+ pipe.Writer.Advance(writeSize);
+ await pipe.Writer.FlushAsync();
+
+ Assert.Equal(2, pool.CurrentlyRentedBlocks);
+
+ // Read everything
+ ReadResult readResult = await pipe.Reader.ReadAsync();
+ pipe.Reader.AdvanceTo(readResult.Buffer.End);
+
+ // Try writing more
+ await pipe.Writer.WriteAsync(new byte[writeSize]);
+
+ Assert.Equal(1, pool.CurrentlyRentedBlocks);
+ Assert.Equal(0, pool.DisposedBlocks);
+ Assert.Equal(2, pool.ReturnedBlocks);
+ }
+
+ [Fact]
+ public async Task MultipleCompleteReaderWriterCauseDisposeOnlyOnce()
+ {
+ var pool = new DisposeTrackingBufferPool();
+
+ var readerWriter = new Pipe(new PipeOptions(pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+ await readerWriter.Writer.WriteAsync(new byte[] { 1 });
+
+ readerWriter.Writer.Complete();
+ readerWriter.Reader.Complete();
+ Assert.Equal(1, pool.ReturnedBlocks);
+ Assert.Equal(0, pool.DisposedBlocks);
+
+ readerWriter.Writer.Complete();
+ readerWriter.Reader.Complete();
+ Assert.Equal(1, pool.ReturnedBlocks);
+ Assert.Equal(0, pool.DisposedBlocks);
+ }
+
+ [Fact]
+ public async Task RentsMinimumSegmentSize()
+ {
+ var pool = new DisposeTrackingBufferPool();
+ var writeSize = 512;
+
+ var pipe = new Pipe(new PipeOptions(pool, minimumSegmentSize: 2020, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+
+ Memory<byte> buffer = pipe.Writer.GetMemory(writeSize);
+ int allocatedSize = buffer.Length;
+ pipe.Writer.Advance(buffer.Length);
+ buffer = pipe.Writer.GetMemory(1);
+ int ensuredSize = buffer.Length;
+ await pipe.Writer.FlushAsync();
+
+ pipe.Reader.Complete();
+ pipe.Writer.Complete();
+
+ Assert.Equal(2020, ensuredSize);
+ Assert.Equal(2020, allocatedSize);
+ }
+
+ [Fact]
+ public void ReturnsWriteHeadOnComplete()
+ {
+ var pool = new DisposeTrackingBufferPool();
+ var pipe = new Pipe(new PipeOptions(pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+ pipe.Writer.GetMemory(512);
+
+ pipe.Reader.Complete();
+ pipe.Writer.Complete();
+ Assert.Equal(0, pool.CurrentlyRentedBlocks);
+ Assert.Equal(1, pool.ReturnedBlocks);
+ Assert.Equal(0, pool.DisposedBlocks);
+ }
+
+ [Fact]
+ public void ReturnsWriteHeadWhenRequestingLargerBlock()
+ {
+ var pool = new DisposeTrackingBufferPool();
+ var pipe = new Pipe(new PipeOptions(pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+ pipe.Writer.GetMemory(512);
+ pipe.Writer.GetMemory(4096);
+
+ pipe.Reader.Complete();
+ pipe.Writer.Complete();
+ Assert.Equal(0, pool.CurrentlyRentedBlocks);
+ Assert.Equal(2, pool.ReturnedBlocks);
+ Assert.Equal(0, pool.DisposedBlocks);
+ }
+
+ [Fact]
+ public async Task WriteDuringReadIsNotReturned()
+ {
+ var pool = new DisposeTrackingBufferPool();
+
+ var writeSize = 512;
+
+ var pipe = new Pipe(new PipeOptions(pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+ await pipe.Writer.WriteAsync(new byte[writeSize]);
+
+ pipe.Writer.GetMemory(writeSize);
+ ReadResult readResult = await pipe.Reader.ReadAsync();
+ pipe.Reader.AdvanceTo(readResult.Buffer.End);
+ pipe.Writer.Write(new byte[writeSize]);
+ await pipe.Writer.FlushAsync();
+
+ Assert.Equal(1, pool.CurrentlyRentedBlocks);
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/tests/PipeReaderWriterFacts.cs b/src/System.IO.Pipelines/tests/PipeReaderWriterFacts.cs
new file mode 100644
index 0000000000..6010fd5b1f
--- /dev/null
+++ b/src/System.IO.Pipelines/tests/PipeReaderWriterFacts.cs
@@ -0,0 +1,826 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.IO.Pipelines.Tests
+{
+ public class PipelineReaderWriterFacts : IDisposable
+ {
+ public PipelineReaderWriterFacts()
+ {
+ _pool = new TestMemoryPool();
+ _pipe = new Pipe(new PipeOptions(_pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+ }
+
+ public void Dispose()
+ {
+ _pipe.Writer.Complete();
+ _pipe.Reader.Complete();
+ _pool?.Dispose();
+ }
+
+ private readonly Pipe _pipe;
+
+ private readonly TestMemoryPool _pool;
+
+ [Fact]
+ public async Task AdvanceEmptyBufferAfterWritingResetsAwaitable()
+ {
+ byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+
+ await _pipe.Writer.WriteAsync(bytes);
+ ReadResult result = await _pipe.Reader.ReadAsync();
+ ReadOnlySequence<byte> buffer = result.Buffer;
+
+ Assert.Equal(11, buffer.Length);
+ Assert.True(buffer.IsSingleSegment);
+ var array = new byte[11];
+ buffer.First.Span.CopyTo(array);
+ Assert.Equal("Hello World", Encoding.ASCII.GetString(array));
+
+ _pipe.Reader.AdvanceTo(buffer.End);
+
+ // Now write 0 and advance 0
+ await _pipe.Writer.WriteAsync(new byte[] { });
+ result = await _pipe.Reader.ReadAsync();
+ _pipe.Reader.AdvanceTo(result.Buffer.End);
+
+ ValueTask<ReadResult> awaitable = _pipe.Reader.ReadAsync();
+ Assert.False(awaitable.IsCompleted);
+ }
+
+ [Fact]
+ public async Task AdvanceResetsCommitHeadIndex()
+ {
+ _pipe.Writer.GetMemory(1);
+ _pipe.Writer.Advance(100);
+ await _pipe.Writer.FlushAsync();
+
+ // Advance to the end
+ ReadResult readResult = await _pipe.Reader.ReadAsync();
+ _pipe.Reader.AdvanceTo(readResult.Buffer.End);
+
+ // Try reading, it should block
+ ValueTask<ReadResult> awaitable = _pipe.Reader.ReadAsync();
+ Assert.False(awaitable.IsCompleted);
+
+ // Unblock without writing anything
+ _pipe.Writer.GetMemory();
+ await _pipe.Writer.FlushAsync();
+
+ Assert.True(awaitable.IsCompleted);
+
+ // Advance to the end should reset awaitable
+ readResult = await awaitable;
+ _pipe.Reader.AdvanceTo(readResult.Buffer.End);
+
+ // Try reading, it should block
+ awaitable = _pipe.Reader.ReadAsync();
+ Assert.False(awaitable.IsCompleted);
+ }
+
+ [Fact]
+ public async Task AdvanceShouldResetStateIfReadCanceled()
+ {
+ _pipe.Reader.CancelPendingRead();
+
+ ReadResult result = await _pipe.Reader.ReadAsync();
+ ReadOnlySequence<byte> buffer = result.Buffer;
+ _pipe.Reader.AdvanceTo(buffer.End);
+
+ Assert.False(result.IsCompleted);
+ Assert.True(result.IsCanceled);
+ Assert.True(buffer.IsEmpty);
+
+ ValueTask<ReadResult> awaitable = _pipe.Reader.ReadAsync();
+ Assert.False(awaitable.IsCompleted);
+ }
+
+ [Fact]
+ public async Task AdvanceToInvalidCursorThrows()
+ {
+ await _pipe.Writer.WriteAsync(new byte[100]);
+
+ ReadResult result = await _pipe.Reader.ReadAsync();
+ ReadOnlySequence<byte> buffer = result.Buffer;
+
+ _pipe.Reader.AdvanceTo(buffer.End);
+
+ _pipe.Reader.CancelPendingRead();
+ result = await _pipe.Reader.ReadAsync();
+ Assert.Throws<InvalidOperationException>(() => _pipe.Reader.AdvanceTo(buffer.End));
+ _pipe.Reader.AdvanceTo(result.Buffer.End);
+ }
+
+ [Fact]
+ public async Task AdvanceWithGetPositionCrossingIntoWriteHeadWorks()
+ {
+ // Create two blocks
+ Memory<byte> memory = _pipe.Writer.GetMemory(1);
+ _pipe.Writer.Advance(memory.Length);
+ memory = _pipe.Writer.GetMemory(1);
+ _pipe.Writer.Advance(memory.Length);
+ await _pipe.Writer.FlushAsync();
+
+ // Read single block
+ ReadResult readResult = await _pipe.Reader.ReadAsync();
+
+ // Allocate more memory
+ memory = _pipe.Writer.GetMemory(1);
+
+ // Create position that would cross into write head
+ ReadOnlySequence<byte> buffer = readResult.Buffer;
+ SequencePosition position = buffer.GetPosition(buffer.Length);
+
+ // Return everything
+ _pipe.Reader.AdvanceTo(position);
+
+ // Advance writer
+ _pipe.Writer.Advance(memory.Length);
+ }
+
+ [Fact]
+ public async Task CompleteReaderAfterFlushWithoutAdvancingDoesNotThrow()
+ {
+ await _pipe.Writer.FlushAsync();
+ ReadResult result = await _pipe.Reader.ReadAsync();
+ ReadOnlySequence<byte> buffer = result.Buffer;
+
+ _pipe.Reader.Complete();
+ }
+
+ [Fact]
+ public async Task ResetAfterCompleteReaderAndWriterWithoutAdvancingClearsEverything()
+ {
+ _pipe.Writer.WriteEmpty(4094);
+ _pipe.Writer.WriteEmpty(4094);
+ await _pipe.Writer.FlushAsync();
+ ReadResult result = await _pipe.Reader.ReadAsync();
+ ReadOnlySequence<byte> buffer = result.Buffer;
+
+ SequenceMarshal.TryGetReadOnlySequenceSegment(
+ buffer,
+ out ReadOnlySequenceSegment<byte> start,
+ out int startIndex,
+ out ReadOnlySequenceSegment<byte> end,
+ out int endIndex);
+
+ var startSegment = (BufferSegment)start;
+ var endSegment = (BufferSegment)end;
+ Assert.NotNull(startSegment.OwnedMemory);
+ Assert.NotNull(endSegment.OwnedMemory);
+
+ _pipe.Reader.Complete();
+
+ // Nothing cleaned up
+ Assert.NotNull(startSegment.OwnedMemory);
+ Assert.NotNull(endSegment.OwnedMemory);
+
+ _pipe.Writer.Complete();
+
+ // Should be cleaned up now
+ Assert.Null(startSegment.OwnedMemory);
+ Assert.Null(endSegment.OwnedMemory);
+
+ _pipe.Reset();
+ }
+
+ [Fact]
+ public async Task AdvanceAfterCompleteThrows()
+ {
+ await _pipe.Writer.WriteAsync(new byte[1]);
+ ReadResult result = await _pipe.Reader.ReadAsync();
+ ReadOnlySequence<byte> buffer = result.Buffer;
+
+ _pipe.Reader.Complete();
+
+ var exception = Assert.Throws<InvalidOperationException>(() => _pipe.Reader.AdvanceTo(buffer.End));
+ Assert.Equal("Reading is not allowed after reader was completed.", exception.Message);
+ }
+
+ [Fact]
+ public async Task EmptyBufferStartCrossingSegmentBoundaryIsTreatedLikeAndEnd()
+ {
+ Memory<byte> memory = _pipe.Writer.GetMemory();
+ // Append one full segment to a pipe
+ _pipe.Writer.Write(memory.Span);
+ await _pipe.Writer.FlushAsync();
+
+ // Consume entire segment
+ ReadResult result = await _pipe.Reader.ReadAsync();
+ _pipe.Reader.AdvanceTo(result.Buffer.End);
+
+ // Append empty segment
+ _pipe.Writer.GetMemory(1);
+ await _pipe.Writer.FlushAsync();
+
+ result = await _pipe.Reader.ReadAsync();
+
+ Assert.True(result.Buffer.IsEmpty);
+ Assert.Equal(result.Buffer.Start, result.Buffer.End);
+
+ _pipe.Writer.GetMemory();
+ _pipe.Reader.AdvanceTo(result.Buffer.Start);
+ ValueTask<ReadResult> awaitable = _pipe.Reader.ReadAsync();
+ Assert.False(awaitable.IsCompleted);
+ }
+
+ [Fact]
+ public void FlushAsync_ReturnsCompletedTaskWhenMaxSizeIfZero()
+ {
+ PipeWriter writableBuffer = _pipe.Writer.WriteEmpty(1);
+ ValueTask<FlushResult> flushTask = writableBuffer.FlushAsync();
+ Assert.True(flushTask.IsCompleted);
+
+ writableBuffer = _pipe.Writer.WriteEmpty(1);
+ flushTask = writableBuffer.FlushAsync();
+ Assert.True(flushTask.IsCompleted);
+ }
+
+ [Fact]
+ public async Task FlushAsync_ThrowsIfWriterReaderWithException()
+ {
+ void ThrowTestException()
+ {
+ try
+ {
+ throw new InvalidOperationException("Reader exception");
+ }
+ catch (Exception e)
+ {
+ _pipe.Reader.Complete(e);
+ }
+ }
+
+ ThrowTestException();
+
+ InvalidOperationException invalidOperationException =
+ await Assert.ThrowsAsync<InvalidOperationException>(async () => await _pipe.Writer.FlushAsync());
+
+ Assert.Equal("Reader exception", invalidOperationException.Message);
+ Assert.Contains("ThrowTestException", invalidOperationException.StackTrace);
+
+ invalidOperationException = await Assert.ThrowsAsync<InvalidOperationException>(async () => await _pipe.Writer.FlushAsync());
+ Assert.Equal("Reader exception", invalidOperationException.Message);
+ Assert.Contains("ThrowTestException", invalidOperationException.StackTrace);
+ }
+
+ [Fact]
+ public async Task HelloWorldAcrossTwoBlocks()
+ {
+ // block 1 -> block2
+ // [padding..hello] -> [ world ]
+ PipeWriter writeBuffer = _pipe.Writer;
+ var blockSize = _pipe.Writer.GetMemory().Length;
+
+ byte[] paddingBytes = Enumerable.Repeat((byte)'a', blockSize - 5).ToArray();
+ byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+
+ writeBuffer.Write(paddingBytes);
+ writeBuffer.Write(bytes);
+ await writeBuffer.FlushAsync();
+
+ ReadResult result = await _pipe.Reader.ReadAsync();
+ ReadOnlySequence<byte> buffer = result.Buffer;
+ Assert.False(buffer.IsSingleSegment);
+ ReadOnlySequence<byte> helloBuffer = buffer.Slice(blockSize - 5);
+ Assert.False(helloBuffer.IsSingleSegment);
+ var memory = new List<ReadOnlyMemory<byte>>();
+ foreach (ReadOnlyMemory<byte> m in helloBuffer)
+ {
+ memory.Add(m);
+ }
+
+ List<ReadOnlyMemory<byte>> spans = memory;
+ _pipe.Reader.AdvanceTo(buffer.Start, buffer.Start);
+
+ Assert.Equal(2, memory.Count);
+ var helloBytes = new byte[spans[0].Length];
+ spans[0].Span.CopyTo(helloBytes);
+ var worldBytes = new byte[spans[1].Length];
+ spans[1].Span.CopyTo(worldBytes);
+ Assert.Equal("Hello", Encoding.ASCII.GetString(helloBytes));
+ Assert.Equal(" World", Encoding.ASCII.GetString(worldBytes));
+ }
+
+ [Fact]
+ public async Task ReadAsync_ThrowsIfWriterCompletedWithException()
+ {
+ void ThrowTestException()
+ {
+ try
+ {
+ throw new InvalidOperationException("Writer exception");
+ }
+ catch (Exception e)
+ {
+ _pipe.Writer.Complete(e);
+ }
+ }
+
+ ThrowTestException();
+
+ InvalidOperationException invalidOperationException =
+ await Assert.ThrowsAsync<InvalidOperationException>(async () => await _pipe.Reader.ReadAsync());
+
+ Assert.Equal("Writer exception", invalidOperationException.Message);
+ Assert.Contains("ThrowTestException", invalidOperationException.StackTrace);
+
+ invalidOperationException = await Assert.ThrowsAsync<InvalidOperationException>(async () => await _pipe.Reader.ReadAsync());
+ Assert.Equal("Writer exception", invalidOperationException.Message);
+ Assert.Contains("ThrowTestException", invalidOperationException.StackTrace);
+ }
+
+ [Fact]
+ public async Task ReaderShouldNotGetUnflushedBytes()
+ {
+ // Write 10 and flush
+ PipeWriter buffer = _pipe.Writer;
+ buffer.Write(new byte[] { 0, 0, 0, 10 });
+ await buffer.FlushAsync();
+
+ // Write 9
+ buffer = _pipe.Writer;
+ buffer.Write(new byte[] { 0, 0, 0, 9 });
+
+ // Write 8
+ buffer.Write(new byte[] { 0, 0, 0, 8 });
+
+ // Make sure we don't see it yet
+ ReadResult result = await _pipe.Reader.ReadAsync();
+ ReadOnlySequence<byte> reader = result.Buffer;
+
+ Assert.Equal(4, reader.Length);
+ Assert.Equal(new byte[] { 0, 0, 0, 10 }, reader.ToArray());
+
+ // Don't move
+ _pipe.Reader.AdvanceTo(reader.Start);
+
+ // Now flush
+ await buffer.FlushAsync();
+
+ reader = (await _pipe.Reader.ReadAsync()).Buffer;
+
+ Assert.Equal(12, reader.Length);
+ Assert.Equal(new byte[] { 0, 0, 0, 10 }, reader.Slice(0, 4).ToArray());
+ Assert.Equal(new byte[] { 0, 0, 0, 9 }, reader.Slice(4, 4).ToArray());
+ Assert.Equal(new byte[] { 0, 0, 0, 8 }, reader.Slice(8, 4).ToArray());
+
+ _pipe.Reader.AdvanceTo(reader.Start, reader.Start);
+ }
+
+ [Fact]
+ public async Task ReaderShouldNotGetUnflushedBytesWhenOverflowingSegments()
+ {
+ // Fill the block with stuff leaving 5 bytes at the end
+ Memory<byte> buffer = _pipe.Writer.GetMemory();
+
+ int len = buffer.Length;
+ // Fill the buffer with garbage
+ // block 1 -> block2
+ // [padding..hello] -> [ world ]
+ byte[] paddingBytes = Enumerable.Repeat((byte)'a', len - 5).ToArray();
+ _pipe.Writer.Write(paddingBytes);
+ await _pipe.Writer.FlushAsync();
+
+ // Write 10 and flush
+ _pipe.Writer.Write(new byte[] { 0, 0, 0, 10 });
+
+ // Write 9
+ _pipe.Writer.Write(new byte[] { 0, 0, 0, 9 });
+
+ // Write 8
+ _pipe.Writer.Write(new byte[] { 0, 0, 0, 8 });
+
+ // Make sure we don't see it yet
+ ReadResult result = await _pipe.Reader.ReadAsync();
+ ReadOnlySequence<byte> reader = result.Buffer;
+
+ Assert.Equal(len - 5, reader.Length);
+
+ // Don't move
+ _pipe.Reader.AdvanceTo(reader.End);
+
+ // Now flush
+ await _pipe.Writer.FlushAsync();
+
+ reader = (await _pipe.Reader.ReadAsync()).Buffer;
+
+ Assert.Equal(12, reader.Length);
+ Assert.Equal(new byte[] { 0, 0, 0, 10 }, reader.Slice(0, 4).ToArray());
+ Assert.Equal(new byte[] { 0, 0, 0, 9 }, reader.Slice(4, 4).ToArray());
+ Assert.Equal(new byte[] { 0, 0, 0, 8 }, reader.Slice(8, 4).ToArray());
+
+ _pipe.Reader.AdvanceTo(reader.Start, reader.Start);
+ }
+
+ [Fact]
+ public async Task ReaderShouldNotGetUnflushedBytesWithAppend()
+ {
+ // Write 10 and flush
+ PipeWriter buffer = _pipe.Writer;
+ buffer.Write(new byte[] { 0, 0, 0, 10 });
+ await buffer.FlushAsync();
+
+ // Write Hello to another pipeline and get the buffer
+ byte[] bytes = Encoding.ASCII.GetBytes("Hello");
+
+ var c2 = new Pipe(new PipeOptions(_pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline));
+ await c2.Writer.WriteAsync(bytes);
+ ReadResult result = await c2.Reader.ReadAsync();
+ ReadOnlySequence<byte> c2Buffer = result.Buffer;
+
+ Assert.Equal(bytes.Length, c2Buffer.Length);
+
+ // Write 9 to the buffer
+ buffer = _pipe.Writer;
+ buffer.Write(new byte[] { 0, 0, 0, 9 });
+
+ // Append the data from the other pipeline
+ foreach (ReadOnlyMemory<byte> memory in c2Buffer)
+ {
+ buffer.Write(memory.Span);
+ }
+
+ // Mark it as consumed
+ c2.Reader.AdvanceTo(c2Buffer.End);
+
+ // Now read and make sure we only see the comitted data
+ result = await _pipe.Reader.ReadAsync();
+ ReadOnlySequence<byte> reader = result.Buffer;
+
+ Assert.Equal(4, reader.Length);
+ Assert.Equal(new byte[] { 0, 0, 0, 10 }, reader.Slice(0, 4).ToArray());
+
+ // Consume nothing
+ _pipe.Reader.AdvanceTo(reader.Start);
+
+ // Flush the second set of writes
+ await buffer.FlushAsync();
+
+ reader = (await _pipe.Reader.ReadAsync()).Buffer;
+
+ // int, int, "Hello"
+ Assert.Equal(13, reader.Length);
+ Assert.Equal(new byte[] { 0, 0, 0, 10 }, reader.Slice(0, 4).ToArray());
+ Assert.Equal(new byte[] { 0, 0, 0, 9 }, reader.Slice(4, 4).ToArray());
+ Assert.Equal("Hello", Encoding.ASCII.GetString(reader.Slice(8).ToArray()));
+
+ _pipe.Reader.AdvanceTo(reader.Start, reader.Start);
+ }
+
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public async Task ReadAsyncOnCompletedCapturesTheExecutionContext(bool useSynchronizationContext)
+ {
+ var pipe = new Pipe(new PipeOptions(useSynchronizationContext: useSynchronizationContext));
+
+ SynchronizationContext previous = SynchronizationContext.Current;
+ var sc = new CustomSynchronizationContext();
+
+ if (useSynchronizationContext)
+ {
+ SynchronizationContext.SetSynchronizationContext(sc);
+ }
+
+ try
+ {
+ AsyncLocal<int> val = new AsyncLocal<int>();
+ var tcs = new TaskCompletionSource<int>();
+ val.Value = 10;
+
+ pipe.Reader.ReadAsync().GetAwaiter().OnCompleted(() =>
+ {
+ tcs.TrySetResult(val.Value);
+ });
+
+ val.Value = 20;
+
+ pipe.Writer.WriteEmpty(100);
+ // Don't run any code on our fake sync context
+ await pipe.Writer.FlushAsync().ConfigureAwait(false);
+
+ if (useSynchronizationContext)
+ {
+ Assert.Equal(1, sc.Callbacks.Count);
+ sc.Callbacks[0].Item1(sc.Callbacks[0].Item2);
+ }
+
+ int value = await tcs.Task.ConfigureAwait(false);
+ Assert.Equal(10, value);
+ }
+ finally
+ {
+ if (useSynchronizationContext)
+ {
+ SynchronizationContext.SetSynchronizationContext(previous);
+ }
+
+ pipe.Reader.Complete();
+ pipe.Writer.Complete();
+ }
+ }
+
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public async Task FlushAsyncOnCompletedCapturesTheExecutionContextAndSyncContext(bool useSynchronizationContext)
+ {
+ var pipe = new Pipe(new PipeOptions(useSynchronizationContext: useSynchronizationContext, pauseWriterThreshold: 20, resumeWriterThreshold: 10));
+
+ SynchronizationContext previous = SynchronizationContext.Current;
+ var sc = new CustomSynchronizationContext();
+
+ if (useSynchronizationContext)
+ {
+ SynchronizationContext.SetSynchronizationContext(sc);
+ }
+
+ try
+ {
+ AsyncLocal<int> val = new AsyncLocal<int>();
+ var tcs = new TaskCompletionSource<int>();
+ val.Value = 10;
+
+ pipe.Writer.WriteEmpty(20);
+ pipe.Writer.FlushAsync().GetAwaiter().OnCompleted(() =>
+ {
+ tcs.TrySetResult(val.Value);
+ });
+
+ val.Value = 20;
+
+ // Don't run any code on our fake sync context
+ ReadResult result = await pipe.Reader.ReadAsync().ConfigureAwait(false);
+ pipe.Reader.AdvanceTo(result.Buffer.End);
+
+ if (useSynchronizationContext)
+ {
+ Assert.Equal(1, sc.Callbacks.Count);
+ sc.Callbacks[0].Item1(sc.Callbacks[0].Item2);
+ }
+
+ int value = await tcs.Task.ConfigureAwait(false);
+ Assert.Equal(10, value);
+ }
+ finally
+ {
+ if (useSynchronizationContext)
+ {
+ SynchronizationContext.SetSynchronizationContext(previous);
+ }
+
+ pipe.Reader.Complete();
+ pipe.Writer.Complete();
+ }
+ }
+
+ [Fact]
+ public async Task ReadingCanBeCanceled()
+ {
+ var cts = new CancellationTokenSource();
+ cts.Token.Register(() => { _pipe.Writer.Complete(new OperationCanceledException(cts.Token)); });
+
+ Task ignore = Task.Run(
+ async () =>
+ {
+ await Task.Delay(1000);
+ cts.Cancel();
+ });
+
+ await Assert.ThrowsAsync<OperationCanceledException>(
+ async () =>
+ {
+ ReadResult result = await _pipe.Reader.ReadAsync();
+ ReadOnlySequence<byte> buffer = result.Buffer;
+ });
+ }
+
+ [Fact]
+ public async Task SyncReadThenAsyncRead()
+ {
+ PipeWriter buffer = _pipe.Writer;
+ buffer.Write(Encoding.ASCII.GetBytes("Hello World"));
+ await buffer.FlushAsync();
+
+ bool gotData = _pipe.Reader.TryRead(out ReadResult result);
+ Assert.True(gotData);
+
+ Assert.Equal("Hello World", Encoding.ASCII.GetString(result.Buffer.ToArray()));
+
+ _pipe.Reader.AdvanceTo(result.Buffer.GetPosition(6));
+
+ result = await _pipe.Reader.ReadAsync();
+
+ Assert.Equal("World", Encoding.ASCII.GetString(result.Buffer.ToArray()));
+
+ _pipe.Reader.AdvanceTo(result.Buffer.End);
+ }
+
+ [Fact]
+ public void ThrowsOnAllocAfterCompleteWriter()
+ {
+ _pipe.Writer.Complete();
+
+ Assert.Throws<InvalidOperationException>(() => _pipe.Writer.GetMemory());
+ }
+
+ [Fact]
+ public void ThrowsOnReadAfterCompleteReader()
+ {
+ _pipe.Reader.Complete();
+
+ Assert.Throws<InvalidOperationException>(() => _pipe.Reader.ReadAsync());
+ }
+
+ [Fact]
+ public void TryReadAfterCancelPendingReadReturnsTrue()
+ {
+ _pipe.Reader.CancelPendingRead();
+
+ bool gotData = _pipe.Reader.TryRead(out ReadResult result);
+
+ Assert.True(result.IsCanceled);
+
+ _pipe.Reader.AdvanceTo(result.Buffer.End);
+ }
+
+ [Fact]
+ public void TryReadAfterCloseWriterWithExceptionThrows()
+ {
+ _pipe.Writer.Complete(new Exception("wow"));
+
+ var ex = Assert.Throws<Exception>(() => _pipe.Reader.TryRead(out ReadResult result));
+ Assert.Equal("wow", ex.Message);
+ }
+
+ [Fact]
+ public void TryReadAfterReaderCompleteThrows()
+ {
+ _pipe.Reader.Complete();
+
+ Assert.Throws<InvalidOperationException>(() => _pipe.Reader.TryRead(out ReadResult result));
+ }
+
+ [Fact]
+ public void TryReadAfterWriterCompleteReturnsTrue()
+ {
+ _pipe.Writer.Complete();
+
+ bool gotData = _pipe.Reader.TryRead(out ReadResult result);
+
+ Assert.True(result.IsCompleted);
+
+ _pipe.Reader.AdvanceTo(result.Buffer.End);
+ }
+
+ [Fact]
+ public void WhenTryReadReturnsFalseDontNeedToCallAdvance()
+ {
+ bool gotData = _pipe.Reader.TryRead(out ReadResult result);
+ Assert.False(gotData);
+ _pipe.Reader.AdvanceTo(default);
+ }
+
+ [Fact]
+ public async Task WritingDataMakesDataReadableViaPipeline()
+ {
+ byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+
+ await _pipe.Writer.WriteAsync(bytes);
+ ReadResult result = await _pipe.Reader.ReadAsync();
+ ReadOnlySequence<byte> buffer = result.Buffer;
+
+ Assert.Equal(11, buffer.Length);
+ Assert.True(buffer.IsSingleSegment);
+ var array = new byte[11];
+ buffer.First.Span.CopyTo(array);
+ Assert.Equal("Hello World", Encoding.ASCII.GetString(array));
+
+ _pipe.Reader.AdvanceTo(buffer.Start, buffer.Start);
+ }
+
+ [Fact]
+ public async Task DoubleAsyncReadThrows()
+ {
+ ValueTask<ReadResult> readTask1 = _pipe.Reader.ReadAsync();
+ ValueTask<ReadResult> readTask2 = _pipe.Reader.ReadAsync();
+
+ var task1 = Assert.ThrowsAsync<InvalidOperationException>(async () => await readTask1);
+ var task2 = Assert.ThrowsAsync<InvalidOperationException>(async () => await readTask2);
+
+ var exception1 = await task1;
+ var exception2 = await task2;
+
+ Assert.Equal("Concurrent reads or writes are not supported.", exception1.Message);
+ Assert.Equal("Concurrent reads or writes are not supported.", exception2.Message);
+ }
+
+ [Fact]
+ public void GetResultBeforeCompletedThrows()
+ {
+ ValueTask<ReadResult> awaiter = _pipe.Reader.ReadAsync();
+
+ Assert.Throws<InvalidOperationException>(() => awaiter.GetAwaiter().GetResult());
+ }
+
+ [Fact]
+ public async Task CompleteAfterAdvanceCommits()
+ {
+ _pipe.Writer.WriteEmpty(4);
+
+ _pipe.Writer.Complete();
+
+ var result = await _pipe.Reader.ReadAsync();
+ Assert.Equal(4, result.Buffer.Length);
+ _pipe.Reader.AdvanceTo(result.Buffer.End);
+ }
+
+ [Fact]
+ public async Task AdvanceWithoutReadThrows()
+ {
+ await _pipe.Writer.WriteAsync(new byte[3]);
+ ReadResult readResult = await _pipe.Reader.ReadAsync();
+ _pipe.Reader.AdvanceTo(readResult.Buffer.Start);
+
+ InvalidOperationException exception = Assert.Throws<InvalidOperationException>(() => _pipe.Reader.AdvanceTo(readResult.Buffer.End));
+ Assert.Equal("No reading operation to complete.", exception.Message);
+ }
+
+ [Fact]
+ public async Task TryReadAfterReadAsyncThrows()
+ {
+ await _pipe.Writer.WriteAsync(new byte[3]);
+ ReadResult readResult = await _pipe.Reader.ReadAsync();
+
+ Assert.Throws<InvalidOperationException>(() => _pipe.Reader.TryRead(out _));
+ _pipe.Reader.AdvanceTo(readResult.Buffer.Start);
+ }
+
+ [Fact]
+ public void GetMemoryZeroReturnsNonEmpty()
+ {
+ Assert.True(_pipe.Writer.GetMemory(0).Length > 0);
+ }
+
+ [Fact]
+ public async Task ReadAsyncWithDataReadyReturnsTaskWithValue()
+ {
+ _pipe.Writer.WriteEmpty(10);
+ await _pipe.Writer.FlushAsync();
+ var task = _pipe.Reader.ReadAsync();
+ Assert.True(IsTaskWithResult(task));
+ }
+
+ [Fact]
+ public void CancelledReadAsyncReturnsTaskWithValue()
+ {
+ _pipe.Reader.CancelPendingRead();
+ var task = _pipe.Reader.ReadAsync();
+ Assert.True(IsTaskWithResult(task));
+ }
+
+ [Fact]
+ public void FlushAsyncWithoutBackpressureReturnsTaskWithValue()
+ {
+ _pipe.Writer.WriteEmpty(10);
+ var task = _pipe.Writer.FlushAsync();
+ Assert.True(IsTaskWithResult(task));
+ }
+
+ [Fact]
+ public void CancelledFlushAsyncReturnsTaskWithValue()
+ {
+ _pipe.Writer.CancelPendingFlush();
+ var task = _pipe.Writer.FlushAsync();
+ Assert.True(IsTaskWithResult(task));
+ }
+
+ private bool IsTaskWithResult<T>(ValueTask<T> task)
+ {
+ return task == new ValueTask<T>(task.Result);
+ }
+
+ private sealed class CustomSynchronizationContext : SynchronizationContext
+ {
+ public List<Tuple<SendOrPostCallback, object>> Callbacks = new List<Tuple<SendOrPostCallback, object>>();
+
+ public override void Post(SendOrPostCallback d, object state)
+ {
+ Callbacks.Add(Tuple.Create(d, state));
+ }
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/tests/PipeResetTests.cs b/src/System.IO.Pipelines/tests/PipeResetTests.cs
new file mode 100644
index 0000000000..566d6237e8
--- /dev/null
+++ b/src/System.IO.Pipelines/tests/PipeResetTests.cs
@@ -0,0 +1,82 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.IO.Pipelines.Tests
+{
+ public class PipeResetTests : IDisposable
+ {
+ public PipeResetTests()
+ {
+ _pool = new TestMemoryPool();
+ _pipe = new Pipe(new PipeOptions(_pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+ }
+
+ public void Dispose()
+ {
+ _pipe.Writer.Complete();
+ _pipe.Reader.Complete();
+ _pool?.Dispose();
+ }
+
+ private readonly TestMemoryPool _pool;
+
+ private readonly Pipe _pipe;
+
+ [Fact]
+ public async Task LengthIsReseted()
+ {
+ var source = new byte[] { 1, 2, 3 };
+
+ await _pipe.Writer.WriteAsync(source);
+
+ _pipe.Reader.Complete();
+ _pipe.Writer.Complete();
+
+ _pipe.Reset();
+
+ Assert.Equal(0, _pipe.Length);
+ }
+
+ [Fact]
+ public async Task ReadsAndWritesAfterReset()
+ {
+ var source = new byte[] { 1, 2, 3 };
+
+ await _pipe.Writer.WriteAsync(source);
+ ReadResult result = await _pipe.Reader.ReadAsync();
+
+ Assert.Equal(source, result.Buffer.ToArray());
+ _pipe.Reader.AdvanceTo(result.Buffer.End);
+
+ _pipe.Reader.Complete();
+ _pipe.Writer.Complete();
+
+ _pipe.Reset();
+
+ await _pipe.Writer.WriteAsync(source);
+ result = await _pipe.Reader.ReadAsync();
+
+ Assert.Equal(source, result.Buffer.ToArray());
+ _pipe.Reader.AdvanceTo(result.Buffer.End);
+ }
+
+ [Fact]
+ public void ResetThrowsIfReaderNotCompleted()
+ {
+ _pipe.Writer.Complete();
+ Assert.Throws<InvalidOperationException>(() => _pipe.Reset());
+ }
+
+ [Fact]
+ public void ResetThrowsIfWriterNotCompleted()
+ {
+ _pipe.Reader.Complete();
+ Assert.Throws<InvalidOperationException>(() => _pipe.Reset());
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/tests/PipeTest.cs b/src/System.IO.Pipelines/tests/PipeTest.cs
new file mode 100644
index 0000000000..909b945fb3
--- /dev/null
+++ b/src/System.IO.Pipelines/tests/PipeTest.cs
@@ -0,0 +1,38 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.IO.Pipelines.Tests
+{
+ public abstract class PipeTest : IDisposable
+ {
+ protected const int MaximumSizeHigh = 65;
+
+ protected const int MaximumSizeLow = 6;
+
+ private readonly TestMemoryPool _pool;
+
+ protected Pipe Pipe;
+
+ protected PipeTest(int pauseWriterThreshold = MaximumSizeHigh, int resumeWriterThreshold = MaximumSizeLow)
+ {
+ _pool = new TestMemoryPool();
+ Pipe = new Pipe(
+ new PipeOptions(
+ _pool,
+ pauseWriterThreshold: pauseWriterThreshold,
+ resumeWriterThreshold: resumeWriterThreshold,
+ readerScheduler: PipeScheduler.Inline,
+ writerScheduler: PipeScheduler.Inline,
+ useSynchronizationContext: false
+ ));
+ }
+
+ public void Dispose()
+ {
+ Pipe.Writer.Complete();
+ Pipe.Reader.Complete();
+ _pool.Dispose();
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/tests/PipeWriterTests.cs b/src/System.IO.Pipelines/tests/PipeWriterTests.cs
new file mode 100644
index 0000000000..4ac05668b7
--- /dev/null
+++ b/src/System.IO.Pipelines/tests/PipeWriterTests.cs
@@ -0,0 +1,209 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Buffers;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.IO.Pipelines.Tests
+{
+ public class PipeWriterTests : PipeTest
+ {
+ public PipeWriterTests() : base(0, 0)
+ {
+ }
+
+ private byte[] Read()
+ {
+ Pipe.Writer.FlushAsync().GetAwaiter().GetResult();
+ ReadResult readResult = Pipe.Reader.ReadAsync().GetAwaiter().GetResult();
+ byte[] data = readResult.Buffer.ToArray();
+ Pipe.Reader.AdvanceTo(readResult.Buffer.End);
+ return data;
+ }
+
+ [Theory]
+ [InlineData(3, -1, 0)]
+ [InlineData(3, 0, -1)]
+ [InlineData(3, 0, 4)]
+ [InlineData(3, 4, 0)]
+ [InlineData(3, -1, -1)]
+ [InlineData(3, 4, 4)]
+ public void ThrowsForInvalidParameters(int arrayLength, int offset, int length)
+ {
+ PipeWriter writer = Pipe.Writer;
+ var array = new byte[arrayLength];
+ for (var i = 0; i < array.Length; i++)
+ {
+ array[i] = (byte)(i + 1);
+ }
+
+ writer.Write(new Span<byte>(array, 0, 0));
+ writer.Write(new Span<byte>(array, array.Length, 0));
+
+ try
+ {
+ writer.Write(new Span<byte>(array, offset, length));
+ Assert.True(false);
+ }
+ catch (Exception ex)
+ {
+ Assert.True(ex is ArgumentOutOfRangeException);
+ }
+
+ writer.Write(new Span<byte>(array, 0, array.Length));
+ Assert.Equal(array, Read());
+ }
+
+ [Theory]
+ [InlineData(0, 0, 3)]
+ [InlineData(0, 1, 2)]
+ [InlineData(0, 2, 1)]
+ [InlineData(0, 1, 1)]
+ [InlineData(1, 0, 3)]
+ [InlineData(1, 1, 2)]
+ [InlineData(1, 2, 1)]
+ [InlineData(1, 1, 1)]
+ public void CanWriteWithOffsetAndLenght(int alloc, int offset, int length)
+ {
+ PipeWriter writer = Pipe.Writer;
+ var array = new byte[] { 1, 2, 3 };
+
+ writer.Write(new Span<byte>(array, offset, length));
+
+ Assert.Equal(array.Skip(offset).Take(length).ToArray(), Read());
+ }
+
+ [Fact]
+ public void CanWriteEmpty()
+ {
+ PipeWriter writer = Pipe.Writer;
+ var array = new byte[] { };
+
+ writer.Write(array);
+ writer.Write(new Span<byte>(array, 0, array.Length));
+
+ Assert.Equal(array, Read());
+ }
+
+ [Fact]
+ public void CanWriteIntoHeadlessBuffer()
+ {
+ PipeWriter writer = Pipe.Writer;
+
+ writer.Write(new byte[] { 1, 2, 3 });
+ Assert.Equal(new byte[] { 1, 2, 3 }, Read());
+ }
+
+ [Fact]
+ public void CanWriteMultipleTimes()
+ {
+ PipeWriter writer = Pipe.Writer;
+
+ writer.Write(new byte[] { 1 });
+ writer.Write(new byte[] { 2 });
+ writer.Write(new byte[] { 3 });
+
+ Assert.Equal(new byte[] { 1, 2, 3 }, Read());
+ }
+
+ [Fact]
+ public void CanWriteOverTheBlockLength()
+ {
+ Memory<byte> memory = Pipe.Writer.GetMemory();
+ PipeWriter writer = Pipe.Writer;
+
+ IEnumerable<byte> source = Enumerable.Range(0, memory.Length).Select(i => (byte)i);
+ byte[] expectedBytes = source.Concat(source).Concat(source).ToArray();
+
+ writer.Write(expectedBytes);
+
+ Assert.Equal(expectedBytes, Read());
+ }
+
+ [Fact]
+ public void EnsureAllocatesSpan()
+ {
+ PipeWriter writer = Pipe.Writer;
+ var span = writer.GetSpan(10);
+
+ Assert.True(span.Length >= 10);
+ Assert.Equal(new byte[] { }, Read());
+ }
+
+ [Fact]
+ public void SlicesSpanAndAdvancesAfterWrite()
+ {
+ int initialLength = Pipe.Writer.GetSpan(3).Length;
+
+ PipeWriter writer = Pipe.Writer;
+
+ writer.Write(new byte[] { 1, 2, 3 });
+ Span<byte> span = Pipe.Writer.GetSpan();
+
+ Assert.Equal(initialLength - 3, span.Length);
+ Assert.Equal(new byte[] { 1, 2, 3 }, Read());
+ }
+
+ [Theory]
+ [InlineData(5)]
+ [InlineData(50)]
+ [InlineData(500)]
+ [InlineData(5000)]
+ [InlineData(50000)]
+ public async Task WriteLargeDataBinary(int length)
+ {
+ var data = new byte[length];
+ new Random(length).NextBytes(data);
+ PipeWriter output = Pipe.Writer;
+ output.Write(data);
+ await output.FlushAsync();
+
+ ReadResult result = await Pipe.Reader.ReadAsync();
+ ReadOnlySequence<byte> input = result.Buffer;
+ Assert.Equal(data, input.ToArray());
+ Pipe.Reader.AdvanceTo(input.End);
+ }
+
+ [Fact]
+ public async Task CanWriteNothingToBuffer()
+ {
+ PipeWriter buffer = Pipe.Writer;
+ buffer.GetMemory(0);
+ buffer.Advance(0); // doing nothing, the hard way
+ await buffer.FlushAsync();
+ }
+
+ [Fact]
+ public void EmptyWriteDoesNotThrow()
+ {
+ Pipe.Writer.Write(new byte[0]);
+ }
+
+ [Fact]
+ public void ThrowsOnAdvanceOverMemorySize()
+ {
+ Memory<byte> buffer = Pipe.Writer.GetMemory(1);
+ var exception = Assert.Throws<InvalidOperationException>(() => Pipe.Writer.Advance(buffer.Length + 1));
+ Assert.Equal("Can't advance past buffer size.", exception.Message);
+ }
+
+ [Fact]
+ public void ThrowsOnAdvanceWithNoMemory()
+ {
+ PipeWriter buffer = Pipe.Writer;
+ var exception = Assert.Throws<InvalidOperationException>(() => buffer.Advance(1));
+ Assert.Equal("No writing operation. Make sure GetMemory() was called.", exception.Message);
+ }
+
+ [Fact]
+ public void GetMemory_AdjustsToPoolMaxBufferSize()
+ {
+ PipeWriter buffer = Pipe.Writer;
+ var memory = buffer.GetMemory(int.MaxValue);
+ Assert.True(memory.Length >= 4096);
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/tests/ReadAsyncCancellationTests.cs b/src/System.IO.Pipelines/tests/ReadAsyncCancellationTests.cs
new file mode 100644
index 0000000000..ea486a30fd
--- /dev/null
+++ b/src/System.IO.Pipelines/tests/ReadAsyncCancellationTests.cs
@@ -0,0 +1,434 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.IO.Pipelines.Tests
+{
+ public class ReadAsyncCancellationTests : PipeTest
+ {
+ [Fact]
+ public async Task AdvanceShouldResetStateIfReadCanceled()
+ {
+ Pipe.Reader.CancelPendingRead();
+
+ ReadResult result = await Pipe.Reader.ReadAsync();
+ ReadOnlySequence<byte> buffer = result.Buffer;
+ Pipe.Reader.AdvanceTo(buffer.End);
+
+ Assert.False(result.IsCompleted);
+ Assert.True(result.IsCanceled);
+ Assert.True(buffer.IsEmpty);
+
+ ValueTask<ReadResult> awaitable = Pipe.Reader.ReadAsync();
+ Assert.False(awaitable.IsCompleted);
+ }
+
+ [Fact]
+ public async Task CancellingBeforeAdvance()
+ {
+ byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+ PipeWriter output = Pipe.Writer;
+ output.Write(bytes);
+ await output.FlushAsync();
+
+ ReadResult result = await Pipe.Reader.ReadAsync();
+ ReadOnlySequence<byte> buffer = result.Buffer;
+
+ Assert.Equal(11, buffer.Length);
+ Assert.False(result.IsCanceled);
+ Assert.True(buffer.IsSingleSegment);
+ var array = new byte[11];
+ buffer.First.Span.CopyTo(array);
+ Assert.Equal("Hello World", Encoding.ASCII.GetString(array));
+
+ Pipe.Reader.CancelPendingRead();
+
+ Pipe.Reader.AdvanceTo(buffer.End);
+
+ ValueTask<ReadResult> awaitable = Pipe.Reader.ReadAsync();
+
+ Assert.True(awaitable.IsCompleted);
+
+ result = await awaitable;
+
+ Assert.True(result.IsCanceled);
+
+ Pipe.Reader.AdvanceTo(result.Buffer.Start, result.Buffer.Start);
+ }
+
+ [Fact]
+ public async Task CancellingPendingAfterReadAsync()
+ {
+ byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+ PipeWriter output = Pipe.Writer;
+ output.Write(bytes);
+
+ Func<Task> taskFunc = async () => {
+ ReadResult result = await Pipe.Reader.ReadAsync();
+ ReadOnlySequence<byte> buffer = result.Buffer;
+ Pipe.Reader.AdvanceTo(buffer.End);
+
+ Assert.False(result.IsCompleted);
+ Assert.True(result.IsCanceled);
+ Assert.True(buffer.IsEmpty);
+
+ await output.FlushAsync();
+
+ result = await Pipe.Reader.ReadAsync();
+ buffer = result.Buffer;
+
+ Assert.Equal(11, buffer.Length);
+ Assert.True(buffer.IsSingleSegment);
+ Assert.False(result.IsCanceled);
+ var array = new byte[11];
+ buffer.First.Span.CopyTo(array);
+ Assert.Equal("Hello World", Encoding.ASCII.GetString(array));
+ Pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End);
+
+ Pipe.Reader.Complete();
+ };
+
+ Task task = taskFunc();
+
+ Pipe.Reader.CancelPendingRead();
+
+ await task;
+
+ Pipe.Writer.Complete();
+ }
+
+ [Fact]
+ public async Task CancellingPendingReadBeforeReadAsync()
+ {
+ Pipe.Reader.CancelPendingRead();
+
+ ReadResult result = await Pipe.Reader.ReadAsync();
+ ReadOnlySequence<byte> buffer = result.Buffer;
+ Pipe.Reader.AdvanceTo(buffer.End);
+
+ Assert.False(result.IsCompleted);
+ Assert.True(result.IsCanceled);
+ Assert.True(buffer.IsEmpty);
+
+ byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+ PipeWriter output = Pipe.Writer;
+ output.Write(bytes);
+ await output.FlushAsync();
+
+ result = await Pipe.Reader.ReadAsync();
+ buffer = result.Buffer;
+
+ Assert.Equal(11, buffer.Length);
+ Assert.False(result.IsCanceled);
+ Assert.True(buffer.IsSingleSegment);
+ var array = new byte[11];
+ buffer.First.Span.CopyTo(array);
+ Assert.Equal("Hello World", Encoding.ASCII.GetString(array));
+
+ Pipe.Reader.AdvanceTo(buffer.Start, buffer.Start);
+ }
+
+ [Fact]
+ public void FlushAsyncCancellationDeadlock()
+ {
+ var cts = new CancellationTokenSource();
+ var cts2 = new CancellationTokenSource();
+ var e = new ManualResetEventSlim();
+
+ ValueTaskAwaiter<ReadResult> awaiter = Pipe.Reader.ReadAsync(cts.Token).GetAwaiter();
+ awaiter.OnCompleted(
+ () => {
+ // We are on cancellation thread and need to wait untill another ReadAsync call
+ // takes pipe state lock
+ e.Wait();
+ // Make sure we had enough time to reach _cancellationTokenRegistration.Dispose
+ Thread.Sleep(100);
+ // Try to take pipe state lock
+ Pipe.Reader.ReadAsync();
+ });
+
+ // Start a thread that would run cancellation calbacks
+ Task cancellationTask = Task.Run(() => cts.Cancel());
+ // Start a thread that would call ReadAsync with different token
+ // and block on _cancellationTokenRegistration.Dispose
+ Task blockingTask = Task.Run(
+ () => {
+ e.Set();
+ Pipe.Reader.ReadAsync(cts2.Token);
+ });
+
+ bool completed = Task.WhenAll(cancellationTask, blockingTask).Wait(TimeSpan.FromSeconds(10));
+ Assert.True(completed);
+ }
+
+ [Fact]
+ public void GetResultThrowsIfFlushAsyncTokenFiredAfterCancelPending()
+ {
+ var onCompletedCalled = false;
+ var cancellationTokenSource = new CancellationTokenSource();
+
+ ValueTaskAwaiter<ReadResult> awaiter = Pipe.Reader.ReadAsync(cancellationTokenSource.Token).GetAwaiter();
+ bool awaiterIsCompleted = awaiter.IsCompleted;
+
+ cancellationTokenSource.Cancel();
+ Pipe.Reader.CancelPendingRead();
+
+ awaiter.OnCompleted(
+ () => {
+ onCompletedCalled = true;
+ Assert.Throws<OperationCanceledException>(() => awaiter.GetResult());
+ });
+
+ Assert.False(awaiterIsCompleted);
+ Assert.True(onCompletedCalled);
+ }
+
+ [Fact]
+ public void GetResultThrowsIfReadAsyncCanceledAfterOnCompleted()
+ {
+ var onCompletedCalled = false;
+ var cancellationTokenSource = new CancellationTokenSource();
+
+ ValueTaskAwaiter<ReadResult> awaiter = Pipe.Reader.ReadAsync(cancellationTokenSource.Token).GetAwaiter();
+ bool awaiterIsCompleted = awaiter.IsCompleted;
+ awaiter.OnCompleted(
+ () => {
+ onCompletedCalled = true;
+ Assert.Throws<OperationCanceledException>(() => awaiter.GetResult());
+ });
+
+ cancellationTokenSource.Cancel();
+
+ Assert.False(awaiterIsCompleted);
+ Assert.True(onCompletedCalled);
+ }
+
+ [Fact]
+ public void GetResultThrowsIfReadAsyncCanceledBeforeOnCompleted()
+ {
+ var onCompletedCalled = false;
+ var cancellationTokenSource = new CancellationTokenSource();
+
+ ValueTaskAwaiter<ReadResult> awaiter = Pipe.Reader.ReadAsync(cancellationTokenSource.Token).GetAwaiter();
+ bool awaiterIsCompleted = awaiter.IsCompleted;
+
+ cancellationTokenSource.Cancel();
+
+ awaiter.OnCompleted(
+ () => {
+ onCompletedCalled = true;
+ Assert.Throws<OperationCanceledException>(() => awaiter.GetResult());
+ });
+
+ Assert.False(awaiterIsCompleted);
+ Assert.True(onCompletedCalled);
+ }
+
+ [Fact]
+ public async Task ReadAsyncCancellationE2E()
+ {
+ var cts = new CancellationTokenSource();
+ var e = new AutoResetEvent(false);
+ var cancelled = false;
+
+ Func<Task> taskFunc = async () => {
+ try
+ {
+ ReadResult result = await Pipe.Reader.ReadAsync(cts.Token);
+ }
+ catch (OperationCanceledException)
+ {
+ cancelled = true;
+ ReadResult result = await Pipe.Reader.ReadAsync();
+ Assert.Equal(new byte[] { 1, 2, 3 }, result.Buffer.ToArray());
+ Pipe.Reader.AdvanceTo(result.Buffer.End);
+ }
+ };
+
+ Task task = taskFunc();
+
+ cts.Cancel();
+
+ await Pipe.Writer.WriteAsync(new byte[] { 1, 2, 3 });
+ await task;
+ Assert.True(cancelled);
+ }
+
+ [Fact]
+ public void ReadAsyncCompletedAfterPreCancellation()
+ {
+ Pipe.Reader.CancelPendingRead();
+ Pipe.Writer.WriteAsync(new byte[] { 1, 2, 3 }).GetAwaiter().GetResult();
+
+ ValueTaskAwaiter<ReadResult> awaitable = Pipe.Reader.ReadAsync().GetAwaiter();
+
+ Assert.True(awaitable.IsCompleted);
+
+ ReadResult result = awaitable.GetResult();
+
+ Assert.True(result.IsCanceled);
+
+ awaitable = Pipe.Reader.ReadAsync().GetAwaiter();
+
+ Assert.True(awaitable.IsCompleted);
+
+ Pipe.Reader.AdvanceTo(awaitable.GetResult().Buffer.End);
+ }
+
+ [Fact]
+ public void ReadAsyncNotCompletedAfterCancellation()
+ {
+ var onCompletedCalled = false;
+ ValueTaskAwaiter<ReadResult> awaitable = Pipe.Reader.ReadAsync().GetAwaiter();
+
+ Assert.False(awaitable.IsCompleted);
+ awaitable.OnCompleted(
+ () => {
+ onCompletedCalled = true;
+ Assert.True(awaitable.IsCompleted);
+
+ ReadResult readResult = awaitable.GetResult();
+ Assert.True(readResult.IsCanceled);
+
+ awaitable = Pipe.Reader.ReadAsync().GetAwaiter();
+ Assert.False(awaitable.IsCompleted);
+ });
+
+ Pipe.Reader.CancelPendingRead();
+ Assert.True(onCompletedCalled);
+ }
+
+ [Fact]
+ public void ReadAsyncNotCompletedAfterCancellationTokenCanceled()
+ {
+ var onCompletedCalled = false;
+ var cts = new CancellationTokenSource();
+ ValueTaskAwaiter<ReadResult> awaitable = Pipe.Reader.ReadAsync(cts.Token).GetAwaiter();
+
+ Assert.False(awaitable.IsCompleted);
+ awaitable.OnCompleted(
+ () => {
+ onCompletedCalled = true;
+ Assert.True(awaitable.IsCompleted);
+
+ Assert.Throws<OperationCanceledException>(() => awaitable.GetResult());
+
+ awaitable = Pipe.Reader.ReadAsync().GetAwaiter();
+ Assert.False(awaitable.IsCompleted);
+ });
+
+ cts.Cancel();
+ Assert.True(onCompletedCalled);
+ }
+
+ [Fact]
+ public void ReadAsyncReturnsIsCancelOnCancelPendingReadAfterGetResult()
+ {
+ ValueTaskAwaiter<ReadResult> awaitable = Pipe.Reader.ReadAsync().GetAwaiter();
+
+ Assert.False(awaitable.IsCompleted);
+ awaitable.OnCompleted(() => { });
+
+ Pipe.Writer.WriteAsync(new byte[] { });
+ Pipe.Reader.CancelPendingRead();
+
+ Assert.True(awaitable.IsCompleted);
+
+ ReadResult result = awaitable.GetResult();
+ Assert.True(result.IsCanceled);
+ }
+
+ [Fact]
+ public void ReadAsyncReturnsIsCancelOnCancelPendingReadBeforeGetResult()
+ {
+ ValueTaskAwaiter<ReadResult> awaitable = Pipe.Reader.ReadAsync().GetAwaiter();
+
+ Assert.False(awaitable.IsCompleted);
+ awaitable.OnCompleted(() => { });
+
+ Pipe.Writer.WriteAsync(new byte[] { });
+ Pipe.Reader.CancelPendingRead();
+
+ Assert.True(awaitable.IsCompleted);
+
+ ReadResult result = awaitable.GetResult();
+ Assert.True(result.IsCanceled);
+ }
+
+ [Fact]
+ public void ReadAsyncThrowsIfPassedCanceledCancellationToken()
+ {
+ var cancellationTokenSource = new CancellationTokenSource();
+ cancellationTokenSource.Cancel();
+
+ Assert.Throws<OperationCanceledException>(() => Pipe.Reader.ReadAsync(cancellationTokenSource.Token));
+ }
+
+ [Fact]
+ public async Task ReadAsyncWithNewCancellationTokenNotAffectedByPrevious()
+ {
+ await Pipe.Writer.WriteAsync(new byte[] { 0 });
+
+ var cancellationTokenSource1 = new CancellationTokenSource();
+ ReadResult result = await Pipe.Reader.ReadAsync(cancellationTokenSource1.Token);
+ Pipe.Reader.AdvanceTo(result.Buffer.Start);
+
+ cancellationTokenSource1.Cancel();
+ var cancellationTokenSource2 = new CancellationTokenSource();
+
+ // Verifying that ReadAsync does not throw
+ result = await Pipe.Reader.ReadAsync(cancellationTokenSource2.Token);
+ Pipe.Reader.AdvanceTo(result.Buffer.Start);
+ }
+
+ [Fact]
+ public async Task ReadingCanBeCanceled()
+ {
+ var cts = new CancellationTokenSource();
+ cts.Token.Register(() => { Pipe.Writer.Complete(new OperationCanceledException(cts.Token)); });
+
+ Task ignore = Task.Run(
+ async () => {
+ await Task.Delay(1000);
+ cts.Cancel();
+ });
+
+ await Assert.ThrowsAsync<OperationCanceledException>(
+ async () => {
+ ReadResult result = await Pipe.Reader.ReadAsync();
+ ReadOnlySequence<byte> buffer = result.Buffer;
+ });
+ }
+
+ [Fact]
+ public async Task WriteAndCancellingPendingReadBeforeReadAsync()
+ {
+ byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+ PipeWriter output = Pipe.Writer;
+ output.Write(bytes);
+ await output.FlushAsync();
+
+ Pipe.Reader.CancelPendingRead();
+
+ ReadResult result = await Pipe.Reader.ReadAsync();
+ ReadOnlySequence<byte> buffer = result.Buffer;
+
+ Assert.False(result.IsCompleted);
+ Assert.True(result.IsCanceled);
+ Assert.False(buffer.IsEmpty);
+ Assert.Equal(11, buffer.Length);
+ Assert.True(buffer.IsSingleSegment);
+ var array = new byte[11];
+ buffer.First.Span.CopyTo(array);
+ Assert.Equal("Hello World", Encoding.ASCII.GetString(array));
+ Pipe.Reader.AdvanceTo(buffer.End, buffer.End);
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/tests/ReadAsyncCompletionTests.cs b/src/System.IO.Pipelines/tests/ReadAsyncCompletionTests.cs
new file mode 100644
index 0000000000..fc11059b00
--- /dev/null
+++ b/src/System.IO.Pipelines/tests/ReadAsyncCompletionTests.cs
@@ -0,0 +1,34 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.IO.Pipelines.Tests
+{
+ public class ReadAsyncCompletionTests : PipeTest
+ {
+ [Fact]
+ public void AwaitingReadAsyncAwaitableTwiceCompletesWriterWithException()
+ {
+ async Task Await(ValueTask<ReadResult> a)
+ {
+ await a;
+ }
+
+ ValueTask<ReadResult> awaitable = Pipe.Reader.ReadAsync();
+
+ Task task1 = Await(awaitable);
+ Task task2 = Await(awaitable);
+
+ Assert.Equal(true, task1.IsCompleted);
+ Assert.Equal(true, task1.IsFaulted);
+ Assert.Equal("Concurrent reads or writes are not supported.", task1.Exception.InnerExceptions[0].Message);
+
+ Assert.Equal(true, task2.IsCompleted);
+ Assert.Equal(true, task2.IsFaulted);
+ Assert.Equal("Concurrent reads or writes are not supported.", task2.Exception.InnerExceptions[0].Message);
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/tests/ReadResultTests.cs b/src/System.IO.Pipelines/tests/ReadResultTests.cs
new file mode 100644
index 0000000000..61ab268807
--- /dev/null
+++ b/src/System.IO.Pipelines/tests/ReadResultTests.cs
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using Xunit;
+
+namespace System.IO.Pipelines.Tests
+{
+ public class ReadResultTests
+ {
+ [InlineData(true, true)]
+ [InlineData(true, false)]
+ [InlineData(false, true)]
+ [InlineData(false, false)]
+ [Theory]
+ public void ReadResultCanBeConstructed(bool cancelled, bool completed)
+ {
+ var buffer = new ReadOnlySequence<byte>(new byte[] { 1, 2, 3 });
+ var result = new ReadResult(buffer, cancelled, completed);
+
+ Assert.Equal(new byte[] { 1, 2, 3 }, result.Buffer.ToArray());
+ Assert.Equal(cancelled, result.IsCanceled);
+ Assert.Equal(completed, result.IsCompleted);
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/tests/SchedulerFacts.cs b/src/System.IO.Pipelines/tests/SchedulerFacts.cs
new file mode 100644
index 0000000000..6b033db9e9
--- /dev/null
+++ b/src/System.IO.Pipelines/tests/SchedulerFacts.cs
@@ -0,0 +1,568 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.IO.Pipelines.Tests
+{
+ public class SchedulerFacts
+ {
+ private class ThreadScheduler : PipeScheduler, IDisposable
+ {
+ private readonly BlockingCollection<Action> _work = new BlockingCollection<Action>();
+
+ public ThreadScheduler()
+ {
+ Thread = new Thread(Work) { IsBackground = true };
+ Thread.Start();
+ }
+
+ public Thread Thread { get; }
+
+ public void Dispose()
+ {
+ _work.CompleteAdding();
+ }
+
+ public override void Schedule(Action<object> action, object state)
+ {
+ _work.Add(() => action(state));
+ }
+
+ private void Work(object state)
+ {
+ foreach (Action callback in _work.GetConsumingEnumerable())
+ {
+ callback();
+ }
+ }
+ }
+
+ [Fact]
+ public async Task UseSynchronizationContextFalseIgnoresSyncContextForReaderScheduler()
+ {
+ SynchronizationContext previous = SynchronizationContext.Current;
+ var sc = new CustomSynchronizationContext();
+ try
+ {
+ SynchronizationContext.SetSynchronizationContext(sc);
+
+ var pipe = new Pipe(new PipeOptions(useSynchronizationContext: false));
+
+ Func<Task> doRead = async () =>
+ {
+ ReadResult result = await pipe.Reader.ReadAsync();
+
+ pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End);
+
+ pipe.Reader.Complete();
+ };
+
+ // This needs to run on the current SynchronizationContext
+ Task reading = doRead();
+
+ PipeWriter buffer = pipe.Writer;
+ buffer.Write(Encoding.UTF8.GetBytes("Hello World"));
+
+ // Don't run code on our sync context (we just want to make sure the callbacks)
+ // are scheduled on the sync context
+ await buffer.FlushAsync().ConfigureAwait(false);
+
+ // Nothing posted to the sync context
+ Assert.Equal(0, sc.Callbacks.Count);
+
+ pipe.Writer.Complete();
+
+ // Don't run code on our sync context
+ await reading.ConfigureAwait(false);
+ }
+ finally
+ {
+ SynchronizationContext.SetSynchronizationContext(previous);
+ }
+ }
+
+ [Fact]
+ public async Task DefaultReaderSchedulerRunsOnSynchronizationContext()
+ {
+ SynchronizationContext previous = SynchronizationContext.Current;
+ var sc = new CustomSynchronizationContext();
+ try
+ {
+ SynchronizationContext.SetSynchronizationContext(sc);
+
+ var pipe = new Pipe();
+
+ Func<Task> doRead = async () =>
+ {
+ ReadResult result = await pipe.Reader.ReadAsync();
+
+ pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End);
+
+ pipe.Reader.Complete();
+ };
+
+ // This needs to run on the current SynchronizationContext
+ Task reading = doRead();
+
+ PipeWriter buffer = pipe.Writer;
+ buffer.Write(Encoding.UTF8.GetBytes("Hello World"));
+
+ // Don't run code on our sync context (we just want to make sure the callbacks)
+ // are scheduled on the sync context
+ await buffer.FlushAsync().ConfigureAwait(false);
+
+ Assert.Equal(1, sc.Callbacks.Count);
+ sc.Callbacks[0].Item1(sc.Callbacks[0].Item2);
+
+ pipe.Writer.Complete();
+
+ // Don't run code on our sync context
+ await reading.ConfigureAwait(false);
+ }
+ finally
+ {
+ SynchronizationContext.SetSynchronizationContext(previous);
+ }
+ }
+
+ [Fact]
+ public async Task DefaultReaderSchedulerIgnoresSyncContextIfConfigureAwaitFalse()
+ {
+ // Get off the xunit sync context
+
+ var previous = SynchronizationContext.Current;
+ try
+ {
+ var sc = new CustomSynchronizationContext();
+ SynchronizationContext.SetSynchronizationContext(sc);
+
+ var pipe = new Pipe();
+
+ Func<Task> doRead = async () =>
+ {
+ ReadResult result = await pipe.Reader.ReadAsync().ConfigureAwait(false);
+
+ Assert.True(Thread.CurrentThread.IsThreadPoolThread);
+
+ pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End);
+
+ pipe.Reader.Complete();
+ };
+
+ // This needs to run on the current SynchronizationContext
+ Task reading = doRead();
+
+ PipeWriter buffer = pipe.Writer;
+ buffer.Write(Encoding.UTF8.GetBytes("Hello World"));
+
+ // We don't want to run any code on our fake sync context
+ await buffer.FlushAsync().ConfigureAwait(false);
+
+ // Nothing posted to the sync context
+ Assert.Equal(0, sc.Callbacks.Count);
+
+ pipe.Writer.Complete();
+
+ // We don't want to run any code on our fake sync context
+ await reading.ConfigureAwait(false);
+ }
+ finally
+ {
+ SynchronizationContext.SetSynchronizationContext(previous);
+ }
+
+ }
+
+ [Fact]
+ public async Task DefaultReaderSchedulerRunsOnThreadPool()
+ {
+ var pipe = new Pipe(new PipeOptions(useSynchronizationContext: false));
+
+ Func<Task> doRead = async () =>
+ {
+ Assert.False(Thread.CurrentThread.IsThreadPoolThread, "We started on the thread pool");
+
+ ReadResult result = await pipe.Reader.ReadAsync();
+
+ Assert.True(Thread.CurrentThread.IsThreadPoolThread);
+
+ pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End);
+
+ pipe.Reader.Complete();
+ };
+
+ Task reading = ExecuteOnNonThreadPoolThread(doRead);
+
+ PipeWriter buffer = pipe.Writer;
+ buffer.Write(Encoding.UTF8.GetBytes("Hello World"));
+ await buffer.FlushAsync();
+
+ pipe.Writer.Complete();
+
+ await reading;
+ }
+
+ [Fact]
+ public async Task DefaultWriterSchedulerRunsOnThreadPool()
+ {
+ using (var pool = new TestMemoryPool())
+ {
+ var pipe = new Pipe(
+ new PipeOptions(
+ pool,
+ resumeWriterThreshold: 32,
+ pauseWriterThreshold: 64,
+ useSynchronizationContext: false
+ ));
+
+ Func<Task> doWrite = async () =>
+ {
+ Assert.False(Thread.CurrentThread.IsThreadPoolThread, "We started on the thread pool");
+
+ PipeWriter writableBuffer = pipe.Writer.WriteEmpty(64);
+ ValueTask<FlushResult> flushAsync = writableBuffer.FlushAsync();
+
+ Assert.False(flushAsync.IsCompleted);
+
+ await flushAsync;
+
+ pipe.Writer.Complete();
+
+ Assert.True(Thread.CurrentThread.IsThreadPoolThread);
+ };
+
+ Task writing = ExecuteOnNonThreadPoolThread(doWrite);
+
+ ReadResult result = await pipe.Reader.ReadAsync();
+
+ pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End);
+
+ pipe.Reader.Complete();
+
+ await writing;
+ }
+ }
+
+ [Fact]
+ public async Task UseSynchronizationContextFalseIgnoresSyncContextForWriterScheduler()
+ {
+ SynchronizationContext previous = SynchronizationContext.Current;
+ var sc = new CustomSynchronizationContext();
+ try
+ {
+ SynchronizationContext.SetSynchronizationContext(sc);
+
+ using (var pool = new TestMemoryPool())
+ {
+ var pipe = new Pipe(
+ new PipeOptions(
+ pool,
+ resumeWriterThreshold: 32,
+ pauseWriterThreshold: 64,
+ useSynchronizationContext: false
+ ));
+
+ Func<Task> doWrite = async () =>
+ {
+ PipeWriter writableBuffer = pipe.Writer.WriteEmpty(64);
+ ValueTask<FlushResult> flushAsync = writableBuffer.FlushAsync();
+
+ Assert.False(flushAsync.IsCompleted);
+
+ await flushAsync;
+
+ pipe.Writer.Complete();
+ };
+
+ Task writing = doWrite();
+
+ // Don't run on our bogus sync context
+ ReadResult result = await pipe.Reader.ReadAsync().ConfigureAwait(false);
+
+ pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End);
+
+ // Nothing scheduled on the sync context
+ Assert.Equal(0, sc.Callbacks.Count);
+
+ pipe.Reader.Complete();
+
+ // Don't run on our bogus sync context
+ await writing.ConfigureAwait(false);
+ }
+ }
+ finally
+ {
+ SynchronizationContext.SetSynchronizationContext(previous);
+ }
+ }
+
+ [Fact]
+ public async Task DefaultWriterSchedulerRunsOnSynchronizationContext()
+ {
+ SynchronizationContext previous = SynchronizationContext.Current;
+ var sc = new CustomSynchronizationContext();
+ try
+ {
+ SynchronizationContext.SetSynchronizationContext(sc);
+
+ using (var pool = new TestMemoryPool())
+ {
+ var pipe = new Pipe(
+ new PipeOptions(
+ pool,
+ resumeWriterThreshold: 32,
+ pauseWriterThreshold: 64
+ ));
+
+ Func<Task> doWrite = async () =>
+ {
+ PipeWriter writableBuffer = pipe.Writer.WriteEmpty(64);
+ ValueTask<FlushResult> flushAsync = writableBuffer.FlushAsync();
+
+ Assert.False(flushAsync.IsCompleted);
+
+ await flushAsync;
+
+ pipe.Writer.Complete();
+
+ Assert.Same(SynchronizationContext.Current, sc);
+ };
+
+ Task writing = doWrite();
+
+ // Don't run on our bogus sync context
+ ReadResult result = await pipe.Reader.ReadAsync().ConfigureAwait(false);
+
+ pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End);
+
+ Assert.Equal(1, sc.Callbacks.Count);
+ sc.Callbacks[0].Item1(sc.Callbacks[0].Item2);
+
+ pipe.Reader.Complete();
+
+ // Don't run on our bogus sync context
+ await writing.ConfigureAwait(false);
+ }
+ }
+ finally
+ {
+ SynchronizationContext.SetSynchronizationContext(previous);
+ }
+ }
+
+ [Fact]
+ public async Task DefaultWriterSchedulerIgnoresSynchronizationContext()
+ {
+ SynchronizationContext previous = SynchronizationContext.Current;
+ var sc = new CustomSynchronizationContext();
+ try
+ {
+ SynchronizationContext.SetSynchronizationContext(sc);
+
+ using (var pool = new TestMemoryPool())
+ {
+ var pipe = new Pipe(
+ new PipeOptions(
+ pool,
+ resumeWriterThreshold: 32,
+ pauseWriterThreshold: 64
+ ));
+
+ PipeWriter writableBuffer = pipe.Writer.WriteEmpty(64);
+ ValueTask<FlushResult> flushAsync = writableBuffer.FlushAsync();
+
+ Assert.False(flushAsync.IsCompleted);
+
+ Func<Task> doWrite = async () =>
+ {
+ await flushAsync.ConfigureAwait(false);
+
+ pipe.Writer.Complete();
+
+ Assert.NotSame(SynchronizationContext.Current, sc);
+ };
+
+ Task writing = doWrite();
+
+ // Don't run on our bogus sync context
+ ReadResult result = await pipe.Reader.ReadAsync().ConfigureAwait(false);
+
+ pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End);
+
+ Assert.Equal(0, sc.Callbacks.Count);
+
+ pipe.Reader.Complete();
+
+ // Don't run on our bogus sync context
+ await writing.ConfigureAwait(false);
+ }
+ }
+ finally
+ {
+ SynchronizationContext.SetSynchronizationContext(previous);
+ }
+ }
+
+ [Fact]
+ public async Task FlushCallbackRunsOnWriterScheduler()
+ {
+ using (var pool = new TestMemoryPool())
+ {
+ using (var scheduler = new ThreadScheduler())
+ {
+ var pipe = new Pipe(
+ new PipeOptions(
+ pool,
+ resumeWriterThreshold: 32,
+ pauseWriterThreshold: 64,
+ readerScheduler: PipeScheduler.Inline,
+ writerScheduler: scheduler,
+ useSynchronizationContext: false));
+
+ PipeWriter writableBuffer = pipe.Writer.WriteEmpty(64);
+ ValueTask<FlushResult> flushAsync = writableBuffer.FlushAsync();
+
+ Assert.False(flushAsync.IsCompleted);
+
+ Func<Task> doWrite = async () =>
+ {
+ int oid = Thread.CurrentThread.ManagedThreadId;
+
+ Assert.False(Thread.CurrentThread.IsThreadPoolThread, "We started on the thread pool");
+
+ await flushAsync;
+
+ Assert.NotEqual(oid, Thread.CurrentThread.ManagedThreadId);
+
+ pipe.Writer.Complete();
+
+ Assert.Equal(Thread.CurrentThread.ManagedThreadId, scheduler.Thread.ManagedThreadId);
+ };
+
+ Task writing = ExecuteOnNonThreadPoolThread(doWrite);
+
+ ReadResult result = await pipe.Reader.ReadAsync();
+
+ pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End);
+
+ pipe.Reader.Complete();
+
+ await writing;
+ }
+ }
+ }
+
+ [Fact]
+ public async Task ReadAsyncCallbackRunsOnReaderScheduler()
+ {
+ using (var pool = new TestMemoryPool())
+ {
+ using (var scheduler = new ThreadScheduler())
+ {
+ var pipe = new Pipe(new PipeOptions(pool, scheduler, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+
+ Func<Task> doRead = async () =>
+ {
+ int oid = Thread.CurrentThread.ManagedThreadId;
+
+ Assert.False(Thread.CurrentThread.IsThreadPoolThread, "We started on the thread pool");
+
+ ReadResult result = await pipe.Reader.ReadAsync();
+
+ Assert.NotEqual(oid, Thread.CurrentThread.ManagedThreadId);
+
+ Assert.Equal(Thread.CurrentThread.ManagedThreadId, scheduler.Thread.ManagedThreadId);
+
+ pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End);
+
+ pipe.Reader.Complete();
+ };
+
+ Task reading = ExecuteOnNonThreadPoolThread(doRead);
+
+ PipeWriter buffer = pipe.Writer;
+ buffer.Write(Encoding.UTF8.GetBytes("Hello World"));
+ await buffer.FlushAsync();
+
+ await reading;
+ }
+ }
+ }
+
+ [Fact]
+ public async Task ThreadPoolScheduler_SchedulesOnThreadPool()
+ {
+ var pipe = new Pipe(new PipeOptions(readerScheduler: PipeScheduler.ThreadPool, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false));
+
+ async Task DoRead()
+ {
+ int oid = Thread.CurrentThread.ManagedThreadId;
+
+ // Make sure we aren't on a thread pool thread
+ Assert.False(Thread.CurrentThread.IsThreadPoolThread, "We started on the thread pool");
+
+ ValueTask<ReadResult> task = pipe.Reader.ReadAsync();
+
+ Assert.False(task.IsCompleted, "Task completed synchronously");
+
+ ReadResult result = await task;
+
+ Assert.NotEqual(oid, Thread.CurrentThread.ManagedThreadId);
+ Assert.True(Thread.CurrentThread.IsThreadPoolThread);
+ pipe.Reader.AdvanceTo(result.Buffer.End, result.Buffer.End);
+ pipe.Reader.Complete();
+ }
+
+ bool callbackRan = false;
+
+ // Wait start the thread and wait for it to finish
+ Task reading = ExecuteOnNonThreadPoolThread(DoRead);
+
+ PipeWriter buffer = pipe.Writer;
+ pipe.Writer.OnReaderCompleted((state, exception) =>
+ {
+ callbackRan = true;
+ Assert.True(Thread.CurrentThread.IsThreadPoolThread);
+ },
+ null);
+
+ buffer.Write(Encoding.UTF8.GetBytes("Hello World"));
+ await buffer.FlushAsync();
+
+ await reading;
+
+ Assert.True(callbackRan);
+ }
+
+ private Task ExecuteOnNonThreadPoolThread(Func<Task> func)
+ {
+ // Starts the execution of a task on a non thread pool thread
+ Task task = null;
+ var thread = new Thread(() =>
+ {
+ task = func();
+ });
+ thread.Start();
+ thread.Join();
+ return task;
+ }
+
+ private sealed class CustomSynchronizationContext : SynchronizationContext
+ {
+ public List<Tuple<SendOrPostCallback, object>> Callbacks = new List<Tuple<SendOrPostCallback, object>>();
+
+ public override void Post(SendOrPostCallback d, object state)
+ {
+ Callbacks.Add(Tuple.Create(d, state));
+ }
+ }
+ }
+}
diff --git a/src/System.IO.Pipelines/tests/System.IO.Pipelines.Tests.csproj b/src/System.IO.Pipelines/tests/System.IO.Pipelines.Tests.csproj
new file mode 100644
index 0000000000..eefcb405be
--- /dev/null
+++ b/src/System.IO.Pipelines/tests/System.IO.Pipelines.Tests.csproj
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <ProjectGuid>{9E984EB2-827E-4029-9647-FB5F8B67C553}</ProjectGuid>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Release|AnyCPU'" />
+ <ItemGroup>
+ <Compile Include="BackpressureTests.cs" />
+ <Compile Include="FlushAsyncCancellationTests.cs" />
+ <Compile Include="FlushAsyncCompletionTests.cs" />
+ <Compile Include="FlushResultTests.cs" />
+ <Compile Include="PipeCompletionCallbacksTests.cs" />
+ <Compile Include="PipeLengthTests.cs" />
+ <Compile Include="PipeOptionsTests.cs" />
+ <Compile Include="PipeReaderWriterFacts.cs" />
+ <Compile Include="PipePoolTests.cs" />
+ <Compile Include="PipeResetTests.cs" />
+ <Compile Include="PipeTest.cs" />
+ <Compile Include="PipeWriterTests.cs" />
+ <Compile Include="ReadAsyncCancellationTests.cs" />
+ <Compile Include="ReadAsyncCompletionTests.cs" />
+ <Compile Include="ReadResultTests.cs" />
+ <Compile Include="SchedulerFacts.cs" />
+ <Compile Include="TestMemoryPool.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <ItemGroup>
+ <!-- Some internal types are needed, so we reference the implementation assembly, rather than the reference assembly. -->
+ <TargetingPackExclusions Include="System.IO.Pipelines" />
+ <ReferenceFromRuntime Include="System.IO.Pipelines" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project> \ No newline at end of file
diff --git a/src/System.IO.Pipelines/tests/TestMemoryPool.cs b/src/System.IO.Pipelines/tests/TestMemoryPool.cs
new file mode 100644
index 0000000000..0736c37876
--- /dev/null
+++ b/src/System.IO.Pipelines/tests/TestMemoryPool.cs
@@ -0,0 +1,144 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Threading;
+
+namespace System.IO.Pipelines
+{
+ public class TestMemoryPool: MemoryPool<byte>
+ {
+ private MemoryPool<byte> _pool = Shared;
+
+ private bool _disposed;
+
+ public override OwnedMemory<byte> Rent(int minBufferSize = -1)
+ {
+ CheckDisposed();
+ return new PooledMemory(_pool.Rent(minBufferSize), this);
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ _disposed = true;
+ }
+
+ public override int MaxBufferSize => 4096;
+
+ internal void CheckDisposed()
+ {
+ if (_disposed)
+ {
+ throw new ObjectDisposedException(nameof(TestMemoryPool));
+ }
+ }
+
+ private class PooledMemory : OwnedMemory<byte>
+ {
+ private OwnedMemory<byte> _ownedMemory;
+
+ private readonly TestMemoryPool _pool;
+
+ private int _referenceCount;
+
+ private bool _returned;
+
+ private string _leaser;
+
+ public PooledMemory(OwnedMemory<byte> ownedMemory, TestMemoryPool pool)
+ {
+ _ownedMemory = ownedMemory;
+ _pool = pool;
+ _leaser = Environment.StackTrace;
+ _referenceCount = 1;
+ }
+
+ ~PooledMemory()
+ {
+ Debug.Assert(_returned, "Block being garbage collected instead of returned to pool" + Environment.NewLine + _leaser);
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ _pool.CheckDisposed();
+ _ownedMemory.Dispose();
+ }
+
+ public override MemoryHandle Pin(int byteOffset = 0)
+ {
+ _pool.CheckDisposed();
+ return _ownedMemory.Pin(byteOffset);
+ }
+
+ public override void Retain()
+ {
+ _pool.CheckDisposed();
+ _ownedMemory.Retain();
+ Interlocked.Increment(ref _referenceCount);
+ }
+
+ public override bool Release()
+ {
+ _pool.CheckDisposed();
+ _ownedMemory.Release();
+
+ int newRefCount = Interlocked.Decrement(ref _referenceCount);
+
+ if (newRefCount < 0)
+ throw new InvalidOperationException();
+
+ if (newRefCount == 0)
+ {
+ _returned = true;
+ return false;
+ }
+ return true;
+ }
+
+ protected override bool TryGetArray(out ArraySegment<byte> segment)
+ {
+ _pool.CheckDisposed();
+ return MemoryMarshal.TryGetArray(_ownedMemory.Memory, out segment);
+ }
+
+ public override bool IsDisposed
+ {
+ get
+ {
+ _pool.CheckDisposed();
+ return _ownedMemory.IsDisposed;
+ }
+ }
+
+ protected override bool IsRetained
+ {
+ get
+ {
+ _pool.CheckDisposed();
+ return !_returned;
+ }
+ }
+
+ public override int Length
+ {
+ get
+ {
+ _pool.CheckDisposed();
+ return _ownedMemory.Length;
+ }
+ }
+
+ public override Span<byte> Span
+ {
+ get
+ {
+ _pool.CheckDisposed();
+ return _ownedMemory.Span;
+ }
+ }
+ }
+ }
+}
diff --git a/src/System.IO.Pipes.AccessControl/System.IO.Pipes.AccessControl.sln b/src/System.IO.Pipes.AccessControl/System.IO.Pipes.AccessControl.sln
index e1624750a0..1452260fa5 100644
--- a/src/System.IO.Pipes.AccessControl/System.IO.Pipes.AccessControl.sln
+++ b/src/System.IO.Pipes.AccessControl/System.IO.Pipes.AccessControl.sln
@@ -30,10 +30,10 @@ Global
{A0356E61-19E1-4722-A53D-5D2616E16312}.Debug|Any CPU.Build.0 = netstandard-Windows_NT-Debug|Any CPU
{A0356E61-19E1-4722-A53D-5D2616E16312}.Release|Any CPU.ActiveCfg = netstandard-Windows_NT-Release|Any CPU
{A0356E61-19E1-4722-A53D-5D2616E16312}.Release|Any CPU.Build.0 = netstandard-Windows_NT-Release|Any CPU
- {40059634-BB03-4A6F-8657-CCE2D376BC8B}.Debug|Any CPU.ActiveCfg = netstandard-Windows_NT-Debug|Any CPU
- {40059634-BB03-4A6F-8657-CCE2D376BC8B}.Debug|Any CPU.Build.0 = netstandard-Windows_NT-Debug|Any CPU
- {40059634-BB03-4A6F-8657-CCE2D376BC8B}.Release|Any CPU.ActiveCfg = netstandard-Windows_NT-Release|Any CPU
- {40059634-BB03-4A6F-8657-CCE2D376BC8B}.Release|Any CPU.Build.0 = netstandard-Windows_NT-Release|Any CPU
+ {40059634-BB03-4A6F-8657-CCE2D376BC8B}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU
+ {40059634-BB03-4A6F-8657-CCE2D376BC8B}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
+ {40059634-BB03-4A6F-8657-CCE2D376BC8B}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
+ {40059634-BB03-4A6F-8657-CCE2D376BC8B}.Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU
{994DCE47-4CF6-479D-AB1D-4EA6A2809C34}.Debug|Any CPU.ActiveCfg = netstandard-Debug|Any CPU
{994DCE47-4CF6-479D-AB1D-4EA6A2809C34}.Debug|Any CPU.Build.0 = netstandard-Debug|Any CPU
{994DCE47-4CF6-479D-AB1D-4EA6A2809C34}.Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
diff --git a/src/System.IO.Pipes.AccessControl/dir.props b/src/System.IO.Pipes.AccessControl/dir.props
index 884a835fb0..8162e77906 100644
--- a/src/System.IO.Pipes.AccessControl/dir.props
+++ b/src/System.IO.Pipes.AccessControl/dir.props
@@ -4,5 +4,8 @@
<PropertyGroup>
<AssemblyVersion>4.0.3.0</AssemblyVersion>
<AssemblyKey>MSFT</AssemblyKey>
+ <IsNETCoreApp>true</IsNETCoreApp>
+ <IsNETCoreAppRef>false</IsNETCoreAppRef>
+ <IsUAP>true</IsUAP>
</PropertyGroup>
</Project> \ No newline at end of file
diff --git a/src/System.IO.Pipes.AccessControl/pkg/System.IO.Pipes.AccessControl.pkgproj b/src/System.IO.Pipes.AccessControl/pkg/System.IO.Pipes.AccessControl.pkgproj
index 107007637e..fa080f3657 100644
--- a/src/System.IO.Pipes.AccessControl/pkg/System.IO.Pipes.AccessControl.pkgproj
+++ b/src/System.IO.Pipes.AccessControl/pkg/System.IO.Pipes.AccessControl.pkgproj
@@ -3,7 +3,7 @@
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<ProjectReference Include="..\ref\System.IO.Pipes.AccessControl.csproj">
- <SupportedFramework>net461;netcoreapp2.0;$(AllXamarinFrameworks)</SupportedFramework>
+ <SupportedFramework>net461;netcoreapp2.0;$(UAPvNextTFM);$(AllXamarinFrameworks)</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\src\System.IO.Pipes.AccessControl.csproj" />
<HarvestIncludePaths Include="ref/net46;lib/net46;runtimes/win/lib/net46" />
@@ -11,6 +11,10 @@
<SupportedFramework>netcore50</SupportedFramework>
</HarvestIncludePaths>
<HarvestIncludePaths Include="runtimes/win/lib/netstandard1.3;lib/netstandard1.3" />
+ <InboxOnTargetFramework Include="$(UAPvNextTFM)" />
+ <File Include="$(PlaceHolderFile)">
+ <TargetPath>runtimes/win/lib/$(UAPvNextTFM)</TargetPath>
+ </File>
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.IO.Pipes.AccessControl/src/Configurations.props b/src/System.IO.Pipes.AccessControl/src/Configurations.props
index 353d21cf4a..ed3e7308d4 100644
--- a/src/System.IO.Pipes.AccessControl/src/Configurations.props
+++ b/src/System.IO.Pipes.AccessControl/src/Configurations.props
@@ -1,10 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
- <BuildConfigurations>
+ <PackageConfigurations>
netfx-Windows_NT;
+ netcoreapp-Windows_NT;
netstandard-Windows_NT;
netstandard;
+ </PackageConfigurations>
+ <BuildConfigurations>
+ $(PackageConfigurations);
+ uap-Windows_NT;
</BuildConfigurations>
</PropertyGroup>
-</Project> \ No newline at end of file
+</Project> \ No newline at end of file
diff --git a/src/System.IO.Pipes.AccessControl/src/System.IO.Pipes.AccessControl.csproj b/src/System.IO.Pipes.AccessControl/src/System.IO.Pipes.AccessControl.csproj
index 15b3bcf8c4..d159299881 100644
--- a/src/System.IO.Pipes.AccessControl/src/System.IO.Pipes.AccessControl.csproj
+++ b/src/System.IO.Pipes.AccessControl/src/System.IO.Pipes.AccessControl.csproj
@@ -4,32 +4,42 @@
<PropertyGroup>
<AssemblyName>System.IO.Pipes.AccessControl</AssemblyName>
<ProjectGuid>{40059634-BB03-4A6F-8657-CCE2D376BC8B}</ProjectGuid>
- <AllowUnsafeBlocks Condition="'$(TargetGroup)'=='netstandard'">true</AllowUnsafeBlocks>
+ <IncludeDefaultReferences Condition="'$(TargetGroup)' == 'netcoreapp' OR '$(TargetGroup)' == 'uap'">false</IncludeDefaultReferences>
+ <AllowUnsafeBlocks Condition="'$(TargetGroup)' == 'netstandard'">true</AllowUnsafeBlocks>
<GeneratePlatformNotSupportedAssemblyMessage Condition="'$(TargetGroup)' == 'netstandard' AND '$(TargetsWindows)' != 'true'">SR.PlatformNotSupported_AccessControl</GeneratePlatformNotSupportedAssemblyMessage>
- <IsPartialFacadeAssembly Condition="'$(TargetGroup)'=='netfx'">true</IsPartialFacadeAssembly>
+ <IsPartialFacadeAssembly Condition="'$(TargetGroup)' != 'netstandard'">true</IsPartialFacadeAssembly>
</PropertyGroup>
- <!-- Default configurations to help VS understand the options -->
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Windows_NT-Release|AnyCPU'" />
- <ItemGroup Condition="'$(IsPartialFacadeAssembly)'!='true' AND '$(TargetsWindows)'=='true'">
- <Compile Include="System\IO\PipeSecurity.cs" />
- <Compile Include="System\IO\PipeAccessRights.cs" />
- <Compile Include="System\IO\PipeAccessRule.cs" />
- <Compile Include="System\IO\PipeAuditRule.cs" />
- <Compile Include="System\IO\PipesAclExtensions.cs" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Release|AnyCPU'" />
+ <ItemGroup Condition="'$(TargetGroup)' == 'netstandard' AND '$(TargetsWindows)' == 'true'">
+ <Compile Include="..\..\System.IO.Pipes\src\System\IO\Pipes\PipeSecurity.cs" />
+ <Compile Include="..\..\System.IO.Pipes\src\System\IO\Pipes\PipeAccessRights.cs" />
+ <Compile Include="..\..\System.IO.Pipes\src\System\IO\Pipes\PipeAccessRule.cs" />
+ <Compile Include="..\..\System.IO.Pipes\src\System\IO\Pipes\PipeAuditRule.cs" />
+ <Compile Include="..\..\System.IO.Pipes\src\System\IO\Pipes\PipesAclExtensions.cs" />
</ItemGroup>
- <ItemGroup Condition="'$(TargetGroup)'=='netfx'">
+ <ItemGroup Condition="'$(TargetGroup)' == 'netfx'">
<Reference Include="mscorlib" />
<Reference Include="System.Core" />
<Compile Include="System\IO\PipesAclExtensions.net46.cs" />
</ItemGroup>
- <ItemGroup Condition="'$(TargetGroup)'!='netfx'">
+ <ItemGroup Condition="'$(TargetGroup)' == 'netstandard'">
<Reference Include="System.Security.AccessControl" />
<Reference Include="System.Security.Principal.Windows" />
</ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp' OR '$(TargetGroup)' == 'uap'">
+ <Reference Include="System.Runtime" />
+ <Reference Include="System.Resources.ResourceManager" />
+ <ProjectReference Include="..\..\System.IO.Pipes\src\System.IO.Pipes.csproj" />
+ <ProjectReference Include="..\..\System.Security.AccessControl\src\System.Security.AccessControl.csproj" />
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.IO.Pipes/ref/System.IO.Pipes.cs b/src/System.IO.Pipes/ref/System.IO.Pipes.cs
index 6e234afd8a..2b0142f143 100644
--- a/src/System.IO.Pipes/ref/System.IO.Pipes.cs
+++ b/src/System.IO.Pipes/ref/System.IO.Pipes.cs
@@ -90,6 +90,7 @@ namespace System.IO.Pipes
public enum PipeOptions
{
Asynchronous = 1073741824,
+ CurrentUserOnly = 536870912,
None = 0,
WriteThrough = -2147483648,
}
diff --git a/src/System.IO.Pipes/src/MatchingRefApiCompatBaseline.txt b/src/System.IO.Pipes/src/MatchingRefApiCompatBaseline.txt
new file mode 100644
index 0000000000..f9ce3480d6
--- /dev/null
+++ b/src/System.IO.Pipes/src/MatchingRefApiCompatBaseline.txt
@@ -0,0 +1,6 @@
+# Exposed public in System.IO.Pipes.AccessControl but implemented in System.IO.Pipes
+TypesMustExist : Type 'System.IO.Pipes.PipeAccessRights' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.IO.Pipes.PipeAccessRule' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.IO.Pipes.PipeAuditRule' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.IO.Pipes.PipesAclExtensions' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.IO.Pipes.PipeSecurity' does not exist in the implementation but it does exist in the contract.
diff --git a/src/System.IO.Pipes/src/Resources/Strings.resx b/src/System.IO.Pipes/src/Resources/Strings.resx
index d9d9e05e7a..6b39e62d7f 100644
--- a/src/System.IO.Pipes/src/Resources/Strings.resx
+++ b/src/System.IO.Pipes/src/Resources/Strings.resx
@@ -120,12 +120,18 @@
<data name="ArgumentOutOfRange_NeedNonNegNum" xml:space="preserve">
<value>Non negative number is required.</value>
</data>
+ <data name="ArgumentOutOfRange_NeedValidPipeAccessRights" xml:space="preserve">
+ <value>Invalid PipeAccessRights value.</value>
+ </data>
<data name="Argument_InvalidOffLen" xml:space="preserve">
<value>Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection.</value>
</data>
<data name="Argument_NeedNonemptyPipeName" xml:space="preserve">
<value>pipeName cannot be an empty string.</value>
</data>
+ <data name="Argument_NonContainerInvalidAnyFlag" xml:space="preserve">
+ <value>This flag may not be set on a pipe.</value>
+ </data>
<data name="Argument_EmptyServerName" xml:space="preserve">
<value>serverName cannot be an empty string. Use \\\".\\\" for current machine.</value>
</data>
@@ -201,6 +207,9 @@
<data name="IO_FileExists_Name" xml:space="preserve">
<value>The file '{0}' already exists.</value>
</data>
+ <data name="IO_IO_PipeBroken" xml:space="preserve">
+ <value>Pipe is broken.</value>
+ </data>
<data name="IO_OperationAborted" xml:space="preserve">
<value>IO operation was aborted unexpectedly.</value>
</data>
@@ -258,8 +267,8 @@
<data name="PlatformNotSupported_RemotePipes" xml:space="preserve">
<value>Access to remote named pipes is not supported on this platform.</value>
</data>
- <data name="PlatformNotSupproted_InvalidNameChars" xml:space="preserve">
- <value>The name of a pipe on this platform must only include characters valid in file names.</value>
+ <data name="PlatformNotSupported_InvalidPipeNameChars" xml:space="preserve">
+ <value>The name of a pipe on this platform must be a valid file name or a valid absolute path to a file name.</value>
</data>
<data name="ObjectDisposed_StreamClosed" xml:space="preserve">
<value>Cannot access a closed Stream.</value>
@@ -273,4 +282,10 @@
<data name="IO_PathTooLong_Path" xml:space="preserve">
<value>The path '{0}' is too long, or a component of the specified path is too long.</value>
</data>
+ <data name="UnauthorizedAccess_NotOwnedByCurrentUser" xml:space="preserve">
+ <value>Could not connect to the pipe because it was not owned by the current user.</value>
+ </data>
+ <data name="UnauthorizedAccess_ClientIsNotCurrentUser" xml:space="preserve">
+ <value>Client connection (user id {0}) was refused because it was not owned by the current user (id {1}).</value>
+ </data>
</root> \ No newline at end of file
diff --git a/src/System.IO.Pipes/src/System.IO.Pipes.csproj b/src/System.IO.Pipes/src/System.IO.Pipes.csproj
index 9a83ec00fe..ed271aa461 100644
--- a/src/System.IO.Pipes/src/System.IO.Pipes.csproj
+++ b/src/System.IO.Pipes/src/System.IO.Pipes.csproj
@@ -7,6 +7,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefineConstants>$(DefineConstants)</DefineConstants>
<OmitTransitiveCompileReferences>true</OmitTransitiveCompileReferences>
+ <ILLinkClearInitLocals>true</ILLinkClearInitLocals>
</PropertyGroup>
<!-- Compiled Source Files -->
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
@@ -131,15 +132,20 @@
<Compile Include="$(CommonPath)\Interop\Windows\advapi32\Interop.ImpersonateNamedPipeClient.cs">
<Link>Common\Interop\Windows\Interop.ImpersonateNamedPipeClient.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\IO\Win32Marshal.cs">
- <Link>Common\System\IO\Win32Marshal.cs</Link>
+ <Compile Include="$(CommonPath)\CoreLib\System\IO\Win32Marshal.cs">
+ <Link>Common\CoreLib\System\IO\Win32Marshal.cs</Link>
</Compile>
<Compile Include="Microsoft\Win32\SafeHandles\SafePipeHandle.Windows.cs" />
<Compile Include="System\IO\Pipes\AnonymousPipeServerStream.Windows.cs" />
<Compile Include="System\IO\Pipes\ConnectionCompletionSource.cs" />
<Compile Include="System\IO\Pipes\NamedPipeClientStream.Windows.cs" />
<Compile Include="System\IO\Pipes\NamedPipeServerStream.Windows.cs" />
+ <Compile Include="System\IO\Pipes\PipeAccessRights.cs" />
+ <Compile Include="System\IO\Pipes\PipeAccessRule.cs" />
+ <Compile Include="System\IO\Pipes\PipeAuditRule.cs" />
+ <Compile Include="System\IO\Pipes\PipesAclExtensions.cs" />
<Compile Include="System\IO\Pipes\PipeCompletionSource.cs" />
+ <Compile Include="System\IO\Pipes\PipeSecurity.cs" />
<Compile Include="System\IO\Pipes\PipeStream.Windows.cs" />
<Compile Include="System\IO\Pipes\ReadWriteCompletionSource.cs" />
</ItemGroup>
@@ -203,7 +209,7 @@
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.OpenFlags.cs">
<Link>Common\Interop\Unix\Interop.OpenFlags.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.Permissions.cs">
+ <Compile Include="$(CommonPath)\CoreLib\Interop\Unix\System.Native\Interop.Permissions.cs">
<Link>Common\Interop\Unix\Interop.Permissions.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.Pipe.cs">
@@ -254,8 +260,15 @@
<Reference Include="System.Threading.Overlapped" />
<Reference Include="System.Threading.Tasks" />
</ItemGroup>
+ <ItemGroup Condition="'$(TargetsWindows)' == 'true'">
+ <Reference Include="System.Collections.NonGeneric" />
+ <Reference Include="System.Security.AccessControl" />
+ <Reference Include="System.Security.Principal.Windows" />
+ <Reference Include="System.Security.Claims" />
+ </ItemGroup>
<ItemGroup Condition="'$(TargetsUnix)' == 'true'">
<Reference Include="Microsoft.Win32.Primitives" />
+ <Reference Include="System.IO.FileSystem" />
<Reference Include="System.Net.Primitives" />
<Reference Include="System.Net.Sockets" />
</ItemGroup>
diff --git a/src/System.IO.Pipes/src/System/IO/Pipes/AnonymousPipeServerStream.Unix.cs b/src/System.IO.Pipes/src/System/IO/Pipes/AnonymousPipeServerStream.Unix.cs
index 2ba5605ddc..0580eeb11b 100644
--- a/src/System.IO.Pipes/src/System/IO/Pipes/AnonymousPipeServerStream.Unix.cs
+++ b/src/System.IO.Pipes/src/System/IO/Pipes/AnonymousPipeServerStream.Unix.cs
@@ -30,7 +30,7 @@ namespace System.IO.Pipes
// bufferSize is just advisory and ignored if platform does not support setting pipe capacity via fcntl.
if (bufferSize > 0 && Interop.Sys.Fcntl.CanGetSetPipeSz)
{
- CheckPipeCall(Interop.Sys.Fcntl.SetPipeSz(serverHandle, bufferSize));
+ Interop.Sys.Fcntl.SetPipeSz(serverHandle, bufferSize); // advisory, ignore errors
}
// We're connected. Finish initialization using the newly created handles.
diff --git a/src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.Unix.cs b/src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.Unix.cs
index bd609d2f0b..d15862dded 100644
--- a/src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.Unix.cs
+++ b/src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.Unix.cs
@@ -3,7 +3,9 @@
// See the LICENSE file in the project root for more information.
using Microsoft.Win32.SafeHandles;
+using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
using System.Net.Sockets;
using System.Security;
using System.Threading;
@@ -49,6 +51,17 @@ namespace System.IO.Pipes
}
}
+ try
+ {
+ ValidateRemotePipeUser(clientHandle);
+ }
+ catch (Exception)
+ {
+ clientHandle.Dispose();
+ socket.Dispose();
+ throw;
+ }
+
InitializeHandle(clientHandle, isExposed: false, isAsync: (_pipeOptions & PipeOptions.Asynchronous) != 0);
State = PipeState.Connected;
return true;
@@ -84,6 +97,23 @@ namespace System.IO.Pipes
}
}
+ private void ValidateRemotePipeUser(SafePipeHandle handle)
+ {
+ if (!IsCurrentUserOnly)
+ return;
+
+ uint userId = Interop.Sys.GetEUid();
+ if (Interop.Sys.GetPeerID(handle, out uint serverOwner) == -1)
+ {
+ throw CreateExceptionForLastError();
+ }
+
+ if (userId != serverOwner)
+ {
+ throw new UnauthorizedAccessException(SR.UnauthorizedAccess_NotOwnedByCurrentUser);
+ }
+ }
+
// -----------------------------
// ---- PAL layer ends here ----
// -----------------------------
diff --git a/src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.Windows.cs b/src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.Windows.cs
index 286e510eee..472d9a9ea7 100644
--- a/src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.Windows.cs
+++ b/src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.Windows.cs
@@ -2,12 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using Microsoft.Win32.SafeHandles;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
-using System.Security;
using System.Security.Principal;
using System.Threading;
+using Microsoft.Win32.SafeHandles;
namespace System.IO.Pipes
{
@@ -25,7 +24,10 @@ namespace System.IO.Pipes
{
Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = PipeStream.GetSecAttrs(_inheritability);
- int _pipeFlags = (int)_pipeOptions;
+ // PipeOptions.CurrentUserOnly is special since it doesn't match directly to a corresponding Win32 valid flag.
+ // Remove it, while keeping others untouched since historically this has been used as a way to pass flags to
+ // CreateNamedPipeClient that were not defined in the enumeration.
+ int _pipeFlags = (int)(_pipeOptions & ~PipeOptions.CurrentUserOnly);
if (_impersonationLevel != TokenImpersonationLevel.None)
{
_pipeFlags |= Interop.Kernel32.SecurityOptions.SECURITY_SQOS_PRESENT;
@@ -99,10 +101,10 @@ namespace System.IO.Pipes
}
}
- // Success!
+ // Success!
InitializeHandle(handle, false, (_pipeOptions & PipeOptions.Asynchronous) != 0);
State = PipeState.Connected;
-
+ ValidateRemotePipeUser();
return true;
}
@@ -129,6 +131,24 @@ namespace System.IO.Pipes
}
}
+ private void ValidateRemotePipeUser()
+ {
+ if (!IsCurrentUserOnly)
+ return;
+
+ PipeSecurity accessControl = this.GetAccessControl();
+ IdentityReference remoteOwnerSid = accessControl.GetOwner(typeof(SecurityIdentifier));
+ using (WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent())
+ {
+ SecurityIdentifier currentUserSid = currentIdentity.Owner;
+ if (remoteOwnerSid != currentUserSid)
+ {
+ State = PipeState.Closed;
+ throw new UnauthorizedAccessException(SR.UnauthorizedAccess_NotOwnedByCurrentUser);
+ }
+ }
+ }
+
// -----------------------------
// ---- PAL layer ends here ----
// -----------------------------
diff --git a/src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.cs b/src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.cs
index cb5bda0977..80767b60bb 100644
--- a/src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.cs
+++ b/src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.cs
@@ -7,6 +7,7 @@ using System.Security;
using System.Security.Principal;
using System.Threading;
using System.Threading.Tasks;
+using System.Diagnostics;
namespace System.IO.Pipes
{
@@ -72,7 +73,7 @@ namespace System.IO.Pipes
{
throw new ArgumentException(SR.Argument_EmptyServerName);
}
- if ((options & ~(PipeOptions.WriteThrough | PipeOptions.Asynchronous)) != 0)
+ if ((options & ~(PipeOptions.WriteThrough | PipeOptions.Asynchronous | PipeOptions.CurrentUserOnly)) != 0)
{
throw new ArgumentOutOfRangeException(nameof(options), SR.ArgumentOutOfRange_OptionsInvalid);
}
@@ -84,6 +85,10 @@ namespace System.IO.Pipes
{
throw new ArgumentOutOfRangeException(nameof(inheritability), SR.ArgumentOutOfRange_HandleInheritabilityNoneOrInheritable);
}
+ if ((options & PipeOptions.CurrentUserOnly) != 0)
+ {
+ IsCurrentUserOnly = true;
+ }
_normalizedPipePath = GetPipePath(serverName, pipeName);
_direction = direction;
diff --git a/src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeServerStream.Unix.cs b/src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeServerStream.Unix.cs
index e2e5b7a88f..c4d755a50c 100644
--- a/src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeServerStream.Unix.cs
+++ b/src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeServerStream.Unix.cs
@@ -41,7 +41,9 @@ namespace System.IO.Pipes
// We don't have a good way to enforce maxNumberOfServerInstances across processes; we only factor it in
// for streams created in this process. Between processes, we behave similarly to maxNumberOfServerInstances == 1,
// in that the second process to come along and create a stream will find the pipe already in existence and will fail.
- _instance = SharedServer.Get(GetPipePath(".", pipeName), maxNumberOfServerInstances);
+ _instance = SharedServer.Get(
+ GetPipePath(".", pipeName),
+ (maxNumberOfServerInstances == MaxAllowedServerInstances) ? int.MaxValue : maxNumberOfServerInstances);
_direction = direction;
_options = options;
@@ -83,8 +85,25 @@ namespace System.IO.Pipes
private void HandleAcceptedSocket(Socket acceptedSocket)
{
var serverHandle = new SafePipeHandle(acceptedSocket);
+
try
{
+ if (IsCurrentUserOnly)
+ {
+ uint serverEUID = Interop.Sys.GetEUid();
+
+ uint peerID;
+ if (Interop.Sys.GetPeerID(serverHandle, out peerID) == -1)
+ {
+ throw CreateExceptionForLastError(_instance?.PipeName);
+ }
+
+ if (serverEUID != peerID)
+ {
+ throw new UnauthorizedAccessException(string.Format(SR.UnauthorizedAccess_ClientIsNotCurrentUser, peerID, serverEUID));
+ }
+ }
+
ConfigureSocket(acceptedSocket, serverHandle, _direction, _inBufferSize, _outBufferSize, _inheritability);
}
catch
@@ -128,7 +147,7 @@ namespace System.IO.Pipes
return name;
}
- throw CreateExceptionForLastError();
+ throw CreateExceptionForLastError(_instance?.PipeName);
}
public override int InBufferSize
@@ -171,13 +190,13 @@ namespace System.IO.Pipes
uint peerID;
if (Interop.Sys.GetPeerID(handle, out peerID) == -1)
{
- throw CreateExceptionForLastError();
+ throw CreateExceptionForLastError(_instance?.PipeName);
}
// set the effective userid of the current (server) process to the clientid
if (Interop.Sys.SetEUid(peerID) == -1)
{
- throw CreateExceptionForLastError();
+ throw CreateExceptionForLastError(_instance?.PipeName);
}
try
@@ -191,14 +210,6 @@ namespace System.IO.Pipes
}
}
- private Exception CreateExceptionForLastError()
- {
- Interop.ErrorInfo error = Interop.Sys.GetLastErrorInfo();
- return error.Error == Interop.Error.ENOTSUP ?
- new PlatformNotSupportedException(SR.Format(SR.PlatformNotSupported_OperatingSystemError, nameof(Interop.Error.ENOTSUP))) :
- Interop.GetExceptionForIoErrno(error, _instance?.PipeName);
- }
-
/// <summary>Shared resources for NamedPipeServerStreams in the same process created for the same path.</summary>
private sealed class SharedServer
{
diff --git a/src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeServerStream.Windows.cs b/src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeServerStream.Windows.cs
index 5f8fe4215d..4a418aca5e 100644
--- a/src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeServerStream.Windows.cs
+++ b/src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeServerStream.Windows.cs
@@ -2,16 +2,16 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using Microsoft.Win32.SafeHandles;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
-using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
-using System.Security;
-using System.Security.Permissions;
+using System.Runtime.InteropServices;
+using System.Security.AccessControl;
+using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.Win32.SafeHandles;
namespace System.IO.Pipes
{
@@ -39,6 +39,28 @@ namespace System.IO.Pipes
throw new ArgumentOutOfRangeException(nameof(pipeName), SR.ArgumentOutOfRange_AnonymousReserved);
}
+ PipeSecurity pipeSecurity = null;
+
+ if (IsCurrentUserOnly)
+ {
+ using (WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent())
+ {
+ SecurityIdentifier identifier = currentIdentity.Owner;
+
+ // Grant full control to the owner so multiple servers can be opened.
+ // Full control is the default per MSDN docs for CreateNamedPipe.
+ PipeAccessRule rule = new PipeAccessRule(identifier, PipeAccessRights.FullControl, AccessControlType.Allow);
+ pipeSecurity = new PipeSecurity();
+
+ pipeSecurity.AddAccessRule(rule);
+ pipeSecurity.SetOwner(identifier);
+ }
+
+ // PipeOptions.CurrentUserOnly is special since it doesn't match directly to a corresponding Win32 valid flag.
+ // Remove it, while keeping others untouched since historically this has been used as a way to pass flags to CreateNamedPipe
+ // that were not defined in the enumeration.
+ options &= ~PipeOptions.CurrentUserOnly;
+ }
int openMode = ((int)direction) |
(maxNumberOfServerInstances == 1 ? Interop.Kernel32.FileOperations.FILE_FLAG_FIRST_PIPE_INSTANCE : 0) |
@@ -53,16 +75,27 @@ namespace System.IO.Pipes
maxNumberOfServerInstances = 255;
}
- Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = PipeStream.GetSecAttrs(inheritability);
- SafePipeHandle handle = Interop.Kernel32.CreateNamedPipe(fullPipeName, openMode, pipeModes,
- maxNumberOfServerInstances, outBufferSize, inBufferSize, 0, ref secAttrs);
+ var pinningHandle = new GCHandle();
+ try
+ {
+ Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = PipeStream.GetSecAttrs(inheritability, pipeSecurity, ref pinningHandle);
+ SafePipeHandle handle = Interop.Kernel32.CreateNamedPipe(fullPipeName, openMode, pipeModes,
+ maxNumberOfServerInstances, outBufferSize, inBufferSize, 0, ref secAttrs);
+
+ if (handle.IsInvalid)
+ {
+ throw Win32Marshal.GetExceptionForLastWin32Error();
+ }
- if (handle.IsInvalid)
+ InitializeHandle(handle, false, (options & PipeOptions.Asynchronous) != 0);
+ }
+ finally
{
- throw Win32Marshal.GetExceptionForLastWin32Error();
+ if (pinningHandle.IsAllocated)
+ {
+ pinningHandle.Free();
+ }
}
-
- InitializeHandle(handle, false, (options & PipeOptions.Asynchronous) != 0);
}
// This will wait until the client calls Connect(). If we return from this method, we guarantee that
diff --git a/src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeServerStream.cs b/src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeServerStream.cs
index 28476c4d77..32c867a942 100644
--- a/src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeServerStream.cs
+++ b/src/System.IO.Pipes/src/System/IO/Pipes/NamedPipeServerStream.cs
@@ -7,6 +7,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Security;
using System.Threading;
using System.Threading.Tasks;
+using System.Diagnostics;
namespace System.IO.Pipes
{
@@ -88,7 +89,7 @@ namespace System.IO.Pipes
{
throw new ArgumentException(SR.Argument_NeedNonemptyPipeName);
}
- if ((options & ~(PipeOptions.WriteThrough | PipeOptions.Asynchronous)) != 0)
+ if ((options & ~(PipeOptions.WriteThrough | PipeOptions.Asynchronous | PipeOptions.CurrentUserOnly)) != 0)
{
throw new ArgumentOutOfRangeException(nameof(options), SR.ArgumentOutOfRange_OptionsInvalid);
}
@@ -112,8 +113,13 @@ namespace System.IO.Pipes
throw new ArgumentOutOfRangeException(nameof(inheritability), SR.ArgumentOutOfRange_HandleInheritabilityNoneOrInheritable);
}
+ if ((options & PipeOptions.CurrentUserOnly) != 0)
+ {
+ IsCurrentUserOnly = true;
+ }
+
Create(pipeName, direction, maxNumberOfServerInstances, transmissionMode,
- options, inBufferSize, outBufferSize, inheritability);
+ options, inBufferSize, outBufferSize, inheritability);
}
// Create a NamedPipeServerStream from an existing server pipe handle.
diff --git a/src/System.IO.Pipes.AccessControl/src/System/IO/PipeAccessRights.cs b/src/System.IO.Pipes/src/System/IO/Pipes/PipeAccessRights.cs
index a75a977fe4..a75a977fe4 100644
--- a/src/System.IO.Pipes.AccessControl/src/System/IO/PipeAccessRights.cs
+++ b/src/System.IO.Pipes/src/System/IO/Pipes/PipeAccessRights.cs
diff --git a/src/System.IO.Pipes.AccessControl/src/System/IO/PipeAccessRule.cs b/src/System.IO.Pipes/src/System/IO/Pipes/PipeAccessRule.cs
index 55fa41ad19..55fa41ad19 100644
--- a/src/System.IO.Pipes.AccessControl/src/System/IO/PipeAccessRule.cs
+++ b/src/System.IO.Pipes/src/System/IO/Pipes/PipeAccessRule.cs
diff --git a/src/System.IO.Pipes.AccessControl/src/System/IO/PipeAuditRule.cs b/src/System.IO.Pipes/src/System/IO/Pipes/PipeAuditRule.cs
index 0687f7388d..0687f7388d 100644
--- a/src/System.IO.Pipes.AccessControl/src/System/IO/PipeAuditRule.cs
+++ b/src/System.IO.Pipes/src/System/IO/Pipes/PipeAuditRule.cs
diff --git a/src/System.IO.Pipes/src/System/IO/Pipes/PipeCompletionSource.cs b/src/System.IO.Pipes/src/System/IO/Pipes/PipeCompletionSource.cs
index c0d462cd4a..ab7fd35d1b 100644
--- a/src/System.IO.Pipes/src/System/IO/Pipes/PipeCompletionSource.cs
+++ b/src/System.IO.Pipes/src/System/IO/Pipes/PipeCompletionSource.cs
@@ -40,7 +40,7 @@ namespace System.IO.Pipes
_threadPoolBinding = handle;
_state = NoResult;
- _pinnedMemory = bufferToPin.Retain(pin: true);
+ _pinnedMemory = bufferToPin.Pin();
_overlapped = _threadPoolBinding.AllocateNativeOverlapped((errorCode, numBytes, pOverlapped) =>
{
var completionSource = (PipeCompletionSource<TResult>)ThreadPoolBoundHandle.GetNativeOverlappedState(pOverlapped);
diff --git a/src/System.IO.Pipes/src/System/IO/Pipes/PipeOptions.cs b/src/System.IO.Pipes/src/System/IO/Pipes/PipeOptions.cs
index 4a36fda29b..6dc1e802ba 100644
--- a/src/System.IO.Pipes/src/System/IO/Pipes/PipeOptions.cs
+++ b/src/System.IO.Pipes/src/System/IO/Pipes/PipeOptions.cs
@@ -10,5 +10,6 @@ namespace System.IO.Pipes
None = 0x0,
WriteThrough = unchecked((int)0x80000000),
Asynchronous = unchecked((int)0x40000000), // corresponds to FILE_FLAG_OVERLAPPED
+ CurrentUserOnly = unchecked((int)0x20000000)
}
}
diff --git a/src/System.IO.Pipes.AccessControl/src/System/IO/PipeSecurity.cs b/src/System.IO.Pipes/src/System/IO/Pipes/PipeSecurity.cs
index a4b8300709..a4b8300709 100644
--- a/src/System.IO.Pipes.AccessControl/src/System/IO/PipeSecurity.cs
+++ b/src/System.IO.Pipes/src/System/IO/Pipes/PipeSecurity.cs
diff --git a/src/System.IO.Pipes/src/System/IO/Pipes/PipeStream.Unix.cs b/src/System.IO.Pipes/src/System/IO/Pipes/PipeStream.Unix.cs
index 1f4d2a9e26..e0448e3588 100644
--- a/src/System.IO.Pipes/src/System/IO/Pipes/PipeStream.Unix.cs
+++ b/src/System.IO.Pipes/src/System/IO/Pipes/PipeStream.Unix.cs
@@ -8,6 +8,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Security;
+using System.IO;
using System.Threading;
using System.Threading.Tasks;
@@ -25,6 +26,9 @@ namespace System.IO.Pipes
/// <summary>Characters that can't be used in a pipe's name.</summary>
private static readonly char[] s_invalidFileNameChars = Path.GetInvalidFileNameChars();
+ /// <summary>Characters that can't be used in an absolute path pipe's name.</summary>
+ private static readonly char[] s_invalidPathNameChars = Path.GetInvalidPathChars();
+
/// <summary>Prefix to prepend to all pipe names.</summary>
private static readonly string s_pipePrefix = Path.Combine(Path.GetTempPath(), "CoreFxPipe_");
@@ -42,16 +46,27 @@ namespace System.IO.Pipes
throw new ArgumentOutOfRangeException(nameof(pipeName), SR.ArgumentOutOfRange_AnonymousReserved);
}
+ // Since pipes are stored as files in the system we support either an absolute path to a file name
+ // or a file name. The support of absolute path was added to allow working around the limited
+ // length available for the pipe name when concatenated with the temp path, while being
+ // cross-platform with Windows (which has only '\' as an invalid char).
+ if (Path.IsPathRooted(pipeName))
+ {
+ if (pipeName.IndexOfAny(s_invalidPathNameChars) >= 0 || pipeName[pipeName.Length - 1] == Path.DirectorySeparatorChar)
+ throw new PlatformNotSupportedException(SR.PlatformNotSupported_InvalidPipeNameChars);
+
+ // Caller is in full control of file location.
+ return pipeName;
+ }
+
if (pipeName.IndexOfAny(s_invalidFileNameChars) >= 0)
{
- // Since pipes are stored as files in the file system, we don't support
- // pipe names that are actually paths or that otherwise have invalid
- // filename characters in them.
- throw new PlatformNotSupportedException(SR.PlatformNotSupproted_InvalidNameChars);
+ throw new PlatformNotSupportedException(SR.PlatformNotSupported_InvalidPipeNameChars);
}
- // Return the pipe path. The pipe is created directly under %TMPDIR%. We previously
- // didn't put it into a subdirectory because it only existed on disk for the duration
+ // The pipe is created directly under Path.GetTempPath() with "CoreFXPipe_" prefix.
+ //
+ // We previously didn't put it into a subdirectory because it only existed on disk for the duration
// between when the server started listening in WaitForConnection and when the client
// connected, after which the pipe was deleted. We now create the pipe when the
// server stream is created, which leaves it on disk longer, but we can't change the
@@ -205,7 +220,7 @@ namespace System.IO.Pipes
}
// Issue the asynchronous read.
- return await (destination.TryGetArray(out ArraySegment<byte> buffer) ?
+ return await (MemoryMarshal.TryGetArray(destination, out ArraySegment<byte> buffer) ?
socket.ReceiveAsync(buffer, SocketFlags.None) :
socket.ReceiveAsync(destination.ToArray(), SocketFlags.None)).ConfigureAwait(false);
}
@@ -473,5 +488,13 @@ namespace System.IO.Pipes
break;
}
}
+
+ internal static Exception CreateExceptionForLastError(string pipeName = null)
+ {
+ Interop.ErrorInfo error = Interop.Sys.GetLastErrorInfo();
+ return error.Error == Interop.Error.ENOTSUP ?
+ new PlatformNotSupportedException(SR.Format(SR.PlatformNotSupported_OperatingSystemError, nameof(Interop.Error.ENOTSUP))) :
+ Interop.GetExceptionForIoErrno(error, pipeName);
+ }
}
}
diff --git a/src/System.IO.Pipes/src/System/IO/Pipes/PipeStream.Windows.cs b/src/System.IO.Pipes/src/System/IO/Pipes/PipeStream.Windows.cs
index 7f5e654bc8..fdcaa423ff 100644
--- a/src/System.IO.Pipes/src/System/IO/Pipes/PipeStream.Windows.cs
+++ b/src/System.IO.Pipes/src/System/IO/Pipes/PipeStream.Windows.cs
@@ -5,7 +5,7 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
-using System.Security;
+using System.Security.Principal;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Win32.SafeHandles;
@@ -412,6 +412,31 @@ namespace System.IO.Pipes
return secAttrs;
}
+ internal static unsafe Interop.Kernel32.SECURITY_ATTRIBUTES GetSecAttrs(HandleInheritability inheritability, PipeSecurity pipeSecurity, ref GCHandle pinningHandle)
+ {
+ Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = default(Interop.Kernel32.SECURITY_ATTRIBUTES);
+ secAttrs.nLength = (uint)sizeof(Interop.Kernel32.SECURITY_ATTRIBUTES);
+
+ if ((inheritability & HandleInheritability.Inheritable) != 0)
+ {
+ secAttrs.bInheritHandle = Interop.BOOL.TRUE;
+ }
+
+ if (pipeSecurity != null)
+ {
+ byte[] securityDescriptor = pipeSecurity.GetSecurityDescriptorBinaryForm();
+ pinningHandle = GCHandle.Alloc(securityDescriptor, GCHandleType.Pinned);
+ fixed (byte* pSecurityDescriptor = securityDescriptor)
+ {
+ secAttrs.lpSecurityDescriptor = (IntPtr)pSecurityDescriptor;
+ }
+ }
+
+ return secAttrs;
+ }
+
+
+
/// <summary>
/// Determine pipe read mode from Win32
/// </summary>
diff --git a/src/System.IO.Pipes/src/System/IO/Pipes/PipeStream.cs b/src/System.IO.Pipes/src/System/IO/Pipes/PipeStream.cs
index 74fe15ed63..f4c0339dc4 100644
--- a/src/System.IO.Pipes/src/System/IO/Pipes/PipeStream.cs
+++ b/src/System.IO.Pipes/src/System/IO/Pipes/PipeStream.cs
@@ -20,6 +20,7 @@ namespace System.IO.Pipes
private bool _canRead;
private bool _canWrite;
private bool _isAsync;
+ private bool _isCurrentUserOnly;
private bool _isMessageComplete;
private bool _isFromExistingHandle;
private bool _isHandleExposed;
@@ -125,11 +126,11 @@ namespace System.IO.Pipes
return ReadCore(new Span<byte>(buffer, offset, count));
}
- public override int Read(Span<byte> destination)
+ public override int Read(Span<byte> buffer)
{
if (_isAsync)
{
- return base.Read(destination);
+ return base.Read(buffer);
}
if (!CanRead)
@@ -138,7 +139,7 @@ namespace System.IO.Pipes
}
CheckReadOperations();
- return ReadCore(destination);
+ return ReadCore(buffer);
}
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
@@ -170,11 +171,11 @@ namespace System.IO.Pipes
return ReadAsyncCore(new Memory<byte>(buffer, offset, count), cancellationToken);
}
- public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken = default(CancellationToken))
+ public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default(CancellationToken))
{
if (!_isAsync)
{
- return base.ReadAsync(destination, cancellationToken);
+ return base.ReadAsync(buffer, cancellationToken);
}
if (!CanRead)
@@ -189,13 +190,13 @@ namespace System.IO.Pipes
CheckReadOperations();
- if (destination.Length == 0)
+ if (buffer.Length == 0)
{
UpdateMessageCompletion(false);
return new ValueTask<int>(0);
}
- return new ValueTask<int>(ReadAsyncCore(destination, cancellationToken));
+ return new ValueTask<int>(ReadAsyncCore(buffer, cancellationToken));
}
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
@@ -232,11 +233,11 @@ namespace System.IO.Pipes
WriteCore(new ReadOnlySpan<byte>(buffer, offset, count));
}
- public override void Write(ReadOnlySpan<byte> source)
+ public override void Write(ReadOnlySpan<byte> buffer)
{
if (_isAsync)
{
- base.Write(source);
+ base.Write(buffer);
return;
}
@@ -246,7 +247,7 @@ namespace System.IO.Pipes
}
CheckWriteOperations();
- WriteCore(source);
+ WriteCore(buffer);
}
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
@@ -277,11 +278,11 @@ namespace System.IO.Pipes
return WriteAsyncCore(new ReadOnlyMemory<byte>(buffer, offset, count), cancellationToken);
}
- public override Task WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken = default(CancellationToken))
+ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default(CancellationToken))
{
if (!_isAsync)
{
- return base.WriteAsync(source, cancellationToken);
+ return base.WriteAsync(buffer, cancellationToken);
}
if (!CanWrite)
@@ -291,17 +292,17 @@ namespace System.IO.Pipes
if (cancellationToken.IsCancellationRequested)
{
- return Task.FromCanceled<int>(cancellationToken);
+ return new ValueTask(Task.FromCanceled<int>(cancellationToken));
}
CheckWriteOperations();
- if (source.Length == 0)
+ if (buffer.Length == 0)
{
- return Task.CompletedTask;
+ return default;
}
- return WriteAsyncCore(source, cancellationToken);
+ return new ValueTask(WriteAsyncCore(buffer, cancellationToken));
}
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
@@ -630,5 +631,17 @@ namespace System.IO.Pipes
_state = value;
}
}
+
+ internal bool IsCurrentUserOnly
+ {
+ get
+ {
+ return _isCurrentUserOnly;
+ }
+ set
+ {
+ _isCurrentUserOnly = value;
+ }
+ }
}
}
diff --git a/src/System.IO.Pipes.AccessControl/src/System/IO/PipesAclExtensions.cs b/src/System.IO.Pipes/src/System/IO/Pipes/PipesAclExtensions.cs
index f6f5078c79..f6f5078c79 100644
--- a/src/System.IO.Pipes.AccessControl/src/System/IO/PipesAclExtensions.cs
+++ b/src/System.IO.Pipes/src/System/IO/Pipes/PipesAclExtensions.cs
diff --git a/src/System.IO.Pipes/tests/AnonymousPipeTests/AnonymousPipeTest.CrossProcess.cs b/src/System.IO.Pipes/tests/AnonymousPipeTests/AnonymousPipeTest.CrossProcess.cs
index c07b10c625..a57347c99e 100644
--- a/src/System.IO.Pipes/tests/AnonymousPipeTests/AnonymousPipeTest.CrossProcess.cs
+++ b/src/System.IO.Pipes/tests/AnonymousPipeTests/AnonymousPipeTest.CrossProcess.cs
@@ -17,7 +17,7 @@ namespace System.IO.Pipes.Tests
// Then spawn another process to communicate with.
using (var outbound = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable))
using (var inbound = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.Inheritable))
- using (var remote = RemoteInvoke(PingPong_OtherProcess, outbound.GetClientHandleAsString(), inbound.GetClientHandleAsString()))
+ using (var remote = RemoteInvoke(new Func<string, string, int>(PingPong_OtherProcess), outbound.GetClientHandleAsString(), inbound.GetClientHandleAsString()))
{
// Close our local copies of the handles now that we've passed them of to the other process
outbound.DisposeLocalCopyOfClientHandle();
diff --git a/src/System.IO.Pipes/tests/AnonymousPipeTests/AnonymousPipeTest.Specific.cs b/src/System.IO.Pipes/tests/AnonymousPipeTests/AnonymousPipeTest.Specific.cs
index 2006587e71..00d0478a32 100644
--- a/src/System.IO.Pipes/tests/AnonymousPipeTests/AnonymousPipeTest.Specific.cs
+++ b/src/System.IO.Pipes/tests/AnonymousPipeTests/AnonymousPipeTest.Specific.cs
@@ -86,9 +86,10 @@ namespace System.IO.Pipes.Tests
// On Linux, setting the buffer size of the server will also set the buffer size of the
// client, regardless of the direction of the flow
- int desiredBufferSize;
- using (var server = new AnonymousPipeServerStream(PipeDirection.Out))
+ int desiredBufferSize = 4096;
+ using (var server = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.None, desiredBufferSize))
{
+ Assert.Equal(desiredBufferSize, server.OutBufferSize);
desiredBufferSize = server.OutBufferSize * 2;
Assert.True(desiredBufferSize > 0);
}
diff --git a/src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CreateClient.cs b/src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CreateClient.cs
index 98293f9c65..3eaff2f4d5 100644
--- a/src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CreateClient.cs
+++ b/src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CreateClient.cs
@@ -75,6 +75,10 @@ namespace System.IO.Pipes.Tests
Assert.Throws<PlatformNotSupportedException>(() => new NamedPipeClientStream("foobar" + hostName, "foobar"));
Assert.Throws<PlatformNotSupportedException>(() => new NamedPipeClientStream(hostName, "foobar" + Path.GetInvalidFileNameChars()[0]));
+ Assert.Throws<PlatformNotSupportedException>(() => new NamedPipeClientStream(hostName, "/tmp/foo\0bar"));
+ Assert.Throws<PlatformNotSupportedException>(() => new NamedPipeClientStream(hostName, "/tmp/foobar/"));
+ Assert.Throws<PlatformNotSupportedException>(() => new NamedPipeClientStream(hostName, "/"));
+ Assert.Throws<PlatformNotSupportedException>(() => new NamedPipeClientStream(hostName, "\0"));
}
[Theory]
diff --git a/src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CrossProcess.cs b/src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CrossProcess.cs
index 482d5f5910..bb3455b57b 100644
--- a/src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CrossProcess.cs
+++ b/src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CrossProcess.cs
@@ -22,7 +22,7 @@ namespace System.IO.Pipes.Tests
// another process with which to communicate
using (var outbound = new NamedPipeServerStream(outName, PipeDirection.Out))
using (var inbound = new NamedPipeClientStream(".", inName, PipeDirection.In))
- using (RemoteInvoke(PingPong_OtherProcess, outName, inName))
+ using (RemoteInvoke(new Func<string, string, int>(PingPong_OtherProcess), outName, inName))
{
// Wait for both pipes to be connected
Task.WaitAll(outbound.WaitForConnectionAsync(), inbound.ConnectAsync());
@@ -48,7 +48,7 @@ namespace System.IO.Pipes.Tests
// another process with which to communicate
using (var outbound = new NamedPipeServerStream(outName, PipeDirection.Out))
using (var inbound = new NamedPipeClientStream(".", inName, PipeDirection.In))
- using (RemoteInvoke(PingPong_OtherProcess, outName, inName))
+ using (RemoteInvoke(new Func<string, string, int>(PingPong_OtherProcess), outName, inName))
{
// Wait for both pipes to be connected
await Task.WhenAll(outbound.WaitForConnectionAsync(), inbound.ConnectAsync());
diff --git a/src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CurrentUserOnly.netcoreapp.Unix.cs b/src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CurrentUserOnly.netcoreapp.Unix.cs
new file mode 100644
index 0000000000..efe976c974
--- /dev/null
+++ b/src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CurrentUserOnly.netcoreapp.Unix.cs
@@ -0,0 +1,65 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+using Xunit.NetCore.Extensions;
+
+namespace System.IO.Pipes.Tests
+{
+ /// <summary>
+ /// Negative tests for PipeOptions.CurrentUserOnly in Unix.
+ /// </summary>
+ public class NamedPipeTest_CurrentUserOnly_Unix : RemoteExecutorTestBase
+ {
+ [Theory]
+ [OuterLoop("Needs sudo access")]
+ [Trait(XunitConstants.Category, XunitConstants.RequiresElevation)]
+ [InlineData(PipeOptions.None, PipeOptions.None)]
+ [InlineData(PipeOptions.None, PipeOptions.CurrentUserOnly)]
+ [InlineData(PipeOptions.CurrentUserOnly, PipeOptions.None)]
+ [InlineData(PipeOptions.CurrentUserOnly, PipeOptions.CurrentUserOnly)]
+ public async Task Connection_UnderDifferentUsers_BehavesAsExpected(
+ PipeOptions serverPipeOptions, PipeOptions clientPipeOptions)
+ {
+ // Use an absolute path, otherwise, the test can fail if the remote invoker and test runner have
+ // different working and/or temp directories.
+ string pipeName = "/tmp/" + Path.GetRandomFileName();
+ using (var server = new NamedPipeServerStream(
+ pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, serverPipeOptions | PipeOptions.Asynchronous))
+ {
+ Task serverTask = server.WaitForConnectionAsync(CancellationToken.None);
+
+ using (RemoteInvoke(
+ new Func<string, string, int>(ConnectClientFromRemoteInvoker),
+ pipeName,
+ clientPipeOptions == PipeOptions.CurrentUserOnly ? "true" : "false",
+ new RemoteInvokeOptions { RunAsSudo = true }))
+ {
+ }
+
+ if (serverPipeOptions == PipeOptions.CurrentUserOnly)
+ await Assert.ThrowsAsync<UnauthorizedAccessException>(() => serverTask);
+ else
+ await serverTask;
+ }
+ }
+
+ private static int ConnectClientFromRemoteInvoker(string pipeName, string isCurrentUserOnly)
+ {
+ PipeOptions pipeOptions = bool.Parse(isCurrentUserOnly) ? PipeOptions.CurrentUserOnly : PipeOptions.None;
+ using (var client = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, pipeOptions))
+ {
+ if (pipeOptions == PipeOptions.CurrentUserOnly)
+ Assert.Throws<UnauthorizedAccessException>(() => client.Connect());
+ else
+ client.Connect();
+ }
+
+ return SuccessExitCode;
+ }
+ }
+}
diff --git a/src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CurrentUserOnly.netcoreapp.Windows.cs b/src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CurrentUserOnly.netcoreapp.Windows.cs
new file mode 100644
index 0000000000..175cbb3d25
--- /dev/null
+++ b/src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CurrentUserOnly.netcoreapp.Windows.cs
@@ -0,0 +1,190 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.Win32.SafeHandles;
+using System.ComponentModel;
+using System.DirectoryServices.AccountManagement;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Principal;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.IO.Pipes.Tests
+{
+ // Class to be used as xUnit fixture to avoid creating the user, an relatively slow operation (couple of seconds), multiple times.
+ public class TestAccountImpersonator : IDisposable
+ {
+ private const string TestAccountName = "CorFxTst0uZa"; // Random suffix to avoid matching any other account by accident, but const to avoid leaking it.
+ private SafeAccessTokenHandle _testAccountTokenHandle;
+
+ public TestAccountImpersonator()
+ {
+ string testAccountPassword;
+ using (RandomNumberGenerator rng = new RNGCryptoServiceProvider())
+ {
+ var randomBytes = new byte[33];
+ rng.GetBytes(randomBytes);
+
+ // Add special chars to ensure it satisfies password requirements.
+ testAccountPassword = Convert.ToBase64String(randomBytes) + "_-As@!%*(1)4#2";
+ }
+
+ DateTime accountExpirationDate = DateTime.UtcNow + TimeSpan.FromMinutes(2);
+ using (var principalCtx = new PrincipalContext(ContextType.Machine))
+ {
+ bool needToCreate = false;
+ using (var foundUserPrincipal = UserPrincipal.FindByIdentity(principalCtx, TestAccountName))
+ {
+ if (foundUserPrincipal == null)
+ {
+ needToCreate = true;
+ }
+ else
+ {
+ // Somehow the account leaked from previous runs, however, password is lost, reset it.
+ foundUserPrincipal.SetPassword(testAccountPassword);
+ foundUserPrincipal.AccountExpirationDate = accountExpirationDate;
+ foundUserPrincipal.Save();
+ }
+ }
+
+ if (needToCreate)
+ {
+ using (var userPrincipal = new UserPrincipal(principalCtx))
+ {
+ userPrincipal.SetPassword(testAccountPassword);
+ userPrincipal.AccountExpirationDate = accountExpirationDate;
+ userPrincipal.Name = TestAccountName;
+ userPrincipal.DisplayName = TestAccountName;
+ userPrincipal.Description = TestAccountName;
+ userPrincipal.Save();
+ }
+ }
+ }
+
+ const int LOGON32_PROVIDER_DEFAULT = 0;
+ const int LOGON32_LOGON_INTERACTIVE = 2;
+
+ if (!LogonUser(TestAccountName, ".", testAccountPassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out _testAccountTokenHandle))
+ {
+ _testAccountTokenHandle = null;
+ throw new Exception($"Failed to get SafeAccessTokenHandle for test account {TestAccountName}", new Win32Exception());
+ }
+ }
+
+ public void Dispose()
+ {
+ if (_testAccountTokenHandle == null)
+ return;
+
+ _testAccountTokenHandle.Dispose();
+ _testAccountTokenHandle = null;
+
+ using (var principalCtx = new PrincipalContext(ContextType.Machine))
+ using (var userPrincipal = UserPrincipal.FindByIdentity(principalCtx, TestAccountName))
+ {
+ if (userPrincipal == null)
+ throw new Exception($"Failed to get user principal to delete test account {TestAccountName}");
+
+ try
+ {
+ userPrincipal.Delete();
+ }
+ catch (InvalidOperationException)
+ {
+ // TODO: Investigate, it always throw this exception with "Can't delete object already deleted", but it actually deletes it.
+ }
+ }
+ }
+
+ // This method asserts if it impersonates the current identity, i.e.: it ensures that an actual impersonation happens
+ public void RunImpersonated(Action action)
+ {
+ using (WindowsIdentity serverIdentity = WindowsIdentity.GetCurrent())
+ {
+ WindowsIdentity.RunImpersonated(_testAccountTokenHandle, () =>
+ {
+ using (WindowsIdentity clientIdentity = WindowsIdentity.GetCurrent())
+ Assert.NotEqual(serverIdentity.Name, clientIdentity.Name);
+
+ action();
+ });
+ }
+ }
+
+ [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ private static extern bool LogonUser(string userName, string domain, string password, int logonType, int logonProvider, out SafeAccessTokenHandle safeAccessTokenHandle);
+ }
+
+ /// <summary>
+ /// Negative tests for PipeOptions.CurrentUserOnly in Windows.
+ /// </summary>
+ public class NamedPipeTest_CurrentUserOnly_Windows : NamedPipeTestBase, IClassFixture<TestAccountImpersonator>
+ {
+ public static bool IsAdminOnSupportedWindowsVersions => PlatformDetection.IsWindowsAndElevated
+ && !PlatformDetection.IsWindows7
+ && !PlatformDetection.IsWindowsNanoServer;
+
+ private TestAccountImpersonator _testAccountImpersonator;
+
+ public NamedPipeTest_CurrentUserOnly_Windows(TestAccountImpersonator testAccountImpersonator)
+ {
+ _testAccountImpersonator = testAccountImpersonator;
+ }
+
+ [OuterLoop]
+ [ConditionalTheory(nameof(IsAdminOnSupportedWindowsVersions))]
+ [InlineData(PipeOptions.None, PipeOptions.None)]
+ [InlineData(PipeOptions.None, PipeOptions.CurrentUserOnly)]
+ [InlineData(PipeOptions.CurrentUserOnly, PipeOptions.None)]
+ [InlineData(PipeOptions.CurrentUserOnly, PipeOptions.CurrentUserOnly)]
+ public void Connection_UnderDifferentUsers_BehavesAsExpected(
+ PipeOptions serverPipeOptions, PipeOptions clientPipeOptions)
+ {
+ string name = GetUniquePipeName();
+ using (var cts = new CancellationTokenSource())
+ using (var server = new NamedPipeServerStream(name, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, serverPipeOptions | PipeOptions.Asynchronous))
+ {
+ Task serverTask = server.WaitForConnectionAsync(cts.Token);
+
+ _testAccountImpersonator.RunImpersonated(() =>
+ {
+ using (var client = new NamedPipeClientStream(".", name, PipeDirection.InOut, clientPipeOptions))
+ {
+ Assert.Throws<UnauthorizedAccessException>(() => client.Connect());
+ }
+ });
+
+ // Server is expected to not have received any request.
+ cts.Cancel();
+ AggregateException e = Assert.Throws<AggregateException>(() => serverTask.Wait(10_000));
+ Assert.IsType(typeof(TaskCanceledException), e.InnerException);
+ }
+ }
+
+ [OuterLoop]
+ [ConditionalFact(nameof(IsAdminOnSupportedWindowsVersions))]
+ public void Allow_Connection_UnderDifferentUsers_ForClientReading()
+ {
+ string name = GetUniquePipeName();
+ using (var server = new NamedPipeServerStream(
+ name, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous))
+ {
+ Task serverTask = server.WaitForConnectionAsync(CancellationToken.None);
+
+ _testAccountImpersonator.RunImpersonated(() =>
+ {
+ using (var client = new NamedPipeClientStream(".", name, PipeDirection.In))
+ {
+ client.Connect(10_000);
+ }
+ });
+
+ Assert.True(serverTask.Wait(10_000));
+ }
+ }
+ }
+}
diff --git a/src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CurrentUserOnly.netcoreapp.cs b/src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CurrentUserOnly.netcoreapp.cs
new file mode 100644
index 0000000000..08b9836b18
--- /dev/null
+++ b/src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CurrentUserOnly.netcoreapp.cs
@@ -0,0 +1,154 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.IO.Pipes.Tests
+{
+ /// <summary>
+ /// Tests for the constructors for NamedPipeClientStream
+ /// </summary>
+ public class NamedPipeTest_CurrentUserOnly : NamedPipeTestBase
+ {
+ [Fact]
+ public static void CreateClient_CurrentUserOnly()
+ {
+ // Should not throw.
+ new NamedPipeClientStream(".", GetUniquePipeName(), PipeDirection.InOut, PipeOptions.CurrentUserOnly).Dispose();
+ }
+
+ [Fact]
+ public static void CreateServer_CurrentUserOnly()
+ {
+ // Should not throw.
+ new NamedPipeServerStream(GetUniquePipeName(), PipeDirection.InOut, 2, PipeTransmissionMode.Byte, PipeOptions.CurrentUserOnly).Dispose();
+ }
+
+ [Fact]
+ public static void CreateServer_ConnectClient()
+ {
+ string name = GetUniquePipeName();
+ using (var server = new NamedPipeServerStream(name, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.CurrentUserOnly))
+ {
+ using (var client = new NamedPipeClientStream(".", name, PipeDirection.InOut, PipeOptions.CurrentUserOnly))
+ {
+ // Should not fail to connect since both, the server and client have the same owner.
+ client.Connect();
+ }
+ }
+ }
+
+ [Fact]
+ public static void CreateServer_ConnectClient_UsingUnixAbsolutePath()
+ {
+ string name = Path.Combine("/tmp", GetUniquePipeName());
+ using (var server = new NamedPipeServerStream(name, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.CurrentUserOnly))
+ {
+ using (var client = new NamedPipeClientStream(".", name, PipeDirection.InOut, PipeOptions.CurrentUserOnly))
+ {
+ client.Connect();
+ }
+ }
+ }
+
+ [Theory]
+ [InlineData(PipeOptions.None, PipeOptions.CurrentUserOnly)]
+ [InlineData(PipeOptions.CurrentUserOnly, PipeOptions.None)]
+ public static void Connection_UnderSameUser_SingleSide_CurrentUserOnly_Works(PipeOptions serverPipeOptions, PipeOptions clientPipeOptions)
+ {
+ string name = GetUniquePipeName();
+ using (var server = new NamedPipeServerStream(name, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, serverPipeOptions))
+ using (var client = new NamedPipeClientStream(".", name, PipeDirection.InOut, clientPipeOptions))
+ {
+ Task[] tasks = new[]
+ {
+ Task.Run(() => server.WaitForConnection()),
+ Task.Run(() => client.Connect())
+ };
+
+ Assert.True(Task.WaitAll(tasks, 20_000));
+ }
+ }
+
+ [Fact]
+ public static void CreateMultipleServers_ConnectMultipleClients()
+ {
+ string name1 = GetUniquePipeName();
+ string name2 = GetUniquePipeName();
+ string name3 = GetUniquePipeName();
+ using (var server1 = new NamedPipeServerStream(name1, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.CurrentUserOnly))
+ using (var server2 = new NamedPipeServerStream(name2, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.CurrentUserOnly))
+ using (var server3 = new NamedPipeServerStream(name3, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.CurrentUserOnly))
+ {
+ using (var client1 = new NamedPipeClientStream(".", name1, PipeDirection.InOut, PipeOptions.CurrentUserOnly))
+ using (var client2 = new NamedPipeClientStream(".", name2, PipeDirection.InOut, PipeOptions.CurrentUserOnly))
+ using (var client3 = new NamedPipeClientStream(".", name3, PipeDirection.InOut, PipeOptions.CurrentUserOnly))
+ {
+ client1.Connect();
+ client2.Connect();
+ client3.Connect();
+ }
+ }
+ }
+
+ [Fact]
+ public static void CreateMultipleServers_ConnectMultipleClients_MultipleThreads()
+ {
+ List<Task> tasks = new List<Task>();
+ for (int i = 0; i < 3; i++)
+ {
+ tasks.Add(Task.Run(() =>
+ {
+ var name = GetUniquePipeName();
+ using (var server = new NamedPipeServerStream(name, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.CurrentUserOnly))
+ {
+ using (var client = new NamedPipeClientStream(".", name, PipeDirection.InOut, PipeOptions.CurrentUserOnly))
+ {
+ // Should not fail to connect since both, the server and client have the same owner.
+ client.Connect();
+ }
+ }
+ }));
+ }
+
+ Task.WaitAll(tasks.ToArray());
+ }
+
+ [Theory]
+ [InlineData(PipeOptions.CurrentUserOnly)]
+ [InlineData(PipeOptions.None)]
+ public static void CreateMultipleConcurrentServers_ConnectMultipleClients(PipeOptions extraPipeOptions)
+ {
+ var pipeServers = new NamedPipeServerStream[5];
+ var pipeClients = new NamedPipeClientStream[pipeServers.Length];
+
+ try
+ {
+ string pipeName = GetUniquePipeName();
+ for (var i = 0; i < pipeServers.Length; i++)
+ {
+ pipeServers[i] = new NamedPipeServerStream(
+ pipeName,
+ PipeDirection.InOut,
+ NamedPipeServerStream.MaxAllowedServerInstances,
+ PipeTransmissionMode.Byte,
+ PipeOptions.Asynchronous | PipeOptions.WriteThrough | extraPipeOptions);
+
+ pipeClients[i] = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.Asynchronous | extraPipeOptions);
+ pipeClients[i].Connect(15_000);
+ }
+ }
+ finally
+ {
+ for (var i = 0; i < pipeServers.Length; i++)
+ {
+ pipeServers[i]?.Dispose();
+ pipeClients[i]?.Dispose();
+ }
+ }
+ }
+ }
+}
diff --git a/src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.RunAsClient.Unix.cs b/src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.RunAsClient.Unix.cs
index e998490e2f..fd3e9b62ad 100644
--- a/src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.RunAsClient.Unix.cs
+++ b/src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.RunAsClient.Unix.cs
@@ -31,7 +31,7 @@ namespace System.IO.Pipes.Tests
{
string pipeName = Path.GetRandomFileName();
uint pairID = (uint)(Math.Abs(new Random(5125123).Next()));
- RemoteInvoke(ServerConnectAsId, pipeName, pairID.ToString()).Dispose();
+ RemoteInvoke(new Func<string, string, int>(ServerConnectAsId), pipeName, pairID.ToString()).Dispose();
}
private static int ServerConnectAsId(string pipeName, string pairIDString)
@@ -39,7 +39,7 @@ namespace System.IO.Pipes.Tests
uint pairID = uint.Parse(pairIDString);
Assert.NotEqual(-1, seteuid(pairID));
using (var outbound = new NamedPipeServerStream(pipeName, PipeDirection.Out))
- using (var handle = RemoteInvoke(ClientConnectAsID, pipeName, pairIDString))
+ using (var handle = RemoteInvoke(new Func<string, string, int>(ClientConnectAsID), pipeName, pairIDString))
{
// Connect as the unpriveleged user, but RunAsClient as the superuser
outbound.WaitForConnection();
diff --git a/src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.UnixDomainSockets.cs b/src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.UnixDomainSockets.cs
new file mode 100644
index 0000000000..2d21107f9f
--- /dev/null
+++ b/src/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.UnixDomainSockets.cs
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Net.Sockets;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.IO.Pipes.Tests
+{
+ public class NamedPipeTest_UnixDomainSockets : NamedPipeTestBase
+ {
+ [Fact]
+ [PlatformSpecific(TestPlatforms.AnyUnix)]
+ public void NamedPipeServer_Connects_With_UnixDomainSocketEndPointClient()
+ {
+ string pipeName = Path.Combine("/tmp", "pipe-tests-corefx-" + Path.GetRandomFileName());
+ var endPoint = new UnixDomainSocketEndPoint(pipeName);
+
+ using (var pipeServer = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.CurrentUserOnly))
+ using (var sockectClient = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified))
+ {
+ sockectClient.Connect(endPoint);
+ Assert.True(File.Exists(pipeName));
+ }
+
+ Assert.False(File.Exists(pipeName));
+ }
+
+ [Fact]
+ [PlatformSpecific(TestPlatforms.AnyUnix)]
+ public async Task NamedPipeClient_Connects_With_UnixDomainSocketEndPointServer()
+ {
+ string pipeName = Path.Combine("/tmp", "pipe-tests-corefx-" + Path.GetRandomFileName());
+ var endPoint = new UnixDomainSocketEndPoint(pipeName);
+
+ using (var socketServer = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified))
+ using (var pipeClient = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.None))
+ {
+ socketServer.Bind(endPoint);
+ socketServer.Listen(1);
+
+ var pipeConnectTask = pipeClient.ConnectAsync(15_000);
+ using (Socket accepted = socketServer.Accept())
+ {
+ await pipeConnectTask;
+ Assert.True(File.Exists(pipeName));
+ }
+ }
+
+ Assert.True(File.Exists(pipeName));
+ try { File.Delete(pipeName); } catch { }
+ }
+ }
+}
diff --git a/src/System.IO.Pipes/tests/PipeTest.Read.netcoreapp.cs b/src/System.IO.Pipes/tests/PipeTest.Read.netcoreapp.cs
index ecaedc9c73..0b1bf32e1b 100644
--- a/src/System.IO.Pipes/tests/PipeTest.Read.netcoreapp.cs
+++ b/src/System.IO.Pipes/tests/PipeTest.Read.netcoreapp.cs
@@ -88,7 +88,7 @@ namespace System.IO.Pipes.Tests
byte[] sent = new byte[] { 123, 0, 5 };
byte[] received = new byte[] { 0, 0, 0 };
- Task write = pair.writeablePipe.WriteAsync(new ReadOnlyMemory<byte>(sent));
+ ValueTask write = pair.writeablePipe.WriteAsync(new ReadOnlyMemory<byte>(sent));
Assert.Equal(sent.Length, await pair.readablePipe.ReadAsync(new Memory<byte>(received, 0, sent.Length)));
Assert.Equal(sent, received);
await write;
@@ -112,7 +112,7 @@ namespace System.IO.Pipes.Tests
for (int iter = 0; iter < iterations; iter++)
{
rand.NextBytes(writeBuffer);
- Task writerTask = pair.writeablePipe.WriteAsync(new ReadOnlyMemory<byte>(writeBuffer), cancellationToken);
+ ValueTask writerTask = pair.writeablePipe.WriteAsync(new ReadOnlyMemory<byte>(writeBuffer), cancellationToken);
int totalRead = 0;
while (totalRead < writeBuffer.Length)
diff --git a/src/System.IO.Pipes/tests/System.IO.Pipes.Tests.csproj b/src/System.IO.Pipes/tests/System.IO.Pipes.Tests.csproj
index d9cd837ac6..a7b8ea1ff8 100644
--- a/src/System.IO.Pipes/tests/System.IO.Pipes.Tests.csproj
+++ b/src/System.IO.Pipes/tests/System.IO.Pipes.Tests.csproj
@@ -15,8 +15,6 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
<ItemGroup>
- <Compile Include="NamedPipeTests\NamedPipeTest.cs" />
- <Compile Include="PipeTest.cs" />
<Compile Include="AnonymousPipeTests\AnonymousPipeTest.CreateServer.cs" />
<Compile Include="AnonymousPipeTests\AnonymousPipeTest.CreateClient.cs" />
<Compile Include="AnonymousPipeTests\AnonymousPipeTest.CrossProcess.cs" />
@@ -24,6 +22,7 @@
<Compile Include="AnonymousPipeTests\AnonymousPipeTest.Read.cs" />
<Compile Include="AnonymousPipeTests\AnonymousPipeTest.Specific.cs" />
<Compile Include="AnonymousPipeTests\AnonymousPipeTest.Write.cs" />
+ <Compile Include="NamedPipeTests\NamedPipeTest.cs" />
<Compile Include="NamedPipeTests\NamedPipeTest.CreateServer.cs" />
<Compile Include="NamedPipeTests\NamedPipeTest.CreateClient.cs" />
<Compile Include="NamedPipeTests\NamedPipeTest.CrossProcess.cs" />
@@ -32,13 +31,24 @@
<Compile Include="NamedPipeTests\NamedPipeTest.Write.cs" />
<Compile Include="NamedPipeTests\NamedPipeTest.Specific.cs" />
<Compile Include="NamedPipeTests\NamedPipeTest.Simple.cs" />
- <Compile Include="PipeTest.Read.netcoreapp.cs" Condition="'$(TargetGroup)' == 'netcoreapp'" />
- <Compile Include="PipeTest.Write.netcoreapp.cs" Condition="'$(TargetGroup)' == 'netcoreapp'" />
+ <Compile Include="PipeTest.cs" />
<Compile Include="PipeTestBase.cs" />
<Compile Include="PipeTest.Read.cs" />
<Compile Include="PipeTest.Write.cs" />
<Compile Include="XunitAssemblyAttributes.cs" />
</ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp'">
+ <Compile Include="NamedPipeTests\NamedPipeTest.CurrentUserOnly.netcoreapp.cs" />
+ <Compile Include="PipeTest.Read.netcoreapp.cs" />
+ <Compile Include="PipeTest.Write.netcoreapp.cs" />
+ </ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp' and '$(TargetsWindows)' == 'true'">
+ <Compile Include="NamedPipeTests\NamedPipeTest.CurrentUserOnly.netcoreapp.Windows.cs" />
+ </ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp' and '$(TargetsUnix)' == 'true'">
+ <Compile Include="NamedPipeTests\NamedPipeTest.CurrentUserOnly.netcoreapp.Unix.cs" />
+ <Compile Include="NamedPipeTests\NamedPipeTest.UnixDomainSockets.cs" />
+ </ItemGroup>
<ItemGroup Condition="'$(TargetsWindows)' == 'true'">
<Compile Include="Interop.Windows.cs" />
<Compile Include="NamedPipeTests\NamedPipeTest.RunAsClient.Windows.cs" />
@@ -55,4 +65,4 @@
</ProjectReference>
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.IO.Ports/pkg/System.IO.Ports.pkgproj b/src/System.IO.Ports/pkg/System.IO.Ports.pkgproj
index 44d2950271..a9ddafcac1 100644
--- a/src/System.IO.Ports/pkg/System.IO.Ports.pkgproj
+++ b/src/System.IO.Ports/pkg/System.IO.Ports.pkgproj
@@ -6,9 +6,9 @@
<SupportedFramework>net461;netcoreapp2.0;$(AllXamarinFrameworks);$(UAPvNextTFM)</SupportedFramework>
</ProjectReference>
<File Include="$(PlaceHolderFile)">
- <TargetPath>runtimes/win/lib/$(UAPvNextTFM)</TargetPath>
+ <TargetPath>runtimes/win/lib/uap10.0.16299</TargetPath>
</File>
- <InboxOnTargetFramework Include="$(UAPvNextTFM)" />
+ <InboxOnTargetFramework Include="uap10.0.16299" />
<ProjectReference Include="..\src\System.IO.Ports.csproj" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
diff --git a/src/System.IO.Ports/src/System.IO.Ports.csproj b/src/System.IO.Ports/src/System.IO.Ports.csproj
index c5f4f027aa..1a710accc0 100644
--- a/src/System.IO.Ports/src/System.IO.Ports.csproj
+++ b/src/System.IO.Ports/src/System.IO.Ports.csproj
@@ -6,6 +6,7 @@
<ProjectGuid>{187503F4-BEF9-4369-A1B2-E3DC5D564E4E}</ProjectGuid>
<IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'netfx'">true</IsPartialFacadeAssembly>
<GeneratePlatformNotSupportedAssemblyMessage Condition="'$(TargetGroup)' == 'netstandard' AND '$(TargetsWindows)' != 'true'">SR.PlatformNotSupported_IOPorts</GeneratePlatformNotSupportedAssemblyMessage>
+ <DefineConstants>$(DefineConstants);NOSPAN</DefineConstants>
<IncludeDllSafeSearchPathAttribute>true</IncludeDllSafeSearchPathAttribute>
</PropertyGroup>
<!-- Default configurations to help VS understand the options -->
diff --git a/src/System.IO/tests/BufferedStream/BufferedStreamTests.netcoreapp.cs b/src/System.IO/tests/BufferedStream/BufferedStreamTests.netcoreapp.cs
index 7ead9aa31e..51a1be459f 100644
--- a/src/System.IO/tests/BufferedStream/BufferedStreamTests.netcoreapp.cs
+++ b/src/System.IO/tests/BufferedStream/BufferedStreamTests.netcoreapp.cs
@@ -83,7 +83,7 @@ namespace System.IO.Tests
using (var bs = new BufferedStream(new MemoryStream()))
{
Assert.Equal(TaskStatus.Canceled, bs.ReadAsync(new byte[1], new CancellationToken(true)).AsTask().Status);
- Assert.Equal(TaskStatus.Canceled, bs.WriteAsync(new byte[1], new CancellationToken(true)).Status);
+ Assert.Equal(TaskStatus.Canceled, bs.WriteAsync(new byte[1], new CancellationToken(true)).AsTask().Status);
}
}
}
diff --git a/src/System.IO/tests/StringWriter/StringWriterTests.cs b/src/System.IO/tests/StringWriter/StringWriterTests.cs
index 4155c9d0c3..34a89b0f68 100644
--- a/src/System.IO/tests/StringWriter/StringWriterTests.cs
+++ b/src/System.IO/tests/StringWriter/StringWriterTests.cs
@@ -4,6 +4,7 @@
using Xunit;
using System;
+using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
@@ -11,7 +12,7 @@ using System.Threading.Tasks;
namespace System.IO.Tests
{
- public partial class StringWriterTests
+ public partial class StringWriterTests : RemoteExecutorTestBase
{
static int[] iArrInvalidValues = new int[] { -1, -2, -100, -1000, -10000, -100000, -1000000, -10000000, -100000000, -1000000000, int.MinValue, short.MinValue };
static int[] iArrLargeValues = new int[] { int.MaxValue, int.MaxValue - 1, int.MaxValue / 2, int.MaxValue / 10, int.MaxValue / 100 };
@@ -291,10 +292,9 @@ namespace System.IO.Tests
[Fact]
public static void TestWriteMisc()
{
- CultureInfo old = CultureInfo.CurrentCulture;
- CultureInfo.CurrentCulture = new CultureInfo("en-US"); // floating-point formatting comparison depends on culture
- try
+ RemoteInvoke(() =>
{
+ CultureInfo.CurrentCulture = new CultureInfo("en-US"); // floating-point formatting comparison depends on culture
var sw = new StringWriter();
sw.Write(true);
@@ -308,11 +308,7 @@ namespace System.IO.Tests
sw.Write((ulong)ulong.MaxValue);
Assert.Equal("Truea1234.013452342.0123456-92233720368547758081234.5429496729518446744073709551615", sw.ToString());
- }
- finally
- {
- CultureInfo.CurrentCulture = old;
- }
+ }).Dispose();
}
[Fact]
@@ -326,10 +322,9 @@ namespace System.IO.Tests
[Fact]
public static void TestWriteLineMisc()
{
- CultureInfo old = CultureInfo.CurrentCulture;
- CultureInfo.CurrentCulture = new CultureInfo("en-US"); // floating-point formatting comparison depends on culture
- try
+ RemoteInvoke(() =>
{
+ CultureInfo.CurrentCulture = new CultureInfo("en-US"); // floating-point formatting comparison depends on culture
var sw = new StringWriter();
sw.WriteLine((bool)false);
sw.WriteLine((char)'B');
@@ -342,11 +337,7 @@ namespace System.IO.Tests
Assert.Equal(
string.Format("False{0}B{0}987{0}875634{0}1.23457{0}45634563{0}18446744073709551615{0}", Environment.NewLine),
sw.ToString());
- }
- finally
- {
- CultureInfo.CurrentCulture = old;
- }
+ }).Dispose();
}
[Fact]
diff --git a/src/System.IO/tests/System.IO.Tests.csproj b/src/System.IO/tests/System.IO.Tests.csproj
index 7a2412da95..52cf08256d 100644
--- a/src/System.IO/tests/System.IO.Tests.csproj
+++ b/src/System.IO/tests/System.IO.Tests.csproj
@@ -78,6 +78,12 @@
<Compile Include="TextWriter\TextWriterTests.netcoreapp.cs" Condition="'$(TargetGroup)' == 'netcoreapp'" />
</ItemGroup>
<ItemGroup>
+ <ProjectReference Include="$(CommonTestPath)\System\Diagnostics\RemoteExecutorConsoleApp\RemoteExecutorConsoleApp.csproj">
+ <Project>{69e46a6f-9966-45a5-8945-2559fe337827}</Project>
+ <Name>RemoteExecutorConsoleApp</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
<EmbeddedResource Include="Resources\$(AssemblyName).rd.xml" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
diff --git a/src/System.Json/src/System.Json.csproj b/src/System.Json/src/System.Json.csproj
index 4f12ea9374..3f4919b253 100644
--- a/src/System.Json/src/System.Json.csproj
+++ b/src/System.Json/src/System.Json.csproj
@@ -31,6 +31,7 @@
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.Extensions" />
<Reference Include="System.Text.Encoding" />
+ <Reference Include="System.Text.Encoding.Extensions" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.Json/src/System/Json/JsonObject.cs b/src/System.Json/src/System/Json/JsonObject.cs
index 465c62f643..d228c7f366 100644
--- a/src/System.Json/src/System/Json/JsonObject.cs
+++ b/src/System.Json/src/System/Json/JsonObject.cs
@@ -114,35 +114,7 @@ namespace System.Json
public override void Save(Stream stream)
{
- if (stream == null)
- {
- throw new ArgumentNullException(nameof(stream));
- }
-
- stream.WriteByte((byte)'{');
-
- foreach (JsonPair pair in _map)
- {
- stream.WriteByte((byte)'"');
- byte[] bytes = Encoding.UTF8.GetBytes(EscapeString(pair.Key));
- stream.Write(bytes, 0, bytes.Length);
- stream.WriteByte((byte)'"');
- stream.WriteByte((byte)',');
- stream.WriteByte((byte)' ');
- if (pair.Value == null)
- {
- stream.WriteByte((byte)'n');
- stream.WriteByte((byte)'u');
- stream.WriteByte((byte)'l');
- stream.WriteByte((byte)'l');
- }
- else
- {
- pair.Value.Save(stream);
- }
- }
-
- stream.WriteByte((byte)'}');
+ base.Save(stream);
}
public bool TryGetValue(string key, out JsonValue value) => _map.TryGetValue(key, out value);
diff --git a/src/System.Json/src/System/Json/JsonValue.cs b/src/System.Json/src/System/Json/JsonValue.cs
index 3204527da6..4fdae75c4d 100644
--- a/src/System.Json/src/System/Json/JsonValue.cs
+++ b/src/System.Json/src/System/Json/JsonValue.cs
@@ -15,6 +15,8 @@ namespace System.Json
{
public abstract class JsonValue : IEnumerable
{
+ private static readonly UTF8Encoding s_encoding = new UTF8Encoding(false, true);
+
public static JsonValue Load(Stream stream)
{
if (stream == null)
@@ -122,7 +124,10 @@ namespace System.Json
throw new ArgumentNullException(nameof(stream));
}
- Save(new StreamWriter(stream));
+ using (StreamWriter writer = new StreamWriter(stream, s_encoding, 1024, true))
+ {
+ Save(writer);
+ }
}
public virtual void Save(TextWriter textWriter)
diff --git a/src/System.Json/tests/JsonObjectTests.cs b/src/System.Json/tests/JsonObjectTests.cs
index 3849144a0f..5a39fcc744 100644
--- a/src/System.Json/tests/JsonObjectTests.cs
+++ b/src/System.Json/tests/JsonObjectTests.cs
@@ -270,7 +270,7 @@ namespace System.Json.Tests
{
obj.Save(stream);
string result = Encoding.UTF8.GetString(stream.ToArray());
- Assert.Equal("{\"key\", true\"key2\", null}", result);
+ Assert.Equal("{\"key\": true, \"key2\": null}", result);
}
}
diff --git a/src/System.Json/tests/JsonValueTests.cs b/src/System.Json/tests/JsonValueTests.cs
index 34fa1d42d5..221a2ade70 100644
--- a/src/System.Json/tests/JsonValueTests.cs
+++ b/src/System.Json/tests/JsonValueTests.cs
@@ -432,7 +432,22 @@ namespace System.Json.Tests
using (MemoryStream stream = new MemoryStream())
{
value.Save(stream);
- Assert.Empty(stream.ToArray());
+ string json = Encoding.UTF8.GetString(stream.ToArray());
+ Assert.True(stream.CanWrite);
+ Assert.Equal("Hello", json);
+ }
+ }
+
+ [Fact]
+ public void Save_TextWriter()
+ {
+ JsonSubValue value = new JsonSubValue();
+
+ using (StringWriter writer = new StringWriter())
+ {
+ value.Save(writer);
+ string json = writer.ToString();
+ Assert.Equal("Hello", json);
}
}
diff --git a/src/System.Linq.Expressions/src/System.Linq.Expressions.csproj b/src/System.Linq.Expressions/src/System.Linq.Expressions.csproj
index 46f8cdee0b..7259a0bbe5 100644
--- a/src/System.Linq.Expressions/src/System.Linq.Expressions.csproj
+++ b/src/System.Linq.Expressions/src/System.Linq.Expressions.csproj
@@ -13,10 +13,10 @@
<DefineConstants Condition=" '$(IsInterpreting)' != 'true' ">$(DefineConstants);FEATURE_COMPILE</DefineConstants>
<DefineConstants Condition=" '$(FeatureInterpret)' == 'true' ">$(DefineConstants);FEATURE_INTERPRET</DefineConstants>
</PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uapaot-Windows_NT-Debug|AnyCPU'" />
@@ -41,12 +41,6 @@
<Compile Include="$(CommonPath)\System\Collections\Generic\ArrayBuilder.cs">
<Link>Common\System\Collections\Generic\ArrayBuilder.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Collections\Generic\EnumerableHelpers.cs">
- <Link>Common\System\Collections\Generic\EnumerableHelpers.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\System\Collections\Generic\LargeArrayBuilder.cs">
- <Link>Common\System\Collections\Generic\LargeArrayBuilder.cs</Link>
- </Compile>
<Compile Include="System\Dynamic\Utils\CacheDict.cs" />
<Compile Include="System\Dynamic\Utils\ContractUtils.cs" />
<Compile Include="System\Dynamic\Utils\ExpressionUtils.cs" />
diff --git a/src/System.Linq.Expressions/src/System/Dynamic/DynamicMetaObject.cs b/src/System.Linq.Expressions/src/System/Dynamic/DynamicMetaObject.cs
index 81d6fe8901..a583e50461 100644
--- a/src/System.Linq.Expressions/src/System/Dynamic/DynamicMetaObject.cs
+++ b/src/System.Linq.Expressions/src/System/Dynamic/DynamicMetaObject.cs
@@ -43,10 +43,13 @@ namespace System.Dynamic
public DynamicMetaObject(Expression expression, BindingRestrictions restrictions, object value)
: this(expression, restrictions)
{
- Value = value;
- HasValue = true;
+ _value = value;
}
+ // having sentinel value means having no value. (this way we do not need a separate hasValue field)
+ private static readonly object s_noValueSentinel = new object();
+ private readonly object _value = s_noValueSentinel;
+
/// <summary>
/// The expression representing the <see cref="DynamicMetaObject"/> during the dynamic binding process.
/// </summary>
@@ -60,12 +63,12 @@ namespace System.Dynamic
/// <summary>
/// The runtime value represented by this <see cref="DynamicMetaObject"/>.
/// </summary>
- public object Value { get; }
+ public object Value => HasValue ? _value : null;
/// <summary>
/// Gets a value indicating whether the <see cref="DynamicMetaObject"/> has the runtime value.
/// </summary>
- public bool HasValue { get; }
+ public bool HasValue => _value != s_noValueSentinel;
/// <summary>
/// Gets the <see cref="Type"/> of the runtime value or null if the <see cref="DynamicMetaObject"/> has no value associated with it.
diff --git a/src/System.Linq.Expressions/src/System/Dynamic/UpdateDelegates.Generated.cs b/src/System.Linq.Expressions/src/System/Dynamic/UpdateDelegates.Generated.cs
index 930539e27b..8f158b24b5 100644
--- a/src/System.Linq.Expressions/src/System/Dynamic/UpdateDelegates.Generated.cs
+++ b/src/System.Linq.Expressions/src/System/Dynamic/UpdateDelegates.Generated.cs
@@ -24,7 +24,7 @@ namespace System.Dynamic
//
// Create matchmaker and its site. We'll need them regardless.
//
- site = CallSiteOps.CreateMatchmaker(@this);
+ site = @this.GetMatchmaker();
//
// Level 1 cache lookup
@@ -48,6 +48,7 @@ namespace System.Dynamic
if (CallSiteOps.GetMatch(site))
{
CallSiteOps.UpdateRules(@this, i);
+ @this.ReleaseMatchmaker(site);
return result;
}
@@ -82,6 +83,7 @@ namespace System.Dynamic
result = rule(site, arg0);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return result;
}
}
@@ -123,6 +125,7 @@ namespace System.Dynamic
result = rule(site, arg0);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return result;
}
}
@@ -167,7 +170,7 @@ namespace System.Dynamic
//
// Create matchmaker and its site. We'll need them regardless.
//
- site = CallSiteOps.CreateMatchmaker(@this);
+ site = @this.GetMatchmaker();
//
// Level 1 cache lookup
@@ -191,6 +194,7 @@ namespace System.Dynamic
if (CallSiteOps.GetMatch(site))
{
CallSiteOps.UpdateRules(@this, i);
+ @this.ReleaseMatchmaker(site);
return result;
}
@@ -225,6 +229,7 @@ namespace System.Dynamic
result = rule(site, arg0, arg1);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return result;
}
}
@@ -266,6 +271,7 @@ namespace System.Dynamic
result = rule(site, arg0, arg1);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return result;
}
}
@@ -310,7 +316,7 @@ namespace System.Dynamic
//
// Create matchmaker and its site. We'll need them regardless.
//
- site = CallSiteOps.CreateMatchmaker(@this);
+ site = @this.GetMatchmaker();
//
// Level 1 cache lookup
@@ -334,6 +340,7 @@ namespace System.Dynamic
if (CallSiteOps.GetMatch(site))
{
CallSiteOps.UpdateRules(@this, i);
+ @this.ReleaseMatchmaker(site);
return result;
}
@@ -368,6 +375,7 @@ namespace System.Dynamic
result = rule(site, arg0, arg1, arg2);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return result;
}
}
@@ -409,6 +417,7 @@ namespace System.Dynamic
result = rule(site, arg0, arg1, arg2);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return result;
}
}
@@ -453,7 +462,7 @@ namespace System.Dynamic
//
// Create matchmaker and its site. We'll need them regardless.
//
- site = CallSiteOps.CreateMatchmaker(@this);
+ site = @this.GetMatchmaker();
//
// Level 1 cache lookup
@@ -477,6 +486,7 @@ namespace System.Dynamic
if (CallSiteOps.GetMatch(site))
{
CallSiteOps.UpdateRules(@this, i);
+ @this.ReleaseMatchmaker(site);
return result;
}
@@ -511,6 +521,7 @@ namespace System.Dynamic
result = rule(site, arg0, arg1, arg2, arg3);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return result;
}
}
@@ -552,6 +563,7 @@ namespace System.Dynamic
result = rule(site, arg0, arg1, arg2, arg3);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return result;
}
}
@@ -596,7 +608,7 @@ namespace System.Dynamic
//
// Create matchmaker and its site. We'll need them regardless.
//
- site = CallSiteOps.CreateMatchmaker(@this);
+ site = @this.GetMatchmaker();
//
// Level 1 cache lookup
@@ -620,6 +632,7 @@ namespace System.Dynamic
if (CallSiteOps.GetMatch(site))
{
CallSiteOps.UpdateRules(@this, i);
+ @this.ReleaseMatchmaker(site);
return result;
}
@@ -654,6 +667,7 @@ namespace System.Dynamic
result = rule(site, arg0, arg1, arg2, arg3, arg4);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return result;
}
}
@@ -695,6 +709,7 @@ namespace System.Dynamic
result = rule(site, arg0, arg1, arg2, arg3, arg4);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return result;
}
}
@@ -739,7 +754,7 @@ namespace System.Dynamic
//
// Create matchmaker and its site. We'll need them regardless.
//
- site = CallSiteOps.CreateMatchmaker(@this);
+ site = @this.GetMatchmaker();
//
// Level 1 cache lookup
@@ -763,6 +778,7 @@ namespace System.Dynamic
if (CallSiteOps.GetMatch(site))
{
CallSiteOps.UpdateRules(@this, i);
+ @this.ReleaseMatchmaker(site);
return result;
}
@@ -797,6 +813,7 @@ namespace System.Dynamic
result = rule(site, arg0, arg1, arg2, arg3, arg4, arg5);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return result;
}
}
@@ -838,6 +855,7 @@ namespace System.Dynamic
result = rule(site, arg0, arg1, arg2, arg3, arg4, arg5);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return result;
}
}
@@ -882,7 +900,7 @@ namespace System.Dynamic
//
// Create matchmaker and its site. We'll need them regardless.
//
- site = CallSiteOps.CreateMatchmaker(@this);
+ site = @this.GetMatchmaker();
//
// Level 1 cache lookup
@@ -906,6 +924,7 @@ namespace System.Dynamic
if (CallSiteOps.GetMatch(site))
{
CallSiteOps.UpdateRules(@this, i);
+ @this.ReleaseMatchmaker(site);
return result;
}
@@ -940,6 +959,7 @@ namespace System.Dynamic
result = rule(site, arg0, arg1, arg2, arg3, arg4, arg5, arg6);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return result;
}
}
@@ -981,6 +1001,7 @@ namespace System.Dynamic
result = rule(site, arg0, arg1, arg2, arg3, arg4, arg5, arg6);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return result;
}
}
@@ -1025,7 +1046,7 @@ namespace System.Dynamic
//
// Create matchmaker and its site. We'll need them regardless.
//
- site = CallSiteOps.CreateMatchmaker(@this);
+ site = @this.GetMatchmaker();
//
// Level 1 cache lookup
@@ -1049,6 +1070,7 @@ namespace System.Dynamic
if (CallSiteOps.GetMatch(site))
{
CallSiteOps.UpdateRules(@this, i);
+ @this.ReleaseMatchmaker(site);
return result;
}
@@ -1083,6 +1105,7 @@ namespace System.Dynamic
result = rule(site, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return result;
}
}
@@ -1124,6 +1147,7 @@ namespace System.Dynamic
result = rule(site, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return result;
}
}
@@ -1168,7 +1192,7 @@ namespace System.Dynamic
//
// Create matchmaker and its site. We'll need them regardless.
//
- site = CallSiteOps.CreateMatchmaker(@this);
+ site = @this.GetMatchmaker();
//
// Level 1 cache lookup
@@ -1192,6 +1216,7 @@ namespace System.Dynamic
if (CallSiteOps.GetMatch(site))
{
CallSiteOps.UpdateRules(@this, i);
+ @this.ReleaseMatchmaker(site);
return result;
}
@@ -1226,6 +1251,7 @@ namespace System.Dynamic
result = rule(site, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return result;
}
}
@@ -1267,6 +1293,7 @@ namespace System.Dynamic
result = rule(site, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return result;
}
}
@@ -1311,7 +1338,7 @@ namespace System.Dynamic
//
// Create matchmaker and its site. We'll need them regardless.
//
- site = CallSiteOps.CreateMatchmaker(@this);
+ site = @this.GetMatchmaker();
//
// Level 1 cache lookup
@@ -1335,6 +1362,7 @@ namespace System.Dynamic
if (CallSiteOps.GetMatch(site))
{
CallSiteOps.UpdateRules(@this, i);
+ @this.ReleaseMatchmaker(site);
return result;
}
@@ -1369,6 +1397,7 @@ namespace System.Dynamic
result = rule(site, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return result;
}
}
@@ -1410,6 +1439,7 @@ namespace System.Dynamic
result = rule(site, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return result;
}
}
@@ -1453,7 +1483,7 @@ namespace System.Dynamic
//
// Create matchmaker and its site. We'll need them regardless.
//
- site = CallSiteOps.CreateMatchmaker(@this);
+ site = @this.GetMatchmaker();
//
// Level 1 cache lookup
@@ -1477,6 +1507,7 @@ namespace System.Dynamic
if (CallSiteOps.GetMatch(site))
{
CallSiteOps.UpdateRules(@this, i);
+ @this.ReleaseMatchmaker(site);
return;
}
@@ -1511,6 +1542,7 @@ namespace System.Dynamic
rule(site, arg0);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return;
}
}
@@ -1552,6 +1584,7 @@ namespace System.Dynamic
rule(site, arg0);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return;
}
}
@@ -1595,7 +1628,7 @@ namespace System.Dynamic
//
// Create matchmaker and its site. We'll need them regardless.
//
- site = CallSiteOps.CreateMatchmaker(@this);
+ site = @this.GetMatchmaker();
//
// Level 1 cache lookup
@@ -1619,6 +1652,7 @@ namespace System.Dynamic
if (CallSiteOps.GetMatch(site))
{
CallSiteOps.UpdateRules(@this, i);
+ @this.ReleaseMatchmaker(site);
return;
}
@@ -1653,6 +1687,7 @@ namespace System.Dynamic
rule(site, arg0, arg1);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return;
}
}
@@ -1694,6 +1729,7 @@ namespace System.Dynamic
rule(site, arg0, arg1);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return;
}
}
@@ -1737,7 +1773,7 @@ namespace System.Dynamic
//
// Create matchmaker and its site. We'll need them regardless.
//
- site = CallSiteOps.CreateMatchmaker(@this);
+ site = @this.GetMatchmaker();
//
// Level 1 cache lookup
@@ -1761,6 +1797,7 @@ namespace System.Dynamic
if (CallSiteOps.GetMatch(site))
{
CallSiteOps.UpdateRules(@this, i);
+ @this.ReleaseMatchmaker(site);
return;
}
@@ -1795,6 +1832,7 @@ namespace System.Dynamic
rule(site, arg0, arg1, arg2);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return;
}
}
@@ -1836,6 +1874,7 @@ namespace System.Dynamic
rule(site, arg0, arg1, arg2);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return;
}
}
@@ -1879,7 +1918,7 @@ namespace System.Dynamic
//
// Create matchmaker and its site. We'll need them regardless.
//
- site = CallSiteOps.CreateMatchmaker(@this);
+ site = @this.GetMatchmaker();
//
// Level 1 cache lookup
@@ -1903,6 +1942,7 @@ namespace System.Dynamic
if (CallSiteOps.GetMatch(site))
{
CallSiteOps.UpdateRules(@this, i);
+ @this.ReleaseMatchmaker(site);
return;
}
@@ -1937,6 +1977,7 @@ namespace System.Dynamic
rule(site, arg0, arg1, arg2, arg3);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return;
}
}
@@ -1978,6 +2019,7 @@ namespace System.Dynamic
rule(site, arg0, arg1, arg2, arg3);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return;
}
}
@@ -2021,7 +2063,7 @@ namespace System.Dynamic
//
// Create matchmaker and its site. We'll need them regardless.
//
- site = CallSiteOps.CreateMatchmaker(@this);
+ site = @this.GetMatchmaker();
//
// Level 1 cache lookup
@@ -2045,6 +2087,7 @@ namespace System.Dynamic
if (CallSiteOps.GetMatch(site))
{
CallSiteOps.UpdateRules(@this, i);
+ @this.ReleaseMatchmaker(site);
return;
}
@@ -2079,6 +2122,7 @@ namespace System.Dynamic
rule(site, arg0, arg1, arg2, arg3, arg4);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return;
}
}
@@ -2120,6 +2164,7 @@ namespace System.Dynamic
rule(site, arg0, arg1, arg2, arg3, arg4);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return;
}
}
@@ -2163,7 +2208,7 @@ namespace System.Dynamic
//
// Create matchmaker and its site. We'll need them regardless.
//
- site = CallSiteOps.CreateMatchmaker(@this);
+ site = @this.GetMatchmaker();
//
// Level 1 cache lookup
@@ -2187,6 +2232,7 @@ namespace System.Dynamic
if (CallSiteOps.GetMatch(site))
{
CallSiteOps.UpdateRules(@this, i);
+ @this.ReleaseMatchmaker(site);
return;
}
@@ -2221,6 +2267,7 @@ namespace System.Dynamic
rule(site, arg0, arg1, arg2, arg3, arg4, arg5);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return;
}
}
@@ -2262,6 +2309,7 @@ namespace System.Dynamic
rule(site, arg0, arg1, arg2, arg3, arg4, arg5);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return;
}
}
@@ -2305,7 +2353,7 @@ namespace System.Dynamic
//
// Create matchmaker and its site. We'll need them regardless.
//
- site = CallSiteOps.CreateMatchmaker(@this);
+ site = @this.GetMatchmaker();
//
// Level 1 cache lookup
@@ -2329,6 +2377,7 @@ namespace System.Dynamic
if (CallSiteOps.GetMatch(site))
{
CallSiteOps.UpdateRules(@this, i);
+ @this.ReleaseMatchmaker(site);
return;
}
@@ -2363,6 +2412,7 @@ namespace System.Dynamic
rule(site, arg0, arg1, arg2, arg3, arg4, arg5, arg6);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return;
}
}
@@ -2404,6 +2454,7 @@ namespace System.Dynamic
rule(site, arg0, arg1, arg2, arg3, arg4, arg5, arg6);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return;
}
}
@@ -2447,7 +2498,7 @@ namespace System.Dynamic
//
// Create matchmaker and its site. We'll need them regardless.
//
- site = CallSiteOps.CreateMatchmaker(@this);
+ site = @this.GetMatchmaker();
//
// Level 1 cache lookup
@@ -2471,6 +2522,7 @@ namespace System.Dynamic
if (CallSiteOps.GetMatch(site))
{
CallSiteOps.UpdateRules(@this, i);
+ @this.ReleaseMatchmaker(site);
return;
}
@@ -2505,6 +2557,7 @@ namespace System.Dynamic
rule(site, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return;
}
}
@@ -2546,6 +2599,7 @@ namespace System.Dynamic
rule(site, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return;
}
}
@@ -2589,7 +2643,7 @@ namespace System.Dynamic
//
// Create matchmaker and its site. We'll need them regardless.
//
- site = CallSiteOps.CreateMatchmaker(@this);
+ site = @this.GetMatchmaker();
//
// Level 1 cache lookup
@@ -2613,6 +2667,7 @@ namespace System.Dynamic
if (CallSiteOps.GetMatch(site))
{
CallSiteOps.UpdateRules(@this, i);
+ @this.ReleaseMatchmaker(site);
return;
}
@@ -2647,6 +2702,7 @@ namespace System.Dynamic
rule(site, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return;
}
}
@@ -2688,6 +2744,7 @@ namespace System.Dynamic
rule(site, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return;
}
}
@@ -2731,7 +2788,7 @@ namespace System.Dynamic
//
// Create matchmaker and its site. We'll need them regardless.
//
- site = CallSiteOps.CreateMatchmaker(@this);
+ site = @this.GetMatchmaker();
//
// Level 1 cache lookup
@@ -2755,6 +2812,7 @@ namespace System.Dynamic
if (CallSiteOps.GetMatch(site))
{
CallSiteOps.UpdateRules(@this, i);
+ @this.ReleaseMatchmaker(site);
return;
}
@@ -2789,6 +2847,7 @@ namespace System.Dynamic
rule(site, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return;
}
}
@@ -2830,6 +2889,7 @@ namespace System.Dynamic
rule(site, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return;
}
}
diff --git a/src/System.Linq.Expressions/src/System/Dynamic/UpdateDelegates.Generated.tt b/src/System.Linq.Expressions/src/System/Dynamic/UpdateDelegates.Generated.tt
index c7c6b5da45..7a1ab2161c 100644
--- a/src/System.Linq.Expressions/src/System/Dynamic/UpdateDelegates.Generated.tt
+++ b/src/System.Linq.Expressions/src/System/Dynamic/UpdateDelegates.Generated.tt
@@ -38,7 +38,7 @@ for (int i = 1; i <= 10; i++)
//
// Create matchmaker and its site. We'll need them regardless.
//
- site = CallSiteOps.CreateMatchmaker(@this);
+ site = @this.GetMatchmaker();
//
// Level 1 cache lookup
@@ -62,6 +62,7 @@ for (int i = 1; i <= 10; i++)
if (CallSiteOps.GetMatch(site))
{
CallSiteOps.UpdateRules(@this, i);
+ @this.ReleaseMatchmaker(site);
return result;
}
@@ -96,6 +97,7 @@ for (int i = 1; i <= 10; i++)
result = rule(<#=ruleInvocationArguments#>);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return result;
}
}
@@ -137,6 +139,7 @@ for (int i = 1; i <= 10; i++)
result = rule(<#=ruleInvocationArguments#>);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return result;
}
}
@@ -191,7 +194,7 @@ for (int i = 1; i <= 10; i++)
//
// Create matchmaker and its site. We'll need them regardless.
//
- site = CallSiteOps.CreateMatchmaker(@this);
+ site = @this.GetMatchmaker();
//
// Level 1 cache lookup
@@ -215,6 +218,7 @@ for (int i = 1; i <= 10; i++)
if (CallSiteOps.GetMatch(site))
{
CallSiteOps.UpdateRules(@this, i);
+ @this.ReleaseMatchmaker(site);
return;
}
@@ -249,6 +253,7 @@ for (int i = 1; i <= 10; i++)
rule(<#=ruleInvocationArguments#>);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return;
}
}
@@ -290,6 +295,7 @@ for (int i = 1; i <= 10; i++)
rule(<#=ruleInvocationArguments#>);
if (CallSiteOps.GetMatch(site))
{
+ @this.ReleaseMatchmaker(site);
return;
}
}
diff --git a/src/System.Linq.Expressions/src/System/Dynamic/Utils/CollectionExtensions.cs b/src/System.Linq.Expressions/src/System/Dynamic/Utils/CollectionExtensions.cs
index 701809b06b..af8ad7557a 100644
--- a/src/System.Linq.Expressions/src/System/Dynamic/Utils/CollectionExtensions.cs
+++ b/src/System.Linq.Expressions/src/System/Dynamic/Utils/CollectionExtensions.cs
@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
+using System.Linq;
using System.Runtime.CompilerServices;
namespace System.Dynamic.Utils
@@ -74,7 +75,7 @@ namespace System.Dynamic.Utils
return builder.ToReadOnlyCollection();
}
- T[] array = EnumerableHelpers.ToArray(enumerable);
+ T[] array = enumerable.ToArray();
return array.Length == 0 ?
EmptyReadOnlyCollection<T>.Instance :
new TrueReadOnlyCollection<T>(array);
diff --git a/src/System.Linq.Expressions/src/System/Linq/Expressions/BinaryExpression.cs b/src/System.Linq.Expressions/src/System/Linq/Expressions/BinaryExpression.cs
index 60d45b933b..87a7ed9e4b 100644
--- a/src/System.Linq.Expressions/src/System/Linq/Expressions/BinaryExpression.cs
+++ b/src/System.Linq.Expressions/src/System/Linq/Expressions/BinaryExpression.cs
@@ -2787,12 +2787,34 @@ namespace System.Linq.Expressions
ExpressionUtils.RequiresCanRead(right, nameof(right));
if (method == null)
{
- method = Math_Pow_Double_Double;
- if (method == null)
+ if (left.Type == right.Type && left.Type.IsArithmetic())
+ {
+ method = Math_Pow_Double_Double;
+ Debug.Assert(method != null);
+ }
+ else
{
- throw Error.BinaryOperatorNotDefined(ExpressionType.Power, left.Type, right.Type);
+ // VB uses op_Exponent, F# uses op_Exponentiation. This inconsistency is unfortunate, but we can
+ // test for either.
+ string name = "op_Exponent";
+ BinaryExpression b = GetUserDefinedBinaryOperator(ExpressionType.Power, name, left, right, liftToNull: true);
+ if (b == null)
+ {
+ name = "op_Exponentiation";
+ b = GetUserDefinedBinaryOperator(ExpressionType.Power, name, left, right, liftToNull: true);
+ if (b == null)
+ {
+ throw Error.BinaryOperatorNotDefined(ExpressionType.Power, left.Type, right.Type);
+ }
+ }
+
+ ParameterInfo[] pis = b.Method.GetParametersCached();
+ ValidateParamswithOperandsOrThrow(pis[0].ParameterType, left.Type, ExpressionType.Power, name);
+ ValidateParamswithOperandsOrThrow(pis[1].ParameterType, right.Type, ExpressionType.Power, name);
+ return b;
}
}
+
return GetMethodBasedBinaryOperator(ExpressionType.Power, left, right, method, liftToNull: true);
}
diff --git a/src/System.Linq.Expressions/src/System/Runtime/CompilerServices/CallSite.cs b/src/System.Linq.Expressions/src/System/Runtime/CompilerServices/CallSite.cs
index ad42af2882..5ad8d72026 100644
--- a/src/System.Linq.Expressions/src/System/Runtime/CompilerServices/CallSite.cs
+++ b/src/System.Linq.Expressions/src/System/Runtime/CompilerServices/CallSite.cs
@@ -8,6 +8,7 @@ using System.Dynamic;
using System.Dynamic.Utils;
using System.Linq.Expressions;
using System.Reflection;
+using System.Threading;
using static System.Linq.Expressions.CachedReflectionInfo;
namespace System.Runtime.CompilerServices
@@ -149,6 +150,11 @@ namespace System.Runtime.CompilerServices
/// </summary>
internal T[] Rules;
+ /// <summary>
+ /// an instance of matchmaker site to opportunistically reuse when site is polymorphic
+ /// </summary>
+ internal CallSite _cachedMatchmaker;
+
// Cached update delegate for all sites with a given T
private static T s_cachedUpdate;
@@ -172,6 +178,30 @@ namespace System.Runtime.CompilerServices
return new CallSite<T>();
}
+ internal CallSite GetMatchmaker()
+ {
+ // check if we have a cached matchmaker and attempt to atomically grab it.
+ var matchmaker = _cachedMatchmaker;
+ if (matchmaker != null)
+ {
+ matchmaker = Interlocked.Exchange(ref _cachedMatchmaker, null);
+ Debug.Assert(matchmaker?._match != false, "cached site should be set up for matchmaking");
+ }
+
+ return matchmaker ?? new CallSite<T>() { _match = true };
+ }
+
+ internal void ReleaseMatchmaker(CallSite matchMaker)
+ {
+ // If "Rules" has not been created, this is the first (and likely the only) Update of the site.
+ // 90% sites stay monomorphic and will never need a matchmaker again.
+ // Otherwise store the matchmaker for the future use.
+ if (Rules != null)
+ {
+ _cachedMatchmaker = matchMaker;
+ }
+ }
+
/// <summary>
/// Creates an instance of the dynamic call site, initialized with the binder responsible for the
/// runtime binding of the dynamic operations at this call site.
diff --git a/src/System.Linq.Expressions/src/System/Runtime/CompilerServices/RuleCache.cs b/src/System.Linq.Expressions/src/System/Runtime/CompilerServices/RuleCache.cs
index 3d4d12b9de..414c54cc74 100644
--- a/src/System.Linq.Expressions/src/System/Runtime/CompilerServices/RuleCache.cs
+++ b/src/System.Linq.Expressions/src/System/Runtime/CompilerServices/RuleCache.cs
@@ -113,9 +113,9 @@ namespace System.Runtime.CompilerServices
else
{
newRules = new T[newLength];
+ Array.Copy(rules, 0, newRules, 0, InsertPosition);
}
- Array.Copy(rules, 0, newRules, 0, InsertPosition);
newRules[InsertPosition] = item;
Array.Copy(rules, InsertPosition, newRules, InsertPosition + 1, newLength - InsertPosition - 1);
return newRules;
diff --git a/src/System.Linq.Expressions/tests/BinaryOperators/Arithmetic/BinaryMultiplyTests.cs b/src/System.Linq.Expressions/tests/BinaryOperators/Arithmetic/BinaryMultiplyTests.cs
index 7134ea755b..3914674629 100644
--- a/src/System.Linq.Expressions/tests/BinaryOperators/Arithmetic/BinaryMultiplyTests.cs
+++ b/src/System.Linq.Expressions/tests/BinaryOperators/Arithmetic/BinaryMultiplyTests.cs
@@ -576,5 +576,87 @@ namespace System.Linq.Expressions.Tests
BinaryExpression e2 = Expression.MultiplyChecked(Expression.Parameter(typeof(int), "a"), Expression.Parameter(typeof(int), "b"));
Assert.Equal("(a * b)", e2.ToString());
}
+
+ // Simulate VB-style overloading of exponentiation operation
+ public struct VBStyleExponentiation
+ {
+ public VBStyleExponentiation(double value) => Value = value;
+
+ public double Value { get; }
+
+ public static implicit operator VBStyleExponentiation(double value) => new VBStyleExponentiation(value);
+
+ public static VBStyleExponentiation op_Exponent(VBStyleExponentiation x, VBStyleExponentiation y) => Math.Pow(x.Value, y.Value);
+ }
+
+ [Theory, ClassData(typeof(CompilationTypes))]
+ public static void VBStyleOperatorOverloading(bool useInterpreter)
+ {
+ var b = Expression.Parameter(typeof(VBStyleExponentiation));
+ var e = Expression.Parameter(typeof(VBStyleExponentiation));
+ var func = Expression.Lambda<Func<VBStyleExponentiation, VBStyleExponentiation, VBStyleExponentiation>>(
+ Expression.Power(b, e), b, e).Compile(useInterpreter);
+ Assert.Equal(8.0, func(2.0, 3.0).Value);
+ Assert.Equal(10000.0, func(10.0, 4.0).Value);
+ }
+
+ [Theory, ClassData(typeof(CompilationTypes))]
+ public static void VBStyleOperatorOverloadingLifted(bool useInterpreter)
+ {
+ var b = Expression.Parameter(typeof(VBStyleExponentiation?));
+ var e = Expression.Parameter(typeof(VBStyleExponentiation?));
+ var func = Expression.Lambda<Func<VBStyleExponentiation?, VBStyleExponentiation?, VBStyleExponentiation?>>(
+ Expression.Power(b, e), b, e).Compile(useInterpreter);
+ Assert.Equal(8.0, func(2.0, 3.0).Value.Value);
+ Assert.Equal(10000.0, func(10.0, 4.0).Value.Value);
+ Assert.Null(func(2.0, null));
+ Assert.Null(func(null, 2.0));
+ Assert.Null(func(null, null));
+ }
+
+ // Simulate F#-style overloading of exponentiation operation
+ public struct FSStyleExponentiation
+ {
+ public FSStyleExponentiation(double value) => Value = value;
+
+ public static implicit operator FSStyleExponentiation(double value) => new FSStyleExponentiation(value);
+
+ public double Value { get; }
+
+ public static FSStyleExponentiation op_Exponentiation(FSStyleExponentiation x, FSStyleExponentiation y)
+ => new FSStyleExponentiation(Math.Pow(x.Value, y.Value));
+ }
+
+ [Theory, ClassData(typeof(CompilationTypes))]
+ public static void FSStyleOperatorOverloading(bool useInterpreter)
+ {
+ var b = Expression.Parameter(typeof(FSStyleExponentiation));
+ var e = Expression.Parameter(typeof(FSStyleExponentiation));
+ var func = Expression.Lambda<Func<FSStyleExponentiation, FSStyleExponentiation, FSStyleExponentiation>>(
+ Expression.Power(b, e), b, e).Compile(useInterpreter);
+ Assert.Equal(8.0, func(2.0, 3.0).Value);
+ Assert.Equal(10000.0, func(10.0, 4.0).Value);
+ }
+
+ [Theory, ClassData(typeof(CompilationTypes))]
+ public static void FSStyleOperatorOverloadingLifted(bool useInterpreter)
+ {
+ var b = Expression.Parameter(typeof(FSStyleExponentiation?));
+ var e = Expression.Parameter(typeof(FSStyleExponentiation?));
+ var func = Expression.Lambda<Func<FSStyleExponentiation?, FSStyleExponentiation?, FSStyleExponentiation?>>(
+ Expression.Power(b, e), b, e).Compile(useInterpreter);
+ Assert.Equal(8.0, func(2.0, 3.0).Value.Value);
+ Assert.Equal(10000.0, func(10.0, 4.0).Value.Value);
+ Assert.Null(func(2.0, null));
+ Assert.Null(func(null, 2.0));
+ Assert.Null(func(null, null));
+ }
+
+ [Fact]
+ public static void ExponentiationNotSupported()
+ {
+ ConstantExpression arg = Expression.Constant("");
+ Assert.Throws<InvalidOperationException>(() => Expression.Power(arg, arg));
+ }
}
}
diff --git a/src/System.Linq.Expressions/tests/Dynamic/CallSiteCachingTests.cs b/src/System.Linq.Expressions/tests/Dynamic/CallSiteCachingTests.cs
new file mode 100644
index 0000000000..0c4fa20e8e
--- /dev/null
+++ b/src/System.Linq.Expressions/tests/Dynamic/CallSiteCachingTests.cs
@@ -0,0 +1,126 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Dynamic;
+using System.Linq.Expressions;
+using Microsoft.CSharp.RuntimeBinder;
+using Xunit;
+
+namespace System.Runtime.CompilerServices.Tests
+{
+ public class CallSiteCachingTests
+ {
+ [Fact]
+ public void InlineCache()
+ {
+ var callSite = CallSite<Func<CallSite, object, object>>.Create(Binder.GetMember(CSharpBinderFlags.None, "A", typeof(CallSiteCachingTests), new CSharpArgumentInfo[1]
+ {
+ CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
+ }));
+
+ var initialTarget = callSite.Target;
+ Assert.Equal((object)initialTarget, callSite.Update);
+
+ object newExpando = CallSiteCachingTests.GetNewExpando(123);
+ callSite.Target(callSite, newExpando);
+
+ var newTarget = callSite.Target;
+
+ for (int i = 0; i < 10; i++)
+ {
+ callSite.Target(callSite, newExpando);
+
+ // rule should not be changing
+ Assert.Equal((object)newTarget, callSite.Target);
+ }
+ }
+
+ [Fact]
+ public void L1Cache()
+ {
+ var callSite = CallSite<Func<CallSite, object, object>>.Create(Binder.GetMember(CSharpBinderFlags.None, "A", typeof(CallSiteCachingTests), new CSharpArgumentInfo[1]
+ {
+ CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
+ }));
+
+ ObjAndRule[] t = new ObjAndRule[200];
+
+ for (int i = 0; i < 10; i++)
+ {
+ object newExpando = CallSiteCachingTests.GetNewExpando(i);
+ callSite.Target(callSite, newExpando);
+
+ t[i].obj = newExpando;
+ t[i].rule = callSite.Target;
+
+ if (i > 0)
+ {
+ // must not reuse rules for new expandos
+ Assert.NotEqual((object)t[i].rule, t[i - 1].rule);
+ }
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ var L1 = CallSiteOps.GetRules((dynamic)callSite);
+
+ // L1 must contain rules
+ Assert.Equal((object)t[9 - i].rule, L1[i]);
+ }
+ }
+
+ [Fact]
+ public void L2Cache()
+ {
+ var callSite = CallSite<Func<CallSite, object, object>>.Create(Binder.GetMember(CSharpBinderFlags.None, "A", typeof(CallSiteCachingTests), new CSharpArgumentInfo[1]
+ {
+ CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
+ }));
+
+ ObjAndRule[] t = new ObjAndRule[200];
+
+ for (int i = 0; i < 100; i++)
+ {
+ object newExpando = CallSiteCachingTests.GetNewExpando(i);
+ callSite.Target(callSite, newExpando);
+
+ t[i].obj = newExpando;
+ t[i].rule = callSite.Target;
+
+ if (i > 0)
+ {
+ // must not reuse rules for new expandos
+ Assert.NotEqual((object)t[i].rule, t[i - 1].rule);
+ }
+ }
+
+ for (int i = 0; i < 100; i++)
+ {
+ object newExpando = CallSiteCachingTests.GetNewExpando(i);
+ callSite.Target(callSite, newExpando);
+
+ // must reuse rules from L2 cache
+ Assert.Equal((object)t[i].rule, callSite.Target);
+ }
+ }
+
+ private static dynamic GetNewExpando(int i)
+ {
+ dynamic e = new ExpandoObject();
+ e.A = i;
+
+ var d = e as IDictionary<string, Object>;
+ d.Add(i.ToString(), i);
+
+ return e;
+ }
+
+ private struct ObjAndRule
+ {
+ public object obj;
+ public object rule;
+ }
+ }
+}
diff --git a/src/System.Linq.Expressions/tests/System.Linq.Expressions.Tests.csproj b/src/System.Linq.Expressions/tests/System.Linq.Expressions.Tests.csproj
index 3eb4ab20e1..d266ec33b7 100644
--- a/src/System.Linq.Expressions/tests/System.Linq.Expressions.Tests.csproj
+++ b/src/System.Linq.Expressions/tests/System.Linq.Expressions.Tests.csproj
@@ -12,10 +12,10 @@
<DefineConstants Condition=" '$(FeatureInterpret)' == 'true' ">$(DefineConstants);FEATURE_INTERPRET</DefineConstants>
<IncludeDefaultReferences>false</IncludeDefaultReferences>
</PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uapaot-Windows_NT-Debug|AnyCPU'" />
@@ -130,6 +130,7 @@
<Compile Include="Dynamic\BindingRestrictionsTests.cs" />
<Compile Include="Dynamic\CallInfoTests.cs" />
<Compile Include="Dynamic\CallSiteBinderDefaultBehaviourTests.cs" />
+ <Compile Include="Dynamic\CallSiteCachingTests.cs" />
<Compile Include="Dynamic\CallSiteTests.cs" />
<Compile Include="Dynamic\ConvertBinderTests.cs" />
<Compile Include="Dynamic\DynamicAttributeTests.cs" />
diff --git a/src/System.Linq.Expressions/tests/Variables/ParameterTests.cs b/src/System.Linq.Expressions/tests/Variables/ParameterTests.cs
index a417e5d43d..4a5219ebe0 100644
--- a/src/System.Linq.Expressions/tests/Variables/ParameterTests.cs
+++ b/src/System.Linq.Expressions/tests/Variables/ParameterTests.cs
@@ -310,7 +310,6 @@ namespace System.Linq.Expressions.Tests
}
[Theory]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot, "This test causes a fail fast on uapaot: https://github.com/dotnet/corefx/issues/19129")]
[MemberData(nameof(ReadAndWriteRefCases))]
public void ReadAndWriteRefParameters(bool useInterpreter, object value, object increment, object result)
{
diff --git a/src/System.Linq.Parallel/tests/ParallelEnumerableTests.cs b/src/System.Linq.Parallel/tests/ParallelEnumerableTests.cs
index f9b2e3b088..475399b9ba 100644
--- a/src/System.Linq.Parallel/tests/ParallelEnumerableTests.cs
+++ b/src/System.Linq.Parallel/tests/ParallelEnumerableTests.cs
@@ -259,7 +259,6 @@ namespace System.Linq.Parallel.Tests
[Theory]
[MemberData(nameof(EmptyData))]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot, "This causes assertion failure on UAPAoT")]
public static void Empty<T>(T def)
{
Assert.Empty(ParallelEnumerable.Empty<T>());
diff --git a/src/System.Linq/src/MatchingRefApiCompatBaseline.txt b/src/System.Linq/src/MatchingRefApiCompatBaseline.txt
new file mode 100644
index 0000000000..332d6f77da
--- /dev/null
+++ b/src/System.Linq/src/MatchingRefApiCompatBaseline.txt
@@ -0,0 +1,2 @@
+# Exposed publicly in the implementation to enable reflection for data-binding scenarios.
+TypesMustExist : Type 'System.Linq.Grouping<TKey, TElement>' does not exist in the implementation but it does exist in the contract.
diff --git a/src/System.Linq/tests/ConsistencyTests.cs b/src/System.Linq/tests/ConsistencyTests.cs
index 843505fd51..ea02f4f0fe 100644
--- a/src/System.Linq/tests/ConsistencyTests.cs
+++ b/src/System.Linq/tests/ConsistencyTests.cs
@@ -16,22 +16,7 @@ namespace System.Linq.Tests
[Fact]
public static void MatchSequencePattern()
{
- // If a change to Enumerable has required a change to the exception list in this test
- // make the same change at src/System.Linq.Queryable/tests/Queryable.cs.
- MethodInfo enumerableNotInQueryable = GetMissingExtensionMethod(
- typeof(Enumerable),
- typeof(Queryable),
- new[] {
- nameof(Enumerable.ToLookup),
- nameof(Enumerable.ToDictionary),
- nameof(Enumerable.ToArray),
- nameof(Enumerable.AsEnumerable),
- nameof(Enumerable.ToList),
- "Fold",
- "LeftJoin",
- "ToHashSet"
- }
- );
+ MethodInfo enumerableNotInQueryable = GetMissingExtensionMethod(typeof(Enumerable), typeof(Queryable), GetExcludedMethods());
Assert.True(enumerableNotInQueryable == null, string.Format("Enumerable method {0} not defined by Queryable", enumerableNotInQueryable));
@@ -46,6 +31,34 @@ namespace System.Linq.Tests
Assert.True(queryableNotInEnumerable == null, string.Format("Queryable method {0} not defined by Enumerable", queryableNotInEnumerable));
}
+ // If a change to Enumerable has required a change to the exception list in this test
+ // make the same change at src/System.Linq.Queryable/tests/Queryable.cs.
+ private static IEnumerable<string> GetExcludedMethods()
+ {
+ IEnumerable<string> result = new[]
+ {
+ nameof(Enumerable.ToLookup),
+ nameof(Enumerable.ToDictionary),
+ nameof(Enumerable.ToArray),
+ nameof(Enumerable.AsEnumerable),
+ nameof(Enumerable.ToList),
+ "Fold",
+ "LeftJoin",
+ "ToHashSet"
+ };
+
+ if (PlatformDetection.IsFullFramework)
+ {
+ result = result.Concat(new[]
+ {
+ nameof(Enumerable.Append),
+ nameof(Enumerable.Prepend)
+ });
+ }
+
+ return result;
+ }
+
private static MethodInfo GetMissingExtensionMethod(Type a, Type b, IEnumerable<string> excludedMethods)
{
var dex = new HashSet<string>(excludedMethods);
diff --git a/src/System.Management/pkg/System.Management.pkgproj b/src/System.Management/pkg/System.Management.pkgproj
index 1079d8066e..57d4110584 100644
--- a/src/System.Management/pkg/System.Management.pkgproj
+++ b/src/System.Management/pkg/System.Management.pkgproj
@@ -3,7 +3,7 @@
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<ProjectReference Include="..\ref\System.Management.csproj">
- <SupportedFramework>netcoreapp2.0;net45;$(AllXamarinFrameworks)</SupportedFramework>
+ <SupportedFramework>uap10.0.16299;netcoreapp2.0;net45;$(AllXamarinFrameworks)</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\src\System.Management.csproj" />
<InboxOnTargetFramework Include="net45">
diff --git a/src/System.Management/src/Configurations.props b/src/System.Management/src/Configurations.props
index 94ac07fdab..e322371832 100644
--- a/src/System.Management/src/Configurations.props
+++ b/src/System.Management/src/Configurations.props
@@ -8,6 +8,7 @@
<BuildConfigurations>
$(PackageConfigurations);
netcoreapp-Windows_NT;
+ _netfx;
</BuildConfigurations>
</PropertyGroup>
</Project>
diff --git a/src/System.Management/src/System/Management/ManagementDateTime.cs b/src/System.Management/src/System/Management/ManagementDateTime.cs
index d4f60011bf..e9224d44ec 100644
--- a/src/System.Management/src/System/Management/ManagementDateTime.cs
+++ b/src/System.Management/src/System/Management/ManagementDateTime.cs
@@ -117,113 +117,94 @@ namespace System.Management
int hour = DateTime.MinValue.Hour;
int minute = DateTime.MinValue.Minute;
int second = DateTime.MinValue.Second;
- int millisec = 0;
string dmtf = dmtfDate;
- DateTime datetime = DateTime.MinValue;
-
+
// If the string passed is empty or null then throw
// an exception
if(dmtf == null)
{
- throw new System.ArgumentOutOfRangeException("dmtfDate");
+ throw new ArgumentOutOfRangeException(nameof(dmtfDate));
}
if (dmtf.Length == 0)
{
- throw new System.ArgumentOutOfRangeException("dmtfDate");
+ throw new ArgumentOutOfRangeException(nameof(dmtfDate));
}
// if the length of the string is not equal to the
// standard length of the DMTF datetime then throw an exception
if(dmtf.Length != SIZEOFDMTFDATETIME)
{
- throw new System.ArgumentOutOfRangeException("dmtfDate");
+ throw new ArgumentOutOfRangeException(nameof(dmtfDate));
}
- IFormatProvider frmInt32 = (IFormatProvider)CultureInfo.InvariantCulture.GetFormat(typeof(System.Int32));
- System.Int64 ticks = 0;
+ IFormatProvider frmInt32 = (IFormatProvider)CultureInfo.InvariantCulture.GetFormat(typeof(int));
+ long ticks = 0;
+ int utcOffset = 0;
try
{
-
- string tempString = System.String.Empty;
- tempString = dmtf.Substring(0, 4);
+ var tempString = dmtf.Substring(0, 4);
if (("****" != tempString))
{
- year = System.Int32.Parse(tempString,frmInt32);
+ year = int.Parse(tempString,frmInt32);
}
tempString = dmtf.Substring(4, 2);
if (("**" != tempString))
{
- month = System.Int32.Parse(tempString,frmInt32);
+ month = int.Parse(tempString,frmInt32);
}
tempString = dmtf.Substring(6, 2);
if (("**" != tempString))
{
- day = System.Int32.Parse(tempString,frmInt32);
+ day = int.Parse(tempString,frmInt32);
}
tempString = dmtf.Substring(8, 2);
if (("**" != tempString))
{
- hour = System.Int32.Parse(tempString,frmInt32);
+ hour = int.Parse(tempString,frmInt32);
}
tempString = dmtf.Substring(10, 2);
if (("**" != tempString))
{
- minute = System.Int32.Parse(tempString,frmInt32);
+ minute = int.Parse(tempString,frmInt32);
}
tempString = dmtf.Substring(12, 2);
if (("**" != tempString))
{
- second = System.Int32.Parse(tempString,frmInt32);
+ second = int.Parse(tempString,frmInt32);
}
tempString = dmtf.Substring(15, 6);
if (("******" != tempString))
{
- ticks = (System.Int64.Parse(tempString,(IFormatProvider)CultureInfo.InvariantCulture.GetFormat(typeof(System.Int64)))) * (System.TimeSpan.TicksPerMillisecond/1000);
+ ticks = (long.Parse(tempString,(IFormatProvider)CultureInfo.InvariantCulture.GetFormat(typeof(Int64)))) * (TimeSpan.TicksPerMillisecond/1000);
}
- if( year < 0 || month < 0 || day < 0 || hour < 0 || minute < 0 || second < 0 || ticks < 0)
+ tempString = dmtf.Substring(22, 3);
+ if (("***" != tempString))
{
- throw new System.ArgumentOutOfRangeException("dmtfDate");
+ tempString = dmtf.Substring(21, 4);
+ utcOffset = int.Parse(tempString,frmInt32);
}
+ if( year < 0 || month < 0 || day < 0 || hour < 0 || minute < 0 || second < 0 || ticks < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(dmtfDate));
+ }
}
catch
{
- throw new System.ArgumentOutOfRangeException("dmtfDate");
+ throw new ArgumentOutOfRangeException(nameof(dmtfDate));
}
// Construct a new System.DateTime object
- datetime = new System.DateTime(year, month, day, hour, minute, second, millisec);
+ var datetime = new DateTime(year, month, day, hour, minute, second, 0, DateTimeKind.Utc);
// Then add the ticks calculated from the microseconds
datetime = datetime.AddTicks(ticks);
-
- // Adjust the UTC time to reflect the current zone time
- System.TimeZone curZone = System.TimeZone.CurrentTimeZone;
- System.TimeSpan tickOffset = curZone.GetUtcOffset(datetime);
- long OffsetMins = tickOffset.Ticks / System.TimeSpan.TicksPerMinute;
-
- // Adjusting the DateTime for the current UTC
- int UTCOffset = 0;
- string tempString1 = dmtf.Substring(22, 3);
- long OffsetToBeAdjusted = 0;
- if (("***" != tempString1))
- {
- tempString1 = dmtf.Substring(21, 4);
- try
- {
- UTCOffset = System.Int32.Parse(tempString1,frmInt32);
- }
- catch
- {
- throw new System.ArgumentOutOfRangeException();
- }
-
- OffsetToBeAdjusted = UTCOffset-OffsetMins;
-
- // We have to substract the minutes from the time
- datetime = datetime.AddMinutes(OffsetToBeAdjusted * -1);
+ // Then subtruct offset in minutes
+ datetime = datetime.AddMinutes(-utcOffset);
- }
+ // Convert to local Time
+ datetime = datetime.ToLocalTime();
+
return datetime;
}
diff --git a/src/System.Management/src/System/Management/WMIGenerator.cs b/src/System.Management/src/System/Management/WMIGenerator.cs
index b6f5b57f2c..31a5a674b8 100644
--- a/src/System.Management/src/System/Management/WMIGenerator.cs
+++ b/src/System.Management/src/System/Management/WMIGenerator.cs
@@ -2787,7 +2787,7 @@ namespace System.Management
/// The code generated changes if the method is static function
/// public &lt;retType&gt; Method1(&lt;type&gt; param1, &lt;type&gt; param2,...) {
/// ManagementBaseObject inParams = null;
- /// ManagementObject classObj = new ManagementObject(null, "WIN32_SHARE", null); // the clasname
+ /// ManagementObject classObj = new ManagementObject(null, "WIN32_SHARE", null); // the classname
/// inParams = classObj.GetMethodParameters("Create");
/// inParams["&lt;inparam1&gt;"] = &lt;Value&gt;;
/// inParams["&lt;inoutparam2&gt;"] = &lt;Value&gt;;
diff --git a/src/System.Management/tests/Configurations.props b/src/System.Management/tests/Configurations.props
index d8cd9ec843..808952d28a 100644
--- a/src/System.Management/tests/Configurations.props
+++ b/src/System.Management/tests/Configurations.props
@@ -3,6 +3,7 @@
<PropertyGroup>
<BuildConfigurations>
netcoreapp-Windows_NT;
+ netfx;
</BuildConfigurations>
</PropertyGroup>
</Project>
diff --git a/src/System.Management/tests/System.Management.Tests.csproj b/src/System.Management/tests/System.Management.Tests.csproj
index 01552f8893..d9b2e2a218 100644
--- a/src/System.Management/tests/System.Management.Tests.csproj
+++ b/src/System.Management/tests/System.Management.Tests.csproj
@@ -6,6 +6,8 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="MofHelpers\MofCollection.cs" />
<Compile Include="MofHelpers\MofFixture.cs" />
diff --git a/src/System.Management/tests/System/Management/ManagementDateTimeConverterTests.cs b/src/System.Management/tests/System/Management/ManagementDateTimeConverterTests.cs
index d2cdfffaf7..a35b9f59a0 100644
--- a/src/System.Management/tests/System/Management/ManagementDateTimeConverterTests.cs
+++ b/src/System.Management/tests/System/Management/ManagementDateTimeConverterTests.cs
@@ -11,15 +11,16 @@ namespace System.Management.Tests
[ConditionalFact(typeof(WmiTestHelper), nameof(WmiTestHelper.IsWmiSupported))]
public void DateTime_RoundTrip()
{
- var date = new DateTime(2002, 4, 8, 14, 18, 35, 978, DateTimeKind.Utc);
- var dmtfDate = "20020408141835.978000+000";
+ var date = new DateTime(2002, 4, 8, 14, 18, 35, 978, DateTimeKind.Utc).AddMinutes(150);
+ var dmtfDate = "20020408141835.978000-150";
+ var dmtfDateExpected = "20020408164835.978000+000";
DateTime convertedDate = ManagementDateTimeConverter.ToDateTime(dmtfDate).ToUniversalTime();
Assert.Equal(date, convertedDate);
// Converting System.DateTime to DMTF datetime
string convertedDmtfDate = ManagementDateTimeConverter.ToDmtfDateTime(date);
- Assert.Equal(dmtfDate, convertedDmtfDate);
+ Assert.Equal(dmtfDateExpected, convertedDmtfDate);
}
[ConditionalFact(typeof(WmiTestHelper), nameof(WmiTestHelper.IsWmiSupported))]
diff --git a/src/System.Memory/System.Memory.sln b/src/System.Memory/System.Memory.sln
index 402cbd12a0..d6455179a9 100644
--- a/src/System.Memory/System.Memory.sln
+++ b/src/System.Memory/System.Memory.sln
@@ -31,10 +31,10 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {15DB0DCC-68B4-4CFB-8BD2-F26BCCAF5A3F}.Debug|Any CPU.ActiveCfg = netstandard-Debug|Any CPU
- {15DB0DCC-68B4-4CFB-8BD2-F26BCCAF5A3F}.Debug|Any CPU.Build.0 = netstandard-Debug|Any CPU
- {15DB0DCC-68B4-4CFB-8BD2-F26BCCAF5A3F}.Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
- {15DB0DCC-68B4-4CFB-8BD2-F26BCCAF5A3F}.Release|Any CPU.Build.0 = netstandard-Release|Any CPU
+ {15DB0DCC-68B4-4CFB-8BD2-F26BCCAF5A3F}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
+ {15DB0DCC-68B4-4CFB-8BD2-F26BCCAF5A3F}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
+ {15DB0DCC-68B4-4CFB-8BD2-F26BCCAF5A3F}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
+ {15DB0DCC-68B4-4CFB-8BD2-F26BCCAF5A3F}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
{18482C55-6B57-41E8-BBC4-383B9E2C7AA2}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
{18482C55-6B57-41E8-BBC4-383B9E2C7AA2}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
{18482C55-6B57-41E8-BBC4-383B9E2C7AA2}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
diff --git a/src/System.Memory/pkg/System.Memory.pkgproj b/src/System.Memory/pkg/System.Memory.pkgproj
index ff57701606..0521e5471d 100644
--- a/src/System.Memory/pkg/System.Memory.pkgproj
+++ b/src/System.Memory/pkg/System.Memory.pkgproj
@@ -7,11 +7,11 @@
<SupportedFramework>net45;netcore45;wpa81;netcoreapp1.0;$(AllXamarinFrameworks)</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\src\System.Memory.csproj" />
-
+ <InboxOnTargetFramework Include="$(AllXamarinFrameworks)" />
<!-- Since UAP and .NETCoreApp are package based we still want to enable
OOBing libraries that happen to overlap with their framework package.
- This avoids us having to lock the API in our NuGet packages just
- to match what shipped inbox: since we can provide a new library
+ This avoids us having to lock the API in our NuGet packages just
+ to match what shipped inbox: since we can provide a new library
we can update it to add API without raising the netstandard version. -->
<ValidatePackageSuppression Include="TreatAsOutOfBox">
<Value>.NETCoreApp;UAP</Value>
diff --git a/src/System.Memory/ref/Configurations.props b/src/System.Memory/ref/Configurations.props
index 41873b4f7e..5d08140899 100644
--- a/src/System.Memory/ref/Configurations.props
+++ b/src/System.Memory/ref/Configurations.props
@@ -1,10 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
- <BuildConfigurations>
+ <PackageConfigurations>
netstandard1.1;
netstandard;
netcoreapp;
+ uap10.0.16299;
+ </PackageConfigurations>
+ <BuildConfigurations>
+ $(PackageConfigurations);
uap;
</BuildConfigurations>
</PropertyGroup>
diff --git a/src/System.Memory/ref/System.Memory.cs b/src/System.Memory/ref/System.Memory.cs
index 529d181270..9775637231 100644
--- a/src/System.Memory/ref/System.Memory.cs
+++ b/src/System.Memory/ref/System.Memory.cs
@@ -9,30 +9,39 @@ namespace System
{
public static partial class MemoryExtensions
{
- public static System.ReadOnlySpan<byte> AsBytes<T>(this System.ReadOnlySpan<T> source) where T : struct { throw null; }
- public static System.Span<byte> AsBytes<T>(this System.Span<T> source) where T : struct { throw null; }
- public static System.ReadOnlyMemory<char> AsReadOnlyMemory(this string text) { throw null; }
- public static System.ReadOnlyMemory<char> AsReadOnlyMemory(this string text, int start) { throw null; }
- public static System.ReadOnlyMemory<char> AsReadOnlyMemory(this string text, int start, int length) { throw null; }
- public static System.ReadOnlyMemory<T> AsReadOnlyMemory<T>(this System.Memory<T> memory) { throw null; }
- public static System.ReadOnlySpan<char> AsReadOnlySpan(this string text) { throw null; }
- public static System.ReadOnlySpan<char> AsReadOnlySpan(this string text, int start) { throw null; }
- public static System.ReadOnlySpan<char> AsReadOnlySpan(this string text, int start, int length) { throw null; }
- public static System.ReadOnlySpan<T> AsReadOnlySpan<T>(this System.ArraySegment<T> arraySegment) { throw null; }
- public static System.ReadOnlySpan<T> AsReadOnlySpan<T>(this System.Span<T> span) { throw null; }
- public static System.ReadOnlySpan<T> AsReadOnlySpan<T>(this T[] array) { throw null; }
- public static System.Span<T> AsSpan<T>(this System.ArraySegment<T> arraySegment) { throw null; }
+ public static System.Memory<T> AsMemory<T>(this System.ArraySegment<T> segment) { throw null; }
+ public static System.Memory<T> AsMemory<T>(this System.ArraySegment<T> segment, int start) { throw null; }
+ public static System.Memory<T> AsMemory<T>(this System.ArraySegment<T> segment, int start, int length) { throw null; }
+ public static System.Memory<T> AsMemory<T>(this T[] array) { throw null; }
+ public static System.Memory<T> AsMemory<T>(this T[] array, int start) { throw null; }
+ public static System.Memory<T> AsMemory<T>(this T[] array, int start, int length) { throw null; }
+ public static System.ReadOnlyMemory<char> AsMemory(this string text) { throw null; }
+ public static System.ReadOnlyMemory<char> AsMemory(this string text, int start) { throw null; }
+ public static System.ReadOnlyMemory<char> AsMemory(this string text, int start, int length) { throw null; }
+ public static System.ReadOnlySpan<char> AsSpan(this string text) { throw null; }
+ public static System.ReadOnlySpan<char> AsSpan(this string text, int start) { throw null; }
+ public static System.ReadOnlySpan<char> AsSpan(this string text, int start, int length) { throw null; }
+ public static System.Span<T> AsSpan<T>(this System.ArraySegment<T> segment) { throw null; }
+ public static System.Span<T> AsSpan<T>(this System.ArraySegment<T> segment, int start) { throw null; }
+ public static System.Span<T> AsSpan<T>(this System.ArraySegment<T> segment, int start, int length) { throw null; }
public static System.Span<T> AsSpan<T>(this T[] array) { throw null; }
+ public static System.Span<T> AsSpan<T>(this T[] array, int start) { throw null; }
+ public static System.Span<T> AsSpan<T>(this T[] array, int start, int length) { throw null; }
public static int BinarySearch<T>(this System.ReadOnlySpan<T> span, System.IComparable<T> comparable) { throw null; }
public static int BinarySearch<T>(this System.Span<T> span, System.IComparable<T> comparable) { throw null; }
public static int BinarySearch<T, TComparer>(this System.ReadOnlySpan<T> span, T value, TComparer comparer) where TComparer : System.Collections.Generic.IComparer<T> { throw null; }
public static int BinarySearch<T, TComparable>(this System.ReadOnlySpan<T> span, TComparable comparable) where TComparable : System.IComparable<T> { throw null; }
public static int BinarySearch<T, TComparer>(this System.Span<T> span, T value, TComparer comparer) where TComparer : System.Collections.Generic.IComparer<T> { throw null; }
public static int BinarySearch<T, TComparable>(this System.Span<T> span, TComparable comparable) where TComparable : System.IComparable<T> { throw null; }
- public static void CopyTo<T>(this T[] array, System.Memory<T> destination) { }
- public static void CopyTo<T>(this T[] array, System.Span<T> destination) { }
+ public static int CompareTo(this System.ReadOnlySpan<char> span, System.ReadOnlySpan<char> other, System.StringComparison comparisonType) { throw null; }
+ public static bool Contains(this System.ReadOnlySpan<char> span, System.ReadOnlySpan<char> value, System.StringComparison comparisonType) { throw null; }
+ public static void CopyTo<T>(this T[] source, System.Memory<T> destination) { }
+ public static void CopyTo<T>(this T[] source, System.Span<T> destination) { }
+ public static bool EndsWith(this System.ReadOnlySpan<char> span, System.ReadOnlySpan<char> value, System.StringComparison comparisonType) { throw null; }
public static bool EndsWith<T>(this System.ReadOnlySpan<T> span, System.ReadOnlySpan<T> value) where T : System.IEquatable<T> { throw null; }
public static bool EndsWith<T>(this System.Span<T> span, System.ReadOnlySpan<T> value) where T : System.IEquatable<T> { throw null; }
+ public static bool Equals(this System.ReadOnlySpan<char> span, System.ReadOnlySpan<char> other, System.StringComparison comparisonType) { throw null; }
+ public static int IndexOf(this System.ReadOnlySpan<char> span, System.ReadOnlySpan<char> value, System.StringComparison comparisonType) { throw null; }
public static int IndexOfAny<T>(this System.ReadOnlySpan<T> span, System.ReadOnlySpan<T> values) where T : System.IEquatable<T> { throw null; }
public static int IndexOfAny<T>(this System.ReadOnlySpan<T> span, T value0, T value1) where T : System.IEquatable<T> { throw null; }
public static int IndexOfAny<T>(this System.ReadOnlySpan<T> span, T value0, T value1, T value2) where T : System.IEquatable<T> { throw null; }
@@ -43,6 +52,7 @@ namespace System
public static int IndexOf<T>(this System.ReadOnlySpan<T> span, T value) where T : System.IEquatable<T> { throw null; }
public static int IndexOf<T>(this System.Span<T> span, System.ReadOnlySpan<T> value) where T : System.IEquatable<T> { throw null; }
public static int IndexOf<T>(this System.Span<T> span, T value) where T : System.IEquatable<T> { throw null; }
+ public static bool IsWhiteSpace(this System.ReadOnlySpan<char> span) { throw null; }
public static int LastIndexOfAny<T>(this System.ReadOnlySpan<T> span, System.ReadOnlySpan<T> values) where T : System.IEquatable<T> { throw null; }
public static int LastIndexOfAny<T>(this System.ReadOnlySpan<T> span, T value0, T value1) where T : System.IEquatable<T> { throw null; }
public static int LastIndexOfAny<T>(this System.ReadOnlySpan<T> span, T value0, T value1, T value2) where T : System.IEquatable<T> { throw null; }
@@ -53,20 +63,31 @@ namespace System
public static int LastIndexOf<T>(this System.ReadOnlySpan<T> span, T value) where T : System.IEquatable<T> { throw null; }
public static int LastIndexOf<T>(this System.Span<T> span, System.ReadOnlySpan<T> value) where T : System.IEquatable<T> { throw null; }
public static int LastIndexOf<T>(this System.Span<T> span, T value) where T : System.IEquatable<T> { throw null; }
- public static System.ReadOnlySpan<TTo> NonPortableCast<TFrom, TTo>(this System.ReadOnlySpan<TFrom> source) where TFrom : struct where TTo : struct { throw null; }
- public static System.Span<TTo> NonPortableCast<TFrom, TTo>(this System.Span<TFrom> source) where TFrom : struct where TTo : struct { throw null; }
- public static bool Overlaps<T>(this System.ReadOnlySpan<T> first, System.ReadOnlySpan<T> second) { throw null; }
- public static bool Overlaps<T>(this System.ReadOnlySpan<T> first, System.ReadOnlySpan<T> second, out int elementOffset) { throw null; }
- public static bool Overlaps<T>(this System.Span<T> first, System.ReadOnlySpan<T> second) { throw null; }
- public static bool Overlaps<T>(this System.Span<T> first, System.ReadOnlySpan<T> second, out int elementOffset) { throw null; }
+ public static bool Overlaps<T>(this System.ReadOnlySpan<T> span, System.ReadOnlySpan<T> other) { throw null; }
+ public static bool Overlaps<T>(this System.ReadOnlySpan<T> span, System.ReadOnlySpan<T> other, out int elementOffset) { throw null; }
+ public static bool Overlaps<T>(this System.Span<T> span, System.ReadOnlySpan<T> other) { throw null; }
+ public static bool Overlaps<T>(this System.Span<T> span, System.ReadOnlySpan<T> other, out int elementOffset) { throw null; }
public static void Reverse<T>(this System.Span<T> span) { }
- public static int SequenceCompareTo<T>(this System.ReadOnlySpan<T> first, System.ReadOnlySpan<T> second) where T : System.IComparable<T> { throw null; }
- public static int SequenceCompareTo<T>(this System.Span<T> first, System.ReadOnlySpan<T> second) where T : System.IComparable<T> { throw null; }
- public static bool SequenceEqual<T>(this System.ReadOnlySpan<T> first, System.ReadOnlySpan<T> second) where T : System.IEquatable<T> { throw null; }
- public static bool SequenceEqual<T>(this System.Span<T> first, System.ReadOnlySpan<T> second) where T : System.IEquatable<T> { throw null; }
+ public static int SequenceCompareTo<T>(this System.ReadOnlySpan<T> span, System.ReadOnlySpan<T> other) where T : System.IComparable<T> { throw null; }
+ public static int SequenceCompareTo<T>(this System.Span<T> span, System.ReadOnlySpan<T> other) where T : System.IComparable<T> { throw null; }
+ public static bool SequenceEqual<T>(this System.ReadOnlySpan<T> span, System.ReadOnlySpan<T> other) where T : System.IEquatable<T> { throw null; }
+ public static bool SequenceEqual<T>(this System.Span<T> span, System.ReadOnlySpan<T> other) where T : System.IEquatable<T> { throw null; }
+ public static bool StartsWith(this System.ReadOnlySpan<char> span, System.ReadOnlySpan<char> value, System.StringComparison comparisonType) { throw null; }
public static bool StartsWith<T>(this System.ReadOnlySpan<T> span, System.ReadOnlySpan<T> value) where T : System.IEquatable<T> { throw null; }
public static bool StartsWith<T>(this System.Span<T> span, System.ReadOnlySpan<T> value) where T : System.IEquatable<T> { throw null; }
- public static bool TryGetString(this System.ReadOnlyMemory<char> readOnlyMemory, out string text, out int start, out int length) { throw null; }
+ public static int ToLower(this System.ReadOnlySpan<char> source, System.Span<char> destination, System.Globalization.CultureInfo culture) { throw null; }
+ public static int ToLowerInvariant(this System.ReadOnlySpan<char> source, System.Span<char> destination) { throw null; }
+ public static int ToUpper(this System.ReadOnlySpan<char> source, System.Span<char> destination, System.Globalization.CultureInfo culture) { throw null; }
+ public static int ToUpperInvariant(this System.ReadOnlySpan<char> source, System.Span<char> destination) { throw null; }
+ public static System.ReadOnlySpan<char> Trim(this System.ReadOnlySpan<char> span) { throw null; }
+ public static System.ReadOnlySpan<char> Trim(this System.ReadOnlySpan<char> span, char trimChar) { throw null; }
+ public static System.ReadOnlySpan<char> Trim(this System.ReadOnlySpan<char> span, System.ReadOnlySpan<char> trimChars) { throw null; }
+ public static System.ReadOnlySpan<char> TrimEnd(this System.ReadOnlySpan<char> span) { throw null; }
+ public static System.ReadOnlySpan<char> TrimEnd(this System.ReadOnlySpan<char> span, char trimChar) { throw null; }
+ public static System.ReadOnlySpan<char> TrimEnd(this System.ReadOnlySpan<char> span, System.ReadOnlySpan<char> trimChars) { throw null; }
+ public static System.ReadOnlySpan<char> TrimStart(this System.ReadOnlySpan<char> span) { throw null; }
+ public static System.ReadOnlySpan<char> TrimStart(this System.ReadOnlySpan<char> span, char trimChar) { throw null; }
+ public static System.ReadOnlySpan<char> TrimStart(this System.ReadOnlySpan<char> span, System.ReadOnlySpan<char> trimChars) { throw null; }
}
public readonly partial struct Memory<T>
{
@@ -83,15 +104,16 @@ namespace System
public override bool Equals(object obj) { throw null; }
[System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
public override int GetHashCode() { throw null; }
- public static implicit operator System.Memory<T> (System.ArraySegment<T> arraySegment) { throw null; }
+ public static implicit operator System.Memory<T> (System.ArraySegment<T> segment) { throw null; }
public static implicit operator System.ReadOnlyMemory<T> (System.Memory<T> memory) { throw null; }
public static implicit operator System.Memory<T> (T[] array) { throw null; }
- public System.Buffers.MemoryHandle Retain(bool pin=false) { throw null; }
+ public System.Buffers.MemoryHandle Pin() { throw null; }
+ public System.Buffers.MemoryHandle Retain(bool pin = false) { throw null; }
public System.Memory<T> Slice(int start) { throw null; }
public System.Memory<T> Slice(int start, int length) { throw null; }
public T[] ToArray() { throw null; }
+ public override string ToString() { throw null; }
public bool TryCopyTo(System.Memory<T> destination) { throw null; }
- public bool TryGetArray(out System.ArraySegment<T> arraySegment) { throw null; }
}
public readonly partial struct ReadOnlyMemory<T>
{
@@ -108,12 +130,14 @@ namespace System
public bool Equals(System.ReadOnlyMemory<T> other) { throw null; }
[System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
public override int GetHashCode() { throw null; }
- public static implicit operator System.ReadOnlyMemory<T> (System.ArraySegment<T> arraySegment) { throw null; }
+ public static implicit operator System.ReadOnlyMemory<T> (System.ArraySegment<T> segment) { throw null; }
public static implicit operator System.ReadOnlyMemory<T> (T[] array) { throw null; }
- public System.Buffers.MemoryHandle Retain(bool pin=false) { throw null; }
+ public System.Buffers.MemoryHandle Pin() { throw null; }
+ public System.Buffers.MemoryHandle Retain(bool pin = false) { throw null; }
public System.ReadOnlyMemory<T> Slice(int start) { throw null; }
public System.ReadOnlyMemory<T> Slice(int start, int length) { throw null; }
public T[] ToArray() { throw null; }
+ public override string ToString() { throw null; }
public bool TryCopyTo(System.Memory<T> destination) { throw null; }
}
public readonly ref partial struct ReadOnlySpan<T>
@@ -129,8 +153,6 @@ namespace System
public int Length { get { throw null; } }
public void CopyTo(System.Span<T> destination) { }
[System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
- public static System.ReadOnlySpan<T> DangerousCreate(object obj, ref T objectData, int length) { throw null; }
- [System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
[System.ObsoleteAttribute("Equals() on ReadOnlySpan will always throw an exception. Use == instead.")]
public override bool Equals(object obj) { throw null; }
public System.ReadOnlySpan<T>.Enumerator GetEnumerator() { throw null; }
@@ -138,12 +160,13 @@ namespace System
[System.ObsoleteAttribute("GetHashCode() on ReadOnlySpan will always throw an exception.")]
public override int GetHashCode() { throw null; }
public static bool operator ==(System.ReadOnlySpan<T> left, System.ReadOnlySpan<T> right) { throw null; }
- public static implicit operator System.ReadOnlySpan<T> (System.ArraySegment<T> arraySegment) { throw null; }
+ public static implicit operator System.ReadOnlySpan<T> (System.ArraySegment<T> segment) { throw null; }
public static implicit operator System.ReadOnlySpan<T> (T[] array) { throw null; }
public static bool operator !=(System.ReadOnlySpan<T> left, System.ReadOnlySpan<T> right) { throw null; }
public System.ReadOnlySpan<T> Slice(int start) { throw null; }
public System.ReadOnlySpan<T> Slice(int start, int length) { throw null; }
public T[] ToArray() { throw null; }
+ public override string ToString() { throw null; }
public bool TryCopyTo(System.Span<T> destination) { throw null; }
public ref partial struct Enumerator
{
@@ -152,6 +175,22 @@ namespace System
public bool MoveNext() { throw null; }
}
}
+ public readonly partial struct SequencePosition : System.IEquatable<System.SequencePosition>
+ {
+ private readonly object _dummy;
+ public SequencePosition(object segment, int index) { throw null; }
+ [System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
+ public int GetInteger() { throw null; }
+ [System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
+ public object GetObject() { throw null; }
+ [System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
+ public override bool Equals(object obj) { throw null; }
+ public bool Equals(System.SequencePosition other) { throw null; }
+ public override int GetHashCode() { throw null; }
+ public static bool operator ==(System.SequencePosition left, System.SequencePosition right) { throw null; }
+ public static bool operator !=(System.SequencePosition left, System.SequencePosition right) { throw null; }
+ public override string ToString() { throw null; }
+ }
public readonly ref partial struct Span<T>
{
private readonly object _dummy;
@@ -166,8 +205,6 @@ namespace System
public void Clear() { }
public void CopyTo(System.Span<T> destination) { }
[System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
- public static System.Span<T> DangerousCreate(object obj, ref T objectData, int length) { throw null; }
- [System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
[System.ObsoleteAttribute("Equals() on Span will always throw an exception. Use == instead.")]
public override bool Equals(object obj) { throw null; }
public void Fill(T value) { }
@@ -176,13 +213,14 @@ namespace System
[System.ObsoleteAttribute("GetHashCode() on Span will always throw an exception.")]
public override int GetHashCode() { throw null; }
public static bool operator ==(System.Span<T> left, System.Span<T> right) { throw null; }
- public static implicit operator System.Span<T> (System.ArraySegment<T> arraySegment) { throw null; }
+ public static implicit operator System.Span<T> (System.ArraySegment<T> segment) { throw null; }
public static implicit operator System.ReadOnlySpan<T> (System.Span<T> span) { throw null; }
public static implicit operator System.Span<T> (T[] array) { throw null; }
public static bool operator !=(System.Span<T> left, System.Span<T> right) { throw null; }
public System.Span<T> Slice(int start) { throw null; }
public System.Span<T> Slice(int start, int length) { throw null; }
public T[] ToArray() { throw null; }
+ public override string ToString() { throw null; }
public bool TryCopyTo(System.Span<T> destination) { throw null; }
public ref partial struct Enumerator
{
@@ -194,6 +232,18 @@ namespace System
}
namespace System.Buffers
{
+ public partial interface IBufferWriter<T>
+ {
+ void Advance(int count);
+ System.Memory<T> GetMemory(int sizeHint = 0);
+ System.Span<T> GetSpan(int sizeHint = 0);
+ }
+ public abstract partial class ReadOnlySequenceSegment<T>
+ {
+ public System.ReadOnlyMemory<T> Memory { get; protected set; }
+ public System.Buffers.ReadOnlySequenceSegment<T> Next { get; protected set; }
+ public long RunningIndex { get; protected set; }
+ }
public partial interface IRetainable
{
bool Release();
@@ -203,12 +253,21 @@ namespace System.Buffers
{
private object _dummy;
[System.CLSCompliantAttribute(false)]
- public unsafe MemoryHandle(System.Buffers.IRetainable retainable, void* pointer=null, System.Runtime.InteropServices.GCHandle handle=default(System.Runtime.InteropServices.GCHandle)) { throw null; }
+ public unsafe MemoryHandle(System.Buffers.IRetainable retainable, void* pointer = null, System.Runtime.InteropServices.GCHandle handle = default(System.Runtime.InteropServices.GCHandle)) { throw null; }
public bool HasPointer { get { throw null; } }
[System.CLSCompliantAttribute(false)]
public unsafe void* Pointer { get { throw null; } }
public void Dispose() { }
}
+ public abstract partial class MemoryPool<T> : System.IDisposable
+ {
+ protected MemoryPool() { }
+ public abstract int MaxBufferSize { get; }
+ public static System.Buffers.MemoryPool<T> Shared { get { throw null; } }
+ public void Dispose() { }
+ protected abstract void Dispose(bool disposing);
+ public abstract System.Buffers.OwnedMemory<T> Rent(int minBufferSize = -1);
+ }
public enum OperationStatus
{
DestinationTooSmall = 1,
@@ -226,17 +285,62 @@ namespace System.Buffers
public abstract System.Span<T> Span { get; }
public void Dispose() { }
protected abstract void Dispose(bool disposing);
- public abstract System.Buffers.MemoryHandle Pin(int offset=0);
+ public abstract System.Buffers.MemoryHandle Pin(int byteOffset = 0);
public abstract bool Release();
public abstract void Retain();
- protected internal abstract bool TryGetArray(out System.ArraySegment<T> arraySegment);
+ protected internal abstract bool TryGetArray(out System.ArraySegment<T> segment);
+ }
+ public static partial class BuffersExtensions
+ {
+ public static void CopyTo<T>(in this System.Buffers.ReadOnlySequence<T> source, System.Span<T> destination) { }
+ public static System.Nullable<System.SequencePosition> PositionOf<T>(in this System.Buffers.ReadOnlySequence<T> source, T value) where T : System.IEquatable<T> { throw null; }
+ public static T[] ToArray<T>(in this System.Buffers.ReadOnlySequence<T> sequence) { throw null; }
+ public static void Write<T>(this System.Buffers.IBufferWriter<T> writer, ReadOnlySpan<T> value) { }
+ }
+ public readonly partial struct ReadOnlySequence<T>
+ {
+ private readonly object _dummy;
+ public static readonly System.Buffers.ReadOnlySequence<T> Empty;
+ public ReadOnlySequence(System.Buffers.ReadOnlySequenceSegment<T> startSegment, int startIndex, System.Buffers.ReadOnlySequenceSegment<T> endSegment, int endIndex) { throw null; }
+ public ReadOnlySequence(T[] array) { throw null; }
+ public ReadOnlySequence(T[] array, int start, int length) { throw null; }
+ public ReadOnlySequence(System.ReadOnlyMemory<T> memory) { throw null; }
+ public ReadOnlySequence(System.Buffers.OwnedMemory<T> memory) { throw null; }
+ public ReadOnlySequence(System.Buffers.OwnedMemory<T> memory, int start, int length) { throw null; }
+ public System.SequencePosition End { get { throw null; } }
+ public System.ReadOnlyMemory<T> First { get { throw null; } }
+ public bool IsEmpty { get { throw null; } }
+ public bool IsSingleSegment { get { throw null; } }
+ public long Length { get { throw null; } }
+ public System.SequencePosition Start { get { throw null; } }
+ public System.Buffers.ReadOnlySequence<T>.Enumerator GetEnumerator() { throw null; }
+ public System.SequencePosition GetPosition(long offset) { throw null; }
+ public System.SequencePosition GetPosition(long offset, System.SequencePosition origin) { throw null; }
+ public System.Buffers.ReadOnlySequence<T> Slice(int start, int length) { throw null; }
+ public System.Buffers.ReadOnlySequence<T> Slice(int start, System.SequencePosition end) { throw null; }
+ public System.Buffers.ReadOnlySequence<T> Slice(long start) { throw null; }
+ public System.Buffers.ReadOnlySequence<T> Slice(long start, long length) { throw null; }
+ public System.Buffers.ReadOnlySequence<T> Slice(long start, System.SequencePosition end) { throw null; }
+ public System.Buffers.ReadOnlySequence<T> Slice(System.SequencePosition start) { throw null; }
+ public System.Buffers.ReadOnlySequence<T> Slice(System.SequencePosition start, int length) { throw null; }
+ public System.Buffers.ReadOnlySequence<T> Slice(System.SequencePosition start, long length) { throw null; }
+ public System.Buffers.ReadOnlySequence<T> Slice(System.SequencePosition start, System.SequencePosition end) { throw null; }
+ public override string ToString() { throw null; }
+ public bool TryGet(ref System.SequencePosition position, out System.ReadOnlyMemory<T> memory, bool advance = true) { throw null; }
+ public partial struct Enumerator
+ {
+ private object _dummy;
+ public Enumerator(in System.Buffers.ReadOnlySequence<T> sequence) { throw null; }
+ public System.ReadOnlyMemory<T> Current { get { throw null; } }
+ public bool MoveNext() { throw null; }
+ }
}
public readonly partial struct StandardFormat : System.IEquatable<System.Buffers.StandardFormat>
{
private readonly int _dummy;
public const byte MaxPrecision = (byte)99;
public const byte NoPrecision = (byte)255;
- public StandardFormat(char symbol, byte precision=(byte)255) { throw null; }
+ public StandardFormat(char symbol, byte precision = (byte)255) { throw null; }
public bool HasPrecision { get { throw null; } }
public bool IsDefault { get { throw null; } }
public byte Precision { get { throw null; } }
@@ -256,25 +360,24 @@ namespace System.Buffers.Binary
{
public static partial class BinaryPrimitives
{
- public static short ReadInt16BigEndian(System.ReadOnlySpan<byte> buffer) { throw null; }
- public static short ReadInt16LittleEndian(System.ReadOnlySpan<byte> buffer) { throw null; }
- public static int ReadInt32BigEndian(System.ReadOnlySpan<byte> buffer) { throw null; }
- public static int ReadInt32LittleEndian(System.ReadOnlySpan<byte> buffer) { throw null; }
- public static long ReadInt64BigEndian(System.ReadOnlySpan<byte> buffer) { throw null; }
- public static long ReadInt64LittleEndian(System.ReadOnlySpan<byte> buffer) { throw null; }
- public static T ReadMachineEndian<T>(System.ReadOnlySpan<byte> buffer) where T : struct { throw null; }
+ public static short ReadInt16BigEndian(System.ReadOnlySpan<byte> source) { throw null; }
+ public static short ReadInt16LittleEndian(System.ReadOnlySpan<byte> source) { throw null; }
+ public static int ReadInt32BigEndian(System.ReadOnlySpan<byte> source) { throw null; }
+ public static int ReadInt32LittleEndian(System.ReadOnlySpan<byte> source) { throw null; }
+ public static long ReadInt64BigEndian(System.ReadOnlySpan<byte> source) { throw null; }
+ public static long ReadInt64LittleEndian(System.ReadOnlySpan<byte> source) { throw null; }
[System.CLSCompliantAttribute(false)]
- public static ushort ReadUInt16BigEndian(System.ReadOnlySpan<byte> buffer) { throw null; }
+ public static ushort ReadUInt16BigEndian(System.ReadOnlySpan<byte> source) { throw null; }
[System.CLSCompliantAttribute(false)]
- public static ushort ReadUInt16LittleEndian(System.ReadOnlySpan<byte> buffer) { throw null; }
+ public static ushort ReadUInt16LittleEndian(System.ReadOnlySpan<byte> source) { throw null; }
[System.CLSCompliantAttribute(false)]
- public static uint ReadUInt32BigEndian(System.ReadOnlySpan<byte> buffer) { throw null; }
+ public static uint ReadUInt32BigEndian(System.ReadOnlySpan<byte> source) { throw null; }
[System.CLSCompliantAttribute(false)]
- public static uint ReadUInt32LittleEndian(System.ReadOnlySpan<byte> buffer) { throw null; }
+ public static uint ReadUInt32LittleEndian(System.ReadOnlySpan<byte> source) { throw null; }
[System.CLSCompliantAttribute(false)]
- public static ulong ReadUInt64BigEndian(System.ReadOnlySpan<byte> buffer) { throw null; }
+ public static ulong ReadUInt64BigEndian(System.ReadOnlySpan<byte> source) { throw null; }
[System.CLSCompliantAttribute(false)]
- public static ulong ReadUInt64LittleEndian(System.ReadOnlySpan<byte> buffer) { throw null; }
+ public static ulong ReadUInt64LittleEndian(System.ReadOnlySpan<byte> source) { throw null; }
public static byte ReverseEndianness(byte value) { throw null; }
public static short ReverseEndianness(short value) { throw null; }
public static int ReverseEndianness(int value) { throw null; }
@@ -287,130 +390,153 @@ namespace System.Buffers.Binary
public static uint ReverseEndianness(uint value) { throw null; }
[System.CLSCompliantAttribute(false)]
public static ulong ReverseEndianness(ulong value) { throw null; }
- public static bool TryReadInt16BigEndian(System.ReadOnlySpan<byte> buffer, out short value) { throw null; }
- public static bool TryReadInt16LittleEndian(System.ReadOnlySpan<byte> buffer, out short value) { throw null; }
- public static bool TryReadInt32BigEndian(System.ReadOnlySpan<byte> buffer, out int value) { throw null; }
- public static bool TryReadInt32LittleEndian(System.ReadOnlySpan<byte> buffer, out int value) { throw null; }
- public static bool TryReadInt64BigEndian(System.ReadOnlySpan<byte> buffer, out long value) { throw null; }
- public static bool TryReadInt64LittleEndian(System.ReadOnlySpan<byte> buffer, out long value) { throw null; }
- public static bool TryReadMachineEndian<T>(System.ReadOnlySpan<byte> buffer, out T value) where T : struct { throw null; }
+ public static bool TryReadInt16BigEndian(System.ReadOnlySpan<byte> source, out short value) { throw null; }
+ public static bool TryReadInt16LittleEndian(System.ReadOnlySpan<byte> source, out short value) { throw null; }
+ public static bool TryReadInt32BigEndian(System.ReadOnlySpan<byte> source, out int value) { throw null; }
+ public static bool TryReadInt32LittleEndian(System.ReadOnlySpan<byte> source, out int value) { throw null; }
+ public static bool TryReadInt64BigEndian(System.ReadOnlySpan<byte> source, out long value) { throw null; }
+ public static bool TryReadInt64LittleEndian(System.ReadOnlySpan<byte> source, out long value) { throw null; }
[System.CLSCompliantAttribute(false)]
- public static bool TryReadUInt16BigEndian(System.ReadOnlySpan<byte> buffer, out ushort value) { throw null; }
+ public static bool TryReadUInt16BigEndian(System.ReadOnlySpan<byte> source, out ushort value) { throw null; }
[System.CLSCompliantAttribute(false)]
- public static bool TryReadUInt16LittleEndian(System.ReadOnlySpan<byte> buffer, out ushort value) { throw null; }
+ public static bool TryReadUInt16LittleEndian(System.ReadOnlySpan<byte> source, out ushort value) { throw null; }
[System.CLSCompliantAttribute(false)]
- public static bool TryReadUInt32BigEndian(System.ReadOnlySpan<byte> buffer, out uint value) { throw null; }
+ public static bool TryReadUInt32BigEndian(System.ReadOnlySpan<byte> source, out uint value) { throw null; }
[System.CLSCompliantAttribute(false)]
- public static bool TryReadUInt32LittleEndian(System.ReadOnlySpan<byte> buffer, out uint value) { throw null; }
+ public static bool TryReadUInt32LittleEndian(System.ReadOnlySpan<byte> source, out uint value) { throw null; }
[System.CLSCompliantAttribute(false)]
- public static bool TryReadUInt64BigEndian(System.ReadOnlySpan<byte> buffer, out ulong value) { throw null; }
+ public static bool TryReadUInt64BigEndian(System.ReadOnlySpan<byte> source, out ulong value) { throw null; }
[System.CLSCompliantAttribute(false)]
- public static bool TryReadUInt64LittleEndian(System.ReadOnlySpan<byte> buffer, out ulong value) { throw null; }
- public static bool TryWriteInt16BigEndian(System.Span<byte> buffer, short value) { throw null; }
- public static bool TryWriteInt16LittleEndian(System.Span<byte> buffer, short value) { throw null; }
- public static bool TryWriteInt32BigEndian(System.Span<byte> buffer, int value) { throw null; }
- public static bool TryWriteInt32LittleEndian(System.Span<byte> buffer, int value) { throw null; }
- public static bool TryWriteInt64BigEndian(System.Span<byte> buffer, long value) { throw null; }
- public static bool TryWriteInt64LittleEndian(System.Span<byte> buffer, long value) { throw null; }
- public static bool TryWriteMachineEndian<T>(System.Span<byte> buffer, ref T value) where T : struct { throw null; }
+ public static bool TryReadUInt64LittleEndian(System.ReadOnlySpan<byte> source, out ulong value) { throw null; }
+ public static bool TryWriteInt16BigEndian(System.Span<byte> destination, short value) { throw null; }
+ public static bool TryWriteInt16LittleEndian(System.Span<byte> destination, short value) { throw null; }
+ public static bool TryWriteInt32BigEndian(System.Span<byte> destination, int value) { throw null; }
+ public static bool TryWriteInt32LittleEndian(System.Span<byte> destination, int value) { throw null; }
+ public static bool TryWriteInt64BigEndian(System.Span<byte> destination, long value) { throw null; }
+ public static bool TryWriteInt64LittleEndian(System.Span<byte> destination, long value) { throw null; }
[System.CLSCompliantAttribute(false)]
- public static bool TryWriteUInt16BigEndian(System.Span<byte> buffer, ushort value) { throw null; }
+ public static bool TryWriteUInt16BigEndian(System.Span<byte> destination, ushort value) { throw null; }
[System.CLSCompliantAttribute(false)]
- public static bool TryWriteUInt16LittleEndian(System.Span<byte> buffer, ushort value) { throw null; }
+ public static bool TryWriteUInt16LittleEndian(System.Span<byte> destination, ushort value) { throw null; }
[System.CLSCompliantAttribute(false)]
- public static bool TryWriteUInt32BigEndian(System.Span<byte> buffer, uint value) { throw null; }
+ public static bool TryWriteUInt32BigEndian(System.Span<byte> destination, uint value) { throw null; }
[System.CLSCompliantAttribute(false)]
- public static bool TryWriteUInt32LittleEndian(System.Span<byte> buffer, uint value) { throw null; }
+ public static bool TryWriteUInt32LittleEndian(System.Span<byte> destination, uint value) { throw null; }
[System.CLSCompliantAttribute(false)]
- public static bool TryWriteUInt64BigEndian(System.Span<byte> buffer, ulong value) { throw null; }
+ public static bool TryWriteUInt64BigEndian(System.Span<byte> destination, ulong value) { throw null; }
[System.CLSCompliantAttribute(false)]
- public static bool TryWriteUInt64LittleEndian(System.Span<byte> buffer, ulong value) { throw null; }
- public static void WriteInt16BigEndian(System.Span<byte> buffer, short value) { }
- public static void WriteInt16LittleEndian(System.Span<byte> buffer, short value) { }
- public static void WriteInt32BigEndian(System.Span<byte> buffer, int value) { }
- public static void WriteInt32LittleEndian(System.Span<byte> buffer, int value) { }
- public static void WriteInt64BigEndian(System.Span<byte> buffer, long value) { }
- public static void WriteInt64LittleEndian(System.Span<byte> buffer, long value) { }
- public static void WriteMachineEndian<T>(System.Span<byte> buffer, ref T value) where T : struct { }
+ public static bool TryWriteUInt64LittleEndian(System.Span<byte> destination, ulong value) { throw null; }
+ public static void WriteInt16BigEndian(System.Span<byte> destination, short value) { }
+ public static void WriteInt16LittleEndian(System.Span<byte> destination, short value) { }
+ public static void WriteInt32BigEndian(System.Span<byte> destination, int value) { }
+ public static void WriteInt32LittleEndian(System.Span<byte> destination, int value) { }
+ public static void WriteInt64BigEndian(System.Span<byte> destination, long value) { }
+ public static void WriteInt64LittleEndian(System.Span<byte> destination, long value) { }
[System.CLSCompliantAttribute(false)]
- public static void WriteUInt16BigEndian(System.Span<byte> buffer, ushort value) { }
+ public static void WriteUInt16BigEndian(System.Span<byte> destination, ushort value) { }
[System.CLSCompliantAttribute(false)]
- public static void WriteUInt16LittleEndian(System.Span<byte> buffer, ushort value) { }
+ public static void WriteUInt16LittleEndian(System.Span<byte> destination, ushort value) { }
[System.CLSCompliantAttribute(false)]
- public static void WriteUInt32BigEndian(System.Span<byte> buffer, uint value) { }
+ public static void WriteUInt32BigEndian(System.Span<byte> destination, uint value) { }
[System.CLSCompliantAttribute(false)]
- public static void WriteUInt32LittleEndian(System.Span<byte> buffer, uint value) { }
+ public static void WriteUInt32LittleEndian(System.Span<byte> destination, uint value) { }
[System.CLSCompliantAttribute(false)]
- public static void WriteUInt64BigEndian(System.Span<byte> buffer, ulong value) { }
+ public static void WriteUInt64BigEndian(System.Span<byte> destination, ulong value) { }
[System.CLSCompliantAttribute(false)]
- public static void WriteUInt64LittleEndian(System.Span<byte> buffer, ulong value) { }
+ public static void WriteUInt64LittleEndian(System.Span<byte> destination, ulong value) { }
}
}
namespace System.Buffers.Text
{
public static partial class Base64
{
- public static System.Buffers.OperationStatus DecodeFromUtf8(System.ReadOnlySpan<byte> utf8, System.Span<byte> bytes, out int consumed, out int written, bool isFinalBlock=true) { throw null; }
- public static System.Buffers.OperationStatus DecodeFromUtf8InPlace(System.Span<byte> buffer, out int written) { throw null; }
- public static System.Buffers.OperationStatus EncodeToUtf8(System.ReadOnlySpan<byte> bytes, System.Span<byte> utf8, out int consumed, out int written, bool isFinalBlock=true) { throw null; }
- public static System.Buffers.OperationStatus EncodeToUtf8InPlace(System.Span<byte> buffer, int dataLength, out int written) { throw null; }
+ public static System.Buffers.OperationStatus DecodeFromUtf8(System.ReadOnlySpan<byte> utf8, System.Span<byte> bytes, out int bytesConsumed, out int bytesWritten, bool isFinalBlock = true) { throw null; }
+ public static System.Buffers.OperationStatus DecodeFromUtf8InPlace(System.Span<byte> buffer, out int bytesWritten) { throw null; }
+ public static System.Buffers.OperationStatus EncodeToUtf8(System.ReadOnlySpan<byte> bytes, System.Span<byte> utf8, out int bytesConsumed, out int bytesWritten, bool isFinalBlock = true) { throw null; }
+ public static System.Buffers.OperationStatus EncodeToUtf8InPlace(System.Span<byte> buffer, int dataLength, out int bytesWritten) { throw null; }
public static int GetMaxDecodedFromUtf8Length(int length) { throw null; }
public static int GetMaxEncodedToUtf8Length(int length) { throw null; }
}
public static partial class Utf8Formatter
{
- public static bool TryFormat(bool value, System.Span<byte> buffer, out int bytesWritten, System.Buffers.StandardFormat format=default(System.Buffers.StandardFormat)) { throw null; }
- public static bool TryFormat(byte value, System.Span<byte> buffer, out int bytesWritten, System.Buffers.StandardFormat format=default(System.Buffers.StandardFormat)) { throw null; }
- public static bool TryFormat(System.DateTime value, System.Span<byte> buffer, out int bytesWritten, System.Buffers.StandardFormat format=default(System.Buffers.StandardFormat)) { throw null; }
- public static bool TryFormat(System.DateTimeOffset value, System.Span<byte> buffer, out int bytesWritten, System.Buffers.StandardFormat format=default(System.Buffers.StandardFormat)) { throw null; }
- public static bool TryFormat(decimal value, System.Span<byte> buffer, out int bytesWritten, System.Buffers.StandardFormat format=default(System.Buffers.StandardFormat)) { throw null; }
- public static bool TryFormat(double value, System.Span<byte> buffer, out int bytesWritten, System.Buffers.StandardFormat format=default(System.Buffers.StandardFormat)) { throw null; }
- public static bool TryFormat(System.Guid value, System.Span<byte> buffer, out int bytesWritten, System.Buffers.StandardFormat format=default(System.Buffers.StandardFormat)) { throw null; }
- public static bool TryFormat(short value, System.Span<byte> buffer, out int bytesWritten, System.Buffers.StandardFormat format=default(System.Buffers.StandardFormat)) { throw null; }
- public static bool TryFormat(int value, System.Span<byte> buffer, out int bytesWritten, System.Buffers.StandardFormat format=default(System.Buffers.StandardFormat)) { throw null; }
- public static bool TryFormat(long value, System.Span<byte> buffer, out int bytesWritten, System.Buffers.StandardFormat format=default(System.Buffers.StandardFormat)) { throw null; }
- [System.CLSCompliantAttribute(false)]
- public static bool TryFormat(sbyte value, System.Span<byte> buffer, out int bytesWritten, System.Buffers.StandardFormat format=default(System.Buffers.StandardFormat)) { throw null; }
- public static bool TryFormat(float value, System.Span<byte> buffer, out int bytesWritten, System.Buffers.StandardFormat format=default(System.Buffers.StandardFormat)) { throw null; }
- public static bool TryFormat(System.TimeSpan value, System.Span<byte> buffer, out int bytesWritten, System.Buffers.StandardFormat format=default(System.Buffers.StandardFormat)) { throw null; }
- [System.CLSCompliantAttribute(false)]
- public static bool TryFormat(ushort value, System.Span<byte> buffer, out int bytesWritten, System.Buffers.StandardFormat format=default(System.Buffers.StandardFormat)) { throw null; }
- [System.CLSCompliantAttribute(false)]
- public static bool TryFormat(uint value, System.Span<byte> buffer, out int bytesWritten, System.Buffers.StandardFormat format=default(System.Buffers.StandardFormat)) { throw null; }
- [System.CLSCompliantAttribute(false)]
- public static bool TryFormat(ulong value, System.Span<byte> buffer, out int bytesWritten, System.Buffers.StandardFormat format=default(System.Buffers.StandardFormat)) { throw null; }
+ public static bool TryFormat(bool value, System.Span<byte> destination, out int bytesWritten, System.Buffers.StandardFormat format = default(System.Buffers.StandardFormat)) { throw null; }
+ public static bool TryFormat(byte value, System.Span<byte> destination, out int bytesWritten, System.Buffers.StandardFormat format = default(System.Buffers.StandardFormat)) { throw null; }
+ public static bool TryFormat(System.DateTime value, System.Span<byte> destination, out int bytesWritten, System.Buffers.StandardFormat format = default(System.Buffers.StandardFormat)) { throw null; }
+ public static bool TryFormat(System.DateTimeOffset value, System.Span<byte> destination, out int bytesWritten, System.Buffers.StandardFormat format = default(System.Buffers.StandardFormat)) { throw null; }
+ public static bool TryFormat(decimal value, System.Span<byte> destination, out int bytesWritten, System.Buffers.StandardFormat format = default(System.Buffers.StandardFormat)) { throw null; }
+ public static bool TryFormat(double value, System.Span<byte> destination, out int bytesWritten, System.Buffers.StandardFormat format = default(System.Buffers.StandardFormat)) { throw null; }
+ public static bool TryFormat(System.Guid value, System.Span<byte> destination, out int bytesWritten, System.Buffers.StandardFormat format = default(System.Buffers.StandardFormat)) { throw null; }
+ public static bool TryFormat(short value, System.Span<byte> destination, out int bytesWritten, System.Buffers.StandardFormat format = default(System.Buffers.StandardFormat)) { throw null; }
+ public static bool TryFormat(int value, System.Span<byte> destination, out int bytesWritten, System.Buffers.StandardFormat format = default(System.Buffers.StandardFormat)) { throw null; }
+ public static bool TryFormat(long value, System.Span<byte> destination, out int bytesWritten, System.Buffers.StandardFormat format = default(System.Buffers.StandardFormat)) { throw null; }
+ [System.CLSCompliantAttribute(false)]
+ public static bool TryFormat(sbyte value, System.Span<byte> destination, out int bytesWritten, System.Buffers.StandardFormat format = default(System.Buffers.StandardFormat)) { throw null; }
+ public static bool TryFormat(float value, System.Span<byte> destination, out int bytesWritten, System.Buffers.StandardFormat format = default(System.Buffers.StandardFormat)) { throw null; }
+ public static bool TryFormat(System.TimeSpan value, System.Span<byte> destination, out int bytesWritten, System.Buffers.StandardFormat format = default(System.Buffers.StandardFormat)) { throw null; }
+ [System.CLSCompliantAttribute(false)]
+ public static bool TryFormat(ushort value, System.Span<byte> destination, out int bytesWritten, System.Buffers.StandardFormat format = default(System.Buffers.StandardFormat)) { throw null; }
+ [System.CLSCompliantAttribute(false)]
+ public static bool TryFormat(uint value, System.Span<byte> destination, out int bytesWritten, System.Buffers.StandardFormat format = default(System.Buffers.StandardFormat)) { throw null; }
+ [System.CLSCompliantAttribute(false)]
+ public static bool TryFormat(ulong value, System.Span<byte> destination, out int bytesWritten, System.Buffers.StandardFormat format = default(System.Buffers.StandardFormat)) { throw null; }
}
public static partial class Utf8Parser
{
- public static bool TryParse(System.ReadOnlySpan<byte> text, out bool value, out int bytesConsumed, char standardFormat='\0') { throw null; }
- public static bool TryParse(System.ReadOnlySpan<byte> text, out byte value, out int bytesConsumed, char standardFormat='\0') { throw null; }
- public static bool TryParse(System.ReadOnlySpan<byte> text, out System.DateTime value, out int bytesConsumed, char standardFormat='\0') { throw null; }
- public static bool TryParse(System.ReadOnlySpan<byte> text, out System.DateTimeOffset value, out int bytesConsumed, char standardFormat='\0') { throw null; }
- public static bool TryParse(System.ReadOnlySpan<byte> text, out decimal value, out int bytesConsumed, char standardFormat='\0') { throw null; }
- public static bool TryParse(System.ReadOnlySpan<byte> text, out double value, out int bytesConsumed, char standardFormat='\0') { throw null; }
- public static bool TryParse(System.ReadOnlySpan<byte> text, out System.Guid value, out int bytesConsumed, char standardFormat='\0') { throw null; }
- public static bool TryParse(System.ReadOnlySpan<byte> text, out short value, out int bytesConsumed, char standardFormat='\0') { throw null; }
- public static bool TryParse(System.ReadOnlySpan<byte> text, out int value, out int bytesConsumed, char standardFormat='\0') { throw null; }
- public static bool TryParse(System.ReadOnlySpan<byte> text, out long value, out int bytesConsumed, char standardFormat='\0') { throw null; }
- [System.CLSCompliantAttribute(false)]
- public static bool TryParse(System.ReadOnlySpan<byte> text, out sbyte value, out int bytesConsumed, char standardFormat='\0') { throw null; }
- public static bool TryParse(System.ReadOnlySpan<byte> text, out float value, out int bytesConsumed, char standardFormat='\0') { throw null; }
- public static bool TryParse(System.ReadOnlySpan<byte> text, out System.TimeSpan value, out int bytesConsumed, char standardFormat='\0') { throw null; }
- [System.CLSCompliantAttribute(false)]
- public static bool TryParse(System.ReadOnlySpan<byte> text, out ushort value, out int bytesConsumed, char standardFormat='\0') { throw null; }
- [System.CLSCompliantAttribute(false)]
- public static bool TryParse(System.ReadOnlySpan<byte> text, out uint value, out int bytesConsumed, char standardFormat='\0') { throw null; }
- [System.CLSCompliantAttribute(false)]
- public static bool TryParse(System.ReadOnlySpan<byte> text, out ulong value, out int bytesConsumed, char standardFormat='\0') { throw null; }
+ public static bool TryParse(System.ReadOnlySpan<byte> source, out bool value, out int bytesConsumed, char standardFormat = '\0') { throw null; }
+ public static bool TryParse(System.ReadOnlySpan<byte> source, out byte value, out int bytesConsumed, char standardFormat = '\0') { throw null; }
+ public static bool TryParse(System.ReadOnlySpan<byte> source, out System.DateTime value, out int bytesConsumed, char standardFormat = '\0') { throw null; }
+ public static bool TryParse(System.ReadOnlySpan<byte> source, out System.DateTimeOffset value, out int bytesConsumed, char standardFormat = '\0') { throw null; }
+ public static bool TryParse(System.ReadOnlySpan<byte> source, out decimal value, out int bytesConsumed, char standardFormat = '\0') { throw null; }
+ public static bool TryParse(System.ReadOnlySpan<byte> source, out double value, out int bytesConsumed, char standardFormat = '\0') { throw null; }
+ public static bool TryParse(System.ReadOnlySpan<byte> source, out System.Guid value, out int bytesConsumed, char standardFormat = '\0') { throw null; }
+ public static bool TryParse(System.ReadOnlySpan<byte> source, out short value, out int bytesConsumed, char standardFormat = '\0') { throw null; }
+ public static bool TryParse(System.ReadOnlySpan<byte> source, out int value, out int bytesConsumed, char standardFormat = '\0') { throw null; }
+ public static bool TryParse(System.ReadOnlySpan<byte> source, out long value, out int bytesConsumed, char standardFormat = '\0') { throw null; }
+ [System.CLSCompliantAttribute(false)]
+ public static bool TryParse(System.ReadOnlySpan<byte> source, out sbyte value, out int bytesConsumed, char standardFormat = '\0') { throw null; }
+ public static bool TryParse(System.ReadOnlySpan<byte> source, out float value, out int bytesConsumed, char standardFormat = '\0') { throw null; }
+ public static bool TryParse(System.ReadOnlySpan<byte> source, out System.TimeSpan value, out int bytesConsumed, char standardFormat = '\0') { throw null; }
+ [System.CLSCompliantAttribute(false)]
+ public static bool TryParse(System.ReadOnlySpan<byte> source, out ushort value, out int bytesConsumed, char standardFormat = '\0') { throw null; }
+ [System.CLSCompliantAttribute(false)]
+ public static bool TryParse(System.ReadOnlySpan<byte> source, out uint value, out int bytesConsumed, char standardFormat = '\0') { throw null; }
+ [System.CLSCompliantAttribute(false)]
+ public static bool TryParse(System.ReadOnlySpan<byte> source, out ulong value, out int bytesConsumed, char standardFormat = '\0') { throw null; }
}
}
namespace System.Runtime.InteropServices
{
public static partial class MemoryMarshal
{
- public static System.Memory<T> AsMemory<T>(System.ReadOnlyMemory<T> readOnlyMemory) { throw null; }
+ public static System.ReadOnlySpan<byte> AsBytes<T>(System.ReadOnlySpan<T> span) where T : struct { throw null; }
+ public static System.Span<byte> AsBytes<T>(System.Span<T> span) where T : struct { throw null; }
+ public static System.Memory<T> AsMemory<T>(System.ReadOnlyMemory<T> memory) { throw null; }
+ public static System.ReadOnlySpan<TTo> Cast<TFrom, TTo>(System.ReadOnlySpan<TFrom> span) where TFrom : struct where TTo : struct { throw null; }
+ public static System.Span<TTo> Cast<TFrom, TTo>(System.Span<TFrom> span) where TFrom : struct where TTo : struct { throw null; }
+#if !FEATURE_PORTABLE_SPAN
+ public static System.ReadOnlySpan<T> CreateReadOnlySpan<T>(ref T reference, int length) { throw null; }
+ public static System.Span<T> CreateSpan<T>(ref T reference, int length) { throw null; }
+#endif
public static ref T GetReference<T>(System.ReadOnlySpan<T> span) { throw null; }
public static ref T GetReference<T>(System.Span<T> span) { throw null; }
- public static bool TryGetArray<T>(System.ReadOnlyMemory<T> readOnlyMemory, out System.ArraySegment<T> arraySegment) { throw null; }
+ public static T Read<T>(System.ReadOnlySpan<byte> source) where T : struct { throw null; }
+ public static System.Collections.Generic.IEnumerable<T> ToEnumerable<T>(System.ReadOnlyMemory<T> memory) { throw null; }
+ public static bool TryGetArray<T>(System.ReadOnlyMemory<T> memory, out System.ArraySegment<T> segment) { throw null; }
+ public static bool TryGetOwnedMemory<T, TOwner>(ReadOnlyMemory<T> memory, out TOwner owner)
+ where TOwner : System.Buffers.OwnedMemory<T> { throw null; }
+ public static bool TryGetOwnedMemory<T, TOwner>(ReadOnlyMemory<T> memory, out TOwner owner, out int start, out int length)
+ where TOwner : System.Buffers.OwnedMemory<T> { throw null; }
+ public static bool TryGetString(System.ReadOnlyMemory<char> memory, out string text, out int start, out int length) { throw null; }
+ public static bool TryRead<T>(System.ReadOnlySpan<byte> source, out T value) where T : struct { throw null; }
+ public static bool TryWrite<T>(System.Span<byte> destination, ref T value) where T : struct { throw null; }
+ public static void Write<T>(System.Span<byte> destination, ref T value) where T : struct { }
+ }
+
+ public static partial class SequenceMarshal
+ {
+ public static bool TryGetArray<T>(System.Buffers.ReadOnlySequence<T> sequence, out System.ArraySegment<T> segment) { throw null; }
+ public static bool TryGetReadOnlySequenceSegment<T>(System.Buffers.ReadOnlySequence<T> sequence, out System.Buffers.ReadOnlySequenceSegment<T> startSegment, out int startIndex, out System.Buffers.ReadOnlySequenceSegment<T> endSegment, out int endIndex) { throw null; }
+ public static bool TryGetOwnedMemory<T>(System.Buffers.ReadOnlySequence<T> sequence, out System.Buffers.OwnedMemory<T> ownedMemory, out int start, out int length) { throw null; }
+ public static bool TryGetReadOnlyMemory<T>(System.Buffers.ReadOnlySequence<T> sequence, out System.ReadOnlyMemory<T> memory) { throw null; }
}
}
diff --git a/src/System.Memory/ref/System.Memory.csproj b/src/System.Memory/ref/System.Memory.csproj
index 2acd7aa17c..3c8714d4c6 100644
--- a/src/System.Memory/ref/System.Memory.csproj
+++ b/src/System.Memory/ref/System.Memory.csproj
@@ -7,25 +7,29 @@
<!-- disable warnings about obsolete APIs -->
<NoWarn>$(NoWarn);0809</NoWarn>
<IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'netcoreapp' Or '$(TargetGroup)' == 'uap'">true</IsPartialFacadeAssembly>
+ <DefineConstants Condition="'$(IsPartialFacadeAssembly)' != 'true'">$(DefineConstants);FEATURE_PORTABLE_SPAN</DefineConstants>
</PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.1-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.1-Release|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap10.0.16299-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap10.0.16299-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="System.Memory.cs" />
</ItemGroup>
- <ItemGroup Condition="'$(IsPartialFacadeAssembly)' == 'true'">
+ <ItemGroup Condition="'$(IsPartialFacadeAssembly)' == 'true' and '$(TargetGroup)' != 'uap10.0.16299'">
<ProjectReference Include="..\..\System.Runtime\ref\System.Runtime.csproj" />
<ProjectReference Include="..\..\System.Runtime.InteropServices\ref\System.Runtime.InteropServices.csproj" />
</ItemGroup>
- <ItemGroup Condition="'$(TargetGroup)' == 'netstandard1.1'">
+ <ItemGroup Condition="'$(TargetGroup)' == 'netstandard1.1' Or '$(TargetGroup)' == 'uap10.0.16299'">
+ <Reference Include="System.Globalization" />
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.InteropServices" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project>
+</Project> \ No newline at end of file
diff --git a/src/System.Memory/src/Configurations.props b/src/System.Memory/src/Configurations.props
index 3026f5c782..7b111f57e3 100644
--- a/src/System.Memory/src/Configurations.props
+++ b/src/System.Memory/src/Configurations.props
@@ -1,12 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
- <BuildConfigurations>
+ <PackageConfigurations>
netstandard1.1;
netstandard;
netcoreapp-Windows_NT;
netcoreapp-Unix;
+ uap10.0.16299-Windows_NT;
+ </PackageConfigurations>
+ <BuildConfigurations>
+ $(PackageConfigurations);
uap-Windows_NT;
</BuildConfigurations>
</PropertyGroup>
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Memory/src/Resources/Strings.resx b/src/System.Memory/src/Resources/Strings.resx
index 219d3c94c5..40db9b75e0 100644
--- a/src/System.Memory/src/Resources/Strings.resx
+++ b/src/System.Memory/src/Resources/Strings.resx
@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
- <!--
- Microsoft ResX Schema
-
+ <!--
+ Microsoft ResX Schema
+
Version 2.0
-
- The primary goals of this format is to allow a simple XML format
- that is mostly human readable. The generation and parsing of the
- various data types are done through the TypeConverter classes
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
associated with the data types.
-
+
Example:
-
+
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
@@ -26,36 +26,36 @@
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
-
- There are any number of "resheader" rows that contain simple
+
+ There are any number of "resheader" rows that contain simple
name/value pairs.
-
- Each data row contains a name, and value. The row also contains a
- type or mimetype. Type corresponds to a .NET class that support
- text/value conversion through the TypeConverter architecture.
- Classes that don't support this are serialized and stored with the
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
mimetype set.
-
- The mimetype is used for serialized objects, and tells the
- ResXResourceReader how to depersist the object. This is currently not
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
-
- Note - application/x-microsoft.net.object.binary.base64 is the format
- that the ResXResourceWriter will generate, however the reader can
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
-
+
mimetype: application/x-microsoft.net.object.binary.base64
- value : The object must be serialized with
+ value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
-
+
mimetype: application/x-microsoft.net.object.soap.base64
- value : The object must be serialized with
+ value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
- value : The object must be serialized into a byte array
+ value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
@@ -117,10 +117,10 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
- <data name="CannotCallEqualsOnSpan" xml:space="preserve">
+ <data name="NotSupported_CannotCallEqualsOnSpan" xml:space="preserve">
<value>Equals() on Span and ReadOnlySpan is not supported. Use operator== instead.</value>
</data>
- <data name="CannotCallGetHashCodeOnSpan" xml:space="preserve">
+ <data name="NotSupported_CannotCallGetHashCodeOnSpan" xml:space="preserve">
<value>GetHashCode() on Span and ReadOnlySpan is not supported.</value>
</data>
<data name="Argument_InvalidTypeWithPointersNotSupported" xml:space="preserve">
@@ -150,4 +150,10 @@
<data name="Argument_OverlapAlignmentMismatch" xml:space="preserve">
<value>Overlapping spans have mismatching alignment.</value>
</data>
-</root>
+ <data name="EndPositionNotReached" xml:space="preserve">
+ <value>End position was not reached during enumeration.</value>
+ </data>
+ <data name="UnexpectedSegmentType" xml:space="preserve">
+ <value>Unexpected segment type.</value>
+ </data>
+</root> \ No newline at end of file
diff --git a/src/System.Memory/src/System.Memory.csproj b/src/System.Memory/src/System.Memory.csproj
index 0f67b7ee9c..5e364ecf6b 100644
--- a/src/System.Memory/src/System.Memory.csproj
+++ b/src/System.Memory/src/System.Memory.csproj
@@ -9,6 +9,7 @@
<DefineConstants Condition="'$(IsPartialFacadeAssembly)' != 'true'">$(DefineConstants);netstandard;FEATURE_PORTABLE_SPAN</DefineConstants>
<DefineConstants Condition="'$(TargetGroup)'=='netcoreapp'">$(DefineConstants);netcoreapp</DefineConstants>
<DefineConstants Condition="'$(TargetGroup)'=='netstandard1.1'">$(DefineConstants);netstandard11</DefineConstants>
+ <ILLinkClearInitLocals>true</ILLinkClearInitLocals>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
@@ -20,21 +21,28 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.1-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap10.0.16299-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap10.0.16299-Windows_NT-Release|AnyCPU'" />
<ItemGroup>
- <Compile Include="System\MemoryExtensions.cs" />
- <Compile Include="System\SpanHelpers.BinarySearch.cs" />
- <Compile Include="System\SpanHelpers.T.cs" />
- <Compile Include="System\SpanHelpers.byte.cs" />
+ <Compile Include="System\SequencePosition.cs" />
<Compile Include="System\ThrowHelper.cs" />
+ <Compile Include="System\Buffers\ArrayMemoryPool.cs" />
+ <Compile Include="System\Buffers\ArrayMemoryPool.ArrayMemoryPoolBuffer.cs" />
+ <Compile Include="System\Buffers\BuffersExtensions.cs" />
+ <Compile Include="System\Buffers\IBufferWriter.cs" />
+ <Compile Include="System\Buffers\MemoryPool.cs" />
<Compile Include="System\Buffers\OperationStatus.cs" />
+ <Compile Include="System\Buffers\ReadOnlySequence.cs" />
+ <Compile Include="System\Buffers\ReadOnlySequenceSegment.cs" />
+ <Compile Include="System\Buffers\ReadOnlySequence_helpers.cs" />
<Compile Include="System\Buffers\Binary\Reader.cs" />
<Compile Include="System\Buffers\Binary\ReaderBigEndian.cs" />
<Compile Include="System\Buffers\Binary\ReaderLittleEndian.cs" />
- <Compile Include="System\Buffers\Binary\Writer.cs" />
<Compile Include="System\Buffers\Binary\WriterBigEndian.cs" />
<Compile Include="System\Buffers\Binary\WriterLittleEndian.cs" />
<Compile Include="System\Buffers\Text\Base64Decoder.cs" />
<Compile Include="System\Buffers\Text\Base64Encoder.cs" />
+ <Compile Include="System\Runtime\InteropServices\SequenceMarshal.cs" />
</ItemGroup>
<!-- Utf8 Formatter/Parser -->
<ItemGroup>
@@ -96,32 +104,44 @@
<Compile Include="System\Number\Number.FormatAndParse.cs" />
<Compile Include="System\Number\Number.NumberBuffer.cs" />
</ItemGroup>
- <ItemGroup>
- <Compile Include="..\Common\src\System\MutableDecimal.cs" />
- </ItemGroup>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true'">
<Compile Include="$(CommonPath)\CoreLib\System\Memory.cs" />
<Compile Include="$(CommonPath)\CoreLib\System\MemoryDebugView.cs" />
+ <Compile Include="$(CommonPath)\CoreLib\System\MemoryExtensions.cs" />
<Compile Include="$(CommonPath)\CoreLib\System\ReadOnlyMemory.cs" />
+ <Compile Include="$(CommonPath)\CoreLib\System\ReadOnlySpan.cs" />
+ <Compile Include="$(CommonPath)\CoreLib\System\Span.cs" />
+ <Compile Include="$(CommonPath)\CoreLib\System\SpanDebugView.cs" />
+ <Compile Include="$(CommonPath)\CoreLib\System\SpanHelpers.BinarySearch.cs" />
+ <Compile Include="$(CommonPath)\CoreLib\System\SpanHelpers.Byte.cs" />
+ <Compile Include="$(CommonPath)\CoreLib\System\SpanHelpers.Char.cs" />
+ <Compile Include="$(CommonPath)\CoreLib\System\SpanHelpers.T.cs" />
<Compile Include="$(CommonPath)\CoreLib\System\Buffers\IRetainable.cs" />
<Compile Include="$(CommonPath)\CoreLib\System\Buffers\MemoryHandle.cs" />
<Compile Include="$(CommonPath)\CoreLib\System\Buffers\OwnedMemory.cs" />
<Compile Include="$(CommonPath)\CoreLib\System\Runtime\InteropServices\MemoryMarshal.cs" />
- <Compile Include="System\ReadOnlySpan.cs" />
- <Compile Include="System\Span.cs" />
- <Compile Include="System\SpanDebugView.cs" />
+ <Compile Include="System\ReadOnlySpan.Portable.cs" />
+ <Compile Include="System\Span.Portable.cs" />
<Compile Include="System\MemoryExtensions.Portable.cs" />
+ <Compile Include="System\NUint.cs" />
<Compile Include="System\SpanHelpers.cs" />
<Compile Include="System\Pinnable.cs" />
- <Compile Include="System\SpanHelpers.Clear.cs" />
+ <Compile Include="System\Runtime\InteropServices\MemoryMarshal.Portable.cs" />
</ItemGroup>
<ItemGroup>
<!-- Common or Common-branched source files -->
+ <Compile Include="$(CommonPath)\System\Numerics\Hashing\HashHelpers.cs">
+ <Link>Common\System\Collections\HashHelpers.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\System\NotImplemented.cs">
<Link>Common\System\NotImplemented.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\MutableDecimal.cs">
+ <Link>Common\System\MutableDecimal.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true'">
+ <Reference Include="System.Buffers" />
<Reference Include="System.Diagnostics.Debug" />
<Reference Include="System.Globalization" />
<Reference Include="System.Reflection" />
@@ -130,16 +150,28 @@
<Reference Include="System.Runtime.Extensions" />
<Reference Include="System.Runtime.InteropServices" />
<Reference Include="System.Runtime.CompilerServices.Unsafe" />
+ <Reference Include="System.Threading" />
<Reference Condition="'$(TargetGroup)' != 'netstandard1.1'" Include="System.Numerics.Vectors" />
</ItemGroup>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' == 'true'">
- <Compile Include="System\MemoryExtensions.Fast.cs" />
- </ItemGroup>
- <ItemGroup Condition="'$(IsPartialFacadeAssembly)' == 'true'">
<ReferenceFromRuntime Include="System.Private.CoreLib" />
<ProjectReference Include="..\..\System.Runtime\src\System.Runtime.csproj" />
<ProjectReference Include="..\..\System.Diagnostics.Debug\src\System.Diagnostics.Debug.csproj" />
<ProjectReference Include="..\..\System.Numerics.Vectors\src\System.Numerics.Vectors.csproj" />
</ItemGroup>
+ <ItemGroup>
+ <None Include="$(CommonPath)\CoreLib\System\MemoryExtensions.Fast.cs">
+ <Link>System\MemoryExtensions.Fast.cs</Link>
+ </None>
+ <None Include="$(CommonPath)\CoreLib\System\Runtime\InteropServices\MemoryMarshal.Fast.cs">
+ <Link>System\Runtime\InteropServices\MemoryMarshal.Fast.cs</Link>
+ </None>
+ <None Include="$(CommonPath)\CoreLib\System\ReadOnlySpan.Fast.cs">
+ <Link>System\ReadOnlySpan.Fast.cs</Link>
+ </None>
+ <None Include="$(CommonPath)\CoreLib\System\Span.Fast.cs">
+ <Link>System\Span.Fast.cs</Link>
+ </None>
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.Memory/src/System/Buffers/ArrayMemoryPool.ArrayMemoryPoolBuffer.cs b/src/System.Memory/src/System/Buffers/ArrayMemoryPool.ArrayMemoryPoolBuffer.cs
new file mode 100644
index 0000000000..e3db9db89d
--- /dev/null
+++ b/src/System.Memory/src/System/Buffers/ArrayMemoryPool.ArrayMemoryPoolBuffer.cs
@@ -0,0 +1,127 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System.Threading;
+
+#if !netstandard
+using Internal.Runtime.CompilerServices;
+#else
+using System.Runtime.CompilerServices;
+#endif
+
+namespace System.Buffers
+{
+ internal sealed partial class ArrayMemoryPool<T> : MemoryPool<T>
+ {
+ private sealed class ArrayMemoryPoolBuffer : OwnedMemory<T>
+ {
+ private T[] _array;
+ private int _refCount;
+
+ public ArrayMemoryPoolBuffer(int size)
+ {
+ _array = ArrayPool<T>.Shared.Rent(size);
+ _refCount = 1;
+ }
+
+ public sealed override int Length => _array.Length;
+
+ public sealed override bool IsDisposed => _array == null;
+
+ protected sealed override bool IsRetained => Volatile.Read(ref _refCount) > 0;
+
+ public sealed override Span<T> Span
+ {
+ get
+ {
+ if (IsDisposed)
+ ThrowHelper.ThrowObjectDisposedException_ArrayMemoryPoolBuffer();
+
+ return _array;
+ }
+ }
+
+ protected sealed override void Dispose(bool disposing)
+ {
+ if (_array != null)
+ {
+ ArrayPool<T>.Shared.Return(_array);
+ _array = null;
+ }
+ }
+
+ // TryGetArray is exposed as "protected internal". Normally, the rules of C# dictate we override it as "protected" because the base class is
+ // in a different assembly. Except in the netstandard config where the base class is in the same assembly.
+ protected
+#if netstandard
+ internal
+#endif
+ sealed override bool TryGetArray(out ArraySegment<T> segment)
+ {
+ if (IsDisposed)
+ ThrowHelper.ThrowObjectDisposedException_ArrayMemoryPoolBuffer();
+
+ segment = new ArraySegment<T>(_array);
+ return true;
+ }
+
+ public sealed override MemoryHandle Pin(int byteOffset = 0)
+ {
+ unsafe
+ {
+ Retain(); // this checks IsDisposed
+
+ try
+ {
+ if ((IntPtr.Size == 4 && (uint)byteOffset > (uint)_array.Length * (uint)Unsafe.SizeOf<T>())
+ || (IntPtr.Size != 4 && (ulong)byteOffset > (uint)_array.Length * (ulong)Unsafe.SizeOf<T>()))
+ {
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.byteOffset);
+ }
+
+ GCHandle handle = GCHandle.Alloc(_array, GCHandleType.Pinned);
+ return new MemoryHandle(this, ((byte*)handle.AddrOfPinnedObject()) + byteOffset, handle);
+ }
+ catch
+ {
+ Release();
+ throw;
+ }
+ }
+ }
+
+ public sealed override void Retain()
+ {
+ while (true)
+ {
+ int currentCount = Volatile.Read(ref _refCount);
+ if (currentCount <= 0)
+ ThrowHelper.ThrowObjectDisposedException_ArrayMemoryPoolBuffer();
+ if (Interlocked.CompareExchange(ref _refCount, currentCount + 1, currentCount) == currentCount)
+ break;
+ }
+ }
+
+ public sealed override bool Release()
+ {
+ while (true)
+ {
+ int currentCount = Volatile.Read(ref _refCount);
+ if (currentCount <= 0)
+ ThrowHelper.ThrowObjectDisposedException_ArrayMemoryPoolBuffer();
+ if (Interlocked.CompareExchange(ref _refCount, currentCount - 1, currentCount) == currentCount)
+ {
+ if (currentCount == 1)
+ {
+ Dispose();
+ return false;
+ }
+ return true;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/System.Memory/src/System/Buffers/ArrayMemoryPool.cs b/src/System.Memory/src/System/Buffers/ArrayMemoryPool.cs
new file mode 100644
index 0000000000..1882c5e723
--- /dev/null
+++ b/src/System.Memory/src/System/Buffers/ArrayMemoryPool.cs
@@ -0,0 +1,30 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#if !netstandard
+using Internal.Runtime.CompilerServices;
+#else
+using System.Runtime.CompilerServices;
+#endif
+
+namespace System.Buffers
+{
+ internal sealed partial class ArrayMemoryPool<T> : MemoryPool<T>
+ {
+ private const int s_maxBufferSize = int.MaxValue;
+ public sealed override int MaxBufferSize => s_maxBufferSize;
+
+ public sealed override OwnedMemory<T> Rent(int minimumBufferSize = -1)
+ {
+ if (minimumBufferSize == -1)
+ minimumBufferSize = 1 + (4095 / Unsafe.SizeOf<T>());
+ else if (((uint)minimumBufferSize) > s_maxBufferSize)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.minimumBufferSize);
+
+ return new ArrayMemoryPoolBuffer(minimumBufferSize);
+ }
+
+ protected sealed override void Dispose(bool disposing) { } // ArrayMemoryPool is a shared pool so Dispose() would be a nop even if there were native resources to dispose.
+ }
+}
diff --git a/src/System.Memory/src/System/Buffers/Binary/Reader.cs b/src/System.Memory/src/System/Buffers/Binary/Reader.cs
index 599bcf27f8..ae3acdf00d 100644
--- a/src/System.Memory/src/System/Buffers/Binary/Reader.cs
+++ b/src/System.Memory/src/System/Buffers/Binary/Reader.cs
@@ -3,11 +3,6 @@
// See the LICENSE file in the project root for more information.
using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-#if !netstandard
-using Internal.Runtime.CompilerServices;
-#endif
namespace System.Buffers.Binary
{
@@ -127,62 +122,5 @@ namespace System.Buffers.Binary
return ((ulong)ReverseEndianness((uint)value) << 32)
+ ReverseEndianness((uint)(value >> 32));
}
-
- /// <summary>
- /// Reads a structure of type T out of a read-only span of bytes.
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static T ReadMachineEndian<T>(ReadOnlySpan<byte> buffer)
- where T : struct
- {
-#if netstandard
- if (SpanHelpers.IsReferenceOrContainsReferences<T>())
- {
- ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T));
- }
-#else
- if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
- {
- ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T));
- }
-#endif
- if (Unsafe.SizeOf<T>() > buffer.Length)
- {
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length);
- }
- return Unsafe.ReadUnaligned<T>(ref MemoryMarshal.GetReference(buffer));
- }
-
- /// <summary>
- /// Reads a structure of type T out of a span of bytes.
- /// <returns>If the span is too small to contain the type T, return false.</returns>
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryReadMachineEndian<T>(ReadOnlySpan<byte> buffer, out T value)
- where T : struct
- {
-#if netstandard
- if (SpanHelpers.IsReferenceOrContainsReferences<T>())
- {
- ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T));
- }
-#else
- if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
- {
- ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T));
- }
-#endif
- if (Unsafe.SizeOf<T>() > (uint)buffer.Length)
- {
-#if __MonoCS__
- value = default(T);
-#else
- value = default;
-#endif
- return false;
- }
- value = Unsafe.ReadUnaligned<T>(ref MemoryMarshal.GetReference(buffer));
- return true;
- }
}
}
diff --git a/src/System.Memory/src/System/Buffers/Binary/ReaderBigEndian.cs b/src/System.Memory/src/System/Buffers/Binary/ReaderBigEndian.cs
index 54cef4eb1f..b45dd8913d 100644
--- a/src/System.Memory/src/System/Buffers/Binary/ReaderBigEndian.cs
+++ b/src/System.Memory/src/System/Buffers/Binary/ReaderBigEndian.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
namespace System.Buffers.Binary
{
@@ -12,9 +13,9 @@ namespace System.Buffers.Binary
/// Reads an Int16 out of a read-only span of bytes as big endian.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static short ReadInt16BigEndian(ReadOnlySpan<byte> buffer)
+ public static short ReadInt16BigEndian(ReadOnlySpan<byte> source)
{
- short result = ReadMachineEndian<short>(buffer);
+ short result = MemoryMarshal.Read<short>(source);
if (BitConverter.IsLittleEndian)
{
result = ReverseEndianness(result);
@@ -26,9 +27,9 @@ namespace System.Buffers.Binary
/// Reads an Int32 out of a read-only span of bytes as big endian.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int ReadInt32BigEndian(ReadOnlySpan<byte> buffer)
+ public static int ReadInt32BigEndian(ReadOnlySpan<byte> source)
{
- int result = ReadMachineEndian<int>(buffer);
+ int result = MemoryMarshal.Read<int>(source);
if (BitConverter.IsLittleEndian)
{
result = ReverseEndianness(result);
@@ -40,9 +41,9 @@ namespace System.Buffers.Binary
/// Reads an Int64 out of a read-only span of bytes as big endian.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static long ReadInt64BigEndian(ReadOnlySpan<byte> buffer)
+ public static long ReadInt64BigEndian(ReadOnlySpan<byte> source)
{
- long result = ReadMachineEndian<long>(buffer);
+ long result = MemoryMarshal.Read<long>(source);
if (BitConverter.IsLittleEndian)
{
result = ReverseEndianness(result);
@@ -55,9 +56,9 @@ namespace System.Buffers.Binary
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ushort ReadUInt16BigEndian(ReadOnlySpan<byte> buffer)
+ public static ushort ReadUInt16BigEndian(ReadOnlySpan<byte> source)
{
- ushort result = ReadMachineEndian<ushort>(buffer);
+ ushort result = MemoryMarshal.Read<ushort>(source);
if (BitConverter.IsLittleEndian)
{
result = ReverseEndianness(result);
@@ -70,9 +71,9 @@ namespace System.Buffers.Binary
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static uint ReadUInt32BigEndian(ReadOnlySpan<byte> buffer)
+ public static uint ReadUInt32BigEndian(ReadOnlySpan<byte> source)
{
- uint result = ReadMachineEndian<uint>(buffer);
+ uint result = MemoryMarshal.Read<uint>(source);
if (BitConverter.IsLittleEndian)
{
result = ReverseEndianness(result);
@@ -85,9 +86,9 @@ namespace System.Buffers.Binary
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ulong ReadUInt64BigEndian(ReadOnlySpan<byte> buffer)
+ public static ulong ReadUInt64BigEndian(ReadOnlySpan<byte> source)
{
- ulong result = ReadMachineEndian<ulong>(buffer);
+ ulong result = MemoryMarshal.Read<ulong>(source);
if (BitConverter.IsLittleEndian)
{
result = ReverseEndianness(result);
@@ -100,9 +101,9 @@ namespace System.Buffers.Binary
/// <returns>If the span is too small to contain an Int16, return false.</returns>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryReadInt16BigEndian(ReadOnlySpan<byte> buffer, out short value)
+ public static bool TryReadInt16BigEndian(ReadOnlySpan<byte> source, out short value)
{
- bool success = TryReadMachineEndian(buffer, out value);
+ bool success = MemoryMarshal.TryRead(source, out value);
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
@@ -115,9 +116,9 @@ namespace System.Buffers.Binary
/// <returns>If the span is too small to contain an Int32, return false.</returns>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryReadInt32BigEndian(ReadOnlySpan<byte> buffer, out int value)
+ public static bool TryReadInt32BigEndian(ReadOnlySpan<byte> source, out int value)
{
- bool success = TryReadMachineEndian(buffer, out value);
+ bool success = MemoryMarshal.TryRead(source, out value);
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
@@ -130,9 +131,9 @@ namespace System.Buffers.Binary
/// <returns>If the span is too small to contain an Int64, return false.</returns>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryReadInt64BigEndian(ReadOnlySpan<byte> buffer, out long value)
+ public static bool TryReadInt64BigEndian(ReadOnlySpan<byte> source, out long value)
{
- bool success = TryReadMachineEndian(buffer, out value);
+ bool success = MemoryMarshal.TryRead(source, out value);
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
@@ -146,9 +147,9 @@ namespace System.Buffers.Binary
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryReadUInt16BigEndian(ReadOnlySpan<byte> buffer, out ushort value)
+ public static bool TryReadUInt16BigEndian(ReadOnlySpan<byte> source, out ushort value)
{
- bool success = TryReadMachineEndian(buffer, out value);
+ bool success = MemoryMarshal.TryRead(source, out value);
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
@@ -162,9 +163,9 @@ namespace System.Buffers.Binary
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryReadUInt32BigEndian(ReadOnlySpan<byte> buffer, out uint value)
+ public static bool TryReadUInt32BigEndian(ReadOnlySpan<byte> source, out uint value)
{
- bool success = TryReadMachineEndian(buffer, out value);
+ bool success = MemoryMarshal.TryRead(source, out value);
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
@@ -178,9 +179,9 @@ namespace System.Buffers.Binary
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryReadUInt64BigEndian(ReadOnlySpan<byte> buffer, out ulong value)
+ public static bool TryReadUInt64BigEndian(ReadOnlySpan<byte> source, out ulong value)
{
- bool success = TryReadMachineEndian(buffer, out value);
+ bool success = MemoryMarshal.TryRead(source, out value);
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
diff --git a/src/System.Memory/src/System/Buffers/Binary/ReaderLittleEndian.cs b/src/System.Memory/src/System/Buffers/Binary/ReaderLittleEndian.cs
index 17cebf1f27..bd832f8995 100644
--- a/src/System.Memory/src/System/Buffers/Binary/ReaderLittleEndian.cs
+++ b/src/System.Memory/src/System/Buffers/Binary/ReaderLittleEndian.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
namespace System.Buffers.Binary
{
@@ -12,9 +13,9 @@ namespace System.Buffers.Binary
/// Reads an Int16 out of a read-only span of bytes as little endian.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static short ReadInt16LittleEndian(ReadOnlySpan<byte> buffer)
+ public static short ReadInt16LittleEndian(ReadOnlySpan<byte> source)
{
- short result = ReadMachineEndian<short>(buffer);
+ short result = MemoryMarshal.Read<short>(source);
if (!BitConverter.IsLittleEndian)
{
result = ReverseEndianness(result);
@@ -26,9 +27,9 @@ namespace System.Buffers.Binary
/// Reads an Int32 out of a read-only span of bytes as little endian.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int ReadInt32LittleEndian(ReadOnlySpan<byte> buffer)
+ public static int ReadInt32LittleEndian(ReadOnlySpan<byte> source)
{
- int result = ReadMachineEndian<int>(buffer);
+ int result = MemoryMarshal.Read<int>(source);
if (!BitConverter.IsLittleEndian)
{
result = ReverseEndianness(result);
@@ -40,9 +41,9 @@ namespace System.Buffers.Binary
/// Reads an Int64 out of a read-only span of bytes as little endian.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static long ReadInt64LittleEndian(ReadOnlySpan<byte> buffer)
+ public static long ReadInt64LittleEndian(ReadOnlySpan<byte> source)
{
- long result = ReadMachineEndian<long>(buffer);
+ long result = MemoryMarshal.Read<long>(source);
if (!BitConverter.IsLittleEndian)
{
result = ReverseEndianness(result);
@@ -55,9 +56,9 @@ namespace System.Buffers.Binary
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ushort ReadUInt16LittleEndian(ReadOnlySpan<byte> buffer)
+ public static ushort ReadUInt16LittleEndian(ReadOnlySpan<byte> source)
{
- ushort result = ReadMachineEndian<ushort>(buffer);
+ ushort result = MemoryMarshal.Read<ushort>(source);
if (!BitConverter.IsLittleEndian)
{
result = ReverseEndianness(result);
@@ -70,9 +71,9 @@ namespace System.Buffers.Binary
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static uint ReadUInt32LittleEndian(ReadOnlySpan<byte> buffer)
+ public static uint ReadUInt32LittleEndian(ReadOnlySpan<byte> source)
{
- uint result = ReadMachineEndian<uint>(buffer);
+ uint result = MemoryMarshal.Read<uint>(source);
if (!BitConverter.IsLittleEndian)
{
result = ReverseEndianness(result);
@@ -85,9 +86,9 @@ namespace System.Buffers.Binary
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ulong ReadUInt64LittleEndian(ReadOnlySpan<byte> buffer)
+ public static ulong ReadUInt64LittleEndian(ReadOnlySpan<byte> source)
{
- ulong result = ReadMachineEndian<ulong>(buffer);
+ ulong result = MemoryMarshal.Read<ulong>(source);
if (!BitConverter.IsLittleEndian)
{
result = ReverseEndianness(result);
@@ -100,9 +101,9 @@ namespace System.Buffers.Binary
/// <returns>If the span is too small to contain an Int16, return false.</returns>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryReadInt16LittleEndian(ReadOnlySpan<byte> buffer, out short value)
+ public static bool TryReadInt16LittleEndian(ReadOnlySpan<byte> source, out short value)
{
- bool success = TryReadMachineEndian(buffer, out value);
+ bool success = MemoryMarshal.TryRead(source, out value);
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
@@ -115,9 +116,9 @@ namespace System.Buffers.Binary
/// <returns>If the span is too small to contain an Int32, return false.</returns>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryReadInt32LittleEndian(ReadOnlySpan<byte> buffer, out int value)
+ public static bool TryReadInt32LittleEndian(ReadOnlySpan<byte> source, out int value)
{
- bool success = TryReadMachineEndian(buffer, out value);
+ bool success = MemoryMarshal.TryRead(source, out value);
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
@@ -130,9 +131,9 @@ namespace System.Buffers.Binary
/// <returns>If the span is too small to contain an Int64, return false.</returns>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryReadInt64LittleEndian(ReadOnlySpan<byte> buffer, out long value)
+ public static bool TryReadInt64LittleEndian(ReadOnlySpan<byte> source, out long value)
{
- bool success = TryReadMachineEndian(buffer, out value);
+ bool success = MemoryMarshal.TryRead(source, out value);
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
@@ -146,9 +147,9 @@ namespace System.Buffers.Binary
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryReadUInt16LittleEndian(ReadOnlySpan<byte> buffer, out ushort value)
+ public static bool TryReadUInt16LittleEndian(ReadOnlySpan<byte> source, out ushort value)
{
- bool success = TryReadMachineEndian(buffer, out value);
+ bool success = MemoryMarshal.TryRead(source, out value);
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
@@ -162,9 +163,9 @@ namespace System.Buffers.Binary
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryReadUInt32LittleEndian(ReadOnlySpan<byte> buffer, out uint value)
+ public static bool TryReadUInt32LittleEndian(ReadOnlySpan<byte> source, out uint value)
{
- bool success = TryReadMachineEndian(buffer, out value);
+ bool success = MemoryMarshal.TryRead(source, out value);
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
@@ -178,9 +179,9 @@ namespace System.Buffers.Binary
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryReadUInt64LittleEndian(ReadOnlySpan<byte> buffer, out ulong value)
+ public static bool TryReadUInt64LittleEndian(ReadOnlySpan<byte> source, out ulong value)
{
- bool success = TryReadMachineEndian(buffer, out value);
+ bool success = MemoryMarshal.TryRead(source, out value);
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
diff --git a/src/System.Memory/src/System/Buffers/Binary/Writer.cs b/src/System.Memory/src/System/Buffers/Binary/Writer.cs
deleted file mode 100644
index fe59623138..0000000000
--- a/src/System.Memory/src/System/Buffers/Binary/Writer.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-#if !netstandard
-using Internal.Runtime.CompilerServices;
-#endif
-
-namespace System.Buffers.Binary
-{
- public static partial class BinaryPrimitives
- {
- /// <summary>
- /// Writes a structure of type T into a span of bytes.
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void WriteMachineEndian<T>(Span<byte> buffer, ref T value)
- where T : struct
- {
-#if netstandard
- if (SpanHelpers.IsReferenceOrContainsReferences<T>())
- {
- ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T));
- }
-#else
- if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
- {
- ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T));
- }
-#endif
- if ((uint)Unsafe.SizeOf<T>() > (uint)buffer.Length)
- {
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length);
- }
- Unsafe.WriteUnaligned<T>(ref MemoryMarshal.GetReference(buffer), value);
- }
-
- /// <summary>
- /// Writes a structure of type T into a span of bytes.
- /// <returns>If the span is too small to contain the type T, return false.</returns>
- /// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryWriteMachineEndian<T>(Span<byte> buffer, ref T value)
- where T : struct
- {
-#if netstandard
- if (SpanHelpers.IsReferenceOrContainsReferences<T>())
- {
- ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T));
- }
-#else
- if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
- {
- ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T));
- }
-#endif
- if (Unsafe.SizeOf<T>() > (uint)buffer.Length)
- {
- return false;
- }
- Unsafe.WriteUnaligned<T>(ref MemoryMarshal.GetReference(buffer), value);
- return true;
- }
- }
-}
-
diff --git a/src/System.Memory/src/System/Buffers/Binary/WriterBigEndian.cs b/src/System.Memory/src/System/Buffers/Binary/WriterBigEndian.cs
index fa7228ba3b..78be9b5a03 100644
--- a/src/System.Memory/src/System/Buffers/Binary/WriterBigEndian.cs
+++ b/src/System.Memory/src/System/Buffers/Binary/WriterBigEndian.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
namespace System.Buffers.Binary
{
@@ -12,39 +13,39 @@ namespace System.Buffers.Binary
/// Writes an Int16 into a span of bytes as big endian.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void WriteInt16BigEndian(Span<byte> buffer, short value)
+ public static void WriteInt16BigEndian(Span<byte> destination, short value)
{
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
- WriteMachineEndian(buffer, ref value);
+ MemoryMarshal.Write(destination, ref value);
}
/// <summary>
/// Writes an Int32 into a span of bytes as big endian.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void WriteInt32BigEndian(Span<byte> buffer, int value)
+ public static void WriteInt32BigEndian(Span<byte> destination, int value)
{
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
- WriteMachineEndian(buffer, ref value);
+ MemoryMarshal.Write(destination, ref value);
}
/// <summary>
/// Writes an Int64 into a span of bytes as big endian.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void WriteInt64BigEndian(Span<byte> buffer, long value)
+ public static void WriteInt64BigEndian(Span<byte> destination, long value)
{
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
- WriteMachineEndian(buffer, ref value);
+ MemoryMarshal.Write(destination, ref value);
}
/// <summary>
@@ -52,13 +53,13 @@ namespace System.Buffers.Binary
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void WriteUInt16BigEndian(Span<byte> buffer, ushort value)
+ public static void WriteUInt16BigEndian(Span<byte> destination, ushort value)
{
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
- WriteMachineEndian(buffer, ref value);
+ MemoryMarshal.Write(destination, ref value);
}
/// <summary>
@@ -66,13 +67,13 @@ namespace System.Buffers.Binary
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void WriteUInt32BigEndian(Span<byte> buffer, uint value)
+ public static void WriteUInt32BigEndian(Span<byte> destination, uint value)
{
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
- WriteMachineEndian(buffer, ref value);
+ MemoryMarshal.Write(destination, ref value);
}
/// <summary>
@@ -80,13 +81,13 @@ namespace System.Buffers.Binary
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void WriteUInt64BigEndian(Span<byte> buffer, ulong value)
+ public static void WriteUInt64BigEndian(Span<byte> destination, ulong value)
{
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
- WriteMachineEndian(buffer, ref value);
+ MemoryMarshal.Write(destination, ref value);
}
/// <summary>
@@ -94,13 +95,13 @@ namespace System.Buffers.Binary
/// <returns>If the span is too small to contain the value, return false.</returns>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryWriteInt16BigEndian(Span<byte> buffer, short value)
+ public static bool TryWriteInt16BigEndian(Span<byte> destination, short value)
{
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
- return TryWriteMachineEndian(buffer, ref value);
+ return MemoryMarshal.TryWrite(destination, ref value);
}
/// <summary>
@@ -108,13 +109,13 @@ namespace System.Buffers.Binary
/// <returns>If the span is too small to contain the value, return false.</returns>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryWriteInt32BigEndian(Span<byte> buffer, int value)
+ public static bool TryWriteInt32BigEndian(Span<byte> destination, int value)
{
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
- return TryWriteMachineEndian(buffer, ref value);
+ return MemoryMarshal.TryWrite(destination, ref value);
}
/// <summary>
@@ -122,13 +123,13 @@ namespace System.Buffers.Binary
/// <returns>If the span is too small to contain the value, return false.</returns>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryWriteInt64BigEndian(Span<byte> buffer, long value)
+ public static bool TryWriteInt64BigEndian(Span<byte> destination, long value)
{
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
- return TryWriteMachineEndian(buffer, ref value);
+ return MemoryMarshal.TryWrite(destination, ref value);
}
/// <summary>
@@ -137,13 +138,13 @@ namespace System.Buffers.Binary
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryWriteUInt16BigEndian(Span<byte> buffer, ushort value)
+ public static bool TryWriteUInt16BigEndian(Span<byte> destination, ushort value)
{
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
- return TryWriteMachineEndian(buffer, ref value);
+ return MemoryMarshal.TryWrite(destination, ref value);
}
/// <summary>
@@ -152,13 +153,13 @@ namespace System.Buffers.Binary
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryWriteUInt32BigEndian(Span<byte> buffer, uint value)
+ public static bool TryWriteUInt32BigEndian(Span<byte> destination, uint value)
{
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
- return TryWriteMachineEndian(buffer, ref value);
+ return MemoryMarshal.TryWrite(destination, ref value);
}
/// <summary>
@@ -167,13 +168,13 @@ namespace System.Buffers.Binary
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryWriteUInt64BigEndian(Span<byte> buffer, ulong value)
+ public static bool TryWriteUInt64BigEndian(Span<byte> destination, ulong value)
{
if (BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
- return TryWriteMachineEndian(buffer, ref value);
+ return MemoryMarshal.TryWrite(destination, ref value);
}
}
}
diff --git a/src/System.Memory/src/System/Buffers/Binary/WriterLittleEndian.cs b/src/System.Memory/src/System/Buffers/Binary/WriterLittleEndian.cs
index 22bbe070eb..5d63ee5f0b 100644
--- a/src/System.Memory/src/System/Buffers/Binary/WriterLittleEndian.cs
+++ b/src/System.Memory/src/System/Buffers/Binary/WriterLittleEndian.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
namespace System.Buffers.Binary
{
@@ -12,39 +13,39 @@ namespace System.Buffers.Binary
/// Writes an Int16 into a span of bytes as little endian.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void WriteInt16LittleEndian(Span<byte> buffer, short value)
+ public static void WriteInt16LittleEndian(Span<byte> destination, short value)
{
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
- WriteMachineEndian(buffer, ref value);
+ MemoryMarshal.Write(destination, ref value);
}
/// <summary>
/// Writes an Int32 into a span of bytes as little endian.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void WriteInt32LittleEndian(Span<byte> buffer, int value)
+ public static void WriteInt32LittleEndian(Span<byte> destination, int value)
{
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
- WriteMachineEndian(buffer, ref value);
+ MemoryMarshal.Write(destination, ref value);
}
/// <summary>
/// Writes an Int64 into a span of bytes as little endian.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void WriteInt64LittleEndian(Span<byte> buffer, long value)
+ public static void WriteInt64LittleEndian(Span<byte> destination, long value)
{
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
- WriteMachineEndian(buffer, ref value);
+ MemoryMarshal.Write(destination, ref value);
}
/// <summary>
@@ -52,13 +53,13 @@ namespace System.Buffers.Binary
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void WriteUInt16LittleEndian(Span<byte> buffer, ushort value)
+ public static void WriteUInt16LittleEndian(Span<byte> destination, ushort value)
{
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
- WriteMachineEndian(buffer, ref value);
+ MemoryMarshal.Write(destination, ref value);
}
/// <summary>
@@ -66,13 +67,13 @@ namespace System.Buffers.Binary
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void WriteUInt32LittleEndian(Span<byte> buffer, uint value)
+ public static void WriteUInt32LittleEndian(Span<byte> destination, uint value)
{
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
- WriteMachineEndian(buffer, ref value);
+ MemoryMarshal.Write(destination, ref value);
}
/// <summary>
@@ -80,13 +81,13 @@ namespace System.Buffers.Binary
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void WriteUInt64LittleEndian(Span<byte> buffer, ulong value)
+ public static void WriteUInt64LittleEndian(Span<byte> destination, ulong value)
{
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
- WriteMachineEndian(buffer, ref value);
+ MemoryMarshal.Write(destination, ref value);
}
/// <summary>
@@ -94,13 +95,13 @@ namespace System.Buffers.Binary
/// <returns>If the span is too small to contain the value, return false.</returns>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryWriteInt16LittleEndian(Span<byte> buffer, short value)
+ public static bool TryWriteInt16LittleEndian(Span<byte> destination, short value)
{
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
- return TryWriteMachineEndian(buffer, ref value);
+ return MemoryMarshal.TryWrite(destination, ref value);
}
/// <summary>
@@ -108,13 +109,13 @@ namespace System.Buffers.Binary
/// <returns>If the span is too small to contain the value, return false.</returns>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryWriteInt32LittleEndian(Span<byte> buffer, int value)
+ public static bool TryWriteInt32LittleEndian(Span<byte> destination, int value)
{
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
- return TryWriteMachineEndian(buffer, ref value);
+ return MemoryMarshal.TryWrite(destination, ref value);
}
/// <summary>
@@ -122,13 +123,13 @@ namespace System.Buffers.Binary
/// <returns>If the span is too small to contain the value, return false.</returns>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryWriteInt64LittleEndian(Span<byte> buffer, long value)
+ public static bool TryWriteInt64LittleEndian(Span<byte> destination, long value)
{
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
- return TryWriteMachineEndian(buffer, ref value);
+ return MemoryMarshal.TryWrite(destination, ref value);
}
/// <summary>
@@ -137,13 +138,13 @@ namespace System.Buffers.Binary
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryWriteUInt16LittleEndian(Span<byte> buffer, ushort value)
+ public static bool TryWriteUInt16LittleEndian(Span<byte> destination, ushort value)
{
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
- return TryWriteMachineEndian(buffer, ref value);
+ return MemoryMarshal.TryWrite(destination, ref value);
}
/// <summary>
@@ -152,13 +153,13 @@ namespace System.Buffers.Binary
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryWriteUInt32LittleEndian(Span<byte> buffer, uint value)
+ public static bool TryWriteUInt32LittleEndian(Span<byte> destination, uint value)
{
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
- return TryWriteMachineEndian(buffer, ref value);
+ return MemoryMarshal.TryWrite(destination, ref value);
}
/// <summary>
@@ -167,13 +168,13 @@ namespace System.Buffers.Binary
/// </summary>
[CLSCompliant(false)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool TryWriteUInt64LittleEndian(Span<byte> buffer, ulong value)
+ public static bool TryWriteUInt64LittleEndian(Span<byte> destination, ulong value)
{
if (!BitConverter.IsLittleEndian)
{
value = ReverseEndianness(value);
}
- return TryWriteMachineEndian(buffer, ref value);
+ return MemoryMarshal.TryWrite(destination, ref value);
}
}
}
diff --git a/src/System.Memory/src/System/Buffers/BuffersExtensions.cs b/src/System.Memory/src/System/Buffers/BuffersExtensions.cs
new file mode 100644
index 0000000000..7d0cc472aa
--- /dev/null
+++ b/src/System.Memory/src/System/Buffers/BuffersExtensions.cs
@@ -0,0 +1,141 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Buffers
+{
+ /// <summary>
+ /// Extension methods for <see cref="ReadOnlySequence{T}"/>
+ /// </summary>
+ public static class BuffersExtensions
+ {
+ /// <summary>
+ /// Returns position of first occurrence of item in the <see cref="ReadOnlySequence{T}"/>
+ /// </summary>
+ public static SequencePosition? PositionOf<T>(in this ReadOnlySequence<T> source, T value) where T : IEquatable<T>
+ {
+ if (source.IsSingleSegment)
+ {
+ int index = source.First.Span.IndexOf(value);
+ if (index != -1)
+ {
+ return source.GetPosition(index);
+ }
+
+ return null;
+ }
+ else
+ {
+ return PositionOfMultiSegement(source, value);
+ }
+ }
+
+ private static SequencePosition? PositionOfMultiSegement<T>(in ReadOnlySequence<T> source, T value) where T : IEquatable<T>
+ {
+ SequencePosition position = source.Start;
+ SequencePosition result = position;
+ while (source.TryGet(ref position, out ReadOnlyMemory<T> memory))
+ {
+ int index = memory.Span.IndexOf(value);
+ if (index != -1)
+ {
+ return source.GetPosition(index, result);
+ }
+ else if (position.GetObject() == null)
+ {
+ break;
+ }
+
+ result = position;
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Copy the <see cref="ReadOnlySequence{T}"/> to the specified <see cref="Span{Byte}"/>.
+ /// </summary>
+ /// <param name="source">The source <see cref="ReadOnlySequence{T}"/>.</param>
+ /// <param name="destination">The destination <see cref="Span{Byte}"/>.</param>
+ public static void CopyTo<T>(in this ReadOnlySequence<T> source, Span<T> destination)
+ {
+ if (source.Length > destination.Length)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.destination);
+
+ if (source.IsSingleSegment)
+ {
+ source.First.Span.CopyTo(destination);
+ }
+ else
+ {
+ CopyToMultiSegement(source, destination);
+ }
+ }
+
+ private static void CopyToMultiSegement<T>(in ReadOnlySequence<T> sequence, Span<T> destination)
+ {
+ SequencePosition position = sequence.Start;
+ while (sequence.TryGet(ref position, out ReadOnlyMemory<T> memory))
+ {
+ ReadOnlySpan<T> span = memory.Span;
+ span.CopyTo(destination);
+ if (position.GetObject() != null)
+ {
+ destination = destination.Slice(span.Length);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Converts the <see cref="ReadOnlySequence{T}"/> to an array
+ /// </summary>
+ public static T[] ToArray<T>(in this ReadOnlySequence<T> sequence)
+ {
+ var array = new T[sequence.Length];
+ sequence.CopyTo(array);
+ return array;
+ }
+
+ /// <summary>
+ /// Writes contents of <paramref name="value"/> to <paramref name="writer"/>
+ /// </summary>
+ public static void Write<T>(this IBufferWriter<T> writer, ReadOnlySpan<T> value)
+ {
+ Span<T> destination = writer.GetSpan();
+
+ // Fast path, try copying to the available memory directly
+ if (value.Length <= destination.Length)
+ {
+ value.CopyTo(destination);
+ writer.Advance(value.Length);
+ }
+ else
+ {
+ WriteMultiSegment(writer, value, destination);
+ }
+ }
+
+ private static void WriteMultiSegment<T>(IBufferWriter<T> writer, in ReadOnlySpan<T> source, Span<T> destination)
+ {
+ ReadOnlySpan<T> input = source;
+ while (true)
+ {
+ int writeSize = Math.Min(destination.Length, input.Length);
+ input.Slice(0, writeSize).CopyTo(destination);
+ writer.Advance(writeSize);
+ input = input.Slice(writeSize);
+ if (input.Length > 0)
+ {
+ destination = writer.GetSpan(input.Length);
+ continue;
+ }
+
+ return;
+ }
+ }
+ }
+}
diff --git a/src/System.Memory/src/System/Buffers/IBufferWriter.cs b/src/System.Memory/src/System/Buffers/IBufferWriter.cs
new file mode 100644
index 0000000000..de5ea408db
--- /dev/null
+++ b/src/System.Memory/src/System/Buffers/IBufferWriter.cs
@@ -0,0 +1,28 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace System.Buffers
+{
+ /// <summary>
+ /// Represents a <typeparam name="T"/> sink
+ /// </summary>
+ public interface IBufferWriter<T>
+ {
+ /// <summary>
+ /// Notifies <see cref="IBufferWriter{T}"/> that <paramref name="count"/> amount of data was written to <see cref="Span{T}"/>/<see cref="Memory{T}"/>
+ /// </summary>
+ void Advance(int count);
+
+ /// <summary>
+ /// Requests the <see cref="Memory{T}"/> that is at least <paramref name="sizeHint"/> in size if possible, otherwise returns maximum available memory.
+ /// If <paramref name="sizeHint"/> is equal to <code>0</code>, currently available memory would get returned.
+ /// </summary>
+ Memory<T> GetMemory(int sizeHint = 0);
+
+ /// <summary>
+ /// Requests the <see cref="Span{T}"/> that is at least <paramref name="sizeHint"/> in size if possible, otherwise returns maximum available memory.
+ /// If <paramref name="sizeHint"/> is equal to <code>0</code>, currently available memory would get returned.
+ /// </summary>
+ Span<T> GetSpan(int sizeHint = 0);
+ }
+}
diff --git a/src/System.Memory/src/System/Buffers/MemoryPool.cs b/src/System.Memory/src/System/Buffers/MemoryPool.cs
new file mode 100644
index 0000000000..febe988ccc
--- /dev/null
+++ b/src/System.Memory/src/System/Buffers/MemoryPool.cs
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Buffers
+{
+ /// <summary>
+ /// Represents a pool of memory blocks.
+ /// </summary>
+ public abstract class MemoryPool<T> : IDisposable
+ {
+ private static readonly MemoryPool<T> s_shared = new ArrayMemoryPool<T>();
+
+ /// <summary>
+ /// Returns a singleton instance of a MemoryPool based on arrays.
+ /// </summary>
+ public static MemoryPool<T> Shared => s_shared;
+
+ /// <summary>
+ /// Returns a memory block capable of holding at least <paramref name="minBufferSize" /> elements of T.
+ /// </summary>
+ /// <param name="minBufferSize">If -1 is passed, this is set to a default value for the pool.</param>
+ public abstract OwnedMemory<T> Rent(int minBufferSize = -1);
+
+ /// <summary>
+ /// Returns the maximum buffer size supported by this pool.
+ /// </summary>
+ public abstract int MaxBufferSize { get; }
+
+ /// <summary>
+ /// Constructs a new instance of a memory pool.
+ /// </summary>
+ protected MemoryPool() { }
+
+ /// <summary>
+ /// Frees all resources used by the memory pool.
+ /// </summary>
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ /// <summary>
+ /// Frees all resources used by the memory pool.
+ /// </summary>
+ /// <param name="disposing"></param>
+ protected abstract void Dispose(bool disposing);
+ }
+}
diff --git a/src/System.Memory/src/System/Buffers/ReadOnlySequence.cs b/src/System.Memory/src/System/Buffers/ReadOnlySequence.cs
new file mode 100644
index 0000000000..64ccf639d9
--- /dev/null
+++ b/src/System.Memory/src/System/Buffers/ReadOnlySequence.cs
@@ -0,0 +1,454 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace System.Buffers
+{
+ /// <summary>
+ /// Represents a sequence that can read a sequential series of <typeparam name="T" />.
+ /// </summary>
+ public readonly partial struct ReadOnlySequence<T>
+ {
+ private readonly SequencePosition _sequenceStart;
+ private readonly SequencePosition _sequenceEnd;
+
+ /// <summary>
+ /// Returns empty <see cref="ReadOnlySequence{T}"/>
+ /// </summary>
+#if FEATURE_PORTABLE_SPAN
+ public static readonly ReadOnlySequence<T> Empty = new ReadOnlySequence<T>(SpanHelpers.PerTypeValues<T>.EmptyArray);
+#else
+ public static readonly ReadOnlySequence<T> Empty = new ReadOnlySequence<T>(Array.Empty<T>());
+#endif // FEATURE_PORTABLE_SPAN
+
+ /// <summary>
+ /// Length of the <see cref="ReadOnlySequence{T}"/>.
+ /// </summary>
+ public long Length => GetLength(_sequenceStart, _sequenceEnd);
+
+ /// <summary>
+ /// Determines if the <see cref="ReadOnlySequence{T}"/> is empty.
+ /// </summary>
+ public bool IsEmpty => Length == 0;
+
+ /// <summary>
+ /// Determines if the <see cref="ReadOnlySequence{T}"/> contains a single <see cref="ReadOnlyMemory{T}"/> segment.
+ /// </summary>
+ public bool IsSingleSegment
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _sequenceStart.GetObject() == _sequenceEnd.GetObject();
+ }
+
+ /// <summary>
+ /// Gets <see cref="ReadOnlyMemory{T}"/> from the first segment.
+ /// </summary>
+ public ReadOnlyMemory<T> First => GetFirstBuffer(_sequenceStart, _sequenceEnd);
+
+ /// <summary>
+ /// A position to the start of the <see cref="ReadOnlySequence{T}"/>.
+ /// </summary>
+ public SequencePosition Start => _sequenceStart;
+
+ /// <summary>
+ /// A position to the end of the <see cref="ReadOnlySequence{T}"/>
+ /// </summary>
+ public SequencePosition End => _sequenceEnd;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private ReadOnlySequence(object startSegment, int startIndexAndFlags, object endSegment, int endIndexAndFlags)
+ {
+ // Used by SliceImpl to create new ReadOnlySequence
+ Debug.Assert(startSegment != null);
+ Debug.Assert(endSegment != null);
+
+ _sequenceStart = new SequencePosition(startSegment, startIndexAndFlags);
+ _sequenceEnd = new SequencePosition(endSegment, endIndexAndFlags);
+ }
+
+ /// <summary>
+ /// Creates an instance of <see cref="ReadOnlySequence{T}"/> from linked memory list represented by start and end segments
+ /// and corresponding indexes in them.
+ /// </summary>
+ public ReadOnlySequence(ReadOnlySequenceSegment<T> startSegment, int startIndex, ReadOnlySequenceSegment<T> endSegment, int endIndex)
+ {
+ if (startSegment == null ||
+ endSegment == null ||
+ (uint)startSegment.Memory.Length < (uint)startIndex ||
+ (uint)endSegment.Memory.Length < (uint)endIndex ||
+ (startSegment == endSegment && endIndex < startIndex))
+ ThrowHelper.ThrowArgumentValidationException(startSegment, startIndex, endSegment);
+
+ _sequenceStart = new SequencePosition(startSegment, ReadOnlySequence.SegmentToSequenceStart(startIndex));
+ _sequenceEnd = new SequencePosition(endSegment, ReadOnlySequence.SegmentToSequenceEnd(endIndex));
+ }
+
+ /// <summary>
+ /// Creates an instance of <see cref="ReadOnlySequence{T}"/> from the <see cref="T:T[]"/>.
+ /// </summary>
+ public ReadOnlySequence(T[] array)
+ {
+ if (array == null)
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
+
+ _sequenceStart = new SequencePosition(array, ReadOnlySequence.ArrayToSequenceStart(0));
+ _sequenceEnd = new SequencePosition(array, ReadOnlySequence.ArrayToSequenceEnd(array.Length));
+ }
+
+ /// <summary>
+ /// Creates an instance of <see cref="ReadOnlySequence{T}"/> from the <see cref="T:T[]"/>, start and index.
+ /// </summary>
+ public ReadOnlySequence(T[] array, int start, int length)
+ {
+ if (array == null ||
+ (uint)start > (uint)array.Length ||
+ (uint)length > (uint)(array.Length - start))
+ ThrowHelper.ThrowArgumentValidationException(array, start);
+
+ _sequenceStart = new SequencePosition(array, ReadOnlySequence.ArrayToSequenceStart(start));
+ _sequenceEnd = new SequencePosition(array, ReadOnlySequence.ArrayToSequenceEnd(start + length));
+ }
+
+ /// <summary>
+ /// Creates an instance of <see cref="ReadOnlySequence{T}"/> from the <see cref="ReadOnlyMemory{T}"/>.
+ /// Consumer is expected to manage lifetime of memory until <see cref="ReadOnlySequence{T}"/> is not used anymore.
+ /// </summary>
+ public ReadOnlySequence(ReadOnlyMemory<T> memory)
+ {
+ if (MemoryMarshal.TryGetOwnedMemory(memory, out OwnedMemory<T> ownedMemory, out int index, out int length))
+ {
+ _sequenceStart = new SequencePosition(ownedMemory, ReadOnlySequence.OwnedMemoryToSequenceStart(index));
+ _sequenceEnd = new SequencePosition(ownedMemory, ReadOnlySequence.OwnedMemoryToSequenceEnd(length));
+ }
+ else if (MemoryMarshal.TryGetArray(memory, out ArraySegment<T> segment))
+ {
+ T[] array = segment.Array;
+ int start = segment.Offset;
+ _sequenceStart = new SequencePosition(array, ReadOnlySequence.ArrayToSequenceStart(start));
+ _sequenceEnd = new SequencePosition(array, ReadOnlySequence.ArrayToSequenceEnd(start + segment.Count));
+ }
+ else if (typeof(T) == typeof(char))
+ {
+ if (!MemoryMarshal.TryGetString(((ReadOnlyMemory<char>)(object)memory), out string text, out int start, out length))
+ ThrowHelper.ThrowInvalidOperationException();
+
+ _sequenceStart = new SequencePosition(text, ReadOnlySequence.StringToSequenceStart(start));
+ _sequenceEnd = new SequencePosition(text, ReadOnlySequence.StringToSequenceEnd(start + length));
+ }
+ else
+ {
+ // Should never be reached
+ ThrowHelper.ThrowInvalidOperationException();
+ _sequenceStart = default;
+ _sequenceEnd = default;
+ }
+ }
+
+ /// <summary>
+ /// Creates an instance of <see cref="ReadOnlySequence{T}"/> from the <see cref="OwnedMemory{T}"/>.
+ /// Consumer is expected to manage lifetime of memory until <see cref="ReadOnlySequence{T}"/> is not used anymore.
+ /// </summary>
+ public ReadOnlySequence(OwnedMemory<T> ownedMemory)
+ {
+ if (ownedMemory == null)
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.ownedMemory);
+
+ _sequenceStart = new SequencePosition(ownedMemory, ReadOnlySequence.OwnedMemoryToSequenceStart(0));
+ _sequenceEnd = new SequencePosition(ownedMemory, ReadOnlySequence.OwnedMemoryToSequenceEnd(ownedMemory.Length));
+ }
+
+ /// <summary>
+ /// Creates an instance of <see cref="ReadOnlySequence{T}"/> from the <see cref="OwnedMemory{T}"/>, start and length.
+ /// Consumer is expected to manage lifetime of memory until <see cref="ReadOnlySequence{T}"/> is not used anymore.
+ /// </summary>
+ public ReadOnlySequence(OwnedMemory<T> ownedMemory, int start, int length)
+ {
+ if (ownedMemory == null ||
+ (uint)start > (uint)ownedMemory.Length ||
+ (uint)length > (uint)(ownedMemory.Length - start))
+ ThrowHelper.ThrowArgumentValidationException(ownedMemory, start);
+
+ _sequenceStart = new SequencePosition(ownedMemory, ReadOnlySequence.OwnedMemoryToSequenceStart(start));
+ _sequenceEnd = new SequencePosition(ownedMemory, ReadOnlySequence.OwnedMemoryToSequenceEnd(start + length));
+ }
+
+ /// <summary>
+ /// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, with <paramref name="length"/> items
+ /// </summary>
+ /// <param name="start">The index at which to begin this slice.</param>
+ /// <param name="length">The length of the slice</param>
+ public ReadOnlySequence<T> Slice(long start, long length)
+ {
+ SequencePosition begin = Seek(_sequenceStart, _sequenceEnd, start);
+ SequencePosition end = Seek(begin, _sequenceEnd, length);
+ return SliceImpl(begin, end);
+ }
+
+ /// <summary>
+ /// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, ending at <paramref name="end"/> (inclusive).
+ /// </summary>
+ /// <param name="start">The index at which to begin this slice.</param>
+ /// <param name="end">The end (inclusive) of the slice</param>
+ public ReadOnlySequence<T> Slice(long start, SequencePosition end)
+ {
+ BoundsCheck(end, _sequenceEnd);
+
+ SequencePosition begin = Seek(_sequenceStart, end, start);
+ object beginObject = begin.GetObject();
+ object endObject = end.GetObject();
+ if (beginObject != endObject)
+ {
+ CheckEndReachable(beginObject, endObject);
+ }
+ return SliceImpl(begin, end);
+ }
+
+ /// <summary>
+ /// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, with <paramref name="length"/> items
+ /// </summary>
+ /// <param name="start">The starting (inclusive) <see cref="SequencePosition"/> at which to begin this slice.</param>
+ /// <param name="length">The length of the slice</param>
+ public ReadOnlySequence<T> Slice(SequencePosition start, long length)
+ {
+ BoundsCheck(start, _sequenceEnd);
+
+ SequencePosition end = Seek(start, _sequenceEnd, length);
+ return SliceImpl(start, end);
+ }
+
+ /// <summary>
+ /// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, with <paramref name="length"/> items
+ /// </summary>
+ /// <param name="start">The index at which to begin this slice.</param>
+ /// <param name="length">The length of the slice</param>
+ public ReadOnlySequence<T> Slice(int start, int length)
+ {
+ SequencePosition begin = Seek(_sequenceStart, _sequenceEnd, start);
+ SequencePosition end = Seek(begin, _sequenceEnd, length);
+ return SliceImpl(begin, end);
+ }
+
+ /// <summary>
+ /// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, ending at <paramref name="end"/> (inclusive).
+ /// </summary>
+ /// <param name="start">The index at which to begin this slice.</param>
+ /// <param name="end">The end (inclusive) of the slice</param>
+ public ReadOnlySequence<T> Slice(int start, SequencePosition end)
+ {
+ BoundsCheck(end, _sequenceEnd);
+
+ SequencePosition begin = Seek(_sequenceStart, end, start);
+ object beginObject = begin.GetObject();
+ object endObject = end.GetObject();
+ if (beginObject != endObject)
+ {
+ CheckEndReachable(beginObject, endObject);
+ }
+ return SliceImpl(begin, end);
+ }
+
+ /// <summary>
+ /// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at '<paramref name="start"/>, with <paramref name="length"/> items
+ /// </summary>
+ /// <param name="start">The starting (inclusive) <see cref="SequencePosition"/> at which to begin this slice.</param>
+ /// <param name="length">The length of the slice</param>
+ public ReadOnlySequence<T> Slice(SequencePosition start, int length)
+ {
+ BoundsCheck(start, _sequenceEnd);
+
+ SequencePosition end = Seek(start, _sequenceEnd, length);
+ return SliceImpl(start, end);
+ }
+
+ /// <summary>
+ /// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, ending at <paramref name="end"/> (inclusive).
+ /// </summary>
+ /// <param name="start">The starting (inclusive) <see cref="SequencePosition"/> at which to begin this slice.</param>
+ /// <param name="end">The ending (inclusive) <see cref="SequencePosition"/> of the slice</param>
+ public ReadOnlySequence<T> Slice(SequencePosition start, SequencePosition end)
+ {
+ BoundsCheck(end, _sequenceEnd);
+ BoundsCheck(start, end);
+
+ return SliceImpl(start, end);
+ }
+
+ /// <summary>
+ /// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, ending at the existing <see cref="ReadOnlySequence{T}"/>'s end.
+ /// </summary>
+ /// <param name="start">The starting (inclusive) <see cref="SequencePosition"/> at which to begin this slice.</param>
+ public ReadOnlySequence<T> Slice(SequencePosition start)
+ {
+ BoundsCheck(start, _sequenceEnd);
+
+ return SliceImpl(start, _sequenceEnd);
+ }
+
+ /// <summary>
+ /// Forms a slice out of the given <see cref="ReadOnlySequence{T}"/>, beginning at <paramref name="start"/>, ending at the existing <see cref="ReadOnlySequence{T}"/>'s end.
+ /// </summary>
+ /// <param name="start">The start index at which to begin this slice.</param>
+ public ReadOnlySequence<T> Slice(long start)
+ {
+ if (start == 0)
+ {
+ return this;
+ }
+
+ SequencePosition begin = Seek(_sequenceStart, _sequenceEnd, start);
+ return SliceImpl(begin, _sequenceEnd);
+ }
+
+ /// <inheritdoc />
+ public override string ToString() => string.Format("System.Buffers.ReadOnlySequence<{0}>[{1}]", typeof(T).Name, Length);
+
+ /// <summary>
+ /// Returns an enumerator over the <see cref="ReadOnlySequence{T}"/>
+ /// </summary>
+ public Enumerator GetEnumerator() => new Enumerator(this);
+
+ /// <summary>
+ /// Returns a new <see cref="SequencePosition"/> at an <paramref name="offset"/> from the start of the sequence.
+ /// </summary>
+ public SequencePosition GetPosition(long offset) => GetPosition(offset, _sequenceStart);
+
+ /// <summary>
+ /// Returns a new <see cref="SequencePosition"/> at an <paramref name="offset"/> from the <paramref name="origin"/>
+ /// </summary>
+ public SequencePosition GetPosition(long offset, SequencePosition origin)
+ {
+ if (offset < 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.offset);
+
+ return Seek(origin, _sequenceEnd, offset);
+ }
+
+ /// <summary>
+ /// Tries to retrieve next segment after <paramref name="position"/> and return its contents in <paramref name="memory"/>.
+ /// Returns <code>false</code> if end of <see cref="ReadOnlySequence{T}"/> was reached otherwise <code>true</code>.
+ /// Sets <paramref name="position"/> to the beginning of next segment if <paramref name="advance"/> is set to <code>true</code>.
+ /// </summary>
+ public bool TryGet(ref SequencePosition position, out ReadOnlyMemory<T> memory, bool advance = true)
+ {
+ bool result = TryGetBuffer(position, End, out memory, out SequencePosition next);
+ if (advance)
+ {
+ position = next;
+ }
+
+ return result;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private ReadOnlySequence<T> SliceImpl(in SequencePosition begin, in SequencePosition end)
+ {
+ // In this method we reset high order bits from indices
+ // of positions that were passed in
+ // and apply type bits specific for current ReadOnlySequence type
+
+ return new ReadOnlySequence<T>(
+ begin.GetObject(),
+ begin.GetInteger() & ReadOnlySequence.IndexBitMask | (Start.GetInteger() & ReadOnlySequence.FlagBitMask),
+ end.GetObject(),
+ end.GetInteger() & ReadOnlySequence.IndexBitMask | (End.GetInteger() & ReadOnlySequence.FlagBitMask)
+ );
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void GetTypeAndIndices(int start, int end, out SequenceType sequenceType, out int startIndex, out int endIndex)
+ {
+ startIndex = start & ReadOnlySequence.IndexBitMask;
+ endIndex = end & ReadOnlySequence.IndexBitMask;
+ // We take high order bits of two indexes index and move them
+ // to a first and second position to convert to BufferType
+ // Masking with 2 is required to only keep the second bit of Start.GetInteger()
+ sequenceType = Start.GetObject() == null ? SequenceType.Empty : (SequenceType)((((uint)Start.GetInteger() >> 30) & 2) | (uint)End.GetInteger() >> 31);
+ }
+
+ /// <summary>
+ /// An enumerator over the <see cref="ReadOnlySequence{T}"/>
+ /// </summary>
+ public struct Enumerator
+ {
+ private readonly ReadOnlySequence<T> _sequence;
+ private SequencePosition _next;
+ private ReadOnlyMemory<T> _currentMemory;
+
+ /// <summary>Initialize the enumerator.</summary>
+ /// <param name="sequence">The <see cref="ReadOnlySequence{T}"/> to enumerate.</param>
+ public Enumerator(in ReadOnlySequence<T> sequence)
+ {
+ _currentMemory = default;
+ _next = sequence.Start;
+ _sequence = sequence;
+ }
+
+ /// <summary>
+ /// The current <see cref="ReadOnlyMemory{T}"/>
+ /// </summary>
+ public ReadOnlyMemory<T> Current => _currentMemory;
+
+ /// <summary>
+ /// Moves to the next <see cref="ReadOnlyMemory{T}"/> in the <see cref="ReadOnlySequence{T}"/>
+ /// </summary>
+ /// <returns></returns>
+ public bool MoveNext()
+ {
+ if (_next.GetObject() == null)
+ {
+ return false;
+ }
+
+ return _sequence.TryGet(ref _next, out _currentMemory);
+ }
+ }
+
+ private enum SequenceType
+ {
+ MultiSegment = 0x00,
+ Array = 0x1,
+ OwnedMemory = 0x2,
+ String = 0x3,
+ Empty = 0x4
+ }
+ }
+
+ internal static class ReadOnlySequence
+ {
+ public const int FlagBitMask = 1 << 31;
+ public const int IndexBitMask = ~FlagBitMask;
+
+ public const int SegmentStartMask = 0;
+ public const int SegmentEndMask = 0;
+
+ public const int ArrayStartMask = 0;
+ public const int ArrayEndMask = FlagBitMask;
+
+ public const int OwnedMemoryStartMask = FlagBitMask;
+ public const int OwnedMemoryEndMask = 0;
+
+ public const int StringStartMask = FlagBitMask;
+ public const int StringEndMask = FlagBitMask;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int SegmentToSequenceStart(int startIndex) => startIndex | SegmentStartMask;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int SegmentToSequenceEnd(int endIndex) => endIndex | SegmentEndMask;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int ArrayToSequenceStart(int startIndex) => startIndex | ArrayStartMask;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int ArrayToSequenceEnd(int endIndex) => endIndex | ArrayEndMask;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int OwnedMemoryToSequenceStart(int startIndex) => startIndex | OwnedMemoryStartMask;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int OwnedMemoryToSequenceEnd(int endIndex) => endIndex | OwnedMemoryEndMask;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int StringToSequenceStart(int startIndex) => startIndex | StringStartMask;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int StringToSequenceEnd(int endIndex) => endIndex | StringEndMask;
+ }
+}
diff --git a/src/System.Memory/src/System/Buffers/ReadOnlySequenceSegment.cs b/src/System.Memory/src/System/Buffers/ReadOnlySequenceSegment.cs
new file mode 100644
index 0000000000..b04e84c6a5
--- /dev/null
+++ b/src/System.Memory/src/System/Buffers/ReadOnlySequenceSegment.cs
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Buffers
+{
+ /// <summary>
+ /// Represents a linked list of <see cref="ReadOnlyMemory{T}"/> nodes.
+ /// </summary>
+ public abstract class ReadOnlySequenceSegment<T>
+ {
+ /// <summary>
+ /// The <see cref="ReadOnlyMemory{T}"/> value for current node.
+ /// </summary>
+ public ReadOnlyMemory<T> Memory { get; protected set; }
+
+ /// <summary>
+ /// The next node.
+ /// </summary>
+ public ReadOnlySequenceSegment<T> Next { get; protected set; }
+
+ /// <summary>
+ /// The sum of node length before current.
+ /// </summary>
+ public long RunningIndex { get; protected set; }
+ }
+}
diff --git a/src/System.Memory/src/System/Buffers/ReadOnlySequence_helpers.cs b/src/System.Memory/src/System/Buffers/ReadOnlySequence_helpers.cs
new file mode 100644
index 0000000000..44c60e8e10
--- /dev/null
+++ b/src/System.Memory/src/System/Buffers/ReadOnlySequence_helpers.cs
@@ -0,0 +1,418 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+
+#if !netstandard
+using Internal.Runtime.CompilerServices;
+#endif
+
+namespace System.Buffers
+{
+ public readonly partial struct ReadOnlySequence<T>
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal bool TryGetBuffer(in SequencePosition start, in SequencePosition end, out ReadOnlyMemory<T> data, out SequencePosition next)
+ {
+ SequenceType type;
+ int startIndex = 0;
+ int endIndex = 0;
+ next = default;
+ object startObject = start.GetObject();
+ if (startObject != null)
+ {
+ GetTypeAndIndices(start.GetInteger(), end.GetInteger(), out type, out startIndex, out endIndex);
+ }
+ else
+ {
+ type = SequenceType.Empty;
+ }
+
+ int length = endIndex - startIndex;
+ object endObject = end.GetObject();
+
+ if (type != SequenceType.MultiSegment && type != SequenceType.Empty && startObject != endObject)
+ ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached();
+
+ if (type == SequenceType.MultiSegment)
+ {
+ Debug.Assert(startObject is ReadOnlySequenceSegment<T>);
+ ReadOnlySequenceSegment<T> startSegment = Unsafe.As<ReadOnlySequenceSegment<T>>(startObject);
+
+ data = startSegment.Memory;
+
+ if (startSegment != endObject)
+ {
+ ReadOnlySequenceSegment<T> nextSegment = startSegment.Next;
+
+ if (nextSegment == null && startSegment != endObject)
+ ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached();
+
+ next = new SequencePosition(nextSegment, 0);
+ length = data.Length - startIndex;
+ }
+ }
+ else if (type == SequenceType.Array)
+ {
+ Debug.Assert(startObject is T[]);
+
+ data = new ReadOnlyMemory<T>(Unsafe.As<T[]>(startObject));
+ }
+ else if (type == SequenceType.OwnedMemory)
+ {
+ Debug.Assert(startObject is OwnedMemory<T>);
+
+ data = (Unsafe.As<OwnedMemory<T>>(startObject)).Memory;
+ }
+ else if (typeof(T) == typeof(char) && type == SequenceType.String)
+ {
+ Debug.Assert(startObject is string);
+
+ data = (ReadOnlyMemory<T>)(object)(Unsafe.As<string>(startObject)).AsMemory();
+ }
+ else
+ {
+ data = default;
+ return false;
+ }
+
+ data = data.Slice(startIndex, length);
+ return true;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal ReadOnlyMemory<T> GetFirstBuffer(in SequencePosition start, in SequencePosition end)
+ {
+ SequenceType type;
+ int startIndex = 0;
+ int endIndex = 0;
+ object startObject = start.GetObject();
+ if (startObject != null)
+ {
+ GetTypeAndIndices(start.GetInteger(), end.GetInteger(), out type, out startIndex, out endIndex);
+ }
+ else
+ {
+ type = SequenceType.Empty;
+ }
+
+ int length = endIndex - startIndex;
+ object endObject = end.GetObject();
+
+ if (type != SequenceType.MultiSegment && type != SequenceType.Empty && startObject != endObject)
+ ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached();
+
+ ReadOnlyMemory<T> memory;
+ if (type == SequenceType.MultiSegment)
+ {
+ Debug.Assert(startObject is ReadOnlySequenceSegment<T>);
+ ReadOnlySequenceSegment<T> startSegment = Unsafe.As<ReadOnlySequenceSegment<T>>(startObject);
+ memory = startSegment.Memory;
+ if (startObject != endObject)
+ {
+ length = memory.Length - startIndex;
+ }
+ }
+ else if (type == SequenceType.Array)
+ {
+ Debug.Assert(startObject is T[]);
+
+ memory = new ReadOnlyMemory<T>(Unsafe.As<T[]>(startObject));
+ }
+ else if (type == SequenceType.OwnedMemory)
+ {
+ Debug.Assert(startObject is OwnedMemory<T>);
+
+ memory = (Unsafe.As<OwnedMemory<T>>(startObject)).Memory;
+ }
+ else if (typeof(T) == typeof(char) && type == SequenceType.String)
+ {
+ Debug.Assert(startObject is string);
+
+ memory = (ReadOnlyMemory<T>)(object)(Unsafe.As<string>(startObject)).AsMemory();
+ }
+ else
+ {
+ return default;
+ }
+
+ return memory.Slice(startIndex, length);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal SequencePosition Seek(in SequencePosition start, in SequencePosition end, int count) => Seek(start, end, (long)count);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal SequencePosition Seek(in SequencePosition start, in SequencePosition end, long count)
+ {
+ GetTypeAndIndices(start.GetInteger(), end.GetInteger(), out SequenceType type, out int startIndex, out int endIndex);
+
+ object startObject = start.GetObject();
+ object endObject = end.GetObject();
+
+ if (type == SequenceType.MultiSegment && startObject != endObject)
+ {
+ Debug.Assert(startObject is ReadOnlySequenceSegment<T>);
+ var startSegment = Unsafe.As<ReadOnlySequenceSegment<T>>(startObject);
+
+ int currentLength = startSegment.Memory.Length - startIndex;
+
+ // Position in start segment, defer to single segment seek
+ if (currentLength > count)
+ goto IsSingleSegment;
+
+ // End of segment. Move to start of next.
+ return SeekMultiSegment(startSegment.Next, startIndex, endObject, endIndex, count - currentLength);
+ }
+
+ Debug.Assert(startObject == endObject);
+
+ if (endIndex - startIndex < count)
+ ThrowHelper.ThrowArgumentOutOfRangeException_CountOutOfRange();
+
+ // Single segment Seek
+ IsSingleSegment:
+ return new SequencePosition(startObject, startIndex + (int)count);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static SequencePosition SeekMultiSegment(ReadOnlySequenceSegment<T> currentSegment, int startIndex, object endObject, int endPosition, long count)
+ {
+ Debug.Assert(currentSegment != null);
+ Debug.Assert(count >= 0);
+
+ while (currentSegment != null && currentSegment != endObject)
+ {
+ int memoryLength = currentSegment.Memory.Length;
+
+ // Fully contained in this segment
+ if (memoryLength > count)
+ goto FoundSegment;
+
+ // Move to next
+ count -= memoryLength;
+ currentSegment = currentSegment.Next;
+ }
+
+ // Hit the end of the segments but didn't reach the count
+ if (currentSegment == null || (currentSegment == endObject && endPosition < count))
+ ThrowHelper.ThrowArgumentOutOfRangeException_CountOutOfRange();
+
+ FoundSegment:
+ return new SequencePosition(currentSegment, (int)count);
+ }
+
+ private static void CheckEndReachable(object startSegment, object endSegment)
+ {
+ Debug.Assert(startSegment != null);
+ Debug.Assert(startSegment is ReadOnlySequenceSegment<T>);
+ Debug.Assert(endSegment != null);
+
+ var current = Unsafe.As<ReadOnlySequenceSegment<T>>(startSegment);
+
+ while (current.Next != null)
+ {
+ current = current.Next;
+ if (current == endSegment)
+ {
+ // Found end
+ return;
+ }
+ }
+
+ ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached();
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private long GetLength(in SequencePosition start, in SequencePosition end)
+ {
+ GetTypeAndIndices(start.GetInteger(), end.GetInteger(), out SequenceType type, out int startIndex, out int endIndex);
+
+ object startObject = start.GetObject();
+ object endObject = end.GetObject();
+ if (type == SequenceType.MultiSegment && startObject != endObject)
+ {
+ Debug.Assert(startObject != null);
+ Debug.Assert(startObject is ReadOnlySequenceSegment<T>);
+ Debug.Assert(endObject != null);
+ Debug.Assert(endObject is ReadOnlySequenceSegment<T>);
+
+ var startSegment = Unsafe.As<ReadOnlySequenceSegment<T>>(startObject);
+ var endSegment = Unsafe.As<ReadOnlySequenceSegment<T>>(endObject);
+ // (end.RunningIndex + endIndex) - (start.RunningIndex + startIndex) // (End offset) - (start offset)
+ return endSegment.RunningIndex - startSegment.RunningIndex - startIndex + endIndex; // Rearranged to avoid overflow
+ }
+
+ Debug.Assert(startObject == endObject);
+ // Single segment length
+ return endIndex - startIndex;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void BoundsCheck(in SequencePosition start, in SequencePosition end)
+ {
+ GetTypeAndIndices(start.GetInteger(), end.GetInteger(), out SequenceType type, out int startIndex, out int endIndex);
+
+ object startObject = start.GetObject();
+ object endObject = end.GetObject();
+ if (type == SequenceType.MultiSegment && startObject != endObject)
+ {
+ Debug.Assert(startObject != null);
+ Debug.Assert(startObject is ReadOnlySequenceSegment<T>);
+ Debug.Assert(endObject != null);
+ Debug.Assert(endObject is ReadOnlySequenceSegment<T>);
+
+ var startSegment = Unsafe.As<ReadOnlySequenceSegment<T>>(startObject);
+ var endSegment = Unsafe.As<ReadOnlySequenceSegment<T>>(endObject);
+
+ // start.RunningIndex + startIndex <= end.RunningIndex + endIndex
+ if (startSegment.RunningIndex - endIndex <= endSegment.RunningIndex - startIndex) // Rearranged to avoid overflow
+ {
+ // Mult-segment in bounds
+ return;
+ }
+ }
+ else if (startIndex <= endIndex)
+ {
+ Debug.Assert(startObject == endObject);
+ // Single segment in bounds
+ return;
+ }
+
+ ThrowHelper.ThrowArgumentOutOfRangeException_PositionOutOfRange();
+ }
+
+ internal bool TryGetReadOnlySequenceSegment(out ReadOnlySequenceSegment<T> startSegment, out int startIndex, out ReadOnlySequenceSegment<T> endSegment, out int endIndex)
+ {
+ GetTypeAndIndices(Start.GetInteger(), End.GetInteger(), out SequenceType type, out startIndex, out endIndex);
+
+ if (type != SequenceType.MultiSegment)
+ {
+ startSegment = null;
+ endSegment = null;
+ return false;
+ }
+
+ Debug.Assert(Start.GetObject() != null);
+ Debug.Assert(Start.GetObject() is ReadOnlySequenceSegment<T>);
+ Debug.Assert(End.GetObject() != null);
+ Debug.Assert(End.GetObject() is ReadOnlySequenceSegment<T>);
+
+ startSegment = Unsafe.As<ReadOnlySequenceSegment<T>>(Start.GetObject());
+ endSegment = Unsafe.As<ReadOnlySequenceSegment<T>>(End.GetObject());
+ return true;
+ }
+
+ internal bool TryGetArray(out ArraySegment<T> segment)
+ {
+ GetTypeAndIndices(Start.GetInteger(), End.GetInteger(), out SequenceType type, out int startIndex, out int endIndex);
+
+ if (type != SequenceType.Array)
+ {
+ segment = default;
+ return false;
+ }
+
+ Debug.Assert(Start.GetObject() != null);
+ Debug.Assert(Start.GetObject() is T[]);
+
+ segment = new ArraySegment<T>(Unsafe.As<T[]>(Start.GetObject()), startIndex, endIndex - startIndex);
+ return true;
+ }
+
+ internal bool TryGetOwnedMemory(out OwnedMemory<T> ownedMemory, out int start, out int length)
+ {
+ GetTypeAndIndices(Start.GetInteger(), End.GetInteger(), out SequenceType type, out start, out int endIndex);
+
+ if (type != SequenceType.OwnedMemory)
+ {
+ ownedMemory = default;
+ length = 0;
+ return false;
+ }
+
+ Debug.Assert(Start.GetObject() != null);
+ Debug.Assert(Start.GetObject() is OwnedMemory<T>);
+
+ ownedMemory = Unsafe.As<OwnedMemory<T>>(Start.GetObject());
+ length = endIndex - start;
+ return true;
+ }
+
+ internal bool TryGetReadOnlyMemory(out ReadOnlyMemory<T> memory)
+ {
+ GetTypeAndIndices(Start.GetInteger(), End.GetInteger(), out SequenceType type, out int startIndex, out int endIndex);
+
+ object startObject = Start.GetObject();
+ object endObject = End.GetObject();
+
+ Debug.Assert(startObject != null);
+ Debug.Assert(endObject != null);
+
+ int length = endIndex - startIndex;
+ if (startObject != endObject)
+ {
+ // Can't get ReadOnlyMemory from multi-block segments
+ memory = default;
+ return false;
+ }
+ else if (type == SequenceType.Array)
+ {
+ Debug.Assert(startObject is T[]);
+
+ memory = new ReadOnlyMemory<T>(Unsafe.As<T[]>(startObject));
+ }
+ else if (type == SequenceType.OwnedMemory)
+ {
+ Debug.Assert(startObject is OwnedMemory<T>);
+
+ memory = Unsafe.As<OwnedMemory<T>>(startObject).Memory;
+ }
+ else if (typeof(T) == typeof(char) && type == SequenceType.String)
+ {
+ Debug.Assert(startObject is string);
+
+ var text = Unsafe.As<string>(startObject);
+ memory = (ReadOnlyMemory<T>)(object)text.AsMemory();
+ }
+ else // ReadOnlySequenceSegment
+ {
+ Debug.Assert(startObject is ReadOnlySequenceSegment<T>);
+
+ memory = Unsafe.As<ReadOnlySequenceSegment<T>>(startObject).Memory;
+ }
+
+ memory = memory.Slice(startIndex, length);
+ return true;
+ }
+
+ internal bool TryGetString(out string text, out int start, out int length)
+ {
+ if (typeof(T) != typeof(char))
+ {
+ start = 0;
+ length = 0;
+ text = null;
+ return false;
+ }
+
+ GetTypeAndIndices(Start.GetInteger(), End.GetInteger(), out SequenceType type, out int startIndex, out int endIndex);
+
+ if (type != SequenceType.String)
+ {
+ start = 0;
+ length = 0;
+ text = null;
+ return false;
+ }
+
+ start = startIndex;
+ length = endIndex - startIndex;
+ text = (string)Start.GetObject();
+
+ return true;
+ }
+ }
+}
diff --git a/src/System.Memory/src/System/Buffers/StandardFormat.cs b/src/System.Memory/src/System/Buffers/StandardFormat.cs
index 58c6514d3c..3354f6d7f2 100644
--- a/src/System.Memory/src/System/Buffers/StandardFormat.cs
+++ b/src/System.Memory/src/System/Buffers/StandardFormat.cs
@@ -103,7 +103,7 @@ namespace System.Buffers
/// <summary>
/// Converts a classic .NET format string into a StandardFormat
/// </summary>
- public static StandardFormat Parse(string format) => format == null ? default : Parse(MemoryExtensions.AsReadOnlySpan(format)); //@todo: Change back to extension syntax once the ambiguous reference with CoreLib is eliminated.
+ public static StandardFormat Parse(string format) => format == null ? default : Parse(format.AsSpan());
/// <summary>
/// Returns true if both the Symbol and Precision are equal.
diff --git a/src/System.Memory/src/System/Buffers/Text/Base64Decoder.cs b/src/System.Memory/src/System/Buffers/Text/Base64Decoder.cs
index 8070b9a2a3..29525d5c97 100644
--- a/src/System.Memory/src/System/Buffers/Text/Base64Decoder.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Base64Decoder.cs
@@ -19,8 +19,8 @@ namespace System.Buffers.Text
///
/// <param name="utf8">The input span which contains UTF-8 encoded text in base 64 that needs to be decoded.</param>
/// <param name="bytes">The output span which contains the result of the operation, i.e. the decoded binary data.</param>
- /// <param name="consumed">The number of input bytes consumed during the operation. This can be used to slice the input for subsequent calls, if necessary.</param>
- /// <param name="written">The number of bytes written into the output span. This can be used to slice the output for subsequent calls, if necessary.</param>
+ /// <param name="bytesConsumed">The number of input bytes consumed during the operation. This can be used to slice the input for subsequent calls, if necessary.</param>
+ /// <param name="bytesWritten">The number of bytes written into the output span. This can be used to slice the output for subsequent calls, if necessary.</param>
/// <param name="isFinalBlock">True (default) when the input span contains the entire data to decode.
/// Set to false only if it is known that the input span contains partial data with more data to follow.</param>
/// <returns>It returns the OperationStatus enum values:
@@ -30,7 +30,7 @@ namespace System.Buffers.Text
/// - InvalidData - if the input contains bytes outside of the expected base 64 range, or if it contains invalid/more than two padding characters,
/// or if the input is incomplete (i.e. not a multiple of 4) and isFinalBlock is true.</returns>
/// </summary>
- public static OperationStatus DecodeFromUtf8(ReadOnlySpan<byte> utf8, Span<byte> bytes, out int consumed, out int written, bool isFinalBlock = true)
+ public static OperationStatus DecodeFromUtf8(ReadOnlySpan<byte> utf8, Span<byte> bytes, out int bytesConsumed, out int bytesWritten, bool isFinalBlock = true)
{
ref byte srcBytes = ref MemoryMarshal.GetReference(utf8);
ref byte destBytes = ref MemoryMarshal.GetReference(bytes);
@@ -148,25 +148,25 @@ namespace System.Buffers.Text
goto InvalidExit;
DoneExit:
- consumed = sourceIndex;
- written = destIndex;
+ bytesConsumed = sourceIndex;
+ bytesWritten = destIndex;
return OperationStatus.Done;
DestinationSmallExit:
if (srcLength != utf8.Length && isFinalBlock)
goto InvalidExit; // if input is not a multiple of 4, and there is no more data, return invalid data instead
- consumed = sourceIndex;
- written = destIndex;
+ bytesConsumed = sourceIndex;
+ bytesWritten = destIndex;
return OperationStatus.DestinationTooSmall;
NeedMoreExit:
- consumed = sourceIndex;
- written = destIndex;
+ bytesConsumed = sourceIndex;
+ bytesWritten = destIndex;
return OperationStatus.NeedMoreData;
InvalidExit:
- consumed = sourceIndex;
- written = destIndex;
+ bytesConsumed = sourceIndex;
+ bytesWritten = destIndex;
return OperationStatus.InvalidData;
}
@@ -191,7 +191,7 @@ namespace System.Buffers.Text
/// If the input is not a multiple of 4, it will not decode any.
///
/// <param name="buffer">The input span which contains the base 64 text data that needs to be decoded.</param>
- /// <param name="written">The number of bytes written into the buffer.</param>
+ /// <param name="bytesWritten">The number of bytes written into the buffer.</param>
/// <returns>It returns the OperationStatus enum values:
/// - Done - on successful processing of the entire input span
/// - InvalidData - if the input contains bytes outside of the expected base 64 range, or if it contains invalid/more than two padding characters,
@@ -200,7 +200,7 @@ namespace System.Buffers.Text
/// It does not return NeedMoreData since this method tramples the data in the buffer and
/// hence can only be called once with all the data in the buffer.</returns>
/// </summary>
- public static OperationStatus DecodeFromUtf8InPlace(Span<byte> buffer, out int written)
+ public static OperationStatus DecodeFromUtf8InPlace(Span<byte> buffer, out int bytesWritten)
{
int bufferLength = buffer.Length;
int sourceIndex = 0;
@@ -277,11 +277,11 @@ namespace System.Buffers.Text
}
DoneExit:
- written = destIndex;
+ bytesWritten = destIndex;
return OperationStatus.Done;
InvalidExit:
- written = destIndex;
+ bytesWritten = destIndex;
return OperationStatus.InvalidData;
}
diff --git a/src/System.Memory/src/System/Buffers/Text/Base64Encoder.cs b/src/System.Memory/src/System/Buffers/Text/Base64Encoder.cs
index fab5542c03..6b243f0a28 100644
--- a/src/System.Memory/src/System/Buffers/Text/Base64Encoder.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Base64Encoder.cs
@@ -21,8 +21,8 @@ namespace System.Buffers.Text
///
/// <param name="bytes">The input span which contains binary data that needs to be encoded.</param>
/// <param name="utf8">The output span which contains the result of the operation, i.e. the UTF-8 encoded text in base 64.</param>
- /// <param name="consumed">The number of input bytes consumed during the operation. This can be used to slice the input for subsequent calls, if necessary.</param>
- /// <param name="written">The number of bytes written into the output span. This can be used to slice the output for subsequent calls, if necessary.</param>
+ /// <param name="bytesConsumed">The number of input bytes consumed during the operation. This can be used to slice the input for subsequent calls, if necessary.</param>
+ /// <param name="bytesWritten">The number of bytes written into the output span. This can be used to slice the output for subsequent calls, if necessary.</param>
/// <param name="isFinalBlock">True (default) when the input span contains the entire data to decode.
/// Set to false only if it is known that the input span contains partial data with more data to follow.</param>
/// <returns>It returns the OperationStatus enum values:
@@ -31,7 +31,7 @@ namespace System.Buffers.Text
/// - NeedMoreData - only if isFinalBlock is false, otherwise the output is padded if the input is not a multiple of 3
/// It does not return InvalidData since that is not possible for base 64 encoding.</returns>
/// </summary>
- public static OperationStatus EncodeToUtf8(ReadOnlySpan<byte> bytes, Span<byte> utf8, out int consumed, out int written, bool isFinalBlock = true)
+ public static OperationStatus EncodeToUtf8(ReadOnlySpan<byte> bytes, Span<byte> utf8, out int bytesConsumed, out int bytesWritten, bool isFinalBlock = true)
{
ref byte srcBytes = ref MemoryMarshal.GetReference(bytes);
ref byte destBytes = ref MemoryMarshal.GetReference(utf8);
@@ -84,18 +84,18 @@ namespace System.Buffers.Text
sourceIndex += 2;
}
- consumed = sourceIndex;
- written = destIndex;
+ bytesConsumed = sourceIndex;
+ bytesWritten = destIndex;
return OperationStatus.Done;
NeedMoreDataExit:
- consumed = sourceIndex;
- written = destIndex;
+ bytesConsumed = sourceIndex;
+ bytesWritten = destIndex;
return OperationStatus.NeedMoreData;
DestinationSmallExit:
- consumed = sourceIndex;
- written = destIndex;
+ bytesConsumed = sourceIndex;
+ bytesWritten = destIndex;
return OperationStatus.DestinationTooSmall;
}
@@ -122,14 +122,14 @@ namespace System.Buffers.Text
/// It needs to be large enough to fit the result of the operation.</param>
/// <param name="dataLength">The amount of binary data contained within the buffer that needs to be encoded
/// (and needs to be smaller than the buffer length).</param>
- /// <param name="written">The number of bytes written into the buffer.</param>
+ /// <param name="bytesWritten">The number of bytes written into the buffer.</param>
/// <returns>It returns the OperationStatus enum values:
/// - Done - on successful processing of the entire buffer
/// - DestinationTooSmall - if there is not enough space in the buffer beyond dataLength to fit the result of encoding the input
/// It does not return NeedMoreData since this method tramples the data in the buffer and hence can only be called once with all the data in the buffer.
/// It does not return InvalidData since that is not possible for base 64 encoding.</returns>
/// </summary>
- public static OperationStatus EncodeToUtf8InPlace(Span<byte> buffer, int dataLength, out int written)
+ public static OperationStatus EncodeToUtf8InPlace(Span<byte> buffer, int dataLength, out int bytesWritten)
{
int encodedLength = GetMaxEncodedToUtf8Length(dataLength);
if (buffer.Length < encodedLength)
@@ -170,11 +170,11 @@ namespace System.Buffers.Text
sourceIndex -= 3;
}
- written = encodedLength;
+ bytesWritten = encodedLength;
return OperationStatus.Done;
FalseExit:
- written = 0;
+ bytesWritten = 0;
return OperationStatus.DestinationTooSmall;
}
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/FormattingHelpers.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/FormattingHelpers.cs
index 86079ed871..1cc78e669e 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/FormattingHelpers.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/FormattingHelpers.cs
@@ -5,10 +5,6 @@
using System.Diagnostics;
using System.Runtime.CompilerServices;
-#if !netstandard
-using Internal.Runtime.CompilerServices;
-#endif
-
namespace System.Buffers.Text
{
// All the helper methods in this class assume that the by-ref is valid and that there is
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Boolean.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Boolean.cs
index d9cb3b7004..e5bc21918e 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Boolean.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Boolean.cs
@@ -12,7 +12,7 @@ namespace System.Buffers.Text
/// Formats a Boolean as a UTF8 string.
/// </summary>
/// <param name="value">Value to format</param>
- /// <param name="buffer">Buffer to write the UTF8-formatted value to</param>
+ /// <param name="destination">Buffer to write the UTF8-formatted value to</param>
/// <param name="bytesWritten">Receives the length of the formatted text in bytes</param>
/// <param name="format">The standard format to use</param>
/// <returns>
@@ -27,7 +27,7 @@ namespace System.Buffers.Text
/// <exceptions>
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
- public static bool TryFormat(bool value, Span<byte> buffer, out int bytesWritten, StandardFormat format = default)
+ public static bool TryFormat(bool value, Span<byte> destination, out int bytesWritten, StandardFormat format = default)
{
char symbol = FormattingHelpers.GetSymbolOrDefault(format, 'G');
@@ -39,7 +39,7 @@ namespace System.Buffers.Text
// constant value is passed to this routine, which means the compiler can reverse endianness
// at compile time instead of runtime if necessary.
const uint TrueValueUppercase = ('T' << 24) + ('r' << 16) + ('u' << 8) + ('e' << 0);
- if (!BinaryPrimitives.TryWriteUInt32BigEndian(buffer, TrueValueUppercase))
+ if (!BinaryPrimitives.TryWriteUInt32BigEndian(destination, TrueValueUppercase))
{
goto BufferTooSmall;
}
@@ -47,7 +47,7 @@ namespace System.Buffers.Text
else if (symbol == 'l')
{
const uint TrueValueLowercase = ('t' << 24) + ('r' << 16) + ('u' << 8) + ('e' << 0);
- if (!BinaryPrimitives.TryWriteUInt32BigEndian(buffer, TrueValueLowercase))
+ if (!BinaryPrimitives.TryWriteUInt32BigEndian(destination, TrueValueLowercase))
{
goto BufferTooSmall;
}
@@ -66,30 +66,30 @@ namespace System.Buffers.Text
{
// This check can't be performed earlier because we need to throw if an invalid symbol is
// provided, even if the buffer is too small.
- if ((uint)4 >= (uint)buffer.Length)
+ if ((uint)4 >= (uint)destination.Length)
{
goto BufferTooSmall;
}
const uint FalsValueUppercase = ('F' << 24) + ('a' << 16) + ('l' << 8) + ('s' << 0);
- BinaryPrimitives.WriteUInt32BigEndian(buffer, FalsValueUppercase);
+ BinaryPrimitives.WriteUInt32BigEndian(destination, FalsValueUppercase);
}
else if (symbol == 'l')
{
- if ((uint)4 >= (uint)buffer.Length)
+ if ((uint)4 >= (uint)destination.Length)
{
goto BufferTooSmall;
}
const uint FalsValueLowercase = ('f' << 24) + ('a' << 16) + ('l' << 8) + ('s' << 0);
- BinaryPrimitives.WriteUInt32BigEndian(buffer, FalsValueLowercase);
+ BinaryPrimitives.WriteUInt32BigEndian(destination, FalsValueLowercase);
}
else
{
goto BadFormat;
}
- buffer[4] = (byte)'e';
+ destination[4] = (byte)'e';
bytesWritten = 5;
return true;
}
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.G.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.G.cs
index 7915ec5c51..7aad6fef0f 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.G.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.G.cs
@@ -19,7 +19,7 @@ namespace System.Buffers.Text
// --------------------------
// 05/25/2017 10:30:15 -08:00
//
- private static bool TryFormatDateTimeG(DateTime value, TimeSpan offset, Span<byte> buffer, out int bytesWritten)
+ private static bool TryFormatDateTimeG(DateTime value, TimeSpan offset, Span<byte> destination, out int bytesWritten)
{
const int MinimumBytesNeeded = 19;
@@ -30,7 +30,7 @@ namespace System.Buffers.Text
bytesRequired += 7; // Space['+'|'-']hh:mm
}
- if (buffer.Length < bytesRequired)
+ if (destination.Length < bytesRequired)
{
bytesWritten = 0;
return false;
@@ -39,28 +39,28 @@ namespace System.Buffers.Text
bytesWritten = bytesRequired;
// Hoist most of the bounds checks on buffer.
- { var unused = buffer[MinimumBytesNeeded - 1]; }
+ { var unused = destination[MinimumBytesNeeded - 1]; }
// TODO: Introduce an API which can parse DateTime instances efficiently, pulling out
// all their properties (Month, Day, etc.) in one shot. This would help avoid the
// duplicate work that implicitly results from calling these properties individually.
- FormattingHelpers.WriteTwoDecimalDigits((uint)value.Month, buffer, 0);
- buffer[2] = Utf8Constants.Slash;
+ FormattingHelpers.WriteTwoDecimalDigits((uint)value.Month, destination, 0);
+ destination[2] = Utf8Constants.Slash;
- FormattingHelpers.WriteTwoDecimalDigits((uint)value.Day, buffer, 3);
- buffer[5] = Utf8Constants.Slash;
+ FormattingHelpers.WriteTwoDecimalDigits((uint)value.Day, destination, 3);
+ destination[5] = Utf8Constants.Slash;
- FormattingHelpers.WriteFourDecimalDigits((uint)value.Year, buffer, 6);
- buffer[10] = Utf8Constants.Space;
+ FormattingHelpers.WriteFourDecimalDigits((uint)value.Year, destination, 6);
+ destination[10] = Utf8Constants.Space;
- FormattingHelpers.WriteTwoDecimalDigits((uint)value.Hour, buffer, 11);
- buffer[13] = Utf8Constants.Colon;
+ FormattingHelpers.WriteTwoDecimalDigits((uint)value.Hour, destination, 11);
+ destination[13] = Utf8Constants.Colon;
- FormattingHelpers.WriteTwoDecimalDigits((uint)value.Minute, buffer, 14);
- buffer[16] = Utf8Constants.Colon;
+ FormattingHelpers.WriteTwoDecimalDigits((uint)value.Minute, destination, 14);
+ destination[16] = Utf8Constants.Colon;
- FormattingHelpers.WriteTwoDecimalDigits((uint)value.Second, buffer, 17);
+ FormattingHelpers.WriteTwoDecimalDigits((uint)value.Second, destination, 17);
if (offset != Utf8Constants.s_nullUtcOffset)
{
@@ -79,11 +79,11 @@ namespace System.Buffers.Text
// Writing the value backward allows the JIT to optimize by
// performing a single bounds check against buffer.
- FormattingHelpers.WriteTwoDecimalDigits((uint)offset.Minutes, buffer, 24);
- buffer[23] = Utf8Constants.Colon;
- FormattingHelpers.WriteTwoDecimalDigits((uint)offset.Hours, buffer, 21);
- buffer[20] = sign;
- buffer[19] = Utf8Constants.Space;
+ FormattingHelpers.WriteTwoDecimalDigits((uint)offset.Minutes, destination, 24);
+ destination[23] = Utf8Constants.Colon;
+ FormattingHelpers.WriteTwoDecimalDigits((uint)offset.Hours, destination, 21);
+ destination[20] = sign;
+ destination[19] = Utf8Constants.Space;
}
return true;
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.L.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.L.cs
index a25737774a..396fcc386f 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.L.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.L.cs
@@ -12,11 +12,11 @@ namespace System.Buffers.Text
// -----------------------------
// tue, 03 jan 2017 08:08:05 gmt
//
- private static bool TryFormatDateTimeL(DateTime value, Span<byte> buffer, out int bytesWritten)
+ private static bool TryFormatDateTimeL(DateTime value, Span<byte> destination, out int bytesWritten)
{
// Writing the check in this fashion elides all bounds checks on 'buffer'
// for the remainder of the method.
- if ((uint)28 >= (uint)buffer.Length)
+ if ((uint)28 >= (uint)destination.Length)
{
bytesWritten = 0;
return false;
@@ -24,40 +24,40 @@ namespace System.Buffers.Text
var dayAbbrev = DayAbbreviationsLowercase[(int)value.DayOfWeek];
- buffer[0] = (byte)dayAbbrev;
+ destination[0] = (byte)dayAbbrev;
dayAbbrev >>= 8;
- buffer[1] = (byte)dayAbbrev;
+ destination[1] = (byte)dayAbbrev;
dayAbbrev >>= 8;
- buffer[2] = (byte)dayAbbrev;
- buffer[3] = Utf8Constants.Comma;
- buffer[4] = Utf8Constants.Space;
+ destination[2] = (byte)dayAbbrev;
+ destination[3] = Utf8Constants.Comma;
+ destination[4] = Utf8Constants.Space;
- FormattingHelpers.WriteTwoDecimalDigits((uint)value.Day, buffer, 5);
- buffer[7] = Utf8Constants.Space;
+ FormattingHelpers.WriteTwoDecimalDigits((uint)value.Day, destination, 5);
+ destination[7] = Utf8Constants.Space;
var monthAbbrev = MonthAbbreviationsLowercase[value.Month - 1];
- buffer[8] = (byte)monthAbbrev;
+ destination[8] = (byte)monthAbbrev;
monthAbbrev >>= 8;
- buffer[9] = (byte)monthAbbrev;
+ destination[9] = (byte)monthAbbrev;
monthAbbrev >>= 8;
- buffer[10] = (byte)monthAbbrev;
- buffer[11] = Utf8Constants.Space;
+ destination[10] = (byte)monthAbbrev;
+ destination[11] = Utf8Constants.Space;
- FormattingHelpers.WriteFourDecimalDigits((uint)value.Year, buffer, 12);
- buffer[16] = Utf8Constants.Space;
+ FormattingHelpers.WriteFourDecimalDigits((uint)value.Year, destination, 12);
+ destination[16] = Utf8Constants.Space;
- FormattingHelpers.WriteTwoDecimalDigits((uint)value.Hour, buffer, 17);
- buffer[19] = Utf8Constants.Colon;
+ FormattingHelpers.WriteTwoDecimalDigits((uint)value.Hour, destination, 17);
+ destination[19] = Utf8Constants.Colon;
- FormattingHelpers.WriteTwoDecimalDigits((uint)value.Minute, buffer, 20);
- buffer[22] = Utf8Constants.Colon;
+ FormattingHelpers.WriteTwoDecimalDigits((uint)value.Minute, destination, 20);
+ destination[22] = Utf8Constants.Colon;
- FormattingHelpers.WriteTwoDecimalDigits((uint)value.Second, buffer, 23);
- buffer[25] = Utf8Constants.Space;
+ FormattingHelpers.WriteTwoDecimalDigits((uint)value.Second, destination, 23);
+ destination[25] = Utf8Constants.Space;
- buffer[26] = GMT1Lowercase;
- buffer[27] = GMT2Lowercase;
- buffer[28] = GMT3Lowercase;
+ destination[26] = GMT1Lowercase;
+ destination[27] = GMT2Lowercase;
+ destination[28] = GMT3Lowercase;
bytesWritten = 29;
return true;
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.O.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.O.cs
index 24e7256268..5a2a7bfadb 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.O.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.O.cs
@@ -15,7 +15,7 @@ namespace System.Buffers.Text
// 2017-06-12T05:30:45.7680000Z (Z is short for "+00:00" but also distinguishes DateTimeKind.Utc from DateTimeKind.Local)
// 2017-06-12T05:30:45.7680000 (interpreted as local time wrt to current time zone)
//
- private static bool TryFormatDateTimeO(DateTime value, TimeSpan offset, Span<byte> buffer, out int bytesWritten)
+ private static bool TryFormatDateTimeO(DateTime value, TimeSpan offset, Span<byte> destination, out int bytesWritten)
{
const int MinimumBytesNeeded = 27;
@@ -40,7 +40,7 @@ namespace System.Buffers.Text
bytesRequired += 6;
}
- if (buffer.Length < bytesRequired)
+ if (destination.Length < bytesRequired)
{
bytesWritten = 0;
return false;
@@ -49,27 +49,27 @@ namespace System.Buffers.Text
bytesWritten = bytesRequired;
// Hoist most of the bounds checks on buffer.
- { var unused = buffer[MinimumBytesNeeded - 1]; }
+ { var unused = destination[MinimumBytesNeeded - 1]; }
- FormattingHelpers.WriteFourDecimalDigits((uint)value.Year, buffer, 0);
- buffer[4] = Utf8Constants.Minus;
+ FormattingHelpers.WriteFourDecimalDigits((uint)value.Year, destination, 0);
+ destination[4] = Utf8Constants.Minus;
- FormattingHelpers.WriteTwoDecimalDigits((uint)value.Month, buffer, 5);
- buffer[7] = Utf8Constants.Minus;
+ FormattingHelpers.WriteTwoDecimalDigits((uint)value.Month, destination, 5);
+ destination[7] = Utf8Constants.Minus;
- FormattingHelpers.WriteTwoDecimalDigits((uint)value.Day, buffer, 8);
- buffer[10] = TimeMarker;
+ FormattingHelpers.WriteTwoDecimalDigits((uint)value.Day, destination, 8);
+ destination[10] = TimeMarker;
- FormattingHelpers.WriteTwoDecimalDigits((uint)value.Hour, buffer, 11);
- buffer[13] = Utf8Constants.Colon;
+ FormattingHelpers.WriteTwoDecimalDigits((uint)value.Hour, destination, 11);
+ destination[13] = Utf8Constants.Colon;
- FormattingHelpers.WriteTwoDecimalDigits((uint)value.Minute, buffer, 14);
- buffer[16] = Utf8Constants.Colon;
+ FormattingHelpers.WriteTwoDecimalDigits((uint)value.Minute, destination, 14);
+ destination[16] = Utf8Constants.Colon;
- FormattingHelpers.WriteTwoDecimalDigits((uint)value.Second, buffer, 17);
- buffer[19] = Utf8Constants.Period;
+ FormattingHelpers.WriteTwoDecimalDigits((uint)value.Second, destination, 17);
+ destination[19] = Utf8Constants.Period;
- FormattingHelpers.WriteDigits((uint)((ulong)value.Ticks % (ulong)TimeSpan.TicksPerSecond), buffer.Slice(20, 7));
+ FormattingHelpers.WriteDigits((uint)((ulong)value.Ticks % (ulong)TimeSpan.TicksPerSecond), destination.Slice(20, 7));
if (kind == DateTimeKind.Local)
{
@@ -88,15 +88,15 @@ namespace System.Buffers.Text
// Writing the value backward allows the JIT to optimize by
// performing a single bounds check against buffer.
- FormattingHelpers.WriteTwoDecimalDigits((uint)offset.Minutes, buffer, 31);
- buffer[30] = Utf8Constants.Colon;
- FormattingHelpers.WriteTwoDecimalDigits((uint)offset.Hours, buffer, 28);
- buffer[27] = sign;
+ FormattingHelpers.WriteTwoDecimalDigits((uint)offset.Minutes, destination, 31);
+ destination[30] = Utf8Constants.Colon;
+ FormattingHelpers.WriteTwoDecimalDigits((uint)offset.Hours, destination, 28);
+ destination[27] = sign;
}
else if (kind == DateTimeKind.Utc)
{
- buffer[27] = UtcMarker;
+ destination[27] = UtcMarker;
}
return true;
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.R.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.R.cs
index 738eb62a28..a3a5d991a2 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.R.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.R.cs
@@ -12,11 +12,11 @@ namespace System.Buffers.Text
// -----------------------------
// Tue, 03 Jan 2017 08:08:05 GMT
//
- private static bool TryFormatDateTimeR(DateTime value, Span<byte> buffer, out int bytesWritten)
+ private static bool TryFormatDateTimeR(DateTime value, Span<byte> destination, out int bytesWritten)
{
// Writing the check in this fashion elides all bounds checks on 'buffer'
// for the remainder of the method.
- if ((uint)28 >= (uint)buffer.Length)
+ if ((uint)28 >= (uint)destination.Length)
{
bytesWritten = 0;
return false;
@@ -24,40 +24,40 @@ namespace System.Buffers.Text
var dayAbbrev = DayAbbreviations[(int)value.DayOfWeek];
- buffer[0] = (byte)dayAbbrev;
+ destination[0] = (byte)dayAbbrev;
dayAbbrev >>= 8;
- buffer[1] = (byte)dayAbbrev;
+ destination[1] = (byte)dayAbbrev;
dayAbbrev >>= 8;
- buffer[2] = (byte)dayAbbrev;
- buffer[3] = Utf8Constants.Comma;
- buffer[4] = Utf8Constants.Space;
+ destination[2] = (byte)dayAbbrev;
+ destination[3] = Utf8Constants.Comma;
+ destination[4] = Utf8Constants.Space;
- FormattingHelpers.WriteTwoDecimalDigits((uint)value.Day, buffer, 5);
- buffer[7] = Utf8Constants.Space;
+ FormattingHelpers.WriteTwoDecimalDigits((uint)value.Day, destination, 5);
+ destination[7] = Utf8Constants.Space;
var monthAbbrev = MonthAbbreviations[value.Month - 1];
- buffer[8] = (byte)monthAbbrev;
+ destination[8] = (byte)monthAbbrev;
monthAbbrev >>= 8;
- buffer[9] = (byte)monthAbbrev;
+ destination[9] = (byte)monthAbbrev;
monthAbbrev >>= 8;
- buffer[10] = (byte)monthAbbrev;
- buffer[11] = Utf8Constants.Space;
+ destination[10] = (byte)monthAbbrev;
+ destination[11] = Utf8Constants.Space;
- FormattingHelpers.WriteFourDecimalDigits((uint)value.Year, buffer, 12);
- buffer[16] = Utf8Constants.Space;
+ FormattingHelpers.WriteFourDecimalDigits((uint)value.Year, destination, 12);
+ destination[16] = Utf8Constants.Space;
- FormattingHelpers.WriteTwoDecimalDigits((uint)value.Hour, buffer, 17);
- buffer[19] = Utf8Constants.Colon;
+ FormattingHelpers.WriteTwoDecimalDigits((uint)value.Hour, destination, 17);
+ destination[19] = Utf8Constants.Colon;
- FormattingHelpers.WriteTwoDecimalDigits((uint)value.Minute, buffer, 20);
- buffer[22] = Utf8Constants.Colon;
+ FormattingHelpers.WriteTwoDecimalDigits((uint)value.Minute, destination, 20);
+ destination[22] = Utf8Constants.Colon;
- FormattingHelpers.WriteTwoDecimalDigits((uint)value.Second, buffer, 23);
- buffer[25] = Utf8Constants.Space;
+ FormattingHelpers.WriteTwoDecimalDigits((uint)value.Second, destination, 23);
+ destination[25] = Utf8Constants.Space;
- buffer[26] = GMT1;
- buffer[27] = GMT2;
- buffer[28] = GMT3;
+ destination[26] = GMT1;
+ destination[27] = GMT2;
+ destination[28] = GMT3;
bytesWritten = 29;
return true;
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.cs
index 3e52d0a4fa..6b188ff117 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.cs
@@ -77,7 +77,7 @@ namespace System.Buffers.Text
/// Formats a DateTimeOffset as a UTF8 string.
/// </summary>
/// <param name="value">Value to format</param>
- /// <param name="buffer">Buffer to write the UTF8-formatted value to</param>
+ /// <param name="destination">Buffer to write the UTF8-formatted value to</param>
/// <param name="bytesWritten">Receives the length of the formatted text in bytes</param>
/// <param name="format">The standard format to use</param>
/// <returns>
@@ -95,7 +95,7 @@ namespace System.Buffers.Text
/// </remarks>
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
- public static bool TryFormat(DateTimeOffset value, Span<byte> buffer, out int bytesWritten, StandardFormat format = default)
+ public static bool TryFormat(DateTimeOffset value, Span<byte> destination, out int bytesWritten, StandardFormat format = default)
{
TimeSpan offset = Utf8Constants.s_nullUtcOffset;
char symbol = format.Symbol;
@@ -108,16 +108,16 @@ namespace System.Buffers.Text
switch (symbol)
{
case 'R':
- return TryFormatDateTimeR(value.UtcDateTime, buffer, out bytesWritten);
+ return TryFormatDateTimeR(value.UtcDateTime, destination, out bytesWritten);
case 'l':
- return TryFormatDateTimeL(value.UtcDateTime, buffer, out bytesWritten);
+ return TryFormatDateTimeL(value.UtcDateTime, destination, out bytesWritten);
case 'O':
- return TryFormatDateTimeO(value.DateTime, value.Offset, buffer, out bytesWritten);
+ return TryFormatDateTimeO(value.DateTime, value.Offset, destination, out bytesWritten);
case 'G':
- return TryFormatDateTimeG(value.DateTime, offset, buffer, out bytesWritten);
+ return TryFormatDateTimeG(value.DateTime, offset, destination, out bytesWritten);
default:
return ThrowHelper.TryFormatThrowFormatException(out bytesWritten);
@@ -128,7 +128,7 @@ namespace System.Buffers.Text
/// Formats a DateTime as a UTF8 string.
/// </summary>
/// <param name="value">Value to format</param>
- /// <param name="buffer">Buffer to write the UTF8-formatted value to</param>
+ /// <param name="destination">Buffer to write the UTF8-formatted value to</param>
/// <param name="bytesWritten">Receives the length of the formatted text in bytes</param>
/// <param name="format">The standard format to use</param>
/// <returns>
@@ -145,23 +145,23 @@ namespace System.Buffers.Text
/// <exceptions>
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
- public static bool TryFormat(DateTime value, Span<byte> buffer, out int bytesWritten, StandardFormat format = default)
+ public static bool TryFormat(DateTime value, Span<byte> destination, out int bytesWritten, StandardFormat format = default)
{
char symbol = FormattingHelpers.GetSymbolOrDefault(format, 'G');
switch (symbol)
{
case 'R':
- return TryFormatDateTimeR(value, buffer, out bytesWritten);
+ return TryFormatDateTimeR(value, destination, out bytesWritten);
case 'l':
- return TryFormatDateTimeL(value, buffer, out bytesWritten);
+ return TryFormatDateTimeL(value, destination, out bytesWritten);
case 'O':
- return TryFormatDateTimeO(value, Utf8Constants.s_nullUtcOffset, buffer, out bytesWritten);
+ return TryFormatDateTimeO(value, Utf8Constants.s_nullUtcOffset, destination, out bytesWritten);
case 'G':
- return TryFormatDateTimeG(value, Utf8Constants.s_nullUtcOffset, buffer, out bytesWritten);
+ return TryFormatDateTimeG(value, Utf8Constants.s_nullUtcOffset, destination, out bytesWritten);
default:
return ThrowHelper.TryFormatThrowFormatException(out bytesWritten);
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Decimal.E.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Decimal.E.cs
index 840e766d49..6cde07ff7f 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Decimal.E.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Decimal.E.cs
@@ -8,7 +8,7 @@ namespace System.Buffers.Text
{
public static partial class Utf8Formatter
{
- private static bool TryFormatDecimalE(ref NumberBuffer number, Span<byte> buffer, out int bytesWritten, byte precision, byte exponentSymbol)
+ private static bool TryFormatDecimalE(ref NumberBuffer number, Span<byte> destination, out int bytesWritten, byte precision, byte exponentSymbol)
{
const int NumExponentDigits = 3;
@@ -22,7 +22,7 @@ namespace System.Buffers.Text
+ 2 // 'E' or 'e' followed by '+' or '-'
+ NumExponentDigits; // exponent digits
- if (buffer.Length < numBytesNeeded)
+ if (destination.Length < numBytesNeeded)
{
bytesWritten = 0;
return false;
@@ -32,7 +32,7 @@ namespace System.Buffers.Text
int srcIndex = 0;
if (number.IsNegative)
{
- buffer[dstIndex++] = Utf8Constants.Minus;
+ destination[dstIndex++] = Utf8Constants.Minus;
}
//
@@ -42,19 +42,19 @@ namespace System.Buffers.Text
byte firstDigit = digits[srcIndex];
if (firstDigit == 0)
{
- buffer[dstIndex++] = (byte)'0'; // Special case: number before the decimal point is exactly 0: Number does not store the zero in this case.
+ destination[dstIndex++] = (byte)'0'; // Special case: number before the decimal point is exactly 0: Number does not store the zero in this case.
exponent = 0;
}
else
{
- buffer[dstIndex++] = firstDigit;
+ destination[dstIndex++] = firstDigit;
srcIndex++;
exponent = scale - 1;
}
if (precision > 0)
{
- buffer[dstIndex++] = Utf8Constants.Period;
+ destination[dstIndex++] = Utf8Constants.Period;
//
// Emit digits after the decimal point.
@@ -67,34 +67,34 @@ namespace System.Buffers.Text
{
while (numDigitsEmitted++ < precision)
{
- buffer[dstIndex++] = (byte)'0';
+ destination[dstIndex++] = (byte)'0';
}
break;
}
- buffer[dstIndex++] = digit;
+ destination[dstIndex++] = digit;
srcIndex++;
numDigitsEmitted++;
}
}
// Emit the exponent symbol
- buffer[dstIndex++] = exponentSymbol;
+ destination[dstIndex++] = exponentSymbol;
if (exponent >= 0)
{
- buffer[dstIndex++] = Utf8Constants.Plus;
+ destination[dstIndex++] = Utf8Constants.Plus;
}
else
{
- buffer[dstIndex++] = Utf8Constants.Minus;
+ destination[dstIndex++] = Utf8Constants.Minus;
exponent = -exponent;
}
Debug.Assert(exponent < Number.DECIMAL_PRECISION, "If you're trying to reuse this routine for double/float, you'll need to review the code carefully for Decimal-specific assumptions.");
// Emit exactly three digits for the exponent.
- buffer[dstIndex++] = (byte)'0'; // The exponent for Decimal can never exceed 28 (let alone 99)
- buffer[dstIndex++] = (byte)((exponent / 10) + '0');
- buffer[dstIndex++] = (byte)((exponent % 10) + '0');
+ destination[dstIndex++] = (byte)'0'; // The exponent for Decimal can never exceed 28 (let alone 99)
+ destination[dstIndex++] = (byte)((exponent / 10) + '0');
+ destination[dstIndex++] = (byte)((exponent % 10) + '0');
Debug.Assert(dstIndex == numBytesNeeded);
bytesWritten = numBytesNeeded;
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Decimal.F.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Decimal.F.cs
index d26ea4bd3e..e2409f909b 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Decimal.F.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Decimal.F.cs
@@ -8,7 +8,7 @@ namespace System.Buffers.Text
{
public static partial class Utf8Formatter
{
- private static bool TryFormatDecimalF(ref NumberBuffer number, Span<byte> buffer, out int bytesWritten, byte precision)
+ private static bool TryFormatDecimalF(ref NumberBuffer number, Span<byte> destination, out int bytesWritten, byte precision)
{
int scale = number.Scale;
ReadOnlySpan<byte> digits = number.Digits;
@@ -18,7 +18,7 @@ namespace System.Buffers.Text
+ ((scale <= 0) ? 1 : scale) // digits before the decimal point (minimum 1)
+ ((precision == 0) ? 0 : (precision + 1)); // if specified precision != 0, the decimal point and the digits after the decimal point (padded with zeroes if needed)
- if (buffer.Length < numBytesNeeded)
+ if (destination.Length < numBytesNeeded)
{
bytesWritten = 0;
return false;
@@ -28,7 +28,7 @@ namespace System.Buffers.Text
int dstIndex = 0;
if (number.IsNegative)
{
- buffer[dstIndex++] = Utf8Constants.Minus;
+ destination[dstIndex++] = Utf8Constants.Minus;
}
//
@@ -36,7 +36,7 @@ namespace System.Buffers.Text
//
if (scale <= 0)
{
- buffer[dstIndex++] = (byte)'0'; // The integer portion is 0 and not stored. The formatter, however, needs to emit it.
+ destination[dstIndex++] = (byte)'0'; // The integer portion is 0 and not stored. The formatter, however, needs to emit it.
}
else
{
@@ -48,19 +48,19 @@ namespace System.Buffers.Text
int numTrailingZeroes = scale - srcIndex;
for (int i = 0; i < numTrailingZeroes; i++)
{
- buffer[dstIndex++] = (byte)'0';
+ destination[dstIndex++] = (byte)'0';
}
break;
}
- buffer[dstIndex++] = digit;
+ destination[dstIndex++] = digit;
srcIndex++;
}
}
if (precision > 0)
{
- buffer[dstIndex++] = Utf8Constants.Period;
+ destination[dstIndex++] = Utf8Constants.Period;
//
// Emit digits after the decimal point.
@@ -71,7 +71,7 @@ namespace System.Buffers.Text
int numLeadingZeroesToEmit = Math.Min((int)precision, -scale);
for (int i = 0; i < numLeadingZeroesToEmit; i++)
{
- buffer[dstIndex++] = (byte)'0';
+ destination[dstIndex++] = (byte)'0';
}
numDigitsEmitted += numLeadingZeroesToEmit;
}
@@ -83,11 +83,11 @@ namespace System.Buffers.Text
{
while (numDigitsEmitted++ < precision)
{
- buffer[dstIndex++] = (byte)'0';
+ destination[dstIndex++] = (byte)'0';
}
break;
}
- buffer[dstIndex++] = digit;
+ destination[dstIndex++] = digit;
srcIndex++;
numDigitsEmitted++;
}
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Decimal.G.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Decimal.G.cs
index 213d319800..b8aa6d75ef 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Decimal.G.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Decimal.G.cs
@@ -9,7 +9,7 @@ namespace System.Buffers.Text
{
public static partial class Utf8Formatter
{
- private static bool TryFormatDecimalG(ref NumberBuffer number, Span<byte> buffer, out int bytesWritten)
+ private static bool TryFormatDecimalG(ref NumberBuffer number, Span<byte> destination, out int bytesWritten)
{
int scale = number.Scale;
ReadOnlySpan<byte> digits = number.Digits;
@@ -35,7 +35,7 @@ namespace System.Buffers.Text
numBytesNeeded++; // And the minus sign.
}
- if (buffer.Length < numBytesNeeded)
+ if (destination.Length < numBytesNeeded)
{
bytesWritten = 0;
return false;
@@ -46,7 +46,7 @@ namespace System.Buffers.Text
if (number.IsNegative)
{
- buffer[dstIndex++] = Utf8Constants.Minus;
+ destination[dstIndex++] = Utf8Constants.Minus;
}
//
@@ -54,7 +54,7 @@ namespace System.Buffers.Text
//
if (scale <= 0)
{
- buffer[dstIndex++] = (byte)'0'; // The integer portion is 0 and not stored. The formatter, however, needs to emit it.
+ destination[dstIndex++] = (byte)'0'; // The integer portion is 0 and not stored. The formatter, however, needs to emit it.
}
else
{
@@ -66,19 +66,19 @@ namespace System.Buffers.Text
int numTrailingZeroes = scale - srcIndex;
for (int i = 0; i < numTrailingZeroes; i++)
{
- buffer[dstIndex++] = (byte)'0';
+ destination[dstIndex++] = (byte)'0';
}
break;
}
- buffer[dstIndex++] = digit;
+ destination[dstIndex++] = digit;
srcIndex++;
}
}
if (isFraction)
{
- buffer[dstIndex++] = Utf8Constants.Period;
+ destination[dstIndex++] = Utf8Constants.Period;
//
// Emit digits after the decimal point.
@@ -88,14 +88,14 @@ namespace System.Buffers.Text
int numLeadingZeroesToEmit = -scale;
for (int i = 0; i < numLeadingZeroesToEmit; i++)
{
- buffer[dstIndex++] = (byte)'0';
+ destination[dstIndex++] = (byte)'0';
}
}
byte digit;
while ((digit = digits[srcIndex++]) != 0)
{
- buffer[dstIndex++] = digit;
+ destination[dstIndex++] = digit;
}
}
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Decimal.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Decimal.cs
index af292ae952..f96136467f 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Decimal.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Decimal.cs
@@ -12,7 +12,7 @@ namespace System.Buffers.Text
/// Formats a Decimal as a UTF8 string.
/// </summary>
/// <param name="value">Value to format</param>
- /// <param name="buffer">Buffer to write the UTF8-formatted value to</param>
+ /// <param name="destination">Buffer to write the UTF8-formatted value to</param>
/// <param name="bytesWritten">Receives the length of the formatted text in bytes</param>
/// <param name="format">The standard format to use</param>
/// <returns>
@@ -28,7 +28,7 @@ namespace System.Buffers.Text
/// <exceptions>
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
- public static bool TryFormat(decimal value, Span<byte> buffer, out int bytesWritten, StandardFormat format = default)
+ public static bool TryFormat(decimal value, Span<byte> destination, out int bytesWritten, StandardFormat format = default)
{
if (format.IsDefault)
{
@@ -48,7 +48,7 @@ namespace System.Buffers.Text
{
number.IsNegative = false; // For Decimals, -0 must print as normal 0.
}
- bool success = TryFormatDecimalG(ref number, buffer, out bytesWritten);
+ bool success = TryFormatDecimalG(ref number, destination, out bytesWritten);
#if DEBUG
// This DEBUG segment exists to close a code coverage hole inside TryFormatDecimalG(). Because we don't call RoundNumber() on this path, we have no way to feed
// TryFormatDecimalG() a number where trailing zeros before the decimal point have been cropped. So if the chance comes up, we'll crop the zeroes
@@ -67,13 +67,13 @@ namespace System.Buffers.Text
number.CheckConsistency();
- byte[] buffer2 = new byte[buffer.Length];
+ byte[] buffer2 = new byte[destination.Length];
bool success2 = TryFormatDecimalG(ref number, buffer2, out int bytesWritten2);
Debug.Assert(success2);
Debug.Assert(bytesWritten2 == bytesWritten);
for (int i = 0; i < bytesWritten; i++)
{
- Debug.Assert(buffer[i] == buffer2[i]);
+ Debug.Assert(destination[i] == buffer2[i]);
}
}
@@ -90,7 +90,7 @@ namespace System.Buffers.Text
byte precision = (format.Precision == StandardFormat.NoPrecision) ? (byte)2 : format.Precision;
Number.RoundNumber(ref number, number.Scale + precision);
Debug.Assert(!(number.Digits[0] == 0 && number.IsNegative)); // For Decimals, -0 must print as normal 0. As it happens, Number.RoundNumber already ensures this invariant.
- return TryFormatDecimalF(ref number, buffer, out bytesWritten, precision);
+ return TryFormatDecimalF(ref number, destination, out bytesWritten, precision);
}
case 'e':
@@ -101,7 +101,7 @@ namespace System.Buffers.Text
byte precision = (format.Precision == StandardFormat.NoPrecision) ? (byte)6 : format.Precision;
Number.RoundNumber(ref number, precision + 1);
Debug.Assert(!(number.Digits[0] == 0 && number.IsNegative)); // For Decimals, -0 must print as normal 0. As it happens, Number.RoundNumber already ensures this invariant.
- return TryFormatDecimalE(ref number, buffer, out bytesWritten, precision, exponentSymbol: (byte)format.Symbol);
+ return TryFormatDecimalE(ref number, destination, out bytesWritten, precision, exponentSymbol: (byte)format.Symbol);
}
default:
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Float.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Float.cs
index 3354c572ae..94591134c6 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Float.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Float.cs
@@ -13,7 +13,7 @@ namespace System.Buffers.Text
/// Formats a Double as a UTF8 string.
/// </summary>
/// <param name="value">Value to format</param>
- /// <param name="buffer">Buffer to write the UTF8-formatted value to</param>
+ /// <param name="destination">Buffer to write the UTF8-formatted value to</param>
/// <param name="bytesWritten">Receives the length of the formatted text in bytes</param>
/// <param name="format">The standard format to use</param>
/// <returns>
@@ -29,16 +29,16 @@ namespace System.Buffers.Text
/// <exceptions>
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
- public static bool TryFormat(double value, Span<byte> buffer, out int bytesWritten, StandardFormat format = default)
+ public static bool TryFormat(double value, Span<byte> destination, out int bytesWritten, StandardFormat format = default)
{
- return TryFormatFloatingPoint<double>(value, buffer, out bytesWritten, format);
+ return TryFormatFloatingPoint<double>(value, destination, out bytesWritten, format);
}
/// <summary>
/// Formats a Single as a UTF8 string.
/// </summary>
/// <param name="value">Value to format</param>
- /// <param name="buffer">Buffer to write the UTF8-formatted value to</param>
+ /// <param name="destination">Buffer to write the UTF8-formatted value to</param>
/// <param name="bytesWritten">Receives the length of the formatted text in bytes</param>
/// <param name="format">The standard format to use</param>
/// <returns>
@@ -54,9 +54,9 @@ namespace System.Buffers.Text
/// <exceptions>
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
- public static bool TryFormat(float value, Span<byte> buffer, out int bytesWritten, StandardFormat format = default)
+ public static bool TryFormat(float value, Span<byte> destination, out int bytesWritten, StandardFormat format = default)
{
- return TryFormatFloatingPoint<float>(value, buffer, out bytesWritten, format);
+ return TryFormatFloatingPoint<float>(value, destination, out bytesWritten, format);
}
//
@@ -65,7 +65,7 @@ namespace System.Buffers.Text
// be preferable not to have another version of that lying around. Until we really hit a scenario where floating point formatting needs the perf, we'll
// make do with this.
//
- private static bool TryFormatFloatingPoint<T>(T value, Span<byte> buffer, out int bytesWritten, StandardFormat format) where T : IFormattable
+ private static bool TryFormatFloatingPoint<T>(T value, Span<byte> destination, out int bytesWritten, StandardFormat format) where T : IFormattable
{
if (format.IsDefault)
{
@@ -93,7 +93,7 @@ namespace System.Buffers.Text
string formatString = format.ToString();
string utf16Text = value.ToString(formatString, CultureInfo.InvariantCulture);
int length = utf16Text.Length;
- if (length > buffer.Length)
+ if (length > destination.Length)
{
bytesWritten = 0;
return false;
@@ -102,7 +102,7 @@ namespace System.Buffers.Text
for (int i = 0; i < length; i++)
{
Debug.Assert(utf16Text[i] < 128, "A culture-invariant ToString() of a floating point expected to produce ASCII characters only.");
- buffer[i] = (byte)(utf16Text[i]);
+ destination[i] = (byte)(utf16Text[i]);
}
bytesWritten = length;
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Guid.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Guid.cs
index 009f8c66b5..c9a6efbaed 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Guid.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Guid.cs
@@ -24,7 +24,7 @@ namespace System.Buffers.Text
/// Formats a Guid as a UTF8 string.
/// </summary>
/// <param name="value">Value to format</param>
- /// <param name="buffer">Buffer to write the UTF8-formatted value to</param>
+ /// <param name="destination">Buffer to write the UTF8-formatted value to</param>
/// <param name="bytesWritten">Receives the length of the formatted text in bytes</param>
/// <param name="format">The standard format to use</param>
/// <returns>
@@ -41,7 +41,7 @@ namespace System.Buffers.Text
/// <exceptions>
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
- public static bool TryFormat(Guid value, Span<byte> buffer, out int bytesWritten, StandardFormat format = default)
+ public static bool TryFormat(Guid value, Span<byte> destination, out int bytesWritten, StandardFormat format = default)
{
const int INSERT_DASHES = unchecked((int)0x80000000);
const int NO_DASHES = 0;
@@ -86,7 +86,7 @@ namespace System.Buffers.Text
// At this point, the low byte of flags contains the minimum required length
- if ((byte)flags > buffer.Length)
+ if ((byte)flags > destination.Length)
{
bytesWritten = 0;
return false;
@@ -99,8 +99,8 @@ namespace System.Buffers.Text
if ((byte)flags != 0)
{
- buffer[0] = (byte)flags;
- buffer = buffer.Slice(1);
+ destination[0] = (byte)flags;
+ destination = destination.Slice(1);
}
flags >>= 8;
@@ -117,75 +117,75 @@ namespace System.Buffers.Text
// because it may have an observeable side effect (throwing).
// We use 8 instead of 7 so that we also capture the dash if we're asked to insert one.
- { var unused = buffer[8]; }
- FormattingHelpers.WriteHexByte(guidAsBytes.Byte03, buffer, 0, FormattingHelpers.HexCasing.Lowercase);
- FormattingHelpers.WriteHexByte(guidAsBytes.Byte02, buffer, 2, FormattingHelpers.HexCasing.Lowercase);
- FormattingHelpers.WriteHexByte(guidAsBytes.Byte01, buffer, 4, FormattingHelpers.HexCasing.Lowercase);
- FormattingHelpers.WriteHexByte(guidAsBytes.Byte00, buffer, 6, FormattingHelpers.HexCasing.Lowercase);
+ { var unused = destination[8]; }
+ FormattingHelpers.WriteHexByte(guidAsBytes.Byte03, destination, 0, FormattingHelpers.HexCasing.Lowercase);
+ FormattingHelpers.WriteHexByte(guidAsBytes.Byte02, destination, 2, FormattingHelpers.HexCasing.Lowercase);
+ FormattingHelpers.WriteHexByte(guidAsBytes.Byte01, destination, 4, FormattingHelpers.HexCasing.Lowercase);
+ FormattingHelpers.WriteHexByte(guidAsBytes.Byte00, destination, 6, FormattingHelpers.HexCasing.Lowercase);
if (flags < 0 /* use dash? */)
{
- buffer[8] = Dash;
- buffer = buffer.Slice(9);
+ destination[8] = Dash;
+ destination = destination.Slice(9);
}
else
{
- buffer = buffer.Slice(8);
+ destination = destination.Slice(8);
}
- { var unused = buffer[4]; }
- FormattingHelpers.WriteHexByte(guidAsBytes.Byte05, buffer, 0, FormattingHelpers.HexCasing.Lowercase);
- FormattingHelpers.WriteHexByte(guidAsBytes.Byte04, buffer, 2, FormattingHelpers.HexCasing.Lowercase);
+ { var unused = destination[4]; }
+ FormattingHelpers.WriteHexByte(guidAsBytes.Byte05, destination, 0, FormattingHelpers.HexCasing.Lowercase);
+ FormattingHelpers.WriteHexByte(guidAsBytes.Byte04, destination, 2, FormattingHelpers.HexCasing.Lowercase);
if (flags < 0 /* use dash? */)
{
- buffer[4] = Dash;
- buffer = buffer.Slice(5);
+ destination[4] = Dash;
+ destination = destination.Slice(5);
}
else
{
- buffer = buffer.Slice(4);
+ destination = destination.Slice(4);
}
- { var unused = buffer[4]; }
- FormattingHelpers.WriteHexByte(guidAsBytes.Byte07, buffer, 0, FormattingHelpers.HexCasing.Lowercase);
- FormattingHelpers.WriteHexByte(guidAsBytes.Byte06, buffer, 2, FormattingHelpers.HexCasing.Lowercase);
+ { var unused = destination[4]; }
+ FormattingHelpers.WriteHexByte(guidAsBytes.Byte07, destination, 0, FormattingHelpers.HexCasing.Lowercase);
+ FormattingHelpers.WriteHexByte(guidAsBytes.Byte06, destination, 2, FormattingHelpers.HexCasing.Lowercase);
if (flags < 0 /* use dash? */)
{
- buffer[4] = Dash;
- buffer = buffer.Slice(5);
+ destination[4] = Dash;
+ destination = destination.Slice(5);
}
else
{
- buffer = buffer.Slice(4);
+ destination = destination.Slice(4);
}
- { var unused = buffer[4]; }
- FormattingHelpers.WriteHexByte(guidAsBytes.Byte08, buffer, 0, FormattingHelpers.HexCasing.Lowercase);
- FormattingHelpers.WriteHexByte(guidAsBytes.Byte09, buffer, 2, FormattingHelpers.HexCasing.Lowercase);
+ { var unused = destination[4]; }
+ FormattingHelpers.WriteHexByte(guidAsBytes.Byte08, destination, 0, FormattingHelpers.HexCasing.Lowercase);
+ FormattingHelpers.WriteHexByte(guidAsBytes.Byte09, destination, 2, FormattingHelpers.HexCasing.Lowercase);
if (flags < 0 /* use dash? */)
{
- buffer[4] = Dash;
- buffer = buffer.Slice(5);
+ destination[4] = Dash;
+ destination = destination.Slice(5);
}
else
{
- buffer = buffer.Slice(4);
+ destination = destination.Slice(4);
}
- { var unused = buffer[11]; } // can't hoist bounds check on the final brace (if exists)
- FormattingHelpers.WriteHexByte(guidAsBytes.Byte10, buffer, 0, FormattingHelpers.HexCasing.Lowercase);
- FormattingHelpers.WriteHexByte(guidAsBytes.Byte11, buffer, 2, FormattingHelpers.HexCasing.Lowercase);
- FormattingHelpers.WriteHexByte(guidAsBytes.Byte12, buffer, 4, FormattingHelpers.HexCasing.Lowercase);
- FormattingHelpers.WriteHexByte(guidAsBytes.Byte13, buffer, 6, FormattingHelpers.HexCasing.Lowercase);
- FormattingHelpers.WriteHexByte(guidAsBytes.Byte14, buffer, 8, FormattingHelpers.HexCasing.Lowercase);
- FormattingHelpers.WriteHexByte(guidAsBytes.Byte15, buffer, 10, FormattingHelpers.HexCasing.Lowercase);
+ { var unused = destination[11]; } // can't hoist bounds check on the final brace (if exists)
+ FormattingHelpers.WriteHexByte(guidAsBytes.Byte10, destination, 0, FormattingHelpers.HexCasing.Lowercase);
+ FormattingHelpers.WriteHexByte(guidAsBytes.Byte11, destination, 2, FormattingHelpers.HexCasing.Lowercase);
+ FormattingHelpers.WriteHexByte(guidAsBytes.Byte12, destination, 4, FormattingHelpers.HexCasing.Lowercase);
+ FormattingHelpers.WriteHexByte(guidAsBytes.Byte13, destination, 6, FormattingHelpers.HexCasing.Lowercase);
+ FormattingHelpers.WriteHexByte(guidAsBytes.Byte14, destination, 8, FormattingHelpers.HexCasing.Lowercase);
+ FormattingHelpers.WriteHexByte(guidAsBytes.Byte15, destination, 10, FormattingHelpers.HexCasing.Lowercase);
if ((byte)flags != 0)
{
- buffer[12] = (byte)flags;
+ destination[12] = (byte)flags;
}
return true;
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Signed.D.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Signed.D.cs
index b4d772a1ff..ddfd4ac544 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Signed.D.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Signed.D.cs
@@ -5,10 +5,6 @@
using System.Diagnostics;
using System.Runtime.CompilerServices;
-#if !netstandard
-using Internal.Runtime.CompilerServices;
-#endif
-
namespace System.Buffers.Text
{
/// <summary>
@@ -17,7 +13,7 @@ namespace System.Buffers.Text
public static partial class Utf8Formatter
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool TryFormatInt64D(long value, byte precision, Span<byte> buffer, out int bytesWritten)
+ private static bool TryFormatInt64D(long value, byte precision, Span<byte> destination, out int bytesWritten)
{
bool insertNegationSign = false;
if (value < 0)
@@ -27,25 +23,25 @@ namespace System.Buffers.Text
if (value < 0)
{
Debug.Assert(value == Int64.MinValue);
- return TryFormatInt64D_MinValue(precision, buffer, out bytesWritten);
+ return TryFormatInt64D_MinValue(precision, destination, out bytesWritten);
}
}
- return TryFormatUInt64D((ulong)value, precision, buffer, insertNegationSign, out bytesWritten);
+ return TryFormatUInt64D((ulong)value, precision, destination, insertNegationSign, out bytesWritten);
}
[MethodImpl(MethodImplOptions.NoInlining)]
- private static bool TryFormatInt64D_MinValue(byte precision, Span<byte> buffer, out int bytesWritten)
+ private static bool TryFormatInt64D_MinValue(byte precision, Span<byte> destination, out int bytesWritten)
{
// Int64.MinValue must be treated specially since its two's complement negation doesn't fit into 64 bits.
// Instead, we'll perform one's complement negation and fix up the +1 later (-x := ~x + 1).
// Int64.MinValue = -9,223,372,036,854,775,808
// Int64.MaxValue = 9,223,372,036,854,775,807
- bool retVal = TryFormatUInt64D((ulong)Int64.MaxValue, precision, buffer, insertNegationSign: true, out int tempBytesWritten);
+ bool retVal = TryFormatUInt64D((ulong)Int64.MaxValue, precision, destination, insertNegationSign: true, out int tempBytesWritten);
if (retVal)
{
- buffer[tempBytesWritten - 1]++; // bump the last ASCII '7' to an '8'
+ destination[tempBytesWritten - 1]++; // bump the last ASCII '7' to an '8'
}
bytesWritten = tempBytesWritten;
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Signed.Default.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Signed.Default.cs
index 4555c70078..961c75a685 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Signed.Default.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Signed.Default.cs
@@ -13,36 +13,36 @@ namespace System.Buffers.Text
public static partial class Utf8Formatter
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool TryFormatInt64Default(long value, Span<byte> buffer, out int bytesWritten)
+ private static bool TryFormatInt64Default(long value, Span<byte> destination, out int bytesWritten)
{
if ((ulong)value < 10)
{
- return TryFormatUInt32SingleDigit((uint)value, buffer, out bytesWritten);
+ return TryFormatUInt32SingleDigit((uint)value, destination, out bytesWritten);
}
if (IntPtr.Size == 8) // x64
{
- return TryFormatInt64MultipleDigits(value, buffer, out bytesWritten);
+ return TryFormatInt64MultipleDigits(value, destination, out bytesWritten);
}
else // x86
{
if (value <= int.MaxValue && value >= int.MinValue)
{
- return TryFormatInt32MultipleDigits((int)value, buffer, out bytesWritten);
+ return TryFormatInt32MultipleDigits((int)value, destination, out bytesWritten);
}
else
{
if (value <= (long)Utf8Constants.BillionMaxUIntValue && value >= -(long)Utf8Constants.BillionMaxUIntValue)
{
return value < 0 ?
- TryFormatInt64MoreThanNegativeBillionMaxUInt(-value, buffer, out bytesWritten) :
- TryFormatUInt64LessThanBillionMaxUInt((ulong)value, buffer, out bytesWritten);
+ TryFormatInt64MoreThanNegativeBillionMaxUInt(-value, destination, out bytesWritten) :
+ TryFormatUInt64LessThanBillionMaxUInt((ulong)value, destination, out bytesWritten);
}
else
{
return value < 0 ?
- TryFormatInt64LessThanNegativeBillionMaxUInt(-value, buffer, out bytesWritten) :
- TryFormatUInt64MoreThanBillionMaxUInt((ulong)value, buffer, out bytesWritten);
+ TryFormatInt64LessThanNegativeBillionMaxUInt(-value, destination, out bytesWritten) :
+ TryFormatUInt64MoreThanBillionMaxUInt((ulong)value, destination, out bytesWritten);
}
}
}
@@ -50,65 +50,65 @@ namespace System.Buffers.Text
// TODO: Use this instead of TryFormatInt64Default to format numbers less than int.MaxValue
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool TryFormatInt32Default(int value, Span<byte> buffer, out int bytesWritten)
+ private static bool TryFormatInt32Default(int value, Span<byte> destination, out int bytesWritten)
{
if ((uint)value < 10)
{
- return TryFormatUInt32SingleDigit((uint)value, buffer, out bytesWritten);
+ return TryFormatUInt32SingleDigit((uint)value, destination, out bytesWritten);
}
- return TryFormatInt32MultipleDigits(value, buffer, out bytesWritten);
+ return TryFormatInt32MultipleDigits(value, destination, out bytesWritten);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool TryFormatInt32MultipleDigits(int value, Span<byte> buffer, out int bytesWritten)
+ private static bool TryFormatInt32MultipleDigits(int value, Span<byte> destination, out int bytesWritten)
{
if (value < 0)
{
value = -value;
int digitCount = FormattingHelpers.CountDigits((uint)value);
// WriteDigits does not do bounds checks
- if (digitCount >= buffer.Length)
+ if (digitCount >= destination.Length)
{
bytesWritten = 0;
return false;
}
- buffer[0] = Utf8Constants.Minus;
+ destination[0] = Utf8Constants.Minus;
bytesWritten = digitCount + 1;
- FormattingHelpers.WriteDigits((uint)value, buffer.Slice(1, digitCount));
+ FormattingHelpers.WriteDigits((uint)value, destination.Slice(1, digitCount));
return true;
}
else
{
- return TryFormatUInt32MultipleDigits((uint)value, buffer, out bytesWritten);
+ return TryFormatUInt32MultipleDigits((uint)value, destination, out bytesWritten);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool TryFormatInt64MultipleDigits(long value, Span<byte> buffer, out int bytesWritten)
+ private static bool TryFormatInt64MultipleDigits(long value, Span<byte> destination, out int bytesWritten)
{
if (value < 0)
{
value = -value;
int digitCount = FormattingHelpers.CountDigits((ulong)value);
// WriteDigits does not do bounds checks
- if (digitCount >= buffer.Length)
+ if (digitCount >= destination.Length)
{
bytesWritten = 0;
return false;
}
- buffer[0] = Utf8Constants.Minus;
+ destination[0] = Utf8Constants.Minus;
bytesWritten = digitCount + 1;
- FormattingHelpers.WriteDigits((ulong)value, buffer.Slice(1, digitCount));
+ FormattingHelpers.WriteDigits((ulong)value, destination.Slice(1, digitCount));
return true;
}
else
{
- return TryFormatUInt64MultipleDigits((ulong)value, buffer, out bytesWritten);
+ return TryFormatUInt64MultipleDigits((ulong)value, destination, out bytesWritten);
}
}
// Split long into two parts that can each fit in a uint - {1-10 digits}{9 digits}
- private static bool TryFormatInt64MoreThanNegativeBillionMaxUInt(long value, Span<byte> buffer, out int bytesWritten)
+ private static bool TryFormatInt64MoreThanNegativeBillionMaxUInt(long value, Span<byte> destination, out int bytesWritten)
{
uint overNineDigits = (uint)(value / Utf8Constants.Billion);
uint lastNineDigits = (uint)(value - (overNineDigits * Utf8Constants.Billion));
@@ -117,20 +117,20 @@ namespace System.Buffers.Text
Debug.Assert(digitCountOverNineDigits >= 1 && digitCountOverNineDigits <= 10);
int digitCount = digitCountOverNineDigits + 9;
// WriteDigits does not do bounds checks
- if (digitCount >= buffer.Length)
+ if (digitCount >= destination.Length)
{
bytesWritten = 0;
return false;
}
- buffer[0] = Utf8Constants.Minus;
+ destination[0] = Utf8Constants.Minus;
bytesWritten = digitCount + 1;
- FormattingHelpers.WriteDigits(overNineDigits, buffer.Slice(1, digitCountOverNineDigits));
- FormattingHelpers.WriteDigits(lastNineDigits, buffer.Slice(digitCountOverNineDigits + 1, 9));
+ FormattingHelpers.WriteDigits(overNineDigits, destination.Slice(1, digitCountOverNineDigits));
+ FormattingHelpers.WriteDigits(lastNineDigits, destination.Slice(digitCountOverNineDigits + 1, 9));
return true;
}
// Split long into three parts that can each fit in a uint - {1 digit}{9 digits}{9 digits}
- private static bool TryFormatInt64LessThanNegativeBillionMaxUInt(long value, Span<byte> buffer, out int bytesWritten)
+ private static bool TryFormatInt64LessThanNegativeBillionMaxUInt(long value, Span<byte> destination, out int bytesWritten)
{
// value can still be negative if value == long.MinValue
// Therefore, cast to ulong, since (ulong)value actually equals abs(long.MinValue)
@@ -143,16 +143,16 @@ namespace System.Buffers.Text
Debug.Assert(digitCountOverEighteenDigits == 1);
int digitCount = digitCountOverEighteenDigits + 18;
// WriteDigits does not do bounds checks
- if (digitCount >= buffer.Length)
+ if (digitCount >= destination.Length)
{
bytesWritten = 0;
return false;
}
- buffer[0] = Utf8Constants.Minus;
+ destination[0] = Utf8Constants.Minus;
bytesWritten = digitCount + 1;
- FormattingHelpers.WriteDigits(overEighteenDigits, buffer.Slice(1, digitCountOverEighteenDigits));
- FormattingHelpers.WriteDigits(middleNineDigits, buffer.Slice(digitCountOverEighteenDigits + 1, 9));
- FormattingHelpers.WriteDigits(lastNineDigits, buffer.Slice(digitCountOverEighteenDigits + 1 + 9, 9));
+ FormattingHelpers.WriteDigits(overEighteenDigits, destination.Slice(1, digitCountOverEighteenDigits));
+ FormattingHelpers.WriteDigits(middleNineDigits, destination.Slice(digitCountOverEighteenDigits + 1, 9));
+ FormattingHelpers.WriteDigits(lastNineDigits, destination.Slice(digitCountOverEighteenDigits + 1 + 9, 9));
return true;
}
}
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Signed.N.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Signed.N.cs
index 2fcd472715..412ca8eccd 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Signed.N.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Signed.N.cs
@@ -5,10 +5,6 @@
using System.Diagnostics;
using System.Runtime.CompilerServices;
-#if !netstandard
-using Internal.Runtime.CompilerServices;
-#endif
-
namespace System.Buffers.Text
{
/// <summary>
@@ -17,7 +13,7 @@ namespace System.Buffers.Text
public static partial class Utf8Formatter
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool TryFormatInt64N(long value, byte precision, Span<byte> buffer, out int bytesWritten)
+ private static bool TryFormatInt64N(long value, byte precision, Span<byte> destination, out int bytesWritten)
{
bool insertNegationSign = false;
if (value < 0)
@@ -27,25 +23,25 @@ namespace System.Buffers.Text
if (value < 0)
{
Debug.Assert(value == Int64.MinValue);
- return TryFormatInt64N_MinValue(precision, buffer, out bytesWritten);
+ return TryFormatInt64N_MinValue(precision, destination, out bytesWritten);
}
}
- return TryFormatUInt64N((ulong)value, precision, buffer, insertNegationSign, out bytesWritten);
+ return TryFormatUInt64N((ulong)value, precision, destination, insertNegationSign, out bytesWritten);
}
[MethodImpl(MethodImplOptions.NoInlining)]
- private static bool TryFormatInt64N_MinValue(byte precision, Span<byte> buffer, out int bytesWritten)
+ private static bool TryFormatInt64N_MinValue(byte precision, Span<byte> destination, out int bytesWritten)
{
// Int64.MinValue must be treated specially since its two's complement negation doesn't fit into 64 bits.
// Instead, we'll perform one's complement negation and fix up the +1 later (-x := ~x + 1).
// Int64.MinValue = -9,223,372,036,854,775,808 (26 digits, including minus and commas)
// Int64.MaxValue = 9,223,372,036,854,775,807
- bool retVal = TryFormatUInt64N((ulong)Int64.MaxValue, precision, buffer, insertNegationSign: true, out int tempBytesWritten);
+ bool retVal = TryFormatUInt64N((ulong)Int64.MaxValue, precision, destination, insertNegationSign: true, out int tempBytesWritten);
if (retVal)
{
- buffer[25]++; // bump the last ASCII '7' to an '8'
+ destination[25]++; // bump the last ASCII '7' to an '8'
}
bytesWritten = tempBytesWritten;
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Signed.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Signed.cs
index 2ef45f8a0c..87966ca358 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Signed.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Signed.cs
@@ -15,11 +15,11 @@ namespace System.Buffers.Text
// Common worker for all signed integer TryFormat overloads
//
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool TryFormatInt64(long value, ulong mask, Span<byte> buffer, out int bytesWritten, StandardFormat format)
+ private static bool TryFormatInt64(long value, ulong mask, Span<byte> destination, out int bytesWritten, StandardFormat format)
{
if (format.IsDefault)
{
- return TryFormatInt64Default(value, buffer, out bytesWritten);
+ return TryFormatInt64Default(value, destination, out bytesWritten);
}
switch (format.Symbol)
@@ -28,21 +28,21 @@ namespace System.Buffers.Text
case 'g':
if (format.HasPrecision)
throw new NotSupportedException(SR.Argument_GWithPrecisionNotSupported); // With a precision, 'G' can produce exponential format, even for integers.
- return TryFormatInt64D(value, format.Precision, buffer, out bytesWritten);
+ return TryFormatInt64D(value, format.Precision, destination, out bytesWritten);
case 'd':
case 'D':
- return TryFormatInt64D(value, format.Precision, buffer, out bytesWritten);
+ return TryFormatInt64D(value, format.Precision, destination, out bytesWritten);
case 'n':
case 'N':
- return TryFormatInt64N(value, format.Precision, buffer, out bytesWritten);
+ return TryFormatInt64N(value, format.Precision, destination, out bytesWritten);
case 'x':
- return TryFormatUInt64X((ulong)value & mask, format.Precision, true, buffer, out bytesWritten);
+ return TryFormatUInt64X((ulong)value & mask, format.Precision, true, destination, out bytesWritten);
case 'X':
- return TryFormatUInt64X((ulong)value & mask, format.Precision, false, buffer, out bytesWritten);
+ return TryFormatUInt64X((ulong)value & mask, format.Precision, false, destination, out bytesWritten);
default:
return ThrowHelper.TryFormatThrowFormatException(out bytesWritten);
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Unsigned.D.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Unsigned.D.cs
index 5fef90e11b..9cb8d64bc0 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Unsigned.D.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Unsigned.D.cs
@@ -9,7 +9,7 @@ namespace System.Buffers.Text
/// </summary>
public static partial class Utf8Formatter
{
- private static bool TryFormatUInt64D(ulong value, byte precision, Span<byte> buffer, bool insertNegationSign, out int bytesWritten)
+ private static bool TryFormatUInt64D(ulong value, byte precision, Span<byte> destination, bool insertNegationSign, out int bytesWritten)
{
// Calculate the actual digit count and the number of padding zeroes requested.
// From all of this we can get the required buffer length.
@@ -28,7 +28,7 @@ namespace System.Buffers.Text
requiredBufferLength++;
}
- if (requiredBufferLength > buffer.Length)
+ if (requiredBufferLength > destination.Length)
{
bytesWritten = 0;
return false;
@@ -38,15 +38,15 @@ namespace System.Buffers.Text
if (insertNegationSign)
{
- buffer[0] = Utf8Constants.Minus;
- buffer = buffer.Slice(1);
+ destination[0] = Utf8Constants.Minus;
+ destination = destination.Slice(1);
}
if (leadingZeroCount > 0)
{
- FormattingHelpers.FillWithAsciiZeros(buffer.Slice(0, leadingZeroCount));
+ FormattingHelpers.FillWithAsciiZeros(destination.Slice(0, leadingZeroCount));
}
- FormattingHelpers.WriteDigits(value, buffer.Slice(leadingZeroCount, digitCount));
+ FormattingHelpers.WriteDigits(value, destination.Slice(leadingZeroCount, digitCount));
return true;
}
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Unsigned.Default.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Unsigned.Default.cs
index 237cf1eae5..78105839c0 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Unsigned.Default.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Unsigned.Default.cs
@@ -13,32 +13,32 @@ namespace System.Buffers.Text
public static partial class Utf8Formatter
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool TryFormatUInt64Default(ulong value, Span<byte> buffer, out int bytesWritten)
+ private static bool TryFormatUInt64Default(ulong value, Span<byte> destination, out int bytesWritten)
{
if (value < 10)
{
- return TryFormatUInt32SingleDigit((uint)value, buffer, out bytesWritten);
+ return TryFormatUInt32SingleDigit((uint)value, destination, out bytesWritten);
}
if (IntPtr.Size == 8) // x64
{
- return TryFormatUInt64MultipleDigits(value, buffer, out bytesWritten);
+ return TryFormatUInt64MultipleDigits(value, destination, out bytesWritten);
}
else // x86
{
if (value <= uint.MaxValue)
{
- return TryFormatUInt32MultipleDigits((uint)value, buffer, out bytesWritten);
+ return TryFormatUInt32MultipleDigits((uint)value, destination, out bytesWritten);
}
else
{
if (value <= Utf8Constants.BillionMaxUIntValue)
{
- return TryFormatUInt64LessThanBillionMaxUInt(value, buffer, out bytesWritten);
+ return TryFormatUInt64LessThanBillionMaxUInt(value, destination, out bytesWritten);
}
else
{
- return TryFormatUInt64MoreThanBillionMaxUInt(value, buffer, out bytesWritten);
+ return TryFormatUInt64MoreThanBillionMaxUInt(value, destination, out bytesWritten);
}
}
}
@@ -46,73 +46,73 @@ namespace System.Buffers.Text
// TODO: Use this instead of TryFormatUInt64Default to format numbers less than uint.MaxValue
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool TryFormatUInt32Default(uint value, Span<byte> buffer, out int bytesWritten)
+ private static bool TryFormatUInt32Default(uint value, Span<byte> destination, out int bytesWritten)
{
if (value < 10)
{
- return TryFormatUInt32SingleDigit(value, buffer, out bytesWritten);
+ return TryFormatUInt32SingleDigit(value, destination, out bytesWritten);
}
- return TryFormatUInt32MultipleDigits(value, buffer, out bytesWritten);
+ return TryFormatUInt32MultipleDigits(value, destination, out bytesWritten);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool TryFormatUInt32SingleDigit(uint value, Span<byte> buffer, out int bytesWritten)
+ private static bool TryFormatUInt32SingleDigit(uint value, Span<byte> destination, out int bytesWritten)
{
- if (buffer.Length == 0)
+ if (destination.Length == 0)
{
bytesWritten = 0;
return false;
}
- buffer[0] = (byte)('0' + value);
+ destination[0] = (byte)('0' + value);
bytesWritten = 1;
return true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool TryFormatUInt32MultipleDigits(uint value, Span<byte> buffer, out int bytesWritten)
+ private static bool TryFormatUInt32MultipleDigits(uint value, Span<byte> destination, out int bytesWritten)
{
int digitCount = FormattingHelpers.CountDigits(value);
// WriteDigits does not do bounds checks
- if (digitCount > buffer.Length)
+ if (digitCount > destination.Length)
{
bytesWritten = 0;
return false;
}
bytesWritten = digitCount;
- FormattingHelpers.WriteDigits(value, buffer.Slice(0, digitCount));
+ FormattingHelpers.WriteDigits(value, destination.Slice(0, digitCount));
return true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool TryFormatUInt64SingleDigit(ulong value, Span<byte> buffer, out int bytesWritten)
+ private static bool TryFormatUInt64SingleDigit(ulong value, Span<byte> destination, out int bytesWritten)
{
- if (buffer.Length == 0)
+ if (destination.Length == 0)
{
bytesWritten = 0;
return false;
}
- buffer[0] = (byte)('0' + value);
+ destination[0] = (byte)('0' + value);
bytesWritten = 1;
return true;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool TryFormatUInt64MultipleDigits(ulong value, Span<byte> buffer, out int bytesWritten)
+ private static bool TryFormatUInt64MultipleDigits(ulong value, Span<byte> destination, out int bytesWritten)
{
int digitCount = FormattingHelpers.CountDigits(value);
// WriteDigits does not do bounds checks
- if (digitCount > buffer.Length)
+ if (digitCount > destination.Length)
{
bytesWritten = 0;
return false;
}
bytesWritten = digitCount;
- FormattingHelpers.WriteDigits(value, buffer.Slice(0, digitCount));
+ FormattingHelpers.WriteDigits(value, destination.Slice(0, digitCount));
return true;
}
// Split ulong into two parts that can each fit in a uint - {1-10 digits}{9 digits}
- private static bool TryFormatUInt64LessThanBillionMaxUInt(ulong value, Span<byte> buffer, out int bytesWritten)
+ private static bool TryFormatUInt64LessThanBillionMaxUInt(ulong value, Span<byte> destination, out int bytesWritten)
{
uint overNineDigits = (uint)(value / Utf8Constants.Billion);
uint lastNineDigits = (uint)(value - (overNineDigits * Utf8Constants.Billion));
@@ -121,19 +121,19 @@ namespace System.Buffers.Text
Debug.Assert(digitCountOverNineDigits >= 1 && digitCountOverNineDigits <= 10);
int digitCount = digitCountOverNineDigits + 9;
// WriteDigits does not do bounds checks
- if (digitCount > buffer.Length)
+ if (digitCount > destination.Length)
{
bytesWritten = 0;
return false;
}
bytesWritten = digitCount;
- FormattingHelpers.WriteDigits(overNineDigits, buffer.Slice(0, digitCountOverNineDigits));
- FormattingHelpers.WriteDigits(lastNineDigits, buffer.Slice(digitCountOverNineDigits, 9));
+ FormattingHelpers.WriteDigits(overNineDigits, destination.Slice(0, digitCountOverNineDigits));
+ FormattingHelpers.WriteDigits(lastNineDigits, destination.Slice(digitCountOverNineDigits, 9));
return true;
}
// Split ulong into three parts that can each fit in a uint - {1-2 digits}{9 digits}{9 digits}
- private static bool TryFormatUInt64MoreThanBillionMaxUInt(ulong value, Span<byte> buffer, out int bytesWritten)
+ private static bool TryFormatUInt64MoreThanBillionMaxUInt(ulong value, Span<byte> destination, out int bytesWritten)
{
ulong overNineDigits = value / Utf8Constants.Billion;
uint lastNineDigits = (uint)(value - (overNineDigits * Utf8Constants.Billion));
@@ -144,15 +144,15 @@ namespace System.Buffers.Text
Debug.Assert(digitCountOverEighteenDigits >= 1 && digitCountOverEighteenDigits <= 2);
int digitCount = digitCountOverEighteenDigits + 18;
// WriteDigits does not do bounds checks
- if (digitCount > buffer.Length)
+ if (digitCount > destination.Length)
{
bytesWritten = 0;
return false;
}
bytesWritten = digitCount;
- FormattingHelpers.WriteDigits(overEighteenDigits, buffer.Slice(0, digitCountOverEighteenDigits));
- FormattingHelpers.WriteDigits(middleNineDigits, buffer.Slice(digitCountOverEighteenDigits, 9));
- FormattingHelpers.WriteDigits(lastNineDigits, buffer.Slice(digitCountOverEighteenDigits + 9, 9));
+ FormattingHelpers.WriteDigits(overEighteenDigits, destination.Slice(0, digitCountOverEighteenDigits));
+ FormattingHelpers.WriteDigits(middleNineDigits, destination.Slice(digitCountOverEighteenDigits, 9));
+ FormattingHelpers.WriteDigits(lastNineDigits, destination.Slice(digitCountOverEighteenDigits + 9, 9));
return true;
}
}
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Unsigned.N.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Unsigned.N.cs
index e3b2b7a05e..ce21c0d3dd 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Unsigned.N.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Unsigned.N.cs
@@ -9,7 +9,7 @@ namespace System.Buffers.Text
/// </summary>
public static partial class Utf8Formatter
{
- private static bool TryFormatUInt64N(ulong value, byte precision, Span<byte> buffer, bool insertNegationSign, out int bytesWritten)
+ private static bool TryFormatUInt64N(ulong value, byte precision, Span<byte> destination, bool insertNegationSign, out int bytesWritten)
{
// Calculate the actual digit count, number of group separators required, and the
// number of trailing zeros requested. From all of this we can get the required
@@ -30,7 +30,7 @@ namespace System.Buffers.Text
requiredBufferLength++;
}
- if (requiredBufferLength > buffer.Length)
+ if (requiredBufferLength > destination.Length)
{
bytesWritten = 0;
return false;
@@ -40,16 +40,16 @@ namespace System.Buffers.Text
if (insertNegationSign)
{
- buffer[0] = Utf8Constants.Minus;
- buffer = buffer.Slice(1);
+ destination[0] = Utf8Constants.Minus;
+ destination = destination.Slice(1);
}
- FormattingHelpers.WriteDigitsWithGroupSeparator(value, buffer.Slice(0, digitCount + commaCount));
+ FormattingHelpers.WriteDigitsWithGroupSeparator(value, destination.Slice(0, digitCount + commaCount));
if (trailingZeroCount > 0)
{
- buffer[digitCount + commaCount] = Utf8Constants.Period;
- FormattingHelpers.FillWithAsciiZeros(buffer.Slice(digitCount + commaCount + 1, trailingZeroCount));
+ destination[digitCount + commaCount] = Utf8Constants.Period;
+ FormattingHelpers.FillWithAsciiZeros(destination.Slice(digitCount + commaCount + 1, trailingZeroCount));
}
return true;
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Unsigned.X.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Unsigned.X.cs
index 5a8209f8b1..4cf4d52b5c 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Unsigned.X.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Unsigned.X.cs
@@ -9,14 +9,14 @@ namespace System.Buffers.Text
/// </summary>
public static partial class Utf8Formatter
{
- private static bool TryFormatUInt64X(ulong value, byte precision, bool useLower, Span<byte> buffer, out int bytesWritten)
+ private static bool TryFormatUInt64X(ulong value, byte precision, bool useLower, Span<byte> destination, out int bytesWritten)
{
int actualDigitCount = FormattingHelpers.CountHexDigits(value);
int computedOutputLength = (precision == StandardFormat.NoPrecision)
? actualDigitCount
: Math.Max(precision, actualDigitCount);
- if (buffer.Length < computedOutputLength)
+ if (destination.Length < computedOutputLength)
{
bytesWritten = 0;
return false;
@@ -35,9 +35,9 @@ namespace System.Buffers.Text
// casing output lengths of 2, 4, 8, and 16 and running them down optimized
// code paths.
- while ((uint)(--computedOutputLength) < (uint)buffer.Length)
+ while ((uint)(--computedOutputLength) < (uint)destination.Length)
{
- buffer[computedOutputLength] = (byte)hexTable[(int)value & 0xf];
+ destination[computedOutputLength] = (byte)hexTable[(int)value & 0xf];
value >>= 4;
}
return true;
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Unsigned.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Unsigned.cs
index 2a95f17241..b143061a58 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Unsigned.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.Unsigned.cs
@@ -15,11 +15,11 @@ namespace System.Buffers.Text
// Common worker for all unsigned integer TryFormat overloads
//
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool TryFormatUInt64(ulong value, Span<byte> buffer, out int bytesWritten, StandardFormat format)
+ private static bool TryFormatUInt64(ulong value, Span<byte> destination, out int bytesWritten, StandardFormat format)
{
if (format.IsDefault)
{
- return TryFormatUInt64Default(value, buffer, out bytesWritten);
+ return TryFormatUInt64Default(value, destination, out bytesWritten);
}
switch (format.Symbol)
@@ -28,21 +28,21 @@ namespace System.Buffers.Text
case 'g':
if (format.HasPrecision)
throw new NotSupportedException(SR.Argument_GWithPrecisionNotSupported); // With a precision, 'G' can produce exponential format, even for integers.
- return TryFormatUInt64D(value, format.Precision, buffer, insertNegationSign: false, out bytesWritten);
+ return TryFormatUInt64D(value, format.Precision, destination, insertNegationSign: false, out bytesWritten);
case 'd':
case 'D':
- return TryFormatUInt64D(value, format.Precision, buffer, insertNegationSign: false, out bytesWritten);
+ return TryFormatUInt64D(value, format.Precision, destination, insertNegationSign: false, out bytesWritten);
case 'n':
case 'N':
- return TryFormatUInt64N(value, format.Precision, buffer, insertNegationSign: false, out bytesWritten);
+ return TryFormatUInt64N(value, format.Precision, destination, insertNegationSign: false, out bytesWritten);
case 'x':
- return TryFormatUInt64X(value, format.Precision, true /* useLower */, buffer, out bytesWritten);
+ return TryFormatUInt64X(value, format.Precision, true /* useLower */, destination, out bytesWritten);
case 'X':
- return TryFormatUInt64X(value, format.Precision, false /* useLower */, buffer, out bytesWritten);
+ return TryFormatUInt64X(value, format.Precision, false /* useLower */, destination, out bytesWritten);
default:
return ThrowHelper.TryFormatThrowFormatException(out bytesWritten);
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.cs
index a25155cab9..3b83fb7512 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Integer.cs
@@ -13,7 +13,7 @@ namespace System.Buffers.Text
/// Formats a Byte as a UTF8 string.
/// </summary>
/// <param name="value">Value to format</param>
- /// <param name="buffer">Buffer to write the UTF8-formatted value to</param>
+ /// <param name="destination">Buffer to write the UTF8-formatted value to</param>
/// <param name="bytesWritten">Receives the length of the formatted text in bytes</param>
/// <param name="format">The standard format to use</param>
/// <returns>
@@ -30,14 +30,14 @@ namespace System.Buffers.Text
/// <exceptions>
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
- public static bool TryFormat(byte value, Span<byte> buffer, out int bytesWritten, StandardFormat format = default)
- => TryFormatUInt64(value, buffer, out bytesWritten, format);
+ public static bool TryFormat(byte value, Span<byte> destination, out int bytesWritten, StandardFormat format = default)
+ => TryFormatUInt64(value, destination, out bytesWritten, format);
/// <summary>
/// Formats an SByte as a UTF8 string.
/// </summary>
/// <param name="value">Value to format</param>
- /// <param name="buffer">Buffer to write the UTF8-formatted value to</param>
+ /// <param name="destination">Buffer to write the UTF8-formatted value to</param>
/// <param name="bytesWritten">Receives the length of the formatted text in bytes</param>
/// <param name="format">The standard format to use</param>
/// <returns>
@@ -55,14 +55,14 @@ namespace System.Buffers.Text
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
[CLSCompliant(false)]
- public static bool TryFormat(sbyte value, Span<byte> buffer, out int bytesWritten, StandardFormat format = default)
- => TryFormatInt64(value, 0xff, buffer, out bytesWritten, format);
+ public static bool TryFormat(sbyte value, Span<byte> destination, out int bytesWritten, StandardFormat format = default)
+ => TryFormatInt64(value, 0xff, destination, out bytesWritten, format);
/// <summary>
/// Formats a Unt16 as a UTF8 string.
/// </summary>
/// <param name="value">Value to format</param>
- /// <param name="buffer">Buffer to write the UTF8-formatted value to</param>
+ /// <param name="destination">Buffer to write the UTF8-formatted value to</param>
/// <param name="bytesWritten">Receives the length of the formatted text in bytes</param>
/// <param name="format">The standard format to use</param>
/// <returns>
@@ -80,14 +80,14 @@ namespace System.Buffers.Text
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
[CLSCompliant(false)]
- public static bool TryFormat(ushort value, Span<byte> buffer, out int bytesWritten, StandardFormat format = default)
- => TryFormatUInt64(value, buffer, out bytesWritten, format);
+ public static bool TryFormat(ushort value, Span<byte> destination, out int bytesWritten, StandardFormat format = default)
+ => TryFormatUInt64(value, destination, out bytesWritten, format);
/// <summary>
/// Formats an Int16 as a UTF8 string.
/// </summary>
/// <param name="value">Value to format</param>
- /// <param name="buffer">Buffer to write the UTF8-formatted value to</param>
+ /// <param name="destination">Buffer to write the UTF8-formatted value to</param>
/// <param name="bytesWritten">Receives the length of the formatted text in bytes</param>
/// <param name="format">The standard format to use</param>
/// <returns>
@@ -104,14 +104,14 @@ namespace System.Buffers.Text
/// <exceptions>
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
- public static bool TryFormat(short value, Span<byte> buffer, out int bytesWritten, StandardFormat format = default)
- => TryFormatInt64(value, 0xffff, buffer, out bytesWritten, format);
+ public static bool TryFormat(short value, Span<byte> destination, out int bytesWritten, StandardFormat format = default)
+ => TryFormatInt64(value, 0xffff, destination, out bytesWritten, format);
/// <summary>
/// Formats a UInt32 as a UTF8 string.
/// </summary>
/// <param name="value">Value to format</param>
- /// <param name="buffer">Buffer to write the UTF8-formatted value to</param>
+ /// <param name="destination">Buffer to write the UTF8-formatted value to</param>
/// <param name="bytesWritten">Receives the length of the formatted text in bytes</param>
/// <param name="format">The standard format to use</param>
/// <returns>
@@ -129,14 +129,14 @@ namespace System.Buffers.Text
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
[CLSCompliant(false)]
- public static bool TryFormat(uint value, Span<byte> buffer, out int bytesWritten, StandardFormat format = default)
- => TryFormatUInt64(value, buffer, out bytesWritten, format);
+ public static bool TryFormat(uint value, Span<byte> destination, out int bytesWritten, StandardFormat format = default)
+ => TryFormatUInt64(value, destination, out bytesWritten, format);
/// <summary>
/// Formats an Int32 as a UTF8 string.
/// </summary>
/// <param name="value">Value to format</param>
- /// <param name="buffer">Buffer to write the UTF8-formatted value to</param>
+ /// <param name="destination">Buffer to write the UTF8-formatted value to</param>
/// <param name="bytesWritten">Receives the length of the formatted text in bytes</param>
/// <param name="format">The standard format to use</param>
/// <returns>
@@ -153,14 +153,14 @@ namespace System.Buffers.Text
/// <exceptions>
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
- public static bool TryFormat(int value, Span<byte> buffer, out int bytesWritten, StandardFormat format = default)
- => TryFormatInt64(value, 0xffffffff, buffer, out bytesWritten, format);
+ public static bool TryFormat(int value, Span<byte> destination, out int bytesWritten, StandardFormat format = default)
+ => TryFormatInt64(value, 0xffffffff, destination, out bytesWritten, format);
/// <summary>
/// Formats a UInt64 as a UTF8 string.
/// </summary>
/// <param name="value">Value to format</param>
- /// <param name="buffer">Buffer to write the UTF8-formatted value to</param>
+ /// <param name="destination">Buffer to write the UTF8-formatted value to</param>
/// <param name="bytesWritten">Receives the length of the formatted text in bytes</param>
/// <param name="format">The standard format to use</param>
/// <returns>
@@ -178,14 +178,14 @@ namespace System.Buffers.Text
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
[CLSCompliant(false)]
- public static bool TryFormat(ulong value, Span<byte> buffer, out int bytesWritten, StandardFormat format = default)
- => TryFormatUInt64(value, buffer, out bytesWritten, format);
+ public static bool TryFormat(ulong value, Span<byte> destination, out int bytesWritten, StandardFormat format = default)
+ => TryFormatUInt64(value, destination, out bytesWritten, format);
/// <summary>
/// Formats an Int64 as a UTF8 string.
/// </summary>
/// <param name="value">Value to format</param>
- /// <param name="buffer">Buffer to write the UTF8-formatted value to</param>
+ /// <param name="destination">Buffer to write the UTF8-formatted value to</param>
/// <param name="bytesWritten">Receives the length of the formatted text in bytes</param>
/// <param name="format">The standard format to use</param>
/// <returns>
@@ -202,7 +202,7 @@ namespace System.Buffers.Text
/// <exceptions>
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
- public static bool TryFormat(long value, Span<byte> buffer, out int bytesWritten, StandardFormat format = default)
- => TryFormatInt64(value, 0xffffffffffffffff, buffer, out bytesWritten, format);
+ public static bool TryFormat(long value, Span<byte> destination, out int bytesWritten, StandardFormat format = default)
+ => TryFormatInt64(value, 0xffffffffffffffff, destination, out bytesWritten, format);
}
}
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.TimeSpan.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.TimeSpan.cs
index 2c8dacaa66..3f40291e46 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.TimeSpan.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.TimeSpan.cs
@@ -12,7 +12,7 @@ namespace System.Buffers.Text
/// Formats a TimeSpan as a UTF8 string.
/// </summary>
/// <param name="value">Value to format</param>
- /// <param name="buffer">Buffer to write the UTF8-formatted value to</param>
+ /// <param name="destination">Buffer to write the UTF8-formatted value to</param>
/// <param name="bytesWritten">Receives the length of the formatted text in bytes</param>
/// <param name="format">The standard format to use</param>
/// <returns>
@@ -28,7 +28,7 @@ namespace System.Buffers.Text
/// <exceptions>
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
- public static bool TryFormat(TimeSpan value, Span<byte> buffer, out int bytesWritten, StandardFormat format = default)
+ public static bool TryFormat(TimeSpan value, Span<byte> destination, out int bytesWritten, StandardFormat format = default)
{
char symbol = FormattingHelpers.GetSymbolOrDefault(format, 'c');
@@ -171,7 +171,7 @@ AfterComputeFraction:
requiredOutputLength++; // for the leading '-' sign
}
- if (buffer.Length < requiredOutputLength)
+ if (destination.Length < requiredOutputLength)
{
bytesWritten = 0;
return false;
@@ -184,32 +184,32 @@ AfterComputeFraction:
// Write leading '-' if necessary
if (value.Ticks < 0)
{
- buffer[idx++] = Utf8Constants.Minus;
+ destination[idx++] = Utf8Constants.Minus;
}
// Write day (and separator) if necessary
if (dayDigits > 0)
{
- FormattingHelpers.WriteDigits(days, buffer.Slice(idx, dayDigits));
+ FormattingHelpers.WriteDigits(days, destination.Slice(idx, dayDigits));
idx += dayDigits;
- buffer[idx++] = (symbol == 'c') ? Utf8Constants.Period : Utf8Constants.Colon;
+ destination[idx++] = (symbol == 'c') ? Utf8Constants.Period : Utf8Constants.Colon;
}
// Write "[h]h:mm:ss"
- FormattingHelpers.WriteDigits(hours, buffer.Slice(idx, hourDigits));
+ FormattingHelpers.WriteDigits(hours, destination.Slice(idx, hourDigits));
idx += hourDigits;
- buffer[idx++] = Utf8Constants.Colon;
- FormattingHelpers.WriteDigits((uint)minutes, buffer.Slice(idx, 2));
+ destination[idx++] = Utf8Constants.Colon;
+ FormattingHelpers.WriteDigits((uint)minutes, destination.Slice(idx, 2));
idx += 2;
- buffer[idx++] = Utf8Constants.Colon;
- FormattingHelpers.WriteDigits((uint)seconds, buffer.Slice(idx, 2));
+ destination[idx++] = Utf8Constants.Colon;
+ FormattingHelpers.WriteDigits((uint)seconds, destination.Slice(idx, 2));
idx += 2;
// Write fraction (and separator) if necessary
if (fractionDigits > 0)
{
- buffer[idx++] = Utf8Constants.Period;
- FormattingHelpers.WriteDigits(fraction, buffer.Slice(idx, fractionDigits));
+ destination[idx++] = Utf8Constants.Period;
+ FormattingHelpers.WriteDigits(fraction, destination.Slice(idx, fractionDigits));
idx += fractionDigits;
}
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Boolean.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Boolean.cs
index 51567ba04c..20b627eb33 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Boolean.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Boolean.cs
@@ -9,7 +9,7 @@ namespace System.Buffers.Text
/// <summary>
/// Parses a Boolean at the start of a Utf8 string.
/// </summary>
- /// <param name="text">The Utf8 string to parse</param>
+ /// <param name="source">The Utf8 string to parse</param>
/// <param name="value">Receives the parsed value</param>
/// <param name="bytesConsumed">On a successful parse, receives the length in bytes of the substring that was parsed </param>
/// <param name="standardFormat">Expected format of the Utf8 string</param>
@@ -25,29 +25,29 @@ namespace System.Buffers.Text
/// <exceptions>
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
- public static bool TryParse(ReadOnlySpan<byte> text, out bool value, out int bytesConsumed, char standardFormat = default)
+ public static bool TryParse(ReadOnlySpan<byte> source, out bool value, out int bytesConsumed, char standardFormat = default)
{
if (!(standardFormat == default(char) || standardFormat == 'G' || standardFormat == 'l'))
return ThrowHelper.TryParseThrowFormatException(out value, out bytesConsumed);
- if (text.Length >= 4)
+ if (source.Length >= 4)
{
- if ((text[0] == 'T' || text[0] == 't') &&
- (text[1] == 'R' || text[1] == 'r') &&
- (text[2] == 'U' || text[2] == 'u') &&
- (text[3] == 'E' || text[3] == 'e'))
+ if ((source[0] == 'T' || source[0] == 't') &&
+ (source[1] == 'R' || source[1] == 'r') &&
+ (source[2] == 'U' || source[2] == 'u') &&
+ (source[3] == 'E' || source[3] == 'e'))
{
bytesConsumed = 4;
value = true;
return true;
}
- if (text.Length >= 5)
+ if (source.Length >= 5)
{
- if ((text[0] == 'F' || text[0] == 'f') &&
- (text[1] == 'A' || text[1] == 'a') &&
- (text[2] == 'L' || text[2] == 'l') &&
- (text[3] == 'S' || text[3] == 's') &&
- (text[4] == 'E' || text[4] == 'e'))
+ if ((source[0] == 'F' || source[0] == 'f') &&
+ (source[1] == 'A' || source[1] == 'a') &&
+ (source[2] == 'L' || source[2] == 'l') &&
+ (source[3] == 'S' || source[3] == 's') &&
+ (source[4] == 'E' || source[4] == 'e'))
{
bytesConsumed = 5;
value = false;
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.Default.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.Default.cs
index 73c21c8535..73578ea88c 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.Default.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.Default.cs
@@ -14,30 +14,30 @@ namespace System.Buffers.Text
// --------------------------
// 05/25/2017 10:30:15 -08:00
//
- private static bool TryParseDateTimeOffsetDefault(ReadOnlySpan<byte> text, out DateTimeOffset value, out int bytesConsumed)
+ private static bool TryParseDateTimeOffsetDefault(ReadOnlySpan<byte> source, out DateTimeOffset value, out int bytesConsumed)
{
- if (text.Length < 26)
+ if (source.Length < 26)
{
bytesConsumed = 0;
value = default;
return false;
}
- if (!TryParseDateTimeG(text, out DateTime dateTime, out _, out _))
+ if (!TryParseDateTimeG(source, out DateTime dateTime, out _, out _))
{
bytesConsumed = 0;
value = default;
return false;
}
- if (text[19] != Utf8Constants.Space)
+ if (source[19] != Utf8Constants.Space)
{
bytesConsumed = 0;
value = default;
return false;
}
- byte sign = text[20];
+ byte sign = source[20];
if (sign != Utf8Constants.Plus && sign != Utf8Constants.Minus)
{
bytesConsumed = 0;
@@ -47,8 +47,8 @@ namespace System.Buffers.Text
int offsetHours;
{
- uint digit1 = text[21] - 48u; // '0'
- uint digit2 = text[22] - 48u; // '0'
+ uint digit1 = source[21] - 48u; // '0'
+ uint digit2 = source[22] - 48u; // '0'
if (digit1 > 9 || digit2 > 9)
{
@@ -60,7 +60,7 @@ namespace System.Buffers.Text
offsetHours = (int)(digit1 * 10 + digit2);
}
- if (text[23] != Utf8Constants.Colon)
+ if (source[23] != Utf8Constants.Colon)
{
bytesConsumed = 0;
value = default;
@@ -69,8 +69,8 @@ namespace System.Buffers.Text
int offsetMinutes;
{
- uint digit1 = text[24] - 48u; // '0'
- uint digit2 = text[25] - 48u; // '0'
+ uint digit1 = source[24] - 48u; // '0'
+ uint digit2 = source[25] - 48u; // '0'
if (digit1 > 9 || digit2 > 9)
{
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.G.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.G.cs
index 4850bbbab8..ed18c7ba31 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.G.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.G.cs
@@ -15,9 +15,9 @@ namespace System.Buffers.Text
// ---------------------------------
// 05/25/2017 10:30:15
//
- private static bool TryParseDateTimeG(ReadOnlySpan<byte> text, out DateTime value, out DateTimeOffset valueAsOffset, out int bytesConsumed)
+ private static bool TryParseDateTimeG(ReadOnlySpan<byte> source, out DateTime value, out DateTimeOffset valueAsOffset, out int bytesConsumed)
{
- if (text.Length < 19)
+ if (source.Length < 19)
{
bytesConsumed = 0;
value = default;
@@ -27,8 +27,8 @@ namespace System.Buffers.Text
int month;
{
- uint digit1 = text[0] - 48u; // '0'
- uint digit2 = text[1] - 48u; // '0'
+ uint digit1 = source[0] - 48u; // '0'
+ uint digit2 = source[1] - 48u; // '0'
if (digit1 > 9 || digit2 > 9)
{
@@ -41,7 +41,7 @@ namespace System.Buffers.Text
month = (int)(digit1 * 10 + digit2);
}
- if (text[2] != Utf8Constants.Slash)
+ if (source[2] != Utf8Constants.Slash)
{
bytesConsumed = 0;
value = default;
@@ -51,8 +51,8 @@ namespace System.Buffers.Text
int day;
{
- uint digit1 = text[3] - 48u; // '0'
- uint digit2 = text[4] - 48u; // '0'
+ uint digit1 = source[3] - 48u; // '0'
+ uint digit2 = source[4] - 48u; // '0'
if (digit1 > 9 || digit2 > 9)
{
@@ -65,7 +65,7 @@ namespace System.Buffers.Text
day = (int)(digit1 * 10 + digit2);
}
- if (text[5] != Utf8Constants.Slash)
+ if (source[5] != Utf8Constants.Slash)
{
bytesConsumed = 0;
value = default;
@@ -75,10 +75,10 @@ namespace System.Buffers.Text
int year;
{
- uint digit1 = text[6] - 48u; // '0'
- uint digit2 = text[7] - 48u; // '0'
- uint digit3 = text[8] - 48u; // '0'
- uint digit4 = text[9] - 48u; // '0'
+ uint digit1 = source[6] - 48u; // '0'
+ uint digit2 = source[7] - 48u; // '0'
+ uint digit3 = source[8] - 48u; // '0'
+ uint digit4 = source[9] - 48u; // '0'
if (digit1 > 9 || digit2 > 9 || digit3 > 9 || digit4 > 9)
{
@@ -91,7 +91,7 @@ namespace System.Buffers.Text
year = (int)(digit1 * 1000 + digit2 * 100 + digit3 * 10 + digit4);
}
- if (text[10] != Utf8Constants.Space)
+ if (source[10] != Utf8Constants.Space)
{
bytesConsumed = 0;
value = default;
@@ -101,8 +101,8 @@ namespace System.Buffers.Text
int hour;
{
- uint digit1 = text[11] - 48u; // '0'
- uint digit2 = text[12] - 48u; // '0'
+ uint digit1 = source[11] - 48u; // '0'
+ uint digit2 = source[12] - 48u; // '0'
if (digit1 > 9 || digit2 > 9)
{
@@ -115,7 +115,7 @@ namespace System.Buffers.Text
hour = (int)(digit1 * 10 + digit2);
}
- if (text[13] != Utf8Constants.Colon)
+ if (source[13] != Utf8Constants.Colon)
{
bytesConsumed = 0;
value = default;
@@ -125,8 +125,8 @@ namespace System.Buffers.Text
int minute;
{
- uint digit1 = text[14] - 48u; // '0'
- uint digit2 = text[15] - 48u; // '0'
+ uint digit1 = source[14] - 48u; // '0'
+ uint digit2 = source[15] - 48u; // '0'
if (digit1 > 9 || digit2 > 9)
{
@@ -139,7 +139,7 @@ namespace System.Buffers.Text
minute = (int)(digit1 * 10 + digit2);
}
- if (text[16] != Utf8Constants.Colon)
+ if (source[16] != Utf8Constants.Colon)
{
bytesConsumed = 0;
value = default;
@@ -149,8 +149,8 @@ namespace System.Buffers.Text
int second;
{
- uint digit1 = text[17] - 48u; // '0'
- uint digit2 = text[18] - 48u; // '0'
+ uint digit1 = source[17] - 48u; // '0'
+ uint digit2 = source[18] - 48u; // '0'
if (digit1 > 9 || digit2 > 9)
{
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.O.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.O.cs
index a3028fe984..8d2c681f68 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.O.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.O.cs
@@ -17,9 +17,9 @@ namespace System.Buffers.Text
// 2017-06-12T05:30:45.7680000Z (Z is short for "+00:00" but also distinguishes DateTimeKind.Utc from DateTimeKind.Local)
// 2017-06-12T05:30:45.7680000 (interpreted as local time wrt to current time zone)
//
- private static bool TryParseDateTimeOffsetO(ReadOnlySpan<byte> text, out DateTimeOffset value, out int bytesConsumed, out DateTimeKind kind)
+ private static bool TryParseDateTimeOffsetO(ReadOnlySpan<byte> source, out DateTimeOffset value, out int bytesConsumed, out DateTimeKind kind)
{
- if (text.Length < 27)
+ if (source.Length < 27)
{
value = default;
bytesConsumed = 0;
@@ -29,10 +29,10 @@ namespace System.Buffers.Text
int year;
{
- uint digit1 = text[0] - 48u; // '0'
- uint digit2 = text[1] - 48u; // '0'
- uint digit3 = text[2] - 48u; // '0'
- uint digit4 = text[3] - 48u; // '0'
+ uint digit1 = source[0] - 48u; // '0'
+ uint digit2 = source[1] - 48u; // '0'
+ uint digit3 = source[2] - 48u; // '0'
+ uint digit4 = source[3] - 48u; // '0'
if (digit1 > 9 || digit2 > 9 || digit3 > 9 || digit4 > 9)
{
@@ -45,7 +45,7 @@ namespace System.Buffers.Text
year = (int)(digit1 * 1000 + digit2 * 100 + digit3 * 10 + digit4);
}
- if (text[4] != Utf8Constants.Hyphen)
+ if (source[4] != Utf8Constants.Hyphen)
{
value = default;
bytesConsumed = 0;
@@ -55,8 +55,8 @@ namespace System.Buffers.Text
int month;
{
- uint digit1 = text[5] - 48u; // '0'
- uint digit2 = text[6] - 48u; // '0'
+ uint digit1 = source[5] - 48u; // '0'
+ uint digit2 = source[6] - 48u; // '0'
if (digit1 > 9 || digit2 > 9)
{
@@ -69,7 +69,7 @@ namespace System.Buffers.Text
month = (int)(digit1 * 10 + digit2);
}
- if (text[7] != Utf8Constants.Hyphen)
+ if (source[7] != Utf8Constants.Hyphen)
{
value = default;
bytesConsumed = 0;
@@ -79,8 +79,8 @@ namespace System.Buffers.Text
int day;
{
- uint digit1 = text[8] - 48u; // '0'
- uint digit2 = text[9] - 48u; // '0'
+ uint digit1 = source[8] - 48u; // '0'
+ uint digit2 = source[9] - 48u; // '0'
if (digit1 > 9 || digit2 > 9)
{
@@ -93,7 +93,7 @@ namespace System.Buffers.Text
day = (int)(digit1 * 10 + digit2);
}
- if (text[10] != 'T')
+ if (source[10] != 'T')
{
value = default;
bytesConsumed = 0;
@@ -103,8 +103,8 @@ namespace System.Buffers.Text
int hour;
{
- uint digit1 = text[11] - 48u; // '0'
- uint digit2 = text[12] - 48u; // '0'
+ uint digit1 = source[11] - 48u; // '0'
+ uint digit2 = source[12] - 48u; // '0'
if (digit1 > 9 || digit2 > 9)
{
@@ -117,7 +117,7 @@ namespace System.Buffers.Text
hour = (int)(digit1 * 10 + digit2);
}
- if (text[13] != Utf8Constants.Colon)
+ if (source[13] != Utf8Constants.Colon)
{
value = default;
bytesConsumed = 0;
@@ -127,8 +127,8 @@ namespace System.Buffers.Text
int minute;
{
- uint digit1 = text[14] - 48u; // '0'
- uint digit2 = text[15] - 48u; // '0'
+ uint digit1 = source[14] - 48u; // '0'
+ uint digit2 = source[15] - 48u; // '0'
if (digit1 > 9 || digit2 > 9)
{
@@ -141,7 +141,7 @@ namespace System.Buffers.Text
minute = (int)(digit1 * 10 + digit2);
}
- if (text[16] != Utf8Constants.Colon)
+ if (source[16] != Utf8Constants.Colon)
{
value = default;
bytesConsumed = 0;
@@ -151,8 +151,8 @@ namespace System.Buffers.Text
int second;
{
- uint digit1 = text[17] - 48u; // '0'
- uint digit2 = text[18] - 48u; // '0'
+ uint digit1 = source[17] - 48u; // '0'
+ uint digit2 = source[18] - 48u; // '0'
if (digit1 > 9 || digit2 > 9)
{
@@ -165,7 +165,7 @@ namespace System.Buffers.Text
second = (int)(digit1 * 10 + digit2);
}
- if (text[19] != Utf8Constants.Period)
+ if (source[19] != Utf8Constants.Period)
{
value = default;
bytesConsumed = 0;
@@ -175,13 +175,13 @@ namespace System.Buffers.Text
int fraction;
{
- uint digit1 = text[20] - 48u; // '0'
- uint digit2 = text[21] - 48u; // '0'
- uint digit3 = text[22] - 48u; // '0'
- uint digit4 = text[23] - 48u; // '0'
- uint digit5 = text[24] - 48u; // '0'
- uint digit6 = text[25] - 48u; // '0'
- uint digit7 = text[26] - 48u; // '0'
+ uint digit1 = source[20] - 48u; // '0'
+ uint digit2 = source[21] - 48u; // '0'
+ uint digit3 = source[22] - 48u; // '0'
+ uint digit4 = source[23] - 48u; // '0'
+ uint digit5 = source[24] - 48u; // '0'
+ uint digit6 = source[25] - 48u; // '0'
+ uint digit7 = source[26] - 48u; // '0'
if (digit1 > 9 || digit2 > 9 || digit3 > 9 || digit4 > 9 || digit5 > 9 || digit6 > 9 || digit7 > 9)
{
@@ -194,7 +194,7 @@ namespace System.Buffers.Text
fraction = (int)(digit1 * 1000000 + digit2 * 100000 + digit3 * 10000 + digit4 * 1000 + digit5 * 100 + digit6 * 10 + digit7);
}
- byte offsetChar = (text.Length <= 27) ? default : text[27];
+ byte offsetChar = (source.Length <= 27) ? default : source[27];
if (offsetChar != 'Z' && offsetChar != Utf8Constants.Plus && offsetChar != Utf8Constants.Minus)
{
if (!TryCreateDateTimeOffsetInterpretingDataAsLocalTime(year: year, month: month, day: day, hour: hour, minute: minute, second: second, fraction: fraction, out value))
@@ -226,7 +226,7 @@ namespace System.Buffers.Text
}
Debug.Assert(offsetChar == Utf8Constants.Plus || offsetChar == Utf8Constants.Minus);
- if (text.Length < 33)
+ if (source.Length < 33)
{
value = default;
bytesConsumed = 0;
@@ -236,8 +236,8 @@ namespace System.Buffers.Text
int offsetHours;
{
- uint digit1 = text[28] - 48u; // '0'
- uint digit2 = text[29] - 48u; // '0'
+ uint digit1 = source[28] - 48u; // '0'
+ uint digit2 = source[29] - 48u; // '0'
if (digit1 > 9 || digit2 > 9)
{
@@ -250,7 +250,7 @@ namespace System.Buffers.Text
offsetHours = (int)(digit1 * 10 + digit2);
}
- if (text[30] != Utf8Constants.Colon)
+ if (source[30] != Utf8Constants.Colon)
{
value = default;
bytesConsumed = 0;
@@ -260,8 +260,8 @@ namespace System.Buffers.Text
int offsetMinutes;
{
- uint digit1 = text[31] - 48u; // '0'
- uint digit2 = text[32] - 48u; // '0'
+ uint digit1 = source[31] - 48u; // '0'
+ uint digit2 = source[32] - 48u; // '0'
if (digit1 > 9 || digit2 > 9)
{
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.R.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.R.cs
index af70ca62e5..316bee01b4 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.R.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.R.cs
@@ -13,9 +13,9 @@ namespace System.Buffers.Text
// -----------------------------
// Tue, 03 Jan 2017 08:08:05 GMT
//
- private static bool TryParseDateTimeOffsetR(ReadOnlySpan<byte> text, uint caseFlipXorMask, out DateTimeOffset dateTimeOffset, out int bytesConsumed)
+ private static bool TryParseDateTimeOffsetR(ReadOnlySpan<byte> source, uint caseFlipXorMask, out DateTimeOffset dateTimeOffset, out int bytesConsumed)
{
- if (text.Length < 29)
+ if (source.Length < 29)
{
bytesConsumed = 0;
dateTimeOffset = default;
@@ -24,10 +24,10 @@ namespace System.Buffers.Text
DayOfWeek dayOfWeek;
{
- uint dow0 = text[0] ^ caseFlipXorMask;
- uint dow1 = text[1];
- uint dow2 = text[2];
- uint comma = text[3];
+ uint dow0 = source[0] ^ caseFlipXorMask;
+ uint dow1 = source[1];
+ uint dow2 = source[2];
+ uint comma = source[3];
uint dowString = (dow0 << 24) | (dow1 << 16) | (dow2 << 8) | comma;
switch (dowString)
{
@@ -45,7 +45,7 @@ namespace System.Buffers.Text
}
}
- if (text[4] != Utf8Constants.Space)
+ if (source[4] != Utf8Constants.Space)
{
bytesConsumed = 0;
dateTimeOffset = default;
@@ -54,8 +54,8 @@ namespace System.Buffers.Text
int day;
{
- uint digit1 = text[5] - 48u; // '0'
- uint digit2 = text[6] - 48u; // '0'
+ uint digit1 = source[5] - 48u; // '0'
+ uint digit2 = source[6] - 48u; // '0'
if (digit1 > 9 || digit2 > 9)
{
@@ -67,7 +67,7 @@ namespace System.Buffers.Text
day = (int)(digit1 * 10 + digit2);
}
- if (text[7] != Utf8Constants.Space)
+ if (source[7] != Utf8Constants.Space)
{
bytesConsumed = 0;
dateTimeOffset = default;
@@ -76,10 +76,10 @@ namespace System.Buffers.Text
int month;
{
- uint mon0 = text[8] ^ caseFlipXorMask;
- uint mon1 = text[9];
- uint mon2 = text[10];
- uint space = text[11];
+ uint mon0 = source[8] ^ caseFlipXorMask;
+ uint mon1 = source[9];
+ uint mon2 = source[10];
+ uint space = source[11];
uint monthString = (mon0 << 24) | (mon1 << 16) | (mon2 << 8) | space;
switch (monthString)
{
@@ -104,10 +104,10 @@ namespace System.Buffers.Text
int year;
{
- uint digit1 = text[12] - 48u; // '0'
- uint digit2 = text[13] - 48u; // '0'
- uint digit3 = text[14] - 48u; // '0'
- uint digit4 = text[15] - 48u; // '0'
+ uint digit1 = source[12] - 48u; // '0'
+ uint digit2 = source[13] - 48u; // '0'
+ uint digit3 = source[14] - 48u; // '0'
+ uint digit4 = source[15] - 48u; // '0'
if (digit1 > 9 || digit2 > 9 || digit3 > 9 || digit4 > 9)
{
@@ -119,7 +119,7 @@ namespace System.Buffers.Text
year = (int)(digit1 * 1000 + digit2 * 100 + digit3 * 10 + digit4);
}
- if (text[16] != Utf8Constants.Space)
+ if (source[16] != Utf8Constants.Space)
{
bytesConsumed = 0;
dateTimeOffset = default;
@@ -128,8 +128,8 @@ namespace System.Buffers.Text
int hour;
{
- uint digit1 = text[17] - 48u; // '0'
- uint digit2 = text[18] - 48u; // '0'
+ uint digit1 = source[17] - 48u; // '0'
+ uint digit2 = source[18] - 48u; // '0'
if (digit1 > 9 || digit2 > 9)
{
@@ -141,7 +141,7 @@ namespace System.Buffers.Text
hour = (int)(digit1 * 10 + digit2);
}
- if (text[19] != Utf8Constants.Colon)
+ if (source[19] != Utf8Constants.Colon)
{
bytesConsumed = 0;
dateTimeOffset = default;
@@ -150,8 +150,8 @@ namespace System.Buffers.Text
int minute;
{
- uint digit1 = text[20] - 48u; // '0'
- uint digit2 = text[21] - 48u; // '0'
+ uint digit1 = source[20] - 48u; // '0'
+ uint digit2 = source[21] - 48u; // '0'
if (digit1 > 9 || digit2 > 9)
{
@@ -163,7 +163,7 @@ namespace System.Buffers.Text
minute = (int)(digit1 * 10 + digit2);
}
- if (text[22] != Utf8Constants.Colon)
+ if (source[22] != Utf8Constants.Colon)
{
bytesConsumed = 0;
dateTimeOffset = default;
@@ -172,8 +172,8 @@ namespace System.Buffers.Text
int second;
{
- uint digit1 = text[23] - 48u; // '0'
- uint digit2 = text[24] - 48u; // '0'
+ uint digit1 = source[23] - 48u; // '0'
+ uint digit2 = source[24] - 48u; // '0'
if (digit1 > 9 || digit2 > 9)
{
@@ -186,10 +186,10 @@ namespace System.Buffers.Text
}
{
- uint space = text[25];
- uint g = text[26] ^ caseFlipXorMask;
- uint m = text[27] ^ caseFlipXorMask;
- uint t = text[28] ^ caseFlipXorMask;
+ uint space = source[25];
+ uint g = source[26] ^ caseFlipXorMask;
+ uint m = source[27] ^ caseFlipXorMask;
+ uint t = source[28] ^ caseFlipXorMask;
uint gmtString = (space << 24) | (g << 16) | (m << 8) | t;
if (gmtString != 0x20474d54 /* ' GMT' */)
{
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.cs
index d69ff7ce13..f103492461 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.cs
@@ -11,7 +11,7 @@ namespace System.Buffers.Text
/// <summary>
/// Parses a DateTime at the start of a Utf8 string.
/// </summary>
- /// <param name="text">The Utf8 string to parse</param>
+ /// <param name="source">The Utf8 string to parse</param>
/// <param name="value">Receives the parsed value</param>
/// <param name="bytesConsumed">On a successful parse, receives the length in bytes of the substring that was parsed </param>
/// <param name="standardFormat">Expected format of the Utf8 string</param>
@@ -30,13 +30,13 @@ namespace System.Buffers.Text
/// <exceptions>
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
- public static bool TryParse(ReadOnlySpan<byte> text, out DateTime value, out int bytesConsumed, char standardFormat = default)
+ public static bool TryParse(ReadOnlySpan<byte> source, out DateTime value, out int bytesConsumed, char standardFormat = default)
{
switch (standardFormat)
{
case 'R':
{
- if (!TryParseDateTimeOffsetR(text, NoFlipCase, out DateTimeOffset dateTimeOffset, out bytesConsumed))
+ if (!TryParseDateTimeOffsetR(source, NoFlipCase, out DateTimeOffset dateTimeOffset, out bytesConsumed))
{
value = default;
return false;
@@ -47,7 +47,7 @@ namespace System.Buffers.Text
case 'l':
{
- if (!TryParseDateTimeOffsetR(text, FlipCase, out DateTimeOffset dateTimeOffset, out bytesConsumed))
+ if (!TryParseDateTimeOffsetR(source, FlipCase, out DateTimeOffset dateTimeOffset, out bytesConsumed))
{
value = default;
return false;
@@ -65,7 +65,7 @@ namespace System.Buffers.Text
// 2017-06-12T05:30:45.7680000+00:00 - Local
// 2017-06-12T05:30:45.7680000Z - Utc
- if (!TryParseDateTimeOffsetO(text, out DateTimeOffset dateTimeOffset, out bytesConsumed, out DateTimeKind kind))
+ if (!TryParseDateTimeOffsetO(source, out DateTimeOffset dateTimeOffset, out bytesConsumed, out DateTimeKind kind))
{
value = default;
bytesConsumed = 0;
@@ -89,9 +89,9 @@ namespace System.Buffers.Text
return true;
}
- case (default):
+ case default(char):
case 'G':
- return TryParseDateTimeG(text, out value, out _, out bytesConsumed);
+ return TryParseDateTimeG(source, out value, out _, out bytesConsumed);
default:
return ThrowHelper.TryParseThrowFormatException(out value, out bytesConsumed);
@@ -101,7 +101,7 @@ namespace System.Buffers.Text
/// <summary>
/// Parses a DateTimeOffset at the start of a Utf8 string.
/// </summary>
- /// <param name="text">The Utf8 string to parse</param>
+ /// <param name="source">The Utf8 string to parse</param>
/// <param name="value">Receives the parsed value</param>
/// <param name="bytesConsumed">On a successful parse, receives the length in bytes of the substring that was parsed </param>
/// <param name="standardFormat">Expected format of the Utf8 string</param>
@@ -119,24 +119,24 @@ namespace System.Buffers.Text
/// <exceptions>
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
- public static bool TryParse(ReadOnlySpan<byte> text, out DateTimeOffset value, out int bytesConsumed, char standardFormat = default)
+ public static bool TryParse(ReadOnlySpan<byte> source, out DateTimeOffset value, out int bytesConsumed, char standardFormat = default)
{
switch (standardFormat)
{
case 'R':
- return TryParseDateTimeOffsetR(text, NoFlipCase, out value, out bytesConsumed);
+ return TryParseDateTimeOffsetR(source, NoFlipCase, out value, out bytesConsumed);
case 'l':
- return TryParseDateTimeOffsetR(text, FlipCase, out value, out bytesConsumed);
+ return TryParseDateTimeOffsetR(source, FlipCase, out value, out bytesConsumed);
case 'O':
- return TryParseDateTimeOffsetO(text, out value, out bytesConsumed, out _);
+ return TryParseDateTimeOffsetO(source, out value, out bytesConsumed, out _);
- case (default):
- return TryParseDateTimeOffsetDefault(text, out value, out bytesConsumed);
+ case default(char):
+ return TryParseDateTimeOffsetDefault(source, out value, out bytesConsumed);
case 'G':
- return TryParseDateTimeG(text, out DateTime _, out value, out bytesConsumed);
+ return TryParseDateTimeG(source, out DateTime _, out value, out bytesConsumed);
default:
return ThrowHelper.TryParseThrowFormatException(out value, out bytesConsumed);
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Decimal.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Decimal.cs
index 59f74bb847..c0f1e0c040 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Decimal.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Decimal.cs
@@ -9,7 +9,7 @@ namespace System.Buffers.Text
/// <summary>
/// Parses a Decimal at the start of a Utf8 string.
/// </summary>
- /// <param name="text">The Utf8 string to parse</param>
+ /// <param name="source">The Utf8 string to parse</param>
/// <param name="value">Receives the parsed value</param>
/// <param name="bytesConsumed">On a successful parse, receives the length in bytes of the substring that was parsed </param>
/// <param name="standardFormat">Expected format of the Utf8 string</param>
@@ -26,12 +26,12 @@ namespace System.Buffers.Text
/// <exceptions>
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
- public static bool TryParse(ReadOnlySpan<byte> text, out decimal value, out int bytesConsumed, char standardFormat = default)
+ public static bool TryParse(ReadOnlySpan<byte> source, out decimal value, out int bytesConsumed, char standardFormat = default)
{
ParseNumberOptions options;
switch (standardFormat)
{
- case (default):
+ case default(char):
case 'G':
case 'g':
case 'E':
@@ -49,7 +49,7 @@ namespace System.Buffers.Text
}
NumberBuffer number = default;
- if (!TryParseNumber(text, ref number, out bytesConsumed, options, out bool textUsedExponentNotation))
+ if (!TryParseNumber(source, ref number, out bytesConsumed, options, out bool textUsedExponentNotation))
{
value = default;
return false;
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Float.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Float.cs
index 0b0e25e22d..b00ae277ee 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Float.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Float.cs
@@ -9,7 +9,7 @@ namespace System.Buffers.Text
/// <summary>
/// Parses a Single at the start of a Utf8 string.
/// </summary>
- /// <param name="text">The Utf8 string to parse</param>
+ /// <param name="source">The Utf8 string to parse</param>
/// <param name="value">Receives the parsed value</param>
/// <param name="bytesConsumed">On a successful parse, receives the length in bytes of the substring that was parsed </param>
/// <param name="standardFormat">Expected format of the Utf8 string</param>
@@ -26,9 +26,9 @@ namespace System.Buffers.Text
/// <exceptions>
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
- public static bool TryParse(ReadOnlySpan<byte> text, out float value, out int bytesConsumed, char standardFormat = default)
+ public static bool TryParse(ReadOnlySpan<byte> source, out float value, out int bytesConsumed, char standardFormat = default)
{
- if (TryParseNormalAsFloatingPoint(text, out double d, out bytesConsumed, standardFormat))
+ if (TryParseNormalAsFloatingPoint(source, out double d, out bytesConsumed, standardFormat))
{
value = (float)d;
if (float.IsInfinity(value))
@@ -40,13 +40,13 @@ namespace System.Buffers.Text
return true;
}
- return TryParseAsSpecialFloatingPoint<float>(text, float.PositiveInfinity, float.NegativeInfinity, float.NaN, out value, out bytesConsumed);
+ return TryParseAsSpecialFloatingPoint<float>(source, float.PositiveInfinity, float.NegativeInfinity, float.NaN, out value, out bytesConsumed);
}
/// <summary>
/// Parses a Double at the start of a Utf8 string.
/// </summary>
- /// <param name="text">The Utf8 string to parse</param>
+ /// <param name="source">The Utf8 string to parse</param>
/// <param name="value">Receives the parsed value</param>
/// <param name="bytesConsumed">On a successful parse, receives the length in bytes of the substring that was parsed </param>
/// <param name="standardFormat">Expected format of the Utf8 string</param>
@@ -63,23 +63,23 @@ namespace System.Buffers.Text
/// <exceptions>
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
- public static bool TryParse(ReadOnlySpan<byte> text, out double value, out int bytesConsumed, char standardFormat = default)
+ public static bool TryParse(ReadOnlySpan<byte> source, out double value, out int bytesConsumed, char standardFormat = default)
{
- if (TryParseNormalAsFloatingPoint(text, out value, out bytesConsumed, standardFormat))
+ if (TryParseNormalAsFloatingPoint(source, out value, out bytesConsumed, standardFormat))
return true;
- return TryParseAsSpecialFloatingPoint<double>(text, double.PositiveInfinity, double.NegativeInfinity, double.NaN, out value, out bytesConsumed);
+ return TryParseAsSpecialFloatingPoint<double>(source, double.PositiveInfinity, double.NegativeInfinity, double.NaN, out value, out bytesConsumed);
}
//
// Attempt to parse the regular floating points (the ones without names like "Infinity" and "NaN")
//
- private static bool TryParseNormalAsFloatingPoint(ReadOnlySpan<byte> text, out double value, out int bytesConsumed, char standardFormat)
+ private static bool TryParseNormalAsFloatingPoint(ReadOnlySpan<byte> source, out double value, out int bytesConsumed, char standardFormat)
{
ParseNumberOptions options;
switch (standardFormat)
{
- case (default):
+ case default(char):
case 'G':
case 'g':
case 'E':
@@ -97,7 +97,7 @@ namespace System.Buffers.Text
}
NumberBuffer number = default;
- if (!TryParseNumber(text, ref number, out bytesConsumed, options, out bool textUsedExponentNotation))
+ if (!TryParseNumber(source, ref number, out bytesConsumed, options, out bool textUsedExponentNotation))
{
value = default;
return false;
@@ -128,29 +128,29 @@ namespace System.Buffers.Text
//
// Assuming the text doesn't look like a normal floating point, we attempt to parse it as one the special floating point values.
//
- private static bool TryParseAsSpecialFloatingPoint<T>(ReadOnlySpan<byte> text, T positiveInfinity, T negativeInfinity, T nan, out T value, out int bytesConsumed)
+ private static bool TryParseAsSpecialFloatingPoint<T>(ReadOnlySpan<byte> source, T positiveInfinity, T negativeInfinity, T nan, out T value, out int bytesConsumed)
{
- if (text.Length >= 8 &&
- text[0] == 'I' && text[1] == 'n' && text[2] == 'f' && text[3] == 'i' &&
- text[4] == 'n' && text[5] == 'i' && text[6] == 't' && text[7] == 'y')
+ if (source.Length >= 8 &&
+ source[0] == 'I' && source[1] == 'n' && source[2] == 'f' && source[3] == 'i' &&
+ source[4] == 'n' && source[5] == 'i' && source[6] == 't' && source[7] == 'y')
{
value = positiveInfinity;
bytesConsumed = 8;
return true;
}
- if (text.Length >= 9 &&
- text[0] == Utf8Constants.Minus &&
- text[1] == 'I' && text[2] == 'n' && text[3] == 'f' && text[4] == 'i' &&
- text[5] == 'n' && text[6] == 'i' && text[7] == 't' && text[8] == 'y')
+ if (source.Length >= 9 &&
+ source[0] == Utf8Constants.Minus &&
+ source[1] == 'I' && source[2] == 'n' && source[3] == 'f' && source[4] == 'i' &&
+ source[5] == 'n' && source[6] == 'i' && source[7] == 't' && source[8] == 'y')
{
value = negativeInfinity;
bytesConsumed = 9;
return true;
}
- if (text.Length >= 3 &&
- text[0] == 'N' && text[1] == 'a' && text[2] == 'N')
+ if (source.Length >= 3 &&
+ source[0] == 'N' && source[1] == 'a' && source[2] == 'N')
{
value = nan;
bytesConsumed = 3;
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Guid.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Guid.cs
index baefe25905..17dec828bc 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Guid.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Guid.cs
@@ -9,7 +9,7 @@ namespace System.Buffers.Text
/// <summary>
/// Parses a Guid at the start of a Utf8 string.
/// </summary>
- /// <param name="text">The Utf8 string to parse</param>
+ /// <param name="source">The Utf8 string to parse</param>
/// <param name="value">Receives the parsed value</param>
/// <param name="bytesConsumed">On a successful parse, receives the length in bytes of the substring that was parsed </param>
/// <param name="standardFormat">Expected format of the Utf8 string</param>
@@ -27,19 +27,19 @@ namespace System.Buffers.Text
/// <exceptions>
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
- public static bool TryParse(ReadOnlySpan<byte> text, out Guid value, out int bytesConsumed, char standardFormat = default)
+ public static bool TryParse(ReadOnlySpan<byte> source, out Guid value, out int bytesConsumed, char standardFormat = default)
{
switch (standardFormat)
{
- case (default):
+ case default(char):
case 'D':
- return TryParseGuidCore(text, false, ' ', ' ', out value, out bytesConsumed);
+ return TryParseGuidCore(source, false, ' ', ' ', out value, out bytesConsumed);
case 'B':
- return TryParseGuidCore(text, true, '{', '}', out value, out bytesConsumed);
+ return TryParseGuidCore(source, true, '{', '}', out value, out bytesConsumed);
case 'P':
- return TryParseGuidCore(text, true, '(', ')', out value, out bytesConsumed);
+ return TryParseGuidCore(source, true, '(', ')', out value, out bytesConsumed);
case 'N':
- return TryParseGuidN(text, out value, out bytesConsumed);
+ return TryParseGuidN(source, out value, out bytesConsumed);
default:
return ThrowHelper.TryParseThrowFormatException(out value, out bytesConsumed);
}
@@ -97,11 +97,11 @@ namespace System.Buffers.Text
}
// {8-4-4-4-12}, where number is the number of hex digits, and {/} are ends.
- private static bool TryParseGuidCore(ReadOnlySpan<byte> text, bool ends, char begin, char end, out Guid value, out int bytesConsumed)
+ private static bool TryParseGuidCore(ReadOnlySpan<byte> source, bool ends, char begin, char end, out Guid value, out int bytesConsumed)
{
int expectedCodingUnits = 36 + (ends ? 2 : 0); // 32 hex digits + 4 delimiters + 2 optional ends
- if (text.Length < expectedCodingUnits)
+ if (source.Length < expectedCodingUnits)
{
value = default;
bytesConsumed = 0;
@@ -110,17 +110,17 @@ namespace System.Buffers.Text
if (ends)
{
- if (text[0] != begin)
+ if (source[0] != begin)
{
value = default;
bytesConsumed = 0;
return false;
}
- text = text.Slice(1); // skip begining
+ source = source.Slice(1); // skip begining
}
- if (!TryParseUInt32X(text, out uint i1, out int justConsumed))
+ if (!TryParseUInt32X(source, out uint i1, out int justConsumed))
{
value = default;
bytesConsumed = 0;
@@ -134,16 +134,16 @@ namespace System.Buffers.Text
return false; // 8 digits
}
- if (text[justConsumed] != '-')
+ if (source[justConsumed] != '-')
{
value = default;
bytesConsumed = 0;
return false;
}
- text = text.Slice(9); // justConsumed + 1 for delimiter
+ source = source.Slice(9); // justConsumed + 1 for delimiter
- if (!TryParseUInt16X(text, out ushort i2, out justConsumed))
+ if (!TryParseUInt16X(source, out ushort i2, out justConsumed))
{
value = default;
bytesConsumed = 0;
@@ -157,16 +157,16 @@ namespace System.Buffers.Text
return false; // 4 digits
}
- if (text[justConsumed] != '-')
+ if (source[justConsumed] != '-')
{
value = default;
bytesConsumed = 0;
return false;
}
- text = text.Slice(5); // justConsumed + 1 for delimiter
+ source = source.Slice(5); // justConsumed + 1 for delimiter
- if (!TryParseUInt16X(text, out ushort i3, out justConsumed))
+ if (!TryParseUInt16X(source, out ushort i3, out justConsumed))
{
value = default;
bytesConsumed = 0;
@@ -180,16 +180,16 @@ namespace System.Buffers.Text
return false; // 4 digits
}
- if (text[justConsumed] != '-')
+ if (source[justConsumed] != '-')
{
value = default;
bytesConsumed = 0;
return false;
}
- text = text.Slice(5); // justConsumed + 1 for delimiter
+ source = source.Slice(5); // justConsumed + 1 for delimiter
- if (!TryParseUInt16X(text, out ushort i4, out justConsumed))
+ if (!TryParseUInt16X(source, out ushort i4, out justConsumed))
{
value = default;
bytesConsumed = 0;
@@ -203,16 +203,16 @@ namespace System.Buffers.Text
return false; // 4 digits
}
- if (text[justConsumed] != '-')
+ if (source[justConsumed] != '-')
{
value = default;
bytesConsumed = 0;
return false;
}
- text = text.Slice(5);// justConsumed + 1 for delimiter
+ source = source.Slice(5);// justConsumed + 1 for delimiter
- if (!TryParseUInt64X(text, out ulong i5, out justConsumed))
+ if (!TryParseUInt64X(source, out ulong i5, out justConsumed))
{
value = default;
bytesConsumed = 0;
@@ -226,7 +226,7 @@ namespace System.Buffers.Text
return false; // 12 digits
}
- if (ends && text[justConsumed] != end)
+ if (ends && source[justConsumed] != end)
{
value = default;
bytesConsumed = 0;
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Signed.D.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Signed.D.cs
index b5f7649181..bf1871a1c9 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Signed.D.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Signed.D.cs
@@ -6,28 +6,28 @@ namespace System.Buffers.Text
{
public static partial class Utf8Parser
{
- private static bool TryParseSByteD(ReadOnlySpan<byte> text, out sbyte value, out int bytesConsumed)
+ private static bool TryParseSByteD(ReadOnlySpan<byte> source, out sbyte value, out int bytesConsumed)
{
- if (text.Length < 1)
+ if (source.Length < 1)
goto FalseExit;
int sign = 1;
int index = 0;
- int num = text[index];
+ int num = source[index];
if (num == '-')
{
sign = -1;
index++;
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto FalseExit;
- num = text[index];
+ num = source[index];
}
else if (num == '+')
{
index++;
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto FalseExit;
- num = text[index];
+ num = source[index];
}
int answer = 0;
@@ -39,9 +39,9 @@ namespace System.Buffers.Text
do
{
index++;
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
} while (num == '0');
if (!ParserHelpers.IsDigit(num))
goto Done;
@@ -50,18 +50,18 @@ namespace System.Buffers.Text
answer = num - '0';
index++;
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
answer = 10 * answer + num - '0';
// Potential overflow
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
@@ -71,9 +71,9 @@ namespace System.Buffers.Text
if ((uint)answer > (uint)sbyte.MaxValue + (-1 * sign + 1) / 2)
goto FalseExit; // Overflow
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- if (!ParserHelpers.IsDigit(text[index]))
+ if (!ParserHelpers.IsDigit(source[index]))
goto Done;
// Guaranteed overflow
@@ -91,28 +91,28 @@ namespace System.Buffers.Text
return true;
}
- private static bool TryParseInt16D(ReadOnlySpan<byte> text, out short value, out int bytesConsumed)
+ private static bool TryParseInt16D(ReadOnlySpan<byte> source, out short value, out int bytesConsumed)
{
- if (text.Length < 1)
+ if (source.Length < 1)
goto FalseExit;
int sign = 1;
int index = 0;
- int num = text[index];
+ int num = source[index];
if (num == '-')
{
sign = -1;
index++;
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto FalseExit;
- num = text[index];
+ num = source[index];
}
else if (num == '+')
{
index++;
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto FalseExit;
- num = text[index];
+ num = source[index];
}
int answer = 0;
@@ -124,9 +124,9 @@ namespace System.Buffers.Text
do
{
index++;
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
} while (num == '0');
if (!ParserHelpers.IsDigit(num))
goto Done;
@@ -135,34 +135,34 @@ namespace System.Buffers.Text
answer = num - '0';
index++;
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
answer = 10 * answer + num - '0';
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
answer = 10 * answer + num - '0';
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
answer = 10 * answer + num - '0';
// Potential overflow
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
@@ -172,9 +172,9 @@ namespace System.Buffers.Text
if ((uint)answer > (uint)short.MaxValue + (-1 * sign + 1) / 2)
goto FalseExit; // Overflow
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- if (!ParserHelpers.IsDigit(text[index]))
+ if (!ParserHelpers.IsDigit(source[index]))
goto Done;
// Guaranteed overflow
@@ -192,28 +192,28 @@ namespace System.Buffers.Text
return true;
}
- private static bool TryParseInt32D(ReadOnlySpan<byte> text, out int value, out int bytesConsumed)
+ private static bool TryParseInt32D(ReadOnlySpan<byte> source, out int value, out int bytesConsumed)
{
- if (text.Length < 1)
+ if (source.Length < 1)
goto FalseExit;
int sign = 1;
int index = 0;
- int num = text[index];
+ int num = source[index];
if (num == '-')
{
sign = -1;
index++;
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto FalseExit;
- num = text[index];
+ num = source[index];
}
else if (num == '+')
{
index++;
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto FalseExit;
- num = text[index];
+ num = source[index];
}
int answer = 0;
@@ -225,9 +225,9 @@ namespace System.Buffers.Text
do
{
index++;
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
} while (num == '0');
if (!ParserHelpers.IsDigit(num))
goto Done;
@@ -236,74 +236,74 @@ namespace System.Buffers.Text
answer = num - '0';
index++;
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
answer = 10 * answer + num - '0';
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
answer = 10 * answer + num - '0';
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
answer = 10 * answer + num - '0';
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
answer = 10 * answer + num - '0';
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
answer = 10 * answer + num - '0';
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
answer = 10 * answer + num - '0';
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
answer = 10 * answer + num - '0';
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
answer = 10 * answer + num - '0';
// Potential overflow
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
@@ -315,9 +315,9 @@ namespace System.Buffers.Text
if ((uint)answer > (uint)int.MaxValue + (-1 * sign + 1) / 2)
goto FalseExit; // Overflow
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- if (!ParserHelpers.IsDigit(text[index]))
+ if (!ParserHelpers.IsDigit(source[index]))
goto Done;
// Guaranteed overflow
@@ -335,9 +335,9 @@ namespace System.Buffers.Text
return true;
}
- private static bool TryParseInt64D(ReadOnlySpan<byte> text, out long value, out int bytesConsumed)
+ private static bool TryParseInt64D(ReadOnlySpan<byte> source, out long value, out int bytesConsumed)
{
- if (text.Length < 1)
+ if (source.Length < 1)
{
bytesConsumed = 0;
value = default;
@@ -346,23 +346,23 @@ namespace System.Buffers.Text
int indexOfFirstDigit = 0;
int sign = 1;
- if (text[0] == '-')
+ if (source[0] == '-')
{
indexOfFirstDigit = 1;
sign = -1;
- if (text.Length <= indexOfFirstDigit)
+ if (source.Length <= indexOfFirstDigit)
{
bytesConsumed = 0;
value = default;
return false;
}
}
- else if (text[0] == '+')
+ else if (source[0] == '+')
{
indexOfFirstDigit = 1;
- if (text.Length <= indexOfFirstDigit)
+ if (source.Length <= indexOfFirstDigit)
{
bytesConsumed = 0;
value = default;
@@ -373,7 +373,7 @@ namespace System.Buffers.Text
int overflowLength = ParserHelpers.Int64OverflowLength + indexOfFirstDigit;
// Parse the first digit separately. If invalid here, we need to return false.
- long firstDigit = text[indexOfFirstDigit] - 48; // '0'
+ long firstDigit = source[indexOfFirstDigit] - 48; // '0'
if (firstDigit < 0 || firstDigit > 9)
{
bytesConsumed = 0;
@@ -382,12 +382,12 @@ namespace System.Buffers.Text
}
ulong parsedValue = (ulong)firstDigit;
- if (text.Length < overflowLength)
+ if (source.Length < overflowLength)
{
// Length is less than Parsers.Int64OverflowLength; overflow is not possible
- for (int index = indexOfFirstDigit + 1; index < text.Length; index++)
+ for (int index = indexOfFirstDigit + 1; index < source.Length; index++)
{
- long nextDigit = text[index] - 48; // '0'
+ long nextDigit = source[index] - 48; // '0'
if (nextDigit < 0 || nextDigit > 9)
{
bytesConsumed = index;
@@ -403,7 +403,7 @@ namespace System.Buffers.Text
// digits. There may be no overflow after Parsers.Int64OverflowLength if there are leading zeroes.
for (int index = indexOfFirstDigit + 1; index < overflowLength - 1; index++)
{
- long nextDigit = text[index] - 48; // '0'
+ long nextDigit = source[index] - 48; // '0'
if (nextDigit < 0 || nextDigit > 9)
{
bytesConsumed = index;
@@ -412,9 +412,9 @@ namespace System.Buffers.Text
}
parsedValue = parsedValue * 10 + (ulong)nextDigit;
}
- for (int index = overflowLength - 1; index < text.Length; index++)
+ for (int index = overflowLength - 1; index < source.Length; index++)
{
- long nextDigit = text[index] - 48; // '0'
+ long nextDigit = source[index] - 48; // '0'
if (nextDigit < 0 || nextDigit > 9)
{
bytesConsumed = index;
@@ -435,7 +435,7 @@ namespace System.Buffers.Text
}
}
- bytesConsumed = text.Length;
+ bytesConsumed = source.Length;
value = ((long)parsedValue) * sign;
return true;
}
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Signed.N.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Signed.N.cs
index 66aa994f6d..e087041598 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Signed.N.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Signed.N.cs
@@ -6,24 +6,378 @@ namespace System.Buffers.Text
{
public static partial class Utf8Parser
{
- private static bool TryParseSByteN(ReadOnlySpan<byte> text, out sbyte value, out int bytesConsumed)
+ private static bool TryParseSByteN(ReadOnlySpan<byte> source, out sbyte value, out int bytesConsumed)
{
- throw NotImplemented.ActiveIssue("https://github.com/dotnet/corefx/issues/24986");
+ if (source.Length < 1)
+ goto FalseExit;
+
+ int sign = 1;
+ int index = 0;
+ int c = source[index];
+ if (c == '-')
+ {
+ sign = -1;
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto FalseExit;
+ c = source[index];
+ }
+ else if (c == '+')
+ {
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto FalseExit;
+ c = source[index];
+ }
+
+ int answer;
+
+ // Handle the first digit (or period) as a special case. This ensures some compatible edge-case behavior with the classic parse routines
+ // (at least one digit must precede any commas, and a string without any digits prior to the decimal point must have at least
+ // one digit after the decimal point.)
+ if (c == Utf8Constants.Period)
+ goto FractionalPartWithoutLeadingDigits;
+ if (!ParserHelpers.IsDigit(c))
+ goto FalseExit;
+ answer = c - '0';
+
+ for (; ; )
+ {
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto Done;
+
+ c = source[index];
+ if (c == Utf8Constants.Comma)
+ continue;
+
+ if (c == Utf8Constants.Period)
+ goto FractionalDigits;
+
+ if (!ParserHelpers.IsDigit(c))
+ goto Done;
+
+ answer = answer * 10 + c - '0';
+
+ // if sign < 0, (-1 * sign + 1) / 2 = 1
+ // else, (-1 * sign + 1) / 2 = 0
+ if (answer > sbyte.MaxValue + (-1 * sign + 1) / 2)
+ goto FalseExit; // Overflow
+ }
+
+FractionalPartWithoutLeadingDigits: // If we got here, we found a decimal point before we found any digits. This is legal as long as there's at least one zero after the decimal point.
+ answer = 0;
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto FalseExit;
+ if (source[index] != '0')
+ goto FalseExit;
+
+FractionalDigits: // "N" format allows a fractional portion despite being an integer format but only if the post-fraction digits are all 0.
+ do
+ {
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto Done;
+ c = source[index];
+ }
+ while (c == '0');
+
+ if (ParserHelpers.IsDigit(c))
+ goto FalseExit; // The fractional portion contained a non-zero digit. Treat this as an error, not an early termination.
+ goto Done;
+
+FalseExit:
+ bytesConsumed = default;
+ value = default;
+ return false;
+
+Done:
+ bytesConsumed = index;
+ value = (sbyte)(answer * sign);
+ return true;
}
- private static bool TryParseInt16N(ReadOnlySpan<byte> text, out short value, out int bytesConsumed)
+ private static bool TryParseInt16N(ReadOnlySpan<byte> source, out short value, out int bytesConsumed)
{
- throw NotImplemented.ActiveIssue("https://github.com/dotnet/corefx/issues/24986");
+ if (source.Length < 1)
+ goto FalseExit;
+
+ int sign = 1;
+ int index = 0;
+ int c = source[index];
+ if (c == '-')
+ {
+ sign = -1;
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto FalseExit;
+ c = source[index];
+ }
+ else if (c == '+')
+ {
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto FalseExit;
+ c = source[index];
+ }
+
+ int answer;
+
+ // Handle the first digit (or period) as a special case. This ensures some compatible edge-case behavior with the classic parse routines
+ // (at least one digit must precede any commas, and a string without any digits prior to the decimal point must have at least
+ // one digit after the decimal point.)
+ if (c == Utf8Constants.Period)
+ goto FractionalPartWithoutLeadingDigits;
+ if (!ParserHelpers.IsDigit(c))
+ goto FalseExit;
+ answer = c - '0';
+
+ for (; ; )
+ {
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto Done;
+
+ c = source[index];
+ if (c == Utf8Constants.Comma)
+ continue;
+
+ if (c == Utf8Constants.Period)
+ goto FractionalDigits;
+
+ if (!ParserHelpers.IsDigit(c))
+ goto Done;
+
+ answer = answer * 10 + c - '0';
+
+ // if sign < 0, (-1 * sign + 1) / 2 = 1
+ // else, (-1 * sign + 1) / 2 = 0
+ if (answer > short.MaxValue + (-1 * sign + 1) / 2)
+ goto FalseExit; // Overflow
+ }
+
+FractionalPartWithoutLeadingDigits: // If we got here, we found a decimal point before we found any digits. This is legal as long as there's at least one zero after the decimal point.
+ answer = 0;
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto FalseExit;
+ if (source[index] != '0')
+ goto FalseExit;
+
+FractionalDigits: // "N" format allows a fractional portion despite being an integer format but only if the post-fraction digits are all 0.
+ do
+ {
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto Done;
+ c = source[index];
+ }
+ while (c == '0');
+
+ if (ParserHelpers.IsDigit(c))
+ goto FalseExit; // The fractional portion contained a non-zero digit. Treat this as an error, not an early termination.
+ goto Done;
+
+FalseExit:
+ bytesConsumed = default;
+ value = default;
+ return false;
+
+Done:
+ bytesConsumed = index;
+ value = (short)(answer * sign);
+ return true;
}
- private static bool TryParseInt32N(ReadOnlySpan<byte> text, out int value, out int bytesConsumed)
+ private static bool TryParseInt32N(ReadOnlySpan<byte> source, out int value, out int bytesConsumed)
{
- throw NotImplemented.ActiveIssue("https://github.com/dotnet/corefx/issues/24986");
+ if (source.Length < 1)
+ goto FalseExit;
+
+ int sign = 1;
+ int index = 0;
+ int c = source[index];
+ if (c == '-')
+ {
+ sign = -1;
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto FalseExit;
+ c = source[index];
+ }
+ else if (c == '+')
+ {
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto FalseExit;
+ c = source[index];
+ }
+
+ int answer;
+
+ // Handle the first digit (or period) as a special case. This ensures some compatible edge-case behavior with the classic parse routines
+ // (at least one digit must precede any commas, and a string without any digits prior to the decimal point must have at least
+ // one digit after the decimal point.)
+ if (c == Utf8Constants.Period)
+ goto FractionalPartWithoutLeadingDigits;
+ if (!ParserHelpers.IsDigit(c))
+ goto FalseExit;
+ answer = c - '0';
+
+ for (; ; )
+ {
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto Done;
+
+ c = source[index];
+ if (c == Utf8Constants.Comma)
+ continue;
+
+ if (c == Utf8Constants.Period)
+ goto FractionalDigits;
+
+ if (!ParserHelpers.IsDigit(c))
+ goto Done;
+
+ if (((uint)answer) > int.MaxValue / 10)
+ goto FalseExit;
+
+ answer = answer * 10 + c - '0';
+
+ // if sign < 0, (-1 * sign + 1) / 2 = 1
+ // else, (-1 * sign + 1) / 2 = 0
+ if ((uint)answer > (uint)int.MaxValue + (-1 * sign + 1) / 2)
+ goto FalseExit; // Overflow
+ }
+
+FractionalPartWithoutLeadingDigits: // If we got here, we found a decimal point before we found any digits. This is legal as long as there's at least one zero after the decimal point.
+ answer = 0;
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto FalseExit;
+ if (source[index] != '0')
+ goto FalseExit;
+
+FractionalDigits: // "N" format allows a fractional portion despite being an integer format but only if the post-fraction digits are all 0.
+ do
+ {
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto Done;
+ c = source[index];
+ }
+ while (c == '0');
+
+ if (ParserHelpers.IsDigit(c))
+ goto FalseExit; // The fractional portion contained a non-zero digit. Treat this as an error, not an early termination.
+ goto Done;
+
+FalseExit:
+ bytesConsumed = default;
+ value = default;
+ return false;
+
+Done:
+ bytesConsumed = index;
+ value = answer * sign;
+ return true;
}
- private static bool TryParseInt64N(ReadOnlySpan<byte> text, out long value, out int bytesConsumed)
+ private static bool TryParseInt64N(ReadOnlySpan<byte> source, out long value, out int bytesConsumed)
{
- throw NotImplemented.ActiveIssue("https://github.com/dotnet/corefx/issues/24986");
+ if (source.Length < 1)
+ goto FalseExit;
+
+ int sign = 1;
+ int index = 0;
+ int c = source[index];
+ if (c == '-')
+ {
+ sign = -1;
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto FalseExit;
+ c = source[index];
+ }
+ else if (c == '+')
+ {
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto FalseExit;
+ c = source[index];
+ }
+
+ long answer;
+
+ // Handle the first digit (or period) as a special case. This ensures some compatible edge-case behavior with the classic parse routines
+ // (at least one digit must precede any commas, and a string without any digits prior to the decimal point must have at least
+ // one digit after the decimal point.)
+ if (c == Utf8Constants.Period)
+ goto FractionalPartWithoutLeadingDigits;
+ if (!ParserHelpers.IsDigit(c))
+ goto FalseExit;
+ answer = c - '0';
+
+ for (; ; )
+ {
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto Done;
+
+ c = source[index];
+ if (c == Utf8Constants.Comma)
+ continue;
+
+ if (c == Utf8Constants.Period)
+ goto FractionalDigits;
+
+ if (!ParserHelpers.IsDigit(c))
+ goto Done;
+
+ if (((ulong)answer) > long.MaxValue / 10)
+ goto FalseExit;
+
+ answer = answer * 10 + c - '0';
+
+ // if sign < 0, (-1 * sign + 1) / 2 = 1
+ // else, (-1 * sign + 1) / 2 = 0
+ if ((ulong)answer > (ulong)(long.MaxValue + (-1 * sign + 1) / 2))
+ goto FalseExit; // Overflow
+ }
+
+FractionalPartWithoutLeadingDigits: // If we got here, we found a decimal point before we found any digits. This is legal as long as there's at least one zero after the decimal point.
+ answer = 0;
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto FalseExit;
+ if (source[index] != '0')
+ goto FalseExit;
+
+FractionalDigits: // "N" format allows a fractional portion despite being an integer format but only if the post-fraction digits are all 0.
+ do
+ {
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto Done;
+ c = source[index];
+ }
+ while (c == '0');
+
+ if (ParserHelpers.IsDigit(c))
+ goto FalseExit; // The fractional portion contained a non-zero digit. Treat this as an error, not an early termination.
+ goto Done;
+
+FalseExit:
+ bytesConsumed = default;
+ value = default;
+ return false;
+
+Done:
+ bytesConsumed = index;
+ value = answer * sign;
+ return true;
}
}
}
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Signed.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Signed.cs
index e7f5009684..b387cd26f8 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Signed.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Signed.cs
@@ -18,7 +18,7 @@ namespace System.Buffers.Text
/// <summary>
/// Parses a SByte at the start of a Utf8 string.
/// </summary>
- /// <param name="text">The Utf8 string to parse</param>
+ /// <param name="source">The Utf8 string to parse</param>
/// <param name="value">Receives the parsed value</param>
/// <param name="bytesConsumed">On a successful parse, receives the length in bytes of the substring that was parsed </param>
/// <param name="standardFormat">Expected format of the Utf8 string</param>
@@ -37,25 +37,25 @@ namespace System.Buffers.Text
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
[CLSCompliant(false)]
- public static bool TryParse(ReadOnlySpan<byte> text, out sbyte value, out int bytesConsumed, char standardFormat = default)
+ public static bool TryParse(ReadOnlySpan<byte> source, out sbyte value, out int bytesConsumed, char standardFormat = default)
{
switch (standardFormat)
{
- case (default):
+ case default(char):
case 'g':
case 'G':
case 'd':
case 'D':
- return TryParseSByteD(text, out value, out bytesConsumed);
+ return TryParseSByteD(source, out value, out bytesConsumed);
case 'n':
case 'N':
- return TryParseSByteN(text, out value, out bytesConsumed);
+ return TryParseSByteN(source, out value, out bytesConsumed);
case 'x':
case 'X':
value = default;
- return TryParseByteX(text, out Unsafe.As<sbyte, byte>(ref value), out bytesConsumed);
+ return TryParseByteX(source, out Unsafe.As<sbyte, byte>(ref value), out bytesConsumed);
default:
return ThrowHelper.TryParseThrowFormatException(out value, out bytesConsumed);
@@ -65,7 +65,7 @@ namespace System.Buffers.Text
/// <summary>
/// Parses an Int16 at the start of a Utf8 string.
/// </summary>
- /// <param name="text">The Utf8 string to parse</param>
+ /// <param name="source">The Utf8 string to parse</param>
/// <param name="value">Receives the parsed value</param>
/// <param name="bytesConsumed">On a successful parse, receives the length in bytes of the substring that was parsed </param>
/// <param name="standardFormat">Expected format of the Utf8 string</param>
@@ -83,25 +83,25 @@ namespace System.Buffers.Text
/// <exceptions>
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
- public static bool TryParse(ReadOnlySpan<byte> text, out short value, out int bytesConsumed, char standardFormat = default)
+ public static bool TryParse(ReadOnlySpan<byte> source, out short value, out int bytesConsumed, char standardFormat = default)
{
switch (standardFormat)
{
- case (default):
+ case default(char):
case 'g':
case 'G':
case 'd':
case 'D':
- return TryParseInt16D(text, out value, out bytesConsumed);
+ return TryParseInt16D(source, out value, out bytesConsumed);
case 'n':
case 'N':
- return TryParseInt16N(text, out value, out bytesConsumed);
+ return TryParseInt16N(source, out value, out bytesConsumed);
case 'x':
case 'X':
value = default;
- return TryParseUInt16X(text, out Unsafe.As<short, ushort>(ref value), out bytesConsumed);
+ return TryParseUInt16X(source, out Unsafe.As<short, ushort>(ref value), out bytesConsumed);
default:
return ThrowHelper.TryParseThrowFormatException(out value, out bytesConsumed);
@@ -111,7 +111,7 @@ namespace System.Buffers.Text
/// <summary>
/// Parses an Int32 at the start of a Utf8 string.
/// </summary>
- /// <param name="text">The Utf8 string to parse</param>
+ /// <param name="source">The Utf8 string to parse</param>
/// <param name="value">Receives the parsed value</param>
/// <param name="bytesConsumed">On a successful parse, receives the length in bytes of the substring that was parsed </param>
/// <param name="standardFormat">Expected format of the Utf8 string</param>
@@ -129,25 +129,25 @@ namespace System.Buffers.Text
/// <exceptions>
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
- public static bool TryParse(ReadOnlySpan<byte> text, out int value, out int bytesConsumed, char standardFormat = default)
+ public static bool TryParse(ReadOnlySpan<byte> source, out int value, out int bytesConsumed, char standardFormat = default)
{
switch (standardFormat)
{
- case (default):
+ case default(char):
case 'g':
case 'G':
case 'd':
case 'D':
- return TryParseInt32D(text, out value, out bytesConsumed);
+ return TryParseInt32D(source, out value, out bytesConsumed);
case 'n':
case 'N':
- return TryParseInt32N(text, out value, out bytesConsumed);
+ return TryParseInt32N(source, out value, out bytesConsumed);
case 'x':
case 'X':
value = default;
- return TryParseUInt32X(text, out Unsafe.As<int, uint>(ref value), out bytesConsumed);
+ return TryParseUInt32X(source, out Unsafe.As<int, uint>(ref value), out bytesConsumed);
default:
return ThrowHelper.TryParseThrowFormatException(out value, out bytesConsumed);
@@ -157,7 +157,7 @@ namespace System.Buffers.Text
/// <summary>
/// Parses an Int64 at the start of a Utf8 string.
/// </summary>
- /// <param name="text">The Utf8 string to parse</param>
+ /// <param name="source">The Utf8 string to parse</param>
/// <param name="value">Receives the parsed value</param>
/// <param name="bytesConsumed">On a successful parse, receives the length in bytes of the substring that was parsed </param>
/// <param name="standardFormat">Expected format of the Utf8 string</param>
@@ -175,25 +175,25 @@ namespace System.Buffers.Text
/// <exceptions>
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
- public static bool TryParse(ReadOnlySpan<byte> text, out long value, out int bytesConsumed, char standardFormat = default)
+ public static bool TryParse(ReadOnlySpan<byte> source, out long value, out int bytesConsumed, char standardFormat = default)
{
switch (standardFormat)
{
- case (default):
+ case default(char):
case 'g':
case 'G':
case 'd':
case 'D':
- return TryParseInt64D(text, out value, out bytesConsumed);
+ return TryParseInt64D(source, out value, out bytesConsumed);
case 'n':
case 'N':
- return TryParseInt64N(text, out value, out bytesConsumed);
+ return TryParseInt64N(source, out value, out bytesConsumed);
case 'x':
case 'X':
value = default;
- return TryParseUInt64X(text, out Unsafe.As<long, ulong>(ref value), out bytesConsumed);
+ return TryParseUInt64X(source, out Unsafe.As<long, ulong>(ref value), out bytesConsumed);
default:
return ThrowHelper.TryParseThrowFormatException(out value, out bytesConsumed);
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Unsigned.D.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Unsigned.D.cs
index 99aeceddd3..46753f5c57 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Unsigned.D.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Unsigned.D.cs
@@ -6,13 +6,13 @@ namespace System.Buffers.Text
{
public static partial class Utf8Parser
{
- private static bool TryParseByteD(ReadOnlySpan<byte> text, out byte value, out int bytesConsumed)
+ private static bool TryParseByteD(ReadOnlySpan<byte> source, out byte value, out int bytesConsumed)
{
- if (text.Length < 1)
+ if (source.Length < 1)
goto FalseExit;
int index = 0;
- int num = text[index];
+ int num = source[index];
int answer = 0;
if (ParserHelpers.IsDigit(num))
@@ -22,9 +22,9 @@ namespace System.Buffers.Text
do
{
index++;
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
} while (num == '0');
if (!ParserHelpers.IsDigit(num))
goto Done;
@@ -33,18 +33,18 @@ namespace System.Buffers.Text
answer = num - '0';
index++;
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
answer = 10 * answer + num - '0';
// Potential overflow
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
@@ -52,9 +52,9 @@ namespace System.Buffers.Text
if ((uint)answer > byte.MaxValue)
goto FalseExit; // Overflow
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- if (!ParserHelpers.IsDigit(text[index]))
+ if (!ParserHelpers.IsDigit(source[index]))
goto Done;
// Guaranteed overflow
@@ -72,13 +72,13 @@ namespace System.Buffers.Text
return true;
}
- private static bool TryParseUInt16D(ReadOnlySpan<byte> text, out ushort value, out int bytesConsumed)
+ private static bool TryParseUInt16D(ReadOnlySpan<byte> source, out ushort value, out int bytesConsumed)
{
- if (text.Length < 1)
+ if (source.Length < 1)
goto FalseExit;
int index = 0;
- int num = text[index];
+ int num = source[index];
int answer = 0;
if (ParserHelpers.IsDigit(num))
@@ -88,9 +88,9 @@ namespace System.Buffers.Text
do
{
index++;
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
} while (num == '0');
if (!ParserHelpers.IsDigit(num))
goto Done;
@@ -99,34 +99,34 @@ namespace System.Buffers.Text
answer = num - '0';
index++;
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
answer = 10 * answer + num - '0';
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
answer = 10 * answer + num - '0';
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
answer = 10 * answer + num - '0';
// Potential overflow
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
@@ -134,9 +134,9 @@ namespace System.Buffers.Text
if ((uint)answer > ushort.MaxValue)
goto FalseExit; // Overflow
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- if (!ParserHelpers.IsDigit(text[index]))
+ if (!ParserHelpers.IsDigit(source[index]))
goto Done;
// Guaranteed overflow
@@ -154,13 +154,13 @@ namespace System.Buffers.Text
return true;
}
- private static bool TryParseUInt32D(ReadOnlySpan<byte> text, out uint value, out int bytesConsumed)
+ private static bool TryParseUInt32D(ReadOnlySpan<byte> source, out uint value, out int bytesConsumed)
{
- if (text.Length < 1)
+ if (source.Length < 1)
goto FalseExit;
int index = 0;
- int num = text[index];
+ int num = source[index];
int answer = 0;
if (ParserHelpers.IsDigit(num))
@@ -170,9 +170,9 @@ namespace System.Buffers.Text
do
{
index++;
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
} while (num == '0');
if (!ParserHelpers.IsDigit(num))
goto Done;
@@ -181,74 +181,74 @@ namespace System.Buffers.Text
answer = num - '0';
index++;
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
answer = 10 * answer + num - '0';
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
answer = 10 * answer + num - '0';
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
answer = 10 * answer + num - '0';
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
answer = 10 * answer + num - '0';
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
answer = 10 * answer + num - '0';
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
answer = 10 * answer + num - '0';
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
answer = 10 * answer + num - '0';
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
answer = 10 * answer + num - '0';
// Potential overflow
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- num = text[index];
+ num = source[index];
if (!ParserHelpers.IsDigit(num))
goto Done;
index++;
@@ -256,9 +256,9 @@ namespace System.Buffers.Text
goto FalseExit; // Overflow
answer = answer * 10 + num - '0';
- if ((uint)index >= (uint)text.Length)
+ if ((uint)index >= (uint)source.Length)
goto Done;
- if (!ParserHelpers.IsDigit(text[index]))
+ if (!ParserHelpers.IsDigit(source[index]))
goto Done;
// Guaranteed overflow
@@ -276,9 +276,9 @@ namespace System.Buffers.Text
return true;
}
- private static bool TryParseUInt64D(ReadOnlySpan<byte> text, out ulong value, out int bytesConsumed)
+ private static bool TryParseUInt64D(ReadOnlySpan<byte> source, out ulong value, out int bytesConsumed)
{
- if (text.Length < 1)
+ if (source.Length < 1)
{
bytesConsumed = 0;
value = default;
@@ -286,7 +286,7 @@ namespace System.Buffers.Text
}
// Parse the first digit separately. If invalid here, we need to return false.
- ulong firstDigit = text[0] - 48u; // '0'
+ ulong firstDigit = source[0] - 48u; // '0'
if (firstDigit > 9)
{
bytesConsumed = 0;
@@ -295,12 +295,12 @@ namespace System.Buffers.Text
}
ulong parsedValue = firstDigit;
- if (text.Length < ParserHelpers.Int64OverflowLength)
+ if (source.Length < ParserHelpers.Int64OverflowLength)
{
// Length is less than Parsers.Int64OverflowLength; overflow is not possible
- for (int index = 1; index < text.Length; index++)
+ for (int index = 1; index < source.Length; index++)
{
- ulong nextDigit = text[index] - 48u; // '0'
+ ulong nextDigit = source[index] - 48u; // '0'
if (nextDigit > 9)
{
bytesConsumed = index;
@@ -316,7 +316,7 @@ namespace System.Buffers.Text
// digits. There may be no overflow after Parsers.Int64OverflowLength if there are leading zeroes.
for (int index = 1; index < ParserHelpers.Int64OverflowLength - 1; index++)
{
- ulong nextDigit = text[index] - 48u; // '0'
+ ulong nextDigit = source[index] - 48u; // '0'
if (nextDigit > 9)
{
bytesConsumed = index;
@@ -325,9 +325,9 @@ namespace System.Buffers.Text
}
parsedValue = parsedValue * 10 + nextDigit;
}
- for (int index = ParserHelpers.Int64OverflowLength - 1; index < text.Length; index++)
+ for (int index = ParserHelpers.Int64OverflowLength - 1; index < source.Length; index++)
{
- ulong nextDigit = text[index] - 48u; // '0'
+ ulong nextDigit = source[index] - 48u; // '0'
if (nextDigit > 9)
{
bytesConsumed = index;
@@ -346,7 +346,7 @@ namespace System.Buffers.Text
}
}
- bytesConsumed = text.Length;
+ bytesConsumed = source.Length;
value = parsedValue;
return true;
}
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Unsigned.N.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Unsigned.N.cs
index 0990336af3..bb535fb6cb 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Unsigned.N.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Unsigned.N.cs
@@ -9,24 +9,328 @@ namespace System.Buffers.Text
//
public static partial class Utf8Parser
{
- private static bool TryParseByteN(ReadOnlySpan<byte> text, out byte value, out int bytesConsumed)
+ private static bool TryParseByteN(ReadOnlySpan<byte> source, out byte value, out int bytesConsumed)
{
- throw NotImplemented.ActiveIssue("https://github.com/dotnet/corefx/issues/24986");
+ if (source.Length < 1)
+ goto FalseExit;
+
+ int index = 0;
+ int c = source[index];
+ if (c == '+')
+ {
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto FalseExit;
+ c = source[index];
+ }
+
+ int answer;
+
+ // Handle the first digit (or period) as a special case. This ensures some compatible edge-case behavior with the classic parse routines
+ // (at least one digit must precede any commas, and a string without any digits prior to the decimal point must have at least
+ // one digit after the decimal point.)
+ if (c == Utf8Constants.Period)
+ goto FractionalPartWithoutLeadingDigits;
+ if (!ParserHelpers.IsDigit(c))
+ goto FalseExit;
+ answer = c - '0';
+
+ for (; ; )
+ {
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto Done;
+
+ c = source[index];
+ if (c == Utf8Constants.Comma)
+ continue;
+
+ if (c == Utf8Constants.Period)
+ goto FractionalDigits;
+
+ if (!ParserHelpers.IsDigit(c))
+ goto Done;
+
+ answer = answer * 10 + c - '0';
+
+ if (answer > byte.MaxValue)
+ goto FalseExit; // Overflow
+ }
+
+FractionalPartWithoutLeadingDigits: // If we got here, we found a decimal point before we found any digits. This is legal as long as there's at least one zero after the decimal point.
+ answer = 0;
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto FalseExit;
+ if (source[index] != '0')
+ goto FalseExit;
+
+FractionalDigits: // "N" format allows a fractional portion despite being an integer format but only if the post-fraction digits are all 0.
+ do
+ {
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto Done;
+ c = source[index];
+ }
+ while (c == '0');
+
+ if (ParserHelpers.IsDigit(c))
+ goto FalseExit; // The fractional portion contained a non-zero digit. Treat this as an error, not an early termination.
+ goto Done;
+
+FalseExit:
+ bytesConsumed = default;
+ value = default;
+ return false;
+
+Done:
+ bytesConsumed = index;
+ value = (byte)answer;
+ return true;
}
- private static bool TryParseUInt16N(ReadOnlySpan<byte> text, out ushort value, out int bytesConsumed)
+ private static bool TryParseUInt16N(ReadOnlySpan<byte> source, out ushort value, out int bytesConsumed)
{
- throw NotImplemented.ActiveIssue("https://github.com/dotnet/corefx/issues/24986");
+ if (source.Length < 1)
+ goto FalseExit;
+
+ int index = 0;
+ int c = source[index];
+ if (c == '+')
+ {
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto FalseExit;
+ c = source[index];
+ }
+
+ int answer;
+
+ // Handle the first digit (or period) as a special case. This ensures some compatible edge-case behavior with the classic parse routines
+ // (at least one digit must precede any commas, and a string without any digits prior to the decimal point must have at least
+ // one digit after the decimal point.)
+ if (c == Utf8Constants.Period)
+ goto FractionalPartWithoutLeadingDigits;
+ if (!ParserHelpers.IsDigit(c))
+ goto FalseExit;
+ answer = c - '0';
+
+ for (; ; )
+ {
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto Done;
+
+ c = source[index];
+ if (c == Utf8Constants.Comma)
+ continue;
+
+ if (c == Utf8Constants.Period)
+ goto FractionalDigits;
+
+ if (!ParserHelpers.IsDigit(c))
+ goto Done;
+
+ answer = answer * 10 + c - '0';
+
+ if (answer > ushort.MaxValue)
+ goto FalseExit; // Overflow
+ }
+
+FractionalPartWithoutLeadingDigits: // If we got here, we found a decimal point before we found any digits. This is legal as long as there's at least one zero after the decimal point.
+ answer = 0;
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto FalseExit;
+ if (source[index] != '0')
+ goto FalseExit;
+
+FractionalDigits: // "N" format allows a fractional portion despite being an integer format but only if the post-fraction digits are all 0.
+ do
+ {
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto Done;
+ c = source[index];
+ }
+ while (c == '0');
+
+ if (ParserHelpers.IsDigit(c))
+ goto FalseExit; // The fractional portion contained a non-zero digit. Treat this as an error, not an early termination.
+ goto Done;
+
+FalseExit:
+ bytesConsumed = default;
+ value = default;
+ return false;
+
+Done:
+ bytesConsumed = index;
+ value = (ushort)answer;
+ return true;
}
- private static bool TryParseUInt32N(ReadOnlySpan<byte> text, out uint value, out int bytesConsumed)
+ private static bool TryParseUInt32N(ReadOnlySpan<byte> source, out uint value, out int bytesConsumed)
{
- throw NotImplemented.ActiveIssue("https://github.com/dotnet/corefx/issues/24986");
+ if (source.Length < 1)
+ goto FalseExit;
+
+ int index = 0;
+ int c = source[index];
+ if (c == '+')
+ {
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto FalseExit;
+ c = source[index];
+ }
+
+ int answer;
+
+ // Handle the first digit (or period) as a special case. This ensures some compatible edge-case behavior with the classic parse routines
+ // (at least one digit must precede any commas, and a string without any digits prior to the decimal point must have at least
+ // one digit after the decimal point.)
+ if (c == Utf8Constants.Period)
+ goto FractionalPartWithoutLeadingDigits;
+ if (!ParserHelpers.IsDigit(c))
+ goto FalseExit;
+ answer = c - '0';
+
+ for (; ; )
+ {
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto Done;
+
+ c = source[index];
+ if (c == Utf8Constants.Comma)
+ continue;
+
+ if (c == Utf8Constants.Period)
+ goto FractionalDigits;
+
+ if (!ParserHelpers.IsDigit(c))
+ goto Done;
+
+ if (((uint)answer) > uint.MaxValue / 10 || (((uint)answer) == uint.MaxValue / 10 && c > '5'))
+ goto FalseExit; // Overflow
+
+ answer = answer * 10 + c - '0';
+ }
+
+FractionalPartWithoutLeadingDigits: // If we got here, we found a decimal point before we found any digits. This is legal as long as there's at least one zero after the decimal point.
+ answer = 0;
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto FalseExit;
+ if (source[index] != '0')
+ goto FalseExit;
+
+FractionalDigits: // "N" format allows a fractional portion despite being an integer format but only if the post-fraction digits are all 0.
+ do
+ {
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto Done;
+ c = source[index];
+ }
+ while (c == '0');
+
+ if (ParserHelpers.IsDigit(c))
+ goto FalseExit; // The fractional portion contained a non-zero digit. Treat this as an error, not an early termination.
+ goto Done;
+
+FalseExit:
+ bytesConsumed = default;
+ value = default;
+ return false;
+
+Done:
+ bytesConsumed = index;
+ value = (uint)answer;
+ return true;
}
- private static bool TryParseUInt64N(ReadOnlySpan<byte> text, out ulong value, out int bytesConsumed)
+ private static bool TryParseUInt64N(ReadOnlySpan<byte> source, out ulong value, out int bytesConsumed)
{
- throw NotImplemented.ActiveIssue("https://github.com/dotnet/corefx/issues/24986");
+ if (source.Length < 1)
+ goto FalseExit;
+
+ int index = 0;
+ int c = source[index];
+ if (c == '+')
+ {
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto FalseExit;
+ c = source[index];
+ }
+
+ long answer;
+
+ // Handle the first digit (or period) as a special case. This ensures some compatible edge-case behavior with the classic parse routines
+ // (at least one digit must precede any commas, and a string without any digits prior to the decimal point must have at least
+ // one digit after the decimal point.)
+ if (c == Utf8Constants.Period)
+ goto FractionalPartWithoutLeadingDigits;
+ if (!ParserHelpers.IsDigit(c))
+ goto FalseExit;
+ answer = c - '0';
+
+ for (; ; )
+ {
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto Done;
+
+ c = source[index];
+ if (c == Utf8Constants.Comma)
+ continue;
+
+ if (c == Utf8Constants.Period)
+ goto FractionalDigits;
+
+ if (!ParserHelpers.IsDigit(c))
+ goto Done;
+
+ if (((ulong)answer) > ulong.MaxValue / 10 || (((ulong)answer) == ulong.MaxValue / 10 && c > '5'))
+ goto FalseExit; // Overflow
+
+ answer = answer * 10 + c - '0';
+ }
+
+FractionalPartWithoutLeadingDigits: // If we got here, we found a decimal point before we found any digits. This is legal as long as there's at least one zero after the decimal point.
+ answer = 0;
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto FalseExit;
+ if (source[index] != '0')
+ goto FalseExit;
+
+FractionalDigits: // "N" format allows a fractional portion despite being an integer format but only if the post-fraction digits are all 0.
+ do
+ {
+ index++;
+ if ((uint)index >= (uint)source.Length)
+ goto Done;
+ c = source[index];
+ }
+ while (c == '0');
+
+ if (ParserHelpers.IsDigit(c))
+ goto FalseExit; // The fractional portion contained a non-zero digit. Treat this as an error, not an early termination.
+ goto Done;
+
+FalseExit:
+ bytesConsumed = default;
+ value = default;
+ return false;
+
+Done:
+ bytesConsumed = index;
+ value = (ulong)answer;
+ return true;
}
}
}
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Unsigned.X.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Unsigned.X.cs
index 0e320a229a..7e7867a56f 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Unsigned.X.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Unsigned.X.cs
@@ -6,9 +6,9 @@ namespace System.Buffers.Text
{
public static partial class Utf8Parser
{
- private static bool TryParseByteX(ReadOnlySpan<byte> text, out byte value, out int bytesConsumed)
+ private static bool TryParseByteX(ReadOnlySpan<byte> source, out byte value, out int bytesConsumed)
{
- if (text.Length < 1)
+ if (source.Length < 1)
{
bytesConsumed = 0;
value = default;
@@ -21,7 +21,7 @@ namespace System.Buffers.Text
byte[] hexLookup = ParserHelpers.s_hexLookup;
// Parse the first digit separately. If invalid here, we need to return false.
- nextCharacter = text[0];
+ nextCharacter = source[0];
nextDigit = hexLookup[nextCharacter];
if (nextDigit == 0xFF)
{
@@ -31,12 +31,12 @@ namespace System.Buffers.Text
}
uint parsedValue = nextDigit;
- if (text.Length <= ParserHelpers.ByteOverflowLengthHex)
+ if (source.Length <= ParserHelpers.ByteOverflowLengthHex)
{
// Length is less than or equal to Parsers.ByteOverflowLengthHex; overflow is not possible
- for (int index = 1; index < text.Length; index++)
+ for (int index = 1; index < source.Length; index++)
{
- nextCharacter = text[index];
+ nextCharacter = source[index];
nextDigit = hexLookup[nextCharacter];
if (nextDigit == 0xFF)
{
@@ -53,7 +53,7 @@ namespace System.Buffers.Text
// digits. There may be no overflow after Parsers.ByteOverflowLengthHex if there are leading zeroes.
for (int index = 1; index < ParserHelpers.ByteOverflowLengthHex; index++)
{
- nextCharacter = text[index];
+ nextCharacter = source[index];
nextDigit = hexLookup[nextCharacter];
if (nextDigit == 0xFF)
{
@@ -63,9 +63,9 @@ namespace System.Buffers.Text
}
parsedValue = (parsedValue << 4) + nextDigit;
}
- for (int index = ParserHelpers.ByteOverflowLengthHex; index < text.Length; index++)
+ for (int index = ParserHelpers.ByteOverflowLengthHex; index < source.Length; index++)
{
- nextCharacter = text[index];
+ nextCharacter = source[index];
nextDigit = hexLookup[nextCharacter];
if (nextDigit == 0xFF)
{
@@ -84,14 +84,14 @@ namespace System.Buffers.Text
}
}
- bytesConsumed = text.Length;
+ bytesConsumed = source.Length;
value = (byte)(parsedValue);
return true;
}
- private static bool TryParseUInt16X(ReadOnlySpan<byte> text, out ushort value, out int bytesConsumed)
+ private static bool TryParseUInt16X(ReadOnlySpan<byte> source, out ushort value, out int bytesConsumed)
{
- if (text.Length < 1)
+ if (source.Length < 1)
{
bytesConsumed = 0;
value = default;
@@ -104,7 +104,7 @@ namespace System.Buffers.Text
byte[] hexLookup = ParserHelpers.s_hexLookup;
// Parse the first digit separately. If invalid here, we need to return false.
- nextCharacter = text[0];
+ nextCharacter = source[0];
nextDigit = hexLookup[nextCharacter];
if (nextDigit == 0xFF)
{
@@ -114,12 +114,12 @@ namespace System.Buffers.Text
}
uint parsedValue = nextDigit;
- if (text.Length <= ParserHelpers.Int16OverflowLengthHex)
+ if (source.Length <= ParserHelpers.Int16OverflowLengthHex)
{
// Length is less than or equal to Parsers.Int16OverflowLengthHex; overflow is not possible
- for (int index = 1; index < text.Length; index++)
+ for (int index = 1; index < source.Length; index++)
{
- nextCharacter = text[index];
+ nextCharacter = source[index];
nextDigit = hexLookup[nextCharacter];
if (nextDigit == 0xFF)
{
@@ -136,7 +136,7 @@ namespace System.Buffers.Text
// digits. There may be no overflow after Parsers.Int16OverflowLengthHex if there are leading zeroes.
for (int index = 1; index < ParserHelpers.Int16OverflowLengthHex; index++)
{
- nextCharacter = text[index];
+ nextCharacter = source[index];
nextDigit = hexLookup[nextCharacter];
if (nextDigit == 0xFF)
{
@@ -146,9 +146,9 @@ namespace System.Buffers.Text
}
parsedValue = (parsedValue << 4) + nextDigit;
}
- for (int index = ParserHelpers.Int16OverflowLengthHex; index < text.Length; index++)
+ for (int index = ParserHelpers.Int16OverflowLengthHex; index < source.Length; index++)
{
- nextCharacter = text[index];
+ nextCharacter = source[index];
nextDigit = hexLookup[nextCharacter];
if (nextDigit == 0xFF)
{
@@ -167,14 +167,14 @@ namespace System.Buffers.Text
}
}
- bytesConsumed = text.Length;
+ bytesConsumed = source.Length;
value = (ushort)(parsedValue);
return true;
}
- private static bool TryParseUInt32X(ReadOnlySpan<byte> text, out uint value, out int bytesConsumed)
+ private static bool TryParseUInt32X(ReadOnlySpan<byte> source, out uint value, out int bytesConsumed)
{
- if (text.Length < 1)
+ if (source.Length < 1)
{
bytesConsumed = 0;
value = default;
@@ -187,7 +187,7 @@ namespace System.Buffers.Text
byte[] hexLookup = ParserHelpers.s_hexLookup;
// Parse the first digit separately. If invalid here, we need to return false.
- nextCharacter = text[0];
+ nextCharacter = source[0];
nextDigit = hexLookup[nextCharacter];
if (nextDigit == 0xFF)
{
@@ -197,12 +197,12 @@ namespace System.Buffers.Text
}
uint parsedValue = nextDigit;
- if (text.Length <= ParserHelpers.Int32OverflowLengthHex)
+ if (source.Length <= ParserHelpers.Int32OverflowLengthHex)
{
// Length is less than or equal to Parsers.Int32OverflowLengthHex; overflow is not possible
- for (int index = 1; index < text.Length; index++)
+ for (int index = 1; index < source.Length; index++)
{
- nextCharacter = text[index];
+ nextCharacter = source[index];
nextDigit = hexLookup[nextCharacter];
if (nextDigit == 0xFF)
{
@@ -219,7 +219,7 @@ namespace System.Buffers.Text
// digits. There may be no overflow after Parsers.Int32OverflowLengthHex if there are leading zeroes.
for (int index = 1; index < ParserHelpers.Int32OverflowLengthHex; index++)
{
- nextCharacter = text[index];
+ nextCharacter = source[index];
nextDigit = hexLookup[nextCharacter];
if (nextDigit == 0xFF)
{
@@ -229,9 +229,9 @@ namespace System.Buffers.Text
}
parsedValue = (parsedValue << 4) + nextDigit;
}
- for (int index = ParserHelpers.Int32OverflowLengthHex; index < text.Length; index++)
+ for (int index = ParserHelpers.Int32OverflowLengthHex; index < source.Length; index++)
{
- nextCharacter = text[index];
+ nextCharacter = source[index];
nextDigit = hexLookup[nextCharacter];
if (nextDigit == 0xFF)
{
@@ -250,14 +250,14 @@ namespace System.Buffers.Text
}
}
- bytesConsumed = text.Length;
+ bytesConsumed = source.Length;
value = parsedValue;
return true;
}
- private static bool TryParseUInt64X(ReadOnlySpan<byte> text, out ulong value, out int bytesConsumed)
+ private static bool TryParseUInt64X(ReadOnlySpan<byte> source, out ulong value, out int bytesConsumed)
{
- if (text.Length < 1)
+ if (source.Length < 1)
{
bytesConsumed = 0;
value = default;
@@ -270,7 +270,7 @@ namespace System.Buffers.Text
byte[] hexLookup = ParserHelpers.s_hexLookup;
// Parse the first digit separately. If invalid here, we need to return false.
- nextCharacter = text[0];
+ nextCharacter = source[0];
nextDigit = hexLookup[nextCharacter];
if (nextDigit == 0xFF)
{
@@ -280,12 +280,12 @@ namespace System.Buffers.Text
}
ulong parsedValue = nextDigit;
- if (text.Length <= ParserHelpers.Int64OverflowLengthHex)
+ if (source.Length <= ParserHelpers.Int64OverflowLengthHex)
{
// Length is less than or equal to Parsers.Int64OverflowLengthHex; overflow is not possible
- for (int index = 1; index < text.Length; index++)
+ for (int index = 1; index < source.Length; index++)
{
- nextCharacter = text[index];
+ nextCharacter = source[index];
nextDigit = hexLookup[nextCharacter];
if (nextDigit == 0xFF)
{
@@ -302,7 +302,7 @@ namespace System.Buffers.Text
// digits. There may be no overflow after Parsers.Int64OverflowLengthHex if there are leading zeroes.
for (int index = 1; index < ParserHelpers.Int64OverflowLengthHex; index++)
{
- nextCharacter = text[index];
+ nextCharacter = source[index];
nextDigit = hexLookup[nextCharacter];
if (nextDigit == 0xFF)
{
@@ -312,9 +312,9 @@ namespace System.Buffers.Text
}
parsedValue = (parsedValue << 4) + nextDigit;
}
- for (int index = ParserHelpers.Int64OverflowLengthHex; index < text.Length; index++)
+ for (int index = ParserHelpers.Int64OverflowLengthHex; index < source.Length; index++)
{
- nextCharacter = text[index];
+ nextCharacter = source[index];
nextDigit = hexLookup[nextCharacter];
if (nextDigit == 0xFF)
{
@@ -333,7 +333,7 @@ namespace System.Buffers.Text
}
}
- bytesConsumed = text.Length;
+ bytesConsumed = source.Length;
value = parsedValue;
return true;
}
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Unsigned.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Unsigned.cs
index 78dfdebcd9..ae23c29d04 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Unsigned.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Unsigned.cs
@@ -9,7 +9,7 @@ namespace System.Buffers.Text
/// <summary>
/// Parses a Byte at the start of a Utf8 string.
/// </summary>
- /// <param name="text">The Utf8 string to parse</param>
+ /// <param name="source">The Utf8 string to parse</param>
/// <param name="value">Receives the parsed value</param>
/// <param name="bytesConsumed">On a successful parse, receives the length in bytes of the substring that was parsed </param>
/// <param name="standardFormat">Expected format of the Utf8 string</param>
@@ -27,24 +27,24 @@ namespace System.Buffers.Text
/// <exceptions>
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
- public static bool TryParse(ReadOnlySpan<byte> text, out byte value, out int bytesConsumed, char standardFormat = default)
+ public static bool TryParse(ReadOnlySpan<byte> source, out byte value, out int bytesConsumed, char standardFormat = default)
{
switch (standardFormat)
{
- case (default):
+ case default(char):
case 'g':
case 'G':
case 'd':
case 'D':
- return TryParseByteD(text, out value, out bytesConsumed);
+ return TryParseByteD(source, out value, out bytesConsumed);
case 'n':
case 'N':
- return TryParseByteN(text, out value, out bytesConsumed);
+ return TryParseByteN(source, out value, out bytesConsumed);
case 'x':
case 'X':
- return TryParseByteX(text, out value, out bytesConsumed);
+ return TryParseByteX(source, out value, out bytesConsumed);
default:
return ThrowHelper.TryParseThrowFormatException(out value, out bytesConsumed);
@@ -54,7 +54,7 @@ namespace System.Buffers.Text
/// <summary>
/// Parses a UInt16 at the start of a Utf8 string.
/// </summary>
- /// <param name="text">The Utf8 string to parse</param>
+ /// <param name="source">The Utf8 string to parse</param>
/// <param name="value">Receives the parsed value</param>
/// <param name="bytesConsumed">On a successful parse, receives the length in bytes of the substring that was parsed </param>
/// <param name="standardFormat">Expected format of the Utf8 string</param>
@@ -73,24 +73,24 @@ namespace System.Buffers.Text
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
[CLSCompliant(false)]
- public static bool TryParse(ReadOnlySpan<byte> text, out ushort value, out int bytesConsumed, char standardFormat = default)
+ public static bool TryParse(ReadOnlySpan<byte> source, out ushort value, out int bytesConsumed, char standardFormat = default)
{
switch (standardFormat)
{
- case (default):
+ case default(char):
case 'g':
case 'G':
case 'd':
case 'D':
- return TryParseUInt16D(text, out value, out bytesConsumed);
+ return TryParseUInt16D(source, out value, out bytesConsumed);
case 'n':
case 'N':
- return TryParseUInt16N(text, out value, out bytesConsumed);
+ return TryParseUInt16N(source, out value, out bytesConsumed);
case 'x':
case 'X':
- return TryParseUInt16X(text, out value, out bytesConsumed);
+ return TryParseUInt16X(source, out value, out bytesConsumed);
default:
return ThrowHelper.TryParseThrowFormatException(out value, out bytesConsumed);
@@ -100,7 +100,7 @@ namespace System.Buffers.Text
/// <summary>
/// Parses a UInt32 at the start of a Utf8 string.
/// </summary>
- /// <param name="text">The Utf8 string to parse</param>
+ /// <param name="source">The Utf8 string to parse</param>
/// <param name="value">Receives the parsed value</param>
/// <param name="bytesConsumed">On a successful parse, receives the length in bytes of the substring that was parsed </param>
/// <param name="standardFormat">Expected format of the Utf8 string</param>
@@ -119,24 +119,24 @@ namespace System.Buffers.Text
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
[CLSCompliant(false)]
- public static bool TryParse(ReadOnlySpan<byte> text, out uint value, out int bytesConsumed, char standardFormat = default)
+ public static bool TryParse(ReadOnlySpan<byte> source, out uint value, out int bytesConsumed, char standardFormat = default)
{
switch (standardFormat)
{
- case (default):
+ case default(char):
case 'g':
case 'G':
case 'd':
case 'D':
- return TryParseUInt32D(text, out value, out bytesConsumed);
+ return TryParseUInt32D(source, out value, out bytesConsumed);
case 'n':
case 'N':
- return TryParseUInt32N(text, out value, out bytesConsumed);
+ return TryParseUInt32N(source, out value, out bytesConsumed);
case 'x':
case 'X':
- return TryParseUInt32X(text, out value, out bytesConsumed);
+ return TryParseUInt32X(source, out value, out bytesConsumed);
default:
return ThrowHelper.TryParseThrowFormatException(out value, out bytesConsumed);
@@ -146,7 +146,7 @@ namespace System.Buffers.Text
/// <summary>
/// Parses a UInt64 at the start of a Utf8 string.
/// </summary>
- /// <param name="text">The Utf8 string to parse</param>
+ /// <param name="source">The Utf8 string to parse</param>
/// <param name="value">Receives the parsed value</param>
/// <param name="bytesConsumed">On a successful parse, receives the length in bytes of the substring that was parsed </param>
/// <param name="standardFormat">Expected format of the Utf8 string</param>
@@ -165,24 +165,24 @@ namespace System.Buffers.Text
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
[CLSCompliant(false)]
- public static bool TryParse(ReadOnlySpan<byte> text, out ulong value, out int bytesConsumed, char standardFormat = default)
+ public static bool TryParse(ReadOnlySpan<byte> source, out ulong value, out int bytesConsumed, char standardFormat = default)
{
switch (standardFormat)
{
- case (default):
+ case default(char):
case 'g':
case 'G':
case 'd':
case 'D':
- return TryParseUInt64D(text, out value, out bytesConsumed);
+ return TryParseUInt64D(source, out value, out bytesConsumed);
case 'n':
case 'N':
- return TryParseUInt64N(text, out value, out bytesConsumed);
+ return TryParseUInt64N(source, out value, out bytesConsumed);
case 'x':
case 'X':
- return TryParseUInt64X(text, out value, out bytesConsumed);
+ return TryParseUInt64X(source, out value, out bytesConsumed);
default:
return ThrowHelper.TryParseThrowFormatException(out value, out bytesConsumed);
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Number.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Number.cs
index 4f45a5c2c2..527150963b 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Number.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Number.cs
@@ -14,13 +14,13 @@ namespace System.Buffers.Text
AllowExponent = 0x00000001,
}
- private static bool TryParseNumber(ReadOnlySpan<byte> text, ref NumberBuffer number, out int bytesConsumed, ParseNumberOptions options, out bool textUsedExponentNotation)
+ private static bool TryParseNumber(ReadOnlySpan<byte> source, ref NumberBuffer number, out int bytesConsumed, ParseNumberOptions options, out bool textUsedExponentNotation)
{
Debug.Assert(number.Digits[0] == 0 && number.Scale == 0 && !number.IsNegative, "Number not initialized to default(NumberBuffer)");
textUsedExponentNotation = false;
- if (text.Length == 0)
+ if (source.Length == 0)
{
bytesConsumed = 0;
return false;
@@ -32,7 +32,7 @@ namespace System.Buffers.Text
int dstIndex = 0;
// Consume the leading sign if any.
- byte c = text[srcIndex];
+ byte c = source[srcIndex];
switch (c)
{
case Utf8Constants.Minus:
@@ -41,12 +41,12 @@ namespace System.Buffers.Text
case Utf8Constants.Plus:
srcIndex++;
- if (srcIndex == text.Length)
+ if (srcIndex == source.Length)
{
bytesConsumed = 0;
return false;
}
- c = text[srcIndex];
+ c = source[srcIndex];
break;
default:
@@ -56,15 +56,15 @@ namespace System.Buffers.Text
int startIndexDigitsBeforeDecimal = srcIndex;
// Throw away any leading zeroes
- while (srcIndex != text.Length)
+ while (srcIndex != source.Length)
{
- c = text[srcIndex];
+ c = source[srcIndex];
if (c != '0')
break;
srcIndex++;
}
- if (srcIndex == text.Length)
+ if (srcIndex == source.Length)
{
digits[0] = 0;
number.Scale = 0;
@@ -74,9 +74,9 @@ namespace System.Buffers.Text
}
int startIndexNonLeadingDigitsBeforeDecimal = srcIndex;
- while (srcIndex != text.Length)
+ while (srcIndex != source.Length)
{
- c = text[srcIndex];
+ c = source[srcIndex];
if ((c - 48u) > 9)
break;
srcIndex++;
@@ -87,11 +87,11 @@ namespace System.Buffers.Text
Debug.Assert(dstIndex == 0);
int numNonLeadingDigitsBeforeDecimalToCopy = Math.Min(numNonLeadingDigitsBeforeDecimal, NumberBuffer.BufferSize - 1);
- text.Slice(startIndexNonLeadingDigitsBeforeDecimal, numNonLeadingDigitsBeforeDecimalToCopy).CopyTo(digits);
+ source.Slice(startIndexNonLeadingDigitsBeforeDecimal, numNonLeadingDigitsBeforeDecimalToCopy).CopyTo(digits);
dstIndex = numNonLeadingDigitsBeforeDecimalToCopy;
number.Scale = numNonLeadingDigitsBeforeDecimal;
- if (srcIndex == text.Length)
+ if (srcIndex == source.Length)
{
bytesConsumed = srcIndex;
number.CheckConsistency();
@@ -107,9 +107,9 @@ namespace System.Buffers.Text
srcIndex++;
int startIndexDigitsAfterDecimal = srcIndex;
- while (srcIndex != text.Length)
+ while (srcIndex != source.Length)
{
- c = text[srcIndex];
+ c = source[srcIndex];
if ((c - 48u) > 9)
break;
srcIndex++;
@@ -120,7 +120,7 @@ namespace System.Buffers.Text
if (dstIndex == 0)
{
// Not copied any digits to the Number struct yet. This means we must continue discarding leading zeroes even though they appeared after the decimal point.
- while (startIndexOfDigitsAfterDecimalToCopy < srcIndex && text[startIndexOfDigitsAfterDecimalToCopy] == '0')
+ while (startIndexOfDigitsAfterDecimalToCopy < srcIndex && source[startIndexOfDigitsAfterDecimalToCopy] == '0')
{
number.Scale--;
startIndexOfDigitsAfterDecimalToCopy++;
@@ -128,11 +128,11 @@ namespace System.Buffers.Text
}
int numDigitsAfterDecimalToCopy = Math.Min(srcIndex - startIndexOfDigitsAfterDecimalToCopy, NumberBuffer.BufferSize - dstIndex - 1);
- text.Slice(startIndexOfDigitsAfterDecimalToCopy, numDigitsAfterDecimalToCopy).CopyTo(digits.Slice(dstIndex));
+ source.Slice(startIndexOfDigitsAfterDecimalToCopy, numDigitsAfterDecimalToCopy).CopyTo(digits.Slice(dstIndex));
dstIndex += numDigitsAfterDecimalToCopy;
// We "should" really NUL terminate, but there are multiple places we'd have to do this and it is a precondition that the caller pass in a fully zero=initialized Number.
- if (srcIndex == text.Length)
+ if (srcIndex == source.Length)
{
if (numDigitsBeforeDecimal == 0 && numDigitsAfterDecimal == 0)
{
@@ -172,14 +172,14 @@ namespace System.Buffers.Text
return false;
}
- if (srcIndex == text.Length)
+ if (srcIndex == source.Length)
{
bytesConsumed = 0;
return false;
}
bool exponentIsNegative = false;
- c = text[srcIndex];
+ c = source[srcIndex];
switch (c)
{
case Utf8Constants.Minus:
@@ -188,19 +188,19 @@ namespace System.Buffers.Text
case Utf8Constants.Plus:
srcIndex++;
- if (srcIndex == text.Length)
+ if (srcIndex == source.Length)
{
bytesConsumed = 0;
return false;
}
- c = text[srcIndex];
+ c = source[srcIndex];
break;
default:
break;
}
- if (!Utf8Parser.TryParseUInt32D(text.Slice(srcIndex), out uint absoluteExponent, out int bytesConsumedByExponent))
+ if (!Utf8Parser.TryParseUInt32D(source.Slice(srcIndex), out uint absoluteExponent, out int bytesConsumedByExponent))
{
bytesConsumed = 0;
return false;
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.TimeSpan.BigG.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.TimeSpan.BigG.cs
index 6c4d2265fa..6bcb4d5277 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.TimeSpan.BigG.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.TimeSpan.BigG.cs
@@ -6,19 +6,19 @@ namespace System.Buffers.Text
{
public static partial class Utf8Parser
{
- private static bool TryParseTimeSpanBigG(ReadOnlySpan<byte> text, out TimeSpan value, out int bytesConsumed)
+ private static bool TryParseTimeSpanBigG(ReadOnlySpan<byte> source, out TimeSpan value, out int bytesConsumed)
{
int srcIndex = 0;
byte c = default;
- while (srcIndex != text.Length)
+ while (srcIndex != source.Length)
{
- c = text[srcIndex];
+ c = source[srcIndex];
if (!(c == ' ' || c == '\t'))
break;
srcIndex++;
}
- if (srcIndex == text.Length)
+ if (srcIndex == source.Length)
{
value = default;
bytesConsumed = 0;
@@ -30,7 +30,7 @@ namespace System.Buffers.Text
{
isNegative = true;
srcIndex++;
- if (srcIndex == text.Length)
+ if (srcIndex == source.Length)
{
value = default;
bytesConsumed = 0;
@@ -38,7 +38,7 @@ namespace System.Buffers.Text
}
}
- if (!TryParseUInt32D(text.Slice(srcIndex), out uint days, out int justConsumed))
+ if (!TryParseUInt32D(source.Slice(srcIndex), out uint days, out int justConsumed))
{
value = default;
bytesConsumed = 0;
@@ -46,14 +46,14 @@ namespace System.Buffers.Text
}
srcIndex += justConsumed;
- if (srcIndex == text.Length || text[srcIndex++] != Utf8Constants.Colon)
+ if (srcIndex == source.Length || source[srcIndex++] != Utf8Constants.Colon)
{
value = default;
bytesConsumed = 0;
return false;
}
- if (!TryParseUInt32D(text.Slice(srcIndex), out uint hours, out justConsumed))
+ if (!TryParseUInt32D(source.Slice(srcIndex), out uint hours, out justConsumed))
{
value = default;
bytesConsumed = 0;
@@ -61,14 +61,14 @@ namespace System.Buffers.Text
}
srcIndex += justConsumed;
- if (srcIndex == text.Length || text[srcIndex++] != Utf8Constants.Colon)
+ if (srcIndex == source.Length || source[srcIndex++] != Utf8Constants.Colon)
{
value = default;
bytesConsumed = 0;
return false;
}
- if (!TryParseUInt32D(text.Slice(srcIndex), out uint minutes, out justConsumed))
+ if (!TryParseUInt32D(source.Slice(srcIndex), out uint minutes, out justConsumed))
{
value = default;
bytesConsumed = 0;
@@ -76,14 +76,14 @@ namespace System.Buffers.Text
}
srcIndex += justConsumed;
- if (srcIndex == text.Length || text[srcIndex++] != Utf8Constants.Colon)
+ if (srcIndex == source.Length || source[srcIndex++] != Utf8Constants.Colon)
{
value = default;
bytesConsumed = 0;
return false;
}
- if (!TryParseUInt32D(text.Slice(srcIndex), out uint seconds, out justConsumed))
+ if (!TryParseUInt32D(source.Slice(srcIndex), out uint seconds, out justConsumed))
{
value = default;
bytesConsumed = 0;
@@ -91,14 +91,14 @@ namespace System.Buffers.Text
}
srcIndex += justConsumed;
- if (srcIndex == text.Length || text[srcIndex++] != Utf8Constants.Period)
+ if (srcIndex == source.Length || source[srcIndex++] != Utf8Constants.Period)
{
value = default;
bytesConsumed = 0;
return false;
}
- if (!TryParseTimeSpanFraction(text.Slice(srcIndex), out uint fraction, out justConsumed))
+ if (!TryParseTimeSpanFraction(source.Slice(srcIndex), out uint fraction, out justConsumed))
{
value = default;
bytesConsumed = 0;
@@ -118,7 +118,7 @@ namespace System.Buffers.Text
// There cannot legally be a sixth number. If the next character is a period or colon, treat this as a error as it's likely
// to indicate the start of a sixth number. Otherwise, treat as end of parse with data left over.
//
- if (srcIndex != text.Length && (text[srcIndex] == Utf8Constants.Period || text[srcIndex] == Utf8Constants.Colon))
+ if (srcIndex != source.Length && (source[srcIndex] == Utf8Constants.Period || source[srcIndex] == Utf8Constants.Colon))
{
value = default;
bytesConsumed = 0;
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.TimeSpan.C.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.TimeSpan.C.cs
index 5f50f3ec2e..d0a28969be 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.TimeSpan.C.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.TimeSpan.C.cs
@@ -6,10 +6,10 @@ namespace System.Buffers.Text
{
public static partial class Utf8Parser
{
- private static bool TryParseTimeSpanC(ReadOnlySpan<byte> text, out TimeSpan value, out int bytesConsumed)
+ private static bool TryParseTimeSpanC(ReadOnlySpan<byte> source, out TimeSpan value, out int bytesConsumed)
{
TimeSpanSplitter s = default;
- if (!s.TrySplitTimeSpan(text, periodUsedToSeparateDay: true, out bytesConsumed))
+ if (!s.TrySplitTimeSpan(source, periodUsedToSeparateDay: true, out bytesConsumed))
{
value = default;
return false;
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.TimeSpan.LittleG.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.TimeSpan.LittleG.cs
index ebf885ce9f..19208b9eac 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.TimeSpan.LittleG.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.TimeSpan.LittleG.cs
@@ -6,10 +6,10 @@ namespace System.Buffers.Text
{
public static partial class Utf8Parser
{
- private static bool TryParseTimeSpanLittleG(ReadOnlySpan<byte> text, out TimeSpan value, out int bytesConsumed)
+ private static bool TryParseTimeSpanLittleG(ReadOnlySpan<byte> source, out TimeSpan value, out int bytesConsumed)
{
TimeSpanSplitter s = default;
- if (!s.TrySplitTimeSpan(text, periodUsedToSeparateDay: false, out bytesConsumed))
+ if (!s.TrySplitTimeSpan(source, periodUsedToSeparateDay: false, out bytesConsumed))
{
value = default;
return false;
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.TimeSpan.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.TimeSpan.cs
index e971718fbb..0ce810b392 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.TimeSpan.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.TimeSpan.cs
@@ -11,7 +11,7 @@ namespace System.Buffers.Text
/// <summary>
/// Parses a TimeSpan at the start of a Utf8 string.
/// </summary>
- /// <param name="text">The Utf8 string to parse</param>
+ /// <param name="source">The Utf8 string to parse</param>
/// <param name="value">Receives the parsed value</param>
/// <param name="bytesConsumed">On a successful parse, receives the length in bytes of the substring that was parsed </param>
/// <param name="standardFormat">Expected format of the Utf8 string</param>
@@ -28,21 +28,21 @@ namespace System.Buffers.Text
/// <exceptions>
/// <cref>System.FormatException</cref> if the format is not valid for this data type.
/// </exceptions>
- public static bool TryParse(ReadOnlySpan<byte> text, out TimeSpan value, out int bytesConsumed, char standardFormat = default)
+ public static bool TryParse(ReadOnlySpan<byte> source, out TimeSpan value, out int bytesConsumed, char standardFormat = default)
{
switch (standardFormat)
{
- case (default):
+ case default(char):
case 'c':
case 't':
case 'T':
- return TryParseTimeSpanC(text, out value, out bytesConsumed);
+ return TryParseTimeSpanC(source, out value, out bytesConsumed);
case 'G':
- return TryParseTimeSpanBigG(text, out value, out bytesConsumed);
+ return TryParseTimeSpanBigG(source, out value, out bytesConsumed);
case 'g':
- return TryParseTimeSpanLittleG(text, out value, out bytesConsumed);
+ return TryParseTimeSpanLittleG(source, out value, out bytesConsumed);
default:
return ThrowHelper.TryParseThrowFormatException(out value, out bytesConsumed);
@@ -53,18 +53,18 @@ namespace System.Buffers.Text
/// Parse the fraction portion of a TimeSpan. Must be 1..7 digits. If fewer than 7, zeroes are implied to the right. If more than 7, the TimeSpan
/// parser rejects the string (even if the extra digits are all zeroes.)
/// </summary>
- private static bool TryParseTimeSpanFraction(ReadOnlySpan<byte> text, out uint value, out int bytesConsumed)
+ private static bool TryParseTimeSpanFraction(ReadOnlySpan<byte> source, out uint value, out int bytesConsumed)
{
int srcIndex = 0;
- if (srcIndex == text.Length)
+ if (srcIndex == source.Length)
{
value = default;
bytesConsumed = 0;
return false;
}
- uint digit = text[srcIndex] - 48u; // '0'
+ uint digit = source[srcIndex] - 48u; // '0'
if (digit > 9)
{
value = default;
@@ -76,9 +76,9 @@ namespace System.Buffers.Text
uint fraction = digit;
int digitCount = 1;
- while (srcIndex != text.Length)
+ while (srcIndex != source.Length)
{
- digit = text[srcIndex] - 48u; // '0'
+ digit = source[srcIndex] - 48u; // '0'
if (digit > 9)
break;
srcIndex++;
diff --git a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.TimeSpanSplitter.cs b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.TimeSpanSplitter.cs
index eb76509ee1..0c72d1f3a2 100644
--- a/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.TimeSpanSplitter.cs
+++ b/src/System.Memory/src/System/Buffers/Text/Utf8Parser/Utf8Parser.TimeSpanSplitter.cs
@@ -33,21 +33,21 @@ namespace System.Buffers.Text
// (So a value of 0x01010200 means the string parsed as "nn:nn:nn.nnnnnnn")
public uint Separators;
- public bool TrySplitTimeSpan(ReadOnlySpan<byte> text, bool periodUsedToSeparateDay, out int bytesConsumed)
+ public bool TrySplitTimeSpan(ReadOnlySpan<byte> source, bool periodUsedToSeparateDay, out int bytesConsumed)
{
int srcIndex = 0;
byte c = default;
// Unlike many other data types, TimeSpan allow leading whitespace.
- while (srcIndex != text.Length)
+ while (srcIndex != source.Length)
{
- c = text[srcIndex];
+ c = source[srcIndex];
if (!(c == ' ' || c == '\t'))
break;
srcIndex++;
}
- if (srcIndex == text.Length)
+ if (srcIndex == source.Length)
{
bytesConsumed = 0;
return false;
@@ -58,7 +58,7 @@ namespace System.Buffers.Text
{
IsNegative = true;
srcIndex++;
- if (srcIndex == text.Length)
+ if (srcIndex == source.Length)
{
bytesConsumed = 0;
return false;
@@ -71,7 +71,7 @@ namespace System.Buffers.Text
//
// Timespan has to start with a number - parse the first one.
//
- if (!TryParseUInt32D(text.Slice(srcIndex), out V1, out int justConsumed))
+ if (!TryParseUInt32D(source.Slice(srcIndex), out V1, out int justConsumed))
{
bytesConsumed = 0;
return false;
@@ -85,7 +85,7 @@ namespace System.Buffers.Text
// the fraction is always the fourth component at earliest, so if we do see a period at this stage, always parse the integer as a regular integer, not as
// a fraction.
//
- result = ParseComponent(text, neverParseAsFraction: periodUsedToSeparateDay, ref srcIndex, out V2);
+ result = ParseComponent(source, neverParseAsFraction: periodUsedToSeparateDay, ref srcIndex, out V2);
if (result == ComponentParseResult.ParseFailure)
{
bytesConsumed = 0;
@@ -105,7 +105,7 @@ namespace System.Buffers.Text
//
// Split out the third number (if any)
//
- result = ParseComponent(text, false, ref srcIndex, out V3);
+ result = ParseComponent(source, false, ref srcIndex, out V3);
if (result == ComponentParseResult.ParseFailure)
{
bytesConsumed = 0;
@@ -125,7 +125,7 @@ namespace System.Buffers.Text
//
// Split out the fourth number (if any)
//
- result = ParseComponent(text, false, ref srcIndex, out V4);
+ result = ParseComponent(source, false, ref srcIndex, out V4);
if (result == ComponentParseResult.ParseFailure)
{
bytesConsumed = 0;
@@ -145,7 +145,7 @@ namespace System.Buffers.Text
//
// Split out the fifth number (if any)
//
- result = ParseComponent(text, false, ref srcIndex, out V5);
+ result = ParseComponent(source, false, ref srcIndex, out V5);
if (result == ComponentParseResult.ParseFailure)
{
bytesConsumed = 0;
@@ -166,7 +166,7 @@ namespace System.Buffers.Text
// There cannot legally be a sixth number. If the next character is a period or colon, treat this as a error as it's likely
// to indicate the start of a sixth number. Otherwise, treat as end of parse with data left over.
//
- if (srcIndex != text.Length && (text[srcIndex] == Utf8Constants.Period || text[srcIndex] == Utf8Constants.Colon))
+ if (srcIndex != source.Length && (source[srcIndex] == Utf8Constants.Period || source[srcIndex] == Utf8Constants.Colon))
{
bytesConsumed = 0;
return false;
@@ -179,20 +179,20 @@ namespace System.Buffers.Text
//
// Look for a separator followed by an unsigned integer.
//
- private static ComponentParseResult ParseComponent(ReadOnlySpan<byte> text, bool neverParseAsFraction, ref int srcIndex, out uint value)
+ private static ComponentParseResult ParseComponent(ReadOnlySpan<byte> source, bool neverParseAsFraction, ref int srcIndex, out uint value)
{
- if (srcIndex == text.Length)
+ if (srcIndex == source.Length)
{
value = default;
return ComponentParseResult.NoMoreData;
}
- byte c = text[srcIndex];
+ byte c = source[srcIndex];
if (c == Utf8Constants.Colon || (c == Utf8Constants.Period && neverParseAsFraction))
{
srcIndex++;
- if (!TryParseUInt32D(text.Slice(srcIndex), out value, out int bytesConsumed))
+ if (!TryParseUInt32D(source.Slice(srcIndex), out value, out int bytesConsumed))
{
value = default;
return ComponentParseResult.ParseFailure;
@@ -205,7 +205,7 @@ namespace System.Buffers.Text
{
srcIndex++;
- if (!TryParseTimeSpanFraction(text.Slice(srcIndex), out value, out int bytesConsumed))
+ if (!TryParseTimeSpanFraction(source.Slice(srcIndex), out value, out int bytesConsumed))
{
value = default;
return ComponentParseResult.ParseFailure;
diff --git a/src/System.Memory/src/System/MemoryExtensions.Fast.cs b/src/System.Memory/src/System/MemoryExtensions.Fast.cs
deleted file mode 100644
index d232c7e13d..0000000000
--- a/src/System.Memory/src/System/MemoryExtensions.Fast.cs
+++ /dev/null
@@ -1,145 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Runtime.CompilerServices;
-
-namespace System
-{
- /// <summary>
- /// Extension methods for Span{T}, Memory{T}, and friends.
- /// </summary>
- public static partial class MemoryExtensions
- {
- /// <summary>
- /// Casts a Span of one primitive type <typeparamref name="T"/> to Span of bytes.
- /// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety.
- /// </summary>
- /// <param name="source">The source slice, of type <typeparamref name="T"/>.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when <typeparamref name="T"/> contains pointers.
- /// </exception>
- /// <exception cref="System.OverflowException">
- /// Thrown if the Length property of the new Span would exceed Int32.MaxValue.
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Span<byte> AsBytes<T>(this Span<T> source) where T : struct => Span.AsBytes(source);
-
- /// <summary>
- /// Casts a ReadOnlySpan of one primitive type <typeparamref name="T"/> to ReadOnlySpan of bytes.
- /// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety.
- /// </summary>
- /// <param name="source">The source slice, of type <typeparamref name="T"/>.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when <typeparamref name="T"/> contains pointers.
- /// </exception>
- /// <exception cref="System.OverflowException">
- /// Thrown if the Length property of the new Span would exceed Int32.MaxValue.
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ReadOnlySpan<byte> AsBytes<T>(this ReadOnlySpan<T> source) where T : struct => Span.AsBytes(source);
-
- /// <summary>
- /// Creates a new readonly span over the portion of the target string.
- /// </summary>
- /// <param name="text">The target string.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is null.</exception>
- public static ReadOnlySpan<char> AsReadOnlySpan(this string text) => Span.AsReadOnlySpan(text);
-
- /// <summary>
- /// Creates a new readonly span over the portion of the target string.
- /// </summary>
- /// <param name="text">The target string.</param>
- /// <param name="start">The index at which to begin this slice.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is null.</exception>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> index is not in range (&lt;0 or &gt;text.Length).
- /// </exception>
- public static ReadOnlySpan<char> AsReadOnlySpan(this string text, int start) => Span.AsReadOnlySpan(text, start);
-
- /// <summary>
- /// Creates a new readonly span over the portion of the target string.
- /// </summary>
- /// <param name="text">The target string.</param>
- /// <param name="start">The index at which to begin this slice.</param>
- /// <param name="length">The desired length for the slice (exclusive).</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is null.</exception>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> index or <paramref name="length"/> is not in range.
- /// </exception>
- public static ReadOnlySpan<char> AsReadOnlySpan(this string text, int start, int length) => Span.AsReadOnlySpan(text, start, length);
-
- /// <summary>Creates a new <see cref="ReadOnlyMemory{T}"/> over the portion of the target string.</summary>
- /// <param name="text">The target string.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is a null reference (Nothing in Visual Basic).</exception>
- public static ReadOnlyMemory<char> AsReadOnlyMemory(this string text) => Span.AsReadOnlyMemory(text);
-
- /// <summary>Creates a new <see cref="ReadOnlyMemory{T}"/> over the portion of the target string.</summary>
- /// <param name="text">The target string.</param>
- /// <param name="start">The index at which to begin this slice.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is a null reference (Nothing in Visual Basic).</exception>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> index is not in range (&lt;0 or &gt;text.Length).
- /// </exception>
- public static ReadOnlyMemory<char> AsReadOnlyMemory(this string text, int start) => Span.AsReadOnlyMemory(text, start);
-
- /// <summary>Creates a new <see cref="ReadOnlyMemory{T}"/> over the portion of the target string.</summary>
- /// <param name="text">The target string.</param>
- /// <param name="start">The index at which to begin this slice.</param>
- /// <param name="length">The desired length for the slice (exclusive).</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is a null reference (Nothing in Visual Basic).</exception>
- /// <exception cref="System.ArgumentOutOfRangeException">
- /// Thrown when the specified <paramref name="start"/> index or <paramref name="length"/> is not in range.
- /// </exception>
- public static ReadOnlyMemory<char> AsReadOnlyMemory(this string text, int start, int length) => Span.AsReadOnlyMemory(text, start, length);
-
- /// <summary>Attempts to get the underlying <see cref="string"/> from a <see cref="ReadOnlyMemory{T}"/>.</summary>
- /// <param name="readOnlyMemory">The memory that may be wrapping a <see cref="string"/> object.</param>
- /// <param name="text">The string.</param>
- /// <param name="start">The starting location in <paramref name="text"/>.</param>
- /// <param name="length">The number of items in <paramref name="text"/>.</param>
- /// <returns></returns>
- public static bool TryGetString(this ReadOnlyMemory<char> readOnlyMemory, out string text, out int start, out int length) =>
- Span.TryGetString(readOnlyMemory, out text, out start, out length);
-
- /// <summary>
- /// Casts a Span of one primitive type <typeparamref name="TFrom"/> to another primitive type <typeparamref name="TTo"/>.
- /// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety.
- /// </summary>
- /// <remarks>
- /// Supported only for platforms that support misaligned memory access.
- /// </remarks>
- /// <param name="source">The source slice, of type <typeparamref name="TFrom"/>.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when <typeparamref name="TFrom"/> or <typeparamref name="TTo"/> contains pointers.
- /// </exception>
- /// <exception cref="System.OverflowException">
- /// Thrown if the Length property of the new Span would exceed Int32.MaxValue.
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Span<TTo> NonPortableCast<TFrom, TTo>(this Span<TFrom> source)
- where TFrom : struct
- where TTo : struct
- => Span.NonPortableCast<TFrom, TTo>(source);
-
- /// <summary>
- /// Casts a ReadOnlySpan of one primitive type <typeparamref name="TFrom"/> to another primitive type <typeparamref name="TTo"/>.
- /// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety.
- /// </summary>
- /// <remarks>
- /// Supported only for platforms that support misaligned memory access.
- /// </remarks>
- /// <param name="source">The source slice, of type <typeparamref name="TFrom"/>.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when <typeparamref name="TFrom"/> or <typeparamref name="TTo"/> contains pointers.
- /// </exception>
- /// <exception cref="System.OverflowException">
- /// Thrown if the Length property of the new Span would exceed Int32.MaxValue.
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ReadOnlySpan<TTo> NonPortableCast<TFrom, TTo>(this ReadOnlySpan<TFrom> source)
- where TFrom : struct
- where TTo : struct
- => Span.NonPortableCast<TFrom, TTo>(source);
- }
-}
diff --git a/src/System.Memory/src/System/MemoryExtensions.Portable.cs b/src/System.Memory/src/System/MemoryExtensions.Portable.cs
index dc3ffad9ba..c33b508355 100644
--- a/src/System.Memory/src/System/MemoryExtensions.Portable.cs
+++ b/src/System.Memory/src/System/MemoryExtensions.Portable.cs
@@ -3,7 +3,9 @@
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
+using System.Globalization;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
namespace System
{
@@ -13,59 +15,274 @@ namespace System
public static partial class MemoryExtensions
{
/// <summary>
- /// Casts a Span of one primitive type <typeparamref name="T"/> to Span of bytes.
- /// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety.
+ /// Creates a new span over the portion of the target array.
/// </summary>
- /// <param name="source">The source slice, of type <typeparamref name="T"/>.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when <typeparamref name="T"/> contains pointers.
- /// </exception>
- /// <exception cref="System.OverflowException">
- /// Thrown if the Length property of the new Span would exceed Int32.MaxValue.
- /// </exception>
+ public static Span<T> AsSpan<T>(this T[] array, int start) => Span<T>.Create(array, start);
+
+ /// <summary>
+ /// Returns a value indicating whether the specified <paramref name="value"/> occurs within the <paramref name="span"/>.
+ /// <param name="span">The source span.</param>
+ /// <param name="value">The value to seek within the source span.</param>
+ /// <param name="comparisonType">One of the enumeration values that determines how the <paramref name="span"/> and <paramref name="value"/> are compared.</param>
+ /// </summary>
+ public static bool Contains(this ReadOnlySpan<char> span, ReadOnlySpan<char> value, StringComparison comparisonType)
+ => (IndexOf(span, value, comparisonType) >= 0);
+
+ /// <summary>
+ /// Determines whether this <paramref name="span"/> and the specified <paramref name="other"/> span have the same characters
+ /// when compared using the specified <paramref name="comparisonType"/> option.
+ /// <param name="span">The source span.</param>
+ /// <param name="other">The value to compare with the source span.</param>
+ /// <param name="comparisonType">One of the enumeration values that determines how the <paramref name="span"/> and <paramref name="other"/> are compared.</param>
+ /// </summary>
+ public static bool Equals(this ReadOnlySpan<char> span, ReadOnlySpan<char> other, StringComparison comparisonType)
+ {
+ if (comparisonType == StringComparison.Ordinal)
+ {
+ return span.SequenceEqual<char>(other);
+ }
+ else if (comparisonType == StringComparison.OrdinalIgnoreCase)
+ {
+ if (span.Length != other.Length)
+ return false;
+ return EqualsOrdinalIgnoreCase(span, other);
+ }
+
+ return span.ToString().Equals(other.ToString(), comparisonType);
+ }
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Span<byte> AsBytes<T>(this Span<T> source)
- where T : struct
+ private static bool EqualsOrdinalIgnoreCase(ReadOnlySpan<char> span, ReadOnlySpan<char> other)
{
- if (SpanHelpers.IsReferenceOrContainsReferences<T>())
- ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T));
+ Debug.Assert(span.Length == other.Length);
+ if (other.Length == 0) // span.Length == other.Length == 0
+ return true;
+ return (CompareToOrdinalIgnoreCase(span, other) == 0);
+ }
- int newLength = checked(source.Length * Unsafe.SizeOf<T>());
- return new Span<byte>(Unsafe.As<Pinnable<byte>>(source.Pinnable), source.ByteOffset, newLength);
+ /// <summary>
+ /// Compares the specified <paramref name="span"/> and <paramref name="other"/> using the specified <paramref name="comparisonType"/>,
+ /// and returns an integer that indicates their relative position in the sort order.
+ /// <param name="span">The source span.</param>
+ /// <param name="other">The value to compare with the source span.</param>
+ /// <param name="comparisonType">One of the enumeration values that determines how the <paramref name="span"/> and <paramref name="other"/> are compared.</param>
+ /// </summary>
+ public static int CompareTo(this ReadOnlySpan<char> span, ReadOnlySpan<char> other, StringComparison comparisonType)
+ {
+ if (comparisonType == StringComparison.Ordinal)
+ {
+ return span.SequenceCompareTo(other);
+ }
+ else if (comparisonType == StringComparison.OrdinalIgnoreCase)
+ {
+ return CompareToOrdinalIgnoreCase(span, other);
+ }
+
+ return string.Compare(span.ToString(), other.ToString(), comparisonType);
+ }
+
+ // Borrowed from https://github.com/dotnet/coreclr/blob/master/src/mscorlib/shared/System/Globalization/CompareInfo.cs#L539
+ private static unsafe int CompareToOrdinalIgnoreCase(ReadOnlySpan<char> strA, ReadOnlySpan<char> strB)
+ {
+ int length = Math.Min(strA.Length, strB.Length);
+ int range = length;
+
+ fixed (char* ap = &MemoryMarshal.GetReference(strA))
+ fixed (char* bp = &MemoryMarshal.GetReference(strB))
+ {
+ char* a = ap;
+ char* b = bp;
+
+ while (length != 0 && (*a <= 0x7F) && (*b <= 0x7F))
+ {
+ int charA = *a;
+ int charB = *b;
+
+ if (charA == charB)
+ {
+ a++; b++;
+ length--;
+ continue;
+ }
+
+ // uppercase both chars - notice that we need just one compare per char
+ if ((uint)(charA - 'a') <= 'z' - 'a') charA -= 0x20;
+ if ((uint)(charB - 'a') <= 'z' - 'a') charB -= 0x20;
+
+ // Return the (case-insensitive) difference between them.
+ if (charA != charB)
+ return charA - charB;
+
+ // Next char
+ a++; b++;
+ length--;
+ }
+
+ if (length == 0)
+ return strA.Length - strB.Length;
+
+ range -= length;
+
+ return string.Compare(strA.Slice(range).ToString(), strB.Slice(range).ToString(), StringComparison.OrdinalIgnoreCase);
+ }
+ }
+
+ /// <summary>
+ /// Reports the zero-based index of the first occurrence of the specified <paramref name="value"/> in the current <paramref name="span"/>.
+ /// <param name="span">The source span.</param>
+ /// <param name="value">The value to seek within the source span.</param>
+ /// <param name="comparisonType">One of the enumeration values that determines how the <paramref name="span"/> and <paramref name="value"/> are compared.</param>
+ /// </summary>
+ public static int IndexOf(this ReadOnlySpan<char> span, ReadOnlySpan<char> value, StringComparison comparisonType)
+ {
+ if (comparisonType == StringComparison.Ordinal)
+ {
+ return span.IndexOf<char>(value);
+ }
+
+ return span.ToString().IndexOf(value.ToString(), comparisonType);
}
/// <summary>
- /// Casts a ReadOnlySpan of one primitive type <typeparamref name="T"/> to ReadOnlySpan of bytes.
- /// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety.
+ /// Copies the characters from the source span into the destination, converting each character to lowercase,
+ /// using the casing rules of the specified culture.
/// </summary>
- /// <param name="source">The source slice, of type <typeparamref name="T"/>.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when <typeparamref name="T"/> contains pointers.
+ /// <param name="source">The source span.</param>
+ /// <param name="destination">The destination span which contains the transformed characters.</param>
+ /// <param name="culture">An object that supplies culture-specific casing rules.</param>
+ /// <remarks>If the source and destinations overlap, this method behaves as if the original values are in
+ /// a temporary location before the destination is overwritten.</remarks>
+ /// <exception cref="System.ArgumentNullException">
+ /// Thrown when <paramref name="culture"/> is null.
/// </exception>
- /// <exception cref="System.OverflowException">
- /// Thrown if the Length property of the new Span would exceed Int32.MaxValue.
+ public static int ToLower(this ReadOnlySpan<char> source, Span<char> destination, CultureInfo culture)
+ {
+ if (culture == null)
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.culture);
+
+ // Assuming that changing case does not affect length
+ if (destination.Length < source.Length)
+ return -1;
+
+ string sourceString = source.ToString();
+#if !netstandard11
+ string resultString = sourceString.ToLower(culture);
+#else
+ string resultString = culture.TextInfo.ToLower(sourceString);
+#endif
+ Debug.Assert(sourceString.Length == resultString.Length);
+ resultString.AsSpan().CopyTo(destination);
+ return source.Length;
+ }
+
+ /// <summary>
+ /// Copies the characters from the source span into the destination, converting each character to lowercase,
+ /// using the casing rules of the invariant culture.
+ /// </summary>
+ /// <param name="source">The source span.</param>
+ /// <param name="destination">The destination span which contains the transformed characters.</param>
+ /// <remarks>If the source and destinations overlap, this method behaves as if the original values are in
+ /// a temporary location before the destination is overwritten.</remarks>
+ public static int ToLowerInvariant(this ReadOnlySpan<char> source, Span<char> destination)
+ => ToLower(source, destination, CultureInfo.InvariantCulture);
+
+ /// <summary>
+ /// Copies the characters from the source span into the destination, converting each character to uppercase,
+ /// using the casing rules of the specified culture.
+ /// </summary>
+ /// <param name="source">The source span.</param>
+ /// <param name="destination">The destination span which contains the transformed characters.</param>
+ /// <param name="culture">An object that supplies culture-specific casing rules.</param>
+ /// <remarks>If the source and destinations overlap, this method behaves as if the original values are in
+ /// a temporary location before the destination is overwritten.</remarks>
+ /// <exception cref="System.ArgumentNullException">
+ /// Thrown when <paramref name="culture"/> is null.
/// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ReadOnlySpan<byte> AsBytes<T>(this ReadOnlySpan<T> source)
- where T : struct
+ public static int ToUpper(this ReadOnlySpan<char> source, Span<char> destination, CultureInfo culture)
{
- if (SpanHelpers.IsReferenceOrContainsReferences<T>())
- ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T));
+ if (culture == null)
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.culture);
- int newLength = checked(source.Length * Unsafe.SizeOf<T>());
- return new ReadOnlySpan<byte>(Unsafe.As<Pinnable<byte>>(source.Pinnable), source.ByteOffset, newLength);
+ // Assuming that changing case does not affect length
+ if (destination.Length < source.Length)
+ return -1;
+
+ string sourceString = source.ToString();
+#if !netstandard11
+ string resultString = sourceString.ToUpper(culture);
+#else
+ string resultString = culture.TextInfo.ToUpper(sourceString);
+#endif
+ Debug.Assert(sourceString.Length == resultString.Length);
+ resultString.AsSpan().CopyTo(destination);
+ return source.Length;
+ }
+
+ /// <summary>
+ /// Copies the characters from the source span into the destination, converting each character to uppercase
+ /// using the casing rules of the invariant culture.
+ /// </summary>
+ /// <param name="source">The source span.</param>
+ /// <param name="destination">The destination span which contains the transformed characters.</param>
+ /// <remarks>If the source and destinations overlap, this method behaves as if the original values are in
+ /// a temporary location before the destination is overwritten.</remarks>
+ public static int ToUpperInvariant(this ReadOnlySpan<char> source, Span<char> destination)
+ => ToUpper(source, destination, CultureInfo.InvariantCulture);
+
+ /// <summary>
+ /// Determines whether the end of the <paramref name="span"/> matches the specified <paramref name="value"/> when compared using the specified <paramref name="comparisonType"/> option.
+ /// </summary>
+ /// <param name="span">The source span.</param>
+ /// <param name="value">The sequence to compare to the end of the source span.</param>
+ /// <param name="comparisonType">One of the enumeration values that determines how the <paramref name="span"/> and <paramref name="value"/> are compared.</param>
+ public static bool EndsWith(this ReadOnlySpan<char> span, ReadOnlySpan<char> value, StringComparison comparisonType)
+ {
+ if (comparisonType == StringComparison.Ordinal)
+ {
+ return span.EndsWith<char>(value);
+ }
+ else if (comparisonType == StringComparison.OrdinalIgnoreCase)
+ {
+ return value.Length <= span.Length && EqualsOrdinalIgnoreCase(span.Slice(span.Length - value.Length), value);
+ }
+
+ string sourceString = span.ToString();
+ string valueString = value.ToString();
+ return sourceString.EndsWith(valueString, comparisonType);
+ }
+
+ /// <summary>
+ /// Determines whether the beginning of the <paramref name="span"/> matches the specified <paramref name="value"/> when compared using the specified <paramref name="comparisonType"/> option.
+ /// </summary>
+ /// <param name="span">The source span.</param>
+ /// <param name="value">The sequence to compare to the beginning of the source span.</param>
+ /// <param name="comparisonType">One of the enumeration values that determines how the <paramref name="span"/> and <paramref name="value"/> are compared.</param>
+ public static bool StartsWith(this ReadOnlySpan<char> span, ReadOnlySpan<char> value, StringComparison comparisonType)
+ {
+ if (comparisonType == StringComparison.Ordinal)
+ {
+ return span.StartsWith<char>(value);
+ }
+ else if (comparisonType == StringComparison.OrdinalIgnoreCase)
+ {
+ return value.Length <= span.Length && EqualsOrdinalIgnoreCase(span.Slice(0, value.Length), value);
+ }
+
+ string sourceString = span.ToString();
+ string valueString = value.ToString();
+ return sourceString.StartsWith(valueString, comparisonType);
}
/// <summary>
/// Creates a new readonly span over the portion of the target string.
/// </summary>
/// <param name="text">The target string.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is null.</exception>
+ /// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ReadOnlySpan<char> AsReadOnlySpan(this string text)
+ public static ReadOnlySpan<char> AsSpan(this string text)
{
if (text == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
+ return default;
return new ReadOnlySpan<char>(Unsafe.As<Pinnable<char>>(text), StringAdjustment, text.Length);
}
@@ -75,15 +292,19 @@ namespace System
/// </summary>
/// <param name="text">The target string.</param>
/// <param name="start">The index at which to begin this slice.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is null.</exception>
+ /// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
/// <exception cref="System.ArgumentOutOfRangeException">
/// Thrown when the specified <paramref name="start"/> index is not in range (&lt;0 or &gt;text.Length).
/// </exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ReadOnlySpan<char> AsReadOnlySpan(this string text, int start)
+ public static ReadOnlySpan<char> AsSpan(this string text, int start)
{
if (text == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
+ {
+ if (start != 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+ return default;
+ }
if ((uint)start > (uint)text.Length)
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
@@ -96,15 +317,19 @@ namespace System
/// <param name="text">The target string.</param>
/// <param name="start">The index at which to begin this slice.</param>
/// <param name="length">The desired length for the slice (exclusive).</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is null.</exception>
+ /// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
/// <exception cref="System.ArgumentOutOfRangeException">
/// Thrown when the specified <paramref name="start"/> index or <paramref name="length"/> is not in range.
/// </exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ReadOnlySpan<char> AsReadOnlySpan(this string text, int start, int length)
+ public static ReadOnlySpan<char> AsSpan(this string text, int start, int length)
{
if (text == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
+ {
+ if (start != 0 || length != 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+ return default;
+ }
if ((uint)start > (uint)text.Length || (uint)length > (uint)(text.Length - start))
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
@@ -113,11 +338,11 @@ namespace System
/// <summary>Creates a new <see cref="ReadOnlyMemory{T}"/> over the portion of the target string.</summary>
/// <param name="text">The target string.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is a null reference (Nothing in Visual Basic).</exception>
- public static ReadOnlyMemory<char> AsReadOnlyMemory(this string text)
+ /// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
+ public static ReadOnlyMemory<char> AsMemory(this string text)
{
if (text == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
+ return default;
return new ReadOnlyMemory<char>(text, 0, text.Length);
}
@@ -125,14 +350,18 @@ namespace System
/// <summary>Creates a new <see cref="ReadOnlyMemory{T}"/> over the portion of the target string.</summary>
/// <param name="text">The target string.</param>
/// <param name="start">The index at which to begin this slice.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is a null reference (Nothing in Visual Basic).</exception>
+ /// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
/// <exception cref="System.ArgumentOutOfRangeException">
/// Thrown when the specified <paramref name="start"/> index is not in range (&lt;0 or &gt;text.Length).
/// </exception>
- public static ReadOnlyMemory<char> AsReadOnlyMemory(this string text, int start)
+ public static ReadOnlyMemory<char> AsMemory(this string text, int start)
{
if (text == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
+ {
+ if (start != 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+ return default;
+ }
if ((uint)start > (uint)text.Length)
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
@@ -143,102 +372,24 @@ namespace System
/// <param name="text">The target string.</param>
/// <param name="start">The index at which to begin this slice.</param>
/// <param name="length">The desired length for the slice (exclusive).</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is a null reference (Nothing in Visual Basic).</exception>
+ /// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
/// <exception cref="System.ArgumentOutOfRangeException">
/// Thrown when the specified <paramref name="start"/> index or <paramref name="length"/> is not in range.
/// </exception>
- public static ReadOnlyMemory<char> AsReadOnlyMemory(this string text, int start, int length)
+ public static ReadOnlyMemory<char> AsMemory(this string text, int start, int length)
{
if (text == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
+ {
+ if (start != 0 || length != 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+ return default;
+ }
if ((uint)start > (uint)text.Length || (uint)length > (uint)(text.Length - start))
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
return new ReadOnlyMemory<char>(text, start, length);
}
- /// <summary>Attempts to get the underlying <see cref="string"/> from a <see cref="ReadOnlyMemory{T}"/>.</summary>
- /// <param name="readOnlyMemory">The memory that may be wrapping a <see cref="string"/> object.</param>
- /// <param name="text">The string.</param>
- /// <param name="start">The starting location in <paramref name="text"/>.</param>
- /// <param name="length">The number of items in <paramref name="text"/>.</param>
- /// <returns></returns>
- public static bool TryGetString(this ReadOnlyMemory<char> readOnlyMemory, out string text, out int start, out int length)
- {
- if (readOnlyMemory.GetObjectStartLength(out int offset, out int count) is string s)
- {
- text = s;
- start = offset;
- length = count;
- return true;
- }
- else
- {
- text = null;
- start = 0;
- length = 0;
- return false;
- }
- }
-
- /// <summary>
- /// Casts a Span of one primitive type <typeparamref name="TFrom"/> to another primitive type <typeparamref name="TTo"/>.
- /// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety.
- /// </summary>
- /// <remarks>
- /// Supported only for platforms that support misaligned memory access.
- /// </remarks>
- /// <param name="source">The source slice, of type <typeparamref name="TFrom"/>.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when <typeparamref name="TFrom"/> or <typeparamref name="TTo"/> contains pointers.
- /// </exception>
- /// <exception cref="System.OverflowException">
- /// Thrown if the Length property of the new Span would exceed Int32.MaxValue.
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Span<TTo> NonPortableCast<TFrom, TTo>(this Span<TFrom> source)
- where TFrom : struct
- where TTo : struct
- {
- if (SpanHelpers.IsReferenceOrContainsReferences<TFrom>())
- ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(TFrom));
-
- if (SpanHelpers.IsReferenceOrContainsReferences<TTo>())
- ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(TTo));
-
- int newLength = checked((int)((long)source.Length * Unsafe.SizeOf<TFrom>() / Unsafe.SizeOf<TTo>()));
- return new Span<TTo>(Unsafe.As<Pinnable<TTo>>(source.Pinnable), source.ByteOffset, newLength);
- }
-
- /// <summary>
- /// Casts a ReadOnlySpan of one primitive type <typeparamref name="TFrom"/> to another primitive type <typeparamref name="TTo"/>.
- /// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety.
- /// </summary>
- /// <remarks>
- /// Supported only for platforms that support misaligned memory access.
- /// </remarks>
- /// <param name="source">The source slice, of type <typeparamref name="TFrom"/>.</param>
- /// <exception cref="System.ArgumentException">
- /// Thrown when <typeparamref name="TFrom"/> or <typeparamref name="TTo"/> contains pointers.
- /// </exception>
- /// <exception cref="System.OverflowException">
- /// Thrown if the Length property of the new Span would exceed Int32.MaxValue.
- /// </exception>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ReadOnlySpan<TTo> NonPortableCast<TFrom, TTo>(this ReadOnlySpan<TFrom> source)
- where TFrom : struct
- where TTo : struct
- {
- if (SpanHelpers.IsReferenceOrContainsReferences<TFrom>())
- ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(TFrom));
-
- if (SpanHelpers.IsReferenceOrContainsReferences<TTo>())
- ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(TTo));
-
- int newLength = checked((int)((long)source.Length * Unsafe.SizeOf<TFrom>() / Unsafe.SizeOf<TTo>()));
- return new ReadOnlySpan<TTo>(Unsafe.As<Pinnable<TTo>>(source.Pinnable), source.ByteOffset, newLength);
- }
-
internal static readonly IntPtr StringAdjustment = MeasureStringAdjustment();
private static IntPtr MeasureStringAdjustment()
diff --git a/src/System.Memory/src/System/NUint.cs b/src/System.Memory/src/System/NUint.cs
new file mode 100644
index 0000000000..d7ec5d4f50
--- /dev/null
+++ b/src/System.Memory/src/System/NUint.cs
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.CompilerServices;
+
+namespace System
+{
+ //
+ // A makeshift native uint type for build configurations that don't build 32/64-bit specific binaries (and hence, can't alias them to UInt32/UInt64 via an ifdef.)
+ //
+ // Note that .NET Framework x86 JIT inliner is only capable of inlining of limited number of NUInt operations per method. Do not use this type heavily
+ // in code that needs to be fast on .NET Framework x86.
+ //
+ internal unsafe struct NUInt
+ {
+ private readonly void* _value;
+
+ private NUInt(uint value) => _value = (void*)value;
+ private NUInt(ulong value) => _value = (void*)value;
+
+ public static implicit operator NUInt(uint value) => new NUInt(value);
+ public static implicit operator IntPtr(NUInt value) => (IntPtr)value._value;
+
+ public static explicit operator NUInt(int value) => new NUInt((uint)value);
+
+ public static explicit operator void* (NUInt value) => value._value;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static NUInt operator *(NUInt left, NUInt right)
+ {
+ return (sizeof(IntPtr) == 4) ? new NUInt(((uint)left._value) * (uint)right._value) : new NUInt(((ulong)left._value) * (ulong)right._value);
+ }
+ }
+}
diff --git a/src/System.Memory/src/System/ReadOnlySpan.cs b/src/System.Memory/src/System/ReadOnlySpan.Portable.cs
index 4137248c8d..b1e4846676 100644
--- a/src/System.Memory/src/System/ReadOnlySpan.cs
+++ b/src/System.Memory/src/System/ReadOnlySpan.Portable.cs
@@ -21,21 +21,23 @@ namespace System
/// or native memory, or to memory allocated on the stack. It is type- and memory-safe.
/// </summary>
[DebuggerTypeProxy(typeof(SpanDebugView<>))]
- [DebuggerDisplay("{DebuggerDisplay,nq}")]
- public readonly ref struct ReadOnlySpan<T>
+ [DebuggerDisplay("{ToString(),raw}")]
+ public readonly ref partial struct ReadOnlySpan<T>
{
/// <summary>
/// Creates a new read-only span over the entirety of the target array.
/// </summary>
/// <param name="array">The target array.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
- /// reference (Nothing in Visual Basic).</exception>
+ /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
/// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpan(T[] array)
{
if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
+ {
+ this = default;
+ return; // returns default
+ }
_length = array.Length;
_pinnable = Unsafe.As<Pinnable<T>>(array);
@@ -49,8 +51,7 @@ namespace System
/// <param name="array">The target array.</param>
/// <param name="start">The index at which to begin the read-only span.</param>
/// <param name="length">The number of items in the read-only span.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
- /// reference (Nothing in Visual Basic).</exception>
+ /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
/// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// Thrown when the specified <paramref name="start"/> or end index is not in the range (&lt;0 or &gt;=Length).
@@ -59,7 +60,12 @@ namespace System
public ReadOnlySpan(T[] array, int start, int length)
{
if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
+ {
+ if (start != 0 || length != 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+ this = default;
+ return; // returns default
+ }
if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
@@ -96,26 +102,6 @@ namespace System
_byteOffset = new IntPtr(pointer);
}
- /// <summary>
- /// Create a new read-only span over a portion of a regular managed object. This can be useful
- /// if part of a managed object represents a "fixed array." This is dangerous because neither the
- /// <paramref name="length"/> is checked, nor <paramref name="obj"/> being null, nor the fact that
- /// "rawPointer" actually lies within <paramref name="obj"/>.
- /// </summary>
- /// <param name="obj">The managed object that contains the data to span over.</param>
- /// <param name="objectData">A reference to data within that object.</param>
- /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
-#if !MONO
- [EditorBrowsable(EditorBrowsableState.Never)]
-#endif
- public static ReadOnlySpan<T> DangerousCreate(object obj, ref T objectData, int length)
- {
- Pinnable<T> pinnable = Unsafe.As<Pinnable<T>>(obj);
- IntPtr byteOffset = Unsafe.ByteOffset<T>(ref pinnable.Data, ref objectData);
- return new ReadOnlySpan<T>(pinnable, byteOffset, length);
- }
-
// Constructor for internal use only.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ReadOnlySpan(Pinnable<T> pinnable, IntPtr byteOffset, int length)
@@ -127,19 +113,6 @@ namespace System
_byteOffset = byteOffset;
}
- //Debugger Display = {T[length]}
- private string DebuggerDisplay => string.Format("{{{0}[{1}]}}", typeof(T).Name, _length);
-
- /// <summary>
- /// The number of items in the read-only span.
- /// </summary>
- public int Length => _length;
-
- /// <summary>
- /// Returns true if Length is 0.
- /// </summary>
- public bool IsEmpty => _length == 0;
-
/// <summary>
/// Returns the specified element of the read-only span.
/// </summary>
@@ -215,53 +188,34 @@ namespace System
}
/// <summary>
- /// Returns false if left and right point at the same memory and have the same length. Note that
- /// this does *not* check to see if the *contents* are equal.
- /// </summary>
- public static bool operator !=(ReadOnlySpan<T> left, ReadOnlySpan<T> right) => !(left == right);
-
- /// <summary>
- /// This method is not supported as spans cannot be boxed. To compare two spans, use operator==.
- /// <exception cref="System.NotSupportedException">
- /// Always thrown by this method.
- /// </exception>
+ /// For <see cref="Span{Char}"/>, returns a new instance of string that represents the characters pointed to by the span.
+ /// Otherwise, returns a <see cref="String"/> with the name of the type and the number of elements.
/// </summary>
- [Obsolete("Equals() on ReadOnlySpan will always throw an exception. Use == instead.")]
-#if !MONO
- [EditorBrowsable(EditorBrowsableState.Never)]
-#endif
- public override bool Equals(object obj)
+ public override string ToString()
{
- throw new NotSupportedException(SR.CannotCallEqualsOnSpan);
- }
+ if (typeof(T) == typeof(char))
+ {
+ // If this wraps a string and represents the full length of the string, just return the wrapped string.
+ if (_byteOffset == MemoryExtensions.StringAdjustment)
+ {
+ object obj = Unsafe.As<object>(_pinnable); // minimize chances the compilers will optimize away the 'is' check
+ if (obj is string str && _length == str.Length)
+ {
+ return str;
+ }
+ }
- /// <summary>
- /// This method is not supported as spans cannot be boxed.
- /// <exception cref="System.NotSupportedException">
- /// Always thrown by this method.
- /// </exception>
- /// </summary>
- [Obsolete("GetHashCode() on ReadOnlySpan will always throw an exception.")]
-#if !MONO
- [EditorBrowsable(EditorBrowsableState.Never)]
-#endif
- public override int GetHashCode()
- {
- throw new NotSupportedException(SR.CannotCallGetHashCodeOnSpan);
+ // Otherwise, copy the data to a new string.
+ unsafe
+ {
+ fixed (char* src = &Unsafe.As<T, char>(ref DangerousGetPinnableReference()))
+ return new string(src, 0, _length);
+ }
+ }
+ return string.Format("System.ReadOnlySpan<{0}>[{1}]", typeof(T).Name, _length);
}
/// <summary>
- /// Defines an implicit conversion of an array to a <see cref="ReadOnlySpan{T}"/>
- /// </summary>
- public static implicit operator ReadOnlySpan<T>(T[] array) => array != null ? new ReadOnlySpan<T>(array) : default;
-
- /// <summary>
- /// Defines an implicit conversion of a <see cref="ArraySegment{T}"/> to a <see cref="ReadOnlySpan{T}"/>
- /// </summary>
- public static implicit operator ReadOnlySpan<T>(ArraySegment<T> arraySegment)
- => arraySegment.Array != null ? new ReadOnlySpan<T>(arraySegment.Array, arraySegment.Offset, arraySegment.Count) : default;
-
- /// <summary>
/// Forms a slice out of the given read-only span, beginning at 'start'.
/// </summary>
/// <param name="start">The index at which to begin this slice.</param>
@@ -313,11 +267,6 @@ namespace System
}
/// <summary>
- /// Returns a 0-length read-only span whose base is the null pointer.
- /// </summary>
- public static ReadOnlySpan<T> Empty => default(ReadOnlySpan<T>);
-
- /// <summary>
/// This method is obsolete, use System.Runtime.InteropServices.MemoryMarshal.GetReference instead.
/// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element
/// would have been stored. Such a reference can be used for pinning but must never be dereferenced.
@@ -334,61 +283,6 @@ namespace System
return ref Unsafe.AddByteOffset<T>(ref _pinnable.Data, _byteOffset);
}
- /// <summary>Gets an enumerator for this span.</summary>
- public Enumerator GetEnumerator() => new Enumerator(this);
-
- /// <summary>Enumerates the elements of a <see cref="ReadOnlySpan{T}"/>.</summary>
- public ref struct Enumerator
- {
- /// <summary>The span being enumerated.</summary>
- private readonly ReadOnlySpan<T> _span;
- /// <summary>The next index to yield.</summary>
- private int _index;
-
- /// <summary>Initialize the enumerator.</summary>
- /// <param name="span">The span to enumerate.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal Enumerator(ReadOnlySpan<T> span)
- {
- _span = span;
- _index = -1;
- }
-
- /// <summary>Advances the enumerator to the next element of the span.</summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool MoveNext()
- {
- int index = _index + 1;
- if (index < _span.Length)
- {
- _index = index;
- return true;
- }
-
- return false;
- }
-
- /// <summary>Gets the element at the current position of the enumerator.</summary>
- public ref readonly T Current
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get
- {
- // TODO https://github.com/dotnet/corefx/issues/24105:
- // Change this to simply be:
- // get => ref _span[_index];
- // once ReadOnlySpan<T>'s indexer returns ref readonly.
-
- if ((uint)_index >= (uint)_span.Length)
- {
- ThrowHelper.ThrowIndexOutOfRangeException();
- }
-
- return ref Unsafe.Add(ref _span.DangerousGetPinnableReference(), _index);
- }
- }
- }
-
// These expose the internal representation for Span-related apis use only.
internal Pinnable<T> Pinnable => _pinnable;
internal IntPtr ByteOffset => _byteOffset;
diff --git a/src/System.Memory/src/System/Runtime/InteropServices/MemoryMarshal.Portable.cs b/src/System.Memory/src/System/Runtime/InteropServices/MemoryMarshal.Portable.cs
new file mode 100644
index 0000000000..caedd29ceb
--- /dev/null
+++ b/src/System.Memory/src/System/Runtime/InteropServices/MemoryMarshal.Portable.cs
@@ -0,0 +1,145 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.CompilerServices;
+
+namespace System.Runtime.InteropServices
+{
+ /// <summary>
+ /// Provides a collection of methods for interoperating with <see cref="Memory{T}"/>, <see cref="ReadOnlyMemory{T}"/>,
+ /// <see cref="Span{T}"/>, and <see cref="ReadOnlySpan{T}"/>.
+ /// </summary>
+ public static partial class MemoryMarshal
+ {
+ /// <summary>
+ /// Casts a Span of one primitive type <typeparamref name="T"/> to Span of bytes.
+ /// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety.
+ /// </summary>
+ /// <param name="span">The source slice, of type <typeparamref name="T"/>.</param>
+ /// <exception cref="System.ArgumentException">
+ /// Thrown when <typeparamref name="T"/> contains pointers.
+ /// </exception>
+ /// <exception cref="System.OverflowException">
+ /// Thrown if the Length property of the new Span would exceed Int32.MaxValue.
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Span<byte> AsBytes<T>(Span<T> span)
+ where T : struct
+ {
+ if (SpanHelpers.IsReferenceOrContainsReferences<T>())
+ ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T));
+
+ int newLength = checked(span.Length * Unsafe.SizeOf<T>());
+ return new Span<byte>(Unsafe.As<Pinnable<byte>>(span.Pinnable), span.ByteOffset, newLength);
+ }
+
+ /// <summary>
+ /// Casts a ReadOnlySpan of one primitive type <typeparamref name="T"/> to ReadOnlySpan of bytes.
+ /// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety.
+ /// </summary>
+ /// <param name="span">The source slice, of type <typeparamref name="T"/>.</param>
+ /// <exception cref="System.ArgumentException">
+ /// Thrown when <typeparamref name="T"/> contains pointers.
+ /// </exception>
+ /// <exception cref="System.OverflowException">
+ /// Thrown if the Length property of the new Span would exceed Int32.MaxValue.
+ /// </exception>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ReadOnlySpan<byte> AsBytes<T>(ReadOnlySpan<T> span)
+ where T : struct
+ {
+ if (SpanHelpers.IsReferenceOrContainsReferences<T>())
+ ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T));
+
+ int newLength = checked(span.Length * Unsafe.SizeOf<T>());
+ return new ReadOnlySpan<byte>(Unsafe.As<Pinnable<byte>>(span.Pinnable), span.ByteOffset, newLength);
+ }
+
+ /// <summary>Creates a <see cref="Memory{T}"/> from a <see cref="ReadOnlyMemory{T}"/>.</summary>
+ /// <param name="memory">The <see cref="ReadOnlyMemory{T}"/>.</param>
+ /// <returns>A <see cref="Memory{T}"/> representing the same memory as the <see cref="ReadOnlyMemory{T}"/>, but writable.</returns>
+ /// <remarks>
+ /// <see cref="AsMemory{T}(ReadOnlyMemory{T})"/> must be used with extreme caution. <see cref="ReadOnlyMemory{T}"/> is used
+ /// to represent immutable data and other memory that is not meant to be written to; <see cref="Memory{T}"/> instances created
+ /// by <see cref="AsMemory{T}(ReadOnlyMemory{T})"/> should not be written to. The method exists to enable variables typed
+ /// as <see cref="Memory{T}"/> but only used for reading to store a <see cref="ReadOnlyMemory{T}"/>.
+ /// </remarks>
+ public static Memory<T> AsMemory<T>(ReadOnlyMemory<T> memory) =>
+ Unsafe.As<ReadOnlyMemory<T>, Memory<T>>(ref memory);
+
+ /// <summary>
+ /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element
+ /// would have been stored. Such a reference can be used for pinning but must never be dereferenced.
+ /// </summary>
+ public static ref T GetReference<T>(Span<T> span)
+ {
+ if (span.Pinnable == null)
+ unsafe { return ref Unsafe.AsRef<T>(span.ByteOffset.ToPointer()); }
+ else
+ return ref Unsafe.AddByteOffset<T>(ref span.Pinnable.Data, span.ByteOffset);
+ }
+
+ /// <summary>
+ /// Returns a reference to the 0th element of the ReadOnlySpan. If the Span is empty, returns a reference to the location where the 0th element
+ /// would have been stored. Such a reference can be used for pinning but must never be dereferenced.
+ /// </summary>
+ public static ref T GetReference<T>(ReadOnlySpan<T> span)
+ {
+ if (span.Pinnable == null)
+ unsafe { return ref Unsafe.AsRef<T>(span.ByteOffset.ToPointer()); }
+ else
+ return ref Unsafe.AddByteOffset<T>(ref span.Pinnable.Data, span.ByteOffset);
+ }
+
+ /// <summary>
+ /// Casts a Span of one primitive type <typeparamref name="TFrom"/> to another primitive type <typeparamref name="TTo"/>.
+ /// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety.
+ /// </summary>
+ /// <remarks>
+ /// Supported only for platforms that support misaligned memory access.
+ /// </remarks>
+ /// <param name="span">The source slice, of type <typeparamref name="TFrom"/>.</param>
+ /// <exception cref="System.ArgumentException">
+ /// Thrown when <typeparamref name="TFrom"/> or <typeparamref name="TTo"/> contains pointers.
+ /// </exception>
+ public static Span<TTo> Cast<TFrom, TTo>(Span<TFrom> span)
+ where TFrom : struct
+ where TTo : struct
+ {
+ if (SpanHelpers.IsReferenceOrContainsReferences<TFrom>())
+ ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(TFrom));
+
+ if (SpanHelpers.IsReferenceOrContainsReferences<TTo>())
+ ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(TTo));
+
+ int newLength = checked((int)((long)span.Length * Unsafe.SizeOf<TFrom>() / Unsafe.SizeOf<TTo>()));
+ return new Span<TTo>(Unsafe.As<Pinnable<TTo>>(span.Pinnable), span.ByteOffset, newLength);
+ }
+
+ /// <summary>
+ /// Casts a ReadOnlySpan of one primitive type <typeparamref name="TFrom"/> to another primitive type <typeparamref name="TTo"/>.
+ /// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety.
+ /// </summary>
+ /// <remarks>
+ /// Supported only for platforms that support misaligned memory access.
+ /// </remarks>
+ /// <param name="span">The source slice, of type <typeparamref name="TFrom"/>.</param>
+ /// <exception cref="System.ArgumentException">
+ /// Thrown when <typeparamref name="TFrom"/> or <typeparamref name="TTo"/> contains pointers.
+ /// </exception>
+ public static ReadOnlySpan<TTo> Cast<TFrom, TTo>(ReadOnlySpan<TFrom> span)
+ where TFrom : struct
+ where TTo : struct
+ {
+ if (SpanHelpers.IsReferenceOrContainsReferences<TFrom>())
+ ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(TFrom));
+
+ if (SpanHelpers.IsReferenceOrContainsReferences<TTo>())
+ ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(TTo));
+
+ int newLength = checked((int)((long)span.Length * Unsafe.SizeOf<TFrom>() / Unsafe.SizeOf<TTo>()));
+ return new ReadOnlySpan<TTo>(Unsafe.As<Pinnable<TTo>>(span.Pinnable), span.ByteOffset, newLength);
+ }
+ }
+}
diff --git a/src/System.Memory/src/System/Runtime/InteropServices/SequenceMarshal.cs b/src/System.Memory/src/System/Runtime/InteropServices/SequenceMarshal.cs
new file mode 100644
index 0000000000..e3710b1493
--- /dev/null
+++ b/src/System.Memory/src/System/Runtime/InteropServices/SequenceMarshal.cs
@@ -0,0 +1,63 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+
+namespace System.Runtime.InteropServices
+{
+ /// <summary>
+ /// Provides a collection of methods for interoperating with <see cref="ReadOnlySequence{T}"/>
+ /// </summary>
+ public static partial class SequenceMarshal
+ {
+ /// <summary>
+ /// Get <see cref="ReadOnlySequenceSegment{T}"/> from the underlying <see cref="ReadOnlySequence{T}"/>.
+ /// If unable to get the <see cref="ReadOnlySequenceSegment{T}"/>, return false.
+ /// </summary>
+ public static bool TryGetReadOnlySequenceSegment<T>(ReadOnlySequence<T> sequence,
+ out ReadOnlySequenceSegment<T> startSegment,
+ out int startIndex,
+ out ReadOnlySequenceSegment<T> endSegment,
+ out int endIndex)
+ {
+ return sequence.TryGetReadOnlySequenceSegment(out startSegment, out startIndex, out endSegment, out endIndex);
+ }
+
+ /// <summary>
+ /// Get an array segment from the underlying <see cref="ReadOnlySequence{T}"/>.
+ /// If unable to get the array segment, return false with a default array segment.
+ /// </summary>
+ public static bool TryGetArray<T>(ReadOnlySequence<T> sequence, out ArraySegment<T> segment)
+ {
+ return sequence.TryGetArray(out segment);
+ }
+
+ /// <summary>
+ /// Get <see cref="OwnedMemory{T}"/> from the underlying <see cref="ReadOnlySequence{T}"/>.
+ /// If unable to get the <see cref="OwnedMemory{T}"/>, return false.
+ /// </summary>
+ public static bool TryGetOwnedMemory<T>(ReadOnlySequence<T> sequence, out OwnedMemory<T> ownedMemory, out int start, out int length)
+ {
+ return sequence.TryGetOwnedMemory(out ownedMemory, out start, out length);
+ }
+
+ /// <summary>
+ /// Get <see cref="ReadOnlyMemory{T}"/> from the underlying <see cref="ReadOnlySequence{T}"/>.
+ /// If unable to get the <see cref="ReadOnlyMemory{T}"/>, return false.
+ /// </summary>
+ public static bool TryGetReadOnlyMemory<T>(ReadOnlySequence<T> sequence, out ReadOnlyMemory<T> memory)
+ {
+ return sequence.TryGetReadOnlyMemory(out memory);
+ }
+
+ /// <summary>
+ /// Get <see cref="string"/> from the underlying <see cref="ReadOnlySequence{T}"/>.
+ /// If unable to get the <see cref="string"/>, return false.
+ /// </summary>
+ internal static bool TryGetString(ReadOnlySequence<char> sequence, out string text, out int start, out int length)
+ {
+ return sequence.TryGetString(out text, out start, out length);
+ }
+ }
+}
diff --git a/src/System.Memory/src/System/SequencePosition.cs b/src/System.Memory/src/System/SequencePosition.cs
new file mode 100644
index 0000000000..a94c486486
--- /dev/null
+++ b/src/System.Memory/src/System/SequencePosition.cs
@@ -0,0 +1,61 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Numerics.Hashing;
+using System.ComponentModel;
+
+namespace System
+{
+ /// <summary>
+ /// Represents position in non-contiguous set of memory.
+ /// Properties of this type should not be interpreted by anything but the type that created it.
+ /// </summary>
+ public readonly struct SequencePosition : IEquatable<SequencePosition>
+ {
+ private readonly object _object;
+ private readonly int _integer;
+
+ /// <summary>
+ /// Creates new <see cref="SequencePosition"/>
+ /// </summary>
+ public SequencePosition(object @object, int integer)
+ {
+ _object = @object;
+ _integer = integer;
+ }
+
+ /// <summary>
+ /// Returns object part of this <see cref="SequencePosition"/>
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public object GetObject() => _object;
+
+ /// <summary>
+ /// Returns integer part of this <see cref="SequencePosition"/>
+ /// </summary>
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public int GetInteger() => _integer;
+
+ /// <summary>
+ /// Returns true if left and right point at the same segment and have the same index.
+ /// </summary>
+ public static bool operator ==(SequencePosition left, SequencePosition right) => left._integer == right._integer && left._object == right._object;
+
+ /// <summary>
+ /// Returns true if left and right do not point at the same segment and have the same index.
+ /// </summary>
+ public static bool operator !=(SequencePosition left, SequencePosition right) => !(left == right);
+
+ /// <inheritdoc />
+ public bool Equals(SequencePosition other) => this == other;
+
+ /// <inheritdoc />
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override bool Equals(object obj) => obj is SequencePosition other && this == other;
+
+ /// <inheritdoc />
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public override int GetHashCode() => HashHelpers.Combine(_object?.GetHashCode() ?? 0, _integer);
+ }
+}
diff --git a/src/System.Memory/src/System/Span.cs b/src/System.Memory/src/System/Span.Portable.cs
index bd0060d6ad..e054c7a85b 100644
--- a/src/System.Memory/src/System/Span.cs
+++ b/src/System.Memory/src/System/Span.Portable.cs
@@ -21,21 +21,23 @@ namespace System
/// or native memory, or to memory allocated on the stack. It is type- and memory-safe.
/// </summary>
[DebuggerTypeProxy(typeof(SpanDebugView<>))]
- [DebuggerDisplay("{DebuggerDisplay,nq}")]
- public readonly ref struct Span<T>
+ [DebuggerDisplay("{ToString(),raw}")]
+ public readonly ref partial struct Span<T>
{
/// <summary>
/// Creates a new span over the entirety of the target array.
/// </summary>
/// <param name="array">The target array.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
- /// reference (Nothing in Visual Basic).</exception>
+ /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
/// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span(T[] array)
{
if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
+ {
+ this = default;
+ return; // returns default
+ }
if (default(T) == null && array.GetType() != typeof(T[]))
ThrowHelper.ThrowArrayTypeMismatchException();
@@ -44,6 +46,28 @@ namespace System
_byteOffset = SpanHelpers.PerTypeValues<T>.ArrayAdjustment;
}
+ // This is a constructor that takes an array and start but not length. The reason we expose it as a static method as a constructor
+ // is to mirror the actual api shape. This overload of the constructor was removed from the api surface area due to possible
+ // confusion with other overloads that take an int parameter that don't represent a start index.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static Span<T> Create(T[] array, int start)
+ {
+ if (array == null)
+ {
+ if (start != 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+ return default;
+ }
+ if (default(T) == null && array.GetType() != typeof(T[]))
+ ThrowHelper.ThrowArrayTypeMismatchException();
+ if ((uint)start > (uint)array.Length)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+
+ IntPtr byteOffset = SpanHelpers.PerTypeValues<T>.ArrayAdjustment.Add<T>(start);
+ int length = array.Length - start;
+ return new Span<T>(pinnable: Unsafe.As<Pinnable<T>>(array), byteOffset: byteOffset, length: length);
+ }
+
/// <summary>
/// Creates a new span over the portion of the target array beginning
/// at 'start' index and ending at 'end' index (exclusive).
@@ -51,8 +75,7 @@ namespace System
/// <param name="array">The target array.</param>
/// <param name="start">The index at which to begin the span.</param>
/// <param name="length">The number of items in the span.</param>
- /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
- /// reference (Nothing in Visual Basic).</exception>
+ /// <remarks>Returns default when <paramref name="array"/> is null.</remarks>
/// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// Thrown when the specified <paramref name="start"/> or end index is not in the range (&lt;0 or &gt;=Length).
@@ -61,7 +84,12 @@ namespace System
public Span(T[] array, int start, int length)
{
if (array == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
+ {
+ if (start != 0 || length != 0)
+ ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
+ this = default;
+ return; // returns default
+ }
if (default(T) == null && array.GetType() != typeof(T[]))
ThrowHelper.ThrowArrayTypeMismatchException();
if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
@@ -100,26 +128,6 @@ namespace System
_byteOffset = new IntPtr(pointer);
}
- /// <summary>
- /// Create a new span over a portion of a regular managed object. This can be useful
- /// if part of a managed object represents a "fixed array." This is dangerous because neither the
- /// <paramref name="length"/> is checked, nor <paramref name="obj"/> being null, nor the fact that
- /// "rawPointer" actually lies within <paramref name="obj"/>.
- /// </summary>
- /// <param name="obj">The managed object that contains the data to span over.</param>
- /// <param name="objectData">A reference to data within that object.</param>
- /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
-#if !MONO
- [EditorBrowsable(EditorBrowsableState.Never)]
-#endif
- public static Span<T> DangerousCreate(object obj, ref T objectData, int length)
- {
- Pinnable<T> pinnable = Unsafe.As<Pinnable<T>>(obj);
- IntPtr byteOffset = Unsafe.ByteOffset<T>(ref pinnable.Data, ref objectData);
- return new Span<T>(pinnable, byteOffset, length);
- }
-
// Constructor for internal use only.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Span(Pinnable<T> pinnable, IntPtr byteOffset, int length)
@@ -131,19 +139,6 @@ namespace System
_byteOffset = byteOffset;
}
- //Debugger Display = {T[length]}
- private string DebuggerDisplay => string.Format("{{{0}[{1}]}}", typeof(T).Name, _length);
-
- /// <summary>
- /// The number of items in the span.
- /// </summary>
- public int Length => _length;
-
- /// <summary>
- /// Returns true if Length is 0.
- /// </summary>
- public bool IsEmpty => _length == 0;
-
/// <summary>
/// Returns a reference to specified element of the Span.
/// </summary>
@@ -322,58 +317,28 @@ namespace System
}
/// <summary>
- /// Returns false if left and right point at the same memory and have the same length. Note that
- /// this does *not* check to see if the *contents* are equal.
- /// </summary>
- public static bool operator !=(Span<T> left, Span<T> right) => !(left == right);
-
- /// <summary>
- /// This method is not supported as spans cannot be boxed. To compare two spans, use operator==.
- /// <exception cref="System.NotSupportedException">
- /// Always thrown by this method.
- /// </exception>
+ /// Defines an implicit conversion of a <see cref="Span{T}"/> to a <see cref="ReadOnlySpan{T}"/>
/// </summary>
- [Obsolete("Equals() on Span will always throw an exception. Use == instead.")]
-#if !MONO
- [EditorBrowsable(EditorBrowsableState.Never)]
-#endif
- public override bool Equals(object obj)
- {
- throw new NotSupportedException(SR.CannotCallEqualsOnSpan);
- }
+ public static implicit operator ReadOnlySpan<T>(Span<T> span) => new ReadOnlySpan<T>(span._pinnable, span._byteOffset, span._length);
/// <summary>
- /// This method is not supported as spans cannot be boxed.
- /// <exception cref="System.NotSupportedException">
- /// Always thrown by this method.
- /// </exception>
+ /// For <see cref="Span{Char}"/>, returns a new instance of string that represents the characters pointed to by the span.
+ /// Otherwise, returns a <see cref="String"/> with the name of the type and the number of elements.
/// </summary>
- [Obsolete("GetHashCode() on Span will always throw an exception.")]
-#if !MONO
- [EditorBrowsable(EditorBrowsableState.Never)]
-#endif
- public override int GetHashCode()
+ public override string ToString()
{
- throw new NotSupportedException(SR.CannotCallGetHashCodeOnSpan);
+ if (typeof(T) == typeof(char))
+ {
+ unsafe
+ {
+ fixed (char* src = &Unsafe.As<T, char>(ref DangerousGetPinnableReference()))
+ return new string(src, 0, _length);
+ }
+ }
+ return string.Format("System.Span<{0}>[{1}]", typeof(T).Name, _length);
}
/// <summary>
- /// Defines an implicit conversion of an array to a <see cref="Span{T}"/>
- /// </summary>
- public static implicit operator Span<T>(T[] array) => array != null ? new Span<T>(array) : default;
-
- /// <summary>
- /// Defines an implicit conversion of a <see cref="ArraySegment{T}"/> to a <see cref="Span{T}"/>
- /// </summary>
- public static implicit operator Span<T>(ArraySegment<T> arraySegment)
- => arraySegment.Array != null ? new Span<T>(arraySegment.Array, arraySegment.Offset, arraySegment.Count) : default;
-
- /// <summary>
- /// Defines an implicit conversion of a <see cref="Span{T}"/> to a <see cref="ReadOnlySpan{T}"/>
- /// </summary>
- public static implicit operator ReadOnlySpan<T>(Span<T> span) => new ReadOnlySpan<T>(span._pinnable, span._byteOffset, span._length);
-
- /// <summary>
/// Forms a slice out of the given span, beginning at 'start'.
/// </summary>
/// <param name="start">The index at which to begin this slice.</param>
@@ -425,11 +390,6 @@ namespace System
}
/// <summary>
- /// Returns a 0-length span whose base is the null pointer.
- /// </summary>
- public static Span<T> Empty => default(Span<T>);
-
- /// <summary>
/// This method is obsolete, use System.Runtime.InteropServices.MemoryMarshal.GetReference instead.
/// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element
/// would have been stored. Such a reference can be used for pinning but must never be dereferenced.
@@ -446,48 +406,6 @@ namespace System
return ref Unsafe.AddByteOffset<T>(ref _pinnable.Data, _byteOffset);
}
- /// <summary>Gets an enumerator for this span.</summary>
- public Enumerator GetEnumerator() => new Enumerator(this);
-
- /// <summary>Enumerates the elements of a <see cref="Span{T}"/>.</summary>
- public ref struct Enumerator
- {
- /// <summary>The span being enumerated.</summary>
- private readonly Span<T> _span;
- /// <summary>The next index to yield.</summary>
- private int _index;
-
- /// <summary>Initialize the enumerator.</summary>
- /// <param name="span">The span to enumerate.</param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal Enumerator(Span<T> span)
- {
- _span = span;
- _index = -1;
- }
-
- /// <summary>Advances the enumerator to the next element of the span.</summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool MoveNext()
- {
- int index = _index + 1;
- if (index < _span.Length)
- {
- _index = index;
- return true;
- }
-
- return false;
- }
-
- /// <summary>Gets the element at the current position of the enumerator.</summary>
- public ref T Current
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get => ref _span[_index];
- }
- }
-
// These expose the internal representation for Span-related apis use only.
internal Pinnable<T> Pinnable => _pinnable;
internal IntPtr ByteOffset => _byteOffset;
diff --git a/src/System.Memory/src/System/SpanDebugView.cs b/src/System.Memory/src/System/SpanDebugView.cs
deleted file mode 100644
index 2633028322..0000000000
--- a/src/System.Memory/src/System/SpanDebugView.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-using System.Reflection;
-using System.Runtime.CompilerServices;
-
-namespace System
-{
- internal sealed class SpanDebugView<T>
- {
- private readonly T[] _pinnable;
- private readonly IntPtr _byteOffset;
- private readonly int _length;
-
- public SpanDebugView(Span<T> collection)
- {
- _pinnable = (T[])(object)collection.Pinnable;
- _byteOffset = collection.ByteOffset;
- _length = collection.Length;
- }
-
- public SpanDebugView(ReadOnlySpan<T> collection)
- {
- _pinnable = (T[])(object)collection.Pinnable;
- _byteOffset = collection.ByteOffset;
- _length = collection.Length;
- }
-
- [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
- public unsafe T[] Items
- {
- get
- {
- int elementSize = typeof(T).GetTypeInfo().IsValueType ? Unsafe.SizeOf<T>() : IntPtr.Size;//Workaround to VIL bug where Unsafe.SizeOf<T> where T is a class, returns the size of its fields instead of IntPtr.Size
- T[] result = new T[_length];
-
- if (_pinnable == null)
- {
- byte* source = (byte*)_byteOffset.ToPointer();
-
- for (int i = 0; i < result.Length; i++)
- {
- result[i] = Unsafe.Read<T>(source);
- source = source + elementSize;
- }
- }
- else
- {
- long byteOffsetInt = _byteOffset.ToInt64();
- long arrayAdjustment = SpanHelpers.PerTypeValues<T>.ArrayAdjustment.ToInt64();
- int sourceIndex = (int)((byteOffsetInt - arrayAdjustment) / elementSize);
-
- Array.Copy(_pinnable, sourceIndex, result, 0, _length);
- }
-
- return result;
- }
- }
- }
-}
diff --git a/src/System.Memory/src/System/SpanHelpers.Clear.cs b/src/System.Memory/src/System/SpanHelpers.Clear.cs
deleted file mode 100644
index 34676e5611..0000000000
--- a/src/System.Memory/src/System/SpanHelpers.Clear.cs
+++ /dev/null
@@ -1,156 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Runtime.InteropServices;
-using System.Runtime.CompilerServices;
-
-#if !netstandard
-using Internal.Runtime.CompilerServices;
-#endif
-
-namespace System
-{
- internal static partial class SpanHelpers
- {
- public unsafe static void ClearLessThanPointerSized(byte* ptr, UIntPtr byteLength)
- {
- if (sizeof(UIntPtr) == sizeof(uint))
- {
- Unsafe.InitBlockUnaligned(ptr, 0, (uint)byteLength);
- }
- else
- {
- // PERF: Optimize for common case of length <= uint.MaxValue
- ulong bytesRemaining = (ulong)byteLength;
- uint bytesToClear = (uint)(bytesRemaining & uint.MaxValue);
- Unsafe.InitBlockUnaligned(ptr, 0, bytesToClear);
- bytesRemaining -= bytesToClear;
- ptr += bytesToClear;
- // Clear any bytes > uint.MaxValue
- while (bytesRemaining > 0)
- {
- bytesToClear = (bytesRemaining >= uint.MaxValue) ? uint.MaxValue : (uint)bytesRemaining;
- Unsafe.InitBlockUnaligned(ptr, 0, bytesToClear);
- ptr += bytesToClear;
- bytesRemaining -= bytesToClear;
- }
- }
- }
-
- public static unsafe void ClearLessThanPointerSized(ref byte b, UIntPtr byteLength)
- {
- if (sizeof(UIntPtr) == sizeof(uint))
- {
- Unsafe.InitBlockUnaligned(ref b, 0, (uint)byteLength);
- }
- else
- {
- // PERF: Optimize for common case of length <= uint.MaxValue
- ulong bytesRemaining = (ulong)byteLength;
- uint bytesToClear = (uint)(bytesRemaining & uint.MaxValue);
- Unsafe.InitBlockUnaligned(ref b, 0, bytesToClear);
- bytesRemaining -= bytesToClear;
- long byteOffset = bytesToClear;
- // Clear any bytes > uint.MaxValue
- while (bytesRemaining > 0)
- {
- bytesToClear = (bytesRemaining >= uint.MaxValue) ? uint.MaxValue : (uint)bytesRemaining;
- ref byte bOffset = ref Unsafe.Add(ref b, (IntPtr)byteOffset);
- Unsafe.InitBlockUnaligned(ref bOffset, 0, bytesToClear);
- byteOffset += bytesToClear;
- bytesRemaining -= bytesToClear;
- }
- }
- }
-
- public unsafe static void ClearPointerSizedWithoutReferences(ref byte b, UIntPtr byteLength)
- {
- // TODO: Perhaps do switch casing to improve small size perf
-
- var i = IntPtr.Zero;
- while (i.LessThanEqual(byteLength - sizeof(Reg64)))
- {
- Unsafe.As<byte, Reg64>(ref Unsafe.Add<byte>(ref b, i)) = default(Reg64);
- i += sizeof(Reg64);
- }
- if (i.LessThanEqual(byteLength - sizeof(Reg32)))
- {
- Unsafe.As<byte, Reg32>(ref Unsafe.Add<byte>(ref b, i)) = default(Reg32);
- i += sizeof(Reg32);
- }
- if (i.LessThanEqual(byteLength - sizeof(Reg16)))
- {
- Unsafe.As<byte, Reg16>(ref Unsafe.Add<byte>(ref b, i)) = default(Reg16);
- i += sizeof(Reg16);
- }
- if (i.LessThanEqual(byteLength - sizeof(long)))
- {
- Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, i)) = 0;
- i += sizeof(long);
- }
- // JIT: Should elide this if 64-bit
- if (sizeof(IntPtr) == sizeof(int))
- {
- if (i.LessThanEqual(byteLength - sizeof(int)))
- {
- Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, i)) = 0;
- i += sizeof(int);
- }
- }
- }
-
- public static void ClearPointerSizedWithReferences(ref IntPtr ip, UIntPtr pointerSizeLength)
- {
- // TODO: Perhaps do switch casing to improve small size perf
-
- var i = IntPtr.Zero;
- var n = IntPtr.Zero;
- while ((n = i + 8).LessThanEqual(pointerSizeLength))
- {
- Unsafe.Add<IntPtr>(ref ip, i + 0) = default(IntPtr);
- Unsafe.Add<IntPtr>(ref ip, i + 1) = default(IntPtr);
- Unsafe.Add<IntPtr>(ref ip, i + 2) = default(IntPtr);
- Unsafe.Add<IntPtr>(ref ip, i + 3) = default(IntPtr);
- Unsafe.Add<IntPtr>(ref ip, i + 4) = default(IntPtr);
- Unsafe.Add<IntPtr>(ref ip, i + 5) = default(IntPtr);
- Unsafe.Add<IntPtr>(ref ip, i + 6) = default(IntPtr);
- Unsafe.Add<IntPtr>(ref ip, i + 7) = default(IntPtr);
- i = n;
- }
- if ((n = i + 4).LessThanEqual(pointerSizeLength))
- {
- Unsafe.Add<IntPtr>(ref ip, i + 0) = default(IntPtr);
- Unsafe.Add<IntPtr>(ref ip, i + 1) = default(IntPtr);
- Unsafe.Add<IntPtr>(ref ip, i + 2) = default(IntPtr);
- Unsafe.Add<IntPtr>(ref ip, i + 3) = default(IntPtr);
- i = n;
- }
- if ((n = i + 2).LessThanEqual(pointerSizeLength))
- {
- Unsafe.Add<IntPtr>(ref ip, i + 0) = default(IntPtr);
- Unsafe.Add<IntPtr>(ref ip, i + 1) = default(IntPtr);
- i = n;
- }
- if ((i + 1).LessThanEqual(pointerSizeLength))
- {
- Unsafe.Add<IntPtr>(ref ip, i) = default(IntPtr);
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private unsafe static bool LessThanEqual(this IntPtr index, UIntPtr length)
- {
- return (sizeof(UIntPtr) == sizeof(uint))
- ? (int)index <= (int)length
- : (long)index <= (long)length;
- }
-
- [StructLayout(LayoutKind.Sequential, Size = 64)]
- private struct Reg64 { }
- [StructLayout(LayoutKind.Sequential, Size = 32)]
- private struct Reg32 { }
- [StructLayout(LayoutKind.Sequential, Size = 16)]
- private struct Reg16 { }
- }
-}
diff --git a/src/System.Memory/src/System/SpanHelpers.cs b/src/System.Memory/src/System/SpanHelpers.cs
index 4289fa95e3..e2d154d8da 100644
--- a/src/System.Memory/src/System/SpanHelpers.cs
+++ b/src/System.Memory/src/System/SpanHelpers.cs
@@ -156,6 +156,146 @@ namespace System
return false;
}
+ public unsafe static void ClearLessThanPointerSized(byte* ptr, UIntPtr byteLength)
+ {
+ if (sizeof(UIntPtr) == sizeof(uint))
+ {
+ Unsafe.InitBlockUnaligned(ptr, 0, (uint)byteLength);
+ }
+ else
+ {
+ // PERF: Optimize for common case of length <= uint.MaxValue
+ ulong bytesRemaining = (ulong)byteLength;
+ uint bytesToClear = (uint)(bytesRemaining & uint.MaxValue);
+ Unsafe.InitBlockUnaligned(ptr, 0, bytesToClear);
+ bytesRemaining -= bytesToClear;
+ ptr += bytesToClear;
+ // Clear any bytes > uint.MaxValue
+ while (bytesRemaining > 0)
+ {
+ bytesToClear = (bytesRemaining >= uint.MaxValue) ? uint.MaxValue : (uint)bytesRemaining;
+ Unsafe.InitBlockUnaligned(ptr, 0, bytesToClear);
+ ptr += bytesToClear;
+ bytesRemaining -= bytesToClear;
+ }
+ }
+ }
+
+ public static unsafe void ClearLessThanPointerSized(ref byte b, UIntPtr byteLength)
+ {
+ if (sizeof(UIntPtr) == sizeof(uint))
+ {
+ Unsafe.InitBlockUnaligned(ref b, 0, (uint)byteLength);
+ }
+ else
+ {
+ // PERF: Optimize for common case of length <= uint.MaxValue
+ ulong bytesRemaining = (ulong)byteLength;
+ uint bytesToClear = (uint)(bytesRemaining & uint.MaxValue);
+ Unsafe.InitBlockUnaligned(ref b, 0, bytesToClear);
+ bytesRemaining -= bytesToClear;
+ long byteOffset = bytesToClear;
+ // Clear any bytes > uint.MaxValue
+ while (bytesRemaining > 0)
+ {
+ bytesToClear = (bytesRemaining >= uint.MaxValue) ? uint.MaxValue : (uint)bytesRemaining;
+ ref byte bOffset = ref Unsafe.Add(ref b, (IntPtr)byteOffset);
+ Unsafe.InitBlockUnaligned(ref bOffset, 0, bytesToClear);
+ byteOffset += bytesToClear;
+ bytesRemaining -= bytesToClear;
+ }
+ }
+ }
+
+ public unsafe static void ClearPointerSizedWithoutReferences(ref byte b, UIntPtr byteLength)
+ {
+ // TODO: Perhaps do switch casing to improve small size perf
+
+ var i = IntPtr.Zero;
+ while (i.LessThanEqual(byteLength - sizeof(Reg64)))
+ {
+ Unsafe.As<byte, Reg64>(ref Unsafe.Add<byte>(ref b, i)) = default(Reg64);
+ i += sizeof(Reg64);
+ }
+ if (i.LessThanEqual(byteLength - sizeof(Reg32)))
+ {
+ Unsafe.As<byte, Reg32>(ref Unsafe.Add<byte>(ref b, i)) = default(Reg32);
+ i += sizeof(Reg32);
+ }
+ if (i.LessThanEqual(byteLength - sizeof(Reg16)))
+ {
+ Unsafe.As<byte, Reg16>(ref Unsafe.Add<byte>(ref b, i)) = default(Reg16);
+ i += sizeof(Reg16);
+ }
+ if (i.LessThanEqual(byteLength - sizeof(long)))
+ {
+ Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, i)) = 0;
+ i += sizeof(long);
+ }
+ // JIT: Should elide this if 64-bit
+ if (sizeof(IntPtr) == sizeof(int))
+ {
+ if (i.LessThanEqual(byteLength - sizeof(int)))
+ {
+ Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, i)) = 0;
+ i += sizeof(int);
+ }
+ }
+ }
+
+ public static void ClearPointerSizedWithReferences(ref IntPtr ip, UIntPtr pointerSizeLength)
+ {
+ // TODO: Perhaps do switch casing to improve small size perf
+
+ var i = IntPtr.Zero;
+ var n = IntPtr.Zero;
+ while ((n = i + 8).LessThanEqual(pointerSizeLength))
+ {
+ Unsafe.Add<IntPtr>(ref ip, i + 0) = default(IntPtr);
+ Unsafe.Add<IntPtr>(ref ip, i + 1) = default(IntPtr);
+ Unsafe.Add<IntPtr>(ref ip, i + 2) = default(IntPtr);
+ Unsafe.Add<IntPtr>(ref ip, i + 3) = default(IntPtr);
+ Unsafe.Add<IntPtr>(ref ip, i + 4) = default(IntPtr);
+ Unsafe.Add<IntPtr>(ref ip, i + 5) = default(IntPtr);
+ Unsafe.Add<IntPtr>(ref ip, i + 6) = default(IntPtr);
+ Unsafe.Add<IntPtr>(ref ip, i + 7) = default(IntPtr);
+ i = n;
+ }
+ if ((n = i + 4).LessThanEqual(pointerSizeLength))
+ {
+ Unsafe.Add<IntPtr>(ref ip, i + 0) = default(IntPtr);
+ Unsafe.Add<IntPtr>(ref ip, i + 1) = default(IntPtr);
+ Unsafe.Add<IntPtr>(ref ip, i + 2) = default(IntPtr);
+ Unsafe.Add<IntPtr>(ref ip, i + 3) = default(IntPtr);
+ i = n;
+ }
+ if ((n = i + 2).LessThanEqual(pointerSizeLength))
+ {
+ Unsafe.Add<IntPtr>(ref ip, i + 0) = default(IntPtr);
+ Unsafe.Add<IntPtr>(ref ip, i + 1) = default(IntPtr);
+ i = n;
+ }
+ if ((i + 1).LessThanEqual(pointerSizeLength))
+ {
+ Unsafe.Add<IntPtr>(ref ip, i) = default(IntPtr);
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private unsafe static bool LessThanEqual(this IntPtr index, UIntPtr length)
+ {
+ return (sizeof(UIntPtr) == sizeof(uint))
+ ? (int)index <= (int)length
+ : (long)index <= (long)length;
+ }
+
+ [StructLayout(LayoutKind.Sequential, Size = 64)]
+ private struct Reg64 { }
+ [StructLayout(LayoutKind.Sequential, Size = 32)]
+ private struct Reg32 { }
+ [StructLayout(LayoutKind.Sequential, Size = 16)]
+ private struct Reg16 { }
+
public static class PerTypeValues<T>
{
//
diff --git a/src/System.Memory/src/System/ThrowHelper.cs b/src/System.Memory/src/System/ThrowHelper.cs
index 81d3f793c9..d663fe5bf4 100644
--- a/src/System.Memory/src/System/ThrowHelper.cs
+++ b/src/System.Memory/src/System/ThrowHelper.cs
@@ -60,13 +60,37 @@ namespace System
[MethodImpl(MethodImplOptions.NoInlining)]
private static Exception CreateArgumentOutOfRangeException_SymbolDoesNotFit() { return new ArgumentOutOfRangeException("symbol", SR.Argument_BadFormatSpecifier); }
+ internal static void ThrowInvalidOperationException() { throw CreateInvalidOperationException(); }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static Exception CreateInvalidOperationException() { return new InvalidOperationException(); }
+
internal static void ThrowInvalidOperationException_OutstandingReferences() { throw CreateInvalidOperationException_OutstandingReferences(); }
[MethodImpl(MethodImplOptions.NoInlining)]
private static Exception CreateInvalidOperationException_OutstandingReferences() { return new InvalidOperationException(SR.OutstandingReferences); }
- internal static void ThrowObjectDisposedException_MemoryDisposed(string objectName) { throw CreateObjectDisposedException_MemoryDisposed(objectName); }
+ internal static void ThrowInvalidOperationException_UnexpectedSegmentType() { throw CreateInvalidOperationException_UnexpectedSegmentType(); }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static Exception CreateInvalidOperationException_UnexpectedSegmentType() { return new InvalidOperationException(SR.UnexpectedSegmentType); }
+
+ internal static void ThrowInvalidOperationException_EndPositionNotReached() { throw CreateInvalidOperationException_EndPositionNotReached(); }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static Exception CreateInvalidOperationException_EndPositionNotReached() { return new InvalidOperationException(SR.EndPositionNotReached); }
+
+ internal static void ThrowArgumentOutOfRangeException_PositionOutOfRange() { throw CreateArgumentOutOfRangeException_PositionOutOfRange(); }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static Exception CreateArgumentOutOfRangeException_PositionOutOfRange() { return new ArgumentOutOfRangeException("position"); }
+
+ internal static void ThrowArgumentOutOfRangeException_CountOutOfRange() { throw CreateArgumentOutOfRangeException_CountOutOfRange(); }
[MethodImpl(MethodImplOptions.NoInlining)]
- private static Exception CreateObjectDisposedException_MemoryDisposed(string objectName) { return new ObjectDisposedException(objectName, SR.MemoryDisposed); }
+ private static Exception CreateArgumentOutOfRangeException_CountOutOfRange() { return new ArgumentOutOfRangeException("count"); }
+
+ internal static void ThrowObjectDisposedException_ArrayMemoryPoolBuffer() { throw CreateObjectDisposedException_ArrayMemoryPoolBuffer(); }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static Exception CreateObjectDisposedException_ArrayMemoryPoolBuffer() { return new ObjectDisposedException("ArrayMemoryPoolBuffer"); }
+
+ internal static void ThrowObjectDisposedException_MemoryDisposed() { throw CreateObjectDisposedException_MemoryDisposed(); }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static Exception CreateObjectDisposedException_MemoryDisposed() { return new ObjectDisposedException("OwnedMemory<T>", SR.MemoryDisposed); }
internal static void ThrowFormatException_BadFormatSpecifier() { throw CreateFormatException_BadFormatSpecifier(); }
[MethodImpl(MethodImplOptions.NoInlining)]
@@ -76,6 +100,10 @@ namespace System
[MethodImpl(MethodImplOptions.NoInlining)]
private static Exception CreateArgumentException_OverlapAlignmentMismatch() { return new ArgumentException(SR.Argument_OverlapAlignmentMismatch); }
+ internal static void ThrowNotSupportedException() { throw CreateThrowNotSupportedException(); }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static Exception CreateThrowNotSupportedException() { return new NotSupportedException(); }
+
//
// Enable use of ThrowHelper from TryFormat() routines without introducing dozens of non-code-coveraged "bytesWritten = 0; return false" boilerplate.
//
@@ -96,19 +124,69 @@ namespace System
ThrowHelper.ThrowFormatException_BadFormatSpecifier();
return false;
}
+
+ //
+ // ReadOnlySequence .ctor validation Throws coalesced to enable inlining of the .ctor
+ //
+ public static void ThrowArgumentValidationException<T>(ReadOnlySequenceSegment<T> startSegment, int startIndex, ReadOnlySequenceSegment<T> endSegment)
+ => throw CreateArgumentValidationException(startSegment, startIndex, endSegment);
+
+ private static Exception CreateArgumentValidationException<T>(ReadOnlySequenceSegment<T> startSegment, int startIndex, ReadOnlySequenceSegment<T> endSegment)
+ {
+ if (startSegment == null)
+ return CreateArgumentNullException(ExceptionArgument.startSegment);
+ else if (endSegment == null)
+ return CreateArgumentNullException(ExceptionArgument.endSegment);
+ else if ((uint)startSegment.Memory.Length < (uint)startIndex)
+ return CreateArgumentOutOfRangeException(ExceptionArgument.startIndex);
+ else
+ return CreateArgumentOutOfRangeException(ExceptionArgument.endIndex);
+ }
+
+ public static void ThrowArgumentValidationException(Array array, int start)
+ => throw CreateArgumentValidationException(array, start);
+
+ private static Exception CreateArgumentValidationException(Array array, int start)
+ {
+ if (array == null)
+ return CreateArgumentNullException(ExceptionArgument.array);
+ else if ((uint)start > (uint)array.Length)
+ return CreateArgumentOutOfRangeException(ExceptionArgument.start);
+ else
+ return CreateArgumentOutOfRangeException(ExceptionArgument.length);
+ }
+
+ public static void ThrowArgumentValidationException<T>(OwnedMemory<T> ownedMemory, int start)
+ => throw CreateArgumentValidationException(ownedMemory, start);
+
+ private static Exception CreateArgumentValidationException<T>(OwnedMemory<T> ownedMemory, int start)
+ {
+ if (ownedMemory == null)
+ return CreateArgumentNullException(ExceptionArgument.ownedMemory);
+ else if ((uint)start > (uint)ownedMemory.Length)
+ return CreateArgumentOutOfRangeException(ExceptionArgument.start);
+ else
+ return CreateArgumentOutOfRangeException(ExceptionArgument.length);
+ }
}
#if !MONO
internal enum ExceptionArgument
{
- array,
length,
start,
- text,
- obj,
- ownedMemory,
- pointer,
+ minimumBufferSize,
+ byteOffset,
comparable,
- comparer
+ comparer,
+ destination,
+ offset,
+ startSegment,
+ endSegment,
+ startIndex,
+ endIndex,
+ array,
+ ownedMemory,
+ culture
}
#endif
}
diff --git a/src/System.Memory/tests/Base64/Base64DecoderUnitTests.cs b/src/System.Memory/tests/Base64/Base64DecoderUnitTests.cs
index 15a6733060..3c159ddee4 100644
--- a/src/System.Memory/tests/Base64/Base64DecoderUnitTests.cs
+++ b/src/System.Memory/tests/Base64/Base64DecoderUnitTests.cs
@@ -410,7 +410,7 @@ namespace System.Buffers.Text.Tests
for (int value = 0; value < 256; value++)
{
- Span<byte> sourceBytes = testBytes.AsSpan().Slice(0, value + 1);
+ Span<byte> sourceBytes = testBytes.AsSpan(0, value + 1);
Span<byte> buffer = new byte[Base64.GetMaxEncodedToUtf8Length(sourceBytes.Length)];
Assert.Equal(OperationStatus.Done, Base64.EncodeToUtf8(sourceBytes, buffer, out int consumed, out int written));
diff --git a/src/System.Memory/tests/Base64/Base64EncoderUnitTests.cs b/src/System.Memory/tests/Base64/Base64EncoderUnitTests.cs
index c3f5335106..1628f17257 100644
--- a/src/System.Memory/tests/Base64/Base64EncoderUnitTests.cs
+++ b/src/System.Memory/tests/Base64/Base64EncoderUnitTests.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.SpanTests;
using System.Text;
using Xunit;
@@ -20,7 +21,7 @@ namespace System.Buffers.Text.Tests
for (int value = 0; value < 256; value++)
{
- Span<byte> sourceBytes = bytes.AsSpan().Slice(0, value + 1);
+ Span<byte> sourceBytes = bytes.AsSpan(0, value + 1);
Span<byte> encodedBytes = new byte[Base64.GetMaxEncodedToUtf8Length(sourceBytes.Length)];
Assert.Equal(OperationStatus.Done, Base64.EncodeToUtf8(sourceBytes, encodedBytes, out int consumed, out int encodedBytesCount));
Assert.Equal(sourceBytes.Length, consumed);
@@ -75,20 +76,44 @@ namespace System.Buffers.Text.Tests
[OuterLoop]
public void EncodeTooLargeSpan()
{
+
+ if (IntPtr.Size < 8)
+ return;
+
+ bool allocatedFirst = false;
+ bool allocatedSecond = false;
+ IntPtr memBlockFirst = IntPtr.Zero;
+ IntPtr memBlockSecond = IntPtr.Zero;
+
// int.MaxValue - (int.MaxValue % 4) => 2147483644, largest multiple of 4 less than int.MaxValue
// CLR default limit of 2 gigabytes (GB).
+ // 1610612734, larger than MaximumEncodeLength, requires output buffer of size 2147483648 (which is > int.MaxValue)
+ const int sourceCount = (int.MaxValue >> 2) * 3 + 1;
+ const int encodedCount = 2000000000;
+
try
{
- // 1610612734, larger than MaximumEncodeLength, requires output buffer of size 2147483648 (which is > int.MaxValue)
- Span<byte> source = new byte[(int.MaxValue >> 2) * 3 + 1];
- Span<byte> encodedBytes = new byte[2000000000];
- Assert.Equal(OperationStatus.DestinationTooSmall, Base64.EncodeToUtf8(source, encodedBytes, out int consumed, out int encodedBytesCount));
- Assert.Equal((encodedBytes.Length >> 2) * 3, consumed); // encoding 1500000000 bytes fits into buffer of 2000000000 bytes
- Assert.Equal(encodedBytes.Length, encodedBytesCount);
+ allocatedFirst = AllocationHelper.TryAllocNative((IntPtr)sourceCount, out memBlockFirst);
+ allocatedSecond = AllocationHelper.TryAllocNative((IntPtr)encodedCount, out memBlockSecond);
+ if (allocatedFirst && allocatedSecond)
+ {
+ unsafe
+ {
+ var source = new Span<byte>(memBlockFirst.ToPointer(), sourceCount);
+ var encodedBytes = new Span<byte>(memBlockSecond.ToPointer(), encodedCount);
+
+ Assert.Equal(OperationStatus.DestinationTooSmall, Base64.EncodeToUtf8(source, encodedBytes, out int consumed, out int encodedBytesCount));
+ Assert.Equal((encodedBytes.Length >> 2) * 3, consumed); // encoding 1500000000 bytes fits into buffer of 2000000000 bytes
+ Assert.Equal(encodedBytes.Length, encodedBytesCount);
+ }
+ }
}
- catch (OutOfMemoryException)
+ finally
{
- // do nothing
+ if (allocatedFirst)
+ AllocationHelper.ReleaseNative(ref memBlockFirst);
+ if (allocatedSecond)
+ AllocationHelper.ReleaseNative(ref memBlockSecond);
}
}
diff --git a/src/System.Memory/tests/Binary/BinaryReaderUnitTests.cs b/src/System.Memory/tests/Binary/BinaryReaderUnitTests.cs
index 7a3bc0d4c0..92db3ff275 100644
--- a/src/System.Memory/tests/Binary/BinaryReaderUnitTests.cs
+++ b/src/System.Memory/tests/Binary/BinaryReaderUnitTests.cs
@@ -24,12 +24,12 @@ namespace System.Buffers.Binary.Tests
span = new Span<byte>(&value, 8);
}
- Assert.Equal<byte>(0x11, ReadMachineEndian<byte>(span));
- Assert.True(TryReadMachineEndian(span, out byte byteValue));
+ Assert.Equal<byte>(0x11, MemoryMarshal.Read<byte>(span));
+ Assert.True(MemoryMarshal.TryRead(span, out byte byteValue));
Assert.Equal(0x11, byteValue);
- Assert.Equal<sbyte>(0x11, ReadMachineEndian<sbyte>(span));
- Assert.True(TryReadMachineEndian(span, out byte sbyteValue));
+ Assert.Equal<sbyte>(0x11, MemoryMarshal.Read<sbyte>(span));
+ Assert.True(MemoryMarshal.TryRead(span, out byte sbyteValue));
Assert.Equal(0x11, byteValue);
Assert.Equal<ushort>(0x1122, ReadUInt16BigEndian(span));
@@ -93,12 +93,12 @@ namespace System.Buffers.Binary.Tests
span = new ReadOnlySpan<byte>(&value, 8);
}
- Assert.Equal<byte>(0x11, ReadMachineEndian<byte>(span));
- Assert.True(TryReadMachineEndian(span, out byte byteValue));
+ Assert.Equal<byte>(0x11, MemoryMarshal.Read<byte>(span));
+ Assert.True(MemoryMarshal.TryRead(span, out byte byteValue));
Assert.Equal(0x11, byteValue);
- Assert.Equal<sbyte>(0x11, ReadMachineEndian<sbyte>(span));
- Assert.True(TryReadMachineEndian(span, out byte sbyteValue));
+ Assert.Equal<sbyte>(0x11, MemoryMarshal.Read<sbyte>(span));
+ Assert.True(MemoryMarshal.TryRead(span, out byte sbyteValue));
Assert.Equal(0x11, byteValue);
Assert.Equal<ushort>(0x1122, ReadUInt16BigEndian(span));
@@ -155,27 +155,27 @@ namespace System.Buffers.Binary.Tests
{
Span<byte> span = new byte[] { 1 };
- Assert.Equal<byte>(1, ReadMachineEndian<byte>(span));
- Assert.True(TryReadMachineEndian(span, out byte byteValue));
+ Assert.Equal<byte>(1, MemoryMarshal.Read<byte>(span));
+ Assert.True(MemoryMarshal.TryRead(span, out byte byteValue));
Assert.Equal(1, byteValue);
- TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => ReadMachineEndian<short>(_span));
- Assert.False(TryReadMachineEndian(span, out short shortValue));
- TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => ReadMachineEndian<int>(_span));
- Assert.False(TryReadMachineEndian(span, out int intValue));
- TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => ReadMachineEndian<long>(_span));
- Assert.False(TryReadMachineEndian(span, out long longValue));
+ TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => MemoryMarshal.Read<short>(_span));
+ Assert.False(MemoryMarshal.TryRead(span, out short shortValue));
+ TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => MemoryMarshal.Read<int>(_span));
+ Assert.False(MemoryMarshal.TryRead(span, out int intValue));
+ TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => MemoryMarshal.Read<long>(_span));
+ Assert.False(MemoryMarshal.TryRead(span, out long longValue));
- TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => ReadMachineEndian<ushort>(_span));
- Assert.False(TryReadMachineEndian(span, out ushort ushortValue));
- TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => ReadMachineEndian<uint>(_span));
- Assert.False(TryReadMachineEndian(span, out uint uintValue));
- TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => ReadMachineEndian<ulong>(_span));
- Assert.False(TryReadMachineEndian(span, out ulong ulongValue));
+ TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => MemoryMarshal.Read<ushort>(_span));
+ Assert.False(MemoryMarshal.TryRead(span, out ushort ushortValue));
+ TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => MemoryMarshal.Read<uint>(_span));
+ Assert.False(MemoryMarshal.TryRead(span, out uint uintValue));
+ TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => MemoryMarshal.Read<ulong>(_span));
+ Assert.False(MemoryMarshal.TryRead(span, out ulong ulongValue));
Span<byte> largeSpan = new byte[100];
- TestHelpers.AssertThrows<ArgumentException, byte>(largeSpan, (_span) => ReadMachineEndian<TestHelpers.TestValueTypeWithReference>(_span));
- TestHelpers.AssertThrows<ArgumentException, byte>(largeSpan, (_span) => TryReadMachineEndian(_span, out TestHelpers.TestValueTypeWithReference stringValue));
+ TestHelpers.AssertThrows<ArgumentException, byte>(largeSpan, (_span) => MemoryMarshal.Read<TestHelpers.TestValueTypeWithReference>(_span));
+ TestHelpers.AssertThrows<ArgumentException, byte>(largeSpan, (_span) => MemoryMarshal.TryRead(_span, out TestHelpers.TestValueTypeWithReference stringValue));
}
[Fact]
@@ -183,27 +183,27 @@ namespace System.Buffers.Binary.Tests
{
ReadOnlySpan<byte> span = new byte[] { 1 };
- Assert.Equal<byte>(1, ReadMachineEndian<byte>(span));
- Assert.True(TryReadMachineEndian(span, out byte byteValue));
+ Assert.Equal<byte>(1, MemoryMarshal.Read<byte>(span));
+ Assert.True(MemoryMarshal.TryRead(span, out byte byteValue));
Assert.Equal(1, byteValue);
- TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => ReadMachineEndian<short>(_span));
- Assert.False(TryReadMachineEndian(span, out short shortValue));
- TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => ReadMachineEndian<int>(_span));
- Assert.False(TryReadMachineEndian(span, out int intValue));
- TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => ReadMachineEndian<long>(_span));
- Assert.False(TryReadMachineEndian(span, out long longValue));
+ TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => MemoryMarshal.Read<short>(_span));
+ Assert.False(MemoryMarshal.TryRead(span, out short shortValue));
+ TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => MemoryMarshal.Read<int>(_span));
+ Assert.False(MemoryMarshal.TryRead(span, out int intValue));
+ TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => MemoryMarshal.Read<long>(_span));
+ Assert.False(MemoryMarshal.TryRead(span, out long longValue));
- TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => ReadMachineEndian<ushort>(_span));
- Assert.False(TryReadMachineEndian(span, out ushort ushortValue));
- TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => ReadMachineEndian<uint>(_span));
- Assert.False(TryReadMachineEndian(span, out uint uintValue));
- TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => ReadMachineEndian<ulong>(_span));
- Assert.False(TryReadMachineEndian(span, out ulong ulongValue));
+ TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => MemoryMarshal.Read<ushort>(_span));
+ Assert.False(MemoryMarshal.TryRead(span, out ushort ushortValue));
+ TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => MemoryMarshal.Read<uint>(_span));
+ Assert.False(MemoryMarshal.TryRead(span, out uint uintValue));
+ TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => MemoryMarshal.Read<ulong>(_span));
+ Assert.False(MemoryMarshal.TryRead(span, out ulong ulongValue));
ReadOnlySpan<byte> largeSpan = new byte[100];
- TestHelpers.AssertThrows<ArgumentException, byte>(largeSpan, (_span) => ReadMachineEndian<TestHelpers.TestValueTypeWithReference>(_span));
- TestHelpers.AssertThrows<ArgumentException, byte>(largeSpan, (_span) => TryReadMachineEndian(_span, out TestHelpers.TestValueTypeWithReference stringValue));
+ TestHelpers.AssertThrows<ArgumentException, byte>(largeSpan, (_span) => MemoryMarshal.Read<TestHelpers.TestValueTypeWithReference>(_span));
+ TestHelpers.AssertThrows<ArgumentException, byte>(largeSpan, (_span) => MemoryMarshal.TryRead(_span, out TestHelpers.TestValueTypeWithReference stringValue));
}
[Fact]
@@ -375,7 +375,7 @@ namespace System.Buffers.Binary.Tests
ReadOnlySpan<byte> readOnlySpanBE = new ReadOnlySpan<byte>(spanBE.ToArray());
- TestHelpers.TestStructExplicit readStructAndReverse = ReadMachineEndian<TestHelpers.TestStructExplicit>(spanBE);
+ TestHelpers.TestStructExplicit readStructAndReverse = MemoryMarshal.Read<TestHelpers.TestStructExplicit>(spanBE);
if (BitConverter.IsLittleEndian)
{
readStructAndReverse.S0 = ReverseEndianness(readStructAndReverse.S0);
@@ -408,7 +408,7 @@ namespace System.Buffers.Binary.Tests
UL1 = ReadUInt64BigEndian(spanBE.Slice(48))
};
- TestHelpers.TestStructExplicit readStructAndReverseFromReadOnlySpan = ReadMachineEndian<TestHelpers.TestStructExplicit>(readOnlySpanBE);
+ TestHelpers.TestStructExplicit readStructAndReverseFromReadOnlySpan = MemoryMarshal.Read<TestHelpers.TestStructExplicit>(readOnlySpanBE);
if (BitConverter.IsLittleEndian)
{
readStructAndReverseFromReadOnlySpan.S0 = ReverseEndianness(readStructAndReverseFromReadOnlySpan.S0);
diff --git a/src/System.Memory/tests/Binary/BinaryWriterUnitTests.cs b/src/System.Memory/tests/Binary/BinaryWriterUnitTests.cs
index efd6d2be2f..766fc521f2 100644
--- a/src/System.Memory/tests/Binary/BinaryWriterUnitTests.cs
+++ b/src/System.Memory/tests/Binary/BinaryWriterUnitTests.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Runtime.InteropServices;
using Xunit;
using static System.Buffers.Binary.BinaryPrimitives;
@@ -18,51 +19,51 @@ namespace System.Buffers.Binary.Tests
Span<byte> span = new byte[8];
byte byteValue = 0x11;
- WriteMachineEndian<byte>(span, ref byteValue);
+ MemoryMarshal.Write<byte>(span, ref byteValue);
TestHelpers.Validate<byte>(span, byteValue);
- Assert.True(TryWriteMachineEndian<byte>(span, ref byteValue));
+ Assert.True(MemoryMarshal.TryWrite<byte>(span, ref byteValue));
TestHelpers.Validate<byte>(span, byteValue);
sbyte sbyteValue = 0x11;
- WriteMachineEndian<sbyte>(span, ref sbyteValue);
+ MemoryMarshal.Write<sbyte>(span, ref sbyteValue);
TestHelpers.Validate<sbyte>(span, sbyteValue);
- Assert.True(TryWriteMachineEndian<sbyte>(span, ref sbyteValue));
+ Assert.True(MemoryMarshal.TryWrite<sbyte>(span, ref sbyteValue));
TestHelpers.Validate<sbyte>(span, sbyteValue);
ushort ushortValue = 0x1122;
- WriteMachineEndian<ushort>(span, ref ushortValue);
+ MemoryMarshal.Write<ushort>(span, ref ushortValue);
TestHelpers.Validate<ushort>(span, ushortValue);
- Assert.True(TryWriteMachineEndian<ushort>(span, ref ushortValue));
+ Assert.True(MemoryMarshal.TryWrite<ushort>(span, ref ushortValue));
TestHelpers.Validate<ushort>(span, ushortValue);
uint uintValue = 0x11223344;
- WriteMachineEndian<uint>(span, ref uintValue);
+ MemoryMarshal.Write<uint>(span, ref uintValue);
TestHelpers.Validate<uint>(span, uintValue);
- Assert.True(TryWriteMachineEndian<uint>(span, ref uintValue));
+ Assert.True(MemoryMarshal.TryWrite<uint>(span, ref uintValue));
TestHelpers.Validate<uint>(span, uintValue);
ulong ulongValue = 0x1122334455667788;
- WriteMachineEndian<ulong>(span, ref ulongValue);
+ MemoryMarshal.Write<ulong>(span, ref ulongValue);
TestHelpers.Validate<ulong>(span, ulongValue);
- Assert.True(TryWriteMachineEndian<ulong>(span, ref ulongValue));
+ Assert.True(MemoryMarshal.TryWrite<ulong>(span, ref ulongValue));
TestHelpers.Validate<ulong>(span, ulongValue);
short shortValue = 0x1122;
- WriteMachineEndian<short>(span, ref shortValue);
+ MemoryMarshal.Write<short>(span, ref shortValue);
TestHelpers.Validate<short>(span, shortValue);
- Assert.True(TryWriteMachineEndian<short>(span, ref shortValue));
+ Assert.True(MemoryMarshal.TryWrite<short>(span, ref shortValue));
TestHelpers.Validate<short>(span, shortValue);
int intValue = 0x11223344;
- WriteMachineEndian<int>(span, ref intValue);
+ MemoryMarshal.Write<int>(span, ref intValue);
TestHelpers.Validate<int>(span, intValue);
- Assert.True(TryWriteMachineEndian<int>(span, ref intValue));
+ Assert.True(MemoryMarshal.TryWrite<int>(span, ref intValue));
TestHelpers.Validate<int>(span, intValue);
long longValue = 0x1122334455667788;
- WriteMachineEndian<long>(span, ref longValue);
+ MemoryMarshal.Write<long>(span, ref longValue);
TestHelpers.Validate<long>(span, longValue);
- Assert.True(TryWriteMachineEndian<long>(span, ref longValue));
+ Assert.True(MemoryMarshal.TryWrite<long>(span, ref longValue));
TestHelpers.Validate<long>(span, longValue);
}
@@ -270,41 +271,41 @@ namespace System.Buffers.Binary.Tests
Span<byte> span = new byte[1];
- WriteMachineEndian<byte>(span, ref byteValue);
- byte read = ReadMachineEndian<byte>(span);
+ MemoryMarshal.Write<byte>(span, ref byteValue);
+ byte read = MemoryMarshal.Read<byte>(span);
Assert.Equal<byte>(byteValue, read);
span.Clear();
- Assert.True(TryWriteMachineEndian<byte>(span, ref byteValue));
- read = ReadMachineEndian<byte>(span);
+ Assert.True(MemoryMarshal.TryWrite<byte>(span, ref byteValue));
+ read = MemoryMarshal.Read<byte>(span);
Assert.Equal<byte>(byteValue, read);
- WriteMachineEndian<sbyte>(span, ref sbyteValue);
- sbyte readSbyte = ReadMachineEndian<sbyte>(span);
+ MemoryMarshal.Write<sbyte>(span, ref sbyteValue);
+ sbyte readSbyte = MemoryMarshal.Read<sbyte>(span);
Assert.Equal<sbyte>(sbyteValue, readSbyte);
span.Clear();
- Assert.True(TryWriteMachineEndian<sbyte>(span, ref sbyteValue));
- readSbyte = ReadMachineEndian<sbyte>(span);
+ Assert.True(MemoryMarshal.TryWrite<sbyte>(span, ref sbyteValue));
+ readSbyte = MemoryMarshal.Read<sbyte>(span);
Assert.Equal<sbyte>(sbyteValue, readSbyte);
- TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => WriteMachineEndian<short>(_span, ref shortValue));
- Assert.False(TryWriteMachineEndian<short>(span, ref shortValue));
- TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => WriteMachineEndian<int>(_span, ref intValue));
- Assert.False(TryWriteMachineEndian<int>(span, ref intValue));
- TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => WriteMachineEndian<long>(_span, ref longValue));
- Assert.False(TryWriteMachineEndian<long>(span, ref longValue));
+ TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => MemoryMarshal.Write<short>(_span, ref shortValue));
+ Assert.False(MemoryMarshal.TryWrite<short>(span, ref shortValue));
+ TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => MemoryMarshal.Write<int>(_span, ref intValue));
+ Assert.False(MemoryMarshal.TryWrite<int>(span, ref intValue));
+ TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => MemoryMarshal.Write<long>(_span, ref longValue));
+ Assert.False(MemoryMarshal.TryWrite<long>(span, ref longValue));
- TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => WriteMachineEndian<ushort>(_span, ref ushortValue));
- Assert.False(TryWriteMachineEndian<ushort>(span, ref ushortValue));
- TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => WriteMachineEndian<uint>(_span, ref uintValue));
- Assert.False(TryWriteMachineEndian<uint>(span, ref uintValue));
- TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => WriteMachineEndian<ulong>(_span, ref ulongValue));
- Assert.False(TryWriteMachineEndian<ulong>(span, ref ulongValue));
+ TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => MemoryMarshal.Write<ushort>(_span, ref ushortValue));
+ Assert.False(MemoryMarshal.TryWrite<ushort>(span, ref ushortValue));
+ TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => MemoryMarshal.Write<uint>(_span, ref uintValue));
+ Assert.False(MemoryMarshal.TryWrite<uint>(span, ref uintValue));
+ TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => MemoryMarshal.Write<ulong>(_span, ref ulongValue));
+ Assert.False(MemoryMarshal.TryWrite<ulong>(span, ref ulongValue));
var structValue = new TestHelpers.TestValueTypeWithReference { I = 1, S = "1" };
- TestHelpers.AssertThrows<ArgumentException, byte>(span, (_span) => WriteMachineEndian<TestHelpers.TestValueTypeWithReference>(_span, ref structValue));
- TestHelpers.AssertThrows<ArgumentException, byte>(span, (_span) => TryWriteMachineEndian<TestHelpers.TestValueTypeWithReference>(_span, ref structValue));
+ TestHelpers.AssertThrows<ArgumentException, byte>(span, (_span) => MemoryMarshal.Write<TestHelpers.TestValueTypeWithReference>(_span, ref structValue));
+ TestHelpers.AssertThrows<ArgumentException, byte>(span, (_span) => MemoryMarshal.TryWrite<TestHelpers.TestValueTypeWithReference>(_span, ref structValue));
}
}
}
diff --git a/src/System.Memory/tests/Configurations.props b/src/System.Memory/tests/Configurations.props
index 78953dfc88..30b6227d79 100644
--- a/src/System.Memory/tests/Configurations.props
+++ b/src/System.Memory/tests/Configurations.props
@@ -3,6 +3,8 @@
<PropertyGroup>
<BuildConfigurations>
netstandard;
+ netcoreapp;
+ uap;
</BuildConfigurations>
</PropertyGroup>
</Project>
diff --git a/src/System.Memory/tests/Memory/AsMemory.cs b/src/System.Memory/tests/Memory/AsMemory.cs
new file mode 100644
index 0000000000..b6d1653bbf
--- /dev/null
+++ b/src/System.Memory/tests/Memory/AsMemory.cs
@@ -0,0 +1,122 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.MemoryTests
+{
+ public static class AsMemory
+ {
+ [Theory]
+ [InlineData(0, 0)]
+ [InlineData(3, 0)]
+ [InlineData(3, 1)]
+ [InlineData(3, 2)]
+ [InlineData(3, 3)]
+ [InlineData(10, 0)]
+ [InlineData(10, 3)]
+ [InlineData(10, 10)]
+ public static void ArrayAsMemoryWithStart(int length, int start)
+ {
+ int[] a = new int[length];
+ Memory<int> m = a.AsMemory(start);
+ Assert.Equal(length - start, m.Length);
+ if (start != length)
+ {
+ m.Span[0] = 42;
+ Assert.Equal(42, a[start]);
+ }
+ }
+
+ [Theory]
+ [InlineData(0, 0)]
+ [InlineData(3, 0)]
+ [InlineData(3, 1)]
+ [InlineData(3, 2)]
+ [InlineData(3, 3)]
+ [InlineData(10, 0)]
+ [InlineData(10, 3)]
+ [InlineData(10, 10)]
+ public static void ArraySegmentAsMemoryWithStart(int length, int start)
+ {
+ const int segmentOffset = 5;
+
+ int[] a = new int[length + segmentOffset];
+ ArraySegment<int> segment = new ArraySegment<int>(a, 5, length);
+ Memory<int> m = segment.AsMemory(start);
+ Assert.Equal(length - start, m.Length);
+ if (m.Length != 0)
+ {
+ m.Span[0] = 42;
+ Assert.Equal(42, a[segmentOffset + start]);
+ }
+ }
+
+ [Theory]
+ [InlineData(0, 0, 0)]
+ [InlineData(3, 0, 3)]
+ [InlineData(3, 1, 2)]
+ [InlineData(3, 2, 1)]
+ [InlineData(3, 3, 0)]
+ [InlineData(10, 0, 5)]
+ [InlineData(10, 3, 2)]
+ public static void ArrayAsMemoryWithStartAndLength(int length, int start, int subLength)
+ {
+ int[] a = new int[length];
+ Memory<int> m = a.AsMemory(start, subLength);
+ Assert.Equal(subLength, m.Length);
+ if (subLength != 0)
+ {
+ m.Span[0] = 42;
+ Assert.Equal(42, a[start]);
+ }
+ }
+
+ [Theory]
+ [InlineData(0, 0, 0)]
+ [InlineData(3, 0, 3)]
+ [InlineData(3, 1, 2)]
+ [InlineData(3, 2, 1)]
+ [InlineData(3, 3, 0)]
+ [InlineData(10, 0, 5)]
+ [InlineData(10, 3, 2)]
+ public static void ArraySegmentAsMemoryWithStartAndLength(int length, int start, int subLength)
+ {
+ const int segmentOffset = 5;
+
+ int[] a = new int[length + segmentOffset];
+ ArraySegment<int> segment = new ArraySegment<int>(a, segmentOffset, length);
+ Memory<int> m = segment.AsMemory(start, subLength);
+ Assert.Equal(subLength, m.Length);
+ if (subLength != 0)
+ {
+ m.Span[0] = 42;
+ Assert.Equal(42, a[segmentOffset + start]);
+ }
+ }
+
+ [Theory]
+ [InlineData(0, -1)]
+ [InlineData(0, 1)]
+ [InlineData(5, 6)]
+ public static void ArrayAsMemoryWithStartNegative(int length, int start)
+ {
+ int[] a = new int[length];
+ Assert.Throws<ArgumentOutOfRangeException>(() => a.AsMemory(start));
+ }
+
+ [Theory]
+ [InlineData(0, -1, 0)]
+ [InlineData(0, 1, 0)]
+ [InlineData(0, 0, -1)]
+ [InlineData(0, 0, 1)]
+ [InlineData(5, 6, 0)]
+ [InlineData(5, 3, 3)]
+ public static void ArrayAsMemoryWithStartAndLengthNegative(int length, int start, int subLength)
+ {
+ int[] a = new int[length];
+ Assert.Throws<ArgumentOutOfRangeException>(() => a.AsMemory(start, subLength));
+ }
+ }
+}
diff --git a/src/System.Memory/tests/Memory/CtorArray.cs b/src/System.Memory/tests/Memory/CtorArray.cs
index d5b153768f..f7122f3d73 100644
--- a/src/System.Memory/tests/Memory/CtorArray.cs
+++ b/src/System.Memory/tests/Memory/CtorArray.cs
@@ -71,8 +71,22 @@ namespace System.MemoryTests
[Fact]
public static void CtorArrayNullArray()
{
- Assert.Throws<ArgumentNullException>(() => new Memory<int>(null));
- Assert.Throws<ArgumentNullException>(() => new Memory<int>(null, 0, 0));
+ var memory = new Memory<int>(null);
+ memory.Validate();
+ Assert.Equal(default, memory);
+
+ memory = new Memory<int>(null, 0, 0);
+ memory.Validate();
+ Assert.Equal(default, memory);
+ }
+
+ [Fact]
+ public static void CtorArrayNullArrayNonZeroStartAndLength()
+ {
+ Assert.Throws<ArgumentOutOfRangeException>(() => new Memory<int>(null, 1, 0));
+ Assert.Throws<ArgumentOutOfRangeException>(() => new Memory<int>(null, 0, 1));
+ Assert.Throws<ArgumentOutOfRangeException>(() => new Memory<int>(null, 1, 1));
+ Assert.Throws<ArgumentOutOfRangeException>(() => new Memory<int>(null, -1, -1));
}
[Fact]
diff --git a/src/System.Memory/tests/Memory/CustomMemoryForTest.cs b/src/System.Memory/tests/Memory/CustomMemoryForTest.cs
index c8180303ee..2692bee41d 100644
--- a/src/System.Memory/tests/Memory/CustomMemoryForTest.cs
+++ b/src/System.Memory/tests/Memory/CustomMemoryForTest.cs
@@ -15,15 +15,23 @@ namespace System.MemoryTests
private int _referenceCount;
private int _noReferencesCalledCount;
private T[] _array;
+ private readonly int _offset;
+ private readonly int _length;
- public CustomMemoryForTest(T[] array)
+ public CustomMemoryForTest(T[] array): this(array, 0, array.Length)
+ {
+ }
+
+ public CustomMemoryForTest(T[] array, int offset, int length)
{
_array = array;
+ _offset = offset;
+ _length = length;
}
public int OnNoRefencesCalledCount => _noReferencesCalledCount;
- public override int Length => _array.Length;
+ public override int Length => _length;
public override bool IsDisposed => _disposed;
@@ -35,26 +43,40 @@ namespace System.MemoryTests
{
if (IsDisposed)
throw new ObjectDisposedException(nameof(CustomMemoryForTest<T>));
- return new Span<T>(_array, 0, _array.Length);
+ return new Span<T>(_array, _offset, _length);
}
}
- public override MemoryHandle Pin(int offset = 0)
+ public override MemoryHandle Pin(int byteOffset = 0)
{
unsafe
{
- Retain();
- if (offset < 0 || offset > _array.Length) throw new ArgumentOutOfRangeException(nameof(offset));
- var handle = GCHandle.Alloc(_array, GCHandleType.Pinned);
- return new MemoryHandle(this, Unsafe.Add<byte>((void*)handle.AddrOfPinnedObject(), offset), handle);
+ Retain(); // this checks IsDisposed
+
+ try
+ {
+ if ((IntPtr.Size == 4 && (uint)byteOffset > (uint)_array.Length * (uint)Unsafe.SizeOf<T>())
+ || (IntPtr.Size != 4 && (ulong)byteOffset > (uint)_array.Length * (ulong)Unsafe.SizeOf<T>()))
+ {
+ throw new ArgumentOutOfRangeException(nameof(byteOffset));
+ }
+
+ var handle = GCHandle.Alloc(_array, GCHandleType.Pinned);
+ return new MemoryHandle(this, Unsafe.Add<byte>((void*)handle.AddrOfPinnedObject(), _offset + byteOffset), handle);
+ }
+ catch
+ {
+ Release();
+ throw;
+ }
}
}
- protected override bool TryGetArray(out ArraySegment<T> arraySegment)
+ protected override bool TryGetArray(out ArraySegment<T> segment)
{
if (IsDisposed)
throw new ObjectDisposedException(nameof(CustomMemoryForTest<T>));
- arraySegment = new ArraySegment<T>(_array);
+ segment = new ArraySegment<T>(_array, _offset, _length);
return true;
}
diff --git a/src/System.Memory/tests/Memory/OwnedMemory.cs b/src/System.Memory/tests/Memory/OwnedMemory.cs
index e1249ed0cf..d75e164b40 100644
--- a/src/System.Memory/tests/Memory/OwnedMemory.cs
+++ b/src/System.Memory/tests/Memory/OwnedMemory.cs
@@ -118,6 +118,22 @@ namespace System.MemoryTests
}
[Fact]
+ [OuterLoop]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Desktop framework doesn't support large arrays by default.")]
+ public static void OwnedMemoryPinLargeArray()
+ {
+ // Early-out: we can only run this test on 64-bit platforms.
+ if (IntPtr.Size == 4)
+ {
+ return;
+ }
+
+ int[] array = new int[0x2000_0000]; // will produce array with total byte length > 2 GB
+ OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
+ Assert.Throws<ArgumentOutOfRangeException>(() => owner.Pin(int.MinValue));
+ }
+
+ [Fact]
public static void MemoryFromOwnedMemoryAfterDispose()
{
int[] a = { 91, 92, -93, 94 };
diff --git a/src/System.Memory/tests/Memory/Pin.cs b/src/System.Memory/tests/Memory/Pin.cs
new file mode 100644
index 0000000000..2d0d8ff523
--- /dev/null
+++ b/src/System.Memory/tests/Memory/Pin.cs
@@ -0,0 +1,133 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using Xunit;
+
+namespace System.MemoryTests
+{
+ public static partial class MemoryTests
+ {
+ [Fact]
+ public static void MemoryPin()
+ {
+ int[] array = { 1, 2, 3, 4, 5 };
+ Memory<int> memory = array;
+ MemoryHandle handle = memory.Pin();
+ Assert.True(handle.HasPointer);
+ unsafe
+ {
+ int* pointer = (int*)handle.Pointer;
+
+ GC.Collect();
+
+ for (int i = 0; i < memory.Length; i++)
+ {
+ Assert.Equal(array[i], pointer[i]);
+ }
+ }
+ handle.Dispose();
+ }
+
+ [Fact]
+ public static void MemoryFromEmptyArrayPin()
+ {
+ Memory<int> memory = new int[0];
+ MemoryHandle handle = memory.Pin();
+ Assert.True(handle.HasPointer);
+ handle.Dispose();
+ }
+
+ [Fact]
+ public static void DefaultMemoryPin()
+ {
+ Memory<int> memory = default;
+ MemoryHandle handle = memory.Pin();
+ Assert.False(handle.HasPointer);
+ unsafe
+ {
+ Assert.True(handle.Pointer == null);
+ }
+ handle.Dispose();
+ }
+
+ [Fact]
+ public static void MemoryPinAndSlice()
+ {
+ int[] array = { 1, 2, 3, 4, 5 };
+ Memory<int> memory = array;
+ memory = memory.Slice(1);
+ MemoryHandle handle = memory.Pin();
+ Span<int> span = memory.Span;
+ Assert.True(handle.HasPointer);
+ unsafe
+ {
+ int* pointer = (int*)handle.Pointer;
+
+ GC.Collect();
+
+ for (int i = 0; i < memory.Length; i++)
+ {
+ Assert.Equal(array[i + 1], pointer[i]);
+ }
+
+ for (int i = 0; i < memory.Length; i++)
+ {
+ Assert.Equal(array[i + 1], span[i]);
+ }
+ }
+ handle.Dispose();
+ }
+
+ [Fact]
+ public static void OwnedMemoryPin()
+ {
+ int[] array = { 1, 2, 3, 4, 5 };
+ OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
+ Memory<int> memory = owner.Memory;
+ MemoryHandle handle = memory.Pin();
+ Assert.True(handle.HasPointer);
+ unsafe
+ {
+ int* pointer = (int*)handle.Pointer;
+
+ GC.Collect();
+
+ for (int i = 0; i < memory.Length; i++)
+ {
+ Assert.Equal(array[i], pointer[i]);
+ }
+ }
+ handle.Dispose();
+ }
+
+ [Fact]
+ public static void OwnedMemoryPinAndSlice()
+ {
+ int[] array = { 1, 2, 3, 4, 5 };
+ OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
+ Memory<int> memory = owner.Memory.Slice(1);
+ MemoryHandle handle = memory.Pin();
+ Span<int> span = memory.Span;
+ Assert.True(handle.HasPointer);
+ unsafe
+ {
+ int* pointer = (int*)handle.Pointer;
+
+ GC.Collect();
+
+ for (int i = 0; i < memory.Length; i++)
+ {
+ Assert.Equal(array[i + 1], pointer[i]);
+ }
+
+ for (int i = 0; i < memory.Length; i++)
+ {
+ Assert.Equal(array[i + 1], span[i]);
+ }
+ }
+ handle.Dispose();
+ }
+ }
+}
diff --git a/src/System.Memory/tests/Memory/Retain.cs b/src/System.Memory/tests/Memory/Retain.cs
index 4286685a0d..1ef319103c 100644
--- a/src/System.Memory/tests/Memory/Retain.cs
+++ b/src/System.Memory/tests/Memory/Retain.cs
@@ -46,6 +46,30 @@ namespace System.MemoryTests
}
[Fact]
+ public static void MemoryFromEmptyArrayRetainWithPinning()
+ {
+ Memory<int> memory = new int[0];
+ MemoryHandle handle = memory.Retain(pin: true);
+ Assert.True(handle.HasPointer);
+ handle.Dispose();
+ }
+
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public static void DefaultMemoryRetain(bool pin)
+ {
+ Memory<int> memory = default;
+ MemoryHandle handle = memory.Retain(pin: pin);
+ Assert.False(handle.HasPointer);
+ unsafe
+ {
+ Assert.True(handle.Pointer == null);
+ }
+ handle.Dispose();
+ }
+
+ [Fact]
public static void MemoryRetainWithPinningAndSlice()
{
int[] array = { 1, 2, 3, 4, 5 };
@@ -111,23 +135,6 @@ namespace System.MemoryTests
}
[Fact]
- public static void MemoryFromEmptyArrayRetainWithPinning()
- {
- Memory<int> memory = new int[0];
- MemoryHandle handle = memory.Retain(pin: true);
- Assert.True(handle.HasPointer);
- unsafe
- {
- int* pointer = (int*)handle.Pointer;
-
- GC.Collect();
-
- Assert.True(pointer != null);
- }
- handle.Dispose();
- }
-
- [Fact]
public static void OwnedMemoryRetainWithPinningAndSlice()
{
int[] array = { 1, 2, 3, 4, 5 };
@@ -154,20 +161,5 @@ namespace System.MemoryTests
}
handle.Dispose();
}
-
- [Theory]
- [InlineData(true)]
- [InlineData(false)]
- public static void DefaultMemoryRetain(bool pin)
- {
- Memory<int> memory = default;
- MemoryHandle handle = memory.Retain(pin: pin);
- Assert.False(handle.HasPointer);
- unsafe
- {
- Assert.True(handle.Pointer == null);
- }
- handle.Dispose();
- }
}
}
diff --git a/src/System.Memory/tests/Memory/Strings.cs b/src/System.Memory/tests/Memory/Strings.cs
index fd0f2fd26a..b711179cd1 100644
--- a/src/System.Memory/tests/Memory/Strings.cs
+++ b/src/System.Memory/tests/Memory/Strings.cs
@@ -22,7 +22,7 @@ namespace System.MemoryTests
[MemberData(nameof(StringInputs))]
public static void Memory_ToArray_Roundtrips(string input)
{
- ReadOnlyMemory<char> readonlyMemory = input.AsReadOnlyMemory();
+ ReadOnlyMemory<char> readonlyMemory = input.AsMemory();
Memory<char> m = MemoryMarshal.AsMemory(readonlyMemory);
Assert.Equal(input, new string(m.ToArray()));
}
@@ -31,7 +31,7 @@ namespace System.MemoryTests
[MemberData(nameof(StringInputs))]
public static void Memory_Span_Roundtrips(string input)
{
- ReadOnlyMemory<char> readonlyMemory = input.AsReadOnlyMemory();
+ ReadOnlyMemory<char> readonlyMemory = input.AsMemory();
Memory<char> m = MemoryMarshal.AsMemory(readonlyMemory);
ReadOnlySpan<char> s = m.Span;
Assert.Equal(input, new string(s.ToArray()));
@@ -49,7 +49,7 @@ namespace System.MemoryTests
[InlineData("0123456789", 5, 3)]
public static void Memory_Slice_MatchesSubstring(string input, int offset, int count)
{
- ReadOnlyMemory<char> readonlyMemory = input.AsReadOnlyMemory();
+ ReadOnlyMemory<char> readonlyMemory = input.AsMemory();
Memory<char> m = MemoryMarshal.AsMemory(readonlyMemory);
Assert.Equal(input.Substring(offset, count), new string(m.Slice(offset, count).ToArray()));
Assert.Equal(input.Substring(offset, count), new string(m.Slice(offset, count).Span.ToArray()));
@@ -57,18 +57,13 @@ namespace System.MemoryTests
}
[Fact]
- public static unsafe void Memory_Retain_ExpectedPointerValue()
+ public static unsafe void Memory_Pin_ExpectedPointerValue()
{
string input = "0123456789";
- ReadOnlyMemory<char> readonlyMemory = input.AsReadOnlyMemory();
+ ReadOnlyMemory<char> readonlyMemory = input.AsMemory();
Memory<char> m = MemoryMarshal.AsMemory(readonlyMemory);
- using (MemoryHandle h = m.Retain(pin: false))
- {
- Assert.Equal(IntPtr.Zero, (IntPtr)h.Pointer);
- }
-
- using (MemoryHandle h = m.Retain(pin: true))
+ using (MemoryHandle h = m.Pin())
{
GC.Collect();
fixed (char* ptr = input)
@@ -81,8 +76,8 @@ namespace System.MemoryTests
[Fact]
public static void Memory_EqualsAndGetHashCode_ExpectedResults()
{
- ReadOnlyMemory<char> readonlyMemory1 = new string('a', 4).AsReadOnlyMemory();
- ReadOnlyMemory<char> readonlyMemory2 = new string('a', 4).AsReadOnlyMemory();
+ ReadOnlyMemory<char> readonlyMemory1 = new string('a', 4).AsMemory();
+ ReadOnlyMemory<char> readonlyMemory2 = new string('a', 4).AsMemory();
Memory<char> m1 = MemoryMarshal.AsMemory(readonlyMemory1);
Memory<char> m2 = MemoryMarshal.AsMemory(readonlyMemory2);
diff --git a/src/System.Memory/tests/Memory/ToString.cs b/src/System.Memory/tests/Memory/ToString.cs
new file mode 100644
index 0000000000..e6eb713c8a
--- /dev/null
+++ b/src/System.Memory/tests/Memory/ToString.cs
@@ -0,0 +1,130 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Runtime.InteropServices;
+using Xunit;
+
+namespace System.MemoryTests
+{
+ public static partial class MemoryTests
+ {
+ [Fact]
+ public static void ToStringInt()
+ {
+ int[] a = { 91, 92, 93 };
+ var memory = new Memory<int>(a);
+ Assert.Equal("System.Memory<Int32>[3]", memory.ToString());
+ Assert.Equal("System.Memory<Int32>[1]", memory.Slice(1, 1).ToString());
+ Assert.Equal("System.Span<Int32>[3]", memory.Span.ToString());
+ }
+
+ [Fact]
+ public static void ToStringInt_Empty()
+ {
+ var memory = new Memory<int>();
+ Assert.Equal("System.Memory<Int32>[0]", memory.ToString());
+ Assert.Equal("System.Memory<Int32>[0]", Memory<int>.Empty.ToString());
+ Assert.Equal("System.Span<Int32>[0]", memory.Span.ToString());
+ }
+
+ [Fact]
+ public static void ToStringChar()
+ {
+ char[] a = { 'a', 'b', 'c' };
+ var memory = new Memory<char>(a);
+ Assert.Equal("abc", memory.ToString());
+ Assert.Equal("b", memory.Slice(1, 1).ToString());
+ Assert.Equal("abc", memory.Span.ToString());
+ }
+
+ [Fact]
+ public static void ToStringChar_Empty()
+ {
+ var memory = new Memory<char>();
+ Assert.Equal("", memory.ToString());
+ Assert.Equal("", Memory<char>.Empty.ToString());
+ Assert.Equal("", memory.Span.ToString());
+ }
+
+ [Fact]
+ public static void ToStringMemoryFromReadOnlyMemory()
+ {
+ string testString = "abcdefg";
+ Memory<char> memory = MemoryMarshal.AsMemory(testString.AsMemory());
+ Assert.Equal(testString, memory.ToString());
+ Assert.Equal(testString.Substring(1, 1), memory.Slice(1, 1).ToString());
+ Assert.Equal(testString, memory.Span.ToString());
+ }
+
+ [Fact]
+ public static void ToStringForMemoryOfString()
+ {
+ string[] a = { "a", "b", "c" };
+ var memory = new Memory<string>(a);
+ Assert.Equal("System.Memory<String>[3]", memory.ToString());
+ Assert.Equal("System.Memory<String>[1]", memory.Slice(1, 1).ToString());
+ Assert.Equal("System.Span<String>[3]", memory.Span.ToString());
+ }
+
+ [Fact]
+ public static void ToStringFromMemoryFromOwnedMemory()
+ {
+ int[] a = { 91, 92, -93, 94 };
+ OwnedMemory<int> intOwner = new CustomMemoryForTest<int>(a);
+ Assert.Equal("System.Memory<Int32>[4]", intOwner.Memory.ToString());
+
+ intOwner = new CustomMemoryForTest<int>(Array.Empty<int>());
+ Assert.Equal("System.Memory<Int32>[0]", intOwner.Memory.ToString());
+
+ char[] charArray = { '1', '2', '-', '4' };
+ OwnedMemory<char> charOwner = new CustomMemoryForTest<char>(charArray);
+ Assert.Equal("12-4", charOwner.Memory.ToString());
+
+ charOwner = new CustomMemoryForTest<char>(Array.Empty<char>());
+ Assert.Equal("", charOwner.Memory.ToString());
+
+ string[] strArray = { "91", "92", "-93", "94" };
+ OwnedMemory<string> strOwner = new CustomMemoryForTest<string>(strArray);
+ Assert.Equal("System.Memory<String>[4]", strOwner.Memory.ToString());
+
+ strOwner = new CustomMemoryForTest<string>(Array.Empty<string>());
+ Assert.Equal("System.Memory<String>[0]", strOwner.Memory.ToString());
+ }
+
+ [Fact]
+ public static void ToStringMemoryOverFullStringReturnsOriginal()
+ {
+ string original = TestHelpers.BuildString(10, 42);
+
+ ReadOnlyMemory<char> readOnlyMemory = original.AsMemory();
+ Memory<char> memory = MemoryMarshal.AsMemory(readOnlyMemory);
+
+ string returnedString = memory.ToString();
+ string returnedStringUsingSlice = memory.Slice(0, original.Length).ToString();
+
+ string subString1 = memory.Slice(1).ToString();
+ string subString2 = memory.Slice(0, 2).ToString();
+ string subString3 = memory.Slice(1, 2).ToString();
+
+ Assert.Equal(original, returnedString);
+ Assert.Equal(original, returnedStringUsingSlice);
+
+ Assert.Equal(original.Substring(1), subString1);
+ Assert.Equal(original.Substring(0, 2), subString2);
+ Assert.Equal(original.Substring(1, 2), subString3);
+
+ Assert.Same(original, returnedString);
+ Assert.Same(original, returnedStringUsingSlice);
+
+ Assert.NotSame(original, subString1);
+ Assert.NotSame(original, subString2);
+ Assert.NotSame(original, subString3);
+
+ Assert.NotSame(subString1, subString2);
+ Assert.NotSame(subString1, subString3);
+ Assert.NotSame(subString2, subString3);
+ }
+ }
+}
diff --git a/src/System.Memory/tests/Memory/TryGetArray.cs b/src/System.Memory/tests/Memory/TryGetArray.cs
deleted file mode 100644
index fdd92e8906..0000000000
--- a/src/System.Memory/tests/Memory/TryGetArray.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Buffers;
-using Xunit;
-
-namespace System.MemoryTests
-{
- public static partial class MemoryTests
- {
- [Fact]
- public static void MemoryTryGetArray()
- {
- int[] array = new int[10];
- Memory<int> memory = array;
- Assert.True(memory.TryGetArray(out ArraySegment<int> segment));
- Assert.Equal(array.Length, segment.Count);
-
- for (int i = segment.Offset; i < segment.Count + segment.Offset; i++)
- {
- Assert.Equal(array[i], segment.Array[i]);
- }
- }
-
- [Fact]
- public static void TryGetArrayFromDefaultMemory()
- {
- Memory<int> memory = default;
- Assert.False(memory.TryGetArray(out ArraySegment<int> segment));
- Assert.True(segment.Equals(default));
- }
-
- [Fact]
- public static void OwnedMemoryTryGetArray()
- {
- int[] array = new int[10];
- OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
- Memory<int> memory = owner.Memory;
- Assert.True(memory.TryGetArray(out ArraySegment<int> segment));
- Assert.Equal(array.Length, segment.Count);
-
- for (int i = segment.Offset; i < segment.Count + segment.Offset; i++)
- {
- Assert.Equal(array[i], segment.Array[i]);
- }
- }
- }
-}
diff --git a/src/System.Memory/tests/ReadOnlySpan/AsBytes.cs b/src/System.Memory/tests/MemoryMarshal/AsBytesReadOnlySpan.cs
index 66aad3d6cf..c4c54f49aa 100644
--- a/src/System.Memory/tests/ReadOnlySpan/AsBytes.cs
+++ b/src/System.Memory/tests/MemoryMarshal/AsBytesReadOnlySpan.cs
@@ -8,24 +8,24 @@ using System.Runtime.InteropServices;
namespace System.SpanTests
{
- public static partial class ReadOnlySpanTests
+ public static partial class MemoryMarshalTests
{
[Fact]
- public static void AsBytesUIntToByte()
+ public static void ReadOnlySpan_AsBytesUIntToByte()
{
uint[] a = { 0x44332211, 0x88776655 };
ReadOnlySpan<uint> span = new ReadOnlySpan<uint>(a);
- ReadOnlySpan<byte> asBytes = span.AsBytes<uint>();
+ ReadOnlySpan<byte> asBytes = MemoryMarshal.AsBytes<uint>(span);
Assert.True(Unsafe.AreSame(ref Unsafe.As<uint, byte>(ref Unsafe.AsRef(in MemoryMarshal.GetReference(span))), ref Unsafe.AsRef(in MemoryMarshal.GetReference(asBytes))));
asBytes.Validate<byte>(0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88);
}
[Fact]
- public static void AsBytesContainsReferences()
+ public static void ReadOnlySpan_AsBytesContainsReferences()
{
- ReadOnlySpan<StructWithReferences> span = new ReadOnlySpan<StructWithReferences>(Array.Empty<StructWithReferences>());
- TestHelpers.AssertThrows<ArgumentException, StructWithReferences>(span, (_span) => _span.AsBytes().DontBox());
+ ReadOnlySpan<TestHelpers.StructWithReferences> span = new ReadOnlySpan<TestHelpers.StructWithReferences>(Array.Empty<TestHelpers.StructWithReferences>());
+ TestHelpers.AssertThrows<ArgumentException, TestHelpers.StructWithReferences>(span, (_span) => MemoryMarshal.AsBytes(_span).DontBox());
}
}
}
diff --git a/src/System.Memory/tests/Span/AsBytes.cs b/src/System.Memory/tests/MemoryMarshal/AsBytesSpan.cs
index dbbe885aaa..099a43bc18 100644
--- a/src/System.Memory/tests/Span/AsBytes.cs
+++ b/src/System.Memory/tests/MemoryMarshal/AsBytesSpan.cs
@@ -8,24 +8,24 @@ using System.Runtime.InteropServices;
namespace System.SpanTests
{
- public static partial class SpanTests
+ public static partial class MemoryMarshalTests
{
[Fact]
- public static void AsBytesUIntToByte()
+ public static void Span_AsBytesUIntToByte()
{
uint[] a = { 0x44332211, 0x88776655 };
Span<uint> span = new Span<uint>(a);
- Span<byte> asBytes = span.AsBytes<uint>();
+ Span<byte> asBytes = MemoryMarshal.AsBytes<uint>(span);
Assert.True(Unsafe.AreSame<byte>(ref Unsafe.As<uint, byte>(ref MemoryMarshal.GetReference(span)), ref MemoryMarshal.GetReference(asBytes)));
asBytes.Validate<byte>(0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88);
}
[Fact]
- public static void AsBytesContainsReferences()
+ public static void Span_AsBytesContainsReferences()
{
- Span<StructWithReferences> span = new Span<StructWithReferences>(Array.Empty<StructWithReferences>());
- TestHelpers.AssertThrows<ArgumentException, StructWithReferences>(span, (_span) => _span.AsBytes().DontBox());
+ Span<TestHelpers.StructWithReferences> span = new Span<TestHelpers.StructWithReferences>(Array.Empty<TestHelpers.StructWithReferences>());
+ TestHelpers.AssertThrows<ArgumentException, TestHelpers.StructWithReferences>(span, (_span) => MemoryMarshal.AsBytes(_span).DontBox());
}
}
}
diff --git a/src/System.Memory/tests/MemoryMarshal/AsMemory.cs b/src/System.Memory/tests/MemoryMarshal/AsMemory.cs
index 0d9e9fc08b..40990d08cb 100644
--- a/src/System.Memory/tests/MemoryMarshal/AsMemory.cs
+++ b/src/System.Memory/tests/MemoryMarshal/AsMemory.cs
@@ -34,39 +34,39 @@ namespace System.MemoryTests
yield return new object[] { ReadOnlyMemory<char>.Empty };
yield return new object[] { new ReadOnlyMemory<char>(new char[10], 1, 3) };
yield return new object[] { (ReadOnlyMemory<char>)new CustomMemoryForTest<char>(new char[10]).Memory };
- yield return new object[] { "12345".AsReadOnlyMemory() };
+ yield return new object[] { "12345".AsMemory() };
}
[Theory]
[MemberData(nameof(ReadOnlyMemoryInt32Instances))]
- public static void AsMemory_Roundtrips(ReadOnlyMemory<int> readOnlyMemory) => AsMemory_Roundtrips_Core(readOnlyMemory);
+ public static void AsMemory_Roundtrips(ReadOnlyMemory<int> readOnlyMemory) => AsMemory_Roundtrips_Core(readOnlyMemory, true);
[Theory]
[MemberData(nameof(ReadOnlyMemoryObjectInstances))]
- public static void AsMemory_Roundtrips(ReadOnlyMemory<object> readOnlyMemory) => AsMemory_Roundtrips_Core(readOnlyMemory);
+ public static void AsMemory_Roundtrips(ReadOnlyMemory<object> readOnlyMemory) => AsMemory_Roundtrips_Core(readOnlyMemory, false);
[Theory]
[MemberData(nameof(ReadOnlyMemoryCharInstances))]
public static void AsMemory_Roundtrips(ReadOnlyMemory<char> readOnlyMemory)
{
- AsMemory_Roundtrips_Core(readOnlyMemory);
+ AsMemory_Roundtrips_Core(readOnlyMemory, true);
Memory<char> memory = MemoryMarshal.AsMemory(readOnlyMemory);
ReadOnlyMemory<char> readOnlyClone = memory;
// TryGetString
- bool gotString1 = readOnlyMemory.TryGetString(out string text1, out int start1, out int length1);
- Assert.Equal(gotString1, readOnlyClone.TryGetString(out string text2, out int start2, out int length2));
+ bool gotString1 = MemoryMarshal.TryGetString(readOnlyMemory, out string text1, out int start1, out int length1);
+ Assert.Equal(gotString1, MemoryMarshal.TryGetString(readOnlyClone, out string text2, out int start2, out int length2));
Assert.Same(text1, text2);
Assert.Equal(start1, start2);
Assert.Equal(length1, length2);
if (gotString1)
{
- Assert.False(memory.TryGetArray(out ArraySegment<char> array));
+ Assert.False(MemoryMarshal.TryGetArray(memory, out ArraySegment<char> array));
}
}
- private static unsafe void AsMemory_Roundtrips_Core<T>(ReadOnlyMemory<T> readOnlyMemory)
+ private static unsafe void AsMemory_Roundtrips_Core<T>(ReadOnlyMemory<T> readOnlyMemory, bool canBePinned)
{
Memory<T> memory = MemoryMarshal.AsMemory(readOnlyMemory);
ReadOnlyMemory<T> readOnlyClone = memory;
@@ -81,18 +81,22 @@ namespace System.MemoryTests
Assert.True(readOnlyMemory.Span == memory.Span);
// TryGetArray
- Assert.True(MemoryMarshal.TryGetArray(readOnlyMemory, out ArraySegment<T> array1) == memory.TryGetArray(out ArraySegment<T> array2));
+ Assert.True(MemoryMarshal.TryGetArray(readOnlyMemory, out ArraySegment<T> array1)
+ == MemoryMarshal.TryGetArray(memory, out ArraySegment<T> array2));
Assert.Same(array1.Array, array2.Array);
Assert.Equal(array1.Offset, array2.Offset);
Assert.Equal(array1.Count, array2.Count);
- // Retain
- using (MemoryHandle readOnlyMemoryHandle = readOnlyMemory.Retain())
- using (MemoryHandle readOnlyCloneHandle = readOnlyMemory.Retain())
- using (MemoryHandle memoryHandle = readOnlyMemory.Retain())
+ if (canBePinned)
{
- Assert.Equal((IntPtr)readOnlyMemoryHandle.Pointer, (IntPtr)readOnlyCloneHandle.Pointer);
- Assert.Equal((IntPtr)readOnlyMemoryHandle.Pointer, (IntPtr)memoryHandle.Pointer);
+ // Pin
+ using (MemoryHandle readOnlyMemoryHandle = readOnlyMemory.Pin())
+ using (MemoryHandle readOnlyCloneHandle = readOnlyMemory.Pin())
+ using (MemoryHandle memoryHandle = readOnlyMemory.Pin())
+ {
+ Assert.Equal((IntPtr)readOnlyMemoryHandle.Pointer, (IntPtr)readOnlyCloneHandle.Pointer);
+ Assert.Equal((IntPtr)readOnlyMemoryHandle.Pointer, (IntPtr)memoryHandle.Pointer);
+ }
}
}
}
diff --git a/src/System.Memory/tests/ReadOnlySpan/NonPortableCast.cs b/src/System.Memory/tests/MemoryMarshal/CastReadOnlySpan.cs
index 1153e66bf5..26b738ef60 100644
--- a/src/System.Memory/tests/ReadOnlySpan/NonPortableCast.cs
+++ b/src/System.Memory/tests/MemoryMarshal/CastReadOnlySpan.cs
@@ -8,51 +8,51 @@ using System.Runtime.InteropServices;
namespace System.SpanTests
{
- public static partial class ReadOnlySpanTests
+ public static partial class MemoryMarshalTests
{
[Fact]
- public static void NonPortableCastUIntToUShort()
+ public static void CastReadOnlySpanUIntToUShort()
{
uint[] a = { 0x44332211, 0x88776655 };
ReadOnlySpan<uint> span = new ReadOnlySpan<uint>(a);
- ReadOnlySpan<ushort> asUShort = span.NonPortableCast<uint, ushort>();
+ ReadOnlySpan<ushort> asUShort = MemoryMarshal.Cast<uint, ushort>(span);
Assert.True(Unsafe.AreSame<ushort>(ref Unsafe.As<uint, ushort>(ref Unsafe.AsRef(in MemoryMarshal.GetReference(span))), ref Unsafe.AsRef(in MemoryMarshal.GetReference(asUShort))));
asUShort.Validate<ushort>(0x2211, 0x4433, 0x6655, 0x8877);
}
[Fact]
- public static void NonPortableCastShortToLong()
+ public static void CastReadOnlySpanShortToLong()
{
short[] a = { 0x1234, 0x2345, 0x3456, 0x4567, 0x5678 };
ReadOnlySpan<short> span = new ReadOnlySpan<short>(a);
- ReadOnlySpan<long> asLong = span.NonPortableCast<short, long>();
+ ReadOnlySpan<long> asLong = MemoryMarshal.Cast<short, long>(span);
Assert.True(Unsafe.AreSame<long>(ref Unsafe.As<short, long>(ref MemoryMarshal.GetReference(span)), ref MemoryMarshal.GetReference(asLong)));
asLong.Validate<long>(0x4567345623451234);
}
[Fact]
- public static unsafe void NonPortableCastOverflow()
+ public static unsafe void CastReadOnlySpanOverflow()
{
ReadOnlySpan<TestHelpers.TestStructExplicit> span = new ReadOnlySpan<TestHelpers.TestStructExplicit>(null, Int32.MaxValue);
- TestHelpers.AssertThrows<OverflowException, TestHelpers.TestStructExplicit>(span, (_span) => _span.NonPortableCast<TestHelpers.TestStructExplicit, byte>().DontBox());
- TestHelpers.AssertThrows<OverflowException, TestHelpers.TestStructExplicit>(span, (_span) => _span.NonPortableCast<TestHelpers.TestStructExplicit, ulong>().DontBox());
+ TestHelpers.AssertThrows<OverflowException, TestHelpers.TestStructExplicit>(span, (_span) => MemoryMarshal.Cast<TestHelpers.TestStructExplicit, byte>(_span).DontBox());
+ TestHelpers.AssertThrows<OverflowException, TestHelpers.TestStructExplicit>(span, (_span) => MemoryMarshal.Cast<TestHelpers.TestStructExplicit, ulong>(_span).DontBox());
}
[Fact]
- public static void NonPortableCastToTypeContainsReferences()
+ public static void CastReadOnlySpanToTypeContainsReferences()
{
ReadOnlySpan<uint> span = new ReadOnlySpan<uint>(Array.Empty<uint>());
- TestHelpers.AssertThrows<ArgumentException, uint>(span, (_span) => _span.NonPortableCast<uint, StructWithReferences>().DontBox());
+ TestHelpers.AssertThrows<ArgumentException, uint>(span, (_span) => MemoryMarshal.Cast<uint, TestHelpers.StructWithReferences>(_span).DontBox());
}
[Fact]
- public static void NonPortableCastFromTypeContainsReferences()
+ public static void CastReadOnlySpanFromTypeContainsReferences()
{
- ReadOnlySpan<StructWithReferences> span = new ReadOnlySpan<StructWithReferences>(Array.Empty<StructWithReferences>());
- TestHelpers.AssertThrows<ArgumentException, StructWithReferences>(span, (_span) => _span.NonPortableCast<StructWithReferences, uint>().DontBox());
+ ReadOnlySpan<TestHelpers.StructWithReferences> span = new ReadOnlySpan<TestHelpers.StructWithReferences>(Array.Empty<TestHelpers.StructWithReferences>());
+ TestHelpers.AssertThrows<ArgumentException, TestHelpers.StructWithReferences>(span, (_span) => MemoryMarshal.Cast<TestHelpers.StructWithReferences, uint>(_span).DontBox());
}
}
}
diff --git a/src/System.Memory/tests/Span/NonPortableCast.cs b/src/System.Memory/tests/MemoryMarshal/CastSpan.cs
index 81b0bf6e45..d58ff78aba 100644
--- a/src/System.Memory/tests/Span/NonPortableCast.cs
+++ b/src/System.Memory/tests/MemoryMarshal/CastSpan.cs
@@ -8,51 +8,63 @@ using System.Runtime.InteropServices;
namespace System.SpanTests
{
- public static partial class SpanTests
+ public static partial class MemoryMarshalTests
{
+
[Fact]
- public static void NonPortableCastUIntToUShort()
+ public static void CastSpanUIntToUShort()
{
uint[] a = { 0x44332211, 0x88776655 };
Span<uint> span = new Span<uint>(a);
- Span<ushort> asUShort = span.NonPortableCast<uint, ushort>();
+ Span<ushort> asUShort = MemoryMarshal.Cast<uint, ushort>(span);
Assert.True(Unsafe.AreSame<ushort>(ref Unsafe.As<uint, ushort>(ref MemoryMarshal.GetReference(span)), ref MemoryMarshal.GetReference(asUShort)));
asUShort.Validate<ushort>(0x2211, 0x4433, 0x6655, 0x8877);
}
+ struct EmptyStruct { }
+
+ [Fact]
+ public static void CastSpanToEmptyStruct()
+ {
+ Span<uint> span = new Span<uint>(new uint[] { 1 });
+ Span<EmptyStruct> emptyspan = MemoryMarshal.Cast<uint, EmptyStruct>(span);
+ Assert.Equal(1, Unsafe.SizeOf<EmptyStruct>());
+ Assert.Equal(4, emptyspan.Length);
+ }
+
[Fact]
- public static void NonPortableCastShortToLong()
+ public static void CastSpanShortToLong()
{
short[] a = { 0x1234, 0x2345, 0x3456, 0x4567, 0x5678 };
Span<short> span = new Span<short>(a);
- Span<long> asLong = span.NonPortableCast<short, long>();
+ Span<long> asLong = MemoryMarshal.Cast<short, long>(span);
Assert.True(Unsafe.AreSame<long>(ref Unsafe.As<short, long>(ref MemoryMarshal.GetReference(span)), ref MemoryMarshal.GetReference(asLong)));
asLong.Validate<long>(0x4567345623451234);
}
[Fact]
- public static unsafe void NonPortableCastOverflow()
+ public static unsafe void CastSpanOverflow()
{
Span<TestHelpers.TestStructExplicit> span = new Span<TestHelpers.TestStructExplicit>(null, Int32.MaxValue);
- TestHelpers.AssertThrows<OverflowException, TestHelpers.TestStructExplicit>(span, (_span) => _span.NonPortableCast<TestHelpers.TestStructExplicit, byte>().DontBox());
- TestHelpers.AssertThrows<OverflowException, TestHelpers.TestStructExplicit>(span, (_span) => _span.NonPortableCast<TestHelpers.TestStructExplicit, ulong>().DontBox());
+ TestHelpers.AssertThrows<OverflowException, TestHelpers.TestStructExplicit>(span, (_span) => MemoryMarshal.Cast<TestHelpers.TestStructExplicit, byte>(_span).DontBox());
+ TestHelpers.AssertThrows<OverflowException, TestHelpers.TestStructExplicit>(span, (_span) => MemoryMarshal.Cast<TestHelpers.TestStructExplicit, ulong>(_span).DontBox());
}
[Fact]
- public static void NonPortableCastToTypeContainsReferences()
+ public static void CastSpanToTypeContainsReferences()
{
Span<uint> span = new Span<uint>(Array.Empty<uint>());
- TestHelpers.AssertThrows<ArgumentException, uint>(span, (_span) => _span.NonPortableCast<uint, StructWithReferences>().DontBox());
+ TestHelpers.AssertThrows<ArgumentException, uint>(span, (_span) => MemoryMarshal.Cast<uint, TestHelpers.StructWithReferences>(_span).DontBox());
}
[Fact]
- public static void NonPortableCastFromTypeContainsReferences()
+ public static void CastSpanFromTypeContainsReferences()
{
- Span<StructWithReferences> span = new Span<StructWithReferences>(Array.Empty<StructWithReferences>());
- TestHelpers.AssertThrows<ArgumentException, StructWithReferences>(span, (_span) => _span.NonPortableCast<StructWithReferences, uint>().DontBox());
+ Span<TestHelpers.StructWithReferences> span = new Span<TestHelpers.StructWithReferences>(Array.Empty<TestHelpers.StructWithReferences>());
+ TestHelpers.AssertThrows<ArgumentException, TestHelpers.StructWithReferences>(span, (_span) => MemoryMarshal.Cast<TestHelpers.StructWithReferences, uint>(_span).DontBox());
}
}
}
diff --git a/src/System.Memory/tests/ReadOnlySpan/DangerousCreate.cs b/src/System.Memory/tests/MemoryMarshal/CreateReadOnlySpan.cs
index e9feb2f935..347e0503e3 100644
--- a/src/System.Memory/tests/ReadOnlySpan/DangerousCreate.cs
+++ b/src/System.Memory/tests/MemoryMarshal/CreateReadOnlySpan.cs
@@ -10,10 +10,10 @@ using static System.TestHelpers;
namespace System.SpanTests
{
- public static partial class ReadOnlySpanTests
+ public static partial class MemoryMarshalTests
{
[Fact]
- public static void DangerousCreate1()
+ public static void CreateReadOnlySpan()
{
TestClass testClass = new TestClass
{
@@ -23,11 +23,21 @@ namespace System.SpanTests
C3 = 'd',
C4 = 'e'
};
- ReadOnlySpan<char> span = ReadOnlySpan<char>.DangerousCreate(testClass, ref testClass.C1, 3);
+ ReadOnlySpan<char> span = MemoryMarshal.CreateReadOnlySpan<char>(ref testClass.C1, 3);
span.Validate('b', 'c', 'd');
ref char pc1 = ref Unsafe.AsRef(in MemoryMarshal.GetReference(span));
Assert.True(Unsafe.AreSame(ref testClass.C1, ref pc1));
}
+
+ [Fact]
+ public static void ReadOnlySpanGetReferencePointerCreateReadOnlySpan()
+ {
+ TestClass testClass = new TestClass();
+ ReadOnlySpan<char> span = MemoryMarshal.CreateReadOnlySpan<char>(ref testClass.C1, 3);
+
+ ref char pinnableReference = ref Unsafe.AsRef(in MemoryMarshal.GetReference(span));
+ Assert.True(Unsafe.AreSame(ref testClass.C1, ref pinnableReference));
+ }
}
}
diff --git a/src/System.Memory/tests/Span/DangerousCreate.cs b/src/System.Memory/tests/MemoryMarshal/CreateSpan.cs
index ad6e968b8b..05672a6ae9 100644
--- a/src/System.Memory/tests/Span/DangerousCreate.cs
+++ b/src/System.Memory/tests/MemoryMarshal/CreateSpan.cs
@@ -10,10 +10,10 @@ using static System.TestHelpers;
namespace System.SpanTests
{
- public static partial class SpanTests
+ public static partial class MemoryMarshalTests
{
[Fact]
- public static void DangerousCreate1()
+ public static void CreateSpan()
{
TestClass testClass = new TestClass
{
@@ -23,11 +23,22 @@ namespace System.SpanTests
C3 = 'd',
C4 = 'e'
};
- Span<char> span = Span<char>.DangerousCreate(testClass, ref testClass.C1, 3);
+ Span<char> span = MemoryMarshal.CreateSpan<char>(ref testClass.C1, 3);
span.Validate('b', 'c', 'd');
ref char pc1 = ref MemoryMarshal.GetReference(span);
Assert.True(Unsafe.AreSame(ref testClass.C1, ref pc1));
}
+
+ [Fact]
+ public static void SpanGetReferencePointerCreateSpan()
+ {
+ TestClass testClass = new TestClass();
+ Span<char> span = MemoryMarshal.CreateSpan<char>(ref testClass.C1, 3);
+
+ ref char pinnableReference = ref MemoryMarshal.GetReference(span);
+ Assert.True(Unsafe.AreSame(ref testClass.C1, ref pinnableReference));
+ }
+
}
}
diff --git a/src/System.Memory/tests/MemoryMarshal/GetReference.cs b/src/System.Memory/tests/MemoryMarshal/GetReference.cs
index 3993b353e0..1f5efc24f8 100644
--- a/src/System.Memory/tests/MemoryMarshal/GetReference.cs
+++ b/src/System.Memory/tests/MemoryMarshal/GetReference.cs
@@ -47,16 +47,6 @@ namespace System.SpanTests
}
[Fact]
- public static void SpanGetReferencePointerDangerousCreate1()
- {
- TestClass testClass = new TestClass();
- Span<char> span = Span<char>.DangerousCreate(testClass, ref testClass.C1, 3);
-
- ref char pinnableReference = ref MemoryMarshal.GetReference(span);
- Assert.True(Unsafe.AreSame(ref testClass.C1, ref pinnableReference));
- }
-
- [Fact]
public static void SpanGetReferenceEmpty()
{
unsafe
@@ -102,16 +92,6 @@ namespace System.SpanTests
}
[Fact]
- public static void ReadOnlySpanGetReferencePointerDangerousCreate1()
- {
- TestClass testClass = new TestClass();
- ReadOnlySpan<char> span = ReadOnlySpan<char>.DangerousCreate(testClass, ref testClass.C1, 3);
-
- ref char pinnableReference = ref Unsafe.AsRef(in MemoryMarshal.GetReference(span));
- Assert.True(Unsafe.AreSame(ref testClass.C1, ref pinnableReference));
- }
-
- [Fact]
public static void ReadOnlySpanGetReferenceEmpty()
{
unsafe
diff --git a/src/System.Memory/tests/MemoryMarshal/ToEnumerable.cs b/src/System.Memory/tests/MemoryMarshal/ToEnumerable.cs
new file mode 100644
index 0000000000..afb86d69a7
--- /dev/null
+++ b/src/System.Memory/tests/MemoryMarshal/ToEnumerable.cs
@@ -0,0 +1,90 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using Xunit;
+using System.Linq;
+using System.Runtime.InteropServices;
+
+namespace System.MemoryTests
+{
+ public static partial class MemoryTests
+ {
+ [Fact]
+ public static void ToEnumerable()
+ {
+ int[] a = { 91, 92, 93 };
+ var memory = new Memory<int>(a);
+ IEnumerable<int> copy = MemoryMarshal.ToEnumerable<int>(memory);
+ Assert.Equal<int>(a, copy);
+ }
+
+ [Fact]
+ public static void ToEnumerableWithIndex()
+ {
+ int[] a = { 91, 92, 93, 94, 95 };
+ var memory = new Memory<int>(a);
+ IEnumerable<int> copy = MemoryMarshal.ToEnumerable<int>(memory.Slice(2));
+
+ Assert.Equal<int>(new int[] { 93, 94, 95 }, copy);
+ }
+
+ [Fact]
+ public static void ToEnumerableWithIndexAndLength()
+ {
+ int[] a = { 91, 92, 93 };
+ var memory = new Memory<int>(a, 1, 1);
+ IEnumerable<int> copy = MemoryMarshal.ToEnumerable<int>(memory);
+ Assert.Equal<int>(new int[] { 92 }, copy);
+ }
+
+ [Fact]
+ public static void ToEnumerableEmpty()
+ {
+ Memory<int> memory = Memory<int>.Empty;
+ IEnumerable<int> copy = MemoryMarshal.ToEnumerable<int>(memory);
+ Assert.Equal(0, copy.Count());
+ }
+
+ [Fact]
+ public static void ToEnumerableDefault()
+ {
+ Memory<int> memory = default;
+ IEnumerable<int> copy = MemoryMarshal.ToEnumerable<int>(memory);
+ Assert.Equal(0, copy.Count());
+ }
+
+ [Fact]
+ public static void ToEnumerableForEach()
+ {
+ int[] a = { 91, 92, 93 };
+ var memory = new Memory<int>(a);
+ int index = 0;
+ foreach (int curr in MemoryMarshal.ToEnumerable<int>(memory))
+ {
+ Assert.Equal(a[index++], curr);
+ }
+ }
+
+ [Fact]
+ public static void ToEnumerableGivenToExistingConstructor()
+ {
+ int[] a = { 91, 92, 93 };
+ var memory = new Memory<int>(a);
+ IEnumerable<int> enumer = MemoryMarshal.ToEnumerable<int>(memory);
+ var li = new List<int>(enumer);
+ Assert.Equal(a, li);
+ }
+
+ [Fact]
+ public static void ToEnumerableSameAsIEnumerator()
+ {
+ int[] a = { 91, 92, 93 };
+ var memory = new Memory<int>(a);
+ IEnumerable<int> enumer = MemoryMarshal.ToEnumerable<int>(memory);
+ IEnumerator<int> enumerat = enumer.GetEnumerator();
+ Assert.Same(enumer, enumerat);
+ }
+ }
+}
diff --git a/src/System.Memory/tests/MemoryMarshal/TryGetArray.cs b/src/System.Memory/tests/MemoryMarshal/TryGetArray.cs
index ebdc2ce438..0443ed7a6e 100644
--- a/src/System.Memory/tests/MemoryMarshal/TryGetArray.cs
+++ b/src/System.Memory/tests/MemoryMarshal/TryGetArray.cs
@@ -28,8 +28,8 @@ namespace System.MemoryTests
public static void TryGetArrayFromDefaultMemory()
{
ReadOnlyMemory<int> memory = default;
- Assert.False(MemoryMarshal.TryGetArray(memory, out ArraySegment<int> segment));
- Assert.True(segment.Equals(default));
+ Assert.True(MemoryMarshal.TryGetArray(memory, out ArraySegment<int> segment));
+ Assert.Equal(0, segment.Array.Length);
}
[Fact]
@@ -46,5 +46,40 @@ namespace System.MemoryTests
Assert.Equal(array[i], segment.Array[i]);
}
}
+
+ [Fact]
+ public static void TryGetArrayFromEmptyMemory()
+ {
+ int[] array = new int[0];
+ ReadOnlyMemory<int> memory = array;
+
+ Assert.True(MemoryMarshal.TryGetArray(memory, out ArraySegment<int> segment));
+ Assert.Same(array, segment.Array);
+ Assert.Equal(0, segment.Array.Length);
+
+ Assert.True(MemoryMarshal.TryGetArray(ReadOnlyMemory<byte>.Empty, out ArraySegment<byte> byteSegment));
+ Assert.Equal(0, byteSegment.Array.Length);
+ }
+
+ [Fact]
+ public static void TryGetArrayFromEmptyOwnedMemory()
+ {
+ int[] array = new int[0];
+ OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
+
+ Assert.True(MemoryMarshal.TryGetArray(owner.Memory, out ArraySegment<int> segment));
+ Assert.Same(array, segment.Array);
+ Assert.Equal(0, segment.Array.Length);
+ }
+
+ [Fact]
+ public static void TryGetArrayFromEmptyNonRetrievableOwnedMemory()
+ {
+ using (var owner = new NativeOwnedMemory(0))
+ {
+ Assert.True(MemoryMarshal.TryGetArray(owner.Memory, out ArraySegment<byte> segment));
+ Assert.Equal(0, segment.Array.Length);
+ }
+ }
}
}
diff --git a/src/System.Memory/tests/MemoryMarshal/TryGetOwnedMemory.cs b/src/System.Memory/tests/MemoryMarshal/TryGetOwnedMemory.cs
new file mode 100644
index 0000000000..c786042f02
--- /dev/null
+++ b/src/System.Memory/tests/MemoryMarshal/TryGetOwnedMemory.cs
@@ -0,0 +1,93 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Runtime.InteropServices;
+using Xunit;
+
+namespace System.MemoryTests
+{
+ public static partial class MemoryMarshalTests
+ {
+ [Fact]
+ public static void TryGetOwnedMemoryFromDefaultMemory()
+ {
+ ReadOnlyMemory<int> memory = default;
+ Assert.False(MemoryMarshal.TryGetOwnedMemory(memory, out OwnedMemory<int> owner));
+ Assert.Null(owner);
+ }
+
+ [Fact]
+ public static void TryGetOwnedMemory()
+ {
+ int[] array = new int[10];
+ OwnedMemory<int> orignalOwner = new CustomMemoryForTest<int>(array);
+ ReadOnlyMemory<int> memory = orignalOwner.Memory;
+
+ Assert.True(MemoryMarshal.TryGetOwnedMemory(memory, out CustomMemoryForTest<int> customOwner));
+ Assert.Same(orignalOwner, customOwner);
+
+ Assert.True(MemoryMarshal.TryGetOwnedMemory(memory, out OwnedMemory<int> owner));
+ Assert.Same(orignalOwner, owner);
+
+ Assert.False(MemoryMarshal.TryGetOwnedMemory(memory, out OtherMemoryForTest<int> notOwner));
+ Assert.Null(notOwner);
+ }
+
+ [Fact]
+ public static void TryGetOwnedMemoryFromDefaultMemory_IndexLength()
+ {
+ ReadOnlyMemory<int> memory = default;
+ Assert.False(MemoryMarshal.TryGetOwnedMemory(memory, out OwnedMemory<int> owner, out int index, out int length));
+ Assert.Equal(0, index);
+ Assert.Equal(0, length);
+ Assert.Null(owner);
+ }
+
+ [Fact]
+ public static void TryGetOwnedMemory_IndexLength()
+ {
+ int[] array = new int[10];
+ OwnedMemory<int> orignalOwner = new CustomMemoryForTest<int>(array);
+ ReadOnlyMemory<int> memory = orignalOwner.Memory;
+
+ for (int i = 0; i < array.Length; i++)
+ {
+ Assert.True(MemoryMarshal.TryGetOwnedMemory(memory.Slice(i), out CustomMemoryForTest<int> customOwner, out int index, out int length));
+ Assert.Same(orignalOwner, customOwner);
+ Assert.Equal(i, index);
+ Assert.Equal(array.Length - i, length);
+ }
+
+ for (int i = 0; i < array.Length; i++)
+ {
+ Assert.True(MemoryMarshal.TryGetOwnedMemory(memory.Slice(i), out OwnedMemory<int> owner, out int index, out int length));
+ Assert.Same(orignalOwner, owner);
+ Assert.Equal(i, index);
+ Assert.Equal(array.Length - i, length);
+ }
+
+ for (int i = 0; i < array.Length; i++)
+ {
+ Assert.False(MemoryMarshal.TryGetOwnedMemory(memory.Slice(i), out OtherMemoryForTest<int> notOwner, out int index, out int length));
+ Assert.Null(notOwner);
+ }
+ }
+
+ internal class OtherMemoryForTest<T> : OwnedMemory<T>
+ {
+ public OtherMemoryForTest() { }
+
+ public override int Length => 0;
+ public override bool IsDisposed => false;
+ protected override bool IsRetained => false;
+ public override Span<T> Span => throw new NotImplementedException();
+ public override MemoryHandle Pin(int byteOffset = 0) => throw new NotImplementedException();
+ protected override bool TryGetArray(out ArraySegment<T> segment) => throw new NotImplementedException();
+ protected override void Dispose(bool disposing) => throw new NotImplementedException();
+ public override void Retain() => throw new NotImplementedException();
+ public override bool Release() => throw new NotImplementedException();
+ }
+ }
+}
diff --git a/src/System.Memory/tests/MemoryMarshal/TryGetString.cs b/src/System.Memory/tests/MemoryMarshal/TryGetString.cs
new file mode 100644
index 0000000000..02c55569f2
--- /dev/null
+++ b/src/System.Memory/tests/MemoryMarshal/TryGetString.cs
@@ -0,0 +1,73 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+using System.Runtime.InteropServices;
+
+namespace System.MemoryTests
+{
+ public static partial class MemoryMarshalTests
+ {
+ [Fact]
+ public static void ReadOnlyMemory_TryGetString_Roundtrips()
+ {
+ string input = "0123456789";
+ ReadOnlyMemory<char> m = input.AsMemory();
+ Assert.False(m.IsEmpty);
+
+ Assert.True(MemoryMarshal.TryGetString(m, out string text, out int start, out int length));
+ Assert.Same(input, text);
+ Assert.Equal(0, start);
+ Assert.Equal(input.Length, length);
+
+ m = m.Slice(1);
+ Assert.True(MemoryMarshal.TryGetString(m, out text, out start, out length));
+ Assert.Same(input, text);
+ Assert.Equal(1, start);
+ Assert.Equal(input.Length - 1, length);
+
+ m = m.Slice(1);
+ Assert.True(MemoryMarshal.TryGetString(m, out text, out start, out length));
+ Assert.Same(input, text);
+ Assert.Equal(2, start);
+ Assert.Equal(input.Length - 2, length);
+
+ m = m.Slice(3, 2);
+ Assert.True(MemoryMarshal.TryGetString(m, out text, out start, out length));
+ Assert.Same(input, text);
+ Assert.Equal(5, start);
+ Assert.Equal(2, length);
+
+ m = m.Slice(m.Length);
+ Assert.True(MemoryMarshal.TryGetString(m, out text, out start, out length));
+ Assert.Same(input, text);
+ Assert.Equal(7, start);
+ Assert.Equal(0, length);
+
+ m = m.Slice(0);
+ Assert.True(MemoryMarshal.TryGetString(m, out text, out start, out length));
+ Assert.Same(input, text);
+ Assert.Equal(7, start);
+ Assert.Equal(0, length);
+
+ m = m.Slice(0, 0);
+ Assert.True(MemoryMarshal.TryGetString(m, out text, out start, out length));
+ Assert.Same(input, text);
+ Assert.Equal(7, start);
+ Assert.Equal(0, length);
+
+ Assert.True(m.IsEmpty);
+ }
+
+ [Fact]
+ public static void Array_TryGetString_ReturnsFalse()
+ {
+ ReadOnlyMemory<char> m = new char[10];
+ Assert.False(MemoryMarshal.TryGetString(m, out string text, out int start, out int length));
+ Assert.Null(text);
+ Assert.Equal(0, start);
+ Assert.Equal(0, length);
+ }
+ }
+}
diff --git a/src/System.Memory/tests/MemoryPool/MemoryPool.cs b/src/System.Memory/tests/MemoryPool/MemoryPool.cs
new file mode 100644
index 0000000000..63d3419972
--- /dev/null
+++ b/src/System.Memory/tests/MemoryPool/MemoryPool.cs
@@ -0,0 +1,345 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using Xunit;
+
+namespace System.MemoryTests
+{
+ public static partial class MemoryPoolTests
+ {
+ [Fact]
+ public static void ThereIsOnlyOneSharedPool()
+ {
+ MemoryPool<int> mp1 = MemoryPool<int>.Shared;
+ MemoryPool<int> mp2 = MemoryPool<int>.Shared;
+ Assert.Same(mp1, mp2);
+ }
+
+ [Fact]
+ public static void DisposingTheSharedPoolIsANop()
+ {
+ MemoryPool<int> mp = MemoryPool<int>.Shared;
+ mp.Dispose();
+ mp.Dispose();
+ using (OwnedMemory<int> block = mp.Rent(10))
+ {
+ Assert.True(block.Length >= 10);
+ block.Release();
+ }
+ }
+
+ [Fact]
+ public static void RentWithTooLargeASize()
+ {
+ MemoryPool<int> pool = MemoryPool<int>.Shared;
+ Assert.Throws<ArgumentOutOfRangeException>(() => pool.Rent(pool.MaxBufferSize + 1));
+ }
+
+ [Fact]
+ public static void MemoryPoolSpan()
+ {
+ MemoryPool<int> pool = MemoryPool<int>.Shared;
+ using (OwnedMemory<int> block = pool.Rent(10))
+ {
+ Span<int> sp = block.Span;
+ Assert.Equal(block.Length, sp.Length);
+ using (MemoryHandle newMemoryHandle = block.Pin())
+ {
+ unsafe
+ {
+ void* pSpan = Unsafe.AsPointer(ref MemoryMarshal.GetReference(sp));
+ Assert.Equal((IntPtr)newMemoryHandle.Pointer, (IntPtr)pSpan);
+ }
+ }
+ block.Release();
+ }
+ }
+
+ [Theory]
+ [InlineData(0)]
+ [InlineData(3)]
+ [InlineData(10 * sizeof(int))]
+ public static void MemoryPoolPin(int byteOffset)
+ {
+ MemoryPool<int> pool = MemoryPool<int>.Shared;
+ using (OwnedMemory<int> block = pool.Rent(10))
+ {
+ Span<int> sp = block.Span;
+ Assert.Equal(block.Length, sp.Length);
+ using (MemoryHandle newMemoryHandle = block.Pin(byteOffset: byteOffset))
+ {
+ unsafe
+ {
+ void* pSpan = Unsafe.AsPointer(ref MemoryMarshal.GetReference(sp));
+ Assert.Equal((IntPtr)pSpan, ((IntPtr)newMemoryHandle.Pointer) - byteOffset);
+ }
+ }
+ block.Release();
+ }
+ }
+
+ [Theory]
+ [InlineData(-1)]
+ [InlineData(int.MinValue)]
+ public static void MemoryPoolPinBadOffset(int byteOffset)
+ {
+ MemoryPool<int> pool = MemoryPool<int>.Shared;
+ OwnedMemory<int> block = pool.Rent(10);
+ Span<int> sp = block.Span;
+ Assert.Equal(block.Length, sp.Length);
+ Assert.Throws<ArgumentOutOfRangeException>(() => block.Pin(byteOffset: byteOffset));
+ }
+
+ [Fact]
+ public static void MemoryPoolPinOffsetAtEnd()
+ {
+ MemoryPool<int> pool = MemoryPool<int>.Shared;
+ OwnedMemory<int> block = pool.Rent(10);
+ Span<int> sp = block.Span;
+ Assert.Equal(block.Length, sp.Length);
+
+ int byteOffset = 0;
+ try
+ {
+ byteOffset = checked(block.Length * sizeof(int));
+ }
+ catch (OverflowException)
+ {
+ return; // The pool gave us a very large block - too big to compute the byteOffset needed to carry out this test. Skip.
+ }
+
+ using (MemoryHandle newMemoryHandle = block.Pin(byteOffset: byteOffset))
+ {
+ unsafe
+ {
+ void* pSpan = Unsafe.AsPointer(ref MemoryMarshal.GetReference(sp));
+ Assert.Equal((IntPtr)pSpan, ((IntPtr)newMemoryHandle.Pointer) - byteOffset);
+ }
+ }
+ }
+
+ [Fact]
+ public static void MemoryPoolPinBadOffsetTooLarge()
+ {
+ MemoryPool<int> pool = MemoryPool<int>.Shared;
+ OwnedMemory<int> block = pool.Rent(10);
+ Span<int> sp = block.Span;
+ Assert.Equal(block.Length, sp.Length);
+
+ int byteOffset = 0;
+ try
+ {
+ byteOffset = checked(block.Length * sizeof(int) + 1);
+ }
+ catch (OverflowException)
+ {
+ return; // The pool gave us a very large block - too big to compute the byteOffset needed to carry out this test. Skip.
+ }
+
+ Assert.Throws<ArgumentOutOfRangeException>(() => block.Pin(byteOffset: byteOffset));
+ }
+
+ [Fact]
+ public static void EachRentalIsUniqueUntilDisposed()
+ {
+ MemoryPool<int> pool = MemoryPool<int>.Shared;
+ List<OwnedMemory<int>> priorBlocks = new List<OwnedMemory<int>>();
+
+ Random r = new Random(42);
+ List<int> testInputs = new List<int>();
+ for (int i = 0; i < 100; i++)
+ {
+ testInputs.Add((Math.Abs(r.Next() % 1000)) + 1);
+ }
+
+ foreach (int minBufferSize in testInputs)
+ {
+ OwnedMemory<int> newBlock = pool.Rent(minBufferSize);
+ Assert.True(newBlock.Length >= minBufferSize);
+
+ foreach (OwnedMemory<int> prior in priorBlocks)
+ {
+ using (MemoryHandle priorMemoryHandle = prior.Pin())
+ {
+ using (MemoryHandle newMemoryHandle = newBlock.Pin())
+ {
+ unsafe
+ {
+ Assert.NotEqual((IntPtr)priorMemoryHandle.Pointer, (IntPtr)newMemoryHandle.Pointer);
+ }
+ }
+ }
+ }
+ priorBlocks.Add(newBlock);
+ }
+
+ foreach (OwnedMemory<int> prior in priorBlocks)
+ {
+ prior.Release();
+ prior.Dispose();
+ }
+ }
+
+ [Fact]
+ public static void RentWithDefaultSize()
+ {
+ using (OwnedMemory<int> block = MemoryPool<int>.Shared.Rent(minBufferSize: -1))
+ {
+ Assert.True(block.Length >= 1);
+ block.Release();
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(BadSizes))]
+ public static void RentBadSizes(int badSize)
+ {
+ MemoryPool<int> pool = MemoryPool<int>.Shared;
+ Assert.Throws<ArgumentOutOfRangeException>(() => pool.Rent(minBufferSize: badSize));
+ }
+
+ public static IEnumerable<object[]> BadSizes
+ {
+ get
+ {
+ yield return new object[] { -2 };
+ yield return new object[] { int.MinValue };
+ }
+ }
+
+ [Fact]
+ public static void MemoryPoolTryGetArray()
+ {
+ using (OwnedMemory<int> block = MemoryPool<int>.Shared.Rent(42))
+ {
+ Memory<int> memory = block.Memory;
+ bool success = MemoryMarshal.TryGetArray(memory, out ArraySegment<int> arraySegment);
+ Assert.True(success);
+ Assert.Equal(block.Length, arraySegment.Count);
+ unsafe
+ {
+ void* pSpan = Unsafe.AsPointer(ref MemoryMarshal.GetReference(block.Span));
+ fixed (int* pArray = arraySegment.Array)
+ {
+ Assert.Equal((IntPtr)pSpan, (IntPtr)pArray);
+ }
+ }
+ block.Release();
+ }
+ }
+
+ [Fact]
+ public static void RefCounting()
+ {
+ using (OwnedMemory<int> block = MemoryPool<int>.Shared.Rent(42))
+ {
+ block.Retain();
+ block.Retain();
+ block.Retain();
+
+ bool moreToGo;
+ moreToGo = block.Release();
+ Assert.True(moreToGo);
+
+ moreToGo = block.Release();
+ Assert.True(moreToGo);
+
+ moreToGo = block.Release();
+ Assert.True(moreToGo);
+
+ moreToGo = block.Release();
+ Assert.False(moreToGo);
+
+ Assert.Throws<ObjectDisposedException>(() => block.Release());
+ }
+ }
+
+ [Fact]
+ public static void IsDisposed()
+ {
+ OwnedMemory<int> block = MemoryPool<int>.Shared.Rent(42);
+ Assert.False(block.IsDisposed);
+ block.Release();
+ Assert.True(block.IsDisposed);
+ block.Dispose();
+ Assert.True(block.IsDisposed);
+ }
+
+ [Fact]
+ public static void ExtraDisposesAreIgnored()
+ {
+ OwnedMemory<int> block = MemoryPool<int>.Shared.Rent(42);
+ block.Release();
+ block.Dispose();
+ block.Dispose();
+ }
+
+ [Fact]
+ public static void NoSpanAfterDispose()
+ {
+ OwnedMemory<int> block = MemoryPool<int>.Shared.Rent(42);
+ block.Release();
+ block.Dispose();
+ Assert.Throws<ObjectDisposedException>(() => block.Span.DontBox());
+ }
+
+ [Fact]
+ public static void NoRetainAfterDispose()
+ {
+ OwnedMemory<int> block = MemoryPool<int>.Shared.Rent(42);
+ block.Release();
+ block.Dispose();
+ Assert.Throws<ObjectDisposedException>(() => block.Retain());
+ }
+
+ [Fact]
+ public static void NoRelease_AfterDispose()
+ {
+ OwnedMemory<int> block = MemoryPool<int>.Shared.Rent(42);
+ block.Release();
+ block.Dispose();
+ Assert.Throws<ObjectDisposedException>(() => block.Release());
+ }
+
+ [Fact]
+ public static void NoPinAfterDispose()
+ {
+ OwnedMemory<int> block = MemoryPool<int>.Shared.Rent(42);
+ block.Release();
+ block.Dispose();
+ Assert.Throws<ObjectDisposedException>(() => block.Pin());
+ }
+
+ [Fact]
+ public static void NoTryGetArrayAfterDispose()
+ {
+ OwnedMemory<int> block = MemoryPool<int>.Shared.Rent(42);
+ Memory<int> memory = block.Memory;
+ block.Release();
+ block.Dispose();
+ Assert.Throws<ObjectDisposedException>(() => MemoryMarshal.TryGetArray(memory, out ArraySegment<int> arraySegment));
+ }
+
+ [Fact]
+ public static void IsRetainedWhenReturned()
+ {
+ OwnedMemory<int> block = MemoryPool<int>.Shared.Rent(42);
+ Assert.False(block.Release());
+ }
+
+ [Fact]
+ public static void IsDisposedWhenReleased()
+ {
+ OwnedMemory<int> block = MemoryPool<int>.Shared.Rent(42);
+ block.Release();
+
+ Assert.True(block.IsDisposed);
+ }
+ }
+}
+
diff --git a/src/System.Memory/tests/ParsersAndFormatters/Parser/ParserTests.2gbOverflow.cs b/src/System.Memory/tests/ParsersAndFormatters/Parser/ParserTests.2gbOverflow.cs
index 6981d9ab8c..a47934c671 100644
--- a/src/System.Memory/tests/ParsersAndFormatters/Parser/ParserTests.2gbOverflow.cs
+++ b/src/System.Memory/tests/ParsersAndFormatters/Parser/ParserTests.2gbOverflow.cs
@@ -93,20 +93,11 @@ namespace System.Buffers.Text.Tests
{
get
{
- yield return new ParserTestData<int>("0", 0, 'D', expectedSuccess: true) { ExpectedBytesConsumed = TwoGiB };
- yield return new ParserTestData<int>("2", 2, 'D', expectedSuccess: true) { ExpectedBytesConsumed = TwoGiB };
- yield return new ParserTestData<int>("21", 21, 'D', expectedSuccess: true) { ExpectedBytesConsumed = TwoGiB };
- yield return new ParserTestData<int>("+2", 2, 'D', expectedSuccess: true) { ExpectedBytesConsumed = TwoGiB };
yield return new ParserTestData<int>("-2", -2, 'D', expectedSuccess: true) { ExpectedBytesConsumed = TwoGiB };
yield return new ParserTestData<int>("2147483647", 2147483647, 'D', expectedSuccess: true) { ExpectedBytesConsumed = TwoGiB };
- yield return new ParserTestData<int>("-2147483648", -2147483648, 'D', expectedSuccess: true) { ExpectedBytesConsumed = TwoGiB };
yield return new ParserTestData<int>("2147483648", default, 'D', expectedSuccess: false);
- yield return new ParserTestData<int>("-2147483649", default, 'D', expectedSuccess: false);
yield return new ParserTestData<int>("12345abcdefg1", 12345, 'D', expectedSuccess: true) { ExpectedBytesConsumed = TwoGiB - 8 };
- yield return new ParserTestData<int>("1234145abcdefg1", 1234145, 'D', expectedSuccess: true) { ExpectedBytesConsumed = TwoGiB - 8 };
yield return new ParserTestData<int>("abcdefghijklmnop1", 0, 'D', expectedSuccess: true) { ExpectedBytesConsumed = TwoGiB - 17 };
- yield return new ParserTestData<int>("1147483648", 1147483648, 'D', expectedSuccess: true) { ExpectedBytesConsumed = TwoGiB };
- yield return new ParserTestData<int>("-1147483649", -1147483649, 'D', expectedSuccess: true) { ExpectedBytesConsumed = TwoGiB };
}
}
}
diff --git a/src/System.Memory/tests/ParsersAndFormatters/Parser/ParserTests.cs b/src/System.Memory/tests/ParsersAndFormatters/Parser/ParserTests.cs
index 1da5faf7a1..3024f6b2b4 100644
--- a/src/System.Memory/tests/ParsersAndFormatters/Parser/ParserTests.cs
+++ b/src/System.Memory/tests/ParsersAndFormatters/Parser/ParserTests.cs
@@ -131,30 +131,6 @@ namespace System.Buffers.Text.Tests
ReadOnlySpan<byte> utf8Text = text.ToUtf8Span();
Utf8Parser.TryParse(utf8Text, out DateTimeOffset dto, out int bytesConsumed, formatSymbol);
}
-
- [Theory]
- [MemberData(nameof(TestData.IntegerTypesTheoryData), MemberType = typeof(TestData))]
- public static void FakeTestParserIntegerN(Type integerType)
- {
- //
- // [ActiveIssue("https://github.com/dotnet/corefx/issues/24986 - UTF8Parser parsing integers with 'N' format not implemented.")]
- //
- // This "test" may look ludicrous but it serves two useful purposes:
- //
- // - It maintains Utf8Parser code coverage at 100% so that endless dev cycles aren't wasted drilling down into it to inspect for code coverage regressions.
- //
- // - As a guide to enabling the 'N' tests when the parsing is implemented.
- //
- try
- {
- TryParseUtf8(integerType, Array.Empty<byte>(), out _, out _, 'N');
- Assert.False(true,
- $"Thank you for implementing the TryParse 'N' format. You can now disable this test and change {nameof(TestData.IsParsingImplemented)}() so it no longer suppresses 'N' testing.");
- }
- catch (NotImplementedException)
- {
- }
- }
}
}
diff --git a/src/System.Memory/tests/ParsersAndFormatters/Parser/TestData.Parser.Integer.cs b/src/System.Memory/tests/ParsersAndFormatters/Parser/TestData.Parser.Integer.cs
index 8e12d876b3..e5fe562305 100644
--- a/src/System.Memory/tests/ParsersAndFormatters/Parser/TestData.Parser.Integer.cs
+++ b/src/System.Memory/tests/ParsersAndFormatters/Parser/TestData.Parser.Integer.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Linq;
+using System.Globalization;
using System.Numerics;
using System.Collections.Generic;
@@ -212,8 +213,8 @@ namespace System.Buffers.Text.Tests
for (int offset = -20; offset <= 0; offset++)
{
BigInteger bigValue = maxValue + offset;
- string textD = bigValue.ToString("D");
- string text = bigValue.ToString(format.Symbol.ToString());
+ string textD = bigValue.ToString("D", CultureInfo.InvariantCulture);
+ string text = bigValue.ToString(format.Symbol.ToString(), CultureInfo.InvariantCulture);
T expectedValue = (T)(Convert.ChangeType(textD, typeof(T)));
yield return new ParserTestData<T>(text, expectedValue, format.Symbol, expectedSuccess: true);
}
@@ -222,13 +223,13 @@ namespace System.Buffers.Text.Tests
for (int offset = 1; offset <= 20; offset++)
{
BigInteger bigValue = maxValue + offset;
- string text = bigValue.ToString(format.Symbol.ToString());
+ string text = bigValue.ToString(format.Symbol.ToString(), CultureInfo.InvariantCulture);
yield return new ParserTestData<T>(text, default, format.Symbol, expectedSuccess: false);
}
{
BigInteger bigValue = maxValue * 10;
- string text = bigValue.ToString(format.Symbol.ToString());
+ string text = bigValue.ToString(format.Symbol.ToString(), CultureInfo.InvariantCulture);
yield return new ParserTestData<T>(text, default, format.Symbol, expectedSuccess: false);
}
@@ -238,8 +239,8 @@ namespace System.Buffers.Text.Tests
for (int offset = 0; offset <= 20; offset++)
{
BigInteger bigValue = minValue + offset;
- string textD = bigValue.ToString("D");
- string text = bigValue.ToString(format.Symbol.ToString());
+ string textD = bigValue.ToString("D", CultureInfo.InvariantCulture);
+ string text = bigValue.ToString(format.Symbol.ToString(), CultureInfo.InvariantCulture);
T expectedValue = (T)(Convert.ChangeType(textD, typeof(T)));
yield return new ParserTestData<T>(text, expectedValue, format.Symbol, expectedSuccess: true);
}
@@ -248,18 +249,95 @@ namespace System.Buffers.Text.Tests
for (int offset = -20; offset <= -1; offset++)
{
BigInteger bigValue = minValue + offset;
- string text = bigValue.ToString(format.Symbol.ToString());
+ string text = bigValue.ToString(format.Symbol.ToString(), CultureInfo.InvariantCulture);
yield return new ParserTestData<T>(text, default, format.Symbol, expectedSuccess: false);
}
{
BigInteger bigValue = minValue * 10;
- string text = bigValue.ToString(format.Symbol.ToString());
+ string text = bigValue.ToString(format.Symbol.ToString(), CultureInfo.InvariantCulture);
yield return new ParserTestData<T>(text, default, format.Symbol, expectedSuccess: false);
}
}
}
+
+ if (format.Symbol == 'N' || format.Symbol == 'n')
+ {
+ // "N" format parsing
+ foreach (ParserTestData<T> testData in TestDataForNFormat.ConvertTestDataForNFormat<T>())
+ {
+ yield return testData;
+ }
+ }
+ }
+ }
+
+ // Test data specific to the "N" format. This set is up-converted and reused for all the integer types.
+ // Non-N-specific issues like overflow and underflow detection are already covered by GeneralIntegerParserTestData().
+ private static IEnumerable<ParserTestData<sbyte>> TestDataForNFormat
+ {
+ get
+ {
+ yield return new ParserTestData<sbyte>("12,3", 123, 'N', expectedSuccess: true);
+ yield return new ParserTestData<sbyte>("1,0,4", 104, 'N', expectedSuccess: true);
+
+ yield return new ParserTestData<sbyte>("1,,23", 123, 'N', expectedSuccess: true); // Comma placement is completely flexible.
+ yield return new ParserTestData<sbyte>("+1,,23", 123, 'N', expectedSuccess: true); // Comma placement is completely flexible.
+ yield return new ParserTestData<sbyte>("-1,,23", -123, 'N', expectedSuccess: true); // Comma placement is completely flexible.
+
+ yield return new ParserTestData<sbyte>(",234", default, 'N', expectedSuccess: false); // Leading comma not allowed.
+ yield return new ParserTestData<sbyte>("+,234", default, 'N', expectedSuccess: false); // Leading comma not allowed.
+ yield return new ParserTestData<sbyte>("-,234", default, 'N', expectedSuccess: false); // Leading comma not allowed.
+
+ yield return new ParserTestData<sbyte>("104,", 104, 'N', expectedSuccess: true); // Trailing comma is allowed.
+ yield return new ParserTestData<sbyte>("104,,", 104, 'N', expectedSuccess: true); // Trailing comma is allowed.
+ yield return new ParserTestData<sbyte>("104,.00", 104, 'N', expectedSuccess: true); // Trailing comma is allowed.
+
+ yield return new ParserTestData<sbyte>(".", default, 'N', expectedSuccess: false); // Standalone period not allowed.
+ yield return new ParserTestData<sbyte>(".0", 0, 'N', expectedSuccess: true); // But missing digits on either side allowed (as long as not both)
+ yield return new ParserTestData<sbyte>("5.", 5, 'N', expectedSuccess: true); // But missing digits on either side allowed (as long as not both)
+
+ yield return new ParserTestData<sbyte>("+", default, 'N', expectedSuccess: false); // Standalone sign symbol not allowed
+ yield return new ParserTestData<sbyte>("-", default, 'N', expectedSuccess: false); // Standalone sign symbol not allowed
+
+ yield return new ParserTestData<sbyte>("2.000000000000000000000000000000000", 2, 'N', expectedSuccess: true); // Decimal portion allowed as long as its 0.
+ yield return new ParserTestData<sbyte>("2.000000000000000000000000000000001", default, 'N', expectedSuccess: false);
+ yield return new ParserTestData<sbyte>(".1", default, 'N', expectedSuccess: false);
+
+ yield return new ParserTestData<sbyte>("2.0,0", 2, 'N', expectedSuccess: true) { ExpectedBytesConsumed = 3 }; // Commas must appear before the decimal point, not after.
}
}
+
+ private static IEnumerable<ParserTestData<T>> ConvertTestDataForNFormat<T>(this IEnumerable<ParserTestData<sbyte>> testData) => testData.Select(td => td.ConvertTestDataForNFormat<T>());
+
+ private static ParserTestData<T> ConvertTestDataForNFormat<T>(this ParserTestData<sbyte> testData)
+ {
+ Type t = typeof(T);
+ bool isSignedType = t == typeof(sbyte) || t == typeof(short) || t == typeof(int) || t == typeof(long);
+ if (testData.ExpectedValue < 0 && !isSignedType)
+ return new ParserTestData<T>(testData.Text, default, testData.FormatSymbol, expectedSuccess: false); // Unsigned parsers will never produce negative values.
+
+ T convertedValue;
+ if (t == typeof(sbyte))
+ convertedValue = (T)(object)testData.ExpectedValue;
+ else if (t == typeof(byte))
+ convertedValue = (T)(object)Convert.ToByte(testData.ExpectedValue);
+ else if (t == typeof(short))
+ convertedValue = (T)(object)Convert.ToInt16(testData.ExpectedValue);
+ else if (t == typeof(ushort))
+ convertedValue = (T)(object)Convert.ToUInt16(testData.ExpectedValue);
+ else if (t == typeof(int))
+ convertedValue = (T)(object)Convert.ToInt32(testData.ExpectedValue);
+ else if (t == typeof(uint))
+ convertedValue = (T)(object)Convert.ToUInt32(testData.ExpectedValue);
+ else if (t == typeof(long))
+ convertedValue = (T)(object)Convert.ToInt64(testData.ExpectedValue);
+ else if (t == typeof(ulong))
+ convertedValue = (T)(object)Convert.ToUInt64(testData.ExpectedValue);
+ else
+ throw new Exception("Not an integer type: " + t);
+
+ return new ParserTestData<T>(testData.Text, convertedValue, testData.FormatSymbol, testData.ExpectedSuccess) { ExpectedBytesConsumed = testData.ExpectedBytesConsumed };
+ }
}
}
diff --git a/src/System.Memory/tests/ParsersAndFormatters/Parser/TestData.Parser.TimeSpan.cs b/src/System.Memory/tests/ParsersAndFormatters/Parser/TestData.Parser.TimeSpan.cs
index 74fb809744..a471a90785 100644
--- a/src/System.Memory/tests/ParsersAndFormatters/Parser/TestData.Parser.TimeSpan.cs
+++ b/src/System.Memory/tests/ParsersAndFormatters/Parser/TestData.Parser.TimeSpan.cs
@@ -4,6 +4,7 @@
using System.Text;
using System.Linq;
+using System.Globalization;
using System.Collections.Generic;
namespace System.Buffers.Text.Tests
@@ -45,7 +46,7 @@ namespace System.Buffers.Text.Tests
StringBuilder sb = new StringBuilder();
for (int i = 0; i < numComponents; i++)
{
- sb.Append((20 + i).ToString());
+ sb.Append((20 + i).ToString("D", CultureInfo.InvariantCulture));
if (i != numComponents - 1)
{
char separator = ((separatorMask & (1 << i)) != 0) ? '.' : ':';
diff --git a/src/System.Memory/tests/ParsersAndFormatters/PseudoDateTime.cs b/src/System.Memory/tests/ParsersAndFormatters/PseudoDateTime.cs
index e546f3e809..36e2a8648e 100644
--- a/src/System.Memory/tests/ParsersAndFormatters/PseudoDateTime.cs
+++ b/src/System.Memory/tests/ParsersAndFormatters/PseudoDateTime.cs
@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Globalization;
+
namespace System.Buffers.Text.Tests
{
//
@@ -38,9 +40,9 @@ namespace System.Buffers.Text.Tests
if (Fraction != 0)
return null;
- return Month.ToString("D2") + "/" + Day.ToString("D2") + "/" + Year.ToString("D4") +
- " " + Hour.ToString("D2") + ":" + Minute.ToString("D2") + ":" + Second.ToString("D2") +
- " " + (OffsetNegative ? "-" : "+") + OffsetHours.ToString("D2") + ":" + OffsetMinutes.ToString("D2");
+ return Month.ToString("D2", CultureInfo.InvariantCulture) + "/" + Day.ToString("D2", CultureInfo.InvariantCulture) + "/" + Year.ToString("D4", CultureInfo.InvariantCulture) +
+ " " + Hour.ToString("D2", CultureInfo.InvariantCulture) + ":" + Minute.ToString("D2", CultureInfo.InvariantCulture) + ":" + Second.ToString("D2", CultureInfo.InvariantCulture) +
+ " " + (OffsetNegative ? "-" : "+") + OffsetHours.ToString("D2", CultureInfo.InvariantCulture) + ":" + OffsetMinutes.ToString("D2", CultureInfo.InvariantCulture);
}
}
@@ -53,8 +55,8 @@ namespace System.Buffers.Text.Tests
if (OffsetHours != 0 || OffsetMinutes != 0)
return null;
- return Month.ToString("D2") + "/" + Day.ToString("D2") + "/" + Year.ToString("D4") +
- " " + Hour.ToString("D2") + ":" + Minute.ToString("D2") + ":" + Second.ToString("D2");
+ return Month.ToString("D2", CultureInfo.InvariantCulture) + "/" + Day.ToString("D2", CultureInfo.InvariantCulture) + "/" + Year.ToString("D4", CultureInfo.InvariantCulture) +
+ " " + Hour.ToString("D2", CultureInfo.InvariantCulture) + ":" + Minute.ToString("D2", CultureInfo.InvariantCulture) + ":" + Second.ToString("D2", CultureInfo.InvariantCulture);
}
}
@@ -94,8 +96,8 @@ namespace System.Buffers.Text.Tests
monthAbbrevation = "Jan";
}
- return dayAbbreviation + ", " + Day.ToString("D2") + " " + monthAbbrevation + " " + Year.ToString("D4") + " "
- + Hour.ToString("D2") + ":" + Minute.ToString("D2") + ":" + Second.ToString("D2") + " "
+ return dayAbbreviation + ", " + Day.ToString("D2", CultureInfo.InvariantCulture) + " " + monthAbbrevation + " " + Year.ToString("D4", CultureInfo.InvariantCulture) + " "
+ + Hour.ToString("D2", CultureInfo.InvariantCulture) + ":" + Minute.ToString("D2", CultureInfo.InvariantCulture) + ":" + Second.ToString("D2", CultureInfo.InvariantCulture) + " "
+ "GMT";
}
}
@@ -109,8 +111,8 @@ namespace System.Buffers.Text.Tests
if (OffsetHours != 0 || OffsetMinutes != 0)
return null;
- return Year.ToString("D4") + "-" + Month.ToString("D2") + "-" + Day.ToString("D2") + "T"
- + Hour.ToString("D2") + ":" + Minute.ToString("D2") + ":" + Second.ToString("D2")
+ return Year.ToString("D4", CultureInfo.InvariantCulture) + "-" + Month.ToString("D2", CultureInfo.InvariantCulture) + "-" + Day.ToString("D2", CultureInfo.InvariantCulture) + "T"
+ + Hour.ToString("D2", CultureInfo.InvariantCulture) + ":" + Minute.ToString("D2", CultureInfo.InvariantCulture) + ":" + Second.ToString("D2", CultureInfo.InvariantCulture)
+ "." + Fraction.ToString("D7");
}
}
@@ -120,10 +122,10 @@ namespace System.Buffers.Text.Tests
{
get
{
- return Year.ToString("D4") + "-" + Month.ToString("D2") + "-" + Day.ToString("D2") + "T"
- + Hour.ToString("D2") + ":" + Minute.ToString("D2") + ":" + Second.ToString("D2")
- + "." + Fraction.ToString("D7")
- + (OffsetNegative ? "-" : "+") + OffsetHours.ToString("D2") + ":" + OffsetMinutes.ToString("D2");
+ return Year.ToString("D4", CultureInfo.InvariantCulture) + "-" + Month.ToString("D2", CultureInfo.InvariantCulture) + "-" + Day.ToString("D2", CultureInfo.InvariantCulture) + "T"
+ + Hour.ToString("D2", CultureInfo.InvariantCulture) + ":" + Minute.ToString("D2", CultureInfo.InvariantCulture) + ":" + Second.ToString("D2", CultureInfo.InvariantCulture)
+ + "." + Fraction.ToString("D7", CultureInfo.InvariantCulture)
+ + (OffsetNegative ? "-" : "+") + OffsetHours.ToString("D2", CultureInfo.InvariantCulture) + ":" + OffsetMinutes.ToString("D2", CultureInfo.InvariantCulture);
}
}
diff --git a/src/System.Memory/tests/ParsersAndFormatters/StandardFormatTests.cs b/src/System.Memory/tests/ParsersAndFormatters/StandardFormatTests.cs
index 4bdc5f918b..326bb0f08b 100644
--- a/src/System.Memory/tests/ParsersAndFormatters/StandardFormatTests.cs
+++ b/src/System.Memory/tests/ParsersAndFormatters/StandardFormatTests.cs
@@ -39,7 +39,7 @@ namespace System.Buffers.Text.Tests
[InlineData("", default(char), default(byte))]
public static void StandardFormatParseSpan(string formatString, char expectedSymbol, byte expectedPrecision)
{
- ReadOnlySpan<char> span = formatString.AsReadOnlySpan();
+ ReadOnlySpan<char> span = formatString.AsSpan();
StandardFormat format = StandardFormat.Parse(span);
Assert.Equal(expectedSymbol, format.Symbol);
Assert.Equal(expectedPrecision, format.Precision);
diff --git a/src/System.Memory/tests/ParsersAndFormatters/SupportedFormats.cs b/src/System.Memory/tests/ParsersAndFormatters/SupportedFormats.cs
index 929e9e2867..736b2dc79a 100644
--- a/src/System.Memory/tests/ParsersAndFormatters/SupportedFormats.cs
+++ b/src/System.Memory/tests/ParsersAndFormatters/SupportedFormats.cs
@@ -29,13 +29,11 @@ namespace System.Buffers.Text.Tests
public static bool IsParsingImplemented<T>(this SupportedFormat f) => f.IsParsingImplemented(typeof(T));
//
- // Used to disable automatic generation of ParserTestData from FormatterTestData
+ // Used to disable automatic generation of ParserTestData from FormatterTestData. Useful for bringing up new
+ // formats as you can use this shutoff valve to bring up formatting without having to bring up parsing at the same time.
//
public static bool IsParsingImplemented(this SupportedFormat f, Type t)
{
- if (IntegerTypes.Contains(t) && (f.Symbol == 'N' || f.Symbol == 'n'))
- return false;
-
return true;
}
diff --git a/src/System.Memory/tests/ParsersAndFormatters/TestData.cs b/src/System.Memory/tests/ParsersAndFormatters/TestData.cs
index f30e4f23b6..4e95b808fe 100644
--- a/src/System.Memory/tests/ParsersAndFormatters/TestData.cs
+++ b/src/System.Memory/tests/ParsersAndFormatters/TestData.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Linq;
+using System.Globalization;
using System.Collections.Generic;
namespace System.Buffers.Text.Tests
@@ -397,16 +398,16 @@ namespace System.Buffers.Text.Tests
yield return "0.000045";
yield return "000000123.000045";
- yield return decimal.MinValue.ToString("G");
- yield return decimal.MaxValue.ToString("G");
+ yield return decimal.MinValue.ToString("G", CultureInfo.InvariantCulture);
+ yield return decimal.MaxValue.ToString("G", CultureInfo.InvariantCulture);
- yield return float.MinValue.ToString("G9");
- yield return float.MaxValue.ToString("G9");
- yield return float.Epsilon.ToString("G9");
+ yield return float.MinValue.ToString("G9", CultureInfo.InvariantCulture);
+ yield return float.MaxValue.ToString("G9", CultureInfo.InvariantCulture);
+ yield return float.Epsilon.ToString("G9", CultureInfo.InvariantCulture);
- yield return double.MinValue.ToString("G17");
- yield return double.MaxValue.ToString("G17");
- yield return double.Epsilon.ToString("G9");
+ yield return double.MinValue.ToString("G17", CultureInfo.InvariantCulture);
+ yield return double.MaxValue.ToString("G17", CultureInfo.InvariantCulture);
+ yield return double.Epsilon.ToString("G9", CultureInfo.InvariantCulture);
yield return "1e";
yield return "1e+";
diff --git a/src/System.Memory/tests/ParsersAndFormatters/TestUtils.cs b/src/System.Memory/tests/ParsersAndFormatters/TestUtils.cs
index f02f6fefdf..c7cbd788f1 100644
--- a/src/System.Memory/tests/ParsersAndFormatters/TestUtils.cs
+++ b/src/System.Memory/tests/ParsersAndFormatters/TestUtils.cs
@@ -62,7 +62,7 @@ namespace System.Buffers.Text.Tests
string sign = isNegative ? "-" : "+";
- return "[" + sign + dec.ToString("G") + ", scale=" + scale + "]";
+ return "[" + sign + dec.ToString("G", CultureInfo.InvariantCulture) + ", scale=" + scale + "]";
}
else if (value is TimeSpan timeSpan)
{
diff --git a/src/System.Memory/tests/Performance/Perf.Span.BinaryReadAndWrite.cs b/src/System.Memory/tests/Performance/Perf.Span.BinaryReadAndWrite.cs
index 1e0e9f278c..78f536b98a 100644
--- a/src/System.Memory/tests/Performance/Perf.Span.BinaryReadAndWrite.cs
+++ b/src/System.Memory/tests/Performance/Perf.Span.BinaryReadAndWrite.cs
@@ -5,6 +5,7 @@
using Microsoft.Xunit.Performance;
using Xunit;
using System.Net;
+using System.Runtime.InteropServices;
using static System.Buffers.Binary.BinaryPrimitives;
@@ -26,7 +27,7 @@ namespace System.Buffers.Binary.Tests
{
for (int i = 0; i < Benchmark.InnerIterationCount; i++)
{
- readStruct = ReadMachineEndian<TestHelpers.TestStructExplicit>(spanBE);
+ readStruct = MemoryMarshal.Read<TestHelpers.TestStructExplicit>(spanBE);
if (BitConverter.IsLittleEndian)
{
readStruct.S0 = ReverseEndianness(readStruct.S0);
@@ -61,7 +62,7 @@ namespace System.Buffers.Binary.Tests
{
for (int i = 0; i < Benchmark.InnerIterationCount; i++)
{
- readStruct = ReadMachineEndian<TestHelpers.TestStructExplicit>(spanLE);
+ readStruct = MemoryMarshal.Read<TestHelpers.TestStructExplicit>(spanLE);
if (!BitConverter.IsLittleEndian)
{
readStruct.S0 = ReverseEndianness(readStruct.S0);
diff --git a/src/System.Memory/tests/Performance/Perf.Span.Clear.cs b/src/System.Memory/tests/Performance/Perf.Span.Clear.cs
index 8557482041..65179cd1f8 100644
--- a/src/System.Memory/tests/Performance/Perf.Span.Clear.cs
+++ b/src/System.Memory/tests/Performance/Perf.Span.Clear.cs
@@ -9,7 +9,9 @@ namespace System.Memory.Tests
{
public class Perf_Span_Clear
{
- [Benchmark]
+ private const int NumIters = 10000;
+
+ [Benchmark(InnerIterationCount = NumIters)]
[InlineData(0)]
[InlineData(1)]
[InlineData(2)]
@@ -41,7 +43,47 @@ namespace System.Memory.Tests
{
using (iteration.StartMeasurement())
{
- for (int i = 0; i < 10000; i++)
+ for (int i = 0; i < Benchmark.InnerIterationCount; i++)
+ {
+ span.Clear();
+ }
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = NumIters)]
+ [InlineData(0)]
+ [InlineData(1)]
+ [InlineData(2)]
+ [InlineData(3)]
+ [InlineData(4)]
+ [InlineData(5)]
+ [InlineData(6)]
+ [InlineData(7)]
+ [InlineData(8)]
+ [InlineData(9)]
+ [InlineData(10)]
+ [InlineData(11)]
+ [InlineData(12)]
+ [InlineData(13)]
+ [InlineData(14)]
+ [InlineData(15)]
+ [InlineData(16)]
+ [InlineData(32)]
+ [InlineData(64)]
+ [InlineData(100)]
+ [InlineData(1000)]
+ [InlineData(10000)]
+ [InlineData(100000)]
+ public void References(int size)
+ {
+ var a = new object[size];
+ var span = new Span<object>(a);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ for (int i = 0; i < Benchmark.InnerIterationCount; i++)
{
span.Clear();
}
diff --git a/src/System.Memory/tests/Performance/Perf.Span.IndexOf.cs b/src/System.Memory/tests/Performance/Perf.Span.IndexOf.cs
index dd678920f4..b260183cc3 100644
--- a/src/System.Memory/tests/Performance/Perf.Span.IndexOf.cs
+++ b/src/System.Memory/tests/Performance/Perf.Span.IndexOf.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Runtime.InteropServices;
using Microsoft.Xunit.Performance;
using Xunit;
@@ -44,7 +45,7 @@ namespace System.Memory.Tests
{
Span<char> charSpan = new char[size];
charSpan[size / 2] = '5';
- Span<byte> byteSpan = charSpan.AsBytes();
+ Span<byte> byteSpan = MemoryMarshal.AsBytes(charSpan);
int index = 0;
foreach (BenchmarkIteration iteration in Benchmark.Iterations)
@@ -120,7 +121,7 @@ namespace System.Memory.Tests
{
Span<char> charSpan = new char[size];
charSpan[size / 2] = '5';
- Span<byte> byteSpan = charSpan.AsBytes();
+ Span<byte> byteSpan = MemoryMarshal.AsBytes(charSpan);
int index = 0;
foreach (BenchmarkIteration iteration in Benchmark.Iterations)
diff --git a/src/System.Memory/tests/Performance/Perf.Span.IndexOfAny.cs b/src/System.Memory/tests/Performance/Perf.Span.IndexOfAny.cs
index 26c5f5bf95..f4a78276f5 100644
--- a/src/System.Memory/tests/Performance/Perf.Span.IndexOfAny.cs
+++ b/src/System.Memory/tests/Performance/Perf.Span.IndexOfAny.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Runtime.InteropServices;
using Microsoft.Xunit.Performance;
using Xunit;
@@ -44,7 +45,7 @@ namespace System.Memory.Tests
{
Span<char> charSpan = new char[size];
charSpan[size / 2] = '5';
- Span<byte> byteSpan = charSpan.AsBytes();
+ Span<byte> byteSpan = MemoryMarshal.AsBytes(charSpan);
int index = 0;
foreach (BenchmarkIteration iteration in Benchmark.Iterations)
@@ -118,7 +119,7 @@ namespace System.Memory.Tests
{
Span<char> charSpan = new char[size];
charSpan[size / 2] = '5';
- Span<byte> byteSpan = charSpan.AsBytes();
+ Span<byte> byteSpan = MemoryMarshal.AsBytes(charSpan);
int index = 0;
foreach (BenchmarkIteration iteration in Benchmark.Iterations)
@@ -193,7 +194,7 @@ namespace System.Memory.Tests
{
Span<char> charSpan = new char[size];
charSpan[size / 2] = '5';
- Span<byte> byteSpan = charSpan.AsBytes();
+ Span<byte> byteSpan = MemoryMarshal.AsBytes(charSpan);
ReadOnlySpan<byte> values = new ReadOnlySpan<byte>(new byte[] { 53, 54, 55, 56 }); // '5' = 53
int index = 0;
@@ -219,7 +220,7 @@ namespace System.Memory.Tests
{
Span<char> charSpan = new char[size];
charSpan[size / 2] = '5';
- Span<byte> byteSpan = charSpan.AsBytes();
+ Span<byte> byteSpan = MemoryMarshal.AsBytes(charSpan);
ReadOnlySpan<byte> values = new ReadOnlySpan<byte>(new byte[] { 54, 55, 56, 57 }); // '5' = 53
int index = 0;
@@ -245,7 +246,7 @@ namespace System.Memory.Tests
{
Span<char> charSpan = new char[size];
charSpan[size / 2] = '5';
- Span<byte> byteSpan = charSpan.AsBytes();
+ Span<byte> byteSpan = MemoryMarshal.AsBytes(charSpan);
ReadOnlySpan<byte> values = new ReadOnlySpan<byte>(new byte[] { 54, 55, 56, 53 }); // '5' = 53
int index = 0;
diff --git a/src/System.Memory/tests/ReadOnlyBuffer/BufferSegment.cs b/src/System.Memory/tests/ReadOnlyBuffer/BufferSegment.cs
new file mode 100644
index 0000000000..5ad113e09f
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlyBuffer/BufferSegment.cs
@@ -0,0 +1,26 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+
+namespace System.Memory.Tests
+{
+ internal class BufferSegment<T> : ReadOnlySequenceSegment<T>
+ {
+ public BufferSegment(Memory<T> memory)
+ {
+ Memory = memory;
+ }
+
+ public BufferSegment<T> Append(Memory<T> memory)
+ {
+ var segment = new BufferSegment<T>(memory)
+ {
+ RunningIndex = RunningIndex + Memory.Length
+ };
+ Next = segment;
+ return segment;
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.byte.cs b/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.byte.cs
new file mode 100644
index 0000000000..d8734b34ec
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.byte.cs
@@ -0,0 +1,150 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Collections.Generic;
+using System.MemoryTests;
+using System.Text;
+
+namespace System.Memory.Tests
+{
+ public abstract class ReadOnlySequenceFactoryByte
+ {
+ public static ReadOnlySequenceFactoryByte ArrayFactory { get; } = new ArrayTestSequenceFactoryByte();
+ public static ReadOnlySequenceFactoryByte MemoryFactory { get; } = new MemoryTestSequenceFactoryByte();
+ public static ReadOnlySequenceFactoryByte OwnedMemoryFactory { get; } = new OwnedMemoryTestSequenceFactoryByte();
+ public static ReadOnlySequenceFactoryByte SingleSegmentFactory { get; } = new SingleSegmentTestSequenceFactoryByte();
+ public static ReadOnlySequenceFactoryByte SegmentPerByteFactory { get; } = new BytePerSegmentTestSequenceFactoryByte();
+
+ public abstract ReadOnlySequence<byte> CreateOfSize(int size);
+ public abstract ReadOnlySequence<byte> CreateWithContent(byte[] data);
+
+ public ReadOnlySequence<byte> CreateWithContent(string data)
+ {
+ return CreateWithContent(Encoding.ASCII.GetBytes(data));
+ }
+
+ internal class ArrayTestSequenceFactoryByte : ReadOnlySequenceFactoryByte
+ {
+ public override ReadOnlySequence<byte> CreateOfSize(int size)
+ {
+ return new ReadOnlySequence<byte>(new byte[size + 20], 10, size);
+ }
+
+ public override ReadOnlySequence<byte> CreateWithContent(byte[] data)
+ {
+ var startSegment = new byte[data.Length + 20];
+ Array.Copy(data, 0, startSegment, 10, data.Length);
+ return new ReadOnlySequence<byte>(startSegment, 10, data.Length);
+ }
+ }
+
+ internal class MemoryTestSequenceFactoryByte : ReadOnlySequenceFactoryByte
+ {
+ public override ReadOnlySequence<byte> CreateOfSize(int size)
+ {
+ return CreateWithContent(new byte[size]);
+ }
+
+ public override ReadOnlySequence<byte> CreateWithContent(byte[] data)
+ {
+ var startSegment = new byte[data.Length + 20];
+ Array.Copy(data, 0, startSegment, 10, data.Length);
+ return new ReadOnlySequence<byte>(new Memory<byte>(startSegment, 10, data.Length));
+ }
+ }
+
+ internal class OwnedMemoryTestSequenceFactoryByte : ReadOnlySequenceFactoryByte
+ {
+ public override ReadOnlySequence<byte> CreateOfSize(int size)
+ {
+ return CreateWithContent(new byte[size]);
+ }
+
+ public override ReadOnlySequence<byte> CreateWithContent(byte[] data)
+ {
+ var startSegment = new byte[data.Length + 20];
+ Array.Copy(data, 0, startSegment, 10, data.Length);
+ return new ReadOnlySequence<byte>(new CustomMemoryForTest<byte>(startSegment, 10, data.Length));
+ }
+ }
+
+ internal class SingleSegmentTestSequenceFactoryByte : ReadOnlySequenceFactoryByte
+ {
+ public override ReadOnlySequence<byte> CreateOfSize(int size)
+ {
+ return CreateWithContent(new byte[size]);
+ }
+
+ public override ReadOnlySequence<byte> CreateWithContent(byte[] data)
+ {
+ return CreateSegments(data);
+ }
+ }
+
+ internal class BytePerSegmentTestSequenceFactoryByte : ReadOnlySequenceFactoryByte
+ {
+ public override ReadOnlySequence<byte> CreateOfSize(int size)
+ {
+ return CreateWithContent(new byte[size]);
+ }
+
+ public override ReadOnlySequence<byte> CreateWithContent(byte[] data)
+ {
+ var segments = new List<byte[]>();
+
+ segments.Add(Array.Empty<byte>());
+ foreach (var b in data)
+ {
+ segments.Add(new[] { b });
+ segments.Add(Array.Empty<byte>());
+ }
+
+ return CreateSegments(segments.ToArray());
+ }
+ }
+
+ public static ReadOnlySequence<byte> CreateSegments(params byte[][] inputs)
+ {
+ if (inputs == null || inputs.Length == 0)
+ {
+ throw new InvalidOperationException();
+ }
+
+ int i = 0;
+
+ BufferSegment<byte> last = null;
+ BufferSegment<byte> first = null;
+
+ do
+ {
+ byte[] s = inputs[i];
+ int length = s.Length;
+ int dataOffset = length;
+ var chars = new byte[length * 2];
+
+ for (int j = 0; j < length; j++)
+ {
+ chars[dataOffset + j] = s[j];
+ }
+
+ // Create a segment that has offset relative to the OwnedMemory and OwnedMemory itself has offset relative to array
+ Memory<byte> memory = new Memory<byte>(chars).Slice(length, length);
+
+ if (first == null)
+ {
+ first = new BufferSegment<byte>(memory);
+ last = first;
+ }
+ else
+ {
+ last = last.Append(memory);
+ }
+ i++;
+ } while (i < inputs.Length);
+
+ return new ReadOnlySequence<byte>(first, 0, last, last.Memory.Length);
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.char.cs b/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.char.cs
new file mode 100644
index 0000000000..273f5670bb
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.char.cs
@@ -0,0 +1,184 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Collections.Generic;
+using System.Linq;
+using System.MemoryTests;
+using System.Text;
+
+namespace System.Memory.Tests
+{
+ public abstract class ReadOnlySequenceFactoryChar
+ {
+ public static ReadOnlySequenceFactoryChar ArrayFactory { get; } = new ArrayTestSequenceFactoryChar();
+ public static ReadOnlySequenceFactoryChar MemoryFactory { get; } = new MemoryTestSequenceFactoryChar();
+ public static ReadOnlySequenceFactoryChar StringFactory { get; } = new StringTestSequenceFactoryChar();
+ public static ReadOnlySequenceFactoryChar OwnedMemoryFactory { get; } = new OwnedMemoryTestSequenceFactoryChar();
+ public static ReadOnlySequenceFactoryChar SingleSegmentFactory { get; } = new SingleSegmentTestSequenceFactoryChar();
+ public static ReadOnlySequenceFactoryChar SegmentPerCharFactory { get; } = new CharPerSegmentTestSequenceFactoryChar();
+
+ public abstract ReadOnlySequence<char> CreateOfSize(int size);
+ public abstract ReadOnlySequence<char> CreateWithContent(char[] data);
+
+ public ReadOnlySequence<char> CreateWithContent(string data)
+ {
+ return CreateWithContent(data.ToCharArray());
+ }
+
+ internal class ArrayTestSequenceFactoryChar : ReadOnlySequenceFactoryChar
+ {
+ public override ReadOnlySequence<char> CreateOfSize(int size)
+ {
+ return new ReadOnlySequence<char>(new char[size + 20], 10, size);
+ }
+
+ public override ReadOnlySequence<char> CreateWithContent(char[] data)
+ {
+ var startSegment = new char[data.Length + 20];
+ Array.Copy(data, 0, startSegment, 10, data.Length);
+ return new ReadOnlySequence<char>(startSegment, 10, data.Length);
+ }
+ }
+
+ internal class StringTestSequenceFactoryChar : ReadOnlySequenceFactoryChar
+ {
+ static string s_stringData = InitalizeStringData();
+
+ static string InitalizeStringData()
+ {
+ IEnumerable<int> ascii = Enumerable.Range(' ', (char)0x7f - ' ');
+
+ return new string(ascii.Concat(ascii)
+ .Concat(ascii)
+ .Concat(ascii)
+ .Concat(ascii)
+ .Concat(ascii)
+ .Concat(ascii)
+ .Select(c => (char)c)
+ .ToArray());
+ }
+
+ public override ReadOnlySequence<char> CreateOfSize(int size)
+ {
+ return new ReadOnlySequence<char>(s_stringData.AsMemory(10, size));
+ }
+
+ public override ReadOnlySequence<char> CreateWithContent(char[] data)
+ {
+ var startSegment = new char[data.Length + 20];
+ Array.Copy(data, 0, startSegment, 10, data.Length);
+ var text = new string(startSegment);
+ return new ReadOnlySequence<char>(text.AsMemory(10, data.Length));
+ }
+ }
+
+ internal class MemoryTestSequenceFactoryChar : ReadOnlySequenceFactoryChar
+ {
+ public override ReadOnlySequence<char> CreateOfSize(int size)
+ {
+ return CreateWithContent(new char[size]);
+ }
+
+ public override ReadOnlySequence<char> CreateWithContent(char[] data)
+ {
+ var startSegment = new char[data.Length + 20];
+ Array.Copy(data, 0, startSegment, 10, data.Length);
+ return new ReadOnlySequence<char>(new ReadOnlyMemory<char>(startSegment, 10, data.Length));
+ }
+ }
+
+ internal class OwnedMemoryTestSequenceFactoryChar : ReadOnlySequenceFactoryChar
+ {
+ public override ReadOnlySequence<char> CreateOfSize(int size)
+ {
+ return CreateWithContent(new char[size]);
+ }
+
+ public override ReadOnlySequence<char> CreateWithContent(char[] data)
+ {
+ var startSegment = new char[data.Length + 20];
+ Array.Copy(data, 0, startSegment, 10, data.Length);
+ return new ReadOnlySequence<char>(new CustomMemoryForTest<char>(startSegment, 10, data.Length));
+ }
+ }
+
+ internal class SingleSegmentTestSequenceFactoryChar : ReadOnlySequenceFactoryChar
+ {
+ public override ReadOnlySequence<char> CreateOfSize(int size)
+ {
+ return CreateWithContent(new char[size]);
+ }
+
+ public override ReadOnlySequence<char> CreateWithContent(char[] data)
+ {
+ return CreateSegments(data);
+ }
+ }
+
+ internal class CharPerSegmentTestSequenceFactoryChar : ReadOnlySequenceFactoryChar
+ {
+ public override ReadOnlySequence<char> CreateOfSize(int size)
+ {
+ return CreateWithContent(new char[size]);
+ }
+
+ public override ReadOnlySequence<char> CreateWithContent(char[] data)
+ {
+ var segments = new List<char[]>();
+
+ segments.Add(Array.Empty<char>());
+ foreach (var b in data)
+ {
+ segments.Add(new[] { b });
+ segments.Add(Array.Empty<char>());
+ }
+
+ return CreateSegments(segments.ToArray());
+ }
+ }
+
+ public static ReadOnlySequence<char> CreateSegments(params char[][] inputs)
+ {
+ if (inputs == null || inputs.Length == 0)
+ {
+ throw new InvalidOperationException();
+ }
+
+ int i = 0;
+
+ BufferSegment<char> last = null;
+ BufferSegment<char> first = null;
+
+ do
+ {
+ char[] s = inputs[i];
+ int length = s.Length;
+ int dataOffset = length;
+ var chars = new char[length * 2];
+
+ for (int j = 0; j < length; j++)
+ {
+ chars[dataOffset + j] = s[j];
+ }
+
+ // Create a segment that has offset relative to the OwnedMemory and OwnedMemory itself has offset relative to array
+ Memory<char> memory = new Memory<char>(chars).Slice(length, length);
+
+ if (first == null)
+ {
+ first = new BufferSegment<char>(memory);
+ last = first;
+ }
+ else
+ {
+ last = last.Append(memory);
+ }
+ i++;
+ } while (i < inputs.Length);
+
+ return new ReadOnlySequence<char>(first, 0, last, last.Memory.Length);
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.cs b/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.cs
new file mode 100644
index 0000000000..c7971c4a33
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.Common.cs
@@ -0,0 +1,483 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Collections.Generic;
+using System.Linq;
+using System.MemoryTests;
+using System.Text;
+using Xunit;
+
+namespace System.Memory.Tests
+{
+ public class CommonReadOnlySequenceTests
+ {
+ [Fact]
+ public void SegmentStartIsConsideredInBoundsCheck()
+ {
+ // 0 50 100 0 50 100
+ // [ ##############] -> [############## ]
+ // ^c1 ^c2
+ var bufferSegment1 = new BufferSegment<byte>(new byte[49]);
+ BufferSegment<byte> bufferSegment2 = bufferSegment1.Append(new byte[50]);
+
+ var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment2, 50);
+
+ SequencePosition c1 = buffer.GetPosition(25); // segment 1 index 75
+ SequencePosition c2 = buffer.GetPosition(55); // segment 2 index 5
+
+ ReadOnlySequence<byte> sliced = buffer.Slice(c1, c2);
+ Assert.Equal(30, sliced.Length);
+
+ c1 = buffer.GetPosition(25, buffer.Start); // segment 1 index 75
+ c2 = buffer.GetPosition(55, buffer.Start); // segment 2 index 5
+
+ sliced = buffer.Slice(c1, c2);
+ Assert.Equal(30, sliced.Length);
+ }
+
+ [Fact]
+ public void GetPositionPrefersNextSegment()
+ {
+ BufferSegment<byte> bufferSegment1 = new BufferSegment<byte>(new byte[50]);
+ BufferSegment<byte> bufferSegment2 = bufferSegment1.Append(new byte[0]);
+
+ ReadOnlySequence<byte> buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment2, 0);
+
+ SequencePosition c1 = buffer.GetPosition(50);
+
+ Assert.Equal(0, c1.GetInteger());
+ Assert.Equal(bufferSegment2, c1.GetObject());
+
+ c1 = buffer.GetPosition(50, buffer.Start);
+
+ Assert.Equal(0, c1.GetInteger());
+ Assert.Equal(bufferSegment2, c1.GetObject());
+ }
+
+ [Fact]
+ public void GetPositionDoesNotCrossOutsideBuffer()
+ {
+ var bufferSegment1 = new BufferSegment<byte>(new byte[100]);
+ BufferSegment<byte> bufferSegment2 = bufferSegment1.Append(new byte[100]);
+ BufferSegment<byte> bufferSegment3 = bufferSegment2.Append(new byte[0]);
+
+ var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment2, 100);
+
+ SequencePosition c1 = buffer.GetPosition(200);
+
+ Assert.Equal(100, c1.GetInteger());
+ Assert.Equal(bufferSegment2, c1.GetObject());
+
+ c1 = buffer.GetPosition(200, buffer.Start);
+
+ Assert.Equal(100, c1.GetInteger());
+ Assert.Equal(bufferSegment2, c1.GetObject());
+ }
+
+ [Fact]
+ public void CheckEndReachableDoesNotCrossPastEnd()
+ {
+ var bufferSegment1 = new BufferSegment<byte>(new byte[100]);
+ BufferSegment<byte> bufferSegment2 = bufferSegment1.Append(new byte[100]);
+ BufferSegment<byte> bufferSegment3 = bufferSegment2.Append(new byte[100]);
+ BufferSegment<byte> bufferSegment4 = bufferSegment3.Append(new byte[100]);
+
+ var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment4, 100);
+
+ SequencePosition c1 = buffer.GetPosition(200);
+
+ Assert.Equal(0, c1.GetInteger());
+ Assert.Equal(bufferSegment3, c1.GetObject());
+
+ ReadOnlySequence<byte> seq = buffer.Slice(0, c1);
+ Assert.Equal(200, seq.Length);
+
+ c1 = buffer.GetPosition(200, buffer.Start);
+
+ Assert.Equal(0, c1.GetInteger());
+ Assert.Equal(bufferSegment3, c1.GetObject());
+
+ seq = buffer.Slice(0, c1);
+ Assert.Equal(200, seq.Length);
+ }
+
+ [Fact]
+ public void CanGetFirst()
+ {
+ var bufferSegment1 = new BufferSegment<byte>(new byte[100]);
+ BufferSegment<byte> bufferSegment2 = bufferSegment1.Append(new byte[100]);
+ BufferSegment<byte> bufferSegment3 = bufferSegment2.Append(new byte[100]);
+ BufferSegment<byte> bufferSegment4 = bufferSegment3.Append(new byte[200]);
+
+ var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment4, 200);
+
+ Assert.Equal(500, buffer.Length);
+ int length = 500;
+
+ for (int s = 0; s < 3; s++)
+ {
+ for (int i = 100; i > 0; i--)
+ {
+ Assert.Equal(i, buffer.First.Length);
+ buffer = buffer.Slice(1);
+ length--;
+ Assert.Equal(length, buffer.Length);
+ }
+ }
+
+ Assert.Equal(200, buffer.Length);
+
+ for (int i = 200; i > 0; i--)
+ {
+ Assert.Equal(i, buffer.First.Length);
+ buffer = buffer.Slice(1);
+ length--;
+ Assert.Equal(length, buffer.Length);
+ }
+
+ Assert.Equal(0, buffer.Length);
+ Assert.Equal(0, buffer.First.Length);
+ }
+
+ [Fact]
+ public void SeekSkipsEmptySegments()
+ {
+ var bufferSegment1 = new BufferSegment<byte>(new byte[100]);
+ BufferSegment<byte> bufferSegment2 = bufferSegment1.Append(new byte[0]);
+ BufferSegment<byte> bufferSegment3 = bufferSegment2.Append(new byte[0]);
+ BufferSegment<byte> bufferSegment4 = bufferSegment3.Append(new byte[100]);
+
+ var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment4, 100);
+
+ SequencePosition c1 = buffer.GetPosition(100);
+
+ Assert.Equal(0, c1.GetInteger());
+ Assert.Equal(bufferSegment4, c1.GetObject());
+
+ c1 = buffer.GetPosition(100, buffer.Start);
+
+ Assert.Equal(0, c1.GetInteger());
+ Assert.Equal(bufferSegment4, c1.GetObject());
+ }
+
+ [Fact]
+ public void TryGetReturnsEmptySegments()
+ {
+ var bufferSegment1 = new BufferSegment<byte>(new byte[0]);
+ BufferSegment<byte> bufferSegment2 = bufferSegment1.Append(new byte[0]);
+ BufferSegment<byte> bufferSegment3 = bufferSegment2.Append(new byte[0]);
+ BufferSegment<byte> bufferSegment4 = bufferSegment3.Append(new byte[0]);
+
+ var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment3, 0);
+
+ var start = buffer.Start;
+ Assert.True(buffer.TryGet(ref start, out var memory));
+ Assert.Equal(0, memory.Length);
+ Assert.True(buffer.TryGet(ref start, out memory));
+ Assert.Equal(0, memory.Length);
+ Assert.True(buffer.TryGet(ref start, out memory));
+ Assert.Equal(0, memory.Length);
+ Assert.False(buffer.TryGet(ref start, out memory));
+ }
+
+ [Fact]
+ public void TryGetStopsAtEnd()
+ {
+ var bufferSegment1 = new BufferSegment<byte>(new byte[100]);
+ BufferSegment<byte> bufferSegment2 = bufferSegment1.Append(new byte[100]);
+ BufferSegment<byte> bufferSegment3 = bufferSegment2.Append(new byte[100]);
+ BufferSegment<byte> bufferSegment4 = bufferSegment3.Append(new byte[100]);
+ BufferSegment<byte> bufferSegment5 = bufferSegment4.Append(new byte[100]);
+
+ var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment3, 100);
+
+ var start = buffer.Start;
+ Assert.True(buffer.TryGet(ref start, out var memory));
+ Assert.Equal(100, memory.Length);
+ Assert.True(buffer.TryGet(ref start, out memory));
+ Assert.Equal(100, memory.Length);
+ Assert.True(buffer.TryGet(ref start, out memory));
+ Assert.Equal(100, memory.Length);
+ Assert.False(buffer.TryGet(ref start, out memory));
+ }
+
+ [Fact]
+ public void TryGetStopsAtEndWhenEndIsLastByteOfFull()
+ {
+ var bufferSegment1 = new BufferSegment<byte>(new byte[100]);
+ BufferSegment<byte> bufferSegment2 = bufferSegment1.Append(new byte[100]);
+
+ var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment1, 100);
+
+ var start = buffer.Start;
+ Assert.True(buffer.TryGet(ref start, out var memory));
+ Assert.Equal(100, memory.Length);
+ Assert.False(buffer.TryGet(ref start, out memory));
+ }
+
+ [Fact]
+ public void TryGetStopsAtEndWhenEndIsFirstByteOfFull()
+ {
+ var bufferSegment1 = new BufferSegment<byte>(new byte[100]);
+ BufferSegment<byte> bufferSegment2 = bufferSegment1.Append(new byte[100]);
+
+ var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment2, 0);
+
+ var start = buffer.Start;
+ Assert.True(buffer.TryGet(ref start, out var memory));
+ Assert.Equal(100, memory.Length);
+ Assert.True(buffer.TryGet(ref start, out memory));
+ Assert.Equal(0, memory.Length);
+ Assert.False(buffer.TryGet(ref start, out memory));
+ }
+
+ [Fact]
+ public void TryGetStopsAtEndWhenEndIsFirstByteOfEmpty()
+ {
+ var bufferSegment1 = new BufferSegment<byte>(new byte[100]);
+ BufferSegment<byte> bufferSegment2 = bufferSegment1.Append(new byte[0]);
+
+ var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment2, 0);
+
+ var start = buffer.Start;
+ Assert.True(buffer.TryGet(ref start, out var memory));
+ Assert.Equal(100, memory.Length);
+ Assert.True(buffer.TryGet(ref start, out memory));
+ Assert.Equal(0, memory.Length);
+ Assert.False(buffer.TryGet(ref start, out memory));
+ }
+
+ [Fact]
+ public void EnumerableStopsAtEndWhenEndIsLastByteOfFull()
+ {
+ var bufferSegment1 = new BufferSegment<byte>(new byte[100]);
+ BufferSegment<byte> bufferSegment2 = bufferSegment1.Append(new byte[100]);
+
+ var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment1, 100);
+
+ List<int> sizes = new List<int>();
+ foreach (var memory in buffer)
+ {
+ sizes.Add(memory.Length);
+ }
+
+ Assert.Equal(1, sizes.Count);
+ Assert.Equal(new [] { 100 }, sizes);
+ }
+
+ [Fact]
+ public void EnumerableStopsAtEndWhenEndIsFirstByteOfFull()
+ {
+ var bufferSegment1 = new BufferSegment<byte>(new byte[100]);
+ BufferSegment<byte> bufferSegment2 = bufferSegment1.Append(new byte[100]);
+
+ var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment2, 0);
+
+ List<int> sizes = new List<int>();
+ foreach (var memory in buffer)
+ {
+ sizes.Add(memory.Length);
+ }
+
+ Assert.Equal(2, sizes.Count);
+ Assert.Equal(new [] { 100, 0 }, sizes);
+ }
+
+ [Fact]
+ public void EnumerableStopsAtEndWhenEndIsFirstByteOfEmpty()
+ {
+ var bufferSegment1 = new BufferSegment<byte>(new byte[100]);
+ BufferSegment<byte> bufferSegment2 = bufferSegment1.Append(new byte[0]);
+
+ var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment2, 0);
+
+ List<int> sizes = new List<int>();
+ foreach (var memory in buffer)
+ {
+ sizes.Add(memory.Length);
+ }
+
+ Assert.Equal(2, sizes.Count);
+ Assert.Equal(new [] { 100, 0 }, sizes);
+ }
+
+ [Fact]
+ public void SeekEmptySkipDoesNotCrossPastEnd()
+ {
+ var bufferSegment1 = new BufferSegment<byte>(new byte[100]);
+ BufferSegment<byte> bufferSegment2 = bufferSegment1.Append(new byte[0]);
+ BufferSegment<byte> bufferSegment3 = bufferSegment2.Append(new byte[0]);
+ BufferSegment<byte> bufferSegment4 = bufferSegment3.Append(new byte[100]);
+
+ var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment2, 0);
+
+ SequencePosition c1 = buffer.GetPosition(100);
+
+ Assert.Equal(0, c1.GetInteger());
+ Assert.Equal(bufferSegment2, c1.GetObject());
+
+ c1 = buffer.GetPosition(100, buffer.Start);
+
+ Assert.Equal(0, c1.GetInteger());
+ Assert.Equal(bufferSegment2, c1.GetObject());
+
+ // Go out of bounds for segment
+ Assert.Throws<ArgumentOutOfRangeException>(() => c1 = buffer.GetPosition(150, buffer.Start));
+ Assert.Throws<ArgumentOutOfRangeException>(() => c1 = buffer.GetPosition(250, buffer.Start));
+ }
+
+ [Fact]
+ public void SeekEmptySkipDoesNotCrossPastEndWithExtraChainedBlocks()
+ {
+ var bufferSegment1 = new BufferSegment<byte>(new byte[100]);
+ BufferSegment<byte> bufferSegment2 = bufferSegment1.Append(new byte[0]);
+ BufferSegment<byte> bufferSegment3 = bufferSegment2.Append(new byte[0]);
+ BufferSegment<byte> bufferSegment4 = bufferSegment3.Append(new byte[100]);
+ BufferSegment<byte> bufferSegment5 = bufferSegment4.Append(new byte[0]);
+ BufferSegment<byte> bufferSegment6 = bufferSegment5.Append(new byte[100]);
+
+ var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment2, 0);
+
+ SequencePosition c1 = buffer.GetPosition(100);
+
+ Assert.Equal(0, c1.GetInteger());
+ Assert.Equal(bufferSegment2, c1.GetObject());
+
+ c1 = buffer.GetPosition(100, buffer.Start);
+
+ Assert.Equal(0, c1.GetInteger());
+ Assert.Equal(bufferSegment2, c1.GetObject());
+
+ // Go out of bounds for segment
+ Assert.Throws<ArgumentOutOfRangeException>(() => c1 = buffer.GetPosition(150, buffer.Start));
+ Assert.Throws<ArgumentOutOfRangeException>(() => c1 = buffer.GetPosition(250, buffer.Start));
+ }
+
+ [Fact]
+ public void Create_WorksWithArray()
+ {
+ var buffer = new ReadOnlySequence<byte>(new byte[] { 1, 2, 3, 4, 5 });
+ Assert.Equal(buffer.ToArray(), new byte[] { 1, 2, 3, 4, 5 });
+ }
+
+ [Fact]
+ public void Empty_ReturnsLengthZeroBuffer()
+ {
+ var buffer = ReadOnlySequence<byte>.Empty;
+ Assert.Equal(0, buffer.Length);
+ Assert.Equal(true, buffer.IsSingleSegment);
+ Assert.Equal(0, buffer.First.Length);
+ }
+
+ [Fact]
+ public void Ctor_Array_Offset()
+ {
+ var buffer = new ReadOnlySequence<byte>(new byte[] { 1, 2, 3, 4, 5 }, 2, 3);
+ Assert.Equal(buffer.ToArray(), new byte[] { 3, 4, 5 });
+ }
+
+ [Fact]
+ public void Ctor_Array_NoOffset()
+ {
+ var buffer = new ReadOnlySequence<byte>(new byte[] { 1, 2, 3, 4, 5 });
+ Assert.Equal(buffer.ToArray(), new byte[] { 1, 2, 3, 4, 5 });
+ }
+
+ [Fact]
+ public void Ctor_Array_ValidatesArguments()
+ {
+ Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlySequence<byte>(new byte[] { 1, 2, 3, 4, 5 }, 6, 0));
+ Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlySequence<byte>(new byte[] { 1, 2, 3, 4, 5 }, 4, 2));
+ Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlySequence<byte>(new byte[] { 1, 2, 3, 4, 5 }, -4, 0));
+ Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlySequence<byte>(new byte[] { 1, 2, 3, 4, 5 }, 4, -2));
+ Assert.Throws<ArgumentNullException>(() => new ReadOnlySequence<byte>((byte[])null, 4, 2));
+ }
+
+ [Fact]
+ public void Ctor_OwnedMemory_Offset()
+ {
+ var ownedMemory = new CustomMemoryForTest<byte>(new byte[] { 1, 2, 3, 4, 5 }, 0, 5);
+ var buffer = new ReadOnlySequence<byte>(ownedMemory, 2, 3);
+ Assert.Equal(buffer.ToArray(), new byte[] { 3, 4, 5 });
+ }
+
+ [Fact]
+ public void Ctor_OwnedMemory_NoOffset()
+ {
+ var ownedMemory = new CustomMemoryForTest<byte>(new byte[] { 1, 2, 3, 4, 5 }, 0, 5);
+ var buffer = new ReadOnlySequence<byte>(ownedMemory);
+ Assert.Equal(buffer.ToArray(), new byte[] { 1, 2, 3, 4, 5 });
+ }
+
+ [Fact]
+ public void Ctor_OwnedMemory_ValidatesArguments()
+ {
+ var ownedMemory = new CustomMemoryForTest<byte>(new byte[] { 1, 2, 3, 4, 5 }, 0, 5);
+ Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlySequence<byte>(ownedMemory, 6, 0));
+ Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlySequence<byte>(ownedMemory, 4, 2));
+ Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlySequence<byte>(ownedMemory, -4, 0));
+ Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlySequence<byte>(ownedMemory, 4, -2));
+ Assert.Throws<ArgumentNullException>(() => new ReadOnlySequence<byte>((CustomMemoryForTest<byte>)null, 4, 2));
+ }
+
+ [Fact]
+ public void Ctor_Memory()
+ {
+ var memory = new ReadOnlyMemory<byte>(new byte[] { 1, 2, 3, 4, 5 });
+ var buffer = new ReadOnlySequence<byte>(memory.Slice(2, 3));
+ Assert.Equal(new byte[] { 3, 4, 5 }, buffer.ToArray());
+ }
+
+ [Fact]
+ public void Ctor_ReadOnlySequenceSegment_ValidatesArguments()
+ {
+ var segment = new BufferSegment<byte>(new byte[] { 1, 2, 3, 4, 5 });
+ Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlySequence<byte>(segment, 6, segment, 0));
+ Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlySequence<byte>(segment, 0, segment, 6));
+ Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlySequence<byte>(segment, 3, segment, 0));
+
+ Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlySequence<byte>(segment, -5, segment, 0));
+ Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlySequence<byte>(segment, 0, segment, -5));
+
+ Assert.Throws<ArgumentNullException>(() => new ReadOnlySequence<byte>(null, 5, segment, 0));
+ Assert.Throws<ArgumentNullException>(() => new ReadOnlySequence<byte>(segment, 5, null, 0));
+ }
+
+ [Fact]
+ public void HelloWorldAcrossTwoBlocks()
+ {
+ // block 1 -> block2
+ // [padding..hello] -> [ world ]
+ const int blockSize = 4096;
+
+ byte[] bytes = Encoding.ASCII.GetBytes("Hello World");
+ byte[] firstBytes = Enumerable.Repeat((byte)'a', blockSize - 5).Concat(bytes.Take(5)).ToArray();
+ byte[] secondBytes = bytes.Skip(5).Concat(Enumerable.Repeat((byte)'a', blockSize - (bytes.Length - 5))).ToArray();
+
+ BufferSegment<byte> firstSegement = new BufferSegment<byte>(firstBytes);
+ BufferSegment<byte> secondSegement = firstSegement.Append(secondBytes);
+
+ ReadOnlySequence<byte> buffer = new ReadOnlySequence<byte>(firstSegement, 0, secondSegement, bytes.Length - 5);
+ Assert.False(buffer.IsSingleSegment);
+ ReadOnlySequence<byte> helloBuffer = buffer.Slice(blockSize - 5);
+ Assert.False(helloBuffer.IsSingleSegment);
+ var memory = new List<ReadOnlyMemory<byte>>();
+ foreach (ReadOnlyMemory<byte> m in helloBuffer)
+ {
+ memory.Add(m);
+ }
+
+ List<ReadOnlyMemory<byte>> spans = memory;
+
+ Assert.Equal(2, memory.Count);
+ var helloBytes = new byte[spans[0].Length];
+ spans[0].Span.CopyTo(helloBytes);
+ var worldBytes = new byte[spans[1].Length];
+ spans[1].Span.CopyTo(worldBytes);
+ Assert.Equal("Hello", Encoding.ASCII.GetString(helloBytes));
+ Assert.Equal(" World", Encoding.ASCII.GetString(worldBytes));
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.TryGet.cs b/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.TryGet.cs
new file mode 100644
index 0000000000..b99a4f0fe6
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.TryGet.cs
@@ -0,0 +1,128 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.MemoryTests;
+using System.Runtime.InteropServices;
+using Xunit;
+
+namespace System.Memory.Tests
+{
+ public class ReadOnlySequenceTryGetTests
+ {
+ [Fact]
+ public void Ctor_Array_Offset()
+ {
+ var buffer = new ReadOnlySequence<byte>(new byte[] { 1, 2, 3, 4, 5 }, 2, 3);
+
+ Assert.True(SequenceMarshal.TryGetArray(buffer, out ArraySegment<byte> array));
+ Assert.Equal(2, array.Offset);
+ Assert.Equal(3, array.Count);
+
+ Assert.False(SequenceMarshal.TryGetReadOnlySequenceSegment(buffer, out _, out _, out _, out _));
+ Assert.False(SequenceMarshal.TryGetOwnedMemory(buffer, out _, out _, out _));
+
+ // Array can be retrieved with TryGetReadOnlyMemory
+ Assert.True(SequenceMarshal.TryGetReadOnlyMemory(buffer, out ReadOnlyMemory<byte> newMemory));
+ Assert.Equal(new byte[] { 3, 4, 5 }, newMemory.ToArray());
+ }
+
+ [Fact]
+ public void Ctor_Memory()
+ {
+ var memory = new ReadOnlyMemory<byte>(new byte[] { 1, 2, 3, 4, 5 });
+ var buffer = new ReadOnlySequence<byte>(memory.Slice(2, 3));
+
+ Assert.True(SequenceMarshal.TryGetReadOnlyMemory(buffer, out ReadOnlyMemory<byte> newMemory));
+ Assert.Equal(new byte[] { 3, 4, 5 }, newMemory.ToArray());
+
+ Assert.False(SequenceMarshal.TryGetReadOnlySequenceSegment(buffer, out ReadOnlySequenceSegment<byte> startSegment, out int startIndex, out ReadOnlySequenceSegment<byte> endSegment, out int endIndex));
+ Assert.False(SequenceMarshal.TryGetOwnedMemory(buffer, out _, out _, out _));
+
+ // Memory is internally decomposed to its container so it would be accessible via TryGetArray
+ Assert.True(SequenceMarshal.TryGetArray(buffer, out ArraySegment<byte> array));
+ Assert.Equal(2, array.Offset);
+ Assert.Equal(3, array.Count);
+ }
+
+
+ [Fact]
+ public void Ctor_Memory_String()
+ {
+ var text = "Hello";
+ var memory = text.AsMemory();
+ var buffer = new ReadOnlySequence<char>(memory.Slice(2, 3));
+
+ Assert.True(SequenceMarshal.TryGetReadOnlyMemory(buffer, out ReadOnlyMemory<char> newMemory));
+ Assert.Equal(text.Substring(2, 3).ToCharArray(), newMemory.ToArray());
+
+ Assert.False(SequenceMarshal.TryGetReadOnlySequenceSegment(buffer, out ReadOnlySequenceSegment<char> startSegment, out int startIndex, out ReadOnlySequenceSegment<char> endSegment, out int endIndex));
+ Assert.False(SequenceMarshal.TryGetOwnedMemory(buffer, out _, out _, out _));
+ Assert.False(SequenceMarshal.TryGetArray(buffer, out _));
+ }
+
+ [Fact]
+ public void Ctor_OwnedMemory_Offset()
+ {
+ var ownedMemory = new CustomMemoryForTest<byte>(new byte[] { 1, 2, 3, 4, 5 }, 0, 5);
+ var buffer = new ReadOnlySequence<byte>(ownedMemory, 2, 3);
+
+ Assert.True(SequenceMarshal.TryGetOwnedMemory(buffer, out OwnedMemory<byte> newOwnedMemory, out int start, out int length));
+ Assert.Equal(ownedMemory, newOwnedMemory);
+ Assert.Equal(2, start);
+ Assert.Equal(3, length);
+
+ Assert.False(SequenceMarshal.TryGetReadOnlySequenceSegment(buffer, out _, out _, out _, out _));
+ Assert.False(SequenceMarshal.TryGetArray(buffer, out _));
+
+ // OwnedMemory can be retrieved with TryGetReadOnlyMemory
+ Assert.True(SequenceMarshal.TryGetReadOnlyMemory(buffer, out ReadOnlyMemory<byte> newMemory));
+ Assert.Equal(new byte[] { 3, 4, 5 }, newMemory.ToArray());
+ }
+
+ [Fact]
+ public void Ctor_IMemoryList_SingleBlock()
+ {
+ var memoryListSegment = new BufferSegment<byte>(new byte[] { 1, 2, 3, 4, 5 });
+
+ var buffer = new ReadOnlySequence<byte>(memoryListSegment, 2, memoryListSegment, 5);
+
+ Assert.True(SequenceMarshal.TryGetReadOnlySequenceSegment(buffer, out ReadOnlySequenceSegment<byte> startSegment, out int startIndex, out ReadOnlySequenceSegment<byte> endSegment, out int endIndex));
+ Assert.Equal(startSegment, memoryListSegment);
+ Assert.Equal(endSegment, memoryListSegment);
+
+ Assert.Equal(2, startIndex);
+ Assert.Equal(5, endIndex);
+
+ Assert.False(SequenceMarshal.TryGetArray(buffer, out _));
+ Assert.False(SequenceMarshal.TryGetOwnedMemory(buffer, out _, out _, out _));
+
+ // Single block can be retrieved with TryGetReadOnlyMemory
+ Assert.True(SequenceMarshal.TryGetReadOnlyMemory(buffer, out ReadOnlyMemory<byte> newMemory));
+ Assert.Equal(new byte[] { 3, 4, 5 }, newMemory.ToArray());
+ }
+
+ [Fact]
+ public void Ctor_IMemoryList_MultiBlock()
+ {
+ var memoryListSegment1 = new BufferSegment<byte>(new byte[] { 1, 2, 3 });
+ var memoryListSegment2 = memoryListSegment1.Append(new byte[] { 4, 5 });
+
+ var buffer = new ReadOnlySequence<byte>(memoryListSegment1, 2, memoryListSegment2, 1);
+
+ Assert.True(SequenceMarshal.TryGetReadOnlySequenceSegment(buffer, out ReadOnlySequenceSegment<byte> startSegment, out int startIndex, out ReadOnlySequenceSegment<byte> endSegment, out int endIndex));
+ Assert.Equal(startSegment, memoryListSegment1);
+ Assert.Equal(endSegment, memoryListSegment2);
+
+ Assert.Equal(2, startIndex);
+ Assert.Equal(1, endIndex);
+
+ Assert.False(SequenceMarshal.TryGetArray(buffer, out _));
+ Assert.False(SequenceMarshal.TryGetOwnedMemory(buffer, out _, out _, out _));
+
+ // Multi-block can't be retrieved with TryGetReadOnlyMemory
+ Assert.False(SequenceMarshal.TryGetReadOnlyMemory(buffer, out _));
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.byte.cs b/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.byte.cs
new file mode 100644
index 0000000000..3e49ca7ac6
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.byte.cs
@@ -0,0 +1,315 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Linq;
+using System.Text;
+using Xunit;
+
+namespace System.Memory.Tests
+{
+ public abstract class ReadOnlySequenceTestsByte
+ {
+ public class Array : ReadOnlySequenceTestsByte
+ {
+ public Array() : base(ReadOnlySequenceFactoryByte.ArrayFactory) { }
+ }
+
+ public class OwnedMemory : ReadOnlySequenceTestsByte
+ {
+ public OwnedMemory() : base(ReadOnlySequenceFactoryByte.OwnedMemoryFactory) { }
+ }
+
+ public class Memory : ReadOnlySequenceTestsByte
+ {
+ public Memory() : base(ReadOnlySequenceFactoryByte.MemoryFactory) { }
+ }
+
+ public class SingleSegment : ReadOnlySequenceTestsByte
+ {
+ public SingleSegment() : base(ReadOnlySequenceFactoryByte.SingleSegmentFactory) { }
+ }
+
+ public class SegmentPerByte : ReadOnlySequenceTestsByte
+ {
+ public SegmentPerByte() : base(ReadOnlySequenceFactoryByte.SegmentPerByteFactory) { }
+ }
+
+ internal ReadOnlySequenceFactoryByte Factory { get; }
+
+ internal ReadOnlySequenceTestsByte(ReadOnlySequenceFactoryByte factory)
+ {
+ Factory = factory;
+ }
+
+ [Fact]
+ public void EmptyIsCorrect()
+ {
+ ReadOnlySequence<byte> buffer = Factory.CreateOfSize(0);
+ Assert.Equal(0, buffer.Length);
+ Assert.True(buffer.IsEmpty);
+ }
+
+ [Theory]
+ [InlineData(1)]
+ [InlineData(8)]
+ public void LengthIsCorrect(int length)
+ {
+ ReadOnlySequence<byte> buffer = Factory.CreateOfSize(length);
+ Assert.Equal(length, buffer.Length);
+ }
+
+ [Theory]
+ [InlineData(1)]
+ [InlineData(8)]
+ public void ToArrayIsCorrect(int length)
+ {
+ byte[] data = Enumerable.Range(0, length).Select(i => (byte)i).ToArray();
+ ReadOnlySequence<byte> buffer = Factory.CreateWithContent(data);
+ Assert.Equal(length, buffer.Length);
+ Assert.Equal(data, buffer.ToArray());
+ }
+
+ [Fact]
+ public void ToStringIsCorrect()
+ {
+ ReadOnlySequence<byte> buffer = Factory.CreateWithContent(Enumerable.Range(0, 255).Select(i => (byte)i).ToArray());
+ Assert.Equal("System.Buffers.ReadOnlySequence<Byte>[255]", buffer.ToString());
+ }
+
+ [Theory]
+ [MemberData(nameof(ValidSliceCases))]
+ public void Slice_Works(Func<ReadOnlySequence<byte>, ReadOnlySequence<byte>> func)
+ {
+ ReadOnlySequence<byte> buffer = Factory.CreateWithContent(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });
+ ReadOnlySequence<byte> slice = func(buffer);
+ Assert.Equal(new byte[] { 5, 6, 7, 8, 9 }, slice.ToArray());
+ }
+
+ [Theory]
+ [MemberData(nameof(OutOfRangeSliceCases))]
+ public void ReadOnlyBufferDoesNotAllowSlicingOutOfRange(Action<ReadOnlySequence<byte>> fail)
+ {
+ ReadOnlySequence<byte> buffer = Factory.CreateOfSize(100);
+ Assert.Throws<ArgumentOutOfRangeException>(() => fail(buffer));
+ }
+
+ [Fact]
+ public void ReadOnlyBufferGetPosition_MovesPosition()
+ {
+ ReadOnlySequence<byte> buffer = Factory.CreateOfSize(100);
+
+ SequencePosition position = buffer.GetPosition(65);
+ Assert.Equal(buffer.Slice(position).Length, 35);
+
+ position = buffer.GetPosition(65, buffer.Start);
+ Assert.Equal(buffer.Slice(position).Length, 35);
+ }
+
+ [Fact]
+ public void ReadOnlyBufferGetPosition_ChecksBounds()
+ {
+ ReadOnlySequence<byte> buffer = Factory.CreateOfSize(100);
+ Assert.Throws<ArgumentOutOfRangeException>(() => buffer.GetPosition(101));
+ Assert.Throws<ArgumentOutOfRangeException>(() => buffer.GetPosition(101, buffer.Start));
+ }
+
+ [Fact]
+ public void ReadOnlyBufferGetPosition_DoesNotAlowNegative()
+ {
+ ReadOnlySequence<byte> buffer = Factory.CreateOfSize(20);
+ Assert.Throws<ArgumentOutOfRangeException>(() => buffer.GetPosition(-1));
+ Assert.Throws<ArgumentOutOfRangeException>(() => buffer.GetPosition(-1, buffer.Start));
+ }
+
+ public void ReadOnlyBufferSlice_ChecksEnd()
+ {
+ ReadOnlySequence<byte> buffer = Factory.CreateOfSize(100);
+ Assert.Throws<ArgumentOutOfRangeException>(() => buffer.Slice(70, buffer.Start));
+ }
+
+ [Fact]
+ public void SegmentStartIsConsideredInBoundsCheck()
+ {
+ // 0 50 100 0 50 100
+ // [ ##############] -> [############## ]
+ // ^c1 ^c2
+ var bufferSegment1 = new BufferSegment<byte>(new byte[49]);
+ BufferSegment<byte> bufferSegment2 = bufferSegment1.Append(new byte[50]);
+
+ var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment2, 50);
+
+ SequencePosition c1 = buffer.GetPosition(25); // segment 1 index 75
+ SequencePosition c2 = buffer.GetPosition(55); // segment 2 index 5
+
+ ReadOnlySequence<byte> sliced = buffer.Slice(c1, c2);
+ Assert.Equal(30, sliced.Length);
+
+ c1 = buffer.GetPosition(25, buffer.Start); // segment 1 index 75
+ c2 = buffer.GetPosition(55, buffer.Start); // segment 2 index 5
+
+ sliced = buffer.Slice(c1, c2);
+ Assert.Equal(30, sliced.Length);
+ }
+
+ [Fact]
+ public void GetPositionPrefersNextSegment()
+ {
+ BufferSegment<byte> bufferSegment1 = new BufferSegment<byte>(new byte[50]);
+ BufferSegment<byte> bufferSegment2 = bufferSegment1.Append(new byte[0]);
+
+ ReadOnlySequence<byte> buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment2, 0);
+
+ SequencePosition c1 = buffer.GetPosition(50);
+
+ Assert.Equal(0, c1.GetInteger());
+ Assert.Equal(bufferSegment2, c1.GetObject());
+
+ c1 = buffer.GetPosition(50, buffer.Start);
+
+ Assert.Equal(0, c1.GetInteger());
+ Assert.Equal(bufferSegment2, c1.GetObject());
+ }
+
+ [Fact]
+ public void GetPositionDoesNotCrossOutsideBuffer()
+ {
+ var bufferSegment1 = new BufferSegment<byte>(new byte[100]);
+ BufferSegment<byte> bufferSegment2 = bufferSegment1.Append(new byte[100]);
+ BufferSegment<byte> bufferSegment3 = bufferSegment2.Append(new byte[0]);
+
+ var buffer = new ReadOnlySequence<byte>(bufferSegment1, 0, bufferSegment2, 100);
+
+ SequencePosition c1 = buffer.GetPosition(200);
+
+ Assert.Equal(100, c1.GetInteger());
+ Assert.Equal(bufferSegment2, c1.GetObject());
+
+ c1 = buffer.GetPosition(200, buffer.Start);
+
+ Assert.Equal(100, c1.GetInteger());
+ Assert.Equal(bufferSegment2, c1.GetObject());
+ }
+
+ [Fact]
+ public void Create_WorksWithArray()
+ {
+ var buffer = new ReadOnlySequence<byte>(new byte[] { 1, 2, 3, 4, 5 });
+ Assert.Equal(buffer.ToArray(), new byte[] { 1, 2, 3, 4, 5 });
+ }
+
+ [Fact]
+ public void Empty_ReturnsLengthZeroBuffer()
+ {
+ var buffer = ReadOnlySequence<byte>.Empty;
+ Assert.Equal(0, buffer.Length);
+ Assert.Equal(true, buffer.IsSingleSegment);
+ Assert.Equal(0, buffer.First.Length);
+ }
+
+ [Fact]
+ public void Create_WorksWithArrayWithOffset()
+ {
+ var buffer = new ReadOnlySequence<byte>(new byte[] { 1, 2, 3, 4, 5 }, 2, 3);
+ Assert.Equal(buffer.ToArray(), new byte[] { 3, 4, 5 });
+ }
+
+ [Fact]
+ public void C_WorksWithArrayWithOffset()
+ {
+ var buffer = new ReadOnlySequence<byte>(new byte[] { 1, 2, 3, 4, 5 }, 2, 3);
+ Assert.Equal(buffer.ToArray(), new byte[] { 3, 4, 5 });
+ }
+
+
+ [Fact]
+ public void Create_WorksWithMemory()
+ {
+ var memory = new ReadOnlyMemory<byte>(new byte[] { 1, 2, 3, 4, 5 });
+ var buffer = new ReadOnlySequence<byte>(memory.Slice(2, 3));
+ Assert.Equal(new byte[] { 3, 4, 5 }, buffer.ToArray());
+ }
+
+ [Fact]
+ public void SliceToTheEndWorks()
+ {
+ ReadOnlySequence<byte> buffer = Factory.CreateOfSize(10);
+ Assert.True(buffer.Slice(buffer.End).IsEmpty);
+ }
+
+ [Theory]
+ [InlineData("a", 'a', 0)]
+ [InlineData("ab", 'a', 0)]
+ [InlineData("aab", 'a', 0)]
+ [InlineData("acab", 'a', 0)]
+ [InlineData("acab", 'c', 1)]
+ [InlineData("abcdefghijklmnopqrstuvwxyz", 'l', 11)]
+ [InlineData("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", 'l', 11)]
+ [InlineData("aaaaaaaaaaacmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", 'm', 12)]
+ [InlineData("aaaaaaaaaaarmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", 'r', 11)]
+ [InlineData("/localhost:5000/PATH/%2FPATH2/ HTTP/1.1", '%', 21)]
+ [InlineData("/localhost:5000/PATH/%2FPATH2/?key=value HTTP/1.1", '%', 21)]
+ [InlineData("/localhost:5000/PATH/PATH2/?key=value HTTP/1.1", '?', 27)]
+ [InlineData("/localhost:5000/PATH/PATH2/ HTTP/1.1", ' ', 27)]
+ public void PositionOf_ReturnsPosition(string raw, char searchFor, int expectIndex)
+ {
+ ReadOnlySequence<byte> buffer = Factory.CreateWithContent(raw);
+ SequencePosition? result = buffer.PositionOf((byte)searchFor);
+
+ Assert.NotNull(result);
+ Assert.Equal(buffer.Slice(result.Value).ToArray(), Encoding.ASCII.GetBytes(raw.Substring(expectIndex)));
+ }
+
+ [Fact]
+ public void PositionOf_ReturnsNullIfNotFound()
+ {
+ ReadOnlySequence<byte> buffer = Factory.CreateWithContent(new byte[] { 1, 2, 3 });
+ SequencePosition? result = buffer.PositionOf((byte)4);
+
+ Assert.Null(result);
+ }
+
+ [Fact]
+ public void CopyTo_ThrowsWhenSourceLargerThenDestination()
+ {
+ ReadOnlySequence<byte> buffer = Factory.CreateOfSize(10);
+
+ Assert.Throws<ArgumentOutOfRangeException>(() =>
+ {
+ Span<byte> span = new byte[5];
+ buffer.CopyTo(span);
+ });
+ }
+
+ public static TheoryData<Func<ReadOnlySequence<byte>, ReadOnlySequence<byte>>> ValidSliceCases => new TheoryData<Func<ReadOnlySequence<byte>, ReadOnlySequence<byte>>>
+ {
+ b => b.Slice(5),
+ b => b.Slice(0).Slice(5),
+ b => b.Slice(5, 5),
+ b => b.Slice(b.GetPosition(5), 5),
+ b => b.Slice(5, b.GetPosition(10)),
+ b => b.Slice(b.GetPosition(5), b.GetPosition(10)),
+ b => b.Slice(b.GetPosition(5, b.Start), 5),
+ b => b.Slice(5, b.GetPosition(10, b.Start)),
+ b => b.Slice(b.GetPosition(5, b.Start), b.GetPosition(10, b.Start)),
+
+ b => b.Slice((long)5),
+ b => b.Slice((long)5, 5),
+ b => b.Slice(b.GetPosition(5), (long)5),
+ b => b.Slice((long)5, b.GetPosition(10)),
+ b => b.Slice(b.GetPosition(5, b.Start), (long)5),
+ b => b.Slice((long)5, b.GetPosition(10, b.Start)),
+ };
+
+ public static TheoryData<Action<ReadOnlySequence<byte>>> OutOfRangeSliceCases => new TheoryData<Action<ReadOnlySequence<byte>>>
+ {
+ b => b.Slice(101),
+ b => b.Slice(0, 101),
+ b => b.Slice(b.Start, 101),
+ b => b.Slice(0, 70).Slice(b.End, b.End),
+ b => b.Slice(0, 70).Slice(b.Start, b.End),
+ b => b.Slice(0, 70).Slice(0, b.End)
+ };
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.char.cs b/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.char.cs
new file mode 100644
index 0000000000..53a2f1a1a4
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.char.cs
@@ -0,0 +1,318 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Linq;
+using System.Text;
+using Xunit;
+
+namespace System.Memory.Tests
+{
+ public abstract class ReadOnlySequenceTestsChar
+ {
+ public class Array : ReadOnlySequenceTestsChar
+ {
+ public Array() : base(ReadOnlySequenceFactoryChar.ArrayFactory) { }
+ }
+
+ public class String : ReadOnlySequenceTestsChar
+ {
+ public String() : base(ReadOnlySequenceFactoryChar.StringFactory) { }
+ }
+
+ public class OwnedMemory : ReadOnlySequenceTestsChar
+ {
+ public OwnedMemory() : base(ReadOnlySequenceFactoryChar.OwnedMemoryFactory) { }
+ }
+
+ public class Memory : ReadOnlySequenceTestsChar
+ {
+ public Memory() : base(ReadOnlySequenceFactoryChar.MemoryFactory) { }
+ }
+
+ public class SingleSegment : ReadOnlySequenceTestsChar
+ {
+ public SingleSegment() : base(ReadOnlySequenceFactoryChar.SingleSegmentFactory) { }
+ }
+
+ public class SegmentPerChar : ReadOnlySequenceTestsChar
+ {
+ public SegmentPerChar() : base(ReadOnlySequenceFactoryChar.SegmentPerCharFactory) { }
+ }
+
+ internal ReadOnlySequenceFactoryChar Factory { get; }
+
+ internal ReadOnlySequenceTestsChar(ReadOnlySequenceFactoryChar factory)
+ {
+ Factory = factory;
+ }
+
+ [Fact]
+ public void EmptyIsCorrect()
+ {
+ ReadOnlySequence<char> buffer = Factory.CreateOfSize(0);
+ Assert.Equal(0, buffer.Length);
+ Assert.True(buffer.IsEmpty);
+ }
+
+ [Theory]
+ [InlineData(1)]
+ [InlineData(8)]
+ public void LengthIsCorrect(int length)
+ {
+ ReadOnlySequence<char> buffer = Factory.CreateOfSize(length);
+ Assert.Equal(length, buffer.Length);
+ }
+
+ [Theory]
+ [InlineData(1)]
+ [InlineData(8)]
+ public void ToArrayIsCorrect(int length)
+ {
+ char[] data = Enumerable.Range(0, length).Select(i => (char)i).ToArray();
+ ReadOnlySequence<char> buffer = Factory.CreateWithContent(data);
+ Assert.Equal(length, buffer.Length);
+ Assert.Equal(data, buffer.ToArray());
+ }
+
+ [Fact]
+ public void ToStringIsCorrect()
+ {
+ ReadOnlySequence<char> buffer = Factory.CreateWithContent(Enumerable.Range(0, 255).Select(i => (char)i).ToArray());
+ Assert.Equal("System.Buffers.ReadOnlySequence<Char>[255]", buffer.ToString());
+ }
+
+ [Theory]
+ [MemberData(nameof(ValidSliceCases))]
+ public void Slice_Works(Func<ReadOnlySequence<char>, ReadOnlySequence<char>> func)
+ {
+ ReadOnlySequence<char> buffer = Factory.CreateWithContent(new char[] { (char)0, (char)1, (char)2, (char)3, (char)4, (char)5, (char)6, (char)7, (char)8, (char)9 });
+ ReadOnlySequence<char> slice = func(buffer);
+ Assert.Equal(new char[] { (char)5, (char)6, (char)7, (char)8, (char)9 }, slice.ToArray());
+ }
+
+ [Theory]
+ [MemberData(nameof(OutOfRangeSliceCases))]
+ public void ReadOnlyBufferDoesNotAllowSlicingOutOfRange(Action<ReadOnlySequence<char>> fail)
+ {
+ ReadOnlySequence<char> buffer = Factory.CreateOfSize(100);
+ Assert.Throws<ArgumentOutOfRangeException>(() => fail(buffer));
+ }
+
+ [Fact]
+ public void ReadOnlyBufferGetPosition_MovesPosition()
+ {
+ ReadOnlySequence<char> buffer = Factory.CreateOfSize(100);
+ SequencePosition position = buffer.GetPosition(65);
+ Assert.Equal(buffer.Slice(position).Length, 35);
+ position = buffer.GetPosition(65, buffer.Start);
+ Assert.Equal(buffer.Slice(position).Length, 35);
+ }
+
+ [Fact]
+ public void ReadOnlyBufferGetPosition_ChecksBounds()
+ {
+ ReadOnlySequence<char> buffer = Factory.CreateOfSize(100);
+ Assert.Throws<ArgumentOutOfRangeException>(() => buffer.GetPosition(101));
+ Assert.Throws<ArgumentOutOfRangeException>(() => buffer.GetPosition(101, buffer.Start));
+ }
+
+ [Fact]
+ public void ReadOnlyBufferGetPosition_DoesNotAlowNegative()
+ {
+ ReadOnlySequence<char> buffer = Factory.CreateOfSize(20);
+ Assert.Throws<ArgumentOutOfRangeException>(() => buffer.GetPosition(-1));
+ Assert.Throws<ArgumentOutOfRangeException>(() => buffer.GetPosition(-1, buffer.Start));
+ }
+
+ public void ReadOnlyBufferSlice_ChecksEnd()
+ {
+ ReadOnlySequence<char> buffer = Factory.CreateOfSize(100);
+ Assert.Throws<ArgumentOutOfRangeException>(() => buffer.Slice(70, buffer.Start));
+ }
+
+ [Fact]
+ public void SegmentStartIsConsideredInBoundsCheck()
+ {
+ // 0 50 100 0 50 100
+ // [ ##############] -> [############## ]
+ // ^c1 ^c2
+ var bufferSegment1 = new BufferSegment<char>(new char[49]);
+ BufferSegment<char> bufferSegment2 = bufferSegment1.Append(new char[50]);
+
+ var buffer = new ReadOnlySequence<char>(bufferSegment1, 0, bufferSegment2, 50);
+
+ SequencePosition c1 = buffer.GetPosition(25); // segment 1 index 75
+ SequencePosition c2 = buffer.GetPosition(55); // segment 2 index 5
+
+ ReadOnlySequence<char> sliced = buffer.Slice(c1, c2);
+ Assert.Equal(30, sliced.Length);
+
+ c1 = buffer.GetPosition(25, buffer.Start); // segment 1 index 75
+ c2 = buffer.GetPosition(55, buffer.Start); // segment 2 index 5
+
+ sliced = buffer.Slice(c1, c2);
+ Assert.Equal(30, sliced.Length);
+ }
+
+ [Fact]
+ public void GetPositionPrefersNextSegment()
+ {
+ BufferSegment<char> bufferSegment1 = new BufferSegment<char>(new char[50]);
+ BufferSegment<char> bufferSegment2 = bufferSegment1.Append(new char[0]);
+
+ ReadOnlySequence<char> buffer = new ReadOnlySequence<char>(bufferSegment1, 0, bufferSegment2, 0);
+
+ SequencePosition c1 = buffer.GetPosition(50);
+
+ Assert.Equal(0, c1.GetInteger());
+ Assert.Equal(bufferSegment2, c1.GetObject());
+
+ c1 = buffer.GetPosition(50, buffer.Start);
+
+ Assert.Equal(0, c1.GetInteger());
+ Assert.Equal(bufferSegment2, c1.GetObject());
+ }
+
+ [Fact]
+ public void GetPositionDoesNotCrossOutsideBuffer()
+ {
+ var bufferSegment1 = new BufferSegment<char>(new char[100]);
+ BufferSegment<char> bufferSegment2 = bufferSegment1.Append(new char[100]);
+ BufferSegment<char> bufferSegment3 = bufferSegment2.Append(new char[0]);
+
+ var buffer = new ReadOnlySequence<char>(bufferSegment1, 0, bufferSegment2, 100);
+
+ SequencePosition c1 = buffer.GetPosition(200);
+
+ Assert.Equal(100, c1.GetInteger());
+ Assert.Equal(bufferSegment2, c1.GetObject());
+
+ c1 = buffer.GetPosition(200, buffer.Start);
+
+ Assert.Equal(100, c1.GetInteger());
+ Assert.Equal(bufferSegment2, c1.GetObject());
+ }
+
+ [Fact]
+ public void Create_WorksWithArray()
+ {
+ var buffer = new ReadOnlySequence<char>(new char[] { (char)1, (char)2, (char)3, (char)4, (char)5 });
+ Assert.Equal(buffer.ToArray(), new char[] { (char)1, (char)2, (char)3, (char)4, (char)5 });
+ }
+
+ [Fact]
+ public void Empty_ReturnsLengthZeroBuffer()
+ {
+ var buffer = ReadOnlySequence<char>.Empty;
+ Assert.Equal(0, buffer.Length);
+ Assert.Equal(true, buffer.IsSingleSegment);
+ Assert.Equal(0, buffer.First.Length);
+ }
+
+ [Fact]
+ public void Create_WorksWithArrayWithOffset()
+ {
+ var buffer = new ReadOnlySequence<char>(new char[] { (char)1, (char)2, (char)3, (char)4, (char)5 }, 2, 3);
+ Assert.Equal(buffer.ToArray(), new char[] { (char)3, (char)4, (char)5 });
+ }
+
+ [Fact]
+ public void C_WorksWithArrayWithOffset()
+ {
+ var buffer = new ReadOnlySequence<char>(new char[] { (char)1, (char)2, (char)3, (char)4, (char)5 }, 2, 3);
+ Assert.Equal(buffer.ToArray(), new char[] { (char)3, (char)4, (char)5 });
+ }
+
+
+ [Fact]
+ public void Create_WorksWithMemory()
+ {
+ var memory = new ReadOnlyMemory<char>(new char[] { (char)1, (char)2, (char)3, (char)4, (char)5 });
+ var buffer = new ReadOnlySequence<char>(memory.Slice(2, 3));
+ Assert.Equal(new char[] { (char)3, (char)4, (char)5 }, buffer.ToArray());
+ }
+
+ [Fact]
+ public void SliceToTheEndWorks()
+ {
+ ReadOnlySequence<char> buffer = Factory.CreateOfSize(10);
+ Assert.True(buffer.Slice(buffer.End).IsEmpty);
+ }
+
+ [Theory]
+ [InlineData("a", 'a', 0)]
+ [InlineData("ab", 'a', 0)]
+ [InlineData("aab", 'a', 0)]
+ [InlineData("acab", 'a', 0)]
+ [InlineData("acab", 'c', 1)]
+ [InlineData("abcdefghijklmnopqrstuvwxyz", 'l', 11)]
+ [InlineData("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", 'l', 11)]
+ [InlineData("aaaaaaaaaaacmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", 'm', 12)]
+ [InlineData("aaaaaaaaaaarmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", 'r', 11)]
+ [InlineData("/localhost:5000/PATH/%2FPATH2/ HTTP/1.1", '%', 21)]
+ [InlineData("/localhost:5000/PATH/%2FPATH2/?key=value HTTP/1.1", '%', 21)]
+ [InlineData("/localhost:5000/PATH/PATH2/?key=value HTTP/1.1", '?', 27)]
+ [InlineData("/localhost:5000/PATH/PATH2/ HTTP/1.1", ' ', 27)]
+ public void PositionOf_ReturnsPosition(string raw, char searchFor, int expectIndex)
+ {
+ ReadOnlySequence<char> buffer = Factory.CreateWithContent(raw);
+ SequencePosition? result = buffer.PositionOf((char)searchFor);
+
+ Assert.NotNull(result);
+ Assert.Equal(buffer.Slice(result.Value).ToArray(), raw.Substring(expectIndex));
+ }
+
+ [Fact]
+ public void PositionOf_ReturnsNullIfNotFound()
+ {
+ ReadOnlySequence<char> buffer = Factory.CreateWithContent(new char[] { (char)1, (char)2, (char)3 });
+ SequencePosition? result = buffer.PositionOf((char)4);
+
+ Assert.Null(result);
+ }
+
+ [Fact]
+ public void CopyTo_ThrowsWhenSourceLargerThenDestination()
+ {
+ ReadOnlySequence<char> buffer = Factory.CreateOfSize(10);
+
+ Assert.Throws<ArgumentOutOfRangeException>(() =>
+ {
+ Span<char> span = new char[5];
+ buffer.CopyTo(span);
+ });
+ }
+
+ public static TheoryData<Func<ReadOnlySequence<char>, ReadOnlySequence<char>>> ValidSliceCases => new TheoryData<Func<ReadOnlySequence<char>, ReadOnlySequence<char>>>
+ {
+ b => b.Slice(5),
+ b => b.Slice(0).Slice(5),
+ b => b.Slice(5, 5),
+ b => b.Slice(b.GetPosition(5), 5),
+ b => b.Slice(5, b.GetPosition(10)),
+ b => b.Slice(b.GetPosition(5), b.GetPosition(10)),
+ b => b.Slice(b.GetPosition(5, b.Start), 5),
+ b => b.Slice(5, b.GetPosition(10, b.Start)),
+ b => b.Slice(b.GetPosition(5, b.Start), b.GetPosition(10, b.Start)),
+
+ b => b.Slice((long)5),
+ b => b.Slice((long)5, 5),
+ b => b.Slice(b.GetPosition(5), (long)5),
+ b => b.Slice((long)5, b.GetPosition(10)),
+ b => b.Slice(b.GetPosition(5, b.Start), (long)5),
+ b => b.Slice((long)5, b.GetPosition(10, b.Start)),
+ };
+
+ public static TheoryData<Action<ReadOnlySequence<char>>> OutOfRangeSliceCases => new TheoryData<Action<ReadOnlySequence<char>>>
+ {
+ b => b.Slice(101),
+ b => b.Slice(0, 101),
+ b => b.Slice(b.Start, 101),
+ b => b.Slice(0, 70).Slice(b.End, b.End),
+ b => b.Slice(0, 70).Slice(b.Start, b.End),
+ b => b.Slice(0, 70).Slice(0, b.End)
+ };
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlyBuffer/SequencePosition.cs b/src/System.Memory/tests/ReadOnlyBuffer/SequencePosition.cs
new file mode 100644
index 0000000000..83598b40e4
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlyBuffer/SequencePosition.cs
@@ -0,0 +1,38 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.Memory.Tests
+{
+ public class SequencePostionTests
+ {
+ [Fact]
+ public void ComparisonMembers_NotNullSegment()
+ {
+ var segment = new object();
+ var position = new SequencePosition(segment, 2);
+ var position2 = new SequencePosition(segment, 2);
+
+ Assert.True(position == position2);
+ Assert.True(position.Equals(position2));
+ Assert.True(position.Equals((object)position2));
+ Assert.False(position != position2);
+ Assert.Equal(position.GetHashCode(), position2.GetHashCode());
+ }
+
+ [Fact]
+ public void ComparisonMembers_NullSegment()
+ {
+ var position = new SequencePosition(null, 2);
+ var position2 = new SequencePosition(null, 2);
+
+ Assert.True(position == position2);
+ Assert.True(position.Equals(position2));
+ Assert.True(position.Equals((object)position2));
+ Assert.False(position != position2);
+ Assert.Equal(position.GetHashCode(), position2.GetHashCode());
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlyMemory/CtorArray.cs b/src/System.Memory/tests/ReadOnlyMemory/CtorArray.cs
index 046398c076..6fd20a453d 100644
--- a/src/System.Memory/tests/ReadOnlyMemory/CtorArray.cs
+++ b/src/System.Memory/tests/ReadOnlyMemory/CtorArray.cs
@@ -72,8 +72,22 @@ namespace System.MemoryTests
[Fact]
public static void CtorArrayNullArray()
{
- Assert.Throws<ArgumentNullException>(() => new ReadOnlyMemory<int>(null));
- Assert.Throws<ArgumentNullException>(() => new ReadOnlyMemory<int>(null, 0, 0));
+ var memory = new ReadOnlyMemory<int>(null);
+ memory.Validate();
+ Assert.Equal(default, memory);
+
+ memory = new ReadOnlyMemory<int>(null, 0, 0);
+ memory.Validate();
+ Assert.Equal(default, memory);
+ }
+
+ [Fact]
+ public static void CtorArrayNullArrayNonZeroStartAndLength()
+ {
+ Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlyMemory<int>(null, 1, 0));
+ Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlyMemory<int>(null, 0, 1));
+ Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlyMemory<int>(null, 1, 1));
+ Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlyMemory<int>(null, -1, -1));
}
[Fact]
diff --git a/src/System.Memory/tests/ReadOnlyMemory/Pin.cs b/src/System.Memory/tests/ReadOnlyMemory/Pin.cs
new file mode 100644
index 0000000000..803612035c
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlyMemory/Pin.cs
@@ -0,0 +1,133 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using Xunit;
+
+namespace System.MemoryTests
+{
+ public static partial class ReadOnlyMemoryTests
+ {
+ [Fact]
+ public static void MemoryPin()
+ {
+ int[] array = { 1, 2, 3, 4, 5 };
+ ReadOnlyMemory<int> memory = array;
+ MemoryHandle handle = memory.Pin();
+ Assert.True(handle.HasPointer);
+ unsafe
+ {
+ int* pointer = (int*)handle.Pointer;
+
+ GC.Collect();
+
+ for (int i = 0; i < memory.Length; i++)
+ {
+ Assert.Equal(array[i], pointer[i]);
+ }
+ }
+ handle.Dispose();
+ }
+
+ [Fact]
+ public static void MemoryFromEmptyArrayPin()
+ {
+ ReadOnlyMemory<int> memory = new int[0];
+ MemoryHandle handle = memory.Pin();
+ Assert.True(handle.HasPointer);
+ handle.Dispose();
+ }
+
+ [Fact]
+ public static void DefaultMemoryPin()
+ {
+ ReadOnlyMemory<int> memory = default;
+ MemoryHandle handle = memory.Pin();
+ Assert.False(handle.HasPointer);
+ unsafe
+ {
+ Assert.True(handle.Pointer == null);
+ }
+ handle.Dispose();
+ }
+
+ [Fact]
+ public static void MemoryPinAndSlice()
+ {
+ int[] array = { 1, 2, 3, 4, 5 };
+ ReadOnlyMemory<int> memory = array;
+ memory = memory.Slice(1);
+ MemoryHandle handle = memory.Pin();
+ ReadOnlySpan<int> span = memory.Span;
+ Assert.True(handle.HasPointer);
+ unsafe
+ {
+ int* pointer = (int*)handle.Pointer;
+
+ GC.Collect();
+
+ for (int i = 0; i < memory.Length; i++)
+ {
+ Assert.Equal(array[i + 1], pointer[i]);
+ }
+
+ for (int i = 0; i < memory.Length; i++)
+ {
+ Assert.Equal(array[i + 1], span[i]);
+ }
+ }
+ handle.Dispose();
+ }
+
+ [Fact]
+ public static void OwnedMemoryPin()
+ {
+ int[] array = { 1, 2, 3, 4, 5 };
+ OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
+ ReadOnlyMemory<int> memory = owner.Memory;
+ MemoryHandle handle = memory.Pin();
+ Assert.True(handle.HasPointer);
+ unsafe
+ {
+ int* pointer = (int*)handle.Pointer;
+
+ GC.Collect();
+
+ for (int i = 0; i < memory.Length; i++)
+ {
+ Assert.Equal(array[i], pointer[i]);
+ }
+ }
+ handle.Dispose();
+ }
+
+ [Fact]
+ public static void OwnedMemoryPinAndSlice()
+ {
+ int[] array = { 1, 2, 3, 4, 5 };
+ OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
+ ReadOnlyMemory<int> memory = owner.Memory.Slice(1);
+ MemoryHandle handle = memory.Pin();
+ ReadOnlySpan<int> span = memory.Span;
+ Assert.True(handle.HasPointer);
+ unsafe
+ {
+ int* pointer = (int*)handle.Pointer;
+
+ GC.Collect();
+
+ for (int i = 0; i < memory.Length; i++)
+ {
+ Assert.Equal(array[i + 1], pointer[i]);
+ }
+
+ for (int i = 0; i < memory.Length; i++)
+ {
+ Assert.Equal(array[i + 1], span[i]);
+ }
+ }
+ handle.Dispose();
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlyMemory/Retain.cs b/src/System.Memory/tests/ReadOnlyMemory/Retain.cs
index 386211195a..d438c78d77 100644
--- a/src/System.Memory/tests/ReadOnlyMemory/Retain.cs
+++ b/src/System.Memory/tests/ReadOnlyMemory/Retain.cs
@@ -51,13 +51,20 @@ namespace System.MemoryTests
ReadOnlyMemory<int> memory = new int[0];
MemoryHandle handle = memory.Retain(pin: true);
Assert.True(handle.HasPointer);
+ handle.Dispose();
+ }
+
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public static void DefaultMemoryRetain(bool pin)
+ {
+ ReadOnlyMemory<int> memory = default;
+ MemoryHandle handle = memory.Retain(pin: pin);
+ Assert.False(handle.HasPointer);
unsafe
{
- int* pointer = (int*)handle.Pointer;
-
- GC.Collect();
-
- Assert.True(pointer != null);
+ Assert.True(handle.Pointer == null);
}
handle.Dispose();
}
@@ -154,20 +161,5 @@ namespace System.MemoryTests
}
handle.Dispose();
}
-
- [Theory]
- [InlineData(true)]
- [InlineData(false)]
- public static void DefaultMemoryRetain(bool pin)
- {
- ReadOnlyMemory<int> memory = default;
- MemoryHandle handle = memory.Retain(pin: pin);
- Assert.False(handle.HasPointer);
- unsafe
- {
- Assert.True(handle.Pointer == null);
- }
- handle.Dispose();
- }
}
}
diff --git a/src/System.Memory/tests/ReadOnlyMemory/Strings.cs b/src/System.Memory/tests/ReadOnlyMemory/Strings.cs
index 592f398987..6a775ad87a 100644
--- a/src/System.Memory/tests/ReadOnlyMemory/Strings.cs
+++ b/src/System.Memory/tests/ReadOnlyMemory/Strings.cs
@@ -22,7 +22,7 @@ namespace System.MemoryTests
[MemberData(nameof(StringInputs))]
public static void AsReadOnlyMemory_ToArray_Roundtrips(string input)
{
- ReadOnlyMemory<char> m = input.AsReadOnlyMemory();
+ ReadOnlyMemory<char> m = input.AsMemory();
Assert.Equal(input, new string(m.ToArray()));
}
@@ -30,7 +30,7 @@ namespace System.MemoryTests
[MemberData(nameof(StringInputs))]
public static void AsReadOnlyMemory_Span_Roundtrips(string input)
{
- ReadOnlyMemory<char> m = input.AsReadOnlyMemory();
+ ReadOnlyMemory<char> m = input.AsMemory();
ReadOnlySpan<char> s = m.Span;
Assert.Equal(input, new string(s.ToArray()));
}
@@ -47,85 +47,46 @@ namespace System.MemoryTests
[InlineData("0123456789", 5, 3)]
public static void AsReadOnlyMemory_Slice_MatchesSubstring(string input, int offset, int count)
{
- ReadOnlyMemory<char> m = input.AsReadOnlyMemory();
+ ReadOnlyMemory<char> m = input.AsMemory();
Assert.Equal(input.Substring(offset, count), new string(m.Slice(offset, count).ToArray()));
Assert.Equal(input.Substring(offset, count), new string(m.Slice(offset, count).Span.ToArray()));
Assert.Equal(input.Substring(offset), new string(m.Slice(offset).ToArray()));
}
[Fact]
- public static void AsReadOnlyMemory_NullString_Throws()
+ public static void AsReadOnlyMemory_NullString_Default()
{
- AssertExtensions.Throws<ArgumentNullException>("text", () => ((string)null).AsReadOnlyMemory());
- AssertExtensions.Throws<ArgumentNullException>("text", () => ((string)null).AsReadOnlyMemory(0));
- AssertExtensions.Throws<ArgumentNullException>("text", () => ((string)null).AsReadOnlyMemory(0, 0));
- }
+ ReadOnlyMemory<char> m = ((string)null).AsMemory();
+ m.Validate();
+ Assert.Equal(default, m);
- [Fact]
- public static void AsReadOnlyMemory_TryGetString_Roundtrips()
- {
- string input = "0123456789";
- ReadOnlyMemory<char> m = input.AsReadOnlyMemory();
- Assert.False(m.IsEmpty);
-
- Assert.True(m.TryGetString(out string text, out int start, out int length));
- Assert.Same(input, text);
- Assert.Equal(0, start);
- Assert.Equal(input.Length, length);
-
- m = m.Slice(1);
- Assert.True(m.TryGetString(out text, out start, out length));
- Assert.Same(input, text);
- Assert.Equal(1, start);
- Assert.Equal(input.Length - 1, length);
-
- m = m.Slice(1);
- Assert.True(m.TryGetString(out text, out start, out length));
- Assert.Same(input, text);
- Assert.Equal(2, start);
- Assert.Equal(input.Length - 2, length);
-
- m = m.Slice(3, 2);
- Assert.True(m.TryGetString(out text, out start, out length));
- Assert.Same(input, text);
- Assert.Equal(5, start);
- Assert.Equal(2, length);
-
- m = m.Slice(m.Length);
- Assert.True(m.TryGetString(out text, out start, out length));
- Assert.Same(input, text);
- Assert.Equal(7, start);
- Assert.Equal(0, length);
-
- m = m.Slice(0);
- Assert.True(m.TryGetString(out text, out start, out length));
- Assert.Same(input, text);
- Assert.Equal(7, start);
- Assert.Equal(0, length);
-
- m = m.Slice(0, 0);
- Assert.True(m.TryGetString(out text, out start, out length));
- Assert.Same(input, text);
- Assert.Equal(7, start);
- Assert.Equal(0, length);
-
- Assert.True(m.IsEmpty);
+ m = ((string)null).AsMemory(0);
+ m.Validate();
+ Assert.Equal(default, m);
+
+ m = ((string)null).AsMemory(0, 0);
+ m.Validate();
+ Assert.Equal(default, m);
}
[Fact]
- public static void Array_TryGetString_ReturnsFalse()
+ public static void NullAsReadOnlyMemoryNonZeroStartAndLength()
{
- ReadOnlyMemory<char> m = new char[10];
- Assert.False(m.TryGetString(out string text, out int start, out int length));
- Assert.Null(text);
- Assert.Equal(0, start);
- Assert.Equal(0, length);
+ string str = null;
+
+ Assert.Throws<ArgumentOutOfRangeException>(() => str.AsMemory(1));
+ Assert.Throws<ArgumentOutOfRangeException>(() => str.AsMemory(-1));
+
+ Assert.Throws<ArgumentOutOfRangeException>(() => str.AsMemory(0, 1));
+ Assert.Throws<ArgumentOutOfRangeException>(() => str.AsMemory(1, 0));
+ Assert.Throws<ArgumentOutOfRangeException>(() => str.AsMemory(1, 1));
+ Assert.Throws<ArgumentOutOfRangeException>(() => str.AsMemory(-1, -1));
}
[Fact]
public static void AsReadOnlyMemory_TryGetArray_ReturnsFalse()
{
- ReadOnlyMemory<char> m = "0123456789".AsReadOnlyMemory();
+ ReadOnlyMemory<char> m = "0123456789".AsMemory();
Assert.False(MemoryMarshal.TryGetArray(m, out ArraySegment<char> array));
Assert.Null(array.Array);
Assert.Equal(0, array.Offset);
@@ -133,17 +94,12 @@ namespace System.MemoryTests
}
[Fact]
- public static unsafe void AsReadOnlyMemory_Retain_ExpectedPointerValue()
+ public static unsafe void AsReadOnlyMemory_Pin_ExpectedPointerValue()
{
string input = "0123456789";
- ReadOnlyMemory<char> m = input.AsReadOnlyMemory();
-
- using (MemoryHandle h = m.Retain(pin: false))
- {
- Assert.Equal(IntPtr.Zero, (IntPtr)h.Pointer);
- }
+ ReadOnlyMemory<char> m = input.AsMemory();
- using (MemoryHandle h = m.Retain(pin: true))
+ using (MemoryHandle h = m.Pin())
{
GC.Collect();
fixed (char* ptr = input)
@@ -162,21 +118,21 @@ namespace System.MemoryTests
{
start = 0;
length = text.Length;
- m = text.AsReadOnlyMemory();
+ m = text.AsMemory();
}
else if (length == -1)
{
length = text.Length - start;
- m = text.AsReadOnlyMemory(start);
+ m = text.AsMemory(start);
}
else
{
- m = text.AsReadOnlyMemory(start, length);
+ m = text.AsMemory(start, length);
}
Assert.Equal(length, m.Length);
- using (MemoryHandle h = m.Retain(pin: true))
+ using (MemoryHandle h = m.Pin())
{
fixed (char* pText = text)
{
@@ -191,21 +147,21 @@ namespace System.MemoryTests
[MemberData(nameof(TestHelpers.StringSlice2ArgTestOutOfRangeData), MemberType = typeof(TestHelpers))]
public static unsafe void AsReadOnlyMemory_2Arg_OutOfRange(string text, int start)
{
- AssertExtensions.Throws<ArgumentOutOfRangeException>("start", () => text.AsReadOnlyMemory(start));
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("start", () => text.AsMemory(start));
}
[Theory]
[MemberData(nameof(TestHelpers.StringSlice3ArgTestOutOfRangeData), MemberType = typeof(TestHelpers))]
public static unsafe void AsReadOnlyMemory_3Arg_OutOfRange(string text, int start, int length)
{
- AssertExtensions.Throws<ArgumentOutOfRangeException>("start", () => text.AsReadOnlyMemory(start, length));
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("start", () => text.AsMemory(start, length));
}
[Fact]
public static void AsReadOnlyMemory_EqualsAndGetHashCode_ExpectedResults()
{
- ReadOnlyMemory<char> m1 = new string('a', 4).AsReadOnlyMemory();
- ReadOnlyMemory<char> m2 = new string('a', 4).AsReadOnlyMemory();
+ ReadOnlyMemory<char> m1 = new string('a', 4).AsMemory();
+ ReadOnlyMemory<char> m2 = new string('a', 4).AsMemory();
Assert.True(m1.Span.SequenceEqual(m2.Span));
Assert.True(m1.Equals(m1));
diff --git a/src/System.Memory/tests/ReadOnlyMemory/ToString.cs b/src/System.Memory/tests/ReadOnlyMemory/ToString.cs
new file mode 100644
index 0000000000..8781c53942
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlyMemory/ToString.cs
@@ -0,0 +1,128 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using Xunit;
+
+namespace System.MemoryTests
+{
+ public static partial class ReadOnlyMemoryTests
+ {
+ [Fact]
+ public static void ToStringInt()
+ {
+ int[] a = { 91, 92, 93 };
+ var memory = new ReadOnlyMemory<int>(a);
+ Assert.Equal("System.ReadOnlyMemory<Int32>[3]", memory.ToString());
+ Assert.Equal("System.ReadOnlyMemory<Int32>[1]", memory.Slice(1, 1).ToString());
+ Assert.Equal("System.ReadOnlySpan<Int32>[3]", memory.Span.ToString());
+ }
+
+ [Fact]
+ public static void ToStringInt_Empty()
+ {
+ var memory = new ReadOnlyMemory<int>();
+ Assert.Equal("System.ReadOnlyMemory<Int32>[0]", memory.ToString());
+ Assert.Equal("System.ReadOnlyMemory<Int32>[0]", ReadOnlyMemory<int>.Empty.ToString());
+ Assert.Equal("System.ReadOnlySpan<Int32>[0]", memory.Span.ToString());
+ }
+
+ [Fact]
+ public static void ToStringChar()
+ {
+ char[] a = { 'a', 'b', 'c' };
+ var memory = new ReadOnlyMemory<char>(a);
+ Assert.Equal("abc", memory.ToString());
+ Assert.Equal("b", memory.Slice(1, 1).ToString());
+ Assert.Equal("abc", memory.Span.ToString());
+ }
+
+ [Fact]
+ public static void ToStringChar_Empty()
+ {
+ var memory = new ReadOnlyMemory<char>();
+ Assert.Equal("", memory.ToString());
+ Assert.Equal("", ReadOnlyMemory<char>.Empty.ToString());
+ Assert.Equal("", memory.Span.ToString());
+ }
+
+ [Fact]
+ public static void ToStringMemoryFromReadOnlyMemory()
+ {
+ string testString = "abcdefg";
+ ReadOnlyMemory<char> memory = testString.AsMemory();
+ Assert.Equal(testString, memory.ToString());
+ Assert.Equal(testString.Substring(1, 1), memory.Slice(1, 1).ToString());
+ Assert.Equal(testString, memory.Span.ToString());
+ }
+
+ [Fact]
+ public static void ToStringForMemoryOfString()
+ {
+ string[] a = { "a", "b", "c" };
+ var memory = new ReadOnlyMemory<string>(a);
+ Assert.Equal("System.ReadOnlyMemory<String>[3]", memory.ToString());
+ Assert.Equal("System.ReadOnlyMemory<String>[1]", memory.Slice(1, 1).ToString());
+ Assert.Equal("System.ReadOnlySpan<String>[3]", memory.Span.ToString());
+ }
+
+ [Fact]
+ public static void ToStringFromMemoryFromOwnedMemory()
+ {
+ int[] a = { 91, 92, -93, 94 };
+ OwnedMemory<int> intOwner = new CustomMemoryForTest<int>(a);
+ Assert.Equal("System.ReadOnlyMemory<Int32>[4]", ((ReadOnlyMemory<int>)intOwner.Memory).ToString());
+
+ intOwner = new CustomMemoryForTest<int>(Array.Empty<int>());
+ Assert.Equal("System.ReadOnlyMemory<Int32>[0]", ((ReadOnlyMemory<int>)intOwner.Memory).ToString());
+
+ char[] charArray = { '1', '2', '-', '4' };
+ OwnedMemory<char> charOwner = new CustomMemoryForTest<char>(charArray);
+ Assert.Equal("12-4", ((ReadOnlyMemory<char>)charOwner.Memory).ToString());
+
+ charOwner = new CustomMemoryForTest<char>(Array.Empty<char>());
+ Assert.Equal("", ((ReadOnlyMemory<char>)charOwner.Memory).ToString());
+
+ string[] strArray = { "91", "92", "-93", "94" };
+ OwnedMemory<string> strOwner = new CustomMemoryForTest<string>(strArray);
+ Assert.Equal("System.ReadOnlyMemory<String>[4]", ((ReadOnlyMemory<string>)strOwner.Memory).ToString());
+
+ strOwner = new CustomMemoryForTest<string>(Array.Empty<string>());
+ Assert.Equal("System.ReadOnlyMemory<String>[0]", ((ReadOnlyMemory<string>)strOwner.Memory).ToString());
+ }
+
+ [Fact]
+ public static void ToStringMemoryOverFullStringReturnsOriginal()
+ {
+ string original = TestHelpers.BuildString(10, 42);
+
+ ReadOnlyMemory<char> memory = original.AsMemory();
+
+ string returnedString = memory.ToString();
+ string returnedStringUsingSlice = memory.Slice(0, original.Length).ToString();
+
+ string subString1 = memory.Slice(1).ToString();
+ string subString2 = memory.Slice(0, 2).ToString();
+ string subString3 = memory.Slice(1, 2).ToString();
+
+ Assert.Equal(original, returnedString);
+ Assert.Equal(original, returnedStringUsingSlice);
+
+ Assert.Equal(original.Substring(1), subString1);
+ Assert.Equal(original.Substring(0, 2), subString2);
+ Assert.Equal(original.Substring(1, 2), subString3);
+
+ Assert.Same(original, returnedString);
+ Assert.Same(original, returnedStringUsingSlice);
+
+ Assert.NotSame(original, subString1);
+ Assert.NotSame(original, subString2);
+ Assert.NotSame(original, subString3);
+
+ Assert.NotSame(subString1, subString2);
+ Assert.NotSame(subString1, subString3);
+ Assert.NotSame(subString2, subString3);
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlySpan/AsReadOnlySpan.cs b/src/System.Memory/tests/ReadOnlySpan/AsReadOnlySpan.cs
index 71dfa9b417..827e0c99af 100644
--- a/src/System.Memory/tests/ReadOnlySpan/AsReadOnlySpan.cs
+++ b/src/System.Memory/tests/ReadOnlySpan/AsReadOnlySpan.cs
@@ -40,7 +40,9 @@ namespace System.SpanTests
public static void NullArrayAsReadOnlySpan()
{
int[] a = null;
- Assert.Throws<ArgumentNullException>(() => a.AsReadOnlySpan().DontBox());
+ ReadOnlySpan<int> span = a.AsReadOnlySpan();
+ span.Validate();
+ Assert.True(span == default);
}
[Fact]
@@ -100,7 +102,7 @@ namespace System.SpanTests
public static void StringAsReadOnlySpanNullary()
{
string s = "Hello";
- ReadOnlySpan<char> span = s.AsReadOnlySpan();
+ ReadOnlySpan<char> span = s.AsSpan();
char[] expected = s.ToCharArray();
span.Validate(expected);
}
@@ -109,7 +111,7 @@ namespace System.SpanTests
public static void StringAsReadOnlySpanEmptyString()
{
string s = "";
- ReadOnlySpan<char> span = s.AsReadOnlySpan();
+ ReadOnlySpan<char> span = s.AsSpan();
span.ValidateNonNullEmpty();
}
@@ -117,9 +119,31 @@ namespace System.SpanTests
public static void StringAsReadOnlySpanNullChecked()
{
string s = null;
- Assert.Throws<ArgumentNullException>(() => s.AsReadOnlySpan().DontBox());
- Assert.Throws<ArgumentNullException>(() => s.AsReadOnlySpan(0).DontBox());
- Assert.Throws<ArgumentNullException>(() => s.AsReadOnlySpan(0, 0).DontBox());
+ ReadOnlySpan<char> span = s.AsSpan();
+ span.Validate();
+ Assert.True(span == default);
+
+ span = s.AsSpan(0);
+ span.Validate();
+ Assert.True(span == default);
+
+ span = s.AsSpan(0, 0);
+ span.Validate();
+ Assert.True(span == default);
+ }
+
+ [Fact]
+ public static void StringAsReadOnlySpanNullNonZeroStartAndLength()
+ {
+ string str = null;
+
+ Assert.Throws<ArgumentOutOfRangeException>(() => str.AsSpan(1).DontBox());
+ Assert.Throws<ArgumentOutOfRangeException>(() => str.AsSpan(-1).DontBox());
+
+ Assert.Throws<ArgumentOutOfRangeException>(() => str.AsSpan(0, 1).DontBox());
+ Assert.Throws<ArgumentOutOfRangeException>(() => str.AsSpan(1, 0).DontBox());
+ Assert.Throws<ArgumentOutOfRangeException>(() => str.AsSpan(1, 1).DontBox());
+ Assert.Throws<ArgumentOutOfRangeException>(() => str.AsSpan(-1, -1).DontBox());
}
[Fact]
@@ -148,16 +172,16 @@ namespace System.SpanTests
{
start = 0;
length = text.Length;
- span = text.AsReadOnlySpan();
+ span = text.AsSpan();
}
else if (length == -1)
{
length = text.Length - start;
- span = text.AsReadOnlySpan(start);
+ span = text.AsSpan(start);
}
else
{
- span = text.AsReadOnlySpan(start, length);
+ span = text.AsSpan(start, length);
}
Assert.Equal(length, span.Length);
@@ -174,14 +198,14 @@ namespace System.SpanTests
[MemberData(nameof(TestHelpers.StringSlice2ArgTestOutOfRangeData), MemberType = typeof(TestHelpers))]
public static unsafe void AsReadOnlySpan_2Arg_OutOfRange(string text, int start)
{
- AssertExtensions.Throws<ArgumentOutOfRangeException>("start", () => text.AsReadOnlySpan(start).DontBox());
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("start", () => text.AsSpan(start).DontBox());
}
[Theory]
[MemberData(nameof(TestHelpers.StringSlice3ArgTestOutOfRangeData), MemberType = typeof(TestHelpers))]
public static unsafe void AsReadOnlySpan_3Arg_OutOfRange(string text, int start, int length)
{
- AssertExtensions.Throws<ArgumentOutOfRangeException>("start", () => text.AsReadOnlySpan(start, length).DontBox());
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("start", () => text.AsSpan(start, length).DontBox());
}
}
}
diff --git a/src/System.Memory/tests/ReadOnlySpan/CompareTo.cs b/src/System.Memory/tests/ReadOnlySpan/CompareTo.cs
new file mode 100644
index 0000000000..6c3d38b151
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlySpan/CompareTo.cs
@@ -0,0 +1,281 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Globalization;
+using System.Threading;
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class ReadOnlySpanTests
+ {
+ [Fact]
+ public static void ZeroLengthCompareTo_StringComparison()
+ {
+ char[] a = { '4', '5', '6' };
+
+ var span = new ReadOnlySpan<char>(a);
+ var slice = new ReadOnlySpan<char>(a, 2, 0);
+ Assert.True(0 < span.CompareTo(slice, StringComparison.Ordinal));
+
+ Assert.True(0 < span.CompareTo(slice, StringComparison.CurrentCulture));
+ Assert.True(0 < span.CompareTo(slice, StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(0 < span.CompareTo(slice, StringComparison.InvariantCulture));
+ Assert.True(0 < span.CompareTo(slice, StringComparison.InvariantCultureIgnoreCase));
+ Assert.True(0 < span.CompareTo(slice, StringComparison.OrdinalIgnoreCase));
+
+ span = new ReadOnlySpan<char>(a, 1, 0);
+ Assert.Equal(0, span.CompareTo(slice, StringComparison.Ordinal));
+
+ Assert.Equal(0, span.CompareTo(slice, StringComparison.CurrentCulture));
+ Assert.Equal(0, span.CompareTo(slice, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(0, span.CompareTo(slice, StringComparison.InvariantCulture));
+ Assert.Equal(0, span.CompareTo(slice, StringComparison.InvariantCultureIgnoreCase));
+ Assert.Equal(0, span.CompareTo(slice, StringComparison.OrdinalIgnoreCase));
+ }
+
+ [Fact]
+ public static void SameSpanCompareTo_StringComparison()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a);
+ Assert.Equal(0, span.CompareTo(span, StringComparison.Ordinal));
+
+ Assert.Equal(0, span.CompareTo(span, StringComparison.CurrentCulture));
+ Assert.Equal(0, span.CompareTo(span, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(0, span.CompareTo(span, StringComparison.InvariantCulture));
+ Assert.Equal(0, span.CompareTo(span, StringComparison.InvariantCultureIgnoreCase));
+ Assert.Equal(0, span.CompareTo(span, StringComparison.OrdinalIgnoreCase));
+ }
+
+ [Fact]
+ public static void LengthMismatchCompareTo_StringComparison()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a, 0, 2);
+ var slice = new ReadOnlySpan<char>(a, 0, 3);
+ Assert.True(0 > span.CompareTo(slice, StringComparison.Ordinal));
+
+ Assert.True(0 > span.CompareTo(slice, StringComparison.CurrentCulture));
+ Assert.True(0 > span.CompareTo(slice, StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(0 > span.CompareTo(slice, StringComparison.InvariantCulture));
+ Assert.True(0 > span.CompareTo(slice, StringComparison.InvariantCultureIgnoreCase));
+ Assert.True(0 > span.CompareTo(slice, StringComparison.OrdinalIgnoreCase));
+ }
+
+ [Fact]
+ public static void CompareToOverlappingMatch_StringComparison()
+ {
+ char[] a = { '4', '5', '6', '5', '6', '5' };
+ var span = new ReadOnlySpan<char>(a, 1, 3);
+ var slice = new ReadOnlySpan<char>(a, 3, 3);
+ Assert.Equal(0, span.CompareTo(slice, StringComparison.Ordinal));
+
+ Assert.Equal(0, span.CompareTo(slice, StringComparison.CurrentCulture));
+ Assert.Equal(0, span.CompareTo(slice, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(0, span.CompareTo(slice, StringComparison.InvariantCulture));
+ Assert.Equal(0, span.CompareTo(slice, StringComparison.InvariantCultureIgnoreCase));
+ Assert.Equal(0, span.CompareTo(slice, StringComparison.OrdinalIgnoreCase));
+ }
+
+ [Fact]
+ public static void CompareToMatchDifferentSpans_StringComparison()
+ {
+ char[] a = { '4', '5', '6', '7' };
+ char[] b = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a, 0, 3);
+ var slice = new ReadOnlySpan<char>(b, 0, 3);
+ Assert.Equal(0, span.CompareTo(slice, StringComparison.Ordinal));
+
+ Assert.Equal(0, span.CompareTo(slice, StringComparison.CurrentCulture));
+ Assert.Equal(0, span.CompareTo(slice, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(0, span.CompareTo(slice, StringComparison.InvariantCulture));
+ Assert.Equal(0, span.CompareTo(slice, StringComparison.InvariantCultureIgnoreCase));
+ Assert.Equal(0, span.CompareTo(slice, StringComparison.OrdinalIgnoreCase));
+ }
+
+ [Fact]
+ public static void CompareToNoMatch_StringComparison()
+ {
+ for (int length = 1; length < 150; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ var first = new char[length];
+ var second = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = (char)(i + 1);
+ }
+
+ second[mismatchIndex] = (char)(second[mismatchIndex] + 1);
+
+ var firstSpan = new ReadOnlySpan<char>(first);
+ var secondSpan = new ReadOnlySpan<char>(second);
+ Assert.True(0 > firstSpan.CompareTo(secondSpan, StringComparison.Ordinal));
+
+ // Due to differences in the implementation, the exact result of CompareTo will not necessarily match with string.Compare.
+ // However, the sign will match, which is what defines correctness.
+ Assert.Equal(
+ Math.Sign(string.Compare(firstSpan.ToString(), secondSpan.ToString(), StringComparison.OrdinalIgnoreCase)),
+ Math.Sign(firstSpan.CompareTo(secondSpan, StringComparison.OrdinalIgnoreCase)));
+
+ Assert.Equal(
+ string.Compare(firstSpan.ToString(), secondSpan.ToString(), StringComparison.CurrentCulture),
+ firstSpan.CompareTo(secondSpan, StringComparison.CurrentCulture));
+ Assert.Equal(
+ string.Compare(firstSpan.ToString(), secondSpan.ToString(), StringComparison.CurrentCultureIgnoreCase),
+ firstSpan.CompareTo(secondSpan, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(
+ string.Compare(firstSpan.ToString(), secondSpan.ToString(), StringComparison.InvariantCulture),
+ firstSpan.CompareTo(secondSpan, StringComparison.InvariantCulture));
+ Assert.Equal(
+ string.Compare(firstSpan.ToString(), secondSpan.ToString(), StringComparison.InvariantCultureIgnoreCase),
+ firstSpan.CompareTo(secondSpan, StringComparison.InvariantCultureIgnoreCase));
+ }
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoCompareToChecksGoOutOfRange_StringComparison()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new char[length + 2];
+ first[0] = (char)99;
+ first[length + 1] = (char)99;
+ var second = new char[length + 2];
+ second[0] = (char)100;
+ second[length + 1] = (char)100;
+ var span1 = new ReadOnlySpan<char>(first, 1, length);
+ var span2 = new ReadOnlySpan<char>(second, 1, length);
+ Assert.Equal(0, span1.CompareTo(span2, StringComparison.Ordinal));
+
+ Assert.Equal(0, span1.CompareTo(span2, StringComparison.CurrentCulture));
+ Assert.Equal(0, span1.CompareTo(span2, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(0, span1.CompareTo(span2, StringComparison.InvariantCulture));
+ Assert.Equal(0, span1.CompareTo(span2, StringComparison.InvariantCultureIgnoreCase));
+ Assert.Equal(0, span1.CompareTo(span2, StringComparison.OrdinalIgnoreCase));
+ }
+ }
+
+ [Fact]
+ public static void CompareToUnknownComparisonType_StringComparison()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a);
+ TestHelpers.AssertThrows<ArgumentException, char>(span, (_span) => _span.CompareTo(_span, StringComparison.CurrentCulture - 1));
+ TestHelpers.AssertThrows<ArgumentException, char>(span, (_span) => _span.CompareTo(_span, StringComparison.OrdinalIgnoreCase + 1));
+ TestHelpers.AssertThrows<ArgumentException, char>(span, (_span) => _span.CompareTo(_span, (StringComparison)6));
+ }
+
+ [Theory]
+ // CurrentCulture
+ [InlineData("Hello", 0, "Hello", 0, 5, StringComparison.CurrentCulture, 0)]
+ [InlineData("Hello", 0, "Goodbye", 0, 5, StringComparison.CurrentCulture, 1)]
+ [InlineData("Goodbye", 0, "Hello", 0, 5, StringComparison.CurrentCulture, -1)]
+ [InlineData("HELLO", 2, "hello", 2, 3, StringComparison.CurrentCulture, 1)]
+ [InlineData("hello", 2, "HELLO", 2, 3, StringComparison.CurrentCulture, -1)]
+ [InlineData("Hello", 2, "Hello", 2, 3, StringComparison.CurrentCulture, 0)]
+ [InlineData("Hello", 2, "Goodbye", 2, 3, StringComparison.CurrentCulture, -1)]
+ [InlineData("A", 0, "B", 0, 1, StringComparison.CurrentCulture, -1)]
+ [InlineData("B", 0, "A", 0, 1, StringComparison.CurrentCulture, 1)]
+ // CurrentCultureIgnoreCase
+ [InlineData("HELLO", 0, "hello", 0, 5, StringComparison.CurrentCultureIgnoreCase, 0)]
+ [InlineData("Hello", 0, "Hello", 0, 5, StringComparison.CurrentCultureIgnoreCase, 0)]
+ [InlineData("Hello", 2, "Hello", 2, 3, StringComparison.CurrentCultureIgnoreCase, 0)]
+ [InlineData("Hello", 2, "Yellow", 2, 3, StringComparison.CurrentCultureIgnoreCase, 0)]
+ [InlineData("Hello", 0, "Goodbye", 0, 5, StringComparison.CurrentCultureIgnoreCase, 1)]
+ [InlineData("Goodbye", 0, "Hello", 0, 5, StringComparison.CurrentCultureIgnoreCase, -1)]
+ [InlineData("HELLO", 2, "hello", 2, 3, StringComparison.CurrentCultureIgnoreCase, 0)]
+ [InlineData("Hello", 2, "Goodbye", 2, 3, StringComparison.CurrentCultureIgnoreCase, -1)]
+ // InvariantCulture
+ [InlineData("Hello", 0, "Hello", 0, 5, StringComparison.InvariantCulture, 0)]
+ [InlineData("Hello", 0, "Goodbye", 0, 5, StringComparison.InvariantCulture, 1)]
+ [InlineData("Goodbye", 0, "Hello", 0, 5, StringComparison.InvariantCulture, -1)]
+ [InlineData("HELLO", 2, "hello", 2, 3, StringComparison.InvariantCulture, 1)]
+ [InlineData("hello", 2, "HELLO", 2, 3, StringComparison.InvariantCulture, -1)]
+ // InvariantCultureIgnoreCase
+ [InlineData("HELLO", 0, "hello", 0, 5, StringComparison.InvariantCultureIgnoreCase, 0)]
+ [InlineData("Hello", 0, "Hello", 0, 5, StringComparison.InvariantCultureIgnoreCase, 0)]
+ [InlineData("Hello", 2, "Hello", 2, 3, StringComparison.InvariantCultureIgnoreCase, 0)]
+ [InlineData("Hello", 2, "Yellow", 2, 3, StringComparison.InvariantCultureIgnoreCase, 0)]
+ [InlineData("Hello", 0, "Goodbye", 0, 5, StringComparison.InvariantCultureIgnoreCase, 1)]
+ [InlineData("Goodbye", 0, "Hello", 0, 5, StringComparison.InvariantCultureIgnoreCase, -1)]
+ [InlineData("HELLO", 2, "hello", 2, 3, StringComparison.InvariantCultureIgnoreCase, 0)]
+ [InlineData("Hello", 2, "Goodbye", 2, 3, StringComparison.InvariantCultureIgnoreCase, -1)]
+ // Ordinal
+ [InlineData("Hello", 0, "Hello", 0, 5, StringComparison.Ordinal, 0)]
+ [InlineData("Hello", 0, "Goodbye", 0, 5, StringComparison.Ordinal, 1)]
+ [InlineData("Goodbye", 0, "Hello", 0, 5, StringComparison.Ordinal, -1)]
+ [InlineData("Hello", 2, "Hello", 2, 3, StringComparison.Ordinal, 0)]
+ [InlineData("HELLO", 2, "hello", 2, 3, StringComparison.Ordinal, -1)]
+ [InlineData("Hello", 2, "Goodbye", 2, 3, StringComparison.Ordinal, -1)]
+ [InlineData("Hello", 0, "Hello", 0, 0, StringComparison.Ordinal, 0)]
+ [InlineData("Hello", 0, "Hello", 0, 5, StringComparison.Ordinal, 0)]
+ [InlineData("Hello", 0, "Hello", 0, 3, StringComparison.Ordinal, 0)]
+ [InlineData("Hello", 2, "Hello", 2, 3, StringComparison.Ordinal, 0)]
+ [InlineData("Hello", 0, "He" + SoftHyphen + "llo", 0, 5, StringComparison.Ordinal, -1)]
+ [InlineData("Hello", 0, "-=<Hello>=-", 3, 5, StringComparison.Ordinal, 0)]
+ [InlineData("\uD83D\uDD53Hello\uD83D\uDD50", 1, "\uD83D\uDD53Hello\uD83D\uDD54", 1, 7, StringComparison.Ordinal, 0)] // Surrogate split
+ [InlineData("Hello", 0, "Hello123", 0, int.MaxValue, StringComparison.Ordinal, -1)] // Recalculated length, second string longer
+ [InlineData("Hello123", 0, "Hello", 0, int.MaxValue, StringComparison.Ordinal, 1)] // Recalculated length, first string longer
+ [InlineData("---aaaaaaaaaaa", 3, "+++aaaaaaaaaaa", 3, 100, StringComparison.Ordinal, 0)] // Equal long alignment 2, equal compare
+ [InlineData("aaaaaaaaaaaaaa", 3, "aaaxaaaaaaaaaa", 3, 100, StringComparison.Ordinal, -1)] // Equal long alignment 2, different compare at n=1
+ [InlineData("-aaaaaaaaaaaaa", 1, "+aaaaaaaaaaaaa", 1, 100, StringComparison.Ordinal, 0)] // Equal long alignment 6, equal compare
+ [InlineData("aaaaaaaaaaaaaa", 1, "axaaaaaaaaaaaa", 1, 100, StringComparison.Ordinal, -1)] // Equal long alignment 6, different compare at n=1
+ [InlineData("aaaaaaaaaaaaaa", 0, "aaaaaaaaaaaaaa", 0, 100, StringComparison.Ordinal, 0)] // Equal long alignment 4, equal compare
+ [InlineData("aaaaaaaaaaaaaa", 0, "xaaaaaaaaaaaaa", 0, 100, StringComparison.Ordinal, -1)] // Equal long alignment 4, different compare at n=1
+ [InlineData("aaaaaaaaaaaaaa", 0, "axaaaaaaaaaaaa", 0, 100, StringComparison.Ordinal, -1)] // Equal long alignment 4, different compare at n=2
+ [InlineData("--aaaaaaaaaaaa", 2, "++aaaaaaaaaaaa", 2, 100, StringComparison.Ordinal, 0)] // Equal long alignment 0, equal compare
+ [InlineData("aaaaaaaaaaaaaa", 2, "aaxaaaaaaaaaaa", 2, 100, StringComparison.Ordinal, -1)] // Equal long alignment 0, different compare at n=1
+ [InlineData("aaaaaaaaaaaaaa", 2, "aaaxaaaaaaaaaa", 2, 100, StringComparison.Ordinal, -1)] // Equal long alignment 0, different compare at n=2
+ [InlineData("aaaaaaaaaaaaaa", 2, "aaaaxaaaaaaaaa", 2, 100, StringComparison.Ordinal, -1)] // Equal long alignment 0, different compare at n=3
+ [InlineData("aaaaaaaaaaaaaa", 2, "aaaaaxaaaaaaaa", 2, 100, StringComparison.Ordinal, -1)] // Equal long alignment 0, different compare at n=4
+ [InlineData("aaaaaaaaaaaaaa", 2, "aaaaaaxaaaaaaa", 2, 100, StringComparison.Ordinal, -1)] // Equal long alignment 0, different compare at n=5
+ [InlineData("aaaaaaaaaaaaaa", 0, "+aaaaaaaaaaaaa", 1, 13, StringComparison.Ordinal, 0)] // Different int alignment, equal compare
+ [InlineData("aaaaaaaaaaaaaa", 0, "aaaaaaaaaaaaax", 1, 100, StringComparison.Ordinal, -1)] // Different int alignment
+ [InlineData("aaaaaaaaaaaaaa", 1, "aaaxaaaaaaaaaa", 3, 100, StringComparison.Ordinal, -1)] // Different long alignment, abs of 4, one of them is 2, different at n=1
+ [InlineData("-aaaaaaaaaaaaa", 1, "++++aaaaaaaaaa", 4, 10, StringComparison.Ordinal, 0)] // Different long alignment, equal compare
+ [InlineData("aaaaaaaaaaaaaa", 1, "aaaaaaaaaaaaax", 4, 100, StringComparison.Ordinal, -1)] // Different long alignment
+ [InlineData("\0", 0, "", 0, 1, StringComparison.Ordinal, 1)] // Same memory layout, except for m_stringLength (m_firstChars are both 0)
+ [InlineData("\0\0", 0, "", 0, 2, StringComparison.Ordinal, 1)] // Same as above, except m_stringLength for one is 2
+ [InlineData("", 0, "\0b", 0, 2, StringComparison.Ordinal, -1)] // strA's second char != strB's second char codepath
+ [InlineData("", 0, "b", 0, 1, StringComparison.Ordinal, -1)] // Should hit strA.m_firstChar != strB.m_firstChar codepath
+ [InlineData("abcxxxxxxxxxxxxxxxxxxxxxx", 0, "abdxxxxxxxxxxxxxxx", 0, int.MaxValue, StringComparison.Ordinal, -1)] // 64-bit: first long compare is different
+ [InlineData("abcdefgxxxxxxxxxxxxxxxxxx", 0, "abcdefhxxxxxxxxxxx", 0, int.MaxValue, StringComparison.Ordinal, -1)] // 64-bit: second long compare is different
+ [InlineData("abcdefghijkxxxxxxxxxxxxxx", 0, "abcdefghijlxxxxxxx", 0, int.MaxValue, StringComparison.Ordinal, -1)] // 64-bit: third long compare is different
+ [InlineData("abcdexxxxxxxxxxxxxxxxxxxx", 0, "abcdfxxxxxxxxxxxxx", 0, int.MaxValue, StringComparison.Ordinal, -1)] // 32-bit: second int compare is different
+ [InlineData("abcdefghixxxxxxxxxxxxxxxx", 0, "abcdefghjxxxxxxxxx", 0, int.MaxValue, StringComparison.Ordinal, -1)] // 32-bit: fourth int compare is different
+ // OrdinalIgnoreCase
+ [InlineData("HELLO", 0, "hello", 0, 5, StringComparison.OrdinalIgnoreCase, 0)]
+ [InlineData("Hello", 0, "Hello", 0, 5, StringComparison.OrdinalIgnoreCase, 0)]
+ [InlineData("Hello", 2, "Hello", 2, 3, StringComparison.OrdinalIgnoreCase, 0)]
+ [InlineData("Hello", 2, "Yellow", 2, 3, StringComparison.OrdinalIgnoreCase, 0)]
+ [InlineData("Hello", 0, "Goodbye", 0, 5, StringComparison.OrdinalIgnoreCase, 1)]
+ [InlineData("Goodbye", 0, "Hello", 0, 5, StringComparison.OrdinalIgnoreCase, -1)]
+ [InlineData("HELLO", 2, "hello", 2, 3, StringComparison.OrdinalIgnoreCase, 0)]
+ [InlineData("Hello", 2, "Goodbye", 2, 3, StringComparison.OrdinalIgnoreCase, -1)]
+ [InlineData("A", 0, "x", 0, 1, StringComparison.OrdinalIgnoreCase, -1)]
+ [InlineData("a", 0, "X", 0, 1, StringComparison.OrdinalIgnoreCase, -1)]
+ [InlineData("[", 0, "A", 0, 1, StringComparison.OrdinalIgnoreCase, 1)]
+ [InlineData("[", 0, "a", 0, 1, StringComparison.OrdinalIgnoreCase, 1)]
+ [InlineData("\\", 0, "A", 0, 1, StringComparison.OrdinalIgnoreCase, 1)]
+ [InlineData("\\", 0, "a", 0, 1, StringComparison.OrdinalIgnoreCase, 1)]
+ [InlineData("]", 0, "A", 0, 1, StringComparison.OrdinalIgnoreCase, 1)]
+ [InlineData("]", 0, "a", 0, 1, StringComparison.OrdinalIgnoreCase, 1)]
+ [InlineData("^", 0, "A", 0, 1, StringComparison.OrdinalIgnoreCase, 1)]
+ [InlineData("^", 0, "a", 0, 1, StringComparison.OrdinalIgnoreCase, 1)]
+ [InlineData("_", 0, "A", 0, 1, StringComparison.OrdinalIgnoreCase, 1)]
+ [InlineData("_", 0, "a", 0, 1, StringComparison.OrdinalIgnoreCase, 1)]
+ [InlineData("`", 0, "A", 0, 1, StringComparison.OrdinalIgnoreCase, 1)]
+ [InlineData("`", 0, "a", 0, 1, StringComparison.OrdinalIgnoreCase, 1)]
+ public static void Compare(string strA, int indexA, string strB, int indexB, int length, StringComparison comparisonType, int expected)
+ {
+ ReadOnlySpan<char> span = length <= (strA.Length - indexA) ? strA.AsSpan(indexA, length) : strA.AsSpan(indexA);
+ ReadOnlySpan<char> value = length <= (strB.Length - indexB) ? strB.AsSpan(indexB, length) : strB.AsSpan(indexB);
+ Assert.Equal(expected, Math.Sign(span.CompareTo(value, comparisonType)));
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlySpan/Contains.cs b/src/System.Memory/tests/ReadOnlySpan/Contains.cs
new file mode 100644
index 0000000000..a38f904966
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlySpan/Contains.cs
@@ -0,0 +1,181 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class ReadOnlySpanTests
+ {
+ [Fact]
+ public static void ZeroLengthContains_StringComparison()
+ {
+ var a = new char[3];
+
+ var span = new ReadOnlySpan<char>(a);
+ var slice = new ReadOnlySpan<char>(a, 2, 0);
+ Assert.True(span.Contains(slice, StringComparison.Ordinal));
+
+ Assert.True(span.Contains(slice, StringComparison.CurrentCulture));
+ Assert.True(span.Contains(slice, StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(span.Contains(slice, StringComparison.InvariantCulture));
+ Assert.True(span.Contains(slice, StringComparison.InvariantCultureIgnoreCase));
+ Assert.True(span.Contains(slice, StringComparison.OrdinalIgnoreCase));
+
+ span = ReadOnlySpan<char>.Empty;
+ Assert.True(span.Contains(slice, StringComparison.Ordinal));
+
+ Assert.True(span.Contains(slice, StringComparison.CurrentCulture));
+ Assert.True(span.Contains(slice, StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(span.Contains(slice, StringComparison.InvariantCulture));
+ Assert.True(span.Contains(slice, StringComparison.InvariantCultureIgnoreCase));
+ Assert.True(span.Contains(slice, StringComparison.OrdinalIgnoreCase));
+ }
+
+ [Fact]
+ public static void SameSpanContains_StringComparison()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a);
+ Assert.True(span.Contains(span, StringComparison.Ordinal));
+
+ Assert.True(span.Contains(span, StringComparison.CurrentCulture));
+ Assert.True(span.Contains(span, StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(span.Contains(span, StringComparison.InvariantCulture));
+ Assert.True(span.Contains(span, StringComparison.InvariantCultureIgnoreCase));
+ Assert.True(span.Contains(span, StringComparison.OrdinalIgnoreCase));
+ }
+
+ [Fact]
+ public static void LengthMismatchContains_StringComparison()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a, 0, 2);
+ var slice = new ReadOnlySpan<char>(a, 0, 3);
+ Assert.False(span.Contains(slice, StringComparison.Ordinal));
+
+ Assert.False(span.Contains(slice, StringComparison.CurrentCulture));
+ Assert.False(span.Contains(slice, StringComparison.CurrentCultureIgnoreCase));
+ Assert.False(span.Contains(slice, StringComparison.InvariantCulture));
+ Assert.False(span.Contains(slice, StringComparison.InvariantCultureIgnoreCase));
+ Assert.False(span.Contains(slice, StringComparison.OrdinalIgnoreCase));
+ }
+
+ [Fact]
+ public static void ContainsMatch_StringComparison()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a, 0, 3);
+ var slice = new ReadOnlySpan<char>(a, 0, 2);
+ Assert.True(span.Contains(slice, StringComparison.Ordinal));
+
+ Assert.True(span.Contains(slice, StringComparison.CurrentCulture));
+ Assert.True(span.Contains(slice, StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(span.Contains(slice, StringComparison.InvariantCulture));
+ Assert.True(span.Contains(slice, StringComparison.InvariantCultureIgnoreCase));
+ Assert.True(span.Contains(slice, StringComparison.OrdinalIgnoreCase));
+ }
+
+ [Fact]
+ public static void ContainsMatchDifferentSpans_StringComparison()
+ {
+ char[] a = { '4', '5', '6', '7' };
+ char[] b = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a, 0, 3);
+ var slice = new ReadOnlySpan<char>(b, 0, 3);
+ Assert.True(span.Contains(slice, StringComparison.Ordinal));
+
+ Assert.True(span.Contains(slice, StringComparison.CurrentCulture));
+ Assert.True(span.Contains(slice, StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(span.Contains(slice, StringComparison.InvariantCulture));
+ Assert.True(span.Contains(slice, StringComparison.InvariantCultureIgnoreCase));
+ Assert.True(span.Contains(slice, StringComparison.OrdinalIgnoreCase));
+ }
+
+ [Fact]
+ public static void ContainsNoMatch_StringComparison()
+ {
+ for (int length = 1; length < 150; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ var first = new char[length];
+ var second = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = (char)(i + 1);
+ }
+
+ second[mismatchIndex] = (char)(second[mismatchIndex] + 1);
+
+ var firstSpan = new ReadOnlySpan<char>(first);
+ var secondSpan = new ReadOnlySpan<char>(second);
+ Assert.False(firstSpan.Contains(secondSpan, StringComparison.Ordinal));
+
+ Assert.False(firstSpan.Contains(secondSpan, StringComparison.OrdinalIgnoreCase));
+
+ // Different behavior depending on OS
+ Assert.Equal(
+ firstSpan.ToString().StartsWith(secondSpan.ToString(), StringComparison.CurrentCulture),
+ firstSpan.Contains(secondSpan, StringComparison.CurrentCulture));
+ Assert.Equal(
+ firstSpan.ToString().StartsWith(secondSpan.ToString(), StringComparison.CurrentCulture),
+ firstSpan.Contains(secondSpan, StringComparison.CurrentCulture));
+ Assert.Equal(
+ firstSpan.ToString().StartsWith(secondSpan.ToString(), StringComparison.InvariantCulture),
+ firstSpan.Contains(secondSpan, StringComparison.InvariantCulture));
+ Assert.Equal(
+ firstSpan.ToString().StartsWith(secondSpan.ToString(), StringComparison.InvariantCultureIgnoreCase),
+ firstSpan.Contains(secondSpan, StringComparison.InvariantCultureIgnoreCase));
+ }
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoContainsChecksGoOutOfRange_StringComparison()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new char[length + 2];
+ first[0] = (char)99;
+ first[length + 1] = (char)99;
+ var second = new char[length + 2];
+ second[0] = (char)100;
+ second[length + 1] = (char)100;
+ var span1 = new ReadOnlySpan<char>(first, 1, length);
+ var span2 = new ReadOnlySpan<char>(second, 1, length);
+ Assert.True(span1.Contains(span2, StringComparison.Ordinal));
+
+ Assert.True(span1.Contains(span2, StringComparison.CurrentCulture));
+ Assert.True(span1.Contains(span2, StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(span1.Contains(span2, StringComparison.InvariantCulture));
+ Assert.True(span1.Contains(span2, StringComparison.InvariantCultureIgnoreCase));
+ Assert.True(span1.Contains(span2, StringComparison.OrdinalIgnoreCase));
+ }
+ }
+
+ [Fact]
+ public static void ContainsUnknownComparisonType_StringComparison()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a);
+ TestHelpers.AssertThrows<ArgumentException, char>(span, (_span) => _span.Contains(_span, StringComparison.CurrentCulture - 1));
+ TestHelpers.AssertThrows<ArgumentException, char>(span, (_span) => _span.Contains(_span, StringComparison.OrdinalIgnoreCase + 1));
+ TestHelpers.AssertThrows<ArgumentException, char>(span, (_span) => _span.Contains(_span, (StringComparison)6));
+ }
+
+ [Theory]
+ [InlineData("Hello", "ello", true)]
+ [InlineData("Hello", "ELL", false)]
+ [InlineData("Hello", "Larger Hello", false)]
+ [InlineData("Hello", "Goodbye", false)]
+ [InlineData("", "", true)]
+ [InlineData("", "hello", false)]
+ [InlineData("Hello", "", true)]
+ public static void Contains(string s, string value, bool expected)
+ {
+ Assert.Equal(expected, s.AsSpan().Contains(value.AsSpan(), StringComparison.Ordinal));
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlySpan/CopyTo.cs b/src/System.Memory/tests/ReadOnlySpan/CopyTo.cs
index c138032c8a..481ce6cc88 100644
--- a/src/System.Memory/tests/ReadOnlySpan/CopyTo.cs
+++ b/src/System.Memory/tests/ReadOnlySpan/CopyTo.cs
@@ -188,5 +188,36 @@ namespace System.SpanTests
}
}
}
+
+ [Fact]
+ public static void CopyToVaryingSizes()
+ {
+ const int MaxLength = 2048;
+
+ var rng = new Random();
+ byte[] inputArray = new byte[MaxLength];
+ ReadOnlySpan<byte> inputSpan = inputArray;
+ Span<byte> outputSpan = new byte[MaxLength];
+ Span<byte> allZerosSpan = new byte[MaxLength];
+
+ // Test all inputs from size 0 .. MaxLength (inclusive) to make sure we don't have
+ // gaps in our Memmove logic.
+ for (int i = 0; i <= MaxLength; i++)
+ {
+ // Arrange
+
+ rng.NextBytes(inputArray);
+ outputSpan.Clear();
+
+ // Act
+
+ inputSpan.Slice(0, i).CopyTo(outputSpan);
+
+ // Assert
+
+ Assert.True(inputSpan.Slice(0, i).SequenceEqual(outputSpan.Slice(0, i))); // src successfully copied to dst
+ Assert.True(outputSpan.Slice(i).SequenceEqual(allZerosSpan.Slice(i))); // no other part of dst was overwritten
+ }
+ }
}
}
diff --git a/src/System.Memory/tests/ReadOnlySpan/CtorArray.cs b/src/System.Memory/tests/ReadOnlySpan/CtorArray.cs
index ea8f3ba831..5a5129ea6c 100644
--- a/src/System.Memory/tests/ReadOnlySpan/CtorArray.cs
+++ b/src/System.Memory/tests/ReadOnlySpan/CtorArray.cs
@@ -72,8 +72,22 @@ namespace System.SpanTests
[Fact]
public static void CtorArrayNullArray()
{
- Assert.Throws<ArgumentNullException>(() => new ReadOnlySpan<int>(null).DontBox());
- Assert.Throws<ArgumentNullException>(() => new ReadOnlySpan<int>(null, 0, 0).DontBox());
+ var span = new ReadOnlySpan<int>(null);
+ span.Validate();
+ Assert.True(span == default);
+
+ span = new ReadOnlySpan<int>(null, 0, 0);
+ span.Validate();
+ Assert.True(span == default);
+ }
+
+ [Fact]
+ public static void CtorArrayNullArrayNonZeroStartAndLength()
+ {
+ Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlySpan<int>(null, 1, 0).DontBox());
+ Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlySpan<int>(null, 0, 1).DontBox());
+ Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlySpan<int>(null, 1, 1).DontBox());
+ Assert.Throws<ArgumentOutOfRangeException>(() => new ReadOnlySpan<int>(null, -1, -1).DontBox());
}
[Fact]
diff --git a/src/System.Memory/tests/ReadOnlySpan/CtorPointerInt.cs b/src/System.Memory/tests/ReadOnlySpan/CtorPointerInt.cs
index ee7b74f1cc..9cd75b18d5 100644
--- a/src/System.Memory/tests/ReadOnlySpan/CtorPointerInt.cs
+++ b/src/System.Memory/tests/ReadOnlySpan/CtorPointerInt.cs
@@ -60,20 +60,8 @@ namespace System.SpanTests
new ReadOnlySpan<int>((void*)null, 0);
new ReadOnlySpan<int?>((void*)null, 0);
AssertExtensions.Throws<ArgumentException>(null, () => new ReadOnlySpan<object>((void*)null, 0).DontBox());
- AssertExtensions.Throws<ArgumentException>(null, () => new ReadOnlySpan<StructWithReferences>((void*)null, 0).DontBox());
+ AssertExtensions.Throws<ArgumentException>(null, () => new ReadOnlySpan<TestHelpers.StructWithReferences>((void*)null, 0).DontBox());
}
}
-
- private struct StructWithReferences
- {
- public int I;
- public InnerStruct Inner;
- }
-
- private struct InnerStruct
- {
- public int J;
- public object O;
- }
}
}
diff --git a/src/System.Memory/tests/ReadOnlySpan/EndsWith.StringComparison.cs b/src/System.Memory/tests/ReadOnlySpan/EndsWith.StringComparison.cs
new file mode 100644
index 0000000000..62d0fcd0d1
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlySpan/EndsWith.StringComparison.cs
@@ -0,0 +1,347 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Globalization;
+using System.Threading;
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class ReadOnlySpanTests
+ {
+ [Fact]
+ public static void ZeroLengthEndsWith_StringComparison()
+ {
+ var a = new char[3];
+
+ var span = new ReadOnlySpan<char>(a);
+ var slice = new ReadOnlySpan<char>(a, 2, 0);
+ Assert.True(span.EndsWith(slice, StringComparison.Ordinal));
+
+ Assert.True(span.EndsWith(slice, StringComparison.CurrentCulture));
+ Assert.True(span.EndsWith(slice, StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(span.EndsWith(slice, StringComparison.InvariantCulture));
+ Assert.True(span.EndsWith(slice, StringComparison.InvariantCultureIgnoreCase));
+ Assert.True(span.EndsWith(slice, StringComparison.OrdinalIgnoreCase));
+
+ span = ReadOnlySpan<char>.Empty;
+ Assert.True(span.EndsWith(slice, StringComparison.Ordinal));
+
+ Assert.True(span.EndsWith(slice, StringComparison.CurrentCulture));
+ Assert.True(span.EndsWith(slice, StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(span.EndsWith(slice, StringComparison.InvariantCulture));
+ Assert.True(span.EndsWith(slice, StringComparison.InvariantCultureIgnoreCase));
+ Assert.True(span.EndsWith(slice, StringComparison.OrdinalIgnoreCase));
+ }
+
+ [Fact]
+ public static void SameSpanEndsWith_StringComparison()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a);
+ Assert.True(span.EndsWith(span, StringComparison.Ordinal));
+
+ Assert.True(span.EndsWith(span, StringComparison.CurrentCulture));
+ Assert.True(span.EndsWith(span, StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(span.EndsWith(span, StringComparison.InvariantCulture));
+ Assert.True(span.EndsWith(span, StringComparison.InvariantCultureIgnoreCase));
+ Assert.True(span.EndsWith(span, StringComparison.OrdinalIgnoreCase));
+ }
+
+ [Fact]
+ public static void LengthMismatchEndsWith_StringComparison()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a, 0, 2);
+ var slice = new ReadOnlySpan<char>(a, 0, 3);
+ Assert.False(span.EndsWith(slice, StringComparison.Ordinal));
+
+ Assert.False(span.EndsWith(slice, StringComparison.CurrentCulture));
+ Assert.False(span.EndsWith(slice, StringComparison.CurrentCultureIgnoreCase));
+ Assert.False(span.EndsWith(slice, StringComparison.InvariantCulture));
+ Assert.False(span.EndsWith(slice, StringComparison.InvariantCultureIgnoreCase));
+ Assert.False(span.EndsWith(slice, StringComparison.OrdinalIgnoreCase));
+ }
+
+ [Fact]
+ public static void EndsWithMatch_StringComparison()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a, 0, 3);
+ var slice = new ReadOnlySpan<char>(a, 1, 2);
+ Assert.True(span.EndsWith(slice, StringComparison.Ordinal));
+
+ Assert.True(span.EndsWith(slice, StringComparison.CurrentCulture));
+ Assert.True(span.EndsWith(slice, StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(span.EndsWith(slice, StringComparison.InvariantCulture));
+ Assert.True(span.EndsWith(slice, StringComparison.InvariantCultureIgnoreCase));
+ Assert.True(span.EndsWith(slice, StringComparison.OrdinalIgnoreCase));
+ }
+
+ [Fact]
+ public static void EndsWithMatchDifferentSpans_StringComparison()
+ {
+ char[] a = { '7', '4', '5', '6' };
+ char[] b = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a, 1, 3);
+ var slice = new ReadOnlySpan<char>(b, 0, 3);
+ Assert.True(span.EndsWith(slice, StringComparison.Ordinal));
+
+ Assert.True(span.EndsWith(slice, StringComparison.CurrentCulture));
+ Assert.True(span.EndsWith(slice, StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(span.EndsWith(slice, StringComparison.InvariantCulture));
+ Assert.True(span.EndsWith(slice, StringComparison.InvariantCultureIgnoreCase));
+ Assert.True(span.EndsWith(slice, StringComparison.OrdinalIgnoreCase));
+ }
+
+ [Fact]
+ public static void EndsWithNoMatch_StringComparison()
+ {
+ for (int length = 1; length < 150; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ var first = new char[length];
+ var second = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = (char)(i + 1);
+ }
+
+ second[mismatchIndex] = (char)(second[mismatchIndex] + 1);
+
+ var firstSpan = new ReadOnlySpan<char>(first);
+ var secondSpan = new ReadOnlySpan<char>(second);
+ Assert.False(firstSpan.EndsWith(secondSpan, StringComparison.Ordinal));
+
+ Assert.False(firstSpan.EndsWith(secondSpan, StringComparison.OrdinalIgnoreCase));
+
+ // Different behavior depending on OS
+ Assert.Equal(
+ firstSpan.ToString().EndsWith(secondSpan.ToString(), StringComparison.CurrentCulture),
+ firstSpan.EndsWith(secondSpan, StringComparison.CurrentCulture));
+ Assert.Equal(
+ firstSpan.ToString().EndsWith(secondSpan.ToString(), StringComparison.CurrentCultureIgnoreCase),
+ firstSpan.EndsWith(secondSpan, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(
+ firstSpan.ToString().EndsWith(secondSpan.ToString(), StringComparison.InvariantCulture),
+ firstSpan.EndsWith(secondSpan, StringComparison.InvariantCulture));
+ Assert.Equal(
+ firstSpan.ToString().EndsWith(secondSpan.ToString(), StringComparison.InvariantCultureIgnoreCase),
+ firstSpan.EndsWith(secondSpan, StringComparison.InvariantCultureIgnoreCase));
+ }
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoEndsWithChecksGoOutOfRange_StringComparison()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new char[length + 2];
+ first[0] = (char)99;
+ first[length + 1] = (char)99;
+ var second = new char[length + 2];
+ second[0] = (char)100;
+ second[length + 1] = (char)100;
+ var span1 = new ReadOnlySpan<char>(first, 1, length);
+ var span2 = new ReadOnlySpan<char>(second, 1, length);
+ Assert.True(span1.EndsWith(span2, StringComparison.Ordinal));
+
+ Assert.True(span1.EndsWith(span2, StringComparison.CurrentCulture));
+ Assert.True(span1.EndsWith(span2, StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(span1.EndsWith(span2, StringComparison.InvariantCulture));
+ Assert.True(span1.EndsWith(span2, StringComparison.InvariantCultureIgnoreCase));
+ Assert.True(span1.EndsWith(span2, StringComparison.OrdinalIgnoreCase));
+ }
+ }
+
+ [Fact]
+ public static void EndsWithUnknownComparisonType_StringComparison()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a);
+ TestHelpers.AssertThrows<ArgumentException, char>(span, (_span) => _span.EndsWith(_span, StringComparison.CurrentCulture - 1));
+ TestHelpers.AssertThrows<ArgumentException, char>(span, (_span) => _span.EndsWith(_span, StringComparison.OrdinalIgnoreCase + 1));
+ TestHelpers.AssertThrows<ArgumentException, char>(span, (_span) => _span.EndsWith(_span, (StringComparison)6));
+ }
+
+ [Fact]
+ public static void EndsWithMatchNonOrdinal_StringComparison()
+ {
+ ReadOnlySpan<char> span = new char[] { 'd', 'a', 'b', 'c' };
+ ReadOnlySpan<char> value = new char[] { 'a', 'B', 'c' };
+ Assert.False(span.EndsWith(value, StringComparison.Ordinal));
+ Assert.True(span.EndsWith(value, StringComparison.OrdinalIgnoreCase));
+
+ CultureInfo backupCulture = CultureInfo.CurrentCulture;
+
+ Thread.CurrentThread.CurrentCulture = new CultureInfo("el-GR");
+
+ span = new char[] { '\u03b4', '\u03b1', '\u03b2', '\u03b3' }; // δαβγ
+ value = new char[] { '\u03b1', '\u03b2', '\u03b3' }; // αβγ
+
+ Assert.True(span.EndsWith(value, StringComparison.CurrentCulture));
+ Assert.True(span.EndsWith(value, StringComparison.CurrentCultureIgnoreCase));
+
+ value = new char[] { '\u03b1', '\u0392', '\u03b3' }; // αΒγ
+ Assert.False(span.EndsWith(value, StringComparison.CurrentCulture));
+ Assert.True(span.EndsWith(value, StringComparison.CurrentCultureIgnoreCase));
+
+ Thread.CurrentThread.CurrentCulture = backupCulture;
+
+ span = new char[] { '\u03b4', '\u0069', '\u00df', '\u0049' }; // δißI
+ value = new char[] { '\u0069', '\u0073', '\u0073', '\u0049' }; // issI
+
+ Assert.False(span.EndsWith(value, StringComparison.Ordinal));
+ // Different behavior depending on OS - True on Windows, False on Unix
+ Assert.Equal(
+ span.ToString().EndsWith(value.ToString(), StringComparison.InvariantCulture),
+ span.EndsWith(value, StringComparison.InvariantCulture));
+ Assert.Equal(
+ span.ToString().EndsWith(value.ToString(), StringComparison.InvariantCultureIgnoreCase),
+ span.EndsWith(value, StringComparison.InvariantCultureIgnoreCase));
+
+ value = new char[] { '\u0049', '\u0073', '\u0073', '\u0049' }; // IssI
+ Assert.False(span.EndsWith(value, StringComparison.OrdinalIgnoreCase));
+ Assert.False(span.EndsWith(value, StringComparison.InvariantCulture));
+ // Different behavior depending on OS - True on Windows, False on Unix
+ Assert.Equal(
+ span.ToString().EndsWith(value.ToString(), StringComparison.InvariantCultureIgnoreCase),
+ span.EndsWith(value, StringComparison.InvariantCultureIgnoreCase));
+ }
+
+ [Fact]
+ public static void EndsWithNoMatchNonOrdinal_StringComparison()
+ {
+ ReadOnlySpan<char> span = new char[] { 'd', 'a', 'b', 'c' };
+ ReadOnlySpan<char> value = new char[] { 'a', 'D', 'c' };
+ Assert.False(span.EndsWith(value, StringComparison.Ordinal));
+ Assert.False(span.EndsWith(value, StringComparison.OrdinalIgnoreCase));
+
+ CultureInfo backupCulture = CultureInfo.CurrentCulture;
+
+ Thread.CurrentThread.CurrentCulture = new CultureInfo("el-GR");
+
+ span = new char[] { '\u03b4', '\u03b1', '\u03b2', '\u03b3' }; // δαβγ
+ value = new char[] { '\u03b1', '\u03b4', '\u03b3' }; // αδγ
+
+ Assert.False(span.EndsWith(value, StringComparison.CurrentCulture));
+ Assert.False(span.EndsWith(value, StringComparison.CurrentCultureIgnoreCase));
+
+ value = new char[] { '\u03b1', '\u0394', '\u03b3' }; // αΔγ
+ Assert.False(span.EndsWith(value, StringComparison.CurrentCulture));
+ Assert.False(span.EndsWith(value, StringComparison.CurrentCultureIgnoreCase));
+
+ Thread.CurrentThread.CurrentCulture = backupCulture;
+
+ span = new char[] { '\u03b4', '\u0069', '\u00df', '\u0049' }; // δißI
+ value = new char[] { '\u0069', '\u03b4', '\u03b4', '\u0049' }; // iδδI
+
+ Assert.False(span.EndsWith(value, StringComparison.Ordinal));
+ Assert.False(span.EndsWith(value, StringComparison.InvariantCulture));
+ Assert.False(span.EndsWith(value, StringComparison.InvariantCultureIgnoreCase));
+
+ value = new char[] { '\u0049', '\u03b4', '\u03b4', '\u0049' }; // IδδI
+ Assert.False(span.EndsWith(value, StringComparison.OrdinalIgnoreCase));
+ Assert.False(span.EndsWith(value, StringComparison.InvariantCulture));
+ Assert.False(span.EndsWith(value, StringComparison.InvariantCultureIgnoreCase));
+ }
+
+ [Theory]
+ // CurrentCulture
+ [InlineData("", "Foo", StringComparison.CurrentCulture, false)]
+ [InlineData("Hello", "llo", StringComparison.CurrentCulture, true)]
+ [InlineData("Hello", "Hello", StringComparison.CurrentCulture, true)]
+ [InlineData("Hello", "", StringComparison.CurrentCulture, true)]
+ [InlineData("Hello", "HELLO", StringComparison.CurrentCulture, false)]
+ [InlineData("Hello", "Abc", StringComparison.CurrentCulture, false)]
+ [InlineData("Hello", "llo" + SoftHyphen, StringComparison.CurrentCulture, true)]
+ [InlineData("", "", StringComparison.CurrentCulture, true)]
+ [InlineData("", "a", StringComparison.CurrentCulture, false)]
+ // CurrentCultureIgnoreCase
+ [InlineData("Hello", "llo", StringComparison.CurrentCultureIgnoreCase, true)]
+ [InlineData("Hello", "Hello", StringComparison.CurrentCultureIgnoreCase, true)]
+ [InlineData("Hello", "", StringComparison.CurrentCultureIgnoreCase, true)]
+ [InlineData("Hello", "LLO", StringComparison.CurrentCultureIgnoreCase, true)]
+ [InlineData("Hello", "Abc", StringComparison.CurrentCultureIgnoreCase, false)]
+ [InlineData("Hello", "llo" + SoftHyphen, StringComparison.CurrentCultureIgnoreCase, true)]
+ [InlineData("", "", StringComparison.CurrentCultureIgnoreCase, true)]
+ [InlineData("", "a", StringComparison.CurrentCultureIgnoreCase, false)]
+ // InvariantCulture
+ [InlineData("", "Foo", StringComparison.InvariantCulture, false)]
+ [InlineData("Hello", "llo", StringComparison.InvariantCulture, true)]
+ [InlineData("Hello", "Hello", StringComparison.InvariantCulture, true)]
+ [InlineData("Hello", "", StringComparison.InvariantCulture, true)]
+ [InlineData("Hello", "HELLO", StringComparison.InvariantCulture, false)]
+ [InlineData("Hello", "Abc", StringComparison.InvariantCulture, false)]
+ [InlineData("Hello", "llo" + SoftHyphen, StringComparison.InvariantCulture, true)]
+ [InlineData("", "", StringComparison.InvariantCulture, true)]
+ [InlineData("", "a", StringComparison.InvariantCulture, false)]
+ // InvariantCultureIgnoreCase
+ [InlineData("Hello", "llo", StringComparison.InvariantCultureIgnoreCase, true)]
+ [InlineData("Hello", "Hello", StringComparison.InvariantCultureIgnoreCase, true)]
+ [InlineData("Hello", "", StringComparison.InvariantCultureIgnoreCase, true)]
+ [InlineData("Hello", "LLO", StringComparison.InvariantCultureIgnoreCase, true)]
+ [InlineData("Hello", "Abc", StringComparison.InvariantCultureIgnoreCase, false)]
+ [InlineData("Hello", "llo" + SoftHyphen, StringComparison.InvariantCultureIgnoreCase, true)]
+ [InlineData("", "", StringComparison.InvariantCultureIgnoreCase, true)]
+ [InlineData("", "a", StringComparison.InvariantCultureIgnoreCase, false)]
+ // Ordinal
+ [InlineData("Hello", "o", StringComparison.Ordinal, true)]
+ [InlineData("Hello", "llo", StringComparison.Ordinal, true)]
+ [InlineData("Hello", "Hello", StringComparison.Ordinal, true)]
+ [InlineData("Hello", "Larger Hello", StringComparison.Ordinal, false)]
+ [InlineData("Hello", "", StringComparison.Ordinal, true)]
+ [InlineData("Hello", "LLO", StringComparison.Ordinal, false)]
+ [InlineData("Hello", "Abc", StringComparison.Ordinal, false)]
+ [InlineData("Hello", "llo" + SoftHyphen, StringComparison.Ordinal, false)]
+ [InlineData("", "", StringComparison.Ordinal, true)]
+ [InlineData("", "a", StringComparison.Ordinal, false)]
+ // OrdinalIgnoreCase
+ [InlineData("Hello", "llo", StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("Hello", "Hello", StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("Hello", "Larger Hello", StringComparison.OrdinalIgnoreCase, false)]
+ [InlineData("Hello", "", StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("Hello", "LLO", StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("Hello", "Abc", StringComparison.OrdinalIgnoreCase, false)]
+ [InlineData("Hello", "llo" + SoftHyphen, StringComparison.OrdinalIgnoreCase, false)]
+ [InlineData("", "", StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("", "a", StringComparison.OrdinalIgnoreCase, false)]
+ public static void EndsWith(string s, string value, StringComparison comparisonType, bool expected)
+ {
+ Assert.Equal(expected, s.AsSpan().EndsWith(value.AsSpan(), comparisonType));
+ }
+
+ [Theory]
+ [InlineData(StringComparison.Ordinal)]
+ [InlineData(StringComparison.OrdinalIgnoreCase)]
+ public static void EndsWith_NullInStrings(StringComparison comparison)
+ {
+ Assert.True("\0test".AsSpan().EndsWith("test".AsSpan(), comparison));
+ Assert.True("te\0st".AsSpan().EndsWith("e\0st".AsSpan(), comparison));
+ Assert.False("te\0st".AsSpan().EndsWith("test".AsSpan(), comparison));
+ Assert.False("test\0".AsSpan().EndsWith("test".AsSpan(), comparison));
+ Assert.False("test".AsSpan().EndsWith("\0st".AsSpan(), comparison));
+ }
+
+ // NOTE: This is by design. Unix ignores the null characters (i.e. null characters have no weights for the string comparison).
+ // For desired behavior, use ordinal comparison instead of linguistic comparison.
+ // This is a known difference between Windows and Unix (https://github.com/dotnet/coreclr/issues/2051).
+ [Theory]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [InlineData(StringComparison.CurrentCulture)]
+ [InlineData(StringComparison.CurrentCultureIgnoreCase)]
+ [InlineData(StringComparison.InvariantCulture)]
+ [InlineData(StringComparison.InvariantCultureIgnoreCase)]
+ public static void EndsWith_NullInStrings_NonOrdinal(StringComparison comparison)
+ {
+ Assert.True("\0test".AsSpan().EndsWith("test".AsSpan(), comparison));
+ Assert.True("te\0st".AsSpan().EndsWith("e\0st".AsSpan(), comparison));
+ Assert.False("te\0st".AsSpan().EndsWith("test".AsSpan(), comparison));
+ Assert.False("test\0".AsSpan().EndsWith("test".AsSpan(), comparison));
+ Assert.False("test".AsSpan().EndsWith("\0st".AsSpan(), comparison));
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlySpan/EndsWith.char.cs b/src/System.Memory/tests/ReadOnlySpan/EndsWith.char.cs
new file mode 100644
index 0000000000..b8c2752a9d
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlySpan/EndsWith.char.cs
@@ -0,0 +1,104 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class ReadOnlySpanTests
+ {
+ [Fact]
+ public static void ZeroLengthEndsWith_Char()
+ {
+ var a = new char[3];
+
+ var span = new ReadOnlySpan<char>(a);
+ var slice = new ReadOnlySpan<char>(a, 2, 0);
+ bool b = span.EndsWith<char>(slice);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void SameSpanEndsWith_Char()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a);
+ bool b = span.EndsWith(span);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void LengthMismatchEndsWith_Char()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a, 0, 2);
+ var slice = new ReadOnlySpan<char>(a, 0, 3);
+ bool b = span.EndsWith(slice);
+ Assert.False(b);
+ }
+
+ [Fact]
+ public static void EndsWithMatch_Char()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a, 0, 3);
+ var slice = new ReadOnlySpan<char>(a, 1, 2);
+ bool b = span.EndsWith(slice);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void EndsWithMatchDifferentSpans_Char()
+ {
+ char[] a = { '4', '5', '6' };
+ char[] b = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a, 0, 3);
+ var slice = new ReadOnlySpan<char>(b, 0, 3);
+ bool c = span.EndsWith(slice);
+ Assert.True(c);
+ }
+
+ [Fact]
+ public static void EndsWithNoMatch_Char()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ var first = new char[length];
+ var second = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = (char)(i + 1);
+ }
+
+ second[mismatchIndex] = (char)(second[mismatchIndex] + 1);
+
+ var firstSpan = new ReadOnlySpan<char>(first);
+ var secondSpan = new ReadOnlySpan<char>(second);
+ bool b = firstSpan.EndsWith(secondSpan);
+ Assert.False(b);
+ }
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoEndsWithChecksGoOutOfRange_Char()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new char[length + 2];
+ first[0] = '9';
+ first[length + 1] = '9';
+ var second = new char[length + 2];
+ second[0] = 'a';
+ second[length + 1] = 'a';
+ var span1 = new ReadOnlySpan<char>(first, 1, length);
+ var span2 = new ReadOnlySpan<char>(second, 1, length);
+ bool b = span1.EndsWith(span2);
+ Assert.True(b);
+ }
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlySpan/EndsWith.long.cs b/src/System.Memory/tests/ReadOnlySpan/EndsWith.long.cs
new file mode 100644
index 0000000000..ea1be8ec65
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlySpan/EndsWith.long.cs
@@ -0,0 +1,104 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class ReadOnlySpanTests
+ {
+ [Fact]
+ public static void ZeroLengthEndsWith_Long()
+ {
+ var a = new long[3];
+
+ var span = new ReadOnlySpan<long>(a);
+ var slice = new ReadOnlySpan<long>(a, 2, 0);
+ bool b = span.EndsWith<long>(slice);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void SameSpanEndsWith_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ var span = new ReadOnlySpan<long>(a);
+ bool b = span.EndsWith(span);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void LengthMismatchEndsWith_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ var span = new ReadOnlySpan<long>(a, 0, 2);
+ var slice = new ReadOnlySpan<long>(a, 0, 3);
+ bool b = span.EndsWith(slice);
+ Assert.False(b);
+ }
+
+ [Fact]
+ public static void EndsWithMatch_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ var span = new ReadOnlySpan<long>(a, 0, 3);
+ var slice = new ReadOnlySpan<long>(a, 1, 2);
+ bool b = span.EndsWith(slice);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void EndsWithMatchDifferentSpans_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ long[] b = { 488238291, 52498989823, 619890289890 };
+ var span = new ReadOnlySpan<long>(a, 0, 3);
+ var slice = new ReadOnlySpan<long>(b, 0, 3);
+ bool c = span.EndsWith(slice);
+ Assert.True(c);
+ }
+
+ [Fact]
+ public static void EndsWithNoMatch_Long()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ var first = new long[length];
+ var second = new long[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = (long)(i + 1);
+ }
+
+ second[mismatchIndex] = (long)(second[mismatchIndex] + 1);
+
+ var firstSpan = new ReadOnlySpan<long>(first);
+ var secondSpan = new ReadOnlySpan<long>(second);
+ bool b = firstSpan.EndsWith(secondSpan);
+ Assert.False(b);
+ }
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoEndsWithChecksGoOutOfRange_Long()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new long[length + 2];
+ first[0] = 99;
+ first[length + 1] = 99;
+ var second = new long[length + 2];
+ second[0] = 100;
+ second[length + 1] = 100;
+ var span1 = new ReadOnlySpan<long>(first, 1, length);
+ var span2 = new ReadOnlySpan<long>(second, 1, length);
+ bool b = span1.EndsWith(span2);
+ Assert.True(b);
+ }
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlySpan/Equals.cs b/src/System.Memory/tests/ReadOnlySpan/Equals.cs
new file mode 100644
index 0000000000..b2462d5a00
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlySpan/Equals.cs
@@ -0,0 +1,262 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Globalization;
+using System.Runtime.InteropServices;
+using System.Threading;
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class ReadOnlySpanTests
+ {
+ [Fact]
+ public static void ZeroLengthEquals_StringComparison()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a);
+ var slice = new ReadOnlySpan<char>(a, 2, 0);
+ Assert.False(span.Equals(slice, StringComparison.Ordinal));
+
+ Assert.False(span.Equals(slice, StringComparison.CurrentCulture));
+ Assert.False(span.Equals(slice, StringComparison.CurrentCultureIgnoreCase));
+ Assert.False(span.Equals(slice, StringComparison.InvariantCulture));
+ Assert.False(span.Equals(slice, StringComparison.InvariantCultureIgnoreCase));
+ Assert.False(span.Equals(slice, StringComparison.OrdinalIgnoreCase));
+
+ span = new ReadOnlySpan<char>(a, 1, 0);
+ Assert.True(span.Equals(slice, StringComparison.Ordinal));
+
+ Assert.True(span.Equals(slice, StringComparison.CurrentCulture));
+ Assert.True(span.Equals(slice, StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(span.Equals(slice, StringComparison.InvariantCulture));
+ Assert.True(span.Equals(slice, StringComparison.InvariantCultureIgnoreCase));
+ Assert.True(span.Equals(slice, StringComparison.OrdinalIgnoreCase));
+ }
+
+ [Fact]
+ public static void SameSpanEquals_StringComparison()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a);
+ Assert.True(span.Equals(span, StringComparison.Ordinal));
+
+ Assert.True(span.Equals(span, StringComparison.CurrentCulture));
+ Assert.True(span.Equals(span, StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(span.Equals(span, StringComparison.InvariantCulture));
+ Assert.True(span.Equals(span, StringComparison.InvariantCultureIgnoreCase));
+ Assert.True(span.Equals(span, StringComparison.OrdinalIgnoreCase));
+ }
+
+ [Fact]
+ public static void LengthMismatchEquals_StringComparison()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a, 0, 2);
+ var slice = new ReadOnlySpan<char>(a, 0, 3);
+ Assert.False(span.Equals(slice, StringComparison.Ordinal));
+
+ Assert.False(span.Equals(slice, StringComparison.CurrentCulture));
+ Assert.False(span.Equals(slice, StringComparison.CurrentCultureIgnoreCase));
+ Assert.False(span.Equals(slice, StringComparison.InvariantCulture));
+ Assert.False(span.Equals(slice, StringComparison.InvariantCultureIgnoreCase));
+ Assert.False(span.Equals(slice, StringComparison.OrdinalIgnoreCase));
+ }
+
+ [Fact]
+ public static void EqualsOverlappingMatch_StringComparison()
+ {
+ char[] a = { '4', '5', '6', '5', '6', '5' };
+ var span = new ReadOnlySpan<char>(a, 1, 3);
+ var slice = new ReadOnlySpan<char>(a, 3, 3);
+ Assert.True(span.Equals(slice, StringComparison.Ordinal));
+
+ Assert.True(span.Equals(slice, StringComparison.CurrentCulture));
+ Assert.True(span.Equals(slice, StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(span.Equals(slice, StringComparison.InvariantCulture));
+ Assert.True(span.Equals(slice, StringComparison.InvariantCultureIgnoreCase));
+ Assert.True(span.Equals(slice, StringComparison.OrdinalIgnoreCase));
+ }
+
+ [Fact]
+ public static void EqualsMatchDifferentSpans_StringComparison()
+ {
+ char[] a = { '4', '5', '6', '7' };
+ char[] b = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a, 0, 3);
+ var slice = new ReadOnlySpan<char>(b, 0, 3);
+ Assert.True(span.Equals(slice, StringComparison.Ordinal));
+
+ Assert.True(span.Equals(slice, StringComparison.CurrentCulture));
+ Assert.True(span.Equals(slice, StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(span.Equals(slice, StringComparison.InvariantCulture));
+ Assert.True(span.Equals(slice, StringComparison.InvariantCultureIgnoreCase));
+ Assert.True(span.Equals(slice, StringComparison.OrdinalIgnoreCase));
+ }
+
+ [Fact]
+ public static void EqualsNoMatch_StringComparison()
+ {
+ for (int length = 1; length < 150; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ var first = new char[length];
+ var second = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = (char)(i + 1);
+ }
+
+ second[mismatchIndex] = (char)(second[mismatchIndex] + 1);
+
+ var firstSpan = new ReadOnlySpan<char>(first);
+ var secondSpan = new ReadOnlySpan<char>(second);
+ Assert.False(firstSpan.Equals(secondSpan, StringComparison.Ordinal));
+
+ Assert.False(firstSpan.Equals(secondSpan, StringComparison.OrdinalIgnoreCase));
+
+ // Different behavior depending on OS
+ Assert.Equal(
+ firstSpan.ToString().Equals(secondSpan.ToString(), StringComparison.CurrentCulture),
+ firstSpan.Equals(secondSpan, StringComparison.CurrentCulture));
+ Assert.Equal(
+ firstSpan.ToString().Equals(secondSpan.ToString(), StringComparison.CurrentCultureIgnoreCase),
+ firstSpan.Equals(secondSpan, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(
+ firstSpan.ToString().Equals(secondSpan.ToString(), StringComparison.InvariantCulture),
+ firstSpan.Equals(secondSpan, StringComparison.InvariantCulture));
+ Assert.Equal(
+ firstSpan.ToString().Equals(secondSpan.ToString(), StringComparison.InvariantCultureIgnoreCase),
+ firstSpan.Equals(secondSpan, StringComparison.InvariantCultureIgnoreCase));
+ }
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoEqualsChecksGoOutOfRange_StringComparison()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new char[length + 2];
+ first[0] = (char)99;
+ first[length + 1] = (char)99;
+ var second = new char[length + 2];
+ second[0] = (char)100;
+ second[length + 1] = (char)100;
+ var span1 = new ReadOnlySpan<char>(first, 1, length);
+ var span2 = new ReadOnlySpan<char>(second, 1, length);
+ Assert.True(span1.Equals(span2, StringComparison.Ordinal));
+
+ Assert.True(span1.Equals(span2, StringComparison.CurrentCulture));
+ Assert.True(span1.Equals(span2, StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(span1.Equals(span2, StringComparison.InvariantCulture));
+ Assert.True(span1.Equals(span2, StringComparison.InvariantCultureIgnoreCase));
+ Assert.True(span1.Equals(span2, StringComparison.OrdinalIgnoreCase));
+ }
+ }
+
+ [Fact]
+ public static void EqualsUnknownComparisonType_StringComparison()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a);
+ TestHelpers.AssertThrows<ArgumentException, char>(span, (_span) => _span.Equals(_span, StringComparison.CurrentCulture - 1));
+ TestHelpers.AssertThrows<ArgumentException, char>(span, (_span) => _span.Equals(_span, StringComparison.OrdinalIgnoreCase + 1));
+ TestHelpers.AssertThrows<ArgumentException, char>(span, (_span) => _span.Equals(_span, (StringComparison)6));
+ }
+
+ [Theory]
+ // CurrentCulture
+ [InlineData("Hello", "Hello", StringComparison.CurrentCulture, true)]
+ [InlineData("Hello", "hello", StringComparison.CurrentCulture, false)]
+ [InlineData("Hello", "Helloo", StringComparison.CurrentCulture, false)]
+ [InlineData("Hello", "Hell", StringComparison.CurrentCulture, false)]
+ [InlineData("Hello", SoftHyphen + "Hello" + SoftHyphen, StringComparison.CurrentCulture, true)]
+ [InlineData("Hello", "", StringComparison.CurrentCulture, false)]
+ [InlineData("", "Hello", StringComparison.CurrentCulture, false)]
+ [InlineData("", "", StringComparison.CurrentCulture, true)]
+ // CurrentCultureIgnoreCase
+ [InlineData("Hello", "Hello", StringComparison.CurrentCultureIgnoreCase, true)]
+ [InlineData("Hello", "hello", StringComparison.CurrentCultureIgnoreCase, true)]
+ [InlineData("Hello", "helloo", StringComparison.CurrentCultureIgnoreCase, false)]
+ [InlineData("Hello", "hell", StringComparison.CurrentCultureIgnoreCase, false)]
+ [InlineData("Hello", SoftHyphen + "Hello" + SoftHyphen, StringComparison.CurrentCulture, true)]
+ [InlineData("Hello", "", StringComparison.CurrentCultureIgnoreCase, false)]
+ [InlineData("", "Hello", StringComparison.CurrentCultureIgnoreCase, false)]
+ [InlineData("", "", StringComparison.CurrentCultureIgnoreCase, true)]
+ // InvariantCulture
+ [InlineData("Hello", "Hello", StringComparison.InvariantCulture, true)]
+ [InlineData("Hello", "hello", StringComparison.InvariantCulture, false)]
+ [InlineData("Hello", "Helloo", StringComparison.InvariantCulture, false)]
+ [InlineData("Hello", "Hell", StringComparison.InvariantCulture, false)]
+ [InlineData("Hello", SoftHyphen + "Hello" + SoftHyphen, StringComparison.CurrentCulture, true)]
+ [InlineData("Hello", "", StringComparison.InvariantCulture, false)]
+ [InlineData("", "Hello", StringComparison.InvariantCulture, false)]
+ [InlineData("", "", StringComparison.InvariantCulture, true)]
+ // InvariantCultureIgnoreCase
+ [InlineData("Hello", "Hello", StringComparison.InvariantCultureIgnoreCase, true)]
+ [InlineData("Hello", "hello", StringComparison.InvariantCultureIgnoreCase, true)]
+ [InlineData("Hello", "Helloo", StringComparison.InvariantCultureIgnoreCase, false)]
+ [InlineData("Hello", "Hell", StringComparison.InvariantCultureIgnoreCase, false)]
+ [InlineData("Hello", SoftHyphen + "Hello" + SoftHyphen, StringComparison.CurrentCulture, true)]
+ [InlineData("Hello", "", StringComparison.InvariantCultureIgnoreCase, false)]
+ [InlineData("", "Hello", StringComparison.InvariantCultureIgnoreCase, false)]
+ [InlineData("", "", StringComparison.InvariantCultureIgnoreCase, true)]
+ // Ordinal
+ [InlineData("Hello", "Hello", StringComparison.Ordinal, true)]
+ [InlineData("Hello", "hello", StringComparison.Ordinal, false)]
+ [InlineData("Hello", "Helloo", StringComparison.Ordinal, false)]
+ [InlineData("Hello", "Hell", StringComparison.Ordinal, false)]
+ [InlineData("Hello", SoftHyphen + "Hello" + SoftHyphen, StringComparison.Ordinal, false)]
+ [InlineData("Hello", "", StringComparison.Ordinal, false)]
+ [InlineData("", "Hello", StringComparison.Ordinal, false)]
+ [InlineData("", "", StringComparison.Ordinal, true)]
+ // OridinalIgnoreCase
+ [InlineData("Hello", "Hello", StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("HELLO", "hello", StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("Hello", "Helloo", StringComparison.OrdinalIgnoreCase, false)]
+ [InlineData("Hello", "Hell", StringComparison.OrdinalIgnoreCase, false)]
+ [InlineData("Hello", SoftHyphen + "Hello" + SoftHyphen, StringComparison.OrdinalIgnoreCase, false)]
+ [InlineData("\u1234\u5678", "\u1234\u5678", StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("\u1234\u5678", "\u1234\u5679", StringComparison.OrdinalIgnoreCase, false)]
+ [InlineData("\u1234\u5678", "\u1235\u5678", StringComparison.OrdinalIgnoreCase, false)]
+ [InlineData("\u1234\u5678", "\u1234", StringComparison.OrdinalIgnoreCase, false)]
+ [InlineData("\u1234\u5678", "\u1234\u56789\u1234", StringComparison.OrdinalIgnoreCase, false)]
+ [InlineData("Hello", "", StringComparison.OrdinalIgnoreCase, false)]
+ [InlineData("", "Hello", StringComparison.OrdinalIgnoreCase, false)]
+ [InlineData("", "", StringComparison.OrdinalIgnoreCase, true)]
+ public static void Equals(string s1, string s2, StringComparison comparisonType, bool expected)
+ {
+ Assert.Equal(expected, s1.AsSpan().Equals(s2.AsSpan(), comparisonType));
+ }
+
+ public static IEnumerable<object[]> Equals_EncyclopaediaData()
+ {
+ yield return new object[] { StringComparison.CurrentCulture, false };
+ yield return new object[] { StringComparison.CurrentCultureIgnoreCase, false };
+ yield return new object[] { StringComparison.Ordinal, false };
+ yield return new object[] { StringComparison.OrdinalIgnoreCase, false };
+
+ // Windows and ICU disagree about how these strings compare in the default locale.
+ yield return new object[] { StringComparison.InvariantCulture, PlatformDetection.IsWindows };
+ yield return new object[] { StringComparison.InvariantCultureIgnoreCase, PlatformDetection.IsWindows };
+ }
+
+ [Theory]
+ [MemberData(nameof(Equals_EncyclopaediaData))]
+ public static void Equals_Encyclopaedia_ReturnsExpected(StringComparison comparison, bool expected)
+ {
+ string source = "encyclop\u00e6dia";
+ string target = "encyclopaedia";
+ CultureInfo backupCulture = CultureInfo.CurrentCulture;
+
+ Thread.CurrentThread.CurrentCulture = new CultureInfo("se-SE");
+ Assert.Equal(expected, source.AsSpan().Equals(target.AsSpan(), comparison));
+
+ Thread.CurrentThread.CurrentCulture = backupCulture;
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlySpan/IndexOf.byte.cs b/src/System.Memory/tests/ReadOnlySpan/IndexOf.byte.cs
index d587c3738c..29a6e16413 100644
--- a/src/System.Memory/tests/ReadOnlySpan/IndexOf.byte.cs
+++ b/src/System.Memory/tests/ReadOnlySpan/IndexOf.byte.cs
@@ -3,7 +3,6 @@
// See the LICENSE file in the project root for more information.
using System.Numerics;
-using System.Text;
using Xunit;
namespace System.SpanTests
diff --git a/src/System.Memory/tests/ReadOnlySpan/IndexOf.charSpan.cs b/src/System.Memory/tests/ReadOnlySpan/IndexOf.charSpan.cs
new file mode 100644
index 0000000000..b505deaa87
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlySpan/IndexOf.charSpan.cs
@@ -0,0 +1,409 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Globalization;
+using System.Threading;
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class ReadOnlySpanTests
+ {
+ [Theory]
+ [InlineData("Hello", 'l', 0, 5, 2)]
+ [InlineData("Hello", 'x', 0, 5, -1)]
+ [InlineData("Hello", 'l', 1, 4, 2)]
+ [InlineData("Hello", 'l', 3, 2, 3)]
+ [InlineData("Hello", 'l', 4, 1, -1)]
+ [InlineData("Hello", 'x', 1, 4, -1)]
+ [InlineData("Hello", 'l', 3, 0, -1)]
+ [InlineData("Hello", 'l', 0, 2, -1)]
+ [InlineData("Hello", 'l', 0, 3, 2)]
+ [InlineData("Hello", 'l', 4, 1, -1)]
+ [InlineData("Hello", 'x', 1, 4, -1)]
+ [InlineData("Hello", 'o', 5, 0, -1)]
+ [InlineData("H" + SoftHyphen + "ello", 'e', 0, 3, 2)]
+ [InlineData("\ud800\udfff", '\ud800', 0, 1, 0)] // Surrogate characters
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 'A', 0, 26, 0)]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 'B', 1, 25, 1)]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 'C', 2, 24, 2)]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 'D', 3, 23, 3)]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 'G', 2, 24, 6)]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 'K', 2, 24, 10)]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 'O', 2, 24, 14)]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 'P', 2, 24, 15)]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 'Q', 2, 24, 16)]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 'R', 2, 24, 17)]
+ [InlineData("________\u8080\u8080\u8080________", '\u0080', 0, 19, -1)]
+ [InlineData("________\u8000\u8000\u8000________", '\u0080', 0, 19, -1)]
+ [InlineData("__\u8080\u8000\u0080______________", '\u0080', 0, 19, 4)]
+ [InlineData("__\u8080\u8000__\u0080____________", '\u0080', 0, 19, 6)]
+ [InlineData("__________________________________", '\ufffd', 0, 34, -1)]
+ [InlineData("____________________________\ufffd", '\ufffd', 0, 29, 28)]
+ [InlineData("ABCDEFGHIJKLM", 'M', 0, 13, 12)]
+ [InlineData("ABCDEFGHIJKLMN", 'N', 0, 14, 13)]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ", '@', 0, 26, -1)]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXY", '@', 0, 25, -1)]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ#", '@', 0, 27, -1)]
+ [InlineData("_____________\u807f", '\u007f', 0, 14, -1)]
+ [InlineData("_____________\u807f__", '\u007f', 0, 16, -1)]
+ [InlineData("_____________\u807f\u007f_", '\u007f', 0, 16, 14)]
+ [InlineData("__\u807f_______________", '\u007f', 0, 18, -1)]
+ [InlineData("__\u807f___\u007f___________", '\u007f', 0, 18, 6)]
+ [InlineData("ABCDEFGHIJKLMN", 'N', 2, 11, -1)]
+ [InlineData("!@#$%^&", '%', 0, 7, 4)]
+ [InlineData("!@#$", '!', 0, 4, 0)]
+ [InlineData("!@#$", '@', 0, 4, 1)]
+ [InlineData("!@#$", '#', 0, 4, 2)]
+ [InlineData("!@#$", '$', 0, 4, 3)]
+ [InlineData("!@#$%^&*", '%', 0, 8, 4)]
+ public static void IndexOf_SingleLetter(string s, char target, int startIndex, int count, int expected)
+ {
+ bool safeForCurrentCulture =
+ IsSafeForCurrentCultureComparisons(s)
+ && IsSafeForCurrentCultureComparisons(target.ToString());
+
+ ReadOnlySpan<char> span = s.AsSpan();
+ var charArray = new char[1];
+ charArray[0] = target;
+ ReadOnlySpan<char> targetSpan = charArray;
+
+ int expectedFromSpan = expected == -1 ? expected : expected - startIndex;
+
+ if (count + startIndex == s.Length)
+ {
+ if (startIndex == 0)
+ {
+ Assert.Equal(expectedFromSpan, span.IndexOf(targetSpan, StringComparison.Ordinal));
+ Assert.Equal(expectedFromSpan, span.IndexOf(targetSpan, StringComparison.OrdinalIgnoreCase));
+
+ // To be safe we only want to run CurrentCulture comparisons if
+ // we know the results will not vary depending on location
+ if (safeForCurrentCulture)
+ {
+ Assert.Equal(expectedFromSpan, span.IndexOf(targetSpan, StringComparison.CurrentCulture));
+ }
+ }
+
+ Assert.Equal(expectedFromSpan, span.Slice(startIndex).IndexOf(targetSpan, StringComparison.Ordinal));
+ Assert.Equal(expectedFromSpan, span.Slice(startIndex).IndexOf(targetSpan, StringComparison.OrdinalIgnoreCase));
+
+ if (safeForCurrentCulture)
+ {
+ Assert.Equal(expectedFromSpan, span.Slice(startIndex).IndexOf(targetSpan, StringComparison.CurrentCulture));
+ }
+ }
+ Assert.Equal(expectedFromSpan, span.Slice(startIndex, count).IndexOf(targetSpan, StringComparison.Ordinal));
+ Assert.Equal(expectedFromSpan, span.Slice(startIndex, count).IndexOf(targetSpan, StringComparison.OrdinalIgnoreCase));
+
+ if (safeForCurrentCulture)
+ {
+ Assert.Equal(expectedFromSpan, span.Slice(startIndex, count).IndexOf(targetSpan, StringComparison.CurrentCulture));
+ }
+ }
+
+ private static bool IsSafeForCurrentCultureComparisons(string str)
+ {
+ for (int i = 0; i < str.Length; i++)
+ {
+ char c = str[i];
+ // We only want ASCII chars that you can see
+ // No controls, no delete, nothing >= 0x80
+ if (c < 0x20 || c == 0x7f || c >= 0x80)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ // NOTE: This is by design. Unix ignores the null characters (i.e. null characters have no weights for the string comparison).
+ // For desired behavior, use ordinal comparison instead of linguistic comparison.
+ // This is a known difference between Windows and Unix (https://github.com/dotnet/coreclr/issues/2051).
+ [Theory]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [InlineData("He\0lo", "He\0lo", 0)]
+ [InlineData("He\0lo", "He\0", 0)]
+ [InlineData("He\0lo", "\0", 2)]
+ [InlineData("He\0lo", "\0lo", 2)]
+ [InlineData("He\0lo", "lo", 3)]
+ [InlineData("Hello", "lo\0", -1)]
+ [InlineData("Hello", "\0lo", -1)]
+ [InlineData("Hello", "l\0o", -1)]
+ public static void IndexOf_NullInStrings(string s, string value, int expected)
+ {
+ Assert.Equal(expected, s.AsSpan().IndexOf(value.AsSpan(), StringComparison.Ordinal));
+ }
+
+ [Theory]
+ [MemberData(nameof(AllSubstringsAndComparisons), new object[] { "abcde" })]
+ public static void IndexOf_AllSubstrings(string s, string value, int startIndex, StringComparison comparison)
+ {
+ bool ignoringCase = comparison == StringComparison.OrdinalIgnoreCase || comparison == StringComparison.CurrentCultureIgnoreCase;
+
+ // First find the substring. We should be able to with all comparison types.
+ Assert.Equal(startIndex, s.AsSpan().IndexOf(value.AsSpan(), comparison)); // in the whole string
+ Assert.Equal(0, s.AsSpan(startIndex).IndexOf(value.AsSpan(), comparison)); // starting at substring
+ if (startIndex > 0)
+ {
+ Assert.Equal(1, s.AsSpan(startIndex - 1).IndexOf(value.AsSpan(), comparison)); // starting just before substring
+ }
+ Assert.Equal(-1, s.AsSpan(startIndex + 1).IndexOf(value.AsSpan(), comparison)); // starting just after start of substring
+
+ // Shouldn't be able to find the substring if the count is less than substring's length
+ Assert.Equal(-1, s.AsSpan(0, value.Length - 1).IndexOf(value.AsSpan(), comparison));
+
+ // Now double the source. Make sure we find the first copy of the substring.
+ int halfLen = s.Length;
+ s += s;
+ Assert.Equal(startIndex, s.AsSpan().IndexOf(value.AsSpan(), comparison));
+
+ // Now change the case of a letter.
+ s = s.ToUpperInvariant();
+ Assert.Equal(ignoringCase ? startIndex : -1, s.AsSpan().IndexOf(value.AsSpan(), comparison));
+ }
+
+ public static IEnumerable<object[]> AllSubstringsAndComparisons(string source)
+ {
+ var comparisons = new StringComparison[]
+ {
+ StringComparison.CurrentCulture,
+ StringComparison.CurrentCultureIgnoreCase,
+ StringComparison.Ordinal,
+ StringComparison.OrdinalIgnoreCase
+ };
+
+ foreach (StringComparison comparison in comparisons)
+ {
+ for (int i = 0; i <= source.Length; i++)
+ {
+ for (int subLen = source.Length - i; subLen > 0; subLen--)
+ {
+ yield return new object[] { source, source.Substring(i, subLen), i, comparison };
+ }
+ }
+ }
+ }
+
+ [Fact]
+ public static void IndexOf_TurkishI_TurkishCulture()
+ {
+ CultureInfo backupCulture = CultureInfo.CurrentCulture;
+
+ Thread.CurrentThread.CurrentCulture = new CultureInfo("tr-TR");
+
+ string str = "Turkish I \u0131s TROUBL\u0130NG!";
+ string valueString = "\u0130";
+ ReadOnlySpan<char> s = str.AsSpan();
+ ReadOnlySpan<char> value = valueString.AsSpan();
+ Assert.Equal(19, s.IndexOf(value, StringComparison.CurrentCulture));
+ Assert.Equal(4, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(19, s.IndexOf(value, StringComparison.Ordinal));
+ Assert.Equal(19, s.IndexOf(value, StringComparison.OrdinalIgnoreCase));
+
+ valueString = "\u0131";
+ value = valueString.AsSpan();
+ Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCulture));
+ Assert.Equal(8, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(10, s.IndexOf(value, StringComparison.Ordinal));
+ Assert.Equal(10, s.IndexOf(value, StringComparison.OrdinalIgnoreCase));
+
+ Thread.CurrentThread.CurrentCulture = backupCulture;
+ }
+
+ [Fact]
+ public static void IndexOf_TurkishI_InvariantCulture()
+ {
+ CultureInfo backupCulture = CultureInfo.CurrentCulture;
+
+ Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
+
+ string str = "Turkish I \u0131s TROUBL\u0130NG!";
+ string valueString = "\u0130";
+ ReadOnlySpan<char> s = str.AsSpan();
+ ReadOnlySpan<char> value = valueString.AsSpan();
+
+ Assert.Equal(19, s.IndexOf(value, StringComparison.CurrentCulture));
+ Assert.Equal(19, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+
+ valueString = "\u0131";
+ value = valueString.AsSpan();
+ Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCulture));
+ Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+
+ Thread.CurrentThread.CurrentCulture = backupCulture;
+ }
+
+ [Fact]
+ public static void IndexOf_TurkishI_EnglishUSCulture()
+ {
+ CultureInfo backupCulture = CultureInfo.CurrentCulture;
+
+ Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
+
+ string str = "Turkish I \u0131s TROUBL\u0130NG!";
+ string valueString = "\u0130";
+ ReadOnlySpan<char> s = str.AsSpan();
+ ReadOnlySpan<char> value = valueString.AsSpan();
+
+ Assert.Equal(19, s.IndexOf(value, StringComparison.CurrentCulture));
+ Assert.Equal(19, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+
+ valueString = "\u0131";
+ value = valueString.AsSpan();
+ Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCulture));
+ Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+
+ Thread.CurrentThread.CurrentCulture = backupCulture;
+ }
+
+ [Fact]
+ public static void IndexOf_HungarianDoubleCompression_HungarianCulture()
+ {
+ string str = "dzsdzs";
+ string valueString = "ddzs";
+
+ ReadOnlySpan<char> s = str.AsSpan();
+ ReadOnlySpan<char> value = valueString.AsSpan();
+
+ CultureInfo backupCulture = CultureInfo.CurrentCulture;
+
+ Thread.CurrentThread.CurrentCulture = new CultureInfo("hu-HU");
+ /*
+ There are differences between Windows and ICU regarding contractions.
+ Windows has equal contraction collation weights, including case (target="Ddzs" same behavior as "ddzs").
+ ICU has different contraction collation weights, depending on locale collation rules.
+ If CurrentCultureIgnoreCase is specified, ICU will use 'secondary' collation rules
+ which ignore the contraction collation weights (defined as 'tertiary' rules)
+ */
+ Assert.Equal(PlatformDetection.IsWindows ? 0 : -1, s.IndexOf(value, StringComparison.CurrentCulture));
+
+ Assert.Equal(0, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(-1, s.IndexOf(value, StringComparison.Ordinal));
+ Assert.Equal(-1, s.IndexOf(value, StringComparison.OrdinalIgnoreCase));
+
+ Thread.CurrentThread.CurrentCulture = backupCulture;
+ }
+
+ [Fact]
+ public static void IndexOf_HungarianDoubleCompression_InvariantCulture()
+ {
+ string str = "dzsdzs";
+ string valueString = "ddzs";
+
+ ReadOnlySpan<char> s = str.AsSpan();
+ ReadOnlySpan<char> value = valueString.AsSpan();
+
+ CultureInfo backupCulture = CultureInfo.CurrentCulture;
+
+ Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
+ Assert.Equal(-1, s.IndexOf(value, StringComparison.CurrentCulture));
+ Assert.Equal(-1, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+
+ Thread.CurrentThread.CurrentCulture = backupCulture;
+ }
+
+ [Fact]
+ public static void IndexOf_EquivalentDiacritics_EnglishUSCulture()
+ {
+ string str = "Exhibit a\u0300\u00C0";
+ string valueString = "\u00C0";
+
+ ReadOnlySpan<char> s = str.AsSpan();
+ ReadOnlySpan<char> value = valueString.AsSpan();
+
+ CultureInfo backupCulture = CultureInfo.CurrentCulture;
+
+ Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
+ Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCulture));
+ Assert.Equal(8, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(10, s.IndexOf(value, StringComparison.Ordinal));
+ Assert.Equal(10, s.IndexOf(value, StringComparison.OrdinalIgnoreCase));
+
+ valueString = "a\u0300"; // this diacritic combines with preceding character
+ value = valueString.AsSpan();
+ Assert.Equal(8, s.IndexOf(value, StringComparison.CurrentCulture));
+ Assert.Equal(8, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(8, s.IndexOf(value, StringComparison.Ordinal));
+ Assert.Equal(8, s.IndexOf(value, StringComparison.OrdinalIgnoreCase));
+
+ Thread.CurrentThread.CurrentCulture = backupCulture;
+ }
+
+ [Fact]
+ public static void IndexOf_EquivalentDiacritics_InvariantCulture()
+ {
+ string str = "Exhibit a\u0300\u00C0";
+ string valueString = "\u00C0";
+
+ ReadOnlySpan<char> s = str.AsSpan();
+ ReadOnlySpan<char> value = valueString.AsSpan();
+
+ CultureInfo backupCulture = CultureInfo.CurrentCulture;
+
+ Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
+ Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCulture));
+ Assert.Equal(8, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+
+ valueString = "a\u0300"; // this diacritic combines with preceding character
+ value = valueString.AsSpan();
+ Assert.Equal(8, s.IndexOf(value, StringComparison.CurrentCulture));
+ Assert.Equal(8, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+
+ Thread.CurrentThread.CurrentCulture = backupCulture;
+ }
+
+ [Fact]
+ public static void IndexOf_CyrillicE_EnglishUSCulture()
+ {
+ string str = "Foo\u0400Bar";
+ string valueString = "\u0400";
+
+ ReadOnlySpan<char> s = str.AsSpan();
+ ReadOnlySpan<char> value = valueString.AsSpan();
+
+ CultureInfo backupCulture = CultureInfo.CurrentCulture;
+
+ Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
+ Assert.Equal(3, s.IndexOf(value, StringComparison.CurrentCulture));
+ Assert.Equal(3, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(3, s.IndexOf(value, StringComparison.Ordinal));
+ Assert.Equal(3, s.IndexOf(value, StringComparison.OrdinalIgnoreCase));
+
+ valueString = "bar";
+ value = valueString.AsSpan();
+ Assert.Equal(-1, s.IndexOf(value, StringComparison.CurrentCulture));
+ Assert.Equal(4, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(-1, s.IndexOf(value, StringComparison.Ordinal));
+ Assert.Equal(4, s.IndexOf(value, StringComparison.OrdinalIgnoreCase));
+
+ Thread.CurrentThread.CurrentCulture = backupCulture;
+ }
+
+ [Fact]
+ public static void IndexOf_CyrillicE_InvariantCulture()
+ {
+ string str = "Foo\u0400Bar";
+ string valueString = "\u0400";
+
+ ReadOnlySpan<char> s = str.AsSpan();
+ ReadOnlySpan<char> value = valueString.AsSpan();
+
+ CultureInfo backupCulture = CultureInfo.CurrentCulture;
+
+ Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
+ Assert.Equal(3, s.IndexOf(value, StringComparison.CurrentCulture));
+ Assert.Equal(3, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+
+ valueString = "bar";
+ value = valueString.AsSpan();
+ Assert.Equal(-1, s.IndexOf(value, StringComparison.CurrentCulture));
+ Assert.Equal(4, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+
+ Thread.CurrentThread.CurrentCulture = backupCulture;
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlySpan/IndexOfAny.byte.cs b/src/System.Memory/tests/ReadOnlySpan/IndexOfAny.byte.cs
index d9a15cec68..358cf6e4a5 100644
--- a/src/System.Memory/tests/ReadOnlySpan/IndexOfAny.byte.cs
+++ b/src/System.Memory/tests/ReadOnlySpan/IndexOfAny.byte.cs
@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Numerics;
using System.Text;
using Xunit;
diff --git a/src/System.Memory/tests/ReadOnlySpan/IndexOfSequence.char.cs b/src/System.Memory/tests/ReadOnlySpan/IndexOfSequence.char.cs
index eedc14ac0c..9841b76fa1 100644
--- a/src/System.Memory/tests/ReadOnlySpan/IndexOfSequence.char.cs
+++ b/src/System.Memory/tests/ReadOnlySpan/IndexOfSequence.char.cs
@@ -15,6 +15,7 @@ namespace System.SpanTests
ReadOnlySpan<char> value = new ReadOnlySpan<char>(new char[] { '5', '1', '7' });
int index = span.IndexOf(value);
Assert.Equal(0, index);
+ Assert.Equal(index, span.IndexOf(value, StringComparison.Ordinal));
}
[Fact]
@@ -24,6 +25,7 @@ namespace System.SpanTests
ReadOnlySpan<char> value = new ReadOnlySpan<char>(new char[] { '2', '3' });
int index = span.IndexOf(value);
Assert.Equal(1, index);
+ Assert.Equal(index, span.IndexOf(value, StringComparison.Ordinal));
}
[Fact]
@@ -33,6 +35,7 @@ namespace System.SpanTests
ReadOnlySpan<char> value = new ReadOnlySpan<char>(new char[] { '7', '7', '8' });
int index = span.IndexOf(value);
Assert.Equal(10, index);
+ Assert.Equal(index, span.IndexOf(value, StringComparison.Ordinal));
}
[Fact]
@@ -42,6 +45,7 @@ namespace System.SpanTests
ReadOnlySpan<char> value = new ReadOnlySpan<char>(new char[] { '7', '7', '8', 'X' });
int index = span.IndexOf(value);
Assert.Equal(-1, index);
+ Assert.Equal(index, span.IndexOf(value, StringComparison.Ordinal));
}
[Fact]
@@ -51,6 +55,7 @@ namespace System.SpanTests
ReadOnlySpan<char> value = new ReadOnlySpan<char>(new char[] { 'X', '7', '8', '9' });
int index = span.IndexOf(value);
Assert.Equal(-1, index);
+ Assert.Equal(index, span.IndexOf(value, StringComparison.Ordinal));
}
[Fact]
@@ -60,6 +65,7 @@ namespace System.SpanTests
ReadOnlySpan<char> value = new ReadOnlySpan<char>(new char[] { '3', '4', '5' });
int index = span.IndexOf(value);
Assert.Equal(3, index);
+ Assert.Equal(index, span.IndexOf(value, StringComparison.Ordinal));
}
[Fact]
@@ -69,6 +75,7 @@ namespace System.SpanTests
ReadOnlySpan<char> value = new ReadOnlySpan<char>(new char[] { '3', '4', '5' });
int index = span.IndexOf(value);
Assert.Equal(-1, index);
+ Assert.Equal(index, span.IndexOf(value, StringComparison.Ordinal));
}
[Fact]
@@ -79,6 +86,7 @@ namespace System.SpanTests
ReadOnlySpan<char> value = new ReadOnlySpan<char>(Array.Empty<char>());
int index = span.IndexOf(value);
Assert.Equal(0, index);
+ Assert.Equal(index, span.IndexOf(value, StringComparison.Ordinal));
}
[Fact]
@@ -88,6 +96,7 @@ namespace System.SpanTests
ReadOnlySpan<char> value = new ReadOnlySpan<char>(new char[] { '1', '2', '3' });
int index = span.IndexOf(value);
Assert.Equal(-1, index);
+ Assert.Equal(index, span.IndexOf(value, StringComparison.Ordinal));
}
[Fact]
@@ -98,6 +107,7 @@ namespace System.SpanTests
ReadOnlySpan<char> value = new ReadOnlySpan<char>(new char[] { '2' });
int index = span.IndexOf(value);
Assert.Equal(2, index);
+ Assert.Equal(index, span.IndexOf(value, StringComparison.Ordinal));
}
[Fact]
@@ -108,6 +118,7 @@ namespace System.SpanTests
ReadOnlySpan<char> value = new ReadOnlySpan<char>(new char[] { '5' });
int index = span.IndexOf(value);
Assert.Equal(5, index);
+ Assert.Equal(index, span.IndexOf(value, StringComparison.Ordinal));
}
[Fact]
@@ -118,6 +129,7 @@ namespace System.SpanTests
ReadOnlySpan<char> value = new ReadOnlySpan<char>(new char[] { '5' });
int index = span.IndexOf(value);
Assert.Equal(-1, index);
+ Assert.Equal(index, span.IndexOf(value, StringComparison.Ordinal));
}
}
}
diff --git a/src/System.Memory/tests/ReadOnlySpan/IsWhiteSpace.cs b/src/System.Memory/tests/ReadOnlySpan/IsWhiteSpace.cs
new file mode 100644
index 0000000000..3836013957
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlySpan/IsWhiteSpace.cs
@@ -0,0 +1,113 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class ReadOnlySpanTests
+ {
+ private static readonly char[] s_whiteSpaceCharacters = { '\u0009', '\u000a', '\u000b', '\u000c', '\u000d', '\u0020', '\u0085', '\u00a0', '\u1680' };
+
+ [Fact]
+ public static void ZeroLengthIsWhiteSpace()
+ {
+ var span = new ReadOnlySpan<char>(Array.Empty<char>());
+ bool result = span.IsWhiteSpace();
+ Assert.Equal(string.IsNullOrWhiteSpace(""), result);
+ }
+
+ [Fact]
+ public static void IsWhiteSpaceTrueLatin1()
+ {
+ Random rand = new Random(42);
+ for (int length = 0; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = s_whiteSpaceCharacters[rand.Next(0, s_whiteSpaceCharacters.Length - 1)];
+ }
+ var span = new Span<char>(a);
+ bool result = span.AsReadOnlySpan().IsWhiteSpace();
+ Assert.Equal(string.IsNullOrWhiteSpace(new string(a)), result);
+
+ for (int i = 0; i < s_whiteSpaceCharacters.Length - 1; i++)
+ {
+ span.Fill(s_whiteSpaceCharacters[i]);
+ Assert.Equal(string.IsNullOrWhiteSpace(new string(span.ToArray())), span.AsReadOnlySpan().IsWhiteSpace());
+ }
+ }
+ }
+
+ [Fact]
+ public static void IsWhiteSpaceTrue()
+ {
+ Random rand = new Random(42);
+ for (int length = 0; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = s_whiteSpaceCharacters[rand.Next(0, s_whiteSpaceCharacters.Length)];
+ }
+ var span = new ReadOnlySpan<char>(a);
+ bool result = span.IsWhiteSpace();
+ Assert.Equal(string.IsNullOrWhiteSpace(new string(span.ToArray())), result);
+ }
+ }
+
+ [Fact]
+ public static void IsWhiteSpaceFalse()
+ {
+ Random rand = new Random(42);
+ for (int length = 1; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = s_whiteSpaceCharacters[rand.Next(0, s_whiteSpaceCharacters.Length)];
+ }
+ var span = new Span<char>(a);
+
+ // first character is not a white-space character
+ a[0] = 'a';
+ bool result = span.AsReadOnlySpan().IsWhiteSpace();
+ Assert.Equal(string.IsNullOrWhiteSpace(new string(span.ToArray())), result);
+ a[0] = ' ';
+
+ // last character is not a white-space character
+ a[length - 1] = 'a';
+ result = span.AsReadOnlySpan().IsWhiteSpace();
+ Assert.Equal(string.IsNullOrWhiteSpace(new string(span.ToArray())), result);
+ a[length - 1] = ' ';
+
+ // character in the middle is not a white-space character
+ a[length/2] = 'a';
+ result = span.AsReadOnlySpan().IsWhiteSpace();
+ Assert.Equal(string.IsNullOrWhiteSpace(new string(span.ToArray())), result);
+ a[length/2] = ' ';
+
+ // no character is a white-space character
+ span.Fill('a');
+ result = span.AsReadOnlySpan().IsWhiteSpace();
+ Assert.Equal(string.IsNullOrWhiteSpace(new string(span.ToArray())), result);
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoIsWhiteSpaceChecksGoOutOfRange()
+ {
+ for (int length = 3; length < 64; length++)
+ {
+ char[] first = new char[length];
+ first[0] = ' ';
+ first[length - 1] = ' ';
+ var span = new ReadOnlySpan<char>(first, 1, length - 2);
+ bool result = span.IsWhiteSpace();
+ Assert.Equal(string.IsNullOrWhiteSpace(new string(span.ToArray())), result);
+ }
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlySpan/Overlaps.cs b/src/System.Memory/tests/ReadOnlySpan/Overlaps.cs
index ed572d9f36..1c702511b5 100644
--- a/src/System.Memory/tests/ReadOnlySpan/Overlaps.cs
+++ b/src/System.Memory/tests/ReadOnlySpan/Overlaps.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Runtime.InteropServices;
using Xunit;
namespace System.SpanTests
@@ -32,8 +33,8 @@ namespace System.SpanTests
ReadOnlySpan<int> source = a.AsReadOnlySpan().Slice(7, 5);
- Span<int> expected = new int[a.Length].AsSpan().Slice(i, 5);
- Span<int> actual = a.AsSpan().Slice(i, 5);
+ Span<int> expected = new int[a.Length].AsSpan(i, 5);
+ Span<int> actual = a.AsSpan(i, 5);
DoubleEachElementForwards(source, expected);
DoubleEachElementForwards(source, actual);
@@ -49,11 +50,10 @@ namespace System.SpanTests
{
int[] a = new int[] { 1, 2, 3, 4, 5, 6 };
- ReadOnlySpan<int> source = a.AsReadOnlySpan().AsBytes()
- .Slice(2, 5 * sizeof(int))
- .NonPortableCast<byte, int>();
+ ReadOnlySpan<byte> bytes = MemoryMarshal.AsBytes(a.AsReadOnlySpan());
+ ReadOnlySpan<int> source = MemoryMarshal.Cast<byte, int>(bytes.Slice(2, 5 * sizeof(int)));
- Span<int> actual = a.AsSpan().Slice(0, 5);
+ Span<int> actual = a.AsSpan(0, 5);
DoubleEachElementForwards(source, actual);
});
@@ -62,11 +62,10 @@ namespace System.SpanTests
{
int[] a = new int[] { 1, 2, 3, 4, 5, 6 };
- ReadOnlySpan<int> source = a.AsReadOnlySpan().AsBytes()
- .Slice(2, 5 * sizeof(int))
- .NonPortableCast<byte, int>();
+ ReadOnlySpan<byte> bytes = MemoryMarshal.AsBytes(a.AsReadOnlySpan());
+ ReadOnlySpan<int> source = MemoryMarshal.Cast<byte, int>(bytes.Slice(2, 5 * sizeof(int)));
- Span<int> actual = a.AsSpan().Slice(1, 5);
+ Span<int> actual = a.AsSpan(1, 5);
DoubleEachElementForwards(source, actual);
});
@@ -96,8 +95,8 @@ namespace System.SpanTests
ReadOnlySpan<int> source = a.AsReadOnlySpan().Slice(7, 5);
- Span<int> expected = new int[a.Length].AsSpan().Slice(i, 5);
- Span<int> actual = a.AsSpan().Slice(i, 5);
+ Span<int> expected = new int[a.Length].AsSpan(i, 5);
+ Span<int> actual = a.AsSpan(i, 5);
DoubleEachElementBackwards(source, expected);
DoubleEachElementBackwards(source, actual);
@@ -113,11 +112,10 @@ namespace System.SpanTests
{
int[] a = new int[] { 1, 2, 3, 4, 5, 6 };
- ReadOnlySpan<int> source = a.AsReadOnlySpan().AsBytes()
- .Slice(2, 5 * sizeof(int))
- .NonPortableCast<byte, int>();
+ ReadOnlySpan<byte> bytes = MemoryMarshal.AsBytes(a.AsReadOnlySpan());
+ ReadOnlySpan<int> source = MemoryMarshal.Cast<byte, int>(bytes.Slice(2, 5 * sizeof(int)));
- Span<int> actual = a.AsSpan().Slice(0, 5);
+ Span<int> actual = a.AsSpan(0, 5);
DoubleEachElementBackwards(source, actual);
});
@@ -126,11 +124,10 @@ namespace System.SpanTests
{
int[] a = new int[] { 1, 2, 3, 4, 5, 6 };
- ReadOnlySpan<int> source = a.AsReadOnlySpan().AsBytes()
- .Slice(2, 5 * sizeof(int))
- .NonPortableCast<byte, int>();
+ ReadOnlySpan<byte> bytes = MemoryMarshal.AsBytes(a.AsReadOnlySpan());
+ ReadOnlySpan<int> source = MemoryMarshal.Cast<byte, int>(bytes.Slice(2, 5 * sizeof(int)));
- Span<int> actual = a.AsSpan().Slice(1, 5);
+ Span<int> actual = a.AsSpan(1, 5);
DoubleEachElementBackwards(source, actual);
});
diff --git a/src/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.T.cs b/src/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.T.cs
new file mode 100644
index 0000000000..0924295bdc
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.T.cs
@@ -0,0 +1,273 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class ReadOnlySpanTests
+ {
+ [Fact]
+ public static void OnSequenceCompareToOfEqualSpansMakeSureEveryElementIsCompared()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var log = new TIntLog();
+
+ var first = new TInt[length];
+ var second = new TInt[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = new TInt(10 * (i + 1), log);
+ }
+
+ var firstSpan = new ReadOnlySpan<TInt>(first);
+ var secondSpan = new ReadOnlySpan<TInt>(second);
+ int result = firstSpan.SequenceCompareTo(secondSpan);
+ Assert.Equal(0, result);
+
+ // Make sure each element of the array was compared once. (Strictly speaking, it would not be illegal for
+ // SequenceCompareTo to compare an element more than once but that would be a non-optimal implementation and
+ // a red flag. So we'll stick with the stricter test.)
+ Assert.Equal(first.Length, log.Count);
+ foreach (TInt elem in first)
+ {
+ int numCompares = log.CountCompares(elem.Value, elem.Value);
+ Assert.True(numCompares == 1, $"Expected {numCompares} == 1 for element {elem.Value}.");
+ }
+ }
+ }
+
+ [Fact]
+ public static void SequenceCompareToSingleMismatch()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ var log = new TIntLog();
+
+ var first = new TInt[length];
+ var second = new TInt[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = new TInt(10 * (i + 1), log);
+ }
+
+ second[mismatchIndex] = new TInt(second[mismatchIndex].Value + 1, log);
+
+ var firstSpan = new ReadOnlySpan<TInt>(first);
+ var secondSpan = new ReadOnlySpan<TInt>(second);
+ int result = firstSpan.SequenceCompareTo(secondSpan);
+ Assert.True(result < 0);
+ Assert.Equal(1, log.CountCompares(first[mismatchIndex].Value, second[mismatchIndex].Value));
+
+ result = secondSpan.SequenceCompareTo(firstSpan); // adds to log.CountCompares
+ Assert.True(result > 0);
+ Assert.Equal(2, log.CountCompares(first[mismatchIndex].Value, second[mismatchIndex].Value));
+ }
+ }
+ }
+
+ [Fact]
+ public static void SequenceCompareToNoMatch()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ var log = new TIntLog();
+
+ var first = new TInt[length];
+ var second = new TInt[length];
+
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = new TInt(i + 1, log);
+ second[i] = new TInt(length + i + 1, log);
+ }
+
+ var firstSpan = new ReadOnlySpan<TInt>(first);
+ var secondSpan = new ReadOnlySpan<TInt>(second);
+ int result = firstSpan.SequenceCompareTo(secondSpan);
+ Assert.True(result < 0);
+ Assert.Equal(1, log.CountCompares(firstSpan[0].Value, secondSpan[0].Value));
+
+ result = secondSpan.SequenceCompareTo(firstSpan); // adds to log.CountCompares
+ Assert.True(result > 0);
+ Assert.Equal(2, log.CountCompares(firstSpan[0].Value, secondSpan[0].Value));
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoSequenceCompareToChecksGoOutOfRange()
+ {
+ const int GuardValue = 77777;
+ const int GuardLength = 50;
+
+ Action<int, int> checkForOutOfRangeAccess =
+ delegate (int x, int y)
+ {
+ if (x == GuardValue || y == GuardValue)
+ throw new Exception("Detected out of range access in IndexOf()");
+ };
+
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new TInt[GuardLength + length + GuardLength];
+ var second = new TInt[GuardLength + length + GuardLength];
+ for (int i = 0; i < first.Length; i++)
+ {
+ first[i] = second[i] = new TInt(GuardValue, checkForOutOfRangeAccess);
+ }
+
+ for (int i = 0; i < length; i++)
+ {
+ first[GuardLength + i] = second[GuardLength + i] = new TInt(10 * (i + 1), checkForOutOfRangeAccess);
+ }
+
+ var firstSpan = new ReadOnlySpan<TInt>(first, GuardLength, length);
+ var secondSpan = new ReadOnlySpan<TInt>(second, GuardLength, length);
+ int result = firstSpan.SequenceCompareTo(secondSpan);
+ Assert.Equal(0, result);
+ }
+ }
+
+ [Fact]
+ public static void ZeroLengthSequenceCompareTo_String()
+ {
+ var a = new string[3];
+
+ var first = new ReadOnlySpan<string>(a, 1, 0);
+ var second = new ReadOnlySpan<string>(a, 2, 0);
+ int result = first.SequenceCompareTo<string>(second);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SameSpanSequenceCompareTo_String()
+ {
+ string[] a = { "fourth", "fifth", "sixth" };
+ var span = new ReadOnlySpan<string>(a);
+ int result = span.SequenceCompareTo<string>(span);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SequenceCompareToArrayImplicit_String()
+ {
+ string[] a = { "fourth", "fifth", "sixth" };
+ var first = new ReadOnlySpan<string>(a, 0, 3);
+ int result = first.SequenceCompareTo<string>(a);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SequenceCompareToArraySegmentImplicit_String()
+ {
+ string[] src = { "first", "second", "third" };
+ string[] dst = { "fifth", "first", "second", "third", "tenth" };
+ var segment = new ArraySegment<string>(dst, 1, 3);
+
+ var first = new ReadOnlySpan<string>(src, 0, 3);
+ int result = first.SequenceCompareTo<string>(segment);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void LengthMismatchSequenceCompareTo_String()
+ {
+ string[] a = { "fourth", "fifth", "sixth" };
+ var first = new ReadOnlySpan<string>(a, 0, 2);
+ var second = new ReadOnlySpan<string>(a, 0, 3);
+ int result = first.SequenceCompareTo<string>(second);
+ Assert.True(result < 0);
+
+ result = second.SequenceCompareTo<string>(first);
+ Assert.True(result > 0);
+
+ // one sequence is empty
+ first = new Span<string>(a, 1, 0);
+
+ result = first.SequenceCompareTo<string>(second);
+ Assert.True(result < 0);
+
+ result = second.SequenceCompareTo<string>(first);
+ Assert.True(result > 0);
+ }
+
+ [Fact]
+ public static void SequenceCompareToWithSingleMismatch_String()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ var first = new string[length];
+ var second = new string[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = $"item {i + 1}";
+ }
+
+ second[mismatchIndex] = (string)(second[mismatchIndex] + 1);
+
+ var firstSpan = new ReadOnlySpan<string>(first);
+ var secondSpan = new ReadOnlySpan<string>(second);
+ int result = firstSpan.SequenceCompareTo<string>(secondSpan);
+ Assert.True(result < 0);
+
+ result = secondSpan.SequenceCompareTo<string>(firstSpan);
+ Assert.True(result > 0);
+ }
+ }
+ }
+
+ [Fact]
+ public static void SequenceCompareToNoMatch_string()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ var first = new string[length];
+ var second = new string[length];
+
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = $"item {i + 1}";
+ second[i] = $"item {int.MaxValue - i}";
+ }
+
+ var firstSpan = new ReadOnlySpan<string>(first);
+ var secondSpan = new ReadOnlySpan<string>(second);
+ int result = firstSpan.SequenceCompareTo<string>(secondSpan);
+ Assert.True(result < 0);
+
+ result = secondSpan.SequenceCompareTo<string>(firstSpan);
+ Assert.True(result > 0);
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoSequenceCompareToChecksGoOutOfRange_string()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new string[length + 2];
+ first[0] = "99";
+ for (int k = 1; k <= length; k++)
+ first[k] = string.Empty;
+ first[length + 1] = "99";
+
+ var second = new string[length + 2];
+ second[0] = "100";
+ for (int k = 1; k <= length; k++)
+ second[k] = string.Empty;
+ second[length + 1] = "100";
+
+ var span1 = new ReadOnlySpan<string>(first, 1, length);
+ var span2 = new ReadOnlySpan<string>(second, 1, length);
+ int result = span1.SequenceCompareTo<string>(span2);
+ Assert.Equal(0, result);
+ }
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.bool.cs b/src/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.bool.cs
new file mode 100644
index 0000000000..964492edbd
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.bool.cs
@@ -0,0 +1,149 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class ReadOnlySpanTests
+ {
+ [Fact]
+ public static void ZeroLengthSequenceCompareTo_Bool()
+ {
+ var a = new bool[3];
+
+ var first = new ReadOnlySpan<bool>(a, 1, 0);
+ var second = new ReadOnlySpan<bool>(a, 2, 0);
+ int result = first.SequenceCompareTo<bool>(second);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SameSpanSequenceCompareTo_Bool()
+ {
+ bool[] a = { true, true, false };
+ var span = new ReadOnlySpan<bool>(a);
+ int result = span.SequenceCompareTo<bool>(span);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SequenceCompareToArrayImplicit_Bool()
+ {
+ bool[] a = { true, true, false };
+ var first = new ReadOnlySpan<bool>(a, 0, 3);
+ int result = first.SequenceCompareTo<bool>(a);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SequenceCompareToArraySegmentImplicit_Bool()
+ {
+ bool[] src = { true, true, true};
+ bool[] dst = { false, true, true, true, false };
+ var segment = new ArraySegment<bool>(dst, 1, 3);
+
+ var first = new ReadOnlySpan<bool>(src, 0, 3);
+ int result = first.SequenceCompareTo<bool>(segment);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void LengthMismatchSequenceCompareTo_Bool()
+ {
+ bool[] a = { true, true, false };
+ var first = new ReadOnlySpan<bool>(a, 0, 2);
+ var second = new ReadOnlySpan<bool>(a, 0, 3);
+ int result = first.SequenceCompareTo<bool>(second);
+ Assert.True(result < 0);
+
+ result = second.SequenceCompareTo<bool>(first);
+ Assert.True(result > 0);
+
+ // one sequence is empty
+ first = new ReadOnlySpan<bool>(a, 1, 0);
+
+ result = first.SequenceCompareTo<bool>(second);
+ Assert.True(result < 0);
+
+ result = second.SequenceCompareTo<bool>(first);
+ Assert.True(result > 0);
+ }
+
+ [Fact]
+ public static void SequenceCompareToWithSingleMismatch_Bool()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ var first = new bool[length];
+ var second = new bool[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = true;
+ }
+
+ second[mismatchIndex] = !second[mismatchIndex];
+
+ var firstSpan = new ReadOnlySpan<bool>(first);
+ var secondSpan = new ReadOnlySpan<bool>(second);
+ int result = firstSpan.SequenceCompareTo<bool>(secondSpan);
+ Assert.True(result > 0);
+
+ result = secondSpan.SequenceCompareTo<bool>(firstSpan);
+ Assert.True(result < 0);
+ }
+ }
+ }
+
+ [Fact]
+ public static void SequenceCompareToNoMatch_Bool()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ var first = new bool[length];
+ var second = new bool[length];
+
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = (i % 2 != 0);
+ second[i] = (i % 2 == 0);
+ }
+
+ var firstSpan = new ReadOnlySpan<bool>(first);
+ var secondSpan = new ReadOnlySpan<bool>(second);
+ int result = firstSpan.SequenceCompareTo<bool>(secondSpan);
+ Assert.True(result < 0);
+
+ result = secondSpan.SequenceCompareTo<bool>(firstSpan);
+ Assert.True(result > 0);
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoSequenceCompareToChecksGoOutOfRange_Bool()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new bool[length + 2];
+ first[0] = true;
+ for (int k = 1; k <= length; k++)
+ first[k] = false;
+ first[length + 1] = true;
+
+ var second = new bool[length + 2];
+ second[0] = false;
+ for (int k = 1; k <= length; k++)
+ second[k] = false;
+ second[length + 1] = false;
+
+ var span1 = new ReadOnlySpan<bool>(first, 1, length);
+ var span2 = new ReadOnlySpan<bool>(second, 1, length);
+ int result = span1.SequenceCompareTo<bool>(span2);
+ Assert.Equal(0, result);
+ }
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.byte.cs b/src/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.byte.cs
new file mode 100644
index 0000000000..9accd0826e
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.byte.cs
@@ -0,0 +1,145 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class ReadOnlySpanTests
+ {
+ [Fact]
+ public static void ZeroLengthSequenceCompareTo_Byte()
+ {
+ var a = new byte[3];
+
+ var first = new ReadOnlySpan<byte>(a, 1, 0);
+ var second = new ReadOnlySpan<byte>(a, 2, 0);
+ int result = first.SequenceCompareTo<byte>(second);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SameSpanSequenceCompareTo_Byte()
+ {
+ byte[] a = { 4, 5, 6 };
+ var span = new ReadOnlySpan<byte>(a);
+ int result = span.SequenceCompareTo<byte>(span);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SequenceCompareToArrayImplicit_Byte()
+ {
+ byte[] a = { 4, 5, 6 };
+ var first = new ReadOnlySpan<byte>(a, 0, 3);
+ int result = first.SequenceCompareTo<byte>(a);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SequenceCompareToArraySegmentImplicit_Byte()
+ {
+ byte[] src = { 1, 2, 3 };
+ byte[] dst = { 5, 1, 2, 3, 10 };
+ var segment = new ArraySegment<byte>(dst, 1, 3);
+
+ var first = new ReadOnlySpan<byte>(src, 0, 3);
+ int result = first.SequenceCompareTo<byte>(segment);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void LengthMismatchSequenceCompareTo_Byte()
+ {
+ byte[] a = { 4, 5, 6 };
+ var first = new ReadOnlySpan<byte>(a, 0, 2);
+ var second = new ReadOnlySpan<byte>(a, 0, 3);
+ int result = first.SequenceCompareTo<byte>(second);
+ Assert.True(result < 0);
+
+ result = second.SequenceCompareTo<byte>(first);
+ Assert.True(result > 0);
+
+ // one sequence is empty
+ first = new ReadOnlySpan<byte>(a, 1, 0);
+
+ result = first.SequenceCompareTo<byte>(second);
+ Assert.True(result < 0);
+
+ result = second.SequenceCompareTo<byte>(first);
+ Assert.True(result > 0);
+ }
+
+ [Fact]
+ public static void SequenceCompareToWithSingleMismatch_Byte()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ var first = new byte[length];
+ var second = new byte[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = (byte)(i + 1);
+ }
+
+ second[mismatchIndex] = (byte)(second[mismatchIndex] + 1);
+
+ var firstSpan = new ReadOnlySpan<byte>(first);
+ var secondSpan = new ReadOnlySpan<byte>(second);
+ int result = firstSpan.SequenceCompareTo<byte>(secondSpan);
+ Assert.True(result < 0);
+
+ result = secondSpan.SequenceCompareTo<byte>(firstSpan);
+ Assert.True(result > 0);
+ }
+ }
+ }
+
+ [Fact]
+ public static void SequenceCompareToNoMatch_Byte()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ var first = new byte[length];
+ var second = new byte[length];
+
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = (byte)(i + 1);
+ second[i] = (byte)(byte.MaxValue - i);
+ }
+
+ var firstSpan = new ReadOnlySpan<byte>(first);
+ var secondSpan = new ReadOnlySpan<byte>(second);
+ int result = firstSpan.SequenceCompareTo<byte>(secondSpan);
+ Assert.True(result < 0);
+
+ result = secondSpan.SequenceCompareTo<byte>(firstSpan);
+ Assert.True(result > 0);
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoSequenceCompareToChecksGoOutOfRange_Byte()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new byte[length + 2];
+ first[0] = 99;
+ first[length + 1] = 99;
+
+ var second = new byte[length + 2];
+ second[0] = 100;
+ second[length + 1] = 100;
+
+ var span1 = new ReadOnlySpan<byte>(first, 1, length);
+ var span2 = new ReadOnlySpan<byte>(second, 1, length);
+ int result = span1.SequenceCompareTo<byte>(span2);
+ Assert.Equal(0, result);
+ }
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.char.cs b/src/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.char.cs
new file mode 100644
index 0000000000..2e176223f8
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.char.cs
@@ -0,0 +1,145 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class ReadOnlySpanTests
+ {
+ [Fact]
+ public static void ZeroLengthSequenceCompareTo_Char()
+ {
+ var a = new char[3];
+
+ var first = new ReadOnlySpan<char>(a, 1, 0);
+ var second = new ReadOnlySpan<char>(a, 2, 0);
+ int result = first.SequenceCompareTo<char>(second);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SameSpanSequenceCompareTo_Char()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a);
+ int result = span.SequenceCompareTo<char>(span);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SequenceCompareToArrayImplicit_Char()
+ {
+ char[] a = { '4', '5', '6' };
+ var first = new ReadOnlySpan<char>(a, 0, 3);
+ int result = first.SequenceCompareTo<char>(a);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SequenceCompareToArraySegmentImplicit_Char()
+ {
+ char[] src = { '1', '2', '3' };
+ char[] dst = { '5', '1', '2', '3', '9' };
+ var segment = new ArraySegment<char>(dst, 1, 3);
+
+ var first = new ReadOnlySpan<char>(src, 0, 3);
+ int result = first.SequenceCompareTo<char>(segment);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void LengthMismatchSequenceCompareTo_Char()
+ {
+ char[] a = { '4', '5', '6' };
+ var first = new ReadOnlySpan<char>(a, 0, 2);
+ var second = new ReadOnlySpan<char>(a, 0, 3);
+ int result = first.SequenceCompareTo<char>(second);
+ Assert.True(result < 0);
+
+ result = second.SequenceCompareTo<char>(first);
+ Assert.True(result > 0);
+
+ // one sequence is empty
+ first = new ReadOnlySpan<char>(a, 1, 0);
+
+ result = first.SequenceCompareTo<char>(second);
+ Assert.True(result < 0);
+
+ result = second.SequenceCompareTo<char>(first);
+ Assert.True(result > 0);
+ }
+
+ [Fact]
+ public static void SequenceCompareToWithSingleMismatch_Char()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ var first = new char[length];
+ var second = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = (char)(i + 1);
+ }
+
+ second[mismatchIndex] = (char)(second[mismatchIndex] + 1);
+
+ var firstSpan = new ReadOnlySpan<char>(first);
+ var secondSpan = new ReadOnlySpan<char>(second);
+ int result = firstSpan.SequenceCompareTo<char>(secondSpan);
+ Assert.True(result < 0);
+
+ result = secondSpan.SequenceCompareTo<char>(firstSpan);
+ Assert.True(result > 0);
+ }
+ }
+ }
+
+ [Fact]
+ public static void SequenceCompareToNoMatch_Char()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ var first = new char[length];
+ var second = new char[length];
+
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = (char)(i + 1);
+ second[i] = (char)(char.MaxValue - i);
+ }
+
+ var firstSpan = new ReadOnlySpan<char>(first);
+ var secondSpan = new ReadOnlySpan<char>(second);
+ int result = firstSpan.SequenceCompareTo<char>(secondSpan);
+ Assert.True(result < 0);
+
+ result = secondSpan.SequenceCompareTo<char>(firstSpan);
+ Assert.True(result > 0);
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoSequenceCompareToChecksGoOutOfRange_Char()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new char[length + 2];
+ first[0] = '8';
+ first[length + 1] = '8';
+
+ var second = new char[length + 2];
+ second[0] = '9';
+ second[length + 1] = '9';
+
+ var span1 = new ReadOnlySpan<char>(first, 1, length);
+ var span2 = new ReadOnlySpan<char>(second, 1, length);
+ int result = span1.SequenceCompareTo<char>(span2);
+ Assert.Equal(0, result);
+ }
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.int.cs b/src/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.int.cs
new file mode 100644
index 0000000000..743ba7bd8f
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.int.cs
@@ -0,0 +1,145 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class ReadOnlySpanTests
+ {
+ [Fact]
+ public static void ZeroLengthSequenceCompareTo_Int()
+ {
+ var a = new int[3];
+
+ var first = new ReadOnlySpan<int>(a, 1, 0);
+ var second = new ReadOnlySpan<int>(a, 2, 0);
+ int result = first.SequenceCompareTo<int>(second);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SameSpanSequenceCompareTo_Int()
+ {
+ int[] a = { 851227, 28052014, 429104168 };
+ var span = new ReadOnlySpan<int>(a);
+ int result = span.SequenceCompareTo<int>(span);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SequenceCompareToArrayImplicit_Int()
+ {
+ int[] a = { 851227, 28052014, 429104168 };
+ var first = new ReadOnlySpan<int>(a, 0, 3);
+ int result = first.SequenceCompareTo<int>(a);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SequenceCompareToArraySegmentImplicit_Int()
+ {
+ int[] src = { 851227, 28052014, 429104168 };
+ int[] dst = { 5, 851227, 28052014, 429104168, 10 };
+ var segment = new ArraySegment<int>(dst, 1, 3);
+
+ var first = new ReadOnlySpan<int>(src, 0, 3);
+ int result = first.SequenceCompareTo<int>(segment);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void LengthMismatchSequenceCompareTo_Int()
+ {
+ int[] a = { 851227, 28052014, 429104168 };
+ var first = new ReadOnlySpan<int>(a, 0, 2);
+ var second = new ReadOnlySpan<int>(a, 0, 3);
+ int result = first.SequenceCompareTo<int>(second);
+ Assert.True(result < 0);
+
+ result = second.SequenceCompareTo<int>(first);
+ Assert.True(result > 0);
+
+ // one sequence is empty
+ first = new ReadOnlySpan<int>(a, 1, 0);
+
+ result = first.SequenceCompareTo<int>(second);
+ Assert.True(result < 0);
+
+ result = second.SequenceCompareTo<int>(first);
+ Assert.True(result > 0);
+ }
+
+ [Fact]
+ public static void SequenceCompareToWithSingleMismatch_Int()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ var first = new int[length];
+ var second = new int[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = (int)(i + 1);
+ }
+
+ second[mismatchIndex] = (int)(second[mismatchIndex] + 1);
+
+ var firstSpan = new ReadOnlySpan<int>(first);
+ var secondSpan = new ReadOnlySpan<int>(second);
+ int result = firstSpan.SequenceCompareTo<int>(secondSpan);
+ Assert.True(result < 0);
+
+ result = secondSpan.SequenceCompareTo<int>(firstSpan);
+ Assert.True(result > 0);
+ }
+ }
+ }
+
+ [Fact]
+ public static void SequenceCompareToNoMatch_Int()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ var first = new int[length];
+ var second = new int[length];
+
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = (int)(i + 1);
+ second[i] = (int)(int.MaxValue - i);
+ }
+
+ var firstSpan = new ReadOnlySpan<int>(first);
+ var secondSpan = new ReadOnlySpan<int>(second);
+ int result = firstSpan.SequenceCompareTo<int>(secondSpan);
+ Assert.True(result < 0);
+
+ result = secondSpan.SequenceCompareTo<int>(firstSpan);
+ Assert.True(result > 0);
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoSequenceCompareToChecksGoOutOfRange_Int()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new int[length + 2];
+ first[0] = 99;
+ first[length + 1] = 99;
+
+ var second = new int[length + 2];
+ second[0] = 100;
+ second[length + 1] = 100;
+
+ var span1 = new ReadOnlySpan<int>(first, 1, length);
+ var span2 = new ReadOnlySpan<int>(second, 1, length);
+ int result = span1.SequenceCompareTo<int>(span2);
+ Assert.Equal(0, result);
+ }
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.long.cs b/src/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.long.cs
new file mode 100644
index 0000000000..a0c75d3dd5
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlySpan/SequenceCompareTo.long.cs
@@ -0,0 +1,145 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class ReadOnlySpanTests
+ {
+ [Fact]
+ public static void ZeroLengthSequenceCompareTo_Long()
+ {
+ var a = new long[3];
+
+ var first = new ReadOnlySpan<long>(a, 1, 0);
+ var second = new ReadOnlySpan<long>(a, 2, 0);
+ int result = first.SequenceCompareTo<long>(second);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SameSpanSequenceCompareTo_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ var span = new ReadOnlySpan<long>(a);
+ int result = span.SequenceCompareTo<long>(span);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SequenceCompareToArrayImplicit_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ var first = new ReadOnlySpan<long>(a, 0, 3);
+ int result = first.SequenceCompareTo<long>(a);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SequenceCompareToArraySegmentImplicit_Long()
+ {
+ long[] src = { 1989089123, 234523454235, 3123213231 };
+ long[] dst = { 5, 1989089123, 234523454235, 3123213231, 10 };
+ var segment = new ArraySegment<long>(dst, 1, 3);
+
+ var first = new ReadOnlySpan<long>(src, 0, 3);
+ int result = first.SequenceCompareTo<long>(segment);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void LengthMismatchSequenceCompareTo_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ var first = new ReadOnlySpan<long>(a, 0, 2);
+ var second = new ReadOnlySpan<long>(a, 0, 3);
+ int result = first.SequenceCompareTo<long>(second);
+ Assert.True(result < 0);
+
+ result = second.SequenceCompareTo<long>(first);
+ Assert.True(result > 0);
+
+ // one sequence is empty
+ first = new ReadOnlySpan<long>(a, 1, 0);
+
+ result = first.SequenceCompareTo<long>(second);
+ Assert.True(result < 0);
+
+ result = second.SequenceCompareTo<long>(first);
+ Assert.True(result > 0);
+ }
+
+ [Fact]
+ public static void SequenceCompareToWithSingleMismatch_Long()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ var first = new long[length];
+ var second = new long[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = (long)(i + 1);
+ }
+
+ second[mismatchIndex] = (long)(second[mismatchIndex] + 1);
+
+ var firstSpan = new ReadOnlySpan<long>(first);
+ var secondSpan = new ReadOnlySpan<long>(second);
+ int result = firstSpan.SequenceCompareTo<long>(secondSpan);
+ Assert.True(result < 0);
+
+ result = secondSpan.SequenceCompareTo<long>(firstSpan);
+ Assert.True(result > 0);
+ }
+ }
+ }
+
+ [Fact]
+ public static void SequenceCompareToNoMatch_Long()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ var first = new long[length];
+ var second = new long[length];
+
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = (long)(i + 1);
+ second[i] = (long)(long.MaxValue - i);
+ }
+
+ var firstSpan = new ReadOnlySpan<long>(first);
+ var secondSpan = new ReadOnlySpan<long>(second);
+ int result = firstSpan.SequenceCompareTo<long>(secondSpan);
+ Assert.True(result < 0);
+
+ result = secondSpan.SequenceCompareTo<long>(firstSpan);
+ Assert.True(result > 0);
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoSequenceCompareToChecksGoOutOfRange_Long()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new long[length + 2];
+ first[0] = 99;
+ first[length + 1] = 99;
+
+ var second = new long[length + 2];
+ second[0] = 100;
+ second[length + 1] = 100;
+
+ var span1 = new Span<long>(first, 1, length);
+ var span2 = new ReadOnlySpan<long>(second, 1, length);
+ int result = span1.SequenceCompareTo<long>(span2);
+ Assert.Equal(0, result);
+ }
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlySpan/SequenceEqual.long.cs b/src/System.Memory/tests/ReadOnlySpan/SequenceEqual.long.cs
new file mode 100644
index 0000000000..b276916e59
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlySpan/SequenceEqual.long.cs
@@ -0,0 +1,104 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class ReadOnlySpanTests
+ {
+ [Fact]
+ public static void ZeroLengthSequenceEqual_Long()
+ {
+ long[] a = new long[3];
+
+ ReadOnlySpan<long> first = new ReadOnlySpan<long>(a, 1, 0);
+ ReadOnlySpan<long> second = new ReadOnlySpan<long>(a, 2, 0);
+ bool b = first.SequenceEqual<long>(second);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void SameSpanSequenceEqual_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ ReadOnlySpan<long> span = new ReadOnlySpan<long>(a);
+ bool b = span.SequenceEqual<long>(span);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void SequenceEqualArrayImplicit_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ ReadOnlySpan<long> first = new ReadOnlySpan<long>(a, 0, 3);
+ bool b = first.SequenceEqual<long>(a);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void SequenceEqualArraySegmentImplicit_Long()
+ {
+ long[] src = { 1989089123, 234523454235, 3123213231 };
+ long[] dst = { 5, 1989089123, 234523454235, 3123213231, 10 };
+ ArraySegment<long> segment = new ArraySegment<long>(dst, 1, 3);
+
+ ReadOnlySpan<long> first = new ReadOnlySpan<long>(src, 0, 3);
+ bool b = first.SequenceEqual<long>(segment);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void LengthMismatchSequenceEqual_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ ReadOnlySpan<long> first = new ReadOnlySpan<long>(a, 0, 3);
+ ReadOnlySpan<long> second = new ReadOnlySpan<long>(a, 0, 2);
+ bool b = first.SequenceEqual<long>(second);
+ Assert.False(b);
+ }
+
+ [Fact]
+ public static void SequenceEqualNoMatch_Long()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ long[] first = new long[length];
+ long[] second = new long[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = (byte)(i + 1);
+ }
+
+ second[mismatchIndex] = (byte)(second[mismatchIndex] + 1);
+
+ ReadOnlySpan<long> firstSpan = new ReadOnlySpan<long>(first);
+ ReadOnlySpan<long> secondSpan = new ReadOnlySpan<long>(second);
+ bool b = firstSpan.SequenceEqual<long>(secondSpan);
+ Assert.False(b);
+ }
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoSequenceEqualChecksGoOutOfRange_Long()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ long[] first = new long[length + 2];
+ first[0] = 99;
+ first[length + 1] = 99;
+ long[] second = new long[length + 2];
+ second[0] = 100;
+ second[length + 1] = 100;
+ ReadOnlySpan<long> span1 = new ReadOnlySpan<long>(first, 1, length);
+ ReadOnlySpan<long> span2 = new ReadOnlySpan<long>(second, 1, length);
+ bool b = span1.SequenceEqual<long>(span2);
+ Assert.True(b);
+ }
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlySpan/StartsWith.StringComparison.cs b/src/System.Memory/tests/ReadOnlySpan/StartsWith.StringComparison.cs
new file mode 100644
index 0000000000..ba9df189fb
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlySpan/StartsWith.StringComparison.cs
@@ -0,0 +1,355 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Globalization;
+using System.Threading;
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class ReadOnlySpanTests
+ {
+ private const string SoftHyphen = "\u00AD";
+
+ [Fact]
+ public static void ZeroLengthStartsWith_StringComparison()
+ {
+ var a = new char[3];
+
+ var span = new ReadOnlySpan<char>(a);
+ var slice = new ReadOnlySpan<char>(a, 2, 0);
+ Assert.True(span.StartsWith(slice, StringComparison.Ordinal));
+
+ Assert.True(span.StartsWith(slice, StringComparison.CurrentCulture));
+ Assert.True(span.StartsWith(slice, StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(span.StartsWith(slice, StringComparison.InvariantCulture));
+ Assert.True(span.StartsWith(slice, StringComparison.InvariantCultureIgnoreCase));
+ Assert.True(span.StartsWith(slice, StringComparison.OrdinalIgnoreCase));
+
+ span = ReadOnlySpan<char>.Empty;
+ Assert.True(span.StartsWith(slice, StringComparison.Ordinal));
+
+ Assert.True(span.StartsWith(slice, StringComparison.CurrentCulture));
+ Assert.True(span.StartsWith(slice, StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(span.StartsWith(slice, StringComparison.InvariantCulture));
+ Assert.True(span.StartsWith(slice, StringComparison.InvariantCultureIgnoreCase));
+ Assert.True(span.StartsWith(slice, StringComparison.OrdinalIgnoreCase));
+ }
+
+ [Fact]
+ public static void SameSpanStartsWith_StringComparison()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a);
+ Assert.True(span.StartsWith(span, StringComparison.Ordinal));
+
+ Assert.True(span.StartsWith(span, StringComparison.CurrentCulture));
+ Assert.True(span.StartsWith(span, StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(span.StartsWith(span, StringComparison.InvariantCulture));
+ Assert.True(span.StartsWith(span, StringComparison.InvariantCultureIgnoreCase));
+ Assert.True(span.StartsWith(span, StringComparison.OrdinalIgnoreCase));
+ }
+
+ [Fact]
+ public static void LengthMismatchStartsWith_StringComparison()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a, 0, 2);
+ var slice = new ReadOnlySpan<char>(a, 0, 3);
+ Assert.False(span.StartsWith(slice, StringComparison.Ordinal));
+
+ Assert.False(span.StartsWith(slice, StringComparison.CurrentCulture));
+ Assert.False(span.StartsWith(slice, StringComparison.CurrentCultureIgnoreCase));
+ Assert.False(span.StartsWith(slice, StringComparison.InvariantCulture));
+ Assert.False(span.StartsWith(slice, StringComparison.InvariantCultureIgnoreCase));
+ Assert.False(span.StartsWith(slice, StringComparison.OrdinalIgnoreCase));
+ }
+
+ [Fact]
+ public static void StartsWithMatch_StringComparison()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a, 0, 3);
+ var slice = new ReadOnlySpan<char>(a, 0, 2);
+ Assert.True(span.StartsWith(slice, StringComparison.Ordinal));
+
+ Assert.True(span.StartsWith(slice, StringComparison.CurrentCulture));
+ Assert.True(span.StartsWith(slice, StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(span.StartsWith(slice, StringComparison.InvariantCulture));
+ Assert.True(span.StartsWith(slice, StringComparison.InvariantCultureIgnoreCase));
+ Assert.True(span.StartsWith(slice, StringComparison.OrdinalIgnoreCase));
+ }
+
+ [Fact]
+ public static void StartsWithMatchDifferentSpans_StringComparison()
+ {
+ char[] a = { '4', '5', '6', '7' };
+ char[] b = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a, 0, 3);
+ var slice = new ReadOnlySpan<char>(b, 0, 3);
+ Assert.True(span.StartsWith(slice, StringComparison.Ordinal));
+
+ Assert.True(span.StartsWith(slice, StringComparison.CurrentCulture));
+ Assert.True(span.StartsWith(slice, StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(span.StartsWith(slice, StringComparison.InvariantCulture));
+ Assert.True(span.StartsWith(slice, StringComparison.InvariantCultureIgnoreCase));
+ Assert.True(span.StartsWith(slice, StringComparison.OrdinalIgnoreCase));
+ }
+
+ [Fact]
+ public static void StartsWithNoMatch_StringComparison()
+ {
+ for (int length = 1; length < 150; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ var first = new char[length];
+ var second = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = (char)(i + 1);
+ }
+
+ second[mismatchIndex] = (char)(second[mismatchIndex] + 1);
+
+ var firstSpan = new ReadOnlySpan<char>(first);
+ var secondSpan = new ReadOnlySpan<char>(second);
+ Assert.False(firstSpan.StartsWith(secondSpan, StringComparison.Ordinal));
+
+ Assert.False(firstSpan.StartsWith(secondSpan, StringComparison.OrdinalIgnoreCase));
+
+ // Different behavior depending on OS
+ Assert.Equal(
+ firstSpan.ToString().StartsWith(secondSpan.ToString(), StringComparison.CurrentCulture),
+ firstSpan.StartsWith(secondSpan, StringComparison.CurrentCulture));
+ Assert.Equal(
+ firstSpan.ToString().StartsWith(secondSpan.ToString(), StringComparison.CurrentCultureIgnoreCase),
+ firstSpan.StartsWith(secondSpan, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(
+ firstSpan.ToString().StartsWith(secondSpan.ToString(), StringComparison.InvariantCulture),
+ firstSpan.StartsWith(secondSpan, StringComparison.InvariantCulture));
+ Assert.Equal(
+ firstSpan.ToString().StartsWith(secondSpan.ToString(), StringComparison.InvariantCultureIgnoreCase),
+ firstSpan.StartsWith(secondSpan, StringComparison.InvariantCultureIgnoreCase));
+ }
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoStartsWithChecksGoOutOfRange_StringComparison()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new char[length + 2];
+ first[0] = (char)99;
+ first[length + 1] = (char)99;
+ var second = new char[length + 2];
+ second[0] = (char)100;
+ second[length + 1] = (char)100;
+ var span1 = new ReadOnlySpan<char>(first, 1, length);
+ var span2 = new ReadOnlySpan<char>(second, 1, length);
+ Assert.True(span1.StartsWith(span2, StringComparison.Ordinal));
+
+ Assert.True(span1.StartsWith(span2, StringComparison.CurrentCulture));
+ Assert.True(span1.StartsWith(span2, StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(span1.StartsWith(span2, StringComparison.InvariantCulture));
+ Assert.True(span1.StartsWith(span2, StringComparison.InvariantCultureIgnoreCase));
+ Assert.True(span1.StartsWith(span2, StringComparison.OrdinalIgnoreCase));
+ }
+ }
+
+ [Fact]
+ public static void StartsWithUnknownComparisonType_StringComparison()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a);
+ TestHelpers.AssertThrows<ArgumentException, char>(span, (_span) => _span.StartsWith(_span, StringComparison.CurrentCulture - 1));
+ TestHelpers.AssertThrows<ArgumentException, char>(span, (_span) => _span.StartsWith(_span, StringComparison.OrdinalIgnoreCase + 1));
+ TestHelpers.AssertThrows<ArgumentException, char>(span, (_span) => _span.StartsWith(_span, (StringComparison)6));
+ }
+
+ [Fact]
+ public static void StartsWithMatchNonOrdinal_StringComparison()
+ {
+ ReadOnlySpan<char> span = new char[] { 'a', 'b', 'c', 'd' };
+ ReadOnlySpan<char> value = new char[] { 'a', 'B', 'c' };
+ Assert.False(span.StartsWith(value, StringComparison.Ordinal));
+ Assert.True(span.StartsWith(value, StringComparison.OrdinalIgnoreCase));
+
+ CultureInfo backupCulture = CultureInfo.CurrentCulture;
+
+ Thread.CurrentThread.CurrentCulture = new CultureInfo("el-GR");
+
+ span = new char[] { '\u03b1', '\u03b2', '\u03b3', '\u03b4' }; // αβγδ
+ value = new char[] { '\u03b1', '\u03b2', '\u03b3' }; // αβγ
+
+ Assert.True(span.StartsWith(value, StringComparison.CurrentCulture));
+ Assert.True(span.StartsWith(value, StringComparison.CurrentCultureIgnoreCase));
+
+ value = new char[] { '\u03b1', '\u0392', '\u03b3' }; // αΒγ
+ Assert.False(span.StartsWith(value, StringComparison.CurrentCulture));
+ Assert.True(span.StartsWith(value, StringComparison.CurrentCultureIgnoreCase));
+
+ Thread.CurrentThread.CurrentCulture = backupCulture;
+
+ span = new char[] { '\u0069', '\u00df', '\u0049', '\u03b4' }; // ißIδ
+ value = new char[] { '\u0069', '\u0073', '\u0073', '\u0049' }; // issI
+
+ Assert.False(span.StartsWith(value, StringComparison.Ordinal));
+ // Different behavior depending on OS - True on Windows, False on Unix
+ Assert.Equal(
+ span.ToString().StartsWith(value.ToString(), StringComparison.InvariantCulture),
+ span.StartsWith(value, StringComparison.InvariantCulture));
+ Assert.Equal(
+ span.ToString().StartsWith(value.ToString(), StringComparison.InvariantCultureIgnoreCase),
+ span.StartsWith(value, StringComparison.InvariantCultureIgnoreCase));
+
+ value = new char[] { '\u0049', '\u0073', '\u0073', '\u0049' }; // IssI
+ Assert.False(span.StartsWith(value, StringComparison.OrdinalIgnoreCase));
+ Assert.False(span.StartsWith(value, StringComparison.InvariantCulture));
+ // Different behavior depending on OS - True on Windows, False on Unix
+ Assert.Equal(
+ span.ToString().StartsWith(value.ToString(), StringComparison.InvariantCultureIgnoreCase),
+ span.StartsWith(value, StringComparison.InvariantCultureIgnoreCase));
+ }
+
+ [Fact]
+ public static void StartsWithNoMatchNonOrdinal_StringComparison()
+ {
+ ReadOnlySpan<char> span = new char[] { 'a', 'b', 'c', 'd' };
+ ReadOnlySpan<char> value = new char[] { 'a', 'D', 'c' };
+ Assert.False(span.StartsWith(value, StringComparison.Ordinal));
+ Assert.False(span.StartsWith(value, StringComparison.OrdinalIgnoreCase));
+
+ CultureInfo backupCulture = CultureInfo.CurrentCulture;
+
+ Thread.CurrentThread.CurrentCulture = new CultureInfo("el-GR");
+
+ span = new char[] { '\u03b1', '\u03b2', '\u03b3', '\u03b4' }; // αβγδ
+ value = new char[] { '\u03b1', '\u03b4', '\u03b3' }; // αδγ
+
+ Assert.False(span.StartsWith(value, StringComparison.CurrentCulture));
+ Assert.False(span.StartsWith(value, StringComparison.CurrentCultureIgnoreCase));
+
+ value = new char[] { '\u03b1', '\u0394', '\u03b3' }; // αΔγ
+ Assert.False(span.StartsWith(value, StringComparison.CurrentCulture));
+ Assert.False(span.StartsWith(value, StringComparison.CurrentCultureIgnoreCase));
+
+ Thread.CurrentThread.CurrentCulture = backupCulture;
+
+ span = new char[] { '\u0069', '\u00df', '\u0049', '\u03b4' }; // ißIδ
+ value = new char[] { '\u0069', '\u03b4', '\u03b4', '\u0049' }; // iδδI
+
+ Assert.False(span.StartsWith(value, StringComparison.Ordinal));
+ Assert.False(span.StartsWith(value, StringComparison.InvariantCulture));
+ Assert.False(span.StartsWith(value, StringComparison.InvariantCultureIgnoreCase));
+
+ value = new char[] { '\u0049', '\u03b4', '\u03b4', '\u0049' }; // IδδI
+ Assert.False(span.StartsWith(value, StringComparison.OrdinalIgnoreCase));
+ Assert.False(span.StartsWith(value, StringComparison.InvariantCulture));
+ Assert.False(span.StartsWith(value, StringComparison.InvariantCultureIgnoreCase));
+ }
+
+ [Theory]
+ // CurrentCulture
+ [InlineData("Hello", "Hel", StringComparison.CurrentCulture, true)]
+ [InlineData("Hello", "Hello", StringComparison.CurrentCulture, true)]
+ [InlineData("Hello", "", StringComparison.CurrentCulture, true)]
+ [InlineData("Hello", "HELLO", StringComparison.CurrentCulture, false)]
+ [InlineData("Hello", "Abc", StringComparison.CurrentCulture, false)]
+ [InlineData("Hello", SoftHyphen + "Hel", StringComparison.CurrentCulture, true)]
+ [InlineData("", "", StringComparison.CurrentCulture, true)]
+ [InlineData("", "hello", StringComparison.CurrentCulture, false)]
+ // CurrentCultureIgnoreCase
+ [InlineData("Hello", "Hel", StringComparison.CurrentCultureIgnoreCase, true)]
+ [InlineData("Hello", "Hello", StringComparison.CurrentCultureIgnoreCase, true)]
+ [InlineData("Hello", "", StringComparison.CurrentCultureIgnoreCase, true)]
+ [InlineData("Hello", "HEL", StringComparison.CurrentCultureIgnoreCase, true)]
+ [InlineData("Hello", "Abc", StringComparison.CurrentCultureIgnoreCase, false)]
+ [InlineData("Hello", SoftHyphen + "Hel", StringComparison.CurrentCultureIgnoreCase, true)]
+ [InlineData("", "", StringComparison.CurrentCultureIgnoreCase, true)]
+ [InlineData("", "hello", StringComparison.CurrentCultureIgnoreCase, false)]
+ // InvariantCulture
+ [InlineData("Hello", "Hel", StringComparison.InvariantCulture, true)]
+ [InlineData("Hello", "Hello", StringComparison.InvariantCulture, true)]
+ [InlineData("Hello", "", StringComparison.InvariantCulture, true)]
+ [InlineData("Hello", "HELLO", StringComparison.InvariantCulture, false)]
+ [InlineData("Hello", "Abc", StringComparison.InvariantCulture, false)]
+ [InlineData("Hello", SoftHyphen + "Hel", StringComparison.InvariantCulture, true)]
+ [InlineData("", "", StringComparison.InvariantCulture, true)]
+ [InlineData("", "hello", StringComparison.InvariantCulture, false)]
+ // InvariantCultureIgnoreCase
+ [InlineData("Hello", "Hel", StringComparison.InvariantCultureIgnoreCase, true)]
+ [InlineData("Hello", "Hello", StringComparison.InvariantCultureIgnoreCase, true)]
+ [InlineData("Hello", "", StringComparison.InvariantCultureIgnoreCase, true)]
+ [InlineData("Hello", "HEL", StringComparison.InvariantCultureIgnoreCase, true)]
+ [InlineData("Hello", "Abc", StringComparison.InvariantCultureIgnoreCase, false)]
+ [InlineData("Hello", SoftHyphen + "Hel", StringComparison.InvariantCultureIgnoreCase, true)]
+ [InlineData("", "", StringComparison.InvariantCultureIgnoreCase, true)]
+ [InlineData("", "hello", StringComparison.InvariantCultureIgnoreCase, false)]
+ // Ordinal
+ [InlineData("Hello", "H", StringComparison.Ordinal, true)]
+ [InlineData("Hello", "Hel", StringComparison.Ordinal, true)]
+ [InlineData("Hello", "Hello", StringComparison.Ordinal, true)]
+ [InlineData("Hello", "Hello Larger", StringComparison.Ordinal, false)]
+ [InlineData("Hello", "", StringComparison.Ordinal, true)]
+ [InlineData("Hello", "HEL", StringComparison.Ordinal, false)]
+ [InlineData("Hello", "Abc", StringComparison.Ordinal, false)]
+ [InlineData("Hello", SoftHyphen + "Hel", StringComparison.Ordinal, false)]
+ [InlineData("", "", StringComparison.Ordinal, true)]
+ [InlineData("", "hello", StringComparison.Ordinal, false)]
+ [InlineData("abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz", StringComparison.Ordinal, true)]
+ [InlineData("abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwx", StringComparison.Ordinal, true)]
+ [InlineData("abcdefghijklmnopqrstuvwxyz", "abcdefghijklm", StringComparison.Ordinal, true)]
+ [InlineData("abcdefghijklmnopqrstuvwxyz", "ab_defghijklmnopqrstu", StringComparison.Ordinal, false)]
+ [InlineData("abcdefghijklmnopqrstuvwxyz", "abcdef_hijklmn", StringComparison.Ordinal, false)]
+ [InlineData("abcdefghijklmnopqrstuvwxyz", "abcdefghij_lmn", StringComparison.Ordinal, false)]
+ [InlineData("abcdefghijklmnopqrstuvwxyz", "a", StringComparison.Ordinal, true)]
+ [InlineData("abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyza", StringComparison.Ordinal, false)]
+ // OrdinalIgnoreCase
+ [InlineData("Hello", "Hel", StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("Hello", "Hello", StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("Hello", "Hello Larger", StringComparison.OrdinalIgnoreCase, false)]
+ [InlineData("Hello", "", StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("Hello", "HEL", StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("Hello", "Abc", StringComparison.OrdinalIgnoreCase, false)]
+ [InlineData("Hello", SoftHyphen + "Hel", StringComparison.OrdinalIgnoreCase, false)]
+ [InlineData("", "", StringComparison.OrdinalIgnoreCase, true)]
+ [InlineData("", "hello", StringComparison.OrdinalIgnoreCase, false)]
+ public static void StartsWith(string s, string value, StringComparison comparisonType, bool expected)
+ {
+ Assert.Equal(expected, s.AsSpan().StartsWith(value.AsSpan(), comparisonType));
+ }
+
+ [Theory]
+ [InlineData(StringComparison.Ordinal)]
+ [InlineData(StringComparison.OrdinalIgnoreCase)]
+ public static void StartsWith_NullInStrings(StringComparison comparison)
+ {
+ Assert.False("\0test".AsSpan().StartsWith("test".AsSpan(), comparison));
+ Assert.False("te\0st".AsSpan().StartsWith("test".AsSpan(), comparison));
+ Assert.True("te\0st".AsSpan().StartsWith("te\0s".AsSpan(), comparison));
+ Assert.True("test\0".AsSpan().StartsWith("test".AsSpan(), comparison));
+ Assert.False("test".AsSpan().StartsWith("te\0".AsSpan(), comparison));
+ }
+
+ // NOTE: This is by design. Unix ignores the null characters (i.e. null characters have no weights for the string comparison).
+ // For desired behavior, use ordinal comparison instead of linguistic comparison.
+ // This is a known difference between Windows and Unix (https://github.com/dotnet/coreclr/issues/2051).
+ [Theory]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [InlineData(StringComparison.CurrentCulture)]
+ [InlineData(StringComparison.CurrentCultureIgnoreCase)]
+ [InlineData(StringComparison.InvariantCulture)]
+ [InlineData(StringComparison.InvariantCultureIgnoreCase)]
+ public static void StartsWith_NullInStrings_NonOrdinal(StringComparison comparison)
+ {
+ Assert.False("\0test".AsSpan().StartsWith("test".AsSpan(), comparison));
+ Assert.False("te\0st".AsSpan().StartsWith("test".AsSpan(), comparison));
+ Assert.True("te\0st".AsSpan().StartsWith("te\0s".AsSpan(), comparison));
+ Assert.True("test\0".AsSpan().StartsWith("test".AsSpan(), comparison));
+ Assert.False("test".AsSpan().StartsWith("te\0".AsSpan(), comparison));
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlySpan/StartsWith.char.cs b/src/System.Memory/tests/ReadOnlySpan/StartsWith.char.cs
new file mode 100644
index 0000000000..4b92c4960c
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlySpan/StartsWith.char.cs
@@ -0,0 +1,104 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class ReadOnlySpanTests
+ {
+ [Fact]
+ public static void ZeroLengthStartsWith_Char()
+ {
+ var a = new char[3];
+
+ var span = new ReadOnlySpan<char>(a);
+ var slice = new ReadOnlySpan<char>(a, 2, 0);
+ bool b = span.StartsWith<char>(slice);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void SameSpanStartsWith_Char()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a);
+ bool b = span.StartsWith<char>(span);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void LengthMismatchStartsWith_Char()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a, 0, 2);
+ var slice = new ReadOnlySpan<char>(a, 0, 3);
+ bool b = span.StartsWith<char>(slice);
+ Assert.False(b);
+ }
+
+ [Fact]
+ public static void StartsWithMatch_Char()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new ReadOnlySpan<char>(a, 0, 3);
+ var slice = new ReadOnlySpan<char>(a, 0, 2);
+ bool b = span.StartsWith<char>(slice);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void StartsWithMatchDifferentSpans_Char()
+ {
+ char[] a = { '4', '5', '6' };
+ char[] b = { '4', '5', '6' };
+ var span = new Span<char>(a, 0, 3);
+ var slice = new ReadOnlySpan<char>(b, 0, 3);
+ bool c = span.StartsWith<char>(slice);
+ Assert.True(c);
+ }
+
+ [Fact]
+ public static void StartsWithNoMatch_Char()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ var first = new char[length];
+ var second = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = (char)(i + 1);
+ }
+
+ second[mismatchIndex] = (char)(second[mismatchIndex] + 1);
+
+ var firstSpan = new ReadOnlySpan<char>(first);
+ var secondSpan = new ReadOnlySpan<char>(second);
+ bool b = firstSpan.StartsWith<char>(secondSpan);
+ Assert.False(b);
+ }
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoStartsWithChecksGoOutOfRange_Char()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new char[length + 2];
+ first[0] = '9';
+ first[length + 1] = '9';
+ var second = new char[length + 2];
+ second[0] = 'a';
+ second[length + 1] = 'a';
+ var span1 = new ReadOnlySpan<char>(first, 1, length);
+ var span2 = new ReadOnlySpan<char>(second, 1, length);
+ bool b = span1.StartsWith<char>(span2);
+ Assert.True(b);
+ }
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlySpan/StartsWith.long.cs b/src/System.Memory/tests/ReadOnlySpan/StartsWith.long.cs
new file mode 100644
index 0000000000..c7e2d9c3b9
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlySpan/StartsWith.long.cs
@@ -0,0 +1,104 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class ReadOnlySpanTests
+ {
+ [Fact]
+ public static void ZeroLengthStartsWith_Long()
+ {
+ var a = new long[3];
+
+ var span = new ReadOnlySpan<long>(a);
+ var slice = new ReadOnlySpan<long>(a, 2, 0);
+ bool b = span.StartsWith<long>(slice);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void SameSpanStartsWith_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ var span = new ReadOnlySpan<long>(a);
+ bool b = span.StartsWith<long>(span);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void LengthMismatchStartsWith_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ var span = new ReadOnlySpan<long>(a, 0, 2);
+ var slice = new ReadOnlySpan<long>(a, 0, 3);
+ bool b = span.StartsWith<long>(slice);
+ Assert.False(b);
+ }
+
+ [Fact]
+ public static void StartsWithMatch_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ var span = new ReadOnlySpan<long>(a, 0, 3);
+ var slice = new ReadOnlySpan<long>(a, 0, 2);
+ bool b = span.StartsWith<long>(slice);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void StartsWithMatchDifferentSpans_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ long[] b = { 488238291, 52498989823, 619890289890 };
+ var span = new ReadOnlySpan<long>(a, 0, 3);
+ var slice = new ReadOnlySpan<long>(b, 0, 3);
+ bool c = span.StartsWith<long>(slice);
+ Assert.True(c);
+ }
+
+ [Fact]
+ public static void StartsWithNoMatch_Long()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ var first = new long[length];
+ var second = new long[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = (long)(i + 1);
+ }
+
+ second[mismatchIndex] = (long)(second[mismatchIndex] + 1);
+
+ var firstSpan = new ReadOnlySpan<long>(first);
+ var secondSpan = new ReadOnlySpan<long>(second);
+ bool b = firstSpan.StartsWith<long>(secondSpan);
+ Assert.False(b);
+ }
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoStartsWithChecksGoOutOfRange_Long()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new long[length + 2];
+ first[0] = 99;
+ first[length + 1] = 99;
+ var second = new long[length + 2];
+ second[0] = 100;
+ second[length + 1] = 100;
+ var span1 = new ReadOnlySpan<long>(first, 1, length);
+ var span2 = new ReadOnlySpan<long>(second, 1, length);
+ bool b = span1.StartsWith<long>(span2);
+ Assert.True(b);
+ }
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlySpan/ToLower.cs b/src/System.Memory/tests/ReadOnlySpan/ToLower.cs
new file mode 100644
index 0000000000..d0882fd6a1
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlySpan/ToLower.cs
@@ -0,0 +1,310 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Globalization;
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class ReadOnlySpanTests
+ {
+ [Fact]
+ public static void ZeroLengthToLower()
+ {
+ char[] expectedSource = { 'a', 'B', 'c' };
+ char[] a = { 'a', 'B', 'c' };
+ var source = new ReadOnlySpan<char>(a, 2, 0);
+
+ var expectedDestination = new char[1] { 'a' };
+ Span<char> destination = new char[1] { 'a' };
+
+ Assert.Equal(source.Length, source.ToLower(destination, CultureInfo.CurrentCulture));
+ Assert.Equal(source.Length, source.ToLowerInvariant(destination));
+ Assert.Equal(expectedDestination, destination.ToArray());
+ Assert.Equal(expectedSource, a);
+
+ source = ReadOnlySpan<char>.Empty;
+ Assert.Equal(source.Length, source.ToLower(destination, CultureInfo.CurrentCulture));
+ Assert.Equal(source.Length, source.ToLowerInvariant(destination));
+ Assert.Equal(expectedDestination, destination.ToArray());
+ Assert.Equal(expectedSource, a);
+ }
+
+ [Fact]
+ public static void SameSpanToLower()
+ {
+ var expected = new char[3] { 'a', 'b', 'c' };
+ var a = new char[3] { 'a', 'B', 'c' };
+ {
+ ReadOnlySpan<char> source = a;
+ Span<char> destination = a;
+ Assert.Equal(source.Length, source.ToLower(destination, CultureInfo.CurrentCulture));
+ Assert.Equal(expected, destination.ToArray());
+ Assert.Equal(expected, source.ToArray());
+ }
+ {
+ ReadOnlySpan<char> source = a;
+ Span<char> destination = a;
+ Assert.Equal(source.Length, source.ToLowerInvariant(destination));
+ Assert.Equal(expected, destination.ToArray());
+ Assert.Equal(expected, source.ToArray());
+ }
+ }
+
+ [Fact]
+ public static void ToLowerOverlapping()
+ {
+ var expectedSource = new char[3] { 'B', 'c', 'b' };
+ var expectedDestination = new char[3] { 'b', 'c', 'b' };
+
+ {
+ char[] a = { 'a', 'B', 'c', 'B', 'c', 'B' };
+ var source = new ReadOnlySpan<char>(a, 1, 3);
+ var destination = new Span<char>(a, 3, 3);
+ Assert.Equal(source.Length, source.ToLower(destination, CultureInfo.CurrentCulture));
+ Assert.Equal(expectedDestination, destination.ToArray());
+ Assert.Equal(expectedSource, source.ToArray());
+ }
+ {
+ char[] a = { 'a', 'B', 'c', 'B', 'c', 'B' };
+ var source = new ReadOnlySpan<char>(a, 1, 3);
+ var destination = new Span<char>(a, 3, 3);
+ Assert.Equal(source.Length, source.ToLowerInvariant(destination));
+ Assert.Equal(expectedDestination, destination.ToArray());
+ Assert.Equal(expectedSource, source.ToArray());
+ }
+ }
+
+ [Fact]
+ public static void LengthMismatchToLower()
+ {
+ {
+ var expectedSource = new char[3] { 'a', 'B', 'c' };
+ ReadOnlySpan<char> source = new char[3] { 'a', 'B', 'c' };
+
+ var expectedDestination = new char[1] { 'a' };
+ Span<char> destination = new char[1] { 'a' };
+
+ Assert.Equal(-1, source.ToLower(destination, CultureInfo.CurrentCulture));
+ Assert.Equal(-1, source.ToLowerInvariant(destination));
+
+ Assert.Equal(expectedDestination, destination.ToArray());
+ Assert.Equal(expectedSource, source.ToArray());
+ }
+
+ {
+ var expectedSource = new char[3] { 'a', 'B', 'c' };
+ ReadOnlySpan<char> source = new char[3] { 'a', 'B', 'c' };
+
+ var expectedDestination = new char[4] { 'a', 'b', 'c', 'D' };
+ Span<char> destination = new char[4] { 'x', 'Y', 'z', 'D' };
+
+ Assert.Equal(source.Length, source.ToLower(destination, CultureInfo.CurrentCulture));
+ Assert.Equal(source.Length, source.ToLowerInvariant(destination));
+
+ Assert.Equal(expectedDestination, destination.ToArray());
+ Assert.Equal(expectedSource, source.ToArray());
+ }
+ }
+
+ [Fact]
+ public static void ToLower()
+ {
+ var expectedSource = new char[3] { 'a', 'B', 'c' };
+ var expectedDestination = new char[3] { 'a', 'b', 'c' };
+
+ {
+ ReadOnlySpan<char> source = new char[3] { 'a', 'B', 'c' };
+ Span<char> destination = new char[3] { 'x', 'Y', 'z' };
+
+ Assert.Equal(source.Length, source.ToLower(destination, CultureInfo.CurrentCulture));
+ Assert.Equal(expectedDestination, destination.ToArray());
+ Assert.Equal(expectedSource, source.ToArray());
+ }
+
+ {
+ ReadOnlySpan<char> source = new char[3] { 'a', 'B', 'c' };
+ Span<char> destination = new char[3] { 'x', 'Y', 'z' };
+
+ Assert.Equal(source.Length, source.ToLowerInvariant(destination));
+ Assert.Equal(expectedDestination, destination.ToArray());
+ Assert.Equal(expectedSource, source.ToArray());
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoToLowerChecksGoOutOfRange()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new char[length + 2];
+ var second = new char[length + 2];
+
+ for (int i = 0; i < first.Length; i++)
+ {
+ first[i] = 'A';
+ second[i] = 'B';
+ }
+
+ first[0] = 'Z';
+ first[length + 1] = 'Z';
+
+ second[0] = 'Y';
+ second[length + 1] = 'Y';
+
+ var expectedSource = new char[length];
+ var expectedDestination = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ expectedSource[i] = 'A';
+ expectedDestination[i] = 'a';
+ }
+
+ var source = new ReadOnlySpan<char>(first, 1, length);
+ var destination = new Span<char>(second, 1, length);
+ Assert.Equal(source.Length, source.ToLower(destination, CultureInfo.CurrentCulture));
+ Assert.Equal(source.Length, source.ToLowerInvariant(destination));
+ Assert.Equal(expectedDestination, destination.ToArray());
+ Assert.Equal(expectedSource, source.ToArray());
+
+ Assert.Equal('Z', first[0]);
+ Assert.Equal('Z', first[length + 1]);
+ Assert.Equal('Y', second[0]);
+ Assert.Equal('Y', second[length + 1]);
+ }
+ }
+
+ [Fact]
+ public static void ToLowerNullCulture()
+ {
+ ReadOnlySpan<char> source = new char[3] { 'a', 'B', 'c' };
+ Span<char> destination = new char[3] { 'a', 'B', 'c' };
+
+ try
+ {
+ source.ToLower(destination, null);
+ Assert.False(true, "Expected exception: " + typeof(ArgumentNullException).GetType());
+ }
+ catch (ArgumentNullException)
+ {
+ }
+ catch (Exception wrongException)
+ {
+ Assert.False(true, "Wrong exception thrown: Expected " + typeof(ArgumentNullException).GetType() + ": Actual: " + wrongException.GetType());
+ }
+ }
+
+ [Theory]
+ [InlineData("HELLO", "hello")]
+ [InlineData("hello", "hello")]
+ [InlineData("", "")]
+ public static void ToLower(string s, string expected)
+ {
+ ReadOnlySpan<char> source = s.AsSpan();
+ Span<char> destination = new char[source.Length];
+ Assert.Equal(source.Length, source.ToLower(destination, CultureInfo.CurrentCulture));
+ Assert.Equal(expected, destination.ToString());
+ }
+
+ private static IEnumerable<object[]> ToLower_Culture_TestData()
+ {
+ yield return new object[] { "H\u0049 World", "h\u0131 world", new CultureInfo("tr-TR") };
+ yield return new object[] { "H\u0130 World", "h\u0069 world", new CultureInfo("tr-TR") };
+ yield return new object[] { "H\u0131 World", "h\u0131 world", new CultureInfo("tr-TR") };
+
+ yield return new object[] { "H\u0049 World", "h\u0069 world", new CultureInfo("en-US") };
+ yield return new object[] { "H\u0130 World", "h\u0069 world", new CultureInfo("en-US") };
+ yield return new object[] { "H\u0131 World", "h\u0131 world", new CultureInfo("en-US") };
+
+ yield return new object[] { "H\u0049 World", "h\u0069 world", CultureInfo.InvariantCulture };
+ yield return new object[] { "H\u0130 World", "h\u0130 world", CultureInfo.InvariantCulture };
+ yield return new object[] { "H\u0131 World", "h\u0131 world", CultureInfo.InvariantCulture };
+ }
+
+ [Theory]
+ [MemberData(nameof(ToLower_Culture_TestData))]
+ public static void Test_ToLower_Culture(string actual, string expected, CultureInfo culture)
+ {
+ ReadOnlySpan<char> source = actual.AsSpan();
+ Span<char> destination = new char[source.Length];
+ Assert.Equal(source.Length, source.ToLower(destination, culture));
+ Assert.Equal(expected, destination.ToString());
+ }
+
+ [Theory]
+ [InlineData("HELLO", "hello")]
+ [InlineData("hello", "hello")]
+ [InlineData("", "")]
+ public static void ToLowerInvariant(string s, string expected)
+ {
+ ReadOnlySpan<char> source = s.AsSpan();
+ Span<char> destination = new char[source.Length];
+ Assert.Equal(source.Length, source.ToLowerInvariant(destination));
+ Assert.Equal(expected, destination.ToString());
+ }
+
+ [Fact]
+ public static void ToLowerToUpperInvariant_ASCII()
+ {
+ var asciiChars = new char[128];
+ var asciiCharsUpper = new char[128];
+ var asciiCharsLower = new char[128];
+
+ for (int i = 0; i < asciiChars.Length; i++)
+ {
+ char c = (char)i;
+ asciiChars[i] = c;
+
+ // Purposefully avoiding char.ToUpper/ToLower here so as not to use the same thing we're testing.
+ asciiCharsLower[i] = (c >= 'A' && c <= 'Z') ? (char)(c - 'A' + 'a') : c;
+ asciiCharsUpper[i] = (c >= 'a' && c <= 'z') ? (char)(c - 'a' + 'A') : c;
+ }
+
+ ReadOnlySpan<char> source = asciiChars;
+ var ascii = new string(asciiChars);
+ Span<char> destinationLower = new char[source.Length];
+ Span<char> destinationUpper = new char[source.Length];
+
+ Assert.Equal(source.Length, source.ToLowerInvariant(destinationLower));
+ Assert.Equal(source.Length, source.ToUpperInvariant(destinationUpper));
+
+ Assert.Equal(ascii.ToLowerInvariant(), destinationLower.ToString());
+ Assert.Equal(ascii.ToUpperInvariant(), destinationUpper.ToString());
+
+ Assert.Equal(ascii, source.ToString());
+ }
+
+ public static IEnumerable<object[]> UpperLowerCasing_TestData()
+ {
+ //lower, upper, Culture
+ yield return new object[] { "abcd", "ABCD", "en-US" };
+ yield return new object[] { "latin i", "LATIN I", "en-US" };
+ yield return new object[] { "turky \u0131", "TURKY I", "tr-TR" };
+ yield return new object[] { "turky i", "TURKY \u0130", "tr-TR" };
+ yield return new object[] { "\ud801\udc29", PlatformDetection.IsWindows7 ? "\ud801\udc29" : "\ud801\udc01", "en-US" };
+ }
+
+ [Theory]
+ [MemberData(nameof(UpperLowerCasing_TestData))]
+ public static void CasingTest(string lowerForm, string upperForm, string cultureName)
+ {
+ CultureInfo ci = CultureInfo.GetCultureInfo(cultureName);
+
+ ReadOnlySpan<char> sourceLower = lowerForm.AsSpan();
+ ReadOnlySpan<char> sourceUpper = upperForm.AsSpan();
+ Span<char> destinationLower = new char[sourceUpper.Length];
+ Span<char> destinationUpper = new char[sourceLower.Length];
+
+ Assert.Equal(sourceUpper.Length, sourceUpper.ToLower(destinationLower, ci));
+ Assert.Equal(sourceLower.Length, sourceLower.ToUpper(destinationUpper, ci));
+
+ Assert.Equal(upperForm.ToLower(ci), destinationLower.ToString());
+ Assert.Equal(lowerForm.ToUpper(ci), destinationUpper.ToString());
+
+ Assert.Equal(lowerForm, sourceLower.ToString());
+ Assert.Equal(upperForm, sourceUpper.ToString());
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlySpan/ToString.cs b/src/System.Memory/tests/ReadOnlySpan/ToString.cs
new file mode 100644
index 0000000000..90428084b5
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlySpan/ToString.cs
@@ -0,0 +1,107 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class ReadOnlySpanTests
+ {
+ [Fact]
+ public static void ToStringInt()
+ {
+ int[] a = { 91, 92, 93 };
+ var span = new ReadOnlySpan<int>(a);
+ Assert.Equal("System.ReadOnlySpan<Int32>[3]", span.ToString());
+ }
+
+ [Fact]
+ public static void ToStringInt_Empty()
+ {
+ var span = new ReadOnlySpan<int>();
+ Assert.Equal("System.ReadOnlySpan<Int32>[0]", span.ToString());
+ }
+
+ [Fact]
+ public static void ToStringChar()
+ {
+ char[] a = { 'a', 'b', 'c' };
+ var span = new ReadOnlySpan<char>(a);
+ Assert.Equal("abc", span.ToString());
+
+ string testString = "abcdefg";
+ ReadOnlySpan<char> readOnlySpan = testString.AsSpan();
+ Assert.Equal(testString, readOnlySpan.ToString());
+ }
+
+ [Fact]
+ public static void ToStringChar_Empty()
+ {
+ var span = new ReadOnlySpan<char>();
+ Assert.Equal("", span.ToString());
+ }
+
+ [Fact]
+ public static void ToStringForSpanOfString()
+ {
+ string[] a = { "a", "b", "c" };
+ var span = new ReadOnlySpan<string>(a);
+ Assert.Equal("System.ReadOnlySpan<String>[3]", span.ToString());
+ }
+
+ [Fact]
+ public static void ToStringFromString()
+ {
+ string orig = "hello world";
+ Assert.Equal(orig, orig.AsSpan().ToString());
+ Assert.Equal(orig.Substring(0, 5), orig.AsSpan(0, 5).ToString());
+ Assert.Equal(orig.Substring(5), orig.AsSpan(5).ToString());
+ Assert.Equal(orig.Substring(1, 3), orig.AsSpan(1, 3).ToString());
+ }
+
+ [Fact]
+ public static void ToStringSpanOverSubstringDoesNotReturnOriginal()
+ {
+ string original = TestHelpers.BuildString(10, 42);
+ ReadOnlySpan<char> span = original.AsSpan();
+
+ string returnedString = span.ToString();
+ string returnedStringUsingSlice = span.Slice(0, original.Length).ToString();
+
+ string subString1 = span.Slice(1).ToString();
+ string subString2 = span.Slice(0, 2).ToString();
+ string subString3 = span.Slice(1, 2).ToString();
+
+ Assert.Equal(original, returnedString);
+ Assert.Equal(original, returnedStringUsingSlice);
+
+ Assert.Equal(original.Substring(1), subString1);
+ Assert.Equal(original.Substring(0, 2), subString2);
+ Assert.Equal(original.Substring(1, 2), subString3);
+
+ Assert.NotSame(original, subString1);
+ Assert.NotSame(original, subString2);
+ Assert.NotSame(original, subString3);
+
+ Assert.NotSame(subString1, subString2);
+ Assert.NotSame(subString1, subString3);
+ Assert.NotSame(subString2, subString3);
+ }
+
+ // This test is only relevant for portable span
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework, "Optimization only applies to portable span.")]
+ [Fact]
+ public static void ToStringSpanOverFullStringReturnsOriginal()
+ {
+ string original = TestHelpers.BuildString(10, 42);
+ ReadOnlySpan<char> span = original.AsSpan();
+
+ string returnedString = span.ToString();
+ string returnedStringUsingSlice = span.Slice(0, original.Length).ToString();
+
+ Assert.Same(original, returnedString);
+ Assert.Same(original, returnedStringUsingSlice);
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlySpan/ToUpper.cs b/src/System.Memory/tests/ReadOnlySpan/ToUpper.cs
new file mode 100644
index 0000000000..0da84cb94f
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlySpan/ToUpper.cs
@@ -0,0 +1,329 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Globalization;
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class ReadOnlySpanTests
+ {
+ [Fact]
+ public static void ZeroLengthToUpper()
+ {
+ char[] expectedSource = { 'a', 'B', 'c' };
+ char[] a = { 'a', 'B', 'c' };
+ var source = new ReadOnlySpan<char>(a, 2, 0);
+
+ var expectedDestination = new char[1] { 'a' };
+ Span<char> destination = new char[1] { 'a' };
+
+ Assert.Equal(source.Length, source.ToUpper(destination, CultureInfo.CurrentCulture));
+ Assert.Equal(source.Length, source.ToUpperInvariant(destination));
+ Assert.Equal(expectedDestination, destination.ToArray());
+ Assert.Equal(expectedSource, a);
+
+ source = ReadOnlySpan<char>.Empty;
+ Assert.Equal(source.Length, source.ToUpper(destination, CultureInfo.CurrentCulture));
+ Assert.Equal(source.Length, source.ToUpperInvariant(destination));
+ Assert.Equal(expectedDestination, destination.ToArray());
+ Assert.Equal(expectedSource, a);
+ }
+
+ [Fact]
+ public static void SameSpanToUpper()
+ {
+ var expected = new char[3] { 'A', 'B', 'C' };
+ var a = new char[3] { 'a', 'B', 'c' };
+ {
+ ReadOnlySpan<char> source = a;
+ Span<char> destination = a;
+ Assert.Equal(source.Length, source.ToUpper(destination, CultureInfo.CurrentCulture));
+ Assert.Equal(expected, destination.ToArray());
+ Assert.Equal(expected, source.ToArray());
+ }
+ {
+ ReadOnlySpan<char> source = a;
+ Span<char> destination = a;
+ Assert.Equal(source.Length, source.ToUpperInvariant(destination));
+ Assert.Equal(expected, destination.ToArray());
+ Assert.Equal(expected, source.ToArray());
+ }
+ }
+
+ [Fact]
+ public static void ToUpperOverlapping()
+ {
+ var expectedSource = new char[3] { 'b', 'C', 'B' };
+ var expectedDestination = new char[3] { 'B', 'C', 'B' };
+
+ {
+ char[] a = { 'a', 'b', 'C', 'b', 'C', 'b' };
+ var source = new ReadOnlySpan<char>(a, 1, 3);
+ var destination = new Span<char>(a, 3, 3);
+ Assert.Equal(source.Length, source.ToUpper(destination, CultureInfo.CurrentCulture));
+ Assert.Equal(expectedDestination, destination.ToArray());
+ Assert.Equal(expectedSource, source.ToArray());
+ }
+ {
+ char[] a = { 'a', 'b', 'C', 'b', 'C', 'b' };
+ var source = new ReadOnlySpan<char>(a, 1, 3);
+ var destination = new Span<char>(a, 3, 3);
+ Assert.Equal(source.Length, source.ToUpperInvariant(destination));
+ Assert.Equal(expectedDestination, destination.ToArray());
+ Assert.Equal(expectedSource, source.ToArray());
+ }
+ }
+
+ [Fact]
+ public static void LengthMismatchToUpper()
+ {
+ {
+ var expectedSource = new char[3] { 'a', 'B', 'c' };
+ ReadOnlySpan<char> source = new char[3] { 'a', 'B', 'c' };
+
+ var expectedDestination = new char[1] { 'a' };
+ Span<char> destination = new char[1] { 'a' };
+
+ Assert.Equal(-1, source.ToUpper(destination, CultureInfo.CurrentCulture));
+ Assert.Equal(-1, source.ToUpperInvariant(destination));
+
+ Assert.Equal(expectedDestination, destination.ToArray());
+ Assert.Equal(expectedSource, source.ToArray());
+ }
+
+ {
+ var expectedSource = new char[3] { 'a', 'B', 'c' };
+ ReadOnlySpan<char> source = new char[3] { 'a', 'B', 'c' };
+
+ var expectedDestination = new char[4] { 'A', 'B', 'C', 'd' };
+ Span<char> destination = new char[4] { 'x', 'Y', 'z', 'd' };
+
+ Assert.Equal(source.Length, source.ToUpper(destination, CultureInfo.CurrentCulture));
+ Assert.Equal(source.Length, source.ToUpperInvariant(destination));
+
+ Assert.Equal(expectedDestination, destination.ToArray());
+ Assert.Equal(expectedSource, source.ToArray());
+ }
+ }
+
+ [Fact]
+ public static void ToUpper()
+ {
+ var expectedSource = new char[3] { 'a', 'B', 'c' };
+ var expectedDestination = new char[3] { 'A', 'B', 'C' };
+
+ {
+ ReadOnlySpan<char> source = new char[3] { 'a', 'B', 'c' };
+ Span<char> destination = new char[3] { 'x', 'Y', 'z' };
+
+ Assert.Equal(source.Length, source.ToUpper(destination, CultureInfo.CurrentCulture));
+ Assert.Equal(expectedDestination, destination.ToArray());
+ Assert.Equal(expectedSource, source.ToArray());
+ }
+
+ {
+ ReadOnlySpan<char> source = new char[3] { 'a', 'B', 'c' };
+ Span<char> destination = new char[3] { 'x', 'Y', 'z' };
+
+ Assert.Equal(source.Length, source.ToUpperInvariant(destination));
+ Assert.Equal(expectedDestination, destination.ToArray());
+ Assert.Equal(expectedSource, source.ToArray());
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoToUpperChecksGoOutOfRange()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new char[length + 2];
+ var second = new char[length + 2];
+
+ for (int i = 0; i < first.Length; i++)
+ {
+ first[i] = 'a';
+ second[i] = 'b';
+ }
+
+ first[0] = 'z';
+ first[length + 1] = 'z';
+
+ second[0] = 'y';
+ second[length + 1] = 'y';
+
+ var expectedSource = new char[length];
+ var expectedDestination = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ expectedSource[i] = 'a';
+ expectedDestination[i] = 'A';
+ }
+
+ var source = new ReadOnlySpan<char>(first, 1, length);
+ var destination = new Span<char>(second, 1, length);
+ Assert.Equal(source.Length, source.ToUpper(destination, CultureInfo.CurrentCulture));
+ Assert.Equal(source.Length, source.ToUpperInvariant(destination));
+ Assert.Equal(expectedDestination, destination.ToArray());
+ Assert.Equal(expectedSource, source.ToArray());
+
+ Assert.Equal('z', first[0]);
+ Assert.Equal('z', first[length + 1]);
+ Assert.Equal('y', second[0]);
+ Assert.Equal('y', second[length + 1]);
+ }
+ }
+
+ [Fact]
+ public static void ToUpperNullCulture()
+ {
+ ReadOnlySpan<char> source = new char[3] { 'a', 'B', 'c' };
+ Span<char> destination = new char[3] { 'a', 'B', 'c' };
+
+ try
+ {
+ source.ToUpper(destination, null);
+ Assert.False(true, "Expected exception: " + typeof(ArgumentNullException).GetType());
+ }
+ catch (ArgumentNullException)
+ {
+ }
+ catch (Exception wrongException)
+ {
+ Assert.False(true, "Wrong exception thrown: Expected " + typeof(ArgumentNullException).GetType() + ": Actual: " + wrongException.GetType());
+ }
+ }
+
+ [Theory]
+ [InlineData("hello", "HELLO")]
+ [InlineData("HELLO", "HELLO")]
+ [InlineData("", "")]
+ public static void ToUpper(string s, string expected)
+ {
+ ReadOnlySpan<char> source = s.AsSpan();
+ Span<char> destination = new char[source.Length];
+ Assert.Equal(source.Length, source.ToUpper(destination, CultureInfo.CurrentCulture));
+ Assert.Equal(expected, destination.ToString());
+ }
+
+ private static IEnumerable<object[]> ToUpper_Culture_TestData()
+ {
+ yield return new object[] { "h\u0069 world", "H\u0130 WORLD", new CultureInfo("tr-TR") };
+ yield return new object[] { "h\u0130 world", "H\u0130 WORLD", new CultureInfo("tr-TR") };
+ yield return new object[] { "h\u0131 world", "H\u0049 WORLD", new CultureInfo("tr-TR") };
+
+ yield return new object[] { "h\u0069 world", "H\u0049 WORLD", new CultureInfo("en-US") };
+ yield return new object[] { "h\u0130 world", "H\u0130 WORLD", new CultureInfo("en-US") };
+ yield return new object[] { "h\u0131 world", "H\u0049 WORLD", new CultureInfo("en-US") };
+
+ yield return new object[] { "h\u0069 world", "H\u0049 WORLD", CultureInfo.InvariantCulture };
+ yield return new object[] { "h\u0130 world", "H\u0130 WORLD", CultureInfo.InvariantCulture };
+ yield return new object[] { "h\u0131 world", "H\u0131 WORLD", CultureInfo.InvariantCulture };
+ }
+
+ [Theory]
+ [MemberData(nameof(ToUpper_Culture_TestData))]
+ public static void Test_ToUpper_Culture(string actual, string expected, CultureInfo culture)
+ {
+ ReadOnlySpan<char> source = actual.AsSpan();
+ Span<char> destination = new char[source.Length];
+ Assert.Equal(source.Length, source.ToUpper(destination, culture));
+ Assert.Equal(expected, destination.ToString());
+ }
+
+ [Fact]
+ public static void ToUpper_TurkishI_TurkishCulture()
+ {
+ CultureInfo culture = new CultureInfo("tr-TR");
+
+ string s = "H\u0069 World";
+ string expected = "H\u0130 WORLD";
+ ReadOnlySpan<char> source = s.AsSpan();
+ Span<char> destination = new char[source.Length];
+ Assert.Equal(source.Length, source.ToUpper(destination, culture));
+ Assert.Equal(expected, destination.ToString());
+
+ s = "H\u0130 World";
+ expected = "H\u0130 WORLD";
+ source = s.AsSpan();
+ destination = new char[source.Length];
+ Assert.Equal(source.Length, source.ToUpper(destination, culture));
+ Assert.Equal(expected, destination.ToString());
+
+ s = "H\u0131 World";
+ expected = "H\u0049 WORLD";
+ source = s.AsSpan();
+ destination = new char[source.Length];
+ Assert.Equal(source.Length, source.ToUpper(destination, culture));
+ Assert.Equal(expected, destination.ToString());
+ }
+
+ [Fact]
+ public static void ToUpper_TurkishI_EnglishUSCulture()
+ {
+ CultureInfo culture = new CultureInfo("en-US");
+
+ string s = "H\u0069 World";
+ string expected = "H\u0049 WORLD";
+ ReadOnlySpan<char> source = s.AsSpan();
+ Span<char> destination = new char[source.Length];
+ Assert.Equal(source.Length, source.ToUpper(destination, culture));
+ Assert.Equal(expected, destination.ToString());
+
+ s = "H\u0130 World";
+ expected = "H\u0130 WORLD";
+ source = s.AsSpan();
+ destination = new char[source.Length];
+ Assert.Equal(source.Length, source.ToUpper(destination, culture));
+ Assert.Equal(expected, destination.ToString());
+
+ s = "H\u0131 World";
+ expected = "H\u0049 WORLD";
+ source = s.AsSpan();
+ destination = new char[source.Length];
+ Assert.Equal(source.Length, source.ToUpper(destination, culture));
+ Assert.Equal(expected, destination.ToString());
+ }
+
+ [Fact]
+ public static void ToUpper_TurkishI_InvariantCulture()
+ {
+ CultureInfo culture = CultureInfo.InvariantCulture;
+
+ string s = "H\u0069 World";
+ string expected = "H\u0049 WORLD";
+ ReadOnlySpan<char> source = s.AsSpan();
+ Span<char> destination = new char[source.Length];
+ Assert.Equal(source.Length, source.ToUpper(destination, culture));
+ Assert.Equal(expected, destination.ToString());
+
+ s = "H\u0130 World";
+ expected = "H\u0130 WORLD";
+ source = s.AsSpan();
+ destination = new char[source.Length];
+ Assert.Equal(source.Length, source.ToUpper(destination, culture));
+ Assert.Equal(expected, destination.ToString());
+
+ s = "H\u0131 World";
+ expected = "H\u0131 WORLD";
+ source = s.AsSpan();
+ destination = new char[source.Length];
+ Assert.Equal(source.Length, source.ToUpper(destination, culture));
+ Assert.Equal(expected, destination.ToString());
+ }
+
+ [Theory]
+ [InlineData("hello", "HELLO")]
+ [InlineData("HELLO", "HELLO")]
+ [InlineData("", "")]
+ public static void ToUpperInvariant(string s, string expected)
+ {
+ ReadOnlySpan<char> source = s.AsSpan();
+ Span<char> destination = new char[source.Length];
+ Assert.Equal(source.Length, source.ToUpperInvariant(destination));
+ Assert.Equal(expected, destination.ToString());
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlySpan/TrimAnyCharacter.cs b/src/System.Memory/tests/ReadOnlySpan/TrimAnyCharacter.cs
new file mode 100644
index 0000000000..c1975616a0
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlySpan/TrimAnyCharacter.cs
@@ -0,0 +1,169 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class ReadOnlySpanTests
+ {
+ [Fact]
+ public static void ZeroLengthTrimCharacter()
+ {
+ ReadOnlySpan<char> span = new ReadOnlySpan<char>(Array.Empty<char>());
+ Assert.True(span.SequenceEqual(span.Trim('a')));
+ Assert.True(span.SequenceEqual(span.TrimStart('a')));
+ Assert.True(span.SequenceEqual(span.TrimEnd('a')));
+ }
+
+ [Fact]
+ public static void NoTrimCharacter()
+ {
+ for (int length = 0; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 'b';
+ }
+ ReadOnlySpan<char> span = new ReadOnlySpan<char>(a);
+ Assert.True(span.SequenceEqual(span.Trim('a')));
+ Assert.True(span.SequenceEqual(span.TrimStart('a')));
+ Assert.True(span.SequenceEqual(span.TrimEnd('a')));
+ }
+ }
+
+ [Fact]
+ public static void OnlyTrimCharacter()
+ {
+ for (int length = 0; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 'a';
+ }
+ ReadOnlySpan<char> span = new ReadOnlySpan<char>(a);
+ Assert.True(ReadOnlySpan<char>.Empty.SequenceEqual(span.Trim('a')));
+ Assert.True(ReadOnlySpan<char>.Empty.SequenceEqual(span.TrimStart('a')));
+ Assert.True(ReadOnlySpan<char>.Empty.SequenceEqual(span.TrimEnd('a')));
+ }
+ }
+
+ [Fact]
+ public static void TrimCharacterAtStart()
+ {
+ for (int length = 2; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 'b';
+ }
+ a[0] = 'a';
+ ReadOnlySpan<char> span = new ReadOnlySpan<char>(a);
+ Assert.True(span.Slice(1).SequenceEqual(span.Trim('a')));
+ Assert.True(span.Slice(1).SequenceEqual(span.TrimStart('a')));
+ Assert.True(span.SequenceEqual(span.TrimEnd('a')));
+ }
+ }
+
+ [Fact]
+ public static void TrimCharacterAtEnd()
+ {
+ for (int length = 2; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 'b';
+ }
+ a[length - 1] = 'a';
+ ReadOnlySpan<char> span = new ReadOnlySpan<char>(a);
+ Assert.True(span.Slice(0, length - 1).SequenceEqual(span.Trim('a')));
+ Assert.True(span.SequenceEqual(span.TrimStart('a')));
+ Assert.True(span.Slice(0, length - 1).SequenceEqual(span.TrimEnd('a')));
+ }
+ }
+
+ [Fact]
+ public static void TrimCharacterAtStartAndEnd()
+ {
+ for (int length = 3; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 'b';
+ }
+ a[0] = 'a';
+ a[length - 1] = 'a';
+ ReadOnlySpan<char> span = new ReadOnlySpan<char>(a);
+ Assert.True(span.Slice(1, length - 2).SequenceEqual(span.Trim('a')));
+ Assert.True(span.Slice(1).SequenceEqual(span.TrimStart('a')));
+ Assert.True(span.Slice(0, length - 1).SequenceEqual(span.TrimEnd('a')));
+ }
+ }
+
+ [Fact]
+ public static void TrimCharacterInMiddle()
+ {
+ for (int length = 3; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 'b';
+ }
+ a[1] = 'a';
+ ReadOnlySpan<char> span = new ReadOnlySpan<char>(a);
+ Assert.True(span.SequenceEqual(span.Trim('a')));
+ Assert.True(span.SequenceEqual(span.TrimStart('a')));
+ Assert.True(span.SequenceEqual(span.TrimEnd('a')));
+ }
+ }
+
+ [Fact]
+ public static void TrimCharacterMultipleTimes()
+ {
+ for (int length = 3; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 'b';
+ }
+ a[0] = 'a';
+ a[length - 1] = 'a';
+ ReadOnlySpan<char> span = new ReadOnlySpan<char>(a);
+ ReadOnlySpan<char> trimResult = span.Trim('a');
+ ReadOnlySpan<char> trimStartResult = span.TrimStart('a');
+ ReadOnlySpan<char> trimEndResult = span.TrimEnd('a');
+ Assert.True(span.Slice(1, length - 2).SequenceEqual(trimResult));
+ Assert.True(span.Slice(1).SequenceEqual(trimStartResult));
+ Assert.True(span.Slice(0, length - 1).SequenceEqual(trimEndResult));
+
+ // 2nd attempt should do nothing
+ Assert.True(trimResult.SequenceEqual(trimResult.Trim('a')));
+ Assert.True(trimStartResult.SequenceEqual(trimStartResult.TrimStart('a')));
+ Assert.True(trimEndResult.SequenceEqual(trimEndResult.TrimEnd('a')));
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoTrimCharacterChecksGoOutOfRange()
+ {
+ for (int length = 3; length < 64; length++)
+ {
+ char[] first = new char[length];
+ first[0] = 'a';
+ first[length - 1] = 'a';
+ var span = new ReadOnlySpan<char>(first, 1, length - 2);
+ Assert.True(span.SequenceEqual(span.Trim('a')));
+ Assert.True(span.SequenceEqual(span.TrimStart('a')));
+ Assert.True(span.SequenceEqual(span.TrimEnd('a')));
+ }
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlySpan/TrimManyCharacters.cs b/src/System.Memory/tests/ReadOnlySpan/TrimManyCharacters.cs
new file mode 100644
index 0000000000..afade2c2c8
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlySpan/TrimManyCharacters.cs
@@ -0,0 +1,263 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class ReadOnlySpanTests
+ {
+ [Fact]
+ public static void ZeroLengthTrimCharacters()
+ {
+ ReadOnlySpan<char> span = new ReadOnlySpan<char>(Array.Empty<char>());
+ ReadOnlySpan<char> trimChars = new ReadOnlySpan<char>(Array.Empty<char>());
+ Assert.True(span.SequenceEqual(span.Trim(trimChars)));
+ Assert.True(span.SequenceEqual(span.TrimStart(trimChars)));
+ Assert.True(span.SequenceEqual(span.TrimEnd(trimChars)));
+
+ char[] chars = { 'a', 'b', 'c', 'd', 'e' };
+ trimChars = new ReadOnlySpan<char>(chars);
+ Assert.True(span.SequenceEqual(span.Trim(trimChars)));
+ Assert.True(span.SequenceEqual(span.TrimStart(trimChars)));
+ Assert.True(span.SequenceEqual(span.TrimEnd(trimChars)));
+
+ ReadOnlySpan<char> stringSpan = "".AsSpan();
+ ReadOnlySpan<char> trimCharsFromString = "abcde".AsSpan();
+ Assert.True(stringSpan.SequenceEqual(stringSpan.Trim(trimCharsFromString)));
+ Assert.True(stringSpan.SequenceEqual(stringSpan.TrimStart(trimCharsFromString)));
+ Assert.True(stringSpan.SequenceEqual(stringSpan.TrimEnd(trimCharsFromString)));
+ }
+
+ [Fact]
+ public static void NoTrimCharacters()
+ {
+ ReadOnlySpan<char> trimChars = new ReadOnlySpan<char>(Array.Empty<char>());
+ for (int length = 0; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 'f';
+ }
+ ReadOnlySpan<char> span = new ReadOnlySpan<char>(a);
+ Assert.True(span.SequenceEqual(span.Trim(trimChars)));
+ Assert.True(span.SequenceEqual(span.TrimStart(trimChars)));
+ Assert.True(span.SequenceEqual(span.TrimEnd(trimChars)));
+ }
+
+ char[] chars = { 'a', 'b', 'c', 'd', 'e' };
+ for (int length = 0; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 'f';
+ }
+ ReadOnlySpan<char> span = new ReadOnlySpan<char>(a);
+ Assert.True(span.SequenceEqual(span.Trim(chars)));
+ Assert.True(span.SequenceEqual(span.TrimStart(chars)));
+ Assert.True(span.SequenceEqual(span.TrimEnd(chars)));
+ }
+
+ ReadOnlySpan<char> stringSpan = "ffghifhig".AsSpan();
+ ReadOnlySpan<char> trimCharsFromString = "abcde".AsSpan();
+ Assert.True(stringSpan.SequenceEqual(stringSpan.Trim(trimCharsFromString)));
+ Assert.True(stringSpan.SequenceEqual(stringSpan.TrimStart(trimCharsFromString)));
+ Assert.True(stringSpan.SequenceEqual(stringSpan.TrimEnd(trimCharsFromString)));
+ }
+
+ [Fact]
+ public static void OnlyTrimCharacters()
+ {
+ char[] chars = { 'a', 'b', 'c', 'd', 'e' };
+ for (int length = 0; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = chars[i % chars.Length];
+ }
+ ReadOnlySpan<char> span = new ReadOnlySpan<char>(a);
+ Assert.True(ReadOnlySpan<char>.Empty.SequenceEqual(span.Trim(chars)), "G: " + length);
+ Assert.True(ReadOnlySpan<char>.Empty.SequenceEqual(span.TrimStart(chars)), "H: " + length);
+ Assert.True(ReadOnlySpan<char>.Empty.SequenceEqual(span.TrimEnd(chars)), "I: " + length);
+ }
+
+ ReadOnlySpan<char> stringSpan = "babedebcabba".AsSpan();
+ ReadOnlySpan<char> trimChars = "abcde".AsSpan();
+ Assert.True(ReadOnlySpan<char>.Empty.SequenceEqual(stringSpan.Trim(trimChars)), "J");
+ Assert.True(ReadOnlySpan<char>.Empty.SequenceEqual(stringSpan.TrimStart(trimChars)), "K");
+ Assert.True(ReadOnlySpan<char>.Empty.SequenceEqual(stringSpan.TrimEnd(trimChars)), "L");
+ }
+
+ [Fact]
+ public static void TrimCharactersAtStart()
+ {
+ char[] chars = { 'a', 'b', 'c', 'd', 'e' };
+ for (int length = 2; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 'f';
+ }
+ a[0] = 'c';
+ ReadOnlySpan<char> span = new ReadOnlySpan<char>(a);
+ Assert.True(span.Slice(1).SequenceEqual(span.Trim(chars)), "A: " + length);
+ Assert.True(span.Slice(1).SequenceEqual(span.TrimStart(chars)), "B: " + length);
+ Assert.True(span.SequenceEqual(span.TrimEnd(chars)), "C: " + length);
+ }
+
+ ReadOnlySpan<char> stringSpan = "babffffff".AsSpan();
+ ReadOnlySpan<char> trimChars = "abcde".AsSpan();
+ Assert.True(stringSpan.Slice(3).SequenceEqual(stringSpan.Trim(trimChars)), "D");
+ Assert.True(stringSpan.Slice(3).SequenceEqual(stringSpan.TrimStart(trimChars)), "E");
+ Assert.True(stringSpan.SequenceEqual(stringSpan.TrimEnd(trimChars)), "F");
+ }
+
+ [Fact]
+ public static void TrimCharactersAtEnd()
+ {
+ char[] chars = { 'a', 'b', 'c', 'd', 'e' };
+ for (int length = 2; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 'f';
+ }
+ a[length - 1] = 'c';
+ ReadOnlySpan<char> span = new ReadOnlySpan<char>(a);
+ Assert.True(span.Slice(0, length - 1).SequenceEqual(span.Trim(chars)));
+ Assert.True(span.SequenceEqual(span.TrimStart(chars)));
+ Assert.True(span.Slice(0, length - 1).SequenceEqual(span.TrimEnd(chars)));
+ }
+
+ ReadOnlySpan<char> stringSpan = "fffffcced".AsSpan();
+ ReadOnlySpan<char> trimChars = "abcde".AsSpan();
+ Assert.True(stringSpan.Slice(0, 5).SequenceEqual(stringSpan.Trim(trimChars)));
+ Assert.True(stringSpan.SequenceEqual(stringSpan.TrimStart(trimChars)));
+ Assert.True(stringSpan.Slice(0, 5).SequenceEqual(stringSpan.TrimEnd(trimChars)));
+ }
+
+ [Fact]
+ public static void TrimCharactersAtStartAndEnd()
+ {
+ char[] chars = { 'a', 'b', 'c', 'd', 'e' };
+ for (int length = 3; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 'f';
+ }
+ a[0] = 'c';
+ a[length - 1] = 'c';
+ ReadOnlySpan<char> span = new ReadOnlySpan<char>(a);
+ Assert.True(span.Slice(1, length - 2).SequenceEqual(span.Trim(chars)));
+ Assert.True(span.Slice(1).SequenceEqual(span.TrimStart(chars)));
+ Assert.True(span.Slice(0, length - 1).SequenceEqual(span.TrimEnd(chars)));
+ }
+
+ ReadOnlySpan<char> stringSpan = "ccedafffffbdaa".AsSpan();
+ ReadOnlySpan<char> trimChars = "abcde".AsSpan();
+ Assert.True(stringSpan.Slice(5, 5).SequenceEqual(stringSpan.Trim(trimChars)));
+ Assert.True(stringSpan.Slice(5).SequenceEqual(stringSpan.TrimStart(trimChars)));
+ Assert.True(stringSpan.Slice(0, 10).SequenceEqual(stringSpan.TrimEnd(trimChars)));
+ }
+
+ [Fact]
+ public static void TrimCharactersInMiddle()
+ {
+ char[] chars = { 'a', 'b', 'c', 'd', 'e' };
+ for (int length = chars.Length + 2; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 'f';
+ }
+ Array.Copy(chars, 0, a, 1, chars.Length);
+ ReadOnlySpan<char> span = new ReadOnlySpan<char>(a);
+ Assert.True(span.SequenceEqual(span.Trim(chars)));
+ Assert.True(span.SequenceEqual(span.TrimStart(chars)));
+ Assert.True(span.SequenceEqual(span.TrimEnd(chars)));
+ }
+
+ ReadOnlySpan<char> stringSpan = "fabbacddeeddef".AsSpan();
+ ReadOnlySpan<char> trimChars = "abcde".AsSpan();
+ Assert.True(stringSpan.SequenceEqual(stringSpan.Trim(trimChars)));
+ Assert.True(stringSpan.SequenceEqual(stringSpan.TrimStart(trimChars)));
+ Assert.True(stringSpan.SequenceEqual(stringSpan.TrimEnd(trimChars)));
+ }
+
+ [Fact]
+ public static void TrimCharactersMultipleTimes()
+ {
+ char[] chars = { 'a', 'b', 'c', 'd', 'e' };
+ for (int length = 3; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 'f';
+ }
+ a[0] = 'c';
+ a[length - 1] = 'c';
+ ReadOnlySpan<char> span = new ReadOnlySpan<char>(a);
+ ReadOnlySpan<char> trimResult = span.Trim(chars);
+ ReadOnlySpan<char> trimStartResult = span.TrimStart(chars);
+ ReadOnlySpan<char> trimEndResult = span.TrimEnd(chars);
+ Assert.True(span.Slice(1, length - 2).SequenceEqual(trimResult));
+ Assert.True(span.Slice(1).SequenceEqual(trimStartResult));
+ Assert.True(span.Slice(0, length - 1).SequenceEqual(trimEndResult));
+
+ // 2nd attempt should do nothing
+ Assert.True(trimResult.SequenceEqual(trimResult.Trim(chars)));
+ Assert.True(trimStartResult.SequenceEqual(trimStartResult.TrimStart(chars)));
+ Assert.True(trimEndResult.SequenceEqual(trimEndResult.TrimEnd(chars)));
+ }
+
+ ReadOnlySpan<char> stringSpan = "ccedafffffbdaa".AsSpan();
+ ReadOnlySpan<char> trimChars = "abcde".AsSpan();
+
+ ReadOnlySpan<char> trimStringResult = stringSpan.Trim(trimChars);
+ ReadOnlySpan<char> trimStartStringResult = stringSpan.TrimStart(trimChars);
+ ReadOnlySpan<char> trimEndStringResult = stringSpan.TrimEnd(trimChars);
+ Assert.True(stringSpan.Slice(5, 5).SequenceEqual(trimStringResult));
+ Assert.True(stringSpan.Slice(5).SequenceEqual(trimStartStringResult));
+ Assert.True(stringSpan.Slice(0, 10).SequenceEqual(trimEndStringResult));
+
+ // 2nd attempt should do nothing
+ Assert.True(trimStringResult.SequenceEqual(trimStringResult.Trim(trimChars)));
+ Assert.True(trimStartStringResult.SequenceEqual(trimStartStringResult.TrimStart(trimChars)));
+ Assert.True(trimEndStringResult.SequenceEqual(trimEndStringResult.TrimEnd(trimChars)));
+ }
+
+ [Fact]
+ public static void MakeSureNoTrimCharactersChecksGoOutOfRange()
+ {
+ char[] chars = { 'a', 'b', 'c', 'd', 'e' };
+ for (int length = 3; length < 64; length++)
+ {
+ char[] first = new char[length];
+ first[0] = 'f';
+ first[length - 1] = 'f';
+ var span = new ReadOnlySpan<char>(first, 1, length - 2);
+ Assert.Equal(span.ToArray().Length, span.Trim(chars).ToArray().Length);
+ Assert.True(span.SequenceEqual(span.Trim(chars)), "A : " + span.Length);
+ Assert.True(span.SequenceEqual(span.TrimStart(chars)), "B :" + span.Length);
+ Assert.True(span.SequenceEqual(span.TrimEnd(chars)));
+ }
+
+ string testString = "afghijklmnopqrstfe";
+ ReadOnlySpan<char> stringSpan = testString.AsSpan(1, testString.Length - 2);
+ ReadOnlySpan<char> trimChars = "abcde".AsSpan();
+ Assert.True(stringSpan.SequenceEqual(stringSpan.Trim(trimChars)));
+ Assert.True(stringSpan.SequenceEqual(stringSpan.TrimStart(trimChars)));
+ Assert.True(stringSpan.SequenceEqual(stringSpan.TrimEnd(trimChars)));
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlySpan/TrimWhiteSpace.cs b/src/System.Memory/tests/ReadOnlySpan/TrimWhiteSpace.cs
new file mode 100644
index 0000000000..15c94f9603
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlySpan/TrimWhiteSpace.cs
@@ -0,0 +1,169 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class ReadOnlySpanTests
+ {
+ [Fact]
+ public static void ZeroLengthTrim()
+ {
+ ReadOnlySpan<char> span = new ReadOnlySpan<char>(Array.Empty<char>());
+ Assert.True(span.SequenceEqual(span.Trim()));
+ Assert.True(span.SequenceEqual(span.TrimStart()));
+ Assert.True(span.SequenceEqual(span.TrimEnd()));
+ }
+
+ [Fact]
+ public static void NoWhiteSpaceTrim()
+ {
+ for (int length = 0; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 'a';
+ }
+ ReadOnlySpan<char> span = new ReadOnlySpan<char>(a);
+ Assert.True(span.SequenceEqual(span.Trim()));
+ Assert.True(span.SequenceEqual(span.TrimStart()));
+ Assert.True(span.SequenceEqual(span.TrimEnd()));
+ }
+ }
+
+ [Fact]
+ public static void OnlyWhiteSpaceTrim()
+ {
+ for (int length = 0; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = ' ';
+ }
+ ReadOnlySpan<char> span = new ReadOnlySpan<char>(a);
+ Assert.True(ReadOnlySpan<char>.Empty.SequenceEqual(span.Trim()));
+ Assert.True(ReadOnlySpan<char>.Empty.SequenceEqual(span.TrimStart()));
+ Assert.True(ReadOnlySpan<char>.Empty.SequenceEqual(span.TrimEnd()));
+ }
+ }
+
+ [Fact]
+ public static void WhiteSpaceAtStartTrim()
+ {
+ for (int length = 2; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 'a';
+ }
+ a[0] = ' ';
+ ReadOnlySpan<char> span = new ReadOnlySpan<char>(a);
+ Assert.True(span.Slice(1).SequenceEqual(span.Trim()));
+ Assert.True(span.Slice(1).SequenceEqual(span.TrimStart()));
+ Assert.True(span.SequenceEqual(span.TrimEnd()));
+ }
+ }
+
+ [Fact]
+ public static void WhiteSpaceAtEndTrim()
+ {
+ for (int length = 2; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 'a';
+ }
+ a[length - 1] = ' ';
+ ReadOnlySpan<char> span = new ReadOnlySpan<char>(a);
+ Assert.True(span.Slice(0, length - 1).SequenceEqual(span.Trim()));
+ Assert.True(span.SequenceEqual(span.TrimStart()));
+ Assert.True(span.Slice(0, length - 1).SequenceEqual(span.TrimEnd()));
+ }
+ }
+
+ [Fact]
+ public static void WhiteSpaceAtStartAndEndTrim()
+ {
+ for (int length = 3; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 'a';
+ }
+ a[0] = ' ';
+ a[length - 1] = ' ';
+ ReadOnlySpan<char> span = new ReadOnlySpan<char>(a);
+ Assert.True(span.Slice(1, length - 2).SequenceEqual(span.Trim()));
+ Assert.True(span.Slice(1).SequenceEqual(span.TrimStart()));
+ Assert.True(span.Slice(0, length - 1).SequenceEqual(span.TrimEnd()));
+ }
+ }
+
+ [Fact]
+ public static void WhiteSpaceInMiddleTrim()
+ {
+ for (int length = 3; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 'a';
+ }
+ a[1] = ' ';
+ ReadOnlySpan<char> span = new ReadOnlySpan<char>(a);
+ Assert.True(span.SequenceEqual(span.Trim()));
+ Assert.True(span.SequenceEqual(span.TrimStart()));
+ Assert.True(span.SequenceEqual(span.TrimEnd()));
+ }
+ }
+
+ [Fact]
+ public static void TrimWhiteSpaceMultipleTimes()
+ {
+ for (int length = 3; length < 32; length++)
+ {
+ char[] a = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ a[i] = 'a';
+ }
+ a[0] = ' ';
+ a[length - 1] = ' ';
+ ReadOnlySpan<char> span = new ReadOnlySpan<char>(a);
+ ReadOnlySpan<char> trimResult = span.Trim();
+ ReadOnlySpan<char> trimStartResult = span.TrimStart();
+ ReadOnlySpan<char> trimEndResult = span.TrimEnd();
+ Assert.True(span.Slice(1, length - 2).SequenceEqual(trimResult));
+ Assert.True(span.Slice(1).SequenceEqual(trimStartResult));
+ Assert.True(span.Slice(0, length - 1).SequenceEqual(trimEndResult));
+
+ // 2nd attempt should do nothing
+ Assert.True(trimResult.SequenceEqual(trimResult.Trim()));
+ Assert.True(trimStartResult.SequenceEqual(trimStartResult.TrimStart()));
+ Assert.True(trimEndResult.SequenceEqual(trimEndResult.TrimEnd()));
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoTrimChecksGoOutOfRange()
+ {
+ for (int length = 3; length < 64; length++)
+ {
+ char[] first = new char[length];
+ first[0] = ' ';
+ first[length - 1] = ' ';
+ var span = new ReadOnlySpan<char>(first, 1, length - 2);
+ Assert.True(span.SequenceEqual(span.Trim()));
+ Assert.True(span.SequenceEqual(span.TrimStart()));
+ Assert.True(span.SequenceEqual(span.TrimEnd()));
+ }
+ }
+ }
+}
diff --git a/src/System.Memory/tests/Span/AsSpan.cs b/src/System.Memory/tests/Span/AsSpan.cs
index 63befe61c1..07d040fd90 100644
--- a/src/System.Memory/tests/Span/AsSpan.cs
+++ b/src/System.Memory/tests/Span/AsSpan.cs
@@ -35,7 +35,16 @@ namespace System.SpanTests
}
[Fact]
- public static void ZeroLengthArrayAsSpan()
+ public static void NullArrayAsSpan()
+ {
+ int[] a = null;
+ Span<int> span = a.AsSpan();
+ span.Validate();
+ Assert.True(span == default);
+ }
+
+ [Fact]
+ public static void EmptyArrayAsSpan()
{
int[] empty = Array.Empty<int>();
Span<int> span = empty.AsSpan();
@@ -86,5 +95,116 @@ namespace System.SpanTests
Span<int> spanInt = segmentInt.AsSpan();
spanInt.ValidateNonNullEmpty();
}
+
+ [Theory]
+ [InlineData(0, 0)]
+ [InlineData(3, 0)]
+ [InlineData(3, 1)]
+ [InlineData(3, 2)]
+ [InlineData(3, 3)]
+ [InlineData(10, 0)]
+ [InlineData(10, 3)]
+ [InlineData(10, 10)]
+ public static void ArrayAsSpanWithStart(int length, int start)
+ {
+ int[] a = new int[length];
+ Span<int> s = a.AsSpan(start);
+ Assert.Equal(length - start, s.Length);
+ if (start != length)
+ {
+ s[0] = 42;
+ Assert.Equal(42, a[start]);
+ }
+ }
+
+ [Theory]
+ [InlineData(0, 0)]
+ [InlineData(3, 0)]
+ [InlineData(3, 1)]
+ [InlineData(3, 2)]
+ [InlineData(3, 3)]
+ [InlineData(10, 0)]
+ [InlineData(10, 3)]
+ [InlineData(10, 10)]
+ public static void ArraySegmentAsSpanWithStart(int length, int start)
+ {
+ const int segmentOffset = 5;
+
+ int[] a = new int[length + segmentOffset];
+ ArraySegment<int> segment = new ArraySegment<int>(a, 5, length);
+ Span<int> s = segment.AsSpan(start);
+ Assert.Equal(length - start, s.Length);
+ if (s.Length != 0)
+ {
+ s[0] = 42;
+ Assert.Equal(42, a[segmentOffset + start]);
+ }
+ }
+
+ [Theory]
+ [InlineData(0, 0, 0)]
+ [InlineData(3, 0, 3)]
+ [InlineData(3, 1, 2)]
+ [InlineData(3, 2, 1)]
+ [InlineData(3, 3, 0)]
+ [InlineData(10, 0, 5)]
+ [InlineData(10, 3, 2)]
+ public static void ArrayAsSpanWithStartAndLength(int length, int start, int subLength)
+ {
+ int[] a = new int[length];
+ Span<int> s = a.AsSpan(start, subLength);
+ Assert.Equal(subLength, s.Length);
+ if (subLength != 0)
+ {
+ s[0] = 42;
+ Assert.Equal(42, a[start]);
+ }
+ }
+
+ [Theory]
+ [InlineData(0, 0, 0)]
+ [InlineData(3, 0, 3)]
+ [InlineData(3, 1, 2)]
+ [InlineData(3, 2, 1)]
+ [InlineData(3, 3, 0)]
+ [InlineData(10, 0, 5)]
+ [InlineData(10, 3, 2)]
+ public static void ArraySegmentAsSpanWithStartAndLength(int length, int start, int subLength)
+ {
+ const int segmentOffset = 5;
+
+ int[] a = new int[length + segmentOffset];
+ ArraySegment<int> segment = new ArraySegment<int>(a, segmentOffset, length);
+ Span<int> s = segment.AsSpan(start, subLength);
+ Assert.Equal(subLength, s.Length);
+ if (subLength != 0)
+ {
+ s[0] = 42;
+ Assert.Equal(42, a[segmentOffset + start]);
+ }
+ }
+
+ [Theory]
+ [InlineData(0, -1)]
+ [InlineData(0, 1)]
+ [InlineData(5, 6)]
+ public static void ArrayAsSpanWithStartNegative(int length, int start)
+ {
+ int[] a = new int[length];
+ Assert.Throws<ArgumentOutOfRangeException>(() => a.AsSpan(start));
+ }
+
+ [Theory]
+ [InlineData(0, -1, 0)]
+ [InlineData(0, 1, 0)]
+ [InlineData(0, 0, -1)]
+ [InlineData(0, 0, 1)]
+ [InlineData(5, 6, 0)]
+ [InlineData(5, 3, 3)]
+ public static void ArrayAsSpanWithStartAndLengthNegative(int length, int start, int subLength)
+ {
+ int[] a = new int[length];
+ Assert.Throws<ArgumentOutOfRangeException>(() => a.AsSpan(start, subLength));
+ }
}
}
diff --git a/src/System.Memory/tests/Span/Clear.cs b/src/System.Memory/tests/Span/Clear.cs
index 117146191f..5f7c75ca0b 100644
--- a/src/System.Memory/tests/Span/Clear.cs
+++ b/src/System.Memory/tests/Span/Clear.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using Xunit;
+using System.Linq;
using System.Runtime.CompilerServices;
using static System.TestHelpers;
@@ -199,6 +200,31 @@ namespace System.SpanTests
}
[Fact]
+ public static void ClearReferenceTypeSlice()
+ {
+ // A string array [ ""1", ..., "20" ]
+ string[] baseline = Enumerable.Range(1, 20).Select(i => i.ToString()).ToArray();
+
+ for (int i = 0; i < 16; i++)
+ {
+ // Going to clear array.Slice(1, i) manually,
+ // then compare it against array.Slice(1, i).Clear().
+ // Test is written this way to allow detecting overrunning bounds.
+
+ string[] expected = (string[])baseline.Clone();
+ for (int j = 1; j <= i; j++)
+ {
+ expected[j] = null;
+ }
+
+ string[] actual = (string[])baseline.Clone();
+ actual.AsSpan(1, i).Clear();
+
+ Assert.Equal(expected, actual);
+ }
+ }
+
+ [Fact]
public static void ClearEnumType()
{
TestEnum[] actual = { TestEnum.e0, TestEnum.e1, TestEnum.e2 };
@@ -249,20 +275,14 @@ namespace System.SpanTests
try
{
- ref int data = ref Unsafe.AsRef<int>(memory.ToPointer());
-
- int initial = 5;
- for (int i = 0; i < length; i++)
- {
- Unsafe.Add(ref data, i) = initial;
- }
-
Span<int> span = new Span<int>(memory.ToPointer(), length);
+ span.Fill(5);
// Act
span.Clear();
// Assert using custom code for perf and to avoid allocating extra memory
+ ref int data = ref Unsafe.AsRef<int>(memory.ToPointer());
for (int i = 0; i < length; i++)
{
var actual = Unsafe.Add(ref data, i);
diff --git a/src/System.Memory/tests/Span/CopyTo.cs b/src/System.Memory/tests/Span/CopyTo.cs
index d1db216a1b..5dc60cf3cf 100644
--- a/src/System.Memory/tests/Span/CopyTo.cs
+++ b/src/System.Memory/tests/Span/CopyTo.cs
@@ -257,5 +257,36 @@ namespace System.SpanTests
}
}
}
+
+ [Fact]
+ public static void CopyToVaryingSizes()
+ {
+ const int MaxLength = 2048;
+
+ var rng = new Random();
+ byte[] inputArray = new byte[MaxLength];
+ Span<byte> inputSpan = inputArray;
+ Span<byte> outputSpan = new byte[MaxLength];
+ Span<byte> allZerosSpan = new byte[MaxLength];
+
+ // Test all inputs from size 0 .. MaxLength (inclusive) to make sure we don't have
+ // gaps in our Memmove logic.
+ for (int i = 0; i <= MaxLength; i++)
+ {
+ // Arrange
+
+ rng.NextBytes(inputArray);
+ outputSpan.Clear();
+
+ // Act
+
+ inputSpan.Slice(0, i).CopyTo(outputSpan);
+
+ // Assert
+
+ Assert.True(inputSpan.Slice(0, i).SequenceEqual(outputSpan.Slice(0, i))); // src successfully copied to dst
+ Assert.True(outputSpan.Slice(i).SequenceEqual(allZerosSpan.Slice(i))); // no other part of dst was overwritten
+ }
+ }
}
}
diff --git a/src/System.Memory/tests/Span/CtorArray.cs b/src/System.Memory/tests/Span/CtorArray.cs
index 6105a99748..b2f725c767 100644
--- a/src/System.Memory/tests/Span/CtorArray.cs
+++ b/src/System.Memory/tests/Span/CtorArray.cs
@@ -71,8 +71,22 @@ namespace System.SpanTests
[Fact]
public static void CtorArrayNullArray()
{
- Assert.Throws<ArgumentNullException>(() => new Span<int>(null).DontBox());
- Assert.Throws<ArgumentNullException>(() => new Span<int>(null, 0, 0).DontBox());
+ var span = new Span<int>(null);
+ span.Validate();
+ Assert.True(span == default);
+
+ span = new Span<int>(null, 0, 0);
+ span.Validate();
+ Assert.True(span == default);
+ }
+
+ [Fact]
+ public static void CtorArrayNullArrayNonZeroStartAndLength()
+ {
+ Assert.Throws<ArgumentOutOfRangeException>(() => new Span<int>(null, 1, 0).DontBox());
+ Assert.Throws<ArgumentOutOfRangeException>(() => new Span<int>(null, 0, 1).DontBox());
+ Assert.Throws<ArgumentOutOfRangeException>(() => new Span<int>(null, 1, 1).DontBox());
+ Assert.Throws<ArgumentOutOfRangeException>(() => new Span<int>(null, -1, -1).DontBox());
}
[Fact]
diff --git a/src/System.Memory/tests/Span/CtorPointerInt.cs b/src/System.Memory/tests/Span/CtorPointerInt.cs
index 9194da2fca..b4c802a347 100644
--- a/src/System.Memory/tests/Span/CtorPointerInt.cs
+++ b/src/System.Memory/tests/Span/CtorPointerInt.cs
@@ -60,20 +60,8 @@ namespace System.SpanTests
new Span<int>((void*)null, 0);
new Span<int?>((void*)null, 0);
AssertExtensions.Throws<ArgumentException>(null, () => new Span<object>((void*)null, 0).DontBox());
- AssertExtensions.Throws<ArgumentException>(null, () => new Span<StructWithReferences>((void*)null, 0).DontBox());
+ AssertExtensions.Throws<ArgumentException>(null, () => new Span<TestHelpers.StructWithReferences>((void*)null, 0).DontBox());
}
}
-
- private struct StructWithReferences
- {
- public int I;
- public InnerStruct Inner;
- }
-
- private struct InnerStruct
- {
- public int J;
- public object O;
- }
}
}
diff --git a/src/System.Memory/tests/Span/EndsWith.char.cs b/src/System.Memory/tests/Span/EndsWith.char.cs
new file mode 100644
index 0000000000..b291fa9422
--- /dev/null
+++ b/src/System.Memory/tests/Span/EndsWith.char.cs
@@ -0,0 +1,104 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class SpanTests
+ {
+ [Fact]
+ public static void ZeroLengthEndsWith_Char()
+ {
+ var a = new char[3];
+
+ var span = new Span<char>(a);
+ var slice = new ReadOnlySpan<char>(a, 2, 0);
+ bool b = span.EndsWith<char>(slice);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void SameSpanEndsWith_Char()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new Span<char>(a);
+ bool b = span.EndsWith(span);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void LengthMismatchEndsWith_Char()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new Span<char>(a, 0, 2);
+ var slice = new ReadOnlySpan<char>(a, 0, 3);
+ bool b = span.EndsWith(slice);
+ Assert.False(b);
+ }
+
+ [Fact]
+ public static void EndsWithMatch_Char()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new Span<char>(a, 0, 3);
+ var slice = new ReadOnlySpan<char>(a, 1, 2);
+ bool b = span.EndsWith(slice);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void EndsWithMatchDifferentSpans_Char()
+ {
+ char[] a = { '4', '5', '6' };
+ char[] b = { '4', '5', '6' };
+ var span = new Span<char>(a, 0, 3);
+ var slice = new ReadOnlySpan<char>(b, 0, 3);
+ bool c = span.EndsWith(slice);
+ Assert.True(c);
+ }
+
+ [Fact]
+ public static void EndsWithNoMatch_Char()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ var first = new char[length];
+ var second = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = (char)(i + 1);
+ }
+
+ second[mismatchIndex] = (char)(second[mismatchIndex] + 1);
+
+ var firstSpan = new Span<char>(first);
+ var secondSpan = new ReadOnlySpan<char>(second);
+ bool b = firstSpan.EndsWith(secondSpan);
+ Assert.False(b);
+ }
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoEndsWithChecksGoOutOfRange_Char()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new char[length + 2];
+ first[0] = '9';
+ first[length + 1] = '9';
+ var second = new char[length + 2];
+ second[0] = 'a';
+ second[length + 1] = 'a';
+ var span1 = new Span<char>(first, 1, length);
+ var span2 = new ReadOnlySpan<char>(second, 1, length);
+ bool b = span1.EndsWith(span2);
+ Assert.True(b);
+ }
+ }
+ }
+}
diff --git a/src/System.Memory/tests/Span/EndsWith.long.cs b/src/System.Memory/tests/Span/EndsWith.long.cs
new file mode 100644
index 0000000000..7145b0d2e6
--- /dev/null
+++ b/src/System.Memory/tests/Span/EndsWith.long.cs
@@ -0,0 +1,104 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class SpanTests
+ {
+ [Fact]
+ public static void ZeroLengthEndsWith_Long()
+ {
+ var a = new long[3];
+
+ var span = new Span<long>(a);
+ var slice = new ReadOnlySpan<long>(a, 2, 0);
+ bool b = span.EndsWith<long>(slice);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void SameSpanEndsWith_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ var span = new Span<long>(a);
+ bool b = span.EndsWith(span);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void LengthMismatchEndsWith_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ var span = new Span<long>(a, 0, 2);
+ var slice = new ReadOnlySpan<long>(a, 0, 3);
+ bool b = span.EndsWith(slice);
+ Assert.False(b);
+ }
+
+ [Fact]
+ public static void EndsWithMatch_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ var span = new Span<long>(a, 0, 3);
+ var slice = new ReadOnlySpan<long>(a, 1, 2);
+ bool b = span.EndsWith(slice);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void EndsWithMatchDifferentSpans_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ long[] b = { 488238291, 52498989823, 619890289890 };
+ var span = new Span<long>(a, 0, 3);
+ var slice = new ReadOnlySpan<long>(b, 0, 3);
+ bool c = span.EndsWith(slice);
+ Assert.True(c);
+ }
+
+ [Fact]
+ public static void EndsWithNoMatch_Long()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ var first = new long[length];
+ var second = new long[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = (long)(i + 1);
+ }
+
+ second[mismatchIndex] = (long)(second[mismatchIndex] + 1);
+
+ var firstSpan = new Span<long>(first);
+ var secondSpan = new ReadOnlySpan<long>(second);
+ bool b = firstSpan.EndsWith(secondSpan);
+ Assert.False(b);
+ }
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoEndsWithChecksGoOutOfRange_Long()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new long[length + 2];
+ first[0] = 99;
+ first[length + 1] = 99;
+ var second = new long[length + 2];
+ second[0] = 100;
+ second[length + 1] = 100;
+ var span1 = new Span<long>(first, 1, length);
+ var span2 = new ReadOnlySpan<long>(second, 1, length);
+ bool b = span1.EndsWith(span2);
+ Assert.True(b);
+ }
+ }
+ }
+}
diff --git a/src/System.Memory/tests/Span/IndexOf.byte.cs b/src/System.Memory/tests/Span/IndexOf.byte.cs
index 7bdad8d391..03f92fef2f 100644
--- a/src/System.Memory/tests/Span/IndexOf.byte.cs
+++ b/src/System.Memory/tests/Span/IndexOf.byte.cs
@@ -3,7 +3,6 @@
// See the LICENSE file in the project root for more information.
using System.Numerics;
-using System.Text;
using Xunit;
namespace System.SpanTests
diff --git a/src/System.Memory/tests/Span/IndexOfAny.byte.cs b/src/System.Memory/tests/Span/IndexOfAny.byte.cs
index 61b1da24d5..d87c526294 100644
--- a/src/System.Memory/tests/Span/IndexOfAny.byte.cs
+++ b/src/System.Memory/tests/Span/IndexOfAny.byte.cs
@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Numerics;
using System.Text;
using Xunit;
diff --git a/src/System.Memory/tests/Span/Reverse.cs b/src/System.Memory/tests/Span/Reverse.cs
index 7123f0869d..a0d51a5c08 100644
--- a/src/System.Memory/tests/Span/Reverse.cs
+++ b/src/System.Memory/tests/Span/Reverse.cs
@@ -3,7 +3,6 @@
// See the LICENSE file in the project root for more information.
using Xunit;
-using System.Runtime.CompilerServices;
using static System.TestHelpers;
namespace System.SpanTests
@@ -21,7 +20,7 @@ namespace System.SpanTests
span = actual;
span.Slice(2, 0).Reverse();
-
+
Assert.Equal<byte>(expected, span.ToArray());
}
@@ -43,7 +42,7 @@ namespace System.SpanTests
[Fact]
public static void ReverseByte()
{
- for(int length = 0; length < byte.MaxValue; length++)
+ for (int length = 0; length < byte.MaxValue; length++)
{
var actual = new byte[length];
for (int i = 0; i < length; i++)
@@ -110,7 +109,7 @@ namespace System.SpanTests
IntPtr[] expectedFull = new IntPtr[length];
Array.Copy(actualFull, expectedFull, length);
Array.Reverse(expectedFull, offset, length - offset);
-
+
var expectedSpan = new Span<IntPtr>(expectedFull, offset, length - offset);
var actualSpan = new Span<IntPtr>(actualFull, offset, length - offset);
actualSpan.Reverse();
diff --git a/src/System.Memory/tests/Span/SequenceCompareTo.T.cs b/src/System.Memory/tests/Span/SequenceCompareTo.T.cs
index 493b4e2e2f..ed8d66e10e 100644
--- a/src/System.Memory/tests/Span/SequenceCompareTo.T.cs
+++ b/src/System.Memory/tests/Span/SequenceCompareTo.T.cs
@@ -9,48 +9,6 @@ namespace System.SpanTests
public static partial class SpanTests
{
[Fact]
- public static void ZeroLengthSequenceCompareTo()
- {
- int[] a = new int[3];
-
- Span<int> first = new Span<int>(a, 1, 0);
- Span<int> second = new Span<int>(a, 2, 0);
- int result = first.SequenceCompareTo(second);
- Assert.Equal(0, result);
- }
-
- [Fact]
- public static void SameSpanSequenceCompareTo()
- {
- int[] a = { 4, 5, 6 };
- Span<int> span = new Span<int>(a);
- int result = span.SequenceCompareTo(span);
- Assert.Equal(0, result);
- }
-
- [Fact]
- public static void LengthMismatchSequenceCompareTo()
- {
- int[] a = { 4, 5, 6 };
- Span<int> first = new Span<int>(a, 0, 2);
- Span<int> second = new Span<int>(a, 0, 3);
- int result = first.SequenceCompareTo(second);
- Assert.True(result < 0);
-
- result = second.SequenceCompareTo(first);
- Assert.True(result > 0);
-
- // one sequence is empty
- first = new Span<int>(a, 1, 0);
-
- result = first.SequenceCompareTo(second);
- Assert.True(result < 0);
-
- result = second.SequenceCompareTo(first);
- Assert.True(result > 0);
- }
-
- [Fact]
public static void OnSequenceCompareToOfEqualSpansMakeSureEveryElementIsCompared()
{
for (int length = 0; length < 100; length++)
@@ -173,5 +131,143 @@ namespace System.SpanTests
Assert.Equal(0, result);
}
}
+
+ [Fact]
+ public static void ZeroLengthSequenceCompareTo_String()
+ {
+ var a = new string[3];
+
+ var first = new Span<string>(a, 1, 0);
+ var second = new Span<string>(a, 2, 0);
+ int result = first.SequenceCompareTo<string>(second);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SameSpanSequenceCompareTo_String()
+ {
+ string[] a = { "fourth", "fifth", "sixth" };
+ var span = new Span<string>(a);
+ int result = span.SequenceCompareTo<string>(span);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SequenceCompareToArrayImplicit_String()
+ {
+ string[] a = { "fourth", "fifth", "sixth" };
+ var first = new Span<string>(a, 0, 3);
+ int result = first.SequenceCompareTo<string>(a);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SequenceCompareToArraySegmentImplicit_String()
+ {
+ string[] src = { "first", "second", "third" };
+ string[] dst = { "fifth", "first", "second", "third", "tenth" };
+ var segment = new ArraySegment<string>(dst, 1, 3);
+
+ var first = new Span<string>(src, 0, 3);
+ int result = first.SequenceCompareTo<string>(segment);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void LengthMismatchSequenceCompareTo_String()
+ {
+ string[] a = { "fourth", "fifth", "sixth" };
+ var first = new Span<string>(a, 0, 2);
+ var second = new Span<string>(a, 0, 3);
+ int result = first.SequenceCompareTo<string>(second);
+ Assert.True(result < 0);
+
+ result = second.SequenceCompareTo<string>(first);
+ Assert.True(result > 0);
+
+ // one sequence is empty
+ first = new Span<string>(a, 1, 0);
+
+ result = first.SequenceCompareTo<string>(second);
+ Assert.True(result < 0);
+
+ result = second.SequenceCompareTo<string>(first);
+ Assert.True(result > 0);
+ }
+
+ [Fact]
+ public static void SequenceCompareToWithSingleMismatch_String()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ var first = new string[length];
+ var second = new string[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = $"item {i + 1}";
+ }
+
+ second[mismatchIndex] = (string)(second[mismatchIndex] + 1);
+
+ var firstSpan = new Span<string>(first);
+ var secondSpan = new ReadOnlySpan<string>(second);
+ int result = firstSpan.SequenceCompareTo<string>(secondSpan);
+ Assert.True(result < 0);
+
+ result = secondSpan.SequenceCompareTo<string>(firstSpan);
+ Assert.True(result > 0);
+ }
+ }
+ }
+
+ [Fact]
+ public static void SequenceCompareToNoMatch_string()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ var first = new string[length];
+ var second = new string[length];
+
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = $"item {i + 1}";
+ second[i] = $"item {int.MaxValue - i}";
+ }
+
+ var firstSpan = new Span<string>(first);
+ var secondSpan = new ReadOnlySpan<string>(second);
+ int result = firstSpan.SequenceCompareTo<string>(secondSpan);
+ Assert.True(result < 0);
+
+ result = secondSpan.SequenceCompareTo<string>(firstSpan);
+ Assert.True(result > 0);
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoSequenceCompareToChecksGoOutOfRange_string()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new string[length + 2];
+ first[0] = "99";
+ for (int k = 1; k <= length; k++)
+ first[k] = string.Empty;
+ first[length + 1] = "99";
+
+ var second = new string[length + 2];
+ second[0] = "100";
+ for (int k = 1; k <= length; k++)
+ second[k] = string.Empty;
+ second[length + 1] = "100";
+
+ var span1 = new Span<string>(first, 1, length);
+ var span2 = new ReadOnlySpan<string>(second, 1, length);
+ int result = span1.SequenceCompareTo<string>(span2);
+ Assert.Equal(0, result);
+ }
+ }
}
}
diff --git a/src/System.Memory/tests/Span/SequenceCompareTo.bool.cs b/src/System.Memory/tests/Span/SequenceCompareTo.bool.cs
new file mode 100644
index 0000000000..01f8ee2f7d
--- /dev/null
+++ b/src/System.Memory/tests/Span/SequenceCompareTo.bool.cs
@@ -0,0 +1,149 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class SpanTests
+ {
+ [Fact]
+ public static void ZeroLengthSequenceCompareTo_Bool()
+ {
+ var a = new bool[3];
+
+ var first = new Span<bool>(a, 1, 0);
+ var second = new ReadOnlySpan<bool>(a, 2, 0);
+ int result = first.SequenceCompareTo<bool>(second);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SameSpanSequenceCompareTo_Bool()
+ {
+ bool[] a = { true, true, false };
+ var span = new Span<bool>(a);
+ int result = span.SequenceCompareTo<bool>(span);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SequenceCompareToArrayImplicit_Bool()
+ {
+ bool[] a = { true, true, false };
+ var first = new Span<bool>(a, 0, 3);
+ int result = first.SequenceCompareTo<bool>(a);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SequenceCompareToArraySegmentImplicit_Bool()
+ {
+ bool[] src = { true, true, true};
+ bool[] dst = { false, true, true, true, false };
+ var segment = new ArraySegment<bool>(dst, 1, 3);
+
+ var first = new Span<bool>(src, 0, 3);
+ int result = first.SequenceCompareTo<bool>(segment);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void LengthMismatchSequenceCompareTo_Bool()
+ {
+ bool[] a = { true, true, false };
+ var first = new Span<bool>(a, 0, 2);
+ var second = new Span<bool>(a, 0, 3);
+ int result = first.SequenceCompareTo<bool>(second);
+ Assert.True(result < 0);
+
+ result = second.SequenceCompareTo<bool>(first);
+ Assert.True(result > 0);
+
+ // one sequence is empty
+ first = new Span<bool>(a, 1, 0);
+
+ result = first.SequenceCompareTo<bool>(second);
+ Assert.True(result < 0);
+
+ result = second.SequenceCompareTo<bool>(first);
+ Assert.True(result > 0);
+ }
+
+ [Fact]
+ public static void SequenceCompareToWithSingleMismatch_Bool()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ var first = new bool[length];
+ var second = new bool[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = true;
+ }
+
+ second[mismatchIndex] = !second[mismatchIndex];
+
+ var firstSpan = new Span<bool>(first);
+ var secondSpan = new ReadOnlySpan<bool>(second);
+ int result = firstSpan.SequenceCompareTo<bool>(secondSpan);
+ Assert.True(result > 0);
+
+ result = secondSpan.SequenceCompareTo<bool>(firstSpan);
+ Assert.True(result < 0);
+ }
+ }
+ }
+
+ [Fact]
+ public static void SequenceCompareToNoMatch_Bool()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ var first = new bool[length];
+ var second = new bool[length];
+
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = (i % 2 != 0);
+ second[i] = (i % 2 == 0);
+ }
+
+ var firstSpan = new Span<bool>(first);
+ var secondSpan = new ReadOnlySpan<bool>(second);
+ int result = firstSpan.SequenceCompareTo<bool>(secondSpan);
+ Assert.True(result < 0);
+
+ result = secondSpan.SequenceCompareTo<bool>(firstSpan);
+ Assert.True(result > 0);
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoSequenceCompareToChecksGoOutOfRange_Bool()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new bool[length + 2];
+ first[0] = true;
+ for (int k = 1; k <= length; k++)
+ first[k] = false;
+ first[length + 1] = true;
+
+ var second = new bool[length + 2];
+ second[0] = false;
+ for (int k = 1; k <= length; k++)
+ second[k] = false;
+ second[length + 1] = false;
+
+ var span1 = new Span<bool>(first, 1, length);
+ var span2 = new ReadOnlySpan<bool>(second, 1, length);
+ int result = span1.SequenceCompareTo<bool>(span2);
+ Assert.Equal(0, result);
+ }
+ }
+ }
+}
diff --git a/src/System.Memory/tests/Span/SequenceCompareTo.byte.cs b/src/System.Memory/tests/Span/SequenceCompareTo.byte.cs
index 4eab6a68ef..73f3728fa1 100644
--- a/src/System.Memory/tests/Span/SequenceCompareTo.byte.cs
+++ b/src/System.Memory/tests/Span/SequenceCompareTo.byte.cs
@@ -105,7 +105,7 @@ namespace System.SpanTests
{
byte[] first = new byte[length];
byte[] second = new byte[length];
-
+
for (int i = 0; i < length; i++)
{
first[i] = (byte)(i + 1);
diff --git a/src/System.Memory/tests/Span/SequenceCompareTo.char.cs b/src/System.Memory/tests/Span/SequenceCompareTo.char.cs
new file mode 100644
index 0000000000..c45d0eb9c9
--- /dev/null
+++ b/src/System.Memory/tests/Span/SequenceCompareTo.char.cs
@@ -0,0 +1,145 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class SpanTests
+ {
+ [Fact]
+ public static void ZeroLengthSequenceCompareTo_Char()
+ {
+ var a = new char[3];
+
+ var first = new Span<char>(a, 1, 0);
+ var second = new ReadOnlySpan<char>(a, 2, 0);
+ int result = first.SequenceCompareTo<char>(second);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SameSpanSequenceCompareTo_Char()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new Span<char>(a);
+ int result = span.SequenceCompareTo<char>(span);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SequenceCompareToArrayImplicit_Char()
+ {
+ char[] a = { '4', '5', '6' };
+ var first = new Span<char>(a, 0, 3);
+ int result = first.SequenceCompareTo<char>(a);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SequenceCompareToArraySegmentImplicit_Char()
+ {
+ char[] src = { '1', '2', '3' };
+ char[] dst = { '5', '1', '2', '3', '9' };
+ var segment = new ArraySegment<char>(dst, 1, 3);
+
+ var first = new Span<char>(src, 0, 3);
+ int result = first.SequenceCompareTo<char>(segment);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void LengthMismatchSequenceCompareTo_Char()
+ {
+ char[] a = { '4', '5', '6' };
+ var first = new Span<char>(a, 0, 2);
+ var second = new Span<char>(a, 0, 3);
+ int result = first.SequenceCompareTo<char>(second);
+ Assert.True(result < 0);
+
+ result = second.SequenceCompareTo<char>(first);
+ Assert.True(result > 0);
+
+ // one sequence is empty
+ first = new Span<char>(a, 1, 0);
+
+ result = first.SequenceCompareTo<char>(second);
+ Assert.True(result < 0);
+
+ result = second.SequenceCompareTo<char>(first);
+ Assert.True(result > 0);
+ }
+
+ [Fact]
+ public static void SequenceCompareToWithSingleMismatch_Char()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ var first = new char[length];
+ var second = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = (char)(i + 1);
+ }
+
+ second[mismatchIndex] = (char)(second[mismatchIndex] + 1);
+
+ var firstSpan = new Span<char>(first);
+ var secondSpan = new ReadOnlySpan<char>(second);
+ int result = firstSpan.SequenceCompareTo<char>(secondSpan);
+ Assert.True(result < 0);
+
+ result = secondSpan.SequenceCompareTo<char>(firstSpan);
+ Assert.True(result > 0);
+ }
+ }
+ }
+
+ [Fact]
+ public static void SequenceCompareToNoMatch_Char()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ var first = new char[length];
+ var second = new char[length];
+
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = (char)(i + 1);
+ second[i] = (char)(char.MaxValue - i);
+ }
+
+ var firstSpan = new Span<char>(first);
+ var secondSpan = new ReadOnlySpan<char>(second);
+ int result = firstSpan.SequenceCompareTo<char>(secondSpan);
+ Assert.True(result < 0);
+
+ result = secondSpan.SequenceCompareTo<char>(firstSpan);
+ Assert.True(result > 0);
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoSequenceCompareToChecksGoOutOfRange_Char()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new char[length + 2];
+ first[0] = '8';
+ first[length + 1] = '8';
+
+ var second = new char[length + 2];
+ second[0] = '9';
+ second[length + 1] = '9';
+
+ var span1 = new Span<char>(first, 1, length);
+ var span2 = new ReadOnlySpan<char>(second, 1, length);
+ int result = span1.SequenceCompareTo<char>(span2);
+ Assert.Equal(0, result);
+ }
+ }
+ }
+}
diff --git a/src/System.Memory/tests/Span/SequenceCompareTo.int.cs b/src/System.Memory/tests/Span/SequenceCompareTo.int.cs
new file mode 100644
index 0000000000..9e0433ffcb
--- /dev/null
+++ b/src/System.Memory/tests/Span/SequenceCompareTo.int.cs
@@ -0,0 +1,145 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class SpanTests
+ {
+ [Fact]
+ public static void ZeroLengthSequenceCompareTo_Int()
+ {
+ var a = new int[3];
+
+ var first = new Span<int>(a, 1, 0);
+ var second = new ReadOnlySpan<int>(a, 2, 0);
+ int result = first.SequenceCompareTo<int>(second);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SameSpanSequenceCompareTo_Int()
+ {
+ int[] a = { 851227, 28052014, 429104168 };
+ var span = new Span<int>(a);
+ int result = span.SequenceCompareTo<int>(span);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SequenceCompareToArrayImplicit_Int()
+ {
+ int[] a = { 851227, 28052014, 429104168 };
+ var first = new Span<int>(a, 0, 3);
+ int result = first.SequenceCompareTo<int>(a);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SequenceCompareToArraySegmentImplicit_Int()
+ {
+ int[] src = { 851227, 28052014, 429104168 };
+ int[] dst = { 5, 851227, 28052014, 429104168, 10 };
+ var segment = new ArraySegment<int>(dst, 1, 3);
+
+ var first = new Span<int>(src, 0, 3);
+ int result = first.SequenceCompareTo<int>(segment);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void LengthMismatchSequenceCompareTo_Int()
+ {
+ int[] a = { 851227, 28052014, 429104168 };
+ var first = new Span<int>(a, 0, 2);
+ var second = new Span<int>(a, 0, 3);
+ int result = first.SequenceCompareTo<int>(second);
+ Assert.True(result < 0);
+
+ result = second.SequenceCompareTo<int>(first);
+ Assert.True(result > 0);
+
+ // one sequence is empty
+ first = new Span<int>(a, 1, 0);
+
+ result = first.SequenceCompareTo<int>(second);
+ Assert.True(result < 0);
+
+ result = second.SequenceCompareTo<int>(first);
+ Assert.True(result > 0);
+ }
+
+ [Fact]
+ public static void SequenceCompareToWithSingleMismatch_Int()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ var first = new int[length];
+ var second = new int[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = (int)(i + 1);
+ }
+
+ second[mismatchIndex] = (int)(second[mismatchIndex] + 1);
+
+ var firstSpan = new Span<int>(first);
+ var secondSpan = new ReadOnlySpan<int>(second);
+ int result = firstSpan.SequenceCompareTo<int>(secondSpan);
+ Assert.True(result < 0);
+
+ result = secondSpan.SequenceCompareTo<int>(firstSpan);
+ Assert.True(result > 0);
+ }
+ }
+ }
+
+ [Fact]
+ public static void SequenceCompareToNoMatch_Int()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ var first = new int[length];
+ var second = new int[length];
+
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = (int)(i + 1);
+ second[i] = (int)(int.MaxValue - i);
+ }
+
+ var firstSpan = new Span<int>(first);
+ var secondSpan = new ReadOnlySpan<int>(second);
+ int result = firstSpan.SequenceCompareTo<int>(secondSpan);
+ Assert.True(result < 0);
+
+ result = secondSpan.SequenceCompareTo<int>(firstSpan);
+ Assert.True(result > 0);
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoSequenceCompareToChecksGoOutOfRange_Int()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new int[length + 2];
+ first[0] = 99;
+ first[length + 1] = 99;
+
+ var second = new int[length + 2];
+ second[0] = 100;
+ second[length + 1] = 100;
+
+ var span1 = new Span<int>(first, 1, length);
+ var span2 = new ReadOnlySpan<int>(second, 1, length);
+ int result = span1.SequenceCompareTo<int>(span2);
+ Assert.Equal(0, result);
+ }
+ }
+ }
+}
diff --git a/src/System.Memory/tests/Span/SequenceCompareTo.long.cs b/src/System.Memory/tests/Span/SequenceCompareTo.long.cs
new file mode 100644
index 0000000000..87610a2027
--- /dev/null
+++ b/src/System.Memory/tests/Span/SequenceCompareTo.long.cs
@@ -0,0 +1,145 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class SpanTests
+ {
+ [Fact]
+ public static void ZeroLengthSequenceCompareTo_Long()
+ {
+ var a = new long[3];
+
+ var first = new Span<long>(a, 1, 0);
+ var second = new ReadOnlySpan<long>(a, 2, 0);
+ int result = first.SequenceCompareTo<long>(second);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SameSpanSequenceCompareTo_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ var span = new Span<long>(a);
+ int result = span.SequenceCompareTo<long>(span);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SequenceCompareToArrayImplicit_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ var first = new Span<long>(a, 0, 3);
+ int result = first.SequenceCompareTo<long>(a);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void SequenceCompareToArraySegmentImplicit_Long()
+ {
+ long[] src = { 1989089123, 234523454235, 3123213231 };
+ long[] dst = { 5, 1989089123, 234523454235, 3123213231, 10 };
+ var segment = new ArraySegment<long>(dst, 1, 3);
+
+ var first = new Span<long>(src, 0, 3);
+ int result = first.SequenceCompareTo<long>(segment);
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public static void LengthMismatchSequenceCompareTo_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ var first = new Span<long>(a, 0, 2);
+ var second = new Span<long>(a, 0, 3);
+ int result = first.SequenceCompareTo<long>(second);
+ Assert.True(result < 0);
+
+ result = second.SequenceCompareTo<long>(first);
+ Assert.True(result > 0);
+
+ // one sequence is empty
+ first = new Span<long>(a, 1, 0);
+
+ result = first.SequenceCompareTo<long>(second);
+ Assert.True(result < 0);
+
+ result = second.SequenceCompareTo<long>(first);
+ Assert.True(result > 0);
+ }
+
+ [Fact]
+ public static void SequenceCompareToWithSingleMismatch_Long()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ var first = new long[length];
+ var second = new long[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = (long)(i + 1);
+ }
+
+ second[mismatchIndex] = (long)(second[mismatchIndex] + 1);
+
+ var firstSpan = new Span<long>(first);
+ var secondSpan = new ReadOnlySpan<long>(second);
+ int result = firstSpan.SequenceCompareTo<long>(secondSpan);
+ Assert.True(result < 0);
+
+ result = secondSpan.SequenceCompareTo<long>(firstSpan);
+ Assert.True(result > 0);
+ }
+ }
+ }
+
+ [Fact]
+ public static void SequenceCompareToNoMatch_Long()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ var first = new long[length];
+ var second = new long[length];
+
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = (long)(i + 1);
+ second[i] = (long)(long.MaxValue - i);
+ }
+
+ var firstSpan = new Span<long>(first);
+ var secondSpan = new ReadOnlySpan<long>(second);
+ int result = firstSpan.SequenceCompareTo<long>(secondSpan);
+ Assert.True(result < 0);
+
+ result = secondSpan.SequenceCompareTo<long>(firstSpan);
+ Assert.True(result > 0);
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoSequenceCompareToChecksGoOutOfRange_Long()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new long[length + 2];
+ first[0] = 99;
+ first[length + 1] = 99;
+
+ var second = new long[length + 2];
+ second[0] = 100;
+ second[length + 1] = 100;
+
+ var span1 = new Span<long>(first, 1, length);
+ var span2 = new ReadOnlySpan<long>(second, 1, length);
+ int result = span1.SequenceCompareTo<long>(span2);
+ Assert.Equal(0, result);
+ }
+ }
+ }
+}
diff --git a/src/System.Memory/tests/Span/SequenceEqual.long.cs b/src/System.Memory/tests/Span/SequenceEqual.long.cs
new file mode 100644
index 0000000000..1a8660bad8
--- /dev/null
+++ b/src/System.Memory/tests/Span/SequenceEqual.long.cs
@@ -0,0 +1,104 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class SpanTests
+ {
+ [Fact]
+ public static void ZeroLengthSequenceEqual_Long()
+ {
+ long[] a = new long[3];
+
+ Span<long> first = new Span<long>(a, 1, 0);
+ Span<long> second = new Span<long>(a, 2, 0);
+ bool b = first.SequenceEqual<long>(second);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void SameSpanSequenceEqual_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ Span<long> span = new Span<long>(a);
+ bool b = span.SequenceEqual<long>(span);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void SequenceEqualArrayImplicit_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ Span<long> first = new Span<long>(a, 0, 3);
+ bool b = first.SequenceEqual<long>(a);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void SequenceEqualArraySegmentImplicit_Long()
+ {
+ long[] src = { 1989089123, 234523454235, 3123213231 };
+ long[] dst = { 5, 1989089123, 234523454235, 3123213231, 10 };
+ ArraySegment<long> segment = new ArraySegment<long>(dst, 1, 3);
+
+ Span<long> first = new Span<long>(src, 0, 3);
+ bool b = first.SequenceEqual<long>(segment);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void LengthMismatchSequenceEqual_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ Span<long> first = new Span<long>(a, 0, 3);
+ Span<long> second = new Span<long>(a, 0, 2);
+ bool b = first.SequenceEqual<long>(second);
+ Assert.False(b);
+ }
+
+ [Fact]
+ public static void SequenceEqualNoMatch_Long()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ long[] first = new long[length];
+ long[] second = new long[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = (byte)(i + 1);
+ }
+
+ second[mismatchIndex] = (byte)(second[mismatchIndex] + 1);
+
+ Span<long> firstSpan = new Span<long>(first);
+ ReadOnlySpan<long> secondSpan = new ReadOnlySpan<long>(second);
+ bool b = firstSpan.SequenceEqual<long>(secondSpan);
+ Assert.False(b);
+ }
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoSequenceEqualChecksGoOutOfRange_Long()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ long[] first = new long[length + 2];
+ first[0] = 99;
+ first[length + 1] = 99;
+ long[] second = new long[length + 2];
+ second[0] = 100;
+ second[length + 1] = 100;
+ Span<long> span1 = new Span<long>(first, 1, length);
+ ReadOnlySpan<long> span2 = new ReadOnlySpan<long>(second, 1, length);
+ bool b = span1.SequenceEqual<long>(span2);
+ Assert.True(b);
+ }
+ }
+ }
+}
diff --git a/src/System.Memory/tests/Span/StartsWith.char.cs b/src/System.Memory/tests/Span/StartsWith.char.cs
new file mode 100644
index 0000000000..ececb4a38c
--- /dev/null
+++ b/src/System.Memory/tests/Span/StartsWith.char.cs
@@ -0,0 +1,104 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class SpanTests
+ {
+ [Fact]
+ public static void ZeroLengthStartsWith_Char()
+ {
+ var a = new char[3];
+
+ var span = new Span<char>(a);
+ var slice = new ReadOnlySpan<char>(a, 2, 0);
+ bool b = span.StartsWith<char>(slice);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void SameSpanStartsWith_Char()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new Span<char>(a);
+ bool b = span.StartsWith<char>(span);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void LengthMismatchStartsWith_Char()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new Span<char>(a, 0, 2);
+ var slice = new ReadOnlySpan<char>(a, 0, 3);
+ bool b = span.StartsWith<char>(slice);
+ Assert.False(b);
+ }
+
+ [Fact]
+ public static void StartsWithMatch_Char()
+ {
+ char[] a = { '4', '5', '6' };
+ var span = new Span<char>(a, 0, 3);
+ var slice = new ReadOnlySpan<char>(a, 0, 2);
+ bool b = span.StartsWith<char>(slice);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void StartsWithMatchDifferentSpans_Char()
+ {
+ char[] a = { '4', '5', '6' };
+ char[] b = { '4', '5', '6' };
+ var span = new Span<char>(a, 0, 3);
+ var slice = new ReadOnlySpan<char>(b, 0, 3);
+ bool c = span.StartsWith<char>(slice);
+ Assert.True(c);
+ }
+
+ [Fact]
+ public static void StartsWithNoMatch_Char()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ var first = new char[length];
+ var second = new char[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = (char)(i + 1);
+ }
+
+ second[mismatchIndex] = (char)(second[mismatchIndex] + 1);
+
+ var firstSpan = new Span<char>(first);
+ var secondSpan = new ReadOnlySpan<char>(second);
+ bool b = firstSpan.StartsWith<char>(secondSpan);
+ Assert.False(b);
+ }
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoStartsWithChecksGoOutOfRange_Char()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new char[length + 2];
+ first[0] = '9';
+ first[length + 1] = '9';
+ var second = new char[length + 2];
+ second[0] = 'a';
+ second[length + 1] = 'a';
+ var span1 = new Span<char>(first, 1, length);
+ var span2 = new ReadOnlySpan<char>(second, 1, length);
+ bool b = span1.StartsWith<char>(span2);
+ Assert.True(b);
+ }
+ }
+ }
+}
diff --git a/src/System.Memory/tests/Span/StartsWith.long.cs b/src/System.Memory/tests/Span/StartsWith.long.cs
new file mode 100644
index 0000000000..a3d7d4c46a
--- /dev/null
+++ b/src/System.Memory/tests/Span/StartsWith.long.cs
@@ -0,0 +1,104 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class SpanTests
+ {
+ [Fact]
+ public static void ZeroLengthStartsWith_Long()
+ {
+ var a = new long[3];
+
+ var span = new Span<long>(a);
+ var slice = new ReadOnlySpan<long>(a, 2, 0);
+ bool b = span.StartsWith<long>(slice);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void SameSpanStartsWith_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ var span = new Span<long>(a);
+ bool b = span.StartsWith<long>(span);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void LengthMismatchStartsWith_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ var span = new Span<long>(a, 0, 2);
+ var slice = new ReadOnlySpan<long>(a, 0, 3);
+ bool b = span.StartsWith<long>(slice);
+ Assert.False(b);
+ }
+
+ [Fact]
+ public static void StartsWithMatch_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ var span = new Span<long>(a, 0, 3);
+ var slice = new ReadOnlySpan<long>(a, 0, 2);
+ bool b = span.StartsWith<long>(slice);
+ Assert.True(b);
+ }
+
+ [Fact]
+ public static void StartsWithMatchDifferentSpans_Long()
+ {
+ long[] a = { 488238291, 52498989823, 619890289890 };
+ long[] b = { 488238291, 52498989823, 619890289890 };
+ var span = new Span<long>(a, 0, 3);
+ var slice = new ReadOnlySpan<long>(b, 0, 3);
+ bool c = span.StartsWith<long>(slice);
+ Assert.True(c);
+ }
+
+ [Fact]
+ public static void StartsWithNoMatch_Long()
+ {
+ for (int length = 1; length < 32; length++)
+ {
+ for (int mismatchIndex = 0; mismatchIndex < length; mismatchIndex++)
+ {
+ var first = new long[length];
+ var second = new long[length];
+ for (int i = 0; i < length; i++)
+ {
+ first[i] = second[i] = (long)(i + 1);
+ }
+
+ second[mismatchIndex] = (long)(second[mismatchIndex] + 1);
+
+ var firstSpan = new Span<long>(first);
+ var secondSpan = new ReadOnlySpan<long>(second);
+ bool b = firstSpan.StartsWith<long>(secondSpan);
+ Assert.False(b);
+ }
+ }
+ }
+
+ [Fact]
+ public static void MakeSureNoStartsWithChecksGoOutOfRange_Long()
+ {
+ for (int length = 0; length < 100; length++)
+ {
+ var first = new long[length + 2];
+ first[0] = 99;
+ first[length + 1] = 99;
+ var second = new long[length + 2];
+ second[0] = 100;
+ second[length + 1] = 100;
+ var span1 = new Span<long>(first, 1, length);
+ var span2 = new ReadOnlySpan<long>(second, 1, length);
+ bool b = span1.StartsWith<long>(span2);
+ Assert.True(b);
+ }
+ }
+ }
+}
diff --git a/src/System.Memory/tests/Span/ToString.cs b/src/System.Memory/tests/Span/ToString.cs
new file mode 100644
index 0000000000..1875a91d79
--- /dev/null
+++ b/src/System.Memory/tests/Span/ToString.cs
@@ -0,0 +1,95 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using Xunit;
+
+namespace System.SpanTests
+{
+ public static partial class SpanTests
+ {
+ [Fact]
+ public static void ToStringInt()
+ {
+ int[] a = { 91, 92, 93 };
+ var span = new Span<int>(a);
+ Assert.Equal("System.Span<Int32>[3]", span.ToString());
+ }
+
+ [Fact]
+ public static void ToStringInt_Empty()
+ {
+ var span = new Span<int>();
+ Assert.Equal("System.Span<Int32>[0]", span.ToString());
+ }
+
+ [Fact]
+ public static unsafe void ToStringChar()
+ {
+ char[] a = { 'a', 'b', 'c' };
+ var span = new Span<char>(a);
+ Assert.Equal("abc", span.ToString());
+
+ string testString = "abcdefg";
+ ReadOnlySpan<char> readOnlySpan = testString.AsSpan();
+
+ fixed (void* ptr = &MemoryMarshal.GetReference(readOnlySpan))
+ {
+ var temp = new Span<char>(ptr, readOnlySpan.Length);
+ Assert.Equal(testString, temp.ToString());
+ }
+ }
+
+ [Fact]
+ public static void ToStringChar_Empty()
+ {
+ var span = new Span<char>();
+ Assert.Equal("", span.ToString());
+ }
+
+ [Fact]
+ public static void ToStringForSpanOfString()
+ {
+ string[] a = { "a", "b", "c" };
+ var span = new Span<string>(a);
+ Assert.Equal("System.Span<String>[3]", span.ToString());
+ }
+
+ [Fact]
+ public static void ToStringSpanOverFullStringDoesNotReturnOriginal()
+ {
+ string original = TestHelpers.BuildString(10, 42);
+
+ ReadOnlyMemory<char> readOnlyMemory = original.AsMemory();
+ Memory<char> memory = MemoryMarshal.AsMemory(readOnlyMemory);
+
+ Span<char> span = memory.Span;
+
+ string returnedString = span.ToString();
+ string returnedStringUsingSlice = span.Slice(0, original.Length).ToString();
+
+ string subString1 = span.Slice(1).ToString();
+ string subString2 = span.Slice(0, 2).ToString();
+ string subString3 = span.Slice(1, 2).ToString();
+
+ Assert.Equal(original, returnedString);
+ Assert.Equal(original, returnedStringUsingSlice);
+
+ Assert.Equal(original.Substring(1), subString1);
+ Assert.Equal(original.Substring(0, 2), subString2);
+ Assert.Equal(original.Substring(1, 2), subString3);
+
+ Assert.NotSame(original, returnedString);
+ Assert.NotSame(original, returnedStringUsingSlice);
+
+ Assert.NotSame(original, subString1);
+ Assert.NotSame(original, subString2);
+ Assert.NotSame(original, subString3);
+
+ Assert.NotSame(subString1, subString2);
+ Assert.NotSame(subString1, subString3);
+ Assert.NotSame(subString2, subString3);
+ }
+ }
+}
diff --git a/src/System.Memory/tests/System.Memory.Tests.csproj b/src/System.Memory/tests/System.Memory.Tests.csproj
index df4a91e183..27d689a92a 100644
--- a/src/System.Memory/tests/System.Memory.Tests.csproj
+++ b/src/System.Memory/tests/System.Memory.Tests.csproj
@@ -4,9 +4,19 @@
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ProjectGuid>{15DB0DCC-68B4-4CFB-8BD2-F26BCCAF5A3F}</ProjectGuid>
+ <IncludePartialFacadeTests Condition="'$(TargetGroup)' == 'netcoreapp' OR '$(TargetGroup)' == 'uap'">true</IncludePartialFacadeTests>
</PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Release|AnyCPU'" />
+ <ItemGroup Condition="'$(IncludePartialFacadeTests)' == 'true'">
+ <!-- Tests specific to the fast span -->
+ <Compile Include="MemoryMarshal\CreateSpan.cs" />
+ <Compile Include="MemoryMarshal\CreateReadOnlySpan.cs" />
+ </ItemGroup>
<ItemGroup>
<Compile Include="AllocationHelper.cs" />
<Compile Include="TInt.cs" />
@@ -14,7 +24,6 @@
<Compile Include="TestHelpers.cs" />
</ItemGroup>
<ItemGroup>
- <Compile Include="Span\AsBytes.cs" />
<Compile Include="Span\AsSpan.cs" />
<Compile Include="Span\Fill.cs" />
<Compile Include="Span\Clear.cs" />
@@ -22,88 +31,128 @@
<Compile Include="Span\CtorArray.cs" />
<Compile Include="Span\CtorArrayIntInt.cs" />
<Compile Include="Span\CtorPointerInt.cs" />
- <Compile Include="Span\DangerousCreate.cs" />
<Compile Include="Span\Empty.cs" />
<Compile Include="Span\EndsWith.byte.cs" />
+ <Compile Include="Span\EndsWith.char.cs" />
+ <Compile Include="Span\EndsWith.long.cs" />
<Compile Include="Span\EndsWith.T.cs" />
<Compile Include="Span\Equality.cs" />
<Compile Include="Span\GcReporting.cs" />
<Compile Include="Span\GetEnumerator.cs" />
<Compile Include="Span\GetHashCode.cs" />
<Compile Include="Span\ImplicitConversion.cs" />
- <Compile Include="Span\IndexOf.T.cs" />
<Compile Include="Span\IndexOf.byte.cs" />
<Compile Include="Span\IndexOf.char.cs" />
- <Compile Include="Span\IndexOfAny.T.cs" />
+ <Compile Include="Span\IndexOf.T.cs" />
<Compile Include="Span\IndexOfAny.byte.cs" />
- <Compile Include="Span\IndexOfSequence.T.cs" />
+ <Compile Include="Span\IndexOfAny.T.cs" />
<Compile Include="Span\IndexOfSequence.byte.cs" />
<Compile Include="Span\IndexOfSequence.char.cs" />
- <Compile Include="Span\LastIndexOfAny.T.cs" />
+ <Compile Include="Span\IndexOfSequence.T.cs" />
<Compile Include="Span\LastIndexOfAny.byte.cs" />
- <Compile Include="Span\LastIndexOf.T.cs" />
+ <Compile Include="Span\LastIndexOfAny.T.cs" />
<Compile Include="Span\LastIndexOf.byte.cs" />
<Compile Include="Span\LastIndexOf.char.cs" />
- <Compile Include="Span\LastIndexOfSequence.T.cs" />
+ <Compile Include="Span\LastIndexOf.T.cs" />
<Compile Include="Span\LastIndexOfSequence.byte.cs" />
<Compile Include="Span\LastIndexOfSequence.char.cs" />
- <Compile Include="Span\NonPortableCast.cs" />
+ <Compile Include="Span\LastIndexOfSequence.T.cs" />
<Compile Include="Span\Overflow.cs" />
<Compile Include="Span\Reverse.cs" />
- <Compile Include="Span\SequenceCompareTo.T.cs" />
+ <Compile Include="Span\SequenceCompareTo.bool.cs" />
<Compile Include="Span\SequenceCompareTo.byte.cs" />
- <Compile Include="Span\SequenceEqual.T.cs" />
+ <Compile Include="Span\SequenceCompareTo.char.cs" />
+ <Compile Include="Span\SequenceCompareTo.int.cs" />
+ <Compile Include="Span\SequenceCompareTo.long.cs" />
+ <Compile Include="Span\SequenceCompareTo.T.cs" />
<Compile Include="Span\SequenceEqual.byte.cs" />
<Compile Include="Span\SequenceEqual.char.cs" />
+ <Compile Include="Span\SequenceEqual.long.cs" />
+ <Compile Include="Span\SequenceEqual.T.cs" />
<Compile Include="Span\Slice.cs" />
- <Compile Include="Span\StartsWith.T.cs" />
<Compile Include="Span\StartsWith.byte.cs" />
+ <Compile Include="Span\StartsWith.char.cs" />
+ <Compile Include="Span\StartsWith.long.cs" />
+ <Compile Include="Span\StartsWith.T.cs" />
<Compile Include="Span\ToArray.cs" />
+ <Compile Include="Span\ToString.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="ReadOnlyBuffer\BufferSegment.cs" />
+ <Compile Include="ReadOnlyBuffer\ReadOnlySequenceFactory.byte.cs" />
+ <Compile Include="ReadOnlyBuffer\ReadOnlySequenceFactory.char.cs" />
+ <Compile Include="ReadOnlyBuffer\ReadOnlySequenceTests.byte.cs" />
+ <Compile Include="ReadOnlyBuffer\ReadOnlySequenceTests.char.cs" />
+ <Compile Include="ReadOnlyBuffer\ReadOnlySequenceTests.Common.cs" />
+ <Compile Include="ReadOnlyBuffer\ReadOnlySequenceTests.TryGet.cs" />
+ <Compile Include="ReadOnlyBuffer\SequencePosition.cs" />
</ItemGroup>
<ItemGroup>
- <Compile Include="ReadOnlySpan\AsBytes.cs" />
<Compile Include="ReadOnlySpan\AsReadOnlySpan.cs" />
<Compile Include="ReadOnlySpan\BinarySearch.cs" />
+ <Compile Include="ReadOnlySpan\CompareTo.cs" />
+ <Compile Include="ReadOnlySpan\Contains.cs" />
<Compile Include="ReadOnlySpan\CopyTo.cs" />
<Compile Include="ReadOnlySpan\CtorArray.cs" />
<Compile Include="ReadOnlySpan\CtorArrayIntInt.cs" />
<Compile Include="ReadOnlySpan\CtorPointerInt.cs" />
- <Compile Include="ReadOnlySpan\DangerousCreate.cs" />
<Compile Include="ReadOnlySpan\Empty.cs" />
<Compile Include="ReadOnlySpan\EndsWith.byte.cs" />
+ <Compile Include="ReadOnlySpan\EndsWith.char.cs" />
+ <Compile Include="ReadOnlySpan\EndsWith.long.cs" />
+ <Compile Include="ReadOnlySpan\EndsWith.StringComparison.cs" />
<Compile Include="ReadOnlySpan\EndsWith.T.cs" />
<Compile Include="ReadOnlySpan\Equality.cs" />
+ <Compile Include="ReadOnlySpan\Equals.cs" />
<Compile Include="ReadOnlySpan\GetEnumerator.cs" />
<Compile Include="ReadOnlySpan\GetHashCode.cs" />
<Compile Include="ReadOnlySpan\ImplicitConversion.cs" />
- <Compile Include="ReadOnlySpan\IndexOf.T.cs" />
<Compile Include="ReadOnlySpan\IndexOf.byte.cs" />
<Compile Include="ReadOnlySpan\IndexOf.char.cs" />
- <Compile Include="ReadOnlySpan\IndexOfAny.T.cs" />
+ <Compile Include="ReadOnlySpan\IndexOf.charSpan.cs" />
+ <Compile Include="ReadOnlySpan\IndexOf.T.cs" />
<Compile Include="ReadOnlySpan\IndexOfAny.byte.cs" />
- <Compile Include="ReadOnlySpan\IndexOfSequence.T.cs" />
+ <Compile Include="ReadOnlySpan\IndexOfAny.T.cs" />
<Compile Include="ReadOnlySpan\IndexOfSequence.byte.cs" />
<Compile Include="ReadOnlySpan\IndexOfSequence.char.cs" />
- <Compile Include="ReadOnlySpan\LastIndexOfAny.T.cs" />
+ <Compile Include="ReadOnlySpan\IndexOfSequence.T.cs" />
+ <Compile Include="ReadOnlySpan\IsWhiteSpace.cs" />
<Compile Include="ReadOnlySpan\LastIndexOfAny.byte.cs" />
- <Compile Include="ReadOnlySpan\LastIndexOf.T.cs" />
+ <Compile Include="ReadOnlySpan\LastIndexOfAny.T.cs" />
<Compile Include="ReadOnlySpan\LastIndexOf.byte.cs" />
<Compile Include="ReadOnlySpan\LastIndexOf.char.cs" />
- <Compile Include="ReadOnlySpan\LastIndexOfSequence.T.cs" />
+ <Compile Include="ReadOnlySpan\LastIndexOf.T.cs" />
<Compile Include="ReadOnlySpan\LastIndexOfSequence.byte.cs" />
<Compile Include="ReadOnlySpan\LastIndexOfSequence.char.cs" />
- <Compile Include="ReadOnlySpan\NonPortableCast.cs" />
+ <Compile Include="ReadOnlySpan\LastIndexOfSequence.T.cs" />
<Compile Include="ReadOnlySpan\Overflow.cs" />
<Compile Include="ReadOnlySpan\Overlaps.cs" />
- <Compile Include="ReadOnlySpan\SequenceEqual.T.cs" />
+ <Compile Include="ReadOnlySpan\SequenceCompareTo.bool.cs" />
+ <Compile Include="ReadOnlySpan\SequenceCompareTo.byte.cs" />
+ <Compile Include="ReadOnlySpan\SequenceCompareTo.char.cs" />
+ <Compile Include="ReadOnlySpan\SequenceCompareTo.int.cs" />
+ <Compile Include="ReadOnlySpan\SequenceCompareTo.long.cs" />
+ <Compile Include="ReadOnlySpan\SequenceCompareTo.T.cs" />
<Compile Include="ReadOnlySpan\SequenceEqual.byte.cs" />
<Compile Include="ReadOnlySpan\SequenceEqual.char.cs" />
+ <Compile Include="ReadOnlySpan\SequenceEqual.long.cs" />
+ <Compile Include="ReadOnlySpan\SequenceEqual.T.cs" />
<Compile Include="ReadOnlySpan\Slice.cs" />
- <Compile Include="ReadOnlySpan\StartsWith.T.cs" />
<Compile Include="ReadOnlySpan\StartsWith.byte.cs" />
+ <Compile Include="ReadOnlySpan\StartsWith.char.cs" />
+ <Compile Include="ReadOnlySpan\StartsWith.long.cs" />
+ <Compile Include="ReadOnlySpan\StartsWith.StringComparison.cs" />
+ <Compile Include="ReadOnlySpan\StartsWith.T.cs" />
<Compile Include="ReadOnlySpan\ToArray.cs" />
+ <Compile Include="ReadOnlySpan\ToLower.cs" />
+ <Compile Include="ReadOnlySpan\ToString.cs" />
+ <Compile Include="ReadOnlySpan\ToUpper.cs" />
+ <Compile Include="ReadOnlySpan\TrimAnyCharacter.cs" />
+ <Compile Include="ReadOnlySpan\TrimManyCharacters.cs" />
+ <Compile Include="ReadOnlySpan\TrimWhiteSpace.cs" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="Memory\AsMemory.cs" />
<Compile Include="Memory\AsReadOnlyMemory.cs" />
<Compile Include="Memory\CopyTo.cs" />
<Compile Include="Memory\CtorArray.cs" />
@@ -114,17 +163,28 @@
<Compile Include="Memory\GetHashCode.cs" />
<Compile Include="Memory\ImplicitConversion.cs" />
<Compile Include="Memory\OwnedMemory.cs" />
+ <Compile Include="Memory\Pin.cs" />
<Compile Include="Memory\Retain.cs" />
<Compile Include="Memory\Slice.cs" />
<Compile Include="Memory\Span.cs" />
<Compile Include="Memory\Strings.cs" />
<Compile Include="Memory\ToArray.cs" />
- <Compile Include="Memory\TryGetArray.cs" />
+ <Compile Include="Memory\ToString.cs" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="MemoryMarshal\AsBytesReadOnlySpan.cs" />
+ <Compile Include="MemoryMarshal\AsBytesSpan.cs" />
<Compile Include="MemoryMarshal\AsMemory.cs" />
+ <Compile Include="MemoryMarshal\CastReadOnlySpan.cs" />
+ <Compile Include="MemoryMarshal\CastSpan.cs" />
<Compile Include="MemoryMarshal\GetReference.cs" />
<Compile Include="MemoryMarshal\TryGetArray.cs" />
+ <Compile Include="MemoryMarshal\TryGetOwnedMemory.cs" />
+ <Compile Include="MemoryMarshal\TryGetString.cs" />
+ <Compile Include="MemoryMarshal\ToEnumerable.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="MemoryPool\MemoryPool.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="ReadOnlyMemory\CopyTo.cs" />
@@ -134,20 +194,19 @@
<Compile Include="ReadOnlyMemory\Equality.cs" />
<Compile Include="ReadOnlyMemory\GetHashCode.cs" />
<Compile Include="ReadOnlyMemory\ImplicitConversion.cs" />
+ <Compile Include="ReadOnlyMemory\Pin.cs" />
<Compile Include="ReadOnlyMemory\Retain.cs" />
<Compile Include="ReadOnlyMemory\Slice.cs" />
<Compile Include="ReadOnlyMemory\Span.cs" />
<Compile Include="ReadOnlyMemory\Strings.cs" />
<Compile Include="ReadOnlyMemory\ToArray.cs" />
+ <Compile Include="ReadOnlyMemory\ToString.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="Binary\BinaryReaderUnitTests.cs" />
<Compile Include="Binary\BinaryWriterUnitTests.cs" />
</ItemGroup>
<ItemGroup>
- <Compile Include="..\Common\src\System\MutableDecimal.cs" />
- </ItemGroup>
- <ItemGroup>
<Compile Include="ParsersAndFormatters\Formatter\FormatterTestData.cs" />
<Compile Include="ParsersAndFormatters\Formatter\FormatterTests.cs" />
<Compile Include="ParsersAndFormatters\Formatter\FormatterTests.Negative.cs" />
@@ -177,6 +236,14 @@
<Compile Include="Base64\Base64TestHelper.cs" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="$(CommonTestPath)\System\Buffers\NativeOwnedMemory.cs">
+ <Link>Common\System\Buffers\NativeOwnedMemory.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\MutableDecimal.cs">
+ <Link>Common\System\MutableDecimal.cs</Link>
+ </Compile>
+ </ItemGroup>
+ <ItemGroup>
<EmbeddedResource Include="Resources\$(AssemblyName).rd.xml" />
</ItemGroup>
<ItemGroup>
diff --git a/src/System.Memory/tests/TestHelpers.cs b/src/System.Memory/tests/TestHelpers.cs
index a4829d7fc3..dc4d1f90cd 100644
--- a/src/System.Memory/tests/TestHelpers.cs
+++ b/src/System.Memory/tests/TestHelpers.cs
@@ -8,6 +8,7 @@ using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using static System.Buffers.Binary.BinaryPrimitives;
+using System.Text;
namespace System
{
@@ -175,7 +176,7 @@ namespace System
public static void Validate<T>(Span<byte> span, T value) where T : struct
{
- T read = ReadMachineEndian<T>(span);
+ T read = MemoryMarshal.Read<T>(span);
Assert.Equal(value, read);
span.Clear();
}
@@ -238,6 +239,17 @@ namespace System
return spanLE;
}
+ public static string BuildString(int length, int seed)
+ {
+ Random rnd = new Random(seed);
+ var builder = new StringBuilder();
+ for (int i = 0; i < length; i++)
+ {
+ builder.Append((char)rnd.Next(65, 91));
+ }
+ return builder.ToString();
+ }
+
[StructLayout(LayoutKind.Explicit)]
public struct TestStructExplicit
{
@@ -285,6 +297,20 @@ namespace System
public string S;
}
+#pragma warning disable 0649 //Field 'SpanTests.InnerStruct.J' is never assigned to, and will always have its default value 0
+ internal struct StructWithReferences
+ {
+ public int I;
+ public InnerStruct Inner;
+ }
+
+ internal struct InnerStruct
+ {
+ public int J;
+ public object O;
+ }
+#pragma warning restore 0649 //Field 'SpanTests.InnerStruct.J' is never assigned to, and will always have its default value 0
+
public enum TestEnum
{
e0,
@@ -366,6 +392,12 @@ namespace System
}
}
}
+
+ // @todo: https://github.com/dotnet/corefx/issues/26894 - these emulate MemoryExtension apis that we removed. Clean up the callsites and remove this class.
+ public static ReadOnlySpan<T> AsReadOnlySpan<T>(this Span<T> span) => span;
+ public static ReadOnlySpan<T> AsReadOnlySpan<T>(this T[] array) => new ReadOnlySpan<T>(array);
+ public static ReadOnlySpan<T> AsReadOnlySpan<T>(this ArraySegment<T> segment) => new ReadOnlySpan<T>(segment.Array, segment.Offset, segment.Count);
+ public static ReadOnlyMemory<T> AsReadOnlyMemory<T>(this Memory<T> memory) => memory;
}
}
diff --git a/src/System.Net.Http.WinHttpHandler/src/Resources/Strings.resx b/src/System.Net.Http.WinHttpHandler/src/Resources/Strings.resx
index 846190e58d..5ce718aaab 100644
--- a/src/System.Net.Http.WinHttpHandler/src/Resources/Strings.resx
+++ b/src/System.Net.Http.WinHttpHandler/src/Resources/Strings.resx
@@ -121,6 +121,9 @@
<data name="net_http_content_stream_already_read" xml:space="preserve">
<value>The stream was already consumed. It cannot be read again.</value>
</data>
+ <data name="net_http_winhttp_error" xml:space="preserve">
+ <value>Error {0} calling {1}, '{2}'.</value>
+ </data>
<data name="PlatformNotSupported_WinHttpHandler" xml:space="preserve">
<value>WinHttpHandler is only supported on .NET Framework and .NET Core runtimes on Windows. It is not supported for Windows Store Applications (UWP) or Unix platforms.</value>
</data>
diff --git a/src/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.csproj b/src/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.csproj
index 78b6c50387..6ae87d4fb2 100644
--- a/src/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.csproj
+++ b/src/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.csproj
@@ -10,6 +10,7 @@
<!-- Although we have a NS configuration, the actual UWP implementation is a shim over WinRT: so just validate against OneCore -->
<UWPCompatible>false</UWPCompatible>
<IncludeDllSafeSearchPathAttribute>true</IncludeDllSafeSearchPathAttribute>
+ <ILLinkClearInitLocals>true</ILLinkClearInitLocals>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Release|AnyCPU'" />
@@ -42,6 +43,7 @@
<ItemGroup>
<Reference Include="System.Buffers" />
<Reference Include="System.Diagnostics.DiagnosticSource" />
+ <Reference Include="System.Memory" />
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' == 'net46' OR '$(TargetGroup)' == 'netfx'">
<Reference Include="mscorlib" />
diff --git a/src/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.msbuild b/src/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.msbuild
index eca0378858..043e9c4bd8 100644
--- a/src/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.msbuild
+++ b/src/System.Net.Http.WinHttpHandler/src/System.Net.Http.WinHttpHandler.msbuild
@@ -23,7 +23,6 @@
<CompileItem Include="$(CommonPath)\System\Net\UriScheme.cs" />
<CompileItem Include="$(CommonPath)\System\Net\Http\HttpHandlerDefaults.cs" />
<CompileItem Include="$(CommonPath)\System\Net\Http\NoWriteNoSeekStreamContent.cs" />
- <CompileItem Include="$(CommonPath)\System\Net\Http\WinHttpException.cs" />
<CompileItem Include="$(CommonPath)\System\Net\Security\CertificateHelper.cs" />
<CompileItem Include="$(CommonPath)\System\Net\Security\CertificateHelper.Windows.cs" />
<CompileItem Include="$(CommonPath)\System\Runtime\ExceptionServices\ExceptionStackTrace.cs" />
@@ -33,6 +32,7 @@
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpCertificateHelper.cs" />
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpChannelBinding.cs" />
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpCookieContainerAdapter.cs" />
+ <CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpException.cs" />
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpHandler.cs" />
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpRequestCallback.cs" />
<CompileItem Include="$(MSBuildThisFileDirectory)\System\Net\Http\WinHttpRequestState.cs" />
diff --git a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpAuthHelper.cs b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpAuthHelper.cs
index 0635ed2ec2..ab716d47ad 100644
--- a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpAuthHelper.cs
+++ b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpAuthHelper.cs
@@ -102,7 +102,7 @@ namespace System.Net.Http
// But we can validate with assert.
Debug.Assert(authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_SERVER);
- serverAuthScheme = ChooseAuthScheme(supportedSchemes);
+ serverAuthScheme = ChooseAuthScheme(supportedSchemes, state.RequestMessage.RequestUri, state.ServerCredentials);
if (serverAuthScheme != 0)
{
if (SetWinHttpCredential(
@@ -155,7 +155,7 @@ namespace System.Net.Http
// But we can validate with assert.
Debug.Assert(authTarget == Interop.WinHttp.WINHTTP_AUTH_TARGET_PROXY);
- proxyAuthScheme = ChooseAuthScheme(supportedSchemes);
+ proxyAuthScheme = ChooseAuthScheme(supportedSchemes, state.Proxy.GetProxy(state.RequestMessage.RequestUri), proxyCreds);
state.RetryRequest = true;
break;
@@ -296,7 +296,7 @@ namespace System.Net.Http
Interop.WinHttp.WINHTTP_OPTION_AUTOLOGON_POLICY,
ref optionData))
{
- WinHttpException.ThrowExceptionUsingLastError();
+ WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpSetOption));
}
}
@@ -365,17 +365,22 @@ namespace System.Net.Http
password,
IntPtr.Zero))
{
- WinHttpException.ThrowExceptionUsingLastError();
+ WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpSetCredentials));
}
return true;
}
- private static uint ChooseAuthScheme(uint supportedSchemes)
+ private static uint ChooseAuthScheme(uint supportedSchemes, Uri uri, ICredentials credentials)
{
+ if (credentials == null)
+ {
+ return 0;
+ }
+
foreach (uint authScheme in s_authSchemePriorityOrder)
{
- if ((supportedSchemes & authScheme) != 0)
+ if ((supportedSchemes & authScheme) != 0 && credentials.GetCredential(uri, s_authSchemeStringMapping[authScheme]) != null)
{
return authScheme;
}
diff --git a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpCookieContainerAdapter.cs b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpCookieContainerAdapter.cs
index 824d9cc776..5455255a49 100644
--- a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpCookieContainerAdapter.cs
+++ b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpCookieContainerAdapter.cs
@@ -61,7 +61,7 @@ namespace System.Net.Http
int lastError = Marshal.GetLastWin32Error();
if (lastError != Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND)
{
- throw WinHttpException.CreateExceptionUsingError(lastError);
+ throw WinHttpException.CreateExceptionUsingError(lastError, nameof(Interop.WinHttp.WinHttpAddRequestHeaders));
}
}
@@ -76,7 +76,7 @@ namespace System.Net.Http
(uint)cookieHeader.Length,
Interop.WinHttp.WINHTTP_ADDREQ_FLAG_ADD))
{
- WinHttpException.ThrowExceptionUsingLastError();
+ WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpAddRequestHeaders));
}
}
}
diff --git a/src/Common/src/System/Net/Http/WinHttpException.cs b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpException.cs
index d77e347135..bb7956762f 100644
--- a/src/Common/src/System/Net/Http/WinHttpException.cs
+++ b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpException.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.ComponentModel;
+using System.Diagnostics;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
@@ -39,37 +40,41 @@ namespace System.Net.Http
}
}
- public static void ThrowExceptionUsingLastError()
+ public static void ThrowExceptionUsingLastError(string nameOfCalledFunction)
{
- throw CreateExceptionUsingLastError();
+ throw CreateExceptionUsingLastError(nameOfCalledFunction);
}
- public static WinHttpException CreateExceptionUsingLastError()
+ public static WinHttpException CreateExceptionUsingLastError(string nameOfCalledFunction)
{
int lastError = Marshal.GetLastWin32Error();
- return CreateExceptionUsingError(lastError);
+ return CreateExceptionUsingError(lastError, nameOfCalledFunction);
}
- public static WinHttpException CreateExceptionUsingError(int error)
+ public static WinHttpException CreateExceptionUsingError(int error, string nameOfCalledFunction)
{
- var e = new WinHttpException(error, GetErrorMessage(error));
+ var e = new WinHttpException(error, GetErrorMessage(error, nameOfCalledFunction));
ExceptionStackTrace.AddCurrentStack(e);
return e;
}
- public static WinHttpException CreateExceptionUsingError(int error, Exception innerException)
+ public static WinHttpException CreateExceptionUsingError(int error, string nameOfCalledFunction, Exception innerException)
{
- var e = new WinHttpException(error, GetErrorMessage(error), innerException);
+ var e = new WinHttpException(error, GetErrorMessage(error, nameOfCalledFunction), innerException);
ExceptionStackTrace.AddCurrentStack(e);
return e;
}
- public static string GetErrorMessage(int error)
+ public static string GetErrorMessage(int error, string nameOfCalledFunction)
{
+ Debug.Assert(!string.IsNullOrEmpty(nameOfCalledFunction));
+
// Look up specific error message in WINHTTP.DLL since it is not listed in default system resources
// and thus can't be found by default .Net interop.
IntPtr moduleHandle = Interop.Kernel32.GetModuleHandle(Interop.Libraries.WinHttp);
- return Interop.Kernel32.GetMessage(moduleHandle, error);
+ string httpError = Interop.Kernel32.GetMessage(moduleHandle, error);
+
+ return SR.Format(SR.net_http_winhttp_error, error, nameOfCalledFunction, httpError);
}
}
}
diff --git a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs
index aab6a125c8..65ae9c528a 100644
--- a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs
+++ b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs
@@ -661,7 +661,7 @@ namespace System.Net.Http
(uint)requestHeadersBuffer.Length,
Interop.WinHttp.WINHTTP_ADDREQ_FLAG_ADD))
{
- WinHttpException.ThrowExceptionUsingLastError();
+ WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpAddRequestHeaders));
}
}
@@ -728,7 +728,7 @@ namespace System.Net.Http
WinHttpTraceHelper.Trace("WinHttpHandler.EnsureSessionHandleExists: error={0}", lastError);
if (lastError != Interop.WinHttp.ERROR_INVALID_PARAMETER)
{
- ThrowOnInvalidHandle(sessionHandle);
+ ThrowOnInvalidHandle(sessionHandle, nameof(Interop.WinHttp.WinHttpOpen));
}
// We must be running on a platform earlier than Win8.1/Win2K12R2 which doesn't support
@@ -741,7 +741,7 @@ namespace System.Net.Http
_proxyHelper.ManualSettingsOnly ? _proxyHelper.Proxy : Interop.WinHttp.WINHTTP_NO_PROXY_NAME,
_proxyHelper.ManualSettingsOnly ? _proxyHelper.ProxyBypass : Interop.WinHttp.WINHTTP_NO_PROXY_BYPASS,
(int)Interop.WinHttp.WINHTTP_FLAG_ASYNC);
- ThrowOnInvalidHandle(sessionHandle);
+ ThrowOnInvalidHandle(sessionHandle, nameof(Interop.WinHttp.WinHttpOpen));
}
uint optionAssuredNonBlockingTrue = 1; // TRUE
@@ -757,7 +757,7 @@ namespace System.Net.Http
int lastError = Marshal.GetLastWin32Error();
if (lastError != Interop.WinHttp.ERROR_WINHTTP_INVALID_OPTION)
{
- throw WinHttpException.CreateExceptionUsingError(lastError);
+ throw WinHttpException.CreateExceptionUsingError(lastError, nameof(Interop.WinHttp.WinHttpSetOption));
}
}
@@ -788,7 +788,7 @@ namespace System.Net.Http
state.RequestMessage.RequestUri.Host,
(ushort)state.RequestMessage.RequestUri.Port,
0);
- ThrowOnInvalidHandle(connectHandle);
+ ThrowOnInvalidHandle(connectHandle, nameof(Interop.WinHttp.WinHttpConnect));
connectHandle.SetParentHandle(_sessionHandle);
// Try to use the requested version if a known/supported version was explicitly requested.
@@ -821,7 +821,7 @@ namespace System.Net.Http
Interop.WinHttp.WINHTTP_NO_REFERER,
Interop.WinHttp.WINHTTP_DEFAULT_ACCEPT_TYPES,
flags);
- ThrowOnInvalidHandle(state.RequestHandle);
+ ThrowOnInvalidHandle(state.RequestHandle, nameof(Interop.WinHttp.WinHttpOpenRequest));
state.RequestHandle.SetParentHandle(connectHandle);
// Set callback function.
@@ -888,6 +888,16 @@ namespace System.Net.Http
HttpResponseMessage responseMessage = WinHttpResponseParser.CreateResponseMessage(state, _doManualDecompressionCheck);
state.Tcs.TrySetResult(responseMessage);
+
+ // HttpStatusCode cast is needed for 308 Moved Permenantly, which we support but is not included in NetStandard status codes.
+ if (WinHttpTraceHelper.IsTraceEnabled() &&
+ ((responseMessage.StatusCode >= HttpStatusCode.MultipleChoices && responseMessage.StatusCode <= HttpStatusCode.SeeOther) ||
+ (responseMessage.StatusCode >= HttpStatusCode.RedirectKeepVerb && responseMessage.StatusCode <= (HttpStatusCode)308)) &&
+ state.RequestMessage.RequestUri.Scheme == Uri.UriSchemeHttps && responseMessage.Headers.Location?.Scheme == Uri.UriSchemeHttp)
+ {
+ WinHttpTraceHelper.Trace("WinHttpHandler.SendAsync: Insecure https to http redirect from {0} to {1} blocked.",
+ state.RequestMessage.RequestUri.ToString(), responseMessage.Headers.Location.ToString());
+ }
}
catch (Exception ex)
{
@@ -947,7 +957,7 @@ namespace System.Net.Http
(int)_sendTimeout.TotalMilliseconds,
(int)_receiveHeadersTimeout.TotalMilliseconds))
{
- WinHttpException.ThrowExceptionUsingLastError();
+ WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpSetTimeouts));
}
}
@@ -1204,7 +1214,7 @@ namespace System.Net.Http
option,
ref optionData))
{
- WinHttpException.ThrowExceptionUsingLastError();
+ WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpSetOption));
}
}
@@ -1217,7 +1227,7 @@ namespace System.Net.Http
optionData,
(uint)optionData.Length))
{
- WinHttpException.ThrowExceptionUsingLastError();
+ WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpSetOption));
}
}
@@ -1234,7 +1244,7 @@ namespace System.Net.Http
optionData,
optionSize))
{
- WinHttpException.ThrowExceptionUsingLastError();
+ WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpSetOption));
}
}
@@ -1304,18 +1314,18 @@ namespace System.Net.Http
int lastError = Marshal.GetLastWin32Error();
if (lastError != Interop.WinHttp.ERROR_INVALID_HANDLE) // Ignore error if handle was already closed.
{
- throw WinHttpException.CreateExceptionUsingError(lastError);
+ throw WinHttpException.CreateExceptionUsingError(lastError, nameof(Interop.WinHttp.WinHttpSetStatusCallback));
}
}
}
- private void ThrowOnInvalidHandle(SafeWinHttpHandle handle)
+ private void ThrowOnInvalidHandle(SafeWinHttpHandle handle, string nameOfCalledFunction)
{
if (handle.IsInvalid)
{
int lastError = Marshal.GetLastWin32Error();
WinHttpTraceHelper.Trace("WinHttpHandler.ThrowOnInvalidHandle: error={0}", lastError);
- throw WinHttpException.CreateExceptionUsingError(lastError);
+ throw WinHttpException.CreateExceptionUsingError(lastError, nameOfCalledFunction);
}
}
@@ -1333,11 +1343,13 @@ namespace System.Net.Http
0,
state.ToIntPtr()))
{
- // Dispose (which will unpin) the state object. Since this failed, WinHTTP won't associate
- // our context value (state object) to the request handle. And thus we won't get HANDLE_CLOSING
- // notifications which would normally cause the state object to be unpinned and disposed.
+ // WinHTTP doesn't always associate our context value (state object) to the request handle.
+ // And thus we might not get a HANDLE_CLOSING notification which would normally cause the
+ // state object to be unpinned and disposed. So, we manually dispose the request handle and
+ // state object here.
+ state.RequestHandle.Dispose();
state.Dispose();
- WinHttpException.ThrowExceptionUsingLastError();
+ WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpSendRequest));
}
}
@@ -1361,7 +1373,7 @@ namespace System.Net.Http
{
if (!Interop.WinHttp.WinHttpReceiveResponse(state.RequestHandle, IntPtr.Zero))
{
- throw WinHttpException.CreateExceptionUsingLastError();
+ throw WinHttpException.CreateExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpReceiveResponse));
}
}
diff --git a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs
index 995f306435..4d2a989667 100644
--- a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs
+++ b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestCallback.cs
@@ -110,8 +110,19 @@ namespace System.Net.Http
}
catch (Exception ex)
{
- Interop.WinHttp.WinHttpCloseHandle(handle);
state.SavedException = ex;
+ if (state.RequestHandle != null)
+ {
+ // Since we got a fatal error processing the request callback,
+ // we need to close the WinHttp request handle in order to
+ // abort the currently executing WinHttp async operation.
+ //
+ // We must always call Dispose() against the SafeWinHttpHandle
+ // wrapper and never close directly the raw WinHttp handle.
+ // The SafeWinHttpHandle wrapper is thread-safe and guarantees
+ // calling the underlying WinHttpCloseHandle() function only once.
+ state.RequestHandle.Dispose();
+ }
}
}
@@ -214,6 +225,10 @@ namespace System.Net.Http
{
state.ServerCredentials = null;
}
+
+ // Similarly, we need to clear any Auth headers that were added to the request manually or
+ // through the default headers.
+ ResetAuthRequestHeaders(state);
}
private static void OnRequestSendingRequest(WinHttpRequestState state)
@@ -256,7 +271,7 @@ namespace System.Net.Http
return;
}
- throw WinHttpException.CreateExceptionUsingError(lastError);
+ throw WinHttpException.CreateExceptionUsingError(lastError, "WINHTTP_CALLBACK_STATUS_SENDING_REQUEST/WinHttpQueryOption");
}
// Get any additional certificates sent from the remote server during the TLS/SSL handshake.
@@ -291,7 +306,7 @@ namespace System.Net.Http
catch (Exception ex)
{
throw WinHttpException.CreateExceptionUsingError(
- (int)Interop.WinHttp.ERROR_WINHTTP_SECURE_FAILURE, ex);
+ (int)Interop.WinHttp.ERROR_WINHTTP_SECURE_FAILURE, "X509Chain.Build", ex);
}
finally
{
@@ -306,7 +321,7 @@ namespace System.Net.Http
if (!result)
{
throw WinHttpException.CreateExceptionUsingError(
- (int)Interop.WinHttp.ERROR_WINHTTP_SECURE_FAILURE);
+ (int)Interop.WinHttp.ERROR_WINHTTP_SECURE_FAILURE, "ServerCertificateValidationCallback");
}
}
}
@@ -317,7 +332,7 @@ namespace System.Net.Http
Debug.Assert(state != null, "OnRequestError: state is null");
- Exception innerException = WinHttpException.CreateExceptionUsingError(unchecked((int)asyncResult.dwError));
+ Exception innerException = WinHttpException.CreateExceptionUsingError(unchecked((int)asyncResult.dwError), "WINHTTP_CALLBACK_STATUS_REQUEST_ERROR");
switch (unchecked((uint)asyncResult.dwResult.ToInt32()))
{
@@ -404,5 +419,25 @@ namespace System.Net.Http
break;
}
}
+
+ private static void ResetAuthRequestHeaders(WinHttpRequestState state)
+ {
+ const string AuthHeaderNameWithColon = "Authorization:";
+ SafeWinHttpHandle requestHandle = state.RequestHandle;
+
+ // Clear auth headers.
+ if (!Interop.WinHttp.WinHttpAddRequestHeaders(
+ requestHandle,
+ AuthHeaderNameWithColon,
+ (uint)AuthHeaderNameWithColon.Length,
+ Interop.WinHttp.WINHTTP_ADDREQ_FLAG_REPLACE))
+ {
+ int lastError = Marshal.GetLastWin32Error();
+ if (lastError != Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND)
+ {
+ throw WinHttpException.CreateExceptionUsingError(lastError, "WINHTTP_CALLBACK_STATUS_REDIRECT/WinHttpAddRequestHeaders");
+ }
+ }
+ }
}
}
diff --git a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestStream.cs b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestStream.cs
index a1fc3aef65..034fc56427 100644
--- a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestStream.cs
+++ b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpRequestStream.cs
@@ -249,7 +249,7 @@ namespace System.Net.Http
IntPtr.Zero))
{
_state.TcsInternalWriteDataToRequestStream.TrySetException(
- new IOException(SR.net_http_io_write, WinHttpException.CreateExceptionUsingLastError()));
+ new IOException(SR.net_http_io_write, WinHttpException.CreateExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpWriteData))));
}
}
diff --git a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseParser.cs b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseParser.cs
index 16af2adecc..18e655f06b 100644
--- a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseParser.cs
+++ b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseParser.cs
@@ -92,7 +92,7 @@ namespace System.Net.Http
}
}
- response.Content = new NoWriteNoSeekStreamContent(decompressedStream, state.CancellationToken);
+ response.Content = new NoWriteNoSeekStreamContent(decompressedStream);
response.RequestMessage = request;
// Parse raw response headers and place them into response message.
@@ -127,7 +127,7 @@ namespace System.Net.Http
ref resultSize,
IntPtr.Zero))
{
- WinHttpException.ThrowExceptionUsingLastError();
+ WinHttpException.ThrowExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpQueryHeaders));
}
return result;
@@ -189,7 +189,7 @@ namespace System.Net.Http
return GetResponseHeader(requestHandle, infoLevel, ref buffer, ref index, out headerValue);
}
- throw WinHttpException.CreateExceptionUsingError(lastError);
+ throw WinHttpException.CreateExceptionUsingError(lastError, nameof(Interop.WinHttp.WinHttpQueryHeaders));
}
/// <summary>
@@ -216,7 +216,7 @@ namespace System.Net.Http
Debug.Assert(lastError != Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER, "buffer must be of sufficient size.");
- throw WinHttpException.CreateExceptionUsingError(lastError);
+ throw WinHttpException.CreateExceptionUsingError(lastError, nameof(Interop.WinHttp.WinHttpQueryHeaders));
}
}
@@ -240,7 +240,7 @@ namespace System.Net.Http
if (lastError != Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER)
{
- throw WinHttpException.CreateExceptionUsingError(lastError);
+ throw WinHttpException.CreateExceptionUsingError(lastError, nameof(Interop.WinHttp.WinHttpQueryHeaders));
}
}
diff --git a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseStream.cs b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseStream.cs
index 2c3af3458c..a6aa8e4448 100644
--- a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseStream.cs
+++ b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseStream.cs
@@ -121,7 +121,7 @@ namespace System.Net.Http
{
if (!Interop.WinHttp.WinHttpQueryDataAvailable(_requestHandle, IntPtr.Zero))
{
- throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError());
+ throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpQueryDataAvailable)));
}
}
int bytesAvailable = await _state.LifecycleAwaitable;
@@ -137,7 +137,7 @@ namespace System.Net.Http
{
if (!Interop.WinHttp.WinHttpReadData(_requestHandle, Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0), (uint)Math.Min(bytesAvailable, buffer.Length), IntPtr.Zero))
{
- throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError());
+ throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpReadData)));
}
}
int bytesRead = await _state.LifecycleAwaitable;
@@ -222,7 +222,7 @@ namespace System.Net.Http
Debug.Assert(!_requestHandle.IsInvalid);
if (!Interop.WinHttp.WinHttpQueryDataAvailable(_requestHandle, IntPtr.Zero))
{
- throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError());
+ throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpQueryDataAvailable)));
}
}
@@ -237,7 +237,7 @@ namespace System.Net.Http
(uint)Math.Min(bytesAvailable, count),
IntPtr.Zero))
{
- throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError());
+ throw new IOException(SR.net_http_io_read, WinHttpException.CreateExceptionUsingLastError(nameof(Interop.WinHttp.WinHttpReadData)));
}
}
diff --git a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpTraceHelper.cs b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpTraceHelper.cs
index 07aaa39f84..5e2ff60b43 100644
--- a/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpTraceHelper.cs
+++ b/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpTraceHelper.cs
@@ -138,14 +138,14 @@ namespace System.Net.Http
uint apiIndex = (uint)asyncResult.dwResult.ToInt32();
uint error = asyncResult.dwError;
-
+ string apiName = GetNameFromApiIndex(apiIndex);
WriteLine(
"{0}: api={1}, error={2}({3}) \"{4}\"",
message,
- GetNameFromApiIndex(apiIndex),
+ apiName,
GetNameFromError(error),
error,
- WinHttpException.GetErrorMessage((int)error));
+ WinHttpException.GetErrorMessage((int)error, apiName));
}
private static void WriteLine(string message)
diff --git a/src/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs b/src/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs
index c15e689386..cf5812a1d7 100644
--- a/src/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs
+++ b/src/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs
@@ -16,6 +16,8 @@ using Xunit.Abstractions;
// WinHttpHandler is a class and not a namespace and can't be part of namespace paths.
namespace System.Net.Http.WinHttpHandlerFunctional.Tests
{
+ using Configuration = System.Net.Test.Common.Configuration;
+
// Note: Disposing the HttpClient object automatically disposes the handler within. So, it is not necessary
// to separately Dispose (or have a 'using' statement) for the handler.
[SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "WinHttpHandler not supported on UAP")]
@@ -113,6 +115,25 @@ namespace System.Net.Http.WinHttpHandlerFunctional.Tests
}
}
+ [Fact]
+ public async Task SendAsync_GetUsingChunkedEncoding_ThrowsHttpRequestException()
+ {
+ // WinHTTP doesn't support GET requests with a request body that uses
+ // chunked encoding. This test pins this behavior and verifies that the
+ // error handling is working correctly.
+ var server = new Uri("http://www.microsoft.com"); // No network I/O actually happens.
+ var request = new HttpRequestMessage(HttpMethod.Get, server);
+ request.Content = new StringContent("Request body");
+ request.Headers.TransferEncodingChunked = true;
+
+ var handler = new WinHttpHandler();
+ using (HttpClient client = new HttpClient(handler))
+ {
+ HttpRequestException ex = await Assert.ThrowsAsync<HttpRequestException>(() => client.SendAsync(request));
+ _output.WriteLine(ex.ToString());
+ }
+ }
+
public static bool JsonMessageContainsKeyValue(string message, string key, string value)
{
// TODO: Merge with System.Net.Http TestHelper class as part of GitHub Issue #4989.
diff --git a/src/System.Net.Http.WinHttpHandler/tests/UnitTests/System.Net.Http.WinHttpHandler.Unit.Tests.csproj b/src/System.Net.Http.WinHttpHandler/tests/UnitTests/System.Net.Http.WinHttpHandler.Unit.Tests.csproj
index 871e66692e..31adaf06e1 100644
--- a/src/System.Net.Http.WinHttpHandler/tests/UnitTests/System.Net.Http.WinHttpHandler.Unit.Tests.csproj
+++ b/src/System.Net.Http.WinHttpHandler/tests/UnitTests/System.Net.Http.WinHttpHandler.Unit.Tests.csproj
@@ -73,9 +73,6 @@
<Compile Include="$(CommonPath)\System\Net\Http\NoWriteNoSeekStreamContent.cs">
<Link>Common\System\Net\Http\NoWriteNoSeekStreamContent.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Net\Http\WinHttpException.cs">
- <Link>Common\System\Net\Http\WinHttpException.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\System\Net\Security\CertificateHelper.cs">
<Link>Common\System\Net\Security\CertificateHelper.cs</Link>
</Compile>
@@ -103,6 +100,9 @@
<Compile Include="..\..\src\System\Net\Http\WinHttpCookieContainerAdapter.cs">
<Link>ProductionCode\WinHttpCookieContainerAdapter.cs</Link>
</Compile>
+ <Compile Include="..\..\src\System\Net\Http\WinHttpException.cs">
+ <Link>ProductionCode\WinHttpException.cs</Link>
+ </Compile>
<Compile Include="..\..\src\System\Net\Http\WinHttpHandler.cs">
<Link>ProductionCode\WinHttpHandler.cs</Link>
</Compile>
diff --git a/src/System.Net.Http/ref/System.Net.Http.cs b/src/System.Net.Http/ref/System.Net.Http.cs
index 5bfa47a7e3..02cb8fa668 100644
--- a/src/System.Net.Http/ref/System.Net.Http.cs
+++ b/src/System.Net.Http/ref/System.Net.Http.cs
@@ -236,6 +236,34 @@ namespace System.Net.Http
protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext context) => throw null;
protected internal override bool TryComputeLength(out long length) => throw null;
}
+#if !uap
+ public sealed class SocketsHttpHandler : HttpMessageHandler
+ {
+ public SocketsHttpHandler() { }
+ public bool AllowAutoRedirect { get { throw null; } set { } }
+ public System.Net.DecompressionMethods AutomaticDecompression { get { throw null; } set { } }
+ public System.TimeSpan ConnectTimeout { get; set; }
+ public System.Net.CookieContainer CookieContainer { get { throw null; } set { } }
+ public System.Net.ICredentials Credentials { get { throw null; } set { } }
+ public System.Net.ICredentials DefaultProxyCredentials { get { throw null; } set { } }
+ public System.TimeSpan Expect100ContinueTimeout { get; set; }
+ public int MaxAutomaticRedirections { get { throw null; } set { } }
+ public int MaxConnectionsPerServer { get { throw null; } set { } }
+ public int MaxResponseDrainSize { get { throw null; } set { } }
+ public int MaxResponseHeadersLength { get { throw null; } set { } }
+ public bool PreAuthenticate { get { throw null; } set { } }
+ public System.TimeSpan PooledConnectionIdleTimeout { get { throw null; } set { } }
+ public System.TimeSpan PooledConnectionLifetime { get { throw null; } set { } }
+ public System.Collections.Generic.IDictionary<string, object> Properties { get { throw null; } }
+ public System.Net.IWebProxy Proxy { get { throw null; } set { } }
+ public System.TimeSpan ResponseDrainTimeout { get { throw null; } set { } }
+ public System.Net.Security.SslClientAuthenticationOptions SslOptions { get { throw null; } set { } }
+ public bool UseCookies { get { throw null; } set { } }
+ public bool UseProxy { get { throw null; } set { } }
+ protected override void Dispose(bool disposing) { }
+ protected internal override System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage> SendAsync(System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) { throw null; }
+ }
+#endif
public partial class StreamContent : System.Net.Http.HttpContent
{
public StreamContent(System.IO.Stream content) { }
diff --git a/src/System.Net.Http/ref/System.Net.Http.csproj b/src/System.Net.Http/ref/System.Net.Http.csproj
index bc043b82d7..874d233f8b 100644
--- a/src/System.Net.Http/ref/System.Net.Http.csproj
+++ b/src/System.Net.Http/ref/System.Net.Http.csproj
@@ -3,6 +3,7 @@
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
<ProjectGuid>{132BF813-FC40-4D39-8B6F-E55D7633F0ED}</ProjectGuid>
+ <DefineConstants Condition="'$(TargetGroup)' == 'uap'">$(DefineConstants);uap</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
@@ -16,6 +17,7 @@
<ProjectReference Include="..\..\System.Threading.Tasks\ref\System.Threading.Tasks.csproj" />
<ProjectReference Include="..\..\System.IO\ref\System.IO.csproj" />
<ProjectReference Include="..\..\System.Net.Primitives\ref\System.Net.Primitives.csproj" />
+ <ProjectReference Include="..\..\System.Net.Security\ref\System.Net.Security.csproj" />
<ProjectReference Include="..\..\System.Security.Cryptography.X509Certificates\ref\System.Security.Cryptography.X509Certificates.csproj" />
<ProjectReference Include="..\..\System.Text.Encoding\ref\System.Text.Encoding.csproj" />
</ItemGroup>
diff --git a/src/System.Net.Http/src/ILLinkTrim.xml b/src/System.Net.Http/src/ILLinkTrim.xml
index bfe2004834..3957caf8ea 100644
--- a/src/System.Net.Http/src/ILLinkTrim.xml
+++ b/src/System.Net.Http/src/ILLinkTrim.xml
@@ -3,4 +3,4 @@
<!-- Anonymous types are used with DiagnosticSource logging and subscribers reflect over those, calling their public getters. -->
<type fullname="*f__AnonymousType*" />
</assembly>
-</linker> \ No newline at end of file
+</linker>
diff --git a/src/System.Net.Http/src/MatchingRefApiCompatBaseline.uap.txt b/src/System.Net.Http/src/MatchingRefApiCompatBaseline.uap.txt
new file mode 100644
index 0000000000..a6fe8a354e
--- /dev/null
+++ b/src/System.Net.Http/src/MatchingRefApiCompatBaseline.uap.txt
@@ -0,0 +1,4 @@
+Compat issues with assembly System.Net.Http:
+TypesMustExist : Type 'System.Net.Internal.Cookie' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.Net.Internal.CookieException' does not exist in the implementation but it does exist in the contract.
+Total Issues: 2
diff --git a/src/System.Net.Http/src/Resources/Strings.resx b/src/System.Net.Http/src/Resources/Strings.resx
index ae1716b441..b8cdb1d8a1 100644
--- a/src/System.Net.Http/src/Resources/Strings.resx
+++ b/src/System.Net.Http/src/Resources/Strings.resx
@@ -336,6 +336,9 @@
<data name="net_http_response_headers_exceeded_length" xml:space="preserve">
<value>The HTTP response headers length exceeded the set limit of {0} bytes.</value>
</data>
+ <data name="ArgumentOutOfRange_NeedNonNegativeNum" xml:space="preserve">
+ <value>Non-negative number required.</value>
+ </data>
<data name="ArgumentOutOfRange_NeedPosNum" xml:space="preserve">
<value>Positive number required.</value>
</data>
@@ -348,14 +351,20 @@
<data name="ObjectDisposed_StreamClosed" xml:space="preserve">
<value>Can not access a closed Stream.</value>
</data>
- <data name="net_http_libcurl_callback_notsupported" xml:space="preserve">
- <value>The handler does not support custom handling of certificates with this combination of libcurl ({0}) and its SSL backend ("{1}").</value>
+ <data name="net_http_libcurl_callback_notsupported_sslbackend" xml:space="preserve">
+ <value>The handler does not support custom handling of certificates with this combination of libcurl ({0}) and its SSL backend ("{1}"). An SSL backend based on "{2}" is required. Consider using System.Net.Http.SocketsHttpHandler.</value>
+ </data>
+ <data name="net_http_libcurl_callback_notsupported_os" xml:space="preserve">
+ <value>The handler does not support custom handling of certificates on this operating system. Consider using System.Net.Http.SocketsHttpHandler.</value>
+ </data>
+ <data name="net_http_libcurl_clientcerts_notsupported_sslbackend" xml:space="preserve">
+ <value>The handler does not support client authentication certificates with this combination of libcurl ({0}) and its SSL backend ("{1}"). An SSL backend based on "{2}" is required. Consider using System.Net.Http.SocketsHttpHandler.</value>
</data>
- <data name="net_http_libcurl_clientcerts_notsupported" xml:space="preserve">
- <value>The handler does not support client authentication certificates with this combination of libcurl ({0}) and its SSL backend ("{1}").</value>
+ <data name="net_http_libcurl_clientcerts_notsupported_os" xml:space="preserve">
+ <value>The handler does not support client authentication certificates on this operating system. Consider using System.Net.Http.SocketsHttpHandler.</value>
</data>
- <data name="net_http_libcurl_revocation_notsupported" xml:space="preserve">
- <value>The handler does not support changing revocation settings with this combination of libcurl ({0}) and its SSL backend ("{1}").</value>
+ <data name="net_http_libcurl_revocation_notsupported_sslbackend" xml:space="preserve">
+ <value>The handler does not support changing revocation settings with this combination of libcurl ({0}) and its SSL backend ("{1}"). An SSL backend based on "{2}" is required. Consider using System.Net.Http.SocketsHttpHandler.</value>
</data>
<data name="net_http_feature_requires_Windows10Version1607" xml:space="preserve">
<value>Using this feature requires Windows 10 Version 1607.</value>
@@ -363,9 +372,6 @@
<data name="net_http_feature_UWPClientCertSupportRequiresCertInPersonalCertificateStore" xml:space="preserve">
<value>Client certificate was not found in the personal (\"MY\") certificate store. In UWP, client certificates are only supported if they have been added to that certificate store.</value>
</data>
- <data name="net_http_max_redirects" xml:space="preserve">
- <value>The maximum number of redirects was exceeded.</value>
- </data>
<data name="net_http_invalid_proxy_scheme" xml:space="preserve">
<value>Only the 'http' scheme is allowed for proxies.</value>
</data>
@@ -378,6 +384,9 @@
<data name="net_http_unsupported_chunking" xml:space="preserve">
<value>HTTP 1.0 does not support chunking.</value>
</data>
+ <data name="net_http_unsupported_version" xml:space="preserve">
+ <value>Request HttpVersion 0.X is not supported. Use 1.0 or above.</value>
+ </data>
<data name="IO_SeekBeforeBegin" xml:space="preserve">
<value>An attempt was made to move the position before the beginning of the stream.</value>
</data>
@@ -387,4 +396,61 @@
<data name="IO_PathTooLong_Path" xml:space="preserve">
<value>The path '{0}' is too long, or a component of the specified path is too long.</value>
</data>
-</root> \ No newline at end of file
+ <data name="net_http_request_no_host" xml:space="preserve">
+ <value>CONNECT request must contain Host header.</value>
+ </data>
+ <data name="net_http_winhttp_error" xml:space="preserve">
+ <value>Error {0} calling {1}, '{2}'.</value>
+ </data>
+ <data name="net_MethodNotImplementedException" xml:space="preserve">
+ <value>This method is not implemented by this class.</value>
+ </data>
+ <data name="event_OperationReturnedSomething" xml:space="preserve">
+ <value>{0} returned {1}.</value>
+ </data>
+ <data name="net_log_operation_failed_with_error" xml:space="preserve">
+ <value>{0} failed with error {1}.</value>
+ </data>
+ <data name="net_completed_result" xml:space="preserve">
+ <value>This operation cannot be performed on a completed asynchronous result object.</value>
+ </data>
+ <data name="net_invalid_enum" xml:space="preserve">
+ <value>The specified value is not valid in the '{0}' enumeration.</value>
+ </data>
+ <data name="net_auth_message_not_encrypted" xml:space="preserve">
+ <value>Protocol error: A received message contains a valid signature but it was not encrypted as required by the effective Protection Level.</value>
+ </data>
+ <data name="net_securitypackagesupport" xml:space="preserve">
+ <value>The requested security package is not supported.</value>
+ </data>
+ <data name="SSPIInvalidHandleType" xml:space="preserve">
+ <value>'{0}' is not a supported handle type.</value>
+ </data>
+ <data name="net_http_authconnectionfailure" xml:space="preserve">
+ <value>Authentication failed because the connection could not be reused.</value>
+ </data>
+ <data name="net_nego_server_not_supported" xml:space="preserve">
+ <value>Server implementation is not supported</value>
+ </data>
+ <data name="net_nego_protection_level_not_supported" xml:space="preserve">
+ <value>Requested protection level is not supported with the gssapi implementation currently installed.</value>
+ </data>
+ <data name="net_context_buffer_too_small" xml:space="preserve">
+ <value>Insufficient buffer space. Required: {0} Actual: {1}.</value>
+ </data>
+ <data name="net_gssapi_operation_failed_detailed" xml:space="preserve">
+ <value>GSSAPI operation failed with error - {0} ({1}).</value>
+ </data>
+ <data name="net_gssapi_operation_failed" xml:space="preserve">
+ <value>GSSAPI operation failed with status: {0} (Minor status: {1}).</value>
+ </data>
+ <data name="net_nego_channel_binding_not_supported" xml:space="preserve">
+ <value>No support for channel binding on operating systems other than Windows.</value>
+ </data>
+ <data name="net_ntlm_not_possible_default_cred" xml:space="preserve">
+ <value>NTLM authentication is not possible with default credentials on this platform.</value>
+ </data>
+ <data name="net_nego_not_supported_empty_target_with_defaultcreds" xml:space="preserve">
+ <value>Target name should be non empty if default credentials are passed.</value>
+ </data>
+</root>
diff --git a/src/System.Net.Http/src/System.Net.Http.csproj b/src/System.Net.Http/src/System.Net.Http.csproj
index a0d6e505a1..8b4f8e05f9 100644
--- a/src/System.Net.Http/src/System.Net.Http.csproj
+++ b/src/System.Net.Http/src/System.Net.Http.csproj
@@ -10,6 +10,7 @@
<NoWarn>$(NoWarn);0436</NoWarn>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefineConstants>$(DefineConstants);HTTP_DLL</DefineConstants>
+ <ILLinkClearInitLocals>true</ILLinkClearInitLocals>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-OSX-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-OSX-Release|AnyCPU'" />
@@ -105,6 +106,9 @@
<Compile Include="$(CommonPath)\System\Net\HttpVersionInternal.cs">
<Link>Common\System\Net\HttpVersionInternal.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Net\Security\SslClientAuthenticationOptionsExtensions.cs">
+ <Link>Common\System\Net\Security\SslClientAuthenticationOptionsExtensions.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\System\IO\DelegatingStream.cs">
<Link>Common\System\IO\DelegatingStream.cs</Link>
</Compile>
@@ -118,32 +122,210 @@
<Link>Common\System\Net\Logging\NetEventSource.Common.cs</Link>
</Compile>
</ItemGroup>
- <!-- Managed HttpClientHandler implementation -->
+ <!-- SocketsHttpHandler implementation -->
<ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp'">
- <Compile Include="System\Net\Http\Managed\AuthenticateAndRedirectHandler.cs" />
- <Compile Include="System\Net\Http\Managed\AuthenticationHelper.Basic.cs" />
- <Compile Include="System\Net\Http\Managed\AuthenticationHelper.Digest.cs" />
- <Compile Include="System\Net\Http\Managed\ChunkedEncodingReadStream.cs" />
- <Compile Include="System\Net\Http\Managed\ChunkedEncodingWriteStream.cs" />
- <Compile Include="System\Net\Http\Managed\ConnectHelper.cs" />
- <Compile Include="System\Net\Http\Managed\ConnectionCloseReadStream.cs" />
- <Compile Include="System\Net\Http\Managed\ContentLengthReadStream.cs" />
- <Compile Include="System\Net\Http\Managed\ContentLengthWriteStream.cs" />
- <Compile Include="System\Net\Http\Managed\CookieHandler.cs" />
- <Compile Include="System\Net\Http\Managed\DecompressionHandler.cs" />
- <Compile Include="System\Net\Http\Managed\EmptyReadStream.cs" />
- <Compile Include="System\Net\Http\Managed\HttpConnection.cs" />
- <Compile Include="System\Net\Http\Managed\HttpConnectionContent.cs" />
- <Compile Include="System\Net\Http\Managed\HttpConnectionHandler.cs" />
- <Compile Include="System\Net\Http\Managed\HttpConnectionKey.cs" />
- <Compile Include="System\Net\Http\Managed\HttpConnectionPool.cs" />
- <Compile Include="System\Net\Http\Managed\HttpConnectionPools.cs" />
- <Compile Include="System\Net\Http\Managed\HttpConnectionSettings.cs" />
- <Compile Include="System\Net\Http\Managed\HttpContentReadStream.cs" />
- <Compile Include="System\Net\Http\Managed\HttpContentStream.cs" />
- <Compile Include="System\Net\Http\Managed\HttpContentWriteStream.cs" />
- <Compile Include="System\Net\Http\Managed\HttpProxyConnectionHandler.cs" />
- <Compile Include="System\Net\Http\Managed\ManagedHandler.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\AuthenticationHelper.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\AuthenticationHelper.Digest.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\AuthenticationHelper.NtAuth.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\CancellationHelper.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\ChunkedEncodingReadStream.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\ChunkedEncodingWriteStream.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\ConnectHelper.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\ConnectionCloseReadStream.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\ContentLengthReadStream.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\ContentLengthWriteStream.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\CookieHelper.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\DecompressionHandler.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\EmptyReadStream.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\HttpAuthenticatedConnectionHandler.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\HttpConnection.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\HttpConnectionHandler.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\HttpConnectionKind.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\HttpConnectionPool.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\HttpConnectionPoolManager.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\HttpConnectionResponseContent.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\HttpConnectionSettings.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\HttpContentDuplexStream.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\HttpContentReadStream.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\HttpContentStream.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\HttpContentWriteStream.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\SocketsHttpHandler.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\RawConnectionStream.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\RedirectHandler.cs" />
+ <Compile Include="$(CommonPath)\System\Net\NTAuthentication.Common.cs">
+ <Link>Common\System\Net\NTAuthentication.Common.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\ContextFlagsPal.cs">
+ <Link>Common\System\Net\ContextFlagsPal.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\LazyAsyncResult.cs">
+ <Link>Common\System\Net\LazyAsyncResult.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\ContextAwareResult.cs">
+ <Link>Common\System\Net\ContextAwareResult.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\SecurityStatusPal.cs">
+ <Link>Common\System\Net\SecurityStatusPal.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\Security\SecurityBuffer.cs">
+ <Link>Common\System\Net\Security\SecurityBuffer.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\Security\SecurityBufferType.cs">
+ <Link>Common\System\Net\Security\SecurityBufferType.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\Security\SSPIHandleCache.cs">
+ <Link>Common\System\Net\Security\SSPIHandleCache.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\Security\NetEventSource.Security.cs">
+ <Link>Common\System\Net\Security\NetEventSource.Security.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\ExceptionCheck.cs">
+ <Link>Common\System\Net\ExceptionCheck.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\IntPtrHelper.cs">
+ <Link>Common\System\Net\IntPtrHelper.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Collections\Generic\BidirectionalDictionary.cs">
+ <Link>Common\System\Collections\Generic\BidirectionalDictionary.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\NotImplemented.cs">
+ <Link>Common\System\NotImplemented.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\NegotiationInfoClass.cs">
+ <Link>Common\System\Net\NegotiationInfoClass.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\InternalException.cs">
+ <Link>Common\System\Net\InternalException.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\Logging\DebugThreadTracking.cs">
+ <Link>Common\System\Net\Logging\DebugThreadTracking.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\DebugSafeHandle.cs">
+ <Link>Common\System\Net\DebugSafeHandle.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\DebugCriticalHandleMinusOneIsInvalid.cs">
+ <Link>Common\System\Net\DebugCriticalHandleMinusOneIsInvalid.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\DebugCriticalHandleZeroOrMinusOneIsInvalid.cs">
+ <Link>Common\System\Net\DebugCriticalHandleZeroOrMinusOneIsInvalid.cs</Link>
+ </Compile>
+ </ItemGroup>
+ <!-- SocketsHttpHandler platform parts -->
+ <ItemGroup Condition=" '$(TargetsUnix)' == 'true' And '$(TargetGroup)' == 'netcoreapp'">
+ <Compile Include="System\Net\Http\SocketsHttpHandler\SystemProxyInfo.Unix.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\HttpEnvironmentProxy.cs" />
+ <Compile Include="$(CommonPath)\System\Net\ContextAwareResult.Unix.cs">
+ <Link>Common\System\Net\ContextAwareResult.Unix.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\ContextFlagsAdapterPal.Unix.cs">
+ <Link>Common\System\Net\ContextFlagsAdapterPal.Unix.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\Security\Unix\SafeFreeCredentials.cs">
+ <Link>Common\System\Net\Security\Unix\SafeFreeCredentials.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\Security\Unix\SafeDeleteContext.cs">
+ <Link>Common\System\Net\Security\Unix\SafeDeleteContext.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\Security\NegotiateStreamPal.Unix.cs">
+ <Link>Common\System\Net\Security\NegotiateStreamPal.Unix.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\GssSafeHandles.cs">
+ <Link>Common\Microsoft\Win32\SafeHandles\GssSafeHandles.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Unix\System.Net.Security.Native\Interop.GssApiException.cs">
+ <Link>Common\Interop\Unix\System.Net.Security.Native\Interop.GssApiException.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\Security\Unix\SafeFreeNegoCredentials.cs">
+ <Link>Common\System\Net\Security\Unix\SafeFreeNegoCredentials.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Unix\System.Net.Security.Native\Interop.NetSecurityNative.cs">
+ <Link>Common\Interop\Unix\System.Net.Security.Native\Interop.NetSecurityNative.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Unix\System.Net.Security.Native\Interop.GssBuffer.cs">
+ <Link>Common\Interop\Unix\System.Net.Security.Native\Interop.GssBuffer.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\Security\Unix\SafeDeleteNegoContext.cs">
+ <Link>Common\System\Net\Security\Unix\SafeDeleteNegoContext.cs</Link>
+ </Compile>
+ </ItemGroup>
+ <ItemGroup Condition=" '$(TargetsWindows)' == 'true' And '$(TargetGroup)' == 'netcoreapp'">
+ <Compile Include="System\Net\Http\SocketsHttpHandler\SystemProxyInfo.Windows.cs" />
+ <Compile Include="System\Net\Http\SocketsHttpHandler\HttpSystemProxy.cs" />
+ <Compile Include="$(CommonPath)\Interop\Windows\SChannel\Interop.SecPkgContext_ApplicationProtocol.cs">
+ <Link>Common\Interop\Windows\SChannel\Interop.SecPkgContext_ApplicationProtocol.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\Security\SecurityContextTokenHandle.cs">
+ <Link>Common\System\Net\Security\SecurityContextTokenHandle.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\ContextAwareResult.Windows.cs">
+ <Link>Common\System\Net\ContextAwareResult.Windows.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\SecurityStatusAdapterPal.Windows.cs">
+ <Link>Common\System\Net\SecurityStatusAdapterPal.Windows.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\ContextFlagsAdapterPal.Windows.cs">
+ <Link>Common\System\Net\ContextFlagsAdapterPal.Windows.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\Security\NegotiateStreamPal.Windows.cs">
+ <Link>Common\System\Net\Security\NegotiateStreamPal.Windows.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\Security\NetEventSource.Security.Windows.cs">
+ <Link>Common\System\Net\Security\NetEventSource.Security.Windows.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\sspicli\SecPkgContext_Bindings.cs">
+ <Link>Common\Interop\Windows\sspicli\SecPkgContext_Bindings.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\SChannel\Interop.SECURITY_STATUS.cs">
+ <Link>Common\Interop\Windows\SChannel\Interop.SECURITY_STATUS.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.CloseHandle.cs">
+ <Link>Common\Interop\Windows\kernel32\Interop.CloseHandle.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\sspicli\SecPkgContext_StreamSizes.cs">
+ <Link>Common\Interop\Windows\sspicli\SecPkgContext_StreamSizes.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\sspicli\SecPkgContext_NegotiationInfoW.cs">
+ <Link>Common\Interop\Windows\sspicli\SecPkgContext_NegotiationInfoW.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\sspicli\NegotiationInfoClass.cs">
+ <Link>Common\Interop\Windows\sspicli\NegotiationInfoClass.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\SChannel\SecPkgContext_ConnectionInfo.cs">
+ <Link>Common\Interop\Windows\SChannel\SecPkgContext_ConnectionInfo.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\sspicli\SSPISecureChannelType.cs">
+ <Link>Common\Interop\Windows\sspicli\SSPISecureChannelType.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\sspicli\SSPIInterface.cs">
+ <Link>Common\Interop\Windows\sspicli\SSPIInterface.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\sspicli\SSPIAuthType.cs">
+ <Link>Common\Interop\Windows\sspicli\SSPIAuthType.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\sspicli\SecurityPackageInfoClass.cs">
+ <Link>Common\Interop\Windows\sspicli\SecurityPackageInfoClass.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\sspicli\SecurityPackageInfo.cs">
+ <Link>Common\Interop\Windows\sspicli\SecurityPackageInfo.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\sspicli\SecPkgContext_Sizes.cs">
+ <Link>Common\Interop\Windows\sspicli\SecPkgContext_Sizes.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\sspicli\SafeDeleteContext.cs">
+ <Link>Common\Interop\Windows\sspicli\SafeDeleteContext.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\sspicli\GlobalSSPI.cs">
+ <Link>Common\Interop\Windows\sspicli\GlobalSSPI.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\sspicli\Interop.SSPI.cs">
+ <Link>Common\Interop\Windows\sspicli\Interop.SSPI.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\sspicli\SecuritySafeHandles.cs">
+ <Link>Common\Interop\Windows\sspicli\SecuritySafeHandles.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\sspicli\SSPIWrapper.cs">
+ <Link>Common\Interop\Windows\sspicli\SSPIWrapper.cs</Link>
+ </Compile>
</ItemGroup>
<!-- Common -->
<ItemGroup>
@@ -174,9 +356,10 @@
<Link>Common\System\Net\Mail\WhitespaceReader.cs</Link>
</Compile>
</ItemGroup>
- <!-- WinHTTP implementation -->
+ <!-- WinHttpHandler implementation -->
<ItemGroup Condition=" '$(TargetsWindows)' == 'true' And '$(TargetGroup)' != 'uap'">
<Compile Include="System\Net\Http\HttpClientHandler.Core.cs" />
+ <Compile Include="System\Net\Http\HttpClientHandler.netcoreapp.cs" />
<Compile Include="System\Net\Http\HttpClientHandler.Windows.cs" />
</ItemGroup>
<!-- Compile the WinHttpHandler implementation into the System.Net.Http.dll binary. This is a
@@ -193,19 +376,20 @@
<ItemGroup Condition=" '$(TargetsWindows)' == 'true' And '$(TargetGroup)' != 'uap'">
<Compile Include="@(CompileItem)" />
</ItemGroup>
- <!-- Unix -->
+ <!-- CurlHandler implementation -->
<PropertyGroup Condition=" '$(TargetsUnix)' == 'true' ">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup Condition=" '$(TargetsUnix)' == 'true' ">
<Compile Include="System\Net\Http\HttpClientHandler.Core.cs" />
+ <Compile Include="System\Net\Http\HttpClientHandler.netcoreapp.cs" />
<Compile Include="System\Net\Http\HttpClientHandler.Unix.cs" />
- <Compile Include="System\Net\Http\Unix\CurlHandler.cs" />
- <Compile Include="System\Net\Http\Unix\CurlHandler.EasyRequest.cs" />
- <Compile Include="System\Net\Http\Unix\CurlHandler.MultiAgent.cs" />
- <Compile Include="System\Net\Http\Unix\CurlException.cs" />
- <Compile Include="System\Net\Http\Unix\CurlHandler.CurlResponseMessage.cs" />
- <Compile Include="System\Net\Http\Unix\CurlResponseHeaderReader.cs" />
+ <Compile Include="System\Net\Http\CurlHandler\CurlHandler.cs" />
+ <Compile Include="System\Net\Http\CurlHandler\CurlHandler.EasyRequest.cs" />
+ <Compile Include="System\Net\Http\CurlHandler\CurlHandler.MultiAgent.cs" />
+ <Compile Include="System\Net\Http\CurlHandler\CurlException.cs" />
+ <Compile Include="System\Net\Http\CurlHandler\CurlHandler.CurlResponseMessage.cs" />
+ <Compile Include="System\Net\Http\CurlHandler\CurlResponseHeaderReader.cs" />
<Compile Include="$(CommonPath)\System\StrongToWeakReference.cs">
<Link>Common\Interop\Unix\StrongToWeakReference.cs</Link>
</Compile>
@@ -290,6 +474,12 @@
<Compile Include="$(CommonPath)\System\Net\Http\TlsCertificateExtensions.cs">
<Link>Common\System\Net\Http\TlsCertificateExtensions</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Net\Security\CertificateHelper.cs">
+ <Link>Common\System\Net\Security\CertificateHelper.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Net\Security\CertificateHelper.Unix.cs">
+ <Link>Common\System\Net\Security\CertificateHelper.Unix.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\System\Threading\Tasks\TaskToApm.cs">
<Link>Common\System\Threading\Tasks\TaskToApm.cs</Link>
</Compile>
@@ -358,11 +548,11 @@
<Compile Include="$(CommonPath)\System\Net\Security\CertificateValidation.Unix.cs">
<Link>Common\System\Net\Security\CertificateValidation.Unix.cs</Link>
</Compile>
- <Compile Include="System\Net\Http\Unix\CurlHandler.ClientCertificateProvider.cs" />
- <Compile Include="System\Net\Http\Unix\CurlHandler.SslProvider.cs" />
+ <Compile Include="System\Net\Http\CurlHandler\CurlHandler.ClientCertificateProvider.cs" />
+ <Compile Include="System\Net\Http\CurlHandler\CurlHandler.SslProvider.Linux.cs" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetsOSX)' == 'true' ">
- <Compile Include="System\Net\Http\OSX\CurlHandler.SslProvider.cs" />
+ <Compile Include="System\Net\Http\CurlHandler\CurlHandler.SslProvider.OSX.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' == 'uap'">
<Reference Include="Windows" />
@@ -423,12 +613,14 @@
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.Extensions" />
<Reference Include="System.Runtime.InteropServices" />
+ <Reference Include="System.Security.Claims" />
<Reference Include="System.Security.Cryptography.Algorithms" />
<Reference Include="System.Security.Cryptography.Csp" />
<Reference Include="System.Security.Cryptography.Encoding" />
<Reference Include="System.Security.Cryptography.OpenSsl" />
<Reference Include="System.Security.Cryptography.Primitives" />
<Reference Include="System.Security.Cryptography.X509Certificates" />
+ <Reference Include="System.Security.Principal.Windows" />
<Reference Include="System.Text.Encoding" />
<Reference Include="System.Text.Encoding.Extensions" />
<Reference Include="System.Threading" />
@@ -438,9 +630,11 @@
<Reference Include="System.Threading.Timer" />
</ItemGroup>
<ItemGroup Condition="'$(TargetsUnix)' == 'true'">
+ <Reference Include="System.IO.FileSystem" />
<Reference Include="System.Security.Cryptography.Algorithms" />
<Reference Include="System.Security.Cryptography.Encoding" />
<Reference Include="System.Security.Cryptography.Primitives" />
</ItemGroup>
+ <ItemGroup />
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Net.Http/src/System/Net/Http/ByteArrayHelpers.cs b/src/System.Net.Http/src/System/Net/Http/ByteArrayHelpers.cs
index 8ae15c6ce6..5ee60dab6a 100644
--- a/src/System.Net.Http/src/System/Net/Http/ByteArrayHelpers.cs
+++ b/src/System.Net.Http/src/System/Net/Http/ByteArrayHelpers.cs
@@ -3,8 +3,6 @@
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
-using System.Runtime.InteropServices;
-using System.Text;
namespace System
{
@@ -41,14 +39,5 @@ namespace System
return true;
}
-
- internal static unsafe string GetStringFromByteSpan(ReadOnlySpan<byte> bytes)
- {
- // TODO #22431: Use new Span-based Encoding overload when available
- fixed (byte* p = &MemoryMarshal.GetReference(bytes))
- {
- return Encoding.ASCII.GetString(p, bytes.Length);
- }
- }
}
}
diff --git a/src/System.Net.Http/src/System/Net/Http/Unix/CurlException.cs b/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlException.cs
index 67da37e89d..67da37e89d 100644
--- a/src/System.Net.Http/src/System/Net/Http/Unix/CurlException.cs
+++ b/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlException.cs
diff --git a/src/System.Net.Http/src/System/Net/Http/Unix/CurlHandler.ClientCertificateProvider.cs b/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.ClientCertificateProvider.cs
index 4740c70bae..4740c70bae 100644
--- a/src/System.Net.Http/src/System/Net/Http/Unix/CurlHandler.ClientCertificateProvider.cs
+++ b/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.ClientCertificateProvider.cs
diff --git a/src/System.Net.Http/src/System/Net/Http/Unix/CurlHandler.CurlResponseMessage.cs b/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.CurlResponseMessage.cs
index 1fafd9681d..7be1c4af7e 100644
--- a/src/System.Net.Http/src/System/Net/Http/Unix/CurlHandler.CurlResponseMessage.cs
+++ b/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.CurlResponseMessage.cs
@@ -22,7 +22,7 @@ namespace System.Net.Http
Debug.Assert(easy != null, "Expected non-null EasyRequest");
RequestMessage = easy._requestMessage;
ResponseStream = new CurlResponseStream(easy);
- Content = new NoWriteNoSeekStreamContent(ResponseStream, CancellationToken.None);
+ Content = new NoWriteNoSeekStreamContent(ResponseStream);
// On Windows, we pass the equivalent of the easy._cancellationToken
// in to StreamContent's ctor. This in turn passes that token through
@@ -253,11 +253,11 @@ namespace System.Net.Http
return ReadAsync(new Memory<byte>(buffer, offset, count), cancellationToken).AsTask();
}
- public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken = default)
+ public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
{
CheckDisposed();
- EventSourceTrace("Buffer: {0}", destination.Length);
+ EventSourceTrace("Buffer: {0}", buffer.Length);
// Check for cancellation
if (cancellationToken.IsCancellationRequested)
@@ -290,7 +290,7 @@ namespace System.Net.Http
// Quick check for if no data was actually requested. We do this after the check
// for errors so that we can still fail the read and transfer the exception if we should.
- if (destination.Length == 0)
+ if (buffer.Length == 0)
{
return new ValueTask<int>(0);
}
@@ -298,8 +298,8 @@ namespace System.Net.Http
// If there's any data left over from a previous call, grab as much as we can.
if (_remainingDataCount > 0)
{
- int bytesToCopy = Math.Min(destination.Length, _remainingDataCount);
- new Span<byte>(_remainingData, _remainingDataOffset, bytesToCopy).CopyTo(destination.Span);
+ int bytesToCopy = Math.Min(buffer.Length, _remainingDataCount);
+ new Span<byte>(_remainingData, _remainingDataOffset, bytesToCopy).CopyTo(buffer.Span);
_remainingDataOffset += bytesToCopy;
_remainingDataCount -= bytesToCopy;
@@ -332,7 +332,7 @@ namespace System.Net.Http
// the cancellation token. Dispose on the registration won't return until the action
// associated with the registration has completed, but if that action is currently
// executing and is blocked on the lock that's held while calling Dispose... deadlock.
- var crs = new CancelableReadState(destination, this);
+ var crs = new CancelableReadState(buffer, this, cancellationToken);
crs._registration = cancellationToken.Register(s1 =>
{
((CancelableReadState)s1)._stream.EventSourceTrace("Cancellation invoked. Queueing work item to cancel read state");
@@ -341,11 +341,11 @@ namespace System.Net.Http
var crsRef = (CancelableReadState)s2;
lock (crsRef._stream._lockObject)
{
- Debug.Assert(crsRef._registration.Token.IsCancellationRequested, "We should only be here if cancellation was requested.");
+ Debug.Assert(crsRef._token.IsCancellationRequested, "We should only be here if cancellation was requested.");
if (crsRef._stream._pendingReadRequest == crsRef)
{
crsRef._stream.EventSourceTrace("Canceling");
- crsRef.TrySetCanceled(crsRef._registration.Token);
+ crsRef.TrySetCanceled(crsRef._token);
crsRef._stream.ClearPendingReadRequest();
}
}
@@ -356,7 +356,7 @@ namespace System.Net.Http
else
{
// The token isn't cancelable. Just create a normal read state.
- _pendingReadRequest = new ReadState(destination);
+ _pendingReadRequest = new ReadState(buffer);
}
_easy._associatedMultiAgent.RequestUnpause(_easy);
@@ -516,11 +516,13 @@ namespace System.Net.Http
private sealed class CancelableReadState : ReadState
{
internal readonly CurlResponseStream _stream;
+ internal readonly CancellationToken _token;
internal CancellationTokenRegistration _registration;
- internal CancelableReadState(Memory<byte> buffer, CurlResponseStream responseStream) : base(buffer)
+ internal CancelableReadState(Memory<byte> buffer, CurlResponseStream responseStream, CancellationToken cancellationToken) : base(buffer)
{
_stream = responseStream;
+ _token = cancellationToken;
}
}
}
diff --git a/src/System.Net.Http/src/System/Net/Http/Unix/CurlHandler.EasyRequest.cs b/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.EasyRequest.cs
index b6dc5eba69..47996113d1 100644
--- a/src/System.Net.Http/src/System/Net/Http/Unix/CurlHandler.EasyRequest.cs
+++ b/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.EasyRequest.cs
@@ -113,7 +113,7 @@ namespace System.Net.Http
SetProxyOptions(_requestMessage.RequestUri);
SetCredentialsOptions(_handler._useDefaultCredentials ? GetDefaultCredentialAndAuth() : _handler.GetCredentials(_requestMessage.RequestUri));
SetCookieOption(_requestMessage.RequestUri);
- SetRequestHeaders();
+ SetRequestHeaders(copyAuthHeaders:true);
SetSslOptions();
EventSourceTrace("Done configuring request.");
@@ -300,6 +300,8 @@ namespace System.Net.Http
// and when enabled has a measurably negative impact on latency in key scenarios
// (e.g. POST'ing small-ish data).
SetCurlOption(CURLoption.CURLOPT_TCP_NODELAY, 1L);
+ // Enable TCP keep-alive.
+ SetCurlOption(CURLoption.CURLOPT_TCP_KEEPALIVE, 1L);
}
private void SetMultithreading()
@@ -370,6 +372,11 @@ namespace System.Net.Http
{
SetCookieOption(newUri);
}
+
+ if (newUri.Scheme == Uri.UriSchemeHttp && _requestMessage.RequestUri.Scheme == Uri.UriSchemeHttps)
+ {
+ EventSourceTrace("Insecure https to http redirect: {0}", (_requestMessage.RequestUri, newUri));
+ }
}
// Set up the new credentials, either for the new Uri if we were able to get it,
@@ -378,7 +385,7 @@ namespace System.Net.Http
// Set the headers again. This is a workaround for libcurl's limitation in handling
// headers with empty values.
- SetRequestHeaders();
+ SetRequestHeaders(copyAuthHeaders:false);
}
private void SetContentLength(CURLoption lengthOption)
@@ -504,10 +511,11 @@ namespace System.Net.Http
{
// Try to use the requested version, if a known version was explicitly requested.
// If an unknown version was requested, we simply use libcurl's default.
+ // Only allow HTTP/2 when making https requests.
var curlVersion =
(v.Major == 1 && v.Minor == 1) ? Interop.Http.CurlHttpVersion.CURL_HTTP_VERSION_1_1 :
(v.Major == 1 && v.Minor == 0) ? Interop.Http.CurlHttpVersion.CURL_HTTP_VERSION_1_0 :
- (v.Major == 2 && v.Minor == 0) ? Interop.Http.CurlHttpVersion.CURL_HTTP_VERSION_2_0 :
+ (v.Major == 2 && v.Minor == 0) ? Interop.Http.CurlHttpVersion.CURL_HTTP_VERSION_2TLS :
Interop.Http.CurlHttpVersion.CURL_HTTP_VERSION_NONE;
if (curlVersion != Interop.Http.CurlHttpVersion.CURL_HTTP_VERSION_NONE)
@@ -698,7 +706,7 @@ namespace System.Net.Http
}
}
- internal void SetRequestHeaders()
+ internal void SetRequestHeaders(bool copyAuthHeaders)
{
var slist = new SafeCurlSListHandle();
@@ -706,7 +714,7 @@ namespace System.Net.Http
if (_requestMessage.Content != null)
{
// Add content request headers
- AddRequestHeaders(_requestMessage.Content.Headers, slist);
+ AddRequestHeaders(_requestMessage.Content.Headers, slist, copyAuthHeaders);
suppressContentType = _requestMessage.Content.Headers.ContentType == null;
}
else
@@ -721,7 +729,7 @@ namespace System.Net.Http
}
// Add request headers
- AddRequestHeaders(_requestMessage.Headers, slist);
+ AddRequestHeaders(_requestMessage.Headers, slist, copyAuthHeaders);
// Since libcurl always adds a Transfer-Encoding header, we need to explicitly block
// it if caller specifically does not want to set the header
@@ -846,11 +854,12 @@ namespace System.Net.Http
return Interop.Http.RegisterSslCtxCallback(_easyHandle, callback, userPointer, ref _callbackHandle);
}
- private static void AddRequestHeaders(HttpHeaders headers, SafeCurlSListHandle handle)
+ private static void AddRequestHeaders(HttpHeaders headers, SafeCurlSListHandle handle, bool copyAuthHeaders)
{
foreach (KeyValuePair<string, IEnumerable<string>> header in headers)
{
- if (string.Equals(header.Key, HttpKnownHeaderNames.ContentLength, StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(header.Key, HttpKnownHeaderNames.ContentLength, StringComparison.OrdinalIgnoreCase) ||
+ (!copyAuthHeaders && string.Equals(header.Key, HttpKnownHeaderNames.Authorization, StringComparison.OrdinalIgnoreCase)))
{
// avoid overriding libcurl's handling via INFILESIZE/POSTFIELDSIZE
continue;
diff --git a/src/System.Net.Http/src/System/Net/Http/Unix/CurlHandler.MultiAgent.cs b/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.MultiAgent.cs
index 797f5cd4b7..b3202a95d3 100644
--- a/src/System.Net.Http/src/System/Net/Http/Unix/CurlHandler.MultiAgent.cs
+++ b/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.MultiAgent.cs
@@ -999,6 +999,12 @@ namespace System.Net.Http
// our redirect limit, etc.), this will have been unnecessary work in reconfiguring the easy handle, but
// nothing incorrect, as we'll tear down the handle once the request finishes, anyway, and all of the configuration
// we're doing is about initiating a new request.
+ if ((int)response.StatusCode >= 301 && (int)response.StatusCode <= 303)
+ {
+ // ISSUE: 25163
+ // Ideally we want to avoid modifying the users request message.
+ easy._requestMessage.Headers.TransferEncodingChunked = false;
+ }
easy.SetPossibleRedirectForLocationHeader(headerValue);
}
else if (string.Equals(headerName, HttpKnownHeaderNames.SetCookie, StringComparison.OrdinalIgnoreCase))
diff --git a/src/System.Net.Http/src/System/Net/Http/Unix/CurlHandler.SslProvider.cs b/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.SslProvider.Linux.cs
index 993d28b2f8..fc6f5b88c7 100644
--- a/src/System.Net.Http/src/System/Net/Http/Unix/CurlHandler.SslProvider.cs
+++ b/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.SslProvider.Linux.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
+using System.IO;
using System.Net.Security;
using System.Runtime.InteropServices;
using System.Security.Authentication;
@@ -24,6 +25,8 @@ namespace System.Net.Http
private static readonly Interop.Http.SslCtxCallback s_sslCtxCallback = SslCtxCallback;
private static readonly Interop.Ssl.AppVerifyCallback s_sslVerifyCallback = VerifyCertChain;
private static readonly Oid s_serverAuthOid = new Oid("1.3.6.1.5.5.7.3.1");
+ private static string _sslCaPath;
+ private static string _sslCaInfo;
internal static void SetSslOptions(EasyRequest easy, ClientCertificateOption clientCertOption)
{
@@ -101,25 +104,64 @@ namespace System.Net.Http
}
}
+ private static void GetSslCaLocations(out string path, out string info)
+ {
+ // We only provide curl option values when SSL_CERT_FILE or SSL_CERT_DIR is set.
+ // When that is the case, we set the options so curl ends up using the same certificates as the
+ // X509 machine store.
+ path = _sslCaPath;
+ info = _sslCaInfo;
+
+ if (path == null || info == null)
+ {
+ bool hasEnvironmentVariables = Environment.GetEnvironmentVariable("SSL_CERT_FILE") != null ||
+ Environment.GetEnvironmentVariable("SSL_CERT_DIR") != null;
+
+ if (hasEnvironmentVariables)
+ {
+ path = Interop.Crypto.GetX509RootStorePath();
+ if (!Directory.Exists(path))
+ {
+ // X509 store ignores non-existing.
+ path = string.Empty;
+ }
+
+ info = Interop.Crypto.GetX509RootStoreFile();
+ if (!File.Exists(info))
+ {
+ // X509 store ignores non-existing.
+ info = string.Empty;
+ }
+ }
+ else
+ {
+ path = string.Empty;
+ info = string.Empty;
+ }
+ _sslCaPath = path;
+ _sslCaInfo = info;
+ }
+ }
+
private static void SetSslOptionsForCertificateStore(EasyRequest easy)
{
// Support specifying certificate directory/bundle via environment variables: SSL_CERT_DIR, SSL_CERT_FILE.
- string sslCertDir = Environment.GetEnvironmentVariable("SSL_CERT_DIR");
- if (sslCertDir != null)
+ GetSslCaLocations(out string sslCaPath, out string sslCaInfo);
+
+ if (sslCaPath != string.Empty)
{
- easy.SetCurlOption(Interop.Http.CURLoption.CURLOPT_CAPATH, sslCertDir);
+ easy.SetCurlOption(Interop.Http.CURLoption.CURLOPT_CAPATH, sslCaPath);
// https proxy support requires libcurl 7.52.0+
- easy.TrySetCurlOption(Interop.Http.CURLoption.CURLOPT_PROXY_CAPATH, sslCertDir);
+ easy.TrySetCurlOption(Interop.Http.CURLoption.CURLOPT_PROXY_CAPATH, sslCaPath);
}
- string sslCertFile = Environment.GetEnvironmentVariable("SSL_CERT_FILE");
- if (sslCertFile != null)
+ if (sslCaInfo != string.Empty)
{
- easy.SetCurlOption(Interop.Http.CURLoption.CURLOPT_CAINFO, sslCertFile);
+ easy.SetCurlOption(Interop.Http.CURLoption.CURLOPT_CAINFO, sslCaInfo);
// https proxy support requires libcurl 7.52.0+
- easy.TrySetCurlOption(Interop.Http.CURLoption.CURLOPT_PROXY_CAINFO, sslCertFile);
+ easy.TrySetCurlOption(Interop.Http.CURLoption.CURLOPT_PROXY_CAINFO, sslCaInfo);
}
}
@@ -127,12 +169,12 @@ namespace System.Net.Http
{
if (certProvider != null)
{
- throw new PlatformNotSupportedException(SR.Format(SR.net_http_libcurl_clientcerts_notsupported, CurlVersionDescription, CurlSslVersionDescription));
+ throw new PlatformNotSupportedException(SR.Format(SR.net_http_libcurl_clientcerts_notsupported_sslbackend, CurlVersionDescription, CurlSslVersionDescription, Interop.Http.OpenSsl10Description));
}
if (easy._handler.CheckCertificateRevocationList)
{
- throw new PlatformNotSupportedException(SR.Format(SR.net_http_libcurl_revocation_notsupported, CurlVersionDescription, CurlSslVersionDescription));
+ throw new PlatformNotSupportedException(SR.Format(SR.net_http_libcurl_revocation_notsupported_sslbackend, CurlVersionDescription, CurlSslVersionDescription, Interop.Http.OpenSsl10Description));
}
if (easy._handler.ServerCertificateCustomValidationCallback != null)
@@ -145,7 +187,7 @@ namespace System.Net.Http
}
else
{
- throw new PlatformNotSupportedException(SR.Format(SR.net_http_libcurl_callback_notsupported, CurlVersionDescription, CurlSslVersionDescription));
+ throw new PlatformNotSupportedException(SR.Format(SR.net_http_libcurl_callback_notsupported_sslbackend, CurlVersionDescription, CurlSslVersionDescription, Interop.Http.OpenSsl10Description));
}
}
else
diff --git a/src/System.Net.Http/src/System/Net/Http/OSX/CurlHandler.SslProvider.cs b/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.SslProvider.OSX.cs
index 134cfec0dc..4b2c02904d 100644
--- a/src/System.Net.Http/src/System/Net/Http/OSX/CurlHandler.SslProvider.cs
+++ b/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.SslProvider.OSX.cs
@@ -29,11 +29,7 @@ namespace System.Net.Http
// only via writing it to a file and letting it load the PFX.
// This would require that a) we write said file, and b) that it contaminate the default
// keychain (because their PFX loader loads to the default keychain).
- throw new PlatformNotSupportedException(
- SR.Format(
- SR.net_http_libcurl_clientcerts_notsupported,
- CurlVersionDescription,
- CurlSslVersionDescription));
+ throw new PlatformNotSupportedException(SR.net_http_libcurl_clientcerts_notsupported_os);
}
// Revocation checking is always on for darwinssl (SecureTransport).
@@ -44,9 +40,10 @@ namespace System.Net.Http
{
throw new PlatformNotSupportedException(
SR.Format(
- SR.net_http_libcurl_revocation_notsupported,
+ SR.net_http_libcurl_revocation_notsupported_sslbackend,
CurlVersionDescription,
- CurlSslVersionDescription));
+ CurlSslVersionDescription,
+ Interop.Http.SecureTransportDescription));
}
if (easy._handler.ServerCertificateCustomValidationCallback != null)
@@ -87,11 +84,7 @@ namespace System.Net.Http
}
else
{
- throw new PlatformNotSupportedException(
- SR.Format(
- SR.net_http_libcurl_callback_notsupported,
- CurlVersionDescription,
- CurlSslVersionDescription));
+ throw new PlatformNotSupportedException(SR.net_http_libcurl_callback_notsupported_os);
}
}
diff --git a/src/System.Net.Http/src/System/Net/Http/Unix/CurlHandler.cs b/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.cs
index 88eae1bf51..a63fe3991d 100644
--- a/src/System.Net.Http/src/System/Net/Http/Unix/CurlHandler.cs
+++ b/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.cs
@@ -218,10 +218,6 @@ namespace System.Net.Http
}
}
- internal bool SupportsProxy => true;
-
- internal bool SupportsRedirectConfiguration => true;
-
internal bool UseProxy
{
get { return _useProxy; }
@@ -465,7 +461,9 @@ namespace System.Net.Http
if (request.Headers.TransferEncodingChunked.GetValueOrDefault() && (request.Content == null))
{
- throw new InvalidOperationException(SR.net_http_chunked_not_allowed_with_empty_content);
+ return Task.FromException<HttpResponseMessage>(
+ new HttpRequestException(SR.net_http_client_execution_error,
+ new InvalidOperationException(SR.net_http_chunked_not_allowed_with_empty_content)));
}
if (_useCookies && _cookieContainer == null)
@@ -769,6 +767,8 @@ namespace System.Net.Http
// Deal with conflict between 'Content-Length' vs. 'Transfer-Encoding: chunked' semantics.
// libcurl adds a Transfer-Encoding header by default and the request fails if both are set.
+ // ISSUE: 25163
+ // Ideally we want to avoid modifying the users request message.
if (requestContent.Headers.ContentLength.HasValue)
{
if (chunkedMode)
diff --git a/src/System.Net.Http/src/System/Net/Http/Unix/CurlResponseHeaderReader.cs b/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlResponseHeaderReader.cs
index ceafdf6478..ceafdf6478 100644
--- a/src/System.Net.Http/src/System/Net/Http/Unix/CurlResponseHeaderReader.cs
+++ b/src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlResponseHeaderReader.cs
diff --git a/src/System.Net.Http/src/System/Net/Http/DiagnosticsHandler.cs b/src/System.Net.Http/src/System/Net/Http/DiagnosticsHandler.cs
index 69663bb74f..3ddb71c87a 100644
--- a/src/System.Net.Http/src/System/Net/Http/DiagnosticsHandler.cs
+++ b/src/System.Net.Http/src/System/Net/Http/DiagnosticsHandler.cs
@@ -92,10 +92,12 @@ namespace System.Net.Http
}
}
- Task<HttpResponseMessage> responseTask = base.SendAsync(request, cancellationToken);
+ Task<HttpResponseMessage> responseTask = null;
try
{
- await responseTask.ConfigureAwait(false);
+ responseTask = base.SendAsync(request, cancellationToken);
+
+ return await responseTask.ConfigureAwait(false);
}
catch (TaskCanceledException)
{
@@ -120,12 +122,12 @@ namespace System.Net.Http
{
s_diagnosticListener.StopActivity(activity, new
{
- Response = responseTask.Status == TaskStatus.RanToCompletion ? responseTask.Result : null,
+ Response = responseTask?.Status == TaskStatus.RanToCompletion ? responseTask.Result : null,
//If request is failed or cancelled, there is no reponse, therefore no information about request;
//pass the request in the payload, so consumers can have it in Stop for failed/canceled requests
//and not retain all requests in Start
Request = request,
- RequestTaskStatus = responseTask.Status
+ RequestTaskStatus = responseTask?.Status ?? TaskStatus.Faulted
});
}
// Try to write System.Net.Http.Response event (deprecated)
@@ -135,15 +137,14 @@ namespace System.Net.Http
s_diagnosticListener.Write(DiagnosticsHandlerLoggingStrings.ResponseWriteNameDeprecated,
new
{
- Response = responseTask.Status == TaskStatus.RanToCompletion ? responseTask.Result : null,
+ Response = responseTask?.Status == TaskStatus.RanToCompletion ? responseTask.Result : null,
LoggingRequestId = loggingRequestId,
TimeStamp = timestamp,
- RequestTaskStatus = responseTask.Status
+ RequestTaskStatus = responseTask?.Status ?? TaskStatus.Faulted
}
);
}
}
- return responseTask.Result;
}
#region private
@@ -153,4 +154,4 @@ namespace System.Net.Http
#endregion
}
-} \ No newline at end of file
+}
diff --git a/src/System.Net.Http/src/System/Net/Http/Headers/AuthenticationHeaderValue.cs b/src/System.Net.Http/src/System/Net/Http/Headers/AuthenticationHeaderValue.cs
index 48caee22bb..fadc33d606 100644
--- a/src/System.Net.Http/src/System/Net/Http/Headers/AuthenticationHeaderValue.cs
+++ b/src/System.Net.Http/src/System/Net/Http/Headers/AuthenticationHeaderValue.cs
@@ -136,8 +136,19 @@ namespace System.Net.Http.Headers
return 0;
}
- AuthenticationHeaderValue result = new AuthenticationHeaderValue();
- result._scheme = input.Substring(startIndex, schemeLength);
+ var result = new AuthenticationHeaderValue();
+ string targetScheme = null;
+ switch (schemeLength)
+ {
+ // Avoid allocating a scheme string for the most common cases.
+ case 5: targetScheme = "Basic"; break;
+ case 6: targetScheme = "Digest"; break;
+ case 4: targetScheme = "NTLM"; break;
+ case 9: targetScheme = "Negotiate"; break;
+ }
+ result._scheme = targetScheme != null && string.CompareOrdinal(input, startIndex, targetScheme, 0, schemeLength) == 0 ?
+ targetScheme :
+ result._scheme = input.Substring(startIndex, schemeLength);
int current = startIndex + schemeLength;
int whitespaceLength = HttpRuleParser.GetWhitespaceLength(input, current);
diff --git a/src/System.Net.Http/src/System/Net/Http/Headers/HeaderDescriptor.cs b/src/System.Net.Http/src/System/Net/Http/Headers/HeaderDescriptor.cs
index 16b268a73e..a820229d08 100644
--- a/src/System.Net.Http/src/System/Net/Http/Headers/HeaderDescriptor.cs
+++ b/src/System.Net.Http/src/System/Net/Http/Headers/HeaderDescriptor.cs
@@ -31,6 +31,7 @@ namespace System.Net.Http.Headers
public string Name => _headerName;
public HttpHeaderParser Parser => _knownHeader?.Parser;
public HttpHeaderType HeaderType => _knownHeader == null ? HttpHeaderType.Custom : _knownHeader.HeaderType;
+ public KnownHeader KnownHeader => _knownHeader;
public bool Equals(HeaderDescriptor other) =>
_knownHeader == null ?
@@ -81,7 +82,7 @@ namespace System.Net.Http.Headers
return false;
}
- descriptor = new HeaderDescriptor(ByteArrayHelpers.GetStringFromByteSpan(headerName));
+ descriptor = new HeaderDescriptor(HttpRuleParser.GetTokenString(headerName));
return true;
}
@@ -112,7 +113,7 @@ namespace System.Net.Http.Headers
}
}
- return ByteArrayHelpers.GetStringFromByteSpan(headerValue);
+ return HttpRuleParser.DefaultHttpEncoding.GetString(headerValue);
}
}
}
diff --git a/src/System.Net.Http/src/System/Net/Http/Headers/HttpHeaderParser.cs b/src/System.Net.Http/src/System/Net/Http/Headers/HttpHeaderParser.cs
index bc50cad559..ca9c27ec52 100644
--- a/src/System.Net.Http/src/System/Net/Http/Headers/HttpHeaderParser.cs
+++ b/src/System.Net.Http/src/System/Net/Http/Headers/HttpHeaderParser.cs
@@ -8,9 +8,6 @@ using System.Diagnostics.Contracts;
namespace System.Net.Http.Headers
{
-#if DEBUG
- [ContractClass(typeof(HttpHeaderParserContract))]
-#endif
internal abstract class HttpHeaderParser
{
internal const string DefaultSeparator = ", ";
@@ -91,25 +88,4 @@ namespace System.Net.Http.Headers
return value.ToString();
}
}
-
-#if DEBUG
- [ContractClassFor(typeof(HttpHeaderParser))]
- internal abstract class HttpHeaderParserContract : HttpHeaderParser
- {
- public HttpHeaderParserContract()
- : base(false)
- {
- }
-
- public override bool TryParseValue(string value, object storeValue, ref int index, out object parsedValue)
- {
- // Index may be value.Length (e.g. both 0). This may be allowed for some headers (e.g. Accept but not
- // allowed by others (e.g. Content-Length). The parser has to decide if this is valid or not.
- Debug.Assert((value == null) || ((index >= 0) && (index <= value.Length)));
-
- parsedValue = null;
- return false;
- }
- }
-#endif
}
diff --git a/src/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs b/src/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs
index c6c2930023..c59c013131 100644
--- a/src/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs
+++ b/src/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs
@@ -380,9 +380,61 @@ namespace System.Net.Http.Headers
}
}
-#endregion
+ // The following is the same general code as the above GetEnumerator, but returning the
+ // HeaderDescriptor and values string[], rather than the key name and a values enumerable.
+
+ internal IEnumerable<KeyValuePair<HeaderDescriptor, string[]>> GetHeaderDescriptorsAndValues()
+ {
+ return _headerStore != null && _headerStore.Count > 0 ?
+ GetHeaderDescriptorsAndValuesCore() :
+ Array.Empty<KeyValuePair<HeaderDescriptor, string[]>>();
+ }
+
+ private IEnumerable<KeyValuePair<HeaderDescriptor, string[]>> GetHeaderDescriptorsAndValuesCore()
+ {
+ List<HeaderDescriptor> invalidHeaders = null;
+
+ foreach (var header in _headerStore)
+ {
+ HeaderDescriptor descriptor = header.Key;
+ HeaderStoreItemInfo info = header.Value;
+
+ // Make sure we parse all raw values before returning the result. Note that this has to be
+ // done before we calculate the array length (next line): A raw value may contain a list of
+ // values.
+ if (!ParseRawHeaderValues(descriptor, info, false))
+ {
+ // We have an invalid header value (contains invalid newline chars). Mark it as "to-be-deleted"
+ // and skip this header.
+ if (invalidHeaders == null)
+ {
+ invalidHeaders = new List<HeaderDescriptor>();
+ }
+ invalidHeaders.Add(descriptor);
+ }
+ else
+ {
+ string[] values = GetValuesAsStrings(descriptor, info);
+ yield return new KeyValuePair<HeaderDescriptor, string[]>(descriptor, values);
+ }
+ }
+
+ // While we were enumerating headers, we also parsed header values. If during parsing it turned out that
+ // the header value was invalid (contains invalid newline chars), remove the header from the store after
+ // completing the enumeration.
+ if (invalidHeaders != null)
+ {
+ Debug.Assert(_headerStore != null);
+ foreach (HeaderDescriptor invalidheaderInfo in invalidHeaders)
+ {
+ _headerStore.Remove(invalidheaderInfo);
+ }
+ }
+ }
+
+ #endregion
-#region IEnumerable Members
+ #region IEnumerable Members
Collections.IEnumerator Collections.IEnumerable.GetEnumerator()
{
@@ -968,13 +1020,13 @@ namespace System.Net.Http.Headers
{
case StoreLocation.Raw:
currentStoreValue = info.RawValue;
- AddValueToStoreValue<string>(info, value, ref currentStoreValue);
+ AddValueToStoreValue<string>(value, ref currentStoreValue);
info.RawValue = currentStoreValue;
break;
case StoreLocation.Invalid:
currentStoreValue = info.InvalidValue;
- AddValueToStoreValue<string>(info, value, ref currentStoreValue);
+ AddValueToStoreValue<string>(value, ref currentStoreValue);
info.InvalidValue = currentStoreValue;
break;
@@ -983,7 +1035,7 @@ namespace System.Net.Http.Headers
"Header value types must not derive from List<object> since this type is used internally to store " +
"lists of values. So we would not be able to distinguish between a single value and a list of values.");
currentStoreValue = info.ParsedValue;
- AddValueToStoreValue<object>(info, value, ref currentStoreValue);
+ AddValueToStoreValue<object>(value, ref currentStoreValue);
info.ParsedValue = currentStoreValue;
break;
@@ -993,8 +1045,7 @@ namespace System.Net.Http.Headers
}
}
- private static void AddValueToStoreValue<T>(HeaderStoreItemInfo info, object value,
- ref object currentStoreValue) where T : class
+ private static void AddValueToStoreValue<T>(object value, ref object currentStoreValue) where T : class
{
// If there is no value set yet, then add current item as value (we don't create a list
// if not required). If 'info.Value' is already assigned then make sure 'info.Value' is a
@@ -1010,7 +1061,7 @@ namespace System.Net.Http.Headers
if (storeValues == null)
{
storeValues = new List<T>(2);
- Debug.Assert(value is T);
+ Debug.Assert(currentStoreValue is T);
storeValues.Add(currentStoreValue as T);
currentStoreValue = storeValues;
}
diff --git a/src/System.Net.Http/src/System/Net/Http/Headers/KnownHeader.cs b/src/System.Net.Http/src/System/Net/Http/Headers/KnownHeader.cs
index d71e240950..8b3821a45e 100644
--- a/src/System.Net.Http/src/System/Net/Http/Headers/KnownHeader.cs
+++ b/src/System.Net.Http/src/System/Net/Http/Headers/KnownHeader.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
+using System.Text;
namespace System.Net.Http.Headers
{
@@ -12,34 +13,38 @@ namespace System.Net.Http.Headers
private readonly HttpHeaderType _headerType;
private readonly HttpHeaderParser _parser;
private readonly string[] _knownValues;
+ private readonly byte[] _asciiBytesWithColonSpace;
- public KnownHeader(string name, HttpHeaderType headerType, HttpHeaderParser parser, string[] knownValues = null)
+ public KnownHeader(string name) : this(name, HttpHeaderType.Custom, null)
{
Debug.Assert(!string.IsNullOrEmpty(name));
Debug.Assert(HttpRuleParser.GetTokenLength(name, 0) == name.Length);
- Debug.Assert(headerType != HttpHeaderType.Custom);
- Debug.Assert(parser != null);
-
- _name = name;
- _headerType = headerType;
- _parser = parser;
- _knownValues = knownValues;
}
- public KnownHeader(string name)
+ public KnownHeader(string name, HttpHeaderType headerType, HttpHeaderParser parser, string[] knownValues = null)
{
Debug.Assert(!string.IsNullOrEmpty(name));
Debug.Assert(HttpRuleParser.GetTokenLength(name, 0) == name.Length);
+ Debug.Assert((headerType == HttpHeaderType.Custom) == (parser == null));
+ Debug.Assert(knownValues == null || headerType != HttpHeaderType.Custom);
_name = name;
- _headerType = HttpHeaderType.Custom;
- _parser = null;
+ _headerType = headerType;
+ _parser = parser;
+ _knownValues = knownValues;
+
+ _asciiBytesWithColonSpace = new byte[name.Length + 2]; // + 2 for ':' and ' '
+ int asciiBytes = Encoding.ASCII.GetBytes(name, _asciiBytesWithColonSpace);
+ Debug.Assert(asciiBytes == name.Length);
+ _asciiBytesWithColonSpace[_asciiBytesWithColonSpace.Length - 2] = (byte)':';
+ _asciiBytesWithColonSpace[_asciiBytesWithColonSpace.Length - 1] = (byte)' ';
}
public string Name => _name;
public HttpHeaderParser Parser => _parser;
public HttpHeaderType HeaderType => _headerType;
public string[] KnownValues => _knownValues;
+ public byte[] AsciiBytesWithColonSpace => _asciiBytesWithColonSpace;
public HeaderDescriptor Descriptor => new HeaderDescriptor(this);
}
}
diff --git a/src/System.Net.Http/src/System/Net/Http/Headers/KnownHeaders.cs b/src/System.Net.Http/src/System/Net/Http/Headers/KnownHeaders.cs
index 2d1d035bf0..fb22756f1e 100644
--- a/src/System.Net.Http/src/System/Net/Http/Headers/KnownHeaders.cs
+++ b/src/System.Net.Http/src/System/Net/Http/Headers/KnownHeaders.cs
@@ -62,6 +62,7 @@ namespace System.Net.Http.Headers
public static readonly KnownHeader ProxyAuthenticate = new KnownHeader("Proxy-Authenticate", HttpHeaderType.Response, GenericHeaderParser.MultipleValueAuthenticationParser);
public static readonly KnownHeader ProxyAuthorization = new KnownHeader("Proxy-Authorization", HttpHeaderType.Request, GenericHeaderParser.SingleValueAuthenticationParser);
public static readonly KnownHeader ProxyConnection = new KnownHeader("Proxy-Connection");
+ public static readonly KnownHeader ProxySupport = new KnownHeader("Proxy-Support");
public static readonly KnownHeader PublicKeyPins = new KnownHeader("Public-Key-Pins");
public static readonly KnownHeader Range = new KnownHeader("Range", HttpHeaderType.Request, GenericHeaderParser.RangeParser);
public static readonly KnownHeader Referer = new KnownHeader("Referer", HttpHeaderType.Request, UriHeaderParser.RelativeOrAbsoluteUriParser); // NB: The spelling-mistake "Referer" for "Referrer" must be matched.
@@ -248,6 +249,7 @@ namespace System.Net.Http.Headers
case 'T': case 't': return ContentRange; // Conten[t]-Range
case 'E': case 'e': return IfNoneMatch; // If-Non[e]-Match
case 'O': case 'o': return LastModified; // Last-M[o]dified
+ case 'S': case 's': return ProxySupport; // Proxy-[S]upport
}
break;
diff --git a/src/System.Net.Http/src/System/Net/Http/HttpClient.cs b/src/System.Net.Http/src/System/Net/Http/HttpClient.cs
index 1bcac19a93..6f199b2b74 100644
--- a/src/System.Net.Http/src/System/Net/Http/HttpClient.cs
+++ b/src/System.Net.Http/src/System/Net/Http/HttpClient.cs
@@ -452,8 +452,18 @@ namespace System.Net.Http
cts = _pendingRequestsCts;
}
- // Initiate the send
- Task<HttpResponseMessage> sendTask = base.SendAsync(request, cts.Token);
+ // Initiate the send.
+ Task<HttpResponseMessage> sendTask;
+ try
+ {
+ sendTask = base.SendAsync(request, cts.Token);
+ }
+ catch
+ {
+ HandleFinishSendAsyncCleanup(cts, disposeCts);
+ throw;
+ }
+
return completionOption == HttpCompletionOption.ResponseContentRead ?
FinishSendAsyncBuffered(sendTask, request, cts, disposeCts) :
FinishSendAsyncUnbuffered(sendTask, request, cts, disposeCts);
@@ -475,7 +485,7 @@ namespace System.Net.Http
// Buffer the response content if we've been asked to and we have a Content to buffer.
if (response.Content != null)
{
- await response.Content.LoadIntoBufferAsync(_maxResponseContentBufferSize).ConfigureAwait(false);
+ await response.Content.LoadIntoBufferAsync(_maxResponseContentBufferSize, cts.Token).ConfigureAwait(false);
}
if (NetEventSource.IsEnabled) NetEventSource.ClientSendCompleted(this, response, request);
diff --git a/src/System.Net.Http/src/System/Net/Http/HttpClientHandler.Unix.cs b/src/System.Net.Http/src/System/Net/Http/HttpClientHandler.Unix.cs
index 1ab67fabd1..de34df54c6 100644
--- a/src/System.Net.Http/src/System/Net/Http/HttpClientHandler.Unix.cs
+++ b/src/System.Net.Http/src/System/Net/Http/HttpClientHandler.Unix.cs
@@ -15,15 +15,19 @@ namespace System.Net.Http
{
// Only one of these two handlers will be initialized.
private readonly CurlHandler _curlHandler;
- private readonly ManagedHandler _managedHandler;
+ private readonly SocketsHttpHandler _socketsHttpHandler;
private readonly DiagnosticsHandler _diagnosticsHandler;
+ private ClientCertificateOption _clientCertificateOptions;
- public HttpClientHandler()
+ public HttpClientHandler() : this(UseSocketsHttpHandler) { }
+
+ private HttpClientHandler(bool useSocketsHttpHandler) // used by parameterless ctor and as hook for testing
{
- if (UseManagedHandler)
+ if (useSocketsHttpHandler)
{
- _managedHandler = new ManagedHandler();
- _diagnosticsHandler = new DiagnosticsHandler(_managedHandler);
+ _socketsHttpHandler = new SocketsHttpHandler();
+ _diagnosticsHandler = new DiagnosticsHandler(_socketsHttpHandler);
+ ClientCertificateOptions = ClientCertificateOption.Manual;
}
else
{
@@ -36,26 +40,20 @@ namespace System.Net.Http
{
if (disposing)
{
- ((HttpMessageHandler)_curlHandler ?? _managedHandler).Dispose();
+ ((HttpMessageHandler)_curlHandler ?? _socketsHttpHandler).Dispose();
}
base.Dispose(disposing);
}
- public virtual bool SupportsAutomaticDecompression => _curlHandler != null ?
- _curlHandler.SupportsAutomaticDecompression :
- _managedHandler.SupportsAutomaticDecompression;
+ public virtual bool SupportsAutomaticDecompression => _curlHandler == null || _curlHandler.SupportsAutomaticDecompression;
- public virtual bool SupportsProxy => _curlHandler != null ?
- _curlHandler.SupportsProxy :
- _managedHandler.SupportsProxy;
+ public virtual bool SupportsProxy => true;
- public virtual bool SupportsRedirectConfiguration => _curlHandler != null ?
- _curlHandler.SupportsRedirectConfiguration :
- _managedHandler.SupportsRedirectConfiguration;
+ public virtual bool SupportsRedirectConfiguration => true;
public bool UseCookies
{
- get => _curlHandler != null ? _curlHandler.UseCookies : _managedHandler.UseCookies;
+ get => _curlHandler != null ? _curlHandler.UseCookies : _socketsHttpHandler.UseCookies;
set
{
if (_curlHandler != null)
@@ -64,14 +62,14 @@ namespace System.Net.Http
}
else
{
- _managedHandler.UseCookies = value;
+ _socketsHttpHandler.UseCookies = value;
}
}
}
public CookieContainer CookieContainer
{
- get => _curlHandler != null ? _curlHandler.CookieContainer : _managedHandler.CookieContainer;
+ get => _curlHandler != null ? _curlHandler.CookieContainer : _socketsHttpHandler.CookieContainer;
set
{
if (_curlHandler != null)
@@ -80,14 +78,24 @@ namespace System.Net.Http
}
else
{
- _managedHandler.CookieContainer = value;
+ _socketsHttpHandler.CookieContainer = value;
}
}
}
public ClientCertificateOption ClientCertificateOptions
{
- get => _curlHandler != null ? _curlHandler.ClientCertificateOptions : _managedHandler.ClientCertificateOptions;
+ get
+ {
+ if (_curlHandler != null)
+ {
+ return _curlHandler.ClientCertificateOptions;
+ }
+ else
+ {
+ return _clientCertificateOptions;
+ }
+ }
set
{
if (_curlHandler != null)
@@ -96,18 +104,56 @@ namespace System.Net.Http
}
else
{
- _managedHandler.ClientCertificateOptions = value;
+ switch (value)
+ {
+ case ClientCertificateOption.Manual:
+ ThrowForModifiedManagedSslOptionsIfStarted();
+ _clientCertificateOptions = value;
+ _socketsHttpHandler.SslOptions.LocalCertificateSelectionCallback = (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) => CertificateHelper.GetEligibleClientCertificate(ClientCertificates);
+ break;
+
+ case ClientCertificateOption.Automatic:
+ ThrowForModifiedManagedSslOptionsIfStarted();
+ _clientCertificateOptions = value;
+ _socketsHttpHandler.SslOptions.LocalCertificateSelectionCallback = (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) => CertificateHelper.GetEligibleClientCertificate();
+ break;
+
+ default:
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
}
}
}
- public X509CertificateCollection ClientCertificates => _curlHandler != null ?
- _curlHandler.ClientCertificates :
- _managedHandler.ClientCertificates;
+ public X509CertificateCollection ClientCertificates
+ {
+ get
+ {
+ if (_curlHandler != null)
+ {
+ return _curlHandler.ClientCertificates;
+ }
+ else
+ {
+ if (ClientCertificateOptions != ClientCertificateOption.Manual)
+ {
+ throw new InvalidOperationException(SR.Format(SR.net_http_invalid_enable_first, nameof(ClientCertificateOptions), nameof(ClientCertificateOption.Manual)));
+ }
+
+ return _socketsHttpHandler.SslOptions.ClientCertificates ??
+ (_socketsHttpHandler.SslOptions.ClientCertificates = new X509CertificateCollection());
+ }
+ }
+ }
public Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> ServerCertificateCustomValidationCallback
{
- get => _curlHandler != null ? _curlHandler.ServerCertificateCustomValidationCallback : _managedHandler.ServerCertificateCustomValidationCallback;
+ get
+ {
+ return _curlHandler != null ?
+ _curlHandler.ServerCertificateCustomValidationCallback :
+ (_socketsHttpHandler.SslOptions.RemoteCertificateValidationCallback?.Target as ConnectHelper.CertificateCallbackMapper)?.FromHttpClientHandler;
+ }
set
{
if (_curlHandler != null)
@@ -116,14 +162,17 @@ namespace System.Net.Http
}
else
{
- _managedHandler.ServerCertificateCustomValidationCallback = value;
+ ThrowForModifiedManagedSslOptionsIfStarted();
+ _socketsHttpHandler.SslOptions.RemoteCertificateValidationCallback = value != null ?
+ new ConnectHelper.CertificateCallbackMapper(value).ForSocketsHttpHandler :
+ null;
}
}
}
public bool CheckCertificateRevocationList
{
- get => _curlHandler != null ? _curlHandler.CheckCertificateRevocationList : _managedHandler.CheckCertificateRevocationList;
+ get => _curlHandler != null ? _curlHandler.CheckCertificateRevocationList : _socketsHttpHandler.SslOptions.CertificateRevocationCheckMode == X509RevocationMode.Online;
set
{
if (_curlHandler != null)
@@ -132,14 +181,15 @@ namespace System.Net.Http
}
else
{
- _managedHandler.CheckCertificateRevocationList = value;
+ ThrowForModifiedManagedSslOptionsIfStarted();
+ _socketsHttpHandler.SslOptions.CertificateRevocationCheckMode = value ? X509RevocationMode.Online : X509RevocationMode.NoCheck;
}
}
}
public SslProtocols SslProtocols
{
- get => _curlHandler != null ? _curlHandler.SslProtocols : _managedHandler.SslProtocols;
+ get => _curlHandler != null ? _curlHandler.SslProtocols : _socketsHttpHandler.SslOptions.EnabledSslProtocols;
set
{
if (_curlHandler != null)
@@ -148,14 +198,16 @@ namespace System.Net.Http
}
else
{
- _managedHandler.SslProtocols = value;
+ SecurityProtocol.ThrowOnNotAllowed(value, allowNone: true);
+ ThrowForModifiedManagedSslOptionsIfStarted();
+ _socketsHttpHandler.SslOptions.EnabledSslProtocols = value;
}
}
}
public DecompressionMethods AutomaticDecompression
{
- get => _curlHandler != null ? _curlHandler.AutomaticDecompression : _managedHandler.AutomaticDecompression;
+ get => _curlHandler != null ? _curlHandler.AutomaticDecompression : _socketsHttpHandler.AutomaticDecompression;
set
{
if (_curlHandler != null)
@@ -164,14 +216,14 @@ namespace System.Net.Http
}
else
{
- _managedHandler.AutomaticDecompression = value;
+ _socketsHttpHandler.AutomaticDecompression = value;
}
}
}
public bool UseProxy
{
- get => _curlHandler != null ? _curlHandler.UseProxy : _managedHandler.UseProxy;
+ get => _curlHandler != null ? _curlHandler.UseProxy : _socketsHttpHandler.UseProxy;
set
{
if (_curlHandler != null)
@@ -180,14 +232,14 @@ namespace System.Net.Http
}
else
{
- _managedHandler.UseProxy = value;
+ _socketsHttpHandler.UseProxy = value;
}
}
}
public IWebProxy Proxy
{
- get => _curlHandler != null ? _curlHandler.Proxy : _managedHandler.Proxy;
+ get => _curlHandler != null ? _curlHandler.Proxy : _socketsHttpHandler.Proxy;
set
{
if (_curlHandler != null)
@@ -196,14 +248,14 @@ namespace System.Net.Http
}
else
{
- _managedHandler.Proxy = value;
+ _socketsHttpHandler.Proxy = value;
}
}
}
public ICredentials DefaultProxyCredentials
{
- get => _curlHandler != null ? _curlHandler.DefaultProxyCredentials : _managedHandler.DefaultProxyCredentials;
+ get => _curlHandler != null ? _curlHandler.DefaultProxyCredentials : _socketsHttpHandler.DefaultProxyCredentials;
set
{
if (_curlHandler != null)
@@ -212,14 +264,14 @@ namespace System.Net.Http
}
else
{
- _managedHandler.DefaultProxyCredentials = value;
+ _socketsHttpHandler.DefaultProxyCredentials = value;
}
}
}
public bool PreAuthenticate
{
- get => _curlHandler != null ? _curlHandler.PreAuthenticate : _managedHandler.PreAuthenticate;
+ get => _curlHandler != null ? _curlHandler.PreAuthenticate : _socketsHttpHandler.PreAuthenticate;
set
{
if (_curlHandler != null)
@@ -228,30 +280,26 @@ namespace System.Net.Http
}
else
{
- _managedHandler.PreAuthenticate = value;
+ _socketsHttpHandler.PreAuthenticate = value;
}
}
}
public bool UseDefaultCredentials
{
- get => _curlHandler != null ? _curlHandler.UseDefaultCredentials : _managedHandler.UseDefaultCredentials;
+ get => _curlHandler != null ? _curlHandler.UseDefaultCredentials : false;
set
{
if (_curlHandler != null)
{
_curlHandler.UseDefaultCredentials = value;
}
- else
- {
- _managedHandler.UseDefaultCredentials = value;
- }
}
}
public ICredentials Credentials
{
- get => _curlHandler != null ? _curlHandler.Credentials : _managedHandler.Credentials;
+ get => _curlHandler != null ? _curlHandler.Credentials : _socketsHttpHandler.Credentials;
set
{
if (_curlHandler != null)
@@ -260,14 +308,14 @@ namespace System.Net.Http
}
else
{
- _managedHandler.Credentials = value;
+ _socketsHttpHandler.Credentials = value;
}
}
}
public bool AllowAutoRedirect
{
- get => _curlHandler != null ? _curlHandler.AllowAutoRedirect : _managedHandler.AllowAutoRedirect;
+ get => _curlHandler != null ? _curlHandler.AllowAutoRedirect : _socketsHttpHandler.AllowAutoRedirect;
set
{
if (_curlHandler != null)
@@ -276,14 +324,14 @@ namespace System.Net.Http
}
else
{
- _managedHandler.AllowAutoRedirect = value;
+ _socketsHttpHandler.AllowAutoRedirect = value;
}
}
}
public int MaxAutomaticRedirections
{
- get => _curlHandler != null ? _curlHandler.MaxAutomaticRedirections : _managedHandler.MaxAutomaticRedirections;
+ get => _curlHandler != null ? _curlHandler.MaxAutomaticRedirections : _socketsHttpHandler.MaxAutomaticRedirections;
set
{
if (_curlHandler != null)
@@ -292,14 +340,14 @@ namespace System.Net.Http
}
else
{
- _managedHandler.MaxAutomaticRedirections = value;
+ _socketsHttpHandler.MaxAutomaticRedirections = value;
}
}
}
public int MaxConnectionsPerServer
{
- get => _curlHandler != null ? _curlHandler.MaxConnectionsPerServer : _managedHandler.MaxConnectionsPerServer;
+ get => _curlHandler != null ? _curlHandler.MaxConnectionsPerServer : _socketsHttpHandler.MaxConnectionsPerServer;
set
{
if (_curlHandler != null)
@@ -308,14 +356,14 @@ namespace System.Net.Http
}
else
{
- _managedHandler.MaxConnectionsPerServer = value;
+ _socketsHttpHandler.MaxConnectionsPerServer = value;
}
}
}
public int MaxResponseHeadersLength
{
- get => _curlHandler != null ? _curlHandler.MaxResponseHeadersLength : _managedHandler.MaxResponseHeadersLength;
+ get => _curlHandler != null ? _curlHandler.MaxResponseHeadersLength : _socketsHttpHandler.MaxResponseHeadersLength;
set
{
if (_curlHandler != null)
@@ -324,18 +372,18 @@ namespace System.Net.Http
}
else
{
- _managedHandler.MaxResponseHeadersLength = value;
+ _socketsHttpHandler.MaxResponseHeadersLength = value;
}
}
}
- public IDictionary<String, object> Properties => _curlHandler != null ?
+ public IDictionary<string, object> Properties => _curlHandler != null ?
_curlHandler.Properties :
- _managedHandler.Properties;
+ _socketsHttpHandler.Properties;
protected internal override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) =>
DiagnosticsHandler.IsEnabled() ? _diagnosticsHandler.SendAsync(request, cancellationToken) :
_curlHandler != null ? _curlHandler.SendAsync(request, cancellationToken) :
- _managedHandler.SendAsync(request, cancellationToken);
+ _socketsHttpHandler.SendAsync(request, cancellationToken);
}
}
diff --git a/src/System.Net.Http/src/System/Net/Http/HttpClientHandler.Windows.cs b/src/System.Net.Http/src/System/Net/Http/HttpClientHandler.Windows.cs
index 7893fba575..1c0251c404 100644
--- a/src/System.Net.Http/src/System/Net/Http/HttpClientHandler.Windows.cs
+++ b/src/System.Net.Http/src/System/Net/Http/HttpClientHandler.Windows.cs
@@ -3,8 +3,6 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
-using System.Globalization;
-using System.Net.Http.Headers;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
@@ -18,16 +16,21 @@ namespace System.Net.Http
public partial class HttpClientHandler : HttpMessageHandler
{
private readonly WinHttpHandler _winHttpHandler;
- private readonly ManagedHandler _managedHandler;
+ private readonly SocketsHttpHandler _socketsHttpHandler;
private readonly DiagnosticsHandler _diagnosticsHandler;
private bool _useProxy;
+ private ClientCertificateOption _clientCertificateOptions;
- public HttpClientHandler()
+ public HttpClientHandler() : this(UseSocketsHttpHandler) { }
+
+ private HttpClientHandler(bool useSocketsHttpHandler) // used by parameterless ctor and as hook for testing
{
- if (UseManagedHandler)
+ if (useSocketsHttpHandler)
{
- _managedHandler = new ManagedHandler();
- _diagnosticsHandler = new DiagnosticsHandler(_managedHandler);
+ _socketsHttpHandler = new SocketsHttpHandler();
+ _diagnosticsHandler = new DiagnosticsHandler(_socketsHttpHandler);
+ ClientCertificateOptions = ClientCertificateOption.Manual;
+
}
else
{
@@ -62,7 +65,7 @@ namespace System.Net.Http
if (disposing && !_disposed)
{
_disposed = true;
- ((HttpMessageHandler)_winHttpHandler ?? _managedHandler).Dispose();
+ ((HttpMessageHandler)_winHttpHandler ?? _socketsHttpHandler).Dispose();
}
base.Dispose(disposing);
@@ -74,7 +77,7 @@ namespace System.Net.Http
public bool UseCookies
{
- get => _winHttpHandler != null ? _winHttpHandler.CookieUsePolicy == CookieUsePolicy.UseSpecifiedCookieContainer : _managedHandler.UseCookies;
+ get => _winHttpHandler != null ? _winHttpHandler.CookieUsePolicy == CookieUsePolicy.UseSpecifiedCookieContainer : _socketsHttpHandler.UseCookies;
set
{
if (_winHttpHandler != null)
@@ -83,14 +86,14 @@ namespace System.Net.Http
}
else
{
- _managedHandler.UseCookies = value;
+ _socketsHttpHandler.UseCookies = value;
}
}
}
public CookieContainer CookieContainer
{
- get => _winHttpHandler != null ? _winHttpHandler.CookieContainer : _managedHandler.CookieContainer;
+ get => _winHttpHandler != null ? _winHttpHandler.CookieContainer : _socketsHttpHandler.CookieContainer;
set
{
if (_winHttpHandler != null)
@@ -99,30 +102,14 @@ namespace System.Net.Http
}
else
{
- _managedHandler.CookieContainer = value;
- }
- }
- }
-
- public ClientCertificateOption ClientCertificateOptions
- {
- get => _winHttpHandler != null ? _winHttpHandler.ClientCertificateOption : _managedHandler.ClientCertificateOptions;
- set
- {
- if (_winHttpHandler != null)
- {
- _winHttpHandler.ClientCertificateOption = value;
- }
- else
- {
- _managedHandler.ClientCertificateOptions = value;
+ _socketsHttpHandler.CookieContainer = value;
}
}
}
public DecompressionMethods AutomaticDecompression
{
- get => _winHttpHandler != null ? _winHttpHandler.AutomaticDecompression : _managedHandler.AutomaticDecompression;
+ get => _winHttpHandler != null ? _winHttpHandler.AutomaticDecompression : _socketsHttpHandler.AutomaticDecompression;
set
{
if (_winHttpHandler != null)
@@ -131,14 +118,14 @@ namespace System.Net.Http
}
else
{
- _managedHandler.AutomaticDecompression = value;
+ _socketsHttpHandler.AutomaticDecompression = value;
}
}
}
public bool UseProxy
{
- get => _winHttpHandler != null ? _useProxy : _managedHandler.UseProxy;
+ get => _winHttpHandler != null ? _useProxy : _socketsHttpHandler.UseProxy;
set
{
if (_winHttpHandler != null)
@@ -147,14 +134,14 @@ namespace System.Net.Http
}
else
{
- _managedHandler.UseProxy = value;
+ _socketsHttpHandler.UseProxy = value;
}
}
}
public IWebProxy Proxy
{
- get => _winHttpHandler != null ? _winHttpHandler.Proxy : _managedHandler.Proxy;
+ get => _winHttpHandler != null ? _winHttpHandler.Proxy : _socketsHttpHandler.Proxy;
set
{
if (_winHttpHandler != null)
@@ -163,14 +150,14 @@ namespace System.Net.Http
}
else
{
- _managedHandler.Proxy = value;
+ _socketsHttpHandler.Proxy = value;
}
}
}
public ICredentials DefaultProxyCredentials
{
- get => _winHttpHandler != null ? _winHttpHandler.DefaultProxyCredentials : _managedHandler.DefaultProxyCredentials;
+ get => _winHttpHandler != null ? _winHttpHandler.DefaultProxyCredentials : _socketsHttpHandler.DefaultProxyCredentials;
set
{
if (_winHttpHandler != null)
@@ -179,14 +166,14 @@ namespace System.Net.Http
}
else
{
- _managedHandler.DefaultProxyCredentials = value;
+ _socketsHttpHandler.DefaultProxyCredentials = value;
}
}
}
public bool PreAuthenticate
{
- get => _winHttpHandler != null ? _winHttpHandler.PreAuthenticate : _managedHandler.PreAuthenticate;
+ get => _winHttpHandler != null ? _winHttpHandler.PreAuthenticate : _socketsHttpHandler.PreAuthenticate;
set
{
if (_winHttpHandler != null)
@@ -195,7 +182,7 @@ namespace System.Net.Http
}
else
{
- _managedHandler.PreAuthenticate = value;
+ _socketsHttpHandler.PreAuthenticate = value;
}
}
}
@@ -204,10 +191,12 @@ namespace System.Net.Http
{
// WinHttpHandler doesn't have a separate UseDefaultCredentials property. There
// is just a ServerCredentials property. So, we need to map the behavior.
+ // Do the same for SocketsHttpHandler.Credentials.
//
// This property only affect .ServerCredentials and not .DefaultProxyCredentials.
- get => _winHttpHandler != null ? _winHttpHandler.ServerCredentials == CredentialCache.DefaultCredentials : _managedHandler.UseDefaultCredentials;
+ get => _winHttpHandler != null ? _winHttpHandler.ServerCredentials == CredentialCache.DefaultCredentials :
+ _socketsHttpHandler.Credentials == CredentialCache.DefaultCredentials;
set
{
if (_winHttpHandler != null)
@@ -227,14 +216,25 @@ namespace System.Net.Http
}
else
{
- _managedHandler.UseDefaultCredentials = value;
+ if (value)
+ {
+ _socketsHttpHandler.Credentials = CredentialCache.DefaultCredentials;
+ }
+ else
+ {
+ if (_socketsHttpHandler.Credentials == CredentialCache.DefaultCredentials)
+ {
+ // Only clear out the Credentials property if it was a DefaultCredentials.
+ _socketsHttpHandler.Credentials = null;
+ }
+ }
}
}
}
public ICredentials Credentials
{
- get => _winHttpHandler != null ? _winHttpHandler.ServerCredentials : _managedHandler.Credentials;
+ get => _winHttpHandler != null ? _winHttpHandler.ServerCredentials : _socketsHttpHandler.Credentials;
set
{
if (_winHttpHandler != null)
@@ -243,14 +243,14 @@ namespace System.Net.Http
}
else
{
- _managedHandler.Credentials = value;
+ _socketsHttpHandler.Credentials = value;
}
}
}
public bool AllowAutoRedirect
{
- get => _winHttpHandler != null ? _winHttpHandler.AutomaticRedirection : _managedHandler.AllowAutoRedirect;
+ get => _winHttpHandler != null ? _winHttpHandler.AutomaticRedirection : _socketsHttpHandler.AllowAutoRedirect;
set
{
if (_winHttpHandler != null)
@@ -259,14 +259,14 @@ namespace System.Net.Http
}
else
{
- _managedHandler.AllowAutoRedirect = value;
+ _socketsHttpHandler.AllowAutoRedirect = value;
}
}
}
public int MaxAutomaticRedirections
{
- get => _winHttpHandler != null ? _winHttpHandler.MaxAutomaticRedirections : _managedHandler.MaxAutomaticRedirections;
+ get => _winHttpHandler != null ? _winHttpHandler.MaxAutomaticRedirections : _socketsHttpHandler.MaxAutomaticRedirections;
set
{
if (_winHttpHandler != null)
@@ -275,14 +275,14 @@ namespace System.Net.Http
}
else
{
- _managedHandler.MaxAutomaticRedirections = value;
+ _socketsHttpHandler.MaxAutomaticRedirections = value;
}
}
}
public int MaxConnectionsPerServer
{
- get => _winHttpHandler != null ? _winHttpHandler.MaxConnectionsPerServer : _managedHandler.MaxConnectionsPerServer;
+ get => _winHttpHandler != null ? _winHttpHandler.MaxConnectionsPerServer : _socketsHttpHandler.MaxConnectionsPerServer;
set
{
if (_winHttpHandler != null)
@@ -291,14 +291,14 @@ namespace System.Net.Http
}
else
{
- _managedHandler.MaxConnectionsPerServer = value;
+ _socketsHttpHandler.MaxConnectionsPerServer = value;
}
}
}
public int MaxResponseHeadersLength
{
- get => _winHttpHandler != null ? _winHttpHandler.MaxResponseHeadersLength : _managedHandler.MaxResponseHeadersLength;
+ get => _winHttpHandler != null ? _winHttpHandler.MaxResponseHeadersLength : _socketsHttpHandler.MaxResponseHeadersLength;
set
{
if (_winHttpHandler != null)
@@ -307,18 +307,82 @@ namespace System.Net.Http
}
else
{
- _managedHandler.MaxResponseHeadersLength = value;
+ _socketsHttpHandler.MaxResponseHeadersLength = value;
+ }
+ }
+ }
+
+ public ClientCertificateOption ClientCertificateOptions
+ {
+ get
+ {
+ if (_winHttpHandler != null)
+ {
+ return _winHttpHandler.ClientCertificateOption;
+ }
+ else
+ {
+ return _clientCertificateOptions;
+ }
+ }
+ set
+ {
+ if (_winHttpHandler != null)
+ {
+ _winHttpHandler.ClientCertificateOption = value;
+ }
+ else
+ {
+ switch (value)
+ {
+ case ClientCertificateOption.Manual:
+ ThrowForModifiedManagedSslOptionsIfStarted();
+ _clientCertificateOptions = value;
+ _socketsHttpHandler.SslOptions.LocalCertificateSelectionCallback = (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) => CertificateHelper.GetEligibleClientCertificate(ClientCertificates);
+ break;
+
+ case ClientCertificateOption.Automatic:
+ ThrowForModifiedManagedSslOptionsIfStarted();
+ _clientCertificateOptions = value;
+ _socketsHttpHandler.SslOptions.LocalCertificateSelectionCallback = (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) => CertificateHelper.GetEligibleClientCertificate();
+ break;
+
+ default:
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+ }
+ }
+ }
+
+ public X509CertificateCollection ClientCertificates
+ {
+ get
+ {
+ if (_winHttpHandler != null)
+ {
+ return _winHttpHandler.ClientCertificates;
+ }
+ else
+ {
+ if (ClientCertificateOptions != ClientCertificateOption.Manual)
+ {
+ throw new InvalidOperationException(SR.Format(SR.net_http_invalid_enable_first, nameof(ClientCertificateOptions), nameof(ClientCertificateOption.Manual)));
+ }
+
+ return _socketsHttpHandler.SslOptions.ClientCertificates ??
+ (_socketsHttpHandler.SslOptions.ClientCertificates = new X509CertificateCollection());
}
}
}
- public X509CertificateCollection ClientCertificates => _winHttpHandler != null ?
- _winHttpHandler.ClientCertificates :
- _managedHandler.ClientCertificates;
-
public Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> ServerCertificateCustomValidationCallback
{
- get => _winHttpHandler != null ? _winHttpHandler.ServerCertificateValidationCallback : _managedHandler.ServerCertificateCustomValidationCallback;
+ get
+ {
+ return _winHttpHandler != null ?
+ _winHttpHandler.ServerCertificateValidationCallback :
+ (_socketsHttpHandler.SslOptions.RemoteCertificateValidationCallback?.Target as ConnectHelper.CertificateCallbackMapper)?.FromHttpClientHandler;
+ }
set
{
if (_winHttpHandler != null)
@@ -327,14 +391,17 @@ namespace System.Net.Http
}
else
{
- _managedHandler.ServerCertificateCustomValidationCallback = value;
+ ThrowForModifiedManagedSslOptionsIfStarted();
+ _socketsHttpHandler.SslOptions.RemoteCertificateValidationCallback = value != null ?
+ new ConnectHelper.CertificateCallbackMapper(value).ForSocketsHttpHandler :
+ null;
}
}
}
public bool CheckCertificateRevocationList
{
- get => _winHttpHandler != null ? _winHttpHandler.CheckCertificateRevocationList : _managedHandler.CheckCertificateRevocationList;
+ get => _winHttpHandler != null ? _winHttpHandler.CheckCertificateRevocationList : _socketsHttpHandler.SslOptions.CertificateRevocationCheckMode == X509RevocationMode.Online;
set
{
if (_winHttpHandler != null)
@@ -343,14 +410,15 @@ namespace System.Net.Http
}
else
{
- _managedHandler.CheckCertificateRevocationList = value;
+ ThrowForModifiedManagedSslOptionsIfStarted();
+ _socketsHttpHandler.SslOptions.CertificateRevocationCheckMode = value ? X509RevocationMode.Online : X509RevocationMode.NoCheck;
}
}
}
public SslProtocols SslProtocols
{
- get => _winHttpHandler != null ? _winHttpHandler.SslProtocols : _managedHandler.SslProtocols;
+ get => _winHttpHandler != null ? _winHttpHandler.SslProtocols : _socketsHttpHandler.SslOptions.EnabledSslProtocols;
set
{
if (_winHttpHandler != null)
@@ -359,16 +427,17 @@ namespace System.Net.Http
}
else
{
- _managedHandler.SslProtocols = value;
+ SecurityProtocol.ThrowOnNotAllowed(value, allowNone: true);
+ ThrowForModifiedManagedSslOptionsIfStarted();
+ _socketsHttpHandler.SslOptions.EnabledSslProtocols = value;
}
}
}
- public IDictionary<String, object> Properties => _winHttpHandler != null ?
+ public IDictionary<string, object> Properties => _winHttpHandler != null ?
_winHttpHandler.Properties :
- _managedHandler.Properties;
+ _socketsHttpHandler.Properties;
-
protected internal override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
@@ -411,7 +480,7 @@ namespace System.Net.Http
{
return DiagnosticsHandler.IsEnabled() ?
_diagnosticsHandler.SendAsync(request, cancellationToken) :
- _managedHandler.SendAsync(request, cancellationToken);
+ _socketsHttpHandler.SendAsync(request, cancellationToken);
}
}
}
diff --git a/src/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs b/src/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs
index 119644a254..3080369d59 100644
--- a/src/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs
+++ b/src/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs
@@ -5,53 +5,35 @@
using System.Diagnostics;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
-using System.Threading;
namespace System.Net.Http
{
public partial class HttpClientHandler : HttpMessageHandler
{
// This partial implementation contains members common to all HttpClientHandler implementations.
- private const string ManagedHandlerSettingName = "COMPlus_UseManagedHttpClientHandler";
- private const string AppCtxManagedHandlerSettingName = "System.Net.Http.UseManagedHttpClientHandler";
+ private const string SocketsHttpHandlerEnvironmentVariableSettingName = "DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER";
+ private const string SocketsHttpHandlerAppCtxSettingName = "System.Net.Http.UseSocketsHttpHandler";
- private static LocalDataStoreSlot s_useManagedHandlerSlot;
-
- private static bool UseManagedHandler
+ private static bool UseSocketsHttpHandler
{
get
{
- // Check the environment variable to see if it's been set to true. If it has, use the managed handler.
- if (Environment.GetEnvironmentVariable(ManagedHandlerSettingName) == "true")
+ // First check for the AppContext switch, giving it priority over over the environment variable.
+ if (AppContext.TryGetSwitch(SocketsHttpHandlerAppCtxSettingName, out bool useSocketsHttpHandler))
{
- return true;
+ return useSocketsHttpHandler;
}
- if (AppContext.TryGetSwitch(AppCtxManagedHandlerSettingName, out bool isManagedEnabled) && isManagedEnabled)
+ // AppContext switch wasn't used. Check the environment variable to determine which handler should be used.
+ string envVar = Environment.GetEnvironmentVariable(SocketsHttpHandlerEnvironmentVariableSettingName);
+ if (envVar != null && (envVar.Equals("false", StringComparison.OrdinalIgnoreCase) || envVar.Equals("0")))
{
- return true;
+ // Use WinHttpHandler on Windows and CurlHandler on Unix.
+ return false;
}
- // Then check whether a thread local has been set with the same name.
- // If it's been set to a Boolean true, also use the managed handler.
- LocalDataStoreSlot slot = LazyInitializer.EnsureInitialized(ref s_useManagedHandlerSlot, () =>
- {
- LocalDataStoreSlot local = Thread.GetNamedDataSlot(ManagedHandlerSettingName);
- if (local == null)
- {
- try
- {
- local = Thread.AllocateNamedDataSlot(ManagedHandlerSettingName);
- }
- catch (ArgumentException)
- {
- local = Thread.GetNamedDataSlot(ManagedHandlerSettingName);
- }
- }
- return local;
- });
- Debug.Assert(slot != null);
- return Thread.GetData(slot) is bool result && result;
+ // Default to using SocketsHttpHandler.
+ return true;
}
}
diff --git a/src/System.Net.Http/src/System/Net/Http/HttpClientHandler.netcoreapp.cs b/src/System.Net.Http/src/System/Net/Http/HttpClientHandler.netcoreapp.cs
new file mode 100644
index 0000000000..8296f917ae
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/HttpClientHandler.netcoreapp.cs
@@ -0,0 +1,24 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Net.Security;
+using System.Security.Authentication;
+using System.Security.Cryptography.X509Certificates;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Net.Http
+{
+ // This partial implementation contains members common to NetCoreApp
+ public partial class HttpClientHandler : HttpMessageHandler
+ {
+ private void ThrowForModifiedManagedSslOptionsIfStarted()
+ {
+ // Hack to trigger an InvalidOperationException if a property that's stored on
+ // SslOptions is changed, since SslOptions itself does not do any such checks.
+ _socketsHttpHandler.SslOptions = _socketsHttpHandler.SslOptions;
+ }
+ }
+}
diff --git a/src/System.Net.Http/src/System/Net/Http/HttpContent.cs b/src/System.Net.Http/src/System/Net/Http/HttpContent.cs
index 191c5f422b..feadae8c6a 100644
--- a/src/System.Net.Http/src/System/Net/Http/HttpContent.cs
+++ b/src/System.Net.Http/src/System/Net/Http/HttpContent.cs
@@ -299,7 +299,18 @@ namespace System.Net.Http
protected abstract Task SerializeToStreamAsync(Stream stream, TransportContext context);
- public Task CopyToAsync(Stream stream, TransportContext context)
+ // TODO #9071: Expose this publicly. Until it's public, only sealed or internal types should override it, and then change
+ // their SerializeToStreamAsync implementation to delegate to this one. They need to be sealed as otherwise an external
+ // type could derive from it and override SerializeToStreamAsync(stream, context) further, at which point when
+ // HttpClient calls SerializeToStreamAsync(stream, context, cancellationToken), their custom override will be skipped.
+ internal virtual Task SerializeToStreamAsync(Stream stream, TransportContext context, CancellationToken cancellationToken) =>
+ SerializeToStreamAsync(stream, context);
+
+ public Task CopyToAsync(Stream stream, TransportContext context) =>
+ CopyToAsync(stream, context, CancellationToken.None);
+
+ // TODO #9071: Expose this publicly.
+ internal Task CopyToAsync(Stream stream, TransportContext context, CancellationToken cancellationToken)
{
CheckDisposed();
if (stream == null)
@@ -309,19 +320,17 @@ namespace System.Net.Http
try
{
- Task task = null;
ArraySegment<byte> buffer;
if (TryGetBuffer(out buffer))
{
- task = stream.WriteAsync(buffer.Array, buffer.Offset, buffer.Count);
+ return CopyToAsyncCore(stream.WriteAsync(new ReadOnlyMemory<byte>(buffer.Array, buffer.Offset, buffer.Count), cancellationToken));
}
else
{
- task = SerializeToStreamAsync(stream, context);
+ Task task = SerializeToStreamAsync(stream, context, cancellationToken);
CheckTaskNotNull(task);
+ return CopyToAsyncCore(new ValueTask(task));
}
-
- return CopyToAsyncCore(task);
}
catch (Exception e) when (StreamCopyExceptionNeedsWrapping(e))
{
@@ -329,7 +338,7 @@ namespace System.Net.Http
}
}
- private static async Task CopyToAsyncCore(Task copyTask)
+ private static async Task CopyToAsyncCore(ValueTask copyTask)
{
try
{
@@ -354,7 +363,10 @@ namespace System.Net.Http
// No "CancellationToken" parameter needed since canceling the CTS will close the connection, resulting
// in an exception being thrown while we're buffering.
// If buffering is used without a connection, it is supposed to be fast, thus no cancellation required.
- public Task LoadIntoBufferAsync(long maxBufferSize)
+ public Task LoadIntoBufferAsync(long maxBufferSize) =>
+ LoadIntoBufferAsync(maxBufferSize, CancellationToken.None);
+
+ internal Task LoadIntoBufferAsync(long maxBufferSize, CancellationToken cancellationToken)
{
CheckDisposed();
if (maxBufferSize > HttpContent.MaxBufferSize)
@@ -382,7 +394,7 @@ namespace System.Net.Http
try
{
- Task task = SerializeToStreamAsync(tempBuffer, null);
+ Task task = SerializeToStreamAsync(tempBuffer, null, cancellationToken);
CheckTaskNotNull(task);
return LoadIntoBufferAsyncCore(task, tempBuffer);
}
@@ -719,6 +731,12 @@ namespace System.Net.Http
return base.WriteAsync(buffer, offset, count, cancellationToken);
}
+ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken)
+ {
+ CheckSize(buffer.Length);
+ return base.WriteAsync(buffer, cancellationToken);
+ }
+
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
{
CheckSize(count);
@@ -851,11 +869,11 @@ namespace System.Net.Http
_length += count;
}
- public override void Write(ReadOnlySpan<byte> source)
+ public override void Write(ReadOnlySpan<byte> buffer)
{
- EnsureCapacity(_length + source.Length);
- source.CopyTo(new Span<byte>(_buffer, _length, source.Length));
- _length += source.Length;
+ EnsureCapacity(_length + buffer.Length);
+ buffer.CopyTo(new Span<byte>(_buffer, _length, buffer.Length));
+ _length += buffer.Length;
}
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
@@ -864,10 +882,10 @@ namespace System.Net.Http
return Task.CompletedTask;
}
- public override Task WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken = default)
+ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
{
- Write(source.Span);
- return Task.CompletedTask;
+ Write(buffer.Span);
+ return default;
}
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState) =>
diff --git a/src/System.Net.Http/src/System/Net/Http/HttpMethod.cs b/src/System.Net.Http/src/System/Net/Http/HttpMethod.cs
index 8abe00eceb..fbe6b1aca8 100644
--- a/src/System.Net.Http/src/System/Net/Http/HttpMethod.cs
+++ b/src/System.Net.Http/src/System/Net/Http/HttpMethod.cs
@@ -19,9 +19,7 @@ namespace System.Net.Http
private static readonly HttpMethod s_optionsMethod = new HttpMethod("OPTIONS");
private static readonly HttpMethod s_traceMethod = new HttpMethod("TRACE");
private static readonly HttpMethod s_patchMethod = new HttpMethod("PATCH");
-
- // Don't expose CONNECT as static property, since it's used by the transport to connect to a proxy.
- // CONNECT is not used by users directly.
+ private static readonly HttpMethod s_connectMethod = new HttpMethod("CONNECT");
public static HttpMethod Get
{
@@ -63,6 +61,14 @@ namespace System.Net.Http
get { return s_patchMethod; }
}
+ // Don't expose CONNECT as static property, since it's used by the transport to connect to a proxy.
+ // CONNECT is not used by users directly.
+
+ internal static HttpMethod Connect
+ {
+ get { return s_connectMethod; }
+ }
+
public string Method
{
get { return _method; }
diff --git a/src/System.Net.Http/src/System/Net/Http/HttpResponseMessage.cs b/src/System.Net.Http/src/System/Net/Http/HttpResponseMessage.cs
index 3e368add2a..9df1d1c989 100644
--- a/src/System.Net.Http/src/System/Net/Http/HttpResponseMessage.cs
+++ b/src/System.Net.Http/src/System/Net/Http/HttpResponseMessage.cs
@@ -36,6 +36,8 @@ namespace System.Net.Http
}
}
+ internal void SetVersionWithoutValidation(Version value) => _version = value;
+
public HttpContent Content
{
get { return _content; }
@@ -74,6 +76,8 @@ namespace System.Net.Http
}
}
+ internal void SetStatusCodeWithoutValidation(HttpStatusCode value) => _statusCode = value;
+
public string ReasonPhrase
{
get
@@ -97,6 +101,8 @@ namespace System.Net.Http
}
}
+ internal void SetReasonPhraseWithoutValidation(string value) => _reasonPhrase = value;
+
public HttpResponseHeaders Headers
{
get
diff --git a/src/System.Net.Http/src/System/Net/Http/HttpRuleParser.cs b/src/System.Net.Http/src/System/Net/Http/HttpRuleParser.cs
index e104353ebe..8f8961030b 100644
--- a/src/System.Net.Http/src/System/Net/Http/HttpRuleParser.cs
+++ b/src/System.Net.Http/src/System/Net/Http/HttpRuleParser.cs
@@ -143,6 +143,13 @@ namespace System.Net.Http
return true;
}
+ internal static string GetTokenString(ReadOnlySpan<byte> input)
+ {
+ Debug.Assert(IsToken(input));
+
+ return Encoding.ASCII.GetString(input);
+ }
+
internal static int GetWhitespaceLength(string input, int startIndex)
{
Debug.Assert(input != null);
diff --git a/src/System.Net.Http/src/System/Net/Http/HttpUtilities.cs b/src/System.Net.Http/src/System/Net/Http/HttpUtilities.cs
index 6bd04526a1..81452d118a 100644
--- a/src/System.Net.Http/src/System/Net/Http/HttpUtilities.cs
+++ b/src/System.Net.Http/src/System/Net/Http/HttpUtilities.cs
@@ -14,23 +14,32 @@ namespace System.Net.Http
{
internal static class HttpUtilities
{
- internal static Version DefaultRequestVersion =>
-#if uap
- HttpVersionInternal.Version20;
-#else
- HttpVersionInternal.Version11;
-#endif
+ internal static Version DefaultRequestVersion => HttpVersionInternal.Version20;
+
internal static Version DefaultResponseVersion => HttpVersionInternal.Version11;
internal static bool IsHttpUri(Uri uri)
{
Debug.Assert(uri != null);
-
- string scheme = uri.Scheme;
- return string.Equals("http", scheme, StringComparison.OrdinalIgnoreCase) ||
- string.Equals("https", scheme, StringComparison.OrdinalIgnoreCase);
+ return IsSupportedScheme(uri.Scheme);
}
+ internal static bool IsSupportedScheme(string scheme) =>
+ IsSupportedNonSecureScheme(scheme) ||
+ IsSupportedSecureScheme(scheme);
+
+ internal static bool IsSupportedNonSecureScheme(string scheme) =>
+ string.Equals(scheme, "http", StringComparison.OrdinalIgnoreCase) || IsNonSecureWebSocketScheme(scheme);
+
+ internal static bool IsSupportedSecureScheme(string scheme) =>
+ string.Equals(scheme, "https", StringComparison.OrdinalIgnoreCase) || IsSecureWebSocketScheme(scheme);
+
+ internal static bool IsNonSecureWebSocketScheme(string scheme) =>
+ string.Equals(scheme, "ws", StringComparison.OrdinalIgnoreCase);
+
+ internal static bool IsSecureWebSocketScheme(string scheme) =>
+ string.Equals(scheme, "wss", StringComparison.OrdinalIgnoreCase);
+
// Always specify TaskScheduler.Default to prevent us from using a user defined TaskScheduler.Current.
//
// Since we're not doing any CPU and/or I/O intensive operations, continue on the same thread.
@@ -42,4 +51,4 @@ namespace System.Net.Http
TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
}
}
-}
+} \ No newline at end of file
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/AuthenticateAndRedirectHandler.cs b/src/System.Net.Http/src/System/Net/Http/Managed/AuthenticateAndRedirectHandler.cs
deleted file mode 100644
index 24f4201eb9..0000000000
--- a/src/System.Net.Http/src/System/Net/Http/Managed/AuthenticateAndRedirectHandler.cs
+++ /dev/null
@@ -1,228 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-using System.Net.Http.Headers;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace System.Net.Http
-{
- internal sealed partial class AuthenticateAndRedirectHandler : HttpMessageHandler
- {
- private readonly HttpMessageHandler _innerHandler;
- private readonly bool _preAuthenticate;
- private readonly ICredentials _credentials;
- private readonly bool _allowRedirect;
- private readonly int _maxAutomaticRedirections;
-
- public AuthenticateAndRedirectHandler(bool preAuthenticate, ICredentials credentials, bool allowRedirect, int maxAutomaticRedirections, HttpMessageHandler innerHandler)
- {
- Debug.Assert(innerHandler != null);
-
- _preAuthenticate = preAuthenticate;
- _credentials = credentials;
- _allowRedirect = allowRedirect;
-
- if (allowRedirect && maxAutomaticRedirections < 0)
- {
- throw new ArgumentOutOfRangeException(nameof(maxAutomaticRedirections));
- }
-
- _maxAutomaticRedirections = maxAutomaticRedirections;
- _innerHandler = innerHandler;
- }
-
- protected internal override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
- {
- HttpResponseMessage response;
- uint redirectCount = 0;
- while (true)
- {
- // Just as with WinHttpHandler and CurlHandler, for security reasons, we drop the server credential if it is
- // anything other than a CredentialCache on redirection. We allow credentials in a CredentialCache since they
- // are specifically tied to URIs.
- ICredentials currentCredential = redirectCount > 0 ? _credentials as CredentialCache : _credentials;
-
- if (currentCredential != null && _preAuthenticate)
- {
- AuthenticationHelper.TrySetBasicAuthToken(request, currentCredential);
- }
-
- response = await _innerHandler.SendAsync(request, cancellationToken).ConfigureAwait(false);
-
- if (currentCredential != null && response.StatusCode == HttpStatusCode.Unauthorized)
- {
- AuthenticationHeaderValue selectedAuth = GetSupportedAuthScheme(response.Headers.WwwAuthenticate);
- if (selectedAuth != null)
- {
- switch (selectedAuth.Scheme)
- {
- case AuthenticationHelper.Digest:
- // Update digest response with new parameter from WWWAuthenticate
- var digestResponse = new AuthenticationHelper.DigestResponse(selectedAuth.Parameter);
- if (await AuthenticationHelper.TrySetDigestAuthToken(request, currentCredential, digestResponse, HttpKnownHeaderNames.Authorization).ConfigureAwait(false))
- {
- response.Dispose();
- response = await _innerHandler.SendAsync(request, cancellationToken).ConfigureAwait(false);
-
- // Retry in case of nonce timeout in server.
- if (response.StatusCode == HttpStatusCode.Unauthorized)
- {
- foreach (AuthenticationHeaderValue ahv in response.Headers.WwwAuthenticate)
- {
- if (ahv.Scheme == AuthenticationHelper.Digest)
- {
- digestResponse = new AuthenticationHelper.DigestResponse(ahv.Parameter);
- if (AuthenticationHelper.IsServerNonceStale(digestResponse) &&
- await AuthenticationHelper.TrySetDigestAuthToken(request, currentCredential, digestResponse, HttpKnownHeaderNames.Authorization).ConfigureAwait(false))
- {
- response.Dispose();
- response = await _innerHandler.SendAsync(request, cancellationToken).ConfigureAwait(false);
- }
-
- break;
- }
- }
- }
- }
- break;
-
- case AuthenticationHelper.Basic:
- if (_preAuthenticate)
- {
- // We already tried these credentials via preauthentication, so no need to try again
- break;
- }
-
- if (AuthenticationHelper.TrySetBasicAuthToken(request, currentCredential))
- {
- response.Dispose();
- response = await _innerHandler.SendAsync(request, cancellationToken).ConfigureAwait(false);
- }
- break;
- }
- }
- }
-
- if (!RequestNeedsRedirect(response))
- {
- break;
- }
-
- // Clear the authorization header, if the request requires redirect.
- request.Headers.Authorization = null;
-
- Uri location = response.Headers.Location;
- if (location == null)
- {
- // No location header. Nothing to redirect to.
- break;
- }
-
- if (!location.IsAbsoluteUri)
- {
- location = new Uri(request.RequestUri, location);
- }
-
- // Disallow automatic redirection from secure to non-secure schemes
- bool allowed =
- (HttpUtilities.IsSupportedNonSecureScheme(request.RequestUri.Scheme) && HttpUtilities.IsSupportedScheme(location.Scheme)) ||
- (HttpUtilities.IsSupportedSecureScheme(request.RequestUri.Scheme) && HttpUtilities.IsSupportedSecureScheme(location.Scheme));
- if (!allowed)
- {
- break;
- }
-
- redirectCount++;
- if (redirectCount > _maxAutomaticRedirections)
- {
- throw new HttpRequestException(SR.net_http_max_redirects);
- }
-
- // Set up for the automatic redirect
- request.RequestUri = location;
-
- if (RequestRequiresForceGet(response.StatusCode, request.Method))
- {
- request.Method = HttpMethod.Get;
- request.Content = null;
- }
-
- // Do the redirect.
- response.Dispose();
- }
-
- return response;
- }
-
- private bool RequestNeedsRedirect(HttpResponseMessage response)
- {
- // Return if redirect is not requested.
- if (!_allowRedirect)
- return false;
-
- bool needRedirect = false;
- switch (response.StatusCode)
- {
- case HttpStatusCode.Moved:
- case HttpStatusCode.Found:
- case HttpStatusCode.SeeOther:
- case HttpStatusCode.TemporaryRedirect:
- needRedirect = true;
- break;
-
- case HttpStatusCode.MultipleChoices:
- needRedirect = response.Headers.Location != null; // Don't redirect if no Location specified
- break;
- }
-
- return needRedirect;
- }
-
- private static bool RequestRequiresForceGet(HttpStatusCode statusCode, HttpMethod requestMethod)
- {
- if (statusCode == HttpStatusCode.Moved ||
- statusCode == HttpStatusCode.Found ||
- statusCode == HttpStatusCode.SeeOther ||
- statusCode == HttpStatusCode.MultipleChoices)
- {
- return requestMethod == HttpMethod.Post;
- }
-
- return false;
- }
-
- private static AuthenticationHeaderValue GetSupportedAuthScheme(HttpHeaderValueCollection<AuthenticationHeaderValue> authenticateValues)
- {
- AuthenticationHeaderValue basicAuthenticationHeaderValue = null;
-
- // Only Digest and Basic auth supported, ignore others.
- foreach (AuthenticationHeaderValue ahv in authenticateValues)
- {
- if (ahv.Scheme == AuthenticationHelper.Digest)
- {
- return ahv;
- }
- else if (ahv.Scheme == AuthenticationHelper.Basic)
- {
- basicAuthenticationHeaderValue = ahv;
- }
- }
-
- return basicAuthenticationHeaderValue;
- }
-
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- _innerHandler.Dispose();
- }
-
- base.Dispose(disposing);
- }
- }
-}
-
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/AuthenticationHelper.Basic.cs b/src/System.Net.Http/src/System/Net/Http/Managed/AuthenticationHelper.Basic.cs
deleted file mode 100644
index 1e55050131..0000000000
--- a/src/System.Net.Http/src/System/Net/Http/Managed/AuthenticationHelper.Basic.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Net.Http.Headers;
-using System.Text;
-
-namespace System.Net.Http
-{
- internal partial class AuthenticationHelper
- {
- public const string Basic = "Basic";
-
- public static bool TrySetBasicAuthToken(HttpRequestMessage request, ICredentials credentials)
- {
- NetworkCredential credential = credentials.GetCredential(request.RequestUri, Basic);
- if (credential == null)
- {
- return false;
- }
-
- request.Headers.Authorization = new AuthenticationHeaderValue(Basic, GetBasicTokenForCredential(credential));
- return true;
- }
-
- public static string GetBasicTokenForCredential(NetworkCredential credential)
- {
- if (credential.UserName.IndexOf(':') != -1)
- {
- // TODO #23135: What's the right way to handle this?
- throw new NotImplementedException($"Basic auth: can't handle ':' in username \"{credential.UserName}\"");
- }
-
- string userPass = credential.UserName + ":" + credential.Password;
- if (!string.IsNullOrEmpty(credential.Domain))
- {
- if (credential.Domain.IndexOf(':') != -1)
- {
- // TODO #23135: What's the right way to handle this?
- throw new NotImplementedException($"Basic auth: can't handle ':' in domain \"{credential.Domain}\"");
- }
-
- userPass = credential.Domain + "\\" + userPass;
- }
-
- return Convert.ToBase64String(Encoding.UTF8.GetBytes(userPass));
- }
- }
-}
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/ChunkedEncodingReadStream.cs b/src/System.Net.Http/src/System/Net/Http/Managed/ChunkedEncodingReadStream.cs
deleted file mode 100644
index 9b8b5670eb..0000000000
--- a/src/System.Net.Http/src/System/Net/Http/Managed/ChunkedEncodingReadStream.cs
+++ /dev/null
@@ -1,159 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace System.Net.Http
-{
- internal sealed partial class HttpConnection
- {
- private sealed class ChunkedEncodingReadStream : HttpContentReadStream
- {
- private ulong _chunkBytesRemaining;
-
- public ChunkedEncodingReadStream(HttpConnection connection)
- : base(connection)
- {
- _chunkBytesRemaining = 0;
- }
-
- private async Task<bool> TryGetNextChunk(CancellationToken cancellationToken)
- {
- Debug.Assert(_chunkBytesRemaining == 0);
-
- // Start of chunk, read chunk size.
- ulong chunkSize = ParseHexSize(await _connection.ReadNextLineAsync(cancellationToken).ConfigureAwait(false));
- _chunkBytesRemaining = chunkSize;
-
- if (chunkSize > 0)
- {
- return true;
- }
-
- // Indicates end of response body. We expect final CRLF after this.
- await _connection.ReadCrLfAsync(cancellationToken).ConfigureAwait(false);
- _connection.ReturnConnectionToPool();
- _connection = null;
- return false;
- }
-
- private ulong ParseHexSize(ArraySegment<byte> line)
- {
- ulong size = 0;
- try
- {
- for (int i = 0; i < line.Count; i++)
- {
- char c = (char)line[i];
- if ((uint)(c - '0') <= '9' - '0')
- {
- size = checked(size * 16 + ((ulong)c - '0'));
- }
- else if ((uint)(c - 'a') <= ('f' - 'a'))
- {
- size = checked(size * 16 + ((ulong)c - 'a' + 10));
- }
- else if ((uint)(c - 'A') <= ('F' - 'A'))
- {
- size = checked(size * 16 + ((ulong)c - 'A' + 10));
- }
- else
- {
- if (c == '\r' && i > 0)
- {
- break;
- }
- throw new IOException(SR.net_http_invalid_response);
- }
- }
- }
- catch (OverflowException e)
- {
- throw new IOException(SR.net_http_invalid_response, e);
- }
- return size;
- }
-
- private async Task ConsumeChunkBytes(ulong bytesConsumed, CancellationToken cancellationToken)
- {
- Debug.Assert(bytesConsumed <= _chunkBytesRemaining);
- _chunkBytesRemaining -= bytesConsumed;
- if (_chunkBytesRemaining == 0)
- {
- await _connection.ReadCrLfAsync(cancellationToken).ConfigureAwait(false);
- }
- }
-
- public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
- {
- ValidateBufferArgs(buffer, offset, count);
- return ReadAsync(new Memory<byte>(buffer, offset, count)).AsTask();
- }
-
- public override async ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken = default)
- {
- if (_connection == null || destination.Length == 0)
- {
- // Response body fully consumed or the caller didn't ask for any data
- return 0;
- }
-
- if (_chunkBytesRemaining == 0)
- {
- if (!await TryGetNextChunk(cancellationToken).ConfigureAwait(false))
- {
- // End of response body
- return 0;
- }
- }
-
- if (_chunkBytesRemaining < (ulong)destination.Length)
- {
- destination = destination.Slice(0, (int)_chunkBytesRemaining);
- }
-
- int bytesRead = await _connection.ReadAsync(destination, cancellationToken).ConfigureAwait(false);
-
- if (bytesRead <= 0)
- {
- // Unexpected end of response stream
- throw new IOException(SR.net_http_invalid_response);
- }
-
- await ConsumeChunkBytes((ulong)bytesRead, cancellationToken).ConfigureAwait(false);
-
- return bytesRead;
- }
-
- public override async Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
- {
- if (destination == null)
- {
- throw new ArgumentNullException(nameof(destination));
- }
-
- if (_connection == null)
- {
- // Response body fully consumed
- return;
- }
-
- if (_chunkBytesRemaining > 0)
- {
- await _connection.CopyToAsync(destination, _chunkBytesRemaining, cancellationToken).ConfigureAwait(false);
- await ConsumeChunkBytes(_chunkBytesRemaining, cancellationToken).ConfigureAwait(false);
- }
-
- while (await TryGetNextChunk(cancellationToken).ConfigureAwait(false))
- {
- await _connection.CopyToAsync(destination, _chunkBytesRemaining, cancellationToken).ConfigureAwait(false);
- await ConsumeChunkBytes(_chunkBytesRemaining, cancellationToken).ConfigureAwait(false);
- }
- }
- }
- }
-}
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/ChunkedEncodingWriteStream.cs b/src/System.Net.Http/src/System/Net/Http/Managed/ChunkedEncodingWriteStream.cs
deleted file mode 100644
index 16fad17c4d..0000000000
--- a/src/System.Net.Http/src/System/Net/Http/Managed/ChunkedEncodingWriteStream.cs
+++ /dev/null
@@ -1,91 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace System.Net.Http
-{
- internal sealed partial class HttpConnection : IDisposable
- {
- private sealed class ChunkedEncodingWriteStream : HttpContentWriteStream
- {
- private static readonly byte[] s_finalChunkBytes = { (byte)'0', (byte)'\r', (byte)'\n', (byte)'\r', (byte)'\n' };
-
- public ChunkedEncodingWriteStream(HttpConnection connection, CancellationToken cancellationToken) :
- base(connection, cancellationToken)
- {
- }
-
- public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken ignored)
- {
- ValidateBufferArgs(buffer, offset, count);
- return WriteAsync(new Memory<byte>(buffer, offset, count), ignored);
- }
-
- public override Task WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken = default)
- {
- if (source.Length == 0)
- {
- // Don't write if nothing was given, especially since we don't want to accidentally send a 0 chunk,
- // which would indicate end of body. Instead, just ensure no content is stuck in the buffer.
- return _connection.FlushAsync(RequestCancellationToken);
- }
-
- if (_connection._currentRequest == null)
- {
- // Avoid sending anything if the response has already completed, in which case there's no point
- // sending further data (this might happen, for example, on a redirect.)
- return Task.CompletedTask;
- }
-
- return WriteChunkAsync(source);
- }
-
- private async Task WriteChunkAsync(ReadOnlyMemory<byte> source)
- {
- // Write chunk length -- hex representation of count
- bool digitWritten = false;
- for (int i = 7; i >= 0; i--)
- {
- int shift = i * 4;
- int mask = 0xF << shift;
- int digit = (source.Length & mask) >> shift;
- if (digitWritten || digit != 0)
- {
- await _connection.WriteByteAsync((byte)(digit < 10 ? '0' + digit : 'A' + digit - 10), RequestCancellationToken).ConfigureAwait(false);
- digitWritten = true;
- }
- }
-
- // End chunk length
- await _connection.WriteTwoBytesAsync((byte)'\r', (byte)'\n', RequestCancellationToken).ConfigureAwait(false);
-
- // Write chunk contents
- await _connection.WriteAsync(source, RequestCancellationToken).ConfigureAwait(false);
- await _connection.WriteTwoBytesAsync((byte)'\r', (byte)'\n', RequestCancellationToken).ConfigureAwait(false);
-
- // Flush the chunk. This is reasonable from the standpoint of having just written a standalone piece
- // of data, but is also necessary to support duplex communication, where a CopyToAsync is taking the
- // data from content and writing it here; if there was no flush, we might not send the data until the
- // source was empty, and it might be kept open to enable subsequent communication. And it's necessary
- // in general for at least the first write, as we need to ensure if it's the entirety of the content
- // and if all of the headers and content fit in the write buffer that we've actually sent the request.
- await _connection.FlushAsync(RequestCancellationToken).ConfigureAwait(false);
- }
-
- public override Task FlushAsync(CancellationToken ignored)
- {
- return _connection.FlushAsync(RequestCancellationToken);
- }
-
- public override async Task FinishAsync()
- {
- // Send 0 byte chunk to indicate end, then final CrLf
- await _connection.WriteBytesAsync(s_finalChunkBytes, RequestCancellationToken).ConfigureAwait(false);
- _connection = null;
- }
- }
- }
-}
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/ConnectHelper.cs b/src/System.Net.Http/src/System/Net/Http/Managed/ConnectHelper.cs
deleted file mode 100644
index 3d64d2d660..0000000000
--- a/src/System.Net.Http/src/System/Net/Http/Managed/ConnectHelper.cs
+++ /dev/null
@@ -1,100 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-using System.IO;
-using System.Net.Sockets;
-using System.Runtime.CompilerServices;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace System.Net.Http
-{
- internal static class ConnectHelper
- {
- public static async ValueTask<Stream> ConnectAsync(string host, int port, CancellationToken cancellationToken)
- {
- try
- {
- // Rather than creating a new Socket and calling ConnectAsync on it, we use the static
- // Socket.ConnectAsync with a SocketAsyncEventArgs, as we can then use Socket.CancelConnectAsync
- // to cancel it if needed.
- using (var saea = new BuilderAndCancellationTokenSocketAsyncEventArgs(cancellationToken))
- {
- // Configure which server to which to connect.
- saea.RemoteEndPoint = IPAddress.TryParse(host, out IPAddress address) ?
- (EndPoint)new IPEndPoint(address, port) :
- new DnsEndPoint(host, port);
-
- // Hook up a callback that'll complete the Task when the operation completes.
- saea.Completed += (s, e) =>
- {
- var csaea = (BuilderAndCancellationTokenSocketAsyncEventArgs)e;
- switch (e.SocketError)
- {
- case SocketError.Success:
- csaea.Builder.SetResult();
- break;
- case SocketError.OperationAborted:
- case SocketError.ConnectionAborted:
- if (cancellationToken.IsCancellationRequested)
- {
- csaea.Builder.SetException(new OperationCanceledException(csaea.CancellationToken));
- break;
- }
- goto default;
- default:
- csaea.Builder.SetException(new SocketException((int)e.SocketError));
- break;
- }
- };
-
- // Initiate the connection.
- if (Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, saea))
- {
- // Connect completing asynchronously. Enable it to be canceled and wait for it.
- using (cancellationToken.Register(s => Socket.CancelConnectAsync((SocketAsyncEventArgs)s), saea))
- {
- await saea.Builder.Task.ConfigureAwait(false);
- }
- }
- else if (saea.SocketError != SocketError.Success)
- {
- // Connect completed synchronously but unsuccessfully.
- throw new SocketException((int)saea.SocketError);
- }
-
- Debug.Assert(saea.SocketError == SocketError.Success, $"Expected Success, got {saea.SocketError}.");
- Debug.Assert(saea.ConnectSocket != null, "Expected non-null socket");
- Debug.Assert(saea.ConnectSocket.Connected, "Expected socket to be connected");
-
- // Configure the socket and return a stream for it.
- Socket socket = saea.ConnectSocket;
- socket.NoDelay = true;
- return new NetworkStream(socket, ownsSocket: true);
- }
- }
- catch (SocketException se)
- {
- throw new HttpRequestException(se.Message, se);
- }
- }
-
- /// <summary>SocketAsyncEventArgs that carries with it additional state for a Task builder and a CancellationToken.</summary>
- private sealed class BuilderAndCancellationTokenSocketAsyncEventArgs : SocketAsyncEventArgs
- {
- public AsyncTaskMethodBuilder Builder { get; }
- public CancellationToken CancellationToken { get; }
-
- public BuilderAndCancellationTokenSocketAsyncEventArgs(CancellationToken cancellationToken)
- {
- var b = new AsyncTaskMethodBuilder();
- var ignored = b.Task; // force initialization
- Builder = b;
-
- CancellationToken = cancellationToken;
- }
- }
- }
-}
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/ConnectionCloseReadStream.cs b/src/System.Net.Http/src/System/Net/Http/Managed/ConnectionCloseReadStream.cs
deleted file mode 100644
index ac4cb984c1..0000000000
--- a/src/System.Net.Http/src/System/Net/Http/Managed/ConnectionCloseReadStream.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace System.Net.Http
-{
- internal sealed partial class HttpConnection : IDisposable
- {
- private sealed class ConnectionCloseReadStream : HttpContentReadStream
- {
- public ConnectionCloseReadStream(HttpConnection connection)
- : base(connection)
- {
- }
-
- public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
- {
- ValidateBufferArgs(buffer, offset, count);
- return ReadAsync(new Memory<byte>(buffer, offset, count), cancellationToken).AsTask();
- }
-
- public override async ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken = default)
- {
- if (_connection == null || destination.Length == 0)
- {
- // Response body fully consumed or the caller didn't ask for any data
- return 0;
- }
-
- int bytesRead = await _connection.ReadAsync(destination, cancellationToken).ConfigureAwait(false);
- if (bytesRead == 0)
- {
- // We cannot reuse this connection, so close it.
- _connection.Dispose();
- _connection = null;
- return 0;
- }
-
- return bytesRead;
- }
-
- public override async Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
- {
- if (destination == null)
- {
- throw new ArgumentNullException(nameof(destination));
- }
-
- if (_connection == null)
- {
- // Response body fully consumed
- return;
- }
-
- await _connection.CopyToAsync(destination, cancellationToken).ConfigureAwait(false);
-
- // We cannot reuse this connection, so close it.
- _connection.Dispose();
- _connection = null;
- }
- }
- }
-}
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/ContentLengthReadStream.cs b/src/System.Net.Http/src/System/Net/Http/Managed/ContentLengthReadStream.cs
deleted file mode 100644
index d7b9f739bc..0000000000
--- a/src/System.Net.Http/src/System/Net/Http/Managed/ContentLengthReadStream.cs
+++ /dev/null
@@ -1,88 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace System.Net.Http
-{
- internal sealed partial class HttpConnection : IDisposable
- {
- private sealed class ContentLengthReadStream : HttpContentReadStream
- {
- private ulong _contentBytesRemaining;
-
- public ContentLengthReadStream(HttpConnection connection, ulong contentLength)
- : base(connection)
- {
- Debug.Assert(contentLength > 0, "Caller should have checked for 0.");
- _contentBytesRemaining = contentLength;
- }
-
- public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
- {
- ValidateBufferArgs(buffer, offset, count);
- return ReadAsync(new Memory<byte>(buffer, offset, count), cancellationToken).AsTask();
- }
-
- public override async ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken = default)
- {
- if (_connection == null || destination.Length == 0)
- {
- // Response body fully consumed or the caller didn't ask for any data
- return 0;
- }
-
- Debug.Assert(_contentBytesRemaining > 0);
-
- if ((ulong)destination.Length > _contentBytesRemaining)
- {
- destination = destination.Slice(0, (int)_contentBytesRemaining);
- }
-
- int bytesRead = await _connection.ReadAsync(destination, cancellationToken).ConfigureAwait(false);
-
- if (bytesRead <= 0)
- {
- // Unexpected end of response stream
- throw new IOException(SR.net_http_invalid_response);
- }
-
- Debug.Assert((ulong)bytesRead <= _contentBytesRemaining);
- _contentBytesRemaining -= (ulong)bytesRead;
-
- if (_contentBytesRemaining == 0)
- {
- // End of response body
- _connection.ReturnConnectionToPool();
- _connection = null;
- }
-
- return bytesRead;
- }
-
- public override async Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
- {
- if (destination == null)
- {
- throw new ArgumentNullException(nameof(destination));
- }
-
- if (_connection == null)
- {
- // Response body fully consumed
- return;
- }
-
- await _connection.CopyToAsync(destination, _contentBytesRemaining, cancellationToken).ConfigureAwait(false);
-
- _contentBytesRemaining = 0;
- _connection.ReturnConnectionToPool();
- _connection = null;
- }
- }
- }
-}
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/ContentLengthWriteStream.cs b/src/System.Net.Http/src/System/Net/Http/Managed/ContentLengthWriteStream.cs
deleted file mode 100644
index de00dd7468..0000000000
--- a/src/System.Net.Http/src/System/Net/Http/Managed/ContentLengthWriteStream.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace System.Net.Http
-{
- internal sealed partial class HttpConnection : IDisposable
- {
- private sealed class ContentLengthWriteStream : HttpContentWriteStream
- {
- public ContentLengthWriteStream(HttpConnection connection, CancellationToken cancellationToken) :
- base(connection, cancellationToken)
- {
- }
-
- public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken ignored)
- {
- ValidateBufferArgs(buffer, offset, count);
- return WriteAsync(new ReadOnlyMemory<byte>(buffer, offset, count), ignored);
- }
-
- public override Task WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken = default)
- {
- if (_connection._currentRequest == null)
- {
- // Avoid sending anything if the response has already completed, in which case there's no point
- // sending further data (this might happen, for example, on a redirect.)
- return Task.CompletedTask;
- }
-
- // Have the connection write the data, skipping the buffer. Importantly, this will
- // force a flush of anything already in the buffer, i.e. any remaining request headers
- // that are still buffered.
- return _connection.WriteWithoutBufferingAsync(source, RequestCancellationToken);
- }
-
- public override Task FlushAsync(CancellationToken ignored)
- {
- return _connection.FlushAsync(RequestCancellationToken);
- }
-
- public override Task FinishAsync()
- {
- _connection = null;
- return Task.CompletedTask;
- }
- }
- }
-}
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/CookieHandler.cs b/src/System.Net.Http/src/System/Net/Http/Managed/CookieHandler.cs
deleted file mode 100644
index 99277d0867..0000000000
--- a/src/System.Net.Http/src/System/Net/Http/Managed/CookieHandler.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace System.Net.Http
-{
- internal sealed class CookieHandler : HttpMessageHandler
- {
- private readonly HttpMessageHandler _innerHandler;
- private readonly CookieContainer _cookieContainer;
-
- public CookieHandler(CookieContainer cookieContainer, HttpMessageHandler innerHandler)
- {
- _innerHandler = innerHandler ?? throw new ArgumentNullException(nameof(innerHandler));
- _cookieContainer = cookieContainer ?? throw new ArgumentNullException(nameof(cookieContainer));
- }
-
- protected internal override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
- {
- // Add cookies to request, if any
- string cookieHeader = _cookieContainer.GetCookieHeader(request.RequestUri);
- if (!string.IsNullOrEmpty(cookieHeader))
- {
- request.Headers.Add(HttpKnownHeaderNames.Cookie, cookieHeader);
- }
-
- HttpResponseMessage response = await _innerHandler.SendAsync(request, cancellationToken).ConfigureAwait(false);
-
- // Handle Set-Cookie
- IEnumerable<string> setCookies;
- if (response.Headers.TryGetValues(HttpKnownHeaderNames.SetCookie, out setCookies))
- {
- foreach (string setCookie in setCookies)
- {
- _cookieContainer.SetCookies(response.RequestMessage.RequestUri, setCookie);
- }
- }
-
- return response;
- }
-
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- _innerHandler.Dispose();
- }
-
- base.Dispose(disposing);
- }
- }
-}
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnection.cs b/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnection.cs
deleted file mode 100644
index cc083ad605..0000000000
--- a/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnection.cs
+++ /dev/null
@@ -1,1198 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Globalization;
-using System.IO;
-using System.Net.Http.Headers;
-using System.Net.Security;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace System.Net.Http
-{
- internal sealed partial class HttpConnection : IDisposable
- {
- /// <summary>Default size of the read buffer used for the connection.</summary>
- private const int InitialReadBufferSize =
-#if DEBUG
- 10;
-#else
- 4096;
-#endif
- /// <summary>Default size of the write buffer used for the connection.</summary>
- private const int InitialWriteBufferSize = InitialReadBufferSize;
- /// <summary>
- /// Delay after which we'll send the request payload for ExpectContinue if
- /// the server hasn't yet responded.
- /// </summary>
- private const int Expect100TimeoutMilliseconds = 1000;
- /// <summary>
- /// Size after which we'll close the connection rather than send the payload in response
- /// to final error status code sent by the server when using Expect: 100-continue.
- /// </summary>
- private const int Expect100ErrorSendThreshold = 1024;
-
- private static readonly byte[] s_contentLength0NewlineAsciiBytes = Encoding.ASCII.GetBytes("Content-Length: 0\r\n");
- private static readonly byte[] s_spaceHttp10NewlineAsciiBytes = Encoding.ASCII.GetBytes(" HTTP/1.0\r\n");
- private static readonly byte[] s_spaceHttp11NewlineAsciiBytes = Encoding.ASCII.GetBytes(" HTTP/1.1\r\n");
- private static readonly byte[] s_hostKeyAndSeparator = Encoding.ASCII.GetBytes(HttpKnownHeaderNames.Host + ": ");
-
- private readonly HttpConnectionPool _pool;
- private readonly HttpConnectionKey _key;
- private readonly Stream _stream;
- private readonly TransportContext _transportContext;
- private readonly bool _usingProxy;
- private readonly byte[] _idnHostAsciiBytes;
-
- private HttpRequestMessage _currentRequest;
- private Task _sendRequestContentTask;
- private readonly byte[] _writeBuffer;
- private int _writeOffset;
- private Exception _pendingException;
-
- private Task<int> _readAheadTask;
- private byte[] _readBuffer;
- private int _readOffset;
- private int _readLength;
-
- private bool _connectionClose; // Connection: close was seen on last response
- private int _disposed; // 1 yes, 0 no
-
- public HttpConnection(
- HttpConnectionPool pool,
- HttpConnectionKey key,
- string requestIdnHost,
- Stream stream,
- TransportContext transportContext,
- bool usingProxy)
- {
- Debug.Assert(pool != null);
- Debug.Assert(stream != null);
-
- _pool = pool;
- _key = key;
- _stream = stream;
- _transportContext = transportContext;
- _usingProxy = usingProxy;
- if (requestIdnHost != null)
- {
- _idnHostAsciiBytes = Encoding.ASCII.GetBytes(requestIdnHost);
- }
-
- _writeBuffer = new byte[InitialWriteBufferSize];
- _readBuffer = new byte[InitialReadBufferSize];
-
- if (NetEventSource.IsEnabled)
- {
- if (_stream is SslStream sslStream)
- {
- Trace(
- $"Secure connection created to {key.Host}:{key.Port}. " +
- $"SslProtocol:{sslStream.SslProtocol}, " +
- $"CipherAlgorithm:{sslStream.CipherAlgorithm}, CipherStrength:{sslStream.CipherStrength}, " +
- $"HashAlgorithm:{sslStream.HashAlgorithm}, HashStrength:{sslStream.HashStrength}, " +
- $"KeyExchangeAlgorithm:{sslStream.KeyExchangeAlgorithm}, KeyExchangeStrength:{sslStream.KeyExchangeStrength}, " +
- $"LocalCert:{sslStream.LocalCertificate}, RemoteCert:{sslStream.RemoteCertificate}");
- }
- else
- {
- Trace($"Connection created to {key.Host}:{key.Port}.");
- }
- }
- }
-
- public void Dispose()
- {
- // Ensure we're only disposed once. Dispose could be called concurrently, for example,
- // if the request and the response were running concurrently and both incurred an exception.
- if (Interlocked.Exchange(ref _disposed, 1) == 0)
- {
- if (NetEventSource.IsEnabled) Trace("Connection closing.");
- _pool.DecrementConnectionCount();
- _stream.Dispose();
- }
- }
-
- public bool ReadAheadCompleted
- {
- get
- {
- Debug.Assert(_readAheadTask != null, $"{nameof(_readAheadTask)} should have been initialized");
- return _readAheadTask.IsCompleted;
- }
- }
-
- private async Task WriteHeadersAsync(HttpHeaders headers, CancellationToken cancellationToken)
- {
- foreach (KeyValuePair<string, IEnumerable<string>> header in headers)
- {
- await WriteAsciiStringAsync(header.Key, cancellationToken).ConfigureAwait(false);
- await WriteTwoBytesAsync((byte)':', (byte)' ', cancellationToken).ConfigureAwait(false);
-
- var values = (string[])header.Value; // typed as IEnumerable<string>, but always a string[]
- Debug.Assert(values.Length > 0, "No values for header??");
- if (values.Length > 0)
- {
- await WriteStringAsync(values[0], cancellationToken).ConfigureAwait(false);
- for (int i = 1; i < values.Length; i++)
- {
- await WriteTwoBytesAsync((byte)',', (byte)' ', cancellationToken).ConfigureAwait(false);
- await WriteStringAsync(values[i], cancellationToken).ConfigureAwait(false);
- }
- }
-
- await WriteTwoBytesAsync((byte)'\r', (byte)'\n', cancellationToken).ConfigureAwait(false);
- }
- }
-
- private async Task WriteHostHeaderAsync(Uri uri, CancellationToken cancellationToken)
- {
- await WriteBytesAsync(s_hostKeyAndSeparator, cancellationToken).ConfigureAwait(false);
-
- await (_idnHostAsciiBytes != null ?
- WriteBytesAsync(_idnHostAsciiBytes, cancellationToken) :
- WriteAsciiStringAsync(uri.IdnHost, cancellationToken)).ConfigureAwait(false);
-
- if (!uri.IsDefaultPort)
- {
- await WriteByteAsync((byte)':', cancellationToken).ConfigureAwait(false);
- await WriteFormattedInt32Async(uri.Port, cancellationToken).ConfigureAwait(false);
- }
-
- await WriteTwoBytesAsync((byte)'\r', (byte)'\n', cancellationToken).ConfigureAwait(false);
- }
-
- private Task WriteFormattedInt32Async(int value, CancellationToken cancellationToken)
- {
- const int MaxFormattedInt32Length = 10; // number of digits in int.MaxValue.ToString()
-
- // If the maximum possible number of digits fits in our buffer, we can format synchronously
- if (_writeOffset <= _writeBuffer.Length - MaxFormattedInt32Length)
- {
- if (value == 0)
- {
- _writeBuffer[_writeOffset++] = (byte)'0';
- }
- else
- {
- int initialOffset = _writeOffset;
- while (value > 0)
- {
- value = Math.DivRem(value, 10, out int digit);
- _writeBuffer[_writeOffset++] = (byte)('0' + digit);
- }
- Array.Reverse(_writeBuffer, initialOffset, _writeOffset - initialOffset);
- }
- return Task.CompletedTask;
- }
-
- // Otherwise, do it the slower way.
- return WriteAsciiStringAsync(value.ToString(CultureInfo.InvariantCulture), cancellationToken);
- }
-
- public async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
- {
- TaskCompletionSource<bool> allowExpect100ToContinue = null;
- Debug.Assert(_currentRequest == null, $"Expected null {nameof(_currentRequest)}.");
- _currentRequest = request;
- try
- {
- bool isHttp10 = request.Version.Major == 1 && request.Version.Minor == 0;
-
- // Send the request.
- if (NetEventSource.IsEnabled) Trace($"Sending request: {request}");
-
- // Add headers to define content transfer, if not present
- if (request.Content != null &&
- (!request.HasHeaders || request.Headers.TransferEncodingChunked != true) &&
- request.Content.Headers.ContentLength == null)
- {
- // We have content, but neither Transfer-Encoding or Content-Length is set.
- request.Headers.TransferEncodingChunked = true;
- }
-
- if (isHttp10 && request.HasHeaders && request.Headers.TransferEncodingChunked == true)
- {
- // HTTP 1.0 does not support chunking
- throw new NotSupportedException(SR.net_http_unsupported_chunking);
- }
-
- // Write request line
- await WriteStringAsync(request.Method.Method, cancellationToken).ConfigureAwait(false);
- await WriteByteAsync((byte)' ', cancellationToken).ConfigureAwait(false);
- await WriteStringAsync(
- _usingProxy ? request.RequestUri.AbsoluteUri : request.RequestUri.PathAndQuery,
- cancellationToken).ConfigureAwait(false);
-
- // fall-back to 1.1 for all versions other than 1.0
- await WriteBytesAsync(isHttp10 ? s_spaceHttp10NewlineAsciiBytes : s_spaceHttp11NewlineAsciiBytes,
- cancellationToken).ConfigureAwait(false);
-
- // Write request headers
- if (request.HasHeaders)
- {
- await WriteHeadersAsync(request.Headers, cancellationToken).ConfigureAwait(false);
- }
-
- if (request.Content == null)
- {
- // Write out Content-Length: 0 header to indicate no body,
- // unless this is a method that never has a body.
- if (request.Method != HttpMethod.Get && request.Method != HttpMethod.Head)
- {
- await WriteBytesAsync(s_contentLength0NewlineAsciiBytes, cancellationToken).ConfigureAwait(false);
- }
- }
- else
- {
- // Write content headers
- await WriteHeadersAsync(request.Content.Headers, cancellationToken).ConfigureAwait(false);
- }
-
- // Write special additional headers. If a host isn't in the headers list, then a Host header
- // wasn't sent, so as it's required by HTTP 1.1 spec, send one based on the Request Uri.
- if (!request.HasHeaders || request.Headers.Host == null)
- {
- await WriteHostHeaderAsync(request.RequestUri, cancellationToken).ConfigureAwait(false);
- }
-
- // CRLF for end of headers.
- await WriteTwoBytesAsync((byte)'\r', (byte)'\n', cancellationToken).ConfigureAwait(false);
-
- Debug.Assert(_sendRequestContentTask == null);
- if (request.Content == null)
- {
- // We have nothing more to send, so flush out any headers we haven't yet sent.
- await FlushAsync(cancellationToken).ConfigureAwait(false);
- }
- else
- {
- // Asynchronously send the body if there is one. This can run concurrently with receiving
- // the response. The write content streams will handle ensuring appropriate flushes are done
- // to ensure the headers and content are sent.
- bool transferEncodingChunked = request.HasHeaders && request.Headers.TransferEncodingChunked == true;
- HttpContentWriteStream stream = transferEncodingChunked ? (HttpContentWriteStream)
- new ChunkedEncodingWriteStream(this, cancellationToken) :
- new ContentLengthWriteStream(this, cancellationToken);
-
- if (!request.HasHeaders || request.Headers.ExpectContinue != true)
- {
- // Start the copy from the request. We do this here in case it synchronously throws
- // an exception, e.g. StreamContent throwing for non-rewindable content, and because if
- // we did it in SendRequestContentAsync, that exception would get trapped in the returned
- // task... at that point, we might get stuck waiting to receive a response from the server
- // that'll never come, as the server is still expecting us to send data.
- _sendRequestContentTask = SendRequestContentAsync(request.Content.CopyToAsync(stream, _transportContext), stream);
- }
- else
- {
- // We're sending an Expect: 100-continue header. We need to flush headers so that the server receives
- // all of them, and we need to do so before initiating the send, as once we do that, it effectively
- // owns the right to write, and we don't want to concurrently be accessing the write buffer.
- await FlushAsync(cancellationToken).ConfigureAwait(false);
-
- // Create a TCS we'll use to block the request content from being sent, and create a timer that's used
- // as a fail-safe to unblock the request content if we don't hear back from the server in a timely manner.
- // Then kick off the request. The TCS' result indicates whether content should be sent or not.
- allowExpect100ToContinue = new TaskCompletionSource<bool>();
- var expect100Timer = new Timer(
- s => ((TaskCompletionSource<bool>)s).TrySetResult(true),
- allowExpect100ToContinue, TimeSpan.FromMilliseconds(Expect100TimeoutMilliseconds), Timeout.InfiniteTimeSpan);
- _sendRequestContentTask = SendRequestContentWithExpect100ContinueAsync(request, allowExpect100ToContinue.Task, stream, expect100Timer);
- }
- }
-
- // Parse the response status line.
- var response = new HttpResponseMessage() { RequestMessage = request, Content = new HttpConnectionContent(CancellationToken.None) };
- ParseStatusLine(await ReadNextLineAsync(cancellationToken).ConfigureAwait(false), response);
-
- // If we sent an Expect: 100-continue header, handle the response accordingly.
- if (allowExpect100ToContinue != null)
- {
- if ((int)response.StatusCode >= 300 &&
- (request.Content.Headers.ContentLength == null || request.Content.Headers.ContentLength.GetValueOrDefault() > Expect100ErrorSendThreshold))
- {
- // For error final status codes, try to avoid sending the payload if its size is unknown or if it's known to be "big".
- // If we already sent a header detailing the size of the payload, if we then don't send that payload, the server may wait
- // for it and assume that the next request on the connection is actually this request's payload. Thus we mark the connection
- // to be closed. However, we may have also lost a race condition with the Expect: 100-continue timeout, so if it turns out
- // we've already started sending the payload (we weren't able to cancel it), then we don't need to force close the connection.
- allowExpect100ToContinue.TrySetResult(false);
- if (!allowExpect100ToContinue.Task.Result) // if Result is true, the timeout already expired and we started sending content
- {
- _connectionClose = true;
- }
- }
- else
- {
- // For any success or informational status codes (including 100 continue), send the payload.
- allowExpect100ToContinue.TrySetResult(true);
-
- // And if this was 100 continue, deal with the extra headers.
- if (response.StatusCode == HttpStatusCode.Continue)
- {
- // We got our continue header. Read the subsequent \r\n and parse the additional status line.
- if (!LineIsEmpty(await ReadNextLineAsync(cancellationToken).ConfigureAwait(false)))
- {
- ThrowInvalidHttpResponse();
- }
-
- ParseStatusLine(await ReadNextLineAsync(cancellationToken).ConfigureAwait(false), response);
- }
- }
- }
-
- // Parse the response headers.
- while (true)
- {
- ArraySegment<byte> line = await ReadNextLineAsync(cancellationToken).ConfigureAwait(false);
- if (LineIsEmpty(line))
- {
- break;
- }
- ParseHeaderNameValue(line, response);
- }
-
- // Determine whether we need to force close the connection when the request/response has completed.
- if (response.Headers.ConnectionClose.GetValueOrDefault())
- {
- _connectionClose = true;
- }
-
- // Before creating the response stream, check to see if we're done sending any content,
- // and propagate any exceptions that may have occurred. The most common case is that
- // the server won't send back response content until it's received the whole request,
- // so the majority of the time this task will be complete.
- Task sendRequestContentTask = _sendRequestContentTask;
- if (sendRequestContentTask != null && sendRequestContentTask.IsCompleted)
- {
- sendRequestContentTask.GetAwaiter().GetResult();
- _sendRequestContentTask = null;
- }
-
- // Create the response stream.
- HttpContentReadStream responseStream;
- if (request.Method == HttpMethod.Head || (int)response.StatusCode == 204 || (int)response.StatusCode == 304)
- {
- responseStream = EmptyReadStream.Instance;
- ReturnConnectionToPool();
- }
- else if (response.Content.Headers.ContentLength != null)
- {
- long contentLength = response.Content.Headers.ContentLength.GetValueOrDefault();
- if (contentLength <= 0)
- {
- responseStream = EmptyReadStream.Instance;
- ReturnConnectionToPool();
- }
- else
- {
- responseStream = new ContentLengthReadStream(this, (ulong)contentLength);
- }
- }
- else if (response.Headers.TransferEncodingChunked == true)
- {
- responseStream = new ChunkedEncodingReadStream(this);
- }
- else
- {
- responseStream = new ConnectionCloseReadStream(this);
- }
- ((HttpConnectionContent)response.Content).SetStream(responseStream);
-
- if (NetEventSource.IsEnabled) Trace($"Received response: {response}");
- return response;
- }
- catch (Exception error)
- {
- // Make sure to complete the allowExpect100ToContinue task if it exists.
- allowExpect100ToContinue?.TrySetResult(false);
-
- if (NetEventSource.IsEnabled) Trace($"Error sending request: {error}");
- Dispose();
-
- if (_pendingException != null)
- {
- // If we incurred an exception in non-linear control flow such that
- // the exception didn't bubble up here (e.g. concurrent sending of
- // the request content), use that error instead.
- throw new HttpRequestException(SR.net_http_client_execution_error, _pendingException);
- }
-
- // Otherwise, propagate this exception, wrapping it if necessary to
- // match exception type expectations.
- if (error is InvalidOperationException || error is IOException)
- {
- throw new HttpRequestException(SR.net_http_client_execution_error, error);
- }
- throw;
- }
- }
-
- private static bool LineIsEmpty(ArraySegment<byte> line)
- {
- Debug.Assert(line.Count >= 2, "Lines should always be \r\n terminated.");
- return line.Count == 2;
- }
-
- private async Task SendRequestContentAsync(Task copyTask, HttpContentWriteStream stream)
- {
- try
- {
- // Wait for all of the data to be copied to the server.
- await copyTask.ConfigureAwait(false);
-
- // Finish the content; with a chunked upload, this includes writing the terminating chunk.
- await stream.FinishAsync().ConfigureAwait(false);
-
- // Flush any content that might still be buffered.
- await FlushAsync(stream.RequestCancellationToken).ConfigureAwait(false);
- }
- catch (Exception e)
- {
- _pendingException = e;
- if (NetEventSource.IsEnabled) Trace($"Error while sending request content: {e}");
- Dispose();
- throw;
- }
- }
-
- private async Task SendRequestContentWithExpect100ContinueAsync(
- HttpRequestMessage request, Task<bool> allowExpect100ToContinueTask, HttpContentWriteStream stream, Timer expect100Timer)
- {
- // Wait until we receive a trigger notification that it's ok to continue sending content.
- // This will come either when the timer fires or when we receive a response status line from the server.
- bool sendRequestContent = await allowExpect100ToContinueTask.ConfigureAwait(false);
-
- // Clean up the timer; it's no longer needed.
- expect100Timer.Dispose();
-
- // Send the content if we're supposed to. Otherwise, we're done.
- if (sendRequestContent)
- {
- if (NetEventSource.IsEnabled) Trace($"Sending request content for Expect: 100-continue.");
- await SendRequestContentAsync(request.Content.CopyToAsync(stream, _transportContext), stream).ConfigureAwait(false);
- }
- else
- {
- if (NetEventSource.IsEnabled) Trace($"Canceling request content for Expect: 100-continue.");
- }
- }
-
- // TODO: Remove this overload once https://github.com/dotnet/roslyn/issues/17287 is addressed
- // and the compiler doesn't lift the span temporary from the call site into the async state
- // machine in debug builds.
- private void ParseStatusLine(ArraySegment<byte> line, HttpResponseMessage response) =>
- ParseStatusLine((Span<byte>)line, response);
-
- private void ParseStatusLine(Span<byte> line, HttpResponseMessage response)
- {
- if (line.Length < 14 || // "HTTP/1.1 123\r\n" with optional phrase before the crlf
- line[0] != 'H' ||
- line[1] != 'T' ||
- line[2] != 'T' ||
- line[3] != 'P' ||
- line[4] != '/' ||
- line[8] != ' ')
- {
- ThrowInvalidHttpResponse();
- }
-
- // Set the response HttpVersion and status code
- byte majorVersion = line[5], minorVersion = line[7];
- byte status1 = line[9], status2 = line[10], status3 = line[11];
- if (!IsDigit(majorVersion) || line[6] != (byte)'.' || !IsDigit(minorVersion) ||
- !IsDigit(status1) || !IsDigit(status2) || !IsDigit(status3))
- {
- ThrowInvalidHttpResponse();
- }
- response.Version =
- (majorVersion == '1' && minorVersion == '1') ? HttpVersionInternal.Version11 :
- (majorVersion == '1' && minorVersion == '0') ? HttpVersionInternal.Version10 :
- (majorVersion == '2' && minorVersion == '0') ? HttpVersionInternal.Version20 :
- HttpVersionInternal.Unknown;
- response.StatusCode =
- (HttpStatusCode)(100 * (status1 - '0') + 10 * (status2 - '0') + (status3 - '0'));
-
- // Parse (optional) reason phrase
- byte c = line[12];
- if (c == '\r')
- {
- response.ReasonPhrase = string.Empty;
- }
- else if (c != ' ')
- {
- ThrowInvalidHttpResponse();
- }
- else
- {
- Span<byte> reasonBytes = line.Slice(13, line.Length - 13 - 2); // 2 == \r\n ending trimmed off
- string knownReasonPhrase = HttpStatusDescription.Get(response.StatusCode);
- if (knownReasonPhrase != null && EqualsOrdinal(knownReasonPhrase, reasonBytes))
- {
- response.ReasonPhrase = knownReasonPhrase;
- }
- else
- {
- unsafe
- {
- try
- {
- fixed (byte* reasonPtr = &MemoryMarshal.GetReference(reasonBytes))
- {
- response.ReasonPhrase = Encoding.ASCII.GetString(reasonPtr, reasonBytes.Length);
- }
- }
- catch (FormatException e)
- {
- ThrowInvalidHttpResponse(e);
- }
- }
- }
- }
- }
-
- // TODO: Remove this overload once https://github.com/dotnet/roslyn/issues/17287 is addressed
- // and the compiler doesn't lift the span temporary from the call site into the async state
- // machine in debug builds.
- private void ParseHeaderNameValue(ArraySegment<byte> line, HttpResponseMessage response) =>
- ParseHeaderNameValue((Span<byte>)line, response);
-
- private void ParseHeaderNameValue(Span<byte> line, HttpResponseMessage response)
- {
- int pos = 0;
- while (line[pos] != (byte)':' && line[pos] != (byte)' ')
- {
- pos++;
- if (pos == line.Length)
- {
- // Ignore invalid header line that doesn't contain ':'.
- return;
- }
- }
-
- if (pos == 0)
- {
- // Ignore invalid empty header name.
- return;
- }
-
- // CONSIDER: trailing whitespace?
-
- if (!HeaderDescriptor.TryGet(line.Slice(0, pos), out HeaderDescriptor descriptor))
- {
- // Ignore invalid header name
- return;
- }
-
- // Eat any trailing whitespace
- while (line[pos] == (byte)' ')
- {
- pos++;
- if (pos == line.Length)
- {
- // Ignore invalid header line that doesn't contain ':'.
- return;
- }
- }
-
- if (line[pos++] != ':')
- {
- // Ignore invalid header line that doesn't contain ':'.
- return;
- }
-
- // Skip whitespace after colon
- while (pos < line.Length && (line[pos] == (byte)' ' || line[pos] == '\t'))
- {
- pos++;
- }
-
- string headerValue = descriptor.GetHeaderValue(line.Slice(pos, line.Length - pos - 2)); // trim trailing \r\n
-
- // Note we ignore the return value from TryAddWithoutValidation;
- // if the header can't be added, we silently drop it.
- if (descriptor.HeaderType == HttpHeaderType.Content)
- {
- response.Content.Headers.TryAddWithoutValidation(descriptor, headerValue);
- }
- else
- {
- response.Headers.TryAddWithoutValidation(descriptor, headerValue);
- }
- }
-
- private static bool IsDigit(byte c) => (uint)(c - '0') <= '9' - '0';
-
- private void WriteToBuffer(ReadOnlyMemory<byte> source)
- {
- Debug.Assert(source.Length <= _writeBuffer.Length - _writeOffset);
- source.Span.CopyTo(new Span<byte>(_writeBuffer, _writeOffset, source.Length));
- _writeOffset += source.Length;
- }
-
- private async Task WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken)
- {
- int remaining = _writeBuffer.Length - _writeOffset;
-
- if (source.Length <= remaining)
- {
- // Fits in current write buffer. Just copy and return.
- WriteToBuffer(source);
- return;
- }
-
- if (_writeOffset != 0)
- {
- // Fit what we can in the current write buffer and flush it.
- WriteToBuffer(source.Slice(0, remaining));
- source = source.Slice(remaining);
- await FlushAsync(cancellationToken).ConfigureAwait(false);
- }
-
- if (source.Length >= _writeBuffer.Length)
- {
- // Large write. No sense buffering this. Write directly to stream.
- // CONSIDER: May want to be a bit smarter here? Think about how large writes should work...
- await WriteToStreamAsync(source, cancellationToken).ConfigureAwait(false);
- }
- else
- {
- // Copy remainder into buffer
- WriteToBuffer(source);
- }
- }
-
- private Task WriteWithoutBufferingAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken)
- {
- if (_writeOffset == 0)
- {
- // There's nothing in the write buffer we need to flush.
- // Just write the supplied data out to the stream.
- return WriteToStreamAsync(source, cancellationToken);
- }
-
- int remaining = _writeBuffer.Length - _writeOffset;
- if (source.Length <= remaining)
- {
- // There's something already in the write buffer, but the content
- // we're writing can also fit after it in the write buffer. Copy
- // the content to the write buffer and then flush it, so that we
- // can do a single send rather than two.
- WriteToBuffer(source);
- return FlushAsync(cancellationToken);
- }
-
- // There's data in the write buffer and the data we're writing doesn't fit after it.
- // Do two writes, one to flush the buffer and then another to write the supplied content.
- return FlushThenWriteWithoutBufferingAsync(source, cancellationToken);
- }
-
- private async Task FlushThenWriteWithoutBufferingAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken)
- {
- await FlushAsync(cancellationToken).ConfigureAwait(false);
- await WriteToStreamAsync(source, cancellationToken).ConfigureAwait(false);
- }
-
- private Task WriteByteAsync(byte b, CancellationToken cancellationToken)
- {
- if (_writeOffset < _writeBuffer.Length)
- {
- _writeBuffer[_writeOffset++] = b;
- return Task.CompletedTask;
- }
- return WriteByteSlowAsync(b, cancellationToken);
- }
-
- private async Task WriteByteSlowAsync(byte b, CancellationToken cancellationToken)
- {
- Debug.Assert(_writeOffset == _writeBuffer.Length);
- await WriteToStreamAsync(_writeBuffer, cancellationToken).ConfigureAwait(false);
-
- _writeBuffer[0] = b;
- _writeOffset = 1;
- }
-
- private Task WriteTwoBytesAsync(byte b1, byte b2, CancellationToken cancellationToken)
- {
- if (_writeOffset <= _writeBuffer.Length - 2)
- {
- byte[] buffer = _writeBuffer;
- buffer[_writeOffset++] = b1;
- buffer[_writeOffset++] = b2;
- return Task.CompletedTask;
- }
- return WriteTwoBytesSlowAsync(b1, b2, cancellationToken);
- }
-
- private async Task WriteTwoBytesSlowAsync(byte b1, byte b2, CancellationToken cancellationToken)
- {
- await WriteByteAsync(b1, cancellationToken).ConfigureAwait(false);
- await WriteByteAsync(b2, cancellationToken).ConfigureAwait(false);
- }
-
- private Task WriteBytesAsync(byte[] bytes, CancellationToken cancellationToken)
- {
- if (_writeOffset <= _writeBuffer.Length - bytes.Length)
- {
- Buffer.BlockCopy(bytes, 0, _writeBuffer, _writeOffset, bytes.Length);
- _writeOffset += bytes.Length;
- return Task.CompletedTask;
- }
- return WriteBytesSlowAsync(bytes, cancellationToken);
- }
-
- private async Task WriteBytesSlowAsync(byte[] bytes, CancellationToken cancellationToken)
- {
- int offset = 0;
- while (true)
- {
- int remaining = bytes.Length - offset;
- int toCopy = Math.Min(remaining, _writeBuffer.Length - _writeOffset);
- Buffer.BlockCopy(bytes, offset, _writeBuffer, _writeOffset, toCopy);
- _writeOffset += toCopy;
- offset += toCopy;
-
- Debug.Assert(offset <= bytes.Length, $"Expected {nameof(offset)} to be <= {bytes.Length}, got {offset}");
- Debug.Assert(_writeOffset <= _writeBuffer.Length, $"Expected {nameof(_writeOffset)} to be <= {_writeBuffer.Length}, got {_writeOffset}");
- if (offset == bytes.Length)
- {
- break;
- }
- else if (_writeOffset == _writeBuffer.Length)
- {
- await WriteToStreamAsync(_writeBuffer, cancellationToken).ConfigureAwait(false);
- _writeOffset = 0;
- }
- }
- }
-
- private Task WriteStringAsync(string s, CancellationToken cancellationToken)
- {
- // If there's enough space in the buffer to just copy all of the string's bytes, do so.
- // Unlike WriteAsciiStringAsync, validate each char along the way.
- int offset = _writeOffset;
- if (s.Length <= _writeBuffer.Length - offset)
- {
- byte[] writeBuffer = _writeBuffer;
- foreach (char c in s)
- {
- if ((c & 0xFF80) != 0)
- {
- throw new HttpRequestException(SR.net_http_request_invalid_char_encoding);
- }
- writeBuffer[offset++] = (byte)c;
- }
- _writeOffset = offset;
- return Task.CompletedTask;
- }
-
- // Otherwise, fall back to doing a normal slow string write; we could optimize away
- // the extra checks later, but the case where we cross a buffer boundary should be rare.
- return WriteStringAsyncSlow(s, cancellationToken);
- }
-
- private Task WriteAsciiStringAsync(string s, CancellationToken cancellationToken)
- {
- // If there's enough space in the buffer to just copy all of the string's bytes, do so.
- int offset = _writeOffset;
- if (s.Length <= _writeBuffer.Length - offset)
- {
- byte[] writeBuffer = _writeBuffer;
- foreach (char c in s)
- {
- writeBuffer[offset++] = (byte)c;
- }
- _writeOffset = offset;
- return Task.CompletedTask;
- }
-
- // Otherwise, fall back to doing a normal slow string write; we could optimize away
- // the extra checks later, but the case where we cross a buffer boundary should be rare.
- return WriteStringAsyncSlow(s, cancellationToken);
- }
-
- private async Task WriteStringAsyncSlow(string s, CancellationToken cancellationToken)
- {
- for (int i = 0; i < s.Length; i++)
- {
- char c = s[i];
- if ((c & 0xFF80) != 0)
- {
- throw new HttpRequestException(SR.net_http_request_invalid_char_encoding);
- }
- await WriteByteAsync((byte)c, cancellationToken).ConfigureAwait(false);
- }
- }
-
- private Task FlushAsync(CancellationToken cancellationToken)
- {
- if (_writeOffset > 0)
- {
- Task t = WriteToStreamAsync(new ReadOnlyMemory<byte>(_writeBuffer, 0, _writeOffset), cancellationToken);
- _writeOffset = 0;
- return t;
- }
- return Task.CompletedTask;
- }
-
- private Task WriteToStreamAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken)
- {
- if (NetEventSource.IsEnabled) Trace($"Writing {source.Length} bytes.");
- return _stream.WriteAsync(source, cancellationToken);
- }
-
- private async ValueTask<ArraySegment<byte>> ReadNextLineAsync(CancellationToken cancellationToken)
- {
- int searchOffset = 0;
- while (true)
- {
- int startIndex = _readOffset + searchOffset;
- int length = _readLength - startIndex;
- int crPos = Array.IndexOf(_readBuffer, (byte)'\r', startIndex, length);
- if (crPos < 0)
- {
- // Couldn't find a \r. Read more.
- searchOffset = length;
- await FillAsync(cancellationToken).ConfigureAwait(false);
- }
- else if (crPos + 1 >= _readLength)
- {
- // We found a \r, but we don't have enough data buffered to read the \n.
- searchOffset = length - 1;
- await FillAsync(cancellationToken).ConfigureAwait(false);
- }
- else if (_readBuffer[crPos + 1] == '\n')
- {
- // We found a \r\n. Return the data up to and including it.
- int lineLength = crPos - _readOffset + 2;
- var result = new ArraySegment<byte>(_readBuffer, _readOffset, lineLength);
- _readOffset += lineLength;
- return result;
- }
- else
- {
- ThrowInvalidHttpResponse();
- }
- }
- }
-
- private async Task ReadCrLfAsync(CancellationToken cancellationToken)
- {
- while (_readLength - _readOffset < 2)
- {
- // We have fewer than 2 chars buffered. Get more.
- await FillAsync(cancellationToken).ConfigureAwait(false);
- }
-
- // We expect \r\n. If so, consume them. If not, it's an error.
- if (_readBuffer[_readOffset] != '\r' || _readBuffer[_readOffset + 1] != '\n')
- {
- ThrowInvalidHttpResponse();
- }
-
- _readOffset += 2;
- }
-
- // Throws IOException on EOF. This is only called when we expect more data.
- private async Task FillAsync(CancellationToken cancellationToken)
- {
- int remaining = _readLength - _readOffset;
- Debug.Assert(remaining >= 0);
-
- if (remaining == 0)
- {
- // No data in the buffer. Simply reset the offset and length to 0 to allow
- // the whole buffer to be filled.
- _readOffset = _readLength = 0;
- }
- else if (_readOffset > 0)
- {
- // There's some data in the buffer but it's not at the beginning. Shift it
- // down to make room for more.
- Buffer.BlockCopy(_readBuffer, _readOffset, _readBuffer, 0, remaining);
- _readOffset = 0;
- _readLength = remaining;
- }
- else if (remaining == _readBuffer.Length)
- {
- // The whole buffer is full, but the caller is still requesting more data,
- // so increase the size of the buffer.
- Debug.Assert(_readOffset == 0);
- Debug.Assert(_readLength == _readBuffer.Length);
-
- byte[] newReadBuffer = new byte[_readBuffer.Length * 2];
- Buffer.BlockCopy(_readBuffer, 0, newReadBuffer, 0, remaining);
- _readBuffer = newReadBuffer;
- _readOffset = 0;
- _readLength = remaining;
- }
-
- // When the connection was put back into the pool, a pre-emptive read was performed
- // into the read buffer. That read should not complete prior to us using the
- // connection again, as that would mean the connection was either closed or had
- // erroneous data sent on it by the server in response to no request from us.
- // We need to consume that read prior to issuing another read request.
- Task<int> t = _readAheadTask;
- int bytesRead;
- if (t != null)
- {
- Debug.Assert(_readOffset == 0);
- Debug.Assert(_readLength == 0);
- _readAheadTask = null;
- bytesRead = await t.ConfigureAwait(false);
- }
- else
- {
- ValueTask<int> vt = _stream.ReadAsync(new Memory<byte>(_readBuffer, _readLength, _readBuffer.Length - _readLength), cancellationToken);
- bytesRead = vt.IsCompletedSuccessfully ? vt.Result : await vt.AsTask().ConfigureAwait(false);
- }
-
- if (NetEventSource.IsEnabled) Trace($"Received {bytesRead} bytes.");
- if (bytesRead == 0)
- {
- throw new IOException(SR.net_http_invalid_response);
- }
- _readLength += bytesRead;
- }
-
- private void ReadFromBuffer(Span<byte> buffer)
- {
- Debug.Assert(buffer.Length <= _readLength - _readOffset);
-
- new Span<byte>(_readBuffer, _readOffset, buffer.Length).CopyTo(buffer);
- _readOffset += buffer.Length;
- }
-
- private async ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken)
- {
- // This is called when reading the response body
-
- int remaining = _readLength - _readOffset;
- if (remaining > 0)
- {
- // We have data in the read buffer. Return it to the caller.
- if (destination.Length <= remaining)
- {
- ReadFromBuffer(destination.Span);
- return destination.Length;
- }
- else
- {
- ReadFromBuffer(destination.Span.Slice(0, remaining));
- return remaining;
- }
- }
-
- // No data in read buffer.
- // Do an unbuffered read directly against the underlying stream.
- Debug.Assert(_readAheadTask == null, "Read ahead task should have been consumed as part of the headers.");
- int count = await _stream.ReadAsync(destination, cancellationToken).ConfigureAwait(false);
- if (NetEventSource.IsEnabled) Trace($"Received {count} bytes.");
- return count;
- }
-
- private async Task CopyFromBufferAsync(Stream destination, int count, CancellationToken cancellationToken)
- {
- Debug.Assert(count <= _readLength - _readOffset);
-
- if (NetEventSource.IsEnabled) Trace($"Copying {count} bytes to stream.");
- await destination.WriteAsync(_readBuffer, _readOffset, count, cancellationToken).ConfigureAwait(false);
- _readOffset += count;
- }
-
- private async Task CopyToAsync(Stream destination, CancellationToken cancellationToken)
- {
- Debug.Assert(destination != null);
-
- int remaining = _readLength - _readOffset;
- if (remaining > 0)
- {
- await CopyFromBufferAsync(destination, remaining, cancellationToken).ConfigureAwait(false);
- }
-
- while (true)
- {
- _readOffset = 0;
-
- // Don't use FillAsync here as it will throw on EOF.
- Debug.Assert(_readAheadTask == null);
- _readLength = await _stream.ReadAsync(_readBuffer, cancellationToken).ConfigureAwait(false);
- if (_readLength == 0)
- {
- // End of stream
- break;
- }
-
- await CopyFromBufferAsync(destination, _readLength, cancellationToken).ConfigureAwait(false);
- }
- }
-
- // Copy *exactly* [length] bytes into destination; throws on end of stream.
- private async Task CopyToAsync(Stream destination, ulong length, CancellationToken cancellationToken)
- {
- Debug.Assert(destination != null);
- Debug.Assert(length > 0);
-
- int remaining = _readLength - _readOffset;
- if (remaining > 0)
- {
- if ((ulong)remaining > length)
- {
- remaining = (int)length;
- }
- await CopyFromBufferAsync(destination, remaining, cancellationToken).ConfigureAwait(false);
-
- length -= (ulong)remaining;
- if (length == 0)
- {
- return;
- }
- }
-
- while (true)
- {
- await FillAsync(cancellationToken).ConfigureAwait(false);
-
- remaining = (ulong)_readLength < length ? _readLength : (int)length;
- await CopyFromBufferAsync(destination, remaining, cancellationToken).ConfigureAwait(false);
-
- length -= (ulong)remaining;
- if (length == 0)
- {
- return;
- }
- }
- }
-
- private void ReturnConnectionToPool()
- {
- Debug.Assert(_readAheadTask == null, "Expected a previous initial read to already be consumed.");
- Debug.Assert(_currentRequest != null, "Expected the connection to be associated with a request.");
-
- // Disassociate the connection from a request. If there's an in-flight request content still
- // being sent, it'll see this nulled out and stop sending. Also clear out other request-specific content.
- _currentRequest = null;
- _pendingException = null;
-
- // Check to see if we're still sending request content.
- Task sendRequestContentTask = _sendRequestContentTask;
- if (sendRequestContentTask != null)
- {
- if (!sendRequestContentTask.IsCompleted)
- {
- // We're still transferring request content. Only put the connection back into the
- // pool when we're done transferring.
- if (NetEventSource.IsEnabled) Trace("Still transferring request content. Delaying returning connection to pool.");
- sendRequestContentTask.ContinueWith((_, state) =>
- {
- var innerConnection = (HttpConnection)state;
- if (NetEventSource.IsEnabled) innerConnection.Trace("Request content send completed.");
- innerConnection.ReturnConnectionToPoolCore();
- }, this, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Default);
- return;
- }
-
- // We're done transferring request content. Check whether we incurred an exception,
- // and if we did, propagate it to our caller.
- if (!sendRequestContentTask.IsCompletedSuccessfully)
- {
- sendRequestContentTask.GetAwaiter().GetResult();
- }
- }
-
- ReturnConnectionToPoolCore();
- }
-
- private void ReturnConnectionToPoolCore()
- {
- Debug.Assert(_sendRequestContentTask == null || _sendRequestContentTask.IsCompleted);
- Debug.Assert(_writeOffset == 0, "Everything in write buffer should have been flushed.");
-
- if (NetEventSource.IsEnabled)
- {
- if (_connectionClose)
- {
- Trace("Server requested connection be closed.");
- }
- if (_sendRequestContentTask != null && _sendRequestContentTask.IsFaulted)
- {
- Trace($"Sending request content incurred an exception: {_sendRequestContentTask.Exception.InnerException}");
- }
- }
-
- // If server told us it's closing the connection, don't put this back in the pool.
- // And if we incurred an error while transferring request content, also skip the pool.
- if (!_connectionClose &&
- (_sendRequestContentTask == null || _sendRequestContentTask.IsCompletedSuccessfully))
- {
- try
- {
- // Null out the associated request before the connection is potentially reused by another.
- _currentRequest = null;
- _sendRequestContentTask = null;
-
- // When putting a connection back into the pool, we initiate a pre-emptive
- // read on the stream. When the connection is subsequently taken out of the
- // pool, this can be used in place of the first read on the stream that would
- // otherwise be done. But by doing it now, we can check the status of the read
- // at any point to understand if the connection has been closed or if errant data
- // has been sent on the connection by the server, either of which would mean we
- // should close the connection and not use it for subsequent requests.
- _readAheadTask = _stream.ReadAsync(_readBuffer, 0, _readBuffer.Length);
-
- // Put connection back in the pool.
- _pool.ReturnConnection(this);
- return;
- }
- catch
- {
- // If reading throws, eat the error and don't pool the connection.
- }
- }
-
- // We're not putting the connection back in the pool. Dispose it.
- Dispose();
- }
-
- private static bool EqualsOrdinal(string left, Span<byte> right)
- {
- Debug.Assert(left != null, "Expected non-null string");
-
- if (left.Length != right.Length)
- {
- return false;
- }
-
- for (int i = 0; i < left.Length; i++)
- {
- if (left[i] != right[i])
- {
- return false;
- }
- }
-
- return true;
- }
-
- public override string ToString() => $"{nameof(HttpConnection)}(Host:{_key.Host})"; // Description for diagnostic purposes
-
- private static void ThrowInvalidHttpResponse() => throw new HttpRequestException(SR.net_http_invalid_response);
-
- private static void ThrowInvalidHttpResponse(Exception innerException) => throw new HttpRequestException(SR.net_http_invalid_response, innerException);
-
- internal void Trace(string message, [CallerMemberName] string memberName = null) =>
- NetEventSource.Log.HandlerMessage(
- _pool?.GetHashCode() ?? 0, // pool ID
- GetHashCode(), // connection ID
- _currentRequest?.GetHashCode() ?? 0, // request ID
- memberName, // method name
- ToString() + ": " + message); // message
- }
-}
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionHandler.cs b/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionHandler.cs
deleted file mode 100644
index 7f926e7aa6..0000000000
--- a/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionHandler.cs
+++ /dev/null
@@ -1,154 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.IO;
-using System.Net.Security;
-using System.Security.Authentication;
-using System.Security.Cryptography.X509Certificates;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace System.Net.Http
-{
- internal sealed class HttpConnectionHandler : HttpMessageHandler
- {
- private readonly HttpConnectionSettings _settings;
- private readonly HttpConnectionPools _connectionPools;
-
- public HttpConnectionHandler(HttpConnectionSettings settings)
- {
- _settings = settings;
- _connectionPools = new HttpConnectionPools(settings._maxConnectionsPerServer);
- }
-
- protected internal override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
- {
- var key = new HttpConnectionKey(request.RequestUri);
-
- HttpConnectionPool pool = _connectionPools.GetOrAddPool(key);
- ValueTask<HttpConnection> connectionTask = pool.GetConnectionAsync(
- (state, ct) => state.handler.CreateConnection(state.request, state.key, state.pool, ct),
- (handler: this, request: request, key: key, pool: pool), cancellationToken);
-
- return connectionTask.IsCompletedSuccessfully ?
- connectionTask.Result.SendAsync(request, cancellationToken) :
- SendAsyncWithAwaitedConnection(connectionTask, request, cancellationToken);
- }
-
- private async Task<HttpResponseMessage> SendAsyncWithAwaitedConnection(
- ValueTask<HttpConnection> connectionTask, HttpRequestMessage request, CancellationToken cancellationToken)
- {
- HttpConnection connection = await connectionTask.ConfigureAwait(false);
- return await connection.SendAsync(request, cancellationToken).ConfigureAwait(false);
- }
-
- private async ValueTask<SslStream> EstablishSslConnection(string host, HttpRequestMessage request, Stream stream, CancellationToken cancellationToken)
- {
- RemoteCertificateValidationCallback callback = null;
- if (_settings._serverCertificateCustomValidationCallback != null)
- {
- callback = (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) =>
- {
- try
- {
- return _settings._serverCertificateCustomValidationCallback(request, certificate as X509Certificate2, chain, sslPolicyErrors);
- }
- catch (Exception e)
- {
- throw new HttpRequestException(SR.net_http_ssl_connection_failed, e);
- }
- };
- }
-
- var sslStream = new SslStream(stream);
-
- try
- {
- await sslStream.AuthenticateAsClientAsync(new SslClientAuthenticationOptions
- {
- TargetHost = host,
- ClientCertificates = _settings._clientCertificates,
- EnabledSslProtocols = _settings._sslProtocols,
- CertificateRevocationCheckMode = _settings._checkCertificateRevocationList ? X509RevocationMode.Online : X509RevocationMode.NoCheck,
- RemoteCertificateValidationCallback = callback
- }, cancellationToken).ConfigureAwait(false);
- }
- catch (Exception e)
- {
- sslStream.Dispose();
- if (e is AuthenticationException || e is IOException)
- {
- throw new HttpRequestException(SR.net_http_ssl_connection_failed, e);
- }
- throw;
- }
-
- return sslStream;
- }
-
- private async ValueTask<HttpConnection> CreateConnection(
- HttpRequestMessage request, HttpConnectionKey key, HttpConnectionPool pool, CancellationToken cancellationToken)
- {
- Uri uri = request.RequestUri;
-
- Stream stream = await ConnectHelper.ConnectAsync(uri.IdnHost, uri.Port, cancellationToken).ConfigureAwait(false);
-
- TransportContext transportContext = null;
-
- if (uri.Scheme == UriScheme.Https)
- {
- // Get the appropriate host name to use for the SSL connection, allowing a host header to override.
- string host = request.Headers.Host;
- if (host == null)
- {
- // No host header, use the host from the Uri.
- host = uri.IdnHost;
- }
- else
- {
- // There is a host header. Use it, but first see if we need to trim off a port.
- int colonPos = host.IndexOf(':');
- if (colonPos >= 0)
- {
- // There is colon, which could either be a port separator or a separator in
- // an IPv6 address. See if this is an IPv6 address; if it's not, use everything
- // before the colon as the host name, and if it is, use everything before the last
- // colon iff the last colon is after the end of the IPv6 address (otherwise it's a
- // part of the address).
- int ipV6AddressEnd = host.IndexOf(']');
- if (ipV6AddressEnd == -1)
- {
- host = host.Substring(0, colonPos);
- }
- else
- {
- colonPos = host.LastIndexOf(':');
- if (colonPos > ipV6AddressEnd)
- {
- host = host.Substring(0, colonPos);
- }
- }
- }
- }
-
- // Establish the connection using the parsed host name.
- SslStream sslStream = await EstablishSslConnection(host, request, stream, cancellationToken).ConfigureAwait(false);
- stream = sslStream;
- transportContext = sslStream.TransportContext;
- }
-
- return new HttpConnection(pool, key, uri.IdnHost, stream, transportContext, false);
- }
-
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- _connectionPools.Dispose();
- }
-
- base.Dispose(disposing);
- }
- }
-}
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionKey.cs b/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionKey.cs
deleted file mode 100644
index 7633841c07..0000000000
--- a/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionKey.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-namespace System.Net.Http
-{
- internal readonly struct HttpConnectionKey : IEquatable<HttpConnectionKey>
- {
- public readonly bool UsingSSL;
- public readonly string Host;
- public readonly int Port;
-
- public HttpConnectionKey(Uri uri)
- {
- UsingSSL =
- uri.Scheme == UriScheme.Http ? false :
- uri.Scheme == UriScheme.Https ? true :
- throw new ArgumentException(SR.net_http_client_http_baseaddress_required, nameof(uri));
-
- Host = uri.Host;
- Port = uri.Port;
- }
-
- public override int GetHashCode() =>
- UsingSSL.GetHashCode() << 16 ^ Host.GetHashCode() ^ Port.GetHashCode();
-
- public override bool Equals(object obj) =>
- obj != null &&
- obj is HttpConnectionKey &&
- Equals((HttpConnectionKey)obj);
-
- public bool Equals(HttpConnectionKey other) =>
- UsingSSL == other.UsingSSL &&
- Host == other.Host &&
- Port == other.Port;
-
- public static bool operator ==(HttpConnectionKey key1, HttpConnectionKey key2) => key1.Equals(key2);
- public static bool operator !=(HttpConnectionKey key1, HttpConnectionKey key2) => !key1.Equals(key2);
- }
-}
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionPools.cs b/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionPools.cs
deleted file mode 100644
index d1d043b543..0000000000
--- a/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionPools.cs
+++ /dev/null
@@ -1,138 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Threading;
-
-namespace System.Net.Http
-{
- /// <summary>Provides a set of connection pools, each for its own endpoint.</summary>
- internal sealed class HttpConnectionPools : IDisposable
- {
- /// <summary>How frequently an operation should be initiated to clean out old pools and connections in those pools.</summary>
- private const int CleanPoolTimeoutMilliseconds =
-#if DEBUG
- 1_000;
-#else
- 30_000;
-#endif
- /// <summary>The pools, indexed by endpoint.</summary>
- private readonly ConcurrentDictionary<HttpConnectionKey, HttpConnectionPool> _pools;
- /// <summary>Timer used to initiate cleaning of the pools.</summary>
- private readonly Timer _cleaningTimer;
- /// <summary>The maximum number of connections allowed per pool. <see cref="int.MaxValue"/> indicates unlimited.</summary>
- private readonly int _maxConnectionsPerServer;
- /// <summary>
- /// Keeps track of whether or not the cleanup timer is running. It helps us avoid the expensive
- /// <see cref="ConcurrentDictionary{TKey,TValue}.IsEmpty"/> call.
- /// </summary>
- private bool _timerIsRunning;
- /// <summary>Object used to synchronize access to state in the pool.</summary>
- private object SyncObj => _pools;
-
- /// <summary>Initializes the pools.</summary>
- /// <param name="maxConnectionsPerServer">The maximum number of connections allowed per pool. <see cref="int.MaxValue"/> indicates unlimited.</param>
- public HttpConnectionPools(int maxConnectionsPerServer)
- {
- _maxConnectionsPerServer = maxConnectionsPerServer;
- _pools = new ConcurrentDictionary<HttpConnectionKey, HttpConnectionPool>();
- // Start out with the timer not running, since we have no pools.
-
- // Don't capture the current ExecutionContext and its AsyncLocals onto the timer causing them to live forever
- bool restoreFlow = false;
- try
- {
- if (!ExecutionContext.IsFlowSuppressed())
- {
- ExecutionContext.SuppressFlow();
- restoreFlow = true;
- }
-
- _cleaningTimer = new Timer(s => ((HttpConnectionPools)s).RemoveStalePools(), this, Timeout.Infinite, Timeout.Infinite);
- }
- finally
- {
- // Restore the current ExecutionContext
- if (restoreFlow)
- ExecutionContext.RestoreFlow();
- }
- }
-
- /// <summary>Gets a pool for the specified endpoint, adding one if none existed.</summary>
- /// <param name="key">The endpoint for the pool.</param>
- /// <returns>The retrieved pool.</returns>
- public HttpConnectionPool GetOrAddPool(HttpConnectionKey key)
- {
- HttpConnectionPool pool;
- while (!_pools.TryGetValue(key, out pool))
- {
- pool = new HttpConnectionPool(_maxConnectionsPerServer);
- if (_pools.TryAdd(key, pool))
- {
- // We need to ensure the cleanup timer is running if it isn't
- // already now that we added a new connection pool.
- lock (SyncObj)
- {
- if (!_timerIsRunning)
- {
- _cleaningTimer.Change(CleanPoolTimeoutMilliseconds, CleanPoolTimeoutMilliseconds);
- _timerIsRunning = true;
- }
- }
- break;
- }
- }
-
- return pool;
- }
-
- /// <summary>Disposes of the pools, disposing of each individual pool.</summary>
- public void Dispose()
- {
- _cleaningTimer.Dispose();
- foreach (KeyValuePair<HttpConnectionKey, HttpConnectionPool> pool in _pools)
- {
- pool.Value.Dispose();
- }
- }
-
- /// <summary>Removes unusable connections from each pool, and removes stale pools entirely.</summary>
- private void RemoveStalePools()
- {
- // Iterate through each pool in the set of pools. For each, ask it to clear out
- // any unusable connections (e.g. those which have expired, those which have been closed, etc.)
- // The pool may detect that it's empty and long unused, in which case it'll dispose of itself,
- // such that any connections returned to the pool to be cached will be disposed of. In such
- // a case, we also remove the pool from the set of pools to avoid a leak.
- foreach (KeyValuePair<HttpConnectionKey, HttpConnectionPool> entry in _pools)
- {
- if (entry.Value.CleanCacheAndDisposeIfUnused())
- {
- _pools.TryRemove(entry.Key, out HttpConnectionPool _);
- }
- }
-
- // Stop running the timer if we don't have any pools to clean up.
- lock (SyncObj)
- {
- if (_pools.IsEmpty)
- {
- _cleaningTimer.Change(Timeout.Infinite, Timeout.Infinite);
- _timerIsRunning = false;
- }
- }
-
- // NOTE: There is a possible race condition with regards to a pool getting cleaned up at the same
- // time it's about to be used for another request. The timer cleanup could start running, see that
- // a pool is empty, and initiate its disposal. Concurrently, the pools could hand out the pool
- // to a request looking to get a connection, because the pool may not have been removed yet
- // from the pools. Worst case here is that connection will end up getting returned to an
- // already disposed pool, in which case the connection will also end up getting disposed rather
- // than reused. This should be a rare occurrence, so for now we don't worry about it. In the
- // future, there are a variety of possible ways to address it, such as allowing connections to
- // be returned to pools they weren't associated with.
- }
- }
-}
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionSettings.cs b/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionSettings.cs
deleted file mode 100644
index 866044af87..0000000000
--- a/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionSettings.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Net.Security;
-using System.Security.Authentication;
-using System.Security.Cryptography.X509Certificates;
-
-namespace System.Net.Http
-{
- /// <summary>Provides a state bag of settings for configuring HTTP connections.</summary>
- internal sealed class HttpConnectionSettings
- {
- internal DecompressionMethods _automaticDecompression = HttpHandlerDefaults.DefaultAutomaticDecompression;
-
- internal bool _useCookies = HttpHandlerDefaults.DefaultUseCookies;
- internal CookieContainer _cookieContainer;
-
- internal bool _useProxy = HttpHandlerDefaults.DefaultUseProxy;
- internal IWebProxy _proxy;
- internal ICredentials _defaultProxyCredentials;
-
- internal bool _preAuthenticate = HttpHandlerDefaults.DefaultPreAuthenticate;
- internal bool _useDefaultCredentials = HttpHandlerDefaults.DefaultUseDefaultCredentials;
- internal ICredentials _credentials;
-
- internal bool _allowAutoRedirect = HttpHandlerDefaults.DefaultAutomaticRedirection;
- internal int _maxAutomaticRedirections = HttpHandlerDefaults.DefaultMaxAutomaticRedirections;
-
- internal int _maxConnectionsPerServer = HttpHandlerDefaults.DefaultMaxConnectionsPerServer;
- internal int _maxResponseHeadersLength = HttpHandlerDefaults.DefaultMaxResponseHeadersLength;
-
- internal ClientCertificateOption _clientCertificateOptions = HttpHandlerDefaults.DefaultClientCertificateOption;
- internal X509CertificateCollection _clientCertificates;
-
- internal Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> _serverCertificateCustomValidationCallback;
- internal bool _checkCertificateRevocationList = false;
- internal SslProtocols _sslProtocols = SslProtocols.None;
-
- internal IDictionary<string, object> _properties;
- }
-}
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/HttpContentDuplexStream.cs b/src/System.Net.Http/src/System/Net/Http/Managed/HttpContentDuplexStream.cs
deleted file mode 100644
index 022e876067..0000000000
--- a/src/System.Net.Http/src/System/Net/Http/Managed/HttpContentDuplexStream.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-using System.IO;
-using System.Threading;
-
-namespace System.Net.Http
-{
- internal abstract class HttpContentDuplexStream : HttpContentStream
- {
- public HttpContentDuplexStream(HttpConnection connection) : base(connection)
- {
- }
-
- public override bool CanRead => true;
- public override bool CanWrite => true;
-
- public override void Flush() => FlushAsync().GetAwaiter().GetResult();
-
- public override int Read(byte[] buffer, int offset, int count)
- {
- ValidateBufferArgs(buffer, offset, count);
- return ReadAsync(new Memory<byte>(buffer, offset, count), CancellationToken.None).GetAwaiter().GetResult();
- }
-
- public override void Write(byte[] buffer, int offset, int count) =>
- WriteAsync(buffer, offset, count, CancellationToken.None).GetAwaiter().GetResult();
-
- public override void CopyTo(Stream destination, int bufferSize) =>
- CopyToAsync(destination, bufferSize, CancellationToken.None).GetAwaiter().GetResult();
- }
-}
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/HttpContentReadStream.cs b/src/System.Net.Http/src/System/Net/Http/Managed/HttpContentReadStream.cs
deleted file mode 100644
index c277cf8df7..0000000000
--- a/src/System.Net.Http/src/System/Net/Http/Managed/HttpContentReadStream.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.IO;
-using System.Threading;
-
-namespace System.Net.Http
-{
- internal abstract class HttpContentReadStream : HttpContentStream
- {
- protected HttpConnection _connection;
-
- public HttpContentReadStream(HttpConnection connection)
- {
- _connection = connection;
- }
-
- public override bool CanRead => true;
- public override bool CanSeek => false;
- public override bool CanWrite => false;
-
- public override long Length => throw new NotSupportedException();
-
- public override long Position
- {
- get { throw new NotSupportedException(); }
- set { throw new NotSupportedException(); }
- }
-
- public override void Flush() => throw new NotSupportedException();
-
- public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
-
- public override void SetLength(long value) => throw new NotSupportedException();
-
- public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
-
- public override int Read(byte[] buffer, int offset, int count)
- {
- ValidateBufferArgs(buffer, offset, count);
- return ReadAsync(new Memory<byte>(buffer, offset, count), CancellationToken.None).GetAwaiter().GetResult();
- }
-
- public override void CopyTo(Stream destination, int bufferSize) =>
- CopyToAsync(destination, bufferSize, CancellationToken.None).GetAwaiter().GetResult();
-
- protected override void Dispose(bool disposing)
- {
- if (_connection != null)
- {
- // We haven't finished reading the body, so close the connection.
- _connection.Dispose();
- _connection = null;
- }
-
- base.Dispose(disposing);
- }
- }
-}
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/HttpContentStream.cs b/src/System.Net.Http/src/System/Net/Http/Managed/HttpContentStream.cs
deleted file mode 100644
index 991ea06bc0..0000000000
--- a/src/System.Net.Http/src/System/Net/Http/Managed/HttpContentStream.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.IO;
-
-namespace System.Net.Http
-{
- internal abstract class HttpContentStream : Stream
- {
- protected static void ValidateBufferArgs(byte[] buffer, int offset, int count)
- {
- if (buffer == null)
- {
- throw new ArgumentNullException(nameof(buffer));
- }
-
- if ((uint)offset > buffer.Length)
- {
- throw new ArgumentOutOfRangeException(nameof(offset));
- }
-
- if ((uint)count > buffer.Length - offset)
- {
- throw new ArgumentOutOfRangeException(nameof(count));
- }
- }
- }
-}
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/HttpContentWriteStream.cs b/src/System.Net.Http/src/System/Net/Http/Managed/HttpContentWriteStream.cs
deleted file mode 100644
index a998366083..0000000000
--- a/src/System.Net.Http/src/System/Net/Http/Managed/HttpContentWriteStream.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace System.Net.Http
-{
- internal abstract class HttpContentWriteStream : HttpContentStream
- {
- protected HttpConnection _connection;
-
- public HttpContentWriteStream(HttpConnection connection, CancellationToken cancellationToken)
- {
- Debug.Assert(connection != null);
- _connection = connection;
- RequestCancellationToken = cancellationToken;
- }
-
- /// <summary>Cancellation token associated with the send operation.</summary>
- /// <remarks>
- /// Because of how this write stream is used, the CancellationToken passed into the individual
- /// stream operations will be the default non-cancelable token and can be ignored. Instead,
- /// this token is used.
- /// </remarks>
- internal CancellationToken RequestCancellationToken { get; }
-
- public override bool CanRead => false;
- public override bool CanSeek => false;
- public override bool CanWrite => true;
-
- public override long Length => throw new NotSupportedException();
-
- public override long Position
- {
- get { throw new NotSupportedException(); }
- set { throw new NotSupportedException(); }
- }
-
- public override void Flush() => FlushAsync().GetAwaiter().GetResult();
-
- public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
-
- public override void SetLength(long value) => throw new NotSupportedException();
-
- public override int Read(byte[] buffer, int offset, int count) => throw new NotSupportedException();
-
- public override void Write(byte[] buffer, int offset, int count) =>
- WriteAsync(buffer, offset, count, CancellationToken.None).GetAwaiter().GetResult();
-
- public abstract Task FinishAsync();
-
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- if (_connection != null)
- {
- _connection.Dispose();
- _connection = null;
- }
- }
-
- base.Dispose(disposing);
- }
- }
-}
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/HttpProxyConnectionHandler.cs b/src/System.Net.Http/src/System/Net/Http/Managed/HttpProxyConnectionHandler.cs
deleted file mode 100644
index bd5718de4c..0000000000
--- a/src/System.Net.Http/src/System/Net/Http/Managed/HttpProxyConnectionHandler.cs
+++ /dev/null
@@ -1,196 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-using System.IO;
-using System.Net.Http.Headers;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace System.Net.Http
-{
- internal sealed class HttpProxyConnectionHandler : HttpMessageHandler
- {
- private readonly HttpMessageHandler _innerHandler;
- private readonly IWebProxy _proxy;
- private readonly ICredentials _defaultCredentials;
- private readonly HttpConnectionPools _connectionPools;
- private bool _disposed;
-
- public HttpProxyConnectionHandler(HttpConnectionSettings settings, HttpMessageHandler innerHandler)
- {
- Debug.Assert(innerHandler != null);
- Debug.Assert(settings._useProxy);
- Debug.Assert(settings._proxy != null || s_proxyFromEnvironment.Value != null);
-
- _innerHandler = innerHandler;
- _proxy = settings._proxy ?? new PassthroughWebProxy(s_proxyFromEnvironment.Value);
- _defaultCredentials = settings._defaultProxyCredentials;
- _connectionPools = new HttpConnectionPools(settings._maxConnectionsPerServer);
- }
-
- protected internal override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
- {
- Uri proxyUri = null;
- try
- {
- if (!_proxy.IsBypassed(request.RequestUri))
- {
- proxyUri = _proxy.GetProxy(request.RequestUri);
- }
- }
- catch (Exception)
- {
- // Eat any exception from the IWebProxy and just treat it as no proxy.
- // This matches the behavior of other handlers.
- }
-
- return proxyUri == null ?
- _innerHandler.SendAsync(request, cancellationToken) :
- SendWithProxyAsync(proxyUri, request, cancellationToken);
- }
-
- private async Task<HttpResponseMessage> SendWithProxyAsync(
- Uri proxyUri, HttpRequestMessage request, CancellationToken cancellationToken)
- {
- if (proxyUri.Scheme != UriScheme.Http)
- {
- throw new InvalidOperationException(SR.net_http_invalid_proxy_scheme);
- }
-
- if (request.RequestUri.Scheme == UriScheme.Https)
- {
- // TODO #23136: Implement SSL tunneling through proxy
- throw new NotImplementedException("no support for SSL tunneling through proxy");
- }
-
- HttpConnection connection = await GetOrCreateConnection(request, proxyUri, cancellationToken).ConfigureAwait(false);
-
- HttpResponseMessage response = await connection.SendAsync(request, cancellationToken).ConfigureAwait(false);
-
- // Handle proxy authentication
- if (response.StatusCode == HttpStatusCode.ProxyAuthenticationRequired)
- {
- foreach (AuthenticationHeaderValue h in response.Headers.ProxyAuthenticate)
- {
- // We only support Basic auth, ignore others
- if (h.Scheme == AuthenticationHelper.Basic)
- {
- NetworkCredential credential =
- _proxy.Credentials?.GetCredential(proxyUri, AuthenticationHelper.Basic) ??
- _defaultCredentials?.GetCredential(proxyUri, AuthenticationHelper.Basic);
-
- if (credential != null)
- {
- response.Dispose();
-
- request.Headers.ProxyAuthorization = new AuthenticationHeaderValue(AuthenticationHelper.Basic,
- AuthenticationHelper.GetBasicTokenForCredential(credential));
-
- connection = await GetOrCreateConnection(request, proxyUri, cancellationToken).ConfigureAwait(false);
- response = await connection.SendAsync(request, cancellationToken).ConfigureAwait(false);
- }
-
- break;
- }
- else if (h.Scheme == AuthenticationHelper.Digest)
- {
- NetworkCredential credential =
- _proxy.Credentials?.GetCredential(proxyUri, AuthenticationHelper.Digest) ??
- _defaultCredentials?.GetCredential(proxyUri, AuthenticationHelper.Digest);
-
- if (credential != null)
- {
- // Update digest response with new parameter from Proxy-Authenticate
- AuthenticationHelper.DigestResponse digestResponse = new AuthenticationHelper.DigestResponse(h.Parameter);
-
- if (await AuthenticationHelper.TrySetDigestAuthToken(request, credential, digestResponse, HttpKnownHeaderNames.ProxyAuthorization).ConfigureAwait(false))
- {
- response.Dispose();
- response = await _innerHandler.SendAsync(request, cancellationToken).ConfigureAwait(false);
-
- // Retry in case of nonce timeout in server.
- if (response.StatusCode == HttpStatusCode.Unauthorized)
- {
- foreach (AuthenticationHeaderValue ahv in response.Headers.ProxyAuthenticate)
- {
- if (ahv.Scheme == AuthenticationHelper.Digest)
- {
- digestResponse = new AuthenticationHelper.DigestResponse(ahv.Parameter);
- if (AuthenticationHelper.IsServerNonceStale(digestResponse) &&
- await AuthenticationHelper.TrySetDigestAuthToken(request, credential, digestResponse, HttpKnownHeaderNames.ProxyAuthorization).ConfigureAwait(false))
- {
- response.Dispose();
- response = await _innerHandler.SendAsync(request, cancellationToken).ConfigureAwait(false);
- }
-
- break;
- }
- }
- }
- }
-
- break;
- }
- }
- }
- }
-
- return response;
- }
-
- private ValueTask<HttpConnection> GetOrCreateConnection(HttpRequestMessage request, Uri proxyUri, CancellationToken cancellationToken)
- {
- var key = new HttpConnectionKey(proxyUri);
- HttpConnectionPool pool = _connectionPools.GetOrAddPool(key);
- return pool.GetConnectionAsync(async (state, ct) =>
- {
- Stream stream = await ConnectHelper.ConnectAsync(state.proxyUri.IdnHost, state.proxyUri.Port, ct).ConfigureAwait(false);
- return new HttpConnection(state.pool, state.key, null, stream, null, true);
- }, (pool: pool, key: key, request: request, proxyUri: proxyUri), cancellationToken);
- }
-
- protected override void Dispose(bool disposing)
- {
- if (disposing && !_disposed)
- {
- _disposed = true;
- _connectionPools.Dispose();
- }
-
- base.Dispose(disposing);
- }
-
- public static bool EnvironmentProxyConfigured => s_proxyFromEnvironment.Value != null;
-
- private static readonly Lazy<Uri> s_proxyFromEnvironment = new Lazy<Uri>(() =>
- {
- // http_proxy is standard on Unix, used e.g. by libcurl.
- // TODO #23150: We should support the full array of environment variables here,
- // including no_proxy, all_proxy, etc.
-
- string proxyString = Environment.GetEnvironmentVariable("http_proxy");
- if (!string.IsNullOrWhiteSpace(proxyString))
- {
- Uri proxyFromEnvironment;
- if (Uri.TryCreate(proxyString, UriKind.Absolute, out proxyFromEnvironment) ||
- Uri.TryCreate(Uri.UriSchemeHttp + Uri.SchemeDelimiter + proxyString, UriKind.Absolute, out proxyFromEnvironment))
- {
- return proxyFromEnvironment;
- }
- }
-
- return null;
- });
-
- private sealed class PassthroughWebProxy : IWebProxy
- {
- private readonly Uri _proxyUri;
- public PassthroughWebProxy(Uri proxyUri) => _proxyUri = proxyUri;
- public ICredentials Credentials { get => null; set { } }
- public Uri GetProxy(Uri destination) => _proxyUri;
- public bool IsBypassed(Uri host) => false;
- }
- }
-}
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/README.md b/src/System.Net.Http/src/System/Net/Http/Managed/README.md
deleted file mode 100644
index c7d6a588ab..0000000000
--- a/src/System.Net.Http/src/System/Net/Http/Managed/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-#### Enabling the ManagedHandler
-
-The shipping version of HttpClientHandler is a wrapper for WinHTTP on Windows and libcurl on Unix. This directory contains a managed implementation that's still under development and that's not intended for production use. By default it's disabled, and the WinHTTP/libcurl versions will be used. However, by setting the "COMPlus_UseManagedHttpClientHandler" environment variable to "true", this managed implementation will be used. \ No newline at end of file
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/RawConnectionStream.cs b/src/System.Net.Http/src/System/Net/Http/Managed/RawConnectionStream.cs
deleted file mode 100644
index 375006bacd..0000000000
--- a/src/System.Net.Http/src/System/Net/Http/Managed/RawConnectionStream.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace System.Net.Http
-{
- internal sealed partial class HttpConnection : IDisposable
- {
- private sealed class RawConnectionStream : HttpContentDuplexStream
- {
- public RawConnectionStream(HttpConnection connection) : base(connection)
- {
- }
-
- public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
- {
- ValidateBufferArgs(buffer, offset, count);
- return ReadAsync(new Memory<byte>(buffer, offset, count), cancellationToken).AsTask();
- }
-
- public override async ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken = default)
- {
- if (_connection == null || destination.Length == 0)
- {
- // Response body fully consumed or the caller didn't ask for any data
- return 0;
- }
-
- int bytesRead = await _connection.ReadAsync(destination, cancellationToken).ConfigureAwait(false);
- if (bytesRead == 0)
- {
- // We cannot reuse this connection, so close it.
- _connection.Dispose();
- _connection = null;
- return 0;
- }
-
- return bytesRead;
- }
-
- public override async Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
- {
- if (destination == null)
- {
- throw new ArgumentNullException(nameof(destination));
- }
-
- if (_connection != null) // null if response body fully consumed
- {
- await _connection.CopyToAsync(destination, cancellationToken).ConfigureAwait(false);
-
- // We cannot reuse this connection, so close it.
- _connection.Dispose();
- _connection = null;
- }
- }
-
- public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
- {
- ValidateBufferArgs(buffer, offset, count);
- return WriteAsync(new ReadOnlyMemory<byte>(buffer, offset, count), cancellationToken);
- }
-
- public override Task WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken = default) =>
- _connection == null ? Task.FromException(new IOException(SR.net_http_io_write)) :
- source.Length > 0 ? _connection.WriteWithoutBufferingAsync(source, cancellationToken) :
- Task.CompletedTask;
-
- public override Task FlushAsync(CancellationToken cancellationToken) =>
- _connection != null ? _connection.FlushAsync(cancellationToken) :
- Task.CompletedTask;
- }
- }
-}
diff --git a/src/System.Net.Http/src/System/Net/Http/MultipartContent.cs b/src/System.Net.Http/src/System/Net/Http/MultipartContent.cs
index 40216b5a27..32b0d647e6 100644
--- a/src/System.Net.Http/src/System/Net/Http/MultipartContent.cs
+++ b/src/System.Net.Http/src/System/Net/Http/MultipartContent.cs
@@ -275,10 +275,10 @@ namespace System.Net.Http
return scratch.ToString();
}
- private static Task EncodeStringToStreamAsync(Stream stream, string input)
+ private static ValueTask EncodeStringToStreamAsync(Stream stream, string input)
{
byte[] buffer = HttpRuleParser.DefaultHttpEncoding.GetBytes(input);
- return stream.WriteAsync(buffer, 0, buffer.Length);
+ return stream.WriteAsync(new ReadOnlyMemory<byte>(buffer));
}
private static Stream EncodeStringToNewStream(string input)
@@ -417,9 +417,9 @@ namespace System.Net.Http
}
}
- public override int Read(Span<byte> destination)
+ public override int Read(Span<byte> buffer)
{
- if (destination.Length == 0)
+ if (buffer.Length == 0)
{
return 0;
}
@@ -428,7 +428,7 @@ namespace System.Net.Http
{
if (_current != null)
{
- int bytesRead = _current.Read(destination);
+ int bytesRead = _current.Read(buffer);
if (bytesRead != 0)
{
_position += bytesRead;
@@ -453,8 +453,8 @@ namespace System.Net.Http
return ReadAsyncPrivate(new Memory<byte>(buffer, offset, count), cancellationToken).AsTask();
}
- public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken = default) =>
- ReadAsyncPrivate(destination, cancellationToken);
+ public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default) =>
+ ReadAsyncPrivate(buffer, cancellationToken);
public override IAsyncResult BeginRead(byte[] array, int offset, int count, AsyncCallback asyncCallback, object asyncState) =>
TaskToApm.Begin(ReadAsync(array, offset, count, CancellationToken.None), asyncCallback, asyncState);
@@ -462,9 +462,9 @@ namespace System.Net.Http
public override int EndRead(IAsyncResult asyncResult) =>
TaskToApm.End<int>(asyncResult);
- public async ValueTask<int> ReadAsyncPrivate(Memory<byte> destination, CancellationToken cancellationToken)
+ public async ValueTask<int> ReadAsyncPrivate(Memory<byte> buffer, CancellationToken cancellationToken)
{
- if (destination.Length == 0)
+ if (buffer.Length == 0)
{
return 0;
}
@@ -473,7 +473,7 @@ namespace System.Net.Http
{
if (_current != null)
{
- int bytesRead = await _current.ReadAsync(destination, cancellationToken).ConfigureAwait(false);
+ int bytesRead = await _current.ReadAsync(buffer, cancellationToken).ConfigureAwait(false);
if (bytesRead != 0)
{
_position += bytesRead;
@@ -581,9 +581,9 @@ namespace System.Net.Http
public override void Flush() { }
public override void SetLength(long value) { throw new NotSupportedException(); }
public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); }
- public override void Write(ReadOnlySpan<byte> source) { throw new NotSupportedException(); }
+ public override void Write(ReadOnlySpan<byte> buffer) { throw new NotSupportedException(); }
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { throw new NotSupportedException(); }
- public override Task WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken = default) { throw new NotSupportedException(); }
+ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default) { throw new NotSupportedException(); }
}
#endregion Serialization
}
diff --git a/src/System.Net.Http/src/System/Net/Http/NetEventSource.Http.cs b/src/System.Net.Http/src/System/Net/Http/NetEventSource.Http.cs
index f4020a804d..8735970c8e 100644
--- a/src/System.Net.Http/src/System/Net/Http/NetEventSource.Http.cs
+++ b/src/System.Net.Http/src/System/Net/Http/NetEventSource.Http.cs
@@ -63,6 +63,7 @@ namespace System.Net
[Event(HandlerMessageId, Keywords = Keywords.Debug, Level = EventLevel.Verbose)]
public void HandlerMessage(int handlerId, int workerId, int requestId, string memberName, string message) =>
WriteEvent(HandlerMessageId, handlerId, workerId, requestId, memberName, message);
+ //Console.WriteLine($"{handlerId}/{workerId}/{requestId}: ({memberName}): {message}"); // uncomment for debugging only
[NonEvent]
private unsafe void WriteEvent(int eventId, int arg1, int arg2, int arg3, string arg4, string arg5)
@@ -78,20 +79,31 @@ namespace System.Net
const int NumEventDatas = 5;
var descrs = stackalloc EventData[NumEventDatas];
- descrs[0].DataPointer = (IntPtr)(&arg1);
- descrs[0].Size = sizeof(int);
-
- descrs[1].DataPointer = (IntPtr)(&arg2);
- descrs[1].Size = sizeof(int);
-
- descrs[2].DataPointer = (IntPtr)(&arg3);
- descrs[2].Size = sizeof(int);
-
- descrs[3].DataPointer = (IntPtr)string4Bytes;
- descrs[3].Size = ((arg4.Length + 1) * 2);
-
- descrs[4].DataPointer = (IntPtr)string5Bytes;
- descrs[4].Size = ((arg5.Length + 1) * 2);
+ descrs[0] = new EventData
+ {
+ DataPointer = (IntPtr)(&arg1),
+ Size = sizeof(int)
+ };
+ descrs[1] = new EventData
+ {
+ DataPointer = (IntPtr)(&arg2),
+ Size = sizeof(int)
+ };
+ descrs[2] = new EventData
+ {
+ DataPointer = (IntPtr)(&arg3),
+ Size = sizeof(int)
+ };
+ descrs[3] = new EventData
+ {
+ DataPointer = (IntPtr)string4Bytes,
+ Size = ((arg4.Length + 1) * 2)
+ };
+ descrs[4] = new EventData
+ {
+ DataPointer = (IntPtr)string5Bytes,
+ Size = ((arg5.Length + 1) * 2)
+ };
WriteEventCore(eventId, NumEventDatas, descrs);
}
diff --git a/src/System.Net.Http/src/System/Net/Http/ReadOnlyMemoryContent.cs b/src/System.Net.Http/src/System/Net/Http/ReadOnlyMemoryContent.cs
index 0a9588d71a..77f713593b 100644
--- a/src/System.Net.Http/src/System/Net/Http/ReadOnlyMemoryContent.cs
+++ b/src/System.Net.Http/src/System/Net/Http/ReadOnlyMemoryContent.cs
@@ -4,6 +4,7 @@
using System.IO;
using System.Runtime.InteropServices;
+using System.Threading;
using System.Threading.Tasks;
namespace System.Net.Http
@@ -24,7 +25,10 @@ namespace System.Net.Http
}
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) =>
- stream.WriteAsync(_content);
+ stream.WriteAsync(_content).AsTask();
+
+ internal override Task SerializeToStreamAsync(Stream stream, TransportContext context, CancellationToken cancellationToken) =>
+ stream.WriteAsync(_content, cancellationToken).AsTask();
protected internal override bool TryComputeLength(out long length)
{
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/AuthenticationHelper.Digest.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.Digest.cs
index 3f0b911689..841872b43d 100644
--- a/src/System.Net.Http/src/System/Net/Http/Managed/AuthenticationHelper.Digest.cs
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.Digest.cs
@@ -15,8 +15,6 @@ namespace System.Net.Http
{
internal partial class AuthenticationHelper
{
- public const string Digest = "Digest";
-
// Define digest constants
private const string Qop = "qop";
private const string Auth = "auth";
@@ -42,35 +40,6 @@ namespace System.Net.Http
// 48='0', 65='A', 97='a'
private static int[] s_alphaNumChooser = new int[] { 48, 65, 97 };
- // Define a random number generator for cnonce
- private static RandomNumberGenerator s_rng = RandomNumberGenerator.Create();
-
- public async static Task<bool> TrySetDigestAuthToken(HttpRequestMessage request, ICredentials credentials, DigestResponse digestResponse, string authHeader)
- {
- NetworkCredential credential = credentials.GetCredential(request.RequestUri, Digest);
- if (credential == null)
- {
- return false;
- }
-
- string parameter = await GetDigestTokenForCredential(credential, request, digestResponse).ConfigureAwait(false);
-
- // Any errors in obtaining parameter return false
- if (string.IsNullOrEmpty(parameter))
- return false;
-
- if (authHeader == HttpKnownHeaderNames.Authorization)
- {
- request.Headers.Authorization = new AuthenticationHeaderValue(Digest, parameter);
- }
- else if (authHeader == HttpKnownHeaderNames.ProxyAuthorization)
- {
- request.Headers.ProxyAuthorization = new AuthenticationHeaderValue(Digest, parameter);
- }
-
- return true;
- }
-
public static async Task<string> GetDigestTokenForCredential(NetworkCredential credential, HttpRequestMessage request, DigestResponse digestResponse)
{
StringBuilder sb = StringBuilderCache.Acquire();
@@ -95,14 +64,16 @@ namespace System.Net.Http
return null;
}
+ // opaque token may or may not exist
string opaque;
- if (!digestResponse.Parameters.TryGetValue(Opaque, out opaque))
+ digestResponse.Parameters.TryGetValue(Opaque, out opaque);
+
+ string realm;
+ if (!digestResponse.Parameters.TryGetValue(Realm, out realm))
{
return null;
}
- string realm = digestResponse.Parameters.ContainsKey(Realm) ? digestResponse.Parameters[Realm] : string.Empty;
-
// Add username
string userhash;
if (digestResponse.Parameters.TryGetValue(UserHash, out userhash) && userhash == "true")
@@ -162,9 +133,8 @@ namespace System.Net.Http
// Calculate response
string a1 = credential.UserName + ":" + realm + ":" + credential.Password;
- if (algorithm == Sha256Sess || algorithm == MD5Sess)
+ if (algorithm.IndexOf("sess") != -1)
{
- algorithm = algorithm == Sha256Sess ? Sha256 : Md5;
a1 = ComputeHash(a1, algorithm) + ":" + nonce + ":" + cnonce;
}
@@ -189,7 +159,10 @@ namespace System.Net.Http
sb.AppendKeyValue(Algorithm, algorithm, includeQuotes: false);
// Add opaque
- sb.AppendKeyValue(Opaque, opaque);
+ if (opaque != null)
+ {
+ sb.AppendKeyValue(Opaque, opaque);
+ }
// Add qop
sb.AppendKeyValue(Qop, qop, includeQuotes: false);
@@ -213,7 +186,7 @@ namespace System.Net.Http
{
const int Length = 16;
Span<byte> randomNumbers = stackalloc byte[Length * 2];
- s_rng.GetBytes(randomNumbers);
+ RandomNumberGenerator.Fill(randomNumbers);
StringBuilder sb = StringBuilderCache.Acquire(Length);
for (int i = 0; i < randomNumbers.Length;)
@@ -231,15 +204,22 @@ namespace System.Net.Http
{
// Disable MD5 insecure warning.
#pragma warning disable CA5351
- using (HashAlgorithm hash = algorithm == Sha256 ? SHA256.Create() : (HashAlgorithm)MD5.Create())
+ using (HashAlgorithm hash = algorithm.Contains(Sha256) ? SHA256.Create() : (HashAlgorithm)MD5.Create())
#pragma warning restore CA5351
{
- Encoding enc = Encoding.UTF8;
- byte[] result = hash.ComputeHash(enc.GetBytes(data));
+ Span<byte> result = stackalloc byte[hash.HashSize / 8]; // HashSize is in bits
+ bool hashComputed = hash.TryComputeHash(Encoding.UTF8.GetBytes(data), result, out int bytesWritten);
+ Debug.Assert(hashComputed && bytesWritten == result.Length);
StringBuilder sb = StringBuilderCache.Acquire(result.Length * 2);
- foreach (byte b in result)
- sb.Append(b.ToString("x2"));
+
+ Span<char> byteX2 = stackalloc char[2];
+ for (int i = 0; i < result.Length; i++)
+ {
+ bool formatted = result[i].TryFormat(byteX2, out int charsWritten, "x2");
+ Debug.Assert(formatted && charsWritten == 2);
+ sb.Append(byteX2);
+ }
return StringBuilderCache.GetStringAndRelease(sb);
}
@@ -252,7 +232,8 @@ namespace System.Net.Http
internal DigestResponse(string challenge)
{
- Parse(challenge);
+ if (!string.IsNullOrEmpty(challenge))
+ Parse(challenge);
}
private static bool CharIsSpaceOrTab(char ch)
@@ -260,6 +241,13 @@ namespace System.Net.Http
return ch == ' ' || ch == '\t';
}
+ private static bool MustValueBeQuoted(string key)
+ {
+ // As per the RFC, these string must be quoted for historical reasons.
+ return key.Equals(Realm, StringComparison.OrdinalIgnoreCase) || key.Equals(Nonce, StringComparison.OrdinalIgnoreCase) ||
+ key.Equals(Opaque, StringComparison.OrdinalIgnoreCase) || key.Equals(Qop, StringComparison.OrdinalIgnoreCase);
+ }
+
private string GetNextKey(string data, int currentIndex, out int parsedIndex)
{
// Skip leading space or tab.
@@ -315,7 +303,7 @@ namespace System.Net.Http
return data.Substring(start, length);
}
- private string GetNextValue(string data, int currentIndex, out int parsedIndex)
+ private string GetNextValue(string data, int currentIndex, bool expectQuotes, out int parsedIndex)
{
Debug.Assert(currentIndex < data.Length && !CharIsSpaceOrTab(data[currentIndex]));
@@ -327,6 +315,12 @@ namespace System.Net.Http
currentIndex++;
}
+ if (expectQuotes && !quotedValue)
+ {
+ parsedIndex = currentIndex;
+ return null;
+ }
+
StringBuilder sb = StringBuilderCache.Acquire();
while (currentIndex < data.Length && ((quotedValue && data[currentIndex] != '"') || (!quotedValue && data[currentIndex] != ',')))
{
@@ -347,6 +341,14 @@ namespace System.Net.Http
}
}
+ // Skip the quote.
+ if (quotedValue)
+ currentIndex++;
+
+ // Skip any whitespace.
+ while (currentIndex < data.Length && CharIsSpaceOrTab(data[currentIndex]))
+ currentIndex++;
+
// Return if this is last value.
if (currentIndex == data.Length)
{
@@ -354,11 +356,15 @@ namespace System.Net.Http
return StringBuilderCache.GetStringAndRelease(sb);
}
- // Skip the end quote or ',' or space or tab.
- currentIndex++;
+ // A key-value pair should end with ','
+ if (data[currentIndex++] != ',')
+ {
+ parsedIndex = currentIndex;
+ return null;
+ }
- // Skip space and tab and ,
- while (currentIndex < data.Length && (CharIsSpaceOrTab(data[currentIndex]) || data[currentIndex] == ','))
+ // Skip space and tab
+ while (currentIndex < data.Length && CharIsSpaceOrTab(data[currentIndex]))
{
currentIndex++;
}
@@ -380,7 +386,11 @@ namespace System.Net.Http
break;
// Get the value.
- string value = GetNextValue(challenge, parsedIndex, out parsedIndex);
+ string value = GetNextValue(challenge, parsedIndex, MustValueBeQuoted(key), out parsedIndex);
+ // Ensure value is valid.
+ if (string.IsNullOrEmpty(value))
+ break;
+
// Add the key-value pair to Parameters.
Parameters.Add(key, value);
}
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.NtAuth.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.NtAuth.cs
new file mode 100644
index 0000000000..22e2610f45
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.NtAuth.cs
@@ -0,0 +1,98 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Net.Http.Headers;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Security.Authentication.ExtendedProtection;
+
+namespace System.Net.Http
+{
+ internal partial class AuthenticationHelper
+ {
+ private static Task<HttpResponseMessage> InnerSendAsync(HttpRequestMessage request, bool isProxyAuth, HttpConnection connection, CancellationToken cancellationToken)
+ {
+ return isProxyAuth ?
+ connection.SendAsyncCore(request, cancellationToken) :
+ connection.SendWithNtProxyAuthAsync(request, cancellationToken);
+ }
+
+ private static bool ProxySupportsConnectionAuth(HttpResponseMessage response)
+ {
+ if (!response.Headers.TryGetValues(KnownHeaders.ProxySupport.Descriptor, out IEnumerable<string> values))
+ {
+ return false;
+ }
+
+ foreach (string v in values)
+ {
+ if (v == "Session-Based-Authentication")
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static async Task<HttpResponseMessage> SendWithNtAuthAsync(HttpRequestMessage request, Uri authUri, ICredentials credentials, bool isProxyAuth, HttpConnection connection, CancellationToken cancellationToken)
+ {
+ HttpResponseMessage response = await InnerSendAsync(request, isProxyAuth, connection, cancellationToken).ConfigureAwait(false);
+
+ if (!isProxyAuth && connection.UsingProxy && !ProxySupportsConnectionAuth(response))
+ {
+ // Proxy didn't indicate that it supports connection-based auth, so we can't proceed.
+ return response;
+ }
+
+ if (TryGetAuthenticationChallenge(response, isProxyAuth, authUri, credentials, out AuthenticationChallenge challenge))
+ {
+ if (challenge.AuthenticationType == AuthenticationType.Negotiate ||
+ challenge.AuthenticationType == AuthenticationType.Ntlm)
+ {
+ string challengeData = challenge.ChallengeData;
+
+ string spn = "HTTP/" + authUri.IdnHost;
+ ChannelBinding channelBinding = connection.TransportContext?.GetChannelBinding(ChannelBindingKind.Endpoint);
+ NTAuthentication authContext = new NTAuthentication(isServer:false, challenge.SchemeName, challenge.Credential, spn, ContextFlagsPal.Connection, channelBinding);
+ try
+ {
+ while (true)
+ {
+ string challengeResponse = authContext.GetOutgoingBlob(challengeData);
+
+ await connection.DrainResponseAsync(response).ConfigureAwait(false);
+
+ SetRequestAuthenticationHeaderValue(request, new AuthenticationHeaderValue(challenge.SchemeName, challengeResponse), isProxyAuth);
+
+ response = await InnerSendAsync(request, isProxyAuth, connection, cancellationToken).ConfigureAwait(false);
+ if (authContext.IsCompleted || !TryGetRepeatedChallenge(response, challenge.SchemeName, isProxyAuth, out challengeData))
+ {
+ break;
+ }
+ }
+ }
+ finally
+ {
+ authContext.CloseContext();
+ }
+ }
+ }
+
+ return response;
+ }
+
+ public static Task<HttpResponseMessage> SendWithNtProxyAuthAsync(HttpRequestMessage request, Uri proxyUri, ICredentials proxyCredentials, HttpConnection connection, CancellationToken cancellationToken)
+ {
+ return SendWithNtAuthAsync(request, proxyUri, proxyCredentials, isProxyAuth:true, connection, cancellationToken);
+ }
+
+ public static Task<HttpResponseMessage> SendWithNtConnectionAuthAsync(HttpRequestMessage request, ICredentials credentials, HttpConnection connection, CancellationToken cancellationToken)
+ {
+ return SendWithNtAuthAsync(request, request.RequestUri, credentials, isProxyAuth:false, connection, cancellationToken);
+ }
+ }
+}
+
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.cs
new file mode 100644
index 0000000000..bf20577068
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.cs
@@ -0,0 +1,281 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Net.Http.Headers;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Net.Http
+{
+ internal partial class AuthenticationHelper
+ {
+ private const string BasicScheme = "Basic";
+ private const string DigestScheme = "Digest";
+ private const string NtlmScheme = "NTLM";
+ private const string NegotiateScheme = "Negotiate";
+
+ private enum AuthenticationType
+ {
+ Basic,
+ Digest,
+ Ntlm,
+ Negotiate
+ }
+
+ private readonly struct AuthenticationChallenge
+ {
+ public AuthenticationType AuthenticationType { get; }
+ public string SchemeName { get; }
+ public NetworkCredential Credential { get; }
+ public string ChallengeData { get; }
+
+ public AuthenticationChallenge(AuthenticationType authenticationType, string schemeName, NetworkCredential credential, string challenge)
+ {
+ AuthenticationType = authenticationType;
+ SchemeName = schemeName;
+ Credential = credential;
+ ChallengeData = challenge;
+ }
+ }
+
+ private static bool TryGetChallengeDataForScheme(string scheme, HttpHeaderValueCollection<AuthenticationHeaderValue> authenticationHeaderValues, out string challengeData)
+ {
+ foreach (AuthenticationHeaderValue ahv in authenticationHeaderValues)
+ {
+ if (StringComparer.OrdinalIgnoreCase.Equals(scheme, ahv.Scheme))
+ {
+ // Note, a valid challenge can have challengeData == null
+ challengeData = ahv.Parameter;
+ return true;
+ }
+ }
+
+ challengeData = null;
+ return false;
+ }
+
+ private static bool TryGetValidAuthenticationChallengeForScheme(string scheme, AuthenticationType authenticationType, Uri uri, ICredentials credentials,
+ HttpHeaderValueCollection<AuthenticationHeaderValue> authenticationHeaderValues, out AuthenticationChallenge challenge)
+ {
+ challenge = default;
+
+ if (!TryGetChallengeDataForScheme(scheme, authenticationHeaderValues, out string challengeData))
+ {
+ return false;
+ }
+
+ NetworkCredential credential = credentials.GetCredential(uri, scheme);
+ if (credential == null)
+ {
+ // We have no credential for this auth type, so we can't respond to the challenge.
+ // We'll continue to look for a different auth type that we do have a credential for.
+ return false;
+ }
+
+ challenge = new AuthenticationChallenge(authenticationType, scheme, credential, challengeData);
+ return true;
+ }
+
+ private static bool TryGetAuthenticationChallenge(HttpResponseMessage response, bool isProxyAuth, Uri authUri, ICredentials credentials, out AuthenticationChallenge challenge)
+ {
+ if (!IsAuthenticationChallenge(response, isProxyAuth))
+ {
+ challenge = default;
+ return false;
+ }
+
+ // Try to get a valid challenge for the schemes we support, in priority order.
+ HttpHeaderValueCollection<AuthenticationHeaderValue> authenticationHeaderValues = GetResponseAuthenticationHeaderValues(response, isProxyAuth);
+ return
+ TryGetValidAuthenticationChallengeForScheme(NegotiateScheme, AuthenticationType.Negotiate, authUri, credentials, authenticationHeaderValues, out challenge) ||
+ TryGetValidAuthenticationChallengeForScheme(NtlmScheme, AuthenticationType.Ntlm, authUri, credentials, authenticationHeaderValues, out challenge) ||
+ TryGetValidAuthenticationChallengeForScheme(DigestScheme, AuthenticationType.Digest, authUri, credentials, authenticationHeaderValues, out challenge) ||
+ TryGetValidAuthenticationChallengeForScheme(BasicScheme, AuthenticationType.Basic, authUri, credentials, authenticationHeaderValues, out challenge);
+ }
+
+ private static bool TryGetRepeatedChallenge(HttpResponseMessage response, string scheme, bool isProxyAuth, out string challengeData)
+ {
+ challengeData = null;
+
+ if (!IsAuthenticationChallenge(response, isProxyAuth))
+ {
+ return false;
+ }
+
+ if (!TryGetChallengeDataForScheme(scheme, GetResponseAuthenticationHeaderValues(response, isProxyAuth), out challengeData))
+ {
+ // We got another challenge status code, but couldn't find the challenge for the scheme we're handling currently.
+ // Just stop processing auth.
+ return false;
+ }
+
+ return true;
+ }
+
+ private static bool IsAuthenticationChallenge(HttpResponseMessage response, bool isProxyAuth)
+ {
+ return isProxyAuth ?
+ response.StatusCode == HttpStatusCode.ProxyAuthenticationRequired :
+ response.StatusCode == HttpStatusCode.Unauthorized;
+ }
+
+ private static HttpHeaderValueCollection<AuthenticationHeaderValue> GetResponseAuthenticationHeaderValues(HttpResponseMessage response, bool isProxyAuth)
+ {
+ return isProxyAuth ?
+ response.Headers.ProxyAuthenticate :
+ response.Headers.WwwAuthenticate;
+ }
+
+ private static void SetRequestAuthenticationHeaderValue(HttpRequestMessage request, AuthenticationHeaderValue headerValue, bool isProxyAuth)
+ {
+ if (isProxyAuth)
+ {
+ request.Headers.ProxyAuthorization = headerValue;
+ }
+ else
+ {
+ request.Headers.Authorization = headerValue;
+ }
+ }
+
+ private static void SetBasicAuthToken(HttpRequestMessage request, NetworkCredential credential, bool isProxyAuth)
+ {
+ string authString = !string.IsNullOrEmpty(credential.Domain) ?
+ credential.Domain + "\\" + credential.UserName + ":" + credential.Password :
+ credential.UserName + ":" + credential.Password;
+
+ string base64AuthString = Convert.ToBase64String(Encoding.UTF8.GetBytes(authString));
+
+ SetRequestAuthenticationHeaderValue(request, new AuthenticationHeaderValue(BasicScheme, base64AuthString), isProxyAuth);
+ }
+
+ private static async Task<bool> TrySetDigestAuthToken(HttpRequestMessage request, NetworkCredential credential, DigestResponse digestResponse, bool isProxyAuth)
+ {
+ string parameter = await GetDigestTokenForCredential(credential, request, digestResponse).ConfigureAwait(false);
+
+ // Any errors in obtaining parameter return false and we don't proceed with auth
+ if (string.IsNullOrEmpty(parameter))
+ {
+ return false;
+ }
+
+ var headerValue = new AuthenticationHeaderValue(DigestScheme, parameter);
+ SetRequestAuthenticationHeaderValue(request, headerValue, isProxyAuth);
+ return true;
+ }
+
+ private static Task<HttpResponseMessage> InnerSendAsync(HttpRequestMessage request, bool isProxyAuth, bool doRequestAuth, HttpConnectionPool pool, CancellationToken cancellationToken)
+ {
+ return isProxyAuth ?
+ pool.SendWithRetryAsync(request, doRequestAuth, cancellationToken) :
+ pool.SendWithProxyAuthAsync(request, doRequestAuth, cancellationToken);
+ }
+
+ private static async Task<HttpResponseMessage> SendWithAuthAsync(HttpRequestMessage request, Uri authUri, ICredentials credentials, bool preAuthenticate, bool isProxyAuth, bool doRequestAuth, HttpConnectionPool pool, CancellationToken cancellationToken)
+ {
+ // If preauth is enabled and this isn't proxy auth, try to get a basic credential from the
+ // preauth credentials cache, and if successful, set an auth header for it onto the request.
+ // Currently we only support preauth for Basic.
+ bool performedBasicPreauth = false;
+ if (preAuthenticate)
+ {
+ Debug.Assert(pool.PreAuthCredentials != null);
+ NetworkCredential credential;
+ lock (pool.PreAuthCredentials) // TODO #28045: Get rid of this lock.
+ {
+ // Just look for basic credentials. If in the future we support preauth
+ // for other schemes, this will need to search in order of precedence.
+ Debug.Assert(pool.PreAuthCredentials.GetCredential(authUri, NegotiateScheme) == null);
+ Debug.Assert(pool.PreAuthCredentials.GetCredential(authUri, NtlmScheme) == null);
+ Debug.Assert(pool.PreAuthCredentials.GetCredential(authUri, DigestScheme) == null);
+ credential = pool.PreAuthCredentials.GetCredential(authUri, BasicScheme);
+ }
+
+ if (credential != null)
+ {
+ SetBasicAuthToken(request, credential, isProxyAuth);
+ performedBasicPreauth = true;
+ }
+ }
+
+ HttpResponseMessage response = await InnerSendAsync(request, isProxyAuth, doRequestAuth, pool, cancellationToken).ConfigureAwait(false);
+
+ if (TryGetAuthenticationChallenge(response, isProxyAuth, authUri, credentials, out AuthenticationChallenge challenge))
+ {
+ switch (challenge.AuthenticationType)
+ {
+ case AuthenticationType.Digest:
+ var digestResponse = new DigestResponse(challenge.ChallengeData);
+ if (await TrySetDigestAuthToken(request, challenge.Credential, digestResponse, isProxyAuth).ConfigureAwait(false))
+ {
+ response.Dispose();
+ response = await InnerSendAsync(request, isProxyAuth, doRequestAuth, pool, cancellationToken).ConfigureAwait(false);
+
+ // Retry in case of nonce timeout in server.
+ if (TryGetRepeatedChallenge(response, challenge.SchemeName, isProxyAuth, out string challengeData))
+ {
+ digestResponse = new DigestResponse(challengeData);
+ if (IsServerNonceStale(digestResponse) &&
+ await TrySetDigestAuthToken(request, challenge.Credential, digestResponse, isProxyAuth).ConfigureAwait(false))
+ {
+ response.Dispose();
+ response = await InnerSendAsync(request, isProxyAuth, doRequestAuth, pool, cancellationToken).ConfigureAwait(false);
+ }
+ }
+ }
+ break;
+
+ case AuthenticationType.Basic:
+ if (performedBasicPreauth)
+ {
+ break;
+ }
+
+ response.Dispose();
+ SetBasicAuthToken(request, challenge.Credential, isProxyAuth);
+ response = await InnerSendAsync(request, isProxyAuth, doRequestAuth, pool, cancellationToken).ConfigureAwait(false);
+
+ if (preAuthenticate)
+ {
+ switch (response.StatusCode)
+ {
+ case HttpStatusCode.ProxyAuthenticationRequired:
+ case HttpStatusCode.Unauthorized:
+ break;
+
+ default:
+ lock (pool.PreAuthCredentials) // TODO #28045: Get rid of this lock.
+ {
+ try
+ {
+ pool.PreAuthCredentials.Add(authUri, BasicScheme, challenge.Credential);
+ }
+ catch (ArgumentException)
+ {
+ // The credential already existed.
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ return response;
+ }
+
+ public static Task<HttpResponseMessage> SendWithProxyAuthAsync(HttpRequestMessage request, Uri proxyUri, ICredentials proxyCredentials, bool doRequestAuth, HttpConnectionPool pool, CancellationToken cancellationToken)
+ {
+ return SendWithAuthAsync(request, proxyUri, proxyCredentials, preAuthenticate:false, isProxyAuth:true, doRequestAuth, pool, cancellationToken);
+ }
+
+ public static Task<HttpResponseMessage> SendWithRequestAuthAsync(HttpRequestMessage request, ICredentials credentials, bool preAuthenticate, HttpConnectionPool pool, CancellationToken cancellationToken)
+ {
+ return SendWithAuthAsync(request, request.RequestUri, credentials, preAuthenticate, isProxyAuth:false, doRequestAuth:true, pool, cancellationToken);
+ }
+ }
+}
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/CancellationHelper.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/CancellationHelper.cs
new file mode 100644
index 0000000000..e13dc68092
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/CancellationHelper.cs
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Net.Http
+{
+ /// <summary>Provides utilities related to cancellation.</summary>
+ internal static class CancellationHelper
+ {
+ /// <summary>The default message used by <see cref="OperationCanceledException"/>.</summary>
+ private static readonly string s_cancellationMessage = new OperationCanceledException().Message; // use same message as the default ctor
+
+ /// <summary>Determines whether to wrap an <see cref="Exception"/> in a cancellation exception.</summary>
+ /// <param name="exception">The exception.</param>
+ /// <param name="cancellationToken">The <see cref="CancellationToken"/> that may have triggered the exception.</param>
+ /// <returns>true if the exception should be wrapped; otherwise, false.</returns>
+ internal static bool ShouldWrapInOperationCanceledException(Exception exception, CancellationToken cancellationToken) =>
+ !(exception is OperationCanceledException) && cancellationToken.IsCancellationRequested;
+
+ /// <summary>Creates a cancellation exception.</summary>
+ /// <param name="innerException">The inner exception to wrap. May be null.</param>
+ /// <param name="cancellationToken">The <see cref="CancellationToken"/> that triggered the cancellation.</param>
+ /// <returns>The cancellation exception.</returns>
+ internal static Exception CreateOperationCanceledException(Exception innerException, CancellationToken cancellationToken) =>
+ new TaskCanceledException(s_cancellationMessage, innerException, cancellationToken); // TCE for compatibility with other handlers that use TaskCompletionSource.TrySetCanceled()
+
+ /// <summary>Throws a cancellation exception.</summary>
+ /// <param name="innerException">The inner exception to wrap. May be null.</param>
+ /// <param name="cancellationToken">The <see cref="CancellationToken"/> that triggered the cancellation.</param>
+ private static void ThrowOperationCanceledException(Exception innerException, CancellationToken cancellationToken) =>
+ throw CreateOperationCanceledException(innerException, cancellationToken);
+
+ /// <summary>Throws a cancellation exception if cancellation has been requested via <paramref name="cancellationToken"/>.</summary>
+ /// <param name="cancellationToken">The token to check for a cancellation request.</param>
+ internal static void ThrowIfCancellationRequested(CancellationToken cancellationToken)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ ThrowOperationCanceledException(innerException:null, cancellationToken);
+ }
+ }
+ }
+}
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ChunkedEncodingReadStream.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ChunkedEncodingReadStream.cs
new file mode 100644
index 0000000000..d7be5bfab6
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ChunkedEncodingReadStream.cs
@@ -0,0 +1,407 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers.Text;
+using System.Diagnostics;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Net.Http
+{
+ internal partial class HttpConnection
+ {
+ private sealed class ChunkedEncodingReadStream : HttpContentReadStream
+ {
+ /// <summary>How long a chunk indicator is allowed to be.</summary>
+ /// <remarks>
+ /// While most chunks indicators will contain no more than ulong.MaxValue.ToString("X").Length characters,
+ /// "chunk extensions" are allowed. We place a limit on how long a line can be to avoid OOM issues if an
+ /// infinite chunk length is sent. This value is arbitrary and can be changed as needed.
+ /// </remarks>
+ private const int MaxChunkBytesAllowed = 16*1024;
+ /// <summary>How long a trailing header can be. This value is arbitrary and can be changed as needed.</summary>
+ private const int MaxTrailingHeaderLength = 16*1024;
+ /// <summary>The number of bytes remaining in the chunk.</summary>
+ private ulong _chunkBytesRemaining;
+ /// <summary>The current state of the parsing state machine for the chunked response.</summary>
+ private ParsingState _state = ParsingState.ExpectChunkHeader;
+
+ public ChunkedEncodingReadStream(HttpConnection connection) : base(connection) { }
+
+ public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ // Cancellation requested.
+ return new ValueTask<int>(Task.FromCanceled<int>(cancellationToken));
+ }
+
+ if (_connection == null || buffer.Length == 0)
+ {
+ // Response body fully consumed or the caller didn't ask for any data.
+ return new ValueTask<int>(0);
+ }
+
+ // Try to consume from data we already have in the buffer.
+ int bytesRead = ReadChunksFromConnectionBuffer(buffer.Span, cancellationRegistration: default);
+ if (bytesRead > 0)
+ {
+ return new ValueTask<int>(bytesRead);
+ }
+
+ // We may have just consumed the remainder of the response (with no actual data
+ // available), so check again.
+ if (_connection == null)
+ {
+ Debug.Assert(_state == ParsingState.Done);
+ return new ValueTask<int>(0);
+ }
+
+ // Nothing available to consume. Fall back to I/O.
+ return ReadAsyncCore(buffer, cancellationToken);
+ }
+
+ private async ValueTask<int> ReadAsyncCore(Memory<byte> buffer, CancellationToken cancellationToken)
+ {
+ // Should only be called if ReadChunksFromConnectionBuffer returned 0.
+
+ Debug.Assert(_connection != null);
+ Debug.Assert(buffer.Length > 0);
+
+ CancellationTokenRegistration ctr = _connection.RegisterCancellation(cancellationToken);
+ try
+ {
+ while (true)
+ {
+ if (_connection == null)
+ {
+ // Fully consumed the response in ReadChunksFromConnectionBuffer.
+ return 0;
+ }
+
+ if (_state == ParsingState.ExpectChunkData &&
+ buffer.Length >= _connection.ReadBufferSize &&
+ _chunkBytesRemaining >= (ulong)_connection.ReadBufferSize)
+ {
+ // As an optimization, we skip going through the connection's read buffer if both
+ // the remaining chunk data and the buffer are both at least as large
+ // as the connection buffer. That avoids an unnecessary copy while still reading
+ // the maximum amount we'd otherwise read at a time.
+ Debug.Assert(_connection.RemainingBuffer.Length == 0);
+ int bytesRead = await _connection.ReadAsync(buffer.Slice(0, (int)Math.Min((ulong)buffer.Length, _chunkBytesRemaining))).ConfigureAwait(false);
+ if (bytesRead == 0)
+ {
+ throw new IOException(SR.net_http_invalid_response);
+ }
+ _chunkBytesRemaining -= (ulong)bytesRead;
+ if (_chunkBytesRemaining == 0)
+ {
+ _state = ParsingState.ExpectChunkTerminator;
+ }
+ return bytesRead;
+ }
+
+ // We're only here if we need more data to make forward progress.
+ await _connection.FillAsync();
+
+ // Now that we have more, see if we can get any response data, and if
+ // we can we're done.
+ int bytesCopied = ReadChunksFromConnectionBuffer(buffer.Span, ctr);
+ if (bytesCopied > 0)
+ {
+ return bytesCopied;
+ }
+ }
+ }
+ catch (Exception exc) when (CancellationHelper.ShouldWrapInOperationCanceledException(exc, cancellationToken))
+ {
+ throw CancellationHelper.CreateOperationCanceledException(exc, cancellationToken);
+ }
+ finally
+ {
+ ctr.Dispose();
+ }
+ }
+
+ public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
+ {
+ ValidateCopyToArgs(this, destination, bufferSize);
+
+ return
+ cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) :
+ _connection == null ? Task.CompletedTask :
+ CopyToAsyncCore(destination, cancellationToken);
+ }
+
+ private async Task CopyToAsyncCore(Stream destination, CancellationToken cancellationToken)
+ {
+ CancellationTokenRegistration ctr = _connection.RegisterCancellation(cancellationToken);
+ try
+ {
+ while (true)
+ {
+ while (true)
+ {
+ ReadOnlyMemory<byte> bytesRead = ReadChunkFromConnectionBuffer(int.MaxValue, ctr);
+ if (bytesRead.Length == 0)
+ {
+ break;
+ }
+ await destination.WriteAsync(bytesRead, cancellationToken).ConfigureAwait(false);
+ }
+
+ if (_connection == null)
+ {
+ // Fully consumed the response.
+ return;
+ }
+
+ await _connection.FillAsync().ConfigureAwait(false);
+ }
+ }
+ catch (Exception exc) when (CancellationHelper.ShouldWrapInOperationCanceledException(exc, cancellationToken))
+ {
+ throw CancellationHelper.CreateOperationCanceledException(exc, cancellationToken);
+ }
+ finally
+ {
+ ctr.Dispose();
+ }
+ }
+
+ private int ReadChunksFromConnectionBuffer(Span<byte> buffer, CancellationTokenRegistration cancellationRegistration)
+ {
+ int totalBytesRead = 0;
+ while (buffer.Length > 0)
+ {
+ ReadOnlyMemory<byte> bytesRead = ReadChunkFromConnectionBuffer(buffer.Length, cancellationRegistration);
+ Debug.Assert(bytesRead.Length <= buffer.Length);
+ if (bytesRead.Length == 0)
+ {
+ break;
+ }
+
+ totalBytesRead += bytesRead.Length;
+ bytesRead.Span.CopyTo(buffer);
+ buffer = buffer.Slice(bytesRead.Length);
+ }
+ return totalBytesRead;
+ }
+
+ private ReadOnlyMemory<byte> ReadChunkFromConnectionBuffer(int maxBytesToRead, CancellationTokenRegistration cancellationRegistration)
+ {
+ Debug.Assert(maxBytesToRead > 0);
+
+ try
+ {
+ ReadOnlySpan<byte> currentLine;
+ switch (_state)
+ {
+ case ParsingState.ExpectChunkHeader:
+ Debug.Assert(_chunkBytesRemaining == 0, $"Expected {nameof(_chunkBytesRemaining)} == 0, got {_chunkBytesRemaining}");
+
+ // Read the chunk header line.
+ _connection._allowedReadLineBytes = MaxChunkBytesAllowed;
+ if (!_connection.TryReadNextLine(out currentLine))
+ {
+ // Could not get a whole line, so we can't parse the chunk header.
+ return default;
+ }
+
+ // Parse the hex value from it.
+ if (!Utf8Parser.TryParse(currentLine, out ulong chunkSize, out int bytesConsumed, 'X'))
+ {
+ throw new IOException(SR.net_http_invalid_response);
+ }
+ _chunkBytesRemaining = chunkSize;
+
+ // If there's a chunk extension after the chunk size, validate it.
+ if (bytesConsumed != currentLine.Length)
+ {
+ ValidateChunkExtension(currentLine.Slice(bytesConsumed));
+ }
+
+ // Proceed to handle the chunk. If there's data in it, go read it.
+ // Otherwise, finish handling the response.
+ if (chunkSize > 0)
+ {
+ _state = ParsingState.ExpectChunkData;
+ goto case ParsingState.ExpectChunkData;
+ }
+ else
+ {
+ _state = ParsingState.ConsumeTrailers;
+ goto case ParsingState.ConsumeTrailers;
+ }
+
+ case ParsingState.ExpectChunkData:
+ Debug.Assert(_chunkBytesRemaining > 0);
+
+ ReadOnlyMemory<byte> connectionBuffer = _connection.RemainingBuffer;
+ if (connectionBuffer.Length == 0)
+ {
+ return default;
+ }
+
+ int bytesToConsume = Math.Min(maxBytesToRead, (int)Math.Min((ulong)connectionBuffer.Length, _chunkBytesRemaining));
+ Debug.Assert(bytesToConsume > 0);
+
+ _connection.ConsumeFromRemainingBuffer(bytesToConsume);
+ _chunkBytesRemaining -= (ulong)bytesToConsume;
+ if (_chunkBytesRemaining == 0)
+ {
+ _state = ParsingState.ExpectChunkTerminator;
+ }
+
+ return connectionBuffer.Slice(0, bytesToConsume);
+
+ case ParsingState.ExpectChunkTerminator:
+ Debug.Assert(_chunkBytesRemaining == 0, $"Expected {nameof(_chunkBytesRemaining)} == 0, got {_chunkBytesRemaining}");
+
+ _connection._allowedReadLineBytes = MaxChunkBytesAllowed;
+ if (!_connection.TryReadNextLine(out currentLine))
+ {
+ return default;
+ }
+
+ if (currentLine.Length != 0)
+ {
+ ThrowInvalidHttpResponse();
+ }
+
+ _state = ParsingState.ExpectChunkHeader;
+ goto case ParsingState.ExpectChunkHeader;
+
+ case ParsingState.ConsumeTrailers:
+ Debug.Assert(_chunkBytesRemaining == 0, $"Expected {nameof(_chunkBytesRemaining)} == 0, got {_chunkBytesRemaining}");
+
+ while (true)
+ {
+ _connection._allowedReadLineBytes = MaxTrailingHeaderLength;
+ if (!_connection.TryReadNextLine(out currentLine))
+ {
+ break;
+ }
+
+ if (currentLine.IsEmpty)
+ {
+ // Dispose of the registration and then check whether cancellation has been
+ // requested. This is necessary to make determinstic a race condition between
+ // cancellation being requested and unregistering from the token. Otherwise,
+ // it's possible cancellation could be requested just before we unregister and
+ // we then return a connection to the pool that has been or will be disposed
+ // (e.g. if a timer is used and has already queued its callback but the
+ // callback hasn't yet run).
+ cancellationRegistration.Dispose();
+ CancellationHelper.ThrowIfCancellationRequested(cancellationRegistration.Token);
+
+ _state = ParsingState.Done;
+ _connection.CompleteResponse();
+ _connection = null;
+ break;
+ }
+ }
+
+ return default;
+
+ default:
+ case ParsingState.Done: // shouldn't be called once we're done
+ Debug.Fail($"Unexpected state: {_state}");
+ return default;
+ }
+ }
+ catch (Exception)
+ {
+ // Ensure we don't try to read from the connection again (in particular, for draining)
+ _connection.Dispose();
+ _connection = null;
+ throw;
+ }
+ }
+
+ private static void ValidateChunkExtension(ReadOnlySpan<byte> lineAfterChunkSize)
+ {
+ // Until we see the ';' denoting the extension, the line after the chunk size
+ // must contain only tabs and spaces. After the ';', anything goes.
+ for (int i = 0; i < lineAfterChunkSize.Length; i++)
+ {
+ byte c = lineAfterChunkSize[i];
+ if (c == ';')
+ {
+ break;
+ }
+ else if (c != ' ' && c != '\t') // not called out in the RFC, but WinHTTP allows it
+ {
+ throw new IOException(SR.net_http_invalid_response);
+ }
+ }
+ }
+
+ private enum ParsingState : byte
+ {
+ ExpectChunkHeader,
+ ExpectChunkData,
+ ExpectChunkTerminator,
+ ConsumeTrailers,
+ Done
+ }
+
+ public override bool NeedsDrain => (_connection != null);
+
+ public override async Task<bool> DrainAsync(int maxDrainBytes)
+ {
+ Debug.Assert(_connection != null);
+
+ CancellationTokenSource cts = null;
+ CancellationTokenRegistration ctr = default;
+ try
+ {
+ int drainedBytes = 0;
+ while (true)
+ {
+ drainedBytes += _connection.RemainingBuffer.Length;
+ while (true)
+ {
+ ReadOnlyMemory<byte> bytesRead = ReadChunkFromConnectionBuffer(int.MaxValue, ctr);
+ if (bytesRead.Length == 0)
+ {
+ break;
+ }
+ }
+
+ // When ReadChunkFromConnectionBuffer reads the final chunk, it will clear out _connection
+ // and return the connection to the pool.
+ if (_connection == null)
+ {
+ return true;
+ }
+
+ if (drainedBytes >= maxDrainBytes)
+ {
+ return false;
+ }
+
+ if (cts == null) // only create the drain timer if we have to go async
+ {
+ TimeSpan drainTime = _connection._pool.Settings._maxResponseDrainTime;
+ if (drainTime != Timeout.InfiniteTimeSpan)
+ {
+ cts = new CancellationTokenSource((int)drainTime.TotalMilliseconds);
+ ctr = cts.Token.Register(s => ((HttpConnection)s).Dispose(), _connection);
+ }
+ }
+
+ await _connection.FillAsync().ConfigureAwait(false);
+ }
+ }
+ finally
+ {
+ ctr.Dispose();
+ cts?.Dispose();
+ }
+ }
+ }
+ }
+}
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ChunkedEncodingWriteStream.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ChunkedEncodingWriteStream.cs
new file mode 100644
index 0000000000..54bb5cfc4c
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ChunkedEncodingWriteStream.cs
@@ -0,0 +1,57 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Net.Http
+{
+ internal partial class HttpConnection : IDisposable
+ {
+ private sealed class ChunkedEncodingWriteStream : HttpContentWriteStream
+ {
+ private static readonly byte[] s_finalChunkBytes = { (byte)'0', (byte)'\r', (byte)'\n', (byte)'\r', (byte)'\n' };
+
+ public ChunkedEncodingWriteStream(HttpConnection connection) : base(connection)
+ {
+ }
+
+ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken ignored)
+ {
+ Debug.Assert(_connection._currentRequest != null);
+
+ // The token is ignored because it's coming from SendAsync and the only operations
+ // here are those that are already covered by the token having been registered with
+ // to close the connection.
+
+ ValueTask task = buffer.Length == 0 ?
+ // Don't write if nothing was given, especially since we don't want to accidentally send a 0 chunk,
+ // which would indicate end of body. Instead, just ensure no content is stuck in the buffer.
+ _connection.FlushAsync() :
+ new ValueTask(WriteChunkAsync(buffer));
+
+ return task;
+ }
+
+ private async Task WriteChunkAsync(ReadOnlyMemory<byte> buffer)
+ {
+ // Write chunk length in hex followed by \r\n
+ await _connection.WriteHexInt32Async(buffer.Length).ConfigureAwait(false);
+ await _connection.WriteTwoBytesAsync((byte)'\r', (byte)'\n').ConfigureAwait(false);
+
+ // Write chunk contents followed by \r\n
+ await _connection.WriteAsync(buffer).ConfigureAwait(false);
+ await _connection.WriteTwoBytesAsync((byte)'\r', (byte)'\n').ConfigureAwait(false);
+ }
+
+ public override async Task FinishAsync()
+ {
+ // Send 0 byte chunk to indicate end, then final CrLf
+ await _connection.WriteBytesAsync(s_finalChunkBytes).ConfigureAwait(false);
+ _connection = null;
+ }
+ }
+ }
+}
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs
new file mode 100644
index 0000000000..c2df52fdb3
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs
@@ -0,0 +1,174 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.IO;
+using System.Net.Security;
+using System.Net.Sockets;
+using System.Runtime.CompilerServices;
+using System.Security.Cryptography.X509Certificates;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Net.Http
+{
+ internal static class ConnectHelper
+ {
+ /// <summary>
+ /// Helper type used by HttpClientHandler when wrapping SocketsHttpHandler to map its
+ /// certificate validation callback to the one used by SslStream.
+ /// </summary>
+ internal sealed class CertificateCallbackMapper
+ {
+ public readonly Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> FromHttpClientHandler;
+ public readonly RemoteCertificateValidationCallback ForSocketsHttpHandler;
+
+ public CertificateCallbackMapper(Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> fromHttpClientHandler)
+ {
+ FromHttpClientHandler = fromHttpClientHandler;
+ ForSocketsHttpHandler = (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) =>
+ FromHttpClientHandler(sender as HttpRequestMessage, certificate as X509Certificate2, chain, sslPolicyErrors);
+ }
+ }
+
+ public static async ValueTask<(Socket, Stream)> ConnectAsync(string host, int port, CancellationToken cancellationToken)
+ {
+ try
+ {
+ // Rather than creating a new Socket and calling ConnectAsync on it, we use the static
+ // Socket.ConnectAsync with a SocketAsyncEventArgs, as we can then use Socket.CancelConnectAsync
+ // to cancel it if needed.
+ using (var saea = new BuilderAndCancellationTokenSocketAsyncEventArgs(cancellationToken))
+ {
+ // Configure which server to which to connect.
+ saea.RemoteEndPoint = IPAddress.TryParse(host, out IPAddress address) ?
+ (EndPoint)new IPEndPoint(address, port) :
+ new DnsEndPoint(host, port);
+
+ // Hook up a callback that'll complete the Task when the operation completes.
+ saea.Completed += (s, e) =>
+ {
+ var csaea = (BuilderAndCancellationTokenSocketAsyncEventArgs)e;
+ switch (e.SocketError)
+ {
+ case SocketError.Success:
+ csaea.Builder.SetResult();
+ break;
+ case SocketError.OperationAborted:
+ case SocketError.ConnectionAborted:
+ if (csaea.CancellationToken.IsCancellationRequested)
+ {
+ csaea.Builder.SetException(CancellationHelper.CreateOperationCanceledException(null, csaea.CancellationToken));
+ break;
+ }
+ goto default;
+ default:
+ csaea.Builder.SetException(new SocketException((int)e.SocketError));
+ break;
+ }
+ };
+
+ // Initiate the connection.
+ if (Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, saea))
+ {
+ // Connect completing asynchronously. Enable it to be canceled and wait for it.
+ using (cancellationToken.Register(s => Socket.CancelConnectAsync((SocketAsyncEventArgs)s), saea))
+ {
+ await saea.Builder.Task.ConfigureAwait(false);
+ }
+ }
+ else if (saea.SocketError != SocketError.Success)
+ {
+ // Connect completed synchronously but unsuccessfully.
+ throw new SocketException((int)saea.SocketError);
+ }
+
+ Debug.Assert(saea.SocketError == SocketError.Success, $"Expected Success, got {saea.SocketError}.");
+ Debug.Assert(saea.ConnectSocket != null, "Expected non-null socket");
+
+ // Configure the socket and return a stream for it.
+ Socket socket = saea.ConnectSocket;
+ socket.NoDelay = true;
+ return (socket, new NetworkStream(socket, ownsSocket: true));
+ }
+ }
+ catch (Exception error)
+ {
+ throw CancellationHelper.ShouldWrapInOperationCanceledException(error, cancellationToken) ?
+ CancellationHelper.CreateOperationCanceledException(error, cancellationToken) :
+ new HttpRequestException(error.Message, error);
+ }
+ }
+
+ /// <summary>SocketAsyncEventArgs that carries with it additional state for a Task builder and a CancellationToken.</summary>
+ private sealed class BuilderAndCancellationTokenSocketAsyncEventArgs : SocketAsyncEventArgs
+ {
+ public AsyncTaskMethodBuilder Builder { get; }
+ public CancellationToken CancellationToken { get; }
+
+ public BuilderAndCancellationTokenSocketAsyncEventArgs(CancellationToken cancellationToken)
+ {
+ var b = new AsyncTaskMethodBuilder();
+ var ignored = b.Task; // force initialization
+ Builder = b;
+
+ CancellationToken = cancellationToken;
+ }
+ }
+
+ public static ValueTask<SslStream> EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, Stream stream, CancellationToken cancellationToken)
+ {
+ // If there's a cert validation callback, and if it came from HttpClientHandler,
+ // wrap the original delegate in order to change the sender to be the request message (expected by HttpClientHandler's delegate).
+ RemoteCertificateValidationCallback callback = sslOptions.RemoteCertificateValidationCallback;
+ if (callback != null && callback.Target is CertificateCallbackMapper mapper)
+ {
+ sslOptions = sslOptions.ShallowClone(); // Clone as we're about to mutate it and don't want to affect the cached copy
+ Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> localFromHttpClientHandler = mapper.FromHttpClientHandler;
+ HttpRequestMessage localRequest = request;
+ sslOptions.RemoteCertificateValidationCallback = (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) =>
+ localFromHttpClientHandler(localRequest, certificate as X509Certificate2, chain, sslPolicyErrors);
+ }
+
+ // Create the SslStream, authenticate, and return it.
+ return EstablishSslConnectionAsyncCore(stream, sslOptions, cancellationToken);
+ }
+
+ private static async ValueTask<SslStream> EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
+ {
+ SslStream sslStream = new SslStream(stream);
+
+ // TODO #25206 and #24430: Register/IsCancellationRequested should be removable once SslStream auth and sockets respect cancellation.
+ CancellationTokenRegistration ctr = cancellationToken.Register(s => ((Stream)s).Dispose(), stream);
+ try
+ {
+ await sslStream.AuthenticateAsClientAsync(sslOptions, cancellationToken).ConfigureAwait(false);
+ }
+ catch (Exception e)
+ {
+ sslStream.Dispose();
+
+ if (CancellationHelper.ShouldWrapInOperationCanceledException(e, cancellationToken))
+ {
+ throw CancellationHelper.CreateOperationCanceledException(e, cancellationToken);
+ }
+
+ throw new HttpRequestException(SR.net_http_ssl_connection_failed, e);
+ }
+ finally
+ {
+ ctr.Dispose();
+ }
+
+ // Handle race condition if cancellation happens after SSL auth completes but before the registration is disposed
+ if (cancellationToken.IsCancellationRequested)
+ {
+ sslStream.Dispose();
+ throw CancellationHelper.CreateOperationCanceledException(null, cancellationToken);
+ }
+
+ return sslStream;
+ }
+ }
+}
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionCloseReadStream.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionCloseReadStream.cs
new file mode 100644
index 0000000000..1506cdf2b8
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectionCloseReadStream.cs
@@ -0,0 +1,129 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Net.Http
+{
+ internal partial class HttpConnection : IDisposable
+ {
+ private sealed class ConnectionCloseReadStream : HttpContentReadStream
+ {
+ public ConnectionCloseReadStream(HttpConnection connection) : base(connection)
+ {
+ }
+
+ public override async ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken)
+ {
+ CancellationHelper.ThrowIfCancellationRequested(cancellationToken);
+
+ if (_connection == null || buffer.Length == 0)
+ {
+ // Response body fully consumed or the caller didn't ask for any data
+ return 0;
+ }
+
+ ValueTask<int> readTask = _connection.ReadAsync(buffer);
+ int bytesRead;
+ if (readTask.IsCompletedSuccessfully)
+ {
+ bytesRead = readTask.Result;
+ }
+ else
+ {
+ CancellationTokenRegistration ctr = _connection.RegisterCancellation(cancellationToken);
+ try
+ {
+ bytesRead = await readTask.ConfigureAwait(false);
+ }
+ catch (Exception exc) when (CancellationHelper.ShouldWrapInOperationCanceledException(exc, cancellationToken))
+ {
+ throw CancellationHelper.CreateOperationCanceledException(exc, cancellationToken);
+ }
+ finally
+ {
+ ctr.Dispose();
+ }
+ }
+
+ if (bytesRead == 0)
+ {
+ // If cancellation is requested and tears down the connection, it could cause the read
+ // to return 0, which would otherwise signal the end of the data, but that would lead
+ // the caller to think that it actually received all of the data, rather than it ending
+ // early due to cancellation. So we prioritize cancellation in this race condition, and
+ // if we read 0 bytes and then find that cancellation has requested, we assume cancellation
+ // was the cause and throw.
+ CancellationHelper.ThrowIfCancellationRequested(cancellationToken);
+
+ // We cannot reuse this connection, so close it.
+ _connection.Dispose();
+ _connection = null;
+ return 0;
+ }
+
+ return bytesRead;
+ }
+
+ public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
+ {
+ ValidateCopyToArgs(this, destination, bufferSize);
+
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return Task.FromCanceled(cancellationToken);
+ }
+
+ if (_connection == null)
+ {
+ // null if response body fully consumed
+ return Task.CompletedTask;
+ }
+
+ Task copyTask = _connection.CopyToUntilEofAsync(destination, bufferSize, cancellationToken);
+ if (copyTask.IsCompletedSuccessfully)
+ {
+ Finish();
+ return Task.CompletedTask;
+ }
+
+ return CompleteCopyToAsync(copyTask, cancellationToken);
+ }
+
+ private async Task CompleteCopyToAsync(Task copyTask, CancellationToken cancellationToken)
+ {
+ CancellationTokenRegistration ctr = _connection.RegisterCancellation(cancellationToken);
+ try
+ {
+ await copyTask.ConfigureAwait(false);
+ }
+ catch (Exception exc) when (CancellationHelper.ShouldWrapInOperationCanceledException(exc, cancellationToken))
+ {
+ throw CancellationHelper.CreateOperationCanceledException(exc, cancellationToken);
+ }
+ finally
+ {
+ ctr.Dispose();
+ }
+
+ // If cancellation is requested and tears down the connection, it could cause the copy
+ // to end early but think it ended successfully. So we prioritize cancellation in this
+ // race condition, and if we find after the copy has completed that cancellation has
+ // been requested, we assume the copy completed due to cancellation and throw.
+ CancellationHelper.ThrowIfCancellationRequested(cancellationToken);
+
+ Finish();
+ }
+
+ private void Finish()
+ {
+ // We cannot reuse this connection, so close it.
+ _connection.Dispose();
+ _connection = null;
+ }
+ }
+ }
+}
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ContentLengthReadStream.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ContentLengthReadStream.cs
new file mode 100644
index 0000000000..cbf51b0424
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ContentLengthReadStream.cs
@@ -0,0 +1,216 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Net.Http
+{
+ internal partial class HttpConnection : IDisposable
+ {
+ private sealed class ContentLengthReadStream : HttpContentReadStream
+ {
+ private ulong _contentBytesRemaining;
+
+ public ContentLengthReadStream(HttpConnection connection, ulong contentLength) : base(connection)
+ {
+ Debug.Assert(contentLength > 0, "Caller should have checked for 0.");
+ _contentBytesRemaining = contentLength;
+ }
+
+ public override async ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken)
+ {
+ CancellationHelper.ThrowIfCancellationRequested(cancellationToken);
+
+ if (_connection == null || buffer.Length == 0)
+ {
+ // Response body fully consumed or the caller didn't ask for any data
+ return 0;
+ }
+
+ Debug.Assert(_contentBytesRemaining > 0);
+
+ if ((ulong)buffer.Length > _contentBytesRemaining)
+ {
+ buffer = buffer.Slice(0, (int)_contentBytesRemaining);
+ }
+
+ ValueTask<int> readTask = _connection.ReadAsync(buffer);
+ int bytesRead;
+ if (readTask.IsCompletedSuccessfully)
+ {
+ bytesRead = readTask.Result;
+ }
+ else
+ {
+ CancellationTokenRegistration ctr = _connection.RegisterCancellation(cancellationToken);
+ try
+ {
+ bytesRead = await readTask.ConfigureAwait(false);
+ }
+ catch (Exception exc) when (CancellationHelper.ShouldWrapInOperationCanceledException(exc, cancellationToken))
+ {
+ throw CancellationHelper.CreateOperationCanceledException(exc, cancellationToken);
+ }
+ finally
+ {
+ ctr.Dispose();
+ }
+ }
+
+ if (bytesRead <= 0)
+ {
+ // A cancellation request may have caused the EOF.
+ CancellationHelper.ThrowIfCancellationRequested(cancellationToken);
+
+ // Unexpected end of response stream.
+ throw new IOException(SR.net_http_invalid_response);
+ }
+
+ Debug.Assert((ulong)bytesRead <= _contentBytesRemaining);
+ _contentBytesRemaining -= (ulong)bytesRead;
+
+ if (_contentBytesRemaining == 0)
+ {
+ // End of response body
+ _connection.CompleteResponse();
+ _connection = null;
+ }
+
+ return bytesRead;
+ }
+
+ public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
+ {
+ ValidateCopyToArgs(this, destination, bufferSize);
+
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return Task.FromCanceled(cancellationToken);
+ }
+
+ if (_connection == null)
+ {
+ // null if response body fully consumed
+ return Task.CompletedTask;
+ }
+
+ Task copyTask = _connection.CopyToExactLengthAsync(destination, _contentBytesRemaining, cancellationToken);
+ if (copyTask.IsCompletedSuccessfully)
+ {
+ Finish();
+ return Task.CompletedTask;
+ }
+
+ return CompleteCopyToAsync(copyTask, cancellationToken);
+ }
+
+ private async Task CompleteCopyToAsync(Task copyTask, CancellationToken cancellationToken)
+ {
+ CancellationTokenRegistration ctr = _connection.RegisterCancellation(cancellationToken);
+ try
+ {
+ await copyTask.ConfigureAwait(false);
+ }
+ catch (Exception exc) when (CancellationHelper.ShouldWrapInOperationCanceledException(exc, cancellationToken))
+ {
+ throw CancellationHelper.CreateOperationCanceledException(exc, cancellationToken);
+ }
+ finally
+ {
+ ctr.Dispose();
+ }
+
+ Finish();
+ }
+
+ private void Finish()
+ {
+ _contentBytesRemaining = 0;
+ _connection.CompleteResponse();
+ _connection = null;
+ }
+
+ // Based on ReadChunkFromConnectionBuffer; perhaps we should refactor into a common routine.
+ private ReadOnlyMemory<byte> ReadFromConnectionBuffer(int maxBytesToRead)
+ {
+ Debug.Assert(maxBytesToRead > 0);
+ Debug.Assert(_contentBytesRemaining > 0);
+
+ ReadOnlyMemory<byte> connectionBuffer = _connection.RemainingBuffer;
+ if (connectionBuffer.Length == 0)
+ {
+ return default;
+ }
+
+ int bytesToConsume = Math.Min(maxBytesToRead, (int)Math.Min((ulong)connectionBuffer.Length, _contentBytesRemaining));
+ Debug.Assert(bytesToConsume > 0);
+
+ _connection.ConsumeFromRemainingBuffer(bytesToConsume);
+ _contentBytesRemaining -= (ulong)bytesToConsume;
+
+ return connectionBuffer.Slice(0, bytesToConsume);
+ }
+
+ public override bool NeedsDrain => (_connection != null);
+
+ public override async Task<bool> DrainAsync(int maxDrainBytes)
+ {
+ Debug.Assert(_connection != null);
+ Debug.Assert(_contentBytesRemaining > 0);
+
+ ReadFromConnectionBuffer(int.MaxValue);
+ if (_contentBytesRemaining == 0)
+ {
+ Finish();
+ return true;
+ }
+
+ if (_contentBytesRemaining > (ulong)maxDrainBytes)
+ {
+ return false;
+ }
+
+ CancellationTokenSource cts = null;
+ CancellationTokenRegistration ctr = default;
+ TimeSpan drainTime = _connection._pool.Settings._maxResponseDrainTime;
+ if (drainTime != Timeout.InfiniteTimeSpan)
+ {
+ cts = new CancellationTokenSource((int)drainTime.TotalMilliseconds);
+ ctr = cts.Token.Register(s => ((HttpConnection)s).Dispose(), _connection);
+ }
+ try
+ {
+ while (true)
+ {
+ await _connection.FillAsync().ConfigureAwait(false);
+ ReadFromConnectionBuffer(int.MaxValue);
+ if (_contentBytesRemaining == 0)
+ {
+ // Dispose of the registration and then check whether cancellation has been
+ // requested. This is necessary to make determinstic a race condition between
+ // cancellation being requested and unregistering from the token. Otherwise,
+ // it's possible cancellation could be requested just before we unregister and
+ // we then return a connection to the pool that has been or will be disposed
+ // (e.g. if a timer is used and has already queued its callback but the
+ // callback hasn't yet run).
+ ctr.Dispose();
+ CancellationHelper.ThrowIfCancellationRequested(ctr.Token);
+
+ Finish();
+ return true;
+ }
+ }
+ }
+ finally
+ {
+ ctr.Dispose();
+ cts?.Dispose();
+ }
+ }
+ }
+ }
+}
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ContentLengthWriteStream.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ContentLengthWriteStream.cs
new file mode 100644
index 0000000000..3c79ead168
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ContentLengthWriteStream.cs
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Net.Http
+{
+ internal partial class HttpConnection : IDisposable
+ {
+ private sealed class ContentLengthWriteStream : HttpContentWriteStream
+ {
+ public ContentLengthWriteStream(HttpConnection connection) : base(connection)
+ {
+ }
+
+ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken ignored) // token ignored as it comes from SendAsync
+ {
+ Debug.Assert(_connection._currentRequest != null);
+
+ // Have the connection write the data, skipping the buffer. Importantly, this will
+ // force a flush of anything already in the buffer, i.e. any remaining request headers
+ // that are still buffered.
+ return new ValueTask(_connection.WriteAsync(buffer));
+ }
+
+ public override Task FinishAsync()
+ {
+ _connection = null;
+ return Task.CompletedTask;
+ }
+ }
+ }
+}
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/CookieHelper.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/CookieHelper.cs
new file mode 100644
index 0000000000..2d60062b10
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/CookieHelper.cs
@@ -0,0 +1,41 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Net.Http.Headers;
+using System.Diagnostics;
+using System.Collections.Generic;
+
+namespace System.Net.Http
+{
+ internal static class CookieHelper
+ {
+ public static void ProcessReceivedCookies(HttpResponseMessage response, CookieContainer cookieContainer)
+ {
+ IEnumerable<string> values;
+ if (response.Headers.TryGetValues(KnownHeaders.SetCookie.Descriptor, out values))
+ {
+ // The header values are always a string[]
+ var valuesArray = (string[])values;
+ Debug.Assert(valuesArray.Length > 0, "No values for header??");
+
+ Uri requestUri = response.RequestMessage.RequestUri;
+ for (int i = 0; i < valuesArray.Length; i++)
+ {
+ try
+ {
+ cookieContainer.SetCookies(requestUri, valuesArray[i]);
+ }
+ catch (CookieException)
+ {
+ // Ignore invalid Set-Cookie header and continue processing.
+ if (NetEventSource.IsEnabled)
+ {
+ NetEventSource.Info(response, $"Invalid Set-Cookie '{valuesArray[i]}' ignored.");
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/DecompressionHandler.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/DecompressionHandler.cs
index 261ae26af7..cbfb0b97a8 100644
--- a/src/System.Net.Http/src/System/Net/Http/Managed/DecompressionHandler.cs
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/DecompressionHandler.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
+using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Net.Http.Headers;
@@ -18,17 +19,16 @@ namespace System.Net.Http
private const string s_gzip = "gzip";
private const string s_deflate = "deflate";
- private static StringWithQualityHeaderValue s_gzipHeaderValue = new StringWithQualityHeaderValue(s_gzip);
- private static StringWithQualityHeaderValue s_deflateHeaderValue = new StringWithQualityHeaderValue(s_deflate);
+ private static readonly StringWithQualityHeaderValue s_gzipHeaderValue = new StringWithQualityHeaderValue(s_gzip);
+ private static readonly StringWithQualityHeaderValue s_deflateHeaderValue = new StringWithQualityHeaderValue(s_deflate);
public DecompressionHandler(DecompressionMethods decompressionMethods, HttpMessageHandler innerHandler)
{
- _innerHandler = innerHandler ?? throw new ArgumentNullException(nameof(innerHandler));
- if (decompressionMethods == DecompressionMethods.None)
- {
- throw new ArgumentOutOfRangeException(nameof(decompressionMethods));
- }
+ Debug.Assert(decompressionMethods != DecompressionMethods.None);
+ Debug.Assert(innerHandler != null);
+
_decompressionMethods = decompressionMethods;
+ _innerHandler = innerHandler;
}
internal bool GZipEnabled => (_decompressionMethods & DecompressionMethods.GZip) != 0;
@@ -108,11 +108,14 @@ namespace System.Net.Http
protected abstract Stream GetDecompressedStream(Stream originalStream);
- protected override async Task SerializeToStreamAsync(Stream stream, TransportContext context)
+ protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) =>
+ SerializeToStreamAsync(stream, context, CancellationToken.None);
+
+ internal override async Task SerializeToStreamAsync(Stream stream, TransportContext context, CancellationToken cancellationToken)
{
using (Stream decompressedStream = await CreateContentReadStreamAsync().ConfigureAwait(false))
{
- await decompressedStream.CopyToAsync(stream).ConfigureAwait(false);
+ await decompressedStream.CopyToAsync(stream, cancellationToken).ConfigureAwait(false);
}
}
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/EmptyReadStream.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/EmptyReadStream.cs
index 2de314374d..f965c92add 100644
--- a/src/System.Net.Http/src/System/Net/Http/Managed/EmptyReadStream.cs
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/EmptyReadStream.cs
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace System.Net.Http
{
- internal sealed partial class HttpConnection : IDisposable
+ internal partial class HttpConnection : IDisposable
{
private sealed class EmptyReadStream : HttpContentReadStream
{
@@ -20,13 +20,12 @@ namespace System.Net.Http
protected override void Dispose(bool disposing) { /* nop */ }
public override void Close() { /* nop */ }
- public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
- {
- ValidateBufferArgs(buffer, offset, count);
- return s_zeroTask;
- }
+ public override int ReadByte() => -1;
- public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken = default) =>
+ public override int Read(Span<byte> buffer) => 0;
+
+ public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken) =>
+ cancellationToken.IsCancellationRequested ? new ValueTask<int>(Task.FromCanceled<int>(cancellationToken)) :
new ValueTask<int>(0);
}
}
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpAuthenticatedConnectionHandler.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpAuthenticatedConnectionHandler.cs
new file mode 100644
index 0000000000..eb0eb3d959
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpAuthenticatedConnectionHandler.cs
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Net.Http
+{
+ internal sealed class HttpAuthenticatedConnectionHandler : HttpMessageHandler
+ {
+ private readonly HttpConnectionPoolManager _poolManager;
+
+ public HttpAuthenticatedConnectionHandler(HttpConnectionPoolManager poolManager)
+ {
+ _poolManager = poolManager;
+ }
+
+ protected internal override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ return _poolManager.SendAsync(request, doRequestAuth:true, cancellationToken);
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _poolManager.Dispose();
+ }
+
+ base.Dispose(disposing);
+ }
+ }
+
+}
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs
new file mode 100644
index 0000000000..93e2b2f4a5
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs
@@ -0,0 +1,1559 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers.Text;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Net.Http.Headers;
+using System.Net.Security;
+using System.Net.Sockets;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Net.Http
+{
+ internal partial class HttpConnection : IDisposable
+ {
+ /// <summary>Default size of the read buffer used for the connection.</summary>
+ private const int InitialReadBufferSize =
+#if DEBUG
+ 10;
+#else
+ 4096;
+#endif
+ /// <summary>Default size of the write buffer used for the connection.</summary>
+ private const int InitialWriteBufferSize = InitialReadBufferSize;
+ /// <summary>
+ /// Size after which we'll close the connection rather than send the payload in response
+ /// to final error status code sent by the server when using Expect: 100-continue.
+ /// </summary>
+ private const int Expect100ErrorSendThreshold = 1024;
+
+ private static readonly byte[] s_contentLength0NewlineAsciiBytes = Encoding.ASCII.GetBytes("Content-Length: 0\r\n");
+ private static readonly byte[] s_spaceHttp10NewlineAsciiBytes = Encoding.ASCII.GetBytes(" HTTP/1.0\r\n");
+ private static readonly byte[] s_spaceHttp11NewlineAsciiBytes = Encoding.ASCII.GetBytes(" HTTP/1.1\r\n");
+ private static readonly byte[] s_httpSchemeAndDelimiter = Encoding.ASCII.GetBytes(Uri.UriSchemeHttp + Uri.SchemeDelimiter);
+ private static readonly byte[] s_http1DotBytes = Encoding.ASCII.GetBytes("HTTP/1.");
+ private static readonly ulong s_http10Bytes = BitConverter.ToUInt64(Encoding.ASCII.GetBytes("HTTP/1.0"));
+ private static readonly ulong s_http11Bytes = BitConverter.ToUInt64(Encoding.ASCII.GetBytes("HTTP/1.1"));
+
+ private readonly HttpConnectionPool _pool;
+ private readonly Socket _socket; // used for polling; _stream should be used for all reading/writing. _stream owns disposal.
+ private readonly Stream _stream;
+ private readonly TransportContext _transportContext;
+ private readonly bool _usingProxy;
+ private readonly WeakReference<HttpConnection> _weakThisRef;
+
+ private HttpRequestMessage _currentRequest;
+ private readonly byte[] _writeBuffer;
+ private int _writeOffset;
+ private int _allowedReadLineBytes;
+
+ private ValueTask<int>? _readAheadTask;
+ private byte[] _readBuffer;
+ private int _readOffset;
+ private int _readLength;
+
+ private bool _inUse;
+ private bool _canRetry;
+ private bool _connectionClose; // Connection: close was seen on last response
+ private int _disposed; // 1 yes, 0 no
+
+ public HttpConnection(
+ HttpConnectionPool pool,
+ Socket socket,
+ Stream stream,
+ TransportContext transportContext)
+ {
+ Debug.Assert(pool != null);
+ Debug.Assert(stream != null);
+
+ _pool = pool;
+ _socket = socket; // may be null in cases where we couldn't easily get the underlying socket
+ _stream = stream;
+ _transportContext = transportContext;
+ _usingProxy = pool.UsingProxy;
+
+ _writeBuffer = new byte[InitialWriteBufferSize];
+ _readBuffer = new byte[InitialReadBufferSize];
+
+ _weakThisRef = new WeakReference<HttpConnection>(this);
+
+ if (NetEventSource.IsEnabled)
+ {
+ if (pool.IsSecure)
+ {
+ var sslStream = (SslStream)_stream;
+ Trace(
+ $"Secure connection created to {pool}. " +
+ $"SslProtocol:{sslStream.SslProtocol}, " +
+ $"CipherAlgorithm:{sslStream.CipherAlgorithm}, CipherStrength:{sslStream.CipherStrength}, " +
+ $"HashAlgorithm:{sslStream.HashAlgorithm}, HashStrength:{sslStream.HashStrength}, " +
+ $"KeyExchangeAlgorithm:{sslStream.KeyExchangeAlgorithm}, KeyExchangeStrength:{sslStream.KeyExchangeStrength}, " +
+ $"LocalCert:{sslStream.LocalCertificate}, RemoteCert:{sslStream.RemoteCertificate}");
+ }
+ else
+ {
+ Trace($"Connection created to {pool}.");
+ }
+ }
+ }
+
+ public void Dispose() => Dispose(disposing: true);
+
+ protected void Dispose(bool disposing)
+ {
+ // Ensure we're only disposed once. Dispose could be called concurrently, for example,
+ // if the request and the response were running concurrently and both incurred an exception.
+ if (Interlocked.Exchange(ref _disposed, 1) == 0)
+ {
+ if (NetEventSource.IsEnabled) Trace("Connection closing.");
+ _pool.DecrementConnectionCount();
+ if (disposing)
+ {
+ GC.SuppressFinalize(this);
+ _stream.Dispose();
+
+ // Eat any exceptions from the read-ahead task. We don't need to log, as we expect
+ // failures from this task due to closing the connection while a read is in progress.
+ if (_readAheadTask != null)
+ {
+ ValueTask<int> t = _readAheadTask.GetValueOrDefault();
+ if (t.IsCompleted)
+ {
+ if (!t.IsCompletedSuccessfully)
+ {
+ Exception ignored = t.AsTask().Exception; // accessing Exception prop is sufficient to suppress unobserved exception events
+ }
+ }
+ else
+ {
+ t.AsTask().ContinueWith(p =>
+ {
+ Exception ignored = p.Exception;
+ }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
+ }
+ }
+ }
+ }
+ }
+
+ /// <summary>Do a non-blocking poll to see whether the connection has data available or has been closed.</summary>
+ /// <remarks>If we don't have direct access to the underlying socket, we instead use a read-ahead task.</remarks>
+ public bool PollRead() => _socket != null ?
+ _socket.Poll(0, SelectMode.SelectRead) :
+ EnsureReadAheadAndPollRead();
+
+ /// <summary>
+ /// Issues a read-ahead on the connection, which will serve both as the first read on the
+ /// response as well as a polling indication of whether the connection is usable.
+ /// </summary>
+ /// <returns>true if there's data available on the connection or it's been closed; otherwise, false.</returns>
+ public bool EnsureReadAheadAndPollRead()
+ {
+ try
+ {
+ Debug.Assert(_readAheadTask == null || _socket == null, "Should only already have a read-ahead task if we don't have a socket to poll");
+ if (_readAheadTask == null)
+ {
+ _readAheadTask = _stream.ReadAsync(new Memory<byte>(_readBuffer));
+ }
+ }
+ catch (Exception error)
+ {
+ // If reading throws, eat the error and don't pool the connection.
+ if (NetEventSource.IsEnabled) Trace($"Error performing read ahead: {error}");
+ Dispose();
+ _readAheadTask = new ValueTask<int>(0);
+ }
+
+ return _readAheadTask.Value.IsCompleted; // equivalent to polling
+ }
+
+ public bool IsNewConnection
+ {
+ get
+ {
+ // This is only valid when we are not actually processing a request.
+ Debug.Assert(_currentRequest == null);
+ return (_readAheadTask == null);
+ }
+ }
+
+ public bool CanRetry
+ {
+ get
+ {
+ // Should only be called when we have been disposed.
+ Debug.Assert(_disposed != 0);
+ return _canRetry;
+ }
+ }
+
+ public DateTimeOffset CreationTime { get; } = DateTimeOffset.UtcNow;
+
+ public TransportContext TransportContext => _transportContext;
+
+ public bool UsingProxy => _usingProxy;
+
+ private int ReadBufferSize => _readBuffer.Length;
+
+ private ReadOnlyMemory<byte> RemainingBuffer => new ReadOnlyMemory<byte>(_readBuffer, _readOffset, _readLength - _readOffset);
+
+ private void ConsumeFromRemainingBuffer(int bytesToConsume)
+ {
+ Debug.Assert(bytesToConsume <= _readLength - _readOffset, $"{bytesToConsume} > {_readLength} - {_readOffset}");
+ _readOffset += bytesToConsume;
+ }
+
+ private async Task WriteHeadersAsync(HttpHeaders headers, string cookiesFromContainer)
+ {
+ foreach (KeyValuePair<HeaderDescriptor, string[]> header in headers.GetHeaderDescriptorsAndValues())
+ {
+ if (header.Key.KnownHeader != null)
+ {
+ await WriteBytesAsync(header.Key.KnownHeader.AsciiBytesWithColonSpace).ConfigureAwait(false);
+ }
+ else
+ {
+ await WriteAsciiStringAsync(header.Key.Name).ConfigureAwait(false);
+ await WriteTwoBytesAsync((byte)':', (byte)' ').ConfigureAwait(false);
+ }
+
+ Debug.Assert(header.Value.Length > 0, "No values for header??");
+ if (header.Value.Length > 0)
+ {
+ await WriteStringAsync(header.Value[0]).ConfigureAwait(false);
+
+ if (cookiesFromContainer != null && header.Key.KnownHeader == KnownHeaders.Cookie)
+ {
+ await WriteTwoBytesAsync((byte)';', (byte)' ').ConfigureAwait(false);
+ await WriteStringAsync(cookiesFromContainer).ConfigureAwait(false);
+
+ cookiesFromContainer = null;
+ }
+
+ for (int i = 1; i < header.Value.Length; i++)
+ {
+ await WriteTwoBytesAsync((byte)',', (byte)' ').ConfigureAwait(false);
+ await WriteStringAsync(header.Value[i]).ConfigureAwait(false);
+ }
+ }
+
+ await WriteTwoBytesAsync((byte)'\r', (byte)'\n').ConfigureAwait(false);
+ }
+
+ if (cookiesFromContainer != null)
+ {
+ await WriteAsciiStringAsync(HttpKnownHeaderNames.Cookie).ConfigureAwait(false);
+ await WriteTwoBytesAsync((byte)':', (byte)' ').ConfigureAwait(false);
+ await WriteAsciiStringAsync(cookiesFromContainer).ConfigureAwait(false);
+ await WriteTwoBytesAsync((byte)'\r', (byte)'\n').ConfigureAwait(false);
+ }
+ }
+
+ private async Task WriteHostHeaderAsync(Uri uri)
+ {
+ await WriteBytesAsync(KnownHeaders.Host.AsciiBytesWithColonSpace).ConfigureAwait(false);
+
+ if (_pool.HostHeaderValueBytes != null)
+ {
+ Debug.Assert(!_pool.UsingProxy);
+ await WriteBytesAsync(_pool.HostHeaderValueBytes).ConfigureAwait(false);
+ }
+ else
+ {
+ Debug.Assert(_pool.UsingProxy);
+ await WriteAsciiStringAsync(uri.IdnHost).ConfigureAwait(false);
+
+ if (!uri.IsDefaultPort)
+ {
+ await WriteByteAsync((byte)':').ConfigureAwait(false);
+ await WriteDecimalInt32Async(uri.Port).ConfigureAwait(false);
+ }
+ }
+
+ await WriteTwoBytesAsync((byte)'\r', (byte)'\n').ConfigureAwait(false);
+ }
+
+ private Task WriteDecimalInt32Async(int value)
+ {
+ // Try to format into our output buffer directly.
+ if (Utf8Formatter.TryFormat(value, new Span<byte>(_writeBuffer, _writeOffset, _writeBuffer.Length - _writeOffset), out int bytesWritten))
+ {
+ _writeOffset += bytesWritten;
+ return Task.CompletedTask;
+ }
+
+ // If we don't have enough room, do it the slow way.
+ return WriteAsciiStringAsync(value.ToString());
+ }
+
+ private Task WriteHexInt32Async(int value)
+ {
+ // Try to format into our output buffer directly.
+ if (Utf8Formatter.TryFormat(value, new Span<byte>(_writeBuffer, _writeOffset, _writeBuffer.Length - _writeOffset), out int bytesWritten, 'X'))
+ {
+ _writeOffset += bytesWritten;
+ return Task.CompletedTask;
+ }
+
+ // If we don't have enough room, do it the slow way.
+ return WriteAsciiStringAsync(value.ToString("X", CultureInfo.InvariantCulture));
+ }
+
+ public async Task<HttpResponseMessage> SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ TaskCompletionSource<bool> allowExpect100ToContinue = null;
+ Debug.Assert(_currentRequest == null, $"Expected null {nameof(_currentRequest)}.");
+ Debug.Assert(RemainingBuffer.Length == 0, "Unexpected data in read buffer");
+
+ _currentRequest = request;
+ bool isConnectMethod = (request.Method == HttpMethod.Connect);
+
+ Debug.Assert(!_canRetry);
+ _canRetry = true;
+
+ // Send the request.
+ if (NetEventSource.IsEnabled) Trace($"Sending request: {request}");
+ CancellationTokenRegistration cancellationRegistration = RegisterCancellation(cancellationToken);
+ try
+ {
+ // Write request line
+ await WriteStringAsync(request.Method.Method).ConfigureAwait(false);
+ await WriteByteAsync((byte)' ').ConfigureAwait(false);
+
+ if (isConnectMethod)
+ {
+ // RFC 7231 #section-4.3.6.
+ // Write only CONNECT foo.com:345 HTTP/1.1
+ if (!request.HasHeaders || request.Headers.Host == null)
+ {
+ throw new HttpRequestException(SR.net_http_request_no_host);
+ }
+ await WriteAsciiStringAsync(request.Headers.Host).ConfigureAwait(false);
+ }
+ else
+ {
+ if (_usingProxy)
+ {
+ // Proxied requests contain full URL
+ Debug.Assert(request.RequestUri.Scheme == Uri.UriSchemeHttp);
+ await WriteBytesAsync(s_httpSchemeAndDelimiter).ConfigureAwait(false);
+ await WriteAsciiStringAsync(request.RequestUri.IdnHost).ConfigureAwait(false);
+ }
+ await WriteStringAsync(request.RequestUri.GetComponents(UriComponents.PathAndQuery | UriComponents.Fragment, UriFormat.UriEscaped)).ConfigureAwait(false);
+ }
+
+ // Fall back to 1.1 for all versions other than 1.0
+ Debug.Assert(request.Version.Major >= 0 && request.Version.Minor >= 0); // guaranteed by Version class
+ bool isHttp10 = request.Version.Minor == 0 && request.Version.Major == 1;
+ await WriteBytesAsync(isHttp10 ? s_spaceHttp10NewlineAsciiBytes : s_spaceHttp11NewlineAsciiBytes).ConfigureAwait(false);
+
+ // Determine cookies to send
+ string cookiesFromContainer = null;
+ if (_pool.Settings._useCookies)
+ {
+ cookiesFromContainer = _pool.Settings._cookieContainer.GetCookieHeader(request.RequestUri);
+ if (cookiesFromContainer == "")
+ {
+ cookiesFromContainer = null;
+ }
+ }
+
+ // Write request headers
+ if (request.HasHeaders || cookiesFromContainer != null)
+ {
+ await WriteHeadersAsync(request.Headers, cookiesFromContainer).ConfigureAwait(false);
+ }
+
+ if (request.Content == null)
+ {
+ // Write out Content-Length: 0 header to indicate no body,
+ // unless this is a method that never has a body.
+ if (request.Method != HttpMethod.Get && request.Method != HttpMethod.Head && !isConnectMethod)
+ {
+ await WriteBytesAsync(s_contentLength0NewlineAsciiBytes).ConfigureAwait(false);
+ }
+ }
+ else
+ {
+ // Write content headers
+ await WriteHeadersAsync(request.Content.Headers, cookiesFromContainer: null).ConfigureAwait(false);
+ }
+
+ // Write special additional headers. If a host isn't in the headers list, then a Host header
+ // wasn't sent, so as it's required by HTTP 1.1 spec, send one based on the Request Uri.
+ if (!request.HasHeaders || request.Headers.Host == null)
+ {
+ await WriteHostHeaderAsync(request.RequestUri).ConfigureAwait(false);
+ }
+
+ // CRLF for end of headers.
+ await WriteTwoBytesAsync((byte)'\r', (byte)'\n').ConfigureAwait(false);
+
+ Task sendRequestContentTask = null;
+ if (request.Content == null)
+ {
+ // We have nothing more to send, so flush out any headers we haven't yet sent.
+ await FlushAsync().ConfigureAwait(false);
+ }
+ else
+ {
+ // Send the body if there is one. We prefer to serialize the sending of the content before
+ // we try to receive any response, but if ExpectContinue has been set, we allow the sending
+ // to run concurrently until we receive the final status line, at which point we wait for it.
+ if (!request.HasHeaders || request.Headers.ExpectContinue != true)
+ {
+ await SendRequestContentAsync(request, CreateRequestContentStream(request), cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ // We're sending an Expect: 100-continue header. We need to flush headers so that the server receives
+ // all of them, and we need to do so before initiating the send, as once we do that, it effectively
+ // owns the right to write, and we don't want to concurrently be accessing the write buffer.
+ await FlushAsync().ConfigureAwait(false);
+
+ // Create a TCS we'll use to block the request content from being sent, and create a timer that's used
+ // as a fail-safe to unblock the request content if we don't hear back from the server in a timely manner.
+ // Then kick off the request. The TCS' result indicates whether content should be sent or not.
+ allowExpect100ToContinue = new TaskCompletionSource<bool>();
+ var expect100Timer = new Timer(
+ s => ((TaskCompletionSource<bool>)s).TrySetResult(true),
+ allowExpect100ToContinue, _pool.Settings._expect100ContinueTimeout, Timeout.InfiniteTimeSpan);
+ sendRequestContentTask = SendRequestContentWithExpect100ContinueAsync(
+ request, allowExpect100ToContinue.Task, CreateRequestContentStream(request), expect100Timer, cancellationToken);
+ }
+ }
+
+ // Start to read response.
+ _allowedReadLineBytes = _pool.Settings._maxResponseHeadersLength * 1024;
+
+ // We should not have any buffered data here; if there was, it should have been treated as an error
+ // by the previous request handling. (Note we do not support HTTP pipelining.)
+ Debug.Assert(_readOffset == _readLength);
+
+ // When the connection was put back into the pool, a pre-emptive read was performed
+ // into the read buffer. That read should not complete prior to us using the
+ // connection again, as that would mean the connection was either closed or had
+ // erroneous data sent on it by the server in response to no request from us.
+ // We need to consume that read prior to issuing another read request.
+ ValueTask<int>? t = _readAheadTask;
+ if (t != null)
+ {
+ _readAheadTask = null;
+
+ int bytesRead = await t.GetValueOrDefault().ConfigureAwait(false);
+ if (NetEventSource.IsEnabled) Trace($"Received {bytesRead} bytes.");
+
+ if (bytesRead == 0)
+ {
+ throw new IOException(SR.net_http_invalid_response);
+ }
+
+ _readOffset = 0;
+ _readLength = bytesRead;
+ }
+
+ // The request is no longer retryable; either we received data from the _readAheadTask,
+ // or there was no _readAheadTask because this is the first request on the connection.
+ // (We may have already set this as well if we sent request content.)
+ _canRetry = false;
+
+ // Parse the response status line.
+ var response = new HttpResponseMessage() { RequestMessage = request, Content = new HttpConnectionResponseContent() };
+ ParseStatusLine(await ReadNextResponseHeaderLineAsync().ConfigureAwait(false), response);
+
+ // If we sent an Expect: 100-continue header, handle the response accordingly.
+ if (allowExpect100ToContinue != null)
+ {
+ if ((int)response.StatusCode >= 300 &&
+ (request.Content.Headers.ContentLength == null || request.Content.Headers.ContentLength.GetValueOrDefault() > Expect100ErrorSendThreshold))
+ {
+ // For error final status codes, try to avoid sending the payload if its size is unknown or if it's known to be "big".
+ // If we already sent a header detailing the size of the payload, if we then don't send that payload, the server may wait
+ // for it and assume that the next request on the connection is actually this request's payload. Thus we mark the connection
+ // to be closed. However, we may have also lost a race condition with the Expect: 100-continue timeout, so if it turns out
+ // we've already started sending the payload (we weren't able to cancel it), then we don't need to force close the connection.
+ allowExpect100ToContinue.TrySetResult(false);
+ if (!allowExpect100ToContinue.Task.Result) // if Result is true, the timeout already expired and we started sending content
+ {
+ _connectionClose = true;
+ }
+ }
+ else
+ {
+ // For any success or informational status codes (including 100 continue), send the payload.
+ allowExpect100ToContinue.TrySetResult(true);
+
+ // And if this was 100 continue, deal with the extra headers.
+ if (response.StatusCode == HttpStatusCode.Continue)
+ {
+ // We got our continue header. Read the subsequent empty line and parse the additional status line.
+ if (!LineIsEmpty(await ReadNextResponseHeaderLineAsync().ConfigureAwait(false)))
+ {
+ ThrowInvalidHttpResponse();
+ }
+
+ ParseStatusLine(await ReadNextResponseHeaderLineAsync().ConfigureAwait(false), response);
+ }
+ }
+ }
+
+ // Now that we've received our final status line, wait for the request content to fully send.
+ // In most common scenarios, the server won't send back a response until all of the request
+ // content has been received, so this task should generally already be complete.
+ if (sendRequestContentTask != null)
+ {
+ await sendRequestContentTask.ConfigureAwait(false);
+ sendRequestContentTask = null;
+ }
+
+ // Parse the response headers.
+ while (true)
+ {
+ ArraySegment<byte> line = await ReadNextResponseHeaderLineAsync(foldedHeadersAllowed: true).ConfigureAwait(false);
+ if (LineIsEmpty(line))
+ {
+ break;
+ }
+ ParseHeaderNameValue(line, response);
+ }
+
+ // Determine whether we need to force close the connection when the request/response has completed.
+ if (response.Headers.ConnectionClose.GetValueOrDefault())
+ {
+ _connectionClose = true;
+ }
+
+ // We're about to create the response stream, at which point responsibility for canceling
+ // the remainder of the response lies with the stream. Thus we dispose of our registration
+ // here (if an exception has occurred or does occur while creating/returning the stream,
+ // we'll still dispose of it in the catch below as part of Dispose'ing the connection).
+ cancellationRegistration.Dispose();
+ CancellationHelper.ThrowIfCancellationRequested(cancellationToken); // in case cancellation may have disposed of the stream
+
+ // Create the response stream.
+ HttpContentStream responseStream;
+ if (request.Method == HttpMethod.Head || response.StatusCode == HttpStatusCode.NoContent || response.StatusCode == HttpStatusCode.NotModified)
+ {
+ responseStream = EmptyReadStream.Instance;
+ CompleteResponse();
+ }
+ else if (isConnectMethod && response.StatusCode == HttpStatusCode.OK)
+ {
+ // Successful response to CONNECT does not have body.
+ // What ever comes next should be opaque.
+ responseStream = new RawConnectionStream(this);
+ // Don't put connection back to the pool if we upgraded to tunnel.
+ // We cannot use it for normal HTTP requests any more.
+ _connectionClose = true;
+
+ }
+ else if (response.Content.Headers.ContentLength != null)
+ {
+ long contentLength = response.Content.Headers.ContentLength.GetValueOrDefault();
+ if (contentLength <= 0)
+ {
+ responseStream = EmptyReadStream.Instance;
+ CompleteResponse();
+ }
+ else
+ {
+ responseStream = new ContentLengthReadStream(this, (ulong)contentLength);
+ }
+ }
+ else if (response.Headers.TransferEncodingChunked == true)
+ {
+ responseStream = new ChunkedEncodingReadStream(this);
+ }
+ else if (response.StatusCode == HttpStatusCode.SwitchingProtocols)
+ {
+ responseStream = new RawConnectionStream(this);
+ }
+ else
+ {
+ responseStream = new ConnectionCloseReadStream(this);
+ }
+ ((HttpConnectionResponseContent)response.Content).SetStream(responseStream);
+
+ if (NetEventSource.IsEnabled) Trace($"Received response: {response}");
+
+ // Process Set-Cookie headers.
+ if (_pool.Settings._useCookies)
+ {
+ CookieHelper.ProcessReceivedCookies(response, _pool.Settings._cookieContainer);
+ }
+
+ return response;
+ }
+ catch (Exception error)
+ {
+ // Clean up the cancellation registration in case we're still registered.
+ cancellationRegistration.Dispose();
+
+ // Make sure to complete the allowExpect100ToContinue task if it exists.
+ allowExpect100ToContinue?.TrySetResult(false);
+
+ if (NetEventSource.IsEnabled) Trace($"Error sending request: {error}");
+ Dispose();
+
+ // At this point, we're going to throw an exception; we just need to
+ // determine which exception to throw.
+
+ if (CancellationHelper.ShouldWrapInOperationCanceledException(error, cancellationToken))
+ {
+ // Cancellation was requested, so assume that the failure is due to
+ // the cancellation request. This is a bit unorthodox, as usually we'd
+ // prioritize a non-OperationCanceledException over a cancellation
+ // request to avoid losing potentially pertinent information. But given
+ // the cancellation design where we tear down the underlying connection upon
+ // a cancellation request, which can then result in a myriad of different
+ // exceptions (argument exceptions, object disposed exceptions, socket exceptions,
+ // etc.), as a middle ground we treat it as cancellation, but still propagate the
+ // original information as the inner exception, for diagnostic purposes.
+ throw CancellationHelper.CreateOperationCanceledException(error, cancellationToken);
+ }
+ else if (error is InvalidOperationException || error is IOException)
+ {
+ // If it's an InvalidOperationException or an IOException, for consistency
+ // with other handlers we wrap the exception in an HttpRequestException.
+ throw new HttpRequestException(SR.net_http_client_execution_error, error);
+ }
+ else
+ {
+ // Otherwise, just allow the original exception to propagate.
+ throw;
+ }
+ }
+ }
+
+ public Task<HttpResponseMessage> SendWithNtProxyAuthAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ if (_pool.UsingProxy && _pool.ProxyCredentials != null)
+ {
+ return AuthenticationHelper.SendWithNtProxyAuthAsync(request, _pool.ProxyUri, _pool.ProxyCredentials, this, cancellationToken);
+ }
+
+ return SendAsyncCore(request, cancellationToken);
+ }
+
+ public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, bool doRequestAuth, CancellationToken cancellationToken)
+ {
+ if (doRequestAuth && _pool.Settings._credentials != null)
+ {
+ return AuthenticationHelper.SendWithNtConnectionAuthAsync(request, _pool.Settings._credentials, this, cancellationToken);
+ }
+
+ return SendWithNtProxyAuthAsync(request, cancellationToken);
+ }
+
+ private HttpContentWriteStream CreateRequestContentStream(HttpRequestMessage request)
+ {
+ bool requestTransferEncodingChunked = request.HasHeaders && request.Headers.TransferEncodingChunked == true;
+ HttpContentWriteStream requestContentStream = requestTransferEncodingChunked ? (HttpContentWriteStream)
+ new ChunkedEncodingWriteStream(this) :
+ new ContentLengthWriteStream(this);
+ return requestContentStream;
+ }
+
+ private CancellationTokenRegistration RegisterCancellation(CancellationToken cancellationToken)
+ {
+ // Cancellation design:
+ // - We register with the SendAsync CancellationToken for the duration of the SendAsync operation.
+ // - We register with the Read/Write/CopyToAsync methods on the response stream for each such individual operation.
+ // - The registration disposes of the connection, tearing it down and causing any pending operations to wake up.
+ // - Because such a tear down can result in a variety of different exception types, we check for a cancellation
+ // request and prioritize that over other exceptions, wrapping the actual exception as an inner of an OCE.
+ // - A weak reference to this HttpConnection is stored in the cancellation token, to prevent the token from
+ // artificially keeping this connection alive.
+ return cancellationToken.Register(s =>
+ {
+ var weakThisRef = (WeakReference<HttpConnection>)s;
+ if (weakThisRef.TryGetTarget(out HttpConnection strongThisRef))
+ {
+ if (NetEventSource.IsEnabled) strongThisRef.Trace("Cancellation requested. Disposing of the connection.");
+ strongThisRef.Dispose();
+ }
+ }, _weakThisRef);
+ }
+
+ private static bool LineIsEmpty(ArraySegment<byte> line) => line.Count == 0;
+
+ private async Task SendRequestContentAsync(HttpRequestMessage request, HttpContentWriteStream stream, CancellationToken cancellationToken)
+ {
+ // Now that we're sending content, prohibit retries on this connection.
+ _canRetry = false;
+
+ // Copy all of the data to the server.
+ await request.Content.CopyToAsync(stream, _transportContext, cancellationToken).ConfigureAwait(false);
+
+ // Finish the content; with a chunked upload, this includes writing the terminating chunk.
+ await stream.FinishAsync().ConfigureAwait(false);
+
+ // Flush any content that might still be buffered.
+ await FlushAsync().ConfigureAwait(false);
+ }
+
+ private async Task SendRequestContentWithExpect100ContinueAsync(
+ HttpRequestMessage request, Task<bool> allowExpect100ToContinueTask, HttpContentWriteStream stream, Timer expect100Timer, CancellationToken cancellationToken)
+ {
+ // Wait until we receive a trigger notification that it's ok to continue sending content.
+ // This will come either when the timer fires or when we receive a response status line from the server.
+ bool sendRequestContent = await allowExpect100ToContinueTask.ConfigureAwait(false);
+
+ // Clean up the timer; it's no longer needed.
+ expect100Timer.Dispose();
+
+ // Send the content if we're supposed to. Otherwise, we're done.
+ if (sendRequestContent)
+ {
+ if (NetEventSource.IsEnabled) Trace($"Sending request content for Expect: 100-continue.");
+ await SendRequestContentAsync(request, stream, cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ if (NetEventSource.IsEnabled) Trace($"Canceling request content for Expect: 100-continue.");
+ }
+ }
+
+ // TODO: Remove this overload once https://github.com/dotnet/csharplang/issues/1331 is addressed
+ // and the compiler doesn't prevent using spans in async methods.
+ private static void ParseStatusLine(ArraySegment<byte> line, HttpResponseMessage response) =>
+ ParseStatusLine((Span<byte>)line, response);
+
+ private static void ParseStatusLine(Span<byte> line, HttpResponseMessage response)
+ {
+ // We sent the request version as either 1.0 or 1.1.
+ // We expect a response version of the form 1.X, where X is a single digit as per RFC.
+
+ // Validate the beginning of the status line and set the response version.
+ const int MinStatusLineLength = 12; // "HTTP/1.x 123"
+ if (line.Length < MinStatusLineLength || line[8] != ' ')
+ {
+ ThrowInvalidHttpResponse();
+ }
+
+ ulong first8Bytes = BitConverter.ToUInt64(line);
+ if (first8Bytes == s_http11Bytes)
+ {
+ response.SetVersionWithoutValidation(HttpVersion.Version11);
+ }
+ else if (first8Bytes == s_http10Bytes)
+ {
+ response.SetVersionWithoutValidation(HttpVersion.Version10);
+ }
+ else
+ {
+ byte minorVersion = line[7];
+ if (IsDigit(minorVersion) &&
+ line.Slice(0, 7).SequenceEqual(s_http1DotBytes))
+ {
+ response.SetVersionWithoutValidation(new Version(1, minorVersion - '0'));
+ }
+ else
+ {
+ ThrowInvalidHttpResponse();
+ }
+ }
+
+ // Set the status code
+ byte status1 = line[9], status2 = line[10], status3 = line[11];
+ if (!IsDigit(status1) || !IsDigit(status2) || !IsDigit(status3))
+ {
+ ThrowInvalidHttpResponse();
+ }
+ response.SetStatusCodeWithoutValidation((HttpStatusCode)(100 * (status1 - '0') + 10 * (status2 - '0') + (status3 - '0')));
+
+ // Parse (optional) reason phrase
+ if (line.Length == MinStatusLineLength)
+ {
+ response.SetReasonPhraseWithoutValidation(string.Empty);
+ }
+ else if (line[MinStatusLineLength] == ' ')
+ {
+ Span<byte> reasonBytes = line.Slice(MinStatusLineLength + 1);
+ string knownReasonPhrase = HttpStatusDescription.Get(response.StatusCode);
+ if (knownReasonPhrase != null && EqualsOrdinal(knownReasonPhrase, reasonBytes))
+ {
+ response.SetReasonPhraseWithoutValidation(knownReasonPhrase);
+ }
+ else
+ {
+ try
+ {
+ response.ReasonPhrase = HttpRuleParser.DefaultHttpEncoding.GetString(reasonBytes);
+ }
+ catch (FormatException error)
+ {
+ ThrowInvalidHttpResponse(error);
+ }
+ }
+ }
+ else
+ {
+ ThrowInvalidHttpResponse();
+ }
+ }
+
+ // TODO: Remove this overload once https://github.com/dotnet/csharplang/issues/1331 is addressed
+ // and the compiler doesn't prevent using spans in async methods.
+ private static void ParseHeaderNameValue(ArraySegment<byte> line, HttpResponseMessage response) =>
+ ParseHeaderNameValue((Span<byte>)line, response);
+
+ private static void ParseHeaderNameValue(Span<byte> line, HttpResponseMessage response)
+ {
+ Debug.Assert(line.Length > 0);
+
+ int pos = 0;
+ while (line[pos] != (byte)':' && line[pos] != (byte)' ')
+ {
+ pos++;
+ if (pos == line.Length)
+ {
+ // Invalid header line that doesn't contain ':'.
+ ThrowInvalidHttpResponse();
+ }
+ }
+
+ if (pos == 0)
+ {
+ // Invalid empty header name.
+ ThrowInvalidHttpResponse();
+ }
+
+ if (!HeaderDescriptor.TryGet(line.Slice(0, pos), out HeaderDescriptor descriptor))
+ {
+ // Invalid header name
+ ThrowInvalidHttpResponse();
+ }
+
+ // Eat any trailing whitespace
+ while (line[pos] == (byte)' ')
+ {
+ pos++;
+ if (pos == line.Length)
+ {
+ // Invalid header line that doesn't contain ':'.
+ ThrowInvalidHttpResponse();
+ }
+ }
+
+ if (line[pos++] != ':')
+ {
+ // Invalid header line that doesn't contain ':'.
+ ThrowInvalidHttpResponse();
+ }
+
+ // Skip whitespace after colon
+ while (pos < line.Length && (line[pos] == (byte)' ' || line[pos] == (byte)'\t'))
+ {
+ pos++;
+ }
+
+ string headerValue = descriptor.GetHeaderValue(line.Slice(pos));
+
+ // Note we ignore the return value from TryAddWithoutValidation;
+ // if the header can't be added, we silently drop it.
+ if (descriptor.HeaderType == HttpHeaderType.Content)
+ {
+ response.Content.Headers.TryAddWithoutValidation(descriptor, headerValue);
+ }
+ else
+ {
+ response.Headers.TryAddWithoutValidation(descriptor, headerValue);
+ }
+ }
+
+ private static bool IsDigit(byte c) => (uint)(c - '0') <= '9' - '0';
+
+ private void WriteToBuffer(ReadOnlyMemory<byte> source)
+ {
+ Debug.Assert(source.Length <= _writeBuffer.Length - _writeOffset);
+ source.Span.CopyTo(new Span<byte>(_writeBuffer, _writeOffset, source.Length));
+ _writeOffset += source.Length;
+ }
+
+ private async Task WriteAsync(ReadOnlyMemory<byte> source)
+ {
+ int remaining = _writeBuffer.Length - _writeOffset;
+
+ if (source.Length <= remaining)
+ {
+ // Fits in current write buffer. Just copy and return.
+ WriteToBuffer(source);
+ return;
+ }
+
+ if (_writeOffset != 0)
+ {
+ // Fit what we can in the current write buffer and flush it.
+ WriteToBuffer(source.Slice(0, remaining));
+ source = source.Slice(remaining);
+ await FlushAsync().ConfigureAwait(false);
+ }
+
+ if (source.Length >= _writeBuffer.Length)
+ {
+ // Large write. No sense buffering this. Write directly to stream.
+ // TODO #27362: CONSIDER: May want to be a bit smarter here? Think about how large writes should work...
+ await WriteToStreamAsync(source).ConfigureAwait(false);
+ }
+ else
+ {
+ // Copy remainder into buffer
+ WriteToBuffer(source);
+ }
+ }
+
+ private ValueTask WriteWithoutBufferingAsync(ReadOnlyMemory<byte> source)
+ {
+ if (_writeOffset == 0)
+ {
+ // There's nothing in the write buffer we need to flush.
+ // Just write the supplied data out to the stream.
+ return WriteToStreamAsync(source);
+ }
+
+ int remaining = _writeBuffer.Length - _writeOffset;
+ if (source.Length <= remaining)
+ {
+ // There's something already in the write buffer, but the content
+ // we're writing can also fit after it in the write buffer. Copy
+ // the content to the write buffer and then flush it, so that we
+ // can do a single send rather than two.
+ WriteToBuffer(source);
+ return FlushAsync();
+ }
+
+ // There's data in the write buffer and the data we're writing doesn't fit after it.
+ // Do two writes, one to flush the buffer and then another to write the supplied content.
+ return new ValueTask(FlushThenWriteWithoutBufferingAsync(source));
+ }
+
+ private async Task FlushThenWriteWithoutBufferingAsync(ReadOnlyMemory<byte> source)
+ {
+ await FlushAsync().ConfigureAwait(false);
+ await WriteToStreamAsync(source).ConfigureAwait(false);
+ }
+
+ private Task WriteByteAsync(byte b)
+ {
+ if (_writeOffset < _writeBuffer.Length)
+ {
+ _writeBuffer[_writeOffset++] = b;
+ return Task.CompletedTask;
+ }
+ return WriteByteSlowAsync(b);
+ }
+
+ private async Task WriteByteSlowAsync(byte b)
+ {
+ Debug.Assert(_writeOffset == _writeBuffer.Length);
+ await WriteToStreamAsync(_writeBuffer).ConfigureAwait(false);
+
+ _writeBuffer[0] = b;
+ _writeOffset = 1;
+ }
+
+ private Task WriteTwoBytesAsync(byte b1, byte b2)
+ {
+ if (_writeOffset <= _writeBuffer.Length - 2)
+ {
+ byte[] buffer = _writeBuffer;
+ buffer[_writeOffset++] = b1;
+ buffer[_writeOffset++] = b2;
+ return Task.CompletedTask;
+ }
+ return WriteTwoBytesSlowAsync(b1, b2);
+ }
+
+ private async Task WriteTwoBytesSlowAsync(byte b1, byte b2)
+ {
+ await WriteByteAsync(b1).ConfigureAwait(false);
+ await WriteByteAsync(b2).ConfigureAwait(false);
+ }
+
+ private Task WriteBytesAsync(byte[] bytes)
+ {
+ if (_writeOffset <= _writeBuffer.Length - bytes.Length)
+ {
+ Buffer.BlockCopy(bytes, 0, _writeBuffer, _writeOffset, bytes.Length);
+ _writeOffset += bytes.Length;
+ return Task.CompletedTask;
+ }
+ return WriteBytesSlowAsync(bytes);
+ }
+
+ private async Task WriteBytesSlowAsync(byte[] bytes)
+ {
+ int offset = 0;
+ while (true)
+ {
+ int remaining = bytes.Length - offset;
+ int toCopy = Math.Min(remaining, _writeBuffer.Length - _writeOffset);
+ Buffer.BlockCopy(bytes, offset, _writeBuffer, _writeOffset, toCopy);
+ _writeOffset += toCopy;
+ offset += toCopy;
+
+ Debug.Assert(offset <= bytes.Length, $"Expected {nameof(offset)} to be <= {bytes.Length}, got {offset}");
+ Debug.Assert(_writeOffset <= _writeBuffer.Length, $"Expected {nameof(_writeOffset)} to be <= {_writeBuffer.Length}, got {_writeOffset}");
+ if (offset == bytes.Length)
+ {
+ break;
+ }
+ else if (_writeOffset == _writeBuffer.Length)
+ {
+ await WriteToStreamAsync(_writeBuffer).ConfigureAwait(false);
+ _writeOffset = 0;
+ }
+ }
+ }
+
+ private Task WriteStringAsync(string s)
+ {
+ // If there's enough space in the buffer to just copy all of the string's bytes, do so.
+ // Unlike WriteAsciiStringAsync, validate each char along the way.
+ int offset = _writeOffset;
+ if (s.Length <= _writeBuffer.Length - offset)
+ {
+ byte[] writeBuffer = _writeBuffer;
+ foreach (char c in s)
+ {
+ if ((c & 0xFF80) != 0)
+ {
+ throw new HttpRequestException(SR.net_http_request_invalid_char_encoding);
+ }
+ writeBuffer[offset++] = (byte)c;
+ }
+ _writeOffset = offset;
+ return Task.CompletedTask;
+ }
+
+ // Otherwise, fall back to doing a normal slow string write; we could optimize away
+ // the extra checks later, but the case where we cross a buffer boundary should be rare.
+ return WriteStringAsyncSlow(s);
+ }
+
+ private Task WriteAsciiStringAsync(string s)
+ {
+ // If there's enough space in the buffer to just copy all of the string's bytes, do so.
+ int offset = _writeOffset;
+ if (s.Length <= _writeBuffer.Length - offset)
+ {
+ byte[] writeBuffer = _writeBuffer;
+ foreach (char c in s)
+ {
+ writeBuffer[offset++] = (byte)c;
+ }
+ _writeOffset = offset;
+ return Task.CompletedTask;
+ }
+
+ // Otherwise, fall back to doing a normal slow string write; we could optimize away
+ // the extra checks later, but the case where we cross a buffer boundary should be rare.
+ return WriteStringAsyncSlow(s);
+ }
+
+ private async Task WriteStringAsyncSlow(string s)
+ {
+ for (int i = 0; i < s.Length; i++)
+ {
+ char c = s[i];
+ if ((c & 0xFF80) != 0)
+ {
+ throw new HttpRequestException(SR.net_http_request_invalid_char_encoding);
+ }
+ await WriteByteAsync((byte)c).ConfigureAwait(false);
+ }
+ }
+
+ private ValueTask FlushAsync()
+ {
+ if (_writeOffset > 0)
+ {
+ ValueTask t = WriteToStreamAsync(new ReadOnlyMemory<byte>(_writeBuffer, 0, _writeOffset));
+ _writeOffset = 0;
+ return t;
+ }
+ return default;
+ }
+
+ private ValueTask WriteToStreamAsync(ReadOnlyMemory<byte> source)
+ {
+ if (NetEventSource.IsEnabled) Trace($"Writing {source.Length} bytes.");
+ return _stream.WriteAsync(source);
+ }
+
+ private bool TryReadNextLine(out ReadOnlySpan<byte> line)
+ {
+ var buffer = new ReadOnlySpan<byte>(_readBuffer, _readOffset, _readLength - _readOffset);
+ int length = buffer.IndexOf((byte)'\n');
+ if (length < 0)
+ {
+ if (_allowedReadLineBytes < buffer.Length)
+ {
+ ThrowInvalidHttpResponse();
+ }
+
+ line = default;
+ return false;
+ }
+
+ int bytesConsumed = length + 1;
+ _readOffset += bytesConsumed;
+ _allowedReadLineBytes -= bytesConsumed;
+ ThrowIfExceededAllowedReadLineBytes();
+
+ line = buffer.Slice(0, length > 0 && buffer[length - 1] == '\r' ? length - 1 : length);
+ return true;
+ }
+
+ private async ValueTask<ArraySegment<byte>> ReadNextResponseHeaderLineAsync(bool foldedHeadersAllowed = false)
+ {
+ int previouslyScannedBytes = 0;
+ while (true)
+ {
+ int scanOffset = _readOffset + previouslyScannedBytes;
+ int lfIndex = Array.IndexOf(_readBuffer, (byte)'\n', scanOffset, _readLength - scanOffset);
+ if (lfIndex >= 0)
+ {
+ int startIndex = _readOffset;
+ int length = lfIndex - startIndex;
+ if (lfIndex > 0 && _readBuffer[lfIndex - 1] == '\r')
+ {
+ length--;
+ }
+
+ // If this isn't the ending header, we need to account for the possibility
+ // of folded headers, which per RFC2616 are headers split across multiple
+ // lines, where the continuation line begins with a space or horizontal tab.
+ // The feature was deprecated in RFC 7230 3.2.4, but some servers still use it.
+ if (foldedHeadersAllowed && length > 0)
+ {
+ // If the newline is the last character we've buffered, we need at least
+ // one more character in order to see whether it's space/tab, in which
+ // case it's a folded header.
+ if (lfIndex + 1 == _readLength)
+ {
+ // The LF is at the end of the buffer, so we need to read more
+ // to determine whether there's a continuation. We'll read
+ // and then loop back around again, but to avoid needing to
+ // rescan the whole header, reposition to one character before
+ // the newline so that we'll find it quickly.
+ int backPos = _readBuffer[lfIndex - 1] == '\r' ? lfIndex - 2 : lfIndex - 1;
+ Debug.Assert(backPos >= 0);
+ previouslyScannedBytes = backPos - _readOffset;
+ _allowedReadLineBytes -= backPos - scanOffset;
+ ThrowIfExceededAllowedReadLineBytes();
+ await FillAsync().ConfigureAwait(false);
+ continue;
+ }
+
+ // We have at least one more character we can look at.
+ Debug.Assert(lfIndex + 1 < _readLength);
+ char nextChar = (char)_readBuffer[lfIndex + 1];
+ if (nextChar == ' ' || nextChar == '\t')
+ {
+ // The next header is a continuation.
+
+ // Folded headers are only allowed within header field values, not within header field names,
+ // so if we haven't seen a colon, this is invalid.
+ if (Array.IndexOf(_readBuffer, (byte)':', _readOffset, lfIndex - _readOffset) == -1)
+ {
+ ThrowInvalidHttpResponse();
+ }
+
+ // When we return the line, we need the interim newlines filtered out. According
+ // to RFC 7230 3.2.4, a valid approach to dealing with them is to "replace each
+ // received obs-fold with one or more SP octets prior to interpreting the field
+ // value or forwarding the message downstream", so that's what we do.
+ _readBuffer[lfIndex] = (byte)' ';
+ if (_readBuffer[lfIndex - 1] == '\r')
+ {
+ _readBuffer[lfIndex - 1] = (byte)' ';
+ }
+
+ // Update how much we've read, and simply go back to search for the next newline.
+ previouslyScannedBytes = (lfIndex + 1 - _readOffset);
+ _allowedReadLineBytes -= (lfIndex + 1 - scanOffset);
+ ThrowIfExceededAllowedReadLineBytes();
+ continue;
+ }
+
+ // Not at the end of a header with a continuation.
+ }
+
+ // Advance read position past the LF
+ _allowedReadLineBytes -= lfIndex + 1 - scanOffset;
+ ThrowIfExceededAllowedReadLineBytes();
+ _readOffset = lfIndex + 1;
+
+ return new ArraySegment<byte>(_readBuffer, startIndex, length);
+ }
+
+ // Couldn't find LF. Read more. Note this may cause _readOffset to change.
+ previouslyScannedBytes = _readLength - _readOffset;
+ _allowedReadLineBytes -= _readLength - scanOffset;
+ ThrowIfExceededAllowedReadLineBytes();
+ await FillAsync().ConfigureAwait(false);
+ }
+ }
+
+ private void ThrowIfExceededAllowedReadLineBytes()
+ {
+ if (_allowedReadLineBytes < 0)
+ {
+ ThrowInvalidHttpResponse();
+ }
+ }
+
+ // Throws IOException on EOF. This is only called when we expect more data.
+ private async Task FillAsync()
+ {
+ Debug.Assert(_readAheadTask == null);
+
+ int remaining = _readLength - _readOffset;
+ Debug.Assert(remaining >= 0);
+
+ if (remaining == 0)
+ {
+ // No data in the buffer. Simply reset the offset and length to 0 to allow
+ // the whole buffer to be filled.
+ _readOffset = _readLength = 0;
+ }
+ else if (_readOffset > 0)
+ {
+ // There's some data in the buffer but it's not at the beginning. Shift it
+ // down to make room for more.
+ Buffer.BlockCopy(_readBuffer, _readOffset, _readBuffer, 0, remaining);
+ _readOffset = 0;
+ _readLength = remaining;
+ }
+ else if (remaining == _readBuffer.Length)
+ {
+ // The whole buffer is full, but the caller is still requesting more data,
+ // so increase the size of the buffer.
+ Debug.Assert(_readOffset == 0);
+ Debug.Assert(_readLength == _readBuffer.Length);
+
+ byte[] newReadBuffer = new byte[_readBuffer.Length * 2];
+ Buffer.BlockCopy(_readBuffer, 0, newReadBuffer, 0, remaining);
+ _readBuffer = newReadBuffer;
+ _readOffset = 0;
+ _readLength = remaining;
+ }
+
+ int bytesRead = await _stream.ReadAsync(new Memory<byte>(_readBuffer, _readLength, _readBuffer.Length - _readLength)).ConfigureAwait(false);
+
+ if (NetEventSource.IsEnabled) Trace($"Received {bytesRead} bytes.");
+ if (bytesRead == 0)
+ {
+ throw new IOException(SR.net_http_invalid_response);
+ }
+
+ _readLength += bytesRead;
+ }
+
+ private void ReadFromBuffer(Span<byte> buffer)
+ {
+ Debug.Assert(buffer.Length <= _readLength - _readOffset);
+
+ new Span<byte>(_readBuffer, _readOffset, buffer.Length).CopyTo(buffer);
+ _readOffset += buffer.Length;
+ }
+
+ private async ValueTask<int> ReadAsync(Memory<byte> destination)
+ {
+ // This is called when reading the response body.
+
+ int remaining = _readLength - _readOffset;
+ if (remaining > 0)
+ {
+ // We have data in the read buffer. Return it to the caller.
+ if (destination.Length <= remaining)
+ {
+ ReadFromBuffer(destination.Span);
+ return destination.Length;
+ }
+ else
+ {
+ ReadFromBuffer(destination.Span.Slice(0, remaining));
+ return remaining;
+ }
+ }
+
+ // No data in read buffer.
+ // Do an unbuffered read directly against the underlying stream.
+ Debug.Assert(_readAheadTask == null, "Read ahead task should have been consumed as part of the headers.");
+ int count = await _stream.ReadAsync(destination).ConfigureAwait(false);
+ if (NetEventSource.IsEnabled) Trace($"Received {count} bytes.");
+ return count;
+ }
+
+ private ValueTask<int> ReadBufferedAsync(Memory<byte> destination)
+ {
+ // If the caller provided buffer, and thus the amount of data desired to be read,
+ // is larger than the internal buffer, there's no point going through the internal
+ // buffer, so just do an unbuffered read.
+ return destination.Length >= _readBuffer.Length ?
+ ReadAsync(destination) :
+ ReadBufferedAsyncCore(destination);
+ }
+
+ private async ValueTask<int> ReadBufferedAsyncCore(Memory<byte> destination)
+ {
+ // This is called when reading the response body.
+
+ int remaining = _readLength - _readOffset;
+ if (remaining > 0)
+ {
+ // We have data in the read buffer. Return it to the caller.
+ if (destination.Length <= remaining)
+ {
+ ReadFromBuffer(destination.Span);
+ return destination.Length;
+ }
+ else
+ {
+ ReadFromBuffer(destination.Span.Slice(0, remaining));
+ return remaining;
+ }
+ }
+
+ // No data in read buffer.
+ _readOffset = _readLength = 0;
+
+ // Do a buffered read directly against the underlying stream.
+ Debug.Assert(_readAheadTask == null, "Read ahead task should have been consumed as part of the headers.");
+ int bytesRead = await _stream.ReadAsync(_readBuffer.AsMemory()).ConfigureAwait(false);
+ if (NetEventSource.IsEnabled) Trace($"Received {bytesRead} bytes.");
+ _readLength = bytesRead;
+
+ // Hand back as much data as we can fit.
+ int bytesToCopy = Math.Min(bytesRead, destination.Length);
+ _readBuffer.AsSpan(0, bytesToCopy).CopyTo(destination.Span);
+ _readOffset = bytesToCopy;
+ return bytesToCopy;
+ }
+
+ private async Task CopyFromBufferAsync(Stream destination, int count, CancellationToken cancellationToken)
+ {
+ Debug.Assert(count <= _readLength - _readOffset);
+
+ if (NetEventSource.IsEnabled) Trace($"Copying {count} bytes to stream.");
+ await destination.WriteAsync(new ReadOnlyMemory<byte>(_readBuffer, _readOffset, count), cancellationToken).ConfigureAwait(false);
+ _readOffset += count;
+ }
+
+ private Task CopyToUntilEofAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
+ {
+ Debug.Assert(destination != null);
+
+ int remaining = _readLength - _readOffset;
+ return remaining > 0 ?
+ CopyToUntilEofWithExistingBufferedDataAsync(destination, cancellationToken) :
+ _stream.CopyToAsync(destination, bufferSize, cancellationToken);
+ }
+
+ private async Task CopyToUntilEofWithExistingBufferedDataAsync(Stream destination, CancellationToken cancellationToken)
+ {
+ int remaining = _readLength - _readOffset;
+ Debug.Assert(remaining > 0);
+
+ await CopyFromBufferAsync(destination, remaining, cancellationToken).ConfigureAwait(false);
+ _readLength = _readOffset = 0;
+
+ await _stream.CopyToAsync(destination).ConfigureAwait(false);
+ }
+
+ // Copy *exactly* [length] bytes into destination; throws on end of stream.
+ private async Task CopyToExactLengthAsync(Stream destination, ulong length, CancellationToken cancellationToken)
+ {
+ Debug.Assert(destination != null);
+ Debug.Assert(length > 0);
+
+ int remaining = _readLength - _readOffset;
+ if (remaining > 0)
+ {
+ if ((ulong)remaining > length)
+ {
+ remaining = (int)length;
+ }
+ await CopyFromBufferAsync(destination, remaining, cancellationToken).ConfigureAwait(false);
+
+ length -= (ulong)remaining;
+ if (length == 0)
+ {
+ return;
+ }
+ }
+
+ while (true)
+ {
+ await FillAsync().ConfigureAwait(false);
+
+ remaining = (ulong)_readLength < length ? _readLength : (int)length;
+ await CopyFromBufferAsync(destination, remaining, cancellationToken).ConfigureAwait(false);
+
+ length -= (ulong)remaining;
+ if (length == 0)
+ {
+ return;
+ }
+ }
+ }
+
+ public void Acquire()
+ {
+ Debug.Assert(_currentRequest == null);
+ Debug.Assert(!_inUse);
+
+ _inUse = true;
+ }
+
+ public void Release()
+ {
+ Debug.Assert(_inUse);
+
+ _inUse = false;
+
+ // If the last request already completed (because the response had no content), return the connection to the pool now.
+ // Otherwise, it will be returned when the response has been consumed and CompleteResponse below is called.
+ if (_currentRequest == null)
+ {
+ ReturnConnectionToPool();
+ }
+ }
+
+ private void CompleteResponse()
+ {
+ Debug.Assert(_currentRequest != null, "Expected the connection to be associated with a request.");
+ Debug.Assert(_writeOffset == 0, "Everything in write buffer should have been flushed.");
+
+ // Disassociate the connection from a request.
+ _currentRequest = null;
+
+ // If we have extraneous data in the read buffer, don't reuse the connection;
+ // otherwise we'd interpret this as part of the next response.
+ if (RemainingBuffer.Length != 0)
+ {
+ if (NetEventSource.IsEnabled)
+ {
+ Trace("Unexpected data on connection after response read.");
+ }
+
+ ConsumeFromRemainingBuffer(RemainingBuffer.Length);
+ _connectionClose = true;
+ }
+
+ // If the connection is no longer in use (i.e. for NT authentication), then we can return it to the pool now.
+ // Otherwise, it will be returned when the connection is no longer in use (i.e. Release above is called).
+ if (!_inUse)
+ {
+ ReturnConnectionToPool();
+ }
+ }
+
+ public async Task DrainResponseAsync(HttpResponseMessage response)
+ {
+ Debug.Assert(_inUse);
+
+ if (_connectionClose)
+ {
+ throw new HttpRequestException(SR.net_http_authconnectionfailure);
+ }
+
+ HttpContentReadStream responseStream = (HttpContentReadStream)await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
+
+ if (responseStream.NeedsDrain)
+ {
+ Debug.Assert(response.RequestMessage == _currentRequest);
+
+ if (!await responseStream.DrainAsync(_pool.Settings._maxResponseDrainSize).ConfigureAwait(false) ||
+ _connectionClose) // Draining may have set this
+ {
+ throw new HttpRequestException(SR.net_http_authconnectionfailure);
+ }
+ }
+
+ Debug.Assert(_currentRequest == null);
+
+ response.Dispose();
+ }
+
+ private void ReturnConnectionToPool()
+ {
+ Debug.Assert(_currentRequest == null, "Connection should no longer be associated with a request.");
+ Debug.Assert(_readAheadTask == null, "Expected a previous initial read to already be consumed.");
+ Debug.Assert(RemainingBuffer.Length == 0, "Unexpected data in connection read buffer.");
+
+ // If we decided not to reuse the connection (either because the server sent Connection: close,
+ // or there was some other problem while processing the request that makes the connection unusable),
+ // don't put the connection back in the pool.
+ if (_connectionClose)
+ {
+ if (NetEventSource.IsEnabled)
+ {
+ Trace("Connection will not be reused.");
+ }
+
+ // We're not putting the connection back in the pool. Dispose it.
+ Dispose();
+ }
+ else
+ {
+ // Put connection back in the pool.
+ _pool.ReturnConnection(this);
+ }
+ }
+
+ private static bool EqualsOrdinal(string left, Span<byte> right)
+ {
+ Debug.Assert(left != null, "Expected non-null string");
+
+ if (left.Length != right.Length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i < left.Length; i++)
+ {
+ if (left[i] != right[i])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public sealed override string ToString() => $"{nameof(HttpConnection)}({_pool})"; // Description for diagnostic purposes
+
+ private static void ThrowInvalidHttpResponse() => throw new HttpRequestException(SR.net_http_invalid_response);
+
+ private static void ThrowInvalidHttpResponse(Exception innerException) => throw new HttpRequestException(SR.net_http_invalid_response, innerException);
+
+ internal void Trace(string message, [CallerMemberName] string memberName = null) =>
+ NetEventSource.Log.HandlerMessage(
+ _pool?.GetHashCode() ?? 0, // pool ID
+ GetHashCode(), // connection ID
+ _currentRequest?.GetHashCode() ?? 0, // request ID
+ memberName, // method name
+ ToString() + ": " + message); // message
+ }
+
+ internal sealed class HttpConnectionWithFinalizer : HttpConnection
+ {
+ public HttpConnectionWithFinalizer(HttpConnectionPool pool, Socket socket, Stream stream, TransportContext transportContext) : base(pool, socket, stream, transportContext) { }
+
+ // This class is separated from HttpConnection so we only pay the price of having a finalizer
+ // when it's actually needed, e.g. when MaxConnectionsPerServer is enabled.
+ ~HttpConnectionWithFinalizer() => Dispose(disposing: false);
+ }
+}
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionHandler.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionHandler.cs
new file mode 100644
index 0000000000..59d440f4bf
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionHandler.cs
@@ -0,0 +1,34 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Net.Http
+{
+ internal sealed class HttpConnectionHandler : HttpMessageHandler
+ {
+ private readonly HttpConnectionPoolManager _poolManager;
+
+ public HttpConnectionHandler(HttpConnectionPoolManager poolManager)
+ {
+ _poolManager = poolManager;
+ }
+
+ protected internal override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ return _poolManager.SendAsync(request, doRequestAuth:false, cancellationToken);
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _poolManager.Dispose();
+ }
+
+ base.Dispose(disposing);
+ }
+ }
+}
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionKind.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionKind.cs
new file mode 100644
index 0000000000..b89bb74c66
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionKind.cs
@@ -0,0 +1,16 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Net.Http
+{
+ internal enum HttpConnectionKind : byte
+ {
+ Http,
+ Https,
+ Proxy,
+ ProxyTunnel, // Non-secure connection tunneled through proxy.
+ SslProxyTunnel, // SSL connection tunneled through proxy.
+ ProxyConnect // Connection used for proxy CONNECT. Tunnel will be established on top of this.
+ }
+}
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionPool.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs
index c0b74d0a0b..1c624fcbc4 100644
--- a/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionPool.cs
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPool.cs
@@ -4,8 +4,12 @@
using System.Collections.Generic;
using System.Diagnostics;
+using System.IO;
+using System.Net.Security;
+using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -14,14 +18,22 @@ namespace System.Net.Http
/// <summary>Provides a pool of connections to the same endpoint.</summary>
internal sealed class HttpConnectionPool : IDisposable
{
- /// <summary>Maximum number of milliseconds a connection is allowed to be idle in the pool before we remove it.</summary>
- private const int MaxIdleTimeMilliseconds = 100_000;
+ private readonly HttpConnectionPoolManager _poolManager;
+ private readonly HttpConnectionKind _kind;
+ private readonly string _host;
+ private readonly int _port;
+ private readonly Uri _proxyUri;
/// <summary>List of idle connections stored in the pool.</summary>
private readonly List<CachedConnection> _idleConnections = new List<CachedConnection>();
/// <summary>The maximum number of connections allowed to be associated with the pool.</summary>
private readonly int _maxConnections;
+ /// <summary>For non-proxy connection pools, this is the host name in bytes; for proxies, null.</summary>
+ private readonly byte[] _hostHeaderValueBytes;
+ /// <summary>Options specialized and cached for this pool and its <see cref="_key"/>.</summary>
+ private readonly SslClientAuthenticationOptions _sslOptions;
+
/// <summary>The head of a list of waiters waiting for a connection. Null if no one's waiting.</summary>
private ConnectionWaiter _waitersHead;
/// <summary>The tail of a list of waiters waiting for a connection. Null if no one's waiting.</summary>
@@ -33,25 +45,129 @@ namespace System.Net.Http
private bool _usedSinceLastCleanup = true;
/// <summary>Whether the pool has been disposed.</summary>
private bool _disposed;
-
+
+ private const int DefaultHttpPort = 80;
+ private const int DefaultHttpsPort = 443;
+
/// <summary>Initializes the pool.</summary>
/// <param name="maxConnections">The maximum number of connections allowed to be associated with the pool at any given time.</param>
- public HttpConnectionPool(int maxConnections = int.MaxValue) // int.MaxValue treated as infinite
+ ///
+ public HttpConnectionPool(HttpConnectionPoolManager poolManager, HttpConnectionKind kind, string host, int port, string sslHostName, Uri proxyUri, int maxConnections)
{
+ _poolManager = poolManager;
+ _kind = kind;
+ _host = host;
+ _port = port;
+ _proxyUri = proxyUri;
_maxConnections = maxConnections;
+
+ switch (kind)
+ {
+ case HttpConnectionKind.Http:
+ Debug.Assert(host != null);
+ Debug.Assert(port != 0);
+ Debug.Assert(sslHostName == null);
+ Debug.Assert(proxyUri == null);
+ break;
+
+ case HttpConnectionKind.Https:
+ Debug.Assert(host != null);
+ Debug.Assert(port != 0);
+ Debug.Assert(sslHostName != null);
+ Debug.Assert(proxyUri == null);
+
+ _sslOptions = ConstructSslOptions(poolManager, sslHostName);
+ break;
+
+ case HttpConnectionKind.Proxy:
+ Debug.Assert(host == null);
+ Debug.Assert(port == 0);
+ Debug.Assert(sslHostName == null);
+ Debug.Assert(proxyUri != null);
+ break;
+
+ case HttpConnectionKind.ProxyTunnel:
+ Debug.Assert(host != null);
+ Debug.Assert(port != 0);
+ Debug.Assert(sslHostName == null);
+ Debug.Assert(proxyUri != null);
+ break;
+
+ case HttpConnectionKind.SslProxyTunnel:
+ Debug.Assert(host != null);
+ Debug.Assert(port != 0);
+ Debug.Assert(sslHostName != null);
+ Debug.Assert(proxyUri != null);
+
+ _sslOptions = ConstructSslOptions(poolManager, sslHostName);
+ break;
+
+ case HttpConnectionKind.ProxyConnect:
+ Debug.Assert(host != null);
+ Debug.Assert(port != 0);
+ Debug.Assert(sslHostName == null);
+ Debug.Assert(proxyUri != null);
+ Debug.Assert(proxyUri.IdnHost == host && proxyUri.Port == port);
+ break;
+
+ default:
+ Debug.Fail("Unkown HttpConnectionKind in HttpConnectionPool.ctor");
+ break;
+ }
+
+ if (_host != null)
+ {
+ // Precalculate ASCII bytes for Host header
+ // Note that if _host is null, this is a (non-tunneled) proxy connection, and we can't cache the hostname.
+ string hostHeader =
+ (_port != (_sslOptions == null ? DefaultHttpPort : DefaultHttpsPort)) ?
+ $"{_host}:{_port}" :
+ _host;
+
+ // Note the IDN hostname should always be ASCII, since it's already been IDNA encoded.
+ _hostHeaderValueBytes = Encoding.ASCII.GetBytes(hostHeader);
+ Debug.Assert(Encoding.ASCII.GetString(_hostHeaderValueBytes) == hostHeader);
+ }
+
+ // Set up for PreAuthenticate. Access to this cache is guarded by a lock on the cache itself.
+ if (_poolManager.Settings._preAuthenticate)
+ {
+ PreAuthCredentials = new CredentialCache();
+ }
}
+ private static SslClientAuthenticationOptions ConstructSslOptions(HttpConnectionPoolManager poolManager, string sslHostName)
+ {
+ Debug.Assert(sslHostName != null);
+
+ SslClientAuthenticationOptions sslOptions = poolManager.Settings._sslOptions?.ShallowClone() ?? new SslClientAuthenticationOptions();
+ sslOptions.ApplicationProtocols = null; // explicitly ignore any ApplicationProtocols set
+ sslOptions.TargetHost = sslHostName; // always use the key's name rather than whatever was specified
+
+ return sslOptions;
+ }
+
+ public HttpConnectionSettings Settings => _poolManager.Settings;
+ public bool IsSecure => _sslOptions != null;
+ public bool UsingProxy => _kind == HttpConnectionKind.Proxy; // Tunnel doesn't count, only direct proxy usage
+ public Uri ProxyUri => _proxyUri;
+ public ICredentials ProxyCredentials => _poolManager.ProxyCredentials;
+ public byte[] HostHeaderValueBytes => _hostHeaderValueBytes;
+ public CredentialCache PreAuthCredentials { get; }
+
/// <summary>Object used to synchronize access to state in the pool.</summary>
private object SyncObj => _idleConnections;
- public ValueTask<HttpConnection> GetConnectionAsync<TState>(
- Func<TState, CancellationToken, ValueTask<HttpConnection>> createConnection, TState state, CancellationToken cancellationToken)
+ private ValueTask<(HttpConnection, HttpResponseMessage)> GetConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
- return new ValueTask<HttpConnection>(Task.FromCanceled<HttpConnection>(cancellationToken));
+ return new ValueTask<(HttpConnection, HttpResponseMessage)>(Task.FromCanceled<(HttpConnection, HttpResponseMessage)>(cancellationToken));
}
+ TimeSpan pooledConnectionLifetime = _poolManager.Settings._pooledConnectionLifetime;
+ TimeSpan pooledConnectionIdleTimeout = _poolManager.Settings._pooledConnectionIdleTimeout;
+ DateTimeOffset now = DateTimeOffset.UtcNow;
List<CachedConnection> list = _idleConnections;
lock (SyncObj)
{
@@ -63,11 +179,12 @@ namespace System.Net.Http
HttpConnection conn = cachedConnection._connection;
list.RemoveAt(list.Count - 1);
- if (cachedConnection.IsUsable())
+ if (cachedConnection.IsUsable(now, pooledConnectionLifetime, pooledConnectionIdleTimeout) &&
+ !conn.EnsureReadAheadAndPollRead())
{
- // We found a valid collection. Return it.
+ // We found a valid connection. Return it.
if (NetEventSource.IsEnabled) conn.Trace("Found usable connection in pool.");
- return new ValueTask<HttpConnection>(conn);
+ return new ValueTask<(HttpConnection, HttpResponseMessage)>((conn, null));
}
// We got a connection, but it was already closed by the server or the
@@ -85,7 +202,7 @@ namespace System.Net.Http
{
if (NetEventSource.IsEnabled) Trace("Creating new connection for pool.");
IncrementConnectionCountNoLock();
- return WaitForCreatedConnectionAsync(createConnection(state, cancellationToken));
+ return WaitForCreatedConnectionAsync(CreateConnectionAsync(request, cancellationToken));
}
else
{
@@ -97,7 +214,7 @@ namespace System.Net.Http
// space is available and the provided creation func has successfully
// created the connection to be used.
if (NetEventSource.IsEnabled) Trace("Limit reached. Waiting to create new connection.");
- var waiter = new ConnectionWaiter<TState>(this, createConnection, state, cancellationToken);
+ var waiter = new ConnectionWaiter(this, request, cancellationToken);
EnqueueWaiter(waiter);
if (cancellationToken.CanBeCanceled)
{
@@ -118,7 +235,7 @@ namespace System.Net.Http
}
}, waiter);
}
- return new ValueTask<HttpConnection>(waiter.Task);
+ return new ValueTask<(HttpConnection, HttpResponseMessage)>(waiter.Task);
}
// Note that we don't check for _disposed. We may end up disposing the
@@ -132,6 +249,135 @@ namespace System.Net.Http
}
}
+ public async Task<HttpResponseMessage> SendWithRetryAsync(HttpRequestMessage request, bool doRequestAuth, CancellationToken cancellationToken)
+ {
+ while (true)
+ {
+ // Loop on connection failures and retry if possible.
+
+ (HttpConnection connection, HttpResponseMessage response) = await GetConnectionAsync(request, cancellationToken).ConfigureAwait(false);
+ if (response != null)
+ {
+ // Proxy tunnel failure; return proxy response
+ return response;
+ }
+
+ bool isNewConnection = connection.IsNewConnection;
+
+ connection.Acquire();
+ try
+ {
+ return await connection.SendAsync(request, doRequestAuth, cancellationToken).ConfigureAwait(false);
+ }
+ catch (HttpRequestException e) when (!isNewConnection && e.InnerException is IOException && connection.CanRetry)
+ {
+ // Eat exception and try again.
+ }
+ finally
+ {
+ connection.Release();
+ }
+ }
+ }
+
+ public Task<HttpResponseMessage> SendWithProxyAuthAsync(HttpRequestMessage request, bool doRequestAuth, CancellationToken cancellationToken)
+ {
+ if ((_kind == HttpConnectionKind.Proxy || _kind == HttpConnectionKind.ProxyConnect) &&
+ _poolManager.ProxyCredentials != null)
+ {
+ return AuthenticationHelper.SendWithProxyAuthAsync(request, _proxyUri, _poolManager.ProxyCredentials, doRequestAuth, this, cancellationToken);
+ }
+
+ return SendWithRetryAsync(request, doRequestAuth, cancellationToken);
+ }
+
+ public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, bool doRequestAuth, CancellationToken cancellationToken)
+ {
+ if (doRequestAuth && Settings._credentials != null)
+ {
+ return AuthenticationHelper.SendWithRequestAuthAsync(request, Settings._credentials, Settings._preAuthenticate, this, cancellationToken);
+ }
+
+ return SendWithProxyAuthAsync(request, doRequestAuth, cancellationToken);
+ }
+
+ private async ValueTask<(HttpConnection, HttpResponseMessage)> CreateConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ // If a non-infinite connect timeout has been set, create and use a new CancellationToken that'll be canceled
+ // when either the original token is canceled or a connect timeout occurs.
+ CancellationTokenSource cancellationWithConnectTimeout = null;
+ if (Settings._connectTimeout != Timeout.InfiniteTimeSpan)
+ {
+ cancellationWithConnectTimeout = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, default);
+ cancellationWithConnectTimeout.CancelAfter(Settings._connectTimeout);
+ cancellationToken = cancellationWithConnectTimeout.Token;
+ }
+
+ try
+ {
+ Socket socket = null;
+ Stream stream = null;
+ switch (_kind)
+ {
+ case HttpConnectionKind.Http:
+ case HttpConnectionKind.Https:
+ case HttpConnectionKind.ProxyConnect:
+ (socket, stream) = await ConnectHelper.ConnectAsync(_host, _port, cancellationToken).ConfigureAwait(false);
+ break;
+
+ case HttpConnectionKind.Proxy:
+ (socket, stream) = await ConnectHelper.ConnectAsync(_proxyUri.IdnHost, _proxyUri.Port, cancellationToken).ConfigureAwait(false);
+ break;
+
+ case HttpConnectionKind.ProxyTunnel:
+ case HttpConnectionKind.SslProxyTunnel:
+ HttpResponseMessage response;
+ (stream, response) = await EstablishProxyTunnel(cancellationToken).ConfigureAwait(false);
+ if (response != null)
+ {
+ // Return non-success response from proxy.
+ response.RequestMessage = request;
+ return (null, response);
+ }
+ break;
+ }
+
+ TransportContext transportContext = null;
+ if (_sslOptions != null)
+ {
+ SslStream sslStream = await ConnectHelper.EstablishSslConnectionAsync(_sslOptions, request, stream, cancellationToken).ConfigureAwait(false);
+ stream = sslStream;
+ transportContext = sslStream.TransportContext;
+ }
+
+ HttpConnection connection = _maxConnections == int.MaxValue ?
+ new HttpConnection(this, socket, stream, transportContext) :
+ new HttpConnectionWithFinalizer(this, socket, stream, transportContext); // finalizer needed to signal the pool when a connection is dropped
+ return (connection, null);
+ }
+ finally
+ {
+ cancellationWithConnectTimeout?.Dispose();
+ }
+ }
+
+ // Returns the established stream or an HttpResponseMessage from the proxy indicating failure.
+ private async ValueTask<(Stream, HttpResponseMessage)> EstablishProxyTunnel(CancellationToken cancellationToken)
+ {
+ // Send a CONNECT request to the proxy server to establish a tunnel.
+ HttpRequestMessage tunnelRequest = new HttpRequestMessage(HttpMethod.Connect, _proxyUri);
+ tunnelRequest.Headers.Host = $"{_host}:{_port}"; // This specifies destination host/port to connect to
+
+ HttpResponseMessage tunnelResponse = await _poolManager.SendProxyConnectAsync(tunnelRequest, _proxyUri, cancellationToken);
+
+ if (tunnelResponse.StatusCode != HttpStatusCode.OK)
+ {
+ return (null, tunnelResponse);
+ }
+
+ return (await tunnelResponse.Content.ReadAsStreamAsync().ConfigureAwait(false), null);
+ }
+
/// <summary>Enqueues a waiter to the waiters list.</summary>
/// <param name="waiter">The waiter to add.</param>
private void EnqueueWaiter(ConnectionWaiter waiter)
@@ -214,11 +460,16 @@ namespace System.Net.Http
}
/// <summary>Waits for and returns the created connection, decrementing the associated connection count if it fails.</summary>
- private async ValueTask<HttpConnection> WaitForCreatedConnectionAsync(ValueTask<HttpConnection> creationTask)
+ private async ValueTask<(HttpConnection, HttpResponseMessage)> WaitForCreatedConnectionAsync(ValueTask<(HttpConnection, HttpResponseMessage)> creationTask)
{
try
{
- return await creationTask.ConfigureAwait(false);
+ (HttpConnection connection, HttpResponseMessage response) = await creationTask.ConfigureAwait(false);
+ if (connection == null)
+ {
+ DecrementConnectionCount();
+ }
+ return (connection, response);
}
catch
{
@@ -283,7 +534,7 @@ namespace System.Net.Http
// Having a waiter means there must not be any idle connections, so we need to create
// one, and we do so using the logic associated with the waiter.
- ValueTask<HttpConnection> connectionTask = waiter.CreateConnectionAsync();
+ ValueTask<(HttpConnection, HttpResponseMessage)> connectionTask = waiter.CreateConnectionAsync();
if (connectionTask.IsCompletedSuccessfully)
{
// We synchronously and successfully created a connection (this is rare).
@@ -301,7 +552,13 @@ namespace System.Net.Http
try
{
// Get the resulting connection.
- HttpConnection result = innerConnectionTask.GetAwaiter().GetResult();
+ (HttpConnection result, HttpResponseMessage response) = innerConnectionTask.GetAwaiter().GetResult();
+
+ if (response != null)
+ {
+ // Proxy tunnel connect failed, so decrement the connection count.
+ innerWaiter._pool.DecrementConnectionCount();
+ }
// Store the resulting connection into the waiter. As in the synchronous case,
// since we already have a count that's inflated due to the connection being
@@ -337,13 +594,13 @@ namespace System.Net.Http
// If there's someone waiting for a connection, simply
// transfer this one to them rather than pooling it.
- if (_waitersTail != null)
+ if (_waitersTail != null && !connection.EnsureReadAheadAndPollRead())
{
ConnectionWaiter waiter = DequeueWaiter();
waiter._cancellationTokenRegistration.Dispose();
if (NetEventSource.IsEnabled) connection.Trace("Transferring connection returned to pool.");
- waiter.SetResult(connection);
+ waiter.SetResult((connection, null));
return;
}
@@ -391,6 +648,9 @@ namespace System.Net.Http
/// </returns>
public bool CleanCacheAndDisposeIfUnused()
{
+ TimeSpan pooledConnectionLifetime = _poolManager.Settings._pooledConnectionLifetime;
+ TimeSpan pooledConnectionIdleTimeout = _poolManager.Settings._pooledConnectionIdleTimeout;
+
List<CachedConnection> list = _idleConnections;
List<HttpConnection> toDispose = null;
bool tookLock = false;
@@ -405,7 +665,7 @@ namespace System.Net.Http
// Find the first item which needs to be removed.
int freeIndex = 0;
- while (freeIndex < list.Count && list[freeIndex].IsUsable(now))
+ while (freeIndex < list.Count && list[freeIndex].IsUsable(now, pooledConnectionLifetime, pooledConnectionIdleTimeout, poll: true))
{
freeIndex++;
}
@@ -423,7 +683,7 @@ namespace System.Net.Http
{
// Look for the first item to be kept. Along the way, any
// that shouldn't be kept are disposed of.
- while (current < list.Count && !list[current].IsUsable(now))
+ while (current < list.Count && !list[current].IsUsable(now, pooledConnectionLifetime, pooledConnectionIdleTimeout, poll: true))
{
toDispose.Add(list[current]._connection);
current++;
@@ -475,7 +735,16 @@ namespace System.Net.Http
return false;
}
- public override string ToString() => $"{nameof(HttpConnectionPool)}(Connections:{_associatedConnectionCount})"; // Description for diagnostic purposes
+ // For diagnostic purposes
+ public override string ToString() =>
+ $"{nameof(HttpConnectionPool)}" +
+ (_proxyUri == null ?
+ (_sslOptions == null ?
+ $"http://{_host}:{_port}" :
+ $"https://{_host}:{_port}" + (_sslOptions.TargetHost != _host ? $", SSL TargetHost={_sslOptions.TargetHost}" : null)) :
+ (_sslOptions == null ?
+ $"Proxy {_proxyUri}" :
+ $"https://{_host}:{_port}/ tunnelled via Proxy {_proxyUri}" + (_sslOptions.TargetHost != _host ? $", SSL TargetHost={_sslOptions.TargetHost}" : null)));
private void Trace(string message, [CallerMemberName] string memberName = null) =>
NetEventSource.Log.HandlerMessage(
@@ -504,11 +773,9 @@ namespace System.Net.Http
}
/// <summary>Gets whether the connection is currently usable.</summary>
- /// <returns>true if we believe the connection can be reused; otherwise, false. See comments on other overload.</returns>
- public bool IsUsable() => !_connection.ReadAheadCompleted;
-
- /// <summary>Gets whether the connection is currently usable, factoring in expiration time.</summary>
/// <param name="now">The current time. Passed in to amortize the cost of calling DateTime.UtcNow.</param>
+ /// <param name="pooledConnectionLifetime">How long a connection can be open to be considered reusable.</param>
+ /// <param name="pooledConnectionIdleTimeout">How long a connection can have been idle in the pool to be considered reusable.</param>
/// <returns>
/// true if we believe the connection can be reused; otherwise, false. There is an inherent race condition here,
/// in that the server could terminate the connection or otherwise make it unusable immediately after we check it,
@@ -516,45 +783,40 @@ namespace System.Net.Http
/// terminate it, which would be considered a failure, so this race condition is largely benign and inherent to
/// the nature of connection pooling.
/// </returns>
- public bool IsUsable(DateTimeOffset now) =>
- now - _returnedTime <= TimeSpan.FromMilliseconds(MaxIdleTimeMilliseconds) &&
- IsUsable();
-
- public bool Equals(CachedConnection other) => ReferenceEquals(other._connection, _connection);
- public override bool Equals(object obj) => obj is CachedConnection && Equals((CachedConnection)obj);
- public override int GetHashCode() => _connection?.GetHashCode() ?? 0;
- }
-
- /// <summary>Provides a waiter object that supports a generic function and state type for creating connections.</summary>
- private sealed class ConnectionWaiter<TState> : ConnectionWaiter
- {
- /// <summary>The function to invoke if/when <see cref="CreateConnectionAsync"/> is invoked.</summary>
- private readonly Func<TState, CancellationToken, ValueTask<HttpConnection>> _createConnectionAsync;
- /// <summary>The state to pass to <paramref name="func"/> when it's invoked.</summary>
- private readonly TState _state;
-
- /// <summary>Initializes the waiter.</summary>
- /// <param name="func">The function to invoke if/when <see cref="CreateConnectionAsync"/> is invoked.</param>
- /// <param name="state">The state to pass to <paramref name="func"/> when it's invoked.</param>
- public ConnectionWaiter(HttpConnectionPool pool, Func<TState, CancellationToken, ValueTask<HttpConnection>> func, TState state, CancellationToken cancellationToken) :
- base(pool, cancellationToken)
+ public bool IsUsable(
+ DateTimeOffset now,
+ TimeSpan pooledConnectionLifetime,
+ TimeSpan pooledConnectionIdleTimeout,
+ bool poll = false)
{
- _createConnectionAsync = func;
- _state = state;
- }
+ // Validate that the connection hasn't been idle in the pool for longer than is allowed.
+ if ((pooledConnectionIdleTimeout != Timeout.InfiniteTimeSpan) && (now - _returnedTime > pooledConnectionIdleTimeout))
+ {
+ if (NetEventSource.IsEnabled) _connection.Trace($"Connection no longer usable. Idle {now - _returnedTime} > {pooledConnectionIdleTimeout}.");
+ return false;
+ }
- /// <summary>Creates a connection by invoking <see cref="_createConnectionAsync"/> with <see cref="_state"/>.</summary>
- public override ValueTask<HttpConnection> CreateConnectionAsync()
- {
- try
+ // Validate that the connection hasn't been alive for longer than is allowed.
+ if ((pooledConnectionLifetime != Timeout.InfiniteTimeSpan) && (now - _connection.CreationTime > pooledConnectionLifetime))
{
- return _createConnectionAsync(_state, _cancellationToken);
+ if (NetEventSource.IsEnabled) _connection.Trace($"Connection no longer usable. Alive {now - _connection.CreationTime} > {pooledConnectionLifetime}.");
+ return false;
}
- catch (Exception e)
+
+ // Validate that the connection hasn't received any stray data while in the pool.
+ if (poll && _connection.PollRead())
{
- return new ValueTask<HttpConnection>(Threading.Tasks.Task.FromException<HttpConnection>(e));
+ if (NetEventSource.IsEnabled) _connection.Trace($"Connection no longer usable. Unexpected data received.");
+ return false;
}
+
+ // The connection is usable.
+ return true;
}
+
+ public bool Equals(CachedConnection other) => ReferenceEquals(other._connection, _connection);
+ public override bool Equals(object obj) => obj is CachedConnection && Equals((CachedConnection)obj);
+ public override int GetHashCode() => _connection?.GetHashCode() ?? 0;
}
/// <summary>
@@ -563,16 +825,13 @@ namespace System.Net.Http
/// into the waiter as a result, and if no connection is available from the pool,
/// this waiter's logic is used to create the connection.
/// </summary>
- /// <remarks>
- /// Implemented as a non-generic base type with a generic derived type to support
- /// passing in arbitrary funcs and associated state while minimizing allocations.
- /// The <see cref="CreateConnectionAsync"/> method will be implemented on the derived
- /// type that is able to work with the supplied state generically.
- /// </remarks>
- private abstract class ConnectionWaiter : TaskCompletionSource<HttpConnection>
+ private class ConnectionWaiter : TaskCompletionSource<(HttpConnection, HttpResponseMessage)>
{
/// <summary>The pool with which this waiter is associated.</summary>
internal readonly HttpConnectionPool _pool;
+ /// <summary>Request to use to create the connection.</summary>
+ private readonly HttpRequestMessage _request;
+
/// <summary>Cancellation token for the waiter.</summary>
internal readonly CancellationToken _cancellationToken;
/// <summary>Registration that removes the waiter from the registration list.</summary>
@@ -583,15 +842,26 @@ namespace System.Net.Http
internal ConnectionWaiter _prev;
/// <summary>Initializes the waiter.</summary>
- public ConnectionWaiter(HttpConnectionPool pool, CancellationToken cancellationToken) : base(TaskCreationOptions.RunContinuationsAsynchronously)
+ public ConnectionWaiter(HttpConnectionPool pool, HttpRequestMessage request, CancellationToken cancellationToken) : base(TaskCreationOptions.RunContinuationsAsynchronously)
{
Debug.Assert(pool != null, "Expected non-null pool");
_pool = pool;
+ _request = request;
_cancellationToken = cancellationToken;
}
-
+
/// <summary>Creates a connection.</summary>
- public abstract ValueTask<HttpConnection> CreateConnectionAsync();
+ public ValueTask<(HttpConnection, HttpResponseMessage)> CreateConnectionAsync()
+ {
+ try
+ {
+ return _pool.CreateConnectionAsync(_request, _cancellationToken);
+ }
+ catch (Exception e)
+ {
+ return new ValueTask<(HttpConnection, HttpResponseMessage)>(Threading.Tasks.Task.FromException<(HttpConnection, HttpResponseMessage)>(e));
+ }
+ }
}
}
}
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPoolManager.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPoolManager.cs
new file mode 100644
index 0000000000..b4b80898f1
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionPoolManager.cs
@@ -0,0 +1,354 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Net.Http.Headers;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Net.Http
+{
+ // General flow of requests through the various layers:
+ //
+ // (1) HttpConnectionPoolManager.SendAsync: Does proxy lookup
+ // (2) HttpConnectionPoolManager.SendAsyncCore: Find or create connection pool
+ // (3) HttpConnectionPool.SendAsync: Handle basic/digest request auth
+ // (4) HttpConnectionPool.SendWithProxyAuthAsync: Handle basic/digest proxy auth
+ // (5) HttpConnectionPool.SendWithRetryAsync: Retrieve connection from pool, or create new
+ // Also, handle retry for failures on connection reuse
+ // (6) HttpConnection.SendAsync: Handle negotiate/ntlm connection auth
+ // (7) HttpConnection.SendWithNtProxyAuthAsync: Handle negotiate/ntlm proxy auth
+ // (8) HttpConnection.SendAsyncCore: Write request to connection and read response
+ // Also, handle cookie processing
+ //
+ // Redirect and deompression handling are done above HttpConnectionPoolManager,
+ // in RedirectHandler and DecompressionHandler respectively.
+
+ /// <summary>Provides a set of connection pools, each for its own endpoint.</summary>
+ internal sealed class HttpConnectionPoolManager : IDisposable
+ {
+ /// <summary>How frequently an operation should be initiated to clean out old pools and connections in those pools.</summary>
+ private readonly TimeSpan _cleanPoolTimeout;
+ /// <summary>The pools, indexed by endpoint.</summary>
+ private readonly ConcurrentDictionary<HttpConnectionKey, HttpConnectionPool> _pools;
+ /// <summary>Timer used to initiate cleaning of the pools.</summary>
+ private readonly Timer _cleaningTimer;
+ /// <summary>The maximum number of connections allowed per pool. <see cref="int.MaxValue"/> indicates unlimited.</summary>
+ private readonly int _maxConnectionsPerServer;
+ // Temporary
+ private readonly HttpConnectionSettings _settings;
+ private readonly IWebProxy _proxy;
+ private readonly ICredentials _proxyCredentials;
+
+ /// <summary>
+ /// Keeps track of whether or not the cleanup timer is running. It helps us avoid the expensive
+ /// <see cref="ConcurrentDictionary{TKey,TValue}.IsEmpty"/> call.
+ /// </summary>
+ private bool _timerIsRunning;
+ /// <summary>Object used to synchronize access to state in the pool.</summary>
+ private object SyncObj => _pools;
+
+ /// <summary>Initializes the pools.</summary>
+ /// <param name="maxConnectionsPerServer">The maximum number of connections allowed per pool. <see cref="int.MaxValue"/> indicates unlimited.</param>
+
+ public HttpConnectionPoolManager(HttpConnectionSettings settings)
+ {
+ _settings = settings;
+ _maxConnectionsPerServer = settings._maxConnectionsPerServer;
+ _pools = new ConcurrentDictionary<HttpConnectionKey, HttpConnectionPool>();
+
+ // Start out with the timer not running, since we have no pools.
+ // When it does run, run it with a frequency based on the idle timeout.
+ if (settings._pooledConnectionIdleTimeout == Timeout.InfiniteTimeSpan)
+ {
+ const int DefaultScavengeSeconds = 30;
+ _cleanPoolTimeout = TimeSpan.FromSeconds(DefaultScavengeSeconds);
+ }
+ else
+ {
+ const int ScavengesPerIdle = 4;
+ const int MinScavengeSeconds = 1;
+ TimeSpan timerPeriod = settings._pooledConnectionIdleTimeout / ScavengesPerIdle;
+ _cleanPoolTimeout = timerPeriod.TotalSeconds >= MinScavengeSeconds ? timerPeriod : TimeSpan.FromSeconds(MinScavengeSeconds);
+ }
+
+ // Figure out proxy stuff.
+ if (settings._useProxy)
+ {
+ _proxy = settings._proxy ?? SystemProxyInfo.ConstructSystemProxy();
+ if (_proxy != null)
+ {
+ _proxyCredentials = _proxy.Credentials ?? settings._defaultProxyCredentials;
+ }
+ }
+
+ // Don't capture the current ExecutionContext and its AsyncLocals onto the timer causing them to live forever
+ bool restoreFlow = false;
+ try
+ {
+ if (!ExecutionContext.IsFlowSuppressed())
+ {
+ ExecutionContext.SuppressFlow();
+ restoreFlow = true;
+ }
+
+ _cleaningTimer = new Timer(s => ((HttpConnectionPoolManager)s).RemoveStalePools(), this, Timeout.Infinite, Timeout.Infinite);
+ }
+ finally
+ {
+ // Restore the current ExecutionContext
+ if (restoreFlow)
+ ExecutionContext.RestoreFlow();
+ }
+ }
+
+ public HttpConnectionSettings Settings => _settings;
+ public ICredentials ProxyCredentials => _proxyCredentials;
+
+ private static string ParseHostNameFromHeader(string hostHeader)
+ {
+ // See if we need to trim off a port.
+ int colonPos = hostHeader.IndexOf(':');
+ if (colonPos >= 0)
+ {
+ // There is colon, which could either be a port separator or a separator in
+ // an IPv6 address. See if this is an IPv6 address; if it's not, use everything
+ // before the colon as the host name, and if it is, use everything before the last
+ // colon iff the last colon is after the end of the IPv6 address (otherwise it's a
+ // part of the address).
+ int ipV6AddressEnd = hostHeader.IndexOf(']');
+ if (ipV6AddressEnd == -1)
+ {
+ return hostHeader.Substring(0, colonPos);
+ }
+ else
+ {
+ colonPos = hostHeader.LastIndexOf(':');
+ if (colonPos > ipV6AddressEnd)
+ {
+ return hostHeader.Substring(0, colonPos);
+ }
+ }
+ }
+
+ return hostHeader;
+ }
+
+ private static HttpConnectionKey GetConnectionKey(HttpRequestMessage request, Uri proxyUri, bool isProxyConnect)
+ {
+ Uri uri = request.RequestUri;
+
+ if (isProxyConnect)
+ {
+ Debug.Assert(uri == proxyUri);
+ return new HttpConnectionKey(HttpConnectionKind.ProxyConnect, uri.IdnHost, uri.Port, null, proxyUri);
+ }
+
+ string sslHostName = null;
+ if (HttpUtilities.IsSupportedSecureScheme(uri.Scheme))
+ {
+ string hostHeader = request.Headers.Host;
+ if (hostHeader != null)
+ {
+ sslHostName = ParseHostNameFromHeader(hostHeader);
+ }
+ else
+ {
+ // No explicit Host header. Use host from uri.
+ sslHostName = uri.IdnHost;
+ }
+ }
+
+ if (proxyUri != null)
+ {
+ Debug.Assert(HttpUtilities.IsSupportedNonSecureScheme(proxyUri.Scheme));
+ if (sslHostName == null)
+ {
+ if (HttpUtilities.IsNonSecureWebSocketScheme(uri.Scheme))
+ {
+ // Non-secure websocket connection through proxy to the destination.
+ return new HttpConnectionKey(HttpConnectionKind.ProxyTunnel, uri.IdnHost, uri.Port, null, proxyUri);
+ }
+ else
+ {
+ // Standard HTTP proxy usage for non-secure requests
+ // The destination host and port are ignored here, since these connections
+ // will be shared across any requests that use the proxy.
+ return new HttpConnectionKey(HttpConnectionKind.Proxy, null, 0, null, proxyUri);
+ }
+ }
+ else
+ {
+ // Tunnel SSL connection through proxy to the destination.
+ return new HttpConnectionKey(HttpConnectionKind.SslProxyTunnel, uri.IdnHost, uri.Port, sslHostName, proxyUri);
+ }
+ }
+ else if (sslHostName != null)
+ {
+ return new HttpConnectionKey(HttpConnectionKind.Https, uri.IdnHost, uri.Port, sslHostName, null);
+ }
+ else
+ {
+ return new HttpConnectionKey(HttpConnectionKind.Http, uri.IdnHost, uri.Port, null, null);
+ }
+ }
+
+ public Task<HttpResponseMessage> SendAsyncCore(HttpRequestMessage request, Uri proxyUri, bool doRequestAuth, bool isProxyConnect, CancellationToken cancellationToken)
+ {
+ HttpConnectionKey key = GetConnectionKey(request, proxyUri, isProxyConnect);
+
+ HttpConnectionPool pool;
+ while (!_pools.TryGetValue(key, out pool))
+ {
+ pool = new HttpConnectionPool(this, key.Kind, key.Host, key.Port, key.SslHostName, key.ProxyUri, _maxConnectionsPerServer);
+ if (_pools.TryAdd(key, pool))
+ {
+ // We need to ensure the cleanup timer is running if it isn't
+ // already now that we added a new connection pool.
+ lock (SyncObj)
+ {
+ if (!_timerIsRunning)
+ {
+ _cleaningTimer.Change(_cleanPoolTimeout, _cleanPoolTimeout);
+ _timerIsRunning = true;
+ }
+ }
+ break;
+ }
+
+ pool.Dispose();
+ }
+
+ return pool.SendAsync(request, doRequestAuth, cancellationToken);
+ }
+
+ public Task<HttpResponseMessage> SendProxyConnectAsync(HttpRequestMessage request, Uri proxyUri, CancellationToken cancellationToken)
+ {
+ return SendAsyncCore(request, proxyUri, doRequestAuth:false, isProxyConnect:true, cancellationToken);
+ }
+
+ public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, bool doRequestAuth, CancellationToken cancellationToken)
+ {
+ if (_proxy == null)
+ {
+ return SendAsyncCore(request, null, doRequestAuth, isProxyConnect:false, cancellationToken);
+ }
+
+ // Do proxy lookup.
+ Uri proxyUri = null;
+ try
+ {
+ if (!_proxy.IsBypassed(request.RequestUri))
+ {
+ proxyUri = _proxy.GetProxy(request.RequestUri);
+ }
+ }
+ catch (Exception)
+ {
+ // Eat any exception from the IWebProxy and just treat it as no proxy.
+ // This matches the behavior of other handlers.
+ }
+
+ if (proxyUri != null && proxyUri.Scheme != UriScheme.Http)
+ {
+ throw new NotSupportedException(SR.net_http_invalid_proxy_scheme);
+ }
+
+ return SendAsyncCore(request, proxyUri, doRequestAuth, isProxyConnect:false, cancellationToken);
+ }
+
+ /// <summary>Disposes of the pools, disposing of each individual pool.</summary>
+ public void Dispose()
+ {
+ _cleaningTimer.Dispose();
+ foreach (KeyValuePair<HttpConnectionKey, HttpConnectionPool> pool in _pools)
+ {
+ pool.Value.Dispose();
+ }
+
+ if (_proxy is IDisposable obj)
+ {
+ obj.Dispose();
+ }
+ }
+
+ /// <summary>Removes unusable connections from each pool, and removes stale pools entirely.</summary>
+ private void RemoveStalePools()
+ {
+ // Iterate through each pool in the set of pools. For each, ask it to clear out
+ // any unusable connections (e.g. those which have expired, those which have been closed, etc.)
+ // The pool may detect that it's empty and long unused, in which case it'll dispose of itself,
+ // such that any connections returned to the pool to be cached will be disposed of. In such
+ // a case, we also remove the pool from the set of pools to avoid a leak.
+ foreach (KeyValuePair<HttpConnectionKey, HttpConnectionPool> entry in _pools)
+ {
+ if (entry.Value.CleanCacheAndDisposeIfUnused())
+ {
+ _pools.TryRemove(entry.Key, out HttpConnectionPool _);
+ }
+ }
+
+ // Stop running the timer if we don't have any pools to clean up.
+ lock (SyncObj)
+ {
+ if (_pools.IsEmpty)
+ {
+ _cleaningTimer.Change(Timeout.Infinite, Timeout.Infinite);
+ _timerIsRunning = false;
+ }
+ }
+
+ // NOTE: There is a possible race condition with regards to a pool getting cleaned up at the same
+ // time it's about to be used for another request. The timer cleanup could start running, see that
+ // a pool is empty, and initiate its disposal. Concurrently, the pools could hand out the pool
+ // to a request looking to get a connection, because the pool may not have been removed yet
+ // from the pools. Worst case here is that connection will end up getting returned to an
+ // already disposed pool, in which case the connection will also end up getting disposed rather
+ // than reused. This should be a rare occurrence, so for now we don't worry about it. In the
+ // future, there are a variety of possible ways to address it, such as allowing connections to
+ // be returned to pools they weren't associated with.
+ }
+
+ internal readonly struct HttpConnectionKey : IEquatable<HttpConnectionKey>
+ {
+ public readonly HttpConnectionKind Kind;
+ public readonly string Host;
+ public readonly int Port;
+ public readonly string SslHostName; // null if not SSL
+ public readonly Uri ProxyUri;
+
+ public HttpConnectionKey(HttpConnectionKind kind, string host, int port, string sslHostName, Uri proxyUri)
+ {
+ Kind = kind;
+ Host = host;
+ Port = port;
+ SslHostName = sslHostName;
+ ProxyUri = proxyUri;
+ }
+
+ // In the common case, SslHostName (when present) is equal to Host. If so, don't include in hash.
+ public override int GetHashCode() =>
+ (SslHostName == Host ?
+ HashCode.Combine(Kind, Host, Port, ProxyUri) :
+ HashCode.Combine(Kind, Host, Port, SslHostName, ProxyUri));
+
+ public override bool Equals(object obj) =>
+ obj != null &&
+ obj is HttpConnectionKey &&
+ Equals((HttpConnectionKey)obj);
+
+ public bool Equals(HttpConnectionKey other) =>
+ Kind == other.Kind &&
+ Host == other.Host &&
+ Port == other.Port &&
+ ProxyUri == other.ProxyUri &&
+ SslHostName == other.SslHostName;
+
+ public static bool operator ==(HttpConnectionKey key1, HttpConnectionKey key2) => key1.Equals(key2);
+ public static bool operator !=(HttpConnectionKey key1, HttpConnectionKey key2) => !key1.Equals(key2);
+ }
+ }
+}
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionContent.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionResponseContent.cs
index 6ce4fea1cf..9ad4413ad3 100644
--- a/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionContent.cs
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionResponseContent.cs
@@ -9,62 +9,62 @@ using System.Threading.Tasks;
namespace System.Net.Http
{
- internal sealed partial class HttpConnection : IDisposable
+ internal partial class HttpConnection : IDisposable
{
- private sealed class HttpConnectionContent : HttpContent
+ private sealed class HttpConnectionResponseContent : HttpContent
{
- private readonly CancellationToken _cancellationToken;
- private HttpContentReadStream _stream;
-
- public HttpConnectionContent(CancellationToken cancellationToken)
- {
- _cancellationToken = cancellationToken;
- }
+ private HttpContentStream _stream;
+ private bool _consumedStream;
public void SetStream(HttpContentReadStream stream)
{
Debug.Assert(stream != null);
Debug.Assert(stream.CanRead);
+ Debug.Assert(!_consumedStream);
_stream = stream;
}
- private HttpContentReadStream ConsumeStream()
+ internal bool IsEmpty => (_stream == EmptyReadStream.Instance);
+
+ private HttpContentStream ConsumeStream()
{
- if (_stream == null)
+ if (_consumedStream || _stream == null)
{
throw new InvalidOperationException(SR.net_http_content_stream_already_read);
}
+ _consumedStream = true;
- HttpContentReadStream stream = _stream;
- _stream = null;
- return stream;
+ return _stream;
}
- protected override async Task SerializeToStreamAsync(Stream stream, TransportContext context)
+ protected sealed override Task SerializeToStreamAsync(Stream stream, TransportContext context) =>
+ SerializeToStreamAsync(stream, context, CancellationToken.None);
+
+ internal sealed override async Task SerializeToStreamAsync(Stream stream, TransportContext context, CancellationToken cancellationToken)
{
Debug.Assert(stream != null);
using (HttpContentReadStream contentStream = ConsumeStream())
{
const int BufferSize = 8192;
- await contentStream.CopyToAsync(stream, BufferSize, _cancellationToken).ConfigureAwait(false);
+ await contentStream.CopyToAsync(stream, BufferSize, cancellationToken).ConfigureAwait(false);
}
}
- protected internal override bool TryComputeLength(out long length)
+ protected internal sealed override bool TryComputeLength(out long length)
{
length = 0;
return false;
}
- protected override Task<Stream> CreateContentReadStreamAsync() =>
+ protected sealed override Task<Stream> CreateContentReadStreamAsync() =>
Task.FromResult<Stream>(ConsumeStream());
- internal override Stream TryCreateContentReadStream() =>
+ internal sealed override Stream TryCreateContentReadStream() =>
ConsumeStream();
- protected override void Dispose(bool disposing)
+ protected sealed override void Dispose(bool disposing)
{
if (disposing)
{
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionSettings.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionSettings.cs
new file mode 100644
index 0000000000..564a4e1da1
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionSettings.cs
@@ -0,0 +1,75 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Net.Security;
+
+namespace System.Net.Http
+{
+ /// <summary>Provides a state bag of settings for configuring HTTP connections.</summary>
+ internal sealed class HttpConnectionSettings
+ {
+ internal DecompressionMethods _automaticDecompression = HttpHandlerDefaults.DefaultAutomaticDecompression;
+
+ internal bool _useCookies = HttpHandlerDefaults.DefaultUseCookies;
+ internal CookieContainer _cookieContainer;
+
+ internal bool _useProxy = HttpHandlerDefaults.DefaultUseProxy;
+ internal IWebProxy _proxy;
+ internal ICredentials _defaultProxyCredentials;
+
+ internal bool _preAuthenticate = HttpHandlerDefaults.DefaultPreAuthenticate;
+ internal ICredentials _credentials;
+
+ internal bool _allowAutoRedirect = HttpHandlerDefaults.DefaultAutomaticRedirection;
+ internal int _maxAutomaticRedirections = HttpHandlerDefaults.DefaultMaxAutomaticRedirections;
+
+ internal int _maxConnectionsPerServer = HttpHandlerDefaults.DefaultMaxConnectionsPerServer;
+ internal int _maxResponseDrainSize = HttpHandlerDefaults.DefaultMaxResponseDrainSize;
+ internal TimeSpan _maxResponseDrainTime = HttpHandlerDefaults.DefaultResponseDrainTimeout;
+ internal int _maxResponseHeadersLength = HttpHandlerDefaults.DefaultMaxResponseHeadersLength;
+
+ internal TimeSpan _pooledConnectionLifetime = HttpHandlerDefaults.DefaultPooledConnectionLifetime;
+ internal TimeSpan _pooledConnectionIdleTimeout = HttpHandlerDefaults.DefaultPooledConnectionIdleTimeout;
+ internal TimeSpan _expect100ContinueTimeout = HttpHandlerDefaults.DefaultExpect100ContinueTimeout;
+ internal TimeSpan _connectTimeout = HttpHandlerDefaults.DefaultConnectTimeout;
+
+ internal SslClientAuthenticationOptions _sslOptions;
+
+ internal IDictionary<string, object> _properties;
+
+ public HttpConnectionSettings Clone()
+ {
+ // Force creation of the cookie container if needed, so the original and clone share the same instance.
+ if (_useCookies && _cookieContainer == null)
+ {
+ _cookieContainer = new CookieContainer();
+ }
+
+ return new HttpConnectionSettings()
+ {
+ _allowAutoRedirect = _allowAutoRedirect,
+ _automaticDecompression = _automaticDecompression,
+ _cookieContainer = _cookieContainer,
+ _connectTimeout = _connectTimeout,
+ _credentials = _credentials,
+ _defaultProxyCredentials = _defaultProxyCredentials,
+ _expect100ContinueTimeout = _expect100ContinueTimeout,
+ _maxAutomaticRedirections = _maxAutomaticRedirections,
+ _maxConnectionsPerServer = _maxConnectionsPerServer,
+ _maxResponseDrainSize = _maxResponseDrainSize,
+ _maxResponseDrainTime = _maxResponseDrainTime,
+ _maxResponseHeadersLength = _maxResponseHeadersLength,
+ _pooledConnectionLifetime = _pooledConnectionLifetime,
+ _pooledConnectionIdleTimeout = _pooledConnectionIdleTimeout,
+ _preAuthenticate = _preAuthenticate,
+ _properties = _properties,
+ _proxy = _proxy,
+ _sslOptions = _sslOptions?.ShallowClone(), // shallow clone the options for basic prevention of mutation issues while processing
+ _useCookies = _useCookies,
+ _useProxy = _useProxy,
+ };
+ }
+ }
+}
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentDuplexStream.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentDuplexStream.cs
new file mode 100644
index 0000000000..1229b0a626
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentDuplexStream.cs
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Net.Http
+{
+ internal abstract class HttpContentDuplexStream : HttpContentStream
+ {
+ public HttpContentDuplexStream(HttpConnection connection) : base(connection)
+ {
+ }
+
+ public sealed override bool CanRead => true;
+ public sealed override bool CanWrite => true;
+
+ public sealed override void Flush() => FlushAsync().GetAwaiter().GetResult();
+
+ public sealed override int Read(byte[] buffer, int offset, int count)
+ {
+ ValidateBufferArgs(buffer, offset, count);
+ return ReadAsync(new Memory<byte>(buffer, offset, count), CancellationToken.None).GetAwaiter().GetResult();
+ }
+
+ public sealed override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+ {
+ ValidateBufferArgs(buffer, offset, count);
+ return ReadAsync(new Memory<byte>(buffer, offset, count), cancellationToken).AsTask();
+ }
+
+ public sealed override void Write(byte[] buffer, int offset, int count)
+ {
+ ValidateBufferArgs(buffer, offset, count);
+ WriteAsync(new Memory<byte>(buffer, offset, count), CancellationToken.None).GetAwaiter().GetResult();
+ }
+
+ public sealed override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+ {
+ ValidateBufferArgs(buffer, offset, count);
+ return WriteAsync(new ReadOnlyMemory<byte>(buffer, offset, count), cancellationToken).AsTask();
+ }
+
+ public sealed override void CopyTo(Stream destination, int bufferSize) =>
+ CopyToAsync(destination, bufferSize, CancellationToken.None).GetAwaiter().GetResult();
+ }
+}
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentReadStream.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentReadStream.cs
new file mode 100644
index 0000000000..d1c44340d8
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentReadStream.cs
@@ -0,0 +1,113 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Net.Http
+{
+ internal partial class HttpConnection
+ {
+ internal abstract class HttpContentReadStream : HttpContentStream
+ {
+ private int _disposed; // 0==no, 1==yes
+
+ public HttpContentReadStream(HttpConnection connection) : base(connection)
+ {
+ }
+
+ public sealed override bool CanRead => true;
+ public sealed override bool CanWrite => false;
+
+ public sealed override void Flush() { }
+ public sealed override Task FlushAsync(CancellationToken cancellationToken) =>
+ cancellationToken.IsCancellationRequested ?
+ Task.FromCanceled(cancellationToken) :
+ Task.CompletedTask;
+
+ public sealed override void WriteByte(byte value) => throw new NotSupportedException();
+ public sealed override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
+ public sealed override void Write(ReadOnlySpan<byte> source) => throw new NotSupportedException();
+ public sealed override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) => throw new NotSupportedException();
+ public sealed override ValueTask WriteAsync(ReadOnlyMemory<byte> destination, CancellationToken cancellationToken) => throw new NotSupportedException();
+
+ public sealed override int Read(byte[] buffer, int offset, int count)
+ {
+ ValidateBufferArgs(buffer, offset, count);
+ return ReadAsync(new Memory<byte>(buffer, offset, count), CancellationToken.None).GetAwaiter().GetResult();
+ }
+
+ public sealed override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+ {
+ ValidateBufferArgs(buffer, offset, count);
+ return ReadAsync(new Memory<byte>(buffer, offset, count), cancellationToken).AsTask();
+ }
+
+ public sealed override void CopyTo(Stream destination, int bufferSize) =>
+ CopyToAsync(destination, bufferSize, CancellationToken.None).GetAwaiter().GetResult();
+
+ public virtual bool NeedsDrain => false;
+
+ public virtual Task<bool> DrainAsync(int maxDrainBytes)
+ {
+ Debug.Fail($"DrainAsync should not be called for this response stream: {GetType()}");
+ return Task.FromResult(false);
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ // Only attempt draining if we haven't started draining due to disposal; otherwise
+ // multiple calls to Dispose (which happens frequently when someone disposes of the
+ // response stream and response content) will kick off multiple concurrent draining
+ // operations. Also don't delegate to the base if Dispose has already been called,
+ // as doing so will end up disposing of the connection before we're done draining.
+ if (Interlocked.Exchange(ref _disposed, 1) != 0)
+ {
+ return;
+ }
+
+ if (disposing && NeedsDrain)
+ {
+ // Start the asynchronous drain.
+ // It may complete synchronously, in which case the connection will be put back in the pool synchronously.
+ // Skip the call to base.Dispose -- it will be deferred until DrainOnDisposeAsync finishes.
+ DrainOnDisposeAsync();
+ return;
+ }
+
+ base.Dispose(disposing);
+ }
+
+ private async void DrainOnDisposeAsync()
+ {
+ HttpConnection connection = _connection; // Will be null after drain succeeds
+
+ try
+ {
+ bool drained = await DrainAsync(connection._pool.Settings._maxResponseDrainSize).ConfigureAwait(false);
+
+ if (NetEventSource.IsEnabled)
+ {
+ connection.Trace(drained ?
+ "Connection drain succeeded" :
+ $"Connection drain failed because MaxResponseDrainSize of {connection._pool.Settings._maxResponseDrainSize} bytes was exceeded");
+ }
+ }
+ catch (Exception e)
+ {
+ if (NetEventSource.IsEnabled)
+ {
+ connection.Trace($"Connection drain failed due to exception: {e}");
+ }
+
+ // Eat any exceptions and just Dispose.
+ }
+
+ base.Dispose(true);
+ }
+ }
+ }
+}
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentStream.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentStream.cs
new file mode 100644
index 0000000000..be3f2a10c9
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentStream.cs
@@ -0,0 +1,101 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.IO;
+using System.Threading.Tasks;
+
+namespace System.Net.Http
+{
+ internal abstract class HttpContentStream : Stream
+ {
+ protected HttpConnection _connection;
+
+ public HttpContentStream(HttpConnection connection)
+ {
+ _connection = connection;
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ if (_connection != null)
+ {
+ _connection.Dispose();
+ _connection = null;
+ }
+ }
+
+ base.Dispose(disposing);
+ }
+
+ public sealed override bool CanSeek => false;
+
+ public sealed override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) =>
+ TaskToApm.Begin(ReadAsync(buffer, offset, count, default), callback, state);
+
+ public sealed override int EndRead(IAsyncResult asyncResult) =>
+ TaskToApm.End<int>(asyncResult);
+
+ public sealed override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) =>
+ TaskToApm.Begin(WriteAsync(buffer, offset, count, default), callback, state);
+
+ public sealed override void EndWrite(IAsyncResult asyncResult) =>
+ TaskToApm.End(asyncResult);
+
+ public sealed override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
+
+ public sealed override void SetLength(long value) => throw new NotSupportedException();
+
+ public sealed override long Length => throw new NotSupportedException();
+
+ public sealed override long Position
+ {
+ get { throw new NotSupportedException(); }
+ set { throw new NotSupportedException(); }
+ }
+
+ protected static void ValidateBufferArgs(byte[] buffer, int offset, int count)
+ {
+ if (buffer == null)
+ {
+ throw new ArgumentNullException(nameof(buffer));
+ }
+
+ if ((uint)offset > buffer.Length)
+ {
+ throw new ArgumentOutOfRangeException(nameof(offset));
+ }
+
+ if ((uint)count > buffer.Length - offset)
+ {
+ throw new ArgumentOutOfRangeException(nameof(count));
+ }
+ }
+
+ /// <summary>
+ /// Validate the arguments to CopyTo, as would Stream.CopyTo, but with knowledge that
+ /// the source stream is always readable and so only checking the destination.
+ /// </summary>
+ protected static void ValidateCopyToArgs(Stream source, Stream destination, int bufferSize)
+ {
+ if (destination == null)
+ {
+ throw new ArgumentNullException(nameof(destination));
+ }
+
+ if (bufferSize <= 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(bufferSize), bufferSize, SR.ArgumentOutOfRange_NeedPosNum);
+ }
+
+ if (!destination.CanWrite)
+ {
+ throw destination.CanRead ?
+ new NotSupportedException(SR.NotSupported_UnwritableStream) :
+ (Exception)new ObjectDisposedException(nameof(destination), SR.ObjectDisposed_StreamClosed);
+ }
+ }
+ }
+}
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentWriteStream.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentWriteStream.cs
new file mode 100644
index 0000000000..6b7993950a
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpContentWriteStream.cs
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Net.Http
+{
+ internal partial class HttpConnection : IDisposable
+ {
+ private abstract class HttpContentWriteStream : HttpContentStream
+ {
+ public HttpContentWriteStream(HttpConnection connection) : base(connection) =>
+ Debug.Assert(connection != null);
+
+ public sealed override bool CanRead => false;
+ public sealed override bool CanWrite => true;
+
+ public sealed override void Flush() => FlushAsync().GetAwaiter().GetResult();
+
+ public sealed override int Read(byte[] buffer, int offset, int count) => throw new NotSupportedException();
+
+ public sealed override void Write(byte[] buffer, int offset, int count) =>
+ WriteAsync(buffer, offset, count, CancellationToken.None).GetAwaiter().GetResult();
+
+ // The token here is ignored because it's coming from SendAsync and the only operations
+ // here are those that are already covered by the token having been registered with
+ // to close the connection.
+
+ public sealed override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken ignored)
+ {
+ ValidateBufferArgs(buffer, offset, count);
+ return WriteAsync(new ReadOnlyMemory<byte>(buffer, offset, count), ignored).AsTask();
+ }
+
+ public sealed override Task FlushAsync(CancellationToken ignored) =>
+ _connection.FlushAsync().AsTask();
+
+ public abstract Task FinishAsync();
+ }
+ }
+}
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpEnvironmentProxy.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpEnvironmentProxy.cs
new file mode 100644
index 0000000000..9b2beb83b2
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpEnvironmentProxy.cs
@@ -0,0 +1,317 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Net.Http;
+using System.Net;
+using System.Collections.Generic;
+
+namespace System.Net.Http
+{
+ internal sealed class HttpEnvironmentProxyCredentials : ICredentials
+ {
+ // Wrapper class for cases when http and https has different authentication.
+ private readonly NetworkCredential _httpCred;
+ private readonly NetworkCredential _httpsCred;
+ private readonly Uri _httpProxy;
+ private readonly Uri _httpsProxy;
+
+ public HttpEnvironmentProxyCredentials(Uri httpProxy, NetworkCredential httpCred,
+ Uri httpsProxy, NetworkCredential httpsCred)
+ {
+ _httpCred = httpCred;
+ _httpsCred = httpsCred;
+ _httpProxy = httpProxy;
+ _httpsProxy = httpsProxy;
+ }
+
+ public NetworkCredential GetCredential(Uri uri, string authType)
+ {
+ if (uri == null)
+ {
+ return null;
+ }
+ return uri.Equals(_httpProxy) ? _httpCred :
+ uri.Equals(_httpsProxy) ? _httpsCred : null;
+ }
+
+ public static HttpEnvironmentProxyCredentials TryCreate(Uri httpProxy, Uri httpsProxy)
+ {
+ NetworkCredential httpCred = null;
+ NetworkCredential httpsCred = null;
+
+ if (httpProxy != null)
+ {
+ httpCred = GetCredentialsFromString(httpProxy.UserInfo);
+ }
+ if (httpsProxy != null)
+ {
+ httpsCred = GetCredentialsFromString(httpsProxy.UserInfo);
+ }
+ if (httpCred == null && httpsCred == null)
+ {
+ return null;
+ }
+ return new HttpEnvironmentProxyCredentials(httpProxy, httpCred, httpsProxy, httpsCred);
+ }
+
+ /// <summary>
+ /// Converts string containing user:password to NetworkCredential object
+ /// </summary>
+ private static NetworkCredential GetCredentialsFromString(string value)
+ {
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ return null;
+ }
+
+ value = Uri.UnescapeDataString(value);
+
+ string password = "";
+ string domain = null;
+ int idx = value.IndexOf(':');
+ if (idx != -1)
+ {
+ password = value.Substring(idx+1);
+ value = value.Substring(0, idx);
+ }
+
+ idx = value.IndexOf('\\');
+ if (idx != -1)
+ {
+ domain = value.Substring(0, idx);
+ value = value.Substring(idx+1);
+ }
+
+ return new NetworkCredential(value, password, domain);
+ }
+ }
+
+ internal sealed class HttpEnvironmentProxy : IWebProxy
+ {
+ private const string EnvAllProxyUC = "ALL_PROXY";
+ private const string EnvAllProxyLC = "all_proxy";
+ private const string EnvHttpProxyLC = "http_proxy";
+ private const string EnvHttpsProxyLC = "https_proxy";
+ private const string EnvHttpsProxyUC = "HTTPS_PROXY";
+ private const string EnvNoProxyLC = "no_proxy";
+
+ private Uri _httpProxyUri; // String URI for HTTP requests
+ private Uri _httpsProxyUri; // String URI for HTTPS requests
+ private string[] _bypass = null;// list of domains not to proxy
+ private ICredentials _credentials;
+
+ public static bool TryCreate(out IWebProxy proxy)
+ {
+ // Get environmental variables. Protocol specific take precedence over
+ // general all_*, lower case variable has precedence over upper case.
+ // Note that curl uses HTTPS_PROXY but not HTTP_PROXY.
+ // For http, only http_proxy and generic variables are used.
+
+ Uri httpProxy = GetUriFromString(Environment.GetEnvironmentVariable(EnvHttpProxyLC));
+ Uri httpsProxy = GetUriFromString(Environment.GetEnvironmentVariable(EnvHttpsProxyLC)) ??
+ GetUriFromString(Environment.GetEnvironmentVariable(EnvHttpsProxyUC));
+
+ if (httpProxy == null || httpsProxy == null)
+ {
+ Uri allProxy = GetUriFromString(Environment.GetEnvironmentVariable(EnvAllProxyLC)) ??
+ GetUriFromString(Environment.GetEnvironmentVariable(EnvAllProxyUC));
+
+ if (httpProxy == null)
+ {
+ httpProxy = allProxy;
+ }
+ if (httpsProxy == null)
+ {
+ httpsProxy = allProxy;
+ }
+ }
+
+ // Do not instantiate if nothing is set.
+ // Caller may pick some other proxy type.
+ if (httpProxy == null && httpsProxy == null)
+ {
+ proxy = null;
+ return false;
+ }
+
+ proxy = new HttpEnvironmentProxy(httpProxy, httpsProxy, Environment.GetEnvironmentVariable(EnvNoProxyLC));
+ return true;
+ }
+
+ private HttpEnvironmentProxy(Uri httpProxy, Uri httpsProxy, string bypassList)
+ {
+ _httpProxyUri = httpProxy;
+ _httpsProxyUri = httpsProxy;
+
+ _credentials = HttpEnvironmentProxyCredentials.TryCreate(httpProxy, httpsProxy);
+
+ if (!string.IsNullOrWhiteSpace(bypassList))
+ {
+ string[] list = bypassList.Split(',');
+ List<string> tmpList = new List<string>();
+
+ foreach (string value in list)
+ {
+ string tmp = value.Trim();
+ if (tmp.Length > 0)
+ {
+ tmpList.Add(tmp);
+ }
+ }
+ if (tmpList.Count > 0)
+ {
+ _bypass = tmpList.ToArray();
+ }
+ }
+ }
+
+ /// <summary>
+ /// This function will evaluate given string and it will try to convert
+ /// it to Uri object. The string could contain URI fragment, IP address and port
+ /// tuple or just IP address or name. It will return null if parsing fails.
+ /// </summary>
+ private static Uri GetUriFromString(string value)
+ {
+ if (string.IsNullOrEmpty(value))
+ {
+ return null;
+ }
+ if (value.StartsWith("http://", StringComparison.OrdinalIgnoreCase))
+ {
+ value = value.Substring(7);
+ }
+
+ string user = null;
+ string password = null;
+ UInt16 port = 80;
+ string host = null;
+
+ // Check if there is authentication part with user and possibly password.
+ // Curl accepts raw text and that may break URI parser.
+ int separatorIndex = value.LastIndexOf('@');
+ if (separatorIndex != -1)
+ {
+ string auth = value.Substring(0, separatorIndex);
+
+ // The User and password may or may not be URL encoded.
+ // Curl seems to accept both. To match that,
+ // we do opportunistic decode and we use original string if it fails.
+ try
+ {
+ auth = Uri.UnescapeDataString(auth);
+ }
+ catch { };
+
+ value = value.Substring(separatorIndex + 1);
+ separatorIndex = auth.IndexOf(':');
+ if (separatorIndex == -1)
+ {
+ user = auth;
+ }
+ else
+ {
+ user = auth.Substring(0, separatorIndex);
+ password = auth.Substring(separatorIndex + 1);
+ }
+ }
+
+ int ipV6AddressEnd = value.IndexOf(']');
+ separatorIndex = value.LastIndexOf(':');
+ // No ':' or it is part of IPv6 address.
+ if (separatorIndex == -1 || (ipV6AddressEnd != -1 && separatorIndex < ipV6AddressEnd))
+ {
+ host = value;
+ }
+ else
+ {
+ host = value.Substring(0, separatorIndex);
+ if (!UInt16.TryParse(value.AsSpan().Slice(separatorIndex + 1), out port))
+ {
+ return null;
+ }
+ }
+
+ try
+ {
+ UriBuilder ub = new UriBuilder("http", host, port);
+ if (user != null)
+ {
+ ub.UserName = Uri.EscapeDataString(user);
+ }
+
+ if (password != null)
+ {
+ ub.Password = Uri.EscapeDataString(password);
+ }
+
+ return ub.Uri;
+ }
+ catch { };
+ return null;
+ }
+
+ /// <summary>
+ /// This function returns true if given Host match bypass list.
+ /// Note, that the list is common for http and https.
+ /// </summary>
+ private bool IsMatchInBypassList(Uri input)
+ {
+ if (_bypass != null)
+ {
+ foreach (string s in _bypass)
+ {
+ if (s[0] == '.')
+ {
+ // This should match either domain it self or any subdomain or host
+ // .foo.com will match foo.com it self or *.foo.com
+ if ((s.Length - 1) == input.Host.Length &&
+ String.Compare(s, 1, input.Host, 0, input.Host.Length, StringComparison.OrdinalIgnoreCase) == 0)
+ {
+ return true;
+ }
+ else if (input.Host.EndsWith(s, StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+
+ }
+ else
+ {
+ if (String.Equals(s, input.Host, StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /// <summary>
+ /// Gets the proxy URI. (iWebProxy interface)
+ /// </summary>
+ public Uri GetProxy(Uri uri)
+ {
+ return uri.Scheme == Uri.UriSchemeHttp ? _httpProxyUri : _httpsProxyUri;
+ }
+
+ /// <summary>
+ /// Checks if URI is subject to proxy or not.
+ /// </summary>
+ public bool IsBypassed(Uri uri)
+ {
+ return GetProxy(uri) == null ? true : IsMatchInBypassList(uri);
+ }
+
+ public ICredentials Credentials
+ {
+ get
+ {
+ return _credentials;
+ }
+ set { throw new NotSupportedException(); }
+ }
+ }
+}
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpSystemProxy.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpSystemProxy.cs
new file mode 100644
index 0000000000..1a7172f85a
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpSystemProxy.cs
@@ -0,0 +1,186 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+using SafeWinHttpHandle = Interop.WinHttp.SafeWinHttpHandle;
+
+namespace System.Net.Http
+{
+ internal sealed class HttpSystemProxy : IWebProxy, IDisposable
+ {
+ private readonly Uri _proxyUri; // URI of the system proxy if set
+ private string[] _bypass; // list of domains not to proxy
+ private bool _bypassLocal = false; // we should bypass domain considered local
+ private ICredentials _credentials;
+ private readonly WinInetProxyHelper _proxyHelper;
+ private SafeWinHttpHandle _sessionHandle;
+ private bool _disposed;
+
+ public static bool TryCreate(out IWebProxy proxy)
+ {
+ // This will get basic proxy setting from system using existing
+ // WinInetProxyHelper functions. If no proxy is enabled, it will return null.
+ SafeWinHttpHandle sessionHandle = null;
+ proxy = null;
+
+ WinInetProxyHelper proxyHelper = new WinInetProxyHelper();
+ if (!proxyHelper.ManualSettingsOnly && !proxyHelper.AutoSettingsUsed)
+ {
+ return false;
+ }
+ if (proxyHelper.AutoSettingsUsed)
+ {
+ sessionHandle = Interop.WinHttp.WinHttpOpen(
+ IntPtr.Zero,
+ Interop.WinHttp.WINHTTP_ACCESS_TYPE_NO_PROXY,
+ Interop.WinHttp.WINHTTP_NO_PROXY_NAME,
+ Interop.WinHttp.WINHTTP_NO_PROXY_BYPASS,
+ (int)Interop.WinHttp.WINHTTP_FLAG_ASYNC);
+ if (sessionHandle.IsInvalid)
+ {
+ // Proxy failures are currently ignored by managed handler.
+ return false;
+ }
+ }
+ proxy = new HttpSystemProxy(proxyHelper, sessionHandle);
+ return true;
+ }
+
+ private HttpSystemProxy(WinInetProxyHelper proxyHelper, SafeWinHttpHandle sessionHandle)
+ {
+ _proxyHelper = proxyHelper;
+ _sessionHandle = sessionHandle;
+
+ if (proxyHelper.ManualSettingsOnly)
+ {
+ _proxyUri = GetUriFromString(proxyHelper.Proxy);
+
+ if (!string.IsNullOrWhiteSpace(proxyHelper.ProxyBypass))
+ {
+ // Process bypass list for manual setting.
+ string[] list = proxyHelper.ProxyBypass.Split(';');
+ List<string> tmpList = new List<string>();
+
+ foreach (string value in list)
+ {
+ string tmp = value.Trim();
+ if (tmp == "<local>")
+ {
+ _bypassLocal = true;
+ continue;
+ }
+ if (tmp.Length > 0)
+ {
+ tmpList.Add(tmp);
+ }
+ }
+ if (tmpList.Count > 0)
+ {
+ _bypass = tmpList.ToArray();
+ }
+ }
+ }
+ }
+
+ public void Dispose()
+ {
+ if (!_disposed)
+ {
+ _disposed = true;
+
+ if (_sessionHandle != null && !_sessionHandle.IsInvalid)
+ {
+ SafeWinHttpHandle.DisposeAndClearHandle(ref _sessionHandle);
+ }
+ }
+ }
+
+ /// <summary>
+ /// This function will evaluate given string and it will try to convert
+ /// it to Uri object. The string could contain URI fragment, IP address and port
+ /// tuple or just IP address or name. It will return null if parsing fails.
+ /// </summary>
+ private static Uri GetUriFromString(string value)
+ {
+ if (string.IsNullOrEmpty(value))
+ {
+ return null;
+ }
+
+ if (!value.Contains("://"))
+ {
+ value = "http://" + value;
+ }
+
+ if (Uri.TryCreate(value, UriKind.Absolute, out Uri uri) &&
+ (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps))
+ {
+ // We only support http and https for now.
+ return uri;
+ }
+ return null;
+ }
+
+ /// <summary>
+ /// Gets the proxy URI. (IWebProxy interface)
+ /// </summary>
+ public Uri GetProxy(Uri uri)
+ {
+ if (_proxyHelper.ManualSettingsOnly)
+ {
+ return _proxyUri;
+ }
+ var proxyInfo = new Interop.WinHttp.WINHTTP_PROXY_INFO();
+ try
+ {
+ if (_proxyHelper.GetProxyForUrl(_sessionHandle, uri, out proxyInfo))
+ {
+ return GetUriFromString(Marshal.PtrToStringUni(proxyInfo.Proxy));
+ }
+ }
+ finally
+ {
+ Marshal.FreeHGlobal(proxyInfo.Proxy);
+ Marshal.FreeHGlobal(proxyInfo.ProxyBypass);
+ }
+ return null;
+ }
+
+ /// <summary>
+ /// Checks if URI is subject to proxy or not.
+ /// </summary>
+ public bool IsBypassed(Uri uri)
+ {
+ if (_proxyHelper.ManualSettingsOnly)
+ {
+ if (_bypassLocal)
+ {
+ // TODO #23150: implement bypass match.
+ }
+ return false;
+ }
+ else if (_proxyHelper.AutoSettingsUsed)
+ {
+ // Always return false for now to avoid query to WinHtttp.
+ // If URI should be bypassed GetProxy() will return null;
+ return false;
+ }
+ return true;
+ }
+
+ public ICredentials Credentials
+ {
+ get
+ {
+ return _credentials;
+ }
+ set
+ {
+ _credentials = value;
+ }
+ }
+ }
+}
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RawConnectionStream.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RawConnectionStream.cs
new file mode 100644
index 0000000000..6eba9babd3
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RawConnectionStream.cs
@@ -0,0 +1,182 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Net.Http
+{
+ internal partial class HttpConnection : IDisposable
+ {
+ private sealed class RawConnectionStream : HttpContentDuplexStream
+ {
+ public RawConnectionStream(HttpConnection connection) : base(connection)
+ {
+ }
+
+ public override async ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken)
+ {
+ CancellationHelper.ThrowIfCancellationRequested(cancellationToken);
+
+ if (_connection == null || buffer.Length == 0)
+ {
+ // Response body fully consumed or the caller didn't ask for any data
+ return 0;
+ }
+
+ ValueTask<int> readTask = _connection.ReadBufferedAsync(buffer);
+ int bytesRead;
+ if (readTask.IsCompletedSuccessfully)
+ {
+ bytesRead = readTask.Result;
+ }
+ else
+ {
+ CancellationTokenRegistration ctr = _connection.RegisterCancellation(cancellationToken);
+ try
+ {
+ bytesRead = await readTask.ConfigureAwait(false);
+ }
+ catch (Exception exc) when (CancellationHelper.ShouldWrapInOperationCanceledException(exc, cancellationToken))
+ {
+ throw CancellationHelper.CreateOperationCanceledException(exc, cancellationToken);
+ }
+ finally
+ {
+ ctr.Dispose();
+ }
+ }
+
+ if (bytesRead == 0)
+ {
+ // A cancellation request may have caused the EOF.
+ CancellationHelper.ThrowIfCancellationRequested(cancellationToken);
+
+ // We cannot reuse this connection, so close it.
+ _connection.Dispose();
+ _connection = null;
+ return 0;
+ }
+
+ return bytesRead;
+ }
+
+ public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
+ {
+ ValidateCopyToArgs(this, destination, bufferSize);
+
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return Task.FromCanceled(cancellationToken);
+ }
+
+ if (_connection == null)
+ {
+ // null if response body fully consumed
+ return Task.CompletedTask;
+ }
+
+ Task copyTask = _connection.CopyToUntilEofAsync(destination, bufferSize, cancellationToken);
+ if (copyTask.IsCompletedSuccessfully)
+ {
+ Finish();
+ return Task.CompletedTask;
+ }
+
+ return CompleteCopyToAsync(copyTask, cancellationToken);
+ }
+
+ private async Task CompleteCopyToAsync(Task copyTask, CancellationToken cancellationToken)
+ {
+ CancellationTokenRegistration ctr = _connection.RegisterCancellation(cancellationToken);
+ try
+ {
+ await copyTask.ConfigureAwait(false);
+ }
+ catch (Exception exc) when (CancellationHelper.ShouldWrapInOperationCanceledException(exc, cancellationToken))
+ {
+ throw CancellationHelper.CreateOperationCanceledException(exc, cancellationToken);
+ }
+ finally
+ {
+ ctr.Dispose();
+ }
+
+ // If cancellation is requested and tears down the connection, it could cause the copy
+ // to end early but think it ended successfully. So we prioritize cancellation in this
+ // race condition, and if we find after the copy has completed that cancellation has
+ // been requested, we assume the copy completed due to cancellation and throw.
+ CancellationHelper.ThrowIfCancellationRequested(cancellationToken);
+
+ Finish();
+ }
+
+ private void Finish()
+ {
+ // We cannot reuse this connection, so close it.
+ _connection.Dispose();
+ _connection = null;
+ }
+
+ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return new ValueTask(Task.FromCanceled(cancellationToken));
+ }
+
+ if (_connection == null)
+ {
+ return new ValueTask(Task.FromException(new IOException(SR.net_http_io_write)));
+ }
+
+ if (buffer.Length == 0)
+ {
+ return default;
+ }
+
+ ValueTask writeTask = _connection.WriteWithoutBufferingAsync(buffer);
+ return writeTask.IsCompleted ?
+ writeTask :
+ new ValueTask(WaitWithConnectionCancellationAsync(writeTask, cancellationToken));
+ }
+
+ public override Task FlushAsync(CancellationToken cancellationToken)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return Task.FromCanceled(cancellationToken);
+ }
+
+ if (_connection == null)
+ {
+ return Task.CompletedTask;
+ }
+
+ ValueTask flushTask = _connection.FlushAsync();
+ return flushTask.IsCompleted ?
+ flushTask.AsTask() :
+ WaitWithConnectionCancellationAsync(flushTask, cancellationToken);
+ }
+
+ private async Task WaitWithConnectionCancellationAsync(ValueTask task, CancellationToken cancellationToken)
+ {
+ CancellationTokenRegistration ctr = _connection.RegisterCancellation(cancellationToken);
+ try
+ {
+ await task.ConfigureAwait(false);
+ }
+ catch (Exception exc) when (CancellationHelper.ShouldWrapInOperationCanceledException(exc, cancellationToken))
+ {
+ throw CancellationHelper.CreateOperationCanceledException(exc, cancellationToken);
+ }
+ finally
+ {
+ ctr.Dispose();
+ }
+ }
+ }
+ }
+}
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RedirectHandler.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RedirectHandler.cs
new file mode 100644
index 0000000000..df723247ce
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RedirectHandler.cs
@@ -0,0 +1,150 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Net.Http
+{
+ internal sealed partial class RedirectHandler : HttpMessageHandler
+ {
+ private readonly HttpMessageHandler _initialInnerHandler; // Used for initial request
+ private readonly HttpMessageHandler _redirectInnerHandler; // Used for redirects; this allows disabling auth
+ private readonly int _maxAutomaticRedirections;
+
+ public RedirectHandler(int maxAutomaticRedirections, HttpMessageHandler initialInnerHandler, HttpMessageHandler redirectInnerHandler)
+ {
+ Debug.Assert(initialInnerHandler != null);
+ Debug.Assert(redirectInnerHandler != null);
+ Debug.Assert(maxAutomaticRedirections > 0);
+
+ _maxAutomaticRedirections = maxAutomaticRedirections;
+ _initialInnerHandler = initialInnerHandler;
+ _redirectInnerHandler = redirectInnerHandler;
+ }
+
+ protected internal override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ HttpResponseMessage response = await _initialInnerHandler.SendAsync(request, cancellationToken).ConfigureAwait(false);
+
+ uint redirectCount = 0;
+ Uri redirectUri;
+ while ((redirectUri = GetUriForRedirect(request.RequestUri, response)) != null)
+ {
+ redirectCount++;
+
+ if (redirectCount > _maxAutomaticRedirections)
+ {
+ // If we exceed the maximum number of redirects
+ // then just return the 3xx response.
+ if (NetEventSource.IsEnabled)
+ {
+ NetEventSource.Info(this, $"Exceeded max number of redirects. Redirect from {request.RequestUri} to {redirectUri} blocked.");
+ }
+
+ break;
+ }
+
+ response.Dispose();
+
+ // Clear the authorization header.
+ request.Headers.Authorization = null;
+
+ // Set up for the redirect
+ request.RequestUri = redirectUri;
+ if (RequestRequiresForceGet(response.StatusCode, request.Method))
+ {
+ request.Method = HttpMethod.Get;
+ request.Content = null;
+ request.Headers.TransferEncodingChunked = false;
+ }
+
+ // Issue the redirected request.
+ response = await _redirectInnerHandler.SendAsync(request, cancellationToken).ConfigureAwait(false);
+ }
+
+ return response;
+ }
+
+ private Uri GetUriForRedirect(Uri requestUri, HttpResponseMessage response)
+ {
+ switch (response.StatusCode)
+ {
+ case HttpStatusCode.Moved:
+ case HttpStatusCode.Found:
+ case HttpStatusCode.SeeOther:
+ case HttpStatusCode.TemporaryRedirect:
+ case HttpStatusCode.MultipleChoices:
+ break;
+
+ default:
+ return null;
+ }
+
+ Uri location = response.Headers.Location;
+ if (location == null)
+ {
+ return null;
+ }
+
+ // Ensure the redirect location is an absolute URI.
+ if (!location.IsAbsoluteUri)
+ {
+ location = new Uri(requestUri, location);
+ }
+
+ // Per https://tools.ietf.org/html/rfc7231#section-7.1.2, a redirect location without a
+ // fragment should inherit the fragment from the original URI.
+ string requestFragment = requestUri.Fragment;
+ if (!string.IsNullOrEmpty(requestFragment))
+ {
+ string redirectFragment = location.Fragment;
+ if (string.IsNullOrEmpty(redirectFragment))
+ {
+ location = new UriBuilder(location) { Fragment = requestFragment }.Uri;
+ }
+ }
+
+ // Disallow automatic redirection from secure to non-secure schemes
+ if (HttpUtilities.IsSupportedSecureScheme(requestUri.Scheme) && !HttpUtilities.IsSupportedSecureScheme(location.Scheme))
+ {
+ if (NetEventSource.IsEnabled)
+ {
+ NetEventSource.Info(this, $"Insecure https to http redirect from '{requestUri}' to '{location}' blocked.");
+ }
+
+ return null;
+ }
+
+ return location;
+ }
+
+ private static bool RequestRequiresForceGet(HttpStatusCode statusCode, HttpMethod requestMethod)
+ {
+ switch (statusCode)
+ {
+ case HttpStatusCode.Moved:
+ case HttpStatusCode.Found:
+ case HttpStatusCode.SeeOther:
+ case HttpStatusCode.MultipleChoices:
+ return requestMethod == HttpMethod.Post;
+ default:
+ return false;
+ }
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _initialInnerHandler.Dispose();
+ _redirectInnerHandler.Dispose();
+ }
+
+ base.Dispose(disposing);
+ }
+ }
+}
+
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/ManagedHandler.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs
index 14029888fb..c276cbf25f 100644
--- a/src/System.Net.Http/src/System/Net/Http/Managed/ManagedHandler.cs
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs
@@ -4,14 +4,12 @@
using System.Collections.Generic;
using System.Net.Security;
-using System.Security.Authentication;
-using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
namespace System.Net.Http
{
- internal sealed class ManagedHandler : HttpMessageHandler
+ public sealed class SocketsHttpHandler : HttpMessageHandler
{
private readonly HttpConnectionSettings _settings = new HttpConnectionSettings();
private HttpMessageHandler _handler;
@@ -21,7 +19,7 @@ namespace System.Net.Http
{
if (_disposed)
{
- throw new ObjectDisposedException(nameof(ManagedHandler));
+ throw new ObjectDisposedException(nameof(SocketsHttpHandler));
}
}
@@ -34,12 +32,6 @@ namespace System.Net.Http
}
}
- public bool SupportsAutomaticDecompression => true;
-
- public bool SupportsProxy => true;
-
- public bool SupportsRedirectConfiguration => true;
-
public bool UseCookies
{
get => _settings._useCookies;
@@ -60,22 +52,6 @@ namespace System.Net.Http
}
}
- public ClientCertificateOption ClientCertificateOptions
- {
- get => _settings._clientCertificateOptions;
- set
- {
- if (value != ClientCertificateOption.Manual &&
- value != ClientCertificateOption.Automatic)
- {
- throw new ArgumentOutOfRangeException(nameof(value));
- }
-
- CheckDisposedOrStarted();
- _settings._clientCertificateOptions = value;
- }
- }
-
public DecompressionMethods AutomaticDecompression
{
get => _settings._automaticDecompression;
@@ -126,16 +102,6 @@ namespace System.Net.Http
}
}
- public bool UseDefaultCredentials
- {
- get => _settings._useDefaultCredentials;
- set
- {
- CheckDisposedOrStarted();
- _settings._useDefaultCredentials = value;
- }
- }
-
public ICredentials Credentials
{
get => _settings._credentials;
@@ -186,6 +152,37 @@ namespace System.Net.Http
}
}
+ public int MaxResponseDrainSize
+ {
+ get => _settings._maxResponseDrainSize;
+ set
+ {
+ if (value < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value), value, SR.ArgumentOutOfRange_NeedNonNegativeNum);
+ }
+
+ CheckDisposedOrStarted();
+ _settings._maxResponseDrainSize = value;
+ }
+ }
+
+ public TimeSpan ResponseDrainTimeout
+ {
+ get => _settings._maxResponseDrainTime;
+ set
+ {
+ if ((value < TimeSpan.Zero && value != Timeout.InfiniteTimeSpan) ||
+ (value.TotalMilliseconds > int.MaxValue))
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
+ CheckDisposedOrStarted();
+ _settings._maxResponseDrainTime = value;
+ }
+ }
+
public int MaxResponseHeadersLength
{
get => _settings._maxResponseHeadersLength;
@@ -201,47 +198,75 @@ namespace System.Net.Http
}
}
- public X509CertificateCollection ClientCertificates
+ public SslClientAuthenticationOptions SslOptions
+ {
+ get => _settings._sslOptions ?? (_settings._sslOptions = new SslClientAuthenticationOptions());
+ set
+ {
+ CheckDisposedOrStarted();
+ _settings._sslOptions = value;
+ }
+ }
+
+ public TimeSpan PooledConnectionLifetime
{
- get
+ get => _settings._pooledConnectionLifetime;
+ set
{
- if (_settings._clientCertificateOptions != ClientCertificateOption.Manual)
+ if (value < TimeSpan.Zero && value != Timeout.InfiniteTimeSpan)
{
- throw new InvalidOperationException(SR.Format(SR.net_http_invalid_enable_first, nameof(ClientCertificateOptions), nameof(ClientCertificateOption.Manual)));
+ throw new ArgumentOutOfRangeException(nameof(value));
}
- return _settings._clientCertificates ?? (_settings._clientCertificates = new X509Certificate2Collection());
+ CheckDisposedOrStarted();
+ _settings._pooledConnectionLifetime = value;
}
}
- public Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> ServerCertificateCustomValidationCallback
+ public TimeSpan PooledConnectionIdleTimeout
{
- get => _settings._serverCertificateCustomValidationCallback;
+ get => _settings._pooledConnectionIdleTimeout;
set
{
+ if (value < TimeSpan.Zero && value != Timeout.InfiniteTimeSpan)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
CheckDisposedOrStarted();
- _settings._serverCertificateCustomValidationCallback = value;
+ _settings._pooledConnectionIdleTimeout = value;
}
}
- public bool CheckCertificateRevocationList
+ public TimeSpan ConnectTimeout
{
- get => _settings._checkCertificateRevocationList;
+ get => _settings._connectTimeout;
set
{
+ if ((value <= TimeSpan.Zero && value != Timeout.InfiniteTimeSpan) ||
+ (value.TotalMilliseconds > int.MaxValue))
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
CheckDisposedOrStarted();
- _settings._checkCertificateRevocationList = value;
+ _settings._connectTimeout = value;
}
}
- public SslProtocols SslProtocols
+ public TimeSpan Expect100ContinueTimeout
{
- get => _settings._sslProtocols;
+ get => _settings._expect100ContinueTimeout;
set
{
- SecurityProtocol.ThrowOnNotAllowed(value, allowNone: true);
+ if ((value < TimeSpan.Zero && value != Timeout.InfiniteTimeSpan) ||
+ (value.TotalMilliseconds > int.MaxValue))
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
CheckDisposedOrStarted();
- _settings._sslProtocols = value;
+ _settings._expect100ContinueTimeout = value;
}
}
@@ -261,38 +286,48 @@ namespace System.Net.Http
private HttpMessageHandler SetupHandlerChain()
{
- HttpMessageHandler handler = new HttpConnectionHandler(_settings);
+ // Clone the settings to get a relatively consistent view that won't change after this point.
+ // (This isn't entirely complete, as some of the collections it contains aren't currently deeply cloned.)
+ HttpConnectionSettings settings = _settings.Clone();
- if (_settings._useProxy &&
- (_settings._proxy != null || HttpProxyConnectionHandler.EnvironmentProxyConfigured))
- {
- handler = new HttpProxyConnectionHandler(_settings, handler);
- }
+ HttpConnectionPoolManager poolManager = new HttpConnectionPoolManager(settings);
+
+ HttpMessageHandler handler;
- if (_settings._useCookies)
+ if (settings._credentials == null)
{
- handler = new CookieHandler(CookieContainer, handler);
+ handler = new HttpConnectionHandler(poolManager);
}
-
- if (_settings._credentials != null || _settings._allowAutoRedirect)
+ else
{
- handler = new AuthenticateAndRedirectHandler(_settings._preAuthenticate, _settings._credentials, _settings._allowAutoRedirect, _settings._maxAutomaticRedirections, handler);
+ handler = new HttpAuthenticatedConnectionHandler(poolManager);
}
- if (_settings._automaticDecompression != DecompressionMethods.None)
+ if (settings._allowAutoRedirect)
{
- handler = new DecompressionHandler(_settings._automaticDecompression, handler);
+ // Just as with WinHttpHandler and CurlHandler, for security reasons, we do not support authentication on redirects
+ // if the credential is anything other than a CredentialCache.
+ // We allow credentials in a CredentialCache since they are specifically tied to URIs.
+ HttpMessageHandler redirectHandler =
+ (settings._credentials == null || settings._credentials is CredentialCache) ?
+ handler :
+ new HttpConnectionHandler(poolManager); // will not authenticate
+
+ handler = new RedirectHandler(settings._maxAutomaticRedirections, handler, redirectHandler);
}
- if (Interlocked.CompareExchange(ref _handler, handler, null) == null)
+ if (settings._automaticDecompression != DecompressionMethods.None)
{
- return handler;
+ handler = new DecompressionHandler(settings._automaticDecompression, handler);
}
- else
+
+ // Ensure a single handler is used for all requests.
+ if (Interlocked.CompareExchange(ref _handler, handler, null) != null)
{
handler.Dispose();
- return _handler;
}
+
+ return _handler;
}
protected internal override Task<HttpResponseMessage> SendAsync(
@@ -300,7 +335,58 @@ namespace System.Net.Http
{
CheckDisposed();
HttpMessageHandler handler = _handler ?? SetupHandlerChain();
+
+ Exception error = ValidateAndNormalizeRequest(request);
+ if (error != null)
+ {
+ return Task.FromException<HttpResponseMessage>(error);
+ }
+
return handler.SendAsync(request, cancellationToken);
}
+
+ private Exception ValidateAndNormalizeRequest(HttpRequestMessage request)
+ {
+ if (request.Version.Major == 0)
+ {
+ return new NotSupportedException(SR.net_http_unsupported_version);
+ }
+
+ // Add headers to define content transfer, if not present
+ if (request.HasHeaders && request.Headers.TransferEncodingChunked.GetValueOrDefault())
+ {
+ if (request.Content == null)
+ {
+ return new HttpRequestException(SR.net_http_client_execution_error,
+ new InvalidOperationException(SR.net_http_chunked_not_allowed_with_empty_content));
+ }
+
+ // Since the user explicitly set TransferEncodingChunked to true, we need to remove
+ // the Content-Length header if present, as sending both is invalid.
+ request.Content.Headers.ContentLength = null;
+ }
+ else if (request.Content != null && request.Content.Headers.ContentLength == null)
+ {
+ // We have content, but neither Transfer-Encoding nor Content-Length is set.
+ request.Headers.TransferEncodingChunked = true;
+ }
+
+ if (request.Version.Minor == 0 && request.Version.Major == 1 && request.HasHeaders)
+ {
+ // HTTP 1.0 does not support chunking
+ if (request.Headers.TransferEncodingChunked == true)
+ {
+ return new NotSupportedException(SR.net_http_unsupported_chunking);
+ }
+
+ // HTTP 1.0 does not support Expect: 100-continue; just disable it.
+ if (request.Headers.ExpectContinue == true)
+ {
+ request.Headers.ExpectContinue = false;
+ }
+ }
+
+ return null;
+ }
}
}
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SystemProxyInfo.Unix.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SystemProxyInfo.Unix.cs
new file mode 100644
index 0000000000..4c79a8eb05
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SystemProxyInfo.Unix.cs
@@ -0,0 +1,16 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Net.Http
+{
+ internal static class SystemProxyInfo
+ {
+ // On Unix we get default proxy configuration from environment variables
+ public static IWebProxy ConstructSystemProxy()
+ {
+ return HttpEnvironmentProxy.TryCreate(out IWebProxy proxy) ? proxy : null;
+ }
+ }
+}
+
diff --git a/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SystemProxyInfo.Windows.cs b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SystemProxyInfo.Windows.cs
new file mode 100644
index 0000000000..0994bf54a9
--- /dev/null
+++ b/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SystemProxyInfo.Windows.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Net.Http
+{
+ internal static class SystemProxyInfo
+ {
+ public static IWebProxy ConstructSystemProxy()
+ {
+ return HttpSystemProxy.TryCreate(out IWebProxy proxy) ? proxy : null;
+ }
+ }
+}
+
diff --git a/src/System.Net.Http/src/System/Net/Http/StreamContent.cs b/src/System.Net.Http/src/System/Net/Http/StreamContent.cs
index edc8c3d826..acb84c0efb 100644
--- a/src/System.Net.Http/src/System/Net/Http/StreamContent.cs
+++ b/src/System.Net.Http/src/System/Net/Http/StreamContent.cs
@@ -11,16 +11,20 @@ namespace System.Net.Http
{
public class StreamContent : HttpContent
{
- private const int DefaultBufferSize = 4096;
-
private Stream _content;
private int _bufferSize;
private bool _contentConsumed;
private long _start;
public StreamContent(Stream content)
- : this(content, DefaultBufferSize)
{
+ if (content == null)
+ {
+ throw new ArgumentNullException(nameof(content));
+ }
+
+ // Indicate that we should use default buffer size by setting size to 0.
+ InitializeContent(content, 0);
}
public StreamContent(Stream content, int bufferSize)
@@ -34,6 +38,11 @@ namespace System.Net.Http
throw new ArgumentOutOfRangeException(nameof(bufferSize));
}
+ InitializeContent(content, bufferSize);
+ }
+
+ private void InitializeContent(Stream content, int bufferSize)
+ {
_content = content;
_bufferSize = bufferSize;
if (content.CanSeek)
@@ -143,7 +152,7 @@ namespace System.Net.Http
throw new NotSupportedException(SR.net_http_content_readonly_stream);
}
- public override void Write(ReadOnlySpan<byte> source)
+ public override void Write(ReadOnlySpan<byte> buffer)
{
throw new NotSupportedException(SR.net_http_content_readonly_stream);
}
@@ -158,7 +167,7 @@ namespace System.Net.Http
throw new NotSupportedException(SR.net_http_content_readonly_stream);
}
- public override Task WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken = default)
+ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
{
throw new NotSupportedException(SR.net_http_content_readonly_stream);
}
diff --git a/src/System.Net.Http/src/System/Net/Http/StreamToStreamCopy.cs b/src/System.Net.Http/src/System/Net/Http/StreamToStreamCopy.cs
index 05e453c2a8..2a74c5cc79 100644
--- a/src/System.Net.Http/src/System/Net/Http/StreamToStreamCopy.cs
+++ b/src/System.Net.Http/src/System/Net/Http/StreamToStreamCopy.cs
@@ -19,18 +19,20 @@ namespace System.Net.Http
/// <summary>Copies the source stream from its current position to the destination stream at its current position.</summary>
/// <param name="source">The source stream from which to copy.</param>
/// <param name="destination">The destination stream to which to copy.</param>
- /// <param name="bufferSize">The size of the buffer to allocate if one needs to be allocated.</param>
+ /// <param name="bufferSize">The size of the buffer to allocate if one needs to be allocated. If zero, use the default buffer size.</param>
/// <param name="disposeSource">Whether to dispose of the source stream after the copy has finished successfully.</param>
/// <param name="cancellationToken">CancellationToken used to cancel the copy operation.</param>
public static Task CopyAsync(Stream source, Stream destination, int bufferSize, bool disposeSource, CancellationToken cancellationToken = default(CancellationToken))
{
Debug.Assert(source != null);
Debug.Assert(destination != null);
- Debug.Assert(bufferSize > 0);
+ Debug.Assert(bufferSize >= 0);
try
{
- Task copyTask = source.CopyToAsync(destination, bufferSize, cancellationToken);
+ Task copyTask = bufferSize == 0 ?
+ source.CopyToAsync(destination, cancellationToken) :
+ source.CopyToAsync(destination, bufferSize, cancellationToken);
return disposeSource ?
DisposeSourceWhenCompleteAsync(copyTask, source) :
copyTask;
diff --git a/src/System.Net.Http/tests/FunctionalTests/CancellationTest.cs b/src/System.Net.Http/tests/FunctionalTests/CancellationTest.cs
deleted file mode 100644
index f29922b17c..0000000000
--- a/src/System.Net.Http/tests/FunctionalTests/CancellationTest.cs
+++ /dev/null
@@ -1,162 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-using System.IO;
-using System.Net.Test.Common;
-using System.Threading;
-using System.Threading.Tasks;
-
-using Xunit;
-using Xunit.Abstractions;
-
-namespace System.Net.Http.Functional.Tests
-{
- public class CancellationTest : HttpClientTestBase
- {
- private readonly ITestOutputHelper _output;
-
- public CancellationTest(ITestOutputHelper output)
- {
- _output = output;
- }
-
- [OuterLoop] // includes seconds of delay
- [Theory]
- [InlineData(false, false)]
- [InlineData(false, true)]
- [InlineData(true, false)]
- [InlineData(true, true)]
- [ActiveIssue("dotnet/corefx #20010", TargetFrameworkMonikers.Uap)]
- [ActiveIssue("dotnet/corefx #19038", TargetFrameworkMonikers.NetFramework)]
- public async Task GetAsync_ResponseContentRead_CancelUsingTimeoutOrToken_TaskCanceledQuickly(
- bool useTimeout, bool startResponseBody)
- {
- var cts = new CancellationTokenSource(); // ignored if useTimeout==true
- TimeSpan timeout = useTimeout ? new TimeSpan(0, 0, 1) : Timeout.InfiniteTimeSpan;
- CancellationToken cancellationToken = useTimeout ? CancellationToken.None : cts.Token;
-
- using (HttpClient client = CreateHttpClient())
- {
- client.Timeout = timeout;
-
- var triggerResponseWrite = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
- var triggerRequestCancel = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
-
- await LoopbackServer.CreateServerAsync(async (server, url) =>
- {
- Task serverTask = LoopbackServer.AcceptSocketAsync(server, async (socket, stream, reader, writer) =>
- {
- while (!string.IsNullOrEmpty(await reader.ReadLineAsync())) ;
- await writer.WriteAsync(
- "HTTP/1.1 200 OK\r\n" +
- $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
- "Content-Length: 16000\r\n" +
- "\r\n" +
- (startResponseBody ? "less than 16000 bytes" : ""));
-
- await Task.Delay(1000);
- triggerRequestCancel.SetResult(true); // allow request to cancel
- await triggerResponseWrite.Task; // pause until we're released
-
- return null;
- });
-
- var stopwatch = Stopwatch.StartNew();
- if (PlatformDetection.IsFullFramework)
- {
- // .NET Framework throws WebException instead of OperationCanceledException.
- await Assert.ThrowsAnyAsync<WebException>(async () =>
- {
- Task<HttpResponseMessage> getResponse = client.GetAsync(url, HttpCompletionOption.ResponseContentRead, cancellationToken);
- await triggerRequestCancel.Task;
- cts.Cancel();
- await getResponse;
- });
- }
- else
- {
- await Assert.ThrowsAnyAsync<OperationCanceledException>(async () =>
- {
- Task<HttpResponseMessage> getResponse = client.GetAsync(url, HttpCompletionOption.ResponseContentRead, cancellationToken);
- await triggerRequestCancel.Task;
- cts.Cancel();
- await getResponse;
- });
- }
- stopwatch.Stop();
- _output.WriteLine("GetAsync() completed at: {0}", stopwatch.Elapsed.ToString());
-
- triggerResponseWrite.SetResult(true);
- Assert.True(stopwatch.Elapsed < new TimeSpan(0, 0, 30), $"Elapsed time {stopwatch.Elapsed} should be less than 30 seconds, was {stopwatch.Elapsed.TotalSeconds}");
- });
- }
- }
-
- [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "dotnet/corefx #18864")] // Hangs on NETFX
- [ActiveIssue(9075, TestPlatforms.AnyUnix)] // recombine this test into the subsequent one when issue is fixed
- [OuterLoop] // includes seconds of delay
- [Fact]
- public Task ReadAsStreamAsync_ReadAsync_Cancel_BodyNeverStarted_TaskCanceledQuickly()
- {
- return ReadAsStreamAsync_ReadAsync_Cancel_TaskCanceledQuickly(false);
- }
-
- [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "dotnet/corefx #18864")] // Hangs on NETFX
- [OuterLoop] // includes seconds of delay
- [Theory]
- [InlineData(true)]
- public async Task ReadAsStreamAsync_ReadAsync_Cancel_TaskCanceledQuickly(bool startResponseBody)
- {
- using (HttpClient client = CreateHttpClient())
- {
- await LoopbackServer.CreateServerAsync(async (server, url) =>
- {
- var triggerResponseWrite = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
-
- Task serverTask = LoopbackServer.AcceptSocketAsync(server, async (socket, stream, reader, writer) =>
- {
- while (!string.IsNullOrEmpty(await reader.ReadLineAsync())) ;
- await writer.WriteAsync(
- "HTTP/1.1 200 OK\r\n" +
- $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
- "Content-Length: 16000\r\n" +
- "\r\n" +
- (startResponseBody ? "20 bytes of the body" : ""));
-
- await triggerResponseWrite.Task; // pause until we're released
-
- return null;
- });
-
- using (HttpResponseMessage response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))
- using (Stream responseStream = await response.Content.ReadAsStreamAsync())
- {
- // Read all expected content
- byte[] buffer = new byte[20];
- if (startResponseBody)
- {
- int totalRead = 0;
- int bytesRead;
- while (totalRead < 20 && (bytesRead = await responseStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
- {
- totalRead += bytesRead;
- }
- }
-
- // Now do a read that'll need to be canceled
- var stopwatch = Stopwatch.StartNew();
- await Assert.ThrowsAnyAsync<OperationCanceledException>(
- () => responseStream.ReadAsync(buffer, 0, buffer.Length, new CancellationTokenSource(1000).Token));
- stopwatch.Stop();
-
- triggerResponseWrite.SetResult(true);
- _output.WriteLine("ReadAsync() completed at: {0}", stopwatch.Elapsed.ToString());
- Assert.True(stopwatch.Elapsed < new TimeSpan(0, 0, 30), $"Elapsed time {stopwatch.Elapsed} should be less than 30 seconds, was {stopwatch.Elapsed.TotalSeconds}");
- }
- });
- }
- }
- }
-}
diff --git a/src/System.Net.Http/tests/FunctionalTests/DefaultCredentialsTest.cs b/src/System.Net.Http/tests/FunctionalTests/DefaultCredentialsTest.cs
index 2e003ac80b..4e822ab538 100644
--- a/src/System.Net.Http/tests/FunctionalTests/DefaultCredentialsTest.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/DefaultCredentialsTest.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Collections.Generic;
using System.Security.Principal;
using System.Threading.Tasks;
@@ -15,82 +16,76 @@ namespace System.Net.Http.Functional.Tests
// TODO: #2383 - Consolidate the use of the environment variable settings to Common/tests.
[SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "dotnet/corefx #20010")]
[PlatformSpecific(TestPlatforms.Windows)]
- public class DefaultCredentialsTest : HttpClientTestBase
+ public abstract class DefaultCredentialsTest : HttpClientTestBase
{
- private static string DomainJoinedTestServer => Configuration.Http.DomainJoinedHttpHost;
- private static bool DomainJoinedTestsEnabled => !string.IsNullOrEmpty(DomainJoinedTestServer);
- private static bool DomainProxyTestsEnabled => (!string.IsNullOrEmpty(Configuration.Http.DomainJoinedProxyHost)) && DomainJoinedTestsEnabled;
+ private static bool DomainJoinedTestsEnabled => !string.IsNullOrEmpty(Configuration.Http.DomainJoinedHttpHost);
+
+ private static bool DomainProxyTestsEnabled => !string.IsNullOrEmpty(Configuration.Http.DomainJoinedProxyHost);
+
+ // Enable this to test against local HttpListener over loopback
+ // Note this doesn't work as expected with WinHttpHandler, because WinHttpHandler will always authenticate the
+ // current user against a loopback server using NTLM or Negotiate.
+ private static bool LocalHttpListenerTestsEnabled = false;
+
+ public static bool ServerAuthenticationTestsEnabled => (LocalHttpListenerTestsEnabled || DomainJoinedTestsEnabled);
private static string s_specificUserName = Configuration.Security.ActiveDirectoryUserName;
private static string s_specificPassword = Configuration.Security.ActiveDirectoryUserPassword;
private static string s_specificDomain = Configuration.Security.ActiveDirectoryName;
- private static Uri s_authenticatedServer =
- new Uri($"http://{DomainJoinedTestServer}/test/auth/negotiate/showidentity.ashx");
-
- // This test endpoint offers multiple schemes, Basic and NTLM, in that specific order. This endpoint
- // helps test that the client will use the stronger of the server proposed auth schemes and
- // not the first auth scheme.
- private static Uri s_multipleSchemesAuthenticatedServer =
- new Uri($"http://{DomainJoinedTestServer}/test/auth/multipleschemes/showidentity.ashx");
-
- private readonly ITestOutputHelper _output;
private readonly NetworkCredential _specificCredential =
new NetworkCredential(s_specificUserName, s_specificPassword, s_specificDomain);
+ private static Uri s_authenticatedServer = DomainJoinedTestsEnabled ?
+ new Uri($"http://{Configuration.Http.DomainJoinedHttpHost}/test/auth/negotiate/showidentity.ashx") : null;
+
+ private readonly ITestOutputHelper _output;
public DefaultCredentialsTest(ITestOutputHelper output)
{
_output = output;
- _output.WriteLine(s_authenticatedServer.ToString());
}
[OuterLoop] // TODO: Issue #11345
- [ActiveIssue(10041)]
- [ConditionalTheory(nameof(DomainJoinedTestsEnabled))]
- [InlineData(false)]
- [InlineData(true)]
- public async Task UseDefaultCredentials_DefaultValue_Unauthorized(bool useProxy)
+ [ConditionalTheory(nameof(ServerAuthenticationTestsEnabled))]
+ [MemberData(nameof(AuthenticatedServers))]
+ public async Task UseDefaultCredentials_DefaultValue_Unauthorized(string uri, bool useProxy)
{
HttpClientHandler handler = CreateHttpClientHandler();
handler.UseProxy = useProxy;
using (var client = new HttpClient(handler))
- using (HttpResponseMessage response = await client.GetAsync(s_authenticatedServer))
+ using (HttpResponseMessage response = await client.GetAsync(uri))
{
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
}
}
[OuterLoop] // TODO: Issue #11345
- [ActiveIssue(10041)]
- [ConditionalTheory(nameof(DomainJoinedTestsEnabled))]
- [InlineData(false)]
- [InlineData(true)]
- public async Task UseDefaultCredentials_SetFalse_Unauthorized(bool useProxy)
+ [ConditionalTheory(nameof(ServerAuthenticationTestsEnabled))]
+ [MemberData(nameof(AuthenticatedServers))]
+ public async Task UseDefaultCredentials_SetFalse_Unauthorized(string uri, bool useProxy)
{
HttpClientHandler handler = CreateHttpClientHandler();
handler.UseProxy = useProxy;
handler.UseDefaultCredentials = false;
using (var client = new HttpClient(handler))
- using (HttpResponseMessage response = await client.GetAsync(s_authenticatedServer))
+ using (HttpResponseMessage response = await client.GetAsync(uri))
{
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
}
}
[OuterLoop] // TODO: Issue #11345
- [ActiveIssue(10041)]
- [ConditionalTheory(nameof(DomainJoinedTestsEnabled))]
- [InlineData(false)]
- [InlineData(true)]
- public async Task UseDefaultCredentials_SetTrue_ConnectAsCurrentIdentity(bool useProxy)
+ [ConditionalTheory(nameof(ServerAuthenticationTestsEnabled))]
+ [MemberData(nameof(AuthenticatedServers))]
+ public async Task UseDefaultCredentials_SetTrue_ConnectAsCurrentIdentity(string uri, bool useProxy)
{
HttpClientHandler handler = CreateHttpClientHandler();
handler.UseProxy = useProxy;
handler.UseDefaultCredentials = true;
using (var client = new HttpClient(handler))
- using (HttpResponseMessage response = await client.GetAsync(s_authenticatedServer))
+ using (HttpResponseMessage response = await client.GetAsync(uri))
{
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@@ -102,18 +97,19 @@ namespace System.Net.Http.Functional.Tests
}
[OuterLoop] // TODO: Issue #11345
- [ActiveIssue(10041)]
- [ConditionalTheory(nameof(DomainJoinedTestsEnabled))]
- [InlineData(false)]
- [InlineData(true)]
- public async Task UseDefaultCredentials_SetTrueAndServerOffersMultipleSchemes_Ok(bool useProxy)
+ [ConditionalTheory(nameof(ServerAuthenticationTestsEnabled))]
+ [MemberData(nameof(AuthenticatedServers))]
+ public async Task Credentials_SetToWrappedDefaultCredential_ConnectAsCurrentIdentity(string uri, bool useProxy)
{
HttpClientHandler handler = CreateHttpClientHandler();
handler.UseProxy = useProxy;
- handler.UseDefaultCredentials = true;
+ handler.Credentials = new CredentialWrapper
+ {
+ InnerCredentials = CredentialCache.DefaultCredentials
+ };
using (var client = new HttpClient(handler))
- using (HttpResponseMessage response = await client.GetAsync(s_multipleSchemesAuthenticatedServer))
+ using (HttpResponseMessage response = await client.GetAsync(uri))
{
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
@@ -125,24 +121,18 @@ namespace System.Net.Http.Functional.Tests
}
[OuterLoop] // TODO: Issue #11345
- [ActiveIssue(10041)]
- [ConditionalTheory(nameof(DomainJoinedTestsEnabled))]
- [InlineData(false)]
- [InlineData(true)]
- public async Task Credentials_SetToSpecificCredential_ConnectAsSpecificIdentity(bool useProxy)
+ [ConditionalTheory(nameof(ServerAuthenticationTestsEnabled))]
+ [MemberData(nameof(AuthenticatedServers))]
+ public async Task Credentials_SetToBadCredential_Unauthorized(string uri, bool useProxy)
{
HttpClientHandler handler = CreateHttpClientHandler();
handler.UseProxy = useProxy;
- handler.UseDefaultCredentials = false;
- handler.Credentials = _specificCredential;
+ handler.Credentials = new NetworkCredential("notarealuser", "123456");
using (var client = new HttpClient(handler))
- using (HttpResponseMessage response = await client.GetAsync(s_authenticatedServer))
+ using (HttpResponseMessage response = await client.GetAsync(uri))
{
- Assert.Equal(HttpStatusCode.OK, response.StatusCode);
-
- string responseBody = await response.Content.ReadAsStringAsync();
- VerifyAuthentication(responseBody, true, s_specificDomain + "\\" + s_specificUserName);
+ Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
}
}
@@ -151,24 +141,20 @@ namespace System.Net.Http.Functional.Tests
[ConditionalTheory(nameof(DomainJoinedTestsEnabled))]
[InlineData(false)]
[InlineData(true)]
- public async Task Credentials_SetToWrappedDefaultCredential_ConnectAsCurrentIdentity(bool useProxy)
+ public async Task Credentials_SetToSpecificCredential_ConnectAsSpecificIdentity(bool useProxy)
{
HttpClientHandler handler = CreateHttpClientHandler();
handler.UseProxy = useProxy;
- handler.Credentials = new CredentialWrapper
- {
- InnerCredentials = CredentialCache.DefaultCredentials
- };
+ handler.UseDefaultCredentials = false;
+ handler.Credentials = _specificCredential;
using (var client = new HttpClient(handler))
using (HttpResponseMessage response = await client.GetAsync(s_authenticatedServer))
{
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
-
+
string responseBody = await response.Content.ReadAsStringAsync();
- WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent();
- _output.WriteLine("currentIdentity={0}", currentIdentity.Name);
- VerifyAuthentication(responseBody, true, currentIdentity.Name);
+ VerifyAuthentication(responseBody, true, s_specificDomain + "\\" + s_specificUserName);
}
}
@@ -221,6 +207,27 @@ namespace System.Net.Http.Functional.Tests
}
}
+ public static IEnumerable<object[]> AuthenticatedServers()
+ {
+ // Note that localhost will not actually use the proxy, but there's no harm in testing it.
+ foreach (bool b in new bool[] { true, false })
+ {
+ if (LocalHttpListenerTestsEnabled)
+ {
+ yield return new object[] { HttpListenerAuthenticatedLoopbackServer.NtlmOnly.Uri, b };
+ yield return new object[] { HttpListenerAuthenticatedLoopbackServer.NegotiateOnly.Uri, b };
+ yield return new object[] { HttpListenerAuthenticatedLoopbackServer.NegotiateAndNtlm.Uri, b };
+ yield return new object[] { HttpListenerAuthenticatedLoopbackServer.BasicAndNtlm.Uri, b };
+ }
+
+ if (!string.IsNullOrEmpty(Configuration.Http.DomainJoinedHttpHost))
+ {
+ yield return new object[] { $"http://{Configuration.Http.DomainJoinedHttpHost}/test/auth/negotiate/showidentity.ashx", b };
+ yield return new object[] { $"http://{Configuration.Http.DomainJoinedHttpHost}/test/auth/multipleschemes/showidentity.ashx", b };
+ }
+ }
+ }
+
private void VerifyAuthentication(string response, bool authenticated, string user)
{
// Convert all strings to lowercase to compare. Windows treats domain and username as case-insensitive.
@@ -296,6 +303,46 @@ namespace System.Net.Http.Functional.Tests
{
return false;
}
- }
+ }
+
+ private sealed class HttpListenerAuthenticatedLoopbackServer
+ {
+ private readonly HttpListener _listener;
+ private readonly string _uri;
+
+ public static readonly HttpListenerAuthenticatedLoopbackServer NtlmOnly = new HttpListenerAuthenticatedLoopbackServer("http://localhost:8080/", AuthenticationSchemes.Ntlm);
+ public static readonly HttpListenerAuthenticatedLoopbackServer NegotiateOnly = new HttpListenerAuthenticatedLoopbackServer("http://localhost:8081/", AuthenticationSchemes.Negotiate);
+ public static readonly HttpListenerAuthenticatedLoopbackServer NegotiateAndNtlm = new HttpListenerAuthenticatedLoopbackServer("http://localhost:8082/", AuthenticationSchemes.Negotiate | AuthenticationSchemes.Ntlm);
+ public static readonly HttpListenerAuthenticatedLoopbackServer BasicAndNtlm = new HttpListenerAuthenticatedLoopbackServer("http://localhost:8083/", AuthenticationSchemes.Basic | AuthenticationSchemes.Ntlm);
+
+ // Don't construct directly, use instances above
+ private HttpListenerAuthenticatedLoopbackServer(string uri, AuthenticationSchemes authenticationSchemes)
+ {
+ _uri = uri;
+
+ _listener = new HttpListener();
+ _listener.Prefixes.Add(uri);
+ _listener.AuthenticationSchemes = authenticationSchemes;
+ _listener.Start();
+
+ Task.Run(() => ProcessRequests());
+ }
+
+ public string Uri => _uri;
+
+ private async void ProcessRequests()
+ {
+ while (true)
+ {
+ var context = await _listener.GetContextAsync();
+
+ // Send a response in the JSON format that the client expects
+ string username = context.User.Identity.Name;
+ await context.Response.OutputStream.WriteAsync(System.Text.Encoding.UTF8.GetBytes($"{{\"authenticated\": \"true\", \"user\": \"{username}\" }}"));
+
+ context.Response.Close();
+ }
+ }
+ }
}
}
diff --git a/src/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs b/src/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs
index 5a991d1d94..f7c5359b02 100644
--- a/src/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs
@@ -20,7 +20,7 @@ namespace System.Net.Http.Functional.Tests
[ActiveIssue(20470, TargetFrameworkMonikers.UapAot)]
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "NetEventSource is only part of .NET Core.")]
- public class DiagnosticsTest : HttpClientTestBase
+ public abstract class DiagnosticsTest : HttpClientTestBase
{
[Fact]
public static void EventSource_ExistsWithCorrectId()
@@ -47,7 +47,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
public void SendAsync_ExpectedDiagnosticSourceLogging()
{
- RemoteInvoke(useManagedHandlerString =>
+ RemoteInvoke(useSocketsHttpHandlerString =>
{
bool requestLogged = false;
Guid requestGuid = Guid.Empty;
@@ -89,7 +89,7 @@ namespace System.Net.Http.Functional.Tests
using (DiagnosticListener.AllListeners.Subscribe(diagnosticListenerObserver))
{
diagnosticListenerObserver.Enable( s => !s.Contains("HttpRequestOut"));
- using (HttpClient client = CreateHttpClient(useManagedHandlerString))
+ using (HttpClient client = CreateHttpClient(useSocketsHttpHandlerString))
{
client.GetAsync(Configuration.Http.RemoteEchoServer).Result.Dispose();
}
@@ -104,7 +104,7 @@ namespace System.Net.Http.Functional.Tests
}
return SuccessExitCode;
- }, UseManagedHandler.ToString()).Dispose();
+ }, UseSocketsHttpHandler.ToString()).Dispose();
}
/// <remarks>
@@ -115,7 +115,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
public void SendAsync_ExpectedDiagnosticSourceNoLogging()
{
- RemoteInvoke(useManagedHandlerString =>
+ RemoteInvoke(useSocketsHttpHandlerString =>
{
bool requestLogged = false;
bool responseLogged = false;
@@ -144,12 +144,11 @@ namespace System.Net.Http.Functional.Tests
using (DiagnosticListener.AllListeners.Subscribe(diagnosticListenerObserver))
{
- using (HttpClient client = CreateHttpClient(useManagedHandlerString))
+ using (HttpClient client = CreateHttpClient(useSocketsHttpHandlerString))
{
LoopbackServer.CreateServerAsync(async (server, url) =>
{
- Task<List<string>> requestLines = LoopbackServer.AcceptSocketAsync(server,
- (s, stream, reader, writer) => LoopbackServer.ReadWriteAcceptedAsync(s, reader, writer));
+ Task<List<string>> requestLines = server.AcceptConnectionSendResponseAndCloseAsync();
Task<HttpResponseMessage> response = client.GetAsync(url);
await Task.WhenAll(response, requestLines);
@@ -164,15 +163,17 @@ namespace System.Net.Http.Functional.Tests
Assert.False(activityStopLogged, "HttpRequestOut.Stop was logged while logging disabled.");
}
return SuccessExitCode;
- }, UseManagedHandler.ToString()).Dispose();
+ }, UseSocketsHttpHandler.ToString()).Dispose();
}
[ActiveIssue(23771, TestPlatforms.AnyUnix)]
[OuterLoop] // TODO: Issue #11345
- [Fact]
- public void SendAsync_HttpTracingEnabled_Succeeds()
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public void SendAsync_HttpTracingEnabled_Succeeds(bool useSsl)
{
- RemoteInvoke(async useManagedHandlerString =>
+ RemoteInvoke(async (useSocketsHttpHandlerString, useSslString) =>
{
using (var listener = new TestEventListener("Microsoft-System-Net-Http", EventLevel.Verbose))
{
@@ -180,21 +181,22 @@ namespace System.Net.Http.Functional.Tests
await listener.RunWithCallbackAsync(events.Enqueue, async () =>
{
// Exercise various code paths to get coverage of tracing
- using (HttpClient client = CreateHttpClient(useManagedHandlerString))
+ using (HttpClient client = CreateHttpClient(useSocketsHttpHandlerString))
{
// Do a get to a loopback server
await LoopbackServer.CreateServerAsync(async (server, url) =>
{
await TestHelper.WhenAllCompletedOrAnyFailed(
- LoopbackServer.ReadRequestAndSendResponseAsync(server),
+ server.AcceptConnectionSendResponseAndCloseAsync(),
client.GetAsync(url));
});
// Do a post to a remote server
byte[] expectedData = Enumerable.Range(0, 20000).Select(i => unchecked((byte)i)).ToArray();
- HttpContent content = new ByteArrayContent(expectedData);
+ Uri remoteServer = bool.Parse(useSslString) ? Configuration.Http.SecureRemoteEchoServer : Configuration.Http.RemoteEchoServer;
+ var content = new ByteArrayContent(expectedData);
content.Headers.ContentMD5 = TestHelper.ComputeMD5Hash(expectedData);
- using (HttpResponseMessage response = await client.PostAsync(Configuration.Http.RemoteEchoServer, content))
+ using (HttpResponseMessage response = await client.PostAsync(remoteServer, content))
{
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
@@ -209,14 +211,14 @@ namespace System.Net.Http.Functional.Tests
}
return SuccessExitCode;
- }, UseManagedHandler.ToString()).Dispose();
+ }, UseSocketsHttpHandler.ToString(), useSsl.ToString()).Dispose();
}
[OuterLoop] // TODO: Issue #11345
[Fact]
public void SendAsync_ExpectedDiagnosticExceptionLogging()
{
- RemoteInvoke(useManagedHandlerString =>
+ RemoteInvoke(useSocketsHttpHandlerString =>
{
bool exceptionLogged = false;
bool responseLogged = false;
@@ -242,7 +244,7 @@ namespace System.Net.Http.Functional.Tests
using (DiagnosticListener.AllListeners.Subscribe(diagnosticListenerObserver))
{
diagnosticListenerObserver.Enable(s => !s.Contains("HttpRequestOut"));
- using (HttpClient client = CreateHttpClient(useManagedHandlerString))
+ using (HttpClient client = CreateHttpClient(useSocketsHttpHandlerString))
{
Assert.ThrowsAsync<HttpRequestException>(() => client.GetAsync($"http://{Guid.NewGuid()}.com")).Wait();
}
@@ -254,7 +256,7 @@ namespace System.Net.Http.Functional.Tests
}
return SuccessExitCode;
- }, UseManagedHandler.ToString()).Dispose();
+ }, UseSocketsHttpHandler.ToString()).Dispose();
}
[ActiveIssue(23209)]
@@ -262,7 +264,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
public void SendAsync_ExpectedDiagnosticCancelledLogging()
{
- RemoteInvoke(useManagedHandlerString =>
+ RemoteInvoke(useSocketsHttpHandlerString =>
{
bool cancelLogged = false;
var diagnosticListenerObserver = new FakeDiagnosticListenerObserver(kvp =>
@@ -279,16 +281,15 @@ namespace System.Net.Http.Functional.Tests
using (DiagnosticListener.AllListeners.Subscribe(diagnosticListenerObserver))
{
diagnosticListenerObserver.Enable(s => !s.Contains("HttpRequestOut"));
- using (HttpClient client = CreateHttpClient(useManagedHandlerString))
+ using (HttpClient client = CreateHttpClient(useSocketsHttpHandlerString))
{
LoopbackServer.CreateServerAsync(async (server, url) =>
{
CancellationTokenSource tcs = new CancellationTokenSource();
- Task request = LoopbackServer.AcceptSocketAsync(server,
- (s, stream, reader, writer) =>
+ Task request = server.AcceptConnectionAsync(connection =>
{
tcs.Cancel();
- return LoopbackServer.ReadWriteAcceptedAsync(s, reader, writer);
+ return connection.ReadRequestHeaderAndSendResponseAsync();
});
Task response = client.GetAsync(url, tcs.Token);
await Assert.ThrowsAnyAsync<Exception>(() => TestHelper.WhenAllCompletedOrAnyFailed(response, request));
@@ -301,14 +302,14 @@ namespace System.Net.Http.Functional.Tests
diagnosticListenerObserver.Disable();
return SuccessExitCode;
- }, UseManagedHandler.ToString()).Dispose();
+ }, UseSocketsHttpHandler.ToString()).Dispose();
}
[OuterLoop] // TODO: Issue #11345
[Fact]
public void SendAsync_ExpectedDiagnosticSourceActivityLogging()
{
- RemoteInvoke(useManagedHandlerString =>
+ RemoteInvoke(useSocketsHttpHandlerString =>
{
bool requestLogged = false;
bool responseLogged = false;
@@ -354,12 +355,11 @@ namespace System.Net.Http.Functional.Tests
using (DiagnosticListener.AllListeners.Subscribe(diagnosticListenerObserver))
{
diagnosticListenerObserver.Enable(s => s.Contains("HttpRequestOut"));
- using (HttpClient client = CreateHttpClient(useManagedHandlerString))
+ using (HttpClient client = CreateHttpClient(useSocketsHttpHandlerString))
{
LoopbackServer.CreateServerAsync(async (server, url) =>
{
- Task<List<string>> requestLines = LoopbackServer.AcceptSocketAsync(server,
- (s, stream, reader, writer) => LoopbackServer.ReadWriteAcceptedAsync(s, reader, writer));
+ Task<List<string>> requestLines = server.AcceptConnectionSendResponseAndCloseAsync();
Task<HttpResponseMessage> response = client.GetAsync(url);
await Task.WhenAll(response, requestLines);
@@ -378,14 +378,14 @@ namespace System.Net.Http.Functional.Tests
}
return SuccessExitCode;
- }, UseManagedHandler.ToString()).Dispose();
+ }, UseSocketsHttpHandler.ToString()).Dispose();
}
[OuterLoop] // TODO: Issue #11345
[Fact]
public void SendAsync_ExpectedDiagnosticSourceUrlFilteredActivityLogging()
{
- RemoteInvoke(useManagedHandlerString =>
+ RemoteInvoke(useSocketsHttpHandlerString =>
{
bool activityStartLogged = false;
bool activityStopLogged = false;
@@ -408,7 +408,7 @@ namespace System.Net.Http.Functional.Tests
}
return true;
});
- using (HttpClient client = CreateHttpClient(useManagedHandlerString))
+ using (HttpClient client = CreateHttpClient(useSocketsHttpHandlerString))
{
client.GetAsync(Configuration.Http.RemoteEchoServer).Result.Dispose();
}
@@ -419,14 +419,14 @@ namespace System.Net.Http.Functional.Tests
}
return SuccessExitCode;
- }, UseManagedHandler.ToString()).Dispose();
+ }, UseSocketsHttpHandler.ToString()).Dispose();
}
[OuterLoop] // TODO: Issue #11345
[Fact]
public void SendAsync_ExpectedDiagnosticExceptionActivityLogging()
{
- RemoteInvoke(useManagedHandlerString =>
+ RemoteInvoke(useSocketsHttpHandlerString =>
{
bool exceptionLogged = false;
bool activityStopLogged = false;
@@ -453,7 +453,7 @@ namespace System.Net.Http.Functional.Tests
using (DiagnosticListener.AllListeners.Subscribe(diagnosticListenerObserver))
{
diagnosticListenerObserver.Enable();
- using (HttpClient client = CreateHttpClient(useManagedHandlerString))
+ using (HttpClient client = CreateHttpClient(useSocketsHttpHandlerString))
{
Assert.ThrowsAsync<HttpRequestException>(() => client.GetAsync($"http://{Guid.NewGuid()}.com")).Wait();
}
@@ -465,14 +465,76 @@ namespace System.Net.Http.Functional.Tests
}
return SuccessExitCode;
- }, UseManagedHandler.ToString()).Dispose();
+ }, UseSocketsHttpHandler.ToString()).Dispose();
+ }
+
+ [OuterLoop] // TODO: Issue #11345
+ [Fact]
+ public void SendAsync_ExpectedDiagnosticSynchronousExceptionActivityLogging()
+ {
+ RemoteInvoke(useSocketsHttpHandlerString =>
+ {
+ bool exceptionLogged = false;
+ bool activityStopLogged = false;
+ var diagnosticListenerObserver = new FakeDiagnosticListenerObserver(kvp =>
+ {
+ if (kvp.Key.Equals("System.Net.Http.HttpRequestOut.Stop"))
+ {
+ Assert.NotNull(kvp.Value);
+ GetPropertyValueFromAnonymousTypeInstance<HttpRequestMessage>(kvp.Value, "Request");
+ var requestStatus = GetPropertyValueFromAnonymousTypeInstance<TaskStatus>(kvp.Value, "RequestTaskStatus");
+ Assert.Equal(TaskStatus.Faulted, requestStatus);
+
+ activityStopLogged = true;
+ }
+ else if (kvp.Key.Equals("System.Net.Http.Exception"))
+ {
+ Assert.NotNull(kvp.Value);
+ GetPropertyValueFromAnonymousTypeInstance<Exception>(kvp.Value, "Exception");
+
+ exceptionLogged = true;
+ }
+ });
+
+ using (DiagnosticListener.AllListeners.Subscribe(diagnosticListenerObserver))
+ {
+ diagnosticListenerObserver.Enable();
+ using (HttpClientHandler handler = CreateHttpClientHandler(useSocketsHttpHandlerString))
+ using (HttpClient client = new HttpClient(handler))
+ {
+ if (bool.Parse(useSocketsHttpHandlerString))
+ {
+ // Forces a synchronous exception for SocketsHttpHandler
+ HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, $"http://{Guid.NewGuid()}.com");
+ request.Version = new Version(0, 0);
+
+ Assert.ThrowsAsync<NotSupportedException>(() => client.SendAsync(request)).Wait();
+ }
+ else
+ {
+ // Forces a synchronous exception for WinHttpHandler
+ handler.UseCookies = true;
+ handler.CookieContainer = null;
+
+ Assert.ThrowsAsync<InvalidOperationException>(() => client.GetAsync($"http://{Guid.NewGuid()}.com")).Wait();
+ }
+ }
+ // Poll with a timeout since logging response is not synchronized with returning a response.
+ WaitForTrue(() => activityStopLogged, TimeSpan.FromSeconds(1),
+ "Response with exception was not logged within 1 second timeout.");
+ Assert.True(exceptionLogged, "Exception was not logged");
+ diagnosticListenerObserver.Disable();
+ }
+
+ return SuccessExitCode;
+ }, UseSocketsHttpHandler.ToString()).Dispose();
}
[OuterLoop] // TODO: Issue #11345
[Fact]
public void SendAsync_ExpectedDiagnosticSourceNewAndDeprecatedEventsLogging()
{
- RemoteInvoke(useManagedHandlerString =>
+ RemoteInvoke(useSocketsHttpHandlerString =>
{
bool requestLogged = false;
bool responseLogged = false;
@@ -490,7 +552,7 @@ namespace System.Net.Http.Functional.Tests
using (DiagnosticListener.AllListeners.Subscribe(diagnosticListenerObserver))
{
diagnosticListenerObserver.Enable();
- using (HttpClient client = CreateHttpClient(useManagedHandlerString))
+ using (HttpClient client = CreateHttpClient(useSocketsHttpHandlerString))
{
client.GetAsync(Configuration.Http.RemoteEchoServer).Result.Dispose();
}
@@ -504,14 +566,14 @@ namespace System.Net.Http.Functional.Tests
}
return SuccessExitCode;
- }, UseManagedHandler.ToString()).Dispose();
+ }, UseSocketsHttpHandler.ToString()).Dispose();
}
[OuterLoop] // TODO: Issue #11345
[Fact]
public void SendAsync_ExpectedDiagnosticExceptionOnlyActivityLogging()
{
- RemoteInvoke(useManagedHandlerString =>
+ RemoteInvoke(useSocketsHttpHandlerString =>
{
bool exceptionLogged = false;
bool activityLogged = false;
@@ -530,7 +592,7 @@ namespace System.Net.Http.Functional.Tests
using (DiagnosticListener.AllListeners.Subscribe(diagnosticListenerObserver))
{
diagnosticListenerObserver.Enable(s => s.Equals("System.Net.Http.Exception"));
- using (HttpClient client = CreateHttpClient(useManagedHandlerString))
+ using (HttpClient client = CreateHttpClient(useSocketsHttpHandlerString))
{
Assert.ThrowsAsync<HttpRequestException>(() => client.GetAsync($"http://{Guid.NewGuid()}.com")).Wait();
}
@@ -542,14 +604,14 @@ namespace System.Net.Http.Functional.Tests
}
return SuccessExitCode;
- }, UseManagedHandler.ToString()).Dispose();
+ }, UseSocketsHttpHandler.ToString()).Dispose();
}
[OuterLoop] // TODO: Issue #11345
[Fact]
public void SendAsync_ExpectedDiagnosticStopOnlyActivityLogging()
{
- RemoteInvoke(useManagedHandlerString =>
+ RemoteInvoke(useSocketsHttpHandlerString =>
{
bool activityStartLogged = false;
bool activityStopLogged = false;
@@ -567,7 +629,7 @@ namespace System.Net.Http.Functional.Tests
using (DiagnosticListener.AllListeners.Subscribe(diagnosticListenerObserver))
{
diagnosticListenerObserver.Enable(s => s.Equals("System.Net.Http.HttpRequestOut"));
- using (HttpClient client = CreateHttpClient(useManagedHandlerString))
+ using (HttpClient client = CreateHttpClient(useSocketsHttpHandlerString))
{
client.GetAsync(Configuration.Http.RemoteEchoServer).Result.Dispose();
}
@@ -579,7 +641,7 @@ namespace System.Net.Http.Functional.Tests
}
return SuccessExitCode;
- }, UseManagedHandler.ToString()).Dispose();
+ }, UseSocketsHttpHandler.ToString()).Dispose();
}
[ActiveIssue(23209)]
@@ -587,7 +649,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
public void SendAsync_ExpectedDiagnosticCancelledActivityLogging()
{
- RemoteInvoke(useManagedHandlerString =>
+ RemoteInvoke(useSocketsHttpHandlerString =>
{
bool cancelLogged = false;
var diagnosticListenerObserver = new FakeDiagnosticListenerObserver(kvp =>
@@ -605,17 +667,16 @@ namespace System.Net.Http.Functional.Tests
using (DiagnosticListener.AllListeners.Subscribe(diagnosticListenerObserver))
{
diagnosticListenerObserver.Enable();
- using (HttpClient client = CreateHttpClient(useManagedHandlerString))
+ using (HttpClient client = CreateHttpClient(useSocketsHttpHandlerString))
{
LoopbackServer.CreateServerAsync(async (server, url) =>
{
CancellationTokenSource tcs = new CancellationTokenSource();
- Task request = LoopbackServer.AcceptSocketAsync(server,
- (s, stream, reader, writer) =>
- {
- tcs.Cancel();
- return LoopbackServer.ReadWriteAcceptedAsync(s, reader, writer);
- });
+ Task request = server.AcceptConnectionAsync(connection =>
+ {
+ tcs.Cancel();
+ return connection.ReadRequestHeaderAndSendResponseAsync();
+ });
Task response = client.GetAsync(url, tcs.Token);
await Assert.ThrowsAnyAsync<Exception>(() => TestHelper.WhenAllCompletedOrAnyFailed(response, request));
}).Wait();
@@ -627,7 +688,7 @@ namespace System.Net.Http.Functional.Tests
diagnosticListenerObserver.Disable();
return SuccessExitCode;
- }, UseManagedHandler.ToString()).Dispose();
+ }, UseSocketsHttpHandler.ToString()).Dispose();
}
private static T GetPropertyValueFromAnonymousTypeInstance<T>(object obj, string propertyName)
@@ -655,7 +716,7 @@ namespace System.Net.Http.Functional.Tests
Assert.False(SpinWait.SpinUntil(p, timeout), message);
}
- private void AssertHeadersAreInjected(List<string> requestLines, Activity parent)
+ private static void AssertHeadersAreInjected(List<string> requestLines, Activity parent)
{
string requestId = null;
var correlationContext = new List<NameValueHeaderValue>();
@@ -687,7 +748,7 @@ namespace System.Net.Http.Functional.Tests
}
}
- private void AssertNoHeadersAreInjected(List<string> requestLines)
+ private static void AssertNoHeadersAreInjected(List<string> requestLines)
{
foreach (var line in requestLines)
{
diff --git a/src/System.Net.Http/tests/FunctionalTests/DribbleStream.cs b/src/System.Net.Http/tests/FunctionalTests/DribbleStream.cs
new file mode 100644
index 0000000000..39e85c875a
--- /dev/null
+++ b/src/System.Net.Http/tests/FunctionalTests/DribbleStream.cs
@@ -0,0 +1,68 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Net.Http.Functional.Tests
+{
+ public sealed class DribbleStream : Stream
+ {
+ private readonly Stream _wrapped;
+ private readonly bool _clientDisconnectAllowed;
+
+ public DribbleStream(Stream wrapped, bool clientDisconnectAllowed = false)
+ {
+ _wrapped = wrapped;
+ _clientDisconnectAllowed = clientDisconnectAllowed;
+ }
+
+ public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+ {
+ try
+ {
+ for (int i = 0; i < count; i++)
+ {
+ await _wrapped.WriteAsync(buffer, offset + i, 1);
+ await _wrapped.FlushAsync();
+ await Task.Yield(); // introduce short delays, enough to send packets individually but not so long as to extend test duration significantly
+ }
+ }
+ catch (IOException) when (_clientDisconnectAllowed)
+ {
+ }
+ }
+
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ try
+ {
+ for (int i = 0; i < count; i++)
+ {
+ _wrapped.Write(buffer, offset + i, 1);
+ _wrapped.Flush();
+ }
+ }
+ catch (IOException) when (_clientDisconnectAllowed)
+ {
+ }
+ }
+
+ public override bool CanRead => _wrapped.CanRead;
+ public override bool CanSeek => _wrapped.CanSeek;
+ public override bool CanWrite => _wrapped.CanWrite;
+ public override long Length => _wrapped.Length;
+ public override long Position { get => _wrapped.Position; set => _wrapped.Position = value; }
+ public override void Flush() => _wrapped.Flush();
+ public override Task FlushAsync(CancellationToken cancellationToken) => _wrapped.FlushAsync(cancellationToken);
+ public override int Read(byte[] buffer, int offset, int count) => _wrapped.Read(buffer, offset, count);
+ public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) => _wrapped.ReadAsync(buffer, offset, count, cancellationToken);
+ public override long Seek(long offset, SeekOrigin origin) => _wrapped.Seek(offset, origin);
+ public override void SetLength(long value) => _wrapped.SetLength(value);
+ public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken) => _wrapped.CopyToAsync(destination, bufferSize, cancellationToken);
+ public override void Close() => _wrapped.Close();
+ protected override void Dispose(bool disposing) => _wrapped.Dispose();
+ }
+}
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClient.SelectedSitesTest.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClient.SelectedSitesTest.cs
new file mode 100644
index 0000000000..efa191b592
--- /dev/null
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpClient.SelectedSitesTest.cs
@@ -0,0 +1,133 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Threading.Tasks;
+
+using Xunit;
+
+namespace System.Net.Http.Functional.Tests
+{
+ public abstract class HttpClient_SelectedSites_Test : HttpClientTestBase
+ {
+ public static bool IsSelectedSitesTestEnabled()
+ {
+ string envVar = Environment.GetEnvironmentVariable("CORFX_NET_HTTP_SELECTED_SITES");
+ return envVar != null &&
+ (envVar.Equals("true", StringComparison.OrdinalIgnoreCase) || envVar.Equals("1"));
+ }
+
+ [ConditionalTheory(nameof(IsSelectedSitesTestEnabled))]
+ [Trait("SelectedSites", "true")]
+ [MemberData(nameof(GetSelectedSites))]
+ public async Task RetrieveSite_Succeeds(string site)
+ {
+ // Not doing this in bulk for platform handlers.
+ if (!UseSocketsHttpHandler)
+ return;
+
+ int remainingAttempts = 2;
+ while (remainingAttempts-- > 0)
+ {
+ try
+ {
+ await VisitSite(site);
+ return;
+ }
+ catch
+ {
+ if (remainingAttempts < 1)
+ throw;
+ await Task.Delay(1500);
+ }
+ }
+
+ throw new Exception("Not expected to reach here");
+ }
+
+ [ConditionalTheory(nameof(IsSelectedSitesTestEnabled))]
+ [Trait("SiteInvestigation", "true")]
+ [InlineData("http://microsoft.com")]
+ public async Task RetrieveSite_Debug_Helper(string site)
+ {
+ await VisitSite(site);
+ }
+
+ public static IEnumerable<string[]> GetSelectedSites()
+ {
+ const string resourceName = "SelectedSitesTest.txt";
+ Assembly assembly = typeof(HttpClient_SelectedSites_Test).Assembly;
+ Stream s = assembly.GetManifestResourceStream(resourceName);
+ if (s == null)
+ {
+ throw new Exception("Couldn't find resource " + resourceName);
+ }
+
+ using (var reader = new StreamReader(s))
+ {
+ string site;
+ while (null != (site = reader.ReadLine()))
+ {
+ yield return new[] { site };
+ }
+ }
+ }
+
+ private async Task VisitSite(string site)
+ {
+ using (HttpClient httpClient = CreateHttpClientForSiteVisit())
+ {
+ await VisitSiteWithClient(site, httpClient);
+ }
+ }
+
+ private async Task VisitSiteWithClient(string site, HttpClient httpClient)
+ {
+ using (HttpResponseMessage response = await httpClient.GetAsync(site))
+ {
+ switch (response.StatusCode)
+ {
+ case HttpStatusCode.Redirect:
+ case HttpStatusCode.OK:
+ if (response.Content.Headers.ContentLength > 0)
+ Assert.Equal(response.Content.Headers.ContentLength.Value, (await response.Content.ReadAsByteArrayAsync()).Length);
+ break;
+ case HttpStatusCode.BadGateway:
+ case HttpStatusCode.Forbidden:
+ case HttpStatusCode.Moved:
+ case HttpStatusCode.NotFound:
+ case HttpStatusCode.ServiceUnavailable:
+ case HttpStatusCode.Unauthorized:
+ case HttpStatusCode.InternalServerError:
+ break;
+ default:
+ throw new Exception($"{site} returned: {response.StatusCode}");
+ }
+ }
+ }
+
+ private HttpClient CreateHttpClientForSiteVisit()
+ {
+ HttpClient httpClient = new HttpClient(CreateHttpClientHandler(UseSocketsHttpHandler));
+
+ // Some extra headers since some sites only give proper responses when they are present.
+ httpClient.DefaultRequestHeaders.Add(
+ "User-Agent",
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36");
+ httpClient.DefaultRequestHeaders.Add(
+ "Accept-Language",
+ "en-US,en;q=0.9");
+ httpClient.DefaultRequestHeaders.Add(
+ "Accept-Encoding",
+ "gzip, deflate, br");
+ httpClient.DefaultRequestHeaders.Add(
+ "Accept",
+ "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
+
+ return httpClient;
+ }
+ }
+}
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientEKUTest.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientEKUTest.cs
index d5c693a6fd..c6badc770e 100644
--- a/src/System.Net.Http/tests/FunctionalTests/HttpClientEKUTest.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientEKUTest.cs
@@ -15,14 +15,14 @@ namespace System.Net.Http.Functional.Tests
{
using Configuration = System.Net.Test.Common.Configuration;
- public class HttpClientEKUTest : HttpClientTestBase
+ public abstract class HttpClientEKUTest : HttpClientTestBase
{
// Curl + OSX SecureTransport doesn't support the custom certificate callback.
private static bool BackendSupportsCustomCertificateHandling =>
#if TargetsWindows
true;
#else
- CurlSslVersionDescription()?.StartsWith("OpenSSL") ?? false;
+ Interop.Http.GetSslVersionDescription()?.StartsWith(Interop.Http.OpenSsl10Description, StringComparison.OrdinalIgnoreCase) ?? false;
#endif
private static bool CanTestCertificates =>
@@ -32,11 +32,6 @@ namespace System.Net.Http.Functional.Tests
private static bool CanTestClientCertificates =>
CanTestCertificates && BackendSupportsCustomCertificateHandling;
-#if !TargetsWindows
- [DllImport("System.Net.Http.Native", EntryPoint = "HttpNative_GetSslVersionDescription")]
- private static extern string CurlSslVersionDescription();
-#endif
-
public const int TestTimeoutMilliseconds = 15 * 1000;
public static X509Certificate2 serverCertificateServerEku = Configuration.Certificates.GetServerCertificate();
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.AcceptAllCerts.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.AcceptAllCerts.cs
index ab8429ecba..6ef12456f6 100644
--- a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.AcceptAllCerts.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.AcceptAllCerts.cs
@@ -12,7 +12,7 @@ namespace System.Net.Http.Functional.Tests
{
using Configuration = System.Net.Test.Common.Configuration;
- public class HttpClientHandler_DangerousAcceptAllCertificatesValidator_Test : HttpClientTestBase
+ public abstract class HttpClientHandler_DangerousAcceptAllCertificatesValidator_Test : HttpClientTestBase
{
private static bool ClientSupportsDHECipherSuites => (!PlatformDetection.IsWindows || PlatformDetection.IsWindows10Version1607OrGreater);
@@ -24,6 +24,7 @@ namespace System.Net.Http.Functional.Tests
Assert.True(HttpClientHandler.DangerousAcceptAnyServerCertificateValidator(null, null, null, SslPolicyErrors.None));
}
+ [ActiveIssue(25676, TestPlatforms.Linux)]
[Theory]
[InlineData(SslProtocols.Tls, false)] // try various protocols to ensure we correctly set versions even when accepting all certs
[InlineData(SslProtocols.Tls, true)]
@@ -51,7 +52,7 @@ namespace System.Net.Http.Functional.Tests
await LoopbackServer.CreateServerAsync(async (server, url) =>
{
await TestHelper.WhenAllCompletedOrAnyFailed(
- LoopbackServer.ReadRequestAndSendResponseAsync(server, options: options),
+ server.AcceptConnectionSendResponseAndCloseAsync(),
client.GetAsync(url));
}, options);
}
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs
new file mode 100644
index 0000000000..b59c26a015
--- /dev/null
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Authentication.cs
@@ -0,0 +1,492 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Net.Test.Common;
+using System.Text;
+using System.Threading.Tasks;
+
+using Xunit;
+
+namespace System.Net.Http.Functional.Tests
+{
+ public abstract class HttpClientHandler_Authentication_Test : HttpClientTestBase
+ {
+ private const string Username = "testusername";
+ private const string Password = "testpassword";
+ private const string Domain = "testdomain";
+
+ private static readonly NetworkCredential s_credentials = new NetworkCredential(Username, Password, Domain);
+ private static readonly NetworkCredential s_credentialsNoDomain = new NetworkCredential(Username, Password);
+
+ private static readonly Func<HttpClientHandler, Uri, HttpStatusCode, ICredentials, Task> s_createAndValidateRequest = async (handler, url, expectedStatusCode, credentials) =>
+ {
+ handler.Credentials = credentials;
+
+ using (HttpClient client = new HttpClient(handler))
+ using (HttpResponseMessage response = await client.GetAsync(url))
+ {
+ Assert.Equal(expectedStatusCode, response.StatusCode);
+ }
+ };
+
+ [Theory]
+ [MemberData(nameof(Authentication_TestData))]
+ public async Task HttpClientHandler_Authentication_Succeeds(string authenticateHeader, bool result)
+ {
+ if (PlatformDetection.IsWindowsNanoServer)
+ {
+ // TODO: #28065: Fix failing authentication test cases on different httpclienthandlers.
+ return;
+ }
+
+ // Digest authentication does not work with domain credentials on CurlHandler. This is blocked by the behavior of LibCurl.
+ NetworkCredential credentials = (IsCurlHandler && authenticateHeader.ToLowerInvariant().Contains("digest")) ?
+ s_credentialsNoDomain :
+ s_credentials;
+
+ var options = new LoopbackServer.Options { Domain = Domain, Username = Username, Password = Password };
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ string serverAuthenticateHeader = $"WWW-Authenticate: {authenticateHeader}\r\n";
+ HttpClientHandler handler = CreateHttpClientHandler();
+ Task serverTask = result ?
+ server.AcceptConnectionPerformAuthenticationAndCloseAsync(serverAuthenticateHeader) :
+ server.AcceptConnectionSendResponseAndCloseAsync(HttpStatusCode.Unauthorized, serverAuthenticateHeader);
+
+ await TestHelper.WhenAllCompletedOrAnyFailedWithTimeout(TestHelper.PassingTestTimeoutMilliseconds,
+ s_createAndValidateRequest(handler, url, result ? HttpStatusCode.OK : HttpStatusCode.Unauthorized, credentials), serverTask);
+ }, options);
+ }
+
+ [Theory]
+ [InlineData("WWW-Authenticate: Basic realm=\"hello1\"\r\nWWW-Authenticate: Basic realm=\"hello2\"\r\n")]
+ [InlineData("WWW-Authenticate: Basic realm=\"hello\"\r\nWWW-Authenticate: Basic realm=\"hello\"\r\n")]
+ [InlineData("WWW-Authenticate: Digest realm=\"hello\", nonce=\"hello\", algorithm=MD5\r\nWWW-Authenticate: Digest realm=\"hello\", nonce=\"hello\", algorithm=MD5\r\n")]
+ [InlineData("WWW-Authenticate: Digest realm=\"hello1\", nonce=\"hello\", algorithm=MD5\r\nWWW-Authenticate: Digest realm=\"hello\", nonce=\"hello\", algorithm=MD5\r\n")]
+ public async void HttpClientHandler_MultipleAuthenticateHeaders_WithSameAuth_Succeeds(string authenticateHeader)
+ {
+ if (IsWinHttpHandler)
+ {
+ // TODO: #28065: Fix failing authentication test cases on different httpclienthandlers.
+ return;
+ }
+
+ await HttpClientHandler_MultipleAuthenticateHeaders_Succeeds(authenticateHeader);
+ }
+
+ [Theory]
+ [InlineData("WWW-Authenticate: Basic realm=\"hello\"\r\nWWW-Authenticate: Digest realm=\"hello\", nonce=\"hello\", algorithm=MD5\r\n")]
+ [InlineData("WWW-Authenticate: Digest realm=\"hello\", nonce=\"hello\", algorithm=MD5\r\nWWW-Authenticate: Basic realm=\"hello\"\r\n")]
+ public async Task HttpClientHandler_MultipleAuthenticateHeaders_Succeeds(string authenticateHeader)
+ {
+ if (PlatformDetection.IsWindowsNanoServer || (IsCurlHandler && authenticateHeader.Contains("Digest")))
+ {
+ // TODO: #28065: Fix failing authentication test cases on different httpclienthandlers.
+ return;
+ }
+
+ var options = new LoopbackServer.Options { Domain = Domain, Username = Username, Password = Password };
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ HttpClientHandler handler = CreateHttpClientHandler();
+ Task serverTask = server.AcceptConnectionPerformAuthenticationAndCloseAsync(authenticateHeader);
+ await TestHelper.WhenAllCompletedOrAnyFailed(s_createAndValidateRequest(handler, url, HttpStatusCode.OK, s_credentials), serverTask);
+ }, options);
+ }
+
+ [Theory]
+ [InlineData("WWW-Authenticate: Basic realm=\"hello\"\r\nWWW-Authenticate: NTLM\r\n", "Basic", "Negotiate")]
+ [InlineData("WWW-Authenticate: Basic realm=\"hello\"\r\nWWW-Authenticate: Digest realm=\"hello\", nonce=\"hello\", algorithm=MD5\r\nWWW-Authenticate: NTLM\r\n", "Digest", "Negotiate")]
+ public async Task HttpClientHandler_MultipleAuthenticateHeaders_PicksSupported(string authenticateHeader, string supportedAuth, string unsupportedAuth)
+ {
+ if (PlatformDetection.IsWindowsNanoServer || (IsCurlHandler && authenticateHeader.Contains("Digest")))
+ {
+ // TODO: #28065: Fix failing authentication test cases on different httpclienthandlers.
+ return;
+ }
+
+ var options = new LoopbackServer.Options { Domain = Domain, Username = Username, Password = Password };
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ HttpClientHandler handler = CreateHttpClientHandler();
+ handler.UseDefaultCredentials = false;
+
+ var credentials = new CredentialCache();
+ credentials.Add(url, supportedAuth, new NetworkCredential(Username, Password, Domain));
+ credentials.Add(url, unsupportedAuth, new NetworkCredential(Username, Password, Domain));
+
+ Task serverTask = server.AcceptConnectionPerformAuthenticationAndCloseAsync(authenticateHeader);
+ await TestHelper.WhenAllCompletedOrAnyFailed(s_createAndValidateRequest(handler, url, HttpStatusCode.OK, credentials), serverTask);
+ }, options);
+ }
+
+ [Theory]
+ [InlineData("WWW-Authenticate: Basic realm=\"hello\"\r\n")]
+ [InlineData("WWW-Authenticate: Digest realm=\"hello\", nonce=\"testnonce\"\r\n")]
+ public async void HttpClientHandler_IncorrectCredentials_Fails(string authenticateHeader)
+ {
+ var options = new LoopbackServer.Options { Domain = Domain, Username = Username, Password = Password };
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ HttpClientHandler handler = CreateHttpClientHandler();
+ Task serverTask = server.AcceptConnectionPerformAuthenticationAndCloseAsync(authenticateHeader);
+ await TestHelper.WhenAllCompletedOrAnyFailed(s_createAndValidateRequest(handler, url, HttpStatusCode.Unauthorized, new NetworkCredential("wronguser", "wrongpassword")), serverTask);
+ }, options);
+ }
+
+ public static IEnumerable<object[]> Authentication_TestData()
+ {
+ yield return new object[] { "Basic realm=\"testrealm\"", true };
+ yield return new object[] { "Basic ", true };
+ yield return new object[] { "Basic realm=withoutquotes", true };
+ yield return new object[] { "basic ", true };
+ yield return new object[] { "bAsiC ", true };
+ yield return new object[] { "basic", true };
+
+ yield return new object[] { $"Digest realm=\"testrealm\", nonce=\"{Convert.ToBase64String(Encoding.UTF8.GetBytes($"{DateTimeOffset.UtcNow}:XMh;z+$5|`i6Hx}}\", qop=auth-int, algorithm=MD5"))}\"", true };
+ yield return new object[] { $"Basic realm=\"testrealm\", " +
+ $"Digest realm=\"testrealm\", nonce=\"{Convert.ToBase64String(Encoding.UTF8.GetBytes($"{DateTimeOffset.UtcNow}:XMh;z+$5|`i6Hx}}"))}\", algorithm=MD5", true };
+
+ if (PlatformDetection.IsNetCore)
+ {
+ // TODO: #28060: Fix failing authentication test cases on Framework run.
+ yield return new object[] { "Basic something, Digest something", false };
+ yield return new object[] { $"Digest realm=\"testrealm\", nonce=\"testnonce\", algorithm=MD5 " +
+ $"Basic realm=\"testrealm\"", false };
+ }
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("Basic")]
+ [InlineData("Digest")]
+ [InlineData("NTLM")]
+ [InlineData("Kerberos")]
+ [InlineData("Negotiate")]
+ public async Task PreAuthenticate_NoPreviousAuthenticatedRequests_NoCredentialsSent(string credCacheScheme)
+ {
+ if (IsCurlHandler && credCacheScheme != null)
+ {
+ // When provided with a credential that targets just one auth scheme,
+ // libcurl will often proactively send an auth header.
+ return;
+ }
+
+ const int NumRequests = 3;
+ await LoopbackServer.CreateClientAndServerAsync(async uri =>
+ {
+ using (HttpClientHandler handler = CreateHttpClientHandler())
+ using (var client = new HttpClient(handler))
+ {
+ client.DefaultRequestHeaders.ConnectionClose = true; // for simplicity of not needing to know every handler's pooling policy
+ handler.PreAuthenticate = true;
+ switch (credCacheScheme)
+ {
+ case null:
+ handler.Credentials = s_credentials;
+ break;
+
+ default:
+ var cc = new CredentialCache();
+ cc.Add(uri, credCacheScheme, s_credentials);
+ handler.Credentials = cc;
+ break;
+ }
+
+ for (int i = 0; i < NumRequests; i++)
+ {
+ Assert.Equal("hello world", await client.GetStringAsync(uri));
+ }
+ }
+ },
+ async server =>
+ {
+ for (int i = 0; i < NumRequests; i++)
+ {
+ List<string> headers = await server.AcceptConnectionSendResponseAndCloseAsync(content: "hello world");
+ Assert.All(headers, header => Assert.DoesNotContain("Authorization", header));
+ }
+ });
+ }
+
+ [Theory]
+ [InlineData(null, "WWW-Authenticate: Basic realm=\"hello\"\r\n")]
+ [InlineData("Basic", "WWW-Authenticate: Basic realm=\"hello\"\r\n")]
+ public async Task PreAuthenticate_FirstRequestNoHeaderAndAuthenticates_SecondRequestPreauthenticates(string credCacheScheme, string authResponse)
+ {
+ if (IsCurlHandler && credCacheScheme != null)
+ {
+ // When provided with a credential that targets just one auth scheme,
+ // libcurl will often proactively send an auth header.
+ return;
+ }
+
+ await LoopbackServer.CreateClientAndServerAsync(async uri =>
+ {
+ using (HttpClientHandler handler = CreateHttpClientHandler())
+ using (var client = new HttpClient(handler))
+ {
+ client.DefaultRequestHeaders.ConnectionClose = true; // for simplicity of not needing to know every handler's pooling policy
+ handler.PreAuthenticate = true;
+ switch (credCacheScheme)
+ {
+ case null:
+ handler.Credentials = s_credentials;
+ break;
+
+ default:
+ var cc = new CredentialCache();
+ cc.Add(uri, credCacheScheme, s_credentials);
+ handler.Credentials = cc;
+ break;
+ }
+
+ Assert.Equal("hello world", await client.GetStringAsync(uri));
+ Assert.Equal("hello world", await client.GetStringAsync(uri));
+ }
+ },
+ async server =>
+ {
+ List<string> headers = await server.AcceptConnectionSendResponseAndCloseAsync(HttpStatusCode.Unauthorized, authResponse);
+ Assert.All(headers, header => Assert.DoesNotContain("Authorization", header));
+
+ for (int i = 0; i < 2; i++)
+ {
+ headers = await server.AcceptConnectionSendResponseAndCloseAsync(content: "hello world");
+ Assert.Contains(headers, header => header.Contains("Authorization"));
+ }
+ });
+ }
+
+ // InlineDatas for all values that pass on WinHttpHandler, which is the most restrictive.
+ // Uses numerical values for values named in .NET Core and not in .NET Framework.
+ [Theory]
+ [InlineData(HttpStatusCode.OK)]
+ [InlineData(HttpStatusCode.Created)]
+ [InlineData(HttpStatusCode.Accepted)]
+ [InlineData(HttpStatusCode.NonAuthoritativeInformation)]
+ [InlineData(HttpStatusCode.NoContent)]
+ [InlineData(HttpStatusCode.ResetContent)]
+ [InlineData(HttpStatusCode.PartialContent)]
+ [InlineData((HttpStatusCode)207)] // MultiStatus
+ [InlineData((HttpStatusCode)208)] // AlreadyReported
+ [InlineData((HttpStatusCode)226)] // IMUsed
+ [InlineData(HttpStatusCode.Ambiguous)]
+ [InlineData(HttpStatusCode.Ambiguous)]
+ [InlineData(HttpStatusCode.NotModified)]
+ [InlineData(HttpStatusCode.UseProxy)]
+ [InlineData(HttpStatusCode.Unused)]
+ [InlineData(HttpStatusCode.BadRequest)]
+ [InlineData(HttpStatusCode.PaymentRequired)]
+ [InlineData(HttpStatusCode.Forbidden)]
+ [InlineData(HttpStatusCode.NotFound)]
+ [InlineData(HttpStatusCode.MethodNotAllowed)]
+ [InlineData(HttpStatusCode.NotAcceptable)]
+ [InlineData(HttpStatusCode.RequestTimeout)]
+ [InlineData(HttpStatusCode.Conflict)]
+ [InlineData(HttpStatusCode.Gone)]
+ [InlineData(HttpStatusCode.LengthRequired)]
+ [InlineData(HttpStatusCode.PreconditionFailed)]
+ [InlineData(HttpStatusCode.RequestEntityTooLarge)]
+ [InlineData(HttpStatusCode.RequestUriTooLong)]
+ [InlineData(HttpStatusCode.UnsupportedMediaType)]
+ [InlineData(HttpStatusCode.RequestedRangeNotSatisfiable)]
+ [InlineData(HttpStatusCode.ExpectationFailed)]
+ [InlineData((HttpStatusCode)421)] // MisdirectedRequest
+ [InlineData((HttpStatusCode)422)] // UnprocessableEntity
+ [InlineData((HttpStatusCode)423)] // Locked
+ [InlineData((HttpStatusCode)424)] // FailedDependency
+ [InlineData(HttpStatusCode.UpgradeRequired)]
+ [InlineData((HttpStatusCode)428)] // PreconditionRequired
+ [InlineData((HttpStatusCode)429)] // TooManyRequests
+ [InlineData((HttpStatusCode)431)] // RequestHeaderFieldsTooLarge
+ [InlineData((HttpStatusCode)451)] // UnavailableForLegalReasons
+ [InlineData(HttpStatusCode.InternalServerError)]
+ [InlineData(HttpStatusCode.NotImplemented)]
+ [InlineData(HttpStatusCode.BadGateway)]
+ [InlineData(HttpStatusCode.ServiceUnavailable)]
+ [InlineData(HttpStatusCode.GatewayTimeout)]
+ [InlineData(HttpStatusCode.HttpVersionNotSupported)]
+ [InlineData((HttpStatusCode)506)] // VariantAlsoNegotiates
+ [InlineData((HttpStatusCode)507)] // InsufficientStorage
+ [InlineData((HttpStatusCode)508)] // LoopDetected
+ [InlineData((HttpStatusCode)510)] // NotExtended
+ [InlineData((HttpStatusCode)511)] // NetworkAuthenticationRequired
+ public async Task PreAuthenticate_FirstRequestNoHeader_SecondRequestVariousStatusCodes_ThirdRequestPreauthenticates(HttpStatusCode statusCode)
+ {
+ const string AuthResponse = "WWW-Authenticate: Basic realm=\"hello\"\r\n";
+
+ await LoopbackServer.CreateClientAndServerAsync(async uri =>
+ {
+ using (HttpClientHandler handler = CreateHttpClientHandler())
+ using (var client = new HttpClient(handler))
+ {
+ client.DefaultRequestHeaders.ConnectionClose = true; // for simplicity of not needing to know every handler's pooling policy
+ handler.PreAuthenticate = true;
+ handler.Credentials = s_credentials;
+ client.DefaultRequestHeaders.ExpectContinue = false;
+
+ using (HttpResponseMessage resp = await client.GetAsync(uri))
+ {
+ Assert.Equal(statusCode, resp.StatusCode);
+ }
+ Assert.Equal("hello world", await client.GetStringAsync(uri));
+ }
+ },
+ async server =>
+ {
+ List<string> headers = await server.AcceptConnectionSendResponseAndCloseAsync(HttpStatusCode.Unauthorized, AuthResponse);
+ Assert.All(headers, header => Assert.DoesNotContain("Authorization", header));
+
+ headers = await server.AcceptConnectionSendResponseAndCloseAsync(statusCode);
+ Assert.Contains(headers, header => header.Contains("Authorization"));
+
+ headers = await server.AcceptConnectionSendResponseAndCloseAsync(HttpStatusCode.OK, content: "hello world");
+ Assert.Contains(headers, header => header.Contains("Authorization"));
+ });
+ }
+
+ [Theory]
+ [InlineData("/something/hello.html", "/something/hello.html", true)]
+ [InlineData("/something/hello.html", "/something/world.html", true)]
+ [InlineData("/something/hello.html", "/something/", true)]
+ [InlineData("/something/hello.html", "/", false)]
+ [InlineData("/something/hello.html", "/hello.html", false)]
+ [InlineData("/something/hello.html", "/world.html", false)]
+ [InlineData("/something/hello.html", "/another/", false)]
+ [InlineData("/something/hello.html", "/another/hello.html", false)]
+ public async Task PreAuthenticate_AuthenticatedUrl_ThenTryDifferentUrl_SendsAuthHeaderOnlyIfPrefixMatches(
+ string originalRelativeUri, string secondRelativeUri, bool expectedAuthHeader)
+ {
+ const string AuthResponse = "WWW-Authenticate: Basic realm=\"hello\"\r\n";
+
+ await LoopbackServer.CreateClientAndServerAsync(async uri =>
+ {
+ using (HttpClientHandler handler = CreateHttpClientHandler())
+ using (var client = new HttpClient(handler))
+ {
+ client.DefaultRequestHeaders.ConnectionClose = true; // for simplicity of not needing to know every handler's pooling policy
+ handler.PreAuthenticate = true;
+ handler.Credentials = s_credentials;
+
+ Assert.Equal("hello world 1", await client.GetStringAsync(new Uri(uri, originalRelativeUri)));
+ Assert.Equal("hello world 2", await client.GetStringAsync(new Uri(uri, secondRelativeUri)));
+ }
+ },
+ async server =>
+ {
+ List<string> headers = await server.AcceptConnectionSendResponseAndCloseAsync(HttpStatusCode.Unauthorized, AuthResponse);
+ Assert.All(headers, header => Assert.DoesNotContain("Authorization", header));
+
+ headers = await server.AcceptConnectionSendResponseAndCloseAsync(content: "hello world 1");
+ Assert.Contains(headers, header => header.Contains("Authorization"));
+
+ headers = await server.AcceptConnectionSendResponseAndCloseAsync(content: "hello world 2");
+ if (expectedAuthHeader)
+ {
+ Assert.Contains(headers, header => header.Contains("Authorization"));
+ }
+ else
+ {
+ Assert.All(headers, header => Assert.DoesNotContain("Authorization", header));
+ }
+ });
+ }
+
+ [Fact]
+ public async Task PreAuthenticate_SuccessfulBasicButThenFails_DoesntLoopInfinitely()
+ {
+ await LoopbackServer.CreateClientAndServerAsync(async uri =>
+ {
+ using (HttpClientHandler handler = CreateHttpClientHandler())
+ using (var client = new HttpClient(handler))
+ {
+ client.DefaultRequestHeaders.ConnectionClose = true; // for simplicity of not needing to know every handler's pooling policy
+ handler.PreAuthenticate = true;
+ handler.Credentials = s_credentials;
+
+ // First two requests: initially without auth header, then with
+ Assert.Equal("hello world", await client.GetStringAsync(uri));
+
+ // Attempt preauth, and when that fails, give up.
+ using (HttpResponseMessage resp = await client.GetAsync(uri))
+ {
+ Assert.Equal(HttpStatusCode.Unauthorized, resp.StatusCode);
+ }
+ }
+ },
+ async server =>
+ {
+ // First request, no auth header, challenge Basic
+ List<string> headers = headers = await server.AcceptConnectionSendResponseAndCloseAsync(HttpStatusCode.Unauthorized, "WWW-Authenticate: Basic realm=\"hello\"\r\n");
+ Assert.All(headers, header => Assert.DoesNotContain("Authorization", header));
+
+ // Second request, contains Basic auth header
+ headers = await server.AcceptConnectionSendResponseAndCloseAsync(content: "hello world");
+ Assert.Contains(headers, header => header.Contains("Authorization"));
+
+ // Third request, contains Basic auth header but challenges anyway
+ headers = headers = await server.AcceptConnectionSendResponseAndCloseAsync(HttpStatusCode.Unauthorized, "WWW-Authenticate: Basic realm=\"hello\"\r\n");
+ Assert.Contains(headers, header => header.Contains("Authorization"));
+
+ if (IsNetfxHandler)
+ {
+ // For some reason, netfx tries one more time.
+ headers = headers = await server.AcceptConnectionSendResponseAndCloseAsync(HttpStatusCode.Unauthorized, "WWW-Authenticate: Basic realm=\"hello\"\r\n");
+ Assert.Contains(headers, header => header.Contains("Authorization"));
+ }
+ });
+ }
+
+ [Fact]
+ public async Task PreAuthenticate_SuccessfulBasic_ThenDigestChallenged()
+ {
+ if (IsWinHttpHandler)
+ {
+ // WinHttpHandler fails with Unauthorized after the basic preauth fails.
+ return;
+ }
+
+ if (IsCurlHandler)
+ {
+ // When provided with a credential that targets just one auth scheme,
+ // libcurl will often proactively send an auth header.
+ return;
+ }
+
+ await LoopbackServer.CreateClientAndServerAsync(async uri =>
+ {
+ using (HttpClientHandler handler = CreateHttpClientHandler())
+ using (var client = new HttpClient(handler))
+ {
+ client.DefaultRequestHeaders.ConnectionClose = true; // for simplicity of not needing to know every handler's pooling policy
+ handler.PreAuthenticate = true;
+ handler.Credentials = s_credentials;
+
+ Assert.Equal("hello world", await client.GetStringAsync(uri));
+ Assert.Equal("hello world", await client.GetStringAsync(uri));
+ }
+ },
+ async server =>
+ {
+ // First request, no auth header, challenge Basic
+ List<string> headers = headers = await server.AcceptConnectionSendResponseAndCloseAsync(HttpStatusCode.Unauthorized, "WWW-Authenticate: Basic realm=\"hello\"\r\n");
+ Assert.All(headers, header => Assert.DoesNotContain("Authorization", header));
+
+ // Second request, contains Basic auth header, success
+ headers = await server.AcceptConnectionSendResponseAndCloseAsync(content: "hello world");
+ Assert.Contains(headers, header => header.Contains("Authorization"));
+
+ // Third request, contains Basic auth header, challenge digest
+ headers = await server.AcceptConnectionSendResponseAndCloseAsync(HttpStatusCode.Unauthorized, "WWW-Authenticate: Digest realm=\"hello\", nonce=\"testnonce\"\r\n");
+ Assert.Contains(headers, header => header.Contains("Authorization: Basic"));
+
+ // Fourth request, contains Digest auth header, success
+ headers = await server.AcceptConnectionSendResponseAndCloseAsync(content: "hello world");
+ Assert.Contains(headers, header => header.Contains("Authorization: Digest"));
+ });
+ }
+ }
+}
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Cancellation.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Cancellation.cs
new file mode 100644
index 0000000000..8cb0273fc1
--- /dev/null
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Cancellation.cs
@@ -0,0 +1,449 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.IO;
+using System.Net.Test.Common;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.Net.Http.Functional.Tests
+{
+ public abstract class HttpClientHandler_Cancellation_Test : HttpClientTestBase
+ {
+ [Theory]
+ [InlineData(false, CancellationMode.Token)]
+ [InlineData(true, CancellationMode.Token)]
+ public async Task PostAsync_CancelDuringRequestContentSend_TaskCanceledQuickly(bool chunkedTransfer, CancellationMode mode)
+ {
+ if (!UseSocketsHttpHandler)
+ {
+ // Issue #27063: hangs / doesn't cancel
+ return;
+ }
+
+ var serverRelease = new TaskCompletionSource<bool>();
+ await LoopbackServer.CreateClientAndServerAsync(async uri =>
+ {
+ try
+ {
+ using (HttpClient client = CreateHttpClient())
+ {
+ client.Timeout = Timeout.InfiniteTimeSpan;
+ var cts = new CancellationTokenSource();
+
+ var waitToSend = new TaskCompletionSource<bool>();
+ var contentSending = new TaskCompletionSource<bool>();
+ var req = new HttpRequestMessage(HttpMethod.Post, uri) { Content = new ByteAtATimeContent(int.MaxValue, waitToSend.Task, contentSending) };
+ req.Headers.TransferEncodingChunked = chunkedTransfer;
+
+ Task<HttpResponseMessage> resp = client.SendAsync(req, HttpCompletionOption.ResponseHeadersRead, cts.Token);
+ waitToSend.SetResult(true);
+ await contentSending.Task;
+ Cancel(mode, client, cts);
+ await ValidateClientCancellationAsync(() => resp);
+ }
+ }
+ finally
+ {
+ serverRelease.SetResult(true);
+ }
+ }, server => server.AcceptConnectionAsync(connection => serverRelease.Task));
+ }
+
+ [Theory]
+ [MemberData(nameof(TwoBoolsAndCancellationMode))]
+ public async Task GetAsync_CancelDuringResponseHeadersReceived_TaskCanceledQuickly(bool chunkedTransfer, bool connectionClose, CancellationMode mode)
+ {
+ using (HttpClient client = CreateHttpClient())
+ {
+ client.Timeout = Timeout.InfiniteTimeSpan;
+ var cts = new CancellationTokenSource();
+
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ var partialResponseHeadersSent = new TaskCompletionSource<bool>();
+ var clientFinished = new TaskCompletionSource<bool>();
+
+ Task serverTask = server.AcceptConnectionAsync(async connection =>
+ {
+ await connection.ReadRequestHeaderAndSendCustomResponseAsync(
+ $"HTTP/1.1 200 OK\r\nDate: {DateTimeOffset.UtcNow:R}\r\n"); // missing final \r\n so headers don't complete
+
+ partialResponseHeadersSent.TrySetResult(true);
+ await clientFinished.Task;
+ });
+
+ await ValidateClientCancellationAsync(async () =>
+ {
+ var req = new HttpRequestMessage(HttpMethod.Get, url);
+ req.Headers.ConnectionClose = connectionClose;
+
+ Task<HttpResponseMessage> getResponse = client.SendAsync(req, HttpCompletionOption.ResponseHeadersRead, cts.Token);
+ await partialResponseHeadersSent.Task;
+ Cancel(mode, client, cts);
+ await getResponse;
+ });
+
+ try
+ {
+ clientFinished.SetResult(true);
+ await serverTask;
+ } catch { }
+ });
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(TwoBoolsAndCancellationMode))]
+ public async Task GetAsync_CancelDuringResponseBodyReceived_Buffered_TaskCanceledQuickly(bool chunkedTransfer, bool connectionClose, CancellationMode mode)
+ {
+ using (HttpClient client = CreateHttpClient())
+ {
+ client.Timeout = Timeout.InfiniteTimeSpan;
+ var cts = new CancellationTokenSource();
+
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ var responseHeadersSent = new TaskCompletionSource<bool>();
+ var clientFinished = new TaskCompletionSource<bool>();
+
+ Task serverTask = server.AcceptConnectionAsync(async connection =>
+ {
+ await connection.ReadRequestHeaderAndSendCustomResponseAsync(
+ $"HTTP/1.1 200 OK\r\n" +
+ $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
+ (!chunkedTransfer ? "Content-Length: 20\r\n" : "") +
+ (connectionClose ? "Connection: close\r\n" : "") +
+ $"\r\n123"); // "123" is part of body and could either be chunked size or part of content-length bytes, both incomplete
+
+ responseHeadersSent.TrySetResult(true);
+ await clientFinished.Task;
+ });
+
+ await ValidateClientCancellationAsync(async () =>
+ {
+ var req = new HttpRequestMessage(HttpMethod.Get, url);
+ req.Headers.ConnectionClose = connectionClose;
+
+ Task<HttpResponseMessage> getResponse = client.SendAsync(req, HttpCompletionOption.ResponseContentRead, cts.Token);
+ await responseHeadersSent.Task;
+ await Task.Delay(1); // make it more likely that client will have started processing response body
+ Cancel(mode, client, cts);
+ await getResponse;
+ });
+
+ try
+ {
+ clientFinished.SetResult(true);
+ await serverTask;
+ } catch { }
+ });
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(ThreeBools))]
+ public async Task GetAsync_CancelDuringResponseBodyReceived_Unbuffered_TaskCanceledQuickly(bool chunkedTransfer, bool connectionClose, bool readOrCopyToAsync)
+ {
+ if (IsNetfxHandler || IsCurlHandler)
+ {
+ // doesn't cancel
+ return;
+ }
+
+ using (HttpClient client = CreateHttpClient())
+ {
+ client.Timeout = Timeout.InfiniteTimeSpan;
+ var cts = new CancellationTokenSource();
+
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ var clientFinished = new TaskCompletionSource<bool>();
+
+ Task serverTask = server.AcceptConnectionAsync(async connection =>
+ {
+ await connection.ReadRequestHeaderAndSendCustomResponseAsync(
+ $"HTTP/1.1 200 OK\r\n" +
+ $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
+ (!chunkedTransfer ? "Content-Length: 20\r\n" : "") +
+ (connectionClose ? "Connection: close\r\n" : "") +
+ $"\r\n");
+
+ await clientFinished.Task;
+ });
+
+ var req = new HttpRequestMessage(HttpMethod.Get, url);
+ req.Headers.ConnectionClose = connectionClose;
+ Task<HttpResponseMessage> getResponse = client.SendAsync(req, HttpCompletionOption.ResponseHeadersRead, cts.Token);
+ await ValidateClientCancellationAsync(async () =>
+ {
+ HttpResponseMessage resp = await getResponse;
+ Stream respStream = await resp.Content.ReadAsStreamAsync();
+ Task readTask = readOrCopyToAsync ?
+ respStream.ReadAsync(new byte[1], 0, 1, cts.Token) :
+ respStream.CopyToAsync(Stream.Null, 10, cts.Token);
+ cts.Cancel();
+ await readTask;
+ });
+
+ try
+ {
+ clientFinished.SetResult(true);
+ await serverTask;
+ } catch { }
+ });
+ }
+ }
+
+ [Theory]
+ [InlineData(CancellationMode.CancelPendingRequests, false)]
+ [InlineData(CancellationMode.DisposeHttpClient, true)]
+ [InlineData(CancellationMode.CancelPendingRequests, false)]
+ [InlineData(CancellationMode.DisposeHttpClient, true)]
+ public async Task GetAsync_CancelPendingRequests_DoesntCancelReadAsyncOnResponseStream(CancellationMode mode, bool copyToAsync)
+ {
+ if (IsNetfxHandler)
+ {
+ // throws ObjectDisposedException as part of Stream.CopyToAsync/ReadAsync
+ return;
+ }
+ if (IsCurlHandler)
+ {
+ // Issue #27065
+ // throws OperationCanceledException from Stream.CopyToAsync/ReadAsync
+ return;
+ }
+
+ using (HttpClient client = CreateHttpClient())
+ {
+ client.Timeout = Timeout.InfiniteTimeSpan;
+
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ var clientReadSomeBody = new TaskCompletionSource<bool>();
+ var clientFinished = new TaskCompletionSource<bool>();
+
+ var responseContentSegment = new string('s', 3000);
+ int responseSegments = 4;
+ int contentLength = responseContentSegment.Length * responseSegments;
+
+ Task serverTask = server.AcceptConnectionAsync(async connection =>
+ {
+ await connection.ReadRequestHeaderAndSendCustomResponseAsync(
+ $"HTTP/1.1 200 OK\r\n" +
+ $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
+ $"Content-Length: {contentLength}\r\n" +
+ $"\r\n");
+
+ for (int i = 0; i < responseSegments; i++)
+ {
+ await connection.Writer.WriteAsync(responseContentSegment);
+ if (i == 0)
+ {
+ await clientReadSomeBody.Task;
+ }
+ }
+
+ await clientFinished.Task;
+ });
+
+
+ using (HttpResponseMessage resp = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))
+ using (Stream respStream = await resp.Content.ReadAsStreamAsync())
+ {
+ var result = new MemoryStream();
+ int b = respStream.ReadByte();
+ Assert.NotEqual(-1, b);
+ result.WriteByte((byte)b);
+
+ Cancel(mode, client, null); // should not cancel the operation, as using ResponseHeadersRead
+ clientReadSomeBody.SetResult(true);
+
+ if (copyToAsync)
+ {
+ await respStream.CopyToAsync(result, 10, new CancellationTokenSource().Token);
+ }
+ else
+ {
+ byte[] buffer = new byte[10];
+ int bytesRead;
+ while ((bytesRead = await respStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
+ {
+ result.Write(buffer, 0, bytesRead);
+ }
+ }
+
+ Assert.Equal(contentLength, result.Length);
+ }
+
+ clientFinished.SetResult(true);
+ await serverTask;
+ });
+ }
+ }
+
+ [Fact]
+ public async Task MaxConnectionsPerServer_WaitingConnectionsAreCancelable()
+ {
+ if (IsWinHttpHandler)
+ {
+ // Issue #27064:
+ // Throws WinHttpException ("The server returned an invalid or unrecognized response")
+ // while parsing headers.
+ return;
+ }
+ if (IsNetfxHandler)
+ {
+ // Throws HttpRequestException wrapping a WebException for the canceled request
+ // instead of throwing an OperationCanceledException or a canceled WebException directly.
+ return;
+ }
+
+ using (HttpClientHandler handler = CreateHttpClientHandler())
+ using (HttpClient client = new HttpClient(handler))
+ {
+ handler.MaxConnectionsPerServer = 1;
+ client.Timeout = Timeout.InfiniteTimeSpan;
+
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ var serverAboutToBlock = new TaskCompletionSource<bool>();
+ var blockServerResponse = new TaskCompletionSource<bool>();
+
+ Task serverTask1 = server.AcceptConnectionAsync(async connection1 =>
+ {
+ await connection1.ReadRequestHeaderAsync();
+ await connection1.Writer.WriteAsync($"HTTP/1.1 200 OK\r\nDate: {DateTimeOffset.UtcNow:R}\r\n");
+ serverAboutToBlock.SetResult(true);
+ await blockServerResponse.Task;
+ await connection1.Writer.WriteAsync("Content-Length: 5\r\n\r\nhello");
+ });
+
+ Task get1 = client.GetAsync(url);
+ await serverAboutToBlock.Task;
+
+ var cts = new CancellationTokenSource();
+ Task get2 = ValidateClientCancellationAsync(() => client.GetAsync(url, cts.Token));
+ Task get3 = ValidateClientCancellationAsync(() => client.GetAsync(url, cts.Token));
+
+ Task get4 = client.GetAsync(url);
+
+ cts.Cancel();
+ await get2;
+ await get3;
+
+ blockServerResponse.SetResult(true);
+ await new[] { get1, serverTask1 }.WhenAllOrAnyFailed();
+
+ Task serverTask4 = server.AcceptConnectionSendResponseAndCloseAsync();
+
+ await new[] { get4, serverTask4 }.WhenAllOrAnyFailed();
+ });
+ }
+ }
+
+ private async Task ValidateClientCancellationAsync(Func<Task> clientBodyAsync)
+ {
+ var stopwatch = Stopwatch.StartNew();
+ Exception error = await Record.ExceptionAsync(clientBodyAsync);
+ stopwatch.Stop();
+
+ Assert.NotNull(error);
+
+ if (IsNetfxHandler)
+ {
+ Assert.True(
+ error is WebException we && we.Status == WebExceptionStatus.RequestCanceled ||
+ error is OperationCanceledException,
+ "Expected cancellation exception, got:" + Environment.NewLine + error);
+ }
+ else
+ {
+ Assert.True(
+ error is OperationCanceledException,
+ "Expected cancellation exception, got:" + Environment.NewLine + error);
+ }
+
+ Assert.True(stopwatch.Elapsed < new TimeSpan(0, 0, 30), $"Elapsed time {stopwatch.Elapsed} should be less than 30 seconds, was {stopwatch.Elapsed.TotalSeconds}");
+ }
+
+ private static void Cancel(CancellationMode mode, HttpClient client, CancellationTokenSource cts)
+ {
+ if ((mode & CancellationMode.Token) != 0)
+ {
+ cts?.Cancel();
+ }
+
+ if ((mode & CancellationMode.CancelPendingRequests) != 0)
+ {
+ client?.CancelPendingRequests();
+ }
+
+ if ((mode & CancellationMode.DisposeHttpClient) != 0)
+ {
+ client?.Dispose();
+ }
+ }
+
+ [Flags]
+ public enum CancellationMode
+ {
+ Token = 0x1,
+ CancelPendingRequests = 0x2,
+ DisposeHttpClient = 0x4
+ }
+
+ private static readonly bool[] s_bools = new[] { true, false };
+
+ public static IEnumerable<object[]> TwoBoolsAndCancellationMode() =>
+ from first in s_bools
+ from second in s_bools
+ from mode in new[] { CancellationMode.Token, CancellationMode.CancelPendingRequests, CancellationMode.DisposeHttpClient, CancellationMode.Token | CancellationMode.CancelPendingRequests }
+ select new object[] { first, second, mode };
+
+ public static IEnumerable<object[]> ThreeBools() =>
+ from first in s_bools
+ from second in s_bools
+ from third in s_bools
+ select new object[] { first, second, third };
+
+ private sealed class ByteAtATimeContent : HttpContent
+ {
+ private readonly Task _waitToSend;
+ private readonly TaskCompletionSource<bool> _startedSend;
+ private readonly int _length;
+
+ public ByteAtATimeContent(int length, Task waitToSend, TaskCompletionSource<bool> startedSend)
+ {
+ _length = length;
+ _waitToSend = waitToSend;
+ _startedSend = startedSend;
+ }
+
+ protected override async Task SerializeToStreamAsync(Stream stream, TransportContext context)
+ {
+ await _waitToSend;
+ _startedSend.SetResult(true);
+
+ var buffer = new byte[1] { 42 };
+ for (int i = 0; i < _length; i++)
+ {
+ await stream.WriteAsync(buffer);
+ await stream.FlushAsync();
+ await Task.Delay(1);
+ }
+ }
+
+ protected override bool TryComputeLength(out long length)
+ {
+ length = _length;
+ return true;
+ }
+ }
+ }
+}
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ClientCertificates.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ClientCertificates.cs
index 9530ce22fe..78d0fdb09f 100644
--- a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ClientCertificates.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ClientCertificates.cs
@@ -5,6 +5,7 @@
using System.Net.Security;
using System.Net.Sockets;
using System.Net.Test.Common;
+using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Xunit;
@@ -14,7 +15,7 @@ namespace System.Net.Http.Functional.Tests
{
using Configuration = System.Net.Test.Common.Configuration;
- public class HttpClientHandler_ClientCertificates_Test : HttpClientTestBase
+ public abstract class HttpClientHandler_ClientCertificates_Test : HttpClientTestBase
{
public bool CanTestCertificates =>
Capability.IsTrustedRootCertificateInstalled() &&
@@ -75,7 +76,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
public async Task Automatic_SSLBackendNotSupported_ThrowsPlatformNotSupportedException()
{
- if (BackendSupportsCustomCertificateHandling) // can't use [Conditional*] right now as it's evaluated at the wrong time for the managed handler
+ if (BackendSupportsCustomCertificateHandling) // can't use [Conditional*] right now as it's evaluated at the wrong time for SocketsHttpHandler
{
return;
}
@@ -92,7 +93,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
public async Task Manual_SSLBackendNotSupported_ThrowsPlatformNotSupportedException()
{
- if (BackendSupportsCustomCertificateHandling) // can't use [Conditional*] right now as it's evaluated at the wrong time for the managed handler
+ if (BackendSupportsCustomCertificateHandling) // can't use [Conditional*] right now as it's evaluated at the wrong time for SocketsHttpHandler
{
return;
}
@@ -109,7 +110,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
public void Manual_SendClientCertificateWithClientAuthEKUToRemoteServer_OK()
{
- if (!CanTestClientCertificates) // can't use [Conditional*] right now as it's evaluated at the wrong time for the managed handler
+ if (!CanTestClientCertificates) // can't use [Conditional*] right now as it's evaluated at the wrong time for SocketsHttpHandler
{
_output.WriteLine($"Skipping {nameof(Manual_SendClientCertificateWithClientAuthEKUToRemoteServer_OK)}()");
return;
@@ -118,10 +119,10 @@ namespace System.Net.Http.Functional.Tests
// UAP HTTP stack caches connections per-process. This causes interference when these tests run in
// the same process as the other tests. Each test needs to be isolated to its own process.
// See dicussion: https://github.com/dotnet/corefx/issues/21945
- RemoteInvoke(async useManagedHandlerString =>
+ RemoteInvoke(async useSocketsHttpHandlerString =>
{
var cert = Configuration.Certificates.GetClientCertificate();
- HttpClientHandler handler = CreateHttpClientHandler(useManagedHandlerString);
+ HttpClientHandler handler = CreateHttpClientHandler(useSocketsHttpHandlerString);
handler.ClientCertificates.Add(cert);
using (var client = new HttpClient(handler))
{
@@ -135,20 +136,14 @@ namespace System.Net.Http.Functional.Tests
return SuccessExitCode;
}
- }, UseManagedHandler.ToString()).Dispose();
+ }, UseSocketsHttpHandler.ToString()).Dispose();
}
[OuterLoop] // TODO: Issue #11345
[Fact]
public void Manual_SendClientCertificateWithServerAuthEKUToRemoteServer_Forbidden()
{
- if (UseManagedHandler)
- {
- // TODO #23128: The managed handler is currently sending out client certificates when it shouldn't.
- return;
- }
-
- if (!CanTestClientCertificates) // can't use [Conditional*] right now as it's evaluated at the wrong time for the managed handler
+ if (!CanTestClientCertificates) // can't use [Conditional*] right now as it's evaluated at the wrong time for SocketsHttpHandler
{
_output.WriteLine($"Skipping {nameof(Manual_SendClientCertificateWithServerAuthEKUToRemoteServer_Forbidden)}()");
return;
@@ -157,10 +152,10 @@ namespace System.Net.Http.Functional.Tests
// UAP HTTP stack caches connections per-process. This causes interference when these tests run in
// the same process as the other tests. Each test needs to be isolated to its own process.
// See dicussion: https://github.com/dotnet/corefx/issues/21945
- RemoteInvoke(async useManagedHandlerString =>
+ RemoteInvoke(async useSocketsHttpHandlerString =>
{
var cert = Configuration.Certificates.GetServerCertificate();
- HttpClientHandler handler = CreateHttpClientHandler(useManagedHandlerString);
+ HttpClientHandler handler = CreateHttpClientHandler(useSocketsHttpHandlerString);
handler.ClientCertificates.Add(cert);
using (var client = new HttpClient(handler))
{
@@ -169,14 +164,14 @@ namespace System.Net.Http.Functional.Tests
return SuccessExitCode;
}
- }, UseManagedHandler.ToString()).Dispose();
+ }, UseSocketsHttpHandler.ToString()).Dispose();
}
[OuterLoop] // TODO: Issue #11345
[Fact]
public void Manual_SendClientCertificateWithNoEKUToRemoteServer_OK()
{
- if (!CanTestClientCertificates) // can't use [Conditional*] right now as it's evaluated at the wrong time for the managed handler
+ if (!CanTestClientCertificates) // can't use [Conditional*] right now as it's evaluated at the wrong time for SocketsHttpHandler
{
_output.WriteLine($"Skipping {nameof(Manual_SendClientCertificateWithNoEKUToRemoteServer_OK)}()");
return;
@@ -185,10 +180,10 @@ namespace System.Net.Http.Functional.Tests
// UAP HTTP stack caches connections per-process. This causes interference when these tests run in
// the same process as the other tests. Each test needs to be isolated to its own process.
// See dicussion: https://github.com/dotnet/corefx/issues/21945
- RemoteInvoke(async useManagedHandlerString =>
+ RemoteInvoke(async useSocketsHttpHandlerString =>
{
var cert = Configuration.Certificates.GetNoEKUCertificate();
- HttpClientHandler handler = CreateHttpClientHandler(useManagedHandlerString);
+ HttpClientHandler handler = CreateHttpClientHandler(useSocketsHttpHandlerString);
handler.ClientCertificates.Add(cert);
using (var client = new HttpClient(handler))
{
@@ -202,12 +197,12 @@ namespace System.Net.Http.Functional.Tests
return SuccessExitCode;
}
- }, UseManagedHandler.ToString()).Dispose();
+ }, UseSocketsHttpHandler.ToString()).Dispose();
}
[SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "dotnet/corefx #20010")]
- [OuterLoop] // TODO: Issue #11345
[ActiveIssue(9543)] // fails sporadically with 'WinHttpException : The server returned an invalid or unrecognized response' or 'TaskCanceledException : A task was canceled'
+ [OuterLoop] // TODO: Issue #11345
[Theory]
[InlineData(6, false)]
[InlineData(3, true)]
@@ -215,12 +210,18 @@ namespace System.Net.Http.Functional.Tests
int numberOfRequests,
bool reuseClient) // validate behavior with and without connection pooling, which impacts client cert usage
{
- if (!BackendSupportsCustomCertificateHandling) // can't use [Conditional*] right now as it's evaluated at the wrong time for the managed handler
+ if (!BackendSupportsCustomCertificateHandling) // can't use [Conditional*] right now as it's evaluated at the wrong time for SocketsHttpHandler
{
_output.WriteLine($"Skipping {nameof(Manual_CertificateSentMatchesCertificateReceived_Success)}()");
return;
}
+ if (!UseSocketsHttpHandler)
+ {
+ // Issue #9543: fails sporadically on WinHttpHandler/CurlHandler
+ return;
+ }
+
var options = new LoopbackServer.Options { UseSsl = true };
Func<X509Certificate2, HttpClient> createClient = (cert) =>
@@ -228,27 +229,27 @@ namespace System.Net.Http.Functional.Tests
HttpClientHandler handler = CreateHttpClientHandler();
handler.ServerCertificateCustomValidationCallback = delegate { return true; };
handler.ClientCertificates.Add(cert);
+ Assert.True(handler.ClientCertificates.Contains(cert));
return new HttpClient(handler);
};
- Func<HttpClient, Socket, Uri, X509Certificate2, Task> makeAndValidateRequest = async (client, server, url, cert) =>
+ Func<HttpClient, LoopbackServer, Uri, X509Certificate2, Task> makeAndValidateRequest = async (client, server, url, cert) =>
{
await TestHelper.WhenAllCompletedOrAnyFailed(
client.GetStringAsync(url),
- LoopbackServer.AcceptSocketAsync(server, async (socket, stream, reader, writer) =>
+ server.AcceptConnectionAsync(async connection =>
{
- SslStream sslStream = Assert.IsType<SslStream>(stream);
+ SslStream sslStream = Assert.IsType<SslStream>(connection.Stream);
Assert.Equal(cert, sslStream.RemoteCertificate);
- await LoopbackServer.ReadWriteAcceptedAsync(socket, reader, writer);
- return null;
- }, options));
+ await connection.ReadRequestHeaderAndSendResponseAsync();
+ }));
};
await LoopbackServer.CreateServerAsync(async (server, url) =>
{
- if (reuseClient)
+ using (X509Certificate2 cert = Configuration.Certificates.GetClientCertificate())
{
- using (X509Certificate2 cert = Configuration.Certificates.GetClientCertificate())
+ if (reuseClient)
{
using (HttpClient client = createClient(cert))
{
@@ -261,28 +262,78 @@ namespace System.Net.Http.Functional.Tests
}
}
}
- }
- else
- {
- for (int i = 0; i < numberOfRequests; i++)
+ else
{
- using (X509Certificate2 cert = Configuration.Certificates.GetClientCertificate())
+ for (int i = 0; i < numberOfRequests; i++)
{
using (HttpClient client = createClient(cert))
{
await makeAndValidateRequest(client, server, url, cert);
}
- }
- GC.Collect();
- GC.WaitForPendingFinalizers();
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ }
}
}
}, options);
}
- private bool BackendSupportsCustomCertificateHandling =>
- UseManagedHandler ||
- new HttpClientHandler_ServerCertificates_Test().BackendSupportsCustomCertificateHandling;
+ [OuterLoop] // TODO: Issue #11345
+ [Theory]
+ [InlineData(ClientCertificateOption.Manual)]
+ [InlineData(ClientCertificateOption.Automatic)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Fails with \"Authentication failed\" error.")]
+ public async Task AutomaticOrManual_DoesntFailRegardlessOfWhetherClientCertsAreAvailable(ClientCertificateOption mode)
+ {
+ if (!BackendSupportsCustomCertificateHandling) // can't use [Conditional*] right now as it's evaluated at the wrong time for SocketsHttpHandler
+ {
+ _output.WriteLine($"Skipping {nameof(Manual_CertificateSentMatchesCertificateReceived_Success)}()");
+ return;
+ }
+
+ using (HttpClientHandler handler = CreateHttpClientHandler())
+ using (var client = new HttpClient(handler))
+ {
+ handler.ServerCertificateCustomValidationCallback = delegate { return true; };
+ handler.ClientCertificateOptions = mode;
+
+ await LoopbackServer.CreateServerAsync(async server =>
+ {
+ Task clientTask = client.GetStringAsync(server.Uri);
+ Task serverTask = server.AcceptConnectionAsync(async connection =>
+ {
+ SslStream sslStream = Assert.IsType<SslStream>(connection.Stream);
+ await connection.ReadRequestHeaderAndSendResponseAsync();
+ });
+
+ await new Task[] { clientTask, serverTask }.WhenAllOrAnyFailed();
+ }, new LoopbackServer.Options { UseSsl = true });
+ }
+ }
+
+ private bool BackendSupportsCustomCertificateHandling
+ {
+ get
+ {
+#if TargetsWindows
+ return true;
+#else
+ if (UseSocketsHttpHandler)
+ {
+ return true;
+ }
+
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ {
+ return false;
+ }
+
+ // For other Unix-based systems it's true if (and only if) the openssl backend
+ // is used with libcurl.
+ return (Interop.Http.GetSslVersionDescription()?.StartsWith(Interop.Http.OpenSsl10Description, StringComparison.OrdinalIgnoreCase) ?? false);
+#endif
+ }
+ }
}
}
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Decompression.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Decompression.cs
new file mode 100644
index 0000000000..362419fbcb
--- /dev/null
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Decompression.cs
@@ -0,0 +1,67 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.IO;
+using System.IO.Compression;
+using System.Net.Test.Common;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.Net.Http.Functional.Tests
+{
+ public abstract class HttpClientHandler_Decompression_Test : HttpClientTestBase
+ {
+ [Fact]
+ public async Task Brotli_DecompressesResponse_Success()
+ {
+ var expectedContent = new byte[12345];
+ new Random(42).NextBytes(expectedContent);
+
+ await LoopbackServer.CreateClientAndServerAsync(async uri =>
+ {
+ using (HttpClient client = CreateHttpClient())
+ using (HttpResponseMessage response = await client.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead))
+ using (var decodedStream = new BrotliStream(await response.Content.ReadAsStreamAsync(), CompressionMode.Decompress))
+ {
+ var data = new MemoryStream();
+ await decodedStream.CopyToAsync(data);
+ Assert.Equal(expectedContent, data.ToArray());
+ }
+ }, async server =>
+ {
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ await connection.ReadRequestHeaderAsync();
+ await connection.Writer.WriteAsync("HTTP/1.1 200 OK\r\nContent-Encoding: br\r\n\r\n");
+ using (var brotli = new BrotliStream(connection.Stream, CompressionLevel.Optimal, leaveOpen: true))
+ {
+ await brotli.WriteAsync(expectedContent);
+ }
+ });
+ });
+ }
+
+ [OuterLoop("Accessing remote server")]
+ [Fact]
+ public async Task Brotli_External_DecompressesResponse_Success()
+ {
+ const string BrotliUrl = "http://httpbin.org/brotli";
+
+ var message = new HttpRequestMessage(HttpMethod.Get, BrotliUrl);
+ message.Headers.TryAddWithoutValidation("SomeAwesomeHeader", "AndItsAwesomeValue");
+
+ using (HttpClient client = CreateHttpClient())
+ using (HttpResponseMessage response = await client.SendAsync(message))
+ {
+ Assert.Contains("br", response.Content.Headers.ContentEncoding);
+ using (var decodedStream = new BrotliStream(await response.Content.ReadAsStreamAsync(), CompressionMode.Decompress))
+ using (var reader = new StreamReader(decodedStream))
+ {
+ string respText = await reader.ReadToEndAsync();
+ Assert.Contains("AndItsAwesomeValue", respText);
+ }
+ }
+ }
+ }
+}
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.DefaultProxyCredentials.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.DefaultProxyCredentials.cs
index ebdf3a648d..b4177f2cd2 100644
--- a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.DefaultProxyCredentials.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.DefaultProxyCredentials.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Test.Common;
using System.Runtime.InteropServices;
@@ -13,7 +14,7 @@ namespace System.Net.Http.Functional.Tests
{
using Configuration = System.Net.Test.Common.Configuration;
- public class HttpClientHandler_DefaultProxyCredentials_Test : HttpClientTestBase
+ public abstract class HttpClientHandler_DefaultProxyCredentials_Test : HttpClientTestBase
{
[Fact]
public void Default_Get_Null()
@@ -44,85 +45,94 @@ namespace System.Net.Http.Functional.Tests
[ActiveIssue(23702, TargetFrameworkMonikers.NetFramework)]
[ActiveIssue(20010, TargetFrameworkMonikers.Uap)]
- [OuterLoop] // TODO: Issue #11345
[Fact]
public async Task ProxyExplicitlyProvided_DefaultCredentials_Ignored()
{
- int port;
- Task<LoopbackGetRequestHttpProxy.ProxyResult> proxyTask = LoopbackGetRequestHttpProxy.StartAsync(out port, requireAuth: true, expectCreds: true);
- Uri proxyUrl = new Uri($"http://localhost:{port}");
-
- var rightCreds = new NetworkCredential("rightusername", "rightpassword");
- var wrongCreds = new NetworkCredential("wrongusername", "wrongpassword");
+ var explicitProxyCreds = new NetworkCredential("rightusername", "rightpassword");
+ var defaultSystemProxyCreds = new NetworkCredential("wrongusername", "wrongpassword");
+ string expectCreds = "Basic " + Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes($"{explicitProxyCreds.UserName}:{explicitProxyCreds.Password}"));
- using (HttpClientHandler handler = CreateHttpClientHandler())
- using (var client = new HttpClient(handler))
+ await LoopbackServer.CreateServerAsync(async (proxyServer, proxyUrl) =>
{
- handler.Proxy = new UseSpecifiedUriWebProxy(proxyUrl, rightCreds);
- handler.DefaultProxyCredentials = wrongCreds;
-
- Task<HttpResponseMessage> responseTask = client.GetAsync(Configuration.Http.RemoteEchoServer);
- Task<string> responseStringTask = responseTask.ContinueWith(t =>
+ using (HttpClientHandler handler = CreateHttpClientHandler())
+ using (var client = new HttpClient(handler))
{
- using (t.Result) return t.Result.Content.ReadAsStringAsync();
- }, TaskScheduler.Default).Unwrap();
- await (new Task[] { proxyTask, responseTask, responseStringTask }).WhenAllOrAnyFailed();
+ handler.Proxy = new UseSpecifiedUriWebProxy(proxyUrl, explicitProxyCreds);
+ handler.DefaultProxyCredentials = defaultSystemProxyCreds;
- TestHelper.VerifyResponseBody(responseStringTask.Result, responseTask.Result.Content.Headers.ContentMD5, false, null);
- Assert.Equal(Encoding.ASCII.GetString(proxyTask.Result.ResponseContent), responseStringTask.Result);
+ // URL does not matter. We will get response from "proxy" code bellow.
+ Task<HttpResponseMessage> responseTask = client.GetAsync("http://notatrealserver.com/");
- string expectedAuth = $"{rightCreds.UserName}:{rightCreds.Password}";
- Assert.Equal(expectedAuth, proxyTask.Result.AuthenticationHeaderValue);
- }
+ await proxyServer.AcceptConnectionAsync(async connection =>
+ {
+ List<string> headers = await connection.ReadRequestHeaderAsync();
+
+ if (!IsCurlHandler)
+ {
+ // Curl sends Basic auth without asking, other handlers wait for 407.
+ await connection.SendResponseAsync(HttpStatusCode.ProxyAuthenticationRequired, "Proxy-Authenticate: Basic\r\n");
+ headers = await connection.ReadRequestHeaderAsync();
+ }
+
+ // Verify that we got explicitProxyCreds.
+ Assert.Equal(expectCreds, LoopbackServer.GetRequestHeaderValue(headers, "Proxy-Authorization"));
+
+ Task serverTask = connection.SendResponseAsync(HttpStatusCode.OK);
+
+ await TestHelper.WhenAllCompletedOrAnyFailed(serverTask, responseTask);
+ HttpResponseMessage response = responseTask.Result;
+
+ Assert.Equal(response.StatusCode, HttpStatusCode.OK);
+ });
+ };
+ });
}
[OuterLoop] // TODO: Issue #11345
+ [PlatformSpecific(TestPlatforms.AnyUnix)] // The default proxy is resolved via WinINet on Windows.
[Theory]
[InlineData(false)]
[InlineData(true)]
- [ActiveIssue(25640, TestPlatforms.Windows)] // TODO It should be enabled for managed Handler on all platforms
- public void ProxySetViaEnvironmentVariable_DefaultProxyCredentialsUsed(bool useProxy)
+ public async Task ProxySetViaEnvironmentVariable_DefaultProxyCredentialsUsed(bool useProxy)
{
- int port = 0;
- Task<LoopbackGetRequestHttpProxy.ProxyResult> proxyTask = null;
- if (useProxy)
- {
- proxyTask = LoopbackGetRequestHttpProxy.StartAsync(out port, requireAuth: true, expectCreds: true);
- }
-
const string ExpectedUsername = "rightusername";
const string ExpectedPassword = "rightpassword";
+ LoopbackServer.Options options = new LoopbackServer.Options { IsProxy = true, Username = ExpectedUsername, Password = ExpectedPassword };
- // libcurl will read a default proxy from the http_proxy environment variable. Ensure that when it does,
- // our default proxy credentials are used. To avoid messing up anything else in this process, we run the
- // test in another process.
- var psi = new ProcessStartInfo();
- psi.Environment.Add("http_proxy", $"http://localhost:{port}");
- RemoteInvoke((useProxyString, useManagedHandlerString) =>
+ await LoopbackServer.CreateServerAsync(async (proxyServer, proxyUri) =>
{
- using (HttpClientHandler handler = CreateHttpClientHandler(useManagedHandlerString))
- using (var client = new HttpClient(handler))
+ // libcurl will read a default proxy from the http_proxy environment variable. Ensure that when it does,
+ // our default proxy credentials are used. To avoid messing up anything else in this process, we run the
+ // test in another process.
+ var psi = new ProcessStartInfo();
+ Task<List<string>> proxyTask = null;
+
+ if (useProxy)
{
- var creds = new NetworkCredential(ExpectedUsername, ExpectedPassword);
- handler.DefaultProxyCredentials = creds;
- handler.UseProxy = bool.Parse(useProxyString);
+ proxyTask = proxyServer.AcceptConnectionPerformAuthenticationAndCloseAsync("Proxy-Authenticate: Basic realm=\"NetCore\"\r\n");
+ psi.Environment.Add("http_proxy", $"http://{proxyUri.Host}:{proxyUri.Port}");
+ }
- Task<HttpResponseMessage> responseTask = client.GetAsync(Configuration.Http.RemoteEchoServer);
- Task<string> responseStringTask = responseTask.ContinueWith(t =>
+ RemoteInvoke(async (useProxyString, useSocketsHttpHandlerString) =>
+ {
+ using (HttpClientHandler handler = CreateHttpClientHandler(useSocketsHttpHandlerString))
+ using (var client = new HttpClient(handler))
{
- using (t.Result) return t.Result.Content.ReadAsStringAsync();
- }, TaskScheduler.Default).Unwrap();
- Task.WaitAll(responseTask, responseStringTask);
-
- TestHelper.VerifyResponseBody(responseStringTask.Result, responseTask.Result.Content.Headers.ContentMD5, false, null);
+ var creds = new NetworkCredential(ExpectedUsername, ExpectedPassword);
+ handler.DefaultProxyCredentials = creds;
+ handler.UseProxy = bool.Parse(useProxyString);
+
+ HttpResponseMessage response = await client.GetAsync(Configuration.Http.RemoteEchoServer);
+ // Correctness of user and password is done in server part.
+ Assert.True(response.StatusCode == HttpStatusCode.OK);
+ }
+ return SuccessExitCode;
+ }, useProxy.ToString(), UseSocketsHttpHandler.ToString(), new RemoteInvokeOptions { StartInfo = psi }).Dispose();
+ if (useProxy)
+ {
+ await proxyTask;
}
- return SuccessExitCode;
- }, useProxy.ToString(), UseManagedHandler.ToString(), new RemoteInvokeOptions { StartInfo = psi }).Dispose();
-
- if (useProxy)
- {
- Assert.Equal($"{ExpectedUsername}:{ExpectedPassword}", proxyTask.Result.AuthenticationHeaderValue);
- }
+ }, options);
}
// The purpose of this test is mainly to validate the .NET Framework OOB System.Net.Http implementation
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.MaxConnectionsPerServer.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.MaxConnectionsPerServer.cs
index f53be768eb..3df4f02bad 100644
--- a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.MaxConnectionsPerServer.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.MaxConnectionsPerServer.cs
@@ -3,7 +3,9 @@
// See the LICENSE file in the project root for more information.
using System.Linq;
+using System.Net.Test.Common;
using System.Runtime.InteropServices;
+using System.Threading;
using System.Threading.Tasks;
using Xunit;
@@ -13,7 +15,7 @@ namespace System.Net.Http.Functional.Tests
using Configuration = System.Net.Test.Common.Configuration;
[SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "dotnet/corefx #20010")]
- public class HttpClientHandler_MaxConnectionsPerServer_Test : HttpClientTestBase
+ public abstract class HttpClientHandler_MaxConnectionsPerServer_Test : HttpClientTestBase
{
[Fact]
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "MaxConnectionsPerServer either returns two or int.MaxValue depending if ctor of HttpClientHandlerTest executed first. Disabling cause of random xunit execution order.")]
@@ -76,5 +78,45 @@ namespace System.Net.Http.Functional.Tests
select client.GetAsync(secure ? Configuration.Http.RemoteEchoServer : Configuration.Http.SecureRemoteEchoServer));
}
}
+
+ [OuterLoop("Relies on kicking off GC and waiting for finalizers")]
+ [Fact]
+ public async Task GetAsync_DontDisposeResponse_EventuallyUnblocksWaiters()
+ {
+ if (!UseSocketsHttpHandler)
+ {
+ // Issue #27067. Hang.
+ return;
+ }
+
+ await LoopbackServer.CreateServerAsync(async (server, uri) =>
+ {
+ using (HttpClientHandler handler = CreateHttpClientHandler())
+ using (HttpClient client = new HttpClient(handler))
+ {
+ handler.MaxConnectionsPerServer = 1;
+
+ // Let server handle two requests.
+ const string ResponseContent = "abcdefghijklmnopqrstuvwxyz";
+ Task serverTask1 = server.AcceptConnectionSendResponseAndCloseAsync(content: ResponseContent);
+ Task serverTask2 = server.AcceptConnectionSendResponseAndCloseAsync(content: ResponseContent);
+
+ // Make first request and drop the response, not explicitly disposing of it.
+ void MakeAndDropRequest() => client.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead); // separated out to enable GC of response
+ MakeAndDropRequest();
+
+ // A second request should eventually succeed, once the first one is cleaned up.
+ Task<HttpResponseMessage> secondResponse = client.GetAsync(uri);
+ Assert.True(SpinWait.SpinUntil(() =>
+ {
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ return secondResponse.IsCompleted;
+ }, 30 * 1000), "Expected second response to have completed");
+
+ await new[] { serverTask1, serverTask2, secondResponse }.WhenAllOrAnyFailed();
+ }
+ });
+ }
}
}
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.MaxResponseHeadersLength.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.MaxResponseHeadersLength.cs
index 1a666845c9..901f05136c 100644
--- a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.MaxResponseHeadersLength.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.MaxResponseHeadersLength.cs
@@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Net.Test.Common;
using System.Text;
+using System.Threading;
using System.Threading.Tasks;
using Xunit;
@@ -12,7 +13,7 @@ namespace System.Net.Http.Functional.Tests
{
using Configuration = System.Net.Test.Common.Configuration;
- public class HttpClientHandler_MaxResponseHeadersLength_Test : HttpClientTestBase
+ public abstract class HttpClientHandler_MaxResponseHeadersLength_Test : HttpClientTestBase
{
[SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "Not currently supported on UAP")]
[Theory]
@@ -46,46 +47,89 @@ namespace System.Net.Http.Functional.Tests
using (HttpClientHandler handler = CreateHttpClientHandler())
using (var client = new HttpClient(handler))
{
- handler.MaxResponseHeadersLength = int.MaxValue;
- await client.GetStreamAsync(Configuration.Http.RemoteEchoServer);
- Assert.Throws<InvalidOperationException>(() => handler.MaxResponseHeadersLength = int.MaxValue);
+ handler.MaxResponseHeadersLength = 1;
+ (await client.GetStreamAsync(Configuration.Http.RemoteEchoServer)).Dispose();
+ Assert.Throws<InvalidOperationException>(() => handler.MaxResponseHeadersLength = 1);
}
}
+ [OuterLoop] // TODO: Issue #11345
+ [Fact]
+ public async Task InfiniteSingleHeader_ThrowsException()
+ {
+ if (IsCurlHandler)
+ {
+ // libcurl fails with an out of memory error
+ return;
+ }
+
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ using (HttpClientHandler handler = CreateHttpClientHandler())
+ using (var client = new HttpClient(handler))
+ {
+ Task<HttpResponseMessage> getAsync = client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ var cts = new CancellationTokenSource();
+ Task serverTask = Task.Run(async delegate
+ {
+ await connection.ReadRequestHeaderAndSendCustomResponseAsync("HTTP/1.1 200 OK\r\nContent-Length: 0\r\nMyInfiniteHeader: ");
+ try
+ {
+ while (!cts.IsCancellationRequested)
+ {
+ await connection.Writer.WriteAsync(new string('s', 16000));
+ await Task.Delay(1);
+ }
+ }
+ catch { }
+ });
+
+ await Assert.ThrowsAsync<HttpRequestException>(() => getAsync);
+ cts.Cancel();
+ await serverTask;
+ });
+ }
+ });
+ }
+
[SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "Not currently supported on UAP")]
[OuterLoop] // TODO: Issue #11345
[Theory, MemberData(nameof(ResponseWithManyHeadersData))]
- public async Task ThresholdExceeded_ThrowsException(string responseHeaders, int maxResponseHeadersLength, bool shouldSucceed)
+ public async Task ThresholdExceeded_ThrowsException(string responseHeaders, int? maxResponseHeadersLength, bool shouldSucceed)
{
+ if (IsCurlHandler)
+ {
+ // libcurl often fails with out of memory errors
+ return;
+ }
+
await LoopbackServer.CreateServerAsync(async (server, url) =>
{
using (HttpClientHandler handler = CreateHttpClientHandler())
using (var client = new HttpClient(handler))
{
- handler.MaxResponseHeadersLength = maxResponseHeadersLength;
+ if (maxResponseHeadersLength.HasValue)
+ {
+ handler.MaxResponseHeadersLength = maxResponseHeadersLength.Value;
+ }
Task<HttpResponseMessage> getAsync = client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
- await LoopbackServer.AcceptSocketAsync(server, async (s, serverStream, reader, writer) =>
+ await server.AcceptConnectionAsync(async connection =>
{
- using (s) using (serverStream) using (reader) using (writer)
- {
- string line;
- while ((line = reader.ReadLine()) != null && !string.IsNullOrEmpty(line)) ;
-
- byte[] headerData = Encoding.ASCII.GetBytes(responseHeaders);
- serverStream.Write(headerData, 0, headerData.Length);
- }
+ Task serverTask = connection.ReadRequestHeaderAndSendCustomResponseAsync(responseHeaders);
if (shouldSucceed)
{
(await getAsync).Dispose();
+ await serverTask;
}
else
{
await Assert.ThrowsAsync<HttpRequestException>(() => getAsync);
+ try { await serverTask; } catch { }
}
-
- return null;
});
}
});
@@ -95,58 +139,32 @@ namespace System.Net.Http.Functional.Tests
{
get
{
- // Success case: response headers of size 1023 bytes (less than 1024 bytes max).
+ foreach (int? max in new int?[] { null, 1, 31, 128 })
{
- yield return new object[] { GenerateLargeResponseHeaders(1023), 1, true };
- }
+ int actualSize = max.HasValue ? max.Value : 64;
- // Success case: response headers of size 1024 bytes (equal to 1024 bytes max).
- {
- yield return new object[] { GenerateLargeResponseHeaders(1024), 1, true };
- }
-
- // Failure case: response headers of size 1025 (greater than 1024 bytes max).
- {
- yield return new object[] { GenerateLargeResponseHeaders(1025), 1, false };
+ yield return new object[] { GenerateLargeResponseHeaders(actualSize * 1024 - 1), max, true }; // Small enough
+ yield return new object[] { GenerateLargeResponseHeaders(actualSize * 1024), max, true }; // Just right
+ yield return new object[] { GenerateLargeResponseHeaders(actualSize * 1024 + 1), max, false }; // Too big
}
}
}
private static string GenerateLargeResponseHeaders(int responseHeadersSizeInBytes)
{
- // This helper method only supports generating sizes of 1023, 1024, or 1025 bytes.
- // These are the only sizes needed to support the above tests.
- Assert.InRange(responseHeadersSizeInBytes, 1023, 1025);
-
- string statusHeader = "HTTP/1.1 200 OK\r\n";
- string contentFooter = "Content-Length: 0\r\n\r\n";
-
var buffer = new StringBuilder();
- buffer.Append(statusHeader);
+ buffer.Append("HTTP/1.1 200 OK\r\n");
+ buffer.Append("Content-Length: 0\r\n");
for (int i = 0; i < 24; i++)
{
buffer.Append($"Custom-{i:D4}: 1234567890123456789012345\r\n");
}
-
- if (responseHeadersSizeInBytes == 1023)
- {
- buffer.Append($"Custom-1023: 1234567890\r\n");
- }
- else if (responseHeadersSizeInBytes == 1024)
- {
- buffer.Append($"Custom-1024: 12345678901\r\n");
- }
- else
- {
- Assert.Equal(1025, responseHeadersSizeInBytes);
- buffer.Append($"Custom-1025: 123456789012\r\n");
- }
-
- buffer.Append(contentFooter);
+ buffer.Append($"Custom-24: ");
+ buffer.Append(new string('c', responseHeadersSizeInBytes - (buffer.Length + 4)));
+ buffer.Append("\r\n\r\n");
string response = buffer.ToString();
Assert.Equal(responseHeadersSizeInBytes, response.Length);
-
return response;
}
}
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ResponseDrain.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ResponseDrain.cs
new file mode 100644
index 0000000000..54e3b7c5a1
--- /dev/null
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ResponseDrain.cs
@@ -0,0 +1,301 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.IO;
+using System.Net.Test.Common;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.Net.Http.Functional.Tests
+{
+ public abstract class HttpClientHandler_ResponseDrain_Test : HttpClientTestBase
+ {
+ protected virtual void SetResponseDrainTimeout(HttpClientHandler handler, TimeSpan time) { }
+
+ public enum ContentMode
+ {
+ ContentLength,
+ SingleChunk,
+ BytePerChunk
+ }
+
+ protected static string GetResponseForContentMode(string content, ContentMode mode)
+ {
+ switch (mode)
+ {
+ case ContentMode.ContentLength:
+ return LoopbackServer.GetHttpResponse(content: content);
+ case ContentMode.SingleChunk:
+ return LoopbackServer.GetSingleChunkHttpResponse(content: content);
+ case ContentMode.BytePerChunk:
+ return LoopbackServer.GetBytePerChunkHttpResponse(content: content);
+ default:
+ Assert.True(false);
+ return null;
+ }
+ }
+
+ [OuterLoop]
+ [Theory]
+ [InlineData(ContentMode.ContentLength)]
+ [InlineData(ContentMode.SingleChunk)]
+ [InlineData(ContentMode.BytePerChunk)]
+ public async Task GetAsync_DisposeBeforeReadingToEnd_DrainsRequestsAndReusesConnection(ContentMode mode)
+ {
+ if ((IsWinHttpHandler || IsCurlHandler) && mode == ContentMode.BytePerChunk)
+ {
+ // These handlers' behavior with multiple chunks is inconsistent, so disable the test.
+ return;
+ }
+
+ const string simpleContent = "Hello world!";
+
+ await LoopbackServer.CreateClientAndServerAsync(
+ async url =>
+ {
+ using (var client = CreateHttpClient())
+ {
+ HttpResponseMessage response1 = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
+ ValidateResponseHeaders(response1, simpleContent.Length, mode);
+
+ // Read up to exactly 1 byte before the end of the response
+ Stream responseStream = await response1.Content.ReadAsStreamAsync();
+ byte[] bytes = await ReadToByteCount(responseStream, simpleContent.Length - 1);
+ Assert.Equal(simpleContent.Substring(0, simpleContent.Length - 1), Encoding.ASCII.GetString(bytes));
+
+ // Introduce a short delay to try to ensure that when we dispose the response,
+ // all response data is available and we can drain synchronously and reuse the connection.
+ await Task.Delay(100);
+
+ response1.Dispose();
+
+ // Issue another request. We'll confirm that it comes on the same connection.
+ HttpResponseMessage response2 = await client.GetAsync(url);
+ ValidateResponseHeaders(response2, simpleContent.Length, mode);
+ Assert.Equal(simpleContent, await response2.Content.ReadAsStringAsync());
+ }
+ },
+ async server =>
+ {
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ string response = GetResponseForContentMode(simpleContent, mode);
+ await connection.ReadRequestHeaderAndSendCustomResponseAsync(response);
+ await connection.ReadRequestHeaderAndSendCustomResponseAsync(response);
+ });
+ });
+ }
+
+ // The actual amount of drain that's supported is handler and timing dependent, apparently.
+ // These cases are an attempt to provide a "min bar" for draining behavior.
+
+ [OuterLoop]
+ [Theory]
+ [InlineData(0, 0, ContentMode.ContentLength)]
+ [InlineData(0, 0, ContentMode.SingleChunk)]
+ [InlineData(1, 0, ContentMode.ContentLength)]
+ [InlineData(1, 0, ContentMode.SingleChunk)]
+ [InlineData(1, 0, ContentMode.BytePerChunk)]
+ [InlineData(2, 1, ContentMode.ContentLength)]
+ [InlineData(2, 1, ContentMode.SingleChunk)]
+ [InlineData(2, 1, ContentMode.BytePerChunk)]
+ [InlineData(10, 1, ContentMode.ContentLength)]
+ [InlineData(10, 1, ContentMode.SingleChunk)]
+ [InlineData(10, 1, ContentMode.BytePerChunk)]
+ [InlineData(100, 10, ContentMode.ContentLength)]
+ [InlineData(100, 10, ContentMode.SingleChunk)]
+ [InlineData(100, 10, ContentMode.BytePerChunk)]
+ [InlineData(1000, 950, ContentMode.ContentLength)]
+ [InlineData(1000, 950, ContentMode.SingleChunk)]
+ [InlineData(1000, 950, ContentMode.BytePerChunk)]
+ [InlineData(10000, 9500, ContentMode.ContentLength)]
+ [InlineData(10000, 9500, ContentMode.SingleChunk)]
+ [InlineData(10000, 9500, ContentMode.BytePerChunk)]
+ public async Task GetAsyncWithMaxConnections_DisposeBeforeReadingToEnd_DrainsRequestsAndReusesConnection(int totalSize, int readSize, ContentMode mode)
+ {
+ if (IsWinHttpHandler)
+ {
+ // WinHttpHandler seems to only do a limited amount of draining, and this test starts
+ // failing if there's any measurable delay introduced in the response such that it dribbles
+ // in. So just skip these tests.
+ return;
+ }
+
+ if (IsCurlHandler)
+ {
+ // CurlHandler drain behavior is very inconsistent, so just skip these tests.
+ return;
+ }
+
+ await LoopbackServer.CreateClientAndServerAsync(
+ async url =>
+ {
+ HttpClientHandler handler = CreateHttpClientHandler();
+ SetResponseDrainTimeout(handler, Timeout.InfiniteTimeSpan);
+
+ // Set MaxConnectionsPerServer to 1. This will ensure we will wait for the previous request to drain (or fail to)
+ handler.MaxConnectionsPerServer = 1;
+
+ using (var client = new HttpClient(handler))
+ {
+ HttpResponseMessage response1 = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
+ ValidateResponseHeaders(response1, totalSize, mode);
+
+ // Read part but not all of response
+ Stream responseStream = await response1.Content.ReadAsStreamAsync();
+ await ReadToByteCount(responseStream, readSize);
+
+ response1.Dispose();
+
+ // Issue another request. We'll confirm that it comes on the same connection.
+ HttpResponseMessage response2 = await client.GetAsync(url);
+ ValidateResponseHeaders(response2, totalSize, mode);
+ Assert.Equal(totalSize, (await response2.Content.ReadAsStringAsync()).Length);
+ }
+ },
+ async server =>
+ {
+ string content = new string('a', totalSize);
+ string response = GetResponseForContentMode(content, mode);
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ // Process the first request, with some introduced delays in the response to
+ // stress the draining.
+ await connection.ReadRequestHeaderAsync().ConfigureAwait(false);
+ foreach (char c in response)
+ {
+ await connection.Writer.WriteAsync(c);
+ }
+
+ // Process the second request.
+ await connection.ReadRequestHeaderAndSendCustomResponseAsync(response);
+ });
+ });
+ }
+
+ [OuterLoop]
+ [Theory]
+ [InlineData(100000, 1, ContentMode.ContentLength)]
+ [InlineData(100000, 1, ContentMode.SingleChunk)]
+ [InlineData(100000, 1, ContentMode.BytePerChunk)]
+ [InlineData(800000, 1, ContentMode.ContentLength)]
+ [InlineData(800000, 1, ContentMode.SingleChunk)]
+ [InlineData(1024 * 1024, 1, ContentMode.ContentLength)]
+ public async Task GetAsyncLargeRequestWithMaxConnections_DisposeBeforeReadingToEnd_DrainsRequestsAndReusesConnection(int totalSize, int readSize, ContentMode mode)
+ {
+ // SocketsHttpHandler will reliably drain up to 1MB; other handlers don't.
+ if (!UseSocketsHttpHandler)
+ {
+ return;
+ }
+
+ await GetAsyncWithMaxConnections_DisposeBeforeReadingToEnd_DrainsRequestsAndReusesConnection(totalSize, readSize, mode);
+ return;
+ }
+
+ // Similar to above, these are semi-extreme cases where the response should never drain for any handler.
+
+ [OuterLoop]
+ [Theory]
+ [InlineData(2000000, 0, ContentMode.ContentLength)]
+ [InlineData(2000000, 0, ContentMode.SingleChunk)]
+ [InlineData(2000000, 0, ContentMode.BytePerChunk)]
+ [InlineData(4000000, 1000000, ContentMode.ContentLength)]
+ [InlineData(4000000, 1000000, ContentMode.SingleChunk)]
+ [InlineData(4000000, 1000000, ContentMode.BytePerChunk)]
+ public async Task GetAsyncWithMaxConnections_DisposeBeforeReadingToEnd_KillsConnection(int totalSize, int readSize, ContentMode mode)
+ {
+ if (IsWinHttpHandler)
+ {
+ // [ActiveIssue(28424)]
+ return;
+ }
+
+ await LoopbackServer.CreateClientAndServerAsync(
+ async url =>
+ {
+ HttpClientHandler handler = CreateHttpClientHandler();
+ SetResponseDrainTimeout(handler, Timeout.InfiniteTimeSpan);
+
+ // Set MaxConnectionsPerServer to 1. This will ensure we will wait for the previous request to drain (or fail to)
+ handler.MaxConnectionsPerServer = 1;
+
+ using (var client = new HttpClient(handler))
+ {
+ HttpResponseMessage response1 = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
+ ValidateResponseHeaders(response1, totalSize, mode);
+
+ // Read part but not all of response
+ Stream responseStream = await response1.Content.ReadAsStreamAsync();
+ await ReadToByteCount(responseStream, readSize);
+
+ response1.Dispose();
+
+ // Issue another request. We'll confirm that it comes on a new connection.
+ HttpResponseMessage response2 = await client.GetAsync(url);
+ ValidateResponseHeaders(response2, totalSize, mode);
+ Assert.Equal(totalSize, (await response2.Content.ReadAsStringAsync()).Length);
+ }
+ },
+ async server =>
+ {
+ string content = new string('a', totalSize);
+ string response = GetResponseForContentMode(content, mode);
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ await connection.ReadRequestHeaderAsync();
+ try
+ {
+ await connection.Writer.WriteAsync(response);
+ }
+ catch (Exception) { } // Eat errors from client disconnect.
+
+ await server.AcceptConnectionSendCustomResponseAndCloseAsync(response);
+ });
+ });
+ }
+
+ protected static void ValidateResponseHeaders(HttpResponseMessage response, int contentLength, ContentMode mode)
+ {
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+
+ switch (mode)
+ {
+ case ContentMode.ContentLength:
+ Assert.Equal(contentLength, response.Content.Headers.ContentLength);
+ break;
+
+ case ContentMode.SingleChunk:
+ case ContentMode.BytePerChunk:
+ Assert.True(response.Headers.TransferEncodingChunked);
+ break;
+ }
+ }
+
+ protected static async Task<byte[]> ReadToByteCount(Stream stream, int byteCount)
+ {
+ byte[] buffer = new byte[byteCount];
+ int totalBytesRead = 0;
+
+ while (totalBytesRead < byteCount)
+ {
+ int bytesRead = await stream.ReadAsync(buffer, totalBytesRead, (byteCount - totalBytesRead));
+ if (bytesRead == 0)
+ {
+ throw new Exception("Unexpected EOF");
+ }
+
+ totalBytesRead += bytesRead;
+ if (totalBytesRead > byteCount)
+ {
+ throw new Exception("Read more bytes than requested???");
+ }
+ }
+
+ return buffer;
+ }
+ }
+}
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ServerCertificates.Unix.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ServerCertificates.Unix.cs
index 3f7d5f264d..d19a63f598 100644
--- a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ServerCertificates.Unix.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ServerCertificates.Unix.cs
@@ -15,7 +15,7 @@ using Xunit;
namespace System.Net.Http.Functional.Tests
{
- public partial class HttpClientHandler_ServerCertificates_Test
+ public abstract partial class HttpClientHandler_ServerCertificates_Test
{
private static bool ShouldSuppressRevocationException
{
@@ -41,7 +41,7 @@ namespace System.Net.Http.Functional.Tests
// MustNotCheck,
// }
- if (CurlSslVersionDescription() == "SecureTransport")
+ if (Interop.Http.GetSslVersionDescription() == "SecureTransport")
{
return true;
}
@@ -53,7 +53,7 @@ namespace System.Net.Http.Functional.Tests
{
get
{
- if (UseManagedHandler)
+ if (UseSocketsHttpHandler)
{
return true;
}
@@ -65,67 +65,36 @@ namespace System.Net.Http.Functional.Tests
// For other Unix-based systems it's true if (and only if) the openssl backend
// is used with libcurl.
- return (CurlSslVersionDescription()?.StartsWith("OpenSSL") ?? false);
+ return (Interop.Http.GetSslVersionDescription()?.StartsWith(Interop.Http.OpenSsl10Description, StringComparison.OrdinalIgnoreCase) ?? false);
}
}
- [DllImport("System.Net.Http.Native", EntryPoint = "HttpNative_GetSslVersionDescription")]
- private static extern string CurlSslVersionDescription();
-
- [Theory]
+ [Fact]
[PlatformSpecific(~TestPlatforms.OSX)] // Not implemented
- [InlineData(false, false, false, false, false)] // system -> ok
- [InlineData(true, true, true, true, true)] // empty dir, empty bundle file -> fail
- // It is enough to override the bundle, since all tested platforms don't have a default dir:
- [InlineData(false, false, true, true, true)] // empty bundle -> fail
- [InlineData(false, false, true, false, true)] // non-existing bundle -> fail
- public void HttpClientUsesSslCertEnvironmentVariables(bool setSslCertDir, bool createSslCertDir,
- bool setSslCertFile, bool createSslCertFile, bool expectedFailure)
+ public void HttpClientUsesSslCertEnvironmentVariables()
{
- // This test sets SSL_CERT_DIR and SSL_CERT_FILE to empty/non-existing locations and then
- // checks the http request fails.
- // Some platforms will use the system default when not specifying a value, while others
- // will not use those certificates. Due to these platform differences, we only check specific
- // combinations that are expected to work the same cross-platform.
+ // We set SSL_CERT_DIR and SSL_CERT_FILE to empty locations.
+ // The HttpClient should fail to validate the server certificate.
+
var psi = new ProcessStartInfo();
- if (setSslCertDir)
- {
- string sslCertDir = GetTestFilePath();
- if (createSslCertDir)
- {
- Directory.CreateDirectory(sslCertDir);
- }
- psi.Environment.Add("SSL_CERT_DIR", sslCertDir);
- }
+ string sslCertDir = GetTestFilePath();
+ Directory.CreateDirectory(sslCertDir);
+ psi.Environment.Add("SSL_CERT_DIR", sslCertDir);
- if (setSslCertFile)
- {
- string sslCertFile = GetTestFilePath();
- if (createSslCertFile)
- {
- File.WriteAllText(sslCertFile, "");
- }
- psi.Environment.Add("SSL_CERT_FILE", sslCertFile);
- }
+ string sslCertFile = GetTestFilePath();
+ File.WriteAllText(sslCertFile, "");
+ psi.Environment.Add("SSL_CERT_FILE", sslCertFile);
- RemoteInvoke(async arg =>
+ RemoteInvoke(async useSocketsHttpHandlerString =>
{
- bool shouldFail = bool.Parse(arg);
const string Url = "https://www.microsoft.com";
- using (HttpClient client = new HttpClient())
+ using (var client = CreateHttpClient(useSocketsHttpHandlerString))
{
- if (shouldFail)
- {
- await Assert.ThrowsAsync<HttpRequestException>(() => client.GetAsync(Url));
- }
- else
- {
- await client.GetAsync(Url);
- }
+ await Assert.ThrowsAsync<HttpRequestException>(() => client.GetAsync(Url));
}
return SuccessExitCode;
- }, expectedFailure.ToString(), new RemoteInvokeOptions { StartInfo = psi }).Dispose();
+ }, UseSocketsHttpHandler.ToString(), new RemoteInvokeOptions { StartInfo = psi }).Dispose();
}
}
}
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ServerCertificates.Windows.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ServerCertificates.Windows.cs
index c213aab296..e5903984a7 100644
--- a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ServerCertificates.Windows.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ServerCertificates.Windows.cs
@@ -4,12 +4,10 @@
namespace System.Net.Http.Functional.Tests
{
- public partial class HttpClientHandler_ServerCertificates_Test
+ public abstract partial class HttpClientHandler_ServerCertificates_Test
{
private static bool ShouldSuppressRevocationException => false;
internal bool BackendSupportsCustomCertificateHandling => true;
-
- private bool BackendDoesNotSupportCustomCertificateHandling => !BackendSupportsCustomCertificateHandling;
}
}
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ServerCertificates.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ServerCertificates.cs
index af3b67fe1b..f8164e104b 100644
--- a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ServerCertificates.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ServerCertificates.cs
@@ -17,7 +17,7 @@ namespace System.Net.Http.Functional.Tests
using Configuration = System.Net.Test.Common.Configuration;
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, ".NET Framework throws PNSE for ServerCertificateCustomValidationCallback")]
- public partial class HttpClientHandler_ServerCertificates_Test : HttpClientTestBase
+ public abstract partial class HttpClientHandler_ServerCertificates_Test : HttpClientTestBase
{
private static bool ClientSupportsDHECipherSuites => (!PlatformDetection.IsWindows || PlatformDetection.IsWindows10Version1607OrGreater);
private bool BackendSupportsCustomCertificateHandlingAndClientSupportsDHECipherSuites =>
@@ -45,6 +45,27 @@ namespace System.Net.Http.Functional.Tests
}
}
+ [Fact]
+ public void ServerCertificateCustomValidationCallback_SetGet_Roundtrips()
+ {
+ using (HttpClientHandler handler = CreateHttpClientHandler())
+ {
+ Assert.Null(handler.ServerCertificateCustomValidationCallback);
+
+ Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> callback1 = (req, cert, chain, policy) => throw new NotImplementedException("callback1");
+ Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> callback2 = (req, cert, chain, policy) => throw new NotImplementedException("callback2");
+
+ handler.ServerCertificateCustomValidationCallback = callback1;
+ Assert.Same(callback1, handler.ServerCertificateCustomValidationCallback);
+
+ handler.ServerCertificateCustomValidationCallback = callback2;
+ Assert.Same(callback2, handler.ServerCertificateCustomValidationCallback);
+
+ handler.ServerCertificateCustomValidationCallback = null;
+ Assert.Null(handler.ServerCertificateCustomValidationCallback);
+ }
+ }
+
[OuterLoop] // TODO: Issue #11345
[Fact]
public async Task NoCallback_ValidCertificate_SuccessAndExpectedPropertyBehavior()
@@ -65,15 +86,59 @@ namespace System.Net.Http.Functional.Tests
[SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "UAP won't send requests through a custom proxy")]
[OuterLoop] // TODO: Issue #11345
[Fact]
- public async Task UseCallback_HaveNoCredsAndUseAuthenticatedCustomProxyAndPostToSecureServer_ProxyAuthenticationRequiredStatusCode()
+ public async Task UseCallback_HaveCredsAndUseAuthenticatedCustomProxyAndPostToSecureServer_Success()
{
if (!BackendSupportsCustomCertificateHandling)
{
return;
}
- if (UseManagedHandler)
+
+ if (IsWinHttpHandler && PlatformDetection.IsWindows7)
{
- return; // TODO #23136: SSL proxy tunneling not yet implemented in ManagedHandler
+ // Issue #27612
+ return;
+ }
+
+ const string content = "This is a test";
+
+ int port;
+ Task<LoopbackGetRequestHttpProxy.ProxyResult> proxyTask = LoopbackGetRequestHttpProxy.StartAsync(
+ out port,
+ requireAuth: true,
+ expectCreds: true);
+ Uri proxyUrl = new Uri($"http://localhost:{port}");
+
+ HttpClientHandler handler = CreateHttpClientHandler();
+ handler.Proxy = new UseSpecifiedUriWebProxy(proxyUrl, new NetworkCredential("rightusername", "rightpassword"));
+ handler.ServerCertificateCustomValidationCallback = delegate { return true; };
+ using (var client = new HttpClient(handler))
+ {
+ HttpResponseMessage response = await client.PostAsync(
+ Configuration.Http.SecureRemoteEchoServer,
+ new StringContent(content));
+
+ string responseContent = await response.Content.ReadAsStringAsync();
+
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ TestHelper.VerifyResponseBody(
+ responseContent,
+ response.Content.Headers.ContentMD5,
+ false,
+ content);
+ }
+
+ // Don't await proxyTask until the HttpClient is closed, otherwise it will wait for connection timeout.
+ await proxyTask;
+ }
+
+ [SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "UAP won't send requests through a custom proxy")]
+ [OuterLoop] // TODO: Issue #11345
+ [Fact]
+ public async Task UseCallback_HaveNoCredsAndUseAuthenticatedCustomProxyAndPostToSecureServer_ProxyAuthenticationRequiredStatusCode()
+ {
+ if (!BackendSupportsCustomCertificateHandling)
+ {
+ return;
}
int port;
@@ -263,7 +328,7 @@ namespace System.Net.Http.Functional.Tests
}
catch (HttpRequestException)
{
- if (UseManagedHandler || !ShouldSuppressRevocationException)
+ if (UseSocketsHttpHandler || !ShouldSuppressRevocationException)
throw;
}
}
@@ -293,7 +358,7 @@ namespace System.Net.Http.Functional.Tests
new object[] { Configuration.Http.WrongHostNameCertRemoteServer , SslPolicyErrors.RemoteCertificateNameMismatch},
};
- private async Task UseCallback_BadCertificate_ExpectedPolicyErrors_Helper(string url, bool useManagedHandler, SslPolicyErrors expectedErrors)
+ private async Task UseCallback_BadCertificate_ExpectedPolicyErrors_Helper(string url, bool useSocketsHttpHandler, SslPolicyErrors expectedErrors)
{
if (!BackendSupportsCustomCertificateHandling)
{
@@ -301,7 +366,7 @@ namespace System.Net.Http.Functional.Tests
return;
}
- HttpClientHandler handler = CreateHttpClientHandler(useManagedHandler);
+ HttpClientHandler handler = CreateHttpClientHandler(useSocketsHttpHandler);
using (var client = new HttpClient(handler))
{
bool callbackCalled = false;
@@ -312,13 +377,7 @@ namespace System.Net.Http.Functional.Tests
Assert.NotNull(request);
Assert.NotNull(cert);
Assert.NotNull(chain);
- if (!useManagedHandler)
- {
- // TODO #23137: This test is failing with the managed handler on the exact value of the managed errors,
- // e.g. reporting "RemoteCertificateNameMismatch, RemoteCertificateChainErrors" when we only expect
- // "RemoteCertificateChainErrors"
- Assert.Equal(expectedErrors, errors);
- }
+ Assert.Equal(expectedErrors, errors);
return true;
};
@@ -350,19 +409,19 @@ namespace System.Net.Http.Functional.Tests
// UAP HTTP stack caches connections per-process. This causes interference when these tests run in
// the same process as the other tests. Each test needs to be isolated to its own process.
// See dicussion: https://github.com/dotnet/corefx/issues/21945
- RemoteInvoke((remoteUrl, remoteExpectedErrors, useManagedHandlerString) =>
+ RemoteInvoke((remoteUrl, remoteExpectedErrors, useSocketsHttpHandlerString) =>
{
UseCallback_BadCertificate_ExpectedPolicyErrors_Helper(
remoteUrl,
- bool.Parse(useManagedHandlerString),
+ bool.Parse(useSocketsHttpHandlerString),
(SslPolicyErrors)Enum.Parse(typeof(SslPolicyErrors), remoteExpectedErrors)).Wait();
return SuccessExitCode;
- }, url, expectedErrors.ToString(), UseManagedHandler.ToString()).Dispose();
+ }, url, expectedErrors.ToString(), UseSocketsHttpHandler.ToString()).Dispose();
}
else
{
- await UseCallback_BadCertificate_ExpectedPolicyErrors_Helper(url, UseManagedHandler, expectedErrors);
+ await UseCallback_BadCertificate_ExpectedPolicyErrors_Helper(url, UseSocketsHttpHandler, expectedErrors);
}
}
catch (HttpRequestException e) when (e.InnerException?.GetType().Name == "WinHttpException" &&
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.Unix.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.Unix.cs
index 56377d5e69..f10fdb75f2 100644
--- a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.Unix.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.Unix.cs
@@ -14,20 +14,14 @@ using Xunit;
namespace System.Net.Http.Functional.Tests
{
- public partial class HttpClientHandler_SslProtocols_Test
+ public abstract partial class HttpClientHandler_SslProtocols_Test
{
private bool BackendSupportsSslConfiguration =>
- UseManagedHandler ||
- (CurlSslVersionDescription()?.StartsWith("OpenSSL") ?? false);
+ UseSocketsHttpHandler ||
+ (Interop.Http.GetSslVersionDescription()?.StartsWith(Interop.Http.OpenSsl10Description, StringComparison.OrdinalIgnoreCase) ?? false);
private bool SSLv3DisabledByDefault =>
BackendSupportsSslConfiguration ||
- Version.Parse(CurlVersionDescription()) >= new Version(7, 39); // libcurl disables SSLv3 by default starting in v7.39
-
- [DllImport("System.Net.Http.Native", EntryPoint = "HttpNative_GetVersionDescription")]
- private static extern string CurlVersionDescription();
-
- [DllImport("System.Net.Http.Native", EntryPoint = "HttpNative_GetSslVersionDescription")]
- private static extern string CurlSslVersionDescription();
+ Version.Parse(Interop.Http.GetVersionDescription()) >= new Version(7, 39); // libcurl disables SSLv3 by default starting in v7.39
}
}
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.Windows.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.Windows.cs
index 28b5e9c8ce..020d9c5afa 100644
--- a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.Windows.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.Windows.cs
@@ -5,7 +5,7 @@
namespace System.Net.Http.Functional.Tests
{
- public partial class HttpClientHandler_SslProtocols_Test
+ public abstract partial class HttpClientHandler_SslProtocols_Test
{
private static bool BackendSupportsSslConfiguration => true;
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.cs
index 2370fa76a0..25fd78fcb1 100644
--- a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.cs
@@ -16,7 +16,7 @@ namespace System.Net.Http.Functional.Tests
[SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "SslProtocols not supported on UAP")]
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "dotnet/corefx #16805")]
- public partial class HttpClientHandler_SslProtocols_Test : HttpClientTestBase
+ public abstract partial class HttpClientHandler_SslProtocols_Test : HttpClientTestBase
{
[Fact]
public void DefaultProtocols_MatchesExpected()
@@ -57,11 +57,11 @@ namespace System.Net.Http.Functional.Tests
using (HttpClientHandler handler = CreateHttpClientHandler())
using (var client = new HttpClient(handler))
{
- handler.ServerCertificateCustomValidationCallback = LoopbackServer.AllowAllCertificates;
+ handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;
await LoopbackServer.CreateServerAsync(async (server, url) =>
{
await TestHelper.WhenAllCompletedOrAnyFailed(
- LoopbackServer.ReadRequestAndSendResponseAsync(server),
+ server.AcceptConnectionSendResponseAndCloseAsync(),
client.GetAsync(url));
});
Assert.Throws<InvalidOperationException>(() => handler.SslProtocols = SslProtocols.Tls12);
@@ -100,16 +100,16 @@ namespace System.Net.Http.Functional.Tests
return;
}
- if (UseManagedHandler)
+ if (UseSocketsHttpHandler)
{
- // TODO #26186: The managed handler is failing on some OSes.
+ // TODO #26186: SocketsHttpHandler is failing on some OSes.
return;
}
using (HttpClientHandler handler = CreateHttpClientHandler())
using (var client = new HttpClient(handler))
{
- handler.ServerCertificateCustomValidationCallback = LoopbackServer.AllowAllCertificates;
+ handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;
if (requestOnlyThisProtocol)
{
@@ -119,7 +119,7 @@ namespace System.Net.Http.Functional.Tests
await LoopbackServer.CreateServerAsync(async (server, url) =>
{
await TestHelper.WhenAllCompletedOrAnyFailed(
- LoopbackServer.ReadRequestAndSendResponseAsync(server, options: options),
+ server.AcceptConnectionSendResponseAndCloseAsync(),
client.GetAsync(url));
}, options);
}
@@ -141,9 +141,9 @@ namespace System.Net.Http.Functional.Tests
[MemberData(nameof(SupportedSSLVersionServers))]
public async Task GetAsync_SupportedSSLVersion_Succeeds(SslProtocols sslProtocols, string url)
{
- if (UseManagedHandler)
+ if (UseSocketsHttpHandler)
{
- // TODO #26186: The managed handler is failing on some OSes.
+ // TODO #26186: SocketsHttpHandler is failing on some OSes.
return;
}
@@ -197,7 +197,7 @@ namespace System.Net.Http.Functional.Tests
return;
}
- if (UseManagedHandler && !PlatformDetection.IsWindows10Version1607OrGreater)
+ if (UseSocketsHttpHandler && !PlatformDetection.IsWindows10Version1607OrGreater)
{
// On Windows, https://github.com/dotnet/corefx/issues/21925#issuecomment-313408314
// On Linux, an older version of OpenSSL may permit negotiating SSLv3.
@@ -215,34 +215,36 @@ namespace System.Net.Http.Functional.Tests
public async Task GetAsync_NoSpecifiedProtocol_DefaultsToTls12()
{
if (!BackendSupportsSslConfiguration)
+ {
return;
+ }
+
using (HttpClientHandler handler = CreateHttpClientHandler())
using (var client = new HttpClient(handler))
{
- handler.ServerCertificateCustomValidationCallback = LoopbackServer.AllowAllCertificates;
+ handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;
var options = new LoopbackServer.Options { UseSsl = true };
await LoopbackServer.CreateServerAsync(async (server, url) =>
{
await TestHelper.WhenAllCompletedOrAnyFailed(
client.GetAsync(url),
- LoopbackServer.AcceptSocketAsync(server, async (s, stream, reader, writer) =>
+ server.AcceptConnectionAsync(async connection =>
{
- Assert.Equal(SslProtocols.Tls12, Assert.IsType<SslStream>(stream).SslProtocol);
- await LoopbackServer.ReadWriteAcceptedAsync(s, reader, writer);
- return null;
- }, options));
+ Assert.Equal(SslProtocols.Tls12, Assert.IsType<SslStream>(connection.Stream).SslProtocol);
+ await connection.ReadRequestHeaderAndSendResponseAsync();
+ }));
}, options);
}
}
[OuterLoop] // TODO: Issue #11345
[Theory]
- [InlineData(SslProtocols.Tls11, SslProtocols.Tls, typeof(IOException))]
- [InlineData(SslProtocols.Tls12, SslProtocols.Tls11, typeof(IOException))]
- [InlineData(SslProtocols.Tls, SslProtocols.Tls12, typeof(AuthenticationException))]
+ [InlineData(SslProtocols.Tls11, SslProtocols.Tls)]
+ [InlineData(SslProtocols.Tls12, SslProtocols.Tls11)]
+ [InlineData(SslProtocols.Tls, SslProtocols.Tls12)]
public async Task GetAsync_AllowedSSLVersionDiffersFromServer_ThrowsException(
- SslProtocols allowedProtocol, SslProtocols acceptedProtocol, Type exceptedServerException)
+ SslProtocols allowedProtocol, SslProtocols acceptedProtocol)
{
if (!BackendSupportsSslConfiguration)
return;
@@ -250,14 +252,25 @@ namespace System.Net.Http.Functional.Tests
using (var client = new HttpClient(handler))
{
handler.SslProtocols = allowedProtocol;
- handler.ServerCertificateCustomValidationCallback = LoopbackServer.AllowAllCertificates;
+ handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;
var options = new LoopbackServer.Options { UseSsl = true, SslProtocols = acceptedProtocol };
await LoopbackServer.CreateServerAsync(async (server, url) =>
{
- await TestHelper.WhenAllCompletedOrAnyFailed(
- Assert.ThrowsAsync(exceptedServerException, () => LoopbackServer.ReadRequestAndSendResponseAsync(server, options: options)),
- Assert.ThrowsAsync<HttpRequestException>(() => client.GetAsync(url)));
+ Task serverTask = server.AcceptConnectionSendResponseAndCloseAsync();
+ await Assert.ThrowsAsync<HttpRequestException>(() => client.GetAsync(url));
+ try
+ {
+ await serverTask;
+ }
+ catch (Exception e) when (e is IOException || e is AuthenticationException)
+ {
+ // Some SSL implementations simply close or reset connection after protocol mismatch.
+ // Newer OpenSSL sends Fatal Alert message before closing.
+ return;
+ }
+ // We expect negotiation to fail so one or the other expected exception should be thrown.
+ Assert.True(false, "Expected exception did not happen.");
}, options);
}
}
@@ -271,7 +284,7 @@ namespace System.Net.Http.Functional.Tests
using (var client = new HttpClient(handler))
{
handler.SslProtocols = SslProtocols.Tls11 | SslProtocols.Tls12;
- handler.ServerCertificateCustomValidationCallback = LoopbackServer.AllowAllCertificates;
+ handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;
if (BackendSupportsSslConfiguration)
{
@@ -280,9 +293,20 @@ namespace System.Net.Http.Functional.Tests
options.SslProtocols = SslProtocols.Tls;
await LoopbackServer.CreateServerAsync(async (server, url) =>
{
- await TestHelper.WhenAllCompletedOrAnyFailed(
- Assert.ThrowsAsync<IOException>(() => LoopbackServer.ReadRequestAndSendResponseAsync(server, options: options)),
- Assert.ThrowsAsync<HttpRequestException>(() => client.GetAsync(url)));
+ Task serverTask = server.AcceptConnectionSendResponseAndCloseAsync();
+ await Assert.ThrowsAsync<HttpRequestException>(() => client.GetAsync(url));
+ try
+ {
+ await serverTask;
+ }
+ catch (Exception e) when (e is IOException || e is AuthenticationException)
+ {
+ // Some SSL implementations simply close or reset connection after protocol mismatch.
+ // Newer OpenSSL sends Fatal Alert message before closing.
+ return;
+ }
+ // We expect negotiation to fail so one or the other expected exception should be thrown.
+ Assert.True(false, "Expected exception did not happen.");
}, options);
foreach (var prot in new[] { SslProtocols.Tls11, SslProtocols.Tls12 })
@@ -291,7 +315,7 @@ namespace System.Net.Http.Functional.Tests
await LoopbackServer.CreateServerAsync(async (server, url) =>
{
await TestHelper.WhenAllCompletedOrAnyFailed(
- LoopbackServer.ReadRequestAndSendResponseAsync(server, options: options),
+ server.AcceptConnectionSendResponseAndCloseAsync(),
client.GetAsync(url));
}, options);
}
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.cs
index b4de81da4f..e35a5843b7 100644
--- a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.cs
@@ -3,13 +3,14 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
-using System.Diagnostics;
using System.IO;
using System.Linq;
+using System.Net.Http.Headers;
using System.Net.Sockets;
using System.Net.Test.Common;
using System.Runtime.InteropServices;
using System.Security.Authentication;
+using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
@@ -24,17 +25,15 @@ namespace System.Net.Http.Functional.Tests
// Note: Disposing the HttpClient object automatically disposes the handler within. So, it is not necessary
// to separately Dispose (or have a 'using' statement) for the handler.
- public class HttpClientHandlerTest : HttpClientTestBase
+ public abstract class HttpClientHandlerTest : HttpClientTestBase
{
readonly ITestOutputHelper _output;
- private const string ExpectedContent = "Test contest";
+ private const string ExpectedContent = "Test content";
private const string Username = "testuser";
private const string Password = "password";
private readonly NetworkCredential _credential = new NetworkCredential(Username, Password);
- public static bool IsNotWindows7 => !PlatformDetection.IsWindows7;
-
public static readonly object[][] EchoServers = Configuration.Http.EchoServers;
public static readonly object[][] VerifyUploadServers = Configuration.Http.VerifyUploadServers;
public static readonly object[][] CompressedServers = Configuration.Http.CompressedServers;
@@ -97,7 +96,6 @@ namespace System.Net.Http.Functional.Tests
GetMethods("HEAD", "TRACE");
private static bool IsWindows10Version1607OrGreater => PlatformDetection.IsWindows10Version1607OrGreater;
- private static bool NotWindowsUAPOrBeforeVersion1709 => !PlatformDetection.IsUap || PlatformDetection.IsWindows10Version1709OrGreater;
private static IEnumerable<object[]> GetMethods(params string[] methods)
{
@@ -242,6 +240,30 @@ namespace System.Net.Http.Functional.Tests
}
}
+ [OuterLoop]
+ [Theory, MemberData(nameof(RedirectStatusCodes))]
+ public async Task DefaultHeaders_SetCredentials_ClearedOnRedirect(int statusCode)
+ {
+ HttpClientHandler handler = CreateHttpClientHandler();
+ using (var client = new HttpClient(handler))
+ {
+ string credentialString = _credential.UserName + ":" + _credential.Password;
+ client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", credentialString);
+ Uri uri = Configuration.Http.RedirectUriForDestinationUri(
+ secure: false,
+ statusCode: statusCode,
+ destinationUri: Configuration.Http.RemoteEchoServer,
+ hops: 1);
+ _output.WriteLine("Uri: {0}", uri);
+ using (HttpResponseMessage response = await client.GetAsync(uri))
+ {
+ string responseText = await response.Content.ReadAsStringAsync();
+ _output.WriteLine(responseText);
+ Assert.False(TestHelper.JsonMessageContainsKey(responseText, "Authorization"));
+ }
+ }
+ }
+
[Fact]
public void Properties_Get_CountIsZero()
{
@@ -312,11 +334,11 @@ namespace System.Net.Http.Functional.Tests
[Fact]
public async Task SendAsync_GetWithInvalidHostHeader_ThrowsException()
{
- if (PlatformDetection.IsNetCore && !UseManagedHandler)
+ if (PlatformDetection.IsNetCore && !UseSocketsHttpHandler)
{
// [ActiveIssue(24862)]
// WinHttpHandler and CurlHandler do not use the Host header to influence the SSL auth.
- // .NET Framework and ManagedHandler do.
+ // .NET Framework and SocketsHttpHandler do.
return;
}
@@ -331,17 +353,17 @@ namespace System.Net.Http.Functional.Tests
[ActiveIssue(22158, TargetFrameworkMonikers.Uap)]
[OuterLoop] // TODO: Issue #11345
- [Fact]
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsSubsystemForLinux))] // TODO: make unconditional after #26813 and #26476 are fixed
public async Task GetAsync_IPv6LinkLocalAddressUri_Success()
{
using (HttpClient client = CreateHttpClient())
{
- var options = new LoopbackServer.Options { Address = LoopbackServer.GetIPv6LinkLocalAddress() };
+ var options = new LoopbackServer.Options { Address = TestHelper.GetIPv6LinkLocalAddress() };
await LoopbackServer.CreateServerAsync(async (server, url) =>
{
_output.WriteLine(url.ToString());
await TestHelper.WhenAllCompletedOrAnyFailed(
- LoopbackServer.ReadRequestAndSendResponseAsync(server, options: options),
+ server.AcceptConnectionSendResponseAndCloseAsync(),
client.GetAsync(url));
}, options);
}
@@ -359,7 +381,7 @@ namespace System.Net.Http.Functional.Tests
{
_output.WriteLine(url.ToString());
await TestHelper.WhenAllCompletedOrAnyFailed(
- LoopbackServer.ReadRequestAndSendResponseAsync(server, options: options),
+ server.AcceptConnectionSendResponseAndCloseAsync(),
client.GetAsync(url));
}, options);
}
@@ -416,7 +438,7 @@ namespace System.Net.Http.Functional.Tests
using (HttpClient client = CreateHttpClient())
{
var request = new HttpRequestMessage(HttpMethod.Post, Configuration.Http.RemoteEchoServer);
- OperationCanceledException ex = await Assert.ThrowsAnyAsync<OperationCanceledException>(() =>
+ TaskCanceledException ex = await Assert.ThrowsAsync<TaskCanceledException>(() =>
client.SendAsync(request, cts.Token));
Assert.True(cts.Token.IsCancellationRequested, "cts token IsCancellationRequested");
if (!PlatformDetection.IsFullFramework)
@@ -504,9 +526,9 @@ namespace System.Net.Http.Functional.Tests
// UAP HTTP stack caches connections per-process. This causes interference when these tests run in
// the same process as the other tests. Each test needs to be isolated to its own process.
// See dicussion: https://github.com/dotnet/corefx/issues/21945
- RemoteInvoke(async useManagedHandlerString =>
+ RemoteInvoke(async useSocketsHttpHandlerString =>
{
- using (var client = CreateHttpClient(useManagedHandlerString))
+ using (var client = CreateHttpClient(useSocketsHttpHandlerString))
{
Uri uri = Configuration.Http.BasicAuthUriForCreds(secure: false, userName: Username, password: Password);
using (HttpResponseMessage response = await client.GetAsync(uri))
@@ -516,7 +538,7 @@ namespace System.Net.Http.Functional.Tests
return SuccessExitCode;
}
- }, UseManagedHandler.ToString()).Dispose();
+ }, UseSocketsHttpHandler.ToString()).Dispose();
}
[OuterLoop] // TODO: Issue #11345
@@ -525,9 +547,6 @@ namespace System.Net.Http.Functional.Tests
[InlineData("")] // RFC7235 requires servers to send this header with 401 but some servers don't.
public async Task GetAsync_ServerNeedsNonStandardAuthAndSetCredential_StatusCodeUnauthorized(string authHeaders)
{
- string responseHeaders =
- $"HTTP/1.1 401 Unauthorized\r\nDate: {DateTimeOffset.UtcNow:R}\r\n{authHeaders}Content-Length: 0\r\n\r\n";
- _output.WriteLine(responseHeaders);
await LoopbackServer.CreateServerAsync(async (server, url) =>
{
HttpClientHandler handler = CreateHttpClientHandler();
@@ -535,7 +554,7 @@ namespace System.Net.Http.Functional.Tests
using (var client = new HttpClient(handler))
{
Task<HttpResponseMessage> getResponseTask = client.GetAsync(url);
- Task<List<string>> serverTask = LoopbackServer.ReadRequestAndSendResponseAsync(server, responseHeaders);
+ Task<List<string>> serverTask = server.AcceptConnectionSendResponseAndCloseAsync(HttpStatusCode.Unauthorized);
await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
using (HttpResponseMessage response = await getResponseTask)
@@ -568,13 +587,17 @@ namespace System.Net.Http.Functional.Tests
}
}
- [ActiveIssue(23769)]
- [ActiveIssue(22707, TestPlatforms.AnyUnix)]
- [OuterLoop] // TODO: Issue #11345
[Theory, MemberData(nameof(RedirectStatusCodesOldMethodsNewMethods))]
public async Task AllowAutoRedirect_True_ValidateNewMethodUsedOnRedirection(
int statusCode, string oldMethod, string newMethod)
{
+ if (IsCurlHandler && statusCode == 300 && oldMethod == "POST")
+ {
+ // Known behavior: curl does not change method to "GET"
+ // https://github.com/dotnet/corefx/issues/26434
+ newMethod = "POST";
+ }
+
HttpClientHandler handler = CreateHttpClientHandler();
using (var client = new HttpClient(handler))
{
@@ -584,29 +607,107 @@ namespace System.Net.Http.Functional.Tests
Task<HttpResponseMessage> getResponseTask = client.SendAsync(request);
- Task<List<string>> serverTask = LoopbackServer.ReadRequestAndSendResponseAsync(origServer,
- $"HTTP/1.1 {statusCode} OK\r\n" +
- $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
- $"Location: {origUrl}\r\n" +
- "\r\n");
- await Task.WhenAny(getResponseTask, serverTask);
- Assert.False(getResponseTask.IsCompleted, $"{getResponseTask.Status}: {getResponseTask.Exception}");
- await serverTask;
+ await LoopbackServer.CreateServerAsync(async (redirServer, redirUrl) =>
+ {
+ // Original URL will redirect to a different URL
+ Task<List<string>> serverTask = origServer.AcceptConnectionSendResponseAndCloseAsync((HttpStatusCode)statusCode, $"Location: {redirUrl}\r\n");
- serverTask = LoopbackServer.ReadRequestAndSendResponseAsync(origServer,
- $"HTTP/1.1 200 OK\r\n" +
- $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
- "\r\n");
- await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
+ await Task.WhenAny(getResponseTask, serverTask);
+ Assert.False(getResponseTask.IsCompleted, $"{getResponseTask.Status}: {getResponseTask.Exception}");
+ await serverTask;
- List<string> receivedRequest = await serverTask;
- string[] statusLineParts = receivedRequest[0].Split(' ');
+ // Redirected URL answers with success
+ serverTask = redirServer.AcceptConnectionSendResponseAndCloseAsync();
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
- using (HttpResponseMessage response = await getResponseTask)
+ List<string> receivedRequest = await serverTask;
+
+ string[] statusLineParts = receivedRequest[0].Split(' ');
+
+ using (HttpResponseMessage response = await getResponseTask)
+ {
+ Assert.Equal(200, (int)response.StatusCode);
+ Assert.Equal(newMethod, statusLineParts[0]);
+ }
+ });
+ });
+ }
+ }
+
+ [Theory]
+ [InlineData(300)]
+ [InlineData(301)]
+ [InlineData(302)]
+ [InlineData(303)]
+ public async Task AllowAutoRedirect_True_PostToGetDoesNotSendTE(int statusCode)
+ {
+ if (IsCurlHandler && statusCode == 300)
+ {
+ // ISSUE #26434:
+ // CurlHandler doesn't change POST to GET for 300 response (see above test).
+ return;
+ }
+
+ if (IsWinHttpHandler)
+ {
+ // ISSUE #27440:
+ // This test occasionally fails on WinHttpHandler.
+ // Likely this is due to the way the loopback server is sending the response before reading the entire request.
+ // We should change the server behavior here.
+ return;
+ }
+
+ HttpClientHandler handler = CreateHttpClientHandler();
+ using (var client = new HttpClient(handler))
+ {
+ await LoopbackServer.CreateServerAsync(async (origServer, origUrl) =>
+ {
+ var request = new HttpRequestMessage(HttpMethod.Post, origUrl);
+ request.Content = new StringContent(ExpectedContent);
+ request.Headers.TransferEncodingChunked = true;
+
+ Task<HttpResponseMessage> getResponseTask = client.SendAsync(request);
+
+ await LoopbackServer.CreateServerAsync(async (redirServer, redirUrl) =>
{
- Assert.Equal(200, (int)response.StatusCode);
- Assert.Equal(newMethod, statusLineParts[0]);
- }
+ // Original URL will redirect to a different URL
+ Task serverTask = origServer.AcceptConnectionAsync(async connection =>
+ {
+ // Send Connection: close so the client will close connection after request is sent,
+ // meaning we can just read to the end to get the content
+ await connection.ReadRequestHeaderAndSendResponseAsync((HttpStatusCode)statusCode, $"Location: {redirUrl}\r\nConnection: close\r\n");
+ connection.Socket.Shutdown(SocketShutdown.Send);
+ await connection.Reader.ReadToEndAsync();
+ });
+
+ await Task.WhenAny(getResponseTask, serverTask);
+ Assert.False(getResponseTask.IsCompleted, $"{getResponseTask.Status}: {getResponseTask.Exception}");
+ await serverTask;
+
+ // Redirected URL answers with success
+ List<string> receivedRequest = null;
+ string receivedContent = null;
+ Task serverTask2 = redirServer.AcceptConnectionAsync(async connection =>
+ {
+ // Send Connection: close so the client will close connection after request is sent,
+ // meaning we can just read to the end to get the content
+ receivedRequest = await connection.ReadRequestHeaderAndSendResponseAsync(additionalHeaders: "Connection: close\r\n");
+ connection.Socket.Shutdown(SocketShutdown.Send);
+ receivedContent = await connection.Reader.ReadToEndAsync();
+ });
+
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask2);
+
+ string[] statusLineParts = receivedRequest[0].Split(' ');
+ Assert.Equal("GET", statusLineParts[0]);
+ Assert.DoesNotContain(receivedRequest, line => line.StartsWith("Transfer-Encoding"));
+ Assert.DoesNotContain(receivedRequest, line => line.StartsWith("Content-Length"));
+
+ using (HttpResponseMessage response = await getResponseTask)
+ {
+ Assert.Equal(200, (int)response.StatusCode);
+ }
+ });
});
}
}
@@ -683,7 +784,7 @@ namespace System.Net.Http.Functional.Tests
public async Task GetAsync_AllowAutoRedirectTrue_RedirectWithoutLocation_ReturnsOriginalResponse()
{
// [ActiveIssue(24819, TestPlatforms.Windows)]
- if (PlatformDetection.IsWindows && PlatformDetection.IsNetCore && !UseManagedHandler)
+ if (PlatformDetection.IsWindows && PlatformDetection.IsNetCore && !UseSocketsHttpHandler)
{
return;
}
@@ -695,10 +796,7 @@ namespace System.Net.Http.Functional.Tests
await LoopbackServer.CreateServerAsync(async (server, url) =>
{
Task<HttpResponseMessage> getTask = client.GetAsync(url);
- Task<List<string>> serverTask = LoopbackServer.ReadRequestAndSendResponseAsync(server,
- $"HTTP/1.1 302 OK\r\n" +
- $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
- "\r\n");
+ Task<List<string>> serverTask = server.AcceptConnectionSendResponseAndCloseAsync(HttpStatusCode.Found);
await TestHelper.WhenAllCompletedOrAnyFailed(getTask, serverTask);
using (HttpResponseMessage response = await getTask)
@@ -740,9 +838,9 @@ namespace System.Net.Http.Functional.Tests
[InlineData(3, 4)]
public async Task GetAsync_MaxAutomaticRedirectionsNServerHops_ThrowsIfTooMany(int maxHops, int hops)
{
- if (PlatformDetection.IsWindows && !PlatformDetection.IsWindows10Version1703OrGreater)
+ if (IsWinHttpHandler && !PlatformDetection.IsWindows10Version1703OrGreater)
{
- // Skip this test if running on Windows but on a release prior to Windows 10 Creators Update.
+ // Skip this test if using WinHttpHandler but on a release prior to Windows 10 Creators Update.
_output.WriteLine("Skipping test due to Windows 10 version prior to Version 1703.");
return;
}
@@ -774,7 +872,17 @@ namespace System.Net.Http.Functional.Tests
}
else
{
- await Assert.ThrowsAsync<HttpRequestException>(() => t);
+ if (UseSocketsHttpHandler)
+ {
+ using (HttpResponseMessage response = await t)
+ {
+ Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
+ }
+ }
+ else
+ {
+ await Assert.ThrowsAsync<HttpRequestException>(() => t);
+ }
}
}
}
@@ -820,15 +928,11 @@ namespace System.Net.Http.Functional.Tests
{
Task<HttpResponseMessage> getResponseTask = client.GetAsync(origUrl);
- Task redirectTask = LoopbackServer.ReadRequestAndSendResponseAsync(redirectServer);
+ Task redirectTask = redirectServer.AcceptConnectionSendResponseAndCloseAsync();
await TestHelper.WhenAllCompletedOrAnyFailed(
getResponseTask,
- LoopbackServer.ReadRequestAndSendResponseAsync(origServer,
- $"HTTP/1.1 {statusCode} OK\r\n" +
- $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
- $"Location: {redirectUrl}\r\n" +
- "\r\n"));
+ origServer.AcceptConnectionSendResponseAndCloseAsync((HttpStatusCode)statusCode, $"Location: {redirectUrl}\r\n"));
using (HttpResponseMessage response = await getResponseTask)
{
@@ -842,7 +946,7 @@ namespace System.Net.Http.Functional.Tests
}
[OuterLoop] // TODO: Issue #11345
- [ConditionalTheory(nameof(IsNotWindows7))] // Skip test on Win7 since WinHTTP has bugs w/ fragments.
+ [Theory]
[InlineData("#origFragment", "", "#origFragment", false)]
[InlineData("#origFragment", "", "#origFragment", true)]
[InlineData("", "#redirFragment", "#redirFragment", false)]
@@ -852,36 +956,67 @@ namespace System.Net.Http.Functional.Tests
public async Task GetAsync_AllowAutoRedirectTrue_RetainsOriginalFragmentIfAppropriate(
string origFragment, string redirFragment, string expectedFragment, bool useRelativeRedirect)
{
+ if (IsCurlHandler)
+ {
+ // Starting with libcurl 7.20, "fragment part of URLs are no longer sent to the server".
+ // So CurlHandler doesn't send fragments.
+ return;
+ }
+
+ if (IsNetfxHandler)
+ {
+ // Similarly, netfx doesn't send fragments at all.
+ return;
+ }
+
+ if (IsWinHttpHandler)
+ {
+ // According to https://tools.ietf.org/html/rfc7231#section-7.1.2,
+ // "If the Location value provided in a 3xx (Redirection) response does
+ // not have a fragment component, a user agent MUST process the
+ // redirection as if the value inherits the fragment component of the
+ // URI reference used to generate the request target(i.e., the
+ // redirection inherits the original reference's fragment, if any)."
+ // WINHTTP is not doing this, and thus neither is WinHttpHandler.
+ // It also sometimes doesn't include the fragments for redirects
+ // even in other cases.
+ return;
+ }
+
HttpClientHandler handler = CreateHttpClientHandler();
handler.AllowAutoRedirect = true;
using (var client = new HttpClient(handler))
{
await LoopbackServer.CreateServerAsync(async (origServer, origUrl) =>
{
- origUrl = new Uri(origUrl.ToString() + origFragment);
- Uri redirectUrl = useRelativeRedirect ?
- new Uri(origUrl.PathAndQuery + redirFragment, UriKind.Relative) :
- new Uri(origUrl.ToString() + redirFragment);
- Uri expectedUrl = new Uri(origUrl.ToString() + expectedFragment);
+ origUrl = new UriBuilder(origUrl) { Fragment = origFragment }.Uri;
+ Uri redirectUrl = new UriBuilder(origUrl) { Fragment = redirFragment }.Uri;
+ if (useRelativeRedirect)
+ {
+ redirectUrl = new Uri(redirectUrl.GetComponents(UriComponents.PathAndQuery | UriComponents.Fragment, UriFormat.SafeUnescaped), UriKind.Relative);
+ }
+ Uri expectedUrl = new UriBuilder(origUrl) { Fragment = expectedFragment }.Uri;
+ // Make and receive the first request that'll be redirected.
Task<HttpResponseMessage> getResponse = client.GetAsync(origUrl);
- Task firstRequest = LoopbackServer.ReadRequestAndSendResponseAsync(origServer,
- $"HTTP/1.1 302 OK\r\n" +
- $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
- $"Location: {redirectUrl}\r\n" +
- "\r\n");
+ Task firstRequest = origServer.AcceptConnectionSendResponseAndCloseAsync(HttpStatusCode.Found, $"Location: {redirectUrl}\r\n");
Assert.Equal(firstRequest, await Task.WhenAny(firstRequest, getResponse));
- Task secondRequest = LoopbackServer.ReadRequestAndSendResponseAsync(origServer,
- $"HTTP/1.1 200 OK\r\n" +
- $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
- "\r\n");
+ // Receive the second request.
+ Task<List<string>> secondRequest = origServer.AcceptConnectionSendResponseAndCloseAsync();
await TestHelper.WhenAllCompletedOrAnyFailed(secondRequest, getResponse);
+ // Make sure the server received the second request for the right Uri.
+ Assert.NotEmpty(secondRequest.Result);
+ string[] statusLineParts = secondRequest.Result[0].Split(' ');
+ Assert.Equal(3, statusLineParts.Length);
+ Assert.Equal(expectedUrl.GetComponents(UriComponents.PathAndQuery | UriComponents.Fragment, UriFormat.SafeUnescaped), statusLineParts[1]);
+
+ // Make sure the request message was updated with the correct redirected location.
using (HttpResponseMessage response = await getResponse)
{
Assert.Equal(200, (int)response.StatusCode);
- Assert.Equal(expectedUrl, response.RequestMessage.RequestUri);
+ Assert.Equal(expectedUrl.ToString(), response.RequestMessage.RequestUri.ToString());
}
});
}
@@ -970,69 +1105,16 @@ namespace System.Net.Http.Functional.Tests
}
[OuterLoop] // TODO: Issue #11345
- [Fact]
- public async Task GetAsync_DefaultCoookieContainer_NoCookieSent()
- {
- using (HttpClient client = CreateHttpClient())
- {
- using (HttpResponseMessage httpResponse = await client.GetAsync(Configuration.Http.RemoteEchoServer))
- {
- string responseText = await httpResponse.Content.ReadAsStringAsync();
- _output.WriteLine(responseText);
- Assert.False(TestHelper.JsonMessageContainsKey(responseText, "Cookie"));
- }
- }
- }
-
- [OuterLoop] // TODO: Issue #11345
- [Theory]
- [InlineData("cookieName1", "cookieValue1")]
- public async Task GetAsync_SetCookieContainer_CookieSent(string cookieName, string cookieValue)
- {
- HttpClientHandler handler = CreateHttpClientHandler();
- var cookieContainer = new CookieContainer();
- cookieContainer.Add(Configuration.Http.RemoteEchoServer, new Cookie(cookieName, cookieValue));
- handler.CookieContainer = cookieContainer;
- using (var client = new HttpClient(handler))
- {
- using (HttpResponseMessage httpResponse = await client.GetAsync(Configuration.Http.RemoteEchoServer))
- {
- Assert.Equal(HttpStatusCode.OK, httpResponse.StatusCode);
- string responseText = await httpResponse.Content.ReadAsStringAsync();
- _output.WriteLine(responseText);
- Assert.True(TestHelper.JsonMessageContainsKeyValue(responseText, cookieName, cookieValue));
- }
- }
- }
-
- [OuterLoop] // TODO: Issue #11345
+ [SkipOnTargetFramework(TargetFrameworkMonikers.Uap)]
[Theory]
- [InlineData("cookieName1", "cookieValue1")]
- public async Task GetAsync_RedirectResponseHasCookie_CookieSentToFinalUri(string cookieName, string cookieValue)
+ [MemberData(nameof(HeaderWithEmptyValueAndUris))]
+ public async Task GetAsync_RequestHeadersAddCustomHeaders_HeaderAndEmptyValueSent(string name, string value, Uri uri)
{
- Uri uri = Configuration.Http.RedirectUriForDestinationUri(
- secure: false,
- statusCode: 302,
- destinationUri: Configuration.Http.RemoteEchoServer,
- hops: 1);
- using (HttpClient client = CreateHttpClient())
+ if (IsWinHttpHandler && !PlatformDetection.IsWindows10Version1709OrGreater)
{
- client.DefaultRequestHeaders.Add(
- "X-SetCookie",
- string.Format("{0}={1};Path=/", cookieName, cookieValue));
- using (HttpResponseMessage httpResponse = await client.GetAsync(uri))
- {
- string responseText = await httpResponse.Content.ReadAsStringAsync();
- _output.WriteLine(responseText);
- Assert.True(TestHelper.JsonMessageContainsKeyValue(responseText, cookieName, cookieValue));
- }
+ return;
}
- }
- [OuterLoop] // TODO: Issue #11345
- [ConditionalTheory(nameof(NotWindowsUAPOrBeforeVersion1709)), MemberData(nameof(HeaderWithEmptyValueAndUris))]
- public async Task GetAsync_RequestHeadersAddCustomHeaders_HeaderAndEmptyValueSent(string name, string value, Uri uri)
- {
using (HttpClient client = CreateHttpClient())
{
_output.WriteLine($"name={name}, value={value}");
@@ -1065,59 +1147,340 @@ namespace System.Net.Http.Functional.Tests
}
}
- private static KeyValuePair<string, string> GenerateCookie(string name, char repeat, int overallHeaderValueLength)
+ [Theory]
+ [InlineData(":")]
+ [InlineData("\x1234: \x5678")]
+ [InlineData("nocolon")]
+ [InlineData("no colon")]
+ [InlineData("Content-Length ")]
+ public async Task GetAsync_InvalidHeaderNameValue_ThrowsHttpRequestException(string invalidHeader)
{
- string emptyHeaderValue = $"{name}=; Path=/";
-
- Debug.Assert(overallHeaderValueLength > emptyHeaderValue.Length);
-
- int valueCount = overallHeaderValueLength - emptyHeaderValue.Length;
- string value = new string(repeat, valueCount);
+ if (IsCurlHandler && invalidHeader.Contains(':'))
+ {
+ // Issue #27172
+ // CurlHandler allows these headers as long as they have a colon.
+ return;
+ }
- return new KeyValuePair<string, string>(name, value);
+ await LoopbackServer.CreateClientAndServerAsync(async uri =>
+ {
+ using (var client = CreateHttpClient())
+ {
+ await Assert.ThrowsAsync<HttpRequestException>(() => client.GetStringAsync(uri));
+ }
+ }, server => server.AcceptConnectionSendCustomResponseAndCloseAsync($"HTTP/1.1 200 OK\r\n{invalidHeader}\r\nContent-Length: 11\r\n\r\nhello world"));
}
- public static object[][] CookieNameValues =
+ [Fact]
+ public async Task PostAsync_ManyDifferentRequestHeaders_SentCorrectly()
{
- // WinHttpHandler calls WinHttpQueryHeaders to iterate through multiple Set-Cookie header values,
- // using an initial buffer size of 128 chars. If the buffer is not large enough, WinHttpQueryHeaders
- // returns an insufficient buffer error, allowing WinHttpHandler to try again with a larger buffer.
- // Sometimes when WinHttpQueryHeaders fails due to insufficient buffer, it still advances the
- // iteration index, which would cause header values to be missed if not handled correctly.
- //
- // In particular, WinHttpQueryHeader behaves as follows for the following header value lengths:
- // * 0-127 chars: succeeds, index advances from 0 to 1.
- // * 128-255 chars: fails due to insufficient buffer, index advances from 0 to 1.
- // * 256+ chars: fails due to insufficient buffer, index stays at 0.
- //
- // The below overall header value lengths were chosen to exercise reading header values at these
- // edges, to ensure WinHttpHandler does not miss multiple Set-Cookie headers.
+ if (IsWinHttpHandler)
+ {
+ // Issue #27171
+ // Fails consistently with:
+ // System.InvalidCastException: "Unable to cast object of type 'System.Object[]' to type 'System.Net.Http.WinHttpRequestState'"
+ // This appears to be due to adding the Expect: 100-continue header, which causes winhttp
+ // to fail with a "The parameter is incorrect" error, which in turn causes the request to
+ // be torn down, and in doing so, we this this during disposal of the SafeWinHttpHandle.
+ return;
+ }
+
+ // Using examples from https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Request_fields
+ // Exercises all exposed request.Headers and request.Content.Headers strongly-typed properties
+ await LoopbackServer.CreateClientAndServerAsync(async uri =>
+ {
+ using (var client = CreateHttpClient())
+ {
+ byte[] contentArray = Encoding.ASCII.GetBytes("hello world");
+ var request = new HttpRequestMessage(HttpMethod.Post, uri) { Content = new ByteArrayContent(contentArray) };
+
+ request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain"));
+ request.Headers.AcceptCharset.Add(new StringWithQualityHeaderValue("utf-8"));
+ request.Headers.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
+ request.Headers.AcceptEncoding.Add(new StringWithQualityHeaderValue("deflate"));
+ request.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue("en-US"));
+ request.Headers.Add("Accept-Datetime", "Thu, 31 May 2007 20:35:00 GMT");
+ request.Headers.Add("Access-Control-Request-Method", "GET");
+ request.Headers.Add("Access-Control-Request-Headers", "GET");
+ request.Headers.Authorization = new AuthenticationHeaderValue("Basic", "QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
+ request.Headers.CacheControl = new CacheControlHeaderValue() { NoCache = true };
+ request.Headers.Connection.Add("close");
+ request.Headers.Add("Cookie", "$Version=1; Skin=new");
+ request.Content.Headers.ContentLength = contentArray.Length;
+ request.Content.Headers.ContentMD5 = MD5.Create().ComputeHash(contentArray);
+ request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
+ request.Headers.Date = DateTimeOffset.Parse("Tue, 15 Nov 1994 08:12:31 GMT");
+ request.Headers.Expect.Add(new NameValueWithParametersHeaderValue("100-continue"));
+ request.Headers.Add("Forwarded", "for=192.0.2.60;proto=http;by=203.0.113.43");
+ request.Headers.Add("From", "User Name <user@example.com>");
+ request.Headers.Host = "en.wikipedia.org:8080";
+ request.Headers.IfMatch.Add(new EntityTagHeaderValue("\"37060cd8c284d8af7ad3082f209582d\""));
+ request.Headers.IfModifiedSince = DateTimeOffset.Parse("Sat, 29 Oct 1994 19:43:31 GMT");
+ request.Headers.IfNoneMatch.Add(new EntityTagHeaderValue("\"737060cd8c284d8af7ad3082f209582d\""));
+ request.Headers.IfRange = new RangeConditionHeaderValue(DateTimeOffset.Parse("Wed, 21 Oct 2015 07:28:00 GMT"));
+ request.Headers.IfUnmodifiedSince = DateTimeOffset.Parse("Sat, 29 Oct 1994 19:43:31 GMT");
+ request.Headers.MaxForwards = 10;
+ request.Headers.Add("Origin", "http://www.example-social-network.com");
+ request.Headers.Pragma.Add(new NameValueHeaderValue("no-cache"));
+ request.Headers.ProxyAuthorization = new AuthenticationHeaderValue("Basic", "QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
+ request.Headers.Range = new RangeHeaderValue(500, 999);
+ request.Headers.Referrer = new Uri("http://en.wikipedia.org/wiki/Main_Page");
+ request.Headers.TE.Add(new TransferCodingWithQualityHeaderValue("trailers"));
+ request.Headers.TE.Add(new TransferCodingWithQualityHeaderValue("deflate"));
+ request.Headers.Trailer.Add("MyTrailer");
+ request.Headers.TransferEncoding.Add(new TransferCodingHeaderValue("chunked"));
+ request.Headers.UserAgent.Add(new ProductInfoHeaderValue(new ProductHeaderValue("Mozilla", "5.0")));
+ request.Headers.Upgrade.Add(new ProductHeaderValue("HTTPS", "1.3"));
+ request.Headers.Upgrade.Add(new ProductHeaderValue("IRC", "6.9"));
+ request.Headers.Upgrade.Add(new ProductHeaderValue("RTA", "x11"));
+ request.Headers.Upgrade.Add(new ProductHeaderValue("websocket"));
+ request.Headers.Via.Add(new ViaHeaderValue("1.0", "fred"));
+ request.Headers.Via.Add(new ViaHeaderValue("1.1", "example.com", null, "(Apache/1.1)"));
+ request.Headers.Warning.Add(new WarningHeaderValue(199, "-", "\"Miscellaneous warning\""));
+ request.Headers.Add("X-Requested-With", "XMLHttpRequest");
+ request.Headers.Add("DNT", "1 (Do Not Track Enabled)");
+ request.Headers.Add("X-Forwarded-For", "client1");
+ request.Headers.Add("X-Forwarded-For", "proxy1");
+ request.Headers.Add("X-Forwarded-For", "proxy2");
+ request.Headers.Add("X-Forwarded-Host", "en.wikipedia.org:8080");
+ request.Headers.Add("X-Forwarded-Proto", "https");
+ request.Headers.Add("Front-End-Https", "https");
+ request.Headers.Add("X-Http-Method-Override", "DELETE");
+ request.Headers.Add("X-ATT-DeviceId", "GT-P7320/P7320XXLPG");
+ request.Headers.Add("X-Wap-Profile", "http://wap.samsungmobile.com/uaprof/SGH-I777.xml");
+ request.Headers.Add("Proxy-Connection", "keep-alive");
+ request.Headers.Add("X-UIDH", "...");
+ request.Headers.Add("X-Csrf-Token", "i8XNjC4b8KVok4uw5RftR38Wgp2BFwql");
+ request.Headers.Add("X-Request-ID", "f058ebd6-02f7-4d3f-942e-904344e8cde5");
+ request.Headers.Add("X-Request-ID", "f058ebd6-02f7-4d3f-942e-904344e8cde5");
+
+ (await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead)).Dispose();
+ }
+ }, async server =>
+ {
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ var headersSet = new HashSet<string>();
+ string line;
+ while (!string.IsNullOrEmpty(line = await connection.Reader.ReadLineAsync()))
+ {
+ Assert.True(headersSet.Add(line));
+ }
+
+ await connection.Writer.WriteAsync($"HTTP/1.1 200 OK\r\nDate: {DateTimeOffset.UtcNow:R}\r\nConnection: close\r\nContent-Length: 0\r\n\r\n");
+ while (await connection.Socket.ReceiveAsync(new ArraySegment<byte>(new byte[1000]), SocketFlags.None) > 0);
+
+ Assert.Contains("Accept-Charset: utf-8", headersSet);
+ Assert.Contains("Accept-Encoding: gzip, deflate", headersSet);
+ Assert.Contains("Accept-Language: en-US", headersSet);
+ Assert.Contains("Accept-Datetime: Thu, 31 May 2007 20:35:00 GMT", headersSet);
+ Assert.Contains("Access-Control-Request-Method: GET", headersSet);
+ Assert.Contains("Access-Control-Request-Headers: GET", headersSet);
+ Assert.Contains("Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==", headersSet);
+ Assert.Contains("Cache-Control: no-cache", headersSet);
+ Assert.Contains("Connection: close", headersSet, StringComparer.OrdinalIgnoreCase); // NetFxHandler uses "Close" vs "close"
+ if (!IsNetfxHandler)
+ {
+ Assert.Contains("Cookie: $Version=1; Skin=new", headersSet);
+ }
+ Assert.Contains("Date: Tue, 15 Nov 1994 08:12:31 GMT", headersSet);
+ Assert.Contains("Expect: 100-continue", headersSet);
+ Assert.Contains("Forwarded: for=192.0.2.60;proto=http;by=203.0.113.43", headersSet);
+ Assert.Contains("From: User Name <user@example.com>", headersSet);
+ Assert.Contains("Host: en.wikipedia.org:8080", headersSet);
+ Assert.Contains("If-Match: \"37060cd8c284d8af7ad3082f209582d\"", headersSet);
+ Assert.Contains("If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT", headersSet);
+ Assert.Contains("If-None-Match: \"737060cd8c284d8af7ad3082f209582d\"", headersSet);
+ Assert.Contains("If-Range: Wed, 21 Oct 2015 07:28:00 GMT", headersSet);
+ Assert.Contains("If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT", headersSet);
+ Assert.Contains("Max-Forwards: 10", headersSet);
+ Assert.Contains("Origin: http://www.example-social-network.com", headersSet);
+ Assert.Contains("Pragma: no-cache", headersSet);
+ Assert.Contains("Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==", headersSet);
+ Assert.Contains("Range: bytes=500-999", headersSet);
+ Assert.Contains("Referer: http://en.wikipedia.org/wiki/Main_Page", headersSet);
+ Assert.Contains("TE: trailers, deflate", headersSet);
+ Assert.Contains("Trailer: MyTrailer", headersSet);
+ Assert.Contains("Transfer-Encoding: chunked", headersSet);
+ Assert.Contains("User-Agent: Mozilla/5.0", headersSet);
+ Assert.Contains("Upgrade: HTTPS/1.3, IRC/6.9, RTA/x11, websocket", headersSet);
+ Assert.Contains("Via: 1.0 fred, 1.1 example.com (Apache/1.1)", headersSet);
+ Assert.Contains("Warning: 199 - \"Miscellaneous warning\"", headersSet);
+ Assert.Contains("X-Requested-With: XMLHttpRequest", headersSet);
+ Assert.Contains("DNT: 1 (Do Not Track Enabled)", headersSet);
+ Assert.Contains("X-Forwarded-For: client1, proxy1, proxy2", headersSet);
+ Assert.Contains("X-Forwarded-Host: en.wikipedia.org:8080", headersSet);
+ Assert.Contains("X-Forwarded-Proto: https", headersSet);
+ Assert.Contains("Front-End-Https: https", headersSet);
+ Assert.Contains("X-Http-Method-Override: DELETE", headersSet);
+ Assert.Contains("X-ATT-DeviceId: GT-P7320/P7320XXLPG", headersSet);
+ Assert.Contains("X-Wap-Profile: http://wap.samsungmobile.com/uaprof/SGH-I777.xml", headersSet);
+ if (!IsNetfxHandler)
+ {
+ Assert.Contains("Proxy-Connection: keep-alive", headersSet);
+ }
+ Assert.Contains("X-UIDH: ...", headersSet);
+ Assert.Contains("X-Csrf-Token: i8XNjC4b8KVok4uw5RftR38Wgp2BFwql", headersSet);
+ Assert.Contains("X-Request-ID: f058ebd6-02f7-4d3f-942e-904344e8cde5, f058ebd6-02f7-4d3f-942e-904344e8cde5", headersSet);
+ });
+ });
+ }
- new object[] { GenerateCookie(name: "foo", repeat: 'a', overallHeaderValueLength: 126) },
- new object[] { GenerateCookie(name: "foo", repeat: 'a', overallHeaderValueLength: 127) },
- new object[] { GenerateCookie(name: "foo", repeat: 'a', overallHeaderValueLength: 128) },
- new object[] { GenerateCookie(name: "foo", repeat: 'a', overallHeaderValueLength: 129) },
+ public static IEnumerable<object[]> GetAsync_ManyDifferentResponseHeaders_ParsedCorrectly_MemberData() =>
+ from newline in new[] { "\n", "\r\n" }
+ from fold in new[] { "", newline + " ", newline + "\t", newline + " " }
+ from dribble in new[] { false, true }
+ select new object[] { newline, fold, dribble };
- new object[] { GenerateCookie(name: "foo", repeat: 'a', overallHeaderValueLength: 254) },
- new object[] { GenerateCookie(name: "foo", repeat: 'a', overallHeaderValueLength: 255) },
- new object[] { GenerateCookie(name: "foo", repeat: 'a', overallHeaderValueLength: 256) },
- new object[] { GenerateCookie(name: "foo", repeat: 'a', overallHeaderValueLength: 257) },
+ [Theory]
+ [MemberData(nameof(GetAsync_ManyDifferentResponseHeaders_ParsedCorrectly_MemberData))]
+ public async Task GetAsync_ManyDifferentResponseHeaders_ParsedCorrectly(string newline, string fold, bool dribble)
+ {
+ if (IsCurlHandler && !string.IsNullOrEmpty(fold))
+ {
+ // CurlHandler doesn't currently support folded headers.
+ return;
+ }
- new object[]
+ if (IsNetfxHandler && newline == "\n")
{
- new KeyValuePair<string, string>(
- ".AspNetCore.Antiforgery.Xam7_OeLcN4",
- "CfDJ8NGNxAt7CbdClq3UJ8_6w_4661wRQZT1aDtUOIUKshbcV4P0NdS8klCL5qGSN-PNBBV7w23G6MYpQ81t0PMmzIN4O04fqhZ0u1YPv66mixtkX3iTi291DgwT3o5kozfQhe08-RAExEmXpoCbueP_QYM")
+ // NetFxHandler doesn't allow LF-only line endings.
+ return;
}
- };
+
+ // Using examples from https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Response_fields
+ // Exercises all exposed response.Headers and response.Content.Headers strongly-typed properties
+ await LoopbackServer.CreateClientAndServerAsync(async uri =>
+ {
+ using (var client = CreateHttpClient())
+ using (HttpResponseMessage resp = await client.GetAsync(uri))
+ {
+ Assert.Equal("1.1", resp.Version.ToString());
+ Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
+ Assert.Contains("*", resp.Headers.GetValues("Access-Control-Allow-Origin"));
+ Assert.Contains("text/example;charset=utf-8", resp.Headers.GetValues("Accept-Patch"));
+ Assert.Contains("bytes", resp.Headers.AcceptRanges);
+ Assert.Equal(TimeSpan.FromSeconds(12), resp.Headers.Age.GetValueOrDefault());
+ Assert.Contains("GET", resp.Content.Headers.Allow);
+ Assert.Contains("HEAD", resp.Content.Headers.Allow);
+ Assert.Contains("http/1.1=\"http2.example.com:8001\"; ma=7200", resp.Headers.GetValues("Alt-Svc"));
+ Assert.Equal(TimeSpan.FromSeconds(3600), resp.Headers.CacheControl.MaxAge.GetValueOrDefault());
+ Assert.Contains("close", resp.Headers.Connection);
+ Assert.True(resp.Headers.ConnectionClose.GetValueOrDefault());
+ Assert.Equal("attachment", resp.Content.Headers.ContentDisposition.DispositionType);
+ Assert.Equal("\"fname.ext\"", resp.Content.Headers.ContentDisposition.FileName);
+ Assert.Contains("gzip", resp.Content.Headers.ContentEncoding);
+ Assert.Contains("da", resp.Content.Headers.ContentLanguage);
+ Assert.Equal(new Uri("/index.htm", UriKind.Relative), resp.Content.Headers.ContentLocation);
+ Assert.Equal(Convert.FromBase64String("Q2hlY2sgSW50ZWdyaXR5IQ=="), resp.Content.Headers.ContentMD5);
+ Assert.Equal("bytes", resp.Content.Headers.ContentRange.Unit);
+ Assert.Equal(21010, resp.Content.Headers.ContentRange.From.GetValueOrDefault());
+ Assert.Equal(47021, resp.Content.Headers.ContentRange.To.GetValueOrDefault());
+ Assert.Equal(47022, resp.Content.Headers.ContentRange.Length.GetValueOrDefault());
+ Assert.Equal("text/html", resp.Content.Headers.ContentType.MediaType);
+ Assert.Equal("utf-8", resp.Content.Headers.ContentType.CharSet);
+ Assert.Equal(DateTimeOffset.Parse("Tue, 15 Nov 1994 08:12:31 GMT"), resp.Headers.Date.GetValueOrDefault());
+ Assert.Equal("\"737060cd8c284d8af7ad3082f209582d\"", resp.Headers.ETag.Tag);
+ Assert.Equal(DateTimeOffset.Parse("Thu, 01 Dec 1994 16:00:00 GMT"), resp.Content.Headers.Expires.GetValueOrDefault());
+ Assert.Equal(DateTimeOffset.Parse("Tue, 15 Nov 1994 12:45:26 GMT"), resp.Content.Headers.LastModified.GetValueOrDefault());
+ Assert.Contains("</feed>; rel=\"alternate\"", resp.Headers.GetValues("Link"));
+ Assert.Equal(new Uri("http://www.w3.org/pub/WWW/People.html"), resp.Headers.Location);
+ Assert.Contains("CP=\"This is not a P3P policy!\"", resp.Headers.GetValues("P3P"));
+ Assert.Contains(new NameValueHeaderValue("no-cache"), resp.Headers.Pragma);
+ Assert.Contains(new AuthenticationHeaderValue("basic"), resp.Headers.ProxyAuthenticate);
+ Assert.Contains("max-age=2592000; pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\"", resp.Headers.GetValues("Public-Key-Pins"));
+ Assert.Equal(TimeSpan.FromSeconds(120), resp.Headers.RetryAfter.Delta.GetValueOrDefault());
+ Assert.Contains(new ProductInfoHeaderValue("Apache", "2.4.1"), resp.Headers.Server);
+ Assert.Contains("UserID=JohnDoe; Max-Age=3600; Version=1", resp.Headers.GetValues("Set-Cookie"));
+ Assert.Contains("max-age=16070400; includeSubDomains", resp.Headers.GetValues("Strict-Transport-Security"));
+ Assert.Contains("Max-Forwards", resp.Headers.Trailer);
+ Assert.Contains("?", resp.Headers.GetValues("Tk"));
+ Assert.Contains(new ProductHeaderValue("HTTPS", "1.3"), resp.Headers.Upgrade);
+ Assert.Contains(new ProductHeaderValue("IRC", "6.9"), resp.Headers.Upgrade);
+ Assert.Contains(new ProductHeaderValue("websocket"), resp.Headers.Upgrade);
+ Assert.Contains("Accept-Language", resp.Headers.Vary);
+ Assert.Contains(new ViaHeaderValue("1.0", "fred"), resp.Headers.Via);
+ Assert.Contains(new ViaHeaderValue("1.1", "example.com", null, "(Apache/1.1)"), resp.Headers.Via);
+ Assert.Contains(new WarningHeaderValue(199, "-", "\"Miscellaneous warning\"", DateTimeOffset.Parse("Wed, 21 Oct 2015 07:28:00 GMT")), resp.Headers.Warning);
+ Assert.Contains(new AuthenticationHeaderValue("Basic"), resp.Headers.WwwAuthenticate);
+ Assert.Contains("deny", resp.Headers.GetValues("X-Frame-Options"));
+ Assert.Contains("default-src 'self'", resp.Headers.GetValues("X-WebKit-CSP"));
+ Assert.Contains("5; url=http://www.w3.org/pub/WWW/People.html", resp.Headers.GetValues("Refresh"));
+ Assert.Contains("200 OK", resp.Headers.GetValues("Status"));
+ Assert.Contains("<origin>[, <origin>]*", resp.Headers.GetValues("Timing-Allow-Origin"));
+ Assert.Contains("42.666", resp.Headers.GetValues("X-Content-Duration"));
+ Assert.Contains("nosniff", resp.Headers.GetValues("X-Content-Type-Options"));
+ Assert.Contains("PHP/5.4.0", resp.Headers.GetValues("X-Powered-By"));
+ Assert.Contains("f058ebd6-02f7-4d3f-942e-904344e8cde5", resp.Headers.GetValues("X-Request-ID"));
+ Assert.Contains("IE=EmulateIE7", resp.Headers.GetValues("X-UA-Compatible"));
+ Assert.Contains("1; mode=block", resp.Headers.GetValues("X-XSS-Protection"));
+ }
+ }, server => server.AcceptConnectionSendCustomResponseAndCloseAsync(
+ $"HTTP/1.1 200 OK{newline}" +
+ $"Access-Control-Allow-Origin:{fold} *{newline}" +
+ $"Accept-Patch:{fold} text/example;charset=utf-8{newline}" +
+ $"Accept-Ranges:{fold} bytes{newline}" +
+ $"Age: {fold}12{newline}" +
+ $"Allow: {fold}GET, HEAD{newline}" +
+ $"Alt-Svc:{fold} http/1.1=\"http2.example.com:8001\"; ma=7200{newline}" +
+ $"Cache-Control: {fold}max-age=3600{newline}" +
+ $"Connection:{fold} close{newline}" +
+ $"Content-Disposition: {fold}attachment;{fold} filename=\"fname.ext\"{newline}" +
+ $"Content-Encoding: {fold}gzip{newline}" +
+ $"Content-Language:{fold} da{newline}" +
+ $"Content-Location: {fold}/index.htm{newline}" +
+ $"Content-MD5:{fold} Q2hlY2sgSW50ZWdyaXR5IQ=={newline}" +
+ $"Content-Range: {fold}bytes {fold}21010-47021/47022{newline}" +
+ $"Content-Type: text/html;{fold} charset=utf-8{newline}" +
+ $"Date: Tue, 15 Nov 1994{fold} 08:12:31 GMT{newline}" +
+ $"ETag: {fold}\"737060cd8c284d8af7ad3082f209582d\"{newline}" +
+ $"Expires: Thu,{fold} 01 Dec 1994 16:00:00 GMT{newline}" +
+ $"Last-Modified:{fold} Tue, 15 Nov 1994 12:45:26 GMT{newline}" +
+ $"Link:{fold} </feed>; rel=\"alternate\"{newline}" +
+ $"Location:{fold} http://www.w3.org/pub/WWW/People.html{newline}" +
+ $"P3P: {fold}CP=\"This is not a P3P policy!\"{newline}" +
+ $"Pragma: {fold}no-cache{newline}" +
+ $"Proxy-Authenticate:{fold} Basic{newline}" +
+ $"Public-Key-Pins:{fold} max-age=2592000; pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\"{newline}" +
+ $"Retry-After: {fold}120{newline}" +
+ $"Server: {fold}Apache/2.4.1{fold} (Unix){newline}" +
+ $"Set-Cookie: {fold}UserID=JohnDoe; Max-Age=3600; Version=1{newline}" +
+ $"Strict-Transport-Security: {fold}max-age=16070400; includeSubDomains{newline}" +
+ $"Trailer: {fold}Max-Forwards{newline}" +
+ $"Tk: {fold}?{newline}" +
+ $"Upgrade: HTTPS/1.3,{fold} IRC/6.9,{fold} RTA/x11, {fold}websocket{newline}" +
+ $"Vary:{fold} Accept-Language{newline}" +
+ $"Via:{fold} 1.0 fred, 1.1 example.com{fold} (Apache/1.1){newline}" +
+ $"Warning:{fold} 199 - \"Miscellaneous warning\" \"Wed, 21 Oct 2015 07:28:00 GMT\"{newline}" +
+ $"WWW-Authenticate: {fold}Basic{newline}" +
+ $"X-Frame-Options: {fold}deny{newline}" +
+ $"X-WebKit-CSP: default-src 'self'{newline}" +
+ $"Refresh: {fold}5; url=http://www.w3.org/pub/WWW/People.html{newline}" +
+ $"Status: {fold}200 OK{newline}" +
+ $"Timing-Allow-Origin: {fold}<origin>[, <origin>]*{newline}" +
+ $"Upgrade-Insecure-Requests:{fold} 1{newline}" +
+ $"X-Content-Duration:{fold} 42.666{newline}" +
+ $"X-Content-Type-Options: {fold}nosniff{newline}" +
+ $"X-Powered-By: {fold}PHP/5.4.0{newline}" +
+ $"X-Request-ID:{fold} f058ebd6-02f7-4d3f-942e-904344e8cde5{newline}" +
+ $"X-UA-Compatible: {fold}IE=EmulateIE7{newline}" +
+ $"X-XSS-Protection:{fold} 1; mode=block{newline}" +
+ $"{newline}"),
+ dribble ? new LoopbackServer.Options { StreamWrapper = s => new DribbleStream(s) } : null);
+ }
[OuterLoop] // TODO: Issue #11345
[Theory]
- [MemberData(nameof(CookieNameValues))]
- public async Task GetAsync_ResponseWithSetCookieHeaders_AllCookiesRead(KeyValuePair<string, string> cookie1)
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task GetAsync_TrailingHeaders_Ignored(bool includeTrailerHeader)
{
- var cookie2 = new KeyValuePair<string, string>(".AspNetCore.Session", "RAExEmXpoCbueP_QYM");
- var cookie3 = new KeyValuePair<string, string>("name", "value");
+ if (IsCurlHandler)
+ {
+ // ActiveIssue #17174: CurlHandler has a problem here
+ // https://github.com/curl/curl/issues/1354
+ return;
+ }
await LoopbackServer.CreateServerAsync(async (server, url) =>
{
@@ -1127,41 +1490,39 @@ namespace System.Net.Http.Functional.Tests
Task<HttpResponseMessage> getResponseTask = client.GetAsync(url);
await TestHelper.WhenAllCompletedOrAnyFailed(
getResponseTask,
- LoopbackServer.ReadRequestAndSendResponseAsync(server,
- $"HTTP/1.1 200 OK\r\n" +
- $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
- $"Set-Cookie: {cookie1.Key}={cookie1.Value}; Path=/\r\n" +
- $"Set-Cookie : {cookie2.Key}={cookie2.Value}; Path=/\r\n" + // space before colon to verify header is trimmed and recognized
- $"Set-Cookie: {cookie3.Key}={cookie3.Value}; Path=/\r\n" +
+ server.AcceptConnectionSendCustomResponseAndCloseAsync(
+ "HTTP/1.1 200 OK\r\n" +
+ "Transfer-Encoding: chunked\r\n" +
+ (includeTrailerHeader ? "Trailer: MyCoolTrailerHeader\r\n" : "") +
+ "\r\n" +
+ "4\r\n" +
+ "data\r\n" +
+ "0\r\n" +
+ "MyCoolTrailerHeader: amazingtrailer\r\n" +
"\r\n"));
using (HttpResponseMessage response = await getResponseTask)
{
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
- CookieCollection cookies = handler.CookieContainer.GetCookies(url);
+ if (includeTrailerHeader)
+ {
+ Assert.Contains("MyCoolTrailerHeader", response.Headers.GetValues("Trailer"));
+ }
+ Assert.False(response.Headers.Contains("MyCoolTrailerHeader"), "Trailer should have been ignored");
- Assert.Equal(3, cookies.Count);
- Assert.Equal(cookie1.Value, cookies[cookie1.Key].Value);
- Assert.Equal(cookie2.Value, cookies[cookie2.Key].Value);
- Assert.Equal(cookie3.Value, cookies[cookie3.Key].Value);
+ string data = await response.Content.ReadAsStringAsync();
+ Assert.Contains("data", data);
+ Assert.DoesNotContain("MyCoolTrailerHeader", data);
+ Assert.DoesNotContain("amazingtrailer", data);
}
}
});
}
[OuterLoop] // TODO: Issue #11345
- [ActiveIssue(17174, TestPlatforms.AnyUnix)] // https://github.com/curl/curl/issues/1354
- [Theory]
- [InlineData(false)]
- [InlineData(true)]
- public async Task GetAsync_TrailingHeaders_Ignored(bool includeTrailerHeader)
+ [Fact]
+ public async Task GetAsync_NonTraditionalChunkSizes_Accepted()
{
- if (UseManagedHandler)
- {
- // TODO #23130: The managed handler isn't correctly handling trailing headers.
- return;
- }
-
await LoopbackServer.CreateServerAsync(async (server, url) =>
{
using (HttpClientHandler handler = CreateHttpClientHandler())
@@ -1170,25 +1531,29 @@ namespace System.Net.Http.Functional.Tests
Task<HttpResponseMessage> getResponseTask = client.GetAsync(url);
await TestHelper.WhenAllCompletedOrAnyFailed(
getResponseTask,
- LoopbackServer.ReadRequestAndSendResponseAsync(server,
+ server.AcceptConnectionSendCustomResponseAndCloseAsync(
"HTTP/1.1 200 OK\r\n" +
"Transfer-Encoding: chunked\r\n" +
- (includeTrailerHeader ? "Trailer: MyCoolTrailerHeader\r\n" : "") +
"\r\n" +
- "4\r\n" +
+ "4 \r\n" + // whitespace after size
"data\r\n" +
+ "5;somekey=somevalue\r\n" + // chunk extension
+ "hello\r\n" +
+ "7\t ;chunkextension\r\n" + // tabs/spaces then chunk extension
+ "netcore\r\n" +
"0\r\n" +
- "MyCoolTrailerHeader: amazingtrailer\r\n" +
"\r\n"));
using (HttpResponseMessage response = await getResponseTask)
{
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
- if (includeTrailerHeader)
- {
- Assert.Contains("MyCoolTrailerHeader", response.Headers.GetValues("Trailer"));
- }
- Assert.False(response.Headers.Contains("MyCoolTrailerHeader"), "Trailer should have been ignored");
+ string data = await response.Content.ReadAsStringAsync();
+ Assert.Contains("data", data);
+ Assert.Contains("hello", data);
+ Assert.Contains("netcore", data);
+ Assert.DoesNotContain("somekey", data);
+ Assert.DoesNotContain("somevalue", data);
+ Assert.DoesNotContain("chunkextension", data);
}
}
});
@@ -1197,9 +1562,19 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop] // TODO: Issue #11345
[Theory]
[InlineData("")] // missing size
+ [InlineData(" ")] // missing size
[InlineData("10000000000000000")] // overflowing size
+ [InlineData("xyz")] // non-hex
+ [InlineData("7gibberish")] // valid size then gibberish
+ [InlineData("7\v\f")] // unacceptable whitespace
public async Task GetAsync_InvalidChunkSize_ThrowsHttpRequestException(string chunkSize)
{
+ if (IsCurlHandler)
+ {
+ // libcurl allows any arbitrary characters after the hex value
+ return;
+ }
+
await LoopbackServer.CreateServerAsync(async (server, url) =>
{
using (HttpClient client = CreateHttpClient())
@@ -1210,13 +1585,11 @@ namespace System.Net.Http.Functional.Tests
$"{chunkSize}\r\n";
var tcs = new TaskCompletionSource<bool>();
- Task serverTask =
- LoopbackServer.AcceptSocketAsync(server, async (s, stream, reader, writer) =>
+ Task serverTask = server.AcceptConnectionAsync(async connection =>
{
- var list = await LoopbackServer.ReadWriteAcceptedAsync(s, reader, writer, partialResponse);
+ await connection.ReadRequestHeaderAndSendCustomResponseAsync(partialResponse);
await tcs.Task;
- return list;
- }, null);
+ });
await Assert.ThrowsAsync<HttpRequestException>(() => client.GetAsync(url));
tcs.SetResult(true);
@@ -1224,6 +1597,79 @@ namespace System.Net.Http.Functional.Tests
}
});
}
+
+ [Fact]
+ public async Task GetAsync_InvalidChunkTerminator_ThrowsHttpRequestException()
+ {
+ await LoopbackServer.CreateClientAndServerAsync(async url =>
+ {
+ using (HttpClient client = CreateHttpClient())
+ {
+ await Assert.ThrowsAsync<HttpRequestException>(() => client.GetAsync(url));
+ }
+ }, server => server.AcceptConnectionSendCustomResponseAndCloseAsync(
+ "HTTP/1.1 200 OK\r\n" +
+ "Transfer-Encoding: chunked\r\n" +
+ "\r\n" +
+ "5\r\n" +
+ "hello" + // missing \r\n terminator
+ //"5\r\n" +
+ //"world" + // missing \r\n terminator
+ "0\r\n" +
+ "\r\n"));
+ }
+
+ [OuterLoop] // TODO: Issue #11345
+ [Fact]
+ public async Task GetAsync_InfiniteChunkSize_ThrowsHttpRequestException()
+ {
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ using (HttpClient client = CreateHttpClient())
+ {
+ client.Timeout = Timeout.InfiniteTimeSpan;
+
+ var cts = new CancellationTokenSource();
+ var tcs = new TaskCompletionSource<bool>();
+ Task serverTask = server.AcceptConnectionAsync(async connection =>
+ {
+ await connection.ReadRequestHeaderAndSendCustomResponseAsync("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
+ TextWriter writer = connection.Writer;
+ try
+ {
+ while (!cts.IsCancellationRequested) // infinite to make sure implementation doesn't OOM
+ {
+ await writer.WriteAsync(new string(' ', 10000));
+ await Task.Delay(1);
+ }
+ }
+ catch { }
+ });
+
+ await Assert.ThrowsAsync<HttpRequestException>(() => client.GetAsync(url));
+ cts.Cancel();
+ await serverTask;
+ }
+ });
+ }
+
+ [Fact]
+ public async Task SendAsync_TransferEncodingSetButNoRequestContent_Throws()
+ {
+ if (IsNetfxHandler)
+ {
+ // no exception thrown
+ return;
+ }
+
+ var req = new HttpRequestMessage(HttpMethod.Post, "http://bing.com");
+ req.Headers.TransferEncodingChunked = true;
+ using (HttpClient c = CreateHttpClient())
+ {
+ HttpRequestException error = await Assert.ThrowsAsync<HttpRequestException>(() => c.SendAsync(req));
+ Assert.IsType<InvalidOperationException>(error.InnerException);
+ }
+ }
[OuterLoop] // TODO: Issue #11345
[Fact]
@@ -1281,10 +1727,9 @@ namespace System.Net.Http.Functional.Tests
{
Task<HttpResponseMessage> getResponse = client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
- await LoopbackServer.AcceptSocketAsync(server, async (s, stream, reader, writer) =>
+ await server.AcceptConnectionAsync(async connection =>
{
- while (!string.IsNullOrEmpty(reader.ReadLine())) ;
- await writer.WriteAsync(
+ await connection.ReadRequestHeaderAndSendCustomResponseAsync(
"HTTP/1.1 200 OK\r\n" +
$"Date: {DateTimeOffset.UtcNow:R}\r\n" +
"Content-Length: 16000\r\n" +
@@ -1301,59 +1746,282 @@ namespace System.Net.Http.Functional.Tests
Assert.True(bytesRead < buffer.Length, "bytesRead should be less than buffer.Length");
}
}
-
- return null;
});
}
});
}
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ [InlineData(null)]
+ public async Task ReadAsStreamAsync_HandlerProducesWellBehavedResponseStream(bool? chunked)
+ {
+ await LoopbackServer.CreateClientAndServerAsync(async uri =>
+ {
+ var request = new HttpRequestMessage(HttpMethod.Get, uri);
+ using (var client = new HttpMessageInvoker(CreateHttpClientHandler()))
+ using (HttpResponseMessage response = await client.SendAsync(request, CancellationToken.None))
+ {
+ using (Stream responseStream = await response.Content.ReadAsStreamAsync())
+ {
+ Assert.Same(responseStream, await response.Content.ReadAsStreamAsync());
+
+ // Boolean properties returning correct values
+ Assert.True(responseStream.CanRead);
+ Assert.False(responseStream.CanWrite);
+ Assert.False(responseStream.CanSeek);
+
+ // Not supported operations
+ Assert.Throws<NotSupportedException>(() => responseStream.BeginWrite(new byte[1], 0, 1, null, null));
+ Assert.Throws<NotSupportedException>(() => responseStream.Length);
+ Assert.Throws<NotSupportedException>(() => responseStream.Position);
+ Assert.Throws<NotSupportedException>(() => responseStream.Position = 0);
+ Assert.Throws<NotSupportedException>(() => responseStream.Seek(0, SeekOrigin.Begin));
+ Assert.Throws<NotSupportedException>(() => responseStream.SetLength(0));
+ Assert.Throws<NotSupportedException>(() => responseStream.Write(new byte[1], 0, 1));
+ Assert.Throws<NotSupportedException>(() => responseStream.Write(new Span<byte>(new byte[1])));
+ Assert.Throws<NotSupportedException>(() => { responseStream.WriteAsync(new Memory<byte>(new byte[1])); });
+ Assert.Throws<NotSupportedException>(() => { responseStream.WriteAsync(new byte[1], 0, 1); });
+ Assert.Throws<NotSupportedException>(() => responseStream.WriteByte(1));
+
+ // Invalid arguments
+ var nonWritableStream = new MemoryStream(new byte[1], false);
+ var disposedStream = new MemoryStream();
+ disposedStream.Dispose();
+ Assert.Throws<ArgumentNullException>(() => responseStream.CopyTo(null));
+ Assert.Throws<ArgumentOutOfRangeException>(() => responseStream.CopyTo(Stream.Null, 0));
+ Assert.Throws<ArgumentNullException>(() => { responseStream.CopyToAsync(null, 100, default); });
+ Assert.Throws<ArgumentOutOfRangeException>(() => { responseStream.CopyToAsync(Stream.Null, 0, default); });
+ Assert.Throws<ArgumentOutOfRangeException>(() => { responseStream.CopyToAsync(Stream.Null, -1, default); });
+ Assert.Throws<NotSupportedException>(() => { responseStream.CopyToAsync(nonWritableStream, 100, default); });
+ Assert.Throws<ObjectDisposedException>(() => { responseStream.CopyToAsync(disposedStream, 100, default); });
+ Assert.Throws<ArgumentNullException>(() => responseStream.Read(null, 0, 100));
+ Assert.Throws<ArgumentOutOfRangeException>(() => responseStream.Read(new byte[1], -1, 1));
+ Assert.ThrowsAny<ArgumentException>(() => responseStream.Read(new byte[1], 2, 1));
+ Assert.Throws<ArgumentOutOfRangeException>(() => responseStream.Read(new byte[1], 0, -1));
+ Assert.ThrowsAny<ArgumentException>(() => responseStream.Read(new byte[1], 0, 2));
+ Assert.Throws<ArgumentNullException>(() => responseStream.BeginRead(null, 0, 100, null, null));
+ Assert.Throws<ArgumentOutOfRangeException>(() => responseStream.BeginRead(new byte[1], -1, 1, null, null));
+ Assert.ThrowsAny<ArgumentException>(() => responseStream.BeginRead(new byte[1], 2, 1, null, null));
+ Assert.Throws<ArgumentOutOfRangeException>(() => responseStream.BeginRead(new byte[1], 0, -1, null, null));
+ Assert.ThrowsAny<ArgumentException>(() => responseStream.BeginRead(new byte[1], 0, 2, null, null));
+ Assert.Throws<ArgumentNullException>(() => responseStream.EndRead(null));
+ if (IsNetfxHandler)
+ {
+ // Argument exceptions on netfx are thrown out of these asynchronously rather than synchronously
+ await Assert.ThrowsAsync<ArgumentNullException>(() => responseStream.ReadAsync(null, 0, 100, default));
+ await Assert.ThrowsAsync<ArgumentOutOfRangeException>(() => responseStream.ReadAsync(new byte[1], -1, 1, default));
+ await Assert.ThrowsAsync<ArgumentOutOfRangeException>(() => responseStream.ReadAsync(new byte[1], 2, 1, default));
+ await Assert.ThrowsAsync<ArgumentOutOfRangeException>(() => responseStream.ReadAsync(new byte[1], 0, -1, default));
+ await Assert.ThrowsAsync<ArgumentOutOfRangeException>(() => responseStream.ReadAsync(new byte[1], 0, 2, default));
+ }
+ else
+ {
+ Assert.Throws<ArgumentNullException>(() => { responseStream.ReadAsync(null, 0, 100, default); });
+ Assert.Throws<ArgumentOutOfRangeException>(() => { responseStream.ReadAsync(new byte[1], -1, 1, default); });
+ Assert.ThrowsAny<ArgumentException>(() => { responseStream.ReadAsync(new byte[1], 2, 1, default); });
+ Assert.Throws<ArgumentOutOfRangeException>(() => { responseStream.ReadAsync(new byte[1], 0, -1, default); });
+ Assert.ThrowsAny<ArgumentException>(() => { responseStream.ReadAsync(new byte[1], 0, 2, default); });
+ }
+
+ // Various forms of reading
+ var buffer = new byte[1];
+
+ Assert.Equal('h', responseStream.ReadByte());
+
+ Assert.Equal(1, await Task.Factory.FromAsync(responseStream.BeginRead, responseStream.EndRead, buffer, 0, 1, null));
+ Assert.Equal((byte)'e', buffer[0]);
+
+ Assert.Equal(1, await responseStream.ReadAsync(new Memory<byte>(buffer)));
+ Assert.Equal((byte)'l', buffer[0]);
+
+ Assert.Equal(1, await responseStream.ReadAsync(buffer, 0, 1));
+ Assert.Equal((byte)'l', buffer[0]);
+
+ Assert.Equal(1, responseStream.Read(new Span<byte>(buffer)));
+ Assert.Equal((byte)'o', buffer[0]);
+
+ Assert.Equal(1, responseStream.Read(buffer, 0, 1));
+ Assert.Equal((byte)' ', buffer[0]);
+
+ if (!IsNetfxHandler)
+ {
+ // Doing any of these 0-byte reads causes the connection to fail.
+ Assert.Equal(0, await Task.Factory.FromAsync(responseStream.BeginRead, responseStream.EndRead, Array.Empty<byte>(), 0, 0, null));
+ Assert.Equal(0, await responseStream.ReadAsync(Memory<byte>.Empty));
+ Assert.Equal(0, await responseStream.ReadAsync(Array.Empty<byte>(), 0, 0));
+ Assert.Equal(0, responseStream.Read(Span<byte>.Empty));
+ Assert.Equal(0, responseStream.Read(Array.Empty<byte>(), 0, 0));
+ }
+
+ // And copying
+ var ms = new MemoryStream();
+ await responseStream.CopyToAsync(ms);
+ Assert.Equal("world", Encoding.ASCII.GetString(ms.ToArray()));
+
+ // Read and copy again once we've exhausted all data
+ ms = new MemoryStream();
+ await responseStream.CopyToAsync(ms);
+ responseStream.CopyTo(ms);
+ Assert.Equal(0, ms.Length);
+ Assert.Equal(-1, responseStream.ReadByte());
+ Assert.Equal(0, responseStream.Read(buffer, 0, 1));
+ Assert.Equal(0, responseStream.Read(new Span<byte>(buffer)));
+ Assert.Equal(0, await responseStream.ReadAsync(buffer, 0, 1));
+ Assert.Equal(0, await responseStream.ReadAsync(new Memory<byte>(buffer)));
+ Assert.Equal(0, await Task.Factory.FromAsync(responseStream.BeginRead, responseStream.EndRead, buffer, 0, 1, null));
+ }
+ }
+ }, async server =>
+ {
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ await connection.ReadRequestHeaderAsync();
+ await connection.Writer.WriteAsync("HTTP/1.1 200 OK\r\n");
+ switch (chunked)
+ {
+ case true:
+ await connection.Writer.WriteAsync("Transfer-Encoding: chunked\r\n\r\n3\r\nhel\r\n8\r\nlo world\r\n0\r\n\r\n");
+ break;
+
+ case false:
+ await connection.Writer.WriteAsync("Content-Length: 11\r\n\r\nhello world");
+ break;
+
+ case null:
+ await connection.Writer.WriteAsync("\r\nhello world");
+ break;
+ }
+ });
+ });
+ }
+
+ [Fact]
+ public async Task ReadAsStreamAsync_EmptyResponseBody_HandlerProducesWellBehavedResponseStream()
+ {
+ await LoopbackServer.CreateClientAndServerAsync(async uri =>
+ {
+ using (var client = new HttpMessageInvoker(CreateHttpClientHandler()))
+ {
+ var request = new HttpRequestMessage(HttpMethod.Get, uri);
+
+ using (HttpResponseMessage response = await client.SendAsync(request, CancellationToken.None))
+ using (Stream responseStream = await response.Content.ReadAsStreamAsync())
+ {
+ // Boolean properties returning correct values
+ Assert.True(responseStream.CanRead);
+ Assert.False(responseStream.CanWrite);
+ Assert.False(responseStream.CanSeek);
+
+ // Not supported operations
+ Assert.Throws<NotSupportedException>(() => responseStream.BeginWrite(new byte[1], 0, 1, null, null));
+ Assert.Throws<NotSupportedException>(() => responseStream.Length);
+ Assert.Throws<NotSupportedException>(() => responseStream.Position);
+ Assert.Throws<NotSupportedException>(() => responseStream.Position = 0);
+ Assert.Throws<NotSupportedException>(() => responseStream.Seek(0, SeekOrigin.Begin));
+ Assert.Throws<NotSupportedException>(() => responseStream.SetLength(0));
+ Assert.Throws<NotSupportedException>(() => responseStream.Write(new byte[1], 0, 1));
+ Assert.Throws<NotSupportedException>(() => responseStream.Write(new Span<byte>(new byte[1])));
+ await Assert.ThrowsAsync<NotSupportedException>(async () => await responseStream.WriteAsync(new Memory<byte>(new byte[1])));
+ await Assert.ThrowsAsync<NotSupportedException>(async () => await responseStream.WriteAsync(new byte[1], 0, 1));
+ Assert.Throws<NotSupportedException>(() => responseStream.WriteByte(1));
+
+ // Invalid arguments
+ var nonWritableStream = new MemoryStream(new byte[1], false);
+ var disposedStream = new MemoryStream();
+ disposedStream.Dispose();
+ Assert.Throws<ArgumentNullException>(() => responseStream.CopyTo(null));
+ Assert.Throws<ArgumentOutOfRangeException>(() => responseStream.CopyTo(Stream.Null, 0));
+ Assert.Throws<ArgumentNullException>(() => { responseStream.CopyToAsync(null, 100, default); });
+ Assert.Throws<ArgumentOutOfRangeException>(() => { responseStream.CopyToAsync(Stream.Null, 0, default); });
+ Assert.Throws<ArgumentOutOfRangeException>(() => { responseStream.CopyToAsync(Stream.Null, -1, default); });
+ Assert.Throws<NotSupportedException>(() => { responseStream.CopyToAsync(nonWritableStream, 100, default); });
+ Assert.Throws<ObjectDisposedException>(() => { responseStream.CopyToAsync(disposedStream, 100, default); });
+ Assert.Throws<ArgumentNullException>(() => responseStream.Read(null, 0, 100));
+ Assert.Throws<ArgumentOutOfRangeException>(() => responseStream.Read(new byte[1], -1, 1));
+ Assert.ThrowsAny<ArgumentException>(() => responseStream.Read(new byte[1], 2, 1));
+ Assert.Throws<ArgumentOutOfRangeException>(() => responseStream.Read(new byte[1], 0, -1));
+ Assert.ThrowsAny<ArgumentException>(() => responseStream.Read(new byte[1], 0, 2));
+ Assert.Throws<ArgumentNullException>(() => responseStream.BeginRead(null, 0, 100, null, null));
+ Assert.Throws<ArgumentOutOfRangeException>(() => responseStream.BeginRead(new byte[1], -1, 1, null, null));
+ Assert.ThrowsAny<ArgumentException>(() => responseStream.BeginRead(new byte[1], 2, 1, null, null));
+ Assert.Throws<ArgumentOutOfRangeException>(() => responseStream.BeginRead(new byte[1], 0, -1, null, null));
+ Assert.ThrowsAny<ArgumentException>(() => responseStream.BeginRead(new byte[1], 0, 2, null, null));
+ Assert.Throws<ArgumentNullException>(() => responseStream.EndRead(null));
+ if (!IsNetfxHandler)
+ {
+ // The netfx handler doesn't validate these arguments.
+ Assert.Throws<ArgumentNullException>(() => { responseStream.CopyTo(null); });
+ Assert.Throws<ArgumentNullException>(() => { responseStream.CopyToAsync(null, 100, default); });
+ Assert.Throws<ArgumentNullException>(() => { responseStream.CopyToAsync(null, 100, default); });
+ Assert.Throws<ArgumentNullException>(() => { responseStream.Read(null, 0, 100); });
+ Assert.Throws<ArgumentNullException>(() => { responseStream.ReadAsync(null, 0, 100, default); });
+ Assert.Throws<ArgumentNullException>(() => { responseStream.BeginRead(null, 0, 100, null, null); });
+ }
+
+ // Empty reads
+ var buffer = new byte[1];
+ Assert.Equal(-1, responseStream.ReadByte());
+ Assert.Equal(0, await Task.Factory.FromAsync(responseStream.BeginRead, responseStream.EndRead, buffer, 0, 1, null));
+ Assert.Equal(0, await responseStream.ReadAsync(new Memory<byte>(buffer)));
+ Assert.Equal(0, await responseStream.ReadAsync(buffer, 0, 1));
+ Assert.Equal(0, responseStream.Read(new Span<byte>(buffer)));
+ Assert.Equal(0, responseStream.Read(buffer, 0, 1));
+
+ // Empty copies
+ var ms = new MemoryStream();
+ await responseStream.CopyToAsync(ms);
+ Assert.Equal(0, ms.Length);
+ responseStream.CopyTo(ms);
+ Assert.Equal(0, ms.Length);
+ }
+ }
+ },
+ server => server.AcceptConnectionSendResponseAndCloseAsync());
+ }
+
[OuterLoop] // TODO: Issue #11345
[Fact]
public async Task Dispose_DisposingHandlerCancelsActiveOperationsWithoutResponses()
{
- if (UseManagedHandler)
+ if (UseSocketsHttpHandler)
{
- // TODO #23131: The ManagedHandler isn't correctly handling disposal of the handler.
+ // TODO #23131: The SocketsHttpHandler isn't correctly handling disposal of the handler.
// It should cause the outstanding requests to be canceled with OperationCanceledExceptions,
// whereas currently it's resulting in ObjectDisposedExceptions.
return;
}
- await LoopbackServer.CreateServerAsync(async (socket1, url1) =>
+ await LoopbackServer.CreateServerAsync(async (server1, url1) =>
{
- await LoopbackServer.CreateServerAsync(async (socket2, url2) =>
+ await LoopbackServer.CreateServerAsync(async (server2, url2) =>
{
- await LoopbackServer.CreateServerAsync(async (socket3, url3) =>
+ await LoopbackServer.CreateServerAsync(async (server3, url3) =>
{
var unblockServers = new TaskCompletionSource<bool>(TaskContinuationOptions.RunContinuationsAsynchronously);
// First server connects but doesn't send any response yet
- Task server1 = LoopbackServer.AcceptSocketAsync(socket1, async (s, stream, reader, writer) =>
+ Task serverTask1 = server1.AcceptConnectionAsync(async connection1 =>
{
await unblockServers.Task;
- return null;
});
// Second server connects and sends some but not all headers
- Task server2 = LoopbackServer.AcceptSocketAsync(socket2, async (s, stream, reader, writer) =>
+ Task serverTask2 = server2.AcceptConnectionAsync(async connection2 =>
{
- while (!string.IsNullOrEmpty(await reader.ReadLineAsync())) ;
- await writer.WriteAsync($"HTTP/1.1 200 OK\r\n");
+ await connection2.ReadRequestHeaderAndSendCustomResponseAsync($"HTTP/1.1 200 OK\r\n");
await unblockServers.Task;
- return null;
});
// Third server connects and sends all headers and some but not all of the body
- Task server3 = LoopbackServer.AcceptSocketAsync(socket3, async (s, stream, reader, writer) =>
+ Task serverTask3 = server3.AcceptConnectionAsync(async connection3 =>
{
- while (!string.IsNullOrEmpty(await reader.ReadLineAsync())) ;
- await writer.WriteAsync($"HTTP/1.1 200 OK\r\nDate: {DateTimeOffset.UtcNow:R}\r\nContent-Length: 20\r\n\r\n");
- await writer.WriteAsync("1234567890");
+ await connection3.ReadRequestHeaderAndSendCustomResponseAsync($"HTTP/1.1 200 OK\r\nDate: {DateTimeOffset.UtcNow:R}\r\nContent-Length: 20\r\n\r\n");
+ await connection3.Writer.WriteAsync("1234567890");
await unblockServers.Task;
- await writer.WriteAsync("1234567890");
- s.Shutdown(SocketShutdown.Send);
- return null;
+ await connection3.Writer.WriteAsync("1234567890");
+ connection3.Socket.Shutdown(SocketShutdown.Send);
});
// Make three requests
@@ -1367,8 +2035,8 @@ namespace System.Net.Http.Functional.Tests
} // Dispose the handler while requests are still outstanding
// Requests 1 and 2 should be canceled as we haven't finished receiving their headers
- await Assert.ThrowsAnyAsync<OperationCanceledException>(() => get1);
- await Assert.ThrowsAnyAsync<OperationCanceledException>(() => get2);
+ await Assert.ThrowsAsync<TaskCanceledException>(() => get1);
+ await Assert.ThrowsAsync<TaskCanceledException>(() => get2);
// Request 3 should still be active, and we should be able to receive all of the data.
unblockServers.SetResult(true);
@@ -1398,7 +2066,7 @@ namespace System.Net.Http.Functional.Tests
using (HttpClient client = CreateHttpClient())
{
Task<HttpResponseMessage> getResponseTask = client.GetAsync(url);
- await LoopbackServer.ReadRequestAndSendResponseAsync(server,
+ await server.AcceptConnectionSendCustomResponseAndCloseAsync(
$"HTTP/1.1 {statusCode}\r\n" +
$"Date: {DateTimeOffset.UtcNow:R}\r\n" +
"\r\n");
@@ -1638,10 +2306,13 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop] // TODO: Issue #11345
[Theory]
- [InlineData(false)]
- [InlineData(true)]
- [InlineData(null)]
- public async Task PostAsync_ExpectContinue_Success(bool? expectContinue)
+ [InlineData(false, "1.0")]
+ [InlineData(true, "1.0")]
+ [InlineData(null, "1.0")]
+ [InlineData(false, "1.1")]
+ [InlineData(true, "1.1")]
+ [InlineData(null, "1.1")]
+ public async Task PostAsync_ExpectContinue_Success(bool? expectContinue, string version)
{
using (HttpClient client = CreateHttpClient())
{
@@ -1650,14 +2321,15 @@ namespace System.Net.Http.Functional.Tests
Content = new StringContent("Test String", Encoding.UTF8)
};
req.Headers.ExpectContinue = expectContinue;
+ req.Version = new Version(version);
using (HttpResponseMessage response = await client.SendAsync(req))
{
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
- if (UseManagedHandler)
+ if (UseSocketsHttpHandler)
{
const string ExpectedReqHeader = "\"Expect\": \"100-continue\"";
- if (expectContinue == true)
+ if (expectContinue == true && version == "1.1")
{
Assert.Contains(ExpectedReqHeader, await response.Content.ReadAsStringAsync());
}
@@ -1670,6 +2342,43 @@ namespace System.Net.Http.Functional.Tests
}
}
+ [OuterLoop]
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task PostAsync_ThrowFromContentCopy_RequestFails(bool syncFailure)
+ {
+ await LoopbackServer.CreateServerAsync(async (server, uri) =>
+ {
+ Task responseTask = server.AcceptConnectionAsync(async connection =>
+ {
+ var buffer = new byte[1000];
+ while (await connection.Socket.ReceiveAsync(new ArraySegment<byte>(buffer, 0, buffer.Length), SocketFlags.None) != 0);
+ });
+
+ using (var client = CreateHttpClient())
+ {
+ Exception error = new FormatException();
+ var content = new StreamContent(new DelegateStream(
+ canSeekFunc: () => true,
+ lengthFunc: () => 12345678,
+ positionGetFunc: () => 0,
+ canReadFunc: () => true,
+ readAsyncFunc: (buffer, offset, count, cancellationToken) => syncFailure ? throw error : Task.Delay(1).ContinueWith<int>(_ => throw error)));
+
+ if (PlatformDetection.IsUap)
+ {
+ HttpRequestException requestException = await Assert.ThrowsAsync<HttpRequestException>(() => client.PostAsync(uri, content));
+ Assert.Same(error, requestException.InnerException);
+ }
+ else
+ {
+ Assert.Same(error, await Assert.ThrowsAsync<FormatException>(() => client.PostAsync(uri, content)));
+ }
+ }
+ });
+ }
+
[OuterLoop] // TODO: Issue #11345
[Theory]
[InlineData(false)]
@@ -1694,6 +2403,7 @@ namespace System.Net.Http.Functional.Tests
}
}
+ [ActiveIssue(23768)]
[ActiveIssue(22191, TargetFrameworkMonikers.Uap)]
[OuterLoop] // takes several seconds
[Fact]
@@ -1906,7 +2616,7 @@ namespace System.Net.Http.Functional.Tests
using (HttpResponseMessage response = await client.SendAsync(request))
{
- if (method == "TRACE" && (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || UseManagedHandler))
+ if (method == "TRACE" && (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || UseSocketsHttpHandler))
{
// .NET Framework also allows the HttpWebRequest and HttpClient APIs to send a request using 'TRACE'
// verb and a request body. The usual response from a server is "400 Bad Request".
@@ -1948,13 +2658,19 @@ namespace System.Net.Http.Functional.Tests
[Fact]
public async Task SendAsync_RequestVersionNotSpecified_ServerReceivesVersion11Request()
{
+ // SocketsHttpHandler treats 0.0 as a bad version, and throws.
+ if (UseSocketsHttpHandler)
+ {
+ return;
+ }
+
// The default value for HttpRequestMessage.Version is Version(1,1).
// So, we need to set something different (0,0), to test the "unknown" version.
Version receivedRequestVersion = await SendRequestAndGetRequestVersionAsync(new Version(0, 0));
Assert.Equal(new Version(1, 1), receivedRequestVersion);
}
- [ActiveIssue(23770, TestPlatforms.AnyUnix)]
+ [ActiveIssue(23037, TestPlatforms.AnyUnix)]
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Specifying Version(2,0) throws exception on netfx")]
[OuterLoop] // TODO: Issue #11345
[Theory]
@@ -1967,9 +2683,9 @@ namespace System.Net.Http.Functional.Tests
_output.WriteLine("Skipping test due to Windows 10 version prior to Version 1703.");
return;
}
- if (UseManagedHandler)
+ if (UseSocketsHttpHandler)
{
- // TODO #23134: The managed handler doesn't yet support HTTP/2.
+ // TODO #23134: SocketsHttpHandler doesn't yet support HTTP/2.
return;
}
@@ -2015,13 +2731,30 @@ namespace System.Net.Http.Functional.Tests
}
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Specifying Version(2,0) throws exception on netfx")]
+ [Fact]
+ public async Task SendAsync_RequestVersion20_HttpNotHttps_NoUpgradeRequest()
+ {
+ await LoopbackServer.CreateClientAndServerAsync(async uri =>
+ {
+ using (HttpClient client = CreateHttpClient())
+ {
+ (await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, uri) { Version = new Version(2, 0) })).Dispose();
+ }
+ }, async server =>
+ {
+ List<string> headers = await server.AcceptConnectionSendResponseAndCloseAsync();
+ Assert.All(headers, header => Assert.DoesNotContain("Upgrade", header, StringComparison.OrdinalIgnoreCase));
+ });
+ }
+
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Specifying Version(2,0) throws exception on netfx")]
[OuterLoop] // TODO: Issue #11345
[ConditionalTheory(nameof(IsWindows10Version1607OrGreater)), MemberData(nameof(Http2NoPushServers))]
public async Task SendAsync_RequestVersion20_ResponseVersion20(Uri server)
{
- if (UseManagedHandler)
+ if (UseSocketsHttpHandler)
{
- // TODO #23134: The managed handler doesn't yet support HTTP/2.
+ // TODO #23134: SocketsHttpHandler doesn't yet support HTTP/2.
return;
}
@@ -2052,7 +2785,7 @@ namespace System.Net.Http.Functional.Tests
using (HttpClient client = CreateHttpClient())
{
Task<HttpResponseMessage> getResponse = client.SendAsync(request);
- Task<List<string>> serverTask = LoopbackServer.ReadRequestAndSendResponseAsync(server);
+ Task<List<string>> serverTask = server.AcceptConnectionSendResponseAndCloseAsync();
await TestHelper.WhenAllCompletedOrAnyFailed(getResponse, serverTask);
List<string> receivedRequest = await serverTask;
@@ -2086,15 +2819,23 @@ namespace System.Net.Http.Functional.Tests
[SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "UAP does not support custom proxies.")]
[OuterLoop] // TODO: Issue #11345
[Theory]
- [MemberData(nameof(CredentialsForProxy))]
- public async Task Proxy_BypassFalse_GetRequestGoesThroughCustomProxy(ICredentials creds, bool wrapCredsInCache)
+ [MemberData(nameof(CredentialsForProxyRfcCompliant))]
+ public async Task Proxy_BypassFalse_GetRequestGoesThroughCustomProxy_RfcCompliant(ICredentials creds, bool wrapCredsInCache)
{
- if (UseManagedHandler)
- {
- // TODO #23135: ManagedHandler currently gets error "System.NotImplementedException : Basic auth: can't handle ':' in domain "dom:\ain""
- return;
- }
+ await Proxy_BypassFalse_GetRequestGoesThroughCustomProxy_Implementation(creds, wrapCredsInCache);
+ }
+ [SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "UAP does not support custom proxies.")]
+ [OuterLoop] // TODO: Issue #11345
+ [Theory]
+ [MemberData(nameof(CredentialsForProxyNonRfcCompliant))]
+ public async Task Proxy_BypassFalse_GetRequestGoesThroughCustomProxy_NonRfcCompliant(ICredentials creds, bool wrapCredsInCache)
+ {
+ await Proxy_BypassFalse_GetRequestGoesThroughCustomProxy_Implementation(creds, wrapCredsInCache);
+ }
+
+ private async Task Proxy_BypassFalse_GetRequestGoesThroughCustomProxy_Implementation(ICredentials creds, bool wrapCredsInCache)
+ {
int port;
Task<LoopbackGetRequestHttpProxy.ProxyResult> proxyTask = LoopbackGetRequestHttpProxy.StartAsync(
out port,
@@ -2179,13 +2920,123 @@ namespace System.Net.Http.Functional.Tests
}
}
+ [Fact]
+ public async Task Proxy_SslProxyUnsupported_Throws()
+ {
+ using (HttpClientHandler handler = CreateHttpClientHandler())
+ using (var client = new HttpClient(handler))
+ {
+ handler.Proxy = new WebProxy("https://" + Guid.NewGuid().ToString("N"));
+
+ Type expectedType = IsNetfxHandler || UseSocketsHttpHandler ?
+ typeof(NotSupportedException) :
+ typeof(HttpRequestException);
+
+ await Assert.ThrowsAsync(expectedType, () => client.GetAsync("http://" + Guid.NewGuid().ToString("N")));
+ }
+ }
+
+ [SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "UAP does not support custom proxies.")]
+ [Fact]
+ public async Task Proxy_UseSecureProxyTunnel_Success()
+ {
+ if (IsWinHttpHandler || IsNetfxHandler || IsCurlHandler)
+ {
+ // Issue #27746: WinHttpHandler and netfx hang on this test.
+ // The same happens consistently on macOS 10.13 Release and with some
+ // frequency on some Linux flavors, disabling the test for curl handler due to that.
+ return;
+ }
+
+ LoopbackServer.Options options = new LoopbackServer.Options { UseSsl = true };
+
+ var listener = new TcpListener(IPAddress.Loopback, 0);
+ listener.Start();
+ var ep = (IPEndPoint)listener.Server.LocalEndPoint;
+ Uri proxyUrl = new Uri($"http://{ep.Address}:{ep.Port}/");
+ //TODO : refactor once LoopbackGetRequestHttpProxy is merged with LoppbackServer
+ Task proxy = LoopbackGetRequestHttpProxy.StartAsync(listener, false, false);
+
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ Task serverTask = server.AcceptConnectionAsync(async connection =>
+ {
+ await connection.ReadRequestHeaderAndSendResponseAsync(content: "OK\r\n");
+ });
+
+ using (HttpClientHandler handler = CreateHttpClientHandler()){
+ // Point handler at out loopback proxy
+ handler.Proxy = new UseSpecifiedUriWebProxy(proxyUrl, null);
+ handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;
+
+ using (HttpClient client = new HttpClient(handler))
+ {
+ HttpResponseMessage response = await client.GetAsync(url);
+ Assert.True(response.StatusCode == HttpStatusCode.OK);
+ }
+ }
+ await serverTask;
+ }, options);
+ await proxy;
+ }
+
+ [ActiveIssue(23702, TargetFrameworkMonikers.NetFramework)]
+ [ActiveIssue(20010, TargetFrameworkMonikers.Uap)]
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))]
+ public async Task ProxyAuth_Digest_Succeeds()
+ {
+ if (IsCurlHandler)
+ {
+ // Issue #27870 curl HttpHandler can only do basic auth to proxy
+ return;
+ }
+
+ const string expectedUsername = "testusername";
+ const string expectedPassword = "testpassword";
+ const string authHeader = "Proxy-Authenticate: Digest realm=\"NetCore\", nonce=\"PwOnWgAAAAAAjnbW438AAJSQi1kAAAAA\", qop=\"auth\", stale=false\r\n";
+ LoopbackServer.Options options = new LoopbackServer.Options { IsProxy = true, Username = expectedUsername, Password = expectedPassword };
+ var proxyCreds = new NetworkCredential(expectedUsername, expectedPassword);
+
+ await LoopbackServer.CreateServerAsync(async (proxyServer, proxyUrl) =>
+ {
+ using (HttpClientHandler handler = CreateHttpClientHandler())
+ using (var client = new HttpClient(handler))
+ {
+ handler.Proxy = new UseSpecifiedUriWebProxy(proxyUrl, proxyCreds);
+
+ // URL does not matter. We will get response from "proxy" code bellow.
+ Task<HttpResponseMessage> responseTask = client.GetAsync("http://notatrealserver.com/");
+
+ // Send Digest challenge.
+ await proxyServer.AcceptConnectionSendResponseAndCloseAsync(HttpStatusCode.ProxyAuthenticationRequired, authHeader);
+ // Verify user & password.
+ var task = proxyServer.AcceptConnectionPerformAuthenticationAndCloseAsync("");
+ await TestHelper.WhenAllCompletedOrAnyFailedWithTimeout(TestHelper.PassingTestTimeoutMilliseconds, task);
+
+ await TestHelper.WhenAllCompletedOrAnyFailedWithTimeout(TestHelper.PassingTestTimeoutMilliseconds, responseTask);
+ HttpResponseMessage response = responseTask.Result;
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ }
+ }, options);
+
+ }
+
private static IEnumerable<object[]> BypassedProxies()
{
yield return new object[] { null };
yield return new object[] { new UseSpecifiedUriWebProxy(new Uri($"http://{Guid.NewGuid().ToString().Substring(0, 15)}:12345"), bypass: true) };
}
- private static IEnumerable<object[]> CredentialsForProxy()
+ private static IEnumerable<object[]> CredentialsForProxyRfcCompliant()
+ {
+ foreach (bool wrapCredsInCache in new[] { true, false })
+ {
+ yield return new object[] { new NetworkCredential("username", "password"), wrapCredsInCache };
+ yield return new object[] { new NetworkCredential("username", "password", "domain"), wrapCredsInCache };
+ }
+ }
+
+ private static IEnumerable<object[]> CredentialsForProxyNonRfcCompliant()
{
yield return new object[] { null, false };
foreach (bool wrapCredsInCache in new[] { true, false })
@@ -2194,6 +3045,7 @@ namespace System.Net.Http.Functional.Tests
yield return new object[] { new NetworkCredential("username", "password", "dom:\\ain"), wrapCredsInCache };
}
}
+
#endregion
#region Uri wire transmission encoding tests
@@ -2211,7 +3063,7 @@ namespace System.Net.Http.Functional.Tests
using (HttpClient client = CreateHttpClient())
{
Task<HttpResponseMessage> getResponseTask = client.SendAsync(request);
- Task<List<string>> serverTask = LoopbackServer.ReadRequestAndSendResponseAsync(server);
+ Task<List<string>> serverTask = server.AcceptConnectionSendResponseAndCloseAsync();
await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
List<string> receivedRequest = await serverTask;
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientMiniStressTest.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientMiniStressTest.cs
index 7866a00087..6ef4370683 100644
--- a/src/System.Net.Http/tests/FunctionalTests/HttpClientMiniStressTest.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientMiniStressTest.cs
@@ -12,13 +12,9 @@ using Xunit;
namespace System.Net.Http.Functional.Tests
{
- using Configuration = System.Net.Test.Common.Configuration;
-
- public class HttpClientMiniStress : HttpClientTestBase
+ public abstract class HttpClientMiniStress : HttpClientTestBase
{
- private static bool HttpStressEnabled => Configuration.Http.StressEnabled;
-
- [ConditionalTheory(nameof(HttpStressEnabled))]
+ [ConditionalTheory(typeof(TestEnvironment), nameof(TestEnvironment.IsStressModeEnabled))]
[MemberData(nameof(GetStressOptions))]
public void SingleClient_ManyGets_Sync(int numRequests, int dop, HttpCompletionOption completionOption)
{
@@ -32,7 +28,7 @@ namespace System.Net.Http.Functional.Tests
}
}
- [ConditionalTheory(nameof(HttpStressEnabled))]
+ [ConditionalTheory(typeof(TestEnvironment), nameof(TestEnvironment.IsStressModeEnabled))]
public async Task SingleClient_ManyGets_Async(int numRequests, int dop, HttpCompletionOption completionOption)
{
string responseText = CreateResponse("abcdefghijklmnopqrstuvwxyz");
@@ -42,7 +38,7 @@ namespace System.Net.Http.Functional.Tests
}
}
- [ConditionalTheory(nameof(HttpStressEnabled))]
+ [ConditionalTheory(typeof(TestEnvironment), nameof(TestEnvironment.IsStressModeEnabled))]
[MemberData(nameof(GetStressOptions))]
public void ManyClients_ManyGets(int numRequests, int dop, HttpCompletionOption completionOption)
{
@@ -56,7 +52,7 @@ namespace System.Net.Http.Functional.Tests
});
}
- [ConditionalTheory(nameof(HttpStressEnabled))]
+ [ConditionalTheory(typeof(TestEnvironment), nameof(TestEnvironment.IsStressModeEnabled))]
[MemberData(nameof(PostStressOptions))]
public async Task ManyClients_ManyPosts_Async(int numRequests, int dop, int numBytes)
{
@@ -70,7 +66,7 @@ namespace System.Net.Http.Functional.Tests
});
}
- [ConditionalTheory(nameof(HttpStressEnabled))]
+ [ConditionalTheory(typeof(TestEnvironment), nameof(TestEnvironment.IsStressModeEnabled))]
[InlineData(1000000)]
public void CreateAndDestroyManyClients(int numClients)
{
@@ -80,7 +76,7 @@ namespace System.Net.Http.Functional.Tests
}
}
- [ConditionalTheory(nameof(HttpStressEnabled))]
+ [ConditionalTheory(typeof(TestEnvironment), nameof(TestEnvironment.IsStressModeEnabled))]
[InlineData(5000)]
public async Task MakeAndFaultManyRequests(int numRequests)
{
@@ -90,13 +86,12 @@ namespace System.Net.Http.Functional.Tests
{
client.Timeout = Timeout.InfiniteTimeSpan;
- var ep = (IPEndPoint)server.LocalEndPoint;
Task<string>[] tasks =
(from i in Enumerable.Range(0, numRequests)
- select client.GetStringAsync($"http://{ep.Address}:{ep.Port}"))
+ select client.GetStringAsync(url))
.ToArray();
- Assert.All(tasks, t =>
+ Assert.All(tasks, t =>
Assert.True(t.IsFaulted || t.Status == TaskStatus.WaitingForActivation, $"Unexpected status {t.Status}"));
server.Dispose();
@@ -123,14 +118,14 @@ namespace System.Net.Http.Functional.Tests
{
Task<HttpResponseMessage> getAsync = client.GetAsync(url, completionOption);
- LoopbackServer.AcceptSocketAsync(server, (s, stream, reader, writer) =>
+ server.AcceptConnectionAsync(connection =>
{
- while (!string.IsNullOrEmpty(reader.ReadLine())) ;
+ while (!string.IsNullOrEmpty(connection.Reader.ReadLine())) ;
- writer.Write(responseText);
- s.Shutdown(SocketShutdown.Send);
+ connection.Writer.Write(responseText);
+ connection.Socket.Shutdown(SocketShutdown.Send);
- return Task.FromResult<List<string>>(null);
+ return Task.CompletedTask;
}).GetAwaiter().GetResult();
getAsync.GetAwaiter().GetResult().Dispose();
@@ -144,14 +139,12 @@ namespace System.Net.Http.Functional.Tests
{
Task<HttpResponseMessage> getAsync = client.GetAsync(url, completionOption);
- await LoopbackServer.AcceptSocketAsync(server, async (s, stream, reader, writer) =>
+ await server.AcceptConnectionAsync(async connection =>
{
- while (!string.IsNullOrEmpty(await reader.ReadLineAsync().ConfigureAwait(false))) ;
+ while (!string.IsNullOrEmpty(await connection.Reader.ReadLineAsync().ConfigureAwait(false))) ;
- await writer.WriteAsync(responseText).ConfigureAwait(false);
- s.Shutdown(SocketShutdown.Send);
-
- return null;
+ await connection.Writer.WriteAsync(responseText).ConfigureAwait(false);
+ connection.Socket.Shutdown(SocketShutdown.Send);
});
(await getAsync.ConfigureAwait(false)).Dispose();
@@ -173,35 +166,33 @@ namespace System.Net.Http.Functional.Tests
var content = new ByteArrayContent(new byte[numBytes]);
Task<HttpResponseMessage> postAsync = client.PostAsync(url, content);
- await LoopbackServer.AcceptSocketAsync(server, async (s, stream, reader, writer) =>
+ await server.AcceptConnectionAsync(async connection =>
{
- while (!string.IsNullOrEmpty(await reader.ReadLineAsync().ConfigureAwait(false))) ;
- for (int i = 0; i < numBytes; i++) Assert.NotEqual(-1, reader.Read());
+ while (!string.IsNullOrEmpty(await connection.Reader.ReadLineAsync().ConfigureAwait(false))) ;
+ for (int i = 0; i < numBytes; i++) Assert.NotEqual(-1, connection.Reader.Read());
- await writer.WriteAsync(responseText).ConfigureAwait(false);
- s.Shutdown(SocketShutdown.Send);
-
- return null;
+ await connection.Writer.WriteAsync(responseText).ConfigureAwait(false);
+ connection.Socket.Shutdown(SocketShutdown.Send);
});
(await postAsync.ConfigureAwait(false)).Dispose();
});
}
- [ConditionalFact(nameof(HttpStressEnabled))]
+ [ConditionalFact(typeof(TestEnvironment), nameof(TestEnvironment.IsStressModeEnabled))]
public async Task UnreadResponseMessage_Collectible()
{
await LoopbackServer.CreateServerAsync(async (server, url) =>
{
using (HttpClient client = CreateHttpClient())
{
- Func<Task<WeakReference>> getAsync = async () => new WeakReference(await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead));
+ Func<Task<WeakReference>> getAsync = () => client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead).ContinueWith(t => new WeakReference(t.Result));
Task<WeakReference> wrt = getAsync();
- await LoopbackServer.AcceptSocketAsync(server, async (s, stream, reader, writer) =>
+ await server.AcceptConnectionAsync(async connection =>
{
- while (!string.IsNullOrEmpty(await reader.ReadLineAsync())) ;
- await writer.WriteAsync(CreateResponse(new string('a', 32 * 1024)));
+ while (!string.IsNullOrEmpty(await connection.Reader.ReadLineAsync())) ;
+ await connection.Writer.WriteAsync(CreateResponse(new string('a', 32 * 1024)));
WeakReference wr = wrt.GetAwaiter().GetResult();
Assert.True(SpinWait.SpinUntil(() =>
@@ -211,8 +202,6 @@ namespace System.Net.Http.Functional.Tests
GC.Collect();
return !wr.IsAlive;
}, 10 * 1000), "Response object should have been collected");
-
- return null;
});
}
});
@@ -224,7 +213,7 @@ namespace System.Net.Http.Functional.Tests
"Content-Type: text/plain\r\n" +
$"Content-Length: {asciiBody.Length}\r\n" +
"\r\n" +
- $"{asciiBody}\r\n";
+ $"{asciiBody}";
private static Task ForCountAsync(int count, int dop, Func<int, Task> bodyAsync)
{
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientTest.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientTest.cs
index b8eace674e..182af3292d 100644
--- a/src/System.Net.Http/tests/FunctionalTests/HttpClientTest.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientTest.cs
@@ -12,7 +12,7 @@ using Xunit;
namespace System.Net.Http.Functional.Tests
{
- public partial class HttpClientTest : HttpClientTestBase
+ public abstract partial class HttpClientTest : HttpClientTestBase
{
[Fact]
public void Dispose_MultipleTimes_Success()
@@ -125,12 +125,7 @@ namespace System.Net.Http.Functional.Tests
await LoopbackServer.CreateServerAsync(async (server, url) =>
{
Task<string> getTask = client.GetStringAsync(url);
- Task serverTask = LoopbackServer.ReadRequestAndSendResponseAsync(server,
- $"HTTP/1.1 200 OK\r\n" +
- $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
- $"Content-Length: {contentLength}\r\n" +
- "\r\n" +
- new string('s', contentLength));
+ Task serverTask = server.AcceptConnectionSendResponseAndCloseAsync(content: new string('s', contentLength));
Task bothTasks = TestHelper.WhenAllCompletedOrAnyFailed(getTask, serverTask);
if (exceptionExpected)
@@ -272,11 +267,11 @@ namespace System.Net.Http.Functional.Tests
cts.Cancel();
- await Assert.ThrowsAnyAsync<OperationCanceledException>(() => t1);
- await Assert.ThrowsAnyAsync<OperationCanceledException>(() => t2);
- await Assert.ThrowsAnyAsync<OperationCanceledException>(() => t3);
- await Assert.ThrowsAnyAsync<OperationCanceledException>(() => t4);
- await Assert.ThrowsAnyAsync<OperationCanceledException>(() => t5);
+ await Assert.ThrowsAsync<TaskCanceledException>(() => t1);
+ await Assert.ThrowsAsync<TaskCanceledException>(() => t2);
+ await Assert.ThrowsAsync<TaskCanceledException>(() => t3);
+ await Assert.ThrowsAsync<TaskCanceledException>(() => t4);
+ await Assert.ThrowsAsync<TaskCanceledException>(() => t5);
}
}
@@ -388,7 +383,7 @@ namespace System.Net.Http.Functional.Tests
}
Task<HttpResponseMessage>[] tasks = Enumerable.Range(0, 3).Select(_ => client.GetAsync(CreateFakeUri())).ToArray();
client.CancelPendingRequests();
- Assert.All(tasks, task => Assert.ThrowsAny<OperationCanceledException>(() => task.GetAwaiter().GetResult()));
+ Assert.All(tasks, task => Assert.Throws<TaskCanceledException>(() => task.GetAwaiter().GetResult()));
}
}
@@ -399,7 +394,7 @@ namespace System.Net.Http.Functional.Tests
{
client.Timeout = TimeSpan.FromMilliseconds(1);
Task<HttpResponseMessage>[] tasks = Enumerable.Range(0, 3).Select(_ => client.GetAsync(CreateFakeUri())).ToArray();
- Assert.All(tasks, task => Assert.ThrowsAny<OperationCanceledException>(() => task.GetAwaiter().GetResult()));
+ Assert.All(tasks, task => Assert.Throws<TaskCanceledException>(() => task.GetAwaiter().GetResult()));
}
}
@@ -417,7 +412,7 @@ namespace System.Net.Http.Functional.Tests
await Task.Delay(TimeSpan.FromSeconds(.5));
await TestHelper.WhenAllCompletedOrAnyFailed(
getTask,
- LoopbackServer.ReadRequestAndSendResponseAsync(server));
+ server.AcceptConnectionSendResponseAndCloseAsync());
});
}
}
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientTest.netcoreapp.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientTest.netcoreapp.cs
index 618bc2cb80..adbe4f18d4 100644
--- a/src/System.Net.Http/tests/FunctionalTests/HttpClientTest.netcoreapp.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientTest.netcoreapp.cs
@@ -9,7 +9,7 @@ using Xunit;
namespace System.Net.Http.Functional.Tests
{
- public partial class HttpClientTest
+ public abstract partial class HttpClientTest
{
[Fact]
public async Task PatchAsync_Canceled_Throws()
@@ -23,7 +23,7 @@ namespace System.Net.Http.Functional.Tests
cts.Cancel();
- await Assert.ThrowsAnyAsync<OperationCanceledException>(() => t1);
+ await Assert.ThrowsAsync<TaskCanceledException>(() => t1);
}
}
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientTestBase.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientTestBase.cs
index c8220d916b..5758dde86e 100644
--- a/src/System.Net.Http/tests/FunctionalTests/HttpClientTestBase.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientTestBase.cs
@@ -3,58 +3,53 @@
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
-using System.Threading;
+using System.Reflection;
namespace System.Net.Http.Functional.Tests
{
public abstract class HttpClientTestBase : RemoteExecutorTestBase
{
- private const string ManagedHandlerEnvVar = "COMPlus_UseManagedHttpClientHandler";
- private static readonly LocalDataStoreSlot s_managedHandlerSlot;
+ protected virtual bool UseSocketsHttpHandler => true;
- static HttpClientTestBase()
- {
- s_managedHandlerSlot = Thread.GetNamedDataSlot(ManagedHandlerEnvVar);
- if (s_managedHandlerSlot == null)
- {
- try
- {
- s_managedHandlerSlot = Thread.AllocateNamedDataSlot(ManagedHandlerEnvVar);
- }
- catch (ArgumentException)
- {
- s_managedHandlerSlot = Thread.GetNamedDataSlot(ManagedHandlerEnvVar);
- }
- }
- Debug.Assert(s_managedHandlerSlot != null);
- }
-
- protected virtual bool UseManagedHandler => false;
+ protected bool IsWinHttpHandler => !UseSocketsHttpHandler && PlatformDetection.IsWindows && !PlatformDetection.IsUap && !PlatformDetection.IsFullFramework;
+ protected bool IsCurlHandler => !UseSocketsHttpHandler && !PlatformDetection.IsWindows;
+ protected bool IsNetfxHandler => PlatformDetection.IsWindows && PlatformDetection.IsFullFramework;
+ protected bool IsUapHandler => PlatformDetection.IsWindows && PlatformDetection.IsUap;
protected HttpClient CreateHttpClient() => new HttpClient(CreateHttpClientHandler());
- protected HttpClientHandler CreateHttpClientHandler() => CreateHttpClientHandler(UseManagedHandler);
-
- protected static HttpClient CreateHttpClient(string useManagedHandlerBoolString) =>
- new HttpClient(CreateHttpClientHandler(useManagedHandlerBoolString));
+ protected HttpClientHandler CreateHttpClientHandler() => CreateHttpClientHandler(UseSocketsHttpHandler);
- protected static HttpClientHandler CreateHttpClientHandler(string useManagedHandlerBoolString) =>
- CreateHttpClientHandler(bool.Parse(useManagedHandlerBoolString));
+ protected static HttpClient CreateHttpClient(string useSocketsHttpHandlerBoolString) =>
+ new HttpClient(CreateHttpClientHandler(useSocketsHttpHandlerBoolString));
- protected static HttpClientHandler CreateHttpClientHandler(bool useManagedHandler) =>
- useManagedHandler ? CreateManagedHttpClientHandler() : new HttpClientHandler();
+ protected static HttpClientHandler CreateHttpClientHandler(string useSocketsHttpHandlerBoolString) =>
+ CreateHttpClientHandler(bool.Parse(useSocketsHttpHandlerBoolString));
- private static HttpClientHandler CreateManagedHttpClientHandler()
+ protected static HttpClientHandler CreateHttpClientHandler(bool useSocketsHttpHandler)
{
- try
+ if (!PlatformDetection.IsNetCore || useSocketsHttpHandler)
{
- Thread.SetData(s_managedHandlerSlot, true);
return new HttpClientHandler();
}
- finally
- {
- Thread.SetData(s_managedHandlerSlot, null);
- }
+
+ // Create platform specific handler.
+ ConstructorInfo ctor = typeof(HttpClientHandler).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(bool) }, null);
+ Debug.Assert(ctor != null, "Couldn't find test constructor on HttpClientHandler");
+
+ HttpClientHandler handler = (HttpClientHandler)ctor.Invoke(new object[] { useSocketsHttpHandler });
+ Debug.Assert(useSocketsHttpHandler == IsSocketsHttpHandler(handler), "Unexpected handler.");
+
+ return handler;
+ }
+
+ protected static bool IsSocketsHttpHandler(HttpClientHandler handler) =>
+ GetUnderlyingSocketsHttpHandler(handler) != null;
+
+ protected static object GetUnderlyingSocketsHttpHandler(HttpClientHandler handler)
+ {
+ FieldInfo field = typeof(HttpClientHandler).GetField("_socketsHttpHandler", BindingFlags.Instance | BindingFlags.NonPublic);
+ return field?.GetValue(handler);
}
}
}
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpCookieProtocolTests.cs b/src/System.Net.Http/tests/FunctionalTests/HttpCookieProtocolTests.cs
new file mode 100644
index 0000000000..19d76c8214
--- /dev/null
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpCookieProtocolTests.cs
@@ -0,0 +1,641 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Net.Test.Common;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.Net.Http.Functional.Tests
+{
+ public abstract class HttpCookieProtocolTests : HttpClientTestBase
+ {
+ private const string s_cookieName = "ABC";
+ private const string s_cookieValue = "123";
+ private const string s_expectedCookieHeaderValue = "ABC=123";
+
+ private const string s_customCookieHeaderValue = "CustomCookie=456";
+
+ private const string s_simpleContent = "Hello world!";
+
+ //
+ // Send cookie tests
+ //
+
+ private static CookieContainer CreateSingleCookieContainer(Uri uri) => CreateSingleCookieContainer(uri, s_cookieName, s_cookieValue);
+
+ private static CookieContainer CreateSingleCookieContainer(Uri uri, string cookieName, string cookieValue)
+ {
+ var container = new CookieContainer();
+ container.Add(uri, new Cookie(cookieName, cookieValue));
+ return container;
+ }
+
+ private static string GetCookieHeaderValue(string cookieName, string cookieValue) => $"{cookieName}={cookieValue}";
+
+
+ [Fact]
+ public async Task GetAsync_DefaultCoookieContainer_NoCookieSent()
+ {
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ using (HttpClient client = CreateHttpClient())
+ {
+ Task<HttpResponseMessage> getResponseTask = client.GetAsync(url);
+ Task<List<string>> serverTask = server.AcceptConnectionSendResponseAndCloseAsync();
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
+
+ List<string> requestLines = await serverTask;
+
+ Assert.Equal(0, requestLines.Count(s => s.StartsWith("Cookie:")));
+ }
+ });
+ }
+
+ [Theory]
+ [MemberData(nameof(CookieNamesValuesAndUseCookies))]
+ public async Task GetAsync_SetCookieContainer_CookieSent(string cookieName, string cookieValue, bool useCookies)
+ {
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ HttpClientHandler handler = CreateHttpClientHandler();
+ handler.CookieContainer = CreateSingleCookieContainer(url, cookieName, cookieValue);
+ handler.UseCookies = useCookies;
+
+ using (HttpClient client = new HttpClient(handler))
+ {
+ Task<HttpResponseMessage> getResponseTask = client.GetAsync(url);
+ Task<List<string>> serverTask = server.AcceptConnectionSendResponseAndCloseAsync();
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
+
+ List<string> requestLines = await serverTask;
+
+ if (useCookies)
+ {
+ Assert.Contains($"Cookie: {GetCookieHeaderValue(cookieName, cookieValue)}", requestLines);
+ Assert.Equal(1, requestLines.Count(s => s.StartsWith("Cookie:")));
+ }
+ else
+ {
+ Assert.Equal(0, requestLines.Count(s => s.StartsWith("Cookie:")));
+ }
+ }
+ });
+ }
+
+ [Fact]
+ public async Task GetAsync_SetCookieContainerMultipleCookies_CookiesSent()
+ {
+ var cookies = new Cookie[]
+ {
+ new Cookie("hello", "world"),
+ new Cookie("foo", "bar"),
+ new Cookie("ABC", "123")
+ };
+
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ HttpClientHandler handler = CreateHttpClientHandler();
+
+ var cookieContainer = new CookieContainer();
+ foreach (Cookie c in cookies)
+ {
+ cookieContainer.Add(url, c);
+ }
+
+ handler.CookieContainer = cookieContainer;
+
+ using (HttpClient client = new HttpClient(handler))
+ {
+ Task<HttpResponseMessage> getResponseTask = client.GetAsync(url);
+ Task<List<string>> serverTask = server.AcceptConnectionSendResponseAndCloseAsync();
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
+
+ List<string> requestLines = await serverTask;
+
+ string expectedHeader = "Cookie: " + string.Join("; ", cookies.Select(c => $"{c.Name}={c.Value}").ToArray());
+ Assert.Contains(expectedHeader, requestLines);
+ Assert.Equal(1, requestLines.Count(s => s.StartsWith("Cookie:")));
+ }
+ });
+ }
+
+ [Fact]
+ public async Task GetAsync_AddCookieHeader_CookieHeaderSent()
+ {
+ if (IsNetfxHandler)
+ {
+ // Netfx handler does not support custom cookie header
+ return;
+ }
+
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ HttpClientHandler handler = CreateHttpClientHandler();
+ using (HttpClient client = new HttpClient(handler))
+ {
+ HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
+ requestMessage.Headers.Add("Cookie", s_customCookieHeaderValue);
+
+ Task<HttpResponseMessage> getResponseTask = client.SendAsync(requestMessage);
+ Task<List<string>> serverTask = server.AcceptConnectionSendResponseAndCloseAsync();
+
+ List<string> requestLines = await serverTask;
+
+ Assert.Contains($"Cookie: {s_customCookieHeaderValue}", requestLines);
+ Assert.Equal(1, requestLines.Count(s => s.StartsWith("Cookie:")));
+ }
+ });
+ }
+
+ [Fact]
+ public async Task GetAsync_AddMultipleCookieHeaders_CookiesSent()
+ {
+ if (IsNetfxHandler)
+ {
+ // Netfx handler does not support custom cookie header
+ return;
+ }
+
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ HttpClientHandler handler = CreateHttpClientHandler();
+ using (HttpClient client = new HttpClient(handler))
+ {
+ HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
+ requestMessage.Headers.Add("Cookie", "A=1");
+ requestMessage.Headers.Add("Cookie", "B=2");
+ requestMessage.Headers.Add("Cookie", "C=3");
+
+ Task<HttpResponseMessage> getResponseTask = client.SendAsync(requestMessage);
+ Task<List<string>> serverTask = server.AcceptConnectionSendResponseAndCloseAsync();
+
+ List<string> requestLines = await serverTask;
+
+ Assert.Equal(1, requestLines.Count(s => s.StartsWith("Cookie: ")));
+
+ // Multiple Cookie header values are treated as any other header values and are
+ // concatenated using ", " as the separator.
+
+ var cookieValues = requestLines.Single(s => s.StartsWith("Cookie: ")).Substring(8).Split(new string[] { ", " }, StringSplitOptions.None);
+ Assert.Contains("A=1", cookieValues);
+ Assert.Contains("B=2", cookieValues);
+ Assert.Contains("C=3", cookieValues);
+ Assert.Equal(3, cookieValues.Count());
+ }
+ });
+ }
+
+ [Fact]
+ public async Task GetAsync_SetCookieContainerAndCookieHeader_BothCookiesSent()
+ {
+ if (IsNetfxHandler)
+ {
+ // Netfx handler does not support custom cookie header
+ return;
+ }
+
+ if (IsCurlHandler)
+ {
+ // Issue #26983
+ // CurlHandler ignores container cookies when custom Cookie header is set.
+ return;
+ }
+
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ HttpClientHandler handler = CreateHttpClientHandler();
+ handler.CookieContainer = CreateSingleCookieContainer(url);
+
+ using (HttpClient client = new HttpClient(handler))
+ {
+ HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
+ requestMessage.Headers.Add("Cookie", s_customCookieHeaderValue);
+
+ Task<HttpResponseMessage> getResponseTask = client.SendAsync(requestMessage);
+ Task<List<string>> serverTask = server.AcceptConnectionSendResponseAndCloseAsync();
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
+
+ List<string> requestLines = await serverTask;
+
+ Assert.Equal(1, requestLines.Count(s => s.StartsWith("Cookie: ")));
+
+ var cookies = requestLines.Single(s => s.StartsWith("Cookie: ")).Substring(8).Split(new string[] { "; " }, StringSplitOptions.None);
+ Assert.Contains(s_expectedCookieHeaderValue, cookies);
+ Assert.Contains(s_customCookieHeaderValue, cookies);
+ Assert.Equal(2, cookies.Count());
+ }
+ });
+ }
+
+ [Fact]
+ public async Task GetAsync_SetCookieContainerAndMultipleCookieHeaders_BothCookiesSent()
+ {
+ if (IsNetfxHandler)
+ {
+ // Netfx handler does not support custom cookie header
+ return;
+ }
+
+ if (IsCurlHandler)
+ {
+ // Issue #26983
+ // CurlHandler ignores container cookies when custom Cookie header is set.
+ return;
+ }
+
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ HttpClientHandler handler = CreateHttpClientHandler();
+ handler.CookieContainer = CreateSingleCookieContainer(url);
+
+ using (HttpClient client = new HttpClient(handler))
+ {
+ HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
+ requestMessage.Headers.Add("Cookie", "A=1");
+ requestMessage.Headers.Add("Cookie", "B=2");
+
+ Task<HttpResponseMessage> getResponseTask = client.SendAsync(requestMessage);
+ Task<List<string>> serverTask = server.AcceptConnectionSendResponseAndCloseAsync();
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
+
+ List<string> requestLines = await serverTask;
+
+ Assert.Equal(1, requestLines.Count(s => s.StartsWith("Cookie: ")));
+
+ // Multiple Cookie header values are treated as any other header values and are
+ // concatenated using ", " as the separator. The container cookie is concatenated to
+ // one of these values using the "; " cookie separator.
+
+ var cookieValues = requestLines.Single(s => s.StartsWith("Cookie: ")).Substring(8).Split(new string[] { ", " }, StringSplitOptions.None);
+ Assert.Equal(2, cookieValues.Count());
+
+ // Find container cookie and remove it so we can validate the rest of the cookie header values
+ bool sawContainerCookie = false;
+ for (int i = 0; i < cookieValues.Length; i++)
+ {
+ if (cookieValues[i].Contains(';'))
+ {
+ Assert.False(sawContainerCookie);
+
+ var cookies = cookieValues[i].Split(new string[] { "; " }, StringSplitOptions.None);
+ Assert.Equal(2, cookies.Count());
+ Assert.Contains(s_expectedCookieHeaderValue, cookies);
+
+ sawContainerCookie = true;
+ cookieValues[i] = cookies.Where(c => c != s_expectedCookieHeaderValue).Single();
+ }
+ }
+
+ Assert.Contains("A=1", cookieValues);
+ Assert.Contains("B=2", cookieValues);
+ }
+ });
+ }
+
+ [Fact]
+ public async Task GetAsyncWithRedirect_SetCookieContainer_CorrectCookiesSent()
+ {
+ const string path1 = "/foo";
+ const string path2 = "/bar";
+
+ await LoopbackServer.CreateClientAndServerAsync(async url =>
+ {
+ Uri url1 = new Uri(url, path1);
+ Uri url2 = new Uri(url, path2);
+ Uri unusedUrl = new Uri(url, "/unused");
+
+ HttpClientHandler handler = CreateHttpClientHandler();
+ handler.CookieContainer = new CookieContainer();
+ handler.CookieContainer.Add(url1, new Cookie("cookie1", "value1"));
+ handler.CookieContainer.Add(url2, new Cookie("cookie2", "value2"));
+ handler.CookieContainer.Add(unusedUrl, new Cookie("cookie3", "value3"));
+
+ using (HttpClient client = new HttpClient(handler))
+ {
+ client.DefaultRequestHeaders.ConnectionClose = true; // to avoid issues with connection pooling
+ await client.GetAsync(url1);
+ }
+ },
+ async server =>
+ {
+ List<string> request1Lines = await server.AcceptConnectionSendResponseAndCloseAsync(HttpStatusCode.Found, $"Location: {path2}\r\n");
+
+ Assert.Contains($"Cookie: cookie1=value1", request1Lines);
+ Assert.Equal(1, request1Lines.Count(s => s.StartsWith("Cookie:")));
+
+ List<string> request2Lines = await server.AcceptConnectionSendResponseAndCloseAsync(content: s_simpleContent);
+
+ Assert.Contains($"Cookie: cookie2=value2", request2Lines);
+ Assert.Equal(1, request2Lines.Count(s => s.StartsWith("Cookie:")));
+ });
+ }
+
+ //
+ // Receive cookie tests
+ //
+
+ [Theory]
+ [MemberData(nameof(CookieNamesValuesAndUseCookies))]
+ public async Task GetAsync_ReceiveSetCookieHeader_CookieAdded(string cookieName, string cookieValue, bool useCookies)
+ {
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ HttpClientHandler handler = CreateHttpClientHandler();
+ handler.UseCookies = useCookies;
+
+ using (HttpClient client = new HttpClient(handler))
+ {
+ Task<HttpResponseMessage> getResponseTask = client.GetAsync(url);
+ Task<List<string>> serverTask = server.AcceptConnectionSendResponseAndCloseAsync(
+ HttpStatusCode.OK, $"Set-Cookie: {GetCookieHeaderValue(cookieName, cookieValue)}\r\n", s_simpleContent);
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
+
+ CookieCollection collection = handler.CookieContainer.GetCookies(url);
+
+ if (useCookies)
+ {
+ Assert.Equal(1, collection.Count);
+ Assert.Equal(cookieName, collection[0].Name);
+ Assert.Equal(cookieValue, collection[0].Value);
+ }
+ else
+ {
+ Assert.Equal(0, collection.Count);
+ }
+ }
+ });
+ }
+
+ [Fact]
+ public async Task GetAsync_ReceiveMultipleSetCookieHeaders_CookieAdded()
+ {
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ HttpClientHandler handler = CreateHttpClientHandler();
+
+ using (HttpClient client = new HttpClient(handler))
+ {
+ Task<HttpResponseMessage> getResponseTask = client.GetAsync(url);
+ Task<List<string>> serverTask = server.AcceptConnectionSendResponseAndCloseAsync(
+ HttpStatusCode.OK,
+ $"Set-Cookie: A=1; Path=/\r\n" +
+ $"Set-Cookie : B=2; Path=/\r\n" + // space before colon to verify header is trimmed and recognized
+ $"Set-Cookie: C=3; Path=/\r\n",
+ s_simpleContent);
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
+
+ CookieCollection collection = handler.CookieContainer.GetCookies(url);
+ Assert.Equal(3, collection.Count);
+
+ // Convert to array so we can more easily process contents, since CookieCollection does not implement IEnumerable<Cookie>
+ Cookie[] cookies = new Cookie[3];
+ collection.CopyTo(cookies, 0);
+
+ Assert.Contains(cookies, c => c.Name == "A" && c.Value == "1");
+ Assert.Contains(cookies, c => c.Name == "B" && c.Value == "2");
+ Assert.Contains(cookies, c => c.Name == "C" && c.Value == "3");
+ }
+ });
+ }
+
+ [Fact]
+ public async Task GetAsync_ReceiveSetCookieHeader_CookieUpdated()
+ {
+ const string newCookieValue = "789";
+
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ HttpClientHandler handler = CreateHttpClientHandler();
+ handler.CookieContainer = CreateSingleCookieContainer(url);
+
+ using (HttpClient client = new HttpClient(handler))
+ {
+ Task<HttpResponseMessage> getResponseTask = client.GetAsync(url);
+ Task<List<string>> serverTask = server.AcceptConnectionSendResponseAndCloseAsync(
+ HttpStatusCode.OK, $"Set-Cookie: {s_cookieName}={newCookieValue}\r\n", s_simpleContent);
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
+
+ CookieCollection collection = handler.CookieContainer.GetCookies(url);
+ Assert.Equal(1, collection.Count);
+ Assert.Equal(s_cookieName, collection[0].Name);
+ Assert.Equal(newCookieValue, collection[0].Value);
+ }
+ });
+ }
+
+ [Fact]
+ public async Task GetAsync_ReceiveSetCookieHeader_CookieRemoved()
+ {
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ HttpClientHandler handler = CreateHttpClientHandler();
+ handler.CookieContainer = CreateSingleCookieContainer(url);
+
+ using (HttpClient client = new HttpClient(handler))
+ {
+ Task<HttpResponseMessage> getResponseTask = client.GetAsync(url);
+ Task<List<string>> serverTask = server.AcceptConnectionSendResponseAndCloseAsync(
+ HttpStatusCode.OK, $"Set-Cookie: {s_cookieName}=; Expires=Sun, 06 Nov 1994 08:49:37 GMT\r\n", s_simpleContent);
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
+
+ CookieCollection collection = handler.CookieContainer.GetCookies(url);
+ Assert.Equal(0, collection.Count);
+ }
+ });
+ }
+
+ [Fact]
+ public async Task GetAsync_ReceiveInvalidSetCookieHeader_ValidCookiesAdded()
+ {
+ if (IsNetfxHandler)
+ {
+ // NetfxHandler incorrectly only processes one valid cookie
+ return;
+ }
+
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ HttpClientHandler handler = CreateHttpClientHandler();
+
+ using (HttpClient client = new HttpClient(handler))
+ {
+ Task<HttpResponseMessage> getResponseTask = client.GetAsync(url);
+ Task<List<string>> serverTask = server.AcceptConnectionSendResponseAndCloseAsync(
+ HttpStatusCode.OK,
+ $"Set-Cookie: A=1; Path=/;Expires=asdfsadgads\r\n" + // invalid Expires
+ $"Set-Cookie: B=2; Path=/\r\n" +
+ $"Set-Cookie: C=3; Path=/\r\n",
+ s_simpleContent);
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
+
+ CookieCollection collection = handler.CookieContainer.GetCookies(url);
+ Assert.Equal(2, collection.Count);
+
+ // Convert to array so we can more easily process contents, since CookieCollection does not implement IEnumerable<Cookie>
+ Cookie[] cookies = new Cookie[3];
+ collection.CopyTo(cookies, 0);
+
+ Assert.Contains(cookies, c => c.Name == "B" && c.Value == "2");
+ Assert.Contains(cookies, c => c.Name == "C" && c.Value == "3");
+ }
+ });
+ }
+
+ [Fact]
+ public async Task GetAsyncWithRedirect_ReceiveSetCookie_CookieSent()
+ {
+ const string path1 = "/foo";
+ const string path2 = "/bar";
+
+ await LoopbackServer.CreateClientAndServerAsync(async url =>
+ {
+ Uri url1 = new Uri(url, path1);
+
+ HttpClientHandler handler = CreateHttpClientHandler();
+
+ using (HttpClient client = new HttpClient(handler))
+ {
+ client.DefaultRequestHeaders.ConnectionClose = true; // to avoid issues with connection pooling
+ await client.GetAsync(url1);
+
+ CookieCollection collection = handler.CookieContainer.GetCookies(url);
+
+ Assert.Equal(2, collection.Count);
+
+ // Convert to array so we can more easily process contents, since CookieCollection does not implement IEnumerable<Cookie>
+ Cookie[] cookies = new Cookie[2];
+ collection.CopyTo(cookies, 0);
+
+ Assert.Contains(cookies, c => c.Name == "A" && c.Value == "1");
+ Assert.Contains(cookies, c => c.Name == "B" && c.Value == "2");
+ }
+ },
+ async server =>
+ {
+ List<string> request1Lines = await server.AcceptConnectionSendResponseAndCloseAsync(
+ HttpStatusCode.Found, $"Location: {path2}\r\nSet-Cookie: A=1; Path=/\r\n");
+
+ Assert.Equal(0, request1Lines.Count(s => s.StartsWith("Cookie:")));
+
+ List<string> request2Lines = await server.AcceptConnectionSendResponseAndCloseAsync(
+ HttpStatusCode.OK, $"Set-Cookie: B=2; Path=/\r\n", s_simpleContent);
+
+ Assert.Contains($"Cookie: A=1", request2Lines);
+ Assert.Equal(1, request2Lines.Count(s => s.StartsWith("Cookie:")));
+ });
+ }
+
+ [Fact]
+ public async Task GetAsyncWithBasicAuth_ReceiveSetCookie_CookieSent()
+ {
+ if (IsWinHttpHandler)
+ {
+ // Issue #26986
+ // WinHttpHandler does not process the cookie.
+ return;
+ }
+
+ await LoopbackServer.CreateClientAndServerAsync(async url =>
+ {
+ HttpClientHandler handler = CreateHttpClientHandler();
+ handler.Credentials = new NetworkCredential("user", "pass");
+
+ using (HttpClient client = new HttpClient(handler))
+ {
+ await client.GetAsync(url);
+
+ CookieCollection collection = handler.CookieContainer.GetCookies(url);
+
+ Assert.Equal(2, collection.Count);
+
+ // Convert to array so we can more easily process contents, since CookieCollection does not implement IEnumerable<Cookie>
+ Cookie[] cookies = new Cookie[2];
+ collection.CopyTo(cookies, 0);
+
+ Assert.Contains(cookies, c => c.Name == "A" && c.Value == "1");
+ Assert.Contains(cookies, c => c.Name == "B" && c.Value == "2");
+ }
+ },
+ async server =>
+ {
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ List<string> request1Lines = await connection.ReadRequestHeaderAndSendResponseAsync(
+ HttpStatusCode.Unauthorized,
+ $"WWW-Authenticate: Basic realm=\"WallyWorld\"\r\nSet-Cookie: A=1; Path=/\r\n");
+
+ Assert.Equal(0, request1Lines.Count(s => s.StartsWith("Cookie:")));
+
+ List<string> request2Lines = await connection.ReadRequestHeaderAndSendResponseAsync(
+ HttpStatusCode.OK,
+ $"Set-Cookie: B=2; Path=/\r\n",
+ s_simpleContent);
+
+ Assert.Contains($"Cookie: A=1", request2Lines);
+ Assert.Equal(1, request2Lines.Count(s => s.StartsWith("Cookie:")));
+ });
+ });
+ }
+
+ //
+ // MemberData stuff
+ //
+
+ private static string GenerateCookie(string name, char repeat, int overallHeaderValueLength)
+ {
+ string emptyHeaderValue = $"{name}=; Path=/";
+
+ Debug.Assert(overallHeaderValueLength > emptyHeaderValue.Length);
+
+ int valueCount = overallHeaderValueLength - emptyHeaderValue.Length;
+ return new string(repeat, valueCount);
+ }
+
+ public static IEnumerable<object[]> CookieNamesValuesAndUseCookies()
+ {
+ foreach (bool useCookies in new[] { true, false })
+ {
+ yield return new object[] { "ABC", "123", useCookies };
+ yield return new object[] { "Hello", "World", useCookies };
+ yield return new object[] { "foo", "bar", useCookies };
+
+ yield return new object[] { ".AspNetCore.Session", "RAExEmXpoCbueP_QYM", useCookies };
+
+ yield return new object[]
+ {
+ ".AspNetCore.Antiforgery.Xam7_OeLcN4",
+ "CfDJ8NGNxAt7CbdClq3UJ8_6w_4661wRQZT1aDtUOIUKshbcV4P0NdS8klCL5qGSN-PNBBV7w23G6MYpQ81t0PMmzIN4O04fqhZ0u1YPv66mixtkX3iTi291DgwT3o5kozfQhe08-RAExEmXpoCbueP_QYM",
+ useCookies
+ };
+
+ // WinHttpHandler calls WinHttpQueryHeaders to iterate through multiple Set-Cookie header values,
+ // using an initial buffer size of 128 chars. If the buffer is not large enough, WinHttpQueryHeaders
+ // returns an insufficient buffer error, allowing WinHttpHandler to try again with a larger buffer.
+ // Sometimes when WinHttpQueryHeaders fails due to insufficient buffer, it still advances the
+ // iteration index, which would cause header values to be missed if not handled correctly.
+ //
+ // In particular, WinHttpQueryHeader behaves as follows for the following header value lengths:
+ // * 0-127 chars: succeeds, index advances from 0 to 1.
+ // * 128-255 chars: fails due to insufficient buffer, index advances from 0 to 1.
+ // * 256+ chars: fails due to insufficient buffer, index stays at 0.
+ //
+ // The below overall header value lengths were chosen to exercise reading header values at these
+ // edges, to ensure WinHttpHandler does not miss multiple Set-Cookie headers.
+
+ yield return new object[] { "foo", GenerateCookie(name: "foo", repeat: 'a', overallHeaderValueLength: 126), useCookies };
+ yield return new object[] { "foo", GenerateCookie(name: "foo", repeat: 'a', overallHeaderValueLength: 127), useCookies };
+ yield return new object[] { "foo", GenerateCookie(name: "foo", repeat: 'a', overallHeaderValueLength: 128), useCookies };
+ yield return new object[] { "foo", GenerateCookie(name: "foo", repeat: 'a', overallHeaderValueLength: 129), useCookies };
+
+ yield return new object[] { "foo", GenerateCookie(name: "foo", repeat: 'a', overallHeaderValueLength: 254), useCookies };
+ yield return new object[] { "foo", GenerateCookie(name: "foo", repeat: 'a', overallHeaderValueLength: 255), useCookies };
+ yield return new object[] { "foo", GenerateCookie(name: "foo", repeat: 'a', overallHeaderValueLength: 256), useCookies };
+ yield return new object[] { "foo", GenerateCookie(name: "foo", repeat: 'a', overallHeaderValueLength: 257), useCookies };
+ }
+ }
+ }
+}
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpProtocolTests.cs b/src/System.Net.Http/tests/FunctionalTests/HttpProtocolTests.cs
index 6df3d74381..0915ddd23d 100644
--- a/src/System.Net.Http/tests/FunctionalTests/HttpProtocolTests.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpProtocolTests.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Collections.Generic;
using System.IO;
using System.Net.Test.Common;
using System.Threading;
@@ -10,9 +11,320 @@ using Xunit;
namespace System.Net.Http.Functional.Tests
{
- public class HttpProtocolTests : HttpClientTest
+ public abstract class HttpProtocolTests : HttpClientTestBase
{
protected virtual Stream GetStream(Stream s) => s;
+ protected virtual Stream GetStream_ClientDisconnectOk(Stream s) => s;
+
+ [SkipOnTargetFramework(TargetFrameworkMonikers.Uap)] // Uap does not support 1.0
+ [Fact]
+ public async Task GetAsync_RequestVersion10_Success()
+ {
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ using (HttpClient client = CreateHttpClient())
+ {
+ HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
+ request.Version = HttpVersion.Version10;
+
+ Task<HttpResponseMessage> getResponseTask = client.SendAsync(request);
+ Task<List<string>> serverTask = server.AcceptConnectionSendResponseAndCloseAsync();
+
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
+
+ var requestLines = await serverTask;
+ Assert.Equal($"GET {url.PathAndQuery} HTTP/1.0", requestLines[0]);
+ }
+ }, new LoopbackServer.Options { StreamWrapper = GetStream });
+ }
+
+ [Fact]
+ public async Task GetAsync_RequestVersion11_Success()
+ {
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ using (HttpClient client = CreateHttpClient())
+ {
+ HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
+ request.Version = HttpVersion.Version11;
+
+ Task<HttpResponseMessage> getResponseTask = client.SendAsync(request);
+ Task<List<string>> serverTask = server.AcceptConnectionSendResponseAndCloseAsync();
+
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
+
+ var requestLines = await serverTask;
+ Assert.Equal($"GET {url.PathAndQuery} HTTP/1.1", requestLines[0]);
+ }
+ }, new LoopbackServer.Options { StreamWrapper = GetStream });
+ }
+
+ [Theory]
+ [InlineData(0)]
+ [InlineData(1)]
+ [InlineData(9)]
+ public async Task GetAsync_RequestVersion0X_ThrowsOr11(int minorVersion)
+ {
+ Type exceptionType = null;
+ if (PlatformDetection.IsFullFramework)
+ {
+ exceptionType = typeof(ArgumentException);
+ }
+ else if (UseSocketsHttpHandler)
+ {
+ exceptionType = typeof(NotSupportedException);
+ }
+
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ using (HttpClient client = CreateHttpClient())
+ {
+ HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
+ request.Version = new Version(0, minorVersion);
+
+ Task<HttpResponseMessage> getResponseTask = client.SendAsync(request);
+ Task<List<string>> serverTask = server.AcceptConnectionSendResponseAndCloseAsync();
+
+ if (exceptionType == null)
+ {
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
+ var requestLines = await serverTask;
+ Assert.Equal($"GET {url.PathAndQuery} HTTP/1.1", requestLines[0]);
+ }
+ else
+ {
+ await Assert.ThrowsAsync(exceptionType, (() => TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask)));
+ }
+ }
+ }, new LoopbackServer.Options { StreamWrapper = GetStream_ClientDisconnectOk});
+ }
+
+ [Theory]
+ [InlineData(1, 2)]
+ [InlineData(1, 6)]
+ [InlineData(2, 0)] // Note, this is plain HTTP (not HTTPS), so 2.0 is not supported and should degrade to 1.1
+ [InlineData(2, 1)]
+ [InlineData(2, 7)]
+ [InlineData(3, 0)]
+ [InlineData(4, 2)]
+ public async Task GetAsync_UnknownRequestVersion_ThrowsOrDegradesTo11(int majorVersion, int minorVersion)
+ {
+ Type exceptionType = null;
+ if (PlatformDetection.IsFullFramework)
+ {
+ exceptionType = typeof(ArgumentException);
+ }
+
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ using (HttpClient client = CreateHttpClient())
+ {
+ HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
+ request.Version = new Version(majorVersion, minorVersion);
+
+ Task<HttpResponseMessage> getResponseTask = client.SendAsync(request);
+ Task<List<string>> serverTask = server.AcceptConnectionSendResponseAndCloseAsync();
+
+ if (exceptionType == null)
+ {
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
+ var requestLines = await serverTask;
+ Assert.Equal($"GET {url.PathAndQuery} HTTP/1.1", requestLines[0]);
+ }
+ else
+ {
+ await Assert.ThrowsAsync(exceptionType, (() => TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask)));
+ }
+ }
+ }, new LoopbackServer.Options { StreamWrapper = GetStream_ClientDisconnectOk });
+ }
+
+ [Theory]
+ [InlineData(0)]
+ [InlineData(1)]
+ public async Task GetAsync_ResponseVersion10or11_Success(int responseMinorVersion)
+ {
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ using (HttpClient client = CreateHttpClient())
+ {
+ HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
+ request.Version = HttpVersion.Version11;
+
+ Task<HttpResponseMessage> getResponseTask = client.SendAsync(request);
+ Task<List<string>> serverTask =
+ server.AcceptConnectionSendCustomResponseAndCloseAsync(
+ $"HTTP/1.{responseMinorVersion} 200 OK\r\nDate: {DateTimeOffset.UtcNow:R}\r\nContent-Length: 0\r\n\r\n");
+
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
+
+ using (HttpResponseMessage response = await getResponseTask)
+ {
+ Assert.Equal(1, response.Version.Major);
+ Assert.Equal(responseMinorVersion, response.Version.Minor);
+ }
+ }
+ }, new LoopbackServer.Options { StreamWrapper = GetStream });
+ }
+
+ [Theory]
+ [InlineData(2)]
+ [InlineData(7)]
+ public async Task GetAsync_ResponseUnknownVersion1X_Success(int responseMinorVersion)
+ {
+ bool reportAs11 = PlatformDetection.IsFullFramework;
+ bool reportAs00 = !UseSocketsHttpHandler;
+
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ using (HttpClient client = CreateHttpClient())
+ {
+ HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
+ request.Version = HttpVersion.Version11;
+
+ Task<HttpResponseMessage> getResponseTask = client.SendAsync(request);
+ Task<List<string>> serverTask =
+ server.AcceptConnectionSendCustomResponseAndCloseAsync(
+ $"HTTP/1.{responseMinorVersion} 200 OK\r\nDate: {DateTimeOffset.UtcNow:R}\r\nContent-Length: 0\r\n\r\n");
+
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
+
+ using (HttpResponseMessage response = await getResponseTask)
+ {
+ if (reportAs11)
+ {
+ Assert.Equal(1, response.Version.Major);
+ Assert.Equal(1, response.Version.Minor);
+ }
+ else if (reportAs00)
+ {
+ Assert.Equal(0, response.Version.Major);
+ Assert.Equal(0, response.Version.Minor);
+ }
+ else
+ {
+ Assert.Equal(1, response.Version.Major);
+ Assert.Equal(responseMinorVersion, response.Version.Minor);
+ }
+ }
+ }
+ }, new LoopbackServer.Options { StreamWrapper = GetStream });
+ }
+
+ [SkipOnTargetFramework(TargetFrameworkMonikers.Uap)] // Uap ignores response version if not 1.0 or 1.1
+ [Theory]
+ [InlineData(0)]
+ [InlineData(1)]
+ [InlineData(9)]
+ public async Task GetAsync_ResponseVersion0X_ThrowsOr10(int responseMinorVersion)
+ {
+ bool reportAs10 = PlatformDetection.IsFullFramework;
+
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ using (HttpClient client = CreateHttpClient())
+ {
+ HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
+ request.Version = HttpVersion.Version11;
+
+ Task<HttpResponseMessage> getResponseTask = client.SendAsync(request);
+ Task<List<string>> serverTask =
+ server.AcceptConnectionSendCustomResponseAndCloseAsync(
+ $"HTTP/0.{responseMinorVersion} 200 OK\r\nDate: {DateTimeOffset.UtcNow:R}\r\nContent-Length: 0\r\n\r\n");
+
+ if (reportAs10)
+ {
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
+
+ using (HttpResponseMessage response = await getResponseTask)
+ {
+ Assert.Equal(1, response.Version.Major);
+ Assert.Equal(0, response.Version.Minor);
+ }
+ }
+ else
+ {
+ await Assert.ThrowsAsync<HttpRequestException>(async () => await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask));
+ }
+ }
+ }, new LoopbackServer.Options { StreamWrapper = GetStream_ClientDisconnectOk });
+ }
+
+ [SkipOnTargetFramework(TargetFrameworkMonikers.Uap)] // Uap ignores response version if not 1.0 or 1.1
+ [Theory]
+ [InlineData(2, 0)]
+ [InlineData(2, 1)]
+ [InlineData(3, 0)]
+ [InlineData(4, 2)]
+ public async Task GetAsyncVersion11_BadResponseVersion_ThrowsOr00(int responseMajorVersion, int responseMinorVersion)
+ {
+ // Full framework reports 1.0 or 1.1, depending on minor version, instead of throwing
+ bool reportAs1X = PlatformDetection.IsFullFramework;
+
+ // CurlHandler reports these as 0.0, except for 2.0 which is reported as 2.0, instead of throwing.
+ bool reportAs00 = false;
+ bool reportAs20 = false;
+ if (!PlatformDetection.IsWindows && !UseSocketsHttpHandler)
+ {
+ if (responseMajorVersion == 2 && responseMinorVersion == 0)
+ {
+ reportAs20 = true;
+ }
+ else
+ {
+ reportAs00 = true;
+ }
+ }
+
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ using (HttpClient client = CreateHttpClient())
+ {
+ HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
+ request.Version = HttpVersion.Version11;
+
+ Task<HttpResponseMessage> getResponseTask = client.SendAsync(request);
+ Task<List<string>> serverTask =
+ server.AcceptConnectionSendCustomResponseAndCloseAsync(
+ $"HTTP/{responseMajorVersion}.{responseMinorVersion} 200 OK\r\nDate: {DateTimeOffset.UtcNow:R}\r\nContent-Length: 0\r\n\r\n");
+
+ if (reportAs00)
+ {
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
+
+ using (HttpResponseMessage response = await getResponseTask)
+ {
+ Assert.Equal(0, response.Version.Major);
+ Assert.Equal(0, response.Version.Minor);
+ }
+ }
+ else if (reportAs20)
+ {
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
+
+ using (HttpResponseMessage response = await getResponseTask)
+ {
+ Assert.Equal(2, response.Version.Major);
+ Assert.Equal(0, response.Version.Minor);
+ }
+ }
+ else if (reportAs1X)
+ {
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
+
+ using (HttpResponseMessage response = await getResponseTask)
+ {
+ Assert.Equal(1, response.Version.Major);
+ Assert.Equal(responseMinorVersion == 0 ? 0 : 1, response.Version.Minor);
+ }
+ }
+ else
+ {
+ await Assert.ThrowsAsync<HttpRequestException>(async () => await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask));
+ }
+ }
+ }, new LoopbackServer.Options { StreamWrapper = GetStream_ClientDisconnectOk });
+ }
[Theory]
[InlineData("HTTP/1.1 200 OK", 200, "OK")]
@@ -27,18 +339,48 @@ namespace System.Net.Http.Functional.Tests
[InlineData("HTTP/1.1 500 Internal Server Error", 500, "Internal Server Error")]
[InlineData("HTTP/1.1 555 we just don't like you", 555, "we just don't like you")]
[InlineData("HTTP/1.1 600 still valid", 600, "still valid")]
- // TODO #24713: The following pass on Windows on .NET Core but fail on .NET Framework.
- //[InlineData("HTTP/1.1 200 ", 200, "")]
- //[InlineData("HTTP/1.1 200 Something", 200, "Something")]
- //[InlineData("HTTP/1.1\t200 OK", 200, "OK")]
- //[InlineData("HTTP/1.1 200\tOK", 200, "OK")]
- //[InlineData("HTTP/1.1 200", 200, "")]
- //[InlineData("HTTP/1.1 200\t", 200, "")]
- //[InlineData("HTTP/1.1 200 O\tK", 200, "O\tK")]
- //[InlineData("HTTP/1.1 200 O \t\t \t\t\t\t \t K", 200, "O \t\t \t\t\t\t \t K")]
- //[InlineData("HTTP/1.1 999 this\ttoo\t", 999, "this\ttoo\t")]
public async Task GetAsync_ExpectedStatusCodeAndReason_Success(string statusLine, int expectedStatusCode, string expectedReason)
{
+ if (IsWinHttpHandler)
+ {
+ return; // [ActiveIssue(25880)]
+ }
+
+ await GetAsyncSuccessHelper(statusLine, expectedStatusCode, expectedReason);
+ }
+
+ [Theory]
+ [InlineData("HTTP/1.1 200 ", 200, " ", "")]
+ [InlineData("HTTP/1.1 200 Something", 200, " Something", "Something")]
+ public async Task GetAsync_ExpectedStatusCodeAndReason_PlatformBehaviorTest(string statusLine,
+ int expectedStatusCode, string reasonWithSpace, string reasonNoSpace)
+ {
+ if (UseSocketsHttpHandler || PlatformDetection.IsFullFramework)
+ {
+ // SocketsHttpHandler and .NET Framework will keep the space characters.
+ await GetAsyncSuccessHelper(statusLine, expectedStatusCode, reasonWithSpace);
+ }
+ else
+ {
+ // WinRT, WinHttpHandler, and CurlHandler will trim space characters.
+ await GetAsyncSuccessHelper(statusLine, expectedStatusCode, reasonNoSpace);
+ }
+ }
+
+ [Theory]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "The following pass on .NET Core but fail on .NET Framework.")]
+ [InlineData("HTTP/1.1 200", 200, "")] // This test data requires the fix in .NET Framework 4.7.3
+ [InlineData("HTTP/1.1 200 O\tK", 200, "O\tK")]
+ [InlineData("HTTP/1.1 200 O \t\t \t\t\t\t \t K", 200, "O \t\t \t\t\t\t \t K")]
+ // Only CurlHandler will trim the '\t' at the end and causing failure.
+ // [InlineData("HTTP/1.1 999 this\ttoo\t", 999, "this\ttoo\t")]
+ public async Task GetAsync_StatusLineNotFollowRFC_SuccessOnCore(string statusLine, int expectedStatusCode, string expectedReason)
+ {
+ await GetAsyncSuccessHelper(statusLine, expectedStatusCode, expectedReason);
+ }
+
+ private async Task GetAsyncSuccessHelper(string statusLine, int expectedStatusCode, string expectedReason)
+ {
await LoopbackServer.CreateServerAsync(async (server, url) =>
{
using (HttpClient client = CreateHttpClient())
@@ -46,98 +388,230 @@ namespace System.Net.Http.Functional.Tests
Task<HttpResponseMessage> getResponseTask = client.GetAsync(url);
await TestHelper.WhenAllCompletedOrAnyFailed(
getResponseTask,
- LoopbackServer.ReadRequestAndSendResponseAsync(server,
+ server.AcceptConnectionSendCustomResponseAndCloseAsync(
$"{statusLine}\r\n" +
$"Date: {DateTimeOffset.UtcNow:R}\r\n" +
- "\r\n",
- new LoopbackServer.Options { ResponseStreamWrapper = GetStream }));
+ "Content-Length: 0\r\n" +
+ "\r\n"));
using (HttpResponseMessage response = await getResponseTask)
{
Assert.Equal(expectedStatusCode, (int)response.StatusCode);
Assert.Equal(expectedReason, response.ReasonPhrase);
}
}
- });
+ }, new LoopbackServer.Options { StreamWrapper = GetStream });
+ }
+
+ public static IEnumerable<string> GetInvalidStatusLine()
+ {
+ yield return "HTTP/1.1 2345";
+ yield return "HTTP/A.1 200 OK";
+ yield return "HTTP/X.Y.Z 200 OK";
+
+ // Only pass on .NET Core Windows & SocketsHttpHandler.
+ if (PlatformDetection.IsNetCore && PlatformDetection.IsWindows)
+ {
+ yield return "HTTP/0.1 200 OK";
+ yield return "HTTP/3.5 200 OK";
+ yield return "HTTP/1.12 200 OK";
+ yield return "HTTP/12.1 200 OK";
+ yield return "HTTP/1.1 200 O\rK";
+ }
+
+ // Skip these test cases on CurlHandler since the behavior is different.
+ if (PlatformDetection.IsWindows)
+ {
+ yield return "HTTP/1.A 200 OK";
+ yield return "HTTP/1.1 ";
+ yield return "HTTP/1.1 !11";
+ yield return "HTTP/1.1 a11";
+ yield return "HTTP/1.1 abc";
+ yield return "HTTP/1.1\t\t";
+ yield return "HTTP/1.1\t";
+ yield return "HTTP/1.1 ";
+ }
+
+ // Skip these test cases on UAP since the behavior is different.
+ if (!PlatformDetection.IsUap)
+ {
+ yield return "HTTP/1.1 200OK";
+ yield return "HTTP/1.1 20c";
+ yield return "HTTP/1.1 23";
+ yield return "HTTP/1.1 2bc";
+ }
+
+ // Skip these test cases on UAP & CurlHandler since the behavior is different.
+ if (!PlatformDetection.IsUap && PlatformDetection.IsWindows)
+ {
+ yield return "NOTHTTP/1.1";
+ yield return "HTTP 1.1 200 OK";
+ yield return "ABCD/1.1 200 OK";
+ yield return "HTTP/1.1";
+ yield return "HTTP\\1.1 200 OK";
+ yield return "NOTHTTP/1.1 200 OK";
+ }
}
+
+ public static TheoryData InvalidStatusLine = GetInvalidStatusLine().ToTheoryData();
[Theory]
- [InlineData("HTTP/1.1 2345")]
- [InlineData("HTTP/A.1 200 OK")]
- [InlineData("HTTP/X.Y.Z 200 OK")]
- // TODO #24713: The following pass on Windows on .NET Core but fail on .NET Framework.
- //[InlineData("HTTP/0.1 200 OK")]
- //[InlineData("HTTP/3.5 200 OK")]
- //[InlineData("HTTP/1.12 200 OK")]
- //[InlineData("HTTP/12.1 200 OK")]
- // TODO #24713: The following pass on Windows on .NET Core but fail on UWP / WinRT.
- //[InlineData("HTTP/1.1 200 O\nK")]
- //[InlineData("HTTP/1.1 200OK")]
- //[InlineData("HTTP/1.1 20c")]
- //[InlineData("HTTP/1.1 23")]
- //[InlineData("HTTP/1.1 2bc")]
- // TODO #24713: The following pass on Windows but fail on CurlHandler on Linux.
- //[InlineData("NOTHTTP/1.1")]
- //[InlineData("HTTP/1.A 200 OK")]
- //[InlineData("HTTP 1.1 200 OK")]
- //[InlineData("ABCD/1.1 200 OK")]
- //[InlineData("HTTP/1.1")]
- //[InlineData("HTTP\\1.1 200 OK")]
- //[InlineData("HTTP/1.1 ")]
- //[InlineData("HTTP/1.1 !11")]
- //[InlineData("HTTP/1.1 a11")]
- //[InlineData("HTTP/1.1 abc")]
- //[InlineData("HTTP/1.1 200 O\rK")]
- //[InlineData("HTTP/1.1\t\t")]
- //[InlineData("HTTP/1.1\t")]
- //[InlineData("HTTP/1.1 ")]
- //[InlineData("NOTHTTP/1.1 200 OK")]
+ [MemberData(nameof(InvalidStatusLine))]
public async Task GetAsync_InvalidStatusLine_ThrowsException(string responseString)
{
+ await GetAsyncThrowsExceptionHelper(responseString);
+ }
+
+ [Fact]
+ public async Task GetAsync_ReasonPhraseHasLF_BehaviorDifference()
+ {
+ string responseString = "HTTP/1.1 200 O\n";
+ int expectedStatusCode = 200;
+ string expectedReason = "O";
+
+ if (IsNetfxHandler)
+ {
+ // .NET Framework will throw HttpRequestException.
+ await GetAsyncThrowsExceptionHelper(responseString);
+ }
+ else
+ {
+ await GetAsyncSuccessHelper(responseString, expectedStatusCode, expectedReason);
+ }
+ }
+
+ [Theory]
+ [InlineData("HTTP/1.1\t200 OK")]
+ [InlineData("HTTP/1.1 200\tOK")]
+ [InlineData("HTTP/1.1 200\t")]
+ public async Task GetAsync_InvalidStatusLine_ThrowsExceptionOnSocketsHttpHandler(string responseString)
+ {
+ if (UseSocketsHttpHandler || PlatformDetection.IsFullFramework)
+ {
+ // SocketsHttpHandler and .NET Framework will throw HttpRequestException.
+ await GetAsyncThrowsExceptionHelper(responseString);
+ }
+ // WinRT, WinHttpHandler, and CurlHandler will succeed.
+ }
+
+ private async Task GetAsyncThrowsExceptionHelper(string responseString)
+ {
await LoopbackServer.CreateServerAsync(async (server, url) =>
{
using (HttpClient client = CreateHttpClient())
{
- Task ignoredServerTask = LoopbackServer.ReadRequestAndSendResponseAsync(
- server,
- responseString + "\r\nContent-Length: 0\r\n\r\n",
- new LoopbackServer.Options { ResponseStreamWrapper = GetStream });
+ Task ignoredServerTask = server.AcceptConnectionSendCustomResponseAndCloseAsync(
+ responseString + "\r\nContent-Length: 0\r\n\r\n");
await Assert.ThrowsAsync<HttpRequestException>(() => client.GetAsync(url));
}
- });
+ }, new LoopbackServer.Options { StreamWrapper = GetStream });
}
- }
- public class HttpProtocolTests_Dribble : HttpProtocolTests, IDisposable
- {
- protected override Stream GetStream(Stream s) => new DribbleStream(s);
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)] // Does not support LF-only
+ [Theory]
+ [InlineData("\r\n")]
+ [InlineData("\n")]
+ public async Task GetAsync_ResponseHasNormalLineEndings_Success(string lineEnding)
+ {
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ using (HttpClient client = CreateHttpClient())
+ {
+ Task<HttpResponseMessage> getResponseTask = client.GetAsync(url);
+ Task<List<string>> serverTask = server.AcceptConnectionSendCustomResponseAndCloseAsync(
+ $"HTTP/1.1 200 OK{lineEnding}Date: {DateTimeOffset.UtcNow:R}{lineEnding}Server: TestServer{lineEnding}Content-Length: 0{lineEnding}{lineEnding}");
+
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
- private sealed class DribbleStream : Stream
+ using (HttpResponseMessage response = await getResponseTask)
+ {
+ Assert.Equal(200, (int)response.StatusCode);
+ Assert.Equal("OK", response.ReasonPhrase);
+ Assert.Equal("TestServer", response.Headers.Server.ToString());
+ }
+ }
+ }, new LoopbackServer.Options { StreamWrapper = GetStream });
+ }
+
+ public static IEnumerable<object> GetAsync_Chunked_VaryingSizeChunks_ReceivedCorrectly_MemberData()
+ {
+ foreach (int maxChunkSize in new[] { 1, 10_000 })
+ foreach (string lineEnding in new[] { "\n", "\r\n" })
+ foreach (bool useCopyToAsync in new[] { false, true })
+ yield return new object[] { maxChunkSize, lineEnding, useCopyToAsync };
+ }
+
+ [OuterLoop]
+ [Theory]
+ [MemberData(nameof(GetAsync_Chunked_VaryingSizeChunks_ReceivedCorrectly_MemberData))]
+ public async Task GetAsync_Chunked_VaryingSizeChunks_ReceivedCorrectly(int maxChunkSize, string lineEnding, bool useCopyToAsync)
{
- private readonly Stream _wrapped;
+ if (IsWinHttpHandler)
+ {
+ // [ActiveIssue(28423)]
+ return;
+ }
- public DribbleStream(Stream wrapped) => _wrapped = wrapped;
+ if (!UseSocketsHttpHandler && lineEnding != "\r\n")
+ {
+ // Some handlers don't deal well with "\n" alone as the line ending
+ return;
+ }
- public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+ var rand = new Random(42);
+ byte[] expectedData = new byte[100_000];
+ rand.NextBytes(expectedData);
+
+ await LoopbackServer.CreateClientAndServerAsync(async uri =>
{
- for (int i = 0; i < count; i++)
+ using (HttpMessageInvoker client = new HttpMessageInvoker(CreateHttpClientHandler()))
+ using (HttpResponseMessage resp = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, uri), CancellationToken.None))
+ using (Stream respStream = await resp.Content.ReadAsStreamAsync())
{
- await _wrapped.WriteAsync(buffer, offset + i, 1);
- await Task.Yield(); // introduce short delays, enough to send packets individually but so long as to extend test duration significantly
+ var actualData = new MemoryStream();
+
+ if (useCopyToAsync)
+ {
+ await respStream.CopyToAsync(actualData);
+ }
+ else
+ {
+ byte[] buffer = new byte[4096];
+ int bytesRead;
+ while ((bytesRead = await respStream.ReadAsync(buffer)) > 0)
+ {
+ actualData.Write(buffer, 0, bytesRead);
+ }
+ }
+
+ Assert.Equal<byte>(expectedData, actualData.ToArray());
}
- }
+ }, async server =>
+ {
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ await connection.ReadRequestHeaderAsync();
- public override bool CanRead => false;
- public override bool CanSeek => false;
- public override bool CanWrite => _wrapped.CanWrite;
- public override long Length => throw new NotSupportedException();
- public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
- public override void Flush() => _wrapped.Flush();
- public override Task FlushAsync(CancellationToken cancellationToken) => _wrapped.FlushAsync(cancellationToken);
- public override int Read(byte[] buffer, int offset, int count) => throw new NotImplementedException();
- public override long Seek(long offset, SeekOrigin origin) => throw new NotImplementedException();
- public override void SetLength(long value) => throw new NotImplementedException();
- public override void Write(byte[] buffer, int offset, int count) => throw new NotImplementedException();
+ await connection.Writer.WriteAsync($"HTTP/1.1 200 OK{lineEnding}Transfer-Encoding: chunked{lineEnding}{lineEnding}");
+ for (int bytesSent = 0; bytesSent < expectedData.Length;)
+ {
+ int bytesRemaining = expectedData.Length - bytesSent;
+ int bytesToSend = rand.Next(1, Math.Min(bytesRemaining, maxChunkSize + 1));
+ await connection.Writer.WriteAsync(bytesToSend.ToString("X") + lineEnding);
+ await connection.Stream.WriteAsync(new Memory<byte>(expectedData, bytesSent, bytesToSend));
+ await connection.Writer.WriteAsync(lineEnding);
+ bytesSent += bytesToSend;
+ }
+ await connection.Writer.WriteAsync($"0{lineEnding}");
+ await connection.Writer.WriteAsync(lineEnding);
+ });
+ });
}
}
+
+ public abstract class HttpProtocolTests_Dribble : HttpProtocolTests
+ {
+ protected override Stream GetStream(Stream s) => new DribbleStream(s);
+ protected override Stream GetStream_ClientDisconnectOk(Stream s) => new DribbleStream(s, true);
+ }
}
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpRequestMessageTest.cs b/src/System.Net.Http/tests/FunctionalTests/HttpRequestMessageTest.cs
index bfc4d5042e..3261d0f76a 100644
--- a/src/System.Net.Http/tests/FunctionalTests/HttpRequestMessageTest.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpRequestMessageTest.cs
@@ -14,7 +14,7 @@ namespace System.Net.Http.Functional.Tests
{
public class HttpRequestMessageTest
{
- Version _expectedRequestMessageVersion = PlatformDetection.IsUap ? new Version(2,0) : new Version(1, 1);
+ Version _expectedRequestMessageVersion = !PlatformDetection.IsFullFramework ? new Version(2,0) : new Version(1, 1);
[Fact]
public void Ctor_Default_CorrectDefaults()
diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpRetryProtocolTests.cs b/src/System.Net.Http/tests/FunctionalTests/HttpRetryProtocolTests.cs
new file mode 100644
index 0000000000..860435de5a
--- /dev/null
+++ b/src/System.Net.Http/tests/FunctionalTests/HttpRetryProtocolTests.cs
@@ -0,0 +1,140 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.IO;
+using System.Net.Sockets;
+using System.Net.Test.Common;
+using System.Text;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.Net.Http.Functional.Tests
+{
+ public abstract class HttpRetryProtocolTests : HttpClientTestBase
+ {
+ private static readonly string s_simpleContent = "Hello World\r\n";
+
+ // Retry logic is supported by SocketsHttpHandler, CurlHandler, uap, and netfx. Only WinHttp does not support.
+ private bool IsRetrySupported => !IsWinHttpHandler;
+
+ [Fact]
+ [ActiveIssue(26770, TargetFrameworkMonikers.NetFramework)]
+ public async Task GetAsync_RetryOnConnectionClosed_Success()
+ {
+ if (!IsRetrySupported)
+ {
+ return;
+ }
+
+ await LoopbackServer.CreateClientAndServerAsync(async url =>
+ {
+ using (HttpClient client = CreateHttpClient())
+ {
+ // Send initial request and receive response so connection is established
+ HttpResponseMessage response1 = await client.GetAsync(url);
+ Assert.Equal(HttpStatusCode.OK, response1.StatusCode);
+ Assert.Equal(s_simpleContent, await response1.Content.ReadAsStringAsync());
+
+ // Send second request. Should reuse same connection.
+ // The server will close the connection, but HttpClient should retry the request.
+ HttpResponseMessage response2 = await client.GetAsync(url);
+ Assert.Equal(HttpStatusCode.OK, response1.StatusCode);
+ Assert.Equal(s_simpleContent, await response1.Content.ReadAsStringAsync());
+ }
+ },
+ async server =>
+ {
+ // Accept first connection
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ // Initial response
+ await connection.ReadRequestHeaderAndSendResponseAsync(content: s_simpleContent);
+
+ // Second response: Read request headers, then close connection
+ await connection.ReadRequestHeaderAsync();
+ });
+
+ // Client should reconnect. Accept that connection and send response.
+ await server.AcceptConnectionSendResponseAndCloseAsync(content: s_simpleContent);
+ });
+ }
+
+ [Fact]
+ public async Task PostAsyncExpect100Continue_FailsAfterContentSendStarted_Throws()
+ {
+ if (IsWinHttpHandler)
+ {
+ // WinHttpHandler does not support Expect: 100-continue.
+ return;
+ }
+
+ var contentSending = new TaskCompletionSource<bool>();
+ var connectionClosed = new TaskCompletionSource<bool>();
+
+ await LoopbackServer.CreateClientAndServerAsync(async url =>
+ {
+ using (HttpClient client = CreateHttpClient())
+ {
+ // Send initial request and receive response so connection is established
+ HttpResponseMessage response1 = await client.GetAsync(url);
+ Assert.Equal(HttpStatusCode.OK, response1.StatusCode);
+ Assert.Equal(s_simpleContent, await response1.Content.ReadAsStringAsync());
+
+ // Send second request on same connection. When the Expect: 100-continue timeout
+ // expires, the content will start to be serialized and will signal the server to
+ // close the connection; then once the connection is closed, the send will be allowed
+ // to continue and will fail.
+ var request = new HttpRequestMessage(HttpMethod.Post, url);
+ request.Headers.ExpectContinue = true;
+ request.Content = new SynchronizedSendContent(contentSending, connectionClosed.Task);
+ await Assert.ThrowsAsync<HttpRequestException>(() => client.SendAsync(request));
+ }
+ },
+ async server =>
+ {
+ // Accept connection
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ // Shut down the listen socket so no additional connections can happen
+ server.ListenSocket.Close();
+
+ // Initial response
+ await connection.ReadRequestHeaderAndSendResponseAsync(content: s_simpleContent);
+
+ // Second response: Read request headers, then close connection
+ List<string> lines = await connection.ReadRequestHeaderAsync();
+ Assert.Contains("Expect: 100-continue", lines);
+ await contentSending.Task;
+ });
+ connectionClosed.SetResult(true);
+ });
+ }
+
+ private sealed class SynchronizedSendContent : HttpContent
+ {
+ private readonly Task _connectionClosed;
+ private readonly TaskCompletionSource<bool> _sendingContent;
+
+ public SynchronizedSendContent(TaskCompletionSource<bool> sendingContent, Task connectionClosed)
+ {
+ _connectionClosed = connectionClosed;
+ _sendingContent = sendingContent;
+ }
+
+ protected override async Task SerializeToStreamAsync(Stream stream, TransportContext context)
+ {
+ _sendingContent.SetResult(true);
+ await _connectionClosed;
+ await stream.WriteAsync(Encoding.UTF8.GetBytes(s_simpleContent));
+ }
+
+ protected override bool TryComputeLength(out long length)
+ {
+ length = s_simpleContent.Length;
+ return true;
+ }
+ }
+ }
+}
diff --git a/src/System.Net.Http/tests/FunctionalTests/IdnaProtocolTests.cs b/src/System.Net.Http/tests/FunctionalTests/IdnaProtocolTests.cs
new file mode 100644
index 0000000000..505805316a
--- /dev/null
+++ b/src/System.Net.Http/tests/FunctionalTests/IdnaProtocolTests.cs
@@ -0,0 +1,133 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Net.Test.Common;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.Net.Http.Functional.Tests
+{
+ public abstract class IdnaProtocolTests : HttpClientTestBase
+ {
+ protected abstract bool SupportsIdna { get; }
+
+ [SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "UAP does not support custom proxies.")]
+ [Theory]
+ [MemberData(nameof(InternationalHostNames))]
+ public async Task InternationalUrl_UsesIdnaEncoding_Success(string hostname)
+ {
+ if (!SupportsIdna)
+ {
+ return;
+ }
+
+ Uri uri = new Uri($"http://{hostname}/");
+
+ await LoopbackServer.CreateServerAsync(async (server, serverUrl) =>
+ {
+ // We don't actually want to do DNS lookup on the IDNA host name in the URL.
+ // So instead, configure the loopback server as a proxy so we will send to it.
+ HttpClientHandler handler = CreateHttpClientHandler();
+ handler.UseProxy = true;
+ handler.Proxy = new WebProxy(serverUrl.ToString());
+
+ using (HttpClient client = new HttpClient(handler))
+ {
+ Task<HttpResponseMessage> getResponseTask = client.GetAsync(uri);
+ Task<List<string>> serverTask = server.AcceptConnectionSendResponseAndCloseAsync();
+
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
+
+ List<string> requestLines = await serverTask;
+
+ // Note since we're using a proxy, host name is included in the request line
+ Assert.Equal($"GET http://{uri.IdnHost}/ HTTP/1.1", requestLines[0]);
+ Assert.Contains($"Host: {uri.IdnHost}", requestLines);
+ }
+ });
+ }
+
+ [ActiveIssue(26355)] // We aren't doing IDNA encoding properly
+ [Theory]
+ [MemberData(nameof(InternationalHostNames))]
+ public async Task InternationalRequestHeaderValues_UsesIdnaEncoding_Success(string hostname)
+ {
+ if (!SupportsIdna)
+ {
+ return;
+ }
+
+ Uri uri = new Uri($"http://{hostname}/");
+
+ await LoopbackServer.CreateServerAsync(async (server, serverUrl) =>
+ {
+ using (HttpClient client = new HttpClient(CreateHttpClientHandler()))
+ {
+ var request = new HttpRequestMessage(HttpMethod.Get, serverUrl);
+ request.Headers.Host = hostname;
+ request.Headers.Referrer = uri;
+ Task<HttpResponseMessage> getResponseTask = client.SendAsync(request);
+ Task<List<string>> serverTask = server.AcceptConnectionSendResponseAndCloseAsync();
+
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
+
+ List<string> requestLines = await serverTask;
+
+ Assert.Contains($"Host: {uri.IdnHost}", requestLines);
+ Assert.Contains($"Referer: http://{uri.IdnHost}/", requestLines);
+ }
+ });
+ }
+
+ [ActiveIssue(26355)] // We aren't doing IDNA decoding properly
+ [Theory]
+ [MemberData(nameof(InternationalHostNames))]
+ public async Task InternationalResponseHeaderValues_UsesIdnaDecoding_Success(string hostname)
+ {
+ if (!SupportsIdna)
+ {
+ return;
+ }
+
+ Uri uri = new Uri($"http://{hostname}/");
+
+ await LoopbackServer.CreateServerAsync(async (server, serverUrl) =>
+ {
+ HttpClientHandler handler = CreateHttpClientHandler();
+ handler.AllowAutoRedirect = false;
+
+ using (HttpClient client = new HttpClient(handler))
+ {
+ Task<HttpResponseMessage> getResponseTask = client.GetAsync(serverUrl);
+ Task<List<string>> serverTask = server.AcceptConnectionSendResponseAndCloseAsync(
+ HttpStatusCode.Found, "Location: http://{uri.IdnHost}/\r\n");
+
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
+
+ HttpResponseMessage response = await getResponseTask;
+
+ Assert.Equal(uri, response.Headers.Location);
+ }
+ });
+ }
+
+ private static IEnumerable<object[]> InternationalHostNames()
+ {
+ // Latin-1 supplement
+ yield return new object[] { "\u00E1.com" };
+ yield return new object[] { "\u00E1b\u00E7d\u00EB.com" };
+ yield return new object[] { "b\u00E7.com" };
+ yield return new object[] { "b\u00E7d.com" };
+
+ // Hebrew
+ yield return new object[] { "\u05E1.com" };
+ yield return new object[] { "\u05D1\u05F1.com" };
+
+ // Katakana
+ yield return new object[] { "\u30A5.com" };
+ yield return new object[] { "\u30B6\u30C7\u30D8.com" };
+ }
+ }
+}
diff --git a/src/System.Net.Http/tests/FunctionalTests/LoopbackGetRequestHttpProxy.cs b/src/System.Net.Http/tests/FunctionalTests/LoopbackGetRequestHttpProxy.cs
index 10f99e938c..3ddee257df 100644
--- a/src/System.Net.Http/tests/FunctionalTests/LoopbackGetRequestHttpProxy.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/LoopbackGetRequestHttpProxy.cs
@@ -32,14 +32,16 @@ namespace System.Net.Http.Functional.Tests
return StartAsync(listener, requireAuth, expectCreds);
}
- private static async Task<ProxyResult> StartAsync(TcpListener listener, bool requireAuth, bool expectCreds)
+ public static async Task<ProxyResult> StartAsync(TcpListener listener, bool requireAuth, bool expectCreds)
{
ProxyResult result = new ProxyResult();
var headers = new Dictionary<string, string>();
Socket clientSocket = null;
- Stream clientStream = null;
+ NetworkStream clientStream = null;
StreamReader clientReader = null;
string url = null;
+ string method = null;
+
try
{
// Get and parse the incoming request.
@@ -55,7 +57,9 @@ namespace System.Net.Http.Functional.Tests
clientReader = new StreamReader(clientStream, Encoding.ASCII);
headers.Clear();
- url = clientReader.ReadLine().Split(' ')[1];
+ var requestTokens = clientReader.ReadLine().Split(' ');
+ method = requestTokens[0];
+ url = requestTokens[1];
string line;
while (!string.IsNullOrEmpty(line = clientReader.ReadLine()))
{
@@ -93,6 +97,44 @@ namespace System.Net.Http.Functional.Tests
result.AuthenticationHeaderValue = Encoding.UTF8.GetString(Convert.FromBase64String(authValue.Substring("Basic ".Length)));
}
+ if (method.Equals("CONNECT"))
+ {
+ String[] tokens = url.Split(':');
+ Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+ await serverSocket.ConnectAsync(tokens[0], Int32.Parse(tokens[1])).ConfigureAwait(false);
+ NetworkStream serverStream = new NetworkStream(serverSocket);
+
+ // Send response to client and relay traffic in both directions.
+ await clientSocket.SendAsync(new ArraySegment<byte>(Encoding.ASCII.GetBytes("HTTP/1.1 200 OK\r\n\r\n")),
+ SocketFlags.None).ConfigureAwait(false);
+
+ Task clientCopyTask = Task.Run(async delegate
+ {
+ byte[] buffer = new byte[8000];
+ int bytesRead;
+ while ((bytesRead = await clientStream.ReadAsync(buffer)) > 0)
+ {
+ await serverStream.WriteAsync(buffer, 0, bytesRead);
+ }
+ serverStream.Flush();
+ serverSocket.Shutdown(SocketShutdown.Send);
+ });
+ Task serverCopyTask = Task.Run(async delegate
+ {
+ byte[] buffer = new byte[8000];
+ int bytesRead;
+ while ((bytesRead = await serverStream.ReadAsync(buffer)) > 0)
+ {
+ await clientStream.WriteAsync(buffer, 0, bytesRead);
+ }
+ clientStream.Flush();
+ clientSocket.Shutdown(SocketShutdown.Send);
+ });
+ // Relay bidirectional data including close.
+ await Task.WhenAll(clientCopyTask, serverCopyTask).ConfigureAwait(false);
+ return result;
+ }
+
// Forward the request to the server.
var request = new HttpRequestMessage(HttpMethod.Get, url);
foreach (var header in headers) request.Headers.Add(header.Key, header.Value);
diff --git a/src/System.Net.Http/tests/FunctionalTests/ManagedHandlerTest.cs b/src/System.Net.Http/tests/FunctionalTests/ManagedHandlerTest.cs
deleted file mode 100644
index 3658fb78ff..0000000000
--- a/src/System.Net.Http/tests/FunctionalTests/ManagedHandlerTest.cs
+++ /dev/null
@@ -1,384 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Concurrent;
-using System.IO;
-using System.Net.Sockets;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using Xunit;
-using Xunit.Abstractions;
-
-namespace System.Net.Http.Functional.Tests
-{
- public sealed class ManagedHandler_HttpProtocolTests : HttpProtocolTests
- {
- protected override bool UseManagedHandler => true;
- }
-
- public sealed class ManagedHandler_HttpProtocolTests_Dribble : HttpProtocolTests_Dribble
- {
- protected override bool UseManagedHandler => true;
- }
-
- public sealed class ManagedHandler_HttpClientTest : HttpClientTest
- {
- protected override bool UseManagedHandler => true;
- }
-
- public sealed class ManagedHandler_DiagnosticsTest : DiagnosticsTest
- {
- protected override bool UseManagedHandler => true;
- }
-
- public sealed class ManagedHandler_HttpClientEKUTest : HttpClientEKUTest
- {
- protected override bool UseManagedHandler => true;
- }
-
- public sealed class ManagedHandler_HttpClientHandler_DangerousAcceptAllCertificatesValidator_Test : HttpClientHandler_DangerousAcceptAllCertificatesValidator_Test
- {
- protected override bool UseManagedHandler => true;
- }
-
- public sealed class ManagedHandler_HttpClientHandler_ClientCertificates_Test : HttpClientHandler_ClientCertificates_Test
- {
- public ManagedHandler_HttpClientHandler_ClientCertificates_Test(ITestOutputHelper output) : base(output) { }
- protected override bool UseManagedHandler => true;
- }
-
- public sealed class ManagedHandler_HttpClientHandler_DefaultProxyCredentials_Test : HttpClientHandler_DefaultProxyCredentials_Test
- {
- protected override bool UseManagedHandler => true;
- }
-
- public sealed class ManagedHandler_HttpClientHandler_MaxConnectionsPerServer_Test : HttpClientHandler_MaxConnectionsPerServer_Test
- {
- protected override bool UseManagedHandler => true;
- }
-
- public sealed class ManagedHandler_HttpClientHandler_ServerCertificates_Test : HttpClientHandler_ServerCertificates_Test
- {
- protected override bool UseManagedHandler => true;
- }
-
- public sealed class ManagedHandler_PostScenarioTest : PostScenarioTest
- {
- public ManagedHandler_PostScenarioTest(ITestOutputHelper output) : base(output) { }
- protected override bool UseManagedHandler => true;
- }
-
- public sealed class ManagedHandler_ResponseStreamTest : ResponseStreamTest
- {
- public ManagedHandler_ResponseStreamTest(ITestOutputHelper output) : base(output) { }
- protected override bool UseManagedHandler => true;
- }
-
- public sealed class ManagedHandler_HttpClientHandler_SslProtocols_Test : HttpClientHandler_SslProtocols_Test
- {
- protected override bool UseManagedHandler => true;
- }
-
- public sealed class ManagedHandler_SchSendAuxRecordHttpTest : SchSendAuxRecordHttpTest
- {
- public ManagedHandler_SchSendAuxRecordHttpTest(ITestOutputHelper output) : base(output) { }
- protected override bool UseManagedHandler => true;
- }
-
- public sealed class ManagedHandler_HttpClientMiniStress : HttpClientMiniStress
- {
- protected override bool UseManagedHandler => true;
- }
-
- public sealed class ManagedHandler_HttpClientHandlerTest : HttpClientHandlerTest
- {
- public ManagedHandler_HttpClientHandlerTest(ITestOutputHelper output) : base(output) { }
- protected override bool UseManagedHandler => true;
- }
-
- public sealed class ManagedHandler_DefaultCredentialsTest : DefaultCredentialsTest
- {
- public ManagedHandler_DefaultCredentialsTest(ITestOutputHelper output) : base(output) { }
- protected override bool UseManagedHandler => true;
- }
-
- // TODO #23141: Socket's don't support canceling individual operations, so ReadStream on NetworkStream
- // isn't cancelable once the operation has started. We either need to wrap the operation with one that's
- // "cancelable", meaning that the underlying operation will still be running even though we've returned "canceled",
- // or we need to just recognize that cancellation in such situations can be left up to the caller to do the
- // same thing if it's really important.
- //public sealed class ManagedHandler_CancellationTest : CancellationTest
- //{
- // public ManagedHandler_CancellationTest(ITestOutputHelper output) : base(output) { }
- // protected override bool UseManagedHandler => true;
- //}
-
- // TODO #23142: The managed handler doesn't currently track how much data was written for the response headers.
- //public sealed class ManagedHandler_HttpClientHandler_MaxResponseHeadersLength_Test : HttpClientHandler_MaxResponseHeadersLength_Test
- //{
- // protected override bool UseManagedHandler => true;
- //}
-
- public sealed class ManagedHandler_HttpClientHandler_DuplexCommunication_Test : HttpClientTestBase
- {
- protected override bool UseManagedHandler => true;
-
- [Fact]
- public async Task SendBytesBackAndForthBetweenClientAndServer_Success()
- {
- using (HttpClient client = CreateHttpClient())
- using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
- {
- listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
- listener.Listen(1);
- var ep = (IPEndPoint)listener.LocalEndPoint;
-
- var clientToServerStream = new ProducerConsumerStream();
- clientToServerStream.WriteByte(0);
-
- var reqMsg = new HttpRequestMessage
- {
- RequestUri = new Uri($"http://{ep.Address}:{ep.Port}/"),
- Content = new StreamContent(clientToServerStream),
- };
- Task<HttpResponseMessage> req = client.SendAsync(reqMsg, HttpCompletionOption.ResponseHeadersRead);
-
- using (Socket server = await listener.AcceptAsync())
- using (var serverStream = new NetworkStream(server, ownsSocket: false))
- {
- // Skip request headers.
- while (true)
- {
- if (serverStream.ReadByte() == '\r')
- {
- serverStream.ReadByte();
- break;
- }
- while (serverStream.ReadByte() != '\r') { }
- serverStream.ReadByte();
- }
-
- // Send response headers.
- await server.SendAsync(
- new ArraySegment<byte>(Encoding.ASCII.GetBytes($"HTTP/1.1 200 OK\r\nConnection: close\r\nDate: {DateTimeOffset.UtcNow:R}\r\n\r\n")),
- SocketFlags.None);
-
- HttpResponseMessage resp = await req;
- Stream serverToClientStream = await resp.Content.ReadAsStreamAsync();
-
- // Communication should now be open between the client and server.
- // Ping pong bytes back and forth.
- for (byte i = 0; i < 100; i++)
- {
- // Send a byte from the client to the server. The server will receive
- // the byte as a chunk.
- if (i > 0) clientToServerStream.WriteByte(i); // 0 was already seeded when the stream was created above
- Assert.Equal('1', serverStream.ReadByte());
- Assert.Equal('\r', serverStream.ReadByte());
- Assert.Equal('\n', serverStream.ReadByte());
- Assert.Equal(i, serverStream.ReadByte());
- Assert.Equal('\r', serverStream.ReadByte());
- Assert.Equal('\n', serverStream.ReadByte());
-
- // Send a byte from the server to the client. The client will receive
- // the byte on its own, with HttpClient stripping away the chunk encoding.
- serverStream.WriteByte(i);
- Assert.Equal(i, serverToClientStream.ReadByte());
- }
-
- clientToServerStream.DoneWriting();
- server.Shutdown(SocketShutdown.Send);
- Assert.Equal(-1, clientToServerStream.ReadByte());
- }
- }
- }
-
- private sealed class ProducerConsumerStream : Stream
- {
- private readonly BlockingCollection<byte[]> _buffers = new BlockingCollection<byte[]>();
- private ArraySegment<byte> _remaining;
-
- public override void Write(byte[] buffer, int offset, int count)
- {
- if (count > 0)
- {
- byte[] tmp = new byte[count];
- Buffer.BlockCopy(buffer, offset, tmp, 0, count);
- _buffers.Add(tmp);
- }
- }
-
- public override int Read(byte[] buffer, int offset, int count)
- {
- if (count > 0)
- {
- if (_remaining.Count == 0)
- {
- if (!_buffers.TryTake(out byte[] tmp, Timeout.Infinite))
- {
- return 0;
- }
- _remaining = new ArraySegment<byte>(tmp, 0, tmp.Length);
- }
-
- if (_remaining.Count <= count)
- {
- count = _remaining.Count;
- Buffer.BlockCopy(_remaining.Array, _remaining.Offset, buffer, offset, count);
- _remaining = default(ArraySegment<byte>);
- }
- else
- {
- Buffer.BlockCopy(_remaining.Array, _remaining.Offset, buffer, offset, count);
- _remaining = new ArraySegment<byte>(_remaining.Array, _remaining.Offset + count, _remaining.Count - count);
- }
- }
-
- return count;
- }
-
- public void DoneWriting() => _buffers.CompleteAdding();
-
- public override bool CanRead => true;
- public override bool CanSeek => false;
- public override bool CanWrite => true;
- public override long Length => throw new NotImplementedException();
- public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
- public override void Flush() { }
- public override long Seek(long offset, SeekOrigin origin) => throw new NotImplementedException();
- public override void SetLength(long value) => throw new NotImplementedException();
- }
-
- }
-
- public sealed class ManagedHandler_HttpClientHandler_ConnectionPooling_Test : HttpClientTestBase
- {
- protected override bool UseManagedHandler => true;
-
- // TODO: Currently the subsequent tests sometimes fail/hang with WinHttpHandler / CurlHandler.
- // In theory they should pass with any handler that does appropriate connection pooling.
- // We should understand why they sometimes fail there and ideally move them to be
- // used by all handlers this test project tests.
-
- [Fact]
- public async Task MultipleIterativeRequests_SameConnectionReused()
- {
- using (HttpClient client = CreateHttpClient())
- using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
- {
- listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
- listener.Listen(1);
- var ep = (IPEndPoint)listener.LocalEndPoint;
- var uri = new Uri($"http://{ep.Address}:{ep.Port}/");
-
- string responseBody =
- "HTTP/1.1 200 OK\r\n" +
- $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
- "Content-Length: 0\r\n" +
- "\r\n";
-
- Task<string> firstRequest = client.GetStringAsync(uri);
- using (Socket server = await listener.AcceptAsync())
- using (var serverStream = new NetworkStream(server, ownsSocket: false))
- using (var serverReader = new StreamReader(serverStream))
- {
- while (!string.IsNullOrWhiteSpace(await serverReader.ReadLineAsync()));
- await server.SendAsync(new ArraySegment<byte>(Encoding.ASCII.GetBytes(responseBody)), SocketFlags.None);
- await firstRequest;
-
- Task<Socket> secondAccept = listener.AcceptAsync(); // shouldn't complete
-
- Task<string> additionalRequest = client.GetStringAsync(uri);
- while (!string.IsNullOrWhiteSpace(await serverReader.ReadLineAsync()));
- await server.SendAsync(new ArraySegment<byte>(Encoding.ASCII.GetBytes(responseBody)), SocketFlags.None);
- await additionalRequest;
-
- Assert.False(secondAccept.IsCompleted, $"Second accept should never complete");
- }
- }
- }
-
- [OuterLoop("Incurs a delay")]
- [Fact]
- public async Task ServerDisconnectsAfterInitialRequest_SubsequentRequestUsesDifferentConnection()
- {
- using (HttpClient client = CreateHttpClient())
- using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
- {
- listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
- listener.Listen(100);
- var ep = (IPEndPoint)listener.LocalEndPoint;
- var uri = new Uri($"http://{ep.Address}:{ep.Port}/");
-
- string responseBody =
- "HTTP/1.1 200 OK\r\n" +
- $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
- "Content-Length: 0\r\n" +
- "\r\n";
-
- // Make multiple requests iteratively.
- for (int i = 0; i < 2; i++)
- {
- Task<string> request = client.GetStringAsync(uri);
- using (Socket server = await listener.AcceptAsync())
- using (var serverStream = new NetworkStream(server, ownsSocket: false))
- using (var serverReader = new StreamReader(serverStream))
- {
- while (!string.IsNullOrWhiteSpace(await serverReader.ReadLineAsync()));
- await server.SendAsync(new ArraySegment<byte>(Encoding.ASCII.GetBytes(responseBody)), SocketFlags.None);
- await request;
-
- server.Shutdown(SocketShutdown.Both);
- if (i == 0)
- {
- await Task.Delay(2000); // give client time to see the closing before next connect
- }
- }
- }
- }
- }
-
- [Fact]
- public async Task ServerSendsConnectionClose_SubsequentRequestUsesDifferentConnection()
- {
- using (HttpClient client = CreateHttpClient())
- using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
- {
- listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
- listener.Listen(100);
- var ep = (IPEndPoint)listener.LocalEndPoint;
- var uri = new Uri($"http://{ep.Address}:{ep.Port}/");
-
- string responseBody =
- "HTTP/1.1 200 OK\r\n" +
- $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
- "Content-Length: 0\r\n" +
- "Connection: close\r\n" +
- "\r\n";
-
- // Make multiple requests iteratively.
- Task<string> request1 = client.GetStringAsync(uri);
- using (Socket server1 = await listener.AcceptAsync())
- using (var serverStream1 = new NetworkStream(server1, ownsSocket: false))
- using (var serverReader1 = new StreamReader(serverStream1))
- {
- while (!string.IsNullOrWhiteSpace(await serverReader1.ReadLineAsync()));
- await server1.SendAsync(new ArraySegment<byte>(Encoding.ASCII.GetBytes(responseBody)), SocketFlags.None);
- await request1;
-
- Task<string> request2 = client.GetStringAsync(uri);
- using (Socket server2 = await listener.AcceptAsync())
- using (var serverStream2 = new NetworkStream(server2, ownsSocket: false))
- using (var serverReader2 = new StreamReader(serverStream2))
- {
- while (!string.IsNullOrWhiteSpace(await serverReader2.ReadLineAsync()));
- await server2.SendAsync(new ArraySegment<byte>(Encoding.ASCII.GetBytes(responseBody)), SocketFlags.None);
- await request2;
- }
- }
- }
- }
- }
-}
diff --git a/src/System.Net.Http/tests/FunctionalTests/PlatformHandlerTest.cs b/src/System.Net.Http/tests/FunctionalTests/PlatformHandlerTest.cs
new file mode 100644
index 0000000000..70dfcfae57
--- /dev/null
+++ b/src/System.Net.Http/tests/FunctionalTests/PlatformHandlerTest.cs
@@ -0,0 +1,159 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Net.Security;
+using System.Net.Sockets;
+using System.Net.Test.Common;
+using System.Reflection;
+using System.Security.Authentication;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace System.Net.Http.Functional.Tests
+{
+ public sealed class PlatformHandler_HttpProtocolTests : HttpProtocolTests
+ {
+ protected override bool UseSocketsHttpHandler => false;
+ }
+
+ public sealed class PlatformHandler_HttpProtocolTests_Dribble : HttpProtocolTests_Dribble
+ {
+ protected override bool UseSocketsHttpHandler => false;
+ }
+
+ public sealed class PlatformHandler_HttpClientTest : HttpClientTest
+ {
+ protected override bool UseSocketsHttpHandler => false;
+ }
+
+ public sealed class PlatformHandler_DiagnosticsTest : DiagnosticsTest
+ {
+ protected override bool UseSocketsHttpHandler => false;
+ }
+
+ public sealed class PlatformHandler_HttpClient_SelectedSites_Test : HttpClient_SelectedSites_Test
+ {
+ protected override bool UseSocketsHttpHandler => false;
+ }
+
+ public sealed class PlatformHandler_HttpClientEKUTest : HttpClientEKUTest
+ {
+ protected override bool UseSocketsHttpHandler => false;
+ }
+
+#if netcoreapp
+ public sealed class PlatformHandler_HttpClientHandler_DangerousAcceptAllCertificatesValidator_Test : HttpClientHandler_DangerousAcceptAllCertificatesValidator_Test
+ {
+ protected override bool UseSocketsHttpHandler => false;
+ }
+#endif
+
+ public sealed class PlatformHandler_HttpClientHandler_ClientCertificates_Test : HttpClientHandler_ClientCertificates_Test
+ {
+ public PlatformHandler_HttpClientHandler_ClientCertificates_Test(ITestOutputHelper output) : base(output) { }
+ protected override bool UseSocketsHttpHandler => false;
+ }
+
+ public sealed class PlatformHandler_HttpClientHandler_DefaultProxyCredentials_Test : HttpClientHandler_DefaultProxyCredentials_Test
+ {
+ protected override bool UseSocketsHttpHandler => false;
+ }
+
+ public sealed class PlatformHandler_HttpClientHandler_MaxConnectionsPerServer_Test : HttpClientHandler_MaxConnectionsPerServer_Test
+ {
+ protected override bool UseSocketsHttpHandler => false;
+ }
+
+ public sealed class PlatformHandler_HttpClientHandler_ServerCertificates_Test : HttpClientHandler_ServerCertificates_Test
+ {
+ protected override bool UseSocketsHttpHandler => false;
+ }
+
+ public sealed class PlatformHandler_PostScenarioTest : PostScenarioTest
+ {
+ public PlatformHandler_PostScenarioTest(ITestOutputHelper output) : base(output) { }
+ protected override bool UseSocketsHttpHandler => false;
+ }
+
+ public sealed class PlatformHandler_ResponseStreamTest : ResponseStreamTest
+ {
+ public PlatformHandler_ResponseStreamTest(ITestOutputHelper output) : base(output) { }
+ protected override bool UseSocketsHttpHandler => false;
+ }
+
+ public sealed class PlatformHandler_HttpClientHandler_SslProtocols_Test : HttpClientHandler_SslProtocols_Test
+ {
+ protected override bool UseSocketsHttpHandler => false;
+ }
+
+ public sealed class PlatformHandler_SchSendAuxRecordHttpTest : SchSendAuxRecordHttpTest
+ {
+ public PlatformHandler_SchSendAuxRecordHttpTest(ITestOutputHelper output) : base(output) { }
+ protected override bool UseSocketsHttpHandler => false;
+ }
+
+ public sealed class PlatformHandler_HttpClientMiniStress : HttpClientMiniStress
+ {
+ protected override bool UseSocketsHttpHandler => false;
+ }
+
+ public sealed class PlatformHandler_HttpClientHandlerTest : HttpClientHandlerTest
+ {
+ public PlatformHandler_HttpClientHandlerTest(ITestOutputHelper output) : base(output) { }
+ protected override bool UseSocketsHttpHandler => false;
+ }
+
+ public sealed class PlatformHandler_DefaultCredentialsTest : DefaultCredentialsTest
+ {
+ public PlatformHandler_DefaultCredentialsTest(ITestOutputHelper output) : base(output) { }
+ protected override bool UseSocketsHttpHandler => false;
+ }
+
+ public sealed class PlatformHandler_IdnaProtocolTests : IdnaProtocolTests
+ {
+ protected override bool UseSocketsHttpHandler => false;
+ // WinHttp on Win7 does not support IDNA
+ protected override bool SupportsIdna => !PlatformDetection.IsWindows7 && !PlatformDetection.IsFullFramework;
+ }
+
+ public sealed class PlatformHandler_HttpRetryProtocolTests : HttpRetryProtocolTests
+ {
+ protected override bool UseSocketsHttpHandler => false;
+ }
+
+ public sealed class PlatformHandler_HttpCookieProtocolTests : HttpCookieProtocolTests
+ {
+ protected override bool UseSocketsHttpHandler => false;
+ }
+
+ public sealed class PlatformHandler_HttpClientHandler_MaxResponseHeadersLength_Test : HttpClientHandler_MaxResponseHeadersLength_Test
+ {
+ protected override bool UseSocketsHttpHandler => false;
+ }
+
+ public sealed class PlatformHandler_HttpClientHandler_ResponseDrain_Test : HttpClientHandler_ResponseDrain_Test
+ {
+ protected override bool UseSocketsHttpHandler => false;
+ }
+
+ public sealed class PlatformHandler_HttpClientHandler_Cancellation_Test : HttpClientHandler_Cancellation_Test
+ {
+ protected override bool UseSocketsHttpHandler => false;
+ }
+
+ public sealed class PlatformHandler_HttpClientHandler_Authentication_Test : HttpClientHandler_Authentication_Test
+ {
+ protected override bool UseSocketsHttpHandler => false;
+ }
+}
diff --git a/src/System.Net.Http/tests/FunctionalTests/PostScenarioTest.cs b/src/System.Net.Http/tests/FunctionalTests/PostScenarioTest.cs
index 5c5ee93fe8..ca5d55f1da 100644
--- a/src/System.Net.Http/tests/FunctionalTests/PostScenarioTest.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/PostScenarioTest.cs
@@ -14,7 +14,7 @@ namespace System.Net.Http.Functional.Tests
// Note: Disposing the HttpClient object automatically disposes the handler within. So, it is not necessary
// to separately Dispose (or have a 'using' statement) for the handler.
[SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "dotnet/corefx #20010")]
- public class PostScenarioTest : HttpClientTestBase
+ public abstract class PostScenarioTest : HttpClientTestBase
{
private const string ExpectedContent = "Test contest";
private const string UserName = "user1";
@@ -160,9 +160,14 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop] // TODO: Issue #11345
[Theory, MemberData(nameof(BasicAuthEchoServers))]
- [ActiveIssue(9228, TestPlatforms.Windows)]
public async Task PostNonRewindableContentUsingAuth_PreAuthenticate_Success(Uri serverUri)
{
+ if (IsWinHttpHandler)
+ {
+ // Issue #9228
+ return;
+ }
+
HttpContent content = CustomContent.Create(ExpectedContent, false);
var credential = new NetworkCredential(UserName, Password);
await PostUsingAuthHelper(serverUri, ExpectedContent, content, credential, preAuthenticate: true);
@@ -191,9 +196,17 @@ namespace System.Net.Http.Functional.Tests
{
using (HttpClient client = CreateHttpClient())
{
- if (!useContentLengthUpload && requestContent != null)
+ if (requestContent != null)
{
- requestContent.Headers.ContentLength = null;
+ if (useContentLengthUpload)
+ {
+ // Ensure that Content-Length is populated (see issue #27245)
+ requestContent.Headers.ContentLength = requestContent.Headers.ContentLength;
+ }
+ else
+ {
+ requestContent.Headers.ContentLength = null;
+ }
}
if (useChunkedEncodingUpload)
diff --git a/src/System.Net.Http/tests/FunctionalTests/PostScenarioUWPTest.cs b/src/System.Net.Http/tests/FunctionalTests/PostScenarioUWPTest.cs
index 1c58ff83eb..f484e170cd 100644
--- a/src/System.Net.Http/tests/FunctionalTests/PostScenarioUWPTest.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/PostScenarioUWPTest.cs
@@ -15,7 +15,7 @@ namespace System.Net.Http.Functional.Tests
{
using Configuration = System.Net.Test.Common.Configuration;
- public class PostScenarioUWPTest : HttpClientTestBase
+ public abstract class PostScenarioUWPTest : HttpClientTestBase
{
private readonly ITestOutputHelper _output;
@@ -27,7 +27,7 @@ namespace System.Net.Http.Functional.Tests
[Fact]
public void Authentication_UseStreamContent_Throws()
{
- RemoteInvoke(async useManagedHandlerString =>
+ RemoteInvoke(async useSocketsHttpHandlerString =>
{
// This test validates the current limitation of CoreFx's NetFxToWinRtStreamAdapter
// which throws exceptions when trying to rewind a .NET Stream when it needs to be
@@ -35,7 +35,7 @@ namespace System.Net.Http.Functional.Tests
string username = "testuser";
string password = "password";
Uri uri = Configuration.Http.BasicAuthUriForCreds(secure: false, userName: username, password: password);
- HttpClientHandler handler = CreateHttpClientHandler(useManagedHandlerString);
+ HttpClientHandler handler = CreateHttpClientHandler(useSocketsHttpHandlerString);
handler.Credentials = new NetworkCredential(username, password);
using (var client = new HttpClient(handler))
@@ -48,18 +48,18 @@ namespace System.Net.Http.Functional.Tests
}
return SuccessExitCode;
- }, UseManagedHandler.ToString()).Dispose();
+ }, UseSocketsHttpHandler.ToString()).Dispose();
}
[Fact]
public void Authentication_UseMultiInterfaceNonRewindableStreamContent_Throws()
{
- RemoteInvoke(async useManagedHandlerString =>
+ RemoteInvoke(async useSocketsHttpHandlerString =>
{
string username = "testuser";
string password = "password";
Uri uri = Configuration.Http.BasicAuthUriForCreds(secure: false, userName: username, password: password);
- HttpClientHandler handler = CreateHttpClientHandler(useManagedHandlerString);
+ HttpClientHandler handler = CreateHttpClientHandler(useSocketsHttpHandlerString);
handler.Credentials = new NetworkCredential(username, password);
using (var client = new HttpClient(handler))
@@ -72,18 +72,18 @@ namespace System.Net.Http.Functional.Tests
}
return SuccessExitCode;
- }, UseManagedHandler.ToString()).Dispose();
+ }, UseSocketsHttpHandler.ToString()).Dispose();
}
[Fact]
public void Authentication_UseMultiInterfaceStreamContent_Success()
{
- RemoteInvoke(async useManagedHandlerString =>
+ RemoteInvoke(async useSocketsHttpHandlerString =>
{
string username = "testuser";
string password = "password";
Uri uri = Configuration.Http.BasicAuthUriForCreds(secure: false, userName: username, password: password);
- HttpClientHandler handler = CreateHttpClientHandler(useManagedHandlerString);
+ HttpClientHandler handler = CreateHttpClientHandler(useSocketsHttpHandlerString);
handler.Credentials = new NetworkCredential(username, password);
using (var client = new HttpClient(handler))
@@ -100,18 +100,18 @@ namespace System.Net.Http.Functional.Tests
}
return SuccessExitCode;
- }, UseManagedHandler.ToString()).Dispose();
+ }, UseSocketsHttpHandler.ToString()).Dispose();
}
[Fact]
public void Authentication_UseMemoryStreamVisibleBufferContent_Success()
{
- RemoteInvoke(async useManagedHandlerString =>
+ RemoteInvoke(async useSocketsHttpHandlerString =>
{
string username = "testuser";
string password = "password";
Uri uri = Configuration.Http.BasicAuthUriForCreds(secure: false, userName: username, password: password);
- HttpClientHandler handler = CreateHttpClientHandler(useManagedHandlerString);
+ HttpClientHandler handler = CreateHttpClientHandler(useSocketsHttpHandlerString);
handler.Credentials = new NetworkCredential(username, password);
using (var client = new HttpClient(handler))
@@ -128,18 +128,18 @@ namespace System.Net.Http.Functional.Tests
}
return SuccessExitCode;
- }, UseManagedHandler.ToString()).Dispose();
+ }, UseSocketsHttpHandler.ToString()).Dispose();
}
[Fact]
public void Authentication_UseMemoryStreamNotVisibleBufferContent_Success()
{
- RemoteInvoke(async useManagedHandlerString =>
+ RemoteInvoke(async useSocketsHttpHandlerString =>
{
string username = "testuser";
string password = "password";
Uri uri = Configuration.Http.BasicAuthUriForCreds(secure: false, userName: username, password: password);
- HttpClientHandler handler = CreateHttpClientHandler(useManagedHandlerString);
+ HttpClientHandler handler = CreateHttpClientHandler(useSocketsHttpHandlerString);
handler.Credentials = new NetworkCredential(username, password);
using (var client = new HttpClient(handler))
@@ -156,7 +156,7 @@ namespace System.Net.Http.Functional.Tests
}
return SuccessExitCode;
- }, UseManagedHandler.ToString()).Dispose();
+ }, UseSocketsHttpHandler.ToString()).Dispose();
}
}
}
diff --git a/src/System.Net.Http/tests/FunctionalTests/ReadOnlyMemoryContentTest.cs b/src/System.Net.Http/tests/FunctionalTests/ReadOnlyMemoryContentTest.cs
index 98bb3426b5..f33fc4bb74 100644
--- a/src/System.Net.Http/tests/FunctionalTests/ReadOnlyMemoryContentTest.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/ReadOnlyMemoryContentTest.cs
@@ -66,8 +66,8 @@ namespace System.Net.Http.Functional.Tests
Assert.Throws<NotSupportedException>(() => stream.WriteByte(0));
Assert.Throws<NotSupportedException>(() => stream.Write(new byte[1], 0, 1));
Assert.Throws<NotSupportedException>(() => stream.Write(new ReadOnlySpan<byte>(new byte[1])));
- await Assert.ThrowsAsync<NotSupportedException>(() => stream.WriteAsync(new byte[1], 0, 1));
- await Assert.ThrowsAsync<NotSupportedException>(() => stream.WriteAsync(new ReadOnlyMemory<byte>(new byte[1])));
+ await Assert.ThrowsAsync<NotSupportedException>(async () => await stream.WriteAsync(new byte[1], 0, 1));
+ await Assert.ThrowsAsync<NotSupportedException>(async () => await stream.WriteAsync(new ReadOnlyMemory<byte>(new byte[1])));
// nops
stream.Flush();
diff --git a/src/System.Net.Http/tests/FunctionalTests/ResponseStreamTest.cs b/src/System.Net.Http/tests/FunctionalTests/ResponseStreamTest.cs
index d067473b05..a099f05403 100644
--- a/src/System.Net.Http/tests/FunctionalTests/ResponseStreamTest.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/ResponseStreamTest.cs
@@ -16,7 +16,7 @@ namespace System.Net.Http.Functional.Tests
using Configuration = System.Net.Test.Common.Configuration;
[SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "dotnet/corefx #20010")]
- public class ResponseStreamTest : HttpClientTestBase
+ public abstract class ResponseStreamTest : HttpClientTestBase
{
private readonly ITestOutputHelper _output;
@@ -182,9 +182,9 @@ namespace System.Net.Http.Functional.Tests
Assert.True(task.IsCompleted, "Task was not yet completed");
// Verify that the task completed successfully or is canceled.
- if (PlatformDetection.IsWindows)
+ if (IsWinHttpHandler)
{
- // On Windows, we may fault because canceling the task destroys the request handle
+ // With WinHttpHandler, we may fault because canceling the task destroys the request handle
// which may randomly cause an ObjectDisposedException (or other exception).
Assert.True(
task.Status == TaskStatus.RanToCompletion ||
@@ -208,44 +208,112 @@ namespace System.Net.Http.Functional.Tests
[OuterLoop] // TODO: Issue #11345
[Theory]
- [InlineData(LoopbackServer.TransferType.ContentLength, LoopbackServer.TransferError.ContentLengthTooLarge)]
- [InlineData(LoopbackServer.TransferType.Chunked, LoopbackServer.TransferError.MissingChunkTerminator)]
- [InlineData(LoopbackServer.TransferType.Chunked, LoopbackServer.TransferError.ChunkSizeTooLarge)]
+ [InlineData(TransferType.ContentLength, TransferError.ContentLengthTooLarge)]
+ [InlineData(TransferType.Chunked, TransferError.MissingChunkTerminator)]
+ [InlineData(TransferType.Chunked, TransferError.ChunkSizeTooLarge)]
public async Task ReadAsStreamAsync_InvalidServerResponse_ThrowsIOException(
- LoopbackServer.TransferType transferType,
- LoopbackServer.TransferError transferError)
+ TransferType transferType,
+ TransferError transferError)
{
- IPEndPoint serverEndPoint;
- Task serverTask = LoopbackServer.StartTransferTypeAndErrorServer(transferType, transferError, out serverEndPoint);
-
- await Assert.ThrowsAsync<IOException>(() => ReadAsStreamHelper(serverEndPoint));
-
- await serverTask;
+ await StartTransferTypeAndErrorServer(transferType, transferError, async uri =>
+ {
+ await Assert.ThrowsAsync<IOException>(() => ReadAsStreamHelper(uri));
+ });
}
[OuterLoop] // TODO: Issue #11345
[Theory]
- [InlineData(LoopbackServer.TransferType.None, LoopbackServer.TransferError.None)]
- [InlineData(LoopbackServer.TransferType.ContentLength, LoopbackServer.TransferError.None)]
- [InlineData(LoopbackServer.TransferType.Chunked, LoopbackServer.TransferError.None)]
+ [InlineData(TransferType.None, TransferError.None)]
+ [InlineData(TransferType.ContentLength, TransferError.None)]
+ [InlineData(TransferType.Chunked, TransferError.None)]
public async Task ReadAsStreamAsync_ValidServerResponse_Success(
- LoopbackServer.TransferType transferType,
- LoopbackServer.TransferError transferError)
+ TransferType transferType,
+ TransferError transferError)
{
- IPEndPoint serverEndPoint;
- Task serverTask = LoopbackServer.StartTransferTypeAndErrorServer(transferType, transferError, out serverEndPoint);
+ await StartTransferTypeAndErrorServer(transferType, transferError, async uri =>
+ {
+ await ReadAsStreamHelper(uri);
+ });
+ }
- await ReadAsStreamHelper(serverEndPoint);
+ public enum TransferType
+ {
+ None = 0,
+ ContentLength,
+ Chunked
+ }
+
+ public enum TransferError
+ {
+ None = 0,
+ ContentLengthTooLarge,
+ ChunkSizeTooLarge,
+ MissingChunkTerminator
+ }
+
+ public static Task StartTransferTypeAndErrorServer(
+ TransferType transferType,
+ TransferError transferError,
+ Func<Uri, Task> clientFunc)
+ {
+ return LoopbackServer.CreateClientAndServerAsync(
+ clientFunc,
+ server => server.AcceptConnectionAsync(async connection =>
+ {
+ // Read past request headers.
+ await connection.ReadRequestHeaderAsync();
- await serverTask;
+ // Determine response transfer headers.
+ string transferHeader = null;
+ string content = "This is some response content.";
+ if (transferType == TransferType.ContentLength)
+ {
+ transferHeader = transferError == TransferError.ContentLengthTooLarge ?
+ $"Content-Length: {content.Length + 42}\r\n" :
+ $"Content-Length: {content.Length}\r\n";
+ }
+ else if (transferType == TransferType.Chunked)
+ {
+ transferHeader = "Transfer-Encoding: chunked\r\n";
+ }
+
+ // Write response header
+ TextWriter writer = connection.Writer;
+ await writer.WriteAsync("HTTP/1.1 200 OK\r\n").ConfigureAwait(false);
+ await writer.WriteAsync($"Date: {DateTimeOffset.UtcNow:R}\r\n").ConfigureAwait(false);
+ await writer.WriteAsync("Content-Type: text/plain\r\n").ConfigureAwait(false);
+ if (!string.IsNullOrEmpty(transferHeader))
+ {
+ await writer.WriteAsync(transferHeader).ConfigureAwait(false);
+ }
+ await writer.WriteAsync("\r\n").ConfigureAwait(false);
+
+ // Write response body
+ if (transferType == TransferType.Chunked)
+ {
+ string chunkSizeInHex = string.Format(
+ "{0:x}\r\n",
+ content.Length + (transferError == TransferError.ChunkSizeTooLarge ? 42 : 0));
+ await writer.WriteAsync(chunkSizeInHex).ConfigureAwait(false);
+ await writer.WriteAsync($"{content}\r\n").ConfigureAwait(false);
+ if (transferError != TransferError.MissingChunkTerminator)
+ {
+ await writer.WriteAsync("0\r\n\r\n").ConfigureAwait(false);
+ }
+ }
+ else
+ {
+ await writer.WriteAsync($"{content}").ConfigureAwait(false);
+ }
+ }));
}
- private async Task ReadAsStreamHelper(IPEndPoint serverEndPoint)
+ private async Task ReadAsStreamHelper(Uri serverUri)
{
using (HttpClient client = CreateHttpClient())
{
using (var response = await client.GetAsync(
- new Uri($"http://{serverEndPoint.Address}:{(serverEndPoint).Port}/"),
+ serverUri,
HttpCompletionOption.ResponseHeadersRead))
using (var stream = await response.Content.ReadAsStreamAsync())
{
diff --git a/src/System.Net.Http/tests/FunctionalTests/SchSendAuxRecordHttpTest.cs b/src/System.Net.Http/tests/FunctionalTests/SchSendAuxRecordHttpTest.cs
index c02e2f1eb6..19261e1022 100644
--- a/src/System.Net.Http/tests/FunctionalTests/SchSendAuxRecordHttpTest.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/SchSendAuxRecordHttpTest.cs
@@ -12,7 +12,7 @@ using Xunit.Abstractions;
namespace System.Net.Http.Functional.Tests
{
[SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "dotnet/corefx #20010")]
- public class SchSendAuxRecordHttpTest : HttpClientTestBase
+ public abstract class SchSendAuxRecordHttpTest : HttpClientTestBase
{
readonly ITestOutputHelper _output;
@@ -33,7 +33,7 @@ namespace System.Net.Http.Functional.Tests
using (HttpClientHandler handler = CreateHttpClientHandler())
using (var client = new HttpClient(handler))
{
- handler.ServerCertificateCustomValidationCallback = LoopbackServer.AllowAllCertificates;
+ handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;
server.Start();
var tasks = new Task[2];
diff --git a/src/System.Net.Http/tests/FunctionalTests/SelectedSitesTest.txt b/src/System.Net.Http/tests/FunctionalTests/SelectedSitesTest.txt
new file mode 100644
index 0000000000..42788a115a
--- /dev/null
+++ b/src/System.Net.Http/tests/FunctionalTests/SelectedSitesTest.txt
@@ -0,0 +1,50 @@
+http://facebook.com
+http://google.com
+http://youtube.com
+http://live.com
+http://yahoo.com
+http://wikipedia.org
+http://msn.com
+http://blogger.com
+http://microsoft.com
+http://bing.com
+http://qq.com
+http://baidu.com
+http://ask.com
+http://wordpress.com
+http://mozilla.com
+http://apple.com
+http://taobao.com
+http://amazon.com
+http://twitter.com
+http://ebay.com
+http://myspace.com
+http://ehow.com
+http://cnet.com
+http://flickr.com
+http://aol.com
+http://google.com.hk
+http://sohu.com
+http://yahoo.co.jp
+http://cnn.com
+http://bbc.co.uk
+http://linkedin.com
+http://craigslist.org
+http://google.fr
+http://nytimes.com
+http://msnbc.com
+http://skype.com
+http://mapquest.com
+http://uol.com.br
+http://alibaba.com
+http://paypal.com
+http://espn.com
+http://real.com
+http://hp.com
+http://dictionary.com
+http://sourceforge.net
+http://terra.com.br
+http://opera.com
+http://google.es
+http://walmart.com
+http://dailymail.co.uk \ No newline at end of file
diff --git a/src/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs b/src/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs
new file mode 100644
index 0000000000..5478ece4b4
--- /dev/null
+++ b/src/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs
@@ -0,0 +1,1420 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Net.Security;
+using System.Net.Sockets;
+using System.Net.Test.Common;
+using System.Security.Authentication;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace System.Net.Http.Functional.Tests
+{
+ public sealed class SocketsHttpHandler_HttpProtocolTests : HttpProtocolTests
+ {
+ protected override bool UseSocketsHttpHandler => true;
+ }
+
+ public sealed class SocketsHttpHandler_HttpProtocolTests_Dribble : HttpProtocolTests_Dribble
+ {
+ protected override bool UseSocketsHttpHandler => true;
+ }
+
+ public sealed class SocketsHttpHandler_HttpClientTest : HttpClientTest
+ {
+ protected override bool UseSocketsHttpHandler => true;
+ }
+
+ public sealed class SocketsHttpHandler_DiagnosticsTest : DiagnosticsTest
+ {
+ protected override bool UseSocketsHttpHandler => true;
+ }
+
+ public sealed class SocketsHttpHandler_HttpClient_SelectedSites_Test : HttpClient_SelectedSites_Test
+ {
+ protected override bool UseSocketsHttpHandler => true;
+ }
+
+ public sealed class SocketsHttpHandler_HttpClientEKUTest : HttpClientEKUTest
+ {
+ protected override bool UseSocketsHttpHandler => true;
+ }
+
+ public sealed class SocketsHttpHandler_HttpClientHandler_Decompression_Tests : HttpClientHandler_Decompression_Test
+ {
+ protected override bool UseSocketsHttpHandler => true;
+ }
+
+ public sealed class SocketsHttpHandler_HttpClientHandler_DangerousAcceptAllCertificatesValidator_Test : HttpClientHandler_DangerousAcceptAllCertificatesValidator_Test
+ {
+ protected override bool UseSocketsHttpHandler => true;
+ }
+
+ public sealed class SocketsHttpHandler_HttpClientHandler_ClientCertificates_Test : HttpClientHandler_ClientCertificates_Test
+ {
+ public SocketsHttpHandler_HttpClientHandler_ClientCertificates_Test(ITestOutputHelper output) : base(output) { }
+ protected override bool UseSocketsHttpHandler => true;
+ }
+
+ public sealed class SocketsHttpHandler_HttpClientHandler_DefaultProxyCredentials_Test : HttpClientHandler_DefaultProxyCredentials_Test
+ {
+ protected override bool UseSocketsHttpHandler => true;
+ }
+
+ public sealed class SocketsHttpHandler_HttpClientHandler_MaxConnectionsPerServer_Test : HttpClientHandler_MaxConnectionsPerServer_Test
+ {
+ protected override bool UseSocketsHttpHandler => true;
+ }
+
+ public sealed class SocketsHttpHandler_HttpClientHandler_ServerCertificates_Test : HttpClientHandler_ServerCertificates_Test
+ {
+ protected override bool UseSocketsHttpHandler => true;
+ }
+
+ public sealed class SocketsHttpHandler_HttpClientHandler_ResponseDrain_Test : HttpClientHandler_ResponseDrain_Test
+ {
+ protected override bool UseSocketsHttpHandler => true;
+
+ protected override void SetResponseDrainTimeout(HttpClientHandler handler, TimeSpan time)
+ {
+ SocketsHttpHandler s = (SocketsHttpHandler)GetUnderlyingSocketsHttpHandler(handler);
+ Assert.NotNull(s);
+ s.ResponseDrainTimeout = time;
+ }
+
+ [Fact]
+ public void MaxResponseDrainSize_Roundtrips()
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ Assert.Equal(1024 * 1024, handler.MaxResponseDrainSize);
+
+ handler.MaxResponseDrainSize = 0;
+ Assert.Equal(0, handler.MaxResponseDrainSize);
+
+ handler.MaxResponseDrainSize = int.MaxValue;
+ Assert.Equal(int.MaxValue, handler.MaxResponseDrainSize);
+ }
+ }
+
+ [Fact]
+ public void MaxResponseDrainSize_InvalidArgument_Throws()
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ Assert.Equal(1024 * 1024, handler.MaxResponseDrainSize);
+
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => handler.MaxResponseDrainSize = -1);
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => handler.MaxResponseDrainSize = int.MinValue);
+
+ Assert.Equal(1024 * 1024, handler.MaxResponseDrainSize);
+ }
+ }
+
+ [Fact]
+ public void MaxResponseDrainSize_SetAfterUse_Throws()
+ {
+ using (var handler = new SocketsHttpHandler())
+ using (var client = new HttpClient(handler))
+ {
+ handler.MaxResponseDrainSize = 1;
+ client.GetAsync("http://" + Guid.NewGuid().ToString("N")); // ignoring failure
+ Assert.Equal(1, handler.MaxResponseDrainSize);
+ Assert.Throws<InvalidOperationException>(() => handler.MaxResponseDrainSize = 1);
+ }
+ }
+
+ [Fact]
+ public void ResponseDrainTimeout_Roundtrips()
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ Assert.Equal(TimeSpan.FromSeconds(2), handler.ResponseDrainTimeout);
+
+ handler.ResponseDrainTimeout = TimeSpan.Zero;
+ Assert.Equal(TimeSpan.Zero, handler.ResponseDrainTimeout);
+
+ handler.ResponseDrainTimeout = TimeSpan.FromTicks(int.MaxValue);
+ Assert.Equal(TimeSpan.FromTicks(int.MaxValue), handler.ResponseDrainTimeout);
+ }
+ }
+
+ [Fact]
+ public void MaxResponseDraiTime_InvalidArgument_Throws()
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ Assert.Equal(TimeSpan.FromSeconds(2), handler.ResponseDrainTimeout);
+
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => handler.ResponseDrainTimeout = TimeSpan.FromSeconds(-1));
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => handler.ResponseDrainTimeout = TimeSpan.MaxValue);
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => handler.ResponseDrainTimeout = TimeSpan.FromSeconds(int.MaxValue));
+
+ Assert.Equal(TimeSpan.FromSeconds(2), handler.ResponseDrainTimeout);
+ }
+ }
+
+ [Fact]
+ public void ResponseDrainTimeout_SetAfterUse_Throws()
+ {
+ using (var handler = new SocketsHttpHandler())
+ using (var client = new HttpClient(handler))
+ {
+ handler.ResponseDrainTimeout = TimeSpan.FromSeconds(42);
+ client.GetAsync("http://" + Guid.NewGuid().ToString("N")); // ignoring failure
+ Assert.Equal(TimeSpan.FromSeconds(42), handler.ResponseDrainTimeout);
+ Assert.Throws<InvalidOperationException>(() => handler.ResponseDrainTimeout = TimeSpan.FromSeconds(42));
+ }
+ }
+
+ [OuterLoop]
+ [Theory]
+ [InlineData(1024 * 1024 * 2, 9_500, 1024 * 1024 * 3, ContentMode.ContentLength)]
+ [InlineData(1024 * 1024 * 2, 9_500, 1024 * 1024 * 3, ContentMode.SingleChunk)]
+ [InlineData(1024 * 1024 * 2, 9_500, 1024 * 1024 * 13, ContentMode.BytePerChunk)]
+ public async Task GetAsyncWithMaxConnections_DisposeBeforeReadingToEnd_DrainsRequestsUnderMaxDrainSizeAndReusesConnection(int totalSize, int readSize, int maxDrainSize, ContentMode mode)
+ {
+ await LoopbackServer.CreateClientAndServerAsync(
+ async url =>
+ {
+ var handler = new SocketsHttpHandler();
+ handler.MaxResponseDrainSize = maxDrainSize;
+ handler.ResponseDrainTimeout = Timeout.InfiniteTimeSpan;
+
+ // Set MaxConnectionsPerServer to 1. This will ensure we will wait for the previous request to drain (or fail to)
+ handler.MaxConnectionsPerServer = 1;
+
+ using (var client = new HttpClient(handler))
+ {
+ HttpResponseMessage response1 = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
+ ValidateResponseHeaders(response1, totalSize, mode);
+
+ // Read part but not all of response
+ Stream responseStream = await response1.Content.ReadAsStreamAsync();
+ await ReadToByteCount(responseStream, readSize);
+
+ response1.Dispose();
+
+ // Issue another request. We'll confirm that it comes on the same connection.
+ HttpResponseMessage response2 = await client.GetAsync(url);
+ ValidateResponseHeaders(response2, totalSize, mode);
+ Assert.Equal(totalSize, (await response2.Content.ReadAsStringAsync()).Length);
+ }
+ },
+ async server =>
+ {
+ string content = new string('a', totalSize);
+ string response = GetResponseForContentMode(content, mode);
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ await connection.ReadRequestHeaderAndSendCustomResponseAsync(response);
+ await connection.ReadRequestHeaderAndSendCustomResponseAsync(response);
+ });
+ });
+ }
+
+ [OuterLoop]
+ [Theory]
+ [InlineData(100_000, 0, ContentMode.ContentLength)]
+ [InlineData(100_000, 0, ContentMode.SingleChunk)]
+ [InlineData(100_000, 0, ContentMode.BytePerChunk)]
+ public async Task GetAsyncWithMaxConnections_DisposeLargerThanMaxDrainSize_KillsConnection(int totalSize, int maxDrainSize, ContentMode mode)
+ {
+ await LoopbackServer.CreateClientAndServerAsync(
+ async url =>
+ {
+ var handler = new SocketsHttpHandler();
+ handler.MaxResponseDrainSize = maxDrainSize;
+ handler.ResponseDrainTimeout = Timeout.InfiniteTimeSpan;
+
+ // Set MaxConnectionsPerServer to 1. This will ensure we will wait for the previous request to drain (or fail to)
+ handler.MaxConnectionsPerServer = 1;
+
+ using (var client = new HttpClient(handler))
+ {
+ HttpResponseMessage response1 = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
+ ValidateResponseHeaders(response1, totalSize, mode);
+ response1.Dispose();
+
+ // Issue another request. We'll confirm that it comes on a new connection.
+ HttpResponseMessage response2 = await client.GetAsync(url);
+ ValidateResponseHeaders(response2, totalSize, mode);
+ Assert.Equal(totalSize, (await response2.Content.ReadAsStringAsync()).Length);
+ }
+ },
+ async server =>
+ {
+ string content = new string('a', totalSize);
+ string response = GetResponseForContentMode(content, mode);
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ await connection.ReadRequestHeaderAsync();
+ try
+ {
+ await connection.Writer.WriteAsync(response);
+ }
+ catch (Exception) { } // Eat errors from client disconnect.
+
+ await server.AcceptConnectionSendCustomResponseAndCloseAsync(response);
+ });
+ });
+ }
+
+ [OuterLoop]
+ [Theory]
+ [InlineData(ContentMode.ContentLength)]
+ [InlineData(ContentMode.SingleChunk)]
+ [InlineData(ContentMode.BytePerChunk)]
+ public async Task GetAsyncWithMaxConnections_DrainTakesLongerThanTimeout_KillsConnection(ContentMode mode)
+ {
+ const int ContentLength = 10_000;
+
+ await LoopbackServer.CreateClientAndServerAsync(
+ async url =>
+ {
+ var handler = new SocketsHttpHandler();
+ handler.MaxResponseDrainSize = int.MaxValue;
+ handler.ResponseDrainTimeout = TimeSpan.FromMilliseconds(1);
+
+ // Set MaxConnectionsPerServer to 1. This will ensure we will wait for the previous request to drain (or fail to)
+ handler.MaxConnectionsPerServer = 1;
+
+ using (var client = new HttpClient(handler))
+ {
+ client.Timeout = Timeout.InfiniteTimeSpan;
+
+ HttpResponseMessage response1 = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
+ ValidateResponseHeaders(response1, ContentLength, mode);
+ response1.Dispose();
+
+ // Issue another request. We'll confirm that it comes on a new connection.
+ HttpResponseMessage response2 = await client.GetAsync(url);
+ ValidateResponseHeaders(response2, ContentLength, mode);
+ Assert.Equal(ContentLength, (await response2.Content.ReadAsStringAsync()).Length);
+ }
+ },
+ async server =>
+ {
+ string content = new string('a', ContentLength);
+ string response = GetResponseForContentMode(content, mode);
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ await connection.ReadRequestHeaderAsync();
+ try
+ {
+ // Write out only part of the response
+ await connection.Writer.WriteAsync(response.Substring(0, response.Length / 2));
+ }
+ catch (Exception) { } // Eat errors from client disconnect.
+
+ await server.AcceptConnectionSendCustomResponseAndCloseAsync(response);
+ });
+ });
+ }
+ }
+
+ public sealed class SocketsHttpHandler_PostScenarioTest : PostScenarioTest
+ {
+ public SocketsHttpHandler_PostScenarioTest(ITestOutputHelper output) : base(output) { }
+ protected override bool UseSocketsHttpHandler => true;
+ }
+
+ public sealed class SocketsHttpHandler_ResponseStreamTest : ResponseStreamTest
+ {
+ public SocketsHttpHandler_ResponseStreamTest(ITestOutputHelper output) : base(output) { }
+ protected override bool UseSocketsHttpHandler => true;
+ }
+
+ public sealed class SocketsHttpHandler_HttpClientHandler_SslProtocols_Test : HttpClientHandler_SslProtocols_Test
+ {
+ protected override bool UseSocketsHttpHandler => true;
+ }
+
+ public sealed class SocketsHttpHandler_SchSendAuxRecordHttpTest : SchSendAuxRecordHttpTest
+ {
+ public SocketsHttpHandler_SchSendAuxRecordHttpTest(ITestOutputHelper output) : base(output) { }
+ protected override bool UseSocketsHttpHandler => true;
+ }
+
+ public sealed class SocketsHttpHandler_HttpClientMiniStress : HttpClientMiniStress
+ {
+ protected override bool UseSocketsHttpHandler => true;
+ }
+
+ public sealed class SocketsHttpHandler_HttpClientHandlerTest : HttpClientHandlerTest
+ {
+ public SocketsHttpHandler_HttpClientHandlerTest(ITestOutputHelper output) : base(output) { }
+ protected override bool UseSocketsHttpHandler => true;
+ }
+
+ public sealed class SocketsHttpHandler_DefaultCredentialsTest : DefaultCredentialsTest
+ {
+ public SocketsHttpHandler_DefaultCredentialsTest(ITestOutputHelper output) : base(output) { }
+ protected override bool UseSocketsHttpHandler => true;
+ }
+
+ public sealed class SocketsHttpHandler_IdnaProtocolTests : IdnaProtocolTests
+ {
+ protected override bool UseSocketsHttpHandler => true;
+ protected override bool SupportsIdna => true;
+ }
+
+ public sealed class SocketsHttpHandler_HttpRetryProtocolTests : HttpRetryProtocolTests
+ {
+ protected override bool UseSocketsHttpHandler => true;
+ }
+
+ public sealed class SocketsHttpHandler_HttpCookieProtocolTests : HttpCookieProtocolTests
+ {
+ protected override bool UseSocketsHttpHandler => true;
+ }
+
+ public sealed class SocketsHttpHandler_HttpClientHandler_Cancellation_Test : HttpClientHandler_Cancellation_Test
+ {
+ protected override bool UseSocketsHttpHandler => true;
+
+ [Fact]
+ public void ConnectTimeout_Default()
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ Assert.Equal(Timeout.InfiniteTimeSpan, handler.ConnectTimeout);
+ }
+ }
+
+ [Theory]
+ [InlineData(0)]
+ [InlineData(-2)]
+ [InlineData(int.MaxValue + 1L)]
+ public void ConnectTimeout_InvalidValues(long ms)
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ Assert.Throws<ArgumentOutOfRangeException>(() => handler.ConnectTimeout = TimeSpan.FromMilliseconds(ms));
+ }
+ }
+
+ [Theory]
+ [InlineData(-1)]
+ [InlineData(1)]
+ [InlineData(int.MaxValue - 1)]
+ [InlineData(int.MaxValue)]
+ public void ConnectTimeout_ValidValues_Roundtrip(long ms)
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ handler.ConnectTimeout = TimeSpan.FromMilliseconds(ms);
+ Assert.Equal(TimeSpan.FromMilliseconds(ms), handler.ConnectTimeout);
+ }
+ }
+
+ [Fact]
+ public void ConnectTimeout_SetAfterUse_Throws()
+ {
+ using (var handler = new SocketsHttpHandler())
+ using (var client = new HttpClient(handler))
+ {
+ handler.ConnectTimeout = TimeSpan.FromMilliseconds(int.MaxValue);
+ client.GetAsync("http://" + Guid.NewGuid().ToString("N")); // ignoring failure
+ Assert.Equal(TimeSpan.FromMilliseconds(int.MaxValue), handler.ConnectTimeout);
+ Assert.Throws<InvalidOperationException>(() => handler.ConnectTimeout = TimeSpan.FromMilliseconds(1));
+ }
+ }
+
+ [OuterLoop]
+ [Fact]
+ public async Task ConnectTimeout_TimesOutSSLAuth_Throws()
+ {
+ var releaseServer = new TaskCompletionSource<bool>();
+ await LoopbackServer.CreateClientAndServerAsync(async uri =>
+ {
+ using (var handler = new SocketsHttpHandler())
+ using (var invoker = new HttpMessageInvoker(handler))
+ {
+ handler.ConnectTimeout = TimeSpan.FromSeconds(1);
+
+ var sw = Stopwatch.StartNew();
+ await Assert.ThrowsAsync<TaskCanceledException>(() =>
+ invoker.SendAsync(new HttpRequestMessage(HttpMethod.Get,
+ new UriBuilder(uri) { Scheme = "https" }.ToString()), default));
+ sw.Stop();
+
+ Assert.InRange(sw.ElapsedMilliseconds, 500, 30_000);
+ releaseServer.SetResult(true);
+ }
+ }, server => releaseServer.Task); // doesn't establish SSL connection
+ }
+
+
+ [Fact]
+ public void Expect100ContinueTimeout_Default()
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ Assert.Equal(TimeSpan.FromSeconds(1), handler.Expect100ContinueTimeout);
+ }
+ }
+
+ [Theory]
+ [InlineData(-2)]
+ [InlineData(int.MaxValue + 1L)]
+ public void Expect100ContinueTimeout_InvalidValues(long ms)
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ Assert.Throws<ArgumentOutOfRangeException>(() => handler.Expect100ContinueTimeout = TimeSpan.FromMilliseconds(ms));
+ }
+ }
+
+ [Theory]
+ [InlineData(-1)]
+ [InlineData(1)]
+ [InlineData(int.MaxValue - 1)]
+ [InlineData(int.MaxValue)]
+ public void Expect100ContinueTimeout_ValidValues_Roundtrip(long ms)
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ handler.Expect100ContinueTimeout = TimeSpan.FromMilliseconds(ms);
+ Assert.Equal(TimeSpan.FromMilliseconds(ms), handler.Expect100ContinueTimeout);
+ }
+ }
+
+ [Fact]
+ public void Expect100ContinueTimeout_SetAfterUse_Throws()
+ {
+ using (var handler = new SocketsHttpHandler())
+ using (var client = new HttpClient(handler))
+ {
+ handler.Expect100ContinueTimeout = TimeSpan.FromMilliseconds(int.MaxValue);
+ client.GetAsync("http://" + Guid.NewGuid().ToString("N")); // ignoring failure
+ Assert.Equal(TimeSpan.FromMilliseconds(int.MaxValue), handler.Expect100ContinueTimeout);
+ Assert.Throws<InvalidOperationException>(() => handler.Expect100ContinueTimeout = TimeSpan.FromMilliseconds(1));
+ }
+ }
+
+ [OuterLoop("Incurs significant delay")]
+ [Fact]
+ public async Task Expect100Continue_WaitsExpectedPeriodOfTimeBeforeSendingContent()
+ {
+ await LoopbackServer.CreateClientAndServerAsync(async uri =>
+ {
+ using (var handler = new SocketsHttpHandler())
+ using (var invoker = new HttpMessageInvoker(handler))
+ {
+ TimeSpan delay = TimeSpan.FromSeconds(3);
+ handler.Expect100ContinueTimeout = delay;
+
+ var tcs = new TaskCompletionSource<bool>();
+ var content = new SetTcsContent(new MemoryStream(new byte[1]), tcs);
+ var request = new HttpRequestMessage(HttpMethod.Post, uri) { Content = content };
+ request.Headers.ExpectContinue = true;
+
+ var sw = Stopwatch.StartNew();
+ (await invoker.SendAsync(request, default)).Dispose();
+ sw.Stop();
+
+ Assert.InRange(sw.Elapsed, delay - TimeSpan.FromSeconds(.5), delay * 10); // arbitrary wiggle room
+ }
+ }, async server =>
+ {
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ await connection.ReadRequestHeaderAsync();
+ await connection.Reader.ReadAsync(new char[1]);
+ await connection.SendResponseAsync();
+ });
+ });
+ }
+
+ private sealed class SetTcsContent : StreamContent
+ {
+ private readonly TaskCompletionSource<bool> _tcs;
+
+ public SetTcsContent(Stream stream, TaskCompletionSource<bool> tcs) : base(stream) => _tcs = tcs;
+
+ protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
+ {
+ _tcs.SetResult(true);
+ return base.SerializeToStreamAsync(stream, context);
+ }
+ }
+ }
+
+ public sealed class SocketsHttpHandler_HttpClientHandler_MaxResponseHeadersLength_Test : HttpClientHandler_MaxResponseHeadersLength_Test
+ {
+ protected override bool UseSocketsHttpHandler => true;
+ }
+
+ public sealed class SocketsHttpHandler_HttpClientHandler_Authentication_Test : HttpClientHandler_Authentication_Test
+ {
+ protected override bool UseSocketsHttpHandler => true;
+
+ [Theory]
+ [MemberData(nameof(Authentication_SocketsHttpHandler_TestData))]
+ public async void SocketsHttpHandler_Authentication_Succeeds(string authenticateHeader, bool result)
+ {
+ await HttpClientHandler_Authentication_Succeeds(authenticateHeader, result);
+ }
+
+ public static IEnumerable<object[]> Authentication_SocketsHttpHandler_TestData()
+ {
+ // These test cases successfully authenticate on SocketsHttpHandler but fail on the other handlers.
+ // These are legal as per the the RFC, so authenticating is the expected behavior. See #28521 for details.
+ yield return new object[] { "Basic realm=\"testrealm1\" basic realm=\"testrealm1\"", true };
+ yield return new object[] { "Basic something digest something", true };
+ yield return new object[] { "Digest realm=\"api@example.org\", qop=\"auth\", algorithm=MD5-sess, nonce=\"5TsQWLVdgBdmrQ0XsxbDODV+57QdFR34I9HAbC/RVvkK\", " +
+ "opaque=\"HRPCssKJSGjCrkzDg8OhwpzCiGPChXYjwrI2QmXDnsOS\", charset=UTF-8, userhash=true", true };
+ yield return new object[] { "dIgEsT realm=\"api@example.org\", qop=\"auth\", algorithm=MD5-sess, nonce=\"5TsQWLVdgBdmrQ0XsxbDODV+57QdFR34I9HAbC/RVvkK\", " +
+ "opaque=\"HRPCssKJSGjCrkzDg8OhwpzCiGPChXYjwrI2QmXDnsOS\", charset=UTF-8, userhash=true", true };
+
+ // These cases fail on WinHttpHandler because of a behavior in WinHttp that causes requests to be duplicated
+ // when the digest header has certain parameters. See #28522 for details.
+ yield return new object[] { "Digest ", false };
+ yield return new object[] { "Digest realm=\"testrealm\", nonce=\"testnonce\", algorithm=\"myown\"", false };
+
+ // These cases fail to authenticate on SocketsHttpHandler, but succeed on the other handlers.
+ // they are all invalid as per the RFC, so failing is the expected behavior. See #28523 for details.
+ yield return new object[] { "Digest realm=withoutquotes, nonce=withoutquotes", false };
+ yield return new object[] { "Digest realm=\"testrealm\" nonce=\"testnonce\"", false };
+ yield return new object[] { "Digest realm=\"testrealm1\", nonce=\"testnonce1\" Digest realm=\"testrealm2\", nonce=\"testnonce2\"", false };
+ }
+ }
+
+ public sealed class SocketsHttpHandler_ConnectionUpgrade_Test : HttpClientTestBase
+ {
+ protected override bool UseSocketsHttpHandler => true;
+
+ [Fact]
+ public async Task UpgradeConnection_ReturnsReadableAndWritableStream()
+ {
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ using (HttpClient client = CreateHttpClient())
+ {
+ // We need to use ResponseHeadersRead here, otherwise we will hang trying to buffer the response body.
+ Task<HttpResponseMessage> getResponseTask = client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ Task<List<string>> serverTask = connection.ReadRequestHeaderAndSendCustomResponseAsync($"HTTP/1.1 101 Switching Protocols\r\nDate: {DateTimeOffset.UtcNow:R}\r\n\r\n");
+
+ await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);
+
+ using (Stream clientStream = await (await getResponseTask).Content.ReadAsStreamAsync())
+ {
+ // Boolean properties returning correct values
+ Assert.True(clientStream.CanWrite);
+ Assert.True(clientStream.CanRead);
+ Assert.False(clientStream.CanSeek);
+
+ // Not supported operations
+ Assert.Throws<NotSupportedException>(() => clientStream.Length);
+ Assert.Throws<NotSupportedException>(() => clientStream.Position);
+ Assert.Throws<NotSupportedException>(() => clientStream.Position = 0);
+ Assert.Throws<NotSupportedException>(() => clientStream.Seek(0, SeekOrigin.Begin));
+ Assert.Throws<NotSupportedException>(() => clientStream.SetLength(0));
+
+ // Invalid arguments
+ var nonWritableStream = new MemoryStream(new byte[1], false);
+ var disposedStream = new MemoryStream();
+ disposedStream.Dispose();
+ Assert.Throws<ArgumentNullException>(() => clientStream.CopyTo(null));
+ Assert.Throws<ArgumentOutOfRangeException>(() => clientStream.CopyTo(Stream.Null, 0));
+ Assert.Throws<ArgumentNullException>(() => { clientStream.CopyToAsync(null, 100, default); });
+ Assert.Throws<ArgumentOutOfRangeException>(() => { clientStream.CopyToAsync(Stream.Null, 0, default); });
+ Assert.Throws<ArgumentOutOfRangeException>(() => { clientStream.CopyToAsync(Stream.Null, -1, default); });
+ Assert.Throws<NotSupportedException>(() => { clientStream.CopyToAsync(nonWritableStream, 100, default); });
+ Assert.Throws<ObjectDisposedException>(() => { clientStream.CopyToAsync(disposedStream, 100, default); });
+ Assert.Throws<ArgumentNullException>(() => clientStream.Read(null, 0, 100));
+ Assert.Throws<ArgumentOutOfRangeException>(() => clientStream.Read(new byte[1], -1, 1));
+ Assert.ThrowsAny<ArgumentException>(() => clientStream.Read(new byte[1], 2, 1));
+ Assert.Throws<ArgumentOutOfRangeException>(() => clientStream.Read(new byte[1], 0, -1));
+ Assert.ThrowsAny<ArgumentException>(() => clientStream.Read(new byte[1], 0, 2));
+ Assert.Throws<ArgumentNullException>(() => clientStream.BeginRead(null, 0, 100, null, null));
+ Assert.Throws<ArgumentOutOfRangeException>(() => clientStream.BeginRead(new byte[1], -1, 1, null, null));
+ Assert.ThrowsAny<ArgumentException>(() => clientStream.BeginRead(new byte[1], 2, 1, null, null));
+ Assert.Throws<ArgumentOutOfRangeException>(() => clientStream.BeginRead(new byte[1], 0, -1, null, null));
+ Assert.ThrowsAny<ArgumentException>(() => clientStream.BeginRead(new byte[1], 0, 2, null, null));
+ Assert.Throws<ArgumentNullException>(() => clientStream.EndRead(null));
+ Assert.Throws<ArgumentNullException>(() => { clientStream.ReadAsync(null, 0, 100, default); });
+ Assert.Throws<ArgumentOutOfRangeException>(() => { clientStream.ReadAsync(new byte[1], -1, 1, default); });
+ Assert.ThrowsAny<ArgumentException>(() => { clientStream.ReadAsync(new byte[1], 2, 1, default); });
+ Assert.Throws<ArgumentOutOfRangeException>(() => { clientStream.ReadAsync(new byte[1], 0, -1, default); });
+ Assert.ThrowsAny<ArgumentException>(() => { clientStream.ReadAsync(new byte[1], 0, 2, default); });
+
+ // Validate writing APIs on clientStream
+
+ clientStream.WriteByte((byte)'!');
+ clientStream.Write(new byte[] { (byte)'\r', (byte)'\n' }, 0, 2);
+ Assert.Equal("!", await connection.Reader.ReadLineAsync());
+
+ clientStream.Write(new Span<byte>(new byte[] { (byte)'h', (byte)'e', (byte)'l', (byte)'l', (byte)'o', (byte)'\r', (byte)'\n' }));
+ Assert.Equal("hello", await connection.Reader.ReadLineAsync());
+
+ await clientStream.WriteAsync(new byte[] { (byte)'w', (byte)'o', (byte)'r', (byte)'l', (byte)'d', (byte)'\r', (byte)'\n' }, 0, 7);
+ Assert.Equal("world", await connection.Reader.ReadLineAsync());
+
+ await clientStream.WriteAsync(new Memory<byte>(new byte[] { (byte)'a', (byte)'n', (byte)'d', (byte)'\r', (byte)'\n' }, 0, 5));
+ Assert.Equal("and", await connection.Reader.ReadLineAsync());
+
+ await Task.Factory.FromAsync(clientStream.BeginWrite, clientStream.EndWrite, new byte[] { (byte)'b', (byte)'e', (byte)'y', (byte)'o', (byte)'n', (byte)'d', (byte)'\r', (byte)'\n' }, 0, 8, null);
+ Assert.Equal("beyond", await connection.Reader.ReadLineAsync());
+
+ clientStream.Flush();
+ await clientStream.FlushAsync();
+
+ // Validate reading APIs on clientStream
+ await connection.Stream.WriteAsync(Encoding.ASCII.GetBytes("abcdefghijklmnopqrstuvwxyz"));
+ var buffer = new byte[1];
+
+ Assert.Equal('a', clientStream.ReadByte());
+
+ Assert.Equal(1, clientStream.Read(buffer, 0, 1));
+ Assert.Equal((byte)'b', buffer[0]);
+
+ Assert.Equal(1, clientStream.Read(new Span<byte>(buffer, 0, 1)));
+ Assert.Equal((byte)'c', buffer[0]);
+
+ Assert.Equal(1, await clientStream.ReadAsync(buffer, 0, 1));
+ Assert.Equal((byte)'d', buffer[0]);
+
+ Assert.Equal(1, await clientStream.ReadAsync(new Memory<byte>(buffer, 0, 1)));
+ Assert.Equal((byte)'e', buffer[0]);
+
+ Assert.Equal(1, await Task.Factory.FromAsync(clientStream.BeginRead, clientStream.EndRead, buffer, 0, 1, null));
+ Assert.Equal((byte)'f', buffer[0]);
+
+ var ms = new MemoryStream();
+ Task copyTask = clientStream.CopyToAsync(ms);
+
+ string bigString = string.Concat(Enumerable.Repeat("abcdefghijklmnopqrstuvwxyz", 1000));
+ Task lotsOfDataSent = connection.Socket.SendAsync(Encoding.ASCII.GetBytes(bigString), SocketFlags.None);
+ connection.Socket.Shutdown(SocketShutdown.Send);
+ await copyTask;
+ await lotsOfDataSent;
+ Assert.Equal("ghijklmnopqrstuvwxyz" + bigString, Encoding.ASCII.GetString(ms.ToArray()));
+ }
+ });
+ }
+ });
+ }
+ }
+
+ public sealed class SocketsHttpHandler_Connect_Test : HttpClientTestBase
+ {
+ protected override bool UseSocketsHttpHandler => true;
+
+ [Fact]
+ public async Task ConnectMethod_Success()
+ {
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ using (HttpClient client = CreateHttpClient())
+ {
+ HttpRequestMessage request = new HttpRequestMessage(new HttpMethod("CONNECT"), url);
+ request.Headers.Host = "foo.com:345";
+
+ // We need to use ResponseHeadersRead here, otherwise we will hang trying to buffer the response body.
+ Task<HttpResponseMessage> responseTask = client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
+
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ // Verify that Host header exist and has same value and URI authority.
+ List<string> lines = await connection.ReadRequestHeaderAsync().ConfigureAwait(false);
+ string authority = lines[0].Split()[1];
+ foreach (string line in lines)
+ {
+ if (line.StartsWith("Host:",StringComparison.InvariantCultureIgnoreCase))
+ {
+ Assert.Equal(line, "Host: foo.com:345");
+ break;
+ }
+ }
+
+ Task serverTask = connection.SendResponseAsync(HttpStatusCode.OK);
+ await TestHelper.WhenAllCompletedOrAnyFailed(responseTask, serverTask).ConfigureAwait(false);
+
+ using (Stream clientStream = await (await responseTask).Content.ReadAsStreamAsync())
+ {
+ Assert.True(clientStream.CanWrite);
+ Assert.True(clientStream.CanRead);
+ Assert.False(clientStream.CanSeek);
+
+ TextReader clientReader = new StreamReader(clientStream);
+ TextWriter clientWriter = new StreamWriter(clientStream) { AutoFlush = true };
+ TextReader serverReader = connection.Reader;
+ TextWriter serverWriter = connection.Writer;
+
+ const string helloServer = "hello server";
+ const string helloClient = "hello client";
+ const string goodbyeServer = "goodbye server";
+ const string goodbyeClient = "goodbye client";
+
+ clientWriter.WriteLine(helloServer);
+ Assert.Equal(helloServer, serverReader.ReadLine());
+ serverWriter.WriteLine(helloClient);
+ Assert.Equal(helloClient, clientReader.ReadLine());
+ clientWriter.WriteLine(goodbyeServer);
+ Assert.Equal(goodbyeServer, serverReader.ReadLine());
+ serverWriter.WriteLine(goodbyeClient);
+ Assert.Equal(goodbyeClient, clientReader.ReadLine());
+ }
+ });
+ }
+ });
+ }
+
+ [Fact]
+ public async Task ConnectMethod_Fails()
+ {
+ await LoopbackServer.CreateServerAsync(async (server, url) =>
+ {
+ using (HttpClient client = CreateHttpClient())
+ {
+ HttpRequestMessage request = new HttpRequestMessage(new HttpMethod("CONNECT"), url);
+ request.Headers.Host = "foo.com:345";
+ // We need to use ResponseHeadersRead here, otherwise we will hang trying to buffer the response body.
+ Task<HttpResponseMessage> responseTask = client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ Task<List<string>> serverTask = connection.ReadRequestHeaderAndSendResponseAsync(HttpStatusCode.Forbidden, content: "error");
+
+ await TestHelper.WhenAllCompletedOrAnyFailed(responseTask, serverTask);
+ HttpResponseMessage response = await responseTask;
+
+ Assert.True(response.StatusCode == HttpStatusCode.Forbidden);
+ });
+ }
+ });
+ }
+ }
+
+ public sealed class SocketsHttpHandler_HttpClientHandler_ConnectionPooling_Test : HttpClientTestBase
+ {
+ protected override bool UseSocketsHttpHandler => true;
+
+ // TODO: ISSUE #27272
+ // Currently the subsequent tests sometimes fail/hang with WinHttpHandler / CurlHandler.
+ // In theory they should pass with any handler that does appropriate connection pooling.
+ // We should understand why they sometimes fail there and ideally move them to be
+ // used by all handlers this test project tests.
+
+ [Fact]
+ public async Task MultipleIterativeRequests_SameConnectionReused()
+ {
+ using (HttpClient client = CreateHttpClient())
+ using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ {
+ listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
+ listener.Listen(1);
+ var ep = (IPEndPoint)listener.LocalEndPoint;
+ var uri = new Uri($"http://{ep.Address}:{ep.Port}/");
+
+ string responseBody =
+ "HTTP/1.1 200 OK\r\n" +
+ $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
+ "Content-Length: 0\r\n" +
+ "\r\n";
+
+ Task<string> firstRequest = client.GetStringAsync(uri);
+ using (Socket server = await listener.AcceptAsync())
+ using (var serverStream = new NetworkStream(server, ownsSocket: false))
+ using (var serverReader = new StreamReader(serverStream))
+ {
+ while (!string.IsNullOrWhiteSpace(await serverReader.ReadLineAsync()));
+ await server.SendAsync(new ArraySegment<byte>(Encoding.ASCII.GetBytes(responseBody)), SocketFlags.None);
+ await firstRequest;
+
+ Task<Socket> secondAccept = listener.AcceptAsync(); // shouldn't complete
+
+ Task<string> additionalRequest = client.GetStringAsync(uri);
+ while (!string.IsNullOrWhiteSpace(await serverReader.ReadLineAsync()));
+ await server.SendAsync(new ArraySegment<byte>(Encoding.ASCII.GetBytes(responseBody)), SocketFlags.None);
+ await additionalRequest;
+
+ Assert.False(secondAccept.IsCompleted, $"Second accept should never complete");
+ }
+ }
+ }
+
+ [OuterLoop("Incurs a delay")]
+ [Fact]
+ public async Task ServerDisconnectsAfterInitialRequest_SubsequentRequestUsesDifferentConnection()
+ {
+ using (HttpClient client = CreateHttpClient())
+ {
+ await LoopbackServer.CreateServerAsync(async (server, uri) =>
+ {
+ // Make multiple requests iteratively.
+ for (int i = 0; i < 2; i++)
+ {
+ Task<string> request = client.GetStringAsync(uri);
+ await server.AcceptConnectionSendResponseAndCloseAsync();
+ await request;
+
+ if (i == 0)
+ {
+ await Task.Delay(2000); // give client time to see the closing before next connect
+ }
+ }
+ });
+ }
+ }
+
+ [Fact]
+ public async Task ServerSendsGarbageAfterInitialRequest_SubsequentRequestUsesDifferentConnection()
+ {
+ using (HttpClient client = CreateHttpClient())
+ {
+ await LoopbackServer.CreateServerAsync(async (server, uri) =>
+ {
+ // Make multiple requests iteratively.
+ for (int i = 0; i < 2; i++)
+ {
+ Task<string> request = client.GetStringAsync(uri);
+ string response = LoopbackServer.GetHttpResponse() + "here is a bunch of garbage";
+ await server.AcceptConnectionSendCustomResponseAndCloseAsync(response);
+ await request;
+ }
+ });
+ }
+ }
+
+ [Fact]
+ public async Task ServerSendsConnectionClose_SubsequentRequestUsesDifferentConnection()
+ {
+ using (HttpClient client = CreateHttpClient())
+ {
+ await LoopbackServer.CreateServerAsync(async (server, uri) =>
+ {
+ string responseBody =
+ "HTTP/1.1 200 OK\r\n" +
+ $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
+ "Content-Length: 0\r\n" +
+ "Connection: close\r\n" +
+ "\r\n";
+
+ // Make first request.
+ Task<string> request1 = client.GetStringAsync(uri);
+ await server.AcceptConnectionAsync(async connection1 =>
+ {
+ await connection1.ReadRequestHeaderAndSendCustomResponseAsync(responseBody);
+ await request1;
+
+ // Make second request and expect it to be served from a different connection.
+ Task<string> request2 = client.GetStringAsync(uri);
+ await server.AcceptConnectionAsync(async connection2 =>
+ {
+ await connection2.ReadRequestHeaderAndSendCustomResponseAsync(responseBody);
+ await request2;
+ });
+ });
+ });
+ }
+ }
+
+ [Theory]
+ [InlineData("PooledConnectionLifetime")]
+ [InlineData("PooledConnectionIdleTimeout")]
+ public async Task SmallConnectionTimeout_SubsequentRequestUsesDifferentConnection(string timeoutPropertyName)
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ switch (timeoutPropertyName)
+ {
+ case "PooledConnectionLifetime": handler.PooledConnectionLifetime = TimeSpan.FromMilliseconds(1); break;
+ case "PooledConnectionIdleTimeout": handler.PooledConnectionLifetime = TimeSpan.FromMilliseconds(1); break;
+ default: throw new ArgumentOutOfRangeException(nameof(timeoutPropertyName));
+ }
+
+ using (HttpClient client = new HttpClient(handler))
+ {
+ await LoopbackServer.CreateServerAsync(async (server, uri) =>
+ {
+ // Make first request.
+ Task<string> request1 = client.GetStringAsync(uri);
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ await connection.ReadRequestHeaderAndSendResponseAsync();
+ await request1;
+
+ // Wait a small amount of time before making the second request, to give the first request time to timeout.
+ await Task.Delay(100);
+
+ // Make second request and expect it to be served from a different connection.
+ Task<string> request2 = client.GetStringAsync(uri);
+ await server.AcceptConnectionAsync(async connection2 =>
+ {
+ await connection2.ReadRequestHeaderAndSendResponseAsync();
+ await request2;
+ });
+ });
+ });
+ }
+ }
+ }
+
+ [OuterLoop]
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public void ConnectionsPooledThenDisposed_NoUnobservedTaskExceptions(bool secure)
+ {
+ RemoteInvoke(async secureString =>
+ {
+ var releaseServer = new TaskCompletionSource<bool>();
+ await LoopbackServer.CreateClientAndServerAsync(async uri =>
+ {
+ using (var handler = new SocketsHttpHandler())
+ using (var client = new HttpClient(handler))
+ {
+ handler.SslOptions.RemoteCertificateValidationCallback = delegate { return true; };
+ handler.PooledConnectionLifetime = TimeSpan.FromMilliseconds(1);
+
+ var exceptions = new List<Exception>();
+ TaskScheduler.UnobservedTaskException += (s, e) => exceptions.Add(e.Exception);
+
+ await client.GetStringAsync(uri);
+ await Task.Delay(10); // any value >= the lifetime
+ Task ignored = client.GetStringAsync(uri); // force the pool to look for the previous connection and find it's too old
+ await Task.Delay(100); // give some time for the connection close to fail pending reads
+
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+
+ // Note that there are race conditions here such that we may not catch every failure,
+ // and thus could have some false negatives, but there won't be any false positives.
+ Assert.True(exceptions.Count == 0, string.Concat(exceptions));
+
+ releaseServer.SetResult(true);
+ }
+ }, server => server.AcceptConnectionAsync(async connection =>
+ {
+ await connection.ReadRequestHeaderAndSendResponseAsync(content: "hello world");
+ await releaseServer.Task;
+ }),
+ new LoopbackServer.Options { UseSsl = bool.Parse(secureString) });
+ return SuccessExitCode;
+ }, secure.ToString()).Dispose();
+ }
+ }
+
+ public sealed class SocketsHttpHandler_PublicAPIBehavior_Test
+ {
+ private static async Task IssueRequestAsync(HttpMessageHandler handler)
+ {
+ using (var c = new HttpMessageInvoker(handler, disposeHandler: false))
+ await Assert.ThrowsAnyAsync<Exception>(() =>
+ c.SendAsync(new HttpRequestMessage(HttpMethod.Get, new Uri("/shouldquicklyfail", UriKind.Relative)), default));
+ }
+
+ [Fact]
+ public void AllowAutoRedirect_GetSet_Roundtrips()
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ Assert.True(handler.AllowAutoRedirect);
+
+ handler.AllowAutoRedirect = true;
+ Assert.True(handler.AllowAutoRedirect);
+
+ handler.AllowAutoRedirect = false;
+ Assert.False(handler.AllowAutoRedirect);
+ }
+ }
+
+ [Fact]
+ public void AutomaticDecompression_GetSet_Roundtrips()
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ Assert.Equal(DecompressionMethods.None, handler.AutomaticDecompression);
+
+ handler.AutomaticDecompression = DecompressionMethods.GZip;
+ Assert.Equal(DecompressionMethods.GZip, handler.AutomaticDecompression);
+
+ handler.AutomaticDecompression = DecompressionMethods.Deflate;
+ Assert.Equal(DecompressionMethods.Deflate, handler.AutomaticDecompression);
+
+ handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
+ Assert.Equal(DecompressionMethods.GZip | DecompressionMethods.Deflate, handler.AutomaticDecompression);
+ }
+ }
+
+ [Fact]
+ public void CookieContainer_GetSet_Roundtrips()
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ CookieContainer container = handler.CookieContainer;
+ Assert.Same(container, handler.CookieContainer);
+
+ var newContainer = new CookieContainer();
+ handler.CookieContainer = newContainer;
+ Assert.Same(newContainer, handler.CookieContainer);
+ }
+ }
+
+ [Fact]
+ public void Credentials_GetSet_Roundtrips()
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ Assert.Null(handler.Credentials);
+
+ var newCredentials = new NetworkCredential("username", "password");
+ handler.Credentials = newCredentials;
+ Assert.Same(newCredentials, handler.Credentials);
+ }
+ }
+
+ [Fact]
+ public void DefaultProxyCredentials_GetSet_Roundtrips()
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ Assert.Null(handler.DefaultProxyCredentials);
+
+ var newCredentials = new NetworkCredential("username", "password");
+ handler.DefaultProxyCredentials = newCredentials;
+ Assert.Same(newCredentials, handler.DefaultProxyCredentials);
+ }
+ }
+
+ [Fact]
+ public void MaxAutomaticRedirections_GetSet_Roundtrips()
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ Assert.Equal(50, handler.MaxAutomaticRedirections);
+
+ handler.MaxAutomaticRedirections = int.MaxValue;
+ Assert.Equal(int.MaxValue, handler.MaxAutomaticRedirections);
+
+ handler.MaxAutomaticRedirections = 1;
+ Assert.Equal(1, handler.MaxAutomaticRedirections);
+
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => handler.MaxAutomaticRedirections = 0);
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => handler.MaxAutomaticRedirections = -1);
+ }
+ }
+
+ [Fact]
+ public void MaxConnectionsPerServer_GetSet_Roundtrips()
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ Assert.Equal(int.MaxValue, handler.MaxConnectionsPerServer);
+
+ handler.MaxConnectionsPerServer = int.MaxValue;
+ Assert.Equal(int.MaxValue, handler.MaxConnectionsPerServer);
+
+ handler.MaxConnectionsPerServer = 1;
+ Assert.Equal(1, handler.MaxConnectionsPerServer);
+
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => handler.MaxConnectionsPerServer = 0);
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => handler.MaxConnectionsPerServer = -1);
+ }
+ }
+
+ [Fact]
+ public void MaxResponseHeadersLength_GetSet_Roundtrips()
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ Assert.Equal(64, handler.MaxResponseHeadersLength);
+
+ handler.MaxResponseHeadersLength = int.MaxValue;
+ Assert.Equal(int.MaxValue, handler.MaxResponseHeadersLength);
+
+ handler.MaxResponseHeadersLength = 1;
+ Assert.Equal(1, handler.MaxResponseHeadersLength);
+
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => handler.MaxResponseHeadersLength = 0);
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => handler.MaxResponseHeadersLength = -1);
+ }
+ }
+
+ [Fact]
+ public void PreAuthenticate_GetSet_Roundtrips()
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ Assert.False(handler.PreAuthenticate);
+
+ handler.PreAuthenticate = false;
+ Assert.False(handler.PreAuthenticate);
+
+ handler.PreAuthenticate = true;
+ Assert.True(handler.PreAuthenticate);
+ }
+ }
+
+ [Fact]
+ public void PooledConnectionIdleTimeout_GetSet_Roundtrips()
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ Assert.Equal(TimeSpan.FromMinutes(2), handler.PooledConnectionIdleTimeout);
+
+ handler.PooledConnectionIdleTimeout = Timeout.InfiniteTimeSpan;
+ Assert.Equal(Timeout.InfiniteTimeSpan, handler.PooledConnectionIdleTimeout);
+
+ handler.PooledConnectionIdleTimeout = TimeSpan.FromSeconds(0);
+ Assert.Equal(TimeSpan.FromSeconds(0), handler.PooledConnectionIdleTimeout);
+
+ handler.PooledConnectionIdleTimeout = TimeSpan.FromSeconds(1);
+ Assert.Equal(TimeSpan.FromSeconds(1), handler.PooledConnectionIdleTimeout);
+
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => handler.PooledConnectionIdleTimeout = TimeSpan.FromSeconds(-2));
+ }
+ }
+
+ [Fact]
+ public void PooledConnectionLifetime_GetSet_Roundtrips()
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ Assert.Equal(Timeout.InfiniteTimeSpan, handler.PooledConnectionLifetime);
+
+ handler.PooledConnectionLifetime = Timeout.InfiniteTimeSpan;
+ Assert.Equal(Timeout.InfiniteTimeSpan, handler.PooledConnectionLifetime);
+
+ handler.PooledConnectionLifetime = TimeSpan.FromSeconds(0);
+ Assert.Equal(TimeSpan.FromSeconds(0), handler.PooledConnectionLifetime);
+
+ handler.PooledConnectionLifetime = TimeSpan.FromSeconds(1);
+ Assert.Equal(TimeSpan.FromSeconds(1), handler.PooledConnectionLifetime);
+
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => handler.PooledConnectionLifetime = TimeSpan.FromSeconds(-2));
+ }
+ }
+
+ [Fact]
+ public void Properties_Roundtrips()
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ IDictionary<string, object> props = handler.Properties;
+ Assert.NotNull(props);
+ Assert.Empty(props);
+
+ props.Add("hello", "world");
+ Assert.Equal(1, props.Count);
+ Assert.Equal("world", props["hello"]);
+ }
+ }
+
+ [Fact]
+ public void Proxy_GetSet_Roundtrips()
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ Assert.Null(handler.Proxy);
+
+ var proxy = new WebProxy();
+ handler.Proxy = proxy;
+ Assert.Same(proxy, handler.Proxy);
+ }
+ }
+
+ [Fact]
+ public void SslOptions_GetSet_Roundtrips()
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ SslClientAuthenticationOptions options = handler.SslOptions;
+ Assert.NotNull(options);
+
+ Assert.True(options.AllowRenegotiation);
+ Assert.Null(options.ApplicationProtocols);
+ Assert.Equal(X509RevocationMode.NoCheck, options.CertificateRevocationCheckMode);
+ Assert.Null(options.ClientCertificates);
+ Assert.Equal(SslProtocols.None, options.EnabledSslProtocols);
+ Assert.Equal(EncryptionPolicy.RequireEncryption, options.EncryptionPolicy);
+ Assert.Null(options.LocalCertificateSelectionCallback);
+ Assert.Null(options.RemoteCertificateValidationCallback);
+ Assert.Null(options.TargetHost);
+
+ Assert.Same(options, handler.SslOptions);
+
+ var newOptions = new SslClientAuthenticationOptions();
+ handler.SslOptions = newOptions;
+ Assert.Same(newOptions, handler.SslOptions);
+ }
+ }
+
+ [Fact]
+ public void UseCookies_GetSet_Roundtrips()
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ Assert.True(handler.UseCookies);
+
+ handler.UseCookies = true;
+ Assert.True(handler.UseCookies);
+
+ handler.UseCookies = false;
+ Assert.False(handler.UseCookies);
+ }
+ }
+
+ [Fact]
+ public void UseProxy_GetSet_Roundtrips()
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ Assert.True(handler.UseProxy);
+
+ handler.UseProxy = false;
+ Assert.False(handler.UseProxy);
+
+ handler.UseProxy = true;
+ Assert.True(handler.UseProxy);
+ }
+ }
+
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task AfterDisposeSendAsync_GettersUsable_SettersThrow(bool dispose)
+ {
+ using (var handler = new SocketsHttpHandler())
+ {
+ Type expectedExceptionType;
+ if (dispose)
+ {
+ handler.Dispose();
+ expectedExceptionType = typeof(ObjectDisposedException);
+ }
+ else
+ {
+ await IssueRequestAsync(handler);
+ expectedExceptionType = typeof(InvalidOperationException);
+ }
+
+ Assert.True(handler.AllowAutoRedirect);
+ Assert.Equal(DecompressionMethods.None, handler.AutomaticDecompression);
+ Assert.NotNull(handler.CookieContainer);
+ Assert.Null(handler.Credentials);
+ Assert.Null(handler.DefaultProxyCredentials);
+ Assert.Equal(50, handler.MaxAutomaticRedirections);
+ Assert.Equal(int.MaxValue, handler.MaxConnectionsPerServer);
+ Assert.Equal(64, handler.MaxResponseHeadersLength);
+ Assert.False(handler.PreAuthenticate);
+ Assert.Equal(TimeSpan.FromMinutes(2), handler.PooledConnectionIdleTimeout);
+ Assert.Equal(Timeout.InfiniteTimeSpan, handler.PooledConnectionLifetime);
+ Assert.NotNull(handler.Properties);
+ Assert.Null(handler.Proxy);
+ Assert.NotNull(handler.SslOptions);
+ Assert.True(handler.UseCookies);
+ Assert.True(handler.UseProxy);
+
+ Assert.Throws(expectedExceptionType, () => handler.AllowAutoRedirect = false);
+ Assert.Throws(expectedExceptionType, () => handler.AutomaticDecompression = DecompressionMethods.GZip);
+ Assert.Throws(expectedExceptionType, () => handler.CookieContainer = new CookieContainer());
+ Assert.Throws(expectedExceptionType, () => handler.Credentials = new NetworkCredential("anotheruser", "anotherpassword"));
+ Assert.Throws(expectedExceptionType, () => handler.DefaultProxyCredentials = new NetworkCredential("anotheruser", "anotherpassword"));
+ Assert.Throws(expectedExceptionType, () => handler.MaxAutomaticRedirections = 2);
+ Assert.Throws(expectedExceptionType, () => handler.MaxConnectionsPerServer = 2);
+ Assert.Throws(expectedExceptionType, () => handler.MaxResponseHeadersLength = 2);
+ Assert.Throws(expectedExceptionType, () => handler.PreAuthenticate = false);
+ Assert.Throws(expectedExceptionType, () => handler.PooledConnectionIdleTimeout = TimeSpan.FromSeconds(2));
+ Assert.Throws(expectedExceptionType, () => handler.PooledConnectionLifetime = TimeSpan.FromSeconds(2));
+ Assert.Throws(expectedExceptionType, () => handler.Proxy = new WebProxy());
+ Assert.Throws(expectedExceptionType, () => handler.SslOptions = new SslClientAuthenticationOptions());
+ Assert.Throws(expectedExceptionType, () => handler.UseCookies = false);
+ Assert.Throws(expectedExceptionType, () => handler.UseProxy = false);
+ }
+ }
+ }
+
+ public sealed class SocketsHttpHandler_ExternalConfiguration_Test : HttpClientTestBase
+ {
+ private const string EnvironmentVariableSettingName = "DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER";
+ private const string AppContextSettingName = "System.Net.Http.UseSocketsHttpHandler";
+
+ private static bool UseSocketsHttpHandlerEnvironmentVariableIsNotSet =>
+ string.IsNullOrEmpty(Environment.GetEnvironmentVariable(EnvironmentVariableSettingName));
+
+ [ConditionalTheory(nameof(UseSocketsHttpHandlerEnvironmentVariableIsNotSet))]
+ [InlineData("true", true)]
+ [InlineData("TRUE", true)]
+ [InlineData("tRuE", true)]
+ [InlineData("1", true)]
+ [InlineData("0", false)]
+ [InlineData("false", false)]
+ [InlineData("helloworld", true)]
+ [InlineData("", true)]
+ public void HttpClientHandler_SettingEnvironmentVariableChangesDefault(string envVarValue, bool expectedUseSocketsHandler)
+ {
+ RemoteInvoke((innerEnvVarValue, innerExpectedUseSocketsHandler) =>
+ {
+ Environment.SetEnvironmentVariable(EnvironmentVariableSettingName, innerEnvVarValue);
+ using (var handler = new HttpClientHandler())
+ {
+ Assert.Equal(bool.Parse(innerExpectedUseSocketsHandler), IsSocketsHttpHandler(handler));
+ }
+ return SuccessExitCode;
+ }, envVarValue, expectedUseSocketsHandler.ToString()).Dispose();
+ }
+
+ [Fact]
+ public void HttpClientHandler_SettingAppContextChangesDefault()
+ {
+ RemoteInvoke(() =>
+ {
+ AppContext.SetSwitch(AppContextSettingName, isEnabled: true);
+ using (var handler = new HttpClientHandler())
+ {
+ Assert.True(IsSocketsHttpHandler(handler));
+ }
+
+ AppContext.SetSwitch(AppContextSettingName, isEnabled: false);
+ using (var handler = new HttpClientHandler())
+ {
+ Assert.False(IsSocketsHttpHandler(handler));
+ }
+
+ return SuccessExitCode;
+ }).Dispose();
+ }
+
+ [Fact]
+ public void HttpClientHandler_AppContextOverridesEnvironmentVariable()
+ {
+ RemoteInvoke(() =>
+ {
+ Environment.SetEnvironmentVariable(EnvironmentVariableSettingName, "true");
+ using (var handler = new HttpClientHandler())
+ {
+ Assert.True(IsSocketsHttpHandler(handler));
+ }
+
+ AppContext.SetSwitch(AppContextSettingName, isEnabled: false);
+ using (var handler = new HttpClientHandler())
+ {
+ Assert.False(IsSocketsHttpHandler(handler));
+ }
+
+ AppContext.SetSwitch(AppContextSettingName, isEnabled: true);
+ Environment.SetEnvironmentVariable(EnvironmentVariableSettingName, null);
+ using (var handler = new HttpClientHandler())
+ {
+ Assert.True(IsSocketsHttpHandler(handler));
+ }
+
+ return SuccessExitCode;
+ }).Dispose();
+ }
+ }
+}
diff --git a/src/System.Net.Http/tests/FunctionalTests/StreamContentTest.cs b/src/System.Net.Http/tests/FunctionalTests/StreamContentTest.cs
index d512edbcc5..239154d856 100644
--- a/src/System.Net.Http/tests/FunctionalTests/StreamContentTest.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/StreamContentTest.cs
@@ -33,6 +33,12 @@ namespace System.Net.Http.Functional.Tests
}
[Fact]
+ public void Ctor_NullStreamAndZeroBufferSize_ThrowsArgumentNullException()
+ {
+ Assert.Throws<ArgumentNullException>(() => new StreamContent(null, 0));
+ }
+
+ [Fact]
public void ContentLength_SetStreamSupportingSeeking_StreamLengthMatchesHeaderValue()
{
var source = new MockStream(new byte[10], true, true); // Supports seeking.
diff --git a/src/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj b/src/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
index 08a2a2a241..6e9a8807ef 100644
--- a/src/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
+++ b/src/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
@@ -18,6 +18,12 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Release|AnyCPU'" />
<ItemGroup>
+ <Compile Include="$(CommonPath)\Interop\Unix\Interop.Libraries.cs" Condition="'$(TargetsUnix)' == 'true'">
+ <Link>Common\Interop\Unix\System.Net.Http.Native\Interop.VersionInfo.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Unix\System.Net.Http.Native\Interop.VersionInfo.cs" Condition="'$(TargetsUnix)' == 'true'">
+ <Link>Common\Interop\Unix\System.Net.Http.Native\Interop.VersionInfo.cs</Link>
+ </Compile>
<Compile Include="$(CommonTestPath)\System\Buffers\NativeOwnedMemory.cs">
<Link>Common\System\Buffers\NativeOwnedMemory.cs</Link>
</Compile>
@@ -63,19 +69,25 @@
<Compile Include="$(CommonTestPath)\System\Net\Http\LoopbackServer.cs">
<Link>Common\System\Net\Http\LoopbackServer.cs</Link>
</Compile>
+ <Compile Include="$(CommonTestPath)\System\Net\Http\LoopbackServer.AuthenticationHelpers.cs">
+ <Link>Common\System\Net\Http\LoopbackServer.AuthenticationHelpers.cs</Link>
+ </Compile>
<Compile Include="$(CommonTestPath)\System\Threading\Tasks\TaskTimeoutExtensions.cs">
<Link>Common\System\Threading\Tasks\TaskTimeoutExtensions.cs</Link>
</Compile>
<Compile Include="ByteArrayContentTest.cs" />
- <Compile Include="CancellationTest.cs" />
<Compile Include="ChannelBindingAwareContent.cs" />
+ <Compile Include="DribbleStream.cs" />
<Compile Include="CustomContent.cs" />
<Compile Include="DelegatingHandlerTest.cs" />
<Compile Include="FakeDiagnosticSourceListenerObserver.cs" />
<Compile Include="FormUrlEncodedContentTest.cs" />
+ <Compile Include="HttpClientHandlerTest.Authentication.cs" />
<Compile Include="HttpClientHandlerTest.cs" />
+ <Compile Include="HttpClientHandlerTest.Cancellation.cs" />
<Compile Include="HttpClientHandlerTest.ClientCertificates.cs" />
<Compile Include="HttpClientHandlerTest.DefaultProxyCredentials.cs" />
+ <Compile Include="HttpClientHandlerTest.ResponseDrain.cs" />
<Compile Include="HttpClientHandlerTest.MaxConnectionsPerServer.cs" />
<Compile Include="HttpClientHandlerTest.MaxResponseHeadersLength.cs" />
<Compile Include="HttpClientHandlerTest.ServerCertificates.cs" />
@@ -89,9 +101,13 @@
<Compile Include="HttpClientTest.cs" />
<Compile Include="HttpClientEKUTest.cs" />
<Compile Include="HttpClientMiniStressTest.cs" />
+ <Compile Include="HttpClient.SelectedSitesTest.cs" />
<Compile Include="HttpContentTest.cs" />
<Compile Include="HttpMessageInvokerTest.cs" />
<Compile Include="HttpMethodTest.cs" />
+ <Compile Include="HttpCookieProtocolTests.cs" />
+ <Compile Include="HttpRetryProtocolTests.cs" />
+ <Compile Include="IdnaProtocolTests.cs" />
<Compile Include="HttpProtocolTests.cs" />
<Compile Include="HttpRequestMessageTest.cs" />
<Compile Include="HttpResponseMessageTest.cs" />
@@ -99,6 +115,7 @@
<Compile Include="MessageProcessingHandlerTest.cs" />
<Compile Include="MultipartContentTest.cs" />
<Compile Include="MultipartFormDataContentTest.cs" />
+ <Compile Include="PlatformHandlerTest.cs" />
<Compile Include="PostScenarioTest.cs" />
<Compile Include="RepeatedFlushContent.cs" />
<Compile Include="ResponseStreamTest.cs" />
@@ -110,11 +127,12 @@
<Compile Include="DefaultCredentialsTest.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp'">
- <Compile Include="ManagedHandlerTest.cs" />
<Compile Include="HttpClientHandlerTest.AcceptAllCerts.cs" />
- <Compile Include="ReadOnlyMemoryContentTest.cs" />
+ <Compile Include="HttpClientHandlerTest.Decompression.cs" />
<Compile Include="HttpClientTest.netcoreapp.cs" />
<Compile Include="HttpMethodTest.netcoreapp.cs" />
+ <Compile Include="ReadOnlyMemoryContentTest.cs" />
+ <Compile Include="SocketsHttpHandlerTest.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' == 'netstandard'">
<Compile Include="$(CommonTestPath)\System\IO\StreamSpanExtensions.netstandard.cs">
@@ -140,5 +158,13 @@
<ItemGroup Condition="'$(TargetsOSX)'=='true'">
<TestCommandLines Include="ulimit -Sn 4096" />
</ItemGroup>
+ <ItemGroup >
+ <EmbeddedResource Include="SelectedSitesTest.txt">
+ <Link>SelectedSitesTest.txt</Link>
+ </EmbeddedResource>
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project>
+</Project> \ No newline at end of file
diff --git a/src/System.Net.Http/tests/FunctionalTests/TestHelper.cs b/src/System.Net.Http/tests/FunctionalTests/TestHelper.cs
index 0f7820f093..9bf6f216d1 100644
--- a/src/System.Net.Http/tests/FunctionalTests/TestHelper.cs
+++ b/src/System.Net.Http/tests/FunctionalTests/TestHelper.cs
@@ -3,17 +3,20 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
+using System.Linq;
+using System.Net.NetworkInformation;
+using System.Net.Security;
using System.Security.Cryptography;
+using System.Security.Cryptography.X509Certificates;
using System.Text;
-using System.Threading;
using System.Threading.Tasks;
using Xunit;
namespace System.Net.Http.Functional.Tests
{
- // TODO (#5525): This class will eventually be moved to Common once the HttpTestServers are finalized.
public static class TestHelper
{
+ public static int PassingTestTimeoutMilliseconds => 60 * 1000;
public static bool JsonMessageContainsKeyValue(string message, string key, string value)
{
// TODO (#5525): Align with the rest of tests w.r.t response parsing once the test server is finalized.
@@ -83,29 +86,26 @@ namespace System.Net.Http.Functional.Tests
public static Task WhenAllCompletedOrAnyFailed(params Task[] tasks)
{
- var tcs = new TaskCompletionSource<bool>();
-
- int remaining = tasks.Length;
- foreach (var task in tasks)
- {
- task.ContinueWith(t =>
- {
- if (t.IsFaulted)
- {
- tcs.SetException(t.Exception.InnerExceptions);
- }
- else if (t.IsCanceled)
- {
- tcs.SetCanceled();
- }
- else if (Interlocked.Decrement(ref remaining) == 0)
- {
- tcs.SetResult(true);
- }
- }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
- }
+ return TaskTimeoutExtensions.WhenAllOrAnyFailed(tasks);
+ }
- return tcs.Task;
+ public static Task WhenAllCompletedOrAnyFailedWithTimeout(int timeoutInMilliseconds, params Task[] tasks)
+ {
+ return TaskTimeoutExtensions.WhenAllOrAnyFailed(tasks, timeoutInMilliseconds);
}
+
+#if netcoreapp
+ public static Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> AllowAllCertificates = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
+#else
+ public static Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> AllowAllCertificates = (_, __, ___, ____) => true;
+#endif
+
+ public static IPAddress GetIPv6LinkLocalAddress() =>
+ NetworkInterface
+ .GetAllNetworkInterfaces()
+ .SelectMany(i => i.GetIPProperties().UnicastAddresses)
+ .Select(a => a.Address)
+ .Where(a => a.IsIPv6LinkLocal)
+ .FirstOrDefault();
}
}
diff --git a/src/System.Net.Http/tests/UnitTests/DigestAuthenticationTests.cs b/src/System.Net.Http/tests/UnitTests/DigestAuthenticationTests.cs
index 6758686447..f339ba78e4 100644
--- a/src/System.Net.Http/tests/UnitTests/DigestAuthenticationTests.cs
+++ b/src/System.Net.Http/tests/UnitTests/DigestAuthenticationTests.cs
@@ -12,6 +12,7 @@ namespace System.Net.Http.Tests
{
private static readonly List<string> s_keyListWithCountTwo = new List<string> { "key1", "key2" };
private static readonly List<string> s_valueListWithCountTwo = new List<string> { "value1", "value2" };
+ private static readonly List<string> s_listWithCountOne = new List<string> { "item1" };
private static readonly List<string> s_emptyStringList = new List<string>();
[Theory]
@@ -30,8 +31,8 @@ namespace System.Net.Http.Tests
yield return new object[] { "key1=value1,key2=value2", s_keyListWithCountTwo, s_valueListWithCountTwo };
yield return new object[] { "\tkey1===value1,key2 \t===\tvalue2", s_keyListWithCountTwo, s_valueListWithCountTwo };
yield return new object[] { " key1 = value1, key2 = value2,", s_keyListWithCountTwo, s_valueListWithCountTwo };
- yield return new object[] { "key1 === value1,key2=, value2", s_keyListWithCountTwo, new List<string> { "value1", string.Empty } };
- yield return new object[] { "key1,==value1,,, key2=\"value2\", key3 m", new List<string> { "key1,", "key2" }, s_valueListWithCountTwo };
+ yield return new object[] { "item1 === item1,key2=, value2", s_listWithCountOne, s_listWithCountOne };
+ yield return new object[] { "item1,==item1,,, key2=\"value2\", key3 m", new List<string> { "item1," }, s_listWithCountOne };
yield return new object[] { "key1= \"value1 \",key2 = \"v alu#e2\" ,", s_keyListWithCountTwo, new List<string> { "value1 ", "v alu#e2"} };
yield return new object[] { "key1 ", s_emptyStringList, s_emptyStringList };
yield return new object[] { "=====", s_emptyStringList, s_emptyStringList };
@@ -40,5 +41,20 @@ namespace System.Net.Http.Tests
yield return new object[] { "=value1,key2=,", s_emptyStringList, s_emptyStringList };
yield return new object[] { "key1\tm= value1", s_emptyStringList, s_emptyStringList };
}
+
+ [Theory]
+ [InlineData("realm=\"NetCore\", nonce=\"qMRqWgAAAAAQMjIABgAAAFwEiEwAAAAA\", qop=\"auth\", stale=false", true)]
+ [InlineData("realm=\"NetCore\", nonce=\"qMRqWgAAAAAQMjIABgAAAFwEiEwAAAAA\"", true)]
+ [InlineData("nonce=\"qMRqWgAAAAAQMjIABgAAAFwEiEwAAAAA\", qop=\"auth\", stale=false", false)]
+ [InlineData("realm=\"NetCore\", qop=\"auth\", stale=false", false)]
+ public async void DigestResponse_AuthToken_Handling(string response, bool expectedResult)
+ {
+ NetworkCredential credential = new NetworkCredential("foo","bar");
+ AuthenticationHelper.DigestResponse digestResponse = new AuthenticationHelper.DigestResponse(response);
+ HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "http://microsoft.com/");
+ string parameter = await AuthenticationHelper.GetDigestTokenForCredential(credential, request, digestResponse).ConfigureAwait(false);
+
+ Assert.Equal(expectedResult, parameter != null);
+ }
}
}
diff --git a/src/System.Net.Http/tests/UnitTests/HttpEnvironmentProxyTest.cs b/src/System.Net.Http/tests/UnitTests/HttpEnvironmentProxyTest.cs
new file mode 100644
index 0000000000..7f7b8a8317
--- /dev/null
+++ b/src/System.Net.Http/tests/UnitTests/HttpEnvironmentProxyTest.cs
@@ -0,0 +1,208 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Net.Http;
+using Xunit;
+using Xunit.Abstractions;
+using System.Diagnostics;
+
+namespace System.Net.Http.Tests
+{
+ public class HttpEnvironmentProxyTest : RemoteExecutorTestBase
+ {
+ private readonly ITestOutputHelper _output;
+ private static readonly Uri fooHttp = new Uri("http://foo.com");
+ private static readonly Uri fooHttps = new Uri("https://foo.com");
+
+ // This will clean specific environmental variables
+ // to be sure they do not interfere with the test.
+ private void CleanEnv()
+ {
+ List<string> vars = new List<string>() { "http_proxy", "HTTPS_PROXY", "https_proxy",
+ "all_proxy", "ALL_PROXY",
+ "NO_PROXY" };
+ foreach (string v in vars)
+ {
+ Environment.SetEnvironmentVariable(v, null);
+ }
+ }
+
+ public HttpEnvironmentProxyTest(ITestOutputHelper output)
+ {
+ _output = output;
+ CleanEnv();
+ }
+
+ [Fact]
+ public void HttpProxy_EnvironmentProxy_Loaded()
+ {
+ RemoteInvoke(() =>
+ {
+
+ IWebProxy p;
+ Uri u;
+
+ // It should not return object if there are no variables set.
+ Assert.False(HttpEnvironmentProxy.TryCreate(out p));
+
+ Environment.SetEnvironmentVariable("all_proxy", "http://1.1.1.1:3000");
+ Assert.True(HttpEnvironmentProxy.TryCreate(out p));
+ Assert.NotNull(p);
+ Assert.Null(p.Credentials);
+
+ u = p.GetProxy(fooHttp);
+ Assert.True(u != null && u.Host == "1.1.1.1");
+ u = p.GetProxy(fooHttps);
+ Assert.True(u != null && u.Host == "1.1.1.1");
+
+ Environment.SetEnvironmentVariable("http_proxy", "http://1.1.1.2:3001");
+ Assert.True(HttpEnvironmentProxy.TryCreate(out p));
+ Assert.NotNull(p);
+
+ // Protocol specific variables should take precedence over all_
+ // and https should still use all_proxy.
+ u = p.GetProxy(fooHttp);
+ Assert.True(u != null && u.Host == "1.1.1.2" && u.Port == 3001);
+ u = p.GetProxy(fooHttps);
+ Assert.True(u != null && u.Host == "1.1.1.1" && u.Port == 3000);
+
+ // Set https to invalid strings and use only IP & port for http.
+ Environment.SetEnvironmentVariable("http_proxy", "1.1.1.3:3003");
+ Environment.SetEnvironmentVariable("https_proxy", "ab!cd");
+ Assert.True(HttpEnvironmentProxy.TryCreate(out p));
+ Assert.NotNull(p);
+
+ u = p.GetProxy(fooHttp);
+ Assert.True(u != null && u.Host == "1.1.1.3" && u.Port == 3003);
+ u = p.GetProxy(fooHttps);
+ Assert.True(u != null && u.Host == "1.1.1.1" && u.Port == 3000);
+
+ // Try valid URI with unsupported protocol. It will be ignored
+ // to mimic curl behavior.
+ Environment.SetEnvironmentVariable("https_proxy", "socks5://1.1.1.4:3004");
+ Assert.True(HttpEnvironmentProxy.TryCreate(out p));
+ Assert.NotNull(p);
+ u = p.GetProxy(fooHttps);
+ Assert.True(u != null && u.Host == "1.1.1.1" && u.Port == 3000);
+
+ // Set https to valid URI but different from http.
+ Environment.SetEnvironmentVariable("https_proxy", "http://1.1.1.5:3005");
+ Assert.True(HttpEnvironmentProxy.TryCreate(out p));
+ Assert.NotNull(p);
+
+ u = p.GetProxy(fooHttp);
+ Assert.True(u != null && u.Host == "1.1.1.3" && u.Port == 3003);
+ u = p.GetProxy(fooHttps);
+ Assert.True(u != null && u.Host == "1.1.1.5" && u.Port == 3005);
+
+ return SuccessExitCode;
+ }).Dispose();
+ }
+
+ [Theory]
+ [InlineData("1.1.1.5", "1.1.1.5", "80", null, null)]
+ [InlineData("http://1.1.1.5:3005", "1.1.1.5", "3005", null, null)]
+ [InlineData("http://foo@1.1.1.5", "1.1.1.5", "80", "foo", "")]
+ [InlineData("http://[::1]:80", "[::1]", "80", null, null)]
+ [InlineData("foo:bar@[::1]:3128", "[::1]", "3128", "foo", "bar")]
+ [InlineData("foo:Pass$!#\\.$@127.0.0.1:3128", "127.0.0.1", "3128", "foo", "Pass$!#\\.$")]
+ [InlineData("[::1]", "[::1]", "80", null, null)]
+ [InlineData("domain\\foo:bar@1.1.1.1", "1.1.1.1", "80", "foo", "bar")]
+ [InlineData("domain%5Cfoo:bar@1.1.1.1", "1.1.1.1", "80", "foo", "bar")]
+ [InlineData("HTTP://ABC.COM/", "abc.com", "80", null, null)]
+ public void HttpProxy_Uri_Parsing(string _input, string _host, string _port, string _user , string _password)
+ {
+ RemoteInvoke((input, host, port, user, password) =>
+ {
+ // Remote exec does not allow to pass null at this moment.
+ if (user == "null")
+ {
+ user = null;
+ }
+ if (password == "null")
+ {
+ password = null;
+ }
+
+ Environment.SetEnvironmentVariable("all_proxy", input);
+ IWebProxy p;
+ Uri u;
+
+ Assert.True(HttpEnvironmentProxy.TryCreate(out p));
+ Assert.NotNull(p);
+
+ u = p.GetProxy(fooHttp);
+ Assert.Equal(host, u.Host);
+ Assert.Equal(Convert.ToInt32(port), u.Port);
+
+ if (user != null)
+ {
+ NetworkCredential nc = p.Credentials.GetCredential(u, "Basic");
+ Assert.NotNull(nc);
+ Assert.Equal(user, nc.UserName);
+ Assert.Equal(password, nc.Password);
+ }
+
+ return SuccessExitCode;
+ }, _input, _host, _port, _user ?? "null" , _password ?? "null").Dispose();
+ }
+
+ [Fact]
+ public void HttpProxy_CredentialParsing_Basic()
+ {
+ RemoteInvoke(() =>
+ {
+ IWebProxy p;
+
+ Environment.SetEnvironmentVariable("all_proxy", "http://foo:bar@1.1.1.1:3000");
+ Assert.True(HttpEnvironmentProxy.TryCreate(out p));
+ Assert.NotNull(p);
+ Assert.NotNull(p.Credentials);
+
+ // Use user only without password.
+ Environment.SetEnvironmentVariable("all_proxy", "http://foo@1.1.1.1:3000");
+ Assert.True(HttpEnvironmentProxy.TryCreate(out p));
+ Assert.NotNull(p);
+ Assert.NotNull(p.Credentials);
+
+ // Use different user for http and https
+ Environment.SetEnvironmentVariable("https_proxy", "http://foo1:bar1@1.1.1.1:3000");
+ Assert.True(HttpEnvironmentProxy.TryCreate(out p));
+ Assert.NotNull(p);
+ Uri u = p.GetProxy(fooHttp);
+ Assert.NotNull(p.Credentials.GetCredential(u, "Basic"));
+ u = p.GetProxy(fooHttps);
+ Assert.NotNull(p.Credentials.GetCredential(u, "Basic"));
+ // This should not match Proxy Uri
+ Assert.Null(p.Credentials.GetCredential(fooHttp, "Basic"));
+ Assert.Null(p.Credentials.GetCredential(null, null));
+
+ return SuccessExitCode;
+ }).Dispose();
+ }
+
+ [Fact]
+ public void HttpProxy_Exceptions_Match()
+ {
+ RemoteInvoke(() =>
+ {
+ IWebProxy p;
+
+ Environment.SetEnvironmentVariable("no_proxy", ".test.com,, foo.com");
+ Environment.SetEnvironmentVariable("all_proxy", "http://foo:bar@1.1.1.1:3000");
+ Assert.True(HttpEnvironmentProxy.TryCreate(out p));
+ Assert.NotNull(p);
+
+ Assert.True(p.IsBypassed(fooHttp));
+ Assert.True(p.IsBypassed(fooHttps));
+ Assert.True(p.IsBypassed(new Uri("http://test.com")));
+ Assert.False(p.IsBypassed(new Uri("http://1test.com")));
+ Assert.True(p.IsBypassed(new Uri("http://www.test.com")));
+
+ return SuccessExitCode;
+ }).Dispose();
+ }
+ }
+}
diff --git a/src/System.Net.Http/tests/UnitTests/HttpSystemProxyTest.cs b/src/System.Net.Http/tests/UnitTests/HttpSystemProxyTest.cs
new file mode 100644
index 0000000000..c8535b797a
--- /dev/null
+++ b/src/System.Net.Http/tests/UnitTests/HttpSystemProxyTest.cs
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Net.Http;
+using Xunit;
+using Xunit.Abstractions;
+using System.Diagnostics;
+using System.Net.Http.WinHttpHandlerUnitTests;
+
+namespace System.Net.Http.Tests
+{
+ public class HttpSystemProxyTest : RemoteExecutorTestBase
+ {
+ private readonly ITestOutputHelper _output;
+ private const string FakeProxyString = "http://proxy.contoso.com";
+ private readonly Uri fakeProxyUri = new Uri("http://proxy.contoso.com");
+ private readonly Uri fooHttp = new Uri("http://foo.com");
+ private readonly Uri fooHttps = new Uri("https://foo.com");
+
+ public HttpSystemProxyTest(ITestOutputHelper output)
+ {
+ _output = output;
+ }
+
+ [Fact]
+ public void HttpProxy_SystemProxy_Loaded()
+ {
+ IWebProxy p;
+
+ FakeRegistry.Reset();
+ Assert.False(HttpSystemProxy.TryCreate(out p));
+
+ FakeRegistry.WinInetProxySettings.Proxy = FakeProxyString;
+ WinInetProxyHelper proxyHelper = new WinInetProxyHelper();
+
+ Assert.True(HttpSystemProxy.TryCreate(out p));
+ Assert.NotNull(p);
+ Assert.Equal(fakeProxyUri, p.GetProxy(fooHttp));
+ Assert.Equal(fakeProxyUri, p.GetProxy(fooHttps));
+ }
+ }
+}
diff --git a/src/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj b/src/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj
index fc3a641c44..cd2b2c90c2 100644
--- a/src/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj
+++ b/src/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj
@@ -84,8 +84,8 @@
<Compile Include="$(CommonPath)\System\Threading\Tasks\TaskToApm.cs">
<Link>ProductionCode\Common\System\Threading\Tasks\TaskToApm.cs</Link>
</Compile>
- <Compile Include="..\..\src\System\Net\Http\Managed\AuthenticationHelper.Digest.cs">
- <Link>ProductionCode\System\Net\Http\Managed\AuthenticationHelper.Digest.cs</Link>
+ <Compile Include="..\..\src\System\Net\Http\SocketsHttpHandler\AuthenticationHelper.Digest.cs">
+ <Link>ProductionCode\System\Net\Http\SocketsHttpHandler\AuthenticationHelper.Digest.cs</Link>
</Compile>
<Compile Include="..\..\src\System\Net\Http\ByteArrayContent.cs">
<Link>ProductionCode\System\Net\Http\ByteArrayContent.cs</Link>
@@ -297,9 +297,12 @@
<Compile Include="..\..\src\System\Net\Http\StringContent.cs">
<Link>ProductionCode\System\Net\Http\StringContent.cs</Link>
</Compile>
- <Compile Include="..\..\src\System\Net\Http\Unix\CurlResponseHeaderReader.cs">
+ <Compile Include="..\..\src\System\Net\Http\CurlHandler\CurlResponseHeaderReader.cs">
<Link>ProductionCode\System\Net\Http\CurlResponseHeaderReader.cs</Link>
</Compile>
+ <Compile Include="..\..\src\System\Net\Http\SocketsHttpHandler\HttpEnvironmentProxy.cs">
+ <Link>ProductionCode\System\Net\Http\SocketsHttpHandler\HttpEnvironmentProxy.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\System\Net\Http\HttpHandlerDefaults.cs">
<Link>ProductionCode\System\Net\Http\HttpHandlerDefaults.cs</Link>
</Compile>
@@ -362,11 +365,76 @@
<Compile Include="HttpRuleParserTest.cs" />
<Compile Include="MockContent.cs" />
<Compile Include="StreamToStreamCopyTest.cs" />
+ <Compile Include="HttpEnvironmentProxyTest.cs" />
+ </ItemGroup>
+ <!-- <ItemGroup Condition=" '$(TargetsWindows)' == 'true' And '$(TargetGroup)' == 'netcoreapp'"> -->
+ <ItemGroup Condition=" '$(TargetGroup)' == 'netcoreapp'">
+ <Compile Include="HttpSystemProxyTest.cs" />
+ <Compile Include="..\..\src\System\Net\Http\SocketsHttpHandler\HttpSystemProxy.cs">
+ <Link>ProductionCode\System\Net\Http\HttpSystemProxy.cs</Link>
+ </Compile>
+ <Compile Include="..\..\..\System.Net.Http.WinHttpHandler\src\System\Net\Http\WinHttpException.cs">
+ <Link>ProductionCode\System\Net\Http\WinHttpException.cs</Link>
+ </Compile>
+ <Compile Include="..\..\..\System.Net.Http.WinHttpHandler\src\System\Net\Http\WinInetProxyHelper.cs">
+ <Link>ProductionCode\System\Net\Http\WinInetProxyHelper.cs</Link>
+ </Compile>
+ <Compile Include="..\..\..\System.Net.Http.WinHttpHandler\src\System\Net\Http\WinHttpTraceHelper.cs">
+ <Link>ProductionCode\System\Net\Http\WinInetProxyHelper.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\Interop.Libraries.cs">
+ <Link>Common\Interop\Windows\Interop.Libraries.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\Crypt32\Interop.CertEnumCertificatesInStore.cs">
+ <Link>Common\Interop\Windows\Crypt32\Interop.CertEnumCertificatesInStore.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\Crypt32\Interop.certificates_types.cs">
+ <Link>Common\Interop\Windows\Crypt32\Interop.certificates_types.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\Interop.HRESULT_FROM_WIN32.cs">
+ <Link>Common\Interop\Windows\Interop.HRESULT_FROM_WIN32.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\winhttp\Interop.SafeWinHttpHandle.cs">
+ <Link>Common\Interop\Windows\winhttp\Interop.SafeWinHttpHandle.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Runtime\ExceptionServices\ExceptionStackTrace.cs">
+ <Link>Common\System\Runtime\ExceptionServices\ExceptionStackTrace.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\winhttp\Interop.winhttp_types.cs">
+ <Link>Common\Interop\Windows\winhttp\Interop.winhttp_types.cs</Link>
+ </Compile>
+ <Compile Include="..\..\..\System.Net.Http.WinHttpHandler\tests\UnitTests\FakeInterop.cs">
+ <Link>ProductionCode\System\Net\Http\WinInetProxyHelper.cs</Link>
+ </Compile>
+ <Compile Include="..\..\..\System.Net.Http.WinHttpHandler\tests\UnitTests\FakeRegistry.cs">
+ <Link>ProductionCode\System\Net\Http\WinInetProxyHelper.cs</Link>
+ </Compile>
+ <Compile Include="..\..\..\System.Net.Http.WinHttpHandler\tests\UnitTests\FakeSafeWinHttpHandle.cs">
+ <Link>ProductionCode\System\Net\Http\WinInetProxyHelper.cs</Link>
+ </Compile>
+ <Compile Include="..\..\..\System.Net.Http.WinHttpHandler\tests\UnitTests\TestControl.cs">
+ <Link>ProductionCode\System\Net\Http\WinInetProxyHelper.cs</Link>
+ </Compile>
+ <Compile Include="..\..\..\System.Net.Http.WinHttpHandler\tests\UnitTests\APICallHistory.cs">
+ <Link>ProductionCode\System\Net\Http\WinInetProxyHelper.cs</Link>
+ </Compile>
+ <Compile Include="..\..\..\System.Net.Http.WinHttpHandler\tests\UnitTests\TestServer.cs">
+ <Link>ProductionCode\System\Net\Http\WinInetProxyHelper.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' != 'netstandard' And '$(TargetGroup)' != 'netcoreapp'">
<Compile Include="$(CommonPath)\System\SerializableAttribute.cs">
<Link>Common\System\SerializableAttribute.cs</Link>
</Compile>
</ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="$(CommonTestPath)\System\Diagnostics\RemoteExecutorConsoleApp\RemoteExecutorConsoleApp.csproj">
+ <Project>{69e46a6f-9966-45a5-8945-2559fe337827}</Project>
+ <Name>RemoteExecutorConsoleApp</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.Net.HttpListener/src/System/Net/Managed/HttpListenerResponse.Managed.cs b/src/System.Net.HttpListener/src/System/Net/Managed/HttpListenerResponse.Managed.cs
index 4825b54efa..4e7063d8a4 100644
--- a/src/System.Net.HttpListener/src/System/Net/Managed/HttpListenerResponse.Managed.cs
+++ b/src/System.Net.HttpListener/src/System/Net/Managed/HttpListenerResponse.Managed.cs
@@ -315,7 +315,15 @@ namespace System.Net
{
if (anyValues)
{
- sb.Append(", ");
+ if (key.Equals(HttpKnownHeaderNames.SetCookie, StringComparison.OrdinalIgnoreCase) ||
+ key.Equals(HttpKnownHeaderNames.SetCookie2, StringComparison.OrdinalIgnoreCase))
+ {
+ sb.Append("\r\n").Append(key).Append(": ");
+ }
+ else
+ {
+ sb.Append(", ");
+ }
}
sb.Append(value);
anyValues = true;
diff --git a/src/System.Net.HttpListener/src/System/Net/ServiceNameStore.cs b/src/System.Net.HttpListener/src/System/Net/ServiceNameStore.cs
index fedc94bbe8..0459834bb9 100644
--- a/src/System.Net.HttpListener/src/System/Net/ServiceNameStore.cs
+++ b/src/System.Net.HttpListener/src/System/Net/ServiceNameStore.cs
@@ -297,11 +297,11 @@ namespace System.Net
}
catch (System.Net.Sockets.SocketException)
{
- return new string[0];
+ return Array.Empty<string>();
}
catch (System.Security.SecurityException)
{
- return new string[0];
+ return Array.Empty<string>();
}
}
else if (!hostname.Contains("."))
diff --git a/src/System.Net.HttpListener/src/System/Net/Windows/HttpListener.Windows.cs b/src/System.Net.HttpListener/src/System/Net/Windows/HttpListener.Windows.cs
index 019af2ea01..be8fe5fba1 100644
--- a/src/System.Net.HttpListener/src/System/Net/Windows/HttpListener.Windows.cs
+++ b/src/System.Net.HttpListener/src/System/Net/Windows/HttpListener.Windows.cs
@@ -851,7 +851,7 @@ namespace System.Net
NetEventSource.Info(this, $"authenticationScheme: {authenticationScheme}");
}
SendError(requestId, HttpStatusCode.InternalServerError, null);
- httpContext.Close();
+ FreeContext(ref httpContext, memoryBlob);
return null;
}
}
@@ -935,9 +935,7 @@ namespace System.Net
}
httpError = HttpStatusCode.Unauthorized;
- httpContext.Request.DetachBlob(memoryBlob);
- httpContext.Close();
- httpContext = null;
+ FreeContext(ref httpContext, memoryBlob);
}
else
{
@@ -1161,9 +1159,7 @@ namespace System.Net
NetEventSource.Info(this, "Handshake has failed.");
}
- httpContext.Request.DetachBlob(memoryBlob);
- httpContext.Close();
- httpContext = null;
+ FreeContext(ref httpContext, memoryBlob);
}
}
@@ -1240,8 +1236,7 @@ namespace System.Net
if (NetEventSource.IsEnabled) NetEventSource.Info(this, "connectionId:" + connectionId + " because of failed HttpWaitForDisconnect");
SendError(requestId, HttpStatusCode.InternalServerError, null);
- httpContext.Request.DetachBlob(memoryBlob);
- httpContext.Close();
+ FreeContext(ref httpContext, memoryBlob);
return null;
}
}
@@ -1282,11 +1277,7 @@ namespace System.Net
}
catch
{
- if (httpContext != null)
- {
- httpContext.Request.DetachBlob(memoryBlob);
- httpContext.Close();
- }
+ FreeContext(ref httpContext, memoryBlob);
if (newContext != null)
{
if (newContext == context)
@@ -1341,6 +1332,16 @@ namespace System.Net
}
}
}
+
+ private static void FreeContext(ref HttpListenerContext httpContext, RequestContextBase memoryBlob)
+ {
+ if (httpContext != null)
+ {
+ httpContext.Request.DetachBlob(memoryBlob);
+ httpContext.Close();
+ httpContext = null;
+ }
+ }
// Using the configured Auth schemes, populate the auth challenge headers. This is for scenarios where
// Anonymous access is allowed for some resources, but the server later determines that authorization
diff --git a/src/System.Net.HttpListener/src/System/Net/Windows/WebSockets/WebSocketBuffer.cs b/src/System.Net.HttpListener/src/System/Net/Windows/WebSockets/WebSocketBuffer.cs
index 02547dcafb..f96532d57b 100644
--- a/src/System.Net.HttpListener/src/System/Net/Windows/WebSockets/WebSocketBuffer.cs
+++ b/src/System.Net.HttpListener/src/System/Net/Windows/WebSockets/WebSocketBuffer.cs
@@ -39,7 +39,7 @@ namespace System.Net.WebSockets
private readonly ArraySegment<byte> _propertyBuffer;
private readonly int _sendBufferSize;
private volatile int _payloadOffset;
- private volatile WebSocketReceiveResult _bufferedPayloadReceiveResult;
+ private volatile PayloadReceiveResult _bufferedPayloadReceiveResult;
private long _pinnedSendBufferStartAddress;
private long _pinnedSendBufferEndAddress;
private ArraySegment<byte> _pinnedSendBuffer;
@@ -305,7 +305,7 @@ namespace System.Net.WebSockets
Debug.Assert(_payloadOffset == 0,
"'m_PayloadOffset' MUST be '0' at this point.");
Debug.Assert(_bufferedPayloadReceiveResult == null || _bufferedPayloadReceiveResult.Count == 0,
- "'m_BufferedPayloadReceiveResult.Count' MUST be '0' at this point.");
+ "'_bufferedPayloadReceiveResult.Count' MUST be '0' at this point.");
Buffer.BlockCopy(payload.Array,
payload.Offset + unconsumedDataOffset,
@@ -314,7 +314,7 @@ namespace System.Net.WebSockets
bytesBuffered);
_bufferedPayloadReceiveResult =
- new WebSocketReceiveResult(bytesBuffered, messageType, endOfMessage);
+ new PayloadReceiveResult(bytesBuffered, messageType, endOfMessage);
this.ValidateBufferedPayload();
}
@@ -326,12 +326,12 @@ namespace System.Net.WebSockets
int bytesTransferred = Math.Min(buffer.Count, _bufferedPayloadReceiveResult.Count);
+ _bufferedPayloadReceiveResult.Count -= bytesTransferred;
+
receiveResult = new WebSocketReceiveResult(
bytesTransferred,
_bufferedPayloadReceiveResult.MessageType,
- bytesTransferred == 0 && _bufferedPayloadReceiveResult.EndOfMessage,
- _bufferedPayloadReceiveResult.CloseStatus,
- _bufferedPayloadReceiveResult.CloseStatusDescription);
+ _bufferedPayloadReceiveResult.Count == 0 && _bufferedPayloadReceiveResult.EndOfMessage);
Buffer.BlockCopy(_payloadBuffer.Array,
_payloadBuffer.Offset + _payloadOffset,
@@ -558,9 +558,9 @@ namespace System.Net.WebSockets
private void ValidateBufferedPayload()
{
Debug.Assert(_bufferedPayloadReceiveResult != null,
- "'m_BufferedPayloadReceiveResult' MUST NOT be NULL.");
+ "'_bufferedPayloadReceiveResult' MUST NOT be NULL.");
Debug.Assert(_bufferedPayloadReceiveResult.Count >= 0,
- "'m_BufferedPayloadReceiveResult.Count' MUST NOT be negative.");
+ "'_bufferedPayloadReceiveResult.Count' MUST NOT be negative.");
Debug.Assert(_payloadOffset >= 0, "'m_PayloadOffset' MUST NOT be smaller than 0.");
Debug.Assert(_payloadOffset <= _payloadBuffer.Count,
"'m_PayloadOffset' MUST NOT be bigger than 'm_PayloadBuffer.Count'.");
@@ -685,5 +685,24 @@ namespace System.Net.WebSockets
public const int None = 0;
public const int SendPayloadSpecified = 1;
}
+
+ private class PayloadReceiveResult
+ {
+ public int Count { get; set; }
+ public bool EndOfMessage { get; }
+ public WebSocketMessageType MessageType { get; }
+
+ public PayloadReceiveResult(int count, WebSocketMessageType messageType, bool endOfMessage)
+ {
+ if (count < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(count));
+ }
+
+ Count = count;
+ EndOfMessage = endOfMessage;
+ MessageType = messageType;
+ }
+ }
}
-} \ No newline at end of file
+}
diff --git a/src/System.Net.HttpListener/tests/HttpListenerResponseTests.Cookies.cs b/src/System.Net.HttpListener/tests/HttpListenerResponseTests.Cookies.cs
index b52204e16e..4ea2c89d16 100644
--- a/src/System.Net.HttpListener/tests/HttpListenerResponseTests.Cookies.cs
+++ b/src/System.Net.HttpListener/tests/HttpListenerResponseTests.Cookies.cs
@@ -128,9 +128,9 @@ namespace System.Net.Tests
response.Close();
- string clientResponse = GetClientResponse(173);
- Assert.Contains($"\r\nSet-Cookie: name1=value1\r\n", clientResponse);
- Assert.Contains($"\r\nSet-Cookie2: name2=value2\r\n", clientResponse);
+ string clientResponse = GetClientResponse(expectedLength:173);
+ Assert.Contains("\r\nSet-Cookie: name1=value1\r\n", clientResponse);
+ Assert.Contains("\r\nSet-Cookie2: name2=value2\r\n", clientResponse);
}
[Fact]
@@ -147,9 +147,9 @@ namespace System.Net.Tests
Assert.Null(response.Headers["Set-Cookie"]);
Assert.Equal("name3=value3; Port=\"200\"; Version=1", response.Headers["Set-Cookie2"]);
- string clientResponse = GetClientResponse(170);
+ string clientResponse = GetClientResponse(expectedLength:170);
Assert.DoesNotContain("Set-Cookie:", clientResponse);
- Assert.Contains($"\r\nSet-Cookie2: name3=value3; Port=\"200\"; Version=1\r\n", clientResponse);
+ Assert.Contains("\r\nSet-Cookie2: name3=value3; Port=\"200\"; Version=1\r\n", clientResponse);
}
[Fact]
@@ -166,10 +166,28 @@ namespace System.Net.Tests
Assert.Equal("name3=value3", response.Headers["Set-Cookie"]);
Assert.Null(response.Headers["Set-Cookie2"]);
- string clientResponse = GetClientResponse(146);
- Assert.Contains($"\r\nSet-Cookie: name3=value3\r\n", clientResponse);
+ string clientResponse = GetClientResponse(expectedLength:146);
+ Assert.Contains("\r\nSet-Cookie: name3=value3\r\n", clientResponse);
Assert.DoesNotContain("Set-Cookie2", clientResponse);
}
+
+ [Fact]
+ public async Task Cookies_AddMultipleInHeader_ClientReceivesExpectedHeaders()
+ {
+ HttpListenerResponse response = await GetResponse();
+ response.Headers.Add("Set-Cookie", "name1=value1");
+ response.Headers.Add("Set-Cookie", "name2=value2");
+ response.Headers.Add("Set-Cookie", "name3=value3");
+ response.Headers.Add("Set-Cookie", "name4=value4");
+
+ response.Close();
+
+ string clientResponse = GetClientResponse(expectedLength:224);
+ Assert.Contains("\r\nSet-Cookie: name1=value1\r\n", clientResponse);
+ Assert.Contains("\r\nSet-Cookie: name2=value2\r\n", clientResponse);
+ Assert.Contains("\r\nSet-Cookie: name3=value3\r\n", clientResponse);
+ Assert.Contains("\r\nSet-Cookie: name4=value4\r\n", clientResponse);
+ }
[Fact]
public async Task AppendCookie_ValidCookie_AddsCookieToCollection()
diff --git a/src/System.Net.HttpListener/tests/HttpListenerWebSocketTests.cs b/src/System.Net.HttpListener/tests/HttpListenerWebSocketTests.cs
index 4e061dd255..a0697b15cb 100644
--- a/src/System.Net.HttpListener/tests/HttpListenerWebSocketTests.cs
+++ b/src/System.Net.HttpListener/tests/HttpListenerWebSocketTests.cs
@@ -112,6 +112,40 @@ namespace System.Net.Tests
Assert.Equal(Text, Encoding.ASCII.GetString(receivedBytes));
}
+ [ConditionalTheory(nameof(IsNotWindows7))]
+ [InlineData(300)]
+ [InlineData(500)]
+ [InlineData(1000)]
+ [InlineData(1300)]
+ public async Task ReceiveAsync_DetectEndOfMessage_Success(int bufferSize)
+ {
+ const int StringLength = 1000;
+ string sendString = new string('A', StringLength);
+ byte[] sentBytes = Encoding.ASCII.GetBytes(sendString);
+
+ HttpListenerWebSocketContext context = await GetWebSocketContext();
+ await ClientConnectTask;
+
+ await Client.SendAsync(new ArraySegment<byte>(sentBytes), WebSocketMessageType.Text, true, new CancellationToken());
+
+ byte[] receivedBytes = new byte[bufferSize];
+ List<byte> compoundBuffer = new List<byte>();
+
+ WebSocketReceiveResult result = new WebSocketReceiveResult(0, WebSocketMessageType.Close, false);
+ while (!result.EndOfMessage)
+ {
+ result = await (context.WebSocket).ReceiveAsync(new ArraySegment<byte>(receivedBytes), new CancellationToken());
+
+ byte[] readBytes = new byte[result.Count];
+ Array.Copy(receivedBytes, readBytes, result.Count);
+ compoundBuffer.AddRange(readBytes);
+ }
+
+ Assert.True(result.EndOfMessage);
+ string msg = Encoding.UTF8.GetString(compoundBuffer.ToArray());
+ Assert.Equal(sendString, msg);
+ }
+
[ConditionalFact(nameof(IsNotWindows7))]
public async Task ReceiveAsync_NoInnerBuffer_ThrowsArgumentNullException()
{
@@ -133,8 +167,6 @@ namespace System.Net.Tests
public static IEnumerable<object[]> CloseStatus_Valid_TestData()
{
- yield return new object[] { (WebSocketCloseStatus)(-1), "Negative", 65535 };
- yield return new object[] { WebSocketCloseStatus.Empty, null, WebSocketCloseStatus.Empty };
yield return new object[] { WebSocketCloseStatus.EndpointUnavailable, "", WebSocketCloseStatus.EndpointUnavailable };
yield return new object[] { WebSocketCloseStatus.MandatoryExtension, "StatusDescription", WebSocketCloseStatus.MandatoryExtension };
}
diff --git a/src/System.Net.HttpListener/tests/HttpRequestStreamTests.cs b/src/System.Net.HttpListener/tests/HttpRequestStreamTests.cs
index 80d19c33b9..4f43e91f76 100644
--- a/src/System.Net.HttpListener/tests/HttpRequestStreamTests.cs
+++ b/src/System.Net.HttpListener/tests/HttpRequestStreamTests.cs
@@ -10,6 +10,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
+using Xunit.Abstractions;
namespace System.Net.Tests
{
@@ -18,12 +19,15 @@ namespace System.Net.Tests
private HttpListenerFactory _factory;
private HttpListener _listener;
private GetContextHelper _helper;
+ private const int TimeoutMilliseconds = 60*1000;
+ private readonly ITestOutputHelper _output;
- public HttpRequestStreamTests()
+ public HttpRequestStreamTests(ITestOutputHelper output)
{
_factory = new HttpListenerFactory();
_listener = _factory.GetListener();
_helper = new GetContextHelper(_listener, _factory.ListeningUrl);
+ _output = output;
}
public void Dispose()
@@ -32,6 +36,58 @@ namespace System.Net.Tests
_helper.Dispose();
}
+ // Try to read 'length' bytes from stream or fail after timeout.
+ private async Task<int> ReadLengthAsync(Stream stream, byte[] array, int offset, int length)
+ {
+ int remaining = length;
+ int readLength;
+
+ do
+ {
+ readLength = await TaskTimeoutExtensions.TimeoutAfter(stream.ReadAsync(array, offset, remaining), TimeoutMilliseconds);
+ if (readLength <= 0)
+ {
+ break;
+ }
+ remaining -= readLength;
+ offset += readLength;
+ }
+ while (remaining > 0);
+
+ if (remaining != 0)
+ {
+ _output.WriteLine("Expected {0} bytes but got {1}", length, length-remaining);
+ }
+
+ return length - remaining;
+ }
+
+ // Synchronous version of ReadLengthAsync above.
+ private int ReadLength(Stream stream, byte[] array, int offset, int length)
+ {
+ int remaining = length;
+ int readLength;
+
+ do
+ {
+ readLength = stream.Read(array, offset, remaining);
+ if (readLength <= 0)
+ {
+ break;
+ }
+ remaining -= readLength;
+ offset += readLength;
+ }
+ while (remaining > 0);
+
+ if (remaining != 0)
+ {
+ _output.WriteLine("Expected {0} bytes but got {1}", length, length-remaining);
+ }
+
+ return length - remaining;
+ }
+
[Theory]
[InlineData(true, "")]
[InlineData(false, "")]
@@ -60,7 +116,7 @@ namespace System.Net.Tests
}
byte[] buffer = new byte[expected.Length];
- int bytesRead = await context.Request.InputStream.ReadAsync(buffer, 0, buffer.Length);
+ int bytesRead = await ReadLengthAsync(context.Request.InputStream, buffer, 0, expected.Length);
Assert.Equal(expected.Length, bytesRead);
Assert.Equal(expected, buffer);
@@ -107,7 +163,7 @@ namespace System.Net.Tests
// Add padding at beginning and end to test for correct offset/size handling
byte[] buffer = new byte[pad + expected.Length + pad];
- int bytesRead = await context.Request.InputStream.ReadAsync(buffer, pad, expected.Length);
+ int bytesRead = await ReadLengthAsync(context.Request.InputStream, buffer, pad, expected.Length);
Assert.Equal(expected.Length, bytesRead);
Assert.Equal(expected, buffer.Skip(pad).Take(bytesRead));
@@ -150,7 +206,7 @@ namespace System.Net.Tests
}
byte[] buffer = new byte[expected.Length];
- int bytesRead = context.Request.InputStream.Read(buffer, 0, buffer.Length);
+ int bytesRead = ReadLength(context.Request.InputStream, buffer, 0, buffer.Length);
Assert.Equal(expected.Length, bytesRead);
Assert.Equal(expected, buffer);
@@ -263,7 +319,7 @@ namespace System.Net.Tests
HttpListenerContext context = await contextTask;
byte[] buffer = new byte[expected.Length + 5];
- int bytesRead = await context.Request.InputStream.ReadAsync(buffer, 0, buffer.Length);
+ int bytesRead = await ReadLengthAsync(context.Request.InputStream, buffer, 0, buffer.Length);
Assert.Equal(expected.Length, bytesRead);
Assert.Equal(expected.Concat(new byte[5]), buffer);
@@ -289,7 +345,7 @@ namespace System.Net.Tests
HttpListenerContext context = await contextTask;
byte[] buffer = new byte[expected.Length + 5];
- int bytesRead = context.Request.InputStream.Read(buffer, 0, buffer.Length);
+ int bytesRead = ReadLength(context.Request.InputStream, buffer, 0, buffer.Length);
Assert.Equal(expected.Length, bytesRead);
Assert.Equal(expected.Concat(new byte[5]), buffer);
@@ -315,7 +371,7 @@ namespace System.Net.Tests
HttpListenerContext context = await contextTask;
byte[] buffer = new byte[expected.Length - 5];
- int bytesRead = await context.Request.InputStream.ReadAsync(buffer, 0, buffer.Length);
+ int bytesRead = await ReadLengthAsync(context.Request.InputStream, buffer, 0, buffer.Length);
Assert.Equal(buffer.Length, bytesRead);
context.Response.Close();
diff --git a/src/System.Net.HttpListener/tests/System.Net.HttpListener.Tests.csproj b/src/System.Net.HttpListener/tests/System.Net.HttpListener.Tests.csproj
index 9f7b02a8db..7c61c94e01 100644
--- a/src/System.Net.HttpListener/tests/System.Net.HttpListener.Tests.csproj
+++ b/src/System.Net.HttpListener/tests/System.Net.HttpListener.Tests.csproj
@@ -31,6 +31,9 @@
<Compile Include="SimpleHttpTests.cs" />
<Compile Include="WebSocketTests.cs" />
<Compile Include="XUnitAssemblyAttributes.cs" />
+ <Compile Include="$(CommonTestPath)\System\Threading\Tasks\TaskTimeoutExtensions.cs">
+ <Link>Common\System\Threading\Tasks\TaskTimeoutExtensions.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\System.Net.HttpListener.Tests.rd.xml" />
diff --git a/src/System.Net.HttpListener/tests/WebSocketTests.cs b/src/System.Net.HttpListener/tests/WebSocketTests.cs
index 7665e2ab66..8e32b4d324 100644
--- a/src/System.Net.HttpListener/tests/WebSocketTests.cs
+++ b/src/System.Net.HttpListener/tests/WebSocketTests.cs
@@ -28,8 +28,7 @@ namespace System.Net.Tests
{
if (PlatformDetection.IsWindows7)
{
- // Websockets in WinHttp 5.1 is only supported from Windows 8+
- Assert.Throws<PlatformNotSupportedException>(() => new ClientWebSocket());
+ // Websockets is supported only from Windows 8+
return;
}
diff --git a/src/System.Net.Mail/ref/System.Net.Mime.cs b/src/System.Net.Mail/ref/System.Net.Mime.cs
index 4066b48f9a..904d525242 100644
--- a/src/System.Net.Mail/ref/System.Net.Mime.cs
+++ b/src/System.Net.Mail/ref/System.Net.Mime.cs
@@ -58,6 +58,8 @@ namespace System.Net.Mime
public const string Rtf = "application/rtf";
public const string Pdf = "application/pdf";
public const string Zip = "application/zip";
+ public const string Json = "application/json";
+ public const string Xml = "application/xml";
}
public static class Image
diff --git a/src/System.Net.Mail/src/System/Net/Mime/MediaTypeNames.cs b/src/System.Net.Mail/src/System/Net/Mime/MediaTypeNames.cs
index 09b6455122..6f62b58068 100644
--- a/src/System.Net.Mail/src/System/Net/Mime/MediaTypeNames.cs
+++ b/src/System.Net.Mail/src/System/Net/Mime/MediaTypeNames.cs
@@ -21,6 +21,8 @@ namespace System.Net.Mime
public const string Rtf = "application/rtf";
public const string Pdf = "application/pdf";
public const string Zip = "application/zip";
+ public const string Json = "application/json";
+ public const string Xml = "application/xml";
}
public static class Image
diff --git a/src/System.Net.Mail/src/System/Net/Mime/SmtpDateTime.cs b/src/System.Net.Mail/src/System/Net/Mime/SmtpDateTime.cs
index 17c431f786..73498f939b 100644
--- a/src/System.Net.Mail/src/System/Net/Mime/SmtpDateTime.cs
+++ b/src/System.Net.Mail/src/System/Net/Mime/SmtpDateTime.cs
@@ -230,7 +230,7 @@ namespace System.Net.Mime
{
if (!Char.IsLetter(value, i))
{
- throw new FormatException(SR.MailHeaderFieldInvalidCharacter);
+ throw new FormatException(SR.Format(SR.MailHeaderFieldInvalidCharacter, value));
}
}
}
@@ -258,7 +258,7 @@ namespace System.Net.Mime
// no ':' means invalid value
if (indexOfHourSeparator == -1)
{
- throw new FormatException(SR.MailHeaderFieldInvalidCharacter);
+ throw new FormatException(SR.Format(SR.MailHeaderFieldInvalidCharacter, data));
}
// now we know where hours and minutes are separated. The first whitespace after
@@ -269,7 +269,7 @@ namespace System.Net.Mime
if (indexOfTimeZoneSeparator == -1)
{
- throw new FormatException(SR.MailHeaderFieldInvalidCharacter);
+ throw new FormatException(SR.Format(SR.MailHeaderFieldInvalidCharacter, data));
}
// extract the time portion and remove all leading and trailing whitespace
diff --git a/src/System.Net.Mail/tests/Functional/SmtpExceptionTest.cs b/src/System.Net.Mail/tests/Functional/SmtpExceptionTest.cs
index eefce6e9ed..d54f0d3699 100644
--- a/src/System.Net.Mail/tests/Functional/SmtpExceptionTest.cs
+++ b/src/System.Net.Mail/tests/Functional/SmtpExceptionTest.cs
@@ -12,6 +12,7 @@
using System.Collections;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
+using System.Text.RegularExpressions;
using Xunit;
namespace System.Net.Mail.Tests
@@ -80,7 +81,12 @@ namespace System.Net.Mail.Tests
Assert.Equal(0, se.Data.Keys.Count);
Assert.Null(se.InnerException);
Assert.NotNull(se.Message);
- Assert.NotEqual(-1, se.Message.IndexOf("'" + typeof(SmtpException).FullName + "'"));
+
+ // \p{Pi} any kind of opening quote https://www.compart.com/en/unicode/category/Pi
+ // \p{Pf} any kind of closing quote https://www.compart.com/en/unicode/category/Pf
+ // \p{Po} any kind of punctuation character that is not a dash, bracket, quote or connector https://www.compart.com/en/unicode/category/Po
+ Assert.Matches(@"[\p{Pi}\p{Po}]" + Regex.Escape(typeof(SmtpException).FullName) + @"[\p{Pf}\p{Po}]", se.Message);
+
Assert.Equal(SmtpStatusCode.GeneralFailure, se.StatusCode);
}
@@ -112,7 +118,12 @@ namespace System.Net.Mail.Tests
Assert.Equal(0, se.Data.Keys.Count);
Assert.Null(se.InnerException);
Assert.NotNull(se.Message);
- Assert.NotEqual(-1, se.Message.IndexOf("'" + typeof(SmtpException).FullName + "'"));
+
+ // \p{Pi} any kind of opening quote https://www.compart.com/en/unicode/category/Pi
+ // \p{Pf} any kind of closing quote https://www.compart.com/en/unicode/category/Pf
+ // \p{Po} any kind of punctuation character that is not a dash, bracket, quote or connector https://www.compart.com/en/unicode/category/Po
+ Assert.Matches(@"[\p{Pi}\p{Po}]" + Regex.Escape(typeof(SmtpException).FullName) + @"[\p{Pf}\p{Po}]", se.Message);
+
Assert.Equal((SmtpStatusCode)666, se.StatusCode);
}
diff --git a/src/System.Net.NameResolution/src/MatchingRefApiCompatBaseline.txt b/src/System.Net.NameResolution/src/MatchingRefApiCompatBaseline.txt
new file mode 100644
index 0000000000..20f44b7edf
--- /dev/null
+++ b/src/System.Net.NameResolution/src/MatchingRefApiCompatBaseline.txt
@@ -0,0 +1,4 @@
+Compat issues with assembly System.Net.NameResolution:
+TypesMustExist : Type 'System.Net.Internals.ProtocolFamily' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.Net.Internals.ProtocolType' does not exist in the implementation but it does exist in the contract.
+Total Issues: 2
diff --git a/src/System.Net.NameResolution/src/System.Net.NameResolution.csproj b/src/System.Net.NameResolution/src/System.Net.NameResolution.csproj
index ef34f9675b..2abcd175b8 100644
--- a/src/System.Net.NameResolution/src/System.Net.NameResolution.csproj
+++ b/src/System.Net.NameResolution/src/System.Net.NameResolution.csproj
@@ -5,6 +5,7 @@
<AssemblyName>System.Net.NameResolution</AssemblyName>
<ProjectGuid>{1714448C-211E-48C1-8B7E-4EE667D336A1}</ProjectGuid>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <ILLinkClearInitLocals>true</ILLinkClearInitLocals>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='uap-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='uap-Windows_NT-Release|AnyCPU'" />
@@ -46,9 +47,15 @@
<Compile Include="$(CommonPath)\System\Net\IPEndPointStatics.cs">
<Link>Common\System\Net\IPEndPointStatics.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Net\ByteOrder.cs">
+ <Link>Common\System\Net\ByteOrder.cs</Link>
+ </Compile>
+ <Compile Include="System\Net\DnsResolveAsyncResult.cs" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetsWindows)' == 'true'">
<Compile Include="System\Net\NameResolutionPal.Windows.cs" />
+ <Compile Include="System\Net\NameResolutionPal.Win32.cs" Condition="'$(TargetGroup)' != 'uap'"/>
+ <Compile Include="System\Net\NameResolutionPal.Uap.cs" Condition="'$(TargetGroup)' == 'uap'"/>
<Compile Include="$(CommonPath)\System\Net\ContextAwareResult.Windows.cs">
<Link>Common\System\Net\ContextAwareResult.Windows.cs</Link>
</Compile>
@@ -72,6 +79,9 @@
<Compile Include="$(CommonPath)\System\Net\SocketProtocolSupportPal.Windows.cs">
<Link>Common\System\Net\SocketProtocolSupportPal.Windows</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Net\SocketAddressPal.Windows.cs">
+ <Link>Common\System\Net\SocketAddressPal.Windows</Link>
+ </Compile>
<!-- Interop -->
<Compile Include="$(CommonPath)\Interop\Windows\Interop.Libraries.cs">
<Link>Interop\Windows\Interop.Libraries.cs</Link>
@@ -87,13 +97,7 @@
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\Winsock\Interop.closesocket.cs">
<Link>Interop\Windows\Winsock\Interop.closesocket.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\Winsock\Interop.gethostbyaddr.cs">
- <Link>Interop\Windows\Winsock\Interop.gethostbyaddr.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\Winsock\Interop.gethostbyname.cs">
- <Link>Interop\Windows\Winsock\Interop.gethostbyname.cs</Link>
- </Compile>
+ </Compile>
<Compile Include="$(CommonPath)\Interop\Windows\Winsock\Interop.gethostname.cs">
<Link>Interop\Windows\Winsock\Interop.gethostname.cs</Link>
</Compile>
@@ -118,12 +122,27 @@
<Compile Include="$(CommonPath)\Interop\Windows\Winsock\SafeFreeAddrInfo.cs">
<Link>Interop\Windows\Winsock\SafeFreeAddrInfo.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\Winsock\AddressInfoEx.cs">
+ <Link>Interop\Windows\Winsock\AddressInfoEx.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\Winsock\Interop.GetAddrInfoExW.cs">
+ <Link>Interop\Windows\Winsock\Interop.GetAddrInfoExW.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeLibraryHandle.cs" Condition="'$(TargetGroup)' != 'uap'">
+ <Link>Common\Microsoft\Win32\SafeHandles\SafeLibraryHandle.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\Kernel32\Interop.GetProcAddress.cs" Condition="'$(TargetGroup)' != 'uap'">
+ <Link>Interop\Windows\Kernel32\Interop.GetProcAddress.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\Kernel32\Interop.LoadLibraryEx.cs" Condition="'$(TargetGroup)' != 'uap'">
+ <Link>Interop\Windows\Kernel32\Interop.LoadLibraryEx.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\Kernel32\Interop.FreeLibrary.cs">
+ <Link>Interop\Windows\Kernel32\Interop.FreeLibrary.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup Condition=" '$(TargetsUnix)' == 'true' ">
<Compile Include="System\Net\NameResolutionPal.Unix.cs" />
- <Compile Include="$(CommonPath)\System\Net\ByteOrder.cs">
- <Link>Common\System\Net\Internals\ByteOrder.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\System\Net\ContextAwareResult.Unix.cs">
<Link>Common\System\Net\ContextAwareResult.Unix.cs</Link>
</Compile>
@@ -189,6 +208,7 @@
<Reference Include="System.Security.Claims" />
<Reference Include="System.Security.Principal.Windows" />
<Reference Include="System.Threading" />
+ <Reference Include="System.Threading.Overlapped" />
<Reference Include="System.Threading.Tasks" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
diff --git a/src/System.Net.NameResolution/src/System/Net/DNS.cs b/src/System.Net.NameResolution/src/System/Net/DNS.cs
index a51ca67828..fff6712946 100644
--- a/src/System.Net.NameResolution/src/System/Net/DNS.cs
+++ b/src/System.Net.NameResolution/src/System/Net/DNS.cs
@@ -38,52 +38,31 @@ namespace System.Net
{
return NameResolutionUtilities.GetUnresolvedAnswer(address);
}
- return InternalGetHostByName(hostName, false);
+ return InternalGetHostByName(hostName);
}
- private static IPHostEntry InternalGetHostByName(string hostName, bool includeIPv6)
+ private static void ValidateHostName(string hostName)
{
- if (NetEventSource.IsEnabled) NetEventSource.Enter(null, hostName);
- IPHostEntry ipHostEntry = null;
-
if (hostName.Length > MaxHostName // If 255 chars, the last one must be a dot.
|| hostName.Length == MaxHostName && hostName[MaxHostName - 1] != '.')
{
throw new ArgumentOutOfRangeException(nameof(hostName), SR.Format(SR.net_toolong,
nameof(hostName), MaxHostName.ToString(NumberFormatInfo.CurrentInfo)));
}
+ }
- //
- // IPv6 Changes: IPv6 requires the use of getaddrinfo() rather
- // than the traditional IPv4 gethostbyaddr() / gethostbyname().
- // getaddrinfo() is also protocol independent in that it will also
- // resolve IPv4 names / addresses. As a result, it is the preferred
- // resolution mechanism on platforms that support it (Windows 5.1+).
- // If getaddrinfo() is unsupported, IPv6 resolution does not work.
- //
- // Consider : If IPv6 is disabled, we could detect IPv6 addresses
- // and throw an unsupported platform exception.
- //
- // Note : Whilst getaddrinfo is available on WinXP+, we only
- // use it if IPv6 is enabled (platform is part of that
- // decision). This is done to minimize the number of
- // possible tests that are needed.
- //
- if (includeIPv6 || SocketProtocolSupportPal.OSSupportsIPv6)
- {
- //
- // IPv6 enabled: use getaddrinfo() to obtain DNS information.
- //
- int nativeErrorCode;
- SocketError errorCode = NameResolutionPal.TryGetAddrInfo(hostName, out ipHostEntry, out nativeErrorCode);
- if (errorCode != SocketError.Success)
- {
- throw SocketExceptionFactory.CreateSocketException(errorCode, nativeErrorCode);
- }
- }
- else
+ private static IPHostEntry InternalGetHostByName(string hostName)
+ {
+ if (NetEventSource.IsEnabled) NetEventSource.Enter(null, hostName);
+ IPHostEntry ipHostEntry = null;
+
+ ValidateHostName(hostName);
+
+ int nativeErrorCode;
+ SocketError errorCode = NameResolutionPal.TryGetAddrInfo(hostName, out ipHostEntry, out nativeErrorCode);
+ if (errorCode != SocketError.Success)
{
- ipHostEntry = NameResolutionPal.GetHostByName(hostName);
+ throw SocketExceptionFactory.CreateSocketException(errorCode, nativeErrorCode);
}
if (NetEventSource.IsEnabled) NetEventSource.Exit(null, ipHostEntry);
@@ -101,7 +80,7 @@ namespace System.Net
throw new ArgumentNullException(nameof(address));
}
- IPHostEntry ipHostEntry = InternalGetHostByAddress(IPAddress.Parse(address), false);
+ IPHostEntry ipHostEntry = InternalGetHostByAddress(IPAddress.Parse(address));
if (NetEventSource.IsEnabled) NetEventSource.Exit(null, ipHostEntry);
return ipHostEntry;
@@ -118,79 +97,51 @@ namespace System.Net
throw new ArgumentNullException(nameof(address));
}
- IPHostEntry ipHostEntry = InternalGetHostByAddress(address, false);
+ IPHostEntry ipHostEntry = InternalGetHostByAddress(address);
if (NetEventSource.IsEnabled) NetEventSource.Exit(null, ipHostEntry);
return ipHostEntry;
} // GetHostByAddress
// Does internal IPAddress reverse and then forward lookups (for Legacy and current public methods).
- private static IPHostEntry InternalGetHostByAddress(IPAddress address, bool includeIPv6)
+ private static IPHostEntry InternalGetHostByAddress(IPAddress address)
{
if (NetEventSource.IsEnabled) NetEventSource.Info(null, address);
-
+
//
- // IPv6 Changes: We need to use the new getnameinfo / getaddrinfo functions
- // for resolution of IPv6 addresses.
+ // Try to get the data for the host from it's address
//
-
- if (SocketProtocolSupportPal.OSSupportsIPv6 || includeIPv6)
- {
- //
- // Try to get the data for the host from it's address
- //
- // We need to call getnameinfo first, because getaddrinfo w/ the ipaddress string
- // will only return that address and not the full list.
-
- // Do a reverse lookup to get the host name.
- SocketError errorCode;
- int nativeErrorCode;
- string name = NameResolutionPal.TryGetNameInfo(address, out errorCode, out nativeErrorCode);
+ // We need to call getnameinfo first, because getaddrinfo w/ the ipaddress string
+ // will only return that address and not the full list.
+
+ // Do a reverse lookup to get the host name.
+ SocketError errorCode;
+ int nativeErrorCode;
+ string name = NameResolutionPal.TryGetNameInfo(address, out errorCode, out nativeErrorCode);
+ if (errorCode == SocketError.Success)
+ {
+ // Do the forward lookup to get the IPs for that host name
+ IPHostEntry hostEntry;
+ errorCode = NameResolutionPal.TryGetAddrInfo(name, out hostEntry, out nativeErrorCode);
if (errorCode == SocketError.Success)
{
- // Do the forward lookup to get the IPs for that host name
- IPHostEntry hostEntry;
- errorCode = NameResolutionPal.TryGetAddrInfo(name, out hostEntry, out nativeErrorCode);
- if (errorCode == SocketError.Success)
- {
- return hostEntry;
- }
-
- if (NetEventSource.IsEnabled) NetEventSource.Error(null, SocketExceptionFactory.CreateSocketException(errorCode, nativeErrorCode));
-
- // One of two things happened:
- // 1. There was a ptr record in dns, but not a corollary A/AAA record.
- // 2. The IP was a local (non-loopback) IP that resolved to a connection specific dns suffix.
- // - Workaround, Check "Use this connection's dns suffix in dns registration" on that network
- // adapter's advanced dns settings.
-
- // Just return the resolved host name and no IPs.
return hostEntry;
}
- throw SocketExceptionFactory.CreateSocketException(errorCode, nativeErrorCode);
- }
+ if (NetEventSource.IsEnabled) NetEventSource.Error(null, SocketExceptionFactory.CreateSocketException(errorCode, nativeErrorCode));
- //
- // If IPv6 is not enabled (maybe config switch) but we've been
- // given an IPv6 address then we need to bail out now.
- //
- else
- {
- if (address.AddressFamily == AddressFamily.InterNetworkV6)
- {
- //
- // Protocol not supported
- //
- throw new SocketException((int)SocketError.ProtocolNotSupported);
- }
- //
- // Use gethostbyaddr() to try to resolve the IP address
- //
- // End IPv6 Changes
- //
- return NameResolutionPal.GetHostByAddr(address);
+ // One of two things happened:
+ // 1. There was a ptr record in dns, but not a corollary A/AAA record.
+ // 2. The IP was a local (non-loopback) IP that resolved to a connection specific dns suffix.
+ // - Workaround, Check "Use this connection's dns suffix in dns registration" on that network
+ // adapter's advanced dns settings.
+
+ // Just return the resolved host name and no IPs.
+ return hostEntry;
}
+
+ throw SocketExceptionFactory.CreateSocketException(errorCode, nativeErrorCode);
+
} // InternalGetHostByAddress
/*****************************************************************************
@@ -235,7 +186,7 @@ namespace System.Net
{
try
{
- ipHostEntry = InternalGetHostByAddress(address, false);
+ ipHostEntry = InternalGetHostByAddress(address);
}
catch (SocketException ex)
{
@@ -245,49 +196,26 @@ namespace System.Net
}
else
{
- ipHostEntry = InternalGetHostByName(hostName, false);
+ ipHostEntry = InternalGetHostByName(hostName);
}
if (NetEventSource.IsEnabled) NetEventSource.Exit(null, ipHostEntry);
return ipHostEntry;
}
- private class ResolveAsyncResult : ContextAwareResult
- {
- // Forward lookup
- internal ResolveAsyncResult(string hostName, object myObject, bool includeIPv6, object myState, AsyncCallback myCallBack) :
- base(myObject, myState, myCallBack)
- {
- this.hostName = hostName;
- this.includeIPv6 = includeIPv6;
- }
-
- // Reverse lookup
- internal ResolveAsyncResult(IPAddress address, object myObject, bool includeIPv6, object myState, AsyncCallback myCallBack) :
- base(myObject, myState, myCallBack)
- {
- this.includeIPv6 = includeIPv6;
- this.address = address;
- }
-
- internal readonly string hostName;
- internal bool includeIPv6;
- internal IPAddress address;
- }
-
private static void ResolveCallback(object context)
{
- ResolveAsyncResult result = (ResolveAsyncResult)context;
+ DnsResolveAsyncResult result = (DnsResolveAsyncResult)context;
IPHostEntry hostEntry;
try
{
- if (result.address != null)
+ if (result.IpAddress != null)
{
- hostEntry = InternalGetHostByAddress(result.address, result.includeIPv6);
+ hostEntry = InternalGetHostByAddress(result.IpAddress);
}
else
{
- hostEntry = InternalGetHostByName(result.hostName, result.includeIPv6);
+ hostEntry = InternalGetHostByName(result.HostName);
}
}
catch (OutOfMemoryException)
@@ -305,7 +233,7 @@ namespace System.Net
// Helpers for async GetHostByName, ResolveToAddresses, and Resolve - they're almost identical
// If hostName is an IPString and justReturnParsedIP==true then no reverse lookup will be attempted, but the original address is returned.
- private static IAsyncResult HostResolutionBeginHelper(string hostName, bool justReturnParsedIp, bool includeIPv6, bool throwOnIIPAny, AsyncCallback requestCallback, object state)
+ private static IAsyncResult HostResolutionBeginHelper(string hostName, bool justReturnParsedIp, bool throwOnIIPAny, AsyncCallback requestCallback, object state)
{
if (hostName == null)
{
@@ -315,20 +243,20 @@ namespace System.Net
if (NetEventSource.IsEnabled) NetEventSource.Info(null, hostName);
// See if it's an IP Address.
- IPAddress address;
- ResolveAsyncResult asyncResult;
- if (IPAddress.TryParse(hostName, out address))
+ IPAddress ipAddress;
+ DnsResolveAsyncResult asyncResult;
+ if (IPAddress.TryParse(hostName, out ipAddress))
{
- if (throwOnIIPAny && (address.Equals(IPAddress.Any) || address.Equals(IPAddress.IPv6Any)))
+ if (throwOnIIPAny && (ipAddress.Equals(IPAddress.Any) || ipAddress.Equals(IPAddress.IPv6Any)))
{
throw new ArgumentException(SR.net_invalid_ip_addr, nameof(hostName));
}
- asyncResult = new ResolveAsyncResult(address, null, includeIPv6, state, requestCallback);
+ asyncResult = new DnsResolveAsyncResult(ipAddress, null, state, requestCallback);
if (justReturnParsedIp)
{
- IPHostEntry hostEntry = NameResolutionUtilities.GetUnresolvedAnswer(address);
+ IPHostEntry hostEntry = NameResolutionUtilities.GetUnresolvedAnswer(ipAddress);
asyncResult.StartPostingAsyncOp(false);
asyncResult.InvokeCallback(hostEntry);
asyncResult.FinishPostingAsyncOp();
@@ -337,26 +265,36 @@ namespace System.Net
}
else
{
- asyncResult = new ResolveAsyncResult(hostName, null, includeIPv6, state, requestCallback);
+ asyncResult = new DnsResolveAsyncResult(hostName, null, state, requestCallback);
}
// Set up the context, possibly flow.
asyncResult.StartPostingAsyncOp(false);
- // Start the resolve.
- Task.Factory.StartNew(
- s => ResolveCallback(s),
- asyncResult,
- CancellationToken.None,
- TaskCreationOptions.DenyChildAttach,
- TaskScheduler.Default);
+ // If the OS supports it and 'hostName' is not an IP Address, resolve the name asynchronously
+ // instead of calling the synchronous version in the ThreadPool.
+ if (NameResolutionPal.SupportsGetAddrInfoAsync && ipAddress == null)
+ {
+ ValidateHostName(hostName);
+ NameResolutionPal.GetAddrInfoAsync(asyncResult);
+ }
+ else
+ {
+ // Start the resolve.
+ Task.Factory.StartNew(
+ s => ResolveCallback(s),
+ asyncResult,
+ CancellationToken.None,
+ TaskCreationOptions.DenyChildAttach,
+ TaskScheduler.Default);
+ }
// Finish the flowing, maybe it completed? This does nothing if we didn't initiate the flowing above.
asyncResult.FinishPostingAsyncOp();
return asyncResult;
}
- private static IAsyncResult HostResolutionBeginHelper(IPAddress address, bool flowContext, bool includeIPv6, AsyncCallback requestCallback, object state)
+ private static IAsyncResult HostResolutionBeginHelper(IPAddress address, bool flowContext, AsyncCallback requestCallback, object state)
{
if (address == null)
{
@@ -371,7 +309,7 @@ namespace System.Net
if (NetEventSource.IsEnabled) NetEventSource.Info(null, address);
// Set up the context, possibly flow.
- ResolveAsyncResult asyncResult = new ResolveAsyncResult(address, null, includeIPv6, state, requestCallback);
+ DnsResolveAsyncResult asyncResult = new DnsResolveAsyncResult(address, null, state, requestCallback);
if (flowContext)
{
asyncResult.StartPostingAsyncOp(false);
@@ -399,7 +337,7 @@ namespace System.Net
{
throw new ArgumentNullException(nameof(asyncResult));
}
- ResolveAsyncResult castedResult = asyncResult as ResolveAsyncResult;
+ DnsResolveAsyncResult castedResult = asyncResult as DnsResolveAsyncResult;
if (castedResult == null)
{
throw new ArgumentException(SR.net_io_invalidasyncresult, nameof(asyncResult));
@@ -430,7 +368,7 @@ namespace System.Net
NameResolutionPal.EnsureSocketsAreInitialized();
- IAsyncResult asyncResult = HostResolutionBeginHelper(hostName, true, true, false, requestCallback, stateObject);
+ IAsyncResult asyncResult = HostResolutionBeginHelper(hostName, true, true, requestCallback, stateObject);
if (NetEventSource.IsEnabled) NetEventSource.Exit(null, asyncResult);
return asyncResult;
@@ -468,11 +406,11 @@ namespace System.Net
throw new ArgumentException(SR.Format(SR.net_invalid_ip_addr, nameof(hostNameOrAddress)));
}
- ipHostEntry = InternalGetHostByAddress(address, true);
+ ipHostEntry = InternalGetHostByAddress(address);
}
else
{
- ipHostEntry = InternalGetHostByName(hostNameOrAddress, true);
+ ipHostEntry = InternalGetHostByName(hostNameOrAddress);
}
if (NetEventSource.IsEnabled) NetEventSource.Exit(null, ipHostEntry);
@@ -495,7 +433,7 @@ namespace System.Net
throw new ArgumentException(SR.Format(SR.net_invalid_ip_addr, nameof(address)));
}
- IPHostEntry ipHostEntry = InternalGetHostByAddress(address, true);
+ IPHostEntry ipHostEntry = InternalGetHostByAddress(address);
if (NetEventSource.IsEnabled) NetEventSource.Exit(null, ipHostEntry);
return ipHostEntry;
@@ -526,7 +464,7 @@ namespace System.Net
{
// InternalGetHostByName works with IP addresses (and avoids a reverse-lookup), but we need
// explicit handling in order to do the ArgumentException and guarantee the behavior.
- addresses = InternalGetHostByName(hostNameOrAddress, true).AddressList;
+ addresses = InternalGetHostByName(hostNameOrAddress).AddressList;
}
if (NetEventSource.IsEnabled) NetEventSource.Exit(null, addresses);
@@ -538,7 +476,7 @@ namespace System.Net
if (NetEventSource.IsEnabled) NetEventSource.Enter(null, hostNameOrAddress);
NameResolutionPal.EnsureSocketsAreInitialized();
- IAsyncResult asyncResult = HostResolutionBeginHelper(hostNameOrAddress, false, true, true, requestCallback, stateObject);
+ IAsyncResult asyncResult = HostResolutionBeginHelper(hostNameOrAddress, false, true, requestCallback, stateObject);
if (NetEventSource.IsEnabled) NetEventSource.Exit(null, asyncResult);
return asyncResult;
@@ -550,7 +488,7 @@ namespace System.Net
NameResolutionPal.EnsureSocketsAreInitialized();
- IAsyncResult asyncResult = HostResolutionBeginHelper(address, true, true, requestCallback, stateObject);
+ IAsyncResult asyncResult = HostResolutionBeginHelper(address, true, requestCallback, stateObject);
if (NetEventSource.IsEnabled) NetEventSource.Exit(null, asyncResult);
return asyncResult;
@@ -570,7 +508,7 @@ namespace System.Net
if (NetEventSource.IsEnabled) NetEventSource.Enter(null, hostNameOrAddress);
NameResolutionPal.EnsureSocketsAreInitialized();
- IAsyncResult asyncResult = HostResolutionBeginHelper(hostNameOrAddress, true, true, true, requestCallback, state);
+ IAsyncResult asyncResult = HostResolutionBeginHelper(hostNameOrAddress, true, true, requestCallback, state);
if (NetEventSource.IsEnabled) NetEventSource.Exit(null, asyncResult);
return asyncResult;
@@ -592,7 +530,7 @@ namespace System.Net
NameResolutionPal.EnsureSocketsAreInitialized();
- IAsyncResult asyncResult = HostResolutionBeginHelper(hostName, false, false, false, requestCallback, stateObject);
+ IAsyncResult asyncResult = HostResolutionBeginHelper(hostName, false, false, requestCallback, stateObject);
if (NetEventSource.IsEnabled) NetEventSource.Exit(null, asyncResult);
return asyncResult;
@@ -611,7 +549,7 @@ namespace System.Net
}
catch (SocketException ex)
{
- IPAddress address = ((ResolveAsyncResult)asyncResult).address;
+ IPAddress address = ((DnsResolveAsyncResult)asyncResult).IpAddress;
if (address == null)
throw; // BeginResolve was called with a HostName, not an IPAddress
diff --git a/src/System.Net.NameResolution/src/System/Net/DnsResolveAsyncResult.cs b/src/System.Net.NameResolution/src/System/Net/DnsResolveAsyncResult.cs
new file mode 100644
index 0000000000..e96b81aab7
--- /dev/null
+++ b/src/System.Net.NameResolution/src/System/Net/DnsResolveAsyncResult.cs
@@ -0,0 +1,26 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Net
+{
+ internal sealed class DnsResolveAsyncResult : ContextAwareResult
+ {
+ internal string HostName { get; }
+ internal IPAddress IpAddress { get; }
+
+ // Forward lookup
+ internal DnsResolveAsyncResult(string hostName, object myObject, object myState, AsyncCallback myCallBack)
+ : base(myObject, myState, myCallBack)
+ {
+ HostName = hostName;
+ }
+
+ // Reverse lookup
+ internal DnsResolveAsyncResult(IPAddress ipAddress, object myObject, object myState, AsyncCallback myCallBack)
+ : base(myObject, myState, myCallBack)
+ {
+ IpAddress = ipAddress;
+ }
+ }
+}
diff --git a/src/System.Net.NameResolution/src/System/Net/NameResolutionPal.Uap.cs b/src/System.Net.NameResolution/src/System/Net/NameResolutionPal.Uap.cs
new file mode 100644
index 0000000000..7f752ba354
--- /dev/null
+++ b/src/System.Net.NameResolution/src/System/Net/NameResolutionPal.Uap.cs
@@ -0,0 +1,11 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Net
+{
+ internal static partial class NameResolutionPal
+ {
+ private static bool GetAddrInfoExSupportsOverlapped() => false;
+ }
+}
diff --git a/src/System.Net.NameResolution/src/System/Net/NameResolutionPal.Unix.cs b/src/System.Net.NameResolution/src/System/Net/NameResolutionPal.Unix.cs
index 139e2740f9..c0e94fe05f 100644
--- a/src/System.Net.NameResolution/src/System/Net/NameResolutionPal.Unix.cs
+++ b/src/System.Net.NameResolution/src/System/Net/NameResolutionPal.Unix.cs
@@ -13,26 +13,8 @@ namespace System.Net
{
internal static partial class NameResolutionPal
{
- private static SocketError GetSocketErrorForErrno(int errno)
- {
- switch (errno)
- {
- case 0:
- return SocketError.Success;
- case (int)Interop.Sys.GetHostErrorCodes.HOST_NOT_FOUND:
- return SocketError.HostNotFound;
- case (int)Interop.Sys.GetHostErrorCodes.NO_DATA:
- return SocketError.NoData;
- case (int)Interop.Sys.GetHostErrorCodes.NO_RECOVERY:
- return SocketError.NoRecovery;
- case (int)Interop.Sys.GetHostErrorCodes.TRY_AGAIN:
- return SocketError.TryAgain;
- default:
- Debug.Fail("Unexpected errno: " + errno.ToString());
- return SocketError.SocketError;
- }
- }
-
+ public const bool SupportsGetAddrInfoAsync = false;
+
private static SocketError GetSocketErrorForNativeError(int error)
{
switch (error)
@@ -138,39 +120,7 @@ namespace System.Net
Aliases = aliases
};
}
-
- public static unsafe IPHostEntry GetHostByName(string hostName)
- {
- if (hostName == "")
- {
- // To match documented behavior on Windows, if an empty string is passed in, use the local host's name.
- hostName = Dns.GetHostName();
- }
-
- Interop.Sys.HostEntry entry;
- int err = Interop.Sys.GetHostByName(hostName, &entry);
- if (err != 0)
- {
- throw SocketExceptionFactory.CreateSocketException(GetSocketErrorForErrno(err), err);
- }
-
- return CreateIPHostEntry(entry);
- }
-
- public static unsafe IPHostEntry GetHostByAddr(IPAddress addr)
- {
- // TODO #2891: Optimize this (or decide if this legacy code can be removed):
- Interop.Sys.IPAddress address = addr.GetNativeIPAddress();
- Interop.Sys.HostEntry entry;
- int err = Interop.Sys.GetHostByAddress(&address, &entry);
- if (err != 0)
- {
- throw SocketExceptionFactory.CreateSocketException(GetSocketErrorForErrno(err), err);
- }
-
- return CreateIPHostEntry(entry);
- }
-
+
public static unsafe SocketError TryGetAddrInfo(string name, out IPHostEntry hostinfo, out int nativeErrorCode)
{
if (name == "")
@@ -194,30 +144,45 @@ namespace System.Net
return SocketError.Success;
}
+ internal static void GetAddrInfoAsync(DnsResolveAsyncResult asyncResult)
+ {
+ throw new NotSupportedException();
+ }
+
public static unsafe string TryGetNameInfo(IPAddress addr, out SocketError socketError, out int nativeErrorCode)
{
byte* buffer = stackalloc byte[Interop.Sys.NI_MAXHOST + 1 /*for null*/];
- // TODO #2891: Remove the copying step to improve performance. This requires a change in the contracts.
- byte[] addressBuffer = addr.GetAddressBytes();
-
- int error;
- fixed (byte* rawAddress = &addressBuffer[0])
+ byte isIPv6;
+ int rawAddressLength;
+ if (addr.AddressFamily == AddressFamily.InterNetwork)
{
- error = Interop.Sys.GetNameInfo(
- rawAddress,
- unchecked((uint)addressBuffer.Length),
- addr.AddressFamily == AddressFamily.InterNetworkV6 ? (byte)1 : (byte)0,
- buffer,
- Interop.Sys.NI_MAXHOST,
- null,
- 0,
- Interop.Sys.GetNameInfoFlags.NI_NAMEREQD);
+ isIPv6 = 0;
+ rawAddressLength = IPAddressParserStatics.IPv4AddressBytes;
}
+ else
+ {
+ isIPv6 = 1;
+ rawAddressLength = IPAddressParserStatics.IPv6AddressBytes;
+ }
+
+ byte* rawAddress = stackalloc byte[rawAddressLength];
+ addr.TryWriteBytes(new Span<byte>(rawAddress, rawAddressLength), out int bytesWritten);
+ Debug.Assert(bytesWritten == rawAddressLength);
+
+ int error = Interop.Sys.GetNameInfo(
+ rawAddress,
+ (uint)rawAddressLength,
+ isIPv6,
+ buffer,
+ Interop.Sys.NI_MAXHOST,
+ null,
+ 0,
+ Interop.Sys.GetNameInfoFlags.NI_NAMEREQD);
socketError = GetSocketErrorForNativeError(error);
nativeErrorCode = error;
- return socketError != SocketError.Success ? null : Marshal.PtrToStringAnsi((IntPtr)buffer);
+ return socketError != SocketError.Success ? null : Marshal.PtrToStringAnsi((IntPtr)buffer);
}
public static string GetHostName()
diff --git a/src/System.Net.NameResolution/src/System/Net/NameResolutionPal.Win32.cs b/src/System.Net.NameResolution/src/System/Net/NameResolutionPal.Win32.cs
new file mode 100644
index 0000000000..3fd64550cd
--- /dev/null
+++ b/src/System.Net.NameResolution/src/System/Net/NameResolutionPal.Win32.cs
@@ -0,0 +1,24 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.Win32.SafeHandles;
+
+namespace System.Net
+{
+ internal static partial class NameResolutionPal
+ {
+ private static bool GetAddrInfoExSupportsOverlapped()
+ {
+ using (SafeLibraryHandle libHandle = Interop.Kernel32.LoadLibraryExW(Interop.Libraries.Ws2_32, IntPtr.Zero, Interop.Kernel32.LOAD_LIBRARY_SEARCH_SYSTEM32))
+ {
+ if (libHandle.IsInvalid)
+ return false;
+
+ // We can't just check that 'GetAddrInfoEx' exists, because it existed before supporting overlapped.
+ // The existence of 'GetAddrInfoExCancel' indicates that overlapped is supported.
+ return Interop.Kernel32.GetProcAddress(libHandle, Interop.Winsock.GetAddrInfoExCancelFunctionName) != IntPtr.Zero;
+ }
+ }
+ }
+}
diff --git a/src/System.Net.NameResolution/src/System/Net/NameResolutionPal.Windows.cs b/src/System.Net.NameResolution/src/System/Net/NameResolutionPal.Windows.cs
index 36a69f8637..ed6216eca9 100644
--- a/src/System.Net.NameResolution/src/System/Net/NameResolutionPal.Windows.cs
+++ b/src/System.Net.NameResolution/src/System/Net/NameResolutionPal.Windows.cs
@@ -7,19 +7,34 @@ using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Win32.SafeHandles;
using ProtocolFamily = System.Net.Internals.ProtocolFamily;
namespace System.Net
{
- internal static class NameResolutionPal
+ internal static partial class NameResolutionPal
{
//
// used by GetHostName() to preallocate a buffer for the call to gethostname.
//
private const int HostNameBufferLength = 256;
+
private static bool s_initialized;
private static readonly object s_initializedLock = new object();
+ private static readonly unsafe Interop.Winsock.LPLOOKUPSERVICE_COMPLETION_ROUTINE s_getAddrInfoExCallback = GetAddressInfoExCallback;
+ private static bool s_getAddrInfoExSupported;
+
+ public static bool SupportsGetAddrInfoAsync
+ {
+ get
+ {
+ EnsureSocketsAreInitialized();
+ return s_getAddrInfoExSupported;
+ }
+ }
+
/*++
Routine Description:
@@ -141,62 +156,6 @@ namespace System.Net
return HostEntry;
} // NativeToHostEntry
- public static IPHostEntry GetHostByName(string hostName)
- {
- //
- // IPv6 disabled: use gethostbyname() to obtain DNS information.
- //
- IntPtr nativePointer =
- Interop.Winsock.gethostbyname(
- hostName);
-
- if (nativePointer == IntPtr.Zero)
- {
- // Need to do this first since if we wait the last error code might be overwritten.
- SocketException socketException = new SocketException();
-
- IPAddress address;
- if (IPAddress.TryParse(hostName, out address))
- {
- IPHostEntry ipHostEntry = NameResolutionUtilities.GetUnresolvedAnswer(address);
- if (NetEventSource.IsEnabled) NetEventSource.Exit(null, ipHostEntry);
- return ipHostEntry;
- }
-
- throw socketException;
- }
-
- return NativeToHostEntry(nativePointer);
- }
-
- public static IPHostEntry GetHostByAddr(IPAddress address)
- {
- // TODO #2891: Optimize this (or decide if this legacy code can be removed):
-#pragma warning disable CS0618 // Address is marked obsolete
- int addressAsInt = unchecked((int)address.Address);
-#pragma warning restore CS0618
-
-#if BIGENDIAN
- // TODO #2891: above code needs testing for BIGENDIAN.
-
- addressAsInt = (int)(((uint)addressAsInt << 24) | (((uint)addressAsInt & 0x0000FF00) << 8) |
- (((uint)addressAsInt >> 8) & 0x0000FF00) | ((uint)addressAsInt >> 24));
-#endif
-
- IntPtr nativePointer =
- Interop.Winsock.gethostbyaddr(
- ref addressAsInt,
- sizeof(int),
- ProtocolFamily.InterNetwork);
-
- if (nativePointer != IntPtr.Zero)
- {
- return NativeToHostEntry(nativePointer);
- }
-
- throw new SocketException();
- }
-
public static unsafe SocketError TryGetAddrInfo(string name, out IPHostEntry hostinfo, out int nativeErrorCode)
{
//
@@ -232,7 +191,6 @@ namespace System.Net
//
while (pAddressInfo != null)
{
- SocketAddress sockaddr;
//
// Retrieve the canonical name for the host - only appears in the first AddressInfo
// entry in the returned array.
@@ -247,29 +205,17 @@ namespace System.Net
// We also filter based on whether IPv6 is supported on the current
// platform / machine.
//
- if ((pAddressInfo->ai_family == AddressFamily.InterNetwork) || // Never filter v4
- (pAddressInfo->ai_family == AddressFamily.InterNetworkV6 && SocketProtocolSupportPal.OSSupportsIPv6))
+ var socketAddress = new ReadOnlySpan<byte>(pAddressInfo->ai_addr, pAddressInfo->ai_addrlen);
+
+ if (pAddressInfo->ai_family == AddressFamily.InterNetwork)
{
- sockaddr = new SocketAddress(pAddressInfo->ai_family, pAddressInfo->ai_addrlen);
- //
- // Push address data into the socket address buffer
- //
- for (int d = 0; d < pAddressInfo->ai_addrlen; d++)
- {
- sockaddr[d] = *(pAddressInfo->ai_addr + d);
- }
- //
- // NOTE: We need an IPAddress now, the only way to create it from a
- // SocketAddress is via IPEndPoint. This ought to be simpler.
- //
- if (pAddressInfo->ai_family == AddressFamily.InterNetwork)
- {
- addresses.Add(((IPEndPoint)IPEndPointStatics.Any.Create(sockaddr)).Address);
- }
- else
- {
- addresses.Add(((IPEndPoint)IPEndPointStatics.IPv6Any.Create(sockaddr)).Address);
- }
+ if (socketAddress.Length == SocketAddressPal.IPv4AddressSize)
+ addresses.Add(CreateIPv4Address(socketAddress));
+ }
+ else if (pAddressInfo->ai_family == AddressFamily.InterNetworkV6 && SocketProtocolSupportPal.OSSupportsIPv6)
+ {
+ if (socketAddress.Length == SocketAddressPal.IPv6AddressSize)
+ addresses.Add(CreateIPv6Address(socketAddress));
}
//
// Next addressinfo entry
@@ -385,10 +331,193 @@ namespace System.Net
throw new SocketException((int)errorCode);
}
+ s_getAddrInfoExSupported = GetAddrInfoExSupportsOverlapped();
+
Volatile.Write(ref s_initialized, true);
}
}
}
}
+
+ public static unsafe void GetAddrInfoAsync(DnsResolveAsyncResult asyncResult)
+ {
+ GetAddrInfoExContext* context = GetAddrInfoExContext.AllocateContext();
+
+ try
+ {
+ var state = new GetAddrInfoExState(asyncResult);
+ context->QueryStateHandle = state.CreateHandle();
+ }
+ catch
+ {
+ GetAddrInfoExContext.FreeContext(context);
+ throw;
+ }
+
+ AddressInfoEx hints = new AddressInfoEx();
+ hints.ai_flags = AddressInfoHints.AI_CANONNAME;
+ hints.ai_family = AddressFamily.Unspecified; // Gets all address families
+
+ SocketError errorCode =
+ (SocketError)Interop.Winsock.GetAddrInfoExW(asyncResult.HostName, null, 0 /* NS_ALL*/, IntPtr.Zero, ref hints, out context->Result, IntPtr.Zero, ref context->Overlapped, s_getAddrInfoExCallback, out context->CancelHandle);
+
+ if (errorCode != SocketError.IOPending)
+ ProcessResult(errorCode, context);
+ }
+
+ private static unsafe void GetAddressInfoExCallback([In] int error, [In] int bytes, [In] NativeOverlapped* overlapped)
+ {
+ // Can be casted directly to GetAddrInfoExContext* because the overlapped is its first field
+ GetAddrInfoExContext* context = (GetAddrInfoExContext*)overlapped;
+
+ ProcessResult((SocketError)error, context);
+ }
+
+ private static unsafe void ProcessResult(SocketError errorCode, GetAddrInfoExContext* context)
+ {
+ try
+ {
+ GetAddrInfoExState state = GetAddrInfoExState.FromHandleAndFree(context->QueryStateHandle);
+
+ if (errorCode != SocketError.Success)
+ {
+ state.CompleteAsyncResult(new SocketException((int)errorCode));
+ return;
+ }
+
+ AddressInfoEx* result = context->Result;
+ string canonicalName = null;
+
+ List<IPAddress> addresses = new List<IPAddress>();
+
+ while (result != null)
+ {
+ if (canonicalName == null && result->ai_canonname != IntPtr.Zero)
+ canonicalName = Marshal.PtrToStringUni(result->ai_canonname);
+
+ var socketAddress = new ReadOnlySpan<byte>(result->ai_addr, result->ai_addrlen);
+
+ if (result->ai_family == AddressFamily.InterNetwork)
+ {
+ if (socketAddress.Length == SocketAddressPal.IPv4AddressSize)
+ addresses.Add(CreateIPv4Address(socketAddress));
+ }
+ else if (SocketProtocolSupportPal.OSSupportsIPv6 && result->ai_family == AddressFamily.InterNetworkV6)
+ {
+ if (socketAddress.Length == SocketAddressPal.IPv6AddressSize)
+ addresses.Add(CreateIPv6Address(socketAddress));
+ }
+
+ result = result->ai_next;
+ }
+
+ if (canonicalName == null)
+ canonicalName = state.HostName;
+
+ state.CompleteAsyncResult(new IPHostEntry
+ {
+ HostName = canonicalName,
+ Aliases = Array.Empty<string>(),
+ AddressList = addresses.ToArray()
+ });
+ }
+ finally
+ {
+ GetAddrInfoExContext.FreeContext(context);
+ }
+ }
+
+ private static unsafe IPAddress CreateIPv4Address(ReadOnlySpan<byte> socketAddress)
+ {
+ long address = (long)SocketAddressPal.GetIPv4Address(socketAddress) & 0x0FFFFFFFF;
+ return new IPAddress(address);
+ }
+
+ private static unsafe IPAddress CreateIPv6Address(ReadOnlySpan<byte> socketAddress)
+ {
+ Span<byte> address = stackalloc byte[IPAddressParserStatics.IPv6AddressBytes];
+ uint scope;
+ SocketAddressPal.GetIPv6Address(socketAddress, address, out scope);
+
+ return new IPAddress(address, (long)scope);
+ }
+
+ #region GetAddrInfoAsync Helper Classes
+
+ //
+ // Warning: If this ever ported to NETFX, AppDomain unloads needs to be handled
+ // to protect against AppDomainUnloadException if there are pending operations.
+ //
+
+ private sealed class GetAddrInfoExState
+ {
+ private DnsResolveAsyncResult _asyncResult;
+ private object _result;
+
+ public string HostName => _asyncResult.HostName;
+
+ public GetAddrInfoExState(DnsResolveAsyncResult asyncResult)
+ {
+ _asyncResult = asyncResult;
+ }
+
+ public void CompleteAsyncResult(object o)
+ {
+ // We don't want to expose the GetAddrInfoEx callback thread to user code.
+ // The callback occurs in a native windows thread pool.
+
+ _result = o;
+
+ Task.Factory.StartNew(s =>
+ {
+ var self = (GetAddrInfoExState)s;
+ self._asyncResult.InvokeCallback(self._result);
+ }, this, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
+ }
+
+ public IntPtr CreateHandle()
+ {
+ GCHandle handle = GCHandle.Alloc(this, GCHandleType.Normal);
+ return GCHandle.ToIntPtr(handle);
+ }
+
+ public static GetAddrInfoExState FromHandleAndFree(IntPtr handle)
+ {
+ GCHandle gcHandle = GCHandle.FromIntPtr(handle);
+ var state = (GetAddrInfoExState)gcHandle.Target;
+ gcHandle.Free();
+
+ return state;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private unsafe struct GetAddrInfoExContext
+ {
+ private static readonly int Size = sizeof(GetAddrInfoExContext);
+
+ public NativeOverlapped Overlapped;
+ public AddressInfoEx* Result;
+ public IntPtr CancelHandle;
+ public IntPtr QueryStateHandle;
+
+ public static GetAddrInfoExContext* AllocateContext()
+ {
+ var context = (GetAddrInfoExContext*)Marshal.AllocHGlobal(Size);
+ *context = default;
+
+ return context;
+ }
+
+ public static void FreeContext(GetAddrInfoExContext* context)
+ {
+ if (context->Result != null)
+ Interop.Winsock.FreeAddrInfoEx(context->Result);
+
+ Marshal.FreeHGlobal((IntPtr)context);
+ }
+ }
+
+ #endregion
}
}
diff --git a/src/System.Net.NameResolution/tests/PalTests/Configurations.props b/src/System.Net.NameResolution/tests/PalTests/Configurations.props
index eddfd3a9ac..1040c9ba37 100644
--- a/src/System.Net.NameResolution/tests/PalTests/Configurations.props
+++ b/src/System.Net.NameResolution/tests/PalTests/Configurations.props
@@ -2,8 +2,6 @@
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildConfigurations>
- netstandard-Windows_NT;
- netstandard-Unix;
netcoreapp-Windows_NT;
netcoreapp-Unix;
</BuildConfigurations>
diff --git a/src/System.Net.NameResolution/tests/PalTests/Fakes/FakeContextAwareResult.cs b/src/System.Net.NameResolution/tests/PalTests/Fakes/FakeContextAwareResult.cs
new file mode 100644
index 0000000000..8a9615c9d2
--- /dev/null
+++ b/src/System.Net.NameResolution/tests/PalTests/Fakes/FakeContextAwareResult.cs
@@ -0,0 +1,91 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading;
+
+namespace System.Net
+{
+ internal partial class ContextAwareResult : IAsyncResult
+ {
+ private AsyncCallback _callback;
+
+ private static Func<object> _resultFactory;
+
+ public static void FakeSetResultFactory(Func<object> resultFactory)
+ {
+ _resultFactory = resultFactory;
+ }
+
+ public object AsyncState
+ {
+ get
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ internal bool EndCalled
+ {
+ get;
+ set;
+ }
+
+ internal object Result
+ {
+ get
+ {
+ return _resultFactory?.Invoke();
+ }
+ }
+
+ public WaitHandle AsyncWaitHandle
+ {
+ get
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public bool CompletedSynchronously
+ {
+ get
+ {
+ // Simulate sync completion:
+ return true;
+ }
+ }
+
+ public bool IsCompleted
+ {
+ get
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ internal ContextAwareResult(object myObject, object myState, AsyncCallback myCallBack)
+ {
+ _callback = myCallBack;
+ }
+
+ internal object StartPostingAsyncOp(bool lockCapture)
+ {
+ return null;
+ }
+
+ internal bool FinishPostingAsyncOp()
+ {
+ return true;
+ }
+
+ internal void InvokeCallback(object result)
+ {
+ _callback.Invoke(this);
+ }
+
+ internal void InternalWaitForCompletion() { }
+
+
+ }
+}
diff --git a/src/System.Net.NameResolution/tests/PalTests/NameResolutionPalTests.cs b/src/System.Net.NameResolution/tests/PalTests/NameResolutionPalTests.cs
index 1481a4a8cf..cd11cdf5d9 100644
--- a/src/System.Net.NameResolution/tests/PalTests/NameResolutionPalTests.cs
+++ b/src/System.Net.NameResolution/tests/PalTests/NameResolutionPalTests.cs
@@ -23,87 +23,6 @@ namespace System.Net.NameResolution.PalTests
}
[Fact]
- public void GetHostByName_LocalHost()
- {
- IPHostEntry hostEntry = NameResolutionPal.GetHostByName("localhost");
- Assert.NotNull(hostEntry);
- Assert.NotNull(hostEntry.HostName);
- Assert.NotNull(hostEntry.AddressList);
- Assert.NotNull(hostEntry.Aliases);
- }
-
- public static object[][] InvalidHostNames = new object[][] {
- new object[] { ":" },
- new object[] { "..." }
- };
-
- [Theory, MemberData(nameof(InvalidHostNames))]
- public void GetHostByName_InvalidHostName_Throws(string hostName)
- {
- Assert.ThrowsAny<SocketException>(() => NameResolutionPal.GetHostByName(hostName));
- }
-
- [Fact]
- public void GetHostByName_HostName()
- {
- string hostName = NameResolutionPal.GetHostName();
- Assert.NotNull(hostName);
-
- IPHostEntry hostEntry = NameResolutionPal.GetHostByName(hostName);
- Assert.NotNull(hostEntry);
- Assert.NotNull(hostEntry.HostName);
- Assert.NotNull(hostEntry.AddressList);
- Assert.NotNull(hostEntry.Aliases);
- }
-
- [Fact]
- public void GetHostByAddr_LocalHost()
- {
- Assert.NotNull(NameResolutionPal.GetHostByAddr(new IPAddress(0x0100007f)));
- }
-
- [Fact]
- public void GetHostByName_LocalHost_GetHostByAddr()
- {
- IPHostEntry hostEntry1 = NameResolutionPal.GetHostByName("localhost");
- Assert.NotNull(hostEntry1);
- IPHostEntry hostEntry2 = NameResolutionPal.GetHostByAddr(hostEntry1.AddressList[0]);
- Assert.NotNull(hostEntry2);
-
- IPAddress[] list1 = hostEntry1.AddressList;
- IPAddress[] list2 = hostEntry2.AddressList;
-
- for (int i = 0; i < list1.Length; i++)
- {
- Assert.NotEqual(-1, Array.IndexOf(list2, list1[i]));
- }
- }
-
- [Fact]
- public void GetHostByName_HostName_GetHostByAddr()
- {
- IPHostEntry hostEntry1 = NameResolutionPal.GetHostByName(System.Net.Test.Common.Configuration.Http.Http2Host);
- Assert.NotNull(hostEntry1);
-
- IPAddress[] list1 = hostEntry1.AddressList;
- Assert.InRange(list1.Length, 1, Int32.MaxValue);
-
- foreach (IPAddress addr1 in list1)
- {
- IPHostEntry hostEntry2 = NameResolutionPal.GetHostByAddr(addr1);
- Assert.NotNull(hostEntry2);
-
- IPAddress[] list2 = hostEntry2.AddressList;
- Assert.InRange(list2.Length, 1, list1.Length);
-
- foreach (IPAddress addr2 in list2)
- {
- Assert.NotEqual(-1, Array.IndexOf(list1, addr2));
- }
- }
- }
-
- [Fact]
public void TryGetAddrInfo_LocalHost()
{
IPHostEntry hostEntry;
@@ -125,6 +44,13 @@ namespace System.Net.NameResolution.PalTests
IPHostEntry hostEntry;
int nativeErrorCode;
SocketError error = NameResolutionPal.TryGetAddrInfo(hostName, out hostEntry, out nativeErrorCode);
+ if (error == SocketError.HostNotFound && (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)))
+ {
+ // On Unix, we are not guaranteed to be able to resove the local host. The ability to do so depends on the
+ // machine configurations, which varies by distro and is often inconsistent.
+ return;
+ }
+
Assert.Equal(SocketError.Success, error);
Assert.NotNull(hostEntry);
Assert.NotNull(hostEntry.HostName);
diff --git a/src/System.Net.NameResolution/tests/PalTests/System.Net.NameResolution.Pal.Tests.csproj b/src/System.Net.NameResolution/tests/PalTests/System.Net.NameResolution.Pal.Tests.csproj
index 333aa11cc1..acab23bbe2 100644
--- a/src/System.Net.NameResolution/tests/PalTests/System.Net.NameResolution.Pal.Tests.csproj
+++ b/src/System.Net.NameResolution/tests/PalTests/System.Net.NameResolution.Pal.Tests.csproj
@@ -10,10 +10,6 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Unix-Debug|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Unix-Release|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Windows_NT-Debug|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Windows_NT-Release|AnyCPU'" />
<!-- Do not reference these assemblies from the TargetingPack since we are building part of the source code for tests. -->
<ItemGroup>
<TargetingPackExclusions Include="System.Net.NameResolution" />
@@ -24,6 +20,7 @@
</Compile>
</ItemGroup>
<ItemGroup>
+ <Compile Include="Fakes\FakeContextAwareResult.cs" />
<Compile Include="NameResolutionPalTests.cs" />
<Compile Include="Fakes\DebugThreadTracking.cs" />
<Compile Include="Fakes\DnsFake.cs" />
@@ -34,6 +31,9 @@
<Compile Include="..\..\src\System\Net\NameResolutionUtilities.cs">
<Link>ProductionCode\System\Net\NameResolutionUtilities.cs</Link>
</Compile>
+ <Compile Include="..\..\src\System\Net\DnsResolveAsyncResult.cs">
+ <Link>ProductionCode\System\Net\DnsResolveAsyncResult.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\System\Net\Sockets\ProtocolType.cs" Condition="'$(OSGroup)' == 'Windows_NT'">
<Link>Common\System\Net\Sockets\ProtocolType.cs</Link>
</Compile>
@@ -52,11 +52,20 @@
<Compile Include="$(CommonTestPath)\System\Net\Configuration.Http.cs">
<Link>Common\System\Net\Configuration.Http.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Net\ByteOrder.cs">
+ <Link>Common\System\Net\ByteOrder.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup Condition=" '$(TargetsWindows)' == 'true' ">
<Compile Include="..\..\src\System\Net\NameResolutionPal.Windows.cs">
<Link>ProductionCode\System\Net\NameResolutionPal.Windows.cs</Link>
</Compile>
+ <Compile Include="..\..\src\System\Net\NameResolutionPal.Uap.cs" Condition="'$(TargetGroup)' == 'uap'">
+ <Link>ProductionCode\System\Net\NameResolutionPal.Uap.cs</Link>
+ </Compile>
+ <Compile Include="..\..\src\System\Net\NameResolutionPal.Win32.cs" Condition="'$(TargetGroup)' == 'netcoreapp'">
+ <Link>ProductionCode\System\Net\NameResolutionPal.Win32.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\System\Net\InternalException.cs">
<Link>Common\System\Net\InternalException.cs</Link>
</Compile>
@@ -66,6 +75,9 @@
<Compile Include="$(CommonPath)\System\Net\SocketProtocolSupportPal.Windows.cs">
<Link>System\Net\SocketProtocolSupportPal.Windows</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Net\SocketAddressPal.Windows.cs">
+ <Link>Common\System\Net\SocketAddressPal.Windows</Link>
+ </Compile>
<!-- Debug only -->
<Compile Include="$(CommonPath)\System\Net\DebugSafeHandle.cs">
<Link>Common\System\Net\DebugSafeHandle.cs</Link>
@@ -86,12 +98,6 @@
<Compile Include="$(CommonPath)\Interop\Windows\Winsock\Interop.closesocket.cs">
<Link>Interop\Windows\Winsock\Interop.closesocket.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\Winsock\Interop.gethostbyaddr.cs">
- <Link>Interop\Windows\Winsock\Interop.gethostbyaddr.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\Winsock\Interop.gethostbyname.cs">
- <Link>Interop\Windows\Winsock\Interop.gethostbyname.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\Interop\Windows\Winsock\Interop.gethostname.cs">
<Link>Interop\Windows\Winsock\Interop.gethostname.cs</Link>
</Compile>
@@ -116,6 +122,24 @@
<Compile Include="$(CommonPath)\Interop\Windows\Winsock\SafeFreeAddrInfo.cs">
<Link>Interop\Windows\Winsock\SafeFreeAddrInfo.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\Winsock\AddressInfoEx.cs">
+ <Link>Interop\Windows\Winsock\AddressInfoEx.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\Winsock\Interop.GetAddrInfoExW.cs">
+ <Link>Interop\Windows\Winsock\Interop.GetAddrInfoExW.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeLibraryHandle.cs">
+ <Link>Common\Microsoft\Win32\SafeHandles\SafeLibraryHandle.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\Kernel32\Interop.GetProcAddress.cs">
+ <Link>Interop\Windows\Kernel32\Interop.GetProcAddress.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\Kernel32\Interop.LoadLibraryEx.cs">
+ <Link>Interop\Windows\Kernel32\Interop.LoadLibraryEx.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\Kernel32\Interop.FreeLibrary.cs">
+ <Link>Interop\Windows\Kernel32\Interop.FreeLibrary.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup Condition=" '$(TargetsUnix)' == 'true' ">
<Compile Include="$(CommonPath)\System\Net\SocketAddressPal.Unix.cs">
@@ -124,9 +148,6 @@
<Compile Include="$(CommonPath)\Interop\Interop.CheckedAccess.cs">
<Link>Common\System\Net\Internals\Interop.CheckedAccess.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Net\ByteOrder.cs">
- <Link>Common\System\Net\Internals\ByteOrder.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\System\Net\InteropIPAddressExtensions.Unix.cs">
<Link>Common\System\Net\InteropIPAddressExtensions.Unix.cs</Link>
</Compile>
@@ -171,4 +192,4 @@
</Compile>
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project>
+</Project> \ No newline at end of file
diff --git a/src/System.Net.NameResolution/tests/UnitTests/Fakes/FakeNameResolutionPal.cs b/src/System.Net.NameResolution/tests/UnitTests/Fakes/FakeNameResolutionPal.cs
index 74da893f32..69d1bc9929 100644
--- a/src/System.Net.NameResolution/tests/UnitTests/Fakes/FakeNameResolutionPal.cs
+++ b/src/System.Net.NameResolution/tests/UnitTests/Fakes/FakeNameResolutionPal.cs
@@ -10,6 +10,8 @@ namespace System.Net
{
internal static class NameResolutionPal
{
+ public static bool SupportsGetAddrInfoAsync => false;
+
internal static int FakesEnsureSocketsAreInitializedCallCount
{
get;
@@ -49,6 +51,11 @@ namespace System.Net
throw new NotImplementedException();
}
+ internal static void GetAddrInfoAsync(DnsResolveAsyncResult asyncResult)
+ {
+ throw new NotImplementedException();
+ }
+
internal static IPHostEntry GetHostByAddr(IPAddress address)
{
throw new NotImplementedException();
diff --git a/src/System.Net.NameResolution/tests/UnitTests/System.Net.NameResolution.Unit.Tests.csproj b/src/System.Net.NameResolution/tests/UnitTests/System.Net.NameResolution.Unit.Tests.csproj
index e99d16ebed..b52ff2aafc 100644
--- a/src/System.Net.NameResolution/tests/UnitTests/System.Net.NameResolution.Unit.Tests.csproj
+++ b/src/System.Net.NameResolution/tests/UnitTests/System.Net.NameResolution.Unit.Tests.csproj
@@ -27,6 +27,9 @@
<Compile Include="..\..\src\System\Net\DNS.cs">
<Link>ProductionCode\System\Net\DNS.cs</Link>
</Compile>
+ <Compile Include="..\..\src\System\Net\DnsResolveAsyncResult.cs">
+ <Link>ProductionCode\System\Net\DnsResolveAsyncResult.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup>
<Compile Include="InitializationTest.cs" />
diff --git a/src/System.Net.NetworkInformation/src/System.Net.NetworkInformation.csproj b/src/System.Net.NetworkInformation/src/System.Net.NetworkInformation.csproj
index 575d33d0a3..e2a3f6ae0b 100644
--- a/src/System.Net.NetworkInformation/src/System.Net.NetworkInformation.csproj
+++ b/src/System.Net.NetworkInformation/src/System.Net.NetworkInformation.csproj
@@ -6,6 +6,7 @@
<OutputType>Library</OutputType>
<ProjectGuid>{3CA89D6C-F8D1-4813-9775-F8D249686E31}</ProjectGuid>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <ILLinkClearInitLocals>true</ILLinkClearInitLocals>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='uap-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='uap-Windows_NT-Release|AnyCPU'" />
@@ -34,6 +35,7 @@
<Compile Include="System\Net\NetworkInformation\MulticastIPAddressInformationCollection.cs" />
<Compile Include="System\Net\NetworkInformation\NetBiosNodeType.cs" />
<Compile Include="System\Net\NetworkInformation\NetEventSource.NetworkInformation.cs" />
+ <Compile Include="System\Net\NetworkInformation\NetworkAddressChange.cs" />
<Compile Include="System\Net\NetworkInformation\NetworkAvailabilityEventArgs.cs" />
<Compile Include="System\Net\NetworkInformation\NetworkChangeDelegates.cs" />
<Compile Include="System\Net\NetworkInformation\NetworkInterface.cs" />
diff --git a/src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.Linux.cs b/src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.Linux.cs
index c7a29ebcef..20eb573056 100644
--- a/src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.Linux.cs
+++ b/src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.Linux.cs
@@ -2,18 +2,16 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Collections.Generic;
using System.Diagnostics;
-using System.Linq;
using System.Threading.Tasks;
using System.Threading;
namespace System.Net.NetworkInformation
{
// Linux implementation of NetworkChange
- public class NetworkChange
+ public partial class NetworkChange
{
- private static NetworkAddressChangedEventHandler s_addressChangedSubscribers;
- private static NetworkAvailabilityChangedEventHandler s_availabilityChangedSubscribers;
private static volatile int s_socket = 0;
// Lock controlling access to delegate subscriptions, socket initialization, availability-changed state and timer.
private static readonly object s_gate = new object();
@@ -37,30 +35,37 @@ namespace System.Net.NetworkInformation
{
add
{
- lock (s_gate)
+ if (value != null)
{
- if (s_socket == 0)
+ lock (s_gate)
{
- CreateSocket();
- }
+ if (s_socket == 0)
+ {
+ CreateSocket();
+ }
- s_addressChangedSubscribers += value;
+ s_addressChangedSubscribers.TryAdd(value, ExecutionContext.Capture());
+ }
}
}
remove
{
- lock (s_gate)
+ if (value != null)
{
- if (s_addressChangedSubscribers == null && s_availabilityChangedSubscribers == null)
+ lock (s_gate)
{
- Debug.Assert(s_socket == 0, "s_socket != 0, but there are no subscribers to NetworkAddressChanged or NetworkAvailabilityChanged.");
- return;
- }
+ if (s_addressChangedSubscribers.Count == 0 && s_availabilityChangedSubscribers.Count == 0)
+ {
+ Debug.Assert(s_socket == 0,
+ "s_socket != 0, but there are no subscribers to NetworkAddressChanged or NetworkAvailabilityChanged.");
+ return;
+ }
- s_addressChangedSubscribers -= value;
- if (s_addressChangedSubscribers == null && s_availabilityChangedSubscribers == null)
- {
- CloseSocket();
+ s_addressChangedSubscribers.Remove(value);
+ if (s_addressChangedSubscribers.Count == 0 && s_availabilityChangedSubscribers.Count == 0)
+ {
+ CloseSocket();
+ }
}
}
}
@@ -70,50 +75,74 @@ namespace System.Net.NetworkInformation
{
add
{
- lock (s_gate)
+ if (value != null)
{
- if (s_socket == 0)
- {
- CreateSocket();
- }
- if (s_availabilityTimer == null)
+ lock (s_gate)
{
- s_availabilityTimer = new Timer(s_availabilityTimerFiredCallback, null, -1, -1);
- }
+ if (s_socket == 0)
+ {
+ CreateSocket();
+ }
+
+ if (s_availabilityTimer == null)
+ {
+ // Don't capture the current ExecutionContext and its AsyncLocals onto the timer causing them to live forever
+ bool restoreFlow = false;
+ try
+ {
+ if (!ExecutionContext.IsFlowSuppressed())
+ {
+ ExecutionContext.SuppressFlow();
+ restoreFlow = true;
+ }
+
+ s_availabilityTimer = new Timer(s_availabilityTimerFiredCallback, null, Timeout.Infinite, Timeout.Infinite);
+ }
+ finally
+ {
+ // Restore the current ExecutionContext
+ if (restoreFlow)
+ ExecutionContext.RestoreFlow();
+ }
+ }
- s_availabilityChangedSubscribers += value;
+ s_availabilityChangedSubscribers.TryAdd(value, ExecutionContext.Capture());
+ }
}
}
remove
{
- lock (s_gate)
+ if (value != null)
{
- if (s_addressChangedSubscribers == null && s_availabilityChangedSubscribers == null)
- {
- Debug.Assert(s_socket == 0, "s_socket != 0, but there are no subscribers to NetworkAddressChanged or NetworkAvailabilityChanged.");
- return;
- }
-
- s_availabilityChangedSubscribers -= value;
- if (s_availabilityChangedSubscribers == null)
+ lock (s_gate)
{
- if (s_availabilityTimer != null)
+ if (s_addressChangedSubscribers.Count == 0 && s_availabilityChangedSubscribers.Count == 0)
{
- s_availabilityTimer.Dispose();
- s_availabilityTimer = null;
- s_availabilityHasChanged = false;
+ Debug.Assert(s_socket == 0,
+ "s_socket != 0, but there are no subscribers to NetworkAddressChanged or NetworkAvailabilityChanged.");
+ return;
}
- if (s_addressChangedSubscribers == null)
+ s_availabilityChangedSubscribers.Remove(value);
+ if (s_availabilityChangedSubscribers.Count == 0)
{
- CloseSocket();
+ if (s_availabilityTimer != null)
+ {
+ s_availabilityTimer.Dispose();
+ s_availabilityTimer = null;
+ s_availabilityHasChanged = false;
+ }
+
+ if (s_addressChangedSubscribers.Count == 0)
+ {
+ CloseSocket();
+ }
}
}
}
}
}
-
private static void CreateSocket()
{
Debug.Assert(s_socket == 0, "s_socket != 0, must close existing socket before opening another.");
@@ -150,7 +179,7 @@ namespace System.Net.NetworkInformation
Interop.Sys.ReadEvents(socket, s_networkChangeCallback);
}
}
-
+
private static void ProcessEvent(int socket, Interop.Sys.NetworkChangeKind kind)
{
if (kind != Interop.Sys.NetworkChangeKind.None)
@@ -171,7 +200,7 @@ namespace System.Net.NetworkInformation
{
case Interop.Sys.NetworkChangeKind.AddressAdded:
case Interop.Sys.NetworkChangeKind.AddressRemoved:
- s_addressChangedSubscribers?.Invoke(null, EventArgs.Empty);
+ OnAddressChanged();
break;
case Interop.Sys.NetworkChangeKind.AvailabilityChanged:
lock (s_gate)
@@ -189,18 +218,77 @@ namespace System.Net.NetworkInformation
}
}
+ private static void OnAddressChanged()
+ {
+ Dictionary<NetworkAddressChangedEventHandler, ExecutionContext> addressChangedSubscribers = null;
+
+ lock (s_gate)
+ {
+ if (s_addressChangedSubscribers.Count > 0)
+ {
+ addressChangedSubscribers = new Dictionary<NetworkAddressChangedEventHandler, ExecutionContext>(s_addressChangedSubscribers);
+ }
+ }
+
+ if (addressChangedSubscribers != null)
+ {
+ foreach (KeyValuePair<NetworkAddressChangedEventHandler, ExecutionContext>
+ subscriber in addressChangedSubscribers)
+ {
+ NetworkAddressChangedEventHandler handler = subscriber.Key;
+ ExecutionContext ec = subscriber.Value;
+
+ if (ec == null) // Flow supressed
+ {
+ handler(null, EventArgs.Empty);
+ }
+ else
+ {
+ ExecutionContext.Run(ec, s_runAddressChangedHandler, handler);
+ }
+ }
+ }
+ }
+
private static void OnAvailabilityTimerFired(object state)
{
- bool changed;
+ Dictionary<NetworkAvailabilityChangedEventHandler, ExecutionContext> availabilityChangedSubscribers = null;
+
lock (s_gate)
{
- changed = s_availabilityHasChanged;
- s_availabilityHasChanged = false;
+ if (s_availabilityHasChanged)
+ {
+ s_availabilityHasChanged = false;
+ if (s_availabilityChangedSubscribers.Count > 0)
+ {
+ availabilityChangedSubscribers =
+ new Dictionary<NetworkAvailabilityChangedEventHandler, ExecutionContext>(
+ s_availabilityChangedSubscribers);
+ }
+ }
}
- if (changed)
+ if (availabilityChangedSubscribers != null)
{
- s_availabilityChangedSubscribers?.Invoke(null, new NetworkAvailabilityEventArgs(NetworkInterface.GetIsNetworkAvailable()));
+ bool isAvailable = NetworkInterface.GetIsNetworkAvailable();
+ NetworkAvailabilityEventArgs args = isAvailable ? s_availableEventArgs : s_notAvailableEventArgs;
+ ContextCallback callbackContext = isAvailable ? s_runHandlerAvailable : s_runHandlerNotAvailable;
+
+ foreach (KeyValuePair<NetworkAvailabilityChangedEventHandler, ExecutionContext>
+ subscriber in availabilityChangedSubscribers)
+ {
+ NetworkAvailabilityChangedEventHandler handler = subscriber.Key;
+ ExecutionContext ec = subscriber.Value;
+
+ if (ec == null) // Flow supressed
+ {
+ handler(null, args);
+ }
+ else
+ {
+ ExecutionContext.Run(ec, callbackContext, handler);
+ }
+ }
}
}
}
diff --git a/src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.OSX.cs b/src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.OSX.cs
index cff7cd1cae..aef7fb0994 100644
--- a/src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.OSX.cs
+++ b/src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.OSX.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Collections.Generic;
using Microsoft.Win32.SafeHandles;
using System.Diagnostics;
using System.Threading;
@@ -14,16 +15,10 @@ namespace System.Net.NetworkInformation
// OSX implementation of NetworkChange
// See <SystemConfiguration/SystemConfiguration.h> and its documentation, as well as
// the documentation for CFRunLoop for more information on the components involved.
- public class NetworkChange
+ public partial class NetworkChange
{
private static object s_lockObj = new object();
- // The list of current address-changed subscribers.
- private static NetworkAddressChangedEventHandler s_addressChangedSubscribers;
-
- // The list of current availability-changed subscribers.
- private static NetworkAvailabilityChangedEventHandler s_availabilityChangedSubscribers;
-
// The dynamic store. We listen to changes in the IPv4 and IPv6 address keys.
// When those keys change, our callback below is called (OnAddressChanged).
private static SafeCreateHandle s_dynamicStoreRef;
@@ -54,26 +49,34 @@ namespace System.Net.NetworkInformation
{
add
{
- lock (s_lockObj)
+ if (value != null)
{
- if (s_addressChangedSubscribers == null && s_availabilityChangedSubscribers == null)
+ lock (s_lockObj)
{
- CreateAndStartRunLoop();
- }
+ if (s_addressChangedSubscribers.Count == 0 &&
+ s_availabilityChangedSubscribers.Count == 0)
+ {
+ CreateAndStartRunLoop();
+ }
- s_addressChangedSubscribers += value;
+ s_addressChangedSubscribers.TryAdd(value, ExecutionContext.Capture());
+ }
}
}
remove
{
- lock (s_lockObj)
+ if (value != null)
{
- bool hadAddressChangedSubscribers = s_addressChangedSubscribers != null;
- s_addressChangedSubscribers -= value;
-
- if (hadAddressChangedSubscribers && s_addressChangedSubscribers == null && s_availabilityChangedSubscribers == null)
+ lock (s_lockObj)
{
- StopRunLoop();
+ bool hadAddressChangedSubscribers = s_addressChangedSubscribers.Count != 0;
+ s_addressChangedSubscribers.Remove(value);
+
+ if (hadAddressChangedSubscribers && s_addressChangedSubscribers.Count == 0 &&
+ s_availabilityChangedSubscribers.Count == 0)
+ {
+ StopRunLoop();
+ }
}
}
}
@@ -83,30 +86,39 @@ namespace System.Net.NetworkInformation
{
add
{
- lock (s_lockObj)
+ if (value != null)
{
- if (s_addressChangedSubscribers == null && s_availabilityChangedSubscribers == null)
- {
- CreateAndStartRunLoop();
- }
- else
+ lock (s_lockObj)
{
- Debug.Assert(s_runLoop != IntPtr.Zero);
- }
+ if (s_addressChangedSubscribers.Count == 0 &&
+ s_availabilityChangedSubscribers.Count == 0)
+ {
+ CreateAndStartRunLoop();
+ }
+ else
+ {
+ Debug.Assert(s_runLoop != IntPtr.Zero);
+ }
- s_availabilityChangedSubscribers += value;
+ s_availabilityChangedSubscribers.TryAdd(value, ExecutionContext.Capture());
+ }
}
}
remove
{
- lock (s_lockObj)
+ if (value != null)
{
- bool hadSubscribers = s_addressChangedSubscribers != null || s_availabilityChangedSubscribers != null;
- s_availabilityChangedSubscribers -= value;
-
- if (hadSubscribers && s_addressChangedSubscribers == null && s_availabilityChangedSubscribers == null)
+ lock (s_lockObj)
{
- StopRunLoop();
+ bool hadSubscribers = s_addressChangedSubscribers.Count != 0 ||
+ s_availabilityChangedSubscribers.Count != 0;
+ s_availabilityChangedSubscribers.Remove(value);
+
+ if (hadSubscribers && s_addressChangedSubscribers.Count == 0 &&
+ s_availabilityChangedSubscribers.Count == 0)
+ {
+ StopRunLoop();
+ }
}
}
}
@@ -221,8 +233,61 @@ namespace System.Net.NetworkInformation
private static void OnAddressChanged(IntPtr store, IntPtr changedKeys, IntPtr info)
{
- s_addressChangedSubscribers?.Invoke(null, EventArgs.Empty);
- s_availabilityChangedSubscribers?.Invoke(null, new NetworkAvailabilityEventArgs(NetworkInterface.GetIsNetworkAvailable()));
+ Dictionary<NetworkAddressChangedEventHandler, ExecutionContext> addressChangedSubscribers = null;
+ Dictionary<NetworkAvailabilityChangedEventHandler, ExecutionContext> availabilityChangedSubscribers = null;
+
+ lock (s_lockObj)
+ {
+ if (s_addressChangedSubscribers.Count > 0)
+ {
+ addressChangedSubscribers = new Dictionary<NetworkAddressChangedEventHandler, ExecutionContext>(s_addressChangedSubscribers);
+ }
+ if (s_availabilityChangedSubscribers.Count > 0)
+ {
+ availabilityChangedSubscribers = new Dictionary<NetworkAvailabilityChangedEventHandler, ExecutionContext>(s_availabilityChangedSubscribers);
+ }
+ }
+
+ if (addressChangedSubscribers != null)
+ {
+ foreach (KeyValuePair<NetworkAddressChangedEventHandler, ExecutionContext>
+ subscriber in addressChangedSubscribers)
+ {
+ NetworkAddressChangedEventHandler handler = subscriber.Key;
+ ExecutionContext ec = subscriber.Value;
+
+ if (ec == null) // Flow supressed
+ {
+ handler(null, EventArgs.Empty);
+ }
+ else
+ {
+ ExecutionContext.Run(ec, s_runAddressChangedHandler, handler);
+ }
+ }
+ }
+
+ if (availabilityChangedSubscribers != null)
+ {
+ bool isAvailable = NetworkInterface.GetIsNetworkAvailable();
+ NetworkAvailabilityEventArgs args = isAvailable ? s_availableEventArgs : s_notAvailableEventArgs;
+ ContextCallback callbackContext = isAvailable ? s_runHandlerAvailable : s_runHandlerNotAvailable;
+ foreach (KeyValuePair<NetworkAvailabilityChangedEventHandler, ExecutionContext>
+ subscriber in availabilityChangedSubscribers)
+ {
+ NetworkAvailabilityChangedEventHandler handler = subscriber.Key;
+ ExecutionContext ec = subscriber.Value;
+
+ if (ec == null) // Flow supressed
+ {
+ handler(null, args);
+ }
+ else
+ {
+ ExecutionContext.Run(ec, callbackContext, handler);
+ }
+ }
+ }
}
}
}
diff --git a/src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.UnknownUnix.cs b/src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.UnknownUnix.cs
index e327f60a19..081c3420ba 100644
--- a/src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.UnknownUnix.cs
+++ b/src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.UnknownUnix.cs
@@ -4,7 +4,7 @@
namespace System.Net.NetworkInformation
{
- public class NetworkChange
+ public partial class NetworkChange
{
public static event NetworkAddressChangedEventHandler NetworkAddressChanged
{
diff --git a/src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.Windows.cs b/src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.Windows.cs
index f731dc3e79..28e9b7c616 100644
--- a/src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.Windows.cs
+++ b/src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.Windows.cs
@@ -10,7 +10,7 @@ using System.Threading;
namespace System.Net.NetworkInformation
{
- public class NetworkChange
+ public partial class NetworkChange
{
//introduced for supporting design-time loading of System.Windows.dll
[Obsolete("This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.", true)]
@@ -44,20 +44,12 @@ namespace System.Net.NetworkInformation
internal static class AvailabilityChangeListener
{
- private static readonly Dictionary<NetworkAvailabilityChangedEventHandler, ExecutionContext> s_availabilityCallerArray =
- new Dictionary<NetworkAvailabilityChangedEventHandler, ExecutionContext>();
private static readonly NetworkAddressChangedEventHandler s_addressChange = ChangedAddress;
private static volatile bool s_isAvailable = false;
- private static readonly ContextCallback s_RunHandlerCallback = new ContextCallback(RunHandlerCallback);
-
- private static void RunHandlerCallback(object state)
- {
- ((NetworkAvailabilityChangedEventHandler)state)(null, new NetworkAvailabilityEventArgs(s_isAvailable));
- }
private static void ChangedAddress(object sender, EventArgs eventArgs)
{
- Dictionary<NetworkAvailabilityChangedEventHandler, ExecutionContext> copy = null;
+ Dictionary<NetworkAvailabilityChangedEventHandler, ExecutionContext> availabilityChangedSubscribers = null;
lock (s_globalLock)
{
@@ -68,25 +60,33 @@ namespace System.Net.NetworkInformation
{
s_isAvailable = isAvailableNow;
- copy =
- new Dictionary<NetworkAvailabilityChangedEventHandler, ExecutionContext>(s_availabilityCallerArray);
+ if (s_availabilityChangedSubscribers.Count > 0)
+ {
+ availabilityChangedSubscribers = new Dictionary<NetworkAvailabilityChangedEventHandler, ExecutionContext>(s_availabilityChangedSubscribers);
+ }
}
}
// Executing user callbacks if Availability Change event occured.
- if (copy != null)
+ if (availabilityChangedSubscribers != null)
{
- foreach (var entry in copy)
+ bool isAvailable = s_isAvailable;
+ NetworkAvailabilityEventArgs args = isAvailable ? s_availableEventArgs : s_notAvailableEventArgs;
+ ContextCallback callbackContext = isAvailable ? s_runHandlerAvailable : s_runHandlerNotAvailable;
+
+ foreach (KeyValuePair<NetworkAvailabilityChangedEventHandler, ExecutionContext>
+ subscriber in availabilityChangedSubscribers)
{
- NetworkAvailabilityChangedEventHandler handler = entry.Key;
- ExecutionContext context = entry.Value;
- if (context == null)
+ NetworkAvailabilityChangedEventHandler handler = subscriber.Key;
+ ExecutionContext ec = subscriber.Value;
+
+ if (ec == null) // Flow supressed
{
- handler(null, new NetworkAvailabilityEventArgs(s_isAvailable));
+ handler(null, args);
}
else
{
- ExecutionContext.Run(context, s_RunHandlerCallback, handler);
+ ExecutionContext.Run(ec, callbackContext, handler);
}
}
}
@@ -94,29 +94,32 @@ namespace System.Net.NetworkInformation
internal static void Start(NetworkAvailabilityChangedEventHandler caller)
{
- lock (s_globalLock)
+ if (caller != null)
{
- if (s_availabilityCallerArray.Count == 0)
+ lock (s_globalLock)
{
- s_isAvailable = NetworkInterface.GetIsNetworkAvailable();
- AddressChangeListener.UnsafeStart(s_addressChange);
- }
+ if (s_availabilityChangedSubscribers.Count == 0)
+ {
+ s_isAvailable = NetworkInterface.GetIsNetworkAvailable();
+ AddressChangeListener.UnsafeStart(s_addressChange);
+ }
- if ((caller != null) && (!s_availabilityCallerArray.ContainsKey(caller)))
- {
- s_availabilityCallerArray.Add(caller, ExecutionContext.Capture());
+ s_availabilityChangedSubscribers.TryAdd(caller, ExecutionContext.Capture());
}
}
}
internal static void Stop(NetworkAvailabilityChangedEventHandler caller)
{
- lock (s_globalLock)
+ if (caller != null)
{
- s_availabilityCallerArray.Remove(caller);
- if (s_availabilityCallerArray.Count == 0)
+ lock (s_globalLock)
{
- AddressChangeListener.Stop(s_addressChange);
+ s_availabilityChangedSubscribers.Remove(caller);
+ if (s_availabilityChangedSubscribers.Count == 0)
+ {
+ AddressChangeListener.Stop(s_addressChange);
+ }
}
}
}
@@ -125,9 +128,6 @@ namespace System.Net.NetworkInformation
// Helper class for detecting address change events.
internal static unsafe class AddressChangeListener
{
- private static readonly Dictionary<NetworkAddressChangedEventHandler, ExecutionContext> s_callerArray =
- new Dictionary<NetworkAddressChangedEventHandler, ExecutionContext>();
- private static readonly ContextCallback s_runHandlerCallback = new ContextCallback(RunHandlerCallback);
private static RegisteredWaitHandle s_registeredWait;
// Need to keep the reference so it isn't GC'd before the native call executes.
@@ -141,7 +141,7 @@ namespace System.Net.NetworkInformation
// Callback fired when an address change occurs.
private static void AddressChangedCallback(object stateObject, bool signaled)
{
- Dictionary<NetworkAddressChangedEventHandler, ExecutionContext> copy;
+ Dictionary<NetworkAddressChangedEventHandler, ExecutionContext> addressChangedSubscribers = null;
lock (s_globalLock)
{
@@ -156,7 +156,10 @@ namespace System.Net.NetworkInformation
s_isListening = false;
// Need to copy the array so the callback can call start and stop
- copy = new Dictionary<NetworkAddressChangedEventHandler, ExecutionContext>(s_callerArray);
+ if (s_addressChangedSubscribers.Count > 0)
+ {
+ addressChangedSubscribers = new Dictionary<NetworkAddressChangedEventHandler, ExecutionContext>(s_addressChangedSubscribers);
+ }
try
{
@@ -170,29 +173,26 @@ namespace System.Net.NetworkInformation
}
// Release the lock before calling into user callback.
- if (copy.Count > 0)
+ if (addressChangedSubscribers != null)
{
- foreach (var entry in copy)
+ foreach (KeyValuePair<NetworkAddressChangedEventHandler, ExecutionContext>
+ subscriber in addressChangedSubscribers)
{
- NetworkAddressChangedEventHandler handler = entry.Key;
- ExecutionContext context = entry.Value;
- if (context == null)
+ NetworkAddressChangedEventHandler handler = subscriber.Key;
+ ExecutionContext ec = subscriber.Value;
+
+ if (ec == null) // Flow supressed
{
handler(null, EventArgs.Empty);
}
else
{
- ExecutionContext.Run(context, s_runHandlerCallback, handler);
+ ExecutionContext.Run(ec, s_runAddressChangedHandler, handler);
}
}
}
}
- private static void RunHandlerCallback(object state)
- {
- ((NetworkAddressChangedEventHandler)state)(null, EventArgs.Empty);
- }
-
internal static void Start(NetworkAddressChangedEventHandler caller)
{
StartHelper(caller, true, StartIPOptions.Both);
@@ -205,138 +205,141 @@ namespace System.Net.NetworkInformation
private static void StartHelper(NetworkAddressChangedEventHandler caller, bool captureContext, StartIPOptions startIPOptions)
{
- lock (s_globalLock)
+ if (caller != null)
{
- // Setup changedEvent and native overlapped struct.
- if (s_ipv4Socket == null)
+ lock (s_globalLock)
{
- int blocking;
-
- // Sockets will be initialized by the call to OSSupportsIP*.
- if (Socket.OSSupportsIPv4)
+ // Setup changedEvent and native overlapped struct.
+ if (s_ipv4Socket == null)
{
- blocking = -1;
- s_ipv4Socket = SafeCloseSocketAndEvent.CreateWSASocketWithEvent(AddressFamily.InterNetwork, SocketType.Dgram, (ProtocolType)0, true, false);
- Interop.Winsock.ioctlsocket(s_ipv4Socket, Interop.Winsock.IoctlSocketConstants.FIONBIO, ref blocking);
- s_ipv4WaitHandle = s_ipv4Socket.GetEventHandle();
- }
+ int blocking;
- if (Socket.OSSupportsIPv6)
- {
- blocking = -1;
- s_ipv6Socket = SafeCloseSocketAndEvent.CreateWSASocketWithEvent(AddressFamily.InterNetworkV6, SocketType.Dgram, (ProtocolType)0, true, false);
- Interop.Winsock.ioctlsocket(s_ipv6Socket, Interop.Winsock.IoctlSocketConstants.FIONBIO, ref blocking);
- s_ipv6WaitHandle = s_ipv6Socket.GetEventHandle();
- }
- }
+ // Sockets will be initialized by the call to OSSupportsIP*.
+ if (Socket.OSSupportsIPv4)
+ {
+ blocking = -1;
+ s_ipv4Socket = SafeCloseSocketAndEvent.CreateWSASocketWithEvent(AddressFamily.InterNetwork, SocketType.Dgram, (ProtocolType)0, true, false);
+ Interop.Winsock.ioctlsocket(s_ipv4Socket, Interop.Winsock.IoctlSocketConstants.FIONBIO, ref blocking);
+ s_ipv4WaitHandle = s_ipv4Socket.GetEventHandle();
+ }
- if ((caller != null) && (!s_callerArray.ContainsKey(caller)))
- {
- s_callerArray.Add(caller, captureContext ? ExecutionContext.Capture() : null);
- }
+ if (Socket.OSSupportsIPv6)
+ {
+ blocking = -1;
+ s_ipv6Socket = SafeCloseSocketAndEvent.CreateWSASocketWithEvent(AddressFamily.InterNetworkV6, SocketType.Dgram, (ProtocolType)0, true, false);
+ Interop.Winsock.ioctlsocket(s_ipv6Socket, Interop.Winsock.IoctlSocketConstants.FIONBIO, ref blocking);
+ s_ipv6WaitHandle = s_ipv6Socket.GetEventHandle();
+ }
+ }
- if (s_isListening || s_callerArray.Count == 0)
- {
- return;
- }
+ s_addressChangedSubscribers.TryAdd(caller, captureContext ? ExecutionContext.Capture() : null);
- if (!s_isPending)
- {
- int length;
- SocketError errorCode;
+ if (s_isListening || s_addressChangedSubscribers.Count == 0)
+ {
+ return;
+ }
- if (Socket.OSSupportsIPv4 && (startIPOptions & StartIPOptions.StartIPv4) != 0)
+ if (!s_isPending)
{
- s_registeredWait = ThreadPool.RegisterWaitForSingleObject(
- s_ipv4WaitHandle,
- new WaitOrTimerCallback(AddressChangedCallback),
- StartIPOptions.StartIPv4,
- -1,
- true);
-
- errorCode = Interop.Winsock.WSAIoctl_Blocking(
- s_ipv4Socket.DangerousGetHandle(),
- (int)IOControlCode.AddressListChange,
- null, 0, null, 0,
- out length,
- IntPtr.Zero, IntPtr.Zero);
-
- if (errorCode != SocketError.Success)
+ int length;
+ SocketError errorCode;
+
+ if (Socket.OSSupportsIPv4 && (startIPOptions & StartIPOptions.StartIPv4) != 0)
{
- NetworkInformationException exception = new NetworkInformationException();
- if (exception.ErrorCode != (uint)SocketError.WouldBlock)
+ s_registeredWait = ThreadPool.RegisterWaitForSingleObject(
+ s_ipv4WaitHandle,
+ new WaitOrTimerCallback(AddressChangedCallback),
+ StartIPOptions.StartIPv4,
+ -1,
+ true);
+
+ errorCode = Interop.Winsock.WSAIoctl_Blocking(
+ s_ipv4Socket.DangerousGetHandle(),
+ (int)IOControlCode.AddressListChange,
+ null, 0, null, 0,
+ out length,
+ IntPtr.Zero, IntPtr.Zero);
+
+ if (errorCode != SocketError.Success)
{
- throw exception;
+ NetworkInformationException exception = new NetworkInformationException();
+ if (exception.ErrorCode != (uint)SocketError.WouldBlock)
+ {
+ throw exception;
+ }
}
- }
- SafeWaitHandle s_ipv4SocketGetEventHandleSafeWaitHandle =
- s_ipv4Socket.GetEventHandle().GetSafeWaitHandle();
+ SafeWaitHandle s_ipv4SocketGetEventHandleSafeWaitHandle =
+ s_ipv4Socket.GetEventHandle().GetSafeWaitHandle();
- errorCode = Interop.Winsock.WSAEventSelect(
- s_ipv4Socket,
- s_ipv4SocketGetEventHandleSafeWaitHandle,
- Interop.Winsock.AsyncEventBits.FdAddressListChange);
+ errorCode = Interop.Winsock.WSAEventSelect(
+ s_ipv4Socket,
+ s_ipv4SocketGetEventHandleSafeWaitHandle,
+ Interop.Winsock.AsyncEventBits.FdAddressListChange);
- if (errorCode != SocketError.Success)
- {
- throw new NetworkInformationException();
+ if (errorCode != SocketError.Success)
+ {
+ throw new NetworkInformationException();
+ }
}
- }
- if (Socket.OSSupportsIPv6 && (startIPOptions & StartIPOptions.StartIPv6) != 0)
- {
- s_registeredWait = ThreadPool.RegisterWaitForSingleObject(
- s_ipv6WaitHandle,
- new WaitOrTimerCallback(AddressChangedCallback),
- StartIPOptions.StartIPv6,
- -1,
- true);
-
- errorCode = Interop.Winsock.WSAIoctl_Blocking(
- s_ipv6Socket.DangerousGetHandle(),
- (int)IOControlCode.AddressListChange,
- null, 0, null, 0,
- out length,
- IntPtr.Zero, IntPtr.Zero);
-
- if (errorCode != SocketError.Success)
+ if (Socket.OSSupportsIPv6 && (startIPOptions & StartIPOptions.StartIPv6) != 0)
{
- NetworkInformationException exception = new NetworkInformationException();
- if (exception.ErrorCode != (uint)SocketError.WouldBlock)
+ s_registeredWait = ThreadPool.RegisterWaitForSingleObject(
+ s_ipv6WaitHandle,
+ new WaitOrTimerCallback(AddressChangedCallback),
+ StartIPOptions.StartIPv6,
+ -1,
+ true);
+
+ errorCode = Interop.Winsock.WSAIoctl_Blocking(
+ s_ipv6Socket.DangerousGetHandle(),
+ (int)IOControlCode.AddressListChange,
+ null, 0, null, 0,
+ out length,
+ IntPtr.Zero, IntPtr.Zero);
+
+ if (errorCode != SocketError.Success)
{
- throw exception;
+ NetworkInformationException exception = new NetworkInformationException();
+ if (exception.ErrorCode != (uint)SocketError.WouldBlock)
+ {
+ throw exception;
+ }
}
- }
- SafeWaitHandle s_ipv6SocketGetEventHandleSafeWaitHandle =
- s_ipv6Socket.GetEventHandle().GetSafeWaitHandle();
+ SafeWaitHandle s_ipv6SocketGetEventHandleSafeWaitHandle =
+ s_ipv6Socket.GetEventHandle().GetSafeWaitHandle();
- errorCode = Interop.Winsock.WSAEventSelect(
- s_ipv6Socket,
- s_ipv6SocketGetEventHandleSafeWaitHandle,
- Interop.Winsock.AsyncEventBits.FdAddressListChange);
+ errorCode = Interop.Winsock.WSAEventSelect(
+ s_ipv6Socket,
+ s_ipv6SocketGetEventHandleSafeWaitHandle,
+ Interop.Winsock.AsyncEventBits.FdAddressListChange);
- if (errorCode != SocketError.Success)
- {
- throw new NetworkInformationException();
+ if (errorCode != SocketError.Success)
+ {
+ throw new NetworkInformationException();
+ }
}
}
- }
- s_isListening = true;
- s_isPending = true;
+ s_isListening = true;
+ s_isPending = true;
+ }
}
}
internal static void Stop(NetworkAddressChangedEventHandler caller)
{
- lock (s_globalLock)
+ if (caller != null)
{
- s_callerArray.Remove(caller);
- if (s_callerArray.Count == 0 && s_isListening)
+ lock (s_globalLock)
{
- s_isListening = false;
+ s_addressChangedSubscribers.Remove(caller);
+ if (s_addressChangedSubscribers.Count == 0 && s_isListening)
+ {
+ s_isListening = false;
+ }
}
}
}
diff --git a/src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.cs b/src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.cs
new file mode 100644
index 0000000000..ed099bac0d
--- /dev/null
+++ b/src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.cs
@@ -0,0 +1,41 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Threading;
+
+namespace System.Net.NetworkInformation
+{
+ public partial class NetworkChange
+ {
+ // The list of current address-changed subscribers.
+ private static readonly Dictionary<NetworkAddressChangedEventHandler, ExecutionContext> s_addressChangedSubscribers =
+ new Dictionary<NetworkAddressChangedEventHandler, ExecutionContext>();
+
+ // The list of current availability-changed subscribers.
+ private static readonly Dictionary<NetworkAvailabilityChangedEventHandler, ExecutionContext> s_availabilityChangedSubscribers =
+ new Dictionary<NetworkAvailabilityChangedEventHandler, ExecutionContext>();
+
+ private static readonly NetworkAvailabilityEventArgs s_availableEventArgs = new NetworkAvailabilityEventArgs(isAvailable: true);
+ private static readonly NetworkAvailabilityEventArgs s_notAvailableEventArgs = new NetworkAvailabilityEventArgs(isAvailable: false);
+ private static readonly ContextCallback s_runHandlerAvailable = new ContextCallback(RunAvailabilityHandlerAvailable);
+ private static readonly ContextCallback s_runHandlerNotAvailable = new ContextCallback(RunAvailabilityHandlerNotAvailable);
+ private static readonly ContextCallback s_runAddressChangedHandler = new ContextCallback(RunAddressChangedHandler);
+
+ private static void RunAddressChangedHandler(object state)
+ {
+ ((NetworkAddressChangedEventHandler)state)(null, EventArgs.Empty);
+ }
+
+ private static void RunAvailabilityHandlerAvailable(object state)
+ {
+ ((NetworkAvailabilityChangedEventHandler)state)(null, s_availableEventArgs);
+ }
+
+ private static void RunAvailabilityHandlerNotAvailable(object state)
+ {
+ ((NetworkAvailabilityChangedEventHandler)state)(null, s_notAvailableEventArgs);
+ }
+ }
+}
diff --git a/src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/SystemNetworkInterface.cs b/src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/SystemNetworkInterface.cs
index e6f4764f32..8bc75efcde 100644
--- a/src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/SystemNetworkInterface.cs
+++ b/src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/SystemNetworkInterface.cs
@@ -123,7 +123,7 @@ namespace System.Net.NetworkInformation
// If we don't have any interfaces detected, return empty.
if (result == Interop.IpHlpApi.ERROR_NO_DATA || result == Interop.IpHlpApi.ERROR_INVALID_PARAMETER)
{
- return new SystemNetworkInterface[0];
+ return Array.Empty<SystemNetworkInterface>();
}
// Otherwise we throw on an error.
diff --git a/src/System.Net.Ping/tests/FunctionalTests/UnixPingUtilityTests.cs b/src/System.Net.Ping/tests/FunctionalTests/UnixPingUtilityTests.cs
index 62e9191af9..e05d073f11 100644
--- a/src/System.Net.Ping/tests/FunctionalTests/UnixPingUtilityTests.cs
+++ b/src/System.Net.Ping/tests/FunctionalTests/UnixPingUtilityTests.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Sockets;
using System.Runtime.InteropServices;
@@ -33,21 +34,59 @@ namespace System.Net.NetworkInformation.Tests
? UnixCommandLinePing.Ping4UtilityPath
: UnixCommandLinePing.Ping6UtilityPath;
- ProcessStartInfo psi = new ProcessStartInfo(utilityPath, arguments);
- psi.RedirectStandardError = true;
- psi.RedirectStandardOutput = true;
- Process p = Process.Start(psi);
+ var p = new Process();
+ p.StartInfo.FileName = utilityPath;
+ p.StartInfo.Arguments = arguments;
+ p.StartInfo.UseShellExecute = false;
+
+ p.StartInfo.RedirectStandardOutput = true;
+ var stdOutLines = new List<string>();
+ p.OutputDataReceived += new DataReceivedEventHandler(
+ delegate (object sendingProcess, DataReceivedEventArgs outputLine) { stdOutLines.Add(outputLine.Data); });
- string pingOutput = p.StandardOutput.ReadToEnd();
- Assert.True(p.WaitForExit(TestSettings.PingTimeout), "Ping process did not exit in " + TestSettings.PingTimeout + " ms.");
- if (p.ExitCode == 1 || p.ExitCode == 2)
+ p.StartInfo.RedirectStandardError = true;
+ var stdErrLines = new List<string>();
+ p.ErrorDataReceived += new DataReceivedEventHandler(
+ delegate (object sendingProcess, DataReceivedEventArgs errorLine) { stdErrLines.Add(errorLine.Data); });
+
+ p.Start();
+ p.BeginOutputReadLine();
+ p.BeginErrorReadLine();
+
+ // There are multiple issues with ping6 in macOS 10.12 (Sierra), see https://github.com/dotnet/corefx/issues/26358.
+ bool isPing6OnMacSierra = utilityPath.Equals(UnixCommandLinePing.Ping6UtilityPath) &&
+ RuntimeInformation.IsOSPlatform(OSPlatform.OSX) &&
+ !PlatformDetection.IsMacOsHighSierraOrHigher;
+
+ string pingOutput;
+ if (!p.WaitForExit(TestSettings.PingTimeout))
{
- // Workaround known OSX bug in ping6 utility.
- Assert.Equal(utilityPath, UnixCommandLinePing.Ping6UtilityPath);
- Assert.True(RuntimeInformation.IsOSPlatform(OSPlatform.OSX));
- return;
+ // Workaround known issues with ping6 in macOS 10.12
+ if (isPing6OnMacSierra)
+ return;
+
+ pingOutput = string.Join("\n", stdOutLines);
+ string stdErr = string.Join("\n", stdErrLines);
+ throw new Exception(
+ $"[{utilityPath} {arguments}] process did not exit in {TestSettings.PingTimeout} ms.\nStdOut:[{pingOutput}]\nStdErr:[{stdErr}]");
}
+ // Ensure standard output and error are flushed
+ p.WaitForExit();
+
+ pingOutput = string.Join("\n", stdOutLines);
+ var exitCode = p.ExitCode;
+ if (exitCode != 0)
+ {
+ // Workaround known issues with ping6 in macOS 10.12
+ if (isPing6OnMacSierra)
+ return;
+
+ string stdErr = string.Join("\n", stdErrLines);
+ throw new Exception(
+ $"[{utilityPath} {arguments}] process exit code is {exitCode}.\nStdOut:[{pingOutput}]\nStdErr:[{stdErr}]");
+ }
+
try
{
// Validate that the returned data size is correct.
@@ -65,7 +104,9 @@ namespace System.Net.NetworkInformation.Tests
}
catch (Exception e)
{
- throw new Exception($"Ping output was <{pingOutput}>", e);
+ string stdErr = string.Join("\n", stdErrLines);
+ throw new Exception(
+ $"Parse error for [{utilityPath} {arguments}] process exit code is {exitCode}.\nStdOut:[{pingOutput}]\nStdErr:[{stdErr}]", e);
}
}
diff --git a/src/System.Net.Primitives/ref/System.Net.Primitives.cs b/src/System.Net.Primitives/ref/System.Net.Primitives.cs
index f5123e3d7e..775a21d3dc 100644
--- a/src/System.Net.Primitives/ref/System.Net.Primitives.cs
+++ b/src/System.Net.Primitives/ref/System.Net.Primitives.cs
@@ -126,40 +126,55 @@ namespace System.Net
public enum HttpStatusCode
{
Accepted = 202,
+ AlreadyReported = 208,
Ambiguous = 300,
BadGateway = 502,
BadRequest = 400,
Conflict = 409,
Continue = 100,
Created = 201,
+ EarlyHints = 103,
ExpectationFailed = 417,
+ FailedDependency = 424,
Forbidden = 403,
Found = 302,
GatewayTimeout = 504,
Gone = 410,
HttpVersionNotSupported = 505,
+ IMUsed = 226,
+ InsufficientStorage = 507,
InternalServerError = 500,
LengthRequired = 411,
+ Locked = 423,
+ LoopDetected = 508,
MethodNotAllowed = 405,
+ MisdirectedRequest = 421,
Moved = 301,
MovedPermanently = 301,
MultipleChoices = 300,
+ MultiStatus = 207,
+ NetworkAuthenticationRequired = 511,
NoContent = 204,
NonAuthoritativeInformation = 203,
NotAcceptable = 406,
+ NotExtended = 510,
NotFound = 404,
NotImplemented = 501,
NotModified = 304,
OK = 200,
PartialContent = 206,
PaymentRequired = 402,
+ PermanentRedirect = 308,
PreconditionFailed = 412,
+ PreconditionRequired = 428,
+ Processing = 102,
ProxyAuthenticationRequired = 407,
Redirect = 302,
RedirectKeepVerb = 307,
RedirectMethod = 303,
RequestedRangeNotSatisfiable = 416,
RequestEntityTooLarge = 413,
+ RequestHeaderFieldsTooLarge = 431,
RequestTimeout = 408,
RequestUriTooLong = 414,
ResetContent = 205,
@@ -167,11 +182,15 @@ namespace System.Net
ServiceUnavailable = 503,
SwitchingProtocols = 101,
TemporaryRedirect = 307,
+ TooManyRequests = 429,
Unauthorized = 401,
+ UnavailableForLegalReasons = 451,
+ UnprocessableEntity = 422,
UnsupportedMediaType = 415,
Unused = 306,
UpgradeRequired = 426,
UseProxy = 305,
+ VariantAlsoNegotiates = 506
}
public partial interface ICredentials
{
diff --git a/src/System.Net.Primitives/src/MatchingRefApiCompatBaseline.netcoreapp.txt b/src/System.Net.Primitives/src/MatchingRefApiCompatBaseline.netcoreapp.txt
new file mode 100644
index 0000000000..074f381930
--- /dev/null
+++ b/src/System.Net.Primitives/src/MatchingRefApiCompatBaseline.netcoreapp.txt
@@ -0,0 +1,4 @@
+Compat issues with assembly System.Net.Primitives:
+TypesMustExist : Type 'System.Net.CookieVariant' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.Net.PathList' does not exist in the implementation but it does exist in the contract.
+Total Issues: 2
diff --git a/src/System.Net.Primitives/src/MatchingRefApiCompatBaseline.uap.txt b/src/System.Net.Primitives/src/MatchingRefApiCompatBaseline.uap.txt
new file mode 100644
index 0000000000..b33f3c8765
--- /dev/null
+++ b/src/System.Net.Primitives/src/MatchingRefApiCompatBaseline.uap.txt
@@ -0,0 +1,12 @@
+Compat issues with assembly System.Net.Primitives:
+MembersMustExist : Member 'System.Boolean System.Net.Cookie.IsQuotedDomain' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Boolean System.Net.Cookie.IsQuotedVersion' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Net.Cookie.Clone()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Net.Cookie.InternalSetName(System.String)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Net.Cookie.ToServerString()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Net.Cookie.Variant.get()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Net.Cookie.Variant.set(System.Net.CookieVariant)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Net.CookieCollection.InternalAdd(System.Net.Cookie, System.Boolean)' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.Net.CookieVariant' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.Net.PathList' does not exist in the implementation but it does exist in the contract.
+Total Issues: 10
diff --git a/src/System.Net.Primitives/src/System.Net.Primitives.csproj b/src/System.Net.Primitives/src/System.Net.Primitives.csproj
index f759c979af..1351157f59 100644
--- a/src/System.Net.Primitives/src/System.Net.Primitives.csproj
+++ b/src/System.Net.Primitives/src/System.Net.Primitives.csproj
@@ -6,6 +6,7 @@
<OutputType>Library</OutputType>
<ProjectGuid>{8772BC91-7B55-49B9-94FA-4B1BE5BEAB55}</ProjectGuid>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <ILLinkClearInitLocals>true</ILLinkClearInitLocals>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='uap-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='uap-Windows_NT-Release|AnyCPU'" />
diff --git a/src/System.Net.Primitives/src/System/Net/HttpStatusCode.cs b/src/System.Net.Primitives/src/System/Net/HttpStatusCode.cs
index 2dc66e3244..e46a925a33 100644
--- a/src/System.Net.Primitives/src/System/Net/HttpStatusCode.cs
+++ b/src/System.Net.Primitives/src/System/Net/HttpStatusCode.cs
@@ -10,6 +10,8 @@ namespace System.Net
// Informational 1xx
Continue = 100,
SwitchingProtocols = 101,
+ Processing = 102,
+ EarlyHints = 103,
// Successful 2xx
OK = 200,
@@ -19,6 +21,10 @@ namespace System.Net
NoContent = 204,
ResetContent = 205,
PartialContent = 206,
+ MultiStatus = 207,
+ AlreadyReported = 208,
+
+ IMUsed = 226,
// Redirection 3xx
MultipleChoices = 300,
@@ -34,6 +40,7 @@ namespace System.Net
Unused = 306,
TemporaryRedirect = 307,
RedirectKeepVerb = 307,
+ PermanentRedirect = 308,
// Client Error 4xx
BadRequest = 400,
@@ -54,9 +61,25 @@ namespace System.Net
UnsupportedMediaType = 415,
RequestedRangeNotSatisfiable = 416,
ExpectationFailed = 417,
+ // From the discussion thread on #4382:
+ // "It would be a mistake to add it to .NET now. See golang/go#21326,
+ // nodejs/node#14644, requests/requests#4238 and aspnet/HttpAbstractions#915".
+ // ImATeapot = 418
+
+ MisdirectedRequest = 421,
+ UnprocessableEntity = 422,
+ Locked = 423,
+ FailedDependency = 424,
UpgradeRequired = 426,
+ PreconditionRequired = 428,
+ TooManyRequests = 429,
+
+ RequestHeaderFieldsTooLarge = 431,
+
+ UnavailableForLegalReasons = 451,
+
// Server Error 5xx
InternalServerError = 500,
NotImplemented = 501,
@@ -64,5 +87,11 @@ namespace System.Net
ServiceUnavailable = 503,
GatewayTimeout = 504,
HttpVersionNotSupported = 505,
+ VariantAlsoNegotiates = 506,
+ InsufficientStorage = 507,
+ LoopDetected = 508,
+
+ NotExtended = 510,
+ NetworkAuthenticationRequired = 511
}
}
diff --git a/src/System.Net.Primitives/src/System/Net/IPAddress.cs b/src/System.Net.Primitives/src/System/Net/IPAddress.cs
index 5aeeac6ccc..7b7781bfea 100644
--- a/src/System.Net.Primitives/src/System/Net/IPAddress.cs
+++ b/src/System.Net.Primitives/src/System/Net/IPAddress.cs
@@ -6,6 +6,7 @@ using System.Buffers.Binary;
using System.Diagnostics;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
namespace System.Net
{
@@ -232,7 +233,7 @@ namespace System.Net
return false;
}
- address = IPAddressParser.Parse(ipString.AsReadOnlySpan(), tryParse: true);
+ address = IPAddressParser.Parse(ipString.AsSpan(), tryParse: true);
return (address != null);
}
@@ -249,7 +250,7 @@ namespace System.Net
throw new ArgumentNullException(nameof(ipString));
}
- return IPAddressParser.Parse(ipString.AsReadOnlySpan(), tryParse: false);
+ return IPAddressParser.Parse(ipString.AsSpan(), tryParse: false);
}
public static IPAddress Parse(ReadOnlySpan<char> ipSpan)
@@ -611,7 +612,7 @@ namespace System.Net
const int addressAndScopeIdLength = IPAddressParserStatics.IPv6AddressBytes + sizeof(uint);
Span<byte> addressAndScopeIdSpan = stackalloc byte[addressAndScopeIdLength];
- new ReadOnlySpan<ushort>(_numbers).AsBytes().CopyTo(addressAndScopeIdSpan);
+ MemoryMarshal.AsBytes(new ReadOnlySpan<ushort>(_numbers)).CopyTo(addressAndScopeIdSpan);
Span<byte> scopeIdSpan = addressAndScopeIdSpan.Slice(IPAddressParserStatics.IPv6AddressBytes);
bool scopeWritten = BitConverter.TryWriteBytes(scopeIdSpan, _addressOrScopeId);
Debug.Assert(scopeWritten);
@@ -627,7 +628,7 @@ namespace System.Net
// For IPv4 addresses, we use Marvin on the integer representation of the Address.
hashCode = Marvin.ComputeHash32(
- addressOrScopeIdSpan.AsBytes(),
+ MemoryMarshal.AsBytes(addressOrScopeIdSpan),
Marvin.DefaultSeed);
}
diff --git a/src/System.Net.Primitives/src/System/Net/IPAddressParser.cs b/src/System.Net.Primitives/src/System/Net/IPAddressParser.cs
index 930914f9b2..35998e6437 100644
--- a/src/System.Net.Primitives/src/System/Net/IPAddressParser.cs
+++ b/src/System.Net.Primitives/src/System/Net/IPAddressParser.cs
@@ -21,6 +21,7 @@ namespace System.Net
// The address is parsed as IPv6 if and only if it contains a colon. This is valid because
// we don't support/parse a port specification at the end of an IPv4 address.
ushort* numbers = stackalloc ushort[IPAddressParserStatics.IPv6AddressShorts];
+ new Span<ushort>(numbers, IPAddressParserStatics.IPv6AddressShorts).Clear();
if (Ipv6StringToAddress(ipSpan, numbers, IPAddressParserStatics.IPv6AddressShorts, out uint scope))
{
return new IPAddress(numbers, IPAddressParserStatics.IPv6AddressShorts, scope);
diff --git a/src/System.Net.Primitives/tests/FunctionalTests/IPAddressParsingSpan.cs b/src/System.Net.Primitives/tests/FunctionalTests/IPAddressParsingSpan.cs
index b8f38d10d4..0b41beb2e7 100644
--- a/src/System.Net.Primitives/tests/FunctionalTests/IPAddressParsingSpan.cs
+++ b/src/System.Net.Primitives/tests/FunctionalTests/IPAddressParsingSpan.cs
@@ -9,8 +9,8 @@ namespace System.Net.Primitives.Functional.Tests
{
public sealed class IPAddressParsing_Span : IPAddressParsing
{
- public override IPAddress Parse(string ipString) => IPAddress.Parse(ipString.AsReadOnlySpan());
- public override bool TryParse(string ipString, out IPAddress address) => IPAddress.TryParse(ipString.AsReadOnlySpan(), out address);
+ public override IPAddress Parse(string ipString) => IPAddress.Parse(ipString.AsSpan());
+ public override bool TryParse(string ipString, out IPAddress address) => IPAddress.TryParse(ipString.AsSpan(), out address);
[Theory]
diff --git a/src/System.Net.Primitives/tests/FunctionalTests/IPAddressSpanTest.cs b/src/System.Net.Primitives/tests/FunctionalTests/IPAddressSpanTest.cs
index 890ef3b14a..57de140b5e 100644
--- a/src/System.Net.Primitives/tests/FunctionalTests/IPAddressSpanTest.cs
+++ b/src/System.Net.Primitives/tests/FunctionalTests/IPAddressSpanTest.cs
@@ -37,7 +37,7 @@ namespace System.Net.Primitives.Functional.Tests
IPAddress ip = new IPAddress(address);
Assert.True(ip.TryWriteBytes(new Span<byte>(result), out int bytesWritten));
- Assert.Equal<byte>(address, result.AsSpan().Slice(0, bytesWritten).ToArray());
+ Assert.Equal<byte>(address, result.AsSpan(0, bytesWritten).ToArray());
Assert.Equal(address.Length, bytesWritten);
}
diff --git a/src/System.Net.Primitives/tests/UnitTests/CookieInternalTest.cs b/src/System.Net.Primitives/tests/UnitTests/CookieInternalTest.cs
index 35653d720d..797fcf63f0 100644
--- a/src/System.Net.Primitives/tests/UnitTests/CookieInternalTest.cs
+++ b/src/System.Net.Primitives/tests/UnitTests/CookieInternalTest.cs
@@ -80,33 +80,5 @@ namespace NetPrimitivesUnitTests
int expectedCookieCount = expectedStrings.Length >> 1;
Assert.Equal(expectedCookieCount, cookieCount);
}
-
- [ActiveIssue(22925)]
- [Theory]
- [InlineData("cookie_name=cookie_value", new[] { "cookie_name", "cookie_value" })]
- [InlineData("cookie_name=cookie_value;", new[] { "cookie_name", "cookie_value" })]
- [InlineData("cookie_name1=cookie_value1;cookie_name2=cookie_value2", new[] { "cookie_name1", "cookie_value1", "cookie_name2", "cookie_value2" })]
- [InlineData("cookie_name1=cookie_value1;cookie_name2=cookie_value2;", new[] { "cookie_name1", "cookie_value1", "cookie_name2", "cookie_value2" })]
- public void CookieParserGet_SetCookieHeaderValue_Success(string cookieString, string[] expectedStrings)
- {
- int index = 0;
- int cookieCount = 0;
- var parser = new CookieParser(cookieString);
- while (true)
- {
- Cookie cookie = parser.Get();
- if (cookie == null)
- {
- break;
- }
-
- cookieCount++;
- Assert.Equal(expectedStrings[index++], cookie.Name);
- Assert.Equal(expectedStrings[index++], cookie.Value);
- }
-
- int expectedCookieCount = expectedStrings.Length >> 1;
- Assert.Equal(expectedCookieCount, cookieCount);
- }
}
}
diff --git a/src/System.Net.Requests/src/FxCopBaseline.cs b/src/System.Net.Requests/src/FxCopBaseline.cs
index 864b3c544d..555bfdee18 100644
--- a/src/System.Net.Requests/src/FxCopBaseline.cs
+++ b/src/System.Net.Requests/src/FxCopBaseline.cs
@@ -1,3 +1,7 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information
+
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Microsoft.Design", "CA2237", Scope = "type", Target = "System.Net.FtpWebRequest")]
diff --git a/src/System.Net.Requests/src/MatchingRefApiCompatBaseline.txt b/src/System.Net.Requests/src/MatchingRefApiCompatBaseline.txt
new file mode 100644
index 0000000000..7cfb162513
--- /dev/null
+++ b/src/System.Net.Requests/src/MatchingRefApiCompatBaseline.txt
@@ -0,0 +1,3 @@
+Compat issues with assembly System.Net.Requests:
+MembersMustExist : Member 'System.Net.HttpWebRequest..ctor()' does not exist in the implementation but it does exist in the contract.
+Total Issues: 1
diff --git a/src/System.Net.Requests/src/System.Net.Requests.csproj b/src/System.Net.Requests/src/System.Net.Requests.csproj
index 1052fe84b7..02ba7fd65b 100644
--- a/src/System.Net.Requests/src/System.Net.Requests.csproj
+++ b/src/System.Net.Requests/src/System.Net.Requests.csproj
@@ -6,6 +6,7 @@
<RootNamespace>System.Net.Requests</RootNamespace>
<AssemblyName>System.Net.Requests</AssemblyName>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <ILLinkClearInitLocals>true</ILLinkClearInitLocals>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
@@ -140,4 +141,4 @@
<Reference Include="System.Threading.Thread" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Net.Requests/src/System/Net/HttpWebRequest.cs b/src/System.Net.Requests/src/System/Net/HttpWebRequest.cs
index 1d10fe8d35..85c3117cbd 100644
--- a/src/System.Net.Requests/src/System/Net/HttpWebRequest.cs
+++ b/src/System.Net.Requests/src/System/Net/HttpWebRequest.cs
@@ -1164,7 +1164,7 @@ namespace System.Net
if (_hostUri != null)
{
- request.Headers.Host = _hostUri.Host;
+ request.Headers.Host = Host;
}
// Copy the HttpWebRequest request headers from the WebHeaderCollection into HttpRequestMessage.Headers and
diff --git a/src/System.Net.Requests/src/System/Net/WebException.cs b/src/System.Net.Requests/src/System/Net/WebException.cs
index 1b9865776e..bdf2e157d0 100644
--- a/src/System.Net.Requests/src/System/Net/WebException.cs
+++ b/src/System.Net.Requests/src/System/Net/WebException.cs
@@ -4,6 +4,7 @@
using System.Diagnostics;
using System.Net.Http;
+using System.Net.Sockets;
using System.Runtime.Serialization;
using System.Threading.Tasks;
@@ -112,5 +113,28 @@ namespace System.Net
return exception;
}
+
+ private static WebExceptionStatus GetStatusFromExceptionHelper(HttpRequestException ex)
+ {
+ SocketException socketEx = ex.InnerException as SocketException;
+
+ if (socketEx is null)
+ {
+ return WebExceptionStatus.UnknownError;
+ }
+
+ WebExceptionStatus status;
+ switch (socketEx.SocketErrorCode)
+ {
+ case SocketError.HostNotFound:
+ status = WebExceptionStatus.NameResolutionFailure;
+ break;
+ default:
+ status = WebExceptionStatus.UnknownError;
+ break;
+ }
+
+ return status;
+ }
}
}
diff --git a/src/System.Net.Requests/src/System/Net/WebExceptionPal.Unix.cs b/src/System.Net.Requests/src/System/Net/WebExceptionPal.Unix.cs
index b4ed5af7b8..7ad711cc94 100644
--- a/src/System.Net.Requests/src/System/Net/WebExceptionPal.Unix.cs
+++ b/src/System.Net.Requests/src/System/Net/WebExceptionPal.Unix.cs
@@ -26,7 +26,7 @@ namespace System.Net
status = WebExceptionStatus.NameResolutionFailure;
break;
default:
- status = WebExceptionStatus.UnknownError;
+ status = GetStatusFromExceptionHelper(ex);
break;
}
diff --git a/src/System.Net.Requests/src/System/Net/WebExceptionPal.Windows.cs b/src/System.Net.Requests/src/System/Net/WebExceptionPal.Windows.cs
index 2de80f48f1..fb5a7f341d 100644
--- a/src/System.Net.Requests/src/System/Net/WebExceptionPal.Windows.cs
+++ b/src/System.Net.Requests/src/System/Net/WebExceptionPal.Windows.cs
@@ -26,7 +26,7 @@ namespace System.Net
status = WebExceptionStatus.NameResolutionFailure;
break;
default:
- status = WebExceptionStatus.UnknownError;
+ status = GetStatusFromExceptionHelper(ex);
break;
}
diff --git a/src/System.Net.Requests/tests/HttpWebRequestTest.cs b/src/System.Net.Requests/tests/HttpWebRequestTest.cs
index eb488b7505..3745049b94 100644
--- a/src/System.Net.Requests/tests/HttpWebRequestTest.cs
+++ b/src/System.Net.Requests/tests/HttpWebRequestTest.cs
@@ -173,7 +173,7 @@ namespace System.Net.Tests
{
HttpWebRequest request = WebRequest.CreateHttp(uri);
Task<WebResponse> getResponse = request.GetResponseAsync();
- await LoopbackServer.ReadRequestAndSendResponseAsync(server);
+ await server.AcceptConnectionSendResponseAndCloseAsync();
using (WebResponse response = await getResponse)
{
Assert.Throws<InvalidOperationException>(() => request.AutomaticDecompression = DecompressionMethods.Deflate);
@@ -188,6 +188,29 @@ namespace System.Net.Tests
});
}
+ [Fact]
+ public async Task HttpWebRequest_SetHostHeader_ContainsPortNumber()
+ {
+ await LoopbackServer.CreateServerAsync(async (server, uri) =>
+ {
+ HttpWebRequest request = WebRequest.CreateHttp(uri);
+ string host = uri.Host + ":" + uri.Port;
+ request.Host = host;
+ Task<WebResponse> getResponse = request.GetResponseAsync();
+
+ await server.AcceptConnectionAsync(async connection =>
+ {
+ List<string> headers = await connection.ReadRequestHeaderAndSendResponseAsync();
+ Assert.Contains($"Host: {host}", headers);
+ });
+
+ using (var response = (HttpWebResponse) await getResponse)
+ {
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ }
+ });
+ }
+
[Theory, MemberData(nameof(EchoServers))]
public void MaximumResponseHeadersLength_SetNegativeTwo_ThrowsArgumentOutOfRangeException(Uri remoteServer)
{
@@ -682,14 +705,7 @@ namespace System.Net.Tests
public void ServicePoint_GetValue_ExpectedResult(Uri remoteServer)
{
HttpWebRequest request = WebRequest.CreateHttp(remoteServer);
- if (PlatformDetection.IsFullFramework)
- {
- Assert.NotNull(request.ServicePoint);
- }
- else
- {
- Assert.Throws<PlatformNotSupportedException>(() => request.ServicePoint);
- }
+ Assert.NotNull(request.ServicePoint);
}
[Theory, MemberData(nameof(EchoServers))]
@@ -752,7 +768,7 @@ namespace System.Net.Tests
request.ProtocolVersion = requestVersion;
Task<WebResponse> getResponse = request.GetResponseAsync();
- Task<List<string>> serverTask = LoopbackServer.ReadRequestAndSendResponseAsync(server);
+ Task<List<string>> serverTask = server.AcceptConnectionSendResponseAndCloseAsync();
using (HttpWebResponse response = (HttpWebResponse) await getResponse)
{
diff --git a/src/System.Net.Requests/tests/HttpWebResponseHeaderTest.cs b/src/System.Net.Requests/tests/HttpWebResponseHeaderTest.cs
index 67155869ed..9cdbb8293a 100644
--- a/src/System.Net.Requests/tests/HttpWebResponseHeaderTest.cs
+++ b/src/System.Net.Requests/tests/HttpWebResponseHeaderTest.cs
@@ -31,13 +31,7 @@ namespace System.Net.Tests
request.ContinueDelegate = continueDelegate;
Task<WebResponse> getResponse = request.GetResponseAsync();
DateTimeOffset utcNow = DateTimeOffset.UtcNow;
- await LoopbackServer.ReadRequestAndSendResponseAsync(server,
- $"HTTP/1.1 200 OK\r\n" +
- $"Date: {utcNow:R}\r\n" +
- "Content-Type: application/json;charset=UTF-8\r\n" +
- "Content-Length: 5\r\n" +
- "\r\n" +
- "12345");
+ await server.AcceptConnectionSendResponseAndCloseAsync(HttpStatusCode.OK, "Content-Type: application/json;charset=UTF-8\r\n", "12345");
Assert.Equal(continueDelegate, request.ContinueDelegate);
});
}
@@ -52,13 +46,7 @@ namespace System.Net.Tests
request.Method = HttpMethod.Get.Method;
Task<WebResponse> getResponse = request.GetResponseAsync();
DateTimeOffset utcNow = DateTimeOffset.UtcNow;
- await LoopbackServer.ReadRequestAndSendResponseAsync(server,
- $"HTTP/1.1 200 OK\r\n" +
- $"Date: {utcNow:R}\r\n" +
- "Content-Type: application/json;charset=UTF-8\r\n" +
- "Content-Length: 5\r\n" +
- "\r\n" +
- "12345");
+ await server.AcceptConnectionSendResponseAndCloseAsync(HttpStatusCode.OK, "Content-Type: application/json;charset=UTF-8\r\n", "12345");
using (WebResponse response = await getResponse)
{
@@ -85,13 +73,7 @@ namespace System.Net.Tests
request.Method = HttpMethod.Get.Method;
Task<WebResponse> getResponse = request.GetResponseAsync();
DateTimeOffset utcNow = DateTimeOffset.UtcNow;
- await LoopbackServer.ReadRequestAndSendResponseAsync(server,
- $"HTTP/1.1 200 OK\r\n" +
- $"Date: {utcNow:R}\r\n" +
- "Content-Type: application/json;charset=UTF-8\r\n" +
- "Content-Length: 5\r\n" +
- "\r\n" +
- "12345");
+ await server.AcceptConnectionSendResponseAndCloseAsync(HttpStatusCode.OK, "Content-Type: application/json;charset=UTF-8\r\n", "12345");
WebResponse response = await getResponse;
HttpWebResponse httpResponse = (HttpWebResponse)response;
httpResponse.Close();
@@ -120,11 +102,7 @@ namespace System.Net.Tests
request.Method = HttpMethod.Get.Method;
Task<WebResponse> getResponse = request.GetResponseAsync();
DateTimeOffset utcNow = DateTimeOffset.UtcNow;
- await LoopbackServer.ReadRequestAndSendResponseAsync(server,
- $"HTTP/1.1 200 OK\r\n" +
- $"Date: {utcNow:R}\r\n" +
- "Content-Length: 0\r\n" +
- "\r\n");
+ await server.AcceptConnectionSendResponseAndCloseAsync();
using (WebResponse response = await getResponse)
{
diff --git a/src/System.Net.Requests/tests/HttpWebResponseTest.cs b/src/System.Net.Requests/tests/HttpWebResponseTest.cs
index 03c67329bd..d60921bc85 100644
--- a/src/System.Net.Requests/tests/HttpWebResponseTest.cs
+++ b/src/System.Net.Requests/tests/HttpWebResponseTest.cs
@@ -23,13 +23,7 @@ namespace System.Net.Tests
HttpWebRequest request = WebRequest.CreateHttp(url);
request.Method = HttpMethod.Get.Method;
Task<WebResponse> getResponse = request.GetResponseAsync();
- await LoopbackServer.ReadRequestAndSendResponseAsync(server,
- $"HTTP/1.1 200 OK\r\n" +
- $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
- $"Content-Type: {expectedContentType}\r\n" +
- "Content-Length: 5\r\n" +
- "\r\n" +
- "12345");
+ await server.AcceptConnectionSendResponseAndCloseAsync(HttpStatusCode.OK, $"Content-Type: {expectedContentType}\r\n", "12345");
using (WebResponse response = await getResponse)
{
@@ -46,12 +40,7 @@ namespace System.Net.Tests
HttpWebRequest request = WebRequest.CreateHttp(url);
request.Method = HttpMethod.Get.Method;
Task<WebResponse> getResponse = request.GetResponseAsync();
- await LoopbackServer.ReadRequestAndSendResponseAsync(server,
- $"HTTP/1.1 200 OK\r\n" +
- $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
- "Content-Length: 5\r\n" +
- "\r\n" +
- "12345");
+ await server.AcceptConnectionSendResponseAndCloseAsync(content: "12345");
using (WebResponse response = await getResponse)
{
diff --git a/src/System.Net.Requests/tests/System.Net.Requests.Tests.csproj b/src/System.Net.Requests/tests/System.Net.Requests.Tests.csproj
index 7b8600d644..35dc993fef 100644
--- a/src/System.Net.Requests/tests/System.Net.Requests.Tests.csproj
+++ b/src/System.Net.Requests/tests/System.Net.Requests.Tests.csproj
@@ -24,6 +24,9 @@
<Compile Include="$(CommonTestPath)\System\Net\Http\LoopbackServer.cs">
<Link>Common\System\Net\Http\LoopbackServer.cs</Link>
</Compile>
+ <Compile Include="$(CommonTestPath)\System\Threading\Tasks\TaskTimeoutExtensions.cs">
+ <Link>Common\System\Threading\Tasks\TaskTimeoutExtensions.cs</Link>
+ </Compile>
<ProjectReference Include="$(CommonTestPath)\System\Diagnostics\RemoteExecutorConsoleApp\RemoteExecutorConsoleApp.csproj">
<Project>{69e46a6f-9966-45a5-8945-2559fe337827}</Project>
<Name>RemoteExecutorConsoleApp</Name>
diff --git a/src/System.Net.Security/ref/System.Net.Security.cs b/src/System.Net.Security/ref/System.Net.Security.cs
index 1aad87183a..fbe4022fbe 100644
--- a/src/System.Net.Security/ref/System.Net.Security.cs
+++ b/src/System.Net.Security/ref/System.Net.Security.cs
@@ -186,7 +186,7 @@ namespace System.Net.Security
public virtual System.Threading.Tasks.Task AuthenticateAsServerAsync(System.Security.Cryptography.X509Certificates.X509Certificate serverCertificate) { throw null; }
public virtual System.Threading.Tasks.Task AuthenticateAsServerAsync(System.Security.Cryptography.X509Certificates.X509Certificate serverCertificate, bool clientCertificateRequired, System.Security.Authentication.SslProtocols enabledSslProtocols, bool checkCertificateRevocation) { throw null; }
public virtual System.Threading.Tasks.Task AuthenticateAsServerAsync(System.Security.Cryptography.X509Certificates.X509Certificate serverCertificate, bool clientCertificateRequired, bool checkCertificateRevocation) { throw null; }
- public Task AuthenticateAsServerAsync(SslServerAuthenticationOptions sslClientAuthenticationOptions, CancellationToken cancellationToken) { throw null; }
+ public Task AuthenticateAsServerAsync(SslServerAuthenticationOptions sslServerAuthenticationOptions, CancellationToken cancellationToken) { throw null; }
public virtual System.IAsyncResult BeginAuthenticateAsClient(string targetHost, System.AsyncCallback asyncCallback, object asyncState) { throw null; }
public virtual System.IAsyncResult BeginAuthenticateAsClient(string targetHost, System.Security.Cryptography.X509Certificates.X509CertificateCollection clientCertificates, System.Security.Authentication.SslProtocols enabledSslProtocols, bool checkCertificateRevocation, System.AsyncCallback asyncCallback, object asyncState) { throw null; }
public virtual System.IAsyncResult BeginAuthenticateAsClient(string targetHost, System.Security.Cryptography.X509Certificates.X509CertificateCollection clientCertificates, bool checkCertificateRevocation, System.AsyncCallback asyncCallback, object asyncState) { throw null; }
diff --git a/src/System.Net.Security/src/Resources/Strings.resx b/src/System.Net.Security/src/Resources/Strings.resx
index fe5ef27660..8d115d4762 100644
--- a/src/System.Net.Security/src/Resources/Strings.resx
+++ b/src/System.Net.Security/src/Resources/Strings.resx
@@ -208,7 +208,7 @@
<value>Once authentication is attempted as the client or server, additional authentication attempts must use the same client or server role.</value>
</data>
<data name="net_auth_SSPI" xml:space="preserve">
- <value>A call to SSPI failed, see inner exception.</value>
+ <value>Authentication failed, see inner exception.</value>
</data>
<data name="net_auth_eof" xml:space="preserve">
<value>Authentication failed because the remote party has closed the transport stream.</value>
diff --git a/src/System.Net.Security/src/System.Net.Security.csproj b/src/System.Net.Security/src/System.Net.Security.csproj
index ef39db997d..5600de5691 100644
--- a/src/System.Net.Security/src/System.Net.Security.csproj
+++ b/src/System.Net.Security/src/System.Net.Security.csproj
@@ -5,6 +5,7 @@
<AssemblyName>System.Net.Security</AssemblyName>
<ProjectGuid>{89F37791-6254-4D60-AB96-ACD3CCA0E771}</ProjectGuid>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <ILLinkClearInitLocals>true</ILLinkClearInitLocals>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetsOSX)' == 'true' ">
<DefineConstants>$(DefineConstants);SYSNETSECURITY_NO_OPENSSL</DefineConstants>
diff --git a/src/System.Net.Security/src/System/Net/FixedSizeReader.cs b/src/System.Net.Security/src/System/Net/FixedSizeReader.cs
index 94dc81225e..14ed8a79de 100644
--- a/src/System.Net.Security/src/System/Net/FixedSizeReader.cs
+++ b/src/System.Net.Security/src/System/Net/FixedSizeReader.cs
@@ -53,7 +53,7 @@ namespace System.Net
int remainingCount = request.Count, offset = request.Offset;
do
{
- int bytes = await transport.ReadAsync(request.Buffer, offset, remainingCount, CancellationToken.None).ConfigureAwait(false);
+ int bytes = await transport.ReadAsync(new Memory<byte>(request.Buffer, offset, remainingCount), CancellationToken.None).ConfigureAwait(false);
if (bytes == 0)
{
if (remainingCount != request.Count)
diff --git a/src/System.Net.Security/src/System/Net/Security/NetEventSource.Security.cs b/src/System.Net.Security/src/System/Net/Security/NetEventSource.Security.cs
index 1590996740..1cf0c0ac82 100644
--- a/src/System.Net.Security/src/System/Net/Security/NetEventSource.Security.cs
+++ b/src/System.Net.Security/src/System/Net/Security/NetEventSource.Security.cs
@@ -14,21 +14,12 @@ namespace System.Net
[EventSource(Name = "Microsoft-System-Net-Security", LocalizationResources = "FxResources.System.Net.Security.SR")]
internal sealed partial class NetEventSource
{
- private const int EnumerateSecurityPackagesId = NextAvailableEventId;
- private const int SspiPackageNotFoundId = EnumerateSecurityPackagesId + 1;
- private const int AcquireDefaultCredentialId = SspiPackageNotFoundId + 1;
- private const int AcquireCredentialsHandleId = AcquireDefaultCredentialId + 1;
- private const int SecureChannelCtorId = AcquireCredentialsHandleId + 1;
+ private const int SecureChannelCtorId = NextAvailableEventId;
private const int LocatingPrivateKeyId = SecureChannelCtorId + 1;
private const int CertIsType2Id = LocatingPrivateKeyId + 1;
private const int FoundCertInStoreId = CertIsType2Id + 1;
private const int NotFoundCertInStoreId = FoundCertInStoreId + 1;
- private const int InitializeSecurityContextId = NotFoundCertInStoreId + 1;
- private const int SecurityContextInputBufferId = InitializeSecurityContextId + 1;
- private const int SecurityContextInputBuffersId = SecurityContextInputBufferId + 1;
- private const int AcceptSecuritContextId = SecurityContextInputBuffersId + 1;
- private const int OperationReturnedSomethingId = AcceptSecuritContextId + 1;
- private const int RemoteCertificateId = OperationReturnedSomethingId + 1;
+ private const int RemoteCertificateId = NotFoundCertInStoreId + 1;
private const int CertificateFromDelegateId = RemoteCertificateId + 1;
private const int NoDelegateNoClientCertId = CertificateFromDelegateId + 1;
private const int NoDelegateButClientCertId = NoDelegateNoClientCertId + 1;
@@ -343,29 +334,46 @@ namespace System.Net
const int NumEventDatas = 8;
var descrs = stackalloc EventData[NumEventDatas];
- descrs[0].DataPointer = (IntPtr)(arg1Ptr);
- descrs[0].Size = (arg1.Length + 1) * sizeof(char);
-
- descrs[1].DataPointer = (IntPtr)(&arg2);
- descrs[1].Size = sizeof(int);
-
- descrs[2].DataPointer = (IntPtr)(&arg3);
- descrs[2].Size = sizeof(int);
-
- descrs[3].DataPointer = (IntPtr)(&arg4);
- descrs[3].Size = sizeof(int);
-
- descrs[4].DataPointer = (IntPtr)(&arg5);
- descrs[4].Size = sizeof(int);
-
- descrs[5].DataPointer = (IntPtr)(&arg6);
- descrs[5].Size = sizeof(int);
-
- descrs[6].DataPointer = (IntPtr)(&arg7);
- descrs[6].Size = sizeof(int);
-
- descrs[7].DataPointer = (IntPtr)(&arg8);
- descrs[7].Size = sizeof(int);
+ descrs[0] = new EventData
+ {
+ DataPointer = (IntPtr)(arg1Ptr),
+ Size = (arg1.Length + 1) * sizeof(char)
+ };
+ descrs[1] = new EventData
+ {
+ DataPointer = (IntPtr)(&arg2),
+ Size = sizeof(int)
+ };
+ descrs[2] = new EventData
+ {
+ DataPointer = (IntPtr)(&arg3),
+ Size = sizeof(int)
+ };
+ descrs[3] = new EventData
+ {
+ DataPointer = (IntPtr)(&arg4),
+ Size = sizeof(int)
+ };
+ descrs[4] = new EventData
+ {
+ DataPointer = (IntPtr)(&arg5),
+ Size = sizeof(int)
+ };
+ descrs[5] = new EventData
+ {
+ DataPointer = (IntPtr)(&arg6),
+ Size = sizeof(int)
+ };
+ descrs[6] = new EventData
+ {
+ DataPointer = (IntPtr)(&arg7),
+ Size = sizeof(int)
+ };
+ descrs[7] = new EventData
+ {
+ DataPointer = (IntPtr)(&arg8),
+ Size = sizeof(int)
+ };
WriteEventCore(eventId, NumEventDatas, descrs);
}
diff --git a/src/System.Net.Security/src/System/Net/Security/Pal.OSX/SafeDeleteSslContext.cs b/src/System.Net.Security/src/System/Net/Security/Pal.OSX/SafeDeleteSslContext.cs
index 2007763ab6..1fc55e8997 100644
--- a/src/System.Net.Security/src/System/Net/Security/Pal.OSX/SafeDeleteSslContext.cs
+++ b/src/System.Net.Security/src/System/Net/Security/Pal.OSX/SafeDeleteSslContext.cs
@@ -66,7 +66,7 @@ namespace System.Net
// let it pass.
break;
default:
- throw new PlatformNotSupportedException(SR.net_encryptionpolicy_notsupported);
+ throw new PlatformNotSupportedException(SR.Format(SR.net_encryptionpolicy_notsupported, credential.Policy));
}
SafeSslHandle sslContext = Interop.AppleCrypto.SslCreateContext(isServer ? 1 : 0);
@@ -274,7 +274,7 @@ namespace System.Net
maxProtocolId = SslProtocols.Tls11;
break;
default:
- throw new PlatformNotSupportedException(SR.net_security_sslprotocol_contiguous);
+ throw new PlatformNotSupportedException(SR.Format(SR.net_security_sslprotocol_contiguous, protocols));
}
Interop.AppleCrypto.SslSetMinProtocolVersion(sslContext, minProtocolId);
diff --git a/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs b/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs
index b444eea312..4c92ae8754 100644
--- a/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs
+++ b/src/System.Net.Security/src/System/Net/Security/SecureChannel.cs
@@ -870,24 +870,20 @@ namespace System.Net.Security
if (NetEventSource.IsEnabled)
NetEventSource.Enter(this);
- StreamSizes streamSizes;
- SslStreamPal.QueryContextStreamSizes(_securityContext, out streamSizes);
+ SslStreamPal.QueryContextStreamSizes(_securityContext, out StreamSizes streamSizes);
- if (streamSizes != null)
+ try
{
- try
- {
- _headerSize = streamSizes.Header;
- _trailerSize = streamSizes.Trailer;
- _maxDataSize = checked(streamSizes.MaximumMessage - (_headerSize + _trailerSize));
+ _headerSize = streamSizes.Header;
+ _trailerSize = streamSizes.Trailer;
+ _maxDataSize = checked(streamSizes.MaximumMessage - (_headerSize + _trailerSize));
- Debug.Assert(_maxDataSize > 0, "_maxDataSize > 0");
- }
- catch (Exception e) when (!ExceptionCheck.IsFatal(e))
- {
- NetEventSource.Fail(this, "StreamSizes out of range.");
- throw;
- }
+ Debug.Assert(_maxDataSize > 0, "_maxDataSize > 0");
+ }
+ catch (Exception e) when (!ExceptionCheck.IsFatal(e))
+ {
+ NetEventSource.Fail(this, "StreamSizes out of range.");
+ throw;
}
SslStreamPal.QueryContextConnectionInfo(_securityContext, out _connectionInfo);
diff --git a/src/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs b/src/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs
index 609666aee4..5fede486d1 100644
--- a/src/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs
+++ b/src/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs
@@ -11,12 +11,12 @@ namespace System.Net.Security
{
internal class SslAuthenticationOptions
{
- internal SslAuthenticationOptions(SslClientAuthenticationOptions sslClientAuthenticationOptions)
+ internal SslAuthenticationOptions(SslClientAuthenticationOptions sslClientAuthenticationOptions, RemoteCertValidationCallback remoteCallback, LocalCertSelectionCallback localCallback)
{
// Common options.
AllowRenegotiation = sslClientAuthenticationOptions.AllowRenegotiation;
ApplicationProtocols = sslClientAuthenticationOptions.ApplicationProtocols;
- CertValidationDelegate = sslClientAuthenticationOptions._certValidationDelegate;
+ CertValidationDelegate = remoteCallback;
CheckCertName = true;
EnabledSslProtocols = sslClientAuthenticationOptions.EnabledSslProtocols;
EncryptionPolicy = sslClientAuthenticationOptions.EncryptionPolicy;
@@ -26,7 +26,7 @@ namespace System.Net.Security
TargetHost = sslClientAuthenticationOptions.TargetHost;
// Client specific options.
- CertSelectionDelegate = sslClientAuthenticationOptions._certSelectionDelegate;
+ CertSelectionDelegate = localCallback;
CertificateRevocationCheckMode = sslClientAuthenticationOptions.CertificateRevocationCheckMode;
ClientCertificates = sslClientAuthenticationOptions.ClientCertificates;
LocalCertificateSelectionCallback = sslClientAuthenticationOptions.LocalCertificateSelectionCallback;
diff --git a/src/System.Net.Security/src/System/Net/Security/SslClientAuthenticationOptions.cs b/src/System.Net.Security/src/System/Net/Security/SslClientAuthenticationOptions.cs
index 4bc3773708..bf68f1d602 100644
--- a/src/System.Net.Security/src/System/Net/Security/SslClientAuthenticationOptions.cs
+++ b/src/System.Net.Security/src/System/Net/Security/SslClientAuthenticationOptions.cs
@@ -16,9 +16,6 @@ namespace System.Net.Security
private SslProtocols _enabledSslProtocols = SecurityProtocol.SystemDefaultSecurityProtocols;
private bool _allowRenegotiation = true;
- internal RemoteCertValidationCallback _certValidationDelegate;
- internal LocalCertSelectionCallback _certSelectionDelegate;
-
public bool AllowRenegotiation
{
get => _allowRenegotiation;
diff --git a/src/System.Net.Security/src/System/Net/Security/SslState.cs b/src/System.Net.Security/src/System/Net/Security/SslState.cs
index d415cf5bde..0e08a47427 100644
--- a/src/System.Net.Security/src/System/Net/Security/SslState.cs
+++ b/src/System.Net.Security/src/System/Net/Security/SslState.cs
@@ -77,12 +77,29 @@ namespace System.Net.Security
_innerStream = innerStream;
}
- internal void ValidateCreateContext(SslClientAuthenticationOptions sslClientAuthenticationOptions)
+ /// <summary>Set as the _exception when the instance is disposed.</summary>
+ private static readonly ExceptionDispatchInfo s_disposedSentinel = ExceptionDispatchInfo.Capture(new ObjectDisposedException(nameof(SslStream)));
+
+ private void ThrowIfExceptional()
{
- if (_exception != null)
+ ExceptionDispatchInfo e = _exception;
+ if (e != null)
{
- _exception.Throw();
+ // If the stored exception just indicates disposal, throw a new ODE rather than the stored one,
+ // so as to not continually build onto the shared exception's stack.
+ if (ReferenceEquals(e, s_disposedSentinel))
+ {
+ throw new ObjectDisposedException(nameof(SslStream));
+ }
+
+ // Throw the stored exception.
+ e.Throw();
}
+ }
+
+ internal void ValidateCreateContext(SslClientAuthenticationOptions sslClientAuthenticationOptions, RemoteCertValidationCallback remoteCallback, LocalCertSelectionCallback localCallback)
+ {
+ ThrowIfExceptional();
if (Context != null && Context.IsValidContext)
{
@@ -99,15 +116,14 @@ namespace System.Net.Security
throw new ArgumentNullException(nameof(sslClientAuthenticationOptions.TargetHost));
}
- if (sslClientAuthenticationOptions.TargetHost.Length == 0)
- {
- sslClientAuthenticationOptions.TargetHost = "?" + Interlocked.Increment(ref s_uniqueNameInteger).ToString(NumberFormatInfo.InvariantInfo);
- }
-
_exception = null;
try
{
- _sslAuthenticationOptions = new SslAuthenticationOptions(sslClientAuthenticationOptions);
+ _sslAuthenticationOptions = new SslAuthenticationOptions(sslClientAuthenticationOptions, remoteCallback, localCallback);
+ if (_sslAuthenticationOptions.TargetHost.Length == 0)
+ {
+ _sslAuthenticationOptions.TargetHost = "?" + Interlocked.Increment(ref s_uniqueNameInteger).ToString(NumberFormatInfo.InvariantInfo);
+ }
_context = new SecureChannel(_sslAuthenticationOptions);
}
catch (Win32Exception e)
@@ -118,10 +134,7 @@ namespace System.Net.Security
internal void ValidateCreateContext(SslServerAuthenticationOptions sslServerAuthenticationOptions)
{
- if (_exception != null)
- {
- _exception.Throw();
- }
+ ThrowIfExceptional();
if (Context != null && Context.IsValidContext)
{
@@ -401,7 +414,7 @@ namespace System.Net.Security
}
}
- private ExceptionDispatchInfo SetException(Exception e)
+ private void SetException(Exception e)
{
Debug.Assert(e != null, $"Expected non-null Exception to be passed to {nameof(SetException)}");
@@ -410,12 +423,7 @@ namespace System.Net.Security
_exception = ExceptionDispatchInfo.Capture(e);
}
- if (_exception != null && Context != null)
- {
- Context.Close();
- }
-
- return _exception;
+ Context?.Close();
}
private bool HandshakeCompleted
@@ -436,10 +444,7 @@ namespace System.Net.Security
internal void CheckThrow(bool authSuccessCheck, bool shutdownCheck = false)
{
- if (_exception != null)
- {
- _exception.Throw();
- }
+ ThrowIfExceptional();
if (authSuccessCheck && !IsAuthenticated)
{
@@ -467,11 +472,9 @@ namespace System.Net.Security
//
internal void Close()
{
- _exception = ExceptionDispatchInfo.Capture(new ObjectDisposedException("SslStream"));
- if (Context != null)
- {
- Context.Close();
- }
+ _exception = s_disposedSentinel;
+ Context?.Close();
+ _secureStream?.Dispose();
}
internal SecurityStatusPal EncryptData(ReadOnlyMemory<byte> buffer, ref byte[] outBuffer, out int outSize)
@@ -668,14 +671,12 @@ namespace System.Net.Security
_Framing = Framing.Unknown;
_handshakeCompleted = false;
- if (SetException(e).SourceException == e)
+ SetException(e);
+ if (_exception.SourceException != e)
{
- throw;
- }
- else
- {
- _exception.Throw();
+ ThrowIfExceptional();
}
+ throw;
}
finally
{
@@ -734,7 +735,8 @@ namespace System.Net.Security
_Framing = Framing.Unknown;
_handshakeCompleted = false;
- SetException(e).Throw();
+ SetException(e);
+ ThrowIfExceptional();
}
}
@@ -1286,7 +1288,7 @@ namespace System.Net.Security
AsyncProtocolRequest request = (AsyncProtocolRequest)_queuedReadStateRequest;
request.Buffer = renegotiateBuffer;
_queuedReadStateRequest = null;
- ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncResumeHandshakeRead), request);
+ ThreadPool.QueueUserWorkItem(s => s.sslState.AsyncResumeHandshakeRead(s.request), (sslState: this, request), preferLocal: false);
}
}
}
@@ -1384,7 +1386,7 @@ namespace System.Net.Security
taskCompletionSource.SetResult(0);
break;
default:
- ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncResumeHandshake), obj);
+ ThreadPool.QueueUserWorkItem(s => s.sslState.AsyncResumeHandshake(s.obj), (sslState: this, obj), preferLocal: false);
break;
}
}
@@ -1748,9 +1750,8 @@ namespace System.Net.Security
//
// Called with no user stack.
//
- private void AsyncResumeHandshakeRead(object state)
+ private void AsyncResumeHandshakeRead(AsyncProtocolRequest asyncRequest)
{
- AsyncProtocolRequest asyncRequest = (AsyncProtocolRequest)state;
try
{
if (_pendingReHandshake)
@@ -1776,22 +1777,6 @@ namespace System.Net.Security
}
}
- //
- // Called with no user stack.
- //
- private void CompleteRequestWaitCallback(object state)
- {
- AsyncProtocolRequest request = (AsyncProtocolRequest)state;
-
- // Force async completion.
- if (request.MustCompleteSynchronously)
- {
- throw new InternalException();
- }
-
- request.CompleteRequest(0);
- }
-
private void RehandshakeCompleteCallback(IAsyncResult result)
{
LazyAsyncResult lazyAsyncResult = (LazyAsyncResult)result;
diff --git a/src/System.Net.Security/src/System/Net/Security/SslStream.cs b/src/System.Net.Security/src/System/Net/Security/SslStream.cs
index 62027859b7..a4ff6d8c05 100644
--- a/src/System.Net.Security/src/System/Net/Security/SslStream.cs
+++ b/src/System.Net.Security/src/System/Net/Security/SslStream.cs
@@ -178,11 +178,7 @@ namespace System.Net.Security
SetAndVerifyValidationCallback(sslClientAuthenticationOptions.RemoteCertificateValidationCallback);
SetAndVerifySelectionCallback(sslClientAuthenticationOptions.LocalCertificateSelectionCallback);
- // Set the delegates on the options.
- sslClientAuthenticationOptions._certValidationDelegate = _certValidationDelegate;
- sslClientAuthenticationOptions._certSelectionDelegate = _certSelectionDelegate;
-
- _sslState.ValidateCreateContext(sslClientAuthenticationOptions);
+ _sslState.ValidateCreateContext(sslClientAuthenticationOptions, _certValidationDelegate, _certSelectionDelegate);
LazyAsyncResult result = new LazyAsyncResult(_sslState, asyncState, asyncCallback);
_sslState.ProcessAuthentication(result);
@@ -302,11 +298,7 @@ namespace System.Net.Security
SetAndVerifyValidationCallback(sslClientAuthenticationOptions.RemoteCertificateValidationCallback);
SetAndVerifySelectionCallback(sslClientAuthenticationOptions.LocalCertificateSelectionCallback);
- // Set the delegates on the options.
- sslClientAuthenticationOptions._certValidationDelegate = _certValidationDelegate;
- sslClientAuthenticationOptions._certSelectionDelegate = _certSelectionDelegate;
-
- _sslState.ValidateCreateContext(sslClientAuthenticationOptions);
+ _sslState.ValidateCreateContext(sslClientAuthenticationOptions, _certValidationDelegate, _certSelectionDelegate);
_sslState.ProcessAuthentication(null);
}
@@ -711,9 +703,9 @@ namespace System.Net.Security
return _sslState.SecureStream.WriteAsync(buffer, offset, count, cancellationToken);
}
- public override Task WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken)
+ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken)
{
- return _sslState.SecureStream.WriteAsync(source, cancellationToken);
+ return _sslState.SecureStream.WriteAsync(buffer, cancellationToken);
}
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
@@ -721,9 +713,9 @@ namespace System.Net.Security
return _sslState.SecureStream.ReadAsync(buffer, offset, count, cancellationToken);
}
- public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken = default)
+ public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
{
- return _sslState.SecureStream.ReadAsync(destination, cancellationToken);
+ return _sslState.SecureStream.ReadAsync(buffer, cancellationToken);
}
}
}
diff --git a/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.Adapters.cs b/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.Adapters.cs
index a94abda4d5..2dcc93fe31 100644
--- a/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.Adapters.cs
+++ b/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.Adapters.cs
@@ -12,7 +12,7 @@ namespace System.Net.Security
private interface ISslWriteAdapter
{
Task LockAsync();
- Task WriteAsync(byte[] buffer, int offset, int count);
+ ValueTask WriteAsync(byte[] buffer, int offset, int count);
}
private interface ISslReadAdapter
@@ -61,7 +61,7 @@ namespace System.Net.Security
public Task LockAsync() => _sslState.CheckEnqueueWriteAsync();
- public Task WriteAsync(byte[] buffer, int offset, int count) => _sslState.InnerStream.WriteAsync(buffer, offset, count, _cancellationToken);
+ public ValueTask WriteAsync(byte[] buffer, int offset, int count) => _sslState.InnerStream.WriteAsync(new ReadOnlyMemory<byte>(buffer, offset, count), _cancellationToken);
}
private readonly struct SslWriteSync : ISslWriteAdapter
@@ -76,10 +76,10 @@ namespace System.Net.Security
return Task.CompletedTask;
}
- public Task WriteAsync(byte[] buffer, int offset, int count)
+ public ValueTask WriteAsync(byte[] buffer, int offset, int count)
{
_sslState.InnerStream.Write(buffer, offset, count);
- return Task.CompletedTask;
+ return default;
}
}
}
diff --git a/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs b/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs
index 99e2f8b18a..a2581fa0b6 100644
--- a/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs
+++ b/src/System.Net.Security/src/System/Net/Security/SslStreamInternal.cs
@@ -14,7 +14,7 @@ namespace System.Net.Security
//
// This is a wrapping stream that does data encryption/decryption based on a successfully authenticated SSPI context.
//
- internal partial class SslStreamInternal
+ internal partial class SslStreamInternal : IDisposable
{
private const int FrameOverhead = 32;
private const int ReadBufferSize = 4096 * 4 + FrameOverhead; // We read in 16K chunks + headers.
@@ -57,10 +57,36 @@ namespace System.Net.Security
~SslStreamInternal()
{
- if (_internalBuffer != null)
+ Dispose(disposing: false);
+ }
+
+ public void Dispose()
+ {
+ Dispose(disposing: true);
+
+ if (_internalBuffer == null)
{
- ArrayPool<byte>.Shared.Return(_internalBuffer);
- _internalBuffer = null;
+ // Suppress finalizer if the read buffer was returned.
+ GC.SuppressFinalize(this);
+ }
+ }
+
+ private void Dispose(bool disposing)
+ {
+ // Ensure a Read operation is not in progress,
+ // block potential reads since SslStream is disposing.
+ // This leaves the _nestedRead = 1, but that's ok, since
+ // subsequent Reads first check if the context is still available.
+ if (Interlocked.CompareExchange(ref _nestedRead, 1, 0) == 0)
+ {
+ byte[] buffer = _internalBuffer;
+ if (buffer != null)
+ {
+ _internalBuffer = null;
+ _internalBufferCount = 0;
+ _internalOffset = 0;
+ ArrayPool<byte>.Shared.Return(buffer);
+ }
}
}
@@ -141,7 +167,7 @@ namespace System.Net.Security
internal void EndWrite(IAsyncResult asyncResult) => TaskToApm.End(asyncResult);
- internal Task WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken)
+ internal ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken)
{
SslWriteAsync writeAdapter = new SslWriteAsync(_sslState, cancellationToken);
return WriteAsyncInternal(writeAdapter, buffer);
@@ -150,7 +176,7 @@ namespace System.Net.Security
internal Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
ValidateParameters(buffer, offset, count);
- return WriteAsync(new ReadOnlyMemory<byte>(buffer, offset, count), cancellationToken);
+ return WriteAsync(new ReadOnlyMemory<byte>(buffer, offset, count), cancellationToken).AsTask();
}
private void ResetReadBuffer()
@@ -312,7 +338,7 @@ namespace System.Net.Security
}
}
- private Task WriteAsyncInternal<TWriteAdapter>(TWriteAdapter writeAdapter, ReadOnlyMemory<byte> buffer)
+ private ValueTask WriteAsyncInternal<TWriteAdapter>(TWriteAdapter writeAdapter, ReadOnlyMemory<byte> buffer)
where TWriteAdapter : struct, ISslWriteAdapter
{
_sslState.CheckThrow(authSuccessCheck: true, shutdownCheck: true);
@@ -320,7 +346,7 @@ namespace System.Net.Security
if (buffer.Length == 0 && !SslStreamPal.CanEncryptEmptyMessage)
{
// If it's an empty message and the PAL doesn't support that, we're done.
- return Task.CompletedTask;
+ return default;
}
if (Interlocked.Exchange(ref _nestedWrite, 1) == 1)
@@ -328,18 +354,18 @@ namespace System.Net.Security
throw new NotSupportedException(SR.Format(SR.net_io_invalidnestedcall, nameof(WriteAsync), "write"));
}
- Task t = buffer.Length < _sslState.MaxDataSize ?
+ ValueTask t = buffer.Length < _sslState.MaxDataSize ?
WriteSingleChunk(writeAdapter, buffer) :
- WriteAsyncChunked(writeAdapter, buffer);
+ new ValueTask(WriteAsyncChunked(writeAdapter, buffer));
if (t.IsCompletedSuccessfully)
{
_nestedWrite = 0;
return t;
}
- return ExitWriteAsync(t);
+ return new ValueTask(ExitWriteAsync(t));
- async Task ExitWriteAsync(Task task)
+ async Task ExitWriteAsync(ValueTask task)
{
try
{
@@ -363,7 +389,7 @@ namespace System.Net.Security
}
}
- private Task WriteSingleChunk<TWriteAdapter>(TWriteAdapter writeAdapter, ReadOnlyMemory<byte> buffer)
+ private ValueTask WriteSingleChunk<TWriteAdapter>(TWriteAdapter writeAdapter, ReadOnlyMemory<byte> buffer)
where TWriteAdapter : struct, ISslWriteAdapter
{
// Request a write IO slot.
@@ -371,7 +397,7 @@ namespace System.Net.Security
if (!ioSlot.IsCompletedSuccessfully)
{
// Operation is async and has been queued, return.
- return WaitForWriteIOSlot(writeAdapter, ioSlot, buffer);
+ return new ValueTask(WaitForWriteIOSlot(writeAdapter, ioSlot, buffer));
}
byte[] rentedBuffer = ArrayPool<byte>.Shared.Rent(buffer.Length + FrameOverhead);
@@ -384,10 +410,10 @@ namespace System.Net.Security
// Re-handshake status is not supported.
ArrayPool<byte>.Shared.Return(rentedBuffer);
ProtocolToken message = new ProtocolToken(null, status);
- return Task.FromException(new IOException(SR.net_io_encrypt, message.GetException()));
+ return new ValueTask(Task.FromException(new IOException(SR.net_io_encrypt, message.GetException())));
}
- Task t = writeAdapter.WriteAsync(outBuffer, 0, encryptedBytes);
+ ValueTask t = writeAdapter.WriteAsync(outBuffer, 0, encryptedBytes);
if (t.IsCompletedSuccessfully)
{
ArrayPool<byte>.Shared.Return(rentedBuffer);
@@ -396,7 +422,7 @@ namespace System.Net.Security
}
else
{
- return CompleteAsync(t, rentedBuffer);
+ return new ValueTask(CompleteAsync(t, rentedBuffer));
}
async Task WaitForWriteIOSlot(TWriteAdapter wAdapter, Task lockTask, ReadOnlyMemory<byte> buff)
@@ -405,7 +431,7 @@ namespace System.Net.Security
await WriteSingleChunk(wAdapter, buff).ConfigureAwait(false);
}
- async Task CompleteAsync(Task writeTask, byte[] bufferToReturn)
+ async Task CompleteAsync(ValueTask writeTask, byte[] bufferToReturn)
{
try
{
@@ -445,7 +471,7 @@ namespace System.Net.Security
ValueTask<int> t = adapter.ReadAsync(_internalBuffer, _internalBufferCount, _internalBuffer.Length - _internalBufferCount);
if (!t.IsCompletedSuccessfully)
{
- return new ValueTask<int>(InternalFillBufferAsync(adapter, t.AsTask(), minSize, initialCount));
+ return new ValueTask<int>(InternalFillBufferAsync(adapter, t, minSize, initialCount));
}
int bytes = t.Result;
if (bytes == 0)
@@ -464,7 +490,7 @@ namespace System.Net.Security
return new ValueTask<int>(minSize);
- async Task<int> InternalFillBufferAsync(TReadAdapter adap, Task<int> task, int min, int initial)
+ async Task<int> InternalFillBufferAsync(TReadAdapter adap, ValueTask<int> task, int min, int initial)
{
while (true)
{
@@ -485,7 +511,7 @@ namespace System.Net.Security
return min;
}
- task = adap.ReadAsync(_internalBuffer, _internalBufferCount, _internalBuffer.Length - _internalBufferCount).AsTask();
+ task = adap.ReadAsync(_internalBuffer, _internalBufferCount, _internalBuffer.Length - _internalBufferCount);
}
}
}
diff --git a/src/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs b/src/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs
index 54f8303ce5..02943cc70f 100644
--- a/src/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs
+++ b/src/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs
@@ -16,8 +16,6 @@ namespace System.Net.Security
{
internal static class SslStreamPal
{
- private static readonly StreamSizes s_streamSizes = new StreamSizes();
-
public static Exception GetException(SecurityStatusPal status)
{
return status.Exception ?? new Win32Exception((int)status.ErrorCode);
@@ -128,7 +126,7 @@ namespace System.Net.Security
unsafe
{
- MemoryHandle memHandle = input.Retain(pin: true);
+ MemoryHandle memHandle = input.Pin();
try
{
PAL_TlsIo status;
@@ -259,7 +257,7 @@ namespace System.Net.Security
SafeDeleteContext securityContext,
out StreamSizes streamSizes)
{
- streamSizes = s_streamSizes;
+ streamSizes = StreamSizes.Default;
}
public static void QueryContextConnectionInfo(
diff --git a/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs b/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs
index 38461f1996..e0d7ebc9d2 100644
--- a/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs
+++ b/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Unix.cs
@@ -15,8 +15,6 @@ namespace System.Net.Security
{
internal static class SslStreamPal
{
- private static readonly StreamSizes s_streamSizes = new StreamSizes();
-
public static Exception GetException(SecurityStatusPal status)
{
return status.Exception ?? new Interop.OpenSsl.SslException((int)status.ErrorCode);
@@ -122,7 +120,7 @@ namespace System.Net.Security
public static void QueryContextStreamSizes(SafeDeleteContext securityContext, out StreamSizes streamSizes)
{
- streamSizes = s_streamSizes;
+ streamSizes = StreamSizes.Default;
}
public static void QueryContextConnectionInfo(SafeDeleteContext securityContext, out SslConnectionInfo connectionInfo)
diff --git a/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs b/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs
index d2b822b84d..399d1c3750 100644
--- a/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs
+++ b/src/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs
@@ -153,7 +153,8 @@ namespace System.Net.Security
Interop.SspiCli.SCHANNEL_CRED.Flags.SCH_SEND_AUX_RECORD;
// CoreFX: always opt-in SCH_USE_STRONG_CRYPTO except for SSL3.
- if (((protocolFlags & (Interop.SChannel.SP_PROT_TLS1_0 | Interop.SChannel.SP_PROT_TLS1_1 | Interop.SChannel.SP_PROT_TLS1_2)) != 0)
+ if (((protocolFlags == 0) ||
+ (protocolFlags & (Interop.SChannel.SP_PROT_TLS1_0 | Interop.SChannel.SP_PROT_TLS1_1 | Interop.SChannel.SP_PROT_TLS1_2)) != 0)
&& (policy != EncryptionPolicy.AllowNoEncryption) && (policy != EncryptionPolicy.NoEncryption))
{
flags |= Interop.SspiCli.SCHANNEL_CRED.Flags.SCH_USE_STRONG_CRYPTO;
@@ -165,6 +166,7 @@ namespace System.Net.Security
flags = Interop.SspiCli.SCHANNEL_CRED.Flags.SCH_SEND_AUX_RECORD;
}
+ if (NetEventSource.IsEnabled) NetEventSource.Info($"flags=({flags}), ProtocolFlags=({protocolFlags}), EncryptionPolicy={policy}");
Interop.SspiCli.SCHANNEL_CRED secureCredential = CreateSecureCredential(
Interop.SspiCli.SCHANNEL_CRED.CurrentVersion,
certificate,
diff --git a/src/System.Net.Security/src/System/Net/Security/StreamSizes.OSX.cs b/src/System.Net.Security/src/System/Net/Security/StreamSizes.OSX.cs
index ed34467fe9..5d8e5e9ef6 100644
--- a/src/System.Net.Security/src/System/Net/Security/StreamSizes.OSX.cs
+++ b/src/System.Net.Security/src/System/Net/Security/StreamSizes.OSX.cs
@@ -4,7 +4,7 @@
namespace System.Net
{
- internal partial class StreamSizes
+ internal partial struct StreamSizes
{
// Windows SChannel requires that you pass it a buffer big enough to hold
// the header, the trailer, and the payload. You're also required to do your
@@ -19,11 +19,6 @@ namespace System.Net
// but using a bound of 32k means that if we were to switch from pointers to temporary
// arrays, we'd be maintaining a reasonable upper bound.
- public StreamSizes()
- {
- Header = 0;
- Trailer = 0;
- MaximumMessage = 32 * 1024;
- }
+ public static StreamSizes Default => new StreamSizes { MaximumMessage = 32 * 1024 };
}
}
diff --git a/src/System.Net.Security/src/System/Net/Security/StreamSizes.Unix.cs b/src/System.Net.Security/src/System/Net/Security/StreamSizes.Unix.cs
index 58025fa760..69d1a46318 100644
--- a/src/System.Net.Security/src/System/Net/Security/StreamSizes.Unix.cs
+++ b/src/System.Net.Security/src/System/Net/Security/StreamSizes.Unix.cs
@@ -4,7 +4,7 @@
namespace System.Net
{
- internal partial class StreamSizes
+ internal partial struct StreamSizes
{
// Windows SChannel requires that you pass it a buffer big enough to hold
// the header, the trailer, and the payload. You're also required to do your
@@ -20,11 +20,6 @@ namespace System.Net
// but using a bound of 32k means that if we were to switch from pointers to temporary
// arrays, we'd be maintaining a reasonable upper bound.
- public StreamSizes()
- {
- Header = 0;
- Trailer = 0;
- MaximumMessage = 32 * 1024;
- }
+ public static StreamSizes Default => new StreamSizes { MaximumMessage = 32 * 1024 };
}
}
diff --git a/src/System.Net.Security/src/System/Net/Security/StreamSizes.Windows.cs b/src/System.Net.Security/src/System/Net/Security/StreamSizes.Windows.cs
index a09cad726a..2b1184aa04 100644
--- a/src/System.Net.Security/src/System/Net/Security/StreamSizes.Windows.cs
+++ b/src/System.Net.Security/src/System/Net/Security/StreamSizes.Windows.cs
@@ -4,7 +4,7 @@
namespace System.Net
{
- internal partial class StreamSizes
+ internal partial struct StreamSizes
{
public StreamSizes(SecPkgContext_StreamSizes interopStreamSizes)
{
diff --git a/src/System.Net.Security/src/System/Net/Security/StreamSizes.cs b/src/System.Net.Security/src/System/Net/Security/StreamSizes.cs
index a885fa364e..a9cfaff12d 100644
--- a/src/System.Net.Security/src/System/Net/Security/StreamSizes.cs
+++ b/src/System.Net.Security/src/System/Net/Security/StreamSizes.cs
@@ -4,7 +4,7 @@
namespace System.Net
{
- internal partial class StreamSizes
+ internal partial struct StreamSizes
{
public int Header
{
diff --git a/src/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs b/src/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs
index e89925d910..4739156715 100644
--- a/src/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs
+++ b/src/System.Net.Security/tests/FunctionalTests/ClientAsyncAuthenticateTest.cs
@@ -25,6 +25,17 @@ namespace System.Net.Security.Tests
}
[Fact]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "CI uses old Framework version, which doesn't support using SslProtocols.None for SystemDefaultTlsVersions behavior")]
+ public async Task ClientAsyncAuthenticate_SslStreamClientServerNone_UseStrongCryptoSet()
+ {
+ SslProtocols protocol = SslProtocols.None;
+ await ClientAsyncSslHelper(protocol, protocol);
+
+ // Additional manual verification.
+ // Step into the code and verify that the 'SCH_USE_STRONG_CRYPTO' flag is being set.
+ }
+
+ [Fact]
public async Task ClientAsyncAuthenticate_ServerRequireEncryption_ConnectWithEncryption()
{
await ClientAsyncSslHelper(EncryptionPolicy.RequireEncryption);
diff --git a/src/System.Net.Security/tests/FunctionalTests/NegotiateStreamStreamToStreamTest.cs b/src/System.Net.Security/tests/FunctionalTests/NegotiateStreamStreamToStreamTest.cs
index 30ddb217fd..552c731a5e 100644
--- a/src/System.Net.Security/tests/FunctionalTests/NegotiateStreamStreamToStreamTest.cs
+++ b/src/System.Net.Security/tests/FunctionalTests/NegotiateStreamStreamToStreamTest.cs
@@ -184,7 +184,7 @@ namespace System.Net.Security.Tests
Assert.Equal(false, clientIdentity.IsAuthenticated);
// On .Net Desktop: Assert.Equal(true, clientIdentity.IsAuthenticated);
- IdentityValidator.AssertHasName(clientIdentity, @"NT AUTHORITY\ANONYMOUS LOGON");
+ IdentityValidator.AssertHasName(clientIdentity, new SecurityIdentifier(WellKnownSidType.AnonymousSid, null).Translate(typeof(NTAccount)).Value);
}
}
diff --git a/src/System.Net.Security/tests/FunctionalTests/SslAuthenticationOptionsTest.cs b/src/System.Net.Security/tests/FunctionalTests/SslAuthenticationOptionsTest.cs
new file mode 100644
index 0000000000..ada4a652b6
--- /dev/null
+++ b/src/System.Net.Security/tests/FunctionalTests/SslAuthenticationOptionsTest.cs
@@ -0,0 +1,108 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Net.Test.Common;
+using System.Security.Cryptography.X509Certificates;
+using System.Security.Authentication;
+using System.Threading.Tasks;
+using Xunit;
+using System.Linq;
+
+namespace System.Net.Security.Tests
+{
+ using Configuration = System.Net.Test.Common.Configuration;
+
+ public class SslClientAuthenticationOptionsTest
+ {
+ [Fact]
+ public async Task ClientOptions_ServerOptions_NotMutatedDuringAuthentication()
+ {
+ using (X509Certificate2 clientCert = Configuration.Certificates.GetClientCertificate())
+ using (X509Certificate2 serverCert = Configuration.Certificates.GetServerCertificate())
+ {
+ // Values used to populate client options
+ bool clientAllowRenegotiation = false;
+ List<SslApplicationProtocol> clientAppProtocols = new List<SslApplicationProtocol> { SslApplicationProtocol.Http11 };
+ X509RevocationMode clientRevocation = X509RevocationMode.NoCheck;
+ X509CertificateCollection clientCertificates = new X509CertificateCollection() { clientCert };
+ SslProtocols clientSslProtocols = SslProtocols.Tls12;
+ EncryptionPolicy clientEncryption = EncryptionPolicy.RequireEncryption;
+ LocalCertificateSelectionCallback clientLocalCallback = new LocalCertificateSelectionCallback(delegate { return null; });
+ RemoteCertificateValidationCallback clientRemoteCallback = new RemoteCertificateValidationCallback(delegate { return true; });
+ string clientHost = serverCert.GetNameInfo(X509NameType.SimpleName, false);
+
+ // Values used to populate server options
+ bool serverAllowRenegotiation = true;
+ List<SslApplicationProtocol> serverAppProtocols = new List<SslApplicationProtocol> { SslApplicationProtocol.Http11, SslApplicationProtocol.Http2 };
+ X509RevocationMode serverRevocation = X509RevocationMode.NoCheck;
+ bool serverCertRequired = false;
+ SslProtocols serverSslProtocols = SslProtocols.Tls11 | SslProtocols.Tls12;
+ EncryptionPolicy serverEncryption = EncryptionPolicy.AllowNoEncryption;
+ RemoteCertificateValidationCallback serverRemoteCallback = new RemoteCertificateValidationCallback(delegate { return true; });
+
+ var network = new VirtualNetwork();
+ using (var client = new SslStream(new VirtualNetworkStream(network, isServer: false)))
+ using (var server = new SslStream(new VirtualNetworkStream(network, isServer: true)))
+ {
+ // Create client options
+ var clientOptions = new SslClientAuthenticationOptions
+ {
+ AllowRenegotiation = clientAllowRenegotiation,
+ ApplicationProtocols = clientAppProtocols,
+ CertificateRevocationCheckMode = clientRevocation,
+ ClientCertificates = clientCertificates,
+ EnabledSslProtocols = clientSslProtocols,
+ EncryptionPolicy = clientEncryption,
+ LocalCertificateSelectionCallback = clientLocalCallback,
+ RemoteCertificateValidationCallback = clientRemoteCallback,
+ TargetHost = clientHost
+ };
+
+ // Create server options
+ var serverOptions = new SslServerAuthenticationOptions
+ {
+ AllowRenegotiation = serverAllowRenegotiation,
+ ApplicationProtocols = serverAppProtocols,
+ CertificateRevocationCheckMode = serverRevocation,
+ ClientCertificateRequired = serverCertRequired,
+ EnabledSslProtocols = serverSslProtocols,
+ EncryptionPolicy = serverEncryption,
+ RemoteCertificateValidationCallback = serverRemoteCallback,
+ ServerCertificate = serverCert
+ };
+
+ // Authenticate
+ Task clientTask = client.AuthenticateAsClientAsync(clientOptions, default);
+ Task serverTask = server.AuthenticateAsServerAsync(serverOptions, default);
+ await new[] { clientTask, serverTask }.WhenAllOrAnyFailed();
+
+ // Validate that client options are unchanged
+ Assert.Equal(clientAllowRenegotiation, clientOptions.AllowRenegotiation);
+ Assert.Same(clientAppProtocols, clientOptions.ApplicationProtocols);
+ Assert.Equal(1, clientOptions.ApplicationProtocols.Count);
+ Assert.Equal(clientRevocation, clientOptions.CertificateRevocationCheckMode);
+ Assert.Same(clientCertificates, clientOptions.ClientCertificates);
+ Assert.Contains(clientCert, clientOptions.ClientCertificates.Cast<X509Certificate2>());
+ Assert.Equal(clientSslProtocols, clientOptions.EnabledSslProtocols);
+ Assert.Equal(clientEncryption, clientOptions.EncryptionPolicy);
+ Assert.Same(clientLocalCallback, clientOptions.LocalCertificateSelectionCallback);
+ Assert.Same(clientRemoteCallback, clientOptions.RemoteCertificateValidationCallback);
+ Assert.Same(clientHost, clientOptions.TargetHost);
+
+ // Validate that server options are unchanged
+ Assert.Equal(serverAllowRenegotiation, serverOptions.AllowRenegotiation);
+ Assert.Same(serverAppProtocols, serverOptions.ApplicationProtocols);
+ Assert.Equal(2, serverOptions.ApplicationProtocols.Count);
+ Assert.Equal(clientRevocation, serverOptions.CertificateRevocationCheckMode);
+ Assert.Equal(serverCertRequired, serverOptions.ClientCertificateRequired);
+ Assert.Equal(serverSslProtocols, serverOptions.EnabledSslProtocols);
+ Assert.Equal(serverEncryption, serverOptions.EncryptionPolicy);
+ Assert.Same(serverRemoteCallback, serverOptions.RemoteCertificateValidationCallback);
+ Assert.Same(serverCert, serverOptions.ServerCertificate);
+ }
+ }
+ }
+ }
+}
diff --git a/src/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs b/src/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs
index b02f57468e..ae608d302b 100644
--- a/src/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs
+++ b/src/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.IO;
using System.Linq;
using System.Net.Test.Common;
using System.Security.Authentication;
@@ -307,6 +308,51 @@ namespace System.Net.Security.Tests
}
[Fact]
+ public async Task SslStream_StreamToStream_Dispose_Throws()
+ {
+ VirtualNetwork network = new VirtualNetwork();
+ using (var clientStream = new VirtualNetworkStream(network, isServer: false))
+ using (var serverStream = new VirtualNetworkStream(network, isServer: true))
+ using (var clientSslStream = new SslStream(clientStream, false, AllowAnyServerCertificate))
+ {
+ var serverSslStream = new SslStream(serverStream);
+ await DoHandshake(clientSslStream, serverSslStream);
+
+ var serverBuffer = new byte[1];
+ Task serverReadTask = serverSslStream.ReadAsync(serverBuffer, 0, serverBuffer.Length);
+ await serverSslStream.WriteAsync(new byte[] { 1 }, 0, 1)
+ .TimeoutAfter(TestConfiguration.PassingTestTimeoutMilliseconds);
+
+ // Shouldn't throw, the context is diposed now.
+ // Since the server read task is in progress, the read buffer is not returned to ArrayPool.
+ serverSslStream.Dispose();
+
+ // Read in client
+ var clientBuffer = new byte[1];
+ await clientSslStream.ReadAsync(clientBuffer, 0, clientBuffer.Length);
+ Assert.Equal(1, clientBuffer[0]);
+
+ await clientSslStream.WriteAsync(new byte[] { 2 }, 0, 1);
+
+ if (PlatformDetection.IsFullFramework)
+ {
+ await Assert.ThrowsAsync<ObjectDisposedException>(() => serverReadTask);
+ }
+ else
+ {
+ IOException serverException = await Assert.ThrowsAsync<IOException>(() => serverReadTask);
+ Assert.IsType<ObjectDisposedException>(serverException.InnerException);
+ }
+
+ await Assert.ThrowsAsync<ObjectDisposedException>(() => serverSslStream.ReadAsync(serverBuffer, 0, serverBuffer.Length));
+
+ // Now, there is no pending read, so the internal buffer will be returned to ArrayPool.
+ serverSslStream.Dispose();
+ await Assert.ThrowsAsync<ObjectDisposedException>(() => serverSslStream.ReadAsync(serverBuffer, 0, serverBuffer.Length));
+ }
+ }
+
+ [Fact]
public void SslStream_StreamToStream_Flush_Propagated()
{
VirtualNetwork network = new VirtualNetwork();
diff --git a/src/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj b/src/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj
index 87291673ac..8268fd077b 100644
--- a/src/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj
+++ b/src/System.Net.Security/tests/FunctionalTests/System.Net.Security.Tests.csproj
@@ -90,6 +90,7 @@
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)'=='netcoreapp'">
<!-- TODO #13070: Add net463 to the condition after the TFM gets updated to the actual .Net 4.7-->
+ <Compile Include="SslAuthenticationOptionsTest.cs" />
<Compile Include="SslStreamAlertsTest.cs" />
<Compile Include="SslStreamAllowRenegotiationTests.cs" />
<Compile Include="SslStreamAlpnTests.cs" />
@@ -154,5 +155,8 @@
<Name>RemoteExecutorConsoleApp</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.Net.Security/tests/UnitTests/Fakes/FakeAuthenticatedStream.cs b/src/System.Net.Security/tests/UnitTests/Fakes/FakeAuthenticatedStream.cs
index be2d2483d5..1a549fea08 100644
--- a/src/System.Net.Security/tests/UnitTests/Fakes/FakeAuthenticatedStream.cs
+++ b/src/System.Net.Security/tests/UnitTests/Fakes/FakeAuthenticatedStream.cs
@@ -33,7 +33,7 @@ namespace System.Net.Security
public abstract bool IsSigned { get; }
public abstract bool IsServer { get; }
- public new abstract Task WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken token);
+ public new abstract ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken token);
public new abstract ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken);
}
}
diff --git a/src/System.Net.Security/tests/UnitTests/Fakes/FakeSslState.cs b/src/System.Net.Security/tests/UnitTests/Fakes/FakeSslState.cs
index 2ee788a9ea..9382bd1398 100644
--- a/src/System.Net.Security/tests/UnitTests/Fakes/FakeSslState.cs
+++ b/src/System.Net.Security/tests/UnitTests/Fakes/FakeSslState.cs
@@ -21,7 +21,7 @@ namespace System.Net.Security
{
}
- internal void ValidateCreateContext(SslClientAuthenticationOptions sslClientAuthenticationOptions)
+ internal void ValidateCreateContext(SslClientAuthenticationOptions sslClientAuthenticationOptions, RemoteCertValidationCallback remoteCallback, LocalCertSelectionCallback localCallback)
{
}
@@ -279,7 +279,7 @@ namespace System.Net.Security
throw new NotImplementedException();
}
- public new Task WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken)
+ public new ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
diff --git a/src/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj b/src/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj
index d1181a7f2e..fba7e18fba 100644
--- a/src/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj
+++ b/src/System.Net.Security/tests/UnitTests/System.Net.Security.Unit.Tests.csproj
@@ -85,5 +85,8 @@
<Reference Include="System.Threading" />
<Reference Include="System.Threading.Tasks" />
</ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.Net.ServicePoint/src/System/Net/ServicePointManager.cs b/src/System.Net.ServicePoint/src/System/Net/ServicePointManager.cs
index 5d0f21c44a..250c455aba 100644
--- a/src/System.Net.ServicePoint/src/System/Net/ServicePointManager.cs
+++ b/src/System.Net.ServicePoint/src/System/Net/ServicePointManager.cs
@@ -176,16 +176,27 @@ namespace System.Net
{
if (proxy != null && !address.IsLoopback)
{
- Uri proxyAddress = proxy.GetProxy(address);
- if (proxyAddress != null)
+ try
{
- if (proxyAddress.Scheme != Uri.UriSchemeHttp)
+ Uri proxyAddress = proxy.GetProxy(address);
+ if (proxyAddress != null)
{
- throw new NotSupportedException(SR.Format(SR.net_proxyschemenotsupported, address.Scheme));
- }
+ if (proxyAddress.Scheme != Uri.UriSchemeHttp)
+ {
+ throw new NotSupportedException(SR.Format(SR.net_proxyschemenotsupported, address.Scheme));
+ }
- address = proxyAddress;
- return true;
+ address = proxyAddress;
+ return true;
+ }
+ }
+ catch (PlatformNotSupportedException)
+ {
+ // HttpWebRequest has a dummy SystemWebProxy that's used as a sentinel
+ // and whose GetProxy method throws a PlatformNotSupportedException.
+ // For the purposes of this stand-in ServicePointManager implementation,
+ // we ignore this default "system" proxy for the purposes of mapping
+ // to a particular ServicePoint instance.
}
}
diff --git a/src/System.Net.ServicePoint/tests/ServicePointManagerTest.cs b/src/System.Net.ServicePoint/tests/ServicePointManagerTest.cs
index f25ad6f7e3..f9ab985f3c 100644
--- a/src/System.Net.ServicePoint/tests/ServicePointManagerTest.cs
+++ b/src/System.Net.ServicePoint/tests/ServicePointManagerTest.cs
@@ -15,7 +15,7 @@ namespace System.Net.Tests
[Fact]
public static void RequireEncryption_ExpectedDefault()
{
- RemoteInvoke(() => Assert.Equal(EncryptionPolicy.RequireEncryption, ServicePointManager.EncryptionPolicy));
+ RemoteInvoke(() => Assert.Equal(EncryptionPolicy.RequireEncryption, ServicePointManager.EncryptionPolicy)).Dispose();
}
[Fact]
@@ -30,7 +30,7 @@ namespace System.Net.Tests
ServicePointManager.CheckCertificateRevocationList = false;
Assert.False(ServicePointManager.CheckCertificateRevocationList);
- });
+ }).Dispose();
}
[Fact]
@@ -45,7 +45,7 @@ namespace System.Net.Tests
ServicePointManager.DefaultConnectionLimit = 2;
Assert.Equal(2, ServicePointManager.DefaultConnectionLimit);
- });
+ }).Dispose();
}
[Fact]
@@ -60,7 +60,7 @@ namespace System.Net.Tests
ServicePointManager.DnsRefreshTimeout = 120000;
Assert.Equal(120000, ServicePointManager.DnsRefreshTimeout);
- });
+ }).Dispose();
}
[Fact]
@@ -75,7 +75,7 @@ namespace System.Net.Tests
ServicePointManager.EnableDnsRoundRobin = false;
Assert.False(ServicePointManager.EnableDnsRoundRobin);
- });
+ }).Dispose();
}
[Fact]
@@ -90,7 +90,7 @@ namespace System.Net.Tests
ServicePointManager.Expect100Continue = true;
Assert.True(ServicePointManager.Expect100Continue);
- });
+ }).Dispose();
}
[Fact]
@@ -105,7 +105,7 @@ namespace System.Net.Tests
ServicePointManager.MaxServicePointIdleTime = 100000;
Assert.Equal(100000, ServicePointManager.MaxServicePointIdleTime);
- });
+ }).Dispose();
}
[Fact]
@@ -120,7 +120,7 @@ namespace System.Net.Tests
ServicePointManager.MaxServicePoints = 0;
Assert.Equal(0, ServicePointManager.MaxServicePoints);
- });
+ }).Dispose();
}
[Fact]
@@ -135,7 +135,7 @@ namespace System.Net.Tests
ServicePointManager.ReusePort = false;
Assert.False(ServicePointManager.ReusePort);
- });
+ }).Dispose();
}
[Fact]
@@ -152,7 +152,7 @@ namespace System.Net.Tests
ServicePointManager.SecurityProtocol = orig;
Assert.Equal(orig, ServicePointManager.SecurityProtocol);
- });
+ }).Dispose();
}
[Fact]
@@ -168,7 +168,7 @@ namespace System.Net.Tests
ServicePointManager.ServerCertificateValidationCallback = null;
Assert.Null(ServicePointManager.ServerCertificateValidationCallback);
- });
+ }).Dispose();
}
[Fact]
@@ -183,7 +183,7 @@ namespace System.Net.Tests
ServicePointManager.UseNagleAlgorithm = true;
Assert.True(ServicePointManager.UseNagleAlgorithm);
- });
+ }).Dispose();
}
[Fact]
@@ -214,7 +214,7 @@ namespace System.Net.Tests
AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => sp.ReceiveBufferSize = -2);
AssertExtensions.Throws<ArgumentOutOfRangeException>("keepAliveTime", () => sp.SetTcpKeepAlive(true, -1, 1));
AssertExtensions.Throws<ArgumentOutOfRangeException>("keepAliveInterval", () => sp.SetTcpKeepAlive(true, 1, -1));
- });
+ }).Dispose();
}
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Ssl3 is supported by desktop but explicitly not by core")]
@@ -231,7 +231,7 @@ namespace System.Net.Tests
Assert.Throws<NotSupportedException>(() => ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3);
Assert.Throws<NotSupportedException>(() => ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | ssl2);
#pragma warning restore
- });
+ }).Dispose();
}
[Fact]
@@ -267,7 +267,7 @@ namespace System.Net.Tests
Assert.NotSame(
ServicePointManager.FindServicePoint(address1, new FixedWebProxy(address1)),
ServicePointManager.FindServicePoint(address1, new FixedWebProxy(address2)));
- });
+ }).Dispose();
}
[Fact]
@@ -286,7 +286,7 @@ namespace System.Net.Tests
GC.Collect();
Assert.Equal(initial, GetExpect100Continue(address));
- });
+ }).Dispose();
}
[Fact]
@@ -313,7 +313,7 @@ namespace System.Net.Tests
Assert.Equal(-1, sp.ReceiveBufferSize);
Assert.True(sp.SupportsPipelining, "SupportsPipelining");
Assert.True(sp.UseNagleAlgorithm, "UseNagleAlgorithm");
- });
+ }).Dispose();
}
[Fact]
@@ -348,7 +348,7 @@ namespace System.Net.Tests
Assert.Equal(expectedMaxIdleTime, sp2.MaxIdleTime);
Assert.Equal(expectedReceiveBufferSize, sp2.ReceiveBufferSize);
Assert.Equal(expectedUseNagleAlgorithm, sp2.UseNagleAlgorithm);
- });
+ }).Dispose();
}
[Fact]
@@ -378,7 +378,7 @@ namespace System.Net.Tests
ServicePointManager.Expect100Continue = orig100Continue;
ServicePointManager.UseNagleAlgorithm = origNagle;
- });
+ }).Dispose();
}
// Separated out to avoid the JIT in debug builds interfering with object lifetimes
diff --git a/src/System.Net.ServicePoint/tests/TlsSystemDefault.cs b/src/System.Net.ServicePoint/tests/TlsSystemDefault.cs
index 76e7d8ce7c..67ee162073 100644
--- a/src/System.Net.ServicePoint/tests/TlsSystemDefault.cs
+++ b/src/System.Net.ServicePoint/tests/TlsSystemDefault.cs
@@ -12,13 +12,13 @@ namespace System.Net.Tests
[Fact]
public void ServicePointManager_SecurityProtocolDefault_Ok()
{
- RemoteInvoke(() => Assert.Equal(SecurityProtocolType.SystemDefault, ServicePointManager.SecurityProtocol));
+ RemoteInvoke(() => Assert.Equal(SecurityProtocolType.SystemDefault, ServicePointManager.SecurityProtocol)).Dispose();
}
[Fact]
public void ServicePointManager_CheckAllowedProtocols_SystemDefault_Allowed()
{
- RemoteInvoke(() => ServicePointManager.SecurityProtocol = SecurityProtocolType.SystemDefault);
+ RemoteInvoke(() => ServicePointManager.SecurityProtocol = SecurityProtocolType.SystemDefault).Dispose();
}
}
}
diff --git a/src/System.Net.Sockets/src/Resources/Strings.resx b/src/System.Net.Sockets/src/Resources/Strings.resx
index de08663dd3..b95d2522e7 100644
--- a/src/System.Net.Sockets/src/Resources/Strings.resx
+++ b/src/System.Net.Sockets/src/Resources/Strings.resx
@@ -238,4 +238,10 @@
<data name="InvalidOperation_BufferNotExplicitArray" xml:space="preserve">
<value>This operation may only be performed when the buffer was set using the SetBuffer overload that accepts an array.</value>
</data>
+ <data name="InvalidOperation_IncorrectToken" xml:space="preserve">
+ <value>The result of the operation was already consumed and may not be used again.</value>
+ </data>
+ <data name="InvalidOperation_MultipleContinuations" xml:space="preserve">
+ <value>Another continuation was already registered.</value>
+ </data>
</root>
diff --git a/src/System.Net.Sockets/src/System.Net.Sockets.csproj b/src/System.Net.Sockets/src/System.Net.Sockets.csproj
index dd4680c6d4..35a8203423 100644
--- a/src/System.Net.Sockets/src/System.Net.Sockets.csproj
+++ b/src/System.Net.Sockets/src/System.Net.Sockets.csproj
@@ -7,6 +7,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'netfx'">true</IsPartialFacadeAssembly>
<OmitResources Condition="'$(TargetGroup)' == 'netfx'">true</OmitResources>
+ <ILLinkClearInitLocals>true</ILLinkClearInitLocals>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
@@ -62,6 +63,7 @@
<Compile Include="System\Net\Sockets\MultipleConnectAsync.cs" />
<Compile Include="System\Net\Sockets\OverlappedAsyncResult.cs" />
<Compile Include="System\Net\Sockets\ReceiveMessageOverlappedAsyncResult.cs" />
+ <Compile Include="System\Net\Sockets\UnixDomainSocketEndPoint.cs" />
<Compile Include="$(CommonPath)\System\IO\StreamHelpers.CopyValidation.cs">
<Link>Common\System\IO\StreamHelpers.CopyValidation.cs</Link>
</Compile>
@@ -411,6 +413,7 @@
<Reference Include="System.Threading" />
<Reference Include="System.Threading.Overlapped" />
<Reference Include="System.Threading.Tasks" />
+ <Reference Include="System.Threading.ThreadPool" />
</ItemGroup>
<ItemGroup Condition="'$(TargetsUnix)' == 'true'">
<Reference Include="System.Threading.ThreadPool" />
diff --git a/src/System.Net.Sockets/src/System/Net/Sockets/NetEventSource.Sockets.cs b/src/System.Net.Sockets/src/System/Net/Sockets/NetEventSource.Sockets.cs
index 9210ded65a..6529d794f3 100644
--- a/src/System.Net.Sockets/src/System/Net/Sockets/NetEventSource.Sockets.cs
+++ b/src/System.Net.Sockets/src/System/Net/Sockets/NetEventSource.Sockets.cs
@@ -5,6 +5,7 @@
using System.Diagnostics.Tracing;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
namespace System.Net
{
@@ -106,7 +107,7 @@ namespace System.Net
}
buffer = buffer.Slice(offset, Math.Min(count, MaxDumpSize));
- byte[] slice = buffer.TryGetArray(out ArraySegment<byte> arraySegment) && arraySegment.Offset == 0 && arraySegment.Count == buffer.Length ?
+ byte[] slice = MemoryMarshal.TryGetArray(buffer, out ArraySegment<byte> arraySegment) && arraySegment.Offset == 0 && arraySegment.Count == buffer.Length ?
arraySegment.Array :
buffer.ToArray();
diff --git a/src/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs b/src/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs
index 64a3b7803c..d8ab22b135 100644
--- a/src/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs
+++ b/src/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs
@@ -204,7 +204,7 @@ namespace System.Net.Sockets
#endif
if (_cleanedUp)
{
- throw new ObjectDisposedException(this.GetType().FullName);
+ throw new ObjectDisposedException(GetType().FullName);
}
// Ask the socket how many bytes are available. If it's
@@ -269,7 +269,7 @@ namespace System.Net.Sockets
bool canRead = CanRead; // Prevent race with Dispose.
if (_cleanedUp)
{
- throw new ObjectDisposedException(this.GetType().FullName);
+ throw new ObjectDisposedException(GetType().FullName);
}
if (!canRead)
{
@@ -281,11 +281,11 @@ namespace System.Net.Sockets
{
throw new ArgumentNullException(nameof(buffer));
}
- if (offset < 0 || offset > buffer.Length)
+ if ((uint)offset > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(offset));
}
- if (size < 0 || size > buffer.Length - offset)
+ if ((uint)size > buffer.Length - offset)
{
throw new ArgumentOutOfRangeException(nameof(size));
}
@@ -329,7 +329,7 @@ namespace System.Net.Sockets
public override unsafe int ReadByte()
{
- int b;
+ byte b;
return Read(new Span<byte>(&b, 1)) == 0 ? -1 : b;
}
@@ -358,7 +358,7 @@ namespace System.Net.Sockets
bool canWrite = CanWrite; // Prevent race with Dispose.
if (_cleanedUp)
{
- throw new ObjectDisposedException(this.GetType().FullName);
+ throw new ObjectDisposedException(GetType().FullName);
}
if (!canWrite)
{
@@ -370,11 +370,11 @@ namespace System.Net.Sockets
{
throw new ArgumentNullException(nameof(buffer));
}
- if (offset < 0 || offset > buffer.Length)
+ if ((uint)offset > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(offset));
}
- if (size < 0 || size > buffer.Length - offset)
+ if ((uint)size > buffer.Length - offset)
{
throw new ArgumentOutOfRangeException(nameof(size));
}
@@ -504,7 +504,7 @@ namespace System.Net.Sockets
bool canRead = CanRead; // Prevent race with Dispose.
if (_cleanedUp)
{
- throw new ObjectDisposedException(this.GetType().FullName);
+ throw new ObjectDisposedException(GetType().FullName);
}
if (!canRead)
{
@@ -516,11 +516,11 @@ namespace System.Net.Sockets
{
throw new ArgumentNullException(nameof(buffer));
}
- if (offset < 0 || offset > buffer.Length)
+ if ((uint)offset > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(offset));
}
- if (size < 0 || size > buffer.Length - offset)
+ if ((uint)size > buffer.Length - offset)
{
throw new ArgumentOutOfRangeException(nameof(size));
}
@@ -562,7 +562,7 @@ namespace System.Net.Sockets
#endif
if (_cleanedUp)
{
- throw new ObjectDisposedException(this.GetType().FullName);
+ throw new ObjectDisposedException(GetType().FullName);
}
// Validate input parameters.
@@ -609,7 +609,7 @@ namespace System.Net.Sockets
bool canWrite = CanWrite; // Prevent race with Dispose.
if (_cleanedUp)
{
- throw new ObjectDisposedException(this.GetType().FullName);
+ throw new ObjectDisposedException(GetType().FullName);
}
if (!canWrite)
{
@@ -621,11 +621,11 @@ namespace System.Net.Sockets
{
throw new ArgumentNullException(nameof(buffer));
}
- if (offset < 0 || offset > buffer.Length)
+ if ((uint)offset > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(offset));
}
- if (size < 0 || size > buffer.Length - offset)
+ if ((uint)size > buffer.Length - offset)
{
throw new ArgumentOutOfRangeException(nameof(size));
}
@@ -664,7 +664,7 @@ namespace System.Net.Sockets
#endif
if (_cleanedUp)
{
- throw new ObjectDisposedException(this.GetType().FullName);
+ throw new ObjectDisposedException(GetType().FullName);
}
// Validate input parameters.
@@ -708,7 +708,7 @@ namespace System.Net.Sockets
bool canRead = CanRead; // Prevent race with Dispose.
if (_cleanedUp)
{
- throw new ObjectDisposedException(this.GetType().FullName);
+ throw new ObjectDisposedException(GetType().FullName);
}
if (!canRead)
{
@@ -720,26 +720,22 @@ namespace System.Net.Sockets
{
throw new ArgumentNullException(nameof(buffer));
}
- if (offset < 0 || offset > buffer.Length)
+ if ((uint)offset > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(offset));
}
- if (size < 0 || size > buffer.Length - offset)
+ if ((uint)size > buffer.Length - offset)
{
throw new ArgumentOutOfRangeException(nameof(size));
}
- if (cancellationToken.IsCancellationRequested)
- {
- return Task.FromCanceled<int>(cancellationToken);
- }
-
try
{
return _streamSocket.ReceiveAsync(
- new ArraySegment<byte>(buffer, offset, size),
+ new Memory<byte>(buffer, offset, size),
SocketFlags.None,
- fromNetworkStream: true);
+ fromNetworkStream: true,
+ cancellationToken).AsTask();
}
catch (Exception exception) when (!(exception is OutOfMemoryException))
{
@@ -749,12 +745,12 @@ namespace System.Net.Sockets
}
}
- public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken)
+ public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken)
{
bool canRead = CanRead; // Prevent race with Dispose.
if (_cleanedUp)
{
- throw new ObjectDisposedException(this.GetType().FullName);
+ throw new ObjectDisposedException(GetType().FullName);
}
if (!canRead)
{
@@ -764,7 +760,7 @@ namespace System.Net.Sockets
try
{
return _streamSocket.ReceiveAsync(
- destination,
+ buffer,
SocketFlags.None,
fromNetworkStream: true,
cancellationToken: cancellationToken);
@@ -797,7 +793,7 @@ namespace System.Net.Sockets
bool canWrite = CanWrite; // Prevent race with Dispose.
if (_cleanedUp)
{
- throw new ObjectDisposedException(this.GetType().FullName);
+ throw new ObjectDisposedException(GetType().FullName);
}
if (!canWrite)
{
@@ -809,26 +805,21 @@ namespace System.Net.Sockets
{
throw new ArgumentNullException(nameof(buffer));
}
- if (offset < 0 || offset > buffer.Length)
+ if ((uint)offset > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(offset));
}
- if (size < 0 || size > buffer.Length - offset)
+ if ((uint)size > buffer.Length - offset)
{
throw new ArgumentOutOfRangeException(nameof(size));
}
- if (cancellationToken.IsCancellationRequested)
- {
- return Task.FromCanceled(cancellationToken);
- }
-
try
{
- return _streamSocket.SendAsync(
- new ArraySegment<byte>(buffer, offset, size),
+ return _streamSocket.SendAsyncForNetworkStream(
+ new ReadOnlyMemory<byte>(buffer, offset, size),
SocketFlags.None,
- fromNetworkStream: true);
+ cancellationToken).AsTask();
}
catch (Exception exception) when (!(exception is OutOfMemoryException))
{
@@ -838,12 +829,12 @@ namespace System.Net.Sockets
}
}
- public override Task WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken)
+ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken)
{
bool canWrite = CanWrite; // Prevent race with Dispose.
if (_cleanedUp)
{
- throw new ObjectDisposedException(this.GetType().FullName);
+ throw new ObjectDisposedException(GetType().FullName);
}
if (!canWrite)
{
@@ -852,15 +843,10 @@ namespace System.Net.Sockets
try
{
- ValueTask<int> t = _streamSocket.SendAsync(
- source,
+ return _streamSocket.SendAsyncForNetworkStream(
+ buffer,
SocketFlags.None,
- fromNetworkStream: true,
cancellationToken: cancellationToken);
-
- return t.IsCompletedSuccessfully ?
- Task.CompletedTask :
- t.AsTask();
}
catch (Exception exception) when (!(exception is OutOfMemoryException))
{
@@ -870,50 +856,6 @@ namespace System.Net.Sockets
}
}
- public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
- {
- // Validate arguments as would the base CopyToAsync
- StreamHelpers.ValidateCopyToArgs(this, destination, bufferSize);
-
- // And bail early if cancellation has already been requested
- if (cancellationToken.IsCancellationRequested)
- {
- return Task.FromCanceled(cancellationToken);
- }
-
- // Do the copy. We get a copy buffer from the shared pool, and we pass both it and the
- // socket into the copy as part of the event args so as to avoid additional fields in
- // the async method's state machine.
- return CopyToAsyncCore(
- destination,
- new AwaitableSocketAsyncEventArgs(_streamSocket, ArrayPool<byte>.Shared.Rent(bufferSize)),
- cancellationToken);
- }
-
- private static async Task CopyToAsyncCore(Stream destination, AwaitableSocketAsyncEventArgs ea, CancellationToken cancellationToken)
- {
- try
- {
- while (true)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- int bytesRead = await ea.ReceiveAsync();
- if (bytesRead == 0)
- {
- break;
- }
-
- await destination.WriteAsync(ea.Buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);
- }
- }
- finally
- {
- ArrayPool<byte>.Shared.Return(ea.Buffer, clearArray: true);
- ea.Dispose();
- }
- }
-
// Flushes data from the stream. This is meaningless for us, so it does nothing.
public override void Flush()
{
@@ -959,115 +901,5 @@ namespace System.Net.Sockets
}
}
}
-
- /// <summary>A SocketAsyncEventArgs that can be awaited to get the result of an operation.</summary>
- internal sealed class AwaitableSocketAsyncEventArgs : SocketAsyncEventArgs, ICriticalNotifyCompletion
- {
- /// <summary>Sentinel object used to indicate that the operation has completed prior to OnCompleted being called.</summary>
- private static readonly Action s_completedSentinel = () => { };
- /// <summary>
- /// null if the operation has not completed, <see cref="s_completedSentinel"/> if it has, and another object
- /// if OnCompleted was called before the operation could complete, in which case it's the delegate to invoke
- /// when the operation does complete.
- /// </summary>
- private Action _continuation;
-
- /// <summary>Initializes the event args.</summary>
- /// <param name="socket">The associated socket.</param>
- /// <param name="buffer">The buffer to use for all operations.</param>
- public AwaitableSocketAsyncEventArgs(Socket socket, byte[] buffer)
- {
- Debug.Assert(socket != null);
- Debug.Assert(buffer != null && buffer.Length > 0);
-
- // Store the socket into the base's UserToken. This avoids the need for an extra field, at the expense
- // of an object=>Socket cast when we need to access it, which is only once per operation.
- UserToken = socket;
-
- // Store the buffer for use by all operations with this instance.
- SetBuffer(buffer, 0, buffer.Length);
-
- // Hook up the completed event.
- Completed += delegate
- {
- // When the operation completes, see if OnCompleted was already called to hook up a continuation.
- // If it was, invoke the continuation.
- Action c = _continuation;
- if (c != null)
- {
- c();
- }
- else
- {
- // We may be racing with OnCompleted, so check with synchronization, trying to swap in our
- // completion sentinel. If we lose the race and OnCompleted did hook up a continuation,
- // invoke it. Otherwise, there's nothing more to be done.
- Interlocked.CompareExchange(ref _continuation, s_completedSentinel, null)?.Invoke();
- }
- };
- }
-
- /// <summary>Initiates a receive operation on the associated socket.</summary>
- /// <returns>This instance.</returns>
- public AwaitableSocketAsyncEventArgs ReceiveAsync()
- {
- if (!Socket.ReceiveAsync(this))
- {
- _continuation = s_completedSentinel;
- }
- return this;
- }
-
- /// <summary>Gets this instance.</summary>
- public AwaitableSocketAsyncEventArgs GetAwaiter() => this;
-
- /// <summary>Gets whether the operation has already completed.</summary>
- /// <remarks>
- /// This is not a generically usable IsCompleted operation that suggests the whole operation has completed.
- /// Rather, it's specifically used as part of the await pattern, and is only usable to determine whether the
- /// operation has completed by the time the instance is awaited.
- /// </remarks>
- public bool IsCompleted => _continuation != null;
-
- /// <summary>Same as <see cref="OnCompleted(Action)"/> </summary>
- public void UnsafeOnCompleted(Action continuation) => OnCompleted(continuation);
-
- /// <summary>Queues the provided continuation to be executed once the operation has completed.</summary>
- public void OnCompleted(Action continuation)
- {
- if (ReferenceEquals(_continuation, s_completedSentinel) ||
- ReferenceEquals(Interlocked.CompareExchange(ref _continuation, continuation, null), s_completedSentinel))
- {
- Task.Run(continuation);
- }
- }
-
- /// <summary>Gets the result of the completion operation.</summary>
- /// <returns>Number of bytes transferred.</returns>
- /// <remarks>
- /// Unlike Task's awaiter's GetResult, this does not block until the operation completes: it must only
- /// be used once the operation has completed. This is handled implicitly by await.
- /// </remarks>
- public int GetResult()
- {
- _continuation = null;
- if (SocketError != SocketError.Success)
- {
- ThrowIOSocketException();
- }
- return BytesTransferred;
- }
-
- /// <summary>Gets the associated socket.</summary>
- internal Socket Socket => (Socket)UserToken; // stored in the base's UserToken to avoid an extra field in the object
-
- /// <summary>Throws an IOException wrapping a SocketException using the current <see cref="SocketError"/>.</summary>
- [MethodImpl(MethodImplOptions.NoInlining)]
- private void ThrowIOSocketException()
- {
- var se = new SocketException((int)SocketError);
- throw new IOException(SR.Format(SR.net_io_readfailure, se.Message), se);
- }
- }
}
}
diff --git a/src/System.Net.Sockets/src/System/Net/Sockets/Socket.Tasks.cs b/src/System.Net.Sockets/src/System/Net/Sockets/Socket.Tasks.cs
index fc796379ec..4e0b8cf521 100644
--- a/src/System.Net.Sockets/src/System/Net/Sockets/Socket.Tasks.cs
+++ b/src/System.Net.Sockets/src/System/Net/Sockets/Socket.Tasks.cs
@@ -10,6 +10,7 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
+using System.Threading.Tasks.Sources;
namespace System.Net.Sockets
{
@@ -46,12 +47,12 @@ namespace System.Net.Sockets
private static readonly Task<int> s_zeroTask = Task.FromResult(0);
/// <summary>Cached event args used with Task-based async operations.</summary>
- private CachedTaskEventArgs _cachedTaskEventArgs;
+ private CachedEventArgs _cachedTaskEventArgs;
internal Task<Socket> AcceptAsync(Socket acceptSocket)
{
// Get any cached SocketAsyncEventArg we may have.
- TaskSocketAsyncEventArgs<Socket> saea = Interlocked.Exchange(ref LazyInitializer.EnsureInitialized(ref _cachedTaskEventArgs).Accept, s_rentedSocketSentinel);
+ TaskSocketAsyncEventArgs<Socket> saea = Interlocked.Exchange(ref LazyInitializer.EnsureInitialized(ref _cachedTaskEventArgs).TaskAccept, s_rentedSocketSentinel);
if (saea == s_rentedSocketSentinel)
{
// An instance was once created (or is currently being created elsewhere), but some other
@@ -179,24 +180,13 @@ namespace System.Net.Sockets
internal Task<int> ReceiveAsync(ArraySegment<byte> buffer, SocketFlags socketFlags, bool fromNetworkStream)
{
- // Validate the arguments.
ValidateBuffer(buffer);
-
- Int32TaskSocketAsyncEventArgs saea = RentSocketAsyncEventArgs(isReceive: true);
- if (saea != null)
- {
- // We got a cached instance. Configure the buffer and initate the operation.
- ConfigureBuffer(saea, buffer, socketFlags, wrapExceptionsInIOExceptions: fromNetworkStream);
- return GetTaskForSendReceive(ReceiveAsync(saea), saea, fromNetworkStream, isReceive: true);
- }
- else
- {
- // We couldn't get a cached instance, due to a concurrent receive operation on the socket.
- // Fall back to wrapping APM.
- return ReceiveAsyncApm(buffer, socketFlags);
- }
+ return ReceiveAsync((Memory<byte>)buffer, socketFlags, fromNetworkStream, default).AsTask();
}
+ // TODO https://github.com/dotnet/corefx/issues/24430:
+ // Fully plumb cancellation down into socket operations.
+
internal ValueTask<int> ReceiveAsync(Memory<byte> buffer, SocketFlags socketFlags, bool fromNetworkStream, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
@@ -204,15 +194,14 @@ namespace System.Net.Sockets
return new ValueTask<int>(Task.FromCanceled<int>(cancellationToken));
}
- // TODO https://github.com/dotnet/corefx/issues/24430:
- // Fully plumb cancellation down into socket operations.
-
- Int32TaskSocketAsyncEventArgs saea = RentSocketAsyncEventArgs(isReceive: true);
- if (saea != null)
+ AwaitableSocketAsyncEventArgs saea = LazyInitializer.EnsureInitialized(ref LazyInitializer.EnsureInitialized(ref _cachedTaskEventArgs).ValueTaskReceive);
+ if (saea.Reserve())
{
- // We got a cached instance. Configure the buffer and initate the operation.
- ConfigureBuffer(saea, buffer, socketFlags, wrapExceptionsInIOExceptions: fromNetworkStream);
- return GetValueTaskForSendReceive(ReceiveAsync(saea), saea, fromNetworkStream, isReceive: true);
+ Debug.Assert(saea.BufferList == null);
+ saea.SetBuffer(buffer);
+ saea.SocketFlags = socketFlags;
+ saea.WrapExceptionsInIOExceptions = fromNetworkStream;
+ return saea.ReceiveAsync(this);
}
else
{
@@ -225,7 +214,7 @@ namespace System.Net.Sockets
/// <summary>Implements Task-returning ReceiveAsync on top of Begin/EndReceive.</summary>
private Task<int> ReceiveAsyncApm(Memory<byte> buffer, SocketFlags socketFlags)
{
- if (buffer.TryGetArray(out ArraySegment<byte> bufferArray))
+ if (MemoryMarshal.TryGetArray(buffer, out ArraySegment<byte> bufferArray))
{
// We were able to extract the underlying byte[] from the Memory<byte>. Use it.
var tcs = new TaskCompletionSource<int>(this);
@@ -341,48 +330,57 @@ namespace System.Net.Sockets
return tcs.Task;
}
- internal Task<int> SendAsync(ArraySegment<byte> buffer, SocketFlags socketFlags, bool fromNetworkStream)
+ internal Task<int> SendAsync(ArraySegment<byte> buffer, SocketFlags socketFlags)
{
- // Validate the arguments.
ValidateBuffer(buffer);
-
- Int32TaskSocketAsyncEventArgs saea = RentSocketAsyncEventArgs(isReceive: false);
- if (saea != null)
+ return SendAsync((ReadOnlyMemory<byte>)buffer, socketFlags, default).AsTask();
+ }
+
+ internal ValueTask<int> SendAsync(ReadOnlyMemory<byte> buffer, SocketFlags socketFlags, CancellationToken cancellationToken)
+ {
+ if (cancellationToken.IsCancellationRequested)
{
- // We got a cached instance. Configure the buffer and initate the operation.
- ConfigureBuffer(saea, buffer, socketFlags, wrapExceptionsInIOExceptions: fromNetworkStream);
- return GetTaskForSendReceive(SendAsync(saea), saea, fromNetworkStream, isReceive: false);
+ return new ValueTask<int>(Task.FromCanceled<int>(cancellationToken));
+ }
+
+ AwaitableSocketAsyncEventArgs saea = LazyInitializer.EnsureInitialized(ref LazyInitializer.EnsureInitialized(ref _cachedTaskEventArgs).ValueTaskSend);
+ if (saea.Reserve())
+ {
+ Debug.Assert(saea.BufferList == null);
+ saea.SetBuffer(MemoryMarshal.AsMemory(buffer));
+ saea.SocketFlags = socketFlags;
+ saea.WrapExceptionsInIOExceptions = false;
+ return saea.SendAsync(this);
}
else
{
// We couldn't get a cached instance, due to a concurrent send operation on the socket.
// Fall back to wrapping APM.
- return SendAsyncApm(buffer, socketFlags);
+ return new ValueTask<int>(SendAsyncApm(buffer, socketFlags));
}
}
- internal ValueTask<int> SendAsync(ReadOnlyMemory<byte> buffer, SocketFlags socketFlags, bool fromNetworkStream, CancellationToken cancellationToken)
+ internal ValueTask SendAsyncForNetworkStream(ReadOnlyMemory<byte> buffer, SocketFlags socketFlags, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
- return new ValueTask<int>(Task.FromCanceled<int>(cancellationToken));
+ return new ValueTask(Task.FromCanceled(cancellationToken));
}
- // TODO https://github.com/dotnet/corefx/issues/24430:
- // Fully plumb cancellation down into socket operations.
-
- Int32TaskSocketAsyncEventArgs saea = RentSocketAsyncEventArgs(isReceive: false);
- if (saea != null)
+ AwaitableSocketAsyncEventArgs saea = LazyInitializer.EnsureInitialized(ref LazyInitializer.EnsureInitialized(ref _cachedTaskEventArgs).ValueTaskSend);
+ if (saea.Reserve())
{
- // We got a cached instance. Configure the buffer and initate the operation.
- ConfigureBuffer(saea, MemoryMarshal.AsMemory<byte>(buffer), socketFlags, wrapExceptionsInIOExceptions: fromNetworkStream);
- return GetValueTaskForSendReceive(SendAsync(saea), saea, fromNetworkStream, isReceive: false);
+ Debug.Assert(saea.BufferList == null);
+ saea.SetBuffer(MemoryMarshal.AsMemory(buffer));
+ saea.SocketFlags = socketFlags;
+ saea.WrapExceptionsInIOExceptions = true;
+ return saea.SendAsyncForNetworkStream(this);
}
else
{
// We couldn't get a cached instance, due to a concurrent send operation on the socket.
// Fall back to wrapping APM.
- return new ValueTask<int>(SendAsyncApm(buffer, socketFlags));
+ return new ValueTask(SendAsyncApm(buffer, socketFlags));
}
}
@@ -502,19 +500,6 @@ namespace System.Net.Sockets
}
}
- private static void ConfigureBuffer(
- Int32TaskSocketAsyncEventArgs saea, Memory<byte> buffer, SocketFlags socketFlags, bool wrapExceptionsInIOExceptions)
- {
- // Configure the buffer. We don't clear the buffers when returning the SAEA to the pool,
- // so as to minimize overhead if the same buffer is used for subsequent operations (which is likely).
- // But SAEA doesn't support having both a buffer and a buffer list configured, so clear out a buffer list
- // if there is one before we set the desired buffer.
- if (saea.BufferList != null) saea.BufferList = null;
- saea.SetBuffer(buffer);
- saea.SocketFlags = socketFlags;
- saea._wrapExceptionsInIOExceptions = wrapExceptionsInIOExceptions;
- }
-
private static void ConfigureBufferList(
Int32TaskSocketAsyncEventArgs saea, IList<ArraySegment<byte>> buffers, SocketFlags socketFlags)
{
@@ -572,16 +557,8 @@ namespace System.Net.Sockets
}
else
{
- // Get any cached, successfully-completed cached task that may exist on this SAEA.
- Task<int> lastTask = saea._successfullyCompletedTask;
- Debug.Assert(lastTask == null || lastTask.IsCompletedSuccessfully);
-
- // If there is a task and if it has the desired result, simply reuse it.
- // Otherwise, create a new one for this result value, and in addition to returning it,
- // also store it into the SAEA for potential future reuse.
- t = lastTask != null && lastTask.Result == bytesTransferred ?
- lastTask :
- (saea._successfullyCompletedTask = Task.FromResult(bytesTransferred));
+ // Otherwise, create a new task for this result value.
+ t = Task.FromResult(bytesTransferred);
}
}
else
@@ -596,48 +573,6 @@ namespace System.Net.Sockets
return t;
}
- /// <summary>Gets a value task to represent the operation.</summary>
- /// <param name="pending">true if the operation completes asynchronously; false if it completed synchronously.</param>
- /// <param name="saea">The event args instance used with the operation.</param>
- /// <param name="fromNetworkStream">
- /// true if the request is coming from NetworkStream, which has special semantics for
- /// exceptions and cached tasks; otherwise, false.
- /// </param>
- /// <param name="isReceive">true if this is a receive; false if this is a send.</param>
- private ValueTask<int> GetValueTaskForSendReceive(
- bool pending, Int32TaskSocketAsyncEventArgs saea,
- bool fromNetworkStream, bool isReceive)
- {
- ValueTask<int> t;
-
- if (pending)
- {
- // The operation is completing asynchronously (it may have already completed).
- // Get the task for the operation, with appropriate synchronization to coordinate
- // with the async callback that'll be completing the task.
- bool responsibleForReturningToPool;
- t = new ValueTask<int>(saea.GetCompletionResponsibility(out responsibleForReturningToPool).Task);
- if (responsibleForReturningToPool)
- {
- // We're responsible for returning it only if the callback has already been invoked
- // and gotten what it needs from the SAEA; otherwise, the callback will return it.
- ReturnSocketAsyncEventArgs(saea, isReceive);
- }
- }
- else
- {
- // The operation completed synchronously. Return a ValueTask for it.
- t = saea.SocketError == SocketError.Success ?
- new ValueTask<int>(saea.BytesTransferred) :
- new ValueTask<int>(Task.FromException<int>(GetException(saea.SocketError, wrapExceptionsInIOExceptions: fromNetworkStream)));
-
- // There won't be a callback, and we're done with the SAEA, so return it to the pool.
- ReturnSocketAsyncEventArgs(saea, isReceive);
- }
-
- return t;
- }
-
/// <summary>Completes the SocketAsyncEventArg's Task with the result of the send or receive, and returns it to the specified pool.</summary>
private static void CompleteAccept(Socket s, TaskSocketAsyncEventArgs<Socket> saea)
{
@@ -709,10 +644,10 @@ namespace System.Net.Sockets
private Int32TaskSocketAsyncEventArgs RentSocketAsyncEventArgs(bool isReceive)
{
// Get any cached SocketAsyncEventArg we may have.
- CachedTaskEventArgs cea = LazyInitializer.EnsureInitialized(ref _cachedTaskEventArgs);
+ CachedEventArgs cea = LazyInitializer.EnsureInitialized(ref _cachedTaskEventArgs);
Int32TaskSocketAsyncEventArgs saea = isReceive ?
- Interlocked.Exchange(ref cea.Receive, s_rentedInt32Sentinel) :
- Interlocked.Exchange(ref cea.Send, s_rentedInt32Sentinel);
+ Interlocked.Exchange(ref cea.TaskReceive, s_rentedInt32Sentinel) :
+ Interlocked.Exchange(ref cea.TaskSend, s_rentedInt32Sentinel);
if (saea == s_rentedInt32Sentinel)
{
@@ -752,13 +687,13 @@ namespace System.Net.Sockets
// never null or another instance.
if (isReceive)
{
- Debug.Assert(_cachedTaskEventArgs.Receive == s_rentedInt32Sentinel);
- Volatile.Write(ref _cachedTaskEventArgs.Receive, saea);
+ Debug.Assert(_cachedTaskEventArgs.TaskReceive == s_rentedInt32Sentinel);
+ Volatile.Write(ref _cachedTaskEventArgs.TaskReceive, saea);
}
else
{
- Debug.Assert(_cachedTaskEventArgs.Send == s_rentedInt32Sentinel);
- Volatile.Write(ref _cachedTaskEventArgs.Send, saea);
+ Debug.Assert(_cachedTaskEventArgs.TaskSend == s_rentedInt32Sentinel);
+ Volatile.Write(ref _cachedTaskEventArgs.TaskSend, saea);
}
}
@@ -779,19 +714,21 @@ namespace System.Net.Sockets
// Write this instance back as a cached instance. It should only ever be overwriting the sentinel,
// never null or another instance.
- Debug.Assert(_cachedTaskEventArgs.Accept == s_rentedSocketSentinel);
- Volatile.Write(ref _cachedTaskEventArgs.Accept, saea);
+ Debug.Assert(_cachedTaskEventArgs.TaskAccept == s_rentedSocketSentinel);
+ Volatile.Write(ref _cachedTaskEventArgs.TaskAccept, saea);
}
/// <summary>Dispose of any cached <see cref="Int32TaskSocketAsyncEventArgs"/> instances.</summary>
private void DisposeCachedTaskSocketAsyncEventArgs()
{
- CachedTaskEventArgs cea = _cachedTaskEventArgs;
+ CachedEventArgs cea = _cachedTaskEventArgs;
if (cea != null)
{
- Interlocked.Exchange(ref cea.Accept, s_rentedSocketSentinel)?.Dispose();
- Interlocked.Exchange(ref cea.Receive, s_rentedInt32Sentinel)?.Dispose();
- Interlocked.Exchange(ref cea.Send, s_rentedInt32Sentinel)?.Dispose();
+ Interlocked.Exchange(ref cea.TaskAccept, s_rentedSocketSentinel)?.Dispose();
+ Interlocked.Exchange(ref cea.TaskReceive, s_rentedInt32Sentinel)?.Dispose();
+ Interlocked.Exchange(ref cea.TaskSend, s_rentedInt32Sentinel)?.Dispose();
+ Interlocked.Exchange(ref cea.ValueTaskReceive, AwaitableSocketAsyncEventArgs.Reserved)?.Dispose();
+ Interlocked.Exchange(ref cea.ValueTaskSend, AwaitableSocketAsyncEventArgs.Reserved)?.Dispose();
}
}
@@ -810,14 +747,18 @@ namespace System.Net.Sockets
}
/// <summary>Cached event args used with Task-based async operations.</summary>
- private sealed class CachedTaskEventArgs
+ private sealed class CachedEventArgs
{
/// <summary>Cached instance for accept operations.</summary>
- public TaskSocketAsyncEventArgs<Socket> Accept;
- /// <summary>Cached instance for receive operations.</summary>
- public Int32TaskSocketAsyncEventArgs Receive;
- /// <summary>Cached instance for send operations.</summary>
- public Int32TaskSocketAsyncEventArgs Send;
+ public TaskSocketAsyncEventArgs<Socket> TaskAccept;
+ /// <summary>Cached instance for receive operations that return <see cref="Task{Int32}"/>.</summary>
+ public Int32TaskSocketAsyncEventArgs TaskReceive;
+ /// <summary>Cached instance for send operations that return <see cref="Task{Int32}"/>.</summary>
+ public Int32TaskSocketAsyncEventArgs TaskSend;
+ /// <summary>Cached instance for receive operations that return <see cref="ValueTask{Int32}"/>.</summary>
+ public AwaitableSocketAsyncEventArgs ValueTaskReceive;
+ /// <summary>Cached instance for send operations that return <see cref="ValueTask{Int32}"/>.</summary>
+ public AwaitableSocketAsyncEventArgs ValueTaskSend;
}
/// <summary>A SocketAsyncEventArgs with an associated async method builder.</summary>
@@ -838,6 +779,11 @@ namespace System.Net.Sockets
/// </summary>
internal bool _accessed = false;
+ internal TaskSocketAsyncEventArgs() :
+ base(flowExecutionContext: false) // avoid flowing context at lower layers as we only expose Task, which handles it
+ {
+ }
+
/// <summary>Gets the builder's task with appropriate synchronization.</summary>
internal AsyncTaskMethodBuilder<TResult> GetCompletionResponsibility(out bool responsibleForReturningToPool)
{
@@ -854,10 +800,300 @@ namespace System.Net.Sockets
/// <summary>A SocketAsyncEventArgs with an associated async method builder.</summary>
private sealed class Int32TaskSocketAsyncEventArgs : TaskSocketAsyncEventArgs<int>
{
- /// <summary>A cached, successfully completed task.</summary>
- internal Task<int> _successfullyCompletedTask;
/// <summary>Whether exceptions that emerge should be wrapped in IOExceptions.</summary>
internal bool _wrapExceptionsInIOExceptions;
}
+
+ /// <summary>A SocketAsyncEventArgs that can be awaited to get the result of an operation.</summary>
+ internal sealed class AwaitableSocketAsyncEventArgs : SocketAsyncEventArgs, IValueTaskSource, IValueTaskSource<int>
+ {
+ internal static readonly AwaitableSocketAsyncEventArgs Reserved = new AwaitableSocketAsyncEventArgs() { _continuation = null };
+ /// <summary>Sentinel object used to indicate that the operation has completed prior to OnCompleted being called.</summary>
+ private static readonly Action<object> s_completedSentinel = new Action<object>(state => throw new Exception(nameof(s_completedSentinel)));
+ /// <summary>Sentinel object used to indicate that the instance is available for use.</summary>
+ private static readonly Action<object> s_availableSentinel = new Action<object>(state => throw new Exception(nameof(s_availableSentinel)));
+ /// <summary>
+ /// <see cref="s_availableSentinel"/> if the object is available for use, after GetResult has been called on a previous use.
+ /// null if the operation has not completed.
+ /// <see cref="s_completedSentinel"/> if it has completed.
+ /// Another delegate if OnCompleted was called before the operation could complete, in which case it's the delegate to invoke
+ /// when the operation does complete.
+ /// </summary>
+ private Action<object> _continuation = s_availableSentinel;
+ private ExecutionContext _executionContext;
+ private object _scheduler;
+ /// <summary>Current token value given to a ValueTask and then verified against the value it passes back to us.</summary>
+ /// <remarks>
+ /// This is not meant to be a completely reliable mechanism, doesn't require additional synchronization, etc.
+ /// It's purely a best effort attempt to catch misuse, including awaiting for a value task twice and after
+ /// it's already being reused by someone else.
+ /// </remarks>
+ private short _token;
+
+ /// <summary>Initializes the event args.</summary>
+ /// <param name="socket">The associated socket.</param>
+ /// <param name="buffer">The buffer to use for all operations.</param>
+ public AwaitableSocketAsyncEventArgs() :
+ base(flowExecutionContext: false) // avoid flowing context at lower layers as we only expose ValueTask, which handles it
+ {
+ }
+
+ public bool WrapExceptionsInIOExceptions { get; set; }
+
+ public bool Reserve() =>
+ ReferenceEquals(Interlocked.CompareExchange(ref _continuation, null, s_availableSentinel), s_availableSentinel);
+
+ private void Release()
+ {
+ _token++;
+ Volatile.Write(ref _continuation, s_availableSentinel);
+ }
+
+ protected override void OnCompleted(SocketAsyncEventArgs _)
+ {
+ // When the operation completes, see if OnCompleted was already called to hook up a continuation.
+ // If it was, invoke the continuation.
+ Action<object> c = _continuation;
+ if (c != null || (c = Interlocked.CompareExchange(ref _continuation, s_completedSentinel, null)) != null)
+ {
+ Debug.Assert(c != s_availableSentinel, "The delegate should not have been the available sentinel.");
+ Debug.Assert(c != s_completedSentinel, "The delegate should not have been the completed sentinel.");
+
+ object continuationState = UserToken;
+ UserToken = null;
+ _continuation = s_completedSentinel; // in case someone's polling IsCompleted
+
+ ExecutionContext ec = _executionContext;
+ if (ec == null)
+ {
+ InvokeContinuation(c, continuationState, forceAsync: false);
+ }
+ else
+ {
+ // This case should be relatively rare, as the async Task/ValueTask method builders
+ // use the awaiter's UnsafeOnCompleted, so this will only happen with code that
+ // explicitly uses the awaiter's OnCompleted instead.
+ _executionContext = null;
+ ExecutionContext.Run(ec, runState =>
+ {
+ var t = (Tuple<AwaitableSocketAsyncEventArgs, Action<object>, object>)runState;
+ t.Item1.InvokeContinuation(t.Item2, t.Item3, forceAsync: false);
+ }, Tuple.Create(this, c, continuationState));
+ }
+ }
+ }
+
+ /// <summary>Initiates a receive operation on the associated socket.</summary>
+ /// <returns>This instance.</returns>
+ public ValueTask<int> ReceiveAsync(Socket socket)
+ {
+ Debug.Assert(Volatile.Read(ref _continuation) == null, $"Expected null continuation to indicate reserved for use");
+
+ if (socket.ReceiveAsync(this))
+ {
+ return new ValueTask<int>(this, _token);
+ }
+
+ int bytesTransferred = BytesTransferred;
+ SocketError error = SocketError;
+
+ Release();
+
+ return error == SocketError.Success ?
+ new ValueTask<int>(bytesTransferred) :
+ new ValueTask<int>(Task.FromException<int>(CreateException(error)));
+ }
+
+ /// <summary>Initiates a send operation on the associated socket.</summary>
+ /// <returns>This instance.</returns>
+ public ValueTask<int> SendAsync(Socket socket)
+ {
+ Debug.Assert(Volatile.Read(ref _continuation) == null, $"Expected null continuation to indicate reserved for use");
+
+ if (socket.SendAsync(this))
+ {
+ return new ValueTask<int>(this, _token);
+ }
+
+ int bytesTransferred = BytesTransferred;
+ SocketError error = SocketError;
+
+ Release();
+
+ return error == SocketError.Success ?
+ new ValueTask<int>(bytesTransferred) :
+ new ValueTask<int>(Task.FromException<int>(CreateException(error)));
+ }
+
+ public ValueTask SendAsyncForNetworkStream(Socket socket)
+ {
+ Debug.Assert(Volatile.Read(ref _continuation) == null, $"Expected null continuation to indicate reserved for use");
+
+ if (socket.SendAsync(this))
+ {
+ return new ValueTask(this, _token);
+ }
+
+ SocketError error = SocketError;
+
+ Release();
+
+ return error == SocketError.Success ?
+ default :
+ new ValueTask(Task.FromException(CreateException(error)));
+ }
+
+ /// <summary>Gets the status of the operation.</summary>
+ public ValueTaskSourceStatus GetStatus(short token)
+ {
+ if (token != _token)
+ {
+ ThrowIncorrectTokenException();
+ }
+
+ return
+ !ReferenceEquals(_continuation, s_completedSentinel) ? ValueTaskSourceStatus.Pending :
+ base.SocketError == SocketError.Success ? ValueTaskSourceStatus.Succeeded :
+ ValueTaskSourceStatus.Faulted;
+ }
+
+ /// <summary>Queues the provided continuation to be executed once the operation has completed.</summary>
+ public void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags)
+ {
+ if (token != _token)
+ {
+ ThrowIncorrectTokenException();
+ }
+
+ if ((flags & ValueTaskSourceOnCompletedFlags.FlowExecutionContext) != 0)
+ {
+ _executionContext = ExecutionContext.Capture();
+ }
+
+ if ((flags & ValueTaskSourceOnCompletedFlags.UseSchedulingContext) != 0)
+ {
+ SynchronizationContext sc = SynchronizationContext.Current;
+ if (sc != null && sc.GetType() != typeof(SynchronizationContext))
+ {
+ _scheduler = sc;
+ }
+ else
+ {
+ TaskScheduler ts = TaskScheduler.Current;
+ if (ts != TaskScheduler.Default)
+ {
+ _scheduler = ts;
+ }
+ }
+ }
+
+ UserToken = state; // Use UserToken to carry the continuation state around
+ Action<object> prevContinuation = Interlocked.CompareExchange(ref _continuation, continuation, null);
+ if (ReferenceEquals(prevContinuation, s_completedSentinel))
+ {
+ // Lost the race condition and the operation has now already completed.
+ // We need to invoke the continuation, but it must be asynchronously to
+ // avoid a stack dive. However, since all of the queueing mechanisms flow
+ // ExecutionContext, and since we're still in the same context where we
+ // captured it, we can just ignore the one we captured.
+ _executionContext = null;
+ UserToken = null; // we have the state in "state"; no need for the one in UserToken
+ InvokeContinuation(continuation, state, forceAsync: true);
+ }
+ else if (prevContinuation != null)
+ {
+ // Flag errors with the continuation being hooked up multiple times.
+ // This is purely to help alert a developer to a bug they need to fix.
+ ThrowMultipleContinuationsException();
+ }
+ }
+
+ private void InvokeContinuation(Action<object> continuation, object state, bool forceAsync)
+ {
+ object scheduler = _scheduler;
+ _scheduler = null;
+
+ if (scheduler != null)
+ {
+ if (scheduler is SynchronizationContext sc)
+ {
+ sc.Post(s =>
+ {
+ var t = (Tuple<Action<object>, object>)s;
+ t.Item1(t.Item2);
+ }, Tuple.Create(continuation, state));
+ }
+ else
+ {
+ Debug.Assert(scheduler is TaskScheduler, $"Expected TaskScheduler, got {scheduler}");
+ Task.Factory.StartNew(continuation, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, (TaskScheduler)scheduler);
+ }
+ }
+ else if (forceAsync)
+ {
+ ThreadPool.QueueUserWorkItem(continuation, state, preferLocal: true);
+ }
+ else
+ {
+ continuation(state);
+ }
+ }
+
+ /// <summary>Gets the result of the completion operation.</summary>
+ /// <returns>Number of bytes transferred.</returns>
+ /// <remarks>
+ /// Unlike TaskAwaiter's GetResult, this does not block until the operation completes: it must only
+ /// be used once the operation has completed. This is handled implicitly by await.
+ /// </remarks>
+ public int GetResult(short token)
+ {
+ if (token != _token)
+ {
+ ThrowIncorrectTokenException();
+ }
+
+ SocketError error = SocketError;
+ int bytes = BytesTransferred;
+
+ Release();
+
+ if (error != SocketError.Success)
+ {
+ ThrowException(error);
+ }
+ return bytes;
+ }
+
+ void IValueTaskSource.GetResult(short token)
+ {
+ if (token != _token)
+ {
+ ThrowIncorrectTokenException();
+ }
+
+ SocketError error = SocketError;
+
+ Release();
+
+ if (error != SocketError.Success)
+ {
+ ThrowException(error);
+ }
+ }
+
+ private void ThrowIncorrectTokenException() => throw new InvalidOperationException(SR.InvalidOperation_IncorrectToken);
+
+ private void ThrowMultipleContinuationsException() => throw new InvalidOperationException(SR.InvalidOperation_MultipleContinuations);
+
+ private void ThrowException(SocketError error) => throw CreateException(error);
+
+ private Exception CreateException(SocketError error)
+ {
+ var se = new SocketException((int)error);
+ return WrapExceptionsInIOExceptions ? (Exception)
+ new IOException(SR.Format(SR.net_io_readfailure, se.Message), se) :
+ se;
+ }
+ }
}
}
diff --git a/src/System.Net.Sockets/src/System/Net/Sockets/Socket.Windows.cs b/src/System.Net.Sockets/src/System/Net/Sockets/Socket.Windows.cs
index 897bebb851..0c7eeb8fe3 100644
--- a/src/System.Net.Sockets/src/System/Net/Sockets/Socket.Windows.cs
+++ b/src/System.Net.Sockets/src/System/Net/Sockets/Socket.Windows.cs
@@ -5,8 +5,7 @@
using Microsoft.Win32.SafeHandles;
using System.Collections;
using System.IO;
-using System.Runtime.ExceptionServices;
-using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
using System.Threading;
namespace System.Net.Sockets
@@ -285,10 +284,14 @@ namespace System.Net.Sockets
}
- internal ThreadPoolBoundHandle GetOrAllocateThreadPoolBoundHandle()
+ internal ThreadPoolBoundHandle GetOrAllocateThreadPoolBoundHandle() =>
+ _handle.GetThreadPoolBoundHandle() ??
+ GetOrAllocateThreadPoolBoundHandleSlow();
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal ThreadPoolBoundHandle GetOrAllocateThreadPoolBoundHandleSlow()
{
- // There is a known bug that exists through Windows 7 with UDP and
- // SetFileCompletionNotificationModes.
+ // There is a known bug that exists through Windows 7 with UDP and SetFileCompletionNotificationModes.
// So, don't try to enable skipping the completion port on success in this case.
bool trySkipCompletionPortOnSuccess = !(CompletionPortHelper.PlatformHasUdpIssue && _protocolType == ProtocolType.Udp);
return _handle.GetOrAllocateThreadPoolBoundHandle(trySkipCompletionPortOnSuccess);
diff --git a/src/System.Net.Sockets/src/System/Net/Sockets/Socket.cs b/src/System.Net.Sockets/src/System/Net/Sockets/Socket.cs
index 10bd970a50..fa85ae8d57 100644
--- a/src/System.Net.Sockets/src/System/Net/Sockets/Socket.cs
+++ b/src/System.Net.Sockets/src/System/Net/Sockets/Socket.cs
@@ -72,9 +72,12 @@ namespace System.Net.Sockets
#region Constructors
public Socket(SocketType socketType, ProtocolType protocolType)
- : this(AddressFamily.InterNetworkV6, socketType, protocolType)
+ : this(OSSupportsIPv6 ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork, socketType, protocolType)
{
- DualMode = true;
+ if (OSSupportsIPv6)
+ {
+ DualMode = true;
+ }
}
// Initializes a new instance of the Sockets.Socket class.
@@ -789,6 +792,11 @@ namespace System.Net.Sockets
throw new InvalidOperationException(SR.net_sockets_mustnotlisten);
}
+ if (_isConnected)
+ {
+ throw new SocketException((int)SocketError.IsConnected);
+ }
+
ValidateBlockingMode();
if (NetEventSource.IsEnabled)
@@ -842,6 +850,11 @@ namespace System.Net.Sockets
throw new ArgumentOutOfRangeException(nameof(port));
}
+ if (_isConnected)
+ {
+ throw new SocketException((int)SocketError.IsConnected);
+ }
+
ValidateForMultiConnect(isMultiEndpoint: false); // needs to come before CanTryAddressFamily call
if (!CanTryAddressFamily(address.AddressFamily))
@@ -917,6 +930,11 @@ namespace System.Net.Sockets
throw new NotSupportedException(SR.net_invalidversion);
}
+ if (_isConnected)
+ {
+ throw new SocketException((int)SocketError.IsConnected);
+ }
+
ValidateForMultiConnect(isMultiEndpoint: true); // needs to come before CanTryAddressFamily call
ExceptionDispatchInfo lastex = null;
@@ -2074,6 +2092,11 @@ namespace System.Net.Sockets
throw new InvalidOperationException(SR.net_sockets_mustnotlisten);
}
+ if (_isConnected)
+ {
+ throw new SocketException((int)SocketError.IsConnected);
+ }
+
DnsEndPoint dnsEP = remoteEP as DnsEndPoint;
if (dnsEP != null)
@@ -2154,6 +2177,11 @@ namespace System.Net.Sockets
throw new InvalidOperationException(SR.net_sockets_mustnotlisten);
}
+ if (_isConnected)
+ {
+ throw new SocketException((int)SocketError.IsConnected);
+ }
+
IPAddress parsedAddress;
if (IPAddress.TryParse(host, out parsedAddress))
{
@@ -2201,6 +2229,11 @@ namespace System.Net.Sockets
throw new ArgumentOutOfRangeException(nameof(port));
}
+ if (_isConnected)
+ {
+ throw new SocketException((int)SocketError.IsConnected);
+ }
+
ValidateForMultiConnect(isMultiEndpoint: false); // needs to be called before CanTryAddressFamily
if (!CanTryAddressFamily(address.AddressFamily))
@@ -2243,6 +2276,11 @@ namespace System.Net.Sockets
throw new InvalidOperationException(SR.net_sockets_mustnotlisten);
}
+ if (_isConnected)
+ {
+ throw new SocketException((int)SocketError.IsConnected);
+ }
+
ValidateForMultiConnect(isMultiEndpoint: true);
// Set up the result to capture the context. No need for a lock.
@@ -3804,6 +3842,11 @@ namespace System.Net.Sockets
throw new InvalidOperationException(SR.net_sockets_mustnotlisten);
}
+ if (_isConnected)
+ {
+ throw new SocketException((int)SocketError.IsConnected);
+ }
+
// Prepare SocketAddress.
EndPoint endPointSnapshot = e.RemoteEndPoint;
DnsEndPoint dnsEP = endPointSnapshot as DnsEndPoint;
@@ -4333,14 +4376,16 @@ namespace System.Net.Sockets
{
if (!s_initialized)
{
+ InitializeSocketsCore();
+ }
+
+ void InitializeSocketsCore()
+ {
lock (InternalSyncObject)
{
if (!s_initialized)
{
SocketPal.Initialize();
-
- // Cache some settings locally.
- // s_perfCountersEnabled = SocketPerfCounter.Instance.Enabled; // TODO (#7833): Implement socket perf counters.
s_initialized = true;
}
}
diff --git a/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Unix.cs b/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Unix.cs
index 2321c9c297..6320ac5d40 100644
--- a/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Unix.cs
+++ b/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Unix.cs
@@ -208,11 +208,6 @@ namespace System.Net.Sockets
Volatile.Write(ref _state, (int)State.Waiting);
}
- public void DoCallback()
- {
- InvokeCallback();
- }
-
public bool TryCancel()
{
Trace("Enter");
@@ -267,8 +262,11 @@ namespace System.Net.Sockets
#if DEBUG
Debug.Assert(Interlocked.CompareExchange(ref _callbackQueued, 1, 0) == 0, $"Unexpected _callbackQueued: {_callbackQueued}");
#endif
-
- ThreadPool.QueueUserWorkItem(o => ((AsyncOperation)o).InvokeCallback(), this);
+ // We've marked the operation as canceled, and so should invoke the callback, but
+ // we can't pool the object, as ProcessQueue may still have a reference to it, due to
+ // using a pattern whereby it takes the lock to grab an item, but then releases the lock
+ // to do further processing on the item that's still in the list.
+ ThreadPool.QueueUserWorkItem(o => ((AsyncOperation)o).InvokeCallback(allowPooling: false), this);
}
Trace("Exit");
@@ -289,7 +287,7 @@ namespace System.Net.Sockets
protected abstract bool DoTryComplete(SocketAsyncContext context);
- protected abstract void InvokeCallback();
+ public abstract void InvokeCallback(bool allowPooling);
[Conditional("SOCKETASYNCCONTEXT_TRACE")]
public void Trace(string message, [CallerMemberName] string memberName = null)
@@ -332,7 +330,7 @@ namespace System.Net.Sockets
set => CallbackOrEvent = value;
}
- protected override void InvokeCallback() =>
+ public override void InvokeCallback(bool allowPooling) =>
((Action<int, byte[], int, SocketFlags, SocketError>)CallbackOrEvent)(BytesTransferred, SocketAddress, SocketAddressLen, SocketFlags.None, ErrorCode);
}
@@ -348,7 +346,7 @@ namespace System.Net.Sockets
return SocketPal.TryCompleteSendTo(context._socket, Buffer.Span, null, ref bufferIndex, ref Offset, ref Count, Flags, SocketAddress, SocketAddressLen, ref BytesTransferred, out ErrorCode);
}
- protected override void InvokeCallback()
+ public override void InvokeCallback(bool allowPooling)
{
var cb = (Action<int, byte[], int, SocketFlags, SocketError>)CallbackOrEvent;
int bt = BytesTransferred;
@@ -356,7 +354,10 @@ namespace System.Net.Sockets
int sal = SocketAddressLen;
SocketError ec = ErrorCode;
- AssociatedContext.ReturnOperation(this);
+ if (allowPooling)
+ {
+ AssociatedContext.ReturnOperation(this);
+ }
cb(bt, sa, sal, SocketFlags.None, ec);
}
@@ -374,7 +375,7 @@ namespace System.Net.Sockets
return SocketPal.TryCompleteSendTo(context._socket, default(ReadOnlySpan<byte>), Buffers, ref BufferIndex, ref Offset, ref Count, Flags, SocketAddress, SocketAddressLen, ref BytesTransferred, out ErrorCode);
}
- protected override void InvokeCallback()
+ public override void InvokeCallback(bool allowPooling)
{
var cb = (Action<int, byte[], int, SocketFlags, SocketError>)CallbackOrEvent;
int bt = BytesTransferred;
@@ -382,7 +383,10 @@ namespace System.Net.Sockets
int sal = SocketAddressLen;
SocketError ec = ErrorCode;
- AssociatedContext.ReturnOperation(this);
+ if (allowPooling)
+ {
+ AssociatedContext.ReturnOperation(this);
+ }
cb(bt, sa, sal, SocketFlags.None, ec);
}
@@ -416,7 +420,7 @@ namespace System.Net.Sockets
set => CallbackOrEvent = value;
}
- protected override void InvokeCallback() =>
+ public override void InvokeCallback(bool allowPooling) =>
((Action<int, byte[], int, SocketFlags, SocketError>)CallbackOrEvent)(
BytesTransferred, SocketAddress, SocketAddressLen, ReceivedFlags, ErrorCode);
}
@@ -427,10 +431,24 @@ namespace System.Net.Sockets
public BufferMemoryReceiveOperation(SocketAsyncContext context) : base(context) { }
- protected override bool DoTryComplete(SocketAsyncContext context) =>
- SocketPal.TryCompleteReceiveFrom(context._socket, Buffer.Span, null, Flags, SocketAddress, ref SocketAddressLen, out BytesTransferred, out ReceivedFlags, out ErrorCode);
+ protected override bool DoTryComplete(SocketAsyncContext context)
+ {
+ // Zero byte read is performed to know when data is available.
+ // We don't have to call receive, our caller is interested in the event.
+ if (Buffer.Length == 0 && Flags == SocketFlags.None && SocketAddress == null)
+ {
+ BytesTransferred = 0;
+ ReceivedFlags = SocketFlags.None;
+ ErrorCode = SocketError.Success;
+ return true;
+ }
+ else
+ {
+ return SocketPal.TryCompleteReceiveFrom(context._socket, Buffer.Span, null, Flags, SocketAddress, ref SocketAddressLen, out BytesTransferred, out ReceivedFlags, out ErrorCode);
+ }
+ }
- protected override void InvokeCallback()
+ public override void InvokeCallback(bool allowPooling)
{
var cb = (Action<int, byte[], int, SocketFlags, SocketError>)CallbackOrEvent;
int bt = BytesTransferred;
@@ -439,7 +457,10 @@ namespace System.Net.Sockets
SocketFlags rf = ReceivedFlags;
SocketError ec = ErrorCode;
- AssociatedContext.ReturnOperation(this);
+ if (allowPooling)
+ {
+ AssociatedContext.ReturnOperation(this);
+ }
cb(bt, sa, sal, rf, ec);
}
@@ -454,7 +475,7 @@ namespace System.Net.Sockets
protected override bool DoTryComplete(SocketAsyncContext context) =>
SocketPal.TryCompleteReceiveFrom(context._socket, default(Span<byte>), Buffers, Flags, SocketAddress, ref SocketAddressLen, out BytesTransferred, out ReceivedFlags, out ErrorCode);
- protected override void InvokeCallback()
+ public override void InvokeCallback(bool allowPooling)
{
var cb = (Action<int, byte[], int, SocketFlags, SocketError>)CallbackOrEvent;
int bt = BytesTransferred;
@@ -463,7 +484,10 @@ namespace System.Net.Sockets
SocketFlags rf = ReceivedFlags;
SocketError ec = ErrorCode;
- AssociatedContext.ReturnOperation(this);
+ if (allowPooling)
+ {
+ AssociatedContext.ReturnOperation(this);
+ }
cb(bt, sa, sal, rf, ec);
}
@@ -504,7 +528,7 @@ namespace System.Net.Sockets
protected override bool DoTryComplete(SocketAsyncContext context) =>
SocketPal.TryCompleteReceiveMessageFrom(context._socket, Buffer.Span, Buffers, Flags, SocketAddress, ref SocketAddressLen, IsIPv4, IsIPv6, out BytesTransferred, out ReceivedFlags, out IPPacketInformation, out ErrorCode);
- protected override void InvokeCallback() =>
+ public override void InvokeCallback(bool allowPooling) =>
((Action<int, byte[], int, SocketFlags, IPPacketInformation, SocketError>)CallbackOrEvent)(
BytesTransferred, SocketAddress, SocketAddressLen, ReceivedFlags, IPPacketInformation, ErrorCode);
}
@@ -530,7 +554,7 @@ namespace System.Net.Sockets
return completed;
}
- protected override void InvokeCallback()
+ public override void InvokeCallback(bool allowPooling)
{
var cb = (Action<IntPtr, byte[], int, SocketError>)CallbackOrEvent;
IntPtr fd = AcceptedFileDescriptor;
@@ -538,7 +562,10 @@ namespace System.Net.Sockets
int sal = SocketAddressLen;
SocketError ec = ErrorCode;
- AssociatedContext.ReturnOperation(this);
+ if (allowPooling)
+ {
+ AssociatedContext.ReturnOperation(this);
+ }
cb(fd, sa, sal, ec);
}
@@ -562,7 +589,7 @@ namespace System.Net.Sockets
return result;
}
- protected override void InvokeCallback() =>
+ public override void InvokeCallback(bool allowPooling) =>
((Action<SocketError>)CallbackOrEvent)(ErrorCode);
}
@@ -582,7 +609,7 @@ namespace System.Net.Sockets
set => CallbackOrEvent = value;
}
- protected override void InvokeCallback() =>
+ public override void InvokeCallback(bool allowPooling) =>
((Action<long, SocketError>)CallbackOrEvent)(BytesTransferred, ErrorCode);
protected override bool DoTryComplete(SocketAsyncContext context) =>
@@ -944,7 +971,10 @@ namespace System.Net.Sockets
ThreadPool.QueueUserWorkItem(s_processingCallback, context);
}
- op.DoCallback();
+ // At this point, the operation has completed and it's no longer
+ // in the queue / no one else has a reference to it. We can invoke
+ // the callback and let it pool the object if appropriate.
+ op.InvokeCallback(allowPooling: true);
}
else
{
@@ -1013,10 +1043,7 @@ namespace System.Net.Sockets
private void Register()
{
- // Note, on OSX, this is not always true because in certain cases,
- // the socket can already be in non-blocking mode even though we didn't set that ourselves.
- // TODO: Track down exactly why this is
- // Debug.Assert(_nonBlockingSet);
+ Debug.Assert(_nonBlockingSet);
lock (_registerLock)
{
if (!_registered)
diff --git a/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs b/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs
index 7bcabcfba4..0caf582202 100644
--- a/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs
+++ b/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs
@@ -46,7 +46,20 @@ namespace System.Net.Sockets
private void InitializeInternals()
{
- _preAllocatedOverlapped = new PreAllocatedOverlapped(s_completionPortCallback, this, null);
+ // PreAllocatedOverlapped captures ExecutionContext, but SocketAsyncEventArgs ensures
+ // that context is properly flowed if necessary, and thus we don't need the overlapped
+ // infrastructure capturing and flowing as well.
+ bool suppressFlow = !ExecutionContext.IsFlowSuppressed();
+ try
+ {
+ if (suppressFlow) ExecutionContext.SuppressFlow();
+ _preAllocatedOverlapped = new PreAllocatedOverlapped(s_completionPortCallback, this, null);
+ }
+ finally
+ {
+ if (suppressFlow) ExecutionContext.RestoreFlow();
+ }
+
if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"new PreAllocatedOverlapped {_preAllocatedOverlapped}");
}
@@ -58,9 +71,9 @@ namespace System.Net.Sockets
private unsafe NativeOverlapped* AllocateNativeOverlapped()
{
+ Debug.Assert(_operating == InProgress, $"Expected {nameof(_operating)} == {nameof(InProgress)}, got {_operating}");
Debug.Assert(_currentSocket != null, "_currentSocket is null");
Debug.Assert(_currentSocket.SafeHandle != null, "_currentSocket.SafeHandle is null");
- Debug.Assert(!_currentSocket.SafeHandle.IsInvalid, "_currentSocket.SafeHandle is invalid");
Debug.Assert(_preAllocatedOverlapped != null, "_preAllocatedOverlapped is null");
ThreadPoolBoundHandle boundHandle = _currentSocket.GetOrAllocateThreadPoolBoundHandle();
@@ -70,6 +83,7 @@ namespace System.Net.Sockets
private unsafe void FreeNativeOverlapped(NativeOverlapped* overlapped)
{
Debug.Assert(overlapped != null, "overlapped is null");
+ Debug.Assert(_operating == InProgress, $"Expected _operating == InProgress, got {_operating}");
Debug.Assert(_currentSocket != null, "_currentSocket is null");
Debug.Assert(_currentSocket.SafeHandle != null, "_currentSocket.SafeHandle is null");
Debug.Assert(_currentSocket.SafeHandle.IOCPBoundHandle != null, "_currentSocket.SafeHandle.IOCPBoundHandle is null");
@@ -78,16 +92,16 @@ namespace System.Net.Sockets
_currentSocket.SafeHandle.IOCPBoundHandle.FreeNativeOverlapped(overlapped);
}
- private unsafe void FreeNativeOverlappedIfNotPending(NativeOverlapped* overlapped, SocketError error)
+ /// <summary>Handles the result of an IOCP operation.</summary>
+ /// <param name="success">true if the operation completed synchronously and successfully; otherwise, false.</param>
+ /// <param name="bytesTransferred">The number of bytes transferred, if the operation completed synchronously and successfully.</param>
+ /// <param name="overlapped">The overlapped to be freed if the operation completed synchronously.</param>
+ /// <returns>The result status of the operation.</returns>
+ private unsafe SocketError ProcessIOCPResult(bool success, int bytesTransferred, NativeOverlapped* overlapped)
{
- if (error != SocketError.IOPending)
- {
- FreeNativeOverlapped(overlapped);
- }
- }
+ // Note: We need to dispose of the overlapped iff the operation completed synchronously,
+ // and if we do, we must do so before we mark the operation as completed.
- private SocketError ProcessIOCPResult(bool success, int bytesTransferred)
- {
if (success)
{
// Synchronous success.
@@ -95,6 +109,7 @@ namespace System.Net.Sockets
{
// The socket handle is configured to skip completion on success,
// so we can set the results right now.
+ FreeNativeOverlapped(overlapped);
FinishOperationSyncSuccess(bytesTransferred, SocketFlags.None);
return SocketError.Success;
}
@@ -109,6 +124,7 @@ namespace System.Net.Sockets
if (socketError != SocketError.IOPending)
{
// Completed synchronously with a failure.
+ FreeNativeOverlapped(overlapped);
FinishOperationSyncFailure(socketError, bytesTransferred, SocketFlags.None);
return socketError;
}
@@ -121,8 +137,16 @@ namespace System.Net.Sockets
return SocketError.IOPending;
}
- private SocketError ProcessIOCPResultWithSingleBufferHandle(SocketError socketError, int bytesTransferred)
+ /// <summary>Handles the result of an IOCP operation.</summary>
+ /// <param name="socketError">The result status of the operation, as returned from the API call.</param>
+ /// <param name="bytesTransferred">The number of bytes transferred, if the operation completed synchronously and successfully.</param>
+ /// <param name="overlapped">The overlapped to be freed if the operation completed synchronously.</param>
+ /// <returns>The result status of the operation.</returns>
+ private unsafe SocketError ProcessIOCPResultWithSingleBufferHandle(SocketError socketError, int bytesTransferred, NativeOverlapped* overlapped)
{
+ // Note: We need to dispose of the overlapped iff the operation completed synchronously,
+ // and if we do, we must do so before we mark the operation as completed.
+
if (socketError == SocketError.Success)
{
// Synchronous success.
@@ -131,6 +155,7 @@ namespace System.Net.Sockets
// The socket handle is configured to skip completion on success,
// so we can set the results right now.
_singleBufferHandleState = SingleBufferHandleState.None;
+ FreeNativeOverlapped(overlapped);
FinishOperationSyncSuccess(bytesTransferred, SocketFlags.None);
return SocketError.Success;
}
@@ -146,6 +171,7 @@ namespace System.Net.Sockets
{
// Completed synchronously with a failure.
_singleBufferHandleState = SingleBufferHandleState.None;
+ FreeNativeOverlapped(overlapped);
FinishOperationSyncFailure(socketError, bytesTransferred, SocketFlags.None);
return socketError;
}
@@ -157,7 +183,7 @@ namespace System.Net.Sockets
// Return pending and we will continue in the completion port callback.
if (_singleBufferHandleState == SingleBufferHandleState.InProcess)
{
- _singleBufferHandle = _buffer.Retain(pin: true);
+ _singleBufferHandle = _buffer.Pin();
_singleBufferHandleState = SingleBufferHandleState.Set;
}
return SocketError.IOPending;
@@ -165,15 +191,15 @@ namespace System.Net.Sockets
internal unsafe SocketError DoOperationAccept(Socket socket, SafeCloseSocket handle, SafeCloseSocket acceptHandle)
{
- SocketError socketError = SocketError.Success;
+ bool userBuffer = _count != 0;
+ Debug.Assert(!userBuffer || (!_buffer.Equals(default) && _count >= _acceptAddressBufferCount));
+ Memory<byte> buffer = userBuffer ? _buffer : _acceptBuffer;
+ Debug.Assert(_singleBufferHandleState == SingleBufferHandleState.None);
+
NativeOverlapped* overlapped = AllocateNativeOverlapped();
try
{
- bool userBuffer = _count != 0;
- Debug.Assert(!userBuffer || (!_buffer.Equals(default) && _count >= _acceptAddressBufferCount));
- Memory<byte> buffer = userBuffer ? _buffer : _acceptBuffer;
- Debug.Assert(_singleBufferHandleState == SingleBufferHandleState.None);
- _singleBufferHandle = buffer.Retain(pin: true);
+ _singleBufferHandle = buffer.Pin();
_singleBufferHandleState = SingleBufferHandleState.Set;
bool success = socket.AcceptEx(
@@ -186,19 +212,15 @@ namespace System.Net.Sockets
out int bytesTransferred,
overlapped);
- socketError = ProcessIOCPResult(success, bytesTransferred);
- return socketError;
+ return ProcessIOCPResult(success, bytesTransferred, overlapped);
}
catch
{
+ FreeNativeOverlapped(overlapped);
_singleBufferHandle.Dispose();
_singleBufferHandleState = SingleBufferHandleState.None;
throw;
}
- finally
- {
- FreeNativeOverlappedIfNotPending(overlapped, socketError);
- }
}
internal unsafe SocketError DoOperationConnect(Socket socket, SafeCloseSocket handle)
@@ -208,12 +230,11 @@ namespace System.Net.Sockets
// The sockaddr is pinned with a GCHandle to avoid having to use the object array form of UnsafePack.
PinSocketAddressBuffer();
- SocketError socketError = SocketError.Success;
NativeOverlapped* overlapped = AllocateNativeOverlapped();
try
{
Debug.Assert(_singleBufferHandleState == SingleBufferHandleState.None);
- _singleBufferHandle = _buffer.Retain(pin: true);
+ _singleBufferHandle = _buffer.Pin();
_singleBufferHandleState = SingleBufferHandleState.Set;
bool success = socket.ConnectEx(
@@ -225,24 +246,19 @@ namespace System.Net.Sockets
out int bytesTransferred,
overlapped);
- socketError = ProcessIOCPResult(success, bytesTransferred);
- return socketError;
+ return ProcessIOCPResult(success, bytesTransferred, overlapped);
}
catch
{
+ FreeNativeOverlapped(overlapped);
_singleBufferHandle.Dispose();
_singleBufferHandleState = SingleBufferHandleState.None;
throw;
}
- finally
- {
- FreeNativeOverlappedIfNotPending(overlapped, socketError);
- }
}
internal unsafe SocketError DoOperationDisconnect(Socket socket, SafeCloseSocket handle)
{
- SocketError socketError = SocketError.Success;
NativeOverlapped* overlapped = AllocateNativeOverlapped();
try
{
@@ -252,12 +268,12 @@ namespace System.Net.Sockets
(int)(DisconnectReuseSocket ? TransmitFileOptions.ReuseSocket : 0),
0);
- socketError = ProcessIOCPResult(success, 0);
- return socketError;
+ return ProcessIOCPResult(success, 0, overlapped);
}
- finally
+ catch
{
- FreeNativeOverlappedIfNotPending(overlapped, socketError);
+ FreeNativeOverlapped(overlapped);
+ throw;
}
}
@@ -267,18 +283,17 @@ namespace System.Net.Sockets
internal unsafe SocketError DoOperationReceiveSingleBuffer(SafeCloseSocket handle)
{
- SocketError socketError = SocketError.Success;
- NativeOverlapped* overlapped = AllocateNativeOverlapped();
- try
+ fixed (byte* bufferPtr = &MemoryMarshal.GetReference(_buffer.Span))
{
- fixed (byte* bufferPtr = &MemoryMarshal.GetReference(_buffer.Span))
+ Debug.Assert(_singleBufferHandleState == SingleBufferHandleState.None, $"Expected None, got {_singleBufferHandleState}");
+ _singleBufferHandleState = SingleBufferHandleState.InProcess;
+ var wsaBuffer = new WSABuffer { Length = _count, Pointer = (IntPtr)(bufferPtr + _offset) };
+
+ NativeOverlapped* overlapped = AllocateNativeOverlapped();
+ try
{
- Debug.Assert(_singleBufferHandleState == SingleBufferHandleState.None, $"Expected None, got {_singleBufferHandleState}");
- _singleBufferHandleState = SingleBufferHandleState.InProcess;
- var wsaBuffer = new WSABuffer { Length = _count, Pointer = (IntPtr)(bufferPtr + _offset) };
SocketFlags flags = _socketFlags;
-
- socketError = Interop.Winsock.WSARecv(
+ SocketError socketError = Interop.Winsock.WSARecv(
handle.DangerousGetHandle(), // to minimize chances of handle recycling from misuse, this should use DangerousAddRef/Release, but it adds too much overhead
ref wsaBuffer,
1,
@@ -288,29 +303,24 @@ namespace System.Net.Sockets
IntPtr.Zero);
GC.KeepAlive(handle); // small extra safe guard against handle getting collected/finalized while P/Invoke in progress
- socketError = ProcessIOCPResultWithSingleBufferHandle(socketError, bytesTransferred);
+ return ProcessIOCPResultWithSingleBufferHandle(socketError, bytesTransferred, overlapped);
+ }
+ catch
+ {
+ FreeNativeOverlapped(overlapped);
+ _singleBufferHandleState = SingleBufferHandleState.None;
+ throw;
}
- return socketError;
- }
- catch
- {
- _singleBufferHandleState = SingleBufferHandleState.None;
- throw;
- }
- finally
- {
- FreeNativeOverlappedIfNotPending(overlapped, socketError);
}
}
internal unsafe SocketError DoOperationReceiveMultiBuffer(SafeCloseSocket handle)
{
- SocketError socketError = SocketError.Success;
NativeOverlapped* overlapped = AllocateNativeOverlapped();
try
{
SocketFlags flags = _socketFlags;
- socketError = Interop.Winsock.WSARecv(
+ SocketError socketError = Interop.Winsock.WSARecv(
handle.DangerousGetHandle(), // to minimize chances of handle recycling from misuse, this should use DangerousAddRef/Release, but it adds too much overhead
_wsaBufferArray,
_bufferListInternal.Count,
@@ -320,12 +330,12 @@ namespace System.Net.Sockets
IntPtr.Zero);
GC.KeepAlive(handle); // small extra safe guard against handle getting collected/finalized while P/Invoke in progress
- socketError = ProcessIOCPResult(socketError == SocketError.Success, bytesTransferred);
- return socketError;
+ return ProcessIOCPResult(socketError == SocketError.Success, bytesTransferred, overlapped);
}
- finally
+ catch
{
- FreeNativeOverlappedIfNotPending(overlapped, socketError);
+ FreeNativeOverlapped(overlapped);
+ throw;
}
}
@@ -345,19 +355,17 @@ namespace System.Net.Sockets
internal unsafe SocketError DoOperationReceiveFromSingleBuffer(SafeCloseSocket handle)
{
-
- SocketError socketError = SocketError.Success;
- NativeOverlapped* overlapped = AllocateNativeOverlapped();
- try
+ fixed (byte* bufferPtr = &MemoryMarshal.GetReference(_buffer.Span))
{
- fixed (byte* bufferPtr = &MemoryMarshal.GetReference(_buffer.Span))
+ Debug.Assert(_singleBufferHandleState == SingleBufferHandleState.None);
+ _singleBufferHandleState = SingleBufferHandleState.InProcess;
+ var wsaBuffer = new WSABuffer { Length = _count, Pointer = (IntPtr)(bufferPtr + _offset) };
+
+ NativeOverlapped* overlapped = AllocateNativeOverlapped();
+ try
{
- Debug.Assert(_singleBufferHandleState == SingleBufferHandleState.None);
- _singleBufferHandleState = SingleBufferHandleState.InProcess;
- var wsaBuffer = new WSABuffer { Length = _count, Pointer = (IntPtr)(bufferPtr + _offset) };
SocketFlags flags = _socketFlags;
-
- socketError = Interop.Winsock.WSARecvFrom(
+ SocketError socketError = Interop.Winsock.WSARecvFrom(
handle.DangerousGetHandle(), // to minimize chances of handle recycling from misuse, this should use DangerousAddRef/Release, but it adds too much overhead
ref wsaBuffer,
1,
@@ -369,30 +377,24 @@ namespace System.Net.Sockets
IntPtr.Zero);
GC.KeepAlive(handle); // small extra safe guard against handle getting collected/finalized while P/Invoke in progress
- socketError = ProcessIOCPResultWithSingleBufferHandle(socketError, bytesTransferred);
- return socketError;
+ return ProcessIOCPResultWithSingleBufferHandle(socketError, bytesTransferred, overlapped);
+ }
+ catch
+ {
+ FreeNativeOverlapped(overlapped);
+ _singleBufferHandleState = SingleBufferHandleState.None;
+ throw;
}
- }
- catch
- {
- _singleBufferHandleState = SingleBufferHandleState.None;
- throw;
- }
- finally
- {
- FreeNativeOverlappedIfNotPending(overlapped, socketError);
}
}
internal unsafe SocketError DoOperationReceiveFromMultiBuffer(SafeCloseSocket handle)
{
-
- SocketError socketError = SocketError.Success;
NativeOverlapped* overlapped = AllocateNativeOverlapped();
try
{
SocketFlags flags = _socketFlags;
- socketError = Interop.Winsock.WSARecvFrom(
+ SocketError socketError = Interop.Winsock.WSARecvFrom(
handle.DangerousGetHandle(), // to minimize chances of handle recycling from misuse, this should use DangerousAddRef/Release, but it adds too much overhead
_wsaBufferArray,
_bufferListInternal.Count,
@@ -404,12 +406,12 @@ namespace System.Net.Sockets
IntPtr.Zero);
GC.KeepAlive(handle); // small extra safe guard against handle getting collected/finalized while P/Invoke in progress
- socketError = ProcessIOCPResult(socketError == SocketError.Success, bytesTransferred);
- return socketError;
+ return ProcessIOCPResult(socketError == SocketError.Success, bytesTransferred, overlapped);
}
- finally
+ catch
{
- FreeNativeOverlappedIfNotPending(overlapped, socketError);
+ FreeNativeOverlapped(overlapped);
+ throw;
}
}
@@ -470,7 +472,7 @@ namespace System.Net.Sockets
}
Debug.Assert(_singleBufferHandleState == SingleBufferHandleState.None);
- _singleBufferHandle = _buffer.Retain(pin: true);
+ _singleBufferHandle = _buffer.Pin();
_singleBufferHandleState = SingleBufferHandleState.Set;
_wsaRecvMsgWSABufferArray[0].Pointer = (IntPtr)_singleBufferHandle.Pointer;
@@ -522,30 +524,25 @@ namespace System.Net.Sockets
pMessage->flags = _socketFlags;
}
- SocketError socketError = SocketError.Success;
NativeOverlapped* overlapped = AllocateNativeOverlapped();
try
{
- socketError = socket.WSARecvMsg(
+ SocketError socketError = socket.WSARecvMsg(
handle,
Marshal.UnsafeAddrOfPinnedArrayElement(_wsaMessageBuffer, 0),
out int bytesTransferred,
overlapped,
IntPtr.Zero);
- socketError = ProcessIOCPResultWithSingleBufferHandle(socketError, bytesTransferred);
- return socketError;
+ return ProcessIOCPResultWithSingleBufferHandle(socketError, bytesTransferred, overlapped);
}
catch
{
+ FreeNativeOverlapped(overlapped);
_singleBufferHandle.Dispose();
_singleBufferHandleState = SingleBufferHandleState.None;
throw;
}
- finally
- {
- FreeNativeOverlappedIfNotPending(overlapped, socketError);
- }
}
internal unsafe SocketError DoOperationSend(SafeCloseSocket handle) => _bufferList == null ?
@@ -554,17 +551,16 @@ namespace System.Net.Sockets
internal unsafe SocketError DoOperationSendSingleBuffer(SafeCloseSocket handle)
{
- SocketError socketError = SocketError.Success;
- NativeOverlapped* overlapped = AllocateNativeOverlapped();
- try
+ fixed (byte* bufferPtr = &MemoryMarshal.GetReference(_buffer.Span))
{
- fixed (byte* bufferPtr = &MemoryMarshal.GetReference(_buffer.Span))
- {
- Debug.Assert(_singleBufferHandleState == SingleBufferHandleState.None);
- _singleBufferHandleState = SingleBufferHandleState.InProcess;
- var wsaBuffer = new WSABuffer { Length = _count, Pointer = (IntPtr)(bufferPtr + _offset) };
+ Debug.Assert(_singleBufferHandleState == SingleBufferHandleState.None);
+ _singleBufferHandleState = SingleBufferHandleState.InProcess;
+ var wsaBuffer = new WSABuffer { Length = _count, Pointer = (IntPtr)(bufferPtr + _offset) };
- socketError = Interop.Winsock.WSASend(
+ NativeOverlapped* overlapped = AllocateNativeOverlapped();
+ try
+ {
+ SocketError socketError = Interop.Winsock.WSASend(
handle.DangerousGetHandle(), // to minimize chances of handle recycling from misuse, this should use DangerousAddRef/Release, but it adds too much overhead
ref wsaBuffer,
1,
@@ -574,28 +570,23 @@ namespace System.Net.Sockets
IntPtr.Zero);
GC.KeepAlive(handle); // small extra safe guard against handle getting collected/finalized while P/Invoke in progress
- socketError = ProcessIOCPResultWithSingleBufferHandle(socketError, bytesTransferred);
- return socketError;
+ return ProcessIOCPResultWithSingleBufferHandle(socketError, bytesTransferred, overlapped);
+ }
+ catch
+ {
+ FreeNativeOverlapped(overlapped);
+ _singleBufferHandleState = SingleBufferHandleState.None;
+ throw;
}
- }
- catch
- {
- _singleBufferHandleState = SingleBufferHandleState.None;
- throw;
- }
- finally
- {
- FreeNativeOverlappedIfNotPending(overlapped, socketError);
}
}
internal unsafe SocketError DoOperationSendMultiBuffer(SafeCloseSocket handle)
{
- SocketError socketError = SocketError.Success;
NativeOverlapped* overlapped = AllocateNativeOverlapped();
try
{
- socketError = Interop.Winsock.WSASend(
+ SocketError socketError = Interop.Winsock.WSASend(
handle.DangerousGetHandle(), // to minimize chances of handle recycling from misuse, this should use DangerousAddRef/Release, but it adds too much overhead
_wsaBufferArray,
_bufferListInternal.Count,
@@ -605,12 +596,12 @@ namespace System.Net.Sockets
IntPtr.Zero);
GC.KeepAlive(handle); // small extra safe guard against handle getting collected/finalized while P/Invoke in progress
- socketError = ProcessIOCPResult(socketError == SocketError.Success, bytesTransferred);
- return socketError;
+ return ProcessIOCPResult(socketError == SocketError.Success, bytesTransferred, overlapped);
}
- finally
+ catch
{
- FreeNativeOverlappedIfNotPending(overlapped, socketError);
+ FreeNativeOverlapped(overlapped);
+ throw;
}
}
@@ -697,7 +688,6 @@ namespace System.Net.Sockets
Debug.Assert(_multipleBufferGCHandles[0].IsAllocated);
Debug.Assert(_multipleBufferGCHandles[0].Target == sendPacketsDescriptor);
- SocketError socketError = SocketError.Success;
NativeOverlapped* overlapped = AllocateNativeOverlapped();
try
{
@@ -709,12 +699,12 @@ namespace System.Net.Sockets
overlapped,
_sendPacketsFlags);
- socketError = ProcessIOCPResult(result, 0);
- return socketError;
+ return ProcessIOCPResult(result, 0, overlapped);
}
- finally
+ catch
{
- FreeNativeOverlappedIfNotPending(overlapped, socketError);
+ FreeNativeOverlapped(overlapped);
+ throw;
}
}
@@ -735,17 +725,16 @@ namespace System.Net.Sockets
internal unsafe SocketError DoOperationSendToSingleBuffer(SafeCloseSocket handle)
{
- SocketError socketError = SocketError.Success;
- NativeOverlapped* overlapped = AllocateNativeOverlapped();
- try
+ fixed (byte* bufferPtr = &MemoryMarshal.GetReference(_buffer.Span))
{
- fixed (byte* bufferPtr = &MemoryMarshal.GetReference(_buffer.Span))
- {
- Debug.Assert(_singleBufferHandleState == SingleBufferHandleState.None);
- _singleBufferHandleState = SingleBufferHandleState.InProcess;
- var wsaBuffer = new WSABuffer { Length = _count, Pointer = (IntPtr)(bufferPtr + _offset) };
+ Debug.Assert(_singleBufferHandleState == SingleBufferHandleState.None);
+ _singleBufferHandleState = SingleBufferHandleState.InProcess;
+ var wsaBuffer = new WSABuffer { Length = _count, Pointer = (IntPtr)(bufferPtr + _offset) };
- socketError = Interop.Winsock.WSASendTo(
+ NativeOverlapped* overlapped = AllocateNativeOverlapped();
+ try
+ {
+ SocketError socketError = Interop.Winsock.WSASendTo(
handle.DangerousGetHandle(), // to minimize chances of handle recycling from misuse, this should use DangerousAddRef/Release, but it adds too much overhead
ref wsaBuffer,
1,
@@ -757,28 +746,23 @@ namespace System.Net.Sockets
IntPtr.Zero);
GC.KeepAlive(handle); // small extra safe guard against handle getting collected/finalized while P/Invoke in progress
- socketError = ProcessIOCPResultWithSingleBufferHandle(socketError, bytesTransferred);
- return socketError;
+ return ProcessIOCPResultWithSingleBufferHandle(socketError, bytesTransferred, overlapped);
+ }
+ catch
+ {
+ FreeNativeOverlapped(overlapped);
+ _singleBufferHandleState = SingleBufferHandleState.None;
+ throw;
}
- }
- catch
- {
- _singleBufferHandleState = SingleBufferHandleState.None;
- throw;
- }
- finally
- {
- FreeNativeOverlappedIfNotPending(overlapped, socketError);
}
}
internal unsafe SocketError DoOperationSendToMultiBuffer(SafeCloseSocket handle)
{
- SocketError socketError = SocketError.Success;
NativeOverlapped* overlapped = AllocateNativeOverlapped();
try
{
- socketError = Interop.Winsock.WSASendTo(
+ SocketError socketError = Interop.Winsock.WSASendTo(
handle.DangerousGetHandle(), // to minimize chances of handle recycling from misuse, this should use DangerousAddRef/Release, but it adds too much overhead
_wsaBufferArray,
_bufferListInternal.Count,
@@ -790,12 +774,12 @@ namespace System.Net.Sockets
IntPtr.Zero);
GC.KeepAlive(handle); // small extra safe guard against handle getting collected/finalized while P/Invoke in progress
- socketError = ProcessIOCPResult(socketError == SocketError.Success, bytesTransferred);
- return socketError;
+ return ProcessIOCPResult(socketError == SocketError.Success, bytesTransferred, overlapped);
}
- finally
+ catch
{
- FreeNativeOverlappedIfNotPending(overlapped, socketError);
+ FreeNativeOverlapped(overlapped);
+ throw;
}
}
diff --git a/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs b/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs
index 97257b02ff..db23f3d1f8 100644
--- a/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs
+++ b/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs
@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Diagnostics;
+using System.Runtime.InteropServices;
using System.Threading;
namespace System.Net.Sockets
@@ -70,6 +71,7 @@ namespace System.Net.Sockets
internal Internals.SocketAddress _socketAddress;
// Misc state variables.
+ private readonly bool _flowExecutionContext;
private ExecutionContext _context;
private static readonly ContextCallback s_executionCallback = ExecutionCallback;
private Socket _currentSocket;
@@ -84,8 +86,18 @@ namespace System.Net.Sockets
private MultipleConnectAsync _multipleConnect;
- public SocketAsyncEventArgs()
+ public SocketAsyncEventArgs() : this(flowExecutionContext: true)
{
+ }
+
+ /// <summary>Initialize the SocketAsyncEventArgs</summary>
+ /// <param name="flowExecutionContext">
+ /// Whether to capture and flow ExecutionContext. ExecutionContext flow should only
+ /// be disabled if it's going to be handled by higher layers.
+ /// </param>
+ internal SocketAsyncEventArgs(bool flowExecutionContext)
+ {
+ _flowExecutionContext = flowExecutionContext;
InitializeInternals();
}
@@ -106,7 +118,7 @@ namespace System.Net.Sockets
{
if (_bufferIsExplicitArray)
{
- bool success = _buffer.TryGetArray(out ArraySegment<byte> arraySegment);
+ bool success = MemoryMarshal.TryGetArray(_buffer, out ArraySegment<byte> arraySegment);
Debug.Assert(success);
return arraySegment.Array;
}
@@ -519,8 +531,8 @@ namespace System.Net.Sockets
_context = null;
}
- // Capture execution context if none already.
- if (_context == null)
+ // Capture execution context if necessary.
+ if (_flowExecutionContext && _context == null)
{
_context = ExecutionContext.Capture();
}
diff --git a/src/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs b/src/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs
index 3367ac0259..bd2d7b4903 100644
--- a/src/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs
+++ b/src/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs
@@ -47,7 +47,7 @@ namespace System.Net.Sockets
return default(IPPacketInformation);
}
- Interop.Sys.IPPacketInformation nativePacketInfo;
+ Interop.Sys.IPPacketInformation nativePacketInfo = default;
if (!Interop.Sys.TryGetIPPacketInformation(messageHeader, isIPv4, &nativePacketInfo))
{
return default(IPPacketInformation);
@@ -65,7 +65,7 @@ namespace System.Net.Sockets
{
Debug.Assert(socketAddress != null || socketAddressLen == 0, $"Unexpected values: socketAddress={socketAddress}, socketAddressLen={socketAddressLen}");
- long received;
+ long received = 0;
int sockAddrLen = socketAddress != null ? socketAddressLen : 0;
fixed (byte* sockAddr = socketAddress)
@@ -123,7 +123,7 @@ namespace System.Net.Sockets
IOVectorCount = 1
};
- long bytesSent;
+ long bytesSent = 0;
errno = Interop.Sys.SendMessage(
socket.DangerousGetHandle(), // to minimize chances of handle recycling from misuse, this should use DangerousAddRef/Release, but it adds too much overhead
&messageHeader,
@@ -186,7 +186,7 @@ namespace System.Net.Sockets
IOVectorCount = iovCount
};
- long bytesSent;
+ long bytesSent = 0;
errno = Interop.Sys.SendMessage(
socket.DangerousGetHandle(), // to minimize chances of handle recycling from misuse, this should use DangerousAddRef/Release, but it adds too much overhead
&messageHeader,
@@ -244,7 +244,7 @@ namespace System.Net.Sockets
private static unsafe int Receive(SafeCloseSocket socket, SocketFlags flags, IList<ArraySegment<byte>> buffers, byte[] socketAddress, ref int socketAddressLen, out SocketFlags receivedFlags, out Interop.Error errno)
{
- int available;
+ int available = 0;
errno = Interop.Sys.GetBytesAvailable(socket, &available);
if (errno != Interop.Error.SUCCESS)
{
@@ -353,7 +353,7 @@ namespace System.Net.Sockets
Interop.Sys.MessageHeader messageHeader;
- long received;
+ long received = 0;
fixed (byte* rawSocketAddress = socketAddress)
fixed (byte* b = &MemoryMarshal.GetReference(buffer))
{
@@ -432,7 +432,7 @@ namespace System.Net.Sockets
ControlBufferLen = cmsgBufferLen
};
- long received;
+ long received = 0;
errno = Interop.Sys.ReceiveMessage(
socket.DangerousGetHandle(), // to minimize chances of handle recycling from misuse, this should use DangerousAddRef/Release, but it adds too much overhead
&messageHeader,
@@ -470,7 +470,7 @@ namespace System.Net.Sockets
public static unsafe bool TryCompleteAccept(SafeCloseSocket socket, byte[] socketAddress, ref int socketAddressLen, out IntPtr acceptedFd, out SocketError errorCode)
{
- IntPtr fd;
+ IntPtr fd = IntPtr.Zero;
Interop.Error errno;
int sockAddrLen = socketAddressLen;
fixed (byte* rawSocketAddress = socketAddress)
@@ -545,7 +545,7 @@ namespace System.Net.Sockets
public static unsafe bool TryCompleteConnect(SafeCloseSocket socket, int socketAddressLen, out SocketError errorCode)
{
- Interop.Error socketError;
+ Interop.Error socketError = default;
Interop.Error err;
try
{
@@ -1307,7 +1307,7 @@ namespace System.Net.Sockets
Interop.Sys.MulticastOption.MULTICAST_ADD :
Interop.Sys.MulticastOption.MULTICAST_DROP;
- Interop.Sys.IPv4MulticastOption opt;
+ Interop.Sys.IPv4MulticastOption opt = default;
Interop.Error err = Interop.Sys.GetIPv4MulticastOption(handle, optName, &opt);
if (err != Interop.Error.SUCCESS)
{
@@ -1332,7 +1332,7 @@ namespace System.Net.Sockets
Interop.Sys.MulticastOption.MULTICAST_ADD :
Interop.Sys.MulticastOption.MULTICAST_DROP;
- Interop.Sys.IPv6MulticastOption opt;
+ Interop.Sys.IPv6MulticastOption opt = default;
Interop.Error err = Interop.Sys.GetIPv6MulticastOption(handle, optName, &opt);
if (err != Interop.Error.SUCCESS)
{
diff --git a/src/System.Net.Sockets/src/System/Net/Sockets/SocketTaskExtensions.cs b/src/System.Net.Sockets/src/System/Net/Sockets/SocketTaskExtensions.cs
index 7407206222..e32adfba41 100644
--- a/src/System.Net.Sockets/src/System/Net/Sockets/SocketTaskExtensions.cs
+++ b/src/System.Net.Sockets/src/System/Net/Sockets/SocketTaskExtensions.cs
@@ -36,9 +36,9 @@ namespace System.Net.Sockets
socket.ReceiveMessageFromAsync(buffer, socketFlags, remoteEndPoint);
public static Task<int> SendAsync(this Socket socket, ArraySegment<byte> buffer, SocketFlags socketFlags) =>
- socket.SendAsync(buffer, socketFlags, fromNetworkStream: false);
+ socket.SendAsync(buffer, socketFlags);
public static ValueTask<int> SendAsync(this Socket socket, ReadOnlyMemory<byte> buffer, SocketFlags socketFlags, CancellationToken cancellationToken = default) =>
- socket.SendAsync(buffer, socketFlags, fromNetworkStream: false, cancellationToken: cancellationToken);
+ socket.SendAsync(buffer, socketFlags, cancellationToken);
public static Task<int> SendAsync(this Socket socket, IList<ArraySegment<byte>> buffers, SocketFlags socketFlags) =>
socket.SendAsync(buffers, socketFlags);
public static Task<int> SendToAsync(this Socket socket, ArraySegment<byte> buffer, SocketFlags socketFlags, EndPoint remoteEP) =>
diff --git a/src/System.Net.Sockets/src/System/Net/Sockets/TCPListener.cs b/src/System.Net.Sockets/src/System/Net/Sockets/TCPListener.cs
index e761e80051..9bb3834591 100644
--- a/src/System.Net.Sockets/src/System/Net/Sockets/TCPListener.cs
+++ b/src/System.Net.Sockets/src/System/Net/Sockets/TCPListener.cs
@@ -316,8 +316,18 @@ namespace System.Net.Sockets
throw new ArgumentOutOfRangeException(nameof(port));
}
- TcpListener listener = new TcpListener(IPAddress.IPv6Any, port);
- listener.Server.DualMode = true;
+ TcpListener listener;
+ if (Socket.OSSupportsIPv6)
+ {
+ // If OS supports IPv6 use dual mode so both address families work.
+ listener = new TcpListener(IPAddress.IPv6Any, port);
+ listener.Server.DualMode = true;
+ }
+ else
+ {
+ // If not, fall-back to old IPv4.
+ listener = new TcpListener(IPAddress.Any , port);
+ }
if (NetEventSource.IsEnabled) NetEventSource.Exit(null, port);
diff --git a/src/System.Net.Sockets/src/System/Net/Sockets/UDPClient.cs b/src/System.Net.Sockets/src/System/Net/Sockets/UDPClient.cs
index b8746d5654..326caaf921 100644
--- a/src/System.Net.Sockets/src/System/Net/Sockets/UDPClient.cs
+++ b/src/System.Net.Sockets/src/System/Net/Sockets/UDPClient.cs
@@ -60,7 +60,7 @@ namespace System.Net.Sockets
// Validate the address family.
if (family != AddressFamily.InterNetwork && family != AddressFamily.InterNetworkV6)
{
- throw new ArgumentException(SR.net_protocol_invalid_family, nameof(family));
+ throw new ArgumentException(SR.Format(SR.net_protocol_invalid_family, "UDP"), nameof(family));
}
IPEndPoint localEP;
diff --git a/src/System.Net.Sockets/src/System/Net/Sockets/UnixDomainSocketEndPoint.Unix.cs b/src/System.Net.Sockets/src/System/Net/Sockets/UnixDomainSocketEndPoint.Unix.cs
index 1dc982dce9..0fd3087b60 100644
--- a/src/System.Net.Sockets/src/System/Net/Sockets/UnixDomainSocketEndPoint.Unix.cs
+++ b/src/System.Net.Sockets/src/System/Net/Sockets/UnixDomainSocketEndPoint.Unix.cs
@@ -8,18 +8,12 @@ using System.Text;
namespace System.Net.Sockets
{
/// <summary>Represents a Unix Domain Socket endpoint as a path.</summary>
- public sealed class UnixDomainSocketEndPoint : EndPoint
+ public sealed partial class UnixDomainSocketEndPoint : EndPoint
{
- private const AddressFamily EndPointAddressFamily = AddressFamily.Unix;
-
- private static readonly Encoding s_pathEncoding = Encoding.UTF8;
private static readonly int s_nativePathOffset;
private static readonly int s_nativePathLength;
private static readonly int s_nativeAddressSize;
- private readonly string _path;
- private readonly byte[] _encodedPath;
-
static UnixDomainSocketEndPoint()
{
Interop.Sys.GetDomainSocketSizes(out s_nativePathOffset, out s_nativePathLength, out s_nativeAddressSize);
@@ -29,107 +23,7 @@ namespace System.Net.Sockets
Debug.Assert(s_nativePathLength >= 92, "Expected max path length to be at least 92"); // per http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_un.h.html
}
- public UnixDomainSocketEndPoint(string path)
- {
- if (path == null)
- {
- throw new ArgumentNullException(nameof(path));
- }
-
- // Pathname socket addresses should be null-terminated.
- // Linux abstract socket addresses start with a zero byte, they must not be null-terminated.
- bool isAbstract = IsAbstract(path);
- int bufferLength = s_pathEncoding.GetByteCount(path);
- if (!isAbstract)
- {
- // for null terminator
- bufferLength++;
- }
-
- if (path.Length == 0 || bufferLength > s_nativePathLength)
- {
- throw new ArgumentOutOfRangeException(
- nameof(path), path,
- SR.Format(SR.ArgumentOutOfRange_PathLengthInvalid, path, s_nativePathLength));
- }
-
- _path = path;
- _encodedPath = new byte[bufferLength];
- int bytesEncoded = s_pathEncoding.GetBytes(path, 0, path.Length, _encodedPath, 0);
- Debug.Assert(bufferLength - (isAbstract ? 0 : 1) == bytesEncoded);
- }
-
- internal UnixDomainSocketEndPoint(SocketAddress socketAddress)
- {
- if (socketAddress == null)
- {
- throw new ArgumentNullException(nameof(socketAddress));
- }
-
- if (socketAddress.Family != EndPointAddressFamily ||
- socketAddress.Size > s_nativeAddressSize)
- {
- throw new ArgumentOutOfRangeException(nameof(socketAddress));
- }
-
- if (socketAddress.Size > s_nativePathOffset)
- {
- _encodedPath = new byte[socketAddress.Size - s_nativePathOffset];
- for (int i = 0; i < _encodedPath.Length; i++)
- {
- _encodedPath[i] = socketAddress[s_nativePathOffset + i];
- }
-
- // Strip trailing null of pathname socket addresses.
- int length = _encodedPath.Length;
- if (!IsAbstract(_encodedPath))
- {
- // Since this isn't an abstract path, we're sure our first byte isn't 0.
- while (_encodedPath[length - 1] == 0)
- {
- length--;
- }
- }
- _path = s_pathEncoding.GetString(_encodedPath, 0, length);
- }
- else
- {
- _encodedPath = Array.Empty<byte>();
- _path = string.Empty;
- }
- }
-
- public override SocketAddress Serialize()
- {
- var result = new SocketAddress(AddressFamily.Unix, s_nativePathOffset + _encodedPath.Length);
-
- for (int index = 0; index < _encodedPath.Length; index++)
- {
- result[s_nativePathOffset + index] = _encodedPath[index];
- }
-
- return result;
- }
-
- public override EndPoint Create(SocketAddress socketAddress) => new UnixDomainSocketEndPoint(socketAddress);
-
- public override AddressFamily AddressFamily => EndPointAddressFamily;
-
- public override string ToString()
- {
- bool isAbstract = IsAbstract(_path);
- if (isAbstract)
- {
- return "@" + _path.Substring(1);
- }
- else
- {
- return _path;
- }
- }
-
- private static bool IsAbstract(string path) => path.Length > 0 && path[0] == '\0';
-
- private static bool IsAbstract(byte[] encodedPath) => encodedPath.Length > 0 && encodedPath[0] == 0;
+ private SocketAddress CreateSocketAddressForSerialize() =>
+ new SocketAddress(AddressFamily.Unix, s_nativePathOffset + _encodedPath.Length);
}
}
diff --git a/src/System.Net.Sockets/src/System/Net/Sockets/UnixDomainSocketEndPoint.Windows.cs b/src/System.Net.Sockets/src/System/Net/Sockets/UnixDomainSocketEndPoint.Windows.cs
index 6a6c9925d9..c778247c2a 100644
--- a/src/System.Net.Sockets/src/System/Net/Sockets/UnixDomainSocketEndPoint.Windows.cs
+++ b/src/System.Net.Sockets/src/System/Net/Sockets/UnixDomainSocketEndPoint.Windows.cs
@@ -5,11 +5,22 @@
namespace System.Net.Sockets
{
/// <summary>Represents a Unix Domain Socket endpoint as a path.</summary>
- public sealed class UnixDomainSocketEndPoint : EndPoint
+ public sealed partial class UnixDomainSocketEndPoint : EndPoint
{
- public UnixDomainSocketEndPoint(string path)
- {
- throw new PlatformNotSupportedException();
- }
+ private static readonly int s_nativePathOffset = 2; // sizeof(sun_family)
+ private static readonly int s_nativePathLength = 108; // sizeof(sun_path)
+ private static readonly int s_nativeAddressSize = s_nativePathOffset + s_nativePathLength; // sizeof(sockaddr_un)
+
+ private SocketAddress CreateSocketAddressForSerialize() =>
+ new SocketAddress(AddressFamily.Unix, s_nativeAddressSize);
+
+ // from afunix.h:
+ //#define UNIX_PATH_MAX 108
+ //typedef struct sockaddr_un
+ //{
+ // ADDRESS_FAMILY sun_family; /* AF_UNIX */
+ // char sun_path[UNIX_PATH_MAX]; /* pathname */
+ //}
+ //SOCKADDR_UN, *PSOCKADDR_UN;
}
}
diff --git a/src/System.Net.Sockets/src/System/Net/Sockets/UnixDomainSocketEndPoint.cs b/src/System.Net.Sockets/src/System/Net/Sockets/UnixDomainSocketEndPoint.cs
new file mode 100644
index 0000000000..534df754d3
--- /dev/null
+++ b/src/System.Net.Sockets/src/System/Net/Sockets/UnixDomainSocketEndPoint.cs
@@ -0,0 +1,140 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Text;
+
+namespace System.Net.Sockets
+{
+ /// <summary>Represents a Unix Domain Socket endpoint as a path.</summary>
+ public sealed partial class UnixDomainSocketEndPoint : EndPoint
+ {
+ private const AddressFamily EndPointAddressFamily = AddressFamily.Unix;
+
+ private static readonly Encoding s_pathEncoding = Encoding.UTF8;
+ private static readonly Lazy<bool> s_udsSupported = new Lazy<bool>(() =>
+ {
+ try
+ {
+ new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified).Dispose();
+ return true;
+ }
+ catch
+ {
+ return false;
+ }
+ });
+
+ private readonly string _path;
+ private readonly byte[] _encodedPath;
+
+ public UnixDomainSocketEndPoint(string path)
+ {
+ if (path == null)
+ {
+ throw new ArgumentNullException(nameof(path));
+ }
+
+ // Pathname socket addresses should be null-terminated.
+ // Linux abstract socket addresses start with a zero byte, they must not be null-terminated.
+ bool isAbstract = IsAbstract(path);
+ int bufferLength = s_pathEncoding.GetByteCount(path);
+ if (!isAbstract)
+ {
+ // for null terminator
+ bufferLength++;
+ }
+
+ if (path.Length == 0 || bufferLength > s_nativePathLength)
+ {
+ throw new ArgumentOutOfRangeException(
+ nameof(path), path,
+ SR.Format(SR.ArgumentOutOfRange_PathLengthInvalid, path, s_nativePathLength));
+ }
+
+ _path = path;
+ _encodedPath = new byte[bufferLength];
+ int bytesEncoded = s_pathEncoding.GetBytes(path, 0, path.Length, _encodedPath, 0);
+ Debug.Assert(bufferLength - (isAbstract ? 0 : 1) == bytesEncoded);
+
+ if (!s_udsSupported.Value)
+ {
+ throw new PlatformNotSupportedException();
+ }
+ }
+
+ internal UnixDomainSocketEndPoint(SocketAddress socketAddress)
+ {
+ if (socketAddress == null)
+ {
+ throw new ArgumentNullException(nameof(socketAddress));
+ }
+
+ if (socketAddress.Family != EndPointAddressFamily ||
+ socketAddress.Size > s_nativeAddressSize)
+ {
+ throw new ArgumentOutOfRangeException(nameof(socketAddress));
+ }
+
+ if (socketAddress.Size > s_nativePathOffset)
+ {
+ _encodedPath = new byte[socketAddress.Size - s_nativePathOffset];
+ for (int i = 0; i < _encodedPath.Length; i++)
+ {
+ _encodedPath[i] = socketAddress[s_nativePathOffset + i];
+ }
+
+ // Strip trailing null of pathname socket addresses.
+ int length = _encodedPath.Length;
+ if (!IsAbstract(_encodedPath))
+ {
+ // Since this isn't an abstract path, we're sure our first byte isn't 0.
+ while (_encodedPath[length - 1] == 0)
+ {
+ length--;
+ }
+ }
+ _path = s_pathEncoding.GetString(_encodedPath, 0, length);
+ }
+ else
+ {
+ _encodedPath = Array.Empty<byte>();
+ _path = string.Empty;
+ }
+ }
+
+ public override SocketAddress Serialize()
+ {
+ SocketAddress result = CreateSocketAddressForSerialize();
+
+ for (int index = 0; index < _encodedPath.Length; index++)
+ {
+ result[s_nativePathOffset + index] = _encodedPath[index];
+ }
+
+ return result;
+ }
+
+ public override EndPoint Create(SocketAddress socketAddress) => new UnixDomainSocketEndPoint(socketAddress);
+
+ public override AddressFamily AddressFamily => EndPointAddressFamily;
+
+ public override string ToString()
+ {
+ bool isAbstract = IsAbstract(_path);
+ if (isAbstract)
+ {
+ return "@" + _path.Substring(1);
+ }
+ else
+ {
+ return _path;
+ }
+ }
+
+ private static bool IsAbstract(string path) => path.Length > 0 && path[0] == '\0';
+
+ private static bool IsAbstract(byte[] encodedPath) => encodedPath.Length > 0 && encodedPath[0] == 0;
+ }
+}
diff --git a/src/System.Net.Sockets/tests/FunctionalTests/Accept.cs b/src/System.Net.Sockets/tests/FunctionalTests/Accept.cs
index 270b35599b..d5348dbe51 100644
--- a/src/System.Net.Sockets/tests/FunctionalTests/Accept.cs
+++ b/src/System.Net.Sockets/tests/FunctionalTests/Accept.cs
@@ -276,6 +276,30 @@ namespace System.Net.Sockets.Tests
Assert.Throws<InvalidOperationException>(() => { AcceptAsync(listener, server); });
}
}
+
+ [Fact]
+ public async Task AcceptAsync_MultipleAcceptsThenDispose_AcceptsThrowAfterDispose()
+ {
+ if (UsesSync)
+ {
+ return;
+ }
+
+ for (int i = 0; i < 100; i++)
+ {
+ using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ {
+ listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
+ listener.Listen(2);
+
+ Task accept1 = AcceptAsync(listener);
+ Task accept2 = AcceptAsync(listener);
+ listener.Dispose();
+ await Assert.ThrowsAnyAsync<Exception>(() => accept1);
+ await Assert.ThrowsAnyAsync<Exception>(() => accept2);
+ }
+ }
+ }
}
public sealed class AcceptSync : Accept<SocketHelperArraySync> { }
diff --git a/src/System.Net.Sockets/tests/FunctionalTests/Connect.cs b/src/System.Net.Sockets/tests/FunctionalTests/Connect.cs
index 5fe40c29b3..51d92fc7f7 100644
--- a/src/System.Net.Sockets/tests/FunctionalTests/Connect.cs
+++ b/src/System.Net.Sockets/tests/FunctionalTests/Connect.cs
@@ -44,9 +44,7 @@ namespace System.Net.Sockets.Tests
}
}
- [OuterLoop] // TODO: Issue #11345
[Fact]
- [ActiveIssue(22765, TestPlatforms.AnyUnix)]
public async Task Connect_OnConnectedSocket_Fails()
{
int port;
diff --git a/src/System.Net.Sockets/tests/FunctionalTests/ExecutionContextFlowTest.cs b/src/System.Net.Sockets/tests/FunctionalTests/ExecutionContextFlowTest.cs
new file mode 100644
index 0000000000..e30e0ce6b2
--- /dev/null
+++ b/src/System.Net.Sockets/tests/FunctionalTests/ExecutionContextFlowTest.cs
@@ -0,0 +1,501 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.Net.Sockets.Tests
+{
+ public partial class ExecutionContextFlowTest : FileCleanupTestBase
+ {
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task SocketAsyncEventArgs_ExecutionContextFlowsAcrossAcceptAsyncOperation(bool suppressContext)
+ {
+ using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ using (var saea = new SocketAsyncEventArgs())
+ {
+ listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
+ listener.Listen(1);
+
+ var asyncLocal = new AsyncLocal<int>();
+ var tcs = new TaskCompletionSource<int>();
+ saea.Completed += (s, e) =>
+ {
+ e.AcceptSocket.Dispose();
+ tcs.SetResult(asyncLocal.Value);
+ };
+
+ asyncLocal.Value = 42;
+ if (suppressContext) ExecutionContext.SuppressFlow();
+ try
+ {
+ Assert.True(listener.AcceptAsync(saea));
+ }
+ finally
+ {
+ if (suppressContext) ExecutionContext.RestoreFlow();
+ }
+ asyncLocal.Value = 0;
+
+ client.Connect(listener.LocalEndPoint);
+
+ Assert.Equal(suppressContext ? 0 : 42, await tcs.Task);
+ }
+ }
+
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task APM_ExecutionContextFlowsAcrossBeginAcceptOperation(bool suppressContext)
+ {
+ using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ {
+ listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
+ listener.Listen(1);
+
+ var asyncLocal = new AsyncLocal<int>();
+ var tcs = new TaskCompletionSource<int>();
+
+ asyncLocal.Value = 42;
+ if (suppressContext) ExecutionContext.SuppressFlow();
+ try
+ {
+ listener.BeginAccept(iar =>
+ {
+ listener.EndAccept(iar).Dispose();
+ tcs.SetResult(asyncLocal.Value);
+ }, null);
+ }
+ finally
+ {
+ if (suppressContext) ExecutionContext.RestoreFlow();
+ }
+ asyncLocal.Value = 0;
+
+ client.Connect(listener.LocalEndPoint);
+
+ Assert.Equal(suppressContext ? 0 : 42, await tcs.Task);
+ }
+ }
+
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task SocketAsyncEventArgs_ExecutionContextFlowsAcrossConnectAsyncOperation(bool suppressContext)
+ {
+ using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ using (var saea = new SocketAsyncEventArgs())
+ {
+ listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
+ listener.Listen(1);
+
+ var asyncLocal = new AsyncLocal<int>();
+ var tcs = new TaskCompletionSource<int>();
+ saea.Completed += (s, e) => tcs.SetResult(asyncLocal.Value);
+ saea.RemoteEndPoint = listener.LocalEndPoint;
+
+ bool pending;
+ asyncLocal.Value = 42;
+ if (suppressContext) ExecutionContext.SuppressFlow();
+ try
+ {
+ pending = client.ConnectAsync(saea);
+ }
+ finally
+ {
+ if (suppressContext) ExecutionContext.RestoreFlow();
+ }
+ asyncLocal.Value = 0;
+
+ if (pending)
+ {
+ Assert.Equal(suppressContext ? 0 : 42, await tcs.Task);
+ }
+ }
+ }
+
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task APM_ExecutionContextFlowsAcrossBeginConnectOperation(bool suppressContext)
+ {
+ using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ {
+ listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
+ listener.Listen(1);
+
+ var asyncLocal = new AsyncLocal<int>();
+ var tcs = new TaskCompletionSource<int>();
+
+ bool pending;
+ asyncLocal.Value = 42;
+ if (suppressContext) ExecutionContext.SuppressFlow();
+ try
+ {
+ pending = !client.BeginConnect(listener.LocalEndPoint, iar =>
+ {
+ client.EndConnect(iar);
+ tcs.SetResult(asyncLocal.Value);
+ }, null).CompletedSynchronously;
+ }
+ finally
+ {
+ if (suppressContext) ExecutionContext.RestoreFlow();
+ }
+ asyncLocal.Value = 0;
+
+ if (pending)
+ {
+ Assert.Equal(suppressContext ? 0 : 42, await tcs.Task);
+ }
+ }
+ }
+
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task SocketAsyncEventArgs_ExecutionContextFlowsAcrossDisconnectAsyncOperation(bool suppressContext)
+ {
+ using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ using (var saea = new SocketAsyncEventArgs())
+ {
+ listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
+ listener.Listen(1);
+
+ client.Connect(listener.LocalEndPoint);
+ using (Socket server = listener.Accept())
+ {
+ var asyncLocal = new AsyncLocal<int>();
+ var tcs = new TaskCompletionSource<int>();
+ saea.Completed += (s, e) => tcs.SetResult(asyncLocal.Value);
+
+ bool pending;
+ asyncLocal.Value = 42;
+ if (suppressContext) ExecutionContext.SuppressFlow();
+ try
+ {
+ pending = client.DisconnectAsync(saea);
+ }
+ finally
+ {
+ if (suppressContext) ExecutionContext.RestoreFlow();
+ }
+ asyncLocal.Value = 0;
+
+ if (pending)
+ {
+ Assert.Equal(suppressContext ? 0 : 42, await tcs.Task);
+ }
+ }
+ }
+ }
+
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task APM_ExecutionContextFlowsAcrossBeginDisconnectOperation(bool suppressContext)
+ {
+ using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ {
+ listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
+ listener.Listen(1);
+
+ client.Connect(listener.LocalEndPoint);
+ using (Socket server = listener.Accept())
+ {
+ var asyncLocal = new AsyncLocal<int>();
+ var tcs = new TaskCompletionSource<int>();
+
+ bool pending;
+ asyncLocal.Value = 42;
+ if (suppressContext) ExecutionContext.SuppressFlow();
+ try
+ {
+ pending = !client.BeginDisconnect(reuseSocket: false, iar =>
+ {
+ client.EndDisconnect(iar);
+ tcs.SetResult(asyncLocal.Value);
+ }, null).CompletedSynchronously;
+ }
+ finally
+ {
+ if (suppressContext) ExecutionContext.RestoreFlow();
+ }
+ asyncLocal.Value = 0;
+
+ if (pending)
+ {
+ Assert.Equal(suppressContext ? 0 : 42, await tcs.Task);
+ }
+ }
+ }
+ }
+
+ [Theory]
+ [InlineData(false, false)]
+ [InlineData(true, false)]
+ [InlineData(false, true)]
+ [InlineData(true, true)]
+ public async Task SocketAsyncEventArgs_ExecutionContextFlowsAcrossReceiveAsyncOperation(bool suppressContext, bool receiveFrom)
+ {
+ using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ using (var saea = new SocketAsyncEventArgs())
+ {
+ listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
+ listener.Listen(1);
+
+ client.Connect(listener.LocalEndPoint);
+ using (Socket server = listener.Accept())
+ {
+ var asyncLocal = new AsyncLocal<int>();
+ var tcs = new TaskCompletionSource<int>();
+ saea.Completed += (s, e) => tcs.SetResult(asyncLocal.Value);
+ saea.SetBuffer(new byte[1], 0, 1);
+ saea.RemoteEndPoint = server.LocalEndPoint;
+
+ asyncLocal.Value = 42;
+ if (suppressContext) ExecutionContext.SuppressFlow();
+ try
+ {
+ Assert.True(receiveFrom ?
+ client.ReceiveFromAsync(saea) :
+ client.ReceiveAsync(saea));
+ }
+ finally
+ {
+ if (suppressContext) ExecutionContext.RestoreFlow();
+ }
+ asyncLocal.Value = 0;
+
+ server.Send(new byte[] { 18 });
+ Assert.Equal(suppressContext ? 0 : 42, await tcs.Task);
+ }
+ }
+ }
+
+ [Theory]
+ [InlineData(false, false)]
+ [InlineData(true, false)]
+ [InlineData(false, true)]
+ [InlineData(true, true)]
+ public async Task APM_ExecutionContextFlowsAcrossBeginReceiveOperation(bool suppressContext, bool receiveFrom)
+ {
+ using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ {
+ listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
+ listener.Listen(1);
+
+ client.Connect(listener.LocalEndPoint);
+ using (Socket server = listener.Accept())
+ {
+ var asyncLocal = new AsyncLocal<int>();
+ var tcs = new TaskCompletionSource<int>();
+
+ asyncLocal.Value = 42;
+ if (suppressContext) ExecutionContext.SuppressFlow();
+ try
+ {
+ EndPoint ep = server.LocalEndPoint;
+ Assert.False(receiveFrom ?
+ client.BeginReceiveFrom(new byte[1], 0, 1, SocketFlags.None, ref ep, iar =>
+ {
+ client.EndReceiveFrom(iar, ref ep);
+ tcs.SetResult(asyncLocal.Value);
+ }, null).CompletedSynchronously :
+ client.BeginReceive(new byte[1], 0, 1, SocketFlags.None, iar =>
+ {
+ client.EndReceive(iar);
+ tcs.SetResult(asyncLocal.Value);
+ }, null).CompletedSynchronously);
+ }
+ finally
+ {
+ if (suppressContext)
+ ExecutionContext.RestoreFlow();
+ }
+ asyncLocal.Value = 0;
+
+ server.Send(new byte[] { 18 });
+ Assert.Equal(suppressContext ? 0 : 42, await tcs.Task);
+ }
+ }
+ }
+
+ [Theory]
+ [InlineData(false, 0)]
+ [InlineData(true, 0)]
+ [InlineData(false, 1)]
+ [InlineData(true, 1)]
+ [InlineData(false, 2)]
+ [InlineData(true, 2)]
+ public async Task SocketAsyncEventArgs_ExecutionContextFlowsAcrossSendAsyncOperation(bool suppressContext, int sendMode)
+ {
+ using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ using (var saea = new SocketAsyncEventArgs())
+ {
+ listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
+ listener.Listen(1);
+
+ client.Connect(listener.LocalEndPoint);
+ using (Socket server = listener.Accept())
+ {
+ byte[] buffer = new byte[10_000_000];
+
+ var asyncLocal = new AsyncLocal<int>();
+ var tcs = new TaskCompletionSource<int>();
+ saea.Completed += (s, e) => tcs.SetResult(asyncLocal.Value);
+ saea.SetBuffer(buffer, 0, buffer.Length);
+ saea.RemoteEndPoint = server.LocalEndPoint;
+ saea.SendPacketsElements = new[] { new SendPacketsElement(buffer) };
+
+ bool pending;
+ asyncLocal.Value = 42;
+ if (suppressContext) ExecutionContext.SuppressFlow();
+ try
+ {
+ pending =
+ sendMode == 0 ? client.SendAsync(saea) :
+ sendMode == 1 ? client.SendToAsync(saea) :
+ client.SendPacketsAsync(saea);
+ }
+ finally
+ {
+ if (suppressContext) ExecutionContext.RestoreFlow();
+ }
+ asyncLocal.Value = 0;
+
+ int totalReceived = 0;
+ while (totalReceived < buffer.Length)
+ {
+ totalReceived += server.Receive(buffer);
+ }
+
+ if (pending)
+ {
+ Assert.Equal(suppressContext ? 0 : 42, await tcs.Task);
+ }
+ }
+ }
+ }
+
+ [Theory]
+ [InlineData(false, false)]
+ [InlineData(true, false)]
+ [InlineData(false, true)]
+ [InlineData(true, true)]
+ public async Task APM_ExecutionContextFlowsAcrossBeginSendOperation(bool suppressContext, bool sendTo)
+ {
+ using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ {
+ listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
+ listener.Listen(1);
+
+ client.Connect(listener.LocalEndPoint);
+ using (Socket server = listener.Accept())
+ {
+ byte[] buffer = new byte[10_000_000];
+
+ var asyncLocal = new AsyncLocal<int>();
+ var tcs = new TaskCompletionSource<int>();
+
+ bool pending;
+ asyncLocal.Value = 42;
+ if (suppressContext) ExecutionContext.SuppressFlow();
+ try
+ {
+ pending = sendTo ?
+ !client.BeginSendTo(buffer, 0, buffer.Length, SocketFlags.None, server.LocalEndPoint, iar =>
+ {
+ client.EndSendTo(iar);
+ tcs.SetResult(asyncLocal.Value);
+ }, null).CompletedSynchronously :
+ !client.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, iar =>
+ {
+ client.EndSend(iar);
+ tcs.SetResult(asyncLocal.Value);
+ }, null).CompletedSynchronously;
+ }
+ finally
+ {
+ if (suppressContext) ExecutionContext.RestoreFlow();
+ }
+ asyncLocal.Value = 0;
+
+ int totalReceived = 0;
+ while (totalReceived < buffer.Length)
+ {
+ totalReceived += server.Receive(buffer);
+ }
+
+ if (pending)
+ {
+ Assert.Equal(suppressContext ? 0 : 42, await tcs.Task);
+ }
+ }
+ }
+ }
+
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task APM_ExecutionContextFlowsAcrossBeginSendFileOperation(bool suppressContext)
+ {
+ using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ {
+ listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
+ listener.Listen(1);
+
+ client.Connect(listener.LocalEndPoint);
+ using (Socket server = listener.Accept())
+ {
+ string filePath = GetTestFilePath();
+ using (FileStream fs = File.Create(filePath))
+ {
+ fs.WriteByte(18);
+ }
+
+ var asyncLocal = new AsyncLocal<int>();
+ var tcs = new TaskCompletionSource<int>();
+
+ bool pending;
+ asyncLocal.Value = 42;
+ if (suppressContext) ExecutionContext.SuppressFlow();
+ try
+ {
+ pending = !client.BeginSendFile(filePath, iar =>
+ {
+ client.EndSendFile(iar);
+ tcs.SetResult(asyncLocal.Value);
+ }, null).CompletedSynchronously;
+ }
+ finally
+ {
+ if (suppressContext) ExecutionContext.RestoreFlow();
+ }
+ asyncLocal.Value = 0;
+
+ if (pending)
+ {
+ Assert.Equal(suppressContext ? 0 : 42, await tcs.Task);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/System.Net.Sockets/tests/FunctionalTests/ExecutionContextFlowTest.netcoreapp.cs b/src/System.Net.Sockets/tests/FunctionalTests/ExecutionContextFlowTest.netcoreapp.cs
new file mode 100644
index 0000000000..c2c1e37f0d
--- /dev/null
+++ b/src/System.Net.Sockets/tests/FunctionalTests/ExecutionContextFlowTest.netcoreapp.cs
@@ -0,0 +1,89 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.IO;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.Net.Sockets.Tests
+{
+ public partial class ExecutionContextFlowTest : FileCleanupTestBase
+ {
+ [Fact]
+ public Task ExecutionContext_FlowsOnlyOnceAcrossAsyncOperations()
+ {
+ return Task.Run(async () => // escape xunit's sync ctx
+ {
+ using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ {
+ listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
+ listener.Listen(1);
+
+ client.Connect(listener.LocalEndPoint);
+ using (Socket server = listener.Accept())
+ {
+ var stackLog = new StringBuilder();
+ int executionContextChanges = 0;
+ var asyncLocal = new AsyncLocal<int>(_ =>
+ {
+ executionContextChanges++;
+ stackLog.AppendLine($"#{executionContextChanges}: {Environment.StackTrace}");
+ });
+ Assert.Equal(0, executionContextChanges);
+
+ int numAwaits = 20;
+ for (int i = 1; i <= numAwaits; i++)
+ {
+ asyncLocal.Value = i;
+
+ await new AwaitWithOnCompletedInvocation<int>(
+ client.ReceiveAsync(new Memory<byte>(new byte[1]), SocketFlags.None),
+ () => server.Send(new byte[1]));
+
+ Assert.Equal(i, asyncLocal.Value);
+ }
+
+ // This doesn't count EC changes where EC.Run is passed the same context
+ // as is current, but it's the best we can track via public API.
+ try
+ {
+ Assert.InRange(executionContextChanges, 1, numAwaits * 3); // at most: 1 / AsyncLocal change + 1 / suspend + 1 / resume
+ }
+ catch (Exception e)
+ {
+ throw new Exception($"{nameof(executionContextChanges)} == {executionContextChanges} with log: {stackLog.ToString()}", e);
+ }
+ }
+ }
+ });
+ }
+
+ private readonly struct AwaitWithOnCompletedInvocation<T> : ICriticalNotifyCompletion
+ {
+ private readonly ValueTask<T> _valueTask;
+ private readonly Action _invokeAfterOnCompleted;
+
+ public AwaitWithOnCompletedInvocation(ValueTask<T> valueTask, Action invokeAfterOnCompleted)
+ {
+ _valueTask = valueTask;
+ _invokeAfterOnCompleted = invokeAfterOnCompleted;
+ }
+
+ public AwaitWithOnCompletedInvocation<T> GetAwaiter() => this;
+
+ public bool IsCompleted => false;
+ public T GetResult() => _valueTask.GetAwaiter().GetResult();
+ public void OnCompleted(Action continuation) => throw new NotSupportedException();
+ public void UnsafeOnCompleted(Action continuation)
+ {
+ _valueTask.GetAwaiter().UnsafeOnCompleted(continuation);
+ _invokeAfterOnCompleted();
+ }
+ }
+ }
+}
diff --git a/src/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.cs b/src/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.cs
index d4a50d03a6..af10c538d7 100644
--- a/src/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.cs
+++ b/src/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.cs
@@ -455,6 +455,21 @@ namespace System.Net.Sockets.Tests
}
[Fact]
+ public async Task ReadWrite_Byte_Success()
+ {
+ await RunWithConnectedNetworkStreamsAsync(async (server, client) =>
+ {
+ for (byte i = 0; i < 10; i++)
+ {
+ Task<int> read = Task.Run(() => client.ReadByte());
+ Task write = Task.Run(() => server.WriteByte(i));
+ await Task.WhenAll(read, write);
+ Assert.Equal(i, await read);
+ }
+ });
+ }
+
+ [Fact]
public async Task ReadWrite_Array_Success()
{
await RunWithConnectedNetworkStreamsAsync((server, client) =>
diff --git a/src/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.netcoreapp.cs b/src/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.netcoreapp.cs
index bcf29d4bb5..38be110fad 100644
--- a/src/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.netcoreapp.cs
+++ b/src/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.netcoreapp.cs
@@ -2,6 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
@@ -44,16 +47,332 @@ namespace System.Net.Sockets.Tests
}
[Fact]
+ public async Task ReadWrite_Memory_LargeWrite_Success()
+ {
+ await RunWithConnectedNetworkStreamsAsync(async (server, client) =>
+ {
+ var writeBuffer = new byte[10 * 1024 * 1024];
+ var readBuffer = new byte[writeBuffer.Length];
+ RandomNumberGenerator.Fill(writeBuffer);
+
+ ValueTask writeTask = client.WriteAsync((ReadOnlyMemory<byte>)writeBuffer);
+
+ int totalRead = 0;
+ while (totalRead < readBuffer.Length)
+ {
+ int bytesRead = await server.ReadAsync(new Memory<byte>(readBuffer).Slice(totalRead));
+ Assert.InRange(bytesRead, 0, int.MaxValue);
+ if (bytesRead == 0)
+ {
+ break;
+ }
+ totalRead += bytesRead;
+ }
+ Assert.Equal(readBuffer.Length, totalRead);
+ Assert.Equal<byte>(writeBuffer, readBuffer);
+
+ await writeTask;
+ });
+ }
+
+ [Fact]
public async Task ReadWrite_Precanceled_Throws()
{
await RunWithConnectedNetworkStreamsAsync(async (server, client) =>
{
- await Assert.ThrowsAnyAsync<OperationCanceledException>(() => server.WriteAsync((ArraySegment<byte>)new byte[0], new CancellationToken(true)));
- await Assert.ThrowsAnyAsync<OperationCanceledException>(() => server.ReadAsync((ArraySegment<byte>)new byte[0], new CancellationToken(true)).AsTask());
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await server.WriteAsync((ArraySegment<byte>)new byte[0], new CancellationToken(true)));
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await server.ReadAsync((ArraySegment<byte>)new byte[0], new CancellationToken(true)));
+
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await server.WriteAsync((ReadOnlyMemory<byte>)new byte[0], new CancellationToken(true)));
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await server.ReadAsync((Memory<byte>)new byte[0], new CancellationToken(true)));
+ });
+ }
- await Assert.ThrowsAnyAsync<OperationCanceledException>(() => server.WriteAsync((ReadOnlyMemory<byte>)new byte[0], new CancellationToken(true)));
- await Assert.ThrowsAnyAsync<OperationCanceledException>(() => server.ReadAsync((Memory<byte>)new byte[0], new CancellationToken(true)).AsTask());
+ [Fact]
+ public async Task ReadAsync_AwaitMultipleTimes_Throws()
+ {
+ await RunWithConnectedNetworkStreamsAsync(async (server, client) =>
+ {
+ var b = new byte[1];
+ ValueTask<int> r = server.ReadAsync(b);
+ await client.WriteAsync(new byte[] { 42 });
+ Assert.Equal(1, await r);
+ Assert.Equal(42, b[0]);
+ await Assert.ThrowsAsync<InvalidOperationException>(async () => await r);
+ Assert.Throws<InvalidOperationException>(() => r.GetAwaiter().IsCompleted);
+ Assert.Throws<InvalidOperationException>(() => r.GetAwaiter().OnCompleted(() => { }));
+ Assert.Throws<InvalidOperationException>(() => r.GetAwaiter().GetResult());
+ });
+ }
+
+ [Fact]
+ public async Task ReadAsync_MultipleContinuations_Throws()
+ {
+ await RunWithConnectedNetworkStreamsAsync((server, client) =>
+ {
+ var b = new byte[1];
+ ValueTask<int> r = server.ReadAsync(b);
+ r.GetAwaiter().OnCompleted(() => { });
+ Assert.Throws<InvalidOperationException>(() => r.GetAwaiter().OnCompleted(() => { }));
+ return Task.CompletedTask;
});
}
+
+ [Fact]
+ public async Task ReadAsync_MultipleConcurrentValueTaskReads_Success()
+ {
+ await RunWithConnectedNetworkStreamsAsync(async (server, client) =>
+ {
+ // Technically this isn't supported behavior, but it happens to work because it's supported on socket.
+ // So validate it to alert us to any potential future breaks.
+
+ byte[] b1 = new byte[1], b2 = new byte[1], b3 = new byte[1];
+ ValueTask<int> r1 = server.ReadAsync(b1);
+ ValueTask<int> r2 = server.ReadAsync(b2);
+ ValueTask<int> r3 = server.ReadAsync(b3);
+
+ await client.WriteAsync(new byte[] { 42, 43, 44 });
+
+ Assert.Equal(3, await r1 + await r2 + await r3);
+ Assert.Equal(42 + 43 + 44, b1[0] + b2[0] + b3[0]);
+ });
+ }
+
+ [Fact]
+ public async Task ReadAsync_MultipleConcurrentValueTaskReads_AsTask_Success()
+ {
+ await RunWithConnectedNetworkStreamsAsync(async (server, client) =>
+ {
+ // Technically this isn't supported behavior, but it happens to work because it's supported on socket.
+ // So validate it to alert us to any potential future breaks.
+
+ byte[] b1 = new byte[1], b2 = new byte[1], b3 = new byte[1];
+ Task<int> r1 = server.ReadAsync((Memory<byte>)b1).AsTask();
+ Task<int> r2 = server.ReadAsync((Memory<byte>)b2).AsTask();
+ Task<int> r3 = server.ReadAsync((Memory<byte>)b3).AsTask();
+
+ await client.WriteAsync(new byte[] { 42, 43, 44 });
+
+ Assert.Equal(3, await r1 + await r2 + await r3);
+ Assert.Equal(42 + 43 + 44, b1[0] + b2[0] + b3[0]);
+ });
+ }
+
+ [Fact]
+ public async Task WriteAsync_MultipleConcurrentValueTaskWrites_Success()
+ {
+ await RunWithConnectedNetworkStreamsAsync(async (server, client) =>
+ {
+ // Technically this isn't supported behavior, but it happens to work because it's supported on socket.
+ // So validate it to alert us to any potential future breaks.
+
+ ValueTask s1 = server.WriteAsync(new ReadOnlyMemory<byte>(new byte[] { 42 }));
+ ValueTask s2 = server.WriteAsync(new ReadOnlyMemory<byte>(new byte[] { 43 }));
+ ValueTask s3 = server.WriteAsync(new ReadOnlyMemory<byte>(new byte[] { 44 }));
+
+ byte[] b1 = new byte[1], b2 = new byte[1], b3 = new byte[1];
+ Assert.Equal(3,
+ await client.ReadAsync((Memory<byte>)b1) +
+ await client.ReadAsync((Memory<byte>)b2) +
+ await client.ReadAsync((Memory<byte>)b3));
+
+ await s1;
+ await s2;
+ await s3;
+
+ Assert.Equal(42 + 43 + 44, b1[0] + b2[0] + b3[0]);
+ });
+ }
+
+ [Fact]
+ public async Task WriteAsync_MultipleConcurrentValueTaskWrites_AsTask_Success()
+ {
+ await RunWithConnectedNetworkStreamsAsync(async (server, client) =>
+ {
+ // Technically this isn't supported behavior, but it happens to work because it's supported on socket.
+ // So validate it to alert us to any potential future breaks.
+
+ Task s1 = server.WriteAsync(new ReadOnlyMemory<byte>(new byte[] { 42 })).AsTask();
+ Task s2 = server.WriteAsync(new ReadOnlyMemory<byte>(new byte[] { 43 })).AsTask();
+ Task s3 = server.WriteAsync(new ReadOnlyMemory<byte>(new byte[] { 44 })).AsTask();
+
+ byte[] b1 = new byte[1], b2 = new byte[1], b3 = new byte[1];
+ Task<int> r1 = client.ReadAsync((Memory<byte>)b1).AsTask();
+ Task<int> r2 = client.ReadAsync((Memory<byte>)b2).AsTask();
+ Task<int> r3 = client.ReadAsync((Memory<byte>)b3).AsTask();
+
+ await Task.WhenAll(s1, s2, s3, r1, r2, r3);
+
+ Assert.Equal(3, await r1 + await r2 + await r3);
+ Assert.Equal(42 + 43 + 44, b1[0] + b2[0] + b3[0]);
+ });
+ }
+
+ public static IEnumerable<object[]> ReadAsync_ContinuesOnCurrentContextIfDesired_MemberData() =>
+ from flowExecutionContext in new[] { true, false }
+ from continueOnCapturedContext in new bool?[] { null, false, true }
+ select new object[] { flowExecutionContext, continueOnCapturedContext };
+
+ [Theory]
+ [MemberData(nameof(ReadAsync_ContinuesOnCurrentContextIfDesired_MemberData))]
+ public async Task ReadAsync_ContinuesOnCurrentSynchronizationContextIfDesired(
+ bool flowExecutionContext, bool? continueOnCapturedContext)
+ {
+ await Task.Run(async () => // escape xunit sync ctx
+ {
+ await RunWithConnectedNetworkStreamsAsync(async (server, client) =>
+ {
+ Assert.Null(SynchronizationContext.Current);
+
+ var continuationRan = new TaskCompletionSource<bool>();
+ var asyncLocal = new AsyncLocal<int>();
+ bool schedulerWasFlowed = false;
+ bool executionContextWasFlowed = false;
+ Action continuation = () =>
+ {
+ schedulerWasFlowed = SynchronizationContext.Current is CustomSynchronizationContext;
+ executionContextWasFlowed = 42 == asyncLocal.Value;
+ continuationRan.SetResult(true);
+ };
+
+ var readBuffer = new byte[1];
+ ValueTask<int> readValueTask = client.ReadAsync((Memory<byte>)new byte[1]);
+
+ SynchronizationContext.SetSynchronizationContext(new CustomSynchronizationContext());
+ asyncLocal.Value = 42;
+ switch (continueOnCapturedContext)
+ {
+ case null:
+ if (flowExecutionContext)
+ {
+ readValueTask.GetAwaiter().OnCompleted(continuation);
+ }
+ else
+ {
+ readValueTask.GetAwaiter().UnsafeOnCompleted(continuation);
+ }
+ break;
+ default:
+ if (flowExecutionContext)
+ {
+ readValueTask.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().OnCompleted(continuation);
+ }
+ else
+ {
+ readValueTask.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().UnsafeOnCompleted(continuation);
+ }
+ break;
+ }
+ asyncLocal.Value = 0;
+ SynchronizationContext.SetSynchronizationContext(null);
+
+ Assert.False(readValueTask.IsCompleted);
+ Assert.False(readValueTask.IsCompletedSuccessfully);
+ await server.WriteAsync(new byte[] { 42 });
+
+ await continuationRan.Task;
+ Assert.True(readValueTask.IsCompleted);
+ Assert.True(readValueTask.IsCompletedSuccessfully);
+
+ Assert.Equal(continueOnCapturedContext != false, schedulerWasFlowed);
+ Assert.Equal(flowExecutionContext, executionContextWasFlowed);
+ });
+ });
+ }
+
+ [Theory]
+ [MemberData(nameof(ReadAsync_ContinuesOnCurrentContextIfDesired_MemberData))]
+ public async Task ReadAsync_ContinuesOnCurrentTaskSchedulerIfDesired(
+ bool flowExecutionContext, bool? continueOnCapturedContext)
+ {
+ await Task.Run(async () => // escape xunit sync ctx
+ {
+ await RunWithConnectedNetworkStreamsAsync(async (server, client) =>
+ {
+ Assert.Null(SynchronizationContext.Current);
+
+ var continuationRan = new TaskCompletionSource<bool>();
+ var asyncLocal = new AsyncLocal<int>();
+ bool schedulerWasFlowed = false;
+ bool executionContextWasFlowed = false;
+ Action continuation = () =>
+ {
+ schedulerWasFlowed = TaskScheduler.Current is CustomTaskScheduler;
+ executionContextWasFlowed = 42 == asyncLocal.Value;
+ continuationRan.SetResult(true);
+ };
+
+ var readBuffer = new byte[1];
+ ValueTask<int> readValueTask = client.ReadAsync((Memory<byte>)new byte[1]);
+
+ await Task.Factory.StartNew(() =>
+ {
+ Assert.IsType<CustomTaskScheduler>(TaskScheduler.Current);
+ asyncLocal.Value = 42;
+ switch (continueOnCapturedContext)
+ {
+ case null:
+ if (flowExecutionContext)
+ {
+ readValueTask.GetAwaiter().OnCompleted(continuation);
+ }
+ else
+ {
+ readValueTask.GetAwaiter().UnsafeOnCompleted(continuation);
+ }
+ break;
+ default:
+ if (flowExecutionContext)
+ {
+ readValueTask.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().OnCompleted(continuation);
+ }
+ else
+ {
+ readValueTask.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().UnsafeOnCompleted(continuation);
+ }
+ break;
+ }
+ asyncLocal.Value = 0;
+ }, CancellationToken.None, TaskCreationOptions.None, new CustomTaskScheduler());
+
+ Assert.False(readValueTask.IsCompleted);
+ Assert.False(readValueTask.IsCompletedSuccessfully);
+ await server.WriteAsync(new byte[] { 42 });
+
+ await continuationRan.Task;
+ Assert.True(readValueTask.IsCompleted);
+ Assert.True(readValueTask.IsCompletedSuccessfully);
+
+ Assert.Equal(continueOnCapturedContext != false, schedulerWasFlowed);
+ Assert.Equal(flowExecutionContext, executionContextWasFlowed);
+ });
+ });
+ }
+
+ private sealed class CustomSynchronizationContext : SynchronizationContext
+ {
+ public override void Post(SendOrPostCallback d, object state)
+ {
+ ThreadPool.QueueUserWorkItem(delegate
+ {
+ SetSynchronizationContext(this);
+ try
+ {
+ d(state);
+ }
+ finally
+ {
+ SetSynchronizationContext(null);
+ }
+ }, null);
+ }
+ }
+
+ private sealed class CustomTaskScheduler : TaskScheduler
+ {
+ protected override void QueueTask(Task task) => ThreadPool.QueueUserWorkItem(_ => TryExecuteTask(task));
+ protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) => false;
+ protected override IEnumerable<Task> GetScheduledTasks() => null;
+ }
}
}
diff --git a/src/System.Net.Sockets/tests/FunctionalTests/OSSupport.cs b/src/System.Net.Sockets/tests/FunctionalTests/OSSupport.cs
index 3e1614a737..064c00cf23 100644
--- a/src/System.Net.Sockets/tests/FunctionalTests/OSSupport.cs
+++ b/src/System.Net.Sockets/tests/FunctionalTests/OSSupport.cs
@@ -81,9 +81,9 @@ namespace System.Net.Sockets.Tests
}
}
- [ActiveIssue(25639)]
+ [PlatformSpecific(TestPlatforms.AnyUnix)]
[Fact]
- public void IOControl_SIOCATMARK_Success()
+ public void IOControl_SIOCATMARK_Unix_Success()
{
using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
@@ -101,25 +101,89 @@ namespace System.Net.Sockets.Tests
{
byte[] siocatmarkResult = new byte[sizeof(int)];
+ // Socket connected but no data sent.
+ Assert.Equal(4, client.IOControl(IOControlCode.OobDataRead, null, siocatmarkResult));
+ Assert.Equal(0, BitConverter.ToInt32(siocatmarkResult, 0));
+
server.Send(new byte[] { 42 }, SocketFlags.None);
server.Send(new byte[] { 43 }, SocketFlags.OutOfBand);
- Assert.Equal(4, client.IOControl(IOControlCode.OobDataRead, null, siocatmarkResult));
- Assert.Equal(0, BitConverter.ToInt32(siocatmarkResult, 0));
+ // OOB data recieved, but read pointer not at mark.
+ Assert.True(SpinWait.SpinUntil(() =>
+ {
+ Assert.Equal(4, client.IOControl(IOControlCode.OobDataRead, null, siocatmarkResult));
+ return BitConverter.ToInt32(siocatmarkResult, 0) == 0;
+ }, 10_000));
var received = new byte[1];
Assert.Equal(1, client.Receive(received));
Assert.Equal(42, received[0]);
+ // OOB data recieved, read pointer at mark.
+ Assert.Equal(4, client.IOControl(IOControlCode.OobDataRead, null, siocatmarkResult));
+ Assert.Equal(1, BitConverter.ToInt32(siocatmarkResult, 0));
+
Assert.Equal(1, client.Receive(received, SocketFlags.OutOfBand));
Assert.Equal(43, received[0]);
+ // OOB data read, read pointer at mark.
+ Assert.Equal(4, client.IOControl(IOControlCode.OobDataRead, null, siocatmarkResult));
+ Assert.Equal(PlatformDetection.IsOSX ? 0 : 1, BitConverter.ToInt32(siocatmarkResult, 0));
+ }
+ }
+ }
+ }
+
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [Fact]
+ public void IOControl_SIOCATMARK_Windows_Success()
+ {
+ using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ {
+ Assert.Throws<SocketException>(() => client.IOControl(IOControlCode.OobDataRead, null, null));
+ Assert.Throws<SocketException>(() => client.IOControl(IOControlCode.OobDataRead, null, new byte[0]));
+ Assert.Throws<SocketException>(() => client.IOControl(IOControlCode.OobDataRead, null, new byte[sizeof(int) - 1]));
+
+ using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ {
+ listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
+ listener.Listen(1);
+
+ client.Connect(listener.LocalEndPoint);
+ using (Socket server = listener.Accept())
+ {
+ byte[] siocatmarkResult = new byte[sizeof(int)];
+
+ // Socket connected but no data sent.
+ Assert.Equal(4, client.IOControl(IOControlCode.OobDataRead, null, siocatmarkResult));
+ Assert.Equal(1, BitConverter.ToInt32(siocatmarkResult, 0));
+
+ server.Send(new byte[] { 42 }, SocketFlags.None);
+ server.Send(new byte[] { 43 }, SocketFlags.OutOfBand);
+
+ // OOB data recieved, but read pointer not at mark
Assert.True(SpinWait.SpinUntil(() =>
{
Assert.Equal(4, client.IOControl(IOControlCode.OobDataRead, null, siocatmarkResult));
- return BitConverter.ToInt32(siocatmarkResult, 0) == 1;
+ return BitConverter.ToInt32(siocatmarkResult, 0) == 0;
}, 10_000));
+
+ var received = new byte[1];
+
+ Assert.Equal(1, client.Receive(received));
+ Assert.Equal(42, received[0]);
+
+ // OOB data recieved, read pointer at mark.
+ Assert.Equal(4, client.IOControl(IOControlCode.OobDataRead, null, siocatmarkResult));
+ Assert.Equal(0, BitConverter.ToInt32(siocatmarkResult, 0));
+
+ Assert.Equal(1, client.Receive(received, SocketFlags.OutOfBand));
+ Assert.Equal(43, received[0]);
+
+ // OOB data read, read pointer at mark.
+ Assert.Equal(4, client.IOControl(IOControlCode.OobDataRead, null, siocatmarkResult));
+ Assert.Equal(1, BitConverter.ToInt32(siocatmarkResult, 0));
}
}
}
diff --git a/src/System.Net.Sockets/tests/FunctionalTests/SendPacketsAsync.cs b/src/System.Net.Sockets/tests/FunctionalTests/SendPacketsAsync.cs
index 00baeb74a7..f1d15d9251 100644
--- a/src/System.Net.Sockets/tests/FunctionalTests/SendPacketsAsync.cs
+++ b/src/System.Net.Sockets/tests/FunctionalTests/SendPacketsAsync.cs
@@ -286,11 +286,12 @@ namespace System.Net.Sockets.Tests
AssertExtensions.Throws<ArgumentException>("path", null, () =>
{
// Existence is validated on send
- SendPackets(type, new SendPacketsElement(" \t "), 0);
+ SendPackets(type, new SendPacketsElement(" "), 0);
});
}
[Theory]
+ [ActiveIssue(27269)]
[InlineData(SocketImplementationType.APM)]
[InlineData(SocketImplementationType.Async)]
[PlatformSpecific(TestPlatforms.Windows)] // valid filename chars on Unix
diff --git a/src/System.Net.Sockets/tests/FunctionalTests/SendReceive.netcoreapp.cs b/src/System.Net.Sockets/tests/FunctionalTests/SendReceive.netcoreapp.cs
index 9b511de045..ae34a6e90b 100644
--- a/src/System.Net.Sockets/tests/FunctionalTests/SendReceive.netcoreapp.cs
+++ b/src/System.Net.Sockets/tests/FunctionalTests/SendReceive.netcoreapp.cs
@@ -2,10 +2,58 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+
namespace System.Net.Sockets.Tests
{
public sealed class SendReceiveSpanSync : SendReceive<SocketHelperSpanSync> { }
public sealed class SendReceiveSpanSyncForceNonBlocking : SendReceive<SocketHelperSpanSyncForceNonBlocking> { }
- public sealed class SendReceiveMemoryArrayTask : SendReceive<SocketHelperMemoryArrayTask> { }
+ public sealed class SendReceiveMemoryArrayTask : SendReceive<SocketHelperMemoryArrayTask>
+ {
+ [Fact]
+ public async Task Precanceled_Throws()
+ {
+ using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ {
+ listener.BindToAnonymousPort(IPAddress.Loopback);
+ listener.Listen(1);
+
+ await client.ConnectAsync(listener.LocalEndPoint);
+ using (Socket server = await listener.AcceptAsync())
+ {
+ var cts = new CancellationTokenSource();
+ cts.Cancel();
+
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await server.SendAsync((ReadOnlyMemory<byte>)new byte[0], SocketFlags.None, cts.Token));
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await server.ReceiveAsync((Memory<byte>)new byte[0], SocketFlags.None, cts.Token));
+ }
+ }
+ }
+
+ [Fact]
+ public async Task DisposedSocket_ThrowsOperationCanceledException()
+ {
+ using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
+ {
+ listener.BindToAnonymousPort(IPAddress.Loopback);
+ listener.Listen(1);
+
+ await client.ConnectAsync(listener.LocalEndPoint);
+ using (Socket server = await listener.AcceptAsync())
+ {
+ var cts = new CancellationTokenSource();
+ cts.Cancel();
+
+ server.Shutdown(SocketShutdown.Both);
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await server.SendAsync((ReadOnlyMemory<byte>)new byte[0], SocketFlags.None, cts.Token));
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await server.ReceiveAsync((Memory<byte>)new byte[0], SocketFlags.None, cts.Token));
+ }
+ }
+ }
+ }
public sealed class SendReceiveMemoryNativeTask : SendReceive<SocketHelperMemoryNativeTask> { }
}
diff --git a/src/System.Net.Sockets/tests/FunctionalTests/SocketAsyncEventArgsTest.netcoreapp.cs b/src/System.Net.Sockets/tests/FunctionalTests/SocketAsyncEventArgsTest.netcoreapp.cs
index 90edf5b175..78f1545426 100644
--- a/src/System.Net.Sockets/tests/FunctionalTests/SocketAsyncEventArgsTest.netcoreapp.cs
+++ b/src/System.Net.Sockets/tests/FunctionalTests/SocketAsyncEventArgsTest.netcoreapp.cs
@@ -4,6 +4,7 @@
using System.Buffers;
using System.Collections.Generic;
+using System.Runtime.InteropServices;
using Xunit;
namespace System.Net.Sockets.Tests
@@ -48,7 +49,7 @@ namespace System.Net.Sockets.Tests
byte[] array = new byte[42];
saea.SetBuffer(array, 0, array.Length);
- Assert.True(saea.MemoryBuffer.TryGetArray(out ArraySegment<byte> result));
+ Assert.True(MemoryMarshal.TryGetArray(saea.MemoryBuffer, out ArraySegment<byte> result));
Assert.Same(array, result.Array);
Assert.Same(saea.Buffer, array);
Assert.Equal(0, result.Offset);
@@ -59,7 +60,7 @@ namespace System.Net.Sockets.Tests
Assert.Equal(1, saea.Offset);
Assert.Equal(2, saea.Count);
- Assert.True(saea.MemoryBuffer.TryGetArray(out result));
+ Assert.True(MemoryMarshal.TryGetArray(saea.MemoryBuffer, out result));
Assert.Same(array, result.Array);
Assert.Equal(0, result.Offset);
Assert.Equal(array.Length, result.Count);
diff --git a/src/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj b/src/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj
index 47411a841d..186d721e72 100644
--- a/src/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj
+++ b/src/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj
@@ -21,6 +21,8 @@
<Compile Include="DisposedSocketTests.cs" />
<Compile Include="DnsEndPointTest.cs" />
<Compile Include="DualModeSocketTest.cs" />
+ <Compile Include="ExecutionContextFlowTest.cs" />
+ <Compile Include="ExecutionContextFlowTest.netcoreapp.cs" Condition="'$(TargetGroup)' != 'netstandard'" />
<Compile Include="IPPacketInformationTest.cs" />
<Compile Include="LingerStateTest.cs" />
<Compile Include="LoggingTest.cs" />
@@ -48,7 +50,6 @@
<Compile Include="SocketOptionNameTest.cs" />
<Compile Include="MulticastOptionTest.cs" />
<Compile Include="UdpClientTest.cs" />
- <Compile Include="UnixDomainSocketTest.cs" />
<Compile Include="UnixDomainSocketTest.netcoreapp.cs" Condition="'$(TargetGroup)' != 'netstandard'" />
<!-- Common Sockets files -->
<Compile Include="$(CommonTestPath)\System\Net\Configuration.cs">
@@ -119,5 +120,8 @@
<ItemGroup>
<EmbeddedResource Include="Resources\$(AssemblyName).rd.xml" />
</ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
diff --git a/src/System.Net.Sockets/tests/FunctionalTests/TcpListenerTest.cs b/src/System.Net.Sockets/tests/FunctionalTests/TcpListenerTest.cs
index 78ef0fe6b9..0bb6d7fa64 100644
--- a/src/System.Net.Sockets/tests/FunctionalTests/TcpListenerTest.cs
+++ b/src/System.Net.Sockets/tests/FunctionalTests/TcpListenerTest.cs
@@ -124,6 +124,24 @@ namespace System.Net.Sockets.Tests
listener.Stop();
}
+ [Fact]
+ // This verify that basic constructs do work when IPv6 is NOT available.
+ public void IPv6_Only_Works()
+ {
+ if (Socket.OSSupportsIPv6 || !Socket.OSSupportsIPv4)
+ {
+ // TBD we should figure out better way how to execute this in IPv4 only environment.
+ return;
+ }
+
+ // This should not throw e.g. default to IPv6.
+ TcpListener l = TcpListener.Create(0);
+ l.Stop();
+
+ Socket s = new Socket(SocketType.Stream, ProtocolType.Tcp);
+ s.Close();
+ }
+
private sealed class DerivedTcpListener : TcpListener
{
#pragma warning disable 0618
diff --git a/src/System.Net.Sockets/tests/FunctionalTests/UnixDomainSocketTest.cs b/src/System.Net.Sockets/tests/FunctionalTests/UnixDomainSocketTest.cs
deleted file mode 100644
index af17a979cb..0000000000
--- a/src/System.Net.Sockets/tests/FunctionalTests/UnixDomainSocketTest.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Net.Test.Common;
-
-using Xunit;
-using Xunit.Abstractions;
-
-namespace System.Net.Sockets.Tests
-{
- public partial class UnixDomainSocketTest
- {
- private readonly ITestOutputHelper _log;
-
- public UnixDomainSocketTest(ITestOutputHelper output)
- {
- _log = TestLogging.GetInstance();
- }
-
- [OuterLoop] // TODO: Issue #11345
- [Fact]
- [PlatformSpecific(TestPlatforms.Windows)] // CreateUnixDomainSocket should throw on Windows
- public void Socket_CreateUnixDomainSocket_Throws_OnWindows()
- {
- SocketException e = Assert.Throws<SocketException>(() => new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified));
- Assert.Equal(SocketError.AddressFamilyNotSupported, e.SocketErrorCode);
- }
- }
-}
diff --git a/src/System.Net.Sockets/tests/FunctionalTests/UnixDomainSocketTest.netcoreapp.cs b/src/System.Net.Sockets/tests/FunctionalTests/UnixDomainSocketTest.netcoreapp.cs
index 661eb872ff..8d03c24142 100644
--- a/src/System.Net.Sockets/tests/FunctionalTests/UnixDomainSocketTest.netcoreapp.cs
+++ b/src/System.Net.Sockets/tests/FunctionalTests/UnixDomainSocketTest.netcoreapp.cs
@@ -15,16 +15,8 @@ namespace System.Net.Sockets.Tests
{
public partial class UnixDomainSocketTest
{
- [Fact]
- [PlatformSpecific(TestPlatforms.Windows)] // new UnixDomainSocketEndPoint should throw on Windows
- public void UnixDomainSocketEndPoint_Throws_OnWindows()
- {
- Assert.Throws<PlatformNotSupportedException>(() => new UnixDomainSocketEndPoint("/path"));
- }
-
- [OuterLoop] // TODO: Issue #11345
- [Fact]
- [PlatformSpecific(TestPlatforms.AnyUnix)] // Tests ConnectAsyncUnixDomainSocketEndPoint success on Unix
+ [PlatformSpecific(~TestPlatforms.Windows)] // Windows doesn't currently support ConnectEx with domain sockets
+ [ConditionalFact(nameof(PlatformSupportsUnixDomainSockets))]
public async Task Socket_ConnectAsyncUnixDomainSocketEndPoint_Success()
{
string path = null;
@@ -79,9 +71,7 @@ namespace System.Net.Sockets.Tests
}
}
- [OuterLoop] // TODO: Issue #11345
- [Fact]
- [PlatformSpecific(TestPlatforms.AnyUnix)] // Tests ConnectAsyncUnixDomainSocketEndPoint seccess on Unix
+ [ConditionalFact(nameof(PlatformSupportsUnixDomainSockets))]
public async Task Socket_ConnectAsyncUnixDomainSocketEndPoint_NotServer()
{
string path = GetRandomNonExistingFilePath();
@@ -103,7 +93,9 @@ namespace System.Net.Sockets.Tests
await complete.Task;
}
- Assert.Equal(SocketError.AddressNotAvailable, args.SocketError);
+ Assert.Equal(
+ RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? SocketError.InvalidArgument : SocketError.AddressNotAvailable,
+ args.SocketError);
}
}
finally
@@ -113,9 +105,7 @@ namespace System.Net.Sockets.Tests
}
}
- [OuterLoop] // TODO: Issue #11345
- [Fact]
- [PlatformSpecific(TestPlatforms.AnyUnix)] // Tests SendReceive success for UnixDomainSocketEndPoint on Unix
+ [ConditionalFact(nameof(PlatformSupportsUnixDomainSockets))]
public void Socket_SendReceive_Success()
{
string path = GetRandomNonExistingFilePath();
@@ -152,9 +142,7 @@ namespace System.Net.Sockets.Tests
}
}
- [OuterLoop] // TODO: Issue #11345
- [Fact]
- [PlatformSpecific(TestPlatforms.AnyUnix)] // Tests SendReceiveAsync success for UnixDomainSocketEndPoint on Unix
+ [ConditionalFact(nameof(PlatformSupportsUnixDomainSockets))]
public async Task Socket_SendReceiveAsync_Success()
{
string path = GetRandomNonExistingFilePath();
@@ -191,13 +179,11 @@ namespace System.Net.Sockets.Tests
}
}
- [OuterLoop] // TODO: Issue #11345
- [Theory]
+ [ConditionalTheory(nameof(PlatformSupportsUnixDomainSockets))]
[InlineData(5000, 1, 1)]
[InlineData(500, 18, 21)]
[InlineData(500, 21, 18)]
[InlineData(5, 128000, 64000)]
- [PlatformSpecific(TestPlatforms.AnyUnix)] // Tests SendReceiveAsync success for UnixDomainSocketEndPoint on Unix
public async Task Socket_SendReceiveAsync_PropagateToStream_Success(int iterations, int writeBufferSize, int readBufferSize)
{
var writeBuffer = new byte[writeBufferSize * iterations];
@@ -219,10 +205,15 @@ namespace System.Net.Sockets.Tests
Task clientReceives = Task.Run(async () =>
{
- int bytesRead;
byte[] buffer = new byte[readBufferSize];
- while ((bytesRead = await client.ReceiveAsync(new ArraySegment<byte>(buffer), SocketFlags.None)) > 0)
+ while (true)
{
+ int bytesRead = await client.ReceiveAsync(new Memory<byte>(buffer), SocketFlags.None);
+ if (bytesRead == 0)
+ {
+ break;
+ }
+ Assert.InRange(bytesRead, 1, writeBuffer.Length - readData.Length);
readData.Write(buffer, 0, bytesRead);
}
});
@@ -250,11 +241,9 @@ namespace System.Net.Sockets.Tests
}
}
- [OuterLoop] // TODO: Issue #11345
- [Theory]
+ [ConditionalTheory(nameof(PlatformSupportsUnixDomainSockets))]
[InlineData(false)]
[InlineData(true)]
- [PlatformSpecific(TestPlatforms.AnyUnix)] // Tests ConcurrentSendReceive success for UnixDomainSocketEndPoint on Unix
public async Task ConcurrentSendReceive(bool forceNonBlocking)
{
using (Socket server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified))
@@ -296,9 +285,7 @@ namespace System.Net.Sockets.Tests
}
}
- [OuterLoop] // TODO: Issue #11345
- [Fact]
- [PlatformSpecific(TestPlatforms.AnyUnix)] // Tests ConcurrentSendReceive success for UnixDomainSocketEndPoint on Unix
+ [ConditionalFact(nameof(PlatformSupportsUnixDomainSockets))]
public async Task ConcurrentSendReceiveAsync()
{
using (Socket server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified))
@@ -336,8 +323,7 @@ namespace System.Net.Sockets.Tests
}
}
- [Fact]
- [PlatformSpecific(TestPlatforms.AnyUnix)] // Tests new UnixDomainSocketEndPoint throws the correct exception for invalid args
+ [ConditionalFact(nameof(PlatformSupportsUnixDomainSockets))]
public void UnixDomainSocketEndPoint_InvalidPaths_Throws()
{
Assert.Throws<ArgumentNullException>(() => new UnixDomainSocketEndPoint(null));
@@ -351,8 +337,7 @@ namespace System.Net.Sockets.Tests
Assert.Throws<ArgumentOutOfRangeException>(() => new UnixDomainSocketEndPoint(invalidLengthString));
}
- [Theory]
- [PlatformSpecific(TestPlatforms.AnyUnix)]
+ [ConditionalTheory(nameof(PlatformSupportsUnixDomainSockets))]
[InlineData(false)]
[InlineData(true)]
public void UnixDomainSocketEndPoint_RemoteEndPointEqualsBindAddress(bool abstractAddress)
@@ -412,7 +397,7 @@ namespace System.Net.Sockets.Tests
}
}
- [Fact]
+ [ConditionalFact(nameof(PlatformSupportsUnixDomainSockets))]
[PlatformSpecific(TestPlatforms.AnyUnix & ~TestPlatforms.Linux)] // Don't support abstract socket addresses.
public void UnixDomainSocketEndPoint_UsingAbstractSocketAddressOnUnsupported_Throws()
{
@@ -432,6 +417,16 @@ namespace System.Net.Sockets.Tests
}
}
+ [ConditionalFact(nameof(PlatformDoesntSupportUnixDomainSockets))]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void Socket_CreateUnixDomainSocket_Throws_OnWindows()
+ {
+ AssertExtensions.Throws<ArgumentNullException>("path", () => new UnixDomainSocketEndPoint(null));
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("path", () => new UnixDomainSocketEndPoint(""));
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("path", () => new UnixDomainSocketEndPoint(new string('s', 1000)));
+ Assert.Throws<PlatformNotSupportedException>(() => new UnixDomainSocketEndPoint("hello"));
+ }
+
private static string GetRandomNonExistingFilePath()
{
string result;
@@ -443,5 +438,34 @@ namespace System.Net.Sockets.Tests
return result;
}
+
+
+ private static bool PlatformSupportsUnixDomainSockets => s_platformSupportsUnixDomainSockets.Value;
+
+ private static bool PlatformDoesntSupportUnixDomainSockets => !s_platformSupportsUnixDomainSockets.Value;
+
+ private static readonly Lazy<bool> s_platformSupportsUnixDomainSockets = new Lazy<bool>(() =>
+ {
+ // All Unixes should support UDS. Some Windows will.
+
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ IntPtr s = socket((int)AddressFamily.Unix, (int)SocketType.Stream, (int)ProtocolType.Unspecified);
+ if (s == (IntPtr)(-1))
+ {
+ return false;
+ }
+
+ closesocket(s);
+ }
+
+ return true;
+ });
+
+ [DllImport("ws2_32.dll")]
+ internal static extern IntPtr socket(int af, int type, int protocol);
+
+ [DllImport("ws2_32.dll")]
+ internal static extern int closesocket(IntPtr socketHandle);
}
}
diff --git a/src/System.Net.Sockets/tests/ManualPerformanceTests/System.Net.Sockets.Async.Performance.Tests.csproj b/src/System.Net.Sockets/tests/ManualPerformanceTests/System.Net.Sockets.Async.Performance.Tests.csproj
index f5b5401921..c64e8caa64 100644
--- a/src/System.Net.Sockets/tests/ManualPerformanceTests/System.Net.Sockets.Async.Performance.Tests.csproj
+++ b/src/System.Net.Sockets/tests/ManualPerformanceTests/System.Net.Sockets.Async.Performance.Tests.csproj
@@ -68,5 +68,8 @@
<Name>PerfRunner</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project>
+</Project> \ No newline at end of file
diff --git a/src/System.Net.Sockets/tests/Performance/Perf.Socket.SendReceive.cs b/src/System.Net.Sockets/tests/Performance/Perf.Socket.SendReceive.cs
index 5f359277ac..ac8ed2c992 100644
--- a/src/System.Net.Sockets/tests/Performance/Perf.Socket.SendReceive.cs
+++ b/src/System.Net.Sockets/tests/Performance/Perf.Socket.SendReceive.cs
@@ -17,8 +17,8 @@ namespace System.Net.Sockets.Tests
{
await OpenLoopbackConnectionAsync(async (client, server) =>
{
- byte[] clientBuffer = new byte[1];
- byte[] serverBuffer = new byte[1];
+ ReadOnlyMemory<byte> clientBuffer = new byte[1];
+ Memory<byte> serverBuffer = new byte[1];
foreach (BenchmarkIteration iteration in Benchmark.Iterations)
{
long iters = Benchmark.InnerIterationCount;
@@ -39,8 +39,8 @@ namespace System.Net.Sockets.Tests
{
await OpenLoopbackConnectionAsync(async (client, server) =>
{
- byte[] clientBuffer = new byte[1];
- byte[] serverBuffer = new byte[1];
+ ReadOnlyMemory<byte> clientBuffer = new byte[1];
+ Memory<byte> serverBuffer = new byte[1];
foreach (BenchmarkIteration iteration in Benchmark.Iterations)
{
long iters = Benchmark.InnerIterationCount;
@@ -48,7 +48,7 @@ namespace System.Net.Sockets.Tests
{
for (int i = 0; i < iters; i++)
{
- Task r = server.ReceiveAsync(serverBuffer, SocketFlags.None);
+ ValueTask<int> r = server.ReceiveAsync(serverBuffer, SocketFlags.None);
await client.SendAsync(clientBuffer, SocketFlags.None);
await r;
}
@@ -57,30 +57,6 @@ namespace System.Net.Sockets.Tests
});
}
- [Benchmark(InnerIterationCount = 1_000_000)]
- [InlineData(16)]
- public async Task ReceiveAsyncThenSendAsync_Task_Parallel(int numConnections)
- {
- byte[] clientBuffer = new byte[1];
- byte[] serverBuffer = new byte[1];
- foreach (BenchmarkIteration iteration in Benchmark.Iterations)
- {
- await OpenLoopbackConnectionAsync(async (client, server) =>
- {
- long iters = Benchmark.InnerIterationCount;
- using (iteration.StartMeasurement())
- {
- for (int i = 0; i < iters; i++)
- {
- Task r = server.ReceiveAsync(serverBuffer, SocketFlags.None);
- await client.SendAsync(clientBuffer, SocketFlags.None);
- await r;
- }
- }
- });
- }
- }
-
[Benchmark(InnerIterationCount = 10_000), MeasureGCAllocations]
public async Task SendAsyncThenReceiveAsync_SocketAsyncEventArgs()
{
diff --git a/src/System.Net.Sockets/tests/Performance/System.Net.Sockets.Performance.Tests.csproj b/src/System.Net.Sockets/tests/Performance/System.Net.Sockets.Performance.Tests.csproj
index 11c4fca607..03fc01f29b 100644
--- a/src/System.Net.Sockets/tests/Performance/System.Net.Sockets.Performance.Tests.csproj
+++ b/src/System.Net.Sockets/tests/Performance/System.Net.Sockets.Performance.Tests.csproj
@@ -20,5 +20,8 @@
<Name>PerfRunner</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.Net.WebClient/src/System/Net/WebClient.cs b/src/System.Net.WebClient/src/System/Net/WebClient.cs
index 68cf3bd93f..eaf5e9bffc 100644
--- a/src/System.Net.WebClient/src/System/Net/WebClient.cs
+++ b/src/System.Net.WebClient/src/System/Net/WebClient.cs
@@ -875,6 +875,11 @@ namespace System.Net
}
writeStream.SetLength(copyBuffer.Length);
}
+
+ if (contentLength >= 0)
+ {
+ _progress.TotalBytesToReceive = contentLength;
+ }
using (writeStream)
using (Stream readStream = response.GetResponseStream())
@@ -883,7 +888,7 @@ namespace System.Net
{
while (true)
{
- int bytesRead = await readStream.ReadAsync(copyBuffer, 0, copyBuffer.Length).ConfigureAwait(false);
+ int bytesRead = await readStream.ReadAsync(new Memory<byte>(copyBuffer)).ConfigureAwait(false);
if (bytesRead == 0)
{
break;
@@ -895,7 +900,7 @@ namespace System.Net
PostProgressChanged(asyncOp, _progress);
}
- await writeStream.WriteAsync(copyBuffer, 0, bytesRead).ConfigureAwait(false);
+ await writeStream.WriteAsync(new ReadOnlyMemory<byte>(copyBuffer, 0, bytesRead)).ConfigureAwait(false);
}
}
@@ -1005,7 +1010,7 @@ namespace System.Net
{
if (header != null)
{
- await writeStream.WriteAsync(header, 0, header.Length).ConfigureAwait(false);
+ await writeStream.WriteAsync(new ReadOnlyMemory<byte>(header)).ConfigureAwait(false);
_progress.BytesSent += header.Length;
PostProgressChanged(asyncOp, _progress);
}
@@ -1016,9 +1021,9 @@ namespace System.Net
{
while (true)
{
- int bytesRead = await readStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
+ int bytesRead = await readStream.ReadAsync(new Memory<byte>(buffer)).ConfigureAwait(false);
if (bytesRead <= 0) break;
- await writeStream.WriteAsync(buffer, 0, bytesRead).ConfigureAwait(false);
+ await writeStream.WriteAsync(new ReadOnlyMemory<byte>(buffer, 0, bytesRead)).ConfigureAwait(false);
_progress.BytesSent += bytesRead;
PostProgressChanged(asyncOp, _progress);
@@ -1034,7 +1039,7 @@ namespace System.Net
{
toWrite = chunkSize;
}
- await writeStream.WriteAsync(buffer, pos, toWrite).ConfigureAwait(false);
+ await writeStream.WriteAsync(new ReadOnlyMemory<byte>(buffer, pos, toWrite)).ConfigureAwait(false);
pos += toWrite;
_progress.BytesSent += toWrite;
PostProgressChanged(asyncOp, _progress);
@@ -1043,7 +1048,7 @@ namespace System.Net
if (footer != null)
{
- await writeStream.WriteAsync(footer, 0, footer.Length).ConfigureAwait(false);
+ await writeStream.WriteAsync(new ReadOnlyMemory<byte>(footer)).ConfigureAwait(false);
_progress.BytesSent += footer.Length;
PostProgressChanged(asyncOp, _progress);
}
diff --git a/src/System.Net.WebClient/tests/System.Net.WebClient.Tests.csproj b/src/System.Net.WebClient/tests/System.Net.WebClient.Tests.csproj
index 7c5b8ceec6..bfa64249a8 100644
--- a/src/System.Net.WebClient/tests/System.Net.WebClient.Tests.csproj
+++ b/src/System.Net.WebClient/tests/System.Net.WebClient.Tests.csproj
@@ -20,6 +20,9 @@
<Compile Include="$(CommonTestPath)\System\Net\Http\LoopbackServer.cs">
<Link>Common\System\Net\Http\LoopbackServer.cs</Link>
</Compile>
+ <Compile Include="$(CommonTestPath)\System\Threading\Tasks\TaskTimeoutExtensions.cs">
+ <Link>Common\System\Threading\Tasks\TaskTimeoutExtensions.cs</Link>
+ </Compile>
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Net.WebClient/tests/WebClientTest.cs b/src/System.Net.WebClient/tests/WebClientTest.cs
index 64efdb0509..45d32915da 100644
--- a/src/System.Net.WebClient/tests/WebClientTest.cs
+++ b/src/System.Net.WebClient/tests/WebClientTest.cs
@@ -374,12 +374,7 @@ namespace System.Net.Tests
{
Task<string> download = wc.DownloadStringTaskAsync(url.ToString());
Assert.Null(wc.ResponseHeaders);
- await LoopbackServer.ReadRequestAndSendResponseAsync(server,
- "HTTP/1.1 200 OK\r\n" +
- $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
- $"Content-Length: 0\r\n" +
- "ArbitraryHeader: ArbitraryValue\r\n" +
- "\r\n");
+ await server.AcceptConnectionSendResponseAndCloseAsync(additionalHeaders: "ArbitraryHeader: ArbitraryValue\r\n");
await download;
});
@@ -430,11 +425,7 @@ namespace System.Net.Tests
{
Task<string> download = wc.DownloadStringTaskAsync(url.ToString());
Assert.Null(wc.ResponseHeaders);
- await LoopbackServer.ReadRequestAndSendResponseAsync(server,
- "HTTP/1.1 200 OK\r\n" +
- $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
- $"Content-Length: 0\r\n" +
- "\r\n");
+ await server.AcceptConnectionSendResponseAndCloseAsync();
await download;
});
}
@@ -476,6 +467,8 @@ namespace System.Net.Tests
public abstract class WebClientTestBase
{
+ public const int TimeoutMilliseconds = 30 * 1000;
+
public static readonly object[][] EchoServers = System.Net.Test.Common.Configuration.Http.EchoServers;
const string ExpectedText =
"To be, or not to be, that is the question:" +
@@ -520,12 +513,7 @@ namespace System.Net.Tests
}
Task<string> download = DownloadStringAsync(wc, url.ToString());
- await LoopbackServer.ReadRequestAndSendResponseAsync(server,
- "HTTP/1.1 200 OK\r\n" +
- $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
- $"Content-Length: {ExpectedText.Length}\r\n" +
- "\r\n" +
- $"{ExpectedText}");
+ await server.AcceptConnectionSendResponseAndCloseAsync(content: ExpectedText);
Assert.Equal(ExpectedText, await download);
});
}
@@ -541,14 +529,13 @@ namespace System.Net.Tests
wc.DownloadProgressChanged += (s, e) => downloadProgressInvoked.TrySetResult(true);
Task<byte[]> download = DownloadDataAsync(wc, url.ToString());
- await LoopbackServer.ReadRequestAndSendResponseAsync(server,
- "HTTP/1.1 200 OK\r\n" +
- $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
- $"Content-Length: {ExpectedText.Length}\r\n" +
- "\r\n" +
- $"{ExpectedText}");
+ await server.AcceptConnectionSendResponseAndCloseAsync(content: ExpectedText);
Assert.Equal(ExpectedText, Encoding.ASCII.GetString(await download));
- Assert.True(!IsAsync || await downloadProgressInvoked.Task, "Expected download progress callback to be invoked");
+
+ if (IsAsync)
+ {
+ await downloadProgressInvoked.Task.TimeoutAfter(TimeoutMilliseconds);
+ }
});
}
@@ -559,15 +546,24 @@ namespace System.Net.Tests
{
string largeText = GetRandomText(1024 * 1024);
+ var downloadProgressInvokedWithContentLength = new TaskCompletionSource<bool>();
var wc = new WebClient();
+ wc.DownloadProgressChanged += (s, e) =>
+ {
+ if (e.TotalBytesToReceive == largeText.Length && e.BytesReceived < e.TotalBytesToReceive)
+ {
+ downloadProgressInvokedWithContentLength.TrySetResult(true);
+ }
+ };
+
Task<byte[]> download = DownloadDataAsync(wc, url.ToString());
- await LoopbackServer.ReadRequestAndSendResponseAsync(server,
- "HTTP/1.1 200 OK\r\n" +
- $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
- $"Content-Length: {largeText.Length}\r\n" +
- "\r\n" +
- $"{largeText}");
+ await server.AcceptConnectionSendResponseAndCloseAsync(content: largeText);
Assert.Equal(largeText, Encoding.ASCII.GetString(await download));
+
+ if (IsAsync)
+ {
+ await downloadProgressInvokedWithContentLength.Task.TimeoutAfter(TimeoutMilliseconds);
+ }
});
}
@@ -581,12 +577,7 @@ namespace System.Net.Tests
{
var wc = new WebClient();
Task download = DownloadFileAsync(wc, url.ToString(), tempPath);
- await LoopbackServer.ReadRequestAndSendResponseAsync(server,
- "HTTP/1.1 200 OK\r\n" +
- $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
- $"Content-Length: {ExpectedText.Length}\r\n" +
- "\r\n" +
- $"{ExpectedText}");
+ await server.AcceptConnectionSendResponseAndCloseAsync(content: ExpectedText);
await download;
Assert.Equal(ExpectedText, File.ReadAllText(tempPath));
@@ -605,12 +596,7 @@ namespace System.Net.Tests
{
var wc = new WebClient();
Task<Stream> download = OpenReadAsync(wc, url.ToString());
- await LoopbackServer.ReadRequestAndSendResponseAsync(server,
- "HTTP/1.1 200 OK\r\n" +
- $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
- $"Content-Length: {ExpectedText.Length}\r\n" +
- "\r\n" +
- $"{ExpectedText}");
+ await server.AcceptConnectionSendResponseAndCloseAsync(content: ExpectedText);
using (var reader = new StreamReader(await download))
{
@@ -644,7 +630,10 @@ namespace System.Net.Tests
byte[] result = await UploadDataAsync(wc, echoServer.ToString(), Encoding.UTF8.GetBytes(ExpectedText));
Assert.Contains(ExpectedText, Encoding.UTF8.GetString(result));
- Assert.True(!IsAsync || await uploadProgressInvoked.Task, "Expected upload progress callback to be invoked");
+ if(IsAsync)
+ {
+ await uploadProgressInvoked.Task.TimeoutAfter(TimeoutMilliseconds);
+ }
}
[OuterLoop("Networking test talking to remote server: issue #11345")]
diff --git a/src/System.Net.WebSockets.Client/ref/System.Net.WebSockets.Client.cs b/src/System.Net.WebSockets.Client/ref/System.Net.WebSockets.Client.cs
index a80079730a..7dfcff2fd8 100644
--- a/src/System.Net.WebSockets.Client/ref/System.Net.WebSockets.Client.cs
+++ b/src/System.Net.WebSockets.Client/ref/System.Net.WebSockets.Client.cs
@@ -32,6 +32,7 @@ namespace System.Net.WebSockets
public System.Net.ICredentials Credentials { get { throw null; } set { } }
public System.TimeSpan KeepAliveInterval { get { throw null; } set { } }
public System.Net.IWebProxy Proxy { get { throw null; } set { } }
+ public System.Net.Security.RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get { throw null; } set { } }
public bool UseDefaultCredentials { get { throw null; } set { } }
public void AddSubProtocol(string subProtocol) { }
public void SetBuffer(int receiveBufferSize, int sendBufferSize) { }
diff --git a/src/System.Net.WebSockets.Client/ref/System.Net.WebSockets.Client.csproj b/src/System.Net.WebSockets.Client/ref/System.Net.WebSockets.Client.csproj
index b4619853bb..18a1d23354 100644
--- a/src/System.Net.WebSockets.Client/ref/System.Net.WebSockets.Client.csproj
+++ b/src/System.Net.WebSockets.Client/ref/System.Net.WebSockets.Client.csproj
@@ -13,6 +13,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\System.Net.Primitives\ref\System.Net.Primitives.csproj" />
+ <ProjectReference Include="..\..\System.Net.Security\ref\System.Net.Security.csproj" />
<ProjectReference Include="..\..\System.Net.WebSockets\ref\System.Net.WebSockets.csproj" />
<ProjectReference Include="..\..\System.Runtime\ref\System.Runtime.csproj" />
<ProjectReference Include="..\..\System.Security.Cryptography.X509Certificates\ref\System.Security.Cryptography.X509Certificates.csproj" />
diff --git a/src/System.Net.WebSockets.Client/src/Resources/Strings.resx b/src/System.Net.WebSockets.Client/src/Resources/Strings.resx
index cc93c4738e..dc7a2067a1 100644
--- a/src/System.Net.WebSockets.Client/src/Resources/Strings.resx
+++ b/src/System.Net.WebSockets.Client/src/Resources/Strings.resx
@@ -183,4 +183,7 @@
<data name="net_WebSockets_UWPClientCertSupportRequiresCertInPersonalCertificateStore" xml:space="preserve">
<value>Client certificate was not found in the personal (\"MY\") certificate store. In UWP, client certificates are only supported if they have been added to that certificate store.</value>
</data>
+ <data name="net_WebSockets_RemoteValidationCallbackNotSupported" xml:space="preserve">
+ <value>ClientWebSocketOptions.RemoteCertificateValidationCallback is not supported on this platform.</value>
+ </data>
</root>
diff --git a/src/System.Net.WebSockets.Client/src/System.Net.WebSockets.Client.csproj b/src/System.Net.WebSockets.Client/src/System.Net.WebSockets.Client.csproj
index 60f70c705f..51ea4edfdd 100644
--- a/src/System.Net.WebSockets.Client/src/System.Net.WebSockets.Client.csproj
+++ b/src/System.Net.WebSockets.Client/src/System.Net.WebSockets.Client.csproj
@@ -4,20 +4,17 @@
<PropertyGroup>
<ProjectGuid>{B8AD98AE-84C3-4313-B3F1-EE8BD5BFF69B}</ProjectGuid>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
- <!-- // uncomment to use the managed "unix" implementation on Windows
- <TargetsWindows>false</TargetsWindows>
- <TargetsUnix>true</TargetsUnix>
- -->
+ <ILLinkClearInitLocals>true</ILLinkClearInitLocals>
</PropertyGroup>
<PropertyGroup>
<DefineConstants Condition="'$(TargetGroup)' == 'uap'">$(DefineConstants);uap</DefineConstants>
</PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='uap-Windows_NT-Debug|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='uap-Windows_NT-Release|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netcoreapp-Unix-Debug|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netcoreapp-Unix-Release|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netcoreapp-Windows_NT-Debug|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netcoreapp-Windows_NT-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="System\Net\WebSockets\ClientWebSocket.cs" />
<Compile Include="System\Net\WebSockets\ClientWebSocketOptions.cs" />
@@ -33,70 +30,18 @@
<Link>Common\System\Net\WebSockets\WebSocketValidate.cs</Link>
</Compile>
</ItemGroup>
- <ItemGroup Condition=" '$(TargetsWindows)' == 'true'">
+ <ItemGroup Condition="'$(TargetGroup)' == 'uap'">
<Compile Include="System\Net\WebSockets\WebSocketHandle.Windows.cs" />
- </ItemGroup>
- <!-- Windows : Win32 only -->
- <ItemGroup Condition="'$(TargetsWindows)' == 'true' AND '$(TargetGroup)' != 'uap'">
- <Compile Include="System\Net\WebSockets\WebSocketHandle.Win32.cs" />
- <Compile Include="System\Net\WebSockets\WebSocketMessageTypeAdapter.cs" />
- <Compile Include="System\Net\WebSockets\WinHttpWebSocket.cs" />
- <Compile Include="System\Net\WebSockets\WinHttpWebSocketCallback.cs" />
- <Compile Include="System\Net\WebSockets\WinHttpWebSocketState.cs" />
- <!-- Common -->
- <Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeLibraryHandle.cs">
- <Link>Common\Microsoft\Win32\SafeHandles\SafeLibraryHandle.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\System\Net\Http\WinHttpException.cs">
- <Link>Common\System\Net\Http\WinHttpException.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\System\Runtime\ExceptionServices\ExceptionStackTrace.cs">
- <Link>Common\System\Runtime\ExceptionServices\ExceptionStackTrace.cs</Link>
- </Compile>
- <!-- Interop -->
- <Compile Include="$(CommonPath)\Interop\Windows\Interop.Libraries.cs">
- <Link>Interop\Windows\Interop.Libraries.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.GetModuleHandle.cs">
- <Link>Interop\Windows\kernel32\Interop.GetModuleHandle.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\Interop.HRESULT_FROM_WIN32.cs">
- <Link>Interop\Windows\Interop.HRESULT_FROM_WIN32.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.FormatMessage.cs">
- <Link>Interop\Windows\kernel32\Interop.FormatMessage.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.FreeLibrary.cs">
- <Link>Interop\Windows\kernel32\Interop.FreeLibrary.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.GetProcAddress.cs">
- <Link>Interop\Windows\kernel32\Interop.GetProcAddress.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.LoadLibraryEx.cs">
- <Link>Interop\Windows\kernel32\Interop.LoadLibraryEx.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\winhttp\Interop.SafeWinHttpHandle.cs">
- <Link>Interop\Windows\winhttp\Interop.SafeWinHttpHandle.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\winhttp\Interop.winhttp.cs">
- <Link>Interop\Windows\winhttp\Interop.winhttp.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\winhttp\Interop.winhttp_types.cs">
- <Link>Interop\Windows\winhttp\Interop.winhttp_types.cs</Link>
- </Compile>
- </ItemGroup>
- <!-- Windows : Win32 + WinRT -->
- <ItemGroup Condition="'$(TargetsWindows)' == 'true' AND '$(TargetGroup)' == 'uap'">
<Compile Include="$(CommonPath)\System\Net\Security\CertificateHelper.cs">
<Link>Common\System\Net\Security\CertificateHelper.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Net\Security\CertificateHelper.Uap.cs">
<Link>Common\System\Net\Security\CertificateHelper.Uap.cs</Link>
- </Compile>
+ </Compile>
<Compile Include="System\Net\WebSockets\WebSocketHandle.WinRT.cs" />
<Compile Include="System\Net\WebSockets\WinRTWebSocket.cs" />
</ItemGroup>
- <ItemGroup Condition=" '$(TargetsUnix)' == 'true' ">
+ <ItemGroup Condition="'$(TargetGroup)' != 'uap'">
<Compile Include="System\Net\WebSockets\WebSocketHandle.Managed.cs" />
<Compile Include="$(CommonPath)\System\StringExtensions.cs">
<Link>Common\System\StringExtensions.cs</Link>
@@ -125,6 +70,7 @@
<Reference Include="System.Globalization" />
<Reference Include="System.Memory" />
<Reference Include="System.Net.Primitives" />
+ <Reference Include="System.Net.Security" />
<Reference Include="System.Net.WebHeaderCollection" />
<Reference Include="System.Net.WebSockets" />
<Reference Include="System.Resources.ResourceManager" />
@@ -137,10 +83,9 @@
<Reference Include="System.Threading" />
<Reference Include="System.Threading.Tasks" />
</ItemGroup>
- <ItemGroup Condition="'$(TargetsUnix)' == 'true'">
+ <ItemGroup Condition="'$(TargetGroup)' != 'uap'">
<Reference Include="System.Buffers" />
<Reference Include="System.Net.NameResolution" />
- <Reference Include="System.Net.Security" />
<Reference Include="System.Net.Sockets" />
<Reference Include="System.Numerics.Vectors" />
<Reference Include="System.Security.Cryptography.Algorithms" />
@@ -149,4 +94,4 @@
<Reference Include="System.Threading.Timer" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project>
+</Project> \ No newline at end of file
diff --git a/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ClientWebSocket.cs b/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ClientWebSocket.cs
index b0409ce728..8d0146ea38 100644
--- a/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ClientWebSocket.cs
+++ b/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ClientWebSocket.cs
@@ -31,7 +31,7 @@ namespace System.Net.WebSockets
WebSocketHandle.CheckPlatformSupport();
_state = (int)InternalState.Created;
- _options = new ClientWebSocketOptions();
+ _options = new ClientWebSocketOptions() { Proxy = DefaultWebProxy.Instance };
if (NetEventSource.IsEnabled) NetEventSource.Exit(this);
}
@@ -165,7 +165,7 @@ namespace System.Net.WebSockets
return _innerWebSocket.SendAsync(buffer, messageType, endOfMessage, cancellationToken);
}
- public override Task SendAsync(ReadOnlyMemory<byte> buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken)
+ public override ValueTask SendAsync(ReadOnlyMemory<byte> buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken)
{
ThrowIfNotConnected();
return _innerWebSocket.SendAsync(buffer, messageType, endOfMessage, cancellationToken);
@@ -236,5 +236,14 @@ namespace System.Net.WebSockets
throw new InvalidOperationException(SR.net_WebSockets_NotConnected);
}
}
+
+ /// <summary>Used as a sentinel to indicate that ClientWebSocket should use the system's default proxy.</summary>
+ internal sealed class DefaultWebProxy : IWebProxy
+ {
+ public static DefaultWebProxy Instance { get; } = new DefaultWebProxy();
+ public ICredentials Credentials { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
+ public Uri GetProxy(Uri destination) => throw new NotSupportedException();
+ public bool IsBypassed(Uri host) => throw new NotSupportedException();
+ }
}
}
diff --git a/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ClientWebSocketOptions.cs b/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ClientWebSocketOptions.cs
index c488277150..56aef0d781 100644
--- a/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ClientWebSocketOptions.cs
+++ b/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ClientWebSocketOptions.cs
@@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
+using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
@@ -24,6 +25,7 @@ namespace System.Net.WebSockets
private int _receiveBufferSize = 0x1000;
private int _sendBufferSize = 0x1000;
private ArraySegment<byte>? _buffer;
+ private RemoteCertificateValidationCallback _remoteCertificateValidationCallback;
internal ClientWebSocketOptions()
{
@@ -108,6 +110,16 @@ namespace System.Net.WebSockets
}
}
+ public RemoteCertificateValidationCallback RemoteCertificateValidationCallback
+ {
+ get => _remoteCertificateValidationCallback;
+ set
+ {
+ ThrowIfReadOnly();
+ _remoteCertificateValidationCallback = value;
+ }
+ }
+
public CookieContainer Cookies
{
get
diff --git a/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Managed.cs b/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Managed.cs
index 8405225836..deabfb68f9 100644
--- a/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Managed.cs
+++ b/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Managed.cs
@@ -9,6 +9,7 @@ using System.Net.Security;
using System.Net.Sockets;
using System.Runtime.ExceptionServices;
using System.Security.Cryptography;
+using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -29,6 +30,9 @@ namespace System.Net.WebSockets
/// <summary>GUID appended by the server as part of the security key response. Defined in the RFC.</summary>
private const string WSServerGuid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+ /// <summary>Shared, lazily-initialized handler for when using default options.</summary>
+ private static SocketsHttpHandler s_defaultHandler;
+
private readonly CancellationTokenSource _abortSource = new CancellationTokenSource();
private WebSocketState _state = WebSocketState.Connecting;
private WebSocket _webSocket;
@@ -62,7 +66,7 @@ namespace System.Net.WebSockets
public Task SendAsync(ArraySegment<byte> buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken) =>
_webSocket.SendAsync(buffer, messageType, endOfMessage, cancellationToken);
- public Task SendAsync(ReadOnlyMemory<byte> buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken) =>
+ public ValueTask SendAsync(ReadOnlyMemory<byte> buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken) =>
_webSocket.SendAsync(buffer, messageType, endOfMessage, cancellationToken);
public Task<WebSocketReceiveResult> ReceiveAsync(ArraySegment<byte> buffer, CancellationToken cancellationToken) =>
@@ -76,93 +80,16 @@ namespace System.Net.WebSockets
public Task CloseOutputAsync(WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken) =>
_webSocket.CloseOutputAsync(closeStatus, statusDescription, cancellationToken);
-
+
public async Task ConnectAsyncCore(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options)
{
- // TODO #14480 : Not currently implemented, or explicitly ignored:
- // - ClientWebSocketOptions.UseDefaultCredentials
- // - ClientWebSocketOptions.Credentials
- // - ClientWebSocketOptions.Proxy
- // - ClientWebSocketOptions._sendBufferSize
-
- // Establish connection to the server
- CancellationTokenRegistration registration = cancellationToken.Register(s => ((WebSocketHandle)s).Abort(), this);
+ HttpResponseMessage response = null;
+ SocketsHttpHandler handler = null;
+ bool disposeHandler = true;
try
{
- // Connect to the remote server
- Socket connectedSocket = await ConnectSocketAsync(uri.Host, uri.Port, cancellationToken).ConfigureAwait(false);
- Stream stream = new NetworkStream(connectedSocket, ownsSocket:true);
-
- // Upgrade to SSL if needed
- if (uri.Scheme == UriScheme.Wss)
- {
- var sslStream = new SslStream(stream);
- await sslStream.AuthenticateAsClientAsync(
- uri.Host,
- options.ClientCertificates,
- SecurityProtocol.AllowedSecurityProtocols,
- checkCertificateRevocation: false).ConfigureAwait(false);
- stream = sslStream;
- }
-
- // Create the security key and expected response, then build all of the request headers
- KeyValuePair<string, string> secKeyAndSecWebSocketAccept = CreateSecKeyAndSecWebSocketAccept();
- byte[] requestHeader = BuildRequestHeader(uri, options, secKeyAndSecWebSocketAccept.Key);
-
- // Write out the header to the connection
- await stream.WriteAsync(requestHeader, 0, requestHeader.Length, cancellationToken).ConfigureAwait(false);
-
- // Parse the response and store our state for the remainder of the connection
- string subprotocol = await ParseAndValidateConnectResponseAsync(stream, options, secKeyAndSecWebSocketAccept.Value, cancellationToken).ConfigureAwait(false);
-
- _webSocket = WebSocket.CreateClientWebSocket(
- stream, subprotocol, options.ReceiveBufferSize, options.SendBufferSize, options.KeepAliveInterval, false, options.Buffer.GetValueOrDefault());
-
- // If a concurrent Abort or Dispose came in before we set _webSocket, make sure to update it appropriately
- if (_state == WebSocketState.Aborted)
- {
- _webSocket.Abort();
- }
- else if (_state == WebSocketState.Closed)
- {
- _webSocket.Dispose();
- }
- }
- catch (Exception exc)
- {
- if (_state < WebSocketState.Closed)
- {
- _state = WebSocketState.Closed;
- }
-
- Abort();
-
- if (exc is WebSocketException)
- {
- throw;
- }
- throw new WebSocketException(SR.net_webstatus_ConnectFailure, exc);
- }
- finally
- {
- registration.Dispose();
- }
- }
-
- /// <summary>Connects a socket to the specified host and port, subject to cancellation and aborting.</summary>
- /// <param name="host">The host to which to connect.</param>
- /// <param name="port">The port to which to connect on the host.</param>
- /// <param name="cancellationToken">The CancellationToken to use to cancel the websocket.</param>
- /// <returns>The connected Socket.</returns>
- private async Task<Socket> ConnectSocketAsync(string host, int port, CancellationToken cancellationToken)
- {
- IPAddress[] addresses = await Dns.GetHostAddressesAsync(host).ConfigureAwait(false);
-
- ExceptionDispatchInfo lastException = null;
- foreach (IPAddress address in addresses)
- {
- var socket = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
- try
+ var request = new HttpRequestMessage(HttpMethod.Get, uri);
+ if (options._requestHeaders?.Count > 0) // use field to avoid lazily initializing the collection
{
using (cancellationToken.Register(s => ((Socket)s).Dispose(), socket))
using (_abortSource.Token.Register(s => ((Socket)s).Dispose(), socket))
@@ -186,10 +113,70 @@ namespace System.Net.WebSockets
_abortSource.Token.ThrowIfCancellationRequested();
return socket;
}
- catch (Exception exc)
+
+ // Create the security key and expected response, then build all of the request headers
+ KeyValuePair<string, string> secKeyAndSecWebSocketAccept = CreateSecKeyAndSecWebSocketAccept();
+ AddWebSocketHeaders(request, secKeyAndSecWebSocketAccept.Key, options);
+
+ // Create the handler for this request and populate it with all of the options.
+ // Try to use a shared handler rather than creating a new one just for this request, if
+ // the options are compatible.
+ if (options.Credentials == null &&
+ !options.UseDefaultCredentials &&
+ options.Proxy == null &&
+ options.Cookies == null &&
+ options.RemoteCertificateValidationCallback == null &&
+ options._clientCertificates?.Count == 0)
+ {
+ disposeHandler = false;
+ handler = s_defaultHandler;
+ if (handler == null)
+ {
+ handler = new SocketsHttpHandler()
+ {
+ PooledConnectionLifetime = TimeSpan.Zero,
+ UseProxy = false,
+ UseCookies = false,
+ };
+ if (Interlocked.CompareExchange(ref s_defaultHandler, handler, null) != null)
+ {
+ handler.Dispose();
+ handler = s_defaultHandler;
+ }
+ }
+ }
+ else
{
- socket.Dispose();
- lastException = ExceptionDispatchInfo.Capture(exc);
+ handler = new SocketsHttpHandler();
+ handler.PooledConnectionLifetime = TimeSpan.Zero;
+ handler.CookieContainer = options.Cookies;
+ handler.UseCookies = options.Cookies != null;
+ handler.SslOptions.RemoteCertificateValidationCallback = options.RemoteCertificateValidationCallback;
+
+ if (options.UseDefaultCredentials)
+ {
+ handler.Credentials = CredentialCache.DefaultCredentials;
+ }
+ else
+ {
+ handler.Credentials = options.Credentials;
+ }
+
+ if (options.Proxy == null)
+ {
+ handler.UseProxy = false;
+ }
+ else if (options.Proxy != ClientWebSocket.DefaultWebProxy.Instance)
+ {
+ handler.Proxy = options.Proxy;
+ }
+
+ if (options._clientCertificates?.Count > 0) // use field to avoid lazily initializing the collection
+ {
+ Debug.Assert(handler.SslOptions.ClientCertificates == null);
+ handler.SslOptions.ClientCertificates = new X509Certificate2Collection();
+ handler.SslOptions.ClientCertificates.AddRange(options.ClientCertificates);
+ }
}
}
@@ -217,17 +204,20 @@ namespace System.Net.WebSockets
builder.Append("Host: ");
if (string.IsNullOrEmpty(hostHeader))
{
- builder.Append(uri.IdnHost).Append(':').Append(uri.Port).Append("\r\n");
+ linkedCancellation =
+ externalAndAbortCancellation =
+ CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _abortSource.Token);
}
else
{
builder.Append(hostHeader).Append("\r\n");
}
- builder.Append("Connection: Upgrade\r\n");
- builder.Append("Upgrade: websocket\r\n");
- builder.Append("Sec-WebSocket-Version: 13\r\n");
- builder.Append("Sec-WebSocket-Key: ").Append(secKey).Append("\r\n");
+ using (linkedCancellation)
+ {
+ response = await new HttpMessageInvoker(handler).SendAsync(request, externalAndAbortCancellation.Token).ConfigureAwait(false);
+ externalAndAbortCancellation.Token.ThrowIfCancellationRequested(); // poll in case sends/receives in request/response didn't observe cancellation
+ }
// Add all of the additionally requested headers
foreach (string key in options.RequestHeaders.AllKeys)
@@ -253,8 +243,28 @@ namespace System.Net.WebSockets
builder.Append("\r\n");
}
- // Add an optional cookies header
- if (options.Cookies != null)
+ // Get or create the buffer to use
+ const int MinBufferSize = 125; // from ManagedWebSocket.MaxControlPayloadLength
+ ArraySegment<byte> optionsBuffer = options.Buffer.GetValueOrDefault();
+ Memory<byte> buffer =
+ optionsBuffer.Count >= MinBufferSize ? optionsBuffer : // use the provided buffer if it's big enough
+ default; // or let WebSocket.CreateFromStream use its default
+ // options.ReceiveBufferSize is ignored, as we rely on the buffer inside the SocketsHttpHandler stream
+
+ // Get the response stream and wrap it in a web socket.
+ Stream connectedStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ Debug.Assert(connectedStream.CanWrite);
+ Debug.Assert(connectedStream.CanRead);
+ _webSocket = WebSocket.CreateFromStream(
+ connectedStream,
+ isServer: false,
+ subprotocol,
+ options.KeepAliveInterval,
+ buffer);
+ }
+ catch (Exception exc)
+ {
+ if (_state < WebSocketState.Closed)
{
string header = options.Cookies.GetCookieHeader(uri);
if (!string.IsNullOrWhiteSpace(header))
@@ -271,6 +281,23 @@ namespace System.Net.WebSockets
}
finally
{
+ // Disposing the handler will not affect any active stream wrapped in the WebSocket.
+ if (disposeHandler)
+ {
+ handler?.Dispose();
+ }
+ }
+ }
+
+ /// <param name="secKey">The generated security key to send in the Sec-WebSocket-Key header.</param>
+ private static void AddWebSocketHeaders(HttpRequestMessage request, string secKey, ClientWebSocketOptions options)
+ {
+ request.Headers.TryAddWithoutValidation(HttpKnownHeaderNames.Connection, HttpKnownHeaderNames.Upgrade);
+ request.Headers.TryAddWithoutValidation(HttpKnownHeaderNames.Upgrade, "websocket");
+ request.Headers.TryAddWithoutValidation(HttpKnownHeaderNames.SecWebSocketVersion, "13");
+ request.Headers.TryAddWithoutValidation(HttpKnownHeaderNames.SecWebSocketKey, secKey);
+ if (options._requestedSubProtocols?.Count > 0)
+ {
// Make sure we clear the builder
builder.Clear();
}
diff --git a/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Win32.cs b/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Win32.cs
deleted file mode 100644
index d602478f37..0000000000
--- a/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Win32.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Diagnostics.CodeAnalysis;
-using System.Diagnostics;
-using System.Net;
-using System.Security.Cryptography.X509Certificates;
-using System.Threading;
-using System.Threading.Tasks;
-
-using Microsoft.Win32.SafeHandles;
-
-namespace System.Net.WebSockets
-{
- internal readonly partial struct WebSocketHandle
- {
- private const string WebSocketAvailableApiCheck = "WinHttpWebSocketCompleteUpgrade";
-
- private readonly WinHttpWebSocket _webSocket;
-
- public static WebSocketHandle Create()
- {
- return new WebSocketHandle(new WinHttpWebSocket());
- }
-
- public static void CheckPlatformSupport()
- {
- bool isPlatformSupported = false;
-
- using (SafeLibraryHandle libHandle = Interop.Kernel32.LoadLibraryExW(Interop.Libraries.WinHttp, IntPtr.Zero, 0))
- {
- isPlatformSupported = Interop.Kernel32.GetProcAddress(libHandle, WebSocketAvailableApiCheck) != IntPtr.Zero;
- }
-
- if (!isPlatformSupported)
- {
- WebSocketValidate.ThrowPlatformNotSupportedException();
- }
- }
-
- private WebSocketHandle(WinHttpWebSocket webSocket)
- {
- _webSocket = webSocket;
- }
-
- public async Task ConnectAsyncCore(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options)
- {
- try
- {
- await _webSocket.ConnectAsync(uri, cancellationToken, options).ConfigureAwait(false);
- }
- catch (Win32Exception ex)
- {
- var wex = new WebSocketException(SR.net_webstatus_ConnectFailure, ex);
- if (NetEventSource.IsEnabled) NetEventSource.Error(_webSocket, wex);
- throw wex;
- }
- }
- }
-}
diff --git a/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.WinRT.cs b/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.WinRT.cs
index 6a69057405..38a9de071a 100644
--- a/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.WinRT.cs
+++ b/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.WinRT.cs
@@ -39,6 +39,11 @@ namespace System.Net.WebSockets
public async Task ConnectAsyncCore(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options)
{
+ if (options.RemoteCertificateValidationCallback != null)
+ {
+ throw new PlatformNotSupportedException(SR.net_WebSockets_RemoteValidationCallbackNotSupported);
+ }
+
try
{
await _webSocket.ConnectAsync(uri, cancellationToken, options).ConfigureAwait(false);
diff --git a/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Windows.cs b/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Windows.cs
index a7f9d1083d..679b5e5d6d 100644
--- a/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Windows.cs
+++ b/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Windows.cs
@@ -80,7 +80,7 @@ namespace System.Net.WebSockets
return _webSocket.SendAsync(buffer, messageType, endOfMessage, cancellationToken);
}
- public Task SendAsync(ReadOnlyMemory<byte> buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken)
+ public ValueTask SendAsync(ReadOnlyMemory<byte> buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken)
{
if (messageType != WebSocketMessageType.Text && messageType != WebSocketMessageType.Binary)
{
diff --git a/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketMessageTypeAdapter.cs b/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketMessageTypeAdapter.cs
deleted file mode 100644
index 965b67831f..0000000000
--- a/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketMessageTypeAdapter.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-using System.Net.Http;
-
-namespace System.Net.WebSockets
-{
- internal static class WebSocketMessageTypeAdapter
- {
- internal static Interop.WinHttp.WINHTTP_WEB_SOCKET_BUFFER_TYPE GetWinHttpMessageType(WebSocketMessageType messageType, bool endOfMessage)
- {
- switch (messageType)
- {
- case WebSocketMessageType.Binary:
- if (endOfMessage)
- {
- return Interop.WinHttp.WINHTTP_WEB_SOCKET_BUFFER_TYPE.WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE;
- }
- else
- {
- return Interop.WinHttp.WINHTTP_WEB_SOCKET_BUFFER_TYPE.WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE;
- }
-
- case WebSocketMessageType.Text:
- if (endOfMessage)
- {
- return Interop.WinHttp.WINHTTP_WEB_SOCKET_BUFFER_TYPE.WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE;
- }
- else
- {
- return Interop.WinHttp.WINHTTP_WEB_SOCKET_BUFFER_TYPE.WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE;
- }
-
- case WebSocketMessageType.Close:
- return Interop.WinHttp.WINHTTP_WEB_SOCKET_BUFFER_TYPE.WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE;
-
- default:
- Debug.Fail("Unknown WebSocketMessageType.");
- return Interop.WinHttp.WINHTTP_WEB_SOCKET_BUFFER_TYPE.WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE;
- }
- }
-
- internal static WebSocketMessageType GetWebSocketMessageType(Interop.WinHttp.WINHTTP_WEB_SOCKET_BUFFER_TYPE winHttpMessageType, out bool endOfMessage)
- {
- switch (winHttpMessageType)
- {
- case Interop.WinHttp.WINHTTP_WEB_SOCKET_BUFFER_TYPE.WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE:
- endOfMessage = true;
- return WebSocketMessageType.Binary;
- case Interop.WinHttp.WINHTTP_WEB_SOCKET_BUFFER_TYPE.WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE:
- endOfMessage = false;
- return WebSocketMessageType.Binary;
- case Interop.WinHttp.WINHTTP_WEB_SOCKET_BUFFER_TYPE.WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE:
- endOfMessage = true;
- return WebSocketMessageType.Text;
- case Interop.WinHttp.WINHTTP_WEB_SOCKET_BUFFER_TYPE.WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE:
- endOfMessage = false;
- return WebSocketMessageType.Text;
- case Interop.WinHttp.WINHTTP_WEB_SOCKET_BUFFER_TYPE.WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE:
- endOfMessage = true;
- return WebSocketMessageType.Close;
- default:
- throw new ArgumentOutOfRangeException(nameof(winHttpMessageType), "Unknown WINHTTP_WEB_SOCKET_BUFFER_TYPE.");
- }
- }
- }
-}
diff --git a/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WinHttpWebSocket.cs b/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WinHttpWebSocket.cs
deleted file mode 100644
index 62052b29bb..0000000000
--- a/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WinHttpWebSocket.cs
+++ /dev/null
@@ -1,865 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Net.Http;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace System.Net.WebSockets
-{
- internal sealed class WinHttpWebSocket : WebSocket
- {
- #region Constants
- // TODO (#7893): This code needs to be shared with WinHttpClientHandler
- private const string HeaderNameCookie = "Cookie";
- private const string HeaderNameWebSocketProtocol = "Sec-WebSocket-Protocol";
- #endregion
-
- // TODO (Issue 2503): move System.Net.* strings to resources as appropriate.
-
- // NOTE: All WinHTTP operations must be called while holding the _operation.Lock.
- // It is critical that no handle gets closed while a WinHTTP function is running.
- private WebSocketCloseStatus? _closeStatus = null;
- private string _closeStatusDescription = null;
- private string _subProtocol = null;
- private bool _disposed = false;
-
- private WinHttpWebSocketState _operation = new WinHttpWebSocketState();
-
- public WinHttpWebSocket()
- {
- }
-
- #region Properties
- public override WebSocketCloseStatus? CloseStatus
- {
- get
- {
- return _closeStatus;
- }
- }
-
- public override string CloseStatusDescription
- {
- get
- {
- return _closeStatusDescription;
- }
- }
-
- public override WebSocketState State
- {
- get
- {
- return _operation.State;
- }
- }
-
- public override string SubProtocol
- {
- get
- {
- return _subProtocol;
- }
- }
- #endregion
-
- static readonly WebSocketState[] s_validConnectStates = { WebSocketState.None };
- static readonly WebSocketState[] s_validConnectingStates = { WebSocketState.Connecting };
-
- public async Task ConnectAsync(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options)
- {
- _operation.InterlockedCheckAndUpdateState(WebSocketState.Connecting, s_validConnectStates);
-
- using (CancellationTokenRegistration ctr = ThrowOrRegisterCancellation(cancellationToken))
- {
- lock (_operation.Lock)
- {
- _operation.CheckValidState(s_validConnectingStates);
-
- // Must grab lock until RequestHandle is populated, otherwise we risk resource leaks on Abort.
- //
- // TODO (Issue 2506): Alternatively, release the lock between WinHTTP operations and check, under lock, that the
- // state is still valid to continue operation.
- _operation.SessionHandle = InitializeWinHttp(options);
-
- _operation.ConnectionHandle = Interop.WinHttp.WinHttpConnectWithCallback(
- _operation.SessionHandle,
- uri.IdnHost,
- (ushort)uri.Port,
- 0);
-
- ThrowOnInvalidHandle(_operation.ConnectionHandle);
-
- bool secureConnection = uri.Scheme == UriScheme.Https || uri.Scheme == UriScheme.Wss;
-
- _operation.RequestHandle = Interop.WinHttp.WinHttpOpenRequestWithCallback(
- _operation.ConnectionHandle,
- "GET",
- uri.PathAndQuery,
- null,
- Interop.WinHttp.WINHTTP_NO_REFERER,
- null,
- secureConnection ? Interop.WinHttp.WINHTTP_FLAG_SECURE : 0);
-
- ThrowOnInvalidHandle(_operation.RequestHandle);
- _operation.IncrementHandlesOpenWithCallback();
-
- if (!Interop.WinHttp.WinHttpSetOption(
- _operation.RequestHandle,
- Interop.WinHttp.WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET,
- IntPtr.Zero,
- 0))
- {
- WinHttpException.ThrowExceptionUsingLastError();
- }
-
- // We need the address of the IntPtr to the GCHandle.
- IntPtr context = _operation.ToIntPtr();
- IntPtr contextAddress;
- unsafe
- {
- contextAddress = (IntPtr)(void*)&context;
- }
-
- if (!Interop.WinHttp.WinHttpSetOption(
- _operation.RequestHandle,
- Interop.WinHttp.WINHTTP_OPTION_CONTEXT_VALUE,
- contextAddress,
- (uint)IntPtr.Size))
- {
- WinHttpException.ThrowExceptionUsingLastError();
- }
-
- const uint notificationFlags =
- Interop.WinHttp.WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS |
- Interop.WinHttp.WINHTTP_CALLBACK_FLAG_HANDLES |
- Interop.WinHttp.WINHTTP_CALLBACK_FLAG_SECURE_FAILURE;
-
- if (Interop.WinHttp.WinHttpSetStatusCallback(
- _operation.RequestHandle,
- WinHttpWebSocketCallback.s_StaticCallbackDelegate,
- notificationFlags,
- IntPtr.Zero) == (IntPtr)Interop.WinHttp.WINHTTP_INVALID_STATUS_CALLBACK)
- {
- WinHttpException.ThrowExceptionUsingLastError();
- }
-
- _operation.RequestHandle.AttachCallback();
-
- // We need to pin the operation object at this point in time since the WinHTTP callback
- // has been fully wired to the request handle and the operation object has been set as
- // the context value of the callback. Any notifications from activity on the handle will
- // result in the callback being called with the context value.
- _operation.Pin();
-
- AddRequestHeaders(uri, options);
-
- _operation.TcsUpgrade = new TaskCompletionSource<bool>();
- }
-
- await InternalSendWsUpgradeRequestAsync().ConfigureAwait(false);
-
- await InternalReceiveWsUpgradeResponse().ConfigureAwait(false);
-
- lock (_operation.Lock)
- {
- VerifyUpgradeResponse();
-
- ThrowOnInvalidConnectState();
-
- _operation.WebSocketHandle =
- Interop.WinHttp.WinHttpWebSocketCompleteUpgrade(_operation.RequestHandle, IntPtr.Zero);
-
- ThrowOnInvalidHandle(_operation.WebSocketHandle);
- _operation.IncrementHandlesOpenWithCallback();
-
- // We need the address of the IntPtr to the GCHandle.
- IntPtr context = _operation.ToIntPtr();
- IntPtr contextAddress;
- unsafe
- {
- contextAddress = (IntPtr)(void*)&context;
- }
-
- if (!Interop.WinHttp.WinHttpSetOption(
- _operation.WebSocketHandle,
- Interop.WinHttp.WINHTTP_OPTION_CONTEXT_VALUE,
- contextAddress,
- (uint)IntPtr.Size))
- {
- WinHttpException.ThrowExceptionUsingLastError();
- }
-
- _operation.WebSocketHandle.AttachCallback();
- _operation.UpdateState(WebSocketState.Open);
-
- if (_operation.RequestHandle != null)
- {
- _operation.RequestHandle.Dispose();
- // RequestHandle will be set to null in the callback.
- }
- _operation.TcsUpgrade = null;
-
- ctr.Dispose();
- }
- }
- }
-
- // Requires lock taken.
- private Interop.WinHttp.SafeWinHttpHandle InitializeWinHttp(ClientWebSocketOptions options)
- {
- Interop.WinHttp.SafeWinHttpHandle sessionHandle;
- sessionHandle = Interop.WinHttp.WinHttpOpen(
- IntPtr.Zero,
- Interop.WinHttp.WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
- null,
- null,
- (int)Interop.WinHttp.WINHTTP_FLAG_ASYNC);
-
- ThrowOnInvalidHandle(sessionHandle);
-
- uint optionAssuredNonBlockingTrue = 1; // TRUE
-
- if (!Interop.WinHttp.WinHttpSetOption(
- sessionHandle,
- Interop.WinHttp.WINHTTP_OPTION_ASSURED_NON_BLOCKING_CALLBACKS,
- ref optionAssuredNonBlockingTrue,
- (uint)sizeof(uint)))
- {
- WinHttpException.ThrowExceptionUsingLastError();
- }
-
- return sessionHandle;
- }
-
- private Task<bool> InternalSendWsUpgradeRequestAsync()
- {
- lock (_operation.Lock)
- {
- ThrowOnInvalidConnectState();
- if (!Interop.WinHttp.WinHttpSendRequest(
- _operation.RequestHandle,
- Interop.WinHttp.WINHTTP_NO_ADDITIONAL_HEADERS,
- 0,
- IntPtr.Zero,
- 0,
- 0,
- _operation.ToIntPtr()))
- {
- WinHttpException.ThrowExceptionUsingLastError();
- }
- }
-
- return _operation.TcsUpgrade.Task;
- }
-
- private Task<bool> InternalReceiveWsUpgradeResponse()
- {
- // TODO (Issue 2507): Potential optimization: move this in WinHttpWebSocketCallback.
- lock (_operation.Lock)
- {
- ThrowOnInvalidConnectState();
-
- _operation.TcsUpgrade = new TaskCompletionSource<bool>();
-
- if (!Interop.WinHttp.WinHttpReceiveResponse(_operation.RequestHandle, IntPtr.Zero))
- {
- WinHttpException.ThrowExceptionUsingLastError();
- }
- }
-
- return _operation.TcsUpgrade.Task;
- }
-
- private void ThrowOnInvalidConnectState()
- {
- // A special behavior for WebSocket upgrade: throws ConnectFailure instead of other Abort messages.
- if (_operation.State != WebSocketState.Connecting)
- {
- throw new WebSocketException(SR.net_webstatus_ConnectFailure);
- }
- }
-
- private static readonly WebSocketState[] s_validSendStates = { WebSocketState.Open, WebSocketState.CloseReceived };
- public override Task SendAsync(
- ArraySegment<byte> buffer,
- WebSocketMessageType messageType,
- bool endOfMessage,
- CancellationToken cancellationToken)
- {
- _operation.InterlockedCheckValidStates(s_validSendStates);
-
- using (CancellationTokenRegistration ctr = ThrowOrRegisterCancellation(cancellationToken))
- {
- var bufferType = WebSocketMessageTypeAdapter.GetWinHttpMessageType(messageType, endOfMessage);
-
- _operation.PinSendBuffer(buffer);
-
- bool sendOperationAlreadyPending = false;
- if (_operation.PendingWriteOperation == false)
- {
- lock (_operation.Lock)
- {
- _operation.CheckValidState(s_validSendStates);
-
- if (_operation.PendingWriteOperation == false)
- {
- _operation.PendingWriteOperation = true;
- _operation.TcsSend = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
-
- uint ret = Interop.WinHttp.WinHttpWebSocketSend(
- _operation.WebSocketHandle,
- bufferType,
- buffer.Count > 0 ? Marshal.UnsafeAddrOfPinnedArrayElement(buffer.Array, buffer.Offset) : IntPtr.Zero,
- (uint)buffer.Count);
-
- if (Interop.WinHttp.ERROR_SUCCESS != ret)
- {
- throw WinHttpException.CreateExceptionUsingError((int)ret);
- }
- }
- else
- {
- sendOperationAlreadyPending = true;
- }
- }
- }
- else
- {
- sendOperationAlreadyPending = true;
- }
-
- if (sendOperationAlreadyPending)
- {
- var exception = new InvalidOperationException(
- SR.Format(SR.net_Websockets_AlreadyOneOutstandingOperation, "SendAsync"));
-
- _operation.TcsSend.TrySetException(exception);
- Abort();
- }
-
- return _operation.TcsSend.Task;
- }
- }
-
- private static readonly WebSocketState[] s_validReceiveStates = { WebSocketState.Open, WebSocketState.CloseSent };
- private static readonly WebSocketState[] s_validAfterReceiveStates = { WebSocketState.Open, WebSocketState.CloseSent, WebSocketState.CloseReceived };
- public override async Task<WebSocketReceiveResult> ReceiveAsync(
- ArraySegment<byte> buffer,
- CancellationToken cancellationToken)
- {
- _operation.InterlockedCheckValidStates(s_validReceiveStates);
-
- using (ThrowOrRegisterCancellation(cancellationToken))
- {
- _operation.PinReceiveBuffer(buffer);
-
- await InternalReceiveAsync(buffer).ConfigureAwait(false);
-
- // Check for abort.
- _operation.InterlockedCheckValidStates(s_validAfterReceiveStates);
-
- bool endOfMessage;
- WebSocketMessageType bufferType = WebSocketMessageTypeAdapter.GetWebSocketMessageType(_operation.BufferType, out endOfMessage);
- int bytesTransferred = checked((int)_operation.BytesTransferred);
-
- WebSocketReceiveResult ret;
-
- if (bufferType == WebSocketMessageType.Close)
- {
- UpdateServerCloseStatus();
- ret = new WebSocketReceiveResult(bytesTransferred, bufferType, endOfMessage, _closeStatus, _closeStatusDescription);
- }
- else
- {
- ret = new WebSocketReceiveResult(bytesTransferred, bufferType, endOfMessage);
- }
-
- return ret;
- }
- }
-
- public override async ValueTask<ValueWebSocketReceiveResult> ReceiveAsync(Memory<byte> buffer, CancellationToken cancellationToken)
- {
- _operation.InterlockedCheckValidStates(s_validReceiveStates);
-
- using (ThrowOrRegisterCancellation(cancellationToken))
- using (buffer.Retain(pin: true))
- {
- await InternalReceiveAsync(buffer).ConfigureAwait(false);
-
- // Check for abort.
- _operation.InterlockedCheckValidStates(s_validAfterReceiveStates);
-
- WebSocketMessageType bufferType = WebSocketMessageTypeAdapter.GetWebSocketMessageType(_operation.BufferType, out bool endOfMessage);
- int bytesTransferred = checked((int)_operation.BytesTransferred);
-
- if (bufferType == WebSocketMessageType.Close)
- {
- UpdateServerCloseStatus();
- }
-
- return new ValueWebSocketReceiveResult(bytesTransferred, bufferType, endOfMessage);
- }
- }
-
- private Task<bool> InternalReceiveAsync(Memory<byte> pinnedBuffer)
- {
- bool receiveOperationAlreadyPending = false;
- if (_operation.PendingReadOperation == false)
- {
- lock (_operation.Lock)
- {
- if (_operation.PendingReadOperation == false)
- {
- _operation.CheckValidState(s_validReceiveStates);
-
- // Prevent continuations from running on the same thread as the callback to prevent re-entrance deadlocks
- _operation.TcsReceive = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
- _operation.PendingReadOperation = true;
-
- uint bytesRead = 0;
- Interop.WinHttp.WINHTTP_WEB_SOCKET_BUFFER_TYPE winHttpBufferType = 0;
- IntPtr pinnedBufferPtr;
- unsafe
- {
- fixed (byte* p = &MemoryMarshal.GetReference(pinnedBuffer.Span))
- {
- pinnedBufferPtr = (IntPtr)p;
- }
- }
-
- uint status = Interop.WinHttp.WinHttpWebSocketReceive(
- _operation.WebSocketHandle,
- pinnedBufferPtr,
- (uint)pinnedBuffer.Length,
- out bytesRead, // Unused in async mode: ignore.
- out winHttpBufferType); // Unused in async mode: ignore.
-
- if (Interop.WinHttp.ERROR_SUCCESS != status)
- {
- throw WinHttpException.CreateExceptionUsingError((int)status);
- }
- }
- else
- {
- receiveOperationAlreadyPending = true;
- }
- }
- }
- else
- {
- receiveOperationAlreadyPending = true;
- }
-
- if (receiveOperationAlreadyPending)
- {
- var exception = new InvalidOperationException(
- SR.Format(SR.net_Websockets_AlreadyOneOutstandingOperation, "ReceiveAsync"));
- _operation.TcsReceive.TrySetException(exception);
-
- Abort();
- }
-
- return _operation.TcsReceive.Task;
- }
-
- private static readonly WebSocketState[] s_validCloseStates = { WebSocketState.Open, WebSocketState.CloseReceived, WebSocketState.CloseSent };
- public override async Task CloseAsync(
- WebSocketCloseStatus closeStatus,
- string statusDescription,
- CancellationToken cancellationToken)
- {
- _operation.InterlockedCheckAndUpdateState(WebSocketState.CloseSent, s_validCloseStates);
-
- using (CancellationTokenRegistration ctr = ThrowOrRegisterCancellation(cancellationToken))
- {
- _operation.TcsClose = new TaskCompletionSource<bool>();
- await InternalCloseAsync(closeStatus, statusDescription).ConfigureAwait(false);
- UpdateServerCloseStatus();
- }
- }
-
- private Task<bool> InternalCloseAsync(WebSocketCloseStatus closeStatus, string statusDescription)
- {
- uint ret;
- _operation.TcsClose = new TaskCompletionSource<bool>();
-
- lock (_operation.Lock)
- {
- _operation.CheckValidState(s_validCloseStates);
-
- if (!string.IsNullOrEmpty(statusDescription))
- {
- byte[] statusDescriptionBuffer = Encoding.UTF8.GetBytes(statusDescription);
-
- ret = Interop.WinHttp.WinHttpWebSocketClose(
- _operation.WebSocketHandle,
- (ushort)closeStatus,
- statusDescriptionBuffer,
- (uint)statusDescriptionBuffer.Length);
- }
- else
- {
- ret = Interop.WinHttp.WinHttpWebSocketClose(
- _operation.WebSocketHandle,
- (ushort)closeStatus,
- IntPtr.Zero,
- 0);
- }
-
- if (ret != Interop.WinHttp.ERROR_SUCCESS)
- {
- throw WinHttpException.CreateExceptionUsingError((int)ret);
- }
- }
- return _operation.TcsClose.Task;
- }
-
- private void UpdateServerCloseStatus()
- {
- uint ret;
- ushort serverStatus;
- var closeDescription = new byte[WebSocketValidate.MaxControlFramePayloadLength];
- uint closeDescriptionConsumed;
-
- lock (_operation.Lock)
- {
- ret = Interop.WinHttp.WinHttpWebSocketQueryCloseStatus(
- _operation.WebSocketHandle,
- out serverStatus,
- closeDescription,
- (uint)closeDescription.Length,
- out closeDescriptionConsumed);
-
- if (ret != Interop.WinHttp.ERROR_SUCCESS)
- {
- throw WinHttpException.CreateExceptionUsingError((int)ret);
- }
-
- _closeStatus = (WebSocketCloseStatus)serverStatus;
- _closeStatusDescription = Encoding.UTF8.GetString(closeDescription, 0, (int)closeDescriptionConsumed);
- }
- }
-
- private static readonly WebSocketState[] s_validCloseOutputStates = { WebSocketState.Open, WebSocketState.CloseReceived };
- private static readonly WebSocketState[] s_validCloseOutputStatesAfterUpdate = { WebSocketState.CloseReceived, WebSocketState.CloseSent };
- public override Task CloseOutputAsync(
- WebSocketCloseStatus closeStatus,
- string statusDescription,
- CancellationToken cancellationToken)
- {
- _operation.InterlockedCheckAndUpdateState(WebSocketState.CloseSent, s_validCloseOutputStates);
-
- using (CancellationTokenRegistration ctr = ThrowOrRegisterCancellation(cancellationToken))
- {
- lock (_operation.Lock)
- {
- _operation.CheckValidState(s_validCloseOutputStatesAfterUpdate);
-
- uint ret;
- _operation.TcsCloseOutput = new TaskCompletionSource<bool>();
-
- if (!string.IsNullOrEmpty(statusDescription))
- {
- byte[] statusDescriptionBuffer = Encoding.UTF8.GetBytes(statusDescription);
-
- ret = Interop.WinHttp.WinHttpWebSocketShutdown(
- _operation.WebSocketHandle,
- (ushort)closeStatus,
- statusDescriptionBuffer,
- (uint)statusDescriptionBuffer.Length);
- }
- else
- {
- ret = Interop.WinHttp.WinHttpWebSocketShutdown(
- _operation.WebSocketHandle,
- (ushort)closeStatus,
- IntPtr.Zero,
- 0);
- }
-
- if (ret != Interop.WinHttp.ERROR_SUCCESS)
- {
- throw WinHttpException.CreateExceptionUsingError((int)ret);
- }
- }
-
- return _operation.TcsCloseOutput.Task;
- }
- }
-
- private void VerifyUpgradeResponse()
- {
- // Check the status code
- var statusCode = GetHttpStatusCode();
- if (statusCode != HttpStatusCode.SwitchingProtocols)
- {
- Abort();
- return;
- }
-
- _subProtocol = GetResponseHeader(HeaderNameWebSocketProtocol);
- }
-
- private void AddRequestHeaders(Uri uri, ClientWebSocketOptions options)
- {
- var requestHeadersBuffer = new StringBuilder();
-
- // Manually add cookies.
- if (options.Cookies != null)
- {
- AppendCookieHeaderLine(uri, options.Cookies, requestHeadersBuffer);
- }
-
- // Serialize general request headers.
- requestHeadersBuffer.AppendLine(options.RequestHeaders.ToString());
-
- using (List<string>.Enumerator e = options.RequestedSubProtocols.GetEnumerator())
- {
- if (e.MoveNext())
- {
- requestHeadersBuffer.Append(HeaderNameWebSocketProtocol + ": ");
- requestHeadersBuffer.Append(e.Current);
-
- while (e.MoveNext())
- {
- requestHeadersBuffer.Append(", ");
- requestHeadersBuffer.Append(e.Current);
- }
-
- requestHeadersBuffer.AppendLine();
- }
- }
-
- // Add request headers to WinHTTP request handle.
- if (!Interop.WinHttp.WinHttpAddRequestHeaders(
- _operation.RequestHandle,
- requestHeadersBuffer,
- (uint)requestHeadersBuffer.Length,
- Interop.WinHttp.WINHTTP_ADDREQ_FLAG_ADD))
- {
- WinHttpException.ThrowExceptionUsingLastError();
- }
- }
-
- private static void AppendCookieHeaderLine(Uri uri, CookieContainer cookies, StringBuilder requestHeadersBuffer)
- {
- Debug.Assert(cookies != null);
- Debug.Assert(requestHeadersBuffer != null);
-
- string cookieValues = cookies.GetCookieHeader(uri);
- if (!string.IsNullOrEmpty(cookieValues))
- {
- requestHeadersBuffer.Append(HeaderNameCookie + ": ");
- requestHeadersBuffer.AppendLine(cookieValues);
- }
- }
-
- private HttpStatusCode GetHttpStatusCode()
- {
- uint infoLevel = Interop.WinHttp.WINHTTP_QUERY_STATUS_CODE | Interop.WinHttp.WINHTTP_QUERY_FLAG_NUMBER;
- uint result = 0;
- uint resultSize = sizeof(uint);
-
- if (!Interop.WinHttp.WinHttpQueryHeaders(
- _operation.RequestHandle,
- infoLevel,
- Interop.WinHttp.WINHTTP_HEADER_NAME_BY_INDEX,
- ref result,
- ref resultSize,
- IntPtr.Zero))
- {
- WinHttpException.ThrowExceptionUsingLastError();
- }
-
- return (HttpStatusCode)result;
- }
-
- private unsafe string GetResponseHeader(string headerName, char[] buffer = null)
- {
- const int StackLimit = 128;
-
- Debug.Assert(buffer == null || (buffer != null && buffer.Length > StackLimit));
-
- int bufferLength;
-
- if (buffer == null)
- {
- bufferLength = StackLimit;
- char* pBuffer = stackalloc char[bufferLength];
- if (QueryHeaders(headerName, pBuffer, ref bufferLength))
- {
- return new string(pBuffer, 0, bufferLength);
- }
- }
- else
- {
- bufferLength = buffer.Length;
- fixed (char* pBuffer = &buffer[0])
- {
- if (QueryHeaders(headerName, pBuffer, ref bufferLength))
- {
- return new string(pBuffer, 0, bufferLength);
- }
- }
- }
-
- int lastError = Marshal.GetLastWin32Error();
-
- if (lastError == Interop.WinHttp.ERROR_WINHTTP_HEADER_NOT_FOUND)
- {
- return null;
- }
-
- if (lastError == Interop.WinHttp.ERROR_INSUFFICIENT_BUFFER)
- {
- buffer = new char[bufferLength];
- return GetResponseHeader(headerName, buffer);
- }
-
- throw WinHttpException.CreateExceptionUsingError(lastError);
- }
-
- private unsafe bool QueryHeaders(string headerName, char* buffer, ref int bufferLength)
- {
- Debug.Assert(bufferLength >= 0, "bufferLength must not be negative.");
-
- uint index = 0;
-
- // Convert the char buffer length to the length in bytes.
- uint bufferLengthInBytes = (uint)bufferLength * sizeof(char);
-
- // The WinHttpQueryHeaders buffer length is in bytes,
- // but the API actually returns Unicode characters.
- bool result = Interop.WinHttp.WinHttpQueryHeaders(
- _operation.RequestHandle,
- Interop.WinHttp.WINHTTP_QUERY_CUSTOM,
- headerName,
- new IntPtr(buffer),
- ref bufferLengthInBytes,
- ref index);
-
- // Convert the byte buffer length back to the length in chars.
- bufferLength = (int)bufferLengthInBytes / sizeof(char);
-
- return result;
- }
-
- public override void Dispose()
- {
- if (!_disposed)
- {
- lock (_operation.Lock)
- {
- // Disposing will involve calling WinHttpClose on handles. It is critical that no other WinHttp
- // function is running at the same time.
-
- if (!_disposed)
- {
- _operation.Dispose();
-
- _disposed = true;
- }
- }
- }
-
- // No need to suppress finalization since the finalizer is not overridden.
- }
-
- public override void Abort()
- {
- lock (_operation.Lock)
- {
- if ((State != WebSocketState.None) && (State != WebSocketState.Connecting))
- {
- _operation.UpdateState(WebSocketState.Aborted);
- }
- else
- {
- // ClientWebSocket Desktop behavior: a ws that was not connected will not switch state to Aborted.
- _operation.UpdateState(WebSocketState.Closed);
- }
-
- Dispose();
- }
-
- CancelAllOperations();
- }
-
- private void CancelAllOperations()
- {
- if (_operation.TcsClose != null)
- {
- var exception = new WebSocketException(
- WebSocketError.InvalidState,
- SR.Format(
- SR.net_WebSockets_InvalidState_ClosedOrAborted,
- "System.Net.WebSockets.InternalClientWebSocket",
- "Aborted"));
-
- _operation.TcsClose.TrySetException(exception);
- }
-
- if (_operation.TcsCloseOutput != null)
- {
- var exception = new WebSocketException(
- WebSocketError.InvalidState,
- SR.Format(
- SR.net_WebSockets_InvalidState_ClosedOrAborted,
- "System.Net.WebSockets.InternalClientWebSocket",
- "Aborted"));
-
- _operation.TcsCloseOutput.TrySetException(exception);
- }
-
- if (_operation.TcsReceive != null)
- {
- _operation.TcsReceive.TrySetCanceled();
- }
-
- if (_operation.TcsSend != null)
- {
- var exception = new OperationCanceledException();
- _operation.TcsSend.TrySetException(exception);
- }
-
- if (_operation.TcsUpgrade != null)
- {
- var exception = new WebSocketException(SR.net_webstatus_ConnectFailure);
- _operation.TcsUpgrade.TrySetException(exception);
- }
- }
-
- private void ThrowOnInvalidHandle(Interop.WinHttp.SafeWinHttpHandle value)
- {
- if (value.IsInvalid)
- {
- Abort();
- throw new WebSocketException(
- SR.net_webstatus_ConnectFailure,
- WinHttpException.CreateExceptionUsingLastError());
- }
- }
-
- private CancellationTokenRegistration ThrowOrRegisterCancellation(CancellationToken cancellationToken)
- {
- if (cancellationToken.IsCancellationRequested)
- {
- Abort();
- cancellationToken.ThrowIfCancellationRequested();
- }
-
- CancellationTokenRegistration cancellationRegistration =
- cancellationToken.Register(s => ((WinHttpWebSocket)s).Abort(), this);
-
- return cancellationRegistration;
- }
- }
-}
diff --git a/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WinHttpWebSocketCallback.cs b/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WinHttpWebSocketCallback.cs
deleted file mode 100644
index 5ba776c1ba..0000000000
--- a/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WinHttpWebSocketCallback.cs
+++ /dev/null
@@ -1,376 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Net.Http;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using System.ComponentModel;
-using System.Runtime.InteropServices;
-using System.Diagnostics;
-
-namespace System.Net.WebSockets
-{
- /// <summary>
- /// Static class containing the WinHttp global callback and associated routines.
- /// </summary>
- internal static class WinHttpWebSocketCallback
- {
- public static Interop.WinHttp.WINHTTP_STATUS_CALLBACK s_StaticCallbackDelegate =
- new Interop.WinHttp.WINHTTP_STATUS_CALLBACK(WinHttpCallback);
-
- public static void WinHttpCallback(
- IntPtr handle,
- IntPtr context,
- uint internetStatus,
- IntPtr statusInformation,
- uint statusInformationLength)
- {
- if (Environment.HasShutdownStarted)
- {
- return;
- }
-
- if (context == IntPtr.Zero)
- {
- Debug.Assert(internetStatus != Interop.WinHttp.WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING);
- return;
- }
-
- try
- {
- WinHttpWebSocketState state = WinHttpWebSocketState.FromIntPtr(context);
- Debug.Assert(state != null, "WinHttpWebSocketCallback: state should not be null");
-
- if ((state.RequestHandle != null) &&
- (state.RequestHandle.DangerousGetHandle() == handle))
- {
- RequestCallback(handle, state, internetStatus, statusInformation, statusInformationLength);
- return;
- }
-
- if ((state.WebSocketHandle != null) &&
- (state.WebSocketHandle.DangerousGetHandle() == handle))
- {
- WebSocketCallback(handle, state, internetStatus, statusInformation, statusInformationLength);
- return;
- }
- }
- catch (Exception ex)
- {
- Debug.Fail("Unhandled exception in WinHTTP callback: " + ex);
- }
- }
-
- #region RequestCallback
-
- private static void RequestCallback(
- IntPtr handle,
- WinHttpWebSocketState state,
- uint internetStatus,
- IntPtr statusInformation,
- uint statusInformationLength)
- {
- switch (internetStatus)
- {
- case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:
- OnRequestSendRequestComplete(state);
- return;
-
- case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE:
- OnRequestHeadersAvailable(state);
- return;
-
- case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING:
- OnRequestHandleClosing(state);
- return;
-
- case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
- Debug.Assert(
- statusInformationLength == Marshal.SizeOf<Interop.WinHttp.WINHTTP_ASYNC_RESULT>(),
- "RequestCallback: statusInformationLength=" + statusInformationLength +
- " must be sizeof(WINHTTP_ASYNC_RESULT)=" + Marshal.SizeOf<Interop.WinHttp.WINHTTP_ASYNC_RESULT>());
-
- var asyncResult = Marshal.PtrToStructure<Interop.WinHttp.WINHTTP_ASYNC_RESULT>(statusInformation);
- OnRequestError(state, asyncResult);
- return;
-
- case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_SECURE_FAILURE:
- Debug.Assert(
- statusInformationLength == sizeof(uint),
- "RequestCallback: statusInformationLength must be sizeof(uint).");
-
- // statusInformation contains a flag: WINHTTP_CALLBACK_STATUS_FLAG_*
- uint flags = 0;
- unchecked
- {
- flags = (uint)Marshal.ReadInt32(statusInformation);
- }
- OnRequestSecureFailure(state, flags);
-
- return;
- }
- }
-
- private static void OnRequestSendRequestComplete(WinHttpWebSocketState state)
- {
- Debug.Assert(state != null, "OnRequestSendRequestComplete: state is null");
- Debug.Assert(state.TcsUpgrade != null, "OnRequestSendRequestComplete: task completion source is null");
- state.TcsUpgrade.TrySetResult(true);
- }
-
- private static void OnRequestHeadersAvailable(WinHttpWebSocketState state)
- {
- Debug.Assert(state != null, "OnRequestHeadersAvailable: state is null");
- Debug.Assert(state.TcsUpgrade != null, "OnRequestHeadersAvailable: task completion source is null");
- state.TcsUpgrade.TrySetResult(true);
- }
-
- private static void OnRequestHandleClosing(WinHttpWebSocketState state)
- {
- Debug.Assert(state != null, "OnRequestError: state is null");
- Debug.Assert(state.RequestHandle != null, "OnRequestError: RequestHandle is null");
- Debug.Assert(!state.RequestHandle.IsInvalid, "OnRequestError: RequestHandle is invalid");
-
- state.RequestHandle.DetachCallback();
- state.RequestHandle = null;
-
- // Unpin the state object if there are no more open handles that are wired to the callback.
- if (state.DecrementHandlesOpenWithCallback() == 0)
- {
- state.Unpin();
- }
- }
-
- private static void OnRequestError(
- WinHttpWebSocketState state,
- Interop.WinHttp.WINHTTP_ASYNC_RESULT asyncResult)
- {
- Debug.Assert(state != null, "OnRequestError: state is null");
-
- var innerException = WinHttpException.CreateExceptionUsingError(unchecked((int)asyncResult.dwError));
-
- switch (unchecked((uint)asyncResult.dwResult.ToInt32()))
- {
- case Interop.WinHttp.API_SEND_REQUEST:
- case Interop.WinHttp.API_RECEIVE_RESPONSE:
- {
- var exception = new WebSocketException(SR.net_webstatus_ConnectFailure, innerException);
- state.UpdateState(WebSocketState.Closed);
- state.TcsUpgrade.TrySetException(exception);
- }
- break;
-
- default:
- {
- Debug.Fail(
- "OnRequestError: Result (" + asyncResult.dwResult + ") is not expected.",
- "Error code: " + asyncResult.dwError + " (" + innerException.Message + ")");
- }
- break;
- }
- }
-
- private static void OnRequestSecureFailure(WinHttpWebSocketState state, uint flags)
- {
- Debug.Assert(state != null, "OnRequestSecureFailure: state is null");
-
- var innerException = WinHttpException.CreateExceptionUsingError(unchecked((int)Interop.WinHttp.ERROR_WINHTTP_SECURE_FAILURE));
-
- var exception = new WebSocketException(
- WebSocketError.Success,
- SR.net_webstatus_ConnectFailure,
- innerException);
-
- // TODO (#2509): handle SSL related exceptions.
- state.UpdateState(WebSocketState.Closed);
-
- // TODO (#2509): Create exception from WINHTTP_CALLBACK_STATUS_SECURE_FAILURE flags.
- state.TcsUpgrade.TrySetException(exception);
- }
- #endregion
-
- #region WebSocketCallback
- private static void WebSocketCallback(
- IntPtr handle,
- WinHttpWebSocketState state,
- uint internetStatus,
- IntPtr statusInformation,
- uint statusInformationLength)
- {
- switch (internetStatus)
- {
- case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE:
- OnWebSocketWriteComplete(state);
- return;
-
- case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
- Debug.Assert(
- statusInformationLength == Marshal.SizeOf<Interop.WinHttp.WINHTTP_WEB_SOCKET_STATUS>(),
- "WebSocketCallback: statusInformationLength must be sizeof(WINHTTP_WEB_SOCKET_STATUS).");
-
- var info = Marshal.PtrToStructure<Interop.WinHttp.WINHTTP_WEB_SOCKET_STATUS>(statusInformation);
- OnWebSocketReadComplete(state, info);
- return;
-
- case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE:
- OnWebSocketCloseComplete(state);
- return;
-
- case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE:
- OnWebSocketShutdownComplete(state);
- return;
-
- case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING:
- OnWebSocketHandleClosing(state);
- return;
-
- case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
- Debug.Assert(
- statusInformationLength == Marshal.SizeOf<Interop.WinHttp.WINHTTP_WEB_SOCKET_ASYNC_RESULT>(),
- "WebSocketCallback: statusInformationLength must be sizeof(WINHTTP_WEB_SOCKET_ASYNC_RESULT).");
-
- var asyncResult = Marshal.PtrToStructure<Interop.WinHttp.WINHTTP_WEB_SOCKET_ASYNC_RESULT>(statusInformation);
- OnWebSocketError(state, asyncResult);
- return;
-
- case Interop.WinHttp.WINHTTP_CALLBACK_STATUS_SECURE_FAILURE:
- Debug.Assert(
- statusInformationLength == sizeof(uint),
- "WebSocketCallback: statusInformationLength must be sizeof(uint).");
-
- // statusInformation contains a flag: WINHTTP_CALLBACK_STATUS_FLAG_*
- uint flags = unchecked((uint)statusInformation);
- OnRequestSecureFailure(state, flags);
- return;
- }
- }
-
- private static void OnWebSocketWriteComplete(WinHttpWebSocketState state)
- {
- Debug.Assert(state != null, "OnWebSocketWriteComplete: state is null");
-
- state.PendingWriteOperation = false;
- state.TcsSend.TrySetResult(true);
- }
-
- private static void OnWebSocketReadComplete(
- WinHttpWebSocketState state,
- Interop.WinHttp.WINHTTP_WEB_SOCKET_STATUS info)
- {
- Debug.Assert(state != null, "OnWebSocketReadComplete: state is null");
-
- if (info.eBufferType == Interop.WinHttp.WINHTTP_WEB_SOCKET_BUFFER_TYPE.WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE)
- {
- state.UpdateState(WebSocketState.CloseReceived);
- }
-
- state.BufferType = info.eBufferType;
- state.BytesTransferred = info.dwBytesTransferred;
- state.PendingReadOperation = false;
-
- state.TcsReceive.TrySetResult(true);
- }
-
- private static void OnWebSocketCloseComplete(WinHttpWebSocketState state)
- {
- Debug.Assert(state != null, "OnWebSocketCloseComplete: state is null");
-
- state.UpdateState(WebSocketState.Closed);
- state.TcsClose.TrySetResult(true);
- }
-
- private static void OnWebSocketShutdownComplete(WinHttpWebSocketState state)
- {
- Debug.Assert(state != null, "OnWebSocketShutdownComplete: state is null");
-
- state.UpdateState(WebSocketState.CloseSent);
- state.TcsCloseOutput.TrySetResult(true);
- }
-
- private static void OnWebSocketHandleClosing(WinHttpWebSocketState state)
- {
- Debug.Assert(state != null, "OnWebSocketHandleClosing: state is null");
- Debug.Assert(state.WebSocketHandle != null, "OnWebSocketHandleClosing: WebSocketHandle is null");
- Debug.Assert(!state.WebSocketHandle.IsInvalid, "OnWebSocketHandleClosing: WebSocketHandle is invalid");
-
- state.WebSocketHandle.DetachCallback();
- state.WebSocketHandle = null;
-
- // Unpin the state object if there are no more open handles that are wired to the callback.
- if (state.DecrementHandlesOpenWithCallback() == 0)
- {
- state.Unpin();
- }
- }
-
- private static void OnWebSocketError(
- WinHttpWebSocketState state,
- Interop.WinHttp.WINHTTP_WEB_SOCKET_ASYNC_RESULT asyncResult)
- {
- Debug.Assert(state != null, "OnWebSocketError: state is null");
-
- var innerException = WinHttpException.CreateExceptionUsingError(unchecked((int)(asyncResult.AsyncResult.dwError)));
-
- if (asyncResult.AsyncResult.dwError == Interop.WinHttp.ERROR_WINHTTP_OPERATION_CANCELLED)
- {
- state.UpdateState(WebSocketState.Aborted);
-
- if (state.TcsReceive != null)
- {
- state.TcsReceive.TrySetCanceled();
- }
-
- if (state.TcsSend != null)
- {
- state.TcsSend.TrySetCanceled();
- }
-
- return;
- }
-
- switch (asyncResult.Operation)
- {
- case Interop.WinHttp.WINHTTP_WEB_SOCKET_OPERATION.WINHTTP_WEB_SOCKET_SEND_OPERATION:
- state.PendingWriteOperation = false;
- state.TcsSend.TrySetException(innerException);
- break;
-
- case Interop.WinHttp.WINHTTP_WEB_SOCKET_OPERATION.WINHTTP_WEB_SOCKET_RECEIVE_OPERATION:
- state.PendingReadOperation = false;
- state.TcsReceive.TrySetException(innerException);
- break;
-
- case Interop.WinHttp.WINHTTP_WEB_SOCKET_OPERATION.WINHTTP_WEB_SOCKET_CLOSE_OPERATION:
- state.TcsClose.TrySetException(innerException);
- break;
-
- case Interop.WinHttp.WINHTTP_WEB_SOCKET_OPERATION.WINHTTP_WEB_SOCKET_SHUTDOWN_OPERATION:
- state.TcsCloseOutput.TrySetException(innerException);
- break;
-
- default:
- Debug.Fail(
- "OnWebSocketError: Operation (" + asyncResult.Operation + ") is not expected.",
- "Error code: " + asyncResult.AsyncResult.dwError + " (" + innerException.Message + ")");
- break;
- }
- }
-
- private static void OnWebSocketSecureFailure(WinHttpWebSocketState state, uint flags)
- {
- Debug.Assert(state != null, "OnWebSocketSecureFailure: state is null");
-
- var innerException = WinHttpException.CreateExceptionUsingError(unchecked((int)Interop.WinHttp.ERROR_WINHTTP_SECURE_FAILURE));
- var exception = new WebSocketException(WebSocketError.ConnectionClosedPrematurely, innerException);
-
- // TODO (Issue 2509): handle SSL related exceptions.
- state.UpdateState(WebSocketState.Aborted);
-
- // TODO (Issue 2509): Create exception from WINHTTP_CALLBACK_STATUS_SECURE_FAILURE flags.
- state.TcsUpgrade.TrySetException(exception);
- }
- #endregion
- }
-}
diff --git a/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WinHttpWebSocketState.cs b/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WinHttpWebSocketState.cs
deleted file mode 100644
index f96c318cac..0000000000
--- a/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WinHttpWebSocketState.cs
+++ /dev/null
@@ -1,286 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace System.Net.WebSockets
-{
- internal sealed class WinHttpWebSocketState : IDisposable
- {
- // TODO (Issue 2506): The current locking mechanism doesn't allow any two WinHttp functions executing at
- // the same time for the same handle. Enhance locking to prevent only WinHttpCloseHandle being called
- // during other API execution. E.g. using a Reader/Writer model or, even better, Interlocked functions.
-
- // The _lock object must be during the execution of any WinHttp function to ensure no race conditions with
- // calling WinHttpCloseHandle.
- private readonly object _lock = new object();
-
- private Interop.WinHttp.SafeWinHttpHandle _sessionHandle;
- private Interop.WinHttp.SafeWinHttpHandle _connectionHandle;
- private Interop.WinHttp.SafeWinHttpHandleWithCallback _requestHandle;
- private Interop.WinHttp.SafeWinHttpHandleWithCallback _webSocketHandle;
- private int _handlesOpenWithCallback = 0;
-
- // A GCHandle for this operation object.
- // This is owned by the callback and will be unpinned by the callback when it determines that
- // no further calls will happen on the callback, i.e. all WinHTTP handles have fully closed via
- // a WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING notification being received by the callback.
- private GCHandle _operationHandle = new GCHandle();
-
- private volatile WebSocketState _state = WebSocketState.None;
- private volatile bool _pendingReadOperation = false;
- private volatile bool _pendingWriteOperation = false;
-
- // TODO (Issue 2505): temporary pinned buffer caches of 1 item. Will be replaced by PinnableBufferCache.
- private GCHandle _cachedSendPinnedBuffer = default(GCHandle);
- private GCHandle _cachedReceivePinnedBuffer = default(GCHandle);
-
- private volatile bool _disposed = false; // To detect redundant calls
-
- public WinHttpWebSocketState()
- {
- }
-
- public void Pin()
- {
- Debug.Assert(!_operationHandle.IsAllocated);
- _operationHandle = GCHandle.Alloc(this);
- }
-
- public void Unpin()
- {
- if (_operationHandle.IsAllocated)
- {
- Debug.Assert(_handlesOpenWithCallback == 0);
-
- // This method only gets called when the WinHTTP request/websocket handles are fully closed and thus
- // all async operations are done. So, it is safe at this point to unpin the buffers and release
- // the strong GCHandle for this object.
- if (_cachedReceivePinnedBuffer.IsAllocated)
- {
- _cachedReceivePinnedBuffer.Free();
- _cachedReceivePinnedBuffer = default(GCHandle);
- }
-
- if (_cachedSendPinnedBuffer.IsAllocated)
- {
- _cachedSendPinnedBuffer.Free();
- _cachedSendPinnedBuffer = default(GCHandle);
- }
-
- _operationHandle.Free();
- _operationHandle = default(GCHandle);
- }
- }
-
- public void PinSendBuffer(ArraySegment<byte> buffer)
- {
- if (!_cachedSendPinnedBuffer.IsAllocated || _cachedSendPinnedBuffer.Target != buffer.Array)
- {
- if (_cachedSendPinnedBuffer.IsAllocated)
- {
- _cachedSendPinnedBuffer.Free();
- }
-
- _cachedSendPinnedBuffer = GCHandle.Alloc(buffer.Array, GCHandleType.Pinned);
- }
- }
-
- public void PinReceiveBuffer(ArraySegment<byte> buffer)
- {
- if (!_cachedReceivePinnedBuffer.IsAllocated || _cachedReceivePinnedBuffer.Target != buffer.Array)
- {
- if (_cachedReceivePinnedBuffer.IsAllocated)
- {
- _cachedReceivePinnedBuffer.Free();
- }
-
- _cachedReceivePinnedBuffer = GCHandle.Alloc(buffer.Array, GCHandleType.Pinned);
- }
- }
-
- public void IncrementHandlesOpenWithCallback()
- {
- Interlocked.Increment(ref _handlesOpenWithCallback);
- }
-
- public int DecrementHandlesOpenWithCallback()
- {
- int count = Interlocked.Decrement(ref _handlesOpenWithCallback);
- Debug.Assert(count >= 0);
-
- return count;
- }
-
- public WebSocketState State
- {
- get
- {
- return _state;
- }
- }
-
- public object Lock
- {
- get
- {
- return _lock;
- }
- }
-
- public Interop.WinHttp.SafeWinHttpHandle SessionHandle
- {
- get
- {
- return _sessionHandle;
- }
- set
- {
- _sessionHandle = value;
- }
- }
-
- public Interop.WinHttp.SafeWinHttpHandle ConnectionHandle
- {
- get
- {
- return _connectionHandle;
- }
- set
- {
- _connectionHandle = value;
- }
- }
-
- public Interop.WinHttp.SafeWinHttpHandleWithCallback RequestHandle
- {
- get
- {
- return _requestHandle;
- }
- set
- {
- _requestHandle = value;
- }
- }
-
- public Interop.WinHttp.SafeWinHttpHandleWithCallback WebSocketHandle
- {
- get
- {
- return _webSocketHandle;
- }
- set
- {
- _webSocketHandle = value;
- }
- }
-
- // Important: do not hold _lock while signaling completion of any of below TaskCompletionSources.
- public TaskCompletionSource<bool> TcsUpgrade { get; set; }
- public TaskCompletionSource<bool> TcsSend { get; set; }
- public TaskCompletionSource<bool> TcsReceive { get; set; }
- public TaskCompletionSource<bool> TcsClose { get; set; }
- public TaskCompletionSource<bool> TcsCloseOutput { get; set; }
-
- public bool PendingReadOperation
- {
- get
- {
- return _pendingReadOperation;
- }
-
- set
- {
- _pendingReadOperation = value;
- }
- }
-
- public bool PendingWriteOperation
- {
- get
- {
- return _pendingWriteOperation;
- }
-
- set
- {
- _pendingWriteOperation = value;
- }
- }
-
- public IntPtr ToIntPtr()
- {
- return GCHandle.ToIntPtr(_operationHandle);
- }
-
- public static WinHttpWebSocketState FromIntPtr(IntPtr gcHandle)
- {
- var stateHandle = GCHandle.FromIntPtr(gcHandle);
- return (WinHttpWebSocketState)stateHandle.Target;
- }
-
- public Interop.WinHttp.WINHTTP_WEB_SOCKET_BUFFER_TYPE BufferType { get; set; }
-
- public uint BytesTransferred { get; set; }
-
- public void InterlockedCheckValidStates(WebSocketState[] validStates)
- {
- lock (_lock)
- {
- WebSocketValidate.ThrowIfInvalidState(_state, _disposed, validStates);
- }
- }
-
- public void InterlockedCheckAndUpdateState(
- WebSocketState newState,
- params WebSocketState[] validStates)
- {
- lock (_lock)
- {
- CheckValidState(validStates);
- UpdateState(newState);
- }
- }
-
- // Must be called with Lock taken.
- public void CheckValidState(WebSocketState[] validStates)
- {
- WebSocketValidate.ThrowIfInvalidState(_state, _disposed, validStates);
- }
-
- public void UpdateState(WebSocketState value)
- {
- if ((_state != WebSocketState.Closed) && (_state != WebSocketState.Aborted))
- {
- _state = value;
- }
- }
-
- #region IDisposable Support
- private void Dispose(bool disposing)
- {
- // These will be set to null in the callback.
- _webSocketHandle?.Dispose();
- _requestHandle?.Dispose();
-
- Interop.WinHttp.SafeWinHttpHandle.DisposeAndClearHandle(ref _connectionHandle);
- Interop.WinHttp.SafeWinHttpHandle.DisposeAndClearHandle(ref _sessionHandle);
- }
-
- public void Dispose()
- {
- if (!_disposed)
- {
- // No need to suppress finalization since the finalizer is not overridden.
- Dispose(true);
- _disposed = true;
- }
- }
- #endregion
- }
-}
diff --git a/src/System.Net.WebSockets.Client/tests/ClientWebSocketOptionsTests.Unix.cs b/src/System.Net.WebSockets.Client/tests/ClientWebSocketOptionsTests.Unix.cs
deleted file mode 100644
index 2f1dba038d..0000000000
--- a/src/System.Net.WebSockets.Client/tests/ClientWebSocketOptionsTests.Unix.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Net.Security;
-using System.Net.Test.Common;
-using System.Runtime.InteropServices;
-using System.Security.Authentication.ExtendedProtection;
-using System.Security.Cryptography.X509Certificates;
-using System.Threading.Tasks;
-using Xunit;
-
-namespace System.Net.WebSockets.Client.Tests
-{
- public partial class ClientWebSocketOptionsTests
- {
- internal static bool BackendSupportsCustomCertificateHandling
- {
- get
- {
- if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
- {
- return false;
- }
-
- // For other Unix-based systems it's true if (and only if) the openssl backend
- // is used with libcurl.
- return (CurlSslVersionDescription()?.StartsWith("OpenSSL") ?? false);
- }
- }
-
- [DllImport("System.Net.Http.Native", EntryPoint = "HttpNative_GetSslVersionDescription")]
- private static extern string CurlSslVersionDescription();
- }
-}
diff --git a/src/System.Net.WebSockets.Client/tests/ClientWebSocketOptionsTests.Windows.cs b/src/System.Net.WebSockets.Client/tests/ClientWebSocketOptionsTests.Windows.cs
deleted file mode 100644
index 967efd4474..0000000000
--- a/src/System.Net.WebSockets.Client/tests/ClientWebSocketOptionsTests.Windows.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Net.Security;
-using System.Net.Test.Common;
-using System.Runtime.InteropServices;
-using System.Security.Authentication.ExtendedProtection;
-using System.Security.Cryptography.X509Certificates;
-using System.Threading.Tasks;
-using Xunit;
-
-namespace System.Net.WebSockets.Client.Tests
-{
- public partial class ClientWebSocketOptionsTests
- {
- internal static bool BackendSupportsCustomCertificateHandling => true;
- }
-}
diff --git a/src/System.Net.WebSockets.Client/tests/ClientWebSocketOptionsTests.cs b/src/System.Net.WebSockets.Client/tests/ClientWebSocketOptionsTests.cs
index 3e6615e982..c94f554832 100644
--- a/src/System.Net.WebSockets.Client/tests/ClientWebSocketOptionsTests.cs
+++ b/src/System.Net.WebSockets.Client/tests/ClientWebSocketOptionsTests.cs
@@ -2,11 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Collections.Generic;
using System.Net.Security;
-using System.Net.Sockets;
using System.Net.Test.Common;
-using System.Security.Authentication;
+using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
@@ -18,17 +16,9 @@ namespace System.Net.WebSockets.Client.Tests
{
public partial class ClientWebSocketOptionsTests : ClientWebSocketTestBase
{
- public static bool CanTestCertificates =>
- Capability.IsTrustedRootCertificateInstalled() &&
- (BackendSupportsCustomCertificateHandling || Capability.AreHostsFileNamesInstalled());
-
- public static bool CanTestClientCertificates =>
- CanTestCertificates && BackendSupportsCustomCertificateHandling;
-
// Windows 10 Version 1709 introduced the necessary APIs for the UAP version of
// ClientWebSocket.ConnectAsync to carry out mutual TLS authentication.
- public static bool ClientCertificatesSupported =>
- !PlatformDetection.IsUap || PlatformDetection.IsWindows10Version1709OrGreater;
+ public static bool ClientCertificatesSupported => !PlatformDetection.IsUap;
public ClientWebSocketOptionsTests(ITestOutputHelper output) : base(output) { }
@@ -44,6 +34,77 @@ namespace System.Net.WebSockets.Client.Tests
}
[ConditionalFact(nameof(WebSocketsSupported))]
+ public static void Proxy_Roundtrips()
+ {
+ var cws = new ClientWebSocket();
+
+ Assert.NotNull(cws.Options.Proxy);
+ Assert.Same(cws.Options.Proxy, cws.Options.Proxy);
+
+ IWebProxy p = new WebProxy();
+ cws.Options.Proxy = p;
+ Assert.Same(p, cws.Options.Proxy);
+
+ cws.Options.Proxy = null;
+ Assert.Null(cws.Options.Proxy);
+ }
+
+ [OuterLoop] // TODO: Issue #11345
+ [ConditionalTheory(nameof(WebSocketsSupported)), MemberData(nameof(EchoServers))]
+ public async Task Proxy_SetNull_ConnectsSuccessfully(Uri server)
+ {
+ for (int i = 0; i < 3; i++) // Connect and disconnect multiple times to exercise shared handler on netcoreapp
+ {
+ var ws = await WebSocketHelper.Retry(_output, async () =>
+ {
+ var cws = new ClientWebSocket();
+ cws.Options.Proxy = null;
+ await cws.ConnectAsync(server, default);
+ return cws;
+ });
+ await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, default);
+ ws.Dispose();
+ }
+ }
+
+ [ActiveIssue(28027)]
+ [OuterLoop] // TODO: Issue #11345
+ [ConditionalTheory(nameof(WebSocketsSupported)), MemberData(nameof(EchoServers))]
+ public async Task Proxy_ConnectThruProxy_Success(Uri server)
+ {
+ string proxyServerUri = System.Net.Test.Common.Configuration.WebSockets.ProxyServerUri;
+ if (string.IsNullOrEmpty(proxyServerUri))
+ {
+ _output.WriteLine("Skipping test...no proxy server defined.");
+ return;
+ }
+
+ _output.WriteLine($"ProxyServer: {proxyServerUri}");
+
+ IWebProxy proxy = new WebProxy(new Uri(proxyServerUri));
+ using (ClientWebSocket cws = await WebSocketHelper.GetConnectedWebSocket(
+ server,
+ TimeOutMilliseconds,
+ _output,
+ default(TimeSpan),
+ proxy))
+ {
+ var cts = new CancellationTokenSource(TimeOutMilliseconds);
+ Assert.Equal(WebSocketState.Open, cws.State);
+
+ var closeStatus = WebSocketCloseStatus.NormalClosure;
+ string closeDescription = "Normal Closure";
+
+ await cws.CloseAsync(closeStatus, closeDescription, cts.Token);
+
+ // Verify a clean close frame handshake.
+ Assert.Equal(WebSocketState.Closed, cws.State);
+ Assert.Equal(closeStatus, cws.CloseStatus);
+ Assert.Equal(closeDescription, cws.CloseStatusDescription);
+ }
+ }
+
+ [ConditionalFact(nameof(WebSocketsSupported))]
public static void SetBuffer_InvalidArgs_Throws()
{
// Recreate the minimum WebSocket buffer size values from the .NET Framework version of WebSocket,
@@ -81,48 +142,5 @@ namespace System.Net.WebSockets.Client.Tests
AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => cws.Options.KeepAliveInterval = TimeSpan.MinValue);
}
-
- [OuterLoop] // TODO: Issue #11345
- [ActiveIssue(5120, TargetFrameworkMonikers.Netcoreapp)]
- [ConditionalFact(nameof(WebSocketsSupported), nameof(CanTestClientCertificates), nameof(ClientCertificatesSupported))]
- public async Task ClientCertificates_ValidCertificate_ServerReceivesCertificateAndConnectAsyncSucceeds()
- {
- var options = new LoopbackServer.Options { UseSsl = true, WebSocketEndpoint = true };
-
- Func<ClientWebSocket, Socket, Uri, X509Certificate2, Task> connectToServerWithClientCert = async (clientSocket, server, url, clientCert) =>
- {
- // Start listening for incoming connections on the server side.
- Task<List<string>> acceptTask = LoopbackServer.AcceptSocketAsync(server, async (socket, stream, reader, writer) =>
- {
- // Validate that the client certificate received by the server matches the one configured on
- // the client-side socket.
- SslStream sslStream = Assert.IsType<SslStream>(stream);
- Assert.NotNull(sslStream.RemoteCertificate);
- Assert.Equal(clientCert, new X509Certificate2(sslStream.RemoteCertificate));
-
- // Complete the WebSocket upgrade over the secure channel. After this is done, the client-side
- // ConnectAsync should complete.
- Assert.True(await LoopbackServer.WebSocketHandshakeAsync(socket, reader, writer));
- return null;
- }, options);
-
- // Initiate a connection attempt with a client certificate configured on the socket.
- clientSocket.Options.ClientCertificates.Add(clientCert);
- var cts = new CancellationTokenSource(TimeOutMilliseconds);
- await clientSocket.ConnectAsync(url, cts.Token);
- acceptTask.Wait(cts.Token);
- };
-
- await LoopbackServer.CreateServerAsync(async (server, url) =>
- {
- using (X509Certificate2 clientCert = Test.Common.Configuration.Certificates.GetClientCertificate())
- {
- using (ClientWebSocket clientSocket = new ClientWebSocket())
- {
- await connectToServerWithClientCert(clientSocket, server, url, clientCert);
- }
- }
- }, options);
- }
}
}
diff --git a/src/System.Net.WebSockets.Client/tests/ClientWebSocketOptionsTests.netcoreapp.cs b/src/System.Net.WebSockets.Client/tests/ClientWebSocketOptionsTests.netcoreapp.cs
new file mode 100644
index 0000000000..e7101406fd
--- /dev/null
+++ b/src/System.Net.WebSockets.Client/tests/ClientWebSocketOptionsTests.netcoreapp.cs
@@ -0,0 +1,136 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Net.Security;
+using System.Net.Test.Common;
+using System.Reflection;
+using System.Security.Cryptography.X509Certificates;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Xunit;
+using Xunit.Abstractions;
+
+namespace System.Net.WebSockets.Client.Tests
+{
+ public partial class ClientWebSocketOptionsTests : ClientWebSocketTestBase
+ {
+ [ConditionalFact(nameof(WebSocketsSupported), nameof(ClientCertificatesSupported))]
+ public void RemoteCertificateValidationCallback_Roundtrips()
+ {
+ using (var cws = new ClientWebSocket())
+ {
+ Assert.Null(cws.Options.RemoteCertificateValidationCallback);
+
+ RemoteCertificateValidationCallback callback = delegate { return true; };
+ cws.Options.RemoteCertificateValidationCallback = callback;
+ Assert.Same(callback, cws.Options.RemoteCertificateValidationCallback);
+
+ cws.Options.RemoteCertificateValidationCallback = null;
+ Assert.Null(cws.Options.RemoteCertificateValidationCallback);
+ }
+ }
+
+ [OuterLoop("Connects to remote service")]
+ [ConditionalTheory(nameof(WebSocketsSupported), nameof(ClientCertificatesSupported))]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task RemoteCertificateValidationCallback_PassedRemoteCertificateInfo(bool secure)
+ {
+ if (PlatformDetection.IsWindows7)
+ {
+ return; // [ActiveIssue(27846)]
+ }
+
+ bool callbackInvoked = false;
+
+ await LoopbackServer.CreateClientAndServerAsync(async uri =>
+ {
+ using (var cws = new ClientWebSocket())
+ using (var cts = new CancellationTokenSource(TimeOutMilliseconds))
+ {
+ cws.Options.RemoteCertificateValidationCallback = (source, cert, chain, errors) =>
+ {
+ Assert.NotNull(source);
+ Assert.NotNull(cert);
+ Assert.NotNull(chain);
+ Assert.NotEqual(SslPolicyErrors.None, errors);
+ callbackInvoked = true;
+ return true;
+ };
+ await cws.ConnectAsync(uri, cts.Token);
+ }
+ }, server => server.AcceptConnectionAsync(async connection =>
+ {
+ Assert.True(await LoopbackHelper.WebSocketHandshakeAsync(connection));
+ }),
+ new LoopbackServer.Options { UseSsl = secure, WebSocketEndpoint = true });
+
+ Assert.Equal(secure, callbackInvoked);
+ }
+
+ [OuterLoop("Connects to remote service")]
+ [ConditionalFact(nameof(WebSocketsSupported), nameof(ClientCertificatesSupported))]
+ public async Task ClientCertificates_ValidCertificate_ServerReceivesCertificateAndConnectAsyncSucceeds()
+ {
+ if (PlatformDetection.IsWindows7)
+ {
+ return; // [ActiveIssue(27846)]
+ }
+
+ using (X509Certificate2 clientCert = Test.Common.Configuration.Certificates.GetClientCertificate())
+ {
+ await LoopbackServer.CreateClientAndServerAsync(async uri =>
+ {
+ using (var clientSocket = new ClientWebSocket())
+ using (var cts = new CancellationTokenSource(TimeOutMilliseconds))
+ {
+ clientSocket.Options.ClientCertificates.Add(clientCert);
+ clientSocket.Options.RemoteCertificateValidationCallback = delegate { return true; };
+ await clientSocket.ConnectAsync(uri, cts.Token);
+ }
+ }, server => server.AcceptConnectionAsync(async connection =>
+ {
+ // Validate that the client certificate received by the server matches the one configured on
+ // the client-side socket.
+ SslStream sslStream = Assert.IsType<SslStream>(connection.Stream);
+ Assert.NotNull(sslStream.RemoteCertificate);
+ Assert.Equal(clientCert, new X509Certificate2(sslStream.RemoteCertificate));
+
+ // Complete the WebSocket upgrade over the secure channel. After this is done, the client-side
+ // ConnectAsync should complete.
+ Assert.True(await LoopbackHelper.WebSocketHandshakeAsync(connection));
+ }), new LoopbackServer.Options { UseSsl = true, WebSocketEndpoint = true });
+ }
+ }
+
+ [ConditionalTheory(nameof(WebSocketsSupported))]
+ [InlineData("ws://")]
+ [InlineData("wss://")]
+ public async Task NonSecureConnect_ConnectThruProxy_CONNECTisUsed(string connectionType)
+ {
+ if (PlatformDetection.IsWindows7)
+ {
+ return; // [ActiveIssue(27846)]
+ }
+
+ bool connectionAccepted = false;
+
+ await LoopbackServer.CreateClientAndServerAsync(async proxyUri =>
+ {
+ using (var cws = new ClientWebSocket())
+ {
+ cws.Options.Proxy = new WebProxy(proxyUri);
+ try { await cws.ConnectAsync(new Uri(connectionType + Guid.NewGuid().ToString("N")), default); } catch { }
+ }
+ }, server => server.AcceptConnectionAsync(async connection =>
+ {
+ Assert.Contains("CONNECT", await connection.Reader.ReadLineAsync());
+ connectionAccepted = true;
+ }));
+
+ Assert.True(connectionAccepted);
+ }
+ }
+}
diff --git a/src/System.Net.WebSockets.Client/tests/ClientWebSocketUnitTest.cs b/src/System.Net.WebSockets.Client/tests/ClientWebSocketUnitTest.cs
index 44fcf82070..0314befd4f 100644
--- a/src/System.Net.WebSockets.Client/tests/ClientWebSocketUnitTest.cs
+++ b/src/System.Net.WebSockets.Client/tests/ClientWebSocketUnitTest.cs
@@ -2,11 +2,12 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Common.Tests;
+using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
-using Xunit.Abstractions;
namespace System.Net.WebSockets.Client.Tests
{
@@ -15,16 +16,8 @@ namespace System.Net.WebSockets.Client.Tests
/// </summary>
public class ClientWebSocketUnitTest
{
- private readonly ITestOutputHelper _output;
-
- public ClientWebSocketUnitTest(ITestOutputHelper output)
- {
- _output = output;
- }
-
private static bool WebSocketsSupported { get { return WebSocketHelper.WebSocketsSupported; } }
- [OuterLoop] // TODO: Issue #11345
[ConditionalFact(nameof(WebSocketsSupported))]
public void Ctor_Success()
{
@@ -32,7 +25,6 @@ namespace System.Net.WebSockets.Client.Tests
cws.Dispose();
}
- [OuterLoop] // TODO: Issue #11345
[ConditionalFact(nameof(WebSocketsSupported))]
public void Abort_CreateAndAbort_StateIsClosed()
{
@@ -44,7 +36,6 @@ namespace System.Net.WebSockets.Client.Tests
}
}
- [OuterLoop] // TODO: Issue #11345
[ConditionalFact(nameof(WebSocketsSupported))]
public void CloseAsync_CreateAndClose_ThrowsInvalidOperationException()
{
@@ -57,14 +48,21 @@ namespace System.Net.WebSockets.Client.Tests
}
}
- [OuterLoop] // TODO: Issue #11345
[ConditionalFact(nameof(WebSocketsSupported))]
public async Task CloseAsync_CreateAndCloseOutput_ThrowsInvalidOperationExceptionWithMessage()
{
using (var cws = new ClientWebSocket())
{
- var exception = await Assert.ThrowsAsync<InvalidOperationException>(
- () => cws.CloseOutputAsync(WebSocketCloseStatus.Empty, "", new CancellationToken()));
+ InvalidOperationException exception;
+ using (var tcc = new ThreadCultureChange())
+ {
+ // The .Net Native toolchain optimizes away exception messages.
+ if (!PlatformDetection.IsNetNative)
+ tcc.ChangeCultureInfo(CultureInfo.InvariantCulture);
+
+ exception = await Assert.ThrowsAsync<InvalidOperationException>(
+ () => cws.CloseOutputAsync(WebSocketCloseStatus.Empty, "", new CancellationToken()));
+ }
// The .Net Native toolchain optimizes away exception messages.
if (!PlatformDetection.IsNetNative)
@@ -77,7 +75,6 @@ namespace System.Net.WebSockets.Client.Tests
}
}
- [OuterLoop] // TODO: Issue #11345
[ConditionalFact(nameof(WebSocketsSupported))]
public void CloseAsync_CreateAndReceive_ThrowsInvalidOperationException()
{
@@ -94,7 +91,6 @@ namespace System.Net.WebSockets.Client.Tests
}
}
- [OuterLoop] // TODO: Issue #11345
[ConditionalFact(nameof(WebSocketsSupported))]
public async Task CloseAsync_CreateAndReceive_ThrowsInvalidOperationExceptionWithMessage()
{
@@ -104,8 +100,17 @@ namespace System.Net.WebSockets.Client.Tests
var segment = new ArraySegment<byte>(buffer);
var ct = new CancellationToken();
- var exception = await Assert.ThrowsAsync<InvalidOperationException>(
- () => cws.ReceiveAsync(segment, ct));
+ InvalidOperationException exception;
+
+ using (var tcc = new ThreadCultureChange())
+ {
+ // The .Net Native toolchain optimizes away exception messages.
+ if (!PlatformDetection.IsNetNative)
+ tcc.ChangeCultureInfo(CultureInfo.InvariantCulture);
+
+ exception = await Assert.ThrowsAsync<InvalidOperationException>(
+ () => cws.ReceiveAsync(segment, ct));
+ }
// The .Net Native toolchain optimizes away exception messages.
if (!PlatformDetection.IsNetNative)
@@ -118,7 +123,6 @@ namespace System.Net.WebSockets.Client.Tests
}
}
- [OuterLoop] // TODO: Issue #11345
[ConditionalFact(nameof(WebSocketsSupported))]
public void CloseAsync_CreateAndSend_ThrowsInvalidOperationException()
{
@@ -135,7 +139,6 @@ namespace System.Net.WebSockets.Client.Tests
}
}
- [OuterLoop] // TODO: Issue #11345
[ConditionalFact(nameof(WebSocketsSupported))]
public async Task CloseAsync_CreateAndSend_ThrowsInvalidOperationExceptionWithMessage()
{
@@ -145,8 +148,16 @@ namespace System.Net.WebSockets.Client.Tests
var segment = new ArraySegment<byte>(buffer);
var ct = new CancellationToken();
- var exception = await Assert.ThrowsAsync<InvalidOperationException>(
- () => cws.SendAsync(segment, WebSocketMessageType.Text, false, ct));
+ InvalidOperationException exception;
+ using (var tcc = new ThreadCultureChange())
+ {
+ // The .Net Native toolchain optimizes away exception messages.
+ if (!PlatformDetection.IsNetNative)
+ tcc.ChangeCultureInfo(CultureInfo.InvariantCulture);
+
+ exception = await Assert.ThrowsAsync<InvalidOperationException>(
+ () => cws.SendAsync(segment, WebSocketMessageType.Text, false, ct));
+ }
// The .Net Native toolchain optimizes away exception messages.
if (!PlatformDetection.IsNetNative)
@@ -159,7 +170,6 @@ namespace System.Net.WebSockets.Client.Tests
}
}
- [OuterLoop] // TODO: Issue #11345
[ConditionalFact(nameof(WebSocketsSupported))]
public void Ctor_ExpectedPropertyValues()
{
@@ -174,7 +184,6 @@ namespace System.Net.WebSockets.Client.Tests
}
}
- [OuterLoop] // TODO: Issue #11345
[ConditionalFact(nameof(WebSocketsSupported))]
public void Abort_CreateAndDisposeAndAbort_StateIsClosedSuccess()
{
@@ -185,7 +194,6 @@ namespace System.Net.WebSockets.Client.Tests
Assert.Equal(WebSocketState.Closed, cws.State);
}
- [OuterLoop] // TODO: Issue #11345
[ConditionalFact(nameof(WebSocketsSupported))]
public void CloseAsync_DisposeAndClose_ThrowsObjectDisposedException()
{
@@ -198,7 +206,6 @@ namespace System.Net.WebSockets.Client.Tests
Assert.Equal(WebSocketState.Closed, cws.State);
}
- [OuterLoop] // TODO: Issue #11345
[ConditionalFact(nameof(WebSocketsSupported))]
public void CloseAsync_DisposeAndCloseOutput_ThrowsObjectDisposedExceptionWithMessage()
{
@@ -215,7 +222,6 @@ namespace System.Net.WebSockets.Client.Tests
Assert.Equal(WebSocketState.Closed, cws.State);
}
- [OuterLoop] // TODO: Issue #11345
[ConditionalFact(nameof(WebSocketsSupported))]
public void ReceiveAsync_CreateAndDisposeAndReceive_ThrowsObjectDisposedExceptionWithMessage()
{
@@ -235,7 +241,6 @@ namespace System.Net.WebSockets.Client.Tests
Assert.Equal(WebSocketState.Closed, cws.State);
}
- [OuterLoop] // TODO: Issue #11345
[ConditionalFact(nameof(WebSocketsSupported))]
public void SendAsync_CreateAndDisposeAndSend_ThrowsObjectDisposedExceptionWithMessage()
{
@@ -255,7 +260,6 @@ namespace System.Net.WebSockets.Client.Tests
Assert.Equal(WebSocketState.Closed, cws.State);
}
- [OuterLoop] // TODO: Issue #11345
[ConditionalFact(nameof(WebSocketsSupported))]
public void Dispose_CreateAndDispose_ExpectedPropertyValues()
{
diff --git a/src/System.Net.WebSockets.Client/tests/LoopbackHelper.cs b/src/System.Net.WebSockets.Client/tests/LoopbackHelper.cs
new file mode 100644
index 0000000000..093250cf0b
--- /dev/null
+++ b/src/System.Net.WebSockets.Client/tests/LoopbackHelper.cs
@@ -0,0 +1,59 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Net.Test.Common;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace System.Net.WebSockets.Client.Tests
+{
+ public static class LoopbackHelper
+ {
+ public static async Task<bool> WebSocketHandshakeAsync(LoopbackServer.Connection connection)
+ {
+ string serverResponse = null;
+ string currentRequestLine;
+ while (!string.IsNullOrEmpty(currentRequestLine = await connection.Reader.ReadLineAsync().ConfigureAwait(false)))
+ {
+ string[] tokens = currentRequestLine.Split(new char[] { ':' }, 2);
+ if (tokens.Length == 2)
+ {
+ string headerName = tokens[0];
+ if (headerName == "Sec-WebSocket-Key")
+ {
+ string headerValue = tokens[1].Trim();
+ string responseSecurityAcceptValue = ComputeWebSocketHandshakeSecurityAcceptValue(headerValue);
+ serverResponse =
+ "HTTP/1.1 101 Switching Protocols\r\n" +
+ "Upgrade: websocket\r\n" +
+ "Connection: Upgrade\r\n" +
+ "Sec-WebSocket-Accept: " + responseSecurityAcceptValue + "\r\n\r\n";
+ }
+ }
+ }
+
+ if (serverResponse != null)
+ {
+ // We received a valid WebSocket opening handshake. Send the appropriate response.
+ await connection.Writer.WriteAsync(serverResponse).ConfigureAwait(false);
+ return true;
+ }
+
+ return false;
+ }
+
+ private static string ComputeWebSocketHandshakeSecurityAcceptValue(string secWebSocketKey)
+ {
+ // GUID specified by RFC 6455.
+ const string Rfc6455Guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+ string combinedKey = secWebSocketKey + Rfc6455Guid;
+
+ // Use of SHA1 hash is required by RFC 6455.
+ SHA1 sha1Provider = new SHA1CryptoServiceProvider();
+ byte[] sha1Hash = sha1Provider.ComputeHash(Encoding.UTF8.GetBytes(combinedKey));
+ return Convert.ToBase64String(sha1Hash);
+ }
+ }
+}
diff --git a/src/System.Net.WebSockets.Client/tests/SendReceiveTest.cs b/src/System.Net.WebSockets.Client/tests/SendReceiveTest.cs
index 82ec689f2e..e2235068b6 100644
--- a/src/System.Net.WebSockets.Client/tests/SendReceiveTest.cs
+++ b/src/System.Net.WebSockets.Client/tests/SendReceiveTest.cs
@@ -2,8 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Collections.Generic;
-using System.ComponentModel;
using System.Net.Sockets;
using System.Net.Test.Common;
using System.Threading;
@@ -305,7 +303,6 @@ namespace System.Net.WebSockets.Client.Tests
}
}
- [ActiveIssue(23765)]
[OuterLoop] // TODO: Issue #11345
[ConditionalTheory(nameof(WebSocketsSupported)), MemberData(nameof(EchoServers))]
public async Task SendReceive_VaryingLengthBuffers_Success(Uri server)
@@ -381,25 +378,23 @@ namespace System.Net.WebSockets.Client.Tests
{
var options = new LoopbackServer.Options { WebSocketEndpoint = true };
- Func<ClientWebSocket, Socket, Uri, Task> connectToServerThatAbortsConnection = async (clientSocket, server, url) =>
+ Func<ClientWebSocket, LoopbackServer, Uri, Task> connectToServerThatAbortsConnection = async (clientSocket, server, url) =>
{
AutoResetEvent pendingReceiveAsyncPosted = new AutoResetEvent(false);
// Start listening for incoming connections on the server side.
- Task<List<string>> acceptTask = LoopbackServer.AcceptSocketAsync(server, async (socket, stream, reader, writer) =>
+ Task acceptTask = server.AcceptConnectionAsync(async connection =>
{
// Complete the WebSocket upgrade. After this is done, the client-side ConnectAsync should complete.
- Assert.True(await LoopbackServer.WebSocketHandshakeAsync(socket, reader, writer));
+ Assert.True(await LoopbackHelper.WebSocketHandshakeAsync(connection));
// Wait for client-side ConnectAsync to complete and for a pending ReceiveAsync to be posted.
pendingReceiveAsyncPosted.WaitOne(TimeOutMilliseconds);
// Close the underlying connection prematurely (without sending a WebSocket Close frame).
- socket.Shutdown(SocketShutdown.Both);
- socket.Close();
-
- return null;
- }, options);
+ connection.Socket.Shutdown(SocketShutdown.Both);
+ connection.Socket.Close();
+ });
// Initiate a connection attempt.
var cts = new CancellationTokenSource(TimeOutMilliseconds);
@@ -414,75 +409,27 @@ namespace System.Net.WebSockets.Client.Tests
// Wait for the server to close the underlying connection.
acceptTask.Wait(cts.Token);
- // Validate I/O errors and socket state.
- if (!PlatformDetection.IsWindows)
- {
- _output.WriteLine("[Non-Windows] ManagedWebSocket-based implementation.");
-
- WebSocketException pendingReceiveException = await Assert.ThrowsAsync<WebSocketException>(() => pendingReceiveAsync);
- Assert.Equal(WebSocketError.ConnectionClosedPrematurely, pendingReceiveException.WebSocketErrorCode);
-
- WebSocketException newReceiveException =
- await Assert.ThrowsAsync<WebSocketException>(() => ReceiveAsync(clientSocket, recvSegment, cts.Token));
- Assert.Equal(WebSocketError.ConnectionClosedPrematurely, newReceiveException.WebSocketErrorCode);
-
- Assert.Equal(WebSocketState.Open, clientSocket.State);
- Assert.Null(clientSocket.CloseStatus);
- }
- else if (PlatformDetection.IsFullFramework)
- {
- _output.WriteLine("[Windows] ManagedWebSocket-based implementation.");
-
- WebSocketException pendingReceiveException = await Assert.ThrowsAsync<WebSocketException>(() => pendingReceiveAsync);
- Assert.Equal(WebSocketError.ConnectionClosedPrematurely, pendingReceiveException.WebSocketErrorCode);
+ WebSocketException pendingReceiveException = await Assert.ThrowsAsync<WebSocketException>(() => pendingReceiveAsync);
- WebSocketException newReceiveException =
- await Assert.ThrowsAsync<WebSocketException>(() => ReceiveAsync(clientSocket, recvSegment, cts.Token));
- Assert.Equal(WebSocketError.Success, newReceiveException.WebSocketErrorCode);
- Assert.Equal(
- ResourceHelper.GetExceptionMessage("net_WebSockets_InvalidState", "Aborted", "Open, CloseSent"),
- newReceiveException.Message);
+ Assert.Equal(WebSocketError.ConnectionClosedPrematurely, pendingReceiveException.WebSocketErrorCode);
- Assert.Equal(WebSocketState.Aborted, clientSocket.State);
- Assert.Null(clientSocket.CloseStatus);
- }
- else if (PlatformDetection.IsUap)
+ if (PlatformDetection.IsUap)
{
- _output.WriteLine("WinRTWebSocket-based implementation.");
-
const uint WININET_E_CONNECTION_ABORTED = 0x80072EFE;
- WebSocketException pendingReceiveException = await Assert.ThrowsAsync<WebSocketException>(() => pendingReceiveAsync);
- Assert.Equal(WebSocketError.ConnectionClosedPrematurely, pendingReceiveException.WebSocketErrorCode);
Assert.NotNull(pendingReceiveException.InnerException);
Assert.Equal(WININET_E_CONNECTION_ABORTED, (uint)pendingReceiveException.InnerException.HResult);
-
- WebSocketException newReceiveException =
- await Assert.ThrowsAsync<WebSocketException>(() => ReceiveAsync(clientSocket, recvSegment, cts.Token));
- Assert.Equal(WebSocketError.Success, newReceiveException.WebSocketErrorCode);
- Assert.Equal(
- ResourceHelper.GetExceptionMessage("net_WebSockets_InvalidState", "Aborted", "Open, CloseSent"),
- newReceiveException.Message);
-
- Assert.Equal(WebSocketState.Aborted, clientSocket.State);
- Assert.Null(clientSocket.CloseStatus);
}
- else
- {
- _output.WriteLine("WinHttpWebSocket-based implementation.");
-
- const uint WININET_E_CONNECTION_RESET = 0x80072eff;
- Win32Exception pendingReceiveException = await Assert.ThrowsAnyAsync<Win32Exception>(() => pendingReceiveAsync);
- Assert.Equal(WININET_E_CONNECTION_RESET, (uint)pendingReceiveException.HResult);
-
- Win32Exception newReceiveException =
- await Assert.ThrowsAnyAsync<Win32Exception>(() => ReceiveAsync(clientSocket, recvSegment, cts.Token));
- Assert.Equal(WININET_E_CONNECTION_RESET, (uint)newReceiveException.HResult);
+ WebSocketException newReceiveException =
+ await Assert.ThrowsAsync<WebSocketException>(() => ReceiveAsync(clientSocket, recvSegment, cts.Token));
+
+ Assert.Equal(
+ ResourceHelper.GetExceptionMessage("net_WebSockets_InvalidState", "Aborted", "Open, CloseSent"),
+ newReceiveException.Message);
- Assert.Equal(WebSocketState.Open, clientSocket.State);
- Assert.Null(clientSocket.CloseStatus);
- }
+ Assert.Equal(WebSocketState.Aborted, clientSocket.State);
+ Assert.Null(clientSocket.CloseStatus);
};
await LoopbackServer.CreateServerAsync(async (server, url) =>
@@ -493,5 +440,42 @@ namespace System.Net.WebSockets.Client.Tests
}
}, options);
}
+
+ [OuterLoop] // TODO: Issue #11345
+ [ConditionalTheory(nameof(WebSocketsSupported)), MemberData(nameof(EchoServers))]
+ public async Task ZeroByteReceive_CompletesWhenDataAvailable(Uri server)
+ {
+ using (ClientWebSocket cws = await WebSocketHelper.GetConnectedWebSocket(server, TimeOutMilliseconds, _output))
+ {
+ var rand = new Random();
+ var ctsDefault = new CancellationTokenSource(TimeOutMilliseconds);
+
+ // Do a 0-byte receive. It shouldn't complete yet.
+ Task<WebSocketReceiveResult> t = ReceiveAsync(cws, new ArraySegment<byte>(Array.Empty<byte>()), ctsDefault.Token);
+ Assert.False(t.IsCompleted);
+
+ // Send a packet to the echo server.
+ await SendAsync(cws, new ArraySegment<byte>(new byte[1] { 42 }), WebSocketMessageType.Binary, true, ctsDefault.Token);
+
+ // Now the 0-byte receive should complete, but without reading any data.
+ WebSocketReceiveResult r = await t;
+ Assert.Equal(WebSocketMessageType.Binary, r.MessageType);
+ Assert.Equal(0, r.Count);
+ Assert.False(r.EndOfMessage);
+
+ // Now do a receive to get the payload.
+ var receiveBuffer = new byte[1];
+ t = ReceiveAsync(cws, new ArraySegment<byte>(receiveBuffer), ctsDefault.Token);
+ Assert.Equal(TaskStatus.RanToCompletion, t.Status);
+ r = await t;
+ Assert.Equal(WebSocketMessageType.Binary, r.MessageType);
+ Assert.Equal(1, r.Count);
+ Assert.True(r.EndOfMessage);
+ Assert.Equal(42, receiveBuffer[0]);
+
+ // Clean up.
+ await cws.CloseAsync(WebSocketCloseStatus.NormalClosure, nameof(ZeroByteReceive_CompletesWhenDataAvailable), ctsDefault.Token);
+ }
+ }
}
}
diff --git a/src/System.Net.WebSockets.Client/tests/SendReceiveTest.netcoreapp.cs b/src/System.Net.WebSockets.Client/tests/SendReceiveTest.netcoreapp.cs
index 4c7759cba0..778ba03213 100644
--- a/src/System.Net.WebSockets.Client/tests/SendReceiveTest.netcoreapp.cs
+++ b/src/System.Net.WebSockets.Client/tests/SendReceiveTest.netcoreapp.cs
@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Xunit.Abstractions;
@@ -16,16 +15,16 @@ namespace System.Net.WebSockets.Client.Tests
protected override async Task<WebSocketReceiveResult> ReceiveAsync(WebSocket ws, ArraySegment<byte> arraySegment, CancellationToken cancellationToken)
{
ValueWebSocketReceiveResult r = await ws.ReceiveAsync(
- arraySegment == default(ArraySegment<byte>) ? Memory<byte>.Empty : (Memory<byte>)arraySegment,
+ (Memory<byte>)arraySegment,
cancellationToken);
return new WebSocketReceiveResult(r.Count, r.MessageType, r.EndOfMessage, ws.CloseStatus, ws.CloseStatusDescription);
}
protected override Task SendAsync(WebSocket ws, ArraySegment<byte> arraySegment, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken) =>
ws.SendAsync(
- arraySegment == default(ArraySegment<byte>) ? ReadOnlyMemory<byte>.Empty : (ReadOnlyMemory<byte>)arraySegment,
+ (ReadOnlyMemory<byte>)arraySegment,
messageType,
endOfMessage,
- cancellationToken);
+ cancellationToken).AsTask();
}
}
diff --git a/src/System.Net.WebSockets.Client/tests/System.Net.WebSockets.Client.Tests.csproj b/src/System.Net.WebSockets.Client/tests/System.Net.WebSockets.Client.Tests.csproj
index 206d82430f..4b57c19a40 100644
--- a/src/System.Net.WebSockets.Client/tests/System.Net.WebSockets.Client.Tests.csproj
+++ b/src/System.Net.WebSockets.Client/tests/System.Net.WebSockets.Client.Tests.csproj
@@ -39,17 +39,23 @@
<Compile Include="$(CommonTestPath)\System\Net\Http\LoopbackServer.cs">
<Link>Common\System\Net\Http\LoopbackServer.cs</Link>
</Compile>
+ <Compile Include="$(CommonTestPath)\System\Threading\Tasks\TaskTimeoutExtensions.cs">
+ <Link>Common\System\Threading\Tasks\TaskTimeoutExtensions.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\ThreadCultureChange.cs">
+ <Link>Common\System\ThreadCultureChange.cs</Link>
+ </Compile>
<Compile Include="AbortTest.cs" />
<Compile Include="CancelTest.cs" />
<Compile Include="ClientWebSocketOptionsTests.cs" />
- <Compile Include="ClientWebSocketOptionsTests.Unix.cs" Condition="'$(TargetsUnix)' == 'true'" />
- <Compile Include="ClientWebSocketOptionsTests.Windows.cs" Condition="'$(TargetsWindows)' == 'true'" />
+ <Compile Include="ClientWebSocketOptionsTests.netcoreapp.cs" Condition="'$(TargetGroup)' == 'netcoreapp'" />
<Compile Include="ClientWebSocketTestBase.cs" />
<Compile Include="ClientWebSocketUnitTest.cs" />
<Compile Include="CloseTest.cs" />
<Compile Include="ConnectTest.cs" />
<Compile Include="LoggingTest.cs" />
<Compile Include="KeepAliveTest.cs" />
+ <Compile Include="LoopbackHelper.cs" />
<Compile Include="ResourceHelper.cs" />
<Compile Include="SendReceiveTest.netcoreapp.cs" Condition="'$(TargetGroup)' == 'netcoreapp'" />
<Compile Include="SendReceiveTest.cs" />
diff --git a/src/System.Net.WebSockets.Client/tests/WebSocketHelper.cs b/src/System.Net.WebSockets.Client/tests/WebSocketHelper.cs
index 38dd18f4e5..e5b95119ca 100644
--- a/src/System.Net.WebSockets.Client/tests/WebSocketHelper.cs
+++ b/src/System.Net.WebSockets.Client/tests/WebSocketHelper.cs
@@ -61,11 +61,43 @@ namespace System.Net.WebSockets.Client.Tests
}
}
- public static async Task<ClientWebSocket> GetConnectedWebSocket(
+ public static Task<ClientWebSocket> GetConnectedWebSocket(
Uri server,
int timeOutMilliseconds,
ITestOutputHelper output,
- TimeSpan keepAliveInterval = default(TimeSpan))
+ TimeSpan keepAliveInterval = default,
+ IWebProxy proxy = null) =>
+ Retry(output, async () =>
+ {
+ var cws = new ClientWebSocket();
+ if (proxy != null)
+ {
+ cws.Options.Proxy = proxy;
+ }
+
+ if (keepAliveInterval.TotalSeconds > 0)
+ {
+ cws.Options.KeepAliveInterval = keepAliveInterval;
+ }
+
+ using (var cts = new CancellationTokenSource(timeOutMilliseconds))
+ {
+ output.WriteLine("GetConnectedWebSocket: ConnectAsync starting.");
+ Task taskConnect = cws.ConnectAsync(server, cts.Token);
+ Assert.True(
+ (cws.State == WebSocketState.None) ||
+ (cws.State == WebSocketState.Connecting) ||
+ (cws.State == WebSocketState.Open) ||
+ (cws.State == WebSocketState.Aborted),
+ "State immediately after ConnectAsync incorrect: " + cws.State);
+ await taskConnect;
+ output.WriteLine("GetConnectedWebSocket: ConnectAsync done.");
+ Assert.Equal(WebSocketState.Open, cws.State);
+ }
+ return cws;
+ });
+
+ public static async Task<T> Retry<T>(ITestOutputHelper output, Func<Task<T>> func)
{
const int MaxTries = 5;
int betweenTryDelayMilliseconds = 1000;
@@ -74,27 +106,7 @@ namespace System.Net.WebSockets.Client.Tests
{
try
{
- var cws = new ClientWebSocket();
- if (keepAliveInterval.TotalSeconds > 0)
- {
- cws.Options.KeepAliveInterval = keepAliveInterval;
- }
-
- using (var cts = new CancellationTokenSource(timeOutMilliseconds))
- {
- output.WriteLine("GetConnectedWebSocket: ConnectAsync starting.");
- Task taskConnect = cws.ConnectAsync(server, cts.Token);
- Assert.True(
- (cws.State == WebSocketState.None) ||
- (cws.State == WebSocketState.Connecting) ||
- (cws.State == WebSocketState.Open) ||
- (cws.State == WebSocketState.Aborted),
- "State immediately after ConnectAsync incorrect: " + cws.State);
- await taskConnect;
- output.WriteLine("GetConnectedWebSocket: ConnectAsync done.");
- Assert.Equal(WebSocketState.Open, cws.State);
- }
- return cws;
+ return await func();
}
catch (WebSocketException exc)
{
diff --git a/src/System.Net.WebSockets.WebSocketProtocol/System.Net.WebSockets.WebSocketProtocol.sln b/src/System.Net.WebSockets.WebSocketProtocol/System.Net.WebSockets.WebSocketProtocol.sln
index 74e571f6e3..6d49347244 100644
--- a/src/System.Net.WebSockets.WebSocketProtocol/System.Net.WebSockets.WebSocketProtocol.sln
+++ b/src/System.Net.WebSockets.WebSocketProtocol/System.Net.WebSockets.WebSocketProtocol.sln
@@ -1,55 +1,50 @@
-
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27214.1
+# Visual Studio 14
+VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Net.WebSockets.WebSocketProtocol.Tests", "tests\System.Net.WebSockets.WebSocketProtocol.Tests.csproj", "{CF73547B-07D2-4290-A14A-CA2A354F4D21}"
+ ProjectSection(ProjectDependencies) = postProject
+ {747BE014-7C1D-4460-95AF-B41C35717165} = {747BE014-7C1D-4460-95AF-B41C35717165}
+ EndProjectSection
+EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Net.WebSockets.WebSocketProtocol", "src\System.Net.WebSockets.WebSocketProtocol.csproj", "{747BE014-7C1D-4460-95AF-B41C35717165}"
+ ProjectSection(ProjectDependencies) = postProject
+ {203345A4-0E3B-43C1-ADEB-FF493E578063} = {203345A4-0E3B-43C1-ADEB-FF493E578063}
+ EndProjectSection
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{D5A36F24-E27C-43DF-8658-10C5290423E0}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Net.WebSockets.WebSocketProtocol", "ref\System.Net.WebSockets.WebSocketProtocol.csproj", "{203345A4-0E3B-43C1-ADEB-FF493E578063}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{9D10D7AD-2F8C-4F7A-B0FA-E5EB3ECE287F}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{1A2F9F4A-A032-433E-B914-ADD5992BB178}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Net.WebSockets.WebSocketProtocol", "ref\System.Net.WebSockets.WebSocketProtocol.csproj", "{4EDBE9F5-D10A-4553-AE24-2E0E946B15B0}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E107E9C1-E893-4E87-987E-04EF0DCEAEFD}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{F47347C3-433C-4D3B-90F9-487FE7F4F444}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Net.WebSockets.WebSocketProtocol.Tests", "tests\System.Net.WebSockets.WebSocketProtocol.Tests.csproj", "{CF73547B-07D2-4290-A14A-CA2A354F4D21}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{2E666815-2EDB-464B-9DF6-380BF4789AD4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
- netstandard-Debug|Any CPU = netstandard-Debug|Any CPU
- netstandard-Release|Any CPU = netstandard-Release|Any CPU
+ Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {747BE014-7C1D-4460-95AF-B41C35717165}.Debug|Any CPU.ActiveCfg = netstandard-Debug|Any CPU
- {747BE014-7C1D-4460-95AF-B41C35717165}.Debug|Any CPU.Build.0 = netstandard-Debug|Any CPU
- {747BE014-7C1D-4460-95AF-B41C35717165}.netstandard-Debug|Any CPU.ActiveCfg = netstandard-Debug|Any CPU
- {747BE014-7C1D-4460-95AF-B41C35717165}.netstandard-Debug|Any CPU.Build.0 = netstandard-Debug|Any CPU
- {747BE014-7C1D-4460-95AF-B41C35717165}.netstandard-Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
- {747BE014-7C1D-4460-95AF-B41C35717165}.netstandard-Release|Any CPU.Build.0 = netstandard-Release|Any CPU
- {4EDBE9F5-D10A-4553-AE24-2E0E946B15B0}.Debug|Any CPU.ActiveCfg = netstandard-Debug|Any CPU
- {4EDBE9F5-D10A-4553-AE24-2E0E946B15B0}.Debug|Any CPU.Build.0 = netstandard-Debug|Any CPU
- {4EDBE9F5-D10A-4553-AE24-2E0E946B15B0}.netstandard-Debug|Any CPU.ActiveCfg = netstandard-Debug|Any CPU
- {4EDBE9F5-D10A-4553-AE24-2E0E946B15B0}.netstandard-Debug|Any CPU.Build.0 = netstandard-Debug|Any CPU
- {4EDBE9F5-D10A-4553-AE24-2E0E946B15B0}.netstandard-Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
- {4EDBE9F5-D10A-4553-AE24-2E0E946B15B0}.netstandard-Release|Any CPU.Build.0 = netstandard-Release|Any CPU
- {CF73547B-07D2-4290-A14A-CA2A354F4D21}.Debug|Any CPU.ActiveCfg = netstandard-Debug|Any CPU
- {CF73547B-07D2-4290-A14A-CA2A354F4D21}.Debug|Any CPU.Build.0 = netstandard-Debug|Any CPU
- {CF73547B-07D2-4290-A14A-CA2A354F4D21}.netstandard-Debug|Any CPU.ActiveCfg = netstandard-Debug|Any CPU
- {CF73547B-07D2-4290-A14A-CA2A354F4D21}.netstandard-Debug|Any CPU.Build.0 = netstandard-Debug|Any CPU
- {CF73547B-07D2-4290-A14A-CA2A354F4D21}.netstandard-Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
- {CF73547B-07D2-4290-A14A-CA2A354F4D21}.netstandard-Release|Any CPU.Build.0 = netstandard-Release|Any CPU
+ {CF73547B-07D2-4290-A14A-CA2A354F4D21}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
+ {CF73547B-07D2-4290-A14A-CA2A354F4D21}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
+ {CF73547B-07D2-4290-A14A-CA2A354F4D21}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
+ {CF73547B-07D2-4290-A14A-CA2A354F4D21}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
+ {747BE014-7C1D-4460-95AF-B41C35717165}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
+ {747BE014-7C1D-4460-95AF-B41C35717165}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
+ {747BE014-7C1D-4460-95AF-B41C35717165}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
+ {747BE014-7C1D-4460-95AF-B41C35717165}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
+ {203345A4-0E3B-43C1-ADEB-FF493E578063}.Debug|Any CPU.ActiveCfg = netstandard-Debug|Any CPU
+ {203345A4-0E3B-43C1-ADEB-FF493E578063}.Debug|Any CPU.Build.0 = netstandard-Debug|Any CPU
+ {203345A4-0E3B-43C1-ADEB-FF493E578063}.Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
+ {203345A4-0E3B-43C1-ADEB-FF493E578063}.Release|Any CPU.Build.0 = netstandard-Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
- {747BE014-7C1D-4460-95AF-B41C35717165} = {D5A36F24-E27C-43DF-8658-10C5290423E0}
- {4EDBE9F5-D10A-4553-AE24-2E0E946B15B0} = {9D10D7AD-2F8C-4F7A-B0FA-E5EB3ECE287F}
- {CF73547B-07D2-4290-A14A-CA2A354F4D21} = {F47347C3-433C-4D3B-90F9-487FE7F4F444}
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {6618B298-BA53-4E58-9795-756C6DC1BA38}
+ {CF73547B-07D2-4290-A14A-CA2A354F4D21} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
+ {747BE014-7C1D-4460-95AF-B41C35717165} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD}
+ {203345A4-0E3B-43C1-ADEB-FF493E578063} = {2E666815-2EDB-464B-9DF6-380BF4789AD4}
EndGlobalSection
EndGlobal
diff --git a/src/System.Net.WebSockets.WebSocketProtocol/pkg/System.Net.WebSockets.WebSocketProtocol.pkgproj b/src/System.Net.WebSockets.WebSocketProtocol/pkg/System.Net.WebSockets.WebSocketProtocol.pkgproj
index 44ceae2df0..3a937242ec 100644
--- a/src/System.Net.WebSockets.WebSocketProtocol/pkg/System.Net.WebSockets.WebSocketProtocol.pkgproj
+++ b/src/System.Net.WebSockets.WebSocketProtocol/pkg/System.Net.WebSockets.WebSocketProtocol.pkgproj
@@ -3,7 +3,7 @@
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<ProjectReference Include="..\ref\System.Net.WebSockets.WebSocketProtocol.csproj">
- <SupportedFramework>net461;netcoreapp2.0;$(AllXamarinFrameworks)</SupportedFramework>
+ <SupportedFramework>uap10.0.16299;net461;netcoreapp2.0;$(AllXamarinFrameworks)</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\src\System.Net.WebSockets.WebSocketProtocol.csproj" />
</ItemGroup>
diff --git a/src/System.Net.WebSockets.WebSocketProtocol/ref/System.Net.WebSockets.WebSocketProtocol.csproj b/src/System.Net.WebSockets.WebSocketProtocol/ref/System.Net.WebSockets.WebSocketProtocol.csproj
index 702a9a5a3a..6db4fdf4dc 100644
--- a/src/System.Net.WebSockets.WebSocketProtocol/ref/System.Net.WebSockets.WebSocketProtocol.csproj
+++ b/src/System.Net.WebSockets.WebSocketProtocol/ref/System.Net.WebSockets.WebSocketProtocol.csproj
@@ -1,6 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <ProjectGuid>{203345A4-0E3B-43C1-ADEB-FF493E578063}</ProjectGuid>
+ </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
<ItemGroup>
@@ -10,4 +13,4 @@
<ProjectReference Include="..\..\System.Memory\ref\System.Memory.csproj" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project>
+</Project> \ No newline at end of file
diff --git a/src/System.Net.WebSockets.WebSocketProtocol/src/System.Net.WebSockets.WebSocketProtocol.csproj b/src/System.Net.WebSockets.WebSocketProtocol/src/System.Net.WebSockets.WebSocketProtocol.csproj
index ae63f2d5f0..a5321205dd 100644
--- a/src/System.Net.WebSockets.WebSocketProtocol/src/System.Net.WebSockets.WebSocketProtocol.csproj
+++ b/src/System.Net.WebSockets.WebSocketProtocol/src/System.Net.WebSockets.WebSocketProtocol.csproj
@@ -5,6 +5,7 @@
<AssemblyName>System.Net.WebSockets.WebSocketProtocol</AssemblyName>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<ProjectGuid>{747BE014-7C1D-4460-95AF-B41C35717165}</ProjectGuid>
+ <ILLinkClearInitLocals>true</ILLinkClearInitLocals>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
diff --git a/src/System.Net.WebSockets.WebSocketProtocol/src/System/Net/WebSockets/ManagedWebSocketExtensions.cs b/src/System.Net.WebSockets.WebSocketProtocol/src/System/Net/WebSockets/ManagedWebSocketExtensions.cs
index 3f2143990e..52b9e2fdc1 100644
--- a/src/System.Net.WebSockets.WebSocketProtocol/src/System/Net/WebSockets/ManagedWebSocketExtensions.cs
+++ b/src/System.Net.WebSockets.WebSocketProtocol/src/System/Net/WebSockets/ManagedWebSocketExtensions.cs
@@ -23,16 +23,16 @@ namespace System.Net.WebSockets
}
}
- internal static Task<int> ReadAsync(this Stream stream, Memory<byte> destination, CancellationToken cancellationToken)
+ internal static ValueTask<int> ReadAsync(this Stream stream, Memory<byte> destination, CancellationToken cancellationToken = default)
{
- if (destination.TryGetArray(out ArraySegment<byte> array))
+ if (MemoryMarshal.TryGetArray(destination, out ArraySegment<byte> array))
{
- return stream.ReadAsync(array.Array, array.Offset, array.Count, cancellationToken);
+ return new ValueTask<int>(stream.ReadAsync(array.Array, array.Offset, array.Count, cancellationToken));
}
else
{
byte[] buffer = ArrayPool<byte>.Shared.Rent(destination.Length);
- return FinishReadAsync(stream.ReadAsync(buffer, 0, destination.Length, cancellationToken), buffer, destination);
+ return new ValueTask<int>(FinishReadAsync(stream.ReadAsync(buffer, 0, destination.Length, cancellationToken), buffer, destination));
async Task<int> FinishReadAsync(Task<int> readTask, byte[] localBuffer, Memory<byte> localDestination)
{
@@ -49,6 +49,32 @@ namespace System.Net.WebSockets
}
}
}
+
+ internal static ValueTask WriteAsync(this Stream stream, ReadOnlyMemory<byte> source, CancellationToken cancellationToken = default)
+ {
+ if (MemoryMarshal.TryGetArray(source, out ArraySegment<byte> array))
+ {
+ return new ValueTask(stream.WriteAsync(array.Array, array.Offset, array.Count, cancellationToken));
+ }
+ else
+ {
+ byte[] buffer = ArrayPool<byte>.Shared.Rent(source.Length);
+ source.Span.CopyTo(buffer);
+ return new ValueTask(FinishWriteAsync(stream.WriteAsync(buffer, 0, source.Length, cancellationToken), buffer));
+
+ async Task FinishWriteAsync(Task writeTask, byte[] localBuffer)
+ {
+ try
+ {
+ await writeTask.ConfigureAwait(false);
+ }
+ finally
+ {
+ ArrayPool<byte>.Shared.Return(localBuffer);
+ }
+ }
+ }
+ }
}
internal static class BitConverter
diff --git a/src/System.Net.WebSockets.WebSocketProtocol/tests/System.Net.WebSockets.WebSocketProtocol.Tests.csproj b/src/System.Net.WebSockets.WebSocketProtocol/tests/System.Net.WebSockets.WebSocketProtocol.Tests.csproj
index f0ac7ecbac..8460f376bc 100644
--- a/src/System.Net.WebSockets.WebSocketProtocol/tests/System.Net.WebSockets.WebSocketProtocol.Tests.csproj
+++ b/src/System.Net.WebSockets.WebSocketProtocol/tests/System.Net.WebSockets.WebSocketProtocol.Tests.csproj
@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
<PropertyGroup>
@@ -19,4 +21,4 @@
<Compile Include="WebSocketProtocolTests.cs" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project>
+</Project> \ No newline at end of file
diff --git a/src/System.Net.WebSockets.WebSocketProtocol/tests/WebSocketProtocolTests.cs b/src/System.Net.WebSockets.WebSocketProtocol/tests/WebSocketProtocolTests.cs
index 2b5964ed66..9db60cd882 100644
--- a/src/System.Net.WebSockets.WebSocketProtocol/tests/WebSocketProtocolTests.cs
+++ b/src/System.Net.WebSockets.WebSocketProtocol/tests/WebSocketProtocolTests.cs
@@ -7,6 +7,7 @@ using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
+using System.Net.Security;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
@@ -55,19 +56,41 @@ namespace System.Net.WebSockets.Tests
[MemberData(nameof(EchoServers))]
public async Task WebSocketProtocol_CreateFromConnectedStream_Succeeds(Uri echoUri)
{
- Uri uri = new UriBuilder(echoUri) { Scheme = (echoUri.Scheme == "ws") ? "http" : "https" }.Uri;
- HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, uri);
- KeyValuePair<string, string> secKeyAndSecWebSocketAccept = CreateSecKeyAndSecWebSocketAccept();
- AddWebSocketHeaders(request, secKeyAndSecWebSocketAccept.Key);
- DirectManagedHttpClientHandler handler = DirectManagedHttpClientHandler.CreateHandler();
- using (HttpResponseMessage response = await handler.SendAsync(request, CancellationToken.None).ConfigureAwait(false))
+ using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
- Assert.Equal(HttpStatusCode.SwitchingProtocols, response.StatusCode);
- using (Stream connectedStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
+ bool secure = echoUri.Scheme == "wss";
+ client.Connect(echoUri.Host, secure ? 443 : 80);
+
+ Stream stream = new NetworkStream(client, ownsSocket: false);
+ if (secure)
{
- Assert.True(connectedStream.CanRead);
- Assert.True(connectedStream.CanWrite);
- using (WebSocket socket = WebSocketProtocol.CreateFromStream(connectedStream, false, null, TimeSpan.FromSeconds(10)))
+ SslStream ssl = new SslStream(stream, leaveInnerStreamOpen: true, delegate { return true; });
+ await ssl.AuthenticateAsClientAsync(echoUri.Host);
+ stream = ssl;
+ }
+
+ using (stream)
+ {
+ using (var writer = new StreamWriter(stream, Encoding.ASCII, bufferSize: 1, leaveOpen: true))
+ {
+ await writer.WriteAsync($"GET {echoUri.PathAndQuery} HTTP/1.1\r\n");
+ await writer.WriteAsync($"Host: {echoUri.Host}\r\n");
+ await writer.WriteAsync($"Upgrade: websocket\r\n");
+ await writer.WriteAsync($"Connection: Upgrade\r\n");
+ await writer.WriteAsync($"Sec-WebSocket-Version: 13\r\n");
+ await writer.WriteAsync($"Sec-WebSocket-Key: {Convert.ToBase64String(Guid.NewGuid().ToByteArray())}\r\n");
+ await writer.WriteAsync($"\r\n");
+ }
+
+ using (var reader = new StreamReader(stream, Encoding.ASCII, detectEncodingFromByteOrderMarks: false, bufferSize: 1, leaveOpen: true))
+ {
+ string statusLine = await reader.ReadLineAsync();
+ Assert.NotEmpty(statusLine);
+ Assert.Equal("HTTP/1.1 101 Switching Protocols", statusLine);
+ while (!string.IsNullOrEmpty(await reader.ReadLineAsync()));
+ }
+
+ using (WebSocket socket = WebSocketProtocol.CreateFromStream(stream, false, null, TimeSpan.FromSeconds(10)))
{
Assert.NotNull(socket);
Assert.Equal(WebSocketState.Open, socket.State);
@@ -87,28 +110,6 @@ namespace System.Net.WebSockets.Tests
public static readonly object[][] EchoServers = System.Net.Test.Common.Configuration.WebSockets.EchoServers;
- /// <summary>GUID appended by the server as part of the security key response. Defined in the RFC.</summary>
- private const string WSServerGuid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
-
- private static KeyValuePair<string, string> CreateSecKeyAndSecWebSocketAccept()
- {
- string secKey = Convert.ToBase64String(Guid.NewGuid().ToByteArray());
- using (SHA1 sha = SHA1.Create())
- {
- return new KeyValuePair<string, string>(
- secKey,
- Convert.ToBase64String(sha.ComputeHash(Encoding.ASCII.GetBytes(secKey + WSServerGuid))));
- }
- }
-
- private static void AddWebSocketHeaders(HttpRequestMessage request, string secKey)
- {
- request.Headers.TryAddWithoutValidation(HttpKnownHeaderNames.Connection, HttpKnownHeaderNames.Upgrade);
- request.Headers.TryAddWithoutValidation(HttpKnownHeaderNames.Upgrade, "websocket");
- request.Headers.TryAddWithoutValidation(HttpKnownHeaderNames.SecWebSocketVersion, "13");
- request.Headers.TryAddWithoutValidation(HttpKnownHeaderNames.SecWebSocketKey, secKey);
- }
-
private sealed class UnreadableStream : Stream
{
public override bool CanRead => false;
@@ -122,44 +123,5 @@ namespace System.Net.WebSockets.Tests
public override void SetLength(long value) => throw new NotImplementedException();
public override void Write(byte[] buffer, int offset, int count) => throw new NotImplementedException();
}
-
- private sealed class DirectManagedHttpClientHandler : HttpClientHandler
- {
- private const string ManagedHandlerEnvVar = "COMPlus_UseManagedHttpClientHandler";
- private static readonly LocalDataStoreSlot s_managedHandlerSlot = GetSlot();
- private static readonly object s_true = true;
-
- private static LocalDataStoreSlot GetSlot()
- {
- LocalDataStoreSlot slot = Thread.GetNamedDataSlot(ManagedHandlerEnvVar);
- if (slot != null)
- {
- return slot;
- }
-
- try
- {
- return Thread.AllocateNamedDataSlot(ManagedHandlerEnvVar);
- }
- catch (ArgumentException) // in case of a race condition where multiple threads all try to allocate the slot concurrently
- {
- return Thread.GetNamedDataSlot(ManagedHandlerEnvVar);
- }
- }
-
- public static DirectManagedHttpClientHandler CreateHandler()
- {
- Thread.SetData(s_managedHandlerSlot, s_true);
- try
- {
- return new DirectManagedHttpClientHandler();
- }
- finally { Thread.SetData(s_managedHandlerSlot, null); }
- }
-
- public new Task<HttpResponseMessage> SendAsync(
- HttpRequestMessage request, CancellationToken cancellationToken) =>
- base.SendAsync(request, cancellationToken);
- }
}
}
diff --git a/src/System.Net.WebSockets/ref/System.Net.WebSockets.cs b/src/System.Net.WebSockets/ref/System.Net.WebSockets.cs
index 924dc869fe..126887bc2e 100644
--- a/src/System.Net.WebSockets/ref/System.Net.WebSockets.cs
+++ b/src/System.Net.WebSockets/ref/System.Net.WebSockets.cs
@@ -41,7 +41,7 @@ namespace System.Net.WebSockets
[System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
public static void RegisterPrefixes() { }
public abstract System.Threading.Tasks.Task SendAsync(System.ArraySegment<byte> buffer, System.Net.WebSockets.WebSocketMessageType messageType, bool endOfMessage, System.Threading.CancellationToken cancellationToken);
- public virtual System.Threading.Tasks.Task SendAsync(System.ReadOnlyMemory<byte> buffer, System.Net.WebSockets.WebSocketMessageType messageType, bool endOfMessage, System.Threading.CancellationToken cancellationToken) { throw null; }
+ public virtual System.Threading.Tasks.ValueTask SendAsync(System.ReadOnlyMemory<byte> buffer, System.Net.WebSockets.WebSocketMessageType messageType, bool endOfMessage, System.Threading.CancellationToken cancellationToken) { throw null; }
protected static void ThrowOnInvalidState(System.Net.WebSockets.WebSocketState state, params System.Net.WebSockets.WebSocketState[] validStates) { }
}
public enum WebSocketCloseStatus
diff --git a/src/System.Net.WebSockets/src/System.Net.WebSockets.csproj b/src/System.Net.WebSockets/src/System.Net.WebSockets.csproj
index 882d8eed46..8f7a330915 100644
--- a/src/System.Net.WebSockets/src/System.Net.WebSockets.csproj
+++ b/src/System.Net.WebSockets/src/System.Net.WebSockets.csproj
@@ -5,6 +5,7 @@
<ProjectGuid>{B0C83201-EC32-4E8D-9DE4-EEF41E052DA1}</ProjectGuid>
<AssemblyName>System.Net.WebSockets</AssemblyName>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
+ <ILLinkClearInitLocals>true</ILLinkClearInitLocals>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
diff --git a/src/System.Net.WebSockets/src/System/Net/WebSockets/ManagedWebSocket.netcoreapp.cs b/src/System.Net.WebSockets/src/System/Net/WebSockets/ManagedWebSocket.netcoreapp.cs
index 23e5f6949c..f61f3177dd 100644
--- a/src/System.Net.WebSockets/src/System/Net/WebSockets/ManagedWebSocket.netcoreapp.cs
+++ b/src/System.Net.WebSockets/src/System/Net/WebSockets/ManagedWebSocket.netcoreapp.cs
@@ -10,7 +10,7 @@ namespace System.Net.WebSockets
{
internal sealed partial class ManagedWebSocket : WebSocket
{
- public override Task SendAsync(ReadOnlyMemory<byte> buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken)
+ public override ValueTask SendAsync(ReadOnlyMemory<byte> buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken)
{
return SendPrivateAsync(buffer, messageType, endOfMessage, cancellationToken);
}
@@ -24,8 +24,11 @@ namespace System.Net.WebSockets
Debug.Assert(!Monitor.IsEntered(StateUpdateLock), $"{nameof(StateUpdateLock)} must never be held when acquiring {nameof(ReceiveAsyncLock)}");
lock (ReceiveAsyncLock) // synchronize with receives in CloseAsync
{
- ThrowIfOperationInProgress(_lastReceiveAsync);
+ ThrowIfOperationInProgress(_lastReceiveAsync.IsCompleted);
ValueTask<ValueWebSocketReceiveResult> t = ReceiveAsyncPrivate<ValueWebSocketReceiveResultGetter, ValueWebSocketReceiveResult>(buffer, cancellationToken);
+
+ // WARNING: This code is only valid because ReceiveAsyncPrivate returns a ValueTask that wraps a T or a Task.
+ // If that ever changes where ReceiveAsyncPrivate could wrap an IValueTaskSource, this must also change.
_lastReceiveAsync =
t.IsCompletedSuccessfully ? (t.Result.MessageType == WebSocketMessageType.Close ? s_cachedCloseTask : Task.CompletedTask) :
t.AsTask();
diff --git a/src/System.Net.WebSockets/src/System/Net/WebSockets/WebSocket.cs b/src/System.Net.WebSockets/src/System/Net/WebSockets/WebSocket.cs
index 8013388494..64a8192275 100644
--- a/src/System.Net.WebSockets/src/System/Net/WebSockets/WebSocket.cs
+++ b/src/System.Net.WebSockets/src/System/Net/WebSockets/WebSocket.cs
@@ -35,7 +35,7 @@ namespace System.Net.WebSockets
public virtual async ValueTask<ValueWebSocketReceiveResult> ReceiveAsync(Memory<byte> buffer, CancellationToken cancellationToken)
{
- if (buffer.TryGetArray(out ArraySegment<byte> arraySegment))
+ if (MemoryMarshal.TryGetArray(buffer, out ArraySegment<byte> arraySegment))
{
WebSocketReceiveResult r = await ReceiveAsync(arraySegment, cancellationToken).ConfigureAwait(false);
return new ValueWebSocketReceiveResult(r.Count, r.MessageType, r.EndOfMessage);
@@ -56,10 +56,10 @@ namespace System.Net.WebSockets
}
}
- public virtual Task SendAsync(ReadOnlyMemory<byte> buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken) =>
- MemoryMarshal.TryGetArray(buffer, out ArraySegment<byte> arraySegment) ?
+ public virtual ValueTask SendAsync(ReadOnlyMemory<byte> buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken) =>
+ new ValueTask(MemoryMarshal.TryGetArray(buffer, out ArraySegment<byte> arraySegment) ?
SendAsync(arraySegment, messageType, endOfMessage, cancellationToken) :
- SendWithArrayPoolAsync(buffer, messageType, endOfMessage, cancellationToken);
+ SendWithArrayPoolAsync(buffer, messageType, endOfMessage, cancellationToken));
private async Task SendWithArrayPoolAsync(
ReadOnlyMemory<byte> buffer,
diff --git a/src/System.Numerics.Vectors/System.Numerics.Vectors.sln b/src/System.Numerics.Vectors/System.Numerics.Vectors.sln
index e07ec13da9..1880dbdf04 100644
--- a/src/System.Numerics.Vectors/System.Numerics.Vectors.sln
+++ b/src/System.Numerics.Vectors/System.Numerics.Vectors.sln
@@ -39,10 +39,10 @@ Global
{D9906F1A-A41A-43CD-81D2-BA94CF0001C9}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
{D9906F1A-A41A-43CD-81D2-BA94CF0001C9}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
{D9906F1A-A41A-43CD-81D2-BA94CF0001C9}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
- {53134B0C-0D57-481B-B84E-D1991E8D54FF}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
- {53134B0C-0D57-481B-B84E-D1991E8D54FF}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
- {53134B0C-0D57-481B-B84E-D1991E8D54FF}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
- {53134B0C-0D57-481B-B84E-D1991E8D54FF}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
+ {53134B0C-0D57-481B-B84E-D1991E8D54FF}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU
+ {53134B0C-0D57-481B-B84E-D1991E8D54FF}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
+ {53134B0C-0D57-481B-B84E-D1991E8D54FF}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
+ {53134B0C-0D57-481B-B84E-D1991E8D54FF}.Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU
{650277B5-9423-4ACE-BB54-2659995B21C7}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
{650277B5-9423-4ACE-BB54-2659995B21C7}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
{650277B5-9423-4ACE-BB54-2659995B21C7}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
diff --git a/src/System.Numerics.Vectors/pkg/System.Numerics.Vectors.pkgproj b/src/System.Numerics.Vectors/pkg/System.Numerics.Vectors.pkgproj
index fb09f270ed..1d607dbf60 100644
--- a/src/System.Numerics.Vectors/pkg/System.Numerics.Vectors.pkgproj
+++ b/src/System.Numerics.Vectors/pkg/System.Numerics.Vectors.pkgproj
@@ -21,15 +21,8 @@
<InboxOnTargetFramework Include="xamarinmac20" />
<InboxOnTargetFramework Include="xamarintvos10" />
<InboxOnTargetFramework Include="xamarinwatchos10" />
-
- <!-- Since UAP and .NETCoreApp are package based we still want to enable
- OOBing libraries that happen to overlap with their framework package.
- This avoids us having to lock the API in our NuGet packages just
- to match what shipped inbox: since we can provide a new library
- we can update it to add API without raising the netstandard version. -->
- <ValidatePackageSuppression Include="TreatAsOutOfBox">
- <Value>.NETCoreApp;UAP</Value>
- </ValidatePackageSuppression>
+ <InboxOnTargetFramework Include="netcoreapp2.1" />
+ <InboxOnTargetFramework Include="uap10.0.16299" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs b/src/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs
index 486ad29db9..9936f66954 100644
--- a/src/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs
+++ b/src/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs
@@ -301,6 +301,9 @@ namespace System.Numerics
public Vector(T value) { throw null; }
public Vector(T[] values) { throw null; }
public Vector(T[] values, int index) { throw null; }
+#if netcoreapp
+ public Vector(Span<T> values) { throw null; }
+#endif
public static int Count { get { throw null; } }
public T this[int index] { get { throw null; } }
public static System.Numerics.Vector<T> One { get { throw null; } }
diff --git a/src/System.Numerics.Vectors/ref/System.Numerics.Vectors.csproj b/src/System.Numerics.Vectors/ref/System.Numerics.Vectors.csproj
index e613f45d1c..ed07ba967e 100644
--- a/src/System.Numerics.Vectors/ref/System.Numerics.Vectors.csproj
+++ b/src/System.Numerics.Vectors/ref/System.Numerics.Vectors.csproj
@@ -3,7 +3,10 @@
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
<ProjectGuid>{650277B5-9423-4ACE-BB54-2659995B21C7}</ProjectGuid>
- <IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'netfx' OR '$(TargetGroup)' == 'net46'">true</IsPartialFacadeAssembly>
+ <IsTargetingNetFx Condition="'$(TargetGroup)'=='netfx' OR '$(TargetGroup)'=='net46'">true</IsTargetingNetFx>
+ <IsTargetingNetCoreApp Condition="'$(TargetGroup)'=='netcoreapp' OR '$(TargetGroup)'=='uap'">true</IsTargetingNetCoreApp>
+ <IsPartialFacadeAssembly Condition="'$(IsTargetingNetFx)'=='true'">true</IsPartialFacadeAssembly>
+ <DefineConstants Condition="'$(IsTargetingNetCoreApp)'=='true'">$(DefineConstants);netcoreapp</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'net46-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'net46-Release|AnyCPU'" />
@@ -20,14 +23,14 @@
<ItemGroup>
<Compile Include="System.Numerics.Vectors.cs" />
</ItemGroup>
- <ItemGroup Condition="'$(TargetGroup)' == 'netfx' OR '$(TargetGroup)' == 'net46'">
+ <ItemGroup Condition="'$(IsTargetingNetFx)'=='true'">
<Reference Include="mscorlib" />
<Reference Include="System.Numerics" />
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' == 'netstandard1.0'">
<Reference Include="System.Runtime" />
</ItemGroup>
- <ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp' OR '$(TargetGroup)' == 'uap'">
+ <ItemGroup Condition="'$(IsTargetingNetCoreApp)'=='true'">
<ProjectReference Include="..\..\System.Runtime\ref\System.Runtime.csproj" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
diff --git a/src/System.Numerics.Vectors/src/ApiCompatBaseline.uapaot.txt b/src/System.Numerics.Vectors/src/ApiCompatBaseline.uapaot.txt
new file mode 100644
index 0000000000..bc7a12f526
--- /dev/null
+++ b/src/System.Numerics.Vectors/src/ApiCompatBaseline.uapaot.txt
@@ -0,0 +1 @@
+MembersMustExist : Member 'System.Numerics.Vector<T>..ctor(System.Span<T>)' does not exist in the implementation but it does exist in the contract. \ No newline at end of file
diff --git a/src/System.Numerics.Vectors/src/Configurations.props b/src/System.Numerics.Vectors/src/Configurations.props
index 29a728f3e8..3e3accde0d 100644
--- a/src/System.Numerics.Vectors/src/Configurations.props
+++ b/src/System.Numerics.Vectors/src/Configurations.props
@@ -7,10 +7,12 @@
net46;
</PackageConfigurations>
<BuildConfigurations>
+ uapaot-Windows_NT;
uap-Windows_NT;
netfx-Windows_NT;
- netcoreapp;
+ netcoreapp-Windows_NT;
+ netcoreapp-Unix;
$(PackageConfigurations)
</BuildConfigurations>
</PropertyGroup>
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Numerics.Vectors/src/Resources/Strings.resx b/src/System.Numerics.Vectors/src/Resources/Strings.resx
index fc8ea5b29b..688f37d005 100644
--- a/src/System.Numerics.Vectors/src/Resources/Strings.resx
+++ b/src/System.Numerics.Vectors/src/Resources/Strings.resx
@@ -70,4 +70,7 @@
<data name="Arg_TypeNotSupported" xml:space="preserve">
<value>Specified type is not supported</value>
</data>
+ <data name="Arg_InsufficientNumberOfElements" xml:space="preserve">
+ <value>At least {0} element(s) are expected in the parameter "{1}".</value>
+ </data>
</root> \ No newline at end of file
diff --git a/src/System.Numerics.Vectors/src/System.Numerics.Vectors.csproj b/src/System.Numerics.Vectors/src/System.Numerics.Vectors.csproj
index d3f22a00a7..47a3bf9c34 100644
--- a/src/System.Numerics.Vectors/src/System.Numerics.Vectors.csproj
+++ b/src/System.Numerics.Vectors/src/System.Numerics.Vectors.csproj
@@ -6,13 +6,17 @@
<RootNamespace>System.Numerics</RootNamespace>
<DocumentationFile>$(OutputPath)$(MSBuildProjectName).xml</DocumentationFile>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
- <IsPartialFacadeAssembly Condition="'$(TargetGroup)'=='netfx' OR '$(TargetGroup)'=='net46'">true</IsPartialFacadeAssembly>
+ <IsTargetingNetFx Condition="'$(TargetGroup)'=='netfx' OR '$(TargetGroup)'=='net46'">true</IsTargetingNetFx>
+ <IsTargetingNetCoreApp Condition="'$(TargetGroup)'=='netcoreapp' OR '$(TargetGroup)'=='uap' OR '$(TargetGroup)'=='uapaot'">true</IsTargetingNetCoreApp>
+ <IsPartialFacadeAssembly Condition="'$(IsTargetingNetFx)'=='true' OR '$(IsTargetingNetCoreApp)'=='true'">true</IsPartialFacadeAssembly>
<PackageTargetFramework Condition="'$(TargetGroup)' == 'netstandard1.0'">netstandard1.0;portable-net45+win8+wp8+wpa81</PackageTargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'net46-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'net46-Release|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
@@ -21,37 +25,49 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.0-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uapaot-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uapaot-Windows_NT-Release|AnyCPU'" />
<!-- Shared -->
<ItemGroup>
- <Compile Include="..\..\Common\src\System\Numerics\Hashing\HashHelpers.cs">
+ <Compile Include="$(CommonPath)\System\Numerics\Hashing\HashHelpers.cs">
<Link>Common\System\Numerics\Hashing\HashHelpers.cs</Link>
</Compile>
- <Compile Include="System\Numerics\ConstantHelper.cs">
+ <Compile Include="$(CommonPath)\CoreLib\System\Runtime\CompilerServices\IntrinsicAttribute.cs">
+ <Link>System\Runtime\CompilerServices\IntrinsicAttribute.cs</Link>
+ </Compile>
+ </ItemGroup>
+ <!-- On .NET Core, Vector<T> is in System.Private.CoreLib -->
+ <ItemGroup Condition="'$(IsTargetingNetCoreApp)' != 'true'">
+ <Compile Include="$(CommonPath)\CoreLib\System\Numerics\ConstantHelper.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>ConstantHelper.tt</DependentUpon>
+ <Link>System\Numerics\ConstantHelper.cs</Link>
</Compile>
- <Compile Include="System\Numerics\JitIntrinsicAttribute.cs" />
- <Compile Include="System\Numerics\Register.cs">
+ <Compile Include="$(CommonPath)\CoreLib\System\Numerics\Register.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Register.tt</DependentUpon>
+ <Link>System\Numerics\Register.cs</Link>
</Compile>
- <Compile Include="System\Numerics\Vector.cs">
+ <Compile Include="$(CommonPath)\CoreLib\System\Numerics\Vector.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Vector.tt</DependentUpon>
+ <Link>System\Numerics\Vector.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\CoreLib\System\Numerics\Vector_Operations.cs">
+ <Link>System\Numerics\Vector_Operations.cs</Link>
</Compile>
- <Compile Include="System\Numerics\Vector_Operations.cs" />
</ItemGroup>
<!-- Carry a copy of MathF where not available -->
- <ItemGroup Condition="'$(IsPartialFacadeAssembly)' == 'true' OR $(TargetGroup.StartsWith('netstandard'))">
- <Compile Include="..\..\Common\src\System\MathF.netstandard.cs">
+ <ItemGroup Condition="'$(IsTargetingNetFx)' == 'true' OR $(TargetGroup.StartsWith('netstandard'))">
+ <Compile Include="$(CommonPath)\System\MathF.netstandard.cs">
<Link>System\MathF.netstandard.cs</Link>
</Compile>
</ItemGroup>
<!-- Portable version only -->
- <ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true'">
+ <ItemGroup Condition="'$(IsTargetingNetFx)' != 'true'">
<Compile Include="System\Numerics\Matrix3x2.cs" />
<Compile Include="System\Numerics\Matrix4x4.cs" />
<Compile Include="System\Numerics\Plane.cs" />
@@ -63,24 +79,34 @@
<Compile Include="System\Numerics\Vector4.cs" />
<Compile Include="System\Numerics\Vector4_Intrinsics.cs" />
</ItemGroup>
- <ItemGroup Condition="'$(IsPartialFacadeAssembly)' == 'true'">
+ <ItemGroup Condition="'$(IsTargetingNetFx)' == 'true'">
<Reference Include="mscorlib" />
<Reference Include="System.Numerics" />
</ItemGroup>
<ItemGroup>
- <None Include="System\Numerics\GenerationConfig.ttinclude" />
- <Content Include="System\Numerics\ConstantHelper.tt">
+ <None Include="$(CommonPath)\CoreLib\System\Numerics\GenerationConfig.ttinclude">
+ <Link>System\Numerics\GenerationConfig.ttinclude</Link>
+ </None>
+ <Content Include="$(CommonPath)\CoreLib\System\Numerics\ConstantHelper.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>ConstantHelper.cs</LastGenOutput>
+ <Link>System\Numerics\ConstantHelper.tt</Link>
</Content>
- <Content Include="System\Numerics\Register.tt">
+ <Content Include="$(CommonPath)\CoreLib\System\Numerics\Register.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Register.cs</LastGenOutput>
+ <Link>System\Numerics\Register.tt</Link>
</Content>
- <Content Include="System\Numerics\Vector.tt">
+ <Content Include="$(CommonPath)\CoreLib\System\Numerics\Vector.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Vector.cs</LastGenOutput>
+ <Link>System\Numerics\Vector.tt</Link>
</Content>
+ </ItemGroup>
+ <ItemGroup Condition="'$(IsTargetingNetCoreApp)' == 'true'">
+ <ReferenceFromRuntime Include="System.Private.CoreLib" />
+ </ItemGroup>
+ <ItemGroup Condition="'$(IsTargetingNetCoreApp)' != 'true'">
<Reference Include="System.Diagnostics.Tools" />
<Reference Include="System.Globalization" />
<Reference Include="System.Resources.ResourceManager" />
diff --git a/src/System.Numerics.Vectors/src/System/Numerics/JitIntrinsicAttribute.cs b/src/System.Numerics.Vectors/src/System/Numerics/JitIntrinsicAttribute.cs
deleted file mode 100644
index 741041222f..0000000000
--- a/src/System.Numerics.Vectors/src/System/Numerics/JitIntrinsicAttribute.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-namespace System.Numerics
-{
- /// <summary>
- /// An attribute that can be attached to JIT Intrinsic methods/properties
- /// </summary>
- [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Property)]
- internal class JitIntrinsicAttribute : Attribute
- {
- }
-}
diff --git a/src/System.Numerics.Vectors/src/System/Numerics/Vector2_Intrinsics.cs b/src/System.Numerics.Vectors/src/System/Numerics/Vector2_Intrinsics.cs
index 8578ac877f..59db2b078d 100644
--- a/src/System.Numerics.Vectors/src/System/Numerics/Vector2_Intrinsics.cs
+++ b/src/System.Numerics.Vectors/src/System/Numerics/Vector2_Intrinsics.cs
@@ -27,7 +27,7 @@ namespace System.Numerics
/// Constructs a vector whose elements are all the single specified value.
/// </summary>
/// <param name="value">The element to fill the vector with.</param>
- [JitIntrinsic]
+ [Intrinsic]
public Vector2(Single value) : this(value, value) { }
/// <summary>
@@ -35,7 +35,7 @@ namespace System.Numerics
/// </summary>
/// <param name="x">The X component.</param>
/// <param name="y">The Y component.</param>
- [JitIntrinsic]
+ [Intrinsic]
public Vector2(Single x, Single y)
{
X = x;
@@ -86,7 +86,7 @@ namespace System.Numerics
/// </summary>
/// <param name="other">The Vector2 to compare this instance to.</param>
/// <returns>True if the other Vector2 is equal to this instance; False otherwise.</returns>
- [JitIntrinsic]
+ [Intrinsic]
public bool Equals(Vector2 other)
{
return this.X == other.X && this.Y == other.Y;
@@ -100,7 +100,7 @@ namespace System.Numerics
/// <param name="value1">The first vector.</param>
/// <param name="value2">The second vector.</param>
/// <returns>The dot product.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Dot(Vector2 value1, Vector2 value2)
{
@@ -114,7 +114,7 @@ namespace System.Numerics
/// <param name="value1">The first source vector.</param>
/// <param name="value2">The second source vector.</param>
/// <returns>The minimized vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Min(Vector2 value1, Vector2 value2)
{
@@ -129,7 +129,7 @@ namespace System.Numerics
/// <param name="value1">The first source vector</param>
/// <param name="value2">The second source vector</param>
/// <returns>The maximized vector</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Max(Vector2 value1, Vector2 value2)
{
@@ -143,7 +143,7 @@ namespace System.Numerics
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The absolute value vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Abs(Vector2 value)
{
@@ -155,7 +155,7 @@ namespace System.Numerics
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The square root vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 SquareRoot(Vector2 value)
{
@@ -170,7 +170,7 @@ namespace System.Numerics
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The summed vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator +(Vector2 left, Vector2 right)
{
@@ -183,7 +183,7 @@ namespace System.Numerics
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The difference vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator -(Vector2 left, Vector2 right)
{
@@ -196,7 +196,7 @@ namespace System.Numerics
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The product vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator *(Vector2 left, Vector2 right)
{
@@ -209,7 +209,7 @@ namespace System.Numerics
/// <param name="left">The scalar value.</param>
/// <param name="right">The source vector.</param>
/// <returns>The scaled vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator *(Single left, Vector2 right)
{
@@ -222,7 +222,7 @@ namespace System.Numerics
/// <param name="left">The source vector.</param>
/// <param name="right">The scalar value.</param>
/// <returns>The scaled vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator *(Vector2 left, Single right)
{
@@ -235,7 +235,7 @@ namespace System.Numerics
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The vector resulting from the division.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator /(Vector2 left, Vector2 right)
{
@@ -248,14 +248,10 @@ namespace System.Numerics
/// <param name="value1">The source vector.</param>
/// <param name="value2">The scalar value.</param>
/// <returns>The result of the division.</returns>
- [JitIntrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 operator /(Vector2 value1, float value2)
{
- float invDiv = 1.0f / value2;
- return new Vector2(
- value1.X * invDiv,
- value1.Y * invDiv);
+ return value1 / new Vector2(value2);
}
/// <summary>
diff --git a/src/System.Numerics.Vectors/src/System/Numerics/Vector3_Intrinsics.cs b/src/System.Numerics.Vectors/src/System/Numerics/Vector3_Intrinsics.cs
index baefa0e3ec..b8c034ac93 100644
--- a/src/System.Numerics.Vectors/src/System/Numerics/Vector3_Intrinsics.cs
+++ b/src/System.Numerics.Vectors/src/System/Numerics/Vector3_Intrinsics.cs
@@ -32,7 +32,7 @@ namespace System.Numerics
/// Constructs a vector whose elements are all the single specified value.
/// </summary>
/// <param name="value">The element to fill the vector with.</param>
- [JitIntrinsic]
+ [Intrinsic]
public Vector3(Single value) : this(value, value, value) { }
/// <summary>
@@ -48,7 +48,7 @@ namespace System.Numerics
/// <param name="x">The X component.</param>
/// <param name="y">The Y component.</param>
/// <param name="z">The Z component.</param>
- [JitIntrinsic]
+ [Intrinsic]
public Vector3(Single x, Single y, Single z)
{
X = x;
@@ -74,7 +74,7 @@ namespace System.Numerics
/// <exception cref="RankException">If array is multidimensional.</exception>
/// <exception cref="ArgumentOutOfRangeException">If index is greater than end of the array or index is less than zero.</exception>
/// <exception cref="ArgumentException">If number of elements in source vector is greater than those available in destination array.</exception>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyTo(Single[] array, int index)
{
@@ -101,7 +101,7 @@ namespace System.Numerics
/// </summary>
/// <param name="other">The Vector3 to compare this instance to.</param>
/// <returns>True if the other Vector3 is equal to this instance; False otherwise.</returns>
- [JitIntrinsic]
+ [Intrinsic]
public bool Equals(Vector3 other)
{
return X == other.X &&
@@ -117,7 +117,7 @@ namespace System.Numerics
/// <param name="vector1">The first vector.</param>
/// <param name="vector2">The second vector.</param>
/// <returns>The dot product.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Dot(Vector3 vector1, Vector3 vector2)
{
@@ -132,7 +132,7 @@ namespace System.Numerics
/// <param name="value1">The first source vector.</param>
/// <param name="value2">The second source vector.</param>
/// <returns>The minimized vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
public static Vector3 Min(Vector3 value1, Vector3 value2)
{
return new Vector3(
@@ -147,7 +147,7 @@ namespace System.Numerics
/// <param name="value1">The first source vector.</param>
/// <param name="value2">The second source vector.</param>
/// <returns>The maximized vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Max(Vector3 value1, Vector3 value2)
{
@@ -162,7 +162,7 @@ namespace System.Numerics
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The absolute value vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Abs(Vector3 value)
{
@@ -174,7 +174,7 @@ namespace System.Numerics
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The square root vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 SquareRoot(Vector3 value)
{
@@ -189,7 +189,7 @@ namespace System.Numerics
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The summed vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator +(Vector3 left, Vector3 right)
{
@@ -202,7 +202,7 @@ namespace System.Numerics
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The difference vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator -(Vector3 left, Vector3 right)
{
@@ -215,7 +215,7 @@ namespace System.Numerics
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The product vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator *(Vector3 left, Vector3 right)
{
@@ -228,7 +228,7 @@ namespace System.Numerics
/// <param name="left">The source vector.</param>
/// <param name="right">The scalar value.</param>
/// <returns>The scaled vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator *(Vector3 left, Single right)
{
@@ -241,7 +241,7 @@ namespace System.Numerics
/// <param name="left">The scalar value.</param>
/// <param name="right">The source vector.</param>
/// <returns>The scaled vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator *(Single left, Vector3 right)
{
@@ -254,7 +254,7 @@ namespace System.Numerics
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The vector resulting from the division.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator /(Vector3 left, Vector3 right)
{
@@ -267,16 +267,10 @@ namespace System.Numerics
/// <param name="value1">The source vector.</param>
/// <param name="value2">The scalar value.</param>
/// <returns>The result of the division.</returns>
- [JitIntrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 operator /(Vector3 value1, float value2)
{
- float invDiv = 1.0f / value2;
-
- return new Vector3(
- value1.X * invDiv,
- value1.Y * invDiv,
- value1.Z * invDiv);
+ return value1 / new Vector3(value2);
}
/// <summary>
@@ -296,7 +290,7 @@ namespace System.Numerics
/// <param name="left">The first vector to compare.</param>
/// <param name="right">The second vector to compare.</param>
/// <returns>True if the vectors are equal; False otherwise.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Vector3 left, Vector3 right)
{
diff --git a/src/System.Numerics.Vectors/src/System/Numerics/Vector4_Intrinsics.cs b/src/System.Numerics.Vectors/src/System/Numerics/Vector4_Intrinsics.cs
index b6add39ec6..067b387f55 100644
--- a/src/System.Numerics.Vectors/src/System/Numerics/Vector4_Intrinsics.cs
+++ b/src/System.Numerics.Vectors/src/System/Numerics/Vector4_Intrinsics.cs
@@ -36,7 +36,7 @@ namespace System.Numerics
/// Constructs a vector whose elements are all the single specified value.
/// </summary>
/// <param name="value">The element to fill the vector with.</param>
- [JitIntrinsic]
+ [Intrinsic]
public Vector4(Single value)
: this(value, value, value, value)
{
@@ -48,7 +48,7 @@ namespace System.Numerics
/// <param name="x">X component.</param>
/// <param name="y">Y component.</param>
/// <param name="z">Z component.</param>
- [JitIntrinsic]
+ [Intrinsic]
public Vector4(Single x, Single y, Single z, Single w)
{
W = w;
@@ -102,7 +102,7 @@ namespace System.Numerics
/// <exception cref="RankException">If array is multidimensional.</exception>
/// <exception cref="ArgumentOutOfRangeException">If index is greater than end of the array or index is less than zero.</exception>
/// <exception cref="ArgumentException">If number of elements in source vector is greater than those available in destination array.</exception>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyTo(Single[] array, int index)
{
@@ -130,7 +130,7 @@ namespace System.Numerics
/// </summary>
/// <param name="other">The Vector4 to compare this instance to.</param>
/// <returns>True if the other Vector4 is equal to this instance; False otherwise.</returns>
- [JitIntrinsic]
+ [Intrinsic]
public bool Equals(Vector4 other)
{
return this.X == other.X
@@ -147,7 +147,7 @@ namespace System.Numerics
/// <param name="vector1">The first vector.</param>
/// <param name="vector2">The second vector.</param>
/// <returns>The dot product.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Dot(Vector4 vector1, Vector4 vector2)
{
@@ -163,7 +163,7 @@ namespace System.Numerics
/// <param name="value1">The first source vector.</param>
/// <param name="value2">The second source vector.</param>
/// <returns>The minimized vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Min(Vector4 value1, Vector4 value2)
{
@@ -180,7 +180,7 @@ namespace System.Numerics
/// <param name="value1">The first source vector.</param>
/// <param name="value2">The second source vector.</param>
/// <returns>The maximized vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Max(Vector4 value1, Vector4 value2)
{
@@ -196,7 +196,7 @@ namespace System.Numerics
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The absolute value vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Abs(Vector4 value)
{
@@ -208,7 +208,7 @@ namespace System.Numerics
/// </summary>
/// <param name="value">The source vector.</param>
/// <returns>The square root vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 SquareRoot(Vector4 value)
{
@@ -223,7 +223,7 @@ namespace System.Numerics
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The summed vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 operator +(Vector4 left, Vector4 right)
{
@@ -236,7 +236,7 @@ namespace System.Numerics
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The difference vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 operator -(Vector4 left, Vector4 right)
{
@@ -249,7 +249,7 @@ namespace System.Numerics
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The product vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 operator *(Vector4 left, Vector4 right)
{
@@ -262,7 +262,7 @@ namespace System.Numerics
/// <param name="left">The source vector.</param>
/// <param name="right">The scalar value.</param>
/// <returns>The scaled vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 operator *(Vector4 left, Single right)
{
@@ -275,7 +275,7 @@ namespace System.Numerics
/// <param name="left">The scalar value.</param>
/// <param name="right">The source vector.</param>
/// <returns>The scaled vector.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 operator *(Single left, Vector4 right)
{
@@ -288,7 +288,7 @@ namespace System.Numerics
/// <param name="left">The first source vector.</param>
/// <param name="right">The second source vector.</param>
/// <returns>The vector resulting from the division.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 operator /(Vector4 left, Vector4 right)
{
@@ -301,17 +301,10 @@ namespace System.Numerics
/// <param name="value1">The source vector.</param>
/// <param name="value2">The scalar value.</param>
/// <returns>The result of the division.</returns>
- [JitIntrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 operator /(Vector4 value1, float value2)
{
- float invDiv = 1.0f / value2;
-
- return new Vector4(
- value1.X * invDiv,
- value1.Y * invDiv,
- value1.Z * invDiv,
- value1.W * invDiv);
+ return value1 / new Vector4(value2);
}
/// <summary>
@@ -331,7 +324,7 @@ namespace System.Numerics
/// <param name="left">The first vector to compare.</param>
/// <param name="right">The second vector to compare.</param>
/// <returns>True if the vectors are equal; False otherwise.</returns>
- [JitIntrinsic]
+ [Intrinsic]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Vector4 left, Vector4 right)
{
diff --git a/src/System.Numerics.Vectors/tests/GenericVectorTests.cs b/src/System.Numerics.Vectors/tests/GenericVectorTests.cs
index e03022a216..eb0e588d64 100644
--- a/src/System.Numerics.Vectors/tests/GenericVectorTests.cs
+++ b/src/System.Numerics.Vectors/tests/GenericVectorTests.cs
@@ -14,7 +14,7 @@ namespace System.Numerics.Tests
/// <summary>
/// Vector{T} tests that use random number generation and a unified generic test structure
/// </summary>
- public class GenericVectorTests
+ public partial class GenericVectorTests
{
// Static constructor in top-level class\
static System.Numerics.Vector<float> dummy;
@@ -2699,11 +2699,11 @@ namespace System.Numerics.Tests
}
}
- internal static T[] GenerateRandomValuesForVector<T>() where T : struct
+ internal static T[] GenerateRandomValuesForVector<T>(int? numValues = null) where T : struct
{
int minValue = GetMinValue<T>();
int maxValue = GetMaxValue<T>();
- return Util.GenerateRandomValues<T>(Vector<T>.Count, minValue, maxValue);
+ return Util.GenerateRandomValues<T>(numValues ?? Vector<T>.Count, minValue, maxValue);
}
internal static int GetMinValue<T>() where T : struct
@@ -2776,4 +2776,4 @@ namespace System.Numerics.Tests
}
#endregion
}
-} \ No newline at end of file
+}
diff --git a/src/System.Numerics.Vectors/tests/GenericVectorTests.netcoreapp.cs b/src/System.Numerics.Vectors/tests/GenericVectorTests.netcoreapp.cs
new file mode 100644
index 0000000000..cb5ed7b81a
--- /dev/null
+++ b/src/System.Numerics.Vectors/tests/GenericVectorTests.netcoreapp.cs
@@ -0,0 +1,226 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using Xunit;
+using Xunit.Sdk;
+
+namespace System.Numerics.Tests
+{
+ /// <summary>
+ /// Vector{T} tests that use random number generation and a unified generic test structure
+ /// </summary>
+ public partial class GenericVectorTests
+ {
+ #region Constructor Tests
+
+ #region Tests for Span based constructor
+ [Fact]
+ public void ConstructorWithSpanByte() => TestConstructorWithSpan<Byte>();
+ [Fact]
+ public void ConstructorWithSpanSByte() => TestConstructorWithSpan<SByte>();
+ [Fact]
+ public void ConstructorWithSpanUInt16() => TestConstructorWithSpan<UInt16>();
+ [Fact]
+ public void ConstructorWithSpanInt16() => TestConstructorWithSpan<Int16>();
+ [Fact]
+ public void ConstructorWithSpanUInt32() => TestConstructorWithSpan<UInt32>();
+ [Fact]
+ public void ConstructorWithSpanInt32() => TestConstructorWithSpan<Int32>();
+ [Fact]
+ public void ConstructorWithSpanUInt64() => TestConstructorWithSpan<UInt64>();
+ [Fact]
+ public void ConstructorWithSpanInt64() => TestConstructorWithSpan<Int64>();
+ [Fact]
+ public void ConstructorWithSpanSingle() => TestConstructorWithSpan<Single>();
+ [Fact]
+ public void ConstructorWithSpanDouble() => TestConstructorWithSpan<Double>();
+
+ private void TestConstructorWithSpan<T>() where T : struct
+ {
+ T[] values = GenerateRandomValuesForVector<T>().ToArray();
+ var valueSpan = new Span<T>(values);
+
+ var vector = new Vector<T>(valueSpan);
+ ValidateVector(vector,
+ (index, val) =>
+ {
+ Assert.Equal(values[index], val);
+ });
+ }
+
+ [Fact]
+ public void SpanBasedConstructorWithLessElements_Byte() => Assert.Throws<IndexOutOfRangeException>(() => TestSpanBasedConstructorWithLessElements<Byte>());
+ [Fact]
+ public void SpanBasedConstructorWithLessElements_SByte() => Assert.Throws<IndexOutOfRangeException>(() => TestSpanBasedConstructorWithLessElements<SByte>());
+ [Fact]
+ public void SpanBasedConstructorWithLessElements_UInt16() => Assert.Throws<IndexOutOfRangeException>(() => TestSpanBasedConstructorWithLessElements<UInt16>());
+ [Fact]
+ public void SpanBasedConstructorWithLessElements_Int16() => Assert.Throws<IndexOutOfRangeException>(() => TestSpanBasedConstructorWithLessElements<Int16>());
+ [Fact]
+ public void SpanBasedConstructorWithLessElements_UInt32() => Assert.Throws<IndexOutOfRangeException>(() => TestSpanBasedConstructorWithLessElements<UInt32>());
+ [Fact]
+ public void SpanBasedConstructorWithLessElements_Int32() => Assert.Throws<IndexOutOfRangeException>(() => TestSpanBasedConstructorWithLessElements<Int32>());
+ [Fact]
+ public void SpanBasedConstructorWithLessElements_UInt64() => Assert.Throws<IndexOutOfRangeException>(() => TestSpanBasedConstructorWithLessElements<UInt64>());
+ [Fact]
+ public void SpanBasedConstructorWithLessElements_Int64() => Assert.Throws<IndexOutOfRangeException>(() => TestSpanBasedConstructorWithLessElements<Int64>());
+ [Fact]
+ public void SpanBasedConstructorWithLessElements_Single() => Assert.Throws<IndexOutOfRangeException>(() => TestSpanBasedConstructorWithLessElements<Single>());
+ [Fact]
+ public void SpanBasedConstructorWithLessElements_Double() => Assert.Throws<IndexOutOfRangeException>(() => TestSpanBasedConstructorWithLessElements<Double>());
+
+ private void TestSpanBasedConstructorWithLessElements<T>() where T : struct
+ {
+ T[] values = GenerateRandomValuesForVector<T>(Vector<T>.Count - 1).ToArray();
+ var vector = new Vector<T>(new Span<T>(values));
+ }
+
+ #endregion Tests for Span based constructor
+
+ #region Tests for Array based constructor
+
+ [Fact]
+ public void ArrayBasedConstructor_Byte() => TestArrayBasedConstructor<Byte>();
+ [Fact]
+ public void ArrayBasedConstructor_SByte() => TestArrayBasedConstructor<SByte>();
+ [Fact]
+ public void ArrayBasedConstructor_UInt16() => TestArrayBasedConstructor<UInt16>();
+ [Fact]
+ public void ArrayBasedConstructor_Int16() => TestArrayBasedConstructor<Int16>();
+ [Fact]
+ public void ArrayBasedConstructor_UInt32() => TestArrayBasedConstructor<UInt32>();
+ [Fact]
+ public void ArrayBasedConstructor_Int32() => TestArrayBasedConstructor<Int32>();
+ [Fact]
+ public void ArrayBasedConstructor_UInt64() => TestArrayBasedConstructor<UInt64>();
+ [Fact]
+ public void ArrayBasedConstructor_Int64() => TestArrayBasedConstructor<Int64>();
+ [Fact]
+ public void ArrayBasedConstructor_Single() => TestArrayBasedConstructor<Single>();
+ [Fact]
+ public void ArrayBasedConstructor_Double() => TestArrayBasedConstructor<Double>();
+
+ private void TestArrayBasedConstructor<T>() where T : struct
+ {
+ T[] values = GenerateRandomValuesForVector<T>(Vector<T>.Count).ToArray();
+ var vector = new Vector<T>(values);
+ ValidateVector(vector,
+ (index, val) =>
+ {
+ Assert.Equal(values[index], val);
+ });
+ }
+
+ [Fact]
+ public void ArrayIndexBasedConstructor_Byte() => TestArrayIndexBasedConstructor<Byte>();
+ [Fact]
+ public void ArrayIndexBasedConstructor_SByte() => TestArrayIndexBasedConstructor<SByte>();
+ [Fact]
+ public void ArrayIndexBasedConstructor_UInt16() => TestArrayIndexBasedConstructor<UInt16>();
+ [Fact]
+ public void ArrayIndexBasedConstructor_Int16() => TestArrayIndexBasedConstructor<Int16>();
+ [Fact]
+ public void ArrayIndexBasedConstructor_UInt32() => TestArrayIndexBasedConstructor<UInt32>();
+ [Fact]
+ public void ArrayIndexBasedConstructor_Int32() => TestArrayIndexBasedConstructor<Int32>();
+ [Fact]
+ public void ArrayIndexBasedConstructor_UInt64() => TestArrayIndexBasedConstructor<UInt64>();
+ [Fact]
+ public void ArrayIndexBasedConstructor_Int64() => TestArrayIndexBasedConstructor<Int64>();
+ [Fact]
+ public void ArrayIndexBasedConstructor_Single() => TestArrayIndexBasedConstructor<Single>();
+ [Fact]
+ public void ArrayIndexBasedConstructor_Double() => TestArrayIndexBasedConstructor<Double>();
+
+ private void TestArrayIndexBasedConstructor<T>() where T : struct
+ {
+ T[] values = GenerateRandomValuesForVector<T>(Vector<T>.Count * 2).ToArray();
+ int offset = Vector<T>.Count - 1;
+ var vector = new Vector<T>(values, offset);
+ ValidateVector(vector,
+ (index, val) =>
+ {
+ Assert.Equal(values[offset + index], val);
+ });
+ }
+
+ [Fact]
+ public void ArrayBasedConstructorWithLessElements_Byte() => TestArrayBasedConstructorWithLessElements<Byte>();
+ [Fact]
+ public void ArrayBasedConstructorWithLessElements_SByte() => TestArrayBasedConstructorWithLessElements<SByte>();
+ [Fact]
+ public void ArrayBasedConstructorWithLessElements_UInt16() => TestArrayBasedConstructorWithLessElements<UInt16>();
+ [Fact]
+ public void ArrayBasedConstructorWithLessElements_Int16() => TestArrayBasedConstructorWithLessElements<Int16>();
+ [Fact]
+ public void ArrayBasedConstructorWithLessElements_UInt32() => TestArrayBasedConstructorWithLessElements<UInt32>();
+ [Fact]
+ public void ArrayBasedConstructorWithLessElements_Int32() => TestArrayBasedConstructorWithLessElements<Int32>();
+ [Fact]
+ public void ArrayBasedConstructorWithLessElements_UInt64() => TestArrayBasedConstructorWithLessElements<UInt64>();
+ [Fact]
+ public void ArrayBasedConstructorWithLessElements_Int64() => TestArrayBasedConstructorWithLessElements<Int64>();
+ [Fact]
+ public void ArrayBasedConstructorWithLessElements_Single() => TestArrayBasedConstructorWithLessElements<Single>();
+ [Fact]
+ public void ArrayBasedConstructorWithLessElements_Double() => TestArrayBasedConstructorWithLessElements<Double>();
+
+ private void TestArrayBasedConstructorWithLessElements<T>() where T : struct
+ {
+ T[] values = GenerateRandomValuesForVector<T>(Vector<T>.Count - 1).ToArray();
+ Assert.Throws<IndexOutOfRangeException>(() => new Vector<T>(values));
+ }
+
+ [Fact]
+ public void ArrayIndexBasedConstructorLessElements_Byte() => TestArrayIndexBasedConstructorLessElements<Byte>();
+ [Fact]
+ public void ArrayIndexBasedConstructorLessElements_SByte() => TestArrayIndexBasedConstructorLessElements<SByte>();
+ [Fact]
+ public void ArrayIndexBasedConstructorLessElements_UInt16() => TestArrayIndexBasedConstructorLessElements<UInt16>();
+ [Fact]
+ public void ArrayIndexBasedConstructorLessElements_Int16() => TestArrayIndexBasedConstructorLessElements<Int16>();
+ [Fact]
+ public void ArrayIndexBasedConstructorLessElements_UInt32() => TestArrayIndexBasedConstructorLessElements<UInt32>();
+ [Fact]
+ public void ArrayIndexBasedConstructorLessElements_Int32() => TestArrayIndexBasedConstructorLessElements<Int32>();
+ [Fact]
+ public void ArrayIndexBasedConstructorLessElements_UInt64() => TestArrayIndexBasedConstructorLessElements<UInt64>();
+ [Fact]
+ public void ArrayIndexBasedConstructorLessElements_Int64() => TestArrayIndexBasedConstructorLessElements<Int64>();
+ [Fact]
+ public void ArrayIndexBasedConstructorLessElements_Single() => TestArrayIndexBasedConstructorLessElements<Single>();
+ [Fact]
+ public void ArrayIndexBasedConstructorLessElements_Double() => TestArrayIndexBasedConstructorLessElements<Double>();
+
+ private void TestArrayIndexBasedConstructorLessElements<T>() where T : struct
+ {
+ T[] values = GenerateRandomValuesForVector<T>(Vector<T>.Count * 2).ToArray();
+ Assert.Throws<IndexOutOfRangeException>(() => new Vector<T>(values, Vector<T>.Count + 1));
+ }
+
+ #endregion Tests for Array based constructor
+
+ #region Tests for constructors using unsupported types
+
+ [Fact]
+ public void ConstructorWithUnsupportedTypes_Guid() => TestConstructorWithUnsupportedTypes<Guid>();
+ [Fact]
+ public void ConstructorWithUnsupportedTypes_DateTime() => TestConstructorWithUnsupportedTypes<DateTime>();
+ [Fact]
+ public void ConstructorWithUnsupportedTypes_Char() => TestConstructorWithUnsupportedTypes<Char>();
+
+ private void TestConstructorWithUnsupportedTypes<T>() where T : struct
+ {
+ Assert.Throws<NotSupportedException>(() => new Vector<T>(new Span<T>(new T[4])));
+ }
+
+ #endregion Tests for constructors using unsupported types
+
+ #endregion Constructor Tests
+ }
+}
diff --git a/src/System.Numerics.Vectors/tests/GenericVectorTests.netcoreapp.tt b/src/System.Numerics.Vectors/tests/GenericVectorTests.netcoreapp.tt
new file mode 100644
index 0000000000..68a0c15077
--- /dev/null
+++ b/src/System.Numerics.Vectors/tests/GenericVectorTests.netcoreapp.tt
@@ -0,0 +1,174 @@
+<#@ template debug="true" hostSpecific="true" #>
+<#@ output extension=".cs" #>
+<#@ Assembly Name="System.Core.dll" #>
+<#@ Assembly Name="System.Xml.dll" #>
+<#@ import namespace="System" #>
+<#@ import namespace="System.Linq" #>
+<#@ import namespace="System.Runtime.InteropServices" #>
+<#@ include file="..\..\Common\src\CoreLib\System\Numerics\GenerationConfig.ttinclude" #><# GenerateCopyrightHeader(); #>
+
+using System;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using Xunit;
+using Xunit.Sdk;
+
+namespace System.Numerics.Tests
+{
+ /// <summary>
+ /// Vector{T} tests that use random number generation and a unified generic test structure
+ /// </summary>
+ public partial class GenericVectorTests
+ {
+ #region Constructor Tests
+
+ #region Tests for Span based constructor
+<#
+ foreach (var type in supportedTypes)
+ {
+#>
+ [Fact]
+ public void ConstructorWithSpan<#=type.Name#>() => TestConstructorWithSpan<<#=type.Name#>>();
+<#
+ }
+#>
+
+ private void TestConstructorWithSpan<T>() where T : struct
+ {
+ T[] values = GenerateRandomValuesForVector<T>().ToArray();
+ var valueSpan = new Span<T>(values);
+
+ var vector = new Vector<T>(valueSpan);
+ ValidateVector(vector,
+ (index, val) =>
+ {
+ Assert.Equal(values[index], val);
+ });
+ }
+
+<#
+ foreach (var type in supportedTypes)
+ {
+#>
+ [Fact]
+ public void SpanBasedConstructorWithLessElements_<#=type.Name#>() => Assert.Throws<IndexOutOfRangeException>(() => TestSpanBasedConstructorWithLessElements<<#=type.Name#>>());
+<#
+ }
+#>
+
+ private void TestSpanBasedConstructorWithLessElements<T>() where T : struct
+ {
+ T[] values = GenerateRandomValuesForVector<T>(Vector<T>.Count - 1).ToArray();
+ var vector = new Vector<T>(new Span<T>(values));
+ }
+
+ #endregion Tests for Span based constructor
+
+ #region Tests for Array based constructor
+
+<#
+ foreach (var type in supportedTypes)
+ {
+#>
+ [Fact]
+ public void ArrayBasedConstructor_<#=type.Name#>() => TestArrayBasedConstructor<<#=type.Name#>>();
+<#
+ }
+#>
+
+ private void TestArrayBasedConstructor<T>() where T : struct
+ {
+ T[] values = GenerateRandomValuesForVector<T>(Vector<T>.Count).ToArray();
+ var vector = new Vector<T>(values);
+ ValidateVector(vector,
+ (index, val) =>
+ {
+ Assert.Equal(values[index], val);
+ });
+ }
+
+<#
+ foreach (var type in supportedTypes)
+ {
+#>
+ [Fact]
+ public void ArrayIndexBasedConstructor_<#=type.Name#>() => TestArrayIndexBasedConstructor<<#=type.Name#>>();
+<#
+ }
+#>
+
+ private void TestArrayIndexBasedConstructor<T>() where T : struct
+ {
+ T[] values = GenerateRandomValuesForVector<T>(Vector<T>.Count * 2).ToArray();
+ int offset = Vector<T>.Count - 1;
+ var vector = new Vector<T>(values, offset);
+ ValidateVector(vector,
+ (index, val) =>
+ {
+ Assert.Equal(values[offset + index], val);
+ });
+ }
+
+<#
+ foreach (var type in supportedTypes)
+ {
+#>
+ [Fact]
+ public void ArrayBasedConstructorWithLessElements_<#=type.Name#>() => TestArrayBasedConstructorWithLessElements<<#=type.Name#>>();
+<#
+ }
+#>
+
+ private void TestArrayBasedConstructorWithLessElements<T>() where T : struct
+ {
+ T[] values = GenerateRandomValuesForVector<T>(Vector<T>.Count - 1).ToArray();
+ Assert.Throws<IndexOutOfRangeException>(() => new Vector<T>(values));
+ }
+
+<#
+ foreach (var type in supportedTypes)
+ {
+#>
+ [Fact]
+ public void ArrayIndexBasedConstructorLessElements_<#=type.Name#>() => TestArrayIndexBasedConstructorLessElements<<#=type.Name#>>();
+<#
+ }
+#>
+
+ private void TestArrayIndexBasedConstructorLessElements<T>() where T : struct
+ {
+ T[] values = GenerateRandomValuesForVector<T>(Vector<T>.Count * 2).ToArray();
+ Assert.Throws<IndexOutOfRangeException>(() => new Vector<T>(values, Vector<T>.Count + 1));
+ }
+
+ #endregion Tests for Array based constructor
+
+ #region Tests for constructors using unsupported types
+
+<#
+ Type[] unsupportedTypes = new[]
+ {
+ typeof(Guid), typeof(DateTime), typeof(char)
+ };
+
+
+ foreach (var type in unsupportedTypes)
+ {
+#>
+ [Fact]
+ public void ConstructorWithUnsupportedTypes_<#=type.Name#>() => TestConstructorWithUnsupportedTypes<<#=type.Name#>>();
+<#
+ }
+#>
+
+ private void TestConstructorWithUnsupportedTypes<T>() where T : struct
+ {
+ Assert.Throws<NotSupportedException>(() => new Vector<T>(new Span<T>(new T[4])));
+ }
+
+ #endregion Tests for constructors using unsupported types
+
+ #endregion Constructor Tests
+ }
+}
diff --git a/src/System.Numerics.Vectors/tests/GenericVectorTests.tt b/src/System.Numerics.Vectors/tests/GenericVectorTests.tt
index 4790b1ac50..5fbd230724 100644
--- a/src/System.Numerics.Vectors/tests/GenericVectorTests.tt
+++ b/src/System.Numerics.Vectors/tests/GenericVectorTests.tt
@@ -5,7 +5,7 @@
<#@ import namespace="System" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Runtime.InteropServices" #>
-<#@ include file="..\src\System\Numerics\GenerationConfig.ttinclude" #><# GenerateCopyrightHeader(); #>
+<#@ include file="..\..\common\src\corelib\System\Numerics\GenerationConfig.ttinclude" #><# GenerateCopyrightHeader(); #>
using System;
using System.Globalization;
@@ -19,7 +19,7 @@ namespace System.Numerics.Tests
/// <summary>
/// Vector{T} tests that use random number generation and a unified generic test structure
/// </summary>
- public class GenericVectorTests
+ public partial class GenericVectorTests
{
// Static constructor in top-level class\
static System.Numerics.Vector<float> dummy;
@@ -116,7 +116,7 @@ namespace System.Numerics.Tests
});
}
-<#
+<#
foreach (var type in supportedTypes)
{
#>
@@ -1792,11 +1792,11 @@ namespace System.Numerics.Tests
}
}
- internal static T[] GenerateRandomValuesForVector<T>() where T : struct
+ internal static T[] GenerateRandomValuesForVector<T>(int? numValues = null) where T : struct
{
int minValue = GetMinValue<T>();
int maxValue = GetMaxValue<T>();
- return Util.GenerateRandomValues<T>(Vector<T>.Count, minValue, maxValue);
+ return Util.GenerateRandomValues<T>(numValues ?? Vector<T>.Count, minValue, maxValue);
}
internal static int GetMinValue<T>() where T : struct
@@ -1869,4 +1869,4 @@ namespace System.Numerics.Tests
}
#endregion
}
-} \ No newline at end of file
+}
diff --git a/src/System.Numerics.Vectors/tests/Performance/Constructor/GenericVectorConstructorTests.cs b/src/System.Numerics.Vectors/tests/Performance/Constructor/GenericVectorConstructorTests.cs
new file mode 100644
index 0000000000..4220c38085
--- /dev/null
+++ b/src/System.Numerics.Vectors/tests/Performance/Constructor/GenericVectorConstructorTests.cs
@@ -0,0 +1,352 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using Xunit;
+using Xunit.Sdk;
+using Microsoft.Xunit.Performance;
+
+namespace System.Numerics.Tests
+{
+ public static class Constructor
+ {
+ private static Random s_random = new Random();
+
+ public const int DefaultInnerIterationsCount = 100000000;
+
+ [Benchmark(InnerIterationCount = DefaultInnerIterationsCount)]
+ public static void ConstructorBenchmark_Byte()
+ {
+ Byte[] arrValues = GenerateRandomValuesForVector<Byte>();
+ var spanValues = new Span<Byte>(arrValues);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ Construct<Byte>(spanValues);
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = DefaultInnerIterationsCount)]
+ public static void ConstructorBenchmark_SByte()
+ {
+ SByte[] arrValues = GenerateRandomValuesForVector<SByte>();
+ var spanValues = new Span<SByte>(arrValues);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ Construct<SByte>(spanValues);
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = DefaultInnerIterationsCount)]
+ public static void ConstructorBenchmark_UInt16()
+ {
+ UInt16[] arrValues = GenerateRandomValuesForVector<UInt16>();
+ var spanValues = new Span<UInt16>(arrValues);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ Construct<UInt16>(spanValues);
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = DefaultInnerIterationsCount)]
+ public static void ConstructorBenchmark_Int16()
+ {
+ Int16[] arrValues = GenerateRandomValuesForVector<Int16>();
+ var spanValues = new Span<Int16>(arrValues);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ Construct<Int16>(spanValues);
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = DefaultInnerIterationsCount)]
+ public static void ConstructorBenchmark_UInt32()
+ {
+ UInt32[] arrValues = GenerateRandomValuesForVector<UInt32>();
+ var spanValues = new Span<UInt32>(arrValues);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ Construct<UInt32>(spanValues);
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = DefaultInnerIterationsCount)]
+ public static void ConstructorBenchmark_Int32()
+ {
+ Int32[] arrValues = GenerateRandomValuesForVector<Int32>();
+ var spanValues = new Span<Int32>(arrValues);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ Construct<Int32>(spanValues);
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = DefaultInnerIterationsCount)]
+ public static void ConstructorBenchmark_UInt64()
+ {
+ UInt64[] arrValues = GenerateRandomValuesForVector<UInt64>();
+ var spanValues = new Span<UInt64>(arrValues);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ Construct<UInt64>(spanValues);
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = DefaultInnerIterationsCount)]
+ public static void ConstructorBenchmark_Int64()
+ {
+ Int64[] arrValues = GenerateRandomValuesForVector<Int64>();
+ var spanValues = new Span<Int64>(arrValues);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ Construct<Int64>(spanValues);
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = DefaultInnerIterationsCount)]
+ public static void ConstructorBenchmark_Single()
+ {
+ Single[] arrValues = GenerateRandomValuesForVector<Single>();
+ var spanValues = new Span<Single>(arrValues);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ Construct<Single>(spanValues);
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = DefaultInnerIterationsCount)]
+ public static void ConstructorBenchmark_Double()
+ {
+ Double[] arrValues = GenerateRandomValuesForVector<Double>();
+ var spanValues = new Span<Double>(arrValues);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ Construct<Double>(spanValues);
+ }
+ }
+ }
+
+
+ public static void Construct<T>(Span<T> values) where T : struct
+ {
+ for (var iteration = 0; iteration < Benchmark.InnerIterationCount; iteration++)
+ {
+ Vector<T> vect = new Vector<T>(values);
+ }
+ }
+
+ [Benchmark(InnerIterationCount = DefaultInnerIterationsCount)]
+ public static void SpanCastBenchmark_Byte()
+ {
+ Byte[] arrValues = GenerateRandomValuesForVector<Byte>();
+ var spanValues = new ReadOnlySpan<Byte>(arrValues);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ SpanCast<Byte>(spanValues);
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = DefaultInnerIterationsCount)]
+ public static void SpanCastBenchmark_SByte()
+ {
+ SByte[] arrValues = GenerateRandomValuesForVector<SByte>();
+ var spanValues = new ReadOnlySpan<SByte>(arrValues);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ SpanCast<SByte>(spanValues);
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = DefaultInnerIterationsCount)]
+ public static void SpanCastBenchmark_UInt16()
+ {
+ UInt16[] arrValues = GenerateRandomValuesForVector<UInt16>();
+ var spanValues = new ReadOnlySpan<UInt16>(arrValues);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ SpanCast<UInt16>(spanValues);
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = DefaultInnerIterationsCount)]
+ public static void SpanCastBenchmark_Int16()
+ {
+ Int16[] arrValues = GenerateRandomValuesForVector<Int16>();
+ var spanValues = new ReadOnlySpan<Int16>(arrValues);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ SpanCast<Int16>(spanValues);
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = DefaultInnerIterationsCount)]
+ public static void SpanCastBenchmark_UInt32()
+ {
+ UInt32[] arrValues = GenerateRandomValuesForVector<UInt32>();
+ var spanValues = new ReadOnlySpan<UInt32>(arrValues);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ SpanCast<UInt32>(spanValues);
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = DefaultInnerIterationsCount)]
+ public static void SpanCastBenchmark_Int32()
+ {
+ Int32[] arrValues = GenerateRandomValuesForVector<Int32>();
+ var spanValues = new ReadOnlySpan<Int32>(arrValues);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ SpanCast<Int32>(spanValues);
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = DefaultInnerIterationsCount)]
+ public static void SpanCastBenchmark_UInt64()
+ {
+ UInt64[] arrValues = GenerateRandomValuesForVector<UInt64>();
+ var spanValues = new ReadOnlySpan<UInt64>(arrValues);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ SpanCast<UInt64>(spanValues);
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = DefaultInnerIterationsCount)]
+ public static void SpanCastBenchmark_Int64()
+ {
+ Int64[] arrValues = GenerateRandomValuesForVector<Int64>();
+ var spanValues = new ReadOnlySpan<Int64>(arrValues);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ SpanCast<Int64>(spanValues);
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = DefaultInnerIterationsCount)]
+ public static void SpanCastBenchmark_Single()
+ {
+ Single[] arrValues = GenerateRandomValuesForVector<Single>();
+ var spanValues = new ReadOnlySpan<Single>(arrValues);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ SpanCast<Single>(spanValues);
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = DefaultInnerIterationsCount)]
+ public static void SpanCastBenchmark_Double()
+ {
+ Double[] arrValues = GenerateRandomValuesForVector<Double>();
+ var spanValues = new ReadOnlySpan<Double>(arrValues);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ SpanCast<Double>(spanValues);
+ }
+ }
+ }
+
+
+ public static void SpanCast<T>(ReadOnlySpan<T> values) where T : struct
+ {
+ for (var iteration = 0; iteration < Benchmark.InnerIterationCount; iteration++)
+ {
+ ReadOnlySpan<Vector<T>> vectors = MemoryMarshal.Cast<T, Vector<T>>(values);
+ Vector<T> vector = vectors[0];
+ }
+ }
+
+ internal static T[] GenerateRandomValuesForVector<T>() where T : struct
+ {
+ int minValue = GetMinValue<T>();
+ int maxValue = GetMaxValue<T>();
+ return Util.GenerateRandomValues<T>(Vector<T>.Count, minValue, maxValue);
+ }
+
+ internal static int GetMinValue<T>() where T : struct
+ {
+ if (typeof(T) == typeof(Int64) || typeof(T) == typeof(Single) || typeof(T) == typeof(Double) || typeof(T) == typeof(UInt32) || typeof(T) == typeof(UInt64))
+ {
+ return int.MinValue;
+ }
+ TypeInfo typeInfo = typeof(T).GetTypeInfo();
+ FieldInfo field = typeInfo.GetDeclaredField("MinValue");
+ var value = field.GetValue(null);
+ return (int)(dynamic)value;
+ }
+
+ internal static int GetMaxValue<T>() where T : struct
+ {
+ if (typeof(T) == typeof(Int64) || typeof(T) == typeof(Single) || typeof(T) == typeof(Double) || typeof(T) == typeof(UInt32) || typeof(T) == typeof(UInt64))
+ {
+ return int.MaxValue;
+ }
+ TypeInfo typeInfo = typeof(T).GetTypeInfo();
+ FieldInfo field = typeInfo.GetDeclaredField("MaxValue");
+ var value = field.GetValue(null);
+ return (int)(dynamic)value;
+ }
+ }
+}
diff --git a/src/System.Numerics.Vectors/tests/Performance/Constructor/GenericVectorConstructorTests.tt b/src/System.Numerics.Vectors/tests/Performance/Constructor/GenericVectorConstructorTests.tt
new file mode 100644
index 0000000000..5fb58ea5a7
--- /dev/null
+++ b/src/System.Numerics.Vectors/tests/Performance/Constructor/GenericVectorConstructorTests.tt
@@ -0,0 +1,119 @@
+<#@ template debug="true" hostSpecific="true" #>
+<#@ output extension=".cs" #>
+<#@ Assembly Name="System.Core.dll" #>
+<#@ Assembly Name="System.Xml.dll" #>
+<#@ import namespace="System" #>
+<#@ import namespace="System.Linq" #>
+<#@ import namespace="System.Runtime.InteropServices" #>
+<#@ include file="..\..\..\..\Common\src\CoreLib\System\Numerics\GenerationConfig.ttinclude" #><# GenerateCopyrightHeader(); #>
+
+using System;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using Xunit;
+using Xunit.Sdk;
+using Microsoft.Xunit.Performance;
+
+namespace System.Numerics.Tests
+{
+ public static class Constructor
+ {
+ private static Random s_random = new Random();
+
+ public const int DefaultInnerIterationsCount = 100000000;
+
+<#
+ foreach (var type in supportedTypes)
+ {
+#>
+ [Benchmark(InnerIterationCount = DefaultInnerIterationsCount)]
+ public static void ConstructorBenchmark_<#=type.Name#>()
+ {
+ <#=type.Name#>[] arrValues = GenerateRandomValuesForVector<<#=type.Name#>>();
+ var spanValues = new Span<<#=type.Name#>>(arrValues);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ Construct<<#=type.Name#>>(spanValues);
+ }
+ }
+ }
+
+<#
+ }
+#>
+
+ public static void Construct<T>(Span<T> values) where T : struct
+ {
+ for (var iteration = 0; iteration < Benchmark.InnerIterationCount; iteration++)
+ {
+ Vector<T> vect = new Vector<T>(values);
+ }
+ }
+
+<#
+ foreach (var type in supportedTypes)
+ {
+#>
+ [Benchmark(InnerIterationCount = DefaultInnerIterationsCount)]
+ public static void SpanCastBenchmark_<#=type.Name#>()
+ {
+ <#=type.Name#>[] arrValues = GenerateRandomValuesForVector<<#=type.Name#>>();
+ var spanValues = new ReadOnlySpan<<#=type.Name#>>(arrValues);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ SpanCast<<#=type.Name#>>(spanValues);
+ }
+ }
+ }
+
+<#
+ }
+#>
+
+ public static void SpanCast<T>(ReadOnlySpan<T> values) where T : struct
+ {
+ for (var iteration = 0; iteration < Benchmark.InnerIterationCount; iteration++)
+ {
+ ReadOnlySpan<Vector<T>> vectors = MemoryMarshal.Cast<T, Vector<T>>(values);
+ Vector<T> vector = vectors[0];
+ }
+ }
+
+ internal static T[] GenerateRandomValuesForVector<T>() where T : struct
+ {
+ int minValue = GetMinValue<T>();
+ int maxValue = GetMaxValue<T>();
+ return Util.GenerateRandomValues<T>(Vector<T>.Count, minValue, maxValue);
+ }
+
+ internal static int GetMinValue<T>() where T : struct
+ {
+ if (typeof(T) == typeof(Int64) || typeof(T) == typeof(Single) || typeof(T) == typeof(Double) || typeof(T) == typeof(UInt32) || typeof(T) == typeof(UInt64))
+ {
+ return int.MinValue;
+ }
+ TypeInfo typeInfo = typeof(T).GetTypeInfo();
+ FieldInfo field = typeInfo.GetDeclaredField("MinValue");
+ var value = field.GetValue(null);
+ return (int)(dynamic)value;
+ }
+
+ internal static int GetMaxValue<T>() where T : struct
+ {
+ if (typeof(T) == typeof(Int64) || typeof(T) == typeof(Single) || typeof(T) == typeof(Double) || typeof(T) == typeof(UInt32) || typeof(T) == typeof(UInt64))
+ {
+ return int.MaxValue;
+ }
+ TypeInfo typeInfo = typeof(T).GetTypeInfo();
+ FieldInfo field = typeInfo.GetDeclaredField("MaxValue");
+ var value = field.GetValue(null);
+ return (int)(dynamic)value;
+ }
+ }
+}
diff --git a/src/System.Numerics.Vectors/tests/Performance/System.Numerics.Vectors.Performance.Tests.csproj b/src/System.Numerics.Vectors/tests/Performance/System.Numerics.Vectors.Performance.Tests.csproj
index 0c1b1634d4..318d8f0e62 100644
--- a/src/System.Numerics.Vectors/tests/Performance/System.Numerics.Vectors.Performance.Tests.csproj
+++ b/src/System.Numerics.Vectors/tests/Performance/System.Numerics.Vectors.Performance.Tests.csproj
@@ -62,5 +62,30 @@
<Name>PerfRunner</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <Content Include="Constructor\GenericVectorConstructorTests.tt">
+ <Generator>TextTemplatingFileGenerator</Generator>
+ <LastGenOutput>GenericVectorConstructorTests.cs</LastGenOutput>
+ </Content>
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\Util.cs">
+ <Link>Util.cs</Link>
+ </Compile>
+ <Compile Include="Constructor\GenericVectorConstructorTests.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTime>True</DesignTime>
+ <DependentUpon>GenericVectorConstructorTests.tt</DependentUpon>
+ </Compile>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\..\..\Common\src\CoreLib\System\Numerics\GenerationConfig.ttinclude">
+ <Link>GenerationConfig.ttinclude</Link>
+ </None>
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.Numerics.Vectors/tests/QuaternionTests.cs b/src/System.Numerics.Vectors/tests/QuaternionTests.cs
index 6bb5c32e72..759f62a189 100644
--- a/src/System.Numerics.Vectors/tests/QuaternionTests.cs
+++ b/src/System.Numerics.Vectors/tests/QuaternionTests.cs
@@ -21,7 +21,7 @@ namespace System.Numerics.Tests
float actual;
actual = Quaternion.Dot(a, b);
- Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Dot did not return the expected value.");
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.Dot did not return the expected value: expected {expected} actual {actual}");
}
// A test for Length ()
@@ -39,7 +39,7 @@ namespace System.Numerics.Tests
actual = target.Length();
- Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Length did not return the expected value.");
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.Length did not return the expected value: expected {expected} actual {actual}");
}
// A test for LengthSquared ()
@@ -56,7 +56,7 @@ namespace System.Numerics.Tests
actual = target.LengthSquared();
- Assert.True(MathHelper.Equal(expected, actual), "Quaternion.LengthSquared did not return the expected value.");
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.LengthSquared did not return the expected value: expected {expected} actual {actual}");
}
// A test for Lerp (Quaternion, Quaternion, float)
@@ -73,12 +73,12 @@ namespace System.Numerics.Tests
Quaternion actual;
actual = Quaternion.Lerp(a, b, t);
- Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Lerp did not return the expected value.");
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.Lerp did not return the expected value: expected {expected} actual {actual}");
// Case a and b are same.
expected = a;
actual = Quaternion.Lerp(a, a, t);
- Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Lerp did not return the expected value.");
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.Lerp did not return the expected value: expected {expected} actual {actual}");
}
// A test for Lerp (Quaternion, Quaternion, float)
@@ -94,7 +94,7 @@ namespace System.Numerics.Tests
Quaternion expected = new Quaternion(a.X, a.Y, a.Z, a.W);
Quaternion actual = Quaternion.Lerp(a, b, t);
- Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Lerp did not return the expected value.");
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.Lerp did not return the expected value: expected {expected} actual {actual}");
}
// A test for Lerp (Quaternion, Quaternion, float)
@@ -110,7 +110,7 @@ namespace System.Numerics.Tests
Quaternion expected = new Quaternion(b.X, b.Y, b.Z, b.W);
Quaternion actual = Quaternion.Lerp(a, b, t);
- Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Lerp did not return the expected value.");
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.Lerp did not return the expected value: expected {expected} actual {actual}");
}
// A test for Lerp (Quaternion, Quaternion, float)
@@ -128,7 +128,7 @@ namespace System.Numerics.Tests
// Note that in quaternion world, Q == -Q. In the case of quaternions dot product is zero,
// one of the quaternion will be flipped to compute the shortest distance. When t = 1, we
// expect the result to be the same as quaternion b but flipped.
- Assert.True(actual == a, "Quaternion.Lerp did not return the expected value.");
+ Assert.True(actual == a, $"Quaternion.Lerp did not return the expected value: expected {a} actual {actual}");
}
// A test for Conjugate(Quaternion)
@@ -141,7 +141,7 @@ namespace System.Numerics.Tests
Quaternion actual;
actual = Quaternion.Conjugate(a);
- Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Conjugate did not return the expected value.");
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.Conjugate did not return the expected value: expected {expected} actual {actual}");
}
// A test for Normalize (Quaternion)
@@ -154,7 +154,7 @@ namespace System.Numerics.Tests
Quaternion actual;
actual = Quaternion.Normalize(a);
- Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Normalize did not return the expected value.");
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.Normalize did not return the expected value: expected {expected} actual {actual}");
}
// A test for Normalize (Quaternion)
@@ -166,7 +166,7 @@ namespace System.Numerics.Tests
Quaternion actual = Quaternion.Normalize(a);
Assert.True(float.IsNaN(actual.X) && float.IsNaN(actual.Y) && float.IsNaN(actual.Z) && float.IsNaN(actual.W)
- , "Quaternion.Normalize did not return the expected value.");
+ , $"Quaternion.Normalize did not return the expected value: expected {new Quaternion(float.NaN, float.NaN, float.NaN, float.NaN)} actual {actual}");
}
// A test for Concatenate(Quaternion, Quaternion)
@@ -180,7 +180,7 @@ namespace System.Numerics.Tests
Quaternion actual;
actual = Quaternion.Concatenate(a, b);
- Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Concatenate did not return the expected value.");
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.Concatenate did not return the expected value: expected {expected} actual {actual}");
}
// A test for operator - (Quaternion, Quaternion)
@@ -195,7 +195,7 @@ namespace System.Numerics.Tests
actual = a - b;
- Assert.True(MathHelper.Equal(expected, actual), "Quaternion.operator - did not return the expected value.");
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.operator - did not return the expected value: expected {expected} actual {actual}");
}
// A test for operator * (Quaternion, float)
@@ -210,7 +210,7 @@ namespace System.Numerics.Tests
actual = a * factor;
- Assert.True(MathHelper.Equal(expected, actual), "Quaternion.operator * did not return the expected value.");
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.operator * did not return the expected value: expected {expected} actual {actual}");
}
// A test for operator * (Quaternion, Quaternion)
@@ -225,7 +225,7 @@ namespace System.Numerics.Tests
actual = a * b;
- Assert.True(MathHelper.Equal(expected, actual), "Quaternion.operator * did not return the expected value.");
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.operator * did not return the expected value: expected {expected} actual {actual}");
}
// A test for operator / (Quaternion, Quaternion)
@@ -240,7 +240,7 @@ namespace System.Numerics.Tests
actual = a / b;
- Assert.True(MathHelper.Equal(expected, actual), "Quaternion.operator / did not return the expected value.");
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.operator / did not return the expected value: expected {expected} actual {actual}");
}
// A test for operator + (Quaternion, Quaternion)
@@ -255,7 +255,7 @@ namespace System.Numerics.Tests
actual = a + b;
- Assert.True(MathHelper.Equal(expected, actual), "Quaternion.operator + did not return the expected value.");
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.operator + did not return the expected value: expected {expected} actual {actual}");
}
// A test for Quaternion (float, float, float, float)
@@ -296,7 +296,7 @@ namespace System.Numerics.Tests
Quaternion actual;
actual = Quaternion.CreateFromAxisAngle(axis, angle);
- Assert.True(MathHelper.Equal(expected, actual), "Quaternion.CreateFromAxisAngle did not return the expected value.");
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.CreateFromAxisAngle did not return the expected value: expected {expected} actual {actual}");
}
// A test for CreateFromAxisAngle (Vector3f, float)
@@ -325,7 +325,7 @@ namespace System.Numerics.Tests
Quaternion actual1 = Quaternion.CreateFromAxisAngle(axis, angle1);
Quaternion actual2 = Quaternion.CreateFromAxisAngle(axis, angle2);
- Assert.True(MathHelper.Equal(actual1, actual2), "Quaternion.CreateFromAxisAngle did not return the expected value.");
+ Assert.True(MathHelper.Equal(actual1, actual2), $"Quaternion.CreateFromAxisAngle did not return the expected value: actual1 {actual1} actual2 {actual2}");
}
// A test for CreateFromAxisAngle (Vector3f, float)
@@ -342,7 +342,7 @@ namespace System.Numerics.Tests
actual1.X = -actual1.X;
actual1.W = -actual1.W;
- Assert.True(MathHelper.Equal(actual1, actual2), "Quaternion.CreateFromAxisAngle did not return the expected value.");
+ Assert.True(MathHelper.Equal(actual1, actual2), $"Quaternion.CreateFromAxisAngle did not return the expected value: actual1 {actual1} actual2 {actual2}");
}
[Fact]
@@ -358,7 +358,7 @@ namespace System.Numerics.Tests
Quaternion expected = yaw * pitch * roll;
Quaternion actual = Quaternion.CreateFromYawPitchRoll(yawAngle, pitchAngle, rollAngle);
- Assert.True(MathHelper.Equal(expected, actual));
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.QuaternionCreateFromYawPitchRollTest1 did not return the expected value: expected {expected} actual {actual}");
}
// Covers more numeric rigions
@@ -383,7 +383,7 @@ namespace System.Numerics.Tests
Quaternion expected = yaw * pitch * roll;
Quaternion actual = Quaternion.CreateFromYawPitchRoll(yawRad, pitchRad, rollRad);
- Assert.True(MathHelper.Equal(expected, actual), String.Format("Yaw:{0} Pitch:{1} Roll:{2}", yawAngle, pitchAngle, rollAngle));
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.QuaternionCreateFromYawPitchRollTest2 Yaw:{yawAngle} Pitch:{pitchAngle} Roll:{rollAngle} did not return the expected value: expected {expected} actual {actual}");
}
}
}
@@ -403,12 +403,12 @@ namespace System.Numerics.Tests
Quaternion actual;
actual = Quaternion.Slerp(a, b, t);
- Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Slerp did not return the expected value.");
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.Slerp did not return the expected value: expected {expected} actual {actual}");
// Case a and b are same.
expected = a;
actual = Quaternion.Slerp(a, a, t);
- Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Slerp did not return the expected value.");
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.Slerp did not return the expected value: expected {expected} actual {actual}");
}
// A test for Slerp (Quaternion, Quaternion, float)
@@ -424,7 +424,7 @@ namespace System.Numerics.Tests
Quaternion expected = new Quaternion(a.X, a.Y, a.Z, a.W);
Quaternion actual = Quaternion.Slerp(a, b, t);
- Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Slerp did not return the expected value.");
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.Slerp did not return the expected value: expected {expected} actual {actual}");
}
// A test for Slerp (Quaternion, Quaternion, float)
@@ -440,7 +440,7 @@ namespace System.Numerics.Tests
Quaternion expected = new Quaternion(b.X, b.Y, b.Z, b.W);
Quaternion actual = Quaternion.Slerp(a, b, t);
- Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Slerp did not return the expected value.");
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.Slerp did not return the expected value: expected {expected} actual {actual}");
}
// A test for Slerp (Quaternion, Quaternion, float)
@@ -459,7 +459,7 @@ namespace System.Numerics.Tests
// Note that in quaternion world, Q == -Q. In the case of quaternions dot product is zero,
// one of the quaternion will be flipped to compute the shortest distance. When t = 1, we
// expect the result to be the same as quaternion b but flipped.
- Assert.True(actual == expected, "Quaternion.Slerp did not return the expected value.");
+ Assert.True(actual == expected, $"Quaternion.Slerp did not return the expected value: expected {expected} actual {actual}");
}
// A test for Slerp (Quaternion, Quaternion, float)
@@ -475,7 +475,7 @@ namespace System.Numerics.Tests
Quaternion expected = new Quaternion(a.X, a.Y, a.Z, a.W);
Quaternion actual = Quaternion.Slerp(a, b, t);
- Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Slerp did not return the expected value.");
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.Slerp did not return the expected value: expected {expected} actual {actual}");
}
// A test for operator - (Quaternion)
@@ -489,7 +489,7 @@ namespace System.Numerics.Tests
actual = -a;
- Assert.True(MathHelper.Equal(expected, actual), "Quaternion.operator - did not return the expected value.");
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.operator - did not return the expected value: expected {expected} actual {actual}");
}
// A test for Inverse (Quaternion)
@@ -514,7 +514,7 @@ namespace System.Numerics.Tests
Quaternion actual = Quaternion.Inverse(a);
Assert.True(float.IsNaN(actual.X) && float.IsNaN(actual.Y) && float.IsNaN(actual.Z) && float.IsNaN(actual.W)
- );
+ , $"Quaternion.Inverse - did not return the expected value: expected {new Quaternion(float.NaN, float.NaN, float.NaN, float.NaN)} actual {actual}");
}
// A test for ToString ()
@@ -556,7 +556,7 @@ namespace System.Numerics.Tests
Quaternion actual;
actual = Quaternion.Divide(a, b);
- Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Divide did not return the expected value.");
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.Divide did not return the expected value: expected {expected} actual {actual}");
}
// A test for Equals (object)
@@ -615,7 +615,7 @@ namespace System.Numerics.Tests
Quaternion actual;
actual = Quaternion.Multiply(a, factor);
- Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Multiply did not return the expected value.");
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.Multiply did not return the expected value: expected {expected} actual {actual}");
}
// A test for Multiply (Quaternion, Quaternion)
@@ -629,7 +629,7 @@ namespace System.Numerics.Tests
Quaternion actual;
actual = Quaternion.Multiply(a, b);
- Assert.True(MathHelper.Equal(expected, actual), "Quaternion.Multiply did not return the expected value.");
+ Assert.True(MathHelper.Equal(expected, actual), $"Quaternion.Multiply did not return the expected value: expected {expected} actual {actual}");
}
// A test for Negate (Quaternion)
@@ -706,11 +706,13 @@ namespace System.Numerics.Tests
Quaternion expected = new Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
Quaternion actual = Quaternion.CreateFromRotationMatrix(matrix);
- Assert.True(MathHelper.Equal(expected, actual), "Quaternion.CreateFromRotationMatrix did not return the expected value.");
+ Assert.True(MathHelper.Equal(expected, actual),
+ $"Quaternion.CreateFromRotationMatrix did not return the expected value: expected {expected} actual {actual}");
// make sure convert back to matrix is same as we passed matrix.
Matrix4x4 m2 = Matrix4x4.CreateFromQuaternion(actual);
- Assert.True(MathHelper.Equal(matrix, m2), "Quaternion.CreateFromRotationMatrix did not return the expected value.");
+ Assert.True(MathHelper.Equal(matrix, m2),
+ $"Quaternion.CreateFromQuaternion did not return the expected value: matrix {matrix} m2 {m2}");
}
// A test for CreateFromRotationMatrix (Matrix4x4)
@@ -725,14 +727,12 @@ namespace System.Numerics.Tests
Quaternion expected = Quaternion.CreateFromAxisAngle(Vector3.UnitX, angle);
Quaternion actual = Quaternion.CreateFromRotationMatrix(matrix);
Assert.True(MathHelper.EqualRotation(expected, actual),
- string.Format("Quaternion.CreateFromRotationMatrix did not return the expected value. angle:{0} expected:{1} actual:{2}",
- angle.ToString(), expected.ToString(), actual.ToString()));
+ $"Quaternion.CreateFromRotationMatrix angle:{angle} did not return the expected value: expected {expected} actual {actual}");
// make sure convert back to matrix is same as we passed matrix.
Matrix4x4 m2 = Matrix4x4.CreateFromQuaternion(actual);
Assert.True(MathHelper.Equal(matrix, m2),
- string.Format("Quaternion.CreateFromRotationMatrix did not return the expected value. angle:{0} expected:{1} actual:{2}",
- angle.ToString(), matrix.ToString(), m2.ToString()));
+ $"Quaternion.CreateFromQuaternion angle:{angle} did not return the expected value: matrix {matrix} m2 {m2}");
}
}
@@ -748,14 +748,12 @@ namespace System.Numerics.Tests
Quaternion expected = Quaternion.CreateFromAxisAngle(Vector3.UnitY, angle);
Quaternion actual = Quaternion.CreateFromRotationMatrix(matrix);
Assert.True(MathHelper.EqualRotation(expected, actual),
- string.Format("Quaternion.CreateFromRotationMatrix did not return the expected value. angle:{0}",
- angle.ToString()));
+ $"Quaternion.CreateFromRotationMatrix angle:{angle} did not return the expected value: expected {expected} actual {actual}");
// make sure convert back to matrix is same as we passed matrix.
Matrix4x4 m2 = Matrix4x4.CreateFromQuaternion(actual);
Assert.True(MathHelper.Equal(matrix, m2),
- string.Format("Quaternion.CreateFromRotationMatrix did not return the expected value. angle:{0}",
- angle.ToString()));
+ $"Quaternion.CreateFromQuaternion angle:{angle} did not return the expected value: matrix {matrix} m2 {m2}");
}
}
@@ -771,14 +769,12 @@ namespace System.Numerics.Tests
Quaternion expected = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, angle);
Quaternion actual = Quaternion.CreateFromRotationMatrix(matrix);
Assert.True(MathHelper.EqualRotation(expected, actual),
- string.Format("Quaternion.CreateFromRotationMatrix did not return the expected value. angle:{0} expected:{1} actual:{2}",
- angle.ToString(), expected.ToString(), actual.ToString()));
+ $"Quaternion.CreateFromRotationMatrix angle:{angle} did not return the expected value: expected {expected} actual {actual}");
// make sure convert back to matrix is same as we passed matrix.
Matrix4x4 m2 = Matrix4x4.CreateFromQuaternion(actual);
Assert.True(MathHelper.Equal(matrix, m2),
- string.Format("Quaternion.CreateFromRotationMatrix did not return the expected value. angle:{0} expected:{1} actual:{2}",
- angle.ToString(), matrix.ToString(), m2.ToString()));
+ $"Quaternion.CreateFromQuaternion angle:{angle} did not return the expected value: matrix {matrix} m2 {m2}");
}
}
@@ -798,14 +794,12 @@ namespace System.Numerics.Tests
Quaternion actual = Quaternion.CreateFromRotationMatrix(matrix);
Assert.True(MathHelper.EqualRotation(expected, actual),
- string.Format("Quaternion.CreateFromRotationMatrix did not return the expected value. angle:{0} expected:{1} actual:{2}",
- angle.ToString(), expected.ToString(), actual.ToString()));
+ $"Quaternion.CreateFromRotationMatrix angle:{angle} did not return the expected value: expected {expected} actual {actual}");
// make sure convert back to matrix is same as we passed matrix.
Matrix4x4 m2 = Matrix4x4.CreateFromQuaternion(actual);
Assert.True(MathHelper.Equal(matrix, m2),
- string.Format("Quaternion.CreateFromRotationMatrix did not return the expected value. angle:{0} expected:{1} actual:{2}",
- angle.ToString(), matrix.ToString(), m2.ToString()));
+ $"Quaternion.CreateFromQuaternion angle:{angle} did not return the expected value: matrix {matrix} m2 {m2}");
}
}
@@ -819,11 +813,13 @@ namespace System.Numerics.Tests
Quaternion expected = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, angle) * Quaternion.CreateFromAxisAngle(Vector3.UnitY, angle);
Quaternion actual = Quaternion.CreateFromRotationMatrix(matrix);
- Assert.True(MathHelper.EqualRotation(expected, actual), "Quaternion.CreateFromRotationMatrix did not return the expected value.");
+ Assert.True(MathHelper.EqualRotation(expected, actual),
+ $"Quaternion.CreateFromRotationMatrix did not return the expected value: expected {expected} actual {actual}");
// make sure convert back to matrix is same as we passed matrix.
Matrix4x4 m2 = Matrix4x4.CreateFromQuaternion(actual);
- Assert.True(MathHelper.Equal(matrix, m2), "Quaternion.CreateFromRotationMatrix did not return the expected value.");
+ Assert.True(MathHelper.Equal(matrix, m2),
+ $"Quaternion.CreateFromQuaternion did not return the expected value: matrix {matrix} m2 {m2}");
}
// A test for CreateFromRotationMatrix (Matrix4x4)
@@ -836,11 +832,13 @@ namespace System.Numerics.Tests
Quaternion expected = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, angle) * Quaternion.CreateFromAxisAngle(Vector3.UnitX, angle);
Quaternion actual = Quaternion.CreateFromRotationMatrix(matrix);
- Assert.True(MathHelper.EqualRotation(expected, actual), "Quaternion.CreateFromRotationMatrix did not return the expected value.");
+ Assert.True(MathHelper.EqualRotation(expected, actual),
+ $"Quaternion.CreateFromRotationMatrix did not return the expected value: expected {expected} actual {actual}");
// make sure convert back to matrix is same as we passed matrix.
Matrix4x4 m2 = Matrix4x4.CreateFromQuaternion(actual);
- Assert.True(MathHelper.Equal(matrix, m2), "Quaternion.CreateFromRotationMatrix did not return the expected value.");
+ Assert.True(MathHelper.Equal(matrix, m2),
+ $"Quaternion.CreateFromQuaternion did not return the expected value: matrix {matrix} m2 {m2}");
}
// A test for CreateFromRotationMatrix (Matrix4x4)
@@ -853,11 +851,13 @@ namespace System.Numerics.Tests
Quaternion expected = Quaternion.CreateFromAxisAngle(Vector3.UnitY, angle) * Quaternion.CreateFromAxisAngle(Vector3.UnitX, angle);
Quaternion actual = Quaternion.CreateFromRotationMatrix(matrix);
- Assert.True(MathHelper.EqualRotation(expected, actual), "Quaternion.CreateFromRotationMatrix did not return the expected value.");
+ Assert.True(MathHelper.EqualRotation(expected, actual),
+ $"Quaternion.CreateFromRotationMatrix did not return the expected value: expected {expected} actual {actual}");
// make sure convert back to matrix is same as we passed matrix.
Matrix4x4 m2 = Matrix4x4.CreateFromQuaternion(actual);
- Assert.True(MathHelper.Equal(matrix, m2), "Quaternion.CreateFromRotationMatrix did not return the expected value.");
+ Assert.True(MathHelper.Equal(matrix, m2),
+ $"Quaternion.CreateFromQuaternion did not return the expected value: matrix {matrix} m2 {m2}");
}
// A test for Equals (Quaternion)
diff --git a/src/System.Numerics.Vectors/tests/System.Numerics.Vectors.Tests.csproj b/src/System.Numerics.Vectors/tests/System.Numerics.Vectors.Tests.csproj
index c52b2f9485..a79a3da3e2 100644
--- a/src/System.Numerics.Vectors/tests/System.Numerics.Vectors.Tests.csproj
+++ b/src/System.Numerics.Vectors/tests/System.Numerics.Vectors.Tests.csproj
@@ -12,7 +12,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Release|AnyCPU'" />
<ItemGroup>
- <Compile Include="..\src\System\Numerics\ConstantHelper.cs">
+ <Compile Include="$(CommonPath)\CoreLib\System\Numerics\ConstantHelper.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>ConstantHelper.tt</DependentUpon>
@@ -35,13 +35,20 @@
<Link>System\MathF.netstandard.cs</Link>
</Compile>
</ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp' OR '$(TargetGroup)' == 'uap'">
+ <Compile Include="GenericVectorTests.netcoreapp.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTime>True</DesignTime>
+ <DependentUpon>GenericVectorTests.netcoreapp.tt</DependentUpon>
+ </Compile>
+ </ItemGroup>
<ItemGroup>
- <None Include="..\src\System\Numerics\ConstantHelper.tt">
+ <None Include="$(CommonPath)\CoreLib\System\Numerics\ConstantHelper.tt">
<Link>ConstantHelper.tt</Link>
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>ConstantHelper.cs</LastGenOutput>
</None>
- <None Include="..\src\System\Numerics\GenerationConfig.ttinclude">
+ <None Include="$(CommonPath)\CoreLib\System\Numerics\GenerationConfig.ttinclude">
<Link>GenerationConfig.ttinclude</Link>
</None>
<None Include="GenericVectorTests.tt">
@@ -49,5 +56,15 @@
<LastGenOutput>GenericVectorTests.cs</LastGenOutput>
</None>
</ItemGroup>
+ <ItemGroup>
+ <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp'">
+ <Content Include="GenericVectorTests.netcoreapp.tt">
+ <Generator>TextTemplatingFileGenerator</Generator>
+ <LastGenOutput>GenericVectorTests.netcoreapp.cs</LastGenOutput>
+ </Content>
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SurrogateDataContract.cs b/src/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SurrogateDataContract.cs
index 0a5bc4c6b8..68bee7ff61 100644
--- a/src/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SurrogateDataContract.cs
+++ b/src/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SurrogateDataContract.cs
@@ -1,6 +1,7 @@
-//-----------------------------------------------------------------------------
-// Copyright (c) Microsoft Corporation. All rights reserved.
-//-----------------------------------------------------------------------------
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information
+
namespace System.Runtime.Serialization
{
using System;
diff --git a/src/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlReaderDelegator.cs b/src/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlReaderDelegator.cs
index 6acfc8c0f0..dc18ceb406 100644
--- a/src/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlReaderDelegator.cs
+++ b/src/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlReaderDelegator.cs
@@ -502,7 +502,7 @@ namespace System.Runtime.Serialization
public virtual byte[] ReadContentAsBase64()
{
if (isEndOfEmptyElement)
- return new byte[0];
+ return Array.Empty<byte>();
if (dictionaryReader == null)
{
diff --git a/src/System.Private.DataContractSerialization/src/System/Xml/XmlDictionaryReader.cs b/src/System.Private.DataContractSerialization/src/System/Xml/XmlDictionaryReader.cs
index 8028d77080..bdafce7db8 100644
--- a/src/System.Private.DataContractSerialization/src/System/Xml/XmlDictionaryReader.cs
+++ b/src/System.Private.DataContractSerialization/src/System/Xml/XmlDictionaryReader.cs
@@ -1322,11 +1322,6 @@ namespace System.Xml
return ReadArray(XmlDictionaryString.GetString(localName), XmlDictionaryString.GetString(namespaceUri), array, offset, count);
}
- public override void Close()
- {
- base.Dispose();
- }
-
private class XmlWrappedReader : XmlDictionaryReader, IXmlLineInfo
{
private XmlReader _reader;
diff --git a/src/System.Private.Reflection.Metadata.Ecma335/src/Resources/Strings.resx b/src/System.Private.Reflection.Metadata.Ecma335/src/Resources/Strings.resx
index 75779ebbda..731f0bb4a0 100644
--- a/src/System.Private.Reflection.Metadata.Ecma335/src/Resources/Strings.resx
+++ b/src/System.Private.Reflection.Metadata.Ecma335/src/Resources/Strings.resx
@@ -294,6 +294,12 @@
</data>
<data name="UnexpectedEmbeddedPortablePdbDataSignature" xml:space="preserve">
<value>Unexpected Embedded Portable PDB data signature value.</value>
+ </data>
+ <data name="UnexpectedPdbChecksumDataSignature" xml:space="preserve">
+ <value>Unexpected PDB Checksum data signature value.</value>
+ </data>
+ <data name="InvalidPdbChecksumDataFormat" xml:space="preserve">
+ <value>Invalid PDB Checksum data data format.</value>
</data>
<data name="UnexpectedSignatureHeader" xml:space="preserve">
<value>Expected signature header for '{0}', but found '{1}' (0x{2:x2}).</value>
@@ -354,6 +360,9 @@
</data>
<data name="ExpectedNonEmptyList" xml:space="preserve">
<value>Expected non-empty list.</value>
+ </data>
+ <data name="ExpectedNonEmptyArray" xml:space="preserve">
+ <value>Expected non-empty array.</value>
</data>
<data name="ExpectedNonEmptyString" xml:space="preserve">
<value>Expected non-empty string.</value>
diff --git a/src/System.Private.Reflection.Metadata.Ecma335/src/System.Private.Reflection.Metadata.Ecma335.csproj b/src/System.Private.Reflection.Metadata.Ecma335/src/System.Private.Reflection.Metadata.Ecma335.csproj
index 9853f6d4f9..409e24a6a4 100644
--- a/src/System.Private.Reflection.Metadata.Ecma335/src/System.Private.Reflection.Metadata.Ecma335.csproj
+++ b/src/System.Private.Reflection.Metadata.Ecma335/src/System.Private.Reflection.Metadata.Ecma335.csproj
@@ -224,6 +224,7 @@
<Compile Include="$(SystemReflectionMetadataPath)System\Reflection\PortableExecutable\CorFlags.cs" />
<Compile Include="$(SystemReflectionMetadataPath)System\Reflection\PortableExecutable\CorHeader.cs" />
<Compile Include="$(SystemReflectionMetadataPath)System\Reflection\PortableExecutable\DebugDirectory\CodeViewDebugDirectoryData.cs" />
+ <Compile Include="$(SystemReflectionMetadataPath)System\Reflection\PortableExecutable\DebugDirectory\PdbChecksumDebugDirectoryData.cs" />
<Compile Include="$(SystemReflectionMetadataPath)System\Reflection\PortableExecutable\DebugDirectory\DebugDirectoryEntry.cs" />
<Compile Include="$(SystemReflectionMetadataPath)System\Reflection\PortableExecutable\DebugDirectory\DebugDirectoryEntryType.cs" />
<Compile Include="$(SystemReflectionMetadataPath)System\Reflection\PortableExecutable\DirectoryEntry.cs" />
diff --git a/src/System.Private.Uri/src/FxCopBaseline.cs b/src/System.Private.Uri/src/FxCopBaseline.cs
index 5207ad7c67..dc2623db1e 100644
--- a/src/System.Private.Uri/src/FxCopBaseline.cs
+++ b/src/System.Private.Uri/src/FxCopBaseline.cs
@@ -1,3 +1,7 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
using System.Diagnostics.CodeAnalysis;
// TODO: Remove this once https://github.com/dotnet/corefx/issues/13107 is fixed
diff --git a/src/System.Private.Uri/src/System.Private.Uri.csproj b/src/System.Private.Uri/src/System.Private.Uri.csproj
index b7c563e485..90f37cff19 100644
--- a/src/System.Private.Uri/src/System.Private.Uri.csproj
+++ b/src/System.Private.Uri/src/System.Private.Uri.csproj
@@ -5,6 +5,7 @@
<ProjectGuid>{4AC5343E-6E31-4BA5-A795-0493AE7E9008}</ProjectGuid>
<AssemblyName>System.Private.Uri</AssemblyName>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <ILLinkClearInitLocals>true</ILLinkClearInitLocals>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
@@ -57,4 +58,4 @@
<ReferenceFromRuntime Include="System.Private.CoreLib" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Private.Uri/src/System/IPv4AddressHelper.cs b/src/System.Private.Uri/src/System/IPv4AddressHelper.cs
index e03eabac38..af47cb6a0f 100644
--- a/src/System.Private.Uri/src/System/IPv4AddressHelper.cs
+++ b/src/System.Private.Uri/src/System/IPv4AddressHelper.cs
@@ -27,7 +27,18 @@ namespace System
{
byte* numbers = stackalloc byte[NumberOfLabels];
isLoopback = Parse(str, numbers, start, end);
- return numbers[0] + "." + numbers[1] + "." + numbers[2] + "." + numbers[3];
+
+ Span<char> stackSpace = stackalloc char[NumberOfLabels * 3 + 3];
+ int totalChars = 0, charsWritten;
+ for (int i = 0; i < 3; i++)
+ {
+ numbers[i].TryFormat(stackSpace.Slice(totalChars), out charsWritten);
+ int periodPos = totalChars + charsWritten;
+ stackSpace[periodPos] = '.';
+ totalChars = periodPos + 1;
+ }
+ numbers[3].TryFormat(stackSpace.Slice(totalChars), out charsWritten);
+ return new string(stackSpace.Slice(0, totalChars + charsWritten));
}
}
@@ -184,7 +195,7 @@ namespace System
{
int numberBase = Decimal;
char ch;
- long[] parts = new long[4];
+ Span<long> parts = stackalloc long[4];
long currentValue = 0;
bool atLeastOneChar = false;
diff --git a/src/System.Private.Uri/src/System/Uri.cs b/src/System.Private.Uri/src/System/Uri.cs
index ebf064fad2..fcc1b9ea14 100644
--- a/src/System.Private.Uri/src/System/Uri.cs
+++ b/src/System.Private.Uri/src/System/Uri.cs
@@ -1411,14 +1411,12 @@ namespace System
throw new ArgumentOutOfRangeException(nameof(character));
}
- unsafe
+ return string.Create(3, character, (Span<char> chars, char c) =>
{
- char* chars = stackalloc char[3];
chars[0] = '%';
- chars[1] = UriHelper.s_hexUpperChars[(character & 0xf0) >> 4];
- chars[2] = UriHelper.s_hexUpperChars[character & 0xf];
- return new string(chars, 0, 3);
- }
+ chars[1] = UriHelper.s_hexUpperChars[(c & 0xf0) >> 4];
+ chars[2] = UriHelper.s_hexUpperChars[c & 0xf];
+ });
}
//
@@ -2023,7 +2021,7 @@ namespace System
((_flags & Flags.HasUnicode) != 0) &&
((_flags & Flags.HostUnicodeNormalized) == 0)) ? _originalUnicodeString : _string))
{
- // Cut trailing spaces in m_String
+ // Cut trailing spaces in _string
if (length > idx && UriHelper.IsLWS(pUriString[length - 1]))
{
--length;
@@ -2145,10 +2143,16 @@ namespace System
_flags |= Flags.AuthorityFound;
idx += 2;
}
+ // There is no Authority component, save the Path index
+ // Ideally we would treat mailto like any other URI, but for historical reasons we have to separate out its host parsing.
else if (_syntax.NotAny(UriSyntaxFlags.MailToLikeUri))
{
- // There is no Authority component, save the Path index
- // Note: mailto is the only guy who is treated specially, should be not.
+ // By now we know the URI has no Authority, so if the URI must be normalized, initialize it without one.
+ if (_iriParsing && (_flags & Flags.HasUnicode) != 0 && (_flags & Flags.HostUnicodeNormalized) == 0)
+ {
+ _string = _string.Substring(0, idx);
+ }
+ // Since there is no Authority, the path index is just the end of the scheme.
_flags |= ((Flags)idx | Flags.UnknownHostType);
return ParsingError.None;
}
@@ -2157,10 +2161,16 @@ namespace System
{
return ParsingError.BadAuthority;
}
+ // There is no Authority component, save the Path index
+ // Ideally we would treat mailto like any other URI, but for historical reasons we have to separate out its host parsing.
else if (_syntax.NotAny(UriSyntaxFlags.MailToLikeUri))
{
- // There is no Authority component, save the Path index
- // mailto is treated specially.
+ // By now we know the URI has no Authority, so if the URI must be normalized, initialize it without one.
+ if (_iriParsing && (_flags & Flags.HasUnicode) != 0 && (_flags & Flags.HostUnicodeNormalized) == 0)
+ {
+ _string = _string.Substring(0, idx);
+ }
+ // Since there is no Authority, the path index is just the end of the scheme.
_flags |= ((Flags)idx | Flags.UnknownHostType);
return ParsingError.None;
}
@@ -3368,12 +3378,6 @@ namespace System
_string = _syntax.SchemeName + SchemeDelimiter;
}
}
-
- // If host is absent, uri is abnormal and relative as in RFC 3986 section 5.4.2
- if (_info.Offset.Host == _info.Offset.Path)
- {
- _string = _syntax.SchemeName + ":";
- }
_info.Offset.Path = (ushort)_string.Length;
idx = _info.Offset.Path;
diff --git a/src/System.Private.Uri/tests/FunctionalTests/IriTest.cs b/src/System.Private.Uri/tests/FunctionalTests/IriTest.cs
index a7a09da6eb..ac7ba5a8ab 100644
--- a/src/System.Private.Uri/tests/FunctionalTests/IriTest.cs
+++ b/src/System.Private.Uri/tests/FunctionalTests/IriTest.cs
@@ -540,5 +540,32 @@ namespace System.PrivateUri.Tests
Assert.Equal(authority, fileTwoSlashes.Authority); // Two slashes must be followed by an authority
Assert.Equal(authority, fileFourSlashes.Authority); // More than three slashes looks like a UNC share
}
+
+ [Theory]
+ [InlineData(@"c:/path/with/unicode/ö/test.xml")]
+ [InlineData(@"file://c:/path/with/unicode/ö/test.xml")]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Requires fix shipping in .NET 4.7.2")]
+ public void Iri_WindowsPathWithUnicode_DoesRemoveScheme(string uriString)
+ {
+ var uri = new Uri(uriString);
+ Assert.False(uri.LocalPath.StartsWith("file:"));
+ }
+
+ [Theory]
+ [InlineData("http:%C3%A8")]
+ [InlineData("http:\u00E8")]
+ [InlineData("%C3%A8")]
+ [InlineData("\u00E8")]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Requires fix shipping in .NET 4.7.2")]
+ public void Iri_RelativeUriCreation_ShouldNotNormalize(string uriString)
+ {
+ Uri href;
+ Uri hrefAbsolute;
+ Uri baseIri = new Uri("http://www.contoso.com");
+
+ Assert.True(Uri.TryCreate(uriString, UriKind.RelativeOrAbsolute, out href));
+ Assert.True(Uri.TryCreate(baseIri, href, out hrefAbsolute));
+ Assert.Equal("http://www.contoso.com/%C3%A8", hrefAbsolute.AbsoluteUri);
+ }
}
}
diff --git a/src/System.Private.Xml.Linq/src/System/Xml/Linq/XContainer.cs b/src/System.Private.Xml.Linq/src/System/Xml/Linq/XContainer.cs
index 7a3ae67461..31c5801dbd 100644
--- a/src/System.Private.Xml.Linq/src/System/Xml/Linq/XContainer.cs
+++ b/src/System.Private.Xml.Linq/src/System/Xml/Linq/XContainer.cs
@@ -108,7 +108,7 @@ namespace System.Xml.Linq
/// <item>TimeSpan</item>
/// <item>Any type implementing ToString()</item>
/// <item>Any type implementing IEnumerable</item>
- ///
+ ///
/// </list>
/// When adding complex content, a number of types may be passed to this method.
/// <list>
@@ -117,19 +117,19 @@ namespace System.Xml.Linq
/// <item>XAttribute</item>
/// <item>Any type implementing IEnumerable</item>
/// </list>
- ///
+ ///
/// If an object implements IEnumerable, then the collection in the object is enumerated,
/// and all items in the collection are added. If the collection contains simple content,
/// then the simple content in the collection is concatenated and added as a single
/// string of simple content. If the collection contains complex content, then each item
/// in the collection is added separately.
- ///
+ ///
/// If content is null, nothing is added. This allows the results of a query to be passed
/// as content. If the query returns null, no contents are added, and this method does not
/// throw a NullReferenceException.
- ///
+ ///
/// Attributes and simple content can't be added to a document.
- ///
+ ///
/// An added attribute must have a unique name within the element to
/// which it is being added.
/// </remarks>
@@ -235,7 +235,7 @@ namespace System.Xml.Linq
}
/// <summary>
- /// Creates an <see cref="XmlWriter"/> used to add either nodes
+ /// Creates an <see cref="XmlWriter"/> used to add either nodes
/// or attributes to the <see cref="XContainer"/>. The later option
/// applies only for <see cref="XElement"/>.
/// </summary>
@@ -259,7 +259,7 @@ namespace System.Xml.Linq
/// <summary>
/// Returns the descendant <see cref="XElement"/>s of this <see cref="XContainer"/>. Note this method will
/// not return itself in the resulting IEnumerable. See <see cref="XElement.DescendantsAndSelf()"/> if you
- /// need to include the current <see cref="XElement"/> in the results.
+ /// need to include the current <see cref="XElement"/> in the results.
/// <seealso cref="XElement.DescendantsAndSelf()"/>
/// </summary>
/// <returns>
@@ -275,7 +275,7 @@ namespace System.Xml.Linq
/// of XElement.
/// </summary>
/// <param name="name">The <see cref="XName"/> to match against descendant <see cref="XElement"/>s.</param>
- /// <returns>An <see cref="IEnumerable"/> of <see cref="XElement"/></returns>
+ /// <returns>An <see cref="IEnumerable"/> of <see cref="XElement"/></returns>
public IEnumerable<XElement> Descendants(XName name)
{
return name != null ? GetDescendants(name, false) : XElement.EmptySequence;
@@ -346,7 +346,7 @@ namespace System.Xml.Linq
/// that the content does not include <see cref="XAttribute"/>s.
/// <seealso cref="XElement.Attributes()"/>
/// </summary>
- /// <returns>The contents of this <see cref="XContainer"/></returns>
+ /// <returns>The contents of this <see cref="XContainer"/></returns>
public IEnumerable<XNode> Nodes()
{
XNode n = LastNode;
@@ -385,7 +385,7 @@ namespace System.Xml.Linq
{
if (this is XElement)
{
- // Change in the serialization of an empty element:
+ // Change in the serialization of an empty element:
// from start/end tag pair to empty tag
NotifyChanging(this, XObjectChangeEventArgs.Value);
if ((object)s != (object)content) throw new InvalidOperationException(SR.InvalidOperation_ExternalCode);
@@ -554,7 +554,7 @@ namespace System.Xml.Linq
{
if (this is XElement)
{
- // Change in the serialization of an empty element:
+ // Change in the serialization of an empty element:
// from empty tag to start/end tag pair
NotifyChanging(this, XObjectChangeEventArgs.Value);
if (content != null) throw new InvalidOperationException(SR.InvalidOperation_ExternalCode);
@@ -830,7 +830,7 @@ namespace System.Xml.Linq
}
else if (value is DateTime)
{
- s = ((DateTime)value).ToString("o"); // Round-trip date/time pattern.
+ s = XmlConvert.ToString((DateTime) value, XmlDateTimeSerializationMode.RoundtripKind);
}
else if (value is DateTimeOffset)
{
@@ -855,7 +855,7 @@ namespace System.Xml.Linq
internal void ReadContentFrom(XmlReader r)
{
if (r.ReadState != ReadState.Interactive) throw new InvalidOperationException(SR.InvalidOperation_ExpectedInteractive);
-
+
ContentReader cr = new ContentReader(this);
while (cr.ReadContentFrom(this, r) && r.Read()) ;
}
@@ -893,7 +893,7 @@ namespace System.Xml.Linq
return;
}
if (r.ReadState != ReadState.Interactive) throw new InvalidOperationException(SR.InvalidOperation_ExpectedInteractive);
-
+
ContentReader cr = new ContentReader(this, r, o);
do
{
diff --git a/src/System.Private.Xml.Linq/tests/misc/System.Xml.Linq.Misc.Tests.csproj b/src/System.Private.Xml.Linq/tests/misc/System.Xml.Linq.Misc.Tests.csproj
index 37d30161d0..def58e5d8c 100644
--- a/src/System.Private.Xml.Linq/tests/misc/System.Xml.Linq.Misc.Tests.csproj
+++ b/src/System.Private.Xml.Linq/tests/misc/System.Xml.Linq.Misc.Tests.csproj
@@ -16,6 +16,7 @@
<Compile Include="XHashtable.cs" />
<Compile Include="XLinqErrata4.cs" />
<Compile Include="XNameAPI.cs" />
+ <Compile Include="XAttribute.cs" />
<Compile Include="LoadSaveAsyncTests.cs" Condition="'$(TargetGroup)'=='netcoreapp'" />
</ItemGroup>
<ItemGroup>
diff --git a/src/System.Private.Xml.Linq/tests/misc/XAttribute.cs b/src/System.Private.Xml.Linq/tests/misc/XAttribute.cs
new file mode 100644
index 0000000000..5bb72329eb
--- /dev/null
+++ b/src/System.Private.Xml.Linq/tests/misc/XAttribute.cs
@@ -0,0 +1,22 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Test.ModuleCore;
+using Xunit;
+
+namespace System.Xml.Linq.Tests
+{
+ public class XAttributeTests
+ {
+ [Fact]
+ public void FormattedDate()
+ {
+ // Ensure we are compatible with the full framework
+ Assert.Equal("CreatedTime=\"2018-01-01T12:13:14Z\"", new XAttribute("CreatedTime", new DateTime(2018, 1, 1, 12, 13, 14, DateTimeKind.Utc)).ToString());
+ }
+ }
+}
diff --git a/src/System.Private.Xml.Linq/tests/xNodeBuilder/CommonTests.cs b/src/System.Private.Xml.Linq/tests/xNodeBuilder/CommonTests.cs
index bf5589d9cb..4fa4ab03de 100644
--- a/src/System.Private.Xml.Linq/tests/xNodeBuilder/CommonTests.cs
+++ b/src/System.Private.Xml.Linq/tests/xNodeBuilder/CommonTests.cs
@@ -9,6 +9,7 @@ using System.Linq;
using System.Globalization;
using System.Collections;
using System.Collections.Generic;
+using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XmlDiff;
@@ -3418,8 +3419,12 @@ namespace CoreXml.Test.XLinq
Exception exception = AssertExtensions.Throws<ArgumentException>(null, () => MoveToFirstElement(reader).ReadOuterXml());
if (!PlatformDetection.IsNetNative) // .Net Native toolchain optimizes away Exception messages
{
- string expectedMsg = "Cannot have ']]>' inside an XML CDATA block.";
- Assert.Equal(expectedMsg, exception.Message);
+ // \p{Pi} any kind of opening quote https://www.compart.com/en/unicode/category/Pi
+ // \p{Pf} any kind of closing quote https://www.compart.com/en/unicode/category/Pf
+ // \p{Po} any kind of punctuation character that is not a dash, bracket, quote or connector https://www.compart.com/en/unicode/category/Po
+ Assert.True(Regex.IsMatch(exception.Message, @"[\p{Pi}\p{Po}]" + Regex.Escape("]]>") + @"[\p{Pf}\p{Po}]"));
+ Assert.True(Regex.IsMatch(exception.Message, @"\b" + "XML" + @"\b"));
+ Assert.True(Regex.IsMatch(exception.Message, @"\b" + "CDATA" + @"\b"));
}
}
}
@@ -3612,8 +3617,13 @@ namespace CoreXml.Test.XLinq
Exception exception = AssertExtensions.Throws<ArgumentException>(null, () => MoveToFirstElement(reader).ReadOuterXml());
if (!PlatformDetection.IsNetNative) // .Net Native toolchain optimizes away Exception messages
{
- string expectedMsg = "An XML comment cannot contain '--', and '-' cannot be the last character.";
- Assert.Equal(expectedMsg, exception.Message);
+ // \b word boundary
+ // \p{Pi} any kind of opening quote https://www.compart.com/en/unicode/category/Pi
+ // \p{Pf} any kind of closing quote https://www.compart.com/en/unicode/category/Pf
+ // \p{Po} any kind of punctuation character that is not a dash, bracket, quote or connector https://www.compart.com/en/unicode/category/Po
+ Assert.True(Regex.IsMatch(exception.Message, @"\b" + "XML" + @"\b"));
+ Assert.True(Regex.IsMatch(exception.Message, @"[\p{Pi}\p{Po}]" + Regex.Escape("--") + @"[\p{Pf}\p{Po}]"));
+ Assert.True(Regex.IsMatch(exception.Message, @"[\p{Pi}\p{Po}]" + Regex.Escape("-") + @"[\p{Pf}\p{Po}]"));
}
}
}
@@ -4215,8 +4225,12 @@ namespace CoreXml.Test.XLinq
Exception exception = AssertExtensions.Throws<ArgumentException>(null, () => MoveToFirstElement(reader).ReadOuterXml());
if (!PlatformDetection.IsNetNative) // .Net Native toolchain optimizes away Exception messages
{
- string expectedMsg = "Cannot have '?>' inside an XML processing instruction.";
- Assert.Equal(expectedMsg, exception.Message);
+ // \b word boundary
+ // \p{Pi} any kind of opening quote https://www.compart.com/en/unicode/category/Pi
+ // \p{Pf} any kind of closing quote https://www.compart.com/en/unicode/category/Pf
+ // \p{Po} any kind of punctuation character that is not a dash, bracket, quote or connector https://www.compart.com/en/unicode/category/Po
+ Assert.True(Regex.IsMatch(exception.Message, @"[\p{Pi}\p{Po}]" + Regex.Escape("?>") + @"[\p{Pf}\p{Po}]"));
+ Assert.True(Regex.IsMatch(exception.Message, @"\b" + "XML" + @"\b"));
}
}
}
diff --git a/src/System.Private.Xml/src/Resources/Strings.resx b/src/System.Private.Xml/src/Resources/Strings.resx
index b7c8d8724f..073ceecb21 100644
--- a/src/System.Private.Xml/src/Resources/Strings.resx
+++ b/src/System.Private.Xml/src/Resources/Strings.resx
@@ -3413,42 +3413,38 @@ building and deploying the assemblies with the application.
</data>
<data name="HelpUsage" xml:space="preserve">
<value>
-Usage: dotnet {0} [[/assembly:&lt;assembly name&gt;] | [&lt;assembly file location&gt;]]
- [/type:] [/debug].
- </value>
+Usage: dotnet {0} [--assembly &lt;assembly file path&gt;] [--type &lt;type name&gt;]</value>
</data>
<data name="HelpDevOptions" xml:space="preserve">
- <value> Developer options:</value>
+ <value>
+ Developer options:</value>
</data>
<data name="HelpAssembly" xml:space="preserve">
- <value> {0} Assembly location or display name. Short form is '{1}'.</value>
+ <value> {0}|{1} Assembly location or display name.</value>
</data>
<data name="HelpType" xml:space="preserve">
- <value> {0} Generate code for serialization/deserialization of the
- specified type from the input assembly. Short form is '{1}'.</value>
+ <value> {0} Generate code for serialization/deserialization of the specified type from the input assembly.</value>
</data>
<data name="HelpForce" xml:space="preserve">
- <value> {0} Forces overwrite of a previously generated assembly.
- Short form is '{1}'.</value>
+ <value> {0} Forces overwrite of a previously generated assembly.</value>
</data>
<data name="HelpProxy" xml:space="preserve">
- <value> {0} Generate serialization code only for proxy classes and web
- method parameters. Short form is '{1}'.</value>
+ <value> {0} Generate serialization code only for proxy classes and web method parameters.</value>
</data>
<data name="HelpOut" xml:space="preserve">
- <value> {0} Output directory name (default: target assembly location).
- Short form is '{1}'.</value>
+ <value> {0}|{1} Output directory name (default: target assembly location).</value>
</data>
<data name="HelpMiscOptions" xml:space="preserve">
- <value> Miscellaneous options:</value>
+ <value>
+ Miscellaneous options:</value>
</data>
<data name="HelpHelp" xml:space="preserve">
- <value> {0} or {1} Show this message</value>
+ <value> {0}|{1} Show help.</value>
</data>
<data name="MoreHelp" xml:space="preserve">
<value>If you would like more help, please type "sgen {0}".</value>
</data>
<data name="GenerateSerializerNotFound" xml:space="preserve">
- <value>`System.Xml.Serialization.XmlSerializer` does not have a method named `GenerateSerializerNotFound`. SGen does not support the framework of the version you are using.</value>
+ <value>Method 'System.Xml.Serialization.XmlSerializer.GenerateSerializer' was not found. This is likely because you are using an older version of the framework. Please update to .NET Core v2.1 or later.</value>
</data>
-</root> \ No newline at end of file
+</root>
diff --git a/src/System.Private.Xml/src/System/Xml/Core/XmlEncodedRawTextWriter.cs b/src/System.Private.Xml/src/System/Xml/Core/XmlEncodedRawTextWriter.cs
index a1e6c3e1d2..3c8f752f65 100644
--- a/src/System.Private.Xml/src/System/Xml/Core/XmlEncodedRawTextWriter.cs
+++ b/src/System.Private.Xml/src/System/Xml/Core/XmlEncodedRawTextWriter.cs
@@ -171,6 +171,11 @@ namespace System.Xml
_textContentMarks[0] = 1;
_charEntityFallback = new CharEntityEncoderFallback();
+
+ // grab bom before possibly changing encoding settings
+ ReadOnlySpan<byte> bom = encoding.Preamble;
+
+ // the encoding instance this creates can differ from the one passed in
this.encoding = Encoding.GetEncoding(
settings.Encoding.CodePage,
_charEntityFallback,
@@ -180,7 +185,6 @@ namespace System.Xml
if (!stream.CanSeek || stream.Position == 0)
{
- ReadOnlySpan<byte> bom = encoding.Preamble;
if (bom.Length != 0)
{
this.stream.Write(bom);
diff --git a/src/System.Private.Xml/src/System/Xml/NameTable.cs b/src/System.Private.Xml/src/System/Xml/NameTable.cs
index 2218a369e8..2317dd9767 100644
--- a/src/System.Private.Xml/src/System/Xml/NameTable.cs
+++ b/src/System.Private.Xml/src/System/Xml/NameTable.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System;
+using System.Runtime.InteropServices;
namespace System.Xml
{
@@ -197,7 +198,7 @@ namespace System.Xml
Entry[] oldEntries = _entries;
Entry[] newEntries = new Entry[newMask + 1];
- // use oldEntries.Length to eliminate the range check
+ // use oldEntries.Length to eliminate the range check
for (int i = 0; i < oldEntries.Length; i++)
{
Entry e = oldEntries[i];
@@ -234,13 +235,13 @@ namespace System.Xml
private static int ComputeHash32(string key)
{
- ReadOnlySpan<byte> bytes = key.AsReadOnlySpan().AsBytes();
+ ReadOnlySpan<byte> bytes = MemoryMarshal.AsBytes(key.AsSpan());
return Marvin.ComputeHash32(bytes, Marvin.DefaultSeed);
}
private static int ComputeHash32(char[] key, int start, int len)
{
- ReadOnlySpan<byte> bytes = key.AsReadOnlySpan().Slice(start, len).AsBytes();
+ ReadOnlySpan<byte> bytes = MemoryMarshal.AsBytes(key.AsSpan(start, len));
return Marvin.ComputeHash32(bytes, Marvin.DefaultSeed);
}
}
diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/SchemaImporter.cs b/src/System.Private.Xml/src/System/Xml/Serialization/SchemaImporter.cs
index 974aa82ba4..8bf4b20188 100644
--- a/src/System.Private.Xml/src/System/Xml/Serialization/SchemaImporter.cs
+++ b/src/System.Private.Xml/src/System/Xml/Serialization/SchemaImporter.cs
@@ -155,7 +155,7 @@ namespace System.Xml.Serialization
TypeDesc typeDesc = Scope.GetTypeDesc(typeof(object));
StructMapping mapping = new StructMapping();
mapping.TypeDesc = typeDesc;
- mapping.Members = new MemberMapping[0];
+ mapping.Members = Array.Empty<MemberMapping>();
mapping.IncludeInSchema = false;
mapping.TypeName = Soap.UrType;
mapping.Namespace = XmlSchema.Namespace;
diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/SoapReflectionImporter.cs b/src/System.Private.Xml/src/System/Xml/Serialization/SoapReflectionImporter.cs
index 05838f6828..383946e7d4 100644
--- a/src/System.Private.Xml/src/System/Xml/Serialization/SoapReflectionImporter.cs
+++ b/src/System.Private.Xml/src/System/Xml/Serialization/SoapReflectionImporter.cs
@@ -266,7 +266,7 @@ namespace System.Xml.Serialization
StructMapping mapping = new StructMapping();
mapping.IsSoap = true;
mapping.TypeDesc = typeDesc;
- mapping.Members = new MemberMapping[0];
+ mapping.Members = Array.Empty<MemberMapping>();
mapping.IncludeInSchema = false;
mapping.TypeName = Soap.UrType;
mapping.Namespace = XmlSchema.Namespace;
@@ -739,7 +739,7 @@ namespace System.Xml.Serialization
attribute.Mapping = ImportTypeMapping(_modelScope.GetTypeModel(accessorType), (a.SoapAttribute == null ? String.Empty : a.SoapAttribute.DataType), limiter);
attribute.Default = GetDefaultValue(model.FieldTypeDesc, a);
accessor.Attribute = attribute;
- accessor.Elements = new ElementAccessor[0];
+ accessor.Elements = Array.Empty<ElementAccessor>();
}
else
{
diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/Types.cs b/src/System.Private.Xml/src/System/Xml/Serialization/Types.cs
index 079ec5e661..8f099cc27f 100644
--- a/src/System.Private.Xml/src/System/Xml/Serialization/Types.cs
+++ b/src/System.Private.Xml/src/System/Xml/Serialization/Types.cs
@@ -1253,7 +1253,7 @@ namespace System.Xml.Serialization
{
if (typeof(IEnumerable).IsAssignableFrom(type))
{
- MethodInfo enumerator = type.GetMethod("GetEnumerator", new Type[0]);
+ MethodInfo enumerator = type.GetMethod("GetEnumerator", Array.Empty<Type>());
if (enumerator == null || !typeof(IEnumerator).IsAssignableFrom(enumerator.ReturnType))
{
diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSchemaImporter.cs b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSchemaImporter.cs
index 8dd5777b34..6d4dc7c57e 100644
--- a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSchemaImporter.cs
+++ b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSchemaImporter.cs
@@ -1166,7 +1166,7 @@ namespace System.Xml.Serialization
accessor.Mapping = mapping;
MemberMapping member = new MemberMapping();
- member.Elements = new ElementAccessor[0];
+ member.Elements = Array.Empty<ElementAccessor>();
member.Text = accessor;
if (isMixed)
{
@@ -1499,7 +1499,7 @@ namespace System.Xml.Serialization
AttributeAccessor accessor = ImportAttribute(attribute, identifier, ns, attribute);
if (accessor == null) return;
MemberMapping member = new MemberMapping();
- member.Elements = new ElementAccessor[0];
+ member.Elements = Array.Empty<ElementAccessor>();
member.Attribute = accessor;
member.Name = CodeIdentifier.MakeValid(Accessor.UnescapeName(accessor.Name));
member.Name = membersScope.AddUnique(member.Name, member);
@@ -1529,7 +1529,7 @@ namespace System.Xml.Serialization
accessor.Mapping = mapping;
MemberMapping member = new MemberMapping();
- member.Elements = new ElementAccessor[0];
+ member.Elements = Array.Empty<ElementAccessor>();
member.Attribute = accessor;
member.Name = membersScope.MakeRightCase("AnyAttr");
member.Name = membersScope.AddUnique(member.Name, member);
@@ -1584,7 +1584,7 @@ namespace System.Xml.Serialization
xmlnsMapping.TypeDesc = xmlnsTypeDesc;
xmlnsMapping.TypeName = xmlnsMapping.TypeDesc.Name;
- xmlnsMapping.Members = new MemberMapping[0];
+ xmlnsMapping.Members = Array.Empty<MemberMapping>();
xmlnsMapping.IncludeInSchema = false;
xmlnsMapping.ReferencedByTopLevelElement = true;
diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReader.cs b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReader.cs
index c9882b4b25..17a11a2cf5 100644
--- a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReader.cs
+++ b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReader.cs
@@ -111,7 +111,7 @@ namespace System.Xml.Serialization
private string _guidID;
private string _timeSpanID;
- private static bool s_checkDeserializeAdvances;
+ private static bool s_checkDeserializeAdvances=false;
protected abstract void InitIDs();
@@ -1106,7 +1106,7 @@ namespace System.Xml.Serialization
if (arraySize != null && arraySize.Length > 0)
dimensions = arraySize.Split(null);
else
- dimensions = new string[0];
+ dimensions = Array.Empty<string>();
soapArrayInfo.dimensions = 0;
soapArrayInfo.length = -1;
@@ -2411,7 +2411,7 @@ namespace System.Xml.Serialization
internal void GenerateEnd()
{
- GenerateEnd(new string[0], new XmlMapping[0], new Type[0]);
+ GenerateEnd(Array.Empty<string>(), Array.Empty<XmlMapping>(), Array.Empty<Type>());
}
internal void GenerateEnd(string[] methods, XmlMapping[] xmlMappings, Type[] types)
{
@@ -3573,7 +3573,7 @@ namespace System.Xml.Serialization
Writer.Write(", ");
WriteQuotedCSharpString(structMapping.Namespace);
Writer.WriteLine(");");
- members = new Member[0];
+ members = Array.Empty<Member>();
anyFixups = false;
fixupMethodName = null;
}
diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationWriter.cs b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationWriter.cs
index 766ee3628a..dda50dfb90 100644
--- a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationWriter.cs
+++ b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationWriter.cs
@@ -4153,6 +4153,15 @@ namespace System.Xml.Serialization
Writer.Write(source);
Writer.Write(".Length != 0)");
}
+ else if(value is Double || value is Single)
+ {
+ Writer.Write("!");
+ Writer.Write(source);
+ Writer.Write(".Equals(");
+ Type type= Type.GetType(mapping.TypeDesc.Type.FullName);
+ WriteValue(type != null ? Convert.ChangeType(value, type) : value);
+ Writer.Write(")");
+ }
else
{
Writer.Write(source);
@@ -4220,9 +4229,17 @@ namespace System.Xml.Serialization
Writer.Write(((Int32)value).ToString(null, NumberFormatInfo.InvariantInfo));
else if (type == typeof(Double))
{
- if (double.IsNaN((Double)value))
+ if (Double.IsNaN((Double)value))
+ {
+ Writer.Write("System.Double.NaN");
+ }
+ else if(Double.IsPositiveInfinity((Double)value))
{
- Writer.Write("double.NaN");
+ Writer.Write("System.Double.PositiveInfinity");
+ }
+ else if(Double.IsNegativeInfinity((Double)value))
+ {
+ Writer.Write("System.Double.NegativeInfinity");
}
else
{
@@ -4246,6 +4263,14 @@ namespace System.Xml.Serialization
{
Writer.Write("System.Single.NaN");
}
+ else if(Single.IsPositiveInfinity((Single)value))
+ {
+ Writer.Write("System.Single.PositiveInfinity");
+ }
+ else if (Single.IsNegativeInfinity((Single)value))
+ {
+ Writer.Write("System.Single.NegativeInfinity");
+ }
else
{
Writer.Write(((Single)value).ToString("R", NumberFormatInfo.InvariantInfo));
diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializer.cs b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializer.cs
index e7a3342436..25fdb4df57 100644
--- a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializer.cs
+++ b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializer.cs
@@ -159,6 +159,7 @@ namespace System.Xml.Serialization
internal string DefaultNamespace = null;
#endif
private Type _rootType;
+ private bool _isReflectionBasedSerializer = false;
private static TempAssemblyCache s_cache = new TempAssemblyCache();
private static volatile XmlSerializerNamespaces s_defaultNamespaces;
@@ -447,7 +448,7 @@ namespace System.Xml.Serialization
}
SerializePrimitive(xmlWriter, o, namespaces);
}
- else if (ShouldUseReflectionBasedSerialization(_mapping))
+ else if (ShouldUseReflectionBasedSerialization(_mapping) || _isReflectionBasedSerializer)
{
SerializeUsingReflection(xmlWriter, o, namespaces, encodingStyle, id);
}
@@ -587,7 +588,7 @@ namespace System.Xml.Serialization
}
return DeserializePrimitive(xmlReader, events);
}
- else if (ShouldUseReflectionBasedSerialization(_mapping))
+ else if (ShouldUseReflectionBasedSerialization(_mapping) || _isReflectionBasedSerializer)
{
return DeserializeUsingReflection(xmlReader, encodingStyle, events);
}
@@ -797,6 +798,7 @@ namespace System.Xml.Serialization
serializers[i] = new XmlSerializer();
serializers[i]._rootType = type;
serializers[i]._mapping = mappings[i];
+ serializers[i]._isReflectionBasedSerializer = true;
}
return serializers;
diff --git a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializerFactory.cs b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializerFactory.cs
index cfd9374aff..95f2f17bf9 100644
--- a/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializerFactory.cs
+++ b/src/System.Private.Xml/src/System/Xml/Serialization/XmlSerializerFactory.cs
@@ -40,7 +40,7 @@ namespace System.Xml.Serialization
/// </devdoc>
public XmlSerializer CreateSerializer(Type type, XmlRootAttribute root)
{
- return CreateSerializer(type, null, new Type[0], root, null, null);
+ return CreateSerializer(type, null, Array.Empty<Type>(), root, null, null);
}
/// <include file='doc\XmlSerializerFactory.uex' path='docs/doc[@for="XmlSerializerFactory.CreateSerializer3"]/*' />
@@ -58,7 +58,7 @@ namespace System.Xml.Serialization
/// </devdoc>
public XmlSerializer CreateSerializer(Type type, XmlAttributeOverrides overrides)
{
- return CreateSerializer(type, overrides, new Type[0], null, null, null);
+ return CreateSerializer(type, overrides, Array.Empty<Type>(), null, null, null);
}
/// <include file='doc\XmlSerializerFactory.uex' path='docs/doc[@for="XmlSerializerFactory.CreateSerializer5"]/*' />
diff --git a/src/System.Private.Xml/src/System/Xml/Xsl/XsltOld/DbgCompiler.cs b/src/System.Private.Xml/src/System/Xml/Xsl/XsltOld/DbgCompiler.cs
index 0dce03c365..aa992b9ecf 100644
--- a/src/System.Private.Xml/src/System/Xml/Xsl/XsltOld/DbgCompiler.cs
+++ b/src/System.Private.Xml/src/System/Xml/Xsl/XsltOld/DbgCompiler.cs
@@ -32,7 +32,7 @@ namespace System.Xml.Xsl.XsltOld
private DbgData()
{
_styleSheet = null;
- _variables = new VariableAction[0];
+ _variables = Array.Empty<VariableAction>();
}
public static DbgData Empty { get { return s_nullDbgData; } }
}
diff --git a/src/System.Private.Xml/src/System/Xml/Xsl/XsltOld/UseAttributeSetsAction.cs b/src/System.Private.Xml/src/System/Xml/Xsl/XsltOld/UseAttributeSetsAction.cs
index bac0d33715..7f1fc34c64 100644
--- a/src/System.Private.Xml/src/System/Xml/Xsl/XsltOld/UseAttributeSetsAction.cs
+++ b/src/System.Private.Xml/src/System/Xml/Xsl/XsltOld/UseAttributeSetsAction.cs
@@ -32,7 +32,7 @@ namespace System.Xml.Xsl.XsltOld
if (_useString.Length == 0)
{
// Split creates empty node is spliting empty string
- _useAttributeSets = new XmlQualifiedName[0];
+ _useAttributeSets = Array.Empty<XmlQualifiedName>();
return;
}
@@ -56,7 +56,7 @@ namespace System.Xml.Xsl.XsltOld
throw;
}
// Ignore the whole list in forwards-compatible mode
- _useAttributeSets = new XmlQualifiedName[0];
+ _useAttributeSets = Array.Empty<XmlQualifiedName>();
}
}
diff --git a/src/System.Private.Xml/tests/Misc/System.Xml.Misc.Tests.csproj b/src/System.Private.Xml/tests/Misc/System.Xml.Misc.Tests.csproj
index 275891669f..102aa3cc79 100644
--- a/src/System.Private.Xml/tests/Misc/System.Xml.Misc.Tests.csproj
+++ b/src/System.Private.Xml/tests/Misc/System.Xml.Misc.Tests.csproj
@@ -10,6 +10,7 @@
<ItemGroup>
<Compile Include="RandomizedHashing.cs" />
<Compile Include="..\..\src\System\Xml\Core\SecureStringHasher.cs" />
+ <Compile Include="XmlUrlResolverTests.cs" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.Private.Xml/tests/Misc/XmlUrlResolverTests.cs b/src/System.Private.Xml/tests/Misc/XmlUrlResolverTests.cs
new file mode 100644
index 0000000000..ae7f394cee
--- /dev/null
+++ b/src/System.Private.Xml/tests/Misc/XmlUrlResolverTests.cs
@@ -0,0 +1,77 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.InteropServices;
+using Xunit;
+
+namespace System.Xml.Tests
+{
+ public class XmlUriResolverTests
+ {
+ [Fact]
+ public void Resolving_RelativeBase_Throws()
+ {
+ var resolver = new XmlUrlResolver();
+ Assert.Throws<NotSupportedException>(() => resolver.ResolveUri(
+ new Uri(Environment.CurrentDirectory + Path.DirectorySeparatorChar, UriKind.Relative), "test.xml"));
+ }
+
+ [Theory]
+ [MemberData(nameof(GetBaseUriAndPath))]
+ public void Resolving_LocalPath_Ok(Uri baseUri, string path)
+ {
+ var resolver = new XmlUrlResolver();
+ Uri resolvedUri = resolver.ResolveUri(baseUri, path);
+
+ Assert.Equal(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, path)), resolvedUri.LocalPath);
+ Assert.True(resolvedUri.LocalPath.EndsWith(path.Replace('/', Path.DirectorySeparatorChar)));
+ }
+
+ [Theory]
+ [MemberData(nameof(XmlFileTargets))]
+ public void Resolving_OnlyWithBaseUri_Ok(string basePath)
+ {
+ var baseUri = new Uri(Path.GetFullPath(basePath));
+ var resolver = new XmlUrlResolver();
+ Uri resolvedUri = resolver.ResolveUri(baseUri, string.Empty);
+
+ Assert.Equal(Path.GetFullPath(basePath), resolvedUri.LocalPath);
+ }
+
+ public static IEnumerable<object[]> GetBaseUriAndPath()
+ {
+ // Base URI as null is the default for internal Xml operation.
+ var baseUris = new List<Uri> { null };
+
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ // The case below does not work on Unix, the '#' ends up treated as a fragment and the path is cut there.
+ var currDirWithDirSeparator = Environment.CurrentDirectory + Path.DirectorySeparatorChar;
+ baseUris.Add(new Uri(currDirWithDirSeparator, UriKind.Absolute));
+ baseUris.Add(new Uri(string.Empty, UriKind.RelativeOrAbsolute));
+ }
+
+ foreach (Uri baseUri in baseUris)
+ {
+ foreach (object[] targetFile in XmlFileTargets)
+ yield return new object[] { baseUri, targetFile[0] };
+ }
+ }
+
+ public static IEnumerable<object[]> XmlFileTargets => new object[][]
+ {
+ new object[] { "f#/t/\u00eb/test.xml" },
+ new object[] { "/f#/t/\u00eb/t#st.xml" },
+ new object[] { "/f#/\u00e3/\u00eb/t\u00ebst.xml" },
+ new object[] { "u/t/c/test.xml" },
+ new object[] { "u/t/c/t#st.xml" },
+ new object[] { "/u/t/c/t\u00ebst.xml" },
+ new object[] { "test.xml" },
+ new object[] { "t#st.xml" },
+ new object[] { "t\u00ebst.xml" }
+ };
+ }
+}
diff --git a/src/System.Private.Xml/tests/Writers/XmlWriterApi/TCFullEndElement.cs b/src/System.Private.Xml/tests/Writers/XmlWriterApi/TCFullEndElement.cs
index afb534ae18..82a09864ec 100644
--- a/src/System.Private.Xml/tests/Writers/XmlWriterApi/TCFullEndElement.cs
+++ b/src/System.Private.Xml/tests/Writers/XmlWriterApi/TCFullEndElement.cs
@@ -4251,7 +4251,6 @@ namespace System.Xml.Tests
[XmlWriterInlineData(2, "XmlQualifiedName", "XmlQualifiedName", true, null )]
public void writeValue_27(XmlWriterUtils utils, int param, string sourceStr, string destStr, bool isValid, object expVal)
{
- Type source = typeMapper[sourceStr];
Type dest = typeMapper[destStr];
CultureInfo origCulture = null;
@@ -4270,7 +4269,8 @@ namespace System.Xml.Tests
if (param == 1)
w.WriteValue(value[sourceStr]);
else
- w.WriteAttributeString("a", value[sourceStr].ToString());
+ w.WriteAttributeString("a",
+ string.Format(CultureInfo.InvariantCulture, "{0}", value[sourceStr]));
w.WriteEndElement();
}
try
diff --git a/src/System.Private.Xml/tests/XmlReader/XmlResolver/XmlSystemPathResolverTests.cs b/src/System.Private.Xml/tests/XmlReader/XmlResolver/XmlSystemPathResolverTests.cs
index 4404f5fb9c..8c711bae7c 100644
--- a/src/System.Private.Xml/tests/XmlReader/XmlResolver/XmlSystemPathResolverTests.cs
+++ b/src/System.Private.Xml/tests/XmlReader/XmlResolver/XmlSystemPathResolverTests.cs
@@ -76,6 +76,7 @@ namespace System.Xml.Tests
|| e is FileNotFoundException
|| e is FormatException
|| e is UnauthorizedAccessException
+ || e is IOException
|| e is XmlException);
}
diff --git a/src/System.Private.Xml/tests/XmlSchema/XmlSchemaSet/TC_SchemaSet_Reprocess.cs b/src/System.Private.Xml/tests/XmlSchema/XmlSchemaSet/TC_SchemaSet_Reprocess.cs
index 0acd938c88..269dffa070 100644
--- a/src/System.Private.Xml/tests/XmlSchema/XmlSchemaSet/TC_SchemaSet_Reprocess.cs
+++ b/src/System.Private.Xml/tests/XmlSchema/XmlSchemaSet/TC_SchemaSet_Reprocess.cs
@@ -635,15 +635,15 @@ namespace System.Xml.Tests
string correctUri = Path.GetFullPath(path);
_output.WriteLine("Include uri: " + includeUri);
_output.WriteLine("Correct uri: " + correctUri);
- Stream s = new FileStream(Path.GetFullPath(path), FileMode.Open, FileAccess.Read, FileShare.Read, 1);
- XmlReader r = XmlReader.Create(s, new XmlReaderSettings(), includeUri);
- _output.WriteLine("Reader uri: " + r.BaseURI);
- XmlSchema som = null;
- using (r)
+ using (Stream s = new FileStream(Path.GetFullPath(path), FileMode.Open, FileAccess.Read, FileShare.Read, 1))
{
- som = XmlSchema.Read(r, new ValidationEventHandler(ValidationCallback));
+ XmlReader r = XmlReader.Create(s, new XmlReaderSettings(), includeUri);
+ _output.WriteLine("Reader uri: " + r.BaseURI);
+ using (r)
+ {
+ return XmlSchema.Read(r, new ValidationEventHandler(ValidationCallback));
+ }
}
- return som;
}
}
}
diff --git a/src/System.Private.Xml/tests/XmlSerializer/Performance/System.Xml.XmlSerializer.Performance.Tests.csproj b/src/System.Private.Xml/tests/XmlSerializer/Performance/System.Xml.XmlSerializer.Performance.Tests.csproj
index a04c4db3fb..a36a097ac3 100644
--- a/src/System.Private.Xml/tests/XmlSerializer/Performance/System.Xml.XmlSerializer.Performance.Tests.csproj
+++ b/src/System.Private.Xml/tests/XmlSerializer/Performance/System.Xml.XmlSerializer.Performance.Tests.csproj
@@ -11,7 +11,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
<ItemGroup>
- <Compile Include="$(TestSourceFolder)..\..\..\..\System.Runtime.Serialization.Xml\tests\Utils.cs" />
+ <Compile Include="$(CommonTestPath)\System\Runtime\Serialization\Utils.cs" />
<Compile Include="$(TestSourceFolder)..\..\..\..\System.Runtime.Serialization.Xml\tests\SerializationTypes.cs" />
<Compile Include="$(TestSourceFolder)..\..\..\..\System.Runtime.Serialization.Xml\tests\SerializationTypes.RuntimeOnly.cs" />
<Compile Include="$(TestSourceFolder)..\..\..\..\System.Runtime.Serialization.Xml\tests\Performance\PerformanceTestsCommon.cs" />
@@ -24,4 +24,4 @@
</ProjectReference>
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Private.Xml/tests/XmlSerializer/ReflectionOnly/System.Xml.XmlSerializer.ReflectionOnly.Tests.csproj b/src/System.Private.Xml/tests/XmlSerializer/ReflectionOnly/System.Xml.XmlSerializer.ReflectionOnly.Tests.csproj
index 11e1057ae5..ba3f95079b 100644
--- a/src/System.Private.Xml/tests/XmlSerializer/ReflectionOnly/System.Xml.XmlSerializer.ReflectionOnly.Tests.csproj
+++ b/src/System.Private.Xml/tests/XmlSerializer/ReflectionOnly/System.Xml.XmlSerializer.ReflectionOnly.Tests.csproj
@@ -11,7 +11,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uapaot-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uapaot-Release|AnyCPU'" />
<ItemGroup>
- <Compile Include="$(TestSourceFolder)..\..\..\..\System.Runtime.Serialization.Xml\tests\Utils.cs" />
+ <Compile Include="$(CommonTestPath)\System\Runtime\Serialization\Utils.cs" />
<Compile Include="$(TestSourceFolder)..\..\..\..\System.Runtime.Serialization.Xml\tests\SerializationTypes.cs" />
<Compile Include="$(TestSourceFolder)..\..\..\..\System.Runtime.Serialization.Xml\tests\SerializationTypes.RuntimeOnly.cs" />
<Compile Include="$(TestSourceFolder)..\..\..\..\System.Runtime.Serialization.Xml\tests\Performance\PerformanceTestsCommon.cs" />
diff --git a/src/System.Private.Xml/tests/XmlSerializer/System.Xml.XmlSerializer.Tests.csproj b/src/System.Private.Xml/tests/XmlSerializer/System.Xml.XmlSerializer.Tests.csproj
index 261a6360d6..f1bfe4c675 100644
--- a/src/System.Private.Xml/tests/XmlSerializer/System.Xml.XmlSerializer.Tests.csproj
+++ b/src/System.Private.Xml/tests/XmlSerializer/System.Xml.XmlSerializer.Tests.csproj
@@ -11,7 +11,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uapaot-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uapaot-Release|AnyCPU'" />
<ItemGroup>
- <Compile Include="$(TestSourceFolder)..\..\..\System.Runtime.Serialization.Xml\tests\Utils.cs" />
+ <Compile Include="$(CommonTestPath)\System\Runtime\Serialization\Utils.cs" />
<Compile Include="$(TestSourceFolder)..\..\..\System.Runtime.Serialization.Xml\tests\SerializationTypes.RuntimeOnly.cs" />
<Compile Include="$(TestSourceFolder)..\..\..\System.Runtime.Serialization.Xml\tests\SerializationTypes.cs" />
<Compile Include="$(TestSourceFolder)XmlSerializerTests.cs" />
diff --git a/src/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.cs b/src/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.cs
index 10281561d3..81c8f7bb1e 100644
--- a/src/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.cs
+++ b/src/System.Private.Xml/tests/XmlSerializer/XmlSerializerTests.cs
@@ -477,15 +477,15 @@ string.Format(@"<?xml version=""1.0"" encoding=""utf-8""?>
public static void XML_TypeWithXmlSchemaFormAttribute()
{
var value = new TypeWithXmlSchemaFormAttribute() { NoneSchemaFormListProperty = new List<string> { "abc" }, QualifiedSchemaFormListProperty = new List<bool> { true }, UnqualifiedSchemaFormListProperty = new List<int> { 1 } };
- var acutal = SerializeAndDeserialize<TypeWithXmlSchemaFormAttribute>(value,
+ var actual = SerializeAndDeserialize<TypeWithXmlSchemaFormAttribute>(value,
@"<?xml version=""1.0""?><TypeWithXmlSchemaFormAttribute xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""><UnqualifiedSchemaFormListProperty><int>1</int></UnqualifiedSchemaFormListProperty><NoneSchemaFormListProperty><NoneParameter>abc</NoneParameter></NoneSchemaFormListProperty><QualifiedSchemaFormListProperty><QualifiedParameter>true</QualifiedParameter></QualifiedSchemaFormListProperty></TypeWithXmlSchemaFormAttribute>");
- Assert.StrictEqual(value.NoneSchemaFormListProperty.Count, acutal.NoneSchemaFormListProperty.Count);
- Assert.StrictEqual(value.NoneSchemaFormListProperty[0], acutal.NoneSchemaFormListProperty[0]);
- Assert.StrictEqual(value.UnqualifiedSchemaFormListProperty.Count, acutal.UnqualifiedSchemaFormListProperty.Count);
- Assert.StrictEqual(value.UnqualifiedSchemaFormListProperty[0], acutal.UnqualifiedSchemaFormListProperty[0]);
- Assert.StrictEqual(value.QualifiedSchemaFormListProperty.Count, acutal.QualifiedSchemaFormListProperty.Count);
- Assert.StrictEqual(value.QualifiedSchemaFormListProperty[0], acutal.QualifiedSchemaFormListProperty[0]);
+ Assert.StrictEqual(value.NoneSchemaFormListProperty.Count, actual.NoneSchemaFormListProperty.Count);
+ Assert.StrictEqual(value.NoneSchemaFormListProperty[0], actual.NoneSchemaFormListProperty[0]);
+ Assert.StrictEqual(value.UnqualifiedSchemaFormListProperty.Count, actual.UnqualifiedSchemaFormListProperty.Count);
+ Assert.StrictEqual(value.UnqualifiedSchemaFormListProperty[0], actual.UnqualifiedSchemaFormListProperty[0]);
+ Assert.StrictEqual(value.QualifiedSchemaFormListProperty.Count, actual.QualifiedSchemaFormListProperty.Count);
+ Assert.StrictEqual(value.QualifiedSchemaFormListProperty[0], actual.QualifiedSchemaFormListProperty[0]);
}
[Fact]
@@ -1614,6 +1614,97 @@ string.Format(@"<?xml version=""1.0"" encoding=""utf-8""?>
}
[Fact]
+ public static void Xml_DefaultValueAttributeSetToPositiveInfinityTest()
+ {
+ var value = new DefaultValuesSetToPositiveInfinity();
+ var actual = SerializeAndDeserialize(value,
+@"<?xml version=""1.0""?>
+<DefaultValuesSetToPositiveInfinity xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">
+ <DoubleField>0</DoubleField>
+ <SingleField>0</SingleField>
+ <DoubleProp>0</DoubleProp>
+ <FloatProp>0</FloatProp>
+</DefaultValuesSetToPositiveInfinity>");
+ Assert.NotNull(actual);
+ Assert.Equal(value, actual);
+ }
+
+ [Fact]
+ public static void Xml_DefaultValueAttributeSetToNegativeInfinityTest()
+ {
+ var value = new DefaultValuesSetToNegativeInfinity();
+ var actual = SerializeAndDeserialize(value,
+@"<?xml version=""1.0""?>
+<DefaultValuesSetToNegativeInfinity xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">
+ <DoubleField>0</DoubleField>
+ <SingleField>0</SingleField>
+ <DoubleProp>0</DoubleProp>
+ <FloatProp>0</FloatProp>
+</DefaultValuesSetToNegativeInfinity>");
+ Assert.NotNull(actual);
+ Assert.Equal(value, actual);
+ }
+
+ [ActiveIssue(28321)]
+ [Fact]
+ public static void SerializeWithDefaultValueSetToNaNTest()
+ {
+ var value = new DefaultValuesSetToNaN();
+ value.DoubleField = Double.NaN;
+ value.SingleField = Single.NaN;
+ value.FloatProp = Single.NaN;
+ value.DoubleProp = Double.NaN;
+
+ bool result=SerializeWithDefaultValue(value,
+@"<?xml version=""1.0""?>
+<DefaultValuesSetToNaN xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" />");
+ Assert.True(result);
+ }
+
+ [Fact]
+ public static void SerializeWithDefaultValueSetToPositiveInfinityTest()
+ {
+ var value = new DefaultValuesSetToPositiveInfinity();
+ value.DoubleField = Double.PositiveInfinity;
+ value.SingleField = Single.PositiveInfinity;
+ value.FloatProp = Single.PositiveInfinity;
+ value.DoubleProp = Double.PositiveInfinity;
+
+ bool result = SerializeWithDefaultValue(value,
+@"<?xml version=""1.0""?>
+<DefaultValuesSetToPositiveInfinity xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" />");
+ Assert.True(result);
+ }
+
+ [Fact]
+ public static void SerializeWithDefaultValueSetToNegativeInfinityTest()
+ {
+ var value = new DefaultValuesSetToNegativeInfinity();
+ value.DoubleField = Double.NegativeInfinity;
+ value.SingleField = Single.NegativeInfinity;
+ value.FloatProp = Single.NegativeInfinity;
+ value.DoubleProp = Double.NegativeInfinity;
+
+ bool result = SerializeWithDefaultValue(value,
+ @"<?xml version=""1.0""?>
+<DefaultValuesSetToNegativeInfinity xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" />");
+ Assert.True(result);
+ }
+
+ private static bool SerializeWithDefaultValue<T>(T value, string baseline)
+ {
+ XmlSerializer serializer = new XmlSerializer(typeof(T));
+ using (MemoryStream ms = new MemoryStream())
+ {
+ serializer.Serialize(ms, value);
+ ms.Position = 0;
+ string output = new StreamReader(ms).ReadToEnd();
+ Utils.CompareResult result = Utils.Compare(baseline, output);
+ return result.Equal;
+ }
+ }
+
+ [Fact]
public static void Xml_TypeWithMismatchBetweenAttributeAndPropertyType()
{
var value = new TypeWithMismatchBetweenAttributeAndPropertyType();
diff --git a/src/System.Private.Xml/tests/XmlWriter/WriteWithEncoding.cs b/src/System.Private.Xml/tests/XmlWriter/WriteWithEncoding.cs
index 78c191a4d8..b764701630 100644
--- a/src/System.Private.Xml/tests/XmlWriter/WriteWithEncoding.cs
+++ b/src/System.Private.Xml/tests/XmlWriter/WriteWithEncoding.cs
@@ -3,7 +3,9 @@
// See the LICENSE file in the project root for more information.
using System.IO;
+using System.Linq;
using System.Text;
+using System.Xml.Xsl;
using Xunit;
namespace System.Xml.Tests
@@ -36,5 +38,38 @@ namespace System.Xml.Tests
Assert.Equal("<orderID>1-456-ab&#x661;</orderID><orderID>2-36-00a&#x10000;&#x10401;</orderID>", s);
}
+
+ [Fact]
+ public void WriteWithUtf32EncodingNoBom()
+ {
+ //Given, encoding set to UTF32 with no BOM
+ var settings = new XmlWriterSettings
+ {
+ OmitXmlDeclaration = false,
+ ConformanceLevel = ConformanceLevel.Document,
+ Encoding = new UTF32Encoding(false, false, true)
+ };
+
+ string resultString;
+ using (var result = new MemoryStream())
+ {
+ // BOM can be written in this call
+ var writer = XmlWriter.Create(result, settings);
+
+ // When, do work and get result
+ writer.WriteStartDocument();
+ writer.WriteStartElement("orders");
+ writer.WriteElementString("orderID", "1-456-ab\u0661");
+ writer.WriteElementString("orderID", "2-36-00a\uD800\uDC00\uD801\uDC01");
+ writer.WriteEndElement();
+ writer.WriteEndDocument();
+ writer.Flush();
+ result.Position = 0;
+ resultString = settings.Encoding.GetString(result.ToArray());
+ }
+
+ // Then, last '>' will be cut off in resulting string if BOM is present
+ Assert.Equal("<?xml version=\"1.0\" encoding=\"utf-32\"?>", string.Concat(resultString.Take(39)));
+ }
}
}
diff --git a/src/System.Private.Xml/tests/Xslt/XslCompiledTransformApi/XslCompiledTransform.cs b/src/System.Private.Xml/tests/Xslt/XslCompiledTransformApi/XslCompiledTransform.cs
index f9f00e7d3f..0c6dfaf71d 100644
--- a/src/System.Private.Xml/tests/Xslt/XslCompiledTransformApi/XslCompiledTransform.cs
+++ b/src/System.Private.Xml/tests/Xslt/XslCompiledTransformApi/XslCompiledTransform.cs
@@ -1616,7 +1616,7 @@ namespace System.Xml.Tests
{
try
{
- LoadXSL("\\\\", XslInputType.URI, readerType, new XmlUrlResolver());
+ LoadXSL(" ", XslInputType.URI, readerType, new XmlUrlResolver());
}
catch (System.ArgumentException)
{
@@ -2913,7 +2913,7 @@ namespace System.Xml.Tests
if (LoadXSL("showParam.xsl", xslInputType, readerType) == 1)
{
- Assert.Throws<System.ArgumentException>(() => xslt.Transform(szFullFilename, "\\\\"));
+ Assert.Throws<System.ArgumentException>(() => xslt.Transform(szFullFilename, " "));
return;
}
diff --git a/src/System.Private.Xml/tests/Xslt/XslCompiledTransformApi/XsltApiV2.cs b/src/System.Private.Xml/tests/Xslt/XslCompiledTransformApi/XsltApiV2.cs
index 5e058dce06..e06d0a74e2 100644
--- a/src/System.Private.Xml/tests/Xslt/XslCompiledTransformApi/XsltApiV2.cs
+++ b/src/System.Private.Xml/tests/Xslt/XslCompiledTransformApi/XsltApiV2.cs
@@ -44,7 +44,7 @@ namespace System.Xml.Tests
public String szDefaultNS = "urn:my-object";
public String szEmpty = "";
- public String szInvalid = "*?%(){}[]&!@#$";
+ public String szInvalid = "*?%(){}\0[]&!@#$";
public String szLongString = "ThisIsAVeryLongStringToBeStoredAsAVariableToDetermineHowLargeThisBufferForAVariableNameCanBeAndStillFunctionAsExpected";
public String szLongNS = "http://www.microsoft.com/this/is/a/very/long/namespace/uri/to/do/the/api/testing/for/xslt/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/";
public String[] szWhiteSpace = { " ", "\n", "\t", "\r", "\t\n \r\t" };
diff --git a/src/System.Private.Xml/tests/Xslt/XslCompiledTransformApi/XsltSettings.cs b/src/System.Private.Xml/tests/Xslt/XslCompiledTransformApi/XsltSettings.cs
index 01d7d5519a..7bfb96f3cc 100644
--- a/src/System.Private.Xml/tests/Xslt/XslCompiledTransformApi/XsltSettings.cs
+++ b/src/System.Private.Xml/tests/Xslt/XslCompiledTransformApi/XsltSettings.cs
@@ -5,6 +5,7 @@
using Xunit;
using Xunit.Abstractions;
using System.IO;
+using System.Text.RegularExpressions;
using System.Xml.XPath;
using System.Xml.Xsl;
@@ -335,7 +336,12 @@ namespace System.Xml.Tests
StringWriter sw;
var e = Assert.ThrowsAny<XsltException>(() => sw = Transform());
- Assert.Contains("Execution of the 'document()' function was prohibited. Use the XsltSettings.EnableDocumentFunction property to enable it.", e.Message);
+
+ // \p{Pi} any kind of opening quote https://www.compart.com/en/unicode/category/Pi
+ // \p{Pf} any kind of closing quote https://www.compart.com/en/unicode/category/Pf
+ // \p{Po} any kind of punctuation character that is not a dash, bracket, quote or connector https://www.compart.com/en/unicode/category/Po
+ Assert.Matches(@"[\p{Pi}\p{Po}]" + Regex.Escape("document()") + @"[\p{Pf}\p{Po}]", e.Message);
+ Assert.Matches(@"\b" + Regex.Escape("XsltSettings.EnableDocumentFunction") + @"\b", e.Message);
}
}
-} \ No newline at end of file
+}
diff --git a/src/System.Private.Xml/tests/Xslt/XslTransformApi/CXslTransform.cs b/src/System.Private.Xml/tests/Xslt/XslTransformApi/CXslTransform.cs
index 0a8ecb612c..bf9194ae81 100644
--- a/src/System.Private.Xml/tests/Xslt/XslTransformApi/CXslTransform.cs
+++ b/src/System.Private.Xml/tests/Xslt/XslTransformApi/CXslTransform.cs
@@ -1413,7 +1413,7 @@ namespace System.Xml.Tests
{
try
{
- LoadXSL("\\\\", InputType.URI, readerType);
+ LoadXSL(" ", InputType.URI, readerType);
}
catch (System.ArgumentException)
{
@@ -2522,7 +2522,7 @@ namespace System.Xml.Tests
if (LoadXSL("showParam.xsl", inputType, readerType) == 1)
{
- Assert.Throws<System.ArgumentException>(() => xslt.Transform(szFullFilename, "\\\\"));
+ Assert.Throws<System.ArgumentException>(() => xslt.Transform(szFullFilename, " "));
return;
}
diff --git a/src/System.Private.Xml/tests/Xslt/XslTransformApi/XSLTransform.cs b/src/System.Private.Xml/tests/Xslt/XslTransformApi/XSLTransform.cs
index a75f8ea73c..010efa92a2 100644
--- a/src/System.Private.Xml/tests/Xslt/XslTransformApi/XSLTransform.cs
+++ b/src/System.Private.Xml/tests/Xslt/XslTransformApi/XSLTransform.cs
@@ -57,7 +57,7 @@ namespace System.Xml.Tests
public String szDefaultNS = "urn:my-object";
public String szEmpty = "";
- public String szInvalid = "*?%(){}[]&!@#$";
+ public String szInvalid = "*?%()\0{}[]&!@#$";
public String szLongString = "ThisIsAVeryLongStringToBeStoredAsAVariableToDetermineHowLargeThisBufferForAVariableNameCanBeAndStillFunctionAsExpected";
public String szLongNS = "http://www.miocrosoft.com/this/is/a/very/long/namespace/uri/to/do/the/api/testing/for/xslt/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/0123456789/";
public String[] szWhiteSpace = { " ", "\n", "\t", "\r", "\t\n \r\t" };
diff --git a/src/System.Reflection.DispatchProxy/ref/Configurations.props b/src/System.Reflection.DispatchProxy/ref/Configurations.props
index c398e42e89..637e93f3d7 100644
--- a/src/System.Reflection.DispatchProxy/ref/Configurations.props
+++ b/src/System.Reflection.DispatchProxy/ref/Configurations.props
@@ -3,6 +3,8 @@
<PropertyGroup>
<BuildConfigurations>
netstandard;
+ uap10.0.16299;
+ uap;
</BuildConfigurations>
</PropertyGroup>
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Reflection.DispatchProxy/ref/System.Reflection.DispatchProxy.csproj b/src/System.Reflection.DispatchProxy/ref/System.Reflection.DispatchProxy.csproj
index ed520e0316..477e983d47 100644
--- a/src/System.Reflection.DispatchProxy/ref/System.Reflection.DispatchProxy.csproj
+++ b/src/System.Reflection.DispatchProxy/ref/System.Reflection.DispatchProxy.csproj
@@ -6,8 +6,18 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap10.0.16299-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap10.0.16299-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="System.Reflection.DispatchProxy.cs" />
</ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)' == 'uap10.0.16299'">
+ <Reference Include="System.Runtime" />
+ </ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)' == 'uap'">
+ <ProjectReference Include="..\..\System.Runtime\ref\System.Runtime.csproj" />
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Reflection.DispatchProxy/src/Configurations.props b/src/System.Reflection.DispatchProxy/src/Configurations.props
index 3fbbd69075..b3f3f55017 100644
--- a/src/System.Reflection.DispatchProxy/src/Configurations.props
+++ b/src/System.Reflection.DispatchProxy/src/Configurations.props
@@ -5,12 +5,14 @@
netfx;
netstandard;
netcoreapp2.0;
- uapaot-Windows_NT;
- uap-Windows_NT;
+ uap10.0.16299-Windows_NT;
+ uap10.0.16299aot-Windows_NT;
</PackageConfigurations>
<BuildConfigurations>
$(PackageConfigurations);
netcoreapp;
+ uap-Windows_NT;
+ uapaot-Windows_NT;
</BuildConfigurations>
</PropertyGroup>
</Project>
diff --git a/src/System.Reflection.DispatchProxy/src/System.Reflection.DispatchProxy.csproj b/src/System.Reflection.DispatchProxy/src/System.Reflection.DispatchProxy.csproj
index 58e4b88958..04020a4094 100644
--- a/src/System.Reflection.DispatchProxy/src/System.Reflection.DispatchProxy.csproj
+++ b/src/System.Reflection.DispatchProxy/src/System.Reflection.DispatchProxy.csproj
@@ -5,10 +5,10 @@
<ProjectGuid>{1E689C1B-690C-4799-BDE9-6E7990585894}</ProjectGuid>
<AssemblyName>System.Reflection.DispatchProxy</AssemblyName>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
- <IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'uapaot'">true</IsPartialFacadeAssembly>
+ <IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'uapaot' OR '$(TargetGroup)' == 'uap10.0.16299aot'">true</IsPartialFacadeAssembly>
<!-- this library depends on Ref.Emit which is not available for netstandard -->
<GeneratePlatformNotSupportedAssemblyMessage Condition="'$(TargetGroup)' == 'netstandard'">SR.PlatformNotSupported_ReflectionDispatchProxy</GeneratePlatformNotSupportedAssemblyMessage>
- <ResourcesSourceOutputDirectory Condition="'$(TargetGroup)' == 'uapaot'">None</ResourcesSourceOutputDirectory>
+ <ResourcesSourceOutputDirectory Condition="'$(TargetGroup)' == 'uapaot' OR '$(TargetGroup)' == 'uap10.0.16299aot'">None</ResourcesSourceOutputDirectory>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
@@ -22,6 +22,10 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uapaot-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uapaot-Windows_NT-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap10.0.16299-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap10.0.16299-Windows_NT-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap10.0.16299aot-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap10.0.16299aot-Windows_NT-Release|AnyCPU'" />
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true' AND '$(TargetGroup)' != 'netstandard'">
<Compile Include="System\Reflection\DispatchProxy.cs" />
<Compile Include="System\Reflection\DispatchProxyGenerator.cs" />
@@ -31,7 +35,7 @@
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
- <ItemGroup Condition="'$(TargetGroup)' == 'uapaot'">
+ <ItemGroup Condition="'$(TargetGroup)' == 'uapaot' OR '$(TargetGroup)' == 'uap10.0.16299aot'">
<ReferenceFromRuntime Include="System.Private.Interop" />
<ReferenceFromRuntime Include="System.Private.CoreLib" />
</ItemGroup>
diff --git a/src/System.Reflection.Emit.ILGeneration/ref/System.Reflection.Emit.ILGeneration.cs b/src/System.Reflection.Emit.ILGeneration/ref/System.Reflection.Emit.ILGeneration.cs
index 0009996c2a..77213e8ee3 100644
--- a/src/System.Reflection.Emit.ILGeneration/ref/System.Reflection.Emit.ILGeneration.cs
+++ b/src/System.Reflection.Emit.ILGeneration/ref/System.Reflection.Emit.ILGeneration.cs
@@ -48,6 +48,7 @@ namespace System.Reflection.Emit
public virtual void Emit(System.Reflection.Emit.OpCode opcode, System.Type cls) { }
public virtual void EmitCall(System.Reflection.Emit.OpCode opcode, System.Reflection.MethodInfo methodInfo, System.Type[] optionalParameterTypes) { }
public virtual void EmitCalli(System.Reflection.Emit.OpCode opcode, System.Reflection.CallingConventions callingConvention, System.Type returnType, System.Type[] parameterTypes, System.Type[] optionalParameterTypes) { }
+ public virtual void EmitCalli(System.Reflection.Emit.OpCode opcode, System.Runtime.InteropServices.CallingConvention unmanagedCallConv, Type returnType, Type[] parameterTypes) { }
public virtual void EmitWriteLine(System.Reflection.Emit.LocalBuilder localBuilder) { }
public virtual void EmitWriteLine(System.Reflection.FieldInfo fld) { }
public virtual void EmitWriteLine(string value) { }
diff --git a/src/System.Reflection.Emit.ILGeneration/ref/System.Reflection.Emit.ILGeneration.csproj b/src/System.Reflection.Emit.ILGeneration/ref/System.Reflection.Emit.ILGeneration.csproj
index 8f4487c380..c500b168be 100644
--- a/src/System.Reflection.Emit.ILGeneration/ref/System.Reflection.Emit.ILGeneration.csproj
+++ b/src/System.Reflection.Emit.ILGeneration/ref/System.Reflection.Emit.ILGeneration.csproj
@@ -13,6 +13,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\System.Runtime\ref\System.Runtime.csproj" />
+ <ProjectReference Include="..\..\System.Runtime.InteropServices\ref\System.Runtime.InteropServices.csproj" />
<ProjectReference Include="..\..\System.Reflection\ref\System.Reflection.csproj" />
<ProjectReference Include="..\..\System.Reflection.Primitives\ref\System.Reflection.Primitives.csproj" />
</ItemGroup>
diff --git a/src/System.Reflection.Emit.ILGeneration/tests/ILGenerator/Emit4Tests.cs b/src/System.Reflection.Emit.ILGeneration/tests/ILGenerator/Emit4Tests.cs
new file mode 100644
index 0000000000..3002a335f9
--- /dev/null
+++ b/src/System.Reflection.Emit.ILGeneration/tests/ILGenerator/Emit4Tests.cs
@@ -0,0 +1,147 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Linq;
+using System.Runtime.InteropServices;
+using Xunit;
+
+namespace System.Reflection.Emit.Tests
+{
+ public class ILGeneratorEmit4
+ {
+ [Fact]
+ public void TestEmitCalliBlittable()
+ {
+ int a = 1, b = 1, result = 2;
+
+ ModuleBuilder moduleBuilder = Helpers.DynamicModule();
+ TypeBuilder typeBuilder = moduleBuilder.DefineType("T", TypeAttributes.Public);
+ Type returnType = typeof(int);
+
+ MethodBuilder methodBuilder = typeBuilder.DefineMethod("F",
+ MethodAttributes.Public | MethodAttributes.Static, returnType, new Type[] { typeof(IntPtr), typeof(int), typeof(int) });
+ methodBuilder.SetImplementationFlags(MethodImplAttributes.NoInlining);
+
+ ILGenerator il = methodBuilder.GetILGenerator();
+ il.Emit(OpCodes.Ldarg_1);
+ il.Emit(OpCodes.Ldarg_2);
+ il.Emit(OpCodes.Ldarg_0);
+ il.EmitCalli(OpCodes.Calli, CallingConvention.StdCall, returnType, new Type[] { typeof(int), typeof(int) });
+ il.Emit(OpCodes.Ret);
+
+ Type dynamicType = typeBuilder.CreateType();
+
+ var del = new Int32SumStdCall(Int32Sum);
+ IntPtr funcPtr = Marshal.GetFunctionPointerForDelegate(del);
+
+ object resultValue = dynamicType
+ .GetMethod("F", BindingFlags.Public | BindingFlags.Static)
+ .Invoke(null, new object[] { funcPtr, a, b });
+
+ GC.KeepAlive(del);
+
+ Assert.IsType(returnType, resultValue);
+ Assert.Equal(result, resultValue);
+ }
+
+ [Fact]
+ public void TestDynamicMethodEmitCalliBlittable()
+ {
+ int a = 1, b = 1, result = 2;
+
+ Type returnType = typeof(int);
+
+ var dynamicMethod = new DynamicMethod("F", returnType, new Type[] { typeof(IntPtr), typeof(int), typeof(int) });
+
+ ILGenerator il = dynamicMethod.GetILGenerator();
+ il.Emit(OpCodes.Ldarg_1);
+ il.Emit(OpCodes.Ldarg_2);
+ il.Emit(OpCodes.Ldarg_0);
+ il.EmitCalli(OpCodes.Calli, CallingConvention.StdCall, returnType, new Type[] { typeof(int), typeof(int) });
+ il.Emit(OpCodes.Ret);
+
+ var del = new Int32SumStdCall(Int32Sum);
+ IntPtr funcPtr = Marshal.GetFunctionPointerForDelegate(del);
+
+ object resultValue = dynamicMethod
+ .Invoke(null, new object[] { funcPtr, a, b });
+
+ GC.KeepAlive(del);
+
+ Assert.IsType(returnType, resultValue);
+ Assert.Equal(result, resultValue);
+ }
+
+ [Fact]
+ public void TestEmitCalliNonBlittable()
+ {
+ string input = "Test string!", result = "!gnirts tseT";
+
+ ModuleBuilder moduleBuilder = Helpers.DynamicModule();
+ TypeBuilder typeBuilder = moduleBuilder.DefineType("T", TypeAttributes.Public);
+ Type returnType = typeof(string);
+
+ MethodBuilder methodBuilder = typeBuilder.DefineMethod("F",
+ MethodAttributes.Public | MethodAttributes.Static, returnType, new Type[] { typeof(IntPtr), typeof(string) });
+ methodBuilder.SetImplementationFlags(MethodImplAttributes.NoInlining);
+
+ ILGenerator il = methodBuilder.GetILGenerator();
+ il.Emit(OpCodes.Ldarg_1);
+ il.Emit(OpCodes.Ldarg_0);
+ il.EmitCalli(OpCodes.Calli, CallingConvention.Cdecl, returnType, new Type[] { typeof(string) });
+ il.Emit(OpCodes.Ret);
+
+ Type dynamicType = typeBuilder.CreateType();
+
+ var del = new StringReverseCdecl(StringReverse);
+ IntPtr funcPtr = Marshal.GetFunctionPointerForDelegate(del);
+
+ object resultValue = dynamicType
+ .GetMethod("F", BindingFlags.Public | BindingFlags.Static)
+ .Invoke(null, new object[] { funcPtr, input });
+
+ GC.KeepAlive(del);
+
+ Assert.IsType(returnType, resultValue);
+ Assert.Equal(result, resultValue);
+ }
+
+ [Fact]
+ public void TestDynamicMethodEmitCalliNonBlittable()
+ {
+ string input = "Test string!", result = "!gnirts tseT";
+
+ Type returnType = typeof(string);
+
+ var dynamicMethod = new DynamicMethod("F", returnType, new Type[] { typeof(IntPtr), typeof(string) });
+
+ ILGenerator il = dynamicMethod.GetILGenerator();
+ il.Emit(OpCodes.Ldarg_1);
+ il.Emit(OpCodes.Ldarg_0);
+ il.EmitCalli(OpCodes.Calli, CallingConvention.Cdecl, returnType, new Type[] { typeof(string) });
+ il.Emit(OpCodes.Ret);
+
+ var del = new StringReverseCdecl(StringReverse);
+ IntPtr funcPtr = Marshal.GetFunctionPointerForDelegate(del);
+
+ object resultValue = dynamicMethod
+ .Invoke(null, new object[] { funcPtr, input });
+
+ GC.KeepAlive(del);
+
+ Assert.IsType(returnType, resultValue);
+ Assert.Equal(result, resultValue);
+ }
+
+ [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+ private delegate int Int32SumStdCall(int a, int b);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate string StringReverseCdecl(string a);
+
+ private static int Int32Sum(int a, int b) => a + b;
+
+ private static string StringReverse(string a) => string.Join("", a.Reverse());
+ }
+}
diff --git a/src/System.Reflection.Emit.ILGeneration/tests/System.Reflection.Emit.ILGeneration.Tests.csproj b/src/System.Reflection.Emit.ILGeneration/tests/System.Reflection.Emit.ILGeneration.Tests.csproj
index 55be259a78..f4da5f470a 100644
--- a/src/System.Reflection.Emit.ILGeneration/tests/System.Reflection.Emit.ILGeneration.Tests.csproj
+++ b/src/System.Reflection.Emit.ILGeneration/tests/System.Reflection.Emit.ILGeneration.Tests.csproj
@@ -12,6 +12,7 @@
<Compile Include="ILGenerator\Emit1Tests.cs" />
<Compile Include="ILGenerator\Emit2Tests.cs" />
<Compile Include="ILGenerator\Emit3Tests.cs" />
+ <Compile Include="ILGenerator\Emit4Tests.cs" />
<Compile Include="ILGenerator\EmitWriteLineTests.cs" />
<Compile Include="ILGenerator\ExceptionEmitTests.cs" />
<Compile Include="ILGenerator\ILOffsetTests.cs" />
diff --git a/src/System.Reflection.Metadata/pkg/System.Reflection.Metadata.pkgproj b/src/System.Reflection.Metadata/pkg/System.Reflection.Metadata.pkgproj
index d80cfdefce..e73c04ec8b 100644
--- a/src/System.Reflection.Metadata/pkg/System.Reflection.Metadata.pkgproj
+++ b/src/System.Reflection.Metadata/pkg/System.Reflection.Metadata.pkgproj
@@ -1,18 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
- <PropertyGroup>
- <!-- we need to be supported on pre-nuget-3 platforms (Dev12, Dev11, etc) -->
- <MinClientVersion>2.8.6</MinClientVersion>
- </PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\src\System.Reflection.Metadata.csproj">
<SupportedFramework>net45;netcore45;netcoreapp1.0;wpa81;$(AllXamarinFrameworks)</SupportedFramework>
</ProjectReference>
- <FilePackageDependency Include="System.Collections.Immutable">
- <TargetFramework>portable-net45+win8</TargetFramework>
- <Version>1.1.37</Version>
- </FilePackageDependency>
<!-- Since UAP and .NETCoreApp are package based we still want to enable
OOBing libraries that happen to overlap with their framework package.
diff --git a/src/System.Reflection.Metadata/ref/System.Reflection.Metadata.cs b/src/System.Reflection.Metadata/ref/System.Reflection.Metadata.cs
index 93e9e802bb..5fbdd25211 100644
--- a/src/System.Reflection.Metadata/ref/System.Reflection.Metadata.cs
+++ b/src/System.Reflection.Metadata/ref/System.Reflection.Metadata.cs
@@ -84,7 +84,7 @@ namespace System.Reflection.Metadata
{
public readonly partial struct ArrayShape
{
- private readonly int _dummy;
+ private readonly object _dummy;
public ArrayShape(int rank, System.Collections.Immutable.ImmutableArray<int> sizes, System.Collections.Immutable.ImmutableArray<int> lowerBounds) { throw null; }
public System.Collections.Immutable.ImmutableArray<int> LowerBounds { get { throw null; } }
public int Rank { get { throw null; } }
@@ -212,7 +212,7 @@ namespace System.Reflection.Metadata
}
public partial class BlobBuilder
{
- public BlobBuilder(int capacity=256) { }
+ public BlobBuilder(int capacity = 256) { }
protected internal int ChunkCapacity { get { throw null; } }
public int Count { get { throw null; } }
protected int FreeBytes { get { throw null; } }
@@ -267,7 +267,7 @@ namespace System.Reflection.Metadata
public void WriteUserString(string value) { }
public void WriteUTF16(char[] value) { }
public void WriteUTF16(string value) { }
- public void WriteUTF8(string value, bool allowUnpairedSurrogates=true) { }
+ public void WriteUTF8(string value, bool allowUnpairedSurrogates = true) { }
public partial struct Blobs : System.Collections.Generic.IEnumerable<System.Reflection.Metadata.Blob>, System.Collections.Generic.IEnumerator<System.Reflection.Metadata.Blob>, System.Collections.IEnumerable, System.Collections.IEnumerator, System.IDisposable
{
private object _dummy;
@@ -510,7 +510,7 @@ namespace System.Reflection.Metadata
}
public readonly partial struct CustomAttributeValue<TType>
{
- private readonly int _dummy;
+ private readonly object _dummy;
public CustomAttributeValue(System.Collections.Immutable.ImmutableArray<System.Reflection.Metadata.CustomAttributeTypedArgument<TType>> fixedArguments, System.Collections.Immutable.ImmutableArray<System.Reflection.Metadata.CustomAttributeNamedArgument<TType>> namedArguments) { throw null; }
public System.Collections.Immutable.ImmutableArray<System.Reflection.Metadata.CustomAttributeTypedArgument<TType>> FixedArguments { get { throw null; } }
public System.Collections.Immutable.ImmutableArray<System.Reflection.Metadata.CustomAttributeNamedArgument<TType>> NamedArguments { get { throw null; } }
@@ -558,6 +558,7 @@ namespace System.Reflection.Metadata
internal DebugMetadataHeader() { }
public System.Reflection.Metadata.MethodDefinitionHandle EntryPoint { get { throw null; } }
public System.Collections.Immutable.ImmutableArray<byte> Id { get { throw null; } }
+ public int IdStartOffset { get { throw null; } }
}
public readonly partial struct DeclarativeSecurityAttribute
{
@@ -665,7 +666,7 @@ namespace System.Reflection.Metadata
}
public readonly partial struct EventAccessors
{
- private readonly int _dummy;
+ private readonly object _dummy;
public System.Reflection.Metadata.MethodDefinitionHandle Adder { get { throw null; } }
public System.Collections.Immutable.ImmutableArray<System.Reflection.Metadata.MethodDefinitionHandle> Others { get { throw null; } }
public System.Reflection.Metadata.MethodDefinitionHandle Raiser { get { throw null; } }
@@ -1674,11 +1675,11 @@ namespace System.Reflection.Metadata
public void Dispose() { }
public unsafe static System.Reflection.Metadata.MetadataReaderProvider FromMetadataImage(byte* start, int size) { throw null; }
public static System.Reflection.Metadata.MetadataReaderProvider FromMetadataImage(System.Collections.Immutable.ImmutableArray<byte> image) { throw null; }
- public static System.Reflection.Metadata.MetadataReaderProvider FromMetadataStream(System.IO.Stream stream, System.Reflection.Metadata.MetadataStreamOptions options=(System.Reflection.Metadata.MetadataStreamOptions)(0), int size=0) { throw null; }
+ public static System.Reflection.Metadata.MetadataReaderProvider FromMetadataStream(System.IO.Stream stream, System.Reflection.Metadata.MetadataStreamOptions options = (System.Reflection.Metadata.MetadataStreamOptions)(0), int size = 0) { throw null; }
public unsafe static System.Reflection.Metadata.MetadataReaderProvider FromPortablePdbImage(byte* start, int size) { throw null; }
public static System.Reflection.Metadata.MetadataReaderProvider FromPortablePdbImage(System.Collections.Immutable.ImmutableArray<byte> image) { throw null; }
- public static System.Reflection.Metadata.MetadataReaderProvider FromPortablePdbStream(System.IO.Stream stream, System.Reflection.Metadata.MetadataStreamOptions options=(System.Reflection.Metadata.MetadataStreamOptions)(0), int size=0) { throw null; }
- public System.Reflection.Metadata.MetadataReader GetMetadataReader(System.Reflection.Metadata.MetadataReaderOptions options=(System.Reflection.Metadata.MetadataReaderOptions)(1), System.Reflection.Metadata.MetadataStringDecoder utf8Decoder=null) { throw null; }
+ public static System.Reflection.Metadata.MetadataReaderProvider FromPortablePdbStream(System.IO.Stream stream, System.Reflection.Metadata.MetadataStreamOptions options = (System.Reflection.Metadata.MetadataStreamOptions)(0), int size = 0) { throw null; }
+ public System.Reflection.Metadata.MetadataReader GetMetadataReader(System.Reflection.Metadata.MetadataReaderOptions options = (System.Reflection.Metadata.MetadataReaderOptions)(1), System.Reflection.Metadata.MetadataStringDecoder utf8Decoder = null) { throw null; }
}
[System.FlagsAttribute]
public enum MetadataStreamOptions
@@ -2039,7 +2040,7 @@ namespace System.Reflection.Metadata
}
public readonly partial struct PropertyAccessors
{
- private readonly int _dummy;
+ private readonly object _dummy;
public System.Reflection.Metadata.MethodDefinitionHandle Getter { get { throw null; } }
public System.Collections.Immutable.ImmutableArray<System.Reflection.Metadata.MethodDefinitionHandle> Others { get { throw null; } }
public System.Reflection.Metadata.MethodDefinitionHandle Setter { get { throw null; } }
@@ -2276,6 +2277,7 @@ namespace System.Reflection.Metadata
private readonly object _dummy;
public System.Reflection.TypeAttributes Attributes { get { throw null; } }
public System.Reflection.Metadata.EntityHandle BaseType { get { throw null; } }
+ public bool IsNested { get { throw null; } }
public System.Reflection.Metadata.StringHandle Name { get { throw null; } }
public System.Reflection.Metadata.StringHandle Namespace { get { throw null; } }
public System.Reflection.Metadata.NamespaceDefinitionHandle NamespaceDefinition { get { throw null; } }
@@ -2421,11 +2423,11 @@ namespace System.Reflection.Metadata.Ecma335
public void CustomAttributeSignature(out System.Reflection.Metadata.Ecma335.FixedArgumentsEncoder fixedArguments, out System.Reflection.Metadata.Ecma335.CustomAttributeNamedArgumentsEncoder namedArguments) { throw null; }
public System.Reflection.Metadata.Ecma335.SignatureTypeEncoder FieldSignature() { throw null; }
public System.Reflection.Metadata.Ecma335.LocalVariablesEncoder LocalVariableSignature(int variableCount) { throw null; }
- public System.Reflection.Metadata.Ecma335.MethodSignatureEncoder MethodSignature(System.Reflection.Metadata.SignatureCallingConvention convention=(System.Reflection.Metadata.SignatureCallingConvention)(0), int genericParameterCount=0, bool isInstanceMethod=false) { throw null; }
+ public System.Reflection.Metadata.Ecma335.MethodSignatureEncoder MethodSignature(System.Reflection.Metadata.SignatureCallingConvention convention = (System.Reflection.Metadata.SignatureCallingConvention)(0), int genericParameterCount = 0, bool isInstanceMethod = false) { throw null; }
public System.Reflection.Metadata.Ecma335.GenericTypeArgumentsEncoder MethodSpecificationSignature(int genericArgumentCount) { throw null; }
public System.Reflection.Metadata.Ecma335.NamedArgumentsEncoder PermissionSetArguments(int argumentCount) { throw null; }
public System.Reflection.Metadata.Ecma335.PermissionSetEncoder PermissionSetBlob(int attributeCount) { throw null; }
- public System.Reflection.Metadata.Ecma335.MethodSignatureEncoder PropertySignature(bool isInstanceProperty=false) { throw null; }
+ public System.Reflection.Metadata.Ecma335.MethodSignatureEncoder PropertySignature(bool isInstanceProperty = false) { throw null; }
public System.Reflection.Metadata.Ecma335.SignatureTypeEncoder TypeSpecificationSignature() { throw null; }
}
public static partial class CodedIndex
@@ -2522,7 +2524,7 @@ namespace System.Reflection.Metadata.Ecma335
private readonly object _dummy;
public System.Reflection.Metadata.BlobBuilder Builder { get { throw null; } }
public bool HasSmallFormat { get { throw null; } }
- public System.Reflection.Metadata.Ecma335.ExceptionRegionEncoder Add(System.Reflection.Metadata.ExceptionRegionKind kind, int tryOffset, int tryLength, int handlerOffset, int handlerLength, System.Reflection.Metadata.EntityHandle catchType=default(System.Reflection.Metadata.EntityHandle), int filterOffset=0) { throw null; }
+ public System.Reflection.Metadata.Ecma335.ExceptionRegionEncoder Add(System.Reflection.Metadata.ExceptionRegionKind kind, int tryOffset, int tryLength, int handlerOffset, int handlerLength, System.Reflection.Metadata.EntityHandle catchType = default(System.Reflection.Metadata.EntityHandle), int filterOffset = 0) { throw null; }
public System.Reflection.Metadata.Ecma335.ExceptionRegionEncoder AddCatch(int tryOffset, int tryLength, int handlerOffset, int handlerLength, System.Reflection.Metadata.EntityHandle catchType) { throw null; }
public System.Reflection.Metadata.Ecma335.ExceptionRegionEncoder AddFault(int tryOffset, int tryLength, int handlerOffset, int handlerLength) { throw null; }
public System.Reflection.Metadata.Ecma335.ExceptionRegionEncoder AddFilter(int tryOffset, int tryLength, int handlerOffset, int handlerLength, int filterOffset) { throw null; }
@@ -2564,7 +2566,7 @@ namespace System.Reflection.Metadata.Ecma335
public readonly partial struct InstructionEncoder
{
private readonly object _dummy;
- public InstructionEncoder(System.Reflection.Metadata.BlobBuilder codeBuilder, System.Reflection.Metadata.Ecma335.ControlFlowBuilder controlFlowBuilder=null) { throw null; }
+ public InstructionEncoder(System.Reflection.Metadata.BlobBuilder codeBuilder, System.Reflection.Metadata.Ecma335.ControlFlowBuilder controlFlowBuilder = null) { throw null; }
public System.Reflection.Metadata.BlobBuilder CodeBuilder { get { throw null; } }
public System.Reflection.Metadata.Ecma335.ControlFlowBuilder ControlFlowBuilder { get { throw null; } }
public int Offset { get { throw null; } }
@@ -2634,7 +2636,7 @@ namespace System.Reflection.Metadata.Ecma335
public LocalVariableTypeEncoder(System.Reflection.Metadata.BlobBuilder builder) { throw null; }
public System.Reflection.Metadata.BlobBuilder Builder { get { throw null; } }
public System.Reflection.Metadata.Ecma335.CustomModifiersEncoder CustomModifiers() { throw null; }
- public System.Reflection.Metadata.Ecma335.SignatureTypeEncoder Type(bool isByRef=false, bool isPinned=false) { throw null; }
+ public System.Reflection.Metadata.Ecma335.SignatureTypeEncoder Type(bool isByRef = false, bool isPinned = false) { throw null; }
public void TypedReference() { }
}
public sealed partial class MetadataAggregator
@@ -2645,7 +2647,7 @@ namespace System.Reflection.Metadata.Ecma335
}
public sealed partial class MetadataBuilder
{
- public MetadataBuilder(int userStringHeapStartOffset=0, int stringHeapStartOffset=0, int blobHeapStartOffset=0, int guidHeapStartOffset=0) { }
+ public MetadataBuilder(int userStringHeapStartOffset = 0, int stringHeapStartOffset = 0, int blobHeapStartOffset = 0, int guidHeapStartOffset = 0) { }
public System.Reflection.Metadata.AssemblyDefinitionHandle AddAssembly(System.Reflection.Metadata.StringHandle name, System.Version version, System.Reflection.Metadata.StringHandle culture, System.Reflection.Metadata.BlobHandle publicKey, System.Reflection.AssemblyFlags flags, System.Reflection.AssemblyHashAlgorithm hashAlgorithm) { throw null; }
public System.Reflection.Metadata.AssemblyFileHandle AddAssemblyFile(System.Reflection.Metadata.StringHandle name, System.Reflection.Metadata.BlobHandle hashValue, bool containsMetadata) { throw null; }
public System.Reflection.Metadata.AssemblyReferenceHandle AddAssemblyReference(System.Reflection.Metadata.StringHandle name, System.Version version, System.Reflection.Metadata.StringHandle culture, System.Reflection.Metadata.BlobHandle publicKeyOrToken, System.Reflection.AssemblyFlags flags, System.Reflection.Metadata.BlobHandle hashValue) { throw null; }
@@ -2694,7 +2696,7 @@ namespace System.Reflection.Metadata.Ecma335
public System.Reflection.Metadata.BlobHandle GetOrAddBlob(System.Collections.Immutable.ImmutableArray<byte> value) { throw null; }
public System.Reflection.Metadata.BlobHandle GetOrAddBlob(System.Reflection.Metadata.BlobBuilder value) { throw null; }
public System.Reflection.Metadata.BlobHandle GetOrAddBlobUTF16(string value) { throw null; }
- public System.Reflection.Metadata.BlobHandle GetOrAddBlobUTF8(string value, bool allowUnpairedSurrogates=true) { throw null; }
+ public System.Reflection.Metadata.BlobHandle GetOrAddBlobUTF8(string value, bool allowUnpairedSurrogates = true) { throw null; }
public System.Reflection.Metadata.BlobHandle GetOrAddConstantBlob(object value) { throw null; }
public System.Reflection.Metadata.BlobHandle GetOrAddDocumentName(string value) { throw null; }
public System.Reflection.Metadata.GuidHandle GetOrAddGuid(System.Guid guid) { throw null; }
@@ -2725,7 +2727,7 @@ namespace System.Reflection.Metadata.Ecma335
}
public sealed partial class MetadataRootBuilder
{
- public MetadataRootBuilder(System.Reflection.Metadata.Ecma335.MetadataBuilder tablesAndHeaps, string metadataVersion=null, bool suppressValidation=false) { }
+ public MetadataRootBuilder(System.Reflection.Metadata.Ecma335.MetadataBuilder tablesAndHeaps, string metadataVersion = null, bool suppressValidation = false) { }
public string MetadataVersion { get { throw null; } }
public System.Reflection.Metadata.Ecma335.MetadataSizes Sizes { get { throw null; } }
public bool SuppressValidation { get { throw null; } }
@@ -2808,8 +2810,10 @@ namespace System.Reflection.Metadata.Ecma335
private readonly object _dummy;
public MethodBodyStreamEncoder(System.Reflection.Metadata.BlobBuilder builder) { throw null; }
public System.Reflection.Metadata.BlobBuilder Builder { get { throw null; } }
- public System.Reflection.Metadata.Ecma335.MethodBodyStreamEncoder.MethodBody AddMethodBody(int codeSize, int maxStack=8, int exceptionRegionCount=0, bool hasSmallExceptionRegions=true, System.Reflection.Metadata.StandaloneSignatureHandle localVariablesSignature=default(System.Reflection.Metadata.StandaloneSignatureHandle), System.Reflection.Metadata.Ecma335.MethodBodyAttributes attributes=(System.Reflection.Metadata.Ecma335.MethodBodyAttributes)(1)) { throw null; }
- public int AddMethodBody(System.Reflection.Metadata.Ecma335.InstructionEncoder instructionEncoder, int maxStack=8, System.Reflection.Metadata.StandaloneSignatureHandle localVariablesSignature=default(System.Reflection.Metadata.StandaloneSignatureHandle), System.Reflection.Metadata.Ecma335.MethodBodyAttributes attributes=(System.Reflection.Metadata.Ecma335.MethodBodyAttributes)(1)) { throw null; }
+ public System.Reflection.Metadata.Ecma335.MethodBodyStreamEncoder.MethodBody AddMethodBody(int codeSize, int maxStack, int exceptionRegionCount, bool hasSmallExceptionRegions, System.Reflection.Metadata.StandaloneSignatureHandle localVariablesSignature, System.Reflection.Metadata.Ecma335.MethodBodyAttributes attributes) { throw null; }
+ public System.Reflection.Metadata.Ecma335.MethodBodyStreamEncoder.MethodBody AddMethodBody(int codeSize, int maxStack = 8, int exceptionRegionCount = 0, bool hasSmallExceptionRegions = true, System.Reflection.Metadata.StandaloneSignatureHandle localVariablesSignature = default(System.Reflection.Metadata.StandaloneSignatureHandle), System.Reflection.Metadata.Ecma335.MethodBodyAttributes attributes = (System.Reflection.Metadata.Ecma335.MethodBodyAttributes)(1), bool hasDynamicStackAllocation = false) { throw null; }
+ public int AddMethodBody(System.Reflection.Metadata.Ecma335.InstructionEncoder instructionEncoder, int maxStack, System.Reflection.Metadata.StandaloneSignatureHandle localVariablesSignature, System.Reflection.Metadata.Ecma335.MethodBodyAttributes attributes) { throw null; }
+ public int AddMethodBody(System.Reflection.Metadata.Ecma335.InstructionEncoder instructionEncoder, int maxStack = 8, System.Reflection.Metadata.StandaloneSignatureHandle localVariablesSignature = default(System.Reflection.Metadata.StandaloneSignatureHandle), System.Reflection.Metadata.Ecma335.MethodBodyAttributes attributes = (System.Reflection.Metadata.Ecma335.MethodBodyAttributes)(1), bool hasDynamicStackAllocation = false) { throw null; }
public readonly partial struct MethodBody
{
private readonly object _dummy;
@@ -2854,7 +2858,7 @@ namespace System.Reflection.Metadata.Ecma335
public readonly partial struct ParametersEncoder
{
private readonly object _dummy;
- public ParametersEncoder(System.Reflection.Metadata.BlobBuilder builder, bool hasVarArgs=false) { throw null; }
+ public ParametersEncoder(System.Reflection.Metadata.BlobBuilder builder, bool hasVarArgs = false) { throw null; }
public System.Reflection.Metadata.BlobBuilder Builder { get { throw null; } }
public bool HasVarArgs { get { throw null; } }
public System.Reflection.Metadata.Ecma335.ParameterTypeEncoder AddParameter() { throw null; }
@@ -2866,7 +2870,7 @@ namespace System.Reflection.Metadata.Ecma335
public ParameterTypeEncoder(System.Reflection.Metadata.BlobBuilder builder) { throw null; }
public System.Reflection.Metadata.BlobBuilder Builder { get { throw null; } }
public System.Reflection.Metadata.Ecma335.CustomModifiersEncoder CustomModifiers() { throw null; }
- public System.Reflection.Metadata.Ecma335.SignatureTypeEncoder Type(bool isByRef=false) { throw null; }
+ public System.Reflection.Metadata.Ecma335.SignatureTypeEncoder Type(bool isByRef = false) { throw null; }
public void TypedReference() { }
}
public readonly partial struct PermissionSetEncoder
@@ -2879,7 +2883,7 @@ namespace System.Reflection.Metadata.Ecma335
}
public sealed partial class PortablePdbBuilder
{
- public PortablePdbBuilder(System.Reflection.Metadata.Ecma335.MetadataBuilder tablesAndHeaps, System.Collections.Immutable.ImmutableArray<int> typeSystemRowCounts, System.Reflection.Metadata.MethodDefinitionHandle entryPoint, System.Func<System.Collections.Generic.IEnumerable<System.Reflection.Metadata.Blob>, System.Reflection.Metadata.BlobContentId> idProvider=null) { }
+ public PortablePdbBuilder(System.Reflection.Metadata.Ecma335.MetadataBuilder tablesAndHeaps, System.Collections.Immutable.ImmutableArray<int> typeSystemRowCounts, System.Reflection.Metadata.MethodDefinitionHandle entryPoint, System.Func<System.Collections.Generic.IEnumerable<System.Reflection.Metadata.Blob>, System.Reflection.Metadata.BlobContentId> idProvider = null) { }
public ushort FormatVersion { get { throw null; } }
public System.Func<System.Collections.Generic.IEnumerable<System.Reflection.Metadata.Blob>, System.Reflection.Metadata.BlobContentId> IdProvider { get { throw null; } }
public string MetadataVersion { get { throw null; } }
@@ -2891,7 +2895,7 @@ namespace System.Reflection.Metadata.Ecma335
public ReturnTypeEncoder(System.Reflection.Metadata.BlobBuilder builder) { throw null; }
public System.Reflection.Metadata.BlobBuilder Builder { get { throw null; } }
public System.Reflection.Metadata.Ecma335.CustomModifiersEncoder CustomModifiers() { throw null; }
- public System.Reflection.Metadata.Ecma335.SignatureTypeEncoder Type(bool isByRef=false) { throw null; }
+ public System.Reflection.Metadata.Ecma335.SignatureTypeEncoder Type(bool isByRef = false) { throw null; }
public void TypedReference() { }
public void Void() { }
}
@@ -2912,7 +2916,7 @@ namespace System.Reflection.Metadata.Ecma335
public System.Collections.Immutable.ImmutableArray<TType> DecodeLocalSignature(ref System.Reflection.Metadata.BlobReader blobReader) { throw null; }
public System.Reflection.Metadata.MethodSignature<TType> DecodeMethodSignature(ref System.Reflection.Metadata.BlobReader blobReader) { throw null; }
public System.Collections.Immutable.ImmutableArray<TType> DecodeMethodSpecificationSignature(ref System.Reflection.Metadata.BlobReader blobReader) { throw null; }
- public TType DecodeType(ref System.Reflection.Metadata.BlobReader blobReader, bool allowTypeSpecifications=false) { throw null; }
+ public TType DecodeType(ref System.Reflection.Metadata.BlobReader blobReader, bool allowTypeSpecifications = false) { throw null; }
}
public readonly partial struct SignatureTypeEncoder
{
@@ -2926,7 +2930,7 @@ namespace System.Reflection.Metadata.Ecma335
public void Char() { }
public System.Reflection.Metadata.Ecma335.CustomModifiersEncoder CustomModifiers() { throw null; }
public void Double() { }
- public System.Reflection.Metadata.Ecma335.MethodSignatureEncoder FunctionPointer(System.Reflection.Metadata.SignatureCallingConvention convention=(System.Reflection.Metadata.SignatureCallingConvention)(0), System.Reflection.Metadata.Ecma335.FunctionPointerAttributes attributes=(System.Reflection.Metadata.Ecma335.FunctionPointerAttributes)(0), int genericParameterCount=0) { throw null; }
+ public System.Reflection.Metadata.Ecma335.MethodSignatureEncoder FunctionPointer(System.Reflection.Metadata.SignatureCallingConvention convention = (System.Reflection.Metadata.SignatureCallingConvention)(0), System.Reflection.Metadata.Ecma335.FunctionPointerAttributes attributes = (System.Reflection.Metadata.Ecma335.FunctionPointerAttributes)(0), int genericParameterCount = 0) { throw null; }
public System.Reflection.Metadata.Ecma335.GenericTypeArgumentsEncoder GenericInstantiation(System.Reflection.Metadata.EntityHandle genericType, int genericArgumentCount, bool isValueType) { throw null; }
public void GenericMethodTypeParameter(int parameterIndex) { }
public void GenericTypeParameter(int parameterIndex) { }
@@ -3081,6 +3085,9 @@ namespace System.Reflection.PortableExecutable
public DebugDirectoryBuilder() { }
public void AddCodeViewEntry(string pdbPath, System.Reflection.Metadata.BlobContentId pdbContentId, ushort portablePdbVersion) { }
public void AddEmbeddedPortablePdbEntry(System.Reflection.Metadata.BlobBuilder debugMetadata, ushort portablePdbVersion) { }
+ public void AddEntry(System.Reflection.PortableExecutable.DebugDirectoryEntryType type, uint version, uint stamp) { }
+ public void AddEntry<TData>(System.Reflection.PortableExecutable.DebugDirectoryEntryType type, uint version, uint stamp, TData data, System.Action<System.Reflection.Metadata.BlobBuilder, TData> dataSerializer) { }
+ public void AddPdbChecksumEntry(string algorithmName, System.Collections.Immutable.ImmutableArray<byte> checksum) { }
public void AddReproducibleEntry() { }
}
public readonly partial struct DebugDirectoryEntry
@@ -3101,6 +3108,7 @@ namespace System.Reflection.PortableExecutable
CodeView = 2,
Coff = 1,
EmbeddedPortablePdb = 17,
+ PdbChecksum = 19,
Reproducible = 16,
Unknown = 0,
}
@@ -3134,6 +3142,7 @@ namespace System.Reflection.PortableExecutable
AM33 = (ushort)467,
Amd64 = (ushort)34404,
Arm = (ushort)448,
+ Arm64 = (ushort)43620,
ArmThumb2 = (ushort)452,
Ebc = (ushort)3772,
I386 = (ushort)332,
@@ -3158,12 +3167,18 @@ namespace System.Reflection.PortableExecutable
{
public const int ManagedResourcesDataAlignment = 8;
public const int MappedFieldDataAlignment = 8;
- public ManagedPEBuilder(System.Reflection.PortableExecutable.PEHeaderBuilder header, System.Reflection.Metadata.Ecma335.MetadataRootBuilder metadataRootBuilder, System.Reflection.Metadata.BlobBuilder ilStream, System.Reflection.Metadata.BlobBuilder mappedFieldData=null, System.Reflection.Metadata.BlobBuilder managedResources=null, System.Reflection.PortableExecutable.ResourceSectionBuilder nativeResources=null, System.Reflection.PortableExecutable.DebugDirectoryBuilder debugDirectoryBuilder=null, int strongNameSignatureSize=128, System.Reflection.Metadata.MethodDefinitionHandle entryPoint=default(System.Reflection.Metadata.MethodDefinitionHandle), System.Reflection.PortableExecutable.CorFlags flags=(System.Reflection.PortableExecutable.CorFlags)(1), System.Func<System.Collections.Generic.IEnumerable<System.Reflection.Metadata.Blob>, System.Reflection.Metadata.BlobContentId> deterministicIdProvider=null) : base (default(System.Reflection.PortableExecutable.PEHeaderBuilder), default(System.Func<System.Collections.Generic.IEnumerable<System.Reflection.Metadata.Blob>, System.Reflection.Metadata.BlobContentId>)) { }
+ public ManagedPEBuilder(System.Reflection.PortableExecutable.PEHeaderBuilder header, System.Reflection.Metadata.Ecma335.MetadataRootBuilder metadataRootBuilder, System.Reflection.Metadata.BlobBuilder ilStream, System.Reflection.Metadata.BlobBuilder mappedFieldData = null, System.Reflection.Metadata.BlobBuilder managedResources = null, System.Reflection.PortableExecutable.ResourceSectionBuilder nativeResources = null, System.Reflection.PortableExecutable.DebugDirectoryBuilder debugDirectoryBuilder = null, int strongNameSignatureSize = 128, System.Reflection.Metadata.MethodDefinitionHandle entryPoint = default(System.Reflection.Metadata.MethodDefinitionHandle), System.Reflection.PortableExecutable.CorFlags flags = (System.Reflection.PortableExecutable.CorFlags)(1), System.Func<System.Collections.Generic.IEnumerable<System.Reflection.Metadata.Blob>, System.Reflection.Metadata.BlobContentId> deterministicIdProvider = null) : base (default(System.Reflection.PortableExecutable.PEHeaderBuilder), default(System.Func<System.Collections.Generic.IEnumerable<System.Reflection.Metadata.Blob>, System.Reflection.Metadata.BlobContentId>)) { }
protected override System.Collections.Immutable.ImmutableArray<System.Reflection.PortableExecutable.PEBuilder.Section> CreateSections() { throw null; }
protected internal override System.Reflection.PortableExecutable.PEDirectoriesBuilder GetDirectories() { throw null; }
protected override System.Reflection.Metadata.BlobBuilder SerializeSection(string name, System.Reflection.PortableExecutable.SectionLocation location) { throw null; }
public void Sign(System.Reflection.Metadata.BlobBuilder peImage, System.Func<System.Collections.Generic.IEnumerable<System.Reflection.Metadata.Blob>, byte[]> signatureProvider) { }
}
+ public readonly partial struct PdbChecksumDebugDirectoryData
+ {
+ private readonly object _dummy;
+ public string AlgorithmName { get { throw null; } }
+ public System.Collections.Immutable.ImmutableArray<byte> Checksum { get { throw null; } }
+ }
public abstract partial class PEBuilder
{
protected PEBuilder(System.Reflection.PortableExecutable.PEHeaderBuilder header, System.Func<System.Collections.Generic.IEnumerable<System.Reflection.Metadata.Blob>, System.Reflection.Metadata.BlobContentId> deterministicIdProvider) { }
@@ -3250,7 +3265,7 @@ namespace System.Reflection.PortableExecutable
}
public sealed partial class PEHeaderBuilder
{
- public PEHeaderBuilder(System.Reflection.PortableExecutable.Machine machine=(System.Reflection.PortableExecutable.Machine)(0), int sectionAlignment=8192, int fileAlignment=512, ulong imageBase=(ulong)4194304, byte majorLinkerVersion=(byte)48, byte minorLinkerVersion=(byte)0, ushort majorOperatingSystemVersion=(ushort)4, ushort minorOperatingSystemVersion=(ushort)0, ushort majorImageVersion=(ushort)0, ushort minorImageVersion=(ushort)0, ushort majorSubsystemVersion=(ushort)4, ushort minorSubsystemVersion=(ushort)0, System.Reflection.PortableExecutable.Subsystem subsystem=(System.Reflection.PortableExecutable.Subsystem)(3), System.Reflection.PortableExecutable.DllCharacteristics dllCharacteristics=(System.Reflection.PortableExecutable.DllCharacteristics)(34112), System.Reflection.PortableExecutable.Characteristics imageCharacteristics=(System.Reflection.PortableExecutable.Characteristics)(8192), ulong sizeOfStackReserve=(ulong)1048576, ulong sizeOfStackCommit=(ulong)4096, ulong sizeOfHeapReserve=(ulong)1048576, ulong sizeOfHeapCommit=(ulong)4096) { }
+ public PEHeaderBuilder(System.Reflection.PortableExecutable.Machine machine = (System.Reflection.PortableExecutable.Machine)(0), int sectionAlignment = 8192, int fileAlignment = 512, ulong imageBase = (ulong)4194304, byte majorLinkerVersion = (byte)48, byte minorLinkerVersion = (byte)0, ushort majorOperatingSystemVersion = (ushort)4, ushort minorOperatingSystemVersion = (ushort)0, ushort majorImageVersion = (ushort)0, ushort minorImageVersion = (ushort)0, ushort majorSubsystemVersion = (ushort)4, ushort minorSubsystemVersion = (ushort)0, System.Reflection.PortableExecutable.Subsystem subsystem = (System.Reflection.PortableExecutable.Subsystem)(3), System.Reflection.PortableExecutable.DllCharacteristics dllCharacteristics = (System.Reflection.PortableExecutable.DllCharacteristics)(34112), System.Reflection.PortableExecutable.Characteristics imageCharacteristics = (System.Reflection.PortableExecutable.Characteristics)(8192), ulong sizeOfStackReserve = (ulong)1048576, ulong sizeOfStackCommit = (ulong)4096, ulong sizeOfHeapReserve = (ulong)1048576, ulong sizeOfHeapCommit = (ulong)4096) { }
public System.Reflection.PortableExecutable.DllCharacteristics DllCharacteristics { get { throw null; } }
public int FileAlignment { get { throw null; } }
public ulong ImageBase { get { throw null; } }
@@ -3329,6 +3344,7 @@ namespace System.Reflection.PortableExecutable
public System.Reflection.PortableExecutable.CodeViewDebugDirectoryData ReadCodeViewDebugDirectoryData(System.Reflection.PortableExecutable.DebugDirectoryEntry entry) { throw null; }
public System.Collections.Immutable.ImmutableArray<System.Reflection.PortableExecutable.DebugDirectoryEntry> ReadDebugDirectory() { throw null; }
public System.Reflection.Metadata.MetadataReaderProvider ReadEmbeddedPortablePdbDebugDirectoryData(System.Reflection.PortableExecutable.DebugDirectoryEntry entry) { throw null; }
+ public System.Reflection.PortableExecutable.PdbChecksumDebugDirectoryData ReadPdbChecksumDebugDirectoryData(System.Reflection.PortableExecutable.DebugDirectoryEntry entry) { throw null; }
public bool TryOpenAssociatedPortablePdb(string peImagePath, System.Func<string, System.IO.Stream> pdbFileStreamProvider, out System.Reflection.Metadata.MetadataReaderProvider pdbReaderProvider, out string pdbPath) { throw null; }
}
[System.FlagsAttribute]
diff --git a/src/System.Reflection.Metadata/specs/PE-COFF.md b/src/System.Reflection.Metadata/specs/PE-COFF.md
index eb19faef3b..6907430715 100644
--- a/src/System.Reflection.Metadata/specs/PE-COFF.md
+++ b/src/System.Reflection.Metadata/specs/PE-COFF.md
@@ -14,7 +14,7 @@ PE/COFF Specification defines the structure of Debug Directory in section 5.1.1.
### CodeView Debug Directory Entry (type 2)
-*Version Major=0, Minor=0* of the data format:
+<a name="WindowsCodeViewEntry"></a>*Version Major=0, Minor=0* of the data format:
| Offset | Size | Field | Description |
|:-------|:-----|:---------------|----------------------------------------------------------------|
@@ -27,9 +27,9 @@ Guid and Age are used to match PE/COFF image with the associated PDB.
The associated .pdb file may not exist at the path indicated by Path field. If it doesn't the Path, Guid and Age can be used to find the corresponding PDB file locally or on a symbol server. The exact search algorithm used by tools to locate the PDB depends on the tool and its configuration.
-If the containing PE/COFF file is deterministic the Guid field above and DateTimeStamp field of the directory entry are calculated deterministically based solely on the content of the associated .pdb file. Otherwise the value of Guid is random and the value of DateTimeStamp indicates the time and date that the debug data was created.
+If the containing PE/COFF file is deterministic the Guid field above and DateTimeStamp field of the directory entry are calculated deterministically based solely on the content of the associated .pdb file. Otherwise the value of Guid is random and the value of DateTimeStamp indicates the time and date that the debug data was created.
-*Version Major=any, Minor=0x504d* of the data format has the same structure as above. The Age shall be 1. The format of the .pdb file that this PE/COFF file was built with is Portable PDB. The Major version specified in the entry indicates the version of the Portable PDB format. Together 16B of the Guid concatenated with 4B of the TimeDateStamp field of the entry form a PDB ID that should be used to match the PE/COFF image with the associated PDB (instead of Guid and Age). Matching PDB ID is stored in the #Pdb stream of the .pdb file.
+<a name="PortableCodeViewEntry"></a> *Version Major=any, Minor=0x504d* of the data format has the same structure as above. The Age shall be 1. The format of the .pdb file that this PE/COFF file was built with is Portable PDB. The Major version specified in the entry indicates the version of the Portable PDB format. Together 16B of the Guid concatenated with 4B of the TimeDateStamp field of the entry form a PDB ID that should be used to match the PE/COFF image with the associated PDB (instead of Guid and Age). Matching PDB ID is stored in the #Pdb stream of the .pdb file.
> A matching PDB may be found whose format is different than the format of the PDB the PE/COFF file was built with. This may happen when the original PDB file is [converted](http://github.com/dotnet/symreader-converter) to the other format without updating the PE/COFF file. This scenario is fully supported. A tool looking for the associated PDB shall determine the actual format of the found PDB based on the signature at the start of the PDB file. The tool may use the version in CodeView entry as a hint to prefer the original format over the converted one if both are available.
@@ -65,3 +65,45 @@ UncompressedSize shall be greater than 0. Other values are reserved for future u
The Major version specified in the entry indicates the version of the Portable PDB format. The Minor version indicates the version of the Embedded Portable PDB data format.
The value of Stamp field in the entry shall be 0.
+
+### PDB Checksum Debug Directory Entry (type 19)
+
+Stores crypto hash of the content of the symbol file the PE/COFF file was built with.
+
+The hash can be used to validate that a given PDB file was built with the PE/COFF file and not altered in any way.
+
+More than one entry can be present, in case multiple PDBs were produced during the build of the PE/COFF file (e.g. private and public symbols).
+
+*Version Major=0x0001, Minor=0x0000* of the entry data format is following:
+
+| Offset | Size | Field | Description |
+|:--------------|:--------------|:---------------|-------------------------------------------------------------------------|
+| 0 | AlgNameLength | AlgorithmName | Zero-terminated UTF8 string. The name of the crypho hash algorithm. |
+| AlgNameLength | ChecksumSize | Checksum | Blob. Checksum of the PDB content. |
+
+_AlgorithmName_ is the name of the crypto hash algorithm used to calculate the checksum. The name is case-sensitive.
+
+Supported algorithm names include at least:
+
+| AlgorithmName | ChecksumSize | Description |
+|:--------------|:-------------|:-------------------------------------------------------------------|
+| `SHA256` | 32 | The 256-bit secure hash algorithm. Standard: FIPS 180-2, FIPS 198. |
+| `SHA384` | 48 | The 384-bit secure hash algorithm. Standard: FIPS 180-2, FIPS 198. |
+| `SHA512` | 64 | The 512-bit secure hash algorithm. Standard: FIPS 180-2, FIPS 198. |
+
+#### Portable PDB Checksum
+
+If the symbol format is Portable PDB the checksum is calculated by hashing the entire content of the PDB file with the PDB ID set to 0 (20 zeroed bytes).
+
+When validating that Portable PDB matches the debug directory record check that the checksums match and that the PDB ID match the data in the corresponding [Portable CodeView record](#PortableCodeViewEntry).
+
+> Excluding the PDB ID allows the compiler to calculate a single hash of the PDB file content and use it to generate both deterministic PDB ID and PDB checksum.
+
+#### Windows PDB Checksum
+
+If the symbol format is Windows PDB the checksum is calculated by hashing the entire content of the PDB file with the PDB signature comprising of 16B GUID and 4B timestamp zeroed.
+
+When validating that Windows PDB matches the debug directory record check that the checksums match and that the PDB signature (both GUID and timestamp values) match the data in the corresponding [CodeView record](#WindowsCodeViewEntry).
+
+> Note that when the debugger (or other tool) searches for the PDB only GUID and Age fields are used to match the PDB, but the timestamp of the CodeView debug directory entry does not need to match the timestamp stored in the PDB. Therefore, to verify byte-for-byte identity of the PDB, the timestamp field should also be checked.
+
diff --git a/src/System.Reflection.Metadata/src/Resources/Strings.resx b/src/System.Reflection.Metadata/src/Resources/Strings.resx
index 2a75ca3a5a..879ad7ced2 100644
--- a/src/System.Reflection.Metadata/src/Resources/Strings.resx
+++ b/src/System.Reflection.Metadata/src/Resources/Strings.resx
@@ -280,6 +280,9 @@
<data name="UnexpectedEmbeddedPortablePdbDataSignature" xml:space="preserve">
<value>Unexpected Embedded Portable PDB data signature value.</value>
</data>
+ <data name="InvalidPdbChecksumDataFormat" xml:space="preserve">
+ <value>Invalid PDB Checksum data format.</value>
+ </data>
<data name="UnexpectedSignatureHeader" xml:space="preserve">
<value>Expected signature header for '{0}', but found '{1}' (0x{2:x2}).</value>
</data>
@@ -340,6 +343,9 @@
<data name="ExpectedNonEmptyList" xml:space="preserve">
<value>Expected non-empty list.</value>
</data>
+ <data name="ExpectedNonEmptyArray" xml:space="preserve">
+ <value>Expected non-empty array.</value>
+ </data>
<data name="ExpectedNonEmptyString" xml:space="preserve">
<value>Expected non-empty string.</value>
</data>
diff --git a/src/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj b/src/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj
index e75d7ef1bc..773637ee93 100644
--- a/src/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj
+++ b/src/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj
@@ -81,6 +81,7 @@
<Compile Include="System\Reflection\PortableExecutable\PEBuilder.cs" />
<Compile Include="System\Reflection\PortableExecutable\DebugDirectory\DebugDirectoryBuilder.cs" />
<Compile Include="System\Reflection\PortableExecutable\DebugDirectory\DebugDirectoryBuilder.EmbeddedPortablePdb.cs" />
+ <Compile Include="System\Reflection\PortableExecutable\DebugDirectory\PdbChecksumDebugDirectoryData.cs" />
<Compile Include="System\Reflection\PortableExecutable\PEDirectoriesBuilder.cs" />
<Compile Include="System\Reflection\PortableExecutable\PEHeaderBuilder.cs" />
<Compile Include="System\Reflection\PortableExecutable\ResourceSectionBuilder.cs" />
diff --git a/src/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/PathUtilities.cs b/src/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/PathUtilities.cs
index 806e0c81ae..2d7b1416e6 100644
--- a/src/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/PathUtilities.cs
+++ b/src/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/PathUtilities.cs
@@ -56,7 +56,7 @@ namespace System.Reflection.Metadata
/// <summary>
/// Get file name from path.
/// </summary>
- /// <remarks>Unlike <see cref="System.IO.Path.GetFileName"/> doesn't check for invalid path characters.</remarks>
+ /// <remarks>Unlike <see cref="System.IO.Path.GetFileName(string)"/> this method doesn't check for invalid path characters.</remarks>
internal static string GetFileName(string path, bool includeExtension = true)
{
int fileNameStart = IndexOfFileName(path);
diff --git a/src/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/Encoding/ControlFlowBuilder.cs b/src/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/Encoding/ControlFlowBuilder.cs
index d839cba5ab..07800c14d3 100644
--- a/src/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/Encoding/ControlFlowBuilder.cs
+++ b/src/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/Encoding/ControlFlowBuilder.cs
@@ -27,25 +27,27 @@ namespace System.Reflection.Metadata.Ecma335
_opCode = (byte)opCode;
}
- internal bool IsShortBranchDistance(ImmutableArray<int>.Builder labels, out int distance)
+ internal int GetBranchDistance(ImmutableArray<int>.Builder labels, ILOpCode branchOpCode, int branchILOffset, bool isShortBranch)
{
- const int shortBranchSize = 2;
- const int longBranchSize = 5;
-
int labelTargetOffset = labels[Label.Id - 1];
if (labelTargetOffset < 0)
{
Throw.InvalidOperation_LabelNotMarked(Label.Id);
}
- distance = labelTargetOffset - (ILOffset + shortBranchSize);
- if (unchecked((sbyte)distance) == distance)
+ int branchInstructionSize = 1 + (isShortBranch ? sizeof(sbyte) : sizeof(int));
+ int distance = labelTargetOffset - (ILOffset + branchInstructionSize);
+
+ if (isShortBranch && unchecked((sbyte)distance) != distance)
{
- return true;
+ // We could potentially implement algorithm that automatically fixes up branch instructions to accomodate for bigger distances (short vs long),
+ // however an optimal algorithm would be rather complex (something like: calculate topological ordering of crossing branch instructions
+ // and then use fixed point to eliminate cycles). If the caller doesn't care about optimal IL size they can use long branches whenever the
+ // distance is unknown upfront. If they do they probably implement more sophisticated algorithm for IL layout optimization already.
+ throw new InvalidOperationException(SR.Format(SR.DistanceBetweenInstructionAndLabelTooBig, branchOpCode, branchILOffset, distance));
}
- distance = labelTargetOffset - (ILOffset + longBranchSize);
- return false;
+ return distance;
}
}
@@ -279,19 +281,9 @@ namespace System.Reflection.Metadata.Ecma335
// write branch opcode:
dstBuilder.WriteByte(srcBlob.Buffer[srcBlobOffset]);
+ int branchDistance = branch.GetBranchDistance(_labels, branch.OpCode, srcOffset, isShortInstruction);
+
// write branch operand:
- int branchDistance;
- bool isShortDistance = branch.IsShortBranchDistance(_labels, out branchDistance);
-
- if (isShortInstruction && !isShortDistance)
- {
- // We could potentially implement algortihm that automatically fixes up the branch instructions as well to accomodate bigger distances,
- // however an optimal algorithm would be rather complex (something like: calculate topological ordering of crossing branch instructions
- // and then use fixed point to eliminate cycles). If the caller doesn't care about optimal IL size they can use long branches whenever the
- // distance is unknown upfront. If they do they probably already implement more sophisticad algorithm for IL layout optimization already.
- throw new InvalidOperationException(SR.Format(SR.DistanceBetweenInstructionAndLabelTooBig, branch.OpCode, srcOffset, branchDistance));
- }
-
if (isShortInstruction)
{
dstBuilder.WriteSByte((sbyte)branchDistance);
@@ -307,7 +299,7 @@ namespace System.Reflection.Metadata.Ecma335
branchIndex++;
if (branchIndex == _branches.Count)
{
- branch = new BranchInfo(int.MaxValue, default(LabelHandle), 0);
+ branch = new BranchInfo(int.MaxValue, label: default, opCode: default);
}
else
{
diff --git a/src/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/Encoding/MethodBodyAttributes.cs b/src/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/Encoding/MethodBodyAttributes.cs
index f30744ec0f..e63b7952cb 100644
--- a/src/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/Encoding/MethodBodyAttributes.cs
+++ b/src/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/Encoding/MethodBodyAttributes.cs
@@ -4,10 +4,20 @@
namespace System.Reflection.Metadata.Ecma335
{
+ /// <summary>
+ /// Method body attributes.
+ /// </summary>
[Flags]
public enum MethodBodyAttributes
{
+ /// <summary>
+ /// No local memory initialization is performed.
+ /// </summary>
None = 0,
+
+ /// <summary>
+ /// Zero-initialize any locals the method defines and dynamically allocated local memory.
+ /// </summary>
InitLocals = 1,
}
}
diff --git a/src/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/Encoding/MethodBodyStreamEncoder.cs b/src/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/Encoding/MethodBodyStreamEncoder.cs
index 1c97e2bc3b..29121bd4b8 100644
--- a/src/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/Encoding/MethodBodyStreamEncoder.cs
+++ b/src/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/Encoding/MethodBodyStreamEncoder.cs
@@ -45,11 +45,35 @@ namespace System.Reflection.Metadata.Ecma335
/// </exception>
public MethodBody AddMethodBody(
int codeSize,
+ int maxStack,
+ int exceptionRegionCount,
+ bool hasSmallExceptionRegions,
+ StandaloneSignatureHandle localVariablesSignature,
+ MethodBodyAttributes attributes)
+ => AddMethodBody(codeSize, maxStack, exceptionRegionCount, hasSmallExceptionRegions, localVariablesSignature, attributes, hasDynamicStackAllocation: false);
+
+ /// <summary>
+ /// Encodes a method body and adds it to the method body stream.
+ /// </summary>
+ /// <param name="codeSize">Number of bytes to be reserved for instructions.</param>
+ /// <param name="maxStack">Max stack.</param>
+ /// <param name="exceptionRegionCount">Number of exception regions.</param>
+ /// <param name="hasSmallExceptionRegions">True if the exception regions should be encoded in 'small' format.</param>
+ /// <param name="localVariablesSignature">Local variables signature handle.</param>
+ /// <param name="attributes">Attributes.</param>
+ /// <param name="hasDynamicStackAllocation">True if the method allocates from dynamic local memory pool (<c>localloc</c> instruction).</param>
+ /// <returns>The offset of the encoded body within the method body stream.</returns>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="codeSize"/>, <paramref name="exceptionRegionCount"/>, or <paramref name="maxStack"/> is out of allowed range.
+ /// </exception>
+ public MethodBody AddMethodBody(
+ int codeSize,
int maxStack = 8,
int exceptionRegionCount = 0,
bool hasSmallExceptionRegions = true,
- StandaloneSignatureHandle localVariablesSignature = default(StandaloneSignatureHandle),
- MethodBodyAttributes attributes = MethodBodyAttributes.InitLocals)
+ StandaloneSignatureHandle localVariablesSignature = default,
+ MethodBodyAttributes attributes = MethodBodyAttributes.InitLocals,
+ bool hasDynamicStackAllocation = false)
{
if (codeSize < 0)
{
@@ -66,11 +90,11 @@ namespace System.Reflection.Metadata.Ecma335
Throw.ArgumentOutOfRange(nameof(exceptionRegionCount));
}
- int bodyOffset = SerializeHeader(codeSize, (ushort)maxStack, exceptionRegionCount, attributes, localVariablesSignature);
+ int bodyOffset = SerializeHeader(codeSize, (ushort)maxStack, exceptionRegionCount, attributes, localVariablesSignature, hasDynamicStackAllocation);
var instructions = Builder.ReserveBytes(codeSize);
var regionEncoder = (exceptionRegionCount > 0) ?
- ExceptionRegionEncoder.SerializeTableHeader(Builder, exceptionRegionCount, hasSmallExceptionRegions) : default(ExceptionRegionEncoder);
+ ExceptionRegionEncoder.SerializeTableHeader(Builder, exceptionRegionCount, hasSmallExceptionRegions) : default;
return new MethodBody(bodyOffset, instructions, regionEncoder);
}
@@ -112,13 +136,37 @@ namespace System.Reflection.Metadata.Ecma335
/// <exception cref="ArgumentOutOfRangeException"><paramref name="maxStack"/> is out of range [0, <see cref="ushort.MaxValue"/>].</exception>
/// <exception cref="InvalidOperationException">
/// A label targeted by a branch in the instruction stream has not been marked,
- /// or the distance between a branch instruction and the target label is doesn't fit the size of the instruction operand.
+ /// or the distance between a branch instruction and the target label doesn't fit the size of the instruction operand.
+ /// </exception>
+ public int AddMethodBody(
+ InstructionEncoder instructionEncoder,
+ int maxStack,
+ StandaloneSignatureHandle localVariablesSignature,
+ MethodBodyAttributes attributes)
+ => AddMethodBody(instructionEncoder, maxStack, localVariablesSignature, attributes, hasDynamicStackAllocation: false);
+
+ /// <summary>
+ /// Encodes a method body and adds it to the method body stream.
+ /// </summary>
+ /// <param name="instructionEncoder">Instruction encoder.</param>
+ /// <param name="maxStack">Max stack.</param>
+ /// <param name="localVariablesSignature">Local variables signature handle.</param>
+ /// <param name="attributes">Attributes.</param>
+ /// <param name="hasDynamicStackAllocation">True if the method allocates from dynamic local memory pool (the IL contains <c>localloc</c> instruction).
+ /// </param>
+ /// <returns>The offset of the encoded body within the method body stream.</returns>
+ /// <exception cref="ArgumentNullException"><paramref name="instructionEncoder"/> has default value.</exception>
+ /// <exception cref="ArgumentOutOfRangeException"><paramref name="maxStack"/> is out of range [0, <see cref="ushort.MaxValue"/>].</exception>
+ /// <exception cref="InvalidOperationException">
+ /// A label targeted by a branch in the instruction stream has not been marked,
+ /// or the distance between a branch instruction and the target label doesn't fit the size of the instruction operand.
/// </exception>
public int AddMethodBody(
InstructionEncoder instructionEncoder,
int maxStack = 8,
- StandaloneSignatureHandle localVariablesSignature = default(StandaloneSignatureHandle),
- MethodBodyAttributes attributes = MethodBodyAttributes.InitLocals)
+ StandaloneSignatureHandle localVariablesSignature = default,
+ MethodBodyAttributes attributes = MethodBodyAttributes.InitLocals,
+ bool hasDynamicStackAllocation = false)
{
if (unchecked((uint)maxStack) > ushort.MaxValue)
{
@@ -142,7 +190,20 @@ namespace System.Reflection.Metadata.Ecma335
Throw.ArgumentOutOfRange(nameof(instructionEncoder), SR.TooManyExceptionRegions);
}
- int bodyOffset = SerializeHeader(codeBuilder.Count, (ushort)maxStack, exceptionRegionCount, attributes, localVariablesSignature);
+ // Note (see also https://github.com/dotnet/corefx/issues/26910)
+ //
+ // We could potentially automatically determine whether a tiny method with no variables and InitLocals flag set
+ // has localloc instruction and thus needs a fat header. We could parse the IL stored in codeBuilder.
+ // However, it would unnecessarily slow down emit of virtually all tiny methods, which do not use localloc
+ // and would only address uninitialized memory issues in very rare scenarios when the pointer returned by
+ // localloc is not stored in a local variable but passed to a method call or stored in a field.
+ //
+ // Since emitting code with localloc is already a pretty advanced scenario that emits unsafe code
+ // that can be potentially incorrect in many other ways we decide that it's not worth the complexity
+ // and a perf regression to do so. Instead we rely on the caller to let us know if there is a localloc
+ // in the code they emitted.
+
+ int bodyOffset = SerializeHeader(codeBuilder.Count, (ushort)maxStack, exceptionRegionCount, attributes, localVariablesSignature, hasDynamicStackAllocation);
if (flowBuilder?.BranchCount > 0)
{
@@ -158,17 +219,27 @@ namespace System.Reflection.Metadata.Ecma335
return bodyOffset;
}
- private int SerializeHeader(int codeSize, ushort maxStack, int exceptionRegionCount, MethodBodyAttributes attributes, StandaloneSignatureHandle localVariablesSignature)
+ private int SerializeHeader(
+ int codeSize,
+ ushort maxStack,
+ int exceptionRegionCount,
+ MethodBodyAttributes attributes,
+ StandaloneSignatureHandle localVariablesSignature,
+ bool hasDynamicStackAllocation)
{
const int TinyFormat = 2;
const int FatFormat = 3;
const int MoreSections = 8;
const byte InitLocals = 0x10;
- int offset;
+ bool initLocals = (attributes & MethodBodyAttributes.InitLocals) != 0;
- bool isTiny = codeSize < 64 && maxStack <= 8 && localVariablesSignature.IsNil && exceptionRegionCount == 0;
+ bool isTiny = codeSize < 64 &&
+ maxStack <= 8 &&
+ localVariablesSignature.IsNil && (!hasDynamicStackAllocation || !initLocals) &&
+ exceptionRegionCount == 0;
+ int offset;
if (isTiny)
{
offset = Builder.Count;
@@ -186,7 +257,7 @@ namespace System.Reflection.Metadata.Ecma335
flags |= MoreSections;
}
- if ((attributes & MethodBodyAttributes.InitLocals) != 0)
+ if (initLocals)
{
flags |= InitLocals;
}
diff --git a/src/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataReaderExtensions.cs b/src/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataReaderExtensions.cs
index c6fe64065d..4fd4b0b1e1 100644
--- a/src/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataReaderExtensions.cs
+++ b/src/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataReaderExtensions.cs
@@ -425,7 +425,7 @@ namespace System.Reflection.Metadata.Ecma335
return SignatureTypeKind.Unknown;
default:
- throw new ArgumentOutOfRangeException(nameof(typeHandle), SR.UnexpectedHandleKind);
+ throw new ArgumentOutOfRangeException(nameof(typeHandle), SR.Format(SR.UnexpectedHandleKind, typeHandle.Kind));
}
}
}
diff --git a/src/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.cs b/src/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.cs
index e861d542be..27b4796d5d 100644
--- a/src/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.cs
+++ b/src/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.cs
@@ -22,6 +22,9 @@ namespace System.Reflection.Metadata
// A row id of "mscorlib" AssemblyRef in a WinMD file (each WinMD file must have such a reference).
internal readonly int WinMDMscorlibRef;
+ // Keeps the underlying memory alive.
+ private readonly object _memoryOwnerObj;
+
private readonly MetadataReaderOptions _options;
private Dictionary<TypeDefinitionHandle, ImmutableArray<TypeDefinitionHandle>> _lazyNestedTypesMap;
@@ -34,7 +37,7 @@ namespace System.Reflection.Metadata
/// The memory is owned by the caller and it must be kept memory alive and unmodified throughout the lifetime of the <see cref="MetadataReader"/>.
/// </remarks>
public unsafe MetadataReader(byte* metadata, int length)
- : this(metadata, length, MetadataReaderOptions.Default, null)
+ : this(metadata, length, MetadataReaderOptions.Default, utf8Decoder: null, memoryOwner: null)
{
}
@@ -47,7 +50,7 @@ namespace System.Reflection.Metadata
/// metadata from a PE image.
/// </remarks>
public unsafe MetadataReader(byte* metadata, int length, MetadataReaderOptions options)
- : this(metadata, length, options, null)
+ : this(metadata, length, options, utf8Decoder: null, memoryOwner: null)
{
}
@@ -65,17 +68,22 @@ namespace System.Reflection.Metadata
/// <exception cref="PlatformNotSupportedException">The current platform is big-endian.</exception>
/// <exception cref="BadImageFormatException">Bad metadata header.</exception>
public unsafe MetadataReader(byte* metadata, int length, MetadataReaderOptions options, MetadataStringDecoder utf8Decoder)
+ : this(metadata, length, options, utf8Decoder, memoryOwner: null)
+ {
+ }
+
+ internal unsafe MetadataReader(byte* metadata, int length, MetadataReaderOptions options, MetadataStringDecoder utf8Decoder, object memoryOwner)
{
// Do not throw here when length is 0. We'll throw BadImageFormatException later on, so that the caller doesn't need to
// worry about the image (stream) being empty and can handle all image errors by catching BadImageFormatException.
if (length < 0)
{
- throw new ArgumentOutOfRangeException(nameof(length));
+ Throw.ArgumentOutOfRange(nameof(length));
}
if (metadata == null)
{
- throw new ArgumentNullException(nameof(metadata));
+ Throw.ArgumentNull(nameof(metadata));
}
if (utf8Decoder == null)
@@ -85,28 +93,28 @@ namespace System.Reflection.Metadata
if (!(utf8Decoder.Encoding is UTF8Encoding))
{
- throw new ArgumentException(SR.MetadataStringDecoderEncodingMustBeUtf8, nameof(utf8Decoder));
+ Throw.InvalidArgument(SR.MetadataStringDecoderEncodingMustBeUtf8, nameof(utf8Decoder));
}
- this.Block = new MemoryBlock(metadata, length);
+ Block = new MemoryBlock(metadata, length);
+ _memoryOwnerObj = memoryOwner;
_options = options;
- this.UTF8Decoder = utf8Decoder;
+ UTF8Decoder = utf8Decoder;
- var headerReader = new BlobReader(this.Block);
- this.ReadMetadataHeader(ref headerReader, out _versionString);
+ var headerReader = new BlobReader(Block);
+ ReadMetadataHeader(ref headerReader, out _versionString);
_metadataKind = GetMetadataKind(_versionString);
- var streamHeaders = this.ReadStreamHeaders(ref headerReader);
+ var streamHeaders = ReadStreamHeaders(ref headerReader);
// storage header and stream headers:
- MemoryBlock metadataTableStream;
- MemoryBlock standalonePdbStream;
- this.InitializeStreamReaders(ref this.Block, streamHeaders, out _metadataStreamKind, out metadataTableStream, out standalonePdbStream);
+ InitializeStreamReaders(Block, streamHeaders, out _metadataStreamKind, out var metadataTableStream, out var pdbStream);
int[] externalTableRowCountsOpt;
- if (standalonePdbStream.Length > 0)
+ if (pdbStream.Length > 0)
{
- ReadStandalonePortablePdbStream(standalonePdbStream, out _debugMetadataHeader, out externalTableRowCountsOpt);
+ int pdbStreamOffset = (int)(pdbStream.Pointer - metadata);
+ ReadStandalonePortablePdbStream(pdbStream, pdbStreamOffset, out _debugMetadataHeader, out externalTableRowCountsOpt);
}
else
{
@@ -115,30 +123,28 @@ namespace System.Reflection.Metadata
var tableReader = new BlobReader(metadataTableStream);
- HeapSizes heapSizes;
- int[] metadataTableRowCounts;
- this.ReadMetadataTableHeader(ref tableReader, out heapSizes, out metadataTableRowCounts, out _sortedTables);
+ ReadMetadataTableHeader(ref tableReader, out var heapSizes, out var metadataTableRowCounts, out _sortedTables);
- this.InitializeTableReaders(tableReader.GetMemoryBlockAt(0, tableReader.RemainingBytes), heapSizes, metadataTableRowCounts, externalTableRowCountsOpt);
+ InitializeTableReaders(tableReader.GetMemoryBlockAt(0, tableReader.RemainingBytes), heapSizes, metadataTableRowCounts, externalTableRowCountsOpt);
// This previously could occur in obfuscated assemblies but a check was added to prevent
// it getting to this point
- Debug.Assert(this.AssemblyTable.NumberOfRows <= 1);
+ Debug.Assert(AssemblyTable.NumberOfRows <= 1);
// Although the specification states that the module table will have exactly one row,
// the native metadata reader would successfully read files containing more than one row.
// Such files exist in the wild and may be produced by obfuscators.
- if (standalonePdbStream.Length == 0 && this.ModuleTable.NumberOfRows < 1)
+ if (pdbStream.Length == 0 && ModuleTable.NumberOfRows < 1)
{
throw new BadImageFormatException(SR.Format(SR.ModuleTableInvalidNumberOfRows, this.ModuleTable.NumberOfRows));
}
// read
- this.NamespaceCache = new NamespaceCache(this);
+ NamespaceCache = new NamespaceCache(this);
if (_metadataKind != MetadataKind.Ecma335)
{
- this.WinMDMscorlibRef = FindMscorlibAssemblyRefNoProjection();
+ WinMDMscorlibRef = FindMscorlibAssemblyRefNoProjection();
}
}
@@ -259,14 +265,14 @@ namespace System.Reflection.Metadata
}
private void InitializeStreamReaders(
- ref MemoryBlock metadataRoot,
+ in MemoryBlock metadataRoot,
StreamHeader[] streamHeaders,
out MetadataStreamKind metadataStreamKind,
out MemoryBlock metadataTableStream,
out MemoryBlock standalonePdbStream)
{
- metadataTableStream = default(MemoryBlock);
- standalonePdbStream = default(MemoryBlock);
+ metadataTableStream = default;
+ standalonePdbStream = default;
metadataStreamKind = MetadataStreamKind.Illegal;
foreach (StreamHeader streamHeader in streamHeaders)
@@ -517,9 +523,9 @@ namespace System.Reflection.Metadata
}
// internal for testing
- internal static void ReadStandalonePortablePdbStream(MemoryBlock block, out DebugMetadataHeader debugMetadataHeader, out int[] externalTableRowCounts)
+ internal static void ReadStandalonePortablePdbStream(MemoryBlock pdbStreamBlock, int pdbStreamOffset, out DebugMetadataHeader debugMetadataHeader, out int[] externalTableRowCounts)
{
- var reader = new BlobReader(block);
+ var reader = new BlobReader(pdbStreamBlock);
const int PdbIdSize = 20;
byte[] pdbId = reader.ReadBytes(PdbIdSize);
@@ -544,14 +550,15 @@ namespace System.Reflection.Metadata
if ((externalTableMask & ~validTables) != 0)
{
- throw new BadImageFormatException(string.Format(SR.UnknownTables, (TableMask)externalTableMask));
+ throw new BadImageFormatException(string.Format(SR.UnknownTables, externalTableMask));
}
externalTableRowCounts = ReadMetadataTableRowCounts(ref reader, externalTableMask);
debugMetadataHeader = new DebugMetadataHeader(
ImmutableByteArrayInterop.DangerousCreateFromUnderlyingArray(ref pdbId),
- MethodDefinitionHandle.FromRowId(entryPointRowId));
+ MethodDefinitionHandle.FromRowId(entryPointRowId),
+ idStartOffset: pdbStreamOffset);
}
private const int SmallIndexSize = 2;
diff --git a/src/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReaderProvider.cs b/src/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReaderProvider.cs
index 7e7007b000..3665104143 100644
--- a/src/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReaderProvider.cs
+++ b/src/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReaderProvider.cs
@@ -234,7 +234,7 @@ namespace System.Reflection.Metadata
/// Gets a <see cref="MetadataReader"/> from a <see cref="MetadataReaderProvider"/>.
/// </summary>
/// <remarks>
- /// The caller must keep the <see cref="MetadataReaderProvider"/> alive and undisposed throughout the lifetime of the metadata reader.
+ /// The caller must keep the <see cref="MetadataReaderProvider"/> undisposed throughout the lifetime of the metadata reader.
///
/// If this method is called multiple times each call with arguments equal to the arguments passed to the previous successful call
/// returns the same instance of <see cref="MetadataReader"/> as the previous call.
@@ -266,7 +266,7 @@ namespace System.Reflection.Metadata
}
AbstractMemoryBlock metadata = GetMetadataBlock();
- var newReader = new MetadataReader(metadata.Pointer, metadata.Size, options, utf8Decoder);
+ var newReader = new MetadataReader(metadata.Pointer, metadata.Size, options, utf8Decoder, memoryOwner: this);
_lazyMetadataReader = newReader;
return newReader;
}
diff --git a/src/System.Reflection.Metadata/src/System/Reflection/Metadata/PEReaderExtensions.cs b/src/System.Reflection.Metadata/src/System/Reflection/Metadata/PEReaderExtensions.cs
index a08441030f..059e00b545 100644
--- a/src/System.Reflection.Metadata/src/System/Reflection/Metadata/PEReaderExtensions.cs
+++ b/src/System.Reflection.Metadata/src/System/Reflection/Metadata/PEReaderExtensions.cs
@@ -71,7 +71,7 @@ namespace System.Reflection.Metadata
/// Gets a <see cref="MetadataReader"/> from a <see cref="PEReader"/>.
/// </summary>
/// <remarks>
- /// The caller must keep the <see cref="PEReader"/> alive and undisposed throughout the lifetime of the metadata reader.
+ /// The caller must keep the <see cref="PEReader"/> undisposed throughout the lifetime of the metadata reader.
/// </remarks>
/// <exception cref="ArgumentNullException"><paramref name="peReader"/> is null</exception>
/// <exception cref="ArgumentException">The encoding of <paramref name="utf8Decoder"/> is not <see cref="UTF8Encoding"/>.</exception>
@@ -85,7 +85,7 @@ namespace System.Reflection.Metadata
}
var metadata = peReader.GetMetadata();
- return new MetadataReader(metadata.Pointer, metadata.Length, options, utf8Decoder);
+ return new MetadataReader(metadata.Pointer, metadata.Length, options, utf8Decoder, memoryOwner: peReader);
}
}
}
diff --git a/src/System.Reflection.Metadata/src/System/Reflection/Metadata/PortablePdb/DebugMetadataHeader.cs b/src/System.Reflection.Metadata/src/System/Reflection/Metadata/PortablePdb/DebugMetadataHeader.cs
index d5995c5317..3e65ea1b1b 100644
--- a/src/System.Reflection.Metadata/src/System/Reflection/Metadata/PortablePdb/DebugMetadataHeader.cs
+++ b/src/System.Reflection.Metadata/src/System/Reflection/Metadata/PortablePdb/DebugMetadataHeader.cs
@@ -3,7 +3,6 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Immutable;
-using System.Diagnostics;
namespace System.Reflection.Metadata
{
@@ -12,10 +11,16 @@ namespace System.Reflection.Metadata
public ImmutableArray<byte> Id { get; }
public MethodDefinitionHandle EntryPoint { get; }
- internal DebugMetadataHeader(ImmutableArray<byte> id, MethodDefinitionHandle entryPoint)
+ /// <summary>
+ /// Gets the offset (in bytes) from the start of the metadata blob to the start of the <see cref="Id"/> blob.
+ /// </summary>
+ public int IdStartOffset { get; }
+
+ internal DebugMetadataHeader(ImmutableArray<byte> id, MethodDefinitionHandle entryPoint, int idStartOffset)
{
Id = id;
EntryPoint = entryPoint;
+ IdStartOffset = idStartOffset;
}
}
}
diff --git a/src/System.Reflection.Metadata/src/System/Reflection/Metadata/TypeSystem/TypeDefinition.cs b/src/System.Reflection.Metadata/src/System/Reflection/Metadata/TypeSystem/TypeDefinition.cs
index 7d8d7f6a26..fe778b7238 100644
--- a/src/System.Reflection.Metadata/src/System/Reflection/Metadata/TypeSystem/TypeDefinition.cs
+++ b/src/System.Reflection.Metadata/src/System/Reflection/Metadata/TypeSystem/TypeDefinition.cs
@@ -53,6 +53,11 @@ namespace System.Reflection.Metadata
}
/// <summary>
+ /// Indicates whether this is a nested type.
+ /// </summary>
+ public bool IsNested => Attributes.IsNested();
+
+ /// <summary>
/// Name of the type.
/// </summary>
public StringHandle Name
diff --git a/src/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/DebugDirectory/DebugDirectoryBuilder.EmbeddedPortablePdb.cs b/src/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/DebugDirectory/DebugDirectoryBuilder.EmbeddedPortablePdb.cs
index f8375589f5..79dc9e51e2 100644
--- a/src/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/DebugDirectory/DebugDirectoryBuilder.EmbeddedPortablePdb.cs
+++ b/src/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/DebugDirectory/DebugDirectoryBuilder.EmbeddedPortablePdb.cs
@@ -37,7 +37,7 @@ namespace System.Reflection.PortableExecutable
type: DebugDirectoryEntryType.EmbeddedPortablePdb,
version: PortablePdbVersions.DebugDirectoryEmbeddedVersion(portablePdbVersion),
stamp: 0,
- dataSize: dataSize);
+ dataSize);
}
private static int WriteEmbeddedPortablePdbData(BlobBuilder builder, BlobBuilder debugMetadata)
diff --git a/src/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/DebugDirectory/DebugDirectoryBuilder.cs b/src/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/DebugDirectory/DebugDirectoryBuilder.cs
index 5e96fea91c..3b589d5992 100644
--- a/src/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/DebugDirectory/DebugDirectoryBuilder.cs
+++ b/src/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/DebugDirectory/DebugDirectoryBuilder.cs
@@ -3,7 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
-using System.IO;
+using System.Collections.Immutable;
using System.Reflection.Metadata;
namespace System.Reflection.PortableExecutable
@@ -23,11 +23,11 @@ namespace System.Reflection.PortableExecutable
public DebugDirectoryBuilder()
{
- _entries = new List<Entry>(2);
+ _entries = new List<Entry>(3);
_dataBuilder = new BlobBuilder();
}
- internal void AddEntry(DebugDirectoryEntryType type, uint version, uint stamp, int dataSize = 0)
+ internal void AddEntry(DebugDirectoryEntryType type, uint version, uint stamp, int dataSize)
{
_entries.Add(new Entry()
{
@@ -39,6 +39,38 @@ namespace System.Reflection.PortableExecutable
}
/// <summary>
+ /// Adds an entry.
+ /// </summary>
+ /// <param name="type">Entry type.</param>
+ /// <param name="version">Entry version.</param>
+ /// <param name="stamp">Entry stamp.</param>
+ public void AddEntry(DebugDirectoryEntryType type, uint version, uint stamp)
+ => AddEntry(type, version, stamp, dataSize: 0);
+
+ /// <summary>
+ /// Adds an entry.
+ /// </summary>
+ /// <typeparam name="TData">Type of data passed to <paramref name="dataSerializer"/>.</typeparam>
+ /// <param name="type">Entry type.</param>
+ /// <param name="version">Entry version.</param>
+ /// <param name="stamp">Entry stamp.</param>
+ /// <param name="data">Data passed to <paramref name="dataSerializer"/>.</param>
+ /// <param name="dataSerializer">Serializes data to a <see cref="BlobBuilder"/>.</param>
+ public void AddEntry<TData>(DebugDirectoryEntryType type, uint version, uint stamp, TData data, Action<BlobBuilder, TData> dataSerializer)
+ {
+ if (dataSerializer == null)
+ {
+ Throw.ArgumentNull(nameof(dataSerializer));
+ }
+
+ int start = _dataBuilder.Count;
+ dataSerializer(_dataBuilder, data);
+ int dataSize = _dataBuilder.Count - start;
+
+ AddEntry(type, version, stamp, dataSize);
+ }
+
+ /// <summary>
/// Adds a CodeView entry.
/// </summary>
/// <param name="pdbPath">Path to the PDB. Shall not be empty.</param>
@@ -99,16 +131,14 @@ namespace System.Reflection.PortableExecutable
type: DebugDirectoryEntryType.CodeView,
version: (portablePdbVersion == 0) ? 0 : PortablePdbVersions.DebugDirectoryEntryVersion(portablePdbVersion),
stamp: pdbContentId.Stamp,
- dataSize: dataSize);
+ dataSize);
}
/// <summary>
/// Adds Reproducible entry.
/// </summary>
public void AddReproducibleEntry()
- {
- AddEntry(type: DebugDirectoryEntryType.Reproducible, version: 0, stamp: 0);
- }
+ => AddEntry(type: DebugDirectoryEntryType.Reproducible, version: 0, stamp: 0);
private static int WriteCodeViewData(BlobBuilder builder, string pdbPath, Guid pdbGuid, int age)
{
@@ -133,6 +163,58 @@ namespace System.Reflection.PortableExecutable
return builder.Count - start;
}
+ /// <summary>
+ /// Adds PDB checksum entry.
+ /// </summary>
+ /// <param name="algorithmName">Hash algorithm name (e.g. "SHA256").</param>
+ /// <param name="checksum">Checksum.</param>
+ /// <exception cref="ArgumentNullException"><paramref name="algorithmName"/> or <paramref name="checksum"/> is null.</exception>
+ /// <exception cref="ArgumentException"><paramref name="algorithmName"/> or <paramref name="checksum"/> is empty.</exception>
+ public void AddPdbChecksumEntry(string algorithmName, ImmutableArray<byte> checksum)
+ {
+ if (algorithmName == null)
+ {
+ Throw.ArgumentNull(nameof(algorithmName));
+ }
+
+ if (algorithmName.Length == 0)
+ {
+ Throw.ArgumentEmptyString(nameof(algorithmName));
+ }
+
+ if (checksum.IsDefault)
+ {
+ Throw.ArgumentNull(nameof(checksum));
+ }
+
+ if (checksum.Length == 0)
+ {
+ Throw.ArgumentEmptyArray(nameof(checksum));
+ }
+
+ int dataSize = WritePdbChecksumData(_dataBuilder, algorithmName, checksum);
+
+ AddEntry(
+ type: DebugDirectoryEntryType.PdbChecksum,
+ version: 0x00000001,
+ stamp: 0x00000000,
+ dataSize);
+ }
+
+ private static int WritePdbChecksumData(BlobBuilder builder, string algorithmName, ImmutableArray<byte> checksum)
+ {
+ int start = builder.Count;
+
+ // NUL-terminated algorithm name:
+ builder.WriteUTF8(algorithmName, allowUnpairedSurrogates: true);
+ builder.WriteByte(0);
+
+ // checksum:
+ builder.WriteBytes(checksum);
+
+ return builder.Count - start;
+ }
+
internal int TableSize => DebugDirectoryEntry.Size * _entries.Count;
internal int Size => TableSize + _dataBuilder?.Count ?? 0;
diff --git a/src/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/DebugDirectory/DebugDirectoryEntryType.cs b/src/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/DebugDirectory/DebugDirectoryEntryType.cs
index c978844712..e316b71c67 100644
--- a/src/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/DebugDirectory/DebugDirectoryEntryType.cs
+++ b/src/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/DebugDirectory/DebugDirectoryEntryType.cs
@@ -20,6 +20,9 @@ namespace System.Reflection.PortableExecutable
/// <summary>
/// Associated PDB file description.
/// </summary>
+ /// <remarks>
+ /// See https://github.com/dotnet/corefx/blob/master/src/System.Reflection.Metadata/specs/PE-COFF.md#codeview-debug-directory-entry-type-2 for specification.
+ /// </remarks>
CodeView = 2,
/// <summary>
@@ -41,6 +44,9 @@ namespace System.Reflection.PortableExecutable
/// <para>
/// The debug directory entry of type <see cref="Reproducible"/> must have all fields, except for Type zeroed.
/// </para>
+ /// <para>
+ /// See https://github.com/dotnet/corefx/blob/master/src/System.Reflection.Metadata/specs/PE-COFF.md#deterministic-debug-directory-entry-type-16 for specification.
+ /// </para>
/// </remarks>
Reproducible = 16,
@@ -53,7 +59,20 @@ namespace System.Reflection.PortableExecutable
/// blob ::= uncompressed-size data
///
/// Data spans the remainder of the blob and contains a Deflate-compressed Portable PDB.
+ ///
+ /// See https://github.com/dotnet/corefx/blob/master/src/System.Reflection.Metadata/specs/PE-COFF.md#embedded-portable-pdb-debug-directory-entry-type-17 for specification.
/// </remarks>
EmbeddedPortablePdb = 17,
+
+ /// <summary>
+ /// The entry stores crypto hash of the content of the symbol file the PE/COFF file was built with.
+ /// </summary>
+ /// <remarks>
+ /// The hash can be used to validate that a given PDB file was built with the PE/COFF file and not altered in any way.
+ /// More than one entry can be present, in case multiple PDBs were produced during the build of the PE/COFF file (e.g. private and public symbols).
+ ///
+ /// See https://github.com/dotnet/corefx/blob/master/src/System.Reflection.Metadata/specs/PE-COFF.md#pdb-checksum-debug-directory-entry-type-19 for specification.
+ /// </remarks>
+ PdbChecksum = 19,
}
}
diff --git a/src/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/DebugDirectory/PdbChecksumDebugDirectoryData.cs b/src/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/DebugDirectory/PdbChecksumDebugDirectoryData.cs
new file mode 100644
index 0000000000..21569f7aa7
--- /dev/null
+++ b/src/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/DebugDirectory/PdbChecksumDebugDirectoryData.cs
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Immutable;
+using System.Diagnostics;
+
+namespace System.Reflection.PortableExecutable
+{
+ public readonly struct PdbChecksumDebugDirectoryData
+ {
+ /// <summary>
+ /// Checksum algorithm name.
+ /// </summary>
+ public string AlgorithmName { get; }
+
+ /// <summary>
+ /// GUID (Globally Unique Identifier) of the associated PDB.
+ /// </summary>
+ public ImmutableArray<byte> Checksum { get; }
+
+ internal PdbChecksumDebugDirectoryData(string algorithmName, ImmutableArray<byte> checksum)
+ {
+ Debug.Assert(!string.IsNullOrEmpty(algorithmName));
+ Debug.Assert(!checksum.IsDefaultOrEmpty);
+
+ AlgorithmName = algorithmName;
+ Checksum = checksum;
+ }
+ }
+}
diff --git a/src/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEReader.cs b/src/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEReader.cs
index 98fdba1d14..fc28dad6ad 100644
--- a/src/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEReader.cs
+++ b/src/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEReader.cs
@@ -625,6 +625,43 @@ namespace System.Reflection.PortableExecutable
}
/// <summary>
+ /// Reads the data pointed to by the specified Debug Directory entry and interprets them as PDB Checksum entry.
+ /// </summary>
+ /// <exception cref="ArgumentException"><paramref name="entry"/> is not a PDB Checksum entry.</exception>
+ /// <exception cref="BadImageFormatException">Bad format of the data.</exception>
+ /// <exception cref="IOException">IO error while reading from the underlying stream.</exception>
+ /// <exception cref="InvalidOperationException">PE image not available.</exception>
+ public PdbChecksumDebugDirectoryData ReadPdbChecksumDebugDirectoryData(DebugDirectoryEntry entry)
+ {
+ if (entry.Type != DebugDirectoryEntryType.PdbChecksum)
+ {
+ Throw.InvalidArgument(SR.Format(SR.UnexpectedDebugDirectoryType, nameof(DebugDirectoryEntryType.PdbChecksum)), nameof(entry));
+ }
+
+ using (var block = GetDebugDirectoryEntryDataBlock(entry))
+ {
+ return DecodePdbChecksumDebugDirectoryData(block);
+ }
+ }
+
+ // internal for testing
+ internal static PdbChecksumDebugDirectoryData DecodePdbChecksumDebugDirectoryData(AbstractMemoryBlock block)
+ {
+ var reader = block.GetReader();
+
+ var algorithmName = reader.ReadUtf8NullTerminated();
+ var checksum = reader.ReadBytes(reader.RemainingBytes);
+ if (algorithmName.Length == 0 || checksum.Length == 0)
+ {
+ throw new BadImageFormatException(SR.InvalidPdbChecksumDataFormat);
+ }
+
+ return new PdbChecksumDebugDirectoryData(
+ algorithmName,
+ ImmutableByteArrayInterop.DangerousCreateFromUnderlyingArray(ref checksum));
+ }
+
+ /// <summary>
/// Opens a Portable PDB associated with this PE image.
/// </summary>
/// <param name="peImagePath">
diff --git a/src/System.Reflection.Metadata/src/System/Reflection/Throw.cs b/src/System.Reflection.Metadata/src/System/Reflection/Throw.cs
index f2f7ccb77d..37f5b790ac 100644
--- a/src/System.Reflection.Metadata/src/System/Reflection/Throw.cs
+++ b/src/System.Reflection.Metadata/src/System/Reflection/Throw.cs
@@ -109,6 +109,12 @@ namespace System.Reflection
}
[MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void ArgumentEmptyArray(string parameterName)
+ {
+ throw new ArgumentException(SR.ExpectedNonEmptyArray, parameterName);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
internal static void ValueArgumentNull()
{
throw new ArgumentNullException("value");
diff --git a/src/System.Reflection.Metadata/tests/Metadata/Ecma335/Encoding/ControlFlowBuilderTests.cs b/src/System.Reflection.Metadata/tests/Metadata/Ecma335/Encoding/ControlFlowBuilderTests.cs
index eb0debf6fa..7dc0055620 100644
--- a/src/System.Reflection.Metadata/tests/Metadata/Ecma335/Encoding/ControlFlowBuilderTests.cs
+++ b/src/System.Reflection.Metadata/tests/Metadata/Ecma335/Encoding/ControlFlowBuilderTests.cs
@@ -258,5 +258,166 @@ namespace System.Reflection.Metadata.Ecma335.Tests
flow.AddFaultRegion(l1, l2, l4, l3);
Assert.Throws<InvalidOperationException>(() => encoder.AddMethodBody(il));
}
+
+ [Fact]
+ public void Branch_ShortInstruction_LongDistance()
+ {
+ var code = new BlobBuilder();
+ var flow = new ControlFlowBuilder();
+ var il = new InstructionEncoder(code, flow);
+
+ var l1 = il.DefineLabel();
+
+ il.Branch(ILOpCode.Br_s, l1);
+
+ for (int i = 0; i < 100; i++)
+ {
+ il.Call(MetadataTokens.MethodDefinitionHandle(1));
+ }
+
+ il.MarkLabel(l1);
+ il.OpCode(ILOpCode.Ret);
+
+ var builder = new BlobBuilder();
+ var encoder = new MethodBodyStreamEncoder(builder);
+
+ Assert.Throws<InvalidOperationException>(() => encoder.AddMethodBody(il));
+ }
+
+ [Fact]
+ public void Branch_ShortInstruction_ShortDistance()
+ {
+ var code = new BlobBuilder();
+ var flow = new ControlFlowBuilder();
+ var il = new InstructionEncoder(code, flow);
+
+ var l1 = il.DefineLabel();
+
+ il.Branch(ILOpCode.Br_s, l1);
+ il.Call(MetadataTokens.MethodDefinitionHandle(1));
+
+ il.MarkLabel(l1);
+ il.OpCode(ILOpCode.Ret);
+
+ var builder = new BlobBuilder();
+ var encoder = new MethodBodyStreamEncoder(builder).AddMethodBody(il);
+
+ AssertEx.Equal(new byte[]
+ {
+ 0x22, // header
+ (byte)ILOpCode.Br_s, 0x05,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Ret
+ }, builder.ToArray());
+ }
+
+ [Fact]
+ public void Branch_LongInstruction_ShortDistance()
+ {
+ var code = new BlobBuilder();
+ var flow = new ControlFlowBuilder();
+ var il = new InstructionEncoder(code, flow);
+
+ var l1 = il.DefineLabel();
+
+ il.Branch(ILOpCode.Br, l1);
+ il.Call(MetadataTokens.MethodDefinitionHandle(1));
+
+ il.MarkLabel(l1);
+ il.OpCode(ILOpCode.Ret);
+
+ var builder = new BlobBuilder();
+ new MethodBodyStreamEncoder(builder).AddMethodBody(il);
+
+ AssertEx.Equal(new byte[]
+ {
+ 0x2E, // header
+ (byte)ILOpCode.Br, 0x05, 0x00, 0x00, 0x00,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Ret
+ }, builder.ToArray());
+ }
+
+ [Fact]
+ public void Branch_LongInstruction_LongDistance()
+ {
+ var code = new BlobBuilder();
+ var flow = new ControlFlowBuilder();
+ var il = new InstructionEncoder(code, flow);
+
+ var l1 = il.DefineLabel();
+
+ il.Branch(ILOpCode.Br, l1);
+
+ for (int i = 0; i < 256/5 + 1; i++)
+ {
+ il.Call(MetadataTokens.MethodDefinitionHandle(1));
+ }
+
+ il.MarkLabel(l1);
+ il.OpCode(ILOpCode.Ret);
+
+ var builder = new BlobBuilder();
+ var encoder = new MethodBodyStreamEncoder(builder).AddMethodBody(il);
+
+ AssertEx.Equal(new byte[]
+ {
+ 0x13, 0x30, 0x08, 0x00, 0x0A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,// header
+ (byte)ILOpCode.Br, 0x04, 0x01, 0x00, 0x00,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Call, 0x01, 0x00, 0x00, 0x06,
+ (byte)ILOpCode.Ret
+ }, builder.ToArray());
+ }
}
}
diff --git a/src/System.Reflection.Metadata/tests/Metadata/Ecma335/Encoding/MethodBodyStreamEncoderTests.cs b/src/System.Reflection.Metadata/tests/Metadata/Ecma335/Encoding/MethodBodyStreamEncoderTests.cs
index 36ecfade22..9cb8e72df4 100644
--- a/src/System.Reflection.Metadata/tests/Metadata/Ecma335/Encoding/MethodBodyStreamEncoderTests.cs
+++ b/src/System.Reflection.Metadata/tests/Metadata/Ecma335/Encoding/MethodBodyStreamEncoderTests.cs
@@ -261,7 +261,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests
int bodyOffset = streamEncoder.AddMethodBody(
il,
maxStack: 2,
- localVariablesSignature: default(StandaloneSignatureHandle),
+ localVariablesSignature: default,
attributes: MethodBodyAttributes.None);
var bodyBytes = streamBuilder.ToArray();
@@ -284,7 +284,8 @@ namespace System.Reflection.Metadata.Ecma335.Tests
var body = MethodBodyBlock.Create(new BlobReader(bodyPtr, bodyBytes.Length));
Assert.Equal(0, body.ExceptionRegions.Length);
- Assert.Equal(default(StandaloneSignatureHandle), body.LocalSignature);
+ Assert.Equal(default, body.LocalSignature);
+ Assert.False(body.LocalVariablesInitialized);
Assert.Equal(8, body.MaxStack);
Assert.Equal(bodyBytes.Length, body.Size);
@@ -330,7 +331,7 @@ namespace System.Reflection.Metadata.Ecma335.Tests
int bodyOffset = streamEncoder.AddMethodBody(
il,
maxStack: 2,
- localVariablesSignature: default(StandaloneSignatureHandle),
+ localVariablesSignature: default,
attributes: MethodBodyAttributes.None);
var bodyBytes = streamBuilder.ToArray();
@@ -353,7 +354,8 @@ namespace System.Reflection.Metadata.Ecma335.Tests
var body = MethodBodyBlock.Create(new BlobReader(bodyPtr, bodyBytes.Length));
Assert.Equal(0, body.ExceptionRegions.Length);
- Assert.Equal(default(StandaloneSignatureHandle), body.LocalSignature);
+ Assert.Equal(default, body.LocalSignature);
+ Assert.False(body.LocalVariablesInitialized);
Assert.Equal(2, body.MaxStack);
Assert.Equal(bodyBytes.Length, body.Size);
@@ -372,6 +374,109 @@ namespace System.Reflection.Metadata.Ecma335.Tests
}
}
+ [Fact, ActiveIssue(26910)]
+ public unsafe void LocAlloc()
+ {
+ var streamBuilder = new BlobBuilder();
+ var codeBuilder = new BlobBuilder();
+ var flowBuilder = new ControlFlowBuilder();
+
+ var il = new byte[]
+ {
+ 0x1A, // ldc.i4.0
+ 0xFE, 0x0F, // localloc
+ 0x28, 0x01, 0x00, 0x00, 0x06, // call 0x06000001
+ 0x2A // ret
+ };
+
+ var streamEncoder = new MethodBodyStreamEncoder(streamBuilder);
+ var methodBody = streamEncoder.AddMethodBody(
+ il.Length,
+ maxStack: 2,
+ localVariablesSignature: default,
+ attributes: MethodBodyAttributes.InitLocals,
+ hasDynamicStackAllocation: true);
+
+ Assert.Equal(0, methodBody.Offset);
+ Assert.Null(methodBody.ExceptionRegions.Builder);
+ Assert.False(methodBody.ExceptionRegions.HasSmallFormat);
+
+ new BlobWriter(methodBody.Instructions).WriteBytes(il);
+
+ var bodyBytes = streamBuilder.ToArray();
+
+ AssertEx.Equal(new byte[]
+ {
+ 0x13, 0x30, // flags and header size
+ 0x02, 0x00, // max stack
+ 0x09, 0x00, 0x00, 0x00, // code size
+ 0x00, 0x00, 0x00, 0x00, // local variable signature
+
+ 0x1A, // ldc.i4.0
+ 0xFE, 0x0F, // localloc
+ 0x28, 0x01, 0x00, 0x00, 0x06, // call 0x06000001
+ 0x2A // ret
+ }, bodyBytes);
+ }
+
+ [Fact, ActiveIssue(26910)]
+ public unsafe void LocAlloc_WithInstructionEncoder()
+ {
+ var streamBuilder = new BlobBuilder();
+ var codeBuilder = new BlobBuilder();
+ var flowBuilder = new ControlFlowBuilder();
+
+ var il = new InstructionEncoder(codeBuilder, flowBuilder);
+
+ il.OpCode(ILOpCode.Ldc_i4_4);
+ il.OpCode(ILOpCode.Localloc);
+ il.Call(MetadataTokens.MethodDefinitionHandle(1));
+ il.OpCode(ILOpCode.Ret);
+
+ var streamEncoder = new MethodBodyStreamEncoder(streamBuilder);
+ int bodyOffset = streamEncoder.AddMethodBody(
+ il,
+ maxStack: 2,
+ localVariablesSignature: default,
+ attributes: MethodBodyAttributes.InitLocals,
+ hasDynamicStackAllocation: true);
+
+ var bodyBytes = streamBuilder.ToArray();
+
+ AssertEx.Equal(new byte[]
+ {
+ 0x13, 0x30, // flags and header size
+ 0x02, 0x00, // max stack
+ 0x09, 0x00, 0x00, 0x00, // code size
+ 0x00, 0x00, 0x00, 0x00, // local variable signature
+
+ 0x1A, // ldc.i4.0
+ 0xFE, 0x0F, // localloc
+ 0x28, 0x01, 0x00, 0x00, 0x06, // call 0x06000001
+ 0x2A // ret
+ }, bodyBytes);
+
+ fixed (byte* bodyPtr = &bodyBytes[0])
+ {
+ var body = MethodBodyBlock.Create(new BlobReader(bodyPtr, bodyBytes.Length));
+
+ Assert.Equal(0, body.ExceptionRegions.Length);
+ Assert.Equal(default, body.LocalSignature);
+ Assert.Equal(2, body.MaxStack);
+ Assert.True(body.LocalVariablesInitialized);
+ Assert.Equal(bodyBytes.Length, body.Size);
+
+ var ilBytes = body.GetILBytes();
+ AssertEx.Equal(new byte[]
+ {
+ 0x1A, // ldc.i4.0
+ 0xFE, 0x0F, // localloc
+ 0x28, 0x01, 0x00, 0x00, 0x06, // call 0x06000001
+ 0x2A // ret
+ }, ilBytes);
+ }
+ }
+
[Fact]
public void Branches1()
{
diff --git a/src/System.Reflection.Metadata/tests/Metadata/MetadataReaderProviderTests.cs b/src/System.Reflection.Metadata/tests/Metadata/MetadataReaderProviderTests.cs
index 22c2df4092..fddba78780 100644
--- a/src/System.Reflection.Metadata/tests/Metadata/MetadataReaderProviderTests.cs
+++ b/src/System.Reflection.Metadata/tests/Metadata/MetadataReaderProviderTests.cs
@@ -5,6 +5,7 @@
using System.Collections.Immutable;
using System.IO;
using System.Reflection.Metadata.Ecma335;
+using System.Runtime.CompilerServices;
using System.Text;
using Xunit;
@@ -146,5 +147,20 @@ namespace System.Reflection.Metadata.Tests
var reader2 = PortablePdbReader2.GetMetadataReader();
Assert.Equal(13, reader2.Documents.Count);
}
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static MetadataReader GetMetadataReaderFromProvider()
+ => MetadataReaderProvider.FromMetadataImage(PortablePdbs.DocumentsPdb.ToImmutableArray()).GetMetadataReader();
+
+ [Fact, MethodImpl(MethodImplOptions.NoOptimization)]
+ public void KeepMetadataAlive()
+ {
+ var reader = GetMetadataReaderFromProvider();
+
+ GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, blocking: true, compacting: true);
+ GC.WaitForPendingFinalizers();
+
+ Assert.Equal(@"C:\Documents.cs", reader.GetString(reader.GetDocument(MetadataTokens.DocumentHandle(1)).Name));
+ }
}
}
diff --git a/src/System.Reflection.Metadata/tests/Metadata/MetadataReaderTests.cs b/src/System.Reflection.Metadata/tests/Metadata/MetadataReaderTests.cs
index 16133431b8..6d5c4da44e 100644
--- a/src/System.Reflection.Metadata/tests/Metadata/MetadataReaderTests.cs
+++ b/src/System.Reflection.Metadata/tests/Metadata/MetadataReaderTests.cs
@@ -65,7 +65,7 @@ namespace System.Reflection.Metadata.Tests
mdtNestedClass = 0x29000000,
}
- internal static readonly Dictionary<byte[], GCHandle> peImages = new Dictionary<byte[], GCHandle>();
+ private static readonly Dictionary<byte[], GCHandle> s_peImages = new Dictionary<byte[], GCHandle>();
internal static unsafe MetadataReader GetMetadataReader(byte[] peImage, bool isModule = false, MetadataReaderOptions options = MetadataReaderOptions.Default, MetadataStringDecoder decoder = null)
{
@@ -83,18 +83,197 @@ namespace System.Reflection.Metadata.Tests
internal static unsafe GCHandle GetPinnedPEImage(byte[] peImage)
{
- GCHandle pinned;
- if (!peImages.TryGetValue(peImage, out pinned))
+ lock (s_peImages)
{
- peImages.Add(peImage, pinned = GCHandle.Alloc(peImage, GCHandleType.Pinned));
+ GCHandle pinned;
+ if (!s_peImages.TryGetValue(peImage, out pinned))
+ {
+ s_peImages.Add(peImage, pinned = GCHandle.Alloc(peImage, GCHandleType.Pinned));
+ }
+
+ return pinned;
}
+ }
- return pinned;
+ internal static unsafe int IndexOf(byte[] peImage, byte[] toFind, int start)
+ {
+ for (int i = 0; i < peImage.Length - toFind.Length; i++)
+ {
+ if (toFind.SequenceEqual(peImage.Slice(i + start, i + start + toFind.Length)))
+ {
+ return i;
+ }
+ }
+ return -1;
}
#endregion
[Fact]
+ public unsafe void InvalidSignature()
+ {
+ byte* ptr = stackalloc byte[4];
+ Assert.Throws<BadImageFormatException>(() => new MetadataReader(ptr, 16));
+ }
+
+ [Fact]
+ public unsafe void InvalidFindMscorlibAssemblyRefNoProjection()
+ {
+ // start with a valid PE (cloned because we'll mutate it).
+ byte[] peImage = (byte[])WinRT.Lib.Clone();
+
+ GCHandle pinned = GetPinnedPEImage(peImage);
+ PEHeaders headers = new PEHeaders(new MemoryStream(peImage));
+
+ //find index for mscorlib
+ int mscorlibIndex = IndexOf(peImage, Encoding.ASCII.GetBytes("mscorlib"), headers.MetadataStartOffset);
+ Assert.NotEqual(mscorlibIndex, -1);
+ //mutate mscorlib
+ peImage[mscorlibIndex + headers.MetadataStartOffset] = 0xFF;
+
+ Assert.Throws<BadImageFormatException>(() => new MetadataReader((byte*)pinned.AddrOfPinnedObject() + headers.MetadataStartOffset, headers.MetadataSize));
+ }
+
+ [Fact]
+ public unsafe void InvalidStreamHeaderLengths()
+ {
+ // start with a valid PE (cloned because we'll mutate it).
+ byte[] peImage = (byte[])WinRT.Lib.Clone();
+
+ GCHandle pinned = GetPinnedPEImage(peImage);
+ PEHeaders headers = new PEHeaders(new MemoryStream(peImage));
+
+ // mutate CLR to reach MetadataKind.WindowsMetadata
+ // find CLR
+ int clrIndex = IndexOf(peImage, Encoding.ASCII.GetBytes("CLR"), headers.MetadataStartOffset);
+ Assert.NotEqual(clrIndex, -1);
+ //find 5, This is the streamcount and is the last thing that should be read befor the test.
+ int fiveIndex = IndexOf(peImage, new byte[] {5}, headers.MetadataStartOffset + clrIndex);
+ Assert.NotEqual(fiveIndex, -1);
+
+ peImage[clrIndex + headers.MetadataStartOffset] = 0xFF;
+
+ //Not enough space for VersionString
+ Assert.Throws<BadImageFormatException>(() => new MetadataReader((byte*)pinned.AddrOfPinnedObject() + headers.MetadataStartOffset, fiveIndex + 2, MetadataReaderOptions.Default));
+ //NotEnoughSpaceForStreamHeaderName for index of five + uint16 + COR20Constants.MinimumSizeofStreamHeader
+ Assert.Throws<BadImageFormatException>(() => new MetadataReader((byte*)pinned.AddrOfPinnedObject() + headers.MetadataStartOffset, fiveIndex + clrIndex + COR20Constants.MinimumSizeofStreamHeader + 2, MetadataReaderOptions.Default));
+ //SR.StreamHeaderTooSmall
+ Assert.Throws<BadImageFormatException>(() => new MetadataReader((byte*)pinned.AddrOfPinnedObject() + headers.MetadataStartOffset, fiveIndex + clrIndex + COR20Constants.MinimumSizeofStreamHeader , MetadataReaderOptions.Default));
+
+ }
+
+ [Fact]
+ public unsafe void InvalidSpaceForStreams()
+ {
+ // start with a valid PE (cloned because we'll mutate it).
+ byte[] peImage = (byte[])NetModule.AppCS.Clone();
+
+ GCHandle pinned = GetPinnedPEImage(peImage);
+ PEHeaders headers = new PEHeaders(new MemoryStream(peImage));
+
+ //find 5, This is the streamcount we'll change to one to leave out loops.
+ int fiveIndex = IndexOf(peImage, new byte[] { 5 }, headers.MetadataStartOffset);
+ Assert.NotEqual(fiveIndex, -1);
+ Array.Copy(BitConverter.GetBytes((ushort)1), 0, peImage, fiveIndex + headers.MetadataStartOffset, BitConverter.GetBytes((ushort)1).Length);
+
+ string[] streamNames= new string[]
+ {
+ COR20Constants.StringStreamName, COR20Constants.BlobStreamName, COR20Constants.GUIDStreamName,
+ COR20Constants.UserStringStreamName, COR20Constants.CompressedMetadataTableStreamName,
+ COR20Constants.UncompressedMetadataTableStreamName, COR20Constants.MinimalDeltaMetadataTableStreamName,
+ COR20Constants.StandalonePdbStreamName, "#invalid"
+ };
+
+ foreach (string name in streamNames)
+ {
+ Array.Copy(Encoding.ASCII.GetBytes(name), 0, peImage, fiveIndex + 10 + headers.MetadataStartOffset, Encoding.ASCII.GetBytes(name).Length);
+ peImage[fiveIndex + 10 + headers.MetadataStartOffset + name.Length] = (byte)0;
+ Assert.Throws<BadImageFormatException>(() => new MetadataReader((byte*)pinned.AddrOfPinnedObject() + headers.MetadataStartOffset, fiveIndex + 15 + name.Length));
+ }
+
+
+ Array.Copy(Encoding.ASCII.GetBytes(COR20Constants.MinimalDeltaMetadataTableStreamName), 0, peImage, fiveIndex + 10 + headers.MetadataStartOffset, Encoding.ASCII.GetBytes(COR20Constants.MinimalDeltaMetadataTableStreamName).Length);
+ peImage[fiveIndex + 10 + headers.MetadataStartOffset + COR20Constants.MinimalDeltaMetadataTableStreamName.Length] = (byte)0;
+ Assert.Throws<BadImageFormatException>(() => new MetadataReader((byte*)pinned.AddrOfPinnedObject() + headers.MetadataStartOffset, headers.MetadataSize));
+
+ }
+
+ [Fact]
+ public unsafe void InvalidExternalTableMask()
+ {
+ byte[] peImage = (byte[])PortablePdbs.DocumentsPdb.Clone();
+ GCHandle pinned = GetPinnedPEImage(peImage);
+
+ //38654710855 is the external table mask from PortablePdbs.DocumentsPdb
+ int externalTableMaskIndex = IndexOf(peImage, BitConverter.GetBytes(38654710855), 0);
+ Assert.NotEqual(externalTableMaskIndex, -1);
+
+ Array.Copy(BitConverter.GetBytes(38654710855 + 1), 0, peImage, externalTableMaskIndex, BitConverter.GetBytes(38654710855 + 1).Length);
+ Assert.Throws<BadImageFormatException>(() => new MetadataReader((byte*)pinned.AddrOfPinnedObject(), peImage.Length));
+ }
+
+ [Fact]
+ public unsafe void IsMinimalDelta()
+ {
+ byte[] peImage = (byte[])PortablePdbs.DocumentsPdb.Clone();
+ GCHandle pinned = GetPinnedPEImage(peImage);
+ //Find COR20Constants.StringStreamName to be changed to COR20Constants.MinimalDeltaMetadataTableStreamName
+ int stringIndex = IndexOf(peImage, Encoding.ASCII.GetBytes(COR20Constants.StringStreamName), 0);
+ Assert.NotEqual(stringIndex, -1);
+ //find remainingBytes to be increased because we are changing to uncompressed
+ int remainingBytesIndex = IndexOf(peImage, BitConverter.GetBytes(180), 0);
+ Assert.NotEqual(remainingBytesIndex, -1);
+ //find compressed to change to uncompressed
+ int compressedIndex = IndexOf(peImage, Encoding.ASCII.GetBytes(COR20Constants.CompressedMetadataTableStreamName), 0);
+ Assert.NotEqual(compressedIndex, -1);
+
+ Array.Copy(Encoding.ASCII.GetBytes(COR20Constants.MinimalDeltaMetadataTableStreamName), 0, peImage, stringIndex, Encoding.ASCII.GetBytes(COR20Constants.MinimalDeltaMetadataTableStreamName).Length);
+ peImage[stringIndex + COR20Constants.MinimalDeltaMetadataTableStreamName.Length] = (byte)0;
+ Array.Copy(BitConverter.GetBytes(250), 0, peImage, remainingBytesIndex, BitConverter.GetBytes(250).Length);
+ Array.Copy(Encoding.ASCII.GetBytes(COR20Constants.UncompressedMetadataTableStreamName), 0, peImage, compressedIndex, Encoding.ASCII.GetBytes(COR20Constants.UncompressedMetadataTableStreamName).Length);
+
+ MetadataReader minimalDeltaReader = new MetadataReader((byte*)pinned.AddrOfPinnedObject(), peImage.Length);
+ Assert.True(minimalDeltaReader.IsMinimalDelta);
+ }
+
+
+ [Fact]
+ public unsafe void InvalidMetaDataTableHeaders()
+ {
+ // start with a valid PE (cloned because we'll mutate it).
+ byte[] peImage = (byte[])NetModule.AppCS.Clone();
+
+ GCHandle pinned = GetPinnedPEImage(peImage);
+ PEHeaders headers = new PEHeaders(new MemoryStream(peImage));
+
+ //1392 is the remaining bytes from NetModule.AppCS
+ int remainingBytesIndex = IndexOf(peImage, BitConverter.GetBytes(1392), headers.MetadataStartOffset);
+ Assert.NotEqual(remainingBytesIndex, -1);
+ //14057656686423 is the presentTables from NetModule.AppCS, must be after remainingBytesIndex
+ int presentTablesIndex = IndexOf(peImage, BitConverter.GetBytes(14057656686423), headers.MetadataStartOffset + remainingBytesIndex);
+ Assert.NotEqual(presentTablesIndex, -1);
+
+ //Set this.ModuleTable.NumberOfRows to 0
+ Array.Copy(BitConverter.GetBytes((ulong)0), 0, peImage, presentTablesIndex + remainingBytesIndex + headers.MetadataStartOffset + 16, BitConverter.GetBytes((ulong)0).Length);
+ Assert.Throws<BadImageFormatException>(() => new MetadataReader((byte*)pinned.AddrOfPinnedObject() + headers.MetadataStartOffset, headers.MetadataSize));
+ //set row counts greater than TokenTypeIds.RIDMask
+ Array.Copy(BitConverter.GetBytes((ulong)16777216), 0, peImage, presentTablesIndex + remainingBytesIndex + headers.MetadataStartOffset + 16, BitConverter.GetBytes((ulong)16777216).Length);
+ Assert.Throws<BadImageFormatException>(() => new MetadataReader((byte*)pinned.AddrOfPinnedObject() + headers.MetadataStartOffset, headers.MetadataSize));
+ //set remaining bytes smaller than required for row counts.
+ Array.Copy(BitConverter.GetBytes(25), 0, peImage, remainingBytesIndex + headers.MetadataStartOffset, BitConverter.GetBytes(25).Length);
+ Assert.Throws<BadImageFormatException>(() => new MetadataReader((byte*)pinned.AddrOfPinnedObject() + headers.MetadataStartOffset, headers.MetadataSize));
+ //14057656686424 is a value to make (presentTables & ~validTables) != 0 but not (presentTables & (ulong)(TableMask.PtrTables | TableMask.EnCMap)) != 0
+ Array.Copy(BitConverter.GetBytes((ulong)14057656686424), 0, peImage, presentTablesIndex + remainingBytesIndex + headers.MetadataStartOffset, BitConverter.GetBytes((ulong)14057656686424).Length);
+ Assert.Throws<BadImageFormatException>(() => new MetadataReader((byte*)pinned.AddrOfPinnedObject() + headers.MetadataStartOffset, headers.MetadataSize));
+ //14066246621015 makes (presentTables & ~validTables) != 0 fail
+ Array.Copy(BitConverter.GetBytes((ulong)14066246621015), 0, peImage, presentTablesIndex + remainingBytesIndex + headers.MetadataStartOffset, BitConverter.GetBytes((ulong)14066246621015).Length);
+ Assert.Throws<BadImageFormatException>(() => new MetadataReader((byte*)pinned.AddrOfPinnedObject() + headers.MetadataStartOffset, headers.MetadataSize));
+ //set remaining bytes smaller than MetadataStreamConstants.SizeOfMetadataTableHeader
+ Array.Copy(BitConverter.GetBytes(1), 0, peImage, remainingBytesIndex + headers.MetadataStartOffset, BitConverter.GetBytes(1).Length);
+ Assert.Throws<BadImageFormatException>(() => new MetadataReader((byte*)pinned.AddrOfPinnedObject() + headers.MetadataStartOffset, headers.MetadataSize));
+ }
+
+ [Fact]
public unsafe void EmptyMetadata()
{
byte* ptr = stackalloc byte[1];
@@ -251,8 +430,8 @@ namespace System.Reflection.Metadata.Tests
Assert.Equal(StringKind.Plain, winrtDef.Name.StringKind);
Assert.Equal("Class1", reader.GetString(winrtDef.Name));
Assert.Equal(
- TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.AutoLayout | TypeAttributes.AnsiClass |
- TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit,
+ TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.AutoLayout | TypeAttributes.AnsiClass |
+ TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit,
winrtDef.Attributes);
var strReader = reader.GetBlobReader(winrtDef.Name);
@@ -265,7 +444,7 @@ namespace System.Reflection.Metadata.Tests
Assert.Equal(StringKind.WinRTPrefixed, clrDef.Name.StringKind);
Assert.Equal("<WinRT>Class1", reader.GetString(clrDef.Name));
Assert.Equal(
- TypeAttributes.Class | TypeAttributes.NotPublic | TypeAttributes.AutoLayout | TypeAttributes.AnsiClass |
+ TypeAttributes.Class | TypeAttributes.NotPublic | TypeAttributes.AutoLayout | TypeAttributes.AnsiClass |
TypeAttributes.Import | TypeAttributes.WindowsRuntime | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit,
clrDef.Attributes);
@@ -462,7 +641,7 @@ namespace System.Reflection.Metadata.Tests
/// <summary>
/// ModuleRef Table Columns:
/// Name (offset to #String)
- /// -----------------------------
+ /// -----------------------------
/// File Table Columns:
/// Name (offset to #String)
/// Flags (4 byte uint)
@@ -478,7 +657,7 @@ namespace System.Reflection.Metadata.Tests
// ModuleCS01.mod - 2B 56 10 8B 34 A1 DC CD CC B5 CF 66 5E 43 94 5E 09 9F 34 A3
new byte[] { 0x2B, 0x56, 0x10, 0x8B, 0x34, 0xA1, 0xDC, 0xCD, 0xCC, 0xB5, 0xCF, 0x66, 0x5E, 0x43, 0x94, 0x5E, 0x09, 0x9F, 0x34, 0xA3 },
- // ModuleVB01.mod - A7 F0 25 28 0F 3C 29 2E 83 90 F0 FA A7 13 8E E4 54 16 D7 A0
+ // ModuleVB01.mod - A7 F0 25 28 0F 3C 29 2E 83 90 F0 FA A7 13 8E E4 54 16 D7 A0
new byte[] { 0xA7, 0xF0, 0x25, 0x28, 0x0F, 0x3C, 0x29, 0x2E, 0x83, 0x90, 0xF0, 0xFA, 0xA7, 0x13, 0x8E, 0xE4, 0x54, 0x16, 0xD7, 0xA0 }
};
@@ -520,7 +699,7 @@ namespace System.Reflection.Metadata.Tests
/// <summary>
/// ModuleRef Table Columns:
/// Name (offset to #String)
- /// -----------------------------
+ /// -----------------------------
/// File Table Columns:
/// Name (offset to #String)
/// Flags (4 byte uint)
@@ -534,7 +713,7 @@ namespace System.Reflection.Metadata.Tests
var expHashs = new byte[][]
{
// ModuleCS00.mod
- // new byte [] { 0xd4, 0x6b, 0xec, 0x25, 0x47, 0x01, 0x20, 0x30, 0x05, 0x42, 0x34, 0x4b, 0x31, 0x22, 0x44, 0xd8, 0x1c, 0x87, 0xd0, 0x98 },
+ // new byte [] { 0xd4, 0x6b, 0xec, 0x25, 0x47, 0x01, 0x20, 0x30, 0x05, 0x42, 0x34, 0x4b, 0x31, 0x22, 0x44, 0xd8, 0x1c, 0x87, 0xd0, 0x98 },
};
// ModuleVB01
@@ -837,7 +1016,7 @@ namespace System.Reflection.Metadata.Tests
// var expNest = new bool[] { false, false, false, true, true, true, true };
// count is calc-ed by the smaller of last row of table OR next row in EventMap table
- // TODO: check with DEV - too much work to figure out, hard code for now - property, event
+ // TODO: check with DEV - too much work to figure out, hard code for now - property, event
var expMemberCount = new uint[]
{
/*<Module>*/0, 0, /*ModVBClass*/ 2, 0, /*ModVBStruct*/ 0, 1,
@@ -916,13 +1095,13 @@ namespace System.Reflection.Metadata.Tests
/// of it) report correct values for their child namespaces, types, etc. All namespaces in the module are expected
/// to be listed in the allNamespaces array. Additionally, the global namespace is expected to have type definitions
/// for GlobalClassA, GlobalClassB, and Module. No type forwarder declarations are expected.
- ///
+ ///
/// All namespaces that aren't the global NS are expected to have type definitions equal to the array
/// @namespaceName.Split('.')
/// So, ns1.Ns2.NS3 is expected to have type definitions
/// {"ns1", "Ns2", "NS3"}.
- ///
- /// definitionExceptions and forwarderExceptions may be used to override the default expectations. Pass in
+ ///
+ /// definitionExceptions and forwarderExceptions may be used to override the default expectations. Pass in
/// namespace (key) and what is expected (list of strings) for each exception.
/// </summary>
private void ValidateNamespaceChildren(
@@ -1802,7 +1981,7 @@ namespace System.Reflection.Metadata.Tests
{
// CSModule1
var expTDef = new int[] { 0x02000007, 0x2000008 }; // class other who implements the interface
- var expIfs = new int[] { 0x1b000001, 0x1b000002 }; // TypeSpec table
+ var expIfs = new int[] { 0x1b000001, 0x1b000002 }; // TypeSpec table
var reader = GetMetadataReader(NetModule.ModuleCS01, true);
Assert.Equal(2, reader.InterfaceImplTable.NumberOfRows);
@@ -1999,7 +2178,7 @@ namespace System.Reflection.Metadata.Tests
// class other who implements the interface
// InteropImpl
var comClassRids = new int[] { 2, 3, 4 }; // , 0x02000002, 0x2000003, 0x2000004, };
- // TypeDef/Ref/Spec table
+ // TypeDef/Ref/Spec table
var comInterface = new int[] { 0x01000002, 0x01000004, 0x01000005, };
// CSModule1
@@ -2162,7 +2341,7 @@ namespace System.Reflection.Metadata.Tests
/// MethodSemantics Table
/// Semantic (2-byte unsigned)
/// Method (RID to method table)
- /// Association (Token)
+ /// Association (Token)
/// </summary>
[Fact]
public void ValidateMethodSemanticsTable()
@@ -2465,6 +2644,23 @@ namespace System.Reflection.Metadata.Tests
}
[Fact]
+ public void DebugMetadataHeader()
+ {
+ var pdbBlob = PortablePdbs.DocumentsPdb;
+ using (var provider = MetadataReaderProvider.FromPortablePdbStream(new MemoryStream(pdbBlob)))
+ {
+ var reader = provider.GetMetadataReader();
+
+ Assert.Equal(default, reader.DebugMetadataHeader.EntryPoint);
+ AssertEx.Equal(new byte[] { 0x89, 0x03, 0x86, 0xAD, 0xFF, 0x27, 0x56, 0x46, 0x9F, 0x3F, 0xE2, 0x18, 0x4B, 0xEF, 0xFC, 0xC0, 0xBE, 0x0C, 0x52, 0xA0 }, reader.DebugMetadataHeader.Id);
+ Assert.Equal(0x7c, reader.DebugMetadataHeader.IdStartOffset);
+
+ var slice = pdbBlob.AsSpan(reader.DebugMetadataHeader.IdStartOffset, reader.DebugMetadataHeader.Id.Length);
+ AssertEx.Equal(reader.DebugMetadataHeader.Id, slice.ToArray());
+ }
+ }
+
+ [Fact]
public void GetCustomDebugInformation()
{
using (var provider = MetadataReaderProvider.FromPortablePdbStream(new MemoryStream(PortablePdbs.DocumentsPdb)))
diff --git a/src/System.Reflection.Metadata/tests/Metadata/PortablePdb/StandalonePortablePdbStreamTests.cs b/src/System.Reflection.Metadata/tests/Metadata/PortablePdb/StandalonePortablePdbStreamTests.cs
index 558d3be48f..a273fc24a0 100644
--- a/src/System.Reflection.Metadata/tests/Metadata/PortablePdb/StandalonePortablePdbStreamTests.cs
+++ b/src/System.Reflection.Metadata/tests/Metadata/PortablePdb/StandalonePortablePdbStreamTests.cs
@@ -14,7 +14,7 @@ namespace System.Reflection.Metadata.Tests
{
fixed (byte* bufferPtr = &buffer[0])
{
- MetadataReader.ReadStandalonePortablePdbStream(new MemoryBlock(bufferPtr, buffer.Length), out header, out externalRowCounts);
+ MetadataReader.ReadStandalonePortablePdbStream(new MemoryBlock(bufferPtr, buffer.Length), 0, out header, out externalRowCounts);
}
}
diff --git a/src/System.Reflection.Metadata/tests/Metadata/TypeSystem/TypeDefinitionTests.cs b/src/System.Reflection.Metadata/tests/Metadata/TypeSystem/TypeDefinitionTests.cs
new file mode 100644
index 0000000000..3eb1b5faae
--- /dev/null
+++ b/src/System.Reflection.Metadata/tests/Metadata/TypeSystem/TypeDefinitionTests.cs
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.Reflection.Metadata.Tests
+{
+ public class TypeDefinitionTests
+ {
+ [Fact]
+ public void ValidateTypeDefinitionIsNestedNoProjection()
+ {
+ var reader = MetadataReaderTests.GetMetadataReader(Namespace.NamespaceTests, options: MetadataReaderOptions.None);
+
+ foreach (var typeDefHandle in reader.TypeDefinitions)
+ {
+ var typeDef = reader.GetTypeDefinition(typeDefHandle);
+
+ Assert.Equal(typeDef.Attributes.IsNested(), typeDef.IsNested);
+ }
+ }
+
+ [Fact]
+ public void ValidateTypeDefinitionIsNestedWindowsProjection()
+ {
+ var reader = MetadataReaderTests.GetMetadataReader(Namespace.NamespaceTests, options: MetadataReaderOptions.ApplyWindowsRuntimeProjections);
+
+ foreach (var typeDefHandle in reader.TypeDefinitions)
+ {
+ var typeDef = reader.GetTypeDefinition(typeDefHandle);
+
+ Assert.Equal(typeDef.Attributes.IsNested(), typeDef.IsNested);
+ }
+ }
+ }
+}
diff --git a/src/System.Reflection.Metadata/tests/PortableExecutable/DebugDirectoryBuilderTests.cs b/src/System.Reflection.Metadata/tests/PortableExecutable/DebugDirectoryBuilderTests.cs
index 62638b6cf3..c0d97edf7b 100644
--- a/src/System.Reflection.Metadata/tests/PortableExecutable/DebugDirectoryBuilderTests.cs
+++ b/src/System.Reflection.Metadata/tests/PortableExecutable/DebugDirectoryBuilderTests.cs
@@ -46,6 +46,16 @@ namespace System.Reflection.PortableExecutable.Tests
}
[Fact]
+ public void AddPdbChecksumEntry_Args()
+ {
+ var builder = new DebugDirectoryBuilder();
+ AssertExtensions.Throws<ArgumentNullException>("algorithmName", () => builder.AddPdbChecksumEntry(null, ImmutableArray.Create((byte)1)));
+ AssertExtensions.Throws<ArgumentException>("algorithmName", () => builder.AddPdbChecksumEntry("", ImmutableArray.Create((byte)1)));
+ AssertExtensions.Throws<ArgumentNullException>("checksum", () => builder.AddPdbChecksumEntry("XXX", default));
+ AssertExtensions.Throws<ArgumentException>("checksum", () => builder.AddPdbChecksumEntry("XXX", ImmutableArray<byte>.Empty));
+ }
+
+ [Fact]
public void Empty()
{
var b = new DebugDirectoryBuilder();
@@ -304,5 +314,95 @@ namespace System.Reflection.PortableExecutable.Tests
}
}
}
+
+ [Fact]
+ public void AddPdbChecksumEntry()
+ {
+ var b = new DebugDirectoryBuilder();
+
+ b.AddPdbChecksumEntry("A", ImmutableArray.Create(new byte[] { 0x01 }));
+ b.AddPdbChecksumEntry("B", ImmutableArray.Create(new byte[] { 0x02, 0x03 }));
+ b.AddPdbChecksumEntry("XYZ", ImmutableArray.Create(new byte[] { 0x04, 0x05, 0x06 }));
+
+ var blob = new BlobBuilder();
+ b.Serialize(blob, new SectionLocation(0x1000, 0x2000), 0x50);
+ AssertEx.Equal(new byte[]
+ {
+ 0x00, 0x00, 0x00, 0x00, // Characteristics
+ 0x00, 0x00, 0x00, 0x00, // Stamp
+ 0x01, 0x00, 0x00, 0x00, // Version
+ 0x13, 0x00, 0x00, 0x00, // Type
+ 0x03, 0x00, 0x00, 0x00, // SizeOfData
+ 0xA4, 0x10, 0x00, 0x00, // AddressOfRawData
+ 0xA4, 0x20, 0x00, 0x00, // PointerToRawData
+
+ 0x00, 0x00, 0x00, 0x00, // Characteristics
+ 0x00, 0x00, 0x00, 0x00, // Stamp
+ 0x01, 0x00, 0x00, 0x00, // Version
+ 0x13, 0x00, 0x00, 0x00, // Type
+ 0x04, 0x00, 0x00, 0x00, // SizeOfData
+ 0xA7, 0x10, 0x00, 0x00, // AddressOfRawData
+ 0xA7, 0x20, 0x00, 0x00, // PointerToRawData
+
+ 0x00, 0x00, 0x00, 0x00, // Characteristics
+ 0x00, 0x00, 0x00, 0x00, // Stamp
+ 0x01, 0x00, 0x00, 0x00, // Version
+ 0x13, 0x00, 0x00, 0x00, // Type
+ 0x07, 0x00, 0x00, 0x00, // SizeOfData
+ 0xAB, 0x10, 0x00, 0x00, // AddressOfRawData
+ 0xAB, 0x20, 0x00, 0x00, // PointerToRawData
+
+ // data
+ (byte)'A', 0x00,
+ 0x01,
+
+ // data
+ (byte)'B', 0x00,
+ 0x02, 0x03,
+
+ // data
+ (byte)'X', (byte)'Y', (byte)'Z', 0x00,
+ 0x04, 0x05, 0x06,
+ }, blob.ToArray());
+ }
+
+ [Fact]
+ public void AddCustomEntry()
+ {
+ var b = new DebugDirectoryBuilder();
+
+ b.AddEntry((DebugDirectoryEntryType)0xA1, version: 0x12345678, stamp: 0xB1C1D1E1);
+
+ b.AddEntry((DebugDirectoryEntryType)0xA2, version: 0xFFFFFFFF, stamp: 0xFFFFFFFF, (a: 1, b: 2), (builder, data) =>
+ {
+ builder.WriteInt32(data.a);
+ builder.WriteInt32(data.b);
+ });
+
+ var blob = new BlobBuilder();
+ b.Serialize(blob, new SectionLocation(0x1000, 0x2000), 0x50);
+ AssertEx.Equal(new byte[]
+ {
+ 0x00, 0x00, 0x00, 0x00, // Characteristics
+ 0xE1, 0xD1, 0xC1, 0xB1, // Stamp
+ 0x78, 0x56, 0x34, 0x12, // Version
+ 0xA1, 0x00, 0x00, 0x00, // Type
+ 0x00, 0x00, 0x00, 0x00, // SizeOfData
+ 0x00, 0x00, 0x00, 0x00, // AddressOfRawData
+ 0x00, 0x00, 0x00, 0x00, // PointerToRawData
+
+ 0x00, 0x00, 0x00, 0x00, // Characteristics
+ 0xFF, 0xFF, 0xFF, 0xFF, // Stamp
+ 0xFF, 0xFF, 0xFF, 0xFF, // Version
+ 0xA2, 0x00, 0x00, 0x00, // Type
+ 0x08, 0x00, 0x00, 0x00, // SizeOfData
+ 0x88, 0x10, 0x00, 0x00, // AddressOfRawData
+ 0x88, 0x20, 0x00, 0x00, // PointerToRawData
+
+ // data
+ 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00
+ }, blob.ToArray());
+ }
}
}
diff --git a/src/System.Reflection.Metadata/tests/PortableExecutable/DebugDirectoryTests.cs b/src/System.Reflection.Metadata/tests/PortableExecutable/DebugDirectoryTests.cs
index 731755365c..05cfd1ff17 100644
--- a/src/System.Reflection.Metadata/tests/PortableExecutable/DebugDirectoryTests.cs
+++ b/src/System.Reflection.Metadata/tests/PortableExecutable/DebugDirectoryTests.cs
@@ -364,5 +364,56 @@ namespace System.Reflection.PortableExecutable.Tests
Assert.Throws<BadImageFormatException>(() => PEReader.DecodeEmbeddedPortablePdbDebugDirectoryData(block));
}
}
+
+ [Fact]
+ public void PdbChecksum()
+ {
+ var bytes = ImmutableArray.Create(new byte[]
+ {
+ (byte)'A', (byte)'L', (byte)'G', 0, // AlgorithmName
+ 0x01, 0x02, 0x03, 0x04, 0x05 // checksum
+ });
+
+ using (var block = new ByteArrayMemoryProvider(bytes).GetMemoryBlock(0, bytes.Length))
+ {
+ var data = PEReader.DecodePdbChecksumDebugDirectoryData(block);
+ Assert.Equal("ALG", data.AlgorithmName);
+ AssertEx.Equal(new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05 }, data.Checksum);
+ }
+ }
+
+ [Theory]
+ [InlineData(new byte[]
+ {
+ 0, // AlgorithmName
+ 0x01, 0x02, 0x03, 0x04, 0x05 // checksum
+ })]
+ [InlineData(new byte[]
+ {
+ 0x01,
+ 0x01, 0x02, 0x03, 0x04, 0x05
+ })]
+ [InlineData(new byte[]
+ {
+ 0x01, 0x00
+ })]
+ [InlineData(new byte[]
+ {
+ 0x00
+ })]
+ [InlineData(new byte[]
+ {
+ 0x01
+ })]
+ [InlineData(new byte[0])]
+ public void PdbChecksum_Errors(byte[] blob)
+ {
+ var bytes = ImmutableArray.Create(blob);
+
+ using (var block = new ByteArrayMemoryProvider(bytes).GetMemoryBlock(0, bytes.Length))
+ {
+ Assert.Throws<BadImageFormatException>(() => PEReader.DecodePdbChecksumDebugDirectoryData(block));
+ }
+ }
}
}
diff --git a/src/System.Reflection.Metadata/tests/PortableExecutable/PEReaderTests.cs b/src/System.Reflection.Metadata/tests/PortableExecutable/PEReaderTests.cs
index af5d099afe..0b2ce01c87 100644
--- a/src/System.Reflection.Metadata/tests/PortableExecutable/PEReaderTests.cs
+++ b/src/System.Reflection.Metadata/tests/PortableExecutable/PEReaderTests.cs
@@ -3,10 +3,12 @@
// See the LICENSE file in the project root for more information.
using System;
+using System.Collections.Immutable;
using System.IO;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Reflection.Metadata.Tests;
+using System.Runtime.CompilerServices;
using Xunit;
namespace System.Reflection.PortableExecutable.Tests
@@ -833,5 +835,20 @@ namespace System.Reflection.PortableExecutable.Tests
embeddedPdbProvider.Dispose();
}
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static MetadataReader GetMetadataReaderFromPEReader()
+ => new PEReader(Misc.Debug.ToImmutableArray()).GetMetadataReader();
+
+ [Fact, MethodImpl(MethodImplOptions.NoOptimization)]
+ public void KeepMetadataAlive()
+ {
+ var reader = GetMetadataReaderFromPEReader();
+
+ GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, blocking: true, compacting: true);
+ GC.WaitForPendingFinalizers();
+
+ Assert.Equal(@"Debug", reader.GetString(reader.GetAssemblyDefinition().Name));
+ }
}
}
diff --git a/src/System.Reflection.Metadata/tests/System.Reflection.Metadata.Tests.csproj b/src/System.Reflection.Metadata/tests/System.Reflection.Metadata.Tests.csproj
index d3cceecb20..b73e3481c6 100644
--- a/src/System.Reflection.Metadata/tests/System.Reflection.Metadata.Tests.csproj
+++ b/src/System.Reflection.Metadata/tests/System.Reflection.Metadata.Tests.csproj
@@ -60,6 +60,7 @@
<Compile Include="Metadata\PortablePdb\StandalonePortablePdbStreamTests.cs" />
<Compile Include="Metadata\TagToTokenTests.cs" />
<Compile Include="Metadata\PortablePdb\DocumentNameTests.cs" />
+ <Compile Include="Metadata\TypeSystem\TypeDefinitionTests.cs" />
<Compile Include="PortableExecutable\DebugDirectoryBuilderTests.cs" />
<Compile Include="PortableExecutable\PEHeaderBuilderTests.cs" />
<Compile Include="PortableExecutable\PEMemoryBlockTests.cs" />
diff --git a/src/System.Reflection.TypeExtensions/pkg/System.Reflection.TypeExtensions.pkgproj b/src/System.Reflection.TypeExtensions/pkg/System.Reflection.TypeExtensions.pkgproj
index eef231f237..241c0841d6 100644
--- a/src/System.Reflection.TypeExtensions/pkg/System.Reflection.TypeExtensions.pkgproj
+++ b/src/System.Reflection.TypeExtensions/pkg/System.Reflection.TypeExtensions.pkgproj
@@ -17,9 +17,9 @@
</ItemGroup>
<ItemGroup>
<InboxOnTargetFramework Include="netcoreapp2.0" />
- <InboxOnTargetFramework Include="$(UAPvNextTFM)" />
+ <InboxOnTargetFramework Include="uap10.0.16299" />
<File Include="$(PlaceholderFile)">
- <TargetPath>runtimes/aot/lib/$(UAPvNextTFM)</TargetPath>
+ <TargetPath>runtimes/aot/lib/uap10.0.16299</TargetPath>
</File>
<InboxOnTargetFramework Include="MonoAndroid10" />
<InboxOnTargetFramework Include="MonoTouch10" />
diff --git a/src/System.Reflection/ref/System.Reflection.Manual.cs b/src/System.Reflection/ref/System.Reflection.Manual.cs
deleted file mode 100644
index 0a39984a22..0000000000
--- a/src/System.Reflection/ref/System.Reflection.Manual.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-// ------------------------------------------------------------------------------
-// Changes to this file must follow the http://aka.ms/api-review process.
-// ------------------------------------------------------------------------------
-
-
-// This is only needed for COMAwareEventInfo to inherit from EventInfo. Next version when
-// Reflection is extensible then we should remove this InternalsVisibleTo.
-[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("System.Runtime.InteropServices, PublicKey=002400000480000094000000060200000024000052534131000400000100010007D1FA57C4AED9F0A32E84AA0FAEFD0DE9E8FD6AEC8F87FB03766C834C99921EB23BE79AD9D5DCC1DD9AD236132102900B723CF980957FC4E177108FC607774F29E8320E92EA05ECE4E821C0A5EFE8F1645C4C0C93C1AB99285D622CAA652C1DFAD63D745D6F2DE5F17E5EAF0FC4963D261C8A12436518206DC093344D5AD293")]
-
-// This is required so that AssemblyBuilder can derive from Assembly.
-[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("System.Reflection.Emit, PublicKey=002400000480000094000000060200000024000052534131000400000100010007D1FA57C4AED9F0A32E84AA0FAEFD0DE9E8FD6AEC8F87FB03766C834C99921EB23BE79AD9D5DCC1DD9AD236132102900B723CF980957FC4E177108FC607774F29E8320E92EA05ECE4E821C0A5EFE8F1645C4C0C93C1AB99285D622CAA652C1DFAD63D745D6F2DE5F17E5EAF0FC4963D261C8A12436518206DC093344D5AD293")]
-
-// This is required so that DynamicMethod can derive from MethodInfo.
-[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("System.Reflection.Emit.Lightweight, PublicKey=002400000480000094000000060200000024000052534131000400000100010007D1FA57C4AED9F0A32E84AA0FAEFD0DE9E8FD6AEC8F87FB03766C834C99921EB23BE79AD9D5DCC1DD9AD236132102900B723CF980957FC4E177108FC607774F29E8320E92EA05ECE4E821C0A5EFE8F1645C4C0C93C1AB99285D622CAA652C1DFAD63D745D6F2DE5F17E5EAF0FC4963D261C8A12436518206DC093344D5AD293")]
diff --git a/src/System.Reflection/ref/System.Reflection.csproj b/src/System.Reflection/ref/System.Reflection.csproj
index 5552d0bd11..4fe56e1f77 100644
--- a/src/System.Reflection/ref/System.Reflection.csproj
+++ b/src/System.Reflection/ref/System.Reflection.csproj
@@ -10,7 +10,6 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="System.Reflection.cs" />
- <Compile Include="System.Reflection.Manual.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\System.Runtime\ref\System.Runtime.csproj" />
diff --git a/src/System.Runtime.Caching/System.Runtime.Caching.sln b/src/System.Runtime.Caching/System.Runtime.Caching.sln
index 88875dcdcf..e470f68e2f 100644
--- a/src/System.Runtime.Caching/System.Runtime.Caching.sln
+++ b/src/System.Runtime.Caching/System.Runtime.Caching.sln
@@ -1,90 +1,50 @@
-
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27108.1
+# Visual Studio 14
+VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{F19CC87B-3230-42BF-8C1F-88F4F5EDE153}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Runtime.Caching.Tests", "tests\System.Runtime.Caching.Tests.csproj", "{397E49A7-EB26-4368-8F46-D78B98F4A971}"
+ ProjectSection(ProjectDependencies) = postProject
+ {A7B6FB6E-F484-42D7-8A5E-F7D0DCC03829} = {A7B6FB6E-F484-42D7-8A5E-F7D0DCC03829}
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Runtime.Caching", "src\System.Runtime.Caching.csproj", "{A7B6FB6E-F484-42D7-8A5E-F7D0DCC03829}"
+ ProjectSection(ProjectDependencies) = postProject
+ {3B7A97BD-F4DC-4FF9-AB6D-3B714E5D9280} = {3B7A97BD-F4DC-4FF9-AB6D-3B714E5D9280}
+ EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Runtime.Caching", "ref\System.Runtime.Caching.csproj", "{3B7A97BD-F4DC-4FF9-AB6D-3B714E5D9280}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{9EC38C79-BC41-4675-AB3D-A509BDC14FE0}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{1A2F9F4A-A032-433E-B914-ADD5992BB178}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Runtime.Caching", "src\System.Runtime.Caching.csproj", "{A7B6FB6E-F484-42D7-8A5E-F7D0DCC03829}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E107E9C1-E893-4E87-987E-04EF0DCEAEFD}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{D4DA8C10-76FA-49D3-B4F2-BCB0C94330F6}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Runtime.Caching.Tests", "tests\System.Runtime.Caching.Tests.csproj", "{397E49A7-EB26-4368-8F46-D78B98F4A971}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{2E666815-2EDB-464B-9DF6-380BF4789AD4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
- netcoreapp-Windows_NT-Debug|Any CPU = netcoreapp-Windows_NT-Debug|Any CPU
- netcoreapp-Windows_NT-Release|Any CPU = netcoreapp-Windows_NT-Release|Any CPU
- netfx-Debug|Any CPU = netfx-Debug|Any CPU
- netfx-Release|Any CPU = netfx-Release|Any CPU
- netstandard-Debug|Any CPU = netstandard-Debug|Any CPU
- netstandard-Release|Any CPU = netstandard-Release|Any CPU
- netstandard-Windows_NT-Debug|Any CPU = netstandard-Windows_NT-Debug|Any CPU
- netstandard-Windows_NT-Release|Any CPU = netstandard-Windows_NT-Release|Any CPU
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {3B7A97BD-F4DC-4FF9-AB6D-3B714E5D9280}.netcoreapp-Windows_NT-Debug|Any CPU.ActiveCfg = netstandard-Release|Any CPU
- {3B7A97BD-F4DC-4FF9-AB6D-3B714E5D9280}.netcoreapp-Windows_NT-Debug|Any CPU.Build.0 = netstandard-Release|Any CPU
- {3B7A97BD-F4DC-4FF9-AB6D-3B714E5D9280}.netcoreapp-Windows_NT-Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
- {3B7A97BD-F4DC-4FF9-AB6D-3B714E5D9280}.netcoreapp-Windows_NT-Release|Any CPU.Build.0 = netstandard-Release|Any CPU
- {3B7A97BD-F4DC-4FF9-AB6D-3B714E5D9280}.netfx-Debug|Any CPU.ActiveCfg = netfx-Debug|Any CPU
- {3B7A97BD-F4DC-4FF9-AB6D-3B714E5D9280}.netfx-Debug|Any CPU.Build.0 = netfx-Debug|Any CPU
- {3B7A97BD-F4DC-4FF9-AB6D-3B714E5D9280}.netfx-Release|Any CPU.ActiveCfg = netfx-Release|Any CPU
- {3B7A97BD-F4DC-4FF9-AB6D-3B714E5D9280}.netfx-Release|Any CPU.Build.0 = netfx-Release|Any CPU
- {3B7A97BD-F4DC-4FF9-AB6D-3B714E5D9280}.netstandard-Debug|Any CPU.ActiveCfg = netstandard-Debug|Any CPU
- {3B7A97BD-F4DC-4FF9-AB6D-3B714E5D9280}.netstandard-Debug|Any CPU.Build.0 = netstandard-Debug|Any CPU
- {3B7A97BD-F4DC-4FF9-AB6D-3B714E5D9280}.netstandard-Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
- {3B7A97BD-F4DC-4FF9-AB6D-3B714E5D9280}.netstandard-Release|Any CPU.Build.0 = netstandard-Release|Any CPU
- {3B7A97BD-F4DC-4FF9-AB6D-3B714E5D9280}.netstandard-Windows_NT-Debug|Any CPU.ActiveCfg = netstandard-Release|Any CPU
- {3B7A97BD-F4DC-4FF9-AB6D-3B714E5D9280}.netstandard-Windows_NT-Debug|Any CPU.Build.0 = netstandard-Release|Any CPU
- {3B7A97BD-F4DC-4FF9-AB6D-3B714E5D9280}.netstandard-Windows_NT-Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
- {3B7A97BD-F4DC-4FF9-AB6D-3B714E5D9280}.netstandard-Windows_NT-Release|Any CPU.Build.0 = netstandard-Release|Any CPU
- {A7B6FB6E-F484-42D7-8A5E-F7D0DCC03829}.netcoreapp-Windows_NT-Debug|Any CPU.ActiveCfg = netstandard-Release|Any CPU
- {A7B6FB6E-F484-42D7-8A5E-F7D0DCC03829}.netcoreapp-Windows_NT-Debug|Any CPU.Build.0 = netstandard-Release|Any CPU
- {A7B6FB6E-F484-42D7-8A5E-F7D0DCC03829}.netcoreapp-Windows_NT-Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
- {A7B6FB6E-F484-42D7-8A5E-F7D0DCC03829}.netcoreapp-Windows_NT-Release|Any CPU.Build.0 = netstandard-Release|Any CPU
- {A7B6FB6E-F484-42D7-8A5E-F7D0DCC03829}.netfx-Debug|Any CPU.ActiveCfg = netstandard-Release|Any CPU
- {A7B6FB6E-F484-42D7-8A5E-F7D0DCC03829}.netfx-Debug|Any CPU.Build.0 = netstandard-Release|Any CPU
- {A7B6FB6E-F484-42D7-8A5E-F7D0DCC03829}.netfx-Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
- {A7B6FB6E-F484-42D7-8A5E-F7D0DCC03829}.netfx-Release|Any CPU.Build.0 = netstandard-Release|Any CPU
- {A7B6FB6E-F484-42D7-8A5E-F7D0DCC03829}.netstandard-Debug|Any CPU.ActiveCfg = netstandard-Debug|Any CPU
- {A7B6FB6E-F484-42D7-8A5E-F7D0DCC03829}.netstandard-Debug|Any CPU.Build.0 = netstandard-Debug|Any CPU
- {A7B6FB6E-F484-42D7-8A5E-F7D0DCC03829}.netstandard-Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
- {A7B6FB6E-F484-42D7-8A5E-F7D0DCC03829}.netstandard-Release|Any CPU.Build.0 = netstandard-Release|Any CPU
- {A7B6FB6E-F484-42D7-8A5E-F7D0DCC03829}.netstandard-Windows_NT-Debug|Any CPU.ActiveCfg = netstandard-Windows_NT-Debug|Any CPU
- {A7B6FB6E-F484-42D7-8A5E-F7D0DCC03829}.netstandard-Windows_NT-Debug|Any CPU.Build.0 = netstandard-Windows_NT-Debug|Any CPU
- {A7B6FB6E-F484-42D7-8A5E-F7D0DCC03829}.netstandard-Windows_NT-Release|Any CPU.ActiveCfg = netstandard-Windows_NT-Release|Any CPU
- {A7B6FB6E-F484-42D7-8A5E-F7D0DCC03829}.netstandard-Windows_NT-Release|Any CPU.Build.0 = netstandard-Windows_NT-Release|Any CPU
- {397E49A7-EB26-4368-8F46-D78B98F4A971}.netcoreapp-Windows_NT-Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU
- {397E49A7-EB26-4368-8F46-D78B98F4A971}.netcoreapp-Windows_NT-Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
- {397E49A7-EB26-4368-8F46-D78B98F4A971}.netcoreapp-Windows_NT-Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
- {397E49A7-EB26-4368-8F46-D78B98F4A971}.netcoreapp-Windows_NT-Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU
- {397E49A7-EB26-4368-8F46-D78B98F4A971}.netfx-Debug|Any CPU.ActiveCfg = netfx-Debug|Any CPU
- {397E49A7-EB26-4368-8F46-D78B98F4A971}.netfx-Debug|Any CPU.Build.0 = netfx-Debug|Any CPU
- {397E49A7-EB26-4368-8F46-D78B98F4A971}.netfx-Release|Any CPU.ActiveCfg = netfx-Release|Any CPU
- {397E49A7-EB26-4368-8F46-D78B98F4A971}.netfx-Release|Any CPU.Build.0 = netfx-Release|Any CPU
- {397E49A7-EB26-4368-8F46-D78B98F4A971}.netstandard-Debug|Any CPU.ActiveCfg = netfx-Release|Any CPU
- {397E49A7-EB26-4368-8F46-D78B98F4A971}.netstandard-Debug|Any CPU.Build.0 = netfx-Release|Any CPU
- {397E49A7-EB26-4368-8F46-D78B98F4A971}.netstandard-Release|Any CPU.ActiveCfg = netfx-Release|Any CPU
- {397E49A7-EB26-4368-8F46-D78B98F4A971}.netstandard-Release|Any CPU.Build.0 = netfx-Release|Any CPU
- {397E49A7-EB26-4368-8F46-D78B98F4A971}.netstandard-Windows_NT-Debug|Any CPU.ActiveCfg = netfx-Release|Any CPU
- {397E49A7-EB26-4368-8F46-D78B98F4A971}.netstandard-Windows_NT-Debug|Any CPU.Build.0 = netfx-Release|Any CPU
- {397E49A7-EB26-4368-8F46-D78B98F4A971}.netstandard-Windows_NT-Release|Any CPU.ActiveCfg = netfx-Release|Any CPU
- {397E49A7-EB26-4368-8F46-D78B98F4A971}.netstandard-Windows_NT-Release|Any CPU.Build.0 = netfx-Release|Any CPU
+ {397E49A7-EB26-4368-8F46-D78B98F4A971}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU
+ {397E49A7-EB26-4368-8F46-D78B98F4A971}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
+ {397E49A7-EB26-4368-8F46-D78B98F4A971}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
+ {397E49A7-EB26-4368-8F46-D78B98F4A971}.Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU
+ {A7B6FB6E-F484-42D7-8A5E-F7D0DCC03829}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU
+ {A7B6FB6E-F484-42D7-8A5E-F7D0DCC03829}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
+ {A7B6FB6E-F484-42D7-8A5E-F7D0DCC03829}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
+ {A7B6FB6E-F484-42D7-8A5E-F7D0DCC03829}.Release|Any CPU.Build.0 = netcoreapp-Windows_NT-Release|Any CPU
+ {3B7A97BD-F4DC-4FF9-AB6D-3B714E5D9280}.Debug|Any CPU.ActiveCfg = netstandard-Debug|Any CPU
+ {3B7A97BD-F4DC-4FF9-AB6D-3B714E5D9280}.Debug|Any CPU.Build.0 = netstandard-Debug|Any CPU
+ {3B7A97BD-F4DC-4FF9-AB6D-3B714E5D9280}.Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
+ {3B7A97BD-F4DC-4FF9-AB6D-3B714E5D9280}.Release|Any CPU.Build.0 = netstandard-Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
- {3B7A97BD-F4DC-4FF9-AB6D-3B714E5D9280} = {F19CC87B-3230-42BF-8C1F-88F4F5EDE153}
- {A7B6FB6E-F484-42D7-8A5E-F7D0DCC03829} = {9EC38C79-BC41-4675-AB3D-A509BDC14FE0}
- {397E49A7-EB26-4368-8F46-D78B98F4A971} = {D4DA8C10-76FA-49D3-B4F2-BCB0C94330F6}
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {D3D6D992-CDEE-4C0C-83A6-E2EF77383E5C}
+ {397E49A7-EB26-4368-8F46-D78B98F4A971} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
+ {A7B6FB6E-F484-42D7-8A5E-F7D0DCC03829} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD}
+ {3B7A97BD-F4DC-4FF9-AB6D-3B714E5D9280} = {2E666815-2EDB-464B-9DF6-380BF4789AD4}
EndGlobalSection
EndGlobal
diff --git a/src/System.Runtime.Caching/pkg/System.Runtime.Caching.pkgproj b/src/System.Runtime.Caching/pkg/System.Runtime.Caching.pkgproj
index a2ce422ccb..946133d246 100644
--- a/src/System.Runtime.Caching/pkg/System.Runtime.Caching.pkgproj
+++ b/src/System.Runtime.Caching/pkg/System.Runtime.Caching.pkgproj
@@ -3,7 +3,7 @@
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<ProjectReference Include="..\ref\System.Runtime.Caching.csproj">
- <SupportedFramework>netcoreapp2.0;net45;$(AllXamarinFrameworks)</SupportedFramework>
+ <SupportedFramework>uap10.0.16299;netcoreapp2.0;net45;$(AllXamarinFrameworks)</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\src\System.Runtime.Caching.csproj" />
<InboxOnTargetFramework Include="net45">
diff --git a/src/System.Runtime.Caching/src/Configurations.props b/src/System.Runtime.Caching/src/Configurations.props
index 84577c8a06..f1bf1fb00d 100644
--- a/src/System.Runtime.Caching/src/Configurations.props
+++ b/src/System.Runtime.Caching/src/Configurations.props
@@ -4,10 +4,12 @@
<PackageConfigurations>
netstandard;
netcoreapp2.0-Windows_NT;
+ netcoreapp2.0-Unix;
</PackageConfigurations>
<BuildConfigurations>
$(PackageConfigurations);
netcoreapp-Windows_NT;
+ netcoreapp-Unix;
_netfx;
</BuildConfigurations>
</PropertyGroup>
diff --git a/src/System.Runtime.Caching/src/MatchingRefApiCompatBaseline.txt b/src/System.Runtime.Caching/src/MatchingRefApiCompatBaseline.txt
new file mode 100644
index 0000000000..ad5de574e0
--- /dev/null
+++ b/src/System.Runtime.Caching/src/MatchingRefApiCompatBaseline.txt
@@ -0,0 +1,6 @@
+Compat issues with assembly System.Runtime.Caching:
+TypesMustExist : Type 'System.Runtime.Caching.Configuration.CachingSectionGroup' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.Runtime.Caching.Configuration.MemoryCacheElement' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.Runtime.Caching.Configuration.MemoryCacheSection' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.Runtime.Caching.Configuration.MemoryCacheSettingsCollection' does not exist in the implementation but it does exist in the contract.
+Total Issues: 4
diff --git a/src/System.Runtime.Caching/src/Resources/Strings.resx b/src/System.Runtime.Caching/src/Resources/Strings.resx
index 89884bf464..9ac10ce4ed 100644
--- a/src/System.Runtime.Caching/src/Resources/Strings.resx
+++ b/src/System.Runtime.Caching/src/Resources/Strings.resx
@@ -183,4 +183,7 @@
<data name="PlatformNotSupported_Caching" xml:space="preserve">
<value>System.Runtime.Caching is not supported on this platform.</value>
</data>
+ <data name="PlatformNotSupported_PhysicalMemoryLimitPercentage" xml:space="preserve">
+ <value>The PhysicalMemoryLimitPercentage parameter is not supported on this platform.</value>
+ </data>
</root> \ No newline at end of file
diff --git a/src/System.Runtime.Caching/src/System.Runtime.Caching.csproj b/src/System.Runtime.Caching/src/System.Runtime.Caching.csproj
index 004b4ea2ab..5f1a6b7790 100644
--- a/src/System.Runtime.Caching/src/System.Runtime.Caching.csproj
+++ b/src/System.Runtime.Caching/src/System.Runtime.Caching.csproj
@@ -7,15 +7,19 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<!-- Although we have a netstandard configuration, we know we are not currently UAP compatible-->
<UWPCompatible>false</UWPCompatible>
- <GeneratePlatformNotSupportedAssemblyMessage Condition="'$(TargetsWindows)' != 'true'">SR.PlatformNotSupported_Caching</GeneratePlatformNotSupportedAssemblyMessage>
+ <GeneratePlatformNotSupportedAssemblyMessage Condition="'$(TargetGroup)' == 'netstandard'">SR.PlatformNotSupported_Caching</GeneratePlatformNotSupportedAssemblyMessage>
</PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Unix-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Unix-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
- <ItemGroup Condition="'$(TargetsWindows)' == 'true'">
+ <ItemGroup Condition="'$(TargetGroup)' != 'netstandard'">
<Compile Include="System\Runtime\Caching\_shims.cs" />
<Compile Include="System\Runtime\Caching\CacheEntryChangeMonitor.cs" />
<Compile Include="System\Runtime\Caching\CacheEntryRemovedArguments.cs" />
@@ -59,6 +63,10 @@
<Compile Include="System\Runtime\Caching\Hosting\IFileChangeNotificationSystem.cs" />
<Compile Include="System\Runtime\Caching\Hosting\IMemoryCacheManager.cs" />
<Compile Include="System\Runtime\Caching\Resources\RH.cs" />
+ </ItemGroup>
+ <ItemGroup Condition="'$(TargetsWindows)' == 'true'">
+ <Compile Include="System\Runtime\Caching\MemoryMonitor.Windows.cs" />
+ <Compile Include="System\Runtime\Caching\PhysicalMemoryMonitor.Windows.cs" />
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.GlobalMemoryStatusEx.cs">
<Link>Common\Interop\Windows\kernel32\Interop.GlobalMemoryStatusEx.cs</Link>
</Compile>
@@ -69,6 +77,9 @@
<Link>Common\Interop\Windows\Interop.Libraries.cs</Link>
</Compile>
</ItemGroup>
+ <ItemGroup Condition="'$(TargetsUnix)' == 'true'">
+ <Compile Include="System\Runtime\Caching\PhysicalMemoryMonitor.Unix.cs" />
+ </ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.Win32.Primitives" />
<Reference Include="Microsoft.Win32.Registry" />
@@ -90,6 +101,7 @@
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.Extensions" />
<Reference Include="System.Runtime.InteropServices" />
+ <Reference Include="System.Runtime.InteropServices.RuntimeInformation" />
<Reference Include="System.Security.Permissions" />
<Reference Include="System.Security.Principal.Windows" />
<Reference Include="System.Threading" />
diff --git a/src/System.Runtime.Caching/src/System/Runtime/Caching/Dbg.cs b/src/System.Runtime.Caching/src/System/Runtime/Caching/Dbg.cs
index c2b638de06..865d59fb23 100644
--- a/src/System.Runtime.Caching/src/System/Runtime/Caching/Dbg.cs
+++ b/src/System.Runtime.Caching/src/System/Runtime/Caching/Dbg.cs
@@ -413,29 +413,35 @@ namespace System.Runtime.Caching
}
private static void MonitorRegistryForOneChange() {
- // Close the open reg handle
- if (s_regHandle != null) {
- s_regHandle.Close();
- s_regHandle = null;
- }
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ // Close the open reg handle
+ if (s_regHandle != null)
+ {
+ s_regHandle.Close();
+ s_regHandle = null;
+ }
- // Open the reg key
- int result = NativeMethods.RegOpenKeyEx(NativeMethods.HKEY_LOCAL_MACHINE, s_listenKeyName, 0, NativeMethods.KEY_READ, out s_regHandle);
- if (result != 0) {
- StopRegistryMonitor();
- return;
- }
+ // Open the reg key
+ int result = NativeMethods.RegOpenKeyEx(NativeMethods.HKEY_LOCAL_MACHINE, s_listenKeyName, 0, NativeMethods.KEY_READ, out s_regHandle);
+ if (result != 0)
+ {
+ StopRegistryMonitor();
+ return;
+ }
- // Listen for changes.
- result = NativeMethods.RegNotifyChangeKeyValue(
- s_regHandle,
- true,
- NativeMethods.REG_NOTIFY_CHANGE_NAME | NativeMethods.REG_NOTIFY_CHANGE_LAST_SET,
- s_notifyEvent.SafeWaitHandle,
- true);
+ // Listen for changes.
+ result = NativeMethods.RegNotifyChangeKeyValue(
+ s_regHandle,
+ true,
+ NativeMethods.REG_NOTIFY_CHANGE_NAME | NativeMethods.REG_NOTIFY_CHANGE_LAST_SET,
+ s_notifyEvent.SafeWaitHandle,
+ true);
- if (result != 0) {
- StopRegistryMonitor();
+ if (result != 0)
+ {
+ StopRegistryMonitor();
+ }
}
}
@@ -523,8 +529,11 @@ namespace System.Runtime.Caching
}
else {
if (s_includeThreadPrefix) {
- idThread = NativeMethods.GetCurrentThreadId();
- idProcess = NativeMethods.GetCurrentProcessId();
+ idThread = Thread.CurrentThread.ManagedThreadId;
+ using(var process = Process.GetCurrentProcess())
+ {
+ idProcess = process.Id;
+ }
traceFormat = "[0x{0:x}.{1:x} {2} {3}] {4}\n{5}";
}
else {
@@ -610,6 +619,11 @@ Stack trace:
A=Exit process R=Debug I=Continue";
}
+ int idProcess = 0;
+ using (var process = Process.GetCurrentProcess())
+ {
+ idProcess = process.Id;
+ }
string dialogMessage = string.Format(
CultureInfo.InvariantCulture,
@@ -617,35 +631,9 @@ A=Exit process R=Debug I=Continue";
message,
fileName, lineNumber,
COMPONENT,
- NativeMethods.GetCurrentProcessId(), NativeMethods.GetCurrentThreadId(),
+ idProcess, Thread.CurrentThread.ManagedThreadId,
trace.ToString());
- //MBResult mbResult = new MBResult();
-
- //Thread thread = new Thread(
- // delegate() {
- // for (int i = 0; i < 100; i++) {
- // NativeMethods.MSG msg = new NativeMethods.MSG();
- // NativeMethods.PeekMessage(ref msg, new HandleRef(mbResult, IntPtr.Zero), 0, 0, NativeMethods.PM_REMOVE);
- // }
-
- // mbResult.Result = NativeMethods.MessageBox(new HandleRef(mbResult, IntPtr.Zero), dialogMessage, PRODUCT + " Assertion",
- // NativeMethods.MB_SERVICE_NOTIFICATION |
- // NativeMethods.MB_TOPMOST |
- // NativeMethods.MB_ABORTRETRYIGNORE |
- // NativeMethods.MB_ICONEXCLAMATION);
- // }
- //);
-
- //thread.Start();
- //thread.Join();
-
- //if (mbResult.Result == NativeMethods.IDABORT) {
- // IntPtr currentProcess = NativeMethods.GetCurrentProcess();
- // NativeMethods.TerminateProcess(new HandleRef(mbResult, currentProcess), 1);
- //}
-
- //return mbResult.Result == NativeMethods.IDRETRY;
Debug.Fail(dialogMessage);
return true;
}
@@ -826,13 +814,16 @@ A=Exit process R=Debug I=Continue";
internal static void Break()
{
#if DEBUG
- if (NativeMethods.IsDebuggerPresent()) {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && NativeMethods.IsDebuggerPresent())
+ {
NativeMethods.DebugBreak();
}
- else if (!Debugger.IsAttached) {
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !Debugger.IsAttached)
+ {
Debugger.Launch();
}
- else {
+ else
+ {
Debugger.Break();
}
#endif
diff --git a/src/System.Runtime.Caching/src/System/Runtime/Caching/MemoryCacheStatistics.cs b/src/System.Runtime.Caching/src/System/Runtime/Caching/MemoryCacheStatistics.cs
index 7b1430dbdb..f0dd69f1da 100644
--- a/src/System.Runtime.Caching/src/System/Runtime/Caching/MemoryCacheStatistics.cs
+++ b/src/System.Runtime.Caching/src/System/Runtime/Caching/MemoryCacheStatistics.cs
@@ -147,6 +147,10 @@ namespace System.Runtime.Caching
_configCacheMemoryLimitMegabytes = ConfigUtil.GetIntValue(config, ConfigUtil.CacheMemoryLimitMegabytes, _configCacheMemoryLimitMegabytes, true, Int32.MaxValue);
_configPhysicalMemoryLimitPercentage = ConfigUtil.GetIntValue(config, ConfigUtil.PhysicalMemoryLimitPercentage, _configPhysicalMemoryLimitPercentage, true, 100);
}
+ if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && _configPhysicalMemoryLimitPercentage > 0)
+ {
+ throw new PlatformNotSupportedException(SR.PlatformNotSupported_PhysicalMemoryLimitPercentage);
+ }
}
private void InitDisposableMembers()
diff --git a/src/System.Runtime.Caching/src/System/Runtime/Caching/MemoryMonitor.Windows.cs b/src/System.Runtime.Caching/src/System/Runtime/Caching/MemoryMonitor.Windows.cs
new file mode 100644
index 0000000000..d48820639a
--- /dev/null
+++ b/src/System.Runtime.Caching/src/System/Runtime/Caching/MemoryMonitor.Windows.cs
@@ -0,0 +1,26 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Specialized;
+using System.Security;
+using System.Runtime.InteropServices;
+
+
+namespace System.Runtime.Caching
+{
+ internal abstract partial class MemoryMonitor
+ {
+ static MemoryMonitor()
+ {
+ Interop.Kernel32.MEMORYSTATUSEX memoryStatusEx = default;
+ memoryStatusEx.dwLength = (uint)Marshal.SizeOf<Interop.Kernel32.MEMORYSTATUSEX>();
+ if (Interop.Kernel32.GlobalMemoryStatusEx(out memoryStatusEx) != 0)
+ {
+ s_totalPhysical = (long)memoryStatusEx.ullTotalPhys;
+ s_totalVirtual = (long)memoryStatusEx.ullTotalVirtual;
+ }
+ }
+ }
+}
diff --git a/src/System.Runtime.Caching/src/System/Runtime/Caching/MemoryMonitor.cs b/src/System.Runtime.Caching/src/System/Runtime/Caching/MemoryMonitor.cs
index 7318621c1f..37294bba91 100644
--- a/src/System.Runtime.Caching/src/System/Runtime/Caching/MemoryMonitor.cs
+++ b/src/System.Runtime.Caching/src/System/Runtime/Caching/MemoryMonitor.cs
@@ -16,7 +16,7 @@ namespace System.Runtime.Caching
// drop cache entries to avoid paging. The second monitors the amount of memory used by
// the cache itself, and helps determine when we should drop cache entries to avoid
// exceeding the cache's memory limit. Both are configurable (see ConfigUtil.cs).
- internal abstract class MemoryMonitor
+ internal abstract partial class MemoryMonitor
{
protected const int TERABYTE_SHIFT = 40;
protected const long TERABYTE = 1L << TERABYTE_SHIFT;
@@ -39,22 +39,11 @@ namespace System.Runtime.Caching
protected int[] _pressureHist;
protected int _pressureTotal;
- private static long s_totalPhysical;
- private static long s_totalVirtual;
+ private static long s_totalPhysical = 0;
+ private static long s_totalVirtual = 0;
- static MemoryMonitor()
- {
- Interop.Kernel32.MEMORYSTATUSEX memoryStatusEx;
- memoryStatusEx.dwLength = (uint)Marshal.SizeOf(typeof(Interop.Kernel32.MEMORYSTATUSEX));
- if (Interop.Kernel32.GlobalMemoryStatusEx(out memoryStatusEx) != 0)
- {
- s_totalPhysical = (long)memoryStatusEx.ullTotalPhys;
- s_totalVirtual = (long)memoryStatusEx.ullTotalVirtual;
- }
- }
-
- internal static long TotalPhysical { get { return s_totalPhysical; } }
- internal static long TotalVirtual { get { return s_totalVirtual; } }
+ internal static long TotalPhysical => s_totalPhysical;
+ internal static long TotalVirtual => s_totalVirtual;
internal int PressureLast { get { return _pressureHist[_i0]; } }
internal int PressureHigh { get { return _pressureHigh; } }
diff --git a/src/System.Runtime.Caching/src/System/Runtime/Caching/PhysicalMemoryMonitor.Unix.cs b/src/System.Runtime.Caching/src/System/Runtime/Caching/PhysicalMemoryMonitor.Unix.cs
new file mode 100644
index 0000000000..1a5860c06c
--- /dev/null
+++ b/src/System.Runtime.Caching/src/System/Runtime/Caching/PhysicalMemoryMonitor.Unix.cs
@@ -0,0 +1,16 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace System.Runtime.Caching
+{
+ internal sealed partial class PhysicalMemoryMonitor : MemoryMonitor
+ {
+ protected override int GetCurrentPressure()
+ {
+ return 0;
+ }
+ }
+}
diff --git a/src/System.Runtime.Caching/src/System/Runtime/Caching/PhysicalMemoryMonitor.Windows.cs b/src/System.Runtime.Caching/src/System/Runtime/Caching/PhysicalMemoryMonitor.Windows.cs
new file mode 100644
index 0000000000..43949df1db
--- /dev/null
+++ b/src/System.Runtime.Caching/src/System/Runtime/Caching/PhysicalMemoryMonitor.Windows.cs
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.Caching.Configuration;
+using System.Runtime.InteropServices;
+using System.Security;
+
+namespace System.Runtime.Caching
+{
+ internal sealed partial class PhysicalMemoryMonitor : MemoryMonitor
+ {
+ protected override int GetCurrentPressure()
+ {
+ Interop.Kernel32.MEMORYSTATUSEX memoryStatusEx = default;
+ memoryStatusEx.dwLength = (uint)Marshal.SizeOf<Interop.Kernel32.MEMORYSTATUSEX>();
+ if (Interop.Kernel32.GlobalMemoryStatusEx(out memoryStatusEx) == 0)
+ {
+ return 0;
+ }
+
+ int memoryLoad = (int)memoryStatusEx.dwMemoryLoad;
+ return memoryLoad;
+ }
+ }
+}
diff --git a/src/System.Runtime.Caching/src/System/Runtime/Caching/PhysicalMemoryMonitor.cs b/src/System.Runtime.Caching/src/System/Runtime/Caching/PhysicalMemoryMonitor.cs
index 0029db1f72..c3cb2f4d3a 100644
--- a/src/System.Runtime.Caching/src/System/Runtime/Caching/PhysicalMemoryMonitor.cs
+++ b/src/System.Runtime.Caching/src/System/Runtime/Caching/PhysicalMemoryMonitor.cs
@@ -12,7 +12,7 @@ namespace System.Runtime.Caching
// PhysicalMemoryMonitor monitors the amound of physical memory used on the machine
// and helps us determine when to drop entries to avoid paging and GC thrashing.
// The limit is configurable (see ConfigUtil.cs).
- internal sealed class PhysicalMemoryMonitor : MemoryMonitor
+ internal sealed partial class PhysicalMemoryMonitor : MemoryMonitor
{
private const int MIN_TOTAL_MEMORY_TRIM_PERCENT = 10;
private static readonly long s_TARGET_TOTAL_MEMORY_TRIM_INTERVAL_TICKS = 5 * TimeSpan.TicksPerMinute;
@@ -48,7 +48,6 @@ namespace System.Runtime.Caching
*/
long memory = TotalPhysical;
- Dbg.Assert(memory != 0, "memory != 0");
if (memory >= 0x100000000)
{
_pressureHigh = 99;
@@ -76,19 +75,6 @@ namespace System.Runtime.Caching
InitHistory();
}
- protected override int GetCurrentPressure()
- {
- Interop.Kernel32.MEMORYSTATUSEX memoryStatusEx = default;
- memoryStatusEx.dwLength = (uint)Marshal.SizeOf(typeof(Interop.Kernel32.MEMORYSTATUSEX));
- if (Interop.Kernel32.GlobalMemoryStatusEx(out memoryStatusEx) == 0)
- {
- return 0;
- }
-
- int memoryLoad = (int)memoryStatusEx.dwMemoryLoad;
- return memoryLoad;
- }
-
internal override int GetPercentToTrim(DateTime lastTrimTime, int lastTrimPercent)
{
int percent = 0;
diff --git a/src/System.Runtime.Caching/tests/System.Runtime.Caching/MemoryCacheTest.cs b/src/System.Runtime.Caching/tests/System.Runtime.Caching/MemoryCacheTest.cs
index 1e6d59bc18..bb3d941280 100644
--- a/src/System.Runtime.Caching/tests/System.Runtime.Caching/MemoryCacheTest.cs
+++ b/src/System.Runtime.Caching/tests/System.Runtime.Caching/MemoryCacheTest.cs
@@ -33,6 +33,7 @@ using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
+using System.Diagnostics;
using System.Runtime.Caching;
using System.Threading;
using System.Threading.Tasks;
@@ -144,6 +145,18 @@ namespace MonoTests.System.Runtime.Caching
}
[Fact]
+ [PlatformSpecific(TestPlatforms.AnyUnix)] // Negative case for "physicalMemoryLimitPercentage" on non Windows
+ public void PhysicalMemoryLimitNotSupported()
+ {
+ var config = new NameValueCollection();
+ config.Add("PhysicalMemoryLimitPercentage", "99");
+ Assert.Throws<PlatformNotSupportedException>(() =>
+ {
+ new MemoryCache("MyCache", config);
+ });
+ }
+
+ [Fact]
public void Defaults()
{
var mc = new MemoryCache("MyCache");
@@ -176,6 +189,7 @@ namespace MonoTests.System.Runtime.Caching
}
[Fact]
+ [PlatformSpecific(TestPlatforms.Windows)] // Uses "physicalMemoryLimitPercentage" not supported on other platforms
public void ConstructorValues()
{
var config = new NameValueCollection();
@@ -991,6 +1005,7 @@ namespace MonoTests.System.Runtime.Caching
}
[Fact]
+ [PlatformSpecific(TestPlatforms.Windows)] // Uses "physicalMemoryLimitPercentage" not supported on other platforms
public void TestExpiredGetValues()
{
var config = new NameValueCollection();
@@ -1024,6 +1039,8 @@ namespace MonoTests.System.Runtime.Caching
}
[Fact]
+ [PlatformSpecific(TestPlatforms.Windows)] // Uses "physicalMemoryLimitPercentage" not supported on other platforms
+ [OuterLoop] // makes long wait
public void TestCacheSliding()
{
var config = new NameValueCollection();
@@ -1039,7 +1056,8 @@ namespace MonoTests.System.Runtime.Caching
// The sliding expiration timeout has to be greater than 1 second because
// .NET implementation ignores timeouts updates smaller than
// CacheExpires.MIN_UPDATE_DELTA which is equal to 1.
- cip.SlidingExpiration = TimeSpan.FromSeconds(2);
+ const int SlidingExpirationThresholdMSec = 4000;
+ cip.SlidingExpiration = TimeSpan.FromMilliseconds(SlidingExpirationThresholdMSec);
mc.Add("slidingtest", "42", cip);
mc.Add("expire1", "1", cip);
@@ -1049,13 +1067,28 @@ namespace MonoTests.System.Runtime.Caching
mc.Add("expire5", "5", cip);
Assert.Equal(6, mc.GetCount());
-
+ // The loop below would sleep for ~5 seconds total (in 50 intervals).
+ // Each of these intervals is only supposed to be ~100ms.
+ // However due to concurrency with other tests and various system conditions,
+ // we observe occasional delays that are much longer than the SlidingExpirationThresholdMSec
+ // expiration period which causes the "slidingtest" cache item to expire
+ Stopwatch sw = new Stopwatch();
for (int i = 0; i < 50; i++)
{
+ sw.Restart();
Thread.Sleep(100);
-
var item = mc.Get("slidingtest");
- Assert.NotEqual(null, item);
+ sw.Stop();
+
+ if (sw.ElapsedMilliseconds < SlidingExpirationThresholdMSec)
+ {
+ Assert.NotEqual(null, item);
+ }
+ else
+ {
+ // for the sake of simplicity skip an inversed assert here (Assert.Equal(null, item))
+ // (to avoid further complicating the test as we would need to address a few more subtle timing cases)
+ }
}
Assert.Null(mc.Get("expire1"));
@@ -1065,7 +1098,7 @@ namespace MonoTests.System.Runtime.Caching
Assert.Null(mc.Get("expire5"));
Assert.Equal(1, mc.GetCount());
- Thread.Sleep(3000);
+ Thread.Sleep(SlidingExpirationThresholdMSec + 1000);
Assert.Null(mc.Get("slidingtest"));
Assert.Equal(0, mc.GetCount());
@@ -1314,6 +1347,7 @@ namespace MonoTests.System.Runtime.Caching
public class MemoryCacheTestExpires4
{
[Fact]
+ [PlatformSpecific(TestPlatforms.Windows)] // Uses "physicalMemoryLimitPercentage" not supported on other platforms
public async Task TestCacheShrink()
{
const int HEAP_RESIZE_THRESHOLD = 8192 + 2;
@@ -1371,6 +1405,7 @@ namespace MonoTests.System.Runtime.Caching
public class MemoryCacheTestExpires5
{
[Fact]
+ [PlatformSpecific(TestPlatforms.Windows)] // Uses "physicalMemoryLimitPercentage" not supported on other platforms
public async Task TestCacheExpiryOrdering()
{
var config = new NameValueCollection();
diff --git a/src/System.Runtime.CompilerServices.Unsafe/pkg/System.Runtime.CompilerServices.Unsafe.pkgproj b/src/System.Runtime.CompilerServices.Unsafe/pkg/System.Runtime.CompilerServices.Unsafe.pkgproj
index d73c618a40..1f13bc9c19 100644
--- a/src/System.Runtime.CompilerServices.Unsafe/pkg/System.Runtime.CompilerServices.Unsafe.pkgproj
+++ b/src/System.Runtime.CompilerServices.Unsafe/pkg/System.Runtime.CompilerServices.Unsafe.pkgproj
@@ -7,6 +7,10 @@
<SupportedFramework>net45;netcore45;wp8;wpa81;netcoreapp1.0;$(AllXamarinFrameworks)</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\src\System.Runtime.CompilerServices.Unsafe.ilproj" />
+
+ <!-- this package is part of the implementation closure of NETStandard.Library
+ therefore it cannot reference NETStandard.Library -->
+ <SuppressMetaPackage Include="NETStandard.Library" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.Runtime.CompilerServices.Unsafe/ref/System.Runtime.CompilerServices.Unsafe.cs b/src/System.Runtime.CompilerServices.Unsafe/ref/System.Runtime.CompilerServices.Unsafe.cs
index fe7fcc03c0..411b25efd2 100644
--- a/src/System.Runtime.CompilerServices.Unsafe/ref/System.Runtime.CompilerServices.Unsafe.cs
+++ b/src/System.Runtime.CompilerServices.Unsafe/ref/System.Runtime.CompilerServices.Unsafe.cs
@@ -30,6 +30,8 @@ namespace System.Runtime.CompilerServices
public unsafe static void InitBlock(void* startAddress, byte value, uint byteCount) { }
public static void InitBlockUnaligned(ref byte startAddress, byte value, uint byteCount) { }
public unsafe static void InitBlockUnaligned(void* startAddress, byte value, uint byteCount) { }
+ public static bool IsAddressGreaterThan<T>(ref T left, ref T right) { throw null; }
+ public static bool IsAddressLessThan<T>(ref T left, ref T right) { throw null; }
public unsafe static T Read<T>(void* source) { throw null; }
public unsafe static T ReadUnaligned<T>(void* source) { throw null; }
public static T ReadUnaligned<T>(ref byte source) { throw null; }
diff --git a/src/System.Runtime.CompilerServices.Unsafe/src/Configurations.props b/src/System.Runtime.CompilerServices.Unsafe/src/Configurations.props
index d13cce3482..2a68e751ff 100644
--- a/src/System.Runtime.CompilerServices.Unsafe/src/Configurations.props
+++ b/src/System.Runtime.CompilerServices.Unsafe/src/Configurations.props
@@ -1,9 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
- <BuildConfigurations>
+ <PackageConfigurations>
+ netcoreapp2.0;
netstandard1.0;
netstandard;
- </BuildConfigurations>
+ </PackageConfigurations>
+ <BuildConfigurations>
+ $(PackageConfigurations);
+ netcoreapp
+ </BuildConfigurations>
</PropertyGroup>
</Project>
diff --git a/src/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.il b/src/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.il
index 07c61f177d..891f9ac201 100644
--- a/src/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.il
+++ b/src/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.il
@@ -419,6 +419,26 @@
ret
} // end of method Unsafe::AreSame
+ .method public hidebysig static bool IsAddressGreaterThan<T>(!!T& left, !!T& right) cil managed aggressiveinlining
+ {
+ .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 )
+ .maxstack 2
+ ldarg.0
+ ldarg.1
+ cgt.un
+ ret
+ } // end of method Unsafe::IsAddressGreaterThan
+
+ .method public hidebysig static bool IsAddressLessThan<T>(!!T& left, !!T& right) cil managed aggressiveinlining
+ {
+ .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 )
+ .maxstack 2
+ ldarg.0
+ ldarg.1
+ clt.un
+ ret
+ } // end of method Unsafe::IsAddressLessThan
+
} // end of class System.Runtime.CompilerServices.Unsafe
.class private auto ansi sealed beforefieldinit System.Runtime.Versioning.NonVersionableAttribute
diff --git a/src/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.ilproj b/src/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.ilproj
index 2a61d0a70f..4b95956155 100644
--- a/src/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.ilproj
+++ b/src/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.ilproj
@@ -4,12 +4,16 @@
<PropertyGroup>
<DocumentationFile>$(MSBuildThisFileDirectory)System.Runtime.CompilerServices.Unsafe.xml</DocumentationFile>
<ProjectGuid>{04BA3E3C-6979-4792-B19E-C797AD607F42}</ProjectGuid>
- <IlasmFlags>$(IlasmFlags) -INCLUDE=include\$(TargetGroup)</IlasmFlags>
+ <IncludePath>include\$(TargetGroup)</IncludePath>
+ <IncludePath Condition="'$(TargetGroup)' == 'netcoreapp2.0'">include\netcoreapp</IncludePath>
+ <IlasmFlags>$(IlasmFlags) -INCLUDE=$(IncludePath)</IlasmFlags>
<!-- cannot build on unix, but package as OS-agnostic -->
<PackageTargetRuntime />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.0-Debug|AnyCPU'" />
diff --git a/src/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.xml b/src/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.xml
index 8c24ae6194..bb4911a411 100644
--- a/src/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.xml
+++ b/src/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.xml
@@ -201,6 +201,30 @@
<param name="right">The second reference to compare.</param>
<returns><c>true</c> if <paramref name="left"/> and <paramref name="right"/> point to the same location; otherwise <c>false</c>.</returns>
</member>
+ <member name="M:System.Runtime.CompilerServices.Unsafe.IsAddressGreaterThan``1(``0@,``0@)">
+ <summary>
+ Determines whether the memory address referenced by <paramref name="left"/> is greater than the memory address referenced by <paramref name="right"/>.
+ </summary>
+ <param name="left">The first reference to compare.</param>
+ <param name="right">The second reference to compare.</param>
+ <returns><c>true</c> if the memory address referenced by <paramref name="left"/> is greater than the memory address referenced by <paramref name="right"/>; otherwise <c>false</c>.</returns>
+ <remarks>
+ This check is conceptually similar to "(void*)(&amp;left) &gt; (void*)(&amp;right)". Both parameters must reference the same object, array, or span;
+ or the objects being referenced must both be pinned; or both references must represent unmanaged pointers; otherwise the result is undefined.
+ </remarks>
+ </member>
+ <member name="M:System.Runtime.CompilerServices.Unsafe.IsAddressLessThan``1(``0@,``0@)">
+ <summary>
+ Determines whether the memory address referenced by <paramref name="left"/> is less than the memory address referenced by <paramref name="right"/>.
+ </summary>
+ <param name="left">The first reference to compare.</param>
+ <param name="right">The second reference to compare.</param>
+ <returns><c>true</c> if the memory address referenced by <paramref name="left"/> is less than the memory address referenced by <paramref name="right"/>; otherwise <c>false</c>.</returns>
+ <remarks>
+ This check is conceptually similar to "(void*)(&amp;left) &lt; (void*)(&amp;right)". Both parameters must reference the same object, array, or span;
+ or the objects being referenced must both be pinned; or both references must represent unmanaged pointers; otherwise the result is undefined.
+ </remarks>
+ </member>
<member name="M:System.Runtime.CompilerServices.Unsafe.CopyBlock(System.Void*,System.Void*,System.UInt32)">
<summary>
Copies bytes from the source address to the destination address.
diff --git a/src/System.Runtime.CompilerServices.Unsafe/tests/UnsafeTests.cs b/src/System.Runtime.CompilerServices.Unsafe/tests/UnsafeTests.cs
index fce1ae27d3..508358d907 100644
--- a/src/System.Runtime.CompilerServices.Unsafe/tests/UnsafeTests.cs
+++ b/src/System.Runtime.CompilerServices.Unsafe/tests/UnsafeTests.cs
@@ -609,6 +609,44 @@ namespace System.Runtime.CompilerServices
}
[Fact]
+ public static unsafe void RefIsAddressGreaterThan()
+ {
+ int[] a = new int[2];
+
+ Assert.False(Unsafe.IsAddressGreaterThan(ref a[0], ref a[0]));
+ Assert.False(Unsafe.IsAddressGreaterThan(ref a[0], ref a[1]));
+ Assert.True(Unsafe.IsAddressGreaterThan(ref a[1], ref a[0]));
+ Assert.False(Unsafe.IsAddressGreaterThan(ref a[1], ref a[1]));
+
+ // The following tests ensure that we're using unsigned comparison logic
+
+ Assert.False(Unsafe.IsAddressGreaterThan(ref Unsafe.AsRef<byte>((void*)(1)), ref Unsafe.AsRef<byte>((void*)(-1))));
+ Assert.True(Unsafe.IsAddressGreaterThan(ref Unsafe.AsRef<byte>((void*)(-1)), ref Unsafe.AsRef<byte>((void*)(1))));
+ Assert.True(Unsafe.IsAddressGreaterThan(ref Unsafe.AsRef<byte>((void*)(Int32.MinValue)), ref Unsafe.AsRef<byte>((void*)(Int32.MaxValue))));
+ Assert.False(Unsafe.IsAddressGreaterThan(ref Unsafe.AsRef<byte>((void*)(Int32.MaxValue)), ref Unsafe.AsRef<byte>((void*)(Int32.MinValue))));
+ Assert.False(Unsafe.IsAddressGreaterThan(ref Unsafe.AsRef<byte>(null), ref Unsafe.AsRef<byte>(null)));
+ }
+
+ [Fact]
+ public static unsafe void RefIsAddressLessThan()
+ {
+ int[] a = new int[2];
+
+ Assert.False(Unsafe.IsAddressLessThan(ref a[0], ref a[0]));
+ Assert.True(Unsafe.IsAddressLessThan(ref a[0], ref a[1]));
+ Assert.False(Unsafe.IsAddressLessThan(ref a[1], ref a[0]));
+ Assert.False(Unsafe.IsAddressLessThan(ref a[1], ref a[1]));
+
+ // The following tests ensure that we're using unsigned comparison logic
+
+ Assert.True(Unsafe.IsAddressLessThan(ref Unsafe.AsRef<byte>((void*)(1)), ref Unsafe.AsRef<byte>((void*)(-1))));
+ Assert.False(Unsafe.IsAddressLessThan(ref Unsafe.AsRef<byte>((void*)(-1)), ref Unsafe.AsRef<byte>((void*)(1))));
+ Assert.False(Unsafe.IsAddressLessThan(ref Unsafe.AsRef<byte>((void*)(Int32.MinValue)), ref Unsafe.AsRef<byte>((void*)(Int32.MaxValue))));
+ Assert.True(Unsafe.IsAddressLessThan(ref Unsafe.AsRef<byte>((void*)(Int32.MaxValue)), ref Unsafe.AsRef<byte>((void*)(Int32.MinValue))));
+ Assert.False(Unsafe.IsAddressLessThan(ref Unsafe.AsRef<byte>(null), ref Unsafe.AsRef<byte>(null)));
+ }
+
+ [Fact]
public static unsafe void ReadUnaligned_ByRef_Int32()
{
byte[] unaligned = Int32Double.Unaligned(123456789, 3.42);
diff --git a/src/System.Runtime.Extensions/ref/System.Runtime.Extensions.cs b/src/System.Runtime.Extensions/ref/System.Runtime.Extensions.cs
index c21a0bca88..81162f9ce8 100644
--- a/src/System.Runtime.Extensions/ref/System.Runtime.Extensions.cs
+++ b/src/System.Runtime.Extensions/ref/System.Runtime.Extensions.cs
@@ -753,10 +753,14 @@ namespace System
public static sbyte Abs(sbyte value) { throw null; }
public static float Abs(float value) { throw null; }
public static double Acos(double d) { throw null; }
+ public static double Acosh(double d) { throw null; }
public static double Asin(double d) { throw null; }
+ public static double Asinh(double d) { throw null; }
public static double Atan(double d) { throw null; }
public static double Atan2(double y, double x) { throw null; }
+ public static double Atanh(double d) { throw null; }
public static long BigMul(int a, int b) { throw null; }
+ public static double Cbrt(double d) { throw null; }
public static decimal Ceiling(decimal d) { throw null; }
public static double Ceiling(double a) { throw null; }
public static byte Clamp(byte value, byte min, byte max) { throw null; }
@@ -844,9 +848,13 @@ namespace System
{
public static float Abs(float x) { throw null; }
public static float Acos(float x) { throw null; }
+ public static float Acosh(float x) { throw null; }
public static float Asin(float x) { throw null; }
+ public static float Asinh(float x) { throw null; }
public static float Atan(float x) { throw null; }
+ public static float Atanh(float x) { throw null; }
public static float Atan2(float y, float x) { throw null; }
+ public static float Cbrt(float x) { throw null; }
public static float Ceiling(float x) { throw null; }
public static float Cos(float x) { throw null; }
public static float Cosh(float x) { throw null; }
@@ -925,6 +933,7 @@ namespace System
public static System.StringComparer FromComparison(System.StringComparison comparisonType) { throw null; }
public abstract int Compare(string x, string y);
public static System.StringComparer Create(System.Globalization.CultureInfo culture, bool ignoreCase) { throw null; }
+ public static System.StringComparer Create(System.Globalization.CultureInfo culture, System.Globalization.CompareOptions options) { throw null; }
public new bool Equals(object x, object y) { throw null; }
public abstract bool Equals(string x, string y);
public int GetHashCode(object obj) { throw null; }
@@ -1193,20 +1202,33 @@ namespace System.IO
public static string Combine(string path1, string path2, string path3, string path4) { throw null; }
public static string Combine(params string[] paths) { throw null; }
public static string GetDirectoryName(string path) { throw null; }
+ public static ReadOnlySpan<char> GetDirectoryName(ReadOnlySpan<char> path) { throw null; }
public static string GetExtension(string path) { throw null; }
+ public static ReadOnlySpan<char> GetExtension(ReadOnlySpan<char> path) { throw null; }
public static string GetFileName(string path) { throw null; }
+ public static ReadOnlySpan<char> GetFileName(ReadOnlySpan<char> path) { throw null; }
public static string GetFileNameWithoutExtension(string path) { throw null; }
+ public static ReadOnlySpan<char> GetFileNameWithoutExtension(ReadOnlySpan<char> path) { throw null; }
public static string GetFullPath(string path) { throw null; }
+ public static string GetFullPath(string path, string basePath) { throw null; }
public static char[] GetInvalidFileNameChars() { throw null; }
public static char[] GetInvalidPathChars() { throw null; }
public static string GetPathRoot(string path) { throw null; }
+ public static ReadOnlySpan<char> GetPathRoot(ReadOnlySpan<char> path) { throw null; }
public static string GetRandomFileName() { throw null; }
public static string GetTempFileName() { throw null; }
public static string GetTempPath() { throw null; }
public static bool HasExtension(string path) { throw null; }
+ public static bool HasExtension(ReadOnlySpan<char> path) { throw null; }
public static bool IsPathRooted(string path) { throw null; }
+ public static bool IsPathRooted(ReadOnlySpan<char> path) { throw null; }
public static bool IsPathFullyQualified(string path) { throw null; }
+ public static bool IsPathFullyQualified(ReadOnlySpan<char> path) { throw null; }
public static string GetRelativePath(string relativeTo, string path) { throw null; }
+ public static string Join(ReadOnlySpan<char> path1, ReadOnlySpan<char> path2) { throw null; }
+ public static string Join(ReadOnlySpan<char> path1, ReadOnlySpan<char> path2, ReadOnlySpan<char> path3) { throw null; }
+ public static bool TryJoin(ReadOnlySpan<char> path1, ReadOnlySpan<char> path2, Span<char> destination, out int charsWritten) { throw null; }
+ public static bool TryJoin(ReadOnlySpan<char> path1, ReadOnlySpan<char> path2, ReadOnlySpan<char> path3, Span<char> destination, out int charsWritten) { throw null; }
}
public partial class BinaryReader : System.IDisposable
@@ -1364,7 +1386,7 @@ namespace System.IO
public override void Write(byte[] buffer, int offset, int count) { }
public override void Write(System.ReadOnlySpan<byte> source) { }
public override System.Threading.Tasks.Task WriteAsync(byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) { throw null; }
- public override System.Threading.Tasks.Task WriteAsync(System.ReadOnlyMemory<byte> source, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+ public override System.Threading.Tasks.ValueTask WriteAsync(System.ReadOnlyMemory<byte> source, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public override void WriteByte(byte value) { }
public virtual void WriteTo(System.IO.Stream stream) { }
}
diff --git a/src/System.Runtime.Extensions/src/ApiCompatBaseline.uapaot.txt b/src/System.Runtime.Extensions/src/ApiCompatBaseline.uapaot.txt
new file mode 100644
index 0000000000..03ef2c671a
--- /dev/null
+++ b/src/System.Runtime.Extensions/src/ApiCompatBaseline.uapaot.txt
@@ -0,0 +1,5 @@
+TypesMustExist : Type 'System.Globalization.GlobalizationExtensions' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.IO.Path.Join(System.ReadOnlySpan<System.Char>, System.ReadOnlySpan<System.Char>)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.IO.Path.Join(System.ReadOnlySpan<System.Char>, System.ReadOnlySpan<System.Char>, System.ReadOnlySpan<System.Char>)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.IO.Path.TryJoin(System.ReadOnlySpan<System.Char>, System.ReadOnlySpan<System.Char>, System.ReadOnlySpan<System.Char>, System.Span<System.Char>, System.Int32)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.IO.Path.TryJoin(System.ReadOnlySpan<System.Char>, System.ReadOnlySpan<System.Char>, System.Span<System.Char>, System.Int32)' does not exist in the implementation but it does exist in the contract. \ No newline at end of file
diff --git a/src/System.Runtime.Extensions/src/System.Runtime.Extensions.csproj b/src/System.Runtime.Extensions/src/System.Runtime.Extensions.csproj
index 7e5768f0ba..c51a41e3a7 100644
--- a/src/System.Runtime.Extensions/src/System.Runtime.Extensions.csproj
+++ b/src/System.Runtime.Extensions/src/System.Runtime.Extensions.csproj
@@ -9,6 +9,8 @@
<IsPartialFacadeAssembly>true</IsPartialFacadeAssembly>
<IncludeDllSafeSearchPathAttribute>true</IncludeDllSafeSearchPathAttribute>
<DefineConstants Condition="'$(TargetGroup)' == 'uapaot'">$(DefineConstants);uapaot</DefineConstants>
+ <ILLinkClearInitLocals>true</ILLinkClearInitLocals>
+ <GenFacadesIgnoreMissingTypes Condition="'$(TargetGroup)'=='uapaot'">true</GenFacadesIgnoreMissingTypes>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
@@ -19,6 +21,9 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uapaot-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uapaot-Windows_NT-Release|AnyCPU'" />
<ItemGroup>
+ <Compile Include="..\..\Common\src\System\PasteArguments.cs">
+ <Link>Common\System\PasteArguments.cs</Link>
+ </Compile>
<Compile Include="System\AppDomain.cs" />
<Compile Include="System\AppDomainUnloadedException.cs" />
<Compile Include="System\ApplicationId.cs" />
@@ -29,7 +34,6 @@
<Compile Include="System\Environment.cs" />
<Compile Include="System\Environment.SpecialFolder.cs" />
<Compile Include="System\Environment.SpecialFolderOption.cs" />
- <Compile Include="System\Globalization\Extensions.cs" />
<Compile Include="System\LoaderOptimization.cs" />
<Compile Include="System\LoaderOptimizationAttribute.cs" />
<Compile Include="System\OperatingSystem.cs" />
@@ -75,12 +79,15 @@
<Compile Include="$(CommonPath)\System\IO\StringBuilderCache.cs">
<Link>Common\System\IO\StringBuilderCache.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\IO\PathInternal.cs">
- <Link>Common\System\IO\PathInternal.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\System\HResults.cs">
<Link>Common\System\HResults.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\CoreLib\System\Text\ValueStringBuilder.cs">
+ <Link>CoreLib\System\Text\ValueStringBuilder.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Collections\HashHelpers.cs">
+ <Link>Common\System\Collections\HashHelpers.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' == 'uapaot' or '$(TargetGroup)' == 'uap'">
<Compile Include="System\Environment.WinRT.cs" />
@@ -96,11 +103,14 @@
</ItemGroup>
<!-- WINDOWS: Shared CoreCLR and .NET Native -->
<ItemGroup Condition="'$(TargetsWindows)' == 'true'">
+ <Compile Include="..\..\Common\src\System\PasteArguments.Windows.cs">
+ <Link>Common\System\PasteArguments.Windows.cs</Link>
+ </Compile>
<Compile Include="System\Environment.Windows.cs" />
<Compile Include="System\Runtime\Versioning\VersioningHelper.Windows.cs" />
<Compile Include="System\Diagnostics\Stopwatch.Windows.cs" />
- <Compile Include="$(CommonPath)\System\IO\Win32Marshal.cs">
- <Link>Common\System\IO\Win32Marshal.cs</Link>
+ <Compile Include="$(CommonPath)\CoreLib\System\IO\Win32Marshal.cs">
+ <Link>Common\CoreLib\System\IO\Win32Marshal.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\Interop.Libraries.cs">
<Link>Common\Interop\Windows\Interop.Libraries.cs</Link>
@@ -108,6 +118,9 @@
<Compile Include="$(CommonPath)\Interop\Windows\Interop.Errors.cs">
<Link>Common\Interop\Windows\Interop.Errors.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\Interop.BOOLEAN.cs">
+ <Link>Common\Interop\Windows\Interop.BOOLEAN.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\Interop\Windows\advapi32\Interop.LookupAccountNameW.cs">
<Link>Common\Interop\Windows\advapi32\Interop.LookupAccountNameW.cs</Link>
</Compile>
@@ -132,9 +145,6 @@
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.GetLogicalDrive.cs">
<Link>Common\Interop\Windows\Interop.GetLogicalDrive.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.GetLongPathName.cs">
- <Link>Common\Interop\Windows\kernel32\Interop.GetLongPathName.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.GetSystemDirectoryW.cs">
<Link>Common\Interop\Windows\kernel32\Interop.GetSystemDirectoryW.cs</Link>
</Compile>
@@ -165,8 +175,20 @@
<Compile Include="$(CommonPath)\System\IO\DriveInfoInternal.Win32.cs">
<Link>Common\System\IO\DriveInfoInternal.Win32.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\IO\PathInternal.Windows.cs">
- <Link>Common\System\IO\PathInternal.Windows.cs</Link>
+ <Compile Include="$(CommonPath)\CoreLib\System\IO\PathHelper.Windows.cs">
+ <Link>CoreLib\System\IO\PathHelper.Windows.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\CoreLib\System\IO\PathInternal.cs">
+ <Link>CoreLib\System\IO\PathInternal.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\CoreLib\System\IO\PathInternal.Windows.cs">
+ <Link>CoreLib\System\IO\PathInternal.Windows.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\CoreLib\Interop\Windows\Kernel32\Interop.GetLongPathNameW.cs">
+ <Link>CoreLib\Interop\Windows\Kernel32\Interop.GetLongPathNameW.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\CoreLib\Interop\Windows\Kernel32\Interop.GetFullPathNameW.cs">
+ <Link>CoreLib\Interop\Windows\Kernel32\Interop.GetFullPathNameW.cs</Link>
</Compile>
</ItemGroup>
<!-- UNIX -->
@@ -234,15 +256,15 @@
<Compile Include="$(CommonPath)\System\IO\DriveInfoInternal.Unix.cs">
<Link>Common\System\IO\DriveInfoInternal.Unix.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\IO\PathInternal.Unix.cs">
- <Link>Common\System\IO\PathInternal.Unix.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)\System\IO\PersistedFiles.Unix.cs">
<Link>Common\System\IO\PersistedFiles.Unix.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\IO\PersistedFiles.Names.Unix.cs">
<Link>Common\System\IO\PersistedFiles.Unix.cs</Link>
</Compile>
+ <Compile Include="..\..\Common\src\System\PasteArguments.Unix.cs">
+ <Link>Common\System\PasteArguments.Unix.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\System.Private.Uri\src\System.Private.Uri.csproj" />
@@ -261,4 +283,4 @@
<ReferenceFromRuntime Include="System.Private.CoreLib" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Runtime.Extensions/src/System/Collections/Hashtable.cs b/src/System.Runtime.Extensions/src/System/Collections/Hashtable.cs
index 7449e90345..e3b8ed8a5b 100644
--- a/src/System.Runtime.Extensions/src/System/Collections/Hashtable.cs
+++ b/src/System.Runtime.Extensions/src/System/Collections/Hashtable.cs
@@ -156,6 +156,9 @@ namespace System.Collections
private IEqualityComparer _keycomparer;
private Object _syncRoot;
+ private static ConditionalWeakTable<object, SerializationInfo> s_serializationInfoTable;
+ private static ConditionalWeakTable<object, SerializationInfo> SerializationInfoTable => LazyInitializer.EnsureInitialized(ref s_serializationInfoTable);
+
[Obsolete("Please use EqualityComparer property.")]
protected IHashCodeProvider hcp
{
@@ -383,7 +386,7 @@ namespace System.Collections
//We can't do anything with the keys and values until the entire graph has been deserialized
//and we have a reasonable estimate that GetHashCode is not going to fail. For the time being,
//we'll just cache this. The graph is not valid until OnDeserialization has been called.
- HashHelpers.SerializationInfoTable.Add(this, info);
+ SerializationInfoTable.Add(this, info);
}
// ?InitHash? is basically an implementation of classic DoubleHashing (see http://en.wikipedia.org/wiki/Double_hashing)
@@ -1175,7 +1178,7 @@ namespace System.Collections
}
SerializationInfo siInfo;
- HashHelpers.SerializationInfoTable.TryGetValue(this, out siInfo);
+ SerializationInfoTable.TryGetValue(this, out siInfo);
if (siInfo == null)
{
@@ -1257,7 +1260,7 @@ namespace System.Collections
_version = siInfo.GetInt32(VersionName);
- HashHelpers.SerializationInfoTable.Remove(this);
+ SerializationInfoTable.Remove(this);
}
// Implements a Collection for the keys of a hashtable. An instance of this
@@ -1647,84 +1650,4 @@ namespace System.Collections
}
}
}
-
- internal static class HashHelpers
- {
- // Table of prime numbers to use as hash table sizes.
- // A typical resize algorithm would pick the smallest prime number in this array
- // that is larger than twice the previous capacity.
- // Suppose our Hashtable currently has capacity x and enough elements are added
- // such that a resize needs to occur. Resizing first computes 2x then finds the
- // first prime in the table greater than 2x, i.e. if primes are ordered
- // p_1, p_2, ..., p_i, ..., it finds p_n such that p_n-1 < 2x < p_n.
- // Doubling is important for preserving the asymptotic complexity of the
- // hashtable operations such as add. Having a prime guarantees that double
- // hashing does not lead to infinite loops. IE, your hash function will be
- // h1(key) + i*h2(key), 0 <= i < size. h2 and the size must be relatively prime.
- public static readonly int[] primes = {
- 3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919,
- 1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591,
- 17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437,
- 187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,
- 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369};
-
- public static bool IsPrime(int candidate)
- {
- if ((candidate & 1) != 0)
- {
- int limit = (int)Math.Sqrt(candidate);
- for (int divisor = 3; divisor <= limit; divisor += 2)
- {
- if ((candidate % divisor) == 0)
- return false;
- }
- return true;
- }
- return (candidate == 2);
- }
-
- public static int GetPrime(int min)
- {
- if (min < 0)
- throw new ArgumentException(SR.Arg_HTCapacityOverflow);
-
- for (int i = 0; i < primes.Length; i++)
- {
- int prime = primes[i];
- if (prime >= min) return prime;
- }
-
- //outside of our predefined table.
- //compute the hard way.
- for (int i = (min | 1); i < Int32.MaxValue; i += 2)
- {
- if (IsPrime(i) && ((i - 1) % Hashtable.HashPrime != 0))
- return i;
- }
- return min;
- }
-
- // Returns size of hashtable to grow to.
- public static int ExpandPrime(int oldSize)
- {
- int newSize = 2 * oldSize;
-
- // Allow the hashtables to grow to maximum possible size (~2G elements) before encountering capacity overflow.
- // Note that this check works even when _items.Length overflowed thanks to the (uint) cast
- if ((uint)newSize > MaxPrimeArrayLength && MaxPrimeArrayLength > oldSize)
- {
- Debug.Assert(MaxPrimeArrayLength == GetPrime(MaxPrimeArrayLength), "Invalid MaxPrimeArrayLength");
- return MaxPrimeArrayLength;
- }
-
- return GetPrime(newSize);
- }
-
-
- // This is the maximum prime smaller than Array.MaxArrayLength
- public const int MaxPrimeArrayLength = 0x7FEFFFFD;
-
- private static ConditionalWeakTable<object, SerializationInfo> s_serializationInfoTable;
- public static ConditionalWeakTable<object, SerializationInfo> SerializationInfoTable => LazyInitializer.EnsureInitialized(ref s_serializationInfoTable);
- }
}
diff --git a/src/System.Runtime.Extensions/src/System/Environment.Unix.cs b/src/System.Runtime.Extensions/src/System/Environment.Unix.cs
index a10fc04349..14383db0f3 100644
--- a/src/System.Runtime.Extensions/src/System/Environment.Unix.cs
+++ b/src/System.Runtime.Extensions/src/System/Environment.Unix.cs
@@ -18,7 +18,7 @@ namespace System
{
internal static readonly bool IsMac = Interop.Sys.GetUnixName() == "OSX";
private static Func<string, IEnumerable<string>> s_fileReadLines;
- private static Action<string> s_directoryCreateDirectory;
+ private static Func<string, object> s_directoryCreateDirectory;
private static string CurrentDirectoryCore
{
@@ -80,11 +80,11 @@ namespace System
Debug.Assert(option == SpecialFolderOption.Create);
// TODO #11151: Replace with Directory.CreateDirectory once we have access to System.IO.FileSystem here.
- Action<string> createDirectory = LazyInitializer.EnsureInitialized(ref s_directoryCreateDirectory, () =>
+ Func<string, object> createDirectory = LazyInitializer.EnsureInitialized(ref s_directoryCreateDirectory, () =>
{
Type dirType = Type.GetType("System.IO.Directory, System.IO.FileSystem, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", throwOnError: true);
MethodInfo mi = dirType.GetTypeInfo().GetDeclaredMethod("CreateDirectory");
- return (Action<string>)mi.CreateDelegate(typeof(Action<string>));
+ return (Func<string, object>)mi.CreateDelegate(typeof(Func<string, object>));
});
createDirectory(path);
@@ -368,7 +368,7 @@ namespace System
{
// First try with a buffer that should suffice for 99% of cases.
string username;
- const int BufLen = 1024;
+ const int BufLen = Interop.Sys.Passwd.InitialBufferSize;
byte* stackBuf = stackalloc byte[BufLen];
if (TryGetUserNameFromPasswd(stackBuf, BufLen, out username))
{
diff --git a/src/System.Runtime.Extensions/src/System/Environment.Win32.cs b/src/System.Runtime.Extensions/src/System/Environment.Win32.cs
index ca023ced81..3ac7663b50 100644
--- a/src/System.Runtime.Extensions/src/System/Environment.Win32.cs
+++ b/src/System.Runtime.Extensions/src/System/Environment.Win32.cs
@@ -2,60 +2,108 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using Internal.Runtime.Augments;
-using System.Diagnostics;
using System.IO;
-using System.Runtime.InteropServices;
using System.Text;
+using System.Runtime.InteropServices;
namespace System
{
public static partial class Environment
{
- static partial void GetUserName(ref string username)
+ public static string UserName
{
- // Use GetUserNameExW, as GetUserNameW isn't available on all platforms, e.g. Win7
- var domainName = new StringBuilder(1024);
- uint domainNameLen = (uint)domainName.Capacity;
- if (Interop.Secur32.GetUserNameExW(Interop.Secur32.NameSamCompatible, domainName, ref domainNameLen) == 1)
+ get
{
- string samName = domainName.ToString();
- int index = samName.IndexOf('\\');
+ // 40 should be enough as we're asking for the SAM compatible name (DOMAIN\User).
+ // The max length should be 15 (domain) + 1 (separator) + 20 (name) + null. If for
+ // some reason it isn't, we'll grow the buffer.
+
+ // https://support.microsoft.com/en-us/help/909264/naming-conventions-in-active-directory-for-computers-domains-sites-and
+ // https://msdn.microsoft.com/en-us/library/ms679635.aspx
+
+ Span<char> initialBuffer = stackalloc char[40];
+ var builder = new ValueStringBuilder(initialBuffer);
+ GetUserName(ref builder);
+
+ ReadOnlySpan<char> name = builder.AsSpan();
+ int index = name.IndexOf('\\');
if (index != -1)
{
- username = samName.Substring(index + 1);
- return;
+ // In the form of DOMAIN\User, cut off DOMAIN\
+ name = name.Slice(index + 1);
}
- }
- username = string.Empty;
+ return name.ToString();
+ }
}
- static partial void GetDomainName(ref string userDomainName)
+ private static void GetUserName(ref ValueStringBuilder builder)
{
- var domainName = new StringBuilder(1024);
- uint domainNameLen = (uint)domainName.Capacity;
- if (Interop.Secur32.GetUserNameExW(Interop.Secur32.NameSamCompatible, domainName, ref domainNameLen) == 1)
+ uint size = 0;
+ while (Interop.Secur32.GetUserNameExW(Interop.Secur32.NameSamCompatible, ref builder.GetPinnableReference(), ref size) == Interop.BOOLEAN.FALSE)
{
- string samName = domainName.ToString();
- int index = samName.IndexOf('\\');
- if (index != -1)
+ if (Marshal.GetLastWin32Error() == Interop.Errors.ERROR_MORE_DATA)
+ {
+ builder.EnsureCapacity(checked((int)size));
+ }
+ else
{
- userDomainName = samName.Substring(0, index);
+ builder.Length = 0;
return;
}
}
- domainNameLen = (uint)domainName.Capacity;
- byte[] sid = new byte[1024];
- int sidLen = sid.Length;
- int peUse;
- if (!Interop.Advapi32.LookupAccountNameW(null, UserName, sid, ref sidLen, domainName, ref domainNameLen, out peUse))
+ builder.Length = (int)size;
+ }
+
+ public static string UserDomainName
+ {
+ get
{
- throw new InvalidOperationException(Win32Marshal.GetExceptionForLastWin32Error().Message);
- }
+ // See the comment in UserName
+ Span<char> initialBuffer = stackalloc char[40];
+ var builder = new ValueStringBuilder(initialBuffer);
+ GetUserName(ref builder);
+
+ ReadOnlySpan<char> name = builder.AsSpan();
+ int index = name.IndexOf('\\');
+ if (index != -1)
+ {
+ // In the form of DOMAIN\User, cut off \User and return
+ return name.Slice(0, index).ToString();
+ }
+
+ // In theory we should never get use out of LookupAccountNameW as the above API should
+ // always return what we need. Can't find any clues in the historical sources, however.
+
+ // Domain names aren't typically long.
+ // https://support.microsoft.com/en-us/help/909264/naming-conventions-in-active-directory-for-computers-domains-sites-and
+ Span<char> initialDomainNameBuffer = stackalloc char[64];
+ var domainBuilder = new ValueStringBuilder(initialBuffer);
+ uint length = (uint)domainBuilder.Capacity;
- userDomainName = domainName.ToString();
+ // This API will fail to return the domain name without a buffer for the SID.
+ // SIDs are never over 68 bytes long.
+ Span<byte> sid = stackalloc byte[68];
+ uint sidLength = 68;
+
+ while (!Interop.Advapi32.LookupAccountNameW(null, ref builder.GetPinnableReference(), ref MemoryMarshal.GetReference(sid),
+ ref sidLength, ref domainBuilder.GetPinnableReference(), ref length, out _))
+ {
+ int error = Marshal.GetLastWin32Error();
+
+ // The docs don't call this out clearly, but experimenting shows that the error returned is the following.
+ if (error != Interop.Errors.ERROR_INSUFFICIENT_BUFFER)
+ {
+ throw new InvalidOperationException(Win32Marshal.GetMessage(error));
+ }
+
+ domainBuilder.EnsureCapacity((int)length);
+ }
+
+ domainBuilder.Length = (int)length;
+ return domainBuilder.ToString();
+ }
}
private static string GetFolderPathCore(SpecialFolder folder, SpecialFolderOption option)
@@ -224,8 +272,7 @@ namespace System
{
Guid folderId = new Guid(folderGuid);
- string path;
- int hr = Interop.Shell32.SHGetKnownFolderPath(folderId, (uint)option, IntPtr.Zero, out path);
+ int hr = Interop.Shell32.SHGetKnownFolderPath(folderId, (uint)option, IntPtr.Zero, out string path);
if (hr != 0) // Not S_OK
{
return string.Empty;
diff --git a/src/System.Runtime.Extensions/src/System/Environment.WinRT.cs b/src/System.Runtime.Extensions/src/System/Environment.WinRT.cs
index bf55d20f97..c757bea779 100644
--- a/src/System.Runtime.Extensions/src/System/Environment.WinRT.cs
+++ b/src/System.Runtime.Extensions/src/System/Environment.WinRT.cs
@@ -10,6 +10,9 @@ namespace System
{
public static partial class Environment
{
+ public static string UserName => "Windows User";
+ public static string UserDomainName => "Windows Domain";
+
private static string GetFolderPathCore(SpecialFolder folder, SpecialFolderOption option)
{
// For testing we'll fall back if the needed APIs aren't present.
diff --git a/src/System.Runtime.Extensions/src/System/Environment.Windows.cs b/src/System.Runtime.Extensions/src/System/Environment.Windows.cs
index 2caff315a0..317ddd2801 100644
--- a/src/System.Runtime.Extensions/src/System/Environment.Windows.cs
+++ b/src/System.Runtime.Extensions/src/System/Environment.Windows.cs
@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
@@ -16,41 +15,24 @@ namespace System
{
get
{
- StringBuilder sb = StringBuilderCache.Acquire(Interop.Kernel32.MAX_PATH + 1);
- if (Interop.Kernel32.GetCurrentDirectory(sb.Capacity, sb) == 0)
- {
- StringBuilderCache.Release(sb);
- throw Win32Marshal.GetExceptionForLastWin32Error();
- }
- string currentDirectory = sb.ToString();
+ Span<char> initialBuffer = stackalloc char[Interop.Kernel32.MAX_PATH];
+ var builder = new ValueStringBuilder(initialBuffer);
- // Note that if we have somehow put our command prompt into short
- // file name mode (i.e. by running edlin or a DOS grep, etc), then
- // this will return a short file name.
- if (currentDirectory.IndexOf('~') >= 0)
+ uint length;
+ while ((length = Interop.Kernel32.GetCurrentDirectory((uint)builder.Capacity, ref builder.GetPinnableReference())) > builder.Capacity)
{
- int r = Interop.Kernel32.GetLongPathName(currentDirectory, sb, sb.Capacity);
- if (r == 0 || r >= Interop.Kernel32.MAX_PATH)
- {
- int errorCode = r >= Interop.Kernel32.MAX_PATH ?
- Interop.Errors.ERROR_FILENAME_EXCED_RANGE :
- Marshal.GetLastWin32Error();
-
- if (errorCode != Interop.Errors.ERROR_FILE_NOT_FOUND &&
- errorCode != Interop.Errors.ERROR_PATH_NOT_FOUND &&
- errorCode != Interop.Errors.ERROR_INVALID_FUNCTION &&
- errorCode != Interop.Errors.ERROR_ACCESS_DENIED)
- {
- StringBuilderCache.Release(sb);
- throw Win32Marshal.GetExceptionForWin32Error(errorCode);
- }
- }
-
- currentDirectory = sb.ToString();
+ builder.EnsureCapacity((int)length);
}
- StringBuilderCache.Release(sb);
- return currentDirectory;
+ if (length == 0)
+ throw Win32Marshal.GetExceptionForLastWin32Error();
+
+ builder.Length = (int)length;
+
+ // If we have a tilde in the path, make an attempt to expand 8.3 filenames
+ return builder.AsSpan().IndexOf('~') >= 0
+ ? PathHelper.TryExpandShortFileName(ref builder, null)
+ : builder.ToString();
}
set
{
@@ -72,8 +54,7 @@ namespace System
{
get
{
- var info = default(Interop.Kernel32.SYSTEM_INFO);
- Interop.Kernel32.GetSystemInfo(out info);
+ Interop.Kernel32.GetSystemInfo(out Interop.Kernel32.SYSTEM_INFO info);
return info.dwPageSize;
}
}
@@ -82,42 +63,25 @@ namespace System
private static string ExpandEnvironmentVariablesCore(string name)
{
- int currentSize = 100;
- StringBuilder result = StringBuilderCache.Acquire(currentSize); // A somewhat reasonable default size
+ Span<char> initialBuffer = stackalloc char[128];
+ var builder = new ValueStringBuilder(initialBuffer);
- result.Length = 0;
- int size = Interop.Kernel32.ExpandEnvironmentStringsW(name, result, currentSize);
- if (size == 0)
+ uint length;
+ while ((length = Interop.Kernel32.ExpandEnvironmentStringsW(name, ref builder.GetPinnableReference(), (uint)builder.Capacity)) > builder.Capacity)
{
- StringBuilderCache.Release(result);
- Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
+ builder.EnsureCapacity((int)length);
}
- while (size > currentSize)
- {
- currentSize = size;
- result.Length = 0;
- result.Capacity = currentSize;
-
- size = Interop.Kernel32.ExpandEnvironmentStringsW(name, result, currentSize);
- if (size == 0)
- {
- StringBuilderCache.Release(result);
- Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
- }
- }
+ if (length == 0)
+ Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
- return StringBuilderCache.GetStringAndRelease(result);
+ // length includes the null terminator
+ builder.Length = (int)length - 1;
+ return builder.ToString();
}
private static bool Is64BitOperatingSystemWhen32BitProcess
- {
- get
- {
- bool isWow64;
- return Interop.Kernel32.IsWow64Process(Interop.Kernel32.GetCurrentProcess(), out isWow64) && isWow64;
- }
- }
+ => Interop.Kernel32.IsWow64Process(Interop.Kernel32.GetCurrentProcess(), out bool isWow64) && isWow64;
public static string MachineName
{
@@ -150,47 +114,22 @@ namespace System
{
get
{
- // The path will likely be under 32 characters, e.g. C:\Windows\system32
- Span<char> buffer = stackalloc char[32];
- int requiredSize = Interop.Kernel32.GetSystemDirectoryW(buffer);
+ // Normally this will be C:\Windows\System32
+ Span<char> initialBuffer = stackalloc char[32];
+ var builder = new ValueStringBuilder(initialBuffer);
- if (requiredSize > buffer.Length)
+ uint length;
+ while ((length = Interop.Kernel32.GetSystemDirectoryW(ref builder.GetPinnableReference(), (uint)builder.Capacity)) > builder.Capacity)
{
- buffer = new char[requiredSize];
- requiredSize = Interop.Kernel32.GetSystemDirectoryW(buffer);
+ builder.EnsureCapacity((int)length);
}
- if (requiredSize == 0)
- {
+ if (length == 0)
throw Win32Marshal.GetExceptionForLastWin32Error();
- }
- return new string(buffer.Slice(0, requiredSize));
- }
- }
-
- public static string UserName
- {
- get
- {
- string username = "Windows User";
- GetUserName(ref username);
- return username;
+ builder.Length = (int)length;
+ return builder.ToString();
}
}
-
- static partial void GetUserName(ref string username);
-
- public static string UserDomainName
- {
- get
- {
- string userDomainName = "Windows Domain";
- GetDomainName(ref userDomainName);
- return userDomainName;
- }
- }
-
- static partial void GetDomainName(ref string userDomainName);
}
}
diff --git a/src/System.Runtime.Extensions/src/System/Environment.cs b/src/System.Runtime.Extensions/src/System/Environment.cs
index 213ec53ee0..448b434753 100644
--- a/src/System.Runtime.Extensions/src/System/Environment.cs
+++ b/src/System.Runtime.Extensions/src/System/Environment.cs
@@ -2,13 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using Internal.Runtime.Augments;
using System.Collections;
using System.Collections.Generic;
-using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
-using System.Text;
+using Internal.Runtime.Augments;
namespace System
{
@@ -65,35 +63,7 @@ namespace System
{
get
{
- StringBuilder sb = StringBuilderCache.Acquire();
-
- foreach (string arg in GetCommandLineArgs())
- {
- bool containsQuotes = false, containsWhitespace = false;
- foreach (char c in arg)
- {
- if (char.IsWhiteSpace(c))
- {
- containsWhitespace = true;
- }
- else if (c == '"')
- {
- containsQuotes = true;
- }
- }
-
- string quote = containsWhitespace ? "\"" : "";
- string formattedArg = containsQuotes && containsWhitespace ? arg.Replace("\"", "\\\"") : arg;
-
- sb.Append(quote).Append(formattedArg).Append(quote).Append(' ');
- }
-
- if (sb.Length > 0)
- {
- sb.Length--;
- }
-
- return StringBuilderCache.GetStringAndRelease(sb);
+ return PasteArguments.Paste(GetCommandLineArgs(), pasteFirstArgumentUsingArgV0Rules: true);
}
}
diff --git a/src/System.Runtime.Extensions/src/System/Globalization/Extensions.cs b/src/System.Runtime.Extensions/src/System/Globalization/Extensions.cs
deleted file mode 100644
index 080dd877e1..0000000000
--- a/src/System.Runtime.Extensions/src/System/Globalization/Extensions.cs
+++ /dev/null
@@ -1,99 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Diagnostics;
-using System.Diagnostics.Private;
-
-namespace System.Globalization
-{
- public static class GlobalizationExtensions
- {
- public static StringComparer GetStringComparer(this CompareInfo compareInfo, CompareOptions options)
- {
- if (compareInfo == null)
- {
- throw new ArgumentNullException(nameof(compareInfo));
- }
-
- if (options == CompareOptions.Ordinal)
- {
- return StringComparer.Ordinal;
- }
-
- if (options == CompareOptions.OrdinalIgnoreCase)
- {
- return StringComparer.OrdinalIgnoreCase;
- }
-
- if ((options & CultureAwareComparer.ValidCompareMaskOffFlags) != 0)
- {
- throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options));
- }
-
- return new CultureAwareComparer(compareInfo, options);
- }
- }
-
- [Serializable]
- internal sealed class CultureAwareComparer : StringComparer
- {
- internal const CompareOptions ValidCompareMaskOffFlags =
- ~(CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols | CompareOptions.IgnoreNonSpace |
- CompareOptions.IgnoreWidth | CompareOptions.IgnoreKanaType | CompareOptions.StringSort);
-
- private readonly CompareInfo _compareInfo;
- private readonly CompareOptions _options;
-
- internal CultureAwareComparer(CompareInfo compareInfo, CompareOptions options)
- {
- Debug.Assert((options & ValidCompareMaskOffFlags) == 0);
- _compareInfo = compareInfo;
- _options = options;
- }
-
- public override int Compare(string x, string y)
- {
- if (Object.ReferenceEquals(x, y)) return 0;
- if (x == null) return -1;
- if (y == null) return 1;
- return _compareInfo.Compare(x, y, _options);
- }
-
- public override bool Equals(string x, string y)
- {
- if (Object.ReferenceEquals(x, y)) return true;
- if (x == null || y == null) return false;
-
- return (_compareInfo.Compare(x, y, _options) == 0);
- }
-
- public override int GetHashCode(string obj)
- {
- if (obj == null)
- {
- throw new ArgumentNullException(nameof(obj));
- }
-
- // StringSort used in compare operation and not with the hashing
- return _compareInfo.GetHashCode(obj, _options & (~CompareOptions.StringSort));
- }
-
- // Equals method for the comparer itself.
- public override bool Equals(object obj)
- {
- CultureAwareComparer comparer = obj as CultureAwareComparer;
- return
- comparer != null &&
- _options == comparer._options &&
- _compareInfo.Equals(comparer._compareInfo);
- }
-
- public override int GetHashCode()
- {
- return _compareInfo.GetHashCode() ^ ((int)_options & 0x7FFFFFFF);
- }
- }
-}
-
diff --git a/src/System.Runtime.Extensions/src/System/IO/BufferedStream.cs b/src/System.Runtime.Extensions/src/System/IO/BufferedStream.cs
index 90ac28ce24..5398c47ca7 100644
--- a/src/System.Runtime.Extensions/src/System/IO/BufferedStream.cs
+++ b/src/System.Runtime.Extensions/src/System/IO/BufferedStream.cs
@@ -413,7 +413,7 @@ namespace System.IO
Debug.Assert(_buffer != null && _bufferSize >= _writePos,
"BufferedStream: Write buffer must be allocated and write position must be in the bounds of the buffer in FlushWrite!");
- await _stream.WriteAsync(_buffer, 0, _writePos, cancellationToken).ConfigureAwait(false);
+ await _stream.WriteAsync(new ReadOnlyMemory<byte>(_buffer, 0, _writePos), cancellationToken).ConfigureAwait(false);
_writePos = 0;
await _stream.FlushAsync(cancellationToken).ConfigureAwait(false);
}
@@ -440,8 +440,7 @@ namespace System.IO
Debug.Assert(readbytes >= 0);
if (readbytes > 0)
{
- bool copied = new Span<byte>(_buffer, _readPos, readbytes).TryCopyTo(destination);
- Debug.Assert(copied);
+ new ReadOnlySpan<byte>(_buffer, _readPos, readbytes).CopyTo(destination);
_readPos += readbytes;
}
return readbytes;
@@ -645,7 +644,7 @@ namespace System.IO
cancellationToken, bytesFromBuffer, semaphoreLockTask).AsTask();
}
- public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken = default(CancellationToken))
+ public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default(CancellationToken))
{
if (cancellationToken.IsCancellationRequested)
{
@@ -663,8 +662,8 @@ namespace System.IO
bool completeSynchronously = true;
try
{
- bytesFromBuffer = ReadFromBuffer(destination.Span);
- completeSynchronously = bytesFromBuffer == destination.Length;
+ bytesFromBuffer = ReadFromBuffer(buffer.Span);
+ completeSynchronously = bytesFromBuffer == buffer.Length;
if (completeSynchronously)
{
// If we satisfied enough data from the buffer, we can complete synchronously.
@@ -681,7 +680,7 @@ namespace System.IO
}
// Delegate to the async implementation.
- return ReadFromUnderlyingStreamAsync(destination.Slice(bytesFromBuffer), cancellationToken, bytesFromBuffer, semaphoreLockTask);
+ return ReadFromUnderlyingStreamAsync(buffer.Slice(bytesFromBuffer), cancellationToken, bytesFromBuffer, semaphoreLockTask);
}
/// <summary>BufferedStream should be as thin a wrapper as possible. We want ReadAsync to delegate to
@@ -732,7 +731,7 @@ namespace System.IO
// Ok. We can fill the buffer:
EnsureBufferAllocated();
- _readLen = await _stream.ReadAsync(_buffer, 0, _bufferSize, cancellationToken).ConfigureAwait(false);
+ _readLen = await _stream.ReadAsync(new Memory<byte>(_buffer, 0, _bufferSize), cancellationToken).ConfigureAwait(false);
bytesFromBuffer = ReadFromBuffer(buffer.Span);
return bytesAlreadySatisfied + bytesFromBuffer;
@@ -797,13 +796,13 @@ namespace System.IO
offset += bytesToWrite;
}
- private int WriteToBuffer(ReadOnlySpan<byte> source)
+ private int WriteToBuffer(ReadOnlySpan<byte> buffer)
{
- int bytesToWrite = Math.Min(_bufferSize - _writePos, source.Length);
+ int bytesToWrite = Math.Min(_bufferSize - _writePos, buffer.Length);
if (bytesToWrite > 0)
{
EnsureBufferAllocated();
- source.Slice(0, bytesToWrite).CopyTo(new Span<byte>(_buffer, _writePos, bytesToWrite));
+ buffer.Slice(0, bytesToWrite).CopyTo(new Span<byte>(_buffer, _writePos, bytesToWrite));
_writePos += bytesToWrite;
}
return bytesToWrite;
@@ -958,7 +957,7 @@ namespace System.IO
}
}
- public override void Write(ReadOnlySpan<byte> source)
+ public override void Write(ReadOnlySpan<byte> buffer)
{
EnsureNotClosed();
EnsureCanWrite();
@@ -974,21 +973,21 @@ namespace System.IO
checked
{
// We do not expect buffer sizes big enough for an overflow, but if it happens, lets fail early:
- totalUserbytes = _writePos + source.Length;
- useBuffer = (totalUserbytes + source.Length < (_bufferSize + _bufferSize));
+ totalUserbytes = _writePos + buffer.Length;
+ useBuffer = (totalUserbytes + buffer.Length < (_bufferSize + _bufferSize));
}
if (useBuffer)
{
// Copy as much data to the buffer as will fit. If there's still room in the buffer,
// everything must have fit.
- int bytesWritten = WriteToBuffer(source);
+ int bytesWritten = WriteToBuffer(buffer);
if (_writePos < _bufferSize)
{
- Debug.Assert(bytesWritten == source.Length);
+ Debug.Assert(bytesWritten == buffer.Length);
return;
}
- source = source.Slice(bytesWritten);
+ buffer = buffer.Slice(bytesWritten);
Debug.Assert(_writePos == _bufferSize);
Debug.Assert(_buffer != null);
@@ -998,8 +997,8 @@ namespace System.IO
_writePos = 0;
// Now write the remainder. It must fit, as we're only on this path if that's true.
- bytesWritten = WriteToBuffer(source);
- Debug.Assert(bytesWritten == source.Length);
+ bytesWritten = WriteToBuffer(buffer);
+ Debug.Assert(bytesWritten == buffer.Length);
Debug.Assert(_writePos < _bufferSize);
}
@@ -1015,7 +1014,7 @@ namespace System.IO
if (totalUserbytes <= (_bufferSize + _bufferSize) && totalUserbytes <= MaxShadowBufferSize)
{
EnsureShadowBufferAllocated();
- source.CopyTo(new Span<byte>(_buffer, _writePos, source.Length));
+ buffer.CopyTo(new Span<byte>(_buffer, _writePos, buffer.Length));
_stream.Write(_buffer, 0, totalUserbytes);
_writePos = 0;
return;
@@ -1026,7 +1025,7 @@ namespace System.IO
}
// Write out user data.
- _stream.Write(source);
+ _stream.Write(buffer);
}
}
@@ -1041,15 +1040,15 @@ namespace System.IO
if (buffer.Length - offset < count)
throw new ArgumentException(SR.Argument_InvalidOffLen);
- return WriteAsync(new ReadOnlyMemory<byte>(buffer, offset, count), cancellationToken);
+ return WriteAsync(new ReadOnlyMemory<byte>(buffer, offset, count), cancellationToken).AsTask();
}
- public override Task WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken = default(CancellationToken))
+ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default(CancellationToken))
{
// Fast path check for cancellation already requested
if (cancellationToken.IsCancellationRequested)
{
- return Task.FromCanceled<int>(cancellationToken);
+ return new ValueTask(Task.FromCanceled<int>(cancellationToken));
}
EnsureNotClosed();
@@ -1071,12 +1070,12 @@ namespace System.IO
Debug.Assert(_writePos < _bufferSize);
// If the write completely fits into the buffer, we can complete synchronously:
- completeSynchronously = source.Length < _bufferSize - _writePos;
+ completeSynchronously = buffer.Length < _bufferSize - _writePos;
if (completeSynchronously)
{
- int bytesWritten = WriteToBuffer(source.Span);
- Debug.Assert(bytesWritten == source.Length);
- return Task.CompletedTask;
+ int bytesWritten = WriteToBuffer(buffer.Span);
+ Debug.Assert(bytesWritten == buffer.Length);
+ return default;
}
}
finally
@@ -1087,7 +1086,7 @@ namespace System.IO
}
// Delegate to the async implementation.
- return WriteToUnderlyingStreamAsync(source, cancellationToken, semaphoreLockTask);
+ return new ValueTask(WriteToUnderlyingStreamAsync(buffer, cancellationToken, semaphoreLockTask));
}
/// <summary>BufferedStream should be as thin a wrapper as possible. We want WriteAsync to delegate to
@@ -1096,7 +1095,7 @@ namespace System.IO
/// little as possible.
/// </summary>
private async Task WriteToUnderlyingStreamAsync(
- ReadOnlyMemory<byte> source, CancellationToken cancellationToken, Task semaphoreLockTask)
+ ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken, Task semaphoreLockTask)
{
Debug.Assert(_stream != null);
Debug.Assert(_stream.CanWrite);
@@ -1119,29 +1118,29 @@ namespace System.IO
checked
{
// We do not expect buffer sizes big enough for an overflow, but if it happens, lets fail early:
- totalUserBytes = _writePos + source.Length;
- useBuffer = (totalUserBytes + source.Length < (_bufferSize + _bufferSize));
+ totalUserBytes = _writePos + buffer.Length;
+ useBuffer = (totalUserBytes + buffer.Length < (_bufferSize + _bufferSize));
}
if (useBuffer)
{
- source = source.Slice(WriteToBuffer(source.Span));
+ buffer = buffer.Slice(WriteToBuffer(buffer.Span));
if (_writePos < _bufferSize)
{
- Debug.Assert(source.Length == 0);
+ Debug.Assert(buffer.Length == 0);
return;
}
- Debug.Assert(source.Length >= 0);
+ Debug.Assert(buffer.Length >= 0);
Debug.Assert(_writePos == _bufferSize);
Debug.Assert(_buffer != null);
- await _stream.WriteAsync(_buffer, 0, _writePos, cancellationToken).ConfigureAwait(false);
+ await _stream.WriteAsync(new ReadOnlyMemory<byte>(_buffer, 0, _writePos), cancellationToken).ConfigureAwait(false);
_writePos = 0;
- int bytesWritten = WriteToBuffer(source.Span);
- Debug.Assert(bytesWritten == source.Length);
+ int bytesWritten = WriteToBuffer(buffer.Span);
+ Debug.Assert(bytesWritten == buffer.Length);
Debug.Assert(_writePos < _bufferSize);
@@ -1158,19 +1157,19 @@ namespace System.IO
if (totalUserBytes <= (_bufferSize + _bufferSize) && totalUserBytes <= MaxShadowBufferSize)
{
EnsureShadowBufferAllocated();
- source.Span.CopyTo(new Span<byte>(_buffer, _writePos, source.Length));
+ buffer.Span.CopyTo(new Span<byte>(_buffer, _writePos, buffer.Length));
- await _stream.WriteAsync(_buffer, 0, totalUserBytes, cancellationToken).ConfigureAwait(false);
+ await _stream.WriteAsync(new ReadOnlyMemory<byte>(_buffer, 0, totalUserBytes), cancellationToken).ConfigureAwait(false);
_writePos = 0;
return;
}
- await _stream.WriteAsync(_buffer, 0, _writePos, cancellationToken).ConfigureAwait(false);
+ await _stream.WriteAsync(new ReadOnlyMemory<byte>(_buffer, 0, _writePos), cancellationToken).ConfigureAwait(false);
_writePos = 0;
}
// Write out user data.
- await _stream.WriteAsync(source, cancellationToken).ConfigureAwait(false);
+ await _stream.WriteAsync(buffer, cancellationToken).ConfigureAwait(false);
}
}
finally
@@ -1313,7 +1312,7 @@ namespace System.IO
{
// If there's any read data in the buffer, write it all to the destination stream.
Debug.Assert(_writePos == 0, "Write buffer must be empty if there's data in the read buffer");
- await destination.WriteAsync(_buffer, _readPos, readBytes, cancellationToken).ConfigureAwait(false);
+ await destination.WriteAsync(new ReadOnlyMemory<byte>(_buffer, _readPos, readBytes), cancellationToken).ConfigureAwait(false);
_readPos = _readLen = 0;
}
else if (_writePos > 0)
diff --git a/src/System.Runtime.Extensions/src/System/IO/StringReader.cs b/src/System.Runtime.Extensions/src/System/IO/StringReader.cs
index d3d50adb96..9951540c80 100644
--- a/src/System.Runtime.Extensions/src/System/IO/StringReader.cs
+++ b/src/System.Runtime.Extensions/src/System/IO/StringReader.cs
@@ -121,7 +121,7 @@ namespace System.IO
{
if (GetType() != typeof(StringReader))
{
- // This overload was added affter the Read(char[], ...) overload, and so in case
+ // This overload was added after the Read(char[], ...) overload, and so in case
// a derived type may have overridden it, we need to delegate to it, which the base does.
return base.Read(buffer);
}
@@ -139,7 +139,7 @@ namespace System.IO
n = buffer.Length;
}
- _s.AsReadOnlySpan().Slice(_pos, n).CopyTo(buffer);
+ _s.AsSpan(_pos, n).CopyTo(buffer);
_pos += n;
}
diff --git a/src/System.Runtime.Extensions/src/System/OperatingSystem.cs b/src/System.Runtime.Extensions/src/System/OperatingSystem.cs
index 743442edfc..1af20cbbf2 100644
--- a/src/System.Runtime.Extensions/src/System/OperatingSystem.cs
+++ b/src/System.Runtime.Extensions/src/System/OperatingSystem.cs
@@ -23,7 +23,7 @@ namespace System
{
if (platform < PlatformID.Win32S || platform > PlatformID.MacOSX)
{
- throw new ArgumentOutOfRangeException(nameof(platform), platform, SR.Arg_EnumIllegalVal);
+ throw new ArgumentOutOfRangeException(nameof(platform), platform, SR.Format(SR.Arg_EnumIllegalVal, platform));
}
if (version == null)
diff --git a/src/System.Runtime.Extensions/tests/Performance/System.Runtime.Extensions.Performance.Tests.csproj b/src/System.Runtime.Extensions/tests/Performance/System.Runtime.Extensions.Performance.Tests.csproj
index 7e7d8683cd..060e97e526 100644
--- a/src/System.Runtime.Extensions/tests/Performance/System.Runtime.Extensions.Performance.Tests.csproj
+++ b/src/System.Runtime.Extensions/tests/Performance/System.Runtime.Extensions.Performance.Tests.csproj
@@ -30,5 +30,8 @@
<Name>PerfRunner</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.Runtime.Extensions/tests/System.Runtime.Extensions.Tests.csproj b/src/System.Runtime.Extensions/tests/System.Runtime.Extensions.Tests.csproj
index 39599cc9b8..f064b76310 100644
--- a/src/System.Runtime.Extensions/tests/System.Runtime.Extensions.Tests.csproj
+++ b/src/System.Runtime.Extensions/tests/System.Runtime.Extensions.Tests.csproj
@@ -22,6 +22,9 @@
<Compile Include="System\ApplicationIdTests.cs" />
<Compile Include="System\Convert.cs" />
<Compile Include="System\EnvironmentTests.cs" />
+ <Compile Include="System\IO\PathTests.cs" />
+ <Compile Include="System\IO\PathTests_Windows_NetFX.cs" />
+ <Compile Include="System\IO\PathTests_Windows.cs" />
<Compile Include="System\OperatingSystemTests.cs" />
<Compile Include="System\Runtime\Versioning\VersioningHelperTests.cs" />
<Compile Include="System\AppDomainTests.cs" />
@@ -30,9 +33,16 @@
</Compile>
<Compile Include="System\Reflection\AssemblyNameProxyTests.cs" />
<Compile Include="System\MarshalByRefObjectTest.cs" />
+ <Compile Include="TestHelpers.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)'=='netcoreapp'">
<Compile Include="System\Random.netcoreapp.cs" />
+ <Compile Include="System\IO\Path.IsPathFullyQualified.netcoreapp.cs" />
+ <Compile Include="System\IO\PathTestsBase.netcoreapp.cs" />
+ <Compile Include="System\IO\PathTests_Windows.netcoreapp.cs" />
+ <Compile Include="System\IO\PathTests.netcoreapp.cs" />
+ <Compile Include="System\IO\PathTests_Unix.cs" />
+ <Compile Include="System\IO\PathTests_Join.netcoreapp.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)'!='netstandard'">
<Compile Include="System\BitConverterSpan.cs" />
@@ -52,9 +62,9 @@
<Compile Include="System\Environment.UserName.cs" />
<Compile Include="System\Diagnostics\Stopwatch.cs" />
<Compile Include="System\Environment.MachineName.cs" />
- <Compile Include="System\IO\Path.Combine.cs" />
+ <Compile Include="System\IO\PathTests_Combine.cs" />
<Compile Include="System\Runtime\Versioning\FrameworkName.cs" />
- <Compile Include="System\IO\PathTests.cs" />
+ <Compile Include="System\IO\PathTestsBase.cs" />
<Compile Include="System\Net\WebUtility.cs" />
<Compile Include="System\BitConverter.cs" />
<Compile Include="System\Convert.BoxedObjectCheck.cs" />
@@ -102,6 +112,9 @@
<Compile Include="$(CommonTestPath)\System\ShouldNotBeInvokedException.cs">
<Link>Common\System\ShouldNotBeInvokedException.cs</Link>
</Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\ByteUtils.cs">
+ <Link>Common\System\Security\Cryptography\ByteUtils.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(CommonTestPath)\System\Diagnostics\RemoteExecutorConsoleApp\RemoteExecutorConsoleApp.csproj">
@@ -125,5 +138,8 @@
<Name>TestApp</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Runtime.Extensions/tests/System/AppDomainTests.cs b/src/System.Runtime.Extensions/tests/System/AppDomainTests.cs
index cf51f3cac9..1f34257b31 100644
--- a/src/System.Runtime.Extensions/tests/System/AppDomainTests.cs
+++ b/src/System.Runtime.Extensions/tests/System/AppDomainTests.cs
@@ -335,14 +335,21 @@ namespace System.Tests
[Fact]
public void toString()
{
- string actual = AppDomain.CurrentDomain.ToString();
+ // Workaround issue: UWP culture is process wide
+ RemoteInvoke(() =>
+ {
+ CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture;
- // NetFx has additional line endings
- if (PlatformDetection.IsFullFramework)
- actual = actual.Trim();
+ string actual = AppDomain.CurrentDomain.ToString();
- string expected = "Name:" + AppDomain.CurrentDomain.FriendlyName + Environment.NewLine + "There are no context policies.";
- Assert.Equal(expected, actual);
+ // NetFx has additional line endings
+ if (PlatformDetection.IsFullFramework)
+ actual = actual.Trim();
+
+ string expected = "Name:" + AppDomain.CurrentDomain.FriendlyName + Environment.NewLine + "There are no context policies.";
+ Assert.Equal(expected, actual);
+
+ }).Dispose();
}
[Fact]
diff --git a/src/System.Runtime.Extensions/tests/System/Convert.netcoreapp.cs b/src/System.Runtime.Extensions/tests/System/Convert.netcoreapp.cs
index ec1db8cc18..2e96ca0a1b 100644
--- a/src/System.Runtime.Extensions/tests/System/Convert.netcoreapp.cs
+++ b/src/System.Runtime.Extensions/tests/System/Convert.netcoreapp.cs
@@ -3,8 +3,12 @@
// See the LICENSE file in the project root for more information.
using System.Linq;
+using System.Text;
+using System.Collections.Generic;
using Xunit;
+using Test.Cryptography;
+
namespace System.Tests
{
public partial class ConvertTests
@@ -90,72 +94,258 @@ namespace System.Tests
}
[Theory]
- [InlineData("")]
- [InlineData("BQYHCA==")]
- [InlineData(
- "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4\r\n" +
- "OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3Bx\r\n" +
- "cnN0dXZ3")]
- public void TryFromBase64String_MatchesFromBase64String(string stringInput)
+ [MemberData(nameof(Base64TestData))]
+ public static void TryFromBase64String(string encoded, byte[] expected)
{
- byte[] expected = Convert.FromBase64String(stringInput);
- Span<byte> dest;
+ if (expected == null)
+ {
+ Span<byte> actual = new byte[1000];
+ bool success = Convert.TryFromBase64String(encoded, actual, out int bytesWritten);
+ Assert.False(success);
+ Assert.Equal(0, bytesWritten);
+ }
+ else
+ {
+ // Exact-sized buffer
+ {
+ byte[] actual = new byte[expected.Length];
+ bool success = Convert.TryFromBase64String(encoded, actual, out int bytesWritten);
+ Assert.True(success);
+ Assert.Equal<byte>(expected, actual);
+ Assert.Equal(expected.Length, bytesWritten);
+ }
- // Just the right length
- dest = new byte[expected.Length];
- Assert.True(Convert.TryFromBase64String(stringInput, dest, out int bytesWritten));
- Assert.Equal(expected.Length, bytesWritten);
- Assert.Equal<byte>(expected, dest.ToArray());
+ // Buffer too short
+ if (expected.Length != 0)
+ {
+ byte[] actual = new byte[expected.Length - 1];
+ bool success = Convert.TryFromBase64String(encoded, actual, out int bytesWritten);
+ Assert.False(success);
+ Assert.Equal(0, bytesWritten);
+ }
- // Too short
- if (expected.Length > 0)
+ // Buffer larger than needed
+ {
+ byte[] actual = new byte[expected.Length + 1];
+ actual[expected.Length] = 99;
+ bool success = Convert.TryFromBase64String(encoded, actual, out int bytesWritten);
+ Assert.True(success);
+ Assert.Equal(99, actual[expected.Length]);
+ Assert.Equal<byte>(expected, actual.Take(expected.Length));
+ Assert.Equal(expected.Length, bytesWritten);
+ }
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(Base64TestData))]
+ public static void TryFromBase64Chars(string encodedAsString, byte[] expected)
+ {
+ ReadOnlySpan<char> encoded = encodedAsString; // Executing the conversion to ROS here so people debugging don't have to step through it at the api callsite.
+ if (expected == null)
{
- dest = new byte[expected.Length - 1];
- Assert.False(Convert.TryFromBase64String(stringInput, dest, out bytesWritten));
+ Span<byte> actual = new byte[1000];
+ bool success = Convert.TryFromBase64Chars(encoded, actual, out int bytesWritten);
+ Assert.False(success);
Assert.Equal(0, bytesWritten);
}
+ else
+ {
+ // Exact-sized buffer
+ {
+ byte[] actual = new byte[expected.Length];
+ bool success = Convert.TryFromBase64Chars(encoded, actual, out int bytesWritten);
+ Assert.True(success);
+ Assert.Equal<byte>(expected, actual);
+ Assert.Equal(expected.Length, bytesWritten);
+ }
- // Longer than needed
- dest = new byte[expected.Length + 1];
- Assert.True(Convert.TryFromBase64String(stringInput, dest, out bytesWritten));
- Assert.Equal(expected.Length, bytesWritten);
- Assert.Equal<byte>(expected, dest.Slice(0, expected.Length).ToArray());
- Assert.Equal(0, dest[dest.Length - 1]);
+ // Buffer too short
+ if (expected.Length != 0)
+ {
+ byte[] actual = new byte[expected.Length - 1];
+ bool success = Convert.TryFromBase64Chars(encoded, actual, out int bytesWritten);
+ Assert.False(success);
+ Assert.Equal(0, bytesWritten);
+ }
+
+ // Buffer larger than needed
+ {
+ byte[] actual = new byte[expected.Length + 1];
+ actual[expected.Length] = 99;
+ bool success = Convert.TryFromBase64Chars(encoded, actual, out int bytesWritten);
+ Assert.True(success);
+ Assert.Equal(99, actual[expected.Length]);
+ Assert.Equal<byte>(expected, actual.Take(expected.Length));
+ Assert.Equal(expected.Length, bytesWritten);
+ }
+ }
}
- [Theory]
- [InlineData("")]
- [InlineData("BQYHCA==")]
- [InlineData(
- "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4\r\n" +
- "OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3Bx\r\n" +
- "cnN0dXZ3")]
- public void TryFromBase64Chars_MatchesFromBase64CharArray(string stringInput)
+ public static IEnumerable<object[]> Base64TestData
{
- char[] charArrayInput = stringInput.ToCharArray();
- byte[] expected = Convert.FromBase64CharArray(charArrayInput, 0, charArrayInput.Length);
- Span<byte> dest;
+ get
+ {
+ foreach (Tuple<string, byte[]> tuple in Base64TestDataSeed)
+ {
+ yield return new object[] { tuple.Item1, tuple.Item2 };
+ yield return new object[] { InsertSpaces(tuple.Item1, 1), tuple.Item2 };
+ yield return new object[] { InsertSpaces(tuple.Item1, 4), tuple.Item2 };
+ }
+ }
+ }
- // Just the right length
- dest = new byte[expected.Length];
- Assert.True(Convert.TryFromBase64Chars(charArrayInput.AsReadOnlySpan(), dest, out int bytesWritten));
- Assert.Equal(expected.Length, bytesWritten);
- Assert.Equal<byte>(expected, dest.ToArray());
+ public static IEnumerable<Tuple<string, byte[]>> Base64TestDataSeed
+ {
+ get
+ {
+ // Empty
+ yield return Tuple.Create<string, byte[]>("", Array.Empty<byte>());
- // Too short
- if (expected.Length > 0)
+ // All whitespace characters.
+ yield return Tuple.Create<string, byte[]>(" \t\r\n", Array.Empty<byte>());
+
+ // Pad characters
+ yield return Tuple.Create<string, byte[]>("BQYHCAZ=", "0506070806".HexToByteArray());
+ yield return Tuple.Create<string, byte[]>("BQYHCA==", "05060708".HexToByteArray());
+
+ // Typical
+ yield return Tuple.Create<string, byte[]>(
+ "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0" +
+ "BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3",
+
+ ("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E" +
+ "3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677").HexToByteArray()
+ );
+
+ // Input length not multiple of 4
+ yield return Tuple.Create<string, byte[]>("A", null);
+ yield return Tuple.Create<string, byte[]>("AA", null);
+ yield return Tuple.Create<string, byte[]>("AAA", null);
+ yield return Tuple.Create<string, byte[]>("AAAAA", null);
+ yield return Tuple.Create<string, byte[]>("AAAAAA", null);
+ yield return Tuple.Create<string, byte[]>("AAAAAAA", null);
+
+ // Cannot continue past end pad
+ yield return Tuple.Create<string, byte[]>("AAA=BBBB", null);
+ yield return Tuple.Create<string, byte[]>("AA==BBBB", null);
+
+ // Cannot have more than two end pads
+ yield return Tuple.Create<string, byte[]>("A===", null);
+ yield return Tuple.Create<string, byte[]>("====", null);
+
+ // Verify negative entries of charmap.
+ for (int i = 0; i < 256; i++)
+ {
+ char c = (char)i;
+ if (!IsValidBase64Char(c))
+ {
+ string text = new string(c, 1) + "AAA";
+ yield return Tuple.Create<string, byte[]>(text, null);
+ }
+ }
+
+ // Verify >255 character handling.
+ string largerThanByte = new string((char)256, 1);
+ yield return Tuple.Create<string, byte[]>(largerThanByte + "AAA", null);
+ yield return Tuple.Create<string, byte[]>("A" + largerThanByte + "AA", null);
+ yield return Tuple.Create<string, byte[]>("AA" + largerThanByte + "A", null);
+ yield return Tuple.Create<string, byte[]>("AAA" + largerThanByte, null);
+ yield return Tuple.Create<string, byte[]>("AAAA" + largerThanByte + "AAA", null);
+ yield return Tuple.Create<string, byte[]>("AAAA" + "A" + largerThanByte + "AA", null);
+ yield return Tuple.Create<string, byte[]>("AAAA" + "AA" + largerThanByte + "A", null);
+ yield return Tuple.Create<string, byte[]>("AAAA" + "AAA" + largerThanByte, null);
+
+ // Verify positive entries of charmap.
+ yield return Tuple.Create<string, byte[]>("+A==", new byte[] { 0xf8 });
+ yield return Tuple.Create<string, byte[]>("/A==", new byte[] { 0xfc });
+ yield return Tuple.Create<string, byte[]>("0A==", new byte[] { 0xd0 });
+ yield return Tuple.Create<string, byte[]>("1A==", new byte[] { 0xd4 });
+ yield return Tuple.Create<string, byte[]>("2A==", new byte[] { 0xd8 });
+ yield return Tuple.Create<string, byte[]>("3A==", new byte[] { 0xdc });
+ yield return Tuple.Create<string, byte[]>("4A==", new byte[] { 0xe0 });
+ yield return Tuple.Create<string, byte[]>("5A==", new byte[] { 0xe4 });
+ yield return Tuple.Create<string, byte[]>("6A==", new byte[] { 0xe8 });
+ yield return Tuple.Create<string, byte[]>("7A==", new byte[] { 0xec });
+ yield return Tuple.Create<string, byte[]>("8A==", new byte[] { 0xf0 });
+ yield return Tuple.Create<string, byte[]>("9A==", new byte[] { 0xf4 });
+ yield return Tuple.Create<string, byte[]>("AA==", new byte[] { 0x00 });
+ yield return Tuple.Create<string, byte[]>("BA==", new byte[] { 0x04 });
+ yield return Tuple.Create<string, byte[]>("CA==", new byte[] { 0x08 });
+ yield return Tuple.Create<string, byte[]>("DA==", new byte[] { 0x0c });
+ yield return Tuple.Create<string, byte[]>("EA==", new byte[] { 0x10 });
+ yield return Tuple.Create<string, byte[]>("FA==", new byte[] { 0x14 });
+ yield return Tuple.Create<string, byte[]>("GA==", new byte[] { 0x18 });
+ yield return Tuple.Create<string, byte[]>("HA==", new byte[] { 0x1c });
+ yield return Tuple.Create<string, byte[]>("IA==", new byte[] { 0x20 });
+ yield return Tuple.Create<string, byte[]>("JA==", new byte[] { 0x24 });
+ yield return Tuple.Create<string, byte[]>("KA==", new byte[] { 0x28 });
+ yield return Tuple.Create<string, byte[]>("LA==", new byte[] { 0x2c });
+ yield return Tuple.Create<string, byte[]>("MA==", new byte[] { 0x30 });
+ yield return Tuple.Create<string, byte[]>("NA==", new byte[] { 0x34 });
+ yield return Tuple.Create<string, byte[]>("OA==", new byte[] { 0x38 });
+ yield return Tuple.Create<string, byte[]>("PA==", new byte[] { 0x3c });
+ yield return Tuple.Create<string, byte[]>("QA==", new byte[] { 0x40 });
+ yield return Tuple.Create<string, byte[]>("RA==", new byte[] { 0x44 });
+ yield return Tuple.Create<string, byte[]>("SA==", new byte[] { 0x48 });
+ yield return Tuple.Create<string, byte[]>("TA==", new byte[] { 0x4c });
+ yield return Tuple.Create<string, byte[]>("UA==", new byte[] { 0x50 });
+ yield return Tuple.Create<string, byte[]>("VA==", new byte[] { 0x54 });
+ yield return Tuple.Create<string, byte[]>("WA==", new byte[] { 0x58 });
+ yield return Tuple.Create<string, byte[]>("XA==", new byte[] { 0x5c });
+ yield return Tuple.Create<string, byte[]>("YA==", new byte[] { 0x60 });
+ yield return Tuple.Create<string, byte[]>("ZA==", new byte[] { 0x64 });
+ yield return Tuple.Create<string, byte[]>("aA==", new byte[] { 0x68 });
+ yield return Tuple.Create<string, byte[]>("bA==", new byte[] { 0x6c });
+ yield return Tuple.Create<string, byte[]>("cA==", new byte[] { 0x70 });
+ yield return Tuple.Create<string, byte[]>("dA==", new byte[] { 0x74 });
+ yield return Tuple.Create<string, byte[]>("eA==", new byte[] { 0x78 });
+ yield return Tuple.Create<string, byte[]>("fA==", new byte[] { 0x7c });
+ yield return Tuple.Create<string, byte[]>("gA==", new byte[] { 0x80 });
+ yield return Tuple.Create<string, byte[]>("hA==", new byte[] { 0x84 });
+ yield return Tuple.Create<string, byte[]>("iA==", new byte[] { 0x88 });
+ yield return Tuple.Create<string, byte[]>("jA==", new byte[] { 0x8c });
+ yield return Tuple.Create<string, byte[]>("kA==", new byte[] { 0x90 });
+ yield return Tuple.Create<string, byte[]>("lA==", new byte[] { 0x94 });
+ yield return Tuple.Create<string, byte[]>("mA==", new byte[] { 0x98 });
+ yield return Tuple.Create<string, byte[]>("nA==", new byte[] { 0x9c });
+ yield return Tuple.Create<string, byte[]>("oA==", new byte[] { 0xa0 });
+ yield return Tuple.Create<string, byte[]>("pA==", new byte[] { 0xa4 });
+ yield return Tuple.Create<string, byte[]>("qA==", new byte[] { 0xa8 });
+ yield return Tuple.Create<string, byte[]>("rA==", new byte[] { 0xac });
+ yield return Tuple.Create<string, byte[]>("sA==", new byte[] { 0xb0 });
+ yield return Tuple.Create<string, byte[]>("tA==", new byte[] { 0xb4 });
+ yield return Tuple.Create<string, byte[]>("uA==", new byte[] { 0xb8 });
+ yield return Tuple.Create<string, byte[]>("vA==", new byte[] { 0xbc });
+ yield return Tuple.Create<string, byte[]>("wA==", new byte[] { 0xc0 });
+ yield return Tuple.Create<string, byte[]>("xA==", new byte[] { 0xc4 });
+ yield return Tuple.Create<string, byte[]>("yA==", new byte[] { 0xc8 });
+ yield return Tuple.Create<string, byte[]>("zA==", new byte[] { 0xcc });
+ }
+ }
+
+ private static string InsertSpaces(string text, int period)
+ {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < text.Length; i++)
{
- dest = new byte[expected.Length - 1];
- Assert.False(Convert.TryFromBase64Chars(charArrayInput.AsReadOnlySpan(), dest, out bytesWritten));
- Assert.Equal(0, bytesWritten);
+ if ((i % period) == 0)
+ {
+ sb.Append(" ");
+ }
+ sb.Append(text[i]);
}
+ sb.Append(" ");
+ return sb.ToString();
+ }
- // Longer than needed
- dest = new byte[expected.Length + 1];
- Assert.True(Convert.TryFromBase64Chars(charArrayInput.AsReadOnlySpan(), dest, out bytesWritten));
- Assert.Equal(expected.Length, bytesWritten);
- Assert.Equal<byte>(expected, dest.Slice(0, dest.Length - 1).ToArray());
- Assert.Equal(0, dest[dest.Length - 1]);
+ private static bool IsValidBase64Char(char c)
+ {
+ return c >= 'A' && c <= 'Z'
+ || c >= 'a' && c <= 'z'
+ || c >= '0' && c <= '9'
+ || c == '+'
+ || c == '/';
}
}
}
diff --git a/src/System.Runtime.Extensions/tests/System/Environment.UserDomainName.cs b/src/System.Runtime.Extensions/tests/System/Environment.UserDomainName.cs
index 9cbdbed483..8c88b07a40 100644
--- a/src/System.Runtime.Extensions/tests/System/Environment.UserDomainName.cs
+++ b/src/System.Runtime.Extensions/tests/System/Environment.UserDomainName.cs
@@ -22,5 +22,28 @@ namespace System.Tests
// Highly unlikely anyone is using domain with this name
Assert.NotEqual("Windows Domain", Environment.UserDomainName);
}
+
+ [Fact]
+ public void UserDomainName_Valid()
+ {
+ string name = Environment.UserDomainName;
+ Assert.False(string.IsNullOrWhiteSpace(name));
+ Assert.Equal(-1, name.IndexOf('\0'));
+ }
+
+ [Fact]
+ [PlatformSpecific(TestPlatforms.AnyUnix)]
+ public void UserDomainName_MatchesMachineName_Unix()
+ {
+ Assert.Equal(Environment.MachineName, Environment.UserDomainName);
+ }
+
+ [Fact]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.Uap)]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void UserDomainName_MatchesEnvironment_Windows()
+ {
+ Assert.Equal(Environment.GetEnvironmentVariable("USERDOMAIN"), Environment.UserDomainName);
+ }
}
}
diff --git a/src/System.Runtime.Extensions/tests/System/Environment.UserName.cs b/src/System.Runtime.Extensions/tests/System/Environment.UserName.cs
index 3f88f165eb..31abd730cd 100644
--- a/src/System.Runtime.Extensions/tests/System/Environment.UserName.cs
+++ b/src/System.Runtime.Extensions/tests/System/Environment.UserName.cs
@@ -22,5 +22,21 @@ namespace System.Tests
// Highly unlikely anyone is using user with this name
Assert.NotEqual("Windows User", Environment.UserName);
}
+
+ [Fact]
+ public void UserName_Valid()
+ {
+ string name = Environment.UserName;
+ Assert.False(string.IsNullOrWhiteSpace(name));
+ Assert.Equal(-1, name.IndexOf('\0'));
+ }
+
+ [Fact]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.Uap)]
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public void UserName_MatchesEnvironment_Windows()
+ {
+ Assert.Equal(Environment.GetEnvironmentVariable("USERNAME"), Environment.UserName);
+ }
}
}
diff --git a/src/System.Runtime.Extensions/tests/System/EnvironmentTests.cs b/src/System.Runtime.Extensions/tests/System/EnvironmentTests.cs
index 3ac079082d..014342b7ad 100644
--- a/src/System.Runtime.Extensions/tests/System/EnvironmentTests.cs
+++ b/src/System.Runtime.Extensions/tests/System/EnvironmentTests.cs
@@ -149,25 +149,6 @@ namespace System.Tests
}
[Fact]
- public void UserName_Valid()
- {
- Assert.False(string.IsNullOrWhiteSpace(Environment.UserName));
- }
-
- [Fact]
- public void UserDomainName_Valid()
- {
- Assert.False(string.IsNullOrWhiteSpace(Environment.UserDomainName));
- }
-
- [Fact]
- [PlatformSpecific(TestPlatforms.AnyUnix)] // Tests OS-specific environment
- public void UserDomainName_Unix_MatchesMachineName()
- {
- Assert.Equal(Environment.MachineName, Environment.UserDomainName);
- }
-
- [Fact]
public void Version_MatchesFixedVersion()
{
Assert.Equal(new Version(4, 0, 30319, 42000), Environment.Version);
@@ -193,14 +174,18 @@ namespace System.Tests
[ActiveIssue("https://github.com/dotnet/corefx/issues/21404", TargetFrameworkMonikers.Uap)]
public void FailFast_ExpectFailureExitCode()
{
- using (Process p = RemoteInvoke(() => { Environment.FailFast("message"); return SuccessExitCode; }).Process)
+ using (RemoteInvokeHandle handle = RemoteInvoke(() => { Environment.FailFast("message"); return SuccessExitCode; }))
{
+ Process p = handle.Process;
+ handle.Process = null;
p.WaitForExit();
Assert.NotEqual(SuccessExitCode, p.ExitCode);
}
- using (Process p = RemoteInvoke(() => { Environment.FailFast("message", new Exception("uh oh")); return SuccessExitCode; }).Process)
+ using (RemoteInvokeHandle handle = RemoteInvoke(() => { Environment.FailFast("message", new Exception("uh oh")); return SuccessExitCode; }))
{
+ Process p = handle.Process;
+ handle.Process = null;
p.WaitForExit();
Assert.NotEqual(SuccessExitCode, p.ExitCode);
}
@@ -215,6 +200,27 @@ namespace System.Tests
Assert.Equal(Environment.GetEnvironmentVariable("HOME"), Environment.GetFolderPath(Environment.SpecialFolder.UserProfile));
}
+ [Theory]
+ [OuterLoop]
+ [PlatformSpecific(TestPlatforms.AnyUnix)] // Tests OS-specific environment
+ [InlineData(Environment.SpecialFolder.ApplicationData)]
+ [InlineData(Environment.SpecialFolder.Desktop)]
+ [InlineData(Environment.SpecialFolder.DesktopDirectory)]
+ [InlineData(Environment.SpecialFolder.Fonts)]
+ [InlineData(Environment.SpecialFolder.MyMusic)]
+ [InlineData(Environment.SpecialFolder.MyPictures)]
+ [InlineData(Environment.SpecialFolder.MyVideos)]
+ [InlineData(Environment.SpecialFolder.Templates)]
+ public void GetFolderPath_Unix_SpecialFolderDoesNotExist_CreatesSuccessfully(Environment.SpecialFolder folder)
+ {
+ string path = Environment.GetFolderPath(folder, Environment.SpecialFolderOption.DoNotVerify);
+ if (Directory.Exists(path))
+ return;
+ path = Environment.GetFolderPath(folder, Environment.SpecialFolderOption.Create);
+ Assert.True(Directory.Exists(path));
+ Directory.Delete(path);
+ }
+
[Fact]
public void GetSystemDirectory()
{
diff --git a/src/System.Runtime.Extensions/tests/System/IO/Path.IsPathFullyQualified.cs b/src/System.Runtime.Extensions/tests/System/IO/Path.IsPathFullyQualified.cs
index 9816e1659f..a240eb3c0d 100644
--- a/src/System.Runtime.Extensions/tests/System/IO/Path.IsPathFullyQualified.cs
+++ b/src/System.Runtime.Extensions/tests/System/IO/Path.IsPathFullyQualified.cs
@@ -9,7 +9,7 @@ namespace System.IO.Tests
public static class GetFullyQualifiedPathTests
{
[Fact]
- public static void IsPathFullyQualified_NullThrows()
+ public static void IsPathFullyQualified_NullArgument()
{
Assert.Throws<ArgumentNullException>(() => Path.IsPathFullyQualified(null));
}
@@ -67,6 +67,7 @@ namespace System.IO.Tests
public static void IsPathFullyQualified_Unix_Invalid(string path)
{
Assert.False(Path.IsPathFullyQualified(path));
+ Assert.False(Path.IsPathFullyQualified(path.AsSpan()));
}
[PlatformSpecific(TestPlatforms.AnyUnix)]
@@ -80,6 +81,7 @@ namespace System.IO.Tests
public static void IsPathFullyQualified_Unix_Valid(string path)
{
Assert.True(Path.IsPathFullyQualified(path));
+ Assert.True(Path.IsPathFullyQualified(path.AsSpan()));
}
}
}
diff --git a/src/System.Runtime.Extensions/tests/System/IO/Path.IsPathFullyQualified.netcoreapp.cs b/src/System.Runtime.Extensions/tests/System/IO/Path.IsPathFullyQualified.netcoreapp.cs
new file mode 100644
index 0000000000..f70ba4209d
--- /dev/null
+++ b/src/System.Runtime.Extensions/tests/System/IO/Path.IsPathFullyQualified.netcoreapp.cs
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.IO.Tests
+{
+ public static class GetFullyQualifiedPathSpanTests
+ {
+ [Fact]
+ public static void IsPathFullyQualified_Empty()
+ {
+ Assert.False(Path.IsPathFullyQualified(ReadOnlySpan<char>.Empty));
+ }
+
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [Theory]
+ [InlineData("/")]
+ [InlineData(@"\")]
+ [InlineData(".")]
+ [InlineData("C:")]
+ [InlineData("C:foo.txt")]
+ public static void IsPathFullyQualified_Windows_Invalid(string path)
+ {
+ Assert.False(Path.IsPathFullyQualified(path.AsSpan()));
+ }
+
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [Theory]
+ [InlineData(@"\\")]
+ [InlineData(@"\\\")]
+ [InlineData(@"\\Server")]
+ [InlineData(@"\\Server\Foo.txt")]
+ [InlineData(@"\\Server\Share\Foo.txt")]
+ [InlineData(@"\\Server\Share\Test\Foo.txt")]
+ [InlineData(@"C:\")]
+ [InlineData(@"C:\foo1")]
+ [InlineData(@"C:\\")]
+ [InlineData(@"C:\\foo2")]
+ [InlineData(@"C:/")]
+ [InlineData(@"C:/foo1")]
+ [InlineData(@"C://")]
+ [InlineData(@"C://foo2")]
+ public static void IsPathFullyQualified_Windows_Valid(string path)
+ {
+ Assert.True(Path.IsPathFullyQualified(path.AsSpan()));
+ }
+ }
+}
diff --git a/src/System.Runtime.Extensions/tests/System/IO/PathTests.cs b/src/System.Runtime.Extensions/tests/System/IO/PathTests.cs
index 4f690d7d10..e3f17889c0 100644
--- a/src/System.Runtime.Extensions/tests/System/IO/PathTests.cs
+++ b/src/System.Runtime.Extensions/tests/System/IO/PathTests.cs
@@ -1,32 +1,30 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
-using System.Runtime.InteropServices;
using System.Text;
-using System.Text.RegularExpressions;
using Xunit;
namespace System.IO.Tests
{
- public static partial class PathTests
+ public partial class PathTests : PathTestsBase
{
- [Theory]
- [InlineData(null, null, null)]
- [InlineData(null, "exe", null)]
- [InlineData("", "", "")]
- [InlineData("file.exe", null, "file")]
- [InlineData("file.exe", "", "file.")]
- [InlineData("file", "exe", "file.exe")]
- [InlineData("file", ".exe", "file.exe")]
- [InlineData("file.txt", "exe", "file.exe")]
- [InlineData("file.txt", ".exe", "file.exe")]
- [InlineData("file.txt.bin", "exe", "file.txt.exe")]
- [InlineData("dir/file.t", "exe", "dir/file.exe")]
- [InlineData("dir/file.exe", "t", "dir/file.t")]
- [InlineData("dir/file", "exe", "dir/file.exe")]
- public static void ChangeExtension(string path, string newExtension, string expected)
+ [Theory,
+ InlineData(null, null, null),
+ InlineData(null, "exe", null),
+ InlineData("", "", ""),
+ InlineData("file.exe", null, "file"),
+ InlineData("file.exe", "", "file."),
+ InlineData("file", "exe", "file.exe"),
+ InlineData("file", ".exe", "file.exe"),
+ InlineData("file.txt", "exe", "file.exe"),
+ InlineData("file.txt", ".exe", "file.exe"),
+ InlineData("file.txt.bin", "exe", "file.txt.exe"),
+ InlineData("dir/file.t", "exe", "dir/file.exe"),
+ InlineData("dir/file.exe", "t", "dir/file.t"),
+ InlineData("dir/file", "exe", "dir/file.exe")]
+ public void ChangeExtension(string path, string newExtension, string expected)
{
if (expected != null)
expected = expected.Replace('/', Path.DirectorySeparatorChar);
@@ -36,214 +34,78 @@ namespace System.IO.Tests
}
[Fact]
- public static void GetDirectoryName_EmptyThrows()
- {
- AssertExtensions.Throws<ArgumentException>("path", null, () => Path.GetDirectoryName(string.Empty));
- }
-
- [Theory,
- InlineData(" "),
- InlineData("\r\n")]
- [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)]
- public static void GetDirectoryName_SpaceOrControlCharsThrowOnWindows(string path)
- {
- Action action = () => Path.GetDirectoryName(path);
- if (PlatformDetection.IsWindows)
- {
- AssertExtensions.Throws<ArgumentException>("path", null, () => Path.GetDirectoryName(path));
- }
- else
- {
- // These are valid paths on Unix
- action();
- }
- }
-
- [Fact]
- [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
- public static void GetDirectoryName_SpaceThrowOnWindows_Core()
+ public void GetDirectoryName_NullReturnsNull()
{
- string path = " ";
- Action action = () => Path.GetDirectoryName(path);
- if (PlatformDetection.IsWindows)
- {
- AssertExtensions.Throws<ArgumentException>("path", null, () => Path.GetDirectoryName(path));
- }
- else
- {
- // This is a valid path on Unix
- action();
- }
- }
-
- [Theory]
- [InlineData("\u00A0")] // Non-breaking Space
- [InlineData("\u2028")] // Line separator
- [InlineData("\u2029")] // Paragraph separator
- public static void GetDirectoryName_NonControl(string path)
- {
- Assert.Equal(string.Empty, Path.GetDirectoryName(path));
- }
-
- [Theory]
- [InlineData("\u00A0")] // Non-breaking Space
- [InlineData("\u2028")] // Line separator
- [InlineData("\u2029")] // Paragraph separator
- public static void GetDirectoryName_NonControlWithSeparator(string path)
- {
- Assert.Equal(path, Path.GetDirectoryName(Path.Combine(path, path)));
- }
-
- [Theory]
- [InlineData(null, null)]
- [InlineData(".", "")]
- [InlineData("..", "")]
- [InlineData("baz", "")]
- public static void GetDirectoryName(string path, string expected)
- {
- Assert.Equal(expected, Path.GetDirectoryName(path));
- }
-
- [Theory]
- [InlineData(@"dir/baz", "dir")]
- [InlineData(@"dir\baz", "dir")]
- [InlineData(@"dir\baz\bar", @"dir\baz")]
- [InlineData(@"dir\\baz", "dir")]
- [InlineData(@" dir\baz", " dir")]
- [InlineData(@" C:\dir\baz", @"C:\dir")]
- [InlineData(@"..\..\files.txt", @"..\..")]
- [InlineData(@"C:\", null)]
- [InlineData(@"C:", null)]
- [PlatformSpecific(TestPlatforms.Windows)] // Tests Windows-specific paths
- public static void GetDirectoryName_Windows(string path, string expected)
- {
- Assert.Equal(expected, Path.GetDirectoryName(path));
+ Assert.Null(Path.GetDirectoryName(null));
}
- [Theory]
- [InlineData(@"dir/baz", @"dir")]
- [InlineData(@"dir//baz", @"dir")]
- [InlineData(@"dir\baz", @"")]
- [InlineData(@"dir/baz/bar", @"dir/baz")]
- [InlineData(@"../../files.txt", @"../..")]
- [InlineData(@"/", null)]
- [PlatformSpecific(TestPlatforms.AnyUnix)] // Tests Unix-specific paths
- public static void GetDirectoryName_Unix(string path, string expected)
+ [Theory, MemberData(nameof(TestData_GetDirectoryName))]
+ public void GetDirectoryName(string path, string expected)
{
Assert.Equal(expected, Path.GetDirectoryName(path));
}
[Fact]
- public static void GetDirectoryName_CurrentDirectory()
+ public void GetDirectoryName_CurrentDirectory()
{
string curDir = Directory.GetCurrentDirectory();
Assert.Equal(curDir, Path.GetDirectoryName(Path.Combine(curDir, "baz")));
+
Assert.Equal(null, Path.GetDirectoryName(Path.GetPathRoot(curDir)));
}
- [PlatformSpecific(TestPlatforms.AnyUnix)] // Checks Unix-specific special characters in directory path
[Fact]
- public static void GetDirectoryName_ControlCharacters_Unix()
+ public void GetExtension_Null()
{
- Assert.Equal(new string('\t', 1), Path.GetDirectoryName(Path.Combine(new string('\t', 1), "file")));
- Assert.Equal(new string('\b', 2), Path.GetDirectoryName(Path.Combine(new string('\b', 2), "fi le")));
- Assert.Equal(new string('\v', 3), Path.GetDirectoryName(Path.Combine(new string('\v', 3), "fi\nle")));
- Assert.Equal(new string('\n', 4), Path.GetDirectoryName(Path.Combine(new string('\n', 4), "fi\rle")));
+ Assert.Null(Path.GetExtension(null));
}
- [Theory]
- [InlineData("file.exe", ".exe")]
- [InlineData("file", "")]
- [InlineData(null, null)]
- [InlineData("file.", "")]
- [InlineData("file.s", ".s")]
- [InlineData("test/file", "")]
- [InlineData("test/file.extension", ".extension")]
- public static void GetExtension(string path, string expected)
+ [Theory, MemberData(nameof(TestData_GetExtension))]
+ public void GetExtension(string path, string expected)
{
- if (path != null)
- {
- path = path.Replace('/', Path.DirectorySeparatorChar);
- }
Assert.Equal(expected, Path.GetExtension(path));
Assert.Equal(!string.IsNullOrEmpty(expected), Path.HasExtension(path));
}
- [PlatformSpecific(TestPlatforms.AnyUnix)] // Checks file extension behavior on Unix
- [Theory]
- [InlineData("file.e xe", ".e xe")]
- [InlineData("file. ", ". ")]
- [InlineData(" file. ", ". ")]
- [InlineData(" file.extension", ".extension")]
- [InlineData("file.exten\tsion", ".exten\tsion")]
- public static void GetExtension_Unix(string path, string expected)
+ [Fact]
+ public void GetFileName_Null()
{
- Assert.Equal(expected, Path.GetExtension(path));
- Assert.Equal(!string.IsNullOrEmpty(expected), Path.HasExtension(path));
+ Assert.Null(Path.GetFileName(null));
}
- public static IEnumerable<object[]> GetFileName_TestData()
+ [Fact]
+ public void GetFileName_Empty()
{
- yield return new object[] { null, null };
- yield return new object[] { ".", "." };
- yield return new object[] { "..", ".." };
- yield return new object[] { "file", "file" };
- yield return new object[] { "file.", "file." };
- yield return new object[] { "file.exe", "file.exe" };
- yield return new object[] { Path.Combine("baz", "file.exe"), "file.exe" };
- yield return new object[] { Path.Combine("bar", "baz", "file.exe"), "file.exe" };
- yield return new object[] { Path.Combine("bar", "baz", "file.exe") + Path.DirectorySeparatorChar, "" };
+ Assert.Empty(Path.GetFileName(string.Empty));
}
- [Theory]
- [MemberData(nameof(GetFileName_TestData))]
- public static void GetFileName(string path, string expected)
+ [Theory, MemberData(nameof(TestData_GetFileName))]
+ public void GetFileName(string path, string expected)
{
Assert.Equal(expected, Path.GetFileName(path));
+ Assert.Equal(expected, Path.GetFileName(Path.Combine("whizzle", path)));
}
- [PlatformSpecific(TestPlatforms.AnyUnix)] // Tests Unix-specific valid file names
[Fact]
- public static void GetFileName_Unix()
- {
- Assert.Equal(" . ", Path.GetFileName(" . "));
- Assert.Equal(" .. ", Path.GetFileName(" .. "));
- Assert.Equal("fi le", Path.GetFileName("fi le"));
- Assert.Equal("fi le", Path.GetFileName("fi le"));
- Assert.Equal("fi le", Path.GetFileName(Path.Combine("b \r\n ar", "fi le")));
- }
-
- public static IEnumerable<object[]> GetFileNameWithoutExtension_TestData()
+ public void GetFileNameWithoutExtension_Null()
{
- yield return new object[] { null, null };
- yield return new object[] { "", "" };
- yield return new object[] { "file", "file" };
- yield return new object[] { "file.exe", "file" };
- yield return new object[] { Path.Combine("bar", "baz", "file.exe"), "file" };
- yield return new object[] { Path.Combine("bar", "baz") + Path.DirectorySeparatorChar, "" };
+ Assert.Null(Path.GetFileNameWithoutExtension(null));
}
- [Theory]
- [MemberData(nameof(GetFileNameWithoutExtension_TestData))]
- public static void GetFileNameWithoutExtension(string path, string expected)
+ [Theory, MemberData(nameof(TestData_GetFileNameWithoutExtension))]
+ public void GetFileNameWithoutExtension(string path, string expected)
{
Assert.Equal(expected, Path.GetFileNameWithoutExtension(path));
}
[Fact]
- public static void GetPathRoot_NullReturnsNull()
+ public void GetPathRoot_Null()
{
Assert.Null(Path.GetPathRoot(null));
}
[Fact]
- public static void GetPathRoot_EmptyThrows()
- {
- AssertExtensions.Throws<ArgumentException>("path", null, () => Path.GetPathRoot(string.Empty));
- }
-
- [Fact]
- public static void GetPathRoot_Basic()
+ public void GetPathRoot_Basic()
{
string cwd = Directory.GetCurrentDirectory();
Assert.Equal(cwd.Substring(0, cwd.IndexOf(Path.DirectorySeparatorChar) + 1), Path.GetPathRoot(cwd));
@@ -253,150 +115,27 @@ namespace System.IO.Tests
Assert.False(Path.IsPathRooted("file.exe"));
}
- [PlatformSpecific(TestPlatforms.Windows)] // Tests UNC
- [Theory]
- [InlineData(@"\\test\unc\path\to\something", @"\\test\unc")]
- [InlineData(@"\\a\b\c\d\e", @"\\a\b")]
- [InlineData(@"\\a\b\", @"\\a\b")]
- [InlineData(@"\\a\b", @"\\a\b")]
- [InlineData(@"\\test\unc", @"\\test\unc")]
- public static void GetPathRoot_Windows_UncAndExtended(string value, string expected)
- {
- Assert.True(Path.IsPathRooted(value));
- Assert.Equal(expected, Path.GetPathRoot(value));
- }
-
- [PlatformSpecific(TestPlatforms.Windows)] // Tests UNC
- [Theory]
- [InlineData(@"\\?\UNC\test\unc", @"\\?\UNC", @"\\?\UNC\test\unc\path\to\something")]
- [InlineData(@"\\?\UNC\test\unc", @"\\?\UNC", @"\\?\UNC\test\unc")]
- [InlineData(@"\\?\UNC\a\b1", @"\\?\UNC", @"\\?\UNC\a\b1")]
- [InlineData(@"\\?\UNC\a\b2", @"\\?\UNC", @"\\?\UNC\a\b2\")]
- [InlineData(@"\\?\C:\", @"\\?\C:", @"\\?\C:\foo\bar.txt")]
- public static void GetPathRoot_Windows_UncAndExtended_WithLegacySupport(string normalExpected, string legacyExpected, string value)
- {
- Assert.True(Path.IsPathRooted(value));
-
- string expected = PathFeatures.IsUsingLegacyPathNormalization() ? legacyExpected : normalExpected;
- Assert.Equal(expected, Path.GetPathRoot(value));
- }
-
- [PlatformSpecific(TestPlatforms.Windows)] // Tests Windows-specific path convention
- [Theory]
- [InlineData(@"C:", @"C:")]
- [InlineData(@"C:\", @"C:\")]
- [InlineData(@"C:\\", @"C:\")]
- [InlineData(@"C://", @"C:\")]
- [InlineData(@"C:\foo1", @"C:\")]
- [InlineData(@"C:\\foo2", @"C:\")]
- [InlineData(@"C://foo3", @"C:\")]
- public static void GetPathRoot_Windows(string value, string expected)
- {
- Assert.True(Path.IsPathRooted(value));
- Assert.Equal(expected, Path.GetPathRoot(value));
- }
-
- [PlatformSpecific(TestPlatforms.AnyUnix)] // Tests Unix-specific path convention
[Fact]
- public static void GetPathRoot_Unix()
- {
- // slashes are normal filename characters
- string uncPath = @"\\test\unc\path\to\something";
- Assert.False(Path.IsPathRooted(uncPath));
- Assert.Equal(string.Empty, Path.GetPathRoot(uncPath));
- }
-
- [Theory]
- [InlineData(null)]
- [InlineData("")]
- [InlineData(" ")]
- public static void IsPathRooted(string path)
- {
- Assert.False(Path.IsPathRooted(path));
- }
-
- // Testing invalid drive letters !(a-zA-Z)
- [PlatformSpecific(TestPlatforms.Windows)]
- [Theory]
- [InlineData(@"@:\foo")] // 064 = @ 065 = A
- [InlineData(@"[:\\")] // 091 = [ 090 = Z
- [InlineData(@"`:\foo")] // 096 = ` 097 = a
- [InlineData(@"{:\\")] // 123 = { 122 = z
- [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Bug fixed on Core where it would return true if the first char is not a drive letter followed by a VolumeSeparatorChar coreclr/10297")]
- public static void IsPathRooted_Windows_Invalid(string value)
- {
- Assert.False(Path.IsPathRooted(value));
- }
-
- [Fact]
- public static void GetRandomFileName()
- {
- char[] invalidChars = Path.GetInvalidFileNameChars();
- var fileNames = new HashSet<string>();
- for (int i = 0; i < 100; i++)
- {
- string s = Path.GetRandomFileName();
- Assert.Equal(s.Length, 8 + 1 + 3);
- Assert.Equal(s[8], '.');
- Assert.Equal(-1, s.IndexOfAny(invalidChars));
- Assert.True(fileNames.Add(s));
- }
- }
-
- [Fact]
- [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)]
- public static void GetInvalidPathChars()
+ public void GetInvalidPathChars_Invariants()
{
Assert.NotNull(Path.GetInvalidPathChars());
Assert.NotSame(Path.GetInvalidPathChars(), Path.GetInvalidPathChars());
Assert.Equal((IEnumerable<char>)Path.GetInvalidPathChars(), Path.GetInvalidPathChars());
Assert.True(Path.GetInvalidPathChars().Length > 0);
- Assert.All(Path.GetInvalidPathChars(), c =>
- {
- string bad = c.ToString();
- AssertExtensions.Throws<ArgumentException>("path", null, () => Path.ChangeExtension(bad, "ok"));
- AssertExtensions.Throws<ArgumentException>("path", null, () => Path.Combine(bad, "ok"));
- AssertExtensions.Throws<ArgumentException>("path", null, () => Path.Combine("ok", "ok", bad));
- AssertExtensions.Throws<ArgumentException>("path", null, () => Path.Combine("ok", "ok", bad, "ok"));
- AssertExtensions.Throws<ArgumentException>("path", null, () => Path.Combine(bad, bad, bad, bad, bad));
- AssertExtensions.Throws<ArgumentException>("path", null, () => Path.GetDirectoryName(bad));
- AssertExtensions.Throws<ArgumentException>("path", null, () => Path.GetExtension(bad));
- AssertExtensions.Throws<ArgumentException>("path", null, () => Path.GetFileName(bad));
- AssertExtensions.Throws<ArgumentException>("path", null, () => Path.GetFileNameWithoutExtension(bad));
- AssertExtensions.Throws<ArgumentException>(c == 124 ? null : "path", null, () => Path.GetFullPath(bad));
- AssertExtensions.Throws<ArgumentException>("path", null, () => Path.GetPathRoot(bad));
- AssertExtensions.Throws<ArgumentException>("path", null, () => Path.IsPathRooted(bad));
- });
}
[Fact]
- [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
- public static void GetInvalidPathChars_Core()
+ public void InvalidPathChars_MatchesGetInvalidPathChars()
{
- Assert.NotNull(Path.GetInvalidPathChars());
- Assert.NotSame(Path.GetInvalidPathChars(), Path.GetInvalidPathChars());
- Assert.Equal((IEnumerable<char>)Path.GetInvalidPathChars(), Path.GetInvalidPathChars());
- Assert.True(Path.GetInvalidPathChars().Length > 0);
- Assert.All(Path.GetInvalidPathChars(), c =>
- {
- string bad = c.ToString();
- Assert.Equal(bad + ".ok", Path.ChangeExtension(bad, "ok"));
- Assert.Equal(bad + Path.DirectorySeparatorChar + "ok", Path.Combine(bad, "ok"));
- Assert.Equal("ok" + Path.DirectorySeparatorChar + "ok" + Path.DirectorySeparatorChar + bad, Path.Combine("ok", "ok", bad));
- Assert.Equal("ok" + Path.DirectorySeparatorChar + "ok" + Path.DirectorySeparatorChar + bad + Path.DirectorySeparatorChar + "ok", Path.Combine("ok", "ok", bad, "ok"));
- Assert.Equal(bad + Path.DirectorySeparatorChar + bad + Path.DirectorySeparatorChar + bad + Path.DirectorySeparatorChar + bad + Path.DirectorySeparatorChar + bad, Path.Combine(bad, bad, bad, bad, bad));
- Assert.Equal("", Path.GetDirectoryName(bad));
- Assert.Equal(string.Empty, Path.GetExtension(bad));
- Assert.Equal(bad, Path.GetFileName(bad));
- Assert.Equal(bad, Path.GetFileNameWithoutExtension(bad));
- AssertExtensions.Throws<ArgumentException>(c == 124 ? null : "path", null, () => Path.GetFullPath(bad));
- Assert.Equal(string.Empty, Path.GetPathRoot(bad));
- Assert.False(Path.IsPathRooted(bad));
- });
+#pragma warning disable 0618
+ Assert.NotNull(Path.InvalidPathChars);
+ Assert.Equal(Path.GetInvalidPathChars(), Path.InvalidPathChars);
+ Assert.Same(Path.InvalidPathChars, Path.InvalidPathChars);
+#pragma warning restore 0618
}
[Fact]
- public static void GetInvalidFileNameChars()
+ public void GetInvalidFileNameChars_Invariants()
{
Assert.NotNull(Path.GetInvalidFileNameChars());
Assert.NotSame(Path.GetInvalidFileNameChars(), Path.GetInvalidFileNameChars());
@@ -405,24 +144,22 @@ namespace System.IO.Tests
}
[Fact]
- [OuterLoop]
- public static void GetInvalidFileNameChars_OtherCharsValid()
+ public void GetRandomFileName()
{
- string curDir = Directory.GetCurrentDirectory();
- var invalidChars = new HashSet<char>(Path.GetInvalidFileNameChars());
- for (int i = 0; i < char.MaxValue; i++)
+ char[] invalidChars = Path.GetInvalidFileNameChars();
+ var fileNames = new HashSet<string>();
+ for (int i = 0; i < 100; i++)
{
- char c = (char)i;
- if (!invalidChars.Contains(c))
- {
- string name = "file" + c + ".txt";
- Assert.Equal(Path.Combine(curDir, name), Path.GetFullPath(name));
- }
+ string s = Path.GetRandomFileName();
+ Assert.Equal(s.Length, 8 + 1 + 3);
+ Assert.Equal(s[8], '.');
+ Assert.Equal(-1, s.IndexOfAny(invalidChars));
+ Assert.True(fileNames.Add(s));
}
}
[Fact]
- public static void GetTempPath_Default()
+ public void GetTempPath_Default()
{
string tmpPath = Path.GetTempPath();
Assert.False(string.IsNullOrEmpty(tmpPath));
@@ -431,57 +168,8 @@ namespace System.IO.Tests
Assert.True(Directory.Exists(tmpPath));
}
- [PlatformSpecific(TestPlatforms.Windows)] // Sets environment vars with Windows-specific paths
- [Theory]
- [InlineData(@"C:\Users\someuser\AppData\Local\Temp\", @"C:\Users\someuser\AppData\Local\Temp")]
- [InlineData(@"C:\Users\someuser\AppData\Local\Temp\", @"C:\Users\someuser\AppData\Local\Temp\")]
- [InlineData(@"C:\", @"C:\")]
- [InlineData(@"C:\tmp\", @"C:\tmp")]
- [InlineData(@"C:\tmp\", @"C:\tmp\")]
- public static void GetTempPath_SetEnvVar_Windows(string expected, string newTempPath)
- {
- GetTempPath_SetEnvVar("TMP", expected, newTempPath);
- }
-
- [PlatformSpecific(TestPlatforms.AnyUnix)] // Sets environment vars with Unix-specific paths
- [Theory]
- [InlineData("/tmp/", "/tmp")]
- [InlineData("/tmp/", "/tmp/")]
- [InlineData("/", "/")]
- [InlineData("/var/tmp/", "/var/tmp")]
- [InlineData("/var/tmp/", "/var/tmp/")]
- [InlineData("~/", "~")]
- [InlineData("~/", "~/")]
- [InlineData(".tmp/", ".tmp")]
- [InlineData("./tmp/", "./tmp")]
- [InlineData("/home/someuser/sometempdir/", "/home/someuser/sometempdir/")]
- [InlineData("/home/someuser/some tempdir/", "/home/someuser/some tempdir/")]
- [InlineData("/tmp/", null)]
- public static void GetTempPath_SetEnvVar_Unix(string expected, string newTempPath)
- {
- GetTempPath_SetEnvVar("TMPDIR", expected, newTempPath);
- }
-
- private static void GetTempPath_SetEnvVar(string envVar, string expected, string newTempPath)
- {
- string original = Path.GetTempPath();
- Assert.NotNull(original);
- try
- {
- Environment.SetEnvironmentVariable(envVar, newTempPath);
- Assert.Equal(
- Path.GetFullPath(expected),
- Path.GetFullPath(Path.GetTempPath()));
- }
- finally
- {
- Environment.SetEnvironmentVariable(envVar, original);
- Assert.Equal(original, Path.GetTempPath());
- }
- }
-
[Fact]
- public static void GetTempFileName()
+ public void GetTempFileName()
{
string tmpFile = Path.GetTempFileName();
try
@@ -501,449 +189,82 @@ namespace System.IO.Tests
}
}
- [Theory]
- [InlineData("\u0085")] // Next line
- [InlineData("\u00A0")] // Non breaking space
- [InlineData("\u2028")] // Line separator
- [PlatformSpecific(TestPlatforms.Windows)]
- [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)] // not NetFX
- public static void GetFullPath_NonControlWhiteSpaceStays(string component)
- {
- // When not NetFX full path should not cut off component
- string path = "C:\\Test" + component;
- Assert.Equal(path, Path.GetFullPath(path));
- }
-
- [Theory]
- [InlineData(" ")]
- [InlineData(" ")]
- [InlineData(" ")]
- [PlatformSpecific(TestPlatforms.Windows)]
- public static void GetFullPath_TrailingSpaceCut(string component)
- {
- // Windows cuts off any simple white space added to a path
- string path = "C:\\Test" + component;
- Assert.Equal("C:\\Test", Path.GetFullPath(path));
- }
-
[Fact]
- public static void GetFullPath_InvalidArgs()
+ public void GetFullPath_InvalidArgs()
{
Assert.Throws<ArgumentNullException>(() => Path.GetFullPath(null));
AssertExtensions.Throws<ArgumentException>("path", null, () => Path.GetFullPath(string.Empty));
}
- public static IEnumerable<object[]> GetFullPath_BasicExpansions_TestData()
- {
- string curDir = Directory.GetCurrentDirectory();
- yield return new object[] { curDir, curDir }; // Current directory => current directory
- yield return new object[] { ".", curDir }; // "." => current directory
- yield return new object[] { "..", Path.GetDirectoryName(curDir) }; // "." => up a directory
- yield return new object[] { Path.Combine(curDir, ".", ".", ".", ".", "."), curDir }; // "dir/./././." => "dir"
- yield return new object[] { curDir + new string(Path.DirectorySeparatorChar, 3) + ".", curDir }; // "dir///." => "dir"
- yield return new object[] { Path.Combine(curDir, "..", Path.GetFileName(curDir), ".", "..", Path.GetFileName(curDir)), curDir }; // "dir/../dir/./../dir" => "dir"
- yield return new object[] { Path.Combine(Path.GetPathRoot(curDir), "somedir", ".."), Path.GetPathRoot(curDir) }; // "C:\somedir\.." => "C:\"
- yield return new object[] { Path.Combine(Path.GetPathRoot(curDir), "."), Path.GetPathRoot(curDir) }; // "C:\." => "C:\"
- yield return new object[] { Path.Combine(Path.GetPathRoot(curDir), "..", "..", "..", ".."), Path.GetPathRoot(curDir) }; // "C:\..\..\..\.." => "C:\"
- yield return new object[] { Path.GetPathRoot(curDir) + new string(Path.DirectorySeparatorChar, 3), Path.GetPathRoot(curDir) }; // "C:\\\" => "C:\"
-
- // Path longer than MaxPath that normalizes down to less than MaxPath
- const int Iters = 10000;
- var longPath = new StringBuilder(curDir, curDir.Length + (Iters * 2));
- for (int i = 0; i < 10000; i++)
- {
- longPath.Append(Path.DirectorySeparatorChar).Append('.');
- }
- yield return new object[] { longPath.ToString(), curDir };
- }
-
- [Theory]
- [MemberData(nameof(GetFullPath_BasicExpansions_TestData))]
- public static void GetFullPath_BasicExpansions(string path, string expected)
- {
- Assert.Equal(expected, Path.GetFullPath(path));
- }
-
- [PlatformSpecific(TestPlatforms.AnyUnix)] // Tests whitespace in paths on Unix
- [Fact]
- public static void GetFullPath_Unix_Whitespace()
- {
- string curDir = Directory.GetCurrentDirectory();
- Assert.Equal("/ / ", Path.GetFullPath("/ // "));
- Assert.Equal(Path.Combine(curDir, " "), Path.GetFullPath(" "));
- Assert.Equal(Path.Combine(curDir, "\r\n"), Path.GetFullPath("\r\n"));
- }
-
- [PlatformSpecific(TestPlatforms.AnyUnix)] // Tests URIs as valid file names
- [Theory]
- [InlineData("http://www.microsoft.com")]
- [InlineData("file://somefile")]
- public static void GetFullPath_Unix_URIsAsFileNames(string uriAsFileName)
- {
- // URIs are valid filenames, though the multiple slashes will be consolidated in GetFullPath
- Assert.Equal(
- Path.Combine(Directory.GetCurrentDirectory(), uriAsFileName.Replace("//", "/")),
- Path.GetFullPath(uriAsFileName));
- }
-
- [PlatformSpecific(TestPlatforms.Windows)] // Checks normalized long path (> MaxPath) on Windows
- [Fact]
- public static void GetFullPath_Windows_NormalizedLongPathTooLong()
- {
- // Try out a long path that normalizes down to more than MaxPath
- string curDir = Directory.GetCurrentDirectory();
- const int Iters = 260;
- var longPath = new StringBuilder(curDir, curDir.Length + (Iters * 4));
- for (int i = 0; i < Iters; i++)
- {
- longPath.Append(Path.DirectorySeparatorChar).Append('a').Append(Path.DirectorySeparatorChar).Append('.');
- }
-
- if (PathFeatures.AreAllLongPathsAvailable())
- {
- // Now no longer throws unless over ~32K
- Assert.NotNull(Path.GetFullPath(longPath.ToString()));
- }
- else
- {
- Assert.Throws<PathTooLongException>(() => Path.GetFullPath(longPath.ToString()));
- }
- }
-
- [PlatformSpecific(TestPlatforms.Windows)] // Tests Windows-specific invalid paths
- [Fact]
- public static void GetFullPath_Windows_AlternateDataStreamsNotSupported()
- {
- // Throws via our invalid colon filtering
- Assert.Throws<NotSupportedException>(() => Path.GetFullPath(@"bad:path"));
- Assert.Throws<NotSupportedException>(() => Path.GetFullPath(@"C:\some\bad:path"));
- }
-
- [PlatformSpecific(TestPlatforms.Windows)] // Tests Windows-specific invalid paths
- [Theory]
- [InlineData("http://www.microsoft.com")]
- [InlineData("file://www.microsoft.com")]
- public static void GetFullPath_Windows_URIFormatNotSupported(string path)
- {
- // Throws via our invalid colon filtering
- if (!PathFeatures.IsUsingLegacyPathNormalization())
- {
- Assert.Throws<NotSupportedException>(() => Path.GetFullPath(path));
- }
- }
-
- [PlatformSpecific(TestPlatforms.Windows)] // Tests Windows-specific invalid paths
- [Theory]
- [InlineData(@"bad::$DATA")]
- [InlineData(@"C :")]
- [InlineData(@"C :\somedir")]
- public static void GetFullPath_Windows_NotSupportedExceptionPaths(string path)
- {
- // Old path normalization throws ArgumentException, new one throws NotSupportedException
- if (!PathFeatures.IsUsingLegacyPathNormalization())
- {
- Assert.Throws<NotSupportedException>(() => Path.GetFullPath(path));
- }
- else
- {
- AssertExtensions.Throws<ArgumentException>(null, () => Path.GetFullPath(path));
- }
- }
-
- [PlatformSpecific(TestPlatforms.Windows)] // Tests legitimate Windows paths that are now allowed
- [Theory]
- [InlineData(@"C:...")]
- [InlineData(@"C:...\somedir")]
- [InlineData(@"\.. .\")]
- [InlineData(@"\. .\")]
- [InlineData(@"\ .\")]
- public static void GetFullPath_Windows_LegacyArgumentExceptionPaths(string path)
- {
- if (PathFeatures.IsUsingLegacyPathNormalization())
- {
- // We didn't allow these paths on < 4.6.2
- AssertExtensions.Throws<ArgumentException>(null, () => Path.GetFullPath(path));
- }
- else
- {
- // These paths are legitimate Windows paths that can be created without extended syntax.
- // We now allow them through.
- Path.GetFullPath(path);
- }
- }
-
- [PlatformSpecific(TestPlatforms.Windows)] // Tests MaxPathNotTooLong on Windows
- [Fact]
- public static void GetFullPath_Windows_MaxPathNotTooLong()
- {
- string value = @"C:\" + new string('a', 255) + @"\";
- if (PathFeatures.AreAllLongPathsAvailable())
- {
- // Shouldn't throw anymore
- Path.GetFullPath(value);
- }
- else
- {
- Assert.Throws<PathTooLongException>(() => Path.GetFullPath(value));
- }
- }
-
- [PlatformSpecific(TestPlatforms.Windows)] // Tests PathTooLong on Windows
- [Fact]
- public static void GetFullPath_Windows_PathTooLong()
- {
- Assert.Throws<PathTooLongException>(() => Path.GetFullPath(@"C:\" + new string('a', short.MaxValue) + @"\"));
- }
-
- [PlatformSpecific(TestPlatforms.Windows)] // Tests Windows-specific paths
- [Theory]
- [InlineData(@"C:\", @"C:\")]
- [InlineData(@"C:\.", @"C:\")]
- [InlineData(@"C:\..", @"C:\")]
- [InlineData(@"C:\..\..", @"C:\")]
- [InlineData(@"C:\A\..", @"C:\")]
- [InlineData(@"C:\..\..\A\..", @"C:\")]
- public static void GetFullPath_Windows_RelativeRoot(string path, string expected)
- {
- Assert.Equal(Path.GetFullPath(path), expected);
- }
-
- [PlatformSpecific(TestPlatforms.Windows)] // Tests legitimate strage windows paths that are now allowed
- [Fact]
- public static void GetFullPath_Windows_StrangeButLegalPaths()
+ public static TheoryData<string, string> GetFullPath_BasicExpansions
{
- // These are legal and creatable without using extended syntax if you use a trailing slash
- // (such as "md ...\"). We used to filter these out, but now allow them to prevent apps from
- // being blocked when they hit these paths.
- string curDir = Directory.GetCurrentDirectory();
- if (PathFeatures.IsUsingLegacyPathNormalization())
- {
- // Legacy path Path.GetFullePath() ignores . when there is less or more that two, when there is .. in the path it returns one directory up.
- Assert.Equal(
- Path.GetFullPath(curDir + Path.DirectorySeparatorChar),
- Path.GetFullPath(curDir + Path.DirectorySeparatorChar + ". " + Path.DirectorySeparatorChar));
- Assert.Equal(
- Path.GetFullPath(Path.GetDirectoryName(curDir) + Path.DirectorySeparatorChar),
- Path.GetFullPath(curDir + Path.DirectorySeparatorChar + "..." + Path.DirectorySeparatorChar));
- Assert.Equal(
- Path.GetFullPath(Path.GetDirectoryName(curDir) + Path.DirectorySeparatorChar),
- Path.GetFullPath(curDir + Path.DirectorySeparatorChar + ".. " + Path.DirectorySeparatorChar));
- }
- else
+ get
{
- Assert.NotEqual(
- Path.GetFullPath(curDir + Path.DirectorySeparatorChar),
- Path.GetFullPath(curDir + Path.DirectorySeparatorChar + ". " + Path.DirectorySeparatorChar));
- Assert.NotEqual(
- Path.GetFullPath(Path.GetDirectoryName(curDir) + Path.DirectorySeparatorChar),
- Path.GetFullPath(curDir + Path.DirectorySeparatorChar + "..." + Path.DirectorySeparatorChar));
- Assert.NotEqual(
- Path.GetFullPath(Path.GetDirectoryName(curDir) + Path.DirectorySeparatorChar),
- Path.GetFullPath(curDir + Path.DirectorySeparatorChar + ".. " + Path.DirectorySeparatorChar));
- }
- }
+ string currentDirectory = Directory.GetCurrentDirectory();
+ string root = Path.GetPathRoot(currentDirectory);
+ string fileName = Path.GetFileName(currentDirectory);
- [PlatformSpecific(TestPlatforms.Windows)] // Tests Windows-specific paths
- [Theory]
- [InlineData(@"\\?\C:\ ")]
- [InlineData(@"\\?\C:\ \ ")]
- [InlineData(@"\\?\C:\ .")]
- [InlineData(@"\\?\C:\ ..")]
- [InlineData(@"\\?\C:\...")]
- [InlineData(@"\\?\GLOBALROOT\")]
- [InlineData(@"\\?\")]
- [InlineData(@"\\?\.")]
- [InlineData(@"\\?\..")]
- [InlineData(@"\\?\\")]
- [InlineData(@"\\?\C:\\")]
- [InlineData(@"\\?\C:\|")]
- [InlineData(@"\\?\C:\.")]
- [InlineData(@"\\?\C:\..")]
- [InlineData(@"\\?\C:\Foo1\.")]
- [InlineData(@"\\?\C:\Foo2\..")]
- [InlineData(@"\\?\UNC\")]
- [InlineData(@"\\?\UNC\server1")]
- [InlineData(@"\\?\UNC\server2\")]
- [InlineData(@"\\?\UNC\server3\\")]
- [InlineData(@"\\?\UNC\server4\..")]
- [InlineData(@"\\?\UNC\server5\share\.")]
- [InlineData(@"\\?\UNC\server6\share\..")]
- [InlineData(@"\\?\UNC\a\b\\")]
- [InlineData(@"\\.\")]
- [InlineData(@"\\.\.")]
- [InlineData(@"\\.\..")]
- [InlineData(@"\\.\\")]
- [InlineData(@"\\.\C:\\")]
- [InlineData(@"\\.\C:\|")]
- [InlineData(@"\\.\C:\.")]
- [InlineData(@"\\.\C:\..")]
- [InlineData(@"\\.\C:\Foo1\.")]
- [InlineData(@"\\.\C:\Foo2\..")]
- public static void GetFullPath_Windows_ValidExtendedPaths(string path)
- {
- if (PathFeatures.IsUsingLegacyPathNormalization())
- {
- // Legacy Path doesn't support any of these paths.
- AssertExtensions.ThrowsAny<ArgumentException, NotSupportedException>(() => Path.GetFullPath(path));
- return;
- }
+ TheoryData<string, string> data = new TheoryData<string, string>
+ {
+ // Current directory => current directory
+ { currentDirectory, currentDirectory },
+ // "." => current directory
+ { ".", currentDirectory },
+ // ".." => up a directory
+ { "..", Path.GetDirectoryName(currentDirectory) },
+ // "dir/./././." => "dir"
+ { Path.Combine(currentDirectory, ".", ".", ".", ".", "."), currentDirectory },
+ // "dir///." => "dir"
+ { currentDirectory + new string(Path.DirectorySeparatorChar, 3) + ".", currentDirectory },
+ // "dir/../dir/./../dir" => "dir"
+ { Path.Combine(currentDirectory, "..", fileName, ".", "..", fileName), currentDirectory },
+ // "C:\somedir\.." => "C:\"
+ { Path.Combine(root, "somedir", ".."), root },
+ // "C:\." => "C:\"
+ { Path.Combine(root, "."), root },
+ // "C:\..\..\..\.." => "C:\"
+ { Path.Combine(root, "..", "..", "..", ".."), root },
+ // "C:\\\" => "C:\"
+ { root + new string(Path.DirectorySeparatorChar, 3), root },
+ };
+
+ // Path longer than MaxPath that normalizes down to less than MaxPath
+ const int Iters = 10000;
+ var longPath = new StringBuilder(currentDirectory, currentDirectory.Length + (Iters * 2));
+ for (int i = 0; i < 10000; i++)
+ {
+ longPath.Append(Path.DirectorySeparatorChar).Append('.');
+ }
+ data.Add(longPath.ToString(), currentDirectory);
- // None of these should throw
- if (path.StartsWith(@"\\?\"))
- {
- Assert.Equal(path, Path.GetFullPath(path));
- }
- else
- {
- Path.GetFullPath(path);
+ return data;
}
}
- [PlatformSpecific(TestPlatforms.Windows)] // Tests Windows-specific paths
- [Theory]
- [InlineData(@"\\.\UNC\")]
- [InlineData(@"\\.\UNC\LOCALHOST")]
- [InlineData(@"\\.\UNC\localHOST\")]
- [InlineData(@"\\.\UNC\LOcaLHOST\\")]
- [InlineData(@"\\.\UNC\lOCALHOST\..")]
- [InlineData(@"\\.\UNC\LOCALhost\share\.")]
- [InlineData(@"\\.\UNC\loCALHOST\share\..")]
- [InlineData(@"\\.\UNC\a\b\\")]
- public static void GetFullPath_Windows_ValidLegacy_ValidExtendedPaths(string path)
+ public static TheoryData<string, string> GetFullPath_TildePaths
{
- // should not throw
- Path.GetFullPath(path);
- }
-
- [PlatformSpecific(TestPlatforms.Windows)] // Tests valid paths based on UNC
- [Theory]
- // https://github.com/dotnet/corefx/issues/11965
- [InlineData(@"\\LOCALHOST\share\test.txt.~SS", @"\\LOCALHOST\share\test.txt.~SS")]
- [InlineData(@"\\LOCALHOST\share1", @"\\LOCALHOST\share1")]
- [InlineData(@"\\LOCALHOST\share2", @" \\LOCALHOST\share2")]
- [InlineData(@"\\LOCALHOST\share3\dir", @"\\LOCALHOST\share3\dir")]
- [InlineData(@"\\LOCALHOST\share4", @"\\LOCALHOST\share4\.")]
- [InlineData(@"\\LOCALHOST\share5", @"\\LOCALHOST\share5\..")]
- [InlineData(@"\\LOCALHOST\share6\", @"\\LOCALHOST\share6\ ")]
- [InlineData(@"\\LOCALHOST\ share7\", @"\\LOCALHOST\ share7\")]
- [InlineData(@"\\?\UNC\LOCALHOST\share8\test.txt.~SS", @"\\?\UNC\LOCALHOST\share8\test.txt.~SS")]
- [InlineData(@"\\?\UNC\LOCALHOST\share9", @"\\?\UNC\LOCALHOST\share9")]
- [InlineData(@"\\?\UNC\LOCALHOST\shareA\dir", @"\\?\UNC\LOCALHOST\shareA\dir")]
- [InlineData(@"\\?\UNC\LOCALHOST\shareB\. ", @"\\?\UNC\LOCALHOST\shareB\. ")]
- [InlineData(@"\\?\UNC\LOCALHOST\shareC\.. ", @"\\?\UNC\LOCALHOST\shareC\.. ")]
- [InlineData(@"\\?\UNC\LOCALHOST\shareD\ ", @"\\?\UNC\LOCALHOST\shareD\ ")]
- [InlineData(@"\\.\UNC\LOCALHOST\ shareE\", @"\\.\UNC\LOCALHOST\ shareE\")]
- [InlineData(@"\\.\UNC\LOCALHOST\shareF\test.txt.~SS", @"\\.\UNC\LOCALHOST\shareF\test.txt.~SS")]
- [InlineData(@"\\.\UNC\LOCALHOST\shareG", @"\\.\UNC\LOCALHOST\shareG")]
- [InlineData(@"\\.\UNC\LOCALHOST\shareH\dir", @"\\.\UNC\LOCALHOST\shareH\dir")]
- [InlineData(@"\\.\UNC\LOCALHOST\shareK\", @"\\.\UNC\LOCALHOST\shareK\ ")]
- [InlineData(@"\\.\UNC\LOCALHOST\ shareL\", @"\\.\UNC\LOCALHOST\ shareL\")]
- public static void GetFullPath_Windows_UNC_Valid(string expected, string input)
- {
- if (input.StartsWith(@"\\?\") && PathFeatures.IsUsingLegacyPathNormalization())
+ get
{
- AssertExtensions.Throws<ArgumentException>(null, () => Path.GetFullPath(input));
- }
- else
- {
- Assert.Equal(expected, Path.GetFullPath(input));
- }
- }
+ // Paths with tildes '~' are processed for 8.3 expansion on Windows
+ string currentDirectory = Directory.GetCurrentDirectory();
+ string root = Path.GetPathRoot(currentDirectory);
- [PlatformSpecific(TestPlatforms.Windows)] // Tests valid paths based on UNC
- [Theory]
- [InlineData(@"\\.\UNC\LOCALHOST\shareI\", @"\\.\UNC\LOCALHOST\shareI", @"\\.\UNC\LOCALHOST\shareI\. ")]
- [InlineData(@"\\.\UNC\LOCALHOST\shareJ\", @"\\.\UNC\LOCALHOST", @"\\.\UNC\LOCALHOST\shareJ\.. ")]
- public static void GetFullPath_Windows_UNC_Valid_LegacyPathSupport(string normalExpected, string legacyExpected, string input)
- {
- string expected = PathFeatures.IsUsingLegacyPathNormalization() ? legacyExpected : normalExpected;
- Assert.Equal(expected, Path.GetFullPath(input));
- }
-
- [PlatformSpecific(TestPlatforms.Windows)] // Tests invalid paths based on UNC
- [Theory]
- [InlineData(@"\\")]
- [InlineData(@"\\LOCALHOST")]
- [InlineData(@"\\LOCALHOST\")]
- [InlineData(@"\\LOCALHOST\\")]
- [InlineData(@"\\LOCALHOST\..")]
- public static void GetFullPath_Windows_UNC_Invalid(string invalidPath)
- {
- AssertExtensions.Throws<ArgumentException>(null, () => Path.GetFullPath(invalidPath));
- }
-
- [Fact]
- [PlatformSpecific(TestPlatforms.Windows)] // Uses P/Invokes to get short path name
- public static void GetFullPath_Windows_83Paths()
- {
- // Create a temporary file name with a name longer than 8.3 such that it'll need to be shortened.
- string tempFilePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N") + ".txt");
- File.Create(tempFilePath).Dispose();
- try
- {
- // Get its short name
- var sb = new StringBuilder(260);
- if (GetShortPathName(tempFilePath, sb, sb.Capacity) > 0) // only proceed if we could successfully create the short name
+ TheoryData<string, string> data = new TheoryData<string, string>
{
- string shortName = sb.ToString();
-
- // Make sure the shortened name expands back to the original one
- // Sometimes shortening or GetFullPath is changing the casing of "temp" on some test machines: normalize both sides
- tempFilePath = Regex.Replace(tempFilePath, @"\\temp\\", @"\TEMP\", RegexOptions.IgnoreCase);
- shortName = Regex.Replace(Path.GetFullPath(shortName), @"\\temp\\", @"\TEMP\", RegexOptions.IgnoreCase);
- Assert.Equal(tempFilePath, shortName);
-
- // Should work with device paths that aren't well-formed extended syntax
- if (!PathFeatures.IsUsingLegacyPathNormalization())
- {
- Assert.Equal(@"\\.\" + tempFilePath, Path.GetFullPath(@"\\.\" + shortName));
- Assert.Equal(@"\\?\" + tempFilePath, Path.GetFullPath(@"//?/" + shortName));
+ { "~", Path.Combine(currentDirectory, "~") },
+ { Path.Combine(root, "~"), Path.Combine(root, "~") }
+ };
- // Shouldn't mess with well-formed extended syntax
- Assert.Equal(@"\\?\" + shortName, Path.GetFullPath(@"\\?\" + shortName));
- }
-
- // Validate case where short name doesn't expand to a real file
- string invalidShortName = @"S:\DOESNT~1\USERNA~1.RED\LOCALS~1\Temp\bg3ylpzp";
- Assert.Equal(invalidShortName, Path.GetFullPath(invalidShortName));
-
- // Same thing, but with a long path that normalizes down to a short enough one
- const int Iters = 1000;
- var shortLongName = new StringBuilder(invalidShortName, invalidShortName.Length + (Iters * 2));
- for (int i = 0; i < Iters; i++)
- {
- shortLongName.Append(Path.DirectorySeparatorChar).Append('.');
- }
- Assert.Equal(invalidShortName, Path.GetFullPath(shortLongName.ToString()));
- }
+ return data;
}
- finally
- {
- File.Delete(tempFilePath);
- }
- }
-
- [PlatformSpecific(TestPlatforms.Windows)] // Tests Windows-specific invalid paths
- [Theory]
- [InlineData('*')]
- [InlineData('?')]
- public static void GetFullPath_Windows_Wildcards(char wildcard)
- {
- AssertExtensions.Throws<ArgumentException>("path", null, () => Path.GetFullPath("test" + wildcard + "ing"));
}
- // Windows-only P/Invoke to create 8.3 short names from long names
- [DllImport("kernel32.dll", EntryPoint = "GetShortPathNameW" ,CharSet = CharSet.Unicode)]
- private static extern uint GetShortPathName(string lpszLongPath, StringBuilder lpszShortPath, int cchBuffer);
-
- [Fact]
- public static void InvalidPathChars_MatchesGetInvalidPathChars()
+ [Theory,
+ MemberData(nameof(GetFullPath_BasicExpansions)),
+ MemberData(nameof(GetFullPath_TildePaths))]
+ public void GetFullPath_CoreTests(string path, string expected)
{
-#pragma warning disable 0618
- Assert.NotNull(Path.InvalidPathChars);
- Assert.Equal(Path.GetInvalidPathChars(), Path.InvalidPathChars);
- Assert.Same(Path.InvalidPathChars, Path.InvalidPathChars);
-#pragma warning restore 0618
+ Assert.Equal(expected, Path.GetFullPath(path));
}
}
}
diff --git a/src/System.Runtime.Extensions/tests/System/IO/PathTests.netcoreapp.cs b/src/System.Runtime.Extensions/tests/System/IO/PathTests.netcoreapp.cs
new file mode 100644
index 0000000000..373838763e
--- /dev/null
+++ b/src/System.Runtime.Extensions/tests/System/IO/PathTests.netcoreapp.cs
@@ -0,0 +1,246 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using Xunit;
+
+namespace System.IO.Tests
+{
+ public partial class PathTests : PathTestsBase
+ {
+ [Fact]
+ public void GetDirectoryName_EmptyReturnsNull()
+ {
+ // In NetFX this throws argument exception
+ Assert.Null(Path.GetDirectoryName(string.Empty));
+ }
+
+ [Theory, MemberData(nameof(TestData_Spaces))]
+ public void GetDirectoryName_Spaces(string path)
+ {
+ if (PlatformDetection.IsWindows)
+ {
+ // In Windows spaces are eaten by Win32, making them effectively empty
+ Assert.Null(Path.GetDirectoryName(path));
+ }
+ else
+ {
+ Assert.Empty(Path.GetDirectoryName(path));
+ }
+ }
+
+ [Theory, MemberData(nameof(TestData_Spaces))]
+ public void GetDirectoryName_Span_Spaces(string path)
+ {
+ PathAssert.Empty(Path.GetDirectoryName(path.AsSpan()));
+ }
+
+ [Theory,
+ MemberData(nameof(TestData_EmbeddedNull)),
+ MemberData(nameof(TestData_ControlChars)),
+ MemberData(nameof(TestData_UnicodeWhiteSpace))]
+ public void GetDirectoryName_NetFxInvalid(string path)
+ {
+ Assert.Empty(Path.GetDirectoryName(path));
+ Assert.Equal(path, Path.GetDirectoryName(Path.Combine(path, path)));
+ PathAssert.Empty(Path.GetDirectoryName(path.AsSpan()));
+ PathAssert.Equal(path, new string(Path.GetDirectoryName(Path.Combine(path, path).AsSpan())));
+ }
+
+ [Theory, MemberData(nameof(TestData_GetDirectoryName))]
+ public void GetDirectoryName_Span(string path, string expected)
+ {
+ PathAssert.Equal(expected ?? ReadOnlySpan<char>.Empty, Path.GetDirectoryName(path.AsSpan()));
+ }
+
+ [Fact]
+ public void GetDirectoryName_Span_CurrentDirectory()
+ {
+ string curDir = Directory.GetCurrentDirectory();
+ PathAssert.Equal(curDir, Path.GetDirectoryName(Path.Combine(curDir, "baz").AsSpan()));
+ PathAssert.Empty(Path.GetDirectoryName(Path.GetPathRoot(curDir).AsSpan()));
+ }
+
+ [Theory,
+ InlineData(@" C:\dir/baz", @" C:\dir"),
+ InlineData(@" C:\dir/baz", @" C:\dir")]
+ public void GetDirectoryName_SkipSpaces(string path, string expected)
+ {
+ // We no longer trim leading spaces for any path
+ Assert.Equal(expected, Path.GetDirectoryName(path));
+ }
+
+ [Theory, MemberData(nameof(TestData_GetExtension))]
+ public void GetExtension_Span(string path, string expected)
+ {
+ PathAssert.Equal(expected, Path.GetExtension(path.AsSpan()));
+ Assert.Equal(!string.IsNullOrEmpty(expected), Path.HasExtension(path.AsSpan()));
+ }
+
+ [Theory, MemberData(nameof(TestData_GetFileName))]
+ public void GetFileName_Span(string path, string expected)
+ {
+ PathAssert.Equal(expected, Path.GetFileName(path.AsSpan()));
+ }
+
+ public static IEnumerable<object[]> TestData_GetFileName_Volume()
+ {
+ yield return new object[] { ":", ":" };
+ yield return new object[] { ".:", ".:" };
+ yield return new object[] { ".:.", ".:." }; // Not a valid drive letter
+ yield return new object[] { "file:", "file:" };
+ yield return new object[] { ":file", ":file" };
+ yield return new object[] { "file:exe", "file:exe" };
+ yield return new object[] { Path.Combine("baz", "file:exe"), "file:exe" };
+ yield return new object[] { Path.Combine("bar", "baz", "file:exe"), "file:exe" };
+ }
+
+ [Theory, MemberData(nameof(TestData_GetFileName_Volume))]
+ public void GetFileName_Volume(string path, string expected)
+ {
+ // We used to break on ':' on Windows. This is a valid file name character for alternate data streams.
+ // Additionally the character can show up on unix volumes mounted to Windows.
+ Assert.Equal(expected, Path.GetFileName(path));
+ PathAssert.Equal(expected, Path.GetFileName(path.AsSpan()));
+ }
+
+ [Theory, MemberData(nameof(TestData_GetFileNameWithoutExtension))]
+ public void GetFileNameWithoutExtension_Span(string path, string expected)
+ {
+ PathAssert.Equal(expected, Path.GetFileNameWithoutExtension(path.AsSpan()));
+ }
+
+ [Fact]
+ public void GetPathRoot_Empty()
+ {
+ Assert.Null(Path.GetPathRoot(string.Empty));
+ }
+
+ [Fact]
+ public void GetPathRoot_Empty_Span()
+ {
+ PathAssert.Empty(Path.GetPathRoot(ReadOnlySpan<char>.Empty));
+ }
+
+ [Theory,
+ InlineData(nameof(TestData_Spaces)),
+ InlineData(nameof(TestData_ControlChars)),
+ InlineData(nameof(TestData_EmbeddedNull)),
+ InlineData(nameof(TestData_InvalidDriveLetters)),
+ InlineData(nameof(TestData_UnicodeWhiteSpace)),
+ InlineData(nameof(TestData_EmptyString))]
+ public void IsPathRooted_NegativeCases(string path)
+ {
+ Assert.False(Path.IsPathRooted(path));
+ Assert.False(Path.IsPathRooted(path.AsSpan()));
+ }
+
+ [Fact]
+ public void GetInvalidPathChars()
+ {
+ Assert.All(Path.GetInvalidPathChars(), c =>
+ {
+ string bad = c.ToString();
+ Assert.Equal(bad + ".ok", Path.ChangeExtension(bad, "ok"));
+ Assert.Equal(bad + Path.DirectorySeparatorChar + "ok", Path.Combine(bad, "ok"));
+ Assert.Equal("ok" + Path.DirectorySeparatorChar + "ok" + Path.DirectorySeparatorChar + bad, Path.Combine("ok", "ok", bad));
+ Assert.Equal("ok" + Path.DirectorySeparatorChar + "ok" + Path.DirectorySeparatorChar + bad + Path.DirectorySeparatorChar + "ok", Path.Combine("ok", "ok", bad, "ok"));
+ Assert.Equal(bad + Path.DirectorySeparatorChar + bad + Path.DirectorySeparatorChar + bad + Path.DirectorySeparatorChar + bad + Path.DirectorySeparatorChar + bad, Path.Combine(bad, bad, bad, bad, bad));
+ Assert.Equal("", Path.GetDirectoryName(bad));
+ Assert.Equal(string.Empty, Path.GetExtension(bad));
+ Assert.Equal(bad, Path.GetFileName(bad));
+ Assert.Equal(bad, Path.GetFileNameWithoutExtension(bad));
+ if (bad[0] == '\0')
+ {
+ Assert.Throws<ArgumentException>("path", () => Path.GetFullPath(bad));
+ }
+ else
+ {
+ Assert.True(Path.GetFullPath(bad).EndsWith(bad));
+ }
+ Assert.Equal(string.Empty, Path.GetPathRoot(bad));
+ Assert.False(Path.IsPathRooted(bad));
+ });
+ }
+
+ [Fact]
+ public void GetInvalidPathChars_Span()
+ {
+ Assert.All(Path.GetInvalidPathChars(), c =>
+ {
+ string bad = c.ToString();
+ Assert.Equal(string.Empty, new string(Path.GetDirectoryName(bad.AsSpan())));
+ Assert.Equal(string.Empty, new string(Path.GetExtension(bad.AsSpan())));
+ Assert.Equal(bad, new string(Path.GetFileName(bad.AsSpan())));
+ Assert.Equal(bad, new string(Path.GetFileNameWithoutExtension(bad.AsSpan())));
+ Assert.Equal(string.Empty, new string(Path.GetPathRoot(bad.AsSpan())));
+ Assert.False(Path.IsPathRooted(bad.AsSpan()));
+ });
+ }
+
+ [Theory,
+ InlineData("http://www.microsoft.com"),
+ InlineData("file://somefile")]
+ public void GetFullPath_URIsAsFileNames(string uriAsFileName)
+ {
+ // URIs are valid filenames, though the multiple slashes will be consolidated in GetFullPath
+ Assert.Equal(
+ Path.Combine(Directory.GetCurrentDirectory(), uriAsFileName.Replace("//", Path.DirectorySeparatorChar.ToString())),
+ Path.GetFullPath(uriAsFileName));
+ }
+
+ [Theory, MemberData(nameof(TestData_NonDriveColonPaths))]
+ public void GetFullPath_NowSupportedColons(string path)
+ {
+ // Used to throw on Windows, now should never throw
+ Path.GetFullPath(path);
+ }
+
+ [Theory, MemberData(nameof(TestData_InvalidUnc))]
+ public static void GetFullPath_UNC_Invalid(string path)
+ {
+ // These UNCs used to throw on Windows
+ Path.GetFullPath(path);
+ }
+
+ [Theory,
+ MemberData(nameof(TestData_Wildcards)),
+ MemberData(nameof(TestData_ExtendedWildcards))]
+ public void GetFullPath_Wildcards(char wildcard)
+ {
+ string path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + wildcard + "ing");
+ Assert.Equal(path, Path.GetFullPath(path));
+ }
+
+ public static TheoryData<string, string, string> GetFullPathBasePath_ArgumentNullException => new TheoryData<string, string, string>
+ {
+ { @"", null, "basePath" },
+ { @"tmp",null, "basePath" },
+ { @"\home", null, "basePath"},
+ { null, @"foo\bar", "path"},
+ { null, @"foo\bar", "path"},
+ };
+
+ [Theory,
+ MemberData(nameof(GetFullPathBasePath_ArgumentNullException))]
+ public static void GetFullPath_BasePath_NullInput(string path, string basePath, string paramName)
+ {
+ Assert.Throws<ArgumentNullException>(paramName, () => Path.GetFullPath(path, basePath));
+ }
+
+ public static TheoryData<string, string, string> GetFullPathBasePath_ArgumentException => new TheoryData<string, string, string>
+ {
+ { @"", @"foo\bar", "basePath"},
+ { @"tmp", @"foo\bar", "basePath"},
+ { @"\home", @"foo\bar", "basePath"},
+ };
+
+ [Theory,
+ MemberData(nameof(GetFullPathBasePath_ArgumentException))]
+ public static void GetFullPath_BasePath_Input(string path, string basePath, string paramName)
+ {
+ Assert.Throws<ArgumentException>(paramName, () => Path.GetFullPath(path, basePath));
+ }
+ }
+}
diff --git a/src/System.Runtime.Extensions/tests/System/IO/PathTestsBase.cs b/src/System.Runtime.Extensions/tests/System/IO/PathTestsBase.cs
new file mode 100644
index 0000000000..e07cb5291e
--- /dev/null
+++ b/src/System.Runtime.Extensions/tests/System/IO/PathTestsBase.cs
@@ -0,0 +1,226 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using Xunit;
+
+namespace System.IO.Tests
+{
+ public partial class PathTestsBase : RemoteExecutorTestBase
+ {
+ protected static string Sep = Path.DirectorySeparatorChar.ToString();
+ protected static string AltSep = Path.AltDirectorySeparatorChar.ToString();
+
+ public static TheoryData<string> TestData_EmbeddedNull => new TheoryData<string>
+ {
+ "a\0b"
+ };
+
+ public static TheoryData<string> TestData_EmptyString => new TheoryData<string>
+ {
+ ""
+ };
+
+ public static TheoryData<string> TestData_ControlChars => new TheoryData<string>
+ {
+ "\t",
+ "\r\n",
+ "\b",
+ "\v",
+ "\n"
+ };
+
+ public static TheoryData<string> TestData_NonDriveColonPaths => new TheoryData<string>
+ {
+ @"bad:path",
+ @"C:\some\bad:path",
+ @"http://www.microsoft.com",
+ @"file://www.microsoft.com",
+ @"bad::$DATA",
+ @"C :",
+ @"C :\somedir"
+ };
+
+ public static TheoryData<string> TestData_Spaces => new TheoryData<string>
+ {
+ " ",
+ " "
+ };
+
+ public static TheoryData<string> TestData_Periods => new TheoryData<string>
+ {
+ // One and two periods have special meaning (current and parent dir)
+ "...",
+ "...."
+ };
+
+ public static TheoryData<string> TestData_Wildcards => new TheoryData<string>
+ {
+ "*",
+ "?"
+ };
+
+ public static TheoryData<string> TestData_ExtendedWildcards => new TheoryData<string>
+ {
+ // These are supported by Windows although .NET blocked them historically
+ "\"",
+ "<",
+ ">"
+ };
+
+ public static TheoryData<string> TestData_UnicodeWhiteSpace => new TheoryData<string>
+ {
+ "\u00A0", // Non-breaking Space
+ "\u2028", // Line separator
+ "\u2029", // Paragraph separator
+ };
+
+ public static TheoryData<string> TestData_InvalidUnc => new TheoryData<string>
+ {
+ // .NET used to validate properly formed UNCs
+ @"\\",
+ @"\\LOCALHOST",
+ @"\\LOCALHOST\",
+ @"\\LOCALHOST\\",
+ @"\\LOCALHOST\.."
+ };
+
+ public static TheoryData<string> TestData_InvalidDriveLetters => new TheoryData<string>
+ {
+ { @"@:\foo" }, // 064 = @ 065 = A
+ { @"[:\\" }, // 091 = [ 090 = Z
+ { @"`:\foo "}, // 096 = ` 097 = a
+ { @"{:\\" }, // 123 = { 122 = z
+ { @"@:/foo" },
+ { @"[://" },
+ { @"`:/foo "},
+ { @"{:/" },
+ { @"]:" }
+ };
+
+ public static TheoryData<string> TestData_ValidDriveLetters => new TheoryData<string>
+ {
+ { @"A:\foo" }, // 064 = @ 065 = A
+ { @"Z:\\" }, // 091 = [ 090 = Z
+ { @"a:\foo "}, // 096 = ` 097 = a
+ { @"z:\\" }, // 123 = { 122 = z
+ { @"B:/foo" },
+ { @"D://" },
+ { @"E:/foo "},
+ { @"F:/" },
+ { @"G:" }
+ };
+
+ public static TheoryData<string, string> TestData_GetDirectoryName => new TheoryData<string, string>
+ {
+ { ".", "" },
+ { "..", "" },
+ { "baz", "" },
+ { Path.Combine("dir", "baz"), "dir" },
+ { "dir.foo" + Path.AltDirectorySeparatorChar + "baz.txt", "dir.foo" },
+ { Path.Combine("dir", "baz", "bar"), Path.Combine("dir", "baz") },
+ { Path.Combine("..", "..", "files.txt"), Path.Combine("..", "..") },
+ { Path.DirectorySeparatorChar + "foo", Path.DirectorySeparatorChar.ToString() },
+ { Path.DirectorySeparatorChar.ToString(), null }
+ };
+
+ public static TheoryData<string, string> TestData_GetDirectoryName_Windows => new TheoryData<string, string>
+ {
+ { @"C:\", null },
+ { @"C:/", null },
+ { @"C:", null },
+ { @"dir\\baz", "dir" },
+ { @"dir//baz", "dir" },
+ { @"C:\foo", @"C:\" },
+ { @"C:foo", "C:" }
+ };
+
+ public static TheoryData<string, string> TestData_GetExtension => new TheoryData<string, string>
+ {
+ { @"file.exe", ".exe" },
+ { @"file", "" },
+ { @"file.", "" },
+ { @"file.s", ".s" },
+ { @"test/file", "" },
+ { @"test/file.extension", ".extension" },
+ { @"test\file", "" },
+ { @"test\file.extension", ".extension" },
+ { "file.e xe", ".e xe"},
+ { "file. ", ". "},
+ { " file. ", ". "},
+ { " file.extension", ".extension"}
+ };
+
+ public static TheoryData<string, string> TestData_GetFileName => new TheoryData<string, string>
+ {
+ { ".", "." },
+ { "..", ".." },
+ { "file", "file" },
+ { "file.", "file." },
+ { "file.exe", "file.exe" },
+ { " . ", " . " },
+ { " .. ", " .. " },
+ { "fi le", "fi le" },
+ { Path.Combine("baz", "file.exe"), "file.exe" },
+ { Path.Combine("baz", "file.exe") + Path.AltDirectorySeparatorChar, "" },
+ { Path.Combine("bar", "baz", "file.exe"), "file.exe" },
+ { Path.Combine("bar", "baz", "file.exe") + Path.DirectorySeparatorChar, "" }
+ };
+
+ public static TheoryData<string, string> TestData_GetFileNameWithoutExtension => new TheoryData<string, string>
+ {
+ { "", "" },
+ { "file", "file" },
+ { "file.exe", "file" },
+ { Path.Combine("bar", "baz", "file.exe"), "file" },
+ { Path.Combine("bar", "baz") + Path.DirectorySeparatorChar, "" }
+ };
+
+ public static TheoryData<string, string> TestData_GetPathRoot_Unc => new TheoryData<string, string>
+ {
+ { @"\\test\unc\path\to\something", @"\\test\unc" },
+ { @"\\a\b\c\d\e", @"\\a\b" },
+ { @"\\a\b\", @"\\a\b" },
+ { @"\\a\b", @"\\a\b" },
+ { @"\\test\unc", @"\\test\unc" },
+ };
+
+ // TODO: Include \\.\ as well
+ public static TheoryData<string, string> TestData_GetPathRoot_DevicePaths => new TheoryData<string, string>
+ {
+ { @"\\?\UNC\test\unc\path\to\something", PathFeatures.IsUsingLegacyPathNormalization() ? @"\\?\UNC" : @"\\?\UNC\test\unc" },
+ { @"\\?\UNC\test\unc", PathFeatures.IsUsingLegacyPathNormalization() ? @"\\?\UNC" : @"\\?\UNC\test\unc" },
+ { @"\\?\UNC\a\b1", PathFeatures.IsUsingLegacyPathNormalization() ? @"\\?\UNC" : @"\\?\UNC\a\b1" },
+ { @"\\?\UNC\a\b2\", PathFeatures.IsUsingLegacyPathNormalization() ? @"\\?\UNC" : @"\\?\UNC\a\b2" },
+ { @"\\?\C:\foo\bar.txt", PathFeatures.IsUsingLegacyPathNormalization() ? @"\\?\C:" : @"\\?\C:\" }
+ };
+
+ public static TheoryData<string, string> TestData_GetPathRoot_Windows => new TheoryData<string, string>
+ {
+ { @"C:", @"C:" },
+ { @"C:\", @"C:\" },
+ { @"C:\\", @"C:\" },
+ { @"C:\foo1", @"C:\" },
+ { @"C:\\foo2", @"C:\" },
+ };
+
+ protected static void GetTempPath_SetEnvVar(string envVar, string expected, string newTempPath)
+ {
+ string original = Path.GetTempPath();
+ Assert.NotNull(original);
+ try
+ {
+ Environment.SetEnvironmentVariable(envVar, newTempPath);
+ Assert.Equal(
+ Path.GetFullPath(expected),
+ Path.GetFullPath(Path.GetTempPath()));
+ }
+ finally
+ {
+ Environment.SetEnvironmentVariable(envVar, original);
+ Assert.Equal(original, Path.GetTempPath());
+ }
+ }
+ }
+}
diff --git a/src/System.Runtime.Extensions/tests/System/IO/PathTestsBase.netcoreapp.cs b/src/System.Runtime.Extensions/tests/System/IO/PathTestsBase.netcoreapp.cs
new file mode 100644
index 0000000000..78d986ff1f
--- /dev/null
+++ b/src/System.Runtime.Extensions/tests/System/IO/PathTestsBase.netcoreapp.cs
@@ -0,0 +1,23 @@
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.IO.Tests
+{
+ public partial class PathTestsBase
+ {
+ protected static class PathAssert
+ {
+ public static void Equal(ReadOnlySpan<char> expected, ReadOnlySpan<char> actual)
+ {
+ if (!actual.SequenceEqual(expected))
+ throw new Xunit.Sdk.EqualException(new string(expected), new string(actual));
+ }
+
+ public static void Empty(ReadOnlySpan<char> actual)
+ {
+ if (actual.Length > 0)
+ throw new Xunit.Sdk.NotEmptyException();
+ }
+ }
+ }
+}
diff --git a/src/System.Runtime.Extensions/tests/System/IO/Path.Combine.cs b/src/System.Runtime.Extensions/tests/System/IO/PathTests_Combine.cs
index 292c5480d2..382732253f 100644
--- a/src/System.Runtime.Extensions/tests/System/IO/Path.Combine.cs
+++ b/src/System.Runtime.Extensions/tests/System/IO/PathTests_Combine.cs
@@ -7,7 +7,7 @@ using Xunit;
namespace System.IO.Tests
{
- public static partial class PathTests
+ public class PathTests_Combine
{
private static readonly char s_separator = Path.DirectorySeparatorChar;
diff --git a/src/System.Runtime.Extensions/tests/System/IO/PathTests_Join.netcoreapp.cs b/src/System.Runtime.Extensions/tests/System/IO/PathTests_Join.netcoreapp.cs
new file mode 100644
index 0000000000..4c8a9b9bdb
--- /dev/null
+++ b/src/System.Runtime.Extensions/tests/System/IO/PathTests_Join.netcoreapp.cs
@@ -0,0 +1,111 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.IO.Tests
+{
+ public class PathTests_Join : PathTestsBase
+ {
+ public static TheoryData<string, string, string> TestData_JoinTwoPaths = new TheoryData<string, string, string>
+ {
+ { "", "", "" },
+ { Sep, "", Sep },
+ { AltSep, "", AltSep },
+ { "", Sep, Sep },
+ { "", AltSep, AltSep },
+ { Sep, Sep, $"{Sep}{Sep}" },
+ { AltSep, AltSep, $"{AltSep}{AltSep}" },
+ { "a", "", "a" },
+ { "", "a", "a" },
+ { "a", "a", $"a{Sep}a" },
+ { $"a{Sep}", "a", $"a{Sep}a" },
+ { "a", $"{Sep}a", $"a{Sep}a" },
+ { $"a{Sep}", $"{Sep}a", $"a{Sep}{Sep}a" },
+ { "a", $"a{Sep}", $"a{Sep}a{Sep}" },
+ { $"a{AltSep}", "a", $"a{AltSep}a" },
+ { "a", $"{AltSep}a", $"a{AltSep}a" },
+ { $"a{Sep}", $"{AltSep}a", $"a{Sep}{AltSep}a" },
+ { $"a{AltSep}", $"{AltSep}a", $"a{AltSep}{AltSep}a" },
+ { "a", $"a{AltSep}", $"a{Sep}a{AltSep}" },
+ };
+
+ [Theory, MemberData(nameof(TestData_JoinTwoPaths))]
+ public void JoinTwoPaths(string path1, string path2, string expected)
+ {
+ Assert.Equal(expected, Path.Join(path1, path2));
+ }
+
+ [Theory, MemberData(nameof(TestData_JoinTwoPaths))]
+ public void TryJoinTwoPaths(string path1, string path2, string expected)
+ {
+ char[] output = new char[expected.Length];
+
+ Assert.True(Path.TryJoin(path1, path2, output, out int written));
+ Assert.Equal(expected.Length, written);
+ Assert.Equal(expected, new string(output));
+
+ if (expected.Length > 0)
+ {
+ Assert.False(Path.TryJoin(path1, path2, Span<char>.Empty, out written));
+ Assert.Equal(0, written);
+
+ output = new char[expected.Length - 1];
+ Assert.False(Path.TryJoin(path1, path2, output, out written));
+ Assert.Equal(0, written);
+ Assert.Equal(output, new char[output.Length]);
+ }
+ }
+
+ public static TheoryData<string, string, string, string> TestData_JoinThreePaths = new TheoryData<string, string, string, string>
+ {
+ { "", "", "", "" },
+ { Sep, Sep, Sep, $"{Sep}{Sep}{Sep}" },
+ { AltSep, AltSep, AltSep, $"{AltSep}{AltSep}{AltSep}" },
+ { "a", "", "", "a" },
+ { "", "a", "", "a" },
+ { "", "", "a", "a" },
+ { "a", "", "a", $"a{Sep}a" },
+ { "a", "a", "", $"a{Sep}a" },
+ { "", "a", "a", $"a{Sep}a" },
+ { "a", "a", "a", $"a{Sep}a{Sep}a" },
+ { "a", Sep, "a", $"a{Sep}a" },
+ { $"a{Sep}", "", "a", $"a{Sep}a" },
+ { $"a{Sep}", "a", "", $"a{Sep}a" },
+ { "", $"a{Sep}", "a", $"a{Sep}a" },
+ { "a", "", $"{Sep}a", $"a{Sep}a" },
+ { $"a{AltSep}", "", "a", $"a{AltSep}a" },
+ { $"a{AltSep}", "a", "", $"a{AltSep}a" },
+ { "", $"a{AltSep}", "a", $"a{AltSep}a" },
+ { "a", "", $"{AltSep}a", $"a{AltSep}a" },
+ };
+
+ [Theory, MemberData(nameof(TestData_JoinThreePaths))]
+ public void JoinThreePaths(string path1, string path2, string path3, string expected)
+ {
+ Assert.Equal(expected, Path.Join(path1, path2, path3));
+ }
+
+ [Theory, MemberData(nameof(TestData_JoinThreePaths))]
+ public void TryJoinThreePaths(string path1, string path2, string path3, string expected)
+ {
+ char[] output = new char[expected.Length];
+
+ Assert.True(Path.TryJoin(path1, path2, path3, output, out int written));
+ Assert.Equal(expected.Length, written);
+ Assert.Equal(expected, new string(output));
+
+ if (expected.Length > 0)
+ {
+ Assert.False(Path.TryJoin(path1, path2, path3, Span<char>.Empty, out written));
+ Assert.Equal(0, written);
+
+ output = new char[expected.Length - 1];
+ Assert.False(Path.TryJoin(path1, path2, path3, output, out written));
+ Assert.Equal(0, written);
+ Assert.Equal(output, new char[output.Length]);
+ }
+ }
+ }
+}
diff --git a/src/System.Runtime.Extensions/tests/System/IO/PathTests_Unix.cs b/src/System.Runtime.Extensions/tests/System/IO/PathTests_Unix.cs
new file mode 100644
index 0000000000..19b2473235
--- /dev/null
+++ b/src/System.Runtime.Extensions/tests/System/IO/PathTests_Unix.cs
@@ -0,0 +1,131 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using Xunit;
+
+namespace System.IO.Tests
+{
+ [PlatformSpecific(TestPlatforms.AnyUnix)]
+ public class PathTests_Unix : PathTestsBase
+ {
+ [Theory,
+ MemberData(nameof(TestData_GetPathRoot_Unc)),
+ MemberData(nameof(TestData_GetPathRoot_DevicePaths))]
+ public static void GetPathRoot(string value, string expected)
+ {
+ // UNCs and device paths have no special meaning in Unix
+ Assert.Empty(Path.GetPathRoot(value));
+ }
+
+ [Theory,
+ InlineData("B:", "B:"),
+ InlineData("A:.", "A:.")]
+ public void GetFileName_Volume(string path, string expected)
+ {
+ // No such thing as a drive relative path on Unix.
+ Assert.Equal(expected, Path.GetFileName(path));
+ Assert.Equal(expected, new string(Path.GetFileName(path.AsSpan())));
+ }
+
+ public static IEnumerable<string[]> GetTempPath_SetEnvVar_Data()
+ {
+ yield return new string[] { "/tmp/", "/tmp" };
+ yield return new string[] { "/tmp/", "/tmp/" };
+ yield return new string[] { "/", "/" };
+ yield return new string[] { "/var/tmp/", "/var/tmp" };
+ yield return new string[] { "/var/tmp/", "/var/tmp/" };
+ yield return new string[] { "~/", "~" };
+ yield return new string[] { "~/", "~/" };
+ yield return new string[] { ".tmp/", ".tmp" };
+ yield return new string[] { "./tmp/", "./tmp" };
+ yield return new string[] { "/home/someuser/sometempdir/", "/home/someuser/sometempdir/" };
+ yield return new string[] { "/home/someuser/some tempdir/", "/home/someuser/some tempdir/" };
+ yield return new string[] { "/tmp/", null };
+ }
+
+ [Fact]
+ public void GetTempPath_SetEnvVar_Unix()
+ {
+ RemoteInvoke(() =>
+ {
+ foreach (string[] tempPath in GetTempPath_SetEnvVar_Data())
+ {
+ GetTempPath_SetEnvVar("TMPDIR", tempPath[0], tempPath[1]);
+ }
+ }).Dispose();
+ }
+
+ [Fact]
+ public void GetFullPath_Unix_Whitespace()
+ {
+ string curDir = Directory.GetCurrentDirectory();
+ Assert.Equal("/ / ", Path.GetFullPath("/ // "));
+ Assert.Equal(Path.Combine(curDir, " "), Path.GetFullPath(" "));
+ Assert.Equal(Path.Combine(curDir, "\r\n"), Path.GetFullPath("\r\n"));
+ }
+
+ public static TheoryData<string, string, string> GetFullPath_BasePath_BasicExpansions_TestData_Unix => new TheoryData<string, string, string>
+ {
+ { @"/home/git", @"/home/git", @"/home/git" },
+ { "", @"/home/git", @"/home/git" },
+ { "..", @"/home/git", @"/home" },
+ { @"/home/git/././././././", @"/home/git", @"/home/git/" },
+ { @"/home/git///.", @"/home/git", @"/home/git" },
+ { @"/home/git/../git/./../git", @"/home/git", @"/home/git" },
+ { @"/home/git/somedir/..", @"/home/git", @"/home/git" },
+ { @"/home/git/./", @"/home/git", @"/home/git/" },
+ { @"/home/../../../../..", @"/home/git", @"/" },
+ { @"/home///", @"/home/git", @"/home/" },
+ { "tmp", @"/home/git", @"/home/git/tmp" },
+ { "tmp/bar/..", @"/home/git", @"/home/git/tmp" },
+ { "tmp/..", @"/home/git", @"/home/git" },
+ { "tmp/./bar/../", @"/home/git", @"/home/git/tmp/" },
+ { "tmp/bar/../../", @"/home/git", @"/home/git/" },
+ { "tmp/bar/../next/../", @"/home/git", @"/home/git/tmp/" },
+ { "tmp/bar/next", @"/home/git", @"/home/git/tmp/bar/next" },
+
+ // Rooted
+ { @"/tmp/bar", @"/home/git", @"/tmp/bar" },
+ { @"/bar", @"/home/git", @"/bar" },
+ { @"/tmp/..", @"/home/git", @"/" },
+ { @"/tmp/bar/..", @"/home/git", @"/tmp" },
+ { @"/tmp/..", @"/home/git", @"/" },
+ { @"/", @"/home/git", @"/" },
+
+ { @"/tmp/../../../bar", @"/home/git", @"/bar" },
+ { @"/bar/././././../../..", @"/home/git", @"/" },
+ { @"/../../tmp/../../", @"/home/git", @"/" },
+ { @"/../../tmp/bar/..", @"/home/git", @"/tmp" },
+ { @"/tmp/..", @"/home/git", @"/" },
+ { @"/././../../../../", @"/home/git", @"/" },
+
+ { @"/tmp/../../../../../bar", @"/home/git", @"/bar" },
+ { @"/./././bar/../../../", @"/home/git", @"/" },
+ { @"/tmp/..", @"/home/git", @"/" },
+ { @"/../../tmp/bar/..", @"/home/git", @"/tmp" },
+ { @"/tmp/..", @"/home/git", @"/" },
+ { @"../../../", @"/home/git", @"/" },
+
+ { @"../.././././bar/../../../", @"/home/git", @"/" },
+ { @"../../.././tmp/..", @"/home/git", @"/" },
+ { @"../../../tmp/bar/..", @"/home/git", @"/tmp" },
+ { @"../../././tmp/..", @"/home/git", @"/" },
+ { @"././../../../", @"/home/git", @"/" },
+ };
+
+ [Theory,
+ MemberData(nameof(GetFullPath_BasePath_BasicExpansions_TestData_Unix))]
+ public static void GetFullPath_BasicExpansions_Unix(string path, string basePath, string expected)
+ {
+ Assert.Equal(expected, Path.GetFullPath(path, basePath));
+ }
+
+ [Fact]
+ public void GetFullPath_ThrowsOnEmbeddedNulls()
+ {
+ Assert.Throws<ArgumentException>(null, () => Path.GetFullPath("/gi\0t", "/foo/bar"));
+ }
+ }
+}
diff --git a/src/System.Runtime.Extensions/tests/System/IO/PathTests_Windows.cs b/src/System.Runtime.Extensions/tests/System/IO/PathTests_Windows.cs
new file mode 100644
index 0000000000..005a1169f5
--- /dev/null
+++ b/src/System.Runtime.Extensions/tests/System/IO/PathTests_Windows.cs
@@ -0,0 +1,369 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Text.RegularExpressions;
+using Xunit;
+
+namespace System.IO.Tests
+{
+ [PlatformSpecific(TestPlatforms.Windows)]
+ public partial class PathTests_Windows : PathTestsBase
+ {
+ public void GetDirectoryName_DevicePath()
+ {
+ if (PathFeatures.IsUsingLegacyPathNormalization())
+ {
+ Assert.Equal(@"\\?\C:", Path.GetDirectoryName(@"\\?\C:\foo"));
+ }
+ else
+ {
+ Assert.Equal(@"\\?\C:\", Path.GetDirectoryName(@"\\?\C:\foo"));
+ }
+ }
+
+ [Theory, MemberData(nameof(TestData_GetDirectoryName_Windows))]
+ public void GetDirectoryName(string path, string expected)
+ {
+ Assert.Equal(expected, Path.GetDirectoryName(path));
+ }
+
+ [Theory,
+ InlineData("B:", ""),
+ InlineData("A:.", ".")]
+ public static void GetFileName_Volume(string path, string expected)
+ {
+ // With a valid drive letter followed by a colon, we have a root, but only on Windows.
+ Assert.Equal(expected, Path.GetFileName(path));
+ }
+
+ [ActiveIssue(27552)]
+ [Theory,
+ MemberData(nameof(TestData_GetPathRoot_Windows)),
+ MemberData(nameof(TestData_GetPathRoot_Unc)),
+ MemberData(nameof(TestData_GetPathRoot_DevicePaths))]
+ public void GetPathRoot_Windows(string value, string expected)
+ {
+ Assert.Equal(expected, Path.GetPathRoot(value));
+
+ if (value.Length != expected.Length)
+ {
+ // The string overload normalizes the separators
+ Assert.Equal(expected, Path.GetPathRoot(value.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)));
+
+ // UNCs and device paths will have their semantics changed if we double up separators
+ if (!value.StartsWith(@"\\"))
+ Assert.Equal(expected, Path.GetPathRoot(value.Replace(@"\", @"\\")));
+ }
+ }
+
+ public static IEnumerable<string[]> GetTempPath_SetEnvVar_Data()
+ {
+ yield return new string[] { @"C:\Users\someuser\AppData\Local\Temp\", @"C:\Users\someuser\AppData\Local\Temp" };
+ yield return new string[] { @"C:\Users\someuser\AppData\Local\Temp\", @"C:\Users\someuser\AppData\Local\Temp\" };
+ yield return new string[] { @"C:\", @"C:\" };
+ yield return new string[] { @"C:\tmp\", @"C:\tmp" };
+ yield return new string[] { @"C:\tmp\", @"C:\tmp\" };
+ }
+
+ [Fact]
+ public void GetTempPath_SetEnvVar()
+ {
+ RemoteInvoke(() =>
+ {
+ foreach (string[] tempPath in GetTempPath_SetEnvVar_Data())
+ {
+ GetTempPath_SetEnvVar("TMP", tempPath[0], tempPath[1]);
+ }
+ }).Dispose();
+ }
+
+ [Theory, MemberData(nameof(TestData_Spaces))]
+ public void GetFullPath_TrailingSpacesCut(string component)
+ {
+ // Windows cuts off any simple white space added to a path
+ string path = "C:\\Test" + component;
+ Assert.Equal("C:\\Test", Path.GetFullPath(path));
+ }
+
+ [Fact]
+ public void GetFullPath_NormalizedLongPathTooLong()
+ {
+ // Try out a long path that normalizes down to more than MaxPath
+ string curDir = Directory.GetCurrentDirectory();
+ const int Iters = 260;
+ var longPath = new StringBuilder(curDir, curDir.Length + (Iters * 4));
+ for (int i = 0; i < Iters; i++)
+ {
+ longPath.Append(Path.DirectorySeparatorChar).Append('a').Append(Path.DirectorySeparatorChar).Append('.');
+ }
+
+ if (PathFeatures.AreAllLongPathsAvailable())
+ {
+ // Now no longer throws unless over ~32K
+ Assert.NotNull(Path.GetFullPath(longPath.ToString()));
+ }
+ else
+ {
+ Assert.Throws<PathTooLongException>(() => Path.GetFullPath(longPath.ToString()));
+ }
+ }
+
+ [Theory,
+ InlineData(@"C:..."),
+ InlineData(@"C:...\somedir"),
+ InlineData(@"\.. .\"),
+ InlineData(@"\. .\"),
+ InlineData(@"\ .\")]
+ public void GetFullPath_LegacyArgumentExceptionPaths(string path)
+ {
+ if (PathFeatures.IsUsingLegacyPathNormalization())
+ {
+ // We didn't allow these paths on < 4.6.2
+ AssertExtensions.Throws<ArgumentException>(null, () => Path.GetFullPath(path));
+ }
+ else
+ {
+ // These paths are legitimate Windows paths that can be created without extended syntax.
+ // We now allow them through.
+ Path.GetFullPath(path);
+ }
+ }
+
+ [Fact]
+ public void GetFullPath_MaxPathNotTooLong()
+ {
+ string value = @"C:\" + new string('a', 255) + @"\";
+ if (PathFeatures.AreAllLongPathsAvailable())
+ {
+ // Shouldn't throw anymore
+ Path.GetFullPath(value);
+ }
+ else
+ {
+ Assert.Throws<PathTooLongException>(() => Path.GetFullPath(value));
+ }
+ }
+
+ [Fact]
+ public void GetFullPath_PathTooLong()
+ {
+ Assert.Throws<PathTooLongException>(() => Path.GetFullPath(@"C:\" + new string('a', short.MaxValue) + @"\"));
+ }
+
+ [Theory,
+ InlineData(@"C:\", @"C:\"),
+ InlineData(@"C:\.", @"C:\"),
+ InlineData(@"C:\..", @"C:\"),
+ InlineData(@"C:\..\..", @"C:\"),
+ InlineData(@"C:\A\..", @"C:\"),
+ InlineData(@"C:\..\..\A\..", @"C:\")]
+ public void GetFullPath_RelativeRoot(string path, string expected)
+ {
+ Assert.Equal(Path.GetFullPath(path), expected);
+ }
+
+ [Fact]
+ public void GetFullPath_StrangeButLegalPaths()
+ {
+ // These are legal and creatable without using extended syntax if you use a trailing slash
+ // (such as "md ...\"). We used to filter these out, but now allow them to prevent apps from
+ // being blocked when they hit these paths.
+ string curDir = Directory.GetCurrentDirectory();
+ if (PathFeatures.IsUsingLegacyPathNormalization())
+ {
+ // Legacy path Path.GetFullePath() ignores . when there is less or more that two, when there is .. in the path it returns one directory up.
+ Assert.Equal(
+ Path.GetFullPath(curDir + Path.DirectorySeparatorChar),
+ Path.GetFullPath(curDir + Path.DirectorySeparatorChar + ". " + Path.DirectorySeparatorChar));
+ Assert.Equal(
+ Path.GetFullPath(Path.GetDirectoryName(curDir) + Path.DirectorySeparatorChar),
+ Path.GetFullPath(curDir + Path.DirectorySeparatorChar + "..." + Path.DirectorySeparatorChar));
+ Assert.Equal(
+ Path.GetFullPath(Path.GetDirectoryName(curDir) + Path.DirectorySeparatorChar),
+ Path.GetFullPath(curDir + Path.DirectorySeparatorChar + ".. " + Path.DirectorySeparatorChar));
+ }
+ else
+ {
+ Assert.NotEqual(
+ Path.GetFullPath(curDir + Path.DirectorySeparatorChar),
+ Path.GetFullPath(curDir + Path.DirectorySeparatorChar + ". " + Path.DirectorySeparatorChar));
+ Assert.NotEqual(
+ Path.GetFullPath(Path.GetDirectoryName(curDir) + Path.DirectorySeparatorChar),
+ Path.GetFullPath(curDir + Path.DirectorySeparatorChar + "..." + Path.DirectorySeparatorChar));
+ Assert.NotEqual(
+ Path.GetFullPath(Path.GetDirectoryName(curDir) + Path.DirectorySeparatorChar),
+ Path.GetFullPath(curDir + Path.DirectorySeparatorChar + ".. " + Path.DirectorySeparatorChar));
+ }
+ }
+
+ [Theory,
+ InlineData(@"\\?\C:\ "),
+ InlineData(@"\\?\C:\ \ "),
+ InlineData(@"\\?\C:\ ."),
+ InlineData(@"\\?\C:\ .."),
+ InlineData(@"\\?\C:\..."),
+ InlineData(@"\\?\GLOBALROOT\"),
+ InlineData(@"\\?\"),
+ InlineData(@"\\?\."),
+ InlineData(@"\\?\.."),
+ InlineData(@"\\?\\"),
+ InlineData(@"\\?\C:\\"),
+ InlineData(@"\\?\C:\|"),
+ InlineData(@"\\?\C:\."),
+ InlineData(@"\\?\C:\.."),
+ InlineData(@"\\?\C:\Foo1\."),
+ InlineData(@"\\?\C:\Foo2\.."),
+ InlineData(@"\\?\UNC\"),
+ InlineData(@"\\?\UNC\server1"),
+ InlineData(@"\\?\UNC\server2\"),
+ InlineData(@"\\?\UNC\server3\\"),
+ InlineData(@"\\?\UNC\server4\.."),
+ InlineData(@"\\?\UNC\server5\share\."),
+ InlineData(@"\\?\UNC\server6\share\.."),
+ InlineData(@"\\?\UNC\a\b\\"),
+ InlineData(@"\\.\"),
+ InlineData(@"\\.\."),
+ InlineData(@"\\.\.."),
+ InlineData(@"\\.\\"),
+ InlineData(@"\\.\C:\\"),
+ InlineData(@"\\.\C:\|"),
+ InlineData(@"\\.\C:\."),
+ InlineData(@"\\.\C:\.."),
+ InlineData(@"\\.\C:\Foo1\."),
+ InlineData(@"\\.\C:\Foo2\..")]
+ public void GetFullPath_ValidExtendedPaths(string path)
+ {
+ if (PathFeatures.IsUsingLegacyPathNormalization())
+ {
+ // Legacy Path doesn't support any of these paths.
+ AssertExtensions.ThrowsAny<ArgumentException, NotSupportedException>(() => Path.GetFullPath(path));
+ return;
+ }
+
+ // None of these should throw
+ if (path.StartsWith(@"\\?\"))
+ {
+ Assert.Equal(path, Path.GetFullPath(path));
+ }
+ else
+ {
+ Path.GetFullPath(path);
+ }
+ }
+
+ [Theory,
+ InlineData(@"\\.\UNC\"),
+ InlineData(@"\\.\UNC\LOCALHOST"),
+ InlineData(@"\\.\UNC\localHOST\"),
+ InlineData(@"\\.\UNC\LOcaLHOST\\"),
+ InlineData(@"\\.\UNC\lOCALHOST\.."),
+ InlineData(@"\\.\UNC\LOCALhost\share\."),
+ InlineData(@"\\.\UNC\loCALHOST\share\.."),
+ InlineData(@"\\.\UNC\a\b\\")]
+ public static void GetFullPath_ValidLegacy_ValidExtendedPaths(string path)
+ {
+ // should not throw
+ Path.GetFullPath(path);
+ }
+
+ [Theory,
+ // https://github.com/dotnet/corefx/issues/11965
+ InlineData(@"\\LOCALHOST\share\test.txt.~SS", @"\\LOCALHOST\share\test.txt.~SS"),
+ InlineData(@"\\LOCALHOST\share1", @"\\LOCALHOST\share1"),
+ InlineData(@"\\LOCALHOST\share3\dir", @"\\LOCALHOST\share3\dir"),
+ InlineData(@"\\LOCALHOST\share4\.", @"\\LOCALHOST\share4"),
+ InlineData(@"\\LOCALHOST\share5\..", @"\\LOCALHOST\share5"),
+ InlineData(@"\\LOCALHOST\share6\ ", @"\\LOCALHOST\share6\"),
+ InlineData(@"\\LOCALHOST\ share7\", @"\\LOCALHOST\ share7\"),
+ InlineData(@"\\?\UNC\LOCALHOST\share8\test.txt.~SS", @"\\?\UNC\LOCALHOST\share8\test.txt.~SS"),
+ InlineData(@"\\?\UNC\LOCALHOST\share9", @"\\?\UNC\LOCALHOST\share9"),
+ InlineData(@"\\?\UNC\LOCALHOST\shareA\dir", @"\\?\UNC\LOCALHOST\shareA\dir"),
+ InlineData(@"\\?\UNC\LOCALHOST\shareB\. ", @"\\?\UNC\LOCALHOST\shareB\. "),
+ InlineData(@"\\?\UNC\LOCALHOST\shareC\.. ", @"\\?\UNC\LOCALHOST\shareC\.. "),
+ InlineData(@"\\?\UNC\LOCALHOST\shareD\ ", @"\\?\UNC\LOCALHOST\shareD\ "),
+ InlineData(@"\\.\UNC\LOCALHOST\ shareE\", @"\\.\UNC\LOCALHOST\ shareE\"),
+ InlineData(@"\\.\UNC\LOCALHOST\shareF\test.txt.~SS", @"\\.\UNC\LOCALHOST\shareF\test.txt.~SS"),
+ InlineData(@"\\.\UNC\LOCALHOST\shareG", @"\\.\UNC\LOCALHOST\shareG"),
+ InlineData(@"\\.\UNC\LOCALHOST\shareH\dir", @"\\.\UNC\LOCALHOST\shareH\dir"),
+ InlineData(@"\\.\UNC\LOCALHOST\shareK\ ", @"\\.\UNC\LOCALHOST\shareK\"),
+ InlineData(@"\\.\UNC\LOCALHOST\ shareL\", @"\\.\UNC\LOCALHOST\ shareL\")]
+ public void GetFullPath_UNC_Valid(string path, string expected)
+ {
+ if (path.StartsWith(@"\\?\") && PathFeatures.IsUsingLegacyPathNormalization())
+ {
+ AssertExtensions.Throws<ArgumentException>(null, () => Path.GetFullPath(path));
+ }
+ else
+ {
+ Assert.Equal(expected, Path.GetFullPath(path));
+ }
+ }
+
+ [Theory,
+ InlineData(@"\\.\UNC\LOCALHOST\shareI\. ", @"\\.\UNC\LOCALHOST\shareI\", @"\\.\UNC\LOCALHOST\shareI"),
+ InlineData(@"\\.\UNC\LOCALHOST\shareJ\.. ", @"\\.\UNC\LOCALHOST\shareJ\", @"\\.\UNC\LOCALHOST")]
+ public static void GetFullPath_Windows_UNC_Valid_LegacyPathSupport(string path, string normalExpected, string legacyExpected)
+ {
+ string expected = PathFeatures.IsUsingLegacyPathNormalization() ? legacyExpected : normalExpected;
+ Assert.Equal(expected, Path.GetFullPath(path));
+ }
+
+ [Fact]
+ public static void GetFullPath_Windows_83Paths()
+ {
+ // Create a temporary file name with a name longer than 8.3 such that it'll need to be shortened.
+ string tempFilePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N") + ".txt");
+ File.Create(tempFilePath).Dispose();
+ try
+ {
+ // Get its short name
+ var sb = new StringBuilder(260);
+ if (GetShortPathName(tempFilePath, sb, sb.Capacity) > 0) // only proceed if we could successfully create the short name
+ {
+ string shortName = sb.ToString();
+
+ // Make sure the shortened name expands back to the original one
+ // Sometimes shortening or GetFullPath is changing the casing of "temp" on some test machines: normalize both sides
+ tempFilePath = Regex.Replace(tempFilePath, @"\\temp\\", @"\TEMP\", RegexOptions.IgnoreCase);
+ shortName = Regex.Replace(Path.GetFullPath(shortName), @"\\temp\\", @"\TEMP\", RegexOptions.IgnoreCase);
+ Assert.Equal(tempFilePath, shortName);
+
+ // Should work with device paths that aren't well-formed extended syntax
+ if (!PathFeatures.IsUsingLegacyPathNormalization())
+ {
+ Assert.Equal(@"\\.\" + tempFilePath, Path.GetFullPath(@"\\.\" + shortName));
+ Assert.Equal(@"\\?\" + tempFilePath, Path.GetFullPath(@"//?/" + shortName));
+
+ // Shouldn't mess with well-formed extended syntax
+ Assert.Equal(@"\\?\" + shortName, Path.GetFullPath(@"\\?\" + shortName));
+ }
+
+ // Validate case where short name doesn't expand to a real file
+ string invalidShortName = @"S:\DOESNT~1\USERNA~1.RED\LOCALS~1\Temp\bg3ylpzp";
+ Assert.Equal(invalidShortName, Path.GetFullPath(invalidShortName));
+
+ // Same thing, but with a long path that normalizes down to a short enough one
+ const int Iters = 1000;
+ var shortLongName = new StringBuilder(invalidShortName, invalidShortName.Length + (Iters * 2));
+ for (int i = 0; i < Iters; i++)
+ {
+ shortLongName.Append(Path.DirectorySeparatorChar).Append('.');
+ }
+ Assert.Equal(invalidShortName, Path.GetFullPath(shortLongName.ToString()));
+ }
+ }
+ finally
+ {
+ File.Delete(tempFilePath);
+ }
+ }
+
+ // Windows-only P/Invoke to create 8.3 short names from long names
+ [DllImport("kernel32.dll", EntryPoint = "GetShortPathNameW", CharSet = CharSet.Unicode)]
+ private static extern uint GetShortPathName(string lpszLongPath, StringBuilder lpszShortPath, int cchBuffer);
+ }
+}
diff --git a/src/System.Runtime.Extensions/tests/System/IO/PathTests_Windows.netcoreapp.cs b/src/System.Runtime.Extensions/tests/System/IO/PathTests_Windows.netcoreapp.cs
new file mode 100644
index 0000000000..2e8360eb18
--- /dev/null
+++ b/src/System.Runtime.Extensions/tests/System/IO/PathTests_Windows.netcoreapp.cs
@@ -0,0 +1,268 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.IO.Tests
+{
+ public partial class PathTests_Windows : PathTestsBase
+ {
+ [Theory,
+ MemberData(nameof(TestData_GetPathRoot_Windows)),
+ MemberData(nameof(TestData_GetPathRoot_Unc)),
+ MemberData(nameof(TestData_GetPathRoot_DevicePaths))]
+ public void GetPathRoot_Span(string value, string expected)
+ {
+ Assert.Equal(expected, new string(Path.GetPathRoot(value.AsSpan())));
+ Assert.True(Path.IsPathRooted(value.AsSpan()));
+ }
+
+ [Theory, MemberData(nameof(TestData_UnicodeWhiteSpace))]
+ public void GetFullPath_UnicodeWhiteSpaceStays(string component)
+ {
+ // When not NetFX full path should not cut off component
+ string path = "C:\\Test" + component;
+ Assert.Equal(path, Path.GetFullPath(path));
+ }
+
+ [Theory, MemberData(nameof(TestData_Periods))]
+ public void GetFullPath_TrailingPeriodsCut(string component)
+ {
+ // Windows cuts off any simple white space added to a path
+ string path = "C:\\Test" + component;
+ Assert.Equal("C:\\Test", Path.GetFullPath(path));
+ }
+
+ public static TheoryData<string, string, string> GetFullPath_Windows_FullyQualified => new TheoryData<string, string, string>
+ {
+ { @"C:\git\corefx", @"C:\git\corefx", @"C:\git\corefx" },
+ { @"C:\git\corefx.\.\.\.\.\.", @"C:\git\corefx", @"C:\git\corefx" },
+ { @"C:\git\corefx\\\.", @"C:\git\corefx", @"C:\git\corefx" },
+ { @"C:\git\corefx\..\corefx\.\..\corefx", @"C:\git\corefx", @"C:\git\corefx" },
+ { @"C:\somedir\..", @"C:\git\corefx", @"C:\" },
+ { @"C:\", @"C:\git\corefx", @"C:\" },
+ { @"..\..\..\..", @"C:\git\corefx", @"C:\" },
+ { @"C:\\\", @"C:\git\corefx", @"C:\" },
+ { @"C:\..\..\", @"C:\git\corefx", @"C:\" },
+ { @"C:\..\git\..\.\", @"C:\git\corefx", @"C:\" },
+ { @"C:\git\corefx\..\..\..\", @"C:\git\corefx", @"C:\" },
+ { @"C:\.\corefx\", @"C:\git\corefx", @"C:\corefx\" },
+ };
+
+ [Theory,
+ MemberData(nameof(GetFullPath_Windows_FullyQualified))]
+ public void GetFullPath_BasicExpansions_Windows(string path, string basePath, string expected)
+ {
+ Assert.Equal(expected, Path.GetFullPath(path, basePath));
+ }
+
+ public static TheoryData<string, string, string> GetFullPath_Windows_PathIsDevicePath => new TheoryData<string, string, string>
+ {
+ // Device Paths with \\?\ wont get normalized i.e. relative segments wont get removed.
+ { @"\\?\C:\git\corefx.\.\.\.\.\.", @"C:\git\corefx", @"\\?\C:\git\corefx.\.\.\.\.\." },
+ { @"\\?\C:\git\corefx\\\.", @"C:\git\corefx", @"\\?\C:\git\corefx\\\." },
+ { @"\\?\C:\git\corefx\..\corefx\.\..\corefx", @"C:\git\corefx", @"\\?\C:\git\corefx\..\corefx\.\..\corefx" },
+ { @"\\?\\somedir\..", @"C:\git\corefx", @"\\?\\somedir\.." },
+ { @"\\?\", @"C:\git\corefx", @"\\?\" },
+ { @"\\?\..\..\..\..", @"C:\git\corefx", @"\\?\..\..\..\.." },
+ { @"\\?\\\\" , @"C:\git\corefx", @"\\?\\\\" },
+ { @"\\?\C:\Foo." , @"C:\git\corefx", @"\\?\C:\Foo." },
+ { @"\\?\C:\Foo " , @"C:\git\corefx", @"\\?\C:\Foo " },
+
+ { @"\\.\C:\git\corefx.\.\.\.\.\.", @"C:\git\corefx", @"\\.\C:\git\corefx" },
+ { @"\\.\C:\git\corefx\\\.", @"C:\git\corefx", @"\\.\C:\git\corefx" },
+ { @"\\.\C:\git\corefx\..\corefx\.\..\corefx", @"C:\git\corefx", @"\\.\C:\git\corefx" },
+ { @"\\.\\somedir\..", @"C:\git\corefx", @"\\.\" },
+ { @"\\.\", @"C:\git\corefx", @"\\.\" },
+ { @"\\.\..\..\..\..", @"C:\git\corefx", @"\\.\" },
+ { @"\\.\", @"C:\git\corefx", @"\\.\" },
+ { @"\\.\C:\Foo." , @"C:\git\corefx", @"\\.\C:\Foo" },
+ { @"\\.\C:\Foo " , @"C:\git\corefx", @"\\.\C:\Foo" },
+ };
+
+ [Theory,
+ MemberData(nameof(GetFullPath_Windows_PathIsDevicePath))]
+ public void GetFullPath_BasicExpansions_Windows_PathIsDevicePath(string path, string basePath, string expected)
+ {
+ Assert.Equal(expected, Path.GetFullPath(path, basePath));
+ Assert.Equal(expected, Path.GetFullPath(path, @"\\.\" + basePath));
+ Assert.Equal(expected, Path.GetFullPath(path, @"\\?\" + basePath));
+ }
+
+ public static TheoryData<string, string, string> GetFullPath_Windows_UNC => new TheoryData<string, string, string>
+ {
+ { @"foo", @"", @"foo" },
+ { @"foo", @"server1", @"server1\foo" },
+ { @"\foo", @"server2", @"server2\foo" },
+ { @"foo", @"server3\", @"server3\foo" },
+ { @"..\foo", @"server4", @"server4\..\foo" },
+ { @".\foo", @"server5\share", @"server5\share\foo" },
+ { @"..\foo", @"server6\share", @"server6\share\foo" },
+ { @"\foo", @"a\b\\", @"a\b\foo" },
+ { @"foo", @"LOCALHOST\share8\test.txt.~SS", @"LOCALHOST\share8\test.txt.~SS\foo" },
+ { @"foo", @"LOCALHOST\share9", @"LOCALHOST\share9\foo" },
+ { @"foo", @"LOCALHOST\shareA\dir", @"LOCALHOST\shareA\dir\foo" },
+ { @". \foo", @"LOCALHOST\shareB\", @"LOCALHOST\shareB\. \foo" },
+ { @".. \foo", @"LOCALHOST\shareC\", @"LOCALHOST\shareC\.. \foo" },
+ { @" \foo", @"LOCALHOST\shareD\", @"LOCALHOST\shareD\ \foo" },
+
+ { "foo", @"LOCALHOST\ shareE\", @"LOCALHOST\ shareE\foo" },
+ { "foo", @"LOCALHOST\shareF\test.txt.~SS", @"LOCALHOST\shareF\test.txt.~SS\foo" },
+ { "foo", @"LOCALHOST\shareG", @"LOCALHOST\shareG\foo" },
+ { "foo", @"LOCALHOST\shareH\dir", @"LOCALHOST\shareH\dir\foo" },
+ { "foo", @"LOCALHOST\shareK\", @"LOCALHOST\shareK\foo" },
+ { "foo", @"LOCALHOST\ shareL\", @"LOCALHOST\ shareL\foo" },
+
+ // Relative segments eating into the root
+ { @".\..\foo\..\", @"server\share", @"server\share\" },
+ { @"..\foo\tmp\..\..\", @"server\share", @"server\share\" },
+ { @"..\..\..\foo", @"server\share", @"server\share\foo" },
+ { @"..\foo\..\..\tmp", @"server\share", @"server\share\tmp" },
+ { @"..\foo", @"server\share", @"server\share\foo" },
+ { @"...\\foo", @"server\share", @"server\share\...\foo" },
+ { @"...\..\.\foo", @"server\share", @"server\share\foo" },
+ { @"..\foo\tmp\..\..\..\..\..\", @"server\share", @"server\share\" },
+ { @"..\..\..\..\foo", @"server\share", @"server\share\foo" },
+ };
+
+ [Theory,
+ MemberData(nameof(GetFullPath_Windows_UNC))]
+ public void GetFullPath_CommonUnc_Windows(string path, string basePath, string expected)
+ {
+ Assert.Equal(@"\\" + expected, Path.GetFullPath(path, @"\\" + basePath));
+ Assert.Equal(@"\\.\UNC\" + expected, Path.GetFullPath(path, @"\\.\UNC\" + basePath));
+ Assert.Equal(@"\\?\UNC\" + expected, Path.GetFullPath(path, @"\\?\UNC\" + basePath));
+ }
+
+ public static TheoryData<string, string, string> GetFullPath_Windows_CommonDevicePaths => new TheoryData<string, string, string>
+ {
+ // Device paths
+ { "foo", @"C:\ ", @"C:\ \foo" },
+ { @" \ \foo", @"C:\", @"C:\ \ \foo" },
+ { @" .\foo", @"C:\", @"C:\ .\foo" },
+ { @" ..\foo", @"C:\", @"C:\ ..\foo" },
+ { @"...\foo", @"C:\", @"C:\...\foo" },
+
+ { @"foo", @"C:\\", @"C:\foo" },
+ { @"foo.", @"C:\\", @"C:\foo." },
+ { @"foo \git", @"C:\\", @"C:\foo \git" },
+ { @"foo. \git", @"C:\\", @"C:\foo. \git" },
+ { @" foo \git", @"C:\\", @"C:\ foo \git" },
+ { @"foo ", @"C:\\", @"C:\foo " },
+ { @"|\foo", @"C:\", @"C:\|\foo" },
+ { @".\foo", @"C:\", @"C:\foo" },
+ { @"..\foo", @"C:\", @"C:\foo" },
+
+ { @"\Foo1\.\foo", @"C:\", @"C:\Foo1\foo" },
+ { @"\Foo2\..\foo", @"C:\", @"C:\foo" },
+
+ { @"foo", @"GLOBALROOT\", @"GLOBALROOT\foo" },
+ { @"foo", @"", @"foo" },
+ { @".\foo", @"", @".\foo" },
+ { @"..\foo", @"", @"..\foo" },
+ { @"C:", @"", @"C:\"},
+
+ // Relative segments eating into the root
+ { @"foo", @"GLOBALROOT\", @"GLOBALROOT\foo" },
+ { @"..\..\foo\..\..\", @"", @"..\" },
+ { @".\..\..\..\..\foo", @"", @".\foo" },
+ { @"..\foo\..\..\..\", @"", @"..\" },
+ { @"\.\.\..\", @"C:\", @"C:\"},
+ { @"..\..\..\foo", @"GLOBALROOT\", @"GLOBALROOT\foo" },
+ { @"foo\..\..\", @"", @"foo\" },
+ { @".\.\foo\..\", @"", @".\" },
+ };
+
+ [Theory,
+ MemberData(nameof(GetFullPath_Windows_CommonDevicePaths))]
+ public void GetFullPath_CommonDevice_Windows(string path, string basePath, string expected)
+ {
+ Assert.Equal(@"\\.\" + expected, Path.GetFullPath(path, @"\\.\" + basePath));
+ Assert.Equal(@"\\?\" + expected, Path.GetFullPath(path, @"\\?\" + basePath));
+ }
+
+ public static TheoryData<string, string, string> GetFullPath_CommonRootedWindowsData => new TheoryData<string, string, string>
+ {
+ { "", @"C:\git\corefx", @"C:\git\corefx" },
+ { "..", @"C:\git\corefx", @"C:\git" },
+
+ // Current drive rooted
+ { @"\tmp\bar", @"C:\git\corefx", @"C:\tmp\bar" },
+ { @"\.\bar", @"C:\git\corefx", @"C:\bar" },
+ { @"\tmp\..", @"C:\git\corefx", @"C:\" },
+ { @"\tmp\bar\..", @"C:\git\corefx", @"C:\tmp" },
+ { @"\tmp\bar\..", @"C:\git\corefx", @"C:\tmp" },
+ { @"\", @"C:\git\corefx", @"C:\" },
+
+ { @"..\..\tmp\bar", @"C:\git\corefx", @"C:\tmp\bar" },
+ { @"..\..\.\bar", @"C:\git\corefx", @"C:\bar" },
+ { @"..\..\..\..\tmp\..", @"C:\git\corefx", @"C:\" },
+ { @"\tmp\..\bar..\..\..", @"C:\git\corefx", @"C:\" },
+ { @"\tmp\..\bar\..", @"C:\git\corefx", @"C:\" },
+ { @"\.\.\..\..\", @"C:\git\corefx", @"C:\" },
+
+ // Specific drive rooted
+ { @"C:tmp\foo\..", @"C:\git\corefx", @"C:\git\corefx\tmp" },
+ { @"C:tmp\foo\.", @"C:\git\corefx", @"C:\git\corefx\tmp\foo" },
+ { @"C:tmp\foo\..", @"C:\git\corefx", @"C:\git\corefx\tmp" },
+ { @"C:tmp", @"C:\git\corefx", @"C:\git\corefx\tmp" },
+ { @"C:", @"C:\git\corefx", @"C:\git\corefx" },
+ { @"C", @"C:\git\corefx", @"C:\git\corefx\C" },
+
+ { @"Z:tmp\foo\..", @"C:\git\corefx", @"Z:\tmp" },
+ { @"Z:tmp\foo\.", @"C:\git\corefx", @"Z:\tmp\foo" },
+ { @"Z:tmp\foo\..", @"C:\git\corefx", @"Z:\tmp" },
+ { @"Z:tmp", @"C:\git\corefx", @"Z:\tmp" },
+ { @"Z:", @"C:\git\corefx", @"Z:\" },
+ { @"Z", @"C:\git\corefx", @"C:\git\corefx\Z" },
+
+ // Relative segments eating into the root
+ { @"C:..\..\..\tmp\foo\..", @"C:\git\corefx", @"C:\tmp" },
+ { @"C:tmp\..\..\foo\.", @"C:\git\corefx", @"C:\git\foo" },
+ { @"C:..\..\tmp\foo\..", @"C:\git\corefx", @"C:\tmp" },
+ { @"C:tmp\..\", @"C:\git\corefx", @"C:\git\corefx\" },
+ { @"C:", @"C:\git\corefx", @"C:\git\corefx" },
+ { @"C", @"C:\git\corefx", @"C:\git\corefx\C" },
+
+ { @"C:tmp\..\..\..\..\foo\..", @"C:\git\corefx", @"C:\" },
+ { @"C:tmp\..\..\foo\.", @"C:\", @"C:\foo" },
+ { @"C:..\..\tmp\..\foo\..", @"C:\", @"C:\" },
+ { @"C:tmp\..\", @"C:\", @"C:\" },
+
+ { @"Z:tmp\foo\..", @"C:\git\corefx", @"Z:\tmp" },
+ { @"Z:tmp\foo\.", @"C:\git\corefx", @"Z:\tmp\foo" },
+ { @"Z:tmp\foo\..", @"C:\git\corefx", @"Z:\tmp" },
+ { @"Z:tmp", @"C:\git\corefx", @"Z:\tmp" },
+ { @"Z:", @"C:\git\corefx", @"Z:\" },
+ { @"Z", @"C:\git\corefx", @"C:\git\corefx\Z" },
+
+ { @"Z:..\..\..\tmp\foo\..", @"C:\git\corefx", @"Z:\tmp" },
+ { @"Z:tmp\..\..\foo\.", @"C:\git\corefx", @"Z:\foo" },
+ { @"Z:..\..\tmp\foo\..", @"C:\git\corefx", @"Z:\tmp" },
+ { @"Z:tmp\..\", @"C:\git\corefx", @"Z:\" },
+ { @"Z:", @"C:\git\corefx", @"Z:\" },
+ { @"Z", @"C:\git\corefx", @"C:\git\corefx\Z" },
+
+ { @"Z:tmp\..\..\..\..\foo\..", @"C:\git\corefx", @"Z:\" },
+ { @"Z:tmp\..\..\foo\.", @"C:\", @"Z:\foo" },
+ { @"Z:..\..\tmp\..\foo\..", @"C:\", @"Z:\" },
+ { @"Z:tmp\..\", @"C:\", @"Z:\" },
+ };
+
+ [Theory,
+ MemberData(nameof(GetFullPath_CommonRootedWindowsData))]
+ public void GetFullPath_CommonUnRooted_Windows(string path, string basePath, string expected)
+ {
+ Assert.Equal(expected, Path.GetFullPath(path, basePath));
+ Assert.Equal(@"\\.\" + expected, Path.GetFullPath(path, @"\\.\" + basePath));
+ Assert.Equal(@"\\?\" + expected, Path.GetFullPath(path, @"\\?\" + basePath));
+ }
+
+ [Fact]
+ public void GetFullPath_ThrowsOnEmbeddedNulls()
+ {
+ Assert.Throws<ArgumentException>(null, () => Path.GetFullPath("/gi\0t", @"C:\foo\bar"));
+ }
+ }
+}
diff --git a/src/System.Runtime.Extensions/tests/System/IO/PathTests_Windows_NetFX.cs b/src/System.Runtime.Extensions/tests/System/IO/PathTests_Windows_NetFX.cs
new file mode 100644
index 0000000000..56dee5db9d
--- /dev/null
+++ b/src/System.Runtime.Extensions/tests/System/IO/PathTests_Windows_NetFX.cs
@@ -0,0 +1,106 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.IO.Tests
+{
+ [PlatformSpecific(TestPlatforms.Windows)]
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)]
+ public class PathTests_Windows_NetFX : PathTestsBase
+ {
+ [Theory,
+ MemberData(nameof(TestData_EmbeddedNull)),
+ MemberData(nameof(TestData_EmptyString)),
+ MemberData(nameof(TestData_ControlChars))]
+ public void GetDirectoryName_ArgumentExceptions(string path)
+ {
+ // In NetFX we normalize and check invalid path chars
+ AssertExtensions.Throws<ArgumentException>("path", null, () => Path.GetDirectoryName(path));
+ }
+
+ [Theory,
+ MemberData(nameof(TestData_ControlChars)),
+ MemberData(nameof(TestData_EmbeddedNull))]
+ public void IsPathRooted_ArgumentExceptions(string path)
+ {
+ // In NetFX we check invalid path chars
+ AssertExtensions.Throws<ArgumentException>("path", null, () => Path.IsPathRooted(path));
+ }
+
+ [Theory,
+ MemberData(nameof(TestData_Spaces)),
+ MemberData(nameof(TestData_UnicodeWhiteSpace)),
+ MemberData(nameof(TestData_EmptyString))]
+ public void IsPathRooted_NegativeCases(string path)
+ {
+ Assert.False(Path.IsPathRooted(path));
+ }
+
+ [Theory,
+ MemberData(nameof(TestData_InvalidDriveLetters)),
+ MemberData(nameof(TestData_ValidDriveLetters))]
+ public void IsPathRooted(string path)
+ {
+ Assert.True(Path.IsPathRooted(path));
+ }
+
+ [Theory,
+ InlineData(@" C:\dir\baz", @"C:\dir"),
+ InlineData(@" C:\dir\baz", @"C:\dir")]
+ public void GetDirectoryName_SkipSpaces(string path, string expected)
+ {
+ // In very specific cases we would trim leading spaces
+ Assert.Equal(expected, Path.GetDirectoryName(path));
+ }
+
+ [Fact]
+ public void GetPathRoot_EmptyThrows_Desktop()
+ {
+ AssertExtensions.Throws<ArgumentException>("path", null, () => Path.GetPathRoot(string.Empty));
+ }
+
+ [Fact]
+ public void GetInvalidPathChars()
+ {
+ Assert.All(Path.GetInvalidPathChars(), c =>
+ {
+ string bad = c.ToString();
+ AssertExtensions.Throws<ArgumentException>("path", null, () => Path.ChangeExtension(bad, "ok"));
+ AssertExtensions.Throws<ArgumentException>("path", null, () => Path.Combine(bad, "ok"));
+ AssertExtensions.Throws<ArgumentException>("path", null, () => Path.Combine("ok", "ok", bad));
+ AssertExtensions.Throws<ArgumentException>("path", null, () => Path.Combine("ok", "ok", bad, "ok"));
+ AssertExtensions.Throws<ArgumentException>("path", null, () => Path.Combine(bad, bad, bad, bad, bad));
+ AssertExtensions.Throws<ArgumentException>("path", null, () => Path.GetDirectoryName(bad));
+ AssertExtensions.Throws<ArgumentException>("path", null, () => Path.GetExtension(bad));
+ AssertExtensions.Throws<ArgumentException>("path", null, () => Path.GetFileName(bad));
+ AssertExtensions.Throws<ArgumentException>("path", null, () => Path.GetFileNameWithoutExtension(bad));
+ AssertExtensions.Throws<ArgumentException>(c == 124 ? null : "path", null, () => Path.GetFullPath(bad));
+ AssertExtensions.Throws<ArgumentException>("path", null, () => Path.GetPathRoot(bad));
+ AssertExtensions.Throws<ArgumentException>("path", null, () => Path.IsPathRooted(bad));
+ });
+ }
+
+ [Theory, MemberData(nameof(TestData_NonDriveColonPaths))]
+ public void GetFullPath_NotSupportedColons(string path)
+ {
+ // Throws via our invalid colon filtering (as part of FileIOPermissions)
+ AssertExtensions.ThrowsAny<NotSupportedException, ArgumentException>(() => Path.GetFullPath(path));
+ }
+
+ [Theory,
+ MemberData(nameof(TestData_Wildcards)),
+ MemberData(nameof(TestData_ExtendedWildcards))]
+ public void GetFullPath_Wildcards(char wildcard)
+ {
+ AssertExtensions.Throws<ArgumentException>("path", null, () => Path.GetFullPath("test" + wildcard + "ing"));
+ }
+
+ [Theory, MemberData(nameof(TestData_InvalidUnc))]
+ public void GetFullPath_UNC_Invalid(string invalidPath)
+ {
+ AssertExtensions.Throws<ArgumentException>(null, () => Path.GetFullPath(invalidPath));
+ }
+ }
+}
diff --git a/src/System.Runtime.Extensions/tests/System/Math.cs b/src/System.Runtime.Extensions/tests/System/Math.cs
index 8f3dc1bab5..70211b3fca 100644
--- a/src/System.Runtime.Extensions/tests/System/Math.cs
+++ b/src/System.Runtime.Extensions/tests/System/Math.cs
@@ -470,10 +470,13 @@ namespace System.Tests
[Theory]
[InlineData( double.NegativeInfinity, double.NaN, 0.0)]
+ [InlineData(-3.1415926535897932, double.NaN, 0.0)] // value: -(pi)
+ [InlineData(-2.7182818284590452, double.NaN, 0.0)] // value: -(e)
+ [InlineData(-1.4142135623730950, double.NaN, 0.0)] // value: -(sqrt(2))
[InlineData(-1.0, 3.1415926535897932, CrossPlatformMachineEpsilon * 10)] // expected: (pi)
[InlineData(-0.91173391478696510, 2.7182818284590452, CrossPlatformMachineEpsilon * 10)] // expected: (e)
[InlineData(-0.66820151019031295, 2.3025850929940457, CrossPlatformMachineEpsilon * 10)] // expected: (ln(10))
- [InlineData( 0.0, 1.5707963267948966, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2)
+ [InlineData(-0.0, 1.5707963267948966, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2)
[InlineData( double.NaN, double.NaN, 0.0)]
[InlineData( 0.0, 1.5707963267948966, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2)
[InlineData( 0.12775121753523991, 1.4426950408889634, CrossPlatformMachineEpsilon * 10)] // expected: (log2(e))
@@ -487,6 +490,9 @@ namespace System.Tests
[InlineData( 0.90716712923909839, 0.43429448190325183, CrossPlatformMachineEpsilon)] // expected: (log10(e))
[InlineData( 0.94976571538163866, 0.31830988618379067, CrossPlatformMachineEpsilon)] // expected: (1 / pi)
[InlineData( 1.0, 0.0, 0.0 )]
+ [InlineData( 1.4142135623730950, double.NaN, 0.0)] // value: (sqrt(2))
+ [InlineData( 2.7182818284590452, double.NaN, 0.0)] // value: (e)
+ [InlineData( 3.1415926535897932, double.NaN, 0.0)] // value: (pi)
[InlineData( double.PositiveInfinity, double.NaN, 0.0 )]
public static void Acos(double value, double expectedResult, double allowedVariance)
{
@@ -495,6 +501,9 @@ namespace System.Tests
[Theory]
[InlineData( double.NegativeInfinity, double.NaN, 0.0)]
+ [InlineData(-3.1415926535897932, double.NaN, 0.0)] // value: -(pi)
+ [InlineData(-2.7182818284590452, double.NaN, 0.0)] // value: -(e)
+ [InlineData(-1.4142135623730950, double.NaN, 0.0)] // value: -(sqrt(2))
[InlineData(-1.0, -1.5707963267948966, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2)
[InlineData(-0.99180624439366372, -1.4426950408889634, CrossPlatformMachineEpsilon * 10)] // expected: -(log2(e))
[InlineData(-0.98776594599273553, -1.4142135623730950, CrossPlatformMachineEpsilon * 10)] // expected: -(sqrt(2))
@@ -524,6 +533,9 @@ namespace System.Tests
[InlineData( 0.98776594599273553, 1.4142135623730950, CrossPlatformMachineEpsilon * 10)] // expected: (sqrt(2))
[InlineData( 0.99180624439366372, 1.4426950408889634, CrossPlatformMachineEpsilon * 10)] // expected: (log2(e))
[InlineData( 1.0, 1.5707963267948966, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2)
+ [InlineData( 1.4142135623730950, double.NaN, 0.0)] // value: (sqrt(2))
+ [InlineData( 2.7182818284590452, double.NaN, 0.0)] // value: (e)
+ [InlineData( 3.1415926535897932, double.NaN, 0.0)] // value: (pi)
[InlineData( double.PositiveInfinity, double.NaN, 0.0)]
public static void Asin(double value, double expectedResult, double allowedVariance)
{
@@ -920,6 +932,12 @@ namespace System.Tests
[Theory]
[InlineData( double.NegativeInfinity, double.NaN, 0.0)]
+ [InlineData(-3.1415926535897932, double.NaN, 0.0)] // value: -(pi)
+ [InlineData(-2.7182818284590452, double.NaN, 0.0)] // value: -(e)
+ [InlineData(-1.4142135623730950, double.NaN, 0.0)] // value: -(sqrt(2))
+ [InlineData(-1.0, double.NaN, 0.0)]
+ [InlineData(-0.69314718055994531, double.NaN, 0.0)] // value: -(ln(2))
+ [InlineData(-0.43429448190325183, double.NaN, 0.0)] // value: -(log10(e))
[InlineData(-0.0, double.NegativeInfinity, 0.0)]
[InlineData( double.NaN, double.NaN, 0.0)]
[InlineData( 0.0, double.NegativeInfinity, 0.0)]
@@ -972,6 +990,12 @@ namespace System.Tests
[Theory]
[InlineData( double.NegativeInfinity, double.NaN, 0.0)]
+ [InlineData(-3.1415926535897932, double.NaN, 0.0)] // value: -(pi)
+ [InlineData(-2.7182818284590452, double.NaN, 0.0)] // value: -(e)
+ [InlineData(-1.4142135623730950, double.NaN, 0.0)] // value: -(sqrt(2))
+ [InlineData(-1.0, double.NaN, 0.0)]
+ [InlineData(-0.69314718055994531, double.NaN, 0.0)] // value: -(ln(2))
+ [InlineData(-0.43429448190325183, double.NaN, 0.0)] // value: -(log10(e))
[InlineData(-0.0, double.NegativeInfinity, 0.0)]
[InlineData( double.NaN, double.NaN, 0.0)]
[InlineData( 0.0, double.NegativeInfinity, 0.0)]
diff --git a/src/System.Runtime.Extensions/tests/System/MathF.netcoreapp.cs b/src/System.Runtime.Extensions/tests/System/MathF.netcoreapp.cs
index 958dc3806c..484aef174a 100644
--- a/src/System.Runtime.Extensions/tests/System/MathF.netcoreapp.cs
+++ b/src/System.Runtime.Extensions/tests/System/MathF.netcoreapp.cs
@@ -217,6 +217,9 @@ namespace System.Tests
[Theory]
[InlineData( float.NegativeInfinity, float.NaN, 0.0f)]
+ [InlineData(-3.14159265f, float.NaN, 0.0f)] // value: -(pi)
+ [InlineData(-2.71828183f, float.NaN, 0.0f)] // value: -(e)
+ [InlineData(-1.41421356f, float.NaN, 0.0f)] // value: -(sqrt(2))
[InlineData(-1.0f, 3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: (pi)
[InlineData(-0.911733915f, 2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: (e)
[InlineData(-0.668201510f, 2.30258509f, CrossPlatformMachineEpsilon * 10)] // expected: (ln(10))
@@ -234,6 +237,9 @@ namespace System.Tests
[InlineData( 0.907167129f, 0.434294482f, CrossPlatformMachineEpsilon)] // expected: (log10(e))
[InlineData( 0.949765715f, 0.318309886f, CrossPlatformMachineEpsilon)] // expected: (1 / pi)
[InlineData( 1.0f, 0.0f, 0.0f)]
+ [InlineData( 1.41421356f, float.NaN, 0.0f)] // value: (sqrt(2))
+ [InlineData( 2.71828183f, float.NaN, 0.0f)] // value: (e)
+ [InlineData( 3.14159265f, float.NaN, 0.0f)] // value: (pi)
[InlineData( float.PositiveInfinity, float.NaN, 0.0f)]
public static void Acos(float value, float expectedResult, float allowedVariance)
{
@@ -241,7 +247,42 @@ namespace System.Tests
}
[Theory]
+ [InlineData( float.NegativeInfinity, float.NaN, 0.0f)]
+ [InlineData(-3.14159265f, float.NaN, 0.0f)] // value: -(pi)
+ [InlineData(-2.71828183f, float.NaN, 0.0f)] // value: -(e)
+ [InlineData(-1.41421356f, float.NaN, 0.0f)] // value: -(sqrt(2))
+ [InlineData(-1.0f, float.NaN, 0.0f)]
+ [InlineData(-0.693147181f, float.NaN, 0.0f)] // value: -(ln(2))
+ [InlineData(-0.434294482f, float.NaN, 0.0f)] // value: -(log10(e))
+ [InlineData(-0.0f, float.NaN, 0.0f)]
+ [InlineData( float.NaN, float.NaN, 0.0f)]
+ [InlineData( 0.0f, float.NaN, 0.0f)]
+ [InlineData( 1.0f, 0.0f, CrossPlatformMachineEpsilon)]
+ [InlineData( 1.05108979f, 0.318309886f, CrossPlatformMachineEpsilon)] // expected: (1 / pi)
+ [InlineData( 1.09579746f, 0.434294482f, CrossPlatformMachineEpsilon)] // expected: (log10(e))
+ [InlineData( 1.20957949f, 0.636619772f, CrossPlatformMachineEpsilon)] // expected: (2 / pi)
+ [InlineData( 1.25f, 0.693147181f, CrossPlatformMachineEpsilon)] // expected: (ln(2))
+ [InlineData( 1.26059184f, 0.707106781f, CrossPlatformMachineEpsilon)] // expected: (1 / sqrt(2))
+ [InlineData( 1.32460909f, 0.785398163f, CrossPlatformMachineEpsilon)] // expected: (pi / 4)
+ [InlineData( 1.54308063f, 1.0, CrossPlatformMachineEpsilon * 10)]
+ [InlineData( 1.70710014f, 1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: (2 / sqrt(pi))
+ [InlineData( 2.17818356f, 1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: (sqrt(2))
+ [InlineData( 2.23418810f, 1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: (log2(e))
+ [InlineData( 2.50917848f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2)
+ [InlineData( 5.05f, 2.30258509f, CrossPlatformMachineEpsilon * 10)] // expected: (ln(10))
+ [InlineData( 7.61012514f, 2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: (e)
+ [InlineData( 11.5919533f, 3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: (pi)
+ [InlineData( float.PositiveInfinity, float.PositiveInfinity, 0.0f)]
+ public static void Acosh(float value, float expectedResult, float allowedVariance)
+ {
+ AssertEqual(expectedResult, MathF.Acosh(value), allowedVariance);
+ }
+
+ [Theory]
[InlineData( float.NegativeInfinity, float.NaN, 0.0f)]
+ [InlineData(-3.14159265f, float.NaN, 0.0f)] // value: -(pi)
+ [InlineData(-2.71828183f, float.NaN, 0.0f)] // value: -(e)
+ [InlineData(-1.41421356f, float.NaN, 0.0f)] // value: -(sqrt(2))
[InlineData(-1.0f, -1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2)
[InlineData(-0.991806244f, -1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: -(log2(e))
[InlineData(-0.987765946f, -1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: -(sqrt(2))
@@ -271,6 +312,9 @@ namespace System.Tests
[InlineData( 0.987765946f, 1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: (sqrt(2))
[InlineData( 0.991806244f, 1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: (log2(e))
[InlineData( 1.0f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2)
+ [InlineData( 1.41421356f, float.NaN, 0.0f)] // value: (sqrt(2))
+ [InlineData( 2.71828183f, float.NaN, 0.0f)] // value: (e)
+ [InlineData( 3.14159265f, float.NaN, 0.0f)] // value: (pi)
[InlineData( float.PositiveInfinity, float.NaN, 0.0f)]
public static void Asin(float value, float expectedResult, float allowedVariance)
{
@@ -278,6 +322,45 @@ namespace System.Tests
}
[Theory]
+ [InlineData( float.NegativeInfinity, float.NegativeInfinity, 0.0f)]
+ [InlineData(-11.5487394f, -3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi)
+ [InlineData(-7.54413710f, -2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: -(e)
+ [InlineData(-4.95f, -2.30258509f, CrossPlatformMachineEpsilon * 10)] // expected: -(ln(10))
+ [InlineData(-2.30129890f, -1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2)
+ [InlineData(-1.99789801f, -1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: -(log2(e))
+ [InlineData(-1.93506682f, -1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: -(sqrt(2))
+ [InlineData(-1.38354288f, -1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: -(2 / sqrt(pi))
+ [InlineData(-1.17520119f, -1.0f, CrossPlatformMachineEpsilon * 10)]
+ [InlineData(-0.868670961f, -0.785398163f, CrossPlatformMachineEpsilon)] // expected: -(pi / 4)
+ [InlineData(-0.767523145f, -0.707106781f, CrossPlatformMachineEpsilon)] // expected: -(1 / sqrt(2))
+ [InlineData(-0.75f, -0.693147181f, CrossPlatformMachineEpsilon)] // expected: -(ln(2))
+ [InlineData(-0.680501678f, -0.636619772f, CrossPlatformMachineEpsilon)] // expected: -(2 / pi)
+ [InlineData(-0.448075979f, -0.434294482f, CrossPlatformMachineEpsilon)] // expected: -(log10(e))
+ [InlineData(-0.323712439f, -0.318309886f, CrossPlatformMachineEpsilon)] // expected: -(1 / pi)
+ [InlineData(-0.0f, -0.0, 0.0f)]
+ [InlineData( float.NaN, float.NaN, 0.0f)]
+ [InlineData( 0.0f, 0.0, 0.0f)]
+ [InlineData( 0.323712439f, 0.318309886f, CrossPlatformMachineEpsilon)] // expected: (1 / pi)
+ [InlineData( 0.448075979f, 0.434294482f, CrossPlatformMachineEpsilon)] // expected: (log10(e))
+ [InlineData( 0.680501678f, 0.636619772f, CrossPlatformMachineEpsilon)] // expected: (2 / pi)
+ [InlineData( 0.75f, 0.693147181f, CrossPlatformMachineEpsilon)] // expected: (ln(2))
+ [InlineData( 0.767523145f, 0.707106781f, CrossPlatformMachineEpsilon)] // expected: (1 / sqrt(2))
+ [InlineData( 0.868670961f, 0.785398163f, CrossPlatformMachineEpsilon)] // expected: (pi / 4)
+ [InlineData( 1.17520119f, 1.0f, CrossPlatformMachineEpsilon * 10)]
+ [InlineData( 1.38354288f, 1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: (2 / sqrt(pi))
+ [InlineData( 1.93506682f, 1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: (sqrt(2))
+ [InlineData( 1.99789801f, 1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: (log2(e))
+ [InlineData( 2.30129890f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2)
+ [InlineData( 4.95f, 2.30258509f, CrossPlatformMachineEpsilon * 10)] // expected: (ln(10))
+ [InlineData( 7.54413710f, 2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: (e)
+ [InlineData( 11.5487394f, 3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: (pi)
+ [InlineData( float.PositiveInfinity, float.PositiveInfinity, 0.0f)]
+ public static void Asinh(float value, float expectedResult, float allowedVariance)
+ {
+ AssertEqual(expectedResult, MathF.Asinh(value), allowedVariance);
+ }
+
+ [Theory]
[InlineData( float.NegativeInfinity, -1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2)
[InlineData(-7.76357567f, -1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: -(log2(e))
[InlineData(-6.33411917f, -1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: -(sqrt(2))
@@ -432,6 +515,92 @@ namespace System.Tests
}
[Theory]
+ [InlineData( float.NegativeInfinity, float.NaN, 0.0f)]
+ [InlineData(-3.14159265f, float.NaN, 0.0f)] // value: -(pi)
+ [InlineData(-2.71828183f, float.NaN, 0.0f)] // value: -(e)
+ [InlineData(-1.41421356f, float.NaN, 0.0f)] // value: -(sqrt(2))
+ [InlineData(-1.0f, float.NegativeInfinity, CrossPlatformMachineEpsilon * 10)]
+ [InlineData(-0.996272076f, -3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi)
+ [InlineData(-0.991328916f, -2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: -(e)
+ [InlineData(-0.980198020f, -2.30258509f, CrossPlatformMachineEpsilon * 10)] // expected: -(ln(10))
+ [InlineData(-0.917152336f, -1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2)
+ [InlineData(-0.894238946f, -1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: -(log2(e))
+ [InlineData(-0.888385562f, -1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: -(sqrt(2))
+ [InlineData(-0.810463806f, -1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: -(2 / sqrt(pi))
+ [InlineData(-0.761594156f, -1.0f, CrossPlatformMachineEpsilon * 10)]
+ [InlineData(-0.655794203f, -0.785398163f, CrossPlatformMachineEpsilon)] // expected: -(pi / 4)
+ [InlineData(-0.608859365f, -0.707106781f, CrossPlatformMachineEpsilon)] // expected: -(1 / sqrt(2))
+ [InlineData(-0.6f, -0.693147181f, CrossPlatformMachineEpsilon)] // expected: -(ln(2))
+ [InlineData(-0.562593600f, -0.636619772f, CrossPlatformMachineEpsilon)] // expected: -(2 / pi)
+ [InlineData(-0.408904012f, -0.434294482f, CrossPlatformMachineEpsilon)] // expected: -(log10(e))
+ [InlineData(-0.307977913f, -0.318309886f, CrossPlatformMachineEpsilon)] // expected: -(1 / pi)
+ [InlineData(-0.0f, -0.0f, 0.0f)]
+ [InlineData( float.NaN, float.NaN, 0.0f)]
+ [InlineData( 0.0, 0.0f, 0.0f)]
+ [InlineData( 0.307977913f, 0.318309886f, CrossPlatformMachineEpsilon)] // expected: (1 / pi)
+ [InlineData( 0.408904012f, 0.434294482f, CrossPlatformMachineEpsilon)] // expected: (log10(e))
+ [InlineData( 0.562593600f, 0.636619772f, CrossPlatformMachineEpsilon)] // expected: (2 / pi)
+ [InlineData( 0.6f, 0.693147181f, CrossPlatformMachineEpsilon)] // expected: (ln(2))
+ [InlineData( 0.608859365f, 0.707106781f, CrossPlatformMachineEpsilon)] // expected: (1 / sqrt(2))
+ [InlineData( 0.655794203f, 0.785398163f, CrossPlatformMachineEpsilon)] // expected: (pi / 4)
+ [InlineData( 0.761594156f, 1.0f, CrossPlatformMachineEpsilon * 10)]
+ [InlineData( 0.810463806f, 1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: (2 / sqrt(pi))
+ [InlineData( 0.888385562f, 1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: (sqrt(2))
+ [InlineData( 0.894238946f, 1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: (log2(e))
+ [InlineData( 0.917152336f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2)
+ [InlineData( 0.980198020f, 2.30258509f, CrossPlatformMachineEpsilon * 10)] // expected: (ln(10))
+ [InlineData( 0.991328916f, 2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: (e)
+ [InlineData( 0.996272076f, 3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: (pi)
+ [InlineData( 1.0f, float.PositiveInfinity, 0.0f)]
+ [InlineData( 3.14159265f, float.NaN, 0.0f)] // value: (pi)
+ [InlineData( 2.71828183f, float.NaN, 0.0f)] // value: (e)
+ [InlineData( 1.41421356f, float.NaN, 0.0f)] // value: (sqrt(2))
+ [InlineData( float.PositiveInfinity, float.NaN, 0.0f)]
+ public static void Atanh(float value, float expectedResult, float allowedVariance)
+ {
+ AssertEqual(expectedResult, MathF.Atanh(value), allowedVariance);
+ }
+
+ [Theory]
+ [InlineData( float.NegativeInfinity, float.NegativeInfinity, 0.0f)]
+ [InlineData(-3.14159265f, -1.46459189f, CrossPlatformMachineEpsilon * 10)] // value: -(pi)
+ [InlineData(-2.71828183f, -1.39561243f, CrossPlatformMachineEpsilon * 10)] // value: -(e)
+ [InlineData(-2.30258509f, -1.32050048f, CrossPlatformMachineEpsilon * 10)] // value: -(ln(10))
+ [InlineData(-1.57079633f, -1.16244735f, CrossPlatformMachineEpsilon * 10)] // value: -(pi / 2)
+ [InlineData(-1.44269504f, -1.12994728f, CrossPlatformMachineEpsilon * 10)] // value: -(log2(e))
+ [InlineData(-1.41421356f, -1.12246205f, CrossPlatformMachineEpsilon * 10)] // value: -(sqrt(2))
+ [InlineData(-1.12837917f, -1.04108220f, CrossPlatformMachineEpsilon * 10)] // value: -(2 / sqrt(pi))
+ [InlineData(-1.0f, -1.0f, CrossPlatformMachineEpsilon * 10)]
+ [InlineData(-0.785398163f, -0.922635074f, CrossPlatformMachineEpsilon)] // value: -(pi / 4)
+ [InlineData(-0.707106781f, -0.890898718f, CrossPlatformMachineEpsilon)] // value: -(1 / sqrt(2))
+ [InlineData(-0.693147181f, -0.884997045f, CrossPlatformMachineEpsilon)] // value: -(ln(2))
+ [InlineData(-0.636619772f, -0.860254014f, CrossPlatformMachineEpsilon)] // value: -(2 / pi)
+ [InlineData(-0.434294482f, -0.757288631f, CrossPlatformMachineEpsilon)] // value: -(log10(e))
+ [InlineData(-0.318309886f, -0.682784063f, CrossPlatformMachineEpsilon)] // value: -(1 / pi)
+ [InlineData(-0.0f, -0.0f, 0.0f)]
+ [InlineData( float.NaN, float.NaN, 0.0f)]
+ [InlineData( 0.0f, 0.0f, 0.0f)]
+ [InlineData( 0.318309886f, 0.682784063f, CrossPlatformMachineEpsilon)] // value: (1 / pi)
+ [InlineData( 0.434294482f, 0.757288631f, CrossPlatformMachineEpsilon)] // value: (log10(e))
+ [InlineData( 0.636619772f, 0.860254014f, CrossPlatformMachineEpsilon)] // value: (2 / pi)
+ [InlineData( 0.693147181f, 0.884997045f, CrossPlatformMachineEpsilon)] // value: (ln(2))
+ [InlineData( 0.707106781f, 0.890898718f, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2))
+ [InlineData( 0.785398163f, 0.922635074f, CrossPlatformMachineEpsilon)] // value: (pi / 4)
+ [InlineData( 1.0f, 1.0f, CrossPlatformMachineEpsilon * 10)]
+ [InlineData( 1.12837917f, 1.04108220f, CrossPlatformMachineEpsilon * 10)] // value: (2 / sqrt(pi))
+ [InlineData( 1.41421356f, 1.12246205f, CrossPlatformMachineEpsilon * 10)] // value: (sqrt(2))
+ [InlineData( 1.44269504f, 1.12994728f, CrossPlatformMachineEpsilon * 10)] // value: (log2(e))
+ [InlineData( 1.57079633f, 1.16244735f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 2)
+ [InlineData( 2.30258509f, 1.32050048f, CrossPlatformMachineEpsilon * 10)] // value: (ln(10))
+ [InlineData( 2.71828183f, 1.39561243f, CrossPlatformMachineEpsilon * 10)] // value: (e)
+ [InlineData( 3.14159265f, 1.46459189f, CrossPlatformMachineEpsilon * 10)] // value: (pi)
+ [InlineData( float.PositiveInfinity, float.PositiveInfinity, 0.0f)]
+ public static void Cbrt(float value, float expectedResult, float allowedVariance)
+ {
+ AssertEqual(expectedResult, MathF.Cbrt(value), allowedVariance);
+ }
+
+ [Theory]
[InlineData(float.NegativeInfinity, float.NegativeInfinity, 0.0f)]
[InlineData(-3.14159265f, -3.0f, 0.0f)] // value: -(pi)
[InlineData(-2.71828183f, -2.0f, 0.0f)] // value: -(e)
@@ -643,6 +812,12 @@ namespace System.Tests
[Theory]
[InlineData( float.NegativeInfinity, float.NaN, 0.0f)]
+ [InlineData(-3.14159265f, float.NaN, 0.0f)] // value: -(pi)
+ [InlineData(-2.71828183f, float.NaN, 0.0f)] // value: -(e)
+ [InlineData(-1.41421356f, float.NaN, 0.0f)] // value: -(sqrt(2))
+ [InlineData(-1.0f, float.NaN, 0.0f)]
+ [InlineData(-0.693147181f, float.NaN, 0.0f)] // value: -(ln(2))
+ [InlineData(-0.434294482f, float.NaN, 0.0f)] // value: -(log10(e))
[InlineData(-0.0f, float.NegativeInfinity, 0.0f)]
[InlineData( float.NaN, float.NaN, 0.0f)]
[InlineData( 0.0f, float.NegativeInfinity, 0.0f)]
@@ -695,6 +870,12 @@ namespace System.Tests
[Theory]
[InlineData( float.NegativeInfinity, float.NaN, 0.0f)]
+ [InlineData(-3.14159265f, float.NaN, 0.0f)] // value: -(pi)
+ [InlineData(-2.71828183f, float.NaN, 0.0f)] // value: -(e)
+ [InlineData(-1.41421356f, float.NaN, 0.0f)] // value: -(sqrt(2))
+ [InlineData(-1.0f, float.NaN, 0.0f)]
+ [InlineData(-0.693147181f, float.NaN, 0.0f)] // value: -(ln(2))
+ [InlineData(-0.434294482f, float.NaN, 0.0f)] // value: -(log10(e))
[InlineData(-0.0f, float.NegativeInfinity, 0.0f)]
[InlineData( float.NaN, float.NaN, 0.0f)]
[InlineData( 0.0f, float.NegativeInfinity, 0.0f)]
diff --git a/src/System.Runtime.Extensions/tests/System/MathTests.netcoreapp.cs b/src/System.Runtime.Extensions/tests/System/MathTests.netcoreapp.cs
index f179214076..d62b026862 100644
--- a/src/System.Runtime.Extensions/tests/System/MathTests.netcoreapp.cs
+++ b/src/System.Runtime.Extensions/tests/System/MathTests.netcoreapp.cs
@@ -7,7 +7,6 @@ using Xunit;
namespace System.Tests
{
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot, "Math.Clamp is not in CoreRT yet.")]
public static partial class MathTests
{
public static IEnumerable<object[]> Clamp_UnsignedInt_TestData()
@@ -33,6 +32,163 @@ namespace System.Tests
}
[Theory]
+ [InlineData( double.NegativeInfinity, double.NaN, 0.0)]
+ [InlineData(-3.1415926535897932, double.NaN, 0.0)] // value: -(pi)
+ [InlineData(-2.7182818284590452, double.NaN, 0.0)] // value: -(e)
+ [InlineData(-1.4142135623730950, double.NaN, 0.0)] // value: -(sqrt(2))
+ [InlineData(-1.0, double.NaN, 0.0)]
+ [InlineData(-0.69314718055994531, double.NaN, 0.0)] // value: -(ln(2))
+ [InlineData(-0.43429448190325183, double.NaN, 0.0)] // value: -(log10(e))
+ [InlineData(-0.0, double.NaN, 0.0)]
+ [InlineData( double.NaN, double.NaN, 0.0)]
+ [InlineData( 0.0, double.NaN, 0.0)]
+ [InlineData( 1.0, 0.0, CrossPlatformMachineEpsilon)]
+ [InlineData( 1.0510897883672876, 0.31830988618379067, CrossPlatformMachineEpsilon)] // expected: (1 / pi)
+ [InlineData( 1.0957974645564909, 0.43429448190325183, CrossPlatformMachineEpsilon)] // expected: (log10(e))
+ [InlineData( 1.2095794864199787, 0.63661977236758134, CrossPlatformMachineEpsilon)] // expected: (2 / pi)
+ [InlineData( 1.25, 0.69314718055994531, CrossPlatformMachineEpsilon)] // expected: (ln(2))
+ [InlineData( 1.2605918365213561, 0.70710678118654752, CrossPlatformMachineEpsilon)] // expected: (1 / sqrt(2))
+ [InlineData( 1.3246090892520058, 0.78539816339744831, CrossPlatformMachineEpsilon)] // expected: (pi / 4)
+ [InlineData( 1.5430806348152438, 1.0, CrossPlatformMachineEpsilon * 10)]
+ [InlineData( 1.7071001431069344, 1.1283791670955126, CrossPlatformMachineEpsilon * 10)] // expected: (2 / sqrt(pi))
+ [InlineData( 2.1781835566085709, 1.4142135623730950, CrossPlatformMachineEpsilon * 10)] // expected: (sqrt(2))
+ [InlineData( 2.2341880974508023, 1.4426950408889634, CrossPlatformMachineEpsilon * 10)] // expected: (log2(e))
+ [InlineData( 2.5091784786580568, 1.5707963267948966, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2)
+ [InlineData( 5.05, 2.3025850929940457, CrossPlatformMachineEpsilon * 10)] // expected: (ln(10))
+ [InlineData( 7.6101251386622884, 2.7182818284590452, CrossPlatformMachineEpsilon * 10)] // expected: (e)
+ [InlineData( 11.591953275521521, 3.1415926535897932, CrossPlatformMachineEpsilon * 10)] // expected: (pi)
+ [InlineData( double.PositiveInfinity, double.PositiveInfinity, 0.0)]
+ public static void Acosh(double value, double expectedResult, double allowedVariance)
+ {
+ AssertEqual(expectedResult, Math.Acosh(value), allowedVariance);
+ }
+
+ [Theory]
+ [InlineData( double.NegativeInfinity, double.NegativeInfinity, 0.0)]
+ [InlineData(-11.548739357257748, -3.1415926535897932, CrossPlatformMachineEpsilon * 10)] // expected: -(pi)
+ [InlineData(-7.5441371028169758, -2.7182818284590452, CrossPlatformMachineEpsilon * 10)] // expected: -(e)
+ [InlineData(-4.95, -2.3025850929940457, CrossPlatformMachineEpsilon * 10)] // expected: -(ln(10))
+ [InlineData(-2.3012989023072949, -1.5707963267948966, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2)
+ [InlineData(-1.9978980091062796, -1.4426950408889634, CrossPlatformMachineEpsilon * 10)] // expected: -(log2(e))
+ [InlineData(-1.9350668221743567, -1.4142135623730950, CrossPlatformMachineEpsilon * 10)] // expected: -(sqrt(2))
+ [InlineData(-1.3835428792038633, -1.1283791670955126, CrossPlatformMachineEpsilon * 10)] // expected: -(2 / sqrt(pi))
+ [InlineData(-1.1752011936438015, -1, CrossPlatformMachineEpsilon * 10)]
+ [InlineData(-0.86867096148600961, -0.78539816339744831, CrossPlatformMachineEpsilon)] // expected: -(pi / 4)
+ [InlineData(-0.76752314512611633, -0.70710678118654752, CrossPlatformMachineEpsilon)] // expected: -(1 / sqrt(2))
+ [InlineData(-0.75, -0.69314718055994531, CrossPlatformMachineEpsilon)] // expected: -(ln(2))
+ [InlineData(-0.68050167815224332, -0.63661977236758134, CrossPlatformMachineEpsilon)] // expected: -(2 / pi)
+ [InlineData(-0.44807597941469025, -0.43429448190325183, CrossPlatformMachineEpsilon)] // expected: -(log10(e))
+ [InlineData(-0.32371243907207108, -0.31830988618379067, CrossPlatformMachineEpsilon)] // expected: -(1 / pi)
+ [InlineData(-0.0, -0.0, 0.0)]
+ [InlineData( double.NaN, double.NaN, 0.0)]
+ [InlineData( 0.0, 0.0, 0.0)]
+ [InlineData( 0.32371243907207108, 0.31830988618379067, CrossPlatformMachineEpsilon)] // expected: (1 / pi)
+ [InlineData( 0.44807597941469025, 0.43429448190325183, CrossPlatformMachineEpsilon)] // expected: (log10(e))
+ [InlineData( 0.68050167815224332, 0.63661977236758134, CrossPlatformMachineEpsilon)] // expected: (2 / pi)
+ [InlineData( 0.75, 0.69314718055994531, CrossPlatformMachineEpsilon)] // expected: (ln(2))
+ [InlineData( 0.76752314512611633, 0.70710678118654752, CrossPlatformMachineEpsilon)] // expected: (1 / sqrt(2))
+ [InlineData( 0.86867096148600961, 0.78539816339744831, CrossPlatformMachineEpsilon)] // expected: (pi / 4)
+ [InlineData( 1.1752011936438015, 1.0, CrossPlatformMachineEpsilon * 10)]
+ [InlineData( 1.3835428792038633, 1.1283791670955126, CrossPlatformMachineEpsilon * 10)] // expected: (2 / sqrt(pi))
+ [InlineData( 1.9350668221743567, 1.4142135623730950, CrossPlatformMachineEpsilon * 10)] // expected: (sqrt(2))
+ [InlineData( 1.9978980091062796, 1.4426950408889634, CrossPlatformMachineEpsilon * 10)] // expected: (log2(e))
+ [InlineData( 2.3012989023072949, 1.5707963267948966, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2)
+ [InlineData( 4.95, 2.3025850929940457, CrossPlatformMachineEpsilon * 10)] // expected: (ln(10))
+ [InlineData( 7.5441371028169758, 2.7182818284590452, CrossPlatformMachineEpsilon * 10)] // expected: (e)
+ [InlineData( 11.548739357257748, 3.1415926535897932, CrossPlatformMachineEpsilon * 10)] // expected: (pi)
+ [InlineData( double.PositiveInfinity, double.PositiveInfinity, 0.0)]
+ public static void Asinh(double value, double expectedResult, double allowedVariance)
+ {
+ AssertEqual(expectedResult, Math.Asinh(value), allowedVariance);
+ }
+
+ [Theory]
+ [InlineData( double.NegativeInfinity, double.NaN, 0.0)]
+ [InlineData(-3.1415926535897932, double.NaN, 0.0)] // value: -(pi)
+ [InlineData(-2.7182818284590452, double.NaN, 0.0)] // value: -(e)
+ [InlineData(-1.4142135623730950, double.NaN, 0.0)] // value: -(sqrt(2))
+ [InlineData(-1.0, double.NegativeInfinity, CrossPlatformMachineEpsilon * 10)]
+ [InlineData(-0.99627207622074994, -3.1415926535897932, CrossPlatformMachineEpsilon * 10)] // expected: -(pi)
+ [InlineData(-0.99132891580059984, -2.7182818284590452, CrossPlatformMachineEpsilon * 10)] // expected: -(e)
+ [InlineData(-0.98019801980198020, -2.3025850929940457, CrossPlatformMachineEpsilon * 10)] // expected: -(ln(10))
+ [InlineData(-0.91715233566727435, -1.5707963267948966, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2)
+ [InlineData(-0.89423894585503855, -1.4426950408889634, CrossPlatformMachineEpsilon * 10)] // expected: -(log2(e))
+ [InlineData(-0.88838556158566054, -1.4142135623730950, CrossPlatformMachineEpsilon * 10)] // expected: -(sqrt(2))
+ [InlineData(-0.81046380599898809, -1.1283791670955126, CrossPlatformMachineEpsilon * 10)] // expected: -(2 / sqrt(pi))
+ [InlineData(-0.76159415595576489, -1.0, CrossPlatformMachineEpsilon * 10)]
+ [InlineData(-0.65579420263267244, -0.78539816339744831, CrossPlatformMachineEpsilon)] // expected: -(pi / 4)
+ [InlineData(-0.60885936501391381, -0.70710678118654752, CrossPlatformMachineEpsilon)] // expected: -(1 / sqrt(2))
+ [InlineData(-0.6, -0.69314718055994531, CrossPlatformMachineEpsilon)] // expected: -(ln(2))
+ [InlineData(-0.56259360033158334, -0.63661977236758134, CrossPlatformMachineEpsilon)] // expected: -(2 / pi)
+ [InlineData(-0.40890401183401433, -0.43429448190325183, CrossPlatformMachineEpsilon)] // expected: -(log10(e))
+ [InlineData(-0.30797791269089433, -0.31830988618379067, CrossPlatformMachineEpsilon)] // expected: -(1 / pi)
+ [InlineData(-0.0, -0.0, 0.0)]
+ [InlineData( double.NaN, double.NaN, 0.0)]
+ [InlineData( 0.0, 0.0, 0.0)]
+ [InlineData( 0.30797791269089433, 0.31830988618379067, CrossPlatformMachineEpsilon)] // expected: (1 / pi)
+ [InlineData( 0.40890401183401433, 0.43429448190325183, CrossPlatformMachineEpsilon)] // expected: (log10(e))
+ [InlineData( 0.56259360033158334, 0.63661977236758134, CrossPlatformMachineEpsilon)] // expected: (2 / pi)
+ [InlineData( 0.6, 0.69314718055994531, CrossPlatformMachineEpsilon)] // expected: (ln(2))
+ [InlineData( 0.60885936501391381, 0.70710678118654752, CrossPlatformMachineEpsilon)] // expected: (1 / sqrt(2))
+ [InlineData( 0.65579420263267244, 0.78539816339744831, CrossPlatformMachineEpsilon)] // expected: (pi / 4)
+ [InlineData( 0.76159415595576489, 1.0, CrossPlatformMachineEpsilon * 10)]
+ [InlineData( 0.81046380599898809, 1.1283791670955126, CrossPlatformMachineEpsilon * 10)] // expected: (2 / sqrt(pi))
+ [InlineData( 0.88838556158566054, 1.4142135623730950, CrossPlatformMachineEpsilon * 10)] // expected: (sqrt(2))
+ [InlineData( 0.89423894585503855, 1.4426950408889634, CrossPlatformMachineEpsilon * 10)] // expected: (log2(e))
+ [InlineData( 0.91715233566727435, 1.5707963267948966, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2)
+ [InlineData( 0.98019801980198020, 2.3025850929940457, CrossPlatformMachineEpsilon * 10)] // expected: (ln(10))
+ [InlineData( 0.99132891580059984, 2.7182818284590452, CrossPlatformMachineEpsilon * 10)] // expected: (e)
+ [InlineData( 0.99627207622074994, 3.1415926535897932, CrossPlatformMachineEpsilon * 10)] // expected: (pi)
+ [InlineData( 1.0, double.PositiveInfinity, 0.0)]
+ [InlineData( 1.4142135623730950, double.NaN, 0.0)] // value: (sqrt(2))
+ [InlineData( 2.7182818284590452, double.NaN, 0.0)] // value: (e)
+ [InlineData( 3.1415926535897932, double.NaN, 0.0)] // value: (pi)
+ [InlineData( double.PositiveInfinity, double.NaN, 0.0)]
+ public static void Atanh(double value, double expectedResult, double allowedVariance)
+ {
+ AssertEqual(expectedResult, Math.Atanh(value), allowedVariance);
+ }
+
+ [Theory]
+ [InlineData( double.NegativeInfinity, double.NegativeInfinity, 0.0)]
+ [InlineData(-3.1415926535897932, -1.4645918875615233, CrossPlatformMachineEpsilon * 10)] // value: -(pi)
+ [InlineData(-2.7182818284590452, -1.3956124250860895, CrossPlatformMachineEpsilon * 10)] // value: -(e)
+ [InlineData(-2.3025850929940457, -1.3205004784536852, CrossPlatformMachineEpsilon * 10)] // value: -(ln(10))
+ [InlineData(-1.5707963267948966, -1.1624473515096265, CrossPlatformMachineEpsilon * 10)] // value: -(pi / 2)
+ [InlineData(-1.4426950408889634, -1.1299472763373901, CrossPlatformMachineEpsilon * 10)] // value: -(log2(e))
+ [InlineData(-1.4142135623730950, -1.1224620483093730, CrossPlatformMachineEpsilon * 10)] // value: -(sqrt(2))
+ [InlineData(-1.1283791670955126, -1.0410821966965807, CrossPlatformMachineEpsilon * 10)] // value: -(2 / sqrt(pi))
+ [InlineData(-1.0, -1.0, CrossPlatformMachineEpsilon * 10)]
+ [InlineData(-0.78539816339744831, -0.92263507432201421, CrossPlatformMachineEpsilon)] // value: -(pi / 4)
+ [InlineData(-0.70710678118654752, -0.89089871814033930, CrossPlatformMachineEpsilon)] // value: -(1 / sqrt(2))
+ [InlineData(-0.69314718055994531, -0.88499704450051772, CrossPlatformMachineEpsilon)] // value: -(ln(2))
+ [InlineData(-0.63661977236758134, -0.86025401382809963, CrossPlatformMachineEpsilon)] // value: -(2 / pi)
+ [InlineData(-0.43429448190325183, -0.75728863133090766, CrossPlatformMachineEpsilon)] // value: -(log10(e))
+ [InlineData(-0.31830988618379067, -0.68278406325529568, CrossPlatformMachineEpsilon)] // value: -(1 / pi)
+ [InlineData(-0.0, -0.0, 0.0)]
+ [InlineData( double.NaN, double.NaN, 0.0)]
+ [InlineData( 0.0, 0.0, 0.0)]
+ [InlineData( 0.31830988618379067, 0.68278406325529568, CrossPlatformMachineEpsilon)] // value: (1 / pi)
+ [InlineData( 0.43429448190325183, 0.75728863133090766, CrossPlatformMachineEpsilon)] // value: (log10(e))
+ [InlineData( 0.63661977236758134, 0.86025401382809963, CrossPlatformMachineEpsilon)] // value: (2 / pi)
+ [InlineData( 0.69314718055994531, 0.88499704450051772, CrossPlatformMachineEpsilon)] // value: (ln(2))
+ [InlineData( 0.70710678118654752, 0.89089871814033930, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2))
+ [InlineData( 0.78539816339744831, 0.92263507432201421, CrossPlatformMachineEpsilon)] // value: (pi / 4)
+ [InlineData( 1.0, 1.0, CrossPlatformMachineEpsilon * 10)]
+ [InlineData( 1.1283791670955126, 1.0410821966965807, CrossPlatformMachineEpsilon * 10)] // value: (2 / sqrt(pi))
+ [InlineData( 1.4142135623730950, 1.1224620483093730, CrossPlatformMachineEpsilon * 10)] // value: (sqrt(2))
+ [InlineData( 1.4426950408889634, 1.1299472763373901, CrossPlatformMachineEpsilon * 10)] // value: (log2(e))
+ [InlineData( 1.5707963267948966, 1.1624473515096265, CrossPlatformMachineEpsilon * 10)] // value: (pi / 2)
+ [InlineData( 2.3025850929940457, 1.3205004784536852, CrossPlatformMachineEpsilon * 10)] // value: (ln(10))
+ [InlineData( 2.7182818284590452, 1.3956124250860895, CrossPlatformMachineEpsilon * 10)] // value: (e)
+ [InlineData( 3.1415926535897932, 1.4645918875615233, CrossPlatformMachineEpsilon * 10)] // value: (pi)
+ [InlineData( double.PositiveInfinity, double.PositiveInfinity, 0.0)]
+ public static void Cbrt(double value, double expectedResult, double allowedVariance)
+ {
+ AssertEqual(expectedResult, Math.Cbrt(value), allowedVariance);
+ }
+
+ [Theory]
[MemberData(nameof(Clamp_SignedInt_TestData))]
public static void Clamp_SByte(sbyte value, sbyte min, sbyte max, sbyte expected)
{
diff --git a/src/System.Runtime.Extensions/tests/System/StringComparer.cs b/src/System.Runtime.Extensions/tests/System/StringComparer.cs
index f6e998ae2d..3ed12672b3 100644
--- a/src/System.Runtime.Extensions/tests/System/StringComparer.cs
+++ b/src/System.Runtime.Extensions/tests/System/StringComparer.cs
@@ -26,12 +26,24 @@ namespace System.Tests
VerifyComparer(StringComparer.OrdinalIgnoreCase, true);
}
+ [Fact]
+ [ActiveIssue(27098, TargetFrameworkMonikers.NetFramework)]
+ public static void TestOrdinal_EmbeddedNull_ReturnsDifferentHashCodes()
+ {
+ StringComparer sc = StringComparer.Ordinal;
+ Assert.NotEqual(sc.GetHashCode("\0AAAAAAAAA"), sc.GetHashCode("\0BBBBBBBBBBBB"));
+ sc = StringComparer.OrdinalIgnoreCase;
+ Assert.NotEqual(sc.GetHashCode("\0AAAAAAAAA"), sc.GetHashCode("\0BBBBBBBBBBBB"));
+ }
+
private static void VerifyComparer(StringComparer sc, bool ignoreCase)
{
String s1 = "Hello";
String s1a = "Hello";
String s1b = "HELLO";
String s2 = "There";
+ String aa = "\0AAAAAAAAA";
+ String bb = "\0BBBBBBBBBBBB";
Assert.True(sc.Equals(s1, s1a));
Assert.True(sc.Equals(s1, s1a));
@@ -52,6 +64,12 @@ namespace System.Tests
Assert.Equal(ignoreCase, sc.Equals(s1, s1b));
Assert.Equal(ignoreCase, ((IEqualityComparer)sc).Equals(s1, s1b));
+ Assert.NotEqual(0, ((IComparer)sc).Compare(aa, bb));
+ Assert.False(sc.Equals(aa, bb));
+ Assert.False(((IEqualityComparer)sc).Equals(aa, bb));
+ Assert.True(sc.Compare(aa, bb) < 0);
+ Assert.True(((IComparer)sc).Compare(aa, bb) < 0);
+
int result = sc.Compare(s1, s1b);
if (ignoreCase)
Assert.Equal(0, result);
diff --git a/src/System.Runtime.Extensions/tests/System/StringComparer.netcoreapp.cs b/src/System.Runtime.Extensions/tests/System/StringComparer.netcoreapp.cs
index 4b195dce9b..698b38f91b 100644
--- a/src/System.Runtime.Extensions/tests/System/StringComparer.netcoreapp.cs
+++ b/src/System.Runtime.Extensions/tests/System/StringComparer.netcoreapp.cs
@@ -14,13 +14,13 @@ namespace System.Tests
{
public static readonly object[][] FromComparison_TestData =
{
- // StringComparison StringComparer
- new object[] { StringComparison.CurrentCulture, StringComparer.CurrentCulture },
- new object[] { StringComparison.CurrentCultureIgnoreCase, StringComparer.CurrentCultureIgnoreCase },
- new object[] { StringComparison.InvariantCulture, StringComparer.InvariantCulture },
+ // StringComparison StringComparer
+ new object[] { StringComparison.CurrentCulture, StringComparer.CurrentCulture },
+ new object[] { StringComparison.CurrentCultureIgnoreCase, StringComparer.CurrentCultureIgnoreCase },
+ new object[] { StringComparison.InvariantCulture, StringComparer.InvariantCulture },
new object[] { StringComparison.InvariantCultureIgnoreCase, StringComparer.InvariantCultureIgnoreCase },
- new object[] { StringComparison.Ordinal, StringComparer.Ordinal },
- new object[] { StringComparison.OrdinalIgnoreCase, StringComparer.OrdinalIgnoreCase },
+ new object[] { StringComparison.Ordinal, StringComparer.Ordinal },
+ new object[] { StringComparison.OrdinalIgnoreCase, StringComparer.OrdinalIgnoreCase },
};
[Theory]
@@ -39,5 +39,72 @@ namespace System.Tests
AssertExtensions.Throws<ArgumentException>("comparisonType", () => StringComparer.FromComparison(minInvalid));
AssertExtensions.Throws<ArgumentException>("comparisonType", () => StringComparer.FromComparison(maxInvalid));
}
+
+ public static TheoryData<string, string, string, CompareOptions, bool> CreateFromCultureAndOptionsData => new TheoryData<string, string, string, CompareOptions, bool>
+ {
+ { "abcd", "ABCD", "en-US", CompareOptions.None, false},
+ { "latin i", "LATIN I", "en-US", CompareOptions.None, false},
+ { "turky \u0131", "TURKY I", "tr-TR", CompareOptions.None, false},
+ { "turky i", "TURKY \u0130", "tr-TR", CompareOptions.None, false},
+ { "abcd", "ABCD", "en-US", CompareOptions.IgnoreCase, true},
+ { "latin i", "LATIN I", "en-US", CompareOptions.IgnoreCase, true},
+ { "turky \u0131", "TURKY I", "tr-TR", CompareOptions.IgnoreCase, true},
+ { "turky i", "TURKY \u0130", "tr-TR", CompareOptions.IgnoreCase, true},
+ { "abcd", "ab cd", "en-US", CompareOptions.IgnoreSymbols, true },
+ { "abcd", "ab+cd", "en-US", CompareOptions.IgnoreSymbols, true },
+ { "abcd", "ab%cd", "en-US", CompareOptions.IgnoreSymbols, true },
+ { "abcd", "ab&cd", "en-US", CompareOptions.IgnoreSymbols, true },
+ { "abcd", "ab$cd", "en-US", CompareOptions.IgnoreSymbols, true },
+ { "abcd", "ab$cd", "en-US", CompareOptions.IgnoreSymbols, true },
+ { "a-bcd", "ab$cd", "en-US", CompareOptions.IgnoreSymbols, true },
+ { "abcd*", "ab$cd", "en-US", CompareOptions.IgnoreSymbols, true },
+ { "ab$dd", "ab$cd", "en-US", CompareOptions.IgnoreSymbols, false },
+ { "abcd", "ab$cd", "en-US", CompareOptions.IgnoreSymbols, true },
+ };
+
+ public static TheoryData<string, string, string, CompareOptions, bool> CreateFromCultureAndOptionsStringSortData => new TheoryData<string, string, string, CompareOptions, bool>
+ {
+ { "abcd", "abcd", "en-US", CompareOptions.StringSort, true },
+ { "abcd", "ABcd", "en-US", CompareOptions.StringSort, false },
+ };
+
+ [Theory]
+ [MemberData(nameof(CreateFromCultureAndOptionsData))]
+ [MemberData(nameof(CreateFromCultureAndOptionsStringSortData))]
+ public static void CreateFromCultureAndOptions(string actualString, string expectedString, string cultureName, CompareOptions options, bool result)
+ {
+ CultureInfo ci = CultureInfo.GetCultureInfo(cultureName);
+ StringComparer sc = StringComparer.Create(ci, options);
+
+ Assert.Equal(result, sc.Equals(actualString, expectedString));
+ Assert.Equal(result, sc.Equals((object)actualString, (object)expectedString));
+ }
+
+ [Theory]
+ [MemberData(nameof(CreateFromCultureAndOptionsData))]
+ public static void CreateFromCultureAndOptionsStringSort(string actualString, string expectedString, string cultureName, CompareOptions options, bool result)
+ {
+ CultureInfo ci = CultureInfo.GetCultureInfo(cultureName);
+ StringComparer sc = StringComparer.Create(ci, options);
+
+ if (result)
+ {
+ Assert.Equal(sc.GetHashCode(actualString), sc.GetHashCode(expectedString));
+ Assert.Equal(sc.GetHashCode((object)actualString), sc.GetHashCode((object)actualString));
+ }
+ else
+ {
+ Assert.NotEqual(sc.GetHashCode(actualString), sc.GetHashCode(expectedString));
+ Assert.NotEqual(sc.GetHashCode((object)actualString), sc.GetHashCode((object)expectedString));
+ }
+ }
+
+ [Fact]
+ public static void CreateFromCultureAndOptionsOrdinal()
+ {
+ CultureInfo ci = CultureInfo.GetCultureInfo("en-US");
+ Assert.Throws<ArgumentException>(() => StringComparer.Create(ci, CompareOptions.Ordinal));
+ Assert.Throws<ArgumentException>(() => StringComparer.Create(ci, CompareOptions.OrdinalIgnoreCase));
+ }
}
}
diff --git a/src/System.Runtime.Extensions/tests/TestHelpers.cs b/src/System.Runtime.Extensions/tests/TestHelpers.cs
new file mode 100644
index 0000000000..c6c35c9fe9
--- /dev/null
+++ b/src/System.Runtime.Extensions/tests/TestHelpers.cs
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using Xunit;
+
+namespace System
+{
+ public static class TestHelpers
+ {
+ public static TheoryData<T> Concat<T>(this IEnumerable<T> first, TheoryData<T> second)
+ {
+ TheoryData<T> data = new TheoryData<T>();
+ foreach (var item in first)
+ data.Add(item);
+ foreach (var item in second)
+ data.Add((T)item[0]);
+ return data;
+ }
+
+ public static TheoryData<T> Concat<T>(this TheoryData<T> first, TheoryData<T> second)
+ {
+ TheoryData<T> data = new TheoryData<T>();
+ foreach (var item in first)
+ data.Add((T)item[0]);
+ foreach (var item in second)
+ data.Add((T)item[0]);
+ return data;
+ }
+
+ // @todo: https://github.com/dotnet/corefx/issues/26894 - these emulate MemoryExtension apis that we removed. Clean up the callsites and remove this class.
+ public static ReadOnlySpan<T> AsReadOnlySpan<T>(this T[] array) => new ReadOnlySpan<T>(array);
+ }
+}
diff --git a/src/System.Runtime.InteropServices.RuntimeInformation/tests/DescriptionNameTests.cs b/src/System.Runtime.InteropServices.RuntimeInformation/tests/DescriptionNameTests.cs
index 4432b6850b..f89b9bfa18 100644
--- a/src/System.Runtime.InteropServices.RuntimeInformation/tests/DescriptionNameTests.cs
+++ b/src/System.Runtime.InteropServices.RuntimeInformation/tests/DescriptionNameTests.cs
@@ -21,8 +21,10 @@ namespace System.Runtime.InteropServices.RuntimeInformationTests
string osa = RuntimeInformation.OSArchitecture.ToString();
string pra = RuntimeInformation.ProcessArchitecture.ToString();
string frd = RuntimeInformation.FrameworkDescription.Trim();
+ string lcr = PlatformDetection.LibcRelease;
+ string lcv = PlatformDetection.LibcVersion;
- Console.WriteLine($@"{dvs} OS={osd} OSVer={osv} OSArch={osa} Arch={pra} Framework={frd}");
+ Console.WriteLine($@"{dvs} OS={osd} OSVer={osv} OSArch={osa} Arch={pra} Framework={frd} LibcRelease={lcr} LibcVersion={lcv}");
}
[Fact]
diff --git a/src/System.Runtime.InteropServices/src/System/Runtime/InteropServices/ComTypes/IDataObject.cs b/src/System.Runtime.InteropServices/src/System/Runtime/InteropServices/ComTypes/IDataObject.cs
index 33e8c79164..c41c04876d 100644
--- a/src/System.Runtime.InteropServices/src/System/Runtime/InteropServices/ComTypes/IDataObject.cs
+++ b/src/System.Runtime.InteropServices/src/System/Runtime/InteropServices/ComTypes/IDataObject.cs
@@ -4,17 +4,85 @@
namespace System.Runtime.InteropServices.ComTypes
{
+ /// <devdoc>
+ /// The IDataObject interface specifies methods that enable data transfer
+ /// and notification of changes in data. Data transfer methods specify
+ /// the format of the transferred data along with the medium through
+ /// which the data is to be transferred. Optionally, the data can be
+ /// rendered for a specific target device. In addition to methods for
+ /// retrieving and storing data, the IDataObject interface specifies
+ /// methods for enumerating available formats and managing connections
+ /// to advisory sinks for handling change notifications.
+ /// </devdoc>
[CLSCompliant(false)]
- public interface IDataObject
- {
- int DAdvise(ref FORMATETC pFormatetc, ADVF advf, IAdviseSink adviseSink, out int connection);
+ [ComImport()]
+ [Guid("0000010E-0000-0000-C000-000000000046")]
+ [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
+ public interface IDataObject {
+
+ /// <devdoc>
+ /// Called by a data consumer to obtain data from a source data object.
+ /// The GetData method renders the data described in the specified FORMATETC
+ /// structure and transfers it through the specified STGMEDIUM structure.
+ /// The caller then assumes responsibility for releasing the STGMEDIUM structure.
+ /// </devdoc>
+ void GetData([In] ref FORMATETC format, out STGMEDIUM medium);
+
+ /// <devdoc>
+ /// Called by a data consumer to obtain data from a source data object.
+ /// This method differs from the GetData method in that the caller must
+ /// allocate and free the specified storage medium.
+ /// </devdoc>
+ void GetDataHere([In] ref FORMATETC format, ref STGMEDIUM medium);
+
+ /// <devdoc>
+ /// Determines whether the data object is capable of rendering the data
+ /// described in the FORMATETC structure. Objects attempting a paste or
+ /// drop operation can call this method before calling IDataObject::GetData
+ /// to get an indication of whether the operation may be successful.
+ /// </devdoc>
+ [PreserveSig]
+ int QueryGetData([In] ref FORMATETC format);
+
+ /// <devdoc>
+ /// Provides a standard FORMATETC structure that is logically equivalent to one that is more
+ /// complex. You use this method to determine whether two different
+ /// FORMATETC structures would return the same data, removing the need
+ /// for duplicate rendering.
+ /// </devdoc>
+ [PreserveSig]
+ int GetCanonicalFormatEtc([In] ref FORMATETC formatIn, out FORMATETC formatOut);
+
+ /// <devdoc>
+ /// Called by an object containing a data source to transfer data to
+ /// the object that implements this method.
+ /// </devdoc>
+ void SetData([In] ref FORMATETC formatIn, [In] ref STGMEDIUM medium, [MarshalAs(UnmanagedType.Bool)] bool release);
+
+ /// <devdoc>
+ /// Creates an object for enumerating the FORMATETC structures for a
+ /// data object. These structures are used in calls to IDataObject::GetData
+ /// or IDataObject::SetData.
+ /// </devdoc>
+ IEnumFORMATETC EnumFormatEtc(DATADIR direction);
+
+ /// <devdoc>
+ /// Called by an object supporting an advise sink to create a connection between
+ /// a data object and the advise sink. This enables the advise sink to be
+ /// notified of changes in the data of the object.
+ /// </devdoc>
+ [PreserveSig]
+ int DAdvise([In] ref FORMATETC pFormatetc, ADVF advf, IAdviseSink adviseSink, out int connection);
+
+ /// <devdoc>
+ /// Destroys a notification connection that had been previously set up.
+ /// </devdoc>
void DUnadvise(int connection);
+
+ /// <devdoc>
+ /// Creates an object that can be used to enumerate the current advisory connections.
+ /// </devdoc>
+ [PreserveSig]
int EnumDAdvise(out IEnumSTATDATA enumAdvise);
- IEnumFORMATETC EnumFormatEtc(DATADIR direction);
- int GetCanonicalFormatEtc(ref FORMATETC formatIn, out FORMATETC formatOut);
- void GetData(ref FORMATETC format, out STGMEDIUM medium);
- void GetDataHere(ref FORMATETC format, ref STGMEDIUM medium);
- int QueryGetData(ref FORMATETC format);
- void SetData(ref FORMATETC formatIn, ref STGMEDIUM medium, bool release);
}
}
diff --git a/src/System.Runtime.InteropServices/src/System/Runtime/InteropServices/ComTypes/IEnumSTATDATA.cs b/src/System.Runtime.InteropServices/src/System/Runtime/InteropServices/ComTypes/IEnumSTATDATA.cs
index 27f127a399..1c05186040 100644
--- a/src/System.Runtime.InteropServices/src/System/Runtime/InteropServices/ComTypes/IEnumSTATDATA.cs
+++ b/src/System.Runtime.InteropServices/src/System/Runtime/InteropServices/ComTypes/IEnumSTATDATA.cs
@@ -4,12 +4,46 @@
namespace System.Runtime.InteropServices.ComTypes
{
- [CLSCompliant(false)]
+ /// <devdoc>
+ /// The IEnumSTATDATA interface is used to enumerate through an array of
+ /// STATDATA structures, which contain advisory connection information for
+ /// a data object. IEnumSTATDATA has the same methods as all enumerator
+ /// interfaces: Next, Skip, Reset, and Clone.
+ /// </devdoc>
+ [ComImport()]
+ [Guid("00000103-0000-0000-C000-000000000046")]
+ [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IEnumSTATDATA
{
- void Clone(out IEnumSTATDATA newEnum);
- int Next(int celt, STATDATA[] rgelt, int[] pceltFetched);
- int Reset();
+
+ /// <devdoc>
+ /// Retrieves the next celt items in the enumeration sequence. If there are
+ /// fewer than the requested number of elements left in the sequence, it
+ /// retrieves the remaining elements. The number of elements actually
+ /// retrieved is returned through pceltFetched (unless the caller passed
+ /// in NULL for that parameter).
+ /// </devdoc>
+ [PreserveSig]
+ int Next(int celt, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] STATDATA[] rgelt, [Out, MarshalAs(UnmanagedType.LPArray, SizeConst=1)] int[] pceltFetched);
+
+ /// <devdoc>
+ /// Skips over the next specified number of elements in the enumeration sequence.
+ /// </devdoc>
+ [PreserveSig]
int Skip(int celt);
+
+ /// <devdoc>
+ /// Resets the enumeration sequence to the beginning.
+ /// </devdoc>
+ [PreserveSig]
+ int Reset();
+
+ /// <devdoc>
+ /// Creates another enumerator that contains the same enumeration state as
+ /// the current one. Using this function, a client can record a particular
+ /// point in the enumeration sequence and then return to that point at a
+ /// later time. The new enumerator supports the same interface as the original one.
+ /// </devdoc>
+ void Clone(out IEnumSTATDATA newEnum);
}
}
diff --git a/src/System.Runtime.Intrinsics/System.Runtime.Intrinsics.sln b/src/System.Runtime.Intrinsics.Experimental/System.Runtime.Intrinsics.Experimental.sln
index 16efecee03..ef61ead4a2 100644
--- a/src/System.Runtime.Intrinsics/System.Runtime.Intrinsics.sln
+++ b/src/System.Runtime.Intrinsics.Experimental/System.Runtime.Intrinsics.Experimental.sln
@@ -2,12 +2,12 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Runtime.Intrinsics", "src\System.Runtime.Intrinsics.csproj", "{543FBFE5-E9E4-4631-8242-911A707FE818}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Runtime.Intrinsics.Experimental", "src\System.Runtime.Intrinsics.Experimental.csproj", "{543FBFE5-E9E4-4631-8242-911A707FE818}"
ProjectSection(ProjectDependencies) = postProject
{4074AF8C-8C65-486C-960E-F45DAAB0BE0D} = {4074AF8C-8C65-486C-960E-F45DAAB0BE0D}
EndProjectSection
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Runtime.Intrinsics", "ref\System.Runtime.Intrinsics.csproj", "{4074AF8C-8C65-486C-960E-F45DAAB0BE0D}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Runtime.Intrinsics.Experimental", "ref\System.Runtime.Intrinsics.Experimental.csproj", "{4074AF8C-8C65-486C-960E-F45DAAB0BE0D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E107E9C1-E893-4E87-987E-04EF0DCEAEFD}"
EndProject
diff --git a/src/System.Runtime.Intrinsics.Experimental/dir.props b/src/System.Runtime.Intrinsics.Experimental/dir.props
new file mode 100644
index 0000000000..fbbc9a2ce3
--- /dev/null
+++ b/src/System.Runtime.Intrinsics.Experimental/dir.props
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\dir.props" />
+ <PropertyGroup>
+ <AssemblyVersion>4.0.0.0</AssemblyVersion>
+ <AssemblyKey>Open</AssemblyKey>
+ <!-- DO NOT ship this as stable. It contains preview-only APIs that will be stable in a future version. -->
+ <BlockStable>true</BlockStable>
+ </PropertyGroup>
+</Project>
diff --git a/src/System.Runtime.Intrinsics.Experimental/pkg/System.Runtime.Intrinsics.Experimental.pkgproj b/src/System.Runtime.Intrinsics.Experimental/pkg/System.Runtime.Intrinsics.Experimental.pkgproj
new file mode 100644
index 0000000000..b8ebbcce2d
--- /dev/null
+++ b/src/System.Runtime.Intrinsics.Experimental/pkg/System.Runtime.Intrinsics.Experimental.pkgproj
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <ItemGroup>
+ <ProjectReference Include="..\ref\System.Runtime.Intrinsics.Experimental.csproj">
+ <SupportedFramework>netcoreapp2.1</SupportedFramework>
+ </ProjectReference>
+ <ProjectReference Include="..\src\System.Runtime.Intrinsics.Experimental.csproj" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/src/System.Runtime.Intrinsics/ref/Configurations.props b/src/System.Runtime.Intrinsics.Experimental/ref/Configurations.props
index 2845c11c54..2845c11c54 100644
--- a/src/System.Runtime.Intrinsics/ref/Configurations.props
+++ b/src/System.Runtime.Intrinsics.Experimental/ref/Configurations.props
diff --git a/src/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.csproj b/src/System.Runtime.Intrinsics.Experimental/ref/System.Runtime.Intrinsics.Experimental.csproj
index 78a1f4b8fd..f699e7a679 100644
--- a/src/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.csproj
+++ b/src/System.Runtime.Intrinsics.Experimental/ref/System.Runtime.Intrinsics.Experimental.csproj
@@ -9,10 +9,10 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
<ItemGroup>
- <Compile Include="System.Runtime.Intrinsics.X86.cs" />
+ <Compile Include="System.Runtime.Intrinsics.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\System.Runtime\ref\System.Runtime.csproj" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.X86.cs b/src/System.Runtime.Intrinsics.Experimental/ref/System.Runtime.Intrinsics.cs
index 0f3f24effb..c4426c7b23 100644
--- a/src/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.X86.cs
+++ b/src/System.Runtime.Intrinsics.Experimental/ref/System.Runtime.Intrinsics.cs
@@ -9,30 +9,202 @@ using System.Runtime.InteropServices;
namespace System.Runtime.Intrinsics
{
+ [StructLayout(LayoutKind.Sequential, Size = 8)]
+ public struct Vector64<T> where T : struct
+ {
+ private int _dummy;
+ }
[StructLayout(LayoutKind.Sequential, Size = 16)]
- public struct Vector128<T> where T : struct {}
+ public struct Vector128<T> where T : struct
+ {
+ private int _dummy;
+ }
[StructLayout(LayoutKind.Sequential, Size = 32)]
- public struct Vector256<T> where T : struct {}
+ public struct Vector256<T> where T : struct
+ {
+ private int _dummy;
+ }
}
-
-namespace System.Runtime.Intrinsics.X86
+namespace System.Runtime.Intrinsics.Arm.Arm64
{
- public static class Aes
+ public static class Aes
{
public static bool IsSupported { get { throw null; } }
- public static Vector128<sbyte> Decrypt(Vector128<sbyte> value, Vector128<sbyte> roundKey) { throw null; }
public static Vector128<byte> Decrypt(Vector128<byte> value, Vector128<byte> roundKey) { throw null; }
- public static Vector128<sbyte> DecryptLast(Vector128<sbyte> value, Vector128<sbyte> roundKey) { throw null; }
- public static Vector128<byte> DecryptLast(Vector128<byte> value, Vector128<byte> roundKey) { throw null; }
- public static Vector128<sbyte> Encrypt(Vector128<sbyte> value, Vector128<sbyte> roundKey) { throw null; }
public static Vector128<byte> Encrypt(Vector128<byte> value, Vector128<byte> roundKey) { throw null; }
- public static Vector128<sbyte> EncryptLast(Vector128<sbyte> value, Vector128<sbyte> roundKey) { throw null; }
- public static Vector128<byte> EncryptLast(Vector128<byte> value, Vector128<byte> roundKey) { throw null; }
- public static Vector128<sbyte> InvisibleMixColumn(Vector128<sbyte> value) { throw null; }
- public static Vector128<byte> InvisibleMixColumn(Vector128<byte> value) { throw null; }
- public static Vector128<sbyte> KeygenAssist(Vector128<sbyte> value, byte control) { throw null; }
- public static Vector128<byte> KeygenAssist(Vector128<byte> value, byte control) { throw null; }
+ public static Vector128<byte> MixColumns(Vector128<byte> value) { throw null; }
+ public static Vector128<byte> InverseMixColumns(Vector128<byte> value) { throw null; }
+ }
+ public static class Base
+ {
+ public static bool IsSupported { get { throw null; } }
+ public static int LeadingSignCount(int value) { throw null; }
+ public static int LeadingSignCount(long value) { throw null; }
+ public static int LeadingZeroCount(int value) { throw null; }
+ public static int LeadingZeroCount(uint value) { throw null; }
+ public static int LeadingZeroCount(long value) { throw null; }
+ public static int LeadingZeroCount(ulong value) { throw null; }
+ }
+ public static class Sha1
+ {
+ public static bool IsSupported { get { throw null; } }
+ public static Vector128<uint> HashChoose(Vector128<uint> hash_abcd, uint hash_e, Vector128<uint>wk) { throw null; }
+ public static Vector128<uint> HashMajority(Vector128<uint> hash_abcd, uint hash_e, Vector128<uint>wk) { throw null; }
+ public static Vector128<uint> HashParity(Vector128<uint> hash_abcd, uint hash_e, Vector128<uint>wk) { throw null; }
+ public static uint FixedRotate(uint hash_e) { throw null; }
+ public static Vector128<uint> SchedulePart1(Vector128<uint> w0_3, Vector128<uint> w4_7, Vector128<uint> w8_11) { throw null; }
+ public static Vector128<uint> SchedulePart2(Vector128<uint> tw0_3, Vector128<uint> w12_15) { throw null; }
+ }
+ public static class Sha256
+ {
+ public static bool IsSupported { get { throw null; } }
+ public static Vector128<uint> HashLower(Vector128<uint> hash_abcd, Vector128<uint> hash_efgh, Vector128<uint> wk) { throw null; }
+ public static Vector128<uint> HashUpper(Vector128<uint> hash_efgh, Vector128<uint> hash_abcd, Vector128<uint> wk) { throw null; }
+ public static Vector128<uint> SchedulePart1(Vector128<uint> w0_3, Vector128<uint> w4_7) { throw null; }
+ public static Vector128<uint> SchedulePart2(Vector128<uint> w0_3, Vector128<uint> w8_11, Vector128<uint> w12_15) { throw null; }
+ }
+ public static class Simd
+ {
+ public static bool IsSupported { get { throw null; } }
+ public static Vector64<byte> Abs(Vector64<sbyte> value) { throw null; }
+ public static Vector64<ushort> Abs(Vector64<short> value) { throw null; }
+ public static Vector64<uint> Abs(Vector64<int> value) { throw null; }
+ public static Vector64<float> Abs(Vector64<float> value) { throw null; }
+ public static Vector128<byte> Abs(Vector128<sbyte> value) { throw null; }
+ public static Vector128<ushort> Abs(Vector128<short> value) { throw null; }
+ public static Vector128<uint> Abs(Vector128<int> value) { throw null; }
+ public static Vector128<ulong> Abs(Vector128<long> value) { throw null; }
+ public static Vector128<float> Abs(Vector128<float> value) { throw null; }
+ public static Vector128<double> Abs(Vector128<double> value) { throw null; }
+ public static Vector64<T> Add<T>(Vector64<T> left, Vector64<T> right) where T : struct { throw null; }
+ public static Vector128<T> Add<T>(Vector128<T> left, Vector128<T> right) where T : struct { throw null; }
+ public static Vector64<T> And<T>(Vector64<T> left, Vector64<T> right) where T : struct { throw null; }
+ public static Vector128<T> And<T>(Vector128<T> left, Vector128<T> right) where T : struct { throw null; }
+ public static Vector64<T> AndNot<T>(Vector64<T> left, Vector64<T> right) where T : struct { throw null; }
+ public static Vector128<T> AndNot<T>(Vector128<T> left, Vector128<T> right) where T : struct { throw null; }
+ public static Vector64<T> BitwiseSelect<T>(Vector64<T> sel, Vector64<T> left, Vector64<T> right) where T : struct { throw null; }
+ public static Vector128<T> BitwiseSelect<T>(Vector128<T> sel, Vector128<T> left, Vector128<T> right) where T : struct { throw null; }
+ public static Vector64<T> CompareEqual<T>(Vector64<T> left, Vector64<T> right) where T : struct { throw null; }
+ public static Vector128<T> CompareEqual<T>(Vector128<T> left, Vector128<T> right) where T : struct { throw null; }
+ public static Vector64<T> CompareEqualZero<T>(Vector64<T> value) where T : struct { throw null; }
+ public static Vector128<T> CompareEqualZero<T>(Vector128<T> value) where T : struct { throw null; }
+ public static Vector64<T> CompareGreaterThan<T>(Vector64<T> left, Vector64<T> right) where T : struct { throw null; }
+ public static Vector128<T> CompareGreaterThan<T>(Vector128<T> left, Vector128<T> right) where T : struct { throw null; }
+ public static Vector64<T> CompareGreaterThanZero<T>(Vector64<T> value) where T : struct { throw null; }
+ public static Vector128<T> CompareGreaterThanZero<T>(Vector128<T> value) where T : struct { throw null; }
+ public static Vector64<T> CompareGreaterThanOrEqual<T>(Vector64<T> left, Vector64<T> right) where T : struct { throw null; }
+ public static Vector128<T> CompareGreaterThanOrEqual<T>(Vector128<T> left, Vector128<T> right) where T : struct { throw null; }
+ public static Vector64<T> CompareGreaterThanOrEqualZero<T>(Vector64<T> value) where T : struct { throw null; }
+ public static Vector128<T> CompareGreaterThanOrEqualZero<T>(Vector128<T> value) where T : struct { throw null; }
+ public static Vector64<T> CompareLessThanZero<T>(Vector64<T> value) where T : struct { throw null; }
+ public static Vector128<T> CompareLessThanZero<T>(Vector128<T> value) where T : struct { throw null; }
+ public static Vector64<T> CompareLessThanOrEqualZero<T>(Vector64<T> value) where T : struct { throw null; }
+ public static Vector128<T> CompareLessThanOrEqualZero<T>(Vector128<T> value) where T : struct { throw null; }
+ public static Vector64<T> CompareTest<T>(Vector64<T> left, Vector64<T> right) where T : struct { throw null; }
+ public static Vector128<T> CompareTest<T>(Vector128<T> left, Vector128<T> right) where T : struct { throw null; }
+ public static Vector64<float> Divide(Vector64<float> left, Vector64<float> right) { throw null; }
+ public static Vector128<float> Divide(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<double> Divide(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static T Extract<T>(Vector64<T> vector, byte index) where T : struct { throw null; }
+ public static T Extract<T>(Vector128<T> vector, byte index) where T : struct { throw null; }
+ public static Vector64<T> Insert<T>(Vector64<T> vector, byte index, T data) where T : struct { throw null; }
+ public static Vector128<T> Insert<T>(Vector128<T> vector, byte index, T data) where T : struct { throw null; }
+ public static Vector64<sbyte> LeadingSignCount(Vector64<sbyte> value) { throw null; }
+ public static Vector64<short> LeadingSignCount(Vector64<short> value) { throw null; }
+ public static Vector64<int> LeadingSignCount(Vector64<int> value) { throw null; }
+ public static Vector128<sbyte> LeadingSignCount(Vector128<sbyte> value) { throw null; }
+ public static Vector128<short> LeadingSignCount(Vector128<short> value) { throw null; }
+ public static Vector128<int> LeadingSignCount(Vector128<int> value) { throw null; }
+ public static Vector64<byte> LeadingZeroCount(Vector64<byte> value) { throw null; }
+ public static Vector64<sbyte> LeadingZeroCount(Vector64<sbyte> value) { throw null; }
+ public static Vector64<ushort> LeadingZeroCount(Vector64<ushort> value) { throw null; }
+ public static Vector64<short> LeadingZeroCount(Vector64<short> value) { throw null; }
+ public static Vector64<uint> LeadingZeroCount(Vector64<uint> value) { throw null; }
+ public static Vector64<int> LeadingZeroCount(Vector64<int> value) { throw null; }
+ public static Vector128<byte> LeadingZeroCount(Vector128<byte> value) { throw null; }
+ public static Vector128<sbyte> LeadingZeroCount(Vector128<sbyte> value) { throw null; }
+ public static Vector128<ushort> LeadingZeroCount(Vector128<ushort> value) { throw null; }
+ public static Vector128<short> LeadingZeroCount(Vector128<short> value) { throw null; }
+ public static Vector128<uint> LeadingZeroCount(Vector128<uint> value) { throw null; }
+ public static Vector128<int> LeadingZeroCount(Vector128<int> value) { throw null; }
+ public static Vector64<byte> Max(Vector64<byte> left, Vector64<byte> right) { throw null; }
+ public static Vector64<sbyte> Max(Vector64<sbyte> left, Vector64<sbyte> right) { throw null; }
+ public static Vector64<ushort> Max(Vector64<ushort> left, Vector64<ushort> right) { throw null; }
+ public static Vector64<short> Max(Vector64<short> left, Vector64<short> right) { throw null; }
+ public static Vector64<uint> Max(Vector64<uint> left, Vector64<uint> right) { throw null; }
+ public static Vector64<int> Max(Vector64<int> left, Vector64<int> right) { throw null; }
+ public static Vector64<float> Max(Vector64<float> left, Vector64<float> right) { throw null; }
+ public static Vector128<byte> Max(Vector128<byte> left, Vector128<byte> right) { throw null; }
+ public static Vector128<sbyte> Max(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
+ public static Vector128<ushort> Max(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
+ public static Vector128<short> Max(Vector128<short> left, Vector128<short> right) { throw null; }
+ public static Vector128<uint> Max(Vector128<uint> left, Vector128<uint> right) { throw null; }
+ public static Vector128<int> Max(Vector128<int> left, Vector128<int> right) { throw null; }
+ public static Vector128<float> Max(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<double> Max(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static Vector64<byte> Min(Vector64<byte> left, Vector64<byte> right) { throw null; }
+ public static Vector64<sbyte> Min(Vector64<sbyte> left, Vector64<sbyte> right) { throw null; }
+ public static Vector64<ushort> Min(Vector64<ushort> left, Vector64<ushort> right) { throw null; }
+ public static Vector64<short> Min(Vector64<short> left, Vector64<short> right) { throw null; }
+ public static Vector64<uint> Min(Vector64<uint> left, Vector64<uint> right) { throw null; }
+ public static Vector64<int> Min(Vector64<int> left, Vector64<int> right) { throw null; }
+ public static Vector64<float> Min(Vector64<float> left, Vector64<float> right) { throw null; }
+ public static Vector128<byte> Min(Vector128<byte> left, Vector128<byte> right) { throw null; }
+ public static Vector128<sbyte> Min(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
+ public static Vector128<ushort> Min(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
+ public static Vector128<short> Min(Vector128<short> left, Vector128<short> right) { throw null; }
+ public static Vector128<uint> Min(Vector128<uint> left, Vector128<uint> right) { throw null; }
+ public static Vector128<int> Min(Vector128<int> left, Vector128<int> right) { throw null; }
+ public static Vector128<float> Min(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<double> Min(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static Vector64<byte> Multiply(Vector64<byte> left, Vector64<byte> right) { throw null; }
+ public static Vector64<sbyte> Multiply(Vector64<sbyte> left, Vector64<sbyte> right) { throw null; }
+ public static Vector64<ushort> Multiply(Vector64<ushort> left, Vector64<ushort> right) { throw null; }
+ public static Vector64<short> Multiply(Vector64<short> left, Vector64<short> right) { throw null; }
+ public static Vector64<uint> Multiply(Vector64<uint> left, Vector64<uint> right) { throw null; }
+ public static Vector64<int> Multiply(Vector64<int> left, Vector64<int> right) { throw null; }
+ public static Vector64<float> Multiply(Vector64<float> left, Vector64<float> right) { throw null; }
+ public static Vector128<byte> Multiply(Vector128<byte> left, Vector128<byte> right) { throw null; }
+ public static Vector128<sbyte> Multiply(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
+ public static Vector128<ushort> Multiply(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
+ public static Vector128<short> Multiply(Vector128<short> left, Vector128<short> right) { throw null; }
+ public static Vector128<uint> Multiply(Vector128<uint> left, Vector128<uint> right) { throw null; }
+ public static Vector128<int> Multiply(Vector128<int> left, Vector128<int> right) { throw null; }
+ public static Vector128<float> Multiply(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<double> Multiply(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static Vector64<sbyte> Negate(Vector64<sbyte> value) { throw null; }
+ public static Vector64<short> Negate(Vector64<short> value) { throw null; }
+ public static Vector64<int> Negate(Vector64<int> value) { throw null; }
+ public static Vector64<float> Negate(Vector64<float> value) { throw null; }
+ public static Vector128<sbyte> Negate(Vector128<sbyte> value) { throw null; }
+ public static Vector128<short> Negate(Vector128<short> value) { throw null; }
+ public static Vector128<int> Negate(Vector128<int> value) { throw null; }
+ public static Vector128<long> Negate(Vector128<long> value) { throw null; }
+ public static Vector128<float> Negate(Vector128<float> value) { throw null; }
+ public static Vector128<double> Negate(Vector128<double> value) { throw null; }
+ public static Vector64<T> Not<T>(Vector64<T> value) where T : struct { throw null; }
+ public static Vector128<T> Not<T>(Vector128<T> value) where T : struct { throw null; }
+ public static Vector64<T> Or<T>(Vector64<T> left, Vector64<T> right) where T : struct { throw null; }
+ public static Vector128<T> Or<T>(Vector128<T> left, Vector128<T> right) where T : struct { throw null; }
+ public static Vector64<T> OrNot<T>(Vector64<T> left, Vector64<T> right) where T : struct { throw null; }
+ public static Vector128<T> OrNot<T>(Vector128<T> left, Vector128<T> right) where T : struct { throw null; }
+ public static Vector64<byte> PopCount(Vector64<byte> value) { throw null; }
+ public static Vector64<sbyte> PopCount(Vector64<sbyte> value) { throw null; }
+ public static Vector128<byte> PopCount(Vector128<byte> value) { throw null; }
+ public static Vector128<sbyte> PopCount(Vector128<sbyte> value) { throw null; }
+ public static Vector64<T> SetAllVector64<T>(T value) where T : struct { throw null; }
+ public static Vector128<T> SetAllVector128<T>(T value) where T : struct { throw null; }
+ public static Vector64<float> Sqrt(Vector64<float> value) { throw null; }
+ public static Vector128<float> Sqrt(Vector128<float> value) { throw null; }
+ public static Vector128<double> Sqrt(Vector128<double> value) { throw null; }
+ public static Vector64<T> Subtract<T>(Vector64<T> left, Vector64<T> right) where T : struct { throw null; }
+ public static Vector128<T> Subtract<T>(Vector128<T> left, Vector128<T> right) where T : struct { throw null; }
+ public static Vector64<T> Xor<T>(Vector64<T> left, Vector64<T> right) where T : struct { throw null; }
+ public static Vector128<T> Xor<T>(Vector128<T> left, Vector128<T> right) where T : struct { throw null; }
}
+}
+namespace System.Runtime.Intrinsics.X86
+{
public static class Avx
{
public static bool IsSupported { get { throw null; } }
@@ -48,11 +220,11 @@ namespace System.Runtime.Intrinsics.X86
public static Vector256<double> Blend(Vector256<double> left, Vector256<double> right, byte control) { throw null; }
public static Vector256<float> BlendVariable(Vector256<float> left, Vector256<float> right, Vector256<float> mask) { throw null; }
public static Vector256<double> BlendVariable(Vector256<double> left, Vector256<double> right, Vector256<double> mask) { throw null; }
- public static Vector128<float> BroadcastElementToVector128(ref float source) { throw null; }
+ public static unsafe Vector128<float> BroadcastScalarToVector128(float* source) { throw null; }
public static unsafe Vector256<float> BroadcastVector128ToVector256(float* address) { throw null; }
- public static Vector256<float> BroadcastElementToVector256(ref float source) { throw null; }
+ public static unsafe Vector256<float> BroadcastScalarToVector256(float* source) { throw null; }
public static unsafe Vector256<double> BroadcastVector128ToVector256(double* address) { throw null; }
- public static Vector256<double> BroadcastElementToVector256(ref double source) { throw null; }
+ public static unsafe Vector256<double> BroadcastScalarToVector256(double* source) { throw null; }
public static Vector256<float> Ceiling(Vector256<float> value) { throw null; }
public static Vector256<double> Ceiling(Vector256<double> value) { throw null; }
public static Vector128<float> Compare(Vector128<float> left, Vector128<float> right, FloatComparisonMode mode) { throw null; }
@@ -66,8 +238,8 @@ namespace System.Runtime.Intrinsics.X86
public static Vector128<float> ConvertToVector128Single(Vector256<double> value) { throw null; }
public static Vector256<int> ConvertToVector256Int32(Vector256<float> value) { throw null; }
public static Vector256<float> ConvertToVector256Single(Vector256<int> value) { throw null; }
- public static Vector256<double> ConvertToVector256Double(Vector256<float> value) { throw null; }
- public static Vector256<double> ConvertToVector256Double(Vector256<int> value) { throw null; }
+ public static Vector256<double> ConvertToVector256Double(Vector128<float> value) { throw null; }
+ public static Vector256<double> ConvertToVector256Double(Vector128<int> value) { throw null; }
public static Vector128<int> ConvertToVector128Int32WithTruncation(Vector256<double> value) { throw null; }
public static Vector256<int> ConvertToVector256Int32WithTruncation(Vector256<float> value) { throw null; }
public static Vector256<float> Divide(Vector256<float> left, Vector256<float> right) { throw null; }
@@ -111,17 +283,17 @@ namespace System.Runtime.Intrinsics.X86
public static Vector256<uint> Insert(Vector256<uint> value, uint data, byte index) { throw null; }
public static Vector256<long> Insert(Vector256<long> value, long data, byte index) { throw null; }
public static Vector256<ulong> Insert(Vector256<ulong> value, ulong data, byte index) { throw null; }
- public static Vector256<T> Insert<T>(Vector256<T> value, Vector128<T> data, byte index) where T : struct { throw null; }
- public static unsafe Vector256<sbyte> Insert(Vector256<sbyte> value, sbyte* address, byte index) { throw null; }
- public static unsafe Vector256<byte> Insert(Vector256<byte> value, byte* address, byte index) { throw null; }
- public static unsafe Vector256<short> Insert(Vector256<short> value, short* address, byte index) { throw null; }
- public static unsafe Vector256<ushort> Insert(Vector256<ushort> value, ushort* address, byte index) { throw null; }
- public static unsafe Vector256<int> Insert(Vector256<int> value, int* address, byte index) { throw null; }
- public static unsafe Vector256<uint> Insert(Vector256<uint> value, uint* address, byte index) { throw null; }
- public static unsafe Vector256<long> Insert(Vector256<long> value, long* address, byte index) { throw null; }
- public static unsafe Vector256<ulong> Insert(Vector256<ulong> value, ulong* address, byte index) { throw null; }
- public static unsafe Vector256<float> Insert(Vector256<float> value, float* address, byte index) { throw null; }
- public static unsafe Vector256<double> Insert(Vector256<double> value, double* address, byte index) { throw null; }
+ public static Vector256<T> InsertVector128<T>(Vector256<T> value, Vector128<T> data, byte index) where T : struct { throw null; }
+ public static unsafe Vector256<sbyte> InsertVector128(Vector256<sbyte> value, sbyte* address, byte index) { throw null; }
+ public static unsafe Vector256<byte> InsertVector128(Vector256<byte> value, byte* address, byte index) { throw null; }
+ public static unsafe Vector256<short> InsertVector128(Vector256<short> value, short* address, byte index) { throw null; }
+ public static unsafe Vector256<ushort> InsertVector128(Vector256<ushort> value, ushort* address, byte index) { throw null; }
+ public static unsafe Vector256<int> InsertVector128(Vector256<int> value, int* address, byte index) { throw null; }
+ public static unsafe Vector256<uint> InsertVector128(Vector256<uint> value, uint* address, byte index) { throw null; }
+ public static unsafe Vector256<long> InsertVector128(Vector256<long> value, long* address, byte index) { throw null; }
+ public static unsafe Vector256<ulong> InsertVector128(Vector256<ulong> value, ulong* address, byte index) { throw null; }
+ public static unsafe Vector256<float> InsertVector128(Vector256<float> value, float* address, byte index) { throw null; }
+ public static unsafe Vector256<double> InsertVector128(Vector256<double> value, double* address, byte index) { throw null; }
public static unsafe Vector256<sbyte> LoadVector256(sbyte* address) { throw null; }
public static unsafe Vector256<byte> LoadVector256(byte* address) { throw null; }
public static unsafe Vector256<short> LoadVector256(short* address) { throw null; }
@@ -154,10 +326,6 @@ namespace System.Runtime.Intrinsics.X86
public static unsafe Vector128<double> MaskLoad(double* address, Vector128<ulong> mask) { throw null; }
public static unsafe Vector256<float> MaskLoad(float* address, Vector256<uint> mask) { throw null; }
public static unsafe Vector256<double> MaskLoad(double* address, Vector256<ulong> mask) { throw null; }
- public static unsafe void MaskStore(float* address, Vector128<float> mask, Vector128<uint> source) { throw null; }
- public static unsafe void MaskStore(double* address, Vector128<double> mask, Vector128<ulong> source) { throw null; }
- public static unsafe void MaskStore(float* address, Vector256<float> mask, Vector256<uint> source) { throw null; }
- public static unsafe void MaskStore(double* address, Vector256<double> mask, Vector256<ulong> source) { throw null; }
public static Vector256<float> Max(Vector256<float> left, Vector256<float> right) { throw null; }
public static Vector256<double> Max(Vector256<double> left, Vector256<double> right) { throw null; }
public static Vector256<float> Min(Vector256<float> left, Vector256<float> right) { throw null; }
@@ -239,10 +407,10 @@ namespace System.Runtime.Intrinsics.X86
public static unsafe void Store(double* address, Vector256<double> source) { throw null; }
public static Vector256<float> Subtract(Vector256<float> left, Vector256<float> right) { throw null; }
public static Vector256<double> Subtract(Vector256<double> left, Vector256<double> right) { throw null; }
- public static bool TestC(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static bool TestC(Vector128<float> left, Vector128<float> right) { throw null; }
public static bool TestC(Vector128<double> left, Vector128<double> right) { throw null; }
public static bool TestC<T>(Vector256<T> left, Vector256<T> right) where T : struct { throw null; }
- public static bool TestNotZAndNotC(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static bool TestNotZAndNotC(Vector128<float> left, Vector128<float> right) { throw null; }
public static bool TestNotZAndNotC(Vector128<double> left, Vector128<double> right) { throw null; }
public static bool TestNotZAndNotC<T>(Vector256<T> left, Vector256<T> right) where T : struct { throw null; }
public static bool TestZ(Vector128<float> left, Vector128<float> right) { throw null; }
@@ -254,9 +422,6 @@ namespace System.Runtime.Intrinsics.X86
public static Vector256<double> UnpackLow(Vector256<double> left, Vector256<double> right) { throw null; }
public static Vector256<float> Xor(Vector256<float> left, Vector256<float> right) { throw null; }
public static Vector256<double> Xor(Vector256<double> left, Vector256<double> right) { throw null; }
- public static void ZeroAll() { throw null; }
- public static void ZeroUpper() { throw null; }
- public static Vector256<T> ZeroExtendToVector256<T>(Vector128<T> value) where T : struct { throw null; }
}
public static class Avx2
{
@@ -276,7 +441,6 @@ namespace System.Runtime.Intrinsics.X86
public static Vector256<byte> AddSaturate(Vector256<byte> left, Vector256<byte> right) { throw null; }
public static Vector256<short> AddSaturate(Vector256<short> left, Vector256<short> right) { throw null; }
public static Vector256<ushort> AddSaturate(Vector256<ushort> left, Vector256<ushort> right) { throw null; }
- public static Vector256<sbyte> AlignRight(Vector256<sbyte> left, Vector256<sbyte> right, byte mask) { throw null; }
public static Vector256<sbyte> And(Vector256<sbyte> left, Vector256<sbyte> right) { throw null; }
public static Vector256<byte> And(Vector256<byte> left, Vector256<byte> right) { throw null; }
public static Vector256<short> And(Vector256<short> left, Vector256<short> right) { throw null; }
@@ -295,16 +459,10 @@ namespace System.Runtime.Intrinsics.X86
public static Vector256<ulong> AndNot(Vector256<ulong> left, Vector256<ulong> right) { throw null; }
public static Vector256<byte> Average(Vector256<byte> left, Vector256<byte> right) { throw null; }
public static Vector256<ushort> Average(Vector256<ushort> left, Vector256<ushort> right) { throw null; }
- public static Vector128<int> Blend(Vector128<int> left, Vector128<int> right, byte control) { throw null; }
- public static Vector128<uint> Blend(Vector128<uint> left, Vector128<uint> right, byte control) { throw null; }
- public static Vector256<short> Blend(Vector256<short> left, Vector256<short> right, byte control) { throw null; }
- public static Vector256<ushort> Blend(Vector256<ushort> left, Vector256<ushort> right, byte control) { throw null; }
- public static Vector256<int> Blend(Vector256<int> left, Vector256<int> right, byte control) { throw null; }
- public static Vector256<uint> Blend(Vector256<uint> left, Vector256<uint> right, byte control) { throw null; }
public static Vector256<sbyte> BlendVariable(Vector256<sbyte> left, Vector256<sbyte> right, Vector256<sbyte> mask) { throw null; }
public static Vector256<byte> BlendVariable(Vector256<byte> left, Vector256<byte> right, Vector256<byte> mask) { throw null; }
- public static Vector128<T> BroadcastElementToVector128<T>(Vector128<T> value) where T : struct { throw null; }
- public static Vector256<T> BroadcastElementToVector256<T>(Vector128<T> value) where T : struct { throw null; }
+ public static Vector128<T> BroadcastScalarToVector128<T>(Vector128<T> value) where T : struct { throw null; }
+ public static Vector256<T> BroadcastScalarToVector256<T>(Vector128<T> value) where T : struct { throw null; }
public static unsafe Vector256<sbyte> BroadcastVector128ToVector256(sbyte* address) { throw null; }
public static unsafe Vector256<byte> BroadcastVector128ToVector256(byte* address) { throw null; }
public static unsafe Vector256<short> BroadcastVector128ToVector256(short* address) { throw null; }
@@ -325,9 +483,6 @@ namespace System.Runtime.Intrinsics.X86
public static Vector256<short> CompareGreaterThan(Vector256<short> left, Vector256<short> right) { throw null; }
public static Vector256<int> CompareGreaterThan(Vector256<int> left, Vector256<int> right) { throw null; }
public static Vector256<long> CompareGreaterThan(Vector256<long> left, Vector256<long> right) { throw null; }
- public static double ConvertToDouble(Vector256<double> value) { throw null; }
- public static int ConvertToInt32(Vector256<int> value) { throw null; }
- public static uint ConvertToUInt32(Vector256<uint> value) { throw null; }
public static Vector256<short> ConvertToVector256Int16(Vector128<sbyte> value) { throw null; }
public static Vector256<ushort> ConvertToVector256UInt16(Vector128<byte> value) { throw null; }
public static Vector256<int> ConvertToVector256Int32(Vector128<sbyte> value) { throw null; }
@@ -356,77 +511,28 @@ namespace System.Runtime.Intrinsics.X86
public static unsafe void ExtractVector128(long* address, Vector256<long> value, byte index) { throw null; }
public static Vector128<ulong> ExtractVector128(Vector256<ulong> value, byte index) { throw null; }
public static unsafe void ExtractVector128(ulong* address, Vector256<ulong> value, byte index) { throw null; }
- public static unsafe Vector128<int> GatherVector128(int* baseAddress, Vector128<int> index, byte scale) { throw null; }
- public static unsafe Vector128<uint> GatherVector128(uint* baseAddress, Vector128<int> index, byte scale) { throw null; }
- public static unsafe Vector128<long> GatherVector128(long* baseAddress, Vector128<int> index, byte scale) { throw null; }
- public static unsafe Vector128<ulong> GatherVector128(ulong* baseAddress, Vector128<int> index, byte scale) { throw null; }
- public static unsafe Vector128<float> GatherVector128(float* baseAddress, Vector128<int> index, byte scale) { throw null; }
- public static unsafe Vector128<double> GatherVector128(double* baseAddress, Vector128<int> index, byte scale) { throw null; }
- public static unsafe Vector128<int> GatherVector128(int* baseAddress, Vector128<long> index, byte scale) { throw null; }
- public static unsafe Vector128<uint> GatherVector128(uint* baseAddress, Vector128<long> index, byte scale) { throw null; }
- public static unsafe Vector128<long> GatherVector128(long* baseAddress, Vector128<long> index, byte scale) { throw null; }
- public static unsafe Vector128<ulong> GatherVector128(ulong* baseAddress, Vector128<long> index, byte scale) { throw null; }
- public static unsafe Vector128<float> GatherVector128(float* baseAddress, Vector128<long> index, byte scale) { throw null; }
- public static unsafe Vector128<double> GatherVector128(double* baseAddress, Vector128<long> index, byte scale) { throw null; }
- public static unsafe Vector256<int> GatherVector256(int* baseAddress, Vector256<int> index, byte scale) { throw null; }
- public static unsafe Vector256<uint> GatherVector256(uint* baseAddress, Vector256<int> index, byte scale) { throw null; }
- public static unsafe Vector256<long> GatherVector256(long* baseAddress, Vector128<int> index, byte scale) { throw null; }
- public static unsafe Vector256<ulong> GatherVector256(ulong* baseAddress, Vector128<int> index, byte scale) { throw null; }
- public static unsafe Vector256<float> GatherVector256(float* baseAddress, Vector256<int> index, byte scale) { throw null; }
- public static unsafe Vector256<double> GatherVector256(double* baseAddress, Vector128<int> index, byte scale) { throw null; }
- public static unsafe Vector128<int> GatherVector128(int* baseAddress, Vector256<long> index, byte scale) { throw null; }
- public static unsafe Vector128<uint> GatherVector128(uint* baseAddress, Vector256<long> index, byte scale) { throw null; }
- public static unsafe Vector256<long> GatherVector256(long* baseAddress, Vector256<long> index, byte scale) { throw null; }
- public static unsafe Vector256<ulong> GatherVector256(ulong* baseAddress, Vector256<long> index, byte scale) { throw null; }
- public static unsafe Vector128<float> GatherVector128(float* baseAddress, Vector256<long> index, byte scale) { throw null; }
- public static unsafe Vector256<double> GatherVector256(double* baseAddress, Vector256<long> index, byte scale) { throw null; }
- public static unsafe Vector128<int> GatherMaskVector128(Vector128<int> source, int* baseAddress, Vector128<int> index, Vector128<int> mask, byte scale) { throw null; }
- public static unsafe Vector128<uint> GatherMaskVector128(Vector128<uint> source, uint* baseAddress, Vector128<int> index, Vector128<uint> mask, byte scale) { throw null; }
- public static unsafe Vector128<long> GatherMaskVector128(Vector128<long> source, long* baseAddress, Vector128<int> index, Vector128<long> mask, byte scale) { throw null; }
- public static unsafe Vector128<ulong> GatherMaskVector128(Vector128<ulong> source, ulong* baseAddress, Vector128<int> index, Vector128<ulong> mask, byte scale) { throw null; }
- public static unsafe Vector128<float> GatherMaskVector128(Vector128<float> source, float* baseAddress, Vector128<int> index, Vector128<float> mask, byte scale) { throw null; }
- public static unsafe Vector128<double> GatherMaskVector128(Vector128<double> source, double* baseAddress, Vector128<int> index, Vector128<double> mask, byte scale) { throw null; }
- public static unsafe Vector128<int> GatherMaskVector128(Vector128<int> source, int* baseAddress, Vector128<long> index, Vector128<int> mask, byte scale) { throw null; }
- public static unsafe Vector128<uint> GatherMaskVector128(Vector128<uint> source, uint* baseAddress, Vector128<long> index, Vector128<uint> mask, byte scale) { throw null; }
- public static unsafe Vector128<long> GatherMaskVector128(Vector128<long> source, long* baseAddress, Vector128<long> index, Vector128<long> mask, byte scale) { throw null; }
- public static unsafe Vector128<ulong> GatherMaskVector128(Vector128<ulong> source, ulong* baseAddress, Vector128<long> index, Vector128<ulong> mask, byte scale) { throw null; }
- public static unsafe Vector128<float> GatherMaskVector128(Vector128<float> source, float* baseAddress, Vector128<long> index, Vector128<float> mask, byte scale) { throw null; }
- public static unsafe Vector128<double> GatherMaskVector128(Vector128<double> source, double* baseAddress, Vector128<long> index, Vector128<double> mask, byte scale) { throw null; }
- public static unsafe Vector256<int> GatherMaskVector256(Vector256<int> source, int* baseAddress, Vector256<int> index, Vector256<int> mask, byte scale) { throw null; }
- public static unsafe Vector256<uint> GatherMaskVector256(Vector256<uint> source, uint* baseAddress, Vector256<int> index, Vector256<uint> mask, byte scale) { throw null; }
- public static unsafe Vector256<long> GatherMaskVector256(Vector256<long> source, long* baseAddress, Vector128<int> index, Vector256<long> mask, byte scale) { throw null; }
- public static unsafe Vector256<ulong> GatherMaskVector256(Vector256<ulong> source, ulong* baseAddress, Vector128<int> index, Vector256<ulong> mask, byte scale) { throw null; }
- public static unsafe Vector256<float> GatherMaskVector256(Vector256<float> source, float* baseAddress, Vector256<int> index, Vector256<float> mask, byte scale) { throw null; }
- public static unsafe Vector256<double> GatherMaskVector256(Vector256<double> source, double* baseAddress, Vector128<int> index, Vector256<double> mask, byte scale) { throw null; }
- public static unsafe Vector128<int> GatherMaskVector128(Vector128<int> source, int* baseAddress, Vector256<long> index, Vector128<int> mask, byte scale) { throw null; }
- public static unsafe Vector128<uint> GatherMaskVector128(Vector128<uint> source, uint* baseAddress, Vector256<long> index, Vector128<uint> mask, byte scale) { throw null; }
- public static unsafe Vector256<long> GatherMaskVector256(Vector256<long> source, long* baseAddress, Vector256<long> index, Vector256<long> mask, byte scale) { throw null; }
- public static unsafe Vector256<ulong> GatherMaskVector256(Vector256<ulong> source, ulong* baseAddress, Vector256<long> index, Vector256<ulong> mask, byte scale) { throw null; }
- public static unsafe Vector128<float> GatherMaskVector128(Vector128<float> source, float* baseAddress, Vector256<long> index, Vector128<float> mask, byte scale) { throw null; }
- public static unsafe Vector256<double> GatherMaskVector256(Vector256<double> source, double* baseAddress, Vector256<long> index, Vector256<double> mask, byte scale) { throw null; }
public static Vector256<short> HorizontalAdd(Vector256<short> left, Vector256<short> right) { throw null; }
public static Vector256<int> HorizontalAdd(Vector256<int> left, Vector256<int> right) { throw null; }
public static Vector256<short> HorizontalAddSaturate(Vector256<short> left, Vector256<short> right) { throw null; }
public static Vector256<short> HorizontalSubtract(Vector256<short> left, Vector256<short> right) { throw null; }
public static Vector256<int> HorizontalSubtract(Vector256<int> left, Vector256<int> right) { throw null; }
public static Vector256<short> HorizontalSubtractSaturate(Vector256<short> left, Vector256<short> right) { throw null; }
- public static Vector256<sbyte> Insert(Vector256<sbyte> value, Vector128<sbyte> data, byte index) { throw null; }
- public static unsafe Vector256<sbyte> Insert(Vector256<sbyte> value, sbyte* address, byte index) { throw null; }
- public static Vector256<byte> Insert(Vector256<byte> value, Vector128<byte> data, byte index) { throw null; }
- public static unsafe Vector256<byte> Insert(Vector256<byte> value, byte* address, byte index) { throw null; }
- public static Vector256<short> Insert(Vector256<short> value, Vector128<short> data, byte index) { throw null; }
- public static unsafe Vector256<short> Insert(Vector256<short> value, short* address, byte index) { throw null; }
- public static Vector256<ushort> Insert(Vector256<ushort> value, Vector128<ushort> data, byte index) { throw null; }
- public static unsafe Vector256<ushort> Insert(Vector256<ushort> value, ushort* address, byte index) { throw null; }
- public static Vector256<int> Insert(Vector256<int> value, Vector128<int> data, byte index) { throw null; }
- public static unsafe Vector256<int> Insert(Vector256<int> value, int* address, byte index) { throw null; }
- public static Vector256<uint> Insert(Vector256<uint> value, Vector128<uint> data, byte index) { throw null; }
- public static unsafe Vector256<uint> Insert(Vector256<uint> value, uint* address, byte index) { throw null; }
- public static Vector256<long> Insert(Vector256<long> value, Vector128<long> data, byte index) { throw null; }
- public static unsafe Vector256<long> Insert(Vector256<long> value, long* address, byte index) { throw null; }
- public static Vector256<ulong> Insert(Vector256<ulong> value, Vector128<ulong> data, byte index) { throw null; }
- public static unsafe Vector256<ulong> Insert(Vector256<ulong> value, ulong* address, byte index) { throw null; }
- public static unsafe Vector128<int> MaskLoad(int* address, Vector128<int> mask) { throw null; }
+ public static Vector256<sbyte> InsertVector128(Vector256<sbyte> value, Vector128<sbyte> data, byte index) { throw null; }
+ public static unsafe Vector256<sbyte> InsertVector128(Vector256<sbyte> value, sbyte* address, byte index) { throw null; }
+ public static Vector256<byte> InsertVector128(Vector256<byte> value, Vector128<byte> data, byte index) { throw null; }
+ public static unsafe Vector256<byte> InsertVector128(Vector256<byte> value, byte* address, byte index) { throw null; }
+ public static Vector256<short> InsertVector128(Vector256<short> value, Vector128<short> data, byte index) { throw null; }
+ public static unsafe Vector256<short> InsertVector128(Vector256<short> value, short* address, byte index) { throw null; }
+ public static Vector256<ushort> InsertVector128(Vector256<ushort> value, Vector128<ushort> data, byte index) { throw null; }
+ public static unsafe Vector256<ushort> InsertVector128(Vector256<ushort> value, ushort* address, byte index) { throw null; }
+ public static Vector256<int> InsertVector128(Vector256<int> value, Vector128<int> data, byte index) { throw null; }
+ public static unsafe Vector256<int> InsertVector128(Vector256<int> value, int* address, byte index) { throw null; }
+ public static Vector256<uint> InsertVector128(Vector256<uint> value, Vector128<uint> data, byte index) { throw null; }
+ public static unsafe Vector256<uint> InsertVector128(Vector256<uint> value, uint* address, byte index) { throw null; }
+ public static Vector256<long> InsertVector128(Vector256<long> value, Vector128<long> data, byte index) { throw null; }
+ public static unsafe Vector256<long> InsertVector128(Vector256<long> value, long* address, byte index) { throw null; }
+ public static Vector256<ulong> InsertVector128(Vector256<ulong> value, Vector128<ulong> data, byte index) { throw null; }
+ public static unsafe Vector256<ulong> InsertVector128(Vector256<ulong> value, ulong* address, byte index) { throw null; }
public static unsafe Vector256<sbyte> LoadAlignedVector256NonTemporal(sbyte* address) { throw null; }
public static unsafe Vector256<byte> LoadAlignedVector256NonTemporal(byte* address) { throw null; }
public static unsafe Vector256<short> LoadAlignedVector256NonTemporal(short* address) { throw null; }
@@ -435,25 +541,10 @@ namespace System.Runtime.Intrinsics.X86
public static unsafe Vector256<uint> LoadAlignedVector256NonTemporal(uint* address) { throw null; }
public static unsafe Vector256<long> LoadAlignedVector256NonTemporal(long* address) { throw null; }
public static unsafe Vector256<ulong> LoadAlignedVector256NonTemporal(ulong* address) { throw null; }
- public static unsafe Vector128<uint> MaskLoad(uint* address, Vector128<uint> mask) { throw null; }
- public static unsafe Vector128<long> MaskLoad(long* address, Vector128<long> mask) { throw null; }
- public static unsafe Vector128<ulong> MaskLoad(ulong* address, Vector128<ulong> mask) { throw null; }
- public static unsafe Vector256<int> MaskLoad(int* address, Vector256<int> mask) { throw null; }
- public static unsafe Vector256<uint> MaskLoad(uint* address, Vector256<uint> mask) { throw null; }
- public static unsafe Vector256<long> MaskLoad(long* address, Vector256<long> mask) { throw null; }
- public static unsafe Vector256<ulong> MaskLoad(ulong* address, Vector256<ulong> mask) { throw null; }
- public static unsafe void MaskStore(int* address, Vector128<int> mask, Vector128<int> source) { throw null; }
- public static unsafe void MaskStore(uint* address, Vector128<uint> mask, Vector128<uint> source) { throw null; }
- public static unsafe void MaskStore(long* address, Vector128<long> mask, Vector128<long> source) { throw null; }
- public static unsafe void MaskStore(ulong* address, Vector128<ulong> mask, Vector128<ulong> source) { throw null; }
- public static unsafe void MaskStore(int* address, Vector256<int> mask, Vector256<int> source) { throw null; }
- public static unsafe void MaskStore(uint* address, Vector256<uint> mask, Vector256<uint> source) { throw null; }
- public static unsafe void MaskStore(long* address, Vector256<long> mask, Vector256<long> source) { throw null; }
- public static unsafe void MaskStore(ulong* address, Vector256<ulong> mask, Vector256<ulong> source) { throw null; }
public static Vector256<int> MultiplyAddAdjacent(Vector256<short> left, Vector256<short> right) { throw null; }
public static Vector256<short> MultiplyAddAdjacent(Vector256<byte> left, Vector256<sbyte> right) { throw null; }
public static Vector256<sbyte> Max(Vector256<sbyte> left, Vector256<sbyte> right) { throw null; }
- public static Vector256<byte> Max(Vector256<byte> left, Vector256<short> right) { throw null; }
+ public static Vector256<byte> Max(Vector256<byte> left, Vector256<byte> right) { throw null; }
public static Vector256<short> Max(Vector256<short> left, Vector256<short> right) { throw null; }
public static Vector256<ushort> Max(Vector256<ushort> left, Vector256<ushort> right) { throw null; }
public static Vector256<int> Max(Vector256<int> left, Vector256<int> right) { throw null; }
@@ -466,14 +557,8 @@ namespace System.Runtime.Intrinsics.X86
public static Vector256<uint> Min(Vector256<uint> left, Vector256<uint> right) { throw null; }
public static int MoveMask(Vector256<sbyte> value) { throw null; }
public static int MoveMask(Vector256<byte> value) { throw null; }
- public static Vector256<ushort> MultipleSumAbsoluteDifferences(Vector256<byte> left, Vector256<byte> right, byte mask) { throw null; }
public static Vector256<long> Multiply(Vector256<int> left, Vector256<int> right) { throw null; }
public static Vector256<ulong> Multiply(Vector256<uint> left, Vector256<uint> right) { throw null; }
- public static Vector256<short> MultiplyHigh(Vector256<short> left, Vector256<short> right) { throw null; }
- public static Vector256<ushort> MultiplyHigh(Vector256<ushort> left, Vector256<ushort> right) { throw null; }
- public static Vector256<short> MultiplyHighRoundScale(Vector256<short> left, Vector256<short> right) { throw null; }
- public static Vector256<short> MultiplyLow(Vector256<short> left, Vector256<short> right) { throw null; }
- public static Vector256<int> MultiplyLow(Vector256<int> left, Vector256<int> right) { throw null; }
public static Vector256<sbyte> Or(Vector256<sbyte> left, Vector256<sbyte> right) { throw null; }
public static Vector256<byte> Or(Vector256<byte> left, Vector256<byte> right) { throw null; }
public static Vector256<short> Or(Vector256<short> left, Vector256<short> right) { throw null; }
@@ -482,10 +567,6 @@ namespace System.Runtime.Intrinsics.X86
public static Vector256<uint> Or(Vector256<uint> left, Vector256<uint> right) { throw null; }
public static Vector256<long> Or(Vector256<long> left, Vector256<long> right) { throw null; }
public static Vector256<ulong> Or(Vector256<ulong> left, Vector256<ulong> right) { throw null; }
- public static Vector256<sbyte> PackSignedSaturate(Vector256<short> left, Vector256<short> right) { throw null; }
- public static Vector256<short> PackSignedSaturate(Vector256<int> left, Vector256<int> right) { throw null; }
- public static Vector256<byte> PackUnsignedSaturate(Vector256<short> left, Vector256<short> right) { throw null; }
- public static Vector256<ushort> PackUnsignedSaturate(Vector256<int> left, Vector256<int> right) { throw null; }
public static Vector256<sbyte> Permute2x128(Vector256<sbyte> left, Vector256<sbyte> right, byte control) { throw null; }
public static Vector256<byte> Permute2x128(Vector256<byte> left, Vector256<byte> right, byte control) { throw null; }
public static Vector256<short> Permute2x128(Vector256<short> left, Vector256<short> right, byte control) { throw null; }
@@ -494,12 +575,6 @@ namespace System.Runtime.Intrinsics.X86
public static Vector256<uint> Permute2x128(Vector256<uint> left, Vector256<uint> right, byte control) { throw null; }
public static Vector256<long> Permute2x128(Vector256<long> left, Vector256<long> right, byte control) { throw null; }
public static Vector256<ulong> Permute2x128(Vector256<ulong> left, Vector256<ulong> right, byte control) { throw null; }
- public static Vector256<long> Permute4x64(Vector256<long> value, byte control) { throw null; }
- public static Vector256<ulong> Permute4x64(Vector256<ulong> value, byte control) { throw null; }
- public static Vector256<double> Permute4x64(Vector256<double> value, byte control) { throw null; }
- public static Vector256<int> PermuteVar8x32(Vector256<int> left, Vector256<int> mask) { throw null; }
- public static Vector256<uint> PermuteVar8x32(Vector256<uint> left, Vector256<uint> mask) { throw null; }
- public static Vector256<float> PermuteVar8x32(Vector256<float> left, Vector256<float> mask) { throw null; }
public static Vector256<short> ShiftLeftLogical(Vector256<short> value, Vector128<short> count) { throw null; }
public static Vector256<ushort> ShiftLeftLogical(Vector256<ushort> value, Vector128<ushort> count) { throw null; }
public static Vector256<int> ShiftLeftLogical(Vector256<int> value, Vector128<int> count) { throw null; }
@@ -532,8 +607,6 @@ namespace System.Runtime.Intrinsics.X86
public static Vector256<int> ShiftRightArithmetic(Vector256<int> value, Vector128<int> count) { throw null; }
public static Vector256<short> ShiftRightArithmetic(Vector256<short> value, byte count) { throw null; }
public static Vector256<int> ShiftRightArithmetic(Vector256<int> value, byte count) { throw null; }
- public static Vector256<int> ShiftRightArithmeticVariable(Vector256<int> value, Vector256<uint> count) { throw null; }
- public static Vector128<int> ShiftRightArithmeticVariable(Vector128<int> value, Vector128<uint> count) { throw null; }
public static Vector256<short> ShiftRightLogical(Vector256<short> value, Vector128<short> count) { throw null; }
public static Vector256<ushort> ShiftRightLogical(Vector256<ushort> value, Vector128<ushort> count) { throw null; }
public static Vector256<int> ShiftRightLogical(Vector256<int> value, Vector128<int> count) { throw null; }
@@ -562,17 +635,6 @@ namespace System.Runtime.Intrinsics.X86
public static Vector128<uint> ShiftRightLogicalVariable(Vector128<uint> value, Vector128<uint> count) { throw null; }
public static Vector128<long> ShiftRightLogicalVariable(Vector128<long> value, Vector128<ulong> count) { throw null; }
public static Vector128<ulong> ShiftRightLogicalVariable(Vector128<ulong> value, Vector128<ulong> count) { throw null; }
- public static Vector256<sbyte> Shuffle(Vector256<sbyte> value, Vector256<sbyte> mask) { throw null; }
- public static Vector256<byte> Shuffle(Vector256<byte> value, Vector256<byte> mask) { throw null; }
- public static Vector256<int> Shuffle(Vector256<int> value, byte control) { throw null; }
- public static Vector256<uint> Shuffle(Vector256<uint> value, byte control) { throw null; }
- public static Vector256<short> ShuffleHigh(Vector256<short> value, byte control) { throw null; }
- public static Vector256<ushort> ShuffleHigh(Vector256<ushort> value, byte control) { throw null; }
- public static Vector256<short> ShuffleLow(Vector256<short> value, byte control) { throw null; }
- public static Vector256<ushort> ShuffleLow(Vector256<ushort> value, byte control) { throw null; }
- public static Vector256<sbyte> Sign(Vector256<sbyte> left, Vector256<sbyte> right) { throw null; }
- public static Vector256<short> Sign(Vector256<short> left, Vector256<short> right) { throw null; }
- public static Vector256<int> Sign(Vector256<int> left, Vector256<int> right) { throw null; }
public static Vector256<sbyte> Subtract(Vector256<sbyte> left, Vector256<sbyte> right) { throw null; }
public static Vector256<byte> Subtract(Vector256<byte> left, Vector256<byte> right) { throw null; }
public static Vector256<short> Subtract(Vector256<short> left, Vector256<short> right) { throw null; }
@@ -585,7 +647,6 @@ namespace System.Runtime.Intrinsics.X86
public static Vector256<short> SubtractSaturate(Vector256<short> left, Vector256<short> right) { throw null; }
public static Vector256<byte> SubtractSaturate(Vector256<byte> left, Vector256<byte> right) { throw null; }
public static Vector256<ushort> SubtractSaturate(Vector256<ushort> left, Vector256<ushort> right) { throw null; }
- public static Vector256<ulong> SumAbsoluteDifferences(Vector256<byte> left, Vector256<byte> right) { throw null; }
public static Vector256<sbyte> UnpackHigh(Vector256<sbyte> left, Vector256<sbyte> right) { throw null; }
public static Vector256<byte> UnpackHigh(Vector256<byte> left, Vector256<byte> right) { throw null; }
public static Vector256<short> UnpackHigh(Vector256<short> left, Vector256<short> right) { throw null; }
@@ -611,36 +672,6 @@ namespace System.Runtime.Intrinsics.X86
public static Vector256<long> Xor(Vector256<long> left, Vector256<long> right) { throw null; }
public static Vector256<ulong> Xor(Vector256<ulong> left, Vector256<ulong> right) { throw null; }
}
- public static class Bmi1
- {
- public static bool IsSupported { get { throw null; } }
- public static uint AndNot(uint left, uint right) { throw null; }
- public static ulong AndNot(ulong left, ulong right) { throw null; }
- public static uint BitFieldExtract(uint value, uint start, uint length) { throw null; }
- public static ulong BitFieldExtract(ulong value, ulong start, ulong length) { throw null; }
- public static uint BitFieldExtract(uint value, uint control) { throw null; }
- public static ulong BitFieldExtract(ulong value, ulong control) { throw null; }
- public static uint ExtractLowestSetBit(uint value) { throw null; }
- public static ulong ExtractLowestSetBit(ulong value) { throw null; }
- public static uint GetMaskUptoLowestSetBit(uint value) { throw null; }
- public static ulong GetMaskUptoLowestSetBit(ulong value) { throw null; }
- public static uint ResetLowestSetBit(uint value) { throw null; }
- public static ulong ResetLowestSetBit(ulong value) { throw null; }
- public static uint TrailingZeroCount(uint value) { throw null; }
- public static ulong TrailingZeroCount(ulong value) { throw null; }
- }
- public static class Bmi2
- {
- public static bool IsSupported { get { throw null; } }
- public static uint ZeroHighBits(uint value, uint index) { throw null; }
- public static ulong ZeroHighBits(ulong value, ulong index) { throw null; }
- public static unsafe uint MultiplyNoFlags(uint left, uint right, uint* high) { throw null; }
- public static unsafe ulong MultiplyNoFlags(ulong left, ulong right, ulong* high) { throw null; }
- public static uint ParallelBitDeposit(uint value, uint mask) { throw null; }
- public static ulong ParallelBitDeposit(ulong value, ulong mask) { throw null; }
- public static uint ParallelBitExtract(uint value, uint mask) { throw null; }
- public static ulong ParallelBitExtract(ulong value, ulong mask) { throw null; }
- }
public enum FloatComparisonMode : byte
{
EqualOrderedNonSignaling = 0,
@@ -676,73 +707,12 @@ namespace System.Runtime.Intrinsics.X86
GreaterThanOrderedNonSignaling = 30,
TrueUnorderedSignaling = 31,
}
- public enum StringComparisonMode : byte
- {
- EqualAny = 0x00,
- Ranges = 0x04,
- EqualEach = 0x08,
- EqualOrdered = 0x0c,
- NegativePolarity = 0x10,
- MaskedNegativePolarity = 0x30,
- LeastSignificant = 0x00,
- MostSignificant = 0x40,
- }
- public enum ResultsFlag : byte
- {
- CFlag = 0,
- NotCFlagAndNotZFlag = 1,
- OFlag = 2,
- SFlag = 3,
- ZFlag = 4,
- }
- public static class Fma
- {
- public static bool IsSupported { get { throw null; } }
- public static Vector128<float> MultiplyAdd(Vector128<float> a, Vector128<float> b, Vector128<float> c) { throw null; }
- public static Vector128<double> MultiplyAdd(Vector128<double> a, Vector128<double> b, Vector128<double> c) { throw null; }
- public static Vector256<float> MultiplyAdd(Vector256<float> a, Vector256<float> b, Vector256<float> c) { throw null; }
- public static Vector256<double> MultiplyAdd(Vector256<double> a, Vector256<double> b, Vector256<double> c) { throw null; }
- public static Vector128<double> MultiplyAddScalar(Vector128<double> a, Vector128<double> b, Vector128<double> c) { throw null; }
- public static Vector128<float> MultiplyAddScalar(Vector128<float> a, Vector128<float> b, Vector128<float> c) { throw null; }
- public static Vector128<float> MultiplyAddSubtract(Vector128<float> a, Vector128<float> b, Vector128<float> c) { throw null; }
- public static Vector128<double> MultiplyAddSubtract(Vector128<double> a, Vector128<double> b, Vector128<double> c) { throw null; }
- public static Vector256<float> MultiplyAddSubtract(Vector256<float> a, Vector256<float> b, Vector256<float> c) { throw null; }
- public static Vector256<double> MultiplyAddSubtract(Vector256<double> a, Vector256<double> b, Vector256<double> c) { throw null; }
- public static Vector128<float> MultiplySubtract(Vector128<float> a, Vector128<float> b, Vector128<float> c) { throw null; }
- public static Vector128<double> MultiplySubtract(Vector128<double> a, Vector128<double> b, Vector128<double> c) { throw null; }
- public static Vector256<float> MultiplySubtract(Vector256<float> a, Vector256<float> b, Vector256<float> c) { throw null; }
- public static Vector256<double> MultiplySubtract(Vector256<double> a, Vector256<double> b, Vector256<double> c) { throw null; }
- public static Vector128<float> MultiplySubtractAdd(Vector128<float> a, Vector128<float> b, Vector128<float> c) { throw null; }
- public static Vector128<double> MultiplySubtractAdd(Vector128<double> a, Vector128<double> b, Vector128<double> c) { throw null; }
- public static Vector256<float> MultiplySubtractAdd(Vector256<float> a, Vector256<float> b, Vector256<float> c) { throw null; }
- public static Vector256<double> MultiplySubtractAdd(Vector256<double> a, Vector256<double> b, Vector256<double> c) { throw null; }
- public static Vector128<double> MultiplySubtractScalar(Vector128<double> a, Vector128<double> b, Vector128<double> c) { throw null; }
- public static Vector128<float> MultiplySubtractScalar(Vector128<float> a, Vector128<float> b, Vector128<float> c) { throw null; }
- public static Vector128<float> MultiplyAddNegated(Vector128<float> a, Vector128<float> b, Vector128<float> c) { throw null; }
- public static Vector128<double> MultiplyAddNegated(Vector128<double> a, Vector128<double> b, Vector128<double> c) { throw null; }
- public static Vector256<float> MultiplyAddNegated(Vector256<float> a, Vector256<float> b, Vector256<float> c) { throw null; }
- public static Vector256<double> MultiplyAddNegated(Vector256<double> a, Vector256<double> b, Vector256<double> c) { throw null; }
- public static Vector128<double> MultiplyAddNegatedScalar(Vector128<double> a, Vector128<double> b, Vector128<double> c) { throw null; }
- public static Vector128<float> MultiplyAddNegatedScalar(Vector128<float> a, Vector128<float> b, Vector128<float> c) { throw null; }
- public static Vector128<float> MultiplySubtractNegated(Vector128<float> a, Vector128<float> b, Vector128<float> c) { throw null; }
- public static Vector128<double> MultiplySubtractNegated(Vector128<double> a, Vector128<double> b, Vector128<double> c) { throw null; }
- public static Vector256<float> MultiplySubtractNegated(Vector256<float> a, Vector256<float> b, Vector256<float> c) { throw null; }
- public static Vector256<double> MultiplySubtractNegated(Vector256<double> a, Vector256<double> b, Vector256<double> c) { throw null; }
- public static Vector128<double> MultiplySubtractNegatedScalar(Vector128<double> a, Vector128<double> b, Vector128<double> c) { throw null; }
- public static Vector128<float> MultiplySubtractNegatedScalar(Vector128<float> a, Vector128<float> b, Vector128<float> c) { throw null; }
- }
public static class Lzcnt
{
public static bool IsSupported { get { throw null; } }
public static uint LeadingZeroCount(uint value) { throw null; }
public static ulong LeadingZeroCount(ulong value) { throw null; }
}
- public static class Pclmulqdq
- {
- public static bool IsSupported { get { throw null; } }
- public static Vector128<long> CarryLessMultiply(Vector128<long> left, Vector128<long> right, byte control) { throw null; }
- public static Vector128<ulong> CarryLessMultiply(Vector128<ulong> left, Vector128<ulong> right, byte control) { throw null; }
- }
public static class Popcnt
{
public static bool IsSupported { get { throw null; } }
@@ -752,179 +722,187 @@ namespace System.Runtime.Intrinsics.X86
public static class Sse
{
public static bool IsSupported { get { return false; } }
- public static Vector128<float> Add(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<float> Add(Vector128<float> left, Vector128<float> right) { throw null; }
public static Vector128<float> AddScalar(Vector128<float> left, Vector128<float> right) { throw null; }
- public static Vector128<float> And(Vector128<float> left, Vector128<float> right) { throw null; }
- public static Vector128<float> AndNot(Vector128<float> left, Vector128<float> right) { throw null; }
- public static Vector128<float> CompareEqual(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<float> And(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<float> AndNot(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<float> CompareEqual(Vector128<float> left, Vector128<float> right) { throw null; }
public static bool CompareEqualOrderedScalar(Vector128<float> left, Vector128<float> right) { throw null; }
public static Vector128<float> CompareEqualScalar(Vector128<float> left, Vector128<float> right) { throw null; }
public static bool CompareEqualUnorderedScalar(Vector128<float> left, Vector128<float> right) { throw null; }
- public static Vector128<float> CompareGreaterThan(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<float> CompareGreaterThan(Vector128<float> left, Vector128<float> right) { throw null; }
public static bool CompareGreaterThanOrderedScalar(Vector128<float> left, Vector128<float> right) { throw null; }
public static Vector128<float> CompareGreaterThanScalar(Vector128<float> left, Vector128<float> right) { throw null; }
public static bool CompareGreaterThanUnorderedScalar(Vector128<float> left, Vector128<float> right) { throw null; }
- public static Vector128<float> CompareGreaterThanOrEqual(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<float> CompareGreaterThanOrEqual(Vector128<float> left, Vector128<float> right) { throw null; }
public static bool CompareGreaterThanOrEqualOrderedScalar(Vector128<float> left, Vector128<float> right) { throw null; }
public static Vector128<float> CompareGreaterThanOrEqualScalar(Vector128<float> left, Vector128<float> right) { throw null; }
public static bool CompareGreaterThanOrEqualUnorderedScalar(Vector128<float> left, Vector128<float> right) { throw null; }
- public static Vector128<float> CompareLessThan(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<float> CompareLessThan(Vector128<float> left, Vector128<float> right) { throw null; }
public static bool CompareLessThanOrderedScalar(Vector128<float> left, Vector128<float> right) { throw null; }
public static Vector128<float> CompareLessThanScalar(Vector128<float> left, Vector128<float> right) { throw null; }
public static bool CompareLessThanUnorderedScalar(Vector128<float> left, Vector128<float> right) { throw null; }
- public static Vector128<float> CompareLessThanOrEqual(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<float> CompareLessThanOrEqual(Vector128<float> left, Vector128<float> right) { throw null; }
public static bool CompareLessThanOrEqualOrderedScalar(Vector128<float> left, Vector128<float> right) { throw null; }
public static Vector128<float> CompareLessThanOrEqualScalar(Vector128<float> left, Vector128<float> right) { throw null; }
public static bool CompareLessThanOrEqualUnorderedScalar(Vector128<float> left, Vector128<float> right) { throw null; }
- public static Vector128<float> CompareNotEqual(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<float> CompareNotEqual(Vector128<float> left, Vector128<float> right) { throw null; }
public static bool CompareNotEqualOrderedScalar(Vector128<float> left, Vector128<float> right) { throw null; }
public static Vector128<float> CompareNotEqualScalar(Vector128<float> left, Vector128<float> right) { throw null; }
public static bool CompareNotEqualUnorderedScalar(Vector128<float> left, Vector128<float> right) { throw null; }
- public static Vector128<float> CompareNotGreaterThan(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<float> CompareNotGreaterThan(Vector128<float> left, Vector128<float> right) { throw null; }
public static Vector128<float> CompareNotGreaterThanScalar(Vector128<float> left, Vector128<float> right) { throw null; }
- public static Vector128<float> CompareNotGreaterThanOrEqual(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<float> CompareNotGreaterThanOrEqual(Vector128<float> left, Vector128<float> right) { throw null; }
public static Vector128<float> CompareNotGreaterThanOrEqualScalar(Vector128<float> left, Vector128<float> right) { throw null; }
- public static Vector128<float> CompareNotLessThan(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<float> CompareNotLessThan(Vector128<float> left, Vector128<float> right) { throw null; }
public static Vector128<float> CompareNotLessThanScalar(Vector128<float> left, Vector128<float> right) { throw null; }
- public static Vector128<float> CompareNotLessThanOrEqual(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<float> CompareNotLessThanOrEqual(Vector128<float> left, Vector128<float> right) { throw null; }
public static Vector128<float> CompareNotLessThanOrEqualScalar(Vector128<float> left, Vector128<float> right) { throw null; }
- public static Vector128<float> CompareOrdered(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<float> CompareOrdered(Vector128<float> left, Vector128<float> right) { throw null; }
public static Vector128<float> CompareOrderedScalar(Vector128<float> left, Vector128<float> right) { throw null; }
- public static Vector128<float> CompareUnordered(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<float> CompareUnordered(Vector128<float> left, Vector128<float> right) { throw null; }
public static Vector128<float> CompareUnorderedScalar(Vector128<float> left, Vector128<float> right) { throw null; }
public static int ConvertToInt32(Vector128<float> value) { throw null; }
public static int ConvertToInt32WithTruncation(Vector128<float> value) { throw null; }
public static long ConvertToInt64WithTruncation(Vector128<float> value) { throw null; }
public static long ConvertToInt64(Vector128<float> value) { throw null; }
public static float ConvertToSingle(Vector128<float> value) { throw null; }
- public static Vector128<float> ConvertToVector128SingleScalar(Vector128<float> upper, int value) { throw null; }
- public static Vector128<float> ConvertToVector128SingleScalar(Vector128<float> upper, long value) { throw null; }
- public static Vector128<float> Divide(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<float> ConvertScalarToVector128Single(Vector128<float> upper, int value) { throw null; }
+ public static Vector128<float> ConvertScalarToVector128Single(Vector128<float> upper, long value) { throw null; }
+ public static Vector128<float> Divide(Vector128<float> left, Vector128<float> right) { throw null; }
public static Vector128<float> DivideScalar(Vector128<float> left, Vector128<float> right) { throw null; }
public static unsafe Vector128<float> LoadVector128(float* address) { throw null; }
public static unsafe Vector128<float> LoadAlignedVector128(float* address) { throw null; }
- public static unsafe Vector128<float> LoadHigh(Vector128<float> value, float* address) { throw null; }
- public static unsafe Vector128<float> LoadLow(Vector128<float> value, float* address) { throw null; }
- public static unsafe Vector128<float> LoadScalar(float* address) { throw null; }
- public static Vector128<float> Max(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static unsafe Vector128<float> LoadHigh(Vector128<float> lower, float* address) { throw null; }
+ public static unsafe Vector128<float> LoadLow(Vector128<float> upper, float* address) { throw null; }
+ public static unsafe Vector128<float> LoadScalarVector128(float* address) { throw null; }
+ public static Vector128<float> Max(Vector128<float> left, Vector128<float> right) { throw null; }
public static Vector128<float> MaxScalar(Vector128<float> left, Vector128<float> right) { throw null; }
- public static Vector128<float> Min(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<float> Min(Vector128<float> left, Vector128<float> right) { throw null; }
public static Vector128<float> MinScalar(Vector128<float> left, Vector128<float> right) { throw null; }
- public static Vector128<float> MoveHighToLow(Vector128<float> left, Vector128<float> right) { throw null; }
- public static Vector128<float> MoveLowToHigh(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<float> MoveHighToLow(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<float> MoveLowToHigh(Vector128<float> left, Vector128<float> right) { throw null; }
public static Vector128<float> MoveScalar(Vector128<float> upper, Vector128<float> value) { throw null; }
public static int MoveMask(Vector128<float> value) { throw null; }
- public static Vector128<float> Multiply(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<float> Multiply(Vector128<float> left, Vector128<float> right) { throw null; }
public static Vector128<float> MultiplyScalar(Vector128<float> left, Vector128<float> right) { throw null; }
- public static Vector128<float> Or(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<float> Or(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static unsafe void Prefetch0(void* address) { throw null; }
+ public static unsafe void Prefetch1(void* address) { throw null; }
+ public static unsafe void Prefetch2(void* address) { throw null; }
+ public static unsafe void PrefetchNonTemporal(void* address) { throw null; }
public static Vector128<float> Reciprocal(Vector128<float> value) { throw null; }
public static Vector128<float> ReciprocalScalar(Vector128<float> value) { throw null; }
+ public static Vector128<float> ReciprocalScalar(Vector128<float> upper, Vector128<float> value) { throw null; }
public static Vector128<float> ReciprocalSqrt(Vector128<float> value) { throw null; }
public static Vector128<float> ReciprocalSqrtScalar(Vector128<float> value) { throw null; }
+ public static Vector128<float> ReciprocalSqrtScalar(Vector128<float> upper, Vector128<float> value) { throw null; }
public static Vector128<float> SetVector128(float e3, float e2, float e1, float e0) { throw null; }
public static Vector128<float> SetAllVector128(float value) { throw null; }
- public static Vector128<float> SetScalar(float value) { throw null; }
+ public static Vector128<float> SetScalarVector128(float value) { throw null; }
public static Vector128<float> SetZeroVector128() { throw null; }
public static Vector128<U> StaticCast<T, U>(Vector128<T> value) where T : struct where U : struct { throw null; }
public static Vector128<float> Shuffle(Vector128<float> left, Vector128<float> right, byte control) { throw null; }
public static Vector128<float> Sqrt(Vector128<float> value) { throw null; }
public static Vector128<float> SqrtScalar(Vector128<float> value) { throw null; }
+ public static Vector128<float> SqrtScalar(Vector128<float> upper, Vector128<float> value) { throw null; }
public static unsafe void StoreAligned(float* address, Vector128<float> source) { throw null; }
public static unsafe void StoreAlignedNonTemporal(float* address, Vector128<float> source) { throw null; }
public static unsafe void Store(float* address, Vector128<float> source) { throw null; }
+ public static void StoreFence() { throw null; }
public static unsafe void StoreHigh(float* address, Vector128<float> source) { throw null; }
- public static unsafe void StoreLow(float* address, Vector128<float> source) { throw null; }
+ public static unsafe void StoreLow(float* address, Vector128<float> source) { throw null; }
public static unsafe void StoreScalar(float* address, Vector128<float> source) { throw null; }
- public static Vector128<float> Subtract(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<float> Subtract(Vector128<float> left, Vector128<float> right) { throw null; }
public static Vector128<float> SubtractScalar(Vector128<float> left, Vector128<float> right) { throw null; }
- public static Vector128<float> UnpackHigh(Vector128<float> left, Vector128<float> right) { throw null; }
- public static Vector128<float> UnpackLow(Vector128<float> left, Vector128<float> right) { throw null; }
- public static Vector128<float> Xor(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<float> UnpackHigh(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<float> UnpackLow(Vector128<float> left, Vector128<float> right) { throw null; }
+ public static Vector128<float> Xor(Vector128<float> left, Vector128<float> right) { throw null; }
}
public static class Sse2
{
public static bool IsSupported { get { return false; } }
- public static Vector128<byte> Add(Vector128<byte> left, Vector128<byte> right) { throw null; }
- public static Vector128<sbyte> Add(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
- public static Vector128<short> Add(Vector128<short> left, Vector128<short> right) { throw null; }
- public static Vector128<ushort> Add(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
- public static Vector128<int> Add(Vector128<int> left, Vector128<int> right) { throw null; }
- public static Vector128<uint> Add(Vector128<uint> left, Vector128<uint> right) { throw null; }
- public static Vector128<long> Add(Vector128<long> left, Vector128<long> right) { throw null; }
- public static Vector128<ulong> Add(Vector128<ulong> left, Vector128<ulong> right) { throw null; }
- public static Vector128<double> Add(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static Vector128<byte> Add(Vector128<byte> left, Vector128<byte> right) { throw null; }
+ public static Vector128<sbyte> Add(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
+ public static Vector128<short> Add(Vector128<short> left, Vector128<short> right) { throw null; }
+ public static Vector128<ushort> Add(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
+ public static Vector128<int> Add(Vector128<int> left, Vector128<int> right) { throw null; }
+ public static Vector128<uint> Add(Vector128<uint> left, Vector128<uint> right) { throw null; }
+ public static Vector128<long> Add(Vector128<long> left, Vector128<long> right) { throw null; }
+ public static Vector128<ulong> Add(Vector128<ulong> left, Vector128<ulong> right) { throw null; }
+ public static Vector128<double> Add(Vector128<double> left, Vector128<double> right) { throw null; }
public static Vector128<double> AddScalar(Vector128<double> left, Vector128<double> right) { throw null; }
- public static Vector128<sbyte> AddSaturate(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
- public static Vector128<byte> AddSaturate(Vector128<byte> left, Vector128<byte> right) { throw null; }
- public static Vector128<short> AddSaturate(Vector128<short> left, Vector128<short> right) { throw null; }
- public static Vector128<ushort> AddSaturate(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
- public static Vector128<byte> And(Vector128<byte> left, Vector128<byte> right) { throw null; }
- public static Vector128<sbyte> And(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
- public static Vector128<short> And(Vector128<short> left, Vector128<short> right) { throw null; }
- public static Vector128<ushort> And(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
- public static Vector128<int> And(Vector128<int> left, Vector128<int> right) { throw null; }
- public static Vector128<uint> And(Vector128<uint> left, Vector128<uint> right) { throw null; }
- public static Vector128<long> And(Vector128<long> left, Vector128<long> right) { throw null; }
- public static Vector128<ulong> And(Vector128<ulong> left, Vector128<ulong> right) { throw null; }
- public static Vector128<double> And(Vector128<double> left, Vector128<double> right) { throw null; }
- public static Vector128<byte> AndNot(Vector128<byte> left, Vector128<byte> right) { throw null; }
- public static Vector128<sbyte> AndNot(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
- public static Vector128<short> AndNot(Vector128<short> left, Vector128<short> right) { throw null; }
- public static Vector128<ushort> AndNot(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
- public static Vector128<int> AndNot(Vector128<int> left, Vector128<int> right) { throw null; }
- public static Vector128<uint> AndNot(Vector128<uint> left, Vector128<uint> right) { throw null; }
- public static Vector128<long> AndNot(Vector128<long> left, Vector128<long> right) { throw null; }
- public static Vector128<ulong> AndNot(Vector128<ulong> left, Vector128<ulong> right) { throw null; }
- public static Vector128<double> AndNot(Vector128<double> left, Vector128<double> right) { throw null; }
- public static Vector128<byte> Average(Vector128<byte> left, Vector128<byte> right) { throw null; }
- public static Vector128<ushort> Average(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
- public static Vector128<sbyte> CompareEqual(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
- public static Vector128<byte> CompareEqual(Vector128<byte> left, Vector128<byte> right) { throw null; }
- public static Vector128<short> CompareEqual(Vector128<short> left, Vector128<short> right) { throw null; }
- public static Vector128<ushort> CompareEqual(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
- public static Vector128<int> CompareEqual(Vector128<int> left, Vector128<int> right) { throw null; }
- public static Vector128<uint> CompareEqual(Vector128<uint> left, Vector128<uint> right) { throw null; }
- public static Vector128<double> CompareEqual(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static Vector128<sbyte> AddSaturate(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
+ public static Vector128<byte> AddSaturate(Vector128<byte> left, Vector128<byte> right) { throw null; }
+ public static Vector128<short> AddSaturate(Vector128<short> left, Vector128<short> right) { throw null; }
+ public static Vector128<ushort> AddSaturate(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
+ public static Vector128<byte> And(Vector128<byte> left, Vector128<byte> right) { throw null; }
+ public static Vector128<sbyte> And(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
+ public static Vector128<short> And(Vector128<short> left, Vector128<short> right) { throw null; }
+ public static Vector128<ushort> And(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
+ public static Vector128<int> And(Vector128<int> left, Vector128<int> right) { throw null; }
+ public static Vector128<uint> And(Vector128<uint> left, Vector128<uint> right) { throw null; }
+ public static Vector128<long> And(Vector128<long> left, Vector128<long> right) { throw null; }
+ public static Vector128<ulong> And(Vector128<ulong> left, Vector128<ulong> right) { throw null; }
+ public static Vector128<double> And(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static Vector128<byte> AndNot(Vector128<byte> left, Vector128<byte> right) { throw null; }
+ public static Vector128<sbyte> AndNot(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
+ public static Vector128<short> AndNot(Vector128<short> left, Vector128<short> right) { throw null; }
+ public static Vector128<ushort> AndNot(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
+ public static Vector128<int> AndNot(Vector128<int> left, Vector128<int> right) { throw null; }
+ public static Vector128<uint> AndNot(Vector128<uint> left, Vector128<uint> right) { throw null; }
+ public static Vector128<long> AndNot(Vector128<long> left, Vector128<long> right) { throw null; }
+ public static Vector128<ulong> AndNot(Vector128<ulong> left, Vector128<ulong> right) { throw null; }
+ public static Vector128<double> AndNot(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static Vector128<byte> Average(Vector128<byte> left, Vector128<byte> right) { throw null; }
+ public static Vector128<ushort> Average(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
+ public static Vector128<sbyte> CompareEqual(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
+ public static Vector128<byte> CompareEqual(Vector128<byte> left, Vector128<byte> right) { throw null; }
+ public static Vector128<short> CompareEqual(Vector128<short> left, Vector128<short> right) { throw null; }
+ public static Vector128<ushort> CompareEqual(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
+ public static Vector128<int> CompareEqual(Vector128<int> left, Vector128<int> right) { throw null; }
+ public static Vector128<uint> CompareEqual(Vector128<uint> left, Vector128<uint> right) { throw null; }
+ public static Vector128<double> CompareEqual(Vector128<double> left, Vector128<double> right) { throw null; }
public static bool CompareEqualOrderedScalar(Vector128<double> left, Vector128<double> right) { throw null; }
public static Vector128<double> CompareEqualScalar(Vector128<double> left, Vector128<double> right) { throw null; }
public static bool CompareEqualUnorderedScalar(Vector128<double> left, Vector128<double> right) { throw null; }
- public static Vector128<sbyte> CompareGreaterThan(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
- public static Vector128<short> CompareGreaterThan(Vector128<short> left, Vector128<short> right) { throw null; }
- public static Vector128<int> CompareGreaterThan(Vector128<int> left, Vector128<int> right) { throw null; }
- public static Vector128<double> CompareGreaterThan(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static Vector128<sbyte> CompareGreaterThan(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
+ public static Vector128<short> CompareGreaterThan(Vector128<short> left, Vector128<short> right) { throw null; }
+ public static Vector128<int> CompareGreaterThan(Vector128<int> left, Vector128<int> right) { throw null; }
+ public static Vector128<double> CompareGreaterThan(Vector128<double> left, Vector128<double> right) { throw null; }
public static bool CompareGreaterThanOrderedScalar(Vector128<double> left, Vector128<double> right) { throw null; }
public static Vector128<double> CompareGreaterThanScalar(Vector128<double> left, Vector128<double> right) { throw null; }
public static bool CompareGreaterThanUnorderedScalar(Vector128<double> left, Vector128<double> right) { throw null; }
- public static Vector128<double> CompareGreaterThanOrEqual(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static Vector128<double> CompareGreaterThanOrEqual(Vector128<double> left, Vector128<double> right) { throw null; }
public static bool CompareGreaterThanOrEqualOrderedScalar(Vector128<double> left, Vector128<double> right) { throw null; }
public static Vector128<double> CompareGreaterThanOrEqualScalar(Vector128<double> left, Vector128<double> right) { throw null; }
public static bool CompareGreaterThanOrEqualUnorderedScalar(Vector128<double> left, Vector128<double> right) { throw null; }
- public static Vector128<sbyte> CompareLessThan(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
- public static Vector128<short> CompareLessThan(Vector128<short> left, Vector128<short> right) { throw null; }
- public static Vector128<int> CompareLessThan(Vector128<int> left, Vector128<int> right) { throw null; }
- public static Vector128<double> CompareLessThan(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static Vector128<sbyte> CompareLessThan(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
+ public static Vector128<short> CompareLessThan(Vector128<short> left, Vector128<short> right) { throw null; }
+ public static Vector128<int> CompareLessThan(Vector128<int> left, Vector128<int> right) { throw null; }
+ public static Vector128<double> CompareLessThan(Vector128<double> left, Vector128<double> right) { throw null; }
public static bool CompareLessThanOrderedScalar(Vector128<double> left, Vector128<double> right) { throw null; }
public static Vector128<double> CompareLessThanScalar(Vector128<double> left, Vector128<double> right) { throw null; }
public static bool CompareLessThanUnorderedScalar(Vector128<double> left, Vector128<double> right) { throw null; }
- public static Vector128<double> CompareLessThanOrEqual(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static Vector128<double> CompareLessThanOrEqual(Vector128<double> left, Vector128<double> right) { throw null; }
public static bool CompareLessThanOrEqualOrderedScalar(Vector128<double> left, Vector128<double> right) { throw null; }
public static Vector128<double> CompareLessThanOrEqualScalar(Vector128<double> left, Vector128<double> right) { throw null; }
public static bool CompareLessThanOrEqualUnorderedScalar(Vector128<double> left, Vector128<double> right) { throw null; }
- public static Vector128<double> CompareNotEqual(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static Vector128<double> CompareNotEqual(Vector128<double> left, Vector128<double> right) { throw null; }
public static bool CompareNotEqualOrderedScalar(Vector128<double> left, Vector128<double> right) { throw null; }
public static Vector128<double> CompareNotEqualScalar(Vector128<double> left, Vector128<double> right) { throw null; }
public static bool CompareNotEqualUnorderedScalar(Vector128<double> left, Vector128<double> right) { throw null; }
- public static Vector128<double> CompareNotGreaterThan(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static Vector128<double> CompareNotGreaterThan(Vector128<double> left, Vector128<double> right) { throw null; }
public static Vector128<double> CompareNotGreaterThanScalar(Vector128<double> left, Vector128<double> right) { throw null; }
- public static Vector128<double> CompareNotGreaterThanOrEqual(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static Vector128<double> CompareNotGreaterThanOrEqual(Vector128<double> left, Vector128<double> right) { throw null; }
public static Vector128<double> CompareNotGreaterThanOrEqualScalar(Vector128<double> left, Vector128<double> right) { throw null; }
- public static Vector128<double> CompareNotLessThan(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static Vector128<double> CompareNotLessThan(Vector128<double> left, Vector128<double> right) { throw null; }
public static Vector128<double> CompareNotLessThanScalar(Vector128<double> left, Vector128<double> right) { throw null; }
- public static Vector128<double> CompareNotLessThanOrEqual(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static Vector128<double> CompareNotLessThanOrEqual(Vector128<double> left, Vector128<double> right) { throw null; }
public static Vector128<double> CompareNotLessThanOrEqualScalar(Vector128<double> left, Vector128<double> right) { throw null; }
- public static Vector128<double> CompareOrdered(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static Vector128<double> CompareOrdered(Vector128<double> left, Vector128<double> right) { throw null; }
public static Vector128<double> CompareOrderedScalar(Vector128<double> left, Vector128<double> right) { throw null; }
- public static Vector128<double> CompareUnordered(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static Vector128<double> CompareUnordered(Vector128<double> left, Vector128<double> right) { throw null; }
public static Vector128<double> CompareUnorderedScalar(Vector128<double> left, Vector128<double> right) { throw null; }
public static double ConvertToDouble(Vector128<double> value) { throw null; }
public static int ConvertToInt32(Vector128<double> value) { throw null; }
@@ -935,23 +913,23 @@ namespace System.Runtime.Intrinsics.X86
public static long ConvertToInt64WithTruncation(Vector128<double> value) { throw null; }
public static uint ConvertToUInt32(Vector128<uint> value) { throw null; }
public static ulong ConvertToUInt64(Vector128<ulong> value) { throw null; }
- public static Vector128<double> ConvertToVector128DoubleScalar(Vector128<double> upper, int value) { throw null; }
- public static Vector128<double> ConvertToVector128DoubleScalar(Vector128<double> upper, long value) { throw null; }
- public static Vector128<double> ConvertToVector128DoubleScalar(Vector128<double> upper, Vector128<float> value) { throw null; }
+ public static Vector128<double> ConvertScalarToVector128Double(Vector128<double> upper, int value) { throw null; }
+ public static Vector128<double> ConvertScalarToVector128Double(Vector128<double> upper, long value) { throw null; }
+ public static Vector128<double> ConvertScalarToVector128Double(Vector128<double> upper, Vector128<float> value) { throw null; }
public static Vector128<int> ConvertToVector128Int32(Vector128<float> value) { throw null; }
public static Vector128<int> ConvertToVector128Int32(Vector128<double> value) { throw null; }
- public static Vector128<int> ConvertToVector128Int32Scalar(int value) { throw null; }
- public static Vector128<long> ConvertToVector128Int64Scalar(long value) { throw null; }
+ public static Vector128<int> ConvertScalarToVector128Int32(int value) { throw null; }
+ public static Vector128<long> ConvertScalarToVector128Int64(long value) { throw null; }
public static Vector128<float> ConvertToVector128Single(Vector128<int> value) { throw null; }
public static Vector128<float> ConvertToVector128Single(Vector128<double> value) { throw null; }
- public static Vector128<float> ConvertToVector128SingleScalar(Vector128<float> upper, Vector128<double> value) { throw null; }
+ public static Vector128<float> ConvertScalarToVector128Single(Vector128<float> upper, Vector128<double> value) { throw null; }
public static Vector128<double> ConvertToVector128Double(Vector128<int> value) { throw null; }
public static Vector128<double> ConvertToVector128Double(Vector128<float> value) { throw null; }
public static Vector128<int> ConvertToVector128Int32WithTruncation(Vector128<float> value) { throw null; }
public static Vector128<int> ConvertToVector128Int32WithTruncation(Vector128<double> value) { throw null; }
- public static Vector128<uint> ConvertToVector128UInt32Scalar(uint value) { throw null; }
- public static Vector128<ulong> ConvertToVector128UInt64Scalar(ulong value) { throw null; }
- public static Vector128<double> Divide(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static Vector128<uint> ConvertScalarToVector128UInt32(uint value) { throw null; }
+ public static Vector128<ulong> ConvertScalarToVector128UInt64(ulong value) { throw null; }
+ public static Vector128<double> Divide(Vector128<double> left, Vector128<double> right) { throw null; }
public static Vector128<double> DivideScalar(Vector128<double> left, Vector128<double> right) { throw null; }
public static short Extract(Vector128<short> value, byte index) { throw null; }
public static ushort Extract(Vector128<ushort> value, byte index) { throw null; }
@@ -975,49 +953,50 @@ namespace System.Runtime.Intrinsics.X86
public static unsafe Vector128<long> LoadAlignedVector128(long* address) { throw null; }
public static unsafe Vector128<ulong> LoadAlignedVector128(ulong* address) { throw null; }
public static unsafe Vector128<double> LoadAlignedVector128(double* address) { throw null; }
- public static unsafe Vector128<double> LoadHigh(Vector128<double> value, double* address) { throw null; }
- public static unsafe Vector128<double> LoadLow(Vector128<double> value, double* address) { throw null; }
- public static unsafe Vector128<sbyte> LoadScalar(sbyte* address) { throw null; }
- public static unsafe Vector128<byte> LoadScalar(byte* address) { throw null; }
- public static unsafe Vector128<short> LoadScalar(short* address) { throw null; }
- public static unsafe Vector128<ushort> LoadScalar(ushort* address) { throw null; }
- public static unsafe Vector128<int> LoadScalar(int* address) { throw null; }
- public static unsafe Vector128<uint> LoadScalar(uint* address) { throw null; }
- public static unsafe Vector128<long> LoadScalar(long* address) { throw null; }
- public static unsafe Vector128<ulong> LoadScalar(ulong* address) { throw null; }
- public static unsafe Vector128<double> LoadScalar(double* address) { throw null; }
- public static unsafe void MaskMove(Vector128<sbyte> source, Vector128<sbyte> mask, sbyte* address) { throw null; }
- public static unsafe void MaskMove(Vector128<byte> source, Vector128<byte> mask, byte* address) { throw null; }
- public static Vector128<byte> Max(Vector128<byte> left, Vector128<byte> right) { throw null; }
- public static Vector128<short> Max(Vector128<short> left, Vector128<short> right) { throw null; }
- public static Vector128<double> Max(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static void LoadFence() { throw null; }
+ public static unsafe Vector128<double> LoadHigh(Vector128<double> lower, double* address) { throw null; }
+ public static unsafe Vector128<double> LoadLow(Vector128<double> upper, double* address) { throw null; }
+ public static unsafe Vector128<int> LoadScalarVector128(int* address) { throw null; }
+ public static unsafe Vector128<uint> LoadScalarVector128(uint* address) { throw null; }
+ public static unsafe Vector128<long> LoadScalarVector128(long* address) { throw null; }
+ public static unsafe Vector128<ulong> LoadScalarVector128(ulong* address) { throw null; }
+ public static unsafe Vector128<double> LoadScalarVector128(double* address) { throw null; }
+ public static unsafe void MaskMove(Vector128<sbyte> source, Vector128<sbyte> mask, sbyte* address) { throw null; }
+ public static unsafe void MaskMove(Vector128<byte> source, Vector128<byte> mask, byte* address) { throw null; }
+ public static Vector128<byte> Max(Vector128<byte> left, Vector128<byte> right) { throw null; }
+ public static Vector128<short> Max(Vector128<short> left, Vector128<short> right) { throw null; }
+ public static Vector128<double> Max(Vector128<double> left, Vector128<double> right) { throw null; }
public static Vector128<double> MaxScalar(Vector128<double> left, Vector128<double> right) { throw null; }
- public static Vector128<byte> Min(Vector128<byte> left, Vector128<byte> right) { throw null; }
- public static Vector128<short> Min(Vector128<short> left, Vector128<short> right) { throw null; }
- public static Vector128<double> Min(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static void MemoryFence() { throw null; }
+ public static Vector128<byte> Min(Vector128<byte> left, Vector128<byte> right) { throw null; }
+ public static Vector128<short> Min(Vector128<short> left, Vector128<short> right) { throw null; }
+ public static Vector128<double> Min(Vector128<double> left, Vector128<double> right) { throw null; }
public static Vector128<double> MinScalar(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static int MoveMask(Vector128<byte> value) { throw null; }
public static int MoveMask(Vector128<sbyte> value) { throw null; }
public static int MoveMask(Vector128<double> value) { throw null; }
+ public static Vector128<long> MoveScalar(Vector128<long> value) { throw null; }
+ public static Vector128<ulong> MoveScalar(Vector128<ulong> value) { throw null; }
public static Vector128<double> MoveScalar(Vector128<double> upper, Vector128<double> value) { throw null; }
- public static Vector128<ulong> Multiply(Vector128<uint> left, Vector128<uint> right) { throw null; }
- public static Vector128<double> Multiply(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static Vector128<ulong> Multiply(Vector128<uint> left, Vector128<uint> right) { throw null; }
+ public static Vector128<double> Multiply(Vector128<double> left, Vector128<double> right) { throw null; }
public static Vector128<double> MultiplyScalar(Vector128<double> left, Vector128<double> right) { throw null; }
- public static Vector128<short> MultiplyHigh(Vector128<short> left, Vector128<short> right) { throw null; }
- public static Vector128<ushort> MultiplyHigh(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
- public static Vector128<int> MultiplyHorizontalAdd(Vector128<short> left, Vector128<short> right) { throw null; }
- public static Vector128<short> MultiplyLow(Vector128<short> left, Vector128<short> right) { throw null; }
- public static Vector128<byte> Or(Vector128<byte> left, Vector128<byte> right) { throw null; }
- public static Vector128<sbyte> Or(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
- public static Vector128<short> Or(Vector128<short> left, Vector128<short> right) { throw null; }
- public static Vector128<ushort> Or(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
- public static Vector128<int> Or(Vector128<int> left, Vector128<int> right) { throw null; }
- public static Vector128<uint> Or(Vector128<uint> left, Vector128<uint> right) { throw null; }
- public static Vector128<long> Or(Vector128<long> left, Vector128<long> right) { throw null; }
- public static Vector128<ulong> Or(Vector128<ulong> left, Vector128<ulong> right) { throw null; }
- public static Vector128<double> Or(Vector128<double> left, Vector128<double> right) { throw null; }
- public static Vector128<sbyte> PackSignedSaturate(Vector128<short> left, Vector128<short> right) { throw null; }
- public static Vector128<short> PackSignedSaturate(Vector128<int> left, Vector128<int> right) { throw null; }
- public static Vector128<byte> PackUnsignedSaturate(Vector128<short> left, Vector128<short> right) { throw null; }
+ public static Vector128<short> MultiplyHigh(Vector128<short> left, Vector128<short> right) { throw null; }
+ public static Vector128<ushort> MultiplyHigh(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
+ public static Vector128<int> MultiplyHorizontalAdd(Vector128<short> left, Vector128<short> right) { throw null; }
+ public static Vector128<short> MultiplyLow(Vector128<short> left, Vector128<short> right) { throw null; }
+ public static Vector128<byte> Or(Vector128<byte> left, Vector128<byte> right) { throw null; }
+ public static Vector128<sbyte> Or(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
+ public static Vector128<short> Or(Vector128<short> left, Vector128<short> right) { throw null; }
+ public static Vector128<ushort> Or(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
+ public static Vector128<int> Or(Vector128<int> left, Vector128<int> right) { throw null; }
+ public static Vector128<uint> Or(Vector128<uint> left, Vector128<uint> right) { throw null; }
+ public static Vector128<long> Or(Vector128<long> left, Vector128<long> right) { throw null; }
+ public static Vector128<ulong> Or(Vector128<ulong> left, Vector128<ulong> right) { throw null; }
+ public static Vector128<double> Or(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static Vector128<sbyte> PackSignedSaturate(Vector128<short> left, Vector128<short> right) { throw null; }
+ public static Vector128<short> PackSignedSaturate(Vector128<int> left, Vector128<int> right) { throw null; }
+ public static Vector128<byte> PackUnsignedSaturate(Vector128<short> left, Vector128<short> right) { throw null; }
public static Vector128<sbyte> SetVector128(sbyte e15, sbyte e14, sbyte e13, sbyte e12, sbyte e11, sbyte e10, sbyte e9, sbyte e8, sbyte e7, sbyte e6, sbyte e5, sbyte e4, sbyte e3, sbyte e2, sbyte e1, sbyte e0) { throw null; }
public static Vector128<byte> SetVector128(byte e15, byte e14, byte e13, byte e12, byte e11, byte e10, byte e9, byte e8, byte e7, byte e6, byte e5, byte e4, byte e3, byte e2, byte e1, byte e0) { throw null; }
public static Vector128<short> SetVector128(short e7, short e6, short e5, short e4, short e3, short e2, short e1, short e0) { throw null; }
@@ -1036,11 +1015,11 @@ namespace System.Runtime.Intrinsics.X86
public static Vector128<long> SetAllVector128(long value) { throw null; }
public static Vector128<ulong> SetAllVector128(ulong value) { throw null; }
public static Vector128<double> SetAllVector128(double value) { throw null; }
- public static Vector128<double> SetScalar(double value) { throw null; }
+ public static Vector128<double> SetScalarVector128(double value) { throw null; }
public static Vector128<T> SetZeroVector128<T>() where T : struct { throw null; }
- public static Vector128<long> SumAbsoluteDifferences(Vector128<byte> left, Vector128<byte> right) { throw null; }
+ public static Vector128<long> SumAbsoluteDifferences(Vector128<byte> left, Vector128<byte> right) { throw null; }
public static Vector128<int> Shuffle(Vector128<int> value, byte control) { throw null; }
- public static Vector128<uint> Shuffle(Vector128<uint> value, byte control) { throw null; }
+ public static Vector128<uint> Shuffle(Vector128<uint> value, byte control) { throw null; }
public static Vector128<double> Shuffle(Vector128<double> left, Vector128<double> right, byte control) { throw null; }
public static Vector128<short> ShuffleHigh(Vector128<short> value, byte control) { throw null; }
public static Vector128<ushort> ShuffleHigh(Vector128<ushort> value, byte control) { throw null; }
@@ -1092,6 +1071,7 @@ namespace System.Runtime.Intrinsics.X86
public static Vector128<ulong> ShiftRightLogical128BitLane(Vector128<ulong> value, byte numBytes) { throw null; }
public static Vector128<double> Sqrt(Vector128<double> value) { throw null; }
public static Vector128<double> SqrtScalar(Vector128<double> value) { throw null; }
+ public static Vector128<double> SqrtScalar(Vector128<double> upper, Vector128<double> value) { throw null; }
public static unsafe void StoreAligned(sbyte* address, Vector128<sbyte> source) { throw null; }
public static unsafe void StoreAligned(byte* address, Vector128<byte> source) { throw null; }
public static unsafe void StoreAligned(short* address, Vector128<short> source) { throw null; }
@@ -1120,51 +1100,55 @@ namespace System.Runtime.Intrinsics.X86
public static unsafe void Store(long* address, Vector128<long> source) { throw null; }
public static unsafe void Store(ulong* address, Vector128<ulong> source) { throw null; }
public static unsafe void Store(double* address, Vector128<double> source) { throw null; }
+ public static unsafe void StoreNonTemporal(int* address, int value) { throw null; }
+ public static unsafe void StoreNonTemporal(uint* address, uint value) { throw null; }
+ public static unsafe void StoreNonTemporal(long* address, long value) { throw null; }
+ public static unsafe void StoreNonTemporal(ulong* address, ulong value) { throw null; }
public static unsafe void StoreHigh(double* address, Vector128<double> source) { throw null; }
public static unsafe void StoreLow(long* address, Vector128<long> source) { throw null; }
public static unsafe void StoreLow(ulong* address, Vector128<ulong> source) { throw null; }
public static unsafe void StoreLow(double* address, Vector128<double> source) { throw null; }
- public static Vector128<byte> Subtract(Vector128<byte> left, Vector128<byte> right) { throw null; }
- public static Vector128<sbyte> Subtract(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
- public static Vector128<short> Subtract(Vector128<short> left, Vector128<short> right) { throw null; }
- public static Vector128<ushort> Subtract(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
- public static Vector128<int> Subtract(Vector128<int> left, Vector128<int> right) { throw null; }
- public static Vector128<uint> Subtract(Vector128<uint> left, Vector128<uint> right) { throw null; }
- public static Vector128<long> Subtract(Vector128<long> left, Vector128<long> right) { throw null; }
- public static Vector128<ulong> Subtract(Vector128<ulong> left, Vector128<ulong> right) { throw null; }
- public static Vector128<double> Subtract(Vector128<double> left, Vector128<double> right) { throw null; }
- public static Vector128<sbyte> SubtractSaturate(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
- public static Vector128<short> SubtractSaturate(Vector128<short> left, Vector128<short> right) { throw null; }
- public static Vector128<byte> SubtractSaturate(Vector128<byte> left, Vector128<byte> right) { throw null; }
- public static Vector128<ushort> SubtractSaturate(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
+ public static Vector128<byte> Subtract(Vector128<byte> left, Vector128<byte> right) { throw null; }
+ public static Vector128<sbyte> Subtract(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
+ public static Vector128<short> Subtract(Vector128<short> left, Vector128<short> right) { throw null; }
+ public static Vector128<ushort> Subtract(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
+ public static Vector128<int> Subtract(Vector128<int> left, Vector128<int> right) { throw null; }
+ public static Vector128<uint> Subtract(Vector128<uint> left, Vector128<uint> right) { throw null; }
+ public static Vector128<long> Subtract(Vector128<long> left, Vector128<long> right) { throw null; }
+ public static Vector128<ulong> Subtract(Vector128<ulong> left, Vector128<ulong> right) { throw null; }
+ public static Vector128<double> Subtract(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static Vector128<sbyte> SubtractSaturate(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
+ public static Vector128<short> SubtractSaturate(Vector128<short> left, Vector128<short> right) { throw null; }
+ public static Vector128<byte> SubtractSaturate(Vector128<byte> left, Vector128<byte> right) { throw null; }
+ public static Vector128<ushort> SubtractSaturate(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
public static Vector128<double> SubtractScalar(Vector128<double> left, Vector128<double> right) { throw null; }
- public static Vector128<byte> UnpackHigh(Vector128<byte> left, Vector128<byte> right) { throw null; }
- public static Vector128<sbyte> UnpackHigh(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
- public static Vector128<short> UnpackHigh(Vector128<short> left, Vector128<short> right) { throw null; }
- public static Vector128<ushort> UnpackHigh(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
- public static Vector128<int> UnpackHigh(Vector128<int> left, Vector128<int> right) { throw null; }
- public static Vector128<uint> UnpackHigh(Vector128<uint> left, Vector128<uint> right) { throw null; }
- public static Vector128<long> UnpackHigh(Vector128<long> left, Vector128<long> right) { throw null; }
- public static Vector128<ulong> UnpackHigh(Vector128<ulong> left, Vector128<ulong> right) { throw null; }
- public static Vector128<double> UnpackHigh(Vector128<double> left, Vector128<double> right) { throw null; }
- public static Vector128<byte> UnpackLow(Vector128<byte> left, Vector128<byte> right) { throw null; }
- public static Vector128<sbyte> UnpackLow(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
- public static Vector128<short> UnpackLow(Vector128<short> left, Vector128<short> right) { throw null; }
- public static Vector128<ushort> UnpackLow(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
- public static Vector128<int> UnpackLow(Vector128<int> left, Vector128<int> right) { throw null; }
- public static Vector128<uint> UnpackLow(Vector128<uint> left, Vector128<uint> right) { throw null; }
- public static Vector128<long> UnpackLow(Vector128<long> left, Vector128<long> right) { throw null; }
- public static Vector128<ulong> UnpackLow(Vector128<ulong> left, Vector128<ulong> right) { throw null; }
- public static Vector128<double> UnpackLow(Vector128<double> left, Vector128<double> right) { throw null; }
- public static Vector128<byte> Xor(Vector128<byte> left, Vector128<byte> right) { throw null; }
- public static Vector128<sbyte> Xor(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
- public static Vector128<short> Xor(Vector128<short> left, Vector128<short> right) { throw null; }
- public static Vector128<ushort> Xor(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
- public static Vector128<int> Xor(Vector128<int> left, Vector128<int> right) { throw null; }
- public static Vector128<uint> Xor(Vector128<uint> left, Vector128<uint> right) { throw null; }
- public static Vector128<long> Xor(Vector128<long> left, Vector128<long> right) { throw null; }
- public static Vector128<ulong> Xor(Vector128<ulong> left, Vector128<ulong> right) { throw null; }
- public static Vector128<double> Xor(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static Vector128<byte> UnpackHigh(Vector128<byte> left, Vector128<byte> right) { throw null; }
+ public static Vector128<sbyte> UnpackHigh(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
+ public static Vector128<short> UnpackHigh(Vector128<short> left, Vector128<short> right) { throw null; }
+ public static Vector128<ushort> UnpackHigh(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
+ public static Vector128<int> UnpackHigh(Vector128<int> left, Vector128<int> right) { throw null; }
+ public static Vector128<uint> UnpackHigh(Vector128<uint> left, Vector128<uint> right) { throw null; }
+ public static Vector128<long> UnpackHigh(Vector128<long> left, Vector128<long> right) { throw null; }
+ public static Vector128<ulong> UnpackHigh(Vector128<ulong> left, Vector128<ulong> right) { throw null; }
+ public static Vector128<double> UnpackHigh(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static Vector128<byte> UnpackLow(Vector128<byte> left, Vector128<byte> right) { throw null; }
+ public static Vector128<sbyte> UnpackLow(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
+ public static Vector128<short> UnpackLow(Vector128<short> left, Vector128<short> right) { throw null; }
+ public static Vector128<ushort> UnpackLow(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
+ public static Vector128<int> UnpackLow(Vector128<int> left, Vector128<int> right) { throw null; }
+ public static Vector128<uint> UnpackLow(Vector128<uint> left, Vector128<uint> right) { throw null; }
+ public static Vector128<long> UnpackLow(Vector128<long> left, Vector128<long> right) { throw null; }
+ public static Vector128<ulong> UnpackLow(Vector128<ulong> left, Vector128<ulong> right) { throw null; }
+ public static Vector128<double> UnpackLow(Vector128<double> left, Vector128<double> right) { throw null; }
+ public static Vector128<byte> Xor(Vector128<byte> left, Vector128<byte> right) { throw null; }
+ public static Vector128<sbyte> Xor(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
+ public static Vector128<short> Xor(Vector128<short> left, Vector128<short> right) { throw null; }
+ public static Vector128<ushort> Xor(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
+ public static Vector128<int> Xor(Vector128<int> left, Vector128<int> right) { throw null; }
+ public static Vector128<uint> Xor(Vector128<uint> left, Vector128<uint> right) { throw null; }
+ public static Vector128<long> Xor(Vector128<long> left, Vector128<long> right) { throw null; }
+ public static Vector128<ulong> Xor(Vector128<ulong> left, Vector128<ulong> right) { throw null; }
+ public static Vector128<double> Xor(Vector128<double> left, Vector128<double> right) { throw null; }
}
public static class Sse3
{
@@ -1202,7 +1186,9 @@ namespace System.Runtime.Intrinsics.X86
public static Vector128<float> Ceiling(Vector128<float> value) { throw null; }
public static Vector128<double> Ceiling(Vector128<double> value) { throw null; }
public static Vector128<double> CeilingScalar(Vector128<double> value) { throw null; }
+ public static Vector128<double> CeilingScalar(Vector128<double> upper, Vector128<double> value) { throw null; }
public static Vector128<float> CeilingScalar(Vector128<float> value) { throw null; }
+ public static Vector128<float> CeilingScalar(Vector128<float> upper, Vector128<float> value) { throw null; }
public static Vector128<long> CompareEqual(Vector128<long> left, Vector128<long> right) { throw null; }
public static Vector128<ulong> CompareEqual(Vector128<ulong> left, Vector128<ulong> right) { throw null; }
public static Vector128<short> ConvertToVector128Int16(Vector128<sbyte> value) { throw null; }
@@ -1229,7 +1215,9 @@ namespace System.Runtime.Intrinsics.X86
public static Vector128<float> Floor(Vector128<float> value) { throw null; }
public static Vector128<double> Floor(Vector128<double> value) { throw null; }
public static Vector128<double> FloorScalar(Vector128<double> value) { throw null; }
+ public static Vector128<double> FloorScalar(Vector128<double> upper, Vector128<double> value) { throw null; }
public static Vector128<float> FloorScalar(Vector128<float> value) { throw null; }
+ public static Vector128<float> FloorScalar(Vector128<float> upper, Vector128<float> value) { throw null; }
public static Vector128<sbyte> Insert(Vector128<sbyte> value, sbyte data, byte index) { throw null; }
public static Vector128<byte> Insert(Vector128<byte> value, byte data, byte index) { throw null; }
public static Vector128<int> Insert(Vector128<int> value, int data, byte index) { throw null; }
@@ -1237,47 +1225,57 @@ namespace System.Runtime.Intrinsics.X86
public static Vector128<long> Insert(Vector128<long> value, long data, byte index) { throw null; }
public static Vector128<ulong> Insert(Vector128<ulong> value, ulong data, byte index) { throw null; }
public static Vector128<float> Insert(Vector128<float> value, float data, byte index) { throw null; }
- public static Vector128<sbyte> Max(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
- public static Vector128<ushort> Max(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
- public static Vector128<int> Max(Vector128<int> left, Vector128<int> right) { throw null; }
- public static Vector128<uint> Max(Vector128<uint> left, Vector128<uint> right) { throw null; }
- public static Vector128<sbyte> Min(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
- public static Vector128<ushort> Min(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
- public static Vector128<int> Min(Vector128<int> left, Vector128<int> right) { throw null; }
- public static Vector128<uint> Min(Vector128<uint> left, Vector128<uint> right) { throw null; }
+ public static Vector128<sbyte> Max(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
+ public static Vector128<ushort> Max(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
+ public static Vector128<int> Max(Vector128<int> left, Vector128<int> right) { throw null; }
+ public static Vector128<uint> Max(Vector128<uint> left, Vector128<uint> right) { throw null; }
+ public static Vector128<sbyte> Min(Vector128<sbyte> left, Vector128<sbyte> right) { throw null; }
+ public static Vector128<ushort> Min(Vector128<ushort> left, Vector128<ushort> right) { throw null; }
+ public static Vector128<int> Min(Vector128<int> left, Vector128<int> right) { throw null; }
+ public static Vector128<uint> Min(Vector128<uint> left, Vector128<uint> right) { throw null; }
public static Vector128<ushort> MinHorizontal(Vector128<ushort> value) { throw null; }
public static Vector128<ushort> MultipleSumAbsoluteDifferences(Vector128<byte> left, Vector128<byte> right, byte mask) { throw null; }
public static Vector128<long> Multiply(Vector128<int> left, Vector128<int> right) { throw null; }
- public static Vector128<int> MultiplyLow(Vector128<int> left, Vector128<int> right) { throw null; }
- public static Vector128<ushort> PackUnsignedSaturate(Vector128<int> left, Vector128<int> right) { throw null; }
+ public static Vector128<int> MultiplyLow(Vector128<int> left, Vector128<int> right) { throw null; }
+ public static Vector128<ushort> PackUnsignedSaturate(Vector128<int> left, Vector128<int> right) { throw null; }
public static Vector128<double> RoundCurrentDirectionScalar(Vector128<double> value) { throw null; }
+ public static Vector128<double> RoundCurrentDirectionScalar(Vector128<double> upper, Vector128<double> value) { throw null; }
public static Vector128<float> RoundCurrentDirectionScalar(Vector128<float> value) { throw null; }
+ public static Vector128<float> RoundCurrentDirectionScalar(Vector128<float> upper, Vector128<float> value) { throw null; }
public static Vector128<float> RoundToNearestInteger(Vector128<float> value) { throw null; }
public static Vector128<double> RoundToNearestIntegerScalar(Vector128<double> value) { throw null; }
+ public static Vector128<double> RoundToNearestIntegerScalar(Vector128<double> upper, Vector128<double> value) { throw null; }
public static Vector128<float> RoundToNearestIntegerScalar(Vector128<float> value) { throw null; }
+ public static Vector128<float> RoundToNearestIntegerScalar(Vector128<float> upper, Vector128<float> value) { throw null; }
public static Vector128<float> RoundToNegativeInfinity(Vector128<float> value) { throw null; }
public static Vector128<double> RoundToNegativeInfinityScalar(Vector128<double> value) { throw null; }
+ public static Vector128<double> RoundToNegativeInfinityScalar(Vector128<double> upper, Vector128<double> value) { throw null; }
public static Vector128<float> RoundToNegativeInfinityScalar(Vector128<float> value) { throw null; }
+ public static Vector128<float> RoundToNegativeInfinityScalar(Vector128<float> upper, Vector128<float> value) { throw null; }
public static Vector128<float> RoundToPositiveInfinity(Vector128<float> value) { throw null; }
public static Vector128<double> RoundToPositiveInfinityScalar(Vector128<double> value) { throw null; }
+ public static Vector128<double> RoundToPositiveInfinityScalar(Vector128<double> upper, Vector128<double> value) { throw null; }
public static Vector128<float> RoundToPositiveInfinityScalar(Vector128<float> value) { throw null; }
+ public static Vector128<float> RoundToPositiveInfinityScalar(Vector128<float> upper, Vector128<float> value) { throw null; }
public static Vector128<float> RoundToZero(Vector128<float> value) { throw null; }
public static Vector128<double> RoundToZeroScalar(Vector128<double> value) { throw null; }
+ public static Vector128<double> RoundToZeroScalar(Vector128<double> upper, Vector128<double> value) { throw null; }
public static Vector128<float> RoundToZeroScalar(Vector128<float> value) { throw null; }
+ public static Vector128<float> RoundToZeroScalar(Vector128<float> upper, Vector128<float> value) { throw null; }
public static Vector128<float> RoundCurrentDirection(Vector128<float> value) { throw null; }
public static Vector128<double> RoundToNearestInteger(Vector128<double> value) { throw null; }
public static Vector128<double> RoundToNegativeInfinity(Vector128<double> value) { throw null; }
public static Vector128<double> RoundToPositiveInfinity(Vector128<double> value) { throw null; }
public static Vector128<double> RoundToZero(Vector128<double> value) { throw null; }
public static Vector128<double> RoundCurrentDirection(Vector128<double> value) { throw null; }
- public static unsafe Vector128<sbyte> LoadAlignedNonTemporal(sbyte* address) { throw null; }
- public static unsafe Vector128<byte> LoadAlignedNonTemporal(byte* address) { throw null; }
- public static unsafe Vector128<short> LoadAlignedNonTemporal(short* address) { throw null; }
- public static unsafe Vector128<ushort> LoadAlignedNonTemporal(ushort* address) { throw null; }
- public static unsafe Vector128<int> LoadAlignedNonTemporal(int* address) { throw null; }
- public static unsafe Vector128<uint> LoadAlignedNonTemporal(uint* address) { throw null; }
- public static unsafe Vector128<long> LoadAlignedNonTemporal(long* address) { throw null; }
- public static unsafe Vector128<ulong> LoadAlignedNonTemporal(ulong* address) { throw null; }
+ public static unsafe Vector128<sbyte> LoadAlignedVector128NonTemporal(sbyte* address) { throw null; }
+ public static unsafe Vector128<byte> LoadAlignedVector128NonTemporal(byte* address) { throw null; }
+ public static unsafe Vector128<short> LoadAlignedVector128NonTemporal(short* address) { throw null; }
+ public static unsafe Vector128<ushort> LoadAlignedVector128NonTemporal(ushort* address) { throw null; }
+ public static unsafe Vector128<int> LoadAlignedVector128NonTemporal(int* address) { throw null; }
+ public static unsafe Vector128<uint> LoadAlignedVector128NonTemporal(uint* address) { throw null; }
+ public static unsafe Vector128<long> LoadAlignedVector128NonTemporal(long* address) { throw null; }
+ public static unsafe Vector128<ulong> LoadAlignedVector128NonTemporal(ulong* address) { throw null; }
public static bool TestAllOnes(Vector128<sbyte> value) { throw null; }
public static bool TestAllOnes(Vector128<byte> value) { throw null; }
public static bool TestAllOnes(Vector128<short> value) { throw null; }
@@ -1330,38 +1328,6 @@ namespace System.Runtime.Intrinsics.X86
public static class Sse42
{
public static bool IsSupported { get { throw null; } }
- public static bool CompareImplicitLength(Vector128<sbyte> left, Vector128<sbyte> right, ResultsFlag flag, StringComparisonMode mode) { throw null; }
- public static bool CompareImplicitLength(Vector128<byte> left, Vector128<byte> right, ResultsFlag flag, StringComparisonMode mode) { throw null; }
- public static bool CompareImplicitLength(Vector128<short> left, Vector128<short> right, ResultsFlag flag, StringComparisonMode mode) { throw null; }
- public static bool CompareImplicitLength(Vector128<ushort> left, Vector128<ushort> right, ResultsFlag flag, StringComparisonMode mode) { throw null; }
- public static bool CompareExplicitLength(Vector128<sbyte> left, byte leftLength, Vector128<sbyte> right, byte rightLength, ResultsFlag flag, StringComparisonMode mode) { throw null; }
- public static bool CompareExplicitLength(Vector128<byte> left, byte leftLength, Vector128<byte> right, byte rightLength, ResultsFlag flag, StringComparisonMode mode) { throw null; }
- public static bool CompareExplicitLength(Vector128<short> left, byte leftLength, Vector128<short> right, byte rightLength, ResultsFlag flag, StringComparisonMode mode) { throw null; }
- public static bool CompareExplicitLength(Vector128<ushort> left, byte leftLength, Vector128<ushort> right, byte rightLength, ResultsFlag flag, StringComparisonMode mode) { throw null; }
- public static int CompareImplicitLengthIndex(Vector128<sbyte> left, Vector128<sbyte> right, StringComparisonMode mode) { throw null; }
- public static int CompareImplicitLengthIndex(Vector128<byte> left, Vector128<byte> right, StringComparisonMode mode) { throw null; }
- public static int CompareImplicitLengthIndex(Vector128<short> left, Vector128<short> right, StringComparisonMode mode) { throw null; }
- public static int CompareImplicitLengthIndex(Vector128<ushort> left, Vector128<ushort> right, StringComparisonMode mode) { throw null; }
- public static int CompareExplicitLengthIndex(Vector128<sbyte> left, byte leftLength, Vector128<sbyte> right, byte rightLength, StringComparisonMode mode) { throw null; }
- public static int CompareExplicitLengthIndex(Vector128<byte> left, byte leftLength, Vector128<byte> right, byte rightLength, StringComparisonMode mode) { throw null; }
- public static int CompareExplicitLengthIndex(Vector128<short> left, byte leftLength, Vector128<short> right, byte rightLength, StringComparisonMode mode) { throw null; }
- public static int CompareExplicitLengthIndex(Vector128<ushort> left, byte leftLength, Vector128<ushort> right, byte rightLength, StringComparisonMode mode) { throw null; }
- public static Vector128<ushort> CompareImplicitLengthBitMask(Vector128<sbyte> left, Vector128<sbyte> right, StringComparisonMode mode) { throw null; }
- public static Vector128<ushort> CompareImplicitLengthBitMask(Vector128<byte> left, Vector128<byte> right, StringComparisonMode mode) { throw null; }
- public static Vector128<byte> CompareImplicitLengthBitMask(Vector128<short> left, Vector128<short> right, StringComparisonMode mode) { throw null; }
- public static Vector128<byte> CompareImplicitLengthBitMask(Vector128<ushort> left, Vector128<ushort> right, StringComparisonMode mode) { throw null; }
- public static Vector128<byte> CompareImplicitLengthUnitMask(Vector128<sbyte> left, Vector128<sbyte> right, StringComparisonMode mode) { throw null; }
- public static Vector128<byte> CompareImplicitLengthUnitMask(Vector128<byte> left, Vector128<byte> right, StringComparisonMode mode) { throw null; }
- public static Vector128<ushort> CompareImplicitLengthUnitMask(Vector128<short> left, Vector128<short> right, StringComparisonMode mode) { throw null; }
- public static Vector128<ushort> CompareImplicitLengthUnitMask(Vector128<ushort> left, Vector128<ushort> right, StringComparisonMode mode) { throw null; }
- public static Vector128<ushort> CompareExplicitLengthBitMask(Vector128<sbyte> left, byte leftLength, Vector128<sbyte> right, byte rightLength, StringComparisonMode mode) { throw null; }
- public static Vector128<ushort> CompareExplicitLengthBitMask(Vector128<byte> left, byte leftLength, Vector128<byte> right, byte rightLength, StringComparisonMode mode) { throw null; }
- public static Vector128<byte> CompareExplicitLengthBitMask(Vector128<short> left, byte leftLength, Vector128<short> right, byte rightLength, StringComparisonMode mode) { throw null; }
- public static Vector128<byte> CompareExplicitLengthBitMask(Vector128<ushort> left, byte leftLength, Vector128<ushort> right, byte rightLength, StringComparisonMode mode) { throw null; }
- public static Vector128<byte> CompareExplicitLengthUnitMask(Vector128<sbyte> left, byte leftLength, Vector128<sbyte> right, byte rightLength, StringComparisonMode mode) { throw null; }
- public static Vector128<byte> CompareExplicitLengthUnitMask(Vector128<byte> left, byte leftLength, Vector128<byte> right, byte rightLength, StringComparisonMode mode) { throw null; }
- public static Vector128<ushort> CompareExplicitLengthUnitMask(Vector128<short> left, byte leftLength, Vector128<short> right, byte rightLength, StringComparisonMode mode) { throw null; }
- public static Vector128<ushort> CompareExplicitLengthUnitMask(Vector128<ushort> left, byte leftLength, Vector128<ushort> right, byte rightLength, StringComparisonMode mode) { throw null; }
public static Vector128<long> CompareGreaterThan(Vector128<long> left, Vector128<long> right) { throw null; }
public static uint Crc32(uint crc, byte data) { throw null; }
public static uint Crc32(uint crc, ushort data) { throw null; }
diff --git a/src/System.Runtime.Intrinsics/src/Configurations.props b/src/System.Runtime.Intrinsics.Experimental/src/Configurations.props
index e75400d142..e75400d142 100644
--- a/src/System.Runtime.Intrinsics/src/Configurations.props
+++ b/src/System.Runtime.Intrinsics.Experimental/src/Configurations.props
diff --git a/src/System.Runtime.Intrinsics/src/System.Runtime.Intrinsics.csproj b/src/System.Runtime.Intrinsics.Experimental/src/System.Runtime.Intrinsics.Experimental.csproj
index 548805ab48..273ed07308 100644
--- a/src/System.Runtime.Intrinsics/src/System.Runtime.Intrinsics.csproj
+++ b/src/System.Runtime.Intrinsics.Experimental/src/System.Runtime.Intrinsics.Experimental.csproj
@@ -2,7 +2,7 @@
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
- <AssemblyName>System.Runtime.Intrinsics</AssemblyName>
+ <AssemblyName>System.Runtime.Intrinsics.Experimental</AssemblyName>
<IsPartialFacadeAssembly>true</IsPartialFacadeAssembly>
<ProjectGuid>{543FBFE5-E9E4-4631-8242-911A707FE818}</ProjectGuid>
</PropertyGroup>
diff --git a/src/System.Runtime.Loader/System.Runtime.Loader.sln b/src/System.Runtime.Loader/System.Runtime.Loader.sln
index 2884525c90..270ede3878 100644
--- a/src/System.Runtime.Loader/System.Runtime.Loader.sln
+++ b/src/System.Runtime.Loader/System.Runtime.Loader.sln
@@ -22,7 +22,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Runtime.Loader.Noop.
{485A65F0-51C9-4B95-A7A8-A4860C231E67} = {485A65F0-51C9-4B95-A7A8-A4860C231E67}
EndProjectSection
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Runtime.Loader.Test.Assembly", "tests\System.Runtime.Loader.Test.Assembly\System.Runtime.Loader.Test.Assembly.csproj", "{396D6EBF-60BD-4DAF-8783-FB403E070A56}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Runtime.Loader.Test.Assembly", "tests\System.Runtime.Loader.Test.Assembly\System.Runtime.Loader.Test.Assembly.csproj", "{E3C33774-AA3D-4CED-A7A6-BDF9A7F100DF}"
ProjectSection(ProjectDependencies) = postProject
{485A65F0-51C9-4B95-A7A8-A4860C231E67} = {485A65F0-51C9-4B95-A7A8-A4860C231E67}
EndProjectSection
@@ -62,10 +62,10 @@ Global
{396D6EBF-60BD-4DAF-8783-FB403E070A57}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
{396D6EBF-60BD-4DAF-8783-FB403E070A57}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
{396D6EBF-60BD-4DAF-8783-FB403E070A57}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
- {396D6EBF-60BD-4DAF-8783-FB403E070A56}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
- {396D6EBF-60BD-4DAF-8783-FB403E070A56}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
- {396D6EBF-60BD-4DAF-8783-FB403E070A56}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
- {396D6EBF-60BD-4DAF-8783-FB403E070A56}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
+ {E3C33774-AA3D-4CED-A7A6-BDF9A7F100DF}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
+ {E3C33774-AA3D-4CED-A7A6-BDF9A7F100DF}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
+ {E3C33774-AA3D-4CED-A7A6-BDF9A7F100DF}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
+ {E3C33774-AA3D-4CED-A7A6-BDF9A7F100DF}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
{485A65F0-51C9-4B95-A7A8-A4860C231E67}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU
{485A65F0-51C9-4B95-A7A8-A4860C231E67}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
{485A65F0-51C9-4B95-A7A8-A4860C231E67}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
@@ -83,7 +83,7 @@ Global
{701CB3BC-00DC-435D-BDE4-C5FC29A708A8} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
{701CB3BC-00DC-435D-BDE4-C5FC29A708A9} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
{396D6EBF-60BD-4DAF-8783-FB403E070A57} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
- {396D6EBF-60BD-4DAF-8783-FB403E070A56} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
+ {E3C33774-AA3D-4CED-A7A6-BDF9A7F100DF} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
{485A65F0-51C9-4B95-A7A8-A4860C231E67} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD}
{FB507A82-ACDD-4809-A030-6F9372A71194} = {2E666815-2EDB-464B-9DF6-380BF4789AD4}
EndGlobalSection
diff --git a/src/System.Runtime.Loader/tests/System.Runtime.Loader.Test.Assembly/System.Runtime.Loader.Test.Assembly.csproj b/src/System.Runtime.Loader/tests/System.Runtime.Loader.Test.Assembly/System.Runtime.Loader.Test.Assembly.csproj
index 12c34c5bbb..285161427f 100644
--- a/src/System.Runtime.Loader/tests/System.Runtime.Loader.Test.Assembly/System.Runtime.Loader.Test.Assembly.csproj
+++ b/src/System.Runtime.Loader/tests/System.Runtime.Loader.Test.Assembly/System.Runtime.Loader.Test.Assembly.csproj
@@ -2,7 +2,7 @@
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
- <ProjectGuid>{396D6EBF-60BD-4DAF-8783-FB403E070A56}</ProjectGuid>
+ <ProjectGuid>{E3C33774-AA3D-4CED-A7A6-BDF9A7F100DF}</ProjectGuid>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
diff --git a/src/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj b/src/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj
index f017bb6b57..0e853f79dc 100644
--- a/src/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj
+++ b/src/System.Runtime.Numerics/src/System.Runtime.Numerics.csproj
@@ -29,8 +29,8 @@
<Compile Include="$(CommonPath)\System\Globalization\FormatProvider.Number.cs">
<Link>System\Globalization\FormatProvider.Number.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Text\ValueStringBuilder.cs">
- <Link>System\Text\ValueStringBuilder.cs</Link>
+ <Compile Include="$(CommonPath)\CoreLib\System\Text\ValueStringBuilder.cs">
+ <Link>CoreLib\System\Text\ValueStringBuilder.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
diff --git a/src/System.Runtime.Numerics/src/System/Numerics/BigNumber.cs b/src/System.Runtime.Numerics/src/System/Numerics/BigNumber.cs
index 8361b744a2..ccea174b33 100644
--- a/src/System.Runtime.Numerics/src/System/Numerics/BigNumber.cs
+++ b/src/System.Runtime.Numerics/src/System/Numerics/BigNumber.cs
@@ -330,7 +330,7 @@ namespace System.Numerics
return false;
}
- return TryParseBigInteger(value.AsReadOnlySpan(), style, info, out result);
+ return TryParseBigInteger(value.AsSpan(), style, info, out result);
}
internal static bool TryParseBigInteger(ReadOnlySpan<char> value, NumberStyles style, NumberFormatInfo info, out BigInteger result)
@@ -371,7 +371,7 @@ namespace System.Numerics
throw new ArgumentNullException(nameof(value));
}
- return ParseBigInteger(value.AsReadOnlySpan(), style, info);
+ return ParseBigInteger(value.AsSpan(), style, info);
}
internal static BigInteger ParseBigInteger(ReadOnlySpan<char> value, NumberStyles style, NumberFormatInfo info)
diff --git a/src/System.Runtime.Numerics/tests/BigInteger/parse.netcoreapp.cs b/src/System.Runtime.Numerics/tests/BigInteger/parse.netcoreapp.cs
index 31650dd358..593fc5f8b7 100644
--- a/src/System.Runtime.Numerics/tests/BigInteger/parse.netcoreapp.cs
+++ b/src/System.Runtime.Numerics/tests/BigInteger/parse.netcoreapp.cs
@@ -13,26 +13,26 @@ namespace System.Numerics.Tests
{
if (failureNotExpected)
{
- Eval(BigInteger.Parse(num1.AsReadOnlySpan(), ns), expected);
+ Eval(BigInteger.Parse(num1.AsSpan(), ns), expected);
- Assert.True(BigInteger.TryParse(num1.AsReadOnlySpan(), ns, provider: null, out BigInteger test));
+ Assert.True(BigInteger.TryParse(num1.AsSpan(), ns, provider: null, out BigInteger test));
Eval(test, expected);
if (ns == NumberStyles.Integer)
{
- Assert.True(BigInteger.TryParse(num1.AsReadOnlySpan(), out test));
+ Assert.True(BigInteger.TryParse(num1.AsSpan(), out test));
Eval(test, expected);
}
}
else
{
- Assert.Throws<FormatException>(() => { BigInteger.Parse(num1.AsReadOnlySpan(), ns); });
+ Assert.Throws<FormatException>(() => { BigInteger.Parse(num1.AsSpan(), ns); });
- Assert.False(BigInteger.TryParse(num1.AsReadOnlySpan(), ns, provider: null, out BigInteger test));
+ Assert.False(BigInteger.TryParse(num1.AsSpan(), ns, provider: null, out BigInteger test));
if (ns == NumberStyles.Integer)
{
- Assert.False(BigInteger.TryParse(num1.AsReadOnlySpan(), out test));
+ Assert.False(BigInteger.TryParse(num1.AsSpan(), out test));
}
}
}
@@ -41,14 +41,14 @@ namespace System.Numerics.Tests
{
if (!failureExpected)
{
- Assert.Equal(expected, BigInteger.Parse(num1.AsReadOnlySpan(), provider: nfi));
- Assert.True(BigInteger.TryParse(num1.AsReadOnlySpan(), NumberStyles.Any, nfi, out BigInteger test));
+ Assert.Equal(expected, BigInteger.Parse(num1.AsSpan(), provider: nfi));
+ Assert.True(BigInteger.TryParse(num1.AsSpan(), NumberStyles.Any, nfi, out BigInteger test));
Assert.Equal(expected, test);
}
else
{
- Assert.Throws<FormatException>(() => { BigInteger.Parse(num1.AsReadOnlySpan(), provider: nfi); });
- Assert.False(BigInteger.TryParse(num1.AsReadOnlySpan(), NumberStyles.Any, nfi, out BigInteger test), String.Format("Expected TryParse to fail on {0}", num1));
+ Assert.Throws<FormatException>(() => { BigInteger.Parse(num1.AsSpan(), provider: nfi); });
+ Assert.False(BigInteger.TryParse(num1.AsSpan(), NumberStyles.Any, nfi, out BigInteger test), String.Format("Expected TryParse to fail on {0}", num1));
}
}
@@ -56,14 +56,14 @@ namespace System.Numerics.Tests
{
if (!failureExpected)
{
- Assert.Equal(expected, BigInteger.Parse(num1.AsReadOnlySpan(), ns, nfi));
- Assert.True(BigInteger.TryParse(num1.AsReadOnlySpan(), NumberStyles.Any, nfi, out BigInteger test));
+ Assert.Equal(expected, BigInteger.Parse(num1.AsSpan(), ns, nfi));
+ Assert.True(BigInteger.TryParse(num1.AsSpan(), NumberStyles.Any, nfi, out BigInteger test));
Assert.Equal(expected, test);
}
else
{
- Assert.Throws<FormatException>(() => { BigInteger.Parse(num1.AsReadOnlySpan(), ns, nfi); });
- Assert.False(BigInteger.TryParse(num1.AsReadOnlySpan(), ns, nfi, out BigInteger test), String.Format("Expected TryParse to fail on {0}", num1));
+ Assert.Throws<FormatException>(() => { BigInteger.Parse(num1.AsSpan(), ns, nfi); });
+ Assert.False(BigInteger.TryParse(num1.AsSpan(), ns, nfi, out BigInteger test), String.Format("Expected TryParse to fail on {0}", num1));
}
}
}
diff --git a/src/System.Runtime.Serialization.Formatters/src/MatchingRefApiCompatBaseline.txt b/src/System.Runtime.Serialization.Formatters/src/MatchingRefApiCompatBaseline.txt
new file mode 100644
index 0000000000..87f8d5ca0f
--- /dev/null
+++ b/src/System.Runtime.Serialization.Formatters/src/MatchingRefApiCompatBaseline.txt
@@ -0,0 +1,3 @@
+# Exposed publicly only in implementation for serialization compat
+TypesMustExist : Type 'System.Runtime.Serialization.SerializationEventHandler' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.Runtime.Serialization.TypeLoadExceptionHolder' does not exist in the implementation but it does exist in the contract.
diff --git a/src/System.Runtime.Serialization.Formatters/src/Resources/Strings.resx b/src/System.Runtime.Serialization.Formatters/src/Resources/Strings.resx
index 8311d78104..4a01b4fadc 100644
--- a/src/System.Runtime.Serialization.Formatters/src/Resources/Strings.resx
+++ b/src/System.Runtime.Serialization.Formatters/src/Resources/Strings.resx
@@ -58,6 +58,9 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
+ <data name="Arg_HTCapacityOverflow" xml:space="preserve">
+ <value>Capacity overflowed and went negative.</value>
+ </data>
<data name="Serialization_NonSerType" xml:space="preserve">
<value>Type '{0}' in Assembly '{1}' is not marked as serializable.</value>
</data>
diff --git a/src/System.Runtime.Serialization.Formatters/src/System.Runtime.Serialization.Formatters.csproj b/src/System.Runtime.Serialization.Formatters/src/System.Runtime.Serialization.Formatters.csproj
index 7752ff9879..ae432a86ca 100644
--- a/src/System.Runtime.Serialization.Formatters/src/System.Runtime.Serialization.Formatters.csproj
+++ b/src/System.Runtime.Serialization.Formatters/src/System.Runtime.Serialization.Formatters.csproj
@@ -61,6 +61,9 @@
<Compile Include="System\Runtime\Serialization\Formatters\Binary\BinaryObjectWriter.cs" />
<Compile Include="System\Runtime\Serialization\Formatters\Binary\BinaryParser.cs" />
<Compile Include="System\Runtime\Serialization\Formatters\Binary\BinaryUtilClasses.cs" />
+ <Compile Include="$(CommonPath)\System\Collections\HashHelpers.cs">
+ <Link>Common\System\Collections\HashHelpers.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup>
<Reference Include="System.Collections" />
@@ -77,4 +80,4 @@
<EmbeddedResource Include="Resources\System.Runtime.Serialization.Formatters.rd.xml" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/ObjectIDGenerator.cs b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/ObjectIDGenerator.cs
index fab0a64183..8d70b5e190 100644
--- a/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/ObjectIDGenerator.cs
+++ b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/ObjectIDGenerator.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Collections;
using System.Runtime.CompilerServices;
namespace System.Runtime.Serialization
@@ -11,24 +12,16 @@ namespace System.Runtime.Serialization
{
private const int NumBins = 4;
- // Table of prime numbers to use as hash table sizes. Each entry is the
- // smallest prime number larger than twice the previous entry.
- private static readonly int[] s_sizes =
- {
- 5, 11, 29, 47, 97, 197, 397, 797, 1597, 3203, 6421, 12853, 25717, 51437,
- 102877, 205759, 411527, 823117, 1646237, 3292489, 6584983
- };
-
internal int _currentCount;
- internal int _currentSize;
- internal long[] _ids;
- internal object[] _objs;
+ private int _currentSize;
+ private long[] _ids;
+ private object[] _objs;
// Constructs a new ObjectID generator, initializing all of the necessary variables.
public ObjectIDGenerator()
{
_currentCount = 1;
- _currentSize = s_sizes[0];
+ _currentSize = HashHelpers.primes[0]; // Starting with 3
_ids = new long[_currentSize * NumBins];
_objs = new object[_currentSize * NumBins];
}
@@ -107,13 +100,12 @@ namespace System.Runtime.Serialization
// we return that id, otherwise we return 0.
public virtual long HasId(object obj, out bool firstTime)
{
- bool found;
-
if (obj == null)
{
throw new ArgumentNullException(nameof(obj));
}
+ bool found;
int pos = FindElement(obj, out found);
if (found)
{
@@ -130,14 +122,14 @@ namespace System.Runtime.Serialization
// the old arrays into the new ones. Expensive but necessary.
private void Rehash()
{
- int i = 0;
- for (int currSize = _currentSize; i < s_sizes.Length && s_sizes[i] <= currSize; i++) ;
- if (i == s_sizes.Length)
+ int currSize = _currentSize;
+ int newSize = HashHelpers.ExpandPrime(currSize);
+ if (newSize == currSize)
{
// We just walked off the end of the array.
throw new SerializationException(SR.Serialization_TooManyElements);
}
- _currentSize = s_sizes[i];
+ _currentSize = newSize;
long[] newIds = new long[_currentSize * NumBins];
object[] newObjs = new object[_currentSize * NumBins];
@@ -152,8 +144,7 @@ namespace System.Runtime.Serialization
{
if (oldObjs[j] != null)
{
- bool found;
- int pos = FindElement(oldObjs[j], out found);
+ int pos = FindElement(oldObjs[j], out _);
_objs[pos] = oldObjs[j];
_ids[pos] = oldIds[j];
}
diff --git a/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/SurrogateSelector.cs b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/SurrogateSelector.cs
index 82078ef303..5f150f5f0a 100644
--- a/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/SurrogateSelector.cs
+++ b/src/System.Runtime.Serialization.Formatters/src/System/Runtime/Serialization/SurrogateSelector.cs
@@ -67,7 +67,7 @@ namespace System.Runtime.Serialization
// Verify that we don't try and add ourself twice.
if (selector == this)
{
- throw new SerializationException(SR.Serialization_DuplicateSelector);
+ throw new SerializationException(SR.Serialization_SurrogateCycle);
}
// Verify that the argument doesn't contain a cycle.
diff --git a/src/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTestData.cs b/src/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTestData.cs
index 9d15e2597a..2269ed6e13 100644
--- a/src/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTestData.cs
+++ b/src/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTestData.cs
@@ -6,6 +6,7 @@ using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
+using System.Common.Tests;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.ComponentModel.DataAnnotations;
@@ -58,24 +59,15 @@ namespace System.Runtime.Serialization.Formatters.Tests
public partial class BinaryFormatterTests
{
private static DateTime s_fixedTimestamp = DateTime.Parse("11/3/1989 04:50:29 AM", CultureInfo.InvariantCulture.DateTimeFormat);
-
// *** AUTO UPDATED BLOBS ***
public static IEnumerable<object[]> SerializableObjects_MemberData()
{
// Save old culture and set a fixed culture for object instantiation
- CultureInfo oldCulture = CultureInfo.CurrentCulture;
-
- try
+ using (new ThreadCultureChange(CultureInfo.InvariantCulture))
{
- CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
return SerializableObjects().ToArray();
}
- finally
- {
- // Revert setting a fixed culture
- CultureInfo.CurrentCulture = oldCulture;
- }
}
/// <summary>
@@ -86,11 +78,11 @@ namespace System.Runtime.Serialization.Formatters.Tests
public static IEnumerable<object[]> SerializableEqualityComparers_MemberData()
{
// Internal specialized equality comparers
- yield return new object[] { EqualityComparer<UInt32Enum>.Default, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAOEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuVUludDMyRW51bSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAAAAAAs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAOEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuVUludDMyRW51bSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAAAAAAs=" } };
- yield return new object[] { EqualityComparer<Int64Enum>.Default, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAOABU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuSW50NjRFbnVtLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0AAAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAOABU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuSW50NjRFbnVtLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0AAAAACw==" } };
- yield return new object[] { EqualityComparer<UInt64Enum>.Default, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAOEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuVUludDY0RW51bSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAAAAAAs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAOEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuVUludDY0RW51bSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAAAAAAs=" } };
- yield return new object[] { EqualityComparer<SByteEnum>.Default, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAOABU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU0J5dGVFbnVtLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0AAAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAOABU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU0J5dGVFbnVtLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0AAAAACw==" } };
- yield return new object[] { EqualityComparer<Int16Enum>.Default, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAOABU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuSW50MTZFbnVtLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0AAAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAOABU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuSW50MTZFbnVtLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0AAAAACw==" } };
+ yield return new object[] { EqualityComparer<UInt32Enum>.Default, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuVUludDMyRW51bSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAAAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuVUludDMyRW51bSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAAAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { EqualityComparer<Int64Enum>.Default, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOABU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuSW50NjRFbnVtLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0AAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOABU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuSW50NjRFbnVtLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0AAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { EqualityComparer<UInt64Enum>.Default, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuVUludDY0RW51bSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAAAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuVUludDY0RW51bSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAAAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { EqualityComparer<SByteEnum>.Default, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOABU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU0J5dGVFbnVtLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0AAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOABU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU0J5dGVFbnVtLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0AAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { EqualityComparer<Int16Enum>.Default, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOABU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuSW50MTZFbnVtLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0AAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOABU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuSW50MTZFbnVtLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0AAAAACw==", TargetFrameworkMoniker.netfx461) } };
}
/// <summary>
@@ -101,107 +93,107 @@ namespace System.Runtime.Serialization.Formatters.Tests
private static IEnumerable<object[]> SerializableObjects()
{
// Primitive types
- yield return new object[] { byte.MinValue, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAAtTeXN0ZW0uQnl0ZQEAAAAHbV92YWx1ZQACAAs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAAtTeXN0ZW0uQnl0ZQEAAAAHbV92YWx1ZQACAAs=" } };
- yield return new object[] { byte.MaxValue, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAAtTeXN0ZW0uQnl0ZQEAAAAHbV92YWx1ZQAC/ws=", "AAEAAAD/////AQAAAAAAAAAEAQAAAAtTeXN0ZW0uQnl0ZQEAAAAHbV92YWx1ZQAC/ws=" } };
- yield return new object[] { sbyte.MinValue, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uU0J5dGUBAAAAB21fdmFsdWUACoAL", "AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uU0J5dGUBAAAAB21fdmFsdWUACoAL" } };
- yield return new object[] { sbyte.MaxValue, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uU0J5dGUBAAAAB21fdmFsdWUACn8L", "AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uU0J5dGUBAAAAB21fdmFsdWUACn8L" } };
- yield return new object[] { short.MinValue, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50MTYBAAAAB21fdmFsdWUABwCACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50MTYBAAAAB21fdmFsdWUABwCACw==" } };
- yield return new object[] { short.MaxValue, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50MTYBAAAAB21fdmFsdWUAB/9/Cw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50MTYBAAAAB21fdmFsdWUAB/9/Cw==" } };
- yield return new object[] { ushort.MinValue, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uVUludDE2AQAAAAdtX3ZhbHVlAA4AAAs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uVUludDE2AQAAAAdtX3ZhbHVlAA4AAAs=" } };
- yield return new object[] { ushort.MaxValue, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uVUludDE2AQAAAAdtX3ZhbHVlAA7//ws=", "AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uVUludDE2AQAAAAdtX3ZhbHVlAA7//ws=" } };
- yield return new object[] { int.MinValue, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50MzIBAAAAB21fdmFsdWUACAAAAIAL", "AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50MzIBAAAAB21fdmFsdWUACAAAAIAL" } };
- yield return new object[] { int.MaxValue, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50MzIBAAAAB21fdmFsdWUACP///38L", "AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50MzIBAAAAB21fdmFsdWUACP///38L" } };
- yield return new object[] { uint.MinValue, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uVUludDMyAQAAAAdtX3ZhbHVlAA8AAAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uVUludDMyAQAAAAdtX3ZhbHVlAA8AAAAACw==" } };
- yield return new object[] { uint.MaxValue, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uVUludDMyAQAAAAdtX3ZhbHVlAA//////Cw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uVUludDMyAQAAAAdtX3ZhbHVlAA//////Cw==" } };
- yield return new object[] { long.MinValue, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50NjQBAAAAB21fdmFsdWUACQAAAAAAAACACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50NjQBAAAAB21fdmFsdWUACQAAAAAAAACACw==" } };
- yield return new object[] { long.MaxValue, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50NjQBAAAAB21fdmFsdWUACf////////9/Cw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50NjQBAAAAB21fdmFsdWUACf////////9/Cw==" } };
- yield return new object[] { ulong.MinValue, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uVUludDY0AQAAAAdtX3ZhbHVlABAAAAAAAAAAAAs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uVUludDY0AQAAAAdtX3ZhbHVlABAAAAAAAAAAAAs=" } };
- yield return new object[] { ulong.MaxValue, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uVUludDY0AQAAAAdtX3ZhbHVlABD//////////ws=", "AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uVUludDY0AQAAAAdtX3ZhbHVlABD//////////ws=" } };
- yield return new object[] { char.MinValue, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAAtTeXN0ZW0uQ2hhcgEAAAAHbV92YWx1ZQADAAs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAAtTeXN0ZW0uQ2hhcgEAAAAHbV92YWx1ZQADAAs=" } };
- yield return new object[] { char.MaxValue, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAAtTeXN0ZW0uQ2hhcgEAAAAHbV92YWx1ZQAD77+/Cw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAAtTeXN0ZW0uQ2hhcgEAAAAHbV92YWx1ZQAD77+/Cw==" } };
- yield return new object[] { float.MinValue, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uU2luZ2xlAQAAAAdtX3ZhbHVlAAv//3//Cw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uU2luZ2xlAQAAAAdtX3ZhbHVlAAv//3//Cw==" } };
- yield return new object[] { float.MaxValue, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uU2luZ2xlAQAAAAdtX3ZhbHVlAAv//39/Cw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uU2luZ2xlAQAAAAdtX3ZhbHVlAAv//39/Cw==" } };
- yield return new object[] { double.MinValue, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uRG91YmxlAQAAAAdtX3ZhbHVlAAb////////v/ws=", "AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uRG91YmxlAQAAAAdtX3ZhbHVlAAb////////v/ws=" } };
- yield return new object[] { double.MaxValue, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uRG91YmxlAQAAAAdtX3ZhbHVlAAb////////vfws=", "AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uRG91YmxlAQAAAAdtX3ZhbHVlAAb////////vfws=" } };
- yield return new object[] { decimal.MinValue, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uRGVjaW1hbAQAAAAFZmxhZ3MCaGkCbG8DbWlkAAAAAAgICAgAAACA////////////////Cw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uRGVjaW1hbAQAAAAFZmxhZ3MCaGkCbG8DbWlkAAAAAAgICAgAAACA////////////////Cw==" } };
- yield return new object[] { decimal.MaxValue, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uRGVjaW1hbAQAAAAFZmxhZ3MCaGkCbG8DbWlkAAAAAAgICAgAAAAA////////////////Cw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uRGVjaW1hbAQAAAAFZmxhZ3MCaGkCbG8DbWlkAAAAAAgICAgAAAAA////////////////Cw==" } };
- yield return new object[] { decimal.MinusOne, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uRGVjaW1hbAQAAAAFZmxhZ3MCaGkCbG8DbWlkAAAAAAgICAgAAACAAAAAAAEAAAAAAAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uRGVjaW1hbAQAAAAFZmxhZ3MCaGkCbG8DbWlkAAAAAAgICAgAAACAAAAAAAEAAAAAAAAACw==" } };
- yield return new object[] { true, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uQm9vbGVhbgEAAAAHbV92YWx1ZQABAQs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uQm9vbGVhbgEAAAAHbV92YWx1ZQABAQs=" } };
- yield return new object[] { false, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uQm9vbGVhbgEAAAAHbV92YWx1ZQABAAs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uQm9vbGVhbgEAAAAHbV92YWx1ZQABAAs=" } };
- yield return new object[] { "", new string[] { "AAEAAAD/////AQAAAAAAAAAGAQAAAAAL", "AAEAAAD/////AQAAAAAAAAAGAQAAAAAL" } };
- yield return new object[] { "c", new string[] { "AAEAAAD/////AQAAAAAAAAAGAQAAAAFjCw==", "AAEAAAD/////AQAAAAAAAAAGAQAAAAFjCw==" } };
- yield return new object[] { "\u4F60\u597D", new string[] { "AAEAAAD/////AQAAAAAAAAAGAQAAAAbkvaDlpb0L", "AAEAAAD/////AQAAAAAAAAAGAQAAAAbkvaDlpb0L" } };
- yield return new object[] { "some\0data\0with\0null\0chars", new string[] { "AAEAAAD/////AQAAAAAAAAAGAQAAABlzb21lAGRhdGEAd2l0aABudWxsAGNoYXJzCw==", "AAEAAAD/////AQAAAAAAAAAGAQAAABlzb21lAGRhdGEAd2l0aABudWxsAGNoYXJzCw==" } };
- yield return new object[] { "<>&\"\'", new string[] { "AAEAAAD/////AQAAAAAAAAAGAQAAAAU8PiYiJws=", "AAEAAAD/////AQAAAAAAAAAGAQAAAAU8PiYiJws=" } };
- yield return new object[] { " < ", new string[] { "AAEAAAD/////AQAAAAAAAAAGAQAAAAMgPCAL", "AAEAAAD/////AQAAAAAAAAAGAQAAAAMgPCAL" } };
- yield return new object[] { "minchar" + char.MinValue + "minchar", new string[] { "AAEAAAD/////AQAAAAAAAAAGAQAAAA9taW5jaGFyAG1pbmNoYXIL", "AAEAAAD/////AQAAAAAAAAAGAQAAAA9taW5jaGFyAG1pbmNoYXIL" } };
+ yield return new object[] { byte.MinValue, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAtTeXN0ZW0uQnl0ZQEAAAAHbV92YWx1ZQACAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAtTeXN0ZW0uQnl0ZQEAAAAHbV92YWx1ZQACAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { byte.MaxValue, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAtTeXN0ZW0uQnl0ZQEAAAAHbV92YWx1ZQAC/ws=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAtTeXN0ZW0uQnl0ZQEAAAAHbV92YWx1ZQAC/ws=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { sbyte.MinValue, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uU0J5dGUBAAAAB21fdmFsdWUACoAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uU0J5dGUBAAAAB21fdmFsdWUACoAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { sbyte.MaxValue, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uU0J5dGUBAAAAB21fdmFsdWUACn8L", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uU0J5dGUBAAAAB21fdmFsdWUACn8L", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { short.MinValue, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50MTYBAAAAB21fdmFsdWUABwCACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50MTYBAAAAB21fdmFsdWUABwCACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { short.MaxValue, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50MTYBAAAAB21fdmFsdWUAB/9/Cw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50MTYBAAAAB21fdmFsdWUAB/9/Cw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { ushort.MinValue, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uVUludDE2AQAAAAdtX3ZhbHVlAA4AAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uVUludDE2AQAAAAdtX3ZhbHVlAA4AAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { ushort.MaxValue, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uVUludDE2AQAAAAdtX3ZhbHVlAA7//ws=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uVUludDE2AQAAAAdtX3ZhbHVlAA7//ws=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { int.MinValue, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50MzIBAAAAB21fdmFsdWUACAAAAIAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50MzIBAAAAB21fdmFsdWUACAAAAIAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { int.MaxValue, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50MzIBAAAAB21fdmFsdWUACP///38L", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50MzIBAAAAB21fdmFsdWUACP///38L", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { uint.MinValue, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uVUludDMyAQAAAAdtX3ZhbHVlAA8AAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uVUludDMyAQAAAAdtX3ZhbHVlAA8AAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { uint.MaxValue, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uVUludDMyAQAAAAdtX3ZhbHVlAA//////Cw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uVUludDMyAQAAAAdtX3ZhbHVlAA//////Cw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { long.MinValue, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50NjQBAAAAB21fdmFsdWUACQAAAAAAAACACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50NjQBAAAAB21fdmFsdWUACQAAAAAAAACACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { long.MaxValue, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50NjQBAAAAB21fdmFsdWUACf////////9/Cw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50NjQBAAAAB21fdmFsdWUACf////////9/Cw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { ulong.MinValue, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uVUludDY0AQAAAAdtX3ZhbHVlABAAAAAAAAAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uVUludDY0AQAAAAdtX3ZhbHVlABAAAAAAAAAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { ulong.MaxValue, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uVUludDY0AQAAAAdtX3ZhbHVlABD//////////ws=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uVUludDY0AQAAAAdtX3ZhbHVlABD//////////ws=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { char.MinValue, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAtTeXN0ZW0uQ2hhcgEAAAAHbV92YWx1ZQADAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAtTeXN0ZW0uQ2hhcgEAAAAHbV92YWx1ZQADAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { char.MaxValue, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAtTeXN0ZW0uQ2hhcgEAAAAHbV92YWx1ZQAD77+/Cw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAtTeXN0ZW0uQ2hhcgEAAAAHbV92YWx1ZQAD77+/Cw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { float.MinValue, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uU2luZ2xlAQAAAAdtX3ZhbHVlAAv//3//Cw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uU2luZ2xlAQAAAAdtX3ZhbHVlAAv//3//Cw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { float.MaxValue, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uU2luZ2xlAQAAAAdtX3ZhbHVlAAv//39/Cw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uU2luZ2xlAQAAAAdtX3ZhbHVlAAv//39/Cw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { double.MinValue, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uRG91YmxlAQAAAAdtX3ZhbHVlAAb////////v/ws=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uRG91YmxlAQAAAAdtX3ZhbHVlAAb////////v/ws=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { double.MaxValue, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uRG91YmxlAQAAAAdtX3ZhbHVlAAb////////vfws=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uRG91YmxlAQAAAAdtX3ZhbHVlAAb////////vfws=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { decimal.MinValue, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uRGVjaW1hbAQAAAAFZmxhZ3MCaGkCbG8DbWlkAAAAAAgICAgAAACA////////////////Cw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uRGVjaW1hbAQAAAAFZmxhZ3MCaGkCbG8DbWlkAAAAAAgICAgAAACA////////////////Cw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { decimal.MaxValue, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uRGVjaW1hbAQAAAAFZmxhZ3MCaGkCbG8DbWlkAAAAAAgICAgAAAAA////////////////Cw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uRGVjaW1hbAQAAAAFZmxhZ3MCaGkCbG8DbWlkAAAAAAgICAgAAAAA////////////////Cw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { decimal.MinusOne, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uRGVjaW1hbAQAAAAFZmxhZ3MCaGkCbG8DbWlkAAAAAAgICAgAAACAAAAAAAEAAAAAAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uRGVjaW1hbAQAAAAFZmxhZ3MCaGkCbG8DbWlkAAAAAAgICAgAAACAAAAAAAEAAAAAAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { true, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uQm9vbGVhbgEAAAAHbV92YWx1ZQABAQs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uQm9vbGVhbgEAAAAHbV92YWx1ZQABAQs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { false, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uQm9vbGVhbgEAAAAHbV92YWx1ZQABAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uQm9vbGVhbgEAAAAHbV92YWx1ZQABAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { "", new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAGAQAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAGAQAAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { "c", new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAGAQAAAAFjCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAGAQAAAAFjCw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { "\u4F60\u597D", new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAGAQAAAAbkvaDlpb0L", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAGAQAAAAbkvaDlpb0L", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { "some\0data\0with\0null\0chars", new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAGAQAAABlzb21lAGRhdGEAd2l0aABudWxsAGNoYXJzCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAGAQAAABlzb21lAGRhdGEAd2l0aABudWxsAGNoYXJzCw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { "<>&\"\'", new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAGAQAAAAU8PiYiJws=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAGAQAAAAU8PiYiJws=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { " < ", new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAGAQAAAAMgPCAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAGAQAAAAMgPCAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { "minchar" + char.MinValue + "minchar", new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAGAQAAAA9taW5jaGFyAG1pbmNoYXIL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAGAQAAAA9taW5jaGFyAG1pbmNoYXIL", TargetFrameworkMoniker.netfx461) } };
// Exceptions
var exception = new Exception("message", new Exception("Inner exception message"));
- yield return new object[] { PopulateException(exception), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAEFN5c3RlbS5FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAABBQAAAAEAAAAJAgAAAAYMAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYNAAAABnNlY3JldAgBAQkOAAAAAQ4AAAAKAAAACAgBAAAABg8AAAADb25lCgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAEFN5c3RlbS5FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAABBQAAAAEAAAAJAgAAAAYMAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYNAAAABnNlY3JldAgBAQkOAAAAAQ4AAAAKAAAACAgBAAAABg8AAAADb25lCgs=" } };
+ yield return new object[] { PopulateException(exception), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAEFN5c3RlbS5FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAABBQAAAAEAAAAJAgAAAAYMAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYNAAAABnNlY3JldAgBAQkOAAAAAQ4AAAAKAAAACAgBAAAABg8AAAADb25lCgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAEFN5c3RlbS5FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAABBQAAAAEAAAAJAgAAAAYMAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYNAAAABnNlY3JldAgBAQkOAAAAAQ4AAAAKAAAACAgBAAAABg8AAAADb25lCgs=", TargetFrameworkMoniker.netfx461) } };
var aggregateException = new AggregateException("message", new Exception("Exception message", new Exception("Inner exception message")));
- yield return new object[] { PopulateException(aggregateException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgkKAAAABAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBx5TeXN0ZW0uQ29sbGVjdGlvbnMuSURpY3Rpb25hcnkQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24GDQAAABFFeGNlcHRpb24gbWVzc2FnZQoJDgAAAAoKCgAAAAAKABUTgAoKBwoAAAAAAQAAAAEAAAADEFN5c3RlbS5FeGNlcHRpb24JBQAAAAQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYQAAAABnNlY3JldAgBAQkRAAAAAQ4AAAAFAAAACQwAAAAGEwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBEQAAAAsAAAAICAEAAAAGFAAAAANvbmUKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgkKAAAABAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBx5TeXN0ZW0uQ29sbGVjdGlvbnMuSURpY3Rpb25hcnkQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24GDQAAABFFeGNlcHRpb24gbWVzc2FnZQoJDgAAAAoKCgAAAAAKABUTgAoKBwoAAAAAAQAAAAEAAAADEFN5c3RlbS5FeGNlcHRpb24JBQAAAAQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYQAAAABnNlY3JldAgBAQkRAAAAAQ4AAAAFAAAACQwAAAAGEwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBEQAAAAsAAAAICAEAAAAGFAAAAANvbmUKCw==" } };
+ yield return new object[] { PopulateException(aggregateException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgkKAAAABAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBx5TeXN0ZW0uQ29sbGVjdGlvbnMuSURpY3Rpb25hcnkQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24GDQAAABFFeGNlcHRpb24gbWVzc2FnZQoJDgAAAAoKCgAAAAAKABUTgAoKBwoAAAAAAQAAAAEAAAADEFN5c3RlbS5FeGNlcHRpb24JBQAAAAQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYQAAAABnNlY3JldAgBAQkRAAAAAQ4AAAAFAAAACQwAAAAGEwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBEQAAAAsAAAAICAEAAAAGFAAAAANvbmUKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgkKAAAABAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBx5TeXN0ZW0uQ29sbGVjdGlvbnMuSURpY3Rpb25hcnkQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24GDQAAABFFeGNlcHRpb24gbWVzc2FnZQoJDgAAAAoKCgAAAAAKABUTgAoKBwoAAAAAAQAAAAEAAAADEFN5c3RlbS5FeGNlcHRpb24JBQAAAAQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYQAAAABnNlY3JldAgBAQkRAAAAAQ4AAAAFAAAACQwAAAAGEwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBEQAAAAsAAAAICAEAAAAGFAAAAANvbmUKCw==", TargetFrameworkMoniker.netfx461) } };
var abandonedMutexException = new AbandonedMutexException("message", exception);
- yield return new object[] { PopulateException(abandonedMutexException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAChTeXN0ZW0uVGhyZWFkaW5nLkFiYW5kb25lZE11dGV4RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAKFN5c3RlbS5UaHJlYWRpbmcuQWJhbmRvbmVkTXV0ZXhFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAChTeXN0ZW0uVGhyZWFkaW5nLkFiYW5kb25lZE11dGV4RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAKFN5c3RlbS5UaHJlYWRpbmcuQWJhbmRvbmVkTXV0ZXhFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(abandonedMutexException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAChTeXN0ZW0uVGhyZWFkaW5nLkFiYW5kb25lZE11dGV4RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAKFN5c3RlbS5UaHJlYWRpbmcuQWJhbmRvbmVkTXV0ZXhFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAChTeXN0ZW0uVGhyZWFkaW5nLkFiYW5kb25lZE11dGV4RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAKFN5c3RlbS5UaHJlYWRpbmcuQWJhbmRvbmVkTXV0ZXhFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var accessViolationException = new AccessViolationException("message", exception);
- yield return new object[] { PopulateException(accessViolationException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uQWNjZXNzVmlvbGF0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAH1N5c3RlbS5BY2Nlc3NWaW9sYXRpb25FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uQWNjZXNzVmlvbGF0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAH1N5c3RlbS5BY2Nlc3NWaW9sYXRpb25FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(accessViolationException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uQWNjZXNzVmlvbGF0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAH1N5c3RlbS5BY2Nlc3NWaW9sYXRpb25FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uQWNjZXNzVmlvbGF0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAH1N5c3RlbS5BY2Nlc3NWaW9sYXRpb25FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var ambiguousMatchException = new AmbiguousMatchException("message", exception);
- yield return new object[] { PopulateException(ambiguousMatchException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAClTeXN0ZW0uUmVmbGVjdGlvbi5BbWJpZ3VvdXNNYXRjaEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAAClTeXN0ZW0uUmVmbGVjdGlvbi5BbWJpZ3VvdXNNYXRjaEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAAClTeXN0ZW0uUmVmbGVjdGlvbi5BbWJpZ3VvdXNNYXRjaEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAAClTeXN0ZW0uUmVmbGVjdGlvbi5BbWJpZ3VvdXNNYXRjaEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL" } };
+ yield return new object[] { PopulateException(ambiguousMatchException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAClTeXN0ZW0uUmVmbGVjdGlvbi5BbWJpZ3VvdXNNYXRjaEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAAClTeXN0ZW0uUmVmbGVjdGlvbi5BbWJpZ3VvdXNNYXRjaEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAClTeXN0ZW0uUmVmbGVjdGlvbi5BbWJpZ3VvdXNNYXRjaEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAAClTeXN0ZW0uUmVmbGVjdGlvbi5BbWJpZ3VvdXNNYXRjaEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netfx461) } };
var appDomainUnloadedException = new AppDomainUnloadedException("message", exception);
- yield return new object[] { PopulateException(appDomainUnloadedException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACFTeXN0ZW0uQXBwRG9tYWluVW5sb2FkZWRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAhU3lzdGVtLkFwcERvbWFpblVubG9hZGVkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAACFTeXN0ZW0uQXBwRG9tYWluVW5sb2FkZWRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAhU3lzdGVtLkFwcERvbWFpblVubG9hZGVkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(appDomainUnloadedException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACFTeXN0ZW0uQXBwRG9tYWluVW5sb2FkZWRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAhU3lzdGVtLkFwcERvbWFpblVubG9hZGVkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACFTeXN0ZW0uQXBwRG9tYWluVW5sb2FkZWRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAhU3lzdGVtLkFwcERvbWFpblVubG9hZGVkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var applicationException = new ApplicationException("message", exception);
- yield return new object[] { PopulateException(applicationException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQXBwbGljYXRpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAbU3lzdGVtLkFwcGxpY2F0aW9uRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQXBwbGljYXRpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAbU3lzdGVtLkFwcGxpY2F0aW9uRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(applicationException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQXBwbGljYXRpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAbU3lzdGVtLkFwcGxpY2F0aW9uRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQXBwbGljYXRpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAbU3lzdGVtLkFwcGxpY2F0aW9uRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var argumentException = new ArgumentException("message", "paramName", exception);
- yield return new object[] { PopulateException(argumentException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQXJndW1lbnRFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwlQYXJhbU5hbWUBAQMDAQEBAAEAAQcBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAABhTeXN0ZW0uQXJndW1lbnRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYKAAAACXBhcmFtTmFtZQQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkOAAAACQ8AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABAAAAAkWAAAAAgAAAAIAAAABDwAAAAUAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQXJndW1lbnRFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwlQYXJhbU5hbWUBAQMDAQEBAAEAAQcBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAABhTeXN0ZW0uQXJndW1lbnRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYKAAAACXBhcmFtTmFtZQQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkOAAAACQ8AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABAAAAAkWAAAAAgAAAAIAAAABDwAAAAUAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==" } };
+ yield return new object[] { PopulateException(argumentException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQXJndW1lbnRFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwlQYXJhbU5hbWUBAQMDAQEBAAEAAQcBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAABhTeXN0ZW0uQXJndW1lbnRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYKAAAACXBhcmFtTmFtZQQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkOAAAACQ8AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABAAAAAkWAAAAAgAAAAIAAAABDwAAAAUAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQXJndW1lbnRFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwlQYXJhbU5hbWUBAQMDAQEBAAEAAQcBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAABhTeXN0ZW0uQXJndW1lbnRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYKAAAACXBhcmFtTmFtZQQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkOAAAACQ8AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABAAAAAkWAAAAAgAAAAIAAAABDwAAAAUAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var argumentNullException = new ArgumentNullException("message", exception);
- yield return new object[] { PopulateException(argumentNullException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQXJndW1lbnROdWxsRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMJUGFyYW1OYW1lAQEDAwEBAQABAAEHASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAcU3lzdGVtLkFyZ3VtZW50TnVsbEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQXJndW1lbnROdWxsRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMJUGFyYW1OYW1lAQEDAwEBAQABAAEHASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAcU3lzdGVtLkFyZ3VtZW50TnVsbEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(argumentNullException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQXJndW1lbnROdWxsRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMJUGFyYW1OYW1lAQEDAwEBAQABAAEHASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAcU3lzdGVtLkFyZ3VtZW50TnVsbEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQXJndW1lbnROdWxsRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMJUGFyYW1OYW1lAQEDAwEBAQABAAEHASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAcU3lzdGVtLkFyZ3VtZW50TnVsbEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var argumentNullException2 = new ArgumentNullException("paramName", "message");
- yield return new object[] { PopulateException(argumentNullException2), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQXJndW1lbnROdWxsRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMJUGFyYW1OYW1lAQEDAwEBAQABAAEHASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAcU3lzdGVtLkFyZ3VtZW50TnVsbEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAoGBQAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgYAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GBwAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCAAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoGCQAAAAlwYXJhbU5hbWUEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQXJndW1lbnROdWxsRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMJUGFyYW1OYW1lAQEDAwEBAQABAAEHASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAcU3lzdGVtLkFyZ3VtZW50TnVsbEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAoGBQAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgYAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GBwAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCAAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoGCQAAAAlwYXJhbU5hbWUEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==" } };
+ yield return new object[] { PopulateException(argumentNullException2), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQXJndW1lbnROdWxsRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMJUGFyYW1OYW1lAQEDAwEBAQABAAEHASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAcU3lzdGVtLkFyZ3VtZW50TnVsbEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAoGBQAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgYAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GBwAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCAAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoGCQAAAAlwYXJhbU5hbWUEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQXJndW1lbnROdWxsRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMJUGFyYW1OYW1lAQEDAwEBAQABAAEHASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAcU3lzdGVtLkFyZ3VtZW50TnVsbEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAoGBQAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgYAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GBwAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCAAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoGCQAAAAlwYXJhbU5hbWUEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==", TargetFrameworkMoniker.netfx461) } };
var argumentOutOfRangeException = new ArgumentOutOfRangeException("message", exception);
- yield return new object[] { PopulateException(argumentOutOfRangeException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uQXJndW1lbnRPdXRPZlJhbmdlRXhjZXB0aW9uDgAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMJUGFyYW1OYW1lC0FjdHVhbFZhbHVlAQEDAwEBAQABAAEHAQIpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAIlN5c3RlbS5Bcmd1bWVudE91dE9mUmFuZ2VFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgoKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uQXJndW1lbnRPdXRPZlJhbmdlRXhjZXB0aW9uDgAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMJUGFyYW1OYW1lC0FjdHVhbFZhbHVlAQEDAwEBAQABAAEHAQIpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAIlN5c3RlbS5Bcmd1bWVudE91dE9mUmFuZ2VFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgoKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL" } };
+ yield return new object[] { PopulateException(argumentOutOfRangeException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uQXJndW1lbnRPdXRPZlJhbmdlRXhjZXB0aW9uDgAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMJUGFyYW1OYW1lC0FjdHVhbFZhbHVlAQEDAwEBAQABAAEHAQIpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAIlN5c3RlbS5Bcmd1bWVudE91dE9mUmFuZ2VFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgoKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uQXJndW1lbnRPdXRPZlJhbmdlRXhjZXB0aW9uDgAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMJUGFyYW1OYW1lC0FjdHVhbFZhbHVlAQEDAwEBAQABAAEHAQIpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAIlN5c3RlbS5Bcmd1bWVudE91dE9mUmFuZ2VFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgoKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netfx461) } };
var argumentOutOfRangeException2 = new ArgumentOutOfRangeException("paramName", 4, "message");
- yield return new object[] { PopulateException(argumentOutOfRangeException2), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uQXJndW1lbnRPdXRPZlJhbmdlRXhjZXB0aW9uDgAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMJUGFyYW1OYW1lC0FjdHVhbFZhbHVlAQEDAwEBAQABAAEHAQIpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAIlN5c3RlbS5Bcmd1bWVudE91dE9mUmFuZ2VFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAKBgUAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYGAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgcAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABggAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgkAAAAJcGFyYW1OYW1lCAgEAAAABAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYLAAAABnNlY3JldAgBAQkMAAAAAQwAAAAKAAAACAgBAAAABg0AAAADb25lCgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uQXJndW1lbnRPdXRPZlJhbmdlRXhjZXB0aW9uDgAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMJUGFyYW1OYW1lC0FjdHVhbFZhbHVlAQEDAwEBAQABAAEHAQIpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAIlN5c3RlbS5Bcmd1bWVudE91dE9mUmFuZ2VFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAKBgUAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYGAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgcAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABggAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgkAAAAJcGFyYW1OYW1lCAgEAAAABAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYLAAAABnNlY3JldAgBAQkMAAAAAQwAAAAKAAAACAgBAAAABg0AAAADb25lCgs=" } };
+ yield return new object[] { PopulateException(argumentOutOfRangeException2), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uQXJndW1lbnRPdXRPZlJhbmdlRXhjZXB0aW9uDgAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMJUGFyYW1OYW1lC0FjdHVhbFZhbHVlAQEDAwEBAQABAAEHAQIpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAIlN5c3RlbS5Bcmd1bWVudE91dE9mUmFuZ2VFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAKBgUAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYGAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgcAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABggAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgkAAAAJcGFyYW1OYW1lCAgEAAAABAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYLAAAABnNlY3JldAgBAQkMAAAAAQwAAAAKAAAACAgBAAAABg0AAAADb25lCgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uQXJndW1lbnRPdXRPZlJhbmdlRXhjZXB0aW9uDgAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMJUGFyYW1OYW1lC0FjdHVhbFZhbHVlAQEDAwEBAQABAAEHAQIpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAIlN5c3RlbS5Bcmd1bWVudE91dE9mUmFuZ2VFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAKBgUAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYGAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgcAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABggAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgkAAAAJcGFyYW1OYW1lCAgEAAAABAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYLAAAABnNlY3JldAgBAQkMAAAAAQwAAAAKAAAACAgBAAAABg0AAAADb25lCgs=", TargetFrameworkMoniker.netfx461) } };
var arithmeticException = new ArithmeticException("message", exception);
- yield return new object[] { PopulateException(arithmeticException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABpTeXN0ZW0uQXJpdGhtZXRpY0V4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAABpTeXN0ZW0uQXJpdGhtZXRpY0V4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAABpTeXN0ZW0uQXJpdGhtZXRpY0V4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAABpTeXN0ZW0uQXJpdGhtZXRpY0V4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL" } };
+ yield return new object[] { PopulateException(arithmeticException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABpTeXN0ZW0uQXJpdGhtZXRpY0V4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAABpTeXN0ZW0uQXJpdGhtZXRpY0V4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABpTeXN0ZW0uQXJpdGhtZXRpY0V4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAABpTeXN0ZW0uQXJpdGhtZXRpY0V4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netfx461) } };
var arrayTypeMismatchException = new ArrayTypeMismatchException("message", exception);
- yield return new object[] { PopulateException(arrayTypeMismatchException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACFTeXN0ZW0uQXJyYXlUeXBlTWlzbWF0Y2hFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAhU3lzdGVtLkFycmF5VHlwZU1pc21hdGNoRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAACFTeXN0ZW0uQXJyYXlUeXBlTWlzbWF0Y2hFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAhU3lzdGVtLkFycmF5VHlwZU1pc21hdGNoRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(arrayTypeMismatchException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACFTeXN0ZW0uQXJyYXlUeXBlTWlzbWF0Y2hFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAhU3lzdGVtLkFycmF5VHlwZU1pc21hdGNoRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACFTeXN0ZW0uQXJyYXlUeXBlTWlzbWF0Y2hFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAhU3lzdGVtLkFycmF5VHlwZU1pc21hdGNoRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var authenticationException = new AuthenticationException("message", exception);
- yield return new object[] { PopulateException(authenticationException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA2U3lzdGVtLlNlY3VyaXR5LkF1dGhlbnRpY2F0aW9uLkF1dGhlbnRpY2F0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADZTeXN0ZW0uU2VjdXJpdHkuQXV0aGVudGljYXRpb24uQXV0aGVudGljYXRpb25FeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA2U3lzdGVtLlNlY3VyaXR5LkF1dGhlbnRpY2F0aW9uLkF1dGhlbnRpY2F0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADZTeXN0ZW0uU2VjdXJpdHkuQXV0aGVudGljYXRpb24uQXV0aGVudGljYXRpb25FeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==" } };
+ yield return new object[] { PopulateException(authenticationException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA2U3lzdGVtLlNlY3VyaXR5LkF1dGhlbnRpY2F0aW9uLkF1dGhlbnRpY2F0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADZTeXN0ZW0uU2VjdXJpdHkuQXV0aGVudGljYXRpb24uQXV0aGVudGljYXRpb25FeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA2U3lzdGVtLlNlY3VyaXR5LkF1dGhlbnRpY2F0aW9uLkF1dGhlbnRpY2F0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADZTeXN0ZW0uU2VjdXJpdHkuQXV0aGVudGljYXRpb24uQXV0aGVudGljYXRpb25FeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var badImageFormatException = new BadImageFormatException("message", "path.md", exception);
- yield return new object[] { PopulateException(badImageFormatException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uQmFkSW1hZ2VGb3JtYXRFeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cxdCYWRJbWFnZUZvcm1hdF9GaWxlTmFtZRhCYWRJbWFnZUZvcm1hdF9GdXNpb25Mb2cBAQMDAQEBAAEAAQcBASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLkJhZEltYWdlRm9ybWF0RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoGCgAAAAdwYXRoLm1kCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkOAAAACQ8AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABAAAAAkWAAAAAgAAAAIAAAABDwAAAAUAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uQmFkSW1hZ2VGb3JtYXRFeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cxdCYWRJbWFnZUZvcm1hdF9GaWxlTmFtZRhCYWRJbWFnZUZvcm1hdF9GdXNpb25Mb2cBAQMDAQEBAAEAAQcBASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLkJhZEltYWdlRm9ybWF0RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoGCgAAAAdwYXRoLm1kCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkOAAAACQ8AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABAAAAAkWAAAAAgAAAAIAAAABDwAAAAUAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==" } };
+ yield return new object[] { PopulateException(badImageFormatException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uQmFkSW1hZ2VGb3JtYXRFeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cxdCYWRJbWFnZUZvcm1hdF9GaWxlTmFtZRhCYWRJbWFnZUZvcm1hdF9GdXNpb25Mb2cBAQMDAQEBAAEAAQcBASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLkJhZEltYWdlRm9ybWF0RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoGCgAAAAdwYXRoLm1kCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkOAAAACQ8AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABAAAAAkWAAAAAgAAAAIAAAABDwAAAAUAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uQmFkSW1hZ2VGb3JtYXRFeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cxdCYWRJbWFnZUZvcm1hdF9GaWxlTmFtZRhCYWRJbWFnZUZvcm1hdF9GdXNpb25Mb2cBAQMDAQEBAAEAAQcBASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLkJhZEltYWdlRm9ybWF0RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoGCgAAAAdwYXRoLm1kCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkOAAAACQ8AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABAAAAAkWAAAAAgAAAAIAAAABDwAAAAUAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var barrierPostPhaseException = new BarrierPostPhaseException("message", exception);
- yield return new object[] { PopulateException(barrierPostPhaseException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAqU3lzdGVtLlRocmVhZGluZy5CYXJyaWVyUG9zdFBoYXNlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACpTeXN0ZW0uVGhyZWFkaW5nLkJhcnJpZXJQb3N0UGhhc2VFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAqU3lzdGVtLlRocmVhZGluZy5CYXJyaWVyUG9zdFBoYXNlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACpTeXN0ZW0uVGhyZWFkaW5nLkJhcnJpZXJQb3N0UGhhc2VFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==" } };
+ yield return new object[] { PopulateException(barrierPostPhaseException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAqU3lzdGVtLlRocmVhZGluZy5CYXJyaWVyUG9zdFBoYXNlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACpTeXN0ZW0uVGhyZWFkaW5nLkJhcnJpZXJQb3N0UGhhc2VFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAqU3lzdGVtLlRocmVhZGluZy5CYXJyaWVyUG9zdFBoYXNlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACpTeXN0ZW0uVGhyZWFkaW5nLkJhcnJpZXJQb3N0UGhhc2VFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var cOMException = new COMException("message", exception);
- yield return new object[] { PopulateException(cOMException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACtTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuQ09NRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAK1N5c3RlbS5SdW50aW1lLkludGVyb3BTZXJ2aWNlcy5DT01FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAACtTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuQ09NRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAK1N5c3RlbS5SdW50aW1lLkludGVyb3BTZXJ2aWNlcy5DT01FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(cOMException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACtTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuQ09NRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAK1N5c3RlbS5SdW50aW1lLkludGVyb3BTZXJ2aWNlcy5DT01FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACtTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuQ09NRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAK1N5c3RlbS5SdW50aW1lLkludGVyb3BTZXJ2aWNlcy5DT01FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var cOMException2 = new COMException("message", 0);
- yield return new object[] { PopulateException(cOMException2), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACtTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuQ09NRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAK1N5c3RlbS5SdW50aW1lLkludGVyb3BTZXJ2aWNlcy5DT01FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAKBgUAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYGAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgcAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABggAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQkAAAACAAAAAgAAAAQJAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYKAAAABnNlY3JldAgBAQkLAAAAAQsAAAAJAAAACAgBAAAABgwAAAADb25lCgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAACtTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuQ09NRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAK1N5c3RlbS5SdW50aW1lLkludGVyb3BTZXJ2aWNlcy5DT01FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAKBgUAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYGAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgcAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABggAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQkAAAACAAAAAgAAAAQJAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYKAAAABnNlY3JldAgBAQkLAAAAAQsAAAAJAAAACAgBAAAABgwAAAADb25lCgs=" } };
+ yield return new object[] { PopulateException(cOMException2), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACtTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuQ09NRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAK1N5c3RlbS5SdW50aW1lLkludGVyb3BTZXJ2aWNlcy5DT01FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAKBgUAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYGAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgcAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABggAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQkAAAACAAAAAgAAAAQJAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYKAAAABnNlY3JldAgBAQkLAAAAAQsAAAAJAAAACAgBAAAABgwAAAADb25lCgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACtTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuQ09NRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAK1N5c3RlbS5SdW50aW1lLkludGVyb3BTZXJ2aWNlcy5DT01FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAKBgUAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYGAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgcAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABggAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQkAAAACAAAAAgAAAAQJAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYKAAAABnNlY3JldAgBAQkLAAAAAQsAAAAJAAAACAgBAAAABgwAAAADb25lCgs=", TargetFrameworkMoniker.netfx461) } };
var cannotUnloadAppDomainException = new CannotUnloadAppDomainException("message", exception);
- yield return new object[] { PopulateException(cannotUnloadAppDomainException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACVTeXN0ZW0uQ2Fubm90VW5sb2FkQXBwRG9tYWluRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAJVN5c3RlbS5DYW5ub3RVbmxvYWRBcHBEb21haW5FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAACVTeXN0ZW0uQ2Fubm90VW5sb2FkQXBwRG9tYWluRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAJVN5c3RlbS5DYW5ub3RVbmxvYWRBcHBEb21haW5FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(cannotUnloadAppDomainException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACVTeXN0ZW0uQ2Fubm90VW5sb2FkQXBwRG9tYWluRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAJVN5c3RlbS5DYW5ub3RVbmxvYWRBcHBEb21haW5FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACVTeXN0ZW0uQ2Fubm90VW5sb2FkQXBwRG9tYWluRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAJVN5c3RlbS5DYW5ub3RVbmxvYWRBcHBEb21haW5FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var checkoutException = new CheckoutException("message", exception);
- yield return new object[] { PopulateException(checkoutException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAuU3lzdGVtLkNvbXBvbmVudE1vZGVsLkRlc2lnbi5DaGVja291dEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAuU3lzdGVtLkNvbXBvbmVudE1vZGVsLkRlc2lnbi5DaGVja291dEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAuU3lzdGVtLkNvbXBvbmVudE1vZGVsLkRlc2lnbi5DaGVja291dEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAuU3lzdGVtLkNvbXBvbmVudE1vZGVsLkRlc2lnbi5DaGVja291dEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL" } };
+ yield return new object[] { PopulateException(checkoutException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAuU3lzdGVtLkNvbXBvbmVudE1vZGVsLkRlc2lnbi5DaGVja291dEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAuU3lzdGVtLkNvbXBvbmVudE1vZGVsLkRlc2lnbi5DaGVja291dEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAuU3lzdGVtLkNvbXBvbmVudE1vZGVsLkRlc2lnbi5DaGVja291dEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAuU3lzdGVtLkNvbXBvbmVudE1vZGVsLkRlc2lnbi5DaGVja291dEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netfx461) } };
var checkoutException2 = new CheckoutException("message", 0);
- yield return new object[] { PopulateException(checkoutException2), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAuU3lzdGVtLkNvbXBvbmVudE1vZGVsLkRlc2lnbi5DaGVja291dEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAuU3lzdGVtLkNvbXBvbmVudE1vZGVsLkRlc2lnbi5DaGVja291dEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAoGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAuU3lzdGVtLkNvbXBvbmVudE1vZGVsLkRlc2lnbi5DaGVja291dEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAuU3lzdGVtLkNvbXBvbmVudE1vZGVsLkRlc2lnbi5DaGVja291dEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAoGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==" } };
+ yield return new object[] { PopulateException(checkoutException2), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAuU3lzdGVtLkNvbXBvbmVudE1vZGVsLkRlc2lnbi5DaGVja291dEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAuU3lzdGVtLkNvbXBvbmVudE1vZGVsLkRlc2lnbi5DaGVja291dEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAoGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAuU3lzdGVtLkNvbXBvbmVudE1vZGVsLkRlc2lnbi5DaGVja291dEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAuU3lzdGVtLkNvbXBvbmVudE1vZGVsLkRlc2lnbi5DaGVja291dEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAoGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==", TargetFrameworkMoniker.netfx461) } };
// Assembly load errors with shims in uapaot configuration. Issue #24916
if (!PlatformDetection.IsNetNative)
@@ -210,325 +202,325 @@ namespace System.Runtime.Serialization.Formatters.Tests
var configurationErrorsException = new ConfigurationErrorsException("message", exception, "path.md", 1);
// ConfigurationErrorsException sets its HResult itself therefore we pass setHResult as false.
- yield return new object[] { PopulateException(configurationErrorsException, setHResult: false), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uQ29uZmlndXJhdGlvbiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAADFTeXN0ZW0uQ29uZmlndXJhdGlvbi5Db25maWd1cmF0aW9uRXJyb3JzRXhjZXB0aW9uEQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMIZmlsZW5hbWUEbGluZQ1maXJzdEZpbGVuYW1lCWZpcnN0TGluZQVjb3VudAEBAwMBAQEAAQABBwIAAQAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIICAgCAAAABgMAAAAxU3lzdGVtLkNvbmZpZ3VyYXRpb24uQ29uZmlndXJhdGlvbkVycm9yc0V4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAoCGROABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgAAAAAGCwAAAAdwYXRoLm1kAQAAAAAAAAAEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJDAAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDQAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDwAAAAkQAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAwAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhUAAAAGc2VjcmV0CAEBCRYAAAABDwAAAAUAAAAJFwAAAAIAAAACAAAAARAAAAAGAAAACQ0AAAAGGQAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFgAAAAwAAAAICAEAAAAGGgAAAANvbmUKARcAAAAMAAAACRUAAAAIAQEJHAAAAAEcAAAADAAAAAgIAQAAAAkaAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uQ29uZmlndXJhdGlvbiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAADFTeXN0ZW0uQ29uZmlndXJhdGlvbi5Db25maWd1cmF0aW9uRXJyb3JzRXhjZXB0aW9uEQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMIZmlsZW5hbWUEbGluZQ1maXJzdEZpbGVuYW1lCWZpcnN0TGluZQVjb3VudAEBAwMBAQEAAQABBwIAAQAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIICAgCAAAABgMAAAAxU3lzdGVtLkNvbmZpZ3VyYXRpb24uQ29uZmlndXJhdGlvbkVycm9yc0V4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAoCGROABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgAAAAAGCwAAAAdwYXRoLm1kAQAAAAAAAAAEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJDAAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDQAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDwAAAAkQAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAwAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhUAAAAGc2VjcmV0CAEBCRYAAAABDwAAAAUAAAAJFwAAAAIAAAACAAAAARAAAAAGAAAACQ0AAAAGGQAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFgAAAAwAAAAICAEAAAAGGgAAAANvbmUKARcAAAAMAAAACRUAAAAIAQEJHAAAAAEcAAAADAAAAAgIAQAAAAkaAAAACgs=" } };
+ yield return new object[] { PopulateException(configurationErrorsException, setHResult: false), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uQ29uZmlndXJhdGlvbiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAADFTeXN0ZW0uQ29uZmlndXJhdGlvbi5Db25maWd1cmF0aW9uRXJyb3JzRXhjZXB0aW9uEQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMIZmlsZW5hbWUEbGluZQ1maXJzdEZpbGVuYW1lCWZpcnN0TGluZQVjb3VudAEBAwMBAQEAAQABBwIAAQAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIICAgCAAAABgMAAAAxU3lzdGVtLkNvbmZpZ3VyYXRpb24uQ29uZmlndXJhdGlvbkVycm9yc0V4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAoCGROABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgAAAAAGCwAAAAdwYXRoLm1kAQAAAAAAAAAEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJDAAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDQAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDwAAAAkQAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAwAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhUAAAAGc2VjcmV0CAEBCRYAAAABDwAAAAUAAAAJFwAAAAIAAAACAAAAARAAAAAGAAAACQ0AAAAGGQAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFgAAAAwAAAAICAEAAAAGGgAAAANvbmUKARcAAAAMAAAACRUAAAAIAQEJHAAAAAEcAAAADAAAAAgIAQAAAAkaAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uQ29uZmlndXJhdGlvbiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAADFTeXN0ZW0uQ29uZmlndXJhdGlvbi5Db25maWd1cmF0aW9uRXJyb3JzRXhjZXB0aW9uEQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMIZmlsZW5hbWUEbGluZQ1maXJzdEZpbGVuYW1lCWZpcnN0TGluZQVjb3VudAEBAwMBAQEAAQABBwIAAQAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIICAgCAAAABgMAAAAxU3lzdGVtLkNvbmZpZ3VyYXRpb24uQ29uZmlndXJhdGlvbkVycm9yc0V4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAoCGROABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgAAAAAGCwAAAAdwYXRoLm1kAQAAAAAAAAAEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJDAAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDQAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDwAAAAkQAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAwAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhUAAAAGc2VjcmV0CAEBCRYAAAABDwAAAAUAAAAJFwAAAAIAAAACAAAAARAAAAAGAAAACQ0AAAAGGQAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFgAAAAwAAAAICAEAAAAGGgAAAANvbmUKARcAAAAMAAAACRUAAAAIAQEJHAAAAAEcAAAADAAAAAgIAQAAAAkaAAAACgs=", TargetFrameworkMoniker.netfx461) } };
#pragma warning disable CS0618 // Type or member is obsolete
var configurationException = new ConfigurationException("message", exception, "path.md", 1);
#pragma warning restore CS0618 // Type or member is obsolete
// ConfigurationException sets its HResult itself therefore we pass setHResult as false.
- yield return new object[] { PopulateException(configurationException, setHResult: false), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAArU3lzdGVtLkNvbmZpZ3VyYXRpb24uQ29uZmlndXJhdGlvbkV4Y2VwdGlvbg4AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCGZpbGVuYW1lBGxpbmUBAQMDAQEBAAEAAQcBAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAIAAAAGAwAAACtTeXN0ZW0uQ29uZmlndXJhdGlvbi5Db25maWd1cmF0aW9uRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACgIZE4AGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoGCwAAAAdwYXRoLm1kAQAAAAQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkMAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYNAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkPAAAACRAAAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoEDAAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFQAAAAZzZWNyZXQIAQEJFgAAAAEPAAAABQAAAAkXAAAAAgAAAAIAAAABEAAAAAYAAAAJDQAAAAYZAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEWAAAADAAAAAgIAQAAAAYaAAAAA29uZQoBFwAAAAwAAAAJFQAAAAgBAQkcAAAAARwAAAAMAAAACAgBAAAACRoAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAArU3lzdGVtLkNvbmZpZ3VyYXRpb24uQ29uZmlndXJhdGlvbkV4Y2VwdGlvbg4AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCGZpbGVuYW1lBGxpbmUBAQMDAQEBAAEAAQcBAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAIAAAAGAwAAACtTeXN0ZW0uQ29uZmlndXJhdGlvbi5Db25maWd1cmF0aW9uRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACgIZE4AGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoGCwAAAAdwYXRoLm1kAQAAAAQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkMAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYNAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkPAAAACRAAAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoEDAAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFQAAAAZzZWNyZXQIAQEJFgAAAAEPAAAABQAAAAkXAAAAAgAAAAIAAAABEAAAAAYAAAAJDQAAAAYZAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEWAAAADAAAAAgIAQAAAAYaAAAAA29uZQoBFwAAAAwAAAAJFQAAAAgBAQkcAAAAARwAAAAMAAAACAgBAAAACRoAAAAKCw==" } };
+ yield return new object[] { PopulateException(configurationException, setHResult: false), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAArU3lzdGVtLkNvbmZpZ3VyYXRpb24uQ29uZmlndXJhdGlvbkV4Y2VwdGlvbg4AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCGZpbGVuYW1lBGxpbmUBAQMDAQEBAAEAAQcBAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAIAAAAGAwAAACtTeXN0ZW0uQ29uZmlndXJhdGlvbi5Db25maWd1cmF0aW9uRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACgIZE4AGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoGCwAAAAdwYXRoLm1kAQAAAAQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkMAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYNAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkPAAAACRAAAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoEDAAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFQAAAAZzZWNyZXQIAQEJFgAAAAEPAAAABQAAAAkXAAAAAgAAAAIAAAABEAAAAAYAAAAJDQAAAAYZAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEWAAAADAAAAAgIAQAAAAYaAAAAA29uZQoBFwAAAAwAAAAJFQAAAAgBAQkcAAAAARwAAAAMAAAACAgBAAAACRoAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAArU3lzdGVtLkNvbmZpZ3VyYXRpb24uQ29uZmlndXJhdGlvbkV4Y2VwdGlvbg4AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCGZpbGVuYW1lBGxpbmUBAQMDAQEBAAEAAQcBAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAIAAAAGAwAAACtTeXN0ZW0uQ29uZmlndXJhdGlvbi5Db25maWd1cmF0aW9uRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACgIZE4AGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoGCwAAAAdwYXRoLm1kAQAAAAQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkMAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYNAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkPAAAACRAAAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoEDAAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFQAAAAZzZWNyZXQIAQEJFgAAAAEPAAAABQAAAAkXAAAAAgAAAAIAAAABEAAAAAYAAAAJDQAAAAYZAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEWAAAADAAAAAgIAQAAAAYaAAAAA29uZQoBFwAAAAwAAAAJFQAAAAgBAQkcAAAAARwAAAAMAAAACAgBAAAACRoAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var providerException = new ProviderException("message", exception);
- yield return new object[] { PopulateException(providerException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uQ29uZmlndXJhdGlvbiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAAC9TeXN0ZW0uQ29uZmlndXJhdGlvbi5Qcm92aWRlci5Qcm92aWRlckV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAvU3lzdGVtLkNvbmZpZ3VyYXRpb24uUHJvdmlkZXIuUHJvdmlkZXJFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uQ29uZmlndXJhdGlvbiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAAC9TeXN0ZW0uQ29uZmlndXJhdGlvbi5Qcm92aWRlci5Qcm92aWRlckV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAvU3lzdGVtLkNvbmZpZ3VyYXRpb24uUHJvdmlkZXIuUHJvdmlkZXJFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==" } };
+ yield return new object[] { PopulateException(providerException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uQ29uZmlndXJhdGlvbiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAAC9TeXN0ZW0uQ29uZmlndXJhdGlvbi5Qcm92aWRlci5Qcm92aWRlckV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAvU3lzdGVtLkNvbmZpZ3VyYXRpb24uUHJvdmlkZXIuUHJvdmlkZXJFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uQ29uZmlndXJhdGlvbiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAAC9TeXN0ZW0uQ29uZmlndXJhdGlvbi5Qcm92aWRlci5Qcm92aWRlckV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAvU3lzdGVtLkNvbmZpZ3VyYXRpb24uUHJvdmlkZXIuUHJvdmlkZXJFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
// System.Runtime.Serialization
var invalidDataContractException = new InvalidDataContractException("message", exception);
- yield return new object[] { PopulateException(invalidDataContractException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAF9TeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAOVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uSW52YWxpZERhdGFDb250cmFjdEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAA5U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5JbnZhbGlkRGF0YUNvbnRyYWN0RXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAF9TeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAOVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uSW52YWxpZERhdGFDb250cmFjdEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAA5U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5JbnZhbGlkRGF0YUNvbnRyYWN0RXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=" } };
+ yield return new object[] { PopulateException(invalidDataContractException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAF9TeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAOVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uSW52YWxpZERhdGFDb250cmFjdEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAA5U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5JbnZhbGlkRGF0YUNvbnRyYWN0RXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAF9TeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAOVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uSW52YWxpZERhdGFDb250cmFjdEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAA5U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5JbnZhbGlkRGF0YUNvbnRyYWN0RXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netfx461) } };
// System.Transactions
var transactionAbortedException = new TransactionAbortedException("message", exception);
- yield return new object[] { PopulateException(transactionAbortedException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAFZTeXN0ZW0uVHJhbnNhY3Rpb25zLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAL1N5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25BYm9ydGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAC9TeXN0ZW0uVHJhbnNhY3Rpb25zLlRyYW5zYWN0aW9uQWJvcnRlZEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAFZTeXN0ZW0uVHJhbnNhY3Rpb25zLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAL1N5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25BYm9ydGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAC9TeXN0ZW0uVHJhbnNhY3Rpb25zLlRyYW5zYWN0aW9uQWJvcnRlZEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL" } };
+ yield return new object[] { PopulateException(transactionAbortedException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFZTeXN0ZW0uVHJhbnNhY3Rpb25zLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAL1N5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25BYm9ydGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAC9TeXN0ZW0uVHJhbnNhY3Rpb25zLlRyYW5zYWN0aW9uQWJvcnRlZEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFZTeXN0ZW0uVHJhbnNhY3Rpb25zLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAL1N5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25BYm9ydGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAC9TeXN0ZW0uVHJhbnNhY3Rpb25zLlRyYW5zYWN0aW9uQWJvcnRlZEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netfx461) } };
var transactionException = new TransactionException("message", exception);
- yield return new object[] { PopulateException(transactionException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAFZTeXN0ZW0uVHJhbnNhY3Rpb25zLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAKFN5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAKFN5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25FeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAFZTeXN0ZW0uVHJhbnNhY3Rpb25zLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAKFN5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAKFN5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25FeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==" } };
+ yield return new object[] { PopulateException(transactionException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFZTeXN0ZW0uVHJhbnNhY3Rpb25zLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAKFN5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAKFN5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25FeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFZTeXN0ZW0uVHJhbnNhY3Rpb25zLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAKFN5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAKFN5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25FeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var transactionInDoubtException = new TransactionInDoubtException("message", exception);
- yield return new object[] { PopulateException(transactionInDoubtException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAFZTeXN0ZW0uVHJhbnNhY3Rpb25zLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAL1N5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25JbkRvdWJ0RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAC9TeXN0ZW0uVHJhbnNhY3Rpb25zLlRyYW5zYWN0aW9uSW5Eb3VidEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAFZTeXN0ZW0uVHJhbnNhY3Rpb25zLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAL1N5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25JbkRvdWJ0RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAC9TeXN0ZW0uVHJhbnNhY3Rpb25zLlRyYW5zYWN0aW9uSW5Eb3VidEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL" } };
+ yield return new object[] { PopulateException(transactionInDoubtException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFZTeXN0ZW0uVHJhbnNhY3Rpb25zLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAL1N5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25JbkRvdWJ0RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAC9TeXN0ZW0uVHJhbnNhY3Rpb25zLlRyYW5zYWN0aW9uSW5Eb3VidEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFZTeXN0ZW0uVHJhbnNhY3Rpb25zLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAL1N5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25JbkRvdWJ0RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAC9TeXN0ZW0uVHJhbnNhY3Rpb25zLlRyYW5zYWN0aW9uSW5Eb3VidEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netfx461) } };
var transactionManagerCommunicationException = new TransactionManagerCommunicationException("message", exception);
- yield return new object[] { PopulateException(transactionManagerCommunicationException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAFZTeXN0ZW0uVHJhbnNhY3Rpb25zLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAPFN5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25NYW5hZ2VyQ29tbXVuaWNhdGlvbkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAA8U3lzdGVtLlRyYW5zYWN0aW9ucy5UcmFuc2FjdGlvbk1hbmFnZXJDb21tdW5pY2F0aW9uRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAFZTeXN0ZW0uVHJhbnNhY3Rpb25zLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAPFN5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25NYW5hZ2VyQ29tbXVuaWNhdGlvbkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAA8U3lzdGVtLlRyYW5zYWN0aW9ucy5UcmFuc2FjdGlvbk1hbmFnZXJDb21tdW5pY2F0aW9uRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=" } };
+ yield return new object[] { PopulateException(transactionManagerCommunicationException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFZTeXN0ZW0uVHJhbnNhY3Rpb25zLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAPFN5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25NYW5hZ2VyQ29tbXVuaWNhdGlvbkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAA8U3lzdGVtLlRyYW5zYWN0aW9ucy5UcmFuc2FjdGlvbk1hbmFnZXJDb21tdW5pY2F0aW9uRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFZTeXN0ZW0uVHJhbnNhY3Rpb25zLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAPFN5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25NYW5hZ2VyQ29tbXVuaWNhdGlvbkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAA8U3lzdGVtLlRyYW5zYWN0aW9ucy5UcmFuc2FjdGlvbk1hbmFnZXJDb21tdW5pY2F0aW9uRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var transactionPromotionException = new TransactionPromotionException("message", exception);
- yield return new object[] { PopulateException(transactionPromotionException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAFZTeXN0ZW0uVHJhbnNhY3Rpb25zLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAMVN5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25Qcm9tb3Rpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAMVN5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25Qcm9tb3Rpb25FeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAFZTeXN0ZW0uVHJhbnNhY3Rpb25zLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAMVN5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25Qcm9tb3Rpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAMVN5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25Qcm9tb3Rpb25FeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==" } };
+ yield return new object[] { PopulateException(transactionPromotionException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFZTeXN0ZW0uVHJhbnNhY3Rpb25zLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAMVN5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25Qcm9tb3Rpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAMVN5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25Qcm9tb3Rpb25FeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFZTeXN0ZW0uVHJhbnNhY3Rpb25zLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAMVN5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25Qcm9tb3Rpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAMVN5c3RlbS5UcmFuc2FjdGlvbnMuVHJhbnNhY3Rpb25Qcm9tb3Rpb25FeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
// System.Xml
var xPathException = new XPathException("message", exception);
- yield return new object[] { PopulateException(xPathException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAH1N5c3RlbS5YbWwuWFBhdGguWFBhdGhFeGNlcHRpb24PAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwNyZXMEYXJncwd2ZXJzaW9uAQEDAwEBAQABAAEHAQYBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAfU3lzdGVtLlhtbC5YUGF0aC5YUGF0aEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgsAAAADezB9CQwAAAAGDQAAAAMyLjAEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJDgAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDwAAABBTeXN0ZW0uRXhjZXB0aW9uBhAAAAAHbWVzc2FnZQkRAAAACRIAAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoRDAAAAAEAAAAJEAAAAAQOAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYYAAAABnNlY3JldAgBAQkZAAAAAREAAAAFAAAACRoAAAACAAAAAgAAAAESAAAABgAAAAkPAAAABhwAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARkAAAAOAAAACAgBAAAABh0AAAADb25lCgEaAAAADgAAAAkYAAAACAEBCR8AAAABHwAAAA4AAAAICAEAAAAJHQAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAH1N5c3RlbS5YbWwuWFBhdGguWFBhdGhFeGNlcHRpb24PAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwNyZXMEYXJncwd2ZXJzaW9uAQEDAwEBAQABAAEHAQYBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAfU3lzdGVtLlhtbC5YUGF0aC5YUGF0aEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgsAAAARWG1sX1VzZXJFeGNlcHRpb24JDAAAAAYNAAAAAzIuMAQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkOAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYPAAAAEFN5c3RlbS5FeGNlcHRpb24GEAAAAAdtZXNzYWdlCREAAAAJEgAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAAChEMAAAAAQAAAAkQAAAABA4AAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhgAAAAGc2VjcmV0CAEBCRkAAAABEQAAAAUAAAAJGgAAAAIAAAACAAAAARIAAAAGAAAACQ8AAAAGHAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBGQAAAA4AAAAICAEAAAAGHQAAAANvbmUKARoAAAAOAAAACRgAAAAIAQEJHwAAAAEfAAAADgAAAAgIAQAAAAkdAAAACgs=" } };
+ yield return new object[] { PopulateException(xPathException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAH1N5c3RlbS5YbWwuWFBhdGguWFBhdGhFeGNlcHRpb24PAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwNyZXMEYXJncwd2ZXJzaW9uAQEDAwEBAQABAAEHAQYBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAfU3lzdGVtLlhtbC5YUGF0aC5YUGF0aEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgsAAAADezB9CQwAAAAGDQAAAAMyLjAEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJDgAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDwAAABBTeXN0ZW0uRXhjZXB0aW9uBhAAAAAHbWVzc2FnZQkRAAAACRIAAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoRDAAAAAEAAAAJEAAAAAQOAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYYAAAABnNlY3JldAgBAQkZAAAAAREAAAAFAAAACRoAAAACAAAAAgAAAAESAAAABgAAAAkPAAAABhwAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARkAAAAOAAAACAgBAAAABh0AAAADb25lCgEaAAAADgAAAAkYAAAACAEBCR8AAAABHwAAAA4AAAAICAEAAAAJHQAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAH1N5c3RlbS5YbWwuWFBhdGguWFBhdGhFeGNlcHRpb24PAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwNyZXMEYXJncwd2ZXJzaW9uAQEDAwEBAQABAAEHAQYBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAfU3lzdGVtLlhtbC5YUGF0aC5YUGF0aEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgsAAAARWG1sX1VzZXJFeGNlcHRpb24JDAAAAAYNAAAAAzIuMAQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkOAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYPAAAAEFN5c3RlbS5FeGNlcHRpb24GEAAAAAdtZXNzYWdlCREAAAAJEgAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAAChEMAAAAAQAAAAkQAAAABA4AAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhgAAAAGc2VjcmV0CAEBCRkAAAABEQAAAAUAAAAJGgAAAAIAAAACAAAAARIAAAAGAAAACQ8AAAAGHAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBGQAAAA4AAAAICAEAAAAGHQAAAANvbmUKARoAAAAOAAAACRgAAAAIAQEJHwAAAAEfAAAADgAAAAgIAQAAAAkdAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var xmlException = new XmlException("message", exception, 1, 1);
- yield return new object[] { PopulateException(xmlException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAF1N5c3RlbS5YbWwuWG1sRXhjZXB0aW9uEgAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMDcmVzBGFyZ3MKbGluZU51bWJlcgxsaW5lUG9zaXRpb24Jc291cmNlVXJpB3ZlcnNpb24BAQMDAQEBAAEAAQcBBgAAAgEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAggIAgAAAAYDAAAAF1N5c3RlbS5YbWwuWG1sRXhjZXB0aW9uBgQAAAAbbWVzc2FnZSBMaW5lIDEsIHBvc2l0aW9uIDEuCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYLAAAAA3swfQkMAAAAAQAAAAEAAAAKBg0AAAADMi4wBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQ4AAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBg8AAAAQU3lzdGVtLkV4Y2VwdGlvbgYQAAAAB21lc3NhZ2UJEQAAAAkSAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKEQwAAAABAAAACRAAAAAEDgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGGAAAAAZzZWNyZXQIAQEJGQAAAAERAAAABQAAAAkaAAAAAgAAAAIAAAABEgAAAAYAAAAJDwAAAAYcAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEZAAAADgAAAAgIAQAAAAYdAAAAA29uZQoBGgAAAA4AAAAJGAAAAAgBAQkfAAAAAR8AAAAOAAAACAgBAAAACR0AAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAF1N5c3RlbS5YbWwuWG1sRXhjZXB0aW9uEgAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMDcmVzBGFyZ3MKbGluZU51bWJlcgxsaW5lUG9zaXRpb24Jc291cmNlVXJpB3ZlcnNpb24BAQMDAQEBAAEAAQcBBgAAAgEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAggIAgAAAAYDAAAAF1N5c3RlbS5YbWwuWG1sRXhjZXB0aW9uBgQAAAAbbWVzc2FnZSBMaW5lIDEsIHBvc2l0aW9uIDEuCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYLAAAAEVhtbF9Vc2VyRXhjZXB0aW9uCQwAAAABAAAAAQAAAAoGDQAAAAMyLjAEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJDgAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDwAAABBTeXN0ZW0uRXhjZXB0aW9uBhAAAAAHbWVzc2FnZQkRAAAACRIAAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoRDAAAAAEAAAAJEAAAAAQOAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYYAAAABnNlY3JldAgBAQkZAAAAAREAAAAFAAAACRoAAAACAAAAAgAAAAESAAAABgAAAAkPAAAABhwAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARkAAAAOAAAACAgBAAAABh0AAAADb25lCgEaAAAADgAAAAkYAAAACAEBCR8AAAABHwAAAA4AAAAICAEAAAAJHQAAAAoL" } };
+ yield return new object[] { PopulateException(xmlException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAF1N5c3RlbS5YbWwuWG1sRXhjZXB0aW9uEgAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMDcmVzBGFyZ3MKbGluZU51bWJlcgxsaW5lUG9zaXRpb24Jc291cmNlVXJpB3ZlcnNpb24BAQMDAQEBAAEAAQcBBgAAAgEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAggIAgAAAAYDAAAAF1N5c3RlbS5YbWwuWG1sRXhjZXB0aW9uBgQAAAAbbWVzc2FnZSBMaW5lIDEsIHBvc2l0aW9uIDEuCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYLAAAAA3swfQkMAAAAAQAAAAEAAAAKBg0AAAADMi4wBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQ4AAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBg8AAAAQU3lzdGVtLkV4Y2VwdGlvbgYQAAAAB21lc3NhZ2UJEQAAAAkSAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKEQwAAAABAAAACRAAAAAEDgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGGAAAAAZzZWNyZXQIAQEJGQAAAAERAAAABQAAAAkaAAAAAgAAAAIAAAABEgAAAAYAAAAJDwAAAAYcAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEZAAAADgAAAAgIAQAAAAYdAAAAA29uZQoBGgAAAA4AAAAJGAAAAAgBAQkfAAAAAR8AAAAOAAAACAgBAAAACR0AAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAF1N5c3RlbS5YbWwuWG1sRXhjZXB0aW9uEgAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMDcmVzBGFyZ3MKbGluZU51bWJlcgxsaW5lUG9zaXRpb24Jc291cmNlVXJpB3ZlcnNpb24BAQMDAQEBAAEAAQcBBgAAAgEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAggIAgAAAAYDAAAAF1N5c3RlbS5YbWwuWG1sRXhjZXB0aW9uBgQAAAAbbWVzc2FnZSBMaW5lIDEsIHBvc2l0aW9uIDEuCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYLAAAAEVhtbF9Vc2VyRXhjZXB0aW9uCQwAAAABAAAAAQAAAAoGDQAAAAMyLjAEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJDgAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDwAAABBTeXN0ZW0uRXhjZXB0aW9uBhAAAAAHbWVzc2FnZQkRAAAACRIAAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoRDAAAAAEAAAAJEAAAAAQOAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYYAAAABnNlY3JldAgBAQkZAAAAAREAAAAFAAAACRoAAAACAAAAAgAAAAESAAAABgAAAAkPAAAABhwAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARkAAAAOAAAACAgBAAAABh0AAAADb25lCgEaAAAADgAAAAkYAAAACAEBCR8AAAABHwAAAA4AAAAICAEAAAAJHQAAAAoL", TargetFrameworkMoniker.netfx461) } };
var xmlSchemaException = new XmlSchemaException("message", exception, 1, 1);
- yield return new object[] { PopulateException(xmlSchemaException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAJFN5c3RlbS5YbWwuU2NoZW1hLlhtbFNjaGVtYUV4Y2VwdGlvbhIAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzA3JlcwRhcmdzCXNvdXJjZVVyaQpsaW5lTnVtYmVyDGxpbmVQb3NpdGlvbgd2ZXJzaW9uAQEDAwEBAQABAAEHAQYCAAABKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIICAIAAAAGAwAAACRTeXN0ZW0uWG1sLlNjaGVtYS5YbWxTY2hlbWFFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYLAAAAA3swfQkMAAAACgEAAAABAAAABg0AAAADMi4wBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQ4AAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBg8AAAAQU3lzdGVtLkV4Y2VwdGlvbgYQAAAAB21lc3NhZ2UJEQAAAAkSAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKEQwAAAABAAAACRAAAAAEDgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGGAAAAAZzZWNyZXQIAQEJGQAAAAERAAAABQAAAAkaAAAAAgAAAAIAAAABEgAAAAYAAAAJDwAAAAYcAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEZAAAADgAAAAgIAQAAAAYdAAAAA29uZQoBGgAAAA4AAAAJGAAAAAgBAQkfAAAAAR8AAAAOAAAACAgBAAAACR0AAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAJFN5c3RlbS5YbWwuU2NoZW1hLlhtbFNjaGVtYUV4Y2VwdGlvbhIAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzA3JlcwRhcmdzCXNvdXJjZVVyaQpsaW5lTnVtYmVyDGxpbmVQb3NpdGlvbgd2ZXJzaW9uAQEDAwEBAQABAAEHAQYCAAABKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIICAIAAAAGAwAAACRTeXN0ZW0uWG1sLlNjaGVtYS5YbWxTY2hlbWFFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYLAAAAEVhtbF9Vc2VyRXhjZXB0aW9uCQwAAAAKAQAAAAEAAAAGDQAAAAMyLjAEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJDgAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDwAAABBTeXN0ZW0uRXhjZXB0aW9uBhAAAAAHbWVzc2FnZQkRAAAACRIAAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoRDAAAAAEAAAAJEAAAAAQOAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYYAAAABnNlY3JldAgBAQkZAAAAAREAAAAFAAAACRoAAAACAAAAAgAAAAESAAAABgAAAAkPAAAABhwAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARkAAAAOAAAACAgBAAAABh0AAAADb25lCgEaAAAADgAAAAkYAAAACAEBCR8AAAABHwAAAA4AAAAICAEAAAAJHQAAAAoL" } };
+ yield return new object[] { PopulateException(xmlSchemaException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAJFN5c3RlbS5YbWwuU2NoZW1hLlhtbFNjaGVtYUV4Y2VwdGlvbhIAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzA3JlcwRhcmdzCXNvdXJjZVVyaQpsaW5lTnVtYmVyDGxpbmVQb3NpdGlvbgd2ZXJzaW9uAQEDAwEBAQABAAEHAQYCAAABKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIICAIAAAAGAwAAACRTeXN0ZW0uWG1sLlNjaGVtYS5YbWxTY2hlbWFFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYLAAAAA3swfQkMAAAACgEAAAABAAAABg0AAAADMi4wBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQ4AAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBg8AAAAQU3lzdGVtLkV4Y2VwdGlvbgYQAAAAB21lc3NhZ2UJEQAAAAkSAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKEQwAAAABAAAACRAAAAAEDgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGGAAAAAZzZWNyZXQIAQEJGQAAAAERAAAABQAAAAkaAAAAAgAAAAIAAAABEgAAAAYAAAAJDwAAAAYcAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEZAAAADgAAAAgIAQAAAAYdAAAAA29uZQoBGgAAAA4AAAAJGAAAAAgBAQkfAAAAAR8AAAAOAAAACAgBAAAACR0AAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAJFN5c3RlbS5YbWwuU2NoZW1hLlhtbFNjaGVtYUV4Y2VwdGlvbhIAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzA3JlcwRhcmdzCXNvdXJjZVVyaQpsaW5lTnVtYmVyDGxpbmVQb3NpdGlvbgd2ZXJzaW9uAQEDAwEBAQABAAEHAQYCAAABKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIICAIAAAAGAwAAACRTeXN0ZW0uWG1sLlNjaGVtYS5YbWxTY2hlbWFFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYLAAAAEVhtbF9Vc2VyRXhjZXB0aW9uCQwAAAAKAQAAAAEAAAAGDQAAAAMyLjAEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJDgAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDwAAABBTeXN0ZW0uRXhjZXB0aW9uBhAAAAAHbWVzc2FnZQkRAAAACRIAAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoRDAAAAAEAAAAJEAAAAAQOAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYYAAAABnNlY3JldAgBAQkZAAAAAREAAAAFAAAACRoAAAACAAAAAgAAAAESAAAABgAAAAkPAAAABhwAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARkAAAAOAAAACAgBAAAABh0AAAADb25lCgEaAAAADgAAAAkYAAAACAEBCR8AAAABHwAAAA4AAAAICAEAAAAJHQAAAAoL", TargetFrameworkMoniker.netfx461) } };
var xmlSchemaInferenceException = new XmlSchemaInferenceException("message", exception, 1, 1);
- yield return new object[] { PopulateException(xmlSchemaInferenceException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAALVN5c3RlbS5YbWwuU2NoZW1hLlhtbFNjaGVtYUluZmVyZW5jZUV4Y2VwdGlvbhIAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzA3JlcwRhcmdzCXNvdXJjZVVyaQpsaW5lTnVtYmVyDGxpbmVQb3NpdGlvbgd2ZXJzaW9uAQEDAwEBAQABAAEHAQYCAAABKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIICAIAAAAGAwAAAC1TeXN0ZW0uWG1sLlNjaGVtYS5YbWxTY2hlbWFJbmZlcmVuY2VFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYLAAAAA3swfQkMAAAACgEAAAABAAAABg0AAAADMi4wBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQ4AAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBg8AAAAQU3lzdGVtLkV4Y2VwdGlvbgYQAAAAB21lc3NhZ2UJEQAAAAkSAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKEQwAAAABAAAACRAAAAAEDgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGGAAAAAZzZWNyZXQIAQEJGQAAAAERAAAABQAAAAkaAAAAAgAAAAIAAAABEgAAAAYAAAAJDwAAAAYcAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEZAAAADgAAAAgIAQAAAAYdAAAAA29uZQoBGgAAAA4AAAAJGAAAAAgBAQkfAAAAAR8AAAAOAAAACAgBAAAACR0AAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAALVN5c3RlbS5YbWwuU2NoZW1hLlhtbFNjaGVtYUluZmVyZW5jZUV4Y2VwdGlvbhIAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzA3JlcwRhcmdzCXNvdXJjZVVyaQpsaW5lTnVtYmVyDGxpbmVQb3NpdGlvbgd2ZXJzaW9uAQEDAwEBAQABAAEHAQYCAAABKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIICAIAAAAGAwAAAC1TeXN0ZW0uWG1sLlNjaGVtYS5YbWxTY2hlbWFJbmZlcmVuY2VFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYLAAAAEVhtbF9Vc2VyRXhjZXB0aW9uCQwAAAAKAQAAAAEAAAAGDQAAAAMyLjAEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJDgAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDwAAABBTeXN0ZW0uRXhjZXB0aW9uBhAAAAAHbWVzc2FnZQkRAAAACRIAAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoRDAAAAAEAAAAJEAAAAAQOAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYYAAAABnNlY3JldAgBAQkZAAAAAREAAAAFAAAACRoAAAACAAAAAgAAAAESAAAABgAAAAkPAAAABhwAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARkAAAAOAAAACAgBAAAABh0AAAADb25lCgEaAAAADgAAAAkYAAAACAEBCR8AAAABHwAAAA4AAAAICAEAAAAJHQAAAAoL" } };
+ yield return new object[] { PopulateException(xmlSchemaInferenceException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAALVN5c3RlbS5YbWwuU2NoZW1hLlhtbFNjaGVtYUluZmVyZW5jZUV4Y2VwdGlvbhIAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzA3JlcwRhcmdzCXNvdXJjZVVyaQpsaW5lTnVtYmVyDGxpbmVQb3NpdGlvbgd2ZXJzaW9uAQEDAwEBAQABAAEHAQYCAAABKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIICAIAAAAGAwAAAC1TeXN0ZW0uWG1sLlNjaGVtYS5YbWxTY2hlbWFJbmZlcmVuY2VFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYLAAAAA3swfQkMAAAACgEAAAABAAAABg0AAAADMi4wBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQ4AAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBg8AAAAQU3lzdGVtLkV4Y2VwdGlvbgYQAAAAB21lc3NhZ2UJEQAAAAkSAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKEQwAAAABAAAACRAAAAAEDgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGGAAAAAZzZWNyZXQIAQEJGQAAAAERAAAABQAAAAkaAAAAAgAAAAIAAAABEgAAAAYAAAAJDwAAAAYcAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEZAAAADgAAAAgIAQAAAAYdAAAAA29uZQoBGgAAAA4AAAAJGAAAAAgBAQkfAAAAAR8AAAAOAAAACAgBAAAACR0AAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAALVN5c3RlbS5YbWwuU2NoZW1hLlhtbFNjaGVtYUluZmVyZW5jZUV4Y2VwdGlvbhIAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzA3JlcwRhcmdzCXNvdXJjZVVyaQpsaW5lTnVtYmVyDGxpbmVQb3NpdGlvbgd2ZXJzaW9uAQEDAwEBAQABAAEHAQYCAAABKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIICAIAAAAGAwAAAC1TeXN0ZW0uWG1sLlNjaGVtYS5YbWxTY2hlbWFJbmZlcmVuY2VFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYLAAAAEVhtbF9Vc2VyRXhjZXB0aW9uCQwAAAAKAQAAAAEAAAAGDQAAAAMyLjAEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJDgAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDwAAABBTeXN0ZW0uRXhjZXB0aW9uBhAAAAAHbWVzc2FnZQkRAAAACRIAAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoRDAAAAAEAAAAJEAAAAAQOAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYYAAAABnNlY3JldAgBAQkZAAAAAREAAAAFAAAACRoAAAACAAAAAgAAAAESAAAABgAAAAkPAAAABhwAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARkAAAAOAAAACAgBAAAABh0AAAADb25lCgEaAAAADgAAAAkYAAAACAEBCR8AAAABHwAAAA4AAAAICAEAAAAJHQAAAAoL", TargetFrameworkMoniker.netfx461) } };
var xmlSchemaValidationException = new XmlSchemaValidationException("message", exception, 1, 1);
- yield return new object[] { PopulateException(xmlSchemaValidationException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAALlN5c3RlbS5YbWwuU2NoZW1hLlhtbFNjaGVtYVZhbGlkYXRpb25FeGNlcHRpb24SAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwNyZXMEYXJncwlzb3VyY2VVcmkKbGluZU51bWJlcgxsaW5lUG9zaXRpb24HdmVyc2lvbgEBAwMBAQEAAQABBwEGAgAAASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAgCAAAABgMAAAAuU3lzdGVtLlhtbC5TY2hlbWEuWG1sU2NoZW1hVmFsaWRhdGlvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgsAAAADezB9CQwAAAAKAQAAAAEAAAAGDQAAAAMyLjAEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJDgAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDwAAABBTeXN0ZW0uRXhjZXB0aW9uBhAAAAAHbWVzc2FnZQkRAAAACRIAAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoRDAAAAAEAAAAJEAAAAAQOAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYYAAAABnNlY3JldAgBAQkZAAAAAREAAAAFAAAACRoAAAACAAAAAgAAAAESAAAABgAAAAkPAAAABhwAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARkAAAAOAAAACAgBAAAABh0AAAADb25lCgEaAAAADgAAAAkYAAAACAEBCR8AAAABHwAAAA4AAAAICAEAAAAJHQAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAALlN5c3RlbS5YbWwuU2NoZW1hLlhtbFNjaGVtYVZhbGlkYXRpb25FeGNlcHRpb24SAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwNyZXMEYXJncwlzb3VyY2VVcmkKbGluZU51bWJlcgxsaW5lUG9zaXRpb24HdmVyc2lvbgEBAwMBAQEAAQABBwEGAgAAASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAgCAAAABgMAAAAuU3lzdGVtLlhtbC5TY2hlbWEuWG1sU2NoZW1hVmFsaWRhdGlvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgsAAAARWG1sX1VzZXJFeGNlcHRpb24JDAAAAAoBAAAAAQAAAAYNAAAAAzIuMAQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkOAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYPAAAAEFN5c3RlbS5FeGNlcHRpb24GEAAAAAdtZXNzYWdlCREAAAAJEgAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAAChEMAAAAAQAAAAkQAAAABA4AAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhgAAAAGc2VjcmV0CAEBCRkAAAABEQAAAAUAAAAJGgAAAAIAAAACAAAAARIAAAAGAAAACQ8AAAAGHAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBGQAAAA4AAAAICAEAAAAGHQAAAANvbmUKARoAAAAOAAAACRgAAAAIAQEJHwAAAAEfAAAADgAAAAgIAQAAAAkdAAAACgs=" } };
+ yield return new object[] { PopulateException(xmlSchemaValidationException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAALlN5c3RlbS5YbWwuU2NoZW1hLlhtbFNjaGVtYVZhbGlkYXRpb25FeGNlcHRpb24SAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwNyZXMEYXJncwlzb3VyY2VVcmkKbGluZU51bWJlcgxsaW5lUG9zaXRpb24HdmVyc2lvbgEBAwMBAQEAAQABBwEGAgAAASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAgCAAAABgMAAAAuU3lzdGVtLlhtbC5TY2hlbWEuWG1sU2NoZW1hVmFsaWRhdGlvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgsAAAADezB9CQwAAAAKAQAAAAEAAAAGDQAAAAMyLjAEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJDgAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDwAAABBTeXN0ZW0uRXhjZXB0aW9uBhAAAAAHbWVzc2FnZQkRAAAACRIAAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoRDAAAAAEAAAAJEAAAAAQOAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYYAAAABnNlY3JldAgBAQkZAAAAAREAAAAFAAAACRoAAAACAAAAAgAAAAESAAAABgAAAAkPAAAABhwAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARkAAAAOAAAACAgBAAAABh0AAAADb25lCgEaAAAADgAAAAkYAAAACAEBCR8AAAABHwAAAA4AAAAICAEAAAAJHQAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAALlN5c3RlbS5YbWwuU2NoZW1hLlhtbFNjaGVtYVZhbGlkYXRpb25FeGNlcHRpb24SAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwNyZXMEYXJncwlzb3VyY2VVcmkKbGluZU51bWJlcgxsaW5lUG9zaXRpb24HdmVyc2lvbgEBAwMBAQEAAQABBwEGAgAAASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAgCAAAABgMAAAAuU3lzdGVtLlhtbC5TY2hlbWEuWG1sU2NoZW1hVmFsaWRhdGlvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgsAAAARWG1sX1VzZXJFeGNlcHRpb24JDAAAAAoBAAAAAQAAAAYNAAAAAzIuMAQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkOAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYPAAAAEFN5c3RlbS5FeGNlcHRpb24GEAAAAAdtZXNzYWdlCREAAAAJEgAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAAChEMAAAAAQAAAAkQAAAABA4AAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhgAAAAGc2VjcmV0CAEBCRkAAAABEQAAAAUAAAAJGgAAAAIAAAACAAAAARIAAAAGAAAACQ8AAAAGHAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBGQAAAA4AAAAICAEAAAAGHQAAAANvbmUKARoAAAAOAAAACRgAAAAIAQEJHwAAAAEfAAAADgAAAAgIAQAAAAkdAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var xsltCompileException = new XsltCompileException(exception, "///file", 1, 1);
- yield return new object[] { PopulateException(xsltCompileException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAI1N5c3RlbS5YbWwuWHNsLlhzbHRDb21waWxlRXhjZXB0aW9uEgAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMDcmVzBGFyZ3MJc291cmNlVXJpCmxpbmVOdW1iZXIMbGluZVBvc2l0aW9uB3ZlcnNpb24BAQMDAQEBAAEAAQcBAgEAAAEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAggIAgAAAAYDAAAAI1N5c3RlbS5YbWwuWHNsLlhzbHRDb21waWxlRXhjZXB0aW9uBgQAAABDWFNMVCBjb21waWxlIGVycm9yIGF0IC8vL2ZpbGUoMSwxKS4gU2VlIElubmVyRXhjZXB0aW9uIGZvciBkZXRhaWxzLgkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoGCwAAAENYU0xUIGNvbXBpbGUgZXJyb3IgYXQgezB9KHsxfSx7Mn0pLiBTZWUgSW5uZXJFeGNlcHRpb24gZm9yIGRldGFpbHMuCgYMAAAABy8vL2ZpbGUBAAAAAQAAAAYNAAAAAzIuMAQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkOAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYPAAAAEFN5c3RlbS5FeGNlcHRpb24GEAAAAAdtZXNzYWdlCREAAAAJEgAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQOAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYXAAAABnNlY3JldAgBAQkYAAAAAREAAAAFAAAACRkAAAACAAAAAgAAAAESAAAABgAAAAkPAAAABhsAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARgAAAAOAAAACAgBAAAABhwAAAADb25lCgEZAAAADgAAAAkXAAAACAEBCR4AAAABHgAAAA4AAAAICAEAAAAJHAAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAI1N5c3RlbS5YbWwuWHNsLlhzbHRDb21waWxlRXhjZXB0aW9uEgAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMDcmVzBGFyZ3MJc291cmNlVXJpCmxpbmVOdW1iZXIMbGluZVBvc2l0aW9uB3ZlcnNpb24BAQMDAQEBAAEAAQcBAgEAAAEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAggIAgAAAAYDAAAAI1N5c3RlbS5YbWwuWHNsLlhzbHRDb21waWxlRXhjZXB0aW9uBgQAAABDWFNMVCBjb21waWxlIGVycm9yIGF0IC8vL2ZpbGUoMSwxKS4gU2VlIElubmVyRXhjZXB0aW9uIGZvciBkZXRhaWxzLgkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoGCwAAABFYc2x0X0NvbXBpbGVFcnJvcgoGDAAAAAcvLy9maWxlAQAAAAEAAAAGDQAAAAMyLjAEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJDgAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDwAAABBTeXN0ZW0uRXhjZXB0aW9uBhAAAAAHbWVzc2FnZQkRAAAACRIAAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoEDgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFwAAAAZzZWNyZXQIAQEJGAAAAAERAAAABQAAAAkZAAAAAgAAAAIAAAABEgAAAAYAAAAJDwAAAAYbAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEYAAAADgAAAAgIAQAAAAYcAAAAA29uZQoBGQAAAA4AAAAJFwAAAAgBAQkeAAAAAR4AAAAOAAAACAgBAAAACRwAAAAKCw==" } };
+ yield return new object[] { PopulateException(xsltCompileException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAI1N5c3RlbS5YbWwuWHNsLlhzbHRDb21waWxlRXhjZXB0aW9uEgAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMDcmVzBGFyZ3MJc291cmNlVXJpCmxpbmVOdW1iZXIMbGluZVBvc2l0aW9uB3ZlcnNpb24BAQMDAQEBAAEAAQcBAgEAAAEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAggIAgAAAAYDAAAAI1N5c3RlbS5YbWwuWHNsLlhzbHRDb21waWxlRXhjZXB0aW9uBgQAAABDWFNMVCBjb21waWxlIGVycm9yIGF0IC8vL2ZpbGUoMSwxKS4gU2VlIElubmVyRXhjZXB0aW9uIGZvciBkZXRhaWxzLgkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoGCwAAAENYU0xUIGNvbXBpbGUgZXJyb3IgYXQgezB9KHsxfSx7Mn0pLiBTZWUgSW5uZXJFeGNlcHRpb24gZm9yIGRldGFpbHMuCgYMAAAABy8vL2ZpbGUBAAAAAQAAAAYNAAAAAzIuMAQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkOAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYPAAAAEFN5c3RlbS5FeGNlcHRpb24GEAAAAAdtZXNzYWdlCREAAAAJEgAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQOAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYXAAAABnNlY3JldAgBAQkYAAAAAREAAAAFAAAACRkAAAACAAAAAgAAAAESAAAABgAAAAkPAAAABhsAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARgAAAAOAAAACAgBAAAABhwAAAADb25lCgEZAAAADgAAAAkXAAAACAEBCR4AAAABHgAAAA4AAAAICAEAAAAJHAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAI1N5c3RlbS5YbWwuWHNsLlhzbHRDb21waWxlRXhjZXB0aW9uEgAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMDcmVzBGFyZ3MJc291cmNlVXJpCmxpbmVOdW1iZXIMbGluZVBvc2l0aW9uB3ZlcnNpb24BAQMDAQEBAAEAAQcBAgEAAAEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAggIAgAAAAYDAAAAI1N5c3RlbS5YbWwuWHNsLlhzbHRDb21waWxlRXhjZXB0aW9uBgQAAABDWFNMVCBjb21waWxlIGVycm9yIGF0IC8vL2ZpbGUoMSwxKS4gU2VlIElubmVyRXhjZXB0aW9uIGZvciBkZXRhaWxzLgkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoGCwAAABFYc2x0X0NvbXBpbGVFcnJvcgoGDAAAAAcvLy9maWxlAQAAAAEAAAAGDQAAAAMyLjAEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJDgAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDwAAABBTeXN0ZW0uRXhjZXB0aW9uBhAAAAAHbWVzc2FnZQkRAAAACRIAAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoEDgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFwAAAAZzZWNyZXQIAQEJGAAAAAERAAAABQAAAAkZAAAAAgAAAAIAAAABEgAAAAYAAAAJDwAAAAYbAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEYAAAADgAAAAgIAQAAAAYcAAAAA29uZQoBGQAAAA4AAAAJFwAAAAgBAQkeAAAAAR4AAAAOAAAACAgBAAAACRwAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var xsltException = new XsltException("message", exception);
- yield return new object[] { PopulateException(xsltException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAHFN5c3RlbS5YbWwuWHNsLlhzbHRFeGNlcHRpb24SAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwNyZXMEYXJncwlzb3VyY2VVcmkKbGluZU51bWJlcgxsaW5lUG9zaXRpb24HdmVyc2lvbgEBAwMBAQEAAQABBwECAgAAASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAgCAAAABgMAAAAcU3lzdGVtLlhtbC5Yc2wuWHNsdEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgsAAAADezB9CgoAAAAAAAAAAAYMAAAAAzIuMAQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkNAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYOAAAAEFN5c3RlbS5FeGNlcHRpb24GDwAAAAdtZXNzYWdlCRAAAAAJEQAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQNAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYWAAAABnNlY3JldAgBAQkXAAAAARAAAAAFAAAACRgAAAACAAAAAgAAAAERAAAABgAAAAkOAAAABhoAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARcAAAANAAAACAgBAAAABhsAAAADb25lCgEYAAAADQAAAAkWAAAACAEBCR0AAAABHQAAAA0AAAAICAEAAAAJGwAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAHFN5c3RlbS5YbWwuWHNsLlhzbHRFeGNlcHRpb24SAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwNyZXMEYXJncwlzb3VyY2VVcmkKbGluZU51bWJlcgxsaW5lUG9zaXRpb24HdmVyc2lvbgEBAwMBAQEAAQABBwECAgAAASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAgCAAAABgMAAAAcU3lzdGVtLlhtbC5Yc2wuWHNsdEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgsAAAARWG1sX1VzZXJFeGNlcHRpb24KCgAAAAAAAAAABgwAAAADMi4wBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQ0AAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBg4AAAAQU3lzdGVtLkV4Y2VwdGlvbgYPAAAAB21lc3NhZ2UJEAAAAAkRAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBA0AAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhYAAAAGc2VjcmV0CAEBCRcAAAABEAAAAAUAAAAJGAAAAAIAAAACAAAAAREAAAAGAAAACQ4AAAAGGgAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFwAAAA0AAAAICAEAAAAGGwAAAANvbmUKARgAAAANAAAACRYAAAAIAQEJHQAAAAEdAAAADQAAAAgIAQAAAAkbAAAACgs=" } };
+ yield return new object[] { PopulateException(xsltException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAHFN5c3RlbS5YbWwuWHNsLlhzbHRFeGNlcHRpb24SAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwNyZXMEYXJncwlzb3VyY2VVcmkKbGluZU51bWJlcgxsaW5lUG9zaXRpb24HdmVyc2lvbgEBAwMBAQEAAQABBwECAgAAASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAgCAAAABgMAAAAcU3lzdGVtLlhtbC5Yc2wuWHNsdEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgsAAAADezB9CgoAAAAAAAAAAAYMAAAAAzIuMAQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkNAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYOAAAAEFN5c3RlbS5FeGNlcHRpb24GDwAAAAdtZXNzYWdlCRAAAAAJEQAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQNAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYWAAAABnNlY3JldAgBAQkXAAAAARAAAAAFAAAACRgAAAACAAAAAgAAAAERAAAABgAAAAkOAAAABhoAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARcAAAANAAAACAgBAAAABhsAAAADb25lCgEYAAAADQAAAAkWAAAACAEBCR0AAAABHQAAAA0AAAAICAEAAAAJGwAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE1TeXN0ZW0uWG1sLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAHFN5c3RlbS5YbWwuWHNsLlhzbHRFeGNlcHRpb24SAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwNyZXMEYXJncwlzb3VyY2VVcmkKbGluZU51bWJlcgxsaW5lUG9zaXRpb24HdmVyc2lvbgEBAwMBAQEAAQABBwECAgAAASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAgCAAAABgMAAAAcU3lzdGVtLlhtbC5Yc2wuWHNsdEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgsAAAARWG1sX1VzZXJFeGNlcHRpb24KCgAAAAAAAAAABgwAAAADMi4wBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQ0AAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBg4AAAAQU3lzdGVtLkV4Y2VwdGlvbgYPAAAAB21lc3NhZ2UJEAAAAAkRAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBA0AAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhYAAAAGc2VjcmV0CAEBCRcAAAABEAAAAAUAAAAJGAAAAAIAAAACAAAAAREAAAAGAAAACQ4AAAAGGgAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFwAAAA0AAAAICAEAAAAGGwAAAANvbmUKARgAAAANAAAACRYAAAAIAQEJHQAAAAEdAAAADQAAAAgIAQAAAAkbAAAACgs=", TargetFrameworkMoniker.netfx461) } };
}
// Assembly load error with shims in uap/uapaot configuration. Issue #24916
if (!PlatformDetection.IsUap)
{
var validationException = new ValidationException("message", exception);
- yield return new object[] { PopulateException(validationException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAGhTeXN0ZW0uQ29tcG9uZW50TW9kZWwuRGF0YUFubm90YXRpb25zLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49MzFiZjM4NTZhZDM2NGUzNQUBAAAAOVN5c3RlbS5Db21wb25lbnRNb2RlbC5EYXRhQW5ub3RhdGlvbnMuVmFsaWRhdGlvbkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAA5U3lzdGVtLkNvbXBvbmVudE1vZGVsLkRhdGFBbm5vdGF0aW9ucy5WYWxpZGF0aW9uRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAGhTeXN0ZW0uQ29tcG9uZW50TW9kZWwuRGF0YUFubm90YXRpb25zLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49MzFiZjM4NTZhZDM2NGUzNQUBAAAAOVN5c3RlbS5Db21wb25lbnRNb2RlbC5EYXRhQW5ub3RhdGlvbnMuVmFsaWRhdGlvbkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAA5U3lzdGVtLkNvbXBvbmVudE1vZGVsLkRhdGFBbm5vdGF0aW9ucy5WYWxpZGF0aW9uRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=" } };
+ yield return new object[] { PopulateException(validationException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAGhTeXN0ZW0uQ29tcG9uZW50TW9kZWwuRGF0YUFubm90YXRpb25zLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49MzFiZjM4NTZhZDM2NGUzNQUBAAAAOVN5c3RlbS5Db21wb25lbnRNb2RlbC5EYXRhQW5ub3RhdGlvbnMuVmFsaWRhdGlvbkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAA5U3lzdGVtLkNvbXBvbmVudE1vZGVsLkRhdGFBbm5vdGF0aW9ucy5WYWxpZGF0aW9uRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAGhTeXN0ZW0uQ29tcG9uZW50TW9kZWwuRGF0YUFubm90YXRpb25zLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49MzFiZjM4NTZhZDM2NGUzNQUBAAAAOVN5c3RlbS5Db21wb25lbnRNb2RlbC5EYXRhQW5ub3RhdGlvbnMuVmFsaWRhdGlvbkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAA5U3lzdGVtLkNvbXBvbmVudE1vZGVsLkRhdGFBbm5vdGF0aW9ucy5WYWxpZGF0aW9uRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netfx461) } };
}
var constraintException = new ConstraintException("message", exception);
- yield return new object[] { PopulateException(constraintException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB9TeXN0ZW0uRGF0YS5Db25zdHJhaW50RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAB9TeXN0ZW0uRGF0YS5Db25zdHJhaW50RXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB9TeXN0ZW0uRGF0YS5Db25zdHJhaW50RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAB9TeXN0ZW0uRGF0YS5Db25zdHJhaW50RXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=" } };
+ yield return new object[] { PopulateException(constraintException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB9TeXN0ZW0uRGF0YS5Db25zdHJhaW50RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAB9TeXN0ZW0uRGF0YS5Db25zdHJhaW50RXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB9TeXN0ZW0uRGF0YS5Db25zdHJhaW50RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAB9TeXN0ZW0uRGF0YS5Db25zdHJhaW50RXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var contextMarshalException = new ContextMarshalException("message", exception);
- yield return new object[] { PopulateException(contextMarshalException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uQ29udGV4dE1hcnNoYWxFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLkNvbnRleHRNYXJzaGFsRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uQ29udGV4dE1hcnNoYWxFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLkNvbnRleHRNYXJzaGFsRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(contextMarshalException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uQ29udGV4dE1hcnNoYWxFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLkNvbnRleHRNYXJzaGFsRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uQ29udGV4dE1hcnNoYWxFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLkNvbnRleHRNYXJzaGFsRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
if (!PlatformDetection.IsUap)
{
Exception contractException = (Exception)Type.GetType("System.Diagnostics.Contracts.ContractException", true)
.GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(ContractFailureKind), typeof(string), typeof(string), typeof(string), typeof(Exception) }, null)
.Invoke(new object[] { ContractFailureKind.Invariant, "failure", "userMessage", "condition", exception });
- yield return new object[] { PopulateException(contractException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAC5TeXN0ZW0uRGlhZ25vc3RpY3MuQ29udHJhY3RzLkNvbnRyYWN0RXhjZXB0aW9uDwAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMES2luZAtVc2VyTWVzc2FnZQlDb25kaXRpb24BAQMDAQEBAAEAAQcDAQEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAjBTeXN0ZW0uRGlhZ25vc3RpY3MuQ29udHJhY3RzLkNvbnRyYWN0RmFpbHVyZUtpbmQGAgAAAC5TeXN0ZW0uRGlhZ25vc3RpY3MuQ29udHJhY3RzLkNvbnRyYWN0RXhjZXB0aW9uBgMAAAAHZmFpbHVyZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoE9v///zBTeXN0ZW0uRGlhZ25vc3RpY3MuQ29udHJhY3RzLkNvbnRyYWN0RmFpbHVyZUtpbmQBAAAAB3ZhbHVlX18ACAMAAAAGCwAAAAt1c2VyTWVzc2FnZQYMAAAACWNvbmRpdGlvbgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkNAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYOAAAAEFN5c3RlbS5FeGNlcHRpb24GDwAAAAdtZXNzYWdlCRAAAAAJEQAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQNAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYWAAAABnNlY3JldAgBAQkXAAAAARAAAAAEAAAACRgAAAACAAAAAgAAAAERAAAABQAAAAkOAAAABhoAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARcAAAANAAAACAgBAAAABhsAAAADb25lCgEYAAAADQAAAAkWAAAACAEBCR0AAAABHQAAAA0AAAAICAEAAAAJGwAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAAC5TeXN0ZW0uRGlhZ25vc3RpY3MuQ29udHJhY3RzLkNvbnRyYWN0RXhjZXB0aW9uDwAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMES2luZAtVc2VyTWVzc2FnZQlDb25kaXRpb24BAQMDAQEBAAEAAQcDAQEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAjBTeXN0ZW0uRGlhZ25vc3RpY3MuQ29udHJhY3RzLkNvbnRyYWN0RmFpbHVyZUtpbmQGAgAAAC5TeXN0ZW0uRGlhZ25vc3RpY3MuQ29udHJhY3RzLkNvbnRyYWN0RXhjZXB0aW9uBgMAAAAHZmFpbHVyZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoE9v///zBTeXN0ZW0uRGlhZ25vc3RpY3MuQ29udHJhY3RzLkNvbnRyYWN0RmFpbHVyZUtpbmQBAAAAB3ZhbHVlX18ACAMAAAAGCwAAAAt1c2VyTWVzc2FnZQYMAAAACWNvbmRpdGlvbgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkNAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYOAAAAEFN5c3RlbS5FeGNlcHRpb24GDwAAAAdtZXNzYWdlCRAAAAAJEQAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQNAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYWAAAABnNlY3JldAgBAQkXAAAAARAAAAAEAAAACRgAAAACAAAAAgAAAAERAAAABQAAAAkOAAAABhoAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARcAAAANAAAACAgBAAAABhsAAAADb25lCgEYAAAADQAAAAkWAAAACAEBCR0AAAABHQAAAA0AAAAICAEAAAAJGwAAAAoL" } };
+ yield return new object[] { PopulateException(contractException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAC5TeXN0ZW0uRGlhZ25vc3RpY3MuQ29udHJhY3RzLkNvbnRyYWN0RXhjZXB0aW9uDwAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMES2luZAtVc2VyTWVzc2FnZQlDb25kaXRpb24BAQMDAQEBAAEAAQcDAQEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAjBTeXN0ZW0uRGlhZ25vc3RpY3MuQ29udHJhY3RzLkNvbnRyYWN0RmFpbHVyZUtpbmQGAgAAAC5TeXN0ZW0uRGlhZ25vc3RpY3MuQ29udHJhY3RzLkNvbnRyYWN0RXhjZXB0aW9uBgMAAAAHZmFpbHVyZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoE9v///zBTeXN0ZW0uRGlhZ25vc3RpY3MuQ29udHJhY3RzLkNvbnRyYWN0RmFpbHVyZUtpbmQBAAAAB3ZhbHVlX18ACAMAAAAGCwAAAAt1c2VyTWVzc2FnZQYMAAAACWNvbmRpdGlvbgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkNAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYOAAAAEFN5c3RlbS5FeGNlcHRpb24GDwAAAAdtZXNzYWdlCRAAAAAJEQAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQNAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYWAAAABnNlY3JldAgBAQkXAAAAARAAAAAEAAAACRgAAAACAAAAAgAAAAERAAAABQAAAAkOAAAABhoAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARcAAAANAAAACAgBAAAABhsAAAADb25lCgEYAAAADQAAAAkWAAAACAEBCR0AAAABHQAAAA0AAAAICAEAAAAJGwAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAC5TeXN0ZW0uRGlhZ25vc3RpY3MuQ29udHJhY3RzLkNvbnRyYWN0RXhjZXB0aW9uDwAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMES2luZAtVc2VyTWVzc2FnZQlDb25kaXRpb24BAQMDAQEBAAEAAQcDAQEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAjBTeXN0ZW0uRGlhZ25vc3RpY3MuQ29udHJhY3RzLkNvbnRyYWN0RmFpbHVyZUtpbmQGAgAAAC5TeXN0ZW0uRGlhZ25vc3RpY3MuQ29udHJhY3RzLkNvbnRyYWN0RXhjZXB0aW9uBgMAAAAHZmFpbHVyZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoE9v///zBTeXN0ZW0uRGlhZ25vc3RpY3MuQ29udHJhY3RzLkNvbnRyYWN0RmFpbHVyZUtpbmQBAAAAB3ZhbHVlX18ACAMAAAAGCwAAAAt1c2VyTWVzc2FnZQYMAAAACWNvbmRpdGlvbgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkNAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYOAAAAEFN5c3RlbS5FeGNlcHRpb24GDwAAAAdtZXNzYWdlCRAAAAAJEQAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQNAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYWAAAABnNlY3JldAgBAQkXAAAAARAAAAAEAAAACRgAAAACAAAAAgAAAAERAAAABQAAAAkOAAAABhoAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARcAAAANAAAACAgBAAAABhsAAAADb25lCgEYAAAADQAAAAkWAAAACAEBCR0AAAABHQAAAA0AAAAICAEAAAAJGwAAAAoL", TargetFrameworkMoniker.netfx461) } };
}
var cookieException = new CookieException();
- yield return new object[] { PopulateException(cookieException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAaU3lzdGVtLk5ldC5Db29raWVFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAGlN5c3RlbS5OZXQuQ29va2llRXhjZXB0aW9uBgQAAAA1T25lIG9mIHRoZSBpZGVudGlmaWVkIGl0ZW1zIHdhcyBpbiBhbiBpbnZhbGlkIGZvcm1hdC4JBQAAAAoGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAaU3lzdGVtLk5ldC5Db29raWVFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAGlN5c3RlbS5OZXQuQ29va2llRXhjZXB0aW9uBgQAAAA1T25lIG9mIHRoZSBpZGVudGlmaWVkIGl0ZW1zIHdhcyBpbiBhbiBpbnZhbGlkIGZvcm1hdC4JBQAAAAoGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==" } };
+ yield return new object[] { PopulateException(cookieException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAaU3lzdGVtLk5ldC5Db29raWVFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAGlN5c3RlbS5OZXQuQ29va2llRXhjZXB0aW9uBgQAAAA1T25lIG9mIHRoZSBpZGVudGlmaWVkIGl0ZW1zIHdhcyBpbiBhbiBpbnZhbGlkIGZvcm1hdC4JBQAAAAoGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAaU3lzdGVtLk5ldC5Db29raWVFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAGlN5c3RlbS5OZXQuQ29va2llRXhjZXB0aW9uBgQAAAA1T25lIG9mIHRoZSBpZGVudGlmaWVkIGl0ZW1zIHdhcyBpbiBhbiBpbnZhbGlkIGZvcm1hdC4JBQAAAAoGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==", TargetFrameworkMoniker.netfx461) } };
//Exception cryptoSignedXmlRecursionException = (Exception)Type.GetType("System.Security.Cryptography.Xml.CryptoSignedXmlRecursionException", true)
// .GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(string), typeof(Exception) }, null)
// .Invoke(new object[] { "message", exception });
- //yield return new object[] { PopulateException(cryptoSignedXmlRecursionException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL", "AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL" } };
+ //yield return new object[] { PopulateException(cryptoSignedXmlRecursionException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL", SerializationFramework.NetcoreApp), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL", SerializationFramework.Netfx) } };
var cryptographicException = new CryptographicException("message", exception);
- yield return new object[] { PopulateException(cryptographicException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAADNTeXN0ZW0uU2VjdXJpdHkuQ3J5cHRvZ3JhcGh5LkNyeXB0b2dyYXBoaWNFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAzU3lzdGVtLlNlY3VyaXR5LkNyeXB0b2dyYXBoeS5DcnlwdG9ncmFwaGljRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAADNTeXN0ZW0uU2VjdXJpdHkuQ3J5cHRvZ3JhcGh5LkNyeXB0b2dyYXBoaWNFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAzU3lzdGVtLlNlY3VyaXR5LkNyeXB0b2dyYXBoeS5DcnlwdG9ncmFwaGljRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(cryptographicException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADNTeXN0ZW0uU2VjdXJpdHkuQ3J5cHRvZ3JhcGh5LkNyeXB0b2dyYXBoaWNFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAzU3lzdGVtLlNlY3VyaXR5LkNyeXB0b2dyYXBoeS5DcnlwdG9ncmFwaGljRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADNTeXN0ZW0uU2VjdXJpdHkuQ3J5cHRvZ3JhcGh5LkNyeXB0b2dyYXBoaWNFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAzU3lzdGVtLlNlY3VyaXR5LkNyeXB0b2dyYXBoeS5DcnlwdG9ncmFwaGljRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var cryptographicUnexpectedOperationException = new CryptographicUnexpectedOperationException("message", exception);
- yield return new object[] { PopulateException(cryptographicUnexpectedOperationException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAEZTeXN0ZW0uU2VjdXJpdHkuQ3J5cHRvZ3JhcGh5LkNyeXB0b2dyYXBoaWNVbmV4cGVjdGVkT3BlcmF0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAARlN5c3RlbS5TZWN1cml0eS5DcnlwdG9ncmFwaHkuQ3J5cHRvZ3JhcGhpY1VuZXhwZWN0ZWRPcGVyYXRpb25FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAEZTeXN0ZW0uU2VjdXJpdHkuQ3J5cHRvZ3JhcGh5LkNyeXB0b2dyYXBoaWNVbmV4cGVjdGVkT3BlcmF0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAARlN5c3RlbS5TZWN1cml0eS5DcnlwdG9ncmFwaHkuQ3J5cHRvZ3JhcGhpY1VuZXhwZWN0ZWRPcGVyYXRpb25FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(cryptographicUnexpectedOperationException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAEZTeXN0ZW0uU2VjdXJpdHkuQ3J5cHRvZ3JhcGh5LkNyeXB0b2dyYXBoaWNVbmV4cGVjdGVkT3BlcmF0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAARlN5c3RlbS5TZWN1cml0eS5DcnlwdG9ncmFwaHkuQ3J5cHRvZ3JhcGhpY1VuZXhwZWN0ZWRPcGVyYXRpb25FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAEZTeXN0ZW0uU2VjdXJpdHkuQ3J5cHRvZ3JhcGh5LkNyeXB0b2dyYXBoaWNVbmV4cGVjdGVkT3BlcmF0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAARlN5c3RlbS5TZWN1cml0eS5DcnlwdG9ncmFwaHkuQ3J5cHRvZ3JhcGhpY1VuZXhwZWN0ZWRPcGVyYXRpb25FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var cultureNotFoundException = new CultureNotFoundException("message", exception);
- yield return new object[] { PopulateException(cultureNotFoundException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAC1TeXN0ZW0uR2xvYmFsaXphdGlvbi5DdWx0dXJlTm90Rm91bmRFeGNlcHRpb24PAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwlQYXJhbU5hbWUQSW52YWxpZEN1bHR1cmVJZBJJbnZhbGlkQ3VsdHVyZU5hbWUBAQMDAQEBAAEAAQcBAwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAm5TeXN0ZW0uTnVsbGFibGVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQYCAAAALVN5c3RlbS5HbG9iYWxpemF0aW9uLkN1bHR1cmVOb3RGb3VuZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgoKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAAC1TeXN0ZW0uR2xvYmFsaXphdGlvbi5DdWx0dXJlTm90Rm91bmRFeGNlcHRpb24PAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwlQYXJhbU5hbWUQSW52YWxpZEN1bHR1cmVJZBJJbnZhbGlkQ3VsdHVyZU5hbWUBAQMDAQEBAAEAAQcBAwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAm5TeXN0ZW0uTnVsbGFibGVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQYCAAAALVN5c3RlbS5HbG9iYWxpemF0aW9uLkN1bHR1cmVOb3RGb3VuZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgoKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL" } };
+ yield return new object[] { PopulateException(cultureNotFoundException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAC1TeXN0ZW0uR2xvYmFsaXphdGlvbi5DdWx0dXJlTm90Rm91bmRFeGNlcHRpb24PAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwlQYXJhbU5hbWUQSW52YWxpZEN1bHR1cmVJZBJJbnZhbGlkQ3VsdHVyZU5hbWUBAQMDAQEBAAEAAQcBAwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAm5TeXN0ZW0uTnVsbGFibGVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQYCAAAALVN5c3RlbS5HbG9iYWxpemF0aW9uLkN1bHR1cmVOb3RGb3VuZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgoKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAC1TeXN0ZW0uR2xvYmFsaXphdGlvbi5DdWx0dXJlTm90Rm91bmRFeGNlcHRpb24PAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwlQYXJhbU5hbWUQSW52YWxpZEN1bHR1cmVJZBJJbnZhbGlkQ3VsdHVyZU5hbWUBAQMDAQEBAAEAAQcBAwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAm5TeXN0ZW0uTnVsbGFibGVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQYCAAAALVN5c3RlbS5HbG9iYWxpemF0aW9uLkN1bHR1cmVOb3RGb3VuZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgoKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netfx461) } };
var customAttributeFormatException = new CustomAttributeFormatException("message", exception);
- yield return new object[] { PopulateException(customAttributeFormatException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAADBTeXN0ZW0uUmVmbGVjdGlvbi5DdXN0b21BdHRyaWJ1dGVGb3JtYXRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAwU3lzdGVtLlJlZmxlY3Rpb24uQ3VzdG9tQXR0cmlidXRlRm9ybWF0RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAADBTeXN0ZW0uUmVmbGVjdGlvbi5DdXN0b21BdHRyaWJ1dGVGb3JtYXRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAwU3lzdGVtLlJlZmxlY3Rpb24uQ3VzdG9tQXR0cmlidXRlRm9ybWF0RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(customAttributeFormatException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADBTeXN0ZW0uUmVmbGVjdGlvbi5DdXN0b21BdHRyaWJ1dGVGb3JtYXRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAwU3lzdGVtLlJlZmxlY3Rpb24uQ3VzdG9tQXR0cmlidXRlRm9ybWF0RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADBTeXN0ZW0uUmVmbGVjdGlvbi5DdXN0b21BdHRyaWJ1dGVGb3JtYXRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAwU3lzdGVtLlJlZmxlY3Rpb24uQ3VzdG9tQXR0cmlidXRlRm9ybWF0RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var dBConcurrencyException = new DBConcurrencyException("message", exception);
- yield return new object[] { PopulateException(dBConcurrencyException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0ZW0uRGF0YS5EQkNvbmN1cnJlbmN5RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACJTeXN0ZW0uRGF0YS5EQkNvbmN1cnJlbmN5RXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0ZW0uRGF0YS5EQkNvbmN1cnJlbmN5RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACJTeXN0ZW0uRGF0YS5EQkNvbmN1cnJlbmN5RXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=" } };
+ yield return new object[] { PopulateException(dBConcurrencyException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0ZW0uRGF0YS5EQkNvbmN1cnJlbmN5RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACJTeXN0ZW0uRGF0YS5EQkNvbmN1cnJlbmN5RXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0ZW0uRGF0YS5EQkNvbmN1cnJlbmN5RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACJTeXN0ZW0uRGF0YS5EQkNvbmN1cnJlbmN5RXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var dataException = new DataException("message", exception);
- yield return new object[] { PopulateException(dataException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABlTeXN0ZW0uRGF0YS5EYXRhRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAABlTeXN0ZW0uRGF0YS5EYXRhRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABlTeXN0ZW0uRGF0YS5EYXRhRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAABlTeXN0ZW0uRGF0YS5EYXRhRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=" } };
+ yield return new object[] { PopulateException(dataException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABlTeXN0ZW0uRGF0YS5EYXRhRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAABlTeXN0ZW0uRGF0YS5EYXRhRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABlTeXN0ZW0uRGF0YS5EYXRhRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAABlTeXN0ZW0uRGF0YS5EYXRhRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var dataMisalignedException = new DataMisalignedException("message", exception);
- yield return new object[] { PopulateException(dataMisalignedException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uRGF0YU1pc2FsaWduZWRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLkRhdGFNaXNhbGlnbmVkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uRGF0YU1pc2FsaWduZWRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLkRhdGFNaXNhbGlnbmVkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(dataMisalignedException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uRGF0YU1pc2FsaWduZWRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLkRhdGFNaXNhbGlnbmVkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uRGF0YU1pc2FsaWduZWRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLkRhdGFNaXNhbGlnbmVkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var decoderFallbackException = new DecoderFallbackException("message", exception);
// DecoderFallbackException sets its HResult itself therefore we pass setHResult as false.
- yield return new object[] { PopulateException(decoderFallbackException, setHResult: false), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACRTeXN0ZW0uVGV4dC5EZWNvZGVyRmFsbGJhY2tFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwlQYXJhbU5hbWUBAQMDAQEBAAEAAQcBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACRTeXN0ZW0uVGV4dC5EZWNvZGVyRmFsbGJhY2tFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAKVwAHgAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAACRTeXN0ZW0uVGV4dC5EZWNvZGVyRmFsbGJhY2tFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwlQYXJhbU5hbWUBAQMDAQEBAAEAAQcBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACRTeXN0ZW0uVGV4dC5EZWNvZGVyRmFsbGJhY2tFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAKVwAHgAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(decoderFallbackException, setHResult: false), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACRTeXN0ZW0uVGV4dC5EZWNvZGVyRmFsbGJhY2tFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwlQYXJhbU5hbWUBAQMDAQEBAAEAAQcBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACRTeXN0ZW0uVGV4dC5EZWNvZGVyRmFsbGJhY2tFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAKVwAHgAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACRTeXN0ZW0uVGV4dC5EZWNvZGVyRmFsbGJhY2tFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwlQYXJhbU5hbWUBAQMDAQEBAAEAAQcBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACRTeXN0ZW0uVGV4dC5EZWNvZGVyRmFsbGJhY2tFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAKVwAHgAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var decoderFallbackException2 = new DecoderFallbackException("message", new byte[2] { 1, 2 }, 0);
// DecoderFallbackException sets its HResult itself therefore we pass setHResult as false.
- yield return new object[] { PopulateException(decoderFallbackException2, setHResult: false), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACRTeXN0ZW0uVGV4dC5EZWNvZGVyRmFsbGJhY2tFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwlQYXJhbU5hbWUBAQMDAQEBAAEAAQcBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACRTeXN0ZW0uVGV4dC5EZWNvZGVyRmFsbGJhY2tFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAKBgUAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYGAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgcAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAApXAAeABggAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkJAAAAAgAAAAIAAAAECQAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGCgAAAAZzZWNyZXQIAQEJCwAAAAELAAAACQAAAAgIAQAAAAYMAAAAA29uZQoL", "AAEAAAD/////AQAAAAAAAAAEAQAAACRTeXN0ZW0uVGV4dC5EZWNvZGVyRmFsbGJhY2tFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwlQYXJhbU5hbWUBAQMDAQEBAAEAAQcBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACRTeXN0ZW0uVGV4dC5EZWNvZGVyRmFsbGJhY2tFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAKBgUAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYGAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgcAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAApXAAeABggAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkJAAAAAgAAAAIAAAAECQAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGCgAAAAZzZWNyZXQIAQEJCwAAAAELAAAACQAAAAgIAQAAAAYMAAAAA29uZQoL" } };
+ yield return new object[] { PopulateException(decoderFallbackException2, setHResult: false), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACRTeXN0ZW0uVGV4dC5EZWNvZGVyRmFsbGJhY2tFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwlQYXJhbU5hbWUBAQMDAQEBAAEAAQcBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACRTeXN0ZW0uVGV4dC5EZWNvZGVyRmFsbGJhY2tFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAKBgUAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYGAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgcAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAApXAAeABggAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkJAAAAAgAAAAIAAAAECQAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGCgAAAAZzZWNyZXQIAQEJCwAAAAELAAAACQAAAAgIAQAAAAYMAAAAA29uZQoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACRTeXN0ZW0uVGV4dC5EZWNvZGVyRmFsbGJhY2tFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwlQYXJhbU5hbWUBAQMDAQEBAAEAAQcBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACRTeXN0ZW0uVGV4dC5EZWNvZGVyRmFsbGJhY2tFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAKBgUAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYGAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgcAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAApXAAeABggAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkJAAAAAgAAAAIAAAAECQAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGCgAAAAZzZWNyZXQIAQEJCwAAAAELAAAACQAAAAgIAQAAAAYMAAAAA29uZQoL", TargetFrameworkMoniker.netfx461) } };
var deletedRowInaccessibleException = new DeletedRowInaccessibleException("message", exception);
- yield return new object[] { PopulateException(deletedRowInaccessibleException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACtTeXN0ZW0uRGF0YS5EZWxldGVkUm93SW5hY2Nlc3NpYmxlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACtTeXN0ZW0uRGF0YS5EZWxldGVkUm93SW5hY2Nlc3NpYmxlRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACtTeXN0ZW0uRGF0YS5EZWxldGVkUm93SW5hY2Nlc3NpYmxlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACtTeXN0ZW0uRGF0YS5EZWxldGVkUm93SW5hY2Nlc3NpYmxlRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=" } };
+ yield return new object[] { PopulateException(deletedRowInaccessibleException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACtTeXN0ZW0uRGF0YS5EZWxldGVkUm93SW5hY2Nlc3NpYmxlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACtTeXN0ZW0uRGF0YS5EZWxldGVkUm93SW5hY2Nlc3NpYmxlRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACtTeXN0ZW0uRGF0YS5EZWxldGVkUm93SW5hY2Nlc3NpYmxlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACtTeXN0ZW0uRGF0YS5EZWxldGVkUm93SW5hY2Nlc3NpYmxlRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var divideByZeroException = new DivideByZeroException("message", exception);
- yield return new object[] { PopulateException(divideByZeroException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uRGl2aWRlQnlaZXJvRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAHFN5c3RlbS5EaXZpZGVCeVplcm9FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uRGl2aWRlQnlaZXJvRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAHFN5c3RlbS5EaXZpZGVCeVplcm9FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(divideByZeroException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uRGl2aWRlQnlaZXJvRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAHFN5c3RlbS5EaXZpZGVCeVplcm9FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uRGl2aWRlQnlaZXJvRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAHFN5c3RlbS5EaXZpZGVCeVplcm9FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var dllNotFoundException = new DllNotFoundException("message", exception);
- yield return new object[] { PopulateException(dllNotFoundException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uRGxsTm90Rm91bmRFeGNlcHRpb24QAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cxFUeXBlTG9hZENsYXNzTmFtZRRUeXBlTG9hZEFzc2VtYmx5TmFtZRJUeXBlTG9hZE1lc3NhZ2VBcmcSVHlwZUxvYWRSZXNvdXJjZUlEAQEDAwEBAQABAAEHAQEBAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAYCAAAAG1N5c3RlbS5EbGxOb3RGb3VuZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgoKAAAAAAQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uRGxsTm90Rm91bmRFeGNlcHRpb24QAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cxFUeXBlTG9hZENsYXNzTmFtZRRUeXBlTG9hZEFzc2VtYmx5TmFtZRJUeXBlTG9hZE1lc3NhZ2VBcmcSVHlwZUxvYWRSZXNvdXJjZUlEAQEDAwEBAQABAAEHAQEBAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAYCAAAAG1N5c3RlbS5EbGxOb3RGb3VuZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgoKAAAAAAQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(dllNotFoundException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uRGxsTm90Rm91bmRFeGNlcHRpb24QAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cxFUeXBlTG9hZENsYXNzTmFtZRRUeXBlTG9hZEFzc2VtYmx5TmFtZRJUeXBlTG9hZE1lc3NhZ2VBcmcSVHlwZUxvYWRSZXNvdXJjZUlEAQEDAwEBAQABAAEHAQEBAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAYCAAAAG1N5c3RlbS5EbGxOb3RGb3VuZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgoKAAAAAAQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uRGxsTm90Rm91bmRFeGNlcHRpb24QAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cxFUeXBlTG9hZENsYXNzTmFtZRRUeXBlTG9hZEFzc2VtYmx5TmFtZRJUeXBlTG9hZE1lc3NhZ2VBcmcSVHlwZUxvYWRSZXNvdXJjZUlEAQEDAwEBAQABAAEHAQEBAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAYCAAAAG1N5c3RlbS5EbGxOb3RGb3VuZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgoKAAAAAAQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var driveNotFoundException = new DriveNotFoundException("message", exception);
- yield return new object[] { PopulateException(driveNotFoundException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACBTeXN0ZW0uSU8uRHJpdmVOb3RGb3VuZEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACBTeXN0ZW0uSU8uRHJpdmVOb3RGb3VuZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAACBTeXN0ZW0uSU8uRHJpdmVOb3RGb3VuZEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACBTeXN0ZW0uSU8uRHJpdmVOb3RGb3VuZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL" } };
+ yield return new object[] { PopulateException(driveNotFoundException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACBTeXN0ZW0uSU8uRHJpdmVOb3RGb3VuZEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACBTeXN0ZW0uSU8uRHJpdmVOb3RGb3VuZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACBTeXN0ZW0uSU8uRHJpdmVOb3RGb3VuZEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACBTeXN0ZW0uSU8uRHJpdmVOb3RGb3VuZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netfx461) } };
var duplicateNameException = new DuplicateNameException("message", exception);
- yield return new object[] { PopulateException(duplicateNameException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0ZW0uRGF0YS5EdXBsaWNhdGVOYW1lRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACJTeXN0ZW0uRGF0YS5EdXBsaWNhdGVOYW1lRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0ZW0uRGF0YS5EdXBsaWNhdGVOYW1lRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACJTeXN0ZW0uRGF0YS5EdXBsaWNhdGVOYW1lRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=" } };
+ yield return new object[] { PopulateException(duplicateNameException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0ZW0uRGF0YS5EdXBsaWNhdGVOYW1lRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACJTeXN0ZW0uRGF0YS5EdXBsaWNhdGVOYW1lRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0ZW0uRGF0YS5EdXBsaWNhdGVOYW1lRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACJTeXN0ZW0uRGF0YS5EdXBsaWNhdGVOYW1lRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var duplicateWaitObjectException = new DuplicateWaitObjectException("message", exception);
- yield return new object[] { PopulateException(duplicateWaitObjectException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACNTeXN0ZW0uRHVwbGljYXRlV2FpdE9iamVjdEV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCVBhcmFtTmFtZQEBAwMBAQEAAQABBwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAI1N5c3RlbS5EdXBsaWNhdGVXYWl0T2JqZWN0RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAACNTeXN0ZW0uRHVwbGljYXRlV2FpdE9iamVjdEV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCVBhcmFtTmFtZQEBAwMBAQEAAQABBwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAI1N5c3RlbS5EdXBsaWNhdGVXYWl0T2JqZWN0RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL" } };
+ yield return new object[] { PopulateException(duplicateWaitObjectException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACNTeXN0ZW0uRHVwbGljYXRlV2FpdE9iamVjdEV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCVBhcmFtTmFtZQEBAwMBAQEAAQABBwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAI1N5c3RlbS5EdXBsaWNhdGVXYWl0T2JqZWN0RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACNTeXN0ZW0uRHVwbGljYXRlV2FpdE9iamVjdEV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCVBhcmFtTmFtZQEBAwMBAQEAAQABBwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAI1N5c3RlbS5EdXBsaWNhdGVXYWl0T2JqZWN0RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netfx461) } };
var duplicateWaitObjectException2 = new DuplicateWaitObjectException("paramName", "message");
- yield return new object[] { PopulateException(duplicateWaitObjectException2), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACNTeXN0ZW0uRHVwbGljYXRlV2FpdE9iamVjdEV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCVBhcmFtTmFtZQEBAwMBAQEAAQABBwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAI1N5c3RlbS5EdXBsaWNhdGVXYWl0T2JqZWN0RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYJAAAACXBhcmFtTmFtZQQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGCwAAAAZzZWNyZXQIAQEJDAAAAAEMAAAACgAAAAgIAQAAAAYNAAAAA29uZQoL", "AAEAAAD/////AQAAAAAAAAAEAQAAACNTeXN0ZW0uRHVwbGljYXRlV2FpdE9iamVjdEV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCVBhcmFtTmFtZQEBAwMBAQEAAQABBwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAI1N5c3RlbS5EdXBsaWNhdGVXYWl0T2JqZWN0RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYJAAAACXBhcmFtTmFtZQQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGCwAAAAZzZWNyZXQIAQEJDAAAAAEMAAAACgAAAAgIAQAAAAYNAAAAA29uZQoL" } };
+ yield return new object[] { PopulateException(duplicateWaitObjectException2), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACNTeXN0ZW0uRHVwbGljYXRlV2FpdE9iamVjdEV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCVBhcmFtTmFtZQEBAwMBAQEAAQABBwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAI1N5c3RlbS5EdXBsaWNhdGVXYWl0T2JqZWN0RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYJAAAACXBhcmFtTmFtZQQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGCwAAAAZzZWNyZXQIAQEJDAAAAAEMAAAACgAAAAgIAQAAAAYNAAAAA29uZQoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACNTeXN0ZW0uRHVwbGljYXRlV2FpdE9iamVjdEV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCVBhcmFtTmFtZQEBAwMBAQEAAQABBwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAI1N5c3RlbS5EdXBsaWNhdGVXYWl0T2JqZWN0RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYJAAAACXBhcmFtTmFtZQQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGCwAAAAZzZWNyZXQIAQEJDAAAAAEMAAAACgAAAAgIAQAAAAYNAAAAA29uZQoL", TargetFrameworkMoniker.netfx461) } };
//Exception elementNotAvailableException = (Exception)Type.GetType("Windows.UI.Xaml.Automation.ElementNotAvailableException", true)
// .GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(string), typeof(Exception) }, null)
// .Invoke(new object[] { "message", exception });
- //yield return new object[] { PopulateException(elementNotAvailableException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL", "AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL" } };
+ //yield return new object[] { PopulateException(elementNotAvailableException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL", SerializationFramework.NetcoreApp), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL", SerializationFramework.Netfx) } };
//var elementNotEnabledException = new ElementNotEnabledException("message", exception);
- //yield return new object[] { PopulateException(elementNotEnabledException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL", "AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL" } };
+ //yield return new object[] { PopulateException(elementNotEnabledException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL", SerializationFramework.NetcoreApp), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL", SerializationFramework.Netfx) } };
var encoderFallbackException = new EncoderFallbackException("message", exception);
- yield return new object[] { PopulateException(encoderFallbackException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACRTeXN0ZW0uVGV4dC5FbmNvZGVyRmFsbGJhY2tFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwlQYXJhbU5hbWUBAQMDAQEBAAEAAQcBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACRTeXN0ZW0uVGV4dC5FbmNvZGVyRmFsbGJhY2tFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAACRTeXN0ZW0uVGV4dC5FbmNvZGVyRmFsbGJhY2tFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwlQYXJhbU5hbWUBAQMDAQEBAAEAAQcBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACRTeXN0ZW0uVGV4dC5FbmNvZGVyRmFsbGJhY2tFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(encoderFallbackException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACRTeXN0ZW0uVGV4dC5FbmNvZGVyRmFsbGJhY2tFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwlQYXJhbU5hbWUBAQMDAQEBAAEAAQcBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACRTeXN0ZW0uVGV4dC5FbmNvZGVyRmFsbGJhY2tFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACRTeXN0ZW0uVGV4dC5FbmNvZGVyRmFsbGJhY2tFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwlQYXJhbU5hbWUBAQMDAQEBAAEAAQcBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACRTeXN0ZW0uVGV4dC5FbmNvZGVyRmFsbGJhY2tFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var endOfStreamException = new EndOfStreamException("message", exception);
- yield return new object[] { PopulateException(endOfStreamException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uSU8uRW5kT2ZTdHJlYW1FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLklPLkVuZE9mU3RyZWFtRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uSU8uRW5kT2ZTdHJlYW1FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLklPLkVuZE9mU3RyZWFtRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(endOfStreamException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uSU8uRW5kT2ZTdHJlYW1FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLklPLkVuZE9mU3RyZWFtRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uSU8uRW5kT2ZTdHJlYW1FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLklPLkVuZE9mU3RyZWFtRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var entryPointNotFoundException = new EntryPointNotFoundException("message", exception);
- yield return new object[] { PopulateException(entryPointNotFoundException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uRW50cnlQb2ludE5vdEZvdW5kRXhjZXB0aW9uEAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMRVHlwZUxvYWRDbGFzc05hbWUUVHlwZUxvYWRBc3NlbWJseU5hbWUSVHlwZUxvYWRNZXNzYWdlQXJnElR5cGVMb2FkUmVzb3VyY2VJRAEBAwMBAQEAAQABBwEBAQApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAggGAgAAACJTeXN0ZW0uRW50cnlQb2ludE5vdEZvdW5kRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoKCgoAAAAABAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uRW50cnlQb2ludE5vdEZvdW5kRXhjZXB0aW9uEAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMRVHlwZUxvYWRDbGFzc05hbWUUVHlwZUxvYWRBc3NlbWJseU5hbWUSVHlwZUxvYWRNZXNzYWdlQXJnElR5cGVMb2FkUmVzb3VyY2VJRAEBAwMBAQEAAQABBwEBAQApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAggGAgAAACJTeXN0ZW0uRW50cnlQb2ludE5vdEZvdW5kRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoKCgoAAAAABAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL" } };
+ yield return new object[] { PopulateException(entryPointNotFoundException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uRW50cnlQb2ludE5vdEZvdW5kRXhjZXB0aW9uEAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMRVHlwZUxvYWRDbGFzc05hbWUUVHlwZUxvYWRBc3NlbWJseU5hbWUSVHlwZUxvYWRNZXNzYWdlQXJnElR5cGVMb2FkUmVzb3VyY2VJRAEBAwMBAQEAAQABBwEBAQApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAggGAgAAACJTeXN0ZW0uRW50cnlQb2ludE5vdEZvdW5kRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoKCgoAAAAABAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uRW50cnlQb2ludE5vdEZvdW5kRXhjZXB0aW9uEAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMRVHlwZUxvYWRDbGFzc05hbWUUVHlwZUxvYWRBc3NlbWJseU5hbWUSVHlwZUxvYWRNZXNzYWdlQXJnElR5cGVMb2FkUmVzb3VyY2VJRAEBAwMBAQEAAQABBwEBAQApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAggGAgAAACJTeXN0ZW0uRW50cnlQb2ludE5vdEZvdW5kRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoKCgoAAAAABAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netfx461) } };
var evaluateException = new EvaluateException("message", exception);
- yield return new object[] { PopulateException(evaluateException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5FdmFsdWF0ZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAdU3lzdGVtLkRhdGEuRXZhbHVhdGVFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5FdmFsdWF0ZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAdU3lzdGVtLkRhdGEuRXZhbHVhdGVFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==" } };
+ yield return new object[] { PopulateException(evaluateException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5FdmFsdWF0ZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAdU3lzdGVtLkRhdGEuRXZhbHVhdGVFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5FdmFsdWF0ZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAdU3lzdGVtLkRhdGEuRXZhbHVhdGVFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var eventSourceException = new EventSourceException("message", exception);
- yield return new object[] { PopulateException(eventSourceException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAC9TeXN0ZW0uRGlhZ25vc3RpY3MuVHJhY2luZy5FdmVudFNvdXJjZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAAC9TeXN0ZW0uRGlhZ25vc3RpY3MuVHJhY2luZy5FdmVudFNvdXJjZUV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAAC9TeXN0ZW0uRGlhZ25vc3RpY3MuVHJhY2luZy5FdmVudFNvdXJjZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAAC9TeXN0ZW0uRGlhZ25vc3RpY3MuVHJhY2luZy5FdmVudFNvdXJjZUV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL" } };
+ yield return new object[] { PopulateException(eventSourceException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAC9TeXN0ZW0uRGlhZ25vc3RpY3MuVHJhY2luZy5FdmVudFNvdXJjZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAAC9TeXN0ZW0uRGlhZ25vc3RpY3MuVHJhY2luZy5FdmVudFNvdXJjZUV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAC9TeXN0ZW0uRGlhZ25vc3RpY3MuVHJhY2luZy5FdmVudFNvdXJjZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAAC9TeXN0ZW0uRGlhZ25vc3RpY3MuVHJhY2luZy5FdmVudFNvdXJjZUV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netfx461) } };
#pragma warning disable CS0618 // Type or member is obsolete
var executionEngineException = new ExecutionEngineException("message", exception);
#pragma warning restore CS0618 // Type or member is obsolete
- yield return new object[] { PopulateException(executionEngineException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uRXhlY3V0aW9uRW5naW5lRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAH1N5c3RlbS5FeGVjdXRpb25FbmdpbmVFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uRXhlY3V0aW9uRW5naW5lRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAH1N5c3RlbS5FeGVjdXRpb25FbmdpbmVFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(executionEngineException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uRXhlY3V0aW9uRW5naW5lRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAH1N5c3RlbS5FeGVjdXRpb25FbmdpbmVFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uRXhlY3V0aW9uRW5naW5lRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAH1N5c3RlbS5FeGVjdXRpb25FbmdpbmVFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var externalException = new ExternalException("message", exception);
- yield return new object[] { PopulateException(externalException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAADBTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuRXh0ZXJuYWxFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAwU3lzdGVtLlJ1bnRpbWUuSW50ZXJvcFNlcnZpY2VzLkV4dGVybmFsRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAADBTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuRXh0ZXJuYWxFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAwU3lzdGVtLlJ1bnRpbWUuSW50ZXJvcFNlcnZpY2VzLkV4dGVybmFsRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(externalException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADBTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuRXh0ZXJuYWxFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAwU3lzdGVtLlJ1bnRpbWUuSW50ZXJvcFNlcnZpY2VzLkV4dGVybmFsRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADBTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuRXh0ZXJuYWxFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAwU3lzdGVtLlJ1bnRpbWUuSW50ZXJvcFNlcnZpY2VzLkV4dGVybmFsRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var externalException2 = new ExternalException("message", 0);
- yield return new object[] { PopulateException(externalException2), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAADBTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuRXh0ZXJuYWxFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAwU3lzdGVtLlJ1bnRpbWUuSW50ZXJvcFNlcnZpY2VzLkV4dGVybmFsRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkJAAAAAgAAAAIAAAAECQAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGCgAAAAZzZWNyZXQIAQEJCwAAAAELAAAACQAAAAgIAQAAAAYMAAAAA29uZQoL", "AAEAAAD/////AQAAAAAAAAAEAQAAADBTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuRXh0ZXJuYWxFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAwU3lzdGVtLlJ1bnRpbWUuSW50ZXJvcFNlcnZpY2VzLkV4dGVybmFsRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkJAAAAAgAAAAIAAAAECQAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGCgAAAAZzZWNyZXQIAQEJCwAAAAELAAAACQAAAAgIAQAAAAYMAAAAA29uZQoL" } };
+ yield return new object[] { PopulateException(externalException2), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADBTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuRXh0ZXJuYWxFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAwU3lzdGVtLlJ1bnRpbWUuSW50ZXJvcFNlcnZpY2VzLkV4dGVybmFsRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkJAAAAAgAAAAIAAAAECQAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGCgAAAAZzZWNyZXQIAQEJCwAAAAELAAAACQAAAAgIAQAAAAYMAAAAA29uZQoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADBTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuRXh0ZXJuYWxFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAwU3lzdGVtLlJ1bnRpbWUuSW50ZXJvcFNlcnZpY2VzLkV4dGVybmFsRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkJAAAAAgAAAAIAAAAECQAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGCgAAAAZzZWNyZXQIAQEJCwAAAAELAAAACQAAAAgIAQAAAAYMAAAAA29uZQoL", TargetFrameworkMoniker.netfx461) } };
var fieldAccessException = new FieldAccessException("message", exception);
- yield return new object[] { PopulateException(fieldAccessException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uRmllbGRBY2Nlc3NFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAbU3lzdGVtLkZpZWxkQWNjZXNzRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uRmllbGRBY2Nlc3NFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAbU3lzdGVtLkZpZWxkQWNjZXNzRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(fieldAccessException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uRmllbGRBY2Nlc3NFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAbU3lzdGVtLkZpZWxkQWNjZXNzRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uRmllbGRBY2Nlc3NFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAbU3lzdGVtLkZpZWxkQWNjZXNzRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var fileFormatException = new FileFormatException("message", exception);
- yield return new object[] { PopulateException(fileFormatException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAB1TeXN0ZW0uSU8uRmlsZUZvcm1hdEV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCVNvdXJjZVVyaQEBAwMBAQEAAQABBwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAB1TeXN0ZW0uSU8uRmlsZUZvcm1hdEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAB1TeXN0ZW0uSU8uRmlsZUZvcm1hdEV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCVNvdXJjZVVyaQEBAwMBAQEAAQABBwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAB1TeXN0ZW0uSU8uRmlsZUZvcm1hdEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==" } };
+ yield return new object[] { PopulateException(fileFormatException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAB1TeXN0ZW0uSU8uRmlsZUZvcm1hdEV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCVNvdXJjZVVyaQEBAwMBAQEAAQABBwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAB1TeXN0ZW0uSU8uRmlsZUZvcm1hdEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAB1TeXN0ZW0uSU8uRmlsZUZvcm1hdEV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCVNvdXJjZVVyaQEBAwMBAQEAAQABBwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAB1TeXN0ZW0uSU8uRmlsZUZvcm1hdEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var fileFormatException2 = new FileFormatException(new Uri("http://microsoft.com"), "message", exception);
- yield return new object[] { PopulateException(fileFormatException2), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAB1TeXN0ZW0uSU8uRmlsZUZvcm1hdEV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCVNvdXJjZVVyaQEBAwMBAQEAAQABBwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAB1TeXN0ZW0uSU8uRmlsZUZvcm1hdEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgsAAAAVaHR0cDovL21pY3Jvc29mdC5jb20vBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQwAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBg0AAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ8AAAAJEAAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQMAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYVAAAABnNlY3JldAgBAQkWAAAAAQ8AAAAFAAAACRcAAAACAAAAAgAAAAEQAAAABgAAAAkNAAAABhkAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARYAAAAMAAAACAgBAAAABhoAAAADb25lCgEXAAAADAAAAAkVAAAACAEBCRwAAAABHAAAAAwAAAAICAEAAAAJGgAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAB1TeXN0ZW0uSU8uRmlsZUZvcm1hdEV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCVNvdXJjZVVyaQEBAwMBAQEAAQABBwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAB1TeXN0ZW0uSU8uRmlsZUZvcm1hdEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgsAAAAVaHR0cDovL21pY3Jvc29mdC5jb20vBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQwAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBg0AAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ8AAAAJEAAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQMAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYVAAAABnNlY3JldAgBAQkWAAAAAQ8AAAAFAAAACRcAAAACAAAAAgAAAAEQAAAABgAAAAkNAAAABhkAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARYAAAAMAAAACAgBAAAABhoAAAADb25lCgEXAAAADAAAAAkVAAAACAEBCRwAAAABHAAAAAwAAAAICAEAAAAJGgAAAAoL" } };
+ yield return new object[] { PopulateException(fileFormatException2), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAB1TeXN0ZW0uSU8uRmlsZUZvcm1hdEV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCVNvdXJjZVVyaQEBAwMBAQEAAQABBwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAB1TeXN0ZW0uSU8uRmlsZUZvcm1hdEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgsAAAAVaHR0cDovL21pY3Jvc29mdC5jb20vBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQwAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBg0AAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ8AAAAJEAAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQMAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYVAAAABnNlY3JldAgBAQkWAAAAAQ8AAAAFAAAACRcAAAACAAAAAgAAAAEQAAAABgAAAAkNAAAABhkAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARYAAAAMAAAACAgBAAAABhoAAAADb25lCgEXAAAADAAAAAkVAAAACAEBCRwAAAABHAAAAAwAAAAICAEAAAAJGgAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAB1TeXN0ZW0uSU8uRmlsZUZvcm1hdEV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCVNvdXJjZVVyaQEBAwMBAQEAAQABBwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAB1TeXN0ZW0uSU8uRmlsZUZvcm1hdEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgsAAAAVaHR0cDovL21pY3Jvc29mdC5jb20vBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQwAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBg0AAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ8AAAAJEAAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQMAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYVAAAABnNlY3JldAgBAQkWAAAAAQ8AAAAFAAAACRcAAAACAAAAAgAAAAEQAAAABgAAAAkNAAAABhkAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARYAAAAMAAAACAgBAAAABhoAAAADb25lCgEXAAAADAAAAAkVAAAACAEBCRwAAAABHAAAAAwAAAAICAEAAAAJGgAAAAoL", TargetFrameworkMoniker.netfx461) } };
var fileLoadException = new FileLoadException("message", "path.md", exception);
- yield return new object[] { PopulateException(fileLoadException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uSU8uRmlsZUxvYWRFeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cxFGaWxlTG9hZF9GaWxlTmFtZRJGaWxlTG9hZF9GdXNpb25Mb2cBAQMDAQEBAAEAAQcBASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAbU3lzdGVtLklPLkZpbGVMb2FkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoGCgAAAAdwYXRoLm1kCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkOAAAACQ8AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABAAAAAkWAAAAAgAAAAIAAAABDwAAAAUAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uSU8uRmlsZUxvYWRFeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cxFGaWxlTG9hZF9GaWxlTmFtZRJGaWxlTG9hZF9GdXNpb25Mb2cBAQMDAQEBAAEAAQcBASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAbU3lzdGVtLklPLkZpbGVMb2FkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoGCgAAAAdwYXRoLm1kCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkOAAAACQ8AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABAAAAAkWAAAAAgAAAAIAAAABDwAAAAUAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==" } };
+ yield return new object[] { PopulateException(fileLoadException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uSU8uRmlsZUxvYWRFeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cxFGaWxlTG9hZF9GaWxlTmFtZRJGaWxlTG9hZF9GdXNpb25Mb2cBAQMDAQEBAAEAAQcBASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAbU3lzdGVtLklPLkZpbGVMb2FkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoGCgAAAAdwYXRoLm1kCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkOAAAACQ8AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABAAAAAkWAAAAAgAAAAIAAAABDwAAAAUAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uSU8uRmlsZUxvYWRFeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cxFGaWxlTG9hZF9GaWxlTmFtZRJGaWxlTG9hZF9GdXNpb25Mb2cBAQMDAQEBAAEAAQcBASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAbU3lzdGVtLklPLkZpbGVMb2FkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoGCgAAAAdwYXRoLm1kCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkOAAAACQ8AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABAAAAAkWAAAAAgAAAAIAAAABDwAAAAUAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var fileNotFoundException = new FileNotFoundException("message", exception);
- yield return new object[] { PopulateException(fileNotFoundException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uSU8uRmlsZU5vdEZvdW5kRXhjZXB0aW9uDgAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMVRmlsZU5vdEZvdW5kX0ZpbGVOYW1lFkZpbGVOb3RGb3VuZF9GdXNpb25Mb2cBAQMDAQEBAAEAAQcBASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAfU3lzdGVtLklPLkZpbGVOb3RGb3VuZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uSU8uRmlsZU5vdEZvdW5kRXhjZXB0aW9uDgAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMVRmlsZU5vdEZvdW5kX0ZpbGVOYW1lFkZpbGVOb3RGb3VuZF9GdXNpb25Mb2cBAQMDAQEBAAEAAQcBASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAfU3lzdGVtLklPLkZpbGVOb3RGb3VuZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(fileNotFoundException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uSU8uRmlsZU5vdEZvdW5kRXhjZXB0aW9uDgAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMVRmlsZU5vdEZvdW5kX0ZpbGVOYW1lFkZpbGVOb3RGb3VuZF9GdXNpb25Mb2cBAQMDAQEBAAEAAQcBASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAfU3lzdGVtLklPLkZpbGVOb3RGb3VuZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uSU8uRmlsZU5vdEZvdW5kRXhjZXB0aW9uDgAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMVRmlsZU5vdEZvdW5kX0ZpbGVOYW1lFkZpbGVOb3RGb3VuZF9GdXNpb25Mb2cBAQMDAQEBAAEAAQcBASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAfU3lzdGVtLklPLkZpbGVOb3RGb3VuZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var formatException = new FormatException("message", exception);
- yield return new object[] { PopulateException(formatException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABZTeXN0ZW0uRm9ybWF0RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAFlN5c3RlbS5Gb3JtYXRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABZTeXN0ZW0uRm9ybWF0RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAFlN5c3RlbS5Gb3JtYXRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(formatException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABZTeXN0ZW0uRm9ybWF0RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAFlN5c3RlbS5Gb3JtYXRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABZTeXN0ZW0uRm9ybWF0RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAFlN5c3RlbS5Gb3JtYXRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var hostProtectionException = new HostProtectionException("message", exception);
- yield return new object[] { PopulateException(hostProtectionException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACdTeXN0ZW0uU2VjdXJpdHkuSG9zdFByb3RlY3Rpb25FeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cxJQcm90ZWN0ZWRSZXNvdXJjZXMRRGVtYW5kZWRSZXNvdXJjZXMBAQMDAQEBAAEAAQcDAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCMlN5c3RlbS5TZWN1cml0eS5QZXJtaXNzaW9ucy5Ib3N0UHJvdGVjdGlvblJlc291cmNlMlN5c3RlbS5TZWN1cml0eS5QZXJtaXNzaW9ucy5Ib3N0UHJvdGVjdGlvblJlc291cmNlBgIAAAAnU3lzdGVtLlNlY3VyaXR5Lkhvc3RQcm90ZWN0aW9uRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoE9v///zJTeXN0ZW0uU2VjdXJpdHkuUGVybWlzc2lvbnMuSG9zdFByb3RlY3Rpb25SZXNvdXJjZQEAAAAHdmFsdWVfXwAIAAAAAAH1////9v///wAAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJDAAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDQAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDwAAAAkQAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAwAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhUAAAAGc2VjcmV0CAEBCRYAAAABDwAAAAQAAAAJFwAAAAIAAAACAAAAARAAAAAFAAAACQ0AAAAGGQAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFgAAAAwAAAAICAEAAAAGGgAAAANvbmUKARcAAAAMAAAACRUAAAAIAQEJHAAAAAEcAAAADAAAAAgIAQAAAAkaAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAACdTeXN0ZW0uU2VjdXJpdHkuSG9zdFByb3RlY3Rpb25FeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cxJQcm90ZWN0ZWRSZXNvdXJjZXMRRGVtYW5kZWRSZXNvdXJjZXMBAQMDAQEBAAEAAQcDAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCMlN5c3RlbS5TZWN1cml0eS5QZXJtaXNzaW9ucy5Ib3N0UHJvdGVjdGlvblJlc291cmNlMlN5c3RlbS5TZWN1cml0eS5QZXJtaXNzaW9ucy5Ib3N0UHJvdGVjdGlvblJlc291cmNlBgIAAAAnU3lzdGVtLlNlY3VyaXR5Lkhvc3RQcm90ZWN0aW9uRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoE9v///zJTeXN0ZW0uU2VjdXJpdHkuUGVybWlzc2lvbnMuSG9zdFByb3RlY3Rpb25SZXNvdXJjZQEAAAAHdmFsdWVfXwAIAAAAAAH1////9v///wAAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJDAAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDQAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDwAAAAkQAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAwAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhUAAAAGc2VjcmV0CAEBCRYAAAABDwAAAAQAAAAJFwAAAAIAAAACAAAAARAAAAAFAAAACQ0AAAAGGQAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFgAAAAwAAAAICAEAAAAGGgAAAANvbmUKARcAAAAMAAAACRUAAAAIAQEJHAAAAAEcAAAADAAAAAgIAQAAAAkaAAAACgs=" } };
+ yield return new object[] { PopulateException(hostProtectionException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACdTeXN0ZW0uU2VjdXJpdHkuSG9zdFByb3RlY3Rpb25FeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cxJQcm90ZWN0ZWRSZXNvdXJjZXMRRGVtYW5kZWRSZXNvdXJjZXMBAQMDAQEBAAEAAQcDAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCMlN5c3RlbS5TZWN1cml0eS5QZXJtaXNzaW9ucy5Ib3N0UHJvdGVjdGlvblJlc291cmNlMlN5c3RlbS5TZWN1cml0eS5QZXJtaXNzaW9ucy5Ib3N0UHJvdGVjdGlvblJlc291cmNlBgIAAAAnU3lzdGVtLlNlY3VyaXR5Lkhvc3RQcm90ZWN0aW9uRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoE9v///zJTeXN0ZW0uU2VjdXJpdHkuUGVybWlzc2lvbnMuSG9zdFByb3RlY3Rpb25SZXNvdXJjZQEAAAAHdmFsdWVfXwAIAAAAAAH1////9v///wAAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJDAAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDQAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDwAAAAkQAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAwAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhUAAAAGc2VjcmV0CAEBCRYAAAABDwAAAAQAAAAJFwAAAAIAAAACAAAAARAAAAAFAAAACQ0AAAAGGQAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFgAAAAwAAAAICAEAAAAGGgAAAANvbmUKARcAAAAMAAAACRUAAAAIAQEJHAAAAAEcAAAADAAAAAgIAQAAAAkaAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACdTeXN0ZW0uU2VjdXJpdHkuSG9zdFByb3RlY3Rpb25FeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cxJQcm90ZWN0ZWRSZXNvdXJjZXMRRGVtYW5kZWRSZXNvdXJjZXMBAQMDAQEBAAEAAQcDAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCMlN5c3RlbS5TZWN1cml0eS5QZXJtaXNzaW9ucy5Ib3N0UHJvdGVjdGlvblJlc291cmNlMlN5c3RlbS5TZWN1cml0eS5QZXJtaXNzaW9ucy5Ib3N0UHJvdGVjdGlvblJlc291cmNlBgIAAAAnU3lzdGVtLlNlY3VyaXR5Lkhvc3RQcm90ZWN0aW9uRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoE9v///zJTeXN0ZW0uU2VjdXJpdHkuUGVybWlzc2lvbnMuSG9zdFByb3RlY3Rpb25SZXNvdXJjZQEAAAAHdmFsdWVfXwAIAAAAAAH1////9v///wAAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJDAAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDQAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDwAAAAkQAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAwAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhUAAAAGc2VjcmV0CAEBCRYAAAABDwAAAAQAAAAJFwAAAAIAAAACAAAAARAAAAAFAAAACQ0AAAAGGQAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFgAAAAwAAAAICAEAAAAGGgAAAANvbmUKARcAAAAMAAAACRUAAAAIAQEJHAAAAAEcAAAADAAAAAgIAQAAAAkaAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var hostProtectionException2 = new HostProtectionException("message", Security.Permissions.HostProtectionResource.All, Security.Permissions.HostProtectionResource.SharedState);
- yield return new object[] { PopulateException(hostProtectionException2, false), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACdTeXN0ZW0uU2VjdXJpdHkuSG9zdFByb3RlY3Rpb25FeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cxJQcm90ZWN0ZWRSZXNvdXJjZXMRRGVtYW5kZWRSZXNvdXJjZXMBAQMDAQEBAAEAAQcDAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCMlN5c3RlbS5TZWN1cml0eS5QZXJtaXNzaW9ucy5Ib3N0UHJvdGVjdGlvblJlc291cmNlMlN5c3RlbS5TZWN1cml0eS5QZXJtaXNzaW9ucy5Ib3N0UHJvdGVjdGlvblJlc291cmNlBgIAAAAnU3lzdGVtLlNlY3VyaXR5Lkhvc3RQcm90ZWN0aW9uRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAKQBYTgAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgT3////MlN5c3RlbS5TZWN1cml0eS5QZXJtaXNzaW9ucy5Ib3N0UHJvdGVjdGlvblJlc291cmNlAQAAAAd2YWx1ZV9fAAj/AQAAAfb////3////AgAAAAQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGDAAAAAZzZWNyZXQIAQEJDQAAAAENAAAACwAAAAgIAQAAAAYOAAAAA29uZQoL", "AAEAAAD/////AQAAAAAAAAAEAQAAACdTeXN0ZW0uU2VjdXJpdHkuSG9zdFByb3RlY3Rpb25FeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cxJQcm90ZWN0ZWRSZXNvdXJjZXMRRGVtYW5kZWRSZXNvdXJjZXMBAQMDAQEBAAEAAQcDAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCMlN5c3RlbS5TZWN1cml0eS5QZXJtaXNzaW9ucy5Ib3N0UHJvdGVjdGlvblJlc291cmNlMlN5c3RlbS5TZWN1cml0eS5QZXJtaXNzaW9ucy5Ib3N0UHJvdGVjdGlvblJlc291cmNlBgIAAAAnU3lzdGVtLlNlY3VyaXR5Lkhvc3RQcm90ZWN0aW9uRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAKQBYTgAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgT3////MlN5c3RlbS5TZWN1cml0eS5QZXJtaXNzaW9ucy5Ib3N0UHJvdGVjdGlvblJlc291cmNlAQAAAAd2YWx1ZV9fAAj/AQAAAfb////3////AgAAAAQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGDAAAAAZzZWNyZXQIAQEJDQAAAAENAAAACwAAAAgIAQAAAAYOAAAAA29uZQoL" } };
+ yield return new object[] { PopulateException(hostProtectionException2, false), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACdTeXN0ZW0uU2VjdXJpdHkuSG9zdFByb3RlY3Rpb25FeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cxJQcm90ZWN0ZWRSZXNvdXJjZXMRRGVtYW5kZWRSZXNvdXJjZXMBAQMDAQEBAAEAAQcDAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCMlN5c3RlbS5TZWN1cml0eS5QZXJtaXNzaW9ucy5Ib3N0UHJvdGVjdGlvblJlc291cmNlMlN5c3RlbS5TZWN1cml0eS5QZXJtaXNzaW9ucy5Ib3N0UHJvdGVjdGlvblJlc291cmNlBgIAAAAnU3lzdGVtLlNlY3VyaXR5Lkhvc3RQcm90ZWN0aW9uRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAKQBYTgAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgT3////MlN5c3RlbS5TZWN1cml0eS5QZXJtaXNzaW9ucy5Ib3N0UHJvdGVjdGlvblJlc291cmNlAQAAAAd2YWx1ZV9fAAj/AQAAAfb////3////AgAAAAQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGDAAAAAZzZWNyZXQIAQEJDQAAAAENAAAACwAAAAgIAQAAAAYOAAAAA29uZQoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACdTeXN0ZW0uU2VjdXJpdHkuSG9zdFByb3RlY3Rpb25FeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cxJQcm90ZWN0ZWRSZXNvdXJjZXMRRGVtYW5kZWRSZXNvdXJjZXMBAQMDAQEBAAEAAQcDAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCMlN5c3RlbS5TZWN1cml0eS5QZXJtaXNzaW9ucy5Ib3N0UHJvdGVjdGlvblJlc291cmNlMlN5c3RlbS5TZWN1cml0eS5QZXJtaXNzaW9ucy5Ib3N0UHJvdGVjdGlvblJlc291cmNlBgIAAAAnU3lzdGVtLlNlY3VyaXR5Lkhvc3RQcm90ZWN0aW9uRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAKQBYTgAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgT3////MlN5c3RlbS5TZWN1cml0eS5QZXJtaXNzaW9ucy5Ib3N0UHJvdGVjdGlvblJlc291cmNlAQAAAAd2YWx1ZV9fAAj/AQAAAfb////3////AgAAAAQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGDAAAAAZzZWNyZXQIAQEJDQAAAAENAAAACwAAAAgIAQAAAAYOAAAAA29uZQoL", TargetFrameworkMoniker.netfx461) } };
var httpListenerException = new HttpListenerException(404, "not found");
- yield return new object[] { PopulateException(httpListenerException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAgU3lzdGVtLk5ldC5IdHRwTGlzdGVuZXJFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cw9OYXRpdmVFcnJvckNvZGUBAQMDAQEBAAEAAQcAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIIAgAAAAYDAAAAIFN5c3RlbS5OZXQuSHR0cExpc3RlbmVyRXhjZXB0aW9uBgQAAAAJbm90IGZvdW5kCQUAAAAKBgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKlAEAAAQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGCwAAAAZzZWNyZXQIAQEJDAAAAAEMAAAACgAAAAgIAQAAAAYNAAAAA29uZQoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAgU3lzdGVtLk5ldC5IdHRwTGlzdGVuZXJFeGNlcHRpb24NAAAAD05hdGl2ZUVycm9yQ29kZQlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMAAQEDAwEBAQABAAEHCClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAJQBAAAGAwAAACBTeXN0ZW0uTmV0Lkh0dHBMaXN0ZW5lckV4Y2VwdGlvbgYEAAAACW5vdCBmb3VuZAkFAAAACgYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGCwAAAAZzZWNyZXQIAQEJDAAAAAEMAAAACgAAAAgIAQAAAAYNAAAAA29uZQoL" } };
+ yield return new object[] { PopulateException(httpListenerException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAgU3lzdGVtLk5ldC5IdHRwTGlzdGVuZXJFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cw9OYXRpdmVFcnJvckNvZGUBAQMDAQEBAAEAAQcAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIIAgAAAAYDAAAAIFN5c3RlbS5OZXQuSHR0cExpc3RlbmVyRXhjZXB0aW9uBgQAAAAJbm90IGZvdW5kCQUAAAAKBgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKlAEAAAQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGCwAAAAZzZWNyZXQIAQEJDAAAAAEMAAAACgAAAAgIAQAAAAYNAAAAA29uZQoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAgU3lzdGVtLk5ldC5IdHRwTGlzdGVuZXJFeGNlcHRpb24NAAAAD05hdGl2ZUVycm9yQ29kZQlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMAAQEDAwEBAQABAAEHCClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAJQBAAAGAwAAACBTeXN0ZW0uTmV0Lkh0dHBMaXN0ZW5lckV4Y2VwdGlvbgYEAAAACW5vdCBmb3VuZAkFAAAACgYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGCwAAAAZzZWNyZXQIAQEJDAAAAAEMAAAACgAAAAgIAQAAAAYNAAAAA29uZQoL", TargetFrameworkMoniker.netfx461) } };
var iOException = new IOException("message", exception);
- yield return new object[] { PopulateException(iOException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABVTeXN0ZW0uSU8uSU9FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAVU3lzdGVtLklPLklPRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAABVTeXN0ZW0uSU8uSU9FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAVU3lzdGVtLklPLklPRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(iOException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABVTeXN0ZW0uSU8uSU9FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAVU3lzdGVtLklPLklPRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABVTeXN0ZW0uSU8uSU9FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAVU3lzdGVtLklPLklPRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var iOException2 = new IOException("message", 1);
- yield return new object[] { PopulateException(iOException2), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABVTeXN0ZW0uSU8uSU9FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAVU3lzdGVtLklPLklPRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkJAAAAAgAAAAIAAAAECQAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGCgAAAAZzZWNyZXQIAQEJCwAAAAELAAAACQAAAAgIAQAAAAYMAAAAA29uZQoL", "AAEAAAD/////AQAAAAAAAAAEAQAAABVTeXN0ZW0uSU8uSU9FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAVU3lzdGVtLklPLklPRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkJAAAAAgAAAAIAAAAECQAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGCgAAAAZzZWNyZXQIAQEJCwAAAAELAAAACQAAAAgIAQAAAAYMAAAAA29uZQoL" } };
+ yield return new object[] { PopulateException(iOException2), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABVTeXN0ZW0uSU8uSU9FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAVU3lzdGVtLklPLklPRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkJAAAAAgAAAAIAAAAECQAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGCgAAAAZzZWNyZXQIAQEJCwAAAAELAAAACQAAAAgIAQAAAAYMAAAAA29uZQoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABVTeXN0ZW0uSU8uSU9FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAVU3lzdGVtLklPLklPRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkJAAAAAgAAAAIAAAAECQAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGCgAAAAZzZWNyZXQIAQEJCwAAAAELAAAACQAAAAgIAQAAAAYMAAAAA29uZQoL", TargetFrameworkMoniker.netfx461) } };
var inRowChangingEventException = new InRowChangingEventException("message", exception);
- yield return new object[] { PopulateException(inRowChangingEventException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACdTeXN0ZW0uRGF0YS5JblJvd0NoYW5naW5nRXZlbnRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAJ1N5c3RlbS5EYXRhLkluUm93Q2hhbmdpbmdFdmVudEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACdTeXN0ZW0uRGF0YS5JblJvd0NoYW5naW5nRXZlbnRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAJ1N5c3RlbS5EYXRhLkluUm93Q2hhbmdpbmdFdmVudEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL" } };
+ yield return new object[] { PopulateException(inRowChangingEventException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACdTeXN0ZW0uRGF0YS5JblJvd0NoYW5naW5nRXZlbnRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAJ1N5c3RlbS5EYXRhLkluUm93Q2hhbmdpbmdFdmVudEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACdTeXN0ZW0uRGF0YS5JblJvd0NoYW5naW5nRXZlbnRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAJ1N5c3RlbS5EYXRhLkluUm93Q2hhbmdpbmdFdmVudEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netfx461) } };
var indexOutOfRangeException = new IndexOutOfRangeException("message", exception);
- yield return new object[] { PopulateException(indexOutOfRangeException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uSW5kZXhPdXRPZlJhbmdlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAH1N5c3RlbS5JbmRleE91dE9mUmFuZ2VFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uSW5kZXhPdXRPZlJhbmdlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAH1N5c3RlbS5JbmRleE91dE9mUmFuZ2VFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(indexOutOfRangeException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uSW5kZXhPdXRPZlJhbmdlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAH1N5c3RlbS5JbmRleE91dE9mUmFuZ2VFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uSW5kZXhPdXRPZlJhbmdlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAH1N5c3RlbS5JbmRleE91dE9mUmFuZ2VFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var insufficientExecutionStackException = new InsufficientExecutionStackException("message", exception);
- yield return new object[] { PopulateException(insufficientExecutionStackException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACpTeXN0ZW0uSW5zdWZmaWNpZW50RXhlY3V0aW9uU3RhY2tFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAqU3lzdGVtLkluc3VmZmljaWVudEV4ZWN1dGlvblN0YWNrRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAACpTeXN0ZW0uSW5zdWZmaWNpZW50RXhlY3V0aW9uU3RhY2tFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAqU3lzdGVtLkluc3VmZmljaWVudEV4ZWN1dGlvblN0YWNrRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(insufficientExecutionStackException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACpTeXN0ZW0uSW5zdWZmaWNpZW50RXhlY3V0aW9uU3RhY2tFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAqU3lzdGVtLkluc3VmZmljaWVudEV4ZWN1dGlvblN0YWNrRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACpTeXN0ZW0uSW5zdWZmaWNpZW50RXhlY3V0aW9uU3RhY2tFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAqU3lzdGVtLkluc3VmZmljaWVudEV4ZWN1dGlvblN0YWNrRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var insufficientMemoryException = new InsufficientMemoryException("message", exception);
- yield return new object[] { PopulateException(insufficientMemoryException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uSW5zdWZmaWNpZW50TWVtb3J5RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAIlN5c3RlbS5JbnN1ZmZpY2llbnRNZW1vcnlFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uSW5zdWZmaWNpZW50TWVtb3J5RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAIlN5c3RlbS5JbnN1ZmZpY2llbnRNZW1vcnlFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(insufficientMemoryException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uSW5zdWZmaWNpZW50TWVtb3J5RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAIlN5c3RlbS5JbnN1ZmZpY2llbnRNZW1vcnlFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uSW5zdWZmaWNpZW50TWVtb3J5RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAIlN5c3RlbS5JbnN1ZmZpY2llbnRNZW1vcnlFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var internalBufferOverflowException = new InternalBufferOverflowException("message", exception);
- yield return new object[] { PopulateException(internalBufferOverflowException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAApU3lzdGVtLklPLkludGVybmFsQnVmZmVyT3ZlcmZsb3dFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAKVN5c3RlbS5JTy5JbnRlcm5hbEJ1ZmZlck92ZXJmbG93RXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAApU3lzdGVtLklPLkludGVybmFsQnVmZmVyT3ZlcmZsb3dFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAKVN5c3RlbS5JTy5JbnRlcm5hbEJ1ZmZlck92ZXJmbG93RXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=" } };
+ yield return new object[] { PopulateException(internalBufferOverflowException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAApU3lzdGVtLklPLkludGVybmFsQnVmZmVyT3ZlcmZsb3dFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAKVN5c3RlbS5JTy5JbnRlcm5hbEJ1ZmZlck92ZXJmbG93RXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAApU3lzdGVtLklPLkludGVybmFsQnVmZmVyT3ZlcmZsb3dFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAKVN5c3RlbS5JTy5JbnRlcm5hbEJ1ZmZlck92ZXJmbG93RXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var invalidAsynchronousStateException = new InvalidAsynchronousStateException("message", exception);
- yield return new object[] { PopulateException(invalidAsynchronousStateException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA3U3lzdGVtLkNvbXBvbmVudE1vZGVsLkludmFsaWRBc3luY2hyb25vdXNTdGF0ZUV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCVBhcmFtTmFtZQEBAwMBAQEAAQABBwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADdTeXN0ZW0uQ29tcG9uZW50TW9kZWwuSW52YWxpZEFzeW5jaHJvbm91c1N0YXRlRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA3U3lzdGVtLkNvbXBvbmVudE1vZGVsLkludmFsaWRBc3luY2hyb25vdXNTdGF0ZUV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCVBhcmFtTmFtZQEBAwMBAQEAAQABBwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADdTeXN0ZW0uQ29tcG9uZW50TW9kZWwuSW52YWxpZEFzeW5jaHJvbm91c1N0YXRlRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL" } };
+ yield return new object[] { PopulateException(invalidAsynchronousStateException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA3U3lzdGVtLkNvbXBvbmVudE1vZGVsLkludmFsaWRBc3luY2hyb25vdXNTdGF0ZUV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCVBhcmFtTmFtZQEBAwMBAQEAAQABBwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADdTeXN0ZW0uQ29tcG9uZW50TW9kZWwuSW52YWxpZEFzeW5jaHJvbm91c1N0YXRlRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA3U3lzdGVtLkNvbXBvbmVudE1vZGVsLkludmFsaWRBc3luY2hyb25vdXNTdGF0ZUV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCVBhcmFtTmFtZQEBAwMBAQEAAQABBwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADdTeXN0ZW0uQ29tcG9uZW50TW9kZWwuSW52YWxpZEFzeW5jaHJvbm91c1N0YXRlRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netfx461) } };
var invalidCastException = new InvalidCastException("message", exception);
- yield return new object[] { PopulateException(invalidCastException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uSW52YWxpZENhc3RFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAbU3lzdGVtLkludmFsaWRDYXN0RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uSW52YWxpZENhc3RFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAbU3lzdGVtLkludmFsaWRDYXN0RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(invalidCastException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uSW52YWxpZENhc3RFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAbU3lzdGVtLkludmFsaWRDYXN0RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uSW52YWxpZENhc3RFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAbU3lzdGVtLkludmFsaWRDYXN0RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var invalidComObjectException = new InvalidComObjectException("message", exception);
- yield return new object[] { PopulateException(invalidComObjectException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAADhTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuSW52YWxpZENvbU9iamVjdEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAADhTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuSW52YWxpZENvbU9iamVjdEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAADhTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuSW52YWxpZENvbU9iamVjdEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAADhTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuSW52YWxpZENvbU9iamVjdEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL" } };
+ yield return new object[] { PopulateException(invalidComObjectException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADhTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuSW52YWxpZENvbU9iamVjdEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAADhTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuSW52YWxpZENvbU9iamVjdEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADhTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuSW52YWxpZENvbU9iamVjdEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAADhTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuSW52YWxpZENvbU9iamVjdEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netfx461) } };
var invalidConstraintException = new InvalidConstraintException("message", exception);
- yield return new object[] { PopulateException(invalidConstraintException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0ZW0uRGF0YS5JbnZhbGlkQ29uc3RyYWludEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAmU3lzdGVtLkRhdGEuSW52YWxpZENvbnN0cmFpbnRFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0ZW0uRGF0YS5JbnZhbGlkQ29uc3RyYWludEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAmU3lzdGVtLkRhdGEuSW52YWxpZENvbnN0cmFpbnRFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==" } };
+ yield return new object[] { PopulateException(invalidConstraintException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0ZW0uRGF0YS5JbnZhbGlkQ29uc3RyYWludEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAmU3lzdGVtLkRhdGEuSW52YWxpZENvbnN0cmFpbnRFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0ZW0uRGF0YS5JbnZhbGlkQ29uc3RyYWludEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAmU3lzdGVtLkRhdGEuSW52YWxpZENvbnN0cmFpbnRFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var invalidCredentialException = new InvalidCredentialException("message", exception);
- yield return new object[] { PopulateException(invalidCredentialException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA5U3lzdGVtLlNlY3VyaXR5LkF1dGhlbnRpY2F0aW9uLkludmFsaWRDcmVkZW50aWFsRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADlTeXN0ZW0uU2VjdXJpdHkuQXV0aGVudGljYXRpb24uSW52YWxpZENyZWRlbnRpYWxFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA5U3lzdGVtLlNlY3VyaXR5LkF1dGhlbnRpY2F0aW9uLkludmFsaWRDcmVkZW50aWFsRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADlTeXN0ZW0uU2VjdXJpdHkuQXV0aGVudGljYXRpb24uSW52YWxpZENyZWRlbnRpYWxFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==" } };
+ yield return new object[] { PopulateException(invalidCredentialException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA5U3lzdGVtLlNlY3VyaXR5LkF1dGhlbnRpY2F0aW9uLkludmFsaWRDcmVkZW50aWFsRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADlTeXN0ZW0uU2VjdXJpdHkuQXV0aGVudGljYXRpb24uSW52YWxpZENyZWRlbnRpYWxFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA5U3lzdGVtLlNlY3VyaXR5LkF1dGhlbnRpY2F0aW9uLkludmFsaWRDcmVkZW50aWFsRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADlTeXN0ZW0uU2VjdXJpdHkuQXV0aGVudGljYXRpb24uSW52YWxpZENyZWRlbnRpYWxFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var invalidDataException = new InvalidDataException("message", exception);
- yield return new object[] { PopulateException(invalidDataException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAeU3lzdGVtLklPLkludmFsaWREYXRhRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAB5TeXN0ZW0uSU8uSW52YWxpZERhdGFFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAeU3lzdGVtLklPLkludmFsaWREYXRhRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAB5TeXN0ZW0uSU8uSW52YWxpZERhdGFFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==" } };
+ yield return new object[] { PopulateException(invalidDataException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAeU3lzdGVtLklPLkludmFsaWREYXRhRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAB5TeXN0ZW0uSU8uSW52YWxpZERhdGFFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAeU3lzdGVtLklPLkludmFsaWREYXRhRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAB5TeXN0ZW0uSU8uSW52YWxpZERhdGFFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var invalidEnumArgumentException = new InvalidEnumArgumentException("message", exception);
- yield return new object[] { PopulateException(invalidEnumArgumentException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAyU3lzdGVtLkNvbXBvbmVudE1vZGVsLkludmFsaWRFbnVtQXJndW1lbnRFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwlQYXJhbU5hbWUBAQMDAQEBAAEAAQcBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAyU3lzdGVtLkNvbXBvbmVudE1vZGVsLkludmFsaWRFbnVtQXJndW1lbnRFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAyU3lzdGVtLkNvbXBvbmVudE1vZGVsLkludmFsaWRFbnVtQXJndW1lbnRFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwlQYXJhbU5hbWUBAQMDAQEBAAEAAQcBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAyU3lzdGVtLkNvbXBvbmVudE1vZGVsLkludmFsaWRFbnVtQXJndW1lbnRFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=" } };
+ yield return new object[] { PopulateException(invalidEnumArgumentException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAyU3lzdGVtLkNvbXBvbmVudE1vZGVsLkludmFsaWRFbnVtQXJndW1lbnRFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwlQYXJhbU5hbWUBAQMDAQEBAAEAAQcBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAyU3lzdGVtLkNvbXBvbmVudE1vZGVsLkludmFsaWRFbnVtQXJndW1lbnRFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAyU3lzdGVtLkNvbXBvbmVudE1vZGVsLkludmFsaWRFbnVtQXJndW1lbnRFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwlQYXJhbU5hbWUBAQMDAQEBAAEAAQcBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAyU3lzdGVtLkNvbXBvbmVudE1vZGVsLkludmFsaWRFbnVtQXJndW1lbnRFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var invalidExpressionException = new InvalidExpressionException("message", exception);
- yield return new object[] { PopulateException(invalidExpressionException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0ZW0uRGF0YS5JbnZhbGlkRXhwcmVzc2lvbkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAmU3lzdGVtLkRhdGEuSW52YWxpZEV4cHJlc3Npb25FeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0ZW0uRGF0YS5JbnZhbGlkRXhwcmVzc2lvbkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAmU3lzdGVtLkRhdGEuSW52YWxpZEV4cHJlc3Npb25FeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==" } };
+ yield return new object[] { PopulateException(invalidExpressionException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0ZW0uRGF0YS5JbnZhbGlkRXhwcmVzc2lvbkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAmU3lzdGVtLkRhdGEuSW52YWxpZEV4cHJlc3Npb25FeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0ZW0uRGF0YS5JbnZhbGlkRXhwcmVzc2lvbkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAmU3lzdGVtLkRhdGEuSW52YWxpZEV4cHJlc3Npb25FeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var invalidFilterCriteriaException = new InvalidFilterCriteriaException("message", exception);
- yield return new object[] { PopulateException(invalidFilterCriteriaException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAADBTeXN0ZW0uUmVmbGVjdGlvbi5JbnZhbGlkRmlsdGVyQ3JpdGVyaWFFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAwU3lzdGVtLlJlZmxlY3Rpb24uSW52YWxpZEZpbHRlckNyaXRlcmlhRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAADBTeXN0ZW0uUmVmbGVjdGlvbi5JbnZhbGlkRmlsdGVyQ3JpdGVyaWFFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAwU3lzdGVtLlJlZmxlY3Rpb24uSW52YWxpZEZpbHRlckNyaXRlcmlhRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(invalidFilterCriteriaException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADBTeXN0ZW0uUmVmbGVjdGlvbi5JbnZhbGlkRmlsdGVyQ3JpdGVyaWFFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAwU3lzdGVtLlJlZmxlY3Rpb24uSW52YWxpZEZpbHRlckNyaXRlcmlhRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADBTeXN0ZW0uUmVmbGVjdGlvbi5JbnZhbGlkRmlsdGVyQ3JpdGVyaWFFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAwU3lzdGVtLlJlZmxlY3Rpb24uSW52YWxpZEZpbHRlckNyaXRlcmlhRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var invalidOleVariantTypeException = new InvalidOleVariantTypeException("message", exception);
- yield return new object[] { PopulateException(invalidOleVariantTypeException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAD1TeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuSW52YWxpZE9sZVZhcmlhbnRUeXBlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAPVN5c3RlbS5SdW50aW1lLkludGVyb3BTZXJ2aWNlcy5JbnZhbGlkT2xlVmFyaWFudFR5cGVFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAD1TeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuSW52YWxpZE9sZVZhcmlhbnRUeXBlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAPVN5c3RlbS5SdW50aW1lLkludGVyb3BTZXJ2aWNlcy5JbnZhbGlkT2xlVmFyaWFudFR5cGVFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(invalidOleVariantTypeException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAD1TeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuSW52YWxpZE9sZVZhcmlhbnRUeXBlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAPVN5c3RlbS5SdW50aW1lLkludGVyb3BTZXJ2aWNlcy5JbnZhbGlkT2xlVmFyaWFudFR5cGVFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAD1TeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuSW52YWxpZE9sZVZhcmlhbnRUeXBlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAPVN5c3RlbS5SdW50aW1lLkludGVyb3BTZXJ2aWNlcy5JbnZhbGlkT2xlVmFyaWFudFR5cGVFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var invalidOperationException = new InvalidOperationException("message", exception);
- yield return new object[] { PopulateException(invalidOperationException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACBTeXN0ZW0uSW52YWxpZE9wZXJhdGlvbkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACBTeXN0ZW0uSW52YWxpZE9wZXJhdGlvbkV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAACBTeXN0ZW0uSW52YWxpZE9wZXJhdGlvbkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACBTeXN0ZW0uSW52YWxpZE9wZXJhdGlvbkV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL" } };
+ yield return new object[] { PopulateException(invalidOperationException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACBTeXN0ZW0uSW52YWxpZE9wZXJhdGlvbkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACBTeXN0ZW0uSW52YWxpZE9wZXJhdGlvbkV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACBTeXN0ZW0uSW52YWxpZE9wZXJhdGlvbkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACBTeXN0ZW0uSW52YWxpZE9wZXJhdGlvbkV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netfx461) } };
//var invalidPrinterException = new InvalidPrinterException("message", exception);
- //yield return new object[] { PopulateException(invalidPrinterException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL", "AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL" } };
+ //yield return new object[] { PopulateException(invalidPrinterException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL", SerializationFramework.NetcoreApp), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL", SerializationFramework.Netfx) } };
var invalidProgramException = new InvalidProgramException("message", exception);
- yield return new object[] { PopulateException(invalidProgramException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uSW52YWxpZFByb2dyYW1FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLkludmFsaWRQcm9ncmFtRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uSW52YWxpZFByb2dyYW1FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLkludmFsaWRQcm9ncmFtRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(invalidProgramException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uSW52YWxpZFByb2dyYW1FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLkludmFsaWRQcm9ncmFtRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uSW52YWxpZFByb2dyYW1FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLkludmFsaWRQcm9ncmFtRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var invalidTimeZoneException = new InvalidTimeZoneException("message", exception);
- yield return new object[] { PopulateException(invalidTimeZoneException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj0zLjUuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB9TeXN0ZW0uSW52YWxpZFRpbWVab25lRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAB9TeXN0ZW0uSW52YWxpZFRpbWVab25lRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj0zLjUuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB9TeXN0ZW0uSW52YWxpZFRpbWVab25lRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAB9TeXN0ZW0uSW52YWxpZFRpbWVab25lRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=" } };
+ yield return new object[] { PopulateException(invalidTimeZoneException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj0zLjUuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB9TeXN0ZW0uSW52YWxpZFRpbWVab25lRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAB9TeXN0ZW0uSW52YWxpZFRpbWVab25lRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj0zLjUuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB9TeXN0ZW0uSW52YWxpZFRpbWVab25lRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAB9TeXN0ZW0uSW52YWxpZFRpbWVab25lRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var isolatedStorageException = new IsolatedStorageException("message", exception);
- yield return new object[] { PopulateException(isolatedStorageException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAADJTeXN0ZW0uSU8uSXNvbGF0ZWRTdG9yYWdlLklzb2xhdGVkU3RvcmFnZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAADJTeXN0ZW0uSU8uSXNvbGF0ZWRTdG9yYWdlLklzb2xhdGVkU3RvcmFnZUV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAADJTeXN0ZW0uSU8uSXNvbGF0ZWRTdG9yYWdlLklzb2xhdGVkU3RvcmFnZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAADJTeXN0ZW0uSU8uSXNvbGF0ZWRTdG9yYWdlLklzb2xhdGVkU3RvcmFnZUV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL" } };
+ yield return new object[] { PopulateException(isolatedStorageException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADJTeXN0ZW0uSU8uSXNvbGF0ZWRTdG9yYWdlLklzb2xhdGVkU3RvcmFnZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAADJTeXN0ZW0uSU8uSXNvbGF0ZWRTdG9yYWdlLklzb2xhdGVkU3RvcmFnZUV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADJTeXN0ZW0uSU8uSXNvbGF0ZWRTdG9yYWdlLklzb2xhdGVkU3RvcmFnZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAADJTeXN0ZW0uSU8uSXNvbGF0ZWRTdG9yYWdlLklzb2xhdGVkU3RvcmFnZUV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netfx461) } };
var keyNotFoundException = new KeyNotFoundException("message", exception);
- yield return new object[] { PopulateException(keyNotFoundException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAC9TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlOb3RGb3VuZEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAAC9TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlOb3RGb3VuZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAAC9TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlOb3RGb3VuZEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAAC9TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlOb3RGb3VuZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL" } };
+ yield return new object[] { PopulateException(keyNotFoundException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAC9TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlOb3RGb3VuZEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAAC9TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlOb3RGb3VuZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAC9TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlOb3RGb3VuZEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAAC9TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlOb3RGb3VuZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netfx461) } };
var licenseException = new LicenseException(typeof(string), aggregateException, "message", exception);
- yield return new object[] { PopulateException(licenseException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLkNvbXBvbmVudE1vZGVsLkxpY2Vuc2VFeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwR0eXBlCGluc3RhbmNlAQEDAwEBAQABAAEHAgMpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAhlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uAgAAAAYDAAAAJlN5c3RlbS5Db21wb25lbnRNb2RlbC5MaWNlbnNlRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoKCQsAAAAEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJDAAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDQAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDwAAAAkQAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAAZU3lzdGVtLkFnZ3JlZ2F0ZUV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzD0lubmVyRXhjZXB0aW9ucwEBAwMBAQEAAQABBwMpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAhJTeXN0ZW0uRXhjZXB0aW9uW10GFQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uCQQAAAAJFwAAAAkYAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKCR0AAAAEDAAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGHgAAAAZzZWNyZXQIAQEJHwAAAAEPAAAABQAAAAkgAAAAAgAAAAIAAAABEAAAAAYAAAAJDQAAAAYiAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEXAAAABQAAAAkjAAAAAgAAAAIAAAABGAAAAAYAAAAJDQAAAAYlAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkmAAAACgoKAAAAAAoAFROACgoHHQAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkYAAAAAR8AAAAMAAAACAgBAAAABigAAAADb25lCgEgAAAADAAAAAkeAAAACAEBCSoAAAABIwAAAAwAAAAJHgAAAAgBAQksAAAAASYAAAAGAAAACQ0AAAAJIgAAAAoKCgoKAAAAAAoAFROACgoBKgAAAAwAAAAICAEAAAAJKAAAAAoBLAAAAAwAAAAICAEAAAAJKAAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLkNvbXBvbmVudE1vZGVsLkxpY2Vuc2VFeGNlcHRpb24OAAAABHR5cGUIaW5zdGFuY2UJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAwMBAQMDAQEBAAEAAQcfU3lzdGVtLlVuaXR5U2VyaWFsaXphdGlvbkhvbGRlchlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAACQMAAAAJBAAAAAYFAAAAJlN5c3RlbS5Db21wb25lbnRNb2RlbC5MaWNlbnNlRXhjZXB0aW9uBgYAAAAHbWVzc2FnZQkHAAAACQgAAAAGCQAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgoAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCwAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGDAAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEAwAAAB9TeXN0ZW0uVW5pdHlTZXJpYWxpemF0aW9uSG9sZGVyAwAAAAREYXRhCVVuaXR5VHlwZQxBc3NlbWJseU5hbWUBAAEIBg0AAAANU3lzdGVtLlN0cmluZwQAAAAGDgAAAEttc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkEBAAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYPAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24JBgAAAAkRAAAACRIAAAAJCQAAAAkKAAAACQsAAAAAAAAACugDAAAJDAAAAAoJFwAAAAQHAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkYAAAAAgAAAAIAAAAECAAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYZAAAAEFN5c3RlbS5FeGNlcHRpb24JBgAAAAkbAAAACRwAAAAJCQAAAAkKAAAACQsAAAAAAAAACugDAAAJDAAAAAoBEQAAAAcAAAAJIQAAAAIAAAACAAAAARIAAAAIAAAACRkAAAAGIwAAABFFeGNlcHRpb24gbWVzc2FnZQoJJAAAAAoKCgAAAAAKABUTgAoKBxcAAAAAAQAAAAEAAAADEFN5c3RlbS5FeGNlcHRpb24JEgAAAAQYAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYmAAAABnNlY3JldAgBAQknAAAAARsAAAAHAAAACSgAAAACAAAAAgAAAAEcAAAACAAAAAkZAAAABioAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKASEAAAAYAAAACSYAAAAIAQEJLAAAAAEkAAAACAAAAAkZAAAACSoAAAAKCgoKCgAAAAAKABUTgAoKAScAAAAYAAAACAgBAAAABi8AAAADb25lCgEoAAAAGAAAAAkmAAAACAEBCTEAAAABLAAAABgAAAAICAEAAAAJLwAAAAoBMQAAABgAAAAICAEAAAAJLwAAAAoL" } };
+ yield return new object[] { PopulateException(licenseException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLkNvbXBvbmVudE1vZGVsLkxpY2Vuc2VFeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwR0eXBlCGluc3RhbmNlAQEDAwEBAQABAAEHAgMpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAhlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uAgAAAAYDAAAAJlN5c3RlbS5Db21wb25lbnRNb2RlbC5MaWNlbnNlRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoKCQsAAAAEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJDAAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDQAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDwAAAAkQAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAAZU3lzdGVtLkFnZ3JlZ2F0ZUV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzD0lubmVyRXhjZXB0aW9ucwEBAwMBAQEAAQABBwMpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAhJTeXN0ZW0uRXhjZXB0aW9uW10GFQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uCQQAAAAJFwAAAAkYAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKCR0AAAAEDAAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGHgAAAAZzZWNyZXQIAQEJHwAAAAEPAAAABQAAAAkgAAAAAgAAAAIAAAABEAAAAAYAAAAJDQAAAAYiAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEXAAAABQAAAAkjAAAAAgAAAAIAAAABGAAAAAYAAAAJDQAAAAYlAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkmAAAACgoKAAAAAAoAFROACgoHHQAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkYAAAAAR8AAAAMAAAACAgBAAAABigAAAADb25lCgEgAAAADAAAAAkeAAAACAEBCSoAAAABIwAAAAwAAAAJHgAAAAgBAQksAAAAASYAAAAGAAAACQ0AAAAJIgAAAAoKCgoKAAAAAAoAFROACgoBKgAAAAwAAAAICAEAAAAJKAAAAAoBLAAAAAwAAAAICAEAAAAJKAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLkNvbXBvbmVudE1vZGVsLkxpY2Vuc2VFeGNlcHRpb24OAAAABHR5cGUIaW5zdGFuY2UJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAwMBAQMDAQEBAAEAAQcfU3lzdGVtLlVuaXR5U2VyaWFsaXphdGlvbkhvbGRlchlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAACQMAAAAJBAAAAAYFAAAAJlN5c3RlbS5Db21wb25lbnRNb2RlbC5MaWNlbnNlRXhjZXB0aW9uBgYAAAAHbWVzc2FnZQkHAAAACQgAAAAGCQAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgoAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCwAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGDAAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEAwAAAB9TeXN0ZW0uVW5pdHlTZXJpYWxpemF0aW9uSG9sZGVyAwAAAAREYXRhCVVuaXR5VHlwZQxBc3NlbWJseU5hbWUBAAEIBg0AAAANU3lzdGVtLlN0cmluZwQAAAAGDgAAAEttc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkEBAAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYPAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24JBgAAAAkRAAAACRIAAAAJCQAAAAkKAAAACQsAAAAAAAAACugDAAAJDAAAAAoJFwAAAAQHAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkYAAAAAgAAAAIAAAAECAAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYZAAAAEFN5c3RlbS5FeGNlcHRpb24JBgAAAAkbAAAACRwAAAAJCQAAAAkKAAAACQsAAAAAAAAACugDAAAJDAAAAAoBEQAAAAcAAAAJIQAAAAIAAAACAAAAARIAAAAIAAAACRkAAAAGIwAAABFFeGNlcHRpb24gbWVzc2FnZQoJJAAAAAoKCgAAAAAKABUTgAoKBxcAAAAAAQAAAAEAAAADEFN5c3RlbS5FeGNlcHRpb24JEgAAAAQYAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYmAAAABnNlY3JldAgBAQknAAAAARsAAAAHAAAACSgAAAACAAAAAgAAAAEcAAAACAAAAAkZAAAABioAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKASEAAAAYAAAACSYAAAAIAQEJLAAAAAEkAAAACAAAAAkZAAAACSoAAAAKCgoKCgAAAAAKABUTgAoKAScAAAAYAAAACAgBAAAABi8AAAADb25lCgEoAAAAGAAAAAkmAAAACAEBCTEAAAABLAAAABgAAAAICAEAAAAJLwAAAAoBMQAAABgAAAAICAEAAAAJLwAAAAoL", TargetFrameworkMoniker.netfx461) } };
var lockRecursionException = new LockRecursionException("message", exception);
- yield return new object[] { PopulateException(lockRecursionException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj0zLjUuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACdTeXN0ZW0uVGhyZWFkaW5nLkxvY2tSZWN1cnNpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAJ1N5c3RlbS5UaHJlYWRpbmcuTG9ja1JlY3Vyc2lvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj0zLjUuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACdTeXN0ZW0uVGhyZWFkaW5nLkxvY2tSZWN1cnNpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAJ1N5c3RlbS5UaHJlYWRpbmcuTG9ja1JlY3Vyc2lvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL" } };
+ yield return new object[] { PopulateException(lockRecursionException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj0zLjUuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACdTeXN0ZW0uVGhyZWFkaW5nLkxvY2tSZWN1cnNpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAJ1N5c3RlbS5UaHJlYWRpbmcuTG9ja1JlY3Vyc2lvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj0zLjUuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACdTeXN0ZW0uVGhyZWFkaW5nLkxvY2tSZWN1cnNpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAJ1N5c3RlbS5UaHJlYWRpbmcuTG9ja1JlY3Vyc2lvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netfx461) } };
var marshalDirectiveException = new MarshalDirectiveException("message", exception);
- yield return new object[] { PopulateException(marshalDirectiveException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAADhTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuTWFyc2hhbERpcmVjdGl2ZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAADhTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuTWFyc2hhbERpcmVjdGl2ZUV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAADhTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuTWFyc2hhbERpcmVjdGl2ZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAADhTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuTWFyc2hhbERpcmVjdGl2ZUV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL" } };
+ yield return new object[] { PopulateException(marshalDirectiveException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADhTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuTWFyc2hhbERpcmVjdGl2ZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAADhTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuTWFyc2hhbERpcmVjdGl2ZUV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADhTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuTWFyc2hhbERpcmVjdGl2ZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAADhTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuTWFyc2hhbERpcmVjdGl2ZUV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netfx461) } };
var memberAccessException = new MemberAccessException("message", exception);
- yield return new object[] { PopulateException(memberAccessException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uTWVtYmVyQWNjZXNzRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAHFN5c3RlbS5NZW1iZXJBY2Nlc3NFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uTWVtYmVyQWNjZXNzRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAHFN5c3RlbS5NZW1iZXJBY2Nlc3NFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(memberAccessException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uTWVtYmVyQWNjZXNzRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAHFN5c3RlbS5NZW1iZXJBY2Nlc3NFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uTWVtYmVyQWNjZXNzRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAHFN5c3RlbS5NZW1iZXJBY2Nlc3NFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var methodAccessException = new MethodAccessException("message", exception);
- yield return new object[] { PopulateException(methodAccessException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uTWV0aG9kQWNjZXNzRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAHFN5c3RlbS5NZXRob2RBY2Nlc3NFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uTWV0aG9kQWNjZXNzRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAHFN5c3RlbS5NZXRob2RBY2Nlc3NFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(methodAccessException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uTWV0aG9kQWNjZXNzRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAHFN5c3RlbS5NZXRob2RBY2Nlc3NFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uTWV0aG9kQWNjZXNzRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAHFN5c3RlbS5NZXRob2RBY2Nlc3NFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var missingFieldException = new MissingFieldException("message", exception);
- yield return new object[] { PopulateException(missingFieldException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uTWlzc2luZ0ZpZWxkRXhjZXB0aW9uDwAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMLTU1DbGFzc05hbWUMTU1NZW1iZXJOYW1lC01NU2lnbmF0dXJlAQEDAwEBAQABAAEHAQEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICBgIAAAAcU3lzdGVtLk1pc3NpbmdGaWVsZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgoKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uTWlzc2luZ0ZpZWxkRXhjZXB0aW9uDwAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMLTU1DbGFzc05hbWUMTU1NZW1iZXJOYW1lC01NU2lnbmF0dXJlAQEDAwEBAQABAAEHAQEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICBgIAAAAcU3lzdGVtLk1pc3NpbmdGaWVsZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgoKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL" } };
+ yield return new object[] { PopulateException(missingFieldException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uTWlzc2luZ0ZpZWxkRXhjZXB0aW9uDwAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMLTU1DbGFzc05hbWUMTU1NZW1iZXJOYW1lC01NU2lnbmF0dXJlAQEDAwEBAQABAAEHAQEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICBgIAAAAcU3lzdGVtLk1pc3NpbmdGaWVsZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgoKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uTWlzc2luZ0ZpZWxkRXhjZXB0aW9uDwAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMLTU1DbGFzc05hbWUMTU1NZW1iZXJOYW1lC01NU2lnbmF0dXJlAQEDAwEBAQABAAEHAQEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICBgIAAAAcU3lzdGVtLk1pc3NpbmdGaWVsZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgoKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netfx461) } };
var missingManifestResourceException = new MissingManifestResourceException("message", exception);
- yield return new object[] { PopulateException(missingManifestResourceException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAADFTeXN0ZW0uUmVzb3VyY2VzLk1pc3NpbmdNYW5pZmVzdFJlc291cmNlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAMVN5c3RlbS5SZXNvdXJjZXMuTWlzc2luZ01hbmlmZXN0UmVzb3VyY2VFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAADFTeXN0ZW0uUmVzb3VyY2VzLk1pc3NpbmdNYW5pZmVzdFJlc291cmNlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAMVN5c3RlbS5SZXNvdXJjZXMuTWlzc2luZ01hbmlmZXN0UmVzb3VyY2VFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(missingManifestResourceException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADFTeXN0ZW0uUmVzb3VyY2VzLk1pc3NpbmdNYW5pZmVzdFJlc291cmNlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAMVN5c3RlbS5SZXNvdXJjZXMuTWlzc2luZ01hbmlmZXN0UmVzb3VyY2VFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADFTeXN0ZW0uUmVzb3VyY2VzLk1pc3NpbmdNYW5pZmVzdFJlc291cmNlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAMVN5c3RlbS5SZXNvdXJjZXMuTWlzc2luZ01hbmlmZXN0UmVzb3VyY2VFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var missingMemberException = new MissingMemberException("String", "Length");
- yield return new object[] { PopulateException(missingMemberException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uTWlzc2luZ01lbWJlckV4Y2VwdGlvbg8AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzC01NQ2xhc3NOYW1lDE1NTWVtYmVyTmFtZQtNTVNpZ25hdHVyZQEBAwMBAQEAAQABBwEBBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgYCAAAAHVN5c3RlbS5NaXNzaW5nTWVtYmVyRXhjZXB0aW9uBgMAAAAVQ2Fubm90IGFjY2VzcyBtZW1iZXIuCQQAAAAKBgUAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYGAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgcAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABggAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgkAAAAGU3RyaW5nBgoAAAAGTGVuZ3RoCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGDAAAAAZzZWNyZXQIAQEJDQAAAAENAAAACwAAAAgIAQAAAAYOAAAAA29uZQoL", "AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uTWlzc2luZ01lbWJlckV4Y2VwdGlvbg8AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzC01NQ2xhc3NOYW1lDE1NTWVtYmVyTmFtZQtNTVNpZ25hdHVyZQEBAwMBAQEAAQABBwEBBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgYCAAAAHVN5c3RlbS5NaXNzaW5nTWVtYmVyRXhjZXB0aW9uBgMAAAAVQ2Fubm90IGFjY2VzcyBtZW1iZXIuCQQAAAAKBgUAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYGAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgcAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABggAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgkAAAAGU3RyaW5nBgoAAAAGTGVuZ3RoCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGDAAAAAZzZWNyZXQIAQEJDQAAAAENAAAACwAAAAgIAQAAAAYOAAAAA29uZQoL" } };
+ yield return new object[] { PopulateException(missingMemberException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uTWlzc2luZ01lbWJlckV4Y2VwdGlvbg8AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzC01NQ2xhc3NOYW1lDE1NTWVtYmVyTmFtZQtNTVNpZ25hdHVyZQEBAwMBAQEAAQABBwEBBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgYCAAAAHVN5c3RlbS5NaXNzaW5nTWVtYmVyRXhjZXB0aW9uBgMAAAAVQ2Fubm90IGFjY2VzcyBtZW1iZXIuCQQAAAAKBgUAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYGAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgcAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABggAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgkAAAAGU3RyaW5nBgoAAAAGTGVuZ3RoCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGDAAAAAZzZWNyZXQIAQEJDQAAAAENAAAACwAAAAgIAQAAAAYOAAAAA29uZQoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uTWlzc2luZ01lbWJlckV4Y2VwdGlvbg8AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzC01NQ2xhc3NOYW1lDE1NTWVtYmVyTmFtZQtNTVNpZ25hdHVyZQEBAwMBAQEAAQABBwEBBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgYCAAAAHVN5c3RlbS5NaXNzaW5nTWVtYmVyRXhjZXB0aW9uBgMAAAAVQ2Fubm90IGFjY2VzcyBtZW1iZXIuCQQAAAAKBgUAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYGAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgcAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABggAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgkAAAAGU3RyaW5nBgoAAAAGTGVuZ3RoCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGDAAAAAZzZWNyZXQIAQEJDQAAAAENAAAACwAAAAgIAQAAAAYOAAAAA29uZQoL", TargetFrameworkMoniker.netfx461) } };
var missingMethodException = new MissingMethodException("String", "Length");
- yield return new object[] { PopulateException(missingMethodException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uTWlzc2luZ01ldGhvZEV4Y2VwdGlvbg8AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzC01NQ2xhc3NOYW1lDE1NTWVtYmVyTmFtZQtNTVNpZ25hdHVyZQEBAwMBAQEAAQABBwEBBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgYCAAAAHVN5c3RlbS5NaXNzaW5nTWV0aG9kRXhjZXB0aW9uBgMAAAAlQXR0ZW1wdGVkIHRvIGFjY2VzcyBhIG1pc3NpbmcgbWVtYmVyLgkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYJAAAABlN0cmluZwYKAAAABkxlbmd0aAoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgwAAAAGc2VjcmV0CAEBCQ0AAAABDQAAAAsAAAAICAEAAAAGDgAAAANvbmUKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uTWlzc2luZ01ldGhvZEV4Y2VwdGlvbg8AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzC01NQ2xhc3NOYW1lDE1NTWVtYmVyTmFtZQtNTVNpZ25hdHVyZQEBAwMBAQEAAQABBwEBBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgYCAAAAHVN5c3RlbS5NaXNzaW5nTWV0aG9kRXhjZXB0aW9uBgMAAAAlQXR0ZW1wdGVkIHRvIGFjY2VzcyBhIG1pc3NpbmcgbWVtYmVyLgkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYJAAAABlN0cmluZwYKAAAABkxlbmd0aAoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgwAAAAGc2VjcmV0CAEBCQ0AAAABDQAAAAsAAAAICAEAAAAGDgAAAANvbmUKCw==" } };
+ yield return new object[] { PopulateException(missingMethodException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uTWlzc2luZ01ldGhvZEV4Y2VwdGlvbg8AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzC01NQ2xhc3NOYW1lDE1NTWVtYmVyTmFtZQtNTVNpZ25hdHVyZQEBAwMBAQEAAQABBwEBBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgYCAAAAHVN5c3RlbS5NaXNzaW5nTWV0aG9kRXhjZXB0aW9uBgMAAAAlQXR0ZW1wdGVkIHRvIGFjY2VzcyBhIG1pc3NpbmcgbWVtYmVyLgkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYJAAAABlN0cmluZwYKAAAABkxlbmd0aAoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgwAAAAGc2VjcmV0CAEBCQ0AAAABDQAAAAsAAAAICAEAAAAGDgAAAANvbmUKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uTWlzc2luZ01ldGhvZEV4Y2VwdGlvbg8AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzC01NQ2xhc3NOYW1lDE1NTWVtYmVyTmFtZQtNTVNpZ25hdHVyZQEBAwMBAQEAAQABBwEBBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgYCAAAAHVN5c3RlbS5NaXNzaW5nTWV0aG9kRXhjZXB0aW9uBgMAAAAlQXR0ZW1wdGVkIHRvIGFjY2VzcyBhIG1pc3NpbmcgbWVtYmVyLgkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYJAAAABlN0cmluZwYKAAAABkxlbmd0aAoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgwAAAAGc2VjcmV0CAEBCQ0AAAABDQAAAAsAAAAICAEAAAAGDgAAAANvbmUKCw==", TargetFrameworkMoniker.netfx461) } };
var missingPrimaryKeyException = new MissingPrimaryKeyException("message", exception);
- yield return new object[] { PopulateException(missingPrimaryKeyException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0ZW0uRGF0YS5NaXNzaW5nUHJpbWFyeUtleUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAmU3lzdGVtLkRhdGEuTWlzc2luZ1ByaW1hcnlLZXlFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0ZW0uRGF0YS5NaXNzaW5nUHJpbWFyeUtleUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAmU3lzdGVtLkRhdGEuTWlzc2luZ1ByaW1hcnlLZXlFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==" } };
+ yield return new object[] { PopulateException(missingPrimaryKeyException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0ZW0uRGF0YS5NaXNzaW5nUHJpbWFyeUtleUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAmU3lzdGVtLkRhdGEuTWlzc2luZ1ByaW1hcnlLZXlFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0ZW0uRGF0YS5NaXNzaW5nUHJpbWFyeUtleUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAmU3lzdGVtLkRhdGEuTWlzc2luZ1ByaW1hcnlLZXlFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var missingSatelliteAssemblyException = new MissingSatelliteAssemblyException("message", "en-US");
- yield return new object[] { PopulateException(missingSatelliteAssemblyException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAADJTeXN0ZW0uUmVzb3VyY2VzLk1pc3NpbmdTYXRlbGxpdGVBc3NlbWJseUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAADJTeXN0ZW0uUmVzb3VyY2VzLk1pc3NpbmdTYXRlbGxpdGVBc3NlbWJseUV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAoGBQAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgYAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GBwAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCAAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCQAAAAIAAAACAAAABAkAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgoAAAAGc2VjcmV0CAEBCQsAAAABCwAAAAkAAAAICAEAAAAGDAAAAANvbmUKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAADJTeXN0ZW0uUmVzb3VyY2VzLk1pc3NpbmdTYXRlbGxpdGVBc3NlbWJseUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAADJTeXN0ZW0uUmVzb3VyY2VzLk1pc3NpbmdTYXRlbGxpdGVBc3NlbWJseUV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAoGBQAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgYAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GBwAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCAAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCQAAAAIAAAACAAAABAkAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgoAAAAGc2VjcmV0CAEBCQsAAAABCwAAAAkAAAAICAEAAAAGDAAAAANvbmUKCw==" } };
+ yield return new object[] { PopulateException(missingSatelliteAssemblyException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADJTeXN0ZW0uUmVzb3VyY2VzLk1pc3NpbmdTYXRlbGxpdGVBc3NlbWJseUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAADJTeXN0ZW0uUmVzb3VyY2VzLk1pc3NpbmdTYXRlbGxpdGVBc3NlbWJseUV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAoGBQAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgYAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GBwAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCAAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCQAAAAIAAAACAAAABAkAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgoAAAAGc2VjcmV0CAEBCQsAAAABCwAAAAkAAAAICAEAAAAGDAAAAANvbmUKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADJTeXN0ZW0uUmVzb3VyY2VzLk1pc3NpbmdTYXRlbGxpdGVBc3NlbWJseUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAADJTeXN0ZW0uUmVzb3VyY2VzLk1pc3NpbmdTYXRlbGxpdGVBc3NlbWJseUV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAoGBQAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgYAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GBwAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCAAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCQAAAAIAAAACAAAABAkAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgoAAAAGc2VjcmV0CAEBCQsAAAABCwAAAAkAAAAICAEAAAAGDAAAAANvbmUKCw==", TargetFrameworkMoniker.netfx461) } };
var multicastNotSupportedException = new MulticastNotSupportedException("message", exception);
- yield return new object[] { PopulateException(multicastNotSupportedException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACVTeXN0ZW0uTXVsdGljYXN0Tm90U3VwcG9ydGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAJVN5c3RlbS5NdWx0aWNhc3ROb3RTdXBwb3J0ZWRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAACVTeXN0ZW0uTXVsdGljYXN0Tm90U3VwcG9ydGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAJVN5c3RlbS5NdWx0aWNhc3ROb3RTdXBwb3J0ZWRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(multicastNotSupportedException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACVTeXN0ZW0uTXVsdGljYXN0Tm90U3VwcG9ydGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAJVN5c3RlbS5NdWx0aWNhc3ROb3RTdXBwb3J0ZWRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACVTeXN0ZW0uTXVsdGljYXN0Tm90U3VwcG9ydGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAJVN5c3RlbS5NdWx0aWNhc3ROb3RTdXBwb3J0ZWRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var networkInformationException = new NetworkInformationException();
- yield return new object[] { PopulateException(networkInformationException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA5U3lzdGVtLk5ldC5OZXR3b3JrSW5mb3JtYXRpb24uTmV0d29ya0luZm9ybWF0aW9uRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPTmF0aXZlRXJyb3JDb2RlAQEDAwEBAQABAAEHAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAIAAAAGAwAAADlTeXN0ZW0uTmV0Lk5ldHdvcmtJbmZvcm1hdGlvbi5OZXR3b3JrSW5mb3JtYXRpb25FeGNlcHRpb24GBAAAACRUaGUgb3BlcmF0aW9uIGNvbXBsZXRlZCBzdWNjZXNzZnVsbHkJBQAAAAoGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoAAAAABAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYLAAAABnNlY3JldAgBAQkMAAAAAQwAAAAKAAAACAgBAAAABg0AAAADb25lCgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA5U3lzdGVtLk5ldC5OZXR3b3JrSW5mb3JtYXRpb24uTmV0d29ya0luZm9ybWF0aW9uRXhjZXB0aW9uDQAAAA9OYXRpdmVFcnJvckNvZGUJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAAEBAwMBAQEAAQABBwgpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAACAAAABgMAAAA5U3lzdGVtLk5ldC5OZXR3b3JrSW5mb3JtYXRpb24uTmV0d29ya0luZm9ybWF0aW9uRXhjZXB0aW9uBgQAAAApVGhlIHN5c3RlbSBjYW5ub3QgZmluZCB0aGUgZmlsZSBzcGVjaWZpZWQJBQAAAAoGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==" } };
+ yield return new object[] { PopulateException(networkInformationException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA5U3lzdGVtLk5ldC5OZXR3b3JrSW5mb3JtYXRpb24uTmV0d29ya0luZm9ybWF0aW9uRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPTmF0aXZlRXJyb3JDb2RlAQEDAwEBAQABAAEHAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAIAAAAGAwAAADlTeXN0ZW0uTmV0Lk5ldHdvcmtJbmZvcm1hdGlvbi5OZXR3b3JrSW5mb3JtYXRpb25FeGNlcHRpb24GBAAAACRUaGUgb3BlcmF0aW9uIGNvbXBsZXRlZCBzdWNjZXNzZnVsbHkJBQAAAAoGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoAAAAABAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYLAAAABnNlY3JldAgBAQkMAAAAAQwAAAAKAAAACAgBAAAABg0AAAADb25lCgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA5U3lzdGVtLk5ldC5OZXR3b3JrSW5mb3JtYXRpb24uTmV0d29ya0luZm9ybWF0aW9uRXhjZXB0aW9uDQAAAA9OYXRpdmVFcnJvckNvZGUJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAAEBAwMBAQEAAQABBwgpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAACAAAABgMAAAA5U3lzdGVtLk5ldC5OZXR3b3JrSW5mb3JtYXRpb24uTmV0d29ya0luZm9ybWF0aW9uRXhjZXB0aW9uBgQAAAApVGhlIHN5c3RlbSBjYW5ub3QgZmluZCB0aGUgZmlsZSBzcGVjaWZpZWQJBQAAAAoGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==", TargetFrameworkMoniker.netfx461) } };
var noNullAllowedException = new NoNullAllowedException("message", exception);
- yield return new object[] { PopulateException(noNullAllowedException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0ZW0uRGF0YS5Ob051bGxBbGxvd2VkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACJTeXN0ZW0uRGF0YS5Ob051bGxBbGxvd2VkRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0ZW0uRGF0YS5Ob051bGxBbGxvd2VkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACJTeXN0ZW0uRGF0YS5Ob051bGxBbGxvd2VkRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=" } };
+ yield return new object[] { PopulateException(noNullAllowedException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0ZW0uRGF0YS5Ob051bGxBbGxvd2VkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACJTeXN0ZW0uRGF0YS5Ob051bGxBbGxvd2VkRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0ZW0uRGF0YS5Ob051bGxBbGxvd2VkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACJTeXN0ZW0uRGF0YS5Ob051bGxBbGxvd2VkRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var notFiniteNumberException = new NotFiniteNumberException("message", 32.485, exception);
- yield return new object[] { PopulateException(notFiniteNumberException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uTm90RmluaXRlTnVtYmVyRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPT2ZmZW5kaW5nTnVtYmVyAQEDAwEBAQABAAEHAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAYCAAAAH1N5c3RlbS5Ob3RGaW5pdGVOdW1iZXJFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCiAAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uTm90RmluaXRlTnVtYmVyRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPT2ZmZW5kaW5nTnVtYmVyAQEDAwEBAQABAAEHAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAYCAAAAH1N5c3RlbS5Ob3RGaW5pdGVOdW1iZXJFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCiAAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(notFiniteNumberException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uTm90RmluaXRlTnVtYmVyRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPT2ZmZW5kaW5nTnVtYmVyAQEDAwEBAQABAAEHAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAYCAAAAH1N5c3RlbS5Ob3RGaW5pdGVOdW1iZXJFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCiAAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uTm90RmluaXRlTnVtYmVyRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPT2ZmZW5kaW5nTnVtYmVyAQEDAwEBAQABAAEHAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAYCAAAAH1N5c3RlbS5Ob3RGaW5pdGVOdW1iZXJFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCiAAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var notImplementedException = new NotImplementedException("message", exception);
- yield return new object[] { PopulateException(notImplementedException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uTm90SW1wbGVtZW50ZWRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLk5vdEltcGxlbWVudGVkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uTm90SW1wbGVtZW50ZWRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLk5vdEltcGxlbWVudGVkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(notImplementedException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uTm90SW1wbGVtZW50ZWRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLk5vdEltcGxlbWVudGVkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uTm90SW1wbGVtZW50ZWRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLk5vdEltcGxlbWVudGVkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var notSupportedException = new NotSupportedException("message", exception);
- yield return new object[] { PopulateException(notSupportedException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uTm90U3VwcG9ydGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAHFN5c3RlbS5Ob3RTdXBwb3J0ZWRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uTm90U3VwcG9ydGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAHFN5c3RlbS5Ob3RTdXBwb3J0ZWRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(notSupportedException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uTm90U3VwcG9ydGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAHFN5c3RlbS5Ob3RTdXBwb3J0ZWRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uTm90U3VwcG9ydGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAHFN5c3RlbS5Ob3RTdXBwb3J0ZWRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var nullReferenceException = new NullReferenceException("message", exception);
- yield return new object[] { PopulateException(nullReferenceException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uTnVsbFJlZmVyZW5jZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAAB1TeXN0ZW0uTnVsbFJlZmVyZW5jZUV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uTnVsbFJlZmVyZW5jZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAAB1TeXN0ZW0uTnVsbFJlZmVyZW5jZUV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL" } };
+ yield return new object[] { PopulateException(nullReferenceException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uTnVsbFJlZmVyZW5jZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAAB1TeXN0ZW0uTnVsbFJlZmVyZW5jZUV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uTnVsbFJlZmVyZW5jZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAAB1TeXN0ZW0uTnVsbFJlZmVyZW5jZUV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netfx461) } };
var objectDisposedException = new ObjectDisposedException("objectname", "message");
- yield return new object[] { PopulateException(objectDisposedException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uT2JqZWN0RGlzcG9zZWRFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwpPYmplY3ROYW1lAQEDAwEBAQABAAEHASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLk9iamVjdERpc3Bvc2VkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYJAAAACm9iamVjdG5hbWUEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uT2JqZWN0RGlzcG9zZWRFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwpPYmplY3ROYW1lAQEDAwEBAQABAAEHASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLk9iamVjdERpc3Bvc2VkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYJAAAACm9iamVjdG5hbWUEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==" } };
+ yield return new object[] { PopulateException(objectDisposedException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uT2JqZWN0RGlzcG9zZWRFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwpPYmplY3ROYW1lAQEDAwEBAQABAAEHASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLk9iamVjdERpc3Bvc2VkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYJAAAACm9iamVjdG5hbWUEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uT2JqZWN0RGlzcG9zZWRFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwpPYmplY3ROYW1lAQEDAwEBAQABAAEHASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLk9iamVjdERpc3Bvc2VkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYJAAAACm9iamVjdG5hbWUEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==", TargetFrameworkMoniker.netfx461) } };
if (!PlatformDetection.IsUap)
{
@@ -545,7 +537,7 @@ namespace System.Runtime.Serialization.Formatters.Tests
.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(string), typeof(OdbcErrorCollection) }, null)
.Invoke(new object[] { "message", odbcErrorCollection });
// OdbcException sets its HResult itself therefore we pass setHResult as false.
- yield return new object[] { PopulateException(odbcException, setHResult: false), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5PZGJjLk9kYmNFeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwtvZGJjUmV0Y29kZQpvZGJjRXJyb3JzAQEDAwEBAQABAAEHBAQpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAh9TeXN0ZW0uRGF0YS5PZGJjLk9EQkMzMitSRVRDT0RFAgAAACRTeXN0ZW0uRGF0YS5PZGJjLk9kYmNFcnJvckNvbGxlY3Rpb24CAAAAAgAAAAYDAAAAHlN5c3RlbS5EYXRhLk9kYmMuT2RiY0V4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAoGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACjcZE4AGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoF9v///x9TeXN0ZW0uRGF0YS5PZGJjLk9EQkMzMitSRVRDT0RFAQAAAAd2YWx1ZV9fAAgCAAAAAAAAAAkLAAAABAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQwAAAACAAAAAgAAAAULAAAAJFN5c3RlbS5EYXRhLk9kYmMuT2RiY0Vycm9yQ29sbGVjdGlvbgEAAAAGX2l0ZW1zAxxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AgAAAAkNAAAABAwAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBg4AAAAGc2VjcmV0CAEBCQ8AAAAEDQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkQAAAAAQAAAAEAAAABDwAAAAwAAAAICAEAAAAGEQAAAANvbmUKEBAAAAAEAAAACRIAAAANAwUSAAAAGlN5c3RlbS5EYXRhLk9kYmMuT2RiY0Vycm9yBAAAAAhfbWVzc2FnZQZfc3RhdGUMX25hdGl2ZWVycm9yB19zb3VyY2UBAQABCAIAAAAJBAAAAAYUAAAABXN0YXRlAAAAAAYVAAAABnNvdXJjZQs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5PZGJjLk9kYmNFeGNlcHRpb24OAAAAC29kYmNSZXRjb2RlCm9kYmNFcnJvcnMJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzBAQBAQMDAQEBAAEAAQcfU3lzdGVtLkRhdGEuT2RiYy5PREJDMzIrUkVUQ09ERQIAAAAkU3lzdGVtLkRhdGEuT2RiYy5PZGJjRXJyb3JDb2xsZWN0aW9uAgAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAX9////H1N5c3RlbS5EYXRhLk9kYmMuT0RCQzMyK1JFVENPREUBAAAAB3ZhbHVlX18ACAIAAAAAAAAACQQAAAAGBQAAAB5TeXN0ZW0uRGF0YS5PZGJjLk9kYmNFeGNlcHRpb24GBgAAAAdtZXNzYWdlCQcAAAAKBggAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYJAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgoAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAo3GROABgsAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBQQAAAAkU3lzdGVtLkRhdGEuT2RiYy5PZGJjRXJyb3JDb2xsZWN0aW9uAQAAAAZfaXRlbXMDHFN5c3RlbS5Db2xsZWN0aW9ucy5BcnJheUxpc3QCAAAACQwAAAAEBwAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJDQAAAAIAAAACAAAABAwAAAAcU3lzdGVtLkNvbGxlY3Rpb25zLkFycmF5TGlzdAMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBQAACAgJDgAAAAEAAAABAAAABA0AAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBg8AAAAGc2VjcmV0CAEBCRAAAAAQDgAAAAQAAAAJEQAAAA0DARAAAAANAAAACAgBAAAABhIAAAADb25lCgURAAAAGlN5c3RlbS5EYXRhLk9kYmMuT2RiY0Vycm9yBAAAAAhfbWVzc2FnZQZfc3RhdGUMX25hdGl2ZWVycm9yB19zb3VyY2UBAQABCAIAAAAJBgAAAAYUAAAABXN0YXRlAAAAAAYVAAAABnNvdXJjZQs=" } };
+ yield return new object[] { PopulateException(odbcException, setHResult: false), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5PZGJjLk9kYmNFeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwtvZGJjUmV0Y29kZQpvZGJjRXJyb3JzAQEDAwEBAQABAAEHBAQpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAh9TeXN0ZW0uRGF0YS5PZGJjLk9EQkMzMitSRVRDT0RFAgAAACRTeXN0ZW0uRGF0YS5PZGJjLk9kYmNFcnJvckNvbGxlY3Rpb24CAAAAAgAAAAYDAAAAHlN5c3RlbS5EYXRhLk9kYmMuT2RiY0V4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAoGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACjcZE4AGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoF9v///x9TeXN0ZW0uRGF0YS5PZGJjLk9EQkMzMitSRVRDT0RFAQAAAAd2YWx1ZV9fAAgCAAAAAAAAAAkLAAAABAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQwAAAACAAAAAgAAAAULAAAAJFN5c3RlbS5EYXRhLk9kYmMuT2RiY0Vycm9yQ29sbGVjdGlvbgEAAAAGX2l0ZW1zAxxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AgAAAAkNAAAABAwAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBg4AAAAGc2VjcmV0CAEBCQ8AAAAEDQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkQAAAAAQAAAAEAAAABDwAAAAwAAAAICAEAAAAGEQAAAANvbmUKEBAAAAAEAAAACRIAAAANAwUSAAAAGlN5c3RlbS5EYXRhLk9kYmMuT2RiY0Vycm9yBAAAAAhfbWVzc2FnZQZfc3RhdGUMX25hdGl2ZWVycm9yB19zb3VyY2UBAQABCAIAAAAJBAAAAAYUAAAABXN0YXRlAAAAAAYVAAAABnNvdXJjZQs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5PZGJjLk9kYmNFeGNlcHRpb24OAAAAC29kYmNSZXRjb2RlCm9kYmNFcnJvcnMJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzBAQBAQMDAQEBAAEAAQcfU3lzdGVtLkRhdGEuT2RiYy5PREJDMzIrUkVUQ09ERQIAAAAkU3lzdGVtLkRhdGEuT2RiYy5PZGJjRXJyb3JDb2xsZWN0aW9uAgAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAX9////H1N5c3RlbS5EYXRhLk9kYmMuT0RCQzMyK1JFVENPREUBAAAAB3ZhbHVlX18ACAIAAAAAAAAACQQAAAAGBQAAAB5TeXN0ZW0uRGF0YS5PZGJjLk9kYmNFeGNlcHRpb24GBgAAAAdtZXNzYWdlCQcAAAAKBggAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYJAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgoAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAo3GROABgsAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBQQAAAAkU3lzdGVtLkRhdGEuT2RiYy5PZGJjRXJyb3JDb2xsZWN0aW9uAQAAAAZfaXRlbXMDHFN5c3RlbS5Db2xsZWN0aW9ucy5BcnJheUxpc3QCAAAACQwAAAAEBwAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJDQAAAAIAAAACAAAABAwAAAAcU3lzdGVtLkNvbGxlY3Rpb25zLkFycmF5TGlzdAMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBQAACAgJDgAAAAEAAAABAAAABA0AAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBg8AAAAGc2VjcmV0CAEBCRAAAAAQDgAAAAQAAAAJEQAAAA0DARAAAAANAAAACAgBAAAABhIAAAADb25lCgURAAAAGlN5c3RlbS5EYXRhLk9kYmMuT2RiY0Vycm9yBAAAAAhfbWVzc2FnZQZfc3RhdGUMX25hdGl2ZWVycm9yB19zb3VyY2UBAQABCAIAAAAJBgAAAAYUAAAABXN0YXRlAAAAAAYVAAAABnNvdXJjZQs=", TargetFrameworkMoniker.netfx461) } };
}
if (!PlatformDetection.IsUap)
@@ -553,104 +545,104 @@ namespace System.Runtime.Serialization.Formatters.Tests
OperationAbortedException operationAbortedException = (OperationAbortedException)typeof(OperationAbortedException)
.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(string), typeof(Exception) }, null)
.Invoke(new object[] { "message", exception });
- yield return new object[] { PopulateException(operationAbortedException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACVTeXN0ZW0uRGF0YS5PcGVyYXRpb25BYm9ydGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACVTeXN0ZW0uRGF0YS5PcGVyYXRpb25BYm9ydGVkRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACVTeXN0ZW0uRGF0YS5PcGVyYXRpb25BYm9ydGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACVTeXN0ZW0uRGF0YS5PcGVyYXRpb25BYm9ydGVkRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=" } };
+ yield return new object[] { PopulateException(operationAbortedException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACVTeXN0ZW0uRGF0YS5PcGVyYXRpb25BYm9ydGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACVTeXN0ZW0uRGF0YS5PcGVyYXRpb25BYm9ydGVkRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACVTeXN0ZW0uRGF0YS5PcGVyYXRpb25BYm9ydGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACVTeXN0ZW0uRGF0YS5PcGVyYXRpb25BYm9ydGVkRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netfx461) } };
}
var operationCanceledException = new OperationCanceledException("message", exception, new CancellationToken());
- yield return new object[] { PopulateException(operationCanceledException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACFTeXN0ZW0uT3BlcmF0aW9uQ2FuY2VsZWRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAhU3lzdGVtLk9wZXJhdGlvbkNhbmNlbGVkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAACFTeXN0ZW0uT3BlcmF0aW9uQ2FuY2VsZWRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAhU3lzdGVtLk9wZXJhdGlvbkNhbmNlbGVkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(operationCanceledException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACFTeXN0ZW0uT3BlcmF0aW9uQ2FuY2VsZWRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAhU3lzdGVtLk9wZXJhdGlvbkNhbmNlbGVkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACFTeXN0ZW0uT3BlcmF0aW9uQ2FuY2VsZWRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAhU3lzdGVtLk9wZXJhdGlvbkNhbmNlbGVkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var outOfMemoryException = new OutOfMemoryException("message", exception);
- yield return new object[] { PopulateException(outOfMemoryException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uT3V0T2ZNZW1vcnlFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAbU3lzdGVtLk91dE9mTWVtb3J5RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uT3V0T2ZNZW1vcnlFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAbU3lzdGVtLk91dE9mTWVtb3J5RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(outOfMemoryException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uT3V0T2ZNZW1vcnlFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAbU3lzdGVtLk91dE9mTWVtb3J5RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uT3V0T2ZNZW1vcnlFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAbU3lzdGVtLk91dE9mTWVtb3J5RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var overflowException = new OverflowException("message", exception);
- yield return new object[] { PopulateException(overflowException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uT3ZlcmZsb3dFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAYU3lzdGVtLk92ZXJmbG93RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uT3ZlcmZsb3dFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAYU3lzdGVtLk92ZXJmbG93RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(overflowException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uT3ZlcmZsb3dFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAYU3lzdGVtLk92ZXJmbG93RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uT3ZlcmZsb3dFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAYU3lzdGVtLk92ZXJmbG93RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var pathTooLongException = new PathTooLongException("message", exception);
- yield return new object[] { PopulateException(pathTooLongException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uSU8uUGF0aFRvb0xvbmdFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLklPLlBhdGhUb29Mb25nRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uSU8uUGF0aFRvb0xvbmdFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLklPLlBhdGhUb29Mb25nRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(pathTooLongException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uSU8uUGF0aFRvb0xvbmdFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLklPLlBhdGhUb29Mb25nRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB5TeXN0ZW0uSU8uUGF0aFRvb0xvbmdFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAeU3lzdGVtLklPLlBhdGhUb29Mb25nRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var pingException = new PingException("message", exception);
- yield return new object[] { PopulateException(pingException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAArU3lzdGVtLk5ldC5OZXR3b3JrSW5mb3JtYXRpb24uUGluZ0V4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAArU3lzdGVtLk5ldC5OZXR3b3JrSW5mb3JtYXRpb24uUGluZ0V4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAArU3lzdGVtLk5ldC5OZXR3b3JrSW5mb3JtYXRpb24uUGluZ0V4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAArU3lzdGVtLk5ldC5OZXR3b3JrSW5mb3JtYXRpb24uUGluZ0V4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL" } };
+ yield return new object[] { PopulateException(pingException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAArU3lzdGVtLk5ldC5OZXR3b3JrSW5mb3JtYXRpb24uUGluZ0V4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAArU3lzdGVtLk5ldC5OZXR3b3JrSW5mb3JtYXRpb24uUGluZ0V4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAArU3lzdGVtLk5ldC5OZXR3b3JrSW5mb3JtYXRpb24uUGluZ0V4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAArU3lzdGVtLk5ldC5OZXR3b3JrSW5mb3JtYXRpb24uUGluZ0V4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netfx461) } };
var platformNotSupportedException = new PlatformNotSupportedException("message", exception);
- yield return new object[] { PopulateException(platformNotSupportedException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACRTeXN0ZW0uUGxhdGZvcm1Ob3RTdXBwb3J0ZWRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAkU3lzdGVtLlBsYXRmb3JtTm90U3VwcG9ydGVkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAACRTeXN0ZW0uUGxhdGZvcm1Ob3RTdXBwb3J0ZWRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAkU3lzdGVtLlBsYXRmb3JtTm90U3VwcG9ydGVkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(platformNotSupportedException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACRTeXN0ZW0uUGxhdGZvcm1Ob3RTdXBwb3J0ZWRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAkU3lzdGVtLlBsYXRmb3JtTm90U3VwcG9ydGVkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACRTeXN0ZW0uUGxhdGZvcm1Ob3RTdXBwb3J0ZWRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAkU3lzdGVtLlBsYXRmb3JtTm90U3VwcG9ydGVkRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var policyException = new PolicyException("message", exception);
- yield return new object[] { PopulateException(policyException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACZTeXN0ZW0uU2VjdXJpdHkuUG9saWN5LlBvbGljeUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACZTeXN0ZW0uU2VjdXJpdHkuUG9saWN5LlBvbGljeUV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAACZTeXN0ZW0uU2VjdXJpdHkuUG9saWN5LlBvbGljeUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACZTeXN0ZW0uU2VjdXJpdHkuUG9saWN5LlBvbGljeUV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL" } };
-
+ yield return new object[] { PopulateException(policyException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACZTeXN0ZW0uU2VjdXJpdHkuUG9saWN5LlBvbGljeUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACZTeXN0ZW0uU2VjdXJpdHkuUG9saWN5LlBvbGljeUV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACZTeXN0ZW0uU2VjdXJpdHkuUG9saWN5LlBvbGljeUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACZTeXN0ZW0uU2VjdXJpdHkuUG9saWN5LlBvbGljeUV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netfx461) } };
+
var protocolViolationException = new ProtocolViolationException("message");
- yield return new object[] { PopulateException(protocolViolationException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAlU3lzdGVtLk5ldC5Qcm90b2NvbFZpb2xhdGlvbkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAlU3lzdGVtLk5ldC5Qcm90b2NvbFZpb2xhdGlvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAoGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAlU3lzdGVtLk5ldC5Qcm90b2NvbFZpb2xhdGlvbkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAlU3lzdGVtLk5ldC5Qcm90b2NvbFZpb2xhdGlvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAoGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==" } };
+ yield return new object[] { PopulateException(protocolViolationException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAlU3lzdGVtLk5ldC5Qcm90b2NvbFZpb2xhdGlvbkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAlU3lzdGVtLk5ldC5Qcm90b2NvbFZpb2xhdGlvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAoGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAlU3lzdGVtLk5ldC5Qcm90b2NvbFZpb2xhdGlvbkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAlU3lzdGVtLk5ldC5Qcm90b2NvbFZpb2xhdGlvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAoGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==", TargetFrameworkMoniker.netfx461) } };
var rankException = new RankException("message", exception);
- yield return new object[] { PopulateException(rankException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABRTeXN0ZW0uUmFua0V4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAABRTeXN0ZW0uUmFua0V4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAABRTeXN0ZW0uUmFua0V4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAABRTeXN0ZW0uUmFua0V4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL" } };
+ yield return new object[] { PopulateException(rankException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABRTeXN0ZW0uUmFua0V4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAABRTeXN0ZW0uUmFua0V4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABRTeXN0ZW0uUmFua0V4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAABRTeXN0ZW0uUmFua0V4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netfx461) } };
var readOnlyException = new ReadOnlyException("message", exception);
- yield return new object[] { PopulateException(readOnlyException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5SZWFkT25seUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAdU3lzdGVtLkRhdGEuUmVhZE9ubHlFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5SZWFkT25seUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAdU3lzdGVtLkRhdGEuUmVhZE9ubHlFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==" } };
-
+ yield return new object[] { PopulateException(readOnlyException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5SZWFkT25seUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAdU3lzdGVtLkRhdGEuUmVhZE9ubHlFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5SZWFkT25seUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAdU3lzdGVtLkRhdGEuUmVhZE9ubHlFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
+
var reflectionTypeLoadException = new ReflectionTypeLoadException(new Type[] { typeof(string), typeof(int) }, new Exception[] { exception, aggregateException }, "message");
- yield return new object[] { PopulateException(reflectionTypeLoadException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAC1TeXN0ZW0uUmVmbGVjdGlvbi5SZWZsZWN0aW9uVHlwZUxvYWRFeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwVUeXBlcwpFeGNlcHRpb25zAQEDAwEBAQABAAEHAwMpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAg1TeXN0ZW0uVHlwZVtdElN5c3RlbS5FeGNlcHRpb25bXQYCAAAALVN5c3RlbS5SZWZsZWN0aW9uLlJlZmxlY3Rpb25UeXBlTG9hZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAoGBQAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgYAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GBwAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCAAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoKCQkAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABwkAAAAAAQAAAAIAAAADEFN5c3RlbS5FeGNlcHRpb24JCwAAAAkMAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBg0AAAAGc2VjcmV0CAEBCQ4AAAAECwAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYPAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkRAAAACRIAAAAJBQAAAAkGAAAACQcAAAAAAAAACugDAAAJCAAAAAoEDAAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYXAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24JAwAAAAkZAAAACRoAAAAJBQAAAAkGAAAACQcAAAAAAAAACugDAAAJCAAAAAoJHwAAAAEOAAAACgAAAAgIAQAAAAYgAAAAA29uZQoBEQAAAAQAAAAJIQAAAAIAAAACAAAAARIAAAALAAAACQ8AAAAGIwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBGQAAAAQAAAAJJAAAAAIAAAACAAAAARoAAAALAAAACQ8AAAAGJgAAABFFeGNlcHRpb24gbWVzc2FnZQoJJwAAAAoKCgAAAAAKABUTgAoKBx8AAAAAAQAAAAEAAAADEFN5c3RlbS5FeGNlcHRpb24JGgAAAAEhAAAACgAAAAkNAAAACAEBCSoAAAABJAAAAAoAAAAJDQAAAAgBAQksAAAAAScAAAALAAAACQ8AAAAJIwAAAAoKCgoKAAAAAAoAFROACgoBKgAAAAoAAAAICAEAAAAJIAAAAAoBLAAAAAoAAAAICAEAAAAJIAAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAAC1TeXN0ZW0uUmVmbGVjdGlvbi5SZWZsZWN0aW9uVHlwZUxvYWRFeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwVUeXBlcwpFeGNlcHRpb25zAQEDAwEBAQABAAEHAwMpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAg1TeXN0ZW0uVHlwZVtdElN5c3RlbS5FeGNlcHRpb25bXQYCAAAALVN5c3RlbS5SZWZsZWN0aW9uLlJlZmxlY3Rpb25UeXBlTG9hZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAoGBQAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgYAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GBwAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCAAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoJCQAAAAkKAAAABAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAcJAAAAAAEAAAACAAAAAwtTeXN0ZW0uVHlwZQkMAAAACQ0AAAAHCgAAAAABAAAAAgAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkOAAAACQ8AAAAECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEAAAAAZzZWNyZXQIAQEJEQAAAAQMAAAAH1N5c3RlbS5Vbml0eVNlcmlhbGl6YXRpb25Ib2xkZXIDAAAABERhdGEJVW5pdHlUeXBlDEFzc2VtYmx5TmFtZQEAAQgGEgAAAA1TeXN0ZW0uU3RyaW5nBAAAAAYTAAAAS21zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQENAAAADAAAAAYUAAAADFN5c3RlbS5JbnQzMgQAAAAJEwAAAAQOAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBhYAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACRgAAAAJGQAAAAkFAAAACQYAAAAJBwAAAAAAAAAK6AMAAAkIAAAACgQPAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cw9Jbm5lckV4Y2VwdGlvbnMBAQMDAQEBAAEAAQcDKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAISU3lzdGVtLkV4Y2VwdGlvbltdBh4AAAAZU3lzdGVtLkFnZ3JlZ2F0ZUV4Y2VwdGlvbgkDAAAACSAAAAAJIQAAAAkFAAAACQYAAAAJBwAAAAAAAAAK6AMAAAkIAAAACgkmAAAAAREAAAALAAAACAgBAAAABicAAAADb25lCgEYAAAABAAAAAkoAAAAAgAAAAIAAAABGQAAAA4AAAAJFgAAAAYqAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEgAAAABAAAAAkrAAAAAgAAAAIAAAABIQAAAA4AAAAJFgAAAAYtAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkuAAAACgoKAAAAAAoAFROACgoHJgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkhAAAAASgAAAALAAAACRAAAAAIAQEJMQAAAAErAAAACwAAAAkQAAAACAEBCTMAAAABLgAAAA4AAAAJFgAAAAkqAAAACgoKCgoAAAAACgAVE4AKCgExAAAACwAAAAgIAQAAAAknAAAACgEzAAAACwAAAAgIAQAAAAknAAAACgs=" } };
+ yield return new object[] { PopulateException(reflectionTypeLoadException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAC1TeXN0ZW0uUmVmbGVjdGlvbi5SZWZsZWN0aW9uVHlwZUxvYWRFeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwVUeXBlcwpFeGNlcHRpb25zAQEDAwEBAQABAAEHAwMpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAg1TeXN0ZW0uVHlwZVtdElN5c3RlbS5FeGNlcHRpb25bXQYCAAAALVN5c3RlbS5SZWZsZWN0aW9uLlJlZmxlY3Rpb25UeXBlTG9hZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAoGBQAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgYAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GBwAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCAAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoKCQkAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABwkAAAAAAQAAAAIAAAADEFN5c3RlbS5FeGNlcHRpb24JCwAAAAkMAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBg0AAAAGc2VjcmV0CAEBCQ4AAAAECwAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYPAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkRAAAACRIAAAAJBQAAAAkGAAAACQcAAAAAAAAACugDAAAJCAAAAAoEDAAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYXAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24JAwAAAAkZAAAACRoAAAAJBQAAAAkGAAAACQcAAAAAAAAACugDAAAJCAAAAAoJHwAAAAEOAAAACgAAAAgIAQAAAAYgAAAAA29uZQoBEQAAAAQAAAAJIQAAAAIAAAACAAAAARIAAAALAAAACQ8AAAAGIwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBGQAAAAQAAAAJJAAAAAIAAAACAAAAARoAAAALAAAACQ8AAAAGJgAAABFFeGNlcHRpb24gbWVzc2FnZQoJJwAAAAoKCgAAAAAKABUTgAoKBx8AAAAAAQAAAAEAAAADEFN5c3RlbS5FeGNlcHRpb24JGgAAAAEhAAAACgAAAAkNAAAACAEBCSoAAAABJAAAAAoAAAAJDQAAAAgBAQksAAAAAScAAAALAAAACQ8AAAAJIwAAAAoKCgoKAAAAAAoAFROACgoBKgAAAAoAAAAICAEAAAAJIAAAAAoBLAAAAAoAAAAICAEAAAAJIAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAC1TeXN0ZW0uUmVmbGVjdGlvbi5SZWZsZWN0aW9uVHlwZUxvYWRFeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwVUeXBlcwpFeGNlcHRpb25zAQEDAwEBAQABAAEHAwMpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAg1TeXN0ZW0uVHlwZVtdElN5c3RlbS5FeGNlcHRpb25bXQYCAAAALVN5c3RlbS5SZWZsZWN0aW9uLlJlZmxlY3Rpb25UeXBlTG9hZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAoGBQAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgYAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GBwAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCAAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoJCQAAAAkKAAAABAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAcJAAAAAAEAAAACAAAAAwtTeXN0ZW0uVHlwZQkMAAAACQ0AAAAHCgAAAAABAAAAAgAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkOAAAACQ8AAAAECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEAAAAAZzZWNyZXQIAQEJEQAAAAQMAAAAH1N5c3RlbS5Vbml0eVNlcmlhbGl6YXRpb25Ib2xkZXIDAAAABERhdGEJVW5pdHlUeXBlDEFzc2VtYmx5TmFtZQEAAQgGEgAAAA1TeXN0ZW0uU3RyaW5nBAAAAAYTAAAAS21zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQENAAAADAAAAAYUAAAADFN5c3RlbS5JbnQzMgQAAAAJEwAAAAQOAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBhYAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACRgAAAAJGQAAAAkFAAAACQYAAAAJBwAAAAAAAAAK6AMAAAkIAAAACgQPAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cw9Jbm5lckV4Y2VwdGlvbnMBAQMDAQEBAAEAAQcDKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAISU3lzdGVtLkV4Y2VwdGlvbltdBh4AAAAZU3lzdGVtLkFnZ3JlZ2F0ZUV4Y2VwdGlvbgkDAAAACSAAAAAJIQAAAAkFAAAACQYAAAAJBwAAAAAAAAAK6AMAAAkIAAAACgkmAAAAAREAAAALAAAACAgBAAAABicAAAADb25lCgEYAAAABAAAAAkoAAAAAgAAAAIAAAABGQAAAA4AAAAJFgAAAAYqAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEgAAAABAAAAAkrAAAAAgAAAAIAAAABIQAAAA4AAAAJFgAAAAYtAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkuAAAACgoKAAAAAAoAFROACgoHJgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkhAAAAASgAAAALAAAACRAAAAAIAQEJMQAAAAErAAAACwAAAAkQAAAACAEBCTMAAAABLgAAAA4AAAAJFgAAAAkqAAAACgoKCgoAAAAACgAVE4AKCgExAAAACwAAAAgIAQAAAAknAAAACgEzAAAACwAAAAgIAQAAAAknAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var regexMatchTimeoutException = new RegexMatchTimeoutException("message", exception);
- yield return new object[] { PopulateException(regexMatchTimeoutException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA5U3lzdGVtLlRleHQuUmVndWxhckV4cHJlc3Npb25zLlJlZ2V4TWF0Y2hUaW1lb3V0RXhjZXB0aW9uDwAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMKcmVnZXhJbnB1dAxyZWdleFBhdHRlcm4MdGltZW91dFRpY2tzAQEDAwEBAQABAAEHAQEAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIJAgAAAAYDAAAAOVN5c3RlbS5UZXh0LlJlZ3VsYXJFeHByZXNzaW9ucy5SZWdleE1hdGNoVGltZW91dEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgsAAAAACQsAAAD//////////wQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkMAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYNAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkPAAAACRAAAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoEDAAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFQAAAAZzZWNyZXQIAQEJFgAAAAEPAAAABQAAAAkXAAAAAgAAAAIAAAABEAAAAAYAAAAJDQAAAAYZAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEWAAAADAAAAAgIAQAAAAYaAAAAA29uZQoBFwAAAAwAAAAJFQAAAAgBAQkcAAAAARwAAAAMAAAACAgBAAAACRoAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA5U3lzdGVtLlRleHQuUmVndWxhckV4cHJlc3Npb25zLlJlZ2V4TWF0Y2hUaW1lb3V0RXhjZXB0aW9uDwAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMKcmVnZXhJbnB1dAxyZWdleFBhdHRlcm4MdGltZW91dFRpY2tzAQEDAwEBAQABAAEHAQEAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIJAgAAAAYDAAAAOVN5c3RlbS5UZXh0LlJlZ3VsYXJFeHByZXNzaW9ucy5SZWdleE1hdGNoVGltZW91dEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgsAAAAACQsAAAD//////////wQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkMAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYNAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkPAAAACRAAAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoEDAAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFQAAAAZzZWNyZXQIAQEJFgAAAAEPAAAABQAAAAkXAAAAAgAAAAIAAAABEAAAAAYAAAAJDQAAAAYZAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEWAAAADAAAAAgIAQAAAAYaAAAAA29uZQoBFwAAAAwAAAAJFQAAAAgBAQkcAAAAARwAAAAMAAAACAgBAAAACRoAAAAKCw==" } };
+ yield return new object[] { PopulateException(regexMatchTimeoutException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA5U3lzdGVtLlRleHQuUmVndWxhckV4cHJlc3Npb25zLlJlZ2V4TWF0Y2hUaW1lb3V0RXhjZXB0aW9uDwAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMKcmVnZXhJbnB1dAxyZWdleFBhdHRlcm4MdGltZW91dFRpY2tzAQEDAwEBAQABAAEHAQEAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIJAgAAAAYDAAAAOVN5c3RlbS5UZXh0LlJlZ3VsYXJFeHByZXNzaW9ucy5SZWdleE1hdGNoVGltZW91dEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgsAAAAACQsAAAD//////////wQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkMAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYNAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkPAAAACRAAAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoEDAAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFQAAAAZzZWNyZXQIAQEJFgAAAAEPAAAABQAAAAkXAAAAAgAAAAIAAAABEAAAAAYAAAAJDQAAAAYZAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEWAAAADAAAAAgIAQAAAAYaAAAAA29uZQoBFwAAAAwAAAAJFQAAAAgBAQkcAAAAARwAAAAMAAAACAgBAAAACRoAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA5U3lzdGVtLlRleHQuUmVndWxhckV4cHJlc3Npb25zLlJlZ2V4TWF0Y2hUaW1lb3V0RXhjZXB0aW9uDwAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMKcmVnZXhJbnB1dAxyZWdleFBhdHRlcm4MdGltZW91dFRpY2tzAQEDAwEBAQABAAEHAQEAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIJAgAAAAYDAAAAOVN5c3RlbS5UZXh0LlJlZ3VsYXJFeHByZXNzaW9ucy5SZWdleE1hdGNoVGltZW91dEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgsAAAAACQsAAAD//////////wQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkMAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYNAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkPAAAACRAAAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoEDAAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFQAAAAZzZWNyZXQIAQEJFgAAAAEPAAAABQAAAAkXAAAAAgAAAAIAAAABEAAAAAYAAAAJDQAAAAYZAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEWAAAADAAAAAgIAQAAAAYaAAAAA29uZQoBFwAAAAwAAAAJFQAAAAgBAQkcAAAAARwAAAAMAAAACAgBAAAACRoAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var rowNotInTableException = new RowNotInTableException("message", exception);
- yield return new object[] { PopulateException(rowNotInTableException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0ZW0uRGF0YS5Sb3dOb3RJblRhYmxlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACJTeXN0ZW0uRGF0YS5Sb3dOb3RJblRhYmxlRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0ZW0uRGF0YS5Sb3dOb3RJblRhYmxlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACJTeXN0ZW0uRGF0YS5Sb3dOb3RJblRhYmxlRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=" } };
+ yield return new object[] { PopulateException(rowNotInTableException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0ZW0uRGF0YS5Sb3dOb3RJblRhYmxlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACJTeXN0ZW0uRGF0YS5Sb3dOb3RJblRhYmxlRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0ZW0uRGF0YS5Sb3dOb3RJblRhYmxlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACJTeXN0ZW0uRGF0YS5Sb3dOb3RJblRhYmxlRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var runtimeBinderException = new RuntimeBinderException("message", exception);
- yield return new object[] { PopulateException(runtimeBinderException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAFNNaWNyb3NvZnQuQ1NoYXJwLCBWZXJzaW9uPTQuMC40LjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAANU1pY3Jvc29mdC5DU2hhcnAuUnVudGltZUJpbmRlci5SdW50aW1lQmluZGVyRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADVNaWNyb3NvZnQuQ1NoYXJwLlJ1bnRpbWVCaW5kZXIuUnVudGltZUJpbmRlckV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAFNNaWNyb3NvZnQuQ1NoYXJwLCBWZXJzaW9uPTQuMC40LjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAANU1pY3Jvc29mdC5DU2hhcnAuUnVudGltZUJpbmRlci5SdW50aW1lQmluZGVyRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADVNaWNyb3NvZnQuQ1NoYXJwLlJ1bnRpbWVCaW5kZXIuUnVudGltZUJpbmRlckV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL" } };
+ yield return new object[] { PopulateException(runtimeBinderException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFNNaWNyb3NvZnQuQ1NoYXJwLCBWZXJzaW9uPTQuMC40LjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAANU1pY3Jvc29mdC5DU2hhcnAuUnVudGltZUJpbmRlci5SdW50aW1lQmluZGVyRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADVNaWNyb3NvZnQuQ1NoYXJwLlJ1bnRpbWVCaW5kZXIuUnVudGltZUJpbmRlckV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFNNaWNyb3NvZnQuQ1NoYXJwLCBWZXJzaW9uPTQuMC40LjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAANU1pY3Jvc29mdC5DU2hhcnAuUnVudGltZUJpbmRlci5SdW50aW1lQmluZGVyRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADVNaWNyb3NvZnQuQ1NoYXJwLlJ1bnRpbWVCaW5kZXIuUnVudGltZUJpbmRlckV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netfx461) } };
var runtimeBinderInternalCompilerException = new RuntimeBinderInternalCompilerException("message", exception);
- yield return new object[] { PopulateException(runtimeBinderInternalCompilerException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAFNNaWNyb3NvZnQuQ1NoYXJwLCBWZXJzaW9uPTQuMC40LjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAARU1pY3Jvc29mdC5DU2hhcnAuUnVudGltZUJpbmRlci5SdW50aW1lQmluZGVySW50ZXJuYWxDb21waWxlckV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAABFTWljcm9zb2Z0LkNTaGFycC5SdW50aW1lQmluZGVyLlJ1bnRpbWVCaW5kZXJJbnRlcm5hbENvbXBpbGVyRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAFNNaWNyb3NvZnQuQ1NoYXJwLCBWZXJzaW9uPTQuMC40LjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAARU1pY3Jvc29mdC5DU2hhcnAuUnVudGltZUJpbmRlci5SdW50aW1lQmluZGVySW50ZXJuYWxDb21waWxlckV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAABFTWljcm9zb2Z0LkNTaGFycC5SdW50aW1lQmluZGVyLlJ1bnRpbWVCaW5kZXJJbnRlcm5hbENvbXBpbGVyRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=" } };
+ yield return new object[] { PopulateException(runtimeBinderInternalCompilerException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFNNaWNyb3NvZnQuQ1NoYXJwLCBWZXJzaW9uPTQuMC40LjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAARU1pY3Jvc29mdC5DU2hhcnAuUnVudGltZUJpbmRlci5SdW50aW1lQmluZGVySW50ZXJuYWxDb21waWxlckV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAABFTWljcm9zb2Z0LkNTaGFycC5SdW50aW1lQmluZGVyLlJ1bnRpbWVCaW5kZXJJbnRlcm5hbENvbXBpbGVyRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFNNaWNyb3NvZnQuQ1NoYXJwLCBWZXJzaW9uPTQuMC40LjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAARU1pY3Jvc29mdC5DU2hhcnAuUnVudGltZUJpbmRlci5SdW50aW1lQmluZGVySW50ZXJuYWxDb21waWxlckV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAABFTWljcm9zb2Z0LkNTaGFycC5SdW50aW1lQmluZGVyLlJ1bnRpbWVCaW5kZXJJbnRlcm5hbENvbXBpbGVyRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netfx461) } };
if (!PlatformDetection.IsUap)
{
RuntimeWrappedException runtimeWrappedException = (RuntimeWrappedException)typeof(RuntimeWrappedException)
.GetConstructor((PlatformDetection.IsFullFramework ? BindingFlags.NonPublic : BindingFlags.Public) | BindingFlags.Instance, null, new Type[] { typeof(object) }, null)
.Invoke(new object[] { exception });
- yield return new object[] { PopulateException(runtimeWrappedException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAADdTeXN0ZW0uUnVudGltZS5Db21waWxlclNlcnZpY2VzLlJ1bnRpbWVXcmFwcGVkRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMQV3JhcHBlZEV4Y2VwdGlvbgEBAwMBAQEAAQABBwMpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAhBTeXN0ZW0uRXhjZXB0aW9uBgIAAAA3U3lzdGVtLlJ1bnRpbWUuQ29tcGlsZXJTZXJ2aWNlcy5SdW50aW1lV3JhcHBlZEV4Y2VwdGlvbgYDAAAAY0FuIG9iamVjdCB0aGF0IGRvZXMgbm90IGRlcml2ZSBmcm9tIFN5c3RlbS5FeGNlcHRpb24gaGFzIGJlZW4gd3JhcHBlZCBpbiBhIFJ1bnRpbWVXcmFwcGVkRXhjZXB0aW9uLgkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgkJAAAABAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQJAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgYMAAAAB21lc3NhZ2UJDQAAAAkOAAAACQUAAAAJBgAAAAkHAAAAAAAAAAroAwAACQgAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAJAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAADdTeXN0ZW0uUnVudGltZS5Db21waWxlclNlcnZpY2VzLlJ1bnRpbWVXcmFwcGVkRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMQV3JhcHBlZEV4Y2VwdGlvbgEBAwMBAQEAAQABBwMpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAhBTeXN0ZW0uRXhjZXB0aW9uBgIAAAA3U3lzdGVtLlJ1bnRpbWUuQ29tcGlsZXJTZXJ2aWNlcy5SdW50aW1lV3JhcHBlZEV4Y2VwdGlvbgYDAAAAY0FuIG9iamVjdCB0aGF0IGRvZXMgbm90IGRlcml2ZSBmcm9tIFN5c3RlbS5FeGNlcHRpb24gaGFzIGJlZW4gd3JhcHBlZCBpbiBhIFJ1bnRpbWVXcmFwcGVkRXhjZXB0aW9uLgkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgkJAAAABAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQJAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgYMAAAAB21lc3NhZ2UJDQAAAAkOAAAACQUAAAAJBgAAAAkHAAAAAAAAAAroAwAACQgAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAJAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(runtimeWrappedException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADdTeXN0ZW0uUnVudGltZS5Db21waWxlclNlcnZpY2VzLlJ1bnRpbWVXcmFwcGVkRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMQV3JhcHBlZEV4Y2VwdGlvbgEBAwMBAQEAAQABBwMpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAhBTeXN0ZW0uRXhjZXB0aW9uBgIAAAA3U3lzdGVtLlJ1bnRpbWUuQ29tcGlsZXJTZXJ2aWNlcy5SdW50aW1lV3JhcHBlZEV4Y2VwdGlvbgYDAAAAY0FuIG9iamVjdCB0aGF0IGRvZXMgbm90IGRlcml2ZSBmcm9tIFN5c3RlbS5FeGNlcHRpb24gaGFzIGJlZW4gd3JhcHBlZCBpbiBhIFJ1bnRpbWVXcmFwcGVkRXhjZXB0aW9uLgkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgkJAAAABAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQJAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgYMAAAAB21lc3NhZ2UJDQAAAAkOAAAACQUAAAAJBgAAAAkHAAAAAAAAAAroAwAACQgAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAJAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADdTeXN0ZW0uUnVudGltZS5Db21waWxlclNlcnZpY2VzLlJ1bnRpbWVXcmFwcGVkRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMQV3JhcHBlZEV4Y2VwdGlvbgEBAwMBAQEAAQABBwMpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAhBTeXN0ZW0uRXhjZXB0aW9uBgIAAAA3U3lzdGVtLlJ1bnRpbWUuQ29tcGlsZXJTZXJ2aWNlcy5SdW50aW1lV3JhcHBlZEV4Y2VwdGlvbgYDAAAAY0FuIG9iamVjdCB0aGF0IGRvZXMgbm90IGRlcml2ZSBmcm9tIFN5c3RlbS5FeGNlcHRpb24gaGFzIGJlZW4gd3JhcHBlZCBpbiBhIFJ1bnRpbWVXcmFwcGVkRXhjZXB0aW9uLgkEAAAACgYFAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYHAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYIAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgkJAAAABAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQJAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgYMAAAAB21lc3NhZ2UJDQAAAAkOAAAACQUAAAAJBgAAAAkHAAAAAAAAAAroAwAACQgAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAJAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
}
var sEHException = new SEHException("message", exception);
- yield return new object[] { PopulateException(sEHException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACtTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuU0VIRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAK1N5c3RlbS5SdW50aW1lLkludGVyb3BTZXJ2aWNlcy5TRUhFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAACtTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuU0VIRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAK1N5c3RlbS5SdW50aW1lLkludGVyb3BTZXJ2aWNlcy5TRUhFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(sEHException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACtTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuU0VIRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAK1N5c3RlbS5SdW50aW1lLkludGVyb3BTZXJ2aWNlcy5TRUhFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACtTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuU0VIRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAK1N5c3RlbS5SdW50aW1lLkludGVyb3BTZXJ2aWNlcy5TRUhFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var safeArrayRankMismatchException = new SafeArrayRankMismatchException("message", exception);
- yield return new object[] { PopulateException(safeArrayRankMismatchException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAD1TeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuU2FmZUFycmF5UmFua01pc21hdGNoRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAPVN5c3RlbS5SdW50aW1lLkludGVyb3BTZXJ2aWNlcy5TYWZlQXJyYXlSYW5rTWlzbWF0Y2hFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAD1TeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuU2FmZUFycmF5UmFua01pc21hdGNoRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAPVN5c3RlbS5SdW50aW1lLkludGVyb3BTZXJ2aWNlcy5TYWZlQXJyYXlSYW5rTWlzbWF0Y2hFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(safeArrayRankMismatchException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAD1TeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuU2FmZUFycmF5UmFua01pc21hdGNoRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAPVN5c3RlbS5SdW50aW1lLkludGVyb3BTZXJ2aWNlcy5TYWZlQXJyYXlSYW5rTWlzbWF0Y2hFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAD1TeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuU2FmZUFycmF5UmFua01pc21hdGNoRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAPVN5c3RlbS5SdW50aW1lLkludGVyb3BTZXJ2aWNlcy5TYWZlQXJyYXlSYW5rTWlzbWF0Y2hFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var safeArrayTypeMismatchException = new SafeArrayTypeMismatchException("message", exception);
- yield return new object[] { PopulateException(safeArrayTypeMismatchException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAD1TeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuU2FmZUFycmF5VHlwZU1pc21hdGNoRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAPVN5c3RlbS5SdW50aW1lLkludGVyb3BTZXJ2aWNlcy5TYWZlQXJyYXlUeXBlTWlzbWF0Y2hFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAD1TeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuU2FmZUFycmF5VHlwZU1pc21hdGNoRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAPVN5c3RlbS5SdW50aW1lLkludGVyb3BTZXJ2aWNlcy5TYWZlQXJyYXlUeXBlTWlzbWF0Y2hFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(safeArrayTypeMismatchException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAD1TeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuU2FmZUFycmF5VHlwZU1pc21hdGNoRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAPVN5c3RlbS5SdW50aW1lLkludGVyb3BTZXJ2aWNlcy5TYWZlQXJyYXlUeXBlTWlzbWF0Y2hFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAD1TeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXMuU2FmZUFycmF5VHlwZU1pc21hdGNoRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAPVN5c3RlbS5SdW50aW1lLkludGVyb3BTZXJ2aWNlcy5TYWZlQXJyYXlUeXBlTWlzbWF0Y2hFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var securityException = new SecurityException("message", exception);
// Not testing additional serializable properties as they diverged between Core and Desktop
- yield return new object[] { PopulateException(securityException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACFTeXN0ZW0uU2VjdXJpdHkuU2VjdXJpdHlFeGNlcHRpb24SAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwhEZW1hbmRlZApHcmFudGVkU2V0ClJlZnVzZWRTZXQGRGVuaWVkClBlcm1pdE9ubHkDVXJsAQEDAwEBAQABAAEHAQEBAQEBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACFTeXN0ZW0uU2VjdXJpdHkuU2VjdXJpdHlFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgoKCgoKCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAACFTeXN0ZW0uU2VjdXJpdHkuU2VjdXJpdHlFeGNlcHRpb24YAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwZBY3Rpb24ZRmlyc3RQZXJtaXNzaW9uVGhhdEZhaWxlZAhEZW1hbmRlZApHcmFudGVkU2V0ClJlZnVzZWRTZXQGRGVuaWVkClBlcm1pdE9ubHkIQXNzZW1ibHkGTWV0aG9kDU1ldGhvZF9TdHJpbmcEWm9uZQNVcmwBAQMDAQEBAAEAAQcDAQEBAQEBAwcBAwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAipTeXN0ZW0uU2VjdXJpdHkuUGVybWlzc2lvbnMuU2VjdXJpdHlBY3Rpb24eU3lzdGVtLlJlZmxlY3Rpb24uQXNzZW1ibHlOYW1lAhxTeXN0ZW0uU2VjdXJpdHkuU2VjdXJpdHlab25lBgIAAAAhU3lzdGVtLlNlY3VyaXR5LlNlY3VyaXR5RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoE9v///ypTeXN0ZW0uU2VjdXJpdHkuUGVybWlzc2lvbnMuU2VjdXJpdHlBY3Rpb24BAAAAB3ZhbHVlX18ACAAAAAAKCgoKCgoKCgoE9f///xxTeXN0ZW0uU2VjdXJpdHkuU2VjdXJpdHlab25lAQAAAAd2YWx1ZV9fAAgAAAAACgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkMAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYNAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkPAAAACRAAAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoEDAAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFQAAAAZzZWNyZXQIAQEJFgAAAAEPAAAABAAAAAkXAAAAAgAAAAIAAAABEAAAAAUAAAAJDQAAAAYZAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEWAAAADAAAAAgIAQAAAAYaAAAAA29uZQoBFwAAAAwAAAAJFQAAAAgBAQkcAAAAARwAAAAMAAAACAgBAAAACRoAAAAKCw==" } };
+ yield return new object[] { PopulateException(securityException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACFTeXN0ZW0uU2VjdXJpdHkuU2VjdXJpdHlFeGNlcHRpb24SAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwhEZW1hbmRlZApHcmFudGVkU2V0ClJlZnVzZWRTZXQGRGVuaWVkClBlcm1pdE9ubHkDVXJsAQEDAwEBAQABAAEHAQEBAQEBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACFTeXN0ZW0uU2VjdXJpdHkuU2VjdXJpdHlFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgoKCgoKCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACFTeXN0ZW0uU2VjdXJpdHkuU2VjdXJpdHlFeGNlcHRpb24YAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwZBY3Rpb24ZRmlyc3RQZXJtaXNzaW9uVGhhdEZhaWxlZAhEZW1hbmRlZApHcmFudGVkU2V0ClJlZnVzZWRTZXQGRGVuaWVkClBlcm1pdE9ubHkIQXNzZW1ibHkGTWV0aG9kDU1ldGhvZF9TdHJpbmcEWm9uZQNVcmwBAQMDAQEBAAEAAQcDAQEBAQEBAwcBAwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAipTeXN0ZW0uU2VjdXJpdHkuUGVybWlzc2lvbnMuU2VjdXJpdHlBY3Rpb24eU3lzdGVtLlJlZmxlY3Rpb24uQXNzZW1ibHlOYW1lAhxTeXN0ZW0uU2VjdXJpdHkuU2VjdXJpdHlab25lBgIAAAAhU3lzdGVtLlNlY3VyaXR5LlNlY3VyaXR5RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoE9v///ypTeXN0ZW0uU2VjdXJpdHkuUGVybWlzc2lvbnMuU2VjdXJpdHlBY3Rpb24BAAAAB3ZhbHVlX18ACAAAAAAKCgoKCgoKCgoE9f///xxTeXN0ZW0uU2VjdXJpdHkuU2VjdXJpdHlab25lAQAAAAd2YWx1ZV9fAAgAAAAACgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkMAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYNAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkPAAAACRAAAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoEDAAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFQAAAAZzZWNyZXQIAQEJFgAAAAEPAAAABAAAAAkXAAAAAgAAAAIAAAABEAAAAAUAAAAJDQAAAAYZAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEWAAAADAAAAAgIAQAAAAYaAAAAA29uZQoBFwAAAAwAAAAJFQAAAAgBAQkcAAAAARwAAAAMAAAACAgBAAAACRoAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var semaphoreFullException = new SemaphoreFullException("message", exception);
- yield return new object[] { PopulateException(semaphoreFullException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249Mi4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAnU3lzdGVtLlRocmVhZGluZy5TZW1hcGhvcmVGdWxsRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACdTeXN0ZW0uVGhyZWFkaW5nLlNlbWFwaG9yZUZ1bGxFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249Mi4wLjAuMCwgQ3VsdHVyZT1OZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAnU3lzdGVtLlRocmVhZGluZy5TZW1hcGhvcmVGdWxsRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACdTeXN0ZW0uVGhyZWFkaW5nLlNlbWFwaG9yZUZ1bGxFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==" } };
+ yield return new object[] { PopulateException(semaphoreFullException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249Mi4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAnU3lzdGVtLlRocmVhZGluZy5TZW1hcGhvcmVGdWxsRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACdTeXN0ZW0uVGhyZWFkaW5nLlNlbWFwaG9yZUZ1bGxFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249Mi4wLjAuMCwgQ3VsdHVyZT1OZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAnU3lzdGVtLlRocmVhZGluZy5TZW1hcGhvcmVGdWxsRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACdTeXN0ZW0uVGhyZWFkaW5nLlNlbWFwaG9yZUZ1bGxFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var serializationException = new SerializationException("message", exception);
- yield return new object[] { PopulateException(serializationException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLlNlcmlhbGl6YXRpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5TZXJpYWxpemF0aW9uRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLlNlcmlhbGl6YXRpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5TZXJpYWxpemF0aW9uRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(serializationException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLlNlcmlhbGl6YXRpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5TZXJpYWxpemF0aW9uRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLlNlcmlhbGl6YXRpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5TZXJpYWxpemF0aW9uRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var settingsPropertyIsReadOnlyException = new SettingsPropertyIsReadOnlyException("message", exception);
- yield return new object[] { PopulateException(settingsPropertyIsReadOnlyException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA4U3lzdGVtLkNvbmZpZ3VyYXRpb24uU2V0dGluZ3NQcm9wZXJ0eUlzUmVhZE9ubHlFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAOFN5c3RlbS5Db25maWd1cmF0aW9uLlNldHRpbmdzUHJvcGVydHlJc1JlYWRPbmx5RXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA4U3lzdGVtLkNvbmZpZ3VyYXRpb24uU2V0dGluZ3NQcm9wZXJ0eUlzUmVhZE9ubHlFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAOFN5c3RlbS5Db25maWd1cmF0aW9uLlNldHRpbmdzUHJvcGVydHlJc1JlYWRPbmx5RXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=" } };
+ yield return new object[] { PopulateException(settingsPropertyIsReadOnlyException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA4U3lzdGVtLkNvbmZpZ3VyYXRpb24uU2V0dGluZ3NQcm9wZXJ0eUlzUmVhZE9ubHlFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAOFN5c3RlbS5Db25maWd1cmF0aW9uLlNldHRpbmdzUHJvcGVydHlJc1JlYWRPbmx5RXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA4U3lzdGVtLkNvbmZpZ3VyYXRpb24uU2V0dGluZ3NQcm9wZXJ0eUlzUmVhZE9ubHlFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAOFN5c3RlbS5Db25maWd1cmF0aW9uLlNldHRpbmdzUHJvcGVydHlJc1JlYWRPbmx5RXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var settingsPropertyNotFoundException = new SettingsPropertyNotFoundException("message", exception);
- yield return new object[] { PopulateException(settingsPropertyNotFoundException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA2U3lzdGVtLkNvbmZpZ3VyYXRpb24uU2V0dGluZ3NQcm9wZXJ0eU5vdEZvdW5kRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADZTeXN0ZW0uQ29uZmlndXJhdGlvbi5TZXR0aW5nc1Byb3BlcnR5Tm90Rm91bmRFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA2U3lzdGVtLkNvbmZpZ3VyYXRpb24uU2V0dGluZ3NQcm9wZXJ0eU5vdEZvdW5kRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADZTeXN0ZW0uQ29uZmlndXJhdGlvbi5TZXR0aW5nc1Byb3BlcnR5Tm90Rm91bmRFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==" } };
+ yield return new object[] { PopulateException(settingsPropertyNotFoundException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA2U3lzdGVtLkNvbmZpZ3VyYXRpb24uU2V0dGluZ3NQcm9wZXJ0eU5vdEZvdW5kRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADZTeXN0ZW0uQ29uZmlndXJhdGlvbi5TZXR0aW5nc1Byb3BlcnR5Tm90Rm91bmRFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA2U3lzdGVtLkNvbmZpZ3VyYXRpb24uU2V0dGluZ3NQcm9wZXJ0eU5vdEZvdW5kRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADZTeXN0ZW0uQ29uZmlndXJhdGlvbi5TZXR0aW5nc1Byb3BlcnR5Tm90Rm91bmRFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var settingsPropertyWrongTypeException = new SettingsPropertyWrongTypeException("message", exception);
- yield return new object[] { PopulateException(settingsPropertyWrongTypeException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA3U3lzdGVtLkNvbmZpZ3VyYXRpb24uU2V0dGluZ3NQcm9wZXJ0eVdyb25nVHlwZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAA3U3lzdGVtLkNvbmZpZ3VyYXRpb24uU2V0dGluZ3NQcm9wZXJ0eVdyb25nVHlwZUV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA3U3lzdGVtLkNvbmZpZ3VyYXRpb24uU2V0dGluZ3NQcm9wZXJ0eVdyb25nVHlwZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAA3U3lzdGVtLkNvbmZpZ3VyYXRpb24uU2V0dGluZ3NQcm9wZXJ0eVdyb25nVHlwZUV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL" } };
+ yield return new object[] { PopulateException(settingsPropertyWrongTypeException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA3U3lzdGVtLkNvbmZpZ3VyYXRpb24uU2V0dGluZ3NQcm9wZXJ0eVdyb25nVHlwZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAA3U3lzdGVtLkNvbmZpZ3VyYXRpb24uU2V0dGluZ3NQcm9wZXJ0eVdyb25nVHlwZUV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAA3U3lzdGVtLkNvbmZpZ3VyYXRpb24uU2V0dGluZ3NQcm9wZXJ0eVdyb25nVHlwZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAA3U3lzdGVtLkNvbmZpZ3VyYXRpb24uU2V0dGluZ3NQcm9wZXJ0eVdyb25nVHlwZUV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netfx461) } };
var smtpException = new SmtpException(SmtpStatusCode.Ok, "message");
- yield return new object[] { PopulateException(smtpException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAdU3lzdGVtLk5ldC5NYWlsLlNtdHBFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwZTdGF0dXMBAQMDAQEBAAEAAQcAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIIAgAAAAYDAAAAHVN5c3RlbS5OZXQuTWFpbC5TbXRwRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACgYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCvoAAAAEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAdU3lzdGVtLk5ldC5NYWlsLlNtdHBFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwZTdGF0dXMBAQMDAQEBAAEAAQcAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIIAgAAAAYDAAAAHVN5c3RlbS5OZXQuTWFpbC5TbXRwRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACgYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCvoAAAAEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==" } };
+ yield return new object[] { PopulateException(smtpException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAdU3lzdGVtLk5ldC5NYWlsLlNtdHBFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwZTdGF0dXMBAQMDAQEBAAEAAQcAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIIAgAAAAYDAAAAHVN5c3RlbS5OZXQuTWFpbC5TbXRwRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACgYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCvoAAAAEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAdU3lzdGVtLk5ldC5NYWlsLlNtdHBFeGNlcHRpb24NAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwZTdGF0dXMBAQMDAQEBAAEAAQcAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIIAgAAAAYDAAAAHVN5c3RlbS5OZXQuTWFpbC5TbXRwRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACgYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCvoAAAAEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==", TargetFrameworkMoniker.netfx461) } };
var smtpFailedRecipientException = new SmtpFailedRecipientException(SmtpStatusCode.Ok, "failedRecipient", "serverResponse");
- yield return new object[] { PopulateException(smtpFailedRecipientException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAsU3lzdGVtLk5ldC5NYWlsLlNtdHBGYWlsZWRSZWNpcGllbnRFeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwZTdGF0dXMPZmFpbGVkUmVjaXBpZW50AQEDAwEBAQABAAEHAAEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAggCAAAABgMAAAAsU3lzdGVtLk5ldC5NYWlsLlNtdHBGYWlsZWRSZWNpcGllbnRFeGNlcHRpb24GBAAAADJDb21wbGV0ZWQuIFRoZSBzZXJ2ZXIgcmVzcG9uc2Ugd2FzOiBzZXJ2ZXJSZXNwb25zZQkFAAAACgYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCvoAAAAGCgAAAA9mYWlsZWRSZWNpcGllbnQEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgwAAAAGc2VjcmV0CAEBCQ0AAAABDQAAAAsAAAAICAEAAAAGDgAAAANvbmUKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAsU3lzdGVtLk5ldC5NYWlsLlNtdHBGYWlsZWRSZWNpcGllbnRFeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwZTdGF0dXMPZmFpbGVkUmVjaXBpZW50AQEDAwEBAQABAAEHAAEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAggCAAAABgMAAAAsU3lzdGVtLk5ldC5NYWlsLlNtdHBGYWlsZWRSZWNpcGllbnRFeGNlcHRpb24GBAAAADJDb21wbGV0ZWQuIFRoZSBzZXJ2ZXIgcmVzcG9uc2Ugd2FzOiBzZXJ2ZXJSZXNwb25zZQkFAAAACgYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCvoAAAAGCgAAAA9mYWlsZWRSZWNpcGllbnQEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgwAAAAGc2VjcmV0CAEBCQ0AAAABDQAAAAsAAAAICAEAAAAGDgAAAANvbmUKCw==" } };
+ yield return new object[] { PopulateException(smtpFailedRecipientException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAsU3lzdGVtLk5ldC5NYWlsLlNtdHBGYWlsZWRSZWNpcGllbnRFeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwZTdGF0dXMPZmFpbGVkUmVjaXBpZW50AQEDAwEBAQABAAEHAAEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAggCAAAABgMAAAAsU3lzdGVtLk5ldC5NYWlsLlNtdHBGYWlsZWRSZWNpcGllbnRFeGNlcHRpb24GBAAAADJDb21wbGV0ZWQuIFRoZSBzZXJ2ZXIgcmVzcG9uc2Ugd2FzOiBzZXJ2ZXJSZXNwb25zZQkFAAAACgYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCvoAAAAGCgAAAA9mYWlsZWRSZWNpcGllbnQEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgwAAAAGc2VjcmV0CAEBCQ0AAAABDQAAAAsAAAAICAEAAAAGDgAAAANvbmUKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAsU3lzdGVtLk5ldC5NYWlsLlNtdHBGYWlsZWRSZWNpcGllbnRFeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwZTdGF0dXMPZmFpbGVkUmVjaXBpZW50AQEDAwEBAQABAAEHAAEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAggCAAAABgMAAAAsU3lzdGVtLk5ldC5NYWlsLlNtdHBGYWlsZWRSZWNpcGllbnRFeGNlcHRpb24GBAAAADJDb21wbGV0ZWQuIFRoZSBzZXJ2ZXIgcmVzcG9uc2Ugd2FzOiBzZXJ2ZXJSZXNwb25zZQkFAAAACgYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCvoAAAAGCgAAAA9mYWlsZWRSZWNpcGllbnQEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgwAAAAGc2VjcmV0CAEBCQ0AAAABDQAAAAsAAAAICAEAAAAGDgAAAANvbmUKCw==", TargetFrameworkMoniker.netfx461) } };
var smtpFailedRecipientsException = new SmtpFailedRecipientsException("message", new SmtpFailedRecipientException[] { smtpFailedRecipientException });
- yield return new object[] { PopulateException(smtpFailedRecipientsException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLk5ldC5NYWlsLlNtdHBGYWlsZWRSZWNpcGllbnRzRXhjZXB0aW9uDwAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMGU3RhdHVzD2ZhaWxlZFJlY2lwaWVudA9pbm5lckV4Y2VwdGlvbnMBAQMEAQEBAAEAAQcAAQQpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwsU3lzdGVtLk5ldC5NYWlsLlNtdHBGYWlsZWRSZWNpcGllbnRFeGNlcHRpb24CAAAACAgCCC5TeXN0ZW0uTmV0Lk1haWwuU210cEZhaWxlZFJlY2lwaWVudEV4Y2VwdGlvbltdAgAAAAIAAAAGAwAAAC1TeXN0ZW0uTmV0Lk1haWwuU210cEZhaWxlZFJlY2lwaWVudHNFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCv////8GCwAAAA9mYWlsZWRSZWNpcGllbnQJDAAAAAQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkNAAAAAgAAAAIAAAAFBgAAACxTeXN0ZW0uTmV0Lk1haWwuU210cEZhaWxlZFJlY2lwaWVudEV4Y2VwdGlvbg4AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzBlN0YXR1cw9mYWlsZWRSZWNpcGllbnQBAQMDAQEBAAEAAQcAASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAIAAAAGDgAAACxTeXN0ZW0uTmV0Lk1haWwuU210cEZhaWxlZFJlY2lwaWVudEV4Y2VwdGlvbgYPAAAAMkNvbXBsZXRlZC4gVGhlIHNlcnZlciByZXNwb25zZSB3YXM6IHNlcnZlclJlc3BvbnNlCRAAAAAKCQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAK+gAAAAkLAAAABwwAAAAAAQAAAAEAAAAELFN5c3RlbS5OZXQuTWFpbC5TbXRwRmFpbGVkUmVjaXBpZW50RXhjZXB0aW9uAgAAAAkGAAAABA0AAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhcAAAAGc2VjcmV0CAEBCRgAAAABEAAAAAUAAAAJGQAAAAIAAAACAAAAARgAAAANAAAACAgBAAAABhoAAAADb25lCgEZAAAADQAAAAkXAAAACAEBCRwAAAABHAAAAA0AAAAICAEAAAAJGgAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLk5ldC5NYWlsLlNtdHBGYWlsZWRSZWNpcGllbnRzRXhjZXB0aW9uDwAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMGU3RhdHVzD2ZhaWxlZFJlY2lwaWVudA9pbm5lckV4Y2VwdGlvbnMBAQMEAQEBAAEAAQcAAQQpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwsU3lzdGVtLk5ldC5NYWlsLlNtdHBGYWlsZWRSZWNpcGllbnRFeGNlcHRpb24CAAAACAgCCC5TeXN0ZW0uTmV0Lk1haWwuU210cEZhaWxlZFJlY2lwaWVudEV4Y2VwdGlvbltdAgAAAAIAAAAGAwAAAC1TeXN0ZW0uTmV0Lk1haWwuU210cEZhaWxlZFJlY2lwaWVudHNFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCv////8GCwAAAA9mYWlsZWRSZWNpcGllbnQJDAAAAAQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkNAAAAAgAAAAIAAAAFBgAAACxTeXN0ZW0uTmV0Lk1haWwuU210cEZhaWxlZFJlY2lwaWVudEV4Y2VwdGlvbg4AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzBlN0YXR1cw9mYWlsZWRSZWNpcGllbnQBAQMDAQEBAAEAAQcAASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAIAAAAGDgAAACxTeXN0ZW0uTmV0Lk1haWwuU210cEZhaWxlZFJlY2lwaWVudEV4Y2VwdGlvbgYPAAAAMkNvbXBsZXRlZC4gVGhlIHNlcnZlciByZXNwb25zZSB3YXM6IHNlcnZlclJlc3BvbnNlCRAAAAAKCQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAK+gAAAAkLAAAABwwAAAAAAQAAAAEAAAAELFN5c3RlbS5OZXQuTWFpbC5TbXRwRmFpbGVkUmVjaXBpZW50RXhjZXB0aW9uAgAAAAkGAAAABA0AAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhcAAAAGc2VjcmV0CAEBCRgAAAABEAAAAAUAAAAJGQAAAAIAAAACAAAAARgAAAANAAAACAgBAAAABhoAAAADb25lCgEZAAAADQAAAAkXAAAACAEBCRwAAAABHAAAAA0AAAAICAEAAAAJGgAAAAoL" } };
+ yield return new object[] { PopulateException(smtpFailedRecipientsException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLk5ldC5NYWlsLlNtdHBGYWlsZWRSZWNpcGllbnRzRXhjZXB0aW9uDwAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMGU3RhdHVzD2ZhaWxlZFJlY2lwaWVudA9pbm5lckV4Y2VwdGlvbnMBAQMEAQEBAAEAAQcAAQQpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwsU3lzdGVtLk5ldC5NYWlsLlNtdHBGYWlsZWRSZWNpcGllbnRFeGNlcHRpb24CAAAACAgCCC5TeXN0ZW0uTmV0Lk1haWwuU210cEZhaWxlZFJlY2lwaWVudEV4Y2VwdGlvbltdAgAAAAIAAAAGAwAAAC1TeXN0ZW0uTmV0Lk1haWwuU210cEZhaWxlZFJlY2lwaWVudHNFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCv////8GCwAAAA9mYWlsZWRSZWNpcGllbnQJDAAAAAQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkNAAAAAgAAAAIAAAAFBgAAACxTeXN0ZW0uTmV0Lk1haWwuU210cEZhaWxlZFJlY2lwaWVudEV4Y2VwdGlvbg4AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzBlN0YXR1cw9mYWlsZWRSZWNpcGllbnQBAQMDAQEBAAEAAQcAASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAIAAAAGDgAAACxTeXN0ZW0uTmV0Lk1haWwuU210cEZhaWxlZFJlY2lwaWVudEV4Y2VwdGlvbgYPAAAAMkNvbXBsZXRlZC4gVGhlIHNlcnZlciByZXNwb25zZSB3YXM6IHNlcnZlclJlc3BvbnNlCRAAAAAKCQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAK+gAAAAkLAAAABwwAAAAAAQAAAAEAAAAELFN5c3RlbS5OZXQuTWFpbC5TbXRwRmFpbGVkUmVjaXBpZW50RXhjZXB0aW9uAgAAAAkGAAAABA0AAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhcAAAAGc2VjcmV0CAEBCRgAAAABEAAAAAUAAAAJGQAAAAIAAAACAAAAARgAAAANAAAACAgBAAAABhoAAAADb25lCgEZAAAADQAAAAkXAAAACAEBCRwAAAABHAAAAA0AAAAICAEAAAAJGgAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLk5ldC5NYWlsLlNtdHBGYWlsZWRSZWNpcGllbnRzRXhjZXB0aW9uDwAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMGU3RhdHVzD2ZhaWxlZFJlY2lwaWVudA9pbm5lckV4Y2VwdGlvbnMBAQMEAQEBAAEAAQcAAQQpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwsU3lzdGVtLk5ldC5NYWlsLlNtdHBGYWlsZWRSZWNpcGllbnRFeGNlcHRpb24CAAAACAgCCC5TeXN0ZW0uTmV0Lk1haWwuU210cEZhaWxlZFJlY2lwaWVudEV4Y2VwdGlvbltdAgAAAAIAAAAGAwAAAC1TeXN0ZW0uTmV0Lk1haWwuU210cEZhaWxlZFJlY2lwaWVudHNFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCv////8GCwAAAA9mYWlsZWRSZWNpcGllbnQJDAAAAAQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkNAAAAAgAAAAIAAAAFBgAAACxTeXN0ZW0uTmV0Lk1haWwuU210cEZhaWxlZFJlY2lwaWVudEV4Y2VwdGlvbg4AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzBlN0YXR1cw9mYWlsZWRSZWNpcGllbnQBAQMDAQEBAAEAAQcAASlTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAIAAAAGDgAAACxTeXN0ZW0uTmV0Lk1haWwuU210cEZhaWxlZFJlY2lwaWVudEV4Y2VwdGlvbgYPAAAAMkNvbXBsZXRlZC4gVGhlIHNlcnZlciByZXNwb25zZSB3YXM6IHNlcnZlclJlc3BvbnNlCRAAAAAKCQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAK+gAAAAkLAAAABwwAAAAAAQAAAAEAAAAELFN5c3RlbS5OZXQuTWFpbC5TbXRwRmFpbGVkUmVjaXBpZW50RXhjZXB0aW9uAgAAAAkGAAAABA0AAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhcAAAAGc2VjcmV0CAEBCRgAAAABEAAAAAUAAAAJGQAAAAIAAAACAAAAARgAAAANAAAACAgBAAAABhoAAAADb25lCgEZAAAADQAAAAkXAAAACAEBCRwAAAABHAAAAA0AAAAICAEAAAAJGgAAAAoL", TargetFrameworkMoniker.netfx461) } };
var socketException = new SocketException();
- yield return new object[] { PopulateException(socketException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAiU3lzdGVtLk5ldC5Tb2NrZXRzLlNvY2tldEV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzD05hdGl2ZUVycm9yQ29kZQEBAwMBAQEAAQABBwApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAggCAAAABgMAAAAiU3lzdGVtLk5ldC5Tb2NrZXRzLlNvY2tldEV4Y2VwdGlvbgYEAAAAJFRoZSBvcGVyYXRpb24gY29tcGxldGVkIHN1Y2Nlc3NmdWxseQkFAAAACgYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgAAAAAEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAiU3lzdGVtLk5ldC5Tb2NrZXRzLlNvY2tldEV4Y2VwdGlvbg0AAAAPTmF0aXZlRXJyb3JDb2RlCUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwABAQMDAQEBAAEAAQcIKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAAAgAAAAYDAAAAIlN5c3RlbS5OZXQuU29ja2V0cy5Tb2NrZXRFeGNlcHRpb24GBAAAAClUaGUgc3lzdGVtIGNhbm5vdCBmaW5kIHRoZSBmaWxlIHNwZWNpZmllZAkFAAAACgYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGCwAAAAZzZWNyZXQIAQEJDAAAAAEMAAAACgAAAAgIAQAAAAYNAAAAA29uZQoL" } };
+ yield return new object[] { PopulateException(socketException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAiU3lzdGVtLk5ldC5Tb2NrZXRzLlNvY2tldEV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzD05hdGl2ZUVycm9yQ29kZQEBAwMBAQEAAQABBwApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAggCAAAABgMAAAAiU3lzdGVtLk5ldC5Tb2NrZXRzLlNvY2tldEV4Y2VwdGlvbgYEAAAAJFRoZSBvcGVyYXRpb24gY29tcGxldGVkIHN1Y2Nlc3NmdWxseQkFAAAACgYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgAAAAAEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBgsAAAAGc2VjcmV0CAEBCQwAAAABDAAAAAoAAAAICAEAAAAGDQAAAANvbmUKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAiU3lzdGVtLk5ldC5Tb2NrZXRzLlNvY2tldEV4Y2VwdGlvbg0AAAAPTmF0aXZlRXJyb3JDb2RlCUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwABAQMDAQEBAAEAAQcIKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAAAgAAAAYDAAAAIlN5c3RlbS5OZXQuU29ja2V0cy5Tb2NrZXRFeGNlcHRpb24GBAAAAClUaGUgc3lzdGVtIGNhbm5vdCBmaW5kIHRoZSBmaWxlIHNwZWNpZmllZAkFAAAACgYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGCwAAAAZzZWNyZXQIAQEJDAAAAAEMAAAACgAAAAgIAQAAAAYNAAAAA29uZQoL", TargetFrameworkMoniker.netfx461) } };
var sqlAlreadyFilledException = new SqlAlreadyFilledException("message", exception);
- yield return new object[] { PopulateException(sqlAlreadyFilledException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAC5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxBbHJlYWR5RmlsbGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAC5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxBbHJlYWR5RmlsbGVkRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAC5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxBbHJlYWR5RmlsbGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAC5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxBbHJlYWR5RmlsbGVkRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=" } };
+ yield return new object[] { PopulateException(sqlAlreadyFilledException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAC5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxBbHJlYWR5RmlsbGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAC5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxBbHJlYWR5RmlsbGVkRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAC5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxBbHJlYWR5RmlsbGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAC5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxBbHJlYWR5RmlsbGVkRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netfx461) } };
if (!PlatformDetection.IsUap)
{
@@ -679,154 +671,154 @@ namespace System.Runtime.Serialization.Formatters.Tests
.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(string), typeof(SqlErrorCollection), typeof(Exception), typeof(Guid) }, null)
.Invoke(new object[] { "message", sqlErrorCollection, exception, Guid.Parse("082FE40E-F683-402D-89C8-2E7486078620") });
- yield return new object[] { PopulateException(sqlException, setHResult: false), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0ZW0uRGF0YS5TcWxDbGllbnQuU3FsRXhjZXB0aW9uDgAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMGRXJyb3JzEkNsaWVudENvbm5lY3Rpb25JZAEBAwMBAQEAAQABBwIDKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAILU3lzdGVtLkd1aWQCAAAABgMAAAAiU3lzdGVtLkRhdGEuU3FsQ2xpZW50LlNxbEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAoEGROABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgT1////C1N5c3RlbS5HdWlkCwAAAAJfYQJfYgJfYwJfZAJfZQJfZgJfZwJfaAJfaQJfagJfawAAAAAAAAAAAAAACAcHAgICAgICAgIO5C8Ig/YtQInILnSGB4YgBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQwAAAADAAAAAwAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBg0AAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ8AAAAJEAAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQMAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYVAAAABnNlY3JldAgBAQkWAAAAAQ8AAAAFAAAACRcAAAACAAAAAgAAAAEQAAAABgAAAAkNAAAABhkAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARYAAAAMAAAACAgBAAAABhoAAAADb25lCRsAAAABFwAAAAwAAAAJFQAAAAgBAQkdAAAAARsAAAAMAAAABh4AAAAKU3FsRXJyb3IgMQYfAAAAJVN5c3RlbS5EYXRhLlNxbENsaWVudC5TcWxFcnJvcjogZXJyb3IKAR0AAAAMAAAACAgBAAAACRoAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0ZW0uRGF0YS5TcWxDbGllbnQuU3FsRXhjZXB0aW9uDgAAAAZFcnJvcnMSQ2xpZW50Q29ubmVjdGlvbklkCUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwQDAQEDAwEBAQABAAEHKFN5c3RlbS5EYXRhLlNxbENsaWVudC5TcWxFcnJvckNvbGxlY3Rpb24CAAAAC1N5c3RlbS5HdWlkKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAACQMAAAAE/P///wtTeXN0ZW0uR3VpZAsAAAACX2ECX2ICX2MCX2QCX2UCX2YCX2cCX2gCX2kCX2oCX2sAAAAAAAAAAAAAAAgHBwICAgICAgICDuQvCIP2LUCJyC50hgeGIAYFAAAAIlN5c3RlbS5EYXRhLlNxbENsaWVudC5TcWxFeGNlcHRpb24GBgAAAAdtZXNzYWdlCQcAAAAJCAAAAAYJAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYLAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAKBBkTgAYMAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgUDAAAAKFN5c3RlbS5EYXRhLlNxbENsaWVudC5TcWxFcnJvckNvbGxlY3Rpb24BAAAABmVycm9ycwMcU3lzdGVtLkNvbGxlY3Rpb25zLkFycmF5TGlzdAIAAAAJDQAAAAQHAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkOAAAAAgAAAAIAAAAECAAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYPAAAAEFN5c3RlbS5FeGNlcHRpb24JBgAAAAkRAAAACRIAAAAJCQAAAAkKAAAACQsAAAAAAAAACugDAAAJDAAAAAoEDQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkXAAAAAQAAAAEAAAAEDgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGGAAAAAZzZWNyZXQIAQEJGQAAAAERAAAABwAAAAkaAAAAAgAAAAIAAAABEgAAAAgAAAAJDwAAAAYcAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKChAXAAAABAAAAAkdAAAADQMBGQAAAA4AAAAICAEAAAAGHgAAAANvbmUKARoAAAAOAAAACRgAAAAIAQEJIAAAAAUdAAAAHlN5c3RlbS5EYXRhLlNxbENsaWVudC5TcWxFcnJvcgkAAAAGc291cmNlBm51bWJlcgVzdGF0ZQplcnJvckNsYXNzBnNlcnZlcgdtZXNzYWdlCXByb2NlZHVyZQpsaW5lTnVtYmVyDndpbjMyRXJyb3JDb2RlAQAAAAEBAQAACAICCAgCAAAABiEAAAAcLk5ldCBTcWxDbGllbnQgRGF0YSBQcm92aWRlcgEAAAACAwYiAAAACWxvY2FsaG9zdAYjAAAABWVycm9yBiQAAAAJcHJvY2VkdXJlAQAAAAIAAAABIAAAAA4AAAAICAEAAAAJHgAAAAoL" } };
+ yield return new object[] { PopulateException(sqlException, setHResult: false), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0ZW0uRGF0YS5TcWxDbGllbnQuU3FsRXhjZXB0aW9uDgAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMGRXJyb3JzEkNsaWVudENvbm5lY3Rpb25JZAEBAwMBAQEAAQABBwIDKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAILU3lzdGVtLkd1aWQCAAAABgMAAAAiU3lzdGVtLkRhdGEuU3FsQ2xpZW50LlNxbEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAoEGROABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgT1////C1N5c3RlbS5HdWlkCwAAAAJfYQJfYgJfYwJfZAJfZQJfZgJfZwJfaAJfaQJfagJfawAAAAAAAAAAAAAACAcHAgICAgICAgIO5C8Ig/YtQInILnSGB4YgBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQwAAAADAAAAAwAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBg0AAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ8AAAAJEAAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQMAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYVAAAABnNlY3JldAgBAQkWAAAAAQ8AAAAFAAAACRcAAAACAAAAAgAAAAEQAAAABgAAAAkNAAAABhkAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARYAAAAMAAAACAgBAAAABhoAAAADb25lCRsAAAABFwAAAAwAAAAJFQAAAAgBAQkdAAAAARsAAAAMAAAABh4AAAAKU3FsRXJyb3IgMQYfAAAAJVN5c3RlbS5EYXRhLlNxbENsaWVudC5TcWxFcnJvcjogZXJyb3IKAR0AAAAMAAAACAgBAAAACRoAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0ZW0uRGF0YS5TcWxDbGllbnQuU3FsRXhjZXB0aW9uDgAAAAZFcnJvcnMSQ2xpZW50Q29ubmVjdGlvbklkCUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwQDAQEDAwEBAQABAAEHKFN5c3RlbS5EYXRhLlNxbENsaWVudC5TcWxFcnJvckNvbGxlY3Rpb24CAAAAC1N5c3RlbS5HdWlkKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAACQMAAAAE/P///wtTeXN0ZW0uR3VpZAsAAAACX2ECX2ICX2MCX2QCX2UCX2YCX2cCX2gCX2kCX2oCX2sAAAAAAAAAAAAAAAgHBwICAgICAgICDuQvCIP2LUCJyC50hgeGIAYFAAAAIlN5c3RlbS5EYXRhLlNxbENsaWVudC5TcWxFeGNlcHRpb24GBgAAAAdtZXNzYWdlCQcAAAAJCAAAAAYJAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCgAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYLAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAKBBkTgAYMAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgUDAAAAKFN5c3RlbS5EYXRhLlNxbENsaWVudC5TcWxFcnJvckNvbGxlY3Rpb24BAAAABmVycm9ycwMcU3lzdGVtLkNvbGxlY3Rpb25zLkFycmF5TGlzdAIAAAAJDQAAAAQHAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkOAAAAAgAAAAIAAAAECAAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYPAAAAEFN5c3RlbS5FeGNlcHRpb24JBgAAAAkRAAAACRIAAAAJCQAAAAkKAAAACQsAAAAAAAAACugDAAAJDAAAAAoEDQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkXAAAAAQAAAAEAAAAEDgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGGAAAAAZzZWNyZXQIAQEJGQAAAAERAAAABwAAAAkaAAAAAgAAAAIAAAABEgAAAAgAAAAJDwAAAAYcAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKChAXAAAABAAAAAkdAAAADQMBGQAAAA4AAAAICAEAAAAGHgAAAANvbmUKARoAAAAOAAAACRgAAAAIAQEJIAAAAAUdAAAAHlN5c3RlbS5EYXRhLlNxbENsaWVudC5TcWxFcnJvcgkAAAAGc291cmNlBm51bWJlcgVzdGF0ZQplcnJvckNsYXNzBnNlcnZlcgdtZXNzYWdlCXByb2NlZHVyZQpsaW5lTnVtYmVyDndpbjMyRXJyb3JDb2RlAQAAAAEBAQAACAICCAgCAAAABiEAAAAcLk5ldCBTcWxDbGllbnQgRGF0YSBQcm92aWRlcgEAAAACAwYiAAAACWxvY2FsaG9zdAYjAAAABWVycm9yBiQAAAAJcHJvY2VkdXJlAQAAAAIAAAABIAAAAA4AAAAICAEAAAAJHgAAAAoL", TargetFrameworkMoniker.netfx461) } };
}
var sqlNotFilledException = new SqlNotFilledException("message", exception);
- yield return new object[] { PopulateException(sqlNotFilledException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACpTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxOb3RGaWxsZWRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAKlN5c3RlbS5EYXRhLlNxbFR5cGVzLlNxbE5vdEZpbGxlZEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACpTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxOb3RGaWxsZWRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAKlN5c3RlbS5EYXRhLlNxbFR5cGVzLlNxbE5vdEZpbGxlZEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL" } };
+ yield return new object[] { PopulateException(sqlNotFilledException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACpTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxOb3RGaWxsZWRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAKlN5c3RlbS5EYXRhLlNxbFR5cGVzLlNxbE5vdEZpbGxlZEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACpTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxOb3RGaWxsZWRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAKlN5c3RlbS5EYXRhLlNxbFR5cGVzLlNxbE5vdEZpbGxlZEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netfx461) } };
var sqlNullValueException = new SqlNullValueException("message", exception);
- yield return new object[] { PopulateException(sqlNullValueException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACpTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxOdWxsVmFsdWVFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAKlN5c3RlbS5EYXRhLlNxbFR5cGVzLlNxbE51bGxWYWx1ZUV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACpTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxOdWxsVmFsdWVFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAKlN5c3RlbS5EYXRhLlNxbFR5cGVzLlNxbE51bGxWYWx1ZUV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL" } };
+ yield return new object[] { PopulateException(sqlNullValueException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACpTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxOdWxsVmFsdWVFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAKlN5c3RlbS5EYXRhLlNxbFR5cGVzLlNxbE51bGxWYWx1ZUV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACpTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxOdWxsVmFsdWVFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAKlN5c3RlbS5EYXRhLlNxbFR5cGVzLlNxbE51bGxWYWx1ZUV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netfx461) } };
var sqlTruncateException = new SqlTruncateException("message", exception);
- yield return new object[] { PopulateException(sqlTruncateException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAClTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxUcnVuY2F0ZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAApU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsVHJ1bmNhdGVFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAClTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxUcnVuY2F0ZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAApU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsVHJ1bmNhdGVFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==" } };
+ yield return new object[] { PopulateException(sqlTruncateException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAClTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxUcnVuY2F0ZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAApU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsVHJ1bmNhdGVFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAClTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxUcnVuY2F0ZUV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAApU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsVHJ1bmNhdGVFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var sqlTypeException = new SqlTypeException("message", exception);
- yield return new object[] { PopulateException(sqlTypeException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACVTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxUeXBlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACVTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxUeXBlRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACVTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxUeXBlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACVTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxUeXBlRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=" } };
+ yield return new object[] { PopulateException(sqlTypeException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACVTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxUeXBlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACVTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxUeXBlRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACVTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxUeXBlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAACVTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxUeXBlRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var stackOverflowException = new StackOverflowException("message", exception);
- yield return new object[] { PopulateException(stackOverflowException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uU3RhY2tPdmVyZmxvd0V4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAAB1TeXN0ZW0uU3RhY2tPdmVyZmxvd0V4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uU3RhY2tPdmVyZmxvd0V4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAAB1TeXN0ZW0uU3RhY2tPdmVyZmxvd0V4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL" } };
-
+ yield return new object[] { PopulateException(stackOverflowException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uU3RhY2tPdmVyZmxvd0V4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAAB1TeXN0ZW0uU3RhY2tPdmVyZmxvd0V4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uU3RhY2tPdmVyZmxvd0V4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAAB1TeXN0ZW0uU3RhY2tPdmVyZmxvd0V4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netfx461) } };
+
var synchronizationLockException = new SynchronizationLockException("message", exception);
- yield return new object[] { PopulateException(synchronizationLockException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAC1TeXN0ZW0uVGhyZWFkaW5nLlN5bmNocm9uaXphdGlvbkxvY2tFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAtU3lzdGVtLlRocmVhZGluZy5TeW5jaHJvbml6YXRpb25Mb2NrRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAC1TeXN0ZW0uVGhyZWFkaW5nLlN5bmNocm9uaXphdGlvbkxvY2tFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAtU3lzdGVtLlRocmVhZGluZy5TeW5jaHJvbml6YXRpb25Mb2NrRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(synchronizationLockException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAC1TeXN0ZW0uVGhyZWFkaW5nLlN5bmNocm9uaXphdGlvbkxvY2tFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAtU3lzdGVtLlRocmVhZGluZy5TeW5jaHJvbml6YXRpb25Mb2NrRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAC1TeXN0ZW0uVGhyZWFkaW5nLlN5bmNocm9uaXphdGlvbkxvY2tFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAtU3lzdGVtLlRocmVhZGluZy5TeW5jaHJvbml6YXRpb25Mb2NrRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var syntaxErrorException = new SyntaxErrorException("message", exception);
- yield return new object[] { PopulateException(syntaxErrorException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TeW50YXhFcnJvckV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAgU3lzdGVtLkRhdGEuU3ludGF4RXJyb3JFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TeW50YXhFcnJvckV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAgU3lzdGVtLkRhdGEuU3ludGF4RXJyb3JFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==" } };
+ yield return new object[] { PopulateException(syntaxErrorException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TeW50YXhFcnJvckV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAgU3lzdGVtLkRhdGEuU3ludGF4RXJyb3JFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TeW50YXhFcnJvckV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAgU3lzdGVtLkRhdGEuU3ludGF4RXJyb3JFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var systemException = new SystemException("message", exception);
- yield return new object[] { PopulateException(systemException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABZTeXN0ZW0uU3lzdGVtRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAFlN5c3RlbS5TeXN0ZW1FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABZTeXN0ZW0uU3lzdGVtRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAFlN5c3RlbS5TeXN0ZW1FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(systemException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABZTeXN0ZW0uU3lzdGVtRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAFlN5c3RlbS5TeXN0ZW1FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABZTeXN0ZW0uU3lzdGVtRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAFlN5c3RlbS5TeXN0ZW1FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var targetException = new TargetException("message", exception);
- yield return new object[] { PopulateException(targetException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACFTeXN0ZW0uUmVmbGVjdGlvbi5UYXJnZXRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAhU3lzdGVtLlJlZmxlY3Rpb24uVGFyZ2V0RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAACFTeXN0ZW0uUmVmbGVjdGlvbi5UYXJnZXRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAhU3lzdGVtLlJlZmxlY3Rpb24uVGFyZ2V0RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(targetException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACFTeXN0ZW0uUmVmbGVjdGlvbi5UYXJnZXRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAhU3lzdGVtLlJlZmxlY3Rpb24uVGFyZ2V0RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACFTeXN0ZW0uUmVmbGVjdGlvbi5UYXJnZXRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAhU3lzdGVtLlJlZmxlY3Rpb24uVGFyZ2V0RXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var targetInvocationException = new TargetInvocationException("message", exception);
- yield return new object[] { PopulateException(targetInvocationException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACtTeXN0ZW0uUmVmbGVjdGlvbi5UYXJnZXRJbnZvY2F0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAK1N5c3RlbS5SZWZsZWN0aW9uLlRhcmdldEludm9jYXRpb25FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAACtTeXN0ZW0uUmVmbGVjdGlvbi5UYXJnZXRJbnZvY2F0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAK1N5c3RlbS5SZWZsZWN0aW9uLlRhcmdldEludm9jYXRpb25FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(targetInvocationException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACtTeXN0ZW0uUmVmbGVjdGlvbi5UYXJnZXRJbnZvY2F0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAK1N5c3RlbS5SZWZsZWN0aW9uLlRhcmdldEludm9jYXRpb25FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACtTeXN0ZW0uUmVmbGVjdGlvbi5UYXJnZXRJbnZvY2F0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAK1N5c3RlbS5SZWZsZWN0aW9uLlRhcmdldEludm9jYXRpb25FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var targetParameterCountException = new TargetParameterCountException("message", exception);
- yield return new object[] { PopulateException(targetParameterCountException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAC9TeXN0ZW0uUmVmbGVjdGlvbi5UYXJnZXRQYXJhbWV0ZXJDb3VudEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAAC9TeXN0ZW0uUmVmbGVjdGlvbi5UYXJnZXRQYXJhbWV0ZXJDb3VudEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAAC9TeXN0ZW0uUmVmbGVjdGlvbi5UYXJnZXRQYXJhbWV0ZXJDb3VudEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAAC9TeXN0ZW0uUmVmbGVjdGlvbi5UYXJnZXRQYXJhbWV0ZXJDb3VudEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL" } };
+ yield return new object[] { PopulateException(targetParameterCountException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAC9TeXN0ZW0uUmVmbGVjdGlvbi5UYXJnZXRQYXJhbWV0ZXJDb3VudEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAAC9TeXN0ZW0uUmVmbGVjdGlvbi5UYXJnZXRQYXJhbWV0ZXJDb3VudEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAC9TeXN0ZW0uUmVmbGVjdGlvbi5UYXJnZXRQYXJhbWV0ZXJDb3VudEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAAC9TeXN0ZW0uUmVmbGVjdGlvbi5UYXJnZXRQYXJhbWV0ZXJDb3VudEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netfx461) } };
var taskCanceledException = new TaskCanceledException("message", exception);
- yield return new object[] { PopulateException(taskCanceledException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACxTeXN0ZW0uVGhyZWFkaW5nLlRhc2tzLlRhc2tDYW5jZWxlZEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACxTeXN0ZW0uVGhyZWFkaW5nLlRhc2tzLlRhc2tDYW5jZWxlZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAACxTeXN0ZW0uVGhyZWFkaW5nLlRhc2tzLlRhc2tDYW5jZWxlZEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACxTeXN0ZW0uVGhyZWFkaW5nLlRhc2tzLlRhc2tDYW5jZWxlZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL" } };
+ yield return new object[] { PopulateException(taskCanceledException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACxTeXN0ZW0uVGhyZWFkaW5nLlRhc2tzLlRhc2tDYW5jZWxlZEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACxTeXN0ZW0uVGhyZWFkaW5nLlRhc2tzLlRhc2tDYW5jZWxlZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACxTeXN0ZW0uVGhyZWFkaW5nLlRhc2tzLlRhc2tDYW5jZWxlZEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACxTeXN0ZW0uVGhyZWFkaW5nLlRhc2tzLlRhc2tDYW5jZWxlZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netfx461) } };
var taskSchedulerException = new TaskSchedulerException("message", exception);
- yield return new object[] { PopulateException(taskSchedulerException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAC1TeXN0ZW0uVGhyZWFkaW5nLlRhc2tzLlRhc2tTY2hlZHVsZXJFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAtU3lzdGVtLlRocmVhZGluZy5UYXNrcy5UYXNrU2NoZWR1bGVyRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAC1TeXN0ZW0uVGhyZWFkaW5nLlRhc2tzLlRhc2tTY2hlZHVsZXJFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAtU3lzdGVtLlRocmVhZGluZy5UYXNrcy5UYXNrU2NoZWR1bGVyRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(taskSchedulerException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAC1TeXN0ZW0uVGhyZWFkaW5nLlRhc2tzLlRhc2tTY2hlZHVsZXJFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAtU3lzdGVtLlRocmVhZGluZy5UYXNrcy5UYXNrU2NoZWR1bGVyRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAC1TeXN0ZW0uVGhyZWFkaW5nLlRhc2tzLlRhc2tTY2hlZHVsZXJFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAtU3lzdGVtLlRocmVhZGluZy5UYXNrcy5UYXNrU2NoZWR1bGVyRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
if (!PlatformDetection.IsUap)
{
ThreadAbortException threadAbortException = (ThreadAbortException)typeof(ThreadAbortException)
.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { }, null)
.Invoke(new object[] { });
- yield return new object[] { PopulateException(threadAbortException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACVTeXN0ZW0uVGhyZWFkaW5nLlRocmVhZEFib3J0RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAJVN5c3RlbS5UaHJlYWRpbmcuVGhyZWFkQWJvcnRFeGNlcHRpb24GAwAAAA1TeXN0ZW0gZXJyb3IuCQQAAAAKBgUAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYGAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgcAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABggAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQkAAAACAAAAAgAAAAQJAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYKAAAABnNlY3JldAgBAQkLAAAAAQsAAAAJAAAACAgBAAAABgwAAAADb25lCgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAACVTeXN0ZW0uVGhyZWFkaW5nLlRocmVhZEFib3J0RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAJVN5c3RlbS5UaHJlYWRpbmcuVGhyZWFkQWJvcnRFeGNlcHRpb24GAwAAABlUaHJlYWQgd2FzIGJlaW5nIGFib3J0ZWQuCQQAAAAKBgUAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYGAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgcAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABggAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQkAAAACAAAAAgAAAAQJAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYKAAAABnNlY3JldAgBAQkLAAAAAQsAAAAJAAAACAgBAAAABgwAAAADb25lCgs=" } };
+ yield return new object[] { PopulateException(threadAbortException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACVTeXN0ZW0uVGhyZWFkaW5nLlRocmVhZEFib3J0RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAJVN5c3RlbS5UaHJlYWRpbmcuVGhyZWFkQWJvcnRFeGNlcHRpb24GAwAAAA1TeXN0ZW0gZXJyb3IuCQQAAAAKBgUAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYGAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgcAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABggAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQkAAAACAAAAAgAAAAQJAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYKAAAABnNlY3JldAgBAQkLAAAAAQsAAAAJAAAACAgBAAAABgwAAAADb25lCgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACVTeXN0ZW0uVGhyZWFkaW5nLlRocmVhZEFib3J0RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAJVN5c3RlbS5UaHJlYWRpbmcuVGhyZWFkQWJvcnRFeGNlcHRpb24GAwAAABlUaHJlYWQgd2FzIGJlaW5nIGFib3J0ZWQuCQQAAAAKBgUAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYGAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgcAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABggAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQkAAAACAAAAAgAAAAQJAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYKAAAABnNlY3JldAgBAQkLAAAAAQsAAAAJAAAACAgBAAAABgwAAAADb25lCgs=", TargetFrameworkMoniker.netfx461) } };
}
var threadInterruptedException = new ThreadInterruptedException("message", exception);
- yield return new object[] { PopulateException(threadInterruptedException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACtTeXN0ZW0uVGhyZWFkaW5nLlRocmVhZEludGVycnVwdGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAK1N5c3RlbS5UaHJlYWRpbmcuVGhyZWFkSW50ZXJydXB0ZWRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAACtTeXN0ZW0uVGhyZWFkaW5nLlRocmVhZEludGVycnVwdGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAK1N5c3RlbS5UaHJlYWRpbmcuVGhyZWFkSW50ZXJydXB0ZWRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(threadInterruptedException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACtTeXN0ZW0uVGhyZWFkaW5nLlRocmVhZEludGVycnVwdGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAK1N5c3RlbS5UaHJlYWRpbmcuVGhyZWFkSW50ZXJydXB0ZWRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACtTeXN0ZW0uVGhyZWFkaW5nLlRocmVhZEludGVycnVwdGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAK1N5c3RlbS5UaHJlYWRpbmcuVGhyZWFkSW50ZXJydXB0ZWRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
if (!PlatformDetection.IsUap)
{
ThreadStartException threadStartException = (ThreadStartException)typeof(ThreadStartException)
.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(Exception) }, null)
.Invoke(new object[] { exception });
- yield return new object[] { PopulateException(threadStartException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACVTeXN0ZW0uVGhyZWFkaW5nLlRocmVhZFN0YXJ0RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAJVN5c3RlbS5UaHJlYWRpbmcuVGhyZWFkU3RhcnRFeGNlcHRpb24GAwAAABdUaHJlYWQgZmFpbGVkIHRvIHN0YXJ0LgkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uBgwAAAAHbWVzc2FnZQkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAACVTeXN0ZW0uVGhyZWFkaW5nLlRocmVhZFN0YXJ0RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAJVN5c3RlbS5UaHJlYWRpbmcuVGhyZWFkU3RhcnRFeGNlcHRpb24GAwAAABdUaHJlYWQgZmFpbGVkIHRvIHN0YXJ0LgkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uBgwAAAAHbWVzc2FnZQkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(threadStartException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACVTeXN0ZW0uVGhyZWFkaW5nLlRocmVhZFN0YXJ0RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAJVN5c3RlbS5UaHJlYWRpbmcuVGhyZWFkU3RhcnRFeGNlcHRpb24GAwAAABdUaHJlYWQgZmFpbGVkIHRvIHN0YXJ0LgkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uBgwAAAAHbWVzc2FnZQkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACVTeXN0ZW0uVGhyZWFkaW5nLlRocmVhZFN0YXJ0RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAJVN5c3RlbS5UaHJlYWRpbmcuVGhyZWFkU3RhcnRFeGNlcHRpb24GAwAAABdUaHJlYWQgZmFpbGVkIHRvIHN0YXJ0LgkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uBgwAAAAHbWVzc2FnZQkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
}
var threadStateException = new ThreadStateException("message", exception);
- yield return new object[] { PopulateException(threadStateException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACVTeXN0ZW0uVGhyZWFkaW5nLlRocmVhZFN0YXRlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAJVN5c3RlbS5UaHJlYWRpbmcuVGhyZWFkU3RhdGVFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAACVTeXN0ZW0uVGhyZWFkaW5nLlRocmVhZFN0YXRlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAJVN5c3RlbS5UaHJlYWRpbmcuVGhyZWFkU3RhdGVFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(threadStateException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACVTeXN0ZW0uVGhyZWFkaW5nLlRocmVhZFN0YXRlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAJVN5c3RlbS5UaHJlYWRpbmcuVGhyZWFkU3RhdGVFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACVTeXN0ZW0uVGhyZWFkaW5nLlRocmVhZFN0YXRlRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAJVN5c3RlbS5UaHJlYWRpbmcuVGhyZWFkU3RhdGVFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var timeZoneNotFoundException = new TimeZoneNotFoundException("message", exception);
- yield return new object[] { PopulateException(timeZoneNotFoundException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj0zLjUuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uVGltZVpvbmVOb3RGb3VuZEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAgU3lzdGVtLlRpbWVab25lTm90Rm91bmRFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj0zLjUuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uVGltZVpvbmVOb3RGb3VuZEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAgU3lzdGVtLlRpbWVab25lTm90Rm91bmRFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==" } };
+ yield return new object[] { PopulateException(timeZoneNotFoundException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj0zLjUuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uVGltZVpvbmVOb3RGb3VuZEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAgU3lzdGVtLlRpbWVab25lTm90Rm91bmRFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj0zLjUuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uVGltZVpvbmVOb3RGb3VuZEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAgU3lzdGVtLlRpbWVab25lTm90Rm91bmRFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var timeoutException = new TimeoutException("message", exception);
- yield return new object[] { PopulateException(timeoutException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABdTeXN0ZW0uVGltZW91dEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAABdTeXN0ZW0uVGltZW91dEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAABdTeXN0ZW0uVGltZW91dEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAABdTeXN0ZW0uVGltZW91dEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL" } };
+ yield return new object[] { PopulateException(timeoutException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABdTeXN0ZW0uVGltZW91dEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAABdTeXN0ZW0uVGltZW91dEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABdTeXN0ZW0uVGltZW91dEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAABdTeXN0ZW0uVGltZW91dEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netfx461) } };
var typeAccessException = new TypeAccessException("message", exception);
- yield return new object[] { PopulateException(typeAccessException, setHResult: false), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABpTeXN0ZW0uVHlwZUFjY2Vzc0V4Y2VwdGlvbhAAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzEVR5cGVMb2FkQ2xhc3NOYW1lFFR5cGVMb2FkQXNzZW1ibHlOYW1lElR5cGVMb2FkTWVzc2FnZUFyZxJUeXBlTG9hZFJlc291cmNlSUQBAQMDAQEBAAEAAQcBAQEAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIIBgIAAAAaU3lzdGVtLlR5cGVBY2Nlc3NFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAKQxUTgAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgoKCgAAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAABpTeXN0ZW0uVHlwZUFjY2Vzc0V4Y2VwdGlvbhAAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzEVR5cGVMb2FkQ2xhc3NOYW1lFFR5cGVMb2FkQXNzZW1ibHlOYW1lElR5cGVMb2FkTWVzc2FnZUFyZxJUeXBlTG9hZFJlc291cmNlSUQBAQMDAQEBAAEAAQcBAQEAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIIBgIAAAAaU3lzdGVtLlR5cGVBY2Nlc3NFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAKQxUTgAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgoKCgAAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(typeAccessException, setHResult: false), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABpTeXN0ZW0uVHlwZUFjY2Vzc0V4Y2VwdGlvbhAAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzEVR5cGVMb2FkQ2xhc3NOYW1lFFR5cGVMb2FkQXNzZW1ibHlOYW1lElR5cGVMb2FkTWVzc2FnZUFyZxJUeXBlTG9hZFJlc291cmNlSUQBAQMDAQEBAAEAAQcBAQEAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIIBgIAAAAaU3lzdGVtLlR5cGVBY2Nlc3NFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAKQxUTgAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgoKCgAAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABpTeXN0ZW0uVHlwZUFjY2Vzc0V4Y2VwdGlvbhAAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzEVR5cGVMb2FkQ2xhc3NOYW1lFFR5cGVMb2FkQXNzZW1ibHlOYW1lElR5cGVMb2FkTWVzc2FnZUFyZxJUeXBlTG9hZFJlc291cmNlSUQBAQMDAQEBAAEAAQcBAQEAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIIBgIAAAAaU3lzdGVtLlR5cGVBY2Nlc3NFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAKQxUTgAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgoKCgAAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var typeInitializationException = new TypeInitializationException("System.String", exception);
- yield return new object[] { PopulateException(typeInitializationException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uVHlwZUluaXRpYWxpemF0aW9uRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMIVHlwZU5hbWUBAQMDAQEBAAEAAQcBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACJTeXN0ZW0uVHlwZUluaXRpYWxpemF0aW9uRXhjZXB0aW9uBgMAAAA8VGhlIHR5cGUgaW5pdGlhbGl6ZXIgZm9yICdTeXN0ZW0uU3RyaW5nJyB0aHJldyBhbiBleGNlcHRpb24uCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYKAAAADVN5c3RlbS5TdHJpbmcEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uBg0AAAAHbWVzc2FnZQkOAAAACQ8AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABAAAAAkWAAAAAgAAAAIAAAABDwAAAAUAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uVHlwZUluaXRpYWxpemF0aW9uRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMIVHlwZU5hbWUBAQMDAQEBAAEAAQcBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACJTeXN0ZW0uVHlwZUluaXRpYWxpemF0aW9uRXhjZXB0aW9uBgMAAAA8VGhlIHR5cGUgaW5pdGlhbGl6ZXIgZm9yICdTeXN0ZW0uU3RyaW5nJyB0aHJldyBhbiBleGNlcHRpb24uCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYKAAAADVN5c3RlbS5TdHJpbmcEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uBg0AAAAHbWVzc2FnZQkOAAAACQ8AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABAAAAAkWAAAAAgAAAAIAAAABDwAAAAUAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==" } };
+ yield return new object[] { PopulateException(typeInitializationException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uVHlwZUluaXRpYWxpemF0aW9uRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMIVHlwZU5hbWUBAQMDAQEBAAEAAQcBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACJTeXN0ZW0uVHlwZUluaXRpYWxpemF0aW9uRXhjZXB0aW9uBgMAAAA8VGhlIHR5cGUgaW5pdGlhbGl6ZXIgZm9yICdTeXN0ZW0uU3RyaW5nJyB0aHJldyBhbiBleGNlcHRpb24uCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYKAAAADVN5c3RlbS5TdHJpbmcEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uBg0AAAAHbWVzc2FnZQkOAAAACQ8AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABAAAAAkWAAAAAgAAAAIAAAABDwAAAAUAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uVHlwZUluaXRpYWxpemF0aW9uRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMIVHlwZU5hbWUBAQMDAQEBAAEAAQcBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAACJTeXN0ZW0uVHlwZUluaXRpYWxpemF0aW9uRXhjZXB0aW9uBgMAAAA8VGhlIHR5cGUgaW5pdGlhbGl6ZXIgZm9yICdTeXN0ZW0uU3RyaW5nJyB0aHJldyBhbiBleGNlcHRpb24uCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgYKAAAADVN5c3RlbS5TdHJpbmcEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uBg0AAAAHbWVzc2FnZQkOAAAACQ8AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABAAAAAkWAAAAAgAAAAIAAAABDwAAAAUAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var typeLoadException = new TypeLoadException("message", exception);
- yield return new object[] { PopulateException(typeLoadException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uVHlwZUxvYWRFeGNlcHRpb24QAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cxFUeXBlTG9hZENsYXNzTmFtZRRUeXBlTG9hZEFzc2VtYmx5TmFtZRJUeXBlTG9hZE1lc3NhZ2VBcmcSVHlwZUxvYWRSZXNvdXJjZUlEAQEDAwEBAQABAAEHAQEBAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAYCAAAAGFN5c3RlbS5UeXBlTG9hZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgoKAAAAAAQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uVHlwZUxvYWRFeGNlcHRpb24QAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cxFUeXBlTG9hZENsYXNzTmFtZRRUeXBlTG9hZEFzc2VtYmx5TmFtZRJUeXBlTG9hZE1lc3NhZ2VBcmcSVHlwZUxvYWRSZXNvdXJjZUlEAQEDAwEBAQABAAEHAQEBAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAYCAAAAGFN5c3RlbS5UeXBlTG9hZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgoKAAAAAAQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(typeLoadException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uVHlwZUxvYWRFeGNlcHRpb24QAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cxFUeXBlTG9hZENsYXNzTmFtZRRUeXBlTG9hZEFzc2VtYmx5TmFtZRJUeXBlTG9hZE1lc3NhZ2VBcmcSVHlwZUxvYWRSZXNvdXJjZUlEAQEDAwEBAQABAAEHAQEBAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAYCAAAAGFN5c3RlbS5UeXBlTG9hZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgoKAAAAAAQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uVHlwZUxvYWRFeGNlcHRpb24QAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cxFUeXBlTG9hZENsYXNzTmFtZRRUeXBlTG9hZEFzc2VtYmx5TmFtZRJUeXBlTG9hZE1lc3NhZ2VBcmcSVHlwZUxvYWRSZXNvdXJjZUlEAQEDAwEBAQABAAEHAQEBAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAYCAAAAGFN5c3RlbS5UeXBlTG9hZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCgoKAAAAAAQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var typeUnloadedException = new TypeUnloadedException("message", exception);
- yield return new object[] { PopulateException(typeUnloadedException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uVHlwZVVubG9hZGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAHFN5c3RlbS5UeXBlVW5sb2FkZWRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uVHlwZVVubG9hZGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAHFN5c3RlbS5UeXBlVW5sb2FkZWRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(typeUnloadedException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uVHlwZVVubG9hZGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAHFN5c3RlbS5UeXBlVW5sb2FkZWRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uVHlwZVVubG9hZGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAHFN5c3RlbS5UeXBlVW5sb2FkZWRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var unauthorizedAccessException = new UnauthorizedAccessException("message", exception);
- yield return new object[] { PopulateException(unauthorizedAccessException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uVW5hdXRob3JpemVkQWNjZXNzRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAIlN5c3RlbS5VbmF1dGhvcml6ZWRBY2Nlc3NFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uVW5hdXRob3JpemVkQWNjZXNzRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAIlN5c3RlbS5VbmF1dGhvcml6ZWRBY2Nlc3NFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(unauthorizedAccessException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uVW5hdXRob3JpemVkQWNjZXNzRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAIlN5c3RlbS5VbmF1dGhvcml6ZWRBY2Nlc3NFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uVW5hdXRob3JpemVkQWNjZXNzRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAIlN5c3RlbS5VbmF1dGhvcml6ZWRBY2Nlc3NFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var uriFormatException = new UriFormatException("message", exception);
- yield return new object[] { PopulateException(uriFormatException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAZU3lzdGVtLlVyaUZvcm1hdEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAZU3lzdGVtLlVyaUZvcm1hdEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAZU3lzdGVtLlVyaUZvcm1hdEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAZU3lzdGVtLlVyaUZvcm1hdEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL" } };
+ yield return new object[] { PopulateException(uriFormatException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAZU3lzdGVtLlVyaUZvcm1hdEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAZU3lzdGVtLlVyaUZvcm1hdEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAZU3lzdGVtLlVyaUZvcm1hdEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAZU3lzdGVtLlVyaUZvcm1hdEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netfx461) } };
var verificationException = new VerificationException("message", exception);
- yield return new object[] { PopulateException(verificationException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACVTeXN0ZW0uU2VjdXJpdHkuVmVyaWZpY2F0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAJVN5c3RlbS5TZWN1cml0eS5WZXJpZmljYXRpb25FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAACVTeXN0ZW0uU2VjdXJpdHkuVmVyaWZpY2F0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAJVN5c3RlbS5TZWN1cml0eS5WZXJpZmljYXRpb25FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(verificationException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACVTeXN0ZW0uU2VjdXJpdHkuVmVyaWZpY2F0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAJVN5c3RlbS5TZWN1cml0eS5WZXJpZmljYXRpb25FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACVTeXN0ZW0uU2VjdXJpdHkuVmVyaWZpY2F0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAJVN5c3RlbS5TZWN1cml0eS5WZXJpZmljYXRpb25FeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var versionNotFoundException = new VersionNotFoundException("message", exception);
- yield return new object[] { PopulateException(versionNotFoundException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACRTeXN0ZW0uRGF0YS5WZXJzaW9uTm90Rm91bmRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAJFN5c3RlbS5EYXRhLlZlcnNpb25Ob3RGb3VuZEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACRTeXN0ZW0uRGF0YS5WZXJzaW9uTm90Rm91bmRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAJFN5c3RlbS5EYXRhLlZlcnNpb25Ob3RGb3VuZEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL" } };
+ yield return new object[] { PopulateException(versionNotFoundException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACRTeXN0ZW0uRGF0YS5WZXJzaW9uTm90Rm91bmRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAJFN5c3RlbS5EYXRhLlZlcnNpb25Ob3RGb3VuZEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACRTeXN0ZW0uRGF0YS5WZXJzaW9uTm90Rm91bmRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAJFN5c3RlbS5EYXRhLlZlcnNpb25Ob3RGb3VuZEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netfx461) } };
var waitHandleCannotBeOpenedException = new WaitHandleCannotBeOpenedException("message", exception);
- yield return new object[] { PopulateException(waitHandleCannotBeOpenedException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAADJTeXN0ZW0uVGhyZWFkaW5nLldhaXRIYW5kbGVDYW5ub3RCZU9wZW5lZEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAADJTeXN0ZW0uVGhyZWFkaW5nLldhaXRIYW5kbGVDYW5ub3RCZU9wZW5lZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAADJTeXN0ZW0uVGhyZWFkaW5nLldhaXRIYW5kbGVDYW5ub3RCZU9wZW5lZEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAADJTeXN0ZW0uVGhyZWFkaW5nLldhaXRIYW5kbGVDYW5ub3RCZU9wZW5lZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL" } };
+ yield return new object[] { PopulateException(waitHandleCannotBeOpenedException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADJTeXN0ZW0uVGhyZWFkaW5nLldhaXRIYW5kbGVDYW5ub3RCZU9wZW5lZEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAADJTeXN0ZW0uVGhyZWFkaW5nLldhaXRIYW5kbGVDYW5ub3RCZU9wZW5lZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADJTeXN0ZW0uVGhyZWFkaW5nLldhaXRIYW5kbGVDYW5ub3RCZU9wZW5lZEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGAgAAADJTeXN0ZW0uVGhyZWFkaW5nLldhaXRIYW5kbGVDYW5ub3RCZU9wZW5lZEV4Y2VwdGlvbgYDAAAAB21lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQoAAAACAAAAAgAAAAQFAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgsAAAAQU3lzdGVtLkV4Y2VwdGlvbgkDAAAACQ0AAAAJDgAAAAkGAAAACQcAAAAJCAAAAAAAAAAK6AMAAAkJAAAACgQKAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYTAAAABnNlY3JldAgBAQkUAAAAAQ0AAAAEAAAACRUAAAACAAAAAgAAAAEOAAAABQAAAAkLAAAABhcAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARQAAAAKAAAACAgBAAAABhgAAAADb25lCgEVAAAACgAAAAkTAAAACAEBCRoAAAABGgAAAAoAAAAICAEAAAAJGAAAAAoL", TargetFrameworkMoniker.netfx461) } };
var warningException = new WarningException("message", "helpUrl", "helpTopic");
- yield return new object[] { PopulateException(warningException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLkNvbXBvbmVudE1vZGVsLldhcm5pbmdFeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwdoZWxwVXJsCWhlbHBUb3BpYwEBAwMBAQEAAQABBwEBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAmU3lzdGVtLkNvbXBvbmVudE1vZGVsLldhcm5pbmdFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAKBgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgoAAAAHaGVscFVybAYLAAAACWhlbHBUb3BpYwQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkMAAAAAgAAAAIAAAAEDAAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGDQAAAAZzZWNyZXQIAQEJDgAAAAEOAAAADAAAAAgIAQAAAAYPAAAAA29uZQoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLkNvbXBvbmVudE1vZGVsLldhcm5pbmdFeGNlcHRpb24OAAAAB2hlbHBVcmwJaGVscFRvcGljCUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAHaGVscFVybAYEAAAACWhlbHBUb3BpYwYFAAAAJlN5c3RlbS5Db21wb25lbnRNb2RlbC5XYXJuaW5nRXhjZXB0aW9uBgYAAAAHbWVzc2FnZQkHAAAACgYIAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCQAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYKAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYLAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQHAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkMAAAAAgAAAAIAAAAEDAAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGDQAAAAZzZWNyZXQIAQEJDgAAAAEOAAAADAAAAAgIAQAAAAYPAAAAA29uZQoL" } };
+ yield return new object[] { PopulateException(warningException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLkNvbXBvbmVudE1vZGVsLldhcm5pbmdFeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwdoZWxwVXJsCWhlbHBUb3BpYwEBAwMBAQEAAQABBwEBKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAmU3lzdGVtLkNvbXBvbmVudE1vZGVsLldhcm5pbmdFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAKBgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBgoAAAAHaGVscFVybAYLAAAACWhlbHBUb3BpYwQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkMAAAAAgAAAAIAAAAEDAAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGDQAAAAZzZWNyZXQIAQEJDgAAAAEOAAAADAAAAAgIAQAAAAYPAAAAA29uZQoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLkNvbXBvbmVudE1vZGVsLldhcm5pbmdFeGNlcHRpb24OAAAAB2hlbHBVcmwJaGVscFRvcGljCUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAHaGVscFVybAYEAAAACWhlbHBUb3BpYwYFAAAAJlN5c3RlbS5Db21wb25lbnRNb2RlbC5XYXJuaW5nRXhjZXB0aW9uBgYAAAAHbWVzc2FnZQkHAAAACgYIAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCQAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYKAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYLAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQHAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkMAAAAAgAAAAIAAAAEDAAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGDQAAAAZzZWNyZXQIAQEJDgAAAAEOAAAADAAAAAgIAQAAAAYPAAAAA29uZQoL", TargetFrameworkMoniker.netfx461) } };
var webException = new WebException("message", exception, WebExceptionStatus.Pending, null);
- yield return new object[] { PopulateException(webException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAXU3lzdGVtLk5ldC5XZWJFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAF1N5c3RlbS5OZXQuV2ViRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAXU3lzdGVtLk5ldC5XZWJFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAF1N5c3RlbS5OZXQuV2ViRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=" } };
+ yield return new object[] { PopulateException(webException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAXU3lzdGVtLk5ldC5XZWJFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAF1N5c3RlbS5OZXQuV2ViRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAXU3lzdGVtLk5ldC5XZWJFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAAF1N5c3RlbS5OZXQuV2ViRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var webSocketException = new WebSocketException(WebSocketError.Success, 100, "message", exception);
- yield return new object[] { PopulateException(webSocketException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAoU3lzdGVtLk5ldC5XZWJTb2NrZXRzLldlYlNvY2tldEV4Y2VwdGlvbg4AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzD05hdGl2ZUVycm9yQ29kZRJXZWJTb2NrZXRFcnJvckNvZGUBAQMDAQEBAAEAAQcABClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCCRTeXN0ZW0uTmV0LldlYlNvY2tldHMuV2ViU29ja2V0RXJyb3ICAAAAAgAAAAYDAAAAKFN5c3RlbS5OZXQuV2ViU29ja2V0cy5XZWJTb2NrZXRFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgAAAAAF9f///yRTeXN0ZW0uTmV0LldlYlNvY2tldHMuV2ViU29ja2V0RXJyb3IBAAAAB3ZhbHVlX18ACAIAAAAAAAAABAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQwAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBg0AAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ8AAAAJEAAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQMAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYVAAAABnNlY3JldAgBAQkWAAAAAQ8AAAAFAAAACRcAAAACAAAAAgAAAAEQAAAABgAAAAkNAAAABhkAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARYAAAAMAAAACAgBAAAABhoAAAADb25lCgEXAAAADAAAAAkVAAAACAEBCRwAAAABHAAAAAwAAAAICAEAAAAJGgAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAoU3lzdGVtLk5ldC5XZWJTb2NrZXRzLldlYlNvY2tldEV4Y2VwdGlvbg4AAAASV2ViU29ja2V0RXJyb3JDb2RlD05hdGl2ZUVycm9yQ29kZQlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMEAAEBAwMBAQEAAQABByRTeXN0ZW0uTmV0LldlYlNvY2tldHMuV2ViU29ja2V0RXJyb3ICAAAACClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAX9////JFN5c3RlbS5OZXQuV2ViU29ja2V0cy5XZWJTb2NrZXRFcnJvcgEAAAAHdmFsdWVfXwAIAgAAAAAAAAAAAAAABgQAAAAoU3lzdGVtLk5ldC5XZWJTb2NrZXRzLldlYlNvY2tldEV4Y2VwdGlvbgYFAAAAB21lc3NhZ2UJBgAAAAkHAAAABggAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYJAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgoAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgsAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAYAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQwAAAACAAAAAgAAAAQHAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBg0AAAAQU3lzdGVtLkV4Y2VwdGlvbgkFAAAACQ8AAAAJEAAAAAkIAAAACQkAAAAJCgAAAAAAAAAK6AMAAAkLAAAACgQMAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYVAAAABnNlY3JldAgBAQkWAAAAAQ8AAAAGAAAACRcAAAACAAAAAgAAAAEQAAAABwAAAAkNAAAABhkAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARYAAAAMAAAACAgBAAAABhoAAAADb25lCgEXAAAADAAAAAkVAAAACAEBCRwAAAABHAAAAAwAAAAICAEAAAAJGgAAAAoL" } };
+ yield return new object[] { PopulateException(webSocketException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAoU3lzdGVtLk5ldC5XZWJTb2NrZXRzLldlYlNvY2tldEV4Y2VwdGlvbg4AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzD05hdGl2ZUVycm9yQ29kZRJXZWJTb2NrZXRFcnJvckNvZGUBAQMDAQEBAAEAAQcABClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCCRTeXN0ZW0uTmV0LldlYlNvY2tldHMuV2ViU29ja2V0RXJyb3ICAAAAAgAAAAYDAAAAKFN5c3RlbS5OZXQuV2ViU29ja2V0cy5XZWJTb2NrZXRFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgAAAAAF9f///yRTeXN0ZW0uTmV0LldlYlNvY2tldHMuV2ViU29ja2V0RXJyb3IBAAAAB3ZhbHVlX18ACAIAAAAAAAAABAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQwAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBg0AAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ8AAAAJEAAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQMAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYVAAAABnNlY3JldAgBAQkWAAAAAQ8AAAAFAAAACRcAAAACAAAAAgAAAAEQAAAABgAAAAkNAAAABhkAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARYAAAAMAAAACAgBAAAABhoAAAADb25lCgEXAAAADAAAAAkVAAAACAEBCRwAAAABHAAAAAwAAAAICAEAAAAJGgAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAoU3lzdGVtLk5ldC5XZWJTb2NrZXRzLldlYlNvY2tldEV4Y2VwdGlvbg4AAAASV2ViU29ja2V0RXJyb3JDb2RlD05hdGl2ZUVycm9yQ29kZQlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMEAAEBAwMBAQEAAQABByRTeXN0ZW0uTmV0LldlYlNvY2tldHMuV2ViU29ja2V0RXJyb3ICAAAACClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAX9////JFN5c3RlbS5OZXQuV2ViU29ja2V0cy5XZWJTb2NrZXRFcnJvcgEAAAAHdmFsdWVfXwAIAgAAAAAAAAAAAAAABgQAAAAoU3lzdGVtLk5ldC5XZWJTb2NrZXRzLldlYlNvY2tldEV4Y2VwdGlvbgYFAAAAB21lc3NhZ2UJBgAAAAkHAAAABggAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYJAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgoAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgsAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAYAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQwAAAACAAAAAgAAAAQHAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBg0AAAAQU3lzdGVtLkV4Y2VwdGlvbgkFAAAACQ8AAAAJEAAAAAkIAAAACQkAAAAJCgAAAAAAAAAK6AMAAAkLAAAACgQMAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYVAAAABnNlY3JldAgBAQkWAAAAAQ8AAAAGAAAACRcAAAACAAAAAgAAAAEQAAAABwAAAAkNAAAABhkAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARYAAAAMAAAACAgBAAAABhoAAAADb25lCgEXAAAADAAAAAkVAAAACAEBCRwAAAABHAAAAAwAAAAICAEAAAAJGgAAAAoL", TargetFrameworkMoniker.netfx461) } };
var win32Exception = new Win32Exception(100, "message");
- yield return new object[] { PopulateException(win32Exception), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAkU3lzdGVtLkNvbXBvbmVudE1vZGVsLldpbjMyRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPTmF0aXZlRXJyb3JDb2RlAQEDAwEBAQABAAEHAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAIAAAAGAwAAACRTeXN0ZW0uQ29tcG9uZW50TW9kZWwuV2luMzJFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAKBgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKZAAAAAQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGCwAAAAZzZWNyZXQIAQEJDAAAAAEMAAAACgAAAAgIAQAAAAYNAAAAA29uZQoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAkU3lzdGVtLkNvbXBvbmVudE1vZGVsLldpbjMyRXhjZXB0aW9uDQAAAA9OYXRpdmVFcnJvckNvZGUJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAAEBAwMBAQEAAQABBwgpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAABkAAAABgMAAAAkU3lzdGVtLkNvbXBvbmVudE1vZGVsLldpbjMyRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACgYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGCwAAAAZzZWNyZXQIAQEJDAAAAAEMAAAACgAAAAgIAQAAAAYNAAAAA29uZQoL" } };
+ yield return new object[] { PopulateException(win32Exception), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAkU3lzdGVtLkNvbXBvbmVudE1vZGVsLldpbjMyRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPTmF0aXZlRXJyb3JDb2RlAQEDAwEBAQABAAEHAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCCAIAAAAGAwAAACRTeXN0ZW0uQ29tcG9uZW50TW9kZWwuV2luMzJFeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAKBgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKZAAAAAQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGCwAAAAZzZWNyZXQIAQEJDAAAAAEMAAAACgAAAAgIAQAAAAYNAAAAA29uZQoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAkU3lzdGVtLkNvbXBvbmVudE1vZGVsLldpbjMyRXhjZXB0aW9uDQAAAA9OYXRpdmVFcnJvckNvZGUJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAAEBAwMBAQEAAQABBwgpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAABkAAAABgMAAAAkU3lzdGVtLkNvbXBvbmVudE1vZGVsLldpbjMyRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACgYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGCwAAAAZzZWNyZXQIAQEJDAAAAAEMAAAACgAAAAgIAQAAAAYNAAAAA29uZQoL", TargetFrameworkMoniker.netfx461) } };
//var xPathCompileException = new XPathCompileException("message", exception);
- //yield return new object[] { PopulateException(xPathCompileException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL", "AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL" } };
+ //yield return new object[] { PopulateException(xPathCompileException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL", SerializationFramework.NetcoreApp), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL", SerializationFramework.Netfx) } };
//var xamlParseException = new XamlParseException("message", exception);
- //yield return new object[] { PopulateException(xamlParseException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL", "AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL" } };
+ //yield return new object[] { PopulateException(xamlParseException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL", SerializationFramework.NetcoreApp), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL", SerializationFramework.Netfx) } };
var xmlSyntaxException = new XmlSyntaxException("message", exception);
- yield return new object[] { PopulateException(xmlSyntaxException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uU2VjdXJpdHkuWG1sU3ludGF4RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAIlN5c3RlbS5TZWN1cml0eS5YbWxTeW50YXhFeGNlcHRpb24GAwAAAA1TeXN0ZW0gZXJyb3IuCQQAAAAKBgUAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYGAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgcAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABggAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQkAAAACAAAAAgAAAAQJAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYKAAAABnNlY3JldAgBAQkLAAAAAQsAAAAJAAAACAgBAAAABgwAAAADb25lCgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uU2VjdXJpdHkuWG1sU3ludGF4RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAIlN5c3RlbS5TZWN1cml0eS5YbWxTeW50YXhFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(xmlSyntaxException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uU2VjdXJpdHkuWG1sU3ludGF4RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAIlN5c3RlbS5TZWN1cml0eS5YbWxTeW50YXhFeGNlcHRpb24GAwAAAA1TeXN0ZW0gZXJyb3IuCQQAAAAKBgUAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYGAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgcAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABggAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAQAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQkAAAACAAAAAgAAAAQJAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYKAAAABnNlY3JldAgBAQkLAAAAAQsAAAAJAAAACAgBAAAABgwAAAADb25lCgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uU2VjdXJpdHkuWG1sU3ludGF4RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAIlN5c3RlbS5TZWN1cml0eS5YbWxTeW50YXhFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
//var xslTransformException = new XslTransformException("message", exception);
- //yield return new object[] { PopulateException(xslTransformException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL", "AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL" } };
+ //yield return new object[] { PopulateException(xslTransformException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL", SerializationFramework.NetcoreApp), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL", SerializationFramework.Netfx) } };
//var zLibException = new ZLibException("message", exception);
- //yield return new object[] { PopulateException(zLibException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL", "AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL" } };
+ //yield return new object[] { PopulateException(zLibException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL", SerializationFramework.NetcoreApp), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uQWdncmVnYXRlRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMPSW5uZXJFeGNlcHRpb25zAQEDAwEBAQABAAEHAylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCElN5c3RlbS5FeGNlcHRpb25bXQYCAAAAGVN5c3RlbS5BZ2dyZWdhdGVFeGNlcHRpb24GAwAAABtBZ2dyZWdhdGUgZXhjZXB0aW9uIG1lc3NhZ2UJBAAAAAkFAAAABgYAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYHAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBggAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgkAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKCQoAAAAEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHHlN5c3RlbS5Db2xsZWN0aW9ucy5JRGljdGlvbmFyeRBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgYNAAAAEUV4Y2VwdGlvbiBtZXNzYWdlCgkOAAAACgoKAAAAAAoAFROACgoHCgAAAAABAAAAAQAAAAMQU3lzdGVtLkV4Y2VwdGlvbgkFAAAABAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhAAAAAGc2VjcmV0CAEBCREAAAABDgAAAAUAAAAJDAAAAAYTAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgERAAAACwAAAAgIAQAAAAYUAAAAA29uZQoL", SerializationFramework.Netfx) } };
// Enum values
- yield return new object[] { DayOfWeek.Monday, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABBTeXN0ZW0uRGF5T2ZXZWVrAQAAAAd2YWx1ZV9fAAgBAAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABBTeXN0ZW0uRGF5T2ZXZWVrAQAAAAd2YWx1ZV9fAAgBAAAACw==" } };
- yield return new object[] { DateTimeKind.Local, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABNTeXN0ZW0uRGF0ZVRpbWVLaW5kAQAAAAd2YWx1ZV9fAAgCAAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABNTeXN0ZW0uRGF0ZVRpbWVLaW5kAQAAAAd2YWx1ZV9fAAgCAAAACw==" } };
+ yield return new object[] { DayOfWeek.Monday, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABBTeXN0ZW0uRGF5T2ZXZWVrAQAAAAd2YWx1ZV9fAAgBAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABBTeXN0ZW0uRGF5T2ZXZWVrAQAAAAd2YWx1ZV9fAAgBAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { DateTimeKind.Local, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABNTeXN0ZW0uRGF0ZVRpbWVLaW5kAQAAAAd2YWx1ZV9fAAgCAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABNTeXN0ZW0uRGF0ZVRpbWVLaW5kAQAAAAd2YWx1ZV9fAAgCAAAACw==", TargetFrameworkMoniker.netfx461) } };
// Nullables
- yield return new object[] { (int?)1, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50MzIBAAAAB21fdmFsdWUACAEAAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50MzIBAAAAB21fdmFsdWUACAEAAAAL" } };
- yield return new object[] { (StructWithIntField?)new StructWithIntField() { X = 42 }, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABAU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdFdpdGhJbnRGaWVsZAEAAAABWAAIAgAAACoAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABAU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdFdpdGhJbnRGaWVsZAEAAAABWAAIAgAAACoAAAAL" } };
+ yield return new object[] { (int?)1, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50MzIBAAAAB21fdmFsdWUACAEAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAxTeXN0ZW0uSW50MzIBAAAAB21fdmFsdWUACAEAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { (StructWithIntField?)new StructWithIntField() { X = 42 }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABAU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdFdpdGhJbnRGaWVsZAEAAAABWAAIAgAAACoAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABAU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdFdpdGhJbnRGaWVsZAEAAAABWAAIAgAAACoAAAAL", TargetFrameworkMoniker.netfx461) } };
// EventArgs
- yield return new object[] { EventArgs.Empty, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABBTeXN0ZW0uRXZlbnRBcmdzAAAAAAs=", "AAEAAAD/////AQAAAAAAAAAEAQAAABBTeXN0ZW0uRXZlbnRBcmdzAAAAAAs=" } };
- yield return new object[] { new EventArgs(), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABBTeXN0ZW0uRXZlbnRBcmdzAAAAAAs=", "AAEAAAD/////AQAAAAAAAAAEAQAAABBTeXN0ZW0uRXZlbnRBcmdzAAAAAAs=" } };
+ yield return new object[] { EventArgs.Empty, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABBTeXN0ZW0uRXZlbnRBcmdzAAAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABBTeXN0ZW0uRXZlbnRBcmdzAAAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new EventArgs(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABBTeXN0ZW0uRXZlbnRBcmdzAAAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABBTeXN0ZW0uRXZlbnRBcmdzAAAAAAs=", TargetFrameworkMoniker.netfx461) } };
// Nullable equality comparer roundtrips as opposed to other equality comparers which serialize to ObjectEqualityComparer
- yield return new object[] { EqualityComparer<int>.Default, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL" } };
- yield return new object[] { EqualityComparer<long>.Default, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDY0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDY0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL" } };
- yield return new object[] { EqualityComparer<string>.Default, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==" } };
- yield return new object[] { EqualityComparer<object>.Default, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uT2JqZWN0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uT2JqZWN0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL" } };
- yield return new object[] { EqualityComparer<int?>.Default, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTnVsbGFibGVFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTnVsbGFibGVFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==" } };
- yield return new object[] { EqualityComparer<double?>.Default, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAJMBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTnVsbGFibGVFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5Eb3VibGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAJMBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTnVsbGFibGVFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5Eb3VibGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAs=" } };
+ yield return new object[] { EqualityComparer<int>.Default, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { EqualityComparer<long>.Default, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDY0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDY0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { EqualityComparer<string>.Default, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { EqualityComparer<object>.Default, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uT2JqZWN0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uT2JqZWN0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { EqualityComparer<int?>.Default, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTnVsbGFibGVFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTnVsbGFibGVFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { EqualityComparer<double?>.Default, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAJMBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTnVsbGFibGVFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5Eb3VibGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAJMBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTnVsbGFibGVFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5Eb3VibGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAs=", TargetFrameworkMoniker.netfx461) } };
// Equality comparers which can roundtrip
object byteEqualityComparer;
- // .NET Native doesn't create ByteEqualityComparer with EqualityComparer.Default, so create it through reflection
+ // NET Native doesn't create ByteEqualityComparer with EqualityComparer.Default, so create it through reflection
if (PlatformDetection.IsNetNative)
{
Type byteEqualityComparerType = Type.GetType("System.Collections.Generic.ByteEqualityComparer", true);
@@ -837,16 +829,16 @@ namespace System.Runtime.Serialization.Formatters.Tests
byteEqualityComparer = EqualityComparer<byte>.Default;
}
- yield return new object[] { byteEqualityComparer, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAC9TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5CeXRlRXF1YWxpdHlDb21wYXJlcgAAAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAAC9TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5CeXRlRXF1YWxpdHlDb21wYXJlcgAAAAAL" } };
- yield return new object[] { EqualityComparer<Int32Enum>.Default, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAN4BU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRW51bUVxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkludDMyRW51bSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAAAAAAs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAN4BU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRW51bUVxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkludDMyRW51bSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAAAAAAs=" } };
+ yield return new object[] { byteEqualityComparer, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAC9TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5CeXRlRXF1YWxpdHlDb21wYXJlcgAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAC9TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5CeXRlRXF1YWxpdHlDb21wYXJlcgAAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { EqualityComparer<Int32Enum>.Default, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAN4BU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRW51bUVxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkludDMyRW51bSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAAAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAN4BU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRW51bUVxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkludDMyRW51bSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAAAAAAs=", TargetFrameworkMoniker.netfx461) } };
// Other core serializable types
- yield return new object[] { IntPtr.Zero, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uSW50UHRyAQAAAAV2YWx1ZQAJAAAAAAAAAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uSW50UHRyAQAAAAV2YWx1ZQAJAAAAAAAAAAAL" } };
- yield return new object[] { UIntPtr.Zero, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uVUludFB0cgEAAAAFdmFsdWUAEAAAAAAAAAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uVUludFB0cgEAAAAFdmFsdWUAEAAAAAAAAAAACw==" } };
- yield return new object[] { new DateTime(1990, 11, 23), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAA9TeXN0ZW0uRGF0ZVRpbWUCAAAABXRpY2tzCGRhdGVEYXRhAAAJEADA9z1t7LYIAMD3PW3stggL", "AAEAAAD/////AQAAAAAAAAAEAQAAAA9TeXN0ZW0uRGF0ZVRpbWUCAAAABXRpY2tzCGRhdGVEYXRhAAAJEADA9z1t7LYIAMD3PW3stggL" } };
- yield return new object[] { new DateTimeOffset(1990, 11, 23, 03, 30, 00, 00, TimeSpan.FromMinutes(30)), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABVTeXN0ZW0uRGF0ZVRpbWVPZmZzZXQCAAAACERhdGVUaW1lDU9mZnNldE1pbnV0ZXMAAA0HAPhEY4bstggeAAs=", "AAEAAAD/////AQAAAAAAAAAEAQAAABVTeXN0ZW0uRGF0ZVRpbWVPZmZzZXQCAAAACERhdGVUaW1lDU9mZnNldE1pbnV0ZXMAAA0HAPhEY4bstggeAAs=" } };
- yield return new object[] { TimeZoneInfo.Utc, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj0zLjUuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABNTeXN0ZW0uVGltZVpvbmVJbmZvBwAAAAJJZAtEaXNwbGF5TmFtZQxTdGFuZGFyZE5hbWUMRGF5bGlnaHROYW1lDUJhc2VVdGNPZmZzZXQPQWRqdXN0bWVudFJ1bGVzGlN1cHBvcnRzRGF5bGlnaHRTYXZpbmdUaW1lAQEBAQACAAwBAgAAAAYDAAAAA1VUQwkDAAAACQMAAAAJAwAAAAAAAAAAAAAACgAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj0zLjUuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABNTeXN0ZW0uVGltZVpvbmVJbmZvBwAAAAJJZAtEaXNwbGF5TmFtZQxTdGFuZGFyZE5hbWUMRGF5bGlnaHROYW1lDUJhc2VVdGNPZmZzZXQPQWRqdXN0bWVudFJ1bGVzGlN1cHBvcnRzRGF5bGlnaHRTYXZpbmdUaW1lAQEBAQACAAwBAgAAAAYDAAAAA1VUQwkDAAAACQMAAAAJAwAAAAAAAAAAAAAACgAL" } };
- yield return new object[] { TimeZoneInfo.TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1, 2, 0, 0), 3, 15), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uVGltZVpvbmVJbmZvK1RyYW5zaXRpb25UaW1lBgAAAAlUaW1lT2ZEYXkFTW9udGgEV2VlawNEYXkJRGF5T2ZXZWVrD0lzRml4ZWREYXRlUnVsZQAAAAADAA0CAgIQU3lzdGVtLkRheU9mV2VlawEA0IjDEAAAAAMBDwT+////EFN5c3RlbS5EYXlPZldlZWsBAAAAB3ZhbHVlX18ACAAAAAABCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj0zLjUuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0ZW0uVGltZVpvbmVJbmZvK1RyYW5zaXRpb25UaW1lBgAAAAlUaW1lT2ZEYXkFTW9udGgEV2VlawNEYXkJRGF5T2ZXZWVrD0lzRml4ZWREYXRlUnVsZQAAAAADAA0CAgIQU3lzdGVtLkRheU9mV2VlawECAAAAANCIwxAAAAADAQ8E/f///xBTeXN0ZW0uRGF5T2ZXZWVrAQAAAAd2YWx1ZV9fAAgAAAAAAQs=" } };
+ yield return new object[] { IntPtr.Zero, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uSW50UHRyAQAAAAV2YWx1ZQAJAAAAAAAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA1TeXN0ZW0uSW50UHRyAQAAAAV2YWx1ZQAJAAAAAAAAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { UIntPtr.Zero, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uVUludFB0cgEAAAAFdmFsdWUAEAAAAAAAAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uVUludFB0cgEAAAAFdmFsdWUAEAAAAAAAAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new DateTime(1990, 11, 23), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA9TeXN0ZW0uRGF0ZVRpbWUCAAAABXRpY2tzCGRhdGVEYXRhAAAJEADA9z1t7LYIAMD3PW3stggL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA9TeXN0ZW0uRGF0ZVRpbWUCAAAABXRpY2tzCGRhdGVEYXRhAAAJEADA9z1t7LYIAMD3PW3stggL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new DateTimeOffset(1990, 11, 23, 03, 30, 00, 00, TimeSpan.FromMinutes(30)), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABVTeXN0ZW0uRGF0ZVRpbWVPZmZzZXQCAAAACERhdGVUaW1lDU9mZnNldE1pbnV0ZXMAAA0HAPhEY4bstggeAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABVTeXN0ZW0uRGF0ZVRpbWVPZmZzZXQCAAAACERhdGVUaW1lDU9mZnNldE1pbnV0ZXMAAA0HAPhEY4bstggeAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { TimeZoneInfo.Utc, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj0zLjUuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABNTeXN0ZW0uVGltZVpvbmVJbmZvBwAAAAJJZAtEaXNwbGF5TmFtZQxTdGFuZGFyZE5hbWUMRGF5bGlnaHROYW1lDUJhc2VVdGNPZmZzZXQPQWRqdXN0bWVudFJ1bGVzGlN1cHBvcnRzRGF5bGlnaHRTYXZpbmdUaW1lAQEBAQACAAwBAgAAAAYDAAAAA1VUQwkDAAAACQMAAAAJAwAAAAAAAAAAAAAACgAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj0zLjUuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABNTeXN0ZW0uVGltZVpvbmVJbmZvBwAAAAJJZAtEaXNwbGF5TmFtZQxTdGFuZGFyZE5hbWUMRGF5bGlnaHROYW1lDUJhc2VVdGNPZmZzZXQPQWRqdXN0bWVudFJ1bGVzGlN1cHBvcnRzRGF5bGlnaHRTYXZpbmdUaW1lAQEBAQACAAwBAgAAAAYDAAAAA1VUQwkDAAAACQMAAAAJAwAAAAAAAAAAAAAACgAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { TimeZoneInfo.TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1, 2, 0, 0), 3, 15), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uVGltZVpvbmVJbmZvK1RyYW5zaXRpb25UaW1lBgAAAAlUaW1lT2ZEYXkFTW9udGgEV2VlawNEYXkJRGF5T2ZXZWVrD0lzRml4ZWREYXRlUnVsZQAAAAADAA0CAgIQU3lzdGVtLkRheU9mV2VlawEA0IjDEAAAAAMBDwT+////EFN5c3RlbS5EYXlPZldlZWsBAAAAB3ZhbHVlX18ACAAAAAABCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj0zLjUuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0ZW0uVGltZVpvbmVJbmZvK1RyYW5zaXRpb25UaW1lBgAAAAlUaW1lT2ZEYXkFTW9udGgEV2VlawNEYXkJRGF5T2ZXZWVrD0lzRml4ZWREYXRlUnVsZQAAAAADAA0CAgIQU3lzdGVtLkRheU9mV2VlawECAAAAANCIwxAAAAADAQ8E/f///xBTeXN0ZW0uRGF5T2ZXZWVrAQAAAAd2YWx1ZV9fAAgAAAAAAQs=", TargetFrameworkMoniker.netfx461) } };
var adjustmentRule = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(
new DateTime(1900, 1, 1),
@@ -854,57 +846,57 @@ namespace System.Runtime.Serialization.Formatters.Tests
TimeSpan.FromHours(2),
TimeZoneInfo.TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1, 2, 0, 0), 2, 3),
TimeZoneInfo.TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1, 2, 0, 0), 3, 4));
- yield return new object[] { adjustmentRule, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uVGltZVpvbmVJbmZvK0FkanVzdG1lbnRSdWxlBwAAAAlEYXRlU3RhcnQHRGF0ZUVuZA1EYXlsaWdodERlbHRhF0RheWxpZ2h0VHJhbnNpdGlvblN0YXJ0FURheWxpZ2h0VHJhbnNpdGlvbkVuZBJCYXNlVXRjT2Zmc2V0RGVsdGEVTm9EYXlsaWdodFRyYW5zaXRpb25zAAAAAwMAAA0NDCJTeXN0ZW0uVGltZVpvbmVJbmZvK1RyYW5zaXRpb25UaW1lIlN5c3RlbS5UaW1lWm9uZUluZm8rVHJhbnNpdGlvblRpbWUMAQBAVyBTBVEIAEDGiJPMjwgA0IjDEAAAAAT+////IlN5c3RlbS5UaW1lWm9uZUluZm8rVHJhbnNpdGlvblRpbWUGAAAACVRpbWVPZkRheQVNb250aARXZWVrA0RheQlEYXlPZldlZWsPSXNGaXhlZERhdGVSdWxlAAAAAAMADQICAhBTeXN0ZW0uRGF5T2ZXZWVrAQDQiMMQAAAAAgEDBP3///8QU3lzdGVtLkRheU9mV2VlawEAAAAHdmFsdWVfXwAIAAAAAAEB/P////7///8A0IjDEAAAAAMBBAH7/////f///wAAAAABAAAAAAAAAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj0zLjUuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0ZW0uVGltZVpvbmVJbmZvK0FkanVzdG1lbnRSdWxlBgAAAAlEYXRlU3RhcnQHRGF0ZUVuZA1EYXlsaWdodERlbHRhF0RheWxpZ2h0VHJhbnNpdGlvblN0YXJ0FURheWxpZ2h0VHJhbnNpdGlvbkVuZBJCYXNlVXRjT2Zmc2V0RGVsdGEAAAAEBAANDQwiU3lzdGVtLlRpbWVab25lSW5mbytUcmFuc2l0aW9uVGltZQIAAAAiU3lzdGVtLlRpbWVab25lSW5mbytUcmFuc2l0aW9uVGltZQIAAAAMAgAAAABAVyBTBVEIAEDGiJPMjwgA0IjDEAAAAAX9////IlN5c3RlbS5UaW1lWm9uZUluZm8rVHJhbnNpdGlvblRpbWUGAAAACVRpbWVPZkRheQVNb250aARXZWVrA0RheQlEYXlPZldlZWsPSXNGaXhlZERhdGVSdWxlAAAAAAMADQICAhBTeXN0ZW0uRGF5T2ZXZWVrAQIAAAAA0IjDEAAAAAIBAwT8////EFN5c3RlbS5EYXlPZldlZWsBAAAAB3ZhbHVlX18ACAAAAAABAfv////9////ANCIwxAAAAADAQQB+v////z///8AAAAAAQAAAAAAAAAACw==" } };
- yield return new object[] { TimeSpan.FromDays(7), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAA9TeXN0ZW0uVGltZVNwYW4BAAAABl90aWNrcwAJAEDkKIAFAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAAA9TeXN0ZW0uVGltZVNwYW4BAAAABl90aWNrcwAJAEDkKIAFAAAL" } };
- yield return new object[] { new Version(1, 2, 3, 4), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uVmVyc2lvbgQAAAAGX01ham9yBl9NaW5vcgZfQnVpbGQJX1JldmlzaW9uAAAAAAgICAgBAAAAAgAAAAMAAAAEAAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uVmVyc2lvbgQAAAAGX01ham9yBl9NaW5vcgZfQnVpbGQJX1JldmlzaW9uAAAAAAgICAgBAAAAAgAAAAMAAAAEAAAACw==" } };
- yield return new object[] { new Guid("0CACAA4D-C6BD-420A-B660-2F557337CA89"), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAAtTeXN0ZW0uR3VpZAsAAAACX2ECX2ICX2MCX2QCX2UCX2YCX2cCX2gCX2kCX2oCX2sAAAAAAAAAAAAAAAgHBwICAgICAgICTaqsDL3GCkK2YC9VczfKiQs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAAtTeXN0ZW0uR3VpZAsAAAACX2ECX2ICX2MCX2QCX2UCX2YCX2cCX2gCX2kCX2oCX2sAAAAAAAAAAAAAAAgHBwICAgICAgICTaqsDL3GCkK2YC9VczfKiQs=" } };
- yield return new object[] { new List<int>(), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkCAAAAAAAAAAAAAAAPAgAAAAAAAAAICw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkCAAAAAAAAAAAAAAAPAgAAAAAAAAAICw==" } };
- yield return new object[] { new List<int>(27), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkCAAAAAAAAAAAAAAAPAgAAABsAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkCAAAAAAAAAAAAAAAPAgAAABsAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACw==" } };
- yield return new object[] { new List<int>() { 1, 2, 3, 4, 5 }, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkCAAAABQAAAAUAAAAPAgAAAAgAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAAAAAAAAAAAAAAAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkCAAAABQAAAAUAAAAPAgAAAAgAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAAAAAAAAAAAAAAAAAL" } };
+ yield return new object[] { adjustmentRule, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uVGltZVpvbmVJbmZvK0FkanVzdG1lbnRSdWxlBwAAAAlEYXRlU3RhcnQHRGF0ZUVuZA1EYXlsaWdodERlbHRhF0RheWxpZ2h0VHJhbnNpdGlvblN0YXJ0FURheWxpZ2h0VHJhbnNpdGlvbkVuZBJCYXNlVXRjT2Zmc2V0RGVsdGEVTm9EYXlsaWdodFRyYW5zaXRpb25zAAAAAwMAAA0NDCJTeXN0ZW0uVGltZVpvbmVJbmZvK1RyYW5zaXRpb25UaW1lIlN5c3RlbS5UaW1lWm9uZUluZm8rVHJhbnNpdGlvblRpbWUMAQBAVyBTBVEIAEDGiJPMjwgA0IjDEAAAAAT+////IlN5c3RlbS5UaW1lWm9uZUluZm8rVHJhbnNpdGlvblRpbWUGAAAACVRpbWVPZkRheQVNb250aARXZWVrA0RheQlEYXlPZldlZWsPSXNGaXhlZERhdGVSdWxlAAAAAAMADQICAhBTeXN0ZW0uRGF5T2ZXZWVrAQDQiMMQAAAAAgEDBP3///8QU3lzdGVtLkRheU9mV2VlawEAAAAHdmFsdWVfXwAIAAAAAAEB/P////7///8A0IjDEAAAAAMBBAH7/////f///wAAAAABAAAAAAAAAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj0zLjUuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0ZW0uVGltZVpvbmVJbmZvK0FkanVzdG1lbnRSdWxlBgAAAAlEYXRlU3RhcnQHRGF0ZUVuZA1EYXlsaWdodERlbHRhF0RheWxpZ2h0VHJhbnNpdGlvblN0YXJ0FURheWxpZ2h0VHJhbnNpdGlvbkVuZBJCYXNlVXRjT2Zmc2V0RGVsdGEAAAAEBAANDQwiU3lzdGVtLlRpbWVab25lSW5mbytUcmFuc2l0aW9uVGltZQIAAAAiU3lzdGVtLlRpbWVab25lSW5mbytUcmFuc2l0aW9uVGltZQIAAAAMAgAAAABAVyBTBVEIAEDGiJPMjwgA0IjDEAAAAAX9////IlN5c3RlbS5UaW1lWm9uZUluZm8rVHJhbnNpdGlvblRpbWUGAAAACVRpbWVPZkRheQVNb250aARXZWVrA0RheQlEYXlPZldlZWsPSXNGaXhlZERhdGVSdWxlAAAAAAMADQICAhBTeXN0ZW0uRGF5T2ZXZWVrAQIAAAAA0IjDEAAAAAIBAwT8////EFN5c3RlbS5EYXlPZldlZWsBAAAAB3ZhbHVlX18ACAAAAAABAfv////9////ANCIwxAAAAADAQQB+v////z///8AAAAAAQAAAAAAAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { TimeSpan.FromDays(7), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA9TeXN0ZW0uVGltZVNwYW4BAAAABl90aWNrcwAJAEDkKIAFAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA9TeXN0ZW0uVGltZVNwYW4BAAAABl90aWNrcwAJAEDkKIAFAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Version(1, 2, 3, 4), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uVmVyc2lvbgQAAAAGX01ham9yBl9NaW5vcgZfQnVpbGQJX1JldmlzaW9uAAAAAAgICAgBAAAAAgAAAAMAAAAEAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAA5TeXN0ZW0uVmVyc2lvbgQAAAAGX01ham9yBl9NaW5vcgZfQnVpbGQJX1JldmlzaW9uAAAAAAgICAgBAAAAAgAAAAMAAAAEAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Guid("0CACAA4D-C6BD-420A-B660-2F557337CA89"), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAtTeXN0ZW0uR3VpZAsAAAACX2ECX2ICX2MCX2QCX2UCX2YCX2cCX2gCX2kCX2oCX2sAAAAAAAAAAAAAAAgHBwICAgICAgICTaqsDL3GCkK2YC9VczfKiQs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAAtTeXN0ZW0uR3VpZAsAAAACX2ECX2ICX2MCX2QCX2UCX2YCX2cCX2gCX2kCX2oCX2sAAAAAAAAAAAAAAAgHBwICAgICAgICTaqsDL3GCkK2YC9VczfKiQs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new List<int>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkCAAAAAAAAAAAAAAAPAgAAAAAAAAAICw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkCAAAAAAAAAAAAAAAPAgAAAAAAAAAICw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new List<int>(27), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkCAAAAAAAAAAAAAAAPAgAAABsAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkCAAAAAAAAAAAAAAAPAgAAABsAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new List<int>() { 1, 2, 3, 4, 5 }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkCAAAABQAAAAUAAAAPAgAAAAgAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAAAAAAAAAAAAAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkCAAAABQAAAAUAAAAPAgAAAAgAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAAAAAAAAAAAAAAAAAL", TargetFrameworkMoniker.netfx461) } };
var dictionary = new Dictionary<int, string>() { { 1, "test" }, { 2, "another test" } };
- yield return new object[] { dictionary, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAOEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAdWZXJzaW9uCENvbXBhcmVyCEhhc2hTaXplDUtleVZhbHVlUGFpcnMAAwADCJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQjlAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dW10CAAAACQIAAAADAAAACQMAAAAEAgAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAHAwAAAAABAAAAAgAAAAPjAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBPz////jAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAANrZXkFdmFsdWUAAQgBAAAABgUAAAAEdGVzdAH6/////P///wIAAAAGBwAAAAxhbm90aGVyIHRlc3QL", "AAEAAAD/////AQAAAAAAAAAEAQAAAOEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAdWZXJzaW9uCENvbXBhcmVyCEhhc2hTaXplDUtleVZhbHVlUGFpcnMAAwADCJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQjlAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dW10CAAAACQIAAAADAAAACQMAAAAEAgAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAHAwAAAAABAAAAAgAAAAPjAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBPz////jAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAANrZXkFdmFsdWUAAQgBAAAABgUAAAAEdGVzdAH6/////P///wIAAAAGBwAAAAxhbm90aGVyIHRlc3QL" } };
+ yield return new object[] { dictionary, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAdWZXJzaW9uCENvbXBhcmVyCEhhc2hTaXplDUtleVZhbHVlUGFpcnMAAwADCJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQjlAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dW10CAAAACQIAAAADAAAACQMAAAAEAgAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAHAwAAAAABAAAAAgAAAAPjAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBPz////jAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAANrZXkFdmFsdWUAAQgBAAAABgUAAAAEdGVzdAH6/////P///wIAAAAGBwAAAAxhbm90aGVyIHRlc3QL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAdWZXJzaW9uCENvbXBhcmVyCEhhc2hTaXplDUtleVZhbHVlUGFpcnMAAwADCJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQjlAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dW10CAAAACQIAAAADAAAACQMAAAAEAgAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAHAwAAAAABAAAAAgAAAAPjAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBPz////jAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAANrZXkFdmFsdWUAAQgBAAAABgUAAAAEdGVzdAH6/////P///wIAAAAGBwAAAAxhbm90aGVyIHRlc3QL", TargetFrameworkMoniker.netfx461) } };
var pointDictionary = new Dictionary<int, Point>()
{
{ 1, new Point(1, 1) },
{ 2, new Point(2, 2) }
};
- yield return new object[] { Tuple.Create(1), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAGtTeXN0ZW0uVHVwbGVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAHbV9JdGVtMQAIAQAAAAs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAGtTeXN0ZW0uVHVwbGVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAHbV9JdGVtMQAIAQAAAAs=" } };
- yield return new object[] { Tuple.Create(1, "2"), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAMgBU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAAB21fSXRlbTEHbV9JdGVtMgABCAEAAAAGAgAAAAEyCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAMgBU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAAB21fSXRlbTEHbV9JdGVtMgABCAEAAAAGAgAAAAEyCw==" } };
- yield return new object[] { Tuple.Create(1, "2", 3u), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAKUCU3lzdGVtLlR1cGxlYDNbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlVJbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAB21fSXRlbTEHbV9JdGVtMgdtX0l0ZW0zAAEACA8BAAAABgIAAAABMgMAAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAAKUCU3lzdGVtLlR1cGxlYDNbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlVJbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAB21fSXRlbTEHbV9JdGVtMgdtX0l0ZW0zAAEACA8BAAAABgIAAAABMgMAAAAL" } };
- yield return new object[] { Tuple.Create(1, "2", 3u, 4L), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAIEDU3lzdGVtLlR1cGxlYDRbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlVJbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDY0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAHbV9JdGVtMQdtX0l0ZW0yB21fSXRlbTMHbV9JdGVtNAABAAAIDwkBAAAABgIAAAABMgMAAAAEAAAAAAAAAAs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAIEDU3lzdGVtLlR1cGxlYDRbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlVJbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDY0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAHbV9JdGVtMQdtX0l0ZW0yB21fSXRlbTMHbV9JdGVtNAABAAAIDwkBAAAABgIAAAABMgMAAAAEAAAAAAAAAAs=" } };
- yield return new object[] { Tuple.Create(1, "2", 3u, 4L, 5.6), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAN4DU3lzdGVtLlR1cGxlYDVbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlVJbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDY0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uRG91YmxlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQUAAAAHbV9JdGVtMQdtX0l0ZW0yB21fSXRlbTMHbV9JdGVtNAdtX0l0ZW01AAEAAAAIDwkGAQAAAAYCAAAAATIDAAAABAAAAAAAAABmZmZmZmYWQAs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAN4DU3lzdGVtLlR1cGxlYDVbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlVJbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDY0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uRG91YmxlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQUAAAAHbV9JdGVtMQdtX0l0ZW0yB21fSXRlbTMHbV9JdGVtNAdtX0l0ZW01AAEAAAAIDwkGAQAAAAYCAAAAATIDAAAABAAAAAAAAABmZmZmZmYWQAs=" } };
- yield return new object[] { Tuple.Create(1, "2", 3u, 4L, 5.6, 7.8f), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAALsEU3lzdGVtLlR1cGxlYDZbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlVJbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDY0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uRG91YmxlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU2luZ2xlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQYAAAAHbV9JdGVtMQdtX0l0ZW0yB21fSXRlbTMHbV9JdGVtNAdtX0l0ZW01B21fSXRlbTYAAQAAAAAIDwkGCwEAAAAGAgAAAAEyAwAAAAQAAAAAAAAAZmZmZmZmFkCamflACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAALsEU3lzdGVtLlR1cGxlYDZbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlVJbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDY0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uRG91YmxlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU2luZ2xlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQYAAAAHbV9JdGVtMQdtX0l0ZW0yB21fSXRlbTMHbV9JdGVtNAdtX0l0ZW01B21fSXRlbTYAAQAAAAAIDwkGCwEAAAAGAgAAAAEyAwAAAAQAAAAAAAAAZmZmZmZmFkCamflACw==" } };
- yield return new object[] { Tuple.Create(1, "2", 3u, 4L, 5.6, 7.8f, 9m), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAJkFU3lzdGVtLlR1cGxlYDdbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlVJbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDY0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uRG91YmxlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU2luZ2xlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uRGVjaW1hbCwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0HAAAAB21fSXRlbTEHbV9JdGVtMgdtX0l0ZW0zB21fSXRlbTQHbV9JdGVtNQdtX0l0ZW02B21fSXRlbTcAAQAAAAAACA8JBgsFAQAAAAYCAAAAATIDAAAABAAAAAAAAABmZmZmZmYWQJqZ+UABOQs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAJkFU3lzdGVtLlR1cGxlYDdbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlVJbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDY0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uRG91YmxlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU2luZ2xlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uRGVjaW1hbCwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0HAAAAB21fSXRlbTEHbV9JdGVtMgdtX0l0ZW0zB21fSXRlbTQHbV9JdGVtNQdtX0l0ZW02B21fSXRlbTcAAQAAAAAACA8JBgsFAQAAAAYCAAAAATIDAAAABAAAAAAAAABmZmZmZmYWQJqZ+UABOQs=" } };
- yield return new object[] { Tuple.Create(1, "2", 3u, 4L, 5.6, 7.8f, 9m, Tuple.Create(10)), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAALMHU3lzdGVtLlR1cGxlYDhbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlVJbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDY0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uRG91YmxlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU2luZ2xlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uRGVjaW1hbCwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlR1cGxlYDFbW1N5c3RlbS5UdXBsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IAAAAB21fSXRlbTEHbV9JdGVtMgdtX0l0ZW0zB21fSXRlbTQHbV9JdGVtNQdtX0l0ZW02B21fSXRlbTcGbV9SZXN0AAEAAAAAAAMIDwkGCwXKAVN5c3RlbS5UdXBsZWAxW1tTeXN0ZW0uVHVwbGVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAABgIAAAABMgMAAAAEAAAAAAAAAGZmZmZmZhZAmpn5QAE5CQMAAAAEAwAAAMoBU3lzdGVtLlR1cGxlYDFbW1N5c3RlbS5UdXBsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAHbV9JdGVtMQNrU3lzdGVtLlR1cGxlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0JBAAAAAQEAAAAa1N5c3RlbS5UdXBsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAAdtX0l0ZW0xAAgKAAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAALMHU3lzdGVtLlR1cGxlYDhbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlVJbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDY0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uRG91YmxlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU2luZ2xlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uRGVjaW1hbCwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlR1cGxlYDFbW1N5c3RlbS5UdXBsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IAAAAB21fSXRlbTEHbV9JdGVtMgdtX0l0ZW0zB21fSXRlbTQHbV9JdGVtNQdtX0l0ZW02B21fSXRlbTcGbV9SZXN0AAEAAAAAAAMIDwkGCwXKAVN5c3RlbS5UdXBsZWAxW1tTeXN0ZW0uVHVwbGVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAABgIAAAABMgMAAAAEAAAAAAAAAGZmZmZmZhZAmpn5QAE5CQMAAAAEAwAAAMoBU3lzdGVtLlR1cGxlYDFbW1N5c3RlbS5UdXBsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAHbV9JdGVtMQNrU3lzdGVtLlR1cGxlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0JBAAAAAQEAAAAa1N5c3RlbS5UdXBsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAAdtX0l0ZW0xAAgKAAAACw==" } };
- yield return new object[] { new KeyValuePair<int, byte>(42, 84), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAOEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkJ5dGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAANrZXkFdmFsdWUAAAgCKgAAAFQL", "AAEAAAD/////AQAAAAAAAAAEAQAAAOEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkJ5dGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAANrZXkFdmFsdWUAAAgCKgAAAFQL" } };
+ yield return new object[] { Tuple.Create(1), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAGtTeXN0ZW0uVHVwbGVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAHbV9JdGVtMQAIAQAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAGtTeXN0ZW0uVHVwbGVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAHbV9JdGVtMQAIAQAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { Tuple.Create(1, "2"), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAMgBU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAAB21fSXRlbTEHbV9JdGVtMgABCAEAAAAGAgAAAAEyCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAMgBU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAAB21fSXRlbTEHbV9JdGVtMgABCAEAAAAGAgAAAAEyCw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { Tuple.Create(1, "2", 3u), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAKUCU3lzdGVtLlR1cGxlYDNbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlVJbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAB21fSXRlbTEHbV9JdGVtMgdtX0l0ZW0zAAEACA8BAAAABgIAAAABMgMAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAKUCU3lzdGVtLlR1cGxlYDNbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlVJbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAB21fSXRlbTEHbV9JdGVtMgdtX0l0ZW0zAAEACA8BAAAABgIAAAABMgMAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { Tuple.Create(1, "2", 3u, 4L), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAIEDU3lzdGVtLlR1cGxlYDRbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlVJbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDY0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAHbV9JdGVtMQdtX0l0ZW0yB21fSXRlbTMHbV9JdGVtNAABAAAIDwkBAAAABgIAAAABMgMAAAAEAAAAAAAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAIEDU3lzdGVtLlR1cGxlYDRbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlVJbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDY0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAHbV9JdGVtMQdtX0l0ZW0yB21fSXRlbTMHbV9JdGVtNAABAAAIDwkBAAAABgIAAAABMgMAAAAEAAAAAAAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { Tuple.Create(1, "2", 3u, 4L, 5.6), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAN4DU3lzdGVtLlR1cGxlYDVbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlVJbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDY0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uRG91YmxlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQUAAAAHbV9JdGVtMQdtX0l0ZW0yB21fSXRlbTMHbV9JdGVtNAdtX0l0ZW01AAEAAAAIDwkGAQAAAAYCAAAAATIDAAAABAAAAAAAAABmZmZmZmYWQAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAN4DU3lzdGVtLlR1cGxlYDVbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlVJbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDY0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uRG91YmxlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQUAAAAHbV9JdGVtMQdtX0l0ZW0yB21fSXRlbTMHbV9JdGVtNAdtX0l0ZW01AAEAAAAIDwkGAQAAAAYCAAAAATIDAAAABAAAAAAAAABmZmZmZmYWQAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { Tuple.Create(1, "2", 3u, 4L, 5.6, 7.8f), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAALsEU3lzdGVtLlR1cGxlYDZbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlVJbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDY0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uRG91YmxlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU2luZ2xlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQYAAAAHbV9JdGVtMQdtX0l0ZW0yB21fSXRlbTMHbV9JdGVtNAdtX0l0ZW01B21fSXRlbTYAAQAAAAAIDwkGCwEAAAAGAgAAAAEyAwAAAAQAAAAAAAAAZmZmZmZmFkCamflACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAALsEU3lzdGVtLlR1cGxlYDZbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlVJbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDY0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uRG91YmxlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU2luZ2xlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQYAAAAHbV9JdGVtMQdtX0l0ZW0yB21fSXRlbTMHbV9JdGVtNAdtX0l0ZW01B21fSXRlbTYAAQAAAAAIDwkGCwEAAAAGAgAAAAEyAwAAAAQAAAAAAAAAZmZmZmZmFkCamflACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { Tuple.Create(1, "2", 3u, 4L, 5.6, 7.8f, 9m), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAJkFU3lzdGVtLlR1cGxlYDdbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlVJbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDY0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uRG91YmxlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU2luZ2xlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uRGVjaW1hbCwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0HAAAAB21fSXRlbTEHbV9JdGVtMgdtX0l0ZW0zB21fSXRlbTQHbV9JdGVtNQdtX0l0ZW02B21fSXRlbTcAAQAAAAAACA8JBgsFAQAAAAYCAAAAATIDAAAABAAAAAAAAABmZmZmZmYWQJqZ+UABOQs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAJkFU3lzdGVtLlR1cGxlYDdbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlVJbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDY0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uRG91YmxlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU2luZ2xlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uRGVjaW1hbCwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0HAAAAB21fSXRlbTEHbV9JdGVtMgdtX0l0ZW0zB21fSXRlbTQHbV9JdGVtNQdtX0l0ZW02B21fSXRlbTcAAQAAAAAACA8JBgsFAQAAAAYCAAAAATIDAAAABAAAAAAAAABmZmZmZmYWQJqZ+UABOQs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { Tuple.Create(1, "2", 3u, 4L, 5.6, 7.8f, 9m, Tuple.Create(10)), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAALMHU3lzdGVtLlR1cGxlYDhbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlVJbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDY0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uRG91YmxlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU2luZ2xlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uRGVjaW1hbCwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlR1cGxlYDFbW1N5c3RlbS5UdXBsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IAAAAB21fSXRlbTEHbV9JdGVtMgdtX0l0ZW0zB21fSXRlbTQHbV9JdGVtNQdtX0l0ZW02B21fSXRlbTcGbV9SZXN0AAEAAAAAAAMIDwkGCwXKAVN5c3RlbS5UdXBsZWAxW1tTeXN0ZW0uVHVwbGVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAABgIAAAABMgMAAAAEAAAAAAAAAGZmZmZmZhZAmpn5QAE5CQMAAAAEAwAAAMoBU3lzdGVtLlR1cGxlYDFbW1N5c3RlbS5UdXBsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAHbV9JdGVtMQNrU3lzdGVtLlR1cGxlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0JBAAAAAQEAAAAa1N5c3RlbS5UdXBsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAAdtX0l0ZW0xAAgKAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAALMHU3lzdGVtLlR1cGxlYDhbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlVJbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDY0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uRG91YmxlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU2luZ2xlLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uRGVjaW1hbCwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlR1cGxlYDFbW1N5c3RlbS5UdXBsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IAAAAB21fSXRlbTEHbV9JdGVtMgdtX0l0ZW0zB21fSXRlbTQHbV9JdGVtNQdtX0l0ZW02B21fSXRlbTcGbV9SZXN0AAEAAAAAAAMIDwkGCwXKAVN5c3RlbS5UdXBsZWAxW1tTeXN0ZW0uVHVwbGVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAABgIAAAABMgMAAAAEAAAAAAAAAGZmZmZmZhZAmpn5QAE5CQMAAAAEAwAAAMoBU3lzdGVtLlR1cGxlYDFbW1N5c3RlbS5UdXBsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAHbV9JdGVtMQNrU3lzdGVtLlR1cGxlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0JBAAAAAQEAAAAa1N5c3RlbS5UdXBsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAAdtX0l0ZW0xAAgKAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new KeyValuePair<int, byte>(42, 84), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkJ5dGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAANrZXkFdmFsdWUAAAgCKgAAAFQL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkJ5dGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAANrZXkFdmFsdWUAAAgCKgAAAFQL", TargetFrameworkMoniker.netfx461) } };
var dotnetUri = new Uri("https://dot.net");
- yield return new object[] { dotnetUri, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAKU3lzdGVtLlVyaQEAAAALQWJzb2x1dGVVcmkBAgAAAAYDAAAAEGh0dHBzOi8vZG90Lm5ldC8L", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAKU3lzdGVtLlVyaQEAAAALQWJzb2x1dGVVcmkBAgAAAAYDAAAAEGh0dHBzOi8vZG90Lm5ldC8L" } };
- yield return new object[] { new Uri(dotnetUri, "articles/info.html"), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAKU3lzdGVtLlVyaQEAAAALQWJzb2x1dGVVcmkBAgAAAAYDAAAAImh0dHBzOi8vZG90Lm5ldC9hcnRpY2xlcy9pbmZvLmh0bWwL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAKU3lzdGVtLlVyaQEAAAALQWJzb2x1dGVVcmkBAgAAAAYDAAAAImh0dHBzOi8vZG90Lm5ldC9hcnRpY2xlcy9pbmZvLmh0bWwL" } };
- yield return new object[] { new WeakReference(dotnetUri, true), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BAEAAAAUU3lzdGVtLldlYWtSZWZlcmVuY2UCAAAADVRyYWNrZWRPYmplY3QRVHJhY2tSZXN1cnJlY3Rpb24EAApTeXN0ZW0uVXJpAgAAAAEJAwAAAAEFAwAAAApTeXN0ZW0uVXJpAQAAAAtBYnNvbHV0ZVVyaQECAAAABgQAAAAQaHR0cHM6Ly9kb3QubmV0Lws=", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BAEAAAAUU3lzdGVtLldlYWtSZWZlcmVuY2UCAAAADVRyYWNrZWRPYmplY3QRVHJhY2tSZXN1cnJlY3Rpb24EAApTeXN0ZW0uVXJpAgAAAAEJAwAAAAEFAwAAAApTeXN0ZW0uVXJpAQAAAAtBYnNvbHV0ZVVyaQECAAAABgQAAAAQaHR0cHM6Ly9kb3QubmV0Lws=" } };
- yield return new object[] { new WeakReference<Point>(new Point(2, 3), true), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAEAAAC/AVN5c3RlbS5XZWFrUmVmZXJlbmNlYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAA1UcmFja2VkT2JqZWN0EVRyYWNrUmVzdXJyZWN0aW9uBAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAEKAQs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAEAAAC/AVN5c3RlbS5XZWFrUmVmZXJlbmNlYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAA1UcmFja2VkT2JqZWN0EVRyYWNrUmVzdXJyZWN0aW9uBAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAEKAQs=" } };
- yield return new object[] { new StringBuilder(), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uVGV4dC5TdHJpbmdCdWlsZGVyBAAAAA1tX01heENhcGFjaXR5CENhcGFjaXR5DW1fU3RyaW5nVmFsdWUPbV9jdXJyZW50VGhyZWFkAAABAAgICP///38QAAAABgIAAAAAAAAAAAs=", "AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uVGV4dC5TdHJpbmdCdWlsZGVyBAAAAA1tX01heENhcGFjaXR5CENhcGFjaXR5DW1fU3RyaW5nVmFsdWUPbV9jdXJyZW50VGhyZWFkAAABAAgICP///38QAAAABgIAAAAAAAAAAAs=" } };
- yield return new object[] { new StringBuilder("starting", 0, 5, 10), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uVGV4dC5TdHJpbmdCdWlsZGVyBAAAAA1tX01heENhcGFjaXR5CENhcGFjaXR5DW1fU3RyaW5nVmFsdWUPbV9jdXJyZW50VGhyZWFkAAABAAgICP///38KAAAABgIAAAAFc3RhcnQAAAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uVGV4dC5TdHJpbmdCdWlsZGVyBAAAAA1tX01heENhcGFjaXR5CENhcGFjaXR5DW1fU3RyaW5nVmFsdWUPbV9jdXJyZW50VGhyZWFkAAABAAgICP///38KAAAABgIAAAAFc3RhcnQAAAAACw==" } };
+ yield return new object[] { dotnetUri, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAKU3lzdGVtLlVyaQEAAAALQWJzb2x1dGVVcmkBAgAAAAYDAAAAEGh0dHBzOi8vZG90Lm5ldC8L", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAKU3lzdGVtLlVyaQEAAAALQWJzb2x1dGVVcmkBAgAAAAYDAAAAEGh0dHBzOi8vZG90Lm5ldC8L", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Uri(dotnetUri, "articles/info.html"), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAKU3lzdGVtLlVyaQEAAAALQWJzb2x1dGVVcmkBAgAAAAYDAAAAImh0dHBzOi8vZG90Lm5ldC9hcnRpY2xlcy9pbmZvLmh0bWwL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAKU3lzdGVtLlVyaQEAAAALQWJzb2x1dGVVcmkBAgAAAAYDAAAAImh0dHBzOi8vZG90Lm5ldC9hcnRpY2xlcy9pbmZvLmh0bWwL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new WeakReference(dotnetUri, true), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BAEAAAAUU3lzdGVtLldlYWtSZWZlcmVuY2UCAAAADVRyYWNrZWRPYmplY3QRVHJhY2tSZXN1cnJlY3Rpb24EAApTeXN0ZW0uVXJpAgAAAAEJAwAAAAEFAwAAAApTeXN0ZW0uVXJpAQAAAAtBYnNvbHV0ZVVyaQECAAAABgQAAAAQaHR0cHM6Ly9kb3QubmV0Lws=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BAEAAAAUU3lzdGVtLldlYWtSZWZlcmVuY2UCAAAADVRyYWNrZWRPYmplY3QRVHJhY2tSZXN1cnJlY3Rpb24EAApTeXN0ZW0uVXJpAgAAAAEJAwAAAAEFAwAAAApTeXN0ZW0uVXJpAQAAAAtBYnNvbHV0ZVVyaQECAAAABgQAAAAQaHR0cHM6Ly9kb3QubmV0Lws=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new WeakReference<Point>(new Point(2, 3), true), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAEAAAC/AVN5c3RlbS5XZWFrUmVmZXJlbmNlYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAA1UcmFja2VkT2JqZWN0EVRyYWNrUmVzdXJyZWN0aW9uBAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAEKAQs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAEAAAC/AVN5c3RlbS5XZWFrUmVmZXJlbmNlYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAA1UcmFja2VkT2JqZWN0EVRyYWNrUmVzdXJyZWN0aW9uBAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAEKAQs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new StringBuilder(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uVGV4dC5TdHJpbmdCdWlsZGVyBAAAAA1tX01heENhcGFjaXR5CENhcGFjaXR5DW1fU3RyaW5nVmFsdWUPbV9jdXJyZW50VGhyZWFkAAABAAgICP///38QAAAABgIAAAAAAAAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uVGV4dC5TdHJpbmdCdWlsZGVyBAAAAA1tX01heENhcGFjaXR5CENhcGFjaXR5DW1fU3RyaW5nVmFsdWUPbV9jdXJyZW50VGhyZWFkAAABAAgICP///38QAAAABgIAAAAAAAAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new StringBuilder("starting", 0, 5, 10), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uVGV4dC5TdHJpbmdCdWlsZGVyBAAAAA1tX01heENhcGFjaXR5CENhcGFjaXR5DW1fU3RyaW5nVmFsdWUPbV9jdXJyZW50VGhyZWFkAAABAAgICP///38KAAAABgIAAAAFc3RhcnQAAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABlTeXN0ZW0uVGV4dC5TdHJpbmdCdWlsZGVyBAAAAA1tX01heENhcGFjaXR5CENhcGFjaXR5DW1fU3RyaW5nVmFsdWUPbV9jdXJyZW50VGhyZWFkAAABAAgICP///38KAAAABgIAAAAFc3RhcnQAAAAACw==", TargetFrameworkMoniker.netfx461) } };
// Set a fixed timestamp for a Cookie field.
var cookie = new Cookie("name1", "value", "/path", "127.0.0.1");
typeof(Cookie)
.GetField("m_timeStamp", BindingFlags.Instance | BindingFlags.NonPublic)
.SetValue(cookie, s_fixedTimestamp);
- yield return new object[] { cookie, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAARU3lzdGVtLk5ldC5Db29raWUVAAAACW1fY29tbWVudAxtX2NvbW1lbnRVcmkPbV9jb29raWVWYXJpYW50CW1fZGlzY2FyZAhtX2RvbWFpbhFtX2RvbWFpbl9pbXBsaWNpdAltX2V4cGlyZXMGbV9uYW1lBm1fcGF0aA9tX3BhdGhfaW1wbGljaXQGbV9wb3J0D21fcG9ydF9pbXBsaWNpdAttX3BvcnRfbGlzdAhtX3NlY3VyZQptX2h0dHBPbmx5C21fdGltZVN0YW1wB21fdmFsdWUJbV92ZXJzaW9uC21fZG9tYWluS2V5D0lzUXVvdGVkVmVyc2lvbg5Jc1F1b3RlZERvbWFpbgEEBAABAAABAQABAAcAAAABAAEAAApTeXN0ZW0uVXJpAgAAABhTeXN0ZW0uTmV0LkNvb2tpZVZhcmlhbnQCAAAAAQENAQEIAQENCAEBAgAAAAYDAAAAAAoF/P///xhTeXN0ZW0uTmV0LkNvb2tpZVZhcmlhbnQBAAAAB3ZhbHVlX18ACAIAAAABAAAAAAYFAAAACTEyNy4wLjAuMQAAAAAAAAAAAAYGAAAABW5hbWUxBgcAAAAFL3BhdGgACQMAAAABCgAAgFhsCQ2+tQgGCQAAAAV2YWx1ZQAAAAAJAwAAAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAARU3lzdGVtLk5ldC5Db29raWUVAAAACW1fY29tbWVudAxtX2NvbW1lbnRVcmkPbV9jb29raWVWYXJpYW50CW1fZGlzY2FyZAhtX2RvbWFpbhFtX2RvbWFpbl9pbXBsaWNpdAltX2V4cGlyZXMGbV9uYW1lBm1fcGF0aA9tX3BhdGhfaW1wbGljaXQGbV9wb3J0D21fcG9ydF9pbXBsaWNpdAttX3BvcnRfbGlzdAhtX3NlY3VyZQptX2h0dHBPbmx5C21fdGltZVN0YW1wB21fdmFsdWUJbV92ZXJzaW9uC21fZG9tYWluS2V5D0lzUXVvdGVkVmVyc2lvbg5Jc1F1b3RlZERvbWFpbgEEBAABAAABAQABAAcAAAABAAEAAApTeXN0ZW0uVXJpAgAAABhTeXN0ZW0uTmV0LkNvb2tpZVZhcmlhbnQCAAAAAQENAQEIAQENCAEBAgAAAAYDAAAAAAoF/P///xhTeXN0ZW0uTmV0LkNvb2tpZVZhcmlhbnQBAAAAB3ZhbHVlX18ACAIAAAABAAAAAAYFAAAACTEyNy4wLjAuMQAAAAAAAAAAAAYGAAAABW5hbWUxBgcAAAAFL3BhdGgACQMAAAABCgAAgFhsCQ2+tQgGCQAAAAV2YWx1ZQAAAAAJAwAAAAAACw==" } };
+ yield return new object[] { cookie, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAARU3lzdGVtLk5ldC5Db29raWUVAAAACW1fY29tbWVudAxtX2NvbW1lbnRVcmkPbV9jb29raWVWYXJpYW50CW1fZGlzY2FyZAhtX2RvbWFpbhFtX2RvbWFpbl9pbXBsaWNpdAltX2V4cGlyZXMGbV9uYW1lBm1fcGF0aA9tX3BhdGhfaW1wbGljaXQGbV9wb3J0D21fcG9ydF9pbXBsaWNpdAttX3BvcnRfbGlzdAhtX3NlY3VyZQptX2h0dHBPbmx5C21fdGltZVN0YW1wB21fdmFsdWUJbV92ZXJzaW9uC21fZG9tYWluS2V5D0lzUXVvdGVkVmVyc2lvbg5Jc1F1b3RlZERvbWFpbgEEBAABAAABAQABAAcAAAABAAEAAApTeXN0ZW0uVXJpAgAAABhTeXN0ZW0uTmV0LkNvb2tpZVZhcmlhbnQCAAAAAQENAQEIAQENCAEBAgAAAAYDAAAAAAoF/P///xhTeXN0ZW0uTmV0LkNvb2tpZVZhcmlhbnQBAAAAB3ZhbHVlX18ACAIAAAABAAAAAAYFAAAACTEyNy4wLjAuMQAAAAAAAAAAAAYGAAAABW5hbWUxBgcAAAAFL3BhdGgACQMAAAABCgAAgFhsCQ2+tQgGCQAAAAV2YWx1ZQAAAAAJAwAAAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAARU3lzdGVtLk5ldC5Db29raWUVAAAACW1fY29tbWVudAxtX2NvbW1lbnRVcmkPbV9jb29raWVWYXJpYW50CW1fZGlzY2FyZAhtX2RvbWFpbhFtX2RvbWFpbl9pbXBsaWNpdAltX2V4cGlyZXMGbV9uYW1lBm1fcGF0aA9tX3BhdGhfaW1wbGljaXQGbV9wb3J0D21fcG9ydF9pbXBsaWNpdAttX3BvcnRfbGlzdAhtX3NlY3VyZQptX2h0dHBPbmx5C21fdGltZVN0YW1wB21fdmFsdWUJbV92ZXJzaW9uC21fZG9tYWluS2V5D0lzUXVvdGVkVmVyc2lvbg5Jc1F1b3RlZERvbWFpbgEEBAABAAABAQABAAcAAAABAAEAAApTeXN0ZW0uVXJpAgAAABhTeXN0ZW0uTmV0LkNvb2tpZVZhcmlhbnQCAAAAAQENAQEIAQENCAEBAgAAAAYDAAAAAAoF/P///xhTeXN0ZW0uTmV0LkNvb2tpZVZhcmlhbnQBAAAAB3ZhbHVlX18ACAIAAAABAAAAAAYFAAAACTEyNy4wLjAuMQAAAAAAAAAAAAYGAAAABW5hbWUxBgcAAAAFL3BhdGgACQMAAAABCgAAgFhsCQ2+tQgGCQAAAAV2YWx1ZQAAAAAJAwAAAAAACw==", TargetFrameworkMoniker.netfx461) } };
var cookieCollection = new CookieCollection { cookie };
- yield return new object[] { cookieCollection, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAbU3lzdGVtLk5ldC5Db29raWVDb2xsZWN0aW9uBAAAAAZtX2xpc3QJbV92ZXJzaW9uC21fVGltZVN0YW1wFG1faGFzX290aGVyX3ZlcnNpb25zAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0CA0BAgAAAAkDAAAAAQAAAAAAAAAAAAAAAAQDAAAAHFN5c3RlbS5Db2xsZWN0aW9ucy5BcnJheUxpc3QDAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgUAAAgICQQAAAABAAAAAQAAABAEAAAABAAAAAkFAAAADQMFBQAAABFTeXN0ZW0uTmV0LkNvb2tpZRUAAAAJbV9jb21tZW50DG1fY29tbWVudFVyaQ9tX2Nvb2tpZVZhcmlhbnQJbV9kaXNjYXJkCG1fZG9tYWluEW1fZG9tYWluX2ltcGxpY2l0CW1fZXhwaXJlcwZtX25hbWUGbV9wYXRoD21fcGF0aF9pbXBsaWNpdAZtX3BvcnQPbV9wb3J0X2ltcGxpY2l0C21fcG9ydF9saXN0CG1fc2VjdXJlCm1faHR0cE9ubHkLbV90aW1lU3RhbXAHbV92YWx1ZQltX3ZlcnNpb24LbV9kb21haW5LZXkPSXNRdW90ZWRWZXJzaW9uDklzUXVvdGVkRG9tYWluAQQEAAEAAAEBAAEABwAAAAEAAQAAClN5c3RlbS5VcmkCAAAAGFN5c3RlbS5OZXQuQ29va2llVmFyaWFudAIAAAABAQ0BAQgBAQ0IAQECAAAABgYAAAAACgX5////GFN5c3RlbS5OZXQuQ29va2llVmFyaWFudAEAAAAHdmFsdWVfXwAIAgAAAAEAAAAABggAAAAJMTI3LjAuMC4xAAAAAAAAAAAABgkAAAAFbmFtZTEGCgAAAAUvcGF0aAAJBgAAAAEKAACAWGwJDb61CAYMAAAABXZhbHVlAAAAAAkGAAAAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAbU3lzdGVtLk5ldC5Db29raWVDb2xsZWN0aW9uBQAAAAltX3ZlcnNpb24GbV9saXN0C21fVGltZVN0YW1wFG1faGFzX290aGVyX3ZlcnNpb25zDG1fSXNSZWFkT25seQADAAAACBxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0DQEBAgAAAAEAAAAJAwAAAAAAAAAAAAAAAAEEAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkEAAAAAQAAAAEAAAAQBAAAAAQAAAAJBQAAAA0DBQUAAAARU3lzdGVtLk5ldC5Db29raWUVAAAACW1fY29tbWVudAxtX2NvbW1lbnRVcmkPbV9jb29raWVWYXJpYW50CW1fZGlzY2FyZAhtX2RvbWFpbhFtX2RvbWFpbl9pbXBsaWNpdAltX2V4cGlyZXMGbV9uYW1lBm1fcGF0aA9tX3BhdGhfaW1wbGljaXQGbV9wb3J0D21fcG9ydF9pbXBsaWNpdAttX3BvcnRfbGlzdAhtX3NlY3VyZQptX2h0dHBPbmx5C21fdGltZVN0YW1wB21fdmFsdWUJbV92ZXJzaW9uC21fZG9tYWluS2V5D0lzUXVvdGVkVmVyc2lvbg5Jc1F1b3RlZERvbWFpbgEEBAABAAABAQABAAcAAAABAAEAAApTeXN0ZW0uVXJpAgAAABhTeXN0ZW0uTmV0LkNvb2tpZVZhcmlhbnQCAAAAAQENAQEIAQENCAEBAgAAAAYGAAAAAAoF+f///xhTeXN0ZW0uTmV0LkNvb2tpZVZhcmlhbnQBAAAAB3ZhbHVlX18ACAIAAAABAAAAAAYIAAAACTEyNy4wLjAuMQAAAAAAAAAAAAYJAAAABW5hbWUxBgoAAAAFL3BhdGgACQYAAAABCgAAgFhsCQ2+tQgGDAAAAAV2YWx1ZQAAAAAJBgAAAAAACw==" } };
+ yield return new object[] { cookieCollection, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAbU3lzdGVtLk5ldC5Db29raWVDb2xsZWN0aW9uBAAAAAZtX2xpc3QJbV92ZXJzaW9uC21fVGltZVN0YW1wFG1faGFzX290aGVyX3ZlcnNpb25zAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0CA0BAgAAAAkDAAAAAQAAAAAAAAAAAAAAAAQDAAAAHFN5c3RlbS5Db2xsZWN0aW9ucy5BcnJheUxpc3QDAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgUAAAgICQQAAAABAAAAAQAAABAEAAAABAAAAAkFAAAADQMFBQAAABFTeXN0ZW0uTmV0LkNvb2tpZRUAAAAJbV9jb21tZW50DG1fY29tbWVudFVyaQ9tX2Nvb2tpZVZhcmlhbnQJbV9kaXNjYXJkCG1fZG9tYWluEW1fZG9tYWluX2ltcGxpY2l0CW1fZXhwaXJlcwZtX25hbWUGbV9wYXRoD21fcGF0aF9pbXBsaWNpdAZtX3BvcnQPbV9wb3J0X2ltcGxpY2l0C21fcG9ydF9saXN0CG1fc2VjdXJlCm1faHR0cE9ubHkLbV90aW1lU3RhbXAHbV92YWx1ZQltX3ZlcnNpb24LbV9kb21haW5LZXkPSXNRdW90ZWRWZXJzaW9uDklzUXVvdGVkRG9tYWluAQQEAAEAAAEBAAEABwAAAAEAAQAAClN5c3RlbS5VcmkCAAAAGFN5c3RlbS5OZXQuQ29va2llVmFyaWFudAIAAAABAQ0BAQgBAQ0IAQECAAAABgYAAAAACgX5////GFN5c3RlbS5OZXQuQ29va2llVmFyaWFudAEAAAAHdmFsdWVfXwAIAgAAAAEAAAAABggAAAAJMTI3LjAuMC4xAAAAAAAAAAAABgkAAAAFbmFtZTEGCgAAAAUvcGF0aAAJBgAAAAEKAACAWGwJDb61CAYMAAAABXZhbHVlAAAAAAkGAAAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAbU3lzdGVtLk5ldC5Db29raWVDb2xsZWN0aW9uBQAAAAltX3ZlcnNpb24GbV9saXN0C21fVGltZVN0YW1wFG1faGFzX290aGVyX3ZlcnNpb25zDG1fSXNSZWFkT25seQADAAAACBxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0DQEBAgAAAAEAAAAJAwAAAAAAAAAAAAAAAAEEAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkEAAAAAQAAAAEAAAAQBAAAAAQAAAAJBQAAAA0DBQUAAAARU3lzdGVtLk5ldC5Db29raWUVAAAACW1fY29tbWVudAxtX2NvbW1lbnRVcmkPbV9jb29raWVWYXJpYW50CW1fZGlzY2FyZAhtX2RvbWFpbhFtX2RvbWFpbl9pbXBsaWNpdAltX2V4cGlyZXMGbV9uYW1lBm1fcGF0aA9tX3BhdGhfaW1wbGljaXQGbV9wb3J0D21fcG9ydF9pbXBsaWNpdAttX3BvcnRfbGlzdAhtX3NlY3VyZQptX2h0dHBPbmx5C21fdGltZVN0YW1wB21fdmFsdWUJbV92ZXJzaW9uC21fZG9tYWluS2V5D0lzUXVvdGVkVmVyc2lvbg5Jc1F1b3RlZERvbWFpbgEEBAABAAABAQABAAcAAAABAAEAAApTeXN0ZW0uVXJpAgAAABhTeXN0ZW0uTmV0LkNvb2tpZVZhcmlhbnQCAAAAAQENAQEIAQENCAEBAgAAAAYGAAAAAAoF+f///xhTeXN0ZW0uTmV0LkNvb2tpZVZhcmlhbnQBAAAAB3ZhbHVlX18ACAIAAAABAAAAAAYIAAAACTEyNy4wLjAuMQAAAAAAAAAAAAYJAAAABW5hbWUxBgoAAAAFL3BhdGgACQYAAAABCgAAgFhsCQ2+tQgGDAAAAAV2YWx1ZQAAAAAJBgAAAAAACw==", TargetFrameworkMoniker.netfx461) } };
var cookieContainer = new CookieContainer(10, 5, 1024);
// To avoid differences in generated blobs because of machine configuration (domain).
typeof(CookieContainer)
.GetField("m_fqdnMyDomain", BindingFlags.Instance | BindingFlags.NonPublic)
.SetValue(cookieContainer, string.Empty);
cookieContainer.Add(cookie);
- yield return new object[] { cookieContainer, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAaU3lzdGVtLk5ldC5Db29raWVDb250YWluZXIGAAAADW1fZG9tYWluVGFibGUPbV9tYXhDb29raWVTaXplDG1fbWF4Q29va2llcxVtX21heENvb2tpZXNQZXJEb21haW4HbV9jb3VudA5tX2ZxZG5NeURvbWFpbgMAAAAAARxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlCAgICAIAAAAJAwAAAAAEAAAKAAAABQAAAAEAAAAGBAAAAAAEAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBwAAAApMb2FkRmFjdG9yB1ZlcnNpb24IQ29tcGFyZXIQSGFzaENvZGVQcm92aWRlcghIYXNoU2l6ZQRLZXlzBlZhbHVlcwAAAwMABQULCBxTeXN0ZW0uQ29sbGVjdGlvbnMuSUNvbXBhcmVyJFN5c3RlbS5Db2xsZWN0aW9ucy5JSGFzaENvZGVQcm92aWRlcgjsUTg/AQAAAAoKAwAAAAkFAAAACQYAAAAQBQAAAAEAAAAGBwAAAAouMTI3LjAuMC4xEAYAAAABAAAACQgAAAAFCAAAABNTeXN0ZW0uTmV0LlBhdGhMaXN0AQAAAAZtX2xpc3QDLFN5c3RlbS5Db2xsZWN0aW9ucy5Tb3J0ZWRMaXN0K1N5bmNTb3J0ZWRMaXN0AgAAAAkJAAAABAkAAAAsU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QrU3luY1NvcnRlZExpc3QJAAAABV9saXN0BV9yb290D1NvcnRlZExpc3Qra2V5cxFTb3J0ZWRMaXN0K3ZhbHVlcxBTb3J0ZWRMaXN0K19zaXplElNvcnRlZExpc3QrdmVyc2lvbhNTb3J0ZWRMaXN0K2NvbXBhcmVyElNvcnRlZExpc3Qra2V5TGlzdBRTb3J0ZWRMaXN0K3ZhbHVlTGlzdAMCBQUAAAMDAx1TeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdAgIG1N5c3RlbS5Db2xsZWN0aW9ucy5Db21wYXJlciVTeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdCtLZXlMaXN0J1N5c3RlbS5Db2xsZWN0aW9ucy5Tb3J0ZWRMaXN0K1ZhbHVlTGlzdAkKAAAACQsAAAAJDAAAAAkMAAAAAAAAAAAAAAAJDQAAAAoKBAoAAAAdU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QHAAAABGtleXMGdmFsdWVzBV9zaXplB3ZlcnNpb24IY29tcGFyZXIHa2V5TGlzdAl2YWx1ZUxpc3QFBQAABAMDCAgkU3lzdGVtLk5ldC5QYXRoTGlzdCtQYXRoTGlzdENvbXBhcmVyAgAAACVTeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdCtLZXlMaXN0J1N5c3RlbS5Db2xsZWN0aW9ucy5Tb3J0ZWRMaXN0K1ZhbHVlTGlzdAkOAAAACQ8AAAABAAAAAQAAAAkQAAAACgkRAAAABAsAAAANU3lzdGVtLk9iamVjdAAAAAAQDAAAAAAAAAAEDQAAABtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXIBAAAAC0NvbXBhcmVJbmZvAyBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwkSAAAAEA4AAAAQAAAABhMAAAAFL3BhdGgNDxAPAAAAEAAAAAkUAAAADQ8FEAAAACRTeXN0ZW0uTmV0LlBhdGhMaXN0K1BhdGhMaXN0Q29tcGFyZXIAAAAAAgAAAAQRAAAAJ1N5c3RlbS5Db2xsZWN0aW9ucy5Tb3J0ZWRMaXN0K1ZhbHVlTGlzdAEAAAAKc29ydGVkTGlzdAMdU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QJCgAAAAQSAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvAwAAAAZtX25hbWUNbV9Tb3J0VmVyc2lvbgdjdWx0dXJlAQMAIFN5c3RlbS5HbG9iYWxpemF0aW9uLlNvcnRWZXJzaW9uCAkEAAAACn8AAAAFFAAAABtTeXN0ZW0uTmV0LkNvb2tpZUNvbGxlY3Rpb24EAAAABm1fbGlzdAltX3ZlcnNpb24LbV9UaW1lU3RhbXAUbV9oYXNfb3RoZXJfdmVyc2lvbnMDAAAAHFN5c3RlbS5Db2xsZWN0aW9ucy5BcnJheUxpc3QIDQECAAAACRcAAAABAAAAAAAAAAAAAAABBBcAAAAcU3lzdGVtLkNvbGxlY3Rpb25zLkFycmF5TGlzdAMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBQAACAgJGAAAAAEAAAABAAAAEBgAAAAEAAAACRkAAAANAwUZAAAAEVN5c3RlbS5OZXQuQ29va2llFQAAAAltX2NvbW1lbnQMbV9jb21tZW50VXJpD21fY29va2llVmFyaWFudAltX2Rpc2NhcmQIbV9kb21haW4RbV9kb21haW5faW1wbGljaXQJbV9leHBpcmVzBm1fbmFtZQZtX3BhdGgPbV9wYXRoX2ltcGxpY2l0Bm1fcG9ydA9tX3BvcnRfaW1wbGljaXQLbV9wb3J0X2xpc3QIbV9zZWN1cmUKbV9odHRwT25seQttX3RpbWVTdGFtcAdtX3ZhbHVlCW1fdmVyc2lvbgttX2RvbWFpbktleQ9Jc1F1b3RlZFZlcnNpb24OSXNRdW90ZWREb21haW4BBAQAAQAAAQEAAQAHAAAAAQABAAAKU3lzdGVtLlVyaQIAAAAYU3lzdGVtLk5ldC5Db29raWVWYXJpYW50AgAAAAEBDQEBCAEBDQgBAQIAAAAJBAAAAAoF5f///xhTeXN0ZW0uTmV0LkNvb2tpZVZhcmlhbnQBAAAAB3ZhbHVlX18ACAIAAAABAAAAAAYcAAAACTEyNy4wLjAuMQAAAAAAAAAAAAYdAAAABW5hbWUxCRMAAAAACQQAAAABCgAAgFhsCQ2+tQgGIAAAAAV2YWx1ZQAAAAAJBwAAAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAaU3lzdGVtLk5ldC5Db29raWVDb250YWluZXIGAAAADW1fZG9tYWluVGFibGUPbV9tYXhDb29raWVTaXplDG1fbWF4Q29va2llcxVtX21heENvb2tpZXNQZXJEb21haW4HbV9jb3VudA5tX2ZxZG5NeURvbWFpbgMAAAAAARxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlCAgICAIAAAAJAwAAAAAEAAAKAAAABQAAAAEAAAAGBAAAAAAEAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBwAAAApMb2FkRmFjdG9yB1ZlcnNpb24IQ29tcGFyZXIQSGFzaENvZGVQcm92aWRlcghIYXNoU2l6ZQRLZXlzBlZhbHVlcwAAAwMABQULCBxTeXN0ZW0uQ29sbGVjdGlvbnMuSUNvbXBhcmVyJFN5c3RlbS5Db2xsZWN0aW9ucy5JSGFzaENvZGVQcm92aWRlcgjsUTg/AQAAAAoKAwAAAAkFAAAACQYAAAAQBQAAAAEAAAAGBwAAAAouMTI3LjAuMC4xEAYAAAABAAAACQgAAAAFCAAAABNTeXN0ZW0uTmV0LlBhdGhMaXN0AQAAAAZtX2xpc3QDLFN5c3RlbS5Db2xsZWN0aW9ucy5Tb3J0ZWRMaXN0K1N5bmNTb3J0ZWRMaXN0AgAAAAkJAAAABAkAAAAsU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QrU3luY1NvcnRlZExpc3QJAAAABV9saXN0BV9yb290D1NvcnRlZExpc3Qra2V5cxFTb3J0ZWRMaXN0K3ZhbHVlcxBTb3J0ZWRMaXN0K19zaXplElNvcnRlZExpc3QrdmVyc2lvbhNTb3J0ZWRMaXN0K2NvbXBhcmVyElNvcnRlZExpc3Qra2V5TGlzdBRTb3J0ZWRMaXN0K3ZhbHVlTGlzdAMCBQUAAAMDAx1TeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdAgIG1N5c3RlbS5Db2xsZWN0aW9ucy5Db21wYXJlciVTeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdCtLZXlMaXN0J1N5c3RlbS5Db2xsZWN0aW9ucy5Tb3J0ZWRMaXN0K1ZhbHVlTGlzdAkKAAAACQsAAAAJDAAAAAkMAAAAAAAAAAAAAAAJDQAAAAoKBAoAAAAdU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QHAAAABGtleXMGdmFsdWVzBV9zaXplB3ZlcnNpb24IY29tcGFyZXIHa2V5TGlzdAl2YWx1ZUxpc3QFBQAABAMDCAgkU3lzdGVtLk5ldC5QYXRoTGlzdCtQYXRoTGlzdENvbXBhcmVyAgAAACVTeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdCtLZXlMaXN0J1N5c3RlbS5Db2xsZWN0aW9ucy5Tb3J0ZWRMaXN0K1ZhbHVlTGlzdAkOAAAACQ8AAAABAAAAAQAAAAkQAAAACgkRAAAABAsAAAANU3lzdGVtLk9iamVjdAAAAAAQDAAAAAAAAAAEDQAAABtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXIBAAAAC0NvbXBhcmVJbmZvAyBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwkSAAAAEA4AAAAQAAAABhMAAAAFL3BhdGgNDxAPAAAAEAAAAAkUAAAADQ8FEAAAACRTeXN0ZW0uTmV0LlBhdGhMaXN0K1BhdGhMaXN0Q29tcGFyZXIAAAAAAgAAAAQRAAAAJ1N5c3RlbS5Db2xsZWN0aW9ucy5Tb3J0ZWRMaXN0K1ZhbHVlTGlzdAEAAAAKc29ydGVkTGlzdAMdU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QJCgAAAAQSAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvBAAAAAZtX25hbWUJd2luMzJMQ0lEB2N1bHR1cmUNbV9Tb3J0VmVyc2lvbgEAAAMICCBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbgkEAAAAAAAAAH8AAAAKBRQAAAAbU3lzdGVtLk5ldC5Db29raWVDb2xsZWN0aW9uBQAAAAltX3ZlcnNpb24GbV9saXN0C21fVGltZVN0YW1wFG1faGFzX290aGVyX3ZlcnNpb25zDG1fSXNSZWFkT25seQADAAAACBxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0DQEBAgAAAAAAAAAJFwAAAAAAAAAAAAAAAQEEFwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkYAAAAAQAAAAEAAAAQGAAAAAQAAAAJGQAAAA0DBRkAAAARU3lzdGVtLk5ldC5Db29raWUVAAAACW1fY29tbWVudAxtX2NvbW1lbnRVcmkPbV9jb29raWVWYXJpYW50CW1fZGlzY2FyZAhtX2RvbWFpbhFtX2RvbWFpbl9pbXBsaWNpdAltX2V4cGlyZXMGbV9uYW1lBm1fcGF0aA9tX3BhdGhfaW1wbGljaXQGbV9wb3J0D21fcG9ydF9pbXBsaWNpdAttX3BvcnRfbGlzdAhtX3NlY3VyZQptX2h0dHBPbmx5C21fdGltZVN0YW1wB21fdmFsdWUJbV92ZXJzaW9uC21fZG9tYWluS2V5D0lzUXVvdGVkVmVyc2lvbg5Jc1F1b3RlZERvbWFpbgEEBAABAAABAQABAAcAAAABAAEAAApTeXN0ZW0uVXJpAgAAABhTeXN0ZW0uTmV0LkNvb2tpZVZhcmlhbnQCAAAAAQENAQEIAQENCAEBAgAAAAkEAAAACgXl////GFN5c3RlbS5OZXQuQ29va2llVmFyaWFudAEAAAAHdmFsdWVfXwAIAgAAAAEAAAAABhwAAAAJMTI3LjAuMC4xAAAAAAAAAAAABh0AAAAFbmFtZTEJEwAAAAAJBAAAAAEKAACAWGwJDb61CAYgAAAABXZhbHVlAAAAAAkHAAAAAAAL" } };
+ yield return new object[] { cookieContainer, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAaU3lzdGVtLk5ldC5Db29raWVDb250YWluZXIGAAAADW1fZG9tYWluVGFibGUPbV9tYXhDb29raWVTaXplDG1fbWF4Q29va2llcxVtX21heENvb2tpZXNQZXJEb21haW4HbV9jb3VudA5tX2ZxZG5NeURvbWFpbgMAAAAAARxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlCAgICAIAAAAJAwAAAAAEAAAKAAAABQAAAAEAAAAGBAAAAAAEAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBwAAAApMb2FkRmFjdG9yB1ZlcnNpb24IQ29tcGFyZXIQSGFzaENvZGVQcm92aWRlcghIYXNoU2l6ZQRLZXlzBlZhbHVlcwAAAwMABQULCBxTeXN0ZW0uQ29sbGVjdGlvbnMuSUNvbXBhcmVyJFN5c3RlbS5Db2xsZWN0aW9ucy5JSGFzaENvZGVQcm92aWRlcgjsUTg/AQAAAAoKAwAAAAkFAAAACQYAAAAQBQAAAAEAAAAGBwAAAAouMTI3LjAuMC4xEAYAAAABAAAACQgAAAAFCAAAABNTeXN0ZW0uTmV0LlBhdGhMaXN0AQAAAAZtX2xpc3QDLFN5c3RlbS5Db2xsZWN0aW9ucy5Tb3J0ZWRMaXN0K1N5bmNTb3J0ZWRMaXN0AgAAAAkJAAAABAkAAAAsU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QrU3luY1NvcnRlZExpc3QJAAAABV9saXN0BV9yb290D1NvcnRlZExpc3Qra2V5cxFTb3J0ZWRMaXN0K3ZhbHVlcxBTb3J0ZWRMaXN0K19zaXplElNvcnRlZExpc3QrdmVyc2lvbhNTb3J0ZWRMaXN0K2NvbXBhcmVyElNvcnRlZExpc3Qra2V5TGlzdBRTb3J0ZWRMaXN0K3ZhbHVlTGlzdAMCBQUAAAMDAx1TeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdAgIG1N5c3RlbS5Db2xsZWN0aW9ucy5Db21wYXJlciVTeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdCtLZXlMaXN0J1N5c3RlbS5Db2xsZWN0aW9ucy5Tb3J0ZWRMaXN0K1ZhbHVlTGlzdAkKAAAACQsAAAAJDAAAAAkMAAAAAAAAAAAAAAAJDQAAAAoKBAoAAAAdU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QHAAAABGtleXMGdmFsdWVzBV9zaXplB3ZlcnNpb24IY29tcGFyZXIHa2V5TGlzdAl2YWx1ZUxpc3QFBQAABAMDCAgkU3lzdGVtLk5ldC5QYXRoTGlzdCtQYXRoTGlzdENvbXBhcmVyAgAAACVTeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdCtLZXlMaXN0J1N5c3RlbS5Db2xsZWN0aW9ucy5Tb3J0ZWRMaXN0K1ZhbHVlTGlzdAkOAAAACQ8AAAABAAAAAQAAAAkQAAAACgkRAAAABAsAAAANU3lzdGVtLk9iamVjdAAAAAAQDAAAAAAAAAAEDQAAABtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXIBAAAAC0NvbXBhcmVJbmZvAyBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwkSAAAAEA4AAAAQAAAABhMAAAAFL3BhdGgNDxAPAAAAEAAAAAkUAAAADQ8FEAAAACRTeXN0ZW0uTmV0LlBhdGhMaXN0K1BhdGhMaXN0Q29tcGFyZXIAAAAAAgAAAAQRAAAAJ1N5c3RlbS5Db2xsZWN0aW9ucy5Tb3J0ZWRMaXN0K1ZhbHVlTGlzdAEAAAAKc29ydGVkTGlzdAMdU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QJCgAAAAQSAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvAwAAAAZtX25hbWUNbV9Tb3J0VmVyc2lvbgdjdWx0dXJlAQMAIFN5c3RlbS5HbG9iYWxpemF0aW9uLlNvcnRWZXJzaW9uCAkEAAAACn8AAAAFFAAAABtTeXN0ZW0uTmV0LkNvb2tpZUNvbGxlY3Rpb24EAAAABm1fbGlzdAltX3ZlcnNpb24LbV9UaW1lU3RhbXAUbV9oYXNfb3RoZXJfdmVyc2lvbnMDAAAAHFN5c3RlbS5Db2xsZWN0aW9ucy5BcnJheUxpc3QIDQECAAAACRcAAAABAAAAAAAAAAAAAAABBBcAAAAcU3lzdGVtLkNvbGxlY3Rpb25zLkFycmF5TGlzdAMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBQAACAgJGAAAAAEAAAABAAAAEBgAAAAEAAAACRkAAAANAwUZAAAAEVN5c3RlbS5OZXQuQ29va2llFQAAAAltX2NvbW1lbnQMbV9jb21tZW50VXJpD21fY29va2llVmFyaWFudAltX2Rpc2NhcmQIbV9kb21haW4RbV9kb21haW5faW1wbGljaXQJbV9leHBpcmVzBm1fbmFtZQZtX3BhdGgPbV9wYXRoX2ltcGxpY2l0Bm1fcG9ydA9tX3BvcnRfaW1wbGljaXQLbV9wb3J0X2xpc3QIbV9zZWN1cmUKbV9odHRwT25seQttX3RpbWVTdGFtcAdtX3ZhbHVlCW1fdmVyc2lvbgttX2RvbWFpbktleQ9Jc1F1b3RlZFZlcnNpb24OSXNRdW90ZWREb21haW4BBAQAAQAAAQEAAQAHAAAAAQABAAAKU3lzdGVtLlVyaQIAAAAYU3lzdGVtLk5ldC5Db29raWVWYXJpYW50AgAAAAEBDQEBCAEBDQgBAQIAAAAJBAAAAAoF5f///xhTeXN0ZW0uTmV0LkNvb2tpZVZhcmlhbnQBAAAAB3ZhbHVlX18ACAIAAAABAAAAAAYcAAAACTEyNy4wLjAuMQAAAAAAAAAAAAYdAAAABW5hbWUxCRMAAAAACQQAAAABCgAAgFhsCQ2+tQgGIAAAAAV2YWx1ZQAAAAAJBwAAAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAaU3lzdGVtLk5ldC5Db29raWVDb250YWluZXIGAAAADW1fZG9tYWluVGFibGUPbV9tYXhDb29raWVTaXplDG1fbWF4Q29va2llcxVtX21heENvb2tpZXNQZXJEb21haW4HbV9jb3VudA5tX2ZxZG5NeURvbWFpbgMAAAAAARxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlCAgICAIAAAAJAwAAAAAEAAAKAAAABQAAAAEAAAAGBAAAAAAEAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBwAAAApMb2FkRmFjdG9yB1ZlcnNpb24IQ29tcGFyZXIQSGFzaENvZGVQcm92aWRlcghIYXNoU2l6ZQRLZXlzBlZhbHVlcwAAAwMABQULCBxTeXN0ZW0uQ29sbGVjdGlvbnMuSUNvbXBhcmVyJFN5c3RlbS5Db2xsZWN0aW9ucy5JSGFzaENvZGVQcm92aWRlcgjsUTg/AQAAAAoKAwAAAAkFAAAACQYAAAAQBQAAAAEAAAAGBwAAAAouMTI3LjAuMC4xEAYAAAABAAAACQgAAAAFCAAAABNTeXN0ZW0uTmV0LlBhdGhMaXN0AQAAAAZtX2xpc3QDLFN5c3RlbS5Db2xsZWN0aW9ucy5Tb3J0ZWRMaXN0K1N5bmNTb3J0ZWRMaXN0AgAAAAkJAAAABAkAAAAsU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QrU3luY1NvcnRlZExpc3QJAAAABV9saXN0BV9yb290D1NvcnRlZExpc3Qra2V5cxFTb3J0ZWRMaXN0K3ZhbHVlcxBTb3J0ZWRMaXN0K19zaXplElNvcnRlZExpc3QrdmVyc2lvbhNTb3J0ZWRMaXN0K2NvbXBhcmVyElNvcnRlZExpc3Qra2V5TGlzdBRTb3J0ZWRMaXN0K3ZhbHVlTGlzdAMCBQUAAAMDAx1TeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdAgIG1N5c3RlbS5Db2xsZWN0aW9ucy5Db21wYXJlciVTeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdCtLZXlMaXN0J1N5c3RlbS5Db2xsZWN0aW9ucy5Tb3J0ZWRMaXN0K1ZhbHVlTGlzdAkKAAAACQsAAAAJDAAAAAkMAAAAAAAAAAAAAAAJDQAAAAoKBAoAAAAdU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QHAAAABGtleXMGdmFsdWVzBV9zaXplB3ZlcnNpb24IY29tcGFyZXIHa2V5TGlzdAl2YWx1ZUxpc3QFBQAABAMDCAgkU3lzdGVtLk5ldC5QYXRoTGlzdCtQYXRoTGlzdENvbXBhcmVyAgAAACVTeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdCtLZXlMaXN0J1N5c3RlbS5Db2xsZWN0aW9ucy5Tb3J0ZWRMaXN0K1ZhbHVlTGlzdAkOAAAACQ8AAAABAAAAAQAAAAkQAAAACgkRAAAABAsAAAANU3lzdGVtLk9iamVjdAAAAAAQDAAAAAAAAAAEDQAAABtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXIBAAAAC0NvbXBhcmVJbmZvAyBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwkSAAAAEA4AAAAQAAAABhMAAAAFL3BhdGgNDxAPAAAAEAAAAAkUAAAADQ8FEAAAACRTeXN0ZW0uTmV0LlBhdGhMaXN0K1BhdGhMaXN0Q29tcGFyZXIAAAAAAgAAAAQRAAAAJ1N5c3RlbS5Db2xsZWN0aW9ucy5Tb3J0ZWRMaXN0K1ZhbHVlTGlzdAEAAAAKc29ydGVkTGlzdAMdU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QJCgAAAAQSAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvBAAAAAZtX25hbWUJd2luMzJMQ0lEB2N1bHR1cmUNbV9Tb3J0VmVyc2lvbgEAAAMICCBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbgkEAAAAAAAAAH8AAAAKBRQAAAAbU3lzdGVtLk5ldC5Db29raWVDb2xsZWN0aW9uBQAAAAltX3ZlcnNpb24GbV9saXN0C21fVGltZVN0YW1wFG1faGFzX290aGVyX3ZlcnNpb25zDG1fSXNSZWFkT25seQADAAAACBxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0DQEBAgAAAAAAAAAJFwAAAAAAAAAAAAAAAQEEFwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkYAAAAAQAAAAEAAAAQGAAAAAQAAAAJGQAAAA0DBRkAAAARU3lzdGVtLk5ldC5Db29raWUVAAAACW1fY29tbWVudAxtX2NvbW1lbnRVcmkPbV9jb29raWVWYXJpYW50CW1fZGlzY2FyZAhtX2RvbWFpbhFtX2RvbWFpbl9pbXBsaWNpdAltX2V4cGlyZXMGbV9uYW1lBm1fcGF0aA9tX3BhdGhfaW1wbGljaXQGbV9wb3J0D21fcG9ydF9pbXBsaWNpdAttX3BvcnRfbGlzdAhtX3NlY3VyZQptX2h0dHBPbmx5C21fdGltZVN0YW1wB21fdmFsdWUJbV92ZXJzaW9uC21fZG9tYWluS2V5D0lzUXVvdGVkVmVyc2lvbg5Jc1F1b3RlZERvbWFpbgEEBAABAAABAQABAAcAAAABAAEAAApTeXN0ZW0uVXJpAgAAABhTeXN0ZW0uTmV0LkNvb2tpZVZhcmlhbnQCAAAAAQENAQEIAQENCAEBAgAAAAkEAAAACgXl////GFN5c3RlbS5OZXQuQ29va2llVmFyaWFudAEAAAAHdmFsdWVfXwAIAgAAAAEAAAAABhwAAAAJMTI3LjAuMC4xAAAAAAAAAAAABh0AAAAFbmFtZTEJEwAAAAAJBAAAAAEKAACAWGwJDb61CAYgAAAABXZhbHVlAAAAAAkHAAAAAAAL", TargetFrameworkMoniker.netfx461) } };
- yield return new object[] { new DataSet("Dataset") { Locale = CultureInfo.InvariantCulture }, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABNTeXN0ZW0uRGF0YS5EYXRhU2V0AwAAABdEYXRhU2V0LlJlbW90aW5nVmVyc2lvbglYbWxTY2hlbWELWG1sRGlmZkdyYW0DAQEOU3lzdGVtLlZlcnNpb24CAAAACQMAAAAGBAAAAPcCPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+DQo8eHM6c2NoZW1hIGlkPSJEYXRhc2V0IiB4bWxucz0iIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIj4NCiAgPHhzOmVsZW1lbnQgbmFtZT0iRGF0YXNldCIgbXNkYXRhOklzRGF0YVNldD0idHJ1ZSIgbXNkYXRhOkxvY2FsZT0iIj4NCiAgICA8eHM6Y29tcGxleFR5cGU+DQogICAgICA8eHM6Y2hvaWNlIG1pbk9jY3Vycz0iMCIgbWF4T2NjdXJzPSJ1bmJvdW5kZWQiIC8+DQogICAgPC94czpjb21wbGV4VHlwZT4NCiAgPC94czplbGVtZW50Pg0KPC94czpzY2hlbWE+BgUAAACAATxkaWZmZ3I6ZGlmZmdyYW0geG1sbnM6bXNkYXRhPSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOnhtbC1tc2RhdGEiIHhtbG5zOmRpZmZncj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtZGlmZmdyYW0tdjEiIC8+BAMAAAAOU3lzdGVtLlZlcnNpb24EAAAABl9NYWpvcgZfTWlub3IGX0J1aWxkCV9SZXZpc2lvbgAAAAAICAgIAgAAAAAAAAD//////////ws=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABNTeXN0ZW0uRGF0YS5EYXRhU2V0AwAAABdEYXRhU2V0LlJlbW90aW5nVmVyc2lvbglYbWxTY2hlbWELWG1sRGlmZkdyYW0DAQEOU3lzdGVtLlZlcnNpb24CAAAACQMAAAAGBAAAAPcCPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+DQo8eHM6c2NoZW1hIGlkPSJEYXRhc2V0IiB4bWxucz0iIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIj4NCiAgPHhzOmVsZW1lbnQgbmFtZT0iRGF0YXNldCIgbXNkYXRhOklzRGF0YVNldD0idHJ1ZSIgbXNkYXRhOkxvY2FsZT0iIj4NCiAgICA8eHM6Y29tcGxleFR5cGU+DQogICAgICA8eHM6Y2hvaWNlIG1pbk9jY3Vycz0iMCIgbWF4T2NjdXJzPSJ1bmJvdW5kZWQiIC8+DQogICAgPC94czpjb21wbGV4VHlwZT4NCiAgPC94czplbGVtZW50Pg0KPC94czpzY2hlbWE+BgUAAACAATxkaWZmZ3I6ZGlmZmdyYW0geG1sbnM6bXNkYXRhPSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOnhtbC1tc2RhdGEiIHhtbG5zOmRpZmZncj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtZGlmZmdyYW0tdjEiIC8+BAMAAAAOU3lzdGVtLlZlcnNpb24EAAAABl9NYWpvcgZfTWlub3IGX0J1aWxkCV9SZXZpc2lvbgAAAAAICAgIAgAAAAAAAAD//////////ws=" } };
- yield return new object[] { new DataSet() { Locale = CultureInfo.InvariantCulture }, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABNTeXN0ZW0uRGF0YS5EYXRhU2V0AwAAABdEYXRhU2V0LlJlbW90aW5nVmVyc2lvbglYbWxTY2hlbWELWG1sRGlmZkdyYW0DAQEOU3lzdGVtLlZlcnNpb24CAAAACQMAAAAGBAAAAP0CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+DQo8eHM6c2NoZW1hIGlkPSJOZXdEYXRhU2V0IiB4bWxucz0iIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIj4NCiAgPHhzOmVsZW1lbnQgbmFtZT0iTmV3RGF0YVNldCIgbXNkYXRhOklzRGF0YVNldD0idHJ1ZSIgbXNkYXRhOkxvY2FsZT0iIj4NCiAgICA8eHM6Y29tcGxleFR5cGU+DQogICAgICA8eHM6Y2hvaWNlIG1pbk9jY3Vycz0iMCIgbWF4T2NjdXJzPSJ1bmJvdW5kZWQiIC8+DQogICAgPC94czpjb21wbGV4VHlwZT4NCiAgPC94czplbGVtZW50Pg0KPC94czpzY2hlbWE+BgUAAACAATxkaWZmZ3I6ZGlmZmdyYW0geG1sbnM6bXNkYXRhPSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOnhtbC1tc2RhdGEiIHhtbG5zOmRpZmZncj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtZGlmZmdyYW0tdjEiIC8+BAMAAAAOU3lzdGVtLlZlcnNpb24EAAAABl9NYWpvcgZfTWlub3IGX0J1aWxkCV9SZXZpc2lvbgAAAAAICAgIAgAAAAAAAAD//////////ws=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABNTeXN0ZW0uRGF0YS5EYXRhU2V0AwAAABdEYXRhU2V0LlJlbW90aW5nVmVyc2lvbglYbWxTY2hlbWELWG1sRGlmZkdyYW0DAQEOU3lzdGVtLlZlcnNpb24CAAAACQMAAAAGBAAAAP0CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+DQo8eHM6c2NoZW1hIGlkPSJOZXdEYXRhU2V0IiB4bWxucz0iIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIj4NCiAgPHhzOmVsZW1lbnQgbmFtZT0iTmV3RGF0YVNldCIgbXNkYXRhOklzRGF0YVNldD0idHJ1ZSIgbXNkYXRhOkxvY2FsZT0iIj4NCiAgICA8eHM6Y29tcGxleFR5cGU+DQogICAgICA8eHM6Y2hvaWNlIG1pbk9jY3Vycz0iMCIgbWF4T2NjdXJzPSJ1bmJvdW5kZWQiIC8+DQogICAgPC94czpjb21wbGV4VHlwZT4NCiAgPC94czplbGVtZW50Pg0KPC94czpzY2hlbWE+BgUAAACAATxkaWZmZ3I6ZGlmZmdyYW0geG1sbnM6bXNkYXRhPSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOnhtbC1tc2RhdGEiIHhtbG5zOmRpZmZncj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtZGlmZmdyYW0tdjEiIC8+BAMAAAAOU3lzdGVtLlZlcnNpb24EAAAABl9NYWpvcgZfTWlub3IGX0J1aWxkCV9SZXZpc2lvbgAAAAAICAgIAgAAAAAAAAD//////////ws=" } };
- yield return new object[] { new DataTable("Datatable", "corens") { Locale = CultureInfo.InvariantCulture }, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABVTeXN0ZW0uRGF0YS5EYXRhVGFibGUDAAAAGURhdGFUYWJsZS5SZW1vdGluZ1ZlcnNpb24JWG1sU2NoZW1hC1htbERpZmZHcmFtAwEBDlN5c3RlbS5WZXJzaW9uAgAAAAkDAAAABgQAAAD/BDw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi0xNiI/Pg0KPHhzOnNjaGVtYSB0YXJnZXROYW1lc3BhY2U9ImNvcmVucyIgeG1sbnM6bXN0bnM9ImNvcmVucyIgeG1sbnM9ImNvcmVucyIgeG1sbnM6eHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hIiB4bWxuczptc2RhdGE9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLW1zZGF0YSIgYXR0cmlidXRlRm9ybURlZmF1bHQ9InF1YWxpZmllZCIgZWxlbWVudEZvcm1EZWZhdWx0PSJxdWFsaWZpZWQiPg0KICA8eHM6ZWxlbWVudCBuYW1lPSJEYXRhdGFibGUiIG1zZGF0YTpMb2NhbGU9IiI+DQogICAgPHhzOmNvbXBsZXhUeXBlPg0KICAgIDwveHM6Y29tcGxleFR5cGU+DQogIDwveHM6ZWxlbWVudD4NCiAgPHhzOmVsZW1lbnQgbmFtZT0idG1wRGF0YVNldCIgbXNkYXRhOklzRGF0YVNldD0idHJ1ZSIgbXNkYXRhOk1haW5EYXRhVGFibGU9ImNvcmVuc194MDAzQV9EYXRhdGFibGUiIG1zZGF0YTpMb2NhbGU9IiI+DQogICAgPHhzOmNvbXBsZXhUeXBlPg0KICAgICAgPHhzOmNob2ljZSBtaW5PY2N1cnM9IjAiIG1heE9jY3Vycz0idW5ib3VuZGVkIiAvPg0KICAgIDwveHM6Y29tcGxleFR5cGU+DQogIDwveHM6ZWxlbWVudD4NCjwveHM6c2NoZW1hPgYFAAAAgAE8ZGlmZmdyOmRpZmZncmFtIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIiB4bWxuczpkaWZmZ3I9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLWRpZmZncmFtLXYxIiAvPgQDAAAADlN5c3RlbS5WZXJzaW9uBAAAAAZfTWFqb3IGX01pbm9yBl9CdWlsZAlfUmV2aXNpb24AAAAACAgICAIAAAAAAAAA//////////8L", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABVTeXN0ZW0uRGF0YS5EYXRhVGFibGUDAAAAGURhdGFUYWJsZS5SZW1vdGluZ1ZlcnNpb24JWG1sU2NoZW1hC1htbERpZmZHcmFtAwEBDlN5c3RlbS5WZXJzaW9uAgAAAAkDAAAABgQAAAD/BDw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi0xNiI/Pg0KPHhzOnNjaGVtYSB0YXJnZXROYW1lc3BhY2U9ImNvcmVucyIgeG1sbnM6bXN0bnM9ImNvcmVucyIgeG1sbnM9ImNvcmVucyIgeG1sbnM6eHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hIiB4bWxuczptc2RhdGE9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLW1zZGF0YSIgYXR0cmlidXRlRm9ybURlZmF1bHQ9InF1YWxpZmllZCIgZWxlbWVudEZvcm1EZWZhdWx0PSJxdWFsaWZpZWQiPg0KICA8eHM6ZWxlbWVudCBuYW1lPSJEYXRhdGFibGUiIG1zZGF0YTpMb2NhbGU9IiI+DQogICAgPHhzOmNvbXBsZXhUeXBlPg0KICAgIDwveHM6Y29tcGxleFR5cGU+DQogIDwveHM6ZWxlbWVudD4NCiAgPHhzOmVsZW1lbnQgbmFtZT0idG1wRGF0YVNldCIgbXNkYXRhOklzRGF0YVNldD0idHJ1ZSIgbXNkYXRhOk1haW5EYXRhVGFibGU9ImNvcmVuc194MDAzQV9EYXRhdGFibGUiIG1zZGF0YTpMb2NhbGU9IiI+DQogICAgPHhzOmNvbXBsZXhUeXBlPg0KICAgICAgPHhzOmNob2ljZSBtaW5PY2N1cnM9IjAiIG1heE9jY3Vycz0idW5ib3VuZGVkIiAvPg0KICAgIDwveHM6Y29tcGxleFR5cGU+DQogIDwveHM6ZWxlbWVudD4NCjwveHM6c2NoZW1hPgYFAAAAgAE8ZGlmZmdyOmRpZmZncmFtIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIiB4bWxuczpkaWZmZ3I9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLWRpZmZncmFtLXYxIiAvPgQDAAAADlN5c3RlbS5WZXJzaW9uBAAAAAZfTWFqb3IGX01pbm9yBl9CdWlsZAlfUmV2aXNpb24AAAAACAgICAIAAAAAAAAA//////////8L" } };
- yield return new object[] { new DataTable("Datatable") { Locale = CultureInfo.InvariantCulture }, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABVTeXN0ZW0uRGF0YS5EYXRhVGFibGUDAAAAGURhdGFUYWJsZS5SZW1vdGluZ1ZlcnNpb24JWG1sU2NoZW1hC1htbERpZmZHcmFtAwEBDlN5c3RlbS5WZXJzaW9uAgAAAAkDAAAABgQAAAD+Azw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi0xNiI/Pg0KPHhzOnNjaGVtYSB4bWxucz0iIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIj4NCiAgPHhzOmVsZW1lbnQgbmFtZT0iRGF0YXRhYmxlIiBtc2RhdGE6TG9jYWxlPSIiPg0KICAgIDx4czpjb21wbGV4VHlwZT4NCiAgICA8L3hzOmNvbXBsZXhUeXBlPg0KICA8L3hzOmVsZW1lbnQ+DQogIDx4czplbGVtZW50IG5hbWU9InRtcERhdGFTZXQiIG1zZGF0YTpJc0RhdGFTZXQ9InRydWUiIG1zZGF0YTpNYWluRGF0YVRhYmxlPSJEYXRhdGFibGUiIG1zZGF0YTpMb2NhbGU9IiI+DQogICAgPHhzOmNvbXBsZXhUeXBlPg0KICAgICAgPHhzOmNob2ljZSBtaW5PY2N1cnM9IjAiIG1heE9jY3Vycz0idW5ib3VuZGVkIiAvPg0KICAgIDwveHM6Y29tcGxleFR5cGU+DQogIDwveHM6ZWxlbWVudD4NCjwveHM6c2NoZW1hPgYFAAAAgAE8ZGlmZmdyOmRpZmZncmFtIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIiB4bWxuczpkaWZmZ3I9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLWRpZmZncmFtLXYxIiAvPgQDAAAADlN5c3RlbS5WZXJzaW9uBAAAAAZfTWFqb3IGX01pbm9yBl9CdWlsZAlfUmV2aXNpb24AAAAACAgICAIAAAAAAAAA//////////8L", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABVTeXN0ZW0uRGF0YS5EYXRhVGFibGUDAAAAGURhdGFUYWJsZS5SZW1vdGluZ1ZlcnNpb24JWG1sU2NoZW1hC1htbERpZmZHcmFtAwEBDlN5c3RlbS5WZXJzaW9uAgAAAAkDAAAABgQAAAD+Azw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi0xNiI/Pg0KPHhzOnNjaGVtYSB4bWxucz0iIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIj4NCiAgPHhzOmVsZW1lbnQgbmFtZT0iRGF0YXRhYmxlIiBtc2RhdGE6TG9jYWxlPSIiPg0KICAgIDx4czpjb21wbGV4VHlwZT4NCiAgICA8L3hzOmNvbXBsZXhUeXBlPg0KICA8L3hzOmVsZW1lbnQ+DQogIDx4czplbGVtZW50IG5hbWU9InRtcERhdGFTZXQiIG1zZGF0YTpJc0RhdGFTZXQ9InRydWUiIG1zZGF0YTpNYWluRGF0YVRhYmxlPSJEYXRhdGFibGUiIG1zZGF0YTpMb2NhbGU9IiI+DQogICAgPHhzOmNvbXBsZXhUeXBlPg0KICAgICAgPHhzOmNob2ljZSBtaW5PY2N1cnM9IjAiIG1heE9jY3Vycz0idW5ib3VuZGVkIiAvPg0KICAgIDwveHM6Y29tcGxleFR5cGU+DQogIDwveHM6ZWxlbWVudD4NCjwveHM6c2NoZW1hPgYFAAAAgAE8ZGlmZmdyOmRpZmZncmFtIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIiB4bWxuczpkaWZmZ3I9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLWRpZmZncmFtLXYxIiAvPgQDAAAADlN5c3RlbS5WZXJzaW9uBAAAAAZfTWFqb3IGX01pbm9yBl9CdWlsZAlfUmV2aXNpb24AAAAACAgICAIAAAAAAAAA//////////8L" } };
+ yield return new object[] { new DataSet("Dataset") { Locale = CultureInfo.InvariantCulture }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABNTeXN0ZW0uRGF0YS5EYXRhU2V0AwAAABdEYXRhU2V0LlJlbW90aW5nVmVyc2lvbglYbWxTY2hlbWELWG1sRGlmZkdyYW0DAQEOU3lzdGVtLlZlcnNpb24CAAAACQMAAAAGBAAAAPcCPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+DQo8eHM6c2NoZW1hIGlkPSJEYXRhc2V0IiB4bWxucz0iIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIj4NCiAgPHhzOmVsZW1lbnQgbmFtZT0iRGF0YXNldCIgbXNkYXRhOklzRGF0YVNldD0idHJ1ZSIgbXNkYXRhOkxvY2FsZT0iIj4NCiAgICA8eHM6Y29tcGxleFR5cGU+DQogICAgICA8eHM6Y2hvaWNlIG1pbk9jY3Vycz0iMCIgbWF4T2NjdXJzPSJ1bmJvdW5kZWQiIC8+DQogICAgPC94czpjb21wbGV4VHlwZT4NCiAgPC94czplbGVtZW50Pg0KPC94czpzY2hlbWE+BgUAAACAATxkaWZmZ3I6ZGlmZmdyYW0geG1sbnM6bXNkYXRhPSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOnhtbC1tc2RhdGEiIHhtbG5zOmRpZmZncj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtZGlmZmdyYW0tdjEiIC8+BAMAAAAOU3lzdGVtLlZlcnNpb24EAAAABl9NYWpvcgZfTWlub3IGX0J1aWxkCV9SZXZpc2lvbgAAAAAICAgIAgAAAAAAAAD//////////ws=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABNTeXN0ZW0uRGF0YS5EYXRhU2V0AwAAABdEYXRhU2V0LlJlbW90aW5nVmVyc2lvbglYbWxTY2hlbWELWG1sRGlmZkdyYW0DAQEOU3lzdGVtLlZlcnNpb24CAAAACQMAAAAGBAAAAPcCPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+DQo8eHM6c2NoZW1hIGlkPSJEYXRhc2V0IiB4bWxucz0iIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIj4NCiAgPHhzOmVsZW1lbnQgbmFtZT0iRGF0YXNldCIgbXNkYXRhOklzRGF0YVNldD0idHJ1ZSIgbXNkYXRhOkxvY2FsZT0iIj4NCiAgICA8eHM6Y29tcGxleFR5cGU+DQogICAgICA8eHM6Y2hvaWNlIG1pbk9jY3Vycz0iMCIgbWF4T2NjdXJzPSJ1bmJvdW5kZWQiIC8+DQogICAgPC94czpjb21wbGV4VHlwZT4NCiAgPC94czplbGVtZW50Pg0KPC94czpzY2hlbWE+BgUAAACAATxkaWZmZ3I6ZGlmZmdyYW0geG1sbnM6bXNkYXRhPSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOnhtbC1tc2RhdGEiIHhtbG5zOmRpZmZncj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtZGlmZmdyYW0tdjEiIC8+BAMAAAAOU3lzdGVtLlZlcnNpb24EAAAABl9NYWpvcgZfTWlub3IGX0J1aWxkCV9SZXZpc2lvbgAAAAAICAgIAgAAAAAAAAD//////////ws=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new DataSet() { Locale = CultureInfo.InvariantCulture }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABNTeXN0ZW0uRGF0YS5EYXRhU2V0AwAAABdEYXRhU2V0LlJlbW90aW5nVmVyc2lvbglYbWxTY2hlbWELWG1sRGlmZkdyYW0DAQEOU3lzdGVtLlZlcnNpb24CAAAACQMAAAAGBAAAAP0CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+DQo8eHM6c2NoZW1hIGlkPSJOZXdEYXRhU2V0IiB4bWxucz0iIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIj4NCiAgPHhzOmVsZW1lbnQgbmFtZT0iTmV3RGF0YVNldCIgbXNkYXRhOklzRGF0YVNldD0idHJ1ZSIgbXNkYXRhOkxvY2FsZT0iIj4NCiAgICA8eHM6Y29tcGxleFR5cGU+DQogICAgICA8eHM6Y2hvaWNlIG1pbk9jY3Vycz0iMCIgbWF4T2NjdXJzPSJ1bmJvdW5kZWQiIC8+DQogICAgPC94czpjb21wbGV4VHlwZT4NCiAgPC94czplbGVtZW50Pg0KPC94czpzY2hlbWE+BgUAAACAATxkaWZmZ3I6ZGlmZmdyYW0geG1sbnM6bXNkYXRhPSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOnhtbC1tc2RhdGEiIHhtbG5zOmRpZmZncj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtZGlmZmdyYW0tdjEiIC8+BAMAAAAOU3lzdGVtLlZlcnNpb24EAAAABl9NYWpvcgZfTWlub3IGX0J1aWxkCV9SZXZpc2lvbgAAAAAICAgIAgAAAAAAAAD//////////ws=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABNTeXN0ZW0uRGF0YS5EYXRhU2V0AwAAABdEYXRhU2V0LlJlbW90aW5nVmVyc2lvbglYbWxTY2hlbWELWG1sRGlmZkdyYW0DAQEOU3lzdGVtLlZlcnNpb24CAAAACQMAAAAGBAAAAP0CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+DQo8eHM6c2NoZW1hIGlkPSJOZXdEYXRhU2V0IiB4bWxucz0iIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIj4NCiAgPHhzOmVsZW1lbnQgbmFtZT0iTmV3RGF0YVNldCIgbXNkYXRhOklzRGF0YVNldD0idHJ1ZSIgbXNkYXRhOkxvY2FsZT0iIj4NCiAgICA8eHM6Y29tcGxleFR5cGU+DQogICAgICA8eHM6Y2hvaWNlIG1pbk9jY3Vycz0iMCIgbWF4T2NjdXJzPSJ1bmJvdW5kZWQiIC8+DQogICAgPC94czpjb21wbGV4VHlwZT4NCiAgPC94czplbGVtZW50Pg0KPC94czpzY2hlbWE+BgUAAACAATxkaWZmZ3I6ZGlmZmdyYW0geG1sbnM6bXNkYXRhPSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOnhtbC1tc2RhdGEiIHhtbG5zOmRpZmZncj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtZGlmZmdyYW0tdjEiIC8+BAMAAAAOU3lzdGVtLlZlcnNpb24EAAAABl9NYWpvcgZfTWlub3IGX0J1aWxkCV9SZXZpc2lvbgAAAAAICAgIAgAAAAAAAAD//////////ws=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new DataTable("Datatable", "corens") { Locale = CultureInfo.InvariantCulture }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABVTeXN0ZW0uRGF0YS5EYXRhVGFibGUDAAAAGURhdGFUYWJsZS5SZW1vdGluZ1ZlcnNpb24JWG1sU2NoZW1hC1htbERpZmZHcmFtAwEBDlN5c3RlbS5WZXJzaW9uAgAAAAkDAAAABgQAAAD/BDw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi0xNiI/Pg0KPHhzOnNjaGVtYSB0YXJnZXROYW1lc3BhY2U9ImNvcmVucyIgeG1sbnM6bXN0bnM9ImNvcmVucyIgeG1sbnM9ImNvcmVucyIgeG1sbnM6eHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hIiB4bWxuczptc2RhdGE9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLW1zZGF0YSIgYXR0cmlidXRlRm9ybURlZmF1bHQ9InF1YWxpZmllZCIgZWxlbWVudEZvcm1EZWZhdWx0PSJxdWFsaWZpZWQiPg0KICA8eHM6ZWxlbWVudCBuYW1lPSJEYXRhdGFibGUiIG1zZGF0YTpMb2NhbGU9IiI+DQogICAgPHhzOmNvbXBsZXhUeXBlPg0KICAgIDwveHM6Y29tcGxleFR5cGU+DQogIDwveHM6ZWxlbWVudD4NCiAgPHhzOmVsZW1lbnQgbmFtZT0idG1wRGF0YVNldCIgbXNkYXRhOklzRGF0YVNldD0idHJ1ZSIgbXNkYXRhOk1haW5EYXRhVGFibGU9ImNvcmVuc194MDAzQV9EYXRhdGFibGUiIG1zZGF0YTpMb2NhbGU9IiI+DQogICAgPHhzOmNvbXBsZXhUeXBlPg0KICAgICAgPHhzOmNob2ljZSBtaW5PY2N1cnM9IjAiIG1heE9jY3Vycz0idW5ib3VuZGVkIiAvPg0KICAgIDwveHM6Y29tcGxleFR5cGU+DQogIDwveHM6ZWxlbWVudD4NCjwveHM6c2NoZW1hPgYFAAAAgAE8ZGlmZmdyOmRpZmZncmFtIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIiB4bWxuczpkaWZmZ3I9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLWRpZmZncmFtLXYxIiAvPgQDAAAADlN5c3RlbS5WZXJzaW9uBAAAAAZfTWFqb3IGX01pbm9yBl9CdWlsZAlfUmV2aXNpb24AAAAACAgICAIAAAAAAAAA//////////8L", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABVTeXN0ZW0uRGF0YS5EYXRhVGFibGUDAAAAGURhdGFUYWJsZS5SZW1vdGluZ1ZlcnNpb24JWG1sU2NoZW1hC1htbERpZmZHcmFtAwEBDlN5c3RlbS5WZXJzaW9uAgAAAAkDAAAABgQAAAD/BDw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi0xNiI/Pg0KPHhzOnNjaGVtYSB0YXJnZXROYW1lc3BhY2U9ImNvcmVucyIgeG1sbnM6bXN0bnM9ImNvcmVucyIgeG1sbnM9ImNvcmVucyIgeG1sbnM6eHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hIiB4bWxuczptc2RhdGE9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLW1zZGF0YSIgYXR0cmlidXRlRm9ybURlZmF1bHQ9InF1YWxpZmllZCIgZWxlbWVudEZvcm1EZWZhdWx0PSJxdWFsaWZpZWQiPg0KICA8eHM6ZWxlbWVudCBuYW1lPSJEYXRhdGFibGUiIG1zZGF0YTpMb2NhbGU9IiI+DQogICAgPHhzOmNvbXBsZXhUeXBlPg0KICAgIDwveHM6Y29tcGxleFR5cGU+DQogIDwveHM6ZWxlbWVudD4NCiAgPHhzOmVsZW1lbnQgbmFtZT0idG1wRGF0YVNldCIgbXNkYXRhOklzRGF0YVNldD0idHJ1ZSIgbXNkYXRhOk1haW5EYXRhVGFibGU9ImNvcmVuc194MDAzQV9EYXRhdGFibGUiIG1zZGF0YTpMb2NhbGU9IiI+DQogICAgPHhzOmNvbXBsZXhUeXBlPg0KICAgICAgPHhzOmNob2ljZSBtaW5PY2N1cnM9IjAiIG1heE9jY3Vycz0idW5ib3VuZGVkIiAvPg0KICAgIDwveHM6Y29tcGxleFR5cGU+DQogIDwveHM6ZWxlbWVudD4NCjwveHM6c2NoZW1hPgYFAAAAgAE8ZGlmZmdyOmRpZmZncmFtIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIiB4bWxuczpkaWZmZ3I9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLWRpZmZncmFtLXYxIiAvPgQDAAAADlN5c3RlbS5WZXJzaW9uBAAAAAZfTWFqb3IGX01pbm9yBl9CdWlsZAlfUmV2aXNpb24AAAAACAgICAIAAAAAAAAA//////////8L", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new DataTable("Datatable") { Locale = CultureInfo.InvariantCulture }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABVTeXN0ZW0uRGF0YS5EYXRhVGFibGUDAAAAGURhdGFUYWJsZS5SZW1vdGluZ1ZlcnNpb24JWG1sU2NoZW1hC1htbERpZmZHcmFtAwEBDlN5c3RlbS5WZXJzaW9uAgAAAAkDAAAABgQAAAD+Azw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi0xNiI/Pg0KPHhzOnNjaGVtYSB4bWxucz0iIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIj4NCiAgPHhzOmVsZW1lbnQgbmFtZT0iRGF0YXRhYmxlIiBtc2RhdGE6TG9jYWxlPSIiPg0KICAgIDx4czpjb21wbGV4VHlwZT4NCiAgICA8L3hzOmNvbXBsZXhUeXBlPg0KICA8L3hzOmVsZW1lbnQ+DQogIDx4czplbGVtZW50IG5hbWU9InRtcERhdGFTZXQiIG1zZGF0YTpJc0RhdGFTZXQ9InRydWUiIG1zZGF0YTpNYWluRGF0YVRhYmxlPSJEYXRhdGFibGUiIG1zZGF0YTpMb2NhbGU9IiI+DQogICAgPHhzOmNvbXBsZXhUeXBlPg0KICAgICAgPHhzOmNob2ljZSBtaW5PY2N1cnM9IjAiIG1heE9jY3Vycz0idW5ib3VuZGVkIiAvPg0KICAgIDwveHM6Y29tcGxleFR5cGU+DQogIDwveHM6ZWxlbWVudD4NCjwveHM6c2NoZW1hPgYFAAAAgAE8ZGlmZmdyOmRpZmZncmFtIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIiB4bWxuczpkaWZmZ3I9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLWRpZmZncmFtLXYxIiAvPgQDAAAADlN5c3RlbS5WZXJzaW9uBAAAAAZfTWFqb3IGX01pbm9yBl9CdWlsZAlfUmV2aXNpb24AAAAACAgICAIAAAAAAAAA//////////8L", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABVTeXN0ZW0uRGF0YS5EYXRhVGFibGUDAAAAGURhdGFUYWJsZS5SZW1vdGluZ1ZlcnNpb24JWG1sU2NoZW1hC1htbERpZmZHcmFtAwEBDlN5c3RlbS5WZXJzaW9uAgAAAAkDAAAABgQAAAD+Azw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi0xNiI/Pg0KPHhzOnNjaGVtYSB4bWxucz0iIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIj4NCiAgPHhzOmVsZW1lbnQgbmFtZT0iRGF0YXRhYmxlIiBtc2RhdGE6TG9jYWxlPSIiPg0KICAgIDx4czpjb21wbGV4VHlwZT4NCiAgICA8L3hzOmNvbXBsZXhUeXBlPg0KICA8L3hzOmVsZW1lbnQ+DQogIDx4czplbGVtZW50IG5hbWU9InRtcERhdGFTZXQiIG1zZGF0YTpJc0RhdGFTZXQ9InRydWUiIG1zZGF0YTpNYWluRGF0YVRhYmxlPSJEYXRhdGFibGUiIG1zZGF0YTpMb2NhbGU9IiI+DQogICAgPHhzOmNvbXBsZXhUeXBlPg0KICAgICAgPHhzOmNob2ljZSBtaW5PY2N1cnM9IjAiIG1heE9jY3Vycz0idW5ib3VuZGVkIiAvPg0KICAgIDwveHM6Y29tcGxleFR5cGU+DQogIDwveHM6ZWxlbWVudD4NCjwveHM6c2NoZW1hPgYFAAAAgAE8ZGlmZmdyOmRpZmZncmFtIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIiB4bWxuczpkaWZmZ3I9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLWRpZmZncmFtLXYxIiAvPgQDAAAADlN5c3RlbS5WZXJzaW9uBAAAAAZfTWFqb3IGX01pbm9yBl9CdWlsZAlfUmV2aXNpb24AAAAACAgICAIAAAAAAAAA//////////8L", TargetFrameworkMoniker.netfx461) } };
var dt1 = new DataTable("abc", "myns1");
dt1.Columns.Add("col1");
@@ -926,75 +918,75 @@ namespace System.Runtime.Serialization.Formatters.Tests
ds.Tables.Add(dt1);
ds.Tables.Add(dt2);
- yield return new object[] { dt1, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABVTeXN0ZW0uRGF0YS5EYXRhVGFibGUDAAAAGURhdGFUYWJsZS5SZW1vdGluZ1ZlcnNpb24JWG1sU2NoZW1hC1htbERpZmZHcmFtAwEBDlN5c3RlbS5WZXJzaW9uAgAAAAkDAAAABgQAAADeBjw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi0xNiI/Pg0KPHhzOnNjaGVtYSB0YXJnZXROYW1lc3BhY2U9Im15bnMxIiB4bWxuczptc3Rucz0ibXluczEiIHhtbG5zPSJteW5zMSIgeG1sbnM6eHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hIiB4bWxuczptc2RhdGE9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLW1zZGF0YSIgYXR0cmlidXRlRm9ybURlZmF1bHQ9InF1YWxpZmllZCIgZWxlbWVudEZvcm1EZWZhdWx0PSJxdWFsaWZpZWQiPg0KICA8eHM6ZWxlbWVudCBuYW1lPSJhYmMiIG1zZGF0YTpMb2NhbGU9IiI+DQogICAgPHhzOmNvbXBsZXhUeXBlPg0KICAgICAgPHhzOnNlcXVlbmNlPg0KICAgICAgICA8eHM6ZWxlbWVudCBuYW1lPSJjb2wxIiB0eXBlPSJ4czpzdHJpbmciIG1zZGF0YTp0YXJnZXROYW1lc3BhY2U9Im15bnMxIiBtaW5PY2N1cnM9IjAiIC8+DQogICAgICAgIDx4czplbGVtZW50IG5hbWU9ImNvbDIiIHR5cGU9InhzOnN0cmluZyIgbXNkYXRhOnRhcmdldE5hbWVzcGFjZT0ibXluczEiIG1pbk9jY3Vycz0iMCIgLz4NCiAgICAgIDwveHM6c2VxdWVuY2U+DQogICAgPC94czpjb21wbGV4VHlwZT4NCiAgPC94czplbGVtZW50Pg0KICA8eHM6ZWxlbWVudCBuYW1lPSJEYXRhU2V0MTIzIiBtc2RhdGE6SXNEYXRhU2V0PSJ0cnVlIiBtc2RhdGE6TWFpbkRhdGFUYWJsZT0ibXluczFfeDAwM0FfYWJjIiBtc2RhdGE6TG9jYWxlPSIiPg0KICAgIDx4czpjb21wbGV4VHlwZT4NCiAgICAgIDx4czpjaG9pY2UgbWluT2NjdXJzPSIwIiBtYXhPY2N1cnM9InVuYm91bmRlZCIgLz4NCiAgICA8L3hzOmNvbXBsZXhUeXBlPg0KICA8L3hzOmVsZW1lbnQ+DQo8L3hzOnNjaGVtYT4GBQAAANwDPGRpZmZncjpkaWZmZ3JhbSB4bWxuczptc2RhdGE9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLW1zZGF0YSIgeG1sbnM6ZGlmZmdyPSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOnhtbC1kaWZmZ3JhbS12MSI+DQogIDxEYXRhU2V0MTIzIHhtbG5zPSJteW5zMSI+DQogICAgPGFiYyBkaWZmZ3I6aWQ9ImFiYzEiIG1zZGF0YTpyb3dPcmRlcj0iMCIgZGlmZmdyOmhhc0NoYW5nZXM9Imluc2VydGVkIj4NCiAgICAgIDxjb2wxPmZvbzwvY29sMT4NCiAgICAgIDxjb2wyPmJhcjwvY29sMj4NCiAgICA8L2FiYz4NCiAgICA8YWJjIGRpZmZncjppZD0iYWJjMiIgbXNkYXRhOnJvd09yZGVyPSIxIiBkaWZmZ3I6aGFzQ2hhbmdlcz0iaW5zZXJ0ZWQiPg0KICAgICAgPGNvbDE+YXNkYXNkPC9jb2wxPg0KICAgICAgPGNvbDI+ZmZmZmZmZmZmPC9jb2wyPg0KICAgIDwvYWJjPg0KICA8L0RhdGFTZXQxMjM+DQo8L2RpZmZncjpkaWZmZ3JhbT4EAwAAAA5TeXN0ZW0uVmVyc2lvbgQAAAAGX01ham9yBl9NaW5vcgZfQnVpbGQJX1JldmlzaW9uAAAAAAgICAgCAAAAAAAAAP//////////Cw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABVTeXN0ZW0uRGF0YS5EYXRhVGFibGUDAAAAGURhdGFUYWJsZS5SZW1vdGluZ1ZlcnNpb24JWG1sU2NoZW1hC1htbERpZmZHcmFtAwEBDlN5c3RlbS5WZXJzaW9uAgAAAAkDAAAABgQAAADeBjw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi0xNiI/Pg0KPHhzOnNjaGVtYSB0YXJnZXROYW1lc3BhY2U9Im15bnMxIiB4bWxuczptc3Rucz0ibXluczEiIHhtbG5zPSJteW5zMSIgeG1sbnM6eHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hIiB4bWxuczptc2RhdGE9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLW1zZGF0YSIgYXR0cmlidXRlRm9ybURlZmF1bHQ9InF1YWxpZmllZCIgZWxlbWVudEZvcm1EZWZhdWx0PSJxdWFsaWZpZWQiPg0KICA8eHM6ZWxlbWVudCBuYW1lPSJhYmMiIG1zZGF0YTpMb2NhbGU9IiI+DQogICAgPHhzOmNvbXBsZXhUeXBlPg0KICAgICAgPHhzOnNlcXVlbmNlPg0KICAgICAgICA8eHM6ZWxlbWVudCBuYW1lPSJjb2wxIiB0eXBlPSJ4czpzdHJpbmciIG1zZGF0YTp0YXJnZXROYW1lc3BhY2U9Im15bnMxIiBtaW5PY2N1cnM9IjAiIC8+DQogICAgICAgIDx4czplbGVtZW50IG5hbWU9ImNvbDIiIHR5cGU9InhzOnN0cmluZyIgbXNkYXRhOnRhcmdldE5hbWVzcGFjZT0ibXluczEiIG1pbk9jY3Vycz0iMCIgLz4NCiAgICAgIDwveHM6c2VxdWVuY2U+DQogICAgPC94czpjb21wbGV4VHlwZT4NCiAgPC94czplbGVtZW50Pg0KICA8eHM6ZWxlbWVudCBuYW1lPSJEYXRhU2V0MTIzIiBtc2RhdGE6SXNEYXRhU2V0PSJ0cnVlIiBtc2RhdGE6TWFpbkRhdGFUYWJsZT0ibXluczFfeDAwM0FfYWJjIiBtc2RhdGE6TG9jYWxlPSIiPg0KICAgIDx4czpjb21wbGV4VHlwZT4NCiAgICAgIDx4czpjaG9pY2UgbWluT2NjdXJzPSIwIiBtYXhPY2N1cnM9InVuYm91bmRlZCIgLz4NCiAgICA8L3hzOmNvbXBsZXhUeXBlPg0KICA8L3hzOmVsZW1lbnQ+DQo8L3hzOnNjaGVtYT4GBQAAANwDPGRpZmZncjpkaWZmZ3JhbSB4bWxuczptc2RhdGE9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLW1zZGF0YSIgeG1sbnM6ZGlmZmdyPSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOnhtbC1kaWZmZ3JhbS12MSI+DQogIDxEYXRhU2V0MTIzIHhtbG5zPSJteW5zMSI+DQogICAgPGFiYyBkaWZmZ3I6aWQ9ImFiYzEiIG1zZGF0YTpyb3dPcmRlcj0iMCIgZGlmZmdyOmhhc0NoYW5nZXM9Imluc2VydGVkIj4NCiAgICAgIDxjb2wxPmZvbzwvY29sMT4NCiAgICAgIDxjb2wyPmJhcjwvY29sMj4NCiAgICA8L2FiYz4NCiAgICA8YWJjIGRpZmZncjppZD0iYWJjMiIgbXNkYXRhOnJvd09yZGVyPSIxIiBkaWZmZ3I6aGFzQ2hhbmdlcz0iaW5zZXJ0ZWQiPg0KICAgICAgPGNvbDE+YXNkYXNkPC9jb2wxPg0KICAgICAgPGNvbDI+ZmZmZmZmZmZmPC9jb2wyPg0KICAgIDwvYWJjPg0KICA8L0RhdGFTZXQxMjM+DQo8L2RpZmZncjpkaWZmZ3JhbT4EAwAAAA5TeXN0ZW0uVmVyc2lvbgQAAAAGX01ham9yBl9NaW5vcgZfQnVpbGQJX1JldmlzaW9uAAAAAAgICAgCAAAAAAAAAP//////////Cw==" } };
- yield return new object[] { dt2, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABVTeXN0ZW0uRGF0YS5EYXRhVGFibGUDAAAAGURhdGFUYWJsZS5SZW1vdGluZ1ZlcnNpb24JWG1sU2NoZW1hC1htbERpZmZHcmFtAwEBDlN5c3RlbS5WZXJzaW9uAgAAAAkDAAAABgQAAADeBTw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi0xNiI/Pg0KPHhzOnNjaGVtYSB4bWxucz0iIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIj4NCiAgPHhzOmVsZW1lbnQgbmFtZT0ic2Rmc2RmIiBtc2RhdGE6TG9jYWxlPSIiPg0KICAgIDx4czpjb21wbGV4VHlwZT4NCiAgICAgIDx4czpzZXF1ZW5jZT4NCiAgICAgICAgPHhzOmVsZW1lbnQgbmFtZT0ia2trIiB0eXBlPSJ4czpzdHJpbmciIG1zZGF0YTp0YXJnZXROYW1lc3BhY2U9IiIgbWluT2NjdXJzPSIwIiAvPg0KICAgICAgICA8eHM6ZWxlbWVudCBuYW1lPSJqZmpmamYiIHR5cGU9InhzOnN0cmluZyIgbXNkYXRhOnRhcmdldE5hbWVzcGFjZT0iIiBtaW5PY2N1cnM9IjAiIC8+DQogICAgICA8L3hzOnNlcXVlbmNlPg0KICAgIDwveHM6Y29tcGxleFR5cGU+DQogIDwveHM6ZWxlbWVudD4NCiAgPHhzOmVsZW1lbnQgbmFtZT0iRGF0YVNldDEyMyIgbXNkYXRhOklzRGF0YVNldD0idHJ1ZSIgbXNkYXRhOk1haW5EYXRhVGFibGU9InNkZnNkZiIgbXNkYXRhOkxvY2FsZT0iIj4NCiAgICA8eHM6Y29tcGxleFR5cGU+DQogICAgICA8eHM6Y2hvaWNlIG1pbk9jY3Vycz0iMCIgbWF4T2NjdXJzPSJ1bmJvdW5kZWQiIC8+DQogICAgPC94czpjb21wbGV4VHlwZT4NCiAgPC94czplbGVtZW50Pg0KPC94czpzY2hlbWE+BgUAAADiBDxkaWZmZ3I6ZGlmZmdyYW0geG1sbnM6bXNkYXRhPSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOnhtbC1tc2RhdGEiIHhtbG5zOmRpZmZncj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtZGlmZmdyYW0tdjEiPg0KICA8RGF0YVNldDEyMz4NCiAgICA8c2Rmc2RmIGRpZmZncjppZD0ic2Rmc2RmMSIgbXNkYXRhOnJvd09yZGVyPSIwIiBkaWZmZ3I6aGFzQ2hhbmdlcz0iaW5zZXJ0ZWQiPg0KICAgICAgPGtraz5mZjE8L2traz4NCiAgICAgIDxqZmpmamY+ZmYyPC9qZmpmamY+DQogICAgPC9zZGZzZGY+DQogICAgPHNkZnNkZiBkaWZmZ3I6aWQ9InNkZnNkZjIiIG1zZGF0YTpyb3dPcmRlcj0iMSIgZGlmZmdyOmhhc0NoYW5nZXM9Imluc2VydGVkIj4NCiAgICAgIDxra2s+b29vPC9ra2s+DQogICAgICA8amZqZmpmPnNkZmxranNkZmxranNkPC9qZmpmamY+DQogICAgPC9zZGZzZGY+DQogICAgPHNkZnNkZiBkaWZmZ3I6aWQ9InNkZnNkZjMiIG1zZGF0YTpyb3dPcmRlcj0iMiIgZGlmZmdyOmhhc0NoYW5nZXM9Imluc2VydGVkIj4NCiAgICAgIDxra2s+bnVsbHZhbDwva2trPg0KICAgIDwvc2Rmc2RmPg0KICA8L0RhdGFTZXQxMjM+DQo8L2RpZmZncjpkaWZmZ3JhbT4EAwAAAA5TeXN0ZW0uVmVyc2lvbgQAAAAGX01ham9yBl9NaW5vcgZfQnVpbGQJX1JldmlzaW9uAAAAAAgICAgCAAAAAAAAAP//////////Cw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABVTeXN0ZW0uRGF0YS5EYXRhVGFibGUDAAAAGURhdGFUYWJsZS5SZW1vdGluZ1ZlcnNpb24JWG1sU2NoZW1hC1htbERpZmZHcmFtAwEBDlN5c3RlbS5WZXJzaW9uAgAAAAkDAAAABgQAAADeBTw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi0xNiI/Pg0KPHhzOnNjaGVtYSB4bWxucz0iIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIj4NCiAgPHhzOmVsZW1lbnQgbmFtZT0ic2Rmc2RmIiBtc2RhdGE6TG9jYWxlPSIiPg0KICAgIDx4czpjb21wbGV4VHlwZT4NCiAgICAgIDx4czpzZXF1ZW5jZT4NCiAgICAgICAgPHhzOmVsZW1lbnQgbmFtZT0ia2trIiB0eXBlPSJ4czpzdHJpbmciIG1zZGF0YTp0YXJnZXROYW1lc3BhY2U9IiIgbWluT2NjdXJzPSIwIiAvPg0KICAgICAgICA8eHM6ZWxlbWVudCBuYW1lPSJqZmpmamYiIHR5cGU9InhzOnN0cmluZyIgbXNkYXRhOnRhcmdldE5hbWVzcGFjZT0iIiBtaW5PY2N1cnM9IjAiIC8+DQogICAgICA8L3hzOnNlcXVlbmNlPg0KICAgIDwveHM6Y29tcGxleFR5cGU+DQogIDwveHM6ZWxlbWVudD4NCiAgPHhzOmVsZW1lbnQgbmFtZT0iRGF0YVNldDEyMyIgbXNkYXRhOklzRGF0YVNldD0idHJ1ZSIgbXNkYXRhOk1haW5EYXRhVGFibGU9InNkZnNkZiIgbXNkYXRhOkxvY2FsZT0iIj4NCiAgICA8eHM6Y29tcGxleFR5cGU+DQogICAgICA8eHM6Y2hvaWNlIG1pbk9jY3Vycz0iMCIgbWF4T2NjdXJzPSJ1bmJvdW5kZWQiIC8+DQogICAgPC94czpjb21wbGV4VHlwZT4NCiAgPC94czplbGVtZW50Pg0KPC94czpzY2hlbWE+BgUAAADiBDxkaWZmZ3I6ZGlmZmdyYW0geG1sbnM6bXNkYXRhPSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOnhtbC1tc2RhdGEiIHhtbG5zOmRpZmZncj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtZGlmZmdyYW0tdjEiPg0KICA8RGF0YVNldDEyMz4NCiAgICA8c2Rmc2RmIGRpZmZncjppZD0ic2Rmc2RmMSIgbXNkYXRhOnJvd09yZGVyPSIwIiBkaWZmZ3I6aGFzQ2hhbmdlcz0iaW5zZXJ0ZWQiPg0KICAgICAgPGtraz5mZjE8L2traz4NCiAgICAgIDxqZmpmamY+ZmYyPC9qZmpmamY+DQogICAgPC9zZGZzZGY+DQogICAgPHNkZnNkZiBkaWZmZ3I6aWQ9InNkZnNkZjIiIG1zZGF0YTpyb3dPcmRlcj0iMSIgZGlmZmdyOmhhc0NoYW5nZXM9Imluc2VydGVkIj4NCiAgICAgIDxra2s+b29vPC9ra2s+DQogICAgICA8amZqZmpmPnNkZmxranNkZmxranNkPC9qZmpmamY+DQogICAgPC9zZGZzZGY+DQogICAgPHNkZnNkZiBkaWZmZ3I6aWQ9InNkZnNkZjMiIG1zZGF0YTpyb3dPcmRlcj0iMiIgZGlmZmdyOmhhc0NoYW5nZXM9Imluc2VydGVkIj4NCiAgICAgIDxra2s+bnVsbHZhbDwva2trPg0KICAgIDwvc2Rmc2RmPg0KICA8L0RhdGFTZXQxMjM+DQo8L2RpZmZncjpkaWZmZ3JhbT4EAwAAAA5TeXN0ZW0uVmVyc2lvbgQAAAAGX01ham9yBl9NaW5vcgZfQnVpbGQJX1JldmlzaW9uAAAAAAgICAgCAAAAAAAAAP//////////Cw==" } };
- yield return new object[] { ds, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABNTeXN0ZW0uRGF0YS5EYXRhU2V0AwAAABdEYXRhU2V0LlJlbW90aW5nVmVyc2lvbglYbWxTY2hlbWELWG1sRGlmZkdyYW0DAQEOU3lzdGVtLlZlcnNpb24CAAAACQMAAAAGBAAAALoJPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+DQo8eHM6c2NoZW1hIGlkPSJEYXRhU2V0MTIzIiB4bWxucz0iIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIj4NCiAgPHhzOmVsZW1lbnQgbmFtZT0iRGF0YVNldDEyMyIgbXNkYXRhOklzRGF0YVNldD0idHJ1ZSIgbXNkYXRhOkxvY2FsZT0iIj4NCiAgICA8eHM6Y29tcGxleFR5cGU+DQogICAgICA8eHM6Y2hvaWNlIG1pbk9jY3Vycz0iMCIgbWF4T2NjdXJzPSJ1bmJvdW5kZWQiPg0KICAgICAgICA8eHM6ZWxlbWVudCBtc2RhdGE6dGFyZ2V0TmFtZXNwYWNlPSJteW5zMSIgbmFtZT0iYWJjIiBtc2RhdGE6TG9jYWxlPSIiPg0KICAgICAgICAgIDx4czpjb21wbGV4VHlwZT4NCiAgICAgICAgICAgIDx4czpzZXF1ZW5jZT4NCiAgICAgICAgICAgICAgPHhzOmVsZW1lbnQgbmFtZT0iY29sMSIgdHlwZT0ieHM6c3RyaW5nIiBtc2RhdGE6dGFyZ2V0TmFtZXNwYWNlPSJteW5zMSIgbWluT2NjdXJzPSIwIiAvPg0KICAgICAgICAgICAgICA8eHM6ZWxlbWVudCBuYW1lPSJjb2wyIiB0eXBlPSJ4czpzdHJpbmciIG1zZGF0YTp0YXJnZXROYW1lc3BhY2U9Im15bnMxIiBtaW5PY2N1cnM9IjAiIC8+DQogICAgICAgICAgICA8L3hzOnNlcXVlbmNlPg0KICAgICAgICAgIDwveHM6Y29tcGxleFR5cGU+DQogICAgICAgIDwveHM6ZWxlbWVudD4NCiAgICAgICAgPHhzOmVsZW1lbnQgbmFtZT0ic2Rmc2RmIiBtc2RhdGE6TG9jYWxlPSIiPg0KICAgICAgICAgIDx4czpjb21wbGV4VHlwZT4NCiAgICAgICAgICAgIDx4czpzZXF1ZW5jZT4NCiAgICAgICAgICAgICAgPHhzOmVsZW1lbnQgbmFtZT0ia2trIiB0eXBlPSJ4czpzdHJpbmciIG1zZGF0YTp0YXJnZXROYW1lc3BhY2U9IiIgbWluT2NjdXJzPSIwIiAvPg0KICAgICAgICAgICAgICA8eHM6ZWxlbWVudCBuYW1lPSJqZmpmamYiIHR5cGU9InhzOnN0cmluZyIgbXNkYXRhOnRhcmdldE5hbWVzcGFjZT0iIiBtaW5PY2N1cnM9IjAiIC8+DQogICAgICAgICAgICA8L3hzOnNlcXVlbmNlPg0KICAgICAgICAgIDwveHM6Y29tcGxleFR5cGU+DQogICAgICAgIDwveHM6ZWxlbWVudD4NCiAgICAgIDwveHM6Y2hvaWNlPg0KICAgIDwveHM6Y29tcGxleFR5cGU+DQogIDwveHM6ZWxlbWVudD4NCjwveHM6c2NoZW1hPgYFAAAAiwY8ZGlmZmdyOmRpZmZncmFtIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIiB4bWxuczpkaWZmZ3I9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLWRpZmZncmFtLXYxIj48RGF0YVNldDEyMz48YWJjIGRpZmZncjppZD0iYWJjMSIgbXNkYXRhOnJvd09yZGVyPSIwIiBkaWZmZ3I6aGFzQ2hhbmdlcz0iaW5zZXJ0ZWQiIHhtbG5zPSJteW5zMSI+PGNvbDE+Zm9vPC9jb2wxPjxjb2wyPmJhcjwvY29sMj48L2FiYz48YWJjIGRpZmZncjppZD0iYWJjMiIgbXNkYXRhOnJvd09yZGVyPSIxIiBkaWZmZ3I6aGFzQ2hhbmdlcz0iaW5zZXJ0ZWQiIHhtbG5zPSJteW5zMSI+PGNvbDE+YXNkYXNkPC9jb2wxPjxjb2wyPmZmZmZmZmZmZjwvY29sMj48L2FiYz48c2Rmc2RmIGRpZmZncjppZD0ic2Rmc2RmMSIgbXNkYXRhOnJvd09yZGVyPSIwIiBkaWZmZ3I6aGFzQ2hhbmdlcz0iaW5zZXJ0ZWQiPjxra2s+ZmYxPC9ra2s+PGpmamZqZj5mZjI8L2pmamZqZj48L3NkZnNkZj48c2Rmc2RmIGRpZmZncjppZD0ic2Rmc2RmMiIgbXNkYXRhOnJvd09yZGVyPSIxIiBkaWZmZ3I6aGFzQ2hhbmdlcz0iaW5zZXJ0ZWQiPjxra2s+b29vPC9ra2s+PGpmamZqZj5zZGZsa2pzZGZsa2pzZDwvamZqZmpmPjwvc2Rmc2RmPjxzZGZzZGYgZGlmZmdyOmlkPSJzZGZzZGYzIiBtc2RhdGE6cm93T3JkZXI9IjIiIGRpZmZncjpoYXNDaGFuZ2VzPSJpbnNlcnRlZCI+PGtraz5udWxsdmFsPC9ra2s+PC9zZGZzZGY+PC9EYXRhU2V0MTIzPjwvZGlmZmdyOmRpZmZncmFtPgQDAAAADlN5c3RlbS5WZXJzaW9uBAAAAAZfTWFqb3IGX01pbm9yBl9CdWlsZAlfUmV2aXNpb24AAAAACAgICAIAAAAAAAAA//////////8L", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABNTeXN0ZW0uRGF0YS5EYXRhU2V0AwAAABdEYXRhU2V0LlJlbW90aW5nVmVyc2lvbglYbWxTY2hlbWELWG1sRGlmZkdyYW0DAQEOU3lzdGVtLlZlcnNpb24CAAAACQMAAAAGBAAAALoJPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+DQo8eHM6c2NoZW1hIGlkPSJEYXRhU2V0MTIzIiB4bWxucz0iIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIj4NCiAgPHhzOmVsZW1lbnQgbmFtZT0iRGF0YVNldDEyMyIgbXNkYXRhOklzRGF0YVNldD0idHJ1ZSIgbXNkYXRhOkxvY2FsZT0iIj4NCiAgICA8eHM6Y29tcGxleFR5cGU+DQogICAgICA8eHM6Y2hvaWNlIG1pbk9jY3Vycz0iMCIgbWF4T2NjdXJzPSJ1bmJvdW5kZWQiPg0KICAgICAgICA8eHM6ZWxlbWVudCBtc2RhdGE6dGFyZ2V0TmFtZXNwYWNlPSJteW5zMSIgbmFtZT0iYWJjIiBtc2RhdGE6TG9jYWxlPSIiPg0KICAgICAgICAgIDx4czpjb21wbGV4VHlwZT4NCiAgICAgICAgICAgIDx4czpzZXF1ZW5jZT4NCiAgICAgICAgICAgICAgPHhzOmVsZW1lbnQgbmFtZT0iY29sMSIgdHlwZT0ieHM6c3RyaW5nIiBtc2RhdGE6dGFyZ2V0TmFtZXNwYWNlPSJteW5zMSIgbWluT2NjdXJzPSIwIiAvPg0KICAgICAgICAgICAgICA8eHM6ZWxlbWVudCBuYW1lPSJjb2wyIiB0eXBlPSJ4czpzdHJpbmciIG1zZGF0YTp0YXJnZXROYW1lc3BhY2U9Im15bnMxIiBtaW5PY2N1cnM9IjAiIC8+DQogICAgICAgICAgICA8L3hzOnNlcXVlbmNlPg0KICAgICAgICAgIDwveHM6Y29tcGxleFR5cGU+DQogICAgICAgIDwveHM6ZWxlbWVudD4NCiAgICAgICAgPHhzOmVsZW1lbnQgbmFtZT0ic2Rmc2RmIiBtc2RhdGE6TG9jYWxlPSIiPg0KICAgICAgICAgIDx4czpjb21wbGV4VHlwZT4NCiAgICAgICAgICAgIDx4czpzZXF1ZW5jZT4NCiAgICAgICAgICAgICAgPHhzOmVsZW1lbnQgbmFtZT0ia2trIiB0eXBlPSJ4czpzdHJpbmciIG1zZGF0YTp0YXJnZXROYW1lc3BhY2U9IiIgbWluT2NjdXJzPSIwIiAvPg0KICAgICAgICAgICAgICA8eHM6ZWxlbWVudCBuYW1lPSJqZmpmamYiIHR5cGU9InhzOnN0cmluZyIgbXNkYXRhOnRhcmdldE5hbWVzcGFjZT0iIiBtaW5PY2N1cnM9IjAiIC8+DQogICAgICAgICAgICA8L3hzOnNlcXVlbmNlPg0KICAgICAgICAgIDwveHM6Y29tcGxleFR5cGU+DQogICAgICAgIDwveHM6ZWxlbWVudD4NCiAgICAgIDwveHM6Y2hvaWNlPg0KICAgIDwveHM6Y29tcGxleFR5cGU+DQogIDwveHM6ZWxlbWVudD4NCjwveHM6c2NoZW1hPgYFAAAAiwY8ZGlmZmdyOmRpZmZncmFtIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIiB4bWxuczpkaWZmZ3I9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLWRpZmZncmFtLXYxIj48RGF0YVNldDEyMz48YWJjIGRpZmZncjppZD0iYWJjMSIgbXNkYXRhOnJvd09yZGVyPSIwIiBkaWZmZ3I6aGFzQ2hhbmdlcz0iaW5zZXJ0ZWQiIHhtbG5zPSJteW5zMSI+PGNvbDE+Zm9vPC9jb2wxPjxjb2wyPmJhcjwvY29sMj48L2FiYz48YWJjIGRpZmZncjppZD0iYWJjMiIgbXNkYXRhOnJvd09yZGVyPSIxIiBkaWZmZ3I6aGFzQ2hhbmdlcz0iaW5zZXJ0ZWQiIHhtbG5zPSJteW5zMSI+PGNvbDE+YXNkYXNkPC9jb2wxPjxjb2wyPmZmZmZmZmZmZjwvY29sMj48L2FiYz48c2Rmc2RmIGRpZmZncjppZD0ic2Rmc2RmMSIgbXNkYXRhOnJvd09yZGVyPSIwIiBkaWZmZ3I6aGFzQ2hhbmdlcz0iaW5zZXJ0ZWQiPjxra2s+ZmYxPC9ra2s+PGpmamZqZj5mZjI8L2pmamZqZj48L3NkZnNkZj48c2Rmc2RmIGRpZmZncjppZD0ic2Rmc2RmMiIgbXNkYXRhOnJvd09yZGVyPSIxIiBkaWZmZ3I6aGFzQ2hhbmdlcz0iaW5zZXJ0ZWQiPjxra2s+b29vPC9ra2s+PGpmamZqZj5zZGZsa2pzZGZsa2pzZDwvamZqZmpmPjwvc2Rmc2RmPjxzZGZzZGYgZGlmZmdyOmlkPSJzZGZzZGYzIiBtc2RhdGE6cm93T3JkZXI9IjIiIGRpZmZncjpoYXNDaGFuZ2VzPSJpbnNlcnRlZCI+PGtraz5udWxsdmFsPC9ra2s+PC9zZGZzZGY+PC9EYXRhU2V0MTIzPjwvZGlmZmdyOmRpZmZncmFtPgQDAAAADlN5c3RlbS5WZXJzaW9uBAAAAAZfTWFqb3IGX01pbm9yBl9CdWlsZAlfUmV2aXNpb24AAAAACAgICAIAAAAAAAAA//////////8L" } };
+ yield return new object[] { dt1, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABVTeXN0ZW0uRGF0YS5EYXRhVGFibGUDAAAAGURhdGFUYWJsZS5SZW1vdGluZ1ZlcnNpb24JWG1sU2NoZW1hC1htbERpZmZHcmFtAwEBDlN5c3RlbS5WZXJzaW9uAgAAAAkDAAAABgQAAADeBjw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi0xNiI/Pg0KPHhzOnNjaGVtYSB0YXJnZXROYW1lc3BhY2U9Im15bnMxIiB4bWxuczptc3Rucz0ibXluczEiIHhtbG5zPSJteW5zMSIgeG1sbnM6eHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hIiB4bWxuczptc2RhdGE9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLW1zZGF0YSIgYXR0cmlidXRlRm9ybURlZmF1bHQ9InF1YWxpZmllZCIgZWxlbWVudEZvcm1EZWZhdWx0PSJxdWFsaWZpZWQiPg0KICA8eHM6ZWxlbWVudCBuYW1lPSJhYmMiIG1zZGF0YTpMb2NhbGU9IiI+DQogICAgPHhzOmNvbXBsZXhUeXBlPg0KICAgICAgPHhzOnNlcXVlbmNlPg0KICAgICAgICA8eHM6ZWxlbWVudCBuYW1lPSJjb2wxIiB0eXBlPSJ4czpzdHJpbmciIG1zZGF0YTp0YXJnZXROYW1lc3BhY2U9Im15bnMxIiBtaW5PY2N1cnM9IjAiIC8+DQogICAgICAgIDx4czplbGVtZW50IG5hbWU9ImNvbDIiIHR5cGU9InhzOnN0cmluZyIgbXNkYXRhOnRhcmdldE5hbWVzcGFjZT0ibXluczEiIG1pbk9jY3Vycz0iMCIgLz4NCiAgICAgIDwveHM6c2VxdWVuY2U+DQogICAgPC94czpjb21wbGV4VHlwZT4NCiAgPC94czplbGVtZW50Pg0KICA8eHM6ZWxlbWVudCBuYW1lPSJEYXRhU2V0MTIzIiBtc2RhdGE6SXNEYXRhU2V0PSJ0cnVlIiBtc2RhdGE6TWFpbkRhdGFUYWJsZT0ibXluczFfeDAwM0FfYWJjIiBtc2RhdGE6TG9jYWxlPSIiPg0KICAgIDx4czpjb21wbGV4VHlwZT4NCiAgICAgIDx4czpjaG9pY2UgbWluT2NjdXJzPSIwIiBtYXhPY2N1cnM9InVuYm91bmRlZCIgLz4NCiAgICA8L3hzOmNvbXBsZXhUeXBlPg0KICA8L3hzOmVsZW1lbnQ+DQo8L3hzOnNjaGVtYT4GBQAAANwDPGRpZmZncjpkaWZmZ3JhbSB4bWxuczptc2RhdGE9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLW1zZGF0YSIgeG1sbnM6ZGlmZmdyPSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOnhtbC1kaWZmZ3JhbS12MSI+DQogIDxEYXRhU2V0MTIzIHhtbG5zPSJteW5zMSI+DQogICAgPGFiYyBkaWZmZ3I6aWQ9ImFiYzEiIG1zZGF0YTpyb3dPcmRlcj0iMCIgZGlmZmdyOmhhc0NoYW5nZXM9Imluc2VydGVkIj4NCiAgICAgIDxjb2wxPmZvbzwvY29sMT4NCiAgICAgIDxjb2wyPmJhcjwvY29sMj4NCiAgICA8L2FiYz4NCiAgICA8YWJjIGRpZmZncjppZD0iYWJjMiIgbXNkYXRhOnJvd09yZGVyPSIxIiBkaWZmZ3I6aGFzQ2hhbmdlcz0iaW5zZXJ0ZWQiPg0KICAgICAgPGNvbDE+YXNkYXNkPC9jb2wxPg0KICAgICAgPGNvbDI+ZmZmZmZmZmZmPC9jb2wyPg0KICAgIDwvYWJjPg0KICA8L0RhdGFTZXQxMjM+DQo8L2RpZmZncjpkaWZmZ3JhbT4EAwAAAA5TeXN0ZW0uVmVyc2lvbgQAAAAGX01ham9yBl9NaW5vcgZfQnVpbGQJX1JldmlzaW9uAAAAAAgICAgCAAAAAAAAAP//////////Cw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABVTeXN0ZW0uRGF0YS5EYXRhVGFibGUDAAAAGURhdGFUYWJsZS5SZW1vdGluZ1ZlcnNpb24JWG1sU2NoZW1hC1htbERpZmZHcmFtAwEBDlN5c3RlbS5WZXJzaW9uAgAAAAkDAAAABgQAAADeBjw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi0xNiI/Pg0KPHhzOnNjaGVtYSB0YXJnZXROYW1lc3BhY2U9Im15bnMxIiB4bWxuczptc3Rucz0ibXluczEiIHhtbG5zPSJteW5zMSIgeG1sbnM6eHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hIiB4bWxuczptc2RhdGE9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLW1zZGF0YSIgYXR0cmlidXRlRm9ybURlZmF1bHQ9InF1YWxpZmllZCIgZWxlbWVudEZvcm1EZWZhdWx0PSJxdWFsaWZpZWQiPg0KICA8eHM6ZWxlbWVudCBuYW1lPSJhYmMiIG1zZGF0YTpMb2NhbGU9IiI+DQogICAgPHhzOmNvbXBsZXhUeXBlPg0KICAgICAgPHhzOnNlcXVlbmNlPg0KICAgICAgICA8eHM6ZWxlbWVudCBuYW1lPSJjb2wxIiB0eXBlPSJ4czpzdHJpbmciIG1zZGF0YTp0YXJnZXROYW1lc3BhY2U9Im15bnMxIiBtaW5PY2N1cnM9IjAiIC8+DQogICAgICAgIDx4czplbGVtZW50IG5hbWU9ImNvbDIiIHR5cGU9InhzOnN0cmluZyIgbXNkYXRhOnRhcmdldE5hbWVzcGFjZT0ibXluczEiIG1pbk9jY3Vycz0iMCIgLz4NCiAgICAgIDwveHM6c2VxdWVuY2U+DQogICAgPC94czpjb21wbGV4VHlwZT4NCiAgPC94czplbGVtZW50Pg0KICA8eHM6ZWxlbWVudCBuYW1lPSJEYXRhU2V0MTIzIiBtc2RhdGE6SXNEYXRhU2V0PSJ0cnVlIiBtc2RhdGE6TWFpbkRhdGFUYWJsZT0ibXluczFfeDAwM0FfYWJjIiBtc2RhdGE6TG9jYWxlPSIiPg0KICAgIDx4czpjb21wbGV4VHlwZT4NCiAgICAgIDx4czpjaG9pY2UgbWluT2NjdXJzPSIwIiBtYXhPY2N1cnM9InVuYm91bmRlZCIgLz4NCiAgICA8L3hzOmNvbXBsZXhUeXBlPg0KICA8L3hzOmVsZW1lbnQ+DQo8L3hzOnNjaGVtYT4GBQAAANwDPGRpZmZncjpkaWZmZ3JhbSB4bWxuczptc2RhdGE9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLW1zZGF0YSIgeG1sbnM6ZGlmZmdyPSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOnhtbC1kaWZmZ3JhbS12MSI+DQogIDxEYXRhU2V0MTIzIHhtbG5zPSJteW5zMSI+DQogICAgPGFiYyBkaWZmZ3I6aWQ9ImFiYzEiIG1zZGF0YTpyb3dPcmRlcj0iMCIgZGlmZmdyOmhhc0NoYW5nZXM9Imluc2VydGVkIj4NCiAgICAgIDxjb2wxPmZvbzwvY29sMT4NCiAgICAgIDxjb2wyPmJhcjwvY29sMj4NCiAgICA8L2FiYz4NCiAgICA8YWJjIGRpZmZncjppZD0iYWJjMiIgbXNkYXRhOnJvd09yZGVyPSIxIiBkaWZmZ3I6aGFzQ2hhbmdlcz0iaW5zZXJ0ZWQiPg0KICAgICAgPGNvbDE+YXNkYXNkPC9jb2wxPg0KICAgICAgPGNvbDI+ZmZmZmZmZmZmPC9jb2wyPg0KICAgIDwvYWJjPg0KICA8L0RhdGFTZXQxMjM+DQo8L2RpZmZncjpkaWZmZ3JhbT4EAwAAAA5TeXN0ZW0uVmVyc2lvbgQAAAAGX01ham9yBl9NaW5vcgZfQnVpbGQJX1JldmlzaW9uAAAAAAgICAgCAAAAAAAAAP//////////Cw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { dt2, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABVTeXN0ZW0uRGF0YS5EYXRhVGFibGUDAAAAGURhdGFUYWJsZS5SZW1vdGluZ1ZlcnNpb24JWG1sU2NoZW1hC1htbERpZmZHcmFtAwEBDlN5c3RlbS5WZXJzaW9uAgAAAAkDAAAABgQAAADeBTw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi0xNiI/Pg0KPHhzOnNjaGVtYSB4bWxucz0iIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIj4NCiAgPHhzOmVsZW1lbnQgbmFtZT0ic2Rmc2RmIiBtc2RhdGE6TG9jYWxlPSIiPg0KICAgIDx4czpjb21wbGV4VHlwZT4NCiAgICAgIDx4czpzZXF1ZW5jZT4NCiAgICAgICAgPHhzOmVsZW1lbnQgbmFtZT0ia2trIiB0eXBlPSJ4czpzdHJpbmciIG1zZGF0YTp0YXJnZXROYW1lc3BhY2U9IiIgbWluT2NjdXJzPSIwIiAvPg0KICAgICAgICA8eHM6ZWxlbWVudCBuYW1lPSJqZmpmamYiIHR5cGU9InhzOnN0cmluZyIgbXNkYXRhOnRhcmdldE5hbWVzcGFjZT0iIiBtaW5PY2N1cnM9IjAiIC8+DQogICAgICA8L3hzOnNlcXVlbmNlPg0KICAgIDwveHM6Y29tcGxleFR5cGU+DQogIDwveHM6ZWxlbWVudD4NCiAgPHhzOmVsZW1lbnQgbmFtZT0iRGF0YVNldDEyMyIgbXNkYXRhOklzRGF0YVNldD0idHJ1ZSIgbXNkYXRhOk1haW5EYXRhVGFibGU9InNkZnNkZiIgbXNkYXRhOkxvY2FsZT0iIj4NCiAgICA8eHM6Y29tcGxleFR5cGU+DQogICAgICA8eHM6Y2hvaWNlIG1pbk9jY3Vycz0iMCIgbWF4T2NjdXJzPSJ1bmJvdW5kZWQiIC8+DQogICAgPC94czpjb21wbGV4VHlwZT4NCiAgPC94czplbGVtZW50Pg0KPC94czpzY2hlbWE+BgUAAADiBDxkaWZmZ3I6ZGlmZmdyYW0geG1sbnM6bXNkYXRhPSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOnhtbC1tc2RhdGEiIHhtbG5zOmRpZmZncj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtZGlmZmdyYW0tdjEiPg0KICA8RGF0YVNldDEyMz4NCiAgICA8c2Rmc2RmIGRpZmZncjppZD0ic2Rmc2RmMSIgbXNkYXRhOnJvd09yZGVyPSIwIiBkaWZmZ3I6aGFzQ2hhbmdlcz0iaW5zZXJ0ZWQiPg0KICAgICAgPGtraz5mZjE8L2traz4NCiAgICAgIDxqZmpmamY+ZmYyPC9qZmpmamY+DQogICAgPC9zZGZzZGY+DQogICAgPHNkZnNkZiBkaWZmZ3I6aWQ9InNkZnNkZjIiIG1zZGF0YTpyb3dPcmRlcj0iMSIgZGlmZmdyOmhhc0NoYW5nZXM9Imluc2VydGVkIj4NCiAgICAgIDxra2s+b29vPC9ra2s+DQogICAgICA8amZqZmpmPnNkZmxranNkZmxranNkPC9qZmpmamY+DQogICAgPC9zZGZzZGY+DQogICAgPHNkZnNkZiBkaWZmZ3I6aWQ9InNkZnNkZjMiIG1zZGF0YTpyb3dPcmRlcj0iMiIgZGlmZmdyOmhhc0NoYW5nZXM9Imluc2VydGVkIj4NCiAgICAgIDxra2s+bnVsbHZhbDwva2trPg0KICAgIDwvc2Rmc2RmPg0KICA8L0RhdGFTZXQxMjM+DQo8L2RpZmZncjpkaWZmZ3JhbT4EAwAAAA5TeXN0ZW0uVmVyc2lvbgQAAAAGX01ham9yBl9NaW5vcgZfQnVpbGQJX1JldmlzaW9uAAAAAAgICAgCAAAAAAAAAP//////////Cw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABVTeXN0ZW0uRGF0YS5EYXRhVGFibGUDAAAAGURhdGFUYWJsZS5SZW1vdGluZ1ZlcnNpb24JWG1sU2NoZW1hC1htbERpZmZHcmFtAwEBDlN5c3RlbS5WZXJzaW9uAgAAAAkDAAAABgQAAADeBTw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi0xNiI/Pg0KPHhzOnNjaGVtYSB4bWxucz0iIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIj4NCiAgPHhzOmVsZW1lbnQgbmFtZT0ic2Rmc2RmIiBtc2RhdGE6TG9jYWxlPSIiPg0KICAgIDx4czpjb21wbGV4VHlwZT4NCiAgICAgIDx4czpzZXF1ZW5jZT4NCiAgICAgICAgPHhzOmVsZW1lbnQgbmFtZT0ia2trIiB0eXBlPSJ4czpzdHJpbmciIG1zZGF0YTp0YXJnZXROYW1lc3BhY2U9IiIgbWluT2NjdXJzPSIwIiAvPg0KICAgICAgICA8eHM6ZWxlbWVudCBuYW1lPSJqZmpmamYiIHR5cGU9InhzOnN0cmluZyIgbXNkYXRhOnRhcmdldE5hbWVzcGFjZT0iIiBtaW5PY2N1cnM9IjAiIC8+DQogICAgICA8L3hzOnNlcXVlbmNlPg0KICAgIDwveHM6Y29tcGxleFR5cGU+DQogIDwveHM6ZWxlbWVudD4NCiAgPHhzOmVsZW1lbnQgbmFtZT0iRGF0YVNldDEyMyIgbXNkYXRhOklzRGF0YVNldD0idHJ1ZSIgbXNkYXRhOk1haW5EYXRhVGFibGU9InNkZnNkZiIgbXNkYXRhOkxvY2FsZT0iIj4NCiAgICA8eHM6Y29tcGxleFR5cGU+DQogICAgICA8eHM6Y2hvaWNlIG1pbk9jY3Vycz0iMCIgbWF4T2NjdXJzPSJ1bmJvdW5kZWQiIC8+DQogICAgPC94czpjb21wbGV4VHlwZT4NCiAgPC94czplbGVtZW50Pg0KPC94czpzY2hlbWE+BgUAAADiBDxkaWZmZ3I6ZGlmZmdyYW0geG1sbnM6bXNkYXRhPSJ1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOnhtbC1tc2RhdGEiIHhtbG5zOmRpZmZncj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtZGlmZmdyYW0tdjEiPg0KICA8RGF0YVNldDEyMz4NCiAgICA8c2Rmc2RmIGRpZmZncjppZD0ic2Rmc2RmMSIgbXNkYXRhOnJvd09yZGVyPSIwIiBkaWZmZ3I6aGFzQ2hhbmdlcz0iaW5zZXJ0ZWQiPg0KICAgICAgPGtraz5mZjE8L2traz4NCiAgICAgIDxqZmpmamY+ZmYyPC9qZmpmamY+DQogICAgPC9zZGZzZGY+DQogICAgPHNkZnNkZiBkaWZmZ3I6aWQ9InNkZnNkZjIiIG1zZGF0YTpyb3dPcmRlcj0iMSIgZGlmZmdyOmhhc0NoYW5nZXM9Imluc2VydGVkIj4NCiAgICAgIDxra2s+b29vPC9ra2s+DQogICAgICA8amZqZmpmPnNkZmxranNkZmxranNkPC9qZmpmamY+DQogICAgPC9zZGZzZGY+DQogICAgPHNkZnNkZiBkaWZmZ3I6aWQ9InNkZnNkZjMiIG1zZGF0YTpyb3dPcmRlcj0iMiIgZGlmZmdyOmhhc0NoYW5nZXM9Imluc2VydGVkIj4NCiAgICAgIDxra2s+bnVsbHZhbDwva2trPg0KICAgIDwvc2Rmc2RmPg0KICA8L0RhdGFTZXQxMjM+DQo8L2RpZmZncjpkaWZmZ3JhbT4EAwAAAA5TeXN0ZW0uVmVyc2lvbgQAAAAGX01ham9yBl9NaW5vcgZfQnVpbGQJX1JldmlzaW9uAAAAAAgICAgCAAAAAAAAAP//////////Cw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { ds, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABNTeXN0ZW0uRGF0YS5EYXRhU2V0AwAAABdEYXRhU2V0LlJlbW90aW5nVmVyc2lvbglYbWxTY2hlbWELWG1sRGlmZkdyYW0DAQEOU3lzdGVtLlZlcnNpb24CAAAACQMAAAAGBAAAALoJPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+DQo8eHM6c2NoZW1hIGlkPSJEYXRhU2V0MTIzIiB4bWxucz0iIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIj4NCiAgPHhzOmVsZW1lbnQgbmFtZT0iRGF0YVNldDEyMyIgbXNkYXRhOklzRGF0YVNldD0idHJ1ZSIgbXNkYXRhOkxvY2FsZT0iIj4NCiAgICA8eHM6Y29tcGxleFR5cGU+DQogICAgICA8eHM6Y2hvaWNlIG1pbk9jY3Vycz0iMCIgbWF4T2NjdXJzPSJ1bmJvdW5kZWQiPg0KICAgICAgICA8eHM6ZWxlbWVudCBtc2RhdGE6dGFyZ2V0TmFtZXNwYWNlPSJteW5zMSIgbmFtZT0iYWJjIiBtc2RhdGE6TG9jYWxlPSIiPg0KICAgICAgICAgIDx4czpjb21wbGV4VHlwZT4NCiAgICAgICAgICAgIDx4czpzZXF1ZW5jZT4NCiAgICAgICAgICAgICAgPHhzOmVsZW1lbnQgbmFtZT0iY29sMSIgdHlwZT0ieHM6c3RyaW5nIiBtc2RhdGE6dGFyZ2V0TmFtZXNwYWNlPSJteW5zMSIgbWluT2NjdXJzPSIwIiAvPg0KICAgICAgICAgICAgICA8eHM6ZWxlbWVudCBuYW1lPSJjb2wyIiB0eXBlPSJ4czpzdHJpbmciIG1zZGF0YTp0YXJnZXROYW1lc3BhY2U9Im15bnMxIiBtaW5PY2N1cnM9IjAiIC8+DQogICAgICAgICAgICA8L3hzOnNlcXVlbmNlPg0KICAgICAgICAgIDwveHM6Y29tcGxleFR5cGU+DQogICAgICAgIDwveHM6ZWxlbWVudD4NCiAgICAgICAgPHhzOmVsZW1lbnQgbmFtZT0ic2Rmc2RmIiBtc2RhdGE6TG9jYWxlPSIiPg0KICAgICAgICAgIDx4czpjb21wbGV4VHlwZT4NCiAgICAgICAgICAgIDx4czpzZXF1ZW5jZT4NCiAgICAgICAgICAgICAgPHhzOmVsZW1lbnQgbmFtZT0ia2trIiB0eXBlPSJ4czpzdHJpbmciIG1zZGF0YTp0YXJnZXROYW1lc3BhY2U9IiIgbWluT2NjdXJzPSIwIiAvPg0KICAgICAgICAgICAgICA8eHM6ZWxlbWVudCBuYW1lPSJqZmpmamYiIHR5cGU9InhzOnN0cmluZyIgbXNkYXRhOnRhcmdldE5hbWVzcGFjZT0iIiBtaW5PY2N1cnM9IjAiIC8+DQogICAgICAgICAgICA8L3hzOnNlcXVlbmNlPg0KICAgICAgICAgIDwveHM6Y29tcGxleFR5cGU+DQogICAgICAgIDwveHM6ZWxlbWVudD4NCiAgICAgIDwveHM6Y2hvaWNlPg0KICAgIDwveHM6Y29tcGxleFR5cGU+DQogIDwveHM6ZWxlbWVudD4NCjwveHM6c2NoZW1hPgYFAAAAiwY8ZGlmZmdyOmRpZmZncmFtIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIiB4bWxuczpkaWZmZ3I9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLWRpZmZncmFtLXYxIj48RGF0YVNldDEyMz48YWJjIGRpZmZncjppZD0iYWJjMSIgbXNkYXRhOnJvd09yZGVyPSIwIiBkaWZmZ3I6aGFzQ2hhbmdlcz0iaW5zZXJ0ZWQiIHhtbG5zPSJteW5zMSI+PGNvbDE+Zm9vPC9jb2wxPjxjb2wyPmJhcjwvY29sMj48L2FiYz48YWJjIGRpZmZncjppZD0iYWJjMiIgbXNkYXRhOnJvd09yZGVyPSIxIiBkaWZmZ3I6aGFzQ2hhbmdlcz0iaW5zZXJ0ZWQiIHhtbG5zPSJteW5zMSI+PGNvbDE+YXNkYXNkPC9jb2wxPjxjb2wyPmZmZmZmZmZmZjwvY29sMj48L2FiYz48c2Rmc2RmIGRpZmZncjppZD0ic2Rmc2RmMSIgbXNkYXRhOnJvd09yZGVyPSIwIiBkaWZmZ3I6aGFzQ2hhbmdlcz0iaW5zZXJ0ZWQiPjxra2s+ZmYxPC9ra2s+PGpmamZqZj5mZjI8L2pmamZqZj48L3NkZnNkZj48c2Rmc2RmIGRpZmZncjppZD0ic2Rmc2RmMiIgbXNkYXRhOnJvd09yZGVyPSIxIiBkaWZmZ3I6aGFzQ2hhbmdlcz0iaW5zZXJ0ZWQiPjxra2s+b29vPC9ra2s+PGpmamZqZj5zZGZsa2pzZGZsa2pzZDwvamZqZmpmPjwvc2Rmc2RmPjxzZGZzZGYgZGlmZmdyOmlkPSJzZGZzZGYzIiBtc2RhdGE6cm93T3JkZXI9IjIiIGRpZmZncjpoYXNDaGFuZ2VzPSJpbnNlcnRlZCI+PGtraz5udWxsdmFsPC9ra2s+PC9zZGZzZGY+PC9EYXRhU2V0MTIzPjwvZGlmZmdyOmRpZmZncmFtPgQDAAAADlN5c3RlbS5WZXJzaW9uBAAAAAZfTWFqb3IGX01pbm9yBl9CdWlsZAlfUmV2aXNpb24AAAAACAgICAIAAAAAAAAA//////////8L", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABNTeXN0ZW0uRGF0YS5EYXRhU2V0AwAAABdEYXRhU2V0LlJlbW90aW5nVmVyc2lvbglYbWxTY2hlbWELWG1sRGlmZkdyYW0DAQEOU3lzdGVtLlZlcnNpb24CAAAACQMAAAAGBAAAALoJPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+DQo8eHM6c2NoZW1hIGlkPSJEYXRhU2V0MTIzIiB4bWxucz0iIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIj4NCiAgPHhzOmVsZW1lbnQgbmFtZT0iRGF0YVNldDEyMyIgbXNkYXRhOklzRGF0YVNldD0idHJ1ZSIgbXNkYXRhOkxvY2FsZT0iIj4NCiAgICA8eHM6Y29tcGxleFR5cGU+DQogICAgICA8eHM6Y2hvaWNlIG1pbk9jY3Vycz0iMCIgbWF4T2NjdXJzPSJ1bmJvdW5kZWQiPg0KICAgICAgICA8eHM6ZWxlbWVudCBtc2RhdGE6dGFyZ2V0TmFtZXNwYWNlPSJteW5zMSIgbmFtZT0iYWJjIiBtc2RhdGE6TG9jYWxlPSIiPg0KICAgICAgICAgIDx4czpjb21wbGV4VHlwZT4NCiAgICAgICAgICAgIDx4czpzZXF1ZW5jZT4NCiAgICAgICAgICAgICAgPHhzOmVsZW1lbnQgbmFtZT0iY29sMSIgdHlwZT0ieHM6c3RyaW5nIiBtc2RhdGE6dGFyZ2V0TmFtZXNwYWNlPSJteW5zMSIgbWluT2NjdXJzPSIwIiAvPg0KICAgICAgICAgICAgICA8eHM6ZWxlbWVudCBuYW1lPSJjb2wyIiB0eXBlPSJ4czpzdHJpbmciIG1zZGF0YTp0YXJnZXROYW1lc3BhY2U9Im15bnMxIiBtaW5PY2N1cnM9IjAiIC8+DQogICAgICAgICAgICA8L3hzOnNlcXVlbmNlPg0KICAgICAgICAgIDwveHM6Y29tcGxleFR5cGU+DQogICAgICAgIDwveHM6ZWxlbWVudD4NCiAgICAgICAgPHhzOmVsZW1lbnQgbmFtZT0ic2Rmc2RmIiBtc2RhdGE6TG9jYWxlPSIiPg0KICAgICAgICAgIDx4czpjb21wbGV4VHlwZT4NCiAgICAgICAgICAgIDx4czpzZXF1ZW5jZT4NCiAgICAgICAgICAgICAgPHhzOmVsZW1lbnQgbmFtZT0ia2trIiB0eXBlPSJ4czpzdHJpbmciIG1zZGF0YTp0YXJnZXROYW1lc3BhY2U9IiIgbWluT2NjdXJzPSIwIiAvPg0KICAgICAgICAgICAgICA8eHM6ZWxlbWVudCBuYW1lPSJqZmpmamYiIHR5cGU9InhzOnN0cmluZyIgbXNkYXRhOnRhcmdldE5hbWVzcGFjZT0iIiBtaW5PY2N1cnM9IjAiIC8+DQogICAgICAgICAgICA8L3hzOnNlcXVlbmNlPg0KICAgICAgICAgIDwveHM6Y29tcGxleFR5cGU+DQogICAgICAgIDwveHM6ZWxlbWVudD4NCiAgICAgIDwveHM6Y2hvaWNlPg0KICAgIDwveHM6Y29tcGxleFR5cGU+DQogIDwveHM6ZWxlbWVudD4NCjwveHM6c2NoZW1hPgYFAAAAiwY8ZGlmZmdyOmRpZmZncmFtIHhtbG5zOm1zZGF0YT0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp4bWwtbXNkYXRhIiB4bWxuczpkaWZmZ3I9InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206eG1sLWRpZmZncmFtLXYxIj48RGF0YVNldDEyMz48YWJjIGRpZmZncjppZD0iYWJjMSIgbXNkYXRhOnJvd09yZGVyPSIwIiBkaWZmZ3I6aGFzQ2hhbmdlcz0iaW5zZXJ0ZWQiIHhtbG5zPSJteW5zMSI+PGNvbDE+Zm9vPC9jb2wxPjxjb2wyPmJhcjwvY29sMj48L2FiYz48YWJjIGRpZmZncjppZD0iYWJjMiIgbXNkYXRhOnJvd09yZGVyPSIxIiBkaWZmZ3I6aGFzQ2hhbmdlcz0iaW5zZXJ0ZWQiIHhtbG5zPSJteW5zMSI+PGNvbDE+YXNkYXNkPC9jb2wxPjxjb2wyPmZmZmZmZmZmZjwvY29sMj48L2FiYz48c2Rmc2RmIGRpZmZncjppZD0ic2Rmc2RmMSIgbXNkYXRhOnJvd09yZGVyPSIwIiBkaWZmZ3I6aGFzQ2hhbmdlcz0iaW5zZXJ0ZWQiPjxra2s+ZmYxPC9ra2s+PGpmamZqZj5mZjI8L2pmamZqZj48L3NkZnNkZj48c2Rmc2RmIGRpZmZncjppZD0ic2Rmc2RmMiIgbXNkYXRhOnJvd09yZGVyPSIxIiBkaWZmZ3I6aGFzQ2hhbmdlcz0iaW5zZXJ0ZWQiPjxra2s+b29vPC9ra2s+PGpmamZqZj5zZGZsa2pzZGZsa2pzZDwvamZqZmpmPjwvc2Rmc2RmPjxzZGZzZGYgZGlmZmdyOmlkPSJzZGZzZGYzIiBtc2RhdGE6cm93T3JkZXI9IjIiIGRpZmZncjpoYXNDaGFuZ2VzPSJpbnNlcnRlZCI+PGtraz5udWxsdmFsPC9ra2s+PC9zZGZzZGY+PC9EYXRhU2V0MTIzPjwvZGlmZmdyOmRpZmZncmFtPgQDAAAADlN5c3RlbS5WZXJzaW9uBAAAAAZfTWFqb3IGX01pbm9yBl9CdWlsZAlfUmV2aXNpb24AAAAACAgICAIAAAAAAAAA//////////8L", TargetFrameworkMoniker.netfx461) } };
var propertyCollection = new System.Data.PropertyCollection
{
{ "p1", "v1" }
};
- yield return new object[] { propertyCollection, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5Qcm9wZXJ0eUNvbGxlY3Rpb24HAAAACkxvYWRGYWN0b3IHVmVyc2lvbghDb21wYXJlchBIYXNoQ29kZVByb3ZpZGVyCEhhc2hTaXplBEtleXMGVmFsdWVzAAADAwAFBQsIHFN5c3RlbS5Db2xsZWN0aW9ucy5JQ29tcGFyZXIkU3lzdGVtLkNvbGxlY3Rpb25zLklIYXNoQ29kZVByb3ZpZGVyCAIAAADsUTg/AQAAAAoKAwAAAAkDAAAACQQAAAAQAwAAAAEAAAAGBQAAAAJwMRAEAAAAAQAAAAYGAAAAAnYxCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5Qcm9wZXJ0eUNvbGxlY3Rpb24HAAAACkxvYWRGYWN0b3IHVmVyc2lvbghDb21wYXJlchBIYXNoQ29kZVByb3ZpZGVyCEhhc2hTaXplBEtleXMGVmFsdWVzAAADAwAFBQsIHFN5c3RlbS5Db2xsZWN0aW9ucy5JQ29tcGFyZXIkU3lzdGVtLkNvbGxlY3Rpb25zLklIYXNoQ29kZVByb3ZpZGVyCAIAAADsUTg/AQAAAAoKAwAAAAkDAAAACQQAAAAQAwAAAAEAAAAGBQAAAAJwMRAEAAAAAQAAAAYGAAAAAnYxCw==" } };
- yield return new object[] { new SqlGuid(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABxTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxHdWlkAQAAAAdtX3ZhbHVlBwICAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABxTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxHdWlkAQAAAAdtX3ZhbHVlBwICAAAACgs=" } };
- yield return new object[] { new SqlGuid(new byte[] { 74, 17, 188, 26, 104, 117, 191, 64, 132, 93, 95, 0, 182, 136, 150, 121 }), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABxTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxHdWlkAQAAAAdtX3ZhbHVlBwICAAAACQMAAAAPAwAAABAAAAACShG8Gmh1v0CEXV8AtoiWeQs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABxTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxHdWlkAQAAAAdtX3ZhbHVlBwICAAAACQMAAAAPAwAAABAAAAACShG8Gmh1v0CEXV8AtoiWeQs=" } };
- yield return new object[] { new SqlGuid(new Guid("aad872f5-82bb-4989-af0f-bee5de636fd7")), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABxTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxHdWlkAQAAAAdtX3ZhbHVlBwICAAAACQMAAAAPAwAAABAAAAAC9XLYqruCiUmvD77l3mNv1ws=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABxTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxHdWlkAQAAAAdtX3ZhbHVlBwICAAAACQMAAAAPAwAAABAAAAAC9XLYqruCiUmvD77l3mNv1ws=" } };
- yield return new object[] { new SqlGuid("aad872f5-82bb-4989-af0f-bee5de636fd7"), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABxTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxHdWlkAQAAAAdtX3ZhbHVlBwICAAAACQMAAAAPAwAAABAAAAAC9XLYqruCiUmvD77l3mNv1ws=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABxTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxHdWlkAQAAAAdtX3ZhbHVlBwICAAAACQMAAAAPAwAAABAAAAAC9XLYqruCiUmvD77l3mNv1ws=" } };
- yield return new object[] { new SqlBoolean(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB9TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxCb29sZWFuAQAAAAdtX3ZhbHVlAAICAAAAAAs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB9TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxCb29sZWFuAQAAAAdtX3ZhbHVlAAICAAAAAAs=" } };
- yield return new object[] { new SqlBoolean(1), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB9TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxCb29sZWFuAQAAAAdtX3ZhbHVlAAICAAAAAgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB9TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxCb29sZWFuAQAAAAdtX3ZhbHVlAAICAAAAAgs=" } };
- yield return new object[] { new SqlBoolean(true), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB9TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxCb29sZWFuAQAAAAdtX3ZhbHVlAAICAAAAAgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB9TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxCb29sZWFuAQAAAAdtX3ZhbHVlAAICAAAAAgs=" } };
- yield return new object[] { new SqlByte(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABxTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxCeXRlAgAAAAptX2ZOb3ROdWxsB21fdmFsdWUAAAECAgAAAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABxTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxCeXRlAgAAAAptX2ZOb3ROdWxsB21fdmFsdWUAAAECAgAAAAAACw==" } };
- yield return new object[] { new SqlByte(255), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABxTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxCeXRlAgAAAAptX2ZOb3ROdWxsB21fdmFsdWUAAAECAgAAAAH/Cw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABxTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxCeXRlAgAAAAptX2ZOb3ROdWxsB21fdmFsdWUAAAECAgAAAAH/Cw==" } };
- yield return new object[] { new SqlDateTime(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEYXRlVGltZQMAAAAKbV9mTm90TnVsbAVtX2RheQZtX3RpbWUAAAABCAgCAAAAAAAAAAAAAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEYXRlVGltZQMAAAAKbV9mTm90TnVsbAVtX2RheQZtX3RpbWUAAAABCAgCAAAAAAAAAAAAAAAACw==" } };
- yield return new object[] { new SqlDateTime(123, 546), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEYXRlVGltZQMAAAAKbV9mTm90TnVsbAVtX2RheQZtX3RpbWUAAAABCAgCAAAAAXsAAAAiAgAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEYXRlVGltZQMAAAAKbV9mTm90TnVsbAVtX2RheQZtX3RpbWUAAAABCAgCAAAAAXsAAAAiAgAACw==" } };
- yield return new object[] { new SqlDateTime(2017, 11, 3), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEYXRlVGltZQMAAAAKbV9mTm90TnVsbAVtX2RheQZtX3RpbWUAAAABCAgCAAAAASCoAAAAAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEYXRlVGltZQMAAAAKbV9mTm90TnVsbAVtX2RheQZtX3RpbWUAAAABCAgCAAAAASCoAAAAAAAACw==" } };
- yield return new object[] { new SqlDateTime(2017, 11, 3, 4, 50, 30), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEYXRlVGltZQMAAAAKbV9mTm90TnVsbAVtX2RheQZtX3RpbWUAAAABCAgCAAAAASCoAADIyU8ACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEYXRlVGltZQMAAAAKbV9mTm90TnVsbAVtX2RheQZtX3RpbWUAAAABCAgCAAAAASCoAADIyU8ACw==" } };
- yield return new object[] { new SqlDateTime(2017, 11, 3, 4, 50, 30, 99.9), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEYXRlVGltZQMAAAAKbV9mTm90TnVsbAVtX2RheQZtX3RpbWUAAAABCAgCAAAAASCoAADmyU8ACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEYXRlVGltZQMAAAAKbV9mTm90TnVsbAVtX2RheQZtX3RpbWUAAAABCAgCAAAAASCoAADmyU8ACw==" } };
- yield return new object[] { new SqlDateTime(new DateTime(1990, 11, 23, 03, 30, 00, 00, DateTimeKind.Utc)), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEYXRlVGltZQMAAAAKbV9mTm90TnVsbAVtX2RheQZtX3RpbWUAAAABCAgCAAAAAa6BAACgrTkACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEYXRlVGltZQMAAAAKbV9mTm90TnVsbAVtX2RheQZtX3RpbWUAAAABCAgCAAAAAa6BAACgrTkACw==" } };
- yield return new object[] { new SqlDouble(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEb3VibGUCAAAACm1fZk5vdE51bGwHbV92YWx1ZQAAAQYCAAAAAAAAAAAAAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEb3VibGUCAAAACm1fZk5vdE51bGwHbV92YWx1ZQAAAQYCAAAAAAAAAAAAAAAACw==" } };
- yield return new object[] { new SqlDouble(34.5), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEb3VibGUCAAAACm1fZk5vdE51bGwHbV92YWx1ZQAAAQYCAAAAAQAAAAAAQEFACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEb3VibGUCAAAACm1fZk5vdE51bGwHbV92YWx1ZQAAAQYCAAAAAQAAAAAAQEFACw==" } };
- yield return new object[] { new SqlInt16(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxJbnQxNgIAAAAKbV9mTm90TnVsbAdtX3ZhbHVlAAABBwIAAAAAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxJbnQxNgIAAAAKbV9mTm90TnVsbAdtX3ZhbHVlAAABBwIAAAAAAAAL" } };
- yield return new object[] { new SqlInt16(256), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxJbnQxNgIAAAAKbV9mTm90TnVsbAdtX3ZhbHVlAAABBwIAAAABAAEL", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxJbnQxNgIAAAAKbV9mTm90TnVsbAdtX3ZhbHVlAAABBwIAAAABAAEL" } };
- yield return new object[] { new SqlInt32(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxJbnQzMgIAAAAKbV9mTm90TnVsbAdtX3ZhbHVlAAABCAIAAAAAAAAAAAs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxJbnQzMgIAAAAKbV9mTm90TnVsbAdtX3ZhbHVlAAABCAIAAAAAAAAAAAs=" } };
- yield return new object[] { new SqlInt32(4096314), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxJbnQzMgIAAAAKbV9mTm90TnVsbAdtX3ZhbHVlAAABCAIAAAABOoE+AAs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxJbnQzMgIAAAAKbV9mTm90TnVsbAdtX3ZhbHVlAAABCAIAAAABOoE+AAs=" } };
- yield return new object[] { new SqlInt64(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxJbnQ2NAIAAAAKbV9mTm90TnVsbAdtX3ZhbHVlAAABCQIAAAAAAAAAAAAAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxJbnQ2NAIAAAAKbV9mTm90TnVsbAdtX3ZhbHVlAAABCQIAAAAAAAAAAAAAAAAL" } };
- yield return new object[] { new SqlInt64(3492867384596), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxJbnQ2NAIAAAAKbV9mTm90TnVsbAdtX3ZhbHVlAAABCQIAAAABFKUePy0DAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxJbnQ2NAIAAAAKbV9mTm90TnVsbAdtX3ZhbHVlAAABCQIAAAABFKUePy0DAAAL" } };
- yield return new object[] { new SqlString(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAoKAAAAAAX9////JlN5c3RlbS5EYXRhLlNxbFR5cGVzLlNxbENvbXBhcmVPcHRpb25zAQAAAAd2YWx1ZV9fAAgCAAAAAAAAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAoKAAAAAAX9////JlN5c3RlbS5EYXRhLlNxbFR5cGVzLlNxbENvbXBhcmVPcHRpb25zAQAAAAd2YWx1ZV9fAAgCAAAAAAAAAAAL" } };
- yield return new object[] { new SqlString("abc", CultureInfo.InvariantCulture.LCID), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAYDAAAAA2FiYwp/AAAABfz///8mU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAIAAAAZAAAAAQs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAYDAAAAA2FiYwp/AAAABfz///8mU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAIAAAAZAAAAAQs=" } };
- yield return new object[] { new SqlString("abc", CultureInfo.InvariantCulture.LCID, SqlCompareOptions.BinarySort), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAYDAAAAA2FiYwp/AAAABfz///8mU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAIAAAAAgAAAAQs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAYDAAAAA2FiYwp/AAAABfz///8mU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAIAAAAAgAAAAQs=" } };
- yield return new object[] { new SqlString(CultureInfo.InvariantCulture.LCID, SqlCompareOptions.BinarySort, new byte[] { 65, 66, 67 }), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAYDAAAABuSJge+/vQp/AAAABfz///8mU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAIAAAAAgAAAAQs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAYDAAAABuSJge+/vQp/AAAABfz///8mU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAIAAAAAgAAAAQs=" } };
- yield return new object[] { new SqlString(CultureInfo.InvariantCulture.LCID, SqlCompareOptions.BinarySort, new byte[] { 65, 66, 67 }, true), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAYDAAAABuSJge+/vQp/AAAABfz///8mU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAIAAAAAgAAAAQs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAYDAAAABuSJge+/vQp/AAAABfz///8mU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAIAAAAAgAAAAQs=" } };
- yield return new object[] { new SqlString(CultureInfo.InvariantCulture.LCID, SqlCompareOptions.BinarySort, new byte[] { 65, 66, 67 }, 0, 3), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAYDAAAABuSJge+/vQp/AAAABfz///8mU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAIAAAAAgAAAAQs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAYDAAAABuSJge+/vQp/AAAABfz///8mU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAIAAAAAgAAAAQs=" } };
- yield return new object[] { new SqlString(CultureInfo.InvariantCulture.LCID, SqlCompareOptions.BinarySort, new byte[] { 65, 66, 67 }, 0, 3, true), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAYDAAAABuSJge+/vQp/AAAABfz///8mU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAIAAAAAgAAAAQs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAYDAAAABuSJge+/vQp/AAAABfz///8mU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAIAAAAAgAAAAQs=" } };
- yield return new object[] { DBNull.Value, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uVW5pdHlTZXJpYWxpemF0aW9uSG9sZGVyAwAAAAREYXRhCVVuaXR5VHlwZQxBc3NlbWJseU5hbWUBAAEICgIAAAAGAgAAAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uVW5pdHlTZXJpYWxpemF0aW9uSG9sZGVyAwAAAAREYXRhCVVuaXR5VHlwZQxBc3NlbWJseU5hbWUBAAEICgIAAAAGAgAAAAAL" } };
-
- yield return new object[] { new BigInteger(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAEFTeXN0ZW0uTnVtZXJpY3MsIFZlcnNpb249NC4wLjAuMCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAGlN5c3RlbS5OdW1lcmljcy5CaWdJbnRlZ2VyAgAAAAVfc2lnbgVfYml0cwAHCA8CAAAAAAAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAFJTeXN0ZW0uTnVtZXJpY3MsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAaU3lzdGVtLk51bWVyaWNzLkJpZ0ludGVnZXICAAAABV9zaWduBV9iaXRzAAcIDwIAAAAAAAAACgs=" } };
- yield return new object[] { new BigInteger(10324176), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAEFTeXN0ZW0uTnVtZXJpY3MsIFZlcnNpb249NC4wLjAuMCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAGlN5c3RlbS5OdW1lcmljcy5CaWdJbnRlZ2VyAgAAAAVfc2lnbgVfYml0cwAHCA8CAAAA0IidAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAFJTeXN0ZW0uTnVtZXJpY3MsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAaU3lzdGVtLk51bWVyaWNzLkJpZ0ludGVnZXICAAAABV9zaWduBV9iaXRzAAcIDwIAAADQiJ0ACgs=" } };
- yield return new object[] { new BigInteger(new byte[] { 1, 2, 3, 4, 5 }), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAEFTeXN0ZW0uTnVtZXJpY3MsIFZlcnNpb249NC4wLjAuMCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAGlN5c3RlbS5OdW1lcmljcy5CaWdJbnRlZ2VyAgAAAAVfc2lnbgVfYml0cwAHCA8CAAAAAQAAAAkDAAAADwMAAAACAAAADwECAwQFAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAFJTeXN0ZW0uTnVtZXJpY3MsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAaU3lzdGVtLk51bWVyaWNzLkJpZ0ludGVnZXICAAAABV9zaWduBV9iaXRzAAcIDwIAAAABAAAACQMAAAAPAwAAAAIAAAAPAQIDBAUAAAAL" } };
- yield return new object[] { new Complex(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAFJTeXN0ZW0uTnVtZXJpY3MsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAXU3lzdGVtLk51bWVyaWNzLkNvbXBsZXgCAAAABm1fcmVhbAttX2ltYWdpbmFyeQAABgYCAAAAAAAAAAAAAAAAAAAAAAAAAAs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAFJTeXN0ZW0uTnVtZXJpY3MsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAXU3lzdGVtLk51bWVyaWNzLkNvbXBsZXgCAAAABm1fcmVhbAttX2ltYWdpbmFyeQAABgYCAAAAAAAAAAAAAAAAAAAAAAAAAAs=" } };
- yield return new object[] { new Complex(12, 6), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAFJTeXN0ZW0uTnVtZXJpY3MsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAXU3lzdGVtLk51bWVyaWNzLkNvbXBsZXgCAAAABm1fcmVhbAttX2ltYWdpbmFyeQAABgYCAAAAAAAAAAAAKEAAAAAAAAAYQAs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAFJTeXN0ZW0uTnVtZXJpY3MsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAXU3lzdGVtLk51bWVyaWNzLkNvbXBsZXgCAAAABm1fcmVhbAttX2ltYWdpbmFyeQAABgYCAAAAAAAAAAAAKEAAAAAAAAAYQAs=" } };
+ yield return new object[] { propertyCollection, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5Qcm9wZXJ0eUNvbGxlY3Rpb24HAAAACkxvYWRGYWN0b3IHVmVyc2lvbghDb21wYXJlchBIYXNoQ29kZVByb3ZpZGVyCEhhc2hTaXplBEtleXMGVmFsdWVzAAADAwAFBQsIHFN5c3RlbS5Db2xsZWN0aW9ucy5JQ29tcGFyZXIkU3lzdGVtLkNvbGxlY3Rpb25zLklIYXNoQ29kZVByb3ZpZGVyCAIAAADsUTg/AQAAAAoKAwAAAAkDAAAACQQAAAAQAwAAAAEAAAAGBQAAAAJwMRAEAAAAAQAAAAYGAAAAAnYxCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5Qcm9wZXJ0eUNvbGxlY3Rpb24HAAAACkxvYWRGYWN0b3IHVmVyc2lvbghDb21wYXJlchBIYXNoQ29kZVByb3ZpZGVyCEhhc2hTaXplBEtleXMGVmFsdWVzAAADAwAFBQsIHFN5c3RlbS5Db2xsZWN0aW9ucy5JQ29tcGFyZXIkU3lzdGVtLkNvbGxlY3Rpb25zLklIYXNoQ29kZVByb3ZpZGVyCAIAAADsUTg/AQAAAAoKAwAAAAkDAAAACQQAAAAQAwAAAAEAAAAGBQAAAAJwMRAEAAAAAQAAAAYGAAAAAnYxCw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlGuid(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABxTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxHdWlkAQAAAAdtX3ZhbHVlBwICAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABxTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxHdWlkAQAAAAdtX3ZhbHVlBwICAAAACgs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlGuid(new byte[] { 74, 17, 188, 26, 104, 117, 191, 64, 132, 93, 95, 0, 182, 136, 150, 121 }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABxTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxHdWlkAQAAAAdtX3ZhbHVlBwICAAAACQMAAAAPAwAAABAAAAACShG8Gmh1v0CEXV8AtoiWeQs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABxTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxHdWlkAQAAAAdtX3ZhbHVlBwICAAAACQMAAAAPAwAAABAAAAACShG8Gmh1v0CEXV8AtoiWeQs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlGuid(new Guid("aad872f5-82bb-4989-af0f-bee5de636fd7")), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABxTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxHdWlkAQAAAAdtX3ZhbHVlBwICAAAACQMAAAAPAwAAABAAAAAC9XLYqruCiUmvD77l3mNv1ws=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABxTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxHdWlkAQAAAAdtX3ZhbHVlBwICAAAACQMAAAAPAwAAABAAAAAC9XLYqruCiUmvD77l3mNv1ws=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlGuid("aad872f5-82bb-4989-af0f-bee5de636fd7"), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABxTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxHdWlkAQAAAAdtX3ZhbHVlBwICAAAACQMAAAAPAwAAABAAAAAC9XLYqruCiUmvD77l3mNv1ws=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABxTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxHdWlkAQAAAAdtX3ZhbHVlBwICAAAACQMAAAAPAwAAABAAAAAC9XLYqruCiUmvD77l3mNv1ws=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlBoolean(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB9TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxCb29sZWFuAQAAAAdtX3ZhbHVlAAICAAAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB9TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxCb29sZWFuAQAAAAdtX3ZhbHVlAAICAAAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlBoolean(1), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB9TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxCb29sZWFuAQAAAAdtX3ZhbHVlAAICAAAAAgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB9TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxCb29sZWFuAQAAAAdtX3ZhbHVlAAICAAAAAgs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlBoolean(true), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB9TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxCb29sZWFuAQAAAAdtX3ZhbHVlAAICAAAAAgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB9TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxCb29sZWFuAQAAAAdtX3ZhbHVlAAICAAAAAgs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlByte(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABxTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxCeXRlAgAAAAptX2ZOb3ROdWxsB21fdmFsdWUAAAECAgAAAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABxTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxCeXRlAgAAAAptX2ZOb3ROdWxsB21fdmFsdWUAAAECAgAAAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlByte(255), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABxTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxCeXRlAgAAAAptX2ZOb3ROdWxsB21fdmFsdWUAAAECAgAAAAH/Cw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAABxTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxCeXRlAgAAAAptX2ZOb3ROdWxsB21fdmFsdWUAAAECAgAAAAH/Cw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlDateTime(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEYXRlVGltZQMAAAAKbV9mTm90TnVsbAVtX2RheQZtX3RpbWUAAAABCAgCAAAAAAAAAAAAAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEYXRlVGltZQMAAAAKbV9mTm90TnVsbAVtX2RheQZtX3RpbWUAAAABCAgCAAAAAAAAAAAAAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlDateTime(123, 546), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEYXRlVGltZQMAAAAKbV9mTm90TnVsbAVtX2RheQZtX3RpbWUAAAABCAgCAAAAAXsAAAAiAgAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEYXRlVGltZQMAAAAKbV9mTm90TnVsbAVtX2RheQZtX3RpbWUAAAABCAgCAAAAAXsAAAAiAgAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlDateTime(2017, 11, 3), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEYXRlVGltZQMAAAAKbV9mTm90TnVsbAVtX2RheQZtX3RpbWUAAAABCAgCAAAAASCoAAAAAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEYXRlVGltZQMAAAAKbV9mTm90TnVsbAVtX2RheQZtX3RpbWUAAAABCAgCAAAAASCoAAAAAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlDateTime(2017, 11, 3, 4, 50, 30), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEYXRlVGltZQMAAAAKbV9mTm90TnVsbAVtX2RheQZtX3RpbWUAAAABCAgCAAAAASCoAADIyU8ACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEYXRlVGltZQMAAAAKbV9mTm90TnVsbAVtX2RheQZtX3RpbWUAAAABCAgCAAAAASCoAADIyU8ACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlDateTime(2017, 11, 3, 4, 50, 30, 99.9), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEYXRlVGltZQMAAAAKbV9mTm90TnVsbAVtX2RheQZtX3RpbWUAAAABCAgCAAAAASCoAADmyU8ACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEYXRlVGltZQMAAAAKbV9mTm90TnVsbAVtX2RheQZtX3RpbWUAAAABCAgCAAAAASCoAADmyU8ACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlDateTime(new DateTime(1990, 11, 23, 03, 30, 00, 00, DateTimeKind.Utc)), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEYXRlVGltZQMAAAAKbV9mTm90TnVsbAVtX2RheQZtX3RpbWUAAAABCAgCAAAAAa6BAACgrTkACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACBTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEYXRlVGltZQMAAAAKbV9mTm90TnVsbAVtX2RheQZtX3RpbWUAAAABCAgCAAAAAa6BAACgrTkACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlDouble(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEb3VibGUCAAAACm1fZk5vdE51bGwHbV92YWx1ZQAAAQYCAAAAAAAAAAAAAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEb3VibGUCAAAACm1fZk5vdE51bGwHbV92YWx1ZQAAAQYCAAAAAAAAAAAAAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlDouble(34.5), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEb3VibGUCAAAACm1fZk5vdE51bGwHbV92YWx1ZQAAAQYCAAAAAQAAAAAAQEFACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxEb3VibGUCAAAACm1fZk5vdE51bGwHbV92YWx1ZQAAAQYCAAAAAQAAAAAAQEFACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlInt16(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxJbnQxNgIAAAAKbV9mTm90TnVsbAdtX3ZhbHVlAAABBwIAAAAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxJbnQxNgIAAAAKbV9mTm90TnVsbAdtX3ZhbHVlAAABBwIAAAAAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlInt16(256), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxJbnQxNgIAAAAKbV9mTm90TnVsbAdtX3ZhbHVlAAABBwIAAAABAAEL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxJbnQxNgIAAAAKbV9mTm90TnVsbAdtX3ZhbHVlAAABBwIAAAABAAEL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlInt32(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxJbnQzMgIAAAAKbV9mTm90TnVsbAdtX3ZhbHVlAAABCAIAAAAAAAAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxJbnQzMgIAAAAKbV9mTm90TnVsbAdtX3ZhbHVlAAABCAIAAAAAAAAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlInt32(4096314), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxJbnQzMgIAAAAKbV9mTm90TnVsbAdtX3ZhbHVlAAABCAIAAAABOoE+AAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxJbnQzMgIAAAAKbV9mTm90TnVsbAdtX3ZhbHVlAAABCAIAAAABOoE+AAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlInt64(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxJbnQ2NAIAAAAKbV9mTm90TnVsbAdtX3ZhbHVlAAABCQIAAAAAAAAAAAAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxJbnQ2NAIAAAAKbV9mTm90TnVsbAdtX3ZhbHVlAAABCQIAAAAAAAAAAAAAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlInt64(3492867384596), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxJbnQ2NAIAAAAKbV9mTm90TnVsbAdtX3ZhbHVlAAABCQIAAAABFKUePy0DAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB1TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxJbnQ2NAIAAAAKbV9mTm90TnVsbAdtX3ZhbHVlAAABCQIAAAABFKUePy0DAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlString(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAoKAAAAAAX9////JlN5c3RlbS5EYXRhLlNxbFR5cGVzLlNxbENvbXBhcmVPcHRpb25zAQAAAAd2YWx1ZV9fAAgCAAAAAAAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAoKAAAAAAX9////JlN5c3RlbS5EYXRhLlNxbFR5cGVzLlNxbENvbXBhcmVPcHRpb25zAQAAAAd2YWx1ZV9fAAgCAAAAAAAAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlString("abc", CultureInfo.InvariantCulture.LCID), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAYDAAAAA2FiYwp/AAAABfz///8mU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAIAAAAZAAAAAQs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAYDAAAAA2FiYwp/AAAABfz///8mU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAIAAAAZAAAAAQs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlString("abc", CultureInfo.InvariantCulture.LCID, SqlCompareOptions.BinarySort), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAYDAAAAA2FiYwp/AAAABfz///8mU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAIAAAAAgAAAAQs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAYDAAAAA2FiYwp/AAAABfz///8mU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAIAAAAAgAAAAQs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlString(CultureInfo.InvariantCulture.LCID, SqlCompareOptions.BinarySort, new byte[] { 65, 66, 67 }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAYDAAAABuSJge+/vQp/AAAABfz///8mU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAIAAAAAgAAAAQs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAYDAAAABuSJge+/vQp/AAAABfz///8mU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAIAAAAAgAAAAQs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlString(CultureInfo.InvariantCulture.LCID, SqlCompareOptions.BinarySort, new byte[] { 65, 66, 67 }, true), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAYDAAAABuSJge+/vQp/AAAABfz///8mU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAIAAAAAgAAAAQs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAYDAAAABuSJge+/vQp/AAAABfz///8mU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAIAAAAAgAAAAQs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlString(CultureInfo.InvariantCulture.LCID, SqlCompareOptions.BinarySort, new byte[] { 65, 66, 67 }, 0, 3), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAYDAAAABuSJge+/vQp/AAAABfz///8mU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAIAAAAAgAAAAQs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAYDAAAABuSJge+/vQp/AAAABfz///8mU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAIAAAAAgAAAAQs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SqlString(CultureInfo.InvariantCulture.LCID, SqlCompareOptions.BinarySort, new byte[] { 65, 66, 67 }, 0, 3, true), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAYDAAAABuSJge+/vQp/AAAABfz///8mU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAIAAAAAgAAAAQs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxTdHJpbmcFAAAAB21fdmFsdWUJbV9jbXBJbmZvBm1fbGNpZAZtX2ZsYWcKbV9mTm90TnVsbAEDAAQAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCCZTeXN0ZW0uRGF0YS5TcWxUeXBlcy5TcWxDb21wYXJlT3B0aW9ucwIAAAABAgAAAAYDAAAABuSJge+/vQp/AAAABfz///8mU3lzdGVtLkRhdGEuU3FsVHlwZXMuU3FsQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAIAAAAAgAAAAQs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { DBNull.Value, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uVW5pdHlTZXJpYWxpemF0aW9uSG9sZGVyAwAAAAREYXRhCVVuaXR5VHlwZQxBc3NlbWJseU5hbWUBAAEICgIAAAAGAgAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB9TeXN0ZW0uVW5pdHlTZXJpYWxpemF0aW9uSG9sZGVyAwAAAAREYXRhCVVuaXR5VHlwZQxBc3NlbWJseU5hbWUBAAEICgIAAAAGAgAAAAAL", TargetFrameworkMoniker.netfx461) } };
+
+ yield return new object[] { new BigInteger(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAEFTeXN0ZW0uTnVtZXJpY3MsIFZlcnNpb249NC4wLjAuMCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAGlN5c3RlbS5OdW1lcmljcy5CaWdJbnRlZ2VyAgAAAAVfc2lnbgVfYml0cwAHCA8CAAAAAAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFJTeXN0ZW0uTnVtZXJpY3MsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAaU3lzdGVtLk51bWVyaWNzLkJpZ0ludGVnZXICAAAABV9zaWduBV9iaXRzAAcIDwIAAAAAAAAACgs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new BigInteger(10324176), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAEFTeXN0ZW0uTnVtZXJpY3MsIFZlcnNpb249NC4wLjAuMCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAGlN5c3RlbS5OdW1lcmljcy5CaWdJbnRlZ2VyAgAAAAVfc2lnbgVfYml0cwAHCA8CAAAA0IidAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFJTeXN0ZW0uTnVtZXJpY3MsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAaU3lzdGVtLk51bWVyaWNzLkJpZ0ludGVnZXICAAAABV9zaWduBV9iaXRzAAcIDwIAAADQiJ0ACgs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new BigInteger(new byte[] { 1, 2, 3, 4, 5 }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAEFTeXN0ZW0uTnVtZXJpY3MsIFZlcnNpb249NC4wLjAuMCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQUBAAAAGlN5c3RlbS5OdW1lcmljcy5CaWdJbnRlZ2VyAgAAAAVfc2lnbgVfYml0cwAHCA8CAAAAAQAAAAkDAAAADwMAAAACAAAADwECAwQFAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFJTeXN0ZW0uTnVtZXJpY3MsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAaU3lzdGVtLk51bWVyaWNzLkJpZ0ludGVnZXICAAAABV9zaWduBV9iaXRzAAcIDwIAAAABAAAACQMAAAAPAwAAAAIAAAAPAQIDBAUAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Complex(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFJTeXN0ZW0uTnVtZXJpY3MsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAXU3lzdGVtLk51bWVyaWNzLkNvbXBsZXgCAAAABm1fcmVhbAttX2ltYWdpbmFyeQAABgYCAAAAAAAAAAAAAAAAAAAAAAAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFJTeXN0ZW0uTnVtZXJpY3MsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAXU3lzdGVtLk51bWVyaWNzLkNvbXBsZXgCAAAABm1fcmVhbAttX2ltYWdpbmFyeQAABgYCAAAAAAAAAAAAAAAAAAAAAAAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Complex(12, 6), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFJTeXN0ZW0uTnVtZXJpY3MsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAXU3lzdGVtLk51bWVyaWNzLkNvbXBsZXgCAAAABm1fcmVhbAttX2ltYWdpbmFyeQAABgYCAAAAAAAAAAAAKEAAAAAAAAAYQAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFJTeXN0ZW0uTnVtZXJpY3MsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAXU3lzdGVtLk51bWVyaWNzLkNvbXBsZXgCAAAABm1fcmVhbAttX2ltYWdpbmFyeQAABgYCAAAAAAAAAAAAKEAAAAAAAAAYQAs=", TargetFrameworkMoniker.netfx461) } };
// Arrays of primitive types
- yield return new object[] { Enumerable.Range(0, 256).Select(i => (byte)i).ToArray(), new string[] { "AAEAAAD/////AQAAAAAAAAAPAQAAAAABAAACAAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/ws=", "AAEAAAD/////AQAAAAAAAAAPAQAAAAABAAACAAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/ws=" } };
- yield return new object[] { new int[] { }, new string[] { "AAEAAAD/////AQAAAAAAAAAPAQAAAAAAAAAICw==", "AAEAAAD/////AQAAAAAAAAAPAQAAAAAAAAAICw==" } };
- yield return new object[] { new int[] { 1 }, new string[] { "AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAIAQAAAAs=", "AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAIAQAAAAs=" } };
- yield return new object[] { new int[] { 1, 2, 3, 4, 5 }, new string[] { "AAEAAAD/////AQAAAAAAAAAPAQAAAAUAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAL", "AAEAAAD/////AQAAAAAAAAAPAQAAAAUAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAL" } };
- yield return new object[] { new char[] { 'a', 'b', 'c', 'd', 'e' }, new string[] { "AAEAAAD/////AQAAAAAAAAAPAQAAAAUAAAADYWJjZGUL", "AAEAAAD/////AQAAAAAAAAAPAQAAAAUAAAADYWJjZGUL" } };
- yield return new object[] { new string[] { }, new string[] { "AAEAAAD/////AQAAAAAAAAARAQAAAAAAAAAL", "AAEAAAD/////AQAAAAAAAAARAQAAAAAAAAAL" } };
- yield return new object[] { new string[] { "hello", "world" }, new string[] { "AAEAAAD/////AQAAAAAAAAARAQAAAAIAAAAGAgAAAAVoZWxsbwYDAAAABXdvcmxkCw==", "AAEAAAD/////AQAAAAAAAAARAQAAAAIAAAAGAgAAAAVoZWxsbwYDAAAABXdvcmxkCw==" } };
- yield return new object[] { new short[] { short.MaxValue }, new string[] { "AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAH/38L", "AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAH/38L" } };
- yield return new object[] { new long[] { long.MaxValue }, new string[] { "AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAJ/////////38L", "AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAJ/////////38L" } };
- yield return new object[] { new ushort[] { ushort.MaxValue }, new string[] { "AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAO//8L", "AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAO//8L" } };
- yield return new object[] { new uint[] { uint.MaxValue }, new string[] { "AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAP/////ws=", "AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAP/////ws=" } };
- yield return new object[] { new ulong[] { ulong.MaxValue }, new string[] { "AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAQ//////////8L", "AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAQ//////////8L" } };
- yield return new object[] { new bool[] { true, false }, new string[] { "AAEAAAD/////AQAAAAAAAAAPAQAAAAIAAAABAQAL", "AAEAAAD/////AQAAAAAAAAAPAQAAAAIAAAABAQAL" } };
- yield return new object[] { new double[] { 1.2 }, new string[] { "AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAGMzMzMzMz8z8L", "AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAGMzMzMzMz8z8L" } };
- yield return new object[] { new float[] { 1.2f, 3.4f }, new string[] { "AAEAAAD/////AQAAAAAAAAAPAQAAAAIAAAALmpmZP5qZWUAL", "AAEAAAD/////AQAAAAAAAAAPAQAAAAIAAAALmpmZP5qZWUAL" } };
+ yield return new object[] { Enumerable.Range(0, 256).Select(i => (byte)i).ToArray(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAPAQAAAAABAAACAAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/ws=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAPAQAAAAABAAACAAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/ws=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new int[] { }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAPAQAAAAAAAAAICw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAPAQAAAAAAAAAICw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new int[] { 1 }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAIAQAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAIAQAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new int[] { 1, 2, 3, 4, 5 }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAPAQAAAAUAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAPAQAAAAUAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new char[] { 'a', 'b', 'c', 'd', 'e' }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAPAQAAAAUAAAADYWJjZGUL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAPAQAAAAUAAAADYWJjZGUL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new string[] { }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAARAQAAAAAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAARAQAAAAAAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new string[] { "hello", "world" }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAARAQAAAAIAAAAGAgAAAAVoZWxsbwYDAAAABXdvcmxkCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAARAQAAAAIAAAAGAgAAAAVoZWxsbwYDAAAABXdvcmxkCw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new short[] { short.MaxValue }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAH/38L", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAH/38L", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new long[] { long.MaxValue }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAJ/////////38L", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAJ/////////38L", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new ushort[] { ushort.MaxValue }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAO//8L", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAO//8L", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new uint[] { uint.MaxValue }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAP/////ws=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAP/////ws=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new ulong[] { ulong.MaxValue }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAQ//////////8L", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAQ//////////8L", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new bool[] { true, false }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAPAQAAAAIAAAABAQAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAPAQAAAAIAAAABAQAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new double[] { 1.2 }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAGMzMzMzMz8z8L", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAPAQAAAAEAAAAGMzMzMzMz8z8L", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new float[] { 1.2f, 3.4f }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAPAQAAAAIAAAALmpmZP5qZWUAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAPAQAAAAIAAAALmpmZP5qZWUAL", TargetFrameworkMoniker.netfx461) } };
// Arrays of other types
- yield return new object[] { new object[] { }, new string[] { "AAEAAAD/////AQAAAAAAAAAQAQAAAAAAAAAL", "AAEAAAD/////AQAAAAAAAAAQAQAAAAAAAAAL" } };
- yield return new object[] { new Guid[] { new Guid("0CACAA4D-C6BD-420A-B660-2F557337CA89"), new Guid("BE4E9FF4-82D9-4B54-85EA-0957E21DE0E2") }, new string[] { "AAEAAAD/////AQAAAAAAAAAHAQAAAAABAAAAAgAAAAMLU3lzdGVtLkd1aWQE/v///wtTeXN0ZW0uR3VpZAsAAAACX2ECX2ICX2MCX2QCX2UCX2YCX2cCX2gCX2kCX2oCX2sAAAAAAAAAAAAAAAgHBwICAgICAgICTaqsDL3GCkK2YC9VczfKiQH9/////v////SfTr7ZglRLheoJV+Id4OIL", "AAEAAAD/////AQAAAAAAAAAHAQAAAAABAAAAAgAAAAMLU3lzdGVtLkd1aWQE/v///wtTeXN0ZW0uR3VpZAsAAAACX2ECX2ICX2MCX2QCX2UCX2YCX2cCX2gCX2kCX2oCX2sAAAAAAAAAAAAAAAgHBwICAgICAgICTaqsDL3GCkK2YC9VczfKiQH9/////v////SfTr7ZglRLheoJV+Id4OIL" } };
- yield return new object[] { new DayOfWeek[] { DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday }, new string[] { "AAEAAAD/////AQAAAAAAAAAHAQAAAAABAAAABQAAAAMQU3lzdGVtLkRheU9mV2VlawT+////EFN5c3RlbS5EYXlPZldlZWsBAAAAB3ZhbHVlX18ACAEAAAAB/f////7///8CAAAAAfz////+////AwAAAAH7/////v///wQAAAAB+v////7///8FAAAACw==", "AAEAAAD/////AQAAAAAAAAAHAQAAAAABAAAABQAAAAMQU3lzdGVtLkRheU9mV2VlawT+////EFN5c3RlbS5EYXlPZldlZWsBAAAAB3ZhbHVlX18ACAEAAAAB/f////7///8CAAAAAfz////+////AwAAAAH7/////v///wQAAAAB+v////7///8FAAAACw==" } };
- yield return new object[] { new Point[] { new Point(1, 2), new Point(3, 4) }, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBwEAAAAAAQAAAAIAAAAEM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAIAAAAJAwAAAAkEAAAABQMAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIAgAAAAEAAAACAAAAAQQAAAADAAAAAwAAAAQAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBwEAAAAAAQAAAAIAAAAEM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAIAAAAJAwAAAAkEAAAABQMAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIAgAAAAEAAAACAAAAAQQAAAADAAAAAwAAAAQAAAAL" } };
+ yield return new object[] { new object[] { }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAQAQAAAAAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAQAQAAAAAAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Guid[] { new Guid("0CACAA4D-C6BD-420A-B660-2F557337CA89"), new Guid("BE4E9FF4-82D9-4B54-85EA-0957E21DE0E2") }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAHAQAAAAABAAAAAgAAAAMLU3lzdGVtLkd1aWQE/v///wtTeXN0ZW0uR3VpZAsAAAACX2ECX2ICX2MCX2QCX2UCX2YCX2cCX2gCX2kCX2oCX2sAAAAAAAAAAAAAAAgHBwICAgICAgICTaqsDL3GCkK2YC9VczfKiQH9/////v////SfTr7ZglRLheoJV+Id4OIL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAHAQAAAAABAAAAAgAAAAMLU3lzdGVtLkd1aWQE/v///wtTeXN0ZW0uR3VpZAsAAAACX2ECX2ICX2MCX2QCX2UCX2YCX2cCX2gCX2kCX2oCX2sAAAAAAAAAAAAAAAgHBwICAgICAgICTaqsDL3GCkK2YC9VczfKiQH9/////v////SfTr7ZglRLheoJV+Id4OIL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new DayOfWeek[] { DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAHAQAAAAABAAAABQAAAAMQU3lzdGVtLkRheU9mV2VlawT+////EFN5c3RlbS5EYXlPZldlZWsBAAAAB3ZhbHVlX18ACAEAAAAB/f////7///8CAAAAAfz////+////AwAAAAH7/////v///wQAAAAB+v////7///8FAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAHAQAAAAABAAAABQAAAAMQU3lzdGVtLkRheU9mV2VlawT+////EFN5c3RlbS5EYXlPZldlZWsBAAAAB3ZhbHVlX18ACAEAAAAB/f////7///8CAAAAAfz////+////AwAAAAH7/////v///wQAAAAB+v////7///8FAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Point[] { new Point(1, 2), new Point(3, 4) }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBwEAAAAAAQAAAAIAAAAEM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAIAAAAJAwAAAAkEAAAABQMAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIAgAAAAEAAAACAAAAAQQAAAADAAAAAwAAAAQAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBwEAAAAAAQAAAAIAAAAEM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAIAAAAJAwAAAAkEAAAABQMAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIAgAAAAEAAAACAAAAAQQAAAADAAAAAwAAAAQAAAAL", TargetFrameworkMoniker.netfx461) } };
var objectWithArrays = new ObjectWithArrays
{
@@ -1005,166 +997,175 @@ namespace System.Runtime.Serialization.Formatters.Tests
MultiDimensionalArray = new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 } },
TreeArray = new Tree<int>[] { new Tree<int>(1, new Tree<int>(2, null, null), new Tree<int>(3, null, null)) }
};
- yield return new object[] { objectWithArrays, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAAA+U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLk9iamVjdFdpdGhBcnJheXMGAAAACEludEFycmF5C1N0cmluZ0FycmF5CVRyZWVBcnJheQlCeXRlQXJyYXkLSmFnZ2VkQXJyYXkVTXVsdGlEaW1lbnNpb25hbEFycmF5BwYEBwMDCJMBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXVtdAgAAAAIQU3lzdGVtLkludDMyW11bXQ9TeXN0ZW0uSW50MzJbLF0CAAAACQMAAAAJBAAAAAkFAAAACQYAAAAJBwAAAAkIAAAADwMAAAAAAAAACBEEAAAAAgAAAAYJAAAABWhlbGxvBgoAAAAFd29ybGQHBQAAAAABAAAAAQAAAASRAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5UcmVlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACQsAAAAPBgAAABQAAAACAAECAwQFBgcICQoLDA0ODxAREhMHBwAAAAEBAAAAAgAAAAcICQwAAAAJDQAAAAcIAAAAAgIAAAADAAAAAgAAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABQsAAACRAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5UcmVlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAFjxWYWx1ZT5rX19CYWNraW5nRmllbGQVPExlZnQ+a19fQmFja2luZ0ZpZWxkFjxSaWdodD5rX19CYWNraW5nRmllbGQABAQIkQFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuVHJlZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAJEBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAACAAAAAQAAAAkOAAAACQ8AAAAPDAAAAAMAAAAIAQAAAAIAAAADAAAADw0AAAAEAAAACAQAAAAFAAAABgAAAAcAAAABDgAAAAsAAAACAAAACgoBDwAAAAsAAAADAAAACgoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAAA+U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLk9iamVjdFdpdGhBcnJheXMGAAAACEludEFycmF5C1N0cmluZ0FycmF5CVRyZWVBcnJheQlCeXRlQXJyYXkLSmFnZ2VkQXJyYXkVTXVsdGlEaW1lbnNpb25hbEFycmF5BwYEBwMDCJMBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXVtdAgAAAAIQU3lzdGVtLkludDMyW11bXQ9TeXN0ZW0uSW50MzJbLF0CAAAACQMAAAAJBAAAAAkFAAAACQYAAAAJBwAAAAkIAAAADwMAAAAAAAAACBEEAAAAAgAAAAYJAAAABWhlbGxvBgoAAAAFd29ybGQHBQAAAAABAAAAAQAAAASRAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5UcmVlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACQsAAAAPBgAAABQAAAACAAECAwQFBgcICQoLDA0ODxAREhMHBwAAAAEBAAAAAgAAAAcICQwAAAAJDQAAAAcIAAAAAgIAAAADAAAAAgAAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABQsAAACRAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5UcmVlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAFjxWYWx1ZT5rX19CYWNraW5nRmllbGQVPExlZnQ+a19fQmFja2luZ0ZpZWxkFjxSaWdodD5rX19CYWNraW5nRmllbGQABAQIkQFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuVHJlZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAJEBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAACAAAAAQAAAAkOAAAACQ8AAAAPDAAAAAMAAAAIAQAAAAIAAAADAAAADw0AAAAEAAAACAQAAAAFAAAABgAAAAcAAAABDgAAAAsAAAACAAAACgoBDwAAAAsAAAADAAAACgoL" } };
+ yield return new object[] { objectWithArrays, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAAA+U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLk9iamVjdFdpdGhBcnJheXMGAAAACEludEFycmF5C1N0cmluZ0FycmF5CVRyZWVBcnJheQlCeXRlQXJyYXkLSmFnZ2VkQXJyYXkVTXVsdGlEaW1lbnNpb25hbEFycmF5BwYEBwMDCJMBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXVtdAgAAAAIQU3lzdGVtLkludDMyW11bXQ9TeXN0ZW0uSW50MzJbLF0CAAAACQMAAAAJBAAAAAkFAAAACQYAAAAJBwAAAAkIAAAADwMAAAAAAAAACBEEAAAAAgAAAAYJAAAABWhlbGxvBgoAAAAFd29ybGQHBQAAAAABAAAAAQAAAASRAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5UcmVlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACQsAAAAPBgAAABQAAAACAAECAwQFBgcICQoLDA0ODxAREhMHBwAAAAEBAAAAAgAAAAcICQwAAAAJDQAAAAcIAAAAAgIAAAADAAAAAgAAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABQsAAACRAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5UcmVlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAFjxWYWx1ZT5rX19CYWNraW5nRmllbGQVPExlZnQ+a19fQmFja2luZ0ZpZWxkFjxSaWdodD5rX19CYWNraW5nRmllbGQABAQIkQFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuVHJlZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAJEBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAACAAAAAQAAAAkOAAAACQ8AAAAPDAAAAAMAAAAIAQAAAAIAAAADAAAADw0AAAAEAAAACAQAAAAFAAAABgAAAAcAAAABDgAAAAsAAAACAAAACgoBDwAAAAsAAAADAAAACgoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAAA+U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLk9iamVjdFdpdGhBcnJheXMGAAAACEludEFycmF5C1N0cmluZ0FycmF5CVRyZWVBcnJheQlCeXRlQXJyYXkLSmFnZ2VkQXJyYXkVTXVsdGlEaW1lbnNpb25hbEFycmF5BwYEBwMDCJMBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXVtdAgAAAAIQU3lzdGVtLkludDMyW11bXQ9TeXN0ZW0uSW50MzJbLF0CAAAACQMAAAAJBAAAAAkFAAAACQYAAAAJBwAAAAkIAAAADwMAAAAAAAAACBEEAAAAAgAAAAYJAAAABWhlbGxvBgoAAAAFd29ybGQHBQAAAAABAAAAAQAAAASRAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5UcmVlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACQsAAAAPBgAAABQAAAACAAECAwQFBgcICQoLDA0ODxAREhMHBwAAAAEBAAAAAgAAAAcICQwAAAAJDQAAAAcIAAAAAgIAAAADAAAAAgAAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABQsAAACRAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5UcmVlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAFjxWYWx1ZT5rX19CYWNraW5nRmllbGQVPExlZnQ+a19fQmFja2luZ0ZpZWxkFjxSaWdodD5rX19CYWNraW5nRmllbGQABAQIkQFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuVHJlZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAJEBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAACAAAAAQAAAAkOAAAACQ8AAAAPDAAAAAMAAAAIAQAAAAIAAAADAAAADw0AAAAEAAAACAQAAAAFAAAABgAAAAcAAAABDgAAAAsAAAACAAAACgoBDwAAAAsAAAADAAAACgoL", TargetFrameworkMoniker.netfx461) } };
- yield return new object[] { new List<int>(), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkCAAAAAAAAAAAAAAAPAgAAAAAAAAAICw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkCAAAAAAAAAAAAAAAPAgAAAAAAAAAICw==" } };
+ yield return new object[] { new List<int>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkCAAAAAAAAAAAAAAAPAgAAAAAAAAAICw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkCAAAAAAAAAAAAAAAPAgAAAAAAAAAICw==", TargetFrameworkMoniker.netfx461) } };
// Passing an array to the IEnumerable cosntructor to hit its ICollection optimization, which causes all runtimes to
// produce the same internal state. Otherwise, they come up with different _version values
- yield return new object[] { new List<int>(Enumerable.Range(0, 123).ToArray()), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkCAAAAewAAAAAAAAAPAgAAAHsAAAAIAAAAAAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAGwAAABwAAAAdAAAAHgAAAB8AAAAgAAAAIQAAACIAAAAjAAAAJAAAACUAAAAmAAAAJwAAACgAAAApAAAAKgAAACsAAAAsAAAALQAAAC4AAAAvAAAAMAAAADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAAADoAAAA7AAAAPAAAAD0AAAA+AAAAPwAAAEAAAABBAAAAQgAAAEMAAABEAAAARQAAAEYAAABHAAAASAAAAEkAAABKAAAASwAAAEwAAABNAAAATgAAAE8AAABQAAAAUQAAAFIAAABTAAAAVAAAAFUAAABWAAAAVwAAAFgAAABZAAAAWgAAAFsAAABcAAAAXQAAAF4AAABfAAAAYAAAAGEAAABiAAAAYwAAAGQAAABlAAAAZgAAAGcAAABoAAAAaQAAAGoAAABrAAAAbAAAAG0AAABuAAAAbwAAAHAAAABxAAAAcgAAAHMAAAB0AAAAdQAAAHYAAAB3AAAAeAAAAHkAAAB6AAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkCAAAAewAAAAAAAAAPAgAAAHsAAAAIAAAAAAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAGwAAABwAAAAdAAAAHgAAAB8AAAAgAAAAIQAAACIAAAAjAAAAJAAAACUAAAAmAAAAJwAAACgAAAApAAAAKgAAACsAAAAsAAAALQAAAC4AAAAvAAAAMAAAADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAAADoAAAA7AAAAPAAAAD0AAAA+AAAAPwAAAEAAAABBAAAAQgAAAEMAAABEAAAARQAAAEYAAABHAAAASAAAAEkAAABKAAAASwAAAEwAAABNAAAATgAAAE8AAABQAAAAUQAAAFIAAABTAAAAVAAAAFUAAABWAAAAVwAAAFgAAABZAAAAWgAAAFsAAABcAAAAXQAAAF4AAABfAAAAYAAAAGEAAABiAAAAYwAAAGQAAABlAAAAZgAAAGcAAABoAAAAaQAAAGoAAABrAAAAbAAAAG0AAABuAAAAbwAAAHAAAABxAAAAcgAAAHMAAAB0AAAAdQAAAHYAAAB3AAAAeAAAAHkAAAB6AAAACw==" } };
- yield return new object[] { new List<int>(new int[] { 5, 7, 9 }), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkCAAAAAwAAAAAAAAAPAgAAAAMAAAAIBQAAAAcAAAAJAAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkCAAAAAwAAAAAAAAAPAgAAAAMAAAAIBQAAAAcAAAAJAAAACw==" } };
- yield return new object[] { new List<Point>(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAEAAADKAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgQAADVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQIAAAAICAkDAAAAAAAAAAAAAAAHAwAAAAABAAAAAAAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAEAAADKAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgQAADVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQIAAAAICAkDAAAAAAAAAAAAAAAHAwAAAAABAAAAAAAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAs=" } };
- yield return new object[] { new List<Point>(new Point[] { new Point(1, 2), new Point(4, 3) }), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAEAAADKAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgQAADVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQIAAAAICAkDAAAAAgAAAAAAAAAHAwAAAAABAAAAAgAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAkEAAAACQUAAAAFBAAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgCAAAAAQAAAAIAAAABBQAAAAQAAAAEAAAAAwAAAAs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAEAAADKAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgQAADVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQIAAAAICAkDAAAAAgAAAAAAAAAHAwAAAAABAAAAAgAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAkEAAAACQUAAAAFBAAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgCAAAAAQAAAAIAAAABBQAAAAQAAAAEAAAAAwAAAAs=" } };
- yield return new object[] { new List<Tuple<int, Graph<int>>>(), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAOQDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uAwAA9AJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dW10ICAkCAAAAAAAAAAAAAAAHAgAAAAABAAAAAAAAAAPyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0L", "AAEAAAD/////AQAAAAAAAAAEAQAAAOQDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uAwAA9AJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dW10ICAkCAAAAAAAAAAAAAAAHAgAAAAABAAAAAAAAAAPyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0L" } };
- yield return new object[] { new List<Tuple<int, Graph<int>>>(new Tuple<int, Graph<int>>[] { Tuple.Create(1, new Graph<int>()), Tuple.Create(5, new Graph<int>()) }), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAOQDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uAwAA9AJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dW10ICAkCAAAAAgAAAAAAAAAHAgAAAAABAAAAAgAAAAPyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0JAwAAAAkEAAAADAUAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgQDAAAA8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAdtX0l0ZW0xB21fSXRlbTIABAiSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBQAAAAEAAAAJBgAAAAEEAAAAAwAAAAUAAAAJBwAAAAUGAAAAkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAFVmFsdWUFTGlua3MABAiUAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dW10FAAAABQAAAAAAAAAKAQcAAAAGAAAAAAAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAAOQDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uAwAA9AJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dW10ICAkCAAAAAgAAAAAAAAAHAgAAAAABAAAAAgAAAAPyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0JAwAAAAkEAAAADAUAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgQDAAAA8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAdtX0l0ZW0xB21fSXRlbTIABAiSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBQAAAAEAAAAJBgAAAAEEAAAAAwAAAAUAAAAJBwAAAAUGAAAAkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAFVmFsdWUFTGlua3MABAiUAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dW10FAAAABQAAAAAAAAAKAQcAAAAGAAAAAAAAAAoL" } };
-
- yield return new object[] { new Dictionary<int, int>(), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAOABU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAB1ZlcnNpb24IQ29tcGFyZXIISGFzaFNpemUAAwAIkQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljRXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAAJAgAAAAAAAAAEAgAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAAOABU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAB1ZlcnNpb24IQ29tcGFyZXIISGFzaFNpemUAAwAIkQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljRXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAAJAgAAAAAAAAAEAgAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL" } };
- yield return new object[] { new Dictionary<int, int>(4), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAOABU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0EAAAAB1ZlcnNpb24IQ29tcGFyZXIISGFzaFNpemUNS2V5VmFsdWVQYWlycwADAAMIkQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljRXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCOQBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXVtdAAAAAAkCAAAABwAAAAkDAAAABAIAAACRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAABwMAAAAAAQAAAAAAAAAD4gFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAOABU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0EAAAAB1ZlcnNpb24IQ29tcGFyZXIISGFzaFNpemUNS2V5VmFsdWVQYWlycwADAAMIkQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljRXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCOQBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXVtdAAAAAAkCAAAABwAAAAkDAAAABAIAAACRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAABwMAAAAAAQAAAAAAAAAD4gFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCw==" } };
- yield return new object[] { new Dictionary<int, Point>(), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAKwCU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAwAAAAdWZXJzaW9uCENvbXBhcmVyCEhhc2hTaXplAAMACJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgAAAAACQIAAAAAAAAABAIAAACRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAKwCU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAwAAAAdWZXJzaW9uCENvbXBhcmVyCEhhc2hTaXplAAMACJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgAAAAACQIAAAAAAAAABAIAAACRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==" } };
- yield return new object[] { new Dictionary<int, Tuple<int, Graph<int>>>(), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAMYEU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAdWZXJzaW9uCENvbXBhcmVyCEhhc2hTaXplAAMACJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgAAAAACQIAAAAAAAAABAIAAACRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAMYEU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAdWZXJzaW9uCENvbXBhcmVyCEhhc2hTaXplAAMACJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgAAAAACQIAAAAAAAAABAIAAACRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==" } };
- yield return new object[] { new Dictionary<Tuple<int, Point>, Graph<int>>(), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAJIFU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAHVmVyc2lvbghDb21wYXJlcghIYXNoU2l6ZQADAAiXA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLk9iamVjdEVxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAAJAgAAAAAAAAAEAgAAAJcDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAJIFU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAHVmVyc2lvbghDb21wYXJlcghIYXNoU2l6ZQADAAiXA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLk9iamVjdEVxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAAJAgAAAAAAAAAEAgAAAJcDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==" } };
- yield return new object[] { new Dictionary<string, string>() { { "a", "1" }, { "b", "2" } }, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAOIBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAHVmVyc2lvbghDb21wYXJlcghIYXNoU2l6ZQ1LZXlWYWx1ZVBhaXJzAAMAAwiSAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCOYBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dW10CAAAACQIAAAADAAAACQMAAAAEAgAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAABwMAAAAAAQAAAAIAAAAD5AFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0E/P///+QBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAANrZXkFdmFsdWUBAQYFAAAAAWEGBgAAAAExAfn////8////BggAAAABYgYJAAAAATIL", "AAEAAAD/////AQAAAAAAAAAEAQAAAOIBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAHVmVyc2lvbghDb21wYXJlcghIYXNoU2l6ZQ1LZXlWYWx1ZVBhaXJzAAMAAwiSAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCOYBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dW10CAAAACQIAAAADAAAACQMAAAAEAgAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAABwMAAAAAAQAAAAIAAAAD5AFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0E/P///+QBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAANrZXkFdmFsdWUBAQYFAAAAAWEGBgAAAAExAfn////8////BggAAAABYgYJAAAAATIL" } };
-
- yield return new object[] { new CookieCollection(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAbU3lzdGVtLk5ldC5Db29raWVDb2xsZWN0aW9uBAAAAAZtX2xpc3QJbV92ZXJzaW9uC21fVGltZVN0YW1wFG1faGFzX290aGVyX3ZlcnNpb25zAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0CA0BAgAAAAkDAAAAAAAAAAAAAAAAAAAAAAQDAAAAHFN5c3RlbS5Db2xsZWN0aW9ucy5BcnJheUxpc3QDAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgUAAAgICQQAAAAAAAAAAAAAABAEAAAAAAAAAAs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAbU3lzdGVtLk5ldC5Db29raWVDb2xsZWN0aW9uBQAAAAltX3ZlcnNpb24GbV9saXN0C21fVGltZVN0YW1wFG1faGFzX290aGVyX3ZlcnNpb25zDG1fSXNSZWFkT25seQADAAAACBxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0DQEBAgAAAAAAAAAJAwAAAAAAAAAAAAAAAAEEAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkEAAAAAAAAAAAAAAAQBAAAAAAAAAAL" } };
- yield return new object[] { new System.Data.PropertyCollection(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5Qcm9wZXJ0eUNvbGxlY3Rpb24HAAAACkxvYWRGYWN0b3IHVmVyc2lvbghDb21wYXJlchBIYXNoQ29kZVByb3ZpZGVyCEhhc2hTaXplBEtleXMGVmFsdWVzAAADAwAFBQsIHFN5c3RlbS5Db2xsZWN0aW9ucy5JQ29tcGFyZXIkU3lzdGVtLkNvbGxlY3Rpb25zLklIYXNoQ29kZVByb3ZpZGVyCAIAAADsUTg/AAAAAAoKAwAAAAkDAAAACQQAAAAQAwAAAAAAAAAQBAAAAAAAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5Qcm9wZXJ0eUNvbGxlY3Rpb24HAAAACkxvYWRGYWN0b3IHVmVyc2lvbghDb21wYXJlchBIYXNoQ29kZVByb3ZpZGVyCEhhc2hTaXplBEtleXMGVmFsdWVzAAADAwAFBQsIHFN5c3RlbS5Db2xsZWN0aW9ucy5JQ29tcGFyZXIkU3lzdGVtLkNvbGxlY3Rpb25zLklIYXNoQ29kZVByb3ZpZGVyCAIAAADsUTg/AAAAAAoKAwAAAAkDAAAACQQAAAAQAwAAAAAAAAAQBAAAAAAAAAAL" } };
-
- yield return new object[] { new ArrayList(), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAAAAAAAAAAAAQAgAAAAAAAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAAAAAAAAAAAAQAgAAAAAAAAAL" } };
- yield return new object[] { new ArrayList(7), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAAAAAAAAAAAAQAgAAAAcAAAANBws=", "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAAAAAAAAAAAAQAgAAAAcAAAANBws=" } };
- yield return new object[] { new ArrayList(Enumerable.Range(0, 123).ToArray()), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAewAAAAEAAAAQAgAAAHsAAAAICAAAAAAICAEAAAAICAIAAAAICAMAAAAICAQAAAAICAUAAAAICAYAAAAICAcAAAAICAgAAAAICAkAAAAICAoAAAAICAsAAAAICAwAAAAICA0AAAAICA4AAAAICA8AAAAICBAAAAAICBEAAAAICBIAAAAICBMAAAAICBQAAAAICBUAAAAICBYAAAAICBcAAAAICBgAAAAICBkAAAAICBoAAAAICBsAAAAICBwAAAAICB0AAAAICB4AAAAICB8AAAAICCAAAAAICCEAAAAICCIAAAAICCMAAAAICCQAAAAICCUAAAAICCYAAAAICCcAAAAICCgAAAAICCkAAAAICCoAAAAICCsAAAAICCwAAAAICC0AAAAICC4AAAAICC8AAAAICDAAAAAICDEAAAAICDIAAAAICDMAAAAICDQAAAAICDUAAAAICDYAAAAICDcAAAAICDgAAAAICDkAAAAICDoAAAAICDsAAAAICDwAAAAICD0AAAAICD4AAAAICD8AAAAICEAAAAAICEEAAAAICEIAAAAICEMAAAAICEQAAAAICEUAAAAICEYAAAAICEcAAAAICEgAAAAICEkAAAAICEoAAAAICEsAAAAICEwAAAAICE0AAAAICE4AAAAICE8AAAAICFAAAAAICFEAAAAICFIAAAAICFMAAAAICFQAAAAICFUAAAAICFYAAAAICFcAAAAICFgAAAAICFkAAAAICFoAAAAICFsAAAAICFwAAAAICF0AAAAICF4AAAAICF8AAAAICGAAAAAICGEAAAAICGIAAAAICGMAAAAICGQAAAAICGUAAAAICGYAAAAICGcAAAAICGgAAAAICGkAAAAICGoAAAAICGsAAAAICGwAAAAICG0AAAAICG4AAAAICG8AAAAICHAAAAAICHEAAAAICHIAAAAICHMAAAAICHQAAAAICHUAAAAICHYAAAAICHcAAAAICHgAAAAICHkAAAAICHoAAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAewAAAAEAAAAQAgAAAHsAAAAICAAAAAAICAEAAAAICAIAAAAICAMAAAAICAQAAAAICAUAAAAICAYAAAAICAcAAAAICAgAAAAICAkAAAAICAoAAAAICAsAAAAICAwAAAAICA0AAAAICA4AAAAICA8AAAAICBAAAAAICBEAAAAICBIAAAAICBMAAAAICBQAAAAICBUAAAAICBYAAAAICBcAAAAICBgAAAAICBkAAAAICBoAAAAICBsAAAAICBwAAAAICB0AAAAICB4AAAAICB8AAAAICCAAAAAICCEAAAAICCIAAAAICCMAAAAICCQAAAAICCUAAAAICCYAAAAICCcAAAAICCgAAAAICCkAAAAICCoAAAAICCsAAAAICCwAAAAICC0AAAAICC4AAAAICC8AAAAICDAAAAAICDEAAAAICDIAAAAICDMAAAAICDQAAAAICDUAAAAICDYAAAAICDcAAAAICDgAAAAICDkAAAAICDoAAAAICDsAAAAICDwAAAAICD0AAAAICD4AAAAICD8AAAAICEAAAAAICEEAAAAICEIAAAAICEMAAAAICEQAAAAICEUAAAAICEYAAAAICEcAAAAICEgAAAAICEkAAAAICEoAAAAICEsAAAAICEwAAAAICE0AAAAICE4AAAAICE8AAAAICFAAAAAICFEAAAAICFIAAAAICFMAAAAICFQAAAAICFUAAAAICFYAAAAICFcAAAAICFgAAAAICFkAAAAICFoAAAAICFsAAAAICFwAAAAICF0AAAAICF4AAAAICF8AAAAICGAAAAAICGEAAAAICGIAAAAICGMAAAAICGQAAAAICGUAAAAICGYAAAAICGcAAAAICGgAAAAICGkAAAAICGoAAAAICGsAAAAICGwAAAAICG0AAAAICG4AAAAICG8AAAAICHAAAAAICHEAAAAICHIAAAAICHMAAAAICHQAAAAICHUAAAAICHYAAAAICHcAAAAICHgAAAAICHkAAAAICHoAAAAL" } };
- yield return new object[] { new ArrayList(new int[] { 5, 7, 9 }), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAAwAAAAEAAAAQAgAAAAMAAAAICAUAAAAICAcAAAAICAkAAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAAwAAAAEAAAAQAgAAAAMAAAAICAUAAAAICAcAAAAICAkAAAAL" } };
- yield return new object[] { new ArrayList(new Point[] { new Point(1, 2), new Point(4, 3) }), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAAgAAAAEAAAAQAgAAAAIAAAAJAwAAAAkEAAAADAUAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUDAAAAM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAIAAAABWAFZAAAICAUAAAABAAAAAgAAAAEEAAAAAwAAAAQAAAADAAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAAgAAAAEAAAAQAgAAAAIAAAAJAwAAAAkEAAAADAUAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUDAAAAM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAIAAAABWAFZAAAICAUAAAABAAAAAgAAAAEEAAAAAwAAAAQAAAADAAAACw==" } };
- yield return new object[] { new ArrayList(new Tuple<int, Graph<int>>[] { Tuple.Create(1, new Graph<int>()), Tuple.Create(5, new Graph<int>()) }), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAAgAAAAEAAAAQAgAAAAIAAAAJAwAAAAkEAAAADAUAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgQDAAAA8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAdtX0l0ZW0xB21fSXRlbTIABAiSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBQAAAAEAAAAJBgAAAAEEAAAAAwAAAAUAAAAJBwAAAAUGAAAAkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAFVmFsdWUFTGlua3MABAiUAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dW10FAAAABQAAAAAAAAAKAQcAAAAGAAAAAAAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAAgAAAAEAAAAQAgAAAAIAAAAJAwAAAAkEAAAADAUAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgQDAAAA8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAdtX0l0ZW0xB21fSXRlbTIABAiSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBQAAAAEAAAAJBgAAAAEEAAAAAwAAAAUAAAAJBwAAAAUGAAAAkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAFVmFsdWUFTGlua3MABAiUAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dW10FAAAABQAAAAAAAAAKAQcAAAAGAAAAAAAAAAoL" } };
-
- yield return new object[] { new HashSet<int>(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAIEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuSGFzaFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAdWZXJzaW9uCENvbXBhcmVyCENhcGFjaXR5AAMACJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgCAAAAAAAAAAkDAAAAAAAAAAQDAAAAkQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljRXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAIEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuSGFzaFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAdWZXJzaW9uCENvbXBhcmVyCENhcGFjaXR5AAMACJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgCAAAAAAAAAAkDAAAAAAAAAAQDAAAAkQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljRXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAs=" } };
- yield return new object[] { new HashSet<int>(Enumerable.Range(0, 123)), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAIEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuSGFzaFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAdWZXJzaW9uCENvbXBhcmVyCENhcGFjaXR5CEVsZW1lbnRzAAMABwiRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0ICAIAAAB7AAAACQMAAADFAAAACQQAAAAEAwAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAPBAAAAHsAAAAIAAAAAAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAGwAAABwAAAAdAAAAHgAAAB8AAAAgAAAAIQAAACIAAAAjAAAAJAAAACUAAAAmAAAAJwAAACgAAAApAAAAKgAAACsAAAAsAAAALQAAAC4AAAAvAAAAMAAAADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAAADoAAAA7AAAAPAAAAD0AAAA+AAAAPwAAAEAAAABBAAAAQgAAAEMAAABEAAAARQAAAEYAAABHAAAASAAAAEkAAABKAAAASwAAAEwAAABNAAAATgAAAE8AAABQAAAAUQAAAFIAAABTAAAAVAAAAFUAAABWAAAAVwAAAFgAAABZAAAAWgAAAFsAAABcAAAAXQAAAF4AAABfAAAAYAAAAGEAAABiAAAAYwAAAGQAAABlAAAAZgAAAGcAAABoAAAAaQAAAGoAAABrAAAAbAAAAG0AAABuAAAAbwAAAHAAAABxAAAAcgAAAHMAAAB0AAAAdQAAAHYAAAB3AAAAeAAAAHkAAAB6AAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAIEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuSGFzaFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAdWZXJzaW9uCENvbXBhcmVyCENhcGFjaXR5CEVsZW1lbnRzAAMABwiRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0ICAIAAAB7AAAACQMAAADFAAAACQQAAAAEAwAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAPBAAAAHsAAAAIAAAAAAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAGwAAABwAAAAdAAAAHgAAAB8AAAAgAAAAIQAAACIAAAAjAAAAJAAAACUAAAAmAAAAJwAAACgAAAApAAAAKgAAACsAAAAsAAAALQAAAC4AAAAvAAAAMAAAADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAAADoAAAA7AAAAPAAAAD0AAAA+AAAAPwAAAEAAAABBAAAAQgAAAEMAAABEAAAARQAAAEYAAABHAAAASAAAAEkAAABKAAAASwAAAEwAAABNAAAATgAAAE8AAABQAAAAUQAAAFIAAABTAAAAVAAAAFUAAABWAAAAVwAAAFgAAABZAAAAWgAAAFsAAABcAAAAXQAAAF4AAABfAAAAYAAAAGEAAABiAAAAYwAAAGQAAABlAAAAZgAAAGcAAABoAAAAaQAAAGoAAABrAAAAbAAAAG0AAABuAAAAbwAAAHAAAABxAAAAcgAAAHMAAAB0AAAAdQAAAHYAAAB3AAAAeAAAAHkAAAB6AAAACw==" } };
- yield return new object[] { new HashSet<int>(new int[] { 5, 7, 9 }), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAIEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuSGFzaFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAdWZXJzaW9uCENvbXBhcmVyCENhcGFjaXR5CEVsZW1lbnRzAAMABwiRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0ICAIAAAADAAAACQMAAAADAAAACQQAAAAEAwAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAPBAAAAAMAAAAIBQAAAAcAAAAJAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAIEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuSGFzaFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAdWZXJzaW9uCENvbXBhcmVyCENhcGFjaXR5CEVsZW1lbnRzAAMABwiRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0ICAIAAAADAAAACQMAAAADAAAACQQAAAAEAwAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAPBAAAAAMAAAAIBQAAAAcAAAAJAAAACw==" } };
- yield return new object[] { new HashSet<Point>(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAM0BU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuSGFzaFNldGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAHVmVyc2lvbghDb21wYXJlcghDYXBhY2l0eQADAAjdAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCAIAAAAAAAAACQMAAAAAAAAABAMAAADdAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAAAAAAs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAM0BU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuSGFzaFNldGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAHVmVyc2lvbghDb21wYXJlcghDYXBhY2l0eQADAAjdAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCAIAAAAAAAAACQMAAAAAAAAABAMAAADdAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAAAAAAs=" } };
- yield return new object[] { new HashSet<Point>(new Point[] { new Point(1, 2), new Point(4, 3) }), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkMAwAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAADNAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkhhc2hTZXRgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0EAAAAB1ZlcnNpb24IQ29tcGFyZXIIQ2FwYWNpdHkIRWxlbWVudHMAAwAECN0BU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0INVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludFtdAwAAAAIAAAACAAAACQQAAAADAAAACQUAAAAEBAAAAN0BU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0AAAAABwUAAAAAAQAAAAIAAAAEM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAMAAAAJBgAAAAkHAAAABQYAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIAwAAAAEAAAACAAAAAQcAAAAGAAAABAAAAAMAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkMAwAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAADNAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkhhc2hTZXRgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0EAAAAB1ZlcnNpb24IQ29tcGFyZXIIQ2FwYWNpdHkIRWxlbWVudHMAAwAECN0BU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0INVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludFtdAwAAAAIAAAACAAAACQQAAAADAAAACQUAAAAEBAAAAN0BU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0AAAAABwUAAAAAAQAAAAIAAAAEM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAMAAAAJBgAAAAkHAAAABQYAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIAwAAAAEAAAACAAAAAQcAAAAGAAAABAAAAAMAAAAL" } };
- yield return new object[] { new HashSet<Tuple<int, Graph<int>>>(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAOcDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuSGFzaFNldGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAHVmVyc2lvbghDb21wYXJlcghDYXBhY2l0eQADAAj2A1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLk9iamVjdEVxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IAgAAAAAAAAAJAwAAAAAAAAAEAwAAAPYDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAOcDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuSGFzaFNldGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAHVmVyc2lvbghDb21wYXJlcghDYXBhY2l0eQADAAj2A1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLk9iamVjdEVxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IAgAAAAAAAAAJAwAAAAAAAAAEAwAAAPYDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL" } };
- yield return new object[] { new HashSet<Tuple<int, Graph<int>>>(new Tuple<int, Graph<int>>[] { Tuple.Create(1, new Graph<int>()), Tuple.Create(5, new Graph<int>()) }), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAOcDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuSGFzaFNldGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAHVmVyc2lvbghDb21wYXJlcghDYXBhY2l0eQhFbGVtZW50cwADAAMI9gNTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5PYmplY3RFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCPQCU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdAgAAAAIAAAAJAwAAAAMAAAAJBAAAAAQDAAAA9gNTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5PYmplY3RFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAcEAAAAAAEAAAACAAAAA/ICU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQkFAAAACQYAAAAMBwAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAUAAADyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAB21fSXRlbTEHbV9JdGVtMgAECJIBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0HAAAAAQAAAAkIAAAAAQYAAAAFAAAABQAAAAkJAAAABQgAAACSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAVWYWx1ZQVMaW5rcwAECJQBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV1bXQcAAAAHAAAAAAAAAAoBCQAAAAgAAAAAAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAOcDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuSGFzaFNldGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAHVmVyc2lvbghDb21wYXJlcghDYXBhY2l0eQhFbGVtZW50cwADAAMI9gNTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5PYmplY3RFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCPQCU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdAgAAAAIAAAAJAwAAAAMAAAAJBAAAAAQDAAAA9gNTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5PYmplY3RFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAcEAAAAAAEAAAACAAAAA/ICU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQkFAAAACQYAAAAMBwAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAUAAADyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAB21fSXRlbTEHbV9JdGVtMgAECJIBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0HAAAAAQAAAAkIAAAAAQYAAAAFAAAABQAAAAkJAAAABQgAAACSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAVWYWx1ZQVMaW5rcwAECJQBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV1bXQcAAAAHAAAAAAAAAAoBCQAAAAgAAAAAAAAACgs=" } };
-
- yield return new object[] { new LinkedList<int>(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACEAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpbmtlZExpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAHVmVyc2lvbgVDb3VudAAACAgCAAAAAAAAAAAAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACEAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpbmtlZExpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAHVmVyc2lvbgVDb3VudAAACAgCAAAAAAAAAAAAAAAL" } };
- yield return new object[] { new LinkedList<int>(Enumerable.Range(0, 123)), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACEAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpbmtlZExpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAHVmVyc2lvbgVDb3VudAREYXRhAAAHCAgIAgAAAHsAAAB7AAAACQMAAAAPAwAAAHsAAAAIAAAAAAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAGwAAABwAAAAdAAAAHgAAAB8AAAAgAAAAIQAAACIAAAAjAAAAJAAAACUAAAAmAAAAJwAAACgAAAApAAAAKgAAACsAAAAsAAAALQAAAC4AAAAvAAAAMAAAADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAAADoAAAA7AAAAPAAAAD0AAAA+AAAAPwAAAEAAAABBAAAAQgAAAEMAAABEAAAARQAAAEYAAABHAAAASAAAAEkAAABKAAAASwAAAEwAAABNAAAATgAAAE8AAABQAAAAUQAAAFIAAABTAAAAVAAAAFUAAABWAAAAVwAAAFgAAABZAAAAWgAAAFsAAABcAAAAXQAAAF4AAABfAAAAYAAAAGEAAABiAAAAYwAAAGQAAABlAAAAZgAAAGcAAABoAAAAaQAAAGoAAABrAAAAbAAAAG0AAABuAAAAbwAAAHAAAABxAAAAcgAAAHMAAAB0AAAAdQAAAHYAAAB3AAAAeAAAAHkAAAB6AAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACEAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpbmtlZExpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAHVmVyc2lvbgVDb3VudAREYXRhAAAHCAgIAgAAAHsAAAB7AAAACQMAAAAPAwAAAHsAAAAIAAAAAAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAGwAAABwAAAAdAAAAHgAAAB8AAAAgAAAAIQAAACIAAAAjAAAAJAAAACUAAAAmAAAAJwAAACgAAAApAAAAKgAAACsAAAAsAAAALQAAAC4AAAAvAAAAMAAAADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAAADoAAAA7AAAAPAAAAD0AAAA+AAAAPwAAAEAAAABBAAAAQgAAAEMAAABEAAAARQAAAEYAAABHAAAASAAAAEkAAABKAAAASwAAAEwAAABNAAAATgAAAE8AAABQAAAAUQAAAFIAAABTAAAAVAAAAFUAAABWAAAAVwAAAFgAAABZAAAAWgAAAFsAAABcAAAAXQAAAF4AAABfAAAAYAAAAGEAAABiAAAAYwAAAGQAAABlAAAAZgAAAGcAAABoAAAAaQAAAGoAAABrAAAAbAAAAG0AAABuAAAAbwAAAHAAAABxAAAAcgAAAHMAAAB0AAAAdQAAAHYAAAB3AAAAeAAAAHkAAAB6AAAACw==" } };
- yield return new object[] { new LinkedList<int>(new int[] { 5, 7, 9 }), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACEAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpbmtlZExpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAHVmVyc2lvbgVDb3VudAREYXRhAAAHCAgIAgAAAAMAAAADAAAACQMAAAAPAwAAAAMAAAAIBQAAAAcAAAAJAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACEAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpbmtlZExpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAHVmVyc2lvbgVDb3VudAREYXRhAAAHCAgIAgAAAAMAAAADAAAACQMAAAAPAwAAAAMAAAAIBQAAAAcAAAAJAAAACw==" } };
- yield return new object[] { new LinkedList<Point>(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADQAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpbmtlZExpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAB1ZlcnNpb24FQ291bnQAAAgIAgAAAAAAAAAAAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADQAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpbmtlZExpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAB1ZlcnNpb24FQ291bnQAAAgIAgAAAAAAAAAAAAAACw==" } };
- yield return new object[] { new LinkedList<Point>(new Point[] { new Point(1, 2), new Point(4, 3) }), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAA0AFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaW5rZWRMaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAwAAAAdWZXJzaW9uBUNvdW50BERhdGEAAAQICDVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQMAAAACAAAAAgAAAAIAAAAJBAAAAAcEAAAAAAEAAAACAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQDAAAACQUAAAAJBgAAAAUFAAAAM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAIAAAABWAFZAAAICAMAAAABAAAAAgAAAAEGAAAABQAAAAQAAAADAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAA0AFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaW5rZWRMaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAwAAAAdWZXJzaW9uBUNvdW50BERhdGEAAAQICDVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQMAAAACAAAAAgAAAAIAAAAJBAAAAAcEAAAAAAEAAAACAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQDAAAACQUAAAAJBgAAAAUFAAAAM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAIAAAABWAFZAAAICAMAAAABAAAAAgAAAAEGAAAABQAAAAQAAAADAAAACw==" } };
- yield return new object[] { new LinkedList<Tuple<int, Graph<int>>>(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADqA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpbmtlZExpc3RgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAAB1ZlcnNpb24FQ291bnQAAAgIAgAAAAAAAAAAAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADqA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpbmtlZExpc3RgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAAB1ZlcnNpb24FQ291bnQAAAgIAgAAAAAAAAAAAAAACw==" } };
- yield return new object[] { new LinkedList<Tuple<int, Graph<int>>>(new Tuple<int, Graph<int>>[] { Tuple.Create(1, new Graph<int>()), Tuple.Create(5, new Graph<int>()) }), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADqA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpbmtlZExpc3RgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAB1ZlcnNpb24FQ291bnQERGF0YQAAAwgI9AJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dW10CAAAAAgAAAAIAAAAJAwAAAAcDAAAAAAEAAAACAAAAA/ICU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQkEAAAACQUAAAAMBgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAQAAADyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAB21fSXRlbTEHbV9JdGVtMgAECJIBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0GAAAAAQAAAAkHAAAAAQUAAAAEAAAABQAAAAkIAAAABQcAAACSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAVWYWx1ZQVMaW5rcwAECJQBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV1bXQYAAAAGAAAAAAAAAAoBCAAAAAcAAAAAAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADqA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpbmtlZExpc3RgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAB1ZlcnNpb24FQ291bnQERGF0YQAAAwgI9AJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dW10CAAAAAgAAAAIAAAAJAwAAAAcDAAAAAAEAAAACAAAAA/ICU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQkEAAAACQUAAAAMBgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAQAAADyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAB21fSXRlbTEHbV9JdGVtMgAECJIBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0GAAAAAQAAAAkHAAAAAQUAAAAEAAAABQAAAAkIAAAABQcAAACSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAVWYWx1ZQVMaW5rcwAECJQBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV1bXQYAAAAGAAAAAAAAAAoBCAAAAAcAAAAAAAAACgs=" } };
-
- yield return new object[] { new Queue(), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAAAAADIAAAAAAAAABACAAAAIAAAAA0gCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAAAAADIAAAAAAAAABACAAAAIAAAAA0gCw==" } };
- yield return new object[] { new Queue(5), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAAAAADIAAAAAAAAABACAAAABQAAAA0FCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAAAAADIAAAAAAAAABACAAAABQAAAA0FCw==" } };
- yield return new object[] { new Queue(7, 2.2f), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAAAAADcAAAAAAAAABACAAAABwAAAA0HCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAAAAADcAAAAAAAAABACAAAABwAAAA0HCw==" } };
- yield return new object[] { new Queue(Enumerable.Range(0, 123).ToArray()), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAHsAAADIAAAAewAAABACAAAAewAAAAgIAAAAAAgIAQAAAAgIAgAAAAgIAwAAAAgIBAAAAAgIBQAAAAgIBgAAAAgIBwAAAAgICAAAAAgICQAAAAgICgAAAAgICwAAAAgIDAAAAAgIDQAAAAgIDgAAAAgIDwAAAAgIEAAAAAgIEQAAAAgIEgAAAAgIEwAAAAgIFAAAAAgIFQAAAAgIFgAAAAgIFwAAAAgIGAAAAAgIGQAAAAgIGgAAAAgIGwAAAAgIHAAAAAgIHQAAAAgIHgAAAAgIHwAAAAgIIAAAAAgIIQAAAAgIIgAAAAgIIwAAAAgIJAAAAAgIJQAAAAgIJgAAAAgIJwAAAAgIKAAAAAgIKQAAAAgIKgAAAAgIKwAAAAgILAAAAAgILQAAAAgILgAAAAgILwAAAAgIMAAAAAgIMQAAAAgIMgAAAAgIMwAAAAgINAAAAAgINQAAAAgINgAAAAgINwAAAAgIOAAAAAgIOQAAAAgIOgAAAAgIOwAAAAgIPAAAAAgIPQAAAAgIPgAAAAgIPwAAAAgIQAAAAAgIQQAAAAgIQgAAAAgIQwAAAAgIRAAAAAgIRQAAAAgIRgAAAAgIRwAAAAgISAAAAAgISQAAAAgISgAAAAgISwAAAAgITAAAAAgITQAAAAgITgAAAAgITwAAAAgIUAAAAAgIUQAAAAgIUgAAAAgIUwAAAAgIVAAAAAgIVQAAAAgIVgAAAAgIVwAAAAgIWAAAAAgIWQAAAAgIWgAAAAgIWwAAAAgIXAAAAAgIXQAAAAgIXgAAAAgIXwAAAAgIYAAAAAgIYQAAAAgIYgAAAAgIYwAAAAgIZAAAAAgIZQAAAAgIZgAAAAgIZwAAAAgIaAAAAAgIaQAAAAgIagAAAAgIawAAAAgIbAAAAAgIbQAAAAgIbgAAAAgIbwAAAAgIcAAAAAgIcQAAAAgIcgAAAAgIcwAAAAgIdAAAAAgIdQAAAAgIdgAAAAgIdwAAAAgIeAAAAAgIeQAAAAgIegAAAAs=", "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAHsAAADIAAAAewAAABACAAAAewAAAAgIAAAAAAgIAQAAAAgIAgAAAAgIAwAAAAgIBAAAAAgIBQAAAAgIBgAAAAgIBwAAAAgICAAAAAgICQAAAAgICgAAAAgICwAAAAgIDAAAAAgIDQAAAAgIDgAAAAgIDwAAAAgIEAAAAAgIEQAAAAgIEgAAAAgIEwAAAAgIFAAAAAgIFQAAAAgIFgAAAAgIFwAAAAgIGAAAAAgIGQAAAAgIGgAAAAgIGwAAAAgIHAAAAAgIHQAAAAgIHgAAAAgIHwAAAAgIIAAAAAgIIQAAAAgIIgAAAAgIIwAAAAgIJAAAAAgIJQAAAAgIJgAAAAgIJwAAAAgIKAAAAAgIKQAAAAgIKgAAAAgIKwAAAAgILAAAAAgILQAAAAgILgAAAAgILwAAAAgIMAAAAAgIMQAAAAgIMgAAAAgIMwAAAAgINAAAAAgINQAAAAgINgAAAAgINwAAAAgIOAAAAAgIOQAAAAgIOgAAAAgIOwAAAAgIPAAAAAgIPQAAAAgIPgAAAAgIPwAAAAgIQAAAAAgIQQAAAAgIQgAAAAgIQwAAAAgIRAAAAAgIRQAAAAgIRgAAAAgIRwAAAAgISAAAAAgISQAAAAgISgAAAAgISwAAAAgITAAAAAgITQAAAAgITgAAAAgITwAAAAgIUAAAAAgIUQAAAAgIUgAAAAgIUwAAAAgIVAAAAAgIVQAAAAgIVgAAAAgIVwAAAAgIWAAAAAgIWQAAAAgIWgAAAAgIWwAAAAgIXAAAAAgIXQAAAAgIXgAAAAgIXwAAAAgIYAAAAAgIYQAAAAgIYgAAAAgIYwAAAAgIZAAAAAgIZQAAAAgIZgAAAAgIZwAAAAgIaAAAAAgIaQAAAAgIagAAAAgIawAAAAgIbAAAAAgIbQAAAAgIbgAAAAgIbwAAAAgIcAAAAAgIcQAAAAgIcgAAAAgIcwAAAAgIdAAAAAgIdQAAAAgIdgAAAAgIdwAAAAgIeAAAAAgIeQAAAAgIegAAAAs=" } };
- yield return new object[] { new Queue(new int[] { 5, 7, 9 }), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAMAAADIAAAAAwAAABACAAAAAwAAAAgIBQAAAAgIBwAAAAgICQAAAAs=", "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAMAAADIAAAAAwAAABACAAAAAwAAAAgIBQAAAAgIBwAAAAgICQAAAAs=" } };
- yield return new object[] { new Queue(new Point[] { new Point(1, 2), new Point(4, 3) }), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAIAAADIAAAAAgAAABACAAAAAgAAAAkDAAAACQQAAAAMBQAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQMAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIBQAAAAEAAAACAAAAAQQAAAADAAAABAAAAAMAAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAIAAADIAAAAAgAAABACAAAAAgAAAAkDAAAACQQAAAAMBQAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQMAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIBQAAAAEAAAACAAAAAQQAAAADAAAABAAAAAMAAAAL" } };
- yield return new object[] { new Queue(new Tuple<int, Graph<int>>[] { Tuple.Create(1, new Graph<int>()), Tuple.Create(5, new Graph<int>()) }), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAIAAADIAAAAAgAAABACAAAAAgAAAAkDAAAACQQAAAAMBQAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAMAAADyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAB21fSXRlbTEHbV9JdGVtMgAECJIBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0FAAAAAQAAAAkGAAAAAQQAAAADAAAABQAAAAkHAAAABQYAAACSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAVWYWx1ZQVMaW5rcwAECJQBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV1bXQUAAAAFAAAAAAAAAAoBBwAAAAYAAAAAAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAIAAADIAAAAAgAAABACAAAAAgAAAAkDAAAACQQAAAAMBQAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAMAAADyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAB21fSXRlbTEHbV9JdGVtMgAECJIBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0FAAAAAQAAAAkGAAAAAQQAAAADAAAABQAAAAkHAAAABQYAAACSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAVWYWx1ZQVMaW5rcwAECJQBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV1bXQUAAAAFAAAAAAAAAAoBBwAAAAYAAAAAAAAACgs=" } };
-
- yield return new object[] { new SortedDictionary<int, int>(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADmAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAARfc2V0BNcCU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuVHJlZVNldGAxW1tTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAACAAAACQMAAAAMBAAAAFVTeXN0ZW0uQ29sbGVjdGlvbnMsIFZlcnNpb249NC4xLjEuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQMAAADXAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlRyZWVTZXRgMVtbU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABUNvdW50CENvbXBhcmVyB1ZlcnNpb24ABAAI+wFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWREaWN0aW9uYXJ5YDIrS2V5VmFsdWVQYWlyQ29tcGFyZXJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAIAgAAAAAAAAAJBQAAAAAAAAAFBQAAAPsBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuU29ydGVkRGljdGlvbmFyeWAyK0tleVZhbHVlUGFpckNvbXBhcmVyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAAC2tleUNvbXBhcmVyA4kBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0EAAAACQYAAAAEBgAAAIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADmAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAARfc2V0BNcCU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuVHJlZVNldGAxW1tTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAACAAAACQMAAAAFAwAAANcCU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuVHJlZVNldGAxW1tTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgAEAAj7AVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMitLZXlWYWx1ZVBhaXJDb21wYXJlcltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAgCAAAAAAAAAAkEAAAAAAAAAAUEAAAA+wFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWREaWN0aW9uYXJ5YDIrS2V5VmFsdWVQYWlyQ29tcGFyZXJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAALa2V5Q29tcGFyZXIDiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAJBQAAAAQFAAAAiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL" } };
- yield return new object[] { new SortedDictionary<int, int>(Comparer<int>.Default), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADmAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAARfc2V0BNcCU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuVHJlZVNldGAxW1tTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAACAAAACQMAAAAMBAAAAFVTeXN0ZW0uQ29sbGVjdGlvbnMsIFZlcnNpb249NC4xLjEuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQMAAADXAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlRyZWVTZXRgMVtbU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABUNvdW50CENvbXBhcmVyB1ZlcnNpb24ABAAI+wFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWREaWN0aW9uYXJ5YDIrS2V5VmFsdWVQYWlyQ29tcGFyZXJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAIAgAAAAAAAAAJBQAAAAAAAAAFBQAAAPsBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuU29ydGVkRGljdGlvbmFyeWAyK0tleVZhbHVlUGFpckNvbXBhcmVyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAAC2tleUNvbXBhcmVyA4kBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0EAAAACQYAAAAEBgAAAIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADmAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAARfc2V0BNcCU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuVHJlZVNldGAxW1tTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAACAAAACQMAAAAFAwAAANcCU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuVHJlZVNldGAxW1tTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgAEAAj7AVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMitLZXlWYWx1ZVBhaXJDb21wYXJlcltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAgCAAAAAAAAAAkEAAAAAAAAAAUEAAAA+wFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWREaWN0aW9uYXJ5YDIrS2V5VmFsdWVQYWlyQ29tcGFyZXJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAALa2V5Q29tcGFyZXIDiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAJBQAAAAQFAAAAiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL" } };
- yield return new object[] { new SortedDictionary<int, Point>(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACyAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQEAAAAEX3NldASjA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlRyZWVTZXRgMVtbU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAIAAAAJAwAAAAwEAAAAVVN5c3RlbS5Db2xsZWN0aW9ucywgVmVyc2lvbj00LjEuMS4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAwAAAKMDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuVHJlZVNldGAxW1tTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABUNvdW50CENvbXBhcmVyB1ZlcnNpb24ABAAIxwJTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWREaWN0aW9uYXJ5YDIrS2V5VmFsdWVQYWlyQ29tcGFyZXJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0EAAAACAIAAAAAAAAACQUAAAAAAAAABQUAAADHAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMitLZXlWYWx1ZVBhaXJDb21wYXJlcltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQEAAAALa2V5Q29tcGFyZXIDiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAJBgAAAAQGAAAAiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACyAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQEAAAAEX3NldASjA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlRyZWVTZXRgMVtbU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAIAAAAJAwAAAAUDAAAAowNTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5UcmVlU2V0YDFbW1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgAEAAjHAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMitLZXlWYWx1ZVBhaXJDb21wYXJlcltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQIAAAAIAgAAAAAAAAAJBAAAAAAAAAAFBAAAAMcCU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuU29ydGVkRGljdGlvbmFyeWAyK0tleVZhbHVlUGFpckNvbXBhcmVyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAQAAAAtrZXlDb21wYXJlcgOJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAkFAAAABAUAAACJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAs=" } };
- yield return new object[] { new SortedDictionary<int, Tuple<int, Graph<int>>>(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADMBFN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAEX3NldAS9BVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlRyZWVTZXRgMVtbU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAIAAAAJAwAAAAwEAAAAVVN5c3RlbS5Db2xsZWN0aW9ucywgVmVyc2lvbj00LjEuMS4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAwAAAL0FU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuVHJlZVNldGAxW1tTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABUNvdW50CENvbXBhcmVyB1ZlcnNpb24ABAAI4QRTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWREaWN0aW9uYXJ5YDIrS2V5VmFsdWVQYWlyQ29tcGFyZXJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0EAAAACAIAAAAAAAAACQUAAAAAAAAABQUAAADhBFN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMitLZXlWYWx1ZVBhaXJDb21wYXJlcltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAALa2V5Q29tcGFyZXIDiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAJBgAAAAQGAAAAiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADMBFN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAEX3NldAS9BVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlRyZWVTZXRgMVtbU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAIAAAAJAwAAAAUDAAAAvQVTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5UcmVlU2V0YDFbW1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgAEAAjhBFN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMitLZXlWYWx1ZVBhaXJDb21wYXJlcltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAIAgAAAAAAAAAJBAAAAAAAAAAFBAAAAOEEU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuU29ydGVkRGljdGlvbmFyeWAyK0tleVZhbHVlUGFpckNvbXBhcmVyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAAtrZXlDb21wYXJlcgOJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAkFAAAABAUAAACJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAs=" } };
- yield return new object[] { new SortedDictionary<Tuple<int, Point>, Graph<int>>(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACYBVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMltbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0BAAAABF9zZXQEiQZTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5UcmVlU2V0YDFbW1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAAAgAAAAkDAAAADAQAAABVU3lzdGVtLkNvbGxlY3Rpb25zLCBWZXJzaW9uPTQuMS4xLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUDAAAAiQZTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5UcmVlU2V0YDFbW1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABUNvdW50CENvbXBhcmVyB1ZlcnNpb24ABAAIrQVTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWREaWN0aW9uYXJ5YDIrS2V5VmFsdWVQYWlyQ29tcGFyZXJbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dBAAAAAgCAAAAAAAAAAkFAAAAAAAAAAUFAAAArQVTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWREaWN0aW9uYXJ5YDIrS2V5VmFsdWVQYWlyQ29tcGFyZXJbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAQAAAAtrZXlDb21wYXJlcgOPA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLk9iamVjdENvbXBhcmVyYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAJBgAAAAQGAAAAjwNTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5PYmplY3RDb21wYXJlcmAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACYBVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMltbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0BAAAABF9zZXQEiQZTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5UcmVlU2V0YDFbW1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAAAgAAAAkDAAAABQMAAACJBlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlRyZWVTZXRgMVtbU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgAEAAitBVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMitLZXlWYWx1ZVBhaXJDb21wYXJlcltbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAACAIAAAAAAAAACQQAAAAAAAAABQQAAACtBVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMitLZXlWYWx1ZVBhaXJDb21wYXJlcltbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0BAAAAC2tleUNvbXBhcmVyA48DU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0Q29tcGFyZXJgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAkFAAAABAUAAACPA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLk9iamVjdENvbXBhcmVyYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL" } };
-
- yield return new object[] { new SortedList(), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdAcAAAAEa2V5cwZ2YWx1ZXMFX3NpemUHdmVyc2lvbghjb21wYXJlcgdrZXlMaXN0CXZhbHVlTGlzdAUFAAADAwMICBtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXIlU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QrS2V5TGlzdCdTeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdCtWYWx1ZUxpc3QJAgAAAAkCAAAAAAAAAAAAAAAJAwAAAAoKEAIAAAAAAAAABAMAAAAbU3lzdGVtLkNvbGxlY3Rpb25zLkNvbXBhcmVyAQAAAAtDb21wYXJlSW5mbwMgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8JBAAAAAQEAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvAwAAAAZtX25hbWUNbV9Tb3J0VmVyc2lvbgdjdWx0dXJlAQMAIFN5c3RlbS5HbG9iYWxpemF0aW9uLlNvcnRWZXJzaW9uCAYFAAAAAAp/AAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdAcAAAAEa2V5cwZ2YWx1ZXMFX3NpemUHdmVyc2lvbghjb21wYXJlcgdrZXlMaXN0CXZhbHVlTGlzdAUFAAADAwMICBtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXIlU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QrS2V5TGlzdCdTeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdCtWYWx1ZUxpc3QJAgAAAAkCAAAAAAAAAAAAAAAJAwAAAAoKEAIAAAAAAAAABAMAAAAbU3lzdGVtLkNvbGxlY3Rpb25zLkNvbXBhcmVyAQAAAAtDb21wYXJlSW5mbwMgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8JBAAAAAQEAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvBAAAAAZtX25hbWUJd2luMzJMQ0lEB2N1bHR1cmUNbV9Tb3J0VmVyc2lvbgEAAAMICCBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbgYFAAAAAAAAAAB/AAAACgs=" } };
- yield return new object[] { new SortedList(Comparer.DefaultInvariant), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdAcAAAAEa2V5cwZ2YWx1ZXMFX3NpemUHdmVyc2lvbghjb21wYXJlcgdrZXlMaXN0CXZhbHVlTGlzdAUFAAADAwMICBtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXIlU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QrS2V5TGlzdCdTeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdCtWYWx1ZUxpc3QJAgAAAAkCAAAAAAAAAAAAAAAJAwAAAAoKEAIAAAAAAAAABAMAAAAbU3lzdGVtLkNvbGxlY3Rpb25zLkNvbXBhcmVyAQAAAAtDb21wYXJlSW5mbwMgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8JBAAAAAQEAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvAwAAAAZtX25hbWUNbV9Tb3J0VmVyc2lvbgdjdWx0dXJlAQMAIFN5c3RlbS5HbG9iYWxpemF0aW9uLlNvcnRWZXJzaW9uCAYFAAAAAAp/AAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdAcAAAAEa2V5cwZ2YWx1ZXMFX3NpemUHdmVyc2lvbghjb21wYXJlcgdrZXlMaXN0CXZhbHVlTGlzdAUFAAADAwMICBtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXIlU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QrS2V5TGlzdCdTeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdCtWYWx1ZUxpc3QJAgAAAAkCAAAAAAAAAAAAAAAJAwAAAAoKEAIAAAAAAAAABAMAAAAbU3lzdGVtLkNvbGxlY3Rpb25zLkNvbXBhcmVyAQAAAAtDb21wYXJlSW5mbwMgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8JBAAAAAQEAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvBAAAAAZtX25hbWUJd2luMzJMQ0lEB2N1bHR1cmUNbV9Tb3J0VmVyc2lvbgEAAAMICCBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbgYFAAAAAAAAAAB/AAAACgs=" } };
- yield return new object[] { new SortedList(Comparer.DefaultInvariant, 4), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdAcAAAAEa2V5cwZ2YWx1ZXMFX3NpemUHdmVyc2lvbghjb21wYXJlcgdrZXlMaXN0CXZhbHVlTGlzdAUFAAADAwMICBtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXIlU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QrS2V5TGlzdCdTeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdCtWYWx1ZUxpc3QJAgAAAAkDAAAAAAAAAAAAAAAJBAAAAAoKEAIAAAAEAAAADQQQAwAAAAQAAAANBAQEAAAAG1N5c3RlbS5Db2xsZWN0aW9ucy5Db21wYXJlcgEAAAALQ29tcGFyZUluZm8DIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCQUAAAAEBQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwMAAAAGbV9uYW1lDW1fU29ydFZlcnNpb24HY3VsdHVyZQEDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbggGBgAAAAAKfwAAAAs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdAcAAAAEa2V5cwZ2YWx1ZXMFX3NpemUHdmVyc2lvbghjb21wYXJlcgdrZXlMaXN0CXZhbHVlTGlzdAUFAAADAwMICBtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXIlU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QrS2V5TGlzdCdTeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdCtWYWx1ZUxpc3QJAgAAAAkDAAAAAAAAAAAAAAAJBAAAAAoKEAIAAAAEAAAADQQQAwAAAAQAAAANBAQEAAAAG1N5c3RlbS5Db2xsZWN0aW9ucy5Db21wYXJlcgEAAAALQ29tcGFyZUluZm8DIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCQUAAAAEBQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwQAAAAGbV9uYW1lCXdpbjMyTENJRAdjdWx0dXJlDW1fU29ydFZlcnNpb24BAAADCAggU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24GBgAAAAAAAAAAfwAAAAoL" } };
-
- yield return new object[] { new SortedSet<int>(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACDAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAVDb3VudAhDb21wYXJlcgdWZXJzaW9uAAMACIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IAgAAAAAAAAAJAwAAAAAAAAAEAwAAAIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACDAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAVDb3VudAhDb21wYXJlcgdWZXJzaW9uAAMACIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IAgAAAAAAAAAJAwAAAAAAAAAEAwAAAIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==" } };
- yield return new object[] { new SortedSet<int>(Comparer<int>.Default), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACDAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAVDb3VudAhDb21wYXJlcgdWZXJzaW9uAAMACIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IAgAAAAAAAAAJAwAAAAAAAAAEAwAAAIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACDAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAVDb3VudAhDb21wYXJlcgdWZXJzaW9uAAMACIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IAgAAAAAAAAAJAwAAAAAAAAAEAwAAAIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==" } };
- yield return new object[] { new SortedSet<int>(Enumerable.Range(0, 123)), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACDAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAVDb3VudAhDb21wYXJlcgdWZXJzaW9uBUl0ZW1zAAMABwiJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAgCAAAAewAAAAkDAAAAAAAAAAkEAAAABAMAAACJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAA8EAAAAewAAAAgAAAAAAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAASAAAAEwAAABQAAAAVAAAAFgAAABcAAAAYAAAAGQAAABoAAAAbAAAAHAAAAB0AAAAeAAAAHwAAACAAAAAhAAAAIgAAACMAAAAkAAAAJQAAACYAAAAnAAAAKAAAACkAAAAqAAAAKwAAACwAAAAtAAAALgAAAC8AAAAwAAAAMQAAADIAAAAzAAAANAAAADUAAAA2AAAANwAAADgAAAA5AAAAOgAAADsAAAA8AAAAPQAAAD4AAAA/AAAAQAAAAEEAAABCAAAAQwAAAEQAAABFAAAARgAAAEcAAABIAAAASQAAAEoAAABLAAAATAAAAE0AAABOAAAATwAAAFAAAABRAAAAUgAAAFMAAABUAAAAVQAAAFYAAABXAAAAWAAAAFkAAABaAAAAWwAAAFwAAABdAAAAXgAAAF8AAABgAAAAYQAAAGIAAABjAAAAZAAAAGUAAABmAAAAZwAAAGgAAABpAAAAagAAAGsAAABsAAAAbQAAAG4AAABvAAAAcAAAAHEAAAByAAAAcwAAAHQAAAB1AAAAdgAAAHcAAAB4AAAAeQAAAHoAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACDAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAVDb3VudAhDb21wYXJlcgdWZXJzaW9uBUl0ZW1zAAMABwiJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAgCAAAAewAAAAkDAAAAAAAAAAkEAAAABAMAAACJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAA8EAAAAewAAAAgAAAAAAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAASAAAAEwAAABQAAAAVAAAAFgAAABcAAAAYAAAAGQAAABoAAAAbAAAAHAAAAB0AAAAeAAAAHwAAACAAAAAhAAAAIgAAACMAAAAkAAAAJQAAACYAAAAnAAAAKAAAACkAAAAqAAAAKwAAACwAAAAtAAAALgAAAC8AAAAwAAAAMQAAADIAAAAzAAAANAAAADUAAAA2AAAANwAAADgAAAA5AAAAOgAAADsAAAA8AAAAPQAAAD4AAAA/AAAAQAAAAEEAAABCAAAAQwAAAEQAAABFAAAARgAAAEcAAABIAAAASQAAAEoAAABLAAAATAAAAE0AAABOAAAATwAAAFAAAABRAAAAUgAAAFMAAABUAAAAVQAAAFYAAABXAAAAWAAAAFkAAABaAAAAWwAAAFwAAABdAAAAXgAAAF8AAABgAAAAYQAAAGIAAABjAAAAZAAAAGUAAABmAAAAZwAAAGgAAABpAAAAagAAAGsAAABsAAAAbQAAAG4AAABvAAAAcAAAAHEAAAByAAAAcwAAAHQAAAB1AAAAdgAAAHcAAAB4AAAAeQAAAHoAAAAL" } };
- yield return new object[] { new SortedSet<int>(new int[] { 5, 7, 9 }), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACDAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAVDb3VudAhDb21wYXJlcgdWZXJzaW9uBUl0ZW1zAAMABwiJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAgCAAAAAwAAAAkDAAAAAAAAAAkEAAAABAMAAACJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAA8EAAAAAwAAAAgFAAAABwAAAAkAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACDAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAVDb3VudAhDb21wYXJlcgdWZXJzaW9uBUl0ZW1zAAMABwiJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAgCAAAAAwAAAAkDAAAAAAAAAAkEAAAABAMAAACJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAA8EAAAAAwAAAAgFAAAABwAAAAkAAAAL" } };
- yield return new object[] { new SortedSet<Point>(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADPAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgADAAjVAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQgCAAAAAAAAAAkDAAAAAAAAAAQDAAAA1QFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0AAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADPAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgADAAjVAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQgCAAAAAAAAAAkDAAAAAAAAAAQDAAAA1QFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0AAAAACw==" } };
- yield return new object[] { new SortedSet<Point>(Comparer<Point>.Default), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADPAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgADAAjVAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQgCAAAAAAAAAAkDAAAAAAAAAAQDAAAA1QFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0AAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADPAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgADAAjVAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQgCAAAAAAAAAAkDAAAAAAAAAAQDAAAA1QFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0AAAAACw==" } };
- yield return new object[] { new SortedSet<Point>(new Point[] { new Point(1, 2), new Point(4, 3) }), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAAzwFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWRTZXRgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0EAAAABUNvdW50CENvbXBhcmVyB1ZlcnNpb24FSXRlbXMAAwAECNUBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCDVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQMAAAACAAAAAQAAAAkEAAAAAAAAAAkFAAAABAQAAADVAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQAAAAAHBQAAAAABAAAAAQAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AwAAAAkGAAAABQYAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIAwAAAAEAAAACAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAAzwFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWRTZXRgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0EAAAABUNvdW50CENvbXBhcmVyB1ZlcnNpb24FSXRlbXMAAwAECNUBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCDVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQMAAAACAAAAAQAAAAkEAAAAAAAAAAkFAAAABAQAAADVAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQAAAAAHBQAAAAABAAAAAQAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AwAAAAkGAAAABQYAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIAwAAAAEAAAACAAAACw==" } };
- yield return new object[] { new SortedSet<Tuple<int, Graph<int>>>(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADpA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgADAAjuA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLk9iamVjdENvbXBhcmVyYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAIAAAAAAAAACQMAAAAAAAAABAMAAADuA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLk9iamVjdENvbXBhcmVyYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADpA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgADAAjuA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLk9iamVjdENvbXBhcmVyYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAIAAAAAAAAACQMAAAAAAAAABAMAAADuA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLk9iamVjdENvbXBhcmVyYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAs=" } };
- yield return new object[] { new SortedSet<Tuple<int, Graph<int>>>(new Tuple<int, Graph<int>>[] { Tuple.Create(1, new Graph<int>()), Tuple.Create(5, new Graph<int>()) }), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADpA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgVJdGVtcwADAAMI7gNTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5PYmplY3RDb21wYXJlcmAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQj0AlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV1bXQIAAAACAAAACQMAAAAAAAAACQQAAAAEAwAAAO4DU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0Q29tcGFyZXJgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAABwQAAAAAAQAAAAIAAAAD8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCQUAAAAJBgAAAAwHAAAAcFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWIEBQAAAPICU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQIAAAAHbV9JdGVtMQdtX0l0ZW0yAAQIkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQcAAAABAAAACQgAAAABBgAAAAUAAAAFAAAACQkAAAAFCAAAAJIBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAABVZhbHVlBUxpbmtzAAQIlAFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXVtdBwAAAAcAAAAAAAAACgEJAAAACAAAAAAAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADpA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgVJdGVtcwADAAMI7gNTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5PYmplY3RDb21wYXJlcmAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQj0AlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV1bXQIAAAACAAAACQMAAAAAAAAACQQAAAAEAwAAAO4DU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0Q29tcGFyZXJgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAABwQAAAAAAQAAAAIAAAAD8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCQUAAAAJBgAAAAwHAAAAcFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWIEBQAAAPICU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQIAAAAHbV9JdGVtMQdtX0l0ZW0yAAQIkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQcAAAABAAAACQgAAAABBgAAAAUAAAAFAAAACQkAAAAFCAAAAJIBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAABVZhbHVlBUxpbmtzAAQIlAFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXVtdBwAAAAcAAAAAAAAACgEJAAAACAAAAAAAAAAKCw==" } };
-
- yield return new object[] { new Stack(), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuU3RhY2sDAAAABl9hcnJheQVfc2l6ZQhfdmVyc2lvbgUAAAgICQIAAAAAAAAAAAAAABACAAAACgAAAA0KCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuU3RhY2sDAAAABl9hcnJheQVfc2l6ZQhfdmVyc2lvbgUAAAgICQIAAAAAAAAAAAAAABACAAAACgAAAA0KCw==" } };
- yield return new object[] { new Stack(Enumerable.Range(0, 123).ToArray()), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuU3RhY2sDAAAABl9hcnJheQVfc2l6ZQhfdmVyc2lvbgUAAAgICQIAAAB7AAAAewAAABACAAAAewAAAAgIAAAAAAgIAQAAAAgIAgAAAAgIAwAAAAgIBAAAAAgIBQAAAAgIBgAAAAgIBwAAAAgICAAAAAgICQAAAAgICgAAAAgICwAAAAgIDAAAAAgIDQAAAAgIDgAAAAgIDwAAAAgIEAAAAAgIEQAAAAgIEgAAAAgIEwAAAAgIFAAAAAgIFQAAAAgIFgAAAAgIFwAAAAgIGAAAAAgIGQAAAAgIGgAAAAgIGwAAAAgIHAAAAAgIHQAAAAgIHgAAAAgIHwAAAAgIIAAAAAgIIQAAAAgIIgAAAAgIIwAAAAgIJAAAAAgIJQAAAAgIJgAAAAgIJwAAAAgIKAAAAAgIKQAAAAgIKgAAAAgIKwAAAAgILAAAAAgILQAAAAgILgAAAAgILwAAAAgIMAAAAAgIMQAAAAgIMgAAAAgIMwAAAAgINAAAAAgINQAAAAgINgAAAAgINwAAAAgIOAAAAAgIOQAAAAgIOgAAAAgIOwAAAAgIPAAAAAgIPQAAAAgIPgAAAAgIPwAAAAgIQAAAAAgIQQAAAAgIQgAAAAgIQwAAAAgIRAAAAAgIRQAAAAgIRgAAAAgIRwAAAAgISAAAAAgISQAAAAgISgAAAAgISwAAAAgITAAAAAgITQAAAAgITgAAAAgITwAAAAgIUAAAAAgIUQAAAAgIUgAAAAgIUwAAAAgIVAAAAAgIVQAAAAgIVgAAAAgIVwAAAAgIWAAAAAgIWQAAAAgIWgAAAAgIWwAAAAgIXAAAAAgIXQAAAAgIXgAAAAgIXwAAAAgIYAAAAAgIYQAAAAgIYgAAAAgIYwAAAAgIZAAAAAgIZQAAAAgIZgAAAAgIZwAAAAgIaAAAAAgIaQAAAAgIagAAAAgIawAAAAgIbAAAAAgIbQAAAAgIbgAAAAgIbwAAAAgIcAAAAAgIcQAAAAgIcgAAAAgIcwAAAAgIdAAAAAgIdQAAAAgIdgAAAAgIdwAAAAgIeAAAAAgIeQAAAAgIegAAAAs=", "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuU3RhY2sDAAAABl9hcnJheQVfc2l6ZQhfdmVyc2lvbgUAAAgICQIAAAB7AAAAewAAABACAAAAewAAAAgIAAAAAAgIAQAAAAgIAgAAAAgIAwAAAAgIBAAAAAgIBQAAAAgIBgAAAAgIBwAAAAgICAAAAAgICQAAAAgICgAAAAgICwAAAAgIDAAAAAgIDQAAAAgIDgAAAAgIDwAAAAgIEAAAAAgIEQAAAAgIEgAAAAgIEwAAAAgIFAAAAAgIFQAAAAgIFgAAAAgIFwAAAAgIGAAAAAgIGQAAAAgIGgAAAAgIGwAAAAgIHAAAAAgIHQAAAAgIHgAAAAgIHwAAAAgIIAAAAAgIIQAAAAgIIgAAAAgIIwAAAAgIJAAAAAgIJQAAAAgIJgAAAAgIJwAAAAgIKAAAAAgIKQAAAAgIKgAAAAgIKwAAAAgILAAAAAgILQAAAAgILgAAAAgILwAAAAgIMAAAAAgIMQAAAAgIMgAAAAgIMwAAAAgINAAAAAgINQAAAAgINgAAAAgINwAAAAgIOAAAAAgIOQAAAAgIOgAAAAgIOwAAAAgIPAAAAAgIPQAAAAgIPgAAAAgIPwAAAAgIQAAAAAgIQQAAAAgIQgAAAAgIQwAAAAgIRAAAAAgIRQAAAAgIRgAAAAgIRwAAAAgISAAAAAgISQAAAAgISgAAAAgISwAAAAgITAAAAAgITQAAAAgITgAAAAgITwAAAAgIUAAAAAgIUQAAAAgIUgAAAAgIUwAAAAgIVAAAAAgIVQAAAAgIVgAAAAgIVwAAAAgIWAAAAAgIWQAAAAgIWgAAAAgIWwAAAAgIXAAAAAgIXQAAAAgIXgAAAAgIXwAAAAgIYAAAAAgIYQAAAAgIYgAAAAgIYwAAAAgIZAAAAAgIZQAAAAgIZgAAAAgIZwAAAAgIaAAAAAgIaQAAAAgIagAAAAgIawAAAAgIbAAAAAgIbQAAAAgIbgAAAAgIbwAAAAgIcAAAAAgIcQAAAAgIcgAAAAgIcwAAAAgIdAAAAAgIdQAAAAgIdgAAAAgIdwAAAAgIeAAAAAgIeQAAAAgIegAAAAs=" } };
- yield return new object[] { new Stack(new int[] { 5, 7, 9 }), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuU3RhY2sDAAAABl9hcnJheQVfc2l6ZQhfdmVyc2lvbgUAAAgICQIAAAADAAAAAwAAABACAAAACgAAAAgIBQAAAAgIBwAAAAgICQAAAA0HCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuU3RhY2sDAAAABl9hcnJheQVfc2l6ZQhfdmVyc2lvbgUAAAgICQIAAAADAAAAAwAAABACAAAACgAAAAgIBQAAAAgIBwAAAAgICQAAAA0HCw==" } };
- yield return new object[] { new Stack(new Point[] { new Point(1, 2), new Point(4, 3) }), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuU3RhY2sDAAAABl9hcnJheQVfc2l6ZQhfdmVyc2lvbgUAAAgICQIAAAACAAAAAgAAABACAAAACgAAAAkDAAAACQQAAAANCAwFAAAAcFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWIFAwAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgFAAAAAQAAAAIAAAABBAAAAAMAAAAEAAAAAwAAAAs=", "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuU3RhY2sDAAAABl9hcnJheQVfc2l6ZQhfdmVyc2lvbgUAAAgICQIAAAACAAAAAgAAABACAAAACgAAAAkDAAAACQQAAAANCAwFAAAAcFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWIFAwAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgFAAAAAQAAAAIAAAABBAAAAAMAAAAEAAAAAwAAAAs=" } };
- yield return new object[] { new Stack(new Tuple<int, Graph<int>>[] { Tuple.Create(1, new Graph<int>()), Tuple.Create(5, new Graph<int>()) }), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuU3RhY2sDAAAABl9hcnJheQVfc2l6ZQhfdmVyc2lvbgUAAAgICQIAAAACAAAAAgAAABACAAAACgAAAAkDAAAACQQAAAANCAwFAAAAcFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWIEAwAAAPICU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQIAAAAHbV9JdGVtMQdtX0l0ZW0yAAQIkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQUAAAABAAAACQYAAAABBAAAAAMAAAAFAAAACQcAAAAFBgAAAJIBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAABVZhbHVlBUxpbmtzAAQIlAFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXVtdBQAAAAUAAAAAAAAACgEHAAAABgAAAAAAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuU3RhY2sDAAAABl9hcnJheQVfc2l6ZQhfdmVyc2lvbgUAAAgICQIAAAACAAAAAgAAABACAAAACgAAAAkDAAAACQQAAAANCAwFAAAAcFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWIEAwAAAPICU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQIAAAAHbV9JdGVtMQdtX0l0ZW0yAAQIkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQUAAAABAAAACQYAAAABBAAAAAMAAAAFAAAACQcAAAAFBgAAAJIBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAABVZhbHVlBUxpbmtzAAQIlAFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXVtdBQAAAAUAAAAAAAAACgEHAAAABgAAAAAAAAAKCw==" } };
-
- yield return new object[] { new Hashtable(), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBwAAAApMb2FkRmFjdG9yB1ZlcnNpb24IQ29tcGFyZXIQSGFzaENvZGVQcm92aWRlcghIYXNoU2l6ZQRLZXlzBlZhbHVlcwAAAwMABQULCBxTeXN0ZW0uQ29sbGVjdGlvbnMuSUNvbXBhcmVyJFN5c3RlbS5Db2xsZWN0aW9ucy5JSGFzaENvZGVQcm92aWRlcgjsUTg/AAAAAAoKAwAAAAkCAAAACQMAAAAQAgAAAAAAAAAQAwAAAAAAAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBwAAAApMb2FkRmFjdG9yB1ZlcnNpb24IQ29tcGFyZXIQSGFzaENvZGVQcm92aWRlcghIYXNoU2l6ZQRLZXlzBlZhbHVlcwAAAwMABQULCBxTeXN0ZW0uQ29sbGVjdGlvbnMuSUNvbXBhcmVyJFN5c3RlbS5Db2xsZWN0aW9ucy5JSGFzaENvZGVQcm92aWRlcgjsUTg/AAAAAAoKAwAAAAkCAAAACQMAAAAQAgAAAAAAAAAQAwAAAAAAAAAL" } };
- yield return new object[] { new Hashtable(EqualityComparer<object>.Default), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uT2JqZWN0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQjsUTg/AAAAAAkCAAAAAwAAAAkDAAAACQQAAAAEAgAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uT2JqZWN0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAQAwAAAAAAAAAQBAAAAAAAAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uT2JqZWN0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQjsUTg/AAAAAAkCAAAAAwAAAAkDAAAACQQAAAAEAgAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uT2JqZWN0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAQAwAAAAAAAAAQBAAAAAAAAAAL" } };
- yield return new object[] { new Hashtable(5), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBwAAAApMb2FkRmFjdG9yB1ZlcnNpb24IQ29tcGFyZXIQSGFzaENvZGVQcm92aWRlcghIYXNoU2l6ZQRLZXlzBlZhbHVlcwAAAwMABQULCBxTeXN0ZW0uQ29sbGVjdGlvbnMuSUNvbXBhcmVyJFN5c3RlbS5Db2xsZWN0aW9ucy5JSGFzaENvZGVQcm92aWRlcgjsUTg/AAAAAAoKBwAAAAkCAAAACQMAAAAQAgAAAAAAAAAQAwAAAAAAAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBwAAAApMb2FkRmFjdG9yB1ZlcnNpb24IQ29tcGFyZXIQSGFzaENvZGVQcm92aWRlcghIYXNoU2l6ZQRLZXlzBlZhbHVlcwAAAwMABQULCBxTeXN0ZW0uQ29sbGVjdGlvbnMuSUNvbXBhcmVyJFN5c3RlbS5Db2xsZWN0aW9ucy5JSGFzaENvZGVQcm92aWRlcgjsUTg/AAAAAAoKBwAAAAkCAAAACQMAAAAQAgAAAAAAAAAQAwAAAAAAAAAL" } };
- yield return new object[] { new Hashtable(new Dictionary<int, string>(), 0.77f), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBwAAAApMb2FkRmFjdG9yB1ZlcnNpb24IQ29tcGFyZXIQSGFzaENvZGVQcm92aWRlcghIYXNoU2l6ZQRLZXlzBlZhbHVlcwAAAwMABQULCBxTeXN0ZW0uQ29sbGVjdGlvbnMuSUNvbXBhcmVyJFN5c3RlbS5Db2xsZWN0aW9ucy5JSGFzaENvZGVQcm92aWRlcggp7Q0/AAAAAAoKAwAAAAkCAAAACQMAAAAQAgAAAAAAAAAQAwAAAAAAAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBwAAAApMb2FkRmFjdG9yB1ZlcnNpb24IQ29tcGFyZXIQSGFzaENvZGVQcm92aWRlcghIYXNoU2l6ZQRLZXlzBlZhbHVlcwAAAwMABQULCBxTeXN0ZW0uQ29sbGVjdGlvbnMuSUNvbXBhcmVyJFN5c3RlbS5Db2xsZWN0aW9ucy5JSGFzaENvZGVQcm92aWRlcggp7Q0/AAAAAAoKAwAAAAkCAAAACQMAAAAQAgAAAAAAAAAQAwAAAAAAAAAL" } };
- yield return new object[] { new Hashtable(StringComparer.InvariantCultureIgnoreCase), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXII7FE4PwAAAAAJAgAAAAMAAAAJAwAAAAkEAAAABAIAAAAbU3lzdGVtLkN1bHR1cmVBd2FyZUNvbXBhcmVyAgAAAAxfY29tcGFyZUluZm8LX2lnbm9yZUNhc2UDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwEJBQAAAAEQAwAAAAAAAAAQBAAAAAAAAAAEBQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwMAAAAGbV9uYW1lDW1fU29ydFZlcnNpb24HY3VsdHVyZQEDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbggGBgAAAAAKfwAAAAs=", PlatformDetection.IsNetfx471OrNewer ? "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXII7FE4PwAAAAAJAgAAAAMAAAAJAwAAAAkEAAAABAIAAAAbU3lzdGVtLkN1bHR1cmVBd2FyZUNvbXBhcmVyAwAAAAxfY29tcGFyZUluZm8LX2lnbm9yZUNhc2UIX29wdGlvbnMDAAMgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8BI1N5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVPcHRpb25zCQUAAAABBPr///8jU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAEAAAAQAwAAAAAAAAAQBAAAAAAAAAAEBQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwQAAAAGbV9uYW1lCXdpbjMyTENJRAdjdWx0dXJlDW1fU29ydFZlcnNpb24BAAADCAggU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24GBwAAAAAAAAAAfwAAAAoL" : "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXII7FE4PwAAAAAJAgAAAAMAAAAJAwAAAAkEAAAABAIAAAAbU3lzdGVtLkN1bHR1cmVBd2FyZUNvbXBhcmVyAgAAAAxfY29tcGFyZUluZm8LX2lnbm9yZUNhc2UDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwEJBQAAAAEQAwAAAAAAAAAQBAAAAAAAAAAEBQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwQAAAAGbV9uYW1lCXdpbjMyTENJRAdjdWx0dXJlDW1fU29ydFZlcnNpb24BAAADCAggU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24GBgAAAAAAAAAAfwAAAAoL" } };
+ yield return new object[] { new List<int>(Enumerable.Range(0, 123).ToArray()), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkCAAAAewAAAAAAAAAPAgAAAHsAAAAIAAAAAAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAGwAAABwAAAAdAAAAHgAAAB8AAAAgAAAAIQAAACIAAAAjAAAAJAAAACUAAAAmAAAAJwAAACgAAAApAAAAKgAAACsAAAAsAAAALQAAAC4AAAAvAAAAMAAAADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAAADoAAAA7AAAAPAAAAD0AAAA+AAAAPwAAAEAAAABBAAAAQgAAAEMAAABEAAAARQAAAEYAAABHAAAASAAAAEkAAABKAAAASwAAAEwAAABNAAAATgAAAE8AAABQAAAAUQAAAFIAAABTAAAAVAAAAFUAAABWAAAAVwAAAFgAAABZAAAAWgAAAFsAAABcAAAAXQAAAF4AAABfAAAAYAAAAGEAAABiAAAAYwAAAGQAAABlAAAAZgAAAGcAAABoAAAAaQAAAGoAAABrAAAAbAAAAG0AAABuAAAAbwAAAHAAAABxAAAAcgAAAHMAAAB0AAAAdQAAAHYAAAB3AAAAeAAAAHkAAAB6AAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkCAAAAewAAAAAAAAAPAgAAAHsAAAAIAAAAAAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAGwAAABwAAAAdAAAAHgAAAB8AAAAgAAAAIQAAACIAAAAjAAAAJAAAACUAAAAmAAAAJwAAACgAAAApAAAAKgAAACsAAAAsAAAALQAAAC4AAAAvAAAAMAAAADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAAADoAAAA7AAAAPAAAAD0AAAA+AAAAPwAAAEAAAABBAAAAQgAAAEMAAABEAAAARQAAAEYAAABHAAAASAAAAEkAAABKAAAASwAAAEwAAABNAAAATgAAAE8AAABQAAAAUQAAAFIAAABTAAAAVAAAAFUAAABWAAAAVwAAAFgAAABZAAAAWgAAAFsAAABcAAAAXQAAAF4AAABfAAAAYAAAAGEAAABiAAAAYwAAAGQAAABlAAAAZgAAAGcAAABoAAAAaQAAAGoAAABrAAAAbAAAAG0AAABuAAAAbwAAAHAAAABxAAAAcgAAAHMAAAB0AAAAdQAAAHYAAAB3AAAAeAAAAHkAAAB6AAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new List<int>(new int[] { 5, 7, 9 }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkCAAAAAwAAAAAAAAAPAgAAAAMAAAAIBQAAAAcAAAAJAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkCAAAAAwAAAAAAAAAPAgAAAAMAAAAIBQAAAAcAAAAJAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new List<Point>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAEAAADKAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgQAADVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQIAAAAICAkDAAAAAAAAAAAAAAAHAwAAAAABAAAAAAAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAEAAADKAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgQAADVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQIAAAAICAkDAAAAAAAAAAAAAAAHAwAAAAABAAAAAAAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new List<Point>(new Point[] { new Point(1, 2), new Point(4, 3) }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAEAAADKAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgQAADVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQIAAAAICAkDAAAAAgAAAAAAAAAHAwAAAAABAAAAAgAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAkEAAAACQUAAAAFBAAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgCAAAAAQAAAAIAAAABBQAAAAQAAAAEAAAAAwAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAEAAADKAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgQAADVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQIAAAAICAkDAAAAAgAAAAAAAAAHAwAAAAABAAAAAgAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAkEAAAACQUAAAAFBAAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgCAAAAAQAAAAIAAAABBQAAAAQAAAAEAAAAAwAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new List<Tuple<int, Graph<int>>>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOQDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uAwAA9AJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dW10ICAkCAAAAAAAAAAAAAAAHAgAAAAABAAAAAAAAAAPyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0L", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOQDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uAwAA9AJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dW10ICAkCAAAAAAAAAAAAAAAHAgAAAAABAAAAAAAAAAPyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0L", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new List<Tuple<int, Graph<int>>>(new Tuple<int, Graph<int>>[] { Tuple.Create(1, new Graph<int>()), Tuple.Create(5, new Graph<int>()) }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOQDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uAwAA9AJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dW10ICAkCAAAAAgAAAAAAAAAHAgAAAAABAAAAAgAAAAPyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0JAwAAAAkEAAAADAUAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgQDAAAA8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAdtX0l0ZW0xB21fSXRlbTIABAiSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBQAAAAEAAAAJBgAAAAEEAAAAAwAAAAUAAAAJBwAAAAUGAAAAkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAFVmFsdWUFTGlua3MABAiUAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dW10FAAAABQAAAAAAAAAKAQcAAAAGAAAAAAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOQDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uAwAA9AJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dW10ICAkCAAAAAgAAAAAAAAAHAgAAAAABAAAAAgAAAAPyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0JAwAAAAkEAAAADAUAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgQDAAAA8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAdtX0l0ZW0xB21fSXRlbTIABAiSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBQAAAAEAAAAJBgAAAAEEAAAAAwAAAAUAAAAJBwAAAAUGAAAAkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAFVmFsdWUFTGlua3MABAiUAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dW10FAAAABQAAAAAAAAAKAQcAAAAGAAAAAAAAAAoL", TargetFrameworkMoniker.netfx461) } };
+
+ yield return new object[] { new Dictionary<int, int>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOABU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAB1ZlcnNpb24IQ29tcGFyZXIISGFzaFNpemUAAwAIkQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljRXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAAJAgAAAAAAAAAEAgAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOABU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAB1ZlcnNpb24IQ29tcGFyZXIISGFzaFNpemUAAwAIkQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljRXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAAJAgAAAAAAAAAEAgAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Dictionary<int, int>(4), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOABU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0EAAAAB1ZlcnNpb24IQ29tcGFyZXIISGFzaFNpemUNS2V5VmFsdWVQYWlycwADAAMIkQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljRXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCOQBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXVtdAAAAAAkCAAAABwAAAAkDAAAABAIAAACRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAABwMAAAAAAQAAAAAAAAAD4gFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOABU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0EAAAAB1ZlcnNpb24IQ29tcGFyZXIISGFzaFNpemUNS2V5VmFsdWVQYWlycwADAAMIkQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljRXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCOQBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXVtdAAAAAAkCAAAABwAAAAkDAAAABAIAAACRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAABwMAAAAAAQAAAAAAAAAD4gFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Dictionary<int, Point>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAKwCU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAwAAAAdWZXJzaW9uCENvbXBhcmVyCEhhc2hTaXplAAMACJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgAAAAACQIAAAAAAAAABAIAAACRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAKwCU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAwAAAAdWZXJzaW9uCENvbXBhcmVyCEhhc2hTaXplAAMACJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgAAAAACQIAAAAAAAAABAIAAACRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Dictionary<int, Tuple<int, Graph<int>>>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAMYEU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAdWZXJzaW9uCENvbXBhcmVyCEhhc2hTaXplAAMACJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgAAAAACQIAAAAAAAAABAIAAACRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAMYEU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAdWZXJzaW9uCENvbXBhcmVyCEhhc2hTaXplAAMACJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgAAAAACQIAAAAAAAAABAIAAACRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Dictionary<Tuple<int, Point>, Graph<int>>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAJIFU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAHVmVyc2lvbghDb21wYXJlcghIYXNoU2l6ZQADAAiXA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLk9iamVjdEVxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAAJAgAAAAAAAAAEAgAAAJcDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAJIFU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAHVmVyc2lvbghDb21wYXJlcghIYXNoU2l6ZQADAAiXA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLk9iamVjdEVxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAAJAgAAAAAAAAAEAgAAAJcDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Dictionary<string, string>() { { "a", "1" }, { "b", "2" } }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOIBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAHVmVyc2lvbghDb21wYXJlcghIYXNoU2l6ZQ1LZXlWYWx1ZVBhaXJzAAMAAwiSAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCOYBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dW10CAAAACQIAAAADAAAACQMAAAAEAgAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAABwMAAAAAAQAAAAIAAAAD5AFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0E/P///+QBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAANrZXkFdmFsdWUBAQYFAAAAAWEGBgAAAAExAfn////8////BggAAAABYgYJAAAAATIL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOIBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuRGljdGlvbmFyeWAyW1tTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAHVmVyc2lvbghDb21wYXJlcghIYXNoU2l6ZQ1LZXlWYWx1ZVBhaXJzAAMAAwiSAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCOYBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dW10CAAAACQIAAAADAAAACQMAAAAEAgAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAABwMAAAAAAQAAAAIAAAAD5AFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0E/P///+QBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAANrZXkFdmFsdWUBAQYFAAAAAWEGBgAAAAExAfn////8////BggAAAABYgYJAAAAATIL", TargetFrameworkMoniker.netfx461) } };
+
+ yield return new object[] { new CookieCollection(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAbU3lzdGVtLk5ldC5Db29raWVDb2xsZWN0aW9uBAAAAAZtX2xpc3QJbV92ZXJzaW9uC21fVGltZVN0YW1wFG1faGFzX290aGVyX3ZlcnNpb25zAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0CA0BAgAAAAkDAAAAAAAAAAAAAAAAAAAAAAQDAAAAHFN5c3RlbS5Db2xsZWN0aW9ucy5BcnJheUxpc3QDAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgUAAAgICQQAAAAAAAAAAAAAABAEAAAAAAAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAbU3lzdGVtLk5ldC5Db29raWVDb2xsZWN0aW9uBQAAAAltX3ZlcnNpb24GbV9saXN0C21fVGltZVN0YW1wFG1faGFzX290aGVyX3ZlcnNpb25zDG1fSXNSZWFkT25seQADAAAACBxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0DQEBAgAAAAAAAAAJAwAAAAAAAAAAAAAAAAEEAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkEAAAAAAAAAAAAAAAQBAAAAAAAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new System.Data.PropertyCollection(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5Qcm9wZXJ0eUNvbGxlY3Rpb24HAAAACkxvYWRGYWN0b3IHVmVyc2lvbghDb21wYXJlchBIYXNoQ29kZVByb3ZpZGVyCEhhc2hTaXplBEtleXMGVmFsdWVzAAADAwAFBQsIHFN5c3RlbS5Db2xsZWN0aW9ucy5JQ29tcGFyZXIkU3lzdGVtLkNvbGxlY3Rpb25zLklIYXNoQ29kZVByb3ZpZGVyCAIAAADsUTg/AAAAAAoKAwAAAAkDAAAACQQAAAAQAwAAAAAAAAAQBAAAAAAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uRGF0YSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAB5TeXN0ZW0uRGF0YS5Qcm9wZXJ0eUNvbGxlY3Rpb24HAAAACkxvYWRGYWN0b3IHVmVyc2lvbghDb21wYXJlchBIYXNoQ29kZVByb3ZpZGVyCEhhc2hTaXplBEtleXMGVmFsdWVzAAADAwAFBQsIHFN5c3RlbS5Db2xsZWN0aW9ucy5JQ29tcGFyZXIkU3lzdGVtLkNvbGxlY3Rpb25zLklIYXNoQ29kZVByb3ZpZGVyCAIAAADsUTg/AAAAAAoKAwAAAAkDAAAACQQAAAAQAwAAAAAAAAAQBAAAAAAAAAAL", TargetFrameworkMoniker.netfx461) } };
+
+ yield return new object[] { new ArrayList(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAAAAAAAAAAAAQAgAAAAAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAAAAAAAAAAAAQAgAAAAAAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new ArrayList(7), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAAAAAAAAAAAAQAgAAAAcAAAANBws=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAAAAAAAAAAAAQAgAAAAcAAAANBws=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new ArrayList(Enumerable.Range(0, 123).ToArray()), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAewAAAAEAAAAQAgAAAHsAAAAICAAAAAAICAEAAAAICAIAAAAICAMAAAAICAQAAAAICAUAAAAICAYAAAAICAcAAAAICAgAAAAICAkAAAAICAoAAAAICAsAAAAICAwAAAAICA0AAAAICA4AAAAICA8AAAAICBAAAAAICBEAAAAICBIAAAAICBMAAAAICBQAAAAICBUAAAAICBYAAAAICBcAAAAICBgAAAAICBkAAAAICBoAAAAICBsAAAAICBwAAAAICB0AAAAICB4AAAAICB8AAAAICCAAAAAICCEAAAAICCIAAAAICCMAAAAICCQAAAAICCUAAAAICCYAAAAICCcAAAAICCgAAAAICCkAAAAICCoAAAAICCsAAAAICCwAAAAICC0AAAAICC4AAAAICC8AAAAICDAAAAAICDEAAAAICDIAAAAICDMAAAAICDQAAAAICDUAAAAICDYAAAAICDcAAAAICDgAAAAICDkAAAAICDoAAAAICDsAAAAICDwAAAAICD0AAAAICD4AAAAICD8AAAAICEAAAAAICEEAAAAICEIAAAAICEMAAAAICEQAAAAICEUAAAAICEYAAAAICEcAAAAICEgAAAAICEkAAAAICEoAAAAICEsAAAAICEwAAAAICE0AAAAICE4AAAAICE8AAAAICFAAAAAICFEAAAAICFIAAAAICFMAAAAICFQAAAAICFUAAAAICFYAAAAICFcAAAAICFgAAAAICFkAAAAICFoAAAAICFsAAAAICFwAAAAICF0AAAAICF4AAAAICF8AAAAICGAAAAAICGEAAAAICGIAAAAICGMAAAAICGQAAAAICGUAAAAICGYAAAAICGcAAAAICGgAAAAICGkAAAAICGoAAAAICGsAAAAICGwAAAAICG0AAAAICG4AAAAICG8AAAAICHAAAAAICHEAAAAICHIAAAAICHMAAAAICHQAAAAICHUAAAAICHYAAAAICHcAAAAICHgAAAAICHkAAAAICHoAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAewAAAAEAAAAQAgAAAHsAAAAICAAAAAAICAEAAAAICAIAAAAICAMAAAAICAQAAAAICAUAAAAICAYAAAAICAcAAAAICAgAAAAICAkAAAAICAoAAAAICAsAAAAICAwAAAAICA0AAAAICA4AAAAICA8AAAAICBAAAAAICBEAAAAICBIAAAAICBMAAAAICBQAAAAICBUAAAAICBYAAAAICBcAAAAICBgAAAAICBkAAAAICBoAAAAICBsAAAAICBwAAAAICB0AAAAICB4AAAAICB8AAAAICCAAAAAICCEAAAAICCIAAAAICCMAAAAICCQAAAAICCUAAAAICCYAAAAICCcAAAAICCgAAAAICCkAAAAICCoAAAAICCsAAAAICCwAAAAICC0AAAAICC4AAAAICC8AAAAICDAAAAAICDEAAAAICDIAAAAICDMAAAAICDQAAAAICDUAAAAICDYAAAAICDcAAAAICDgAAAAICDkAAAAICDoAAAAICDsAAAAICDwAAAAICD0AAAAICD4AAAAICD8AAAAICEAAAAAICEEAAAAICEIAAAAICEMAAAAICEQAAAAICEUAAAAICEYAAAAICEcAAAAICEgAAAAICEkAAAAICEoAAAAICEsAAAAICEwAAAAICE0AAAAICE4AAAAICE8AAAAICFAAAAAICFEAAAAICFIAAAAICFMAAAAICFQAAAAICFUAAAAICFYAAAAICFcAAAAICFgAAAAICFkAAAAICFoAAAAICFsAAAAICFwAAAAICF0AAAAICF4AAAAICF8AAAAICGAAAAAICGEAAAAICGIAAAAICGMAAAAICGQAAAAICGUAAAAICGYAAAAICGcAAAAICGgAAAAICGkAAAAICGoAAAAICGsAAAAICGwAAAAICG0AAAAICG4AAAAICG8AAAAICHAAAAAICHEAAAAICHIAAAAICHMAAAAICHQAAAAICHUAAAAICHYAAAAICHcAAAAICHgAAAAICHkAAAAICHoAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new ArrayList(new int[] { 5, 7, 9 }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAAwAAAAEAAAAQAgAAAAMAAAAICAUAAAAICAcAAAAICAkAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAAwAAAAEAAAAQAgAAAAMAAAAICAUAAAAICAcAAAAICAkAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new ArrayList(new Point[] { new Point(1, 2), new Point(4, 3) }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAAgAAAAEAAAAQAgAAAAIAAAAJAwAAAAkEAAAADAUAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUDAAAAM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAIAAAABWAFZAAAICAUAAAABAAAAAgAAAAEEAAAAAwAAAAQAAAADAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAAgAAAAEAAAAQAgAAAAIAAAAJAwAAAAkEAAAADAUAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUDAAAAM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAIAAAABWAFZAAAICAUAAAABAAAAAgAAAAEEAAAAAwAAAAQAAAADAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new ArrayList(new Tuple<int, Graph<int>>[] { Tuple.Create(1, new Graph<int>()), Tuple.Create(5, new Graph<int>()) }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAAgAAAAEAAAAQAgAAAAIAAAAJAwAAAAkEAAAADAUAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgQDAAAA8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAdtX0l0ZW0xB21fSXRlbTIABAiSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBQAAAAEAAAAJBgAAAAEEAAAAAwAAAAUAAAAJBwAAAAUGAAAAkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAFVmFsdWUFTGlua3MABAiUAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dW10FAAAABQAAAAAAAAAKAQcAAAAGAAAAAAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAAgAAAAEAAAAQAgAAAAIAAAAJAwAAAAkEAAAADAUAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgQDAAAA8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAdtX0l0ZW0xB21fSXRlbTIABAiSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBQAAAAEAAAAJBgAAAAEEAAAAAwAAAAUAAAAJBwAAAAUGAAAAkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAFVmFsdWUFTGlua3MABAiUAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dW10FAAAABQAAAAAAAAAKAQcAAAAGAAAAAAAAAAoL", TargetFrameworkMoniker.netfx461) } };
+
+ yield return new object[] { new HashSet<int>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAIEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuSGFzaFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAdWZXJzaW9uCENvbXBhcmVyCENhcGFjaXR5AAMACJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgCAAAAAAAAAAkDAAAAAAAAAAQDAAAAkQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljRXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAIEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuSGFzaFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAdWZXJzaW9uCENvbXBhcmVyCENhcGFjaXR5AAMACJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgCAAAAAAAAAAkDAAAAAAAAAAQDAAAAkQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljRXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new HashSet<int>(Enumerable.Range(0, 123)), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAIEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuSGFzaFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAdWZXJzaW9uCENvbXBhcmVyCENhcGFjaXR5CEVsZW1lbnRzAAMABwiRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0ICAIAAAB7AAAACQMAAADFAAAACQQAAAAEAwAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAPBAAAAHsAAAAIAAAAAAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAGwAAABwAAAAdAAAAHgAAAB8AAAAgAAAAIQAAACIAAAAjAAAAJAAAACUAAAAmAAAAJwAAACgAAAApAAAAKgAAACsAAAAsAAAALQAAAC4AAAAvAAAAMAAAADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAAADoAAAA7AAAAPAAAAD0AAAA+AAAAPwAAAEAAAABBAAAAQgAAAEMAAABEAAAARQAAAEYAAABHAAAASAAAAEkAAABKAAAASwAAAEwAAABNAAAATgAAAE8AAABQAAAAUQAAAFIAAABTAAAAVAAAAFUAAABWAAAAVwAAAFgAAABZAAAAWgAAAFsAAABcAAAAXQAAAF4AAABfAAAAYAAAAGEAAABiAAAAYwAAAGQAAABlAAAAZgAAAGcAAABoAAAAaQAAAGoAAABrAAAAbAAAAG0AAABuAAAAbwAAAHAAAABxAAAAcgAAAHMAAAB0AAAAdQAAAHYAAAB3AAAAeAAAAHkAAAB6AAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAIEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuSGFzaFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAdWZXJzaW9uCENvbXBhcmVyCENhcGFjaXR5CEVsZW1lbnRzAAMABwiRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0ICAIAAAB7AAAACQMAAADFAAAACQQAAAAEAwAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAPBAAAAHsAAAAIAAAAAAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAGwAAABwAAAAdAAAAHgAAAB8AAAAgAAAAIQAAACIAAAAjAAAAJAAAACUAAAAmAAAAJwAAACgAAAApAAAAKgAAACsAAAAsAAAALQAAAC4AAAAvAAAAMAAAADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAAADoAAAA7AAAAPAAAAD0AAAA+AAAAPwAAAEAAAABBAAAAQgAAAEMAAABEAAAARQAAAEYAAABHAAAASAAAAEkAAABKAAAASwAAAEwAAABNAAAATgAAAE8AAABQAAAAUQAAAFIAAABTAAAAVAAAAFUAAABWAAAAVwAAAFgAAABZAAAAWgAAAFsAAABcAAAAXQAAAF4AAABfAAAAYAAAAGEAAABiAAAAYwAAAGQAAABlAAAAZgAAAGcAAABoAAAAaQAAAGoAAABrAAAAbAAAAG0AAABuAAAAbwAAAHAAAABxAAAAcgAAAHMAAAB0AAAAdQAAAHYAAAB3AAAAeAAAAHkAAAB6AAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new HashSet<int>(new int[] { 5, 7, 9 }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAIEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuSGFzaFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAdWZXJzaW9uCENvbXBhcmVyCENhcGFjaXR5CEVsZW1lbnRzAAMABwiRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0ICAIAAAADAAAACQMAAAADAAAACQQAAAAEAwAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAPBAAAAAMAAAAIBQAAAAcAAAAJAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAIEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuSGFzaFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAdWZXJzaW9uCENvbXBhcmVyCENhcGFjaXR5CEVsZW1lbnRzAAMABwiRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0ICAIAAAADAAAACQMAAAADAAAACQQAAAAEAwAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAPBAAAAAMAAAAIBQAAAAcAAAAJAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new HashSet<Point>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAM0BU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuSGFzaFNldGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAHVmVyc2lvbghDb21wYXJlcghDYXBhY2l0eQADAAjdAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCAIAAAAAAAAACQMAAAAAAAAABAMAAADdAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAAAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAM0BU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuSGFzaFNldGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAHVmVyc2lvbghDb21wYXJlcghDYXBhY2l0eQADAAjdAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCAIAAAAAAAAACQMAAAAAAAAABAMAAADdAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAAAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new HashSet<Point>(new Point[] { new Point(1, 2), new Point(4, 3) }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkMAwAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAADNAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkhhc2hTZXRgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0EAAAAB1ZlcnNpb24IQ29tcGFyZXIIQ2FwYWNpdHkIRWxlbWVudHMAAwAECN0BU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0INVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludFtdAwAAAAIAAAACAAAACQQAAAADAAAACQUAAAAEBAAAAN0BU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0AAAAABwUAAAAAAQAAAAIAAAAEM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAMAAAAJBgAAAAkHAAAABQYAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIAwAAAAEAAAACAAAAAQcAAAAGAAAABAAAAAMAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkMAwAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAADNAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkhhc2hTZXRgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0EAAAAB1ZlcnNpb24IQ29tcGFyZXIIQ2FwYWNpdHkIRWxlbWVudHMAAwAECN0BU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0INVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludFtdAwAAAAIAAAACAAAACQQAAAADAAAACQUAAAAEBAAAAN0BU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0AAAAABwUAAAAAAQAAAAIAAAAEM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAMAAAAJBgAAAAkHAAAABQYAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIAwAAAAEAAAACAAAAAQcAAAAGAAAABAAAAAMAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new HashSet<Tuple<int, Graph<int>>>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAOcDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuSGFzaFNldGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAHVmVyc2lvbghDb21wYXJlcghDYXBhY2l0eQADAAj2A1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLk9iamVjdEVxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IAgAAAAAAAAAJAwAAAAAAAAAEAwAAAPYDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAOcDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuSGFzaFNldGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAHVmVyc2lvbghDb21wYXJlcghDYXBhY2l0eQADAAj2A1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLk9iamVjdEVxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IAgAAAAAAAAAJAwAAAAAAAAAEAwAAAPYDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new HashSet<Tuple<int, Graph<int>>>(new Tuple<int, Graph<int>>[] { Tuple.Create(1, new Graph<int>()), Tuple.Create(5, new Graph<int>()) }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAOcDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuSGFzaFNldGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAHVmVyc2lvbghDb21wYXJlcghDYXBhY2l0eQhFbGVtZW50cwADAAMI9gNTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5PYmplY3RFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCPQCU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdAgAAAAIAAAAJAwAAAAMAAAAJBAAAAAQDAAAA9gNTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5PYmplY3RFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAcEAAAAAAEAAAACAAAAA/ICU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQkFAAAACQYAAAAMBwAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAUAAADyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAB21fSXRlbTEHbV9JdGVtMgAECJIBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0HAAAAAQAAAAkIAAAAAQYAAAAFAAAABQAAAAkJAAAABQgAAACSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAVWYWx1ZQVMaW5rcwAECJQBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV1bXQcAAAAHAAAAAAAAAAoBCQAAAAgAAAAAAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAAOcDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuSGFzaFNldGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAHVmVyc2lvbghDb21wYXJlcghDYXBhY2l0eQhFbGVtZW50cwADAAMI9gNTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5PYmplY3RFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCPQCU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdAgAAAAIAAAAJAwAAAAMAAAAJBAAAAAQDAAAA9gNTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5PYmplY3RFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAcEAAAAAAEAAAACAAAAA/ICU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQkFAAAACQYAAAAMBwAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAUAAADyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAB21fSXRlbTEHbV9JdGVtMgAECJIBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0HAAAAAQAAAAkIAAAAAQYAAAAFAAAABQAAAAkJAAAABQgAAACSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAVWYWx1ZQVMaW5rcwAECJQBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV1bXQcAAAAHAAAAAAAAAAoBCQAAAAgAAAAAAAAACgs=", TargetFrameworkMoniker.netfx461) } };
+
+ yield return new object[] { new LinkedList<int>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACEAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpbmtlZExpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAHVmVyc2lvbgVDb3VudAAACAgCAAAAAAAAAAAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACEAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpbmtlZExpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAHVmVyc2lvbgVDb3VudAAACAgCAAAAAAAAAAAAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new LinkedList<int>(Enumerable.Range(0, 123)), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACEAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpbmtlZExpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAHVmVyc2lvbgVDb3VudAREYXRhAAAHCAgIAgAAAHsAAAB7AAAACQMAAAAPAwAAAHsAAAAIAAAAAAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAGwAAABwAAAAdAAAAHgAAAB8AAAAgAAAAIQAAACIAAAAjAAAAJAAAACUAAAAmAAAAJwAAACgAAAApAAAAKgAAACsAAAAsAAAALQAAAC4AAAAvAAAAMAAAADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAAADoAAAA7AAAAPAAAAD0AAAA+AAAAPwAAAEAAAABBAAAAQgAAAEMAAABEAAAARQAAAEYAAABHAAAASAAAAEkAAABKAAAASwAAAEwAAABNAAAATgAAAE8AAABQAAAAUQAAAFIAAABTAAAAVAAAAFUAAABWAAAAVwAAAFgAAABZAAAAWgAAAFsAAABcAAAAXQAAAF4AAABfAAAAYAAAAGEAAABiAAAAYwAAAGQAAABlAAAAZgAAAGcAAABoAAAAaQAAAGoAAABrAAAAbAAAAG0AAABuAAAAbwAAAHAAAABxAAAAcgAAAHMAAAB0AAAAdQAAAHYAAAB3AAAAeAAAAHkAAAB6AAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACEAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpbmtlZExpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAHVmVyc2lvbgVDb3VudAREYXRhAAAHCAgIAgAAAHsAAAB7AAAACQMAAAAPAwAAAHsAAAAIAAAAAAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAGwAAABwAAAAdAAAAHgAAAB8AAAAgAAAAIQAAACIAAAAjAAAAJAAAACUAAAAmAAAAJwAAACgAAAApAAAAKgAAACsAAAAsAAAALQAAAC4AAAAvAAAAMAAAADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAAADoAAAA7AAAAPAAAAD0AAAA+AAAAPwAAAEAAAABBAAAAQgAAAEMAAABEAAAARQAAAEYAAABHAAAASAAAAEkAAABKAAAASwAAAEwAAABNAAAATgAAAE8AAABQAAAAUQAAAFIAAABTAAAAVAAAAFUAAABWAAAAVwAAAFgAAABZAAAAWgAAAFsAAABcAAAAXQAAAF4AAABfAAAAYAAAAGEAAABiAAAAYwAAAGQAAABlAAAAZgAAAGcAAABoAAAAaQAAAGoAAABrAAAAbAAAAG0AAABuAAAAbwAAAHAAAABxAAAAcgAAAHMAAAB0AAAAdQAAAHYAAAB3AAAAeAAAAHkAAAB6AAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new LinkedList<int>(new int[] { 5, 7, 9 }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACEAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpbmtlZExpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAHVmVyc2lvbgVDb3VudAREYXRhAAAHCAgIAgAAAAMAAAADAAAACQMAAAAPAwAAAAMAAAAIBQAAAAcAAAAJAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACEAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpbmtlZExpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAHVmVyc2lvbgVDb3VudAREYXRhAAAHCAgIAgAAAAMAAAADAAAACQMAAAAPAwAAAAMAAAAIBQAAAAcAAAAJAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new LinkedList<Point>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADQAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpbmtlZExpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAB1ZlcnNpb24FQ291bnQAAAgIAgAAAAAAAAAAAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADQAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpbmtlZExpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAB1ZlcnNpb24FQ291bnQAAAgIAgAAAAAAAAAAAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new LinkedList<Point>(new Point[] { new Point(1, 2), new Point(4, 3) }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAA0AFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaW5rZWRMaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAwAAAAdWZXJzaW9uBUNvdW50BERhdGEAAAQICDVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQMAAAACAAAAAgAAAAIAAAAJBAAAAAcEAAAAAAEAAAACAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQDAAAACQUAAAAJBgAAAAUFAAAAM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAIAAAABWAFZAAAICAMAAAABAAAAAgAAAAEGAAAABQAAAAQAAAADAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAA0AFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaW5rZWRMaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAwAAAAdWZXJzaW9uBUNvdW50BERhdGEAAAQICDVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQMAAAACAAAAAgAAAAIAAAAJBAAAAAcEAAAAAAEAAAACAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQDAAAACQUAAAAJBgAAAAUFAAAAM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAIAAAABWAFZAAAICAMAAAABAAAAAgAAAAEGAAAABQAAAAQAAAADAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new LinkedList<Tuple<int, Graph<int>>>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADqA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpbmtlZExpc3RgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAAB1ZlcnNpb24FQ291bnQAAAgIAgAAAAAAAAAAAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADqA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpbmtlZExpc3RgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAAB1ZlcnNpb24FQ291bnQAAAgIAgAAAAAAAAAAAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new LinkedList<Tuple<int, Graph<int>>>(new Tuple<int, Graph<int>>[] { Tuple.Create(1, new Graph<int>()), Tuple.Create(5, new Graph<int>()) }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADqA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpbmtlZExpc3RgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAB1ZlcnNpb24FQ291bnQERGF0YQAAAwgI9AJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dW10CAAAAAgAAAAIAAAAJAwAAAAcDAAAAAAEAAAACAAAAA/ICU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQkEAAAACQUAAAAMBgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAQAAADyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAB21fSXRlbTEHbV9JdGVtMgAECJIBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0GAAAAAQAAAAkHAAAAAQUAAAAEAAAABQAAAAkIAAAABQcAAACSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAVWYWx1ZQVMaW5rcwAECJQBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV1bXQYAAAAGAAAAAAAAAAoBCAAAAAcAAAAAAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADqA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpbmtlZExpc3RgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAB1ZlcnNpb24FQ291bnQERGF0YQAAAwgI9AJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dW10CAAAAAgAAAAIAAAAJAwAAAAcDAAAAAAEAAAACAAAAA/ICU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQkEAAAACQUAAAAMBgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAQAAADyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAB21fSXRlbTEHbV9JdGVtMgAECJIBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0GAAAAAQAAAAkHAAAAAQUAAAAEAAAABQAAAAkIAAAABQcAAACSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAVWYWx1ZQVMaW5rcwAECJQBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV1bXQYAAAAGAAAAAAAAAAoBCAAAAAcAAAAAAAAACgs=", TargetFrameworkMoniker.netfx461) } };
+
+ yield return new object[] { new Queue(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAAAAADIAAAAAAAAABACAAAAIAAAAA0gCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAAAAADIAAAAAAAAABACAAAAIAAAAA0gCw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Queue(5), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAAAAADIAAAAAAAAABACAAAABQAAAA0FCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAAAAADIAAAAAAAAABACAAAABQAAAA0FCw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Queue(7, 2.2f), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAAAAADcAAAAAAAAABACAAAABwAAAA0HCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAAAAADcAAAAAAAAABACAAAABwAAAA0HCw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Queue(Enumerable.Range(0, 123).ToArray()), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAHsAAADIAAAAewAAABACAAAAewAAAAgIAAAAAAgIAQAAAAgIAgAAAAgIAwAAAAgIBAAAAAgIBQAAAAgIBgAAAAgIBwAAAAgICAAAAAgICQAAAAgICgAAAAgICwAAAAgIDAAAAAgIDQAAAAgIDgAAAAgIDwAAAAgIEAAAAAgIEQAAAAgIEgAAAAgIEwAAAAgIFAAAAAgIFQAAAAgIFgAAAAgIFwAAAAgIGAAAAAgIGQAAAAgIGgAAAAgIGwAAAAgIHAAAAAgIHQAAAAgIHgAAAAgIHwAAAAgIIAAAAAgIIQAAAAgIIgAAAAgIIwAAAAgIJAAAAAgIJQAAAAgIJgAAAAgIJwAAAAgIKAAAAAgIKQAAAAgIKgAAAAgIKwAAAAgILAAAAAgILQAAAAgILgAAAAgILwAAAAgIMAAAAAgIMQAAAAgIMgAAAAgIMwAAAAgINAAAAAgINQAAAAgINgAAAAgINwAAAAgIOAAAAAgIOQAAAAgIOgAAAAgIOwAAAAgIPAAAAAgIPQAAAAgIPgAAAAgIPwAAAAgIQAAAAAgIQQAAAAgIQgAAAAgIQwAAAAgIRAAAAAgIRQAAAAgIRgAAAAgIRwAAAAgISAAAAAgISQAAAAgISgAAAAgISwAAAAgITAAAAAgITQAAAAgITgAAAAgITwAAAAgIUAAAAAgIUQAAAAgIUgAAAAgIUwAAAAgIVAAAAAgIVQAAAAgIVgAAAAgIVwAAAAgIWAAAAAgIWQAAAAgIWgAAAAgIWwAAAAgIXAAAAAgIXQAAAAgIXgAAAAgIXwAAAAgIYAAAAAgIYQAAAAgIYgAAAAgIYwAAAAgIZAAAAAgIZQAAAAgIZgAAAAgIZwAAAAgIaAAAAAgIaQAAAAgIagAAAAgIawAAAAgIbAAAAAgIbQAAAAgIbgAAAAgIbwAAAAgIcAAAAAgIcQAAAAgIcgAAAAgIcwAAAAgIdAAAAAgIdQAAAAgIdgAAAAgIdwAAAAgIeAAAAAgIeQAAAAgIegAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAHsAAADIAAAAewAAABACAAAAewAAAAgIAAAAAAgIAQAAAAgIAgAAAAgIAwAAAAgIBAAAAAgIBQAAAAgIBgAAAAgIBwAAAAgICAAAAAgICQAAAAgICgAAAAgICwAAAAgIDAAAAAgIDQAAAAgIDgAAAAgIDwAAAAgIEAAAAAgIEQAAAAgIEgAAAAgIEwAAAAgIFAAAAAgIFQAAAAgIFgAAAAgIFwAAAAgIGAAAAAgIGQAAAAgIGgAAAAgIGwAAAAgIHAAAAAgIHQAAAAgIHgAAAAgIHwAAAAgIIAAAAAgIIQAAAAgIIgAAAAgIIwAAAAgIJAAAAAgIJQAAAAgIJgAAAAgIJwAAAAgIKAAAAAgIKQAAAAgIKgAAAAgIKwAAAAgILAAAAAgILQAAAAgILgAAAAgILwAAAAgIMAAAAAgIMQAAAAgIMgAAAAgIMwAAAAgINAAAAAgINQAAAAgINgAAAAgINwAAAAgIOAAAAAgIOQAAAAgIOgAAAAgIOwAAAAgIPAAAAAgIPQAAAAgIPgAAAAgIPwAAAAgIQAAAAAgIQQAAAAgIQgAAAAgIQwAAAAgIRAAAAAgIRQAAAAgIRgAAAAgIRwAAAAgISAAAAAgISQAAAAgISgAAAAgISwAAAAgITAAAAAgITQAAAAgITgAAAAgITwAAAAgIUAAAAAgIUQAAAAgIUgAAAAgIUwAAAAgIVAAAAAgIVQAAAAgIVgAAAAgIVwAAAAgIWAAAAAgIWQAAAAgIWgAAAAgIWwAAAAgIXAAAAAgIXQAAAAgIXgAAAAgIXwAAAAgIYAAAAAgIYQAAAAgIYgAAAAgIYwAAAAgIZAAAAAgIZQAAAAgIZgAAAAgIZwAAAAgIaAAAAAgIaQAAAAgIagAAAAgIawAAAAgIbAAAAAgIbQAAAAgIbgAAAAgIbwAAAAgIcAAAAAgIcQAAAAgIcgAAAAgIcwAAAAgIdAAAAAgIdQAAAAgIdgAAAAgIdwAAAAgIeAAAAAgIeQAAAAgIegAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Queue(new int[] { 5, 7, 9 }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAMAAADIAAAAAwAAABACAAAAAwAAAAgIBQAAAAgIBwAAAAgICQAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAMAAADIAAAAAwAAABACAAAAAwAAAAgIBQAAAAgIBwAAAAgICQAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Queue(new Point[] { new Point(1, 2), new Point(4, 3) }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAIAAADIAAAAAgAAABACAAAAAgAAAAkDAAAACQQAAAAMBQAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQMAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIBQAAAAEAAAACAAAAAQQAAAADAAAABAAAAAMAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAIAAADIAAAAAgAAABACAAAAAgAAAAkDAAAACQQAAAAMBQAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQMAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIBQAAAAEAAAACAAAAAQQAAAADAAAABAAAAAMAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Queue(new Tuple<int, Graph<int>>[] { Tuple.Create(1, new Graph<int>()), Tuple.Create(5, new Graph<int>()) }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAIAAADIAAAAAgAAABACAAAAAgAAAAkDAAAACQQAAAAMBQAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAMAAADyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAB21fSXRlbTEHbV9JdGVtMgAECJIBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0FAAAAAQAAAAkGAAAAAQQAAAADAAAABQAAAAkHAAAABQYAAACSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAVWYWx1ZQVMaW5rcwAECJQBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV1bXQUAAAAFAAAAAAAAAAoBBwAAAAYAAAAAAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAIAAADIAAAAAgAAABACAAAAAgAAAAkDAAAACQQAAAAMBQAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAMAAADyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAB21fSXRlbTEHbV9JdGVtMgAECJIBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0FAAAAAQAAAAkGAAAAAQQAAAADAAAABQAAAAkHAAAABQYAAACSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAVWYWx1ZQVMaW5rcwAECJQBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV1bXQUAAAAFAAAAAAAAAAoBBwAAAAYAAAAAAAAACgs=", TargetFrameworkMoniker.netfx461) } };
+
+ yield return new object[] { new SortedDictionary<int, int>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADmAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAARfc2V0BNcCU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuVHJlZVNldGAxW1tTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAACAAAACQMAAAAMBAAAAFVTeXN0ZW0uQ29sbGVjdGlvbnMsIFZlcnNpb249NC4xLjEuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQMAAADXAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlRyZWVTZXRgMVtbU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABUNvdW50CENvbXBhcmVyB1ZlcnNpb24ABAAI+wFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWREaWN0aW9uYXJ5YDIrS2V5VmFsdWVQYWlyQ29tcGFyZXJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAIAgAAAAAAAAAJBQAAAAAAAAAFBQAAAPsBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuU29ydGVkRGljdGlvbmFyeWAyK0tleVZhbHVlUGFpckNvbXBhcmVyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAAC2tleUNvbXBhcmVyA4kBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0EAAAACQYAAAAEBgAAAIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADmAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAARfc2V0BNcCU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuVHJlZVNldGAxW1tTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAACAAAACQMAAAAFAwAAANcCU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuVHJlZVNldGAxW1tTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgAEAAj7AVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMitLZXlWYWx1ZVBhaXJDb21wYXJlcltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAgCAAAAAAAAAAkEAAAAAAAAAAUEAAAA+wFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWREaWN0aW9uYXJ5YDIrS2V5VmFsdWVQYWlyQ29tcGFyZXJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAALa2V5Q29tcGFyZXIDiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAJBQAAAAQFAAAAiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SortedDictionary<int, int>(Comparer<int>.Default), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADmAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAARfc2V0BNcCU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuVHJlZVNldGAxW1tTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAACAAAACQMAAAAMBAAAAFVTeXN0ZW0uQ29sbGVjdGlvbnMsIFZlcnNpb249NC4xLjEuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQMAAADXAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlRyZWVTZXRgMVtbU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABUNvdW50CENvbXBhcmVyB1ZlcnNpb24ABAAI+wFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWREaWN0aW9uYXJ5YDIrS2V5VmFsdWVQYWlyQ29tcGFyZXJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAIAgAAAAAAAAAJBQAAAAAAAAAFBQAAAPsBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuU29ydGVkRGljdGlvbmFyeWAyK0tleVZhbHVlUGFpckNvbXBhcmVyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAAC2tleUNvbXBhcmVyA4kBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0EAAAACQYAAAAEBgAAAIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADmAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAARfc2V0BNcCU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuVHJlZVNldGAxW1tTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAACAAAACQMAAAAFAwAAANcCU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuVHJlZVNldGAxW1tTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgAEAAj7AVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMitLZXlWYWx1ZVBhaXJDb21wYXJlcltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAgCAAAAAAAAAAkEAAAAAAAAAAUEAAAA+wFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWREaWN0aW9uYXJ5YDIrS2V5VmFsdWVQYWlyQ29tcGFyZXJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAALa2V5Q29tcGFyZXIDiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAJBQAAAAQFAAAAiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SortedDictionary<int, Point>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACyAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQEAAAAEX3NldASjA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlRyZWVTZXRgMVtbU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAIAAAAJAwAAAAwEAAAAVVN5c3RlbS5Db2xsZWN0aW9ucywgVmVyc2lvbj00LjEuMS4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAwAAAKMDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuVHJlZVNldGAxW1tTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABUNvdW50CENvbXBhcmVyB1ZlcnNpb24ABAAIxwJTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWREaWN0aW9uYXJ5YDIrS2V5VmFsdWVQYWlyQ29tcGFyZXJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0EAAAACAIAAAAAAAAACQUAAAAAAAAABQUAAADHAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMitLZXlWYWx1ZVBhaXJDb21wYXJlcltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQEAAAALa2V5Q29tcGFyZXIDiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAJBgAAAAQGAAAAiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACyAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQEAAAAEX3NldASjA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlRyZWVTZXRgMVtbU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAIAAAAJAwAAAAUDAAAAowNTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5UcmVlU2V0YDFbW1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgAEAAjHAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMitLZXlWYWx1ZVBhaXJDb21wYXJlcltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQIAAAAIAgAAAAAAAAAJBAAAAAAAAAAFBAAAAMcCU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuU29ydGVkRGljdGlvbmFyeWAyK0tleVZhbHVlUGFpckNvbXBhcmVyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAQAAAAtrZXlDb21wYXJlcgOJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAkFAAAABAUAAACJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SortedDictionary<int, Tuple<int, Graph<int>>>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADMBFN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAEX3NldAS9BVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlRyZWVTZXRgMVtbU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAIAAAAJAwAAAAwEAAAAVVN5c3RlbS5Db2xsZWN0aW9ucywgVmVyc2lvbj00LjEuMS4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAwAAAL0FU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuVHJlZVNldGAxW1tTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABUNvdW50CENvbXBhcmVyB1ZlcnNpb24ABAAI4QRTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWREaWN0aW9uYXJ5YDIrS2V5VmFsdWVQYWlyQ29tcGFyZXJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0EAAAACAIAAAAAAAAACQUAAAAAAAAABQUAAADhBFN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMitLZXlWYWx1ZVBhaXJDb21wYXJlcltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAALa2V5Q29tcGFyZXIDiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAJBgAAAAQGAAAAiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADMBFN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAEX3NldAS9BVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlRyZWVTZXRgMVtbU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAIAAAAJAwAAAAUDAAAAvQVTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5UcmVlU2V0YDFbW1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgAEAAjhBFN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMitLZXlWYWx1ZVBhaXJDb21wYXJlcltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAIAgAAAAAAAAAJBAAAAAAAAAAFBAAAAOEEU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuU29ydGVkRGljdGlvbmFyeWAyK0tleVZhbHVlUGFpckNvbXBhcmVyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAAtrZXlDb21wYXJlcgOJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAkFAAAABAUAAACJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SortedDictionary<Tuple<int, Point>, Graph<int>>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACYBVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMltbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0BAAAABF9zZXQEiQZTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5UcmVlU2V0YDFbW1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAAAgAAAAkDAAAADAQAAABVU3lzdGVtLkNvbGxlY3Rpb25zLCBWZXJzaW9uPTQuMS4xLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUDAAAAiQZTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5UcmVlU2V0YDFbW1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABUNvdW50CENvbXBhcmVyB1ZlcnNpb24ABAAIrQVTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWREaWN0aW9uYXJ5YDIrS2V5VmFsdWVQYWlyQ29tcGFyZXJbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dBAAAAAgCAAAAAAAAAAkFAAAAAAAAAAUFAAAArQVTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWREaWN0aW9uYXJ5YDIrS2V5VmFsdWVQYWlyQ29tcGFyZXJbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAQAAAAtrZXlDb21wYXJlcgOPA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLk9iamVjdENvbXBhcmVyYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAJBgAAAAQGAAAAjwNTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5PYmplY3RDb21wYXJlcmAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACYBVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMltbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0BAAAABF9zZXQEiQZTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5UcmVlU2V0YDFbW1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAAAgAAAAkDAAAABQMAAACJBlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlRyZWVTZXRgMVtbU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgAEAAitBVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMitLZXlWYWx1ZVBhaXJDb21wYXJlcltbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAACAIAAAAAAAAACQQAAAAAAAAABQQAAACtBVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMitLZXlWYWx1ZVBhaXJDb21wYXJlcltbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0BAAAAC2tleUNvbXBhcmVyA48DU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0Q29tcGFyZXJgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAkFAAAABAUAAACPA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLk9iamVjdENvbXBhcmVyYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL", TargetFrameworkMoniker.netfx461) } };
+
+ yield return new object[] { new SortedList(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdAcAAAAEa2V5cwZ2YWx1ZXMFX3NpemUHdmVyc2lvbghjb21wYXJlcgdrZXlMaXN0CXZhbHVlTGlzdAUFAAADAwMICBtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXIlU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QrS2V5TGlzdCdTeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdCtWYWx1ZUxpc3QJAgAAAAkCAAAAAAAAAAAAAAAJAwAAAAoKEAIAAAAAAAAABAMAAAAbU3lzdGVtLkNvbGxlY3Rpb25zLkNvbXBhcmVyAQAAAAtDb21wYXJlSW5mbwMgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8JBAAAAAQEAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvAwAAAAZtX25hbWUNbV9Tb3J0VmVyc2lvbgdjdWx0dXJlAQMAIFN5c3RlbS5HbG9iYWxpemF0aW9uLlNvcnRWZXJzaW9uCAYFAAAAAAp/AAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdAcAAAAEa2V5cwZ2YWx1ZXMFX3NpemUHdmVyc2lvbghjb21wYXJlcgdrZXlMaXN0CXZhbHVlTGlzdAUFAAADAwMICBtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXIlU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QrS2V5TGlzdCdTeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdCtWYWx1ZUxpc3QJAgAAAAkCAAAAAAAAAAAAAAAJAwAAAAoKEAIAAAAAAAAABAMAAAAbU3lzdGVtLkNvbGxlY3Rpb25zLkNvbXBhcmVyAQAAAAtDb21wYXJlSW5mbwMgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8JBAAAAAQEAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvBAAAAAZtX25hbWUJd2luMzJMQ0lEB2N1bHR1cmUNbV9Tb3J0VmVyc2lvbgEAAAMICCBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbgYFAAAAAAAAAAB/AAAACgs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SortedList(Comparer.DefaultInvariant), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdAcAAAAEa2V5cwZ2YWx1ZXMFX3NpemUHdmVyc2lvbghjb21wYXJlcgdrZXlMaXN0CXZhbHVlTGlzdAUFAAADAwMICBtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXIlU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QrS2V5TGlzdCdTeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdCtWYWx1ZUxpc3QJAgAAAAkCAAAAAAAAAAAAAAAJAwAAAAoKEAIAAAAAAAAABAMAAAAbU3lzdGVtLkNvbGxlY3Rpb25zLkNvbXBhcmVyAQAAAAtDb21wYXJlSW5mbwMgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8JBAAAAAQEAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvAwAAAAZtX25hbWUNbV9Tb3J0VmVyc2lvbgdjdWx0dXJlAQMAIFN5c3RlbS5HbG9iYWxpemF0aW9uLlNvcnRWZXJzaW9uCAYFAAAAAAp/AAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdAcAAAAEa2V5cwZ2YWx1ZXMFX3NpemUHdmVyc2lvbghjb21wYXJlcgdrZXlMaXN0CXZhbHVlTGlzdAUFAAADAwMICBtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXIlU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QrS2V5TGlzdCdTeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdCtWYWx1ZUxpc3QJAgAAAAkCAAAAAAAAAAAAAAAJAwAAAAoKEAIAAAAAAAAABAMAAAAbU3lzdGVtLkNvbGxlY3Rpb25zLkNvbXBhcmVyAQAAAAtDb21wYXJlSW5mbwMgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8JBAAAAAQEAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvBAAAAAZtX25hbWUJd2luMzJMQ0lEB2N1bHR1cmUNbV9Tb3J0VmVyc2lvbgEAAAMICCBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbgYFAAAAAAAAAAB/AAAACgs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SortedList(Comparer.DefaultInvariant, 4), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdAcAAAAEa2V5cwZ2YWx1ZXMFX3NpemUHdmVyc2lvbghjb21wYXJlcgdrZXlMaXN0CXZhbHVlTGlzdAUFAAADAwMICBtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXIlU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QrS2V5TGlzdCdTeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdCtWYWx1ZUxpc3QJAgAAAAkDAAAAAAAAAAAAAAAJBAAAAAoKEAIAAAAEAAAADQQQAwAAAAQAAAANBAQEAAAAG1N5c3RlbS5Db2xsZWN0aW9ucy5Db21wYXJlcgEAAAALQ29tcGFyZUluZm8DIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCQUAAAAEBQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwMAAAAGbV9uYW1lDW1fU29ydFZlcnNpb24HY3VsdHVyZQEDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbggGBgAAAAAKfwAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdAcAAAAEa2V5cwZ2YWx1ZXMFX3NpemUHdmVyc2lvbghjb21wYXJlcgdrZXlMaXN0CXZhbHVlTGlzdAUFAAADAwMICBtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXIlU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QrS2V5TGlzdCdTeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdCtWYWx1ZUxpc3QJAgAAAAkDAAAAAAAAAAAAAAAJBAAAAAoKEAIAAAAEAAAADQQQAwAAAAQAAAANBAQEAAAAG1N5c3RlbS5Db2xsZWN0aW9ucy5Db21wYXJlcgEAAAALQ29tcGFyZUluZm8DIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCQUAAAAEBQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwQAAAAGbV9uYW1lCXdpbjMyTENJRAdjdWx0dXJlDW1fU29ydFZlcnNpb24BAAADCAggU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24GBgAAAAAAAAAAfwAAAAoL", TargetFrameworkMoniker.netfx461) } };
+
+ yield return new object[] { new SortedSet<int>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACDAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAVDb3VudAhDb21wYXJlcgdWZXJzaW9uAAMACIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IAgAAAAAAAAAJAwAAAAAAAAAEAwAAAIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACDAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAVDb3VudAhDb21wYXJlcgdWZXJzaW9uAAMACIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IAgAAAAAAAAAJAwAAAAAAAAAEAwAAAIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SortedSet<int>(Comparer<int>.Default), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACDAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAVDb3VudAhDb21wYXJlcgdWZXJzaW9uAAMACIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IAgAAAAAAAAAJAwAAAAAAAAAEAwAAAIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACDAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAVDb3VudAhDb21wYXJlcgdWZXJzaW9uAAMACIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IAgAAAAAAAAAJAwAAAAAAAAAEAwAAAIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SortedSet<int>(Enumerable.Range(0, 123)), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACDAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAVDb3VudAhDb21wYXJlcgdWZXJzaW9uBUl0ZW1zAAMABwiJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAgCAAAAewAAAAkDAAAAAAAAAAkEAAAABAMAAACJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAA8EAAAAewAAAAgAAAAAAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAASAAAAEwAAABQAAAAVAAAAFgAAABcAAAAYAAAAGQAAABoAAAAbAAAAHAAAAB0AAAAeAAAAHwAAACAAAAAhAAAAIgAAACMAAAAkAAAAJQAAACYAAAAnAAAAKAAAACkAAAAqAAAAKwAAACwAAAAtAAAALgAAAC8AAAAwAAAAMQAAADIAAAAzAAAANAAAADUAAAA2AAAANwAAADgAAAA5AAAAOgAAADsAAAA8AAAAPQAAAD4AAAA/AAAAQAAAAEEAAABCAAAAQwAAAEQAAABFAAAARgAAAEcAAABIAAAASQAAAEoAAABLAAAATAAAAE0AAABOAAAATwAAAFAAAABRAAAAUgAAAFMAAABUAAAAVQAAAFYAAABXAAAAWAAAAFkAAABaAAAAWwAAAFwAAABdAAAAXgAAAF8AAABgAAAAYQAAAGIAAABjAAAAZAAAAGUAAABmAAAAZwAAAGgAAABpAAAAagAAAGsAAABsAAAAbQAAAG4AAABvAAAAcAAAAHEAAAByAAAAcwAAAHQAAAB1AAAAdgAAAHcAAAB4AAAAeQAAAHoAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACDAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAVDb3VudAhDb21wYXJlcgdWZXJzaW9uBUl0ZW1zAAMABwiJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAgCAAAAewAAAAkDAAAAAAAAAAkEAAAABAMAAACJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAA8EAAAAewAAAAgAAAAAAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAASAAAAEwAAABQAAAAVAAAAFgAAABcAAAAYAAAAGQAAABoAAAAbAAAAHAAAAB0AAAAeAAAAHwAAACAAAAAhAAAAIgAAACMAAAAkAAAAJQAAACYAAAAnAAAAKAAAACkAAAAqAAAAKwAAACwAAAAtAAAALgAAAC8AAAAwAAAAMQAAADIAAAAzAAAANAAAADUAAAA2AAAANwAAADgAAAA5AAAAOgAAADsAAAA8AAAAPQAAAD4AAAA/AAAAQAAAAEEAAABCAAAAQwAAAEQAAABFAAAARgAAAEcAAABIAAAASQAAAEoAAABLAAAATAAAAE0AAABOAAAATwAAAFAAAABRAAAAUgAAAFMAAABUAAAAVQAAAFYAAABXAAAAWAAAAFkAAABaAAAAWwAAAFwAAABdAAAAXgAAAF8AAABgAAAAYQAAAGIAAABjAAAAZAAAAGUAAABmAAAAZwAAAGgAAABpAAAAagAAAGsAAABsAAAAbQAAAG4AAABvAAAAcAAAAHEAAAByAAAAcwAAAHQAAAB1AAAAdgAAAHcAAAB4AAAAeQAAAHoAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SortedSet<int>(new int[] { 5, 7, 9 }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACDAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAVDb3VudAhDb21wYXJlcgdWZXJzaW9uBUl0ZW1zAAMABwiJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAgCAAAAAwAAAAkDAAAAAAAAAAkEAAAABAMAAACJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAA8EAAAAAwAAAAgFAAAABwAAAAkAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACDAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAVDb3VudAhDb21wYXJlcgdWZXJzaW9uBUl0ZW1zAAMABwiJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAgCAAAAAwAAAAkDAAAAAAAAAAkEAAAABAMAAACJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAA8EAAAAAwAAAAgFAAAABwAAAAkAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SortedSet<Point>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADPAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgADAAjVAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQgCAAAAAAAAAAkDAAAAAAAAAAQDAAAA1QFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0AAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADPAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgADAAjVAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQgCAAAAAAAAAAkDAAAAAAAAAAQDAAAA1QFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0AAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SortedSet<Point>(Comparer<Point>.Default), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADPAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgADAAjVAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQgCAAAAAAAAAAkDAAAAAAAAAAQDAAAA1QFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0AAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADPAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgADAAjVAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQgCAAAAAAAAAAkDAAAAAAAAAAQDAAAA1QFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0AAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SortedSet<Point>(new Point[] { new Point(1, 2), new Point(4, 3) }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAAzwFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWRTZXRgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0EAAAABUNvdW50CENvbXBhcmVyB1ZlcnNpb24FSXRlbXMAAwAECNUBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCDVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQMAAAACAAAAAQAAAAkEAAAAAAAAAAkFAAAABAQAAADVAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQAAAAAHBQAAAAABAAAAAQAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AwAAAAkGAAAABQYAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIAwAAAAEAAAACAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAAzwFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWRTZXRgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0EAAAABUNvdW50CENvbXBhcmVyB1ZlcnNpb24FSXRlbXMAAwAECNUBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCDVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQMAAAACAAAAAQAAAAkEAAAAAAAAAAkFAAAABAQAAADVAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQAAAAAHBQAAAAABAAAAAQAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AwAAAAkGAAAABQYAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIAwAAAAEAAAACAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SortedSet<Tuple<int, Graph<int>>>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADpA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgADAAjuA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLk9iamVjdENvbXBhcmVyYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAIAAAAAAAAACQMAAAAAAAAABAMAAADuA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLk9iamVjdENvbXBhcmVyYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADpA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgADAAjuA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLk9iamVjdENvbXBhcmVyYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAIAAAAAAAAACQMAAAAAAAAABAMAAADuA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLk9iamVjdENvbXBhcmVyYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SortedSet<Tuple<int, Graph<int>>>(new Tuple<int, Graph<int>>[] { Tuple.Create(1, new Graph<int>()), Tuple.Create(5, new Graph<int>()) }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADpA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgVJdGVtcwADAAMI7gNTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5PYmplY3RDb21wYXJlcmAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQj0AlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV1bXQIAAAACAAAACQMAAAAAAAAACQQAAAAEAwAAAO4DU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0Q29tcGFyZXJgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAABwQAAAAAAQAAAAIAAAAD8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCQUAAAAJBgAAAAwHAAAAcFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWIEBQAAAPICU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQIAAAAHbV9JdGVtMQdtX0l0ZW0yAAQIkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQcAAAABAAAACQgAAAABBgAAAAUAAAAFAAAACQkAAAAFCAAAAJIBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAABVZhbHVlBUxpbmtzAAQIlAFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXVtdBwAAAAcAAAAAAAAACgEJAAAACAAAAAAAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADpA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgVJdGVtcwADAAMI7gNTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5PYmplY3RDb21wYXJlcmAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQj0AlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV1bXQIAAAACAAAACQMAAAAAAAAACQQAAAAEAwAAAO4DU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0Q29tcGFyZXJgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAABwQAAAAAAQAAAAIAAAAD8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCQUAAAAJBgAAAAwHAAAAcFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWIEBQAAAPICU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQIAAAAHbV9JdGVtMQdtX0l0ZW0yAAQIkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQcAAAABAAAACQgAAAABBgAAAAUAAAAFAAAACQkAAAAFCAAAAJIBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAABVZhbHVlBUxpbmtzAAQIlAFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXVtdBwAAAAcAAAAAAAAACgEJAAAACAAAAAAAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
+
+ yield return new object[] { new Stack(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuU3RhY2sDAAAABl9hcnJheQVfc2l6ZQhfdmVyc2lvbgUAAAgICQIAAAAAAAAAAAAAABACAAAACgAAAA0KCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuU3RhY2sDAAAABl9hcnJheQVfc2l6ZQhfdmVyc2lvbgUAAAgICQIAAAAAAAAAAAAAABACAAAACgAAAA0KCw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Stack(Enumerable.Range(0, 123).ToArray()), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuU3RhY2sDAAAABl9hcnJheQVfc2l6ZQhfdmVyc2lvbgUAAAgICQIAAAB7AAAAewAAABACAAAAewAAAAgIAAAAAAgIAQAAAAgIAgAAAAgIAwAAAAgIBAAAAAgIBQAAAAgIBgAAAAgIBwAAAAgICAAAAAgICQAAAAgICgAAAAgICwAAAAgIDAAAAAgIDQAAAAgIDgAAAAgIDwAAAAgIEAAAAAgIEQAAAAgIEgAAAAgIEwAAAAgIFAAAAAgIFQAAAAgIFgAAAAgIFwAAAAgIGAAAAAgIGQAAAAgIGgAAAAgIGwAAAAgIHAAAAAgIHQAAAAgIHgAAAAgIHwAAAAgIIAAAAAgIIQAAAAgIIgAAAAgIIwAAAAgIJAAAAAgIJQAAAAgIJgAAAAgIJwAAAAgIKAAAAAgIKQAAAAgIKgAAAAgIKwAAAAgILAAAAAgILQAAAAgILgAAAAgILwAAAAgIMAAAAAgIMQAAAAgIMgAAAAgIMwAAAAgINAAAAAgINQAAAAgINgAAAAgINwAAAAgIOAAAAAgIOQAAAAgIOgAAAAgIOwAAAAgIPAAAAAgIPQAAAAgIPgAAAAgIPwAAAAgIQAAAAAgIQQAAAAgIQgAAAAgIQwAAAAgIRAAAAAgIRQAAAAgIRgAAAAgIRwAAAAgISAAAAAgISQAAAAgISgAAAAgISwAAAAgITAAAAAgITQAAAAgITgAAAAgITwAAAAgIUAAAAAgIUQAAAAgIUgAAAAgIUwAAAAgIVAAAAAgIVQAAAAgIVgAAAAgIVwAAAAgIWAAAAAgIWQAAAAgIWgAAAAgIWwAAAAgIXAAAAAgIXQAAAAgIXgAAAAgIXwAAAAgIYAAAAAgIYQAAAAgIYgAAAAgIYwAAAAgIZAAAAAgIZQAAAAgIZgAAAAgIZwAAAAgIaAAAAAgIaQAAAAgIagAAAAgIawAAAAgIbAAAAAgIbQAAAAgIbgAAAAgIbwAAAAgIcAAAAAgIcQAAAAgIcgAAAAgIcwAAAAgIdAAAAAgIdQAAAAgIdgAAAAgIdwAAAAgIeAAAAAgIeQAAAAgIegAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuU3RhY2sDAAAABl9hcnJheQVfc2l6ZQhfdmVyc2lvbgUAAAgICQIAAAB7AAAAewAAABACAAAAewAAAAgIAAAAAAgIAQAAAAgIAgAAAAgIAwAAAAgIBAAAAAgIBQAAAAgIBgAAAAgIBwAAAAgICAAAAAgICQAAAAgICgAAAAgICwAAAAgIDAAAAAgIDQAAAAgIDgAAAAgIDwAAAAgIEAAAAAgIEQAAAAgIEgAAAAgIEwAAAAgIFAAAAAgIFQAAAAgIFgAAAAgIFwAAAAgIGAAAAAgIGQAAAAgIGgAAAAgIGwAAAAgIHAAAAAgIHQAAAAgIHgAAAAgIHwAAAAgIIAAAAAgIIQAAAAgIIgAAAAgIIwAAAAgIJAAAAAgIJQAAAAgIJgAAAAgIJwAAAAgIKAAAAAgIKQAAAAgIKgAAAAgIKwAAAAgILAAAAAgILQAAAAgILgAAAAgILwAAAAgIMAAAAAgIMQAAAAgIMgAAAAgIMwAAAAgINAAAAAgINQAAAAgINgAAAAgINwAAAAgIOAAAAAgIOQAAAAgIOgAAAAgIOwAAAAgIPAAAAAgIPQAAAAgIPgAAAAgIPwAAAAgIQAAAAAgIQQAAAAgIQgAAAAgIQwAAAAgIRAAAAAgIRQAAAAgIRgAAAAgIRwAAAAgISAAAAAgISQAAAAgISgAAAAgISwAAAAgITAAAAAgITQAAAAgITgAAAAgITwAAAAgIUAAAAAgIUQAAAAgIUgAAAAgIUwAAAAgIVAAAAAgIVQAAAAgIVgAAAAgIVwAAAAgIWAAAAAgIWQAAAAgIWgAAAAgIWwAAAAgIXAAAAAgIXQAAAAgIXgAAAAgIXwAAAAgIYAAAAAgIYQAAAAgIYgAAAAgIYwAAAAgIZAAAAAgIZQAAAAgIZgAAAAgIZwAAAAgIaAAAAAgIaQAAAAgIagAAAAgIawAAAAgIbAAAAAgIbQAAAAgIbgAAAAgIbwAAAAgIcAAAAAgIcQAAAAgIcgAAAAgIcwAAAAgIdAAAAAgIdQAAAAgIdgAAAAgIdwAAAAgIeAAAAAgIeQAAAAgIegAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Stack(new int[] { 5, 7, 9 }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuU3RhY2sDAAAABl9hcnJheQVfc2l6ZQhfdmVyc2lvbgUAAAgICQIAAAADAAAAAwAAABACAAAACgAAAAgIBQAAAAgIBwAAAAgICQAAAA0HCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuU3RhY2sDAAAABl9hcnJheQVfc2l6ZQhfdmVyc2lvbgUAAAgICQIAAAADAAAAAwAAABACAAAACgAAAAgIBQAAAAgIBwAAAAgICQAAAA0HCw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Stack(new Point[] { new Point(1, 2), new Point(4, 3) }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuU3RhY2sDAAAABl9hcnJheQVfc2l6ZQhfdmVyc2lvbgUAAAgICQIAAAACAAAAAgAAABACAAAACgAAAAkDAAAACQQAAAANCAwFAAAAcFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWIFAwAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgFAAAAAQAAAAIAAAABBAAAAAMAAAAEAAAAAwAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuU3RhY2sDAAAABl9hcnJheQVfc2l6ZQhfdmVyc2lvbgUAAAgICQIAAAACAAAAAgAAABACAAAACgAAAAkDAAAACQQAAAANCAwFAAAAcFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWIFAwAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgFAAAAAQAAAAIAAAABBAAAAAMAAAAEAAAAAwAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Stack(new Tuple<int, Graph<int>>[] { Tuple.Create(1, new Graph<int>()), Tuple.Create(5, new Graph<int>()) }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuU3RhY2sDAAAABl9hcnJheQVfc2l6ZQhfdmVyc2lvbgUAAAgICQIAAAACAAAAAgAAABACAAAACgAAAAkDAAAACQQAAAANCAwFAAAAcFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWIEAwAAAPICU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQIAAAAHbV9JdGVtMQdtX0l0ZW0yAAQIkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQUAAAABAAAACQYAAAABBAAAAAMAAAAFAAAACQcAAAAFBgAAAJIBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAABVZhbHVlBUxpbmtzAAQIlAFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXVtdBQAAAAUAAAAAAAAACgEHAAAABgAAAAAAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuU3RhY2sDAAAABl9hcnJheQVfc2l6ZQhfdmVyc2lvbgUAAAgICQIAAAACAAAAAgAAABACAAAACgAAAAkDAAAACQQAAAANCAwFAAAAcFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWIEAwAAAPICU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQIAAAAHbV9JdGVtMQdtX0l0ZW0yAAQIkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQUAAAABAAAACQYAAAABBAAAAAMAAAAFAAAACQcAAAAFBgAAAJIBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAABVZhbHVlBUxpbmtzAAQIlAFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXVtdBQAAAAUAAAAAAAAACgEHAAAABgAAAAAAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
+
+ yield return new object[] { new Hashtable(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBwAAAApMb2FkRmFjdG9yB1ZlcnNpb24IQ29tcGFyZXIQSGFzaENvZGVQcm92aWRlcghIYXNoU2l6ZQRLZXlzBlZhbHVlcwAAAwMABQULCBxTeXN0ZW0uQ29sbGVjdGlvbnMuSUNvbXBhcmVyJFN5c3RlbS5Db2xsZWN0aW9ucy5JSGFzaENvZGVQcm92aWRlcgjsUTg/AAAAAAoKAwAAAAkCAAAACQMAAAAQAgAAAAAAAAAQAwAAAAAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBwAAAApMb2FkRmFjdG9yB1ZlcnNpb24IQ29tcGFyZXIQSGFzaENvZGVQcm92aWRlcghIYXNoU2l6ZQRLZXlzBlZhbHVlcwAAAwMABQULCBxTeXN0ZW0uQ29sbGVjdGlvbnMuSUNvbXBhcmVyJFN5c3RlbS5Db2xsZWN0aW9ucy5JSGFzaENvZGVQcm92aWRlcgjsUTg/AAAAAAoKAwAAAAkCAAAACQMAAAAQAgAAAAAAAAAQAwAAAAAAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Hashtable(EqualityComparer<object>.Default), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uT2JqZWN0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQjsUTg/AAAAAAkCAAAAAwAAAAkDAAAACQQAAAAEAgAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uT2JqZWN0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAQAwAAAAAAAAAQBAAAAAAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uT2JqZWN0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQjsUTg/AAAAAAkCAAAAAwAAAAkDAAAACQQAAAAEAgAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uT2JqZWN0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAQAwAAAAAAAAAQBAAAAAAAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Hashtable(5), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBwAAAApMb2FkRmFjdG9yB1ZlcnNpb24IQ29tcGFyZXIQSGFzaENvZGVQcm92aWRlcghIYXNoU2l6ZQRLZXlzBlZhbHVlcwAAAwMABQULCBxTeXN0ZW0uQ29sbGVjdGlvbnMuSUNvbXBhcmVyJFN5c3RlbS5Db2xsZWN0aW9ucy5JSGFzaENvZGVQcm92aWRlcgjsUTg/AAAAAAoKBwAAAAkCAAAACQMAAAAQAgAAAAAAAAAQAwAAAAAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBwAAAApMb2FkRmFjdG9yB1ZlcnNpb24IQ29tcGFyZXIQSGFzaENvZGVQcm92aWRlcghIYXNoU2l6ZQRLZXlzBlZhbHVlcwAAAwMABQULCBxTeXN0ZW0uQ29sbGVjdGlvbnMuSUNvbXBhcmVyJFN5c3RlbS5Db2xsZWN0aW9ucy5JSGFzaENvZGVQcm92aWRlcgjsUTg/AAAAAAoKBwAAAAkCAAAACQMAAAAQAgAAAAAAAAAQAwAAAAAAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Hashtable(new Dictionary<int, string>(), 0.77f), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBwAAAApMb2FkRmFjdG9yB1ZlcnNpb24IQ29tcGFyZXIQSGFzaENvZGVQcm92aWRlcghIYXNoU2l6ZQRLZXlzBlZhbHVlcwAAAwMABQULCBxTeXN0ZW0uQ29sbGVjdGlvbnMuSUNvbXBhcmVyJFN5c3RlbS5Db2xsZWN0aW9ucy5JSGFzaENvZGVQcm92aWRlcggp7Q0/AAAAAAoKAwAAAAkCAAAACQMAAAAQAgAAAAAAAAAQAwAAAAAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBwAAAApMb2FkRmFjdG9yB1ZlcnNpb24IQ29tcGFyZXIQSGFzaENvZGVQcm92aWRlcghIYXNoU2l6ZQRLZXlzBlZhbHVlcwAAAwMABQULCBxTeXN0ZW0uQ29sbGVjdGlvbnMuSUNvbXBhcmVyJFN5c3RlbS5Db2xsZWN0aW9ucy5JSGFzaENvZGVQcm92aWRlcggp7Q0/AAAAAAoKAwAAAAkCAAAACQMAAAAQAgAAAAAAAAAQAwAAAAAAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Hashtable(StringComparer.InvariantCultureIgnoreCase), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXII7FE4PwAAAAAJAgAAAAMAAAAJAwAAAAkEAAAABAIAAAAbU3lzdGVtLkN1bHR1cmVBd2FyZUNvbXBhcmVyAgAAAAxfY29tcGFyZUluZm8LX2lnbm9yZUNhc2UDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwEJBQAAAAEQAwAAAAAAAAAQBAAAAAAAAAAEBQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwMAAAAGbV9uYW1lDW1fU29ydFZlcnNpb24HY3VsdHVyZQEDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbggGBgAAAAAKfwAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXII7FE4PwAAAAAJAgAAAAMAAAAJAwAAAAkEAAAABAIAAAAbU3lzdGVtLkN1bHR1cmVBd2FyZUNvbXBhcmVyAgAAAAxfY29tcGFyZUluZm8LX2lnbm9yZUNhc2UDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwEJBQAAAAEQAwAAAAAAAAAQBAAAAAAAAAAEBQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwQAAAAGbV9uYW1lCXdpbjMyTENJRAdjdWx0dXJlDW1fU29ydFZlcnNpb24BAAADCAggU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24GBgAAAAAAAAAAfwAAAAoL", TargetFrameworkMoniker.netfx461), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXII7FE4PwAAAAAJAgAAAAMAAAAJAwAAAAkEAAAABAIAAAAbU3lzdGVtLkN1bHR1cmVBd2FyZUNvbXBhcmVyAwAAAAxfY29tcGFyZUluZm8IX29wdGlvbnMLX2lnbm9yZUNhc2UDAwAgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8jU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZU9wdGlvbnMBCQUAAAAE+v///yNTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlT3B0aW9ucwEAAAAHdmFsdWVfXwAIAQAAAAEQAwAAAAAAAAAQBAAAAAAAAAAEBQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwMAAAAGbV9uYW1lDW1fU29ydFZlcnNpb24HY3VsdHVyZQEDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbggGBwAAAAAKfwAAAAs=", TargetFrameworkMoniker.netcoreapp21), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXII7FE4PwAAAAAJAgAAAAMAAAAJAwAAAAkEAAAABAIAAAAbU3lzdGVtLkN1bHR1cmVBd2FyZUNvbXBhcmVyAwAAAAxfY29tcGFyZUluZm8LX2lnbm9yZUNhc2UIX29wdGlvbnMDAAMgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8BI1N5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVPcHRpb25zCQUAAAABBPr///8jU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAEAAAAQAwAAAAAAAAAQBAAAAAAAAAAEBQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwQAAAAGbV9uYW1lCXdpbjMyTENJRAdjdWx0dXJlDW1fU29ydFZlcnNpb24BAAADCAggU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24GBwAAAAAAAAAAfwAAAAoL", TargetFrameworkMoniker.netfx471) } };
+ yield return new object[] { new Hashtable(StringComparer.InvariantCulture), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXII7FE4PwAAAAAJAgAAAAMAAAAJAwAAAAkEAAAABAIAAAAbU3lzdGVtLkN1bHR1cmVBd2FyZUNvbXBhcmVyAgAAAAxfY29tcGFyZUluZm8LX2lnbm9yZUNhc2UDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwEJBQAAAAAQAwAAAAAAAAAQBAAAAAAAAAAEBQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwMAAAAGbV9uYW1lDW1fU29ydFZlcnNpb24HY3VsdHVyZQEDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbggGBgAAAAAKfwAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXII7FE4PwAAAAAJAgAAAAMAAAAJAwAAAAkEAAAABAIAAAAbU3lzdGVtLkN1bHR1cmVBd2FyZUNvbXBhcmVyAgAAAAxfY29tcGFyZUluZm8LX2lnbm9yZUNhc2UDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwEJBQAAAAAQAwAAAAAAAAAQBAAAAAAAAAAEBQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwQAAAAGbV9uYW1lCXdpbjMyTENJRAdjdWx0dXJlDW1fU29ydFZlcnNpb24BAAADCAggU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24GBgAAAAAAAAAAfwAAAAoL", TargetFrameworkMoniker.netfx461), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXII7FE4PwAAAAAJAgAAAAMAAAAJAwAAAAkEAAAABAIAAAAbU3lzdGVtLkN1bHR1cmVBd2FyZUNvbXBhcmVyAwAAAAxfY29tcGFyZUluZm8IX29wdGlvbnMLX2lnbm9yZUNhc2UDAwAgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8jU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZU9wdGlvbnMBCQUAAAAE+v///yNTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlT3B0aW9ucwEAAAAHdmFsdWVfXwAIAAAAAAAQAwAAAAAAAAAQBAAAAAAAAAAEBQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwMAAAAGbV9uYW1lDW1fU29ydFZlcnNpb24HY3VsdHVyZQEDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbggGBwAAAAAKfwAAAAs=", TargetFrameworkMoniker.netcoreapp21), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXII7FE4PwAAAAAJAgAAAAMAAAAJAwAAAAkEAAAABAIAAAAbU3lzdGVtLkN1bHR1cmVBd2FyZUNvbXBhcmVyAwAAAAxfY29tcGFyZUluZm8LX2lnbm9yZUNhc2UIX29wdGlvbnMDAAMgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8BI1N5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVPcHRpb25zCQUAAAAABPr///8jU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAAAAAAQAwAAAAAAAAAQBAAAAAAAAAAEBQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwQAAAAGbV9uYW1lCXdpbjMyTENJRAdjdWx0dXJlDW1fU29ydFZlcnNpb24BAAADCAggU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24GBwAAAAAAAAAAfwAAAAoL", TargetFrameworkMoniker.netfx471) } };
+ yield return new object[] { new Hashtable(StringComparer.CurrentCultureIgnoreCase), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXII7FE4PwAAAAAJAgAAAAMAAAAJAwAAAAkEAAAABAIAAAAbU3lzdGVtLkN1bHR1cmVBd2FyZUNvbXBhcmVyAgAAAAxfY29tcGFyZUluZm8LX2lnbm9yZUNhc2UDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwEJBQAAAAEQAwAAAAAAAAAQBAAAAAAAAAAEBQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwMAAAAGbV9uYW1lDW1fU29ydFZlcnNpb24HY3VsdHVyZQEDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbggGBgAAAAAKfwAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXII7FE4PwAAAAAJAgAAAAMAAAAJAwAAAAkEAAAABAIAAAAbU3lzdGVtLkN1bHR1cmVBd2FyZUNvbXBhcmVyAgAAAAxfY29tcGFyZUluZm8LX2lnbm9yZUNhc2UDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwEJBQAAAAEQAwAAAAAAAAAQBAAAAAAAAAAEBQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwQAAAAGbV9uYW1lCXdpbjMyTENJRAdjdWx0dXJlDW1fU29ydFZlcnNpb24BAAADCAggU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24GBgAAAAAAAAAAfwAAAAoL", TargetFrameworkMoniker.netfx461), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXII7FE4PwAAAAAJAgAAAAMAAAAJAwAAAAkEAAAABAIAAAAbU3lzdGVtLkN1bHR1cmVBd2FyZUNvbXBhcmVyAwAAAAxfY29tcGFyZUluZm8IX29wdGlvbnMLX2lnbm9yZUNhc2UDAwAgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8jU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZU9wdGlvbnMBCQUAAAAE+v///yNTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlT3B0aW9ucwEAAAAHdmFsdWVfXwAIAQAAAAEQAwAAAAAAAAAQBAAAAAAAAAAEBQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwMAAAAGbV9uYW1lDW1fU29ydFZlcnNpb24HY3VsdHVyZQEDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbggGBwAAAAAKfwAAAAs=", TargetFrameworkMoniker.netcoreapp21), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXII7FE4PwAAAAAJAgAAAAMAAAAJAwAAAAkEAAAABAIAAAAbU3lzdGVtLkN1bHR1cmVBd2FyZUNvbXBhcmVyAwAAAAxfY29tcGFyZUluZm8LX2lnbm9yZUNhc2UIX29wdGlvbnMDAAMgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8BI1N5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVPcHRpb25zCQUAAAABBPr///8jU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAEAAAAQAwAAAAAAAAAQBAAAAAAAAAAEBQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwQAAAAGbV9uYW1lCXdpbjMyTENJRAdjdWx0dXJlDW1fU29ydFZlcnNpb24BAAADCAggU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24GBwAAAAAAAAAAfwAAAAoL", TargetFrameworkMoniker.netfx471) } };
+ yield return new object[] { new Hashtable(StringComparer.CurrentCulture), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXII7FE4PwAAAAAJAgAAAAMAAAAJAwAAAAkEAAAABAIAAAAbU3lzdGVtLkN1bHR1cmVBd2FyZUNvbXBhcmVyAgAAAAxfY29tcGFyZUluZm8LX2lnbm9yZUNhc2UDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwEJBQAAAAAQAwAAAAAAAAAQBAAAAAAAAAAEBQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwMAAAAGbV9uYW1lDW1fU29ydFZlcnNpb24HY3VsdHVyZQEDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbggGBgAAAAAKfwAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXII7FE4PwAAAAAJAgAAAAMAAAAJAwAAAAkEAAAABAIAAAAbU3lzdGVtLkN1bHR1cmVBd2FyZUNvbXBhcmVyAgAAAAxfY29tcGFyZUluZm8LX2lnbm9yZUNhc2UDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwEJBQAAAAAQAwAAAAAAAAAQBAAAAAAAAAAEBQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwQAAAAGbV9uYW1lCXdpbjMyTENJRAdjdWx0dXJlDW1fU29ydFZlcnNpb24BAAADCAggU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24GBgAAAAAAAAAAfwAAAAoL", TargetFrameworkMoniker.netfx461), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXII7FE4PwAAAAAJAgAAAAMAAAAJAwAAAAkEAAAABAIAAAAbU3lzdGVtLkN1bHR1cmVBd2FyZUNvbXBhcmVyAwAAAAxfY29tcGFyZUluZm8IX29wdGlvbnMLX2lnbm9yZUNhc2UDAwAgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8jU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZU9wdGlvbnMBCQUAAAAE+v///yNTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlT3B0aW9ucwEAAAAHdmFsdWVfXwAIAAAAAAAQAwAAAAAAAAAQBAAAAAAAAAAEBQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwMAAAAGbV9uYW1lDW1fU29ydFZlcnNpb24HY3VsdHVyZQEDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbggGBwAAAAAKfwAAAAs=", TargetFrameworkMoniker.netcoreapp21), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXII7FE4PwAAAAAJAgAAAAMAAAAJAwAAAAkEAAAABAIAAAAbU3lzdGVtLkN1bHR1cmVBd2FyZUNvbXBhcmVyAwAAAAxfY29tcGFyZUluZm8LX2lnbm9yZUNhc2UIX29wdGlvbnMDAAMgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8BI1N5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVPcHRpb25zCQUAAAAABPr///8jU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAAAAAAQAwAAAAAAAAAQBAAAAAAAAAAEBQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwQAAAAGbV9uYW1lCXdpbjMyTENJRAdjdWx0dXJlDW1fU29ydFZlcnNpb24BAAADCAggU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24GBwAAAAAAAAAAfwAAAAoL", TargetFrameworkMoniker.netfx471) } };
+ yield return new object[] { StringComparer.InvariantCultureIgnoreCase, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXICAAAADF9jb21wYXJlSW5mbwtfaWdub3JlQ2FzZQMAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvAQkCAAAAAQQCAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvAwAAAAZtX25hbWUNbV9Tb3J0VmVyc2lvbgdjdWx0dXJlAQMAIFN5c3RlbS5HbG9iYWxpemF0aW9uLlNvcnRWZXJzaW9uCAYDAAAAAAp/AAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXICAAAADF9jb21wYXJlSW5mbwtfaWdub3JlQ2FzZQMAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvAQkCAAAAAQQCAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvBAAAAAZtX25hbWUJd2luMzJMQ0lEB2N1bHR1cmUNbV9Tb3J0VmVyc2lvbgEAAAMICCBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbgYDAAAAAAAAAAB/AAAACgs=", TargetFrameworkMoniker.netfx461), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXIDAAAADF9jb21wYXJlSW5mbwhfb3B0aW9ucwtfaWdub3JlQ2FzZQMDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbyNTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlT3B0aW9ucwEJAgAAAAT9////I1N5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVPcHRpb25zAQAAAAd2YWx1ZV9fAAgBAAAAAQQCAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvAwAAAAZtX25hbWUNbV9Tb3J0VmVyc2lvbgdjdWx0dXJlAQMAIFN5c3RlbS5HbG9iYWxpemF0aW9uLlNvcnRWZXJzaW9uCAYEAAAAAAp/AAAACw==", TargetFrameworkMoniker.netcoreapp21), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXIDAAAADF9jb21wYXJlSW5mbwtfaWdub3JlQ2FzZQhfb3B0aW9ucwMAAyBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwEjU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZU9wdGlvbnMJAgAAAAEE/f///yNTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlT3B0aW9ucwEAAAAHdmFsdWVfXwAIAQAAAAQCAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvBAAAAAZtX25hbWUJd2luMzJMQ0lEB2N1bHR1cmUNbV9Tb3J0VmVyc2lvbgEAAAMICCBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbgYEAAAAAAAAAAB/AAAACgs=", TargetFrameworkMoniker.netfx471) } };
+ yield return new object[] { StringComparer.InvariantCulture, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXICAAAADF9jb21wYXJlSW5mbwtfaWdub3JlQ2FzZQMAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvAQkCAAAAAAQCAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvAwAAAAZtX25hbWUNbV9Tb3J0VmVyc2lvbgdjdWx0dXJlAQMAIFN5c3RlbS5HbG9iYWxpemF0aW9uLlNvcnRWZXJzaW9uCAYDAAAAAAp/AAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXICAAAADF9jb21wYXJlSW5mbwtfaWdub3JlQ2FzZQMAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvAQkCAAAAAAQCAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvBAAAAAZtX25hbWUJd2luMzJMQ0lEB2N1bHR1cmUNbV9Tb3J0VmVyc2lvbgEAAAMICCBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbgYDAAAAAAAAAAB/AAAACgs=", TargetFrameworkMoniker.netfx461), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXIDAAAADF9jb21wYXJlSW5mbwhfb3B0aW9ucwtfaWdub3JlQ2FzZQMDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbyNTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlT3B0aW9ucwEJAgAAAAT9////I1N5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVPcHRpb25zAQAAAAd2YWx1ZV9fAAgAAAAAAAQCAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvAwAAAAZtX25hbWUNbV9Tb3J0VmVyc2lvbgdjdWx0dXJlAQMAIFN5c3RlbS5HbG9iYWxpemF0aW9uLlNvcnRWZXJzaW9uCAYEAAAAAAp/AAAACw==", TargetFrameworkMoniker.netcoreapp21), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXIDAAAADF9jb21wYXJlSW5mbwtfaWdub3JlQ2FzZQhfb3B0aW9ucwMAAyBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwEjU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZU9wdGlvbnMJAgAAAAAE/f///yNTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlT3B0aW9ucwEAAAAHdmFsdWVfXwAIAAAAAAQCAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvBAAAAAZtX25hbWUJd2luMzJMQ0lEB2N1bHR1cmUNbV9Tb3J0VmVyc2lvbgEAAAMICCBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbgYEAAAAAAAAAAB/AAAACgs=", TargetFrameworkMoniker.netfx471) } };
+ yield return new object[] { StringComparer.CurrentCultureIgnoreCase, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXICAAAADF9jb21wYXJlSW5mbwtfaWdub3JlQ2FzZQMAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvAQkCAAAAAQQCAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvAwAAAAZtX25hbWUNbV9Tb3J0VmVyc2lvbgdjdWx0dXJlAQMAIFN5c3RlbS5HbG9iYWxpemF0aW9uLlNvcnRWZXJzaW9uCAYDAAAAAAp/AAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXICAAAADF9jb21wYXJlSW5mbwtfaWdub3JlQ2FzZQMAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvAQkCAAAAAQQCAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvBAAAAAZtX25hbWUJd2luMzJMQ0lEB2N1bHR1cmUNbV9Tb3J0VmVyc2lvbgEAAAMICCBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbgYDAAAAAAAAAAB/AAAACgs=", TargetFrameworkMoniker.netfx461), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXIDAAAADF9jb21wYXJlSW5mbwhfb3B0aW9ucwtfaWdub3JlQ2FzZQMDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbyNTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlT3B0aW9ucwEJAgAAAAT9////I1N5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVPcHRpb25zAQAAAAd2YWx1ZV9fAAgBAAAAAQQCAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvAwAAAAZtX25hbWUNbV9Tb3J0VmVyc2lvbgdjdWx0dXJlAQMAIFN5c3RlbS5HbG9iYWxpemF0aW9uLlNvcnRWZXJzaW9uCAYEAAAAAAp/AAAACw==", TargetFrameworkMoniker.netcoreapp21), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXIDAAAADF9jb21wYXJlSW5mbwtfaWdub3JlQ2FzZQhfb3B0aW9ucwMAAyBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwEjU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZU9wdGlvbnMJAgAAAAEE/f///yNTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlT3B0aW9ucwEAAAAHdmFsdWVfXwAIAQAAAAQCAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvBAAAAAZtX25hbWUJd2luMzJMQ0lEB2N1bHR1cmUNbV9Tb3J0VmVyc2lvbgEAAAMICCBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbgYEAAAAAAAAAAB/AAAACgs=", TargetFrameworkMoniker.netfx471) } };
+ yield return new object[] { StringComparer.CurrentCulture, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXICAAAADF9jb21wYXJlSW5mbwtfaWdub3JlQ2FzZQMAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvAQkCAAAAAAQCAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvAwAAAAZtX25hbWUNbV9Tb3J0VmVyc2lvbgdjdWx0dXJlAQMAIFN5c3RlbS5HbG9iYWxpemF0aW9uLlNvcnRWZXJzaW9uCAYDAAAAAAp/AAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXICAAAADF9jb21wYXJlSW5mbwtfaWdub3JlQ2FzZQMAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvAQkCAAAAAAQCAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvBAAAAAZtX25hbWUJd2luMzJMQ0lEB2N1bHR1cmUNbV9Tb3J0VmVyc2lvbgEAAAMICCBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbgYDAAAAAAAAAAB/AAAACgs=", TargetFrameworkMoniker.netfx461), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXIDAAAADF9jb21wYXJlSW5mbwhfb3B0aW9ucwtfaWdub3JlQ2FzZQMDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbyNTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlT3B0aW9ucwEJAgAAAAT9////I1N5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVPcHRpb25zAQAAAAd2YWx1ZV9fAAgAAAAAAAQCAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvAwAAAAZtX25hbWUNbV9Tb3J0VmVyc2lvbgdjdWx0dXJlAQMAIFN5c3RlbS5HbG9iYWxpemF0aW9uLlNvcnRWZXJzaW9uCAYEAAAAAAp/AAAACw==", TargetFrameworkMoniker.netcoreapp21), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXIDAAAADF9jb21wYXJlSW5mbwtfaWdub3JlQ2FzZQhfb3B0aW9ucwMAAyBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwEjU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZU9wdGlvbnMJAgAAAAAE/f///yNTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlT3B0aW9ucwEAAAAHdmFsdWVfXwAIAAAAAAQCAAAAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvBAAAAAZtX25hbWUJd2luMzJMQ0lEB2N1bHR1cmUNbV9Tb3J0VmVyc2lvbgEAAAMICCBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbgYEAAAAAAAAAAB/AAAACgs=", TargetFrameworkMoniker.netfx471) } };
+ yield return new object[] { StringComparer.Ordinal, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABZTeXN0ZW0uT3JkaW5hbENvbXBhcmVyAQAAAAtfaWdub3JlQ2FzZQABAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABZTeXN0ZW0uT3JkaW5hbENvbXBhcmVyAQAAAAtfaWdub3JlQ2FzZQABAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { StringComparer.OrdinalIgnoreCase, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABZTeXN0ZW0uT3JkaW5hbENvbXBhcmVyAQAAAAtfaWdub3JlQ2FzZQABAQs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABZTeXN0ZW0uT3JkaW5hbENvbXBhcmVyAQAAAAtfaWdub3JlQ2FzZQABAQs=", TargetFrameworkMoniker.netfx461) } };
#pragma warning disable 0618 // obsolete warning
- yield return new object[] { new Hashtable(15, 0.8f, new HashCodeProvider(), Comparer.DefaultInvariant), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAEAAAAcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQcAAAAKTG9hZEZhY3RvcgdWZXJzaW9uCENvbXBhcmVyEEhhc2hDb2RlUHJvdmlkZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMEAAUFCwgbU3lzdGVtLkNvbGxlY3Rpb25zLkNvbXBhcmVyPlN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5IYXNoQ29kZVByb3ZpZGVyAgAAAAi9dBM/AAAAAAkDAAAACQQAAAAdAAAACQUAAAAJBgAAAAQDAAAAG1N5c3RlbS5Db2xsZWN0aW9ucy5Db21wYXJlcgEAAAALQ29tcGFyZUluZm8DIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCQcAAAAFBAAAAD5TeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuSGFzaENvZGVQcm92aWRlcgAAAAACAAAAEAUAAAAAAAAAEAYAAAAAAAAABAcAAAAgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8DAAAABm1fbmFtZQ1tX1NvcnRWZXJzaW9uB2N1bHR1cmUBAwAgU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24IBggAAAAACn8AAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAEAAAAcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQcAAAAKTG9hZEZhY3RvcgdWZXJzaW9uCENvbXBhcmVyEEhhc2hDb2RlUHJvdmlkZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMEAAUFCwgbU3lzdGVtLkNvbGxlY3Rpb25zLkNvbXBhcmVyPlN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5IYXNoQ29kZVByb3ZpZGVyAgAAAAi9dBM/AAAAAAkDAAAACQQAAAAdAAAACQUAAAAJBgAAAAQDAAAAG1N5c3RlbS5Db2xsZWN0aW9ucy5Db21wYXJlcgEAAAALQ29tcGFyZUluZm8DIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCQcAAAAFBAAAAD5TeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuSGFzaENvZGVQcm92aWRlcgAAAAACAAAAEAUAAAAAAAAAEAYAAAAAAAAABAcAAAAgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8EAAAABm1fbmFtZQl3aW4zMkxDSUQHY3VsdHVyZQ1tX1NvcnRWZXJzaW9uAQAAAwgIIFN5c3RlbS5HbG9iYWxpemF0aW9uLlNvcnRWZXJzaW9uBggAAAAAAAAAAH8AAAAKCw==" } };
+ yield return new object[] { new Hashtable(15, 0.8f, new HashCodeProvider(), Comparer.DefaultInvariant), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAEAAAAcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQcAAAAKTG9hZEZhY3RvcgdWZXJzaW9uCENvbXBhcmVyEEhhc2hDb2RlUHJvdmlkZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMEAAUFCwgbU3lzdGVtLkNvbGxlY3Rpb25zLkNvbXBhcmVyPlN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5IYXNoQ29kZVByb3ZpZGVyAgAAAAi9dBM/AAAAAAkDAAAACQQAAAAdAAAACQUAAAAJBgAAAAQDAAAAG1N5c3RlbS5Db2xsZWN0aW9ucy5Db21wYXJlcgEAAAALQ29tcGFyZUluZm8DIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCQcAAAAFBAAAAD5TeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuSGFzaENvZGVQcm92aWRlcgAAAAACAAAAEAUAAAAAAAAAEAYAAAAAAAAABAcAAAAgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8DAAAABm1fbmFtZQ1tX1NvcnRWZXJzaW9uB2N1bHR1cmUBAwAgU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24IBggAAAAACn8AAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAEAAAAcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQcAAAAKTG9hZEZhY3RvcgdWZXJzaW9uCENvbXBhcmVyEEhhc2hDb2RlUHJvdmlkZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMEAAUFCwgbU3lzdGVtLkNvbGxlY3Rpb25zLkNvbXBhcmVyPlN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5IYXNoQ29kZVByb3ZpZGVyAgAAAAi9dBM/AAAAAAkDAAAACQQAAAAdAAAACQUAAAAJBgAAAAQDAAAAG1N5c3RlbS5Db2xsZWN0aW9ucy5Db21wYXJlcgEAAAALQ29tcGFyZUluZm8DIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvCQcAAAAFBAAAAD5TeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuSGFzaENvZGVQcm92aWRlcgAAAAACAAAAEAUAAAAAAAAAEAYAAAAAAAAABAcAAAAgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8EAAAABm1fbmFtZQl3aW4zMkxDSUQHY3VsdHVyZQ1tX1NvcnRWZXJzaW9uAQAAAwgIIFN5c3RlbS5HbG9iYWxpemF0aW9uLlNvcnRWZXJzaW9uBggAAAAAAAAAAH8AAAAKCw==", TargetFrameworkMoniker.netfx461) } };
#pragma warning restore 0618
- yield return new object[] { new BindingList<int>(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACAAVN5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAlhZGROZXdQb3MWcmFpc2VMaXN0Q2hhbmdlZEV2ZW50cxZyYWlzZUl0ZW1DaGFuZ2VkRXZlbnRzCGFsbG93TmV3CWFsbG93RWRpdAthbGxvd1JlbW92ZQ91c2VyU2V0QWxsb3dOZXcSQ29sbGVjdGlvbmAxK2l0ZW1zAAAAAAAAAAMIAQEBAQEBflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAD/////AQABAQEACQMAAAAEAwAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkEAAAAAAAAAAAAAAAPBAAAAAAAAAAICw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACAAVN5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAlhZGROZXdQb3MWcmFpc2VMaXN0Q2hhbmdlZEV2ZW50cxZyYWlzZUl0ZW1DaGFuZ2VkRXZlbnRzCGFsbG93TmV3CWFsbG93RWRpdAthbGxvd1JlbW92ZQ91c2VyU2V0QWxsb3dOZXcSQ29sbGVjdGlvbmAxK2l0ZW1zAAAAAAAAAAMIAQEBAQEBflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAD/////AQABAQEACQMAAAAEAwAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkEAAAAAAAAAAAAAAAPBAAAAAAAAAAICw==" } };
- yield return new object[] { new BindingList<int>(Enumerable.Range(0, 123).ToArray()), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACAAVN5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAlhZGROZXdQb3MWcmFpc2VMaXN0Q2hhbmdlZEV2ZW50cxZyYWlzZUl0ZW1DaGFuZ2VkRXZlbnRzCGFsbG93TmV3CWFsbG93RWRpdAthbGxvd1JlbW92ZQ91c2VyU2V0QWxsb3dOZXcSQ29sbGVjdGlvbmAxK2l0ZW1zAAAAAAAAAAMIAQEBAQEBDlN5c3RlbS5JbnQzMltdAgAAAP////8BAAEBAQAJAwAAAA8DAAAAewAAAAgAAAAAAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAASAAAAEwAAABQAAAAVAAAAFgAAABcAAAAYAAAAGQAAABoAAAAbAAAAHAAAAB0AAAAeAAAAHwAAACAAAAAhAAAAIgAAACMAAAAkAAAAJQAAACYAAAAnAAAAKAAAACkAAAAqAAAAKwAAACwAAAAtAAAALgAAAC8AAAAwAAAAMQAAADIAAAAzAAAANAAAADUAAAA2AAAANwAAADgAAAA5AAAAOgAAADsAAAA8AAAAPQAAAD4AAAA/AAAAQAAAAEEAAABCAAAAQwAAAEQAAABFAAAARgAAAEcAAABIAAAASQAAAEoAAABLAAAATAAAAE0AAABOAAAATwAAAFAAAABRAAAAUgAAAFMAAABUAAAAVQAAAFYAAABXAAAAWAAAAFkAAABaAAAAWwAAAFwAAABdAAAAXgAAAF8AAABgAAAAYQAAAGIAAABjAAAAZAAAAGUAAABmAAAAZwAAAGgAAABpAAAAagAAAGsAAABsAAAAbQAAAG4AAABvAAAAcAAAAHEAAAByAAAAcwAAAHQAAAB1AAAAdgAAAHcAAAB4AAAAeQAAAHoAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACAAVN5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAlhZGROZXdQb3MWcmFpc2VMaXN0Q2hhbmdlZEV2ZW50cxZyYWlzZUl0ZW1DaGFuZ2VkRXZlbnRzCGFsbG93TmV3CWFsbG93RWRpdAthbGxvd1JlbW92ZQ91c2VyU2V0QWxsb3dOZXcSQ29sbGVjdGlvbmAxK2l0ZW1zAAAAAAAAAAMIAQEBAQEBDlN5c3RlbS5JbnQzMltdAgAAAP////8BAAEBAQAJAwAAAA8DAAAAewAAAAgAAAAAAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAASAAAAEwAAABQAAAAVAAAAFgAAABcAAAAYAAAAGQAAABoAAAAbAAAAHAAAAB0AAAAeAAAAHwAAACAAAAAhAAAAIgAAACMAAAAkAAAAJQAAACYAAAAnAAAAKAAAACkAAAAqAAAAKwAAACwAAAAtAAAALgAAAC8AAAAwAAAAMQAAADIAAAAzAAAANAAAADUAAAA2AAAANwAAADgAAAA5AAAAOgAAADsAAAA8AAAAPQAAAD4AAAA/AAAAQAAAAEEAAABCAAAAQwAAAEQAAABFAAAARgAAAEcAAABIAAAASQAAAEoAAABLAAAATAAAAE0AAABOAAAATwAAAFAAAABRAAAAUgAAAFMAAABUAAAAVQAAAFYAAABXAAAAWAAAAFkAAABaAAAAWwAAAFwAAABdAAAAXgAAAF8AAABgAAAAYQAAAGIAAABjAAAAZAAAAGUAAABmAAAAZwAAAGgAAABpAAAAagAAAGsAAABsAAAAbQAAAG4AAABvAAAAcAAAAHEAAAByAAAAcwAAAHQAAAB1AAAAdgAAAHcAAAB4AAAAeQAAAHoAAAAL" } };
- yield return new object[] { new BindingList<int>(new int[] { 5, 7, 9 }), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACAAVN5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAlhZGROZXdQb3MWcmFpc2VMaXN0Q2hhbmdlZEV2ZW50cxZyYWlzZUl0ZW1DaGFuZ2VkRXZlbnRzCGFsbG93TmV3CWFsbG93RWRpdAthbGxvd1JlbW92ZQ91c2VyU2V0QWxsb3dOZXcSQ29sbGVjdGlvbmAxK2l0ZW1zAAAAAAAAAAMIAQEBAQEBDlN5c3RlbS5JbnQzMltdAgAAAP////8BAAEBAQAJAwAAAA8DAAAAAwAAAAgFAAAABwAAAAkAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACAAVN5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAlhZGROZXdQb3MWcmFpc2VMaXN0Q2hhbmdlZEV2ZW50cxZyYWlzZUl0ZW1DaGFuZ2VkRXZlbnRzCGFsbG93TmV3CWFsbG93RWRpdAthbGxvd1JlbW92ZQ91c2VyU2V0QWxsb3dOZXcSQ29sbGVjdGlvbmAxK2l0ZW1zAAAAAAAAAAMIAQEBAQEBDlN5c3RlbS5JbnQzMltdAgAAAP////8BAAEBAQAJAwAAAA8DAAAAAwAAAAgFAAAABwAAAAkAAAAL" } };
- yield return new object[] { new BindingList<Point>(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADMAVN5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQgAAAAJYWRkTmV3UG9zFnJhaXNlTGlzdENoYW5nZWRFdmVudHMWcmFpc2VJdGVtQ2hhbmdlZEV2ZW50cwhhbGxvd05ldwlhbGxvd0VkaXQLYWxsb3dSZW1vdmUPdXNlclNldEFsbG93TmV3EkNvbGxlY3Rpb25gMStpdGVtcwAAAAAAAAADCAEBAQEBAcoBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQIAAAD/////AQAAAQEACQMAAAAMBAAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAMAAADKAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgQAADVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQQAAAAICAkFAAAAAAAAAAAAAAAHBQAAAAABAAAAAAAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50BAAAAAs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADMAVN5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQgAAAAJYWRkTmV3UG9zFnJhaXNlTGlzdENoYW5nZWRFdmVudHMWcmFpc2VJdGVtQ2hhbmdlZEV2ZW50cwhhbGxvd05ldwlhbGxvd0VkaXQLYWxsb3dSZW1vdmUPdXNlclNldEFsbG93TmV3EkNvbGxlY3Rpb25gMStpdGVtcwAAAAAAAAADCAEBAQEBAcoBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQIAAAD/////AQAAAQEACQMAAAAMBAAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAMAAADKAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgQAADVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQQAAAAICAkFAAAAAAAAAAAAAAAHBQAAAAABAAAAAAAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50BAAAAAs=" } };
- yield return new object[] { new BindingList<Point>(new Point[] { new Point(1, 2), new Point(4, 3) }), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAAzAFTeXN0ZW0uQ29tcG9uZW50TW9kZWwuQmluZGluZ0xpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0IAAAACWFkZE5ld1BvcxZyYWlzZUxpc3RDaGFuZ2VkRXZlbnRzFnJhaXNlSXRlbUNoYW5nZWRFdmVudHMIYWxsb3dOZXcJYWxsb3dFZGl0C2FsbG93UmVtb3ZlD3VzZXJTZXRBbGxvd05ldxJDb2xsZWN0aW9uYDEraXRlbXMAAAAAAAAABAgBAQEBAQE1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10DAAAAAgAAAP////8BAAABAQAJBAAAAAcEAAAAAAEAAAACAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQDAAAACQUAAAAJBgAAAAUFAAAAM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAIAAAABWAFZAAAICAMAAAABAAAAAgAAAAEGAAAABQAAAAQAAAADAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAAzAFTeXN0ZW0uQ29tcG9uZW50TW9kZWwuQmluZGluZ0xpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0IAAAACWFkZE5ld1BvcxZyYWlzZUxpc3RDaGFuZ2VkRXZlbnRzFnJhaXNlSXRlbUNoYW5nZWRFdmVudHMIYWxsb3dOZXcJYWxsb3dFZGl0C2FsbG93UmVtb3ZlD3VzZXJTZXRBbGxvd05ldxJDb2xsZWN0aW9uYDEraXRlbXMAAAAAAAAABAgBAQEBAQE1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10DAAAAAgAAAP////8BAAABAQAJBAAAAAcEAAAAAAEAAAACAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQDAAAACQUAAAAJBgAAAAUFAAAAM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAIAAAABWAFZAAAICAMAAAABAAAAAgAAAAEGAAAABQAAAAQAAAADAAAACw==" } };
- yield return new object[] { new BindingList<Tuple<int, Graph<int>>>(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADmA1N5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgAAAAJYWRkTmV3UG9zFnJhaXNlTGlzdENoYW5nZWRFdmVudHMWcmFpc2VJdGVtQ2hhbmdlZEV2ZW50cwhhbGxvd05ldwlhbGxvd0VkaXQLYWxsb3dSZW1vdmUPdXNlclNldEFsbG93TmV3EkNvbGxlY3Rpb25gMStpdGVtcwAAAAAAAAADCAEBAQEBAeQDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAD/////AQAAAQEACQMAAAAEAwAAAOQDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uAwAA9AJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dW10ICAkEAAAAAAAAAAAAAAAHBAAAAAABAAAAAAAAAAPyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0L", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADmA1N5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgAAAAJYWRkTmV3UG9zFnJhaXNlTGlzdENoYW5nZWRFdmVudHMWcmFpc2VJdGVtQ2hhbmdlZEV2ZW50cwhhbGxvd05ldwlhbGxvd0VkaXQLYWxsb3dSZW1vdmUPdXNlclNldEFsbG93TmV3EkNvbGxlY3Rpb25gMStpdGVtcwAAAAAAAAADCAEBAQEBAeQDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAD/////AQAAAQEACQMAAAAEAwAAAOQDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uAwAA9AJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dW10ICAkEAAAAAAAAAAAAAAAHBAAAAAABAAAAAAAAAAPyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0L" } };
- yield return new object[] { new BindingList<Tuple<int, Graph<int>>>(new Tuple<int, Graph<int>>[] { Tuple.Create(1, new Graph<int>()), Tuple.Create(5, new Graph<int>()) }), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADmA1N5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgAAAAJYWRkTmV3UG9zFnJhaXNlTGlzdENoYW5nZWRFdmVudHMWcmFpc2VJdGVtQ2hhbmdlZEV2ZW50cwhhbGxvd05ldwlhbGxvd0VkaXQLYWxsb3dSZW1vdmUPdXNlclNldEFsbG93TmV3EkNvbGxlY3Rpb25gMStpdGVtcwAAAAAAAAADCAEBAQEBAfQCU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdAgAAAP////8BAAABAQAJAwAAAAcDAAAAAAEAAAACAAAAA/ICU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQkEAAAACQUAAAAMBgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAQAAADyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAB21fSXRlbTEHbV9JdGVtMgAECJIBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0GAAAAAQAAAAkHAAAAAQUAAAAEAAAABQAAAAkIAAAABQcAAACSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAVWYWx1ZQVMaW5rcwAECJQBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV1bXQYAAAAGAAAAAAAAAAoBCAAAAAcAAAAAAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADmA1N5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgAAAAJYWRkTmV3UG9zFnJhaXNlTGlzdENoYW5nZWRFdmVudHMWcmFpc2VJdGVtQ2hhbmdlZEV2ZW50cwhhbGxvd05ldwlhbGxvd0VkaXQLYWxsb3dSZW1vdmUPdXNlclNldEFsbG93TmV3EkNvbGxlY3Rpb25gMStpdGVtcwAAAAAAAAADCAEBAQEBAfQCU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdAgAAAP////8BAAABAQAJAwAAAAcDAAAAAAEAAAACAAAAA/ICU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQkEAAAACQUAAAAMBgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAQAAADyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAB21fSXRlbTEHbV9JdGVtMgAECJIBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0GAAAAAQAAAAkHAAAAAQUAAAAEAAAABQAAAAkIAAAABQcAAACSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAVWYWx1ZQVMaW5rcwAECJQBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV1bXQYAAAAGAAAAAAAAAAoBCAAAAAcAAAAAAAAACgs=" } };
-
- yield return new object[] { new StringDictionary(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLlN0cmluZ0RpY3Rpb25hcnkBAAAACGNvbnRlbnRzAxxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlAgAAAAkDAAAABAMAAAAcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQcAAAAKTG9hZEZhY3RvcgdWZXJzaW9uCENvbXBhcmVyEEhhc2hDb2RlUHJvdmlkZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMDAAUFCwgcU3lzdGVtLkNvbGxlY3Rpb25zLklDb21wYXJlciRTeXN0ZW0uQ29sbGVjdGlvbnMuSUhhc2hDb2RlUHJvdmlkZXII7FE4PwAAAAAKCgMAAAAJBAAAAAkFAAAAEAQAAAAAAAAAEAUAAAAAAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLlN0cmluZ0RpY3Rpb25hcnkBAAAACGNvbnRlbnRzAxxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlAgAAAAkDAAAABAMAAAAcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQcAAAAKTG9hZEZhY3RvcgdWZXJzaW9uCENvbXBhcmVyEEhhc2hDb2RlUHJvdmlkZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMDAAUFCwgcU3lzdGVtLkNvbGxlY3Rpb25zLklDb21wYXJlciRTeXN0ZW0uQ29sbGVjdGlvbnMuSUhhc2hDb2RlUHJvdmlkZXII7FE4PwAAAAAKCgMAAAAJBAAAAAkFAAAAEAQAAAAAAAAAEAUAAAAAAAAACw==" } };
- yield return new object[] { new StringCollection(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLlN0cmluZ0NvbGxlY3Rpb24BAAAABGRhdGEDHFN5c3RlbS5Db2xsZWN0aW9ucy5BcnJheUxpc3QCAAAACQMAAAAEAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkEAAAAAAAAAAAAAAAQBAAAAAAAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLlN0cmluZ0NvbGxlY3Rpb24BAAAABGRhdGEDHFN5c3RlbS5Db2xsZWN0aW9ucy5BcnJheUxpc3QCAAAACQMAAAAEAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkEAAAAAAAAAAAAAAAQBAAAAAAAAAAL" } };
- yield return new object[] { new OrderedDictionary(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAwU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLk9yZGVyZWREaWN0aW9uYXJ5BAAAAAtLZXlDb21wYXJlcghSZWFkT25seQ9Jbml0aWFsQ2FwYWNpdHkJQXJyYXlMaXN0AwAABSRTeXN0ZW0uQ29sbGVjdGlvbnMuSUVxdWFsaXR5Q29tcGFyZXIBCAIAAAAKAAAAAAAJAwAAABADAAAAAAAAAAs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAwU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLk9yZGVyZWREaWN0aW9uYXJ5BAAAAAtLZXlDb21wYXJlcghSZWFkT25seQ9Jbml0aWFsQ2FwYWNpdHkJQXJyYXlMaXN0AwAABSRTeXN0ZW0uQ29sbGVjdGlvbnMuSUVxdWFsaXR5Q29tcGFyZXIBCAIAAAAKAAAAAAAJAwAAABADAAAAAAAAAAs=" } };
- yield return new object[] { new OrderedDictionary(17, EqualityComparer<object>.Default), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAwU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLk9yZGVyZWREaWN0aW9uYXJ5BAAAAAtLZXlDb21wYXJlcghSZWFkT25seQ9Jbml0aWFsQ2FwYWNpdHkJQXJyYXlMaXN0AwAABZEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uT2JqZWN0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEIAgAAAAkDAAAAABEAAAAJBAAAAAQDAAAAkQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5PYmplY3RFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5PYmplY3QsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAABAEAAAAAAAAAAs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAwU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLk9yZGVyZWREaWN0aW9uYXJ5BAAAAAtLZXlDb21wYXJlcghSZWFkT25seQ9Jbml0aWFsQ2FwYWNpdHkJQXJyYXlMaXN0AwAABZEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uT2JqZWN0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEIAgAAAAkDAAAAABEAAAAJBAAAAAQDAAAAkQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5PYmplY3RFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5PYmplY3QsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAABAEAAAAAAAAAAs=" } };
-
- yield return new object[] { new ListDictionary(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5BAAAAARoZWFkB3ZlcnNpb24FY291bnQIY29tcGFyZXIEAAADPFN5c3RlbS5Db2xsZWN0aW9ucy5TcGVjaWFsaXplZC5MaXN0RGljdGlvbmFyeStEaWN0aW9uYXJ5Tm9kZQIAAAAICBxTeXN0ZW0uQ29sbGVjdGlvbnMuSUNvbXBhcmVyAgAAAAoAAAAAAAAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5BAAAAARoZWFkB3ZlcnNpb24FY291bnQIY29tcGFyZXIEAAADPFN5c3RlbS5Db2xsZWN0aW9ucy5TcGVjaWFsaXplZC5MaXN0RGljdGlvbmFyeStEaWN0aW9uYXJ5Tm9kZQIAAAAICBxTeXN0ZW0uQ29sbGVjdGlvbnMuSUNvbXBhcmVyAgAAAAoAAAAAAAAAAAoL" } };
- yield return new object[] { new ListDictionary(Comparer.DefaultInvariant), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5BAAAAARoZWFkB3ZlcnNpb24FY291bnQIY29tcGFyZXIEAAADPFN5c3RlbS5Db2xsZWN0aW9ucy5TcGVjaWFsaXplZC5MaXN0RGljdGlvbmFyeStEaWN0aW9uYXJ5Tm9kZQIAAAAICBtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXICAAAACgAAAAAAAAAACQMAAAAEAwAAABtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXIBAAAAC0NvbXBhcmVJbmZvAyBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwkEAAAABAQAAAAgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8DAAAABm1fbmFtZQ1tX1NvcnRWZXJzaW9uB2N1bHR1cmUBAwAgU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24IBgUAAAAACn8AAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5BAAAAARoZWFkB3ZlcnNpb24FY291bnQIY29tcGFyZXIEAAADPFN5c3RlbS5Db2xsZWN0aW9ucy5TcGVjaWFsaXplZC5MaXN0RGljdGlvbmFyeStEaWN0aW9uYXJ5Tm9kZQIAAAAICBtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXICAAAACgAAAAAAAAAACQMAAAAEAwAAABtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXIBAAAAC0NvbXBhcmVJbmZvAyBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwkEAAAABAQAAAAgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8EAAAABm1fbmFtZQl3aW4zMkxDSUQHY3VsdHVyZQ1tX1NvcnRWZXJzaW9uAQAAAwgIIFN5c3RlbS5HbG9iYWxpemF0aW9uLlNvcnRWZXJzaW9uBgUAAAAAAAAAAH8AAAAKCw==" } };
- yield return new object[] { new HybridDictionary(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkh5YnJpZERpY3Rpb25hcnkDAAAABGxpc3QJaGFzaHRhYmxlD2Nhc2VJbnNlbnNpdGl2ZQQDAC1TeXN0ZW0uQ29sbGVjdGlvbnMuU3BlY2lhbGl6ZWQuTGlzdERpY3Rpb25hcnkCAAAAHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUBAgAAAAoKAAs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkh5YnJpZERpY3Rpb25hcnkDAAAABGxpc3QJaGFzaHRhYmxlD2Nhc2VJbnNlbnNpdGl2ZQQDAC1TeXN0ZW0uQ29sbGVjdGlvbnMuU3BlY2lhbGl6ZWQuTGlzdERpY3Rpb25hcnkCAAAAHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUBAgAAAAoKAAs=" } };
- yield return new object[] { new HybridDictionary(127, true), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkh5YnJpZERpY3Rpb25hcnkDAAAABGxpc3QJaGFzaHRhYmxlD2Nhc2VJbnNlbnNpdGl2ZQQDAC1TeXN0ZW0uQ29sbGVjdGlvbnMuU3BlY2lhbGl6ZWQuTGlzdERpY3Rpb25hcnkCAAAAHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUBAgAAAAoJAwAAAAEEAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBZTeXN0ZW0uT3JkaW5hbENvbXBhcmVyCOxROD8AAAAACQQAAADFAAAACQUAAAAJBgAAAAQEAAAAFlN5c3RlbS5PcmRpbmFsQ29tcGFyZXIBAAAAC19pZ25vcmVDYXNlAAEBEAUAAAAAAAAAEAYAAAAAAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkh5YnJpZERpY3Rpb25hcnkDAAAABGxpc3QJaGFzaHRhYmxlD2Nhc2VJbnNlbnNpdGl2ZQQDAC1TeXN0ZW0uQ29sbGVjdGlvbnMuU3BlY2lhbGl6ZWQuTGlzdERpY3Rpb25hcnkCAAAAHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUBAgAAAAoJAwAAAAEEAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBZTeXN0ZW0uT3JkaW5hbENvbXBhcmVyCOxROD8AAAAACQQAAADFAAAACQUAAAAJBgAAAAQEAAAAFlN5c3RlbS5PcmRpbmFsQ29tcGFyZXIBAAAAC19pZ25vcmVDYXNlAAEBEAUAAAAAAAAAEAYAAAAAAAAACw==" } };
-
- yield return new object[] { new ObservableCollection<int>(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACF9tb25pdG9yEkNvbGxlY3Rpb25gMStpdGVtcwQDoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACQMAAAAJBAAAAAUDAAAAoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAApfYnVzeUNvdW50AAgCAAAAAAAAAAQEAAAAflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBwAACAgICQUAAAAAAAAAAAAAAA8FAAAAAAAAAAgL", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACF9tb25pdG9yEkNvbGxlY3Rpb25gMStpdGVtcwQDoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACQMAAAAJBAAAAAUDAAAAoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAApfYnVzeUNvdW50AAgCAAAAAAAAAAQEAAAAflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBwAACAgICQUAAAAAAAAAAAAAAA8FAAAAAAAAAAgL" } };
+ yield return new object[] { new BindingList<int>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACAAVN5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAlhZGROZXdQb3MWcmFpc2VMaXN0Q2hhbmdlZEV2ZW50cxZyYWlzZUl0ZW1DaGFuZ2VkRXZlbnRzCGFsbG93TmV3CWFsbG93RWRpdAthbGxvd1JlbW92ZQ91c2VyU2V0QWxsb3dOZXcSQ29sbGVjdGlvbmAxK2l0ZW1zAAAAAAAAAAMIAQEBAQEBflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAD/////AQABAQEACQMAAAAEAwAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkEAAAAAAAAAAAAAAAPBAAAAAAAAAAICw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACAAVN5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAlhZGROZXdQb3MWcmFpc2VMaXN0Q2hhbmdlZEV2ZW50cxZyYWlzZUl0ZW1DaGFuZ2VkRXZlbnRzCGFsbG93TmV3CWFsbG93RWRpdAthbGxvd1JlbW92ZQ91c2VyU2V0QWxsb3dOZXcSQ29sbGVjdGlvbmAxK2l0ZW1zAAAAAAAAAAMIAQEBAQEBflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAD/////AQABAQEACQMAAAAEAwAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgcAAAgICAkEAAAAAAAAAAAAAAAPBAAAAAAAAAAICw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new BindingList<int>(Enumerable.Range(0, 123).ToArray()), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACAAVN5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAlhZGROZXdQb3MWcmFpc2VMaXN0Q2hhbmdlZEV2ZW50cxZyYWlzZUl0ZW1DaGFuZ2VkRXZlbnRzCGFsbG93TmV3CWFsbG93RWRpdAthbGxvd1JlbW92ZQ91c2VyU2V0QWxsb3dOZXcSQ29sbGVjdGlvbmAxK2l0ZW1zAAAAAAAAAAMIAQEBAQEBDlN5c3RlbS5JbnQzMltdAgAAAP////8BAAEBAQAJAwAAAA8DAAAAewAAAAgAAAAAAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAASAAAAEwAAABQAAAAVAAAAFgAAABcAAAAYAAAAGQAAABoAAAAbAAAAHAAAAB0AAAAeAAAAHwAAACAAAAAhAAAAIgAAACMAAAAkAAAAJQAAACYAAAAnAAAAKAAAACkAAAAqAAAAKwAAACwAAAAtAAAALgAAAC8AAAAwAAAAMQAAADIAAAAzAAAANAAAADUAAAA2AAAANwAAADgAAAA5AAAAOgAAADsAAAA8AAAAPQAAAD4AAAA/AAAAQAAAAEEAAABCAAAAQwAAAEQAAABFAAAARgAAAEcAAABIAAAASQAAAEoAAABLAAAATAAAAE0AAABOAAAATwAAAFAAAABRAAAAUgAAAFMAAABUAAAAVQAAAFYAAABXAAAAWAAAAFkAAABaAAAAWwAAAFwAAABdAAAAXgAAAF8AAABgAAAAYQAAAGIAAABjAAAAZAAAAGUAAABmAAAAZwAAAGgAAABpAAAAagAAAGsAAABsAAAAbQAAAG4AAABvAAAAcAAAAHEAAAByAAAAcwAAAHQAAAB1AAAAdgAAAHcAAAB4AAAAeQAAAHoAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACAAVN5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAlhZGROZXdQb3MWcmFpc2VMaXN0Q2hhbmdlZEV2ZW50cxZyYWlzZUl0ZW1DaGFuZ2VkRXZlbnRzCGFsbG93TmV3CWFsbG93RWRpdAthbGxvd1JlbW92ZQ91c2VyU2V0QWxsb3dOZXcSQ29sbGVjdGlvbmAxK2l0ZW1zAAAAAAAAAAMIAQEBAQEBDlN5c3RlbS5JbnQzMltdAgAAAP////8BAAEBAQAJAwAAAA8DAAAAewAAAAgAAAAAAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAASAAAAEwAAABQAAAAVAAAAFgAAABcAAAAYAAAAGQAAABoAAAAbAAAAHAAAAB0AAAAeAAAAHwAAACAAAAAhAAAAIgAAACMAAAAkAAAAJQAAACYAAAAnAAAAKAAAACkAAAAqAAAAKwAAACwAAAAtAAAALgAAAC8AAAAwAAAAMQAAADIAAAAzAAAANAAAADUAAAA2AAAANwAAADgAAAA5AAAAOgAAADsAAAA8AAAAPQAAAD4AAAA/AAAAQAAAAEEAAABCAAAAQwAAAEQAAABFAAAARgAAAEcAAABIAAAASQAAAEoAAABLAAAATAAAAE0AAABOAAAATwAAAFAAAABRAAAAUgAAAFMAAABUAAAAVQAAAFYAAABXAAAAWAAAAFkAAABaAAAAWwAAAFwAAABdAAAAXgAAAF8AAABgAAAAYQAAAGIAAABjAAAAZAAAAGUAAABmAAAAZwAAAGgAAABpAAAAagAAAGsAAABsAAAAbQAAAG4AAABvAAAAcAAAAHEAAAByAAAAcwAAAHQAAAB1AAAAdgAAAHcAAAB4AAAAeQAAAHoAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new BindingList<int>(new int[] { 5, 7, 9 }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACAAVN5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAlhZGROZXdQb3MWcmFpc2VMaXN0Q2hhbmdlZEV2ZW50cxZyYWlzZUl0ZW1DaGFuZ2VkRXZlbnRzCGFsbG93TmV3CWFsbG93RWRpdAthbGxvd1JlbW92ZQ91c2VyU2V0QWxsb3dOZXcSQ29sbGVjdGlvbmAxK2l0ZW1zAAAAAAAAAAMIAQEBAQEBDlN5c3RlbS5JbnQzMltdAgAAAP////8BAAEBAQAJAwAAAA8DAAAAAwAAAAgFAAAABwAAAAkAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACAAVN5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAlhZGROZXdQb3MWcmFpc2VMaXN0Q2hhbmdlZEV2ZW50cxZyYWlzZUl0ZW1DaGFuZ2VkRXZlbnRzCGFsbG93TmV3CWFsbG93RWRpdAthbGxvd1JlbW92ZQ91c2VyU2V0QWxsb3dOZXcSQ29sbGVjdGlvbmAxK2l0ZW1zAAAAAAAAAAMIAQEBAQEBDlN5c3RlbS5JbnQzMltdAgAAAP////8BAAEBAQAJAwAAAA8DAAAAAwAAAAgFAAAABwAAAAkAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new BindingList<Point>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADMAVN5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQgAAAAJYWRkTmV3UG9zFnJhaXNlTGlzdENoYW5nZWRFdmVudHMWcmFpc2VJdGVtQ2hhbmdlZEV2ZW50cwhhbGxvd05ldwlhbGxvd0VkaXQLYWxsb3dSZW1vdmUPdXNlclNldEFsbG93TmV3EkNvbGxlY3Rpb25gMStpdGVtcwAAAAAAAAADCAEBAQEBAcoBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQIAAAD/////AQAAAQEACQMAAAAMBAAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAMAAADKAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgQAADVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQQAAAAICAkFAAAAAAAAAAAAAAAHBQAAAAABAAAAAAAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50BAAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADMAVN5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQgAAAAJYWRkTmV3UG9zFnJhaXNlTGlzdENoYW5nZWRFdmVudHMWcmFpc2VJdGVtQ2hhbmdlZEV2ZW50cwhhbGxvd05ldwlhbGxvd0VkaXQLYWxsb3dSZW1vdmUPdXNlclNldEFsbG93TmV3EkNvbGxlY3Rpb25gMStpdGVtcwAAAAAAAAADCAEBAQEBAcoBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQIAAAD/////AQAAAQEACQMAAAAMBAAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAMAAADKAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgQAADVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQQAAAAICAkFAAAAAAAAAAAAAAAHBQAAAAABAAAAAAAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50BAAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new BindingList<Point>(new Point[] { new Point(1, 2), new Point(4, 3) }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAAzAFTeXN0ZW0uQ29tcG9uZW50TW9kZWwuQmluZGluZ0xpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0IAAAACWFkZE5ld1BvcxZyYWlzZUxpc3RDaGFuZ2VkRXZlbnRzFnJhaXNlSXRlbUNoYW5nZWRFdmVudHMIYWxsb3dOZXcJYWxsb3dFZGl0C2FsbG93UmVtb3ZlD3VzZXJTZXRBbGxvd05ldxJDb2xsZWN0aW9uYDEraXRlbXMAAAAAAAAABAgBAQEBAQE1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10DAAAAAgAAAP////8BAAABAQAJBAAAAAcEAAAAAAEAAAACAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQDAAAACQUAAAAJBgAAAAUFAAAAM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAIAAAABWAFZAAAICAMAAAABAAAAAgAAAAEGAAAABQAAAAQAAAADAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAAzAFTeXN0ZW0uQ29tcG9uZW50TW9kZWwuQmluZGluZ0xpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0IAAAACWFkZE5ld1BvcxZyYWlzZUxpc3RDaGFuZ2VkRXZlbnRzFnJhaXNlSXRlbUNoYW5nZWRFdmVudHMIYWxsb3dOZXcJYWxsb3dFZGl0C2FsbG93UmVtb3ZlD3VzZXJTZXRBbGxvd05ldxJDb2xsZWN0aW9uYDEraXRlbXMAAAAAAAAABAgBAQEBAQE1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10DAAAAAgAAAP////8BAAABAQAJBAAAAAcEAAAAAAEAAAACAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQDAAAACQUAAAAJBgAAAAUFAAAAM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAIAAAABWAFZAAAICAMAAAABAAAAAgAAAAEGAAAABQAAAAQAAAADAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new BindingList<Tuple<int, Graph<int>>>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADmA1N5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgAAAAJYWRkTmV3UG9zFnJhaXNlTGlzdENoYW5nZWRFdmVudHMWcmFpc2VJdGVtQ2hhbmdlZEV2ZW50cwhhbGxvd05ldwlhbGxvd0VkaXQLYWxsb3dSZW1vdmUPdXNlclNldEFsbG93TmV3EkNvbGxlY3Rpb25gMStpdGVtcwAAAAAAAAADCAEBAQEBAeQDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAD/////AQAAAQEACQMAAAAEAwAAAOQDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uAwAA9AJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dW10ICAkEAAAAAAAAAAAAAAAHBAAAAAABAAAAAAAAAAPyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0L", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADmA1N5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgAAAAJYWRkTmV3UG9zFnJhaXNlTGlzdENoYW5nZWRFdmVudHMWcmFpc2VJdGVtQ2hhbmdlZEV2ZW50cwhhbGxvd05ldwlhbGxvd0VkaXQLYWxsb3dSZW1vdmUPdXNlclNldEFsbG93TmV3EkNvbGxlY3Rpb25gMStpdGVtcwAAAAAAAAADCAEBAQEBAeQDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAD/////AQAAAQEACQMAAAAEAwAAAOQDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uAwAA9AJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dW10ICAkEAAAAAAAAAAAAAAAHBAAAAAABAAAAAAAAAAPyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0L", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new BindingList<Tuple<int, Graph<int>>>(new Tuple<int, Graph<int>>[] { Tuple.Create(1, new Graph<int>()), Tuple.Create(5, new Graph<int>()) }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADmA1N5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgAAAAJYWRkTmV3UG9zFnJhaXNlTGlzdENoYW5nZWRFdmVudHMWcmFpc2VJdGVtQ2hhbmdlZEV2ZW50cwhhbGxvd05ldwlhbGxvd0VkaXQLYWxsb3dSZW1vdmUPdXNlclNldEFsbG93TmV3EkNvbGxlY3Rpb25gMStpdGVtcwAAAAAAAAADCAEBAQEBAfQCU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdAgAAAP////8BAAABAQAJAwAAAAcDAAAAAAEAAAACAAAAA/ICU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQkEAAAACQUAAAAMBgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAQAAADyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAB21fSXRlbTEHbV9JdGVtMgAECJIBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0GAAAAAQAAAAkHAAAAAQUAAAAEAAAABQAAAAkIAAAABQcAAACSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAVWYWx1ZQVMaW5rcwAECJQBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV1bXQYAAAAGAAAAAAAAAAoBCAAAAAcAAAAAAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADmA1N5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgAAAAJYWRkTmV3UG9zFnJhaXNlTGlzdENoYW5nZWRFdmVudHMWcmFpc2VJdGVtQ2hhbmdlZEV2ZW50cwhhbGxvd05ldwlhbGxvd0VkaXQLYWxsb3dSZW1vdmUPdXNlclNldEFsbG93TmV3EkNvbGxlY3Rpb25gMStpdGVtcwAAAAAAAAADCAEBAQEBAfQCU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdAgAAAP////8BAAABAQAJAwAAAAcDAAAAAAEAAAACAAAAA/ICU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQkEAAAACQUAAAAMBgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAQAAADyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAB21fSXRlbTEHbV9JdGVtMgAECJIBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0GAAAAAQAAAAkHAAAAAQUAAAAEAAAABQAAAAkIAAAABQcAAACSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAVWYWx1ZQVMaW5rcwAECJQBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV1bXQYAAAAGAAAAAAAAAAoBCAAAAAcAAAAAAAAACgs=", TargetFrameworkMoniker.netfx461) } };
+
+ yield return new object[] { new StringDictionary(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLlN0cmluZ0RpY3Rpb25hcnkBAAAACGNvbnRlbnRzAxxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlAgAAAAkDAAAABAMAAAAcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQcAAAAKTG9hZEZhY3RvcgdWZXJzaW9uCENvbXBhcmVyEEhhc2hDb2RlUHJvdmlkZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMDAAUFCwgcU3lzdGVtLkNvbGxlY3Rpb25zLklDb21wYXJlciRTeXN0ZW0uQ29sbGVjdGlvbnMuSUhhc2hDb2RlUHJvdmlkZXII7FE4PwAAAAAKCgMAAAAJBAAAAAkFAAAAEAQAAAAAAAAAEAUAAAAAAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLlN0cmluZ0RpY3Rpb25hcnkBAAAACGNvbnRlbnRzAxxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlAgAAAAkDAAAABAMAAAAcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQcAAAAKTG9hZEZhY3RvcgdWZXJzaW9uCENvbXBhcmVyEEhhc2hDb2RlUHJvdmlkZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMDAAUFCwgcU3lzdGVtLkNvbGxlY3Rpb25zLklDb21wYXJlciRTeXN0ZW0uQ29sbGVjdGlvbnMuSUhhc2hDb2RlUHJvdmlkZXII7FE4PwAAAAAKCgMAAAAJBAAAAAkFAAAAEAQAAAAAAAAAEAUAAAAAAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new StringCollection(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLlN0cmluZ0NvbGxlY3Rpb24BAAAABGRhdGEDHFN5c3RlbS5Db2xsZWN0aW9ucy5BcnJheUxpc3QCAAAACQMAAAAEAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkEAAAAAAAAAAAAAAAQBAAAAAAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLlN0cmluZ0NvbGxlY3Rpb24BAAAABGRhdGEDHFN5c3RlbS5Db2xsZWN0aW9ucy5BcnJheUxpc3QCAAAACQMAAAAEAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkEAAAAAAAAAAAAAAAQBAAAAAAAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new OrderedDictionary(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAwU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLk9yZGVyZWREaWN0aW9uYXJ5BAAAAAtLZXlDb21wYXJlcghSZWFkT25seQ9Jbml0aWFsQ2FwYWNpdHkJQXJyYXlMaXN0AwAABSRTeXN0ZW0uQ29sbGVjdGlvbnMuSUVxdWFsaXR5Q29tcGFyZXIBCAIAAAAKAAAAAAAJAwAAABADAAAAAAAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAwU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLk9yZGVyZWREaWN0aW9uYXJ5BAAAAAtLZXlDb21wYXJlcghSZWFkT25seQ9Jbml0aWFsQ2FwYWNpdHkJQXJyYXlMaXN0AwAABSRTeXN0ZW0uQ29sbGVjdGlvbnMuSUVxdWFsaXR5Q29tcGFyZXIBCAIAAAAKAAAAAAAJAwAAABADAAAAAAAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new OrderedDictionary(17, EqualityComparer<object>.Default), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAwU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLk9yZGVyZWREaWN0aW9uYXJ5BAAAAAtLZXlDb21wYXJlcghSZWFkT25seQ9Jbml0aWFsQ2FwYWNpdHkJQXJyYXlMaXN0AwAABZEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uT2JqZWN0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEIAgAAAAkDAAAAABEAAAAJBAAAAAQDAAAAkQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5PYmplY3RFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5PYmplY3QsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAABAEAAAAAAAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAwU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLk9yZGVyZWREaWN0aW9uYXJ5BAAAAAtLZXlDb21wYXJlcghSZWFkT25seQ9Jbml0aWFsQ2FwYWNpdHkJQXJyYXlMaXN0AwAABZEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuT2JqZWN0RXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uT2JqZWN0LCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEIAgAAAAkDAAAAABEAAAAJBAAAAAQDAAAAkQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5PYmplY3RFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5PYmplY3QsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAABAEAAAAAAAAAAs=", TargetFrameworkMoniker.netfx461) } };
+
+ yield return new object[] { new ListDictionary(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5BAAAAARoZWFkB3ZlcnNpb24FY291bnQIY29tcGFyZXIEAAADPFN5c3RlbS5Db2xsZWN0aW9ucy5TcGVjaWFsaXplZC5MaXN0RGljdGlvbmFyeStEaWN0aW9uYXJ5Tm9kZQIAAAAICBxTeXN0ZW0uQ29sbGVjdGlvbnMuSUNvbXBhcmVyAgAAAAoAAAAAAAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5BAAAAARoZWFkB3ZlcnNpb24FY291bnQIY29tcGFyZXIEAAADPFN5c3RlbS5Db2xsZWN0aW9ucy5TcGVjaWFsaXplZC5MaXN0RGljdGlvbmFyeStEaWN0aW9uYXJ5Tm9kZQIAAAAICBxTeXN0ZW0uQ29sbGVjdGlvbnMuSUNvbXBhcmVyAgAAAAoAAAAAAAAAAAoL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new ListDictionary(Comparer.DefaultInvariant), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5BAAAAARoZWFkB3ZlcnNpb24FY291bnQIY29tcGFyZXIEAAADPFN5c3RlbS5Db2xsZWN0aW9ucy5TcGVjaWFsaXplZC5MaXN0RGljdGlvbmFyeStEaWN0aW9uYXJ5Tm9kZQIAAAAICBtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXICAAAACgAAAAAAAAAACQMAAAAEAwAAABtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXIBAAAAC0NvbXBhcmVJbmZvAyBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwkEAAAABAQAAAAgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8DAAAABm1fbmFtZQ1tX1NvcnRWZXJzaW9uB2N1bHR1cmUBAwAgU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24IBgUAAAAACn8AAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5BAAAAARoZWFkB3ZlcnNpb24FY291bnQIY29tcGFyZXIEAAADPFN5c3RlbS5Db2xsZWN0aW9ucy5TcGVjaWFsaXplZC5MaXN0RGljdGlvbmFyeStEaWN0aW9uYXJ5Tm9kZQIAAAAICBtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXICAAAACgAAAAAAAAAACQMAAAAEAwAAABtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXIBAAAAC0NvbXBhcmVJbmZvAyBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwkEAAAABAQAAAAgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8EAAAABm1fbmFtZQl3aW4zMkxDSUQHY3VsdHVyZQ1tX1NvcnRWZXJzaW9uAQAAAwgIIFN5c3RlbS5HbG9iYWxpemF0aW9uLlNvcnRWZXJzaW9uBgUAAAAAAAAAAH8AAAAKCw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new HybridDictionary(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkh5YnJpZERpY3Rpb25hcnkDAAAABGxpc3QJaGFzaHRhYmxlD2Nhc2VJbnNlbnNpdGl2ZQQDAC1TeXN0ZW0uQ29sbGVjdGlvbnMuU3BlY2lhbGl6ZWQuTGlzdERpY3Rpb25hcnkCAAAAHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUBAgAAAAoKAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkh5YnJpZERpY3Rpb25hcnkDAAAABGxpc3QJaGFzaHRhYmxlD2Nhc2VJbnNlbnNpdGl2ZQQDAC1TeXN0ZW0uQ29sbGVjdGlvbnMuU3BlY2lhbGl6ZWQuTGlzdERpY3Rpb25hcnkCAAAAHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUBAgAAAAoKAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new HybridDictionary(127, true), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkh5YnJpZERpY3Rpb25hcnkDAAAABGxpc3QJaGFzaHRhYmxlD2Nhc2VJbnNlbnNpdGl2ZQQDAC1TeXN0ZW0uQ29sbGVjdGlvbnMuU3BlY2lhbGl6ZWQuTGlzdERpY3Rpb25hcnkCAAAAHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUBAgAAAAoJAwAAAAEEAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBZTeXN0ZW0uT3JkaW5hbENvbXBhcmVyCOxROD8AAAAACQQAAADFAAAACQUAAAAJBgAAAAQEAAAAFlN5c3RlbS5PcmRpbmFsQ29tcGFyZXIBAAAAC19pZ25vcmVDYXNlAAEBEAUAAAAAAAAAEAYAAAAAAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkh5YnJpZERpY3Rpb25hcnkDAAAABGxpc3QJaGFzaHRhYmxlD2Nhc2VJbnNlbnNpdGl2ZQQDAC1TeXN0ZW0uQ29sbGVjdGlvbnMuU3BlY2lhbGl6ZWQuTGlzdERpY3Rpb25hcnkCAAAAHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUBAgAAAAoJAwAAAAEEAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBZTeXN0ZW0uT3JkaW5hbENvbXBhcmVyCOxROD8AAAAACQQAAADFAAAACQUAAAAJBgAAAAQEAAAAFlN5c3RlbS5PcmRpbmFsQ29tcGFyZXIBAAAAC19pZ25vcmVDYXNlAAEBEAUAAAAAAAAAEAYAAAAAAAAACw==", TargetFrameworkMoniker.netfx461) } };
+
+ yield return new object[] { new ObservableCollection<int>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACF9tb25pdG9yEkNvbGxlY3Rpb25gMStpdGVtcwQDoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACQMAAAAJBAAAAAUDAAAAoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAApfYnVzeUNvdW50AAgCAAAAAAAAAAQEAAAAflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBwAACAgICQUAAAAAAAAAAAAAAA8FAAAAAAAAAAgL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACF9tb25pdG9yEkNvbGxlY3Rpb25gMStpdGVtcwQDoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACQMAAAAJBAAAAAUDAAAAoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAApfYnVzeUNvdW50AAgCAAAAAAAAAAQEAAAAflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBwAACAgICQUAAAAAAAAAAAAAAA8FAAAAAAAAAAgL", TargetFrameworkMoniker.netfx461) } };
// Passing an array to the IEnumerable cosntructor to hit its ICollection optimization, which causes all runtimes to
// produce the same internal state. Otherwise, they come up with different _version values
- yield return new object[] { new ObservableCollection<int>(Enumerable.Range(0, 123).ToArray()), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACF9tb25pdG9yEkNvbGxlY3Rpb25gMStpdGVtcwQDoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACQMAAAAJBAAAAAUDAAAAoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAApfYnVzeUNvdW50AAgCAAAAAAAAAAQEAAAAflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBwAACAgICQUAAAB7AAAAAAAAAA8FAAAAewAAAAgAAAAAAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAASAAAAEwAAABQAAAAVAAAAFgAAABcAAAAYAAAAGQAAABoAAAAbAAAAHAAAAB0AAAAeAAAAHwAAACAAAAAhAAAAIgAAACMAAAAkAAAAJQAAACYAAAAnAAAAKAAAACkAAAAqAAAAKwAAACwAAAAtAAAALgAAAC8AAAAwAAAAMQAAADIAAAAzAAAANAAAADUAAAA2AAAANwAAADgAAAA5AAAAOgAAADsAAAA8AAAAPQAAAD4AAAA/AAAAQAAAAEEAAABCAAAAQwAAAEQAAABFAAAARgAAAEcAAABIAAAASQAAAEoAAABLAAAATAAAAE0AAABOAAAATwAAAFAAAABRAAAAUgAAAFMAAABUAAAAVQAAAFYAAABXAAAAWAAAAFkAAABaAAAAWwAAAFwAAABdAAAAXgAAAF8AAABgAAAAYQAAAGIAAABjAAAAZAAAAGUAAABmAAAAZwAAAGgAAABpAAAAagAAAGsAAABsAAAAbQAAAG4AAABvAAAAcAAAAHEAAAByAAAAcwAAAHQAAAB1AAAAdgAAAHcAAAB4AAAAeQAAAHoAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACF9tb25pdG9yEkNvbGxlY3Rpb25gMStpdGVtcwQDoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACQMAAAAJBAAAAAUDAAAAoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAApfYnVzeUNvdW50AAgCAAAAAAAAAAQEAAAAflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBwAACAgICQUAAAB7AAAAewAAAA8FAAAAgAAAAAgAAAAAAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAASAAAAEwAAABQAAAAVAAAAFgAAABcAAAAYAAAAGQAAABoAAAAbAAAAHAAAAB0AAAAeAAAAHwAAACAAAAAhAAAAIgAAACMAAAAkAAAAJQAAACYAAAAnAAAAKAAAACkAAAAqAAAAKwAAACwAAAAtAAAALgAAAC8AAAAwAAAAMQAAADIAAAAzAAAANAAAADUAAAA2AAAANwAAADgAAAA5AAAAOgAAADsAAAA8AAAAPQAAAD4AAAA/AAAAQAAAAEEAAABCAAAAQwAAAEQAAABFAAAARgAAAEcAAABIAAAASQAAAEoAAABLAAAATAAAAE0AAABOAAAATwAAAFAAAABRAAAAUgAAAFMAAABUAAAAVQAAAFYAAABXAAAAWAAAAFkAAABaAAAAWwAAAFwAAABdAAAAXgAAAF8AAABgAAAAYQAAAGIAAABjAAAAZAAAAGUAAABmAAAAZwAAAGgAAABpAAAAagAAAGsAAABsAAAAbQAAAG4AAABvAAAAcAAAAHEAAAByAAAAcwAAAHQAAAB1AAAAdgAAAHcAAAB4AAAAeQAAAHoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs=" } };
- yield return new object[] { new ObservableCollection<int>(new int[] { 5, 7, 9 }), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACF9tb25pdG9yEkNvbGxlY3Rpb25gMStpdGVtcwQDoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACQMAAAAJBAAAAAUDAAAAoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAApfYnVzeUNvdW50AAgCAAAAAAAAAAQEAAAAflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBwAACAgICQUAAAADAAAAAAAAAA8FAAAAAwAAAAgFAAAABwAAAAkAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACF9tb25pdG9yEkNvbGxlY3Rpb25gMStpdGVtcwQDoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACQMAAAAJBAAAAAUDAAAAoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAApfYnVzeUNvdW50AAgCAAAAAAAAAAQEAAAAflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBwAACAgICQUAAAADAAAAAwAAAA8FAAAABAAAAAgFAAAABwAAAAkAAAAAAAAACw==" } };
- yield return new object[] { new ObservableCollection<Point>(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAN4BU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAhfbW9uaXRvchJDb2xsZWN0aW9uYDEraXRlbXMEA+wBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAkDAAAACQQAAAAFAwAAAOwBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0BAAAACl9idXN5Q291bnQACAIAAAAAAAAADAUAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgQEAAAAygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24EAAA1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10FAAAACAgJBgAAAAAAAAAAAAAABwYAAAAAAQAAAAAAAAAEM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAUAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAN4BU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAhfbW9uaXRvchJDb2xsZWN0aW9uYDEraXRlbXMEA+wBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAkDAAAACQQAAAAFAwAAAOwBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0BAAAACl9idXN5Q291bnQACAIAAAAAAAAADAUAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgQEAAAAygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24EAAA1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10FAAAACAgJBgAAAAAAAAAAAAAABwYAAAAAAQAAAAAAAAAEM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAUAAAAL" } };
- yield return new object[] { new ObservableCollection<Point>(new Point[] { new Point(1, 2), new Point(4, 3) }), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAN4BU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAhfbW9uaXRvchJDb2xsZWN0aW9uYDEraXRlbXMEA+wBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAkDAAAACQQAAAAFAwAAAOwBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0BAAAACl9idXN5Q291bnQACAIAAAAAAAAADAUAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgQEAAAAygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24EAAA1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10FAAAACAgJBgAAAAIAAAAAAAAABwYAAAAAAQAAAAIAAAAEM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAUAAAAJBwAAAAkIAAAABQcAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIBQAAAAEAAAACAAAAAQgAAAAHAAAABAAAAAMAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAN4BU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAhfbW9uaXRvchJDb2xsZWN0aW9uYDEraXRlbXMEA+wBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAkDAAAACQQAAAAFAwAAAOwBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0BAAAACl9idXN5Q291bnQACAIAAAAAAAAADAUAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgQEAAAAygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24EAAA1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10FAAAACAgJBgAAAAIAAAACAAAABwYAAAAAAQAAAAQAAAAEM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAUAAAAJBwAAAAkIAAAADQIFBwAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgFAAAAAQAAAAIAAAABCAAAAAcAAAAEAAAAAwAAAAs=" } };
- yield return new object[] { new ObservableCollection<Tuple<int, Graph<int>>>(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAPgDU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAhfbW9uaXRvchJDb2xsZWN0aW9uYDEraXRlbXMEA4YEU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAA5ANTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAkDAAAACQQAAAAFAwAAAIYEU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAACl9idXN5Q291bnQACAIAAAAAAAAABAQAAADkA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgMAAPQCU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdCAgJBQAAAAAAAAAAAAAABwUAAAAAAQAAAAAAAAAD8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAPgDU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAhfbW9uaXRvchJDb2xsZWN0aW9uYDEraXRlbXMEA4YEU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAA5ANTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAkDAAAACQQAAAAFAwAAAIYEU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAACl9idXN5Q291bnQACAIAAAAAAAAABAQAAADkA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgMAAPQCU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdCAgJBQAAAAAAAAAAAAAABwUAAAAAAQAAAAAAAAAD8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCw==" } };
- yield return new object[] { new ObservableCollection<Tuple<int, Graph<int>>>(new Tuple<int, Graph<int>>[] { Tuple.Create(1, new Graph<int>()), Tuple.Create(5, new Graph<int>()) }), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAPgDU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAhfbW9uaXRvchJDb2xsZWN0aW9uYDEraXRlbXMEA4YEU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAA5ANTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAkDAAAACQQAAAAFAwAAAIYEU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAACl9idXN5Q291bnQACAIAAAAAAAAABAQAAADkA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgMAAPQCU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdCAgJBQAAAAIAAAAAAAAABwUAAAAAAQAAAAIAAAAD8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCQYAAAAJBwAAAAwIAAAAcFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWIEBgAAAPICU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQIAAAAHbV9JdGVtMQdtX0l0ZW0yAAQIkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgAAAABAAAACQkAAAABBwAAAAYAAAAFAAAACQoAAAAFCQAAAJIBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAABVZhbHVlBUxpbmtzAAQIlAFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXVtdCAAAAAgAAAAAAAAACgEKAAAACQAAAAAAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAPgDU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAhfbW9uaXRvchJDb2xsZWN0aW9uYDEraXRlbXMEA4YEU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAA5ANTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAkDAAAACQQAAAAFAwAAAIYEU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAACl9idXN5Q291bnQACAIAAAAAAAAABAQAAADkA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgMAAPQCU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdCAgJBQAAAAIAAAACAAAABwUAAAAAAQAAAAQAAAAD8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCQYAAAAJBwAAAA0CDAgAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgQGAAAA8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAdtX0l0ZW0xB21fSXRlbTIABAiSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAEAAAAJCQAAAAEHAAAABgAAAAUAAAAJCgAAAAUJAAAAkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAFVmFsdWUFTGlua3MABAiUAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dW10IAAAACAAAAAAAAAAKAQoAAAAJAAAAAAAAAAoL" } };
-
- yield return new object[] { new SimpleKeyedCollection(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABDU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlNpbXBsZUtleWVkQ29sbGVjdGlvbgUAAAAaS2V5ZWRDb2xsZWN0aW9uYDIrY29tcGFyZXIWS2V5ZWRDb2xsZWN0aW9uYDIrZGljdBpLZXllZENvbGxlY3Rpb25gMitrZXlDb3VudBtLZXllZENvbGxlY3Rpb25gMit0aHJlc2hvbGQSQ29sbGVjdGlvbmAxK2l0ZW1zAwMAAAORAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV2sAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkRpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQgIygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAkDAAAACgAAAAAAAAAACQQAAAAEAwAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAEBAAAAMoBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBAAANVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludFtdAgAAAAgICQUAAAAAAAAAAAAAAAcFAAAAAAEAAAAAAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABDU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlNpbXBsZUtleWVkQ29sbGVjdGlvbgUAAAAaS2V5ZWRDb2xsZWN0aW9uYDIrY29tcGFyZXIWS2V5ZWRDb2xsZWN0aW9uYDIrZGljdBpLZXllZENvbGxlY3Rpb25gMitrZXlDb3VudBtLZXllZENvbGxlY3Rpb25gMit0aHJlc2hvbGQSQ29sbGVjdGlvbmAxK2l0ZW1zAwMAAAORAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV2sAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkRpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQgIygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAkDAAAACgAAAAAAAAAACQQAAAAEAwAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAEBAAAAMoBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBAAANVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludFtdAgAAAAgICQUAAAAAAAAAAAAAAAcFAAAAAAEAAAAAAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAACw==" } };
-
- yield return new object[] { new Collection<int>(), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAIgBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAFaXRlbXMDflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQkCAAAABAIAAAB+U3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24HAAAICAgJAwAAAAAAAAAAAAAADwMAAAAAAAAACAs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAIgBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAFaXRlbXMDflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQkCAAAABAIAAAB+U3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24HAAAICAgJAwAAAAAAAAAAAAAADwMAAAAAAAAACAs=" } };
- yield return new object[] { new Collection<int>(Enumerable.Range(0, 123).ToArray()), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAIgBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAFaXRlbXMDDlN5c3RlbS5JbnQzMltdCQIAAAAPAgAAAHsAAAAIAAAAAAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAGwAAABwAAAAdAAAAHgAAAB8AAAAgAAAAIQAAACIAAAAjAAAAJAAAACUAAAAmAAAAJwAAACgAAAApAAAAKgAAACsAAAAsAAAALQAAAC4AAAAvAAAAMAAAADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAAADoAAAA7AAAAPAAAAD0AAAA+AAAAPwAAAEAAAABBAAAAQgAAAEMAAABEAAAARQAAAEYAAABHAAAASAAAAEkAAABKAAAASwAAAEwAAABNAAAATgAAAE8AAABQAAAAUQAAAFIAAABTAAAAVAAAAFUAAABWAAAAVwAAAFgAAABZAAAAWgAAAFsAAABcAAAAXQAAAF4AAABfAAAAYAAAAGEAAABiAAAAYwAAAGQAAABlAAAAZgAAAGcAAABoAAAAaQAAAGoAAABrAAAAbAAAAG0AAABuAAAAbwAAAHAAAABxAAAAcgAAAHMAAAB0AAAAdQAAAHYAAAB3AAAAeAAAAHkAAAB6AAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAIgBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAFaXRlbXMDDlN5c3RlbS5JbnQzMltdCQIAAAAPAgAAAHsAAAAIAAAAAAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAGwAAABwAAAAdAAAAHgAAAB8AAAAgAAAAIQAAACIAAAAjAAAAJAAAACUAAAAmAAAAJwAAACgAAAApAAAAKgAAACsAAAAsAAAALQAAAC4AAAAvAAAAMAAAADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAAADoAAAA7AAAAPAAAAD0AAAA+AAAAPwAAAEAAAABBAAAAQgAAAEMAAABEAAAARQAAAEYAAABHAAAASAAAAEkAAABKAAAASwAAAEwAAABNAAAATgAAAE8AAABQAAAAUQAAAFIAAABTAAAAVAAAAFUAAABWAAAAVwAAAFgAAABZAAAAWgAAAFsAAABcAAAAXQAAAF4AAABfAAAAYAAAAGEAAABiAAAAYwAAAGQAAABlAAAAZgAAAGcAAABoAAAAaQAAAGoAAABrAAAAbAAAAG0AAABuAAAAbwAAAHAAAABxAAAAcgAAAHMAAAB0AAAAdQAAAHYAAAB3AAAAeAAAAHkAAAB6AAAACw==" } };
- yield return new object[] { new Collection<int>(new int[] { 5, 7, 9 }), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAIgBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAFaXRlbXMDDlN5c3RlbS5JbnQzMltdCQIAAAAPAgAAAAMAAAAIBQAAAAcAAAAJAAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAIgBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAFaXRlbXMDDlN5c3RlbS5JbnQzMltdCQIAAAAPAgAAAAMAAAAIBQAAAAcAAAAJAAAACw==" } };
- yield return new object[] { new Collection<Point>(), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAANQBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0BAAAABWl0ZW1zA8oBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQkCAAAADAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgQCAAAAygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24EAAA1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10DAAAACAgJBAAAAAAAAAAAAAAABwQAAAAAAQAAAAAAAAAEM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAMAAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAANQBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0BAAAABWl0ZW1zA8oBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQkCAAAADAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgQCAAAAygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24EAAA1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10DAAAACAgJBAAAAAAAAAAAAAAABwQAAAAAAQAAAAAAAAAEM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAMAAAAL" } };
- yield return new object[] { new Collection<Point>(new Point[] { new Point(1, 2), new Point(4, 3) }), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAEAAADUAVN5c3RlbS5Db2xsZWN0aW9ucy5PYmplY3RNb2RlbC5Db2xsZWN0aW9uYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAQAAAAVpdGVtcwQ1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10CAAAACQMAAAAHAwAAAAABAAAAAgAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAkEAAAACQUAAAAFBAAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgCAAAAAQAAAAIAAAABBQAAAAQAAAAEAAAAAwAAAAs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAEAAADUAVN5c3RlbS5Db2xsZWN0aW9ucy5PYmplY3RNb2RlbC5Db2xsZWN0aW9uYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAQAAAAVpdGVtcwQ1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10CAAAACQMAAAAHAwAAAAABAAAAAgAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAkEAAAACQUAAAAFBAAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgCAAAAAQAAAAIAAAABBQAAAAQAAAAEAAAAAwAAAAs=" } };
- yield return new object[] { new Collection<Tuple<int, Graph<int>>>(), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAO4DU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAABWl0ZW1zA+QDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQkCAAAABAIAAADkA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgMAAPQCU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdCAgJAwAAAAAAAAAAAAAABwMAAAAAAQAAAAAAAAAD8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAO4DU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAABWl0ZW1zA+QDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQkCAAAABAIAAADkA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgMAAPQCU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdCAgJAwAAAAAAAAAAAAAABwMAAAAAAQAAAAAAAAAD8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCw==" } };
- yield return new object[] { new Collection<Tuple<int, Graph<int>>>(new Tuple<int, Graph<int>>[] { Tuple.Create(1, new Graph<int>()), Tuple.Create(5, new Graph<int>()) }), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAO4DU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAABWl0ZW1zA/QCU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdCQIAAAAHAgAAAAABAAAAAgAAAAPyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0JAwAAAAkEAAAADAUAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgQDAAAA8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAdtX0l0ZW0xB21fSXRlbTIABAiSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBQAAAAEAAAAJBgAAAAEEAAAAAwAAAAUAAAAJBwAAAAUGAAAAkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAFVmFsdWUFTGlua3MABAiUAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dW10FAAAABQAAAAAAAAAKAQcAAAAGAAAAAAAAAAoL", "AAEAAAD/////AQAAAAAAAAAEAQAAAO4DU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAABWl0ZW1zA/QCU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdCQIAAAAHAgAAAAABAAAAAgAAAAPyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0JAwAAAAkEAAAADAUAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgQDAAAA8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAdtX0l0ZW0xB21fSXRlbTIABAiSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBQAAAAEAAAAJBgAAAAEEAAAAAwAAAAUAAAAJBwAAAAUGAAAAkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAFVmFsdWUFTGlua3MABAiUAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dW10FAAAABQAAAAAAAAAKAQcAAAAGAAAAAAAAAAoL" } };
-
- // .NET Native bug 445667 causes a crash in reflecting over multidimensional arrays
+ yield return new object[] { new ObservableCollection<int>(Enumerable.Range(0, 123).ToArray()), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACF9tb25pdG9yEkNvbGxlY3Rpb25gMStpdGVtcwQDoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACQMAAAAJBAAAAAUDAAAAoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAApfYnVzeUNvdW50AAgCAAAAAAAAAAQEAAAAflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBwAACAgICQUAAAB7AAAAAAAAAA8FAAAAewAAAAgAAAAAAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAASAAAAEwAAABQAAAAVAAAAFgAAABcAAAAYAAAAGQAAABoAAAAbAAAAHAAAAB0AAAAeAAAAHwAAACAAAAAhAAAAIgAAACMAAAAkAAAAJQAAACYAAAAnAAAAKAAAACkAAAAqAAAAKwAAACwAAAAtAAAALgAAAC8AAAAwAAAAMQAAADIAAAAzAAAANAAAADUAAAA2AAAANwAAADgAAAA5AAAAOgAAADsAAAA8AAAAPQAAAD4AAAA/AAAAQAAAAEEAAABCAAAAQwAAAEQAAABFAAAARgAAAEcAAABIAAAASQAAAEoAAABLAAAATAAAAE0AAABOAAAATwAAAFAAAABRAAAAUgAAAFMAAABUAAAAVQAAAFYAAABXAAAAWAAAAFkAAABaAAAAWwAAAFwAAABdAAAAXgAAAF8AAABgAAAAYQAAAGIAAABjAAAAZAAAAGUAAABmAAAAZwAAAGgAAABpAAAAagAAAGsAAABsAAAAbQAAAG4AAABvAAAAcAAAAHEAAAByAAAAcwAAAHQAAAB1AAAAdgAAAHcAAAB4AAAAeQAAAHoAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACF9tb25pdG9yEkNvbGxlY3Rpb25gMStpdGVtcwQDoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACQMAAAAJBAAAAAUDAAAAoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAApfYnVzeUNvdW50AAgCAAAAAAAAAAQEAAAAflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBwAACAgICQUAAAB7AAAAewAAAA8FAAAAgAAAAAgAAAAAAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAASAAAAEwAAABQAAAAVAAAAFgAAABcAAAAYAAAAGQAAABoAAAAbAAAAHAAAAB0AAAAeAAAAHwAAACAAAAAhAAAAIgAAACMAAAAkAAAAJQAAACYAAAAnAAAAKAAAACkAAAAqAAAAKwAAACwAAAAtAAAALgAAAC8AAAAwAAAAMQAAADIAAAAzAAAANAAAADUAAAA2AAAANwAAADgAAAA5AAAAOgAAADsAAAA8AAAAPQAAAD4AAAA/AAAAQAAAAEEAAABCAAAAQwAAAEQAAABFAAAARgAAAEcAAABIAAAASQAAAEoAAABLAAAATAAAAE0AAABOAAAATwAAAFAAAABRAAAAUgAAAFMAAABUAAAAVQAAAFYAAABXAAAAWAAAAFkAAABaAAAAWwAAAFwAAABdAAAAXgAAAF8AAABgAAAAYQAAAGIAAABjAAAAZAAAAGUAAABmAAAAZwAAAGgAAABpAAAAagAAAGsAAABsAAAAbQAAAG4AAABvAAAAcAAAAHEAAAByAAAAcwAAAHQAAAB1AAAAdgAAAHcAAAB4AAAAeQAAAHoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new ObservableCollection<int>(new int[] { 5, 7, 9 }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACF9tb25pdG9yEkNvbGxlY3Rpb25gMStpdGVtcwQDoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACQMAAAAJBAAAAAUDAAAAoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAApfYnVzeUNvdW50AAgCAAAAAAAAAAQEAAAAflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBwAACAgICQUAAAADAAAAAAAAAA8FAAAAAwAAAAgFAAAABwAAAAkAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACF9tb25pdG9yEkNvbGxlY3Rpb25gMStpdGVtcwQDoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACQMAAAAJBAAAAAUDAAAAoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAApfYnVzeUNvdW50AAgCAAAAAAAAAAQEAAAAflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBwAACAgICQUAAAADAAAAAwAAAA8FAAAABAAAAAgFAAAABwAAAAkAAAAAAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new ObservableCollection<Point>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAN4BU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAhfbW9uaXRvchJDb2xsZWN0aW9uYDEraXRlbXMEA+wBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAkDAAAACQQAAAAFAwAAAOwBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0BAAAACl9idXN5Q291bnQACAIAAAAAAAAADAUAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgQEAAAAygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24EAAA1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10FAAAACAgJBgAAAAAAAAAAAAAABwYAAAAAAQAAAAAAAAAEM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAUAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAN4BU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAhfbW9uaXRvchJDb2xsZWN0aW9uYDEraXRlbXMEA+wBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAkDAAAACQQAAAAFAwAAAOwBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0BAAAACl9idXN5Q291bnQACAIAAAAAAAAADAUAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgQEAAAAygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24EAAA1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10FAAAACAgJBgAAAAAAAAAAAAAABwYAAAAAAQAAAAAAAAAEM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAUAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new ObservableCollection<Point>(new Point[] { new Point(1, 2), new Point(4, 3) }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAN4BU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAhfbW9uaXRvchJDb2xsZWN0aW9uYDEraXRlbXMEA+wBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAkDAAAACQQAAAAFAwAAAOwBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0BAAAACl9idXN5Q291bnQACAIAAAAAAAAADAUAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgQEAAAAygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24EAAA1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10FAAAACAgJBgAAAAIAAAAAAAAABwYAAAAAAQAAAAIAAAAEM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAUAAAAJBwAAAAkIAAAABQcAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIBQAAAAEAAAACAAAAAQgAAAAHAAAABAAAAAMAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAN4BU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAhfbW9uaXRvchJDb2xsZWN0aW9uYDEraXRlbXMEA+wBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAkDAAAACQQAAAAFAwAAAOwBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0BAAAACl9idXN5Q291bnQACAIAAAAAAAAADAUAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgQEAAAAygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24EAAA1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10FAAAACAgJBgAAAAIAAAACAAAABwYAAAAAAQAAAAQAAAAEM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAUAAAAJBwAAAAkIAAAADQIFBwAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgFAAAAAQAAAAIAAAABCAAAAAcAAAAEAAAAAwAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new ObservableCollection<Tuple<int, Graph<int>>>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAPgDU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAhfbW9uaXRvchJDb2xsZWN0aW9uYDEraXRlbXMEA4YEU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAA5ANTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAkDAAAACQQAAAAFAwAAAIYEU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAACl9idXN5Q291bnQACAIAAAAAAAAABAQAAADkA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgMAAPQCU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdCAgJBQAAAAAAAAAAAAAABwUAAAAAAQAAAAAAAAAD8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAPgDU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAhfbW9uaXRvchJDb2xsZWN0aW9uYDEraXRlbXMEA4YEU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAA5ANTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAkDAAAACQQAAAAFAwAAAIYEU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAACl9idXN5Q291bnQACAIAAAAAAAAABAQAAADkA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgMAAPQCU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdCAgJBQAAAAAAAAAAAAAABwUAAAAAAQAAAAAAAAAD8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new ObservableCollection<Tuple<int, Graph<int>>>(new Tuple<int, Graph<int>>[] { Tuple.Create(1, new Graph<int>()), Tuple.Create(5, new Graph<int>()) }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAPgDU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAhfbW9uaXRvchJDb2xsZWN0aW9uYDEraXRlbXMEA4YEU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAA5ANTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAkDAAAACQQAAAAFAwAAAIYEU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAACl9idXN5Q291bnQACAIAAAAAAAAABAQAAADkA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgMAAPQCU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdCAgJBQAAAAIAAAAAAAAABwUAAAAAAQAAAAIAAAAD8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCQYAAAAJBwAAAAwIAAAAcFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWIEBgAAAPICU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQIAAAAHbV9JdGVtMQdtX0l0ZW0yAAQIkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgAAAABAAAACQkAAAABBwAAAAYAAAAFAAAACQoAAAAFCQAAAJIBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAABVZhbHVlBUxpbmtzAAQIlAFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXVtdCAAAAAgAAAAAAAAACgEKAAAACQAAAAAAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAPgDU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAhfbW9uaXRvchJDb2xsZWN0aW9uYDEraXRlbXMEA4YEU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAA5ANTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAkDAAAACQQAAAAFAwAAAIYEU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDErU2ltcGxlTW9uaXRvcltbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAACl9idXN5Q291bnQACAIAAAAAAAAABAQAAADkA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgMAAPQCU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdCAgJBQAAAAIAAAACAAAABwUAAAAAAQAAAAQAAAAD8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCQYAAAAJBwAAAA0CDAgAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgQGAAAA8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAdtX0l0ZW0xB21fSXRlbTIABAiSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAEAAAAJCQAAAAEHAAAABgAAAAUAAAAJCgAAAAUJAAAAkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAFVmFsdWUFTGlua3MABAiUAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dW10IAAAACAAAAAAAAAAKAQoAAAAJAAAAAAAAAAoL", TargetFrameworkMoniker.netfx461) } };
+
+ yield return new object[] { new SimpleKeyedCollection(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABDU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlNpbXBsZUtleWVkQ29sbGVjdGlvbgUAAAAaS2V5ZWRDb2xsZWN0aW9uYDIrY29tcGFyZXIWS2V5ZWRDb2xsZWN0aW9uYDIrZGljdBpLZXllZENvbGxlY3Rpb25gMitrZXlDb3VudBtLZXllZENvbGxlY3Rpb25gMit0aHJlc2hvbGQSQ29sbGVjdGlvbmAxK2l0ZW1zAwMAAAORAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV2sAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkRpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQgIygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAkDAAAACgAAAAAAAAAACQQAAAAEAwAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAEBAAAAMoBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBAAANVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludFtdAgAAAAgICQUAAAAAAAAAAAAAAAcFAAAAAAEAAAAAAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABDU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlNpbXBsZUtleWVkQ29sbGVjdGlvbgUAAAAaS2V5ZWRDb2xsZWN0aW9uYDIrY29tcGFyZXIWS2V5ZWRDb2xsZWN0aW9uYDIrZGljdBpLZXllZENvbGxlY3Rpb25gMitrZXlDb3VudBtLZXllZENvbGxlY3Rpb25gMit0aHJlc2hvbGQSQ29sbGVjdGlvbmAxK2l0ZW1zAwMAAAORAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV2sAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkRpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQgIygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAkDAAAACgAAAAAAAAAACQQAAAAEAwAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAEBAAAAMoBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBAAANVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludFtdAgAAAAgICQUAAAAAAAAAAAAAAAcFAAAAAAEAAAAAAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAACw==", TargetFrameworkMoniker.netfx461) } };
+
+ yield return new object[] { new Collection<int>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAIgBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAFaXRlbXMDflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQkCAAAABAIAAAB+U3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24HAAAICAgJAwAAAAAAAAAAAAAADwMAAAAAAAAACAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAIgBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAFaXRlbXMDflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQkCAAAABAIAAAB+U3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24HAAAICAgJAwAAAAAAAAAAAAAADwMAAAAAAAAACAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Collection<int>(Enumerable.Range(0, 123).ToArray()), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAIgBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAFaXRlbXMDDlN5c3RlbS5JbnQzMltdCQIAAAAPAgAAAHsAAAAIAAAAAAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAGwAAABwAAAAdAAAAHgAAAB8AAAAgAAAAIQAAACIAAAAjAAAAJAAAACUAAAAmAAAAJwAAACgAAAApAAAAKgAAACsAAAAsAAAALQAAAC4AAAAvAAAAMAAAADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAAADoAAAA7AAAAPAAAAD0AAAA+AAAAPwAAAEAAAABBAAAAQgAAAEMAAABEAAAARQAAAEYAAABHAAAASAAAAEkAAABKAAAASwAAAEwAAABNAAAATgAAAE8AAABQAAAAUQAAAFIAAABTAAAAVAAAAFUAAABWAAAAVwAAAFgAAABZAAAAWgAAAFsAAABcAAAAXQAAAF4AAABfAAAAYAAAAGEAAABiAAAAYwAAAGQAAABlAAAAZgAAAGcAAABoAAAAaQAAAGoAAABrAAAAbAAAAG0AAABuAAAAbwAAAHAAAABxAAAAcgAAAHMAAAB0AAAAdQAAAHYAAAB3AAAAeAAAAHkAAAB6AAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAIgBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAFaXRlbXMDDlN5c3RlbS5JbnQzMltdCQIAAAAPAgAAAHsAAAAIAAAAAAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAGwAAABwAAAAdAAAAHgAAAB8AAAAgAAAAIQAAACIAAAAjAAAAJAAAACUAAAAmAAAAJwAAACgAAAApAAAAKgAAACsAAAAsAAAALQAAAC4AAAAvAAAAMAAAADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAAADoAAAA7AAAAPAAAAD0AAAA+AAAAPwAAAEAAAABBAAAAQgAAAEMAAABEAAAARQAAAEYAAABHAAAASAAAAEkAAABKAAAASwAAAEwAAABNAAAATgAAAE8AAABQAAAAUQAAAFIAAABTAAAAVAAAAFUAAABWAAAAVwAAAFgAAABZAAAAWgAAAFsAAABcAAAAXQAAAF4AAABfAAAAYAAAAGEAAABiAAAAYwAAAGQAAABlAAAAZgAAAGcAAABoAAAAaQAAAGoAAABrAAAAbAAAAG0AAABuAAAAbwAAAHAAAABxAAAAcgAAAHMAAAB0AAAAdQAAAHYAAAB3AAAAeAAAAHkAAAB6AAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Collection<int>(new int[] { 5, 7, 9 }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAIgBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAFaXRlbXMDDlN5c3RlbS5JbnQzMltdCQIAAAAPAgAAAAMAAAAIBQAAAAcAAAAJAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAIgBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAFaXRlbXMDDlN5c3RlbS5JbnQzMltdCQIAAAAPAgAAAAMAAAAIBQAAAAcAAAAJAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Collection<Point>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAANQBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0BAAAABWl0ZW1zA8oBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQkCAAAADAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgQCAAAAygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24EAAA1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10DAAAACAgJBAAAAAAAAAAAAAAABwQAAAAAAQAAAAAAAAAEM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAMAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAANQBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0BAAAABWl0ZW1zA8oBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQkCAAAADAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgQCAAAAygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24EAAA1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10DAAAACAgJBAAAAAAAAAAAAAAABwQAAAAAAQAAAAAAAAAEM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAMAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Collection<Point>(new Point[] { new Point(1, 2), new Point(4, 3) }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAEAAADUAVN5c3RlbS5Db2xsZWN0aW9ucy5PYmplY3RNb2RlbC5Db2xsZWN0aW9uYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAQAAAAVpdGVtcwQ1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10CAAAACQMAAAAHAwAAAAABAAAAAgAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAkEAAAACQUAAAAFBAAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgCAAAAAQAAAAIAAAABBQAAAAQAAAAEAAAAAwAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBAEAAADUAVN5c3RlbS5Db2xsZWN0aW9ucy5PYmplY3RNb2RlbC5Db2xsZWN0aW9uYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAQAAAAVpdGVtcwQ1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10CAAAACQMAAAAHAwAAAAABAAAAAgAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAkEAAAACQUAAAAFBAAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgCAAAAAQAAAAIAAAABBQAAAAQAAAAEAAAAAwAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Collection<Tuple<int, Graph<int>>>(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAO4DU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAABWl0ZW1zA+QDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQkCAAAABAIAAADkA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgMAAPQCU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdCAgJAwAAAAAAAAAAAAAABwMAAAAAAQAAAAAAAAAD8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAO4DU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAABWl0ZW1zA+QDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQkCAAAABAIAAADkA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgMAAPQCU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdCAgJAwAAAAAAAAAAAAAABwMAAAAAAQAAAAAAAAAD8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Collection<Tuple<int, Graph<int>>>(new Tuple<int, Graph<int>>[] { Tuple.Create(1, new Graph<int>()), Tuple.Create(5, new Graph<int>()) }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAO4DU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAABWl0ZW1zA/QCU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdCQIAAAAHAgAAAAABAAAAAgAAAAPyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0JAwAAAAkEAAAADAUAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgQDAAAA8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAdtX0l0ZW0xB21fSXRlbTIABAiSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBQAAAAEAAAAJBgAAAAEEAAAAAwAAAAUAAAAJBwAAAAUGAAAAkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAFVmFsdWUFTGlua3MABAiUAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dW10FAAAABQAAAAAAAAAKAQcAAAAGAAAAAAAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAO4DU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAABWl0ZW1zA/QCU3lzdGVtLlR1cGxlYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdCQIAAAAHAgAAAAABAAAAAgAAAAPyAlN5c3RlbS5UdXBsZWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0JAwAAAAkEAAAADAUAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgQDAAAA8gJTeXN0ZW0uVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAdtX0l0ZW0xB21fSXRlbTIABAiSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBQAAAAEAAAAJBgAAAAEEAAAAAwAAAAUAAAAJBwAAAAUGAAAAkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAFVmFsdWUFTGlua3MABAiUAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dW10FAAAABQAAAAAAAAAKAQcAAAAGAAAAAAAAAAoL", TargetFrameworkMoniker.netfx461) } };
+
+ // NET Native bug 445667 causes a crash in reflecting over multidimensional arrays
if (!PlatformDetection.IsNetNative)
{
- yield return new object[] { new object[] { new int[,] { { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 10 }, { 11, 12, 13, 14, 15 } } }, new string[] { "AAEAAAD/////AQAAAAAAAAAQAQAAAAEAAAAJAgAAAAcCAAAAAgIAAAADAAAABQAAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAACw==", "AAEAAAD/////AQAAAAAAAAAQAQAAAAEAAAAJAgAAAAcCAAAAAgIAAAADAAAABQAAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAACw==" } };
- yield return new object[] { new object[] { new int[,,] { { { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 10 }, { 11, 12, 13, 14, 15 } } } }, new string[] { "AAEAAAD/////AQAAAAAAAAAQAQAAAAEAAAAJAgAAAAcCAAAAAgMAAAABAAAAAwAAAAUAAAAACAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAAAs=", "AAEAAAD/////AQAAAAAAAAAQAQAAAAEAAAAJAgAAAAcCAAAAAgMAAAABAAAAAwAAAAUAAAAACAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAAAs=" } };
- yield return new object[] { new object[] { new int[,,,] { { { { 1 } } } } }, new string[] { "AAEAAAD/////AQAAAAAAAAAQAQAAAAEAAAAJAgAAAAcCAAAAAgQAAAABAAAAAQAAAAEAAAABAAAAAAgBAAAACw==", "AAEAAAD/////AQAAAAAAAAAQAQAAAAEAAAAJAgAAAAcCAAAAAgQAAAABAAAAAQAAAAEAAAABAAAAAAgBAAAACw==" } };
+ yield return new object[] { new object[] { new int[,] { { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 10 }, { 11, 12, 13, 14, 15 } } }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAQAQAAAAEAAAAJAgAAAAcCAAAAAgIAAAADAAAABQAAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAQAQAAAAEAAAAJAgAAAAcCAAAAAgIAAAADAAAABQAAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new object[] { new int[,,] { { { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 10 }, { 11, 12, 13, 14, 15 } } } }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAQAQAAAAEAAAAJAgAAAAcCAAAAAgMAAAABAAAAAwAAAAUAAAAACAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAQAQAAAAEAAAAJAgAAAAcCAAAAAgMAAAABAAAAAwAAAAUAAAAACAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new object[] { new int[,,,] { { { { 1 } } } } }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAQAQAAAAEAAAAJAgAAAAcCAAAAAgQAAAABAAAAAQAAAAEAAAABAAAAAAgBAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAQAQAAAAEAAAAJAgAAAAcCAAAAAgQAAAABAAAAAQAAAAEAAAABAAAAAAgBAAAACw==", TargetFrameworkMoniker.netfx461) } };
}
- yield return new object[] { new ArraySegment<int>(new int[] { 1, 2, 3, 4, 5 }), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAHJTeXN0ZW0uQXJyYXlTZWdtZW50YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9hcnJheQdfb2Zmc2V0Bl9jb3VudAcAAAgICAkCAAAAAAAAAAUAAAAPAgAAAAUAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAAHJTeXN0ZW0uQXJyYXlTZWdtZW50YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9hcnJheQdfb2Zmc2V0Bl9jb3VudAcAAAgICAkCAAAAAAAAAAUAAAAPAgAAAAUAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAL" } };
- yield return new object[] { new ArraySegment<int>(new int[] { 1, 2, 3, 4, 5 }, 1, 2), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAHJTeXN0ZW0uQXJyYXlTZWdtZW50YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9hcnJheQdfb2Zmc2V0Bl9jb3VudAcAAAgICAkCAAAAAQAAAAIAAAAPAgAAAAUAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAAHJTeXN0ZW0uQXJyYXlTZWdtZW50YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9hcnJheQdfb2Zmc2V0Bl9jb3VudAcAAAgICAkCAAAAAQAAAAIAAAAPAgAAAAUAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAL" } };
- yield return new object[] { Enumerable.Range(0, 10000).Select(i => (object)i).ToArray(), new string[] { "AAEAAAD/////AQAAAAAAAAAQAQAAABAnAAAICAAAAAAICAEAAAAICAIAAAAICAMAAAAICAQAAAAICAUAAAAICAYAAAAICAcAAAAICAgAAAAICAkAAAAICAoAAAAICAsAAAAICAwAAAAICA0AAAAICA4AAAAICA8AAAAICBAAAAAICBEAAAAICBIAAAAICBMAAAAICBQAAAAICBUAAAAICBYAAAAICBcAAAAICBgAAAAICBkAAAAICBoAAAAICBsAAAAICBwAAAAICB0AAAAICB4AAAAICB8AAAAICCAAAAAICCEAAAAICCIAAAAICCMAAAAICCQAAAAICCUAAAAICCYAAAAICCcAAAAICCgAAAAICCkAAAAICCoAAAAICCsAAAAICCwAAAAICC0AAAAICC4AAAAICC8AAAAICDAAAAAICDEAAAAICDIAAAAICDMAAAAICDQAAAAICDUAAAAICDYAAAAICDcAAAAICDgAAAAICDkAAAAICDoAAAAICDsAAAAICDwAAAAICD0AAAAICD4AAAAICD8AAAAICEAAAAAICEEAAAAICEIAAAAICEMAAAAICEQAAAAICEUAAAAICEYAAAAICEcAAAAICEgAAAAICEkAAAAICEoAAAAICEsAAAAICEwAAAAICE0AAAAICE4AAAAICE8AAAAICFAAAAAICFEAAAAICFIAAAAICFMAAAAICFQAAAAICFUAAAAICFYAAAAICFcAAAAICFgAAAAICFkAAAAICFoAAAAICFsAAAAICFwAAAAICF0AAAAICF4AAAAICF8AAAAICGAAAAAICGEAAAAICGIAAAAICGMAAAAICGQAAAAICGUAAAAICGYAAAAICGcAAAAICGgAAAAICGkAAAAICGoAAAAICGsAAAAICGwAAAAICG0AAAAICG4AAAAICG8AAAAICHAAAAAICHEAAAAICHIAAAAICHMAAAAICHQAAAAICHUAAAAICHYAAAAICHcAAAAICHgAAAAICHkAAAAICHoAAAAICHsAAAAICHwAAAAICH0AAAAICH4AAAAICH8AAAAICIAAAAAICIEAAAAICIIAAAAICIMAAAAICIQAAAAICIUAAAAICIYAAAAICIcAAAAICIgAAAAICIkAAAAICIoAAAAICIsAAAAICIwAAAAICI0AAAAICI4AAAAICI8AAAAICJAAAAAICJEAAAAICJIAAAAICJMAAAAICJQAAAAICJUAAAAICJYAAAAICJcAAAAICJgAAAAICJkAAAAICJoAAAAICJsAAAAICJwAAAAICJ0AAAAICJ4AAAAICJ8AAAAICKAAAAAICKEAAAAICKIAAAAICKMAAAAICKQAAAAICKUAAAAICKYAAAAICKcAAAAICKgAAAAICKkAAAAICKoAAAAICKsAAAAICKwAAAAICK0AAAAICK4AAAAICK8AAAAICLAAAAAICLEAAAAICLIAAAAICLMAAAAICLQAAAAICLUAAAAICLYAAAAICLcAAAAICLgAAAAICLkAAAAICLoAAAAICLsAAAAICLwAAAAICL0AAAAICL4AAAAICL8AAAAICMAAAAAICMEAAAAICMIAAAAICMMAAAAICMQAAAAICMUAAAAICMYAAAAICMcAAAAICMgAAAAICMkAAAAICMoAAAAICMsAAAAICMwAAAAICM0AAAAICM4AAAAICM8AAAAICNAAAAAICNEAAAAICNIAAAAICNMAAAAICNQAAAAICNUAAAAICNYAAAAICNcAAAAICNgAAAAICNkAAAAICNoAAAAICNsAAAAICNwAAAAICN0AAAAICN4AAAAICN8AAAAICOAAAAAICOEAAAAICOIAAAAICOMAAAAICOQAAAAICOUAAAAICOYAAAAICOcAAAAICOgAAAAICOkAAAAICOoAAAAICOsAAAAICOwAAAAICO0AAAAICO4AAAAICO8AAAAICPAAAAAICPEAAAAICPIAAAAICPMAAAAICPQAAAAICPUAAAAICPYAAAAICPcAAAAICPgAAAAICPkAAAAICPoAAAAICPsAAAAICPwAAAAICP0AAAAICP4AAAAICP8AAAAICAABAAAICAEBAAAICAIBAAAICAMBAAAICAQBAAAICAUBAAAICAYBAAAICAcBAAAICAgBAAAICAkBAAAICAoBAAAICAsBAAAICAwBAAAICA0BAAAICA4BAAAICA8BAAAICBABAAAICBEBAAAICBIBAAAICBMBAAAICBQBAAAICBUBAAAICBYBAAAICBcBAAAICBgBAAAICBkBAAAICBoBAAAICBsBAAAICBwBAAAICB0BAAAICB4BAAAICB8BAAAICCABAAAICCEBAAAICCIBAAAICCMBAAAICCQBAAAICCUBAAAICCYBAAAICCcBAAAICCgBAAAICCkBAAAICCoBAAAICCsBAAAICCwBAAAICC0BAAAICC4BAAAICC8BAAAICDABAAAICDEBAAAICDIBAAAICDMBAAAICDQBAAAICDUBAAAICDYBAAAICDcBAAAICDgBAAAICDkBAAAICDoBAAAICDsBAAAICDwBAAAICD0BAAAICD4BAAAICD8BAAAICEABAAAICEEBAAAICEIBAAAICEMBAAAICEQBAAAICEUBAAAICEYBAAAICEcBAAAICEgBAAAICEkBAAAICEoBAAAICEsBAAAICEwBAAAICE0BAAAICE4BAAAICE8BAAAICFABAAAICFEBAAAICFIBAAAICFMBAAAICFQBAAAICFUBAAAICFYBAAAICFcBAAAICFgBAAAICFkBAAAICFoBAAAICFsBAAAICFwBAAAICF0BAAAICF4BAAAICF8BAAAICGABAAAICGEBAAAICGIBAAAICGMBAAAICGQBAAAICGUBAAAICGYBAAAICGcBAAAICGgBAAAICGkBAAAICGoBAAAICGsBAAAICGwBAAAICG0BAAAICG4BAAAICG8BAAAICHABAAAICHEBAAAICHIBAAAICHMBAAAICHQBAAAICHUBAAAICHYBAAAICHcBAAAICHgBAAAICHkBAAAICHoBAAAICHsBAAAICHwBAAAICH0BAAAICH4BAAAICH8BAAAICIABAAAICIEBAAAICIIBAAAICIMBAAAICIQBAAAICIUBAAAICIYBAAAICIcBAAAICIgBAAAICIkBAAAICIoBAAAICIsBAAAICIwBAAAICI0BAAAICI4BAAAICI8BAAAICJABAAAICJEBAAAICJIBAAAICJMBAAAICJQBAAAICJUBAAAICJYBAAAICJcBAAAICJgBAAAICJkBAAAICJoBAAAICJsBAAAICJwBAAAICJ0BAAAICJ4BAAAICJ8BAAAICKABAAAICKEBAAAICKIBAAAICKMBAAAICKQBAAAICKUBAAAICKYBAAAICKcBAAAICKgBAAAICKkBAAAICKoBAAAICKsBAAAICKwBAAAICK0BAAAICK4BAAAICK8BAAAICLABAAAICLEBAAAICLIBAAAICLMBAAAICLQBAAAICLUBAAAICLYBAAAICLcBAAAICLgBAAAICLkBAAAICLoBAAAICLsBAAAICLwBAAAICL0BAAAICL4BAAAICL8BAAAICMABAAAICMEBAAAICMIBAAAICMMBAAAICMQBAAAICMUBAAAICMYBAAAICMcBAAAICMgBAAAICMkBAAAICMoBAAAICMsBAAAICMwBAAAICM0BAAAICM4BAAAICM8BAAAICNABAAAICNEBAAAICNIBAAAICNMBAAAICNQBAAAICNUBAAAICNYBAAAICNcBAAAICNgBAAAICNkBAAAICNoBAAAICNsBAAAICNwBAAAICN0BAAAICN4BAAAICN8BAAAICOABAAAICOEBAAAICOIBAAAICOMBAAAICOQBAAAICOUBAAAICOYBAAAICOcBAAAICOgBAAAICOkBAAAICOoBAAAICOsBAAAICOwBAAAICO0BAAAICO4BAAAICO8BAAAICPABAAAICPEBAAAICPIBAAAICPMBAAAICPQBAAAICPUBAAAICPYBAAAICPcBAAAICPgBAAAICPkBAAAICPoBAAAICPsBAAAICPwBAAAICP0BAAAICP4BAAAICP8BAAAICAACAAAICAECAAAICAICAAAICAMCAAAICAQCAAAICAUCAAAICAYCAAAICAcCAAAICAgCAAAICAkCAAAICAoCAAAICAsCAAAICAwCAAAICA0CAAAICA4CAAAICA8CAAAICBACAAAICBECAAAICBICAAAICBMCAAAICBQCAAAICBUCAAAICBYCAAAICBcCAAAICBgCAAAICBkCAAAICBoCAAAICBsCAAAICBwCAAAICB0CAAAICB4CAAAICB8CAAAICCACAAAICCECAAAICCICAAAICCMCAAAICCQCAAAICCUCAAAICCYCAAAICCcCAAAICCgCAAAICCkCAAAICCoCAAAICCsCAAAICCwCAAAICC0CAAAICC4CAAAICC8CAAAICDACAAAICDECAAAICDICAAAICDMCAAAICDQCAAAICDUCAAAICDYCAAAICDcCAAAICDgCAAAICDkCAAAICDoCAAAICDsCAAAICDwCAAAICD0CAAAICD4CAAAICD8CAAAICEACAAAICEECAAAICEICAAAICEMCAAAICEQCAAAICEUCAAAICEYCAAAICEcCAAAICEgCAAAICEkCAAAICEoCAAAICEsCAAAICEwCAAAICE0CAAAICE4CAAAICE8CAAAICFACAAAICFECAAAICFICAAAICFMCAAAICFQCAAAICFUCAAAICFYCAAAICFcCAAAICFgCAAAICFkCAAAICFoCAAAICFsCAAAICFwCAAAICF0CAAAICF4CAAAICF8CAAAICGACAAAICGECAAAICGICAAAICGMCAAAICGQCAAAICGUCAAAICGYCAAAICGcCAAAICGgCAAAICGkCAAAICGoCAAAICGsCAAAICGwCAAAICG0CAAAICG4CAAAICG8CAAAICHACAAAICHECAAAICHICAAAICHMCAAAICHQCAAAICHUCAAAICHYCAAAICHcCAAAICHgCAAAICHkCAAAICHoCAAAICHsCAAAICHwCAAAICH0CAAAICH4CAAAICH8CAAAICIACAAAICIECAAAICIICAAAICIMCAAAICIQCAAAICIUCAAAICIYCAAAICIcCAAAICIgCAAAICIkCAAAICIoCAAAICIsCAAAICIwCAAAICI0CAAAICI4CAAAICI8CAAAICJACAAAICJECAAAICJICAAAICJMCAAAICJQCAAAICJUCAAAICJYCAAAICJcCAAAICJgCAAAICJkCAAAICJoCAAAICJsCAAAICJwCAAAICJ0CAAAICJ4CAAAICJ8CAAAICKACAAAICKECAAAICKICAAAICKMCAAAICKQCAAAICKUCAAAICKYCAAAICKcCAAAICKgCAAAICKkCAAAICKoCAAAICKsCAAAICKwCAAAICK0CAAAICK4CAAAICK8CAAAICLACAAAICLECAAAICLICAAAICLMCAAAICLQCAAAICLUCAAAICLYCAAAICLcCAAAICLgCAAAICLkCAAAICLoCAAAICLsCAAAICLwCAAAICL0CAAAICL4CAAAICL8CAAAICMACAAAICMECAAAICMICAAAICMMCAAAICMQCAAAICMUCAAAICMYCAAAICMcCAAAICMgCAAAICMkCAAAICMoCAAAICMsCAAAICMwCAAAICM0CAAAICM4CAAAICM8CAAAICNACAAAICNECAAAICNICAAAICNMCAAAICNQCAAAICNUCAAAICNYCAAAICNcCAAAICNgCAAAICNkCAAAICNoCAAAICNsCAAAICNwCAAAICN0CAAAICN4CAAAICN8CAAAICOACAAAICOECAAAICOICAAAICOMCAAAICOQCAAAICOUCAAAICOYCAAAICOcCAAAICOgCAAAICOkCAAAICOoCAAAICOsCAAAICOwCAAAICO0CAAAICO4CAAAICO8CAAAICPACAAAICPECAAAICPICAAAICPMCAAAICPQCAAAICPUCAAAICPYCAAAICPcCAAAICPgCAAAICPkCAAAICPoCAAAICPsCAAAICPwCAAAICP0CAAAICP4CAAAICP8CAAAICAADAAAICAEDAAAICAIDAAAICAMDAAAICAQDAAAICAUDAAAICAYDAAAICAcDAAAICAgDAAAICAkDAAAICAoDAAAICAsDAAAICAwDAAAICA0DAAAICA4DAAAICA8DAAAICBADAAAICBEDAAAICBIDAAAICBMDAAAICBQDAAAICBUDAAAICBYDAAAICBcDAAAICBgDAAAICBkDAAAICBoDAAAICBsDAAAICBwDAAAICB0DAAAICB4DAAAICB8DAAAICCADAAAICCEDAAAICCIDAAAICCMDAAAICCQDAAAICCUDAAAICCYDAAAICCcDAAAICCgDAAAICCkDAAAICCoDAAAICCsDAAAICCwDAAAICC0DAAAICC4DAAAICC8DAAAICDADAAAICDEDAAAICDIDAAAICDMDAAAICDQDAAAICDUDAAAICDYDAAAICDcDAAAICDgDAAAICDkDAAAICDoDAAAICDsDAAAICDwDAAAICD0DAAAICD4DAAAICD8DAAAICEADAAAICEEDAAAICEIDAAAICEMDAAAICEQDAAAICEUDAAAICEYDAAAICEcDAAAICEgDAAAICEkDAAAICEoDAAAICEsDAAAICEwDAAAICE0DAAAICE4DAAAICE8DAAAICFADAAAICFEDAAAICFIDAAAICFMDAAAICFQDAAAICFUDAAAICFYDAAAICFcDAAAICFgDAAAICFkDAAAICFoDAAAICFsDAAAICFwDAAAICF0DAAAICF4DAAAICF8DAAAICGADAAAICGEDAAAICGIDAAAICGMDAAAICGQDAAAICGUDAAAICGYDAAAICGcDAAAICGgDAAAICGkDAAAICGoDAAAICGsDAAAICGwDAAAICG0DAAAICG4DAAAICG8DAAAICHADAAAICHEDAAAICHIDAAAICHMDAAAICHQDAAAICHUDAAAICHYDAAAICHcDAAAICHgDAAAICHkDAAAICHoDAAAICHsDAAAICHwDAAAICH0DAAAICH4DAAAICH8DAAAICIADAAAICIEDAAAICIIDAAAICIMDAAAICIQDAAAICIUDAAAICIYDAAAICIcDAAAICIgDAAAICIkDAAAICIoDAAAICIsDAAAICIwDAAAICI0DAAAICI4DAAAICI8DAAAICJADAAAICJEDAAAICJIDAAAICJMDAAAICJQDAAAICJUDAAAICJYDAAAICJcDAAAICJgDAAAICJkDAAAICJoDAAAICJsDAAAICJwDAAAICJ0DAAAICJ4DAAAICJ8DAAAICKADAAAICKEDAAAICKIDAAAICKMDAAAICKQDAAAICKUDAAAICKYDAAAICKcDAAAICKgDAAAICKkDAAAICKoDAAAICKsDAAAICKwDAAAICK0DAAAICK4DAAAICK8DAAAICLADAAAICLEDAAAICLIDAAAICLMDAAAICLQDAAAICLUDAAAICLYDAAAICLcDAAAICLgDAAAICLkDAAAICLoDAAAICLsDAAAICLwDAAAICL0DAAAICL4DAAAICL8DAAAICMADAAAICMEDAAAICMIDAAAICMMDAAAICMQDAAAICMUDAAAICMYDAAAICMcDAAAICMgDAAAICMkDAAAICMoDAAAICMsDAAAICMwDAAAICM0DAAAICM4DAAAICM8DAAAICNADAAAICNEDAAAICNIDAAAICNMDAAAICNQDAAAICNUDAAAICNYDAAAICNcDAAAICNgDAAAICNkDAAAICNoDAAAICNsDAAAICNwDAAAICN0DAAAICN4DAAAICN8DAAAICOADAAAICOEDAAAICOIDAAAICOMDAAAICOQDAAAICOUDAAAICOYDAAAICOcDAAAICOgDAAAICOkDAAAICOoDAAAICOsDAAAICOwDAAAICO0DAAAICO4DAAAICO8DAAAICPADAAAICPEDAAAICPIDAAAICPMDAAAICPQDAAAICPUDAAAICPYDAAAICPcDAAAICPgDAAAICPkDAAAICPoDAAAICPsDAAAICPwDAAAICP0DAAAICP4DAAAICP8DAAAICAAEAAAICAEEAAAICAIEAAAICAMEAAAICAQEAAAICAUEAAAICAYEAAAICAcEAAAICAgEAAAICAkEAAAICAoEAAAICAsEAAAICAwEAAAICA0EAAAICA4EAAAICA8EAAAICBAEAAAICBEEAAAICBIEAAAICBMEAAAICBQEAAAICBUEAAAICBYEAAAICBcEAAAICBgEAAAICBkEAAAICBoEAAAICBsEAAAICBwEAAAICB0EAAAICB4EAAAICB8EAAAICCAEAAAICCEEAAAICCIEAAAICCMEAAAICCQEAAAICCUEAAAICCYEAAAICCcEAAAICCgEAAAICCkEAAAICCoEAAAICCsEAAAICCwEAAAICC0EAAAICC4EAAAICC8EAAAICDAEAAAICDEEAAAICDIEAAAICDMEAAAICDQEAAAICDUEAAAICDYEAAAICDcEAAAICDgEAAAICDkEAAAICDoEAAAICDsEAAAICDwEAAAICD0EAAAICD4EAAAICD8EAAAICEAEAAAICEEEAAAICEIEAAAICEMEAAAICEQEAAAICEUEAAAICEYEAAAICEcEAAAICEgEAAAICEkEAAAICEoEAAAICEsEAAAICEwEAAAICE0EAAAICE4EAAAICE8EAAAICFAEAAAICFEEAAAICFIEAAAICFMEAAAICFQEAAAICFUEAAAICFYEAAAICFcEAAAICFgEAAAICFkEAAAICFoEAAAICFsEAAAICFwEAAAICF0EAAAICF4EAAAICF8EAAAICGAEAAAICGEEAAAICGIEAAAICGMEAAAICGQEAAAICGUEAAAICGYEAAAICGcEAAAICGgEAAAICGkEAAAICGoEAAAICGsEAAAICGwEAAAICG0EAAAICG4EAAAICG8EAAAICHAEAAAICHEEAAAICHIEAAAICHMEAAAICHQEAAAICHUEAAAICHYEAAAICHcEAAAICHgEAAAICHkEAAAICHoEAAAICHsEAAAICHwEAAAICH0EAAAICH4EAAAICH8EAAAICIAEAAAICIEEAAAICIIEAAAICIMEAAAICIQEAAAICIUEAAAICIYEAAAICIcEAAAICIgEAAAICIkEAAAICIoEAAAICIsEAAAICIwEAAAICI0EAAAICI4EAAAICI8EAAAICJAEAAAICJEEAAAICJIEAAAICJMEAAAICJQEAAAICJUEAAAICJYEAAAICJcEAAAICJgEAAAICJkEAAAICJoEAAAICJsEAAAICJwEAAAICJ0EAAAICJ4EAAAICJ8EAAAICKAEAAAICKEEAAAICKIEAAAICKMEAAAICKQEAAAICKUEAAAICKYEAAAICKcEAAAICKgEAAAICKkEAAAICKoEAAAICKsEAAAICKwEAAAICK0EAAAICK4EAAAICK8EAAAICLAEAAAICLEEAAAICLIEAAAICLMEAAAICLQEAAAICLUEAAAICLYEAAAICLcEAAAICLgEAAAICLkEAAAICLoEAAAICLsEAAAICLwEAAAICL0EAAAICL4EAAAICL8EAAAICMAEAAAICMEEAAAICMIEAAAICMMEAAAICMQEAAAICMUEAAAICMYEAAAICMcEAAAICMgEAAAICMkEAAAICMoEAAAICMsEAAAICMwEAAAICM0EAAAICM4EAAAICM8EAAAICNAEAAAICNEEAAAICNIEAAAICNMEAAAICNQEAAAICNUEAAAICNYEAAAICNcEAAAICNgEAAAICNkEAAAICNoEAAAICNsEAAAICNwEAAAICN0EAAAICN4EAAAICN8EAAAICOAEAAAICOEEAAAICOIEAAAICOMEAAAICOQEAAAICOUEAAAICOYEAAAICOcEAAAICOgEAAAICOkEAAAICOoEAAAICOsEAAAICOwEAAAICO0EAAAICO4EAAAICO8EAAAICPAEAAAICPEEAAAICPIEAAAICPMEAAAICPQEAAAICPUEAAAICPYEAAAICPcEAAAICPgEAAAICPkEAAAICPoEAAAICPsEAAAICPwEAAAICP0EAAAICP4EAAAICP8EAAAICAAFAAAICAEFAAAICAIFAAAICAMFAAAICAQFAAAICAUFAAAICAYFAAAICAcFAAAICAgFAAAICAkFAAAICAoFAAAICAsFAAAICAwFAAAICA0FAAAICA4FAAAICA8FAAAICBAFAAAICBEFAAAICBIFAAAICBMFAAAICBQFAAAICBUFAAAICBYFAAAICBcFAAAICBgFAAAICBkFAAAICBoFAAAICBsFAAAICBwFAAAICB0FAAAICB4FAAAICB8FAAAICCAFAAAICCEFAAAICCIFAAAICCMFAAAICCQFAAAICCUFAAAICCYFAAAICCcFAAAICCgFAAAICCkFAAAICCoFAAAICCsFAAAICCwFAAAICC0FAAAICC4FAAAICC8FAAAICDAFAAAICDEFAAAICDIFAAAICDMFAAAICDQFAAAICDUFAAAICDYFAAAICDcFAAAICDgFAAAICDkFAAAICDoFAAAICDsFAAAICDwFAAAICD0FAAAICD4FAAAICD8FAAAICEAFAAAICEEFAAAICEIFAAAICEMFAAAICEQFAAAICEUFAAAICEYFAAAICEcFAAAICEgFAAAICEkFAAAICEoFAAAICEsFAAAICEwFAAAICE0FAAAICE4FAAAICE8FAAAICFAFAAAICFEFAAAICFIFAAAICFMFAAAICFQFAAAICFUFAAAICFYFAAAICFcFAAAICFgFAAAICFkFAAAICFoFAAAICFsFAAAICFwFAAAICF0FAAAICF4FAAAICF8FAAAICGAFAAAICGEFAAAICGIFAAAICGMFAAAICGQFAAAICGUFAAAICGYFAAAICGcFAAAICGgFAAAICGkFAAAICGoFAAAICGsFAAAICGwFAAAICG0FAAAICG4FAAAICG8FAAAICHAFAAAICHEFAAAICHIFAAAICHMFAAAICHQFAAAICHUFAAAICHYFAAAICHcFAAAICHgFAAAICHkFAAAICHoFAAAICHsFAAAICHwFAAAICH0FAAAICH4FAAAICH8FAAAICIAFAAAICIEFAAAICIIFAAAICIMFAAAICIQFAAAICIUFAAAICIYFAAAICIcFAAAICIgFAAAICIkFAAAICIoFAAAICIsFAAAICIwFAAAICI0FAAAICI4FAAAICI8FAAAICJAFAAAICJEFAAAICJIFAAAICJMFAAAICJQFAAAICJUFAAAICJYFAAAICJcFAAAICJgFAAAICJkFAAAICJoFAAAICJsFAAAICJwFAAAICJ0FAAAICJ4FAAAICJ8FAAAICKAFAAAICKEFAAAICKIFAAAICKMFAAAICKQFAAAICKUFAAAICKYFAAAICKcFAAAICKgFAAAICKkFAAAICKoFAAAICKsFAAAICKwFAAAICK0FAAAICK4FAAAICK8FAAAICLAFAAAICLEFAAAICLIFAAAICLMFAAAICLQFAAAICLUFAAAICLYFAAAICLcFAAAICLgFAAAICLkFAAAICLoFAAAICLsFAAAICLwFAAAICL0FAAAICL4FAAAICL8FAAAICMAFAAAICMEFAAAICMIFAAAICMMFAAAICMQFAAAICMUFAAAICMYFAAAICMcFAAAICMgFAAAICMkFAAAICMoFAAAICMsFAAAICMwFAAAICM0FAAAICM4FAAAICM8FAAAICNAFAAAICNEFAAAICNIFAAAICNMFAAAICNQFAAAICNUFAAAICNYFAAAICNcFAAAICNgFAAAICNkFAAAICNoFAAAICNsFAAAICNwFAAAICN0FAAAICN4FAAAICN8FAAAICOAFAAAICOEFAAAICOIFAAAICOMFAAAICOQFAAAICOUFAAAICOYFAAAICOcFAAAICOgFAAAICOkFAAAICOoFAAAICOsFAAAICOwFAAAICO0FAAAICO4FAAAICO8FAAAICPAFAAAICPEFAAAICPIFAAAICPMFAAAICPQFAAAICPUFAAAICPYFAAAICPcFAAAICPgFAAAICPkFAAAICPoFAAAICPsFAAAICPwFAAAICP0FAAAICP4FAAAICP8FAAAICAAGAAAICAEGAAAICAIGAAAICAMGAAAICAQGAAAICAUGAAAICAYGAAAICAcGAAAICAgGAAAICAkGAAAICAoGAAAICAsGAAAICAwGAAAICA0GAAAICA4GAAAICA8GAAAICBAGAAAICBEGAAAICBIGAAAICBMGAAAICBQGAAAICBUGAAAICBYGAAAICBcGAAAICBgGAAAICBkGAAAICBoGAAAICBsGAAAICBwGAAAICB0GAAAICB4GAAAICB8GAAAICCAGAAAICCEGAAAICCIGAAAICCMGAAAICCQGAAAICCUGAAAICCYGAAAICCcGAAAICCgGAAAICCkGAAAICCoGAAAICCsGAAAICCwGAAAICC0GAAAICC4GAAAICC8GAAAICDAGAAAICDEGAAAICDIGAAAICDMGAAAICDQGAAAICDUGAAAICDYGAAAICDcGAAAICDgGAAAICDkGAAAICDoGAAAICDsGAAAICDwGAAAICD0GAAAICD4GAAAICD8GAAAICEAGAAAICEEGAAAICEIGAAAICEMGAAAICEQGAAAICEUGAAAICEYGAAAICEcGAAAICEgGAAAICEkGAAAICEoGAAAICEsGAAAICEwGAAAICE0GAAAICE4GAAAICE8GAAAICFAGAAAICFEGAAAICFIGAAAICFMGAAAICFQGAAAICFUGAAAICFYGAAAICFcGAAAICFgGAAAICFkGAAAICFoGAAAICFsGAAAICFwGAAAICF0GAAAICF4GAAAICF8GAAAICGAGAAAICGEGAAAICGIGAAAICGMGAAAICGQGAAAICGUGAAAICGYGAAAICGcGAAAICGgGAAAICGkGAAAICGoGAAAICGsGAAAICGwGAAAICG0GAAAICG4GAAAICG8GAAAICHAGAAAICHEGAAAICHIGAAAICHMGAAAICHQGAAAICHUGAAAICHYGAAAICHcGAAAICHgGAAAICHkGAAAICHoGAAAICHsGAAAICHwGAAAICH0GAAAICH4GAAAICH8GAAAICIAGAAAICIEGAAAICIIGAAAICIMGAAAICIQGAAAICIUGAAAICIYGAAAICIcGAAAICIgGAAAICIkGAAAICIoGAAAICIsGAAAICIwGAAAICI0GAAAICI4GAAAICI8GAAAICJAGAAAICJEGAAAICJIGAAAICJMGAAAICJQGAAAICJUGAAAICJYGAAAICJcGAAAICJgGAAAICJkGAAAICJoGAAAICJsGAAAICJwGAAAICJ0GAAAICJ4GAAAICJ8GAAAICKAGAAAICKEGAAAICKIGAAAICKMGAAAICKQGAAAICKUGAAAICKYGAAAICKcGAAAICKgGAAAICKkGAAAICKoGAAAICKsGAAAICKwGAAAICK0GAAAICK4GAAAICK8GAAAICLAGAAAICLEGAAAICLIGAAAICLMGAAAICLQGAAAICLUGAAAICLYGAAAICLcGAAAICLgGAAAICLkGAAAICLoGAAAICLsGAAAICLwGAAAICL0GAAAICL4GAAAICL8GAAAICMAGAAAICMEGAAAICMIGAAAICMMGAAAICMQGAAAICMUGAAAICMYGAAAICMcGAAAICMgGAAAICMkGAAAICMoGAAAICMsGAAAICMwGAAAICM0GAAAICM4GAAAICM8GAAAICNAGAAAICNEGAAAICNIGAAAICNMGAAAICNQGAAAICNUGAAAICNYGAAAICNcGAAAICNgGAAAICNkGAAAICNoGAAAICNsGAAAICNwGAAAICN0GAAAICN4GAAAICN8GAAAICOAGAAAICOEGAAAICOIGAAAICOMGAAAICOQGAAAICOUGAAAICOYGAAAICOcGAAAICOgGAAAICOkGAAAICOoGAAAICOsGAAAICOwGAAAICO0GAAAICO4GAAAICO8GAAAICPAGAAAICPEGAAAICPIGAAAICPMGAAAICPQGAAAICPUGAAAICPYGAAAICPcGAAAICPgGAAAICPkGAAAICPoGAAAICPsGAAAICPwGAAAICP0GAAAICP4GAAAICP8GAAAICAAHAAAICAEHAAAICAIHAAAICAMHAAAICAQHAAAICAUHAAAICAYHAAAICAcHAAAICAgHAAAICAkHAAAICAoHAAAICAsHAAAICAwHAAAICA0HAAAICA4HAAAICA8HAAAICBAHAAAICBEHAAAICBIHAAAICBMHAAAICBQHAAAICBUHAAAICBYHAAAICBcHAAAICBgHAAAICBkHAAAICBoHAAAICBsHAAAICBwHAAAICB0HAAAICB4HAAAICB8HAAAICCAHAAAICCEHAAAICCIHAAAICCMHAAAICCQHAAAICCUHAAAICCYHAAAICCcHAAAICCgHAAAICCkHAAAICCoHAAAICCsHAAAICCwHAAAICC0HAAAICC4HAAAICC8HAAAICDAHAAAICDEHAAAICDIHAAAICDMHAAAICDQHAAAICDUHAAAICDYHAAAICDcHAAAICDgHAAAICDkHAAAICDoHAAAICDsHAAAICDwHAAAICD0HAAAICD4HAAAICD8HAAAICEAHAAAICEEHAAAICEIHAAAICEMHAAAICEQHAAAICEUHAAAICEYHAAAICEcHAAAICEgHAAAICEkHAAAICEoHAAAICEsHAAAICEwHAAAICE0HAAAICE4HAAAICE8HAAAICFAHAAAICFEHAAAICFIHAAAICFMHAAAICFQHAAAICFUHAAAICFYHAAAICFcHAAAICFgHAAAICFkHAAAICFoHAAAICFsHAAAICFwHAAAICF0HAAAICF4HAAAICF8HAAAICGAHAAAICGEHAAAICGIHAAAICGMHAAAICGQHAAAICGUHAAAICGYHAAAICGcHAAAICGgHAAAICGkHAAAICGoHAAAICGsHAAAICGwHAAAICG0HAAAICG4HAAAICG8HAAAICHAHAAAICHEHAAAICHIHAAAICHMHAAAICHQHAAAICHUHAAAICHYHAAAICHcHAAAICHgHAAAICHkHAAAICHoHAAAICHsHAAAICHwHAAAICH0HAAAICH4HAAAICH8HAAAICIAHAAAICIEHAAAICIIHAAAICIMHAAAICIQHAAAICIUHAAAICIYHAAAICIcHAAAICIgHAAAICIkHAAAICIoHAAAICIsHAAAICIwHAAAICI0HAAAICI4HAAAICI8HAAAICJAHAAAICJEHAAAICJIHAAAICJMHAAAICJQHAAAICJUHAAAICJYHAAAICJcHAAAICJgHAAAICJkHAAAICJoHAAAICJsHAAAICJwHAAAICJ0HAAAICJ4HAAAICJ8HAAAICKAHAAAICKEHAAAICKIHAAAICKMHAAAICKQHAAAICKUHAAAICKYHAAAICKcHAAAICKgHAAAICKkHAAAICKoHAAAICKsHAAAICKwHAAAICK0HAAAICK4HAAAICK8HAAAICLAHAAAICLEHAAAICLIHAAAICLMHAAAICLQHAAAICLUHAAAICLYHAAAICLcHAAAICLgHAAAICLkHAAAICLoHAAAICLsHAAAICLwHAAAICL0HAAAICL4HAAAICL8HAAAICMAHAAAICMEHAAAICMIHAAAICMMHAAAICMQHAAAICMUHAAAICMYHAAAICMcHAAAICMgHAAAICMkHAAAICMoHAAAICMsHAAAICMwHAAAICM0HAAAICM4HAAAICM8HAAAICNAHAAAICNEHAAAICNIHAAAICNMHAAAICNQHAAAICNUHAAAICNYHAAAICNcHAAAICNgHAAAICNkHAAAICNoHAAAICNsHAAAICNwHAAAICN0HAAAICN4HAAAICN8HAAAICOAHAAAICOEHAAAICOIHAAAICOMHAAAICOQHAAAICOUHAAAICOYHAAAICOcHAAAICOgHAAAICOkHAAAICOoHAAAICOsHAAAICOwHAAAICO0HAAAICO4HAAAICO8HAAAICPAHAAAICPEHAAAICPIHAAAICPMHAAAICPQHAAAICPUHAAAICPYHAAAICPcHAAAICPgHAAAICPkHAAAICPoHAAAICPsHAAAICPwHAAAICP0HAAAICP4HAAAICP8HAAAICAAIAAAICAEIAAAICAIIAAAICAMIAAAICAQIAAAICAUIAAAICAYIAAAICAcIAAAICAgIAAAICAkIAAAICAoIAAAICAsIAAAICAwIAAAICA0IAAAICA4IAAAICA8IAAAICBAIAAAICBEIAAAICBIIAAAICBMIAAAICBQIAAAICBUIAAAICBYIAAAICBcIAAAICBgIAAAICBkIAAAICBoIAAAICBsIAAAICBwIAAAICB0IAAAICB4IAAAICB8IAAAICCAIAAAICCEIAAAICCIIAAAICCMIAAAICCQIAAAICCUIAAAICCYIAAAICCcIAAAICCgIAAAICCkIAAAICCoIAAAICCsIAAAICCwIAAAICC0IAAAICC4IAAAICC8IAAAICDAIAAAICDEIAAAICDIIAAAICDMIAAAICDQIAAAICDUIAAAICDYIAAAICDcIAAAICDgIAAAICDkIAAAICDoIAAAICDsIAAAICDwIAAAICD0IAAAICD4IAAAICD8IAAAICEAIAAAICEEIAAAICEIIAAAICEMIAAAICEQIAAAICEUIAAAICEYIAAAICEcIAAAICEgIAAAICEkIAAAICEoIAAAICEsIAAAICEwIAAAICE0IAAAICE4IAAAICE8IAAAICFAIAAAICFEIAAAICFIIAAAICFMIAAAICFQIAAAICFUIAAAICFYIAAAICFcIAAAICFgIAAAICFkIAAAICFoIAAAICFsIAAAICFwIAAAICF0IAAAICF4IAAAICF8IAAAICGAIAAAICGEIAAAICGIIAAAICGMIAAAICGQIAAAICGUIAAAICGYIAAAICGcIAAAICGgIAAAICGkIAAAICGoIAAAICGsIAAAICGwIAAAICG0IAAAICG4IAAAICG8IAAAICHAIAAAICHEIAAAICHIIAAAICHMIAAAICHQIAAAICHUIAAAICHYIAAAICHcIAAAICHgIAAAICHkIAAAICHoIAAAICHsIAAAICHwIAAAICH0IAAAICH4IAAAICH8IAAAICIAIAAAICIEIAAAICIIIAAAICIMIAAAICIQIAAAICIUIAAAICIYIAAAICIcIAAAICIgIAAAICIkIAAAICIoIAAAICIsIAAAICIwIAAAICI0IAAAICI4IAAAICI8IAAAICJAIAAAICJEIAAAICJIIAAAICJMIAAAICJQIAAAICJUIAAAICJYIAAAICJcIAAAICJgIAAAICJkIAAAICJoIAAAICJsIAAAICJwIAAAICJ0IAAAICJ4IAAAICJ8IAAAICKAIAAAICKEIAAAICKIIAAAICKMIAAAICKQIAAAICKUIAAAICKYIAAAICKcIAAAICKgIAAAICKkIAAAICKoIAAAICKsIAAAICKwIAAAICK0IAAAICK4IAAAICK8IAAAICLAIAAAICLEIAAAICLIIAAAICLMIAAAICLQIAAAICLUIAAAICLYIAAAICLcIAAAICLgIAAAICLkIAAAICLoIAAAICLsIAAAICLwIAAAICL0IAAAICL4IAAAICL8IAAAICMAIAAAICMEIAAAICMIIAAAICMMIAAAICMQIAAAICMUIAAAICMYIAAAICMcIAAAICMgIAAAICMkIAAAICMoIAAAICMsIAAAICMwIAAAICM0IAAAICM4IAAAICM8IAAAICNAIAAAICNEIAAAICNIIAAAICNMIAAAICNQIAAAICNUIAAAICNYIAAAICNcIAAAICNgIAAAICNkIAAAICNoIAAAICNsIAAAICNwIAAAICN0IAAAICN4IAAAICN8IAAAICOAIAAAICOEIAAAICOIIAAAICOMIAAAICOQIAAAICOUIAAAICOYIAAAICOcIAAAICOgIAAAICOkIAAAICOoIAAAICOsIAAAICOwIAAAICO0IAAAICO4IAAAICO8IAAAICPAIAAAICPEIAAAICPIIAAAICPMIAAAICPQIAAAICPUIAAAICPYIAAAICPcIAAAICPgIAAAICPkIAAAICPoIAAAICPsIAAAICPwIAAAICP0IAAAICP4IAAAICP8IAAAICAAJAAAICAEJAAAICAIJAAAICAMJAAAICAQJAAAICAUJAAAICAYJAAAICAcJAAAICAgJAAAICAkJAAAICAoJAAAICAsJAAAICAwJAAAICA0JAAAICA4JAAAICA8JAAAICBAJAAAICBEJAAAICBIJAAAICBMJAAAICBQJAAAICBUJAAAICBYJAAAICBcJAAAICBgJAAAICBkJAAAICBoJAAAICBsJAAAICBwJAAAICB0JAAAICB4JAAAICB8JAAAICCAJAAAICCEJAAAICCIJAAAICCMJAAAICCQJAAAICCUJAAAICCYJAAAICCcJAAAICCgJAAAICCkJAAAICCoJAAAICCsJAAAICCwJAAAICC0JAAAICC4JAAAICC8JAAAICDAJAAAICDEJAAAICDIJAAAICDMJAAAICDQJAAAICDUJAAAICDYJAAAICDcJAAAICDgJAAAICDkJAAAICDoJAAAICDsJAAAICDwJAAAICD0JAAAICD4JAAAICD8JAAAICEAJAAAICEEJAAAICEIJAAAICEMJAAAICEQJAAAICEUJAAAICEYJAAAICEcJAAAICEgJAAAICEkJAAAICEoJAAAICEsJAAAICEwJAAAICE0JAAAICE4JAAAICE8JAAAICFAJAAAICFEJAAAICFIJAAAICFMJAAAICFQJAAAICFUJAAAICFYJAAAICFcJAAAICFgJAAAICFkJAAAICFoJAAAICFsJAAAICFwJAAAICF0JAAAICF4JAAAICF8JAAAICGAJAAAICGEJAAAICGIJAAAICGMJAAAICGQJAAAICGUJAAAICGYJAAAICGcJAAAICGgJAAAICGkJAAAICGoJAAAICGsJAAAICGwJAAAICG0JAAAICG4JAAAICG8JAAAICHAJAAAICHEJAAAICHIJAAAICHMJAAAICHQJAAAICHUJAAAICHYJAAAICHcJAAAICHgJAAAICHkJAAAICHoJAAAICHsJAAAICHwJAAAICH0JAAAICH4JAAAICH8JAAAICIAJAAAICIEJAAAICIIJAAAICIMJAAAICIQJAAAICIUJAAAICIYJAAAICIcJAAAICIgJAAAICIkJAAAICIoJAAAICIsJAAAICIwJAAAICI0JAAAICI4JAAAICI8JAAAICJAJAAAICJEJAAAICJIJAAAICJMJAAAICJQJAAAICJUJAAAICJYJAAAICJcJAAAICJgJAAAICJkJAAAICJoJAAAICJsJAAAICJwJAAAICJ0JAAAICJ4JAAAICJ8JAAAICKAJAAAICKEJAAAICKIJAAAICKMJAAAICKQJAAAICKUJAAAICKYJAAAICKcJAAAICKgJAAAICKkJAAAICKoJAAAICKsJAAAICKwJAAAICK0JAAAICK4JAAAICK8JAAAICLAJAAAICLEJAAAICLIJAAAICLMJAAAICLQJAAAICLUJAAAICLYJAAAICLcJAAAICLgJAAAICLkJAAAICLoJAAAICLsJAAAICLwJAAAICL0JAAAICL4JAAAICL8JAAAICMAJAAAICMEJAAAICMIJAAAICMMJAAAICMQJAAAICMUJAAAICMYJAAAICMcJAAAICMgJAAAICMkJAAAICMoJAAAICMsJAAAICMwJAAAICM0JAAAICM4JAAAICM8JAAAICNAJAAAICNEJAAAICNIJAAAICNMJAAAICNQJAAAICNUJAAAICNYJAAAICNcJAAAICNgJAAAICNkJAAAICNoJAAAICNsJAAAICNwJAAAICN0JAAAICN4JAAAICN8JAAAICOAJAAAICOEJAAAICOIJAAAICOMJAAAICOQJAAAICOUJAAAICOYJAAAICOcJAAAICOgJAAAICOkJAAAICOoJAAAICOsJAAAICOwJAAAICO0JAAAICO4JAAAICO8JAAAICPAJAAAICPEJAAAICPIJAAAICPMJAAAICPQJAAAICPUJAAAICPYJAAAICPcJAAAICPgJAAAICPkJAAAICPoJAAAICPsJAAAICPwJAAAICP0JAAAICP4JAAAICP8JAAAICAAKAAAICAEKAAAICAIKAAAICAMKAAAICAQKAAAICAUKAAAICAYKAAAICAcKAAAICAgKAAAICAkKAAAICAoKAAAICAsKAAAICAwKAAAICA0KAAAICA4KAAAICA8KAAAICBAKAAAICBEKAAAICBIKAAAICBMKAAAICBQKAAAICBUKAAAICBYKAAAICBcKAAAICBgKAAAICBkKAAAICBoKAAAICBsKAAAICBwKAAAICB0KAAAICB4KAAAICB8KAAAICCAKAAAICCEKAAAICCIKAAAICCMKAAAICCQKAAAICCUKAAAICCYKAAAICCcKAAAICCgKAAAICCkKAAAICCoKAAAICCsKAAAICCwKAAAICC0KAAAICC4KAAAICC8KAAAICDAKAAAICDEKAAAICDIKAAAICDMKAAAICDQKAAAICDUKAAAICDYKAAAICDcKAAAICDgKAAAICDkKAAAICDoKAAAICDsKAAAICDwKAAAICD0KAAAICD4KAAAICD8KAAAICEAKAAAICEEKAAAICEIKAAAICEMKAAAICEQKAAAICEUKAAAICEYKAAAICEcKAAAICEgKAAAICEkKAAAICEoKAAAICEsKAAAICEwKAAAICE0KAAAICE4KAAAICE8KAAAICFAKAAAICFEKAAAICFIKAAAICFMKAAAICFQKAAAICFUKAAAICFYKAAAICFcKAAAICFgKAAAICFkKAAAICFoKAAAICFsKAAAICFwKAAAICF0KAAAICF4KAAAICF8KAAAICGAKAAAICGEKAAAICGIKAAAICGMKAAAICGQKAAAICGUKAAAICGYKAAAICGcKAAAICGgKAAAICGkKAAAICGoKAAAICGsKAAAICGwKAAAICG0KAAAICG4KAAAICG8KAAAICHAKAAAICHEKAAAICHIKAAAICHMKAAAICHQKAAAICHUKAAAICHYKAAAICHcKAAAICHgKAAAICHkKAAAICHoKAAAICHsKAAAICHwKAAAICH0KAAAICH4KAAAICH8KAAAICIAKAAAICIEKAAAICIIKAAAICIMKAAAICIQKAAAICIUKAAAICIYKAAAICIcKAAAICIgKAAAICIkKAAAICIoKAAAICIsKAAAICIwKAAAICI0KAAAICI4KAAAICI8KAAAICJAKAAAICJEKAAAICJIKAAAICJMKAAAICJQKAAAICJUKAAAICJYKAAAICJcKAAAICJgKAAAICJkKAAAICJoKAAAICJsKAAAICJwKAAAICJ0KAAAICJ4KAAAICJ8KAAAICKAKAAAICKEKAAAICKIKAAAICKMKAAAICKQKAAAICKUKAAAICKYKAAAICKcKAAAICKgKAAAICKkKAAAICKoKAAAICKsKAAAICKwKAAAICK0KAAAICK4KAAAICK8KAAAICLAKAAAICLEKAAAICLIKAAAICLMKAAAICLQKAAAICLUKAAAICLYKAAAICLcKAAAICLgKAAAICLkKAAAICLoKAAAICLsKAAAICLwKAAAICL0KAAAICL4KAAAICL8KAAAICMAKAAAICMEKAAAICMIKAAAICMMKAAAICMQKAAAICMUKAAAICMYKAAAICMcKAAAICMgKAAAICMkKAAAICMoKAAAICMsKAAAICMwKAAAICM0KAAAICM4KAAAICM8KAAAICNAKAAAICNEKAAAICNIKAAAICNMKAAAICNQKAAAICNUKAAAICNYKAAAICNcKAAAICNgKAAAICNkKAAAICNoKAAAICNsKAAAICNwKAAAICN0KAAAICN4KAAAICN8KAAAICOAKAAAICOEKAAAICOIKAAAICOMKAAAICOQKAAAICOUKAAAICOYKAAAICOcKAAAICOgKAAAICOkKAAAICOoKAAAICOsKAAAICOwKAAAICO0KAAAICO4KAAAICO8KAAAICPAKAAAICPEKAAAICPIKAAAICPMKAAAICPQKAAAICPUKAAAICPYKAAAICPcKAAAICPgKAAAICPkKAAAICPoKAAAICPsKAAAICPwKAAAICP0KAAAICP4KAAAICP8KAAAICAALAAAICAELAAAICAILAAAICAMLAAAICAQLAAAICAULAAAICAYLAAAICAcLAAAICAgLAAAICAkLAAAICAoLAAAICAsLAAAICAwLAAAICA0LAAAICA4LAAAICA8LAAAICBALAAAICBELAAAICBILAAAICBMLAAAICBQLAAAICBULAAAICBYLAAAICBcLAAAICBgLAAAICBkLAAAICBoLAAAICBsLAAAICBwLAAAICB0LAAAICB4LAAAICB8LAAAICCALAAAICCELAAAICCILAAAICCMLAAAICCQLAAAICCULAAAICCYLAAAICCcLAAAICCgLAAAICCkLAAAICCoLAAAICCsLAAAICCwLAAAICC0LAAAICC4LAAAICC8LAAAICDALAAAICDELAAAICDILAAAICDMLAAAICDQLAAAICDULAAAICDYLAAAICDcLAAAICDgLAAAICDkLAAAICDoLAAAICDsLAAAICDwLAAAICD0LAAAICD4LAAAICD8LAAAICEALAAAICEELAAAICEILAAAICEMLAAAICEQLAAAICEULAAAICEYLAAAICEcLAAAICEgLAAAICEkLAAAICEoLAAAICEsLAAAICEwLAAAICE0LAAAICE4LAAAICE8LAAAICFALAAAICFELAAAICFILAAAICFMLAAAICFQLAAAICFULAAAICFYLAAAICFcLAAAICFgLAAAICFkLAAAICFoLAAAICFsLAAAICFwLAAAICF0LAAAICF4LAAAICF8LAAAICGALAAAICGELAAAICGILAAAICGMLAAAICGQLAAAICGULAAAICGYLAAAICGcLAAAICGgLAAAICGkLAAAICGoLAAAICGsLAAAICGwLAAAICG0LAAAICG4LAAAICG8LAAAICHALAAAICHELAAAICHILAAAICHMLAAAICHQLAAAICHULAAAICHYLAAAICHcLAAAICHgLAAAICHkLAAAICHoLAAAICHsLAAAICHwLAAAICH0LAAAICH4LAAAICH8LAAAICIALAAAICIELAAAICIILAAAICIMLAAAICIQLAAAICIULAAAICIYLAAAICIcLAAAICIgLAAAICIkLAAAICIoLAAAICIsLAAAICIwLAAAICI0LAAAICI4LAAAICI8LAAAICJALAAAICJELAAAICJILAAAICJMLAAAICJQLAAAICJULAAAICJYLAAAICJcLAAAICJgLAAAICJkLAAAICJoLAAAICJsLAAAICJwLAAAICJ0LAAAICJ4LAAAICJ8LAAAICKALAAAICKELAAAICKILAAAICKMLAAAICKQLAAAICKULAAAICKYLAAAICKcLAAAICKgLAAAICKkLAAAICKoLAAAICKsLAAAICKwLAAAICK0LAAAICK4LAAAICK8LAAAICLALAAAICLELAAAICLILAAAICLMLAAAICLQLAAAICLULAAAICLYLAAAICLcLAAAICLgLAAAICLkLAAAICLoLAAAICLsLAAAICLwLAAAICL0LAAAICL4LAAAICL8LAAAICMALAAAICMELAAAICMILAAAICMMLAAAICMQLAAAICMULAAAICMYLAAAICMcLAAAICMgLAAAICMkLAAAICMoLAAAICMsLAAAICMwLAAAICM0LAAAICM4LAAAICM8LAAAICNALAAAICNELAAAICNILAAAICNMLAAAICNQLAAAICNULAAAICNYLAAAICNcLAAAICNgLAAAICNkLAAAICNoLAAAICNsLAAAICNwLAAAICN0LAAAICN4LAAAICN8LAAAICOALAAAICOELAAAICOILAAAICOMLAAAICOQLAAAICOULAAAICOYLAAAICOcLAAAICOgLAAAICOkLAAAICOoLAAAICOsLAAAICOwLAAAICO0LAAAICO4LAAAICO8LAAAICPALAAAICPELAAAICPILAAAICPMLAAAICPQLAAAICPULAAAICPYLAAAICPcLAAAICPgLAAAICPkLAAAICPoLAAAICPsLAAAICPwLAAAICP0LAAAICP4LAAAICP8LAAAICAAMAAAICAEMAAAICAIMAAAICAMMAAAICAQMAAAICAUMAAAICAYMAAAICAcMAAAICAgMAAAICAkMAAAICAoMAAAICAsMAAAICAwMAAAICA0MAAAICA4MAAAICA8MAAAICBAMAAAICBEMAAAICBIMAAAICBMMAAAICBQMAAAICBUMAAAICBYMAAAICBcMAAAICBgMAAAICBkMAAAICBoMAAAICBsMAAAICBwMAAAICB0MAAAICB4MAAAICB8MAAAICCAMAAAICCEMAAAICCIMAAAICCMMAAAICCQMAAAICCUMAAAICCYMAAAICCcMAAAICCgMAAAICCkMAAAICCoMAAAICCsMAAAICCwMAAAICC0MAAAICC4MAAAICC8MAAAICDAMAAAICDEMAAAICDIMAAAICDMMAAAICDQMAAAICDUMAAAICDYMAAAICDcMAAAICDgMAAAICDkMAAAICDoMAAAICDsMAAAICDwMAAAICD0MAAAICD4MAAAICD8MAAAICEAMAAAICEEMAAAICEIMAAAICEMMAAAICEQMAAAICEUMAAAICEYMAAAICEcMAAAICEgMAAAICEkMAAAICEoMAAAICEsMAAAICEwMAAAICE0MAAAICE4MAAAICE8MAAAICFAMAAAICFEMAAAICFIMAAAICFMMAAAICFQMAAAICFUMAAAICFYMAAAICFcMAAAICFgMAAAICFkMAAAICFoMAAAICFsMAAAICFwMAAAICF0MAAAICF4MAAAICF8MAAAICGAMAAAICGEMAAAICGIMAAAICGMMAAAICGQMAAAICGUMAAAICGYMAAAICGcMAAAICGgMAAAICGkMAAAICGoMAAAICGsMAAAICGwMAAAICG0MAAAICG4MAAAICG8MAAAICHAMAAAICHEMAAAICHIMAAAICHMMAAAICHQMAAAICHUMAAAICHYMAAAICHcMAAAICHgMAAAICHkMAAAICHoMAAAICHsMAAAICHwMAAAICH0MAAAICH4MAAAICH8MAAAICIAMAAAICIEMAAAICIIMAAAICIMMAAAICIQMAAAICIUMAAAICIYMAAAICIcMAAAICIgMAAAICIkMAAAICIoMAAAICIsMAAAICIwMAAAICI0MAAAICI4MAAAICI8MAAAICJAMAAAICJEMAAAICJIMAAAICJMMAAAICJQMAAAICJUMAAAICJYMAAAICJcMAAAICJgMAAAICJkMAAAICJoMAAAICJsMAAAICJwMAAAICJ0MAAAICJ4MAAAICJ8MAAAICKAMAAAICKEMAAAICKIMAAAICKMMAAAICKQMAAAICKUMAAAICKYMAAAICKcMAAAICKgMAAAICKkMAAAICKoMAAAICKsMAAAICKwMAAAICK0MAAAICK4MAAAICK8MAAAICLAMAAAICLEMAAAICLIMAAAICLMMAAAICLQMAAAICLUMAAAICLYMAAAICLcMAAAICLgMAAAICLkMAAAICLoMAAAICLsMAAAICLwMAAAICL0MAAAICL4MAAAICL8MAAAICMAMAAAICMEMAAAICMIMAAAICMMMAAAICMQMAAAICMUMAAAICMYMAAAICMcMAAAICMgMAAAICMkMAAAICMoMAAAICMsMAAAICMwMAAAICM0MAAAICM4MAAAICM8MAAAICNAMAAAICNEMAAAICNIMAAAICNMMAAAICNQMAAAICNUMAAAICNYMAAAICNcMAAAICNgMAAAICNkMAAAICNoMAAAICNsMAAAICNwMAAAICN0MAAAICN4MAAAICN8MAAAICOAMAAAICOEMAAAICOIMAAAICOMMAAAICOQMAAAICOUMAAAICOYMAAAICOcMAAAICOgMAAAICOkMAAAICOoMAAAICOsMAAAICOwMAAAICO0MAAAICO4MAAAICO8MAAAICPAMAAAICPEMAAAICPIMAAAICPMMAAAICPQMAAAICPUMAAAICPYMAAAICPcMAAAICPgMAAAICPkMAAAICPoMAAAICPsMAAAICPwMAAAICP0MAAAICP4MAAAICP8MAAAICAANAAAICAENAAAICAINAAAICAMNAAAICAQNAAAICAUNAAAICAYNAAAICAcNAAAICAgNAAAICAkNAAAICAoNAAAICAsNAAAICAwNAAAICA0NAAAICA4NAAAICA8NAAAICBANAAAICBENAAAICBINAAAICBMNAAAICBQNAAAICBUNAAAICBYNAAAICBcNAAAICBgNAAAICBkNAAAICBoNAAAICBsNAAAICBwNAAAICB0NAAAICB4NAAAICB8NAAAICCANAAAICCENAAAICCINAAAICCMNAAAICCQNAAAICCUNAAAICCYNAAAICCcNAAAICCgNAAAICCkNAAAICCoNAAAICCsNAAAICCwNAAAICC0NAAAICC4NAAAICC8NAAAICDANAAAICDENAAAICDINAAAICDMNAAAICDQNAAAICDUNAAAICDYNAAAICDcNAAAICDgNAAAICDkNAAAICDoNAAAICDsNAAAICDwNAAAICD0NAAAICD4NAAAICD8NAAAICEANAAAICEENAAAICEINAAAICEMNAAAICEQNAAAICEUNAAAICEYNAAAICEcNAAAICEgNAAAICEkNAAAICEoNAAAICEsNAAAICEwNAAAICE0NAAAICE4NAAAICE8NAAAICFANAAAICFENAAAICFINAAAICFMNAAAICFQNAAAICFUNAAAICFYNAAAICFcNAAAICFgNAAAICFkNAAAICFoNAAAICFsNAAAICFwNAAAICF0NAAAICF4NAAAICF8NAAAICGANAAAICGENAAAICGINAAAICGMNAAAICGQNAAAICGUNAAAICGYNAAAICGcNAAAICGgNAAAICGkNAAAICGoNAAAICGsNAAAICGwNAAAICG0NAAAICG4NAAAICG8NAAAICHANAAAICHENAAAICHINAAAICHMNAAAICHQNAAAICHUNAAAICHYNAAAICHcNAAAICHgNAAAICHkNAAAICHoNAAAICHsNAAAICHwNAAAICH0NAAAICH4NAAAICH8NAAAICIANAAAICIENAAAICIINAAAICIMNAAAICIQNAAAICIUNAAAICIYNAAAICIcNAAAICIgNAAAICIkNAAAICIoNAAAICIsNAAAICIwNAAAICI0NAAAICI4NAAAICI8NAAAICJANAAAICJENAAAICJINAAAICJMNAAAICJQNAAAICJUNAAAICJYNAAAICJcNAAAICJgNAAAICJkNAAAICJoNAAAICJsNAAAICJwNAAAICJ0NAAAICJ4NAAAICJ8NAAAICKANAAAICKENAAAICKINAAAICKMNAAAICKQNAAAICKUNAAAICKYNAAAICKcNAAAICKgNAAAICKkNAAAICKoNAAAICKsNAAAICKwNAAAICK0NAAAICK4NAAAICK8NAAAICLANAAAICLENAAAICLINAAAICLMNAAAICLQNAAAICLUNAAAICLYNAAAICLcNAAAICLgNAAAICLkNAAAICLoNAAAICLsNAAAICLwNAAAICL0NAAAICL4NAAAICL8NAAAICMANAAAICMENAAAICMINAAAICMMNAAAICMQNAAAICMUNAAAICMYNAAAICMcNAAAICMgNAAAICMkNAAAICMoNAAAICMsNAAAICMwNAAAICM0NAAAICM4NAAAICM8NAAAICNANAAAICNENAAAICNINAAAICNMNAAAICNQNAAAICNUNAAAICNYNAAAICNcNAAAICNgNAAAICNkNAAAICNoNAAAICNsNAAAICNwNAAAICN0NAAAICN4NAAAICN8NAAAICOANAAAICOENAAAICOINAAAICOMNAAAICOQNAAAICOUNAAAICOYNAAAICOcNAAAICOgNAAAICOkNAAAICOoNAAAICOsNAAAICOwNAAAICO0NAAAICO4NAAAICO8NAAAICPANAAAICPENAAAICPINAAAICPMNAAAICPQNAAAICPUNAAAICPYNAAAICPcNAAAICPgNAAAICPkNAAAICPoNAAAICPsNAAAICPwNAAAICP0NAAAICP4NAAAICP8NAAAICAAOAAAICAEOAAAICAIOAAAICAMOAAAICAQOAAAICAUOAAAICAYOAAAICAcOAAAICAgOAAAICAkOAAAICAoOAAAICAsOAAAICAwOAAAICA0OAAAICA4OAAAICA8OAAAICBAOAAAICBEOAAAICBIOAAAICBMOAAAICBQOAAAICBUOAAAICBYOAAAICBcOAAAICBgOAAAICBkOAAAICBoOAAAICBsOAAAICBwOAAAICB0OAAAICB4OAAAICB8OAAAICCAOAAAICCEOAAAICCIOAAAICCMOAAAICCQOAAAICCUOAAAICCYOAAAICCcOAAAICCgOAAAICCkOAAAICCoOAAAICCsOAAAICCwOAAAICC0OAAAICC4OAAAICC8OAAAICDAOAAAICDEOAAAICDIOAAAICDMOAAAICDQOAAAICDUOAAAICDYOAAAICDcOAAAICDgOAAAICDkOAAAICDoOAAAICDsOAAAICDwOAAAICD0OAAAICD4OAAAICD8OAAAICEAOAAAICEEOAAAICEIOAAAICEMOAAAICEQOAAAICEUOAAAICEYOAAAICEcOAAAICEgOAAAICEkOAAAICEoOAAAICEsOAAAICEwOAAAICE0OAAAICE4OAAAICE8OAAAICFAOAAAICFEOAAAICFIOAAAICFMOAAAICFQOAAAICFUOAAAICFYOAAAICFcOAAAICFgOAAAICFkOAAAICFoOAAAICFsOAAAICFwOAAAICF0OAAAICF4OAAAICF8OAAAICGAOAAAICGEOAAAICGIOAAAICGMOAAAICGQOAAAICGUOAAAICGYOAAAICGcOAAAICGgOAAAICGkOAAAICGoOAAAICGsOAAAICGwOAAAICG0OAAAICG4OAAAICG8OAAAICHAOAAAICHEOAAAICHIOAAAICHMOAAAICHQOAAAICHUOAAAICHYOAAAICHcOAAAICHgOAAAICHkOAAAICHoOAAAICHsOAAAICHwOAAAICH0OAAAICH4OAAAICH8OAAAICIAOAAAICIEOAAAICIIOAAAICIMOAAAICIQOAAAICIUOAAAICIYOAAAICIcOAAAICIgOAAAICIkOAAAICIoOAAAICIsOAAAICIwOAAAICI0OAAAICI4OAAAICI8OAAAICJAOAAAICJEOAAAICJIOAAAICJMOAAAICJQOAAAICJUOAAAICJYOAAAICJcOAAAICJgOAAAICJkOAAAICJoOAAAICJsOAAAICJwOAAAICJ0OAAAICJ4OAAAICJ8OAAAICKAOAAAICKEOAAAICKIOAAAICKMOAAAICKQOAAAICKUOAAAICKYOAAAICKcOAAAICKgOAAAICKkOAAAICKoOAAAICKsOAAAICKwOAAAICK0OAAAICK4OAAAICK8OAAAICLAOAAAICLEOAAAICLIOAAAICLMOAAAICLQOAAAICLUOAAAICLYOAAAICLcOAAAICLgOAAAICLkOAAAICLoOAAAICLsOAAAICLwOAAAICL0OAAAICL4OAAAICL8OAAAICMAOAAAICMEOAAAICMIOAAAICMMOAAAICMQOAAAICMUOAAAICMYOAAAICMcOAAAICMgOAAAICMkOAAAICMoOAAAICMsOAAAICMwOAAAICM0OAAAICM4OAAAICM8OAAAICNAOAAAICNEOAAAICNIOAAAICNMOAAAICNQOAAAICNUOAAAICNYOAAAICNcOAAAICNgOAAAICNkOAAAICNoOAAAICNsOAAAICNwOAAAICN0OAAAICN4OAAAICN8OAAAICOAOAAAICOEOAAAICOIOAAAICOMOAAAICOQOAAAICOUOAAAICOYOAAAICOcOAAAICOgOAAAICOkOAAAICOoOAAAICOsOAAAICOwOAAAICO0OAAAICO4OAAAICO8OAAAICPAOAAAICPEOAAAICPIOAAAICPMOAAAICPQOAAAICPUOAAAICPYOAAAICPcOAAAICPgOAAAICPkOAAAICPoOAAAICPsOAAAICPwOAAAICP0OAAAICP4OAAAICP8OAAAICAAPAAAICAEPAAAICAIPAAAICAMPAAAICAQPAAAICAUPAAAICAYPAAAICAcPAAAICAgPAAAICAkPAAAICAoPAAAICAsPAAAICAwPAAAICA0PAAAICA4PAAAICA8PAAAICBAPAAAICBEPAAAICBIPAAAICBMPAAAICBQPAAAICBUPAAAICBYPAAAICBcPAAAICBgPAAAICBkPAAAICBoPAAAICBsPAAAICBwPAAAICB0PAAAICB4PAAAICB8PAAAICCAPAAAICCEPAAAICCIPAAAICCMPAAAICCQPAAAICCUPAAAICCYPAAAICCcPAAAICCgPAAAICCkPAAAICCoPAAAICCsPAAAICCwPAAAICC0PAAAICC4PAAAICC8PAAAICDAPAAAICDEPAAAICDIPAAAICDMPAAAICDQPAAAICDUPAAAICDYPAAAICDcPAAAICDgPAAAICDkPAAAICDoPAAAICDsPAAAICDwPAAAICD0PAAAICD4PAAAICD8PAAAICEAPAAAICEEPAAAICEIPAAAICEMPAAAICEQPAAAICEUPAAAICEYPAAAICEcPAAAICEgPAAAICEkPAAAICEoPAAAICEsPAAAICEwPAAAICE0PAAAICE4PAAAICE8PAAAICFAPAAAICFEPAAAICFIPAAAICFMPAAAICFQPAAAICFUPAAAICFYPAAAICFcPAAAICFgPAAAICFkPAAAICFoPAAAICFsPAAAICFwPAAAICF0PAAAICF4PAAAICF8PAAAICGAPAAAICGEPAAAICGIPAAAICGMPAAAICGQPAAAICGUPAAAICGYPAAAICGcPAAAICGgPAAAICGkPAAAICGoPAAAICGsPAAAICGwPAAAICG0PAAAICG4PAAAICG8PAAAICHAPAAAICHEPAAAICHIPAAAICHMPAAAICHQPAAAICHUPAAAICHYPAAAICHcPAAAICHgPAAAICHkPAAAICHoPAAAICHsPAAAICHwPAAAICH0PAAAICH4PAAAICH8PAAAICIAPAAAICIEPAAAICIIPAAAICIMPAAAICIQPAAAICIUPAAAICIYPAAAICIcPAAAICIgPAAAICIkPAAAICIoPAAAICIsPAAAICIwPAAAICI0PAAAICI4PAAAICI8PAAAICJAPAAAICJEPAAAICJIPAAAICJMPAAAICJQPAAAICJUPAAAICJYPAAAICJcPAAAICJgPAAAICJkPAAAICJoPAAAICJsPAAAICJwPAAAICJ0PAAAICJ4PAAAICJ8PAAAICKAPAAAICKEPAAAICKIPAAAICKMPAAAICKQPAAAICKUPAAAICKYPAAAICKcPAAAICKgPAAAICKkPAAAICKoPAAAICKsPAAAICKwPAAAICK0PAAAICK4PAAAICK8PAAAICLAPAAAICLEPAAAICLIPAAAICLMPAAAICLQPAAAICLUPAAAICLYPAAAICLcPAAAICLgPAAAICLkPAAAICLoPAAAICLsPAAAICLwPAAAICL0PAAAICL4PAAAICL8PAAAICMAPAAAICMEPAAAICMIPAAAICMMPAAAICMQPAAAICMUPAAAICMYPAAAICMcPAAAICMgPAAAICMkPAAAICMoPAAAICMsPAAAICMwPAAAICM0PAAAICM4PAAAICM8PAAAICNAPAAAICNEPAAAICNIPAAAICNMPAAAICNQPAAAICNUPAAAICNYPAAAICNcPAAAICNgPAAAICNkPAAAICNoPAAAICNsPAAAICNwPAAAICN0PAAAICN4PAAAICN8PAAAICOAPAAAICOEPAAAICOIPAAAICOMPAAAICOQPAAAICOUPAAAICOYPAAAICOcPAAAICOgPAAAICOkPAAAICOoPAAAICOsPAAAICOwPAAAICO0PAAAICO4PAAAICO8PAAAICPAPAAAICPEPAAAICPIPAAAICPMPAAAICPQPAAAICPUPAAAICPYPAAAICPcPAAAICPgPAAAICPkPAAAICPoPAAAICPsPAAAICPwPAAAICP0PAAAICP4PAAAICP8PAAAICAAQAAAICAEQAAAICAIQAAAICAMQAAAICAQQAAAICAUQAAAICAYQAAAICAcQAAAICAgQAAAICAkQAAAICAoQAAAICAsQAAAICAwQAAAICA0QAAAICA4QAAAICA8QAAAICBAQAAAICBEQAAAICBIQAAAICBMQAAAICBQQAAAICBUQAAAICBYQAAAICBcQAAAICBgQAAAICBkQAAAICBoQAAAICBsQAAAICBwQAAAICB0QAAAICB4QAAAICB8QAAAICCAQAAAICCEQAAAICCIQAAAICCMQAAAICCQQAAAICCUQAAAICCYQAAAICCcQAAAICCgQAAAICCkQAAAICCoQAAAICCsQAAAICCwQAAAICC0QAAAICC4QAAAICC8QAAAICDAQAAAICDEQAAAICDIQAAAICDMQAAAICDQQAAAICDUQAAAICDYQAAAICDcQAAAICDgQAAAICDkQAAAICDoQAAAICDsQAAAICDwQAAAICD0QAAAICD4QAAAICD8QAAAICEAQAAAICEEQAAAICEIQAAAICEMQAAAICEQQAAAICEUQAAAICEYQAAAICEcQAAAICEgQAAAICEkQAAAICEoQAAAICEsQAAAICEwQAAAICE0QAAAICE4QAAAICE8QAAAICFAQAAAICFEQAAAICFIQAAAICFMQAAAICFQQAAAICFUQAAAICFYQAAAICFcQAAAICFgQAAAICFkQAAAICFoQAAAICFsQAAAICFwQAAAICF0QAAAICF4QAAAICF8QAAAICGAQAAAICGEQAAAICGIQAAAICGMQAAAICGQQAAAICGUQAAAICGYQAAAICGcQAAAICGgQAAAICGkQAAAICGoQAAAICGsQAAAICGwQAAAICG0QAAAICG4QAAAICG8QAAAICHAQAAAICHEQAAAICHIQAAAICHMQAAAICHQQAAAICHUQAAAICHYQAAAICHcQAAAICHgQAAAICHkQAAAICHoQAAAICHsQAAAICHwQAAAICH0QAAAICH4QAAAICH8QAAAICIAQAAAICIEQAAAICIIQAAAICIMQAAAICIQQAAAICIUQAAAICIYQAAAICIcQAAAICIgQAAAICIkQAAAICIoQAAAICIsQAAAICIwQAAAICI0QAAAICI4QAAAICI8QAAAICJAQAAAICJEQAAAICJIQAAAICJMQAAAICJQQAAAICJUQAAAICJYQAAAICJcQAAAICJgQAAAICJkQAAAICJoQAAAICJsQAAAICJwQAAAICJ0QAAAICJ4QAAAICJ8QAAAICKAQAAAICKEQAAAICKIQAAAICKMQAAAICKQQAAAICKUQAAAICKYQAAAICKcQAAAICKgQAAAICKkQAAAICKoQAAAICKsQAAAICKwQAAAICK0QAAAICK4QAAAICK8QAAAICLAQAAAICLEQAAAICLIQAAAICLMQAAAICLQQAAAICLUQAAAICLYQAAAICLcQAAAICLgQAAAICLkQAAAICLoQAAAICLsQAAAICLwQAAAICL0QAAAICL4QAAAICL8QAAAICMAQAAAICMEQAAAICMIQAAAICMMQAAAICMQQAAAICMUQAAAICMYQAAAICMcQAAAICMgQAAAICMkQAAAICMoQAAAICMsQAAAICMwQAAAICM0QAAAICM4QAAAICM8QAAAICNAQAAAICNEQAAAICNIQAAAICNMQAAAICNQQAAAICNUQAAAICNYQAAAICNcQAAAICNgQAAAICNkQAAAICNoQAAAICNsQAAAICNwQAAAICN0QAAAICN4QAAAICN8QAAAICOAQAAAICOEQAAAICOIQAAAICOMQAAAICOQQAAAICOUQAAAICOYQAAAICOcQAAAICOgQAAAICOkQAAAICOoQAAAICOsQAAAICOwQAAAICO0QAAAICO4QAAAICO8QAAAICPAQAAAICPEQAAAICPIQAAAICPMQAAAICPQQAAAICPUQAAAICPYQAAAICPcQAAAICPgQAAAICPkQAAAICPoQAAAICPsQAAAICPwQAAAICP0QAAAICP4QAAAICP8QAAAICAARAAAICAERAAAICAIRAAAICAMRAAAICAQRAAAICAURAAAICAYRAAAICAcRAAAICAgRAAAICAkRAAAICAoRAAAICAsRAAAICAwRAAAICA0RAAAICA4RAAAICA8RAAAICBARAAAICBERAAAICBIRAAAICBMRAAAICBQRAAAICBURAAAICBYRAAAICBcRAAAICBgRAAAICBkRAAAICBoRAAAICBsRAAAICBwRAAAICB0RAAAICB4RAAAICB8RAAAICCARAAAICCERAAAICCIRAAAICCMRAAAICCQRAAAICCURAAAICCYRAAAICCcRAAAICCgRAAAICCkRAAAICCoRAAAICCsRAAAICCwRAAAICC0RAAAICC4RAAAICC8RAAAICDARAAAICDERAAAICDIRAAAICDMRAAAICDQRAAAICDURAAAICDYRAAAICDcRAAAICDgRAAAICDkRAAAICDoRAAAICDsRAAAICDwRAAAICD0RAAAICD4RAAAICD8RAAAICEARAAAICEERAAAICEIRAAAICEMRAAAICEQRAAAICEURAAAICEYRAAAICEcRAAAICEgRAAAICEkRAAAICEoRAAAICEsRAAAICEwRAAAICE0RAAAICE4RAAAICE8RAAAICFARAAAICFERAAAICFIRAAAICFMRAAAICFQRAAAICFURAAAICFYRAAAICFcRAAAICFgRAAAICFkRAAAICFoRAAAICFsRAAAICFwRAAAICF0RAAAICF4RAAAICF8RAAAICGARAAAICGERAAAICGIRAAAICGMRAAAICGQRAAAICGURAAAICGYRAAAICGcRAAAICGgRAAAICGkRAAAICGoRAAAICGsRAAAICGwRAAAICG0RAAAICG4RAAAICG8RAAAICHARAAAICHERAAAICHIRAAAICHMRAAAICHQRAAAICHURAAAICHYRAAAICHcRAAAICHgRAAAICHkRAAAICHoRAAAICHsRAAAICHwRAAAICH0RAAAICH4RAAAICH8RAAAICIARAAAICIERAAAICIIRAAAICIMRAAAICIQRAAAICIURAAAICIYRAAAICIcRAAAICIgRAAAICIkRAAAICIoRAAAICIsRAAAICIwRAAAICI0RAAAICI4RAAAICI8RAAAICJARAAAICJERAAAICJIRAAAICJMRAAAICJQRAAAICJURAAAICJYRAAAICJcRAAAICJgRAAAICJkRAAAICJoRAAAICJsRAAAICJwRAAAICJ0RAAAICJ4RAAAICJ8RAAAICKARAAAICKERAAAICKIRAAAICKMRAAAICKQRAAAICKURAAAICKYRAAAICKcRAAAICKgRAAAICKkRAAAICKoRAAAICKsRAAAICKwRAAAICK0RAAAICK4RAAAICK8RAAAICLARAAAICLERAAAICLIRAAAICLMRAAAICLQRAAAICLURAAAICLYRAAAICLcRAAAICLgRAAAICLkRAAAICLoRAAAICLsRAAAICLwRAAAICL0RAAAICL4RAAAICL8RAAAICMARAAAICMERAAAICMIRAAAICMMRAAAICMQRAAAICMURAAAICMYRAAAICMcRAAAICMgRAAAICMkRAAAICMoRAAAICMsRAAAICMwRAAAICM0RAAAICM4RAAAICM8RAAAICNARAAAICNERAAAICNIRAAAICNMRAAAICNQRAAAICNURAAAICNYRAAAICNcRAAAICNgRAAAICNkRAAAICNoRAAAICNsRAAAICNwRAAAICN0RAAAICN4RAAAICN8RAAAICOARAAAICOERAAAICOIRAAAICOMRAAAICOQRAAAICOURAAAICOYRAAAICOcRAAAICOgRAAAICOkRAAAICOoRAAAICOsRAAAICOwRAAAICO0RAAAICO4RAAAICO8RAAAICPARAAAICPERAAAICPIRAAAICPMRAAAICPQRAAAICPURAAAICPYRAAAICPcRAAAICPgRAAAICPkRAAAICPoRAAAICPsRAAAICPwRAAAICP0RAAAICP4RAAAICP8RAAAICAASAAAICAESAAAICAISAAAICAMSAAAICAQSAAAICAUSAAAICAYSAAAICAcSAAAICAgSAAAICAkSAAAICAoSAAAICAsSAAAICAwSAAAICA0SAAAICA4SAAAICA8SAAAICBASAAAICBESAAAICBISAAAICBMSAAAICBQSAAAICBUSAAAICBYSAAAICBcSAAAICBgSAAAICBkSAAAICBoSAAAICBsSAAAICBwSAAAICB0SAAAICB4SAAAICB8SAAAICCASAAAICCESAAAICCISAAAICCMSAAAICCQSAAAICCUSAAAICCYSAAAICCcSAAAICCgSAAAICCkSAAAICCoSAAAICCsSAAAICCwSAAAICC0SAAAICC4SAAAICC8SAAAICDASAAAICDESAAAICDISAAAICDMSAAAICDQSAAAICDUSAAAICDYSAAAICDcSAAAICDgSAAAICDkSAAAICDoSAAAICDsSAAAICDwSAAAICD0SAAAICD4SAAAICD8SAAAICEASAAAICEESAAAICEISAAAICEMSAAAICEQSAAAICEUSAAAICEYSAAAICEcSAAAICEgSAAAICEkSAAAICEoSAAAICEsSAAAICEwSAAAICE0SAAAICE4SAAAICE8SAAAICFASAAAICFESAAAICFISAAAICFMSAAAICFQSAAAICFUSAAAICFYSAAAICFcSAAAICFgSAAAICFkSAAAICFoSAAAICFsSAAAICFwSAAAICF0SAAAICF4SAAAICF8SAAAICGASAAAICGESAAAICGISAAAICGMSAAAICGQSAAAICGUSAAAICGYSAAAICGcSAAAICGgSAAAICGkSAAAICGoSAAAICGsSAAAICGwSAAAICG0SAAAICG4SAAAICG8SAAAICHASAAAICHESAAAICHISAAAICHMSAAAICHQSAAAICHUSAAAICHYSAAAICHcSAAAICHgSAAAICHkSAAAICHoSAAAICHsSAAAICHwSAAAICH0SAAAICH4SAAAICH8SAAAICIASAAAICIESAAAICIISAAAICIMSAAAICIQSAAAICIUSAAAICIYSAAAICIcSAAAICIgSAAAICIkSAAAICIoSAAAICIsSAAAICIwSAAAICI0SAAAICI4SAAAICI8SAAAICJASAAAICJESAAAICJISAAAICJMSAAAICJQSAAAICJUSAAAICJYSAAAICJcSAAAICJgSAAAICJkSAAAICJoSAAAICJsSAAAICJwSAAAICJ0SAAAICJ4SAAAICJ8SAAAICKASAAAICKESAAAICKISAAAICKMSAAAICKQSAAAICKUSAAAICKYSAAAICKcSAAAICKgSAAAICKkSAAAICKoSAAAICKsSAAAICKwSAAAICK0SAAAICK4SAAAICK8SAAAICLASAAAICLESAAAICLISAAAICLMSAAAICLQSAAAICLUSAAAICLYSAAAICLcSAAAICLgSAAAICLkSAAAICLoSAAAICLsSAAAICLwSAAAICL0SAAAICL4SAAAICL8SAAAICMASAAAICMESAAAICMISAAAICMMSAAAICMQSAAAICMUSAAAICMYSAAAICMcSAAAICMgSAAAICMkSAAAICMoSAAAICMsSAAAICMwSAAAICM0SAAAICM4SAAAICM8SAAAICNASAAAICNESAAAICNISAAAICNMSAAAICNQSAAAICNUSAAAICNYSAAAICNcSAAAICNgSAAAICNkSAAAICNoSAAAICNsSAAAICNwSAAAICN0SAAAICN4SAAAICN8SAAAICOASAAAICOESAAAICOISAAAICOMSAAAICOQSAAAICOUSAAAICOYSAAAICOcSAAAICOgSAAAICOkSAAAICOoSAAAICOsSAAAICOwSAAAICO0SAAAICO4SAAAICO8SAAAICPASAAAICPESAAAICPISAAAICPMSAAAICPQSAAAICPUSAAAICPYSAAAICPcSAAAICPgSAAAICPkSAAAICPoSAAAICPsSAAAICPwSAAAICP0SAAAICP4SAAAICP8SAAAICAATAAAICAETAAAICAITAAAICAMTAAAICAQTAAAICAUTAAAICAYTAAAICAcTAAAICAgTAAAICAkTAAAICAoTAAAICAsTAAAICAwTAAAICA0TAAAICA4TAAAICA8TAAAICBATAAAICBETAAAICBITAAAICBMTAAAICBQTAAAICBUTAAAICBYTAAAICBcTAAAICBgTAAAICBkTAAAICBoTAAAICBsTAAAICBwTAAAICB0TAAAICB4TAAAICB8TAAAICCATAAAICCETAAAICCITAAAICCMTAAAICCQTAAAICCUTAAAICCYTAAAICCcTAAAICCgTAAAICCkTAAAICCoTAAAICCsTAAAICCwTAAAICC0TAAAICC4TAAAICC8TAAAICDATAAAICDETAAAICDITAAAICDMTAAAICDQTAAAICDUTAAAICDYTAAAICDcTAAAICDgTAAAICDkTAAAICDoTAAAICDsTAAAICDwTAAAICD0TAAAICD4TAAAICD8TAAAICEATAAAICEETAAAICEITAAAICEMTAAAICEQTAAAICEUTAAAICEYTAAAICEcTAAAICEgTAAAICEkTAAAICEoTAAAICEsTAAAICEwTAAAICE0TAAAICE4TAAAICE8TAAAICFATAAAICFETAAAICFITAAAICFMTAAAICFQTAAAICFUTAAAICFYTAAAICFcTAAAICFgTAAAICFkTAAAICFoTAAAICFsTAAAICFwTAAAICF0TAAAICF4TAAAICF8TAAAICGATAAAICGETAAAICGITAAAICGMTAAAICGQTAAAICGUTAAAICGYTAAAICGcTAAAICGgTAAAICGkTAAAICGoTAAAICGsTAAAICGwTAAAICG0TAAAICG4TAAAICG8TAAAICHATAAAICHETAAAICHITAAAICHMTAAAICHQTAAAICHUTAAAICHYTAAAICHcTAAAICHgTAAAICHkTAAAICHoTAAAICHsTAAAICHwTAAAICH0TAAAICH4TAAAICH8TAAAICIATAAAICIETAAAICIITAAAICIMTAAAICIQTAAAICIUTAAAICIYTAAAICIcTAAAICIgTAAAICIkTAAAICIoTAAAICIsTAAAICIwTAAAICI0TAAAICI4TAAAICI8TAAAICJATAAAICJETAAAICJITAAAICJMTAAAICJQTAAAICJUTAAAICJYTAAAICJcTAAAICJgTAAAICJkTAAAICJoTAAAICJsTAAAICJwTAAAICJ0TAAAICJ4TAAAICJ8TAAAICKATAAAICKETAAAICKITAAAICKMTAAAICKQTAAAICKUTAAAICKYTAAAICKcTAAAICKgTAAAICKkTAAAICKoTAAAICKsTAAAICKwTAAAICK0TAAAICK4TAAAICK8TAAAICLATAAAICLETAAAICLITAAAICLMTAAAICLQTAAAICLUTAAAICLYTAAAICLcTAAAICLgTAAAICLkTAAAICLoTAAAICLsTAAAICLwTAAAICL0TAAAICL4TAAAICL8TAAAICMATAAAICMETAAAICMITAAAICMMTAAAICMQTAAAICMUTAAAICMYTAAAICMcTAAAICMgTAAAICMkTAAAICMoTAAAICMsTAAAICMwTAAAICM0TAAAICM4TAAAICM8TAAAICNATAAAICNETAAAICNITAAAICNMTAAAICNQTAAAICNUTAAAICNYTAAAICNcTAAAICNgTAAAICNkTAAAICNoTAAAICNsTAAAICNwTAAAICN0TAAAICN4TAAAICN8TAAAICOATAAAICOETAAAICOITAAAICOMTAAAICOQTAAAICOUTAAAICOYTAAAICOcTAAAICOgTAAAICOkTAAAICOoTAAAICOsTAAAICOwTAAAICO0TAAAICO4TAAAICO8TAAAICPATAAAICPETAAAICPITAAAICPMTAAAICPQTAAAICPUTAAAICPYTAAAICPcTAAAICPgTAAAICPkTAAAICPoTAAAICPsTAAAICPwTAAAICP0TAAAICP4TAAAICP8TAAAICAAUAAAICAEUAAAICAIUAAAICAMUAAAICAQUAAAICAUUAAAICAYUAAAICAcUAAAICAgUAAAICAkUAAAICAoUAAAICAsUAAAICAwUAAAICA0UAAAICA4UAAAICA8UAAAICBAUAAAICBEUAAAICBIUAAAICBMUAAAICBQUAAAICBUUAAAICBYUAAAICBcUAAAICBgUAAAICBkUAAAICBoUAAAICBsUAAAICBwUAAAICB0UAAAICB4UAAAICB8UAAAICCAUAAAICCEUAAAICCIUAAAICCMUAAAICCQUAAAICCUUAAAICCYUAAAICCcUAAAICCgUAAAICCkUAAAICCoUAAAICCsUAAAICCwUAAAICC0UAAAICC4UAAAICC8UAAAICDAUAAAICDEUAAAICDIUAAAICDMUAAAICDQUAAAICDUUAAAICDYUAAAICDcUAAAICDgUAAAICDkUAAAICDoUAAAICDsUAAAICDwUAAAICD0UAAAICD4UAAAICD8UAAAICEAUAAAICEEUAAAICEIUAAAICEMUAAAICEQUAAAICEUUAAAICEYUAAAICEcUAAAICEgUAAAICEkUAAAICEoUAAAICEsUAAAICEwUAAAICE0UAAAICE4UAAAICE8UAAAICFAUAAAICFEUAAAICFIUAAAICFMUAAAICFQUAAAICFUUAAAICFYUAAAICFcUAAAICFgUAAAICFkUAAAICFoUAAAICFsUAAAICFwUAAAICF0UAAAICF4UAAAICF8UAAAICGAUAAAICGEUAAAICGIUAAAICGMUAAAICGQUAAAICGUUAAAICGYUAAAICGcUAAAICGgUAAAICGkUAAAICGoUAAAICGsUAAAICGwUAAAICG0UAAAICG4UAAAICG8UAAAICHAUAAAICHEUAAAICHIUAAAICHMUAAAICHQUAAAICHUUAAAICHYUAAAICHcUAAAICHgUAAAICHkUAAAICHoUAAAICHsUAAAICHwUAAAICH0UAAAICH4UAAAICH8UAAAICIAUAAAICIEUAAAICIIUAAAICIMUAAAICIQUAAAICIUUAAAICIYUAAAICIcUAAAICIgUAAAICIkUAAAICIoUAAAICIsUAAAICIwUAAAICI0UAAAICI4UAAAICI8UAAAICJAUAAAICJEUAAAICJIUAAAICJMUAAAICJQUAAAICJUUAAAICJYUAAAICJcUAAAICJgUAAAICJkUAAAICJoUAAAICJsUAAAICJwUAAAICJ0UAAAICJ4UAAAICJ8UAAAICKAUAAAICKEUAAAICKIUAAAICKMUAAAICKQUAAAICKUUAAAICKYUAAAICKcUAAAICKgUAAAICKkUAAAICKoUAAAICKsUAAAICKwUAAAICK0UAAAICK4UAAAICK8UAAAICLAUAAAICLEUAAAICLIUAAAICLMUAAAICLQUAAAICLUUAAAICLYUAAAICLcUAAAICLgUAAAICLkUAAAICLoUAAAICLsUAAAICLwUAAAICL0UAAAICL4UAAAICL8UAAAICMAUAAAICMEUAAAICMIUAAAICMMUAAAICMQUAAAICMUUAAAICMYUAAAICMcUAAAICMgUAAAICMkUAAAICMoUAAAICMsUAAAICMwUAAAICM0UAAAICM4UAAAICM8UAAAICNAUAAAICNEUAAAICNIUAAAICNMUAAAICNQUAAAICNUUAAAICNYUAAAICNcUAAAICNgUAAAICNkUAAAICNoUAAAICNsUAAAICNwUAAAICN0UAAAICN4UAAAICN8UAAAICOAUAAAICOEUAAAICOIUAAAICOMUAAAICOQUAAAICOUUAAAICOYUAAAICOcUAAAICOgUAAAICOkUAAAICOoUAAAICOsUAAAICOwUAAAICO0UAAAICO4UAAAICO8UAAAICPAUAAAICPEUAAAICPIUAAAICPMUAAAICPQUAAAICPUUAAAICPYUAAAICPcUAAAICPgUAAAICPkUAAAICPoUAAAICPsUAAAICPwUAAAICP0UAAAICP4UAAAICP8UAAAICAAVAAAICAEVAAAICAIVAAAICAMVAAAICAQVAAAICAUVAAAICAYVAAAICAcVAAAICAgVAAAICAkVAAAICAoVAAAICAsVAAAICAwVAAAICA0VAAAICA4VAAAICA8VAAAICBAVAAAICBEVAAAICBIVAAAICBMVAAAICBQVAAAICBUVAAAICBYVAAAICBcVAAAICBgVAAAICBkVAAAICBoVAAAICBsVAAAICBwVAAAICB0VAAAICB4VAAAICB8VAAAICCAVAAAICCEVAAAICCIVAAAICCMVAAAICCQVAAAICCUVAAAICCYVAAAICCcVAAAICCgVAAAICCkVAAAICCoVAAAICCsVAAAICCwVAAAICC0VAAAICC4VAAAICC8VAAAICDAVAAAICDEVAAAICDIVAAAICDMVAAAICDQVAAAICDUVAAAICDYVAAAICDcVAAAICDgVAAAICDkVAAAICDoVAAAICDsVAAAICDwVAAAICD0VAAAICD4VAAAICD8VAAAICEAVAAAICEEVAAAICEIVAAAICEMVAAAICEQVAAAICEUVAAAICEYVAAAICEcVAAAICEgVAAAICEkVAAAICEoVAAAICEsVAAAICEwVAAAICE0VAAAICE4VAAAICE8VAAAICFAVAAAICFEVAAAICFIVAAAICFMVAAAICFQVAAAICFUVAAAICFYVAAAICFcVAAAICFgVAAAICFkVAAAICFoVAAAICFsVAAAICFwVAAAICF0VAAAICF4VAAAICF8VAAAICGAVAAAICGEVAAAICGIVAAAICGMVAAAICGQVAAAICGUVAAAICGYVAAAICGcVAAAICGgVAAAICGkVAAAICGoVAAAICGsVAAAICGwVAAAICG0VAAAICG4VAAAICG8VAAAICHAVAAAICHEVAAAICHIVAAAICHMVAAAICHQVAAAICHUVAAAICHYVAAAICHcVAAAICHgVAAAICHkVAAAICHoVAAAICHsVAAAICHwVAAAICH0VAAAICH4VAAAICH8VAAAICIAVAAAICIEVAAAICIIVAAAICIMVAAAICIQVAAAICIUVAAAICIYVAAAICIcVAAAICIgVAAAICIkVAAAICIoVAAAICIsVAAAICIwVAAAICI0VAAAICI4VAAAICI8VAAAICJAVAAAICJEVAAAICJIVAAAICJMVAAAICJQVAAAICJUVAAAICJYVAAAICJcVAAAICJgVAAAICJkVAAAICJoVAAAICJsVAAAICJwVAAAICJ0VAAAICJ4VAAAICJ8VAAAICKAVAAAICKEVAAAICKIVAAAICKMVAAAICKQVAAAICKUVAAAICKYVAAAICKcVAAAICKgVAAAICKkVAAAICKoVAAAICKsVAAAICKwVAAAICK0VAAAICK4VAAAICK8VAAAICLAVAAAICLEVAAAICLIVAAAICLMVAAAICLQVAAAICLUVAAAICLYVAAAICLcVAAAICLgVAAAICLkVAAAICLoVAAAICLsVAAAICLwVAAAICL0VAAAICL4VAAAICL8VAAAICMAVAAAICMEVAAAICMIVAAAICMMVAAAICMQVAAAICMUVAAAICMYVAAAICMcVAAAICMgVAAAICMkVAAAICMoVAAAICMsVAAAICMwVAAAICM0VAAAICM4VAAAICM8VAAAICNAVAAAICNEVAAAICNIVAAAICNMVAAAICNQVAAAICNUVAAAICNYVAAAICNcVAAAICNgVAAAICNkVAAAICNoVAAAICNsVAAAICNwVAAAICN0VAAAICN4VAAAICN8VAAAICOAVAAAICOEVAAAICOIVAAAICOMVAAAICOQVAAAICOUVAAAICOYVAAAICOcVAAAICOgVAAAICOkVAAAICOoVAAAICOsVAAAICOwVAAAICO0VAAAICO4VAAAICO8VAAAICPAVAAAICPEVAAAICPIVAAAICPMVAAAICPQVAAAICPUVAAAICPYVAAAICPcVAAAICPgVAAAICPkVAAAICPoVAAAICPsVAAAICPwVAAAICP0VAAAICP4VAAAICP8VAAAICAAWAAAICAEWAAAICAIWAAAICAMWAAAICAQWAAAICAUWAAAICAYWAAAICAcWAAAICAgWAAAICAkWAAAICAoWAAAICAsWAAAICAwWAAAICA0WAAAICA4WAAAICA8WAAAICBAWAAAICBEWAAAICBIWAAAICBMWAAAICBQWAAAICBUWAAAICBYWAAAICBcWAAAICBgWAAAICBkWAAAICBoWAAAICBsWAAAICBwWAAAICB0WAAAICB4WAAAICB8WAAAICCAWAAAICCEWAAAICCIWAAAICCMWAAAICCQWAAAICCUWAAAICCYWAAAICCcWAAAICCgWAAAICCkWAAAICCoWAAAICCsWAAAICCwWAAAICC0WAAAICC4WAAAICC8WAAAICDAWAAAICDEWAAAICDIWAAAICDMWAAAICDQWAAAICDUWAAAICDYWAAAICDcWAAAICDgWAAAICDkWAAAICDoWAAAICDsWAAAICDwWAAAICD0WAAAICD4WAAAICD8WAAAICEAWAAAICEEWAAAICEIWAAAICEMWAAAICEQWAAAICEUWAAAICEYWAAAICEcWAAAICEgWAAAICEkWAAAICEoWAAAICEsWAAAICEwWAAAICE0WAAAICE4WAAAICE8WAAAICFAWAAAICFEWAAAICFIWAAAICFMWAAAICFQWAAAICFUWAAAICFYWAAAICFcWAAAICFgWAAAICFkWAAAICFoWAAAICFsWAAAICFwWAAAICF0WAAAICF4WAAAICF8WAAAICGAWAAAICGEWAAAICGIWAAAICGMWAAAICGQWAAAICGUWAAAICGYWAAAICGcWAAAICGgWAAAICGkWAAAICGoWAAAICGsWAAAICGwWAAAICG0WAAAICG4WAAAICG8WAAAICHAWAAAICHEWAAAICHIWAAAICHMWAAAICHQWAAAICHUWAAAICHYWAAAICHcWAAAICHgWAAAICHkWAAAICHoWAAAICHsWAAAICHwWAAAICH0WAAAICH4WAAAICH8WAAAICIAWAAAICIEWAAAICIIWAAAICIMWAAAICIQWAAAICIUWAAAICIYWAAAICIcWAAAICIgWAAAICIkWAAAICIoWAAAICIsWAAAICIwWAAAICI0WAAAICI4WAAAICI8WAAAICJAWAAAICJEWAAAICJIWAAAICJMWAAAICJQWAAAICJUWAAAICJYWAAAICJcWAAAICJgWAAAICJkWAAAICJoWAAAICJsWAAAICJwWAAAICJ0WAAAICJ4WAAAICJ8WAAAICKAWAAAICKEWAAAICKIWAAAICKMWAAAICKQWAAAICKUWAAAICKYWAAAICKcWAAAICKgWAAAICKkWAAAICKoWAAAICKsWAAAICKwWAAAICK0WAAAICK4WAAAICK8WAAAICLAWAAAICLEWAAAICLIWAAAICLMWAAAICLQWAAAICLUWAAAICLYWAAAICLcWAAAICLgWAAAICLkWAAAICLoWAAAICLsWAAAICLwWAAAICL0WAAAICL4WAAAICL8WAAAICMAWAAAICMEWAAAICMIWAAAICMMWAAAICMQWAAAICMUWAAAICMYWAAAICMcWAAAICMgWAAAICMkWAAAICMoWAAAICMsWAAAICMwWAAAICM0WAAAICM4WAAAICM8WAAAICNAWAAAICNEWAAAICNIWAAAICNMWAAAICNQWAAAICNUWAAAICNYWAAAICNcWAAAICNgWAAAICNkWAAAICNoWAAAICNsWAAAICNwWAAAICN0WAAAICN4WAAAICN8WAAAICOAWAAAICOEWAAAICOIWAAAICOMWAAAICOQWAAAICOUWAAAICOYWAAAICOcWAAAICOgWAAAICOkWAAAICOoWAAAICOsWAAAICOwWAAAICO0WAAAICO4WAAAICO8WAAAICPAWAAAICPEWAAAICPIWAAAICPMWAAAICPQWAAAICPUWAAAICPYWAAAICPcWAAAICPgWAAAICPkWAAAICPoWAAAICPsWAAAICPwWAAAICP0WAAAICP4WAAAICP8WAAAICAAXAAAICAEXAAAICAIXAAAICAMXAAAICAQXAAAICAUXAAAICAYXAAAICAcXAAAICAgXAAAICAkXAAAICAoXAAAICAsXAAAICAwXAAAICA0XAAAICA4XAAAICA8XAAAICBAXAAAICBEXAAAICBIXAAAICBMXAAAICBQXAAAICBUXAAAICBYXAAAICBcXAAAICBgXAAAICBkXAAAICBoXAAAICBsXAAAICBwXAAAICB0XAAAICB4XAAAICB8XAAAICCAXAAAICCEXAAAICCIXAAAICCMXAAAICCQXAAAICCUXAAAICCYXAAAICCcXAAAICCgXAAAICCkXAAAICCoXAAAICCsXAAAICCwXAAAICC0XAAAICC4XAAAICC8XAAAICDAXAAAICDEXAAAICDIXAAAICDMXAAAICDQXAAAICDUXAAAICDYXAAAICDcXAAAICDgXAAAICDkXAAAICDoXAAAICDsXAAAICDwXAAAICD0XAAAICD4XAAAICD8XAAAICEAXAAAICEEXAAAICEIXAAAICEMXAAAICEQXAAAICEUXAAAICEYXAAAICEcXAAAICEgXAAAICEkXAAAICEoXAAAICEsXAAAICEwXAAAICE0XAAAICE4XAAAICE8XAAAICFAXAAAICFEXAAAICFIXAAAICFMXAAAICFQXAAAICFUXAAAICFYXAAAICFcXAAAICFgXAAAICFkXAAAICFoXAAAICFsXAAAICFwXAAAICF0XAAAICF4XAAAICF8XAAAICGAXAAAICGEXAAAICGIXAAAICGMXAAAICGQXAAAICGUXAAAICGYXAAAICGcXAAAICGgXAAAICGkXAAAICGoXAAAICGsXAAAICGwXAAAICG0XAAAICG4XAAAICG8XAAAICHAXAAAICHEXAAAICHIXAAAICHMXAAAICHQXAAAICHUXAAAICHYXAAAICHcXAAAICHgXAAAICHkXAAAICHoXAAAICHsXAAAICHwXAAAICH0XAAAICH4XAAAICH8XAAAICIAXAAAICIEXAAAICIIXAAAICIMXAAAICIQXAAAICIUXAAAICIYXAAAICIcXAAAICIgXAAAICIkXAAAICIoXAAAICIsXAAAICIwXAAAICI0XAAAICI4XAAAICI8XAAAICJAXAAAICJEXAAAICJIXAAAICJMXAAAICJQXAAAICJUXAAAICJYXAAAICJcXAAAICJgXAAAICJkXAAAICJoXAAAICJsXAAAICJwXAAAICJ0XAAAICJ4XAAAICJ8XAAAICKAXAAAICKEXAAAICKIXAAAICKMXAAAICKQXAAAICKUXAAAICKYXAAAICKcXAAAICKgXAAAICKkXAAAICKoXAAAICKsXAAAICKwXAAAICK0XAAAICK4XAAAICK8XAAAICLAXAAAICLEXAAAICLIXAAAICLMXAAAICLQXAAAICLUXAAAICLYXAAAICLcXAAAICLgXAAAICLkXAAAICLoXAAAICLsXAAAICLwXAAAICL0XAAAICL4XAAAICL8XAAAICMAXAAAICMEXAAAICMIXAAAICMMXAAAICMQXAAAICMUXAAAICMYXAAAICMcXAAAICMgXAAAICMkXAAAICMoXAAAICMsXAAAICMwXAAAICM0XAAAICM4XAAAICM8XAAAICNAXAAAICNEXAAAICNIXAAAICNMXAAAICNQXAAAICNUXAAAICNYXAAAICNcXAAAICNgXAAAICNkXAAAICNoXAAAICNsXAAAICNwXAAAICN0XAAAICN4XAAAICN8XAAAICOAXAAAICOEXAAAICOIXAAAICOMXAAAICOQXAAAICOUXAAAICOYXAAAICOcXAAAICOgXAAAICOkXAAAICOoXAAAICOsXAAAICOwXAAAICO0XAAAICO4XAAAICO8XAAAICPAXAAAICPEXAAAICPIXAAAICPMXAAAICPQXAAAICPUXAAAICPYXAAAICPcXAAAICPgXAAAICPkXAAAICPoXAAAICPsXAAAICPwXAAAICP0XAAAICP4XAAAICP8XAAAICAAYAAAICAEYAAAICAIYAAAICAMYAAAICAQYAAAICAUYAAAICAYYAAAICAcYAAAICAgYAAAICAkYAAAICAoYAAAICAsYAAAICAwYAAAICA0YAAAICA4YAAAICA8YAAAICBAYAAAICBEYAAAICBIYAAAICBMYAAAICBQYAAAICBUYAAAICBYYAAAICBcYAAAICBgYAAAICBkYAAAICBoYAAAICBsYAAAICBwYAAAICB0YAAAICB4YAAAICB8YAAAICCAYAAAICCEYAAAICCIYAAAICCMYAAAICCQYAAAICCUYAAAICCYYAAAICCcYAAAICCgYAAAICCkYAAAICCoYAAAICCsYAAAICCwYAAAICC0YAAAICC4YAAAICC8YAAAICDAYAAAICDEYAAAICDIYAAAICDMYAAAICDQYAAAICDUYAAAICDYYAAAICDcYAAAICDgYAAAICDkYAAAICDoYAAAICDsYAAAICDwYAAAICD0YAAAICD4YAAAICD8YAAAICEAYAAAICEEYAAAICEIYAAAICEMYAAAICEQYAAAICEUYAAAICEYYAAAICEcYAAAICEgYAAAICEkYAAAICEoYAAAICEsYAAAICEwYAAAICE0YAAAICE4YAAAICE8YAAAICFAYAAAICFEYAAAICFIYAAAICFMYAAAICFQYAAAICFUYAAAICFYYAAAICFcYAAAICFgYAAAICFkYAAAICFoYAAAICFsYAAAICFwYAAAICF0YAAAICF4YAAAICF8YAAAICGAYAAAICGEYAAAICGIYAAAICGMYAAAICGQYAAAICGUYAAAICGYYAAAICGcYAAAICGgYAAAICGkYAAAICGoYAAAICGsYAAAICGwYAAAICG0YAAAICG4YAAAICG8YAAAICHAYAAAICHEYAAAICHIYAAAICHMYAAAICHQYAAAICHUYAAAICHYYAAAICHcYAAAICHgYAAAICHkYAAAICHoYAAAICHsYAAAICHwYAAAICH0YAAAICH4YAAAICH8YAAAICIAYAAAICIEYAAAICIIYAAAICIMYAAAICIQYAAAICIUYAAAICIYYAAAICIcYAAAICIgYAAAICIkYAAAICIoYAAAICIsYAAAICIwYAAAICI0YAAAICI4YAAAICI8YAAAICJAYAAAICJEYAAAICJIYAAAICJMYAAAICJQYAAAICJUYAAAICJYYAAAICJcYAAAICJgYAAAICJkYAAAICJoYAAAICJsYAAAICJwYAAAICJ0YAAAICJ4YAAAICJ8YAAAICKAYAAAICKEYAAAICKIYAAAICKMYAAAICKQYAAAICKUYAAAICKYYAAAICKcYAAAICKgYAAAICKkYAAAICKoYAAAICKsYAAAICKwYAAAICK0YAAAICK4YAAAICK8YAAAICLAYAAAICLEYAAAICLIYAAAICLMYAAAICLQYAAAICLUYAAAICLYYAAAICLcYAAAICLgYAAAICLkYAAAICLoYAAAICLsYAAAICLwYAAAICL0YAAAICL4YAAAICL8YAAAICMAYAAAICMEYAAAICMIYAAAICMMYAAAICMQYAAAICMUYAAAICMYYAAAICMcYAAAICMgYAAAICMkYAAAICMoYAAAICMsYAAAICMwYAAAICM0YAAAICM4YAAAICM8YAAAICNAYAAAICNEYAAAICNIYAAAICNMYAAAICNQYAAAICNUYAAAICNYYAAAICNcYAAAICNgYAAAICNkYAAAICNoYAAAICNsYAAAICNwYAAAICN0YAAAICN4YAAAICN8YAAAICOAYAAAICOEYAAAICOIYAAAICOMYAAAICOQYAAAICOUYAAAICOYYAAAICOcYAAAICOgYAAAICOkYAAAICOoYAAAICOsYAAAICOwYAAAICO0YAAAICO4YAAAICO8YAAAICPAYAAAICPEYAAAICPIYAAAICPMYAAAICPQYAAAICPUYAAAICPYYAAAICPcYAAAICPgYAAAICPkYAAAICPoYAAAICPsYAAAICPwYAAAICP0YAAAICP4YAAAICP8YAAAICAAZAAAICAEZAAAICAIZAAAICAMZAAAICAQZAAAICAUZAAAICAYZAAAICAcZAAAICAgZAAAICAkZAAAICAoZAAAICAsZAAAICAwZAAAICA0ZAAAICA4ZAAAICA8ZAAAICBAZAAAICBEZAAAICBIZAAAICBMZAAAICBQZAAAICBUZAAAICBYZAAAICBcZAAAICBgZAAAICBkZAAAICBoZAAAICBsZAAAICBwZAAAICB0ZAAAICB4ZAAAICB8ZAAAICCAZAAAICCEZAAAICCIZAAAICCMZAAAICCQZAAAICCUZAAAICCYZAAAICCcZAAAICCgZAAAICCkZAAAICCoZAAAICCsZAAAICCwZAAAICC0ZAAAICC4ZAAAICC8ZAAAICDAZAAAICDEZAAAICDIZAAAICDMZAAAICDQZAAAICDUZAAAICDYZAAAICDcZAAAICDgZAAAICDkZAAAICDoZAAAICDsZAAAICDwZAAAICD0ZAAAICD4ZAAAICD8ZAAAICEAZAAAICEEZAAAICEIZAAAICEMZAAAICEQZAAAICEUZAAAICEYZAAAICEcZAAAICEgZAAAICEkZAAAICEoZAAAICEsZAAAICEwZAAAICE0ZAAAICE4ZAAAICE8ZAAAICFAZAAAICFEZAAAICFIZAAAICFMZAAAICFQZAAAICFUZAAAICFYZAAAICFcZAAAICFgZAAAICFkZAAAICFoZAAAICFsZAAAICFwZAAAICF0ZAAAICF4ZAAAICF8ZAAAICGAZAAAICGEZAAAICGIZAAAICGMZAAAICGQZAAAICGUZAAAICGYZAAAICGcZAAAICGgZAAAICGkZAAAICGoZAAAICGsZAAAICGwZAAAICG0ZAAAICG4ZAAAICG8ZAAAICHAZAAAICHEZAAAICHIZAAAICHMZAAAICHQZAAAICHUZAAAICHYZAAAICHcZAAAICHgZAAAICHkZAAAICHoZAAAICHsZAAAICHwZAAAICH0ZAAAICH4ZAAAICH8ZAAAICIAZAAAICIEZAAAICIIZAAAICIMZAAAICIQZAAAICIUZAAAICIYZAAAICIcZAAAICIgZAAAICIkZAAAICIoZAAAICIsZAAAICIwZAAAICI0ZAAAICI4ZAAAICI8ZAAAICJAZAAAICJEZAAAICJIZAAAICJMZAAAICJQZAAAICJUZAAAICJYZAAAICJcZAAAICJgZAAAICJkZAAAICJoZAAAICJsZAAAICJwZAAAICJ0ZAAAICJ4ZAAAICJ8ZAAAICKAZAAAICKEZAAAICKIZAAAICKMZAAAICKQZAAAICKUZAAAICKYZAAAICKcZAAAICKgZAAAICKkZAAAICKoZAAAICKsZAAAICKwZAAAICK0ZAAAICK4ZAAAICK8ZAAAICLAZAAAICLEZAAAICLIZAAAICLMZAAAICLQZAAAICLUZAAAICLYZAAAICLcZAAAICLgZAAAICLkZAAAICLoZAAAICLsZAAAICLwZAAAICL0ZAAAICL4ZAAAICL8ZAAAICMAZAAAICMEZAAAICMIZAAAICMMZAAAICMQZAAAICMUZAAAICMYZAAAICMcZAAAICMgZAAAICMkZAAAICMoZAAAICMsZAAAICMwZAAAICM0ZAAAICM4ZAAAICM8ZAAAICNAZAAAICNEZAAAICNIZAAAICNMZAAAICNQZAAAICNUZAAAICNYZAAAICNcZAAAICNgZAAAICNkZAAAICNoZAAAICNsZAAAICNwZAAAICN0ZAAAICN4ZAAAICN8ZAAAICOAZAAAICOEZAAAICOIZAAAICOMZAAAICOQZAAAICOUZAAAICOYZAAAICOcZAAAICOgZAAAICOkZAAAICOoZAAAICOsZAAAICOwZAAAICO0ZAAAICO4ZAAAICO8ZAAAICPAZAAAICPEZAAAICPIZAAAICPMZAAAICPQZAAAICPUZAAAICPYZAAAICPcZAAAICPgZAAAICPkZAAAICPoZAAAICPsZAAAICPwZAAAICP0ZAAAICP4ZAAAICP8ZAAAICAAaAAAICAEaAAAICAIaAAAICAMaAAAICAQaAAAICAUaAAAICAYaAAAICAcaAAAICAgaAAAICAkaAAAICAoaAAAICAsaAAAICAwaAAAICA0aAAAICA4aAAAICA8aAAAICBAaAAAICBEaAAAICBIaAAAICBMaAAAICBQaAAAICBUaAAAICBYaAAAICBcaAAAICBgaAAAICBkaAAAICBoaAAAICBsaAAAICBwaAAAICB0aAAAICB4aAAAICB8aAAAICCAaAAAICCEaAAAICCIaAAAICCMaAAAICCQaAAAICCUaAAAICCYaAAAICCcaAAAICCgaAAAICCkaAAAICCoaAAAICCsaAAAICCwaAAAICC0aAAAICC4aAAAICC8aAAAICDAaAAAICDEaAAAICDIaAAAICDMaAAAICDQaAAAICDUaAAAICDYaAAAICDcaAAAICDgaAAAICDkaAAAICDoaAAAICDsaAAAICDwaAAAICD0aAAAICD4aAAAICD8aAAAICEAaAAAICEEaAAAICEIaAAAICEMaAAAICEQaAAAICEUaAAAICEYaAAAICEcaAAAICEgaAAAICEkaAAAICEoaAAAICEsaAAAICEwaAAAICE0aAAAICE4aAAAICE8aAAAICFAaAAAICFEaAAAICFIaAAAICFMaAAAICFQaAAAICFUaAAAICFYaAAAICFcaAAAICFgaAAAICFkaAAAICFoaAAAICFsaAAAICFwaAAAICF0aAAAICF4aAAAICF8aAAAICGAaAAAICGEaAAAICGIaAAAICGMaAAAICGQaAAAICGUaAAAICGYaAAAICGcaAAAICGgaAAAICGkaAAAICGoaAAAICGsaAAAICGwaAAAICG0aAAAICG4aAAAICG8aAAAICHAaAAAICHEaAAAICHIaAAAICHMaAAAICHQaAAAICHUaAAAICHYaAAAICHcaAAAICHgaAAAICHkaAAAICHoaAAAICHsaAAAICHwaAAAICH0aAAAICH4aAAAICH8aAAAICIAaAAAICIEaAAAICIIaAAAICIMaAAAICIQaAAAICIUaAAAICIYaAAAICIcaAAAICIgaAAAICIkaAAAICIoaAAAICIsaAAAICIwaAAAICI0aAAAICI4aAAAICI8aAAAICJAaAAAICJEaAAAICJIaAAAICJMaAAAICJQaAAAICJUaAAAICJYaAAAICJcaAAAICJgaAAAICJkaAAAICJoaAAAICJsaAAAICJwaAAAICJ0aAAAICJ4aAAAICJ8aAAAICKAaAAAICKEaAAAICKIaAAAICKMaAAAICKQaAAAICKUaAAAICKYaAAAICKcaAAAICKgaAAAICKkaAAAICKoaAAAICKsaAAAICKwaAAAICK0aAAAICK4aAAAICK8aAAAICLAaAAAICLEaAAAICLIaAAAICLMaAAAICLQaAAAICLUaAAAICLYaAAAICLcaAAAICLgaAAAICLkaAAAICLoaAAAICLsaAAAICLwaAAAICL0aAAAICL4aAAAICL8aAAAICMAaAAAICMEaAAAICMIaAAAICMMaAAAICMQaAAAICMUaAAAICMYaAAAICMcaAAAICMgaAAAICMkaAAAICMoaAAAICMsaAAAICMwaAAAICM0aAAAICM4aAAAICM8aAAAICNAaAAAICNEaAAAICNIaAAAICNMaAAAICNQaAAAICNUaAAAICNYaAAAICNcaAAAICNgaAAAICNkaAAAICNoaAAAICNsaAAAICNwaAAAICN0aAAAICN4aAAAICN8aAAAICOAaAAAICOEaAAAICOIaAAAICOMaAAAICOQaAAAICOUaAAAICOYaAAAICOcaAAAICOgaAAAICOkaAAAICOoaAAAICOsaAAAICOwaAAAICO0aAAAICO4aAAAICO8aAAAICPAaAAAICPEaAAAICPIaAAAICPMaAAAICPQaAAAICPUaAAAICPYaAAAICPcaAAAICPgaAAAICPkaAAAICPoaAAAICPsaAAAICPwaAAAICP0aAAAICP4aAAAICP8aAAAICAAbAAAICAEbAAAICAIbAAAICAMbAAAICAQbAAAICAUbAAAICAYbAAAICAcbAAAICAgbAAAICAkbAAAICAobAAAICAsbAAAICAwbAAAICA0bAAAICA4bAAAICA8bAAAICBAbAAAICBEbAAAICBIbAAAICBMbAAAICBQbAAAICBUbAAAICBYbAAAICBcbAAAICBgbAAAICBkbAAAICBobAAAICBsbAAAICBwbAAAICB0bAAAICB4bAAAICB8bAAAICCAbAAAICCEbAAAICCIbAAAICCMbAAAICCQbAAAICCUbAAAICCYbAAAICCcbAAAICCgbAAAICCkbAAAICCobAAAICCsbAAAICCwbAAAICC0bAAAICC4bAAAICC8bAAAICDAbAAAICDEbAAAICDIbAAAICDMbAAAICDQbAAAICDUbAAAICDYbAAAICDcbAAAICDgbAAAICDkbAAAICDobAAAICDsbAAAICDwbAAAICD0bAAAICD4bAAAICD8bAAAICEAbAAAICEEbAAAICEIbAAAICEMbAAAICEQbAAAICEUbAAAICEYbAAAICEcbAAAICEgbAAAICEkbAAAICEobAAAICEsbAAAICEwbAAAICE0bAAAICE4bAAAICE8bAAAICFAbAAAICFEbAAAICFIbAAAICFMbAAAICFQbAAAICFUbAAAICFYbAAAICFcbAAAICFgbAAAICFkbAAAICFobAAAICFsbAAAICFwbAAAICF0bAAAICF4bAAAICF8bAAAICGAbAAAICGEbAAAICGIbAAAICGMbAAAICGQbAAAICGUbAAAICGYbAAAICGcbAAAICGgbAAAICGkbAAAICGobAAAICGsbAAAICGwbAAAICG0bAAAICG4bAAAICG8bAAAICHAbAAAICHEbAAAICHIbAAAICHMbAAAICHQbAAAICHUbAAAICHYbAAAICHcbAAAICHgbAAAICHkbAAAICHobAAAICHsbAAAICHwbAAAICH0bAAAICH4bAAAICH8bAAAICIAbAAAICIEbAAAICIIbAAAICIMbAAAICIQbAAAICIUbAAAICIYbAAAICIcbAAAICIgbAAAICIkbAAAICIobAAAICIsbAAAICIwbAAAICI0bAAAICI4bAAAICI8bAAAICJAbAAAICJEbAAAICJIbAAAICJMbAAAICJQbAAAICJUbAAAICJYbAAAICJcbAAAICJgbAAAICJkbAAAICJobAAAICJsbAAAICJwbAAAICJ0bAAAICJ4bAAAICJ8bAAAICKAbAAAICKEbAAAICKIbAAAICKMbAAAICKQbAAAICKUbAAAICKYbAAAICKcbAAAICKgbAAAICKkbAAAICKobAAAICKsbAAAICKwbAAAICK0bAAAICK4bAAAICK8bAAAICLAbAAAICLEbAAAICLIbAAAICLMbAAAICLQbAAAICLUbAAAICLYbAAAICLcbAAAICLgbAAAICLkbAAAICLobAAAICLsbAAAICLwbAAAICL0bAAAICL4bAAAICL8bAAAICMAbAAAICMEbAAAICMIbAAAICMMbAAAICMQbAAAICMUbAAAICMYbAAAICMcbAAAICMgbAAAICMkbAAAICMobAAAICMsbAAAICMwbAAAICM0bAAAICM4bAAAICM8bAAAICNAbAAAICNEbAAAICNIbAAAICNMbAAAICNQbAAAICNUbAAAICNYbAAAICNcbAAAICNgbAAAICNkbAAAICNobAAAICNsbAAAICNwbAAAICN0bAAAICN4bAAAICN8bAAAICOAbAAAICOEbAAAICOIbAAAICOMbAAAICOQbAAAICOUbAAAICOYbAAAICOcbAAAICOgbAAAICOkbAAAICOobAAAICOsbAAAICOwbAAAICO0bAAAICO4bAAAICO8bAAAICPAbAAAICPEbAAAICPIbAAAICPMbAAAICPQbAAAICPUbAAAICPYbAAAICPcbAAAICPgbAAAICPkbAAAICPobAAAICPsbAAAICPwbAAAICP0bAAAICP4bAAAICP8bAAAICAAcAAAICAEcAAAICAIcAAAICAMcAAAICAQcAAAICAUcAAAICAYcAAAICAccAAAICAgcAAAICAkcAAAICAocAAAICAscAAAICAwcAAAICA0cAAAICA4cAAAICA8cAAAICBAcAAAICBEcAAAICBIcAAAICBMcAAAICBQcAAAICBUcAAAICBYcAAAICBccAAAICBgcAAAICBkcAAAICBocAAAICBscAAAICBwcAAAICB0cAAAICB4cAAAICB8cAAAICCAcAAAICCEcAAAICCIcAAAICCMcAAAICCQcAAAICCUcAAAICCYcAAAICCccAAAICCgcAAAICCkcAAAICCocAAAICCscAAAICCwcAAAICC0cAAAICC4cAAAICC8cAAAICDAcAAAICDEcAAAICDIcAAAICDMcAAAICDQcAAAICDUcAAAICDYcAAAICDccAAAICDgcAAAICDkcAAAICDocAAAICDscAAAICDwcAAAICD0cAAAICD4cAAAICD8cAAAICEAcAAAICEEcAAAICEIcAAAICEMcAAAICEQcAAAICEUcAAAICEYcAAAICEccAAAICEgcAAAICEkcAAAICEocAAAICEscAAAICEwcAAAICE0cAAAICE4cAAAICE8cAAAICFAcAAAICFEcAAAICFIcAAAICFMcAAAICFQcAAAICFUcAAAICFYcAAAICFccAAAICFgcAAAICFkcAAAICFocAAAICFscAAAICFwcAAAICF0cAAAICF4cAAAICF8cAAAICGAcAAAICGEcAAAICGIcAAAICGMcAAAICGQcAAAICGUcAAAICGYcAAAICGccAAAICGgcAAAICGkcAAAICGocAAAICGscAAAICGwcAAAICG0cAAAICG4cAAAICG8cAAAICHAcAAAICHEcAAAICHIcAAAICHMcAAAICHQcAAAICHUcAAAICHYcAAAICHccAAAICHgcAAAICHkcAAAICHocAAAICHscAAAICHwcAAAICH0cAAAICH4cAAAICH8cAAAICIAcAAAICIEcAAAICIIcAAAICIMcAAAICIQcAAAICIUcAAAICIYcAAAICIccAAAICIgcAAAICIkcAAAICIocAAAICIscAAAICIwcAAAICI0cAAAICI4cAAAICI8cAAAICJAcAAAICJEcAAAICJIcAAAICJMcAAAICJQcAAAICJUcAAAICJYcAAAICJccAAAICJgcAAAICJkcAAAICJocAAAICJscAAAICJwcAAAICJ0cAAAICJ4cAAAICJ8cAAAICKAcAAAICKEcAAAICKIcAAAICKMcAAAICKQcAAAICKUcAAAICKYcAAAICKccAAAICKgcAAAICKkcAAAICKocAAAICKscAAAICKwcAAAICK0cAAAICK4cAAAICK8cAAAICLAcAAAICLEcAAAICLIcAAAICLMcAAAICLQcAAAICLUcAAAICLYcAAAICLccAAAICLgcAAAICLkcAAAICLocAAAICLscAAAICLwcAAAICL0cAAAICL4cAAAICL8cAAAICMAcAAAICMEcAAAICMIcAAAICMMcAAAICMQcAAAICMUcAAAICMYcAAAICMccAAAICMgcAAAICMkcAAAICMocAAAICMscAAAICMwcAAAICM0cAAAICM4cAAAICM8cAAAICNAcAAAICNEcAAAICNIcAAAICNMcAAAICNQcAAAICNUcAAAICNYcAAAICNccAAAICNgcAAAICNkcAAAICNocAAAICNscAAAICNwcAAAICN0cAAAICN4cAAAICN8cAAAICOAcAAAICOEcAAAICOIcAAAICOMcAAAICOQcAAAICOUcAAAICOYcAAAICOccAAAICOgcAAAICOkcAAAICOocAAAICOscAAAICOwcAAAICO0cAAAICO4cAAAICO8cAAAICPAcAAAICPEcAAAICPIcAAAICPMcAAAICPQcAAAICPUcAAAICPYcAAAICPccAAAICPgcAAAICPkcAAAICPocAAAICPscAAAICPwcAAAICP0cAAAICP4cAAAICP8cAAAICAAdAAAICAEdAAAICAIdAAAICAMdAAAICAQdAAAICAUdAAAICAYdAAAICAcdAAAICAgdAAAICAkdAAAICAodAAAICAsdAAAICAwdAAAICA0dAAAICA4dAAAICA8dAAAICBAdAAAICBEdAAAICBIdAAAICBMdAAAICBQdAAAICBUdAAAICBYdAAAICBcdAAAICBgdAAAICBkdAAAICBodAAAICBsdAAAICBwdAAAICB0dAAAICB4dAAAICB8dAAAICCAdAAAICCEdAAAICCIdAAAICCMdAAAICCQdAAAICCUdAAAICCYdAAAICCcdAAAICCgdAAAICCkdAAAICCodAAAICCsdAAAICCwdAAAICC0dAAAICC4dAAAICC8dAAAICDAdAAAICDEdAAAICDIdAAAICDMdAAAICDQdAAAICDUdAAAICDYdAAAICDcdAAAICDgdAAAICDkdAAAICDodAAAICDsdAAAICDwdAAAICD0dAAAICD4dAAAICD8dAAAICEAdAAAICEEdAAAICEIdAAAICEMdAAAICEQdAAAICEUdAAAICEYdAAAICEcdAAAICEgdAAAICEkdAAAICEodAAAICEsdAAAICEwdAAAICE0dAAAICE4dAAAICE8dAAAICFAdAAAICFEdAAAICFIdAAAICFMdAAAICFQdAAAICFUdAAAICFYdAAAICFcdAAAICFgdAAAICFkdAAAICFodAAAICFsdAAAICFwdAAAICF0dAAAICF4dAAAICF8dAAAICGAdAAAICGEdAAAICGIdAAAICGMdAAAICGQdAAAICGUdAAAICGYdAAAICGcdAAAICGgdAAAICGkdAAAICGodAAAICGsdAAAICGwdAAAICG0dAAAICG4dAAAICG8dAAAICHAdAAAICHEdAAAICHIdAAAICHMdAAAICHQdAAAICHUdAAAICHYdAAAICHcdAAAICHgdAAAICHkdAAAICHodAAAICHsdAAAICHwdAAAICH0dAAAICH4dAAAICH8dAAAICIAdAAAICIEdAAAICIIdAAAICIMdAAAICIQdAAAICIUdAAAICIYdAAAICIcdAAAICIgdAAAICIkdAAAICIodAAAICIsdAAAICIwdAAAICI0dAAAICI4dAAAICI8dAAAICJAdAAAICJEdAAAICJIdAAAICJMdAAAICJQdAAAICJUdAAAICJYdAAAICJcdAAAICJgdAAAICJkdAAAICJodAAAICJsdAAAICJwdAAAICJ0dAAAICJ4dAAAICJ8dAAAICKAdAAAICKEdAAAICKIdAAAICKMdAAAICKQdAAAICKUdAAAICKYdAAAICKcdAAAICKgdAAAICKkdAAAICKodAAAICKsdAAAICKwdAAAICK0dAAAICK4dAAAICK8dAAAICLAdAAAICLEdAAAICLIdAAAICLMdAAAICLQdAAAICLUdAAAICLYdAAAICLcdAAAICLgdAAAICLkdAAAICLodAAAICLsdAAAICLwdAAAICL0dAAAICL4dAAAICL8dAAAICMAdAAAICMEdAAAICMIdAAAICMMdAAAICMQdAAAICMUdAAAICMYdAAAICMcdAAAICMgdAAAICMkdAAAICModAAAICMsdAAAICMwdAAAICM0dAAAICM4dAAAICM8dAAAICNAdAAAICNEdAAAICNIdAAAICNMdAAAICNQdAAAICNUdAAAICNYdAAAICNcdAAAICNgdAAAICNkdAAAICNodAAAICNsdAAAICNwdAAAICN0dAAAICN4dAAAICN8dAAAICOAdAAAICOEdAAAICOIdAAAICOMdAAAICOQdAAAICOUdAAAICOYdAAAICOcdAAAICOgdAAAICOkdAAAICOodAAAICOsdAAAICOwdAAAICO0dAAAICO4dAAAICO8dAAAICPAdAAAICPEdAAAICPIdAAAICPMdAAAICPQdAAAICPUdAAAICPYdAAAICPcdAAAICPgdAAAICPkdAAAICPodAAAICPsdAAAICPwdAAAICP0dAAAICP4dAAAICP8dAAAICAAeAAAICAEeAAAICAIeAAAICAMeAAAICAQeAAAICAUeAAAICAYeAAAICAceAAAICAgeAAAICAkeAAAICAoeAAAICAseAAAICAweAAAICA0eAAAICA4eAAAICA8eAAAICBAeAAAICBEeAAAICBIeAAAICBMeAAAICBQeAAAICBUeAAAICBYeAAAICBceAAAICBgeAAAICBkeAAAICBoeAAAICBseAAAICBweAAAICB0eAAAICB4eAAAICB8eAAAICCAeAAAICCEeAAAICCIeAAAICCMeAAAICCQeAAAICCUeAAAICCYeAAAICCceAAAICCgeAAAICCkeAAAICCoeAAAICCseAAAICCweAAAICC0eAAAICC4eAAAICC8eAAAICDAeAAAICDEeAAAICDIeAAAICDMeAAAICDQeAAAICDUeAAAICDYeAAAICDceAAAICDgeAAAICDkeAAAICDoeAAAICDseAAAICDweAAAICD0eAAAICD4eAAAICD8eAAAICEAeAAAICEEeAAAICEIeAAAICEMeAAAICEQeAAAICEUeAAAICEYeAAAICEceAAAICEgeAAAICEkeAAAICEoeAAAICEseAAAICEweAAAICE0eAAAICE4eAAAICE8eAAAICFAeAAAICFEeAAAICFIeAAAICFMeAAAICFQeAAAICFUeAAAICFYeAAAICFceAAAICFgeAAAICFkeAAAICFoeAAAICFseAAAICFweAAAICF0eAAAICF4eAAAICF8eAAAICGAeAAAICGEeAAAICGIeAAAICGMeAAAICGQeAAAICGUeAAAICGYeAAAICGceAAAICGgeAAAICGkeAAAICGoeAAAICGseAAAICGweAAAICG0eAAAICG4eAAAICG8eAAAICHAeAAAICHEeAAAICHIeAAAICHMeAAAICHQeAAAICHUeAAAICHYeAAAICHceAAAICHgeAAAICHkeAAAICHoeAAAICHseAAAICHweAAAICH0eAAAICH4eAAAICH8eAAAICIAeAAAICIEeAAAICIIeAAAICIMeAAAICIQeAAAICIUeAAAICIYeAAAICIceAAAICIgeAAAICIkeAAAICIoeAAAICIseAAAICIweAAAICI0eAAAICI4eAAAICI8eAAAICJAeAAAICJEeAAAICJIeAAAICJMeAAAICJQeAAAICJUeAAAICJYeAAAICJceAAAICJgeAAAICJkeAAAICJoeAAAICJseAAAICJweAAAICJ0eAAAICJ4eAAAICJ8eAAAICKAeAAAICKEeAAAICKIeAAAICKMeAAAICKQeAAAICKUeAAAICKYeAAAICKceAAAICKgeAAAICKkeAAAICKoeAAAICKseAAAICKweAAAICK0eAAAICK4eAAAICK8eAAAICLAeAAAICLEeAAAICLIeAAAICLMeAAAICLQeAAAICLUeAAAICLYeAAAICLceAAAICLgeAAAICLkeAAAICLoeAAAICLseAAAICLweAAAICL0eAAAICL4eAAAICL8eAAAICMAeAAAICMEeAAAICMIeAAAICMMeAAAICMQeAAAICMUeAAAICMYeAAAICMceAAAICMgeAAAICMkeAAAICMoeAAAICMseAAAICMweAAAICM0eAAAICM4eAAAICM8eAAAICNAeAAAICNEeAAAICNIeAAAICNMeAAAICNQeAAAICNUeAAAICNYeAAAICNceAAAICNgeAAAICNkeAAAICNoeAAAICNseAAAICNweAAAICN0eAAAICN4eAAAICN8eAAAICOAeAAAICOEeAAAICOIeAAAICOMeAAAICOQeAAAICOUeAAAICOYeAAAICOceAAAICOgeAAAICOkeAAAICOoeAAAICOseAAAICOweAAAICO0eAAAICO4eAAAICO8eAAAICPAeAAAICPEeAAAICPIeAAAICPMeAAAICPQeAAAICPUeAAAICPYeAAAICPceAAAICPgeAAAICPkeAAAICPoeAAAICPseAAAICPweAAAICP0eAAAICP4eAAAICP8eAAAICAAfAAAICAEfAAAICAIfAAAICAMfAAAICAQfAAAICAUfAAAICAYfAAAICAcfAAAICAgfAAAICAkfAAAICAofAAAICAsfAAAICAwfAAAICA0fAAAICA4fAAAICA8fAAAICBAfAAAICBEfAAAICBIfAAAICBMfAAAICBQfAAAICBUfAAAICBYfAAAICBcfAAAICBgfAAAICBkfAAAICBofAAAICBsfAAAICBwfAAAICB0fAAAICB4fAAAICB8fAAAICCAfAAAICCEfAAAICCIfAAAICCMfAAAICCQfAAAICCUfAAAICCYfAAAICCcfAAAICCgfAAAICCkfAAAICCofAAAICCsfAAAICCwfAAAICC0fAAAICC4fAAAICC8fAAAICDAfAAAICDEfAAAICDIfAAAICDMfAAAICDQfAAAICDUfAAAICDYfAAAICDcfAAAICDgfAAAICDkfAAAICDofAAAICDsfAAAICDwfAAAICD0fAAAICD4fAAAICD8fAAAICEAfAAAICEEfAAAICEIfAAAICEMfAAAICEQfAAAICEUfAAAICEYfAAAICEcfAAAICEgfAAAICEkfAAAICEofAAAICEsfAAAICEwfAAAICE0fAAAICE4fAAAICE8fAAAICFAfAAAICFEfAAAICFIfAAAICFMfAAAICFQfAAAICFUfAAAICFYfAAAICFcfAAAICFgfAAAICFkfAAAICFofAAAICFsfAAAICFwfAAAICF0fAAAICF4fAAAICF8fAAAICGAfAAAICGEfAAAICGIfAAAICGMfAAAICGQfAAAICGUfAAAICGYfAAAICGcfAAAICGgfAAAICGkfAAAICGofAAAICGsfAAAICGwfAAAICG0fAAAICG4fAAAICG8fAAAICHAfAAAICHEfAAAICHIfAAAICHMfAAAICHQfAAAICHUfAAAICHYfAAAICHcfAAAICHgfAAAICHkfAAAICHofAAAICHsfAAAICHwfAAAICH0fAAAICH4fAAAICH8fAAAICIAfAAAICIEfAAAICIIfAAAICIMfAAAICIQfAAAICIUfAAAICIYfAAAICIcfAAAICIgfAAAICIkfAAAICIofAAAICIsfAAAICIwfAAAICI0fAAAICI4fAAAICI8fAAAICJAfAAAICJEfAAAICJIfAAAICJMfAAAICJQfAAAICJUfAAAICJYfAAAICJcfAAAICJgfAAAICJkfAAAICJofAAAICJsfAAAICJwfAAAICJ0fAAAICJ4fAAAICJ8fAAAICKAfAAAICKEfAAAICKIfAAAICKMfAAAICKQfAAAICKUfAAAICKYfAAAICKcfAAAICKgfAAAICKkfAAAICKofAAAICKsfAAAICKwfAAAICK0fAAAICK4fAAAICK8fAAAICLAfAAAICLEfAAAICLIfAAAICLMfAAAICLQfAAAICLUfAAAICLYfAAAICLcfAAAICLgfAAAICLkfAAAICLofAAAICLsfAAAICLwfAAAICL0fAAAICL4fAAAICL8fAAAICMAfAAAICMEfAAAICMIfAAAICMMfAAAICMQfAAAICMUfAAAICMYfAAAICMcfAAAICMgfAAAICMkfAAAICMofAAAICMsfAAAICMwfAAAICM0fAAAICM4fAAAICM8fAAAICNAfAAAICNEfAAAICNIfAAAICNMfAAAICNQfAAAICNUfAAAICNYfAAAICNcfAAAICNgfAAAICNkfAAAICNofAAAICNsfAAAICNwfAAAICN0fAAAICN4fAAAICN8fAAAICOAfAAAICOEfAAAICOIfAAAICOMfAAAICOQfAAAICOUfAAAICOYfAAAICOcfAAAICOgfAAAICOkfAAAICOofAAAICOsfAAAICOwfAAAICO0fAAAICO4fAAAICO8fAAAICPAfAAAICPEfAAAICPIfAAAICPMfAAAICPQfAAAICPUfAAAICPYfAAAICPcfAAAICPgfAAAICPkfAAAICPofAAAICPsfAAAICPwfAAAICP0fAAAICP4fAAAICP8fAAAICAAgAAAICAEgAAAICAIgAAAICAMgAAAICAQgAAAICAUgAAAICAYgAAAICAcgAAAICAggAAAICAkgAAAICAogAAAICAsgAAAICAwgAAAICA0gAAAICA4gAAAICA8gAAAICBAgAAAICBEgAAAICBIgAAAICBMgAAAICBQgAAAICBUgAAAICBYgAAAICBcgAAAICBggAAAICBkgAAAICBogAAAICBsgAAAICBwgAAAICB0gAAAICB4gAAAICB8gAAAICCAgAAAICCEgAAAICCIgAAAICCMgAAAICCQgAAAICCUgAAAICCYgAAAICCcgAAAICCggAAAICCkgAAAICCogAAAICCsgAAAICCwgAAAICC0gAAAICC4gAAAICC8gAAAICDAgAAAICDEgAAAICDIgAAAICDMgAAAICDQgAAAICDUgAAAICDYgAAAICDcgAAAICDggAAAICDkgAAAICDogAAAICDsgAAAICDwgAAAICD0gAAAICD4gAAAICD8gAAAICEAgAAAICEEgAAAICEIgAAAICEMgAAAICEQgAAAICEUgAAAICEYgAAAICEcgAAAICEggAAAICEkgAAAICEogAAAICEsgAAAICEwgAAAICE0gAAAICE4gAAAICE8gAAAICFAgAAAICFEgAAAICFIgAAAICFMgAAAICFQgAAAICFUgAAAICFYgAAAICFcgAAAICFggAAAICFkgAAAICFogAAAICFsgAAAICFwgAAAICF0gAAAICF4gAAAICF8gAAAICGAgAAAICGEgAAAICGIgAAAICGMgAAAICGQgAAAICGUgAAAICGYgAAAICGcgAAAICGggAAAICGkgAAAICGogAAAICGsgAAAICGwgAAAICG0gAAAICG4gAAAICG8gAAAICHAgAAAICHEgAAAICHIgAAAICHMgAAAICHQgAAAICHUgAAAICHYgAAAICHcgAAAICHggAAAICHkgAAAICHogAAAICHsgAAAICHwgAAAICH0gAAAICH4gAAAICH8gAAAICIAgAAAICIEgAAAICIIgAAAICIMgAAAICIQgAAAICIUgAAAICIYgAAAICIcgAAAICIggAAAICIkgAAAICIogAAAICIsgAAAICIwgAAAICI0gAAAICI4gAAAICI8gAAAICJAgAAAICJEgAAAICJIgAAAICJMgAAAICJQgAAAICJUgAAAICJYgAAAICJcgAAAICJggAAAICJkgAAAICJogAAAICJsgAAAICJwgAAAICJ0gAAAICJ4gAAAICJ8gAAAICKAgAAAICKEgAAAICKIgAAAICKMgAAAICKQgAAAICKUgAAAICKYgAAAICKcgAAAICKggAAAICKkgAAAICKogAAAICKsgAAAICKwgAAAICK0gAAAICK4gAAAICK8gAAAICLAgAAAICLEgAAAICLIgAAAICLMgAAAICLQgAAAICLUgAAAICLYgAAAICLcgAAAICLggAAAICLkgAAAICLogAAAICLsgAAAICLwgAAAICL0gAAAICL4gAAAICL8gAAAICMAgAAAICMEgAAAICMIgAAAICMMgAAAICMQgAAAICMUgAAAICMYgAAAICMcgAAAICMggAAAICMkgAAAICMogAAAICMsgAAAICMwgAAAICM0gAAAICM4gAAAICM8gAAAICNAgAAAICNEgAAAICNIgAAAICNMgAAAICNQgAAAICNUgAAAICNYgAAAICNcgAAAICNggAAAICNkgAAAICNogAAAICNsgAAAICNwgAAAICN0gAAAICN4gAAAICN8gAAAICOAgAAAICOEgAAAICOIgAAAICOMgAAAICOQgAAAICOUgAAAICOYgAAAICOcgAAAICOggAAAICOkgAAAICOogAAAICOsgAAAICOwgAAAICO0gAAAICO4gAAAICO8gAAAICPAgAAAICPEgAAAICPIgAAAICPMgAAAICPQgAAAICPUgAAAICPYgAAAICPcgAAAICPggAAAICPkgAAAICPogAAAICPsgAAAICPwgAAAICP0gAAAICP4gAAAICP8gAAAICAAhAAAICAEhAAAICAIhAAAICAMhAAAICAQhAAAICAUhAAAICAYhAAAICAchAAAICAghAAAICAkhAAAICAohAAAICAshAAAICAwhAAAICA0hAAAICA4hAAAICA8hAAAICBAhAAAICBEhAAAICBIhAAAICBMhAAAICBQhAAAICBUhAAAICBYhAAAICBchAAAICBghAAAICBkhAAAICBohAAAICBshAAAICBwhAAAICB0hAAAICB4hAAAICB8hAAAICCAhAAAICCEhAAAICCIhAAAICCMhAAAICCQhAAAICCUhAAAICCYhAAAICCchAAAICCghAAAICCkhAAAICCohAAAICCshAAAICCwhAAAICC0hAAAICC4hAAAICC8hAAAICDAhAAAICDEhAAAICDIhAAAICDMhAAAICDQhAAAICDUhAAAICDYhAAAICDchAAAICDghAAAICDkhAAAICDohAAAICDshAAAICDwhAAAICD0hAAAICD4hAAAICD8hAAAICEAhAAAICEEhAAAICEIhAAAICEMhAAAICEQhAAAICEUhAAAICEYhAAAICEchAAAICEghAAAICEkhAAAICEohAAAICEshAAAICEwhAAAICE0hAAAICE4hAAAICE8hAAAICFAhAAAICFEhAAAICFIhAAAICFMhAAAICFQhAAAICFUhAAAICFYhAAAICFchAAAICFghAAAICFkhAAAICFohAAAICFshAAAICFwhAAAICF0hAAAICF4hAAAICF8hAAAICGAhAAAICGEhAAAICGIhAAAICGMhAAAICGQhAAAICGUhAAAICGYhAAAICGchAAAICGghAAAICGkhAAAICGohAAAICGshAAAICGwhAAAICG0hAAAICG4hAAAICG8hAAAICHAhAAAICHEhAAAICHIhAAAICHMhAAAICHQhAAAICHUhAAAICHYhAAAICHchAAAICHghAAAICHkhAAAICHohAAAICHshAAAICHwhAAAICH0hAAAICH4hAAAICH8hAAAICIAhAAAICIEhAAAICIIhAAAICIMhAAAICIQhAAAICIUhAAAICIYhAAAICIchAAAICIghAAAICIkhAAAICIohAAAICIshAAAICIwhAAAICI0hAAAICI4hAAAICI8hAAAICJAhAAAICJEhAAAICJIhAAAICJMhAAAICJQhAAAICJUhAAAICJYhAAAICJchAAAICJghAAAICJkhAAAICJohAAAICJshAAAICJwhAAAICJ0hAAAICJ4hAAAICJ8hAAAICKAhAAAICKEhAAAICKIhAAAICKMhAAAICKQhAAAICKUhAAAICKYhAAAICKchAAAICKghAAAICKkhAAAICKohAAAICKshAAAICKwhAAAICK0hAAAICK4hAAAICK8hAAAICLAhAAAICLEhAAAICLIhAAAICLMhAAAICLQhAAAICLUhAAAICLYhAAAICLchAAAICLghAAAICLkhAAAICLohAAAICLshAAAICLwhAAAICL0hAAAICL4hAAAICL8hAAAICMAhAAAICMEhAAAICMIhAAAICMMhAAAICMQhAAAICMUhAAAICMYhAAAICMchAAAICMghAAAICMkhAAAICMohAAAICMshAAAICMwhAAAICM0hAAAICM4hAAAICM8hAAAICNAhAAAICNEhAAAICNIhAAAICNMhAAAICNQhAAAICNUhAAAICNYhAAAICNchAAAICNghAAAICNkhAAAICNohAAAICNshAAAICNwhAAAICN0hAAAICN4hAAAICN8hAAAICOAhAAAICOEhAAAICOIhAAAICOMhAAAICOQhAAAICOUhAAAICOYhAAAICOchAAAICOghAAAICOkhAAAICOohAAAICOshAAAICOwhAAAICO0hAAAICO4hAAAICO8hAAAICPAhAAAICPEhAAAICPIhAAAICPMhAAAICPQhAAAICPUhAAAICPYhAAAICPchAAAICPghAAAICPkhAAAICPohAAAICPshAAAICPwhAAAICP0hAAAICP4hAAAICP8hAAAICAAiAAAICAEiAAAICAIiAAAICAMiAAAICAQiAAAICAUiAAAICAYiAAAICAciAAAICAgiAAAICAkiAAAICAoiAAAICAsiAAAICAwiAAAICA0iAAAICA4iAAAICA8iAAAICBAiAAAICBEiAAAICBIiAAAICBMiAAAICBQiAAAICBUiAAAICBYiAAAICBciAAAICBgiAAAICBkiAAAICBoiAAAICBsiAAAICBwiAAAICB0iAAAICB4iAAAICB8iAAAICCAiAAAICCEiAAAICCIiAAAICCMiAAAICCQiAAAICCUiAAAICCYiAAAICCciAAAICCgiAAAICCkiAAAICCoiAAAICCsiAAAICCwiAAAICC0iAAAICC4iAAAICC8iAAAICDAiAAAICDEiAAAICDIiAAAICDMiAAAICDQiAAAICDUiAAAICDYiAAAICDciAAAICDgiAAAICDkiAAAICDoiAAAICDsiAAAICDwiAAAICD0iAAAICD4iAAAICD8iAAAICEAiAAAICEEiAAAICEIiAAAICEMiAAAICEQiAAAICEUiAAAICEYiAAAICEciAAAICEgiAAAICEkiAAAICEoiAAAICEsiAAAICEwiAAAICE0iAAAICE4iAAAICE8iAAAICFAiAAAICFEiAAAICFIiAAAICFMiAAAICFQiAAAICFUiAAAICFYiAAAICFciAAAICFgiAAAICFkiAAAICFoiAAAICFsiAAAICFwiAAAICF0iAAAICF4iAAAICF8iAAAICGAiAAAICGEiAAAICGIiAAAICGMiAAAICGQiAAAICGUiAAAICGYiAAAICGciAAAICGgiAAAICGkiAAAICGoiAAAICGsiAAAICGwiAAAICG0iAAAICG4iAAAICG8iAAAICHAiAAAICHEiAAAICHIiAAAICHMiAAAICHQiAAAICHUiAAAICHYiAAAICHciAAAICHgiAAAICHkiAAAICHoiAAAICHsiAAAICHwiAAAICH0iAAAICH4iAAAICH8iAAAICIAiAAAICIEiAAAICIIiAAAICIMiAAAICIQiAAAICIUiAAAICIYiAAAICIciAAAICIgiAAAICIkiAAAICIoiAAAICIsiAAAICIwiAAAICI0iAAAICI4iAAAICI8iAAAICJAiAAAICJEiAAAICJIiAAAICJMiAAAICJQiAAAICJUiAAAICJYiAAAICJciAAAICJgiAAAICJkiAAAICJoiAAAICJsiAAAICJwiAAAICJ0iAAAICJ4iAAAICJ8iAAAICKAiAAAICKEiAAAICKIiAAAICKMiAAAICKQiAAAICKUiAAAICKYiAAAICKciAAAICKgiAAAICKkiAAAICKoiAAAICKsiAAAICKwiAAAICK0iAAAICK4iAAAICK8iAAAICLAiAAAICLEiAAAICLIiAAAICLMiAAAICLQiAAAICLUiAAAICLYiAAAICLciAAAICLgiAAAICLkiAAAICLoiAAAICLsiAAAICLwiAAAICL0iAAAICL4iAAAICL8iAAAICMAiAAAICMEiAAAICMIiAAAICMMiAAAICMQiAAAICMUiAAAICMYiAAAICMciAAAICMgiAAAICMkiAAAICMoiAAAICMsiAAAICMwiAAAICM0iAAAICM4iAAAICM8iAAAICNAiAAAICNEiAAAICNIiAAAICNMiAAAICNQiAAAICNUiAAAICNYiAAAICNciAAAICNgiAAAICNkiAAAICNoiAAAICNsiAAAICNwiAAAICN0iAAAICN4iAAAICN8iAAAICOAiAAAICOEiAAAICOIiAAAICOMiAAAICOQiAAAICOUiAAAICOYiAAAICOciAAAICOgiAAAICOkiAAAICOoiAAAICOsiAAAICOwiAAAICO0iAAAICO4iAAAICO8iAAAICPAiAAAICPEiAAAICPIiAAAICPMiAAAICPQiAAAICPUiAAAICPYiAAAICPciAAAICPgiAAAICPkiAAAICPoiAAAICPsiAAAICPwiAAAICP0iAAAICP4iAAAICP8iAAAICAAjAAAICAEjAAAICAIjAAAICAMjAAAICAQjAAAICAUjAAAICAYjAAAICAcjAAAICAgjAAAICAkjAAAICAojAAAICAsjAAAICAwjAAAICA0jAAAICA4jAAAICA8jAAAICBAjAAAICBEjAAAICBIjAAAICBMjAAAICBQjAAAICBUjAAAICBYjAAAICBcjAAAICBgjAAAICBkjAAAICBojAAAICBsjAAAICBwjAAAICB0jAAAICB4jAAAICB8jAAAICCAjAAAICCEjAAAICCIjAAAICCMjAAAICCQjAAAICCUjAAAICCYjAAAICCcjAAAICCgjAAAICCkjAAAICCojAAAICCsjAAAICCwjAAAICC0jAAAICC4jAAAICC8jAAAICDAjAAAICDEjAAAICDIjAAAICDMjAAAICDQjAAAICDUjAAAICDYjAAAICDcjAAAICDgjAAAICDkjAAAICDojAAAICDsjAAAICDwjAAAICD0jAAAICD4jAAAICD8jAAAICEAjAAAICEEjAAAICEIjAAAICEMjAAAICEQjAAAICEUjAAAICEYjAAAICEcjAAAICEgjAAAICEkjAAAICEojAAAICEsjAAAICEwjAAAICE0jAAAICE4jAAAICE8jAAAICFAjAAAICFEjAAAICFIjAAAICFMjAAAICFQjAAAICFUjAAAICFYjAAAICFcjAAAICFgjAAAICFkjAAAICFojAAAICFsjAAAICFwjAAAICF0jAAAICF4jAAAICF8jAAAICGAjAAAICGEjAAAICGIjAAAICGMjAAAICGQjAAAICGUjAAAICGYjAAAICGcjAAAICGgjAAAICGkjAAAICGojAAAICGsjAAAICGwjAAAICG0jAAAICG4jAAAICG8jAAAICHAjAAAICHEjAAAICHIjAAAICHMjAAAICHQjAAAICHUjAAAICHYjAAAICHcjAAAICHgjAAAICHkjAAAICHojAAAICHsjAAAICHwjAAAICH0jAAAICH4jAAAICH8jAAAICIAjAAAICIEjAAAICIIjAAAICIMjAAAICIQjAAAICIUjAAAICIYjAAAICIcjAAAICIgjAAAICIkjAAAICIojAAAICIsjAAAICIwjAAAICI0jAAAICI4jAAAICI8jAAAICJAjAAAICJEjAAAICJIjAAAICJMjAAAICJQjAAAICJUjAAAICJYjAAAICJcjAAAICJgjAAAICJkjAAAICJojAAAICJsjAAAICJwjAAAICJ0jAAAICJ4jAAAICJ8jAAAICKAjAAAICKEjAAAICKIjAAAICKMjAAAICKQjAAAICKUjAAAICKYjAAAICKcjAAAICKgjAAAICKkjAAAICKojAAAICKsjAAAICKwjAAAICK0jAAAICK4jAAAICK8jAAAICLAjAAAICLEjAAAICLIjAAAICLMjAAAICLQjAAAICLUjAAAICLYjAAAICLcjAAAICLgjAAAICLkjAAAICLojAAAICLsjAAAICLwjAAAICL0jAAAICL4jAAAICL8jAAAICMAjAAAICMEjAAAICMIjAAAICMMjAAAICMQjAAAICMUjAAAICMYjAAAICMcjAAAICMgjAAAICMkjAAAICMojAAAICMsjAAAICMwjAAAICM0jAAAICM4jAAAICM8jAAAICNAjAAAICNEjAAAICNIjAAAICNMjAAAICNQjAAAICNUjAAAICNYjAAAICNcjAAAICNgjAAAICNkjAAAICNojAAAICNsjAAAICNwjAAAICN0jAAAICN4jAAAICN8jAAAICOAjAAAICOEjAAAICOIjAAAICOMjAAAICOQjAAAICOUjAAAICOYjAAAICOcjAAAICOgjAAAICOkjAAAICOojAAAICOsjAAAICOwjAAAICO0jAAAICO4jAAAICO8jAAAICPAjAAAICPEjAAAICPIjAAAICPMjAAAICPQjAAAICPUjAAAICPYjAAAICPcjAAAICPgjAAAICPkjAAAICPojAAAICPsjAAAICPwjAAAICP0jAAAICP4jAAAICP8jAAAICAAkAAAICAEkAAAICAIkAAAICAMkAAAICAQkAAAICAUkAAAICAYkAAAICAckAAAICAgkAAAICAkkAAAICAokAAAICAskAAAICAwkAAAICA0kAAAICA4kAAAICA8kAAAICBAkAAAICBEkAAAICBIkAAAICBMkAAAICBQkAAAICBUkAAAICBYkAAAICBckAAAICBgkAAAICBkkAAAICBokAAAICBskAAAICBwkAAAICB0kAAAICB4kAAAICB8kAAAICCAkAAAICCEkAAAICCIkAAAICCMkAAAICCQkAAAICCUkAAAICCYkAAAICCckAAAICCgkAAAICCkkAAAICCokAAAICCskAAAICCwkAAAICC0kAAAICC4kAAAICC8kAAAICDAkAAAICDEkAAAICDIkAAAICDMkAAAICDQkAAAICDUkAAAICDYkAAAICDckAAAICDgkAAAICDkkAAAICDokAAAICDskAAAICDwkAAAICD0kAAAICD4kAAAICD8kAAAICEAkAAAICEEkAAAICEIkAAAICEMkAAAICEQkAAAICEUkAAAICEYkAAAICEckAAAICEgkAAAICEkkAAAICEokAAAICEskAAAICEwkAAAICE0kAAAICE4kAAAICE8kAAAICFAkAAAICFEkAAAICFIkAAAICFMkAAAICFQkAAAICFUkAAAICFYkAAAICFckAAAICFgkAAAICFkkAAAICFokAAAICFskAAAICFwkAAAICF0kAAAICF4kAAAICF8kAAAICGAkAAAICGEkAAAICGIkAAAICGMkAAAICGQkAAAICGUkAAAICGYkAAAICGckAAAICGgkAAAICGkkAAAICGokAAAICGskAAAICGwkAAAICG0kAAAICG4kAAAICG8kAAAICHAkAAAICHEkAAAICHIkAAAICHMkAAAICHQkAAAICHUkAAAICHYkAAAICHckAAAICHgkAAAICHkkAAAICHokAAAICHskAAAICHwkAAAICH0kAAAICH4kAAAICH8kAAAICIAkAAAICIEkAAAICIIkAAAICIMkAAAICIQkAAAICIUkAAAICIYkAAAICIckAAAICIgkAAAICIkkAAAICIokAAAICIskAAAICIwkAAAICI0kAAAICI4kAAAICI8kAAAICJAkAAAICJEkAAAICJIkAAAICJMkAAAICJQkAAAICJUkAAAICJYkAAAICJckAAAICJgkAAAICJkkAAAICJokAAAICJskAAAICJwkAAAICJ0kAAAICJ4kAAAICJ8kAAAICKAkAAAICKEkAAAICKIkAAAICKMkAAAICKQkAAAICKUkAAAICKYkAAAICKckAAAICKgkAAAICKkkAAAICKokAAAICKskAAAICKwkAAAICK0kAAAICK4kAAAICK8kAAAICLAkAAAICLEkAAAICLIkAAAICLMkAAAICLQkAAAICLUkAAAICLYkAAAICLckAAAICLgkAAAICLkkAAAICLokAAAICLskAAAICLwkAAAICL0kAAAICL4kAAAICL8kAAAICMAkAAAICMEkAAAICMIkAAAICMMkAAAICMQkAAAICMUkAAAICMYkAAAICMckAAAICMgkAAAICMkkAAAICMokAAAICMskAAAICMwkAAAICM0kAAAICM4kAAAICM8kAAAICNAkAAAICNEkAAAICNIkAAAICNMkAAAICNQkAAAICNUkAAAICNYkAAAICNckAAAICNgkAAAICNkkAAAICNokAAAICNskAAAICNwkAAAICN0kAAAICN4kAAAICN8kAAAICOAkAAAICOEkAAAICOIkAAAICOMkAAAICOQkAAAICOUkAAAICOYkAAAICOckAAAICOgkAAAICOkkAAAICOokAAAICOskAAAICOwkAAAICO0kAAAICO4kAAAICO8kAAAICPAkAAAICPEkAAAICPIkAAAICPMkAAAICPQkAAAICPUkAAAICPYkAAAICPckAAAICPgkAAAICPkkAAAICPokAAAICPskAAAICPwkAAAICP0kAAAICP4kAAAICP8kAAAICAAlAAAICAElAAAICAIlAAAICAMlAAAICAQlAAAICAUlAAAICAYlAAAICAclAAAICAglAAAICAklAAAICAolAAAICAslAAAICAwlAAAICA0lAAAICA4lAAAICA8lAAAICBAlAAAICBElAAAICBIlAAAICBMlAAAICBQlAAAICBUlAAAICBYlAAAICBclAAAICBglAAAICBklAAAICBolAAAICBslAAAICBwlAAAICB0lAAAICB4lAAAICB8lAAAICCAlAAAICCElAAAICCIlAAAICCMlAAAICCQlAAAICCUlAAAICCYlAAAICCclAAAICCglAAAICCklAAAICColAAAICCslAAAICCwlAAAICC0lAAAICC4lAAAICC8lAAAICDAlAAAICDElAAAICDIlAAAICDMlAAAICDQlAAAICDUlAAAICDYlAAAICDclAAAICDglAAAICDklAAAICDolAAAICDslAAAICDwlAAAICD0lAAAICD4lAAAICD8lAAAICEAlAAAICEElAAAICEIlAAAICEMlAAAICEQlAAAICEUlAAAICEYlAAAICEclAAAICEglAAAICEklAAAICEolAAAICEslAAAICEwlAAAICE0lAAAICE4lAAAICE8lAAAICFAlAAAICFElAAAICFIlAAAICFMlAAAICFQlAAAICFUlAAAICFYlAAAICFclAAAICFglAAAICFklAAAICFolAAAICFslAAAICFwlAAAICF0lAAAICF4lAAAICF8lAAAICGAlAAAICGElAAAICGIlAAAICGMlAAAICGQlAAAICGUlAAAICGYlAAAICGclAAAICGglAAAICGklAAAICGolAAAICGslAAAICGwlAAAICG0lAAAICG4lAAAICG8lAAAICHAlAAAICHElAAAICHIlAAAICHMlAAAICHQlAAAICHUlAAAICHYlAAAICHclAAAICHglAAAICHklAAAICHolAAAICHslAAAICHwlAAAICH0lAAAICH4lAAAICH8lAAAICIAlAAAICIElAAAICIIlAAAICIMlAAAICIQlAAAICIUlAAAICIYlAAAICIclAAAICIglAAAICIklAAAICIolAAAICIslAAAICIwlAAAICI0lAAAICI4lAAAICI8lAAAICJAlAAAICJElAAAICJIlAAAICJMlAAAICJQlAAAICJUlAAAICJYlAAAICJclAAAICJglAAAICJklAAAICJolAAAICJslAAAICJwlAAAICJ0lAAAICJ4lAAAICJ8lAAAICKAlAAAICKElAAAICKIlAAAICKMlAAAICKQlAAAICKUlAAAICKYlAAAICKclAAAICKglAAAICKklAAAICKolAAAICKslAAAICKwlAAAICK0lAAAICK4lAAAICK8lAAAICLAlAAAICLElAAAICLIlAAAICLMlAAAICLQlAAAICLUlAAAICLYlAAAICLclAAAICLglAAAICLklAAAICLolAAAICLslAAAICLwlAAAICL0lAAAICL4lAAAICL8lAAAICMAlAAAICMElAAAICMIlAAAICMMlAAAICMQlAAAICMUlAAAICMYlAAAICMclAAAICMglAAAICMklAAAICMolAAAICMslAAAICMwlAAAICM0lAAAICM4lAAAICM8lAAAICNAlAAAICNElAAAICNIlAAAICNMlAAAICNQlAAAICNUlAAAICNYlAAAICNclAAAICNglAAAICNklAAAICNolAAAICNslAAAICNwlAAAICN0lAAAICN4lAAAICN8lAAAICOAlAAAICOElAAAICOIlAAAICOMlAAAICOQlAAAICOUlAAAICOYlAAAICOclAAAICOglAAAICOklAAAICOolAAAICOslAAAICOwlAAAICO0lAAAICO4lAAAICO8lAAAICPAlAAAICPElAAAICPIlAAAICPMlAAAICPQlAAAICPUlAAAICPYlAAAICPclAAAICPglAAAICPklAAAICPolAAAICPslAAAICPwlAAAICP0lAAAICP4lAAAICP8lAAAICAAmAAAICAEmAAAICAImAAAICAMmAAAICAQmAAAICAUmAAAICAYmAAAICAcmAAAICAgmAAAICAkmAAAICAomAAAICAsmAAAICAwmAAAICA0mAAAICA4mAAAICA8mAAAICBAmAAAICBEmAAAICBImAAAICBMmAAAICBQmAAAICBUmAAAICBYmAAAICBcmAAAICBgmAAAICBkmAAAICBomAAAICBsmAAAICBwmAAAICB0mAAAICB4mAAAICB8mAAAICCAmAAAICCEmAAAICCImAAAICCMmAAAICCQmAAAICCUmAAAICCYmAAAICCcmAAAICCgmAAAICCkmAAAICComAAAICCsmAAAICCwmAAAICC0mAAAICC4mAAAICC8mAAAICDAmAAAICDEmAAAICDImAAAICDMmAAAICDQmAAAICDUmAAAICDYmAAAICDcmAAAICDgmAAAICDkmAAAICDomAAAICDsmAAAICDwmAAAICD0mAAAICD4mAAAICD8mAAAICEAmAAAICEEmAAAICEImAAAICEMmAAAICEQmAAAICEUmAAAICEYmAAAICEcmAAAICEgmAAAICEkmAAAICEomAAAICEsmAAAICEwmAAAICE0mAAAICE4mAAAICE8mAAAICFAmAAAICFEmAAAICFImAAAICFMmAAAICFQmAAAICFUmAAAICFYmAAAICFcmAAAICFgmAAAICFkmAAAICFomAAAICFsmAAAICFwmAAAICF0mAAAICF4mAAAICF8mAAAICGAmAAAICGEmAAAICGImAAAICGMmAAAICGQmAAAICGUmAAAICGYmAAAICGcmAAAICGgmAAAICGkmAAAICGomAAAICGsmAAAICGwmAAAICG0mAAAICG4mAAAICG8mAAAICHAmAAAICHEmAAAICHImAAAICHMmAAAICHQmAAAICHUmAAAICHYmAAAICHcmAAAICHgmAAAICHkmAAAICHomAAAICHsmAAAICHwmAAAICH0mAAAICH4mAAAICH8mAAAICIAmAAAICIEmAAAICIImAAAICIMmAAAICIQmAAAICIUmAAAICIYmAAAICIcmAAAICIgmAAAICIkmAAAICIomAAAICIsmAAAICIwmAAAICI0mAAAICI4mAAAICI8mAAAICJAmAAAICJEmAAAICJImAAAICJMmAAAICJQmAAAICJUmAAAICJYmAAAICJcmAAAICJgmAAAICJkmAAAICJomAAAICJsmAAAICJwmAAAICJ0mAAAICJ4mAAAICJ8mAAAICKAmAAAICKEmAAAICKImAAAICKMmAAAICKQmAAAICKUmAAAICKYmAAAICKcmAAAICKgmAAAICKkmAAAICKomAAAICKsmAAAICKwmAAAICK0mAAAICK4mAAAICK8mAAAICLAmAAAICLEmAAAICLImAAAICLMmAAAICLQmAAAICLUmAAAICLYmAAAICLcmAAAICLgmAAAICLkmAAAICLomAAAICLsmAAAICLwmAAAICL0mAAAICL4mAAAICL8mAAAICMAmAAAICMEmAAAICMImAAAICMMmAAAICMQmAAAICMUmAAAICMYmAAAICMcmAAAICMgmAAAICMkmAAAICMomAAAICMsmAAAICMwmAAAICM0mAAAICM4mAAAICM8mAAAICNAmAAAICNEmAAAICNImAAAICNMmAAAICNQmAAAICNUmAAAICNYmAAAICNcmAAAICNgmAAAICNkmAAAICNomAAAICNsmAAAICNwmAAAICN0mAAAICN4mAAAICN8mAAAICOAmAAAICOEmAAAICOImAAAICOMmAAAICOQmAAAICOUmAAAICOYmAAAICOcmAAAICOgmAAAICOkmAAAICOomAAAICOsmAAAICOwmAAAICO0mAAAICO4mAAAICO8mAAAICPAmAAAICPEmAAAICPImAAAICPMmAAAICPQmAAAICPUmAAAICPYmAAAICPcmAAAICPgmAAAICPkmAAAICPomAAAICPsmAAAICPwmAAAICP0mAAAICP4mAAAICP8mAAAICAAnAAAICAEnAAAICAInAAAICAMnAAAICAQnAAAICAUnAAAICAYnAAAICAcnAAAICAgnAAAICAknAAAICAonAAAICAsnAAAICAwnAAAICA0nAAAICA4nAAAICA8nAAAL", "AAEAAAD/////AQAAAAAAAAAQAQAAABAnAAAICAAAAAAICAEAAAAICAIAAAAICAMAAAAICAQAAAAICAUAAAAICAYAAAAICAcAAAAICAgAAAAICAkAAAAICAoAAAAICAsAAAAICAwAAAAICA0AAAAICA4AAAAICA8AAAAICBAAAAAICBEAAAAICBIAAAAICBMAAAAICBQAAAAICBUAAAAICBYAAAAICBcAAAAICBgAAAAICBkAAAAICBoAAAAICBsAAAAICBwAAAAICB0AAAAICB4AAAAICB8AAAAICCAAAAAICCEAAAAICCIAAAAICCMAAAAICCQAAAAICCUAAAAICCYAAAAICCcAAAAICCgAAAAICCkAAAAICCoAAAAICCsAAAAICCwAAAAICC0AAAAICC4AAAAICC8AAAAICDAAAAAICDEAAAAICDIAAAAICDMAAAAICDQAAAAICDUAAAAICDYAAAAICDcAAAAICDgAAAAICDkAAAAICDoAAAAICDsAAAAICDwAAAAICD0AAAAICD4AAAAICD8AAAAICEAAAAAICEEAAAAICEIAAAAICEMAAAAICEQAAAAICEUAAAAICEYAAAAICEcAAAAICEgAAAAICEkAAAAICEoAAAAICEsAAAAICEwAAAAICE0AAAAICE4AAAAICE8AAAAICFAAAAAICFEAAAAICFIAAAAICFMAAAAICFQAAAAICFUAAAAICFYAAAAICFcAAAAICFgAAAAICFkAAAAICFoAAAAICFsAAAAICFwAAAAICF0AAAAICF4AAAAICF8AAAAICGAAAAAICGEAAAAICGIAAAAICGMAAAAICGQAAAAICGUAAAAICGYAAAAICGcAAAAICGgAAAAICGkAAAAICGoAAAAICGsAAAAICGwAAAAICG0AAAAICG4AAAAICG8AAAAICHAAAAAICHEAAAAICHIAAAAICHMAAAAICHQAAAAICHUAAAAICHYAAAAICHcAAAAICHgAAAAICHkAAAAICHoAAAAICHsAAAAICHwAAAAICH0AAAAICH4AAAAICH8AAAAICIAAAAAICIEAAAAICIIAAAAICIMAAAAICIQAAAAICIUAAAAICIYAAAAICIcAAAAICIgAAAAICIkAAAAICIoAAAAICIsAAAAICIwAAAAICI0AAAAICI4AAAAICI8AAAAICJAAAAAICJEAAAAICJIAAAAICJMAAAAICJQAAAAICJUAAAAICJYAAAAICJcAAAAICJgAAAAICJkAAAAICJoAAAAICJsAAAAICJwAAAAICJ0AAAAICJ4AAAAICJ8AAAAICKAAAAAICKEAAAAICKIAAAAICKMAAAAICKQAAAAICKUAAAAICKYAAAAICKcAAAAICKgAAAAICKkAAAAICKoAAAAICKsAAAAICKwAAAAICK0AAAAICK4AAAAICK8AAAAICLAAAAAICLEAAAAICLIAAAAICLMAAAAICLQAAAAICLUAAAAICLYAAAAICLcAAAAICLgAAAAICLkAAAAICLoAAAAICLsAAAAICLwAAAAICL0AAAAICL4AAAAICL8AAAAICMAAAAAICMEAAAAICMIAAAAICMMAAAAICMQAAAAICMUAAAAICMYAAAAICMcAAAAICMgAAAAICMkAAAAICMoAAAAICMsAAAAICMwAAAAICM0AAAAICM4AAAAICM8AAAAICNAAAAAICNEAAAAICNIAAAAICNMAAAAICNQAAAAICNUAAAAICNYAAAAICNcAAAAICNgAAAAICNkAAAAICNoAAAAICNsAAAAICNwAAAAICN0AAAAICN4AAAAICN8AAAAICOAAAAAICOEAAAAICOIAAAAICOMAAAAICOQAAAAICOUAAAAICOYAAAAICOcAAAAICOgAAAAICOkAAAAICOoAAAAICOsAAAAICOwAAAAICO0AAAAICO4AAAAICO8AAAAICPAAAAAICPEAAAAICPIAAAAICPMAAAAICPQAAAAICPUAAAAICPYAAAAICPcAAAAICPgAAAAICPkAAAAICPoAAAAICPsAAAAICPwAAAAICP0AAAAICP4AAAAICP8AAAAICAABAAAICAEBAAAICAIBAAAICAMBAAAICAQBAAAICAUBAAAICAYBAAAICAcBAAAICAgBAAAICAkBAAAICAoBAAAICAsBAAAICAwBAAAICA0BAAAICA4BAAAICA8BAAAICBABAAAICBEBAAAICBIBAAAICBMBAAAICBQBAAAICBUBAAAICBYBAAAICBcBAAAICBgBAAAICBkBAAAICBoBAAAICBsBAAAICBwBAAAICB0BAAAICB4BAAAICB8BAAAICCABAAAICCEBAAAICCIBAAAICCMBAAAICCQBAAAICCUBAAAICCYBAAAICCcBAAAICCgBAAAICCkBAAAICCoBAAAICCsBAAAICCwBAAAICC0BAAAICC4BAAAICC8BAAAICDABAAAICDEBAAAICDIBAAAICDMBAAAICDQBAAAICDUBAAAICDYBAAAICDcBAAAICDgBAAAICDkBAAAICDoBAAAICDsBAAAICDwBAAAICD0BAAAICD4BAAAICD8BAAAICEABAAAICEEBAAAICEIBAAAICEMBAAAICEQBAAAICEUBAAAICEYBAAAICEcBAAAICEgBAAAICEkBAAAICEoBAAAICEsBAAAICEwBAAAICE0BAAAICE4BAAAICE8BAAAICFABAAAICFEBAAAICFIBAAAICFMBAAAICFQBAAAICFUBAAAICFYBAAAICFcBAAAICFgBAAAICFkBAAAICFoBAAAICFsBAAAICFwBAAAICF0BAAAICF4BAAAICF8BAAAICGABAAAICGEBAAAICGIBAAAICGMBAAAICGQBAAAICGUBAAAICGYBAAAICGcBAAAICGgBAAAICGkBAAAICGoBAAAICGsBAAAICGwBAAAICG0BAAAICG4BAAAICG8BAAAICHABAAAICHEBAAAICHIBAAAICHMBAAAICHQBAAAICHUBAAAICHYBAAAICHcBAAAICHgBAAAICHkBAAAICHoBAAAICHsBAAAICHwBAAAICH0BAAAICH4BAAAICH8BAAAICIABAAAICIEBAAAICIIBAAAICIMBAAAICIQBAAAICIUBAAAICIYBAAAICIcBAAAICIgBAAAICIkBAAAICIoBAAAICIsBAAAICIwBAAAICI0BAAAICI4BAAAICI8BAAAICJABAAAICJEBAAAICJIBAAAICJMBAAAICJQBAAAICJUBAAAICJYBAAAICJcBAAAICJgBAAAICJkBAAAICJoBAAAICJsBAAAICJwBAAAICJ0BAAAICJ4BAAAICJ8BAAAICKABAAAICKEBAAAICKIBAAAICKMBAAAICKQBAAAICKUBAAAICKYBAAAICKcBAAAICKgBAAAICKkBAAAICKoBAAAICKsBAAAICKwBAAAICK0BAAAICK4BAAAICK8BAAAICLABAAAICLEBAAAICLIBAAAICLMBAAAICLQBAAAICLUBAAAICLYBAAAICLcBAAAICLgBAAAICLkBAAAICLoBAAAICLsBAAAICLwBAAAICL0BAAAICL4BAAAICL8BAAAICMABAAAICMEBAAAICMIBAAAICMMBAAAICMQBAAAICMUBAAAICMYBAAAICMcBAAAICMgBAAAICMkBAAAICMoBAAAICMsBAAAICMwBAAAICM0BAAAICM4BAAAICM8BAAAICNABAAAICNEBAAAICNIBAAAICNMBAAAICNQBAAAICNUBAAAICNYBAAAICNcBAAAICNgBAAAICNkBAAAICNoBAAAICNsBAAAICNwBAAAICN0BAAAICN4BAAAICN8BAAAICOABAAAICOEBAAAICOIBAAAICOMBAAAICOQBAAAICOUBAAAICOYBAAAICOcBAAAICOgBAAAICOkBAAAICOoBAAAICOsBAAAICOwBAAAICO0BAAAICO4BAAAICO8BAAAICPABAAAICPEBAAAICPIBAAAICPMBAAAICPQBAAAICPUBAAAICPYBAAAICPcBAAAICPgBAAAICPkBAAAICPoBAAAICPsBAAAICPwBAAAICP0BAAAICP4BAAAICP8BAAAICAACAAAICAECAAAICAICAAAICAMCAAAICAQCAAAICAUCAAAICAYCAAAICAcCAAAICAgCAAAICAkCAAAICAoCAAAICAsCAAAICAwCAAAICA0CAAAICA4CAAAICA8CAAAICBACAAAICBECAAAICBICAAAICBMCAAAICBQCAAAICBUCAAAICBYCAAAICBcCAAAICBgCAAAICBkCAAAICBoCAAAICBsCAAAICBwCAAAICB0CAAAICB4CAAAICB8CAAAICCACAAAICCECAAAICCICAAAICCMCAAAICCQCAAAICCUCAAAICCYCAAAICCcCAAAICCgCAAAICCkCAAAICCoCAAAICCsCAAAICCwCAAAICC0CAAAICC4CAAAICC8CAAAICDACAAAICDECAAAICDICAAAICDMCAAAICDQCAAAICDUCAAAICDYCAAAICDcCAAAICDgCAAAICDkCAAAICDoCAAAICDsCAAAICDwCAAAICD0CAAAICD4CAAAICD8CAAAICEACAAAICEECAAAICEICAAAICEMCAAAICEQCAAAICEUCAAAICEYCAAAICEcCAAAICEgCAAAICEkCAAAICEoCAAAICEsCAAAICEwCAAAICE0CAAAICE4CAAAICE8CAAAICFACAAAICFECAAAICFICAAAICFMCAAAICFQCAAAICFUCAAAICFYCAAAICFcCAAAICFgCAAAICFkCAAAICFoCAAAICFsCAAAICFwCAAAICF0CAAAICF4CAAAICF8CAAAICGACAAAICGECAAAICGICAAAICGMCAAAICGQCAAAICGUCAAAICGYCAAAICGcCAAAICGgCAAAICGkCAAAICGoCAAAICGsCAAAICGwCAAAICG0CAAAICG4CAAAICG8CAAAICHACAAAICHECAAAICHICAAAICHMCAAAICHQCAAAICHUCAAAICHYCAAAICHcCAAAICHgCAAAICHkCAAAICHoCAAAICHsCAAAICHwCAAAICH0CAAAICH4CAAAICH8CAAAICIACAAAICIECAAAICIICAAAICIMCAAAICIQCAAAICIUCAAAICIYCAAAICIcCAAAICIgCAAAICIkCAAAICIoCAAAICIsCAAAICIwCAAAICI0CAAAICI4CAAAICI8CAAAICJACAAAICJECAAAICJICAAAICJMCAAAICJQCAAAICJUCAAAICJYCAAAICJcCAAAICJgCAAAICJkCAAAICJoCAAAICJsCAAAICJwCAAAICJ0CAAAICJ4CAAAICJ8CAAAICKACAAAICKECAAAICKICAAAICKMCAAAICKQCAAAICKUCAAAICKYCAAAICKcCAAAICKgCAAAICKkCAAAICKoCAAAICKsCAAAICKwCAAAICK0CAAAICK4CAAAICK8CAAAICLACAAAICLECAAAICLICAAAICLMCAAAICLQCAAAICLUCAAAICLYCAAAICLcCAAAICLgCAAAICLkCAAAICLoCAAAICLsCAAAICLwCAAAICL0CAAAICL4CAAAICL8CAAAICMACAAAICMECAAAICMICAAAICMMCAAAICMQCAAAICMUCAAAICMYCAAAICMcCAAAICMgCAAAICMkCAAAICMoCAAAICMsCAAAICMwCAAAICM0CAAAICM4CAAAICM8CAAAICNACAAAICNECAAAICNICAAAICNMCAAAICNQCAAAICNUCAAAICNYCAAAICNcCAAAICNgCAAAICNkCAAAICNoCAAAICNsCAAAICNwCAAAICN0CAAAICN4CAAAICN8CAAAICOACAAAICOECAAAICOICAAAICOMCAAAICOQCAAAICOUCAAAICOYCAAAICOcCAAAICOgCAAAICOkCAAAICOoCAAAICOsCAAAICOwCAAAICO0CAAAICO4CAAAICO8CAAAICPACAAAICPECAAAICPICAAAICPMCAAAICPQCAAAICPUCAAAICPYCAAAICPcCAAAICPgCAAAICPkCAAAICPoCAAAICPsCAAAICPwCAAAICP0CAAAICP4CAAAICP8CAAAICAADAAAICAEDAAAICAIDAAAICAMDAAAICAQDAAAICAUDAAAICAYDAAAICAcDAAAICAgDAAAICAkDAAAICAoDAAAICAsDAAAICAwDAAAICA0DAAAICA4DAAAICA8DAAAICBADAAAICBEDAAAICBIDAAAICBMDAAAICBQDAAAICBUDAAAICBYDAAAICBcDAAAICBgDAAAICBkDAAAICBoDAAAICBsDAAAICBwDAAAICB0DAAAICB4DAAAICB8DAAAICCADAAAICCEDAAAICCIDAAAICCMDAAAICCQDAAAICCUDAAAICCYDAAAICCcDAAAICCgDAAAICCkDAAAICCoDAAAICCsDAAAICCwDAAAICC0DAAAICC4DAAAICC8DAAAICDADAAAICDEDAAAICDIDAAAICDMDAAAICDQDAAAICDUDAAAICDYDAAAICDcDAAAICDgDAAAICDkDAAAICDoDAAAICDsDAAAICDwDAAAICD0DAAAICD4DAAAICD8DAAAICEADAAAICEEDAAAICEIDAAAICEMDAAAICEQDAAAICEUDAAAICEYDAAAICEcDAAAICEgDAAAICEkDAAAICEoDAAAICEsDAAAICEwDAAAICE0DAAAICE4DAAAICE8DAAAICFADAAAICFEDAAAICFIDAAAICFMDAAAICFQDAAAICFUDAAAICFYDAAAICFcDAAAICFgDAAAICFkDAAAICFoDAAAICFsDAAAICFwDAAAICF0DAAAICF4DAAAICF8DAAAICGADAAAICGEDAAAICGIDAAAICGMDAAAICGQDAAAICGUDAAAICGYDAAAICGcDAAAICGgDAAAICGkDAAAICGoDAAAICGsDAAAICGwDAAAICG0DAAAICG4DAAAICG8DAAAICHADAAAICHEDAAAICHIDAAAICHMDAAAICHQDAAAICHUDAAAICHYDAAAICHcDAAAICHgDAAAICHkDAAAICHoDAAAICHsDAAAICHwDAAAICH0DAAAICH4DAAAICH8DAAAICIADAAAICIEDAAAICIIDAAAICIMDAAAICIQDAAAICIUDAAAICIYDAAAICIcDAAAICIgDAAAICIkDAAAICIoDAAAICIsDAAAICIwDAAAICI0DAAAICI4DAAAICI8DAAAICJADAAAICJEDAAAICJIDAAAICJMDAAAICJQDAAAICJUDAAAICJYDAAAICJcDAAAICJgDAAAICJkDAAAICJoDAAAICJsDAAAICJwDAAAICJ0DAAAICJ4DAAAICJ8DAAAICKADAAAICKEDAAAICKIDAAAICKMDAAAICKQDAAAICKUDAAAICKYDAAAICKcDAAAICKgDAAAICKkDAAAICKoDAAAICKsDAAAICKwDAAAICK0DAAAICK4DAAAICK8DAAAICLADAAAICLEDAAAICLIDAAAICLMDAAAICLQDAAAICLUDAAAICLYDAAAICLcDAAAICLgDAAAICLkDAAAICLoDAAAICLsDAAAICLwDAAAICL0DAAAICL4DAAAICL8DAAAICMADAAAICMEDAAAICMIDAAAICMMDAAAICMQDAAAICMUDAAAICMYDAAAICMcDAAAICMgDAAAICMkDAAAICMoDAAAICMsDAAAICMwDAAAICM0DAAAICM4DAAAICM8DAAAICNADAAAICNEDAAAICNIDAAAICNMDAAAICNQDAAAICNUDAAAICNYDAAAICNcDAAAICNgDAAAICNkDAAAICNoDAAAICNsDAAAICNwDAAAICN0DAAAICN4DAAAICN8DAAAICOADAAAICOEDAAAICOIDAAAICOMDAAAICOQDAAAICOUDAAAICOYDAAAICOcDAAAICOgDAAAICOkDAAAICOoDAAAICOsDAAAICOwDAAAICO0DAAAICO4DAAAICO8DAAAICPADAAAICPEDAAAICPIDAAAICPMDAAAICPQDAAAICPUDAAAICPYDAAAICPcDAAAICPgDAAAICPkDAAAICPoDAAAICPsDAAAICPwDAAAICP0DAAAICP4DAAAICP8DAAAICAAEAAAICAEEAAAICAIEAAAICAMEAAAICAQEAAAICAUEAAAICAYEAAAICAcEAAAICAgEAAAICAkEAAAICAoEAAAICAsEAAAICAwEAAAICA0EAAAICA4EAAAICA8EAAAICBAEAAAICBEEAAAICBIEAAAICBMEAAAICBQEAAAICBUEAAAICBYEAAAICBcEAAAICBgEAAAICBkEAAAICBoEAAAICBsEAAAICBwEAAAICB0EAAAICB4EAAAICB8EAAAICCAEAAAICCEEAAAICCIEAAAICCMEAAAICCQEAAAICCUEAAAICCYEAAAICCcEAAAICCgEAAAICCkEAAAICCoEAAAICCsEAAAICCwEAAAICC0EAAAICC4EAAAICC8EAAAICDAEAAAICDEEAAAICDIEAAAICDMEAAAICDQEAAAICDUEAAAICDYEAAAICDcEAAAICDgEAAAICDkEAAAICDoEAAAICDsEAAAICDwEAAAICD0EAAAICD4EAAAICD8EAAAICEAEAAAICEEEAAAICEIEAAAICEMEAAAICEQEAAAICEUEAAAICEYEAAAICEcEAAAICEgEAAAICEkEAAAICEoEAAAICEsEAAAICEwEAAAICE0EAAAICE4EAAAICE8EAAAICFAEAAAICFEEAAAICFIEAAAICFMEAAAICFQEAAAICFUEAAAICFYEAAAICFcEAAAICFgEAAAICFkEAAAICFoEAAAICFsEAAAICFwEAAAICF0EAAAICF4EAAAICF8EAAAICGAEAAAICGEEAAAICGIEAAAICGMEAAAICGQEAAAICGUEAAAICGYEAAAICGcEAAAICGgEAAAICGkEAAAICGoEAAAICGsEAAAICGwEAAAICG0EAAAICG4EAAAICG8EAAAICHAEAAAICHEEAAAICHIEAAAICHMEAAAICHQEAAAICHUEAAAICHYEAAAICHcEAAAICHgEAAAICHkEAAAICHoEAAAICHsEAAAICHwEAAAICH0EAAAICH4EAAAICH8EAAAICIAEAAAICIEEAAAICIIEAAAICIMEAAAICIQEAAAICIUEAAAICIYEAAAICIcEAAAICIgEAAAICIkEAAAICIoEAAAICIsEAAAICIwEAAAICI0EAAAICI4EAAAICI8EAAAICJAEAAAICJEEAAAICJIEAAAICJMEAAAICJQEAAAICJUEAAAICJYEAAAICJcEAAAICJgEAAAICJkEAAAICJoEAAAICJsEAAAICJwEAAAICJ0EAAAICJ4EAAAICJ8EAAAICKAEAAAICKEEAAAICKIEAAAICKMEAAAICKQEAAAICKUEAAAICKYEAAAICKcEAAAICKgEAAAICKkEAAAICKoEAAAICKsEAAAICKwEAAAICK0EAAAICK4EAAAICK8EAAAICLAEAAAICLEEAAAICLIEAAAICLMEAAAICLQEAAAICLUEAAAICLYEAAAICLcEAAAICLgEAAAICLkEAAAICLoEAAAICLsEAAAICLwEAAAICL0EAAAICL4EAAAICL8EAAAICMAEAAAICMEEAAAICMIEAAAICMMEAAAICMQEAAAICMUEAAAICMYEAAAICMcEAAAICMgEAAAICMkEAAAICMoEAAAICMsEAAAICMwEAAAICM0EAAAICM4EAAAICM8EAAAICNAEAAAICNEEAAAICNIEAAAICNMEAAAICNQEAAAICNUEAAAICNYEAAAICNcEAAAICNgEAAAICNkEAAAICNoEAAAICNsEAAAICNwEAAAICN0EAAAICN4EAAAICN8EAAAICOAEAAAICOEEAAAICOIEAAAICOMEAAAICOQEAAAICOUEAAAICOYEAAAICOcEAAAICOgEAAAICOkEAAAICOoEAAAICOsEAAAICOwEAAAICO0EAAAICO4EAAAICO8EAAAICPAEAAAICPEEAAAICPIEAAAICPMEAAAICPQEAAAICPUEAAAICPYEAAAICPcEAAAICPgEAAAICPkEAAAICPoEAAAICPsEAAAICPwEAAAICP0EAAAICP4EAAAICP8EAAAICAAFAAAICAEFAAAICAIFAAAICAMFAAAICAQFAAAICAUFAAAICAYFAAAICAcFAAAICAgFAAAICAkFAAAICAoFAAAICAsFAAAICAwFAAAICA0FAAAICA4FAAAICA8FAAAICBAFAAAICBEFAAAICBIFAAAICBMFAAAICBQFAAAICBUFAAAICBYFAAAICBcFAAAICBgFAAAICBkFAAAICBoFAAAICBsFAAAICBwFAAAICB0FAAAICB4FAAAICB8FAAAICCAFAAAICCEFAAAICCIFAAAICCMFAAAICCQFAAAICCUFAAAICCYFAAAICCcFAAAICCgFAAAICCkFAAAICCoFAAAICCsFAAAICCwFAAAICC0FAAAICC4FAAAICC8FAAAICDAFAAAICDEFAAAICDIFAAAICDMFAAAICDQFAAAICDUFAAAICDYFAAAICDcFAAAICDgFAAAICDkFAAAICDoFAAAICDsFAAAICDwFAAAICD0FAAAICD4FAAAICD8FAAAICEAFAAAICEEFAAAICEIFAAAICEMFAAAICEQFAAAICEUFAAAICEYFAAAICEcFAAAICEgFAAAICEkFAAAICEoFAAAICEsFAAAICEwFAAAICE0FAAAICE4FAAAICE8FAAAICFAFAAAICFEFAAAICFIFAAAICFMFAAAICFQFAAAICFUFAAAICFYFAAAICFcFAAAICFgFAAAICFkFAAAICFoFAAAICFsFAAAICFwFAAAICF0FAAAICF4FAAAICF8FAAAICGAFAAAICGEFAAAICGIFAAAICGMFAAAICGQFAAAICGUFAAAICGYFAAAICGcFAAAICGgFAAAICGkFAAAICGoFAAAICGsFAAAICGwFAAAICG0FAAAICG4FAAAICG8FAAAICHAFAAAICHEFAAAICHIFAAAICHMFAAAICHQFAAAICHUFAAAICHYFAAAICHcFAAAICHgFAAAICHkFAAAICHoFAAAICHsFAAAICHwFAAAICH0FAAAICH4FAAAICH8FAAAICIAFAAAICIEFAAAICIIFAAAICIMFAAAICIQFAAAICIUFAAAICIYFAAAICIcFAAAICIgFAAAICIkFAAAICIoFAAAICIsFAAAICIwFAAAICI0FAAAICI4FAAAICI8FAAAICJAFAAAICJEFAAAICJIFAAAICJMFAAAICJQFAAAICJUFAAAICJYFAAAICJcFAAAICJgFAAAICJkFAAAICJoFAAAICJsFAAAICJwFAAAICJ0FAAAICJ4FAAAICJ8FAAAICKAFAAAICKEFAAAICKIFAAAICKMFAAAICKQFAAAICKUFAAAICKYFAAAICKcFAAAICKgFAAAICKkFAAAICKoFAAAICKsFAAAICKwFAAAICK0FAAAICK4FAAAICK8FAAAICLAFAAAICLEFAAAICLIFAAAICLMFAAAICLQFAAAICLUFAAAICLYFAAAICLcFAAAICLgFAAAICLkFAAAICLoFAAAICLsFAAAICLwFAAAICL0FAAAICL4FAAAICL8FAAAICMAFAAAICMEFAAAICMIFAAAICMMFAAAICMQFAAAICMUFAAAICMYFAAAICMcFAAAICMgFAAAICMkFAAAICMoFAAAICMsFAAAICMwFAAAICM0FAAAICM4FAAAICM8FAAAICNAFAAAICNEFAAAICNIFAAAICNMFAAAICNQFAAAICNUFAAAICNYFAAAICNcFAAAICNgFAAAICNkFAAAICNoFAAAICNsFAAAICNwFAAAICN0FAAAICN4FAAAICN8FAAAICOAFAAAICOEFAAAICOIFAAAICOMFAAAICOQFAAAICOUFAAAICOYFAAAICOcFAAAICOgFAAAICOkFAAAICOoFAAAICOsFAAAICOwFAAAICO0FAAAICO4FAAAICO8FAAAICPAFAAAICPEFAAAICPIFAAAICPMFAAAICPQFAAAICPUFAAAICPYFAAAICPcFAAAICPgFAAAICPkFAAAICPoFAAAICPsFAAAICPwFAAAICP0FAAAICP4FAAAICP8FAAAICAAGAAAICAEGAAAICAIGAAAICAMGAAAICAQGAAAICAUGAAAICAYGAAAICAcGAAAICAgGAAAICAkGAAAICAoGAAAICAsGAAAICAwGAAAICA0GAAAICA4GAAAICA8GAAAICBAGAAAICBEGAAAICBIGAAAICBMGAAAICBQGAAAICBUGAAAICBYGAAAICBcGAAAICBgGAAAICBkGAAAICBoGAAAICBsGAAAICBwGAAAICB0GAAAICB4GAAAICB8GAAAICCAGAAAICCEGAAAICCIGAAAICCMGAAAICCQGAAAICCUGAAAICCYGAAAICCcGAAAICCgGAAAICCkGAAAICCoGAAAICCsGAAAICCwGAAAICC0GAAAICC4GAAAICC8GAAAICDAGAAAICDEGAAAICDIGAAAICDMGAAAICDQGAAAICDUGAAAICDYGAAAICDcGAAAICDgGAAAICDkGAAAICDoGAAAICDsGAAAICDwGAAAICD0GAAAICD4GAAAICD8GAAAICEAGAAAICEEGAAAICEIGAAAICEMGAAAICEQGAAAICEUGAAAICEYGAAAICEcGAAAICEgGAAAICEkGAAAICEoGAAAICEsGAAAICEwGAAAICE0GAAAICE4GAAAICE8GAAAICFAGAAAICFEGAAAICFIGAAAICFMGAAAICFQGAAAICFUGAAAICFYGAAAICFcGAAAICFgGAAAICFkGAAAICFoGAAAICFsGAAAICFwGAAAICF0GAAAICF4GAAAICF8GAAAICGAGAAAICGEGAAAICGIGAAAICGMGAAAICGQGAAAICGUGAAAICGYGAAAICGcGAAAICGgGAAAICGkGAAAICGoGAAAICGsGAAAICGwGAAAICG0GAAAICG4GAAAICG8GAAAICHAGAAAICHEGAAAICHIGAAAICHMGAAAICHQGAAAICHUGAAAICHYGAAAICHcGAAAICHgGAAAICHkGAAAICHoGAAAICHsGAAAICHwGAAAICH0GAAAICH4GAAAICH8GAAAICIAGAAAICIEGAAAICIIGAAAICIMGAAAICIQGAAAICIUGAAAICIYGAAAICIcGAAAICIgGAAAICIkGAAAICIoGAAAICIsGAAAICIwGAAAICI0GAAAICI4GAAAICI8GAAAICJAGAAAICJEGAAAICJIGAAAICJMGAAAICJQGAAAICJUGAAAICJYGAAAICJcGAAAICJgGAAAICJkGAAAICJoGAAAICJsGAAAICJwGAAAICJ0GAAAICJ4GAAAICJ8GAAAICKAGAAAICKEGAAAICKIGAAAICKMGAAAICKQGAAAICKUGAAAICKYGAAAICKcGAAAICKgGAAAICKkGAAAICKoGAAAICKsGAAAICKwGAAAICK0GAAAICK4GAAAICK8GAAAICLAGAAAICLEGAAAICLIGAAAICLMGAAAICLQGAAAICLUGAAAICLYGAAAICLcGAAAICLgGAAAICLkGAAAICLoGAAAICLsGAAAICLwGAAAICL0GAAAICL4GAAAICL8GAAAICMAGAAAICMEGAAAICMIGAAAICMMGAAAICMQGAAAICMUGAAAICMYGAAAICMcGAAAICMgGAAAICMkGAAAICMoGAAAICMsGAAAICMwGAAAICM0GAAAICM4GAAAICM8GAAAICNAGAAAICNEGAAAICNIGAAAICNMGAAAICNQGAAAICNUGAAAICNYGAAAICNcGAAAICNgGAAAICNkGAAAICNoGAAAICNsGAAAICNwGAAAICN0GAAAICN4GAAAICN8GAAAICOAGAAAICOEGAAAICOIGAAAICOMGAAAICOQGAAAICOUGAAAICOYGAAAICOcGAAAICOgGAAAICOkGAAAICOoGAAAICOsGAAAICOwGAAAICO0GAAAICO4GAAAICO8GAAAICPAGAAAICPEGAAAICPIGAAAICPMGAAAICPQGAAAICPUGAAAICPYGAAAICPcGAAAICPgGAAAICPkGAAAICPoGAAAICPsGAAAICPwGAAAICP0GAAAICP4GAAAICP8GAAAICAAHAAAICAEHAAAICAIHAAAICAMHAAAICAQHAAAICAUHAAAICAYHAAAICAcHAAAICAgHAAAICAkHAAAICAoHAAAICAsHAAAICAwHAAAICA0HAAAICA4HAAAICA8HAAAICBAHAAAICBEHAAAICBIHAAAICBMHAAAICBQHAAAICBUHAAAICBYHAAAICBcHAAAICBgHAAAICBkHAAAICBoHAAAICBsHAAAICBwHAAAICB0HAAAICB4HAAAICB8HAAAICCAHAAAICCEHAAAICCIHAAAICCMHAAAICCQHAAAICCUHAAAICCYHAAAICCcHAAAICCgHAAAICCkHAAAICCoHAAAICCsHAAAICCwHAAAICC0HAAAICC4HAAAICC8HAAAICDAHAAAICDEHAAAICDIHAAAICDMHAAAICDQHAAAICDUHAAAICDYHAAAICDcHAAAICDgHAAAICDkHAAAICDoHAAAICDsHAAAICDwHAAAICD0HAAAICD4HAAAICD8HAAAICEAHAAAICEEHAAAICEIHAAAICEMHAAAICEQHAAAICEUHAAAICEYHAAAICEcHAAAICEgHAAAICEkHAAAICEoHAAAICEsHAAAICEwHAAAICE0HAAAICE4HAAAICE8HAAAICFAHAAAICFEHAAAICFIHAAAICFMHAAAICFQHAAAICFUHAAAICFYHAAAICFcHAAAICFgHAAAICFkHAAAICFoHAAAICFsHAAAICFwHAAAICF0HAAAICF4HAAAICF8HAAAICGAHAAAICGEHAAAICGIHAAAICGMHAAAICGQHAAAICGUHAAAICGYHAAAICGcHAAAICGgHAAAICGkHAAAICGoHAAAICGsHAAAICGwHAAAICG0HAAAICG4HAAAICG8HAAAICHAHAAAICHEHAAAICHIHAAAICHMHAAAICHQHAAAICHUHAAAICHYHAAAICHcHAAAICHgHAAAICHkHAAAICHoHAAAICHsHAAAICHwHAAAICH0HAAAICH4HAAAICH8HAAAICIAHAAAICIEHAAAICIIHAAAICIMHAAAICIQHAAAICIUHAAAICIYHAAAICIcHAAAICIgHAAAICIkHAAAICIoHAAAICIsHAAAICIwHAAAICI0HAAAICI4HAAAICI8HAAAICJAHAAAICJEHAAAICJIHAAAICJMHAAAICJQHAAAICJUHAAAICJYHAAAICJcHAAAICJgHAAAICJkHAAAICJoHAAAICJsHAAAICJwHAAAICJ0HAAAICJ4HAAAICJ8HAAAICKAHAAAICKEHAAAICKIHAAAICKMHAAAICKQHAAAICKUHAAAICKYHAAAICKcHAAAICKgHAAAICKkHAAAICKoHAAAICKsHAAAICKwHAAAICK0HAAAICK4HAAAICK8HAAAICLAHAAAICLEHAAAICLIHAAAICLMHAAAICLQHAAAICLUHAAAICLYHAAAICLcHAAAICLgHAAAICLkHAAAICLoHAAAICLsHAAAICLwHAAAICL0HAAAICL4HAAAICL8HAAAICMAHAAAICMEHAAAICMIHAAAICMMHAAAICMQHAAAICMUHAAAICMYHAAAICMcHAAAICMgHAAAICMkHAAAICMoHAAAICMsHAAAICMwHAAAICM0HAAAICM4HAAAICM8HAAAICNAHAAAICNEHAAAICNIHAAAICNMHAAAICNQHAAAICNUHAAAICNYHAAAICNcHAAAICNgHAAAICNkHAAAICNoHAAAICNsHAAAICNwHAAAICN0HAAAICN4HAAAICN8HAAAICOAHAAAICOEHAAAICOIHAAAICOMHAAAICOQHAAAICOUHAAAICOYHAAAICOcHAAAICOgHAAAICOkHAAAICOoHAAAICOsHAAAICOwHAAAICO0HAAAICO4HAAAICO8HAAAICPAHAAAICPEHAAAICPIHAAAICPMHAAAICPQHAAAICPUHAAAICPYHAAAICPcHAAAICPgHAAAICPkHAAAICPoHAAAICPsHAAAICPwHAAAICP0HAAAICP4HAAAICP8HAAAICAAIAAAICAEIAAAICAIIAAAICAMIAAAICAQIAAAICAUIAAAICAYIAAAICAcIAAAICAgIAAAICAkIAAAICAoIAAAICAsIAAAICAwIAAAICA0IAAAICA4IAAAICA8IAAAICBAIAAAICBEIAAAICBIIAAAICBMIAAAICBQIAAAICBUIAAAICBYIAAAICBcIAAAICBgIAAAICBkIAAAICBoIAAAICBsIAAAICBwIAAAICB0IAAAICB4IAAAICB8IAAAICCAIAAAICCEIAAAICCIIAAAICCMIAAAICCQIAAAICCUIAAAICCYIAAAICCcIAAAICCgIAAAICCkIAAAICCoIAAAICCsIAAAICCwIAAAICC0IAAAICC4IAAAICC8IAAAICDAIAAAICDEIAAAICDIIAAAICDMIAAAICDQIAAAICDUIAAAICDYIAAAICDcIAAAICDgIAAAICDkIAAAICDoIAAAICDsIAAAICDwIAAAICD0IAAAICD4IAAAICD8IAAAICEAIAAAICEEIAAAICEIIAAAICEMIAAAICEQIAAAICEUIAAAICEYIAAAICEcIAAAICEgIAAAICEkIAAAICEoIAAAICEsIAAAICEwIAAAICE0IAAAICE4IAAAICE8IAAAICFAIAAAICFEIAAAICFIIAAAICFMIAAAICFQIAAAICFUIAAAICFYIAAAICFcIAAAICFgIAAAICFkIAAAICFoIAAAICFsIAAAICFwIAAAICF0IAAAICF4IAAAICF8IAAAICGAIAAAICGEIAAAICGIIAAAICGMIAAAICGQIAAAICGUIAAAICGYIAAAICGcIAAAICGgIAAAICGkIAAAICGoIAAAICGsIAAAICGwIAAAICG0IAAAICG4IAAAICG8IAAAICHAIAAAICHEIAAAICHIIAAAICHMIAAAICHQIAAAICHUIAAAICHYIAAAICHcIAAAICHgIAAAICHkIAAAICHoIAAAICHsIAAAICHwIAAAICH0IAAAICH4IAAAICH8IAAAICIAIAAAICIEIAAAICIIIAAAICIMIAAAICIQIAAAICIUIAAAICIYIAAAICIcIAAAICIgIAAAICIkIAAAICIoIAAAICIsIAAAICIwIAAAICI0IAAAICI4IAAAICI8IAAAICJAIAAAICJEIAAAICJIIAAAICJMIAAAICJQIAAAICJUIAAAICJYIAAAICJcIAAAICJgIAAAICJkIAAAICJoIAAAICJsIAAAICJwIAAAICJ0IAAAICJ4IAAAICJ8IAAAICKAIAAAICKEIAAAICKIIAAAICKMIAAAICKQIAAAICKUIAAAICKYIAAAICKcIAAAICKgIAAAICKkIAAAICKoIAAAICKsIAAAICKwIAAAICK0IAAAICK4IAAAICK8IAAAICLAIAAAICLEIAAAICLIIAAAICLMIAAAICLQIAAAICLUIAAAICLYIAAAICLcIAAAICLgIAAAICLkIAAAICLoIAAAICLsIAAAICLwIAAAICL0IAAAICL4IAAAICL8IAAAICMAIAAAICMEIAAAICMIIAAAICMMIAAAICMQIAAAICMUIAAAICMYIAAAICMcIAAAICMgIAAAICMkIAAAICMoIAAAICMsIAAAICMwIAAAICM0IAAAICM4IAAAICM8IAAAICNAIAAAICNEIAAAICNIIAAAICNMIAAAICNQIAAAICNUIAAAICNYIAAAICNcIAAAICNgIAAAICNkIAAAICNoIAAAICNsIAAAICNwIAAAICN0IAAAICN4IAAAICN8IAAAICOAIAAAICOEIAAAICOIIAAAICOMIAAAICOQIAAAICOUIAAAICOYIAAAICOcIAAAICOgIAAAICOkIAAAICOoIAAAICOsIAAAICOwIAAAICO0IAAAICO4IAAAICO8IAAAICPAIAAAICPEIAAAICPIIAAAICPMIAAAICPQIAAAICPUIAAAICPYIAAAICPcIAAAICPgIAAAICPkIAAAICPoIAAAICPsIAAAICPwIAAAICP0IAAAICP4IAAAICP8IAAAICAAJAAAICAEJAAAICAIJAAAICAMJAAAICAQJAAAICAUJAAAICAYJAAAICAcJAAAICAgJAAAICAkJAAAICAoJAAAICAsJAAAICAwJAAAICA0JAAAICA4JAAAICA8JAAAICBAJAAAICBEJAAAICBIJAAAICBMJAAAICBQJAAAICBUJAAAICBYJAAAICBcJAAAICBgJAAAICBkJAAAICBoJAAAICBsJAAAICBwJAAAICB0JAAAICB4JAAAICB8JAAAICCAJAAAICCEJAAAICCIJAAAICCMJAAAICCQJAAAICCUJAAAICCYJAAAICCcJAAAICCgJAAAICCkJAAAICCoJAAAICCsJAAAICCwJAAAICC0JAAAICC4JAAAICC8JAAAICDAJAAAICDEJAAAICDIJAAAICDMJAAAICDQJAAAICDUJAAAICDYJAAAICDcJAAAICDgJAAAICDkJAAAICDoJAAAICDsJAAAICDwJAAAICD0JAAAICD4JAAAICD8JAAAICEAJAAAICEEJAAAICEIJAAAICEMJAAAICEQJAAAICEUJAAAICEYJAAAICEcJAAAICEgJAAAICEkJAAAICEoJAAAICEsJAAAICEwJAAAICE0JAAAICE4JAAAICE8JAAAICFAJAAAICFEJAAAICFIJAAAICFMJAAAICFQJAAAICFUJAAAICFYJAAAICFcJAAAICFgJAAAICFkJAAAICFoJAAAICFsJAAAICFwJAAAICF0JAAAICF4JAAAICF8JAAAICGAJAAAICGEJAAAICGIJAAAICGMJAAAICGQJAAAICGUJAAAICGYJAAAICGcJAAAICGgJAAAICGkJAAAICGoJAAAICGsJAAAICGwJAAAICG0JAAAICG4JAAAICG8JAAAICHAJAAAICHEJAAAICHIJAAAICHMJAAAICHQJAAAICHUJAAAICHYJAAAICHcJAAAICHgJAAAICHkJAAAICHoJAAAICHsJAAAICHwJAAAICH0JAAAICH4JAAAICH8JAAAICIAJAAAICIEJAAAICIIJAAAICIMJAAAICIQJAAAICIUJAAAICIYJAAAICIcJAAAICIgJAAAICIkJAAAICIoJAAAICIsJAAAICIwJAAAICI0JAAAICI4JAAAICI8JAAAICJAJAAAICJEJAAAICJIJAAAICJMJAAAICJQJAAAICJUJAAAICJYJAAAICJcJAAAICJgJAAAICJkJAAAICJoJAAAICJsJAAAICJwJAAAICJ0JAAAICJ4JAAAICJ8JAAAICKAJAAAICKEJAAAICKIJAAAICKMJAAAICKQJAAAICKUJAAAICKYJAAAICKcJAAAICKgJAAAICKkJAAAICKoJAAAICKsJAAAICKwJAAAICK0JAAAICK4JAAAICK8JAAAICLAJAAAICLEJAAAICLIJAAAICLMJAAAICLQJAAAICLUJAAAICLYJAAAICLcJAAAICLgJAAAICLkJAAAICLoJAAAICLsJAAAICLwJAAAICL0JAAAICL4JAAAICL8JAAAICMAJAAAICMEJAAAICMIJAAAICMMJAAAICMQJAAAICMUJAAAICMYJAAAICMcJAAAICMgJAAAICMkJAAAICMoJAAAICMsJAAAICMwJAAAICM0JAAAICM4JAAAICM8JAAAICNAJAAAICNEJAAAICNIJAAAICNMJAAAICNQJAAAICNUJAAAICNYJAAAICNcJAAAICNgJAAAICNkJAAAICNoJAAAICNsJAAAICNwJAAAICN0JAAAICN4JAAAICN8JAAAICOAJAAAICOEJAAAICOIJAAAICOMJAAAICOQJAAAICOUJAAAICOYJAAAICOcJAAAICOgJAAAICOkJAAAICOoJAAAICOsJAAAICOwJAAAICO0JAAAICO4JAAAICO8JAAAICPAJAAAICPEJAAAICPIJAAAICPMJAAAICPQJAAAICPUJAAAICPYJAAAICPcJAAAICPgJAAAICPkJAAAICPoJAAAICPsJAAAICPwJAAAICP0JAAAICP4JAAAICP8JAAAICAAKAAAICAEKAAAICAIKAAAICAMKAAAICAQKAAAICAUKAAAICAYKAAAICAcKAAAICAgKAAAICAkKAAAICAoKAAAICAsKAAAICAwKAAAICA0KAAAICA4KAAAICA8KAAAICBAKAAAICBEKAAAICBIKAAAICBMKAAAICBQKAAAICBUKAAAICBYKAAAICBcKAAAICBgKAAAICBkKAAAICBoKAAAICBsKAAAICBwKAAAICB0KAAAICB4KAAAICB8KAAAICCAKAAAICCEKAAAICCIKAAAICCMKAAAICCQKAAAICCUKAAAICCYKAAAICCcKAAAICCgKAAAICCkKAAAICCoKAAAICCsKAAAICCwKAAAICC0KAAAICC4KAAAICC8KAAAICDAKAAAICDEKAAAICDIKAAAICDMKAAAICDQKAAAICDUKAAAICDYKAAAICDcKAAAICDgKAAAICDkKAAAICDoKAAAICDsKAAAICDwKAAAICD0KAAAICD4KAAAICD8KAAAICEAKAAAICEEKAAAICEIKAAAICEMKAAAICEQKAAAICEUKAAAICEYKAAAICEcKAAAICEgKAAAICEkKAAAICEoKAAAICEsKAAAICEwKAAAICE0KAAAICE4KAAAICE8KAAAICFAKAAAICFEKAAAICFIKAAAICFMKAAAICFQKAAAICFUKAAAICFYKAAAICFcKAAAICFgKAAAICFkKAAAICFoKAAAICFsKAAAICFwKAAAICF0KAAAICF4KAAAICF8KAAAICGAKAAAICGEKAAAICGIKAAAICGMKAAAICGQKAAAICGUKAAAICGYKAAAICGcKAAAICGgKAAAICGkKAAAICGoKAAAICGsKAAAICGwKAAAICG0KAAAICG4KAAAICG8KAAAICHAKAAAICHEKAAAICHIKAAAICHMKAAAICHQKAAAICHUKAAAICHYKAAAICHcKAAAICHgKAAAICHkKAAAICHoKAAAICHsKAAAICHwKAAAICH0KAAAICH4KAAAICH8KAAAICIAKAAAICIEKAAAICIIKAAAICIMKAAAICIQKAAAICIUKAAAICIYKAAAICIcKAAAICIgKAAAICIkKAAAICIoKAAAICIsKAAAICIwKAAAICI0KAAAICI4KAAAICI8KAAAICJAKAAAICJEKAAAICJIKAAAICJMKAAAICJQKAAAICJUKAAAICJYKAAAICJcKAAAICJgKAAAICJkKAAAICJoKAAAICJsKAAAICJwKAAAICJ0KAAAICJ4KAAAICJ8KAAAICKAKAAAICKEKAAAICKIKAAAICKMKAAAICKQKAAAICKUKAAAICKYKAAAICKcKAAAICKgKAAAICKkKAAAICKoKAAAICKsKAAAICKwKAAAICK0KAAAICK4KAAAICK8KAAAICLAKAAAICLEKAAAICLIKAAAICLMKAAAICLQKAAAICLUKAAAICLYKAAAICLcKAAAICLgKAAAICLkKAAAICLoKAAAICLsKAAAICLwKAAAICL0KAAAICL4KAAAICL8KAAAICMAKAAAICMEKAAAICMIKAAAICMMKAAAICMQKAAAICMUKAAAICMYKAAAICMcKAAAICMgKAAAICMkKAAAICMoKAAAICMsKAAAICMwKAAAICM0KAAAICM4KAAAICM8KAAAICNAKAAAICNEKAAAICNIKAAAICNMKAAAICNQKAAAICNUKAAAICNYKAAAICNcKAAAICNgKAAAICNkKAAAICNoKAAAICNsKAAAICNwKAAAICN0KAAAICN4KAAAICN8KAAAICOAKAAAICOEKAAAICOIKAAAICOMKAAAICOQKAAAICOUKAAAICOYKAAAICOcKAAAICOgKAAAICOkKAAAICOoKAAAICOsKAAAICOwKAAAICO0KAAAICO4KAAAICO8KAAAICPAKAAAICPEKAAAICPIKAAAICPMKAAAICPQKAAAICPUKAAAICPYKAAAICPcKAAAICPgKAAAICPkKAAAICPoKAAAICPsKAAAICPwKAAAICP0KAAAICP4KAAAICP8KAAAICAALAAAICAELAAAICAILAAAICAMLAAAICAQLAAAICAULAAAICAYLAAAICAcLAAAICAgLAAAICAkLAAAICAoLAAAICAsLAAAICAwLAAAICA0LAAAICA4LAAAICA8LAAAICBALAAAICBELAAAICBILAAAICBMLAAAICBQLAAAICBULAAAICBYLAAAICBcLAAAICBgLAAAICBkLAAAICBoLAAAICBsLAAAICBwLAAAICB0LAAAICB4LAAAICB8LAAAICCALAAAICCELAAAICCILAAAICCMLAAAICCQLAAAICCULAAAICCYLAAAICCcLAAAICCgLAAAICCkLAAAICCoLAAAICCsLAAAICCwLAAAICC0LAAAICC4LAAAICC8LAAAICDALAAAICDELAAAICDILAAAICDMLAAAICDQLAAAICDULAAAICDYLAAAICDcLAAAICDgLAAAICDkLAAAICDoLAAAICDsLAAAICDwLAAAICD0LAAAICD4LAAAICD8LAAAICEALAAAICEELAAAICEILAAAICEMLAAAICEQLAAAICEULAAAICEYLAAAICEcLAAAICEgLAAAICEkLAAAICEoLAAAICEsLAAAICEwLAAAICE0LAAAICE4LAAAICE8LAAAICFALAAAICFELAAAICFILAAAICFMLAAAICFQLAAAICFULAAAICFYLAAAICFcLAAAICFgLAAAICFkLAAAICFoLAAAICFsLAAAICFwLAAAICF0LAAAICF4LAAAICF8LAAAICGALAAAICGELAAAICGILAAAICGMLAAAICGQLAAAICGULAAAICGYLAAAICGcLAAAICGgLAAAICGkLAAAICGoLAAAICGsLAAAICGwLAAAICG0LAAAICG4LAAAICG8LAAAICHALAAAICHELAAAICHILAAAICHMLAAAICHQLAAAICHULAAAICHYLAAAICHcLAAAICHgLAAAICHkLAAAICHoLAAAICHsLAAAICHwLAAAICH0LAAAICH4LAAAICH8LAAAICIALAAAICIELAAAICIILAAAICIMLAAAICIQLAAAICIULAAAICIYLAAAICIcLAAAICIgLAAAICIkLAAAICIoLAAAICIsLAAAICIwLAAAICI0LAAAICI4LAAAICI8LAAAICJALAAAICJELAAAICJILAAAICJMLAAAICJQLAAAICJULAAAICJYLAAAICJcLAAAICJgLAAAICJkLAAAICJoLAAAICJsLAAAICJwLAAAICJ0LAAAICJ4LAAAICJ8LAAAICKALAAAICKELAAAICKILAAAICKMLAAAICKQLAAAICKULAAAICKYLAAAICKcLAAAICKgLAAAICKkLAAAICKoLAAAICKsLAAAICKwLAAAICK0LAAAICK4LAAAICK8LAAAICLALAAAICLELAAAICLILAAAICLMLAAAICLQLAAAICLULAAAICLYLAAAICLcLAAAICLgLAAAICLkLAAAICLoLAAAICLsLAAAICLwLAAAICL0LAAAICL4LAAAICL8LAAAICMALAAAICMELAAAICMILAAAICMMLAAAICMQLAAAICMULAAAICMYLAAAICMcLAAAICMgLAAAICMkLAAAICMoLAAAICMsLAAAICMwLAAAICM0LAAAICM4LAAAICM8LAAAICNALAAAICNELAAAICNILAAAICNMLAAAICNQLAAAICNULAAAICNYLAAAICNcLAAAICNgLAAAICNkLAAAICNoLAAAICNsLAAAICNwLAAAICN0LAAAICN4LAAAICN8LAAAICOALAAAICOELAAAICOILAAAICOMLAAAICOQLAAAICOULAAAICOYLAAAICOcLAAAICOgLAAAICOkLAAAICOoLAAAICOsLAAAICOwLAAAICO0LAAAICO4LAAAICO8LAAAICPALAAAICPELAAAICPILAAAICPMLAAAICPQLAAAICPULAAAICPYLAAAICPcLAAAICPgLAAAICPkLAAAICPoLAAAICPsLAAAICPwLAAAICP0LAAAICP4LAAAICP8LAAAICAAMAAAICAEMAAAICAIMAAAICAMMAAAICAQMAAAICAUMAAAICAYMAAAICAcMAAAICAgMAAAICAkMAAAICAoMAAAICAsMAAAICAwMAAAICA0MAAAICA4MAAAICA8MAAAICBAMAAAICBEMAAAICBIMAAAICBMMAAAICBQMAAAICBUMAAAICBYMAAAICBcMAAAICBgMAAAICBkMAAAICBoMAAAICBsMAAAICBwMAAAICB0MAAAICB4MAAAICB8MAAAICCAMAAAICCEMAAAICCIMAAAICCMMAAAICCQMAAAICCUMAAAICCYMAAAICCcMAAAICCgMAAAICCkMAAAICCoMAAAICCsMAAAICCwMAAAICC0MAAAICC4MAAAICC8MAAAICDAMAAAICDEMAAAICDIMAAAICDMMAAAICDQMAAAICDUMAAAICDYMAAAICDcMAAAICDgMAAAICDkMAAAICDoMAAAICDsMAAAICDwMAAAICD0MAAAICD4MAAAICD8MAAAICEAMAAAICEEMAAAICEIMAAAICEMMAAAICEQMAAAICEUMAAAICEYMAAAICEcMAAAICEgMAAAICEkMAAAICEoMAAAICEsMAAAICEwMAAAICE0MAAAICE4MAAAICE8MAAAICFAMAAAICFEMAAAICFIMAAAICFMMAAAICFQMAAAICFUMAAAICFYMAAAICFcMAAAICFgMAAAICFkMAAAICFoMAAAICFsMAAAICFwMAAAICF0MAAAICF4MAAAICF8MAAAICGAMAAAICGEMAAAICGIMAAAICGMMAAAICGQMAAAICGUMAAAICGYMAAAICGcMAAAICGgMAAAICGkMAAAICGoMAAAICGsMAAAICGwMAAAICG0MAAAICG4MAAAICG8MAAAICHAMAAAICHEMAAAICHIMAAAICHMMAAAICHQMAAAICHUMAAAICHYMAAAICHcMAAAICHgMAAAICHkMAAAICHoMAAAICHsMAAAICHwMAAAICH0MAAAICH4MAAAICH8MAAAICIAMAAAICIEMAAAICIIMAAAICIMMAAAICIQMAAAICIUMAAAICIYMAAAICIcMAAAICIgMAAAICIkMAAAICIoMAAAICIsMAAAICIwMAAAICI0MAAAICI4MAAAICI8MAAAICJAMAAAICJEMAAAICJIMAAAICJMMAAAICJQMAAAICJUMAAAICJYMAAAICJcMAAAICJgMAAAICJkMAAAICJoMAAAICJsMAAAICJwMAAAICJ0MAAAICJ4MAAAICJ8MAAAICKAMAAAICKEMAAAICKIMAAAICKMMAAAICKQMAAAICKUMAAAICKYMAAAICKcMAAAICKgMAAAICKkMAAAICKoMAAAICKsMAAAICKwMAAAICK0MAAAICK4MAAAICK8MAAAICLAMAAAICLEMAAAICLIMAAAICLMMAAAICLQMAAAICLUMAAAICLYMAAAICLcMAAAICLgMAAAICLkMAAAICLoMAAAICLsMAAAICLwMAAAICL0MAAAICL4MAAAICL8MAAAICMAMAAAICMEMAAAICMIMAAAICMMMAAAICMQMAAAICMUMAAAICMYMAAAICMcMAAAICMgMAAAICMkMAAAICMoMAAAICMsMAAAICMwMAAAICM0MAAAICM4MAAAICM8MAAAICNAMAAAICNEMAAAICNIMAAAICNMMAAAICNQMAAAICNUMAAAICNYMAAAICNcMAAAICNgMAAAICNkMAAAICNoMAAAICNsMAAAICNwMAAAICN0MAAAICN4MAAAICN8MAAAICOAMAAAICOEMAAAICOIMAAAICOMMAAAICOQMAAAICOUMAAAICOYMAAAICOcMAAAICOgMAAAICOkMAAAICOoMAAAICOsMAAAICOwMAAAICO0MAAAICO4MAAAICO8MAAAICPAMAAAICPEMAAAICPIMAAAICPMMAAAICPQMAAAICPUMAAAICPYMAAAICPcMAAAICPgMAAAICPkMAAAICPoMAAAICPsMAAAICPwMAAAICP0MAAAICP4MAAAICP8MAAAICAANAAAICAENAAAICAINAAAICAMNAAAICAQNAAAICAUNAAAICAYNAAAICAcNAAAICAgNAAAICAkNAAAICAoNAAAICAsNAAAICAwNAAAICA0NAAAICA4NAAAICA8NAAAICBANAAAICBENAAAICBINAAAICBMNAAAICBQNAAAICBUNAAAICBYNAAAICBcNAAAICBgNAAAICBkNAAAICBoNAAAICBsNAAAICBwNAAAICB0NAAAICB4NAAAICB8NAAAICCANAAAICCENAAAICCINAAAICCMNAAAICCQNAAAICCUNAAAICCYNAAAICCcNAAAICCgNAAAICCkNAAAICCoNAAAICCsNAAAICCwNAAAICC0NAAAICC4NAAAICC8NAAAICDANAAAICDENAAAICDINAAAICDMNAAAICDQNAAAICDUNAAAICDYNAAAICDcNAAAICDgNAAAICDkNAAAICDoNAAAICDsNAAAICDwNAAAICD0NAAAICD4NAAAICD8NAAAICEANAAAICEENAAAICEINAAAICEMNAAAICEQNAAAICEUNAAAICEYNAAAICEcNAAAICEgNAAAICEkNAAAICEoNAAAICEsNAAAICEwNAAAICE0NAAAICE4NAAAICE8NAAAICFANAAAICFENAAAICFINAAAICFMNAAAICFQNAAAICFUNAAAICFYNAAAICFcNAAAICFgNAAAICFkNAAAICFoNAAAICFsNAAAICFwNAAAICF0NAAAICF4NAAAICF8NAAAICGANAAAICGENAAAICGINAAAICGMNAAAICGQNAAAICGUNAAAICGYNAAAICGcNAAAICGgNAAAICGkNAAAICGoNAAAICGsNAAAICGwNAAAICG0NAAAICG4NAAAICG8NAAAICHANAAAICHENAAAICHINAAAICHMNAAAICHQNAAAICHUNAAAICHYNAAAICHcNAAAICHgNAAAICHkNAAAICHoNAAAICHsNAAAICHwNAAAICH0NAAAICH4NAAAICH8NAAAICIANAAAICIENAAAICIINAAAICIMNAAAICIQNAAAICIUNAAAICIYNAAAICIcNAAAICIgNAAAICIkNAAAICIoNAAAICIsNAAAICIwNAAAICI0NAAAICI4NAAAICI8NAAAICJANAAAICJENAAAICJINAAAICJMNAAAICJQNAAAICJUNAAAICJYNAAAICJcNAAAICJgNAAAICJkNAAAICJoNAAAICJsNAAAICJwNAAAICJ0NAAAICJ4NAAAICJ8NAAAICKANAAAICKENAAAICKINAAAICKMNAAAICKQNAAAICKUNAAAICKYNAAAICKcNAAAICKgNAAAICKkNAAAICKoNAAAICKsNAAAICKwNAAAICK0NAAAICK4NAAAICK8NAAAICLANAAAICLENAAAICLINAAAICLMNAAAICLQNAAAICLUNAAAICLYNAAAICLcNAAAICLgNAAAICLkNAAAICLoNAAAICLsNAAAICLwNAAAICL0NAAAICL4NAAAICL8NAAAICMANAAAICMENAAAICMINAAAICMMNAAAICMQNAAAICMUNAAAICMYNAAAICMcNAAAICMgNAAAICMkNAAAICMoNAAAICMsNAAAICMwNAAAICM0NAAAICM4NAAAICM8NAAAICNANAAAICNENAAAICNINAAAICNMNAAAICNQNAAAICNUNAAAICNYNAAAICNcNAAAICNgNAAAICNkNAAAICNoNAAAICNsNAAAICNwNAAAICN0NAAAICN4NAAAICN8NAAAICOANAAAICOENAAAICOINAAAICOMNAAAICOQNAAAICOUNAAAICOYNAAAICOcNAAAICOgNAAAICOkNAAAICOoNAAAICOsNAAAICOwNAAAICO0NAAAICO4NAAAICO8NAAAICPANAAAICPENAAAICPINAAAICPMNAAAICPQNAAAICPUNAAAICPYNAAAICPcNAAAICPgNAAAICPkNAAAICPoNAAAICPsNAAAICPwNAAAICP0NAAAICP4NAAAICP8NAAAICAAOAAAICAEOAAAICAIOAAAICAMOAAAICAQOAAAICAUOAAAICAYOAAAICAcOAAAICAgOAAAICAkOAAAICAoOAAAICAsOAAAICAwOAAAICA0OAAAICA4OAAAICA8OAAAICBAOAAAICBEOAAAICBIOAAAICBMOAAAICBQOAAAICBUOAAAICBYOAAAICBcOAAAICBgOAAAICBkOAAAICBoOAAAICBsOAAAICBwOAAAICB0OAAAICB4OAAAICB8OAAAICCAOAAAICCEOAAAICCIOAAAICCMOAAAICCQOAAAICCUOAAAICCYOAAAICCcOAAAICCgOAAAICCkOAAAICCoOAAAICCsOAAAICCwOAAAICC0OAAAICC4OAAAICC8OAAAICDAOAAAICDEOAAAICDIOAAAICDMOAAAICDQOAAAICDUOAAAICDYOAAAICDcOAAAICDgOAAAICDkOAAAICDoOAAAICDsOAAAICDwOAAAICD0OAAAICD4OAAAICD8OAAAICEAOAAAICEEOAAAICEIOAAAICEMOAAAICEQOAAAICEUOAAAICEYOAAAICEcOAAAICEgOAAAICEkOAAAICEoOAAAICEsOAAAICEwOAAAICE0OAAAICE4OAAAICE8OAAAICFAOAAAICFEOAAAICFIOAAAICFMOAAAICFQOAAAICFUOAAAICFYOAAAICFcOAAAICFgOAAAICFkOAAAICFoOAAAICFsOAAAICFwOAAAICF0OAAAICF4OAAAICF8OAAAICGAOAAAICGEOAAAICGIOAAAICGMOAAAICGQOAAAICGUOAAAICGYOAAAICGcOAAAICGgOAAAICGkOAAAICGoOAAAICGsOAAAICGwOAAAICG0OAAAICG4OAAAICG8OAAAICHAOAAAICHEOAAAICHIOAAAICHMOAAAICHQOAAAICHUOAAAICHYOAAAICHcOAAAICHgOAAAICHkOAAAICHoOAAAICHsOAAAICHwOAAAICH0OAAAICH4OAAAICH8OAAAICIAOAAAICIEOAAAICIIOAAAICIMOAAAICIQOAAAICIUOAAAICIYOAAAICIcOAAAICIgOAAAICIkOAAAICIoOAAAICIsOAAAICIwOAAAICI0OAAAICI4OAAAICI8OAAAICJAOAAAICJEOAAAICJIOAAAICJMOAAAICJQOAAAICJUOAAAICJYOAAAICJcOAAAICJgOAAAICJkOAAAICJoOAAAICJsOAAAICJwOAAAICJ0OAAAICJ4OAAAICJ8OAAAICKAOAAAICKEOAAAICKIOAAAICKMOAAAICKQOAAAICKUOAAAICKYOAAAICKcOAAAICKgOAAAICKkOAAAICKoOAAAICKsOAAAICKwOAAAICK0OAAAICK4OAAAICK8OAAAICLAOAAAICLEOAAAICLIOAAAICLMOAAAICLQOAAAICLUOAAAICLYOAAAICLcOAAAICLgOAAAICLkOAAAICLoOAAAICLsOAAAICLwOAAAICL0OAAAICL4OAAAICL8OAAAICMAOAAAICMEOAAAICMIOAAAICMMOAAAICMQOAAAICMUOAAAICMYOAAAICMcOAAAICMgOAAAICMkOAAAICMoOAAAICMsOAAAICMwOAAAICM0OAAAICM4OAAAICM8OAAAICNAOAAAICNEOAAAICNIOAAAICNMOAAAICNQOAAAICNUOAAAICNYOAAAICNcOAAAICNgOAAAICNkOAAAICNoOAAAICNsOAAAICNwOAAAICN0OAAAICN4OAAAICN8OAAAICOAOAAAICOEOAAAICOIOAAAICOMOAAAICOQOAAAICOUOAAAICOYOAAAICOcOAAAICOgOAAAICOkOAAAICOoOAAAICOsOAAAICOwOAAAICO0OAAAICO4OAAAICO8OAAAICPAOAAAICPEOAAAICPIOAAAICPMOAAAICPQOAAAICPUOAAAICPYOAAAICPcOAAAICPgOAAAICPkOAAAICPoOAAAICPsOAAAICPwOAAAICP0OAAAICP4OAAAICP8OAAAICAAPAAAICAEPAAAICAIPAAAICAMPAAAICAQPAAAICAUPAAAICAYPAAAICAcPAAAICAgPAAAICAkPAAAICAoPAAAICAsPAAAICAwPAAAICA0PAAAICA4PAAAICA8PAAAICBAPAAAICBEPAAAICBIPAAAICBMPAAAICBQPAAAICBUPAAAICBYPAAAICBcPAAAICBgPAAAICBkPAAAICBoPAAAICBsPAAAICBwPAAAICB0PAAAICB4PAAAICB8PAAAICCAPAAAICCEPAAAICCIPAAAICCMPAAAICCQPAAAICCUPAAAICCYPAAAICCcPAAAICCgPAAAICCkPAAAICCoPAAAICCsPAAAICCwPAAAICC0PAAAICC4PAAAICC8PAAAICDAPAAAICDEPAAAICDIPAAAICDMPAAAICDQPAAAICDUPAAAICDYPAAAICDcPAAAICDgPAAAICDkPAAAICDoPAAAICDsPAAAICDwPAAAICD0PAAAICD4PAAAICD8PAAAICEAPAAAICEEPAAAICEIPAAAICEMPAAAICEQPAAAICEUPAAAICEYPAAAICEcPAAAICEgPAAAICEkPAAAICEoPAAAICEsPAAAICEwPAAAICE0PAAAICE4PAAAICE8PAAAICFAPAAAICFEPAAAICFIPAAAICFMPAAAICFQPAAAICFUPAAAICFYPAAAICFcPAAAICFgPAAAICFkPAAAICFoPAAAICFsPAAAICFwPAAAICF0PAAAICF4PAAAICF8PAAAICGAPAAAICGEPAAAICGIPAAAICGMPAAAICGQPAAAICGUPAAAICGYPAAAICGcPAAAICGgPAAAICGkPAAAICGoPAAAICGsPAAAICGwPAAAICG0PAAAICG4PAAAICG8PAAAICHAPAAAICHEPAAAICHIPAAAICHMPAAAICHQPAAAICHUPAAAICHYPAAAICHcPAAAICHgPAAAICHkPAAAICHoPAAAICHsPAAAICHwPAAAICH0PAAAICH4PAAAICH8PAAAICIAPAAAICIEPAAAICIIPAAAICIMPAAAICIQPAAAICIUPAAAICIYPAAAICIcPAAAICIgPAAAICIkPAAAICIoPAAAICIsPAAAICIwPAAAICI0PAAAICI4PAAAICI8PAAAICJAPAAAICJEPAAAICJIPAAAICJMPAAAICJQPAAAICJUPAAAICJYPAAAICJcPAAAICJgPAAAICJkPAAAICJoPAAAICJsPAAAICJwPAAAICJ0PAAAICJ4PAAAICJ8PAAAICKAPAAAICKEPAAAICKIPAAAICKMPAAAICKQPAAAICKUPAAAICKYPAAAICKcPAAAICKgPAAAICKkPAAAICKoPAAAICKsPAAAICKwPAAAICK0PAAAICK4PAAAICK8PAAAICLAPAAAICLEPAAAICLIPAAAICLMPAAAICLQPAAAICLUPAAAICLYPAAAICLcPAAAICLgPAAAICLkPAAAICLoPAAAICLsPAAAICLwPAAAICL0PAAAICL4PAAAICL8PAAAICMAPAAAICMEPAAAICMIPAAAICMMPAAAICMQPAAAICMUPAAAICMYPAAAICMcPAAAICMgPAAAICMkPAAAICMoPAAAICMsPAAAICMwPAAAICM0PAAAICM4PAAAICM8PAAAICNAPAAAICNEPAAAICNIPAAAICNMPAAAICNQPAAAICNUPAAAICNYPAAAICNcPAAAICNgPAAAICNkPAAAICNoPAAAICNsPAAAICNwPAAAICN0PAAAICN4PAAAICN8PAAAICOAPAAAICOEPAAAICOIPAAAICOMPAAAICOQPAAAICOUPAAAICOYPAAAICOcPAAAICOgPAAAICOkPAAAICOoPAAAICOsPAAAICOwPAAAICO0PAAAICO4PAAAICO8PAAAICPAPAAAICPEPAAAICPIPAAAICPMPAAAICPQPAAAICPUPAAAICPYPAAAICPcPAAAICPgPAAAICPkPAAAICPoPAAAICPsPAAAICPwPAAAICP0PAAAICP4PAAAICP8PAAAICAAQAAAICAEQAAAICAIQAAAICAMQAAAICAQQAAAICAUQAAAICAYQAAAICAcQAAAICAgQAAAICAkQAAAICAoQAAAICAsQAAAICAwQAAAICA0QAAAICA4QAAAICA8QAAAICBAQAAAICBEQAAAICBIQAAAICBMQAAAICBQQAAAICBUQAAAICBYQAAAICBcQAAAICBgQAAAICBkQAAAICBoQAAAICBsQAAAICBwQAAAICB0QAAAICB4QAAAICB8QAAAICCAQAAAICCEQAAAICCIQAAAICCMQAAAICCQQAAAICCUQAAAICCYQAAAICCcQAAAICCgQAAAICCkQAAAICCoQAAAICCsQAAAICCwQAAAICC0QAAAICC4QAAAICC8QAAAICDAQAAAICDEQAAAICDIQAAAICDMQAAAICDQQAAAICDUQAAAICDYQAAAICDcQAAAICDgQAAAICDkQAAAICDoQAAAICDsQAAAICDwQAAAICD0QAAAICD4QAAAICD8QAAAICEAQAAAICEEQAAAICEIQAAAICEMQAAAICEQQAAAICEUQAAAICEYQAAAICEcQAAAICEgQAAAICEkQAAAICEoQAAAICEsQAAAICEwQAAAICE0QAAAICE4QAAAICE8QAAAICFAQAAAICFEQAAAICFIQAAAICFMQAAAICFQQAAAICFUQAAAICFYQAAAICFcQAAAICFgQAAAICFkQAAAICFoQAAAICFsQAAAICFwQAAAICF0QAAAICF4QAAAICF8QAAAICGAQAAAICGEQAAAICGIQAAAICGMQAAAICGQQAAAICGUQAAAICGYQAAAICGcQAAAICGgQAAAICGkQAAAICGoQAAAICGsQAAAICGwQAAAICG0QAAAICG4QAAAICG8QAAAICHAQAAAICHEQAAAICHIQAAAICHMQAAAICHQQAAAICHUQAAAICHYQAAAICHcQAAAICHgQAAAICHkQAAAICHoQAAAICHsQAAAICHwQAAAICH0QAAAICH4QAAAICH8QAAAICIAQAAAICIEQAAAICIIQAAAICIMQAAAICIQQAAAICIUQAAAICIYQAAAICIcQAAAICIgQAAAICIkQAAAICIoQAAAICIsQAAAICIwQAAAICI0QAAAICI4QAAAICI8QAAAICJAQAAAICJEQAAAICJIQAAAICJMQAAAICJQQAAAICJUQAAAICJYQAAAICJcQAAAICJgQAAAICJkQAAAICJoQAAAICJsQAAAICJwQAAAICJ0QAAAICJ4QAAAICJ8QAAAICKAQAAAICKEQAAAICKIQAAAICKMQAAAICKQQAAAICKUQAAAICKYQAAAICKcQAAAICKgQAAAICKkQAAAICKoQAAAICKsQAAAICKwQAAAICK0QAAAICK4QAAAICK8QAAAICLAQAAAICLEQAAAICLIQAAAICLMQAAAICLQQAAAICLUQAAAICLYQAAAICLcQAAAICLgQAAAICLkQAAAICLoQAAAICLsQAAAICLwQAAAICL0QAAAICL4QAAAICL8QAAAICMAQAAAICMEQAAAICMIQAAAICMMQAAAICMQQAAAICMUQAAAICMYQAAAICMcQAAAICMgQAAAICMkQAAAICMoQAAAICMsQAAAICMwQAAAICM0QAAAICM4QAAAICM8QAAAICNAQAAAICNEQAAAICNIQAAAICNMQAAAICNQQAAAICNUQAAAICNYQAAAICNcQAAAICNgQAAAICNkQAAAICNoQAAAICNsQAAAICNwQAAAICN0QAAAICN4QAAAICN8QAAAICOAQAAAICOEQAAAICOIQAAAICOMQAAAICOQQAAAICOUQAAAICOYQAAAICOcQAAAICOgQAAAICOkQAAAICOoQAAAICOsQAAAICOwQAAAICO0QAAAICO4QAAAICO8QAAAICPAQAAAICPEQAAAICPIQAAAICPMQAAAICPQQAAAICPUQAAAICPYQAAAICPcQAAAICPgQAAAICPkQAAAICPoQAAAICPsQAAAICPwQAAAICP0QAAAICP4QAAAICP8QAAAICAARAAAICAERAAAICAIRAAAICAMRAAAICAQRAAAICAURAAAICAYRAAAICAcRAAAICAgRAAAICAkRAAAICAoRAAAICAsRAAAICAwRAAAICA0RAAAICA4RAAAICA8RAAAICBARAAAICBERAAAICBIRAAAICBMRAAAICBQRAAAICBURAAAICBYRAAAICBcRAAAICBgRAAAICBkRAAAICBoRAAAICBsRAAAICBwRAAAICB0RAAAICB4RAAAICB8RAAAICCARAAAICCERAAAICCIRAAAICCMRAAAICCQRAAAICCURAAAICCYRAAAICCcRAAAICCgRAAAICCkRAAAICCoRAAAICCsRAAAICCwRAAAICC0RAAAICC4RAAAICC8RAAAICDARAAAICDERAAAICDIRAAAICDMRAAAICDQRAAAICDURAAAICDYRAAAICDcRAAAICDgRAAAICDkRAAAICDoRAAAICDsRAAAICDwRAAAICD0RAAAICD4RAAAICD8RAAAICEARAAAICEERAAAICEIRAAAICEMRAAAICEQRAAAICEURAAAICEYRAAAICEcRAAAICEgRAAAICEkRAAAICEoRAAAICEsRAAAICEwRAAAICE0RAAAICE4RAAAICE8RAAAICFARAAAICFERAAAICFIRAAAICFMRAAAICFQRAAAICFURAAAICFYRAAAICFcRAAAICFgRAAAICFkRAAAICFoRAAAICFsRAAAICFwRAAAICF0RAAAICF4RAAAICF8RAAAICGARAAAICGERAAAICGIRAAAICGMRAAAICGQRAAAICGURAAAICGYRAAAICGcRAAAICGgRAAAICGkRAAAICGoRAAAICGsRAAAICGwRAAAICG0RAAAICG4RAAAICG8RAAAICHARAAAICHERAAAICHIRAAAICHMRAAAICHQRAAAICHURAAAICHYRAAAICHcRAAAICHgRAAAICHkRAAAICHoRAAAICHsRAAAICHwRAAAICH0RAAAICH4RAAAICH8RAAAICIARAAAICIERAAAICIIRAAAICIMRAAAICIQRAAAICIURAAAICIYRAAAICIcRAAAICIgRAAAICIkRAAAICIoRAAAICIsRAAAICIwRAAAICI0RAAAICI4RAAAICI8RAAAICJARAAAICJERAAAICJIRAAAICJMRAAAICJQRAAAICJURAAAICJYRAAAICJcRAAAICJgRAAAICJkRAAAICJoRAAAICJsRAAAICJwRAAAICJ0RAAAICJ4RAAAICJ8RAAAICKARAAAICKERAAAICKIRAAAICKMRAAAICKQRAAAICKURAAAICKYRAAAICKcRAAAICKgRAAAICKkRAAAICKoRAAAICKsRAAAICKwRAAAICK0RAAAICK4RAAAICK8RAAAICLARAAAICLERAAAICLIRAAAICLMRAAAICLQRAAAICLURAAAICLYRAAAICLcRAAAICLgRAAAICLkRAAAICLoRAAAICLsRAAAICLwRAAAICL0RAAAICL4RAAAICL8RAAAICMARAAAICMERAAAICMIRAAAICMMRAAAICMQRAAAICMURAAAICMYRAAAICMcRAAAICMgRAAAICMkRAAAICMoRAAAICMsRAAAICMwRAAAICM0RAAAICM4RAAAICM8RAAAICNARAAAICNERAAAICNIRAAAICNMRAAAICNQRAAAICNURAAAICNYRAAAICNcRAAAICNgRAAAICNkRAAAICNoRAAAICNsRAAAICNwRAAAICN0RAAAICN4RAAAICN8RAAAICOARAAAICOERAAAICOIRAAAICOMRAAAICOQRAAAICOURAAAICOYRAAAICOcRAAAICOgRAAAICOkRAAAICOoRAAAICOsRAAAICOwRAAAICO0RAAAICO4RAAAICO8RAAAICPARAAAICPERAAAICPIRAAAICPMRAAAICPQRAAAICPURAAAICPYRAAAICPcRAAAICPgRAAAICPkRAAAICPoRAAAICPsRAAAICPwRAAAICP0RAAAICP4RAAAICP8RAAAICAASAAAICAESAAAICAISAAAICAMSAAAICAQSAAAICAUSAAAICAYSAAAICAcSAAAICAgSAAAICAkSAAAICAoSAAAICAsSAAAICAwSAAAICA0SAAAICA4SAAAICA8SAAAICBASAAAICBESAAAICBISAAAICBMSAAAICBQSAAAICBUSAAAICBYSAAAICBcSAAAICBgSAAAICBkSAAAICBoSAAAICBsSAAAICBwSAAAICB0SAAAICB4SAAAICB8SAAAICCASAAAICCESAAAICCISAAAICCMSAAAICCQSAAAICCUSAAAICCYSAAAICCcSAAAICCgSAAAICCkSAAAICCoSAAAICCsSAAAICCwSAAAICC0SAAAICC4SAAAICC8SAAAICDASAAAICDESAAAICDISAAAICDMSAAAICDQSAAAICDUSAAAICDYSAAAICDcSAAAICDgSAAAICDkSAAAICDoSAAAICDsSAAAICDwSAAAICD0SAAAICD4SAAAICD8SAAAICEASAAAICEESAAAICEISAAAICEMSAAAICEQSAAAICEUSAAAICEYSAAAICEcSAAAICEgSAAAICEkSAAAICEoSAAAICEsSAAAICEwSAAAICE0SAAAICE4SAAAICE8SAAAICFASAAAICFESAAAICFISAAAICFMSAAAICFQSAAAICFUSAAAICFYSAAAICFcSAAAICFgSAAAICFkSAAAICFoSAAAICFsSAAAICFwSAAAICF0SAAAICF4SAAAICF8SAAAICGASAAAICGESAAAICGISAAAICGMSAAAICGQSAAAICGUSAAAICGYSAAAICGcSAAAICGgSAAAICGkSAAAICGoSAAAICGsSAAAICGwSAAAICG0SAAAICG4SAAAICG8SAAAICHASAAAICHESAAAICHISAAAICHMSAAAICHQSAAAICHUSAAAICHYSAAAICHcSAAAICHgSAAAICHkSAAAICHoSAAAICHsSAAAICHwSAAAICH0SAAAICH4SAAAICH8SAAAICIASAAAICIESAAAICIISAAAICIMSAAAICIQSAAAICIUSAAAICIYSAAAICIcSAAAICIgSAAAICIkSAAAICIoSAAAICIsSAAAICIwSAAAICI0SAAAICI4SAAAICI8SAAAICJASAAAICJESAAAICJISAAAICJMSAAAICJQSAAAICJUSAAAICJYSAAAICJcSAAAICJgSAAAICJkSAAAICJoSAAAICJsSAAAICJwSAAAICJ0SAAAICJ4SAAAICJ8SAAAICKASAAAICKESAAAICKISAAAICKMSAAAICKQSAAAICKUSAAAICKYSAAAICKcSAAAICKgSAAAICKkSAAAICKoSAAAICKsSAAAICKwSAAAICK0SAAAICK4SAAAICK8SAAAICLASAAAICLESAAAICLISAAAICLMSAAAICLQSAAAICLUSAAAICLYSAAAICLcSAAAICLgSAAAICLkSAAAICLoSAAAICLsSAAAICLwSAAAICL0SAAAICL4SAAAICL8SAAAICMASAAAICMESAAAICMISAAAICMMSAAAICMQSAAAICMUSAAAICMYSAAAICMcSAAAICMgSAAAICMkSAAAICMoSAAAICMsSAAAICMwSAAAICM0SAAAICM4SAAAICM8SAAAICNASAAAICNESAAAICNISAAAICNMSAAAICNQSAAAICNUSAAAICNYSAAAICNcSAAAICNgSAAAICNkSAAAICNoSAAAICNsSAAAICNwSAAAICN0SAAAICN4SAAAICN8SAAAICOASAAAICOESAAAICOISAAAICOMSAAAICOQSAAAICOUSAAAICOYSAAAICOcSAAAICOgSAAAICOkSAAAICOoSAAAICOsSAAAICOwSAAAICO0SAAAICO4SAAAICO8SAAAICPASAAAICPESAAAICPISAAAICPMSAAAICPQSAAAICPUSAAAICPYSAAAICPcSAAAICPgSAAAICPkSAAAICPoSAAAICPsSAAAICPwSAAAICP0SAAAICP4SAAAICP8SAAAICAATAAAICAETAAAICAITAAAICAMTAAAICAQTAAAICAUTAAAICAYTAAAICAcTAAAICAgTAAAICAkTAAAICAoTAAAICAsTAAAICAwTAAAICA0TAAAICA4TAAAICA8TAAAICBATAAAICBETAAAICBITAAAICBMTAAAICBQTAAAICBUTAAAICBYTAAAICBcTAAAICBgTAAAICBkTAAAICBoTAAAICBsTAAAICBwTAAAICB0TAAAICB4TAAAICB8TAAAICCATAAAICCETAAAICCITAAAICCMTAAAICCQTAAAICCUTAAAICCYTAAAICCcTAAAICCgTAAAICCkTAAAICCoTAAAICCsTAAAICCwTAAAICC0TAAAICC4TAAAICC8TAAAICDATAAAICDETAAAICDITAAAICDMTAAAICDQTAAAICDUTAAAICDYTAAAICDcTAAAICDgTAAAICDkTAAAICDoTAAAICDsTAAAICDwTAAAICD0TAAAICD4TAAAICD8TAAAICEATAAAICEETAAAICEITAAAICEMTAAAICEQTAAAICEUTAAAICEYTAAAICEcTAAAICEgTAAAICEkTAAAICEoTAAAICEsTAAAICEwTAAAICE0TAAAICE4TAAAICE8TAAAICFATAAAICFETAAAICFITAAAICFMTAAAICFQTAAAICFUTAAAICFYTAAAICFcTAAAICFgTAAAICFkTAAAICFoTAAAICFsTAAAICFwTAAAICF0TAAAICF4TAAAICF8TAAAICGATAAAICGETAAAICGITAAAICGMTAAAICGQTAAAICGUTAAAICGYTAAAICGcTAAAICGgTAAAICGkTAAAICGoTAAAICGsTAAAICGwTAAAICG0TAAAICG4TAAAICG8TAAAICHATAAAICHETAAAICHITAAAICHMTAAAICHQTAAAICHUTAAAICHYTAAAICHcTAAAICHgTAAAICHkTAAAICHoTAAAICHsTAAAICHwTAAAICH0TAAAICH4TAAAICH8TAAAICIATAAAICIETAAAICIITAAAICIMTAAAICIQTAAAICIUTAAAICIYTAAAICIcTAAAICIgTAAAICIkTAAAICIoTAAAICIsTAAAICIwTAAAICI0TAAAICI4TAAAICI8TAAAICJATAAAICJETAAAICJITAAAICJMTAAAICJQTAAAICJUTAAAICJYTAAAICJcTAAAICJgTAAAICJkTAAAICJoTAAAICJsTAAAICJwTAAAICJ0TAAAICJ4TAAAICJ8TAAAICKATAAAICKETAAAICKITAAAICKMTAAAICKQTAAAICKUTAAAICKYTAAAICKcTAAAICKgTAAAICKkTAAAICKoTAAAICKsTAAAICKwTAAAICK0TAAAICK4TAAAICK8TAAAICLATAAAICLETAAAICLITAAAICLMTAAAICLQTAAAICLUTAAAICLYTAAAICLcTAAAICLgTAAAICLkTAAAICLoTAAAICLsTAAAICLwTAAAICL0TAAAICL4TAAAICL8TAAAICMATAAAICMETAAAICMITAAAICMMTAAAICMQTAAAICMUTAAAICMYTAAAICMcTAAAICMgTAAAICMkTAAAICMoTAAAICMsTAAAICMwTAAAICM0TAAAICM4TAAAICM8TAAAICNATAAAICNETAAAICNITAAAICNMTAAAICNQTAAAICNUTAAAICNYTAAAICNcTAAAICNgTAAAICNkTAAAICNoTAAAICNsTAAAICNwTAAAICN0TAAAICN4TAAAICN8TAAAICOATAAAICOETAAAICOITAAAICOMTAAAICOQTAAAICOUTAAAICOYTAAAICOcTAAAICOgTAAAICOkTAAAICOoTAAAICOsTAAAICOwTAAAICO0TAAAICO4TAAAICO8TAAAICPATAAAICPETAAAICPITAAAICPMTAAAICPQTAAAICPUTAAAICPYTAAAICPcTAAAICPgTAAAICPkTAAAICPoTAAAICPsTAAAICPwTAAAICP0TAAAICP4TAAAICP8TAAAICAAUAAAICAEUAAAICAIUAAAICAMUAAAICAQUAAAICAUUAAAICAYUAAAICAcUAAAICAgUAAAICAkUAAAICAoUAAAICAsUAAAICAwUAAAICA0UAAAICA4UAAAICA8UAAAICBAUAAAICBEUAAAICBIUAAAICBMUAAAICBQUAAAICBUUAAAICBYUAAAICBcUAAAICBgUAAAICBkUAAAICBoUAAAICBsUAAAICBwUAAAICB0UAAAICB4UAAAICB8UAAAICCAUAAAICCEUAAAICCIUAAAICCMUAAAICCQUAAAICCUUAAAICCYUAAAICCcUAAAICCgUAAAICCkUAAAICCoUAAAICCsUAAAICCwUAAAICC0UAAAICC4UAAAICC8UAAAICDAUAAAICDEUAAAICDIUAAAICDMUAAAICDQUAAAICDUUAAAICDYUAAAICDcUAAAICDgUAAAICDkUAAAICDoUAAAICDsUAAAICDwUAAAICD0UAAAICD4UAAAICD8UAAAICEAUAAAICEEUAAAICEIUAAAICEMUAAAICEQUAAAICEUUAAAICEYUAAAICEcUAAAICEgUAAAICEkUAAAICEoUAAAICEsUAAAICEwUAAAICE0UAAAICE4UAAAICE8UAAAICFAUAAAICFEUAAAICFIUAAAICFMUAAAICFQUAAAICFUUAAAICFYUAAAICFcUAAAICFgUAAAICFkUAAAICFoUAAAICFsUAAAICFwUAAAICF0UAAAICF4UAAAICF8UAAAICGAUAAAICGEUAAAICGIUAAAICGMUAAAICGQUAAAICGUUAAAICGYUAAAICGcUAAAICGgUAAAICGkUAAAICGoUAAAICGsUAAAICGwUAAAICG0UAAAICG4UAAAICG8UAAAICHAUAAAICHEUAAAICHIUAAAICHMUAAAICHQUAAAICHUUAAAICHYUAAAICHcUAAAICHgUAAAICHkUAAAICHoUAAAICHsUAAAICHwUAAAICH0UAAAICH4UAAAICH8UAAAICIAUAAAICIEUAAAICIIUAAAICIMUAAAICIQUAAAICIUUAAAICIYUAAAICIcUAAAICIgUAAAICIkUAAAICIoUAAAICIsUAAAICIwUAAAICI0UAAAICI4UAAAICI8UAAAICJAUAAAICJEUAAAICJIUAAAICJMUAAAICJQUAAAICJUUAAAICJYUAAAICJcUAAAICJgUAAAICJkUAAAICJoUAAAICJsUAAAICJwUAAAICJ0UAAAICJ4UAAAICJ8UAAAICKAUAAAICKEUAAAICKIUAAAICKMUAAAICKQUAAAICKUUAAAICKYUAAAICKcUAAAICKgUAAAICKkUAAAICKoUAAAICKsUAAAICKwUAAAICK0UAAAICK4UAAAICK8UAAAICLAUAAAICLEUAAAICLIUAAAICLMUAAAICLQUAAAICLUUAAAICLYUAAAICLcUAAAICLgUAAAICLkUAAAICLoUAAAICLsUAAAICLwUAAAICL0UAAAICL4UAAAICL8UAAAICMAUAAAICMEUAAAICMIUAAAICMMUAAAICMQUAAAICMUUAAAICMYUAAAICMcUAAAICMgUAAAICMkUAAAICMoUAAAICMsUAAAICMwUAAAICM0UAAAICM4UAAAICM8UAAAICNAUAAAICNEUAAAICNIUAAAICNMUAAAICNQUAAAICNUUAAAICNYUAAAICNcUAAAICNgUAAAICNkUAAAICNoUAAAICNsUAAAICNwUAAAICN0UAAAICN4UAAAICN8UAAAICOAUAAAICOEUAAAICOIUAAAICOMUAAAICOQUAAAICOUUAAAICOYUAAAICOcUAAAICOgUAAAICOkUAAAICOoUAAAICOsUAAAICOwUAAAICO0UAAAICO4UAAAICO8UAAAICPAUAAAICPEUAAAICPIUAAAICPMUAAAICPQUAAAICPUUAAAICPYUAAAICPcUAAAICPgUAAAICPkUAAAICPoUAAAICPsUAAAICPwUAAAICP0UAAAICP4UAAAICP8UAAAICAAVAAAICAEVAAAICAIVAAAICAMVAAAICAQVAAAICAUVAAAICAYVAAAICAcVAAAICAgVAAAICAkVAAAICAoVAAAICAsVAAAICAwVAAAICA0VAAAICA4VAAAICA8VAAAICBAVAAAICBEVAAAICBIVAAAICBMVAAAICBQVAAAICBUVAAAICBYVAAAICBcVAAAICBgVAAAICBkVAAAICBoVAAAICBsVAAAICBwVAAAICB0VAAAICB4VAAAICB8VAAAICCAVAAAICCEVAAAICCIVAAAICCMVAAAICCQVAAAICCUVAAAICCYVAAAICCcVAAAICCgVAAAICCkVAAAICCoVAAAICCsVAAAICCwVAAAICC0VAAAICC4VAAAICC8VAAAICDAVAAAICDEVAAAICDIVAAAICDMVAAAICDQVAAAICDUVAAAICDYVAAAICDcVAAAICDgVAAAICDkVAAAICDoVAAAICDsVAAAICDwVAAAICD0VAAAICD4VAAAICD8VAAAICEAVAAAICEEVAAAICEIVAAAICEMVAAAICEQVAAAICEUVAAAICEYVAAAICEcVAAAICEgVAAAICEkVAAAICEoVAAAICEsVAAAICEwVAAAICE0VAAAICE4VAAAICE8VAAAICFAVAAAICFEVAAAICFIVAAAICFMVAAAICFQVAAAICFUVAAAICFYVAAAICFcVAAAICFgVAAAICFkVAAAICFoVAAAICFsVAAAICFwVAAAICF0VAAAICF4VAAAICF8VAAAICGAVAAAICGEVAAAICGIVAAAICGMVAAAICGQVAAAICGUVAAAICGYVAAAICGcVAAAICGgVAAAICGkVAAAICGoVAAAICGsVAAAICGwVAAAICG0VAAAICG4VAAAICG8VAAAICHAVAAAICHEVAAAICHIVAAAICHMVAAAICHQVAAAICHUVAAAICHYVAAAICHcVAAAICHgVAAAICHkVAAAICHoVAAAICHsVAAAICHwVAAAICH0VAAAICH4VAAAICH8VAAAICIAVAAAICIEVAAAICIIVAAAICIMVAAAICIQVAAAICIUVAAAICIYVAAAICIcVAAAICIgVAAAICIkVAAAICIoVAAAICIsVAAAICIwVAAAICI0VAAAICI4VAAAICI8VAAAICJAVAAAICJEVAAAICJIVAAAICJMVAAAICJQVAAAICJUVAAAICJYVAAAICJcVAAAICJgVAAAICJkVAAAICJoVAAAICJsVAAAICJwVAAAICJ0VAAAICJ4VAAAICJ8VAAAICKAVAAAICKEVAAAICKIVAAAICKMVAAAICKQVAAAICKUVAAAICKYVAAAICKcVAAAICKgVAAAICKkVAAAICKoVAAAICKsVAAAICKwVAAAICK0VAAAICK4VAAAICK8VAAAICLAVAAAICLEVAAAICLIVAAAICLMVAAAICLQVAAAICLUVAAAICLYVAAAICLcVAAAICLgVAAAICLkVAAAICLoVAAAICLsVAAAICLwVAAAICL0VAAAICL4VAAAICL8VAAAICMAVAAAICMEVAAAICMIVAAAICMMVAAAICMQVAAAICMUVAAAICMYVAAAICMcVAAAICMgVAAAICMkVAAAICMoVAAAICMsVAAAICMwVAAAICM0VAAAICM4VAAAICM8VAAAICNAVAAAICNEVAAAICNIVAAAICNMVAAAICNQVAAAICNUVAAAICNYVAAAICNcVAAAICNgVAAAICNkVAAAICNoVAAAICNsVAAAICNwVAAAICN0VAAAICN4VAAAICN8VAAAICOAVAAAICOEVAAAICOIVAAAICOMVAAAICOQVAAAICOUVAAAICOYVAAAICOcVAAAICOgVAAAICOkVAAAICOoVAAAICOsVAAAICOwVAAAICO0VAAAICO4VAAAICO8VAAAICPAVAAAICPEVAAAICPIVAAAICPMVAAAICPQVAAAICPUVAAAICPYVAAAICPcVAAAICPgVAAAICPkVAAAICPoVAAAICPsVAAAICPwVAAAICP0VAAAICP4VAAAICP8VAAAICAAWAAAICAEWAAAICAIWAAAICAMWAAAICAQWAAAICAUWAAAICAYWAAAICAcWAAAICAgWAAAICAkWAAAICAoWAAAICAsWAAAICAwWAAAICA0WAAAICA4WAAAICA8WAAAICBAWAAAICBEWAAAICBIWAAAICBMWAAAICBQWAAAICBUWAAAICBYWAAAICBcWAAAICBgWAAAICBkWAAAICBoWAAAICBsWAAAICBwWAAAICB0WAAAICB4WAAAICB8WAAAICCAWAAAICCEWAAAICCIWAAAICCMWAAAICCQWAAAICCUWAAAICCYWAAAICCcWAAAICCgWAAAICCkWAAAICCoWAAAICCsWAAAICCwWAAAICC0WAAAICC4WAAAICC8WAAAICDAWAAAICDEWAAAICDIWAAAICDMWAAAICDQWAAAICDUWAAAICDYWAAAICDcWAAAICDgWAAAICDkWAAAICDoWAAAICDsWAAAICDwWAAAICD0WAAAICD4WAAAICD8WAAAICEAWAAAICEEWAAAICEIWAAAICEMWAAAICEQWAAAICEUWAAAICEYWAAAICEcWAAAICEgWAAAICEkWAAAICEoWAAAICEsWAAAICEwWAAAICE0WAAAICE4WAAAICE8WAAAICFAWAAAICFEWAAAICFIWAAAICFMWAAAICFQWAAAICFUWAAAICFYWAAAICFcWAAAICFgWAAAICFkWAAAICFoWAAAICFsWAAAICFwWAAAICF0WAAAICF4WAAAICF8WAAAICGAWAAAICGEWAAAICGIWAAAICGMWAAAICGQWAAAICGUWAAAICGYWAAAICGcWAAAICGgWAAAICGkWAAAICGoWAAAICGsWAAAICGwWAAAICG0WAAAICG4WAAAICG8WAAAICHAWAAAICHEWAAAICHIWAAAICHMWAAAICHQWAAAICHUWAAAICHYWAAAICHcWAAAICHgWAAAICHkWAAAICHoWAAAICHsWAAAICHwWAAAICH0WAAAICH4WAAAICH8WAAAICIAWAAAICIEWAAAICIIWAAAICIMWAAAICIQWAAAICIUWAAAICIYWAAAICIcWAAAICIgWAAAICIkWAAAICIoWAAAICIsWAAAICIwWAAAICI0WAAAICI4WAAAICI8WAAAICJAWAAAICJEWAAAICJIWAAAICJMWAAAICJQWAAAICJUWAAAICJYWAAAICJcWAAAICJgWAAAICJkWAAAICJoWAAAICJsWAAAICJwWAAAICJ0WAAAICJ4WAAAICJ8WAAAICKAWAAAICKEWAAAICKIWAAAICKMWAAAICKQWAAAICKUWAAAICKYWAAAICKcWAAAICKgWAAAICKkWAAAICKoWAAAICKsWAAAICKwWAAAICK0WAAAICK4WAAAICK8WAAAICLAWAAAICLEWAAAICLIWAAAICLMWAAAICLQWAAAICLUWAAAICLYWAAAICLcWAAAICLgWAAAICLkWAAAICLoWAAAICLsWAAAICLwWAAAICL0WAAAICL4WAAAICL8WAAAICMAWAAAICMEWAAAICMIWAAAICMMWAAAICMQWAAAICMUWAAAICMYWAAAICMcWAAAICMgWAAAICMkWAAAICMoWAAAICMsWAAAICMwWAAAICM0WAAAICM4WAAAICM8WAAAICNAWAAAICNEWAAAICNIWAAAICNMWAAAICNQWAAAICNUWAAAICNYWAAAICNcWAAAICNgWAAAICNkWAAAICNoWAAAICNsWAAAICNwWAAAICN0WAAAICN4WAAAICN8WAAAICOAWAAAICOEWAAAICOIWAAAICOMWAAAICOQWAAAICOUWAAAICOYWAAAICOcWAAAICOgWAAAICOkWAAAICOoWAAAICOsWAAAICOwWAAAICO0WAAAICO4WAAAICO8WAAAICPAWAAAICPEWAAAICPIWAAAICPMWAAAICPQWAAAICPUWAAAICPYWAAAICPcWAAAICPgWAAAICPkWAAAICPoWAAAICPsWAAAICPwWAAAICP0WAAAICP4WAAAICP8WAAAICAAXAAAICAEXAAAICAIXAAAICAMXAAAICAQXAAAICAUXAAAICAYXAAAICAcXAAAICAgXAAAICAkXAAAICAoXAAAICAsXAAAICAwXAAAICA0XAAAICA4XAAAICA8XAAAICBAXAAAICBEXAAAICBIXAAAICBMXAAAICBQXAAAICBUXAAAICBYXAAAICBcXAAAICBgXAAAICBkXAAAICBoXAAAICBsXAAAICBwXAAAICB0XAAAICB4XAAAICB8XAAAICCAXAAAICCEXAAAICCIXAAAICCMXAAAICCQXAAAICCUXAAAICCYXAAAICCcXAAAICCgXAAAICCkXAAAICCoXAAAICCsXAAAICCwXAAAICC0XAAAICC4XAAAICC8XAAAICDAXAAAICDEXAAAICDIXAAAICDMXAAAICDQXAAAICDUXAAAICDYXAAAICDcXAAAICDgXAAAICDkXAAAICDoXAAAICDsXAAAICDwXAAAICD0XAAAICD4XAAAICD8XAAAICEAXAAAICEEXAAAICEIXAAAICEMXAAAICEQXAAAICEUXAAAICEYXAAAICEcXAAAICEgXAAAICEkXAAAICEoXAAAICEsXAAAICEwXAAAICE0XAAAICE4XAAAICE8XAAAICFAXAAAICFEXAAAICFIXAAAICFMXAAAICFQXAAAICFUXAAAICFYXAAAICFcXAAAICFgXAAAICFkXAAAICFoXAAAICFsXAAAICFwXAAAICF0XAAAICF4XAAAICF8XAAAICGAXAAAICGEXAAAICGIXAAAICGMXAAAICGQXAAAICGUXAAAICGYXAAAICGcXAAAICGgXAAAICGkXAAAICGoXAAAICGsXAAAICGwXAAAICG0XAAAICG4XAAAICG8XAAAICHAXAAAICHEXAAAICHIXAAAICHMXAAAICHQXAAAICHUXAAAICHYXAAAICHcXAAAICHgXAAAICHkXAAAICHoXAAAICHsXAAAICHwXAAAICH0XAAAICH4XAAAICH8XAAAICIAXAAAICIEXAAAICIIXAAAICIMXAAAICIQXAAAICIUXAAAICIYXAAAICIcXAAAICIgXAAAICIkXAAAICIoXAAAICIsXAAAICIwXAAAICI0XAAAICI4XAAAICI8XAAAICJAXAAAICJEXAAAICJIXAAAICJMXAAAICJQXAAAICJUXAAAICJYXAAAICJcXAAAICJgXAAAICJkXAAAICJoXAAAICJsXAAAICJwXAAAICJ0XAAAICJ4XAAAICJ8XAAAICKAXAAAICKEXAAAICKIXAAAICKMXAAAICKQXAAAICKUXAAAICKYXAAAICKcXAAAICKgXAAAICKkXAAAICKoXAAAICKsXAAAICKwXAAAICK0XAAAICK4XAAAICK8XAAAICLAXAAAICLEXAAAICLIXAAAICLMXAAAICLQXAAAICLUXAAAICLYXAAAICLcXAAAICLgXAAAICLkXAAAICLoXAAAICLsXAAAICLwXAAAICL0XAAAICL4XAAAICL8XAAAICMAXAAAICMEXAAAICMIXAAAICMMXAAAICMQXAAAICMUXAAAICMYXAAAICMcXAAAICMgXAAAICMkXAAAICMoXAAAICMsXAAAICMwXAAAICM0XAAAICM4XAAAICM8XAAAICNAXAAAICNEXAAAICNIXAAAICNMXAAAICNQXAAAICNUXAAAICNYXAAAICNcXAAAICNgXAAAICNkXAAAICNoXAAAICNsXAAAICNwXAAAICN0XAAAICN4XAAAICN8XAAAICOAXAAAICOEXAAAICOIXAAAICOMXAAAICOQXAAAICOUXAAAICOYXAAAICOcXAAAICOgXAAAICOkXAAAICOoXAAAICOsXAAAICOwXAAAICO0XAAAICO4XAAAICO8XAAAICPAXAAAICPEXAAAICPIXAAAICPMXAAAICPQXAAAICPUXAAAICPYXAAAICPcXAAAICPgXAAAICPkXAAAICPoXAAAICPsXAAAICPwXAAAICP0XAAAICP4XAAAICP8XAAAICAAYAAAICAEYAAAICAIYAAAICAMYAAAICAQYAAAICAUYAAAICAYYAAAICAcYAAAICAgYAAAICAkYAAAICAoYAAAICAsYAAAICAwYAAAICA0YAAAICA4YAAAICA8YAAAICBAYAAAICBEYAAAICBIYAAAICBMYAAAICBQYAAAICBUYAAAICBYYAAAICBcYAAAICBgYAAAICBkYAAAICBoYAAAICBsYAAAICBwYAAAICB0YAAAICB4YAAAICB8YAAAICCAYAAAICCEYAAAICCIYAAAICCMYAAAICCQYAAAICCUYAAAICCYYAAAICCcYAAAICCgYAAAICCkYAAAICCoYAAAICCsYAAAICCwYAAAICC0YAAAICC4YAAAICC8YAAAICDAYAAAICDEYAAAICDIYAAAICDMYAAAICDQYAAAICDUYAAAICDYYAAAICDcYAAAICDgYAAAICDkYAAAICDoYAAAICDsYAAAICDwYAAAICD0YAAAICD4YAAAICD8YAAAICEAYAAAICEEYAAAICEIYAAAICEMYAAAICEQYAAAICEUYAAAICEYYAAAICEcYAAAICEgYAAAICEkYAAAICEoYAAAICEsYAAAICEwYAAAICE0YAAAICE4YAAAICE8YAAAICFAYAAAICFEYAAAICFIYAAAICFMYAAAICFQYAAAICFUYAAAICFYYAAAICFcYAAAICFgYAAAICFkYAAAICFoYAAAICFsYAAAICFwYAAAICF0YAAAICF4YAAAICF8YAAAICGAYAAAICGEYAAAICGIYAAAICGMYAAAICGQYAAAICGUYAAAICGYYAAAICGcYAAAICGgYAAAICGkYAAAICGoYAAAICGsYAAAICGwYAAAICG0YAAAICG4YAAAICG8YAAAICHAYAAAICHEYAAAICHIYAAAICHMYAAAICHQYAAAICHUYAAAICHYYAAAICHcYAAAICHgYAAAICHkYAAAICHoYAAAICHsYAAAICHwYAAAICH0YAAAICH4YAAAICH8YAAAICIAYAAAICIEYAAAICIIYAAAICIMYAAAICIQYAAAICIUYAAAICIYYAAAICIcYAAAICIgYAAAICIkYAAAICIoYAAAICIsYAAAICIwYAAAICI0YAAAICI4YAAAICI8YAAAICJAYAAAICJEYAAAICJIYAAAICJMYAAAICJQYAAAICJUYAAAICJYYAAAICJcYAAAICJgYAAAICJkYAAAICJoYAAAICJsYAAAICJwYAAAICJ0YAAAICJ4YAAAICJ8YAAAICKAYAAAICKEYAAAICKIYAAAICKMYAAAICKQYAAAICKUYAAAICKYYAAAICKcYAAAICKgYAAAICKkYAAAICKoYAAAICKsYAAAICKwYAAAICK0YAAAICK4YAAAICK8YAAAICLAYAAAICLEYAAAICLIYAAAICLMYAAAICLQYAAAICLUYAAAICLYYAAAICLcYAAAICLgYAAAICLkYAAAICLoYAAAICLsYAAAICLwYAAAICL0YAAAICL4YAAAICL8YAAAICMAYAAAICMEYAAAICMIYAAAICMMYAAAICMQYAAAICMUYAAAICMYYAAAICMcYAAAICMgYAAAICMkYAAAICMoYAAAICMsYAAAICMwYAAAICM0YAAAICM4YAAAICM8YAAAICNAYAAAICNEYAAAICNIYAAAICNMYAAAICNQYAAAICNUYAAAICNYYAAAICNcYAAAICNgYAAAICNkYAAAICNoYAAAICNsYAAAICNwYAAAICN0YAAAICN4YAAAICN8YAAAICOAYAAAICOEYAAAICOIYAAAICOMYAAAICOQYAAAICOUYAAAICOYYAAAICOcYAAAICOgYAAAICOkYAAAICOoYAAAICOsYAAAICOwYAAAICO0YAAAICO4YAAAICO8YAAAICPAYAAAICPEYAAAICPIYAAAICPMYAAAICPQYAAAICPUYAAAICPYYAAAICPcYAAAICPgYAAAICPkYAAAICPoYAAAICPsYAAAICPwYAAAICP0YAAAICP4YAAAICP8YAAAICAAZAAAICAEZAAAICAIZAAAICAMZAAAICAQZAAAICAUZAAAICAYZAAAICAcZAAAICAgZAAAICAkZAAAICAoZAAAICAsZAAAICAwZAAAICA0ZAAAICA4ZAAAICA8ZAAAICBAZAAAICBEZAAAICBIZAAAICBMZAAAICBQZAAAICBUZAAAICBYZAAAICBcZAAAICBgZAAAICBkZAAAICBoZAAAICBsZAAAICBwZAAAICB0ZAAAICB4ZAAAICB8ZAAAICCAZAAAICCEZAAAICCIZAAAICCMZAAAICCQZAAAICCUZAAAICCYZAAAICCcZAAAICCgZAAAICCkZAAAICCoZAAAICCsZAAAICCwZAAAICC0ZAAAICC4ZAAAICC8ZAAAICDAZAAAICDEZAAAICDIZAAAICDMZAAAICDQZAAAICDUZAAAICDYZAAAICDcZAAAICDgZAAAICDkZAAAICDoZAAAICDsZAAAICDwZAAAICD0ZAAAICD4ZAAAICD8ZAAAICEAZAAAICEEZAAAICEIZAAAICEMZAAAICEQZAAAICEUZAAAICEYZAAAICEcZAAAICEgZAAAICEkZAAAICEoZAAAICEsZAAAICEwZAAAICE0ZAAAICE4ZAAAICE8ZAAAICFAZAAAICFEZAAAICFIZAAAICFMZAAAICFQZAAAICFUZAAAICFYZAAAICFcZAAAICFgZAAAICFkZAAAICFoZAAAICFsZAAAICFwZAAAICF0ZAAAICF4ZAAAICF8ZAAAICGAZAAAICGEZAAAICGIZAAAICGMZAAAICGQZAAAICGUZAAAICGYZAAAICGcZAAAICGgZAAAICGkZAAAICGoZAAAICGsZAAAICGwZAAAICG0ZAAAICG4ZAAAICG8ZAAAICHAZAAAICHEZAAAICHIZAAAICHMZAAAICHQZAAAICHUZAAAICHYZAAAICHcZAAAICHgZAAAICHkZAAAICHoZAAAICHsZAAAICHwZAAAICH0ZAAAICH4ZAAAICH8ZAAAICIAZAAAICIEZAAAICIIZAAAICIMZAAAICIQZAAAICIUZAAAICIYZAAAICIcZAAAICIgZAAAICIkZAAAICIoZAAAICIsZAAAICIwZAAAICI0ZAAAICI4ZAAAICI8ZAAAICJAZAAAICJEZAAAICJIZAAAICJMZAAAICJQZAAAICJUZAAAICJYZAAAICJcZAAAICJgZAAAICJkZAAAICJoZAAAICJsZAAAICJwZAAAICJ0ZAAAICJ4ZAAAICJ8ZAAAICKAZAAAICKEZAAAICKIZAAAICKMZAAAICKQZAAAICKUZAAAICKYZAAAICKcZAAAICKgZAAAICKkZAAAICKoZAAAICKsZAAAICKwZAAAICK0ZAAAICK4ZAAAICK8ZAAAICLAZAAAICLEZAAAICLIZAAAICLMZAAAICLQZAAAICLUZAAAICLYZAAAICLcZAAAICLgZAAAICLkZAAAICLoZAAAICLsZAAAICLwZAAAICL0ZAAAICL4ZAAAICL8ZAAAICMAZAAAICMEZAAAICMIZAAAICMMZAAAICMQZAAAICMUZAAAICMYZAAAICMcZAAAICMgZAAAICMkZAAAICMoZAAAICMsZAAAICMwZAAAICM0ZAAAICM4ZAAAICM8ZAAAICNAZAAAICNEZAAAICNIZAAAICNMZAAAICNQZAAAICNUZAAAICNYZAAAICNcZAAAICNgZAAAICNkZAAAICNoZAAAICNsZAAAICNwZAAAICN0ZAAAICN4ZAAAICN8ZAAAICOAZAAAICOEZAAAICOIZAAAICOMZAAAICOQZAAAICOUZAAAICOYZAAAICOcZAAAICOgZAAAICOkZAAAICOoZAAAICOsZAAAICOwZAAAICO0ZAAAICO4ZAAAICO8ZAAAICPAZAAAICPEZAAAICPIZAAAICPMZAAAICPQZAAAICPUZAAAICPYZAAAICPcZAAAICPgZAAAICPkZAAAICPoZAAAICPsZAAAICPwZAAAICP0ZAAAICP4ZAAAICP8ZAAAICAAaAAAICAEaAAAICAIaAAAICAMaAAAICAQaAAAICAUaAAAICAYaAAAICAcaAAAICAgaAAAICAkaAAAICAoaAAAICAsaAAAICAwaAAAICA0aAAAICA4aAAAICA8aAAAICBAaAAAICBEaAAAICBIaAAAICBMaAAAICBQaAAAICBUaAAAICBYaAAAICBcaAAAICBgaAAAICBkaAAAICBoaAAAICBsaAAAICBwaAAAICB0aAAAICB4aAAAICB8aAAAICCAaAAAICCEaAAAICCIaAAAICCMaAAAICCQaAAAICCUaAAAICCYaAAAICCcaAAAICCgaAAAICCkaAAAICCoaAAAICCsaAAAICCwaAAAICC0aAAAICC4aAAAICC8aAAAICDAaAAAICDEaAAAICDIaAAAICDMaAAAICDQaAAAICDUaAAAICDYaAAAICDcaAAAICDgaAAAICDkaAAAICDoaAAAICDsaAAAICDwaAAAICD0aAAAICD4aAAAICD8aAAAICEAaAAAICEEaAAAICEIaAAAICEMaAAAICEQaAAAICEUaAAAICEYaAAAICEcaAAAICEgaAAAICEkaAAAICEoaAAAICEsaAAAICEwaAAAICE0aAAAICE4aAAAICE8aAAAICFAaAAAICFEaAAAICFIaAAAICFMaAAAICFQaAAAICFUaAAAICFYaAAAICFcaAAAICFgaAAAICFkaAAAICFoaAAAICFsaAAAICFwaAAAICF0aAAAICF4aAAAICF8aAAAICGAaAAAICGEaAAAICGIaAAAICGMaAAAICGQaAAAICGUaAAAICGYaAAAICGcaAAAICGgaAAAICGkaAAAICGoaAAAICGsaAAAICGwaAAAICG0aAAAICG4aAAAICG8aAAAICHAaAAAICHEaAAAICHIaAAAICHMaAAAICHQaAAAICHUaAAAICHYaAAAICHcaAAAICHgaAAAICHkaAAAICHoaAAAICHsaAAAICHwaAAAICH0aAAAICH4aAAAICH8aAAAICIAaAAAICIEaAAAICIIaAAAICIMaAAAICIQaAAAICIUaAAAICIYaAAAICIcaAAAICIgaAAAICIkaAAAICIoaAAAICIsaAAAICIwaAAAICI0aAAAICI4aAAAICI8aAAAICJAaAAAICJEaAAAICJIaAAAICJMaAAAICJQaAAAICJUaAAAICJYaAAAICJcaAAAICJgaAAAICJkaAAAICJoaAAAICJsaAAAICJwaAAAICJ0aAAAICJ4aAAAICJ8aAAAICKAaAAAICKEaAAAICKIaAAAICKMaAAAICKQaAAAICKUaAAAICKYaAAAICKcaAAAICKgaAAAICKkaAAAICKoaAAAICKsaAAAICKwaAAAICK0aAAAICK4aAAAICK8aAAAICLAaAAAICLEaAAAICLIaAAAICLMaAAAICLQaAAAICLUaAAAICLYaAAAICLcaAAAICLgaAAAICLkaAAAICLoaAAAICLsaAAAICLwaAAAICL0aAAAICL4aAAAICL8aAAAICMAaAAAICMEaAAAICMIaAAAICMMaAAAICMQaAAAICMUaAAAICMYaAAAICMcaAAAICMgaAAAICMkaAAAICMoaAAAICMsaAAAICMwaAAAICM0aAAAICM4aAAAICM8aAAAICNAaAAAICNEaAAAICNIaAAAICNMaAAAICNQaAAAICNUaAAAICNYaAAAICNcaAAAICNgaAAAICNkaAAAICNoaAAAICNsaAAAICNwaAAAICN0aAAAICN4aAAAICN8aAAAICOAaAAAICOEaAAAICOIaAAAICOMaAAAICOQaAAAICOUaAAAICOYaAAAICOcaAAAICOgaAAAICOkaAAAICOoaAAAICOsaAAAICOwaAAAICO0aAAAICO4aAAAICO8aAAAICPAaAAAICPEaAAAICPIaAAAICPMaAAAICPQaAAAICPUaAAAICPYaAAAICPcaAAAICPgaAAAICPkaAAAICPoaAAAICPsaAAAICPwaAAAICP0aAAAICP4aAAAICP8aAAAICAAbAAAICAEbAAAICAIbAAAICAMbAAAICAQbAAAICAUbAAAICAYbAAAICAcbAAAICAgbAAAICAkbAAAICAobAAAICAsbAAAICAwbAAAICA0bAAAICA4bAAAICA8bAAAICBAbAAAICBEbAAAICBIbAAAICBMbAAAICBQbAAAICBUbAAAICBYbAAAICBcbAAAICBgbAAAICBkbAAAICBobAAAICBsbAAAICBwbAAAICB0bAAAICB4bAAAICB8bAAAICCAbAAAICCEbAAAICCIbAAAICCMbAAAICCQbAAAICCUbAAAICCYbAAAICCcbAAAICCgbAAAICCkbAAAICCobAAAICCsbAAAICCwbAAAICC0bAAAICC4bAAAICC8bAAAICDAbAAAICDEbAAAICDIbAAAICDMbAAAICDQbAAAICDUbAAAICDYbAAAICDcbAAAICDgbAAAICDkbAAAICDobAAAICDsbAAAICDwbAAAICD0bAAAICD4bAAAICD8bAAAICEAbAAAICEEbAAAICEIbAAAICEMbAAAICEQbAAAICEUbAAAICEYbAAAICEcbAAAICEgbAAAICEkbAAAICEobAAAICEsbAAAICEwbAAAICE0bAAAICE4bAAAICE8bAAAICFAbAAAICFEbAAAICFIbAAAICFMbAAAICFQbAAAICFUbAAAICFYbAAAICFcbAAAICFgbAAAICFkbAAAICFobAAAICFsbAAAICFwbAAAICF0bAAAICF4bAAAICF8bAAAICGAbAAAICGEbAAAICGIbAAAICGMbAAAICGQbAAAICGUbAAAICGYbAAAICGcbAAAICGgbAAAICGkbAAAICGobAAAICGsbAAAICGwbAAAICG0bAAAICG4bAAAICG8bAAAICHAbAAAICHEbAAAICHIbAAAICHMbAAAICHQbAAAICHUbAAAICHYbAAAICHcbAAAICHgbAAAICHkbAAAICHobAAAICHsbAAAICHwbAAAICH0bAAAICH4bAAAICH8bAAAICIAbAAAICIEbAAAICIIbAAAICIMbAAAICIQbAAAICIUbAAAICIYbAAAICIcbAAAICIgbAAAICIkbAAAICIobAAAICIsbAAAICIwbAAAICI0bAAAICI4bAAAICI8bAAAICJAbAAAICJEbAAAICJIbAAAICJMbAAAICJQbAAAICJUbAAAICJYbAAAICJcbAAAICJgbAAAICJkbAAAICJobAAAICJsbAAAICJwbAAAICJ0bAAAICJ4bAAAICJ8bAAAICKAbAAAICKEbAAAICKIbAAAICKMbAAAICKQbAAAICKUbAAAICKYbAAAICKcbAAAICKgbAAAICKkbAAAICKobAAAICKsbAAAICKwbAAAICK0bAAAICK4bAAAICK8bAAAICLAbAAAICLEbAAAICLIbAAAICLMbAAAICLQbAAAICLUbAAAICLYbAAAICLcbAAAICLgbAAAICLkbAAAICLobAAAICLsbAAAICLwbAAAICL0bAAAICL4bAAAICL8bAAAICMAbAAAICMEbAAAICMIbAAAICMMbAAAICMQbAAAICMUbAAAICMYbAAAICMcbAAAICMgbAAAICMkbAAAICMobAAAICMsbAAAICMwbAAAICM0bAAAICM4bAAAICM8bAAAICNAbAAAICNEbAAAICNIbAAAICNMbAAAICNQbAAAICNUbAAAICNYbAAAICNcbAAAICNgbAAAICNkbAAAICNobAAAICNsbAAAICNwbAAAICN0bAAAICN4bAAAICN8bAAAICOAbAAAICOEbAAAICOIbAAAICOMbAAAICOQbAAAICOUbAAAICOYbAAAICOcbAAAICOgbAAAICOkbAAAICOobAAAICOsbAAAICOwbAAAICO0bAAAICO4bAAAICO8bAAAICPAbAAAICPEbAAAICPIbAAAICPMbAAAICPQbAAAICPUbAAAICPYbAAAICPcbAAAICPgbAAAICPkbAAAICPobAAAICPsbAAAICPwbAAAICP0bAAAICP4bAAAICP8bAAAICAAcAAAICAEcAAAICAIcAAAICAMcAAAICAQcAAAICAUcAAAICAYcAAAICAccAAAICAgcAAAICAkcAAAICAocAAAICAscAAAICAwcAAAICA0cAAAICA4cAAAICA8cAAAICBAcAAAICBEcAAAICBIcAAAICBMcAAAICBQcAAAICBUcAAAICBYcAAAICBccAAAICBgcAAAICBkcAAAICBocAAAICBscAAAICBwcAAAICB0cAAAICB4cAAAICB8cAAAICCAcAAAICCEcAAAICCIcAAAICCMcAAAICCQcAAAICCUcAAAICCYcAAAICCccAAAICCgcAAAICCkcAAAICCocAAAICCscAAAICCwcAAAICC0cAAAICC4cAAAICC8cAAAICDAcAAAICDEcAAAICDIcAAAICDMcAAAICDQcAAAICDUcAAAICDYcAAAICDccAAAICDgcAAAICDkcAAAICDocAAAICDscAAAICDwcAAAICD0cAAAICD4cAAAICD8cAAAICEAcAAAICEEcAAAICEIcAAAICEMcAAAICEQcAAAICEUcAAAICEYcAAAICEccAAAICEgcAAAICEkcAAAICEocAAAICEscAAAICEwcAAAICE0cAAAICE4cAAAICE8cAAAICFAcAAAICFEcAAAICFIcAAAICFMcAAAICFQcAAAICFUcAAAICFYcAAAICFccAAAICFgcAAAICFkcAAAICFocAAAICFscAAAICFwcAAAICF0cAAAICF4cAAAICF8cAAAICGAcAAAICGEcAAAICGIcAAAICGMcAAAICGQcAAAICGUcAAAICGYcAAAICGccAAAICGgcAAAICGkcAAAICGocAAAICGscAAAICGwcAAAICG0cAAAICG4cAAAICG8cAAAICHAcAAAICHEcAAAICHIcAAAICHMcAAAICHQcAAAICHUcAAAICHYcAAAICHccAAAICHgcAAAICHkcAAAICHocAAAICHscAAAICHwcAAAICH0cAAAICH4cAAAICH8cAAAICIAcAAAICIEcAAAICIIcAAAICIMcAAAICIQcAAAICIUcAAAICIYcAAAICIccAAAICIgcAAAICIkcAAAICIocAAAICIscAAAICIwcAAAICI0cAAAICI4cAAAICI8cAAAICJAcAAAICJEcAAAICJIcAAAICJMcAAAICJQcAAAICJUcAAAICJYcAAAICJccAAAICJgcAAAICJkcAAAICJocAAAICJscAAAICJwcAAAICJ0cAAAICJ4cAAAICJ8cAAAICKAcAAAICKEcAAAICKIcAAAICKMcAAAICKQcAAAICKUcAAAICKYcAAAICKccAAAICKgcAAAICKkcAAAICKocAAAICKscAAAICKwcAAAICK0cAAAICK4cAAAICK8cAAAICLAcAAAICLEcAAAICLIcAAAICLMcAAAICLQcAAAICLUcAAAICLYcAAAICLccAAAICLgcAAAICLkcAAAICLocAAAICLscAAAICLwcAAAICL0cAAAICL4cAAAICL8cAAAICMAcAAAICMEcAAAICMIcAAAICMMcAAAICMQcAAAICMUcAAAICMYcAAAICMccAAAICMgcAAAICMkcAAAICMocAAAICMscAAAICMwcAAAICM0cAAAICM4cAAAICM8cAAAICNAcAAAICNEcAAAICNIcAAAICNMcAAAICNQcAAAICNUcAAAICNYcAAAICNccAAAICNgcAAAICNkcAAAICNocAAAICNscAAAICNwcAAAICN0cAAAICN4cAAAICN8cAAAICOAcAAAICOEcAAAICOIcAAAICOMcAAAICOQcAAAICOUcAAAICOYcAAAICOccAAAICOgcAAAICOkcAAAICOocAAAICOscAAAICOwcAAAICO0cAAAICO4cAAAICO8cAAAICPAcAAAICPEcAAAICPIcAAAICPMcAAAICPQcAAAICPUcAAAICPYcAAAICPccAAAICPgcAAAICPkcAAAICPocAAAICPscAAAICPwcAAAICP0cAAAICP4cAAAICP8cAAAICAAdAAAICAEdAAAICAIdAAAICAMdAAAICAQdAAAICAUdAAAICAYdAAAICAcdAAAICAgdAAAICAkdAAAICAodAAAICAsdAAAICAwdAAAICA0dAAAICA4dAAAICA8dAAAICBAdAAAICBEdAAAICBIdAAAICBMdAAAICBQdAAAICBUdAAAICBYdAAAICBcdAAAICBgdAAAICBkdAAAICBodAAAICBsdAAAICBwdAAAICB0dAAAICB4dAAAICB8dAAAICCAdAAAICCEdAAAICCIdAAAICCMdAAAICCQdAAAICCUdAAAICCYdAAAICCcdAAAICCgdAAAICCkdAAAICCodAAAICCsdAAAICCwdAAAICC0dAAAICC4dAAAICC8dAAAICDAdAAAICDEdAAAICDIdAAAICDMdAAAICDQdAAAICDUdAAAICDYdAAAICDcdAAAICDgdAAAICDkdAAAICDodAAAICDsdAAAICDwdAAAICD0dAAAICD4dAAAICD8dAAAICEAdAAAICEEdAAAICEIdAAAICEMdAAAICEQdAAAICEUdAAAICEYdAAAICEcdAAAICEgdAAAICEkdAAAICEodAAAICEsdAAAICEwdAAAICE0dAAAICE4dAAAICE8dAAAICFAdAAAICFEdAAAICFIdAAAICFMdAAAICFQdAAAICFUdAAAICFYdAAAICFcdAAAICFgdAAAICFkdAAAICFodAAAICFsdAAAICFwdAAAICF0dAAAICF4dAAAICF8dAAAICGAdAAAICGEdAAAICGIdAAAICGMdAAAICGQdAAAICGUdAAAICGYdAAAICGcdAAAICGgdAAAICGkdAAAICGodAAAICGsdAAAICGwdAAAICG0dAAAICG4dAAAICG8dAAAICHAdAAAICHEdAAAICHIdAAAICHMdAAAICHQdAAAICHUdAAAICHYdAAAICHcdAAAICHgdAAAICHkdAAAICHodAAAICHsdAAAICHwdAAAICH0dAAAICH4dAAAICH8dAAAICIAdAAAICIEdAAAICIIdAAAICIMdAAAICIQdAAAICIUdAAAICIYdAAAICIcdAAAICIgdAAAICIkdAAAICIodAAAICIsdAAAICIwdAAAICI0dAAAICI4dAAAICI8dAAAICJAdAAAICJEdAAAICJIdAAAICJMdAAAICJQdAAAICJUdAAAICJYdAAAICJcdAAAICJgdAAAICJkdAAAICJodAAAICJsdAAAICJwdAAAICJ0dAAAICJ4dAAAICJ8dAAAICKAdAAAICKEdAAAICKIdAAAICKMdAAAICKQdAAAICKUdAAAICKYdAAAICKcdAAAICKgdAAAICKkdAAAICKodAAAICKsdAAAICKwdAAAICK0dAAAICK4dAAAICK8dAAAICLAdAAAICLEdAAAICLIdAAAICLMdAAAICLQdAAAICLUdAAAICLYdAAAICLcdAAAICLgdAAAICLkdAAAICLodAAAICLsdAAAICLwdAAAICL0dAAAICL4dAAAICL8dAAAICMAdAAAICMEdAAAICMIdAAAICMMdAAAICMQdAAAICMUdAAAICMYdAAAICMcdAAAICMgdAAAICMkdAAAICModAAAICMsdAAAICMwdAAAICM0dAAAICM4dAAAICM8dAAAICNAdAAAICNEdAAAICNIdAAAICNMdAAAICNQdAAAICNUdAAAICNYdAAAICNcdAAAICNgdAAAICNkdAAAICNodAAAICNsdAAAICNwdAAAICN0dAAAICN4dAAAICN8dAAAICOAdAAAICOEdAAAICOIdAAAICOMdAAAICOQdAAAICOUdAAAICOYdAAAICOcdAAAICOgdAAAICOkdAAAICOodAAAICOsdAAAICOwdAAAICO0dAAAICO4dAAAICO8dAAAICPAdAAAICPEdAAAICPIdAAAICPMdAAAICPQdAAAICPUdAAAICPYdAAAICPcdAAAICPgdAAAICPkdAAAICPodAAAICPsdAAAICPwdAAAICP0dAAAICP4dAAAICP8dAAAICAAeAAAICAEeAAAICAIeAAAICAMeAAAICAQeAAAICAUeAAAICAYeAAAICAceAAAICAgeAAAICAkeAAAICAoeAAAICAseAAAICAweAAAICA0eAAAICA4eAAAICA8eAAAICBAeAAAICBEeAAAICBIeAAAICBMeAAAICBQeAAAICBUeAAAICBYeAAAICBceAAAICBgeAAAICBkeAAAICBoeAAAICBseAAAICBweAAAICB0eAAAICB4eAAAICB8eAAAICCAeAAAICCEeAAAICCIeAAAICCMeAAAICCQeAAAICCUeAAAICCYeAAAICCceAAAICCgeAAAICCkeAAAICCoeAAAICCseAAAICCweAAAICC0eAAAICC4eAAAICC8eAAAICDAeAAAICDEeAAAICDIeAAAICDMeAAAICDQeAAAICDUeAAAICDYeAAAICDceAAAICDgeAAAICDkeAAAICDoeAAAICDseAAAICDweAAAICD0eAAAICD4eAAAICD8eAAAICEAeAAAICEEeAAAICEIeAAAICEMeAAAICEQeAAAICEUeAAAICEYeAAAICEceAAAICEgeAAAICEkeAAAICEoeAAAICEseAAAICEweAAAICE0eAAAICE4eAAAICE8eAAAICFAeAAAICFEeAAAICFIeAAAICFMeAAAICFQeAAAICFUeAAAICFYeAAAICFceAAAICFgeAAAICFkeAAAICFoeAAAICFseAAAICFweAAAICF0eAAAICF4eAAAICF8eAAAICGAeAAAICGEeAAAICGIeAAAICGMeAAAICGQeAAAICGUeAAAICGYeAAAICGceAAAICGgeAAAICGkeAAAICGoeAAAICGseAAAICGweAAAICG0eAAAICG4eAAAICG8eAAAICHAeAAAICHEeAAAICHIeAAAICHMeAAAICHQeAAAICHUeAAAICHYeAAAICHceAAAICHgeAAAICHkeAAAICHoeAAAICHseAAAICHweAAAICH0eAAAICH4eAAAICH8eAAAICIAeAAAICIEeAAAICIIeAAAICIMeAAAICIQeAAAICIUeAAAICIYeAAAICIceAAAICIgeAAAICIkeAAAICIoeAAAICIseAAAICIweAAAICI0eAAAICI4eAAAICI8eAAAICJAeAAAICJEeAAAICJIeAAAICJMeAAAICJQeAAAICJUeAAAICJYeAAAICJceAAAICJgeAAAICJkeAAAICJoeAAAICJseAAAICJweAAAICJ0eAAAICJ4eAAAICJ8eAAAICKAeAAAICKEeAAAICKIeAAAICKMeAAAICKQeAAAICKUeAAAICKYeAAAICKceAAAICKgeAAAICKkeAAAICKoeAAAICKseAAAICKweAAAICK0eAAAICK4eAAAICK8eAAAICLAeAAAICLEeAAAICLIeAAAICLMeAAAICLQeAAAICLUeAAAICLYeAAAICLceAAAICLgeAAAICLkeAAAICLoeAAAICLseAAAICLweAAAICL0eAAAICL4eAAAICL8eAAAICMAeAAAICMEeAAAICMIeAAAICMMeAAAICMQeAAAICMUeAAAICMYeAAAICMceAAAICMgeAAAICMkeAAAICMoeAAAICMseAAAICMweAAAICM0eAAAICM4eAAAICM8eAAAICNAeAAAICNEeAAAICNIeAAAICNMeAAAICNQeAAAICNUeAAAICNYeAAAICNceAAAICNgeAAAICNkeAAAICNoeAAAICNseAAAICNweAAAICN0eAAAICN4eAAAICN8eAAAICOAeAAAICOEeAAAICOIeAAAICOMeAAAICOQeAAAICOUeAAAICOYeAAAICOceAAAICOgeAAAICOkeAAAICOoeAAAICOseAAAICOweAAAICO0eAAAICO4eAAAICO8eAAAICPAeAAAICPEeAAAICPIeAAAICPMeAAAICPQeAAAICPUeAAAICPYeAAAICPceAAAICPgeAAAICPkeAAAICPoeAAAICPseAAAICPweAAAICP0eAAAICP4eAAAICP8eAAAICAAfAAAICAEfAAAICAIfAAAICAMfAAAICAQfAAAICAUfAAAICAYfAAAICAcfAAAICAgfAAAICAkfAAAICAofAAAICAsfAAAICAwfAAAICA0fAAAICA4fAAAICA8fAAAICBAfAAAICBEfAAAICBIfAAAICBMfAAAICBQfAAAICBUfAAAICBYfAAAICBcfAAAICBgfAAAICBkfAAAICBofAAAICBsfAAAICBwfAAAICB0fAAAICB4fAAAICB8fAAAICCAfAAAICCEfAAAICCIfAAAICCMfAAAICCQfAAAICCUfAAAICCYfAAAICCcfAAAICCgfAAAICCkfAAAICCofAAAICCsfAAAICCwfAAAICC0fAAAICC4fAAAICC8fAAAICDAfAAAICDEfAAAICDIfAAAICDMfAAAICDQfAAAICDUfAAAICDYfAAAICDcfAAAICDgfAAAICDkfAAAICDofAAAICDsfAAAICDwfAAAICD0fAAAICD4fAAAICD8fAAAICEAfAAAICEEfAAAICEIfAAAICEMfAAAICEQfAAAICEUfAAAICEYfAAAICEcfAAAICEgfAAAICEkfAAAICEofAAAICEsfAAAICEwfAAAICE0fAAAICE4fAAAICE8fAAAICFAfAAAICFEfAAAICFIfAAAICFMfAAAICFQfAAAICFUfAAAICFYfAAAICFcfAAAICFgfAAAICFkfAAAICFofAAAICFsfAAAICFwfAAAICF0fAAAICF4fAAAICF8fAAAICGAfAAAICGEfAAAICGIfAAAICGMfAAAICGQfAAAICGUfAAAICGYfAAAICGcfAAAICGgfAAAICGkfAAAICGofAAAICGsfAAAICGwfAAAICG0fAAAICG4fAAAICG8fAAAICHAfAAAICHEfAAAICHIfAAAICHMfAAAICHQfAAAICHUfAAAICHYfAAAICHcfAAAICHgfAAAICHkfAAAICHofAAAICHsfAAAICHwfAAAICH0fAAAICH4fAAAICH8fAAAICIAfAAAICIEfAAAICIIfAAAICIMfAAAICIQfAAAICIUfAAAICIYfAAAICIcfAAAICIgfAAAICIkfAAAICIofAAAICIsfAAAICIwfAAAICI0fAAAICI4fAAAICI8fAAAICJAfAAAICJEfAAAICJIfAAAICJMfAAAICJQfAAAICJUfAAAICJYfAAAICJcfAAAICJgfAAAICJkfAAAICJofAAAICJsfAAAICJwfAAAICJ0fAAAICJ4fAAAICJ8fAAAICKAfAAAICKEfAAAICKIfAAAICKMfAAAICKQfAAAICKUfAAAICKYfAAAICKcfAAAICKgfAAAICKkfAAAICKofAAAICKsfAAAICKwfAAAICK0fAAAICK4fAAAICK8fAAAICLAfAAAICLEfAAAICLIfAAAICLMfAAAICLQfAAAICLUfAAAICLYfAAAICLcfAAAICLgfAAAICLkfAAAICLofAAAICLsfAAAICLwfAAAICL0fAAAICL4fAAAICL8fAAAICMAfAAAICMEfAAAICMIfAAAICMMfAAAICMQfAAAICMUfAAAICMYfAAAICMcfAAAICMgfAAAICMkfAAAICMofAAAICMsfAAAICMwfAAAICM0fAAAICM4fAAAICM8fAAAICNAfAAAICNEfAAAICNIfAAAICNMfAAAICNQfAAAICNUfAAAICNYfAAAICNcfAAAICNgfAAAICNkfAAAICNofAAAICNsfAAAICNwfAAAICN0fAAAICN4fAAAICN8fAAAICOAfAAAICOEfAAAICOIfAAAICOMfAAAICOQfAAAICOUfAAAICOYfAAAICOcfAAAICOgfAAAICOkfAAAICOofAAAICOsfAAAICOwfAAAICO0fAAAICO4fAAAICO8fAAAICPAfAAAICPEfAAAICPIfAAAICPMfAAAICPQfAAAICPUfAAAICPYfAAAICPcfAAAICPgfAAAICPkfAAAICPofAAAICPsfAAAICPwfAAAICP0fAAAICP4fAAAICP8fAAAICAAgAAAICAEgAAAICAIgAAAICAMgAAAICAQgAAAICAUgAAAICAYgAAAICAcgAAAICAggAAAICAkgAAAICAogAAAICAsgAAAICAwgAAAICA0gAAAICA4gAAAICA8gAAAICBAgAAAICBEgAAAICBIgAAAICBMgAAAICBQgAAAICBUgAAAICBYgAAAICBcgAAAICBggAAAICBkgAAAICBogAAAICBsgAAAICBwgAAAICB0gAAAICB4gAAAICB8gAAAICCAgAAAICCEgAAAICCIgAAAICCMgAAAICCQgAAAICCUgAAAICCYgAAAICCcgAAAICCggAAAICCkgAAAICCogAAAICCsgAAAICCwgAAAICC0gAAAICC4gAAAICC8gAAAICDAgAAAICDEgAAAICDIgAAAICDMgAAAICDQgAAAICDUgAAAICDYgAAAICDcgAAAICDggAAAICDkgAAAICDogAAAICDsgAAAICDwgAAAICD0gAAAICD4gAAAICD8gAAAICEAgAAAICEEgAAAICEIgAAAICEMgAAAICEQgAAAICEUgAAAICEYgAAAICEcgAAAICEggAAAICEkgAAAICEogAAAICEsgAAAICEwgAAAICE0gAAAICE4gAAAICE8gAAAICFAgAAAICFEgAAAICFIgAAAICFMgAAAICFQgAAAICFUgAAAICFYgAAAICFcgAAAICFggAAAICFkgAAAICFogAAAICFsgAAAICFwgAAAICF0gAAAICF4gAAAICF8gAAAICGAgAAAICGEgAAAICGIgAAAICGMgAAAICGQgAAAICGUgAAAICGYgAAAICGcgAAAICGggAAAICGkgAAAICGogAAAICGsgAAAICGwgAAAICG0gAAAICG4gAAAICG8gAAAICHAgAAAICHEgAAAICHIgAAAICHMgAAAICHQgAAAICHUgAAAICHYgAAAICHcgAAAICHggAAAICHkgAAAICHogAAAICHsgAAAICHwgAAAICH0gAAAICH4gAAAICH8gAAAICIAgAAAICIEgAAAICIIgAAAICIMgAAAICIQgAAAICIUgAAAICIYgAAAICIcgAAAICIggAAAICIkgAAAICIogAAAICIsgAAAICIwgAAAICI0gAAAICI4gAAAICI8gAAAICJAgAAAICJEgAAAICJIgAAAICJMgAAAICJQgAAAICJUgAAAICJYgAAAICJcgAAAICJggAAAICJkgAAAICJogAAAICJsgAAAICJwgAAAICJ0gAAAICJ4gAAAICJ8gAAAICKAgAAAICKEgAAAICKIgAAAICKMgAAAICKQgAAAICKUgAAAICKYgAAAICKcgAAAICKggAAAICKkgAAAICKogAAAICKsgAAAICKwgAAAICK0gAAAICK4gAAAICK8gAAAICLAgAAAICLEgAAAICLIgAAAICLMgAAAICLQgAAAICLUgAAAICLYgAAAICLcgAAAICLggAAAICLkgAAAICLogAAAICLsgAAAICLwgAAAICL0gAAAICL4gAAAICL8gAAAICMAgAAAICMEgAAAICMIgAAAICMMgAAAICMQgAAAICMUgAAAICMYgAAAICMcgAAAICMggAAAICMkgAAAICMogAAAICMsgAAAICMwgAAAICM0gAAAICM4gAAAICM8gAAAICNAgAAAICNEgAAAICNIgAAAICNMgAAAICNQgAAAICNUgAAAICNYgAAAICNcgAAAICNggAAAICNkgAAAICNogAAAICNsgAAAICNwgAAAICN0gAAAICN4gAAAICN8gAAAICOAgAAAICOEgAAAICOIgAAAICOMgAAAICOQgAAAICOUgAAAICOYgAAAICOcgAAAICOggAAAICOkgAAAICOogAAAICOsgAAAICOwgAAAICO0gAAAICO4gAAAICO8gAAAICPAgAAAICPEgAAAICPIgAAAICPMgAAAICPQgAAAICPUgAAAICPYgAAAICPcgAAAICPggAAAICPkgAAAICPogAAAICPsgAAAICPwgAAAICP0gAAAICP4gAAAICP8gAAAICAAhAAAICAEhAAAICAIhAAAICAMhAAAICAQhAAAICAUhAAAICAYhAAAICAchAAAICAghAAAICAkhAAAICAohAAAICAshAAAICAwhAAAICA0hAAAICA4hAAAICA8hAAAICBAhAAAICBEhAAAICBIhAAAICBMhAAAICBQhAAAICBUhAAAICBYhAAAICBchAAAICBghAAAICBkhAAAICBohAAAICBshAAAICBwhAAAICB0hAAAICB4hAAAICB8hAAAICCAhAAAICCEhAAAICCIhAAAICCMhAAAICCQhAAAICCUhAAAICCYhAAAICCchAAAICCghAAAICCkhAAAICCohAAAICCshAAAICCwhAAAICC0hAAAICC4hAAAICC8hAAAICDAhAAAICDEhAAAICDIhAAAICDMhAAAICDQhAAAICDUhAAAICDYhAAAICDchAAAICDghAAAICDkhAAAICDohAAAICDshAAAICDwhAAAICD0hAAAICD4hAAAICD8hAAAICEAhAAAICEEhAAAICEIhAAAICEMhAAAICEQhAAAICEUhAAAICEYhAAAICEchAAAICEghAAAICEkhAAAICEohAAAICEshAAAICEwhAAAICE0hAAAICE4hAAAICE8hAAAICFAhAAAICFEhAAAICFIhAAAICFMhAAAICFQhAAAICFUhAAAICFYhAAAICFchAAAICFghAAAICFkhAAAICFohAAAICFshAAAICFwhAAAICF0hAAAICF4hAAAICF8hAAAICGAhAAAICGEhAAAICGIhAAAICGMhAAAICGQhAAAICGUhAAAICGYhAAAICGchAAAICGghAAAICGkhAAAICGohAAAICGshAAAICGwhAAAICG0hAAAICG4hAAAICG8hAAAICHAhAAAICHEhAAAICHIhAAAICHMhAAAICHQhAAAICHUhAAAICHYhAAAICHchAAAICHghAAAICHkhAAAICHohAAAICHshAAAICHwhAAAICH0hAAAICH4hAAAICH8hAAAICIAhAAAICIEhAAAICIIhAAAICIMhAAAICIQhAAAICIUhAAAICIYhAAAICIchAAAICIghAAAICIkhAAAICIohAAAICIshAAAICIwhAAAICI0hAAAICI4hAAAICI8hAAAICJAhAAAICJEhAAAICJIhAAAICJMhAAAICJQhAAAICJUhAAAICJYhAAAICJchAAAICJghAAAICJkhAAAICJohAAAICJshAAAICJwhAAAICJ0hAAAICJ4hAAAICJ8hAAAICKAhAAAICKEhAAAICKIhAAAICKMhAAAICKQhAAAICKUhAAAICKYhAAAICKchAAAICKghAAAICKkhAAAICKohAAAICKshAAAICKwhAAAICK0hAAAICK4hAAAICK8hAAAICLAhAAAICLEhAAAICLIhAAAICLMhAAAICLQhAAAICLUhAAAICLYhAAAICLchAAAICLghAAAICLkhAAAICLohAAAICLshAAAICLwhAAAICL0hAAAICL4hAAAICL8hAAAICMAhAAAICMEhAAAICMIhAAAICMMhAAAICMQhAAAICMUhAAAICMYhAAAICMchAAAICMghAAAICMkhAAAICMohAAAICMshAAAICMwhAAAICM0hAAAICM4hAAAICM8hAAAICNAhAAAICNEhAAAICNIhAAAICNMhAAAICNQhAAAICNUhAAAICNYhAAAICNchAAAICNghAAAICNkhAAAICNohAAAICNshAAAICNwhAAAICN0hAAAICN4hAAAICN8hAAAICOAhAAAICOEhAAAICOIhAAAICOMhAAAICOQhAAAICOUhAAAICOYhAAAICOchAAAICOghAAAICOkhAAAICOohAAAICOshAAAICOwhAAAICO0hAAAICO4hAAAICO8hAAAICPAhAAAICPEhAAAICPIhAAAICPMhAAAICPQhAAAICPUhAAAICPYhAAAICPchAAAICPghAAAICPkhAAAICPohAAAICPshAAAICPwhAAAICP0hAAAICP4hAAAICP8hAAAICAAiAAAICAEiAAAICAIiAAAICAMiAAAICAQiAAAICAUiAAAICAYiAAAICAciAAAICAgiAAAICAkiAAAICAoiAAAICAsiAAAICAwiAAAICA0iAAAICA4iAAAICA8iAAAICBAiAAAICBEiAAAICBIiAAAICBMiAAAICBQiAAAICBUiAAAICBYiAAAICBciAAAICBgiAAAICBkiAAAICBoiAAAICBsiAAAICBwiAAAICB0iAAAICB4iAAAICB8iAAAICCAiAAAICCEiAAAICCIiAAAICCMiAAAICCQiAAAICCUiAAAICCYiAAAICCciAAAICCgiAAAICCkiAAAICCoiAAAICCsiAAAICCwiAAAICC0iAAAICC4iAAAICC8iAAAICDAiAAAICDEiAAAICDIiAAAICDMiAAAICDQiAAAICDUiAAAICDYiAAAICDciAAAICDgiAAAICDkiAAAICDoiAAAICDsiAAAICDwiAAAICD0iAAAICD4iAAAICD8iAAAICEAiAAAICEEiAAAICEIiAAAICEMiAAAICEQiAAAICEUiAAAICEYiAAAICEciAAAICEgiAAAICEkiAAAICEoiAAAICEsiAAAICEwiAAAICE0iAAAICE4iAAAICE8iAAAICFAiAAAICFEiAAAICFIiAAAICFMiAAAICFQiAAAICFUiAAAICFYiAAAICFciAAAICFgiAAAICFkiAAAICFoiAAAICFsiAAAICFwiAAAICF0iAAAICF4iAAAICF8iAAAICGAiAAAICGEiAAAICGIiAAAICGMiAAAICGQiAAAICGUiAAAICGYiAAAICGciAAAICGgiAAAICGkiAAAICGoiAAAICGsiAAAICGwiAAAICG0iAAAICG4iAAAICG8iAAAICHAiAAAICHEiAAAICHIiAAAICHMiAAAICHQiAAAICHUiAAAICHYiAAAICHciAAAICHgiAAAICHkiAAAICHoiAAAICHsiAAAICHwiAAAICH0iAAAICH4iAAAICH8iAAAICIAiAAAICIEiAAAICIIiAAAICIMiAAAICIQiAAAICIUiAAAICIYiAAAICIciAAAICIgiAAAICIkiAAAICIoiAAAICIsiAAAICIwiAAAICI0iAAAICI4iAAAICI8iAAAICJAiAAAICJEiAAAICJIiAAAICJMiAAAICJQiAAAICJUiAAAICJYiAAAICJciAAAICJgiAAAICJkiAAAICJoiAAAICJsiAAAICJwiAAAICJ0iAAAICJ4iAAAICJ8iAAAICKAiAAAICKEiAAAICKIiAAAICKMiAAAICKQiAAAICKUiAAAICKYiAAAICKciAAAICKgiAAAICKkiAAAICKoiAAAICKsiAAAICKwiAAAICK0iAAAICK4iAAAICK8iAAAICLAiAAAICLEiAAAICLIiAAAICLMiAAAICLQiAAAICLUiAAAICLYiAAAICLciAAAICLgiAAAICLkiAAAICLoiAAAICLsiAAAICLwiAAAICL0iAAAICL4iAAAICL8iAAAICMAiAAAICMEiAAAICMIiAAAICMMiAAAICMQiAAAICMUiAAAICMYiAAAICMciAAAICMgiAAAICMkiAAAICMoiAAAICMsiAAAICMwiAAAICM0iAAAICM4iAAAICM8iAAAICNAiAAAICNEiAAAICNIiAAAICNMiAAAICNQiAAAICNUiAAAICNYiAAAICNciAAAICNgiAAAICNkiAAAICNoiAAAICNsiAAAICNwiAAAICN0iAAAICN4iAAAICN8iAAAICOAiAAAICOEiAAAICOIiAAAICOMiAAAICOQiAAAICOUiAAAICOYiAAAICOciAAAICOgiAAAICOkiAAAICOoiAAAICOsiAAAICOwiAAAICO0iAAAICO4iAAAICO8iAAAICPAiAAAICPEiAAAICPIiAAAICPMiAAAICPQiAAAICPUiAAAICPYiAAAICPciAAAICPgiAAAICPkiAAAICPoiAAAICPsiAAAICPwiAAAICP0iAAAICP4iAAAICP8iAAAICAAjAAAICAEjAAAICAIjAAAICAMjAAAICAQjAAAICAUjAAAICAYjAAAICAcjAAAICAgjAAAICAkjAAAICAojAAAICAsjAAAICAwjAAAICA0jAAAICA4jAAAICA8jAAAICBAjAAAICBEjAAAICBIjAAAICBMjAAAICBQjAAAICBUjAAAICBYjAAAICBcjAAAICBgjAAAICBkjAAAICBojAAAICBsjAAAICBwjAAAICB0jAAAICB4jAAAICB8jAAAICCAjAAAICCEjAAAICCIjAAAICCMjAAAICCQjAAAICCUjAAAICCYjAAAICCcjAAAICCgjAAAICCkjAAAICCojAAAICCsjAAAICCwjAAAICC0jAAAICC4jAAAICC8jAAAICDAjAAAICDEjAAAICDIjAAAICDMjAAAICDQjAAAICDUjAAAICDYjAAAICDcjAAAICDgjAAAICDkjAAAICDojAAAICDsjAAAICDwjAAAICD0jAAAICD4jAAAICD8jAAAICEAjAAAICEEjAAAICEIjAAAICEMjAAAICEQjAAAICEUjAAAICEYjAAAICEcjAAAICEgjAAAICEkjAAAICEojAAAICEsjAAAICEwjAAAICE0jAAAICE4jAAAICE8jAAAICFAjAAAICFEjAAAICFIjAAAICFMjAAAICFQjAAAICFUjAAAICFYjAAAICFcjAAAICFgjAAAICFkjAAAICFojAAAICFsjAAAICFwjAAAICF0jAAAICF4jAAAICF8jAAAICGAjAAAICGEjAAAICGIjAAAICGMjAAAICGQjAAAICGUjAAAICGYjAAAICGcjAAAICGgjAAAICGkjAAAICGojAAAICGsjAAAICGwjAAAICG0jAAAICG4jAAAICG8jAAAICHAjAAAICHEjAAAICHIjAAAICHMjAAAICHQjAAAICHUjAAAICHYjAAAICHcjAAAICHgjAAAICHkjAAAICHojAAAICHsjAAAICHwjAAAICH0jAAAICH4jAAAICH8jAAAICIAjAAAICIEjAAAICIIjAAAICIMjAAAICIQjAAAICIUjAAAICIYjAAAICIcjAAAICIgjAAAICIkjAAAICIojAAAICIsjAAAICIwjAAAICI0jAAAICI4jAAAICI8jAAAICJAjAAAICJEjAAAICJIjAAAICJMjAAAICJQjAAAICJUjAAAICJYjAAAICJcjAAAICJgjAAAICJkjAAAICJojAAAICJsjAAAICJwjAAAICJ0jAAAICJ4jAAAICJ8jAAAICKAjAAAICKEjAAAICKIjAAAICKMjAAAICKQjAAAICKUjAAAICKYjAAAICKcjAAAICKgjAAAICKkjAAAICKojAAAICKsjAAAICKwjAAAICK0jAAAICK4jAAAICK8jAAAICLAjAAAICLEjAAAICLIjAAAICLMjAAAICLQjAAAICLUjAAAICLYjAAAICLcjAAAICLgjAAAICLkjAAAICLojAAAICLsjAAAICLwjAAAICL0jAAAICL4jAAAICL8jAAAICMAjAAAICMEjAAAICMIjAAAICMMjAAAICMQjAAAICMUjAAAICMYjAAAICMcjAAAICMgjAAAICMkjAAAICMojAAAICMsjAAAICMwjAAAICM0jAAAICM4jAAAICM8jAAAICNAjAAAICNEjAAAICNIjAAAICNMjAAAICNQjAAAICNUjAAAICNYjAAAICNcjAAAICNgjAAAICNkjAAAICNojAAAICNsjAAAICNwjAAAICN0jAAAICN4jAAAICN8jAAAICOAjAAAICOEjAAAICOIjAAAICOMjAAAICOQjAAAICOUjAAAICOYjAAAICOcjAAAICOgjAAAICOkjAAAICOojAAAICOsjAAAICOwjAAAICO0jAAAICO4jAAAICO8jAAAICPAjAAAICPEjAAAICPIjAAAICPMjAAAICPQjAAAICPUjAAAICPYjAAAICPcjAAAICPgjAAAICPkjAAAICPojAAAICPsjAAAICPwjAAAICP0jAAAICP4jAAAICP8jAAAICAAkAAAICAEkAAAICAIkAAAICAMkAAAICAQkAAAICAUkAAAICAYkAAAICAckAAAICAgkAAAICAkkAAAICAokAAAICAskAAAICAwkAAAICA0kAAAICA4kAAAICA8kAAAICBAkAAAICBEkAAAICBIkAAAICBMkAAAICBQkAAAICBUkAAAICBYkAAAICBckAAAICBgkAAAICBkkAAAICBokAAAICBskAAAICBwkAAAICB0kAAAICB4kAAAICB8kAAAICCAkAAAICCEkAAAICCIkAAAICCMkAAAICCQkAAAICCUkAAAICCYkAAAICCckAAAICCgkAAAICCkkAAAICCokAAAICCskAAAICCwkAAAICC0kAAAICC4kAAAICC8kAAAICDAkAAAICDEkAAAICDIkAAAICDMkAAAICDQkAAAICDUkAAAICDYkAAAICDckAAAICDgkAAAICDkkAAAICDokAAAICDskAAAICDwkAAAICD0kAAAICD4kAAAICD8kAAAICEAkAAAICEEkAAAICEIkAAAICEMkAAAICEQkAAAICEUkAAAICEYkAAAICEckAAAICEgkAAAICEkkAAAICEokAAAICEskAAAICEwkAAAICE0kAAAICE4kAAAICE8kAAAICFAkAAAICFEkAAAICFIkAAAICFMkAAAICFQkAAAICFUkAAAICFYkAAAICFckAAAICFgkAAAICFkkAAAICFokAAAICFskAAAICFwkAAAICF0kAAAICF4kAAAICF8kAAAICGAkAAAICGEkAAAICGIkAAAICGMkAAAICGQkAAAICGUkAAAICGYkAAAICGckAAAICGgkAAAICGkkAAAICGokAAAICGskAAAICGwkAAAICG0kAAAICG4kAAAICG8kAAAICHAkAAAICHEkAAAICHIkAAAICHMkAAAICHQkAAAICHUkAAAICHYkAAAICHckAAAICHgkAAAICHkkAAAICHokAAAICHskAAAICHwkAAAICH0kAAAICH4kAAAICH8kAAAICIAkAAAICIEkAAAICIIkAAAICIMkAAAICIQkAAAICIUkAAAICIYkAAAICIckAAAICIgkAAAICIkkAAAICIokAAAICIskAAAICIwkAAAICI0kAAAICI4kAAAICI8kAAAICJAkAAAICJEkAAAICJIkAAAICJMkAAAICJQkAAAICJUkAAAICJYkAAAICJckAAAICJgkAAAICJkkAAAICJokAAAICJskAAAICJwkAAAICJ0kAAAICJ4kAAAICJ8kAAAICKAkAAAICKEkAAAICKIkAAAICKMkAAAICKQkAAAICKUkAAAICKYkAAAICKckAAAICKgkAAAICKkkAAAICKokAAAICKskAAAICKwkAAAICK0kAAAICK4kAAAICK8kAAAICLAkAAAICLEkAAAICLIkAAAICLMkAAAICLQkAAAICLUkAAAICLYkAAAICLckAAAICLgkAAAICLkkAAAICLokAAAICLskAAAICLwkAAAICL0kAAAICL4kAAAICL8kAAAICMAkAAAICMEkAAAICMIkAAAICMMkAAAICMQkAAAICMUkAAAICMYkAAAICMckAAAICMgkAAAICMkkAAAICMokAAAICMskAAAICMwkAAAICM0kAAAICM4kAAAICM8kAAAICNAkAAAICNEkAAAICNIkAAAICNMkAAAICNQkAAAICNUkAAAICNYkAAAICNckAAAICNgkAAAICNkkAAAICNokAAAICNskAAAICNwkAAAICN0kAAAICN4kAAAICN8kAAAICOAkAAAICOEkAAAICOIkAAAICOMkAAAICOQkAAAICOUkAAAICOYkAAAICOckAAAICOgkAAAICOkkAAAICOokAAAICOskAAAICOwkAAAICO0kAAAICO4kAAAICO8kAAAICPAkAAAICPEkAAAICPIkAAAICPMkAAAICPQkAAAICPUkAAAICPYkAAAICPckAAAICPgkAAAICPkkAAAICPokAAAICPskAAAICPwkAAAICP0kAAAICP4kAAAICP8kAAAICAAlAAAICAElAAAICAIlAAAICAMlAAAICAQlAAAICAUlAAAICAYlAAAICAclAAAICAglAAAICAklAAAICAolAAAICAslAAAICAwlAAAICA0lAAAICA4lAAAICA8lAAAICBAlAAAICBElAAAICBIlAAAICBMlAAAICBQlAAAICBUlAAAICBYlAAAICBclAAAICBglAAAICBklAAAICBolAAAICBslAAAICBwlAAAICB0lAAAICB4lAAAICB8lAAAICCAlAAAICCElAAAICCIlAAAICCMlAAAICCQlAAAICCUlAAAICCYlAAAICCclAAAICCglAAAICCklAAAICColAAAICCslAAAICCwlAAAICC0lAAAICC4lAAAICC8lAAAICDAlAAAICDElAAAICDIlAAAICDMlAAAICDQlAAAICDUlAAAICDYlAAAICDclAAAICDglAAAICDklAAAICDolAAAICDslAAAICDwlAAAICD0lAAAICD4lAAAICD8lAAAICEAlAAAICEElAAAICEIlAAAICEMlAAAICEQlAAAICEUlAAAICEYlAAAICEclAAAICEglAAAICEklAAAICEolAAAICEslAAAICEwlAAAICE0lAAAICE4lAAAICE8lAAAICFAlAAAICFElAAAICFIlAAAICFMlAAAICFQlAAAICFUlAAAICFYlAAAICFclAAAICFglAAAICFklAAAICFolAAAICFslAAAICFwlAAAICF0lAAAICF4lAAAICF8lAAAICGAlAAAICGElAAAICGIlAAAICGMlAAAICGQlAAAICGUlAAAICGYlAAAICGclAAAICGglAAAICGklAAAICGolAAAICGslAAAICGwlAAAICG0lAAAICG4lAAAICG8lAAAICHAlAAAICHElAAAICHIlAAAICHMlAAAICHQlAAAICHUlAAAICHYlAAAICHclAAAICHglAAAICHklAAAICHolAAAICHslAAAICHwlAAAICH0lAAAICH4lAAAICH8lAAAICIAlAAAICIElAAAICIIlAAAICIMlAAAICIQlAAAICIUlAAAICIYlAAAICIclAAAICIglAAAICIklAAAICIolAAAICIslAAAICIwlAAAICI0lAAAICI4lAAAICI8lAAAICJAlAAAICJElAAAICJIlAAAICJMlAAAICJQlAAAICJUlAAAICJYlAAAICJclAAAICJglAAAICJklAAAICJolAAAICJslAAAICJwlAAAICJ0lAAAICJ4lAAAICJ8lAAAICKAlAAAICKElAAAICKIlAAAICKMlAAAICKQlAAAICKUlAAAICKYlAAAICKclAAAICKglAAAICKklAAAICKolAAAICKslAAAICKwlAAAICK0lAAAICK4lAAAICK8lAAAICLAlAAAICLElAAAICLIlAAAICLMlAAAICLQlAAAICLUlAAAICLYlAAAICLclAAAICLglAAAICLklAAAICLolAAAICLslAAAICLwlAAAICL0lAAAICL4lAAAICL8lAAAICMAlAAAICMElAAAICMIlAAAICMMlAAAICMQlAAAICMUlAAAICMYlAAAICMclAAAICMglAAAICMklAAAICMolAAAICMslAAAICMwlAAAICM0lAAAICM4lAAAICM8lAAAICNAlAAAICNElAAAICNIlAAAICNMlAAAICNQlAAAICNUlAAAICNYlAAAICNclAAAICNglAAAICNklAAAICNolAAAICNslAAAICNwlAAAICN0lAAAICN4lAAAICN8lAAAICOAlAAAICOElAAAICOIlAAAICOMlAAAICOQlAAAICOUlAAAICOYlAAAICOclAAAICOglAAAICOklAAAICOolAAAICOslAAAICOwlAAAICO0lAAAICO4lAAAICO8lAAAICPAlAAAICPElAAAICPIlAAAICPMlAAAICPQlAAAICPUlAAAICPYlAAAICPclAAAICPglAAAICPklAAAICPolAAAICPslAAAICPwlAAAICP0lAAAICP4lAAAICP8lAAAICAAmAAAICAEmAAAICAImAAAICAMmAAAICAQmAAAICAUmAAAICAYmAAAICAcmAAAICAgmAAAICAkmAAAICAomAAAICAsmAAAICAwmAAAICA0mAAAICA4mAAAICA8mAAAICBAmAAAICBEmAAAICBImAAAICBMmAAAICBQmAAAICBUmAAAICBYmAAAICBcmAAAICBgmAAAICBkmAAAICBomAAAICBsmAAAICBwmAAAICB0mAAAICB4mAAAICB8mAAAICCAmAAAICCEmAAAICCImAAAICCMmAAAICCQmAAAICCUmAAAICCYmAAAICCcmAAAICCgmAAAICCkmAAAICComAAAICCsmAAAICCwmAAAICC0mAAAICC4mAAAICC8mAAAICDAmAAAICDEmAAAICDImAAAICDMmAAAICDQmAAAICDUmAAAICDYmAAAICDcmAAAICDgmAAAICDkmAAAICDomAAAICDsmAAAICDwmAAAICD0mAAAICD4mAAAICD8mAAAICEAmAAAICEEmAAAICEImAAAICEMmAAAICEQmAAAICEUmAAAICEYmAAAICEcmAAAICEgmAAAICEkmAAAICEomAAAICEsmAAAICEwmAAAICE0mAAAICE4mAAAICE8mAAAICFAmAAAICFEmAAAICFImAAAICFMmAAAICFQmAAAICFUmAAAICFYmAAAICFcmAAAICFgmAAAICFkmAAAICFomAAAICFsmAAAICFwmAAAICF0mAAAICF4mAAAICF8mAAAICGAmAAAICGEmAAAICGImAAAICGMmAAAICGQmAAAICGUmAAAICGYmAAAICGcmAAAICGgmAAAICGkmAAAICGomAAAICGsmAAAICGwmAAAICG0mAAAICG4mAAAICG8mAAAICHAmAAAICHEmAAAICHImAAAICHMmAAAICHQmAAAICHUmAAAICHYmAAAICHcmAAAICHgmAAAICHkmAAAICHomAAAICHsmAAAICHwmAAAICH0mAAAICH4mAAAICH8mAAAICIAmAAAICIEmAAAICIImAAAICIMmAAAICIQmAAAICIUmAAAICIYmAAAICIcmAAAICIgmAAAICIkmAAAICIomAAAICIsmAAAICIwmAAAICI0mAAAICI4mAAAICI8mAAAICJAmAAAICJEmAAAICJImAAAICJMmAAAICJQmAAAICJUmAAAICJYmAAAICJcmAAAICJgmAAAICJkmAAAICJomAAAICJsmAAAICJwmAAAICJ0mAAAICJ4mAAAICJ8mAAAICKAmAAAICKEmAAAICKImAAAICKMmAAAICKQmAAAICKUmAAAICKYmAAAICKcmAAAICKgmAAAICKkmAAAICKomAAAICKsmAAAICKwmAAAICK0mAAAICK4mAAAICK8mAAAICLAmAAAICLEmAAAICLImAAAICLMmAAAICLQmAAAICLUmAAAICLYmAAAICLcmAAAICLgmAAAICLkmAAAICLomAAAICLsmAAAICLwmAAAICL0mAAAICL4mAAAICL8mAAAICMAmAAAICMEmAAAICMImAAAICMMmAAAICMQmAAAICMUmAAAICMYmAAAICMcmAAAICMgmAAAICMkmAAAICMomAAAICMsmAAAICMwmAAAICM0mAAAICM4mAAAICM8mAAAICNAmAAAICNEmAAAICNImAAAICNMmAAAICNQmAAAICNUmAAAICNYmAAAICNcmAAAICNgmAAAICNkmAAAICNomAAAICNsmAAAICNwmAAAICN0mAAAICN4mAAAICN8mAAAICOAmAAAICOEmAAAICOImAAAICOMmAAAICOQmAAAICOUmAAAICOYmAAAICOcmAAAICOgmAAAICOkmAAAICOomAAAICOsmAAAICOwmAAAICO0mAAAICO4mAAAICO8mAAAICPAmAAAICPEmAAAICPImAAAICPMmAAAICPQmAAAICPUmAAAICPYmAAAICPcmAAAICPgmAAAICPkmAAAICPomAAAICPsmAAAICPwmAAAICP0mAAAICP4mAAAICP8mAAAICAAnAAAICAEnAAAICAInAAAICAMnAAAICAQnAAAICAUnAAAICAYnAAAICAcnAAAICAgnAAAICAknAAAICAonAAAICAsnAAAICAwnAAAICA0nAAAICA4nAAAICA8nAAAL" } };
+ yield return new object[] { new ArraySegment<int>(new int[] { 1, 2, 3, 4, 5 }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAHJTeXN0ZW0uQXJyYXlTZWdtZW50YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9hcnJheQdfb2Zmc2V0Bl9jb3VudAcAAAgICAkCAAAAAAAAAAUAAAAPAgAAAAUAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAHJTeXN0ZW0uQXJyYXlTZWdtZW50YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9hcnJheQdfb2Zmc2V0Bl9jb3VudAcAAAgICAkCAAAAAAAAAAUAAAAPAgAAAAUAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new ArraySegment<int>(new int[] { 1, 2, 3, 4, 5 }, 1, 2), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAHJTeXN0ZW0uQXJyYXlTZWdtZW50YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9hcnJheQdfb2Zmc2V0Bl9jb3VudAcAAAgICAkCAAAAAQAAAAIAAAAPAgAAAAUAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAHJTeXN0ZW0uQXJyYXlTZWdtZW50YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAABl9hcnJheQdfb2Zmc2V0Bl9jb3VudAcAAAgICAkCAAAAAQAAAAIAAAAPAgAAAAUAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { Enumerable.Range(0, 10000).Select(i => (object)i).ToArray(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAQAQAAABAnAAAICAAAAAAICAEAAAAICAIAAAAICAMAAAAICAQAAAAICAUAAAAICAYAAAAICAcAAAAICAgAAAAICAkAAAAICAoAAAAICAsAAAAICAwAAAAICA0AAAAICA4AAAAICA8AAAAICBAAAAAICBEAAAAICBIAAAAICBMAAAAICBQAAAAICBUAAAAICBYAAAAICBcAAAAICBgAAAAICBkAAAAICBoAAAAICBsAAAAICBwAAAAICB0AAAAICB4AAAAICB8AAAAICCAAAAAICCEAAAAICCIAAAAICCMAAAAICCQAAAAICCUAAAAICCYAAAAICCcAAAAICCgAAAAICCkAAAAICCoAAAAICCsAAAAICCwAAAAICC0AAAAICC4AAAAICC8AAAAICDAAAAAICDEAAAAICDIAAAAICDMAAAAICDQAAAAICDUAAAAICDYAAAAICDcAAAAICDgAAAAICDkAAAAICDoAAAAICDsAAAAICDwAAAAICD0AAAAICD4AAAAICD8AAAAICEAAAAAICEEAAAAICEIAAAAICEMAAAAICEQAAAAICEUAAAAICEYAAAAICEcAAAAICEgAAAAICEkAAAAICEoAAAAICEsAAAAICEwAAAAICE0AAAAICE4AAAAICE8AAAAICFAAAAAICFEAAAAICFIAAAAICFMAAAAICFQAAAAICFUAAAAICFYAAAAICFcAAAAICFgAAAAICFkAAAAICFoAAAAICFsAAAAICFwAAAAICF0AAAAICF4AAAAICF8AAAAICGAAAAAICGEAAAAICGIAAAAICGMAAAAICGQAAAAICGUAAAAICGYAAAAICGcAAAAICGgAAAAICGkAAAAICGoAAAAICGsAAAAICGwAAAAICG0AAAAICG4AAAAICG8AAAAICHAAAAAICHEAAAAICHIAAAAICHMAAAAICHQAAAAICHUAAAAICHYAAAAICHcAAAAICHgAAAAICHkAAAAICHoAAAAICHsAAAAICHwAAAAICH0AAAAICH4AAAAICH8AAAAICIAAAAAICIEAAAAICIIAAAAICIMAAAAICIQAAAAICIUAAAAICIYAAAAICIcAAAAICIgAAAAICIkAAAAICIoAAAAICIsAAAAICIwAAAAICI0AAAAICI4AAAAICI8AAAAICJAAAAAICJEAAAAICJIAAAAICJMAAAAICJQAAAAICJUAAAAICJYAAAAICJcAAAAICJgAAAAICJkAAAAICJoAAAAICJsAAAAICJwAAAAICJ0AAAAICJ4AAAAICJ8AAAAICKAAAAAICKEAAAAICKIAAAAICKMAAAAICKQAAAAICKUAAAAICKYAAAAICKcAAAAICKgAAAAICKkAAAAICKoAAAAICKsAAAAICKwAAAAICK0AAAAICK4AAAAICK8AAAAICLAAAAAICLEAAAAICLIAAAAICLMAAAAICLQAAAAICLUAAAAICLYAAAAICLcAAAAICLgAAAAICLkAAAAICLoAAAAICLsAAAAICLwAAAAICL0AAAAICL4AAAAICL8AAAAICMAAAAAICMEAAAAICMIAAAAICMMAAAAICMQAAAAICMUAAAAICMYAAAAICMcAAAAICMgAAAAICMkAAAAICMoAAAAICMsAAAAICMwAAAAICM0AAAAICM4AAAAICM8AAAAICNAAAAAICNEAAAAICNIAAAAICNMAAAAICNQAAAAICNUAAAAICNYAAAAICNcAAAAICNgAAAAICNkAAAAICNoAAAAICNsAAAAICNwAAAAICN0AAAAICN4AAAAICN8AAAAICOAAAAAICOEAAAAICOIAAAAICOMAAAAICOQAAAAICOUAAAAICOYAAAAICOcAAAAICOgAAAAICOkAAAAICOoAAAAICOsAAAAICOwAAAAICO0AAAAICO4AAAAICO8AAAAICPAAAAAICPEAAAAICPIAAAAICPMAAAAICPQAAAAICPUAAAAICPYAAAAICPcAAAAICPgAAAAICPkAAAAICPoAAAAICPsAAAAICPwAAAAICP0AAAAICP4AAAAICP8AAAAICAABAAAICAEBAAAICAIBAAAICAMBAAAICAQBAAAICAUBAAAICAYBAAAICAcBAAAICAgBAAAICAkBAAAICAoBAAAICAsBAAAICAwBAAAICA0BAAAICA4BAAAICA8BAAAICBABAAAICBEBAAAICBIBAAAICBMBAAAICBQBAAAICBUBAAAICBYBAAAICBcBAAAICBgBAAAICBkBAAAICBoBAAAICBsBAAAICBwBAAAICB0BAAAICB4BAAAICB8BAAAICCABAAAICCEBAAAICCIBAAAICCMBAAAICCQBAAAICCUBAAAICCYBAAAICCcBAAAICCgBAAAICCkBAAAICCoBAAAICCsBAAAICCwBAAAICC0BAAAICC4BAAAICC8BAAAICDABAAAICDEBAAAICDIBAAAICDMBAAAICDQBAAAICDUBAAAICDYBAAAICDcBAAAICDgBAAAICDkBAAAICDoBAAAICDsBAAAICDwBAAAICD0BAAAICD4BAAAICD8BAAAICEABAAAICEEBAAAICEIBAAAICEMBAAAICEQBAAAICEUBAAAICEYBAAAICEcBAAAICEgBAAAICEkBAAAICEoBAAAICEsBAAAICEwBAAAICE0BAAAICE4BAAAICE8BAAAICFABAAAICFEBAAAICFIBAAAICFMBAAAICFQBAAAICFUBAAAICFYBAAAICFcBAAAICFgBAAAICFkBAAAICFoBAAAICFsBAAAICFwBAAAICF0BAAAICF4BAAAICF8BAAAICGABAAAICGEBAAAICGIBAAAICGMBAAAICGQBAAAICGUBAAAICGYBAAAICGcBAAAICGgBAAAICGkBAAAICGoBAAAICGsBAAAICGwBAAAICG0BAAAICG4BAAAICG8BAAAICHABAAAICHEBAAAICHIBAAAICHMBAAAICHQBAAAICHUBAAAICHYBAAAICHcBAAAICHgBAAAICHkBAAAICHoBAAAICHsBAAAICHwBAAAICH0BAAAICH4BAAAICH8BAAAICIABAAAICIEBAAAICIIBAAAICIMBAAAICIQBAAAICIUBAAAICIYBAAAICIcBAAAICIgBAAAICIkBAAAICIoBAAAICIsBAAAICIwBAAAICI0BAAAICI4BAAAICI8BAAAICJABAAAICJEBAAAICJIBAAAICJMBAAAICJQBAAAICJUBAAAICJYBAAAICJcBAAAICJgBAAAICJkBAAAICJoBAAAICJsBAAAICJwBAAAICJ0BAAAICJ4BAAAICJ8BAAAICKABAAAICKEBAAAICKIBAAAICKMBAAAICKQBAAAICKUBAAAICKYBAAAICKcBAAAICKgBAAAICKkBAAAICKoBAAAICKsBAAAICKwBAAAICK0BAAAICK4BAAAICK8BAAAICLABAAAICLEBAAAICLIBAAAICLMBAAAICLQBAAAICLUBAAAICLYBAAAICLcBAAAICLgBAAAICLkBAAAICLoBAAAICLsBAAAICLwBAAAICL0BAAAICL4BAAAICL8BAAAICMABAAAICMEBAAAICMIBAAAICMMBAAAICMQBAAAICMUBAAAICMYBAAAICMcBAAAICMgBAAAICMkBAAAICMoBAAAICMsBAAAICMwBAAAICM0BAAAICM4BAAAICM8BAAAICNABAAAICNEBAAAICNIBAAAICNMBAAAICNQBAAAICNUBAAAICNYBAAAICNcBAAAICNgBAAAICNkBAAAICNoBAAAICNsBAAAICNwBAAAICN0BAAAICN4BAAAICN8BAAAICOABAAAICOEBAAAICOIBAAAICOMBAAAICOQBAAAICOUBAAAICOYBAAAICOcBAAAICOgBAAAICOkBAAAICOoBAAAICOsBAAAICOwBAAAICO0BAAAICO4BAAAICO8BAAAICPABAAAICPEBAAAICPIBAAAICPMBAAAICPQBAAAICPUBAAAICPYBAAAICPcBAAAICPgBAAAICPkBAAAICPoBAAAICPsBAAAICPwBAAAICP0BAAAICP4BAAAICP8BAAAICAACAAAICAECAAAICAICAAAICAMCAAAICAQCAAAICAUCAAAICAYCAAAICAcCAAAICAgCAAAICAkCAAAICAoCAAAICAsCAAAICAwCAAAICA0CAAAICA4CAAAICA8CAAAICBACAAAICBECAAAICBICAAAICBMCAAAICBQCAAAICBUCAAAICBYCAAAICBcCAAAICBgCAAAICBkCAAAICBoCAAAICBsCAAAICBwCAAAICB0CAAAICB4CAAAICB8CAAAICCACAAAICCECAAAICCICAAAICCMCAAAICCQCAAAICCUCAAAICCYCAAAICCcCAAAICCgCAAAICCkCAAAICCoCAAAICCsCAAAICCwCAAAICC0CAAAICC4CAAAICC8CAAAICDACAAAICDECAAAICDICAAAICDMCAAAICDQCAAAICDUCAAAICDYCAAAICDcCAAAICDgCAAAICDkCAAAICDoCAAAICDsCAAAICDwCAAAICD0CAAAICD4CAAAICD8CAAAICEACAAAICEECAAAICEICAAAICEMCAAAICEQCAAAICEUCAAAICEYCAAAICEcCAAAICEgCAAAICEkCAAAICEoCAAAICEsCAAAICEwCAAAICE0CAAAICE4CAAAICE8CAAAICFACAAAICFECAAAICFICAAAICFMCAAAICFQCAAAICFUCAAAICFYCAAAICFcCAAAICFgCAAAICFkCAAAICFoCAAAICFsCAAAICFwCAAAICF0CAAAICF4CAAAICF8CAAAICGACAAAICGECAAAICGICAAAICGMCAAAICGQCAAAICGUCAAAICGYCAAAICGcCAAAICGgCAAAICGkCAAAICGoCAAAICGsCAAAICGwCAAAICG0CAAAICG4CAAAICG8CAAAICHACAAAICHECAAAICHICAAAICHMCAAAICHQCAAAICHUCAAAICHYCAAAICHcCAAAICHgCAAAICHkCAAAICHoCAAAICHsCAAAICHwCAAAICH0CAAAICH4CAAAICH8CAAAICIACAAAICIECAAAICIICAAAICIMCAAAICIQCAAAICIUCAAAICIYCAAAICIcCAAAICIgCAAAICIkCAAAICIoCAAAICIsCAAAICIwCAAAICI0CAAAICI4CAAAICI8CAAAICJACAAAICJECAAAICJICAAAICJMCAAAICJQCAAAICJUCAAAICJYCAAAICJcCAAAICJgCAAAICJkCAAAICJoCAAAICJsCAAAICJwCAAAICJ0CAAAICJ4CAAAICJ8CAAAICKACAAAICKECAAAICKICAAAICKMCAAAICKQCAAAICKUCAAAICKYCAAAICKcCAAAICKgCAAAICKkCAAAICKoCAAAICKsCAAAICKwCAAAICK0CAAAICK4CAAAICK8CAAAICLACAAAICLECAAAICLICAAAICLMCAAAICLQCAAAICLUCAAAICLYCAAAICLcCAAAICLgCAAAICLkCAAAICLoCAAAICLsCAAAICLwCAAAICL0CAAAICL4CAAAICL8CAAAICMACAAAICMECAAAICMICAAAICMMCAAAICMQCAAAICMUCAAAICMYCAAAICMcCAAAICMgCAAAICMkCAAAICMoCAAAICMsCAAAICMwCAAAICM0CAAAICM4CAAAICM8CAAAICNACAAAICNECAAAICNICAAAICNMCAAAICNQCAAAICNUCAAAICNYCAAAICNcCAAAICNgCAAAICNkCAAAICNoCAAAICNsCAAAICNwCAAAICN0CAAAICN4CAAAICN8CAAAICOACAAAICOECAAAICOICAAAICOMCAAAICOQCAAAICOUCAAAICOYCAAAICOcCAAAICOgCAAAICOkCAAAICOoCAAAICOsCAAAICOwCAAAICO0CAAAICO4CAAAICO8CAAAICPACAAAICPECAAAICPICAAAICPMCAAAICPQCAAAICPUCAAAICPYCAAAICPcCAAAICPgCAAAICPkCAAAICPoCAAAICPsCAAAICPwCAAAICP0CAAAICP4CAAAICP8CAAAICAADAAAICAEDAAAICAIDAAAICAMDAAAICAQDAAAICAUDAAAICAYDAAAICAcDAAAICAgDAAAICAkDAAAICAoDAAAICAsDAAAICAwDAAAICA0DAAAICA4DAAAICA8DAAAICBADAAAICBEDAAAICBIDAAAICBMDAAAICBQDAAAICBUDAAAICBYDAAAICBcDAAAICBgDAAAICBkDAAAICBoDAAAICBsDAAAICBwDAAAICB0DAAAICB4DAAAICB8DAAAICCADAAAICCEDAAAICCIDAAAICCMDAAAICCQDAAAICCUDAAAICCYDAAAICCcDAAAICCgDAAAICCkDAAAICCoDAAAICCsDAAAICCwDAAAICC0DAAAICC4DAAAICC8DAAAICDADAAAICDEDAAAICDIDAAAICDMDAAAICDQDAAAICDUDAAAICDYDAAAICDcDAAAICDgDAAAICDkDAAAICDoDAAAICDsDAAAICDwDAAAICD0DAAAICD4DAAAICD8DAAAICEADAAAICEEDAAAICEIDAAAICEMDAAAICEQDAAAICEUDAAAICEYDAAAICEcDAAAICEgDAAAICEkDAAAICEoDAAAICEsDAAAICEwDAAAICE0DAAAICE4DAAAICE8DAAAICFADAAAICFEDAAAICFIDAAAICFMDAAAICFQDAAAICFUDAAAICFYDAAAICFcDAAAICFgDAAAICFkDAAAICFoDAAAICFsDAAAICFwDAAAICF0DAAAICF4DAAAICF8DAAAICGADAAAICGEDAAAICGIDAAAICGMDAAAICGQDAAAICGUDAAAICGYDAAAICGcDAAAICGgDAAAICGkDAAAICGoDAAAICGsDAAAICGwDAAAICG0DAAAICG4DAAAICG8DAAAICHADAAAICHEDAAAICHIDAAAICHMDAAAICHQDAAAICHUDAAAICHYDAAAICHcDAAAICHgDAAAICHkDAAAICHoDAAAICHsDAAAICHwDAAAICH0DAAAICH4DAAAICH8DAAAICIADAAAICIEDAAAICIIDAAAICIMDAAAICIQDAAAICIUDAAAICIYDAAAICIcDAAAICIgDAAAICIkDAAAICIoDAAAICIsDAAAICIwDAAAICI0DAAAICI4DAAAICI8DAAAICJADAAAICJEDAAAICJIDAAAICJMDAAAICJQDAAAICJUDAAAICJYDAAAICJcDAAAICJgDAAAICJkDAAAICJoDAAAICJsDAAAICJwDAAAICJ0DAAAICJ4DAAAICJ8DAAAICKADAAAICKEDAAAICKIDAAAICKMDAAAICKQDAAAICKUDAAAICKYDAAAICKcDAAAICKgDAAAICKkDAAAICKoDAAAICKsDAAAICKwDAAAICK0DAAAICK4DAAAICK8DAAAICLADAAAICLEDAAAICLIDAAAICLMDAAAICLQDAAAICLUDAAAICLYDAAAICLcDAAAICLgDAAAICLkDAAAICLoDAAAICLsDAAAICLwDAAAICL0DAAAICL4DAAAICL8DAAAICMADAAAICMEDAAAICMIDAAAICMMDAAAICMQDAAAICMUDAAAICMYDAAAICMcDAAAICMgDAAAICMkDAAAICMoDAAAICMsDAAAICMwDAAAICM0DAAAICM4DAAAICM8DAAAICNADAAAICNEDAAAICNIDAAAICNMDAAAICNQDAAAICNUDAAAICNYDAAAICNcDAAAICNgDAAAICNkDAAAICNoDAAAICNsDAAAICNwDAAAICN0DAAAICN4DAAAICN8DAAAICOADAAAICOEDAAAICOIDAAAICOMDAAAICOQDAAAICOUDAAAICOYDAAAICOcDAAAICOgDAAAICOkDAAAICOoDAAAICOsDAAAICOwDAAAICO0DAAAICO4DAAAICO8DAAAICPADAAAICPEDAAAICPIDAAAICPMDAAAICPQDAAAICPUDAAAICPYDAAAICPcDAAAICPgDAAAICPkDAAAICPoDAAAICPsDAAAICPwDAAAICP0DAAAICP4DAAAICP8DAAAICAAEAAAICAEEAAAICAIEAAAICAMEAAAICAQEAAAICAUEAAAICAYEAAAICAcEAAAICAgEAAAICAkEAAAICAoEAAAICAsEAAAICAwEAAAICA0EAAAICA4EAAAICA8EAAAICBAEAAAICBEEAAAICBIEAAAICBMEAAAICBQEAAAICBUEAAAICBYEAAAICBcEAAAICBgEAAAICBkEAAAICBoEAAAICBsEAAAICBwEAAAICB0EAAAICB4EAAAICB8EAAAICCAEAAAICCEEAAAICCIEAAAICCMEAAAICCQEAAAICCUEAAAICCYEAAAICCcEAAAICCgEAAAICCkEAAAICCoEAAAICCsEAAAICCwEAAAICC0EAAAICC4EAAAICC8EAAAICDAEAAAICDEEAAAICDIEAAAICDMEAAAICDQEAAAICDUEAAAICDYEAAAICDcEAAAICDgEAAAICDkEAAAICDoEAAAICDsEAAAICDwEAAAICD0EAAAICD4EAAAICD8EAAAICEAEAAAICEEEAAAICEIEAAAICEMEAAAICEQEAAAICEUEAAAICEYEAAAICEcEAAAICEgEAAAICEkEAAAICEoEAAAICEsEAAAICEwEAAAICE0EAAAICE4EAAAICE8EAAAICFAEAAAICFEEAAAICFIEAAAICFMEAAAICFQEAAAICFUEAAAICFYEAAAICFcEAAAICFgEAAAICFkEAAAICFoEAAAICFsEAAAICFwEAAAICF0EAAAICF4EAAAICF8EAAAICGAEAAAICGEEAAAICGIEAAAICGMEAAAICGQEAAAICGUEAAAICGYEAAAICGcEAAAICGgEAAAICGkEAAAICGoEAAAICGsEAAAICGwEAAAICG0EAAAICG4EAAAICG8EAAAICHAEAAAICHEEAAAICHIEAAAICHMEAAAICHQEAAAICHUEAAAICHYEAAAICHcEAAAICHgEAAAICHkEAAAICHoEAAAICHsEAAAICHwEAAAICH0EAAAICH4EAAAICH8EAAAICIAEAAAICIEEAAAICIIEAAAICIMEAAAICIQEAAAICIUEAAAICIYEAAAICIcEAAAICIgEAAAICIkEAAAICIoEAAAICIsEAAAICIwEAAAICI0EAAAICI4EAAAICI8EAAAICJAEAAAICJEEAAAICJIEAAAICJMEAAAICJQEAAAICJUEAAAICJYEAAAICJcEAAAICJgEAAAICJkEAAAICJoEAAAICJsEAAAICJwEAAAICJ0EAAAICJ4EAAAICJ8EAAAICKAEAAAICKEEAAAICKIEAAAICKMEAAAICKQEAAAICKUEAAAICKYEAAAICKcEAAAICKgEAAAICKkEAAAICKoEAAAICKsEAAAICKwEAAAICK0EAAAICK4EAAAICK8EAAAICLAEAAAICLEEAAAICLIEAAAICLMEAAAICLQEAAAICLUEAAAICLYEAAAICLcEAAAICLgEAAAICLkEAAAICLoEAAAICLsEAAAICLwEAAAICL0EAAAICL4EAAAICL8EAAAICMAEAAAICMEEAAAICMIEAAAICMMEAAAICMQEAAAICMUEAAAICMYEAAAICMcEAAAICMgEAAAICMkEAAAICMoEAAAICMsEAAAICMwEAAAICM0EAAAICM4EAAAICM8EAAAICNAEAAAICNEEAAAICNIEAAAICNMEAAAICNQEAAAICNUEAAAICNYEAAAICNcEAAAICNgEAAAICNkEAAAICNoEAAAICNsEAAAICNwEAAAICN0EAAAICN4EAAAICN8EAAAICOAEAAAICOEEAAAICOIEAAAICOMEAAAICOQEAAAICOUEAAAICOYEAAAICOcEAAAICOgEAAAICOkEAAAICOoEAAAICOsEAAAICOwEAAAICO0EAAAICO4EAAAICO8EAAAICPAEAAAICPEEAAAICPIEAAAICPMEAAAICPQEAAAICPUEAAAICPYEAAAICPcEAAAICPgEAAAICPkEAAAICPoEAAAICPsEAAAICPwEAAAICP0EAAAICP4EAAAICP8EAAAICAAFAAAICAEFAAAICAIFAAAICAMFAAAICAQFAAAICAUFAAAICAYFAAAICAcFAAAICAgFAAAICAkFAAAICAoFAAAICAsFAAAICAwFAAAICA0FAAAICA4FAAAICA8FAAAICBAFAAAICBEFAAAICBIFAAAICBMFAAAICBQFAAAICBUFAAAICBYFAAAICBcFAAAICBgFAAAICBkFAAAICBoFAAAICBsFAAAICBwFAAAICB0FAAAICB4FAAAICB8FAAAICCAFAAAICCEFAAAICCIFAAAICCMFAAAICCQFAAAICCUFAAAICCYFAAAICCcFAAAICCgFAAAICCkFAAAICCoFAAAICCsFAAAICCwFAAAICC0FAAAICC4FAAAICC8FAAAICDAFAAAICDEFAAAICDIFAAAICDMFAAAICDQFAAAICDUFAAAICDYFAAAICDcFAAAICDgFAAAICDkFAAAICDoFAAAICDsFAAAICDwFAAAICD0FAAAICD4FAAAICD8FAAAICEAFAAAICEEFAAAICEIFAAAICEMFAAAICEQFAAAICEUFAAAICEYFAAAICEcFAAAICEgFAAAICEkFAAAICEoFAAAICEsFAAAICEwFAAAICE0FAAAICE4FAAAICE8FAAAICFAFAAAICFEFAAAICFIFAAAICFMFAAAICFQFAAAICFUFAAAICFYFAAAICFcFAAAICFgFAAAICFkFAAAICFoFAAAICFsFAAAICFwFAAAICF0FAAAICF4FAAAICF8FAAAICGAFAAAICGEFAAAICGIFAAAICGMFAAAICGQFAAAICGUFAAAICGYFAAAICGcFAAAICGgFAAAICGkFAAAICGoFAAAICGsFAAAICGwFAAAICG0FAAAICG4FAAAICG8FAAAICHAFAAAICHEFAAAICHIFAAAICHMFAAAICHQFAAAICHUFAAAICHYFAAAICHcFAAAICHgFAAAICHkFAAAICHoFAAAICHsFAAAICHwFAAAICH0FAAAICH4FAAAICH8FAAAICIAFAAAICIEFAAAICIIFAAAICIMFAAAICIQFAAAICIUFAAAICIYFAAAICIcFAAAICIgFAAAICIkFAAAICIoFAAAICIsFAAAICIwFAAAICI0FAAAICI4FAAAICI8FAAAICJAFAAAICJEFAAAICJIFAAAICJMFAAAICJQFAAAICJUFAAAICJYFAAAICJcFAAAICJgFAAAICJkFAAAICJoFAAAICJsFAAAICJwFAAAICJ0FAAAICJ4FAAAICJ8FAAAICKAFAAAICKEFAAAICKIFAAAICKMFAAAICKQFAAAICKUFAAAICKYFAAAICKcFAAAICKgFAAAICKkFAAAICKoFAAAICKsFAAAICKwFAAAICK0FAAAICK4FAAAICK8FAAAICLAFAAAICLEFAAAICLIFAAAICLMFAAAICLQFAAAICLUFAAAICLYFAAAICLcFAAAICLgFAAAICLkFAAAICLoFAAAICLsFAAAICLwFAAAICL0FAAAICL4FAAAICL8FAAAICMAFAAAICMEFAAAICMIFAAAICMMFAAAICMQFAAAICMUFAAAICMYFAAAICMcFAAAICMgFAAAICMkFAAAICMoFAAAICMsFAAAICMwFAAAICM0FAAAICM4FAAAICM8FAAAICNAFAAAICNEFAAAICNIFAAAICNMFAAAICNQFAAAICNUFAAAICNYFAAAICNcFAAAICNgFAAAICNkFAAAICNoFAAAICNsFAAAICNwFAAAICN0FAAAICN4FAAAICN8FAAAICOAFAAAICOEFAAAICOIFAAAICOMFAAAICOQFAAAICOUFAAAICOYFAAAICOcFAAAICOgFAAAICOkFAAAICOoFAAAICOsFAAAICOwFAAAICO0FAAAICO4FAAAICO8FAAAICPAFAAAICPEFAAAICPIFAAAICPMFAAAICPQFAAAICPUFAAAICPYFAAAICPcFAAAICPgFAAAICPkFAAAICPoFAAAICPsFAAAICPwFAAAICP0FAAAICP4FAAAICP8FAAAICAAGAAAICAEGAAAICAIGAAAICAMGAAAICAQGAAAICAUGAAAICAYGAAAICAcGAAAICAgGAAAICAkGAAAICAoGAAAICAsGAAAICAwGAAAICA0GAAAICA4GAAAICA8GAAAICBAGAAAICBEGAAAICBIGAAAICBMGAAAICBQGAAAICBUGAAAICBYGAAAICBcGAAAICBgGAAAICBkGAAAICBoGAAAICBsGAAAICBwGAAAICB0GAAAICB4GAAAICB8GAAAICCAGAAAICCEGAAAICCIGAAAICCMGAAAICCQGAAAICCUGAAAICCYGAAAICCcGAAAICCgGAAAICCkGAAAICCoGAAAICCsGAAAICCwGAAAICC0GAAAICC4GAAAICC8GAAAICDAGAAAICDEGAAAICDIGAAAICDMGAAAICDQGAAAICDUGAAAICDYGAAAICDcGAAAICDgGAAAICDkGAAAICDoGAAAICDsGAAAICDwGAAAICD0GAAAICD4GAAAICD8GAAAICEAGAAAICEEGAAAICEIGAAAICEMGAAAICEQGAAAICEUGAAAICEYGAAAICEcGAAAICEgGAAAICEkGAAAICEoGAAAICEsGAAAICEwGAAAICE0GAAAICE4GAAAICE8GAAAICFAGAAAICFEGAAAICFIGAAAICFMGAAAICFQGAAAICFUGAAAICFYGAAAICFcGAAAICFgGAAAICFkGAAAICFoGAAAICFsGAAAICFwGAAAICF0GAAAICF4GAAAICF8GAAAICGAGAAAICGEGAAAICGIGAAAICGMGAAAICGQGAAAICGUGAAAICGYGAAAICGcGAAAICGgGAAAICGkGAAAICGoGAAAICGsGAAAICGwGAAAICG0GAAAICG4GAAAICG8GAAAICHAGAAAICHEGAAAICHIGAAAICHMGAAAICHQGAAAICHUGAAAICHYGAAAICHcGAAAICHgGAAAICHkGAAAICHoGAAAICHsGAAAICHwGAAAICH0GAAAICH4GAAAICH8GAAAICIAGAAAICIEGAAAICIIGAAAICIMGAAAICIQGAAAICIUGAAAICIYGAAAICIcGAAAICIgGAAAICIkGAAAICIoGAAAICIsGAAAICIwGAAAICI0GAAAICI4GAAAICI8GAAAICJAGAAAICJEGAAAICJIGAAAICJMGAAAICJQGAAAICJUGAAAICJYGAAAICJcGAAAICJgGAAAICJkGAAAICJoGAAAICJsGAAAICJwGAAAICJ0GAAAICJ4GAAAICJ8GAAAICKAGAAAICKEGAAAICKIGAAAICKMGAAAICKQGAAAICKUGAAAICKYGAAAICKcGAAAICKgGAAAICKkGAAAICKoGAAAICKsGAAAICKwGAAAICK0GAAAICK4GAAAICK8GAAAICLAGAAAICLEGAAAICLIGAAAICLMGAAAICLQGAAAICLUGAAAICLYGAAAICLcGAAAICLgGAAAICLkGAAAICLoGAAAICLsGAAAICLwGAAAICL0GAAAICL4GAAAICL8GAAAICMAGAAAICMEGAAAICMIGAAAICMMGAAAICMQGAAAICMUGAAAICMYGAAAICMcGAAAICMgGAAAICMkGAAAICMoGAAAICMsGAAAICMwGAAAICM0GAAAICM4GAAAICM8GAAAICNAGAAAICNEGAAAICNIGAAAICNMGAAAICNQGAAAICNUGAAAICNYGAAAICNcGAAAICNgGAAAICNkGAAAICNoGAAAICNsGAAAICNwGAAAICN0GAAAICN4GAAAICN8GAAAICOAGAAAICOEGAAAICOIGAAAICOMGAAAICOQGAAAICOUGAAAICOYGAAAICOcGAAAICOgGAAAICOkGAAAICOoGAAAICOsGAAAICOwGAAAICO0GAAAICO4GAAAICO8GAAAICPAGAAAICPEGAAAICPIGAAAICPMGAAAICPQGAAAICPUGAAAICPYGAAAICPcGAAAICPgGAAAICPkGAAAICPoGAAAICPsGAAAICPwGAAAICP0GAAAICP4GAAAICP8GAAAICAAHAAAICAEHAAAICAIHAAAICAMHAAAICAQHAAAICAUHAAAICAYHAAAICAcHAAAICAgHAAAICAkHAAAICAoHAAAICAsHAAAICAwHAAAICA0HAAAICA4HAAAICA8HAAAICBAHAAAICBEHAAAICBIHAAAICBMHAAAICBQHAAAICBUHAAAICBYHAAAICBcHAAAICBgHAAAICBkHAAAICBoHAAAICBsHAAAICBwHAAAICB0HAAAICB4HAAAICB8HAAAICCAHAAAICCEHAAAICCIHAAAICCMHAAAICCQHAAAICCUHAAAICCYHAAAICCcHAAAICCgHAAAICCkHAAAICCoHAAAICCsHAAAICCwHAAAICC0HAAAICC4HAAAICC8HAAAICDAHAAAICDEHAAAICDIHAAAICDMHAAAICDQHAAAICDUHAAAICDYHAAAICDcHAAAICDgHAAAICDkHAAAICDoHAAAICDsHAAAICDwHAAAICD0HAAAICD4HAAAICD8HAAAICEAHAAAICEEHAAAICEIHAAAICEMHAAAICEQHAAAICEUHAAAICEYHAAAICEcHAAAICEgHAAAICEkHAAAICEoHAAAICEsHAAAICEwHAAAICE0HAAAICE4HAAAICE8HAAAICFAHAAAICFEHAAAICFIHAAAICFMHAAAICFQHAAAICFUHAAAICFYHAAAICFcHAAAICFgHAAAICFkHAAAICFoHAAAICFsHAAAICFwHAAAICF0HAAAICF4HAAAICF8HAAAICGAHAAAICGEHAAAICGIHAAAICGMHAAAICGQHAAAICGUHAAAICGYHAAAICGcHAAAICGgHAAAICGkHAAAICGoHAAAICGsHAAAICGwHAAAICG0HAAAICG4HAAAICG8HAAAICHAHAAAICHEHAAAICHIHAAAICHMHAAAICHQHAAAICHUHAAAICHYHAAAICHcHAAAICHgHAAAICHkHAAAICHoHAAAICHsHAAAICHwHAAAICH0HAAAICH4HAAAICH8HAAAICIAHAAAICIEHAAAICIIHAAAICIMHAAAICIQHAAAICIUHAAAICIYHAAAICIcHAAAICIgHAAAICIkHAAAICIoHAAAICIsHAAAICIwHAAAICI0HAAAICI4HAAAICI8HAAAICJAHAAAICJEHAAAICJIHAAAICJMHAAAICJQHAAAICJUHAAAICJYHAAAICJcHAAAICJgHAAAICJkHAAAICJoHAAAICJsHAAAICJwHAAAICJ0HAAAICJ4HAAAICJ8HAAAICKAHAAAICKEHAAAICKIHAAAICKMHAAAICKQHAAAICKUHAAAICKYHAAAICKcHAAAICKgHAAAICKkHAAAICKoHAAAICKsHAAAICKwHAAAICK0HAAAICK4HAAAICK8HAAAICLAHAAAICLEHAAAICLIHAAAICLMHAAAICLQHAAAICLUHAAAICLYHAAAICLcHAAAICLgHAAAICLkHAAAICLoHAAAICLsHAAAICLwHAAAICL0HAAAICL4HAAAICL8HAAAICMAHAAAICMEHAAAICMIHAAAICMMHAAAICMQHAAAICMUHAAAICMYHAAAICMcHAAAICMgHAAAICMkHAAAICMoHAAAICMsHAAAICMwHAAAICM0HAAAICM4HAAAICM8HAAAICNAHAAAICNEHAAAICNIHAAAICNMHAAAICNQHAAAICNUHAAAICNYHAAAICNcHAAAICNgHAAAICNkHAAAICNoHAAAICNsHAAAICNwHAAAICN0HAAAICN4HAAAICN8HAAAICOAHAAAICOEHAAAICOIHAAAICOMHAAAICOQHAAAICOUHAAAICOYHAAAICOcHAAAICOgHAAAICOkHAAAICOoHAAAICOsHAAAICOwHAAAICO0HAAAICO4HAAAICO8HAAAICPAHAAAICPEHAAAICPIHAAAICPMHAAAICPQHAAAICPUHAAAICPYHAAAICPcHAAAICPgHAAAICPkHAAAICPoHAAAICPsHAAAICPwHAAAICP0HAAAICP4HAAAICP8HAAAICAAIAAAICAEIAAAICAIIAAAICAMIAAAICAQIAAAICAUIAAAICAYIAAAICAcIAAAICAgIAAAICAkIAAAICAoIAAAICAsIAAAICAwIAAAICA0IAAAICA4IAAAICA8IAAAICBAIAAAICBEIAAAICBIIAAAICBMIAAAICBQIAAAICBUIAAAICBYIAAAICBcIAAAICBgIAAAICBkIAAAICBoIAAAICBsIAAAICBwIAAAICB0IAAAICB4IAAAICB8IAAAICCAIAAAICCEIAAAICCIIAAAICCMIAAAICCQIAAAICCUIAAAICCYIAAAICCcIAAAICCgIAAAICCkIAAAICCoIAAAICCsIAAAICCwIAAAICC0IAAAICC4IAAAICC8IAAAICDAIAAAICDEIAAAICDIIAAAICDMIAAAICDQIAAAICDUIAAAICDYIAAAICDcIAAAICDgIAAAICDkIAAAICDoIAAAICDsIAAAICDwIAAAICD0IAAAICD4IAAAICD8IAAAICEAIAAAICEEIAAAICEIIAAAICEMIAAAICEQIAAAICEUIAAAICEYIAAAICEcIAAAICEgIAAAICEkIAAAICEoIAAAICEsIAAAICEwIAAAICE0IAAAICE4IAAAICE8IAAAICFAIAAAICFEIAAAICFIIAAAICFMIAAAICFQIAAAICFUIAAAICFYIAAAICFcIAAAICFgIAAAICFkIAAAICFoIAAAICFsIAAAICFwIAAAICF0IAAAICF4IAAAICF8IAAAICGAIAAAICGEIAAAICGIIAAAICGMIAAAICGQIAAAICGUIAAAICGYIAAAICGcIAAAICGgIAAAICGkIAAAICGoIAAAICGsIAAAICGwIAAAICG0IAAAICG4IAAAICG8IAAAICHAIAAAICHEIAAAICHIIAAAICHMIAAAICHQIAAAICHUIAAAICHYIAAAICHcIAAAICHgIAAAICHkIAAAICHoIAAAICHsIAAAICHwIAAAICH0IAAAICH4IAAAICH8IAAAICIAIAAAICIEIAAAICIIIAAAICIMIAAAICIQIAAAICIUIAAAICIYIAAAICIcIAAAICIgIAAAICIkIAAAICIoIAAAICIsIAAAICIwIAAAICI0IAAAICI4IAAAICI8IAAAICJAIAAAICJEIAAAICJIIAAAICJMIAAAICJQIAAAICJUIAAAICJYIAAAICJcIAAAICJgIAAAICJkIAAAICJoIAAAICJsIAAAICJwIAAAICJ0IAAAICJ4IAAAICJ8IAAAICKAIAAAICKEIAAAICKIIAAAICKMIAAAICKQIAAAICKUIAAAICKYIAAAICKcIAAAICKgIAAAICKkIAAAICKoIAAAICKsIAAAICKwIAAAICK0IAAAICK4IAAAICK8IAAAICLAIAAAICLEIAAAICLIIAAAICLMIAAAICLQIAAAICLUIAAAICLYIAAAICLcIAAAICLgIAAAICLkIAAAICLoIAAAICLsIAAAICLwIAAAICL0IAAAICL4IAAAICL8IAAAICMAIAAAICMEIAAAICMIIAAAICMMIAAAICMQIAAAICMUIAAAICMYIAAAICMcIAAAICMgIAAAICMkIAAAICMoIAAAICMsIAAAICMwIAAAICM0IAAAICM4IAAAICM8IAAAICNAIAAAICNEIAAAICNIIAAAICNMIAAAICNQIAAAICNUIAAAICNYIAAAICNcIAAAICNgIAAAICNkIAAAICNoIAAAICNsIAAAICNwIAAAICN0IAAAICN4IAAAICN8IAAAICOAIAAAICOEIAAAICOIIAAAICOMIAAAICOQIAAAICOUIAAAICOYIAAAICOcIAAAICOgIAAAICOkIAAAICOoIAAAICOsIAAAICOwIAAAICO0IAAAICO4IAAAICO8IAAAICPAIAAAICPEIAAAICPIIAAAICPMIAAAICPQIAAAICPUIAAAICPYIAAAICPcIAAAICPgIAAAICPkIAAAICPoIAAAICPsIAAAICPwIAAAICP0IAAAICP4IAAAICP8IAAAICAAJAAAICAEJAAAICAIJAAAICAMJAAAICAQJAAAICAUJAAAICAYJAAAICAcJAAAICAgJAAAICAkJAAAICAoJAAAICAsJAAAICAwJAAAICA0JAAAICA4JAAAICA8JAAAICBAJAAAICBEJAAAICBIJAAAICBMJAAAICBQJAAAICBUJAAAICBYJAAAICBcJAAAICBgJAAAICBkJAAAICBoJAAAICBsJAAAICBwJAAAICB0JAAAICB4JAAAICB8JAAAICCAJAAAICCEJAAAICCIJAAAICCMJAAAICCQJAAAICCUJAAAICCYJAAAICCcJAAAICCgJAAAICCkJAAAICCoJAAAICCsJAAAICCwJAAAICC0JAAAICC4JAAAICC8JAAAICDAJAAAICDEJAAAICDIJAAAICDMJAAAICDQJAAAICDUJAAAICDYJAAAICDcJAAAICDgJAAAICDkJAAAICDoJAAAICDsJAAAICDwJAAAICD0JAAAICD4JAAAICD8JAAAICEAJAAAICEEJAAAICEIJAAAICEMJAAAICEQJAAAICEUJAAAICEYJAAAICEcJAAAICEgJAAAICEkJAAAICEoJAAAICEsJAAAICEwJAAAICE0JAAAICE4JAAAICE8JAAAICFAJAAAICFEJAAAICFIJAAAICFMJAAAICFQJAAAICFUJAAAICFYJAAAICFcJAAAICFgJAAAICFkJAAAICFoJAAAICFsJAAAICFwJAAAICF0JAAAICF4JAAAICF8JAAAICGAJAAAICGEJAAAICGIJAAAICGMJAAAICGQJAAAICGUJAAAICGYJAAAICGcJAAAICGgJAAAICGkJAAAICGoJAAAICGsJAAAICGwJAAAICG0JAAAICG4JAAAICG8JAAAICHAJAAAICHEJAAAICHIJAAAICHMJAAAICHQJAAAICHUJAAAICHYJAAAICHcJAAAICHgJAAAICHkJAAAICHoJAAAICHsJAAAICHwJAAAICH0JAAAICH4JAAAICH8JAAAICIAJAAAICIEJAAAICIIJAAAICIMJAAAICIQJAAAICIUJAAAICIYJAAAICIcJAAAICIgJAAAICIkJAAAICIoJAAAICIsJAAAICIwJAAAICI0JAAAICI4JAAAICI8JAAAICJAJAAAICJEJAAAICJIJAAAICJMJAAAICJQJAAAICJUJAAAICJYJAAAICJcJAAAICJgJAAAICJkJAAAICJoJAAAICJsJAAAICJwJAAAICJ0JAAAICJ4JAAAICJ8JAAAICKAJAAAICKEJAAAICKIJAAAICKMJAAAICKQJAAAICKUJAAAICKYJAAAICKcJAAAICKgJAAAICKkJAAAICKoJAAAICKsJAAAICKwJAAAICK0JAAAICK4JAAAICK8JAAAICLAJAAAICLEJAAAICLIJAAAICLMJAAAICLQJAAAICLUJAAAICLYJAAAICLcJAAAICLgJAAAICLkJAAAICLoJAAAICLsJAAAICLwJAAAICL0JAAAICL4JAAAICL8JAAAICMAJAAAICMEJAAAICMIJAAAICMMJAAAICMQJAAAICMUJAAAICMYJAAAICMcJAAAICMgJAAAICMkJAAAICMoJAAAICMsJAAAICMwJAAAICM0JAAAICM4JAAAICM8JAAAICNAJAAAICNEJAAAICNIJAAAICNMJAAAICNQJAAAICNUJAAAICNYJAAAICNcJAAAICNgJAAAICNkJAAAICNoJAAAICNsJAAAICNwJAAAICN0JAAAICN4JAAAICN8JAAAICOAJAAAICOEJAAAICOIJAAAICOMJAAAICOQJAAAICOUJAAAICOYJAAAICOcJAAAICOgJAAAICOkJAAAICOoJAAAICOsJAAAICOwJAAAICO0JAAAICO4JAAAICO8JAAAICPAJAAAICPEJAAAICPIJAAAICPMJAAAICPQJAAAICPUJAAAICPYJAAAICPcJAAAICPgJAAAICPkJAAAICPoJAAAICPsJAAAICPwJAAAICP0JAAAICP4JAAAICP8JAAAICAAKAAAICAEKAAAICAIKAAAICAMKAAAICAQKAAAICAUKAAAICAYKAAAICAcKAAAICAgKAAAICAkKAAAICAoKAAAICAsKAAAICAwKAAAICA0KAAAICA4KAAAICA8KAAAICBAKAAAICBEKAAAICBIKAAAICBMKAAAICBQKAAAICBUKAAAICBYKAAAICBcKAAAICBgKAAAICBkKAAAICBoKAAAICBsKAAAICBwKAAAICB0KAAAICB4KAAAICB8KAAAICCAKAAAICCEKAAAICCIKAAAICCMKAAAICCQKAAAICCUKAAAICCYKAAAICCcKAAAICCgKAAAICCkKAAAICCoKAAAICCsKAAAICCwKAAAICC0KAAAICC4KAAAICC8KAAAICDAKAAAICDEKAAAICDIKAAAICDMKAAAICDQKAAAICDUKAAAICDYKAAAICDcKAAAICDgKAAAICDkKAAAICDoKAAAICDsKAAAICDwKAAAICD0KAAAICD4KAAAICD8KAAAICEAKAAAICEEKAAAICEIKAAAICEMKAAAICEQKAAAICEUKAAAICEYKAAAICEcKAAAICEgKAAAICEkKAAAICEoKAAAICEsKAAAICEwKAAAICE0KAAAICE4KAAAICE8KAAAICFAKAAAICFEKAAAICFIKAAAICFMKAAAICFQKAAAICFUKAAAICFYKAAAICFcKAAAICFgKAAAICFkKAAAICFoKAAAICFsKAAAICFwKAAAICF0KAAAICF4KAAAICF8KAAAICGAKAAAICGEKAAAICGIKAAAICGMKAAAICGQKAAAICGUKAAAICGYKAAAICGcKAAAICGgKAAAICGkKAAAICGoKAAAICGsKAAAICGwKAAAICG0KAAAICG4KAAAICG8KAAAICHAKAAAICHEKAAAICHIKAAAICHMKAAAICHQKAAAICHUKAAAICHYKAAAICHcKAAAICHgKAAAICHkKAAAICHoKAAAICHsKAAAICHwKAAAICH0KAAAICH4KAAAICH8KAAAICIAKAAAICIEKAAAICIIKAAAICIMKAAAICIQKAAAICIUKAAAICIYKAAAICIcKAAAICIgKAAAICIkKAAAICIoKAAAICIsKAAAICIwKAAAICI0KAAAICI4KAAAICI8KAAAICJAKAAAICJEKAAAICJIKAAAICJMKAAAICJQKAAAICJUKAAAICJYKAAAICJcKAAAICJgKAAAICJkKAAAICJoKAAAICJsKAAAICJwKAAAICJ0KAAAICJ4KAAAICJ8KAAAICKAKAAAICKEKAAAICKIKAAAICKMKAAAICKQKAAAICKUKAAAICKYKAAAICKcKAAAICKgKAAAICKkKAAAICKoKAAAICKsKAAAICKwKAAAICK0KAAAICK4KAAAICK8KAAAICLAKAAAICLEKAAAICLIKAAAICLMKAAAICLQKAAAICLUKAAAICLYKAAAICLcKAAAICLgKAAAICLkKAAAICLoKAAAICLsKAAAICLwKAAAICL0KAAAICL4KAAAICL8KAAAICMAKAAAICMEKAAAICMIKAAAICMMKAAAICMQKAAAICMUKAAAICMYKAAAICMcKAAAICMgKAAAICMkKAAAICMoKAAAICMsKAAAICMwKAAAICM0KAAAICM4KAAAICM8KAAAICNAKAAAICNEKAAAICNIKAAAICNMKAAAICNQKAAAICNUKAAAICNYKAAAICNcKAAAICNgKAAAICNkKAAAICNoKAAAICNsKAAAICNwKAAAICN0KAAAICN4KAAAICN8KAAAICOAKAAAICOEKAAAICOIKAAAICOMKAAAICOQKAAAICOUKAAAICOYKAAAICOcKAAAICOgKAAAICOkKAAAICOoKAAAICOsKAAAICOwKAAAICO0KAAAICO4KAAAICO8KAAAICPAKAAAICPEKAAAICPIKAAAICPMKAAAICPQKAAAICPUKAAAICPYKAAAICPcKAAAICPgKAAAICPkKAAAICPoKAAAICPsKAAAICPwKAAAICP0KAAAICP4KAAAICP8KAAAICAALAAAICAELAAAICAILAAAICAMLAAAICAQLAAAICAULAAAICAYLAAAICAcLAAAICAgLAAAICAkLAAAICAoLAAAICAsLAAAICAwLAAAICA0LAAAICA4LAAAICA8LAAAICBALAAAICBELAAAICBILAAAICBMLAAAICBQLAAAICBULAAAICBYLAAAICBcLAAAICBgLAAAICBkLAAAICBoLAAAICBsLAAAICBwLAAAICB0LAAAICB4LAAAICB8LAAAICCALAAAICCELAAAICCILAAAICCMLAAAICCQLAAAICCULAAAICCYLAAAICCcLAAAICCgLAAAICCkLAAAICCoLAAAICCsLAAAICCwLAAAICC0LAAAICC4LAAAICC8LAAAICDALAAAICDELAAAICDILAAAICDMLAAAICDQLAAAICDULAAAICDYLAAAICDcLAAAICDgLAAAICDkLAAAICDoLAAAICDsLAAAICDwLAAAICD0LAAAICD4LAAAICD8LAAAICEALAAAICEELAAAICEILAAAICEMLAAAICEQLAAAICEULAAAICEYLAAAICEcLAAAICEgLAAAICEkLAAAICEoLAAAICEsLAAAICEwLAAAICE0LAAAICE4LAAAICE8LAAAICFALAAAICFELAAAICFILAAAICFMLAAAICFQLAAAICFULAAAICFYLAAAICFcLAAAICFgLAAAICFkLAAAICFoLAAAICFsLAAAICFwLAAAICF0LAAAICF4LAAAICF8LAAAICGALAAAICGELAAAICGILAAAICGMLAAAICGQLAAAICGULAAAICGYLAAAICGcLAAAICGgLAAAICGkLAAAICGoLAAAICGsLAAAICGwLAAAICG0LAAAICG4LAAAICG8LAAAICHALAAAICHELAAAICHILAAAICHMLAAAICHQLAAAICHULAAAICHYLAAAICHcLAAAICHgLAAAICHkLAAAICHoLAAAICHsLAAAICHwLAAAICH0LAAAICH4LAAAICH8LAAAICIALAAAICIELAAAICIILAAAICIMLAAAICIQLAAAICIULAAAICIYLAAAICIcLAAAICIgLAAAICIkLAAAICIoLAAAICIsLAAAICIwLAAAICI0LAAAICI4LAAAICI8LAAAICJALAAAICJELAAAICJILAAAICJMLAAAICJQLAAAICJULAAAICJYLAAAICJcLAAAICJgLAAAICJkLAAAICJoLAAAICJsLAAAICJwLAAAICJ0LAAAICJ4LAAAICJ8LAAAICKALAAAICKELAAAICKILAAAICKMLAAAICKQLAAAICKULAAAICKYLAAAICKcLAAAICKgLAAAICKkLAAAICKoLAAAICKsLAAAICKwLAAAICK0LAAAICK4LAAAICK8LAAAICLALAAAICLELAAAICLILAAAICLMLAAAICLQLAAAICLULAAAICLYLAAAICLcLAAAICLgLAAAICLkLAAAICLoLAAAICLsLAAAICLwLAAAICL0LAAAICL4LAAAICL8LAAAICMALAAAICMELAAAICMILAAAICMMLAAAICMQLAAAICMULAAAICMYLAAAICMcLAAAICMgLAAAICMkLAAAICMoLAAAICMsLAAAICMwLAAAICM0LAAAICM4LAAAICM8LAAAICNALAAAICNELAAAICNILAAAICNMLAAAICNQLAAAICNULAAAICNYLAAAICNcLAAAICNgLAAAICNkLAAAICNoLAAAICNsLAAAICNwLAAAICN0LAAAICN4LAAAICN8LAAAICOALAAAICOELAAAICOILAAAICOMLAAAICOQLAAAICOULAAAICOYLAAAICOcLAAAICOgLAAAICOkLAAAICOoLAAAICOsLAAAICOwLAAAICO0LAAAICO4LAAAICO8LAAAICPALAAAICPELAAAICPILAAAICPMLAAAICPQLAAAICPULAAAICPYLAAAICPcLAAAICPgLAAAICPkLAAAICPoLAAAICPsLAAAICPwLAAAICP0LAAAICP4LAAAICP8LAAAICAAMAAAICAEMAAAICAIMAAAICAMMAAAICAQMAAAICAUMAAAICAYMAAAICAcMAAAICAgMAAAICAkMAAAICAoMAAAICAsMAAAICAwMAAAICA0MAAAICA4MAAAICA8MAAAICBAMAAAICBEMAAAICBIMAAAICBMMAAAICBQMAAAICBUMAAAICBYMAAAICBcMAAAICBgMAAAICBkMAAAICBoMAAAICBsMAAAICBwMAAAICB0MAAAICB4MAAAICB8MAAAICCAMAAAICCEMAAAICCIMAAAICCMMAAAICCQMAAAICCUMAAAICCYMAAAICCcMAAAICCgMAAAICCkMAAAICCoMAAAICCsMAAAICCwMAAAICC0MAAAICC4MAAAICC8MAAAICDAMAAAICDEMAAAICDIMAAAICDMMAAAICDQMAAAICDUMAAAICDYMAAAICDcMAAAICDgMAAAICDkMAAAICDoMAAAICDsMAAAICDwMAAAICD0MAAAICD4MAAAICD8MAAAICEAMAAAICEEMAAAICEIMAAAICEMMAAAICEQMAAAICEUMAAAICEYMAAAICEcMAAAICEgMAAAICEkMAAAICEoMAAAICEsMAAAICEwMAAAICE0MAAAICE4MAAAICE8MAAAICFAMAAAICFEMAAAICFIMAAAICFMMAAAICFQMAAAICFUMAAAICFYMAAAICFcMAAAICFgMAAAICFkMAAAICFoMAAAICFsMAAAICFwMAAAICF0MAAAICF4MAAAICF8MAAAICGAMAAAICGEMAAAICGIMAAAICGMMAAAICGQMAAAICGUMAAAICGYMAAAICGcMAAAICGgMAAAICGkMAAAICGoMAAAICGsMAAAICGwMAAAICG0MAAAICG4MAAAICG8MAAAICHAMAAAICHEMAAAICHIMAAAICHMMAAAICHQMAAAICHUMAAAICHYMAAAICHcMAAAICHgMAAAICHkMAAAICHoMAAAICHsMAAAICHwMAAAICH0MAAAICH4MAAAICH8MAAAICIAMAAAICIEMAAAICIIMAAAICIMMAAAICIQMAAAICIUMAAAICIYMAAAICIcMAAAICIgMAAAICIkMAAAICIoMAAAICIsMAAAICIwMAAAICI0MAAAICI4MAAAICI8MAAAICJAMAAAICJEMAAAICJIMAAAICJMMAAAICJQMAAAICJUMAAAICJYMAAAICJcMAAAICJgMAAAICJkMAAAICJoMAAAICJsMAAAICJwMAAAICJ0MAAAICJ4MAAAICJ8MAAAICKAMAAAICKEMAAAICKIMAAAICKMMAAAICKQMAAAICKUMAAAICKYMAAAICKcMAAAICKgMAAAICKkMAAAICKoMAAAICKsMAAAICKwMAAAICK0MAAAICK4MAAAICK8MAAAICLAMAAAICLEMAAAICLIMAAAICLMMAAAICLQMAAAICLUMAAAICLYMAAAICLcMAAAICLgMAAAICLkMAAAICLoMAAAICLsMAAAICLwMAAAICL0MAAAICL4MAAAICL8MAAAICMAMAAAICMEMAAAICMIMAAAICMMMAAAICMQMAAAICMUMAAAICMYMAAAICMcMAAAICMgMAAAICMkMAAAICMoMAAAICMsMAAAICMwMAAAICM0MAAAICM4MAAAICM8MAAAICNAMAAAICNEMAAAICNIMAAAICNMMAAAICNQMAAAICNUMAAAICNYMAAAICNcMAAAICNgMAAAICNkMAAAICNoMAAAICNsMAAAICNwMAAAICN0MAAAICN4MAAAICN8MAAAICOAMAAAICOEMAAAICOIMAAAICOMMAAAICOQMAAAICOUMAAAICOYMAAAICOcMAAAICOgMAAAICOkMAAAICOoMAAAICOsMAAAICOwMAAAICO0MAAAICO4MAAAICO8MAAAICPAMAAAICPEMAAAICPIMAAAICPMMAAAICPQMAAAICPUMAAAICPYMAAAICPcMAAAICPgMAAAICPkMAAAICPoMAAAICPsMAAAICPwMAAAICP0MAAAICP4MAAAICP8MAAAICAANAAAICAENAAAICAINAAAICAMNAAAICAQNAAAICAUNAAAICAYNAAAICAcNAAAICAgNAAAICAkNAAAICAoNAAAICAsNAAAICAwNAAAICA0NAAAICA4NAAAICA8NAAAICBANAAAICBENAAAICBINAAAICBMNAAAICBQNAAAICBUNAAAICBYNAAAICBcNAAAICBgNAAAICBkNAAAICBoNAAAICBsNAAAICBwNAAAICB0NAAAICB4NAAAICB8NAAAICCANAAAICCENAAAICCINAAAICCMNAAAICCQNAAAICCUNAAAICCYNAAAICCcNAAAICCgNAAAICCkNAAAICCoNAAAICCsNAAAICCwNAAAICC0NAAAICC4NAAAICC8NAAAICDANAAAICDENAAAICDINAAAICDMNAAAICDQNAAAICDUNAAAICDYNAAAICDcNAAAICDgNAAAICDkNAAAICDoNAAAICDsNAAAICDwNAAAICD0NAAAICD4NAAAICD8NAAAICEANAAAICEENAAAICEINAAAICEMNAAAICEQNAAAICEUNAAAICEYNAAAICEcNAAAICEgNAAAICEkNAAAICEoNAAAICEsNAAAICEwNAAAICE0NAAAICE4NAAAICE8NAAAICFANAAAICFENAAAICFINAAAICFMNAAAICFQNAAAICFUNAAAICFYNAAAICFcNAAAICFgNAAAICFkNAAAICFoNAAAICFsNAAAICFwNAAAICF0NAAAICF4NAAAICF8NAAAICGANAAAICGENAAAICGINAAAICGMNAAAICGQNAAAICGUNAAAICGYNAAAICGcNAAAICGgNAAAICGkNAAAICGoNAAAICGsNAAAICGwNAAAICG0NAAAICG4NAAAICG8NAAAICHANAAAICHENAAAICHINAAAICHMNAAAICHQNAAAICHUNAAAICHYNAAAICHcNAAAICHgNAAAICHkNAAAICHoNAAAICHsNAAAICHwNAAAICH0NAAAICH4NAAAICH8NAAAICIANAAAICIENAAAICIINAAAICIMNAAAICIQNAAAICIUNAAAICIYNAAAICIcNAAAICIgNAAAICIkNAAAICIoNAAAICIsNAAAICIwNAAAICI0NAAAICI4NAAAICI8NAAAICJANAAAICJENAAAICJINAAAICJMNAAAICJQNAAAICJUNAAAICJYNAAAICJcNAAAICJgNAAAICJkNAAAICJoNAAAICJsNAAAICJwNAAAICJ0NAAAICJ4NAAAICJ8NAAAICKANAAAICKENAAAICKINAAAICKMNAAAICKQNAAAICKUNAAAICKYNAAAICKcNAAAICKgNAAAICKkNAAAICKoNAAAICKsNAAAICKwNAAAICK0NAAAICK4NAAAICK8NAAAICLANAAAICLENAAAICLINAAAICLMNAAAICLQNAAAICLUNAAAICLYNAAAICLcNAAAICLgNAAAICLkNAAAICLoNAAAICLsNAAAICLwNAAAICL0NAAAICL4NAAAICL8NAAAICMANAAAICMENAAAICMINAAAICMMNAAAICMQNAAAICMUNAAAICMYNAAAICMcNAAAICMgNAAAICMkNAAAICMoNAAAICMsNAAAICMwNAAAICM0NAAAICM4NAAAICM8NAAAICNANAAAICNENAAAICNINAAAICNMNAAAICNQNAAAICNUNAAAICNYNAAAICNcNAAAICNgNAAAICNkNAAAICNoNAAAICNsNAAAICNwNAAAICN0NAAAICN4NAAAICN8NAAAICOANAAAICOENAAAICOINAAAICOMNAAAICOQNAAAICOUNAAAICOYNAAAICOcNAAAICOgNAAAICOkNAAAICOoNAAAICOsNAAAICOwNAAAICO0NAAAICO4NAAAICO8NAAAICPANAAAICPENAAAICPINAAAICPMNAAAICPQNAAAICPUNAAAICPYNAAAICPcNAAAICPgNAAAICPkNAAAICPoNAAAICPsNAAAICPwNAAAICP0NAAAICP4NAAAICP8NAAAICAAOAAAICAEOAAAICAIOAAAICAMOAAAICAQOAAAICAUOAAAICAYOAAAICAcOAAAICAgOAAAICAkOAAAICAoOAAAICAsOAAAICAwOAAAICA0OAAAICA4OAAAICA8OAAAICBAOAAAICBEOAAAICBIOAAAICBMOAAAICBQOAAAICBUOAAAICBYOAAAICBcOAAAICBgOAAAICBkOAAAICBoOAAAICBsOAAAICBwOAAAICB0OAAAICB4OAAAICB8OAAAICCAOAAAICCEOAAAICCIOAAAICCMOAAAICCQOAAAICCUOAAAICCYOAAAICCcOAAAICCgOAAAICCkOAAAICCoOAAAICCsOAAAICCwOAAAICC0OAAAICC4OAAAICC8OAAAICDAOAAAICDEOAAAICDIOAAAICDMOAAAICDQOAAAICDUOAAAICDYOAAAICDcOAAAICDgOAAAICDkOAAAICDoOAAAICDsOAAAICDwOAAAICD0OAAAICD4OAAAICD8OAAAICEAOAAAICEEOAAAICEIOAAAICEMOAAAICEQOAAAICEUOAAAICEYOAAAICEcOAAAICEgOAAAICEkOAAAICEoOAAAICEsOAAAICEwOAAAICE0OAAAICE4OAAAICE8OAAAICFAOAAAICFEOAAAICFIOAAAICFMOAAAICFQOAAAICFUOAAAICFYOAAAICFcOAAAICFgOAAAICFkOAAAICFoOAAAICFsOAAAICFwOAAAICF0OAAAICF4OAAAICF8OAAAICGAOAAAICGEOAAAICGIOAAAICGMOAAAICGQOAAAICGUOAAAICGYOAAAICGcOAAAICGgOAAAICGkOAAAICGoOAAAICGsOAAAICGwOAAAICG0OAAAICG4OAAAICG8OAAAICHAOAAAICHEOAAAICHIOAAAICHMOAAAICHQOAAAICHUOAAAICHYOAAAICHcOAAAICHgOAAAICHkOAAAICHoOAAAICHsOAAAICHwOAAAICH0OAAAICH4OAAAICH8OAAAICIAOAAAICIEOAAAICIIOAAAICIMOAAAICIQOAAAICIUOAAAICIYOAAAICIcOAAAICIgOAAAICIkOAAAICIoOAAAICIsOAAAICIwOAAAICI0OAAAICI4OAAAICI8OAAAICJAOAAAICJEOAAAICJIOAAAICJMOAAAICJQOAAAICJUOAAAICJYOAAAICJcOAAAICJgOAAAICJkOAAAICJoOAAAICJsOAAAICJwOAAAICJ0OAAAICJ4OAAAICJ8OAAAICKAOAAAICKEOAAAICKIOAAAICKMOAAAICKQOAAAICKUOAAAICKYOAAAICKcOAAAICKgOAAAICKkOAAAICKoOAAAICKsOAAAICKwOAAAICK0OAAAICK4OAAAICK8OAAAICLAOAAAICLEOAAAICLIOAAAICLMOAAAICLQOAAAICLUOAAAICLYOAAAICLcOAAAICLgOAAAICLkOAAAICLoOAAAICLsOAAAICLwOAAAICL0OAAAICL4OAAAICL8OAAAICMAOAAAICMEOAAAICMIOAAAICMMOAAAICMQOAAAICMUOAAAICMYOAAAICMcOAAAICMgOAAAICMkOAAAICMoOAAAICMsOAAAICMwOAAAICM0OAAAICM4OAAAICM8OAAAICNAOAAAICNEOAAAICNIOAAAICNMOAAAICNQOAAAICNUOAAAICNYOAAAICNcOAAAICNgOAAAICNkOAAAICNoOAAAICNsOAAAICNwOAAAICN0OAAAICN4OAAAICN8OAAAICOAOAAAICOEOAAAICOIOAAAICOMOAAAICOQOAAAICOUOAAAICOYOAAAICOcOAAAICOgOAAAICOkOAAAICOoOAAAICOsOAAAICOwOAAAICO0OAAAICO4OAAAICO8OAAAICPAOAAAICPEOAAAICPIOAAAICPMOAAAICPQOAAAICPUOAAAICPYOAAAICPcOAAAICPgOAAAICPkOAAAICPoOAAAICPsOAAAICPwOAAAICP0OAAAICP4OAAAICP8OAAAICAAPAAAICAEPAAAICAIPAAAICAMPAAAICAQPAAAICAUPAAAICAYPAAAICAcPAAAICAgPAAAICAkPAAAICAoPAAAICAsPAAAICAwPAAAICA0PAAAICA4PAAAICA8PAAAICBAPAAAICBEPAAAICBIPAAAICBMPAAAICBQPAAAICBUPAAAICBYPAAAICBcPAAAICBgPAAAICBkPAAAICBoPAAAICBsPAAAICBwPAAAICB0PAAAICB4PAAAICB8PAAAICCAPAAAICCEPAAAICCIPAAAICCMPAAAICCQPAAAICCUPAAAICCYPAAAICCcPAAAICCgPAAAICCkPAAAICCoPAAAICCsPAAAICCwPAAAICC0PAAAICC4PAAAICC8PAAAICDAPAAAICDEPAAAICDIPAAAICDMPAAAICDQPAAAICDUPAAAICDYPAAAICDcPAAAICDgPAAAICDkPAAAICDoPAAAICDsPAAAICDwPAAAICD0PAAAICD4PAAAICD8PAAAICEAPAAAICEEPAAAICEIPAAAICEMPAAAICEQPAAAICEUPAAAICEYPAAAICEcPAAAICEgPAAAICEkPAAAICEoPAAAICEsPAAAICEwPAAAICE0PAAAICE4PAAAICE8PAAAICFAPAAAICFEPAAAICFIPAAAICFMPAAAICFQPAAAICFUPAAAICFYPAAAICFcPAAAICFgPAAAICFkPAAAICFoPAAAICFsPAAAICFwPAAAICF0PAAAICF4PAAAICF8PAAAICGAPAAAICGEPAAAICGIPAAAICGMPAAAICGQPAAAICGUPAAAICGYPAAAICGcPAAAICGgPAAAICGkPAAAICGoPAAAICGsPAAAICGwPAAAICG0PAAAICG4PAAAICG8PAAAICHAPAAAICHEPAAAICHIPAAAICHMPAAAICHQPAAAICHUPAAAICHYPAAAICHcPAAAICHgPAAAICHkPAAAICHoPAAAICHsPAAAICHwPAAAICH0PAAAICH4PAAAICH8PAAAICIAPAAAICIEPAAAICIIPAAAICIMPAAAICIQPAAAICIUPAAAICIYPAAAICIcPAAAICIgPAAAICIkPAAAICIoPAAAICIsPAAAICIwPAAAICI0PAAAICI4PAAAICI8PAAAICJAPAAAICJEPAAAICJIPAAAICJMPAAAICJQPAAAICJUPAAAICJYPAAAICJcPAAAICJgPAAAICJkPAAAICJoPAAAICJsPAAAICJwPAAAICJ0PAAAICJ4PAAAICJ8PAAAICKAPAAAICKEPAAAICKIPAAAICKMPAAAICKQPAAAICKUPAAAICKYPAAAICKcPAAAICKgPAAAICKkPAAAICKoPAAAICKsPAAAICKwPAAAICK0PAAAICK4PAAAICK8PAAAICLAPAAAICLEPAAAICLIPAAAICLMPAAAICLQPAAAICLUPAAAICLYPAAAICLcPAAAICLgPAAAICLkPAAAICLoPAAAICLsPAAAICLwPAAAICL0PAAAICL4PAAAICL8PAAAICMAPAAAICMEPAAAICMIPAAAICMMPAAAICMQPAAAICMUPAAAICMYPAAAICMcPAAAICMgPAAAICMkPAAAICMoPAAAICMsPAAAICMwPAAAICM0PAAAICM4PAAAICM8PAAAICNAPAAAICNEPAAAICNIPAAAICNMPAAAICNQPAAAICNUPAAAICNYPAAAICNcPAAAICNgPAAAICNkPAAAICNoPAAAICNsPAAAICNwPAAAICN0PAAAICN4PAAAICN8PAAAICOAPAAAICOEPAAAICOIPAAAICOMPAAAICOQPAAAICOUPAAAICOYPAAAICOcPAAAICOgPAAAICOkPAAAICOoPAAAICOsPAAAICOwPAAAICO0PAAAICO4PAAAICO8PAAAICPAPAAAICPEPAAAICPIPAAAICPMPAAAICPQPAAAICPUPAAAICPYPAAAICPcPAAAICPgPAAAICPkPAAAICPoPAAAICPsPAAAICPwPAAAICP0PAAAICP4PAAAICP8PAAAICAAQAAAICAEQAAAICAIQAAAICAMQAAAICAQQAAAICAUQAAAICAYQAAAICAcQAAAICAgQAAAICAkQAAAICAoQAAAICAsQAAAICAwQAAAICA0QAAAICA4QAAAICA8QAAAICBAQAAAICBEQAAAICBIQAAAICBMQAAAICBQQAAAICBUQAAAICBYQAAAICBcQAAAICBgQAAAICBkQAAAICBoQAAAICBsQAAAICBwQAAAICB0QAAAICB4QAAAICB8QAAAICCAQAAAICCEQAAAICCIQAAAICCMQAAAICCQQAAAICCUQAAAICCYQAAAICCcQAAAICCgQAAAICCkQAAAICCoQAAAICCsQAAAICCwQAAAICC0QAAAICC4QAAAICC8QAAAICDAQAAAICDEQAAAICDIQAAAICDMQAAAICDQQAAAICDUQAAAICDYQAAAICDcQAAAICDgQAAAICDkQAAAICDoQAAAICDsQAAAICDwQAAAICD0QAAAICD4QAAAICD8QAAAICEAQAAAICEEQAAAICEIQAAAICEMQAAAICEQQAAAICEUQAAAICEYQAAAICEcQAAAICEgQAAAICEkQAAAICEoQAAAICEsQAAAICEwQAAAICE0QAAAICE4QAAAICE8QAAAICFAQAAAICFEQAAAICFIQAAAICFMQAAAICFQQAAAICFUQAAAICFYQAAAICFcQAAAICFgQAAAICFkQAAAICFoQAAAICFsQAAAICFwQAAAICF0QAAAICF4QAAAICF8QAAAICGAQAAAICGEQAAAICGIQAAAICGMQAAAICGQQAAAICGUQAAAICGYQAAAICGcQAAAICGgQAAAICGkQAAAICGoQAAAICGsQAAAICGwQAAAICG0QAAAICG4QAAAICG8QAAAICHAQAAAICHEQAAAICHIQAAAICHMQAAAICHQQAAAICHUQAAAICHYQAAAICHcQAAAICHgQAAAICHkQAAAICHoQAAAICHsQAAAICHwQAAAICH0QAAAICH4QAAAICH8QAAAICIAQAAAICIEQAAAICIIQAAAICIMQAAAICIQQAAAICIUQAAAICIYQAAAICIcQAAAICIgQAAAICIkQAAAICIoQAAAICIsQAAAICIwQAAAICI0QAAAICI4QAAAICI8QAAAICJAQAAAICJEQAAAICJIQAAAICJMQAAAICJQQAAAICJUQAAAICJYQAAAICJcQAAAICJgQAAAICJkQAAAICJoQAAAICJsQAAAICJwQAAAICJ0QAAAICJ4QAAAICJ8QAAAICKAQAAAICKEQAAAICKIQAAAICKMQAAAICKQQAAAICKUQAAAICKYQAAAICKcQAAAICKgQAAAICKkQAAAICKoQAAAICKsQAAAICKwQAAAICK0QAAAICK4QAAAICK8QAAAICLAQAAAICLEQAAAICLIQAAAICLMQAAAICLQQAAAICLUQAAAICLYQAAAICLcQAAAICLgQAAAICLkQAAAICLoQAAAICLsQAAAICLwQAAAICL0QAAAICL4QAAAICL8QAAAICMAQAAAICMEQAAAICMIQAAAICMMQAAAICMQQAAAICMUQAAAICMYQAAAICMcQAAAICMgQAAAICMkQAAAICMoQAAAICMsQAAAICMwQAAAICM0QAAAICM4QAAAICM8QAAAICNAQAAAICNEQAAAICNIQAAAICNMQAAAICNQQAAAICNUQAAAICNYQAAAICNcQAAAICNgQAAAICNkQAAAICNoQAAAICNsQAAAICNwQAAAICN0QAAAICN4QAAAICN8QAAAICOAQAAAICOEQAAAICOIQAAAICOMQAAAICOQQAAAICOUQAAAICOYQAAAICOcQAAAICOgQAAAICOkQAAAICOoQAAAICOsQAAAICOwQAAAICO0QAAAICO4QAAAICO8QAAAICPAQAAAICPEQAAAICPIQAAAICPMQAAAICPQQAAAICPUQAAAICPYQAAAICPcQAAAICPgQAAAICPkQAAAICPoQAAAICPsQAAAICPwQAAAICP0QAAAICP4QAAAICP8QAAAICAARAAAICAERAAAICAIRAAAICAMRAAAICAQRAAAICAURAAAICAYRAAAICAcRAAAICAgRAAAICAkRAAAICAoRAAAICAsRAAAICAwRAAAICA0RAAAICA4RAAAICA8RAAAICBARAAAICBERAAAICBIRAAAICBMRAAAICBQRAAAICBURAAAICBYRAAAICBcRAAAICBgRAAAICBkRAAAICBoRAAAICBsRAAAICBwRAAAICB0RAAAICB4RAAAICB8RAAAICCARAAAICCERAAAICCIRAAAICCMRAAAICCQRAAAICCURAAAICCYRAAAICCcRAAAICCgRAAAICCkRAAAICCoRAAAICCsRAAAICCwRAAAICC0RAAAICC4RAAAICC8RAAAICDARAAAICDERAAAICDIRAAAICDMRAAAICDQRAAAICDURAAAICDYRAAAICDcRAAAICDgRAAAICDkRAAAICDoRAAAICDsRAAAICDwRAAAICD0RAAAICD4RAAAICD8RAAAICEARAAAICEERAAAICEIRAAAICEMRAAAICEQRAAAICEURAAAICEYRAAAICEcRAAAICEgRAAAICEkRAAAICEoRAAAICEsRAAAICEwRAAAICE0RAAAICE4RAAAICE8RAAAICFARAAAICFERAAAICFIRAAAICFMRAAAICFQRAAAICFURAAAICFYRAAAICFcRAAAICFgRAAAICFkRAAAICFoRAAAICFsRAAAICFwRAAAICF0RAAAICF4RAAAICF8RAAAICGARAAAICGERAAAICGIRAAAICGMRAAAICGQRAAAICGURAAAICGYRAAAICGcRAAAICGgRAAAICGkRAAAICGoRAAAICGsRAAAICGwRAAAICG0RAAAICG4RAAAICG8RAAAICHARAAAICHERAAAICHIRAAAICHMRAAAICHQRAAAICHURAAAICHYRAAAICHcRAAAICHgRAAAICHkRAAAICHoRAAAICHsRAAAICHwRAAAICH0RAAAICH4RAAAICH8RAAAICIARAAAICIERAAAICIIRAAAICIMRAAAICIQRAAAICIURAAAICIYRAAAICIcRAAAICIgRAAAICIkRAAAICIoRAAAICIsRAAAICIwRAAAICI0RAAAICI4RAAAICI8RAAAICJARAAAICJERAAAICJIRAAAICJMRAAAICJQRAAAICJURAAAICJYRAAAICJcRAAAICJgRAAAICJkRAAAICJoRAAAICJsRAAAICJwRAAAICJ0RAAAICJ4RAAAICJ8RAAAICKARAAAICKERAAAICKIRAAAICKMRAAAICKQRAAAICKURAAAICKYRAAAICKcRAAAICKgRAAAICKkRAAAICKoRAAAICKsRAAAICKwRAAAICK0RAAAICK4RAAAICK8RAAAICLARAAAICLERAAAICLIRAAAICLMRAAAICLQRAAAICLURAAAICLYRAAAICLcRAAAICLgRAAAICLkRAAAICLoRAAAICLsRAAAICLwRAAAICL0RAAAICL4RAAAICL8RAAAICMARAAAICMERAAAICMIRAAAICMMRAAAICMQRAAAICMURAAAICMYRAAAICMcRAAAICMgRAAAICMkRAAAICMoRAAAICMsRAAAICMwRAAAICM0RAAAICM4RAAAICM8RAAAICNARAAAICNERAAAICNIRAAAICNMRAAAICNQRAAAICNURAAAICNYRAAAICNcRAAAICNgRAAAICNkRAAAICNoRAAAICNsRAAAICNwRAAAICN0RAAAICN4RAAAICN8RAAAICOARAAAICOERAAAICOIRAAAICOMRAAAICOQRAAAICOURAAAICOYRAAAICOcRAAAICOgRAAAICOkRAAAICOoRAAAICOsRAAAICOwRAAAICO0RAAAICO4RAAAICO8RAAAICPARAAAICPERAAAICPIRAAAICPMRAAAICPQRAAAICPURAAAICPYRAAAICPcRAAAICPgRAAAICPkRAAAICPoRAAAICPsRAAAICPwRAAAICP0RAAAICP4RAAAICP8RAAAICAASAAAICAESAAAICAISAAAICAMSAAAICAQSAAAICAUSAAAICAYSAAAICAcSAAAICAgSAAAICAkSAAAICAoSAAAICAsSAAAICAwSAAAICA0SAAAICA4SAAAICA8SAAAICBASAAAICBESAAAICBISAAAICBMSAAAICBQSAAAICBUSAAAICBYSAAAICBcSAAAICBgSAAAICBkSAAAICBoSAAAICBsSAAAICBwSAAAICB0SAAAICB4SAAAICB8SAAAICCASAAAICCESAAAICCISAAAICCMSAAAICCQSAAAICCUSAAAICCYSAAAICCcSAAAICCgSAAAICCkSAAAICCoSAAAICCsSAAAICCwSAAAICC0SAAAICC4SAAAICC8SAAAICDASAAAICDESAAAICDISAAAICDMSAAAICDQSAAAICDUSAAAICDYSAAAICDcSAAAICDgSAAAICDkSAAAICDoSAAAICDsSAAAICDwSAAAICD0SAAAICD4SAAAICD8SAAAICEASAAAICEESAAAICEISAAAICEMSAAAICEQSAAAICEUSAAAICEYSAAAICEcSAAAICEgSAAAICEkSAAAICEoSAAAICEsSAAAICEwSAAAICE0SAAAICE4SAAAICE8SAAAICFASAAAICFESAAAICFISAAAICFMSAAAICFQSAAAICFUSAAAICFYSAAAICFcSAAAICFgSAAAICFkSAAAICFoSAAAICFsSAAAICFwSAAAICF0SAAAICF4SAAAICF8SAAAICGASAAAICGESAAAICGISAAAICGMSAAAICGQSAAAICGUSAAAICGYSAAAICGcSAAAICGgSAAAICGkSAAAICGoSAAAICGsSAAAICGwSAAAICG0SAAAICG4SAAAICG8SAAAICHASAAAICHESAAAICHISAAAICHMSAAAICHQSAAAICHUSAAAICHYSAAAICHcSAAAICHgSAAAICHkSAAAICHoSAAAICHsSAAAICHwSAAAICH0SAAAICH4SAAAICH8SAAAICIASAAAICIESAAAICIISAAAICIMSAAAICIQSAAAICIUSAAAICIYSAAAICIcSAAAICIgSAAAICIkSAAAICIoSAAAICIsSAAAICIwSAAAICI0SAAAICI4SAAAICI8SAAAICJASAAAICJESAAAICJISAAAICJMSAAAICJQSAAAICJUSAAAICJYSAAAICJcSAAAICJgSAAAICJkSAAAICJoSAAAICJsSAAAICJwSAAAICJ0SAAAICJ4SAAAICJ8SAAAICKASAAAICKESAAAICKISAAAICKMSAAAICKQSAAAICKUSAAAICKYSAAAICKcSAAAICKgSAAAICKkSAAAICKoSAAAICKsSAAAICKwSAAAICK0SAAAICK4SAAAICK8SAAAICLASAAAICLESAAAICLISAAAICLMSAAAICLQSAAAICLUSAAAICLYSAAAICLcSAAAICLgSAAAICLkSAAAICLoSAAAICLsSAAAICLwSAAAICL0SAAAICL4SAAAICL8SAAAICMASAAAICMESAAAICMISAAAICMMSAAAICMQSAAAICMUSAAAICMYSAAAICMcSAAAICMgSAAAICMkSAAAICMoSAAAICMsSAAAICMwSAAAICM0SAAAICM4SAAAICM8SAAAICNASAAAICNESAAAICNISAAAICNMSAAAICNQSAAAICNUSAAAICNYSAAAICNcSAAAICNgSAAAICNkSAAAICNoSAAAICNsSAAAICNwSAAAICN0SAAAICN4SAAAICN8SAAAICOASAAAICOESAAAICOISAAAICOMSAAAICOQSAAAICOUSAAAICOYSAAAICOcSAAAICOgSAAAICOkSAAAICOoSAAAICOsSAAAICOwSAAAICO0SAAAICO4SAAAICO8SAAAICPASAAAICPESAAAICPISAAAICPMSAAAICPQSAAAICPUSAAAICPYSAAAICPcSAAAICPgSAAAICPkSAAAICPoSAAAICPsSAAAICPwSAAAICP0SAAAICP4SAAAICP8SAAAICAATAAAICAETAAAICAITAAAICAMTAAAICAQTAAAICAUTAAAICAYTAAAICAcTAAAICAgTAAAICAkTAAAICAoTAAAICAsTAAAICAwTAAAICA0TAAAICA4TAAAICA8TAAAICBATAAAICBETAAAICBITAAAICBMTAAAICBQTAAAICBUTAAAICBYTAAAICBcTAAAICBgTAAAICBkTAAAICBoTAAAICBsTAAAICBwTAAAICB0TAAAICB4TAAAICB8TAAAICCATAAAICCETAAAICCITAAAICCMTAAAICCQTAAAICCUTAAAICCYTAAAICCcTAAAICCgTAAAICCkTAAAICCoTAAAICCsTAAAICCwTAAAICC0TAAAICC4TAAAICC8TAAAICDATAAAICDETAAAICDITAAAICDMTAAAICDQTAAAICDUTAAAICDYTAAAICDcTAAAICDgTAAAICDkTAAAICDoTAAAICDsTAAAICDwTAAAICD0TAAAICD4TAAAICD8TAAAICEATAAAICEETAAAICEITAAAICEMTAAAICEQTAAAICEUTAAAICEYTAAAICEcTAAAICEgTAAAICEkTAAAICEoTAAAICEsTAAAICEwTAAAICE0TAAAICE4TAAAICE8TAAAICFATAAAICFETAAAICFITAAAICFMTAAAICFQTAAAICFUTAAAICFYTAAAICFcTAAAICFgTAAAICFkTAAAICFoTAAAICFsTAAAICFwTAAAICF0TAAAICF4TAAAICF8TAAAICGATAAAICGETAAAICGITAAAICGMTAAAICGQTAAAICGUTAAAICGYTAAAICGcTAAAICGgTAAAICGkTAAAICGoTAAAICGsTAAAICGwTAAAICG0TAAAICG4TAAAICG8TAAAICHATAAAICHETAAAICHITAAAICHMTAAAICHQTAAAICHUTAAAICHYTAAAICHcTAAAICHgTAAAICHkTAAAICHoTAAAICHsTAAAICHwTAAAICH0TAAAICH4TAAAICH8TAAAICIATAAAICIETAAAICIITAAAICIMTAAAICIQTAAAICIUTAAAICIYTAAAICIcTAAAICIgTAAAICIkTAAAICIoTAAAICIsTAAAICIwTAAAICI0TAAAICI4TAAAICI8TAAAICJATAAAICJETAAAICJITAAAICJMTAAAICJQTAAAICJUTAAAICJYTAAAICJcTAAAICJgTAAAICJkTAAAICJoTAAAICJsTAAAICJwTAAAICJ0TAAAICJ4TAAAICJ8TAAAICKATAAAICKETAAAICKITAAAICKMTAAAICKQTAAAICKUTAAAICKYTAAAICKcTAAAICKgTAAAICKkTAAAICKoTAAAICKsTAAAICKwTAAAICK0TAAAICK4TAAAICK8TAAAICLATAAAICLETAAAICLITAAAICLMTAAAICLQTAAAICLUTAAAICLYTAAAICLcTAAAICLgTAAAICLkTAAAICLoTAAAICLsTAAAICLwTAAAICL0TAAAICL4TAAAICL8TAAAICMATAAAICMETAAAICMITAAAICMMTAAAICMQTAAAICMUTAAAICMYTAAAICMcTAAAICMgTAAAICMkTAAAICMoTAAAICMsTAAAICMwTAAAICM0TAAAICM4TAAAICM8TAAAICNATAAAICNETAAAICNITAAAICNMTAAAICNQTAAAICNUTAAAICNYTAAAICNcTAAAICNgTAAAICNkTAAAICNoTAAAICNsTAAAICNwTAAAICN0TAAAICN4TAAAICN8TAAAICOATAAAICOETAAAICOITAAAICOMTAAAICOQTAAAICOUTAAAICOYTAAAICOcTAAAICOgTAAAICOkTAAAICOoTAAAICOsTAAAICOwTAAAICO0TAAAICO4TAAAICO8TAAAICPATAAAICPETAAAICPITAAAICPMTAAAICPQTAAAICPUTAAAICPYTAAAICPcTAAAICPgTAAAICPkTAAAICPoTAAAICPsTAAAICPwTAAAICP0TAAAICP4TAAAICP8TAAAICAAUAAAICAEUAAAICAIUAAAICAMUAAAICAQUAAAICAUUAAAICAYUAAAICAcUAAAICAgUAAAICAkUAAAICAoUAAAICAsUAAAICAwUAAAICA0UAAAICA4UAAAICA8UAAAICBAUAAAICBEUAAAICBIUAAAICBMUAAAICBQUAAAICBUUAAAICBYUAAAICBcUAAAICBgUAAAICBkUAAAICBoUAAAICBsUAAAICBwUAAAICB0UAAAICB4UAAAICB8UAAAICCAUAAAICCEUAAAICCIUAAAICCMUAAAICCQUAAAICCUUAAAICCYUAAAICCcUAAAICCgUAAAICCkUAAAICCoUAAAICCsUAAAICCwUAAAICC0UAAAICC4UAAAICC8UAAAICDAUAAAICDEUAAAICDIUAAAICDMUAAAICDQUAAAICDUUAAAICDYUAAAICDcUAAAICDgUAAAICDkUAAAICDoUAAAICDsUAAAICDwUAAAICD0UAAAICD4UAAAICD8UAAAICEAUAAAICEEUAAAICEIUAAAICEMUAAAICEQUAAAICEUUAAAICEYUAAAICEcUAAAICEgUAAAICEkUAAAICEoUAAAICEsUAAAICEwUAAAICE0UAAAICE4UAAAICE8UAAAICFAUAAAICFEUAAAICFIUAAAICFMUAAAICFQUAAAICFUUAAAICFYUAAAICFcUAAAICFgUAAAICFkUAAAICFoUAAAICFsUAAAICFwUAAAICF0UAAAICF4UAAAICF8UAAAICGAUAAAICGEUAAAICGIUAAAICGMUAAAICGQUAAAICGUUAAAICGYUAAAICGcUAAAICGgUAAAICGkUAAAICGoUAAAICGsUAAAICGwUAAAICG0UAAAICG4UAAAICG8UAAAICHAUAAAICHEUAAAICHIUAAAICHMUAAAICHQUAAAICHUUAAAICHYUAAAICHcUAAAICHgUAAAICHkUAAAICHoUAAAICHsUAAAICHwUAAAICH0UAAAICH4UAAAICH8UAAAICIAUAAAICIEUAAAICIIUAAAICIMUAAAICIQUAAAICIUUAAAICIYUAAAICIcUAAAICIgUAAAICIkUAAAICIoUAAAICIsUAAAICIwUAAAICI0UAAAICI4UAAAICI8UAAAICJAUAAAICJEUAAAICJIUAAAICJMUAAAICJQUAAAICJUUAAAICJYUAAAICJcUAAAICJgUAAAICJkUAAAICJoUAAAICJsUAAAICJwUAAAICJ0UAAAICJ4UAAAICJ8UAAAICKAUAAAICKEUAAAICKIUAAAICKMUAAAICKQUAAAICKUUAAAICKYUAAAICKcUAAAICKgUAAAICKkUAAAICKoUAAAICKsUAAAICKwUAAAICK0UAAAICK4UAAAICK8UAAAICLAUAAAICLEUAAAICLIUAAAICLMUAAAICLQUAAAICLUUAAAICLYUAAAICLcUAAAICLgUAAAICLkUAAAICLoUAAAICLsUAAAICLwUAAAICL0UAAAICL4UAAAICL8UAAAICMAUAAAICMEUAAAICMIUAAAICMMUAAAICMQUAAAICMUUAAAICMYUAAAICMcUAAAICMgUAAAICMkUAAAICMoUAAAICMsUAAAICMwUAAAICM0UAAAICM4UAAAICM8UAAAICNAUAAAICNEUAAAICNIUAAAICNMUAAAICNQUAAAICNUUAAAICNYUAAAICNcUAAAICNgUAAAICNkUAAAICNoUAAAICNsUAAAICNwUAAAICN0UAAAICN4UAAAICN8UAAAICOAUAAAICOEUAAAICOIUAAAICOMUAAAICOQUAAAICOUUAAAICOYUAAAICOcUAAAICOgUAAAICOkUAAAICOoUAAAICOsUAAAICOwUAAAICO0UAAAICO4UAAAICO8UAAAICPAUAAAICPEUAAAICPIUAAAICPMUAAAICPQUAAAICPUUAAAICPYUAAAICPcUAAAICPgUAAAICPkUAAAICPoUAAAICPsUAAAICPwUAAAICP0UAAAICP4UAAAICP8UAAAICAAVAAAICAEVAAAICAIVAAAICAMVAAAICAQVAAAICAUVAAAICAYVAAAICAcVAAAICAgVAAAICAkVAAAICAoVAAAICAsVAAAICAwVAAAICA0VAAAICA4VAAAICA8VAAAICBAVAAAICBEVAAAICBIVAAAICBMVAAAICBQVAAAICBUVAAAICBYVAAAICBcVAAAICBgVAAAICBkVAAAICBoVAAAICBsVAAAICBwVAAAICB0VAAAICB4VAAAICB8VAAAICCAVAAAICCEVAAAICCIVAAAICCMVAAAICCQVAAAICCUVAAAICCYVAAAICCcVAAAICCgVAAAICCkVAAAICCoVAAAICCsVAAAICCwVAAAICC0VAAAICC4VAAAICC8VAAAICDAVAAAICDEVAAAICDIVAAAICDMVAAAICDQVAAAICDUVAAAICDYVAAAICDcVAAAICDgVAAAICDkVAAAICDoVAAAICDsVAAAICDwVAAAICD0VAAAICD4VAAAICD8VAAAICEAVAAAICEEVAAAICEIVAAAICEMVAAAICEQVAAAICEUVAAAICEYVAAAICEcVAAAICEgVAAAICEkVAAAICEoVAAAICEsVAAAICEwVAAAICE0VAAAICE4VAAAICE8VAAAICFAVAAAICFEVAAAICFIVAAAICFMVAAAICFQVAAAICFUVAAAICFYVAAAICFcVAAAICFgVAAAICFkVAAAICFoVAAAICFsVAAAICFwVAAAICF0VAAAICF4VAAAICF8VAAAICGAVAAAICGEVAAAICGIVAAAICGMVAAAICGQVAAAICGUVAAAICGYVAAAICGcVAAAICGgVAAAICGkVAAAICGoVAAAICGsVAAAICGwVAAAICG0VAAAICG4VAAAICG8VAAAICHAVAAAICHEVAAAICHIVAAAICHMVAAAICHQVAAAICHUVAAAICHYVAAAICHcVAAAICHgVAAAICHkVAAAICHoVAAAICHsVAAAICHwVAAAICH0VAAAICH4VAAAICH8VAAAICIAVAAAICIEVAAAICIIVAAAICIMVAAAICIQVAAAICIUVAAAICIYVAAAICIcVAAAICIgVAAAICIkVAAAICIoVAAAICIsVAAAICIwVAAAICI0VAAAICI4VAAAICI8VAAAICJAVAAAICJEVAAAICJIVAAAICJMVAAAICJQVAAAICJUVAAAICJYVAAAICJcVAAAICJgVAAAICJkVAAAICJoVAAAICJsVAAAICJwVAAAICJ0VAAAICJ4VAAAICJ8VAAAICKAVAAAICKEVAAAICKIVAAAICKMVAAAICKQVAAAICKUVAAAICKYVAAAICKcVAAAICKgVAAAICKkVAAAICKoVAAAICKsVAAAICKwVAAAICK0VAAAICK4VAAAICK8VAAAICLAVAAAICLEVAAAICLIVAAAICLMVAAAICLQVAAAICLUVAAAICLYVAAAICLcVAAAICLgVAAAICLkVAAAICLoVAAAICLsVAAAICLwVAAAICL0VAAAICL4VAAAICL8VAAAICMAVAAAICMEVAAAICMIVAAAICMMVAAAICMQVAAAICMUVAAAICMYVAAAICMcVAAAICMgVAAAICMkVAAAICMoVAAAICMsVAAAICMwVAAAICM0VAAAICM4VAAAICM8VAAAICNAVAAAICNEVAAAICNIVAAAICNMVAAAICNQVAAAICNUVAAAICNYVAAAICNcVAAAICNgVAAAICNkVAAAICNoVAAAICNsVAAAICNwVAAAICN0VAAAICN4VAAAICN8VAAAICOAVAAAICOEVAAAICOIVAAAICOMVAAAICOQVAAAICOUVAAAICOYVAAAICOcVAAAICOgVAAAICOkVAAAICOoVAAAICOsVAAAICOwVAAAICO0VAAAICO4VAAAICO8VAAAICPAVAAAICPEVAAAICPIVAAAICPMVAAAICPQVAAAICPUVAAAICPYVAAAICPcVAAAICPgVAAAICPkVAAAICPoVAAAICPsVAAAICPwVAAAICP0VAAAICP4VAAAICP8VAAAICAAWAAAICAEWAAAICAIWAAAICAMWAAAICAQWAAAICAUWAAAICAYWAAAICAcWAAAICAgWAAAICAkWAAAICAoWAAAICAsWAAAICAwWAAAICA0WAAAICA4WAAAICA8WAAAICBAWAAAICBEWAAAICBIWAAAICBMWAAAICBQWAAAICBUWAAAICBYWAAAICBcWAAAICBgWAAAICBkWAAAICBoWAAAICBsWAAAICBwWAAAICB0WAAAICB4WAAAICB8WAAAICCAWAAAICCEWAAAICCIWAAAICCMWAAAICCQWAAAICCUWAAAICCYWAAAICCcWAAAICCgWAAAICCkWAAAICCoWAAAICCsWAAAICCwWAAAICC0WAAAICC4WAAAICC8WAAAICDAWAAAICDEWAAAICDIWAAAICDMWAAAICDQWAAAICDUWAAAICDYWAAAICDcWAAAICDgWAAAICDkWAAAICDoWAAAICDsWAAAICDwWAAAICD0WAAAICD4WAAAICD8WAAAICEAWAAAICEEWAAAICEIWAAAICEMWAAAICEQWAAAICEUWAAAICEYWAAAICEcWAAAICEgWAAAICEkWAAAICEoWAAAICEsWAAAICEwWAAAICE0WAAAICE4WAAAICE8WAAAICFAWAAAICFEWAAAICFIWAAAICFMWAAAICFQWAAAICFUWAAAICFYWAAAICFcWAAAICFgWAAAICFkWAAAICFoWAAAICFsWAAAICFwWAAAICF0WAAAICF4WAAAICF8WAAAICGAWAAAICGEWAAAICGIWAAAICGMWAAAICGQWAAAICGUWAAAICGYWAAAICGcWAAAICGgWAAAICGkWAAAICGoWAAAICGsWAAAICGwWAAAICG0WAAAICG4WAAAICG8WAAAICHAWAAAICHEWAAAICHIWAAAICHMWAAAICHQWAAAICHUWAAAICHYWAAAICHcWAAAICHgWAAAICHkWAAAICHoWAAAICHsWAAAICHwWAAAICH0WAAAICH4WAAAICH8WAAAICIAWAAAICIEWAAAICIIWAAAICIMWAAAICIQWAAAICIUWAAAICIYWAAAICIcWAAAICIgWAAAICIkWAAAICIoWAAAICIsWAAAICIwWAAAICI0WAAAICI4WAAAICI8WAAAICJAWAAAICJEWAAAICJIWAAAICJMWAAAICJQWAAAICJUWAAAICJYWAAAICJcWAAAICJgWAAAICJkWAAAICJoWAAAICJsWAAAICJwWAAAICJ0WAAAICJ4WAAAICJ8WAAAICKAWAAAICKEWAAAICKIWAAAICKMWAAAICKQWAAAICKUWAAAICKYWAAAICKcWAAAICKgWAAAICKkWAAAICKoWAAAICKsWAAAICKwWAAAICK0WAAAICK4WAAAICK8WAAAICLAWAAAICLEWAAAICLIWAAAICLMWAAAICLQWAAAICLUWAAAICLYWAAAICLcWAAAICLgWAAAICLkWAAAICLoWAAAICLsWAAAICLwWAAAICL0WAAAICL4WAAAICL8WAAAICMAWAAAICMEWAAAICMIWAAAICMMWAAAICMQWAAAICMUWAAAICMYWAAAICMcWAAAICMgWAAAICMkWAAAICMoWAAAICMsWAAAICMwWAAAICM0WAAAICM4WAAAICM8WAAAICNAWAAAICNEWAAAICNIWAAAICNMWAAAICNQWAAAICNUWAAAICNYWAAAICNcWAAAICNgWAAAICNkWAAAICNoWAAAICNsWAAAICNwWAAAICN0WAAAICN4WAAAICN8WAAAICOAWAAAICOEWAAAICOIWAAAICOMWAAAICOQWAAAICOUWAAAICOYWAAAICOcWAAAICOgWAAAICOkWAAAICOoWAAAICOsWAAAICOwWAAAICO0WAAAICO4WAAAICO8WAAAICPAWAAAICPEWAAAICPIWAAAICPMWAAAICPQWAAAICPUWAAAICPYWAAAICPcWAAAICPgWAAAICPkWAAAICPoWAAAICPsWAAAICPwWAAAICP0WAAAICP4WAAAICP8WAAAICAAXAAAICAEXAAAICAIXAAAICAMXAAAICAQXAAAICAUXAAAICAYXAAAICAcXAAAICAgXAAAICAkXAAAICAoXAAAICAsXAAAICAwXAAAICA0XAAAICA4XAAAICA8XAAAICBAXAAAICBEXAAAICBIXAAAICBMXAAAICBQXAAAICBUXAAAICBYXAAAICBcXAAAICBgXAAAICBkXAAAICBoXAAAICBsXAAAICBwXAAAICB0XAAAICB4XAAAICB8XAAAICCAXAAAICCEXAAAICCIXAAAICCMXAAAICCQXAAAICCUXAAAICCYXAAAICCcXAAAICCgXAAAICCkXAAAICCoXAAAICCsXAAAICCwXAAAICC0XAAAICC4XAAAICC8XAAAICDAXAAAICDEXAAAICDIXAAAICDMXAAAICDQXAAAICDUXAAAICDYXAAAICDcXAAAICDgXAAAICDkXAAAICDoXAAAICDsXAAAICDwXAAAICD0XAAAICD4XAAAICD8XAAAICEAXAAAICEEXAAAICEIXAAAICEMXAAAICEQXAAAICEUXAAAICEYXAAAICEcXAAAICEgXAAAICEkXAAAICEoXAAAICEsXAAAICEwXAAAICE0XAAAICE4XAAAICE8XAAAICFAXAAAICFEXAAAICFIXAAAICFMXAAAICFQXAAAICFUXAAAICFYXAAAICFcXAAAICFgXAAAICFkXAAAICFoXAAAICFsXAAAICFwXAAAICF0XAAAICF4XAAAICF8XAAAICGAXAAAICGEXAAAICGIXAAAICGMXAAAICGQXAAAICGUXAAAICGYXAAAICGcXAAAICGgXAAAICGkXAAAICGoXAAAICGsXAAAICGwXAAAICG0XAAAICG4XAAAICG8XAAAICHAXAAAICHEXAAAICHIXAAAICHMXAAAICHQXAAAICHUXAAAICHYXAAAICHcXAAAICHgXAAAICHkXAAAICHoXAAAICHsXAAAICHwXAAAICH0XAAAICH4XAAAICH8XAAAICIAXAAAICIEXAAAICIIXAAAICIMXAAAICIQXAAAICIUXAAAICIYXAAAICIcXAAAICIgXAAAICIkXAAAICIoXAAAICIsXAAAICIwXAAAICI0XAAAICI4XAAAICI8XAAAICJAXAAAICJEXAAAICJIXAAAICJMXAAAICJQXAAAICJUXAAAICJYXAAAICJcXAAAICJgXAAAICJkXAAAICJoXAAAICJsXAAAICJwXAAAICJ0XAAAICJ4XAAAICJ8XAAAICKAXAAAICKEXAAAICKIXAAAICKMXAAAICKQXAAAICKUXAAAICKYXAAAICKcXAAAICKgXAAAICKkXAAAICKoXAAAICKsXAAAICKwXAAAICK0XAAAICK4XAAAICK8XAAAICLAXAAAICLEXAAAICLIXAAAICLMXAAAICLQXAAAICLUXAAAICLYXAAAICLcXAAAICLgXAAAICLkXAAAICLoXAAAICLsXAAAICLwXAAAICL0XAAAICL4XAAAICL8XAAAICMAXAAAICMEXAAAICMIXAAAICMMXAAAICMQXAAAICMUXAAAICMYXAAAICMcXAAAICMgXAAAICMkXAAAICMoXAAAICMsXAAAICMwXAAAICM0XAAAICM4XAAAICM8XAAAICNAXAAAICNEXAAAICNIXAAAICNMXAAAICNQXAAAICNUXAAAICNYXAAAICNcXAAAICNgXAAAICNkXAAAICNoXAAAICNsXAAAICNwXAAAICN0XAAAICN4XAAAICN8XAAAICOAXAAAICOEXAAAICOIXAAAICOMXAAAICOQXAAAICOUXAAAICOYXAAAICOcXAAAICOgXAAAICOkXAAAICOoXAAAICOsXAAAICOwXAAAICO0XAAAICO4XAAAICO8XAAAICPAXAAAICPEXAAAICPIXAAAICPMXAAAICPQXAAAICPUXAAAICPYXAAAICPcXAAAICPgXAAAICPkXAAAICPoXAAAICPsXAAAICPwXAAAICP0XAAAICP4XAAAICP8XAAAICAAYAAAICAEYAAAICAIYAAAICAMYAAAICAQYAAAICAUYAAAICAYYAAAICAcYAAAICAgYAAAICAkYAAAICAoYAAAICAsYAAAICAwYAAAICA0YAAAICA4YAAAICA8YAAAICBAYAAAICBEYAAAICBIYAAAICBMYAAAICBQYAAAICBUYAAAICBYYAAAICBcYAAAICBgYAAAICBkYAAAICBoYAAAICBsYAAAICBwYAAAICB0YAAAICB4YAAAICB8YAAAICCAYAAAICCEYAAAICCIYAAAICCMYAAAICCQYAAAICCUYAAAICCYYAAAICCcYAAAICCgYAAAICCkYAAAICCoYAAAICCsYAAAICCwYAAAICC0YAAAICC4YAAAICC8YAAAICDAYAAAICDEYAAAICDIYAAAICDMYAAAICDQYAAAICDUYAAAICDYYAAAICDcYAAAICDgYAAAICDkYAAAICDoYAAAICDsYAAAICDwYAAAICD0YAAAICD4YAAAICD8YAAAICEAYAAAICEEYAAAICEIYAAAICEMYAAAICEQYAAAICEUYAAAICEYYAAAICEcYAAAICEgYAAAICEkYAAAICEoYAAAICEsYAAAICEwYAAAICE0YAAAICE4YAAAICE8YAAAICFAYAAAICFEYAAAICFIYAAAICFMYAAAICFQYAAAICFUYAAAICFYYAAAICFcYAAAICFgYAAAICFkYAAAICFoYAAAICFsYAAAICFwYAAAICF0YAAAICF4YAAAICF8YAAAICGAYAAAICGEYAAAICGIYAAAICGMYAAAICGQYAAAICGUYAAAICGYYAAAICGcYAAAICGgYAAAICGkYAAAICGoYAAAICGsYAAAICGwYAAAICG0YAAAICG4YAAAICG8YAAAICHAYAAAICHEYAAAICHIYAAAICHMYAAAICHQYAAAICHUYAAAICHYYAAAICHcYAAAICHgYAAAICHkYAAAICHoYAAAICHsYAAAICHwYAAAICH0YAAAICH4YAAAICH8YAAAICIAYAAAICIEYAAAICIIYAAAICIMYAAAICIQYAAAICIUYAAAICIYYAAAICIcYAAAICIgYAAAICIkYAAAICIoYAAAICIsYAAAICIwYAAAICI0YAAAICI4YAAAICI8YAAAICJAYAAAICJEYAAAICJIYAAAICJMYAAAICJQYAAAICJUYAAAICJYYAAAICJcYAAAICJgYAAAICJkYAAAICJoYAAAICJsYAAAICJwYAAAICJ0YAAAICJ4YAAAICJ8YAAAICKAYAAAICKEYAAAICKIYAAAICKMYAAAICKQYAAAICKUYAAAICKYYAAAICKcYAAAICKgYAAAICKkYAAAICKoYAAAICKsYAAAICKwYAAAICK0YAAAICK4YAAAICK8YAAAICLAYAAAICLEYAAAICLIYAAAICLMYAAAICLQYAAAICLUYAAAICLYYAAAICLcYAAAICLgYAAAICLkYAAAICLoYAAAICLsYAAAICLwYAAAICL0YAAAICL4YAAAICL8YAAAICMAYAAAICMEYAAAICMIYAAAICMMYAAAICMQYAAAICMUYAAAICMYYAAAICMcYAAAICMgYAAAICMkYAAAICMoYAAAICMsYAAAICMwYAAAICM0YAAAICM4YAAAICM8YAAAICNAYAAAICNEYAAAICNIYAAAICNMYAAAICNQYAAAICNUYAAAICNYYAAAICNcYAAAICNgYAAAICNkYAAAICNoYAAAICNsYAAAICNwYAAAICN0YAAAICN4YAAAICN8YAAAICOAYAAAICOEYAAAICOIYAAAICOMYAAAICOQYAAAICOUYAAAICOYYAAAICOcYAAAICOgYAAAICOkYAAAICOoYAAAICOsYAAAICOwYAAAICO0YAAAICO4YAAAICO8YAAAICPAYAAAICPEYAAAICPIYAAAICPMYAAAICPQYAAAICPUYAAAICPYYAAAICPcYAAAICPgYAAAICPkYAAAICPoYAAAICPsYAAAICPwYAAAICP0YAAAICP4YAAAICP8YAAAICAAZAAAICAEZAAAICAIZAAAICAMZAAAICAQZAAAICAUZAAAICAYZAAAICAcZAAAICAgZAAAICAkZAAAICAoZAAAICAsZAAAICAwZAAAICA0ZAAAICA4ZAAAICA8ZAAAICBAZAAAICBEZAAAICBIZAAAICBMZAAAICBQZAAAICBUZAAAICBYZAAAICBcZAAAICBgZAAAICBkZAAAICBoZAAAICBsZAAAICBwZAAAICB0ZAAAICB4ZAAAICB8ZAAAICCAZAAAICCEZAAAICCIZAAAICCMZAAAICCQZAAAICCUZAAAICCYZAAAICCcZAAAICCgZAAAICCkZAAAICCoZAAAICCsZAAAICCwZAAAICC0ZAAAICC4ZAAAICC8ZAAAICDAZAAAICDEZAAAICDIZAAAICDMZAAAICDQZAAAICDUZAAAICDYZAAAICDcZAAAICDgZAAAICDkZAAAICDoZAAAICDsZAAAICDwZAAAICD0ZAAAICD4ZAAAICD8ZAAAICEAZAAAICEEZAAAICEIZAAAICEMZAAAICEQZAAAICEUZAAAICEYZAAAICEcZAAAICEgZAAAICEkZAAAICEoZAAAICEsZAAAICEwZAAAICE0ZAAAICE4ZAAAICE8ZAAAICFAZAAAICFEZAAAICFIZAAAICFMZAAAICFQZAAAICFUZAAAICFYZAAAICFcZAAAICFgZAAAICFkZAAAICFoZAAAICFsZAAAICFwZAAAICF0ZAAAICF4ZAAAICF8ZAAAICGAZAAAICGEZAAAICGIZAAAICGMZAAAICGQZAAAICGUZAAAICGYZAAAICGcZAAAICGgZAAAICGkZAAAICGoZAAAICGsZAAAICGwZAAAICG0ZAAAICG4ZAAAICG8ZAAAICHAZAAAICHEZAAAICHIZAAAICHMZAAAICHQZAAAICHUZAAAICHYZAAAICHcZAAAICHgZAAAICHkZAAAICHoZAAAICHsZAAAICHwZAAAICH0ZAAAICH4ZAAAICH8ZAAAICIAZAAAICIEZAAAICIIZAAAICIMZAAAICIQZAAAICIUZAAAICIYZAAAICIcZAAAICIgZAAAICIkZAAAICIoZAAAICIsZAAAICIwZAAAICI0ZAAAICI4ZAAAICI8ZAAAICJAZAAAICJEZAAAICJIZAAAICJMZAAAICJQZAAAICJUZAAAICJYZAAAICJcZAAAICJgZAAAICJkZAAAICJoZAAAICJsZAAAICJwZAAAICJ0ZAAAICJ4ZAAAICJ8ZAAAICKAZAAAICKEZAAAICKIZAAAICKMZAAAICKQZAAAICKUZAAAICKYZAAAICKcZAAAICKgZAAAICKkZAAAICKoZAAAICKsZAAAICKwZAAAICK0ZAAAICK4ZAAAICK8ZAAAICLAZAAAICLEZAAAICLIZAAAICLMZAAAICLQZAAAICLUZAAAICLYZAAAICLcZAAAICLgZAAAICLkZAAAICLoZAAAICLsZAAAICLwZAAAICL0ZAAAICL4ZAAAICL8ZAAAICMAZAAAICMEZAAAICMIZAAAICMMZAAAICMQZAAAICMUZAAAICMYZAAAICMcZAAAICMgZAAAICMkZAAAICMoZAAAICMsZAAAICMwZAAAICM0ZAAAICM4ZAAAICM8ZAAAICNAZAAAICNEZAAAICNIZAAAICNMZAAAICNQZAAAICNUZAAAICNYZAAAICNcZAAAICNgZAAAICNkZAAAICNoZAAAICNsZAAAICNwZAAAICN0ZAAAICN4ZAAAICN8ZAAAICOAZAAAICOEZAAAICOIZAAAICOMZAAAICOQZAAAICOUZAAAICOYZAAAICOcZAAAICOgZAAAICOkZAAAICOoZAAAICOsZAAAICOwZAAAICO0ZAAAICO4ZAAAICO8ZAAAICPAZAAAICPEZAAAICPIZAAAICPMZAAAICPQZAAAICPUZAAAICPYZAAAICPcZAAAICPgZAAAICPkZAAAICPoZAAAICPsZAAAICPwZAAAICP0ZAAAICP4ZAAAICP8ZAAAICAAaAAAICAEaAAAICAIaAAAICAMaAAAICAQaAAAICAUaAAAICAYaAAAICAcaAAAICAgaAAAICAkaAAAICAoaAAAICAsaAAAICAwaAAAICA0aAAAICA4aAAAICA8aAAAICBAaAAAICBEaAAAICBIaAAAICBMaAAAICBQaAAAICBUaAAAICBYaAAAICBcaAAAICBgaAAAICBkaAAAICBoaAAAICBsaAAAICBwaAAAICB0aAAAICB4aAAAICB8aAAAICCAaAAAICCEaAAAICCIaAAAICCMaAAAICCQaAAAICCUaAAAICCYaAAAICCcaAAAICCgaAAAICCkaAAAICCoaAAAICCsaAAAICCwaAAAICC0aAAAICC4aAAAICC8aAAAICDAaAAAICDEaAAAICDIaAAAICDMaAAAICDQaAAAICDUaAAAICDYaAAAICDcaAAAICDgaAAAICDkaAAAICDoaAAAICDsaAAAICDwaAAAICD0aAAAICD4aAAAICD8aAAAICEAaAAAICEEaAAAICEIaAAAICEMaAAAICEQaAAAICEUaAAAICEYaAAAICEcaAAAICEgaAAAICEkaAAAICEoaAAAICEsaAAAICEwaAAAICE0aAAAICE4aAAAICE8aAAAICFAaAAAICFEaAAAICFIaAAAICFMaAAAICFQaAAAICFUaAAAICFYaAAAICFcaAAAICFgaAAAICFkaAAAICFoaAAAICFsaAAAICFwaAAAICF0aAAAICF4aAAAICF8aAAAICGAaAAAICGEaAAAICGIaAAAICGMaAAAICGQaAAAICGUaAAAICGYaAAAICGcaAAAICGgaAAAICGkaAAAICGoaAAAICGsaAAAICGwaAAAICG0aAAAICG4aAAAICG8aAAAICHAaAAAICHEaAAAICHIaAAAICHMaAAAICHQaAAAICHUaAAAICHYaAAAICHcaAAAICHgaAAAICHkaAAAICHoaAAAICHsaAAAICHwaAAAICH0aAAAICH4aAAAICH8aAAAICIAaAAAICIEaAAAICIIaAAAICIMaAAAICIQaAAAICIUaAAAICIYaAAAICIcaAAAICIgaAAAICIkaAAAICIoaAAAICIsaAAAICIwaAAAICI0aAAAICI4aAAAICI8aAAAICJAaAAAICJEaAAAICJIaAAAICJMaAAAICJQaAAAICJUaAAAICJYaAAAICJcaAAAICJgaAAAICJkaAAAICJoaAAAICJsaAAAICJwaAAAICJ0aAAAICJ4aAAAICJ8aAAAICKAaAAAICKEaAAAICKIaAAAICKMaAAAICKQaAAAICKUaAAAICKYaAAAICKcaAAAICKgaAAAICKkaAAAICKoaAAAICKsaAAAICKwaAAAICK0aAAAICK4aAAAICK8aAAAICLAaAAAICLEaAAAICLIaAAAICLMaAAAICLQaAAAICLUaAAAICLYaAAAICLcaAAAICLgaAAAICLkaAAAICLoaAAAICLsaAAAICLwaAAAICL0aAAAICL4aAAAICL8aAAAICMAaAAAICMEaAAAICMIaAAAICMMaAAAICMQaAAAICMUaAAAICMYaAAAICMcaAAAICMgaAAAICMkaAAAICMoaAAAICMsaAAAICMwaAAAICM0aAAAICM4aAAAICM8aAAAICNAaAAAICNEaAAAICNIaAAAICNMaAAAICNQaAAAICNUaAAAICNYaAAAICNcaAAAICNgaAAAICNkaAAAICNoaAAAICNsaAAAICNwaAAAICN0aAAAICN4aAAAICN8aAAAICOAaAAAICOEaAAAICOIaAAAICOMaAAAICOQaAAAICOUaAAAICOYaAAAICOcaAAAICOgaAAAICOkaAAAICOoaAAAICOsaAAAICOwaAAAICO0aAAAICO4aAAAICO8aAAAICPAaAAAICPEaAAAICPIaAAAICPMaAAAICPQaAAAICPUaAAAICPYaAAAICPcaAAAICPgaAAAICPkaAAAICPoaAAAICPsaAAAICPwaAAAICP0aAAAICP4aAAAICP8aAAAICAAbAAAICAEbAAAICAIbAAAICAMbAAAICAQbAAAICAUbAAAICAYbAAAICAcbAAAICAgbAAAICAkbAAAICAobAAAICAsbAAAICAwbAAAICA0bAAAICA4bAAAICA8bAAAICBAbAAAICBEbAAAICBIbAAAICBMbAAAICBQbAAAICBUbAAAICBYbAAAICBcbAAAICBgbAAAICBkbAAAICBobAAAICBsbAAAICBwbAAAICB0bAAAICB4bAAAICB8bAAAICCAbAAAICCEbAAAICCIbAAAICCMbAAAICCQbAAAICCUbAAAICCYbAAAICCcbAAAICCgbAAAICCkbAAAICCobAAAICCsbAAAICCwbAAAICC0bAAAICC4bAAAICC8bAAAICDAbAAAICDEbAAAICDIbAAAICDMbAAAICDQbAAAICDUbAAAICDYbAAAICDcbAAAICDgbAAAICDkbAAAICDobAAAICDsbAAAICDwbAAAICD0bAAAICD4bAAAICD8bAAAICEAbAAAICEEbAAAICEIbAAAICEMbAAAICEQbAAAICEUbAAAICEYbAAAICEcbAAAICEgbAAAICEkbAAAICEobAAAICEsbAAAICEwbAAAICE0bAAAICE4bAAAICE8bAAAICFAbAAAICFEbAAAICFIbAAAICFMbAAAICFQbAAAICFUbAAAICFYbAAAICFcbAAAICFgbAAAICFkbAAAICFobAAAICFsbAAAICFwbAAAICF0bAAAICF4bAAAICF8bAAAICGAbAAAICGEbAAAICGIbAAAICGMbAAAICGQbAAAICGUbAAAICGYbAAAICGcbAAAICGgbAAAICGkbAAAICGobAAAICGsbAAAICGwbAAAICG0bAAAICG4bAAAICG8bAAAICHAbAAAICHEbAAAICHIbAAAICHMbAAAICHQbAAAICHUbAAAICHYbAAAICHcbAAAICHgbAAAICHkbAAAICHobAAAICHsbAAAICHwbAAAICH0bAAAICH4bAAAICH8bAAAICIAbAAAICIEbAAAICIIbAAAICIMbAAAICIQbAAAICIUbAAAICIYbAAAICIcbAAAICIgbAAAICIkbAAAICIobAAAICIsbAAAICIwbAAAICI0bAAAICI4bAAAICI8bAAAICJAbAAAICJEbAAAICJIbAAAICJMbAAAICJQbAAAICJUbAAAICJYbAAAICJcbAAAICJgbAAAICJkbAAAICJobAAAICJsbAAAICJwbAAAICJ0bAAAICJ4bAAAICJ8bAAAICKAbAAAICKEbAAAICKIbAAAICKMbAAAICKQbAAAICKUbAAAICKYbAAAICKcbAAAICKgbAAAICKkbAAAICKobAAAICKsbAAAICKwbAAAICK0bAAAICK4bAAAICK8bAAAICLAbAAAICLEbAAAICLIbAAAICLMbAAAICLQbAAAICLUbAAAICLYbAAAICLcbAAAICLgbAAAICLkbAAAICLobAAAICLsbAAAICLwbAAAICL0bAAAICL4bAAAICL8bAAAICMAbAAAICMEbAAAICMIbAAAICMMbAAAICMQbAAAICMUbAAAICMYbAAAICMcbAAAICMgbAAAICMkbAAAICMobAAAICMsbAAAICMwbAAAICM0bAAAICM4bAAAICM8bAAAICNAbAAAICNEbAAAICNIbAAAICNMbAAAICNQbAAAICNUbAAAICNYbAAAICNcbAAAICNgbAAAICNkbAAAICNobAAAICNsbAAAICNwbAAAICN0bAAAICN4bAAAICN8bAAAICOAbAAAICOEbAAAICOIbAAAICOMbAAAICOQbAAAICOUbAAAICOYbAAAICOcbAAAICOgbAAAICOkbAAAICOobAAAICOsbAAAICOwbAAAICO0bAAAICO4bAAAICO8bAAAICPAbAAAICPEbAAAICPIbAAAICPMbAAAICPQbAAAICPUbAAAICPYbAAAICPcbAAAICPgbAAAICPkbAAAICPobAAAICPsbAAAICPwbAAAICP0bAAAICP4bAAAICP8bAAAICAAcAAAICAEcAAAICAIcAAAICAMcAAAICAQcAAAICAUcAAAICAYcAAAICAccAAAICAgcAAAICAkcAAAICAocAAAICAscAAAICAwcAAAICA0cAAAICA4cAAAICA8cAAAICBAcAAAICBEcAAAICBIcAAAICBMcAAAICBQcAAAICBUcAAAICBYcAAAICBccAAAICBgcAAAICBkcAAAICBocAAAICBscAAAICBwcAAAICB0cAAAICB4cAAAICB8cAAAICCAcAAAICCEcAAAICCIcAAAICCMcAAAICCQcAAAICCUcAAAICCYcAAAICCccAAAICCgcAAAICCkcAAAICCocAAAICCscAAAICCwcAAAICC0cAAAICC4cAAAICC8cAAAICDAcAAAICDEcAAAICDIcAAAICDMcAAAICDQcAAAICDUcAAAICDYcAAAICDccAAAICDgcAAAICDkcAAAICDocAAAICDscAAAICDwcAAAICD0cAAAICD4cAAAICD8cAAAICEAcAAAICEEcAAAICEIcAAAICEMcAAAICEQcAAAICEUcAAAICEYcAAAICEccAAAICEgcAAAICEkcAAAICEocAAAICEscAAAICEwcAAAICE0cAAAICE4cAAAICE8cAAAICFAcAAAICFEcAAAICFIcAAAICFMcAAAICFQcAAAICFUcAAAICFYcAAAICFccAAAICFgcAAAICFkcAAAICFocAAAICFscAAAICFwcAAAICF0cAAAICF4cAAAICF8cAAAICGAcAAAICGEcAAAICGIcAAAICGMcAAAICGQcAAAICGUcAAAICGYcAAAICGccAAAICGgcAAAICGkcAAAICGocAAAICGscAAAICGwcAAAICG0cAAAICG4cAAAICG8cAAAICHAcAAAICHEcAAAICHIcAAAICHMcAAAICHQcAAAICHUcAAAICHYcAAAICHccAAAICHgcAAAICHkcAAAICHocAAAICHscAAAICHwcAAAICH0cAAAICH4cAAAICH8cAAAICIAcAAAICIEcAAAICIIcAAAICIMcAAAICIQcAAAICIUcAAAICIYcAAAICIccAAAICIgcAAAICIkcAAAICIocAAAICIscAAAICIwcAAAICI0cAAAICI4cAAAICI8cAAAICJAcAAAICJEcAAAICJIcAAAICJMcAAAICJQcAAAICJUcAAAICJYcAAAICJccAAAICJgcAAAICJkcAAAICJocAAAICJscAAAICJwcAAAICJ0cAAAICJ4cAAAICJ8cAAAICKAcAAAICKEcAAAICKIcAAAICKMcAAAICKQcAAAICKUcAAAICKYcAAAICKccAAAICKgcAAAICKkcAAAICKocAAAICKscAAAICKwcAAAICK0cAAAICK4cAAAICK8cAAAICLAcAAAICLEcAAAICLIcAAAICLMcAAAICLQcAAAICLUcAAAICLYcAAAICLccAAAICLgcAAAICLkcAAAICLocAAAICLscAAAICLwcAAAICL0cAAAICL4cAAAICL8cAAAICMAcAAAICMEcAAAICMIcAAAICMMcAAAICMQcAAAICMUcAAAICMYcAAAICMccAAAICMgcAAAICMkcAAAICMocAAAICMscAAAICMwcAAAICM0cAAAICM4cAAAICM8cAAAICNAcAAAICNEcAAAICNIcAAAICNMcAAAICNQcAAAICNUcAAAICNYcAAAICNccAAAICNgcAAAICNkcAAAICNocAAAICNscAAAICNwcAAAICN0cAAAICN4cAAAICN8cAAAICOAcAAAICOEcAAAICOIcAAAICOMcAAAICOQcAAAICOUcAAAICOYcAAAICOccAAAICOgcAAAICOkcAAAICOocAAAICOscAAAICOwcAAAICO0cAAAICO4cAAAICO8cAAAICPAcAAAICPEcAAAICPIcAAAICPMcAAAICPQcAAAICPUcAAAICPYcAAAICPccAAAICPgcAAAICPkcAAAICPocAAAICPscAAAICPwcAAAICP0cAAAICP4cAAAICP8cAAAICAAdAAAICAEdAAAICAIdAAAICAMdAAAICAQdAAAICAUdAAAICAYdAAAICAcdAAAICAgdAAAICAkdAAAICAodAAAICAsdAAAICAwdAAAICA0dAAAICA4dAAAICA8dAAAICBAdAAAICBEdAAAICBIdAAAICBMdAAAICBQdAAAICBUdAAAICBYdAAAICBcdAAAICBgdAAAICBkdAAAICBodAAAICBsdAAAICBwdAAAICB0dAAAICB4dAAAICB8dAAAICCAdAAAICCEdAAAICCIdAAAICCMdAAAICCQdAAAICCUdAAAICCYdAAAICCcdAAAICCgdAAAICCkdAAAICCodAAAICCsdAAAICCwdAAAICC0dAAAICC4dAAAICC8dAAAICDAdAAAICDEdAAAICDIdAAAICDMdAAAICDQdAAAICDUdAAAICDYdAAAICDcdAAAICDgdAAAICDkdAAAICDodAAAICDsdAAAICDwdAAAICD0dAAAICD4dAAAICD8dAAAICEAdAAAICEEdAAAICEIdAAAICEMdAAAICEQdAAAICEUdAAAICEYdAAAICEcdAAAICEgdAAAICEkdAAAICEodAAAICEsdAAAICEwdAAAICE0dAAAICE4dAAAICE8dAAAICFAdAAAICFEdAAAICFIdAAAICFMdAAAICFQdAAAICFUdAAAICFYdAAAICFcdAAAICFgdAAAICFkdAAAICFodAAAICFsdAAAICFwdAAAICF0dAAAICF4dAAAICF8dAAAICGAdAAAICGEdAAAICGIdAAAICGMdAAAICGQdAAAICGUdAAAICGYdAAAICGcdAAAICGgdAAAICGkdAAAICGodAAAICGsdAAAICGwdAAAICG0dAAAICG4dAAAICG8dAAAICHAdAAAICHEdAAAICHIdAAAICHMdAAAICHQdAAAICHUdAAAICHYdAAAICHcdAAAICHgdAAAICHkdAAAICHodAAAICHsdAAAICHwdAAAICH0dAAAICH4dAAAICH8dAAAICIAdAAAICIEdAAAICIIdAAAICIMdAAAICIQdAAAICIUdAAAICIYdAAAICIcdAAAICIgdAAAICIkdAAAICIodAAAICIsdAAAICIwdAAAICI0dAAAICI4dAAAICI8dAAAICJAdAAAICJEdAAAICJIdAAAICJMdAAAICJQdAAAICJUdAAAICJYdAAAICJcdAAAICJgdAAAICJkdAAAICJodAAAICJsdAAAICJwdAAAICJ0dAAAICJ4dAAAICJ8dAAAICKAdAAAICKEdAAAICKIdAAAICKMdAAAICKQdAAAICKUdAAAICKYdAAAICKcdAAAICKgdAAAICKkdAAAICKodAAAICKsdAAAICKwdAAAICK0dAAAICK4dAAAICK8dAAAICLAdAAAICLEdAAAICLIdAAAICLMdAAAICLQdAAAICLUdAAAICLYdAAAICLcdAAAICLgdAAAICLkdAAAICLodAAAICLsdAAAICLwdAAAICL0dAAAICL4dAAAICL8dAAAICMAdAAAICMEdAAAICMIdAAAICMMdAAAICMQdAAAICMUdAAAICMYdAAAICMcdAAAICMgdAAAICMkdAAAICModAAAICMsdAAAICMwdAAAICM0dAAAICM4dAAAICM8dAAAICNAdAAAICNEdAAAICNIdAAAICNMdAAAICNQdAAAICNUdAAAICNYdAAAICNcdAAAICNgdAAAICNkdAAAICNodAAAICNsdAAAICNwdAAAICN0dAAAICN4dAAAICN8dAAAICOAdAAAICOEdAAAICOIdAAAICOMdAAAICOQdAAAICOUdAAAICOYdAAAICOcdAAAICOgdAAAICOkdAAAICOodAAAICOsdAAAICOwdAAAICO0dAAAICO4dAAAICO8dAAAICPAdAAAICPEdAAAICPIdAAAICPMdAAAICPQdAAAICPUdAAAICPYdAAAICPcdAAAICPgdAAAICPkdAAAICPodAAAICPsdAAAICPwdAAAICP0dAAAICP4dAAAICP8dAAAICAAeAAAICAEeAAAICAIeAAAICAMeAAAICAQeAAAICAUeAAAICAYeAAAICAceAAAICAgeAAAICAkeAAAICAoeAAAICAseAAAICAweAAAICA0eAAAICA4eAAAICA8eAAAICBAeAAAICBEeAAAICBIeAAAICBMeAAAICBQeAAAICBUeAAAICBYeAAAICBceAAAICBgeAAAICBkeAAAICBoeAAAICBseAAAICBweAAAICB0eAAAICB4eAAAICB8eAAAICCAeAAAICCEeAAAICCIeAAAICCMeAAAICCQeAAAICCUeAAAICCYeAAAICCceAAAICCgeAAAICCkeAAAICCoeAAAICCseAAAICCweAAAICC0eAAAICC4eAAAICC8eAAAICDAeAAAICDEeAAAICDIeAAAICDMeAAAICDQeAAAICDUeAAAICDYeAAAICDceAAAICDgeAAAICDkeAAAICDoeAAAICDseAAAICDweAAAICD0eAAAICD4eAAAICD8eAAAICEAeAAAICEEeAAAICEIeAAAICEMeAAAICEQeAAAICEUeAAAICEYeAAAICEceAAAICEgeAAAICEkeAAAICEoeAAAICEseAAAICEweAAAICE0eAAAICE4eAAAICE8eAAAICFAeAAAICFEeAAAICFIeAAAICFMeAAAICFQeAAAICFUeAAAICFYeAAAICFceAAAICFgeAAAICFkeAAAICFoeAAAICFseAAAICFweAAAICF0eAAAICF4eAAAICF8eAAAICGAeAAAICGEeAAAICGIeAAAICGMeAAAICGQeAAAICGUeAAAICGYeAAAICGceAAAICGgeAAAICGkeAAAICGoeAAAICGseAAAICGweAAAICG0eAAAICG4eAAAICG8eAAAICHAeAAAICHEeAAAICHIeAAAICHMeAAAICHQeAAAICHUeAAAICHYeAAAICHceAAAICHgeAAAICHkeAAAICHoeAAAICHseAAAICHweAAAICH0eAAAICH4eAAAICH8eAAAICIAeAAAICIEeAAAICIIeAAAICIMeAAAICIQeAAAICIUeAAAICIYeAAAICIceAAAICIgeAAAICIkeAAAICIoeAAAICIseAAAICIweAAAICI0eAAAICI4eAAAICI8eAAAICJAeAAAICJEeAAAICJIeAAAICJMeAAAICJQeAAAICJUeAAAICJYeAAAICJceAAAICJgeAAAICJkeAAAICJoeAAAICJseAAAICJweAAAICJ0eAAAICJ4eAAAICJ8eAAAICKAeAAAICKEeAAAICKIeAAAICKMeAAAICKQeAAAICKUeAAAICKYeAAAICKceAAAICKgeAAAICKkeAAAICKoeAAAICKseAAAICKweAAAICK0eAAAICK4eAAAICK8eAAAICLAeAAAICLEeAAAICLIeAAAICLMeAAAICLQeAAAICLUeAAAICLYeAAAICLceAAAICLgeAAAICLkeAAAICLoeAAAICLseAAAICLweAAAICL0eAAAICL4eAAAICL8eAAAICMAeAAAICMEeAAAICMIeAAAICMMeAAAICMQeAAAICMUeAAAICMYeAAAICMceAAAICMgeAAAICMkeAAAICMoeAAAICMseAAAICMweAAAICM0eAAAICM4eAAAICM8eAAAICNAeAAAICNEeAAAICNIeAAAICNMeAAAICNQeAAAICNUeAAAICNYeAAAICNceAAAICNgeAAAICNkeAAAICNoeAAAICNseAAAICNweAAAICN0eAAAICN4eAAAICN8eAAAICOAeAAAICOEeAAAICOIeAAAICOMeAAAICOQeAAAICOUeAAAICOYeAAAICOceAAAICOgeAAAICOkeAAAICOoeAAAICOseAAAICOweAAAICO0eAAAICO4eAAAICO8eAAAICPAeAAAICPEeAAAICPIeAAAICPMeAAAICPQeAAAICPUeAAAICPYeAAAICPceAAAICPgeAAAICPkeAAAICPoeAAAICPseAAAICPweAAAICP0eAAAICP4eAAAICP8eAAAICAAfAAAICAEfAAAICAIfAAAICAMfAAAICAQfAAAICAUfAAAICAYfAAAICAcfAAAICAgfAAAICAkfAAAICAofAAAICAsfAAAICAwfAAAICA0fAAAICA4fAAAICA8fAAAICBAfAAAICBEfAAAICBIfAAAICBMfAAAICBQfAAAICBUfAAAICBYfAAAICBcfAAAICBgfAAAICBkfAAAICBofAAAICBsfAAAICBwfAAAICB0fAAAICB4fAAAICB8fAAAICCAfAAAICCEfAAAICCIfAAAICCMfAAAICCQfAAAICCUfAAAICCYfAAAICCcfAAAICCgfAAAICCkfAAAICCofAAAICCsfAAAICCwfAAAICC0fAAAICC4fAAAICC8fAAAICDAfAAAICDEfAAAICDIfAAAICDMfAAAICDQfAAAICDUfAAAICDYfAAAICDcfAAAICDgfAAAICDkfAAAICDofAAAICDsfAAAICDwfAAAICD0fAAAICD4fAAAICD8fAAAICEAfAAAICEEfAAAICEIfAAAICEMfAAAICEQfAAAICEUfAAAICEYfAAAICEcfAAAICEgfAAAICEkfAAAICEofAAAICEsfAAAICEwfAAAICE0fAAAICE4fAAAICE8fAAAICFAfAAAICFEfAAAICFIfAAAICFMfAAAICFQfAAAICFUfAAAICFYfAAAICFcfAAAICFgfAAAICFkfAAAICFofAAAICFsfAAAICFwfAAAICF0fAAAICF4fAAAICF8fAAAICGAfAAAICGEfAAAICGIfAAAICGMfAAAICGQfAAAICGUfAAAICGYfAAAICGcfAAAICGgfAAAICGkfAAAICGofAAAICGsfAAAICGwfAAAICG0fAAAICG4fAAAICG8fAAAICHAfAAAICHEfAAAICHIfAAAICHMfAAAICHQfAAAICHUfAAAICHYfAAAICHcfAAAICHgfAAAICHkfAAAICHofAAAICHsfAAAICHwfAAAICH0fAAAICH4fAAAICH8fAAAICIAfAAAICIEfAAAICIIfAAAICIMfAAAICIQfAAAICIUfAAAICIYfAAAICIcfAAAICIgfAAAICIkfAAAICIofAAAICIsfAAAICIwfAAAICI0fAAAICI4fAAAICI8fAAAICJAfAAAICJEfAAAICJIfAAAICJMfAAAICJQfAAAICJUfAAAICJYfAAAICJcfAAAICJgfAAAICJkfAAAICJofAAAICJsfAAAICJwfAAAICJ0fAAAICJ4fAAAICJ8fAAAICKAfAAAICKEfAAAICKIfAAAICKMfAAAICKQfAAAICKUfAAAICKYfAAAICKcfAAAICKgfAAAICKkfAAAICKofAAAICKsfAAAICKwfAAAICK0fAAAICK4fAAAICK8fAAAICLAfAAAICLEfAAAICLIfAAAICLMfAAAICLQfAAAICLUfAAAICLYfAAAICLcfAAAICLgfAAAICLkfAAAICLofAAAICLsfAAAICLwfAAAICL0fAAAICL4fAAAICL8fAAAICMAfAAAICMEfAAAICMIfAAAICMMfAAAICMQfAAAICMUfAAAICMYfAAAICMcfAAAICMgfAAAICMkfAAAICMofAAAICMsfAAAICMwfAAAICM0fAAAICM4fAAAICM8fAAAICNAfAAAICNEfAAAICNIfAAAICNMfAAAICNQfAAAICNUfAAAICNYfAAAICNcfAAAICNgfAAAICNkfAAAICNofAAAICNsfAAAICNwfAAAICN0fAAAICN4fAAAICN8fAAAICOAfAAAICOEfAAAICOIfAAAICOMfAAAICOQfAAAICOUfAAAICOYfAAAICOcfAAAICOgfAAAICOkfAAAICOofAAAICOsfAAAICOwfAAAICO0fAAAICO4fAAAICO8fAAAICPAfAAAICPEfAAAICPIfAAAICPMfAAAICPQfAAAICPUfAAAICPYfAAAICPcfAAAICPgfAAAICPkfAAAICPofAAAICPsfAAAICPwfAAAICP0fAAAICP4fAAAICP8fAAAICAAgAAAICAEgAAAICAIgAAAICAMgAAAICAQgAAAICAUgAAAICAYgAAAICAcgAAAICAggAAAICAkgAAAICAogAAAICAsgAAAICAwgAAAICA0gAAAICA4gAAAICA8gAAAICBAgAAAICBEgAAAICBIgAAAICBMgAAAICBQgAAAICBUgAAAICBYgAAAICBcgAAAICBggAAAICBkgAAAICBogAAAICBsgAAAICBwgAAAICB0gAAAICB4gAAAICB8gAAAICCAgAAAICCEgAAAICCIgAAAICCMgAAAICCQgAAAICCUgAAAICCYgAAAICCcgAAAICCggAAAICCkgAAAICCogAAAICCsgAAAICCwgAAAICC0gAAAICC4gAAAICC8gAAAICDAgAAAICDEgAAAICDIgAAAICDMgAAAICDQgAAAICDUgAAAICDYgAAAICDcgAAAICDggAAAICDkgAAAICDogAAAICDsgAAAICDwgAAAICD0gAAAICD4gAAAICD8gAAAICEAgAAAICEEgAAAICEIgAAAICEMgAAAICEQgAAAICEUgAAAICEYgAAAICEcgAAAICEggAAAICEkgAAAICEogAAAICEsgAAAICEwgAAAICE0gAAAICE4gAAAICE8gAAAICFAgAAAICFEgAAAICFIgAAAICFMgAAAICFQgAAAICFUgAAAICFYgAAAICFcgAAAICFggAAAICFkgAAAICFogAAAICFsgAAAICFwgAAAICF0gAAAICF4gAAAICF8gAAAICGAgAAAICGEgAAAICGIgAAAICGMgAAAICGQgAAAICGUgAAAICGYgAAAICGcgAAAICGggAAAICGkgAAAICGogAAAICGsgAAAICGwgAAAICG0gAAAICG4gAAAICG8gAAAICHAgAAAICHEgAAAICHIgAAAICHMgAAAICHQgAAAICHUgAAAICHYgAAAICHcgAAAICHggAAAICHkgAAAICHogAAAICHsgAAAICHwgAAAICH0gAAAICH4gAAAICH8gAAAICIAgAAAICIEgAAAICIIgAAAICIMgAAAICIQgAAAICIUgAAAICIYgAAAICIcgAAAICIggAAAICIkgAAAICIogAAAICIsgAAAICIwgAAAICI0gAAAICI4gAAAICI8gAAAICJAgAAAICJEgAAAICJIgAAAICJMgAAAICJQgAAAICJUgAAAICJYgAAAICJcgAAAICJggAAAICJkgAAAICJogAAAICJsgAAAICJwgAAAICJ0gAAAICJ4gAAAICJ8gAAAICKAgAAAICKEgAAAICKIgAAAICKMgAAAICKQgAAAICKUgAAAICKYgAAAICKcgAAAICKggAAAICKkgAAAICKogAAAICKsgAAAICKwgAAAICK0gAAAICK4gAAAICK8gAAAICLAgAAAICLEgAAAICLIgAAAICLMgAAAICLQgAAAICLUgAAAICLYgAAAICLcgAAAICLggAAAICLkgAAAICLogAAAICLsgAAAICLwgAAAICL0gAAAICL4gAAAICL8gAAAICMAgAAAICMEgAAAICMIgAAAICMMgAAAICMQgAAAICMUgAAAICMYgAAAICMcgAAAICMggAAAICMkgAAAICMogAAAICMsgAAAICMwgAAAICM0gAAAICM4gAAAICM8gAAAICNAgAAAICNEgAAAICNIgAAAICNMgAAAICNQgAAAICNUgAAAICNYgAAAICNcgAAAICNggAAAICNkgAAAICNogAAAICNsgAAAICNwgAAAICN0gAAAICN4gAAAICN8gAAAICOAgAAAICOEgAAAICOIgAAAICOMgAAAICOQgAAAICOUgAAAICOYgAAAICOcgAAAICOggAAAICOkgAAAICOogAAAICOsgAAAICOwgAAAICO0gAAAICO4gAAAICO8gAAAICPAgAAAICPEgAAAICPIgAAAICPMgAAAICPQgAAAICPUgAAAICPYgAAAICPcgAAAICPggAAAICPkgAAAICPogAAAICPsgAAAICPwgAAAICP0gAAAICP4gAAAICP8gAAAICAAhAAAICAEhAAAICAIhAAAICAMhAAAICAQhAAAICAUhAAAICAYhAAAICAchAAAICAghAAAICAkhAAAICAohAAAICAshAAAICAwhAAAICA0hAAAICA4hAAAICA8hAAAICBAhAAAICBEhAAAICBIhAAAICBMhAAAICBQhAAAICBUhAAAICBYhAAAICBchAAAICBghAAAICBkhAAAICBohAAAICBshAAAICBwhAAAICB0hAAAICB4hAAAICB8hAAAICCAhAAAICCEhAAAICCIhAAAICCMhAAAICCQhAAAICCUhAAAICCYhAAAICCchAAAICCghAAAICCkhAAAICCohAAAICCshAAAICCwhAAAICC0hAAAICC4hAAAICC8hAAAICDAhAAAICDEhAAAICDIhAAAICDMhAAAICDQhAAAICDUhAAAICDYhAAAICDchAAAICDghAAAICDkhAAAICDohAAAICDshAAAICDwhAAAICD0hAAAICD4hAAAICD8hAAAICEAhAAAICEEhAAAICEIhAAAICEMhAAAICEQhAAAICEUhAAAICEYhAAAICEchAAAICEghAAAICEkhAAAICEohAAAICEshAAAICEwhAAAICE0hAAAICE4hAAAICE8hAAAICFAhAAAICFEhAAAICFIhAAAICFMhAAAICFQhAAAICFUhAAAICFYhAAAICFchAAAICFghAAAICFkhAAAICFohAAAICFshAAAICFwhAAAICF0hAAAICF4hAAAICF8hAAAICGAhAAAICGEhAAAICGIhAAAICGMhAAAICGQhAAAICGUhAAAICGYhAAAICGchAAAICGghAAAICGkhAAAICGohAAAICGshAAAICGwhAAAICG0hAAAICG4hAAAICG8hAAAICHAhAAAICHEhAAAICHIhAAAICHMhAAAICHQhAAAICHUhAAAICHYhAAAICHchAAAICHghAAAICHkhAAAICHohAAAICHshAAAICHwhAAAICH0hAAAICH4hAAAICH8hAAAICIAhAAAICIEhAAAICIIhAAAICIMhAAAICIQhAAAICIUhAAAICIYhAAAICIchAAAICIghAAAICIkhAAAICIohAAAICIshAAAICIwhAAAICI0hAAAICI4hAAAICI8hAAAICJAhAAAICJEhAAAICJIhAAAICJMhAAAICJQhAAAICJUhAAAICJYhAAAICJchAAAICJghAAAICJkhAAAICJohAAAICJshAAAICJwhAAAICJ0hAAAICJ4hAAAICJ8hAAAICKAhAAAICKEhAAAICKIhAAAICKMhAAAICKQhAAAICKUhAAAICKYhAAAICKchAAAICKghAAAICKkhAAAICKohAAAICKshAAAICKwhAAAICK0hAAAICK4hAAAICK8hAAAICLAhAAAICLEhAAAICLIhAAAICLMhAAAICLQhAAAICLUhAAAICLYhAAAICLchAAAICLghAAAICLkhAAAICLohAAAICLshAAAICLwhAAAICL0hAAAICL4hAAAICL8hAAAICMAhAAAICMEhAAAICMIhAAAICMMhAAAICMQhAAAICMUhAAAICMYhAAAICMchAAAICMghAAAICMkhAAAICMohAAAICMshAAAICMwhAAAICM0hAAAICM4hAAAICM8hAAAICNAhAAAICNEhAAAICNIhAAAICNMhAAAICNQhAAAICNUhAAAICNYhAAAICNchAAAICNghAAAICNkhAAAICNohAAAICNshAAAICNwhAAAICN0hAAAICN4hAAAICN8hAAAICOAhAAAICOEhAAAICOIhAAAICOMhAAAICOQhAAAICOUhAAAICOYhAAAICOchAAAICOghAAAICOkhAAAICOohAAAICOshAAAICOwhAAAICO0hAAAICO4hAAAICO8hAAAICPAhAAAICPEhAAAICPIhAAAICPMhAAAICPQhAAAICPUhAAAICPYhAAAICPchAAAICPghAAAICPkhAAAICPohAAAICPshAAAICPwhAAAICP0hAAAICP4hAAAICP8hAAAICAAiAAAICAEiAAAICAIiAAAICAMiAAAICAQiAAAICAUiAAAICAYiAAAICAciAAAICAgiAAAICAkiAAAICAoiAAAICAsiAAAICAwiAAAICA0iAAAICA4iAAAICA8iAAAICBAiAAAICBEiAAAICBIiAAAICBMiAAAICBQiAAAICBUiAAAICBYiAAAICBciAAAICBgiAAAICBkiAAAICBoiAAAICBsiAAAICBwiAAAICB0iAAAICB4iAAAICB8iAAAICCAiAAAICCEiAAAICCIiAAAICCMiAAAICCQiAAAICCUiAAAICCYiAAAICCciAAAICCgiAAAICCkiAAAICCoiAAAICCsiAAAICCwiAAAICC0iAAAICC4iAAAICC8iAAAICDAiAAAICDEiAAAICDIiAAAICDMiAAAICDQiAAAICDUiAAAICDYiAAAICDciAAAICDgiAAAICDkiAAAICDoiAAAICDsiAAAICDwiAAAICD0iAAAICD4iAAAICD8iAAAICEAiAAAICEEiAAAICEIiAAAICEMiAAAICEQiAAAICEUiAAAICEYiAAAICEciAAAICEgiAAAICEkiAAAICEoiAAAICEsiAAAICEwiAAAICE0iAAAICE4iAAAICE8iAAAICFAiAAAICFEiAAAICFIiAAAICFMiAAAICFQiAAAICFUiAAAICFYiAAAICFciAAAICFgiAAAICFkiAAAICFoiAAAICFsiAAAICFwiAAAICF0iAAAICF4iAAAICF8iAAAICGAiAAAICGEiAAAICGIiAAAICGMiAAAICGQiAAAICGUiAAAICGYiAAAICGciAAAICGgiAAAICGkiAAAICGoiAAAICGsiAAAICGwiAAAICG0iAAAICG4iAAAICG8iAAAICHAiAAAICHEiAAAICHIiAAAICHMiAAAICHQiAAAICHUiAAAICHYiAAAICHciAAAICHgiAAAICHkiAAAICHoiAAAICHsiAAAICHwiAAAICH0iAAAICH4iAAAICH8iAAAICIAiAAAICIEiAAAICIIiAAAICIMiAAAICIQiAAAICIUiAAAICIYiAAAICIciAAAICIgiAAAICIkiAAAICIoiAAAICIsiAAAICIwiAAAICI0iAAAICI4iAAAICI8iAAAICJAiAAAICJEiAAAICJIiAAAICJMiAAAICJQiAAAICJUiAAAICJYiAAAICJciAAAICJgiAAAICJkiAAAICJoiAAAICJsiAAAICJwiAAAICJ0iAAAICJ4iAAAICJ8iAAAICKAiAAAICKEiAAAICKIiAAAICKMiAAAICKQiAAAICKUiAAAICKYiAAAICKciAAAICKgiAAAICKkiAAAICKoiAAAICKsiAAAICKwiAAAICK0iAAAICK4iAAAICK8iAAAICLAiAAAICLEiAAAICLIiAAAICLMiAAAICLQiAAAICLUiAAAICLYiAAAICLciAAAICLgiAAAICLkiAAAICLoiAAAICLsiAAAICLwiAAAICL0iAAAICL4iAAAICL8iAAAICMAiAAAICMEiAAAICMIiAAAICMMiAAAICMQiAAAICMUiAAAICMYiAAAICMciAAAICMgiAAAICMkiAAAICMoiAAAICMsiAAAICMwiAAAICM0iAAAICM4iAAAICM8iAAAICNAiAAAICNEiAAAICNIiAAAICNMiAAAICNQiAAAICNUiAAAICNYiAAAICNciAAAICNgiAAAICNkiAAAICNoiAAAICNsiAAAICNwiAAAICN0iAAAICN4iAAAICN8iAAAICOAiAAAICOEiAAAICOIiAAAICOMiAAAICOQiAAAICOUiAAAICOYiAAAICOciAAAICOgiAAAICOkiAAAICOoiAAAICOsiAAAICOwiAAAICO0iAAAICO4iAAAICO8iAAAICPAiAAAICPEiAAAICPIiAAAICPMiAAAICPQiAAAICPUiAAAICPYiAAAICPciAAAICPgiAAAICPkiAAAICPoiAAAICPsiAAAICPwiAAAICP0iAAAICP4iAAAICP8iAAAICAAjAAAICAEjAAAICAIjAAAICAMjAAAICAQjAAAICAUjAAAICAYjAAAICAcjAAAICAgjAAAICAkjAAAICAojAAAICAsjAAAICAwjAAAICA0jAAAICA4jAAAICA8jAAAICBAjAAAICBEjAAAICBIjAAAICBMjAAAICBQjAAAICBUjAAAICBYjAAAICBcjAAAICBgjAAAICBkjAAAICBojAAAICBsjAAAICBwjAAAICB0jAAAICB4jAAAICB8jAAAICCAjAAAICCEjAAAICCIjAAAICCMjAAAICCQjAAAICCUjAAAICCYjAAAICCcjAAAICCgjAAAICCkjAAAICCojAAAICCsjAAAICCwjAAAICC0jAAAICC4jAAAICC8jAAAICDAjAAAICDEjAAAICDIjAAAICDMjAAAICDQjAAAICDUjAAAICDYjAAAICDcjAAAICDgjAAAICDkjAAAICDojAAAICDsjAAAICDwjAAAICD0jAAAICD4jAAAICD8jAAAICEAjAAAICEEjAAAICEIjAAAICEMjAAAICEQjAAAICEUjAAAICEYjAAAICEcjAAAICEgjAAAICEkjAAAICEojAAAICEsjAAAICEwjAAAICE0jAAAICE4jAAAICE8jAAAICFAjAAAICFEjAAAICFIjAAAICFMjAAAICFQjAAAICFUjAAAICFYjAAAICFcjAAAICFgjAAAICFkjAAAICFojAAAICFsjAAAICFwjAAAICF0jAAAICF4jAAAICF8jAAAICGAjAAAICGEjAAAICGIjAAAICGMjAAAICGQjAAAICGUjAAAICGYjAAAICGcjAAAICGgjAAAICGkjAAAICGojAAAICGsjAAAICGwjAAAICG0jAAAICG4jAAAICG8jAAAICHAjAAAICHEjAAAICHIjAAAICHMjAAAICHQjAAAICHUjAAAICHYjAAAICHcjAAAICHgjAAAICHkjAAAICHojAAAICHsjAAAICHwjAAAICH0jAAAICH4jAAAICH8jAAAICIAjAAAICIEjAAAICIIjAAAICIMjAAAICIQjAAAICIUjAAAICIYjAAAICIcjAAAICIgjAAAICIkjAAAICIojAAAICIsjAAAICIwjAAAICI0jAAAICI4jAAAICI8jAAAICJAjAAAICJEjAAAICJIjAAAICJMjAAAICJQjAAAICJUjAAAICJYjAAAICJcjAAAICJgjAAAICJkjAAAICJojAAAICJsjAAAICJwjAAAICJ0jAAAICJ4jAAAICJ8jAAAICKAjAAAICKEjAAAICKIjAAAICKMjAAAICKQjAAAICKUjAAAICKYjAAAICKcjAAAICKgjAAAICKkjAAAICKojAAAICKsjAAAICKwjAAAICK0jAAAICK4jAAAICK8jAAAICLAjAAAICLEjAAAICLIjAAAICLMjAAAICLQjAAAICLUjAAAICLYjAAAICLcjAAAICLgjAAAICLkjAAAICLojAAAICLsjAAAICLwjAAAICL0jAAAICL4jAAAICL8jAAAICMAjAAAICMEjAAAICMIjAAAICMMjAAAICMQjAAAICMUjAAAICMYjAAAICMcjAAAICMgjAAAICMkjAAAICMojAAAICMsjAAAICMwjAAAICM0jAAAICM4jAAAICM8jAAAICNAjAAAICNEjAAAICNIjAAAICNMjAAAICNQjAAAICNUjAAAICNYjAAAICNcjAAAICNgjAAAICNkjAAAICNojAAAICNsjAAAICNwjAAAICN0jAAAICN4jAAAICN8jAAAICOAjAAAICOEjAAAICOIjAAAICOMjAAAICOQjAAAICOUjAAAICOYjAAAICOcjAAAICOgjAAAICOkjAAAICOojAAAICOsjAAAICOwjAAAICO0jAAAICO4jAAAICO8jAAAICPAjAAAICPEjAAAICPIjAAAICPMjAAAICPQjAAAICPUjAAAICPYjAAAICPcjAAAICPgjAAAICPkjAAAICPojAAAICPsjAAAICPwjAAAICP0jAAAICP4jAAAICP8jAAAICAAkAAAICAEkAAAICAIkAAAICAMkAAAICAQkAAAICAUkAAAICAYkAAAICAckAAAICAgkAAAICAkkAAAICAokAAAICAskAAAICAwkAAAICA0kAAAICA4kAAAICA8kAAAICBAkAAAICBEkAAAICBIkAAAICBMkAAAICBQkAAAICBUkAAAICBYkAAAICBckAAAICBgkAAAICBkkAAAICBokAAAICBskAAAICBwkAAAICB0kAAAICB4kAAAICB8kAAAICCAkAAAICCEkAAAICCIkAAAICCMkAAAICCQkAAAICCUkAAAICCYkAAAICCckAAAICCgkAAAICCkkAAAICCokAAAICCskAAAICCwkAAAICC0kAAAICC4kAAAICC8kAAAICDAkAAAICDEkAAAICDIkAAAICDMkAAAICDQkAAAICDUkAAAICDYkAAAICDckAAAICDgkAAAICDkkAAAICDokAAAICDskAAAICDwkAAAICD0kAAAICD4kAAAICD8kAAAICEAkAAAICEEkAAAICEIkAAAICEMkAAAICEQkAAAICEUkAAAICEYkAAAICEckAAAICEgkAAAICEkkAAAICEokAAAICEskAAAICEwkAAAICE0kAAAICE4kAAAICE8kAAAICFAkAAAICFEkAAAICFIkAAAICFMkAAAICFQkAAAICFUkAAAICFYkAAAICFckAAAICFgkAAAICFkkAAAICFokAAAICFskAAAICFwkAAAICF0kAAAICF4kAAAICF8kAAAICGAkAAAICGEkAAAICGIkAAAICGMkAAAICGQkAAAICGUkAAAICGYkAAAICGckAAAICGgkAAAICGkkAAAICGokAAAICGskAAAICGwkAAAICG0kAAAICG4kAAAICG8kAAAICHAkAAAICHEkAAAICHIkAAAICHMkAAAICHQkAAAICHUkAAAICHYkAAAICHckAAAICHgkAAAICHkkAAAICHokAAAICHskAAAICHwkAAAICH0kAAAICH4kAAAICH8kAAAICIAkAAAICIEkAAAICIIkAAAICIMkAAAICIQkAAAICIUkAAAICIYkAAAICIckAAAICIgkAAAICIkkAAAICIokAAAICIskAAAICIwkAAAICI0kAAAICI4kAAAICI8kAAAICJAkAAAICJEkAAAICJIkAAAICJMkAAAICJQkAAAICJUkAAAICJYkAAAICJckAAAICJgkAAAICJkkAAAICJokAAAICJskAAAICJwkAAAICJ0kAAAICJ4kAAAICJ8kAAAICKAkAAAICKEkAAAICKIkAAAICKMkAAAICKQkAAAICKUkAAAICKYkAAAICKckAAAICKgkAAAICKkkAAAICKokAAAICKskAAAICKwkAAAICK0kAAAICK4kAAAICK8kAAAICLAkAAAICLEkAAAICLIkAAAICLMkAAAICLQkAAAICLUkAAAICLYkAAAICLckAAAICLgkAAAICLkkAAAICLokAAAICLskAAAICLwkAAAICL0kAAAICL4kAAAICL8kAAAICMAkAAAICMEkAAAICMIkAAAICMMkAAAICMQkAAAICMUkAAAICMYkAAAICMckAAAICMgkAAAICMkkAAAICMokAAAICMskAAAICMwkAAAICM0kAAAICM4kAAAICM8kAAAICNAkAAAICNEkAAAICNIkAAAICNMkAAAICNQkAAAICNUkAAAICNYkAAAICNckAAAICNgkAAAICNkkAAAICNokAAAICNskAAAICNwkAAAICN0kAAAICN4kAAAICN8kAAAICOAkAAAICOEkAAAICOIkAAAICOMkAAAICOQkAAAICOUkAAAICOYkAAAICOckAAAICOgkAAAICOkkAAAICOokAAAICOskAAAICOwkAAAICO0kAAAICO4kAAAICO8kAAAICPAkAAAICPEkAAAICPIkAAAICPMkAAAICPQkAAAICPUkAAAICPYkAAAICPckAAAICPgkAAAICPkkAAAICPokAAAICPskAAAICPwkAAAICP0kAAAICP4kAAAICP8kAAAICAAlAAAICAElAAAICAIlAAAICAMlAAAICAQlAAAICAUlAAAICAYlAAAICAclAAAICAglAAAICAklAAAICAolAAAICAslAAAICAwlAAAICA0lAAAICA4lAAAICA8lAAAICBAlAAAICBElAAAICBIlAAAICBMlAAAICBQlAAAICBUlAAAICBYlAAAICBclAAAICBglAAAICBklAAAICBolAAAICBslAAAICBwlAAAICB0lAAAICB4lAAAICB8lAAAICCAlAAAICCElAAAICCIlAAAICCMlAAAICCQlAAAICCUlAAAICCYlAAAICCclAAAICCglAAAICCklAAAICColAAAICCslAAAICCwlAAAICC0lAAAICC4lAAAICC8lAAAICDAlAAAICDElAAAICDIlAAAICDMlAAAICDQlAAAICDUlAAAICDYlAAAICDclAAAICDglAAAICDklAAAICDolAAAICDslAAAICDwlAAAICD0lAAAICD4lAAAICD8lAAAICEAlAAAICEElAAAICEIlAAAICEMlAAAICEQlAAAICEUlAAAICEYlAAAICEclAAAICEglAAAICEklAAAICEolAAAICEslAAAICEwlAAAICE0lAAAICE4lAAAICE8lAAAICFAlAAAICFElAAAICFIlAAAICFMlAAAICFQlAAAICFUlAAAICFYlAAAICFclAAAICFglAAAICFklAAAICFolAAAICFslAAAICFwlAAAICF0lAAAICF4lAAAICF8lAAAICGAlAAAICGElAAAICGIlAAAICGMlAAAICGQlAAAICGUlAAAICGYlAAAICGclAAAICGglAAAICGklAAAICGolAAAICGslAAAICGwlAAAICG0lAAAICG4lAAAICG8lAAAICHAlAAAICHElAAAICHIlAAAICHMlAAAICHQlAAAICHUlAAAICHYlAAAICHclAAAICHglAAAICHklAAAICHolAAAICHslAAAICHwlAAAICH0lAAAICH4lAAAICH8lAAAICIAlAAAICIElAAAICIIlAAAICIMlAAAICIQlAAAICIUlAAAICIYlAAAICIclAAAICIglAAAICIklAAAICIolAAAICIslAAAICIwlAAAICI0lAAAICI4lAAAICI8lAAAICJAlAAAICJElAAAICJIlAAAICJMlAAAICJQlAAAICJUlAAAICJYlAAAICJclAAAICJglAAAICJklAAAICJolAAAICJslAAAICJwlAAAICJ0lAAAICJ4lAAAICJ8lAAAICKAlAAAICKElAAAICKIlAAAICKMlAAAICKQlAAAICKUlAAAICKYlAAAICKclAAAICKglAAAICKklAAAICKolAAAICKslAAAICKwlAAAICK0lAAAICK4lAAAICK8lAAAICLAlAAAICLElAAAICLIlAAAICLMlAAAICLQlAAAICLUlAAAICLYlAAAICLclAAAICLglAAAICLklAAAICLolAAAICLslAAAICLwlAAAICL0lAAAICL4lAAAICL8lAAAICMAlAAAICMElAAAICMIlAAAICMMlAAAICMQlAAAICMUlAAAICMYlAAAICMclAAAICMglAAAICMklAAAICMolAAAICMslAAAICMwlAAAICM0lAAAICM4lAAAICM8lAAAICNAlAAAICNElAAAICNIlAAAICNMlAAAICNQlAAAICNUlAAAICNYlAAAICNclAAAICNglAAAICNklAAAICNolAAAICNslAAAICNwlAAAICN0lAAAICN4lAAAICN8lAAAICOAlAAAICOElAAAICOIlAAAICOMlAAAICOQlAAAICOUlAAAICOYlAAAICOclAAAICOglAAAICOklAAAICOolAAAICOslAAAICOwlAAAICO0lAAAICO4lAAAICO8lAAAICPAlAAAICPElAAAICPIlAAAICPMlAAAICPQlAAAICPUlAAAICPYlAAAICPclAAAICPglAAAICPklAAAICPolAAAICPslAAAICPwlAAAICP0lAAAICP4lAAAICP8lAAAICAAmAAAICAEmAAAICAImAAAICAMmAAAICAQmAAAICAUmAAAICAYmAAAICAcmAAAICAgmAAAICAkmAAAICAomAAAICAsmAAAICAwmAAAICA0mAAAICA4mAAAICA8mAAAICBAmAAAICBEmAAAICBImAAAICBMmAAAICBQmAAAICBUmAAAICBYmAAAICBcmAAAICBgmAAAICBkmAAAICBomAAAICBsmAAAICBwmAAAICB0mAAAICB4mAAAICB8mAAAICCAmAAAICCEmAAAICCImAAAICCMmAAAICCQmAAAICCUmAAAICCYmAAAICCcmAAAICCgmAAAICCkmAAAICComAAAICCsmAAAICCwmAAAICC0mAAAICC4mAAAICC8mAAAICDAmAAAICDEmAAAICDImAAAICDMmAAAICDQmAAAICDUmAAAICDYmAAAICDcmAAAICDgmAAAICDkmAAAICDomAAAICDsmAAAICDwmAAAICD0mAAAICD4mAAAICD8mAAAICEAmAAAICEEmAAAICEImAAAICEMmAAAICEQmAAAICEUmAAAICEYmAAAICEcmAAAICEgmAAAICEkmAAAICEomAAAICEsmAAAICEwmAAAICE0mAAAICE4mAAAICE8mAAAICFAmAAAICFEmAAAICFImAAAICFMmAAAICFQmAAAICFUmAAAICFYmAAAICFcmAAAICFgmAAAICFkmAAAICFomAAAICFsmAAAICFwmAAAICF0mAAAICF4mAAAICF8mAAAICGAmAAAICGEmAAAICGImAAAICGMmAAAICGQmAAAICGUmAAAICGYmAAAICGcmAAAICGgmAAAICGkmAAAICGomAAAICGsmAAAICGwmAAAICG0mAAAICG4mAAAICG8mAAAICHAmAAAICHEmAAAICHImAAAICHMmAAAICHQmAAAICHUmAAAICHYmAAAICHcmAAAICHgmAAAICHkmAAAICHomAAAICHsmAAAICHwmAAAICH0mAAAICH4mAAAICH8mAAAICIAmAAAICIEmAAAICIImAAAICIMmAAAICIQmAAAICIUmAAAICIYmAAAICIcmAAAICIgmAAAICIkmAAAICIomAAAICIsmAAAICIwmAAAICI0mAAAICI4mAAAICI8mAAAICJAmAAAICJEmAAAICJImAAAICJMmAAAICJQmAAAICJUmAAAICJYmAAAICJcmAAAICJgmAAAICJkmAAAICJomAAAICJsmAAAICJwmAAAICJ0mAAAICJ4mAAAICJ8mAAAICKAmAAAICKEmAAAICKImAAAICKMmAAAICKQmAAAICKUmAAAICKYmAAAICKcmAAAICKgmAAAICKkmAAAICKomAAAICKsmAAAICKwmAAAICK0mAAAICK4mAAAICK8mAAAICLAmAAAICLEmAAAICLImAAAICLMmAAAICLQmAAAICLUmAAAICLYmAAAICLcmAAAICLgmAAAICLkmAAAICLomAAAICLsmAAAICLwmAAAICL0mAAAICL4mAAAICL8mAAAICMAmAAAICMEmAAAICMImAAAICMMmAAAICMQmAAAICMUmAAAICMYmAAAICMcmAAAICMgmAAAICMkmAAAICMomAAAICMsmAAAICMwmAAAICM0mAAAICM4mAAAICM8mAAAICNAmAAAICNEmAAAICNImAAAICNMmAAAICNQmAAAICNUmAAAICNYmAAAICNcmAAAICNgmAAAICNkmAAAICNomAAAICNsmAAAICNwmAAAICN0mAAAICN4mAAAICN8mAAAICOAmAAAICOEmAAAICOImAAAICOMmAAAICOQmAAAICOUmAAAICOYmAAAICOcmAAAICOgmAAAICOkmAAAICOomAAAICOsmAAAICOwmAAAICO0mAAAICO4mAAAICO8mAAAICPAmAAAICPEmAAAICPImAAAICPMmAAAICPQmAAAICPUmAAAICPYmAAAICPcmAAAICPgmAAAICPkmAAAICPomAAAICPsmAAAICPwmAAAICP0mAAAICP4mAAAICP8mAAAICAAnAAAICAEnAAAICAInAAAICAMnAAAICAQnAAAICAUnAAAICAYnAAAICAcnAAAICAgnAAAICAknAAAICAonAAAICAsnAAAICAwnAAAICA0nAAAICA4nAAAICA8nAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAQAQAAABAnAAAICAAAAAAICAEAAAAICAIAAAAICAMAAAAICAQAAAAICAUAAAAICAYAAAAICAcAAAAICAgAAAAICAkAAAAICAoAAAAICAsAAAAICAwAAAAICA0AAAAICA4AAAAICA8AAAAICBAAAAAICBEAAAAICBIAAAAICBMAAAAICBQAAAAICBUAAAAICBYAAAAICBcAAAAICBgAAAAICBkAAAAICBoAAAAICBsAAAAICBwAAAAICB0AAAAICB4AAAAICB8AAAAICCAAAAAICCEAAAAICCIAAAAICCMAAAAICCQAAAAICCUAAAAICCYAAAAICCcAAAAICCgAAAAICCkAAAAICCoAAAAICCsAAAAICCwAAAAICC0AAAAICC4AAAAICC8AAAAICDAAAAAICDEAAAAICDIAAAAICDMAAAAICDQAAAAICDUAAAAICDYAAAAICDcAAAAICDgAAAAICDkAAAAICDoAAAAICDsAAAAICDwAAAAICD0AAAAICD4AAAAICD8AAAAICEAAAAAICEEAAAAICEIAAAAICEMAAAAICEQAAAAICEUAAAAICEYAAAAICEcAAAAICEgAAAAICEkAAAAICEoAAAAICEsAAAAICEwAAAAICE0AAAAICE4AAAAICE8AAAAICFAAAAAICFEAAAAICFIAAAAICFMAAAAICFQAAAAICFUAAAAICFYAAAAICFcAAAAICFgAAAAICFkAAAAICFoAAAAICFsAAAAICFwAAAAICF0AAAAICF4AAAAICF8AAAAICGAAAAAICGEAAAAICGIAAAAICGMAAAAICGQAAAAICGUAAAAICGYAAAAICGcAAAAICGgAAAAICGkAAAAICGoAAAAICGsAAAAICGwAAAAICG0AAAAICG4AAAAICG8AAAAICHAAAAAICHEAAAAICHIAAAAICHMAAAAICHQAAAAICHUAAAAICHYAAAAICHcAAAAICHgAAAAICHkAAAAICHoAAAAICHsAAAAICHwAAAAICH0AAAAICH4AAAAICH8AAAAICIAAAAAICIEAAAAICIIAAAAICIMAAAAICIQAAAAICIUAAAAICIYAAAAICIcAAAAICIgAAAAICIkAAAAICIoAAAAICIsAAAAICIwAAAAICI0AAAAICI4AAAAICI8AAAAICJAAAAAICJEAAAAICJIAAAAICJMAAAAICJQAAAAICJUAAAAICJYAAAAICJcAAAAICJgAAAAICJkAAAAICJoAAAAICJsAAAAICJwAAAAICJ0AAAAICJ4AAAAICJ8AAAAICKAAAAAICKEAAAAICKIAAAAICKMAAAAICKQAAAAICKUAAAAICKYAAAAICKcAAAAICKgAAAAICKkAAAAICKoAAAAICKsAAAAICKwAAAAICK0AAAAICK4AAAAICK8AAAAICLAAAAAICLEAAAAICLIAAAAICLMAAAAICLQAAAAICLUAAAAICLYAAAAICLcAAAAICLgAAAAICLkAAAAICLoAAAAICLsAAAAICLwAAAAICL0AAAAICL4AAAAICL8AAAAICMAAAAAICMEAAAAICMIAAAAICMMAAAAICMQAAAAICMUAAAAICMYAAAAICMcAAAAICMgAAAAICMkAAAAICMoAAAAICMsAAAAICMwAAAAICM0AAAAICM4AAAAICM8AAAAICNAAAAAICNEAAAAICNIAAAAICNMAAAAICNQAAAAICNUAAAAICNYAAAAICNcAAAAICNgAAAAICNkAAAAICNoAAAAICNsAAAAICNwAAAAICN0AAAAICN4AAAAICN8AAAAICOAAAAAICOEAAAAICOIAAAAICOMAAAAICOQAAAAICOUAAAAICOYAAAAICOcAAAAICOgAAAAICOkAAAAICOoAAAAICOsAAAAICOwAAAAICO0AAAAICO4AAAAICO8AAAAICPAAAAAICPEAAAAICPIAAAAICPMAAAAICPQAAAAICPUAAAAICPYAAAAICPcAAAAICPgAAAAICPkAAAAICPoAAAAICPsAAAAICPwAAAAICP0AAAAICP4AAAAICP8AAAAICAABAAAICAEBAAAICAIBAAAICAMBAAAICAQBAAAICAUBAAAICAYBAAAICAcBAAAICAgBAAAICAkBAAAICAoBAAAICAsBAAAICAwBAAAICA0BAAAICA4BAAAICA8BAAAICBABAAAICBEBAAAICBIBAAAICBMBAAAICBQBAAAICBUBAAAICBYBAAAICBcBAAAICBgBAAAICBkBAAAICBoBAAAICBsBAAAICBwBAAAICB0BAAAICB4BAAAICB8BAAAICCABAAAICCEBAAAICCIBAAAICCMBAAAICCQBAAAICCUBAAAICCYBAAAICCcBAAAICCgBAAAICCkBAAAICCoBAAAICCsBAAAICCwBAAAICC0BAAAICC4BAAAICC8BAAAICDABAAAICDEBAAAICDIBAAAICDMBAAAICDQBAAAICDUBAAAICDYBAAAICDcBAAAICDgBAAAICDkBAAAICDoBAAAICDsBAAAICDwBAAAICD0BAAAICD4BAAAICD8BAAAICEABAAAICEEBAAAICEIBAAAICEMBAAAICEQBAAAICEUBAAAICEYBAAAICEcBAAAICEgBAAAICEkBAAAICEoBAAAICEsBAAAICEwBAAAICE0BAAAICE4BAAAICE8BAAAICFABAAAICFEBAAAICFIBAAAICFMBAAAICFQBAAAICFUBAAAICFYBAAAICFcBAAAICFgBAAAICFkBAAAICFoBAAAICFsBAAAICFwBAAAICF0BAAAICF4BAAAICF8BAAAICGABAAAICGEBAAAICGIBAAAICGMBAAAICGQBAAAICGUBAAAICGYBAAAICGcBAAAICGgBAAAICGkBAAAICGoBAAAICGsBAAAICGwBAAAICG0BAAAICG4BAAAICG8BAAAICHABAAAICHEBAAAICHIBAAAICHMBAAAICHQBAAAICHUBAAAICHYBAAAICHcBAAAICHgBAAAICHkBAAAICHoBAAAICHsBAAAICHwBAAAICH0BAAAICH4BAAAICH8BAAAICIABAAAICIEBAAAICIIBAAAICIMBAAAICIQBAAAICIUBAAAICIYBAAAICIcBAAAICIgBAAAICIkBAAAICIoBAAAICIsBAAAICIwBAAAICI0BAAAICI4BAAAICI8BAAAICJABAAAICJEBAAAICJIBAAAICJMBAAAICJQBAAAICJUBAAAICJYBAAAICJcBAAAICJgBAAAICJkBAAAICJoBAAAICJsBAAAICJwBAAAICJ0BAAAICJ4BAAAICJ8BAAAICKABAAAICKEBAAAICKIBAAAICKMBAAAICKQBAAAICKUBAAAICKYBAAAICKcBAAAICKgBAAAICKkBAAAICKoBAAAICKsBAAAICKwBAAAICK0BAAAICK4BAAAICK8BAAAICLABAAAICLEBAAAICLIBAAAICLMBAAAICLQBAAAICLUBAAAICLYBAAAICLcBAAAICLgBAAAICLkBAAAICLoBAAAICLsBAAAICLwBAAAICL0BAAAICL4BAAAICL8BAAAICMABAAAICMEBAAAICMIBAAAICMMBAAAICMQBAAAICMUBAAAICMYBAAAICMcBAAAICMgBAAAICMkBAAAICMoBAAAICMsBAAAICMwBAAAICM0BAAAICM4BAAAICM8BAAAICNABAAAICNEBAAAICNIBAAAICNMBAAAICNQBAAAICNUBAAAICNYBAAAICNcBAAAICNgBAAAICNkBAAAICNoBAAAICNsBAAAICNwBAAAICN0BAAAICN4BAAAICN8BAAAICOABAAAICOEBAAAICOIBAAAICOMBAAAICOQBAAAICOUBAAAICOYBAAAICOcBAAAICOgBAAAICOkBAAAICOoBAAAICOsBAAAICOwBAAAICO0BAAAICO4BAAAICO8BAAAICPABAAAICPEBAAAICPIBAAAICPMBAAAICPQBAAAICPUBAAAICPYBAAAICPcBAAAICPgBAAAICPkBAAAICPoBAAAICPsBAAAICPwBAAAICP0BAAAICP4BAAAICP8BAAAICAACAAAICAECAAAICAICAAAICAMCAAAICAQCAAAICAUCAAAICAYCAAAICAcCAAAICAgCAAAICAkCAAAICAoCAAAICAsCAAAICAwCAAAICA0CAAAICA4CAAAICA8CAAAICBACAAAICBECAAAICBICAAAICBMCAAAICBQCAAAICBUCAAAICBYCAAAICBcCAAAICBgCAAAICBkCAAAICBoCAAAICBsCAAAICBwCAAAICB0CAAAICB4CAAAICB8CAAAICCACAAAICCECAAAICCICAAAICCMCAAAICCQCAAAICCUCAAAICCYCAAAICCcCAAAICCgCAAAICCkCAAAICCoCAAAICCsCAAAICCwCAAAICC0CAAAICC4CAAAICC8CAAAICDACAAAICDECAAAICDICAAAICDMCAAAICDQCAAAICDUCAAAICDYCAAAICDcCAAAICDgCAAAICDkCAAAICDoCAAAICDsCAAAICDwCAAAICD0CAAAICD4CAAAICD8CAAAICEACAAAICEECAAAICEICAAAICEMCAAAICEQCAAAICEUCAAAICEYCAAAICEcCAAAICEgCAAAICEkCAAAICEoCAAAICEsCAAAICEwCAAAICE0CAAAICE4CAAAICE8CAAAICFACAAAICFECAAAICFICAAAICFMCAAAICFQCAAAICFUCAAAICFYCAAAICFcCAAAICFgCAAAICFkCAAAICFoCAAAICFsCAAAICFwCAAAICF0CAAAICF4CAAAICF8CAAAICGACAAAICGECAAAICGICAAAICGMCAAAICGQCAAAICGUCAAAICGYCAAAICGcCAAAICGgCAAAICGkCAAAICGoCAAAICGsCAAAICGwCAAAICG0CAAAICG4CAAAICG8CAAAICHACAAAICHECAAAICHICAAAICHMCAAAICHQCAAAICHUCAAAICHYCAAAICHcCAAAICHgCAAAICHkCAAAICHoCAAAICHsCAAAICHwCAAAICH0CAAAICH4CAAAICH8CAAAICIACAAAICIECAAAICIICAAAICIMCAAAICIQCAAAICIUCAAAICIYCAAAICIcCAAAICIgCAAAICIkCAAAICIoCAAAICIsCAAAICIwCAAAICI0CAAAICI4CAAAICI8CAAAICJACAAAICJECAAAICJICAAAICJMCAAAICJQCAAAICJUCAAAICJYCAAAICJcCAAAICJgCAAAICJkCAAAICJoCAAAICJsCAAAICJwCAAAICJ0CAAAICJ4CAAAICJ8CAAAICKACAAAICKECAAAICKICAAAICKMCAAAICKQCAAAICKUCAAAICKYCAAAICKcCAAAICKgCAAAICKkCAAAICKoCAAAICKsCAAAICKwCAAAICK0CAAAICK4CAAAICK8CAAAICLACAAAICLECAAAICLICAAAICLMCAAAICLQCAAAICLUCAAAICLYCAAAICLcCAAAICLgCAAAICLkCAAAICLoCAAAICLsCAAAICLwCAAAICL0CAAAICL4CAAAICL8CAAAICMACAAAICMECAAAICMICAAAICMMCAAAICMQCAAAICMUCAAAICMYCAAAICMcCAAAICMgCAAAICMkCAAAICMoCAAAICMsCAAAICMwCAAAICM0CAAAICM4CAAAICM8CAAAICNACAAAICNECAAAICNICAAAICNMCAAAICNQCAAAICNUCAAAICNYCAAAICNcCAAAICNgCAAAICNkCAAAICNoCAAAICNsCAAAICNwCAAAICN0CAAAICN4CAAAICN8CAAAICOACAAAICOECAAAICOICAAAICOMCAAAICOQCAAAICOUCAAAICOYCAAAICOcCAAAICOgCAAAICOkCAAAICOoCAAAICOsCAAAICOwCAAAICO0CAAAICO4CAAAICO8CAAAICPACAAAICPECAAAICPICAAAICPMCAAAICPQCAAAICPUCAAAICPYCAAAICPcCAAAICPgCAAAICPkCAAAICPoCAAAICPsCAAAICPwCAAAICP0CAAAICP4CAAAICP8CAAAICAADAAAICAEDAAAICAIDAAAICAMDAAAICAQDAAAICAUDAAAICAYDAAAICAcDAAAICAgDAAAICAkDAAAICAoDAAAICAsDAAAICAwDAAAICA0DAAAICA4DAAAICA8DAAAICBADAAAICBEDAAAICBIDAAAICBMDAAAICBQDAAAICBUDAAAICBYDAAAICBcDAAAICBgDAAAICBkDAAAICBoDAAAICBsDAAAICBwDAAAICB0DAAAICB4DAAAICB8DAAAICCADAAAICCEDAAAICCIDAAAICCMDAAAICCQDAAAICCUDAAAICCYDAAAICCcDAAAICCgDAAAICCkDAAAICCoDAAAICCsDAAAICCwDAAAICC0DAAAICC4DAAAICC8DAAAICDADAAAICDEDAAAICDIDAAAICDMDAAAICDQDAAAICDUDAAAICDYDAAAICDcDAAAICDgDAAAICDkDAAAICDoDAAAICDsDAAAICDwDAAAICD0DAAAICD4DAAAICD8DAAAICEADAAAICEEDAAAICEIDAAAICEMDAAAICEQDAAAICEUDAAAICEYDAAAICEcDAAAICEgDAAAICEkDAAAICEoDAAAICEsDAAAICEwDAAAICE0DAAAICE4DAAAICE8DAAAICFADAAAICFEDAAAICFIDAAAICFMDAAAICFQDAAAICFUDAAAICFYDAAAICFcDAAAICFgDAAAICFkDAAAICFoDAAAICFsDAAAICFwDAAAICF0DAAAICF4DAAAICF8DAAAICGADAAAICGEDAAAICGIDAAAICGMDAAAICGQDAAAICGUDAAAICGYDAAAICGcDAAAICGgDAAAICGkDAAAICGoDAAAICGsDAAAICGwDAAAICG0DAAAICG4DAAAICG8DAAAICHADAAAICHEDAAAICHIDAAAICHMDAAAICHQDAAAICHUDAAAICHYDAAAICHcDAAAICHgDAAAICHkDAAAICHoDAAAICHsDAAAICHwDAAAICH0DAAAICH4DAAAICH8DAAAICIADAAAICIEDAAAICIIDAAAICIMDAAAICIQDAAAICIUDAAAICIYDAAAICIcDAAAICIgDAAAICIkDAAAICIoDAAAICIsDAAAICIwDAAAICI0DAAAICI4DAAAICI8DAAAICJADAAAICJEDAAAICJIDAAAICJMDAAAICJQDAAAICJUDAAAICJYDAAAICJcDAAAICJgDAAAICJkDAAAICJoDAAAICJsDAAAICJwDAAAICJ0DAAAICJ4DAAAICJ8DAAAICKADAAAICKEDAAAICKIDAAAICKMDAAAICKQDAAAICKUDAAAICKYDAAAICKcDAAAICKgDAAAICKkDAAAICKoDAAAICKsDAAAICKwDAAAICK0DAAAICK4DAAAICK8DAAAICLADAAAICLEDAAAICLIDAAAICLMDAAAICLQDAAAICLUDAAAICLYDAAAICLcDAAAICLgDAAAICLkDAAAICLoDAAAICLsDAAAICLwDAAAICL0DAAAICL4DAAAICL8DAAAICMADAAAICMEDAAAICMIDAAAICMMDAAAICMQDAAAICMUDAAAICMYDAAAICMcDAAAICMgDAAAICMkDAAAICMoDAAAICMsDAAAICMwDAAAICM0DAAAICM4DAAAICM8DAAAICNADAAAICNEDAAAICNIDAAAICNMDAAAICNQDAAAICNUDAAAICNYDAAAICNcDAAAICNgDAAAICNkDAAAICNoDAAAICNsDAAAICNwDAAAICN0DAAAICN4DAAAICN8DAAAICOADAAAICOEDAAAICOIDAAAICOMDAAAICOQDAAAICOUDAAAICOYDAAAICOcDAAAICOgDAAAICOkDAAAICOoDAAAICOsDAAAICOwDAAAICO0DAAAICO4DAAAICO8DAAAICPADAAAICPEDAAAICPIDAAAICPMDAAAICPQDAAAICPUDAAAICPYDAAAICPcDAAAICPgDAAAICPkDAAAICPoDAAAICPsDAAAICPwDAAAICP0DAAAICP4DAAAICP8DAAAICAAEAAAICAEEAAAICAIEAAAICAMEAAAICAQEAAAICAUEAAAICAYEAAAICAcEAAAICAgEAAAICAkEAAAICAoEAAAICAsEAAAICAwEAAAICA0EAAAICA4EAAAICA8EAAAICBAEAAAICBEEAAAICBIEAAAICBMEAAAICBQEAAAICBUEAAAICBYEAAAICBcEAAAICBgEAAAICBkEAAAICBoEAAAICBsEAAAICBwEAAAICB0EAAAICB4EAAAICB8EAAAICCAEAAAICCEEAAAICCIEAAAICCMEAAAICCQEAAAICCUEAAAICCYEAAAICCcEAAAICCgEAAAICCkEAAAICCoEAAAICCsEAAAICCwEAAAICC0EAAAICC4EAAAICC8EAAAICDAEAAAICDEEAAAICDIEAAAICDMEAAAICDQEAAAICDUEAAAICDYEAAAICDcEAAAICDgEAAAICDkEAAAICDoEAAAICDsEAAAICDwEAAAICD0EAAAICD4EAAAICD8EAAAICEAEAAAICEEEAAAICEIEAAAICEMEAAAICEQEAAAICEUEAAAICEYEAAAICEcEAAAICEgEAAAICEkEAAAICEoEAAAICEsEAAAICEwEAAAICE0EAAAICE4EAAAICE8EAAAICFAEAAAICFEEAAAICFIEAAAICFMEAAAICFQEAAAICFUEAAAICFYEAAAICFcEAAAICFgEAAAICFkEAAAICFoEAAAICFsEAAAICFwEAAAICF0EAAAICF4EAAAICF8EAAAICGAEAAAICGEEAAAICGIEAAAICGMEAAAICGQEAAAICGUEAAAICGYEAAAICGcEAAAICGgEAAAICGkEAAAICGoEAAAICGsEAAAICGwEAAAICG0EAAAICG4EAAAICG8EAAAICHAEAAAICHEEAAAICHIEAAAICHMEAAAICHQEAAAICHUEAAAICHYEAAAICHcEAAAICHgEAAAICHkEAAAICHoEAAAICHsEAAAICHwEAAAICH0EAAAICH4EAAAICH8EAAAICIAEAAAICIEEAAAICIIEAAAICIMEAAAICIQEAAAICIUEAAAICIYEAAAICIcEAAAICIgEAAAICIkEAAAICIoEAAAICIsEAAAICIwEAAAICI0EAAAICI4EAAAICI8EAAAICJAEAAAICJEEAAAICJIEAAAICJMEAAAICJQEAAAICJUEAAAICJYEAAAICJcEAAAICJgEAAAICJkEAAAICJoEAAAICJsEAAAICJwEAAAICJ0EAAAICJ4EAAAICJ8EAAAICKAEAAAICKEEAAAICKIEAAAICKMEAAAICKQEAAAICKUEAAAICKYEAAAICKcEAAAICKgEAAAICKkEAAAICKoEAAAICKsEAAAICKwEAAAICK0EAAAICK4EAAAICK8EAAAICLAEAAAICLEEAAAICLIEAAAICLMEAAAICLQEAAAICLUEAAAICLYEAAAICLcEAAAICLgEAAAICLkEAAAICLoEAAAICLsEAAAICLwEAAAICL0EAAAICL4EAAAICL8EAAAICMAEAAAICMEEAAAICMIEAAAICMMEAAAICMQEAAAICMUEAAAICMYEAAAICMcEAAAICMgEAAAICMkEAAAICMoEAAAICMsEAAAICMwEAAAICM0EAAAICM4EAAAICM8EAAAICNAEAAAICNEEAAAICNIEAAAICNMEAAAICNQEAAAICNUEAAAICNYEAAAICNcEAAAICNgEAAAICNkEAAAICNoEAAAICNsEAAAICNwEAAAICN0EAAAICN4EAAAICN8EAAAICOAEAAAICOEEAAAICOIEAAAICOMEAAAICOQEAAAICOUEAAAICOYEAAAICOcEAAAICOgEAAAICOkEAAAICOoEAAAICOsEAAAICOwEAAAICO0EAAAICO4EAAAICO8EAAAICPAEAAAICPEEAAAICPIEAAAICPMEAAAICPQEAAAICPUEAAAICPYEAAAICPcEAAAICPgEAAAICPkEAAAICPoEAAAICPsEAAAICPwEAAAICP0EAAAICP4EAAAICP8EAAAICAAFAAAICAEFAAAICAIFAAAICAMFAAAICAQFAAAICAUFAAAICAYFAAAICAcFAAAICAgFAAAICAkFAAAICAoFAAAICAsFAAAICAwFAAAICA0FAAAICA4FAAAICA8FAAAICBAFAAAICBEFAAAICBIFAAAICBMFAAAICBQFAAAICBUFAAAICBYFAAAICBcFAAAICBgFAAAICBkFAAAICBoFAAAICBsFAAAICBwFAAAICB0FAAAICB4FAAAICB8FAAAICCAFAAAICCEFAAAICCIFAAAICCMFAAAICCQFAAAICCUFAAAICCYFAAAICCcFAAAICCgFAAAICCkFAAAICCoFAAAICCsFAAAICCwFAAAICC0FAAAICC4FAAAICC8FAAAICDAFAAAICDEFAAAICDIFAAAICDMFAAAICDQFAAAICDUFAAAICDYFAAAICDcFAAAICDgFAAAICDkFAAAICDoFAAAICDsFAAAICDwFAAAICD0FAAAICD4FAAAICD8FAAAICEAFAAAICEEFAAAICEIFAAAICEMFAAAICEQFAAAICEUFAAAICEYFAAAICEcFAAAICEgFAAAICEkFAAAICEoFAAAICEsFAAAICEwFAAAICE0FAAAICE4FAAAICE8FAAAICFAFAAAICFEFAAAICFIFAAAICFMFAAAICFQFAAAICFUFAAAICFYFAAAICFcFAAAICFgFAAAICFkFAAAICFoFAAAICFsFAAAICFwFAAAICF0FAAAICF4FAAAICF8FAAAICGAFAAAICGEFAAAICGIFAAAICGMFAAAICGQFAAAICGUFAAAICGYFAAAICGcFAAAICGgFAAAICGkFAAAICGoFAAAICGsFAAAICGwFAAAICG0FAAAICG4FAAAICG8FAAAICHAFAAAICHEFAAAICHIFAAAICHMFAAAICHQFAAAICHUFAAAICHYFAAAICHcFAAAICHgFAAAICHkFAAAICHoFAAAICHsFAAAICHwFAAAICH0FAAAICH4FAAAICH8FAAAICIAFAAAICIEFAAAICIIFAAAICIMFAAAICIQFAAAICIUFAAAICIYFAAAICIcFAAAICIgFAAAICIkFAAAICIoFAAAICIsFAAAICIwFAAAICI0FAAAICI4FAAAICI8FAAAICJAFAAAICJEFAAAICJIFAAAICJMFAAAICJQFAAAICJUFAAAICJYFAAAICJcFAAAICJgFAAAICJkFAAAICJoFAAAICJsFAAAICJwFAAAICJ0FAAAICJ4FAAAICJ8FAAAICKAFAAAICKEFAAAICKIFAAAICKMFAAAICKQFAAAICKUFAAAICKYFAAAICKcFAAAICKgFAAAICKkFAAAICKoFAAAICKsFAAAICKwFAAAICK0FAAAICK4FAAAICK8FAAAICLAFAAAICLEFAAAICLIFAAAICLMFAAAICLQFAAAICLUFAAAICLYFAAAICLcFAAAICLgFAAAICLkFAAAICLoFAAAICLsFAAAICLwFAAAICL0FAAAICL4FAAAICL8FAAAICMAFAAAICMEFAAAICMIFAAAICMMFAAAICMQFAAAICMUFAAAICMYFAAAICMcFAAAICMgFAAAICMkFAAAICMoFAAAICMsFAAAICMwFAAAICM0FAAAICM4FAAAICM8FAAAICNAFAAAICNEFAAAICNIFAAAICNMFAAAICNQFAAAICNUFAAAICNYFAAAICNcFAAAICNgFAAAICNkFAAAICNoFAAAICNsFAAAICNwFAAAICN0FAAAICN4FAAAICN8FAAAICOAFAAAICOEFAAAICOIFAAAICOMFAAAICOQFAAAICOUFAAAICOYFAAAICOcFAAAICOgFAAAICOkFAAAICOoFAAAICOsFAAAICOwFAAAICO0FAAAICO4FAAAICO8FAAAICPAFAAAICPEFAAAICPIFAAAICPMFAAAICPQFAAAICPUFAAAICPYFAAAICPcFAAAICPgFAAAICPkFAAAICPoFAAAICPsFAAAICPwFAAAICP0FAAAICP4FAAAICP8FAAAICAAGAAAICAEGAAAICAIGAAAICAMGAAAICAQGAAAICAUGAAAICAYGAAAICAcGAAAICAgGAAAICAkGAAAICAoGAAAICAsGAAAICAwGAAAICA0GAAAICA4GAAAICA8GAAAICBAGAAAICBEGAAAICBIGAAAICBMGAAAICBQGAAAICBUGAAAICBYGAAAICBcGAAAICBgGAAAICBkGAAAICBoGAAAICBsGAAAICBwGAAAICB0GAAAICB4GAAAICB8GAAAICCAGAAAICCEGAAAICCIGAAAICCMGAAAICCQGAAAICCUGAAAICCYGAAAICCcGAAAICCgGAAAICCkGAAAICCoGAAAICCsGAAAICCwGAAAICC0GAAAICC4GAAAICC8GAAAICDAGAAAICDEGAAAICDIGAAAICDMGAAAICDQGAAAICDUGAAAICDYGAAAICDcGAAAICDgGAAAICDkGAAAICDoGAAAICDsGAAAICDwGAAAICD0GAAAICD4GAAAICD8GAAAICEAGAAAICEEGAAAICEIGAAAICEMGAAAICEQGAAAICEUGAAAICEYGAAAICEcGAAAICEgGAAAICEkGAAAICEoGAAAICEsGAAAICEwGAAAICE0GAAAICE4GAAAICE8GAAAICFAGAAAICFEGAAAICFIGAAAICFMGAAAICFQGAAAICFUGAAAICFYGAAAICFcGAAAICFgGAAAICFkGAAAICFoGAAAICFsGAAAICFwGAAAICF0GAAAICF4GAAAICF8GAAAICGAGAAAICGEGAAAICGIGAAAICGMGAAAICGQGAAAICGUGAAAICGYGAAAICGcGAAAICGgGAAAICGkGAAAICGoGAAAICGsGAAAICGwGAAAICG0GAAAICG4GAAAICG8GAAAICHAGAAAICHEGAAAICHIGAAAICHMGAAAICHQGAAAICHUGAAAICHYGAAAICHcGAAAICHgGAAAICHkGAAAICHoGAAAICHsGAAAICHwGAAAICH0GAAAICH4GAAAICH8GAAAICIAGAAAICIEGAAAICIIGAAAICIMGAAAICIQGAAAICIUGAAAICIYGAAAICIcGAAAICIgGAAAICIkGAAAICIoGAAAICIsGAAAICIwGAAAICI0GAAAICI4GAAAICI8GAAAICJAGAAAICJEGAAAICJIGAAAICJMGAAAICJQGAAAICJUGAAAICJYGAAAICJcGAAAICJgGAAAICJkGAAAICJoGAAAICJsGAAAICJwGAAAICJ0GAAAICJ4GAAAICJ8GAAAICKAGAAAICKEGAAAICKIGAAAICKMGAAAICKQGAAAICKUGAAAICKYGAAAICKcGAAAICKgGAAAICKkGAAAICKoGAAAICKsGAAAICKwGAAAICK0GAAAICK4GAAAICK8GAAAICLAGAAAICLEGAAAICLIGAAAICLMGAAAICLQGAAAICLUGAAAICLYGAAAICLcGAAAICLgGAAAICLkGAAAICLoGAAAICLsGAAAICLwGAAAICL0GAAAICL4GAAAICL8GAAAICMAGAAAICMEGAAAICMIGAAAICMMGAAAICMQGAAAICMUGAAAICMYGAAAICMcGAAAICMgGAAAICMkGAAAICMoGAAAICMsGAAAICMwGAAAICM0GAAAICM4GAAAICM8GAAAICNAGAAAICNEGAAAICNIGAAAICNMGAAAICNQGAAAICNUGAAAICNYGAAAICNcGAAAICNgGAAAICNkGAAAICNoGAAAICNsGAAAICNwGAAAICN0GAAAICN4GAAAICN8GAAAICOAGAAAICOEGAAAICOIGAAAICOMGAAAICOQGAAAICOUGAAAICOYGAAAICOcGAAAICOgGAAAICOkGAAAICOoGAAAICOsGAAAICOwGAAAICO0GAAAICO4GAAAICO8GAAAICPAGAAAICPEGAAAICPIGAAAICPMGAAAICPQGAAAICPUGAAAICPYGAAAICPcGAAAICPgGAAAICPkGAAAICPoGAAAICPsGAAAICPwGAAAICP0GAAAICP4GAAAICP8GAAAICAAHAAAICAEHAAAICAIHAAAICAMHAAAICAQHAAAICAUHAAAICAYHAAAICAcHAAAICAgHAAAICAkHAAAICAoHAAAICAsHAAAICAwHAAAICA0HAAAICA4HAAAICA8HAAAICBAHAAAICBEHAAAICBIHAAAICBMHAAAICBQHAAAICBUHAAAICBYHAAAICBcHAAAICBgHAAAICBkHAAAICBoHAAAICBsHAAAICBwHAAAICB0HAAAICB4HAAAICB8HAAAICCAHAAAICCEHAAAICCIHAAAICCMHAAAICCQHAAAICCUHAAAICCYHAAAICCcHAAAICCgHAAAICCkHAAAICCoHAAAICCsHAAAICCwHAAAICC0HAAAICC4HAAAICC8HAAAICDAHAAAICDEHAAAICDIHAAAICDMHAAAICDQHAAAICDUHAAAICDYHAAAICDcHAAAICDgHAAAICDkHAAAICDoHAAAICDsHAAAICDwHAAAICD0HAAAICD4HAAAICD8HAAAICEAHAAAICEEHAAAICEIHAAAICEMHAAAICEQHAAAICEUHAAAICEYHAAAICEcHAAAICEgHAAAICEkHAAAICEoHAAAICEsHAAAICEwHAAAICE0HAAAICE4HAAAICE8HAAAICFAHAAAICFEHAAAICFIHAAAICFMHAAAICFQHAAAICFUHAAAICFYHAAAICFcHAAAICFgHAAAICFkHAAAICFoHAAAICFsHAAAICFwHAAAICF0HAAAICF4HAAAICF8HAAAICGAHAAAICGEHAAAICGIHAAAICGMHAAAICGQHAAAICGUHAAAICGYHAAAICGcHAAAICGgHAAAICGkHAAAICGoHAAAICGsHAAAICGwHAAAICG0HAAAICG4HAAAICG8HAAAICHAHAAAICHEHAAAICHIHAAAICHMHAAAICHQHAAAICHUHAAAICHYHAAAICHcHAAAICHgHAAAICHkHAAAICHoHAAAICHsHAAAICHwHAAAICH0HAAAICH4HAAAICH8HAAAICIAHAAAICIEHAAAICIIHAAAICIMHAAAICIQHAAAICIUHAAAICIYHAAAICIcHAAAICIgHAAAICIkHAAAICIoHAAAICIsHAAAICIwHAAAICI0HAAAICI4HAAAICI8HAAAICJAHAAAICJEHAAAICJIHAAAICJMHAAAICJQHAAAICJUHAAAICJYHAAAICJcHAAAICJgHAAAICJkHAAAICJoHAAAICJsHAAAICJwHAAAICJ0HAAAICJ4HAAAICJ8HAAAICKAHAAAICKEHAAAICKIHAAAICKMHAAAICKQHAAAICKUHAAAICKYHAAAICKcHAAAICKgHAAAICKkHAAAICKoHAAAICKsHAAAICKwHAAAICK0HAAAICK4HAAAICK8HAAAICLAHAAAICLEHAAAICLIHAAAICLMHAAAICLQHAAAICLUHAAAICLYHAAAICLcHAAAICLgHAAAICLkHAAAICLoHAAAICLsHAAAICLwHAAAICL0HAAAICL4HAAAICL8HAAAICMAHAAAICMEHAAAICMIHAAAICMMHAAAICMQHAAAICMUHAAAICMYHAAAICMcHAAAICMgHAAAICMkHAAAICMoHAAAICMsHAAAICMwHAAAICM0HAAAICM4HAAAICM8HAAAICNAHAAAICNEHAAAICNIHAAAICNMHAAAICNQHAAAICNUHAAAICNYHAAAICNcHAAAICNgHAAAICNkHAAAICNoHAAAICNsHAAAICNwHAAAICN0HAAAICN4HAAAICN8HAAAICOAHAAAICOEHAAAICOIHAAAICOMHAAAICOQHAAAICOUHAAAICOYHAAAICOcHAAAICOgHAAAICOkHAAAICOoHAAAICOsHAAAICOwHAAAICO0HAAAICO4HAAAICO8HAAAICPAHAAAICPEHAAAICPIHAAAICPMHAAAICPQHAAAICPUHAAAICPYHAAAICPcHAAAICPgHAAAICPkHAAAICPoHAAAICPsHAAAICPwHAAAICP0HAAAICP4HAAAICP8HAAAICAAIAAAICAEIAAAICAIIAAAICAMIAAAICAQIAAAICAUIAAAICAYIAAAICAcIAAAICAgIAAAICAkIAAAICAoIAAAICAsIAAAICAwIAAAICA0IAAAICA4IAAAICA8IAAAICBAIAAAICBEIAAAICBIIAAAICBMIAAAICBQIAAAICBUIAAAICBYIAAAICBcIAAAICBgIAAAICBkIAAAICBoIAAAICBsIAAAICBwIAAAICB0IAAAICB4IAAAICB8IAAAICCAIAAAICCEIAAAICCIIAAAICCMIAAAICCQIAAAICCUIAAAICCYIAAAICCcIAAAICCgIAAAICCkIAAAICCoIAAAICCsIAAAICCwIAAAICC0IAAAICC4IAAAICC8IAAAICDAIAAAICDEIAAAICDIIAAAICDMIAAAICDQIAAAICDUIAAAICDYIAAAICDcIAAAICDgIAAAICDkIAAAICDoIAAAICDsIAAAICDwIAAAICD0IAAAICD4IAAAICD8IAAAICEAIAAAICEEIAAAICEIIAAAICEMIAAAICEQIAAAICEUIAAAICEYIAAAICEcIAAAICEgIAAAICEkIAAAICEoIAAAICEsIAAAICEwIAAAICE0IAAAICE4IAAAICE8IAAAICFAIAAAICFEIAAAICFIIAAAICFMIAAAICFQIAAAICFUIAAAICFYIAAAICFcIAAAICFgIAAAICFkIAAAICFoIAAAICFsIAAAICFwIAAAICF0IAAAICF4IAAAICF8IAAAICGAIAAAICGEIAAAICGIIAAAICGMIAAAICGQIAAAICGUIAAAICGYIAAAICGcIAAAICGgIAAAICGkIAAAICGoIAAAICGsIAAAICGwIAAAICG0IAAAICG4IAAAICG8IAAAICHAIAAAICHEIAAAICHIIAAAICHMIAAAICHQIAAAICHUIAAAICHYIAAAICHcIAAAICHgIAAAICHkIAAAICHoIAAAICHsIAAAICHwIAAAICH0IAAAICH4IAAAICH8IAAAICIAIAAAICIEIAAAICIIIAAAICIMIAAAICIQIAAAICIUIAAAICIYIAAAICIcIAAAICIgIAAAICIkIAAAICIoIAAAICIsIAAAICIwIAAAICI0IAAAICI4IAAAICI8IAAAICJAIAAAICJEIAAAICJIIAAAICJMIAAAICJQIAAAICJUIAAAICJYIAAAICJcIAAAICJgIAAAICJkIAAAICJoIAAAICJsIAAAICJwIAAAICJ0IAAAICJ4IAAAICJ8IAAAICKAIAAAICKEIAAAICKIIAAAICKMIAAAICKQIAAAICKUIAAAICKYIAAAICKcIAAAICKgIAAAICKkIAAAICKoIAAAICKsIAAAICKwIAAAICK0IAAAICK4IAAAICK8IAAAICLAIAAAICLEIAAAICLIIAAAICLMIAAAICLQIAAAICLUIAAAICLYIAAAICLcIAAAICLgIAAAICLkIAAAICLoIAAAICLsIAAAICLwIAAAICL0IAAAICL4IAAAICL8IAAAICMAIAAAICMEIAAAICMIIAAAICMMIAAAICMQIAAAICMUIAAAICMYIAAAICMcIAAAICMgIAAAICMkIAAAICMoIAAAICMsIAAAICMwIAAAICM0IAAAICM4IAAAICM8IAAAICNAIAAAICNEIAAAICNIIAAAICNMIAAAICNQIAAAICNUIAAAICNYIAAAICNcIAAAICNgIAAAICNkIAAAICNoIAAAICNsIAAAICNwIAAAICN0IAAAICN4IAAAICN8IAAAICOAIAAAICOEIAAAICOIIAAAICOMIAAAICOQIAAAICOUIAAAICOYIAAAICOcIAAAICOgIAAAICOkIAAAICOoIAAAICOsIAAAICOwIAAAICO0IAAAICO4IAAAICO8IAAAICPAIAAAICPEIAAAICPIIAAAICPMIAAAICPQIAAAICPUIAAAICPYIAAAICPcIAAAICPgIAAAICPkIAAAICPoIAAAICPsIAAAICPwIAAAICP0IAAAICP4IAAAICP8IAAAICAAJAAAICAEJAAAICAIJAAAICAMJAAAICAQJAAAICAUJAAAICAYJAAAICAcJAAAICAgJAAAICAkJAAAICAoJAAAICAsJAAAICAwJAAAICA0JAAAICA4JAAAICA8JAAAICBAJAAAICBEJAAAICBIJAAAICBMJAAAICBQJAAAICBUJAAAICBYJAAAICBcJAAAICBgJAAAICBkJAAAICBoJAAAICBsJAAAICBwJAAAICB0JAAAICB4JAAAICB8JAAAICCAJAAAICCEJAAAICCIJAAAICCMJAAAICCQJAAAICCUJAAAICCYJAAAICCcJAAAICCgJAAAICCkJAAAICCoJAAAICCsJAAAICCwJAAAICC0JAAAICC4JAAAICC8JAAAICDAJAAAICDEJAAAICDIJAAAICDMJAAAICDQJAAAICDUJAAAICDYJAAAICDcJAAAICDgJAAAICDkJAAAICDoJAAAICDsJAAAICDwJAAAICD0JAAAICD4JAAAICD8JAAAICEAJAAAICEEJAAAICEIJAAAICEMJAAAICEQJAAAICEUJAAAICEYJAAAICEcJAAAICEgJAAAICEkJAAAICEoJAAAICEsJAAAICEwJAAAICE0JAAAICE4JAAAICE8JAAAICFAJAAAICFEJAAAICFIJAAAICFMJAAAICFQJAAAICFUJAAAICFYJAAAICFcJAAAICFgJAAAICFkJAAAICFoJAAAICFsJAAAICFwJAAAICF0JAAAICF4JAAAICF8JAAAICGAJAAAICGEJAAAICGIJAAAICGMJAAAICGQJAAAICGUJAAAICGYJAAAICGcJAAAICGgJAAAICGkJAAAICGoJAAAICGsJAAAICGwJAAAICG0JAAAICG4JAAAICG8JAAAICHAJAAAICHEJAAAICHIJAAAICHMJAAAICHQJAAAICHUJAAAICHYJAAAICHcJAAAICHgJAAAICHkJAAAICHoJAAAICHsJAAAICHwJAAAICH0JAAAICH4JAAAICH8JAAAICIAJAAAICIEJAAAICIIJAAAICIMJAAAICIQJAAAICIUJAAAICIYJAAAICIcJAAAICIgJAAAICIkJAAAICIoJAAAICIsJAAAICIwJAAAICI0JAAAICI4JAAAICI8JAAAICJAJAAAICJEJAAAICJIJAAAICJMJAAAICJQJAAAICJUJAAAICJYJAAAICJcJAAAICJgJAAAICJkJAAAICJoJAAAICJsJAAAICJwJAAAICJ0JAAAICJ4JAAAICJ8JAAAICKAJAAAICKEJAAAICKIJAAAICKMJAAAICKQJAAAICKUJAAAICKYJAAAICKcJAAAICKgJAAAICKkJAAAICKoJAAAICKsJAAAICKwJAAAICK0JAAAICK4JAAAICK8JAAAICLAJAAAICLEJAAAICLIJAAAICLMJAAAICLQJAAAICLUJAAAICLYJAAAICLcJAAAICLgJAAAICLkJAAAICLoJAAAICLsJAAAICLwJAAAICL0JAAAICL4JAAAICL8JAAAICMAJAAAICMEJAAAICMIJAAAICMMJAAAICMQJAAAICMUJAAAICMYJAAAICMcJAAAICMgJAAAICMkJAAAICMoJAAAICMsJAAAICMwJAAAICM0JAAAICM4JAAAICM8JAAAICNAJAAAICNEJAAAICNIJAAAICNMJAAAICNQJAAAICNUJAAAICNYJAAAICNcJAAAICNgJAAAICNkJAAAICNoJAAAICNsJAAAICNwJAAAICN0JAAAICN4JAAAICN8JAAAICOAJAAAICOEJAAAICOIJAAAICOMJAAAICOQJAAAICOUJAAAICOYJAAAICOcJAAAICOgJAAAICOkJAAAICOoJAAAICOsJAAAICOwJAAAICO0JAAAICO4JAAAICO8JAAAICPAJAAAICPEJAAAICPIJAAAICPMJAAAICPQJAAAICPUJAAAICPYJAAAICPcJAAAICPgJAAAICPkJAAAICPoJAAAICPsJAAAICPwJAAAICP0JAAAICP4JAAAICP8JAAAICAAKAAAICAEKAAAICAIKAAAICAMKAAAICAQKAAAICAUKAAAICAYKAAAICAcKAAAICAgKAAAICAkKAAAICAoKAAAICAsKAAAICAwKAAAICA0KAAAICA4KAAAICA8KAAAICBAKAAAICBEKAAAICBIKAAAICBMKAAAICBQKAAAICBUKAAAICBYKAAAICBcKAAAICBgKAAAICBkKAAAICBoKAAAICBsKAAAICBwKAAAICB0KAAAICB4KAAAICB8KAAAICCAKAAAICCEKAAAICCIKAAAICCMKAAAICCQKAAAICCUKAAAICCYKAAAICCcKAAAICCgKAAAICCkKAAAICCoKAAAICCsKAAAICCwKAAAICC0KAAAICC4KAAAICC8KAAAICDAKAAAICDEKAAAICDIKAAAICDMKAAAICDQKAAAICDUKAAAICDYKAAAICDcKAAAICDgKAAAICDkKAAAICDoKAAAICDsKAAAICDwKAAAICD0KAAAICD4KAAAICD8KAAAICEAKAAAICEEKAAAICEIKAAAICEMKAAAICEQKAAAICEUKAAAICEYKAAAICEcKAAAICEgKAAAICEkKAAAICEoKAAAICEsKAAAICEwKAAAICE0KAAAICE4KAAAICE8KAAAICFAKAAAICFEKAAAICFIKAAAICFMKAAAICFQKAAAICFUKAAAICFYKAAAICFcKAAAICFgKAAAICFkKAAAICFoKAAAICFsKAAAICFwKAAAICF0KAAAICF4KAAAICF8KAAAICGAKAAAICGEKAAAICGIKAAAICGMKAAAICGQKAAAICGUKAAAICGYKAAAICGcKAAAICGgKAAAICGkKAAAICGoKAAAICGsKAAAICGwKAAAICG0KAAAICG4KAAAICG8KAAAICHAKAAAICHEKAAAICHIKAAAICHMKAAAICHQKAAAICHUKAAAICHYKAAAICHcKAAAICHgKAAAICHkKAAAICHoKAAAICHsKAAAICHwKAAAICH0KAAAICH4KAAAICH8KAAAICIAKAAAICIEKAAAICIIKAAAICIMKAAAICIQKAAAICIUKAAAICIYKAAAICIcKAAAICIgKAAAICIkKAAAICIoKAAAICIsKAAAICIwKAAAICI0KAAAICI4KAAAICI8KAAAICJAKAAAICJEKAAAICJIKAAAICJMKAAAICJQKAAAICJUKAAAICJYKAAAICJcKAAAICJgKAAAICJkKAAAICJoKAAAICJsKAAAICJwKAAAICJ0KAAAICJ4KAAAICJ8KAAAICKAKAAAICKEKAAAICKIKAAAICKMKAAAICKQKAAAICKUKAAAICKYKAAAICKcKAAAICKgKAAAICKkKAAAICKoKAAAICKsKAAAICKwKAAAICK0KAAAICK4KAAAICK8KAAAICLAKAAAICLEKAAAICLIKAAAICLMKAAAICLQKAAAICLUKAAAICLYKAAAICLcKAAAICLgKAAAICLkKAAAICLoKAAAICLsKAAAICLwKAAAICL0KAAAICL4KAAAICL8KAAAICMAKAAAICMEKAAAICMIKAAAICMMKAAAICMQKAAAICMUKAAAICMYKAAAICMcKAAAICMgKAAAICMkKAAAICMoKAAAICMsKAAAICMwKAAAICM0KAAAICM4KAAAICM8KAAAICNAKAAAICNEKAAAICNIKAAAICNMKAAAICNQKAAAICNUKAAAICNYKAAAICNcKAAAICNgKAAAICNkKAAAICNoKAAAICNsKAAAICNwKAAAICN0KAAAICN4KAAAICN8KAAAICOAKAAAICOEKAAAICOIKAAAICOMKAAAICOQKAAAICOUKAAAICOYKAAAICOcKAAAICOgKAAAICOkKAAAICOoKAAAICOsKAAAICOwKAAAICO0KAAAICO4KAAAICO8KAAAICPAKAAAICPEKAAAICPIKAAAICPMKAAAICPQKAAAICPUKAAAICPYKAAAICPcKAAAICPgKAAAICPkKAAAICPoKAAAICPsKAAAICPwKAAAICP0KAAAICP4KAAAICP8KAAAICAALAAAICAELAAAICAILAAAICAMLAAAICAQLAAAICAULAAAICAYLAAAICAcLAAAICAgLAAAICAkLAAAICAoLAAAICAsLAAAICAwLAAAICA0LAAAICA4LAAAICA8LAAAICBALAAAICBELAAAICBILAAAICBMLAAAICBQLAAAICBULAAAICBYLAAAICBcLAAAICBgLAAAICBkLAAAICBoLAAAICBsLAAAICBwLAAAICB0LAAAICB4LAAAICB8LAAAICCALAAAICCELAAAICCILAAAICCMLAAAICCQLAAAICCULAAAICCYLAAAICCcLAAAICCgLAAAICCkLAAAICCoLAAAICCsLAAAICCwLAAAICC0LAAAICC4LAAAICC8LAAAICDALAAAICDELAAAICDILAAAICDMLAAAICDQLAAAICDULAAAICDYLAAAICDcLAAAICDgLAAAICDkLAAAICDoLAAAICDsLAAAICDwLAAAICD0LAAAICD4LAAAICD8LAAAICEALAAAICEELAAAICEILAAAICEMLAAAICEQLAAAICEULAAAICEYLAAAICEcLAAAICEgLAAAICEkLAAAICEoLAAAICEsLAAAICEwLAAAICE0LAAAICE4LAAAICE8LAAAICFALAAAICFELAAAICFILAAAICFMLAAAICFQLAAAICFULAAAICFYLAAAICFcLAAAICFgLAAAICFkLAAAICFoLAAAICFsLAAAICFwLAAAICF0LAAAICF4LAAAICF8LAAAICGALAAAICGELAAAICGILAAAICGMLAAAICGQLAAAICGULAAAICGYLAAAICGcLAAAICGgLAAAICGkLAAAICGoLAAAICGsLAAAICGwLAAAICG0LAAAICG4LAAAICG8LAAAICHALAAAICHELAAAICHILAAAICHMLAAAICHQLAAAICHULAAAICHYLAAAICHcLAAAICHgLAAAICHkLAAAICHoLAAAICHsLAAAICHwLAAAICH0LAAAICH4LAAAICH8LAAAICIALAAAICIELAAAICIILAAAICIMLAAAICIQLAAAICIULAAAICIYLAAAICIcLAAAICIgLAAAICIkLAAAICIoLAAAICIsLAAAICIwLAAAICI0LAAAICI4LAAAICI8LAAAICJALAAAICJELAAAICJILAAAICJMLAAAICJQLAAAICJULAAAICJYLAAAICJcLAAAICJgLAAAICJkLAAAICJoLAAAICJsLAAAICJwLAAAICJ0LAAAICJ4LAAAICJ8LAAAICKALAAAICKELAAAICKILAAAICKMLAAAICKQLAAAICKULAAAICKYLAAAICKcLAAAICKgLAAAICKkLAAAICKoLAAAICKsLAAAICKwLAAAICK0LAAAICK4LAAAICK8LAAAICLALAAAICLELAAAICLILAAAICLMLAAAICLQLAAAICLULAAAICLYLAAAICLcLAAAICLgLAAAICLkLAAAICLoLAAAICLsLAAAICLwLAAAICL0LAAAICL4LAAAICL8LAAAICMALAAAICMELAAAICMILAAAICMMLAAAICMQLAAAICMULAAAICMYLAAAICMcLAAAICMgLAAAICMkLAAAICMoLAAAICMsLAAAICMwLAAAICM0LAAAICM4LAAAICM8LAAAICNALAAAICNELAAAICNILAAAICNMLAAAICNQLAAAICNULAAAICNYLAAAICNcLAAAICNgLAAAICNkLAAAICNoLAAAICNsLAAAICNwLAAAICN0LAAAICN4LAAAICN8LAAAICOALAAAICOELAAAICOILAAAICOMLAAAICOQLAAAICOULAAAICOYLAAAICOcLAAAICOgLAAAICOkLAAAICOoLAAAICOsLAAAICOwLAAAICO0LAAAICO4LAAAICO8LAAAICPALAAAICPELAAAICPILAAAICPMLAAAICPQLAAAICPULAAAICPYLAAAICPcLAAAICPgLAAAICPkLAAAICPoLAAAICPsLAAAICPwLAAAICP0LAAAICP4LAAAICP8LAAAICAAMAAAICAEMAAAICAIMAAAICAMMAAAICAQMAAAICAUMAAAICAYMAAAICAcMAAAICAgMAAAICAkMAAAICAoMAAAICAsMAAAICAwMAAAICA0MAAAICA4MAAAICA8MAAAICBAMAAAICBEMAAAICBIMAAAICBMMAAAICBQMAAAICBUMAAAICBYMAAAICBcMAAAICBgMAAAICBkMAAAICBoMAAAICBsMAAAICBwMAAAICB0MAAAICB4MAAAICB8MAAAICCAMAAAICCEMAAAICCIMAAAICCMMAAAICCQMAAAICCUMAAAICCYMAAAICCcMAAAICCgMAAAICCkMAAAICCoMAAAICCsMAAAICCwMAAAICC0MAAAICC4MAAAICC8MAAAICDAMAAAICDEMAAAICDIMAAAICDMMAAAICDQMAAAICDUMAAAICDYMAAAICDcMAAAICDgMAAAICDkMAAAICDoMAAAICDsMAAAICDwMAAAICD0MAAAICD4MAAAICD8MAAAICEAMAAAICEEMAAAICEIMAAAICEMMAAAICEQMAAAICEUMAAAICEYMAAAICEcMAAAICEgMAAAICEkMAAAICEoMAAAICEsMAAAICEwMAAAICE0MAAAICE4MAAAICE8MAAAICFAMAAAICFEMAAAICFIMAAAICFMMAAAICFQMAAAICFUMAAAICFYMAAAICFcMAAAICFgMAAAICFkMAAAICFoMAAAICFsMAAAICFwMAAAICF0MAAAICF4MAAAICF8MAAAICGAMAAAICGEMAAAICGIMAAAICGMMAAAICGQMAAAICGUMAAAICGYMAAAICGcMAAAICGgMAAAICGkMAAAICGoMAAAICGsMAAAICGwMAAAICG0MAAAICG4MAAAICG8MAAAICHAMAAAICHEMAAAICHIMAAAICHMMAAAICHQMAAAICHUMAAAICHYMAAAICHcMAAAICHgMAAAICHkMAAAICHoMAAAICHsMAAAICHwMAAAICH0MAAAICH4MAAAICH8MAAAICIAMAAAICIEMAAAICIIMAAAICIMMAAAICIQMAAAICIUMAAAICIYMAAAICIcMAAAICIgMAAAICIkMAAAICIoMAAAICIsMAAAICIwMAAAICI0MAAAICI4MAAAICI8MAAAICJAMAAAICJEMAAAICJIMAAAICJMMAAAICJQMAAAICJUMAAAICJYMAAAICJcMAAAICJgMAAAICJkMAAAICJoMAAAICJsMAAAICJwMAAAICJ0MAAAICJ4MAAAICJ8MAAAICKAMAAAICKEMAAAICKIMAAAICKMMAAAICKQMAAAICKUMAAAICKYMAAAICKcMAAAICKgMAAAICKkMAAAICKoMAAAICKsMAAAICKwMAAAICK0MAAAICK4MAAAICK8MAAAICLAMAAAICLEMAAAICLIMAAAICLMMAAAICLQMAAAICLUMAAAICLYMAAAICLcMAAAICLgMAAAICLkMAAAICLoMAAAICLsMAAAICLwMAAAICL0MAAAICL4MAAAICL8MAAAICMAMAAAICMEMAAAICMIMAAAICMMMAAAICMQMAAAICMUMAAAICMYMAAAICMcMAAAICMgMAAAICMkMAAAICMoMAAAICMsMAAAICMwMAAAICM0MAAAICM4MAAAICM8MAAAICNAMAAAICNEMAAAICNIMAAAICNMMAAAICNQMAAAICNUMAAAICNYMAAAICNcMAAAICNgMAAAICNkMAAAICNoMAAAICNsMAAAICNwMAAAICN0MAAAICN4MAAAICN8MAAAICOAMAAAICOEMAAAICOIMAAAICOMMAAAICOQMAAAICOUMAAAICOYMAAAICOcMAAAICOgMAAAICOkMAAAICOoMAAAICOsMAAAICOwMAAAICO0MAAAICO4MAAAICO8MAAAICPAMAAAICPEMAAAICPIMAAAICPMMAAAICPQMAAAICPUMAAAICPYMAAAICPcMAAAICPgMAAAICPkMAAAICPoMAAAICPsMAAAICPwMAAAICP0MAAAICP4MAAAICP8MAAAICAANAAAICAENAAAICAINAAAICAMNAAAICAQNAAAICAUNAAAICAYNAAAICAcNAAAICAgNAAAICAkNAAAICAoNAAAICAsNAAAICAwNAAAICA0NAAAICA4NAAAICA8NAAAICBANAAAICBENAAAICBINAAAICBMNAAAICBQNAAAICBUNAAAICBYNAAAICBcNAAAICBgNAAAICBkNAAAICBoNAAAICBsNAAAICBwNAAAICB0NAAAICB4NAAAICB8NAAAICCANAAAICCENAAAICCINAAAICCMNAAAICCQNAAAICCUNAAAICCYNAAAICCcNAAAICCgNAAAICCkNAAAICCoNAAAICCsNAAAICCwNAAAICC0NAAAICC4NAAAICC8NAAAICDANAAAICDENAAAICDINAAAICDMNAAAICDQNAAAICDUNAAAICDYNAAAICDcNAAAICDgNAAAICDkNAAAICDoNAAAICDsNAAAICDwNAAAICD0NAAAICD4NAAAICD8NAAAICEANAAAICEENAAAICEINAAAICEMNAAAICEQNAAAICEUNAAAICEYNAAAICEcNAAAICEgNAAAICEkNAAAICEoNAAAICEsNAAAICEwNAAAICE0NAAAICE4NAAAICE8NAAAICFANAAAICFENAAAICFINAAAICFMNAAAICFQNAAAICFUNAAAICFYNAAAICFcNAAAICFgNAAAICFkNAAAICFoNAAAICFsNAAAICFwNAAAICF0NAAAICF4NAAAICF8NAAAICGANAAAICGENAAAICGINAAAICGMNAAAICGQNAAAICGUNAAAICGYNAAAICGcNAAAICGgNAAAICGkNAAAICGoNAAAICGsNAAAICGwNAAAICG0NAAAICG4NAAAICG8NAAAICHANAAAICHENAAAICHINAAAICHMNAAAICHQNAAAICHUNAAAICHYNAAAICHcNAAAICHgNAAAICHkNAAAICHoNAAAICHsNAAAICHwNAAAICH0NAAAICH4NAAAICH8NAAAICIANAAAICIENAAAICIINAAAICIMNAAAICIQNAAAICIUNAAAICIYNAAAICIcNAAAICIgNAAAICIkNAAAICIoNAAAICIsNAAAICIwNAAAICI0NAAAICI4NAAAICI8NAAAICJANAAAICJENAAAICJINAAAICJMNAAAICJQNAAAICJUNAAAICJYNAAAICJcNAAAICJgNAAAICJkNAAAICJoNAAAICJsNAAAICJwNAAAICJ0NAAAICJ4NAAAICJ8NAAAICKANAAAICKENAAAICKINAAAICKMNAAAICKQNAAAICKUNAAAICKYNAAAICKcNAAAICKgNAAAICKkNAAAICKoNAAAICKsNAAAICKwNAAAICK0NAAAICK4NAAAICK8NAAAICLANAAAICLENAAAICLINAAAICLMNAAAICLQNAAAICLUNAAAICLYNAAAICLcNAAAICLgNAAAICLkNAAAICLoNAAAICLsNAAAICLwNAAAICL0NAAAICL4NAAAICL8NAAAICMANAAAICMENAAAICMINAAAICMMNAAAICMQNAAAICMUNAAAICMYNAAAICMcNAAAICMgNAAAICMkNAAAICMoNAAAICMsNAAAICMwNAAAICM0NAAAICM4NAAAICM8NAAAICNANAAAICNENAAAICNINAAAICNMNAAAICNQNAAAICNUNAAAICNYNAAAICNcNAAAICNgNAAAICNkNAAAICNoNAAAICNsNAAAICNwNAAAICN0NAAAICN4NAAAICN8NAAAICOANAAAICOENAAAICOINAAAICOMNAAAICOQNAAAICOUNAAAICOYNAAAICOcNAAAICOgNAAAICOkNAAAICOoNAAAICOsNAAAICOwNAAAICO0NAAAICO4NAAAICO8NAAAICPANAAAICPENAAAICPINAAAICPMNAAAICPQNAAAICPUNAAAICPYNAAAICPcNAAAICPgNAAAICPkNAAAICPoNAAAICPsNAAAICPwNAAAICP0NAAAICP4NAAAICP8NAAAICAAOAAAICAEOAAAICAIOAAAICAMOAAAICAQOAAAICAUOAAAICAYOAAAICAcOAAAICAgOAAAICAkOAAAICAoOAAAICAsOAAAICAwOAAAICA0OAAAICA4OAAAICA8OAAAICBAOAAAICBEOAAAICBIOAAAICBMOAAAICBQOAAAICBUOAAAICBYOAAAICBcOAAAICBgOAAAICBkOAAAICBoOAAAICBsOAAAICBwOAAAICB0OAAAICB4OAAAICB8OAAAICCAOAAAICCEOAAAICCIOAAAICCMOAAAICCQOAAAICCUOAAAICCYOAAAICCcOAAAICCgOAAAICCkOAAAICCoOAAAICCsOAAAICCwOAAAICC0OAAAICC4OAAAICC8OAAAICDAOAAAICDEOAAAICDIOAAAICDMOAAAICDQOAAAICDUOAAAICDYOAAAICDcOAAAICDgOAAAICDkOAAAICDoOAAAICDsOAAAICDwOAAAICD0OAAAICD4OAAAICD8OAAAICEAOAAAICEEOAAAICEIOAAAICEMOAAAICEQOAAAICEUOAAAICEYOAAAICEcOAAAICEgOAAAICEkOAAAICEoOAAAICEsOAAAICEwOAAAICE0OAAAICE4OAAAICE8OAAAICFAOAAAICFEOAAAICFIOAAAICFMOAAAICFQOAAAICFUOAAAICFYOAAAICFcOAAAICFgOAAAICFkOAAAICFoOAAAICFsOAAAICFwOAAAICF0OAAAICF4OAAAICF8OAAAICGAOAAAICGEOAAAICGIOAAAICGMOAAAICGQOAAAICGUOAAAICGYOAAAICGcOAAAICGgOAAAICGkOAAAICGoOAAAICGsOAAAICGwOAAAICG0OAAAICG4OAAAICG8OAAAICHAOAAAICHEOAAAICHIOAAAICHMOAAAICHQOAAAICHUOAAAICHYOAAAICHcOAAAICHgOAAAICHkOAAAICHoOAAAICHsOAAAICHwOAAAICH0OAAAICH4OAAAICH8OAAAICIAOAAAICIEOAAAICIIOAAAICIMOAAAICIQOAAAICIUOAAAICIYOAAAICIcOAAAICIgOAAAICIkOAAAICIoOAAAICIsOAAAICIwOAAAICI0OAAAICI4OAAAICI8OAAAICJAOAAAICJEOAAAICJIOAAAICJMOAAAICJQOAAAICJUOAAAICJYOAAAICJcOAAAICJgOAAAICJkOAAAICJoOAAAICJsOAAAICJwOAAAICJ0OAAAICJ4OAAAICJ8OAAAICKAOAAAICKEOAAAICKIOAAAICKMOAAAICKQOAAAICKUOAAAICKYOAAAICKcOAAAICKgOAAAICKkOAAAICKoOAAAICKsOAAAICKwOAAAICK0OAAAICK4OAAAICK8OAAAICLAOAAAICLEOAAAICLIOAAAICLMOAAAICLQOAAAICLUOAAAICLYOAAAICLcOAAAICLgOAAAICLkOAAAICLoOAAAICLsOAAAICLwOAAAICL0OAAAICL4OAAAICL8OAAAICMAOAAAICMEOAAAICMIOAAAICMMOAAAICMQOAAAICMUOAAAICMYOAAAICMcOAAAICMgOAAAICMkOAAAICMoOAAAICMsOAAAICMwOAAAICM0OAAAICM4OAAAICM8OAAAICNAOAAAICNEOAAAICNIOAAAICNMOAAAICNQOAAAICNUOAAAICNYOAAAICNcOAAAICNgOAAAICNkOAAAICNoOAAAICNsOAAAICNwOAAAICN0OAAAICN4OAAAICN8OAAAICOAOAAAICOEOAAAICOIOAAAICOMOAAAICOQOAAAICOUOAAAICOYOAAAICOcOAAAICOgOAAAICOkOAAAICOoOAAAICOsOAAAICOwOAAAICO0OAAAICO4OAAAICO8OAAAICPAOAAAICPEOAAAICPIOAAAICPMOAAAICPQOAAAICPUOAAAICPYOAAAICPcOAAAICPgOAAAICPkOAAAICPoOAAAICPsOAAAICPwOAAAICP0OAAAICP4OAAAICP8OAAAICAAPAAAICAEPAAAICAIPAAAICAMPAAAICAQPAAAICAUPAAAICAYPAAAICAcPAAAICAgPAAAICAkPAAAICAoPAAAICAsPAAAICAwPAAAICA0PAAAICA4PAAAICA8PAAAICBAPAAAICBEPAAAICBIPAAAICBMPAAAICBQPAAAICBUPAAAICBYPAAAICBcPAAAICBgPAAAICBkPAAAICBoPAAAICBsPAAAICBwPAAAICB0PAAAICB4PAAAICB8PAAAICCAPAAAICCEPAAAICCIPAAAICCMPAAAICCQPAAAICCUPAAAICCYPAAAICCcPAAAICCgPAAAICCkPAAAICCoPAAAICCsPAAAICCwPAAAICC0PAAAICC4PAAAICC8PAAAICDAPAAAICDEPAAAICDIPAAAICDMPAAAICDQPAAAICDUPAAAICDYPAAAICDcPAAAICDgPAAAICDkPAAAICDoPAAAICDsPAAAICDwPAAAICD0PAAAICD4PAAAICD8PAAAICEAPAAAICEEPAAAICEIPAAAICEMPAAAICEQPAAAICEUPAAAICEYPAAAICEcPAAAICEgPAAAICEkPAAAICEoPAAAICEsPAAAICEwPAAAICE0PAAAICE4PAAAICE8PAAAICFAPAAAICFEPAAAICFIPAAAICFMPAAAICFQPAAAICFUPAAAICFYPAAAICFcPAAAICFgPAAAICFkPAAAICFoPAAAICFsPAAAICFwPAAAICF0PAAAICF4PAAAICF8PAAAICGAPAAAICGEPAAAICGIPAAAICGMPAAAICGQPAAAICGUPAAAICGYPAAAICGcPAAAICGgPAAAICGkPAAAICGoPAAAICGsPAAAICGwPAAAICG0PAAAICG4PAAAICG8PAAAICHAPAAAICHEPAAAICHIPAAAICHMPAAAICHQPAAAICHUPAAAICHYPAAAICHcPAAAICHgPAAAICHkPAAAICHoPAAAICHsPAAAICHwPAAAICH0PAAAICH4PAAAICH8PAAAICIAPAAAICIEPAAAICIIPAAAICIMPAAAICIQPAAAICIUPAAAICIYPAAAICIcPAAAICIgPAAAICIkPAAAICIoPAAAICIsPAAAICIwPAAAICI0PAAAICI4PAAAICI8PAAAICJAPAAAICJEPAAAICJIPAAAICJMPAAAICJQPAAAICJUPAAAICJYPAAAICJcPAAAICJgPAAAICJkPAAAICJoPAAAICJsPAAAICJwPAAAICJ0PAAAICJ4PAAAICJ8PAAAICKAPAAAICKEPAAAICKIPAAAICKMPAAAICKQPAAAICKUPAAAICKYPAAAICKcPAAAICKgPAAAICKkPAAAICKoPAAAICKsPAAAICKwPAAAICK0PAAAICK4PAAAICK8PAAAICLAPAAAICLEPAAAICLIPAAAICLMPAAAICLQPAAAICLUPAAAICLYPAAAICLcPAAAICLgPAAAICLkPAAAICLoPAAAICLsPAAAICLwPAAAICL0PAAAICL4PAAAICL8PAAAICMAPAAAICMEPAAAICMIPAAAICMMPAAAICMQPAAAICMUPAAAICMYPAAAICMcPAAAICMgPAAAICMkPAAAICMoPAAAICMsPAAAICMwPAAAICM0PAAAICM4PAAAICM8PAAAICNAPAAAICNEPAAAICNIPAAAICNMPAAAICNQPAAAICNUPAAAICNYPAAAICNcPAAAICNgPAAAICNkPAAAICNoPAAAICNsPAAAICNwPAAAICN0PAAAICN4PAAAICN8PAAAICOAPAAAICOEPAAAICOIPAAAICOMPAAAICOQPAAAICOUPAAAICOYPAAAICOcPAAAICOgPAAAICOkPAAAICOoPAAAICOsPAAAICOwPAAAICO0PAAAICO4PAAAICO8PAAAICPAPAAAICPEPAAAICPIPAAAICPMPAAAICPQPAAAICPUPAAAICPYPAAAICPcPAAAICPgPAAAICPkPAAAICPoPAAAICPsPAAAICPwPAAAICP0PAAAICP4PAAAICP8PAAAICAAQAAAICAEQAAAICAIQAAAICAMQAAAICAQQAAAICAUQAAAICAYQAAAICAcQAAAICAgQAAAICAkQAAAICAoQAAAICAsQAAAICAwQAAAICA0QAAAICA4QAAAICA8QAAAICBAQAAAICBEQAAAICBIQAAAICBMQAAAICBQQAAAICBUQAAAICBYQAAAICBcQAAAICBgQAAAICBkQAAAICBoQAAAICBsQAAAICBwQAAAICB0QAAAICB4QAAAICB8QAAAICCAQAAAICCEQAAAICCIQAAAICCMQAAAICCQQAAAICCUQAAAICCYQAAAICCcQAAAICCgQAAAICCkQAAAICCoQAAAICCsQAAAICCwQAAAICC0QAAAICC4QAAAICC8QAAAICDAQAAAICDEQAAAICDIQAAAICDMQAAAICDQQAAAICDUQAAAICDYQAAAICDcQAAAICDgQAAAICDkQAAAICDoQAAAICDsQAAAICDwQAAAICD0QAAAICD4QAAAICD8QAAAICEAQAAAICEEQAAAICEIQAAAICEMQAAAICEQQAAAICEUQAAAICEYQAAAICEcQAAAICEgQAAAICEkQAAAICEoQAAAICEsQAAAICEwQAAAICE0QAAAICE4QAAAICE8QAAAICFAQAAAICFEQAAAICFIQAAAICFMQAAAICFQQAAAICFUQAAAICFYQAAAICFcQAAAICFgQAAAICFkQAAAICFoQAAAICFsQAAAICFwQAAAICF0QAAAICF4QAAAICF8QAAAICGAQAAAICGEQAAAICGIQAAAICGMQAAAICGQQAAAICGUQAAAICGYQAAAICGcQAAAICGgQAAAICGkQAAAICGoQAAAICGsQAAAICGwQAAAICG0QAAAICG4QAAAICG8QAAAICHAQAAAICHEQAAAICHIQAAAICHMQAAAICHQQAAAICHUQAAAICHYQAAAICHcQAAAICHgQAAAICHkQAAAICHoQAAAICHsQAAAICHwQAAAICH0QAAAICH4QAAAICH8QAAAICIAQAAAICIEQAAAICIIQAAAICIMQAAAICIQQAAAICIUQAAAICIYQAAAICIcQAAAICIgQAAAICIkQAAAICIoQAAAICIsQAAAICIwQAAAICI0QAAAICI4QAAAICI8QAAAICJAQAAAICJEQAAAICJIQAAAICJMQAAAICJQQAAAICJUQAAAICJYQAAAICJcQAAAICJgQAAAICJkQAAAICJoQAAAICJsQAAAICJwQAAAICJ0QAAAICJ4QAAAICJ8QAAAICKAQAAAICKEQAAAICKIQAAAICKMQAAAICKQQAAAICKUQAAAICKYQAAAICKcQAAAICKgQAAAICKkQAAAICKoQAAAICKsQAAAICKwQAAAICK0QAAAICK4QAAAICK8QAAAICLAQAAAICLEQAAAICLIQAAAICLMQAAAICLQQAAAICLUQAAAICLYQAAAICLcQAAAICLgQAAAICLkQAAAICLoQAAAICLsQAAAICLwQAAAICL0QAAAICL4QAAAICL8QAAAICMAQAAAICMEQAAAICMIQAAAICMMQAAAICMQQAAAICMUQAAAICMYQAAAICMcQAAAICMgQAAAICMkQAAAICMoQAAAICMsQAAAICMwQAAAICM0QAAAICM4QAAAICM8QAAAICNAQAAAICNEQAAAICNIQAAAICNMQAAAICNQQAAAICNUQAAAICNYQAAAICNcQAAAICNgQAAAICNkQAAAICNoQAAAICNsQAAAICNwQAAAICN0QAAAICN4QAAAICN8QAAAICOAQAAAICOEQAAAICOIQAAAICOMQAAAICOQQAAAICOUQAAAICOYQAAAICOcQAAAICOgQAAAICOkQAAAICOoQAAAICOsQAAAICOwQAAAICO0QAAAICO4QAAAICO8QAAAICPAQAAAICPEQAAAICPIQAAAICPMQAAAICPQQAAAICPUQAAAICPYQAAAICPcQAAAICPgQAAAICPkQAAAICPoQAAAICPsQAAAICPwQAAAICP0QAAAICP4QAAAICP8QAAAICAARAAAICAERAAAICAIRAAAICAMRAAAICAQRAAAICAURAAAICAYRAAAICAcRAAAICAgRAAAICAkRAAAICAoRAAAICAsRAAAICAwRAAAICA0RAAAICA4RAAAICA8RAAAICBARAAAICBERAAAICBIRAAAICBMRAAAICBQRAAAICBURAAAICBYRAAAICBcRAAAICBgRAAAICBkRAAAICBoRAAAICBsRAAAICBwRAAAICB0RAAAICB4RAAAICB8RAAAICCARAAAICCERAAAICCIRAAAICCMRAAAICCQRAAAICCURAAAICCYRAAAICCcRAAAICCgRAAAICCkRAAAICCoRAAAICCsRAAAICCwRAAAICC0RAAAICC4RAAAICC8RAAAICDARAAAICDERAAAICDIRAAAICDMRAAAICDQRAAAICDURAAAICDYRAAAICDcRAAAICDgRAAAICDkRAAAICDoRAAAICDsRAAAICDwRAAAICD0RAAAICD4RAAAICD8RAAAICEARAAAICEERAAAICEIRAAAICEMRAAAICEQRAAAICEURAAAICEYRAAAICEcRAAAICEgRAAAICEkRAAAICEoRAAAICEsRAAAICEwRAAAICE0RAAAICE4RAAAICE8RAAAICFARAAAICFERAAAICFIRAAAICFMRAAAICFQRAAAICFURAAAICFYRAAAICFcRAAAICFgRAAAICFkRAAAICFoRAAAICFsRAAAICFwRAAAICF0RAAAICF4RAAAICF8RAAAICGARAAAICGERAAAICGIRAAAICGMRAAAICGQRAAAICGURAAAICGYRAAAICGcRAAAICGgRAAAICGkRAAAICGoRAAAICGsRAAAICGwRAAAICG0RAAAICG4RAAAICG8RAAAICHARAAAICHERAAAICHIRAAAICHMRAAAICHQRAAAICHURAAAICHYRAAAICHcRAAAICHgRAAAICHkRAAAICHoRAAAICHsRAAAICHwRAAAICH0RAAAICH4RAAAICH8RAAAICIARAAAICIERAAAICIIRAAAICIMRAAAICIQRAAAICIURAAAICIYRAAAICIcRAAAICIgRAAAICIkRAAAICIoRAAAICIsRAAAICIwRAAAICI0RAAAICI4RAAAICI8RAAAICJARAAAICJERAAAICJIRAAAICJMRAAAICJQRAAAICJURAAAICJYRAAAICJcRAAAICJgRAAAICJkRAAAICJoRAAAICJsRAAAICJwRAAAICJ0RAAAICJ4RAAAICJ8RAAAICKARAAAICKERAAAICKIRAAAICKMRAAAICKQRAAAICKURAAAICKYRAAAICKcRAAAICKgRAAAICKkRAAAICKoRAAAICKsRAAAICKwRAAAICK0RAAAICK4RAAAICK8RAAAICLARAAAICLERAAAICLIRAAAICLMRAAAICLQRAAAICLURAAAICLYRAAAICLcRAAAICLgRAAAICLkRAAAICLoRAAAICLsRAAAICLwRAAAICL0RAAAICL4RAAAICL8RAAAICMARAAAICMERAAAICMIRAAAICMMRAAAICMQRAAAICMURAAAICMYRAAAICMcRAAAICMgRAAAICMkRAAAICMoRAAAICMsRAAAICMwRAAAICM0RAAAICM4RAAAICM8RAAAICNARAAAICNERAAAICNIRAAAICNMRAAAICNQRAAAICNURAAAICNYRAAAICNcRAAAICNgRAAAICNkRAAAICNoRAAAICNsRAAAICNwRAAAICN0RAAAICN4RAAAICN8RAAAICOARAAAICOERAAAICOIRAAAICOMRAAAICOQRAAAICOURAAAICOYRAAAICOcRAAAICOgRAAAICOkRAAAICOoRAAAICOsRAAAICOwRAAAICO0RAAAICO4RAAAICO8RAAAICPARAAAICPERAAAICPIRAAAICPMRAAAICPQRAAAICPURAAAICPYRAAAICPcRAAAICPgRAAAICPkRAAAICPoRAAAICPsRAAAICPwRAAAICP0RAAAICP4RAAAICP8RAAAICAASAAAICAESAAAICAISAAAICAMSAAAICAQSAAAICAUSAAAICAYSAAAICAcSAAAICAgSAAAICAkSAAAICAoSAAAICAsSAAAICAwSAAAICA0SAAAICA4SAAAICA8SAAAICBASAAAICBESAAAICBISAAAICBMSAAAICBQSAAAICBUSAAAICBYSAAAICBcSAAAICBgSAAAICBkSAAAICBoSAAAICBsSAAAICBwSAAAICB0SAAAICB4SAAAICB8SAAAICCASAAAICCESAAAICCISAAAICCMSAAAICCQSAAAICCUSAAAICCYSAAAICCcSAAAICCgSAAAICCkSAAAICCoSAAAICCsSAAAICCwSAAAICC0SAAAICC4SAAAICC8SAAAICDASAAAICDESAAAICDISAAAICDMSAAAICDQSAAAICDUSAAAICDYSAAAICDcSAAAICDgSAAAICDkSAAAICDoSAAAICDsSAAAICDwSAAAICD0SAAAICD4SAAAICD8SAAAICEASAAAICEESAAAICEISAAAICEMSAAAICEQSAAAICEUSAAAICEYSAAAICEcSAAAICEgSAAAICEkSAAAICEoSAAAICEsSAAAICEwSAAAICE0SAAAICE4SAAAICE8SAAAICFASAAAICFESAAAICFISAAAICFMSAAAICFQSAAAICFUSAAAICFYSAAAICFcSAAAICFgSAAAICFkSAAAICFoSAAAICFsSAAAICFwSAAAICF0SAAAICF4SAAAICF8SAAAICGASAAAICGESAAAICGISAAAICGMSAAAICGQSAAAICGUSAAAICGYSAAAICGcSAAAICGgSAAAICGkSAAAICGoSAAAICGsSAAAICGwSAAAICG0SAAAICG4SAAAICG8SAAAICHASAAAICHESAAAICHISAAAICHMSAAAICHQSAAAICHUSAAAICHYSAAAICHcSAAAICHgSAAAICHkSAAAICHoSAAAICHsSAAAICHwSAAAICH0SAAAICH4SAAAICH8SAAAICIASAAAICIESAAAICIISAAAICIMSAAAICIQSAAAICIUSAAAICIYSAAAICIcSAAAICIgSAAAICIkSAAAICIoSAAAICIsSAAAICIwSAAAICI0SAAAICI4SAAAICI8SAAAICJASAAAICJESAAAICJISAAAICJMSAAAICJQSAAAICJUSAAAICJYSAAAICJcSAAAICJgSAAAICJkSAAAICJoSAAAICJsSAAAICJwSAAAICJ0SAAAICJ4SAAAICJ8SAAAICKASAAAICKESAAAICKISAAAICKMSAAAICKQSAAAICKUSAAAICKYSAAAICKcSAAAICKgSAAAICKkSAAAICKoSAAAICKsSAAAICKwSAAAICK0SAAAICK4SAAAICK8SAAAICLASAAAICLESAAAICLISAAAICLMSAAAICLQSAAAICLUSAAAICLYSAAAICLcSAAAICLgSAAAICLkSAAAICLoSAAAICLsSAAAICLwSAAAICL0SAAAICL4SAAAICL8SAAAICMASAAAICMESAAAICMISAAAICMMSAAAICMQSAAAICMUSAAAICMYSAAAICMcSAAAICMgSAAAICMkSAAAICMoSAAAICMsSAAAICMwSAAAICM0SAAAICM4SAAAICM8SAAAICNASAAAICNESAAAICNISAAAICNMSAAAICNQSAAAICNUSAAAICNYSAAAICNcSAAAICNgSAAAICNkSAAAICNoSAAAICNsSAAAICNwSAAAICN0SAAAICN4SAAAICN8SAAAICOASAAAICOESAAAICOISAAAICOMSAAAICOQSAAAICOUSAAAICOYSAAAICOcSAAAICOgSAAAICOkSAAAICOoSAAAICOsSAAAICOwSAAAICO0SAAAICO4SAAAICO8SAAAICPASAAAICPESAAAICPISAAAICPMSAAAICPQSAAAICPUSAAAICPYSAAAICPcSAAAICPgSAAAICPkSAAAICPoSAAAICPsSAAAICPwSAAAICP0SAAAICP4SAAAICP8SAAAICAATAAAICAETAAAICAITAAAICAMTAAAICAQTAAAICAUTAAAICAYTAAAICAcTAAAICAgTAAAICAkTAAAICAoTAAAICAsTAAAICAwTAAAICA0TAAAICA4TAAAICA8TAAAICBATAAAICBETAAAICBITAAAICBMTAAAICBQTAAAICBUTAAAICBYTAAAICBcTAAAICBgTAAAICBkTAAAICBoTAAAICBsTAAAICBwTAAAICB0TAAAICB4TAAAICB8TAAAICCATAAAICCETAAAICCITAAAICCMTAAAICCQTAAAICCUTAAAICCYTAAAICCcTAAAICCgTAAAICCkTAAAICCoTAAAICCsTAAAICCwTAAAICC0TAAAICC4TAAAICC8TAAAICDATAAAICDETAAAICDITAAAICDMTAAAICDQTAAAICDUTAAAICDYTAAAICDcTAAAICDgTAAAICDkTAAAICDoTAAAICDsTAAAICDwTAAAICD0TAAAICD4TAAAICD8TAAAICEATAAAICEETAAAICEITAAAICEMTAAAICEQTAAAICEUTAAAICEYTAAAICEcTAAAICEgTAAAICEkTAAAICEoTAAAICEsTAAAICEwTAAAICE0TAAAICE4TAAAICE8TAAAICFATAAAICFETAAAICFITAAAICFMTAAAICFQTAAAICFUTAAAICFYTAAAICFcTAAAICFgTAAAICFkTAAAICFoTAAAICFsTAAAICFwTAAAICF0TAAAICF4TAAAICF8TAAAICGATAAAICGETAAAICGITAAAICGMTAAAICGQTAAAICGUTAAAICGYTAAAICGcTAAAICGgTAAAICGkTAAAICGoTAAAICGsTAAAICGwTAAAICG0TAAAICG4TAAAICG8TAAAICHATAAAICHETAAAICHITAAAICHMTAAAICHQTAAAICHUTAAAICHYTAAAICHcTAAAICHgTAAAICHkTAAAICHoTAAAICHsTAAAICHwTAAAICH0TAAAICH4TAAAICH8TAAAICIATAAAICIETAAAICIITAAAICIMTAAAICIQTAAAICIUTAAAICIYTAAAICIcTAAAICIgTAAAICIkTAAAICIoTAAAICIsTAAAICIwTAAAICI0TAAAICI4TAAAICI8TAAAICJATAAAICJETAAAICJITAAAICJMTAAAICJQTAAAICJUTAAAICJYTAAAICJcTAAAICJgTAAAICJkTAAAICJoTAAAICJsTAAAICJwTAAAICJ0TAAAICJ4TAAAICJ8TAAAICKATAAAICKETAAAICKITAAAICKMTAAAICKQTAAAICKUTAAAICKYTAAAICKcTAAAICKgTAAAICKkTAAAICKoTAAAICKsTAAAICKwTAAAICK0TAAAICK4TAAAICK8TAAAICLATAAAICLETAAAICLITAAAICLMTAAAICLQTAAAICLUTAAAICLYTAAAICLcTAAAICLgTAAAICLkTAAAICLoTAAAICLsTAAAICLwTAAAICL0TAAAICL4TAAAICL8TAAAICMATAAAICMETAAAICMITAAAICMMTAAAICMQTAAAICMUTAAAICMYTAAAICMcTAAAICMgTAAAICMkTAAAICMoTAAAICMsTAAAICMwTAAAICM0TAAAICM4TAAAICM8TAAAICNATAAAICNETAAAICNITAAAICNMTAAAICNQTAAAICNUTAAAICNYTAAAICNcTAAAICNgTAAAICNkTAAAICNoTAAAICNsTAAAICNwTAAAICN0TAAAICN4TAAAICN8TAAAICOATAAAICOETAAAICOITAAAICOMTAAAICOQTAAAICOUTAAAICOYTAAAICOcTAAAICOgTAAAICOkTAAAICOoTAAAICOsTAAAICOwTAAAICO0TAAAICO4TAAAICO8TAAAICPATAAAICPETAAAICPITAAAICPMTAAAICPQTAAAICPUTAAAICPYTAAAICPcTAAAICPgTAAAICPkTAAAICPoTAAAICPsTAAAICPwTAAAICP0TAAAICP4TAAAICP8TAAAICAAUAAAICAEUAAAICAIUAAAICAMUAAAICAQUAAAICAUUAAAICAYUAAAICAcUAAAICAgUAAAICAkUAAAICAoUAAAICAsUAAAICAwUAAAICA0UAAAICA4UAAAICA8UAAAICBAUAAAICBEUAAAICBIUAAAICBMUAAAICBQUAAAICBUUAAAICBYUAAAICBcUAAAICBgUAAAICBkUAAAICBoUAAAICBsUAAAICBwUAAAICB0UAAAICB4UAAAICB8UAAAICCAUAAAICCEUAAAICCIUAAAICCMUAAAICCQUAAAICCUUAAAICCYUAAAICCcUAAAICCgUAAAICCkUAAAICCoUAAAICCsUAAAICCwUAAAICC0UAAAICC4UAAAICC8UAAAICDAUAAAICDEUAAAICDIUAAAICDMUAAAICDQUAAAICDUUAAAICDYUAAAICDcUAAAICDgUAAAICDkUAAAICDoUAAAICDsUAAAICDwUAAAICD0UAAAICD4UAAAICD8UAAAICEAUAAAICEEUAAAICEIUAAAICEMUAAAICEQUAAAICEUUAAAICEYUAAAICEcUAAAICEgUAAAICEkUAAAICEoUAAAICEsUAAAICEwUAAAICE0UAAAICE4UAAAICE8UAAAICFAUAAAICFEUAAAICFIUAAAICFMUAAAICFQUAAAICFUUAAAICFYUAAAICFcUAAAICFgUAAAICFkUAAAICFoUAAAICFsUAAAICFwUAAAICF0UAAAICF4UAAAICF8UAAAICGAUAAAICGEUAAAICGIUAAAICGMUAAAICGQUAAAICGUUAAAICGYUAAAICGcUAAAICGgUAAAICGkUAAAICGoUAAAICGsUAAAICGwUAAAICG0UAAAICG4UAAAICG8UAAAICHAUAAAICHEUAAAICHIUAAAICHMUAAAICHQUAAAICHUUAAAICHYUAAAICHcUAAAICHgUAAAICHkUAAAICHoUAAAICHsUAAAICHwUAAAICH0UAAAICH4UAAAICH8UAAAICIAUAAAICIEUAAAICIIUAAAICIMUAAAICIQUAAAICIUUAAAICIYUAAAICIcUAAAICIgUAAAICIkUAAAICIoUAAAICIsUAAAICIwUAAAICI0UAAAICI4UAAAICI8UAAAICJAUAAAICJEUAAAICJIUAAAICJMUAAAICJQUAAAICJUUAAAICJYUAAAICJcUAAAICJgUAAAICJkUAAAICJoUAAAICJsUAAAICJwUAAAICJ0UAAAICJ4UAAAICJ8UAAAICKAUAAAICKEUAAAICKIUAAAICKMUAAAICKQUAAAICKUUAAAICKYUAAAICKcUAAAICKgUAAAICKkUAAAICKoUAAAICKsUAAAICKwUAAAICK0UAAAICK4UAAAICK8UAAAICLAUAAAICLEUAAAICLIUAAAICLMUAAAICLQUAAAICLUUAAAICLYUAAAICLcUAAAICLgUAAAICLkUAAAICLoUAAAICLsUAAAICLwUAAAICL0UAAAICL4UAAAICL8UAAAICMAUAAAICMEUAAAICMIUAAAICMMUAAAICMQUAAAICMUUAAAICMYUAAAICMcUAAAICMgUAAAICMkUAAAICMoUAAAICMsUAAAICMwUAAAICM0UAAAICM4UAAAICM8UAAAICNAUAAAICNEUAAAICNIUAAAICNMUAAAICNQUAAAICNUUAAAICNYUAAAICNcUAAAICNgUAAAICNkUAAAICNoUAAAICNsUAAAICNwUAAAICN0UAAAICN4UAAAICN8UAAAICOAUAAAICOEUAAAICOIUAAAICOMUAAAICOQUAAAICOUUAAAICOYUAAAICOcUAAAICOgUAAAICOkUAAAICOoUAAAICOsUAAAICOwUAAAICO0UAAAICO4UAAAICO8UAAAICPAUAAAICPEUAAAICPIUAAAICPMUAAAICPQUAAAICPUUAAAICPYUAAAICPcUAAAICPgUAAAICPkUAAAICPoUAAAICPsUAAAICPwUAAAICP0UAAAICP4UAAAICP8UAAAICAAVAAAICAEVAAAICAIVAAAICAMVAAAICAQVAAAICAUVAAAICAYVAAAICAcVAAAICAgVAAAICAkVAAAICAoVAAAICAsVAAAICAwVAAAICA0VAAAICA4VAAAICA8VAAAICBAVAAAICBEVAAAICBIVAAAICBMVAAAICBQVAAAICBUVAAAICBYVAAAICBcVAAAICBgVAAAICBkVAAAICBoVAAAICBsVAAAICBwVAAAICB0VAAAICB4VAAAICB8VAAAICCAVAAAICCEVAAAICCIVAAAICCMVAAAICCQVAAAICCUVAAAICCYVAAAICCcVAAAICCgVAAAICCkVAAAICCoVAAAICCsVAAAICCwVAAAICC0VAAAICC4VAAAICC8VAAAICDAVAAAICDEVAAAICDIVAAAICDMVAAAICDQVAAAICDUVAAAICDYVAAAICDcVAAAICDgVAAAICDkVAAAICDoVAAAICDsVAAAICDwVAAAICD0VAAAICD4VAAAICD8VAAAICEAVAAAICEEVAAAICEIVAAAICEMVAAAICEQVAAAICEUVAAAICEYVAAAICEcVAAAICEgVAAAICEkVAAAICEoVAAAICEsVAAAICEwVAAAICE0VAAAICE4VAAAICE8VAAAICFAVAAAICFEVAAAICFIVAAAICFMVAAAICFQVAAAICFUVAAAICFYVAAAICFcVAAAICFgVAAAICFkVAAAICFoVAAAICFsVAAAICFwVAAAICF0VAAAICF4VAAAICF8VAAAICGAVAAAICGEVAAAICGIVAAAICGMVAAAICGQVAAAICGUVAAAICGYVAAAICGcVAAAICGgVAAAICGkVAAAICGoVAAAICGsVAAAICGwVAAAICG0VAAAICG4VAAAICG8VAAAICHAVAAAICHEVAAAICHIVAAAICHMVAAAICHQVAAAICHUVAAAICHYVAAAICHcVAAAICHgVAAAICHkVAAAICHoVAAAICHsVAAAICHwVAAAICH0VAAAICH4VAAAICH8VAAAICIAVAAAICIEVAAAICIIVAAAICIMVAAAICIQVAAAICIUVAAAICIYVAAAICIcVAAAICIgVAAAICIkVAAAICIoVAAAICIsVAAAICIwVAAAICI0VAAAICI4VAAAICI8VAAAICJAVAAAICJEVAAAICJIVAAAICJMVAAAICJQVAAAICJUVAAAICJYVAAAICJcVAAAICJgVAAAICJkVAAAICJoVAAAICJsVAAAICJwVAAAICJ0VAAAICJ4VAAAICJ8VAAAICKAVAAAICKEVAAAICKIVAAAICKMVAAAICKQVAAAICKUVAAAICKYVAAAICKcVAAAICKgVAAAICKkVAAAICKoVAAAICKsVAAAICKwVAAAICK0VAAAICK4VAAAICK8VAAAICLAVAAAICLEVAAAICLIVAAAICLMVAAAICLQVAAAICLUVAAAICLYVAAAICLcVAAAICLgVAAAICLkVAAAICLoVAAAICLsVAAAICLwVAAAICL0VAAAICL4VAAAICL8VAAAICMAVAAAICMEVAAAICMIVAAAICMMVAAAICMQVAAAICMUVAAAICMYVAAAICMcVAAAICMgVAAAICMkVAAAICMoVAAAICMsVAAAICMwVAAAICM0VAAAICM4VAAAICM8VAAAICNAVAAAICNEVAAAICNIVAAAICNMVAAAICNQVAAAICNUVAAAICNYVAAAICNcVAAAICNgVAAAICNkVAAAICNoVAAAICNsVAAAICNwVAAAICN0VAAAICN4VAAAICN8VAAAICOAVAAAICOEVAAAICOIVAAAICOMVAAAICOQVAAAICOUVAAAICOYVAAAICOcVAAAICOgVAAAICOkVAAAICOoVAAAICOsVAAAICOwVAAAICO0VAAAICO4VAAAICO8VAAAICPAVAAAICPEVAAAICPIVAAAICPMVAAAICPQVAAAICPUVAAAICPYVAAAICPcVAAAICPgVAAAICPkVAAAICPoVAAAICPsVAAAICPwVAAAICP0VAAAICP4VAAAICP8VAAAICAAWAAAICAEWAAAICAIWAAAICAMWAAAICAQWAAAICAUWAAAICAYWAAAICAcWAAAICAgWAAAICAkWAAAICAoWAAAICAsWAAAICAwWAAAICA0WAAAICA4WAAAICA8WAAAICBAWAAAICBEWAAAICBIWAAAICBMWAAAICBQWAAAICBUWAAAICBYWAAAICBcWAAAICBgWAAAICBkWAAAICBoWAAAICBsWAAAICBwWAAAICB0WAAAICB4WAAAICB8WAAAICCAWAAAICCEWAAAICCIWAAAICCMWAAAICCQWAAAICCUWAAAICCYWAAAICCcWAAAICCgWAAAICCkWAAAICCoWAAAICCsWAAAICCwWAAAICC0WAAAICC4WAAAICC8WAAAICDAWAAAICDEWAAAICDIWAAAICDMWAAAICDQWAAAICDUWAAAICDYWAAAICDcWAAAICDgWAAAICDkWAAAICDoWAAAICDsWAAAICDwWAAAICD0WAAAICD4WAAAICD8WAAAICEAWAAAICEEWAAAICEIWAAAICEMWAAAICEQWAAAICEUWAAAICEYWAAAICEcWAAAICEgWAAAICEkWAAAICEoWAAAICEsWAAAICEwWAAAICE0WAAAICE4WAAAICE8WAAAICFAWAAAICFEWAAAICFIWAAAICFMWAAAICFQWAAAICFUWAAAICFYWAAAICFcWAAAICFgWAAAICFkWAAAICFoWAAAICFsWAAAICFwWAAAICF0WAAAICF4WAAAICF8WAAAICGAWAAAICGEWAAAICGIWAAAICGMWAAAICGQWAAAICGUWAAAICGYWAAAICGcWAAAICGgWAAAICGkWAAAICGoWAAAICGsWAAAICGwWAAAICG0WAAAICG4WAAAICG8WAAAICHAWAAAICHEWAAAICHIWAAAICHMWAAAICHQWAAAICHUWAAAICHYWAAAICHcWAAAICHgWAAAICHkWAAAICHoWAAAICHsWAAAICHwWAAAICH0WAAAICH4WAAAICH8WAAAICIAWAAAICIEWAAAICIIWAAAICIMWAAAICIQWAAAICIUWAAAICIYWAAAICIcWAAAICIgWAAAICIkWAAAICIoWAAAICIsWAAAICIwWAAAICI0WAAAICI4WAAAICI8WAAAICJAWAAAICJEWAAAICJIWAAAICJMWAAAICJQWAAAICJUWAAAICJYWAAAICJcWAAAICJgWAAAICJkWAAAICJoWAAAICJsWAAAICJwWAAAICJ0WAAAICJ4WAAAICJ8WAAAICKAWAAAICKEWAAAICKIWAAAICKMWAAAICKQWAAAICKUWAAAICKYWAAAICKcWAAAICKgWAAAICKkWAAAICKoWAAAICKsWAAAICKwWAAAICK0WAAAICK4WAAAICK8WAAAICLAWAAAICLEWAAAICLIWAAAICLMWAAAICLQWAAAICLUWAAAICLYWAAAICLcWAAAICLgWAAAICLkWAAAICLoWAAAICLsWAAAICLwWAAAICL0WAAAICL4WAAAICL8WAAAICMAWAAAICMEWAAAICMIWAAAICMMWAAAICMQWAAAICMUWAAAICMYWAAAICMcWAAAICMgWAAAICMkWAAAICMoWAAAICMsWAAAICMwWAAAICM0WAAAICM4WAAAICM8WAAAICNAWAAAICNEWAAAICNIWAAAICNMWAAAICNQWAAAICNUWAAAICNYWAAAICNcWAAAICNgWAAAICNkWAAAICNoWAAAICNsWAAAICNwWAAAICN0WAAAICN4WAAAICN8WAAAICOAWAAAICOEWAAAICOIWAAAICOMWAAAICOQWAAAICOUWAAAICOYWAAAICOcWAAAICOgWAAAICOkWAAAICOoWAAAICOsWAAAICOwWAAAICO0WAAAICO4WAAAICO8WAAAICPAWAAAICPEWAAAICPIWAAAICPMWAAAICPQWAAAICPUWAAAICPYWAAAICPcWAAAICPgWAAAICPkWAAAICPoWAAAICPsWAAAICPwWAAAICP0WAAAICP4WAAAICP8WAAAICAAXAAAICAEXAAAICAIXAAAICAMXAAAICAQXAAAICAUXAAAICAYXAAAICAcXAAAICAgXAAAICAkXAAAICAoXAAAICAsXAAAICAwXAAAICA0XAAAICA4XAAAICA8XAAAICBAXAAAICBEXAAAICBIXAAAICBMXAAAICBQXAAAICBUXAAAICBYXAAAICBcXAAAICBgXAAAICBkXAAAICBoXAAAICBsXAAAICBwXAAAICB0XAAAICB4XAAAICB8XAAAICCAXAAAICCEXAAAICCIXAAAICCMXAAAICCQXAAAICCUXAAAICCYXAAAICCcXAAAICCgXAAAICCkXAAAICCoXAAAICCsXAAAICCwXAAAICC0XAAAICC4XAAAICC8XAAAICDAXAAAICDEXAAAICDIXAAAICDMXAAAICDQXAAAICDUXAAAICDYXAAAICDcXAAAICDgXAAAICDkXAAAICDoXAAAICDsXAAAICDwXAAAICD0XAAAICD4XAAAICD8XAAAICEAXAAAICEEXAAAICEIXAAAICEMXAAAICEQXAAAICEUXAAAICEYXAAAICEcXAAAICEgXAAAICEkXAAAICEoXAAAICEsXAAAICEwXAAAICE0XAAAICE4XAAAICE8XAAAICFAXAAAICFEXAAAICFIXAAAICFMXAAAICFQXAAAICFUXAAAICFYXAAAICFcXAAAICFgXAAAICFkXAAAICFoXAAAICFsXAAAICFwXAAAICF0XAAAICF4XAAAICF8XAAAICGAXAAAICGEXAAAICGIXAAAICGMXAAAICGQXAAAICGUXAAAICGYXAAAICGcXAAAICGgXAAAICGkXAAAICGoXAAAICGsXAAAICGwXAAAICG0XAAAICG4XAAAICG8XAAAICHAXAAAICHEXAAAICHIXAAAICHMXAAAICHQXAAAICHUXAAAICHYXAAAICHcXAAAICHgXAAAICHkXAAAICHoXAAAICHsXAAAICHwXAAAICH0XAAAICH4XAAAICH8XAAAICIAXAAAICIEXAAAICIIXAAAICIMXAAAICIQXAAAICIUXAAAICIYXAAAICIcXAAAICIgXAAAICIkXAAAICIoXAAAICIsXAAAICIwXAAAICI0XAAAICI4XAAAICI8XAAAICJAXAAAICJEXAAAICJIXAAAICJMXAAAICJQXAAAICJUXAAAICJYXAAAICJcXAAAICJgXAAAICJkXAAAICJoXAAAICJsXAAAICJwXAAAICJ0XAAAICJ4XAAAICJ8XAAAICKAXAAAICKEXAAAICKIXAAAICKMXAAAICKQXAAAICKUXAAAICKYXAAAICKcXAAAICKgXAAAICKkXAAAICKoXAAAICKsXAAAICKwXAAAICK0XAAAICK4XAAAICK8XAAAICLAXAAAICLEXAAAICLIXAAAICLMXAAAICLQXAAAICLUXAAAICLYXAAAICLcXAAAICLgXAAAICLkXAAAICLoXAAAICLsXAAAICLwXAAAICL0XAAAICL4XAAAICL8XAAAICMAXAAAICMEXAAAICMIXAAAICMMXAAAICMQXAAAICMUXAAAICMYXAAAICMcXAAAICMgXAAAICMkXAAAICMoXAAAICMsXAAAICMwXAAAICM0XAAAICM4XAAAICM8XAAAICNAXAAAICNEXAAAICNIXAAAICNMXAAAICNQXAAAICNUXAAAICNYXAAAICNcXAAAICNgXAAAICNkXAAAICNoXAAAICNsXAAAICNwXAAAICN0XAAAICN4XAAAICN8XAAAICOAXAAAICOEXAAAICOIXAAAICOMXAAAICOQXAAAICOUXAAAICOYXAAAICOcXAAAICOgXAAAICOkXAAAICOoXAAAICOsXAAAICOwXAAAICO0XAAAICO4XAAAICO8XAAAICPAXAAAICPEXAAAICPIXAAAICPMXAAAICPQXAAAICPUXAAAICPYXAAAICPcXAAAICPgXAAAICPkXAAAICPoXAAAICPsXAAAICPwXAAAICP0XAAAICP4XAAAICP8XAAAICAAYAAAICAEYAAAICAIYAAAICAMYAAAICAQYAAAICAUYAAAICAYYAAAICAcYAAAICAgYAAAICAkYAAAICAoYAAAICAsYAAAICAwYAAAICA0YAAAICA4YAAAICA8YAAAICBAYAAAICBEYAAAICBIYAAAICBMYAAAICBQYAAAICBUYAAAICBYYAAAICBcYAAAICBgYAAAICBkYAAAICBoYAAAICBsYAAAICBwYAAAICB0YAAAICB4YAAAICB8YAAAICCAYAAAICCEYAAAICCIYAAAICCMYAAAICCQYAAAICCUYAAAICCYYAAAICCcYAAAICCgYAAAICCkYAAAICCoYAAAICCsYAAAICCwYAAAICC0YAAAICC4YAAAICC8YAAAICDAYAAAICDEYAAAICDIYAAAICDMYAAAICDQYAAAICDUYAAAICDYYAAAICDcYAAAICDgYAAAICDkYAAAICDoYAAAICDsYAAAICDwYAAAICD0YAAAICD4YAAAICD8YAAAICEAYAAAICEEYAAAICEIYAAAICEMYAAAICEQYAAAICEUYAAAICEYYAAAICEcYAAAICEgYAAAICEkYAAAICEoYAAAICEsYAAAICEwYAAAICE0YAAAICE4YAAAICE8YAAAICFAYAAAICFEYAAAICFIYAAAICFMYAAAICFQYAAAICFUYAAAICFYYAAAICFcYAAAICFgYAAAICFkYAAAICFoYAAAICFsYAAAICFwYAAAICF0YAAAICF4YAAAICF8YAAAICGAYAAAICGEYAAAICGIYAAAICGMYAAAICGQYAAAICGUYAAAICGYYAAAICGcYAAAICGgYAAAICGkYAAAICGoYAAAICGsYAAAICGwYAAAICG0YAAAICG4YAAAICG8YAAAICHAYAAAICHEYAAAICHIYAAAICHMYAAAICHQYAAAICHUYAAAICHYYAAAICHcYAAAICHgYAAAICHkYAAAICHoYAAAICHsYAAAICHwYAAAICH0YAAAICH4YAAAICH8YAAAICIAYAAAICIEYAAAICIIYAAAICIMYAAAICIQYAAAICIUYAAAICIYYAAAICIcYAAAICIgYAAAICIkYAAAICIoYAAAICIsYAAAICIwYAAAICI0YAAAICI4YAAAICI8YAAAICJAYAAAICJEYAAAICJIYAAAICJMYAAAICJQYAAAICJUYAAAICJYYAAAICJcYAAAICJgYAAAICJkYAAAICJoYAAAICJsYAAAICJwYAAAICJ0YAAAICJ4YAAAICJ8YAAAICKAYAAAICKEYAAAICKIYAAAICKMYAAAICKQYAAAICKUYAAAICKYYAAAICKcYAAAICKgYAAAICKkYAAAICKoYAAAICKsYAAAICKwYAAAICK0YAAAICK4YAAAICK8YAAAICLAYAAAICLEYAAAICLIYAAAICLMYAAAICLQYAAAICLUYAAAICLYYAAAICLcYAAAICLgYAAAICLkYAAAICLoYAAAICLsYAAAICLwYAAAICL0YAAAICL4YAAAICL8YAAAICMAYAAAICMEYAAAICMIYAAAICMMYAAAICMQYAAAICMUYAAAICMYYAAAICMcYAAAICMgYAAAICMkYAAAICMoYAAAICMsYAAAICMwYAAAICM0YAAAICM4YAAAICM8YAAAICNAYAAAICNEYAAAICNIYAAAICNMYAAAICNQYAAAICNUYAAAICNYYAAAICNcYAAAICNgYAAAICNkYAAAICNoYAAAICNsYAAAICNwYAAAICN0YAAAICN4YAAAICN8YAAAICOAYAAAICOEYAAAICOIYAAAICOMYAAAICOQYAAAICOUYAAAICOYYAAAICOcYAAAICOgYAAAICOkYAAAICOoYAAAICOsYAAAICOwYAAAICO0YAAAICO4YAAAICO8YAAAICPAYAAAICPEYAAAICPIYAAAICPMYAAAICPQYAAAICPUYAAAICPYYAAAICPcYAAAICPgYAAAICPkYAAAICPoYAAAICPsYAAAICPwYAAAICP0YAAAICP4YAAAICP8YAAAICAAZAAAICAEZAAAICAIZAAAICAMZAAAICAQZAAAICAUZAAAICAYZAAAICAcZAAAICAgZAAAICAkZAAAICAoZAAAICAsZAAAICAwZAAAICA0ZAAAICA4ZAAAICA8ZAAAICBAZAAAICBEZAAAICBIZAAAICBMZAAAICBQZAAAICBUZAAAICBYZAAAICBcZAAAICBgZAAAICBkZAAAICBoZAAAICBsZAAAICBwZAAAICB0ZAAAICB4ZAAAICB8ZAAAICCAZAAAICCEZAAAICCIZAAAICCMZAAAICCQZAAAICCUZAAAICCYZAAAICCcZAAAICCgZAAAICCkZAAAICCoZAAAICCsZAAAICCwZAAAICC0ZAAAICC4ZAAAICC8ZAAAICDAZAAAICDEZAAAICDIZAAAICDMZAAAICDQZAAAICDUZAAAICDYZAAAICDcZAAAICDgZAAAICDkZAAAICDoZAAAICDsZAAAICDwZAAAICD0ZAAAICD4ZAAAICD8ZAAAICEAZAAAICEEZAAAICEIZAAAICEMZAAAICEQZAAAICEUZAAAICEYZAAAICEcZAAAICEgZAAAICEkZAAAICEoZAAAICEsZAAAICEwZAAAICE0ZAAAICE4ZAAAICE8ZAAAICFAZAAAICFEZAAAICFIZAAAICFMZAAAICFQZAAAICFUZAAAICFYZAAAICFcZAAAICFgZAAAICFkZAAAICFoZAAAICFsZAAAICFwZAAAICF0ZAAAICF4ZAAAICF8ZAAAICGAZAAAICGEZAAAICGIZAAAICGMZAAAICGQZAAAICGUZAAAICGYZAAAICGcZAAAICGgZAAAICGkZAAAICGoZAAAICGsZAAAICGwZAAAICG0ZAAAICG4ZAAAICG8ZAAAICHAZAAAICHEZAAAICHIZAAAICHMZAAAICHQZAAAICHUZAAAICHYZAAAICHcZAAAICHgZAAAICHkZAAAICHoZAAAICHsZAAAICHwZAAAICH0ZAAAICH4ZAAAICH8ZAAAICIAZAAAICIEZAAAICIIZAAAICIMZAAAICIQZAAAICIUZAAAICIYZAAAICIcZAAAICIgZAAAICIkZAAAICIoZAAAICIsZAAAICIwZAAAICI0ZAAAICI4ZAAAICI8ZAAAICJAZAAAICJEZAAAICJIZAAAICJMZAAAICJQZAAAICJUZAAAICJYZAAAICJcZAAAICJgZAAAICJkZAAAICJoZAAAICJsZAAAICJwZAAAICJ0ZAAAICJ4ZAAAICJ8ZAAAICKAZAAAICKEZAAAICKIZAAAICKMZAAAICKQZAAAICKUZAAAICKYZAAAICKcZAAAICKgZAAAICKkZAAAICKoZAAAICKsZAAAICKwZAAAICK0ZAAAICK4ZAAAICK8ZAAAICLAZAAAICLEZAAAICLIZAAAICLMZAAAICLQZAAAICLUZAAAICLYZAAAICLcZAAAICLgZAAAICLkZAAAICLoZAAAICLsZAAAICLwZAAAICL0ZAAAICL4ZAAAICL8ZAAAICMAZAAAICMEZAAAICMIZAAAICMMZAAAICMQZAAAICMUZAAAICMYZAAAICMcZAAAICMgZAAAICMkZAAAICMoZAAAICMsZAAAICMwZAAAICM0ZAAAICM4ZAAAICM8ZAAAICNAZAAAICNEZAAAICNIZAAAICNMZAAAICNQZAAAICNUZAAAICNYZAAAICNcZAAAICNgZAAAICNkZAAAICNoZAAAICNsZAAAICNwZAAAICN0ZAAAICN4ZAAAICN8ZAAAICOAZAAAICOEZAAAICOIZAAAICOMZAAAICOQZAAAICOUZAAAICOYZAAAICOcZAAAICOgZAAAICOkZAAAICOoZAAAICOsZAAAICOwZAAAICO0ZAAAICO4ZAAAICO8ZAAAICPAZAAAICPEZAAAICPIZAAAICPMZAAAICPQZAAAICPUZAAAICPYZAAAICPcZAAAICPgZAAAICPkZAAAICPoZAAAICPsZAAAICPwZAAAICP0ZAAAICP4ZAAAICP8ZAAAICAAaAAAICAEaAAAICAIaAAAICAMaAAAICAQaAAAICAUaAAAICAYaAAAICAcaAAAICAgaAAAICAkaAAAICAoaAAAICAsaAAAICAwaAAAICA0aAAAICA4aAAAICA8aAAAICBAaAAAICBEaAAAICBIaAAAICBMaAAAICBQaAAAICBUaAAAICBYaAAAICBcaAAAICBgaAAAICBkaAAAICBoaAAAICBsaAAAICBwaAAAICB0aAAAICB4aAAAICB8aAAAICCAaAAAICCEaAAAICCIaAAAICCMaAAAICCQaAAAICCUaAAAICCYaAAAICCcaAAAICCgaAAAICCkaAAAICCoaAAAICCsaAAAICCwaAAAICC0aAAAICC4aAAAICC8aAAAICDAaAAAICDEaAAAICDIaAAAICDMaAAAICDQaAAAICDUaAAAICDYaAAAICDcaAAAICDgaAAAICDkaAAAICDoaAAAICDsaAAAICDwaAAAICD0aAAAICD4aAAAICD8aAAAICEAaAAAICEEaAAAICEIaAAAICEMaAAAICEQaAAAICEUaAAAICEYaAAAICEcaAAAICEgaAAAICEkaAAAICEoaAAAICEsaAAAICEwaAAAICE0aAAAICE4aAAAICE8aAAAICFAaAAAICFEaAAAICFIaAAAICFMaAAAICFQaAAAICFUaAAAICFYaAAAICFcaAAAICFgaAAAICFkaAAAICFoaAAAICFsaAAAICFwaAAAICF0aAAAICF4aAAAICF8aAAAICGAaAAAICGEaAAAICGIaAAAICGMaAAAICGQaAAAICGUaAAAICGYaAAAICGcaAAAICGgaAAAICGkaAAAICGoaAAAICGsaAAAICGwaAAAICG0aAAAICG4aAAAICG8aAAAICHAaAAAICHEaAAAICHIaAAAICHMaAAAICHQaAAAICHUaAAAICHYaAAAICHcaAAAICHgaAAAICHkaAAAICHoaAAAICHsaAAAICHwaAAAICH0aAAAICH4aAAAICH8aAAAICIAaAAAICIEaAAAICIIaAAAICIMaAAAICIQaAAAICIUaAAAICIYaAAAICIcaAAAICIgaAAAICIkaAAAICIoaAAAICIsaAAAICIwaAAAICI0aAAAICI4aAAAICI8aAAAICJAaAAAICJEaAAAICJIaAAAICJMaAAAICJQaAAAICJUaAAAICJYaAAAICJcaAAAICJgaAAAICJkaAAAICJoaAAAICJsaAAAICJwaAAAICJ0aAAAICJ4aAAAICJ8aAAAICKAaAAAICKEaAAAICKIaAAAICKMaAAAICKQaAAAICKUaAAAICKYaAAAICKcaAAAICKgaAAAICKkaAAAICKoaAAAICKsaAAAICKwaAAAICK0aAAAICK4aAAAICK8aAAAICLAaAAAICLEaAAAICLIaAAAICLMaAAAICLQaAAAICLUaAAAICLYaAAAICLcaAAAICLgaAAAICLkaAAAICLoaAAAICLsaAAAICLwaAAAICL0aAAAICL4aAAAICL8aAAAICMAaAAAICMEaAAAICMIaAAAICMMaAAAICMQaAAAICMUaAAAICMYaAAAICMcaAAAICMgaAAAICMkaAAAICMoaAAAICMsaAAAICMwaAAAICM0aAAAICM4aAAAICM8aAAAICNAaAAAICNEaAAAICNIaAAAICNMaAAAICNQaAAAICNUaAAAICNYaAAAICNcaAAAICNgaAAAICNkaAAAICNoaAAAICNsaAAAICNwaAAAICN0aAAAICN4aAAAICN8aAAAICOAaAAAICOEaAAAICOIaAAAICOMaAAAICOQaAAAICOUaAAAICOYaAAAICOcaAAAICOgaAAAICOkaAAAICOoaAAAICOsaAAAICOwaAAAICO0aAAAICO4aAAAICO8aAAAICPAaAAAICPEaAAAICPIaAAAICPMaAAAICPQaAAAICPUaAAAICPYaAAAICPcaAAAICPgaAAAICPkaAAAICPoaAAAICPsaAAAICPwaAAAICP0aAAAICP4aAAAICP8aAAAICAAbAAAICAEbAAAICAIbAAAICAMbAAAICAQbAAAICAUbAAAICAYbAAAICAcbAAAICAgbAAAICAkbAAAICAobAAAICAsbAAAICAwbAAAICA0bAAAICA4bAAAICA8bAAAICBAbAAAICBEbAAAICBIbAAAICBMbAAAICBQbAAAICBUbAAAICBYbAAAICBcbAAAICBgbAAAICBkbAAAICBobAAAICBsbAAAICBwbAAAICB0bAAAICB4bAAAICB8bAAAICCAbAAAICCEbAAAICCIbAAAICCMbAAAICCQbAAAICCUbAAAICCYbAAAICCcbAAAICCgbAAAICCkbAAAICCobAAAICCsbAAAICCwbAAAICC0bAAAICC4bAAAICC8bAAAICDAbAAAICDEbAAAICDIbAAAICDMbAAAICDQbAAAICDUbAAAICDYbAAAICDcbAAAICDgbAAAICDkbAAAICDobAAAICDsbAAAICDwbAAAICD0bAAAICD4bAAAICD8bAAAICEAbAAAICEEbAAAICEIbAAAICEMbAAAICEQbAAAICEUbAAAICEYbAAAICEcbAAAICEgbAAAICEkbAAAICEobAAAICEsbAAAICEwbAAAICE0bAAAICE4bAAAICE8bAAAICFAbAAAICFEbAAAICFIbAAAICFMbAAAICFQbAAAICFUbAAAICFYbAAAICFcbAAAICFgbAAAICFkbAAAICFobAAAICFsbAAAICFwbAAAICF0bAAAICF4bAAAICF8bAAAICGAbAAAICGEbAAAICGIbAAAICGMbAAAICGQbAAAICGUbAAAICGYbAAAICGcbAAAICGgbAAAICGkbAAAICGobAAAICGsbAAAICGwbAAAICG0bAAAICG4bAAAICG8bAAAICHAbAAAICHEbAAAICHIbAAAICHMbAAAICHQbAAAICHUbAAAICHYbAAAICHcbAAAICHgbAAAICHkbAAAICHobAAAICHsbAAAICHwbAAAICH0bAAAICH4bAAAICH8bAAAICIAbAAAICIEbAAAICIIbAAAICIMbAAAICIQbAAAICIUbAAAICIYbAAAICIcbAAAICIgbAAAICIkbAAAICIobAAAICIsbAAAICIwbAAAICI0bAAAICI4bAAAICI8bAAAICJAbAAAICJEbAAAICJIbAAAICJMbAAAICJQbAAAICJUbAAAICJYbAAAICJcbAAAICJgbAAAICJkbAAAICJobAAAICJsbAAAICJwbAAAICJ0bAAAICJ4bAAAICJ8bAAAICKAbAAAICKEbAAAICKIbAAAICKMbAAAICKQbAAAICKUbAAAICKYbAAAICKcbAAAICKgbAAAICKkbAAAICKobAAAICKsbAAAICKwbAAAICK0bAAAICK4bAAAICK8bAAAICLAbAAAICLEbAAAICLIbAAAICLMbAAAICLQbAAAICLUbAAAICLYbAAAICLcbAAAICLgbAAAICLkbAAAICLobAAAICLsbAAAICLwbAAAICL0bAAAICL4bAAAICL8bAAAICMAbAAAICMEbAAAICMIbAAAICMMbAAAICMQbAAAICMUbAAAICMYbAAAICMcbAAAICMgbAAAICMkbAAAICMobAAAICMsbAAAICMwbAAAICM0bAAAICM4bAAAICM8bAAAICNAbAAAICNEbAAAICNIbAAAICNMbAAAICNQbAAAICNUbAAAICNYbAAAICNcbAAAICNgbAAAICNkbAAAICNobAAAICNsbAAAICNwbAAAICN0bAAAICN4bAAAICN8bAAAICOAbAAAICOEbAAAICOIbAAAICOMbAAAICOQbAAAICOUbAAAICOYbAAAICOcbAAAICOgbAAAICOkbAAAICOobAAAICOsbAAAICOwbAAAICO0bAAAICO4bAAAICO8bAAAICPAbAAAICPEbAAAICPIbAAAICPMbAAAICPQbAAAICPUbAAAICPYbAAAICPcbAAAICPgbAAAICPkbAAAICPobAAAICPsbAAAICPwbAAAICP0bAAAICP4bAAAICP8bAAAICAAcAAAICAEcAAAICAIcAAAICAMcAAAICAQcAAAICAUcAAAICAYcAAAICAccAAAICAgcAAAICAkcAAAICAocAAAICAscAAAICAwcAAAICA0cAAAICA4cAAAICA8cAAAICBAcAAAICBEcAAAICBIcAAAICBMcAAAICBQcAAAICBUcAAAICBYcAAAICBccAAAICBgcAAAICBkcAAAICBocAAAICBscAAAICBwcAAAICB0cAAAICB4cAAAICB8cAAAICCAcAAAICCEcAAAICCIcAAAICCMcAAAICCQcAAAICCUcAAAICCYcAAAICCccAAAICCgcAAAICCkcAAAICCocAAAICCscAAAICCwcAAAICC0cAAAICC4cAAAICC8cAAAICDAcAAAICDEcAAAICDIcAAAICDMcAAAICDQcAAAICDUcAAAICDYcAAAICDccAAAICDgcAAAICDkcAAAICDocAAAICDscAAAICDwcAAAICD0cAAAICD4cAAAICD8cAAAICEAcAAAICEEcAAAICEIcAAAICEMcAAAICEQcAAAICEUcAAAICEYcAAAICEccAAAICEgcAAAICEkcAAAICEocAAAICEscAAAICEwcAAAICE0cAAAICE4cAAAICE8cAAAICFAcAAAICFEcAAAICFIcAAAICFMcAAAICFQcAAAICFUcAAAICFYcAAAICFccAAAICFgcAAAICFkcAAAICFocAAAICFscAAAICFwcAAAICF0cAAAICF4cAAAICF8cAAAICGAcAAAICGEcAAAICGIcAAAICGMcAAAICGQcAAAICGUcAAAICGYcAAAICGccAAAICGgcAAAICGkcAAAICGocAAAICGscAAAICGwcAAAICG0cAAAICG4cAAAICG8cAAAICHAcAAAICHEcAAAICHIcAAAICHMcAAAICHQcAAAICHUcAAAICHYcAAAICHccAAAICHgcAAAICHkcAAAICHocAAAICHscAAAICHwcAAAICH0cAAAICH4cAAAICH8cAAAICIAcAAAICIEcAAAICIIcAAAICIMcAAAICIQcAAAICIUcAAAICIYcAAAICIccAAAICIgcAAAICIkcAAAICIocAAAICIscAAAICIwcAAAICI0cAAAICI4cAAAICI8cAAAICJAcAAAICJEcAAAICJIcAAAICJMcAAAICJQcAAAICJUcAAAICJYcAAAICJccAAAICJgcAAAICJkcAAAICJocAAAICJscAAAICJwcAAAICJ0cAAAICJ4cAAAICJ8cAAAICKAcAAAICKEcAAAICKIcAAAICKMcAAAICKQcAAAICKUcAAAICKYcAAAICKccAAAICKgcAAAICKkcAAAICKocAAAICKscAAAICKwcAAAICK0cAAAICK4cAAAICK8cAAAICLAcAAAICLEcAAAICLIcAAAICLMcAAAICLQcAAAICLUcAAAICLYcAAAICLccAAAICLgcAAAICLkcAAAICLocAAAICLscAAAICLwcAAAICL0cAAAICL4cAAAICL8cAAAICMAcAAAICMEcAAAICMIcAAAICMMcAAAICMQcAAAICMUcAAAICMYcAAAICMccAAAICMgcAAAICMkcAAAICMocAAAICMscAAAICMwcAAAICM0cAAAICM4cAAAICM8cAAAICNAcAAAICNEcAAAICNIcAAAICNMcAAAICNQcAAAICNUcAAAICNYcAAAICNccAAAICNgcAAAICNkcAAAICNocAAAICNscAAAICNwcAAAICN0cAAAICN4cAAAICN8cAAAICOAcAAAICOEcAAAICOIcAAAICOMcAAAICOQcAAAICOUcAAAICOYcAAAICOccAAAICOgcAAAICOkcAAAICOocAAAICOscAAAICOwcAAAICO0cAAAICO4cAAAICO8cAAAICPAcAAAICPEcAAAICPIcAAAICPMcAAAICPQcAAAICPUcAAAICPYcAAAICPccAAAICPgcAAAICPkcAAAICPocAAAICPscAAAICPwcAAAICP0cAAAICP4cAAAICP8cAAAICAAdAAAICAEdAAAICAIdAAAICAMdAAAICAQdAAAICAUdAAAICAYdAAAICAcdAAAICAgdAAAICAkdAAAICAodAAAICAsdAAAICAwdAAAICA0dAAAICA4dAAAICA8dAAAICBAdAAAICBEdAAAICBIdAAAICBMdAAAICBQdAAAICBUdAAAICBYdAAAICBcdAAAICBgdAAAICBkdAAAICBodAAAICBsdAAAICBwdAAAICB0dAAAICB4dAAAICB8dAAAICCAdAAAICCEdAAAICCIdAAAICCMdAAAICCQdAAAICCUdAAAICCYdAAAICCcdAAAICCgdAAAICCkdAAAICCodAAAICCsdAAAICCwdAAAICC0dAAAICC4dAAAICC8dAAAICDAdAAAICDEdAAAICDIdAAAICDMdAAAICDQdAAAICDUdAAAICDYdAAAICDcdAAAICDgdAAAICDkdAAAICDodAAAICDsdAAAICDwdAAAICD0dAAAICD4dAAAICD8dAAAICEAdAAAICEEdAAAICEIdAAAICEMdAAAICEQdAAAICEUdAAAICEYdAAAICEcdAAAICEgdAAAICEkdAAAICEodAAAICEsdAAAICEwdAAAICE0dAAAICE4dAAAICE8dAAAICFAdAAAICFEdAAAICFIdAAAICFMdAAAICFQdAAAICFUdAAAICFYdAAAICFcdAAAICFgdAAAICFkdAAAICFodAAAICFsdAAAICFwdAAAICF0dAAAICF4dAAAICF8dAAAICGAdAAAICGEdAAAICGIdAAAICGMdAAAICGQdAAAICGUdAAAICGYdAAAICGcdAAAICGgdAAAICGkdAAAICGodAAAICGsdAAAICGwdAAAICG0dAAAICG4dAAAICG8dAAAICHAdAAAICHEdAAAICHIdAAAICHMdAAAICHQdAAAICHUdAAAICHYdAAAICHcdAAAICHgdAAAICHkdAAAICHodAAAICHsdAAAICHwdAAAICH0dAAAICH4dAAAICH8dAAAICIAdAAAICIEdAAAICIIdAAAICIMdAAAICIQdAAAICIUdAAAICIYdAAAICIcdAAAICIgdAAAICIkdAAAICIodAAAICIsdAAAICIwdAAAICI0dAAAICI4dAAAICI8dAAAICJAdAAAICJEdAAAICJIdAAAICJMdAAAICJQdAAAICJUdAAAICJYdAAAICJcdAAAICJgdAAAICJkdAAAICJodAAAICJsdAAAICJwdAAAICJ0dAAAICJ4dAAAICJ8dAAAICKAdAAAICKEdAAAICKIdAAAICKMdAAAICKQdAAAICKUdAAAICKYdAAAICKcdAAAICKgdAAAICKkdAAAICKodAAAICKsdAAAICKwdAAAICK0dAAAICK4dAAAICK8dAAAICLAdAAAICLEdAAAICLIdAAAICLMdAAAICLQdAAAICLUdAAAICLYdAAAICLcdAAAICLgdAAAICLkdAAAICLodAAAICLsdAAAICLwdAAAICL0dAAAICL4dAAAICL8dAAAICMAdAAAICMEdAAAICMIdAAAICMMdAAAICMQdAAAICMUdAAAICMYdAAAICMcdAAAICMgdAAAICMkdAAAICModAAAICMsdAAAICMwdAAAICM0dAAAICM4dAAAICM8dAAAICNAdAAAICNEdAAAICNIdAAAICNMdAAAICNQdAAAICNUdAAAICNYdAAAICNcdAAAICNgdAAAICNkdAAAICNodAAAICNsdAAAICNwdAAAICN0dAAAICN4dAAAICN8dAAAICOAdAAAICOEdAAAICOIdAAAICOMdAAAICOQdAAAICOUdAAAICOYdAAAICOcdAAAICOgdAAAICOkdAAAICOodAAAICOsdAAAICOwdAAAICO0dAAAICO4dAAAICO8dAAAICPAdAAAICPEdAAAICPIdAAAICPMdAAAICPQdAAAICPUdAAAICPYdAAAICPcdAAAICPgdAAAICPkdAAAICPodAAAICPsdAAAICPwdAAAICP0dAAAICP4dAAAICP8dAAAICAAeAAAICAEeAAAICAIeAAAICAMeAAAICAQeAAAICAUeAAAICAYeAAAICAceAAAICAgeAAAICAkeAAAICAoeAAAICAseAAAICAweAAAICA0eAAAICA4eAAAICA8eAAAICBAeAAAICBEeAAAICBIeAAAICBMeAAAICBQeAAAICBUeAAAICBYeAAAICBceAAAICBgeAAAICBkeAAAICBoeAAAICBseAAAICBweAAAICB0eAAAICB4eAAAICB8eAAAICCAeAAAICCEeAAAICCIeAAAICCMeAAAICCQeAAAICCUeAAAICCYeAAAICCceAAAICCgeAAAICCkeAAAICCoeAAAICCseAAAICCweAAAICC0eAAAICC4eAAAICC8eAAAICDAeAAAICDEeAAAICDIeAAAICDMeAAAICDQeAAAICDUeAAAICDYeAAAICDceAAAICDgeAAAICDkeAAAICDoeAAAICDseAAAICDweAAAICD0eAAAICD4eAAAICD8eAAAICEAeAAAICEEeAAAICEIeAAAICEMeAAAICEQeAAAICEUeAAAICEYeAAAICEceAAAICEgeAAAICEkeAAAICEoeAAAICEseAAAICEweAAAICE0eAAAICE4eAAAICE8eAAAICFAeAAAICFEeAAAICFIeAAAICFMeAAAICFQeAAAICFUeAAAICFYeAAAICFceAAAICFgeAAAICFkeAAAICFoeAAAICFseAAAICFweAAAICF0eAAAICF4eAAAICF8eAAAICGAeAAAICGEeAAAICGIeAAAICGMeAAAICGQeAAAICGUeAAAICGYeAAAICGceAAAICGgeAAAICGkeAAAICGoeAAAICGseAAAICGweAAAICG0eAAAICG4eAAAICG8eAAAICHAeAAAICHEeAAAICHIeAAAICHMeAAAICHQeAAAICHUeAAAICHYeAAAICHceAAAICHgeAAAICHkeAAAICHoeAAAICHseAAAICHweAAAICH0eAAAICH4eAAAICH8eAAAICIAeAAAICIEeAAAICIIeAAAICIMeAAAICIQeAAAICIUeAAAICIYeAAAICIceAAAICIgeAAAICIkeAAAICIoeAAAICIseAAAICIweAAAICI0eAAAICI4eAAAICI8eAAAICJAeAAAICJEeAAAICJIeAAAICJMeAAAICJQeAAAICJUeAAAICJYeAAAICJceAAAICJgeAAAICJkeAAAICJoeAAAICJseAAAICJweAAAICJ0eAAAICJ4eAAAICJ8eAAAICKAeAAAICKEeAAAICKIeAAAICKMeAAAICKQeAAAICKUeAAAICKYeAAAICKceAAAICKgeAAAICKkeAAAICKoeAAAICKseAAAICKweAAAICK0eAAAICK4eAAAICK8eAAAICLAeAAAICLEeAAAICLIeAAAICLMeAAAICLQeAAAICLUeAAAICLYeAAAICLceAAAICLgeAAAICLkeAAAICLoeAAAICLseAAAICLweAAAICL0eAAAICL4eAAAICL8eAAAICMAeAAAICMEeAAAICMIeAAAICMMeAAAICMQeAAAICMUeAAAICMYeAAAICMceAAAICMgeAAAICMkeAAAICMoeAAAICMseAAAICMweAAAICM0eAAAICM4eAAAICM8eAAAICNAeAAAICNEeAAAICNIeAAAICNMeAAAICNQeAAAICNUeAAAICNYeAAAICNceAAAICNgeAAAICNkeAAAICNoeAAAICNseAAAICNweAAAICN0eAAAICN4eAAAICN8eAAAICOAeAAAICOEeAAAICOIeAAAICOMeAAAICOQeAAAICOUeAAAICOYeAAAICOceAAAICOgeAAAICOkeAAAICOoeAAAICOseAAAICOweAAAICO0eAAAICO4eAAAICO8eAAAICPAeAAAICPEeAAAICPIeAAAICPMeAAAICPQeAAAICPUeAAAICPYeAAAICPceAAAICPgeAAAICPkeAAAICPoeAAAICPseAAAICPweAAAICP0eAAAICP4eAAAICP8eAAAICAAfAAAICAEfAAAICAIfAAAICAMfAAAICAQfAAAICAUfAAAICAYfAAAICAcfAAAICAgfAAAICAkfAAAICAofAAAICAsfAAAICAwfAAAICA0fAAAICA4fAAAICA8fAAAICBAfAAAICBEfAAAICBIfAAAICBMfAAAICBQfAAAICBUfAAAICBYfAAAICBcfAAAICBgfAAAICBkfAAAICBofAAAICBsfAAAICBwfAAAICB0fAAAICB4fAAAICB8fAAAICCAfAAAICCEfAAAICCIfAAAICCMfAAAICCQfAAAICCUfAAAICCYfAAAICCcfAAAICCgfAAAICCkfAAAICCofAAAICCsfAAAICCwfAAAICC0fAAAICC4fAAAICC8fAAAICDAfAAAICDEfAAAICDIfAAAICDMfAAAICDQfAAAICDUfAAAICDYfAAAICDcfAAAICDgfAAAICDkfAAAICDofAAAICDsfAAAICDwfAAAICD0fAAAICD4fAAAICD8fAAAICEAfAAAICEEfAAAICEIfAAAICEMfAAAICEQfAAAICEUfAAAICEYfAAAICEcfAAAICEgfAAAICEkfAAAICEofAAAICEsfAAAICEwfAAAICE0fAAAICE4fAAAICE8fAAAICFAfAAAICFEfAAAICFIfAAAICFMfAAAICFQfAAAICFUfAAAICFYfAAAICFcfAAAICFgfAAAICFkfAAAICFofAAAICFsfAAAICFwfAAAICF0fAAAICF4fAAAICF8fAAAICGAfAAAICGEfAAAICGIfAAAICGMfAAAICGQfAAAICGUfAAAICGYfAAAICGcfAAAICGgfAAAICGkfAAAICGofAAAICGsfAAAICGwfAAAICG0fAAAICG4fAAAICG8fAAAICHAfAAAICHEfAAAICHIfAAAICHMfAAAICHQfAAAICHUfAAAICHYfAAAICHcfAAAICHgfAAAICHkfAAAICHofAAAICHsfAAAICHwfAAAICH0fAAAICH4fAAAICH8fAAAICIAfAAAICIEfAAAICIIfAAAICIMfAAAICIQfAAAICIUfAAAICIYfAAAICIcfAAAICIgfAAAICIkfAAAICIofAAAICIsfAAAICIwfAAAICI0fAAAICI4fAAAICI8fAAAICJAfAAAICJEfAAAICJIfAAAICJMfAAAICJQfAAAICJUfAAAICJYfAAAICJcfAAAICJgfAAAICJkfAAAICJofAAAICJsfAAAICJwfAAAICJ0fAAAICJ4fAAAICJ8fAAAICKAfAAAICKEfAAAICKIfAAAICKMfAAAICKQfAAAICKUfAAAICKYfAAAICKcfAAAICKgfAAAICKkfAAAICKofAAAICKsfAAAICKwfAAAICK0fAAAICK4fAAAICK8fAAAICLAfAAAICLEfAAAICLIfAAAICLMfAAAICLQfAAAICLUfAAAICLYfAAAICLcfAAAICLgfAAAICLkfAAAICLofAAAICLsfAAAICLwfAAAICL0fAAAICL4fAAAICL8fAAAICMAfAAAICMEfAAAICMIfAAAICMMfAAAICMQfAAAICMUfAAAICMYfAAAICMcfAAAICMgfAAAICMkfAAAICMofAAAICMsfAAAICMwfAAAICM0fAAAICM4fAAAICM8fAAAICNAfAAAICNEfAAAICNIfAAAICNMfAAAICNQfAAAICNUfAAAICNYfAAAICNcfAAAICNgfAAAICNkfAAAICNofAAAICNsfAAAICNwfAAAICN0fAAAICN4fAAAICN8fAAAICOAfAAAICOEfAAAICOIfAAAICOMfAAAICOQfAAAICOUfAAAICOYfAAAICOcfAAAICOgfAAAICOkfAAAICOofAAAICOsfAAAICOwfAAAICO0fAAAICO4fAAAICO8fAAAICPAfAAAICPEfAAAICPIfAAAICPMfAAAICPQfAAAICPUfAAAICPYfAAAICPcfAAAICPgfAAAICPkfAAAICPofAAAICPsfAAAICPwfAAAICP0fAAAICP4fAAAICP8fAAAICAAgAAAICAEgAAAICAIgAAAICAMgAAAICAQgAAAICAUgAAAICAYgAAAICAcgAAAICAggAAAICAkgAAAICAogAAAICAsgAAAICAwgAAAICA0gAAAICA4gAAAICA8gAAAICBAgAAAICBEgAAAICBIgAAAICBMgAAAICBQgAAAICBUgAAAICBYgAAAICBcgAAAICBggAAAICBkgAAAICBogAAAICBsgAAAICBwgAAAICB0gAAAICB4gAAAICB8gAAAICCAgAAAICCEgAAAICCIgAAAICCMgAAAICCQgAAAICCUgAAAICCYgAAAICCcgAAAICCggAAAICCkgAAAICCogAAAICCsgAAAICCwgAAAICC0gAAAICC4gAAAICC8gAAAICDAgAAAICDEgAAAICDIgAAAICDMgAAAICDQgAAAICDUgAAAICDYgAAAICDcgAAAICDggAAAICDkgAAAICDogAAAICDsgAAAICDwgAAAICD0gAAAICD4gAAAICD8gAAAICEAgAAAICEEgAAAICEIgAAAICEMgAAAICEQgAAAICEUgAAAICEYgAAAICEcgAAAICEggAAAICEkgAAAICEogAAAICEsgAAAICEwgAAAICE0gAAAICE4gAAAICE8gAAAICFAgAAAICFEgAAAICFIgAAAICFMgAAAICFQgAAAICFUgAAAICFYgAAAICFcgAAAICFggAAAICFkgAAAICFogAAAICFsgAAAICFwgAAAICF0gAAAICF4gAAAICF8gAAAICGAgAAAICGEgAAAICGIgAAAICGMgAAAICGQgAAAICGUgAAAICGYgAAAICGcgAAAICGggAAAICGkgAAAICGogAAAICGsgAAAICGwgAAAICG0gAAAICG4gAAAICG8gAAAICHAgAAAICHEgAAAICHIgAAAICHMgAAAICHQgAAAICHUgAAAICHYgAAAICHcgAAAICHggAAAICHkgAAAICHogAAAICHsgAAAICHwgAAAICH0gAAAICH4gAAAICH8gAAAICIAgAAAICIEgAAAICIIgAAAICIMgAAAICIQgAAAICIUgAAAICIYgAAAICIcgAAAICIggAAAICIkgAAAICIogAAAICIsgAAAICIwgAAAICI0gAAAICI4gAAAICI8gAAAICJAgAAAICJEgAAAICJIgAAAICJMgAAAICJQgAAAICJUgAAAICJYgAAAICJcgAAAICJggAAAICJkgAAAICJogAAAICJsgAAAICJwgAAAICJ0gAAAICJ4gAAAICJ8gAAAICKAgAAAICKEgAAAICKIgAAAICKMgAAAICKQgAAAICKUgAAAICKYgAAAICKcgAAAICKggAAAICKkgAAAICKogAAAICKsgAAAICKwgAAAICK0gAAAICK4gAAAICK8gAAAICLAgAAAICLEgAAAICLIgAAAICLMgAAAICLQgAAAICLUgAAAICLYgAAAICLcgAAAICLggAAAICLkgAAAICLogAAAICLsgAAAICLwgAAAICL0gAAAICL4gAAAICL8gAAAICMAgAAAICMEgAAAICMIgAAAICMMgAAAICMQgAAAICMUgAAAICMYgAAAICMcgAAAICMggAAAICMkgAAAICMogAAAICMsgAAAICMwgAAAICM0gAAAICM4gAAAICM8gAAAICNAgAAAICNEgAAAICNIgAAAICNMgAAAICNQgAAAICNUgAAAICNYgAAAICNcgAAAICNggAAAICNkgAAAICNogAAAICNsgAAAICNwgAAAICN0gAAAICN4gAAAICN8gAAAICOAgAAAICOEgAAAICOIgAAAICOMgAAAICOQgAAAICOUgAAAICOYgAAAICOcgAAAICOggAAAICOkgAAAICOogAAAICOsgAAAICOwgAAAICO0gAAAICO4gAAAICO8gAAAICPAgAAAICPEgAAAICPIgAAAICPMgAAAICPQgAAAICPUgAAAICPYgAAAICPcgAAAICPggAAAICPkgAAAICPogAAAICPsgAAAICPwgAAAICP0gAAAICP4gAAAICP8gAAAICAAhAAAICAEhAAAICAIhAAAICAMhAAAICAQhAAAICAUhAAAICAYhAAAICAchAAAICAghAAAICAkhAAAICAohAAAICAshAAAICAwhAAAICA0hAAAICA4hAAAICA8hAAAICBAhAAAICBEhAAAICBIhAAAICBMhAAAICBQhAAAICBUhAAAICBYhAAAICBchAAAICBghAAAICBkhAAAICBohAAAICBshAAAICBwhAAAICB0hAAAICB4hAAAICB8hAAAICCAhAAAICCEhAAAICCIhAAAICCMhAAAICCQhAAAICCUhAAAICCYhAAAICCchAAAICCghAAAICCkhAAAICCohAAAICCshAAAICCwhAAAICC0hAAAICC4hAAAICC8hAAAICDAhAAAICDEhAAAICDIhAAAICDMhAAAICDQhAAAICDUhAAAICDYhAAAICDchAAAICDghAAAICDkhAAAICDohAAAICDshAAAICDwhAAAICD0hAAAICD4hAAAICD8hAAAICEAhAAAICEEhAAAICEIhAAAICEMhAAAICEQhAAAICEUhAAAICEYhAAAICEchAAAICEghAAAICEkhAAAICEohAAAICEshAAAICEwhAAAICE0hAAAICE4hAAAICE8hAAAICFAhAAAICFEhAAAICFIhAAAICFMhAAAICFQhAAAICFUhAAAICFYhAAAICFchAAAICFghAAAICFkhAAAICFohAAAICFshAAAICFwhAAAICF0hAAAICF4hAAAICF8hAAAICGAhAAAICGEhAAAICGIhAAAICGMhAAAICGQhAAAICGUhAAAICGYhAAAICGchAAAICGghAAAICGkhAAAICGohAAAICGshAAAICGwhAAAICG0hAAAICG4hAAAICG8hAAAICHAhAAAICHEhAAAICHIhAAAICHMhAAAICHQhAAAICHUhAAAICHYhAAAICHchAAAICHghAAAICHkhAAAICHohAAAICHshAAAICHwhAAAICH0hAAAICH4hAAAICH8hAAAICIAhAAAICIEhAAAICIIhAAAICIMhAAAICIQhAAAICIUhAAAICIYhAAAICIchAAAICIghAAAICIkhAAAICIohAAAICIshAAAICIwhAAAICI0hAAAICI4hAAAICI8hAAAICJAhAAAICJEhAAAICJIhAAAICJMhAAAICJQhAAAICJUhAAAICJYhAAAICJchAAAICJghAAAICJkhAAAICJohAAAICJshAAAICJwhAAAICJ0hAAAICJ4hAAAICJ8hAAAICKAhAAAICKEhAAAICKIhAAAICKMhAAAICKQhAAAICKUhAAAICKYhAAAICKchAAAICKghAAAICKkhAAAICKohAAAICKshAAAICKwhAAAICK0hAAAICK4hAAAICK8hAAAICLAhAAAICLEhAAAICLIhAAAICLMhAAAICLQhAAAICLUhAAAICLYhAAAICLchAAAICLghAAAICLkhAAAICLohAAAICLshAAAICLwhAAAICL0hAAAICL4hAAAICL8hAAAICMAhAAAICMEhAAAICMIhAAAICMMhAAAICMQhAAAICMUhAAAICMYhAAAICMchAAAICMghAAAICMkhAAAICMohAAAICMshAAAICMwhAAAICM0hAAAICM4hAAAICM8hAAAICNAhAAAICNEhAAAICNIhAAAICNMhAAAICNQhAAAICNUhAAAICNYhAAAICNchAAAICNghAAAICNkhAAAICNohAAAICNshAAAICNwhAAAICN0hAAAICN4hAAAICN8hAAAICOAhAAAICOEhAAAICOIhAAAICOMhAAAICOQhAAAICOUhAAAICOYhAAAICOchAAAICOghAAAICOkhAAAICOohAAAICOshAAAICOwhAAAICO0hAAAICO4hAAAICO8hAAAICPAhAAAICPEhAAAICPIhAAAICPMhAAAICPQhAAAICPUhAAAICPYhAAAICPchAAAICPghAAAICPkhAAAICPohAAAICPshAAAICPwhAAAICP0hAAAICP4hAAAICP8hAAAICAAiAAAICAEiAAAICAIiAAAICAMiAAAICAQiAAAICAUiAAAICAYiAAAICAciAAAICAgiAAAICAkiAAAICAoiAAAICAsiAAAICAwiAAAICA0iAAAICA4iAAAICA8iAAAICBAiAAAICBEiAAAICBIiAAAICBMiAAAICBQiAAAICBUiAAAICBYiAAAICBciAAAICBgiAAAICBkiAAAICBoiAAAICBsiAAAICBwiAAAICB0iAAAICB4iAAAICB8iAAAICCAiAAAICCEiAAAICCIiAAAICCMiAAAICCQiAAAICCUiAAAICCYiAAAICCciAAAICCgiAAAICCkiAAAICCoiAAAICCsiAAAICCwiAAAICC0iAAAICC4iAAAICC8iAAAICDAiAAAICDEiAAAICDIiAAAICDMiAAAICDQiAAAICDUiAAAICDYiAAAICDciAAAICDgiAAAICDkiAAAICDoiAAAICDsiAAAICDwiAAAICD0iAAAICD4iAAAICD8iAAAICEAiAAAICEEiAAAICEIiAAAICEMiAAAICEQiAAAICEUiAAAICEYiAAAICEciAAAICEgiAAAICEkiAAAICEoiAAAICEsiAAAICEwiAAAICE0iAAAICE4iAAAICE8iAAAICFAiAAAICFEiAAAICFIiAAAICFMiAAAICFQiAAAICFUiAAAICFYiAAAICFciAAAICFgiAAAICFkiAAAICFoiAAAICFsiAAAICFwiAAAICF0iAAAICF4iAAAICF8iAAAICGAiAAAICGEiAAAICGIiAAAICGMiAAAICGQiAAAICGUiAAAICGYiAAAICGciAAAICGgiAAAICGkiAAAICGoiAAAICGsiAAAICGwiAAAICG0iAAAICG4iAAAICG8iAAAICHAiAAAICHEiAAAICHIiAAAICHMiAAAICHQiAAAICHUiAAAICHYiAAAICHciAAAICHgiAAAICHkiAAAICHoiAAAICHsiAAAICHwiAAAICH0iAAAICH4iAAAICH8iAAAICIAiAAAICIEiAAAICIIiAAAICIMiAAAICIQiAAAICIUiAAAICIYiAAAICIciAAAICIgiAAAICIkiAAAICIoiAAAICIsiAAAICIwiAAAICI0iAAAICI4iAAAICI8iAAAICJAiAAAICJEiAAAICJIiAAAICJMiAAAICJQiAAAICJUiAAAICJYiAAAICJciAAAICJgiAAAICJkiAAAICJoiAAAICJsiAAAICJwiAAAICJ0iAAAICJ4iAAAICJ8iAAAICKAiAAAICKEiAAAICKIiAAAICKMiAAAICKQiAAAICKUiAAAICKYiAAAICKciAAAICKgiAAAICKkiAAAICKoiAAAICKsiAAAICKwiAAAICK0iAAAICK4iAAAICK8iAAAICLAiAAAICLEiAAAICLIiAAAICLMiAAAICLQiAAAICLUiAAAICLYiAAAICLciAAAICLgiAAAICLkiAAAICLoiAAAICLsiAAAICLwiAAAICL0iAAAICL4iAAAICL8iAAAICMAiAAAICMEiAAAICMIiAAAICMMiAAAICMQiAAAICMUiAAAICMYiAAAICMciAAAICMgiAAAICMkiAAAICMoiAAAICMsiAAAICMwiAAAICM0iAAAICM4iAAAICM8iAAAICNAiAAAICNEiAAAICNIiAAAICNMiAAAICNQiAAAICNUiAAAICNYiAAAICNciAAAICNgiAAAICNkiAAAICNoiAAAICNsiAAAICNwiAAAICN0iAAAICN4iAAAICN8iAAAICOAiAAAICOEiAAAICOIiAAAICOMiAAAICOQiAAAICOUiAAAICOYiAAAICOciAAAICOgiAAAICOkiAAAICOoiAAAICOsiAAAICOwiAAAICO0iAAAICO4iAAAICO8iAAAICPAiAAAICPEiAAAICPIiAAAICPMiAAAICPQiAAAICPUiAAAICPYiAAAICPciAAAICPgiAAAICPkiAAAICPoiAAAICPsiAAAICPwiAAAICP0iAAAICP4iAAAICP8iAAAICAAjAAAICAEjAAAICAIjAAAICAMjAAAICAQjAAAICAUjAAAICAYjAAAICAcjAAAICAgjAAAICAkjAAAICAojAAAICAsjAAAICAwjAAAICA0jAAAICA4jAAAICA8jAAAICBAjAAAICBEjAAAICBIjAAAICBMjAAAICBQjAAAICBUjAAAICBYjAAAICBcjAAAICBgjAAAICBkjAAAICBojAAAICBsjAAAICBwjAAAICB0jAAAICB4jAAAICB8jAAAICCAjAAAICCEjAAAICCIjAAAICCMjAAAICCQjAAAICCUjAAAICCYjAAAICCcjAAAICCgjAAAICCkjAAAICCojAAAICCsjAAAICCwjAAAICC0jAAAICC4jAAAICC8jAAAICDAjAAAICDEjAAAICDIjAAAICDMjAAAICDQjAAAICDUjAAAICDYjAAAICDcjAAAICDgjAAAICDkjAAAICDojAAAICDsjAAAICDwjAAAICD0jAAAICD4jAAAICD8jAAAICEAjAAAICEEjAAAICEIjAAAICEMjAAAICEQjAAAICEUjAAAICEYjAAAICEcjAAAICEgjAAAICEkjAAAICEojAAAICEsjAAAICEwjAAAICE0jAAAICE4jAAAICE8jAAAICFAjAAAICFEjAAAICFIjAAAICFMjAAAICFQjAAAICFUjAAAICFYjAAAICFcjAAAICFgjAAAICFkjAAAICFojAAAICFsjAAAICFwjAAAICF0jAAAICF4jAAAICF8jAAAICGAjAAAICGEjAAAICGIjAAAICGMjAAAICGQjAAAICGUjAAAICGYjAAAICGcjAAAICGgjAAAICGkjAAAICGojAAAICGsjAAAICGwjAAAICG0jAAAICG4jAAAICG8jAAAICHAjAAAICHEjAAAICHIjAAAICHMjAAAICHQjAAAICHUjAAAICHYjAAAICHcjAAAICHgjAAAICHkjAAAICHojAAAICHsjAAAICHwjAAAICH0jAAAICH4jAAAICH8jAAAICIAjAAAICIEjAAAICIIjAAAICIMjAAAICIQjAAAICIUjAAAICIYjAAAICIcjAAAICIgjAAAICIkjAAAICIojAAAICIsjAAAICIwjAAAICI0jAAAICI4jAAAICI8jAAAICJAjAAAICJEjAAAICJIjAAAICJMjAAAICJQjAAAICJUjAAAICJYjAAAICJcjAAAICJgjAAAICJkjAAAICJojAAAICJsjAAAICJwjAAAICJ0jAAAICJ4jAAAICJ8jAAAICKAjAAAICKEjAAAICKIjAAAICKMjAAAICKQjAAAICKUjAAAICKYjAAAICKcjAAAICKgjAAAICKkjAAAICKojAAAICKsjAAAICKwjAAAICK0jAAAICK4jAAAICK8jAAAICLAjAAAICLEjAAAICLIjAAAICLMjAAAICLQjAAAICLUjAAAICLYjAAAICLcjAAAICLgjAAAICLkjAAAICLojAAAICLsjAAAICLwjAAAICL0jAAAICL4jAAAICL8jAAAICMAjAAAICMEjAAAICMIjAAAICMMjAAAICMQjAAAICMUjAAAICMYjAAAICMcjAAAICMgjAAAICMkjAAAICMojAAAICMsjAAAICMwjAAAICM0jAAAICM4jAAAICM8jAAAICNAjAAAICNEjAAAICNIjAAAICNMjAAAICNQjAAAICNUjAAAICNYjAAAICNcjAAAICNgjAAAICNkjAAAICNojAAAICNsjAAAICNwjAAAICN0jAAAICN4jAAAICN8jAAAICOAjAAAICOEjAAAICOIjAAAICOMjAAAICOQjAAAICOUjAAAICOYjAAAICOcjAAAICOgjAAAICOkjAAAICOojAAAICOsjAAAICOwjAAAICO0jAAAICO4jAAAICO8jAAAICPAjAAAICPEjAAAICPIjAAAICPMjAAAICPQjAAAICPUjAAAICPYjAAAICPcjAAAICPgjAAAICPkjAAAICPojAAAICPsjAAAICPwjAAAICP0jAAAICP4jAAAICP8jAAAICAAkAAAICAEkAAAICAIkAAAICAMkAAAICAQkAAAICAUkAAAICAYkAAAICAckAAAICAgkAAAICAkkAAAICAokAAAICAskAAAICAwkAAAICA0kAAAICA4kAAAICA8kAAAICBAkAAAICBEkAAAICBIkAAAICBMkAAAICBQkAAAICBUkAAAICBYkAAAICBckAAAICBgkAAAICBkkAAAICBokAAAICBskAAAICBwkAAAICB0kAAAICB4kAAAICB8kAAAICCAkAAAICCEkAAAICCIkAAAICCMkAAAICCQkAAAICCUkAAAICCYkAAAICCckAAAICCgkAAAICCkkAAAICCokAAAICCskAAAICCwkAAAICC0kAAAICC4kAAAICC8kAAAICDAkAAAICDEkAAAICDIkAAAICDMkAAAICDQkAAAICDUkAAAICDYkAAAICDckAAAICDgkAAAICDkkAAAICDokAAAICDskAAAICDwkAAAICD0kAAAICD4kAAAICD8kAAAICEAkAAAICEEkAAAICEIkAAAICEMkAAAICEQkAAAICEUkAAAICEYkAAAICEckAAAICEgkAAAICEkkAAAICEokAAAICEskAAAICEwkAAAICE0kAAAICE4kAAAICE8kAAAICFAkAAAICFEkAAAICFIkAAAICFMkAAAICFQkAAAICFUkAAAICFYkAAAICFckAAAICFgkAAAICFkkAAAICFokAAAICFskAAAICFwkAAAICF0kAAAICF4kAAAICF8kAAAICGAkAAAICGEkAAAICGIkAAAICGMkAAAICGQkAAAICGUkAAAICGYkAAAICGckAAAICGgkAAAICGkkAAAICGokAAAICGskAAAICGwkAAAICG0kAAAICG4kAAAICG8kAAAICHAkAAAICHEkAAAICHIkAAAICHMkAAAICHQkAAAICHUkAAAICHYkAAAICHckAAAICHgkAAAICHkkAAAICHokAAAICHskAAAICHwkAAAICH0kAAAICH4kAAAICH8kAAAICIAkAAAICIEkAAAICIIkAAAICIMkAAAICIQkAAAICIUkAAAICIYkAAAICIckAAAICIgkAAAICIkkAAAICIokAAAICIskAAAICIwkAAAICI0kAAAICI4kAAAICI8kAAAICJAkAAAICJEkAAAICJIkAAAICJMkAAAICJQkAAAICJUkAAAICJYkAAAICJckAAAICJgkAAAICJkkAAAICJokAAAICJskAAAICJwkAAAICJ0kAAAICJ4kAAAICJ8kAAAICKAkAAAICKEkAAAICKIkAAAICKMkAAAICKQkAAAICKUkAAAICKYkAAAICKckAAAICKgkAAAICKkkAAAICKokAAAICKskAAAICKwkAAAICK0kAAAICK4kAAAICK8kAAAICLAkAAAICLEkAAAICLIkAAAICLMkAAAICLQkAAAICLUkAAAICLYkAAAICLckAAAICLgkAAAICLkkAAAICLokAAAICLskAAAICLwkAAAICL0kAAAICL4kAAAICL8kAAAICMAkAAAICMEkAAAICMIkAAAICMMkAAAICMQkAAAICMUkAAAICMYkAAAICMckAAAICMgkAAAICMkkAAAICMokAAAICMskAAAICMwkAAAICM0kAAAICM4kAAAICM8kAAAICNAkAAAICNEkAAAICNIkAAAICNMkAAAICNQkAAAICNUkAAAICNYkAAAICNckAAAICNgkAAAICNkkAAAICNokAAAICNskAAAICNwkAAAICN0kAAAICN4kAAAICN8kAAAICOAkAAAICOEkAAAICOIkAAAICOMkAAAICOQkAAAICOUkAAAICOYkAAAICOckAAAICOgkAAAICOkkAAAICOokAAAICOskAAAICOwkAAAICO0kAAAICO4kAAAICO8kAAAICPAkAAAICPEkAAAICPIkAAAICPMkAAAICPQkAAAICPUkAAAICPYkAAAICPckAAAICPgkAAAICPkkAAAICPokAAAICPskAAAICPwkAAAICP0kAAAICP4kAAAICP8kAAAICAAlAAAICAElAAAICAIlAAAICAMlAAAICAQlAAAICAUlAAAICAYlAAAICAclAAAICAglAAAICAklAAAICAolAAAICAslAAAICAwlAAAICA0lAAAICA4lAAAICA8lAAAICBAlAAAICBElAAAICBIlAAAICBMlAAAICBQlAAAICBUlAAAICBYlAAAICBclAAAICBglAAAICBklAAAICBolAAAICBslAAAICBwlAAAICB0lAAAICB4lAAAICB8lAAAICCAlAAAICCElAAAICCIlAAAICCMlAAAICCQlAAAICCUlAAAICCYlAAAICCclAAAICCglAAAICCklAAAICColAAAICCslAAAICCwlAAAICC0lAAAICC4lAAAICC8lAAAICDAlAAAICDElAAAICDIlAAAICDMlAAAICDQlAAAICDUlAAAICDYlAAAICDclAAAICDglAAAICDklAAAICDolAAAICDslAAAICDwlAAAICD0lAAAICD4lAAAICD8lAAAICEAlAAAICEElAAAICEIlAAAICEMlAAAICEQlAAAICEUlAAAICEYlAAAICEclAAAICEglAAAICEklAAAICEolAAAICEslAAAICEwlAAAICE0lAAAICE4lAAAICE8lAAAICFAlAAAICFElAAAICFIlAAAICFMlAAAICFQlAAAICFUlAAAICFYlAAAICFclAAAICFglAAAICFklAAAICFolAAAICFslAAAICFwlAAAICF0lAAAICF4lAAAICF8lAAAICGAlAAAICGElAAAICGIlAAAICGMlAAAICGQlAAAICGUlAAAICGYlAAAICGclAAAICGglAAAICGklAAAICGolAAAICGslAAAICGwlAAAICG0lAAAICG4lAAAICG8lAAAICHAlAAAICHElAAAICHIlAAAICHMlAAAICHQlAAAICHUlAAAICHYlAAAICHclAAAICHglAAAICHklAAAICHolAAAICHslAAAICHwlAAAICH0lAAAICH4lAAAICH8lAAAICIAlAAAICIElAAAICIIlAAAICIMlAAAICIQlAAAICIUlAAAICIYlAAAICIclAAAICIglAAAICIklAAAICIolAAAICIslAAAICIwlAAAICI0lAAAICI4lAAAICI8lAAAICJAlAAAICJElAAAICJIlAAAICJMlAAAICJQlAAAICJUlAAAICJYlAAAICJclAAAICJglAAAICJklAAAICJolAAAICJslAAAICJwlAAAICJ0lAAAICJ4lAAAICJ8lAAAICKAlAAAICKElAAAICKIlAAAICKMlAAAICKQlAAAICKUlAAAICKYlAAAICKclAAAICKglAAAICKklAAAICKolAAAICKslAAAICKwlAAAICK0lAAAICK4lAAAICK8lAAAICLAlAAAICLElAAAICLIlAAAICLMlAAAICLQlAAAICLUlAAAICLYlAAAICLclAAAICLglAAAICLklAAAICLolAAAICLslAAAICLwlAAAICL0lAAAICL4lAAAICL8lAAAICMAlAAAICMElAAAICMIlAAAICMMlAAAICMQlAAAICMUlAAAICMYlAAAICMclAAAICMglAAAICMklAAAICMolAAAICMslAAAICMwlAAAICM0lAAAICM4lAAAICM8lAAAICNAlAAAICNElAAAICNIlAAAICNMlAAAICNQlAAAICNUlAAAICNYlAAAICNclAAAICNglAAAICNklAAAICNolAAAICNslAAAICNwlAAAICN0lAAAICN4lAAAICN8lAAAICOAlAAAICOElAAAICOIlAAAICOMlAAAICOQlAAAICOUlAAAICOYlAAAICOclAAAICOglAAAICOklAAAICOolAAAICOslAAAICOwlAAAICO0lAAAICO4lAAAICO8lAAAICPAlAAAICPElAAAICPIlAAAICPMlAAAICPQlAAAICPUlAAAICPYlAAAICPclAAAICPglAAAICPklAAAICPolAAAICPslAAAICPwlAAAICP0lAAAICP4lAAAICP8lAAAICAAmAAAICAEmAAAICAImAAAICAMmAAAICAQmAAAICAUmAAAICAYmAAAICAcmAAAICAgmAAAICAkmAAAICAomAAAICAsmAAAICAwmAAAICA0mAAAICA4mAAAICA8mAAAICBAmAAAICBEmAAAICBImAAAICBMmAAAICBQmAAAICBUmAAAICBYmAAAICBcmAAAICBgmAAAICBkmAAAICBomAAAICBsmAAAICBwmAAAICB0mAAAICB4mAAAICB8mAAAICCAmAAAICCEmAAAICCImAAAICCMmAAAICCQmAAAICCUmAAAICCYmAAAICCcmAAAICCgmAAAICCkmAAAICComAAAICCsmAAAICCwmAAAICC0mAAAICC4mAAAICC8mAAAICDAmAAAICDEmAAAICDImAAAICDMmAAAICDQmAAAICDUmAAAICDYmAAAICDcmAAAICDgmAAAICDkmAAAICDomAAAICDsmAAAICDwmAAAICD0mAAAICD4mAAAICD8mAAAICEAmAAAICEEmAAAICEImAAAICEMmAAAICEQmAAAICEUmAAAICEYmAAAICEcmAAAICEgmAAAICEkmAAAICEomAAAICEsmAAAICEwmAAAICE0mAAAICE4mAAAICE8mAAAICFAmAAAICFEmAAAICFImAAAICFMmAAAICFQmAAAICFUmAAAICFYmAAAICFcmAAAICFgmAAAICFkmAAAICFomAAAICFsmAAAICFwmAAAICF0mAAAICF4mAAAICF8mAAAICGAmAAAICGEmAAAICGImAAAICGMmAAAICGQmAAAICGUmAAAICGYmAAAICGcmAAAICGgmAAAICGkmAAAICGomAAAICGsmAAAICGwmAAAICG0mAAAICG4mAAAICG8mAAAICHAmAAAICHEmAAAICHImAAAICHMmAAAICHQmAAAICHUmAAAICHYmAAAICHcmAAAICHgmAAAICHkmAAAICHomAAAICHsmAAAICHwmAAAICH0mAAAICH4mAAAICH8mAAAICIAmAAAICIEmAAAICIImAAAICIMmAAAICIQmAAAICIUmAAAICIYmAAAICIcmAAAICIgmAAAICIkmAAAICIomAAAICIsmAAAICIwmAAAICI0mAAAICI4mAAAICI8mAAAICJAmAAAICJEmAAAICJImAAAICJMmAAAICJQmAAAICJUmAAAICJYmAAAICJcmAAAICJgmAAAICJkmAAAICJomAAAICJsmAAAICJwmAAAICJ0mAAAICJ4mAAAICJ8mAAAICKAmAAAICKEmAAAICKImAAAICKMmAAAICKQmAAAICKUmAAAICKYmAAAICKcmAAAICKgmAAAICKkmAAAICKomAAAICKsmAAAICKwmAAAICK0mAAAICK4mAAAICK8mAAAICLAmAAAICLEmAAAICLImAAAICLMmAAAICLQmAAAICLUmAAAICLYmAAAICLcmAAAICLgmAAAICLkmAAAICLomAAAICLsmAAAICLwmAAAICL0mAAAICL4mAAAICL8mAAAICMAmAAAICMEmAAAICMImAAAICMMmAAAICMQmAAAICMUmAAAICMYmAAAICMcmAAAICMgmAAAICMkmAAAICMomAAAICMsmAAAICMwmAAAICM0mAAAICM4mAAAICM8mAAAICNAmAAAICNEmAAAICNImAAAICNMmAAAICNQmAAAICNUmAAAICNYmAAAICNcmAAAICNgmAAAICNkmAAAICNomAAAICNsmAAAICNwmAAAICN0mAAAICN4mAAAICN8mAAAICOAmAAAICOEmAAAICOImAAAICOMmAAAICOQmAAAICOUmAAAICOYmAAAICOcmAAAICOgmAAAICOkmAAAICOomAAAICOsmAAAICOwmAAAICO0mAAAICO4mAAAICO8mAAAICPAmAAAICPEmAAAICPImAAAICPMmAAAICPQmAAAICPUmAAAICPYmAAAICPcmAAAICPgmAAAICPkmAAAICPomAAAICPsmAAAICPwmAAAICP0mAAAICP4mAAAICP8mAAAICAAnAAAICAEnAAAICAInAAAICAMnAAAICAQnAAAICAUnAAAICAYnAAAICAcnAAAICAgnAAAICAknAAAICAonAAAICAsnAAAICAwnAAAICA0nAAAICA4nAAAICA8nAAAL", TargetFrameworkMoniker.netfx461) } };
// fewer than 256 nulls
- yield return new object[] { new object[200], new string[] { "AAEAAAD/////AQAAAAAAAAAQAQAAAMgAAAANyAs=", "AAEAAAD/////AQAAAAAAAAAQAQAAAMgAAAANyAs=" } };
+ yield return new object[] { new object[200], new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAQAQAAAMgAAAANyAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAQAQAAAMgAAAANyAs=", TargetFrameworkMoniker.netfx461) } };
// more than 256 nulls
- yield return new object[] { new object[300], new string[] { "AAEAAAD/////AQAAAAAAAAAQAQAAACwBAAAOLAEAAAs=", "AAEAAAD/////AQAAAAAAAAAQAQAAACwBAAAOLAEAAAs=" } };
+ yield return new object[] { new object[300], new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAQAQAAACwBAAAOLAEAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAQAQAAACwBAAAOLAEAAAs=", TargetFrameworkMoniker.netfx461) } };
// Non-vector arrays
if (PlatformDetection.IsNonZeroLowerBoundArraySupported)
{
- yield return new object[] { Array.CreateInstance(typeof(uint), new[] { 5 }, new[] { 1 }), new string[] { "AAEAAAD/////AQAAAAAAAAAHAQAAAAMBAAAABQAAAAEAAAAADwAAAAAAAAAAAAAAAAAAAAAAAAAACw==", "AAEAAAD/////AQAAAAAAAAAHAQAAAAMBAAAABQAAAAEAAAAADwAAAAAAAAAAAAAAAAAAAAAAAAAACw==" } };
+ yield return new object[] { Array.CreateInstance(typeof(uint), new[] { 5 }, new[] { 1 }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAHAQAAAAMBAAAABQAAAAEAAAAADwAAAAAAAAAAAAAAAAAAAAAAAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAHAQAAAAMBAAAABQAAAAEAAAAADwAAAAAAAAAAAAAAAAAAAAAAAAAACw==", TargetFrameworkMoniker.netfx461) } };
}
- // .NET Native bug 445667 causes a crash in reflecting over multidimensional arrays
+ // NET Native bug 445667 causes a crash in reflecting over multidimensional arrays
if (!PlatformDetection.IsNetNative)
{
- yield return new object[] { Array.CreateInstance(typeof(int), new[] { 0, 0, 0 }, new[] { 0, 0, 0 }), new string[] { "AAEAAAD/////AQAAAAAAAAAHAQAAAAIDAAAAAAAAAAAAAAAAAAAAAAgL", "AAEAAAD/////AQAAAAAAAAAHAQAAAAIDAAAAAAAAAAAAAAAAAAAAAAgL" } };
+ yield return new object[] { Array.CreateInstance(typeof(int), new[] { 0, 0, 0 }, new[] { 0, 0, 0 }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAHAQAAAAIDAAAAAAAAAAAAAAAAAAAAAAgL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAHAQAAAAIDAAAAAAAAAAAAAAAAAAAAAAgL", TargetFrameworkMoniker.netfx461) } };
}
if (PlatformDetection.IsNonZeroLowerBoundArraySupported)
{
var arr = Array.CreateInstance(typeof(string), new[] { 1, 2 }, new[] { 3, 4 });
arr.SetValue("hello", new[] { 3, 5 });
- yield return new object[] { arr, new string[] { "AAEAAAD/////AQAAAAAAAAAHAQAAAAUCAAAAAQAAAAIAAAADAAAABAAAAAEKBgIAAAAFaGVsbG8L", "AAEAAAD/////AQAAAAAAAAAHAQAAAAUCAAAAAQAAAAIAAAADAAAABAAAAAEKBgIAAAAFaGVsbG8L" } };
+ yield return new object[] { arr, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAHAQAAAAUCAAAAAQAAAAIAAAADAAAABAAAAAEKBgIAAAAFaGVsbG8L", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAHAQAAAAUCAAAAAQAAAAIAAAADAAAABAAAAAEKBgIAAAAFaGVsbG8L", TargetFrameworkMoniker.netfx461) } };
}
// Globalization types
@@ -1178,23 +1179,23 @@ namespace System.Runtime.Serialization.Formatters.Tests
.GetField("m_SortVersion", BindingFlags.NonPublic | BindingFlags.Instance)
.SetValue(compareInfo, sortVersion);
- yield return new object[] { compareInfo, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwMAAAAGbV9uYW1lDW1fU29ydFZlcnNpb24HY3VsdHVyZQEDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbggGAgAAAAAJAwAAAH8AAAAEAwAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbgIAAAAMbV9ObHNWZXJzaW9uCG1fU29ydElkAAMIC1N5c3RlbS5HdWlkOTAAAAT8////C1N5c3RlbS5HdWlkCwAAAAJfYQJfYgJfYwJfZAJfZQJfZgJfZwJfaAJfaQJfagJfawAAAAAAAAAAAAAACAcHAgICAgICAgK7b6yfg/b1QqWTDUpeNLJXCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwQAAAAGbV9uYW1lCXdpbjMyTENJRAdjdWx0dXJlDW1fU29ydFZlcnNpb24BAAADCAggU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24GAgAAAAAAAAAAfwAAAAkDAAAABAMAAAAgU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24CAAAADG1fTmxzVmVyc2lvbghtX1NvcnRJZAADCAtTeXN0ZW0uR3VpZDkwAAAE/P///wtTeXN0ZW0uR3VpZAsAAAACX2ECX2ICX2MCX2QCX2UCX2YCX2cCX2gCX2kCX2oCX2sAAAAAAAAAAAAAAAgHBwICAgICAgICu2+sn4P29UKlkw1KXjSyVws=" } };
- yield return new object[] { sortVersion, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbgIAAAAMbV9ObHNWZXJzaW9uCG1fU29ydElkAAMIC1N5c3RlbS5HdWlkOTAAAAT+////C1N5c3RlbS5HdWlkCwAAAAJfYQJfYgJfYwJfZAJfZQJfZgJfZwJfaAJfaQJfagJfawAAAAAAAAAAAAAACAcHAgICAgICAgK7b6yfg/b1QqWTDUpeNLJXCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbgIAAAAMbV9ObHNWZXJzaW9uCG1fU29ydElkAAMIC1N5c3RlbS5HdWlkOTAAAAT+////C1N5c3RlbS5HdWlkCwAAAAJfYQJfYgJfYwJfZAJfZQJfZgJfZwJfaAJfaQJfagJfawAAAAAAAAAAAAAACAcHAgICAgICAgK7b6yfg/b1QqWTDUpeNLJXCw==" } };
+ yield return new object[] { compareInfo, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwMAAAAGbV9uYW1lDW1fU29ydFZlcnNpb24HY3VsdHVyZQEDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbggGAgAAAAAJAwAAAH8AAAAEAwAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbgIAAAAMbV9ObHNWZXJzaW9uCG1fU29ydElkAAMIC1N5c3RlbS5HdWlkOTAAAAT8////C1N5c3RlbS5HdWlkCwAAAAJfYQJfYgJfYwJfZAJfZQJfZgJfZwJfaAJfaQJfagJfawAAAAAAAAAAAAAACAcHAgICAgICAgK7b6yfg/b1QqWTDUpeNLJXCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwQAAAAGbV9uYW1lCXdpbjMyTENJRAdjdWx0dXJlDW1fU29ydFZlcnNpb24BAAADCAggU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24GAgAAAAAAAAAAfwAAAAkDAAAABAMAAAAgU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24CAAAADG1fTmxzVmVyc2lvbghtX1NvcnRJZAADCAtTeXN0ZW0uR3VpZDkwAAAE/P///wtTeXN0ZW0uR3VpZAsAAAACX2ECX2ICX2MCX2QCX2UCX2YCX2cCX2gCX2kCX2oCX2sAAAAAAAAAAAAAAAgHBwICAgICAgICu2+sn4P29UKlkw1KXjSyVws=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { sortVersion, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbgIAAAAMbV9ObHNWZXJzaW9uCG1fU29ydElkAAMIC1N5c3RlbS5HdWlkOTAAAAT+////C1N5c3RlbS5HdWlkCwAAAAJfYQJfYgJfYwJfZAJfZQJfZgJfZwJfaAJfaQJfagJfawAAAAAAAAAAAAAACAcHAgICAgICAgK7b6yfg/b1QqWTDUpeNLJXCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbgIAAAAMbV9ObHNWZXJzaW9uCG1fU29ydElkAAMIC1N5c3RlbS5HdWlkOTAAAAT+////C1N5c3RlbS5HdWlkCwAAAAJfYQJfYgJfYwJfZAJfZQJfZgJfZwJfaAJfaQJfagJfawAAAAAAAAAAAAAACAcHAgICAgICAgK7b6yfg/b1QqWTDUpeNLJXCw==", TargetFrameworkMoniker.netfx461) } };
// Drawing types
- yield return new object[] { new System.Drawing.Point(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABRTeXN0ZW0uRHJhd2luZy5Qb2ludAIAAAABeAF5AAAICAIAAAAAAAAAAAAAAAs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABRTeXN0ZW0uRHJhd2luZy5Qb2ludAIAAAABeAF5AAAICAIAAAAAAAAAAAAAAAs=" } };
- yield return new object[] { new System.Drawing.Point(10, 10), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABRTeXN0ZW0uRHJhd2luZy5Qb2ludAIAAAABeAF5AAAICAIAAAAKAAAACgAAAAs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABRTeXN0ZW0uRHJhd2luZy5Qb2ludAIAAAABeAF5AAAICAIAAAAKAAAACgAAAAs=" } };
- yield return new object[] { System.Drawing.Color.FromArgb(255, 100, 55, 255), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABRTeXN0ZW0uRHJhd2luZy5Db2xvcgQAAAAEbmFtZQV2YWx1ZQprbm93bkNvbG9yBXN0YXRlAQAAAAkHBwIAAAAK/zdk/wAAAAAAAAIACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABRTeXN0ZW0uRHJhd2luZy5Db2xvcgQAAAAEbmFtZQV2YWx1ZQprbm93bkNvbG9yBXN0YXRlAQAAAAkHBwIAAAAK/zdk/wAAAAAAAAIACw==" } };
- yield return new object[] { new System.Drawing.PointF(10.5f, 10.25f), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABVTeXN0ZW0uRHJhd2luZy5Qb2ludEYCAAAAAXgBeQAACwsCAAAAAAAoQQAAJEEL", "AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABVTeXN0ZW0uRHJhd2luZy5Qb2ludEYCAAAAAXgBeQAACwsCAAAAAAAoQQAAJEEL" } };
- yield return new object[] { new System.Drawing.Rectangle(10, 10, 100, 50), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABhTeXN0ZW0uRHJhd2luZy5SZWN0YW5nbGUEAAAAAXgBeQV3aWR0aAZoZWlnaHQAAAAACAgICAIAAAAKAAAACgAAAGQAAAAyAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABhTeXN0ZW0uRHJhd2luZy5SZWN0YW5nbGUEAAAAAXgBeQV3aWR0aAZoZWlnaHQAAAAACAgICAIAAAAKAAAACgAAAGQAAAAyAAAACw==" } };
- yield return new object[] { new System.Drawing.RectangleF(10.5f, 10.5f, 52.3f, 69.4f), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABlTeXN0ZW0uRHJhd2luZy5SZWN0YW5nbGVGBAAAAAF4AXkFd2lkdGgGaGVpZ2h0AAAAAAsLCwsCAAAAAAAoQQAAKEEzM1FCzcyKQgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABlTeXN0ZW0uRHJhd2luZy5SZWN0YW5nbGVGBAAAAAF4AXkFd2lkdGgGaGVpZ2h0AAAAAAsLCwsCAAAAAAAoQQAAKEEzM1FCzcyKQgs=" } };
- yield return new object[] { new System.Drawing.Size(10, 45), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABNTeXN0ZW0uRHJhd2luZy5TaXplAgAAAAV3aWR0aAZoZWlnaHQAAAgIAgAAAAoAAAAtAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABNTeXN0ZW0uRHJhd2luZy5TaXplAgAAAAV3aWR0aAZoZWlnaHQAAAgIAgAAAAoAAAAtAAAACw==" } };
- yield return new object[] { new System.Drawing.SizeF(10.2f, 45.8f), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABRTeXN0ZW0uRHJhd2luZy5TaXplRgIAAAAFd2lkdGgGaGVpZ2h0AAALCwIAAAAzMyNBMzM3Qgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABRTeXN0ZW0uRHJhd2luZy5TaXplRgIAAAAFd2lkdGgGaGVpZ2h0AAALCwIAAAAzMyNBMzM3Qgs=" } };
+ yield return new object[] { new System.Drawing.Point(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABRTeXN0ZW0uRHJhd2luZy5Qb2ludAIAAAABeAF5AAAICAIAAAAAAAAAAAAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABRTeXN0ZW0uRHJhd2luZy5Qb2ludAIAAAABeAF5AAAICAIAAAAAAAAAAAAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new System.Drawing.Point(10, 10), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABRTeXN0ZW0uRHJhd2luZy5Qb2ludAIAAAABeAF5AAAICAIAAAAKAAAACgAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABRTeXN0ZW0uRHJhd2luZy5Qb2ludAIAAAABeAF5AAAICAIAAAAKAAAACgAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { System.Drawing.Color.FromArgb(255, 100, 55, 255), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABRTeXN0ZW0uRHJhd2luZy5Db2xvcgQAAAAEbmFtZQV2YWx1ZQprbm93bkNvbG9yBXN0YXRlAQAAAAkHBwIAAAAK/zdk/wAAAAAAAAIACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABRTeXN0ZW0uRHJhd2luZy5Db2xvcgQAAAAEbmFtZQV2YWx1ZQprbm93bkNvbG9yBXN0YXRlAQAAAAkHBwIAAAAK/zdk/wAAAAAAAAIACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new System.Drawing.PointF(10.5f, 10.25f), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABVTeXN0ZW0uRHJhd2luZy5Qb2ludEYCAAAAAXgBeQAACwsCAAAAAAAoQQAAJEEL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABVTeXN0ZW0uRHJhd2luZy5Qb2ludEYCAAAAAXgBeQAACwsCAAAAAAAoQQAAJEEL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new System.Drawing.Rectangle(10, 10, 100, 50), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABhTeXN0ZW0uRHJhd2luZy5SZWN0YW5nbGUEAAAAAXgBeQV3aWR0aAZoZWlnaHQAAAAACAgICAIAAAAKAAAACgAAAGQAAAAyAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABhTeXN0ZW0uRHJhd2luZy5SZWN0YW5nbGUEAAAAAXgBeQV3aWR0aAZoZWlnaHQAAAAACAgICAIAAAAKAAAACgAAAGQAAAAyAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new System.Drawing.RectangleF(10.5f, 10.5f, 52.3f, 69.4f), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABlTeXN0ZW0uRHJhd2luZy5SZWN0YW5nbGVGBAAAAAF4AXkFd2lkdGgGaGVpZ2h0AAAAAAsLCwsCAAAAAAAoQQAAKEEzM1FCzcyKQgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABlTeXN0ZW0uRHJhd2luZy5SZWN0YW5nbGVGBAAAAAF4AXkFd2lkdGgGaGVpZ2h0AAAAAAsLCwsCAAAAAAAoQQAAKEEzM1FCzcyKQgs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new System.Drawing.Size(10, 45), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABNTeXN0ZW0uRHJhd2luZy5TaXplAgAAAAV3aWR0aAZoZWlnaHQAAAgIAgAAAAoAAAAtAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABNTeXN0ZW0uRHJhd2luZy5TaXplAgAAAAV3aWR0aAZoZWlnaHQAAAgIAgAAAAoAAAAtAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new System.Drawing.SizeF(10.2f, 45.8f), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABRTeXN0ZW0uRHJhd2luZy5TaXplRgIAAAAFd2lkdGgGaGVpZ2h0AAALCwIAAAAzMyNBMzM3Qgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFFTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAABRTeXN0ZW0uRHJhd2luZy5TaXplRgIAAAAFd2lkdGgGaGVpZ2h0AAALCwIAAAAzMyNBMzM3Qgs=", TargetFrameworkMoniker.netfx461) } };
// Custom object
var sealedObjectWithIntStringFields = new SealedObjectWithIntStringFields();
- yield return new object[] { sealedObjectWithIntStringFields, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABNU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlNlYWxlZE9iamVjdFdpdGhJbnRTdHJpbmdGaWVsZHMDAAAAB01lbWJlcjEHTWVtYmVyMgdNZW1iZXIzAAEBCAIAAAAAAAAACgoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABNU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlNlYWxlZE9iamVjdFdpdGhJbnRTdHJpbmdGaWVsZHMDAAAAB01lbWJlcjEHTWVtYmVyMgdNZW1iZXIzAAEBCAIAAAAAAAAACgoL" } };
- yield return new object[] { new SealedObjectWithIntStringFields() { Member1 = 42, Member2 = null, Member3 = "84" }, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABNU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlNlYWxlZE9iamVjdFdpdGhJbnRTdHJpbmdGaWVsZHMDAAAAB01lbWJlcjEHTWVtYmVyMgdNZW1iZXIzAAEBCAIAAAAqAAAACgYDAAAAAjg0Cw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABNU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlNlYWxlZE9iamVjdFdpdGhJbnRTdHJpbmdGaWVsZHMDAAAAB01lbWJlcjEHTWVtYmVyMgdNZW1iZXIzAAEBCAIAAAAqAAAACgYDAAAAAjg0Cw==" } };
+ yield return new object[] { sealedObjectWithIntStringFields, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABNU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlNlYWxlZE9iamVjdFdpdGhJbnRTdHJpbmdGaWVsZHMDAAAAB01lbWJlcjEHTWVtYmVyMgdNZW1iZXIzAAEBCAIAAAAAAAAACgoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABNU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlNlYWxlZE9iamVjdFdpdGhJbnRTdHJpbmdGaWVsZHMDAAAAB01lbWJlcjEHTWVtYmVyMgdNZW1iZXIzAAEBCAIAAAAAAAAACgoL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SealedObjectWithIntStringFields() { Member1 = 42, Member2 = null, Member3 = "84" }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABNU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlNlYWxlZE9iamVjdFdpdGhJbnRTdHJpbmdGaWVsZHMDAAAAB01lbWJlcjEHTWVtYmVyMgdNZW1iZXIzAAEBCAIAAAAqAAAACgYDAAAAAjg0Cw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABNU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlNlYWxlZE9iamVjdFdpdGhJbnRTdHJpbmdGaWVsZHMDAAAAB01lbWJlcjEHTWVtYmVyMgdNZW1iZXIzAAEBCAIAAAAqAAAACgYDAAAAAjg0Cw==", TargetFrameworkMoniker.netfx461) } };
// Custom object with fields pointing to the same object
var objectWithIntStringUShortUIntULongAndCustomObjectFields = new ObjectWithIntStringUShortUIntULongAndCustomObjectFields
@@ -1214,41 +1215,41 @@ namespace System.Runtime.Serialization.Formatters.Tests
u32 = uint.MaxValue,
u64 = ulong.MaxValue,
};
- yield return new object[] { objectWithIntStringUShortUIntULongAndCustomObjectFields, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABlU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLk9iamVjdFdpdGhJbnRTdHJpbmdVU2hvcnRVSW50VUxvbmdBbmRDdXN0b21PYmplY3RGaWVsZHMOAAAAB01lbWJlcjEHTWVtYmVyMghfbWVtYmVyMwdNZW1iZXI0DU1lbWJlcjRzaGFyZWQHTWVtYmVyNQdNZW1iZXI2BHN0cjEEc3RyMgRzdHIzBHN0cjQDdTE2A3UzMgN1NjQAAQEEBAQBAQEBAQAAAAhNU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlNlYWxlZE9iamVjdFdpdGhJbnRTdHJpbmdGaWVsZHMCAAAATVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5TZWFsZWRPYmplY3RXaXRoSW50U3RyaW5nRmllbGRzAgAAAE1TeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU2VhbGVkT2JqZWN0V2l0aEludFN0cmluZ0ZpZWxkcwIAAAAODxACAAAACgAAAAYDAAAABWhlbGxvCQMAAAAJBAAAAAkEAAAACQUAAAAGBgAAAAtIZWxsbyBXb3JsZAYHAAAADWhlbGxvIDwgd29ybGQGCAAAAAE8BgkAAAAHPCB3b3JsZAkHAAAA//////////////////8FBAAAAE1TeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU2VhbGVkT2JqZWN0V2l0aEludFN0cmluZ0ZpZWxkcwMAAAAHTWVtYmVyMQdNZW1iZXIyB01lbWJlcjMAAQEIAgAAAAAAAAAKCgEFAAAABAAAAAAAAAAKCgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABlU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLk9iamVjdFdpdGhJbnRTdHJpbmdVU2hvcnRVSW50VUxvbmdBbmRDdXN0b21PYmplY3RGaWVsZHMOAAAAB01lbWJlcjEHTWVtYmVyMghfbWVtYmVyMwdNZW1iZXI0DU1lbWJlcjRzaGFyZWQHTWVtYmVyNQdNZW1iZXI2BHN0cjEEc3RyMgRzdHIzBHN0cjQDdTE2A3UzMgN1NjQAAQEEBAQBAQEBAQAAAAhNU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlNlYWxlZE9iamVjdFdpdGhJbnRTdHJpbmdGaWVsZHMCAAAATVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5TZWFsZWRPYmplY3RXaXRoSW50U3RyaW5nRmllbGRzAgAAAE1TeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU2VhbGVkT2JqZWN0V2l0aEludFN0cmluZ0ZpZWxkcwIAAAAODxACAAAACgAAAAYDAAAABWhlbGxvCQMAAAAJBAAAAAkEAAAACQUAAAAGBgAAAAtIZWxsbyBXb3JsZAYHAAAADWhlbGxvIDwgd29ybGQGCAAAAAE8BgkAAAAHPCB3b3JsZAkHAAAA//////////////////8FBAAAAE1TeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU2VhbGVkT2JqZWN0V2l0aEludFN0cmluZ0ZpZWxkcwMAAAAHTWVtYmVyMQdNZW1iZXIyB01lbWJlcjMAAQEIAgAAAAAAAAAKCgEFAAAABAAAAAAAAAAKCgs=" } };
+ yield return new object[] { objectWithIntStringUShortUIntULongAndCustomObjectFields, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABlU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLk9iamVjdFdpdGhJbnRTdHJpbmdVU2hvcnRVSW50VUxvbmdBbmRDdXN0b21PYmplY3RGaWVsZHMOAAAAB01lbWJlcjEHTWVtYmVyMghfbWVtYmVyMwdNZW1iZXI0DU1lbWJlcjRzaGFyZWQHTWVtYmVyNQdNZW1iZXI2BHN0cjEEc3RyMgRzdHIzBHN0cjQDdTE2A3UzMgN1NjQAAQEEBAQBAQEBAQAAAAhNU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlNlYWxlZE9iamVjdFdpdGhJbnRTdHJpbmdGaWVsZHMCAAAATVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5TZWFsZWRPYmplY3RXaXRoSW50U3RyaW5nRmllbGRzAgAAAE1TeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU2VhbGVkT2JqZWN0V2l0aEludFN0cmluZ0ZpZWxkcwIAAAAODxACAAAACgAAAAYDAAAABWhlbGxvCQMAAAAJBAAAAAkEAAAACQUAAAAGBgAAAAtIZWxsbyBXb3JsZAYHAAAADWhlbGxvIDwgd29ybGQGCAAAAAE8BgkAAAAHPCB3b3JsZAkHAAAA//////////////////8FBAAAAE1TeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU2VhbGVkT2JqZWN0V2l0aEludFN0cmluZ0ZpZWxkcwMAAAAHTWVtYmVyMQdNZW1iZXIyB01lbWJlcjMAAQEIAgAAAAAAAAAKCgEFAAAABAAAAAAAAAAKCgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABlU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLk9iamVjdFdpdGhJbnRTdHJpbmdVU2hvcnRVSW50VUxvbmdBbmRDdXN0b21PYmplY3RGaWVsZHMOAAAAB01lbWJlcjEHTWVtYmVyMghfbWVtYmVyMwdNZW1iZXI0DU1lbWJlcjRzaGFyZWQHTWVtYmVyNQdNZW1iZXI2BHN0cjEEc3RyMgRzdHIzBHN0cjQDdTE2A3UzMgN1NjQAAQEEBAQBAQEBAQAAAAhNU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlNlYWxlZE9iamVjdFdpdGhJbnRTdHJpbmdGaWVsZHMCAAAATVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5TZWFsZWRPYmplY3RXaXRoSW50U3RyaW5nRmllbGRzAgAAAE1TeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU2VhbGVkT2JqZWN0V2l0aEludFN0cmluZ0ZpZWxkcwIAAAAODxACAAAACgAAAAYDAAAABWhlbGxvCQMAAAAJBAAAAAkEAAAACQUAAAAGBgAAAAtIZWxsbyBXb3JsZAYHAAAADWhlbGxvIDwgd29ybGQGCAAAAAE8BgkAAAAHPCB3b3JsZAkHAAAA//////////////////8FBAAAAE1TeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU2VhbGVkT2JqZWN0V2l0aEludFN0cmluZ0ZpZWxkcwMAAAAHTWVtYmVyMQdNZW1iZXIyB01lbWJlcjMAAQEIAgAAAAAAAAAKCgEFAAAABAAAAAAAAAAKCgs=", TargetFrameworkMoniker.netfx461) } };
// Simple type without a default ctor
var point = new Point(1, 2);
- yield return new object[] { point, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIAgAAAAEAAAACAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIAgAAAAEAAAACAAAACw==" } };
+ yield return new object[] { point, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIAgAAAAEAAAACAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIAgAAAAEAAAACAAAACw==", TargetFrameworkMoniker.netfx461) } };
// Collections
- yield return new object[] { new System.Collections.BitArray(5, true), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ29sbGVjdGlvbnMuQml0QXJyYXkDAAAAB21fYXJyYXkIbV9sZW5ndGgIX3ZlcnNpb24HAAAICAgJAgAAAAUAAAAAAAAADwIAAAABAAAACP////8L", "AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ29sbGVjdGlvbnMuQml0QXJyYXkDAAAAB21fYXJyYXkIbV9sZW5ndGgIX3ZlcnNpb24HAAAICAgJAgAAAAUAAAAAAAAADwIAAAABAAAACP////8L" } };
- yield return new object[] { new System.Collections.ArrayList(Enumerable.Range(1, 40).ToList()), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAKAAAAAEAAAAQAgAAACgAAAAICAEAAAAICAIAAAAICAMAAAAICAQAAAAICAUAAAAICAYAAAAICAcAAAAICAgAAAAICAkAAAAICAoAAAAICAsAAAAICAwAAAAICA0AAAAICA4AAAAICA8AAAAICBAAAAAICBEAAAAICBIAAAAICBMAAAAICBQAAAAICBUAAAAICBYAAAAICBcAAAAICBgAAAAICBkAAAAICBoAAAAICBsAAAAICBwAAAAICB0AAAAICB4AAAAICB8AAAAICCAAAAAICCEAAAAICCIAAAAICCMAAAAICCQAAAAICCUAAAAICCYAAAAICCcAAAAICCgAAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAKAAAAAEAAAAQAgAAACgAAAAICAEAAAAICAIAAAAICAMAAAAICAQAAAAICAUAAAAICAYAAAAICAcAAAAICAgAAAAICAkAAAAICAoAAAAICAsAAAAICAwAAAAICA0AAAAICA4AAAAICA8AAAAICBAAAAAICBEAAAAICBIAAAAICBMAAAAICBQAAAAICBUAAAAICBYAAAAICBcAAAAICBgAAAAICBkAAAAICBoAAAAICBsAAAAICBwAAAAICB0AAAAICB4AAAAICB8AAAAICCAAAAAICCEAAAAICCIAAAAICCMAAAAICCQAAAAICCUAAAAICCYAAAAICCcAAAAICCgAAAAL" } };
- yield return new object[] { new System.Collections.ArrayList(10), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAAAAAAAAAAAAQAgAAAAoAAAANCgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAAAAAAAAAAAAQAgAAAAoAAAANCgs=" } };
- yield return new object[] { new System.Collections.Comparer(new CultureInfo("")), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXIBAAAAC0NvbXBhcmVJbmZvAyBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwkCAAAABAIAAAAgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8DAAAABm1fbmFtZQ1tX1NvcnRWZXJzaW9uB2N1bHR1cmUBAwAgU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24IBgMAAAAACn8AAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXIBAAAAC0NvbXBhcmVJbmZvAyBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwkCAAAABAIAAAAgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8EAAAABm1fbmFtZQl3aW4zMkxDSUQHY3VsdHVyZQ1tX1NvcnRWZXJzaW9uAQAAAwgIIFN5c3RlbS5HbG9iYWxpemF0aW9uLlNvcnRWZXJzaW9uBgMAAAAAAAAAAH8AAAAKCw==" } };
- yield return new object[] { new System.Collections.DictionaryEntry("key", 5), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uQ29sbGVjdGlvbnMuRGljdGlvbmFyeUVudHJ5AgAAAARfa2V5Bl92YWx1ZQICBgIAAAADa2V5CAgFAAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uQ29sbGVjdGlvbnMuRGljdGlvbmFyeUVudHJ5AgAAAARfa2V5Bl92YWx1ZQICBgIAAAADa2V5CAgFAAAACw==" } };
- yield return new object[] { Comparer<int>.Default, new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==" } };
- yield return new object[] { new HashSet<Point>(new[] { point }, new PointEqualityComparer()), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkMAwAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAADNAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkhhc2hTZXRgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0EAAAAB1ZlcnNpb24IQ29tcGFyZXIIQ2FwYWNpdHkIRWxlbWVudHMABAAECENTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRFcXVhbGl0eUNvbXBhcmVyAwAAAAg1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10DAAAAAgAAAAEAAAAJBAAAAAMAAAAJBQAAAAUEAAAAQ1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludEVxdWFsaXR5Q29tcGFyZXIAAAAAAwAAAAcFAAAAAAEAAAABAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQDAAAACQYAAAAFBgAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgDAAAAAQAAAAIAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkMAwAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAADNAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkhhc2hTZXRgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0EAAAAB1ZlcnNpb24IQ29tcGFyZXIIQ2FwYWNpdHkIRWxlbWVudHMABAAECENTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRFcXVhbGl0eUNvbXBhcmVyAwAAAAg1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10DAAAAAgAAAAEAAAAJBAAAAAMAAAAJBQAAAAUEAAAAQ1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludEVxdWFsaXR5Q29tcGFyZXIAAAAAAwAAAAcFAAAAAAEAAAABAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQDAAAACQYAAAAFBgAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgDAAAAAQAAAAIAAAAL" } };
- yield return new object[] { new KeyValuePair<int, string>(5, "five"), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAOMBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAAA2tleQV2YWx1ZQABCAUAAAAGAgAAAARmaXZlCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAOMBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAAA2tleQV2YWx1ZQABCAUAAAAGAgAAAARmaXZlCw==" } };
- yield return new object[] { new LinkedList<Point>(new[] { point }), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAA0AFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaW5rZWRMaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAwAAAAdWZXJzaW9uBUNvdW50BERhdGEAAAQICDVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQMAAAACAAAAAQAAAAEAAAAJBAAAAAcEAAAAAAEAAAABAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQDAAAACQUAAAAFBQAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgDAAAAAQAAAAIAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAA0AFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaW5rZWRMaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAwAAAAdWZXJzaW9uBUNvdW50BERhdGEAAAQICDVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQMAAAACAAAAAQAAAAEAAAAJBAAAAAcEAAAAAAEAAAABAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQDAAAACQUAAAAFBQAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgDAAAAAQAAAAIAAAAL" } };
- yield return new object[] { new Queue<int>(Enumerable.Range(1, 25)), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAB/U3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuUXVldWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQUAAAAGX2FycmF5BV9oZWFkBV90YWlsBV9zaXplCF92ZXJzaW9uBwAAAAAICAgICAIAAAAJAwAAAAAAAAAZAAAAGQAAAAAAAAAPAwAAACAAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAASAAAAEwAAABQAAAAVAAAAFgAAABcAAAAYAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAB/U3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuUXVldWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQUAAAAGX2FycmF5BV9oZWFkBV90YWlsBV9zaXplCF92ZXJzaW9uBwAAAAAICAgICAIAAAAJAwAAAAAAAAAZAAAAGQAAABwAAAAPAwAAACAAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAASAAAAEwAAABQAAAAVAAAAFgAAABcAAAAYAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL" } };
- yield return new object[] { new Collections.Queue(50, 5.6f), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAAAAAAwAgAAAAAAABACAAAAMgAAAA0yCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAAAAAAwAgAAAAAAABACAAAAMgAAAA0yCw==" } };
- yield return new object[] { new SortedDictionary<int, Point>(pointDictionary, Comparer<int>.Default), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACyAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQEAAAAEX3NldASjA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlRyZWVTZXRgMVtbU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAIAAAAJAwAAAAwEAAAAVVN5c3RlbS5Db2xsZWN0aW9ucywgVmVyc2lvbj00LjEuMS4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAwAAAKMDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuVHJlZVNldGAxW1tTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0EAAAABUNvdW50CENvbXBhcmVyB1ZlcnNpb24FSXRlbXMABAADCMcCU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuU29ydGVkRGljdGlvbmFyeWAyK0tleVZhbHVlUGFpckNvbXBhcmVyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dBAAAAAiwAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dW10CAAAAAgAAAAkFAAAAAgAAAAkGAAAABQUAAADHAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMitLZXlWYWx1ZVBhaXJDb21wYXJlcltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQEAAAALa2V5Q29tcGFyZXIDiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAJBwAAAAcGAAAAAAEAAAACAAAAA64CU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0MCQAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBPj///+uAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAANrZXkFdmFsdWUABAgzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50CQAAAAEAAAAJCgAAAAH1////+P///wIAAAAJDAAAAAQHAAAAiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAFCgAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgJAAAAAQAAAAEAAAABDAAAAAoAAAACAAAAAgAAAAs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACyAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQEAAAAEX3NldASjA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlRyZWVTZXRgMVtbU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAIAAAAJAwAAAAUDAAAAowNTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5UcmVlU2V0YDFbW1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgVJdGVtcwAEAAMIxwJTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWREaWN0aW9uYXJ5YDIrS2V5VmFsdWVQYWlyQ29tcGFyZXJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAACLACU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV1bXQIAAAACAAAACQQAAAACAAAACQUAAAAFBAAAAMcCU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuU29ydGVkRGljdGlvbmFyeWAyK0tleVZhbHVlUGFpckNvbXBhcmVyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAQAAAAtrZXlDb21wYXJlcgOJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAkGAAAABwUAAAAAAQAAAAIAAAADrgJTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQwIAAAAcFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWIE+f///64CU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAA2tleQV2YWx1ZQAECDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQIAAAAAQAAAAkJAAAAAfb////5////AgAAAAkLAAAABAYAAACJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAUJAAAAM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAIAAAABWAFZAAAICAgAAAABAAAAAQAAAAELAAAACQAAAAIAAAACAAAACw==" } };
- yield return new object[] { new SortedList<int, Point>(pointDictionary, Comparer<int>.Default), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgwEAAAAVVN5c3RlbS5Db2xsZWN0aW9ucywgVmVyc2lvbj00LjEuMS4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAAKwCU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuU29ydGVkTGlzdGAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dBwAAAARrZXlzBnZhbHVlcwVfc2l6ZQd2ZXJzaW9uCGNvbXBhcmVyB2tleUxpc3QJdmFsdWVMaXN0BwQAAAMEBAg1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10DAAAACAiJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dtAJTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWRMaXN0YDIrS2V5TGlzdFtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQQAAAC2AlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZExpc3RgMitWYWx1ZUxpc3RbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0EAAAAAgAAAAkFAAAACQYAAAACAAAAAAAAAAkHAAAACgoPBQAAAAIAAAAIAQAAAAIAAAAHBgAAAAABAAAAAgAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AwAAAAkIAAAACQkAAAAEBwAAAIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAABQgAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIAwAAAAEAAAABAAAAAQkAAAAIAAAAAgAAAAIAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAArAJTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWRMaXN0YDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0HAAAABGtleXMGdmFsdWVzBV9zaXplB3ZlcnNpb24IY29tcGFyZXIHa2V5TGlzdAl2YWx1ZUxpc3QHBAAAAwQECDVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQMAAAAICIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV20AlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZExpc3RgMitLZXlMaXN0W1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAALYCU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuU29ydGVkTGlzdGAyK1ZhbHVlTGlzdFtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQIAAAACAAAACQQAAAAJBQAAAAIAAAAAAAAACQYAAAAKCg8EAAAAAgAAAAgBAAAAAgAAAAcFAAAAAAEAAAACAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQDAAAACQcAAAAJCAAAAAQGAAAAiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAFBwAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgDAAAAAQAAAAEAAAABCAAAAAcAAAACAAAAAgAAAAs=" } };
- yield return new object[] { new Collections.SortedList(pointDictionary, Comparer<int>.Default), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdAcAAAAEa2V5cwZ2YWx1ZXMFX3NpemUHdmVyc2lvbghjb21wYXJlcgdrZXlMaXN0CXZhbHVlTGlzdAUFAAADAwMICIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0lU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QrS2V5TGlzdCdTeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdCtWYWx1ZUxpc3QJAgAAAAkDAAAAAgAAAAAAAAAJBAAAAAoKEAIAAAACAAAACAgBAAAACAgCAAAAEAMAAAACAAAACQUAAAAJBgAAAAQEAAAAiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAMBwAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQUAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIBwAAAAEAAAABAAAAAQYAAAAFAAAAAgAAAAIAAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdAcAAAAEa2V5cwZ2YWx1ZXMFX3NpemUHdmVyc2lvbghjb21wYXJlcgdrZXlMaXN0CXZhbHVlTGlzdAUFAAADAwMICIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0lU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QrS2V5TGlzdCdTeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdCtWYWx1ZUxpc3QJAgAAAAkDAAAAAgAAAAAAAAAJBAAAAAoKEAIAAAACAAAACAgBAAAACAgCAAAAEAMAAAACAAAACQUAAAAJBgAAAAQEAAAAiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAMBwAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQUAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIBwAAAAEAAAABAAAAAQYAAAAFAAAAAgAAAAIAAAAL" } };
- yield return new object[] { new SortedSet<Point>(new[] { point, new Point(3, 5) }), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAAzwFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWRTZXRgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0EAAAABUNvdW50CENvbXBhcmVyB1ZlcnNpb24FSXRlbXMAAwAECNUBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCDVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQMAAAACAAAAAQAAAAkEAAAAAAAAAAkFAAAABAQAAADVAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQAAAAAHBQAAAAABAAAAAQAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AwAAAAkGAAAABQYAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIAwAAAAEAAAACAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAAzwFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWRTZXRgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0EAAAABUNvdW50CENvbXBhcmVyB1ZlcnNpb24FSXRlbXMAAwAECNUBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCDVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQMAAAACAAAAAQAAAAkEAAAAAAAAAAkFAAAABAQAAADVAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQAAAAAHBQAAAAABAAAAAQAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AwAAAAkGAAAABQYAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIAwAAAAEAAAACAAAACw==" } };
- yield return new object[] { new SortedSet<int?>(new int?[] { 2, 4, 6, null }, Comparer<int?>.Default), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADlAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uTnVsbGFibGVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0EAAAABUNvdW50CENvbXBhcmVyB1ZlcnNpb24FSXRlbXMAAwADCIoBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTnVsbGFibGVDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCHBTeXN0ZW0uTnVsbGFibGVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXVtdAgAAAAQAAAAJAwAAAAAAAAAJBAAAAAQDAAAAigFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5OdWxsYWJsZUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAABwQAAAAAAQAAAAQAAAADblN5c3RlbS5OdWxsYWJsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCggIAgAAAAgIBAAAAAgIBgAAAAs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADlAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uTnVsbGFibGVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0EAAAABUNvdW50CENvbXBhcmVyB1ZlcnNpb24FSXRlbXMAAwADCIoBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTnVsbGFibGVDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCHBTeXN0ZW0uTnVsbGFibGVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXVtdAgAAAAQAAAAJAwAAAAAAAAAJBAAAAAQDAAAAigFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5OdWxsYWJsZUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAABwQAAAAAAQAAAAQAAAADblN5c3RlbS5OdWxsYWJsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCggIAgAAAAgIBAAAAAgIBgAAAAs=" } };
- yield return new object[] { new Stack<Point>(new[] { point, new Point(2, 2) }), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAAywFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5TdGFja2AxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAGX2FycmF5BV9zaXplCF92ZXJzaW9uBAAANVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludFtdAwAAAAgIAgAAAAkEAAAAAgAAAAAAAAAHBAAAAAABAAAAAgAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AwAAAAkFAAAACQYAAAAFBQAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgDAAAAAQAAAAIAAAABBgAAAAUAAAACAAAAAgAAAAs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAAywFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5TdGFja2AxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAGX2FycmF5BV9zaXplCF92ZXJzaW9uBAAANVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludFtdAwAAAAgIAgAAAAkEAAAAAgAAAAAAAAAHBAAAAAABAAAAAgAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AwAAAAkFAAAACQYAAAAFBQAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgDAAAAAQAAAAIAAAABBgAAAAUAAAACAAAAAgAAAAs=" } };
- yield return new object[] { new System.Collections.Hashtable(255), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBwAAAApMb2FkRmFjdG9yB1ZlcnNpb24IQ29tcGFyZXIQSGFzaENvZGVQcm92aWRlcghIYXNoU2l6ZQRLZXlzBlZhbHVlcwAAAwMABQULCBxTeXN0ZW0uQ29sbGVjdGlvbnMuSUNvbXBhcmVyJFN5c3RlbS5Db2xsZWN0aW9ucy5JSGFzaENvZGVQcm92aWRlcgjsUTg/AAAAAAoKrwEAAAkCAAAACQMAAAAQAgAAAAAAAAAQAwAAAAAAAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBwAAAApMb2FkRmFjdG9yB1ZlcnNpb24IQ29tcGFyZXIQSGFzaENvZGVQcm92aWRlcghIYXNoU2l6ZQRLZXlzBlZhbHVlcwAAAwMABQULCBxTeXN0ZW0uQ29sbGVjdGlvbnMuSUNvbXBhcmVyJFN5c3RlbS5Db2xsZWN0aW9ucy5JSGFzaENvZGVQcm92aWRlcgjsUTg/AAAAAAoKrwEAAAkCAAAACQMAAAAQAgAAAAAAAAAQAwAAAAAAAAAL" } };
- yield return new object[] { new System.Collections.Hashtable(pointDictionary, 0.3f, EqualityComparer<int>.Default), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgcL10+AgAAAAkCAAAACwAAAAkDAAAACQQAAAAEAgAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAQAwAAAAIAAAAICAIAAAAICAEAAAAQBAAAAAIAAAAJBQAAAAkGAAAADAcAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUFAAAAM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAIAAAABWAFZAAAICAcAAAACAAAAAgAAAAEGAAAABQAAAAEAAAABAAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgcL10+AgAAAAkCAAAACwAAAAkDAAAACQQAAAAEAgAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAQAwAAAAIAAAAICAIAAAAICAEAAAAQBAAAAAIAAAAJBQAAAAkGAAAADAcAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUFAAAAM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAIAAAABWAFZAAAICAcAAAACAAAAAgAAAAEGAAAABQAAAAEAAAABAAAACw==" } };
- yield return new object[] { new System.ComponentModel.BindingList<int>(new[] { 34, 52 }), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACAAVN5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAlhZGROZXdQb3MWcmFpc2VMaXN0Q2hhbmdlZEV2ZW50cxZyYWlzZUl0ZW1DaGFuZ2VkRXZlbnRzCGFsbG93TmV3CWFsbG93RWRpdAthbGxvd1JlbW92ZQ91c2VyU2V0QWxsb3dOZXcSQ29sbGVjdGlvbmAxK2l0ZW1zAAAAAAAAAAMIAQEBAQEBDlN5c3RlbS5JbnQzMltdAgAAAP////8BAAEBAQAJAwAAAA8DAAAAAgAAAAgiAAAANAAAAAs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACAAVN5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAlhZGROZXdQb3MWcmFpc2VMaXN0Q2hhbmdlZEV2ZW50cxZyYWlzZUl0ZW1DaGFuZ2VkRXZlbnRzCGFsbG93TmV3CWFsbG93RWRpdAthbGxvd1JlbW92ZQ91c2VyU2V0QWxsb3dOZXcSQ29sbGVjdGlvbmAxK2l0ZW1zAAAAAAAAAAMIAQEBAQEBDlN5c3RlbS5JbnQzMltdAgAAAP////8BAAEBAQAJAwAAAA8DAAAAAgAAAAgiAAAANAAAAAs=" } };
- yield return new object[] { new System.ComponentModel.BindingList<Point>(new[] { point }), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAAzAFTeXN0ZW0uQ29tcG9uZW50TW9kZWwuQmluZGluZ0xpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0IAAAACWFkZE5ld1BvcxZyYWlzZUxpc3RDaGFuZ2VkRXZlbnRzFnJhaXNlSXRlbUNoYW5nZWRFdmVudHMIYWxsb3dOZXcJYWxsb3dFZGl0C2FsbG93UmVtb3ZlD3VzZXJTZXRBbGxvd05ldxJDb2xsZWN0aW9uYDEraXRlbXMAAAAAAAAABAgBAQEBAQE1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10DAAAAAgAAAP////8BAAABAQAJBAAAAAcEAAAAAAEAAAABAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQDAAAACQUAAAAFBQAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgDAAAAAQAAAAIAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAAzAFTeXN0ZW0uQ29tcG9uZW50TW9kZWwuQmluZGluZ0xpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0IAAAACWFkZE5ld1BvcxZyYWlzZUxpc3RDaGFuZ2VkRXZlbnRzFnJhaXNlSXRlbUNoYW5nZWRFdmVudHMIYWxsb3dOZXcJYWxsb3dFZGl0C2FsbG93UmVtb3ZlD3VzZXJTZXRBbGxvd05ldxJDb2xsZWN0aW9uYDEraXRlbXMAAAAAAAAABAgBAQEBAQE1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10DAAAAAgAAAP////8BAAABAQAJBAAAAAcEAAAAAAEAAAABAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQDAAAACQUAAAAFBQAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgDAAAAAQAAAAIAAAAL" } };
- yield return new object[] { new Collections.Stack(new[] { point }), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuU3RhY2sDAAAABl9hcnJheQVfc2l6ZQhfdmVyc2lvbgUAAAgICQIAAAABAAAAAQAAABACAAAACgAAAAkDAAAADQkMBAAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQMAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIBAAAAAEAAAACAAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuU3RhY2sDAAAABl9hcnJheQVfc2l6ZQhfdmVyc2lvbgUAAAgICQIAAAABAAAAAQAAABACAAAACgAAAAkDAAAADQkMBAAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQMAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIBAAAAAEAAAACAAAACw==" } };
+ yield return new object[] { new System.Collections.BitArray(5, true), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ29sbGVjdGlvbnMuQml0QXJyYXkDAAAAB21fYXJyYXkIbV9sZW5ndGgIX3ZlcnNpb24HAAAICAgJAgAAAAUAAAAAAAAADwIAAAABAAAACP////8L", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ29sbGVjdGlvbnMuQml0QXJyYXkDAAAAB21fYXJyYXkIbV9sZW5ndGgIX3ZlcnNpb24HAAAICAgJAgAAAAUAAAAAAAAADwIAAAABAAAACP////8L", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new System.Collections.ArrayList(Enumerable.Range(1, 40).ToList()), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAKAAAAAEAAAAQAgAAACgAAAAICAEAAAAICAIAAAAICAMAAAAICAQAAAAICAUAAAAICAYAAAAICAcAAAAICAgAAAAICAkAAAAICAoAAAAICAsAAAAICAwAAAAICA0AAAAICA4AAAAICA8AAAAICBAAAAAICBEAAAAICBIAAAAICBMAAAAICBQAAAAICBUAAAAICBYAAAAICBcAAAAICBgAAAAICBkAAAAICBoAAAAICBsAAAAICBwAAAAICB0AAAAICB4AAAAICB8AAAAICCAAAAAICCEAAAAICCIAAAAICCMAAAAICCQAAAAICCUAAAAICCYAAAAICCcAAAAICCgAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAKAAAAAEAAAAQAgAAACgAAAAICAEAAAAICAIAAAAICAMAAAAICAQAAAAICAUAAAAICAYAAAAICAcAAAAICAgAAAAICAkAAAAICAoAAAAICAsAAAAICAwAAAAICA0AAAAICA4AAAAICA8AAAAICBAAAAAICBEAAAAICBIAAAAICBMAAAAICBQAAAAICBUAAAAICBYAAAAICBcAAAAICBgAAAAICBkAAAAICBoAAAAICBsAAAAICBwAAAAICB0AAAAICB4AAAAICB8AAAAICCAAAAAICCEAAAAICCIAAAAICCMAAAAICCQAAAAICCUAAAAICCYAAAAICCcAAAAICCgAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new System.Collections.ArrayList(10), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAAAAAAAAAAAAQAgAAAAoAAAANCgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkCAAAAAAAAAAAAAAAQAgAAAAoAAAANCgs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new System.Collections.Comparer(new CultureInfo("")), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXIBAAAAC0NvbXBhcmVJbmZvAyBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwkCAAAABAIAAAAgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8DAAAABm1fbmFtZQ1tX1NvcnRWZXJzaW9uB2N1bHR1cmUBAwAgU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24IBgMAAAAACn8AAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABtTeXN0ZW0uQ29sbGVjdGlvbnMuQ29tcGFyZXIBAAAAC0NvbXBhcmVJbmZvAyBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwkCAAAABAIAAAAgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8EAAAABm1fbmFtZQl3aW4zMkxDSUQHY3VsdHVyZQ1tX1NvcnRWZXJzaW9uAQAAAwgIIFN5c3RlbS5HbG9iYWxpemF0aW9uLlNvcnRWZXJzaW9uBgMAAAAAAAAAAH8AAAAKCw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new System.Collections.DictionaryEntry("key", 5), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uQ29sbGVjdGlvbnMuRGljdGlvbmFyeUVudHJ5AgAAAARfa2V5Bl92YWx1ZQICBgIAAAADa2V5CAgFAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACJTeXN0ZW0uQ29sbGVjdGlvbnMuRGljdGlvbmFyeUVudHJ5AgAAAARfa2V5Bl92YWx1ZQICBgIAAAADa2V5CAgFAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { Comparer<int>.Default, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new HashSet<Point>(new[] { point }, new PointEqualityComparer()), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkMAwAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAADNAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkhhc2hTZXRgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0EAAAAB1ZlcnNpb24IQ29tcGFyZXIIQ2FwYWNpdHkIRWxlbWVudHMABAAECENTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRFcXVhbGl0eUNvbXBhcmVyAwAAAAg1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10DAAAAAgAAAAEAAAAJBAAAAAMAAAAJBQAAAAUEAAAAQ1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludEVxdWFsaXR5Q29tcGFyZXIAAAAAAwAAAAcFAAAAAAEAAAABAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQDAAAACQYAAAAFBgAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgDAAAAAQAAAAIAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5TeXN0ZW0uQ29yZSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkMAwAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAADNAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkhhc2hTZXRgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0EAAAAB1ZlcnNpb24IQ29tcGFyZXIIQ2FwYWNpdHkIRWxlbWVudHMABAAECENTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRFcXVhbGl0eUNvbXBhcmVyAwAAAAg1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10DAAAAAgAAAAEAAAAJBAAAAAMAAAAJBQAAAAUEAAAAQ1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludEVxdWFsaXR5Q29tcGFyZXIAAAAAAwAAAAcFAAAAAAEAAAABAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQDAAAACQYAAAAFBgAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgDAAAAAQAAAAIAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new KeyValuePair<int, string>(5, "five"), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOMBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAAA2tleQV2YWx1ZQABCAUAAAAGAgAAAARmaXZlCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOMBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAAA2tleQV2YWx1ZQABCAUAAAAGAgAAAARmaXZlCw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new LinkedList<Point>(new[] { point }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAA0AFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaW5rZWRMaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAwAAAAdWZXJzaW9uBUNvdW50BERhdGEAAAQICDVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQMAAAACAAAAAQAAAAEAAAAJBAAAAAcEAAAAAAEAAAABAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQDAAAACQUAAAAFBQAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgDAAAAAQAAAAIAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAA0AFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaW5rZWRMaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAwAAAAdWZXJzaW9uBUNvdW50BERhdGEAAAQICDVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQMAAAACAAAAAQAAAAEAAAAJBAAAAAcEAAAAAAEAAAABAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQDAAAACQUAAAAFBQAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgDAAAAAQAAAAIAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Queue<int>(Enumerable.Range(1, 25)), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAB/U3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuUXVldWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQUAAAAGX2FycmF5BV9oZWFkBV90YWlsBV9zaXplCF92ZXJzaW9uBwAAAAAICAgICAIAAAAJAwAAAAAAAAAZAAAAGQAAAAAAAAAPAwAAACAAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAASAAAAEwAAABQAAAAVAAAAFgAAABcAAAAYAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAB/U3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuUXVldWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQUAAAAGX2FycmF5BV9oZWFkBV90YWlsBV9zaXplCF92ZXJzaW9uBwAAAAAICAgICAIAAAAJAwAAAAAAAAAZAAAAGQAAABwAAAAPAwAAACAAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAASAAAAEwAAABQAAAAVAAAAFgAAABcAAAAYAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Collections.Queue(50, 5.6f), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAAAAAAwAgAAAAAAABACAAAAMgAAAA0yCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuUXVldWUGAAAABl9hcnJheQVfaGVhZAVfdGFpbAVfc2l6ZQtfZ3Jvd0ZhY3RvcghfdmVyc2lvbgUAAAAAAAgICAgICQIAAAAAAAAAAAAAAAAAAAAwAgAAAAAAABACAAAAMgAAAA0yCw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SortedDictionary<int, Point>(pointDictionary, Comparer<int>.Default), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACyAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQEAAAAEX3NldASjA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlRyZWVTZXRgMVtbU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAIAAAAJAwAAAAwEAAAAVVN5c3RlbS5Db2xsZWN0aW9ucywgVmVyc2lvbj00LjEuMS4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAwAAAKMDU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuVHJlZVNldGAxW1tTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0EAAAABUNvdW50CENvbXBhcmVyB1ZlcnNpb24FSXRlbXMABAADCMcCU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuU29ydGVkRGljdGlvbmFyeWAyK0tleVZhbHVlUGFpckNvbXBhcmVyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dBAAAAAiwAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dW10CAAAAAgAAAAkFAAAAAgAAAAkGAAAABQUAAADHAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMitLZXlWYWx1ZVBhaXJDb21wYXJlcltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQEAAAALa2V5Q29tcGFyZXIDiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAJBwAAAAcGAAAAAAEAAAACAAAAA64CU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0MCQAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBPj///+uAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAANrZXkFdmFsdWUABAgzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50CQAAAAEAAAAJCgAAAAH1////+P///wIAAAAJDAAAAAQHAAAAiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAFCgAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgJAAAAAQAAAAEAAAABDAAAAAoAAAACAAAAAgAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACyAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZERpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQEAAAAEX3NldASjA1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlRyZWVTZXRgMVtbU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAIAAAAJAwAAAAUDAAAAowNTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5UcmVlU2V0YDFbW1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgVJdGVtcwAEAAMIxwJTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWREaWN0aW9uYXJ5YDIrS2V5VmFsdWVQYWlyQ29tcGFyZXJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAACLACU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV1bXQIAAAACAAAACQQAAAACAAAACQUAAAAFBAAAAMcCU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuU29ydGVkRGljdGlvbmFyeWAyK0tleVZhbHVlUGFpckNvbXBhcmVyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAQAAAAtrZXlDb21wYXJlcgOJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAkGAAAABwUAAAAAAQAAAAIAAAADrgJTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQwIAAAAcFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWIE+f///64CU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0CAAAAA2tleQV2YWx1ZQAECDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQIAAAAAQAAAAkJAAAAAfb////5////AgAAAAkLAAAABAYAAACJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAUJAAAAM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAIAAAABWAFZAAAICAgAAAABAAAAAQAAAAELAAAACQAAAAIAAAACAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SortedList<int, Point>(pointDictionary, Comparer<int>.Default), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgwEAAAAVVN5c3RlbS5Db2xsZWN0aW9ucywgVmVyc2lvbj00LjEuMS4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2EFAQAAAKwCU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuU29ydGVkTGlzdGAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dBwAAAARrZXlzBnZhbHVlcwVfc2l6ZQd2ZXJzaW9uCGNvbXBhcmVyB2tleUxpc3QJdmFsdWVMaXN0BwQAAAMEBAg1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10DAAAACAiJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dtAJTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWRMaXN0YDIrS2V5TGlzdFtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQQAAAC2AlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZExpc3RgMitWYWx1ZUxpc3RbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0EAAAAAgAAAAkFAAAACQYAAAACAAAAAAAAAAkHAAAACgoPBQAAAAIAAAAIAQAAAAIAAAAHBgAAAAABAAAAAgAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AwAAAAkIAAAACQkAAAAEBwAAAIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAABQgAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIAwAAAAEAAAABAAAAAQkAAAAIAAAAAgAAAAIAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAArAJTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWRMaXN0YDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0HAAAABGtleXMGdmFsdWVzBV9zaXplB3ZlcnNpb24IY29tcGFyZXIHa2V5TGlzdAl2YWx1ZUxpc3QHBAAAAwQECDVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQMAAAAICIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV20AlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZExpc3RgMitLZXlMaXN0W1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAALYCU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuU29ydGVkTGlzdGAyK1ZhbHVlTGlzdFtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQIAAAACAAAACQQAAAAJBQAAAAIAAAAAAAAACQYAAAAKCg8EAAAAAgAAAAgBAAAAAgAAAAcFAAAAAAEAAAACAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQDAAAACQcAAAAJCAAAAAQGAAAAiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAFBwAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgDAAAAAQAAAAEAAAABCAAAAAcAAAACAAAAAgAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Collections.SortedList(pointDictionary, Comparer<int>.Default), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdAcAAAAEa2V5cwZ2YWx1ZXMFX3NpemUHdmVyc2lvbghjb21wYXJlcgdrZXlMaXN0CXZhbHVlTGlzdAUFAAADAwMICIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0lU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QrS2V5TGlzdCdTeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdCtWYWx1ZUxpc3QJAgAAAAkDAAAAAgAAAAAAAAAJBAAAAAoKEAIAAAACAAAACAgBAAAACAgCAAAAEAMAAAACAAAACQUAAAAJBgAAAAQEAAAAiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAMBwAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQUAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIBwAAAAEAAAABAAAAAQYAAAAFAAAAAgAAAAIAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAB1TeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdAcAAAAEa2V5cwZ2YWx1ZXMFX3NpemUHdmVyc2lvbghjb21wYXJlcgdrZXlMaXN0CXZhbHVlTGlzdAUFAAADAwMICIkBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0lU3lzdGVtLkNvbGxlY3Rpb25zLlNvcnRlZExpc3QrS2V5TGlzdCdTeXN0ZW0uQ29sbGVjdGlvbnMuU29ydGVkTGlzdCtWYWx1ZUxpc3QJAgAAAAkDAAAAAgAAAAAAAAAJBAAAAAoKEAIAAAACAAAACAgBAAAACAgCAAAAEAMAAAACAAAACQUAAAAJBgAAAAQEAAAAiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAMBwAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQUAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIBwAAAAEAAAABAAAAAQYAAAAFAAAAAgAAAAIAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SortedSet<Point>(new[] { point, new Point(3, 5) }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAAzwFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWRTZXRgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0EAAAABUNvdW50CENvbXBhcmVyB1ZlcnNpb24FSXRlbXMAAwAECNUBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCDVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQMAAAACAAAAAQAAAAkEAAAAAAAAAAkFAAAABAQAAADVAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQAAAAAHBQAAAAABAAAAAQAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AwAAAAkGAAAABQYAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIAwAAAAEAAAACAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAAzwFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWRTZXRgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0EAAAABUNvdW50CENvbXBhcmVyB1ZlcnNpb24FSXRlbXMAAwAECNUBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0NvbXBhcmVyYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dCDVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQMAAAACAAAAAQAAAAkEAAAAAAAAAAkFAAAABAQAAADVAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQAAAAAHBQAAAAABAAAAAQAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AwAAAAkGAAAABQYAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIAwAAAAEAAAACAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SortedSet<int?>(new int?[] { 2, 4, 6, null }, Comparer<int?>.Default), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADlAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uTnVsbGFibGVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0EAAAABUNvdW50CENvbXBhcmVyB1ZlcnNpb24FSXRlbXMAAwADCIoBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTnVsbGFibGVDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCHBTeXN0ZW0uTnVsbGFibGVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXVtdAgAAAAQAAAAJAwAAAAAAAAAJBAAAAAQDAAAAigFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5OdWxsYWJsZUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAABwQAAAAAAQAAAAQAAAADblN5c3RlbS5OdWxsYWJsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCggIAgAAAAgIBAAAAAgIBgAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADlAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uTnVsbGFibGVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0EAAAABUNvdW50CENvbXBhcmVyB1ZlcnNpb24FSXRlbXMAAwADCIoBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTnVsbGFibGVDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCHBTeXN0ZW0uTnVsbGFibGVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXVtdAgAAAAQAAAAJAwAAAAAAAAAJBAAAAAQDAAAAigFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5OdWxsYWJsZUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAABwQAAAAAAQAAAAQAAAADblN5c3RlbS5OdWxsYWJsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCggIAgAAAAgIBAAAAAgIBgAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Stack<Point>(new[] { point, new Point(2, 2) }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAAywFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5TdGFja2AxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAGX2FycmF5BV9zaXplCF92ZXJzaW9uBAAANVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludFtdAwAAAAgIAgAAAAkEAAAAAgAAAAAAAAAHBAAAAAABAAAAAgAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AwAAAAkFAAAACQYAAAAFBQAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgDAAAAAQAAAAIAAAABBgAAAAUAAAACAAAAAgAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAAywFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5TdGFja2AxW1tTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAGX2FycmF5BV9zaXplCF92ZXJzaW9uBAAANVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludFtdAwAAAAgIAgAAAAkEAAAAAgAAAAAAAAAHBAAAAAABAAAAAgAAAAQzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AwAAAAkFAAAACQYAAAAFBQAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgDAAAAAQAAAAIAAAABBgAAAAUAAAACAAAAAgAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new System.Collections.Hashtable(255), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBwAAAApMb2FkRmFjdG9yB1ZlcnNpb24IQ29tcGFyZXIQSGFzaENvZGVQcm92aWRlcghIYXNoU2l6ZQRLZXlzBlZhbHVlcwAAAwMABQULCBxTeXN0ZW0uQ29sbGVjdGlvbnMuSUNvbXBhcmVyJFN5c3RlbS5Db2xsZWN0aW9ucy5JSGFzaENvZGVQcm92aWRlcgjsUTg/AAAAAAoKrwEAAAkCAAAACQMAAAAQAgAAAAAAAAAQAwAAAAAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBwAAAApMb2FkRmFjdG9yB1ZlcnNpb24IQ29tcGFyZXIQSGFzaENvZGVQcm92aWRlcghIYXNoU2l6ZQRLZXlzBlZhbHVlcwAAAwMABQULCBxTeXN0ZW0uQ29sbGVjdGlvbnMuSUNvbXBhcmVyJFN5c3RlbS5Db2xsZWN0aW9ucy5JSGFzaENvZGVQcm92aWRlcgjsUTg/AAAAAAoKrwEAAAkCAAAACQMAAAAQAgAAAAAAAAAQAwAAAAAAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new System.Collections.Hashtable(pointDictionary, 0.3f, EqualityComparer<int>.Default), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgcL10+AgAAAAkCAAAACwAAAAkDAAAACQQAAAAEAgAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAQAwAAAAIAAAAICAIAAAAICAEAAAAQBAAAAAIAAAAJBQAAAAkGAAAADAcAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUFAAAAM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAIAAAABWAFZAAAICAcAAAACAAAAAgAAAAEGAAAABQAAAAEAAAABAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQgcL10+AgAAAAkCAAAACwAAAAkDAAAACQQAAAAEAgAAAJEBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuR2VuZXJpY0VxdWFsaXR5Q29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAQAwAAAAIAAAAICAIAAAAICAEAAAAQBAAAAAIAAAAJBQAAAAkGAAAADAcAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUFAAAAM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAIAAAABWAFZAAAICAcAAAACAAAAAgAAAAEGAAAABQAAAAEAAAABAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new System.ComponentModel.BindingList<int>(new[] { 34, 52 }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACAAVN5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAlhZGROZXdQb3MWcmFpc2VMaXN0Q2hhbmdlZEV2ZW50cxZyYWlzZUl0ZW1DaGFuZ2VkRXZlbnRzCGFsbG93TmV3CWFsbG93RWRpdAthbGxvd1JlbW92ZQ91c2VyU2V0QWxsb3dOZXcSQ29sbGVjdGlvbmAxK2l0ZW1zAAAAAAAAAAMIAQEBAQEBDlN5c3RlbS5JbnQzMltdAgAAAP////8BAAEBAQAJAwAAAA8DAAAAAgAAAAgiAAAANAAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACAAVN5c3RlbS5Db21wb25lbnRNb2RlbC5CaW5kaW5nTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAlhZGROZXdQb3MWcmFpc2VMaXN0Q2hhbmdlZEV2ZW50cxZyYWlzZUl0ZW1DaGFuZ2VkRXZlbnRzCGFsbG93TmV3CWFsbG93RWRpdAthbGxvd1JlbW92ZQ91c2VyU2V0QWxsb3dOZXcSQ29sbGVjdGlvbmAxK2l0ZW1zAAAAAAAAAAMIAQEBAQEBDlN5c3RlbS5JbnQzMltdAgAAAP////8BAAEBAQAJAwAAAA8DAAAAAgAAAAgiAAAANAAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new System.ComponentModel.BindingList<Point>(new[] { point }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAAzAFTeXN0ZW0uQ29tcG9uZW50TW9kZWwuQmluZGluZ0xpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0IAAAACWFkZE5ld1BvcxZyYWlzZUxpc3RDaGFuZ2VkRXZlbnRzFnJhaXNlSXRlbUNoYW5nZWRFdmVudHMIYWxsb3dOZXcJYWxsb3dFZGl0C2FsbG93UmVtb3ZlD3VzZXJTZXRBbGxvd05ldxJDb2xsZWN0aW9uYDEraXRlbXMAAAAAAAAABAgBAQEBAQE1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10DAAAAAgAAAP////8BAAABAQAJBAAAAAcEAAAAAAEAAAABAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQDAAAACQUAAAAFBQAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgDAAAAAQAAAAIAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUBAAAAzAFTeXN0ZW0uQ29tcG9uZW50TW9kZWwuQmluZGluZ0xpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0IAAAACWFkZE5ld1BvcxZyYWlzZUxpc3RDaGFuZ2VkRXZlbnRzFnJhaXNlSXRlbUNoYW5nZWRFdmVudHMIYWxsb3dOZXcJYWxsb3dFZGl0C2FsbG93UmVtb3ZlD3VzZXJTZXRBbGxvd05ldxJDb2xsZWN0aW9uYDEraXRlbXMAAAAAAAAABAgBAQEBAQE1U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50W10DAAAAAgAAAP////8BAAABAQAJBAAAAAcEAAAAAAEAAAABAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQDAAAACQUAAAAFBQAAADNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAAAVgBWQAACAgDAAAAAQAAAAIAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Collections.Stack(new[] { point }), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuU3RhY2sDAAAABl9hcnJheQVfc2l6ZQhfdmVyc2lvbgUAAAgICQIAAAABAAAAAQAAABACAAAACgAAAAkDAAAADQkMBAAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQMAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIBAAAAAEAAAACAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABhTeXN0ZW0uQ29sbGVjdGlvbnMuU3RhY2sDAAAABl9hcnJheQVfc2l6ZQhfdmVyc2lvbgUAAAgICQIAAAABAAAAAQAAABACAAAACgAAAAkDAAAADQkMBAAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQMAAAAzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAFYAVkAAAgIBAAAAAEAAAACAAAACw==", TargetFrameworkMoniker.netfx461) } };
var stringDictionary = new System.Collections.Specialized.StringDictionary
{
{ "key1", "val1" }
};
- yield return new object[] { stringDictionary, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLlN0cmluZ0RpY3Rpb25hcnkBAAAACGNvbnRlbnRzAxxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlAgAAAAkDAAAABAMAAAAcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQcAAAAKTG9hZEZhY3RvcgdWZXJzaW9uCENvbXBhcmVyEEhhc2hDb2RlUHJvdmlkZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMDAAUFCwgcU3lzdGVtLkNvbGxlY3Rpb25zLklDb21wYXJlciRTeXN0ZW0uQ29sbGVjdGlvbnMuSUhhc2hDb2RlUHJvdmlkZXII7FE4PwEAAAAKCgMAAAAJBAAAAAkFAAAAEAQAAAABAAAABgYAAAAEa2V5MRAFAAAAAQAAAAYHAAAABHZhbDEL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLlN0cmluZ0RpY3Rpb25hcnkBAAAACGNvbnRlbnRzAxxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlAgAAAAkDAAAABAMAAAAcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQcAAAAKTG9hZEZhY3RvcgdWZXJzaW9uCENvbXBhcmVyEEhhc2hDb2RlUHJvdmlkZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMDAAUFCwgcU3lzdGVtLkNvbGxlY3Rpb25zLklDb21wYXJlciRTeXN0ZW0uQ29sbGVjdGlvbnMuSUhhc2hDb2RlUHJvdmlkZXII7FE4PwEAAAAKCgMAAAAJBAAAAAkFAAAAEAQAAAABAAAABgYAAAAEa2V5MRAFAAAAAQAAAAYHAAAABHZhbDEL" } };
+ yield return new object[] { stringDictionary, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLlN0cmluZ0RpY3Rpb25hcnkBAAAACGNvbnRlbnRzAxxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlAgAAAAkDAAAABAMAAAAcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQcAAAAKTG9hZEZhY3RvcgdWZXJzaW9uCENvbXBhcmVyEEhhc2hDb2RlUHJvdmlkZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMDAAUFCwgcU3lzdGVtLkNvbGxlY3Rpb25zLklDb21wYXJlciRTeXN0ZW0uQ29sbGVjdGlvbnMuSUhhc2hDb2RlUHJvdmlkZXII7FE4PwEAAAAKCgMAAAAJBAAAAAkFAAAAEAQAAAABAAAABgYAAAAEa2V5MRAFAAAAAQAAAAYHAAAABHZhbDEL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLlN0cmluZ0RpY3Rpb25hcnkBAAAACGNvbnRlbnRzAxxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlAgAAAAkDAAAABAMAAAAcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQcAAAAKTG9hZEZhY3RvcgdWZXJzaW9uCENvbXBhcmVyEEhhc2hDb2RlUHJvdmlkZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMDAAUFCwgcU3lzdGVtLkNvbGxlY3Rpb25zLklDb21wYXJlciRTeXN0ZW0uQ29sbGVjdGlvbnMuSUhhc2hDb2RlUHJvdmlkZXII7FE4PwEAAAAKCgMAAAAJBAAAAAkFAAAAEAQAAAABAAAABgYAAAAEa2V5MRAFAAAAAQAAAAYHAAAABHZhbDEL", TargetFrameworkMoniker.netfx461) } };
var stringCollection = new System.Collections.Specialized.StringCollection()
{
@@ -1256,7 +1257,7 @@ namespace System.Runtime.Serialization.Formatters.Tests
"bdes",
"Abd"
};
- yield return new object[] { stringCollection, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLlN0cmluZ0NvbGxlY3Rpb24BAAAABGRhdGEDHFN5c3RlbS5Db2xsZWN0aW9ucy5BcnJheUxpc3QCAAAACQMAAAAEAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkEAAAAAwAAAAMAAAAQBAAAAAQAAAAGBQAAAARhc2RmBgYAAAAEYmRlcwYHAAAAA0FiZAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLlN0cmluZ0NvbGxlY3Rpb24BAAAABGRhdGEDHFN5c3RlbS5Db2xsZWN0aW9ucy5BcnJheUxpc3QCAAAACQMAAAAEAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkEAAAAAwAAAAMAAAAQBAAAAAQAAAAGBQAAAARhc2RmBgYAAAAEYmRlcwYHAAAAA0FiZAoL" } };
+ yield return new object[] { stringCollection, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLlN0cmluZ0NvbGxlY3Rpb24BAAAABGRhdGEDHFN5c3RlbS5Db2xsZWN0aW9ucy5BcnJheUxpc3QCAAAACQMAAAAEAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkEAAAAAwAAAAMAAAAQBAAAAAQAAAAGBQAAAARhc2RmBgYAAAAEYmRlcwYHAAAAA0FiZAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLlN0cmluZ0NvbGxlY3Rpb24BAAAABGRhdGEDHFN5c3RlbS5Db2xsZWN0aW9ucy5BcnJheUxpc3QCAAAACQMAAAAEAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuQXJyYXlMaXN0AwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24FAAAICAkEAAAAAwAAAAMAAAAQBAAAAAQAAAAGBQAAAARhc2RmBgYAAAAEYmRlcwYHAAAAA0FiZAoL", TargetFrameworkMoniker.netfx461) } };
var orderedDictionary = new System.Collections.Specialized.OrderedDictionary(7)
{
@@ -1264,63 +1265,63 @@ namespace System.Runtime.Serialization.Formatters.Tests
{ "keyx", "s2" },
{ 22, "sample" }
};
- yield return new object[] { orderedDictionary, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAwU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLk9yZGVyZWREaWN0aW9uYXJ5BAAAAAtLZXlDb21wYXJlcghSZWFkT25seQ9Jbml0aWFsQ2FwYWNpdHkJQXJyYXlMaXN0AwAABSRTeXN0ZW0uQ29sbGVjdGlvbnMuSUVxdWFsaXR5Q29tcGFyZXIBCAIAAAAKAAcAAAAJAwAAABADAAAAAwAAAAkEAAAACQUAAAAJBgAAAAQEAAAAIlN5c3RlbS5Db2xsZWN0aW9ucy5EaWN0aW9uYXJ5RW50cnkCAAAABF9rZXkGX3ZhbHVlAgIGBwAAAARrZXkxCAgiAAAAAQUAAAAEAAAABggAAAAEa2V5eAYJAAAAAnMyAQYAAAAEAAAACAgWAAAABgoAAAAGc2FtcGxlCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAwU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLk9yZGVyZWREaWN0aW9uYXJ5BAAAAAtLZXlDb21wYXJlcghSZWFkT25seQ9Jbml0aWFsQ2FwYWNpdHkJQXJyYXlMaXN0AwAABSRTeXN0ZW0uQ29sbGVjdGlvbnMuSUVxdWFsaXR5Q29tcGFyZXIBCAIAAAAKAAcAAAAJAwAAABADAAAAAwAAAAkEAAAACQUAAAAJBgAAAAQEAAAAIlN5c3RlbS5Db2xsZWN0aW9ucy5EaWN0aW9uYXJ5RW50cnkCAAAABF9rZXkGX3ZhbHVlAgIGBwAAAARrZXkxCAgiAAAAAQUAAAAEAAAABggAAAAEa2V5eAYJAAAAAnMyAQYAAAAEAAAACAgWAAAABgoAAAAGc2FtcGxlCw==" } };
+ yield return new object[] { orderedDictionary, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAwU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLk9yZGVyZWREaWN0aW9uYXJ5BAAAAAtLZXlDb21wYXJlcghSZWFkT25seQ9Jbml0aWFsQ2FwYWNpdHkJQXJyYXlMaXN0AwAABSRTeXN0ZW0uQ29sbGVjdGlvbnMuSUVxdWFsaXR5Q29tcGFyZXIBCAIAAAAKAAcAAAAJAwAAABADAAAAAwAAAAkEAAAACQUAAAAJBgAAAAQEAAAAIlN5c3RlbS5Db2xsZWN0aW9ucy5EaWN0aW9uYXJ5RW50cnkCAAAABF9rZXkGX3ZhbHVlAgIGBwAAAARrZXkxCAgiAAAAAQUAAAAEAAAABggAAAAEa2V5eAYJAAAAAnMyAQYAAAAEAAAACAgWAAAABgoAAAAGc2FtcGxlCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAwU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLk9yZGVyZWREaWN0aW9uYXJ5BAAAAAtLZXlDb21wYXJlcghSZWFkT25seQ9Jbml0aWFsQ2FwYWNpdHkJQXJyYXlMaXN0AwAABSRTeXN0ZW0uQ29sbGVjdGlvbnMuSUVxdWFsaXR5Q29tcGFyZXIBCAIAAAAKAAcAAAAJAwAAABADAAAAAwAAAAkEAAAACQUAAAAJBgAAAAQEAAAAIlN5c3RlbS5Db2xsZWN0aW9ucy5EaWN0aW9uYXJ5RW50cnkCAAAABF9rZXkGX3ZhbHVlAgIGBwAAAARrZXkxCAgiAAAAAQUAAAAEAAAABggAAAAEa2V5eAYJAAAAAnMyAQYAAAAEAAAACAgWAAAABgoAAAAGc2FtcGxlCw==", TargetFrameworkMoniker.netfx461) } };
var listDictionary = new System.Collections.Specialized.ListDictionary(StringComparer.Create(CultureInfo.InvariantCulture, false))
{
{ "key1", "value1" },
{ "keyx", "valuex" }
};
- yield return new object[] { listDictionary, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5BAAAAARoZWFkB3ZlcnNpb24FY291bnQIY29tcGFyZXIEAAADPFN5c3RlbS5Db2xsZWN0aW9ucy5TcGVjaWFsaXplZC5MaXN0RGljdGlvbmFyeStEaWN0aW9uYXJ5Tm9kZQIAAAAICBtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXICAAAACQMAAAACAAAAAgAAAAkEAAAABQMAAAA8U3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5K0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICBDxTeXN0ZW0uQ29sbGVjdGlvbnMuU3BlY2lhbGl6ZWQuTGlzdERpY3Rpb25hcnkrRGljdGlvbmFyeU5vZGUCAAAAAgAAAAYFAAAABGtleTEGBgAAAAZ2YWx1ZTEJBwAAAAQEAAAAG1N5c3RlbS5DdWx0dXJlQXdhcmVDb21wYXJlcgIAAAAMX2NvbXBhcmVJbmZvC19pZ25vcmVDYXNlAwAgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8BCQgAAAAAAQcAAAADAAAABgkAAAAEa2V5eAYKAAAABnZhbHVleAoECAAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwMAAAAGbV9uYW1lDW1fU29ydFZlcnNpb24HY3VsdHVyZQEDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbggGCwAAAAAKfwAAAAs=", PlatformDetection.IsNetfx471OrNewer ? "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5BAAAAARoZWFkB3ZlcnNpb24FY291bnQIY29tcGFyZXIEAAADPFN5c3RlbS5Db2xsZWN0aW9ucy5TcGVjaWFsaXplZC5MaXN0RGljdGlvbmFyeStEaWN0aW9uYXJ5Tm9kZQIAAAAICBtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXICAAAACQMAAAACAAAAAgAAAAkEAAAABQMAAAA8U3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5K0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICBDxTeXN0ZW0uQ29sbGVjdGlvbnMuU3BlY2lhbGl6ZWQuTGlzdERpY3Rpb25hcnkrRGljdGlvbmFyeU5vZGUCAAAAAgAAAAYFAAAABGtleTEGBgAAAAZ2YWx1ZTEJBwAAAAQEAAAAG1N5c3RlbS5DdWx0dXJlQXdhcmVDb21wYXJlcgMAAAAMX2NvbXBhcmVJbmZvC19pZ25vcmVDYXNlCF9vcHRpb25zAwADIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvASNTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlT3B0aW9ucwkIAAAAAAT3////I1N5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVPcHRpb25zAQAAAAd2YWx1ZV9fAAgAAAAAAQcAAAADAAAABgoAAAAEa2V5eAYLAAAABnZhbHVleAoECAAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwQAAAAGbV9uYW1lCXdpbjMyTENJRAdjdWx0dXJlDW1fU29ydFZlcnNpb24BAAADCAggU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24GDAAAAAAAAAAAfwAAAAoL" : "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5BAAAAARoZWFkB3ZlcnNpb24FY291bnQIY29tcGFyZXIEAAADPFN5c3RlbS5Db2xsZWN0aW9ucy5TcGVjaWFsaXplZC5MaXN0RGljdGlvbmFyeStEaWN0aW9uYXJ5Tm9kZQIAAAAICBtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXICAAAACQMAAAACAAAAAgAAAAkEAAAABQMAAAA8U3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5K0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICBDxTeXN0ZW0uQ29sbGVjdGlvbnMuU3BlY2lhbGl6ZWQuTGlzdERpY3Rpb25hcnkrRGljdGlvbmFyeU5vZGUCAAAAAgAAAAYFAAAABGtleTEGBgAAAAZ2YWx1ZTEJBwAAAAQEAAAAG1N5c3RlbS5DdWx0dXJlQXdhcmVDb21wYXJlcgIAAAAMX2NvbXBhcmVJbmZvC19pZ25vcmVDYXNlAwAgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8BCQgAAAAAAQcAAAADAAAABgkAAAAEa2V5eAYKAAAABnZhbHVleAoECAAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwQAAAAGbV9uYW1lCXdpbjMyTENJRAdjdWx0dXJlDW1fU29ydFZlcnNpb24BAAADCAggU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24GCwAAAAAAAAAAfwAAAAoL" } };
- yield return new object[] { new System.Collections.Specialized.ListDictionary(StringComparer.Ordinal), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5BAAAAARoZWFkB3ZlcnNpb24FY291bnQIY29tcGFyZXIEAAADPFN5c3RlbS5Db2xsZWN0aW9ucy5TcGVjaWFsaXplZC5MaXN0RGljdGlvbmFyeStEaWN0aW9uYXJ5Tm9kZQIAAAAICBZTeXN0ZW0uT3JkaW5hbENvbXBhcmVyAgAAAAoAAAAAAAAAAAkDAAAABAMAAAAWU3lzdGVtLk9yZGluYWxDb21wYXJlcgEAAAALX2lnbm9yZUNhc2UAAQAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5BAAAAARoZWFkB3ZlcnNpb24FY291bnQIY29tcGFyZXIEAAADPFN5c3RlbS5Db2xsZWN0aW9ucy5TcGVjaWFsaXplZC5MaXN0RGljdGlvbmFyeStEaWN0aW9uYXJ5Tm9kZQIAAAAICBZTeXN0ZW0uT3JkaW5hbENvbXBhcmVyAgAAAAoAAAAAAAAAAAkDAAAABAMAAAAWU3lzdGVtLk9yZGluYWxDb21wYXJlcgEAAAALX2lnbm9yZUNhc2UAAQAL" } };
- yield return new object[] { new System.Collections.Specialized.ListDictionary(StringComparer.OrdinalIgnoreCase), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5BAAAAARoZWFkB3ZlcnNpb24FY291bnQIY29tcGFyZXIEAAADPFN5c3RlbS5Db2xsZWN0aW9ucy5TcGVjaWFsaXplZC5MaXN0RGljdGlvbmFyeStEaWN0aW9uYXJ5Tm9kZQIAAAAICBZTeXN0ZW0uT3JkaW5hbENvbXBhcmVyAgAAAAoAAAAAAAAAAAkDAAAABAMAAAAWU3lzdGVtLk9yZGluYWxDb21wYXJlcgEAAAALX2lnbm9yZUNhc2UAAQEL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5BAAAAARoZWFkB3ZlcnNpb24FY291bnQIY29tcGFyZXIEAAADPFN5c3RlbS5Db2xsZWN0aW9ucy5TcGVjaWFsaXplZC5MaXN0RGljdGlvbmFyeStEaWN0aW9uYXJ5Tm9kZQIAAAAICBZTeXN0ZW0uT3JkaW5hbENvbXBhcmVyAgAAAAoAAAAAAAAAAAkDAAAABAMAAAAWU3lzdGVtLk9yZGluYWxDb21wYXJlcgEAAAALX2lnbm9yZUNhc2UAAQEL" } };
+ yield return new object[] { listDictionary, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5BAAAAARoZWFkB3ZlcnNpb24FY291bnQIY29tcGFyZXIEAAADPFN5c3RlbS5Db2xsZWN0aW9ucy5TcGVjaWFsaXplZC5MaXN0RGljdGlvbmFyeStEaWN0aW9uYXJ5Tm9kZQIAAAAICBtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXICAAAACQMAAAACAAAAAgAAAAkEAAAABQMAAAA8U3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5K0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICBDxTeXN0ZW0uQ29sbGVjdGlvbnMuU3BlY2lhbGl6ZWQuTGlzdERpY3Rpb25hcnkrRGljdGlvbmFyeU5vZGUCAAAAAgAAAAYFAAAABGtleTEGBgAAAAZ2YWx1ZTEJBwAAAAQEAAAAG1N5c3RlbS5DdWx0dXJlQXdhcmVDb21wYXJlcgIAAAAMX2NvbXBhcmVJbmZvC19pZ25vcmVDYXNlAwAgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8BCQgAAAAAAQcAAAADAAAABgkAAAAEa2V5eAYKAAAABnZhbHVleAoECAAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwMAAAAGbV9uYW1lDW1fU29ydFZlcnNpb24HY3VsdHVyZQEDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbggGCwAAAAAKfwAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5BAAAAARoZWFkB3ZlcnNpb24FY291bnQIY29tcGFyZXIEAAADPFN5c3RlbS5Db2xsZWN0aW9ucy5TcGVjaWFsaXplZC5MaXN0RGljdGlvbmFyeStEaWN0aW9uYXJ5Tm9kZQIAAAAICBtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXICAAAACQMAAAACAAAAAgAAAAkEAAAABQMAAAA8U3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5K0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICBDxTeXN0ZW0uQ29sbGVjdGlvbnMuU3BlY2lhbGl6ZWQuTGlzdERpY3Rpb25hcnkrRGljdGlvbmFyeU5vZGUCAAAAAgAAAAYFAAAABGtleTEGBgAAAAZ2YWx1ZTEJBwAAAAQEAAAAG1N5c3RlbS5DdWx0dXJlQXdhcmVDb21wYXJlcgIAAAAMX2NvbXBhcmVJbmZvC19pZ25vcmVDYXNlAwAgU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZUluZm8BCQgAAAAAAQcAAAADAAAABgkAAAAEa2V5eAYKAAAABnZhbHVleAoECAAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwQAAAAGbV9uYW1lCXdpbjMyTENJRAdjdWx0dXJlDW1fU29ydFZlcnNpb24BAAADCAggU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24GCwAAAAAAAAAAfwAAAAoL", TargetFrameworkMoniker.netfx461), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5BAAAAARoZWFkB3ZlcnNpb24FY291bnQIY29tcGFyZXIEAAADPFN5c3RlbS5Db2xsZWN0aW9ucy5TcGVjaWFsaXplZC5MaXN0RGljdGlvbmFyeStEaWN0aW9uYXJ5Tm9kZQIAAAAICBtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXICAAAACQMAAAACAAAAAgAAAAkEAAAABQMAAAA8U3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5K0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICBDxTeXN0ZW0uQ29sbGVjdGlvbnMuU3BlY2lhbGl6ZWQuTGlzdERpY3Rpb25hcnkrRGljdGlvbmFyeU5vZGUCAAAAAgAAAAYFAAAABGtleTEGBgAAAAZ2YWx1ZTEJBwAAAAQEAAAAG1N5c3RlbS5DdWx0dXJlQXdhcmVDb21wYXJlcgMAAAAMX2NvbXBhcmVJbmZvCF9vcHRpb25zC19pZ25vcmVDYXNlAwMAIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvI1N5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVPcHRpb25zAQkIAAAABPf///8jU3lzdGVtLkdsb2JhbGl6YXRpb24uQ29tcGFyZU9wdGlvbnMBAAAAB3ZhbHVlX18ACAAAAAAAAQcAAAADAAAABgoAAAAEa2V5eAYLAAAABnZhbHVleAoECAAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwMAAAAGbV9uYW1lDW1fU29ydFZlcnNpb24HY3VsdHVyZQEDACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Tb3J0VmVyc2lvbggGDAAAAAAKfwAAAAs=", TargetFrameworkMoniker.netcoreapp21), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5BAAAAARoZWFkB3ZlcnNpb24FY291bnQIY29tcGFyZXIEAAADPFN5c3RlbS5Db2xsZWN0aW9ucy5TcGVjaWFsaXplZC5MaXN0RGljdGlvbmFyeStEaWN0aW9uYXJ5Tm9kZQIAAAAICBtTeXN0ZW0uQ3VsdHVyZUF3YXJlQ29tcGFyZXICAAAACQMAAAACAAAAAgAAAAkEAAAABQMAAAA8U3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5K0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICBDxTeXN0ZW0uQ29sbGVjdGlvbnMuU3BlY2lhbGl6ZWQuTGlzdERpY3Rpb25hcnkrRGljdGlvbmFyeU5vZGUCAAAAAgAAAAYFAAAABGtleTEGBgAAAAZ2YWx1ZTEJBwAAAAQEAAAAG1N5c3RlbS5DdWx0dXJlQXdhcmVDb21wYXJlcgMAAAAMX2NvbXBhcmVJbmZvC19pZ25vcmVDYXNlCF9vcHRpb25zAwADIFN5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVJbmZvASNTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlT3B0aW9ucwkIAAAAAAT3////I1N5c3RlbS5HbG9iYWxpemF0aW9uLkNvbXBhcmVPcHRpb25zAQAAAAd2YWx1ZV9fAAgAAAAAAQcAAAADAAAABgoAAAAEa2V5eAYLAAAABnZhbHVleAoECAAAACBTeXN0ZW0uR2xvYmFsaXphdGlvbi5Db21wYXJlSW5mbwQAAAAGbV9uYW1lCXdpbjMyTENJRAdjdWx0dXJlDW1fU29ydFZlcnNpb24BAAADCAggU3lzdGVtLkdsb2JhbGl6YXRpb24uU29ydFZlcnNpb24GDAAAAAAAAAAAfwAAAAoL", TargetFrameworkMoniker.netfx471) } };
+ yield return new object[] { new System.Collections.Specialized.ListDictionary(StringComparer.Ordinal), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5BAAAAARoZWFkB3ZlcnNpb24FY291bnQIY29tcGFyZXIEAAADPFN5c3RlbS5Db2xsZWN0aW9ucy5TcGVjaWFsaXplZC5MaXN0RGljdGlvbmFyeStEaWN0aW9uYXJ5Tm9kZQIAAAAICBZTeXN0ZW0uT3JkaW5hbENvbXBhcmVyAgAAAAoAAAAAAAAAAAkDAAAABAMAAAAWU3lzdGVtLk9yZGluYWxDb21wYXJlcgEAAAALX2lnbm9yZUNhc2UAAQAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5BAAAAARoZWFkB3ZlcnNpb24FY291bnQIY29tcGFyZXIEAAADPFN5c3RlbS5Db2xsZWN0aW9ucy5TcGVjaWFsaXplZC5MaXN0RGljdGlvbmFyeStEaWN0aW9uYXJ5Tm9kZQIAAAAICBZTeXN0ZW0uT3JkaW5hbENvbXBhcmVyAgAAAAoAAAAAAAAAAAkDAAAABAMAAAAWU3lzdGVtLk9yZGluYWxDb21wYXJlcgEAAAALX2lnbm9yZUNhc2UAAQAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new System.Collections.Specialized.ListDictionary(StringComparer.OrdinalIgnoreCase), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5BAAAAARoZWFkB3ZlcnNpb24FY291bnQIY29tcGFyZXIEAAADPFN5c3RlbS5Db2xsZWN0aW9ucy5TcGVjaWFsaXplZC5MaXN0RGljdGlvbmFyeStEaWN0aW9uYXJ5Tm9kZQIAAAAICBZTeXN0ZW0uT3JkaW5hbENvbXBhcmVyAgAAAAoAAAAAAAAAAAkDAAAABAMAAAAWU3lzdGVtLk9yZGluYWxDb21wYXJlcgEAAAALX2lnbm9yZUNhc2UAAQEL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAtU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkxpc3REaWN0aW9uYXJ5BAAAAARoZWFkB3ZlcnNpb24FY291bnQIY29tcGFyZXIEAAADPFN5c3RlbS5Db2xsZWN0aW9ucy5TcGVjaWFsaXplZC5MaXN0RGljdGlvbmFyeStEaWN0aW9uYXJ5Tm9kZQIAAAAICBZTeXN0ZW0uT3JkaW5hbENvbXBhcmVyAgAAAAoAAAAAAAAAAAkDAAAABAMAAAAWU3lzdGVtLk9yZGluYWxDb21wYXJlcgEAAAALX2lnbm9yZUNhc2UAAQEL", TargetFrameworkMoniker.netfx461) } };
var hybridDictionary = new System.Collections.Specialized.HybridDictionary(10, true)
{
{ "5d", 32 }
};
- yield return new object[] { hybridDictionary, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkh5YnJpZERpY3Rpb25hcnkDAAAABGxpc3QJaGFzaHRhYmxlD2Nhc2VJbnNlbnNpdGl2ZQQDAC1TeXN0ZW0uQ29sbGVjdGlvbnMuU3BlY2lhbGl6ZWQuTGlzdERpY3Rpb25hcnkCAAAAHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUBAgAAAAoJAwAAAAEEAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBZTeXN0ZW0uT3JkaW5hbENvbXBhcmVyCOxROD8BAAAACQQAAAARAAAACQUAAAAJBgAAAAQEAAAAFlN5c3RlbS5PcmRpbmFsQ29tcGFyZXIBAAAAC19pZ25vcmVDYXNlAAEBEAUAAAABAAAABgcAAAACNWQQBgAAAAEAAAAICCAAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkh5YnJpZERpY3Rpb25hcnkDAAAABGxpc3QJaGFzaHRhYmxlD2Nhc2VJbnNlbnNpdGl2ZQQDAC1TeXN0ZW0uQ29sbGVjdGlvbnMuU3BlY2lhbGl6ZWQuTGlzdERpY3Rpb25hcnkCAAAAHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUBAgAAAAoJAwAAAAEEAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBZTeXN0ZW0uT3JkaW5hbENvbXBhcmVyCOxROD8BAAAACQQAAAARAAAACQUAAAAJBgAAAAQEAAAAFlN5c3RlbS5PcmRpbmFsQ29tcGFyZXIBAAAAC19pZ25vcmVDYXNlAAEBEAUAAAABAAAABgcAAAACNWQQBgAAAAEAAAAICCAAAAAL" } };
- yield return new object[] { new SortedList<int, string>(dictionary, Comparer<int>.Default), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABVU3lzdGVtLkNvbGxlY3Rpb25zLCBWZXJzaW9uPTQuMS4xLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAA4QFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWRMaXN0YDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0HAAAABGtleXMGdmFsdWVzBV9zaXplB3ZlcnNpb24IY29tcGFyZXIHa2V5TGlzdAl2YWx1ZUxpc3QHBgAAAwQECAgIiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXekBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuU29ydGVkTGlzdGAyK0tleUxpc3RbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAA6wFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWRMaXN0YDIrVmFsdWVMaXN0W1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAIAAAAJBAAAAAkFAAAAAgAAAAAAAAAJBgAAAAoKDwQAAAACAAAACAEAAAACAAAAEQUAAAACAAAABgcAAAAEdGVzdAYIAAAADGFub3RoZXIgdGVzdAQGAAAAiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADhAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZExpc3RgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQcAAAAEa2V5cwZ2YWx1ZXMFX3NpemUHdmVyc2lvbghjb21wYXJlcgdrZXlMaXN0CXZhbHVlTGlzdAcGAAADBAQICAiJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1d6QFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWRMaXN0YDIrS2V5TGlzdFtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAADrAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZExpc3RgMitWYWx1ZUxpc3RbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAAAgAAAAkDAAAACQQAAAACAAAAAAAAAAkFAAAACgoPAwAAAAIAAAAIAQAAAAIAAAARBAAAAAIAAAAGBgAAAAR0ZXN0BgcAAAAMYW5vdGhlciB0ZXN0BAUAAACJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAs=" } };
- yield return new object[] { new Queue<int>(Enumerable.Range(1, 10)), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAB/U3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuUXVldWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQUAAAAGX2FycmF5BV9oZWFkBV90YWlsBV9zaXplCF92ZXJzaW9uBwAAAAAICAgICAIAAAAJAwAAAAAAAAAKAAAACgAAAAAAAAAPAwAAABAAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAB/U3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuUXVldWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQUAAAAGX2FycmF5BV9oZWFkBV90YWlsBV9zaXplCF92ZXJzaW9uBwAAAAAICAgICAIAAAAJAwAAAAAAAAAKAAAACgAAAAwAAAAPAwAAABAAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs=" } };
+ yield return new object[] { hybridDictionary, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkh5YnJpZERpY3Rpb25hcnkDAAAABGxpc3QJaGFzaHRhYmxlD2Nhc2VJbnNlbnNpdGl2ZQQDAC1TeXN0ZW0uQ29sbGVjdGlvbnMuU3BlY2lhbGl6ZWQuTGlzdERpY3Rpb25hcnkCAAAAHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUBAgAAAAoJAwAAAAEEAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBZTeXN0ZW0uT3JkaW5hbENvbXBhcmVyCOxROD8BAAAACQQAAAARAAAACQUAAAAJBgAAAAQEAAAAFlN5c3RlbS5PcmRpbmFsQ29tcGFyZXIBAAAAC19pZ25vcmVDYXNlAAEBEAUAAAABAAAABgcAAAACNWQQBgAAAAEAAAAICCAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAvU3lzdGVtLkNvbGxlY3Rpb25zLlNwZWNpYWxpemVkLkh5YnJpZERpY3Rpb25hcnkDAAAABGxpc3QJaGFzaHRhYmxlD2Nhc2VJbnNlbnNpdGl2ZQQDAC1TeXN0ZW0uQ29sbGVjdGlvbnMuU3BlY2lhbGl6ZWQuTGlzdERpY3Rpb25hcnkCAAAAHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUBAgAAAAoJAwAAAAEEAwAAABxTeXN0ZW0uQ29sbGVjdGlvbnMuSGFzaHRhYmxlBgAAAApMb2FkRmFjdG9yB1ZlcnNpb24LS2V5Q29tcGFyZXIISGFzaFNpemUES2V5cwZWYWx1ZXMAAAMABQULCBZTeXN0ZW0uT3JkaW5hbENvbXBhcmVyCOxROD8BAAAACQQAAAARAAAACQUAAAAJBgAAAAQEAAAAFlN5c3RlbS5PcmRpbmFsQ29tcGFyZXIBAAAAC19pZ25vcmVDYXNlAAEBEAUAAAABAAAABgcAAAACNWQQBgAAAAEAAAAICCAAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new SortedList<int, string>(dictionary, Comparer<int>.Default), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5DAMAAABVU3lzdGVtLkNvbGxlY3Rpb25zLCBWZXJzaW9uPTQuMS4xLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAA4QFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWRMaXN0YDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0HAAAABGtleXMGdmFsdWVzBV9zaXplB3ZlcnNpb24IY29tcGFyZXIHa2V5TGlzdAl2YWx1ZUxpc3QHBgAAAwQECAgIiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXekBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuU29ydGVkTGlzdGAyK0tleUxpc3RbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAA6wFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWRMaXN0YDIrVmFsdWVMaXN0W1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAIAAAAJBAAAAAkFAAAAAgAAAAAAAAAJBgAAAAoKDwQAAAACAAAACAEAAAACAAAAEQUAAAACAAAABgcAAAAEdGVzdAYIAAAADGFub3RoZXIgdGVzdAQGAAAAiQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljQ29tcGFyZXJgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAADhAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZExpc3RgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQcAAAAEa2V5cwZ2YWx1ZXMFX3NpemUHdmVyc2lvbghjb21wYXJlcgdrZXlMaXN0CXZhbHVlTGlzdAcGAAADBAQICAiJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1d6QFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Tb3J0ZWRMaXN0YDIrS2V5TGlzdFtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAADrAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZExpc3RgMitWYWx1ZUxpc3RbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAAAgAAAAkDAAAACQQAAAACAAAAAAAAAAkFAAAACgoPAwAAAAIAAAAIAQAAAAIAAAARBAAAAAIAAAAGBgAAAAR0ZXN0BgcAAAAMYW5vdGhlciB0ZXN0BAUAAACJAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Queue<int>(Enumerable.Range(1, 10)), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAB/U3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuUXVldWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQUAAAAGX2FycmF5BV9oZWFkBV90YWlsBV9zaXplCF92ZXJzaW9uBwAAAAAICAgICAIAAAAJAwAAAAAAAAAKAAAACgAAAAAAAAAPAwAAABAAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAB/U3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuUXVldWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQUAAAAGX2FycmF5BV9oZWFkBV90YWlsBV9zaXplCF92ZXJzaW9uBwAAAAAICAgICAIAAAAJAwAAAAAAAAAKAAAACgAAAAwAAAAPAwAAABAAAAAIAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs=", TargetFrameworkMoniker.netfx461) } };
// Passing an array to the IEnumerable cosntructor to hit its ICollection optimization, which causes all runtimes to
// produce the same internal state. Otherwise, they come up with different _version values
var observableCollection = new System.Collections.ObjectModel.ObservableCollection<int>(Enumerable.Range(1, 5).ToArray());
- yield return new object[] { observableCollection, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACF9tb25pdG9yEkNvbGxlY3Rpb25gMStpdGVtcwQDoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACQMAAAAJBAAAAAUDAAAAoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAApfYnVzeUNvdW50AAgCAAAAAAAAAAQEAAAAflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBwAACAgICQUAAAAFAAAAAAAAAA8FAAAABQAAAAgBAAAAAgAAAAMAAAAEAAAABQAAAAs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACF9tb25pdG9yEkNvbGxlY3Rpb25gMStpdGVtcwQDoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACQMAAAAJBAAAAAUDAAAAoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAApfYnVzeUNvdW50AAgCAAAAAAAAAAQEAAAAflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBwAACAgICQUAAAAFAAAABQAAAA8FAAAACAAAAAgBAAAAAgAAAAMAAAAEAAAABQAAAAAAAAAAAAAAAAAAAAs=" } };
- yield return new object[] { new System.Collections.ObjectModel.ReadOnlyObservableCollection<int>(observableCollection), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAJoBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLlJlYWRPbmx5T2JzZXJ2YWJsZUNvbGxlY3Rpb25gMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAZUmVhZE9ubHlDb2xsZWN0aW9uYDErbGlzdASSAVN5c3RlbS5Db2xsZWN0aW9ucy5PYmplY3RNb2RlbC5PYnNlcnZhYmxlQ29sbGVjdGlvbmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAIAAAAJAwAAAAUDAAAAkgFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAIX21vbml0b3ISQ29sbGVjdGlvbmAxK2l0ZW1zBAOgAVN5c3RlbS5Db2xsZWN0aW9ucy5PYmplY3RNb2RlbC5PYnNlcnZhYmxlQ29sbGVjdGlvbmAxK1NpbXBsZU1vbml0b3JbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAAflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAJBAAAAAkFAAAABQQAAACgAVN5c3RlbS5Db2xsZWN0aW9ucy5PYmplY3RNb2RlbC5PYnNlcnZhYmxlQ29sbGVjdGlvbmAxK1NpbXBsZU1vbml0b3JbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAACl9idXN5Q291bnQACAIAAAAAAAAABAUAAAB+U3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24HAAAICAgJBgAAAAUAAAAAAAAADwYAAAAFAAAACAEAAAACAAAAAwAAAAQAAAAFAAAACw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAJoBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLlJlYWRPbmx5T2JzZXJ2YWJsZUNvbGxlY3Rpb25gMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAZUmVhZE9ubHlDb2xsZWN0aW9uYDErbGlzdASSAVN5c3RlbS5Db2xsZWN0aW9ucy5PYmplY3RNb2RlbC5PYnNlcnZhYmxlQ29sbGVjdGlvbmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAIAAAAJAwAAAAUDAAAAkgFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAIX21vbml0b3ISQ29sbGVjdGlvbmAxK2l0ZW1zBAOgAVN5c3RlbS5Db2xsZWN0aW9ucy5PYmplY3RNb2RlbC5PYnNlcnZhYmxlQ29sbGVjdGlvbmAxK1NpbXBsZU1vbml0b3JbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAAflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAJBAAAAAkFAAAABQQAAACgAVN5c3RlbS5Db2xsZWN0aW9ucy5PYmplY3RNb2RlbC5PYnNlcnZhYmxlQ29sbGVjdGlvbmAxK1NpbXBsZU1vbml0b3JbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAACl9idXN5Q291bnQACAIAAAAAAAAABAUAAAB+U3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24HAAAICAgJBgAAAAUAAAAFAAAADwYAAAAIAAAACAEAAAACAAAAAwAAAAQAAAAFAAAAAAAAAAAAAAAAAAAACw==" } };
- yield return new object[] { new System.Collections.ObjectModel.ReadOnlyCollection<int>(Enumerable.Range(1, 15).ToList()), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAJABU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLlJlYWRPbmx5Q29sbGVjdGlvbmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAARsaXN0A35TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0JAgAAAAQCAAAAflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBwAACAgICQMAAAAPAAAADwAAAA8DAAAADwAAAAgBAAAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAKAAAACwAAAAwAAAANAAAADgAAAA8AAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAAJABU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLlJlYWRPbmx5Q29sbGVjdGlvbmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAARsaXN0A35TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0JAgAAAAQCAAAAflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBwAACAgICQMAAAAPAAAADwAAAA8DAAAAEAAAAAgBAAAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAKAAAACwAAAAwAAAANAAAADgAAAA8AAAAAAAAACw==" } };
- yield return new object[] { new System.Collections.ObjectModel.ReadOnlyDictionary<int, string>(dictionary), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAO0BU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLlJlYWRPbmx5RGljdGlvbmFyeWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAAxtX2RpY3Rpb25hcnkD4QFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5EaWN0aW9uYXJ5YDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0JAgAAAAQCAAAA4QFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5EaWN0aW9uYXJ5YDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0EAAAAB1ZlcnNpb24IQ29tcGFyZXIISGFzaFNpemUNS2V5VmFsdWVQYWlycwADAAMIkQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljRXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCOUBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV1bXQIAAAAJAwAAAAMAAAAJBAAAAAQDAAAAkQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljRXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAcEAAAAAAEAAAACAAAAA+MBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0E+////+MBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAAA2tleQV2YWx1ZQABCAEAAAAGBgAAAAR0ZXN0Afn////7////AgAAAAYIAAAADGFub3RoZXIgdGVzdAs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAO0BU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLlJlYWRPbmx5RGljdGlvbmFyeWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAAxtX2RpY3Rpb25hcnkD4QFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5EaWN0aW9uYXJ5YDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0JAgAAAAQCAAAA4QFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5EaWN0aW9uYXJ5YDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0EAAAAB1ZlcnNpb24IQ29tcGFyZXIISGFzaFNpemUNS2V5VmFsdWVQYWlycwADAAMIkQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljRXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCOUBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV1bXQIAAAAJAwAAAAMAAAAJBAAAAAQDAAAAkQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljRXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAcEAAAAAAEAAAACAAAAA+MBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0E+////+MBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAAA2tleQV2YWx1ZQABCAEAAAAGBgAAAAR0ZXN0Afn////7////AgAAAAYIAAAADGFub3RoZXIgdGVzdAs=" } };
+ yield return new object[] { observableCollection, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACF9tb25pdG9yEkNvbGxlY3Rpb25gMStpdGVtcwQDoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACQMAAAAJBAAAAAUDAAAAoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAApfYnVzeUNvdW50AAgCAAAAAAAAAAQEAAAAflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBwAACAgICQUAAAAFAAAAAAAAAA8FAAAABQAAAAgBAAAAAgAAAAMAAAAEAAAABQAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAJIBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLk9ic2VydmFibGVDb2xsZWN0aW9uYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACF9tb25pdG9yEkNvbGxlY3Rpb25gMStpdGVtcwQDoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAH5TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAACQMAAAAJBAAAAAUDAAAAoAFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMStTaW1wbGVNb25pdG9yW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAApfYnVzeUNvdW50AAgCAAAAAAAAAAQEAAAAflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBwAACAgICQUAAAAFAAAABQAAAA8FAAAACAAAAAgBAAAAAgAAAAMAAAAEAAAABQAAAAAAAAAAAAAAAAAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new System.Collections.ObjectModel.ReadOnlyObservableCollection<int>(observableCollection), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAJoBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLlJlYWRPbmx5T2JzZXJ2YWJsZUNvbGxlY3Rpb25gMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAZUmVhZE9ubHlDb2xsZWN0aW9uYDErbGlzdASSAVN5c3RlbS5Db2xsZWN0aW9ucy5PYmplY3RNb2RlbC5PYnNlcnZhYmxlQ29sbGVjdGlvbmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAIAAAAJAwAAAAUDAAAAkgFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAIX21vbml0b3ISQ29sbGVjdGlvbmAxK2l0ZW1zBAOgAVN5c3RlbS5Db2xsZWN0aW9ucy5PYmplY3RNb2RlbC5PYnNlcnZhYmxlQ29sbGVjdGlvbmAxK1NpbXBsZU1vbml0b3JbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAAflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAJBAAAAAkFAAAABQQAAACgAVN5c3RlbS5Db2xsZWN0aW9ucy5PYmplY3RNb2RlbC5PYnNlcnZhYmxlQ29sbGVjdGlvbmAxK1NpbXBsZU1vbml0b3JbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAACl9idXN5Q291bnQACAIAAAAAAAAABAUAAAB+U3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24HAAAICAgJBgAAAAUAAAAAAAAADwYAAAAFAAAACAEAAAACAAAAAwAAAAQAAAAFAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAE5XaW5kb3dzQmFzZSwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPU5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAJoBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLlJlYWRPbmx5T2JzZXJ2YWJsZUNvbGxlY3Rpb25gMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAZUmVhZE9ubHlDb2xsZWN0aW9uYDErbGlzdASSAVN5c3RlbS5Db2xsZWN0aW9ucy5PYmplY3RNb2RlbC5PYnNlcnZhYmxlQ29sbGVjdGlvbmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAIAAAAJAwAAAAUDAAAAkgFTeXN0ZW0uQ29sbGVjdGlvbnMuT2JqZWN0TW9kZWwuT2JzZXJ2YWJsZUNvbGxlY3Rpb25gMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAIX21vbml0b3ISQ29sbGVjdGlvbmAxK2l0ZW1zBAOgAVN5c3RlbS5Db2xsZWN0aW9ucy5PYmplY3RNb2RlbC5PYnNlcnZhYmxlQ29sbGVjdGlvbmAxK1NpbXBsZU1vbml0b3JbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAAflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAJBAAAAAkFAAAABQQAAACgAVN5c3RlbS5Db2xsZWN0aW9ucy5PYmplY3RNb2RlbC5PYnNlcnZhYmxlQ29sbGVjdGlvbmAxK1NpbXBsZU1vbml0b3JbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAACl9idXN5Q291bnQACAIAAAAAAAAABAUAAAB+U3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24HAAAICAgJBgAAAAUAAAAFAAAADwYAAAAIAAAACAEAAAACAAAAAwAAAAQAAAAFAAAAAAAAAAAAAAAAAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new System.Collections.ObjectModel.ReadOnlyCollection<int>(Enumerable.Range(1, 15).ToList()), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAJABU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLlJlYWRPbmx5Q29sbGVjdGlvbmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAARsaXN0A35TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0JAgAAAAQCAAAAflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBwAACAgICQMAAAAPAAAADwAAAA8DAAAADwAAAAgBAAAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAKAAAACwAAAAwAAAANAAAADgAAAA8AAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAJABU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLlJlYWRPbmx5Q29sbGVjdGlvbmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAARsaXN0A35TeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0JAgAAAAQCAAAAflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBwAACAgICQMAAAAPAAAADwAAAA8DAAAAEAAAAAgBAAAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAKAAAACwAAAAwAAAANAAAADgAAAA8AAAAAAAAACw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new System.Collections.ObjectModel.ReadOnlyDictionary<int, string>(dictionary), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAO0BU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLlJlYWRPbmx5RGljdGlvbmFyeWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAAxtX2RpY3Rpb25hcnkD4QFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5EaWN0aW9uYXJ5YDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0JAgAAAAQCAAAA4QFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5EaWN0aW9uYXJ5YDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0EAAAAB1ZlcnNpb24IQ29tcGFyZXIISGFzaFNpemUNS2V5VmFsdWVQYWlycwADAAMIkQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljRXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCOUBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV1bXQIAAAAJAwAAAAMAAAAJBAAAAAQDAAAAkQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljRXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAcEAAAAAAEAAAACAAAAA+MBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0E+////+MBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAAA2tleQV2YWx1ZQABCAEAAAAGBgAAAAR0ZXN0Afn////7////AgAAAAYIAAAADGFub3RoZXIgdGVzdAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAO0BU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLlJlYWRPbmx5RGljdGlvbmFyeWAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAAxtX2RpY3Rpb25hcnkD4QFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5EaWN0aW9uYXJ5YDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0JAgAAAAQCAAAA4QFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5EaWN0aW9uYXJ5YDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0EAAAAB1ZlcnNpb24IQ29tcGFyZXIISGFzaFNpemUNS2V5VmFsdWVQYWlycwADAAMIkQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljRXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCOUBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV1bXQIAAAAJAwAAAAMAAAAJBAAAAAQDAAAAkQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5HZW5lcmljRXF1YWxpdHlDb21wYXJlcmAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAAAAAAcEAAAAAAEAAAACAAAAA+MBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0E+////+MBU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuS2V5VmFsdWVQYWlyYDJbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0CAAAAA2tleQV2YWx1ZQABCAEAAAAGBgAAAAR0ZXN0Afn////7////AgAAAAYIAAAADGFub3RoZXIgdGVzdAs=", TargetFrameworkMoniker.netfx461) } };
var simpleKeyedCollection = new SimpleKeyedCollection
{
point
};
- yield return new object[] { simpleKeyedCollection, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABDU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlNpbXBsZUtleWVkQ29sbGVjdGlvbgUAAAAaS2V5ZWRDb2xsZWN0aW9uYDIrY29tcGFyZXIWS2V5ZWRDb2xsZWN0aW9uYDIrZGljdBpLZXllZENvbGxlY3Rpb25gMitrZXlDb3VudBtLZXllZENvbGxlY3Rpb25gMit0aHJlc2hvbGQSQ29sbGVjdGlvbmAxK2l0ZW1zAwMAAAORAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV2sAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkRpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQgIygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAkDAAAACQQAAAAAAAAAAAAAAAkFAAAABAMAAACRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAABAQAAACsAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkRpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQQAAAAHVmVyc2lvbghDb21wYXJlcghIYXNoU2l6ZQ1LZXlWYWx1ZVBhaXJzAAMAAwiRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IsAJTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdAQAAAAkDAAAAAwAAAAkHAAAABAUAAADKAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgQAADVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQIAAAAICAkIAAAAAQAAAAEAAAAHBwAAAAABAAAAAQAAAAOuAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dBPf///+uAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAANrZXkFdmFsdWUABAgzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAIAAAAJCgAAAAcIAAAAAAEAAAAEAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAACQoAAAANAwUKAAAAM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAIAAAABWAFZAAAICAIAAAABAAAAAgAAAAs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABDU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlNpbXBsZUtleWVkQ29sbGVjdGlvbgUAAAAaS2V5ZWRDb2xsZWN0aW9uYDIrY29tcGFyZXIWS2V5ZWRDb2xsZWN0aW9uYDIrZGljdBpLZXllZENvbGxlY3Rpb25gMitrZXlDb3VudBtLZXllZENvbGxlY3Rpb25gMit0aHJlc2hvbGQSQ29sbGVjdGlvbmAxK2l0ZW1zAwMAAAORAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV2sAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkRpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQgIygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAkDAAAACQQAAAAAAAAAAAAAAAkFAAAABAMAAACRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAABAQAAACsAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkRpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQQAAAAHVmVyc2lvbghDb21wYXJlcghIYXNoU2l6ZQ1LZXlWYWx1ZVBhaXJzAAMAAwiRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IsAJTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdAQAAAAkDAAAAAwAAAAkHAAAABAUAAADKAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgQAADVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQIAAAAICAkIAAAAAQAAAAEAAAAHBwAAAAABAAAAAQAAAAOuAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dBPf///+uAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAANrZXkFdmFsdWUABAgzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAIAAAAJCgAAAAcIAAAAAAEAAAAEAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAACQoAAAANAwUKAAAAM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAIAAAABWAFZAAAICAIAAAABAAAAAgAAAAs=" } };
- yield return new object[] { new System.Collections.ObjectModel.Collection<int>(Enumerable.Range(1, 20).ToList()), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAIgBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAFaXRlbXMDflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQkCAAAABAIAAAB+U3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24HAAAICAgJAwAAABQAAAAUAAAADwMAAAAUAAAACAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAIgBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAFaXRlbXMDflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQkCAAAABAIAAAB+U3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24HAAAICAgJAwAAABQAAAAUAAAADwMAAAAgAAAACAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACw==" } };
-
+ yield return new object[] { simpleKeyedCollection, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABDU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlNpbXBsZUtleWVkQ29sbGVjdGlvbgUAAAAaS2V5ZWRDb2xsZWN0aW9uYDIrY29tcGFyZXIWS2V5ZWRDb2xsZWN0aW9uYDIrZGljdBpLZXllZENvbGxlY3Rpb25gMitrZXlDb3VudBtLZXllZENvbGxlY3Rpb25gMit0aHJlc2hvbGQSQ29sbGVjdGlvbmAxK2l0ZW1zAwMAAAORAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV2sAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkRpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQgIygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAkDAAAACQQAAAAAAAAAAAAAAAkFAAAABAMAAACRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAABAQAAACsAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkRpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQQAAAAHVmVyc2lvbghDb21wYXJlcghIYXNoU2l6ZQ1LZXlWYWx1ZVBhaXJzAAMAAwiRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IsAJTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdAQAAAAkDAAAAAwAAAAkHAAAABAUAAADKAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgQAADVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQIAAAAICAkIAAAAAQAAAAEAAAAHBwAAAAABAAAAAQAAAAOuAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dBPf///+uAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAANrZXkFdmFsdWUABAgzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAIAAAAJCgAAAAcIAAAAAAEAAAAEAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAACQoAAAANAwUKAAAAM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAIAAAABWAFZAAAICAIAAAABAAAAAgAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABDU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlNpbXBsZUtleWVkQ29sbGVjdGlvbgUAAAAaS2V5ZWRDb2xsZWN0aW9uYDIrY29tcGFyZXIWS2V5ZWRDb2xsZWN0aW9uYDIrZGljdBpLZXllZENvbGxlY3Rpb25gMitrZXlDb3VudBtLZXllZENvbGxlY3Rpb25gMit0aHJlc2hvbGQSQ29sbGVjdGlvbmAxK2l0ZW1zAwMAAAORAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV2sAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkRpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQgIygFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5MaXN0YDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAkDAAAACQQAAAAAAAAAAAAAAAkFAAAABAMAAACRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0AAAAABAQAAACsAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkRpY3Rpb25hcnlgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQQAAAAHVmVyc2lvbghDb21wYXJlcghIYXNoU2l6ZQ1LZXlWYWx1ZVBhaXJzAAMAAwiRAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkdlbmVyaWNFcXVhbGl0eUNvbXBhcmVyYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IsAJTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5LZXlWYWx1ZVBhaXJgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXVtdAQAAAAkDAAAAAwAAAAkHAAAABAUAAADKAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50LCBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lvbgQAADVTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnRbXQIAAAAICAkIAAAAAQAAAAEAAAAHBwAAAAABAAAAAQAAAAOuAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dBPf///+uAlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLktleVZhbHVlUGFpcmAyW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludCwgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAANrZXkFdmFsdWUABAgzU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlBvaW50AgAAAAIAAAAJCgAAAAcIAAAAAAEAAAAEAAAABDNTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuUG9pbnQCAAAACQoAAAANAwUKAAAAM1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Qb2ludAIAAAABWAFZAAAICAIAAAABAAAAAgAAAAs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new System.Collections.ObjectModel.Collection<int>(Enumerable.Range(1, 20).ToList()), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAIgBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAFaXRlbXMDflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQkCAAAABAIAAAB+U3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24HAAAICAgJAwAAABQAAAAUAAAADwMAAAAUAAAACAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAIgBU3lzdGVtLkNvbGxlY3Rpb25zLk9iamVjdE1vZGVsLkNvbGxlY3Rpb25gMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAFaXRlbXMDflN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQkCAAAABAIAAAB+U3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAAAAZfaXRlbXMFX3NpemUIX3ZlcnNpb24HAAAICAgJAwAAABQAAAAUAAAADwMAAAAgAAAACAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACw==", TargetFrameworkMoniker.netfx461) } };
+
// Graph without cycles
- yield return new object[] { new Tree<int>(42, null, null), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAACRAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5UcmVlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAFjxWYWx1ZT5rX19CYWNraW5nRmllbGQVPExlZnQ+a19fQmFja2luZ0ZpZWxkFjxSaWdodD5rX19CYWNraW5nRmllbGQABAQIkQFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuVHJlZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAJEBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAACAAAAKgAAAAoKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAACRAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5UcmVlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAFjxWYWx1ZT5rX19CYWNraW5nRmllbGQVPExlZnQ+a19fQmFja2luZ0ZpZWxkFjxSaWdodD5rX19CYWNraW5nRmllbGQABAQIkQFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuVHJlZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAJEBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAACAAAAKgAAAAoKCw==" } };
- yield return new object[] { new Tree<int>(1, new Tree<int>(2, new Tree<int>(3, null, null), null), null), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAACRAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5UcmVlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAFjxWYWx1ZT5rX19CYWNraW5nRmllbGQVPExlZnQ+a19fQmFja2luZ0ZpZWxkFjxSaWdodD5rX19CYWNraW5nRmllbGQABAQIkQFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuVHJlZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAJEBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAACAAAAAQAAAAkDAAAACgEDAAAAAQAAAAIAAAAJBAAAAAoBBAAAAAEAAAADAAAACgoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAACRAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5UcmVlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAFjxWYWx1ZT5rX19CYWNraW5nRmllbGQVPExlZnQ+a19fQmFja2luZ0ZpZWxkFjxSaWdodD5rX19CYWNraW5nRmllbGQABAQIkQFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuVHJlZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAJEBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAACAAAAAQAAAAkDAAAACgEDAAAAAQAAAAIAAAAJBAAAAAoBBAAAAAEAAAADAAAACgoL" } };
- yield return new object[] { new Tree<Colors>(Colors.Red, null, new Tree<Colors>(Colors.Blue, null, new Tree<Colors>(Colors.Green, null, null))), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAADeAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5UcmVlYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Db2xvcnMsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAWPFZhbHVlPmtfX0JhY2tpbmdGaWVsZBU8TGVmdD5rX19CYWNraW5nRmllbGQWPFJpZ2h0PmtfX0JhY2tpbmdGaWVsZAQEBDRTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuQ29sb3JzAgAAAN4BU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkNvbG9ycywgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAN4BU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkNvbG9ycywgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAIAAAAF/f///zRTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuQ29sb3JzAQAAAAd2YWx1ZV9fAAgCAAAAAAAAAAoJBAAAAAEEAAAAAQAAAAH7/////f///wQAAAAKCQYAAAABBgAAAAEAAAAB+f////3///8DAAAACgoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAADeAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5UcmVlYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Db2xvcnMsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAWPFZhbHVlPmtfX0JhY2tpbmdGaWVsZBU8TGVmdD5rX19CYWNraW5nRmllbGQWPFJpZ2h0PmtfX0JhY2tpbmdGaWVsZAQEBDRTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuQ29sb3JzAgAAAN4BU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkNvbG9ycywgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAN4BU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkNvbG9ycywgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAIAAAAF/f///zRTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuQ29sb3JzAQAAAAd2YWx1ZV9fAAgCAAAAAAAAAAoJBAAAAAEEAAAAAQAAAAH7/////f///wQAAAAKCQYAAAABBgAAAAEAAAAB+f////3///8DAAAACgoL" } };
- yield return new object[] { new Tree<int>(1, new Tree<int>(2, new Tree<int>(3, null, null), new Tree<int>(4, null, null)), new Tree<int>(5, null, null)), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAACRAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5UcmVlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAFjxWYWx1ZT5rX19CYWNraW5nRmllbGQVPExlZnQ+a19fQmFja2luZ0ZpZWxkFjxSaWdodD5rX19CYWNraW5nRmllbGQABAQIkQFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuVHJlZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAJEBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAACAAAAAQAAAAkDAAAACQQAAAABAwAAAAEAAAACAAAACQUAAAAJBgAAAAEEAAAAAQAAAAUAAAAKCgEFAAAAAQAAAAMAAAAKCgEGAAAAAQAAAAQAAAAKCgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAACRAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5UcmVlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAFjxWYWx1ZT5rX19CYWNraW5nRmllbGQVPExlZnQ+a19fQmFja2luZ0ZpZWxkFjxSaWdodD5rX19CYWNraW5nRmllbGQABAQIkQFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuVHJlZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAJEBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAACAAAAAQAAAAkDAAAACQQAAAABAwAAAAEAAAACAAAACQUAAAAJBgAAAAEEAAAAAQAAAAUAAAAKCgEFAAAAAQAAAAMAAAAKCgEGAAAAAQAAAAQAAAAKCgs=" } };
+ yield return new object[] { new Tree<int>(42, null, null), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAACRAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5UcmVlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAFjxWYWx1ZT5rX19CYWNraW5nRmllbGQVPExlZnQ+a19fQmFja2luZ0ZpZWxkFjxSaWdodD5rX19CYWNraW5nRmllbGQABAQIkQFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuVHJlZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAJEBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAACAAAAKgAAAAoKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAACRAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5UcmVlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAFjxWYWx1ZT5rX19CYWNraW5nRmllbGQVPExlZnQ+a19fQmFja2luZ0ZpZWxkFjxSaWdodD5rX19CYWNraW5nRmllbGQABAQIkQFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuVHJlZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAJEBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAACAAAAKgAAAAoKCw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Tree<int>(1, new Tree<int>(2, new Tree<int>(3, null, null), null), null), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAACRAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5UcmVlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAFjxWYWx1ZT5rX19CYWNraW5nRmllbGQVPExlZnQ+a19fQmFja2luZ0ZpZWxkFjxSaWdodD5rX19CYWNraW5nRmllbGQABAQIkQFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuVHJlZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAJEBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAACAAAAAQAAAAkDAAAACgEDAAAAAQAAAAIAAAAJBAAAAAoBBAAAAAEAAAADAAAACgoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAACRAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5UcmVlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAFjxWYWx1ZT5rX19CYWNraW5nRmllbGQVPExlZnQ+a19fQmFja2luZ0ZpZWxkFjxSaWdodD5rX19CYWNraW5nRmllbGQABAQIkQFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuVHJlZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAJEBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAACAAAAAQAAAAkDAAAACgEDAAAAAQAAAAIAAAAJBAAAAAoBBAAAAAEAAAADAAAACgoL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Tree<Colors>(Colors.Red, null, new Tree<Colors>(Colors.Blue, null, new Tree<Colors>(Colors.Green, null, null))), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAADeAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5UcmVlYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Db2xvcnMsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAWPFZhbHVlPmtfX0JhY2tpbmdGaWVsZBU8TGVmdD5rX19CYWNraW5nRmllbGQWPFJpZ2h0PmtfX0JhY2tpbmdGaWVsZAQEBDRTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuQ29sb3JzAgAAAN4BU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkNvbG9ycywgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAN4BU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkNvbG9ycywgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAIAAAAF/f///zRTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuQ29sb3JzAQAAAAd2YWx1ZV9fAAgCAAAAAAAAAAoJBAAAAAEEAAAAAQAAAAH7/////f///wQAAAAKCQYAAAABBgAAAAEAAAAB+f////3///8DAAAACgoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAADeAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5UcmVlYDFbW1N5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5Db2xvcnMsIFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cywgVmVyc2lvbj00LjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTlkNzdjYzdhZDM5YjY4ZWJdXQMAAAAWPFZhbHVlPmtfX0JhY2tpbmdGaWVsZBU8TGVmdD5rX19CYWNraW5nRmllbGQWPFJpZ2h0PmtfX0JhY2tpbmdGaWVsZAQEBDRTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuQ29sb3JzAgAAAN4BU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkNvbG9ycywgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAN4BU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkNvbG9ycywgU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYl1dAgAAAAIAAAAF/f///zRTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuQ29sb3JzAQAAAAd2YWx1ZV9fAAgCAAAAAAAAAAoJBAAAAAEEAAAAAQAAAAH7/////f///wQAAAAKCQYAAAABBgAAAAEAAAAB+f////3///8DAAAACgoL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new Tree<int>(1, new Tree<int>(2, new Tree<int>(3, null, null), new Tree<int>(4, null, null)), new Tree<int>(5, null, null)), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAACRAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5UcmVlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAFjxWYWx1ZT5rX19CYWNraW5nRmllbGQVPExlZnQ+a19fQmFja2luZ0ZpZWxkFjxSaWdodD5rX19CYWNraW5nRmllbGQABAQIkQFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuVHJlZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAJEBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAACAAAAAQAAAAkDAAAACQQAAAABAwAAAAEAAAACAAAACQUAAAAJBgAAAAEEAAAAAQAAAAUAAAAKCgEFAAAAAQAAAAMAAAAKCgEGAAAAAQAAAAQAAAAKCgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAACRAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5UcmVlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0DAAAAFjxWYWx1ZT5rX19CYWNraW5nRmllbGQVPExlZnQ+a19fQmFja2luZ0ZpZWxkFjxSaWdodD5rX19CYWNraW5nRmllbGQABAQIkQFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuVHJlZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAJEBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlRyZWVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAACAAAAAQAAAAkDAAAACQQAAAABAwAAAAEAAAACAAAACQUAAAAJBgAAAAEEAAAAAQAAAAUAAAAKCgEFAAAAAQAAAAMAAAAKCgEGAAAAAQAAAAQAAAAKCgs=", TargetFrameworkMoniker.netfx461) } };
// Graph with cycles
{
- var a = new Graph<int> { Value = 1 };
- var b = new Graph<int> { Value = 2, Links = new[] { a } };
- var c = new Graph<int> { Value = 3, Links = new[] { a, b } };
- var d = new Graph<int> { Value = 3, Links = new[] { a, b, c } };
+ var a = new Graph<int> { Value = 1 };
+ var b = new Graph<int> { Value = 2, Links = new[] { a } };
+ var c = new Graph<int> { Value = 3, Links = new[] { a, b } };
+ var d = new Graph<int> { Value = 3, Links = new[] { a, b, c } };
a.Links = new[] { b, c, d }; // complete the cycle
- yield return new object[] { a, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAACSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAVWYWx1ZQVMaW5rcwAECJQBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV1bXQIAAAACAAAAAQAAAAkDAAAABwMAAAAAAQAAAAMAAAAEkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAJBAAAAAkFAAAACQYAAAABBAAAAAEAAAACAAAACQcAAAABBQAAAAEAAAADAAAACQgAAAABBgAAAAEAAAADAAAACQkAAAAHBwAAAAABAAAAAQAAAASSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAkBAAAABwgAAAAAAQAAAAIAAAAEkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAJAQAAAAkEAAAABwkAAAAAAQAAAAMAAAAEkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAJAQAAAAkEAAAACQUAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAACSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAVWYWx1ZQVMaW5rcwAECJQBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV1bXQIAAAACAAAAAQAAAAkDAAAABwMAAAAAAQAAAAMAAAAEkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAJBAAAAAkFAAAACQYAAAABBAAAAAEAAAACAAAACQcAAAABBQAAAAEAAAADAAAACQgAAAABBgAAAAEAAAADAAAACQkAAAAHBwAAAAABAAAAAQAAAASSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAkBAAAABwgAAAAAAQAAAAIAAAAEkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAJAQAAAAkEAAAABwkAAAAAAQAAAAMAAAAEkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAJAQAAAAkEAAAACQUAAAAL" } };
+ yield return new object[] { a, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAACSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAVWYWx1ZQVMaW5rcwAECJQBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV1bXQIAAAACAAAAAQAAAAkDAAAABwMAAAAAAQAAAAMAAAAEkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAJBAAAAAkFAAAACQYAAAABBAAAAAEAAAACAAAACQcAAAABBQAAAAEAAAADAAAACQgAAAABBgAAAAEAAAADAAAACQkAAAAHBwAAAAABAAAAAQAAAASSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAkBAAAABwgAAAAAAQAAAAIAAAAEkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAJAQAAAAkEAAAABwkAAAAAAQAAAAMAAAAEkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAJAQAAAAkEAAAACQUAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAACSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAVWYWx1ZQVMaW5rcwAECJQBU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkdyYXBoYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV1bXQIAAAACAAAAAQAAAAkDAAAABwMAAAAAAQAAAAMAAAAEkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAJBAAAAAkFAAAACQYAAAABBAAAAAEAAAACAAAACQcAAAABBQAAAAEAAAADAAAACQgAAAABBgAAAAEAAAADAAAACQkAAAAHBwAAAAABAAAAAQAAAASSAVN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5HcmFwaGAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAgAAAAkBAAAABwgAAAAAAQAAAAIAAAAEkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAJAQAAAAkEAAAABwkAAAAAAQAAAAMAAAAEkgFTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuR3JhcGhgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAJAQAAAAkEAAAACQUAAAAL", TargetFrameworkMoniker.netfx461) } };
}
// Structs
- yield return new object[] { new EmptyStruct(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAAA5U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkVtcHR5U3RydWN0AAAAAAIAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAAA5U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkVtcHR5U3RydWN0AAAAAAIAAAAL" } };
- yield return new object[] { new StructWithIntField { X = 42 }, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABAU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdFdpdGhJbnRGaWVsZAEAAAABWAAIAgAAACoAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABAU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdFdpdGhJbnRGaWVsZAEAAAABWAAIAgAAACoAAAAL" } };
- yield return new object[] { new StructWithStringFields { String1 = "hello", String2 = "world" }, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABEU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdFdpdGhTdHJpbmdGaWVsZHMCAAAAB1N0cmluZzEHU3RyaW5nMgEBAgAAAAYDAAAABWhlbGxvBgQAAAAFd29ybGQL", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABEU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdFdpdGhTdHJpbmdGaWVsZHMCAAAAB1N0cmluZzEHU3RyaW5nMgEBAgAAAAYDAAAABWhlbGxvBgQAAAAFd29ybGQL" } };
- yield return new object[] { new StructContainingOtherStructs { Nested1 = new StructWithStringFields { String1 = "a", String2 = "b" }, Nested2 = new StructWithStringFields { String1 = "3", String2 = "4" } }, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABKU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdENvbnRhaW5pbmdPdGhlclN0cnVjdHMCAAAAB05lc3RlZDEHTmVzdGVkMgQERFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5TdHJ1Y3RXaXRoU3RyaW5nRmllbGRzAgAAAERTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0V2l0aFN0cmluZ0ZpZWxkcwIAAAACAAAABf3///9EU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdFdpdGhTdHJpbmdGaWVsZHMCAAAAB1N0cmluZzEHU3RyaW5nMgEBAgAAAAYEAAAAAWEGBQAAAAFiAfr////9////BgcAAAABMwYIAAAAATQL", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABKU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdENvbnRhaW5pbmdPdGhlclN0cnVjdHMCAAAAB05lc3RlZDEHTmVzdGVkMgQERFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5TdHJ1Y3RXaXRoU3RyaW5nRmllbGRzAgAAAERTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0V2l0aFN0cmluZ0ZpZWxkcwIAAAACAAAABf3///9EU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdFdpdGhTdHJpbmdGaWVsZHMCAAAAB1N0cmluZzEHU3RyaW5nMgEBAgAAAAYEAAAAAWEGBQAAAAFiAfr////9////BgcAAAABMwYIAAAAATQL" } };
- yield return new object[] { new StructContainingArraysOfOtherStructs(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABSU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdENvbnRhaW5pbmdBcnJheXNPZk90aGVyU3RydWN0cwEAAAAGTmVzdGVkBExTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0c1tdAgAAAAIAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABSU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdENvbnRhaW5pbmdBcnJheXNPZk90aGVyU3RydWN0cwEAAAAGTmVzdGVkBExTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0c1tdAgAAAAIAAAAKCw==" } };
- yield return new object[] { new StructContainingArraysOfOtherStructs { Nested = new StructContainingOtherStructs[0] }, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABSU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdENvbnRhaW5pbmdBcnJheXNPZk90aGVyU3RydWN0cwEAAAAGTmVzdGVkBExTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0c1tdAgAAAAIAAAAJAwAAAAcDAAAAAAEAAAAAAAAABEpTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0cwIAAAAL", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABSU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdENvbnRhaW5pbmdBcnJheXNPZk90aGVyU3RydWN0cwEAAAAGTmVzdGVkBExTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0c1tdAgAAAAIAAAAJAwAAAAcDAAAAAAEAAAAAAAAABEpTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0cwIAAAAL" } };
+ yield return new object[] { new EmptyStruct(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAAA5U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkVtcHR5U3RydWN0AAAAAAIAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAAA5U3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkVtcHR5U3RydWN0AAAAAAIAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new StructWithIntField { X = 42 }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABAU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdFdpdGhJbnRGaWVsZAEAAAABWAAIAgAAACoAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABAU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdFdpdGhJbnRGaWVsZAEAAAABWAAIAgAAACoAAAAL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new StructWithStringFields { String1 = "hello", String2 = "world" }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABEU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdFdpdGhTdHJpbmdGaWVsZHMCAAAAB1N0cmluZzEHU3RyaW5nMgEBAgAAAAYDAAAABWhlbGxvBgQAAAAFd29ybGQL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABEU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdFdpdGhTdHJpbmdGaWVsZHMCAAAAB1N0cmluZzEHU3RyaW5nMgEBAgAAAAYDAAAABWhlbGxvBgQAAAAFd29ybGQL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new StructContainingOtherStructs { Nested1 = new StructWithStringFields { String1 = "a", String2 = "b" }, Nested2 = new StructWithStringFields { String1 = "3", String2 = "4" } }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABKU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdENvbnRhaW5pbmdPdGhlclN0cnVjdHMCAAAAB05lc3RlZDEHTmVzdGVkMgQERFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5TdHJ1Y3RXaXRoU3RyaW5nRmllbGRzAgAAAERTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0V2l0aFN0cmluZ0ZpZWxkcwIAAAACAAAABf3///9EU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdFdpdGhTdHJpbmdGaWVsZHMCAAAAB1N0cmluZzEHU3RyaW5nMgEBAgAAAAYEAAAAAWEGBQAAAAFiAfr////9////BgcAAAABMwYIAAAAATQL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABKU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdENvbnRhaW5pbmdPdGhlclN0cnVjdHMCAAAAB05lc3RlZDEHTmVzdGVkMgQERFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5TdHJ1Y3RXaXRoU3RyaW5nRmllbGRzAgAAAERTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0V2l0aFN0cmluZ0ZpZWxkcwIAAAACAAAABf3///9EU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdFdpdGhTdHJpbmdGaWVsZHMCAAAAB1N0cmluZzEHU3RyaW5nMgEBAgAAAAYEAAAAAWEGBQAAAAFiAfr////9////BgcAAAABMwYIAAAAATQL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new StructContainingArraysOfOtherStructs(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABSU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdENvbnRhaW5pbmdBcnJheXNPZk90aGVyU3RydWN0cwEAAAAGTmVzdGVkBExTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0c1tdAgAAAAIAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABSU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdENvbnRhaW5pbmdBcnJheXNPZk90aGVyU3RydWN0cwEAAAAGTmVzdGVkBExTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0c1tdAgAAAAIAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new StructContainingArraysOfOtherStructs { Nested = new StructContainingOtherStructs[0] }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABSU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdENvbnRhaW5pbmdBcnJheXNPZk90aGVyU3RydWN0cwEAAAAGTmVzdGVkBExTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0c1tdAgAAAAIAAAAJAwAAAAcDAAAAAAEAAAAAAAAABEpTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0cwIAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABSU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdENvbnRhaW5pbmdBcnJheXNPZk90aGVyU3RydWN0cwEAAAAGTmVzdGVkBExTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0c1tdAgAAAAIAAAAJAwAAAAcDAAAAAAEAAAAAAAAABEpTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0cwIAAAAL", TargetFrameworkMoniker.netfx461) } };
var s = new StructContainingArraysOfOtherStructs
{
Nested = new[]
@@ -1329,74 +1330,74 @@ namespace System.Runtime.Serialization.Formatters.Tests
new StructContainingOtherStructs { Nested1 = new StructWithStringFields { String1 = "e", String2 = "f" }, Nested2 = new StructWithStringFields { String1 = "7", String2 = "8" } },
}
};
- yield return new object[] { s, new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABSU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdENvbnRhaW5pbmdBcnJheXNPZk90aGVyU3RydWN0cwEAAAAGTmVzdGVkBExTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0c1tdAgAAAAIAAAAJAwAAAAcDAAAAAAEAAAACAAAABEpTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0cwIAAAAF/P///0pTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0cwIAAAAHTmVzdGVkMQdOZXN0ZWQyBAREU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdFdpdGhTdHJpbmdGaWVsZHMCAAAARFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5TdHJ1Y3RXaXRoU3RyaW5nRmllbGRzAgAAAAIAAAAF+////0RTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0V2l0aFN0cmluZ0ZpZWxkcwIAAAAHU3RyaW5nMQdTdHJpbmcyAQECAAAABgYAAAABYQYHAAAAAWIB+P////v///8GCQAAAAEzBgoAAAABNAH1/////P///wH0////+////wYNAAAAAWUGDgAAAAFmAfH////7////BhAAAAABNwYRAAAAATgL", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABSU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdENvbnRhaW5pbmdBcnJheXNPZk90aGVyU3RydWN0cwEAAAAGTmVzdGVkBExTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0c1tdAgAAAAIAAAAJAwAAAAcDAAAAAAEAAAACAAAABEpTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0cwIAAAAF/P///0pTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0cwIAAAAHTmVzdGVkMQdOZXN0ZWQyBAREU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdFdpdGhTdHJpbmdGaWVsZHMCAAAARFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5TdHJ1Y3RXaXRoU3RyaW5nRmllbGRzAgAAAAIAAAAF+////0RTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0V2l0aFN0cmluZ0ZpZWxkcwIAAAAHU3RyaW5nMQdTdHJpbmcyAQECAAAABgYAAAABYQYHAAAAAWIB+P////v///8GCQAAAAEzBgoAAAABNAH1/////P///wH0////+////wYNAAAAAWUGDgAAAAFmAfH////7////BhAAAAABNwYRAAAAATgL" } };
- yield return new object[] { new object[] { s, new StructContainingArraysOfOtherStructs?(s) }, new string[] { "AAEAAAD/////AQAAAAAAAAAQAQAAAAIAAAAJAgAAAAkDAAAADAQAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUCAAAAUlN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5TdHJ1Y3RDb250YWluaW5nQXJyYXlzT2ZPdGhlclN0cnVjdHMBAAAABk5lc3RlZARMU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdENvbnRhaW5pbmdPdGhlclN0cnVjdHNbXQQAAAAEAAAACQUAAAABAwAAAAIAAAAJBQAAAAcFAAAAAAEAAAACAAAABEpTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0cwQAAAAF+v///0pTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0cwIAAAAHTmVzdGVkMQdOZXN0ZWQyBAREU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdFdpdGhTdHJpbmdGaWVsZHMEAAAARFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5TdHJ1Y3RXaXRoU3RyaW5nRmllbGRzBAAAAAQAAAAF+f///0RTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0V2l0aFN0cmluZ0ZpZWxkcwIAAAAHU3RyaW5nMQdTdHJpbmcyAQEEAAAABggAAAABYQYJAAAAAWIB9v////n///8GCwAAAAEzBgwAAAABNAHz////+v///wHy////+f///wYPAAAAAWUGEAAAAAFmAe/////5////BhIAAAABNwYTAAAAATgL", "AAEAAAD/////AQAAAAAAAAAQAQAAAAIAAAAJAgAAAAkDAAAADAQAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUCAAAAUlN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5TdHJ1Y3RDb250YWluaW5nQXJyYXlzT2ZPdGhlclN0cnVjdHMBAAAABk5lc3RlZARMU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdENvbnRhaW5pbmdPdGhlclN0cnVjdHNbXQQAAAAEAAAACQUAAAABAwAAAAIAAAAJBQAAAAcFAAAAAAEAAAACAAAABEpTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0cwQAAAAF+v///0pTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0cwIAAAAHTmVzdGVkMQdOZXN0ZWQyBAREU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdFdpdGhTdHJpbmdGaWVsZHMEAAAARFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5TdHJ1Y3RXaXRoU3RyaW5nRmllbGRzBAAAAAQAAAAF+f///0RTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0V2l0aFN0cmluZ0ZpZWxkcwIAAAAHU3RyaW5nMQdTdHJpbmcyAQEEAAAABggAAAABYQYJAAAAAWIB9v////n///8GCwAAAAEzBgwAAAABNAHz////+v///wHy////+f///wYPAAAAAWUGEAAAAAFmAe/////5////BhIAAAABNwYTAAAAATgL" } };
+ yield return new object[] { s, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABSU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdENvbnRhaW5pbmdBcnJheXNPZk90aGVyU3RydWN0cwEAAAAGTmVzdGVkBExTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0c1tdAgAAAAIAAAAJAwAAAAcDAAAAAAEAAAACAAAABEpTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0cwIAAAAF/P///0pTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0cwIAAAAHTmVzdGVkMQdOZXN0ZWQyBAREU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdFdpdGhTdHJpbmdGaWVsZHMCAAAARFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5TdHJ1Y3RXaXRoU3RyaW5nRmllbGRzAgAAAAIAAAAF+////0RTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0V2l0aFN0cmluZ0ZpZWxkcwIAAAAHU3RyaW5nMQdTdHJpbmcyAQECAAAABgYAAAABYQYHAAAAAWIB+P////v///8GCQAAAAEzBgoAAAABNAH1/////P///wH0////+////wYNAAAAAWUGDgAAAAFmAfH////7////BhAAAAABNwYRAAAAATgL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABSU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdENvbnRhaW5pbmdBcnJheXNPZk90aGVyU3RydWN0cwEAAAAGTmVzdGVkBExTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0c1tdAgAAAAIAAAAJAwAAAAcDAAAAAAEAAAACAAAABEpTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0cwIAAAAF/P///0pTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0cwIAAAAHTmVzdGVkMQdOZXN0ZWQyBAREU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdFdpdGhTdHJpbmdGaWVsZHMCAAAARFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5TdHJ1Y3RXaXRoU3RyaW5nRmllbGRzAgAAAAIAAAAF+////0RTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0V2l0aFN0cmluZ0ZpZWxkcwIAAAAHU3RyaW5nMQdTdHJpbmcyAQECAAAABgYAAAABYQYHAAAAAWIB+P////v///8GCQAAAAEzBgoAAAABNAH1/////P///wH0////+////wYNAAAAAWUGDgAAAAFmAfH////7////BhAAAAABNwYRAAAAATgL", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new object[] { s, new StructContainingArraysOfOtherStructs?(s) }, new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAQAQAAAAIAAAAJAgAAAAkDAAAADAQAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUCAAAAUlN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5TdHJ1Y3RDb250YWluaW5nQXJyYXlzT2ZPdGhlclN0cnVjdHMBAAAABk5lc3RlZARMU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdENvbnRhaW5pbmdPdGhlclN0cnVjdHNbXQQAAAAEAAAACQUAAAABAwAAAAIAAAAJBQAAAAcFAAAAAAEAAAACAAAABEpTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0cwQAAAAF+v///0pTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0cwIAAAAHTmVzdGVkMQdOZXN0ZWQyBAREU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdFdpdGhTdHJpbmdGaWVsZHMEAAAARFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5TdHJ1Y3RXaXRoU3RyaW5nRmllbGRzBAAAAAQAAAAF+f///0RTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0V2l0aFN0cmluZ0ZpZWxkcwIAAAAHU3RyaW5nMQdTdHJpbmcyAQEEAAAABggAAAABYQYJAAAAAWIB9v////n///8GCwAAAAEzBgwAAAABNAHz////+v///wHy////+f///wYPAAAAAWUGEAAAAAFmAe/////5////BhIAAAABNwYTAAAAATgL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAQAQAAAAIAAAAJAgAAAAkDAAAADAQAAABwU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLCBWZXJzaW9uPTQuMC4zLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49OWQ3N2NjN2FkMzliNjhlYgUCAAAAUlN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5TdHJ1Y3RDb250YWluaW5nQXJyYXlzT2ZPdGhlclN0cnVjdHMBAAAABk5lc3RlZARMU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdENvbnRhaW5pbmdPdGhlclN0cnVjdHNbXQQAAAAEAAAACQUAAAABAwAAAAIAAAAJBQAAAAcFAAAAAAEAAAACAAAABEpTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0cwQAAAAF+v///0pTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0Q29udGFpbmluZ090aGVyU3RydWN0cwIAAAAHTmVzdGVkMQdOZXN0ZWQyBAREU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLlN0cnVjdFdpdGhTdHJpbmdGaWVsZHMEAAAARFN5c3RlbS5SdW50aW1lLlNlcmlhbGl6YXRpb24uRm9ybWF0dGVycy5UZXN0cy5TdHJ1Y3RXaXRoU3RyaW5nRmllbGRzBAAAAAQAAAAF+f///0RTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMuU3RydWN0V2l0aFN0cmluZ0ZpZWxkcwIAAAAHU3RyaW5nMQdTdHJpbmcyAQEEAAAABggAAAABYQYJAAAAAWIB9v////n///8GCwAAAAEzBgwAAAABNAHz////+v///wHy////+f///wYPAAAAAWUGEAAAAAFmAe/////5////BhIAAAABNwYTAAAAATgL", TargetFrameworkMoniker.netfx461) } };
// ISerializable
- yield return new object[] { new BasicISerializableObject(1, "2"), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABGU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkJhc2ljSVNlcmlhbGl6YWJsZU9iamVjdAIAAAAGVmFsdWUxBlZhbHVlMgABCAIAAAABAAAABgMAAAABMgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABGU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkJhc2ljSVNlcmlhbGl6YWJsZU9iamVjdAIAAAAGVmFsdWUxBlZhbHVlMgABCAIAAAABAAAABgMAAAABMgs=" } };
- yield return new object[] { new DerivedISerializableWithNonPublicDeserializationCtor(1, "2"), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABiU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkRlcml2ZWRJU2VyaWFsaXphYmxlV2l0aE5vblB1YmxpY0Rlc2VyaWFsaXphdGlvbkN0b3ICAAAABlZhbHVlMQZWYWx1ZTIAAQgCAAAAAQAAAAYDAAAAATIL", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABiU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkRlcml2ZWRJU2VyaWFsaXphYmxlV2l0aE5vblB1YmxpY0Rlc2VyaWFsaXphdGlvbkN0b3ICAAAABlZhbHVlMQZWYWx1ZTIAAQgCAAAAAQAAAAYDAAAAATIL" } };
+ yield return new object[] { new BasicISerializableObject(1, "2"), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABGU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkJhc2ljSVNlcmlhbGl6YWJsZU9iamVjdAIAAAAGVmFsdWUxBlZhbHVlMgABCAIAAAABAAAABgMAAAABMgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABGU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkJhc2ljSVNlcmlhbGl6YWJsZU9iamVjdAIAAAAGVmFsdWUxBlZhbHVlMgABCAIAAAABAAAABgMAAAABMgs=", TargetFrameworkMoniker.netfx461) } };
+ yield return new object[] { new DerivedISerializableWithNonPublicDeserializationCtor(1, "2"), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABiU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkRlcml2ZWRJU2VyaWFsaXphYmxlV2l0aE5vblB1YmxpY0Rlc2VyaWFsaXphdGlvbkN0b3ICAAAABlZhbHVlMQZWYWx1ZTIAAQgCAAAAAQAAAAYDAAAAATIL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAABiU3lzdGVtLlJ1bnRpbWUuU2VyaWFsaXphdGlvbi5Gb3JtYXR0ZXJzLlRlc3RzLkRlcml2ZWRJU2VyaWFsaXphYmxlV2l0aE5vblB1YmxpY0Rlc2VyaWFsaXphdGlvbkN0b3ICAAAABlZhbHVlMQZWYWx1ZTIAAQgCAAAAAQAAAAYDAAAAATIL", TargetFrameworkMoniker.netfx461) } };
// Various other special cases
- yield return new object[] { new TypeWithoutNamespace(), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAAAUVHlwZVdpdGhvdXROYW1lc3BhY2UAAAAAAgAAAAs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAAAUVHlwZVdpdGhvdXROYW1lc3BhY2UAAAAAAgAAAAs=" } };
+ yield return new object[] { new TypeWithoutNamespace(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAAAUVHlwZVdpdGhvdXROYW1lc3BhY2UAAAAAAgAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAHBTeXN0ZW0uUnVudGltZS5TZXJpYWxpemF0aW9uLkZvcm1hdHRlcnMuVGVzdHMsIFZlcnNpb249NC4wLjMuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj05ZDc3Y2M3YWQzOWI2OGViBQEAAAAUVHlwZVdpdGhvdXROYW1lc3BhY2UAAAAAAgAAAAs=", TargetFrameworkMoniker.netfx461) } };
// System.DirectoryServices, System.Security.Principal and System.Security.AccessControl are only available on Windows.
// They are currently not supported on UAP
if (PlatformDetection.IsWindows && !PlatformDetection.IsUap)
{
var directoryNotFoundException = new DirectoryNotFoundException("message", exception);
- yield return new object[] { PopulateException(directoryNotFoundException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAACRTeXN0ZW0uSU8uRGlyZWN0b3J5Tm90Rm91bmRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAkU3lzdGVtLklPLkRpcmVjdG9yeU5vdEZvdW5kRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAACRTeXN0ZW0uSU8uRGlyZWN0b3J5Tm90Rm91bmRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAkU3lzdGVtLklPLkRpcmVjdG9yeU5vdEZvdW5kRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=" } };
+ yield return new object[] { PopulateException(directoryNotFoundException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACRTeXN0ZW0uSU8uRGlyZWN0b3J5Tm90Rm91bmRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAkU3lzdGVtLklPLkRpcmVjdG9yeU5vdEZvdW5kRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAACRTeXN0ZW0uSU8uRGlyZWN0b3J5Tm90Rm91bmRFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgIAAAAkU3lzdGVtLklPLkRpcmVjdG9yeU5vdEZvdW5kRXhjZXB0aW9uBgMAAAAHbWVzc2FnZQkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCgAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGCwAAABBTeXN0ZW0uRXhjZXB0aW9uCQMAAAAJDQAAAAkOAAAACQYAAAAJBwAAAAkIAAAAAAAAAAroAwAACQkAAAAKBAoAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhMAAAAGc2VjcmV0CAEBCRQAAAABDQAAAAQAAAAJFQAAAAIAAAACAAAAAQ4AAAAFAAAACQsAAAAGFwAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFAAAAAoAAAAICAEAAAAGGAAAAANvbmUKARUAAAAKAAAACRMAAAAIAQEJGgAAAAEaAAAACgAAAAgIAQAAAAkYAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var identityNotMappedException = new IdentityNotMappedException("message", exception);
- yield return new object[] { PopulateException(identityNotMappedException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAADRTeXN0ZW0uU2VjdXJpdHkuUHJpbmNpcGFsLklkZW50aXR5Tm90TWFwcGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAANFN5c3RlbS5TZWN1cml0eS5QcmluY2lwYWwuSWRlbnRpdHlOb3RNYXBwZWRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAADRTeXN0ZW0uU2VjdXJpdHkuUHJpbmNpcGFsLklkZW50aXR5Tm90TWFwcGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAANFN5c3RlbS5TZWN1cml0eS5QcmluY2lwYWwuSWRlbnRpdHlOb3RNYXBwZWRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==" } };
+ yield return new object[] { PopulateException(identityNotMappedException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADRTeXN0ZW0uU2VjdXJpdHkuUHJpbmNpcGFsLklkZW50aXR5Tm90TWFwcGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAANFN5c3RlbS5TZWN1cml0eS5QcmluY2lwYWwuSWRlbnRpdHlOb3RNYXBwZWRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADRTeXN0ZW0uU2VjdXJpdHkuUHJpbmNpcGFsLklkZW50aXR5Tm90TWFwcGVkRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAANFN5c3RlbS5TZWN1cml0eS5QcmluY2lwYWwuSWRlbnRpdHlOb3RNYXBwZWRFeGNlcHRpb24GAwAAAAdtZXNzYWdlCQQAAAAJBQAAAAYGAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GBwAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYIAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYJAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQEAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkKAAAAAgAAAAIAAAAEBQAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYLAAAAEFN5c3RlbS5FeGNlcHRpb24JAwAAAAkNAAAACQ4AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECgAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGEwAAAAZzZWNyZXQIAQEJFAAAAAENAAAABAAAAAkVAAAAAgAAAAIAAAABDgAAAAUAAAAJCwAAAAYXAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEUAAAACgAAAAgIAQAAAAYYAAAAA29uZQoBFQAAAAoAAAAJEwAAAAgBAQkaAAAAARoAAAAKAAAACAgBAAAACRgAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var privilegeNotHeldException = new PrivilegeNotHeldException("privilege", exception);
- yield return new object[] { PopulateException(privilegeNotHeldException), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAADdTeXN0ZW0uU2VjdXJpdHkuQWNjZXNzQ29udHJvbC5Qcml2aWxlZ2VOb3RIZWxkRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMNUHJpdmlsZWdlTmFtZQEBAwMBAQEAAQABBwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAN1N5c3RlbS5TZWN1cml0eS5BY2Nlc3NDb250cm9sLlByaXZpbGVnZU5vdEhlbGRFeGNlcHRpb24GAwAAAFxUaGUgcHJvY2VzcyBkb2VzIG5vdCBwb3NzZXNzIHRoZSAncHJpdmlsZWdlJyBwcml2aWxlZ2Ugd2hpY2ggaXMgcmVxdWlyZWQgZm9yIHRoaXMgb3BlcmF0aW9uLgkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoGCgAAAAlwcml2aWxlZ2UEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uBg0AAAAHbWVzc2FnZQkOAAAACQ8AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABAAAAAkWAAAAAgAAAAIAAAABDwAAAAUAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAEAQAAADdTeXN0ZW0uU2VjdXJpdHkuQWNjZXNzQ29udHJvbC5Qcml2aWxlZ2VOb3RIZWxkRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMNUHJpdmlsZWdlTmFtZQEBAwMBAQEAAQABBwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAN1N5c3RlbS5TZWN1cml0eS5BY2Nlc3NDb250cm9sLlByaXZpbGVnZU5vdEhlbGRFeGNlcHRpb24GAwAAAFxUaGUgcHJvY2VzcyBkb2VzIG5vdCBwb3NzZXNzIHRoZSAncHJpdmlsZWdlJyBwcml2aWxlZ2Ugd2hpY2ggaXMgcmVxdWlyZWQgZm9yIHRoaXMgb3BlcmF0aW9uLgkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoGCgAAAAlwcml2aWxlZ2UEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uBg0AAAAHbWVzc2FnZQkOAAAACQ8AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABAAAAAkWAAAAAgAAAAIAAAABDwAAAAUAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==" } };
+ yield return new object[] { PopulateException(privilegeNotHeldException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADdTeXN0ZW0uU2VjdXJpdHkuQWNjZXNzQ29udHJvbC5Qcml2aWxlZ2VOb3RIZWxkRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMNUHJpdmlsZWdlTmFtZQEBAwMBAQEAAQABBwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAN1N5c3RlbS5TZWN1cml0eS5BY2Nlc3NDb250cm9sLlByaXZpbGVnZU5vdEhlbGRFeGNlcHRpb24GAwAAAFxUaGUgcHJvY2VzcyBkb2VzIG5vdCBwb3NzZXNzIHRoZSAncHJpdmlsZWdlJyBwcml2aWxlZ2Ugd2hpY2ggaXMgcmVxdWlyZWQgZm9yIHRoaXMgb3BlcmF0aW9uLgkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoGCgAAAAlwcml2aWxlZ2UEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uBg0AAAAHbWVzc2FnZQkOAAAACQ8AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABAAAAAkWAAAAAgAAAAIAAAABDwAAAAUAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAADdTeXN0ZW0uU2VjdXJpdHkuQWNjZXNzQ29udHJvbC5Qcml2aWxlZ2VOb3RIZWxkRXhjZXB0aW9uDQAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMNUHJpdmlsZWdlTmFtZQEBAwMBAQEAAQABBwEpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYCAAAAN1N5c3RlbS5TZWN1cml0eS5BY2Nlc3NDb250cm9sLlByaXZpbGVnZU5vdEhlbGRFeGNlcHRpb24GAwAAAFxUaGUgcHJvY2VzcyBkb2VzIG5vdCBwb3NzZXNzIHRoZSAncHJpdmlsZWdlJyBwcml2aWxlZ2Ugd2hpY2ggaXMgcmVxdWlyZWQgZm9yIHRoaXMgb3BlcmF0aW9uLgkEAAAACQUAAAAGBgAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBgcAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCAAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCQAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoGCgAAAAlwcml2aWxlZ2UEBAAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAUAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uBg0AAAAHbWVzc2FnZQkOAAAACQ8AAAAJBgAAAAkHAAAACQgAAAAAAAAACugDAAAJCQAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABAAAAAkWAAAAAgAAAAIAAAABDwAAAAUAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
// Infrastructure issue where the netstandard dll is PNSE assembly but in full framework DirectoryServices should use the inbox assembly since they have the same identity.
// See: https://github.com/dotnet/corefx/issues/24903
if (!PlatformDetection.IsFullFramework)
{
var activeDirectoryOperationException = new ActiveDirectoryOperationException("message", exception, 0);
- yield return new object[] { PopulateException(activeDirectoryOperationException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABKU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5BY3RpdmVEaXJlY3RvcnlPcGVyYXRpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAASlN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5BY3RpdmVEaXJlY3RvcnkuQWN0aXZlRGlyZWN0b3J5T3BlcmF0aW9uRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABKU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5BY3RpdmVEaXJlY3RvcnlPcGVyYXRpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAASlN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5BY3RpdmVEaXJlY3RvcnkuQWN0aXZlRGlyZWN0b3J5T3BlcmF0aW9uRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=" } };
+ yield return new object[] { PopulateException(activeDirectoryOperationException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABKU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5BY3RpdmVEaXJlY3RvcnlPcGVyYXRpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAASlN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5BY3RpdmVEaXJlY3RvcnkuQWN0aXZlRGlyZWN0b3J5T3BlcmF0aW9uRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABKU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5BY3RpdmVEaXJlY3RvcnlPcGVyYXRpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAASlN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5BY3RpdmVEaXJlY3RvcnkuQWN0aXZlRGlyZWN0b3J5T3BlcmF0aW9uRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var activeDirectoryObjectNotFoundException = new ActiveDirectoryObjectNotFoundException("message", exception);
- yield return new object[] { PopulateException(activeDirectoryObjectNotFoundException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABPU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5BY3RpdmVEaXJlY3RvcnlPYmplY3ROb3RGb3VuZEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAABPU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5BY3RpdmVEaXJlY3RvcnlPYmplY3ROb3RGb3VuZEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABPU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5BY3RpdmVEaXJlY3RvcnlPYmplY3ROb3RGb3VuZEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAABPU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5BY3RpdmVEaXJlY3RvcnlPYmplY3ROb3RGb3VuZEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL" } };
+ yield return new object[] { PopulateException(activeDirectoryObjectNotFoundException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABPU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5BY3RpdmVEaXJlY3RvcnlPYmplY3ROb3RGb3VuZEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAABPU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5BY3RpdmVEaXJlY3RvcnlPYmplY3ROb3RGb3VuZEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABPU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5BY3RpdmVEaXJlY3RvcnlPYmplY3ROb3RGb3VuZEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAABPU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5BY3RpdmVEaXJlY3RvcnlPYmplY3ROb3RGb3VuZEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netfx461) } };
var activeDirectoryObjectExistsException = new ActiveDirectoryObjectExistsException("message", exception);
- yield return new object[] { PopulateException(activeDirectoryObjectExistsException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABNU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5BY3RpdmVEaXJlY3RvcnlPYmplY3RFeGlzdHNFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAATVN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5BY3RpdmVEaXJlY3RvcnkuQWN0aXZlRGlyZWN0b3J5T2JqZWN0RXhpc3RzRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABNU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5BY3RpdmVEaXJlY3RvcnlPYmplY3RFeGlzdHNFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAATVN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5BY3RpdmVEaXJlY3RvcnkuQWN0aXZlRGlyZWN0b3J5T2JqZWN0RXhpc3RzRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=" } };
+ yield return new object[] { PopulateException(activeDirectoryObjectExistsException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABNU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5BY3RpdmVEaXJlY3RvcnlPYmplY3RFeGlzdHNFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAATVN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5BY3RpdmVEaXJlY3RvcnkuQWN0aXZlRGlyZWN0b3J5T2JqZWN0RXhpc3RzRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABNU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5BY3RpdmVEaXJlY3RvcnlPYmplY3RFeGlzdHNFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAATVN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5BY3RpdmVEaXJlY3RvcnkuQWN0aXZlRGlyZWN0b3J5T2JqZWN0RXhpc3RzRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var directoryException = new DirectoryException("message", exception);
- yield return new object[] { PopulateException(directoryException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAGVTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAANVN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5Qcm90b2NvbHMuRGlyZWN0b3J5RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADVTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLkRpcmVjdG9yeUV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAGVTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAANVN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5Qcm90b2NvbHMuRGlyZWN0b3J5RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADVTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLkRpcmVjdG9yeUV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL" } };
+ yield return new object[] { PopulateException(directoryException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAGVTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAANVN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5Qcm90b2NvbHMuRGlyZWN0b3J5RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADVTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLkRpcmVjdG9yeUV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAGVTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAANVN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5Qcm90b2NvbHMuRGlyZWN0b3J5RXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADVTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLkRpcmVjdG9yeUV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netfx461) } };
var directoryOperationException = new DirectoryOperationException("message", exception);
- yield return new object[] { PopulateException(directoryOperationException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAGVTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAAPlN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5Qcm90b2NvbHMuRGlyZWN0b3J5T3BlcmF0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAD5TeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLkRpcmVjdG9yeU9wZXJhdGlvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAGVTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAAPlN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5Qcm90b2NvbHMuRGlyZWN0b3J5T3BlcmF0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAD5TeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLkRpcmVjdG9yeU9wZXJhdGlvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL" } };
+ yield return new object[] { PopulateException(directoryOperationException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAGVTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAAPlN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5Qcm90b2NvbHMuRGlyZWN0b3J5T3BlcmF0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAD5TeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLkRpcmVjdG9yeU9wZXJhdGlvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAGVTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAAPlN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5Qcm90b2NvbHMuRGlyZWN0b3J5T3BlcmF0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAD5TeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLkRpcmVjdG9yeU9wZXJhdGlvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netfx461) } };
var directoryServicesCOMException = new DirectoryServicesCOMException("message", exception);
- yield return new object[] { PopulateException(directoryServicesCOMException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAAA2U3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkRpcmVjdG9yeVNlcnZpY2VzQ09NRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADZTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuRGlyZWN0b3J5U2VydmljZXNDT01FeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAAA2U3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkRpcmVjdG9yeVNlcnZpY2VzQ09NRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADZTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuRGlyZWN0b3J5U2VydmljZXNDT01FeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==" } };
+ yield return new object[] { PopulateException(directoryServicesCOMException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAAA2U3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkRpcmVjdG9yeVNlcnZpY2VzQ09NRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADZTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuRGlyZWN0b3J5U2VydmljZXNDT01FeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAAA2U3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkRpcmVjdG9yeVNlcnZpY2VzQ09NRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADZTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuRGlyZWN0b3J5U2VydmljZXNDT01FeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var ldapException = new LdapException("message", exception);
- yield return new object[] { PopulateException(ldapException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAGVTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAAMFN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5Qcm90b2NvbHMuTGRhcEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAwU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLlByb3RvY29scy5MZGFwRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAGVTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAAMFN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5Qcm90b2NvbHMuTGRhcEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAwU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLlByb3RvY29scy5MZGFwRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=" } };
+ yield return new object[] { PopulateException(ldapException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAGVTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAAMFN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5Qcm90b2NvbHMuTGRhcEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAwU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLlByb3RvY29scy5MZGFwRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAGVTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAAMFN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5Qcm90b2NvbHMuTGRhcEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAAAwU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLlByb3RvY29scy5MZGFwRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netfx461) } };
var tlsOperationException = new TlsOperationException("message", exception);
- yield return new object[] { PopulateException(tlsOperationException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAGVTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAAOFN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5Qcm90b2NvbHMuVGxzT3BlcmF0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADhTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLlRsc09wZXJhdGlvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAGVTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAAOFN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5Qcm90b2NvbHMuVGxzT3BlcmF0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADhTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLlRsc09wZXJhdGlvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL" } };
+ yield return new object[] { PopulateException(tlsOperationException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAGVTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAAOFN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5Qcm90b2NvbHMuVGxzT3BlcmF0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADhTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLlRsc09wZXJhdGlvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAGVTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUBAAAAOFN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5Qcm90b2NvbHMuVGxzT3BlcmF0aW9uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAADhTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuUHJvdG9jb2xzLlRsc09wZXJhdGlvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netfx461) } };
var principalExistsException = new PrincipalExistsException("message", exception);
- yield return new object[] { PopulateException(principalExistsException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAG1TeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuQWNjb3VudE1hbmFnZW1lbnQsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAABDU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjY291bnRNYW5hZ2VtZW50LlByaW5jaXBhbEV4aXN0c0V4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAABDU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjY291bnRNYW5hZ2VtZW50LlByaW5jaXBhbEV4aXN0c0V4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAG1TeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuQWNjb3VudE1hbmFnZW1lbnQsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAABDU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjY291bnRNYW5hZ2VtZW50LlByaW5jaXBhbEV4aXN0c0V4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAABDU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjY291bnRNYW5hZ2VtZW50LlByaW5jaXBhbEV4aXN0c0V4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL" } };
+ yield return new object[] { PopulateException(principalExistsException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAG1TeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuQWNjb3VudE1hbmFnZW1lbnQsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAABDU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjY291bnRNYW5hZ2VtZW50LlByaW5jaXBhbEV4aXN0c0V4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAABDU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjY291bnRNYW5hZ2VtZW50LlByaW5jaXBhbEV4aXN0c0V4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAG1TeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuQWNjb3VudE1hbmFnZW1lbnQsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAABDU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjY291bnRNYW5hZ2VtZW50LlByaW5jaXBhbEV4aXN0c0V4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAABDU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjY291bnRNYW5hZ2VtZW50LlByaW5jaXBhbEV4aXN0c0V4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netfx461) } };
var principalOperationException = new PrincipalOperationException("message", exception, 200);
- yield return new object[] { PopulateException(principalOperationException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAG1TeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuQWNjb3VudE1hbmFnZW1lbnQsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAABGU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjY291bnRNYW5hZ2VtZW50LlByaW5jaXBhbE9wZXJhdGlvbkV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCWVycm9yQ29kZQEBAwMBAQEAAQABBwApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAggCAAAABgMAAABGU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjY291bnRNYW5hZ2VtZW50LlByaW5jaXBhbE9wZXJhdGlvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKyAAAAAQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAG1TeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuQWNjb3VudE1hbmFnZW1lbnQsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAABGU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjY291bnRNYW5hZ2VtZW50LlByaW5jaXBhbE9wZXJhdGlvbkV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCWVycm9yQ29kZQEBAwMBAQEAAQABBwApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAggCAAAABgMAAABGU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjY291bnRNYW5hZ2VtZW50LlByaW5jaXBhbE9wZXJhdGlvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKyAAAAAQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==" } };
+ yield return new object[] { PopulateException(principalOperationException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAG1TeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuQWNjb3VudE1hbmFnZW1lbnQsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAABGU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjY291bnRNYW5hZ2VtZW50LlByaW5jaXBhbE9wZXJhdGlvbkV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCWVycm9yQ29kZQEBAwMBAQEAAQABBwApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAggCAAAABgMAAABGU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjY291bnRNYW5hZ2VtZW50LlByaW5jaXBhbE9wZXJhdGlvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKyAAAAAQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAG1TeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuQWNjb3VudE1hbmFnZW1lbnQsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAABGU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjY291bnRNYW5hZ2VtZW50LlByaW5jaXBhbE9wZXJhdGlvbkV4Y2VwdGlvbg0AAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzCWVycm9yQ29kZQEBAwMBAQEAAQABBwApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAggCAAAABgMAAABGU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjY291bnRNYW5hZ2VtZW50LlByaW5jaXBhbE9wZXJhdGlvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKyAAAAAQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var principalServerDownException = new PrincipalServerDownException("message", exception, 200, "localhost");
- yield return new object[] { PopulateException(principalServerDownException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAG1TeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuQWNjb3VudE1hbmFnZW1lbnQsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAABHU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjY291bnRNYW5hZ2VtZW50LlByaW5jaXBhbFNlcnZlckRvd25FeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwllcnJvckNvZGUKc2VydmVyTmFtZQEBAwMBAQEAAQABBwABKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIIAgAAAAYDAAAAR1N5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5BY2NvdW50TWFuYWdlbWVudC5QcmluY2lwYWxTZXJ2ZXJEb3duRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwrIAAAABgsAAAAJbG9jYWxob3N0BAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQwAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBg0AAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ8AAAAJEAAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQMAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYVAAAABnNlY3JldAgBAQkWAAAAAQ8AAAAFAAAACRcAAAACAAAAAgAAAAEQAAAABgAAAAkNAAAABhkAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARYAAAAMAAAACAgBAAAABhoAAAADb25lCgEXAAAADAAAAAkVAAAACAEBCRwAAAABHAAAAAwAAAAICAEAAAAJGgAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAG1TeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuQWNjb3VudE1hbmFnZW1lbnQsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAABHU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjY291bnRNYW5hZ2VtZW50LlByaW5jaXBhbFNlcnZlckRvd25FeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwllcnJvckNvZGUKc2VydmVyTmFtZQEBAwMBAQEAAQABBwABKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIIAgAAAAYDAAAAR1N5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5BY2NvdW50TWFuYWdlbWVudC5QcmluY2lwYWxTZXJ2ZXJEb3duRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwrIAAAABgsAAAAJbG9jYWxob3N0BAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQwAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBg0AAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ8AAAAJEAAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQMAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYVAAAABnNlY3JldAgBAQkWAAAAAQ8AAAAFAAAACRcAAAACAAAAAgAAAAEQAAAABgAAAAkNAAAABhkAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARYAAAAMAAAACAgBAAAABhoAAAADb25lCgEXAAAADAAAAAkVAAAACAEBCRwAAAABHAAAAAwAAAAICAEAAAAJGgAAAAoL" } };
+ yield return new object[] { PopulateException(principalServerDownException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAG1TeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuQWNjb3VudE1hbmFnZW1lbnQsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAABHU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjY291bnRNYW5hZ2VtZW50LlByaW5jaXBhbFNlcnZlckRvd25FeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwllcnJvckNvZGUKc2VydmVyTmFtZQEBAwMBAQEAAQABBwABKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIIAgAAAAYDAAAAR1N5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5BY2NvdW50TWFuYWdlbWVudC5QcmluY2lwYWxTZXJ2ZXJEb3duRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwrIAAAABgsAAAAJbG9jYWxob3N0BAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQwAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBg0AAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ8AAAAJEAAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQMAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYVAAAABnNlY3JldAgBAQkWAAAAAQ8AAAAFAAAACRcAAAACAAAAAgAAAAEQAAAABgAAAAkNAAAABhkAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARYAAAAMAAAACAgBAAAABhoAAAADb25lCgEXAAAADAAAAAkVAAAACAEBCRwAAAABHAAAAAwAAAAICAEAAAAJGgAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAG1TeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuQWNjb3VudE1hbmFnZW1lbnQsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAABHU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjY291bnRNYW5hZ2VtZW50LlByaW5jaXBhbFNlcnZlckRvd25FeGNlcHRpb24OAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwllcnJvckNvZGUKc2VydmVyTmFtZQEBAwMBAQEAAQABBwABKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIIAgAAAAYDAAAAR1N5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5BY2NvdW50TWFuYWdlbWVudC5QcmluY2lwYWxTZXJ2ZXJEb3duRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwrIAAAABgsAAAAJbG9jYWxob3N0BAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQwAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBg0AAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ8AAAAJEAAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQMAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYVAAAABnNlY3JldAgBAQkWAAAAAQ8AAAAFAAAACRcAAAACAAAAAgAAAAEQAAAABgAAAAkNAAAABhkAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARYAAAAMAAAACAgBAAAABhoAAAADb25lCgEXAAAADAAAAAkVAAAACAEBCRwAAAABHAAAAAwAAAAICAEAAAAJGgAAAAoL", TargetFrameworkMoniker.netfx461) } };
var activeDirectoryServerDownException = new ActiveDirectoryServerDownException("message", exception, 0, "name");
- yield return new object[] { PopulateException(activeDirectoryServerDownException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABLU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5BY3RpdmVEaXJlY3RvcnlTZXJ2ZXJEb3duRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAEtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuQWN0aXZlRGlyZWN0b3J5LkFjdGl2ZURpcmVjdG9yeVNlcnZlckRvd25FeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", "AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABLU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5BY3RpdmVEaXJlY3RvcnlTZXJ2ZXJEb3duRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAEtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuQWN0aXZlRGlyZWN0b3J5LkFjdGl2ZURpcmVjdG9yeVNlcnZlckRvd25FeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==" } };
+ yield return new object[] { PopulateException(activeDirectoryServerDownException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABLU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5BY3RpdmVEaXJlY3RvcnlTZXJ2ZXJEb3duRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAEtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuQWN0aXZlRGlyZWN0b3J5LkFjdGl2ZURpcmVjdG9yeVNlcnZlckRvd25FeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABLU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5BY3RpdmVEaXJlY3RvcnlTZXJ2ZXJEb3duRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgIAAAAGAwAAAEtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMuQWN0aXZlRGlyZWN0b3J5LkFjdGl2ZURpcmVjdG9yeVNlcnZlckRvd25FeGNlcHRpb24GBAAAAAdtZXNzYWdlCQUAAAAJBgAAAAYHAAAAGWh0dHA6Ly9tc2RuLm1pY3Jvc29mdC5jb20GCAAAABRTdGFja1RyYWNlIHN0cmluZy4uLgYJAAAAG1JlbW90ZSBTdGFja1RyYWNlIHN0cmluZy4uLgAAAAAK6AMAAAYKAAAAF0V4Y2VwdGlvbl9DbGFzc19TYW1wbGVzCgQFAAAAKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsAwAAAARoZWFkB3ZlcnNpb24FY291bnQDAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUICAkLAAAAAgAAAAIAAAAEBgAAABBTeXN0ZW0uRXhjZXB0aW9uDAAAAAlDbGFzc05hbWUHTWVzc2FnZQREYXRhDklubmVyRXhjZXB0aW9uB0hlbHBVUkwQU3RhY2tUcmFjZVN0cmluZxZSZW1vdGVTdGFja1RyYWNlU3RyaW5nEFJlbW90ZVN0YWNrSW5kZXgPRXhjZXB0aW9uTWV0aG9kB0hSZXN1bHQGU291cmNlDVdhdHNvbkJ1Y2tldHMBAQMDAQEBAAEAAQcpU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwQU3lzdGVtLkV4Y2VwdGlvbggIAgYMAAAAEFN5c3RlbS5FeGNlcHRpb24JBAAAAAkOAAAACQ8AAAAJBwAAAAkIAAAACQkAAAAAAAAACugDAAAJCgAAAAoECwAAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQMAAAADa2V5BXZhbHVlBG5leHQCAgM4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUGFAAAAAZzZWNyZXQIAQEJFQAAAAEOAAAABQAAAAkWAAAAAgAAAAIAAAABDwAAAAYAAAAJDAAAAAYYAAAAF0lubmVyIGV4Y2VwdGlvbiBtZXNzYWdlCgoKCgoAAAAACgAVE4AKCgEVAAAACwAAAAgIAQAAAAYZAAAAA29uZQoBFgAAAAsAAAAJFAAAAAgBAQkbAAAAARsAAAALAAAACAgBAAAACRkAAAAKCw==", TargetFrameworkMoniker.netfx461) } };
var forestTrustCollisionException = new ForestTrustCollisionException("message", exception);
- yield return new object[] { PopulateException(forestTrustCollisionException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABGU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5Gb3Jlc3RUcnVzdENvbGxpc2lvbkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAABGU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5Gb3Jlc3RUcnVzdENvbGxpc2lvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABGU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5Gb3Jlc3RUcnVzdENvbGxpc2lvbkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAABGU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5Gb3Jlc3RUcnVzdENvbGxpc2lvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL" } };
+ yield return new object[] { PopulateException(forestTrustCollisionException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABGU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5Gb3Jlc3RUcnVzdENvbGxpc2lvbkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAABGU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5Gb3Jlc3RUcnVzdENvbGxpc2lvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABGU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5Gb3Jlc3RUcnVzdENvbGxpc2lvbkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAABGU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5Gb3Jlc3RUcnVzdENvbGxpc2lvbkV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netfx461) } };
var syncFromAllServersOperationException = new SyncFromAllServersOperationException("message", exception);
- yield return new object[] { PopulateException(syncFromAllServersOperationException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABNU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5TeW5jRnJvbUFsbFNlcnZlcnNPcGVyYXRpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAATVN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5BY3RpdmVEaXJlY3RvcnkuU3luY0Zyb21BbGxTZXJ2ZXJzT3BlcmF0aW9uRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABNU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5TeW5jRnJvbUFsbFNlcnZlcnNPcGVyYXRpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAATVN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5BY3RpdmVEaXJlY3RvcnkuU3luY0Zyb21BbGxTZXJ2ZXJzT3BlcmF0aW9uRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=" } };
+ yield return new object[] { PopulateException(syncFromAllServersOperationException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABNU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5TeW5jRnJvbUFsbFNlcnZlcnNPcGVyYXRpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAATVN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5BY3RpdmVEaXJlY3RvcnkuU3luY0Zyb21BbGxTZXJ2ZXJzT3BlcmF0aW9uRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAFtTeXN0ZW0uRGlyZWN0b3J5U2VydmljZXMsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABNU3lzdGVtLkRpcmVjdG9yeVNlcnZpY2VzLkFjdGl2ZURpcmVjdG9yeS5TeW5jRnJvbUFsbFNlcnZlcnNPcGVyYXRpb25FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAATVN5c3RlbS5EaXJlY3RvcnlTZXJ2aWNlcy5BY3RpdmVEaXJlY3RvcnkuU3luY0Zyb21BbGxTZXJ2ZXJzT3BlcmF0aW9uRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netfx461) } };
}
}
@@ -1404,10 +1405,10 @@ namespace System.Runtime.Serialization.Formatters.Tests
if (!PlatformDetection.IsFullFramework)
{
var compositionContractMismatchException = new CompositionContractMismatchException("message", exception);
- yield return new object[] { PopulateException(compositionContractMismatchException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAGRTeXN0ZW0uQ29tcG9uZW50TW9kZWwuQ29tcG9zaXRpb24sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABGU3lzdGVtLkNvbXBvbmVudE1vZGVsLkNvbXBvc2l0aW9uLkNvbXBvc2l0aW9uQ29udHJhY3RNaXNtYXRjaEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAABGU3lzdGVtLkNvbXBvbmVudE1vZGVsLkNvbXBvc2l0aW9uLkNvbXBvc2l0aW9uQ29udHJhY3RNaXNtYXRjaEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", "AAEAAAD/////AQAAAAAAAAAMAgAAAGRTeXN0ZW0uQ29tcG9uZW50TW9kZWwuQ29tcG9zaXRpb24sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAABGU3lzdGVtLkNvbXBvbmVudE1vZGVsLkNvbXBvc2l0aW9uLkNvbXBvc2l0aW9uQ29udHJhY3RNaXNtYXRjaEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAABGU3lzdGVtLkNvbXBvbmVudE1vZGVsLkNvbXBvc2l0aW9uLkNvbXBvc2l0aW9uQ29udHJhY3RNaXNtYXRjaEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL" } };
+ yield return new object[] { PopulateException(compositionContractMismatchException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAGRTeXN0ZW0uQ29tcG9uZW50TW9kZWwuQ29tcG9zaXRpb24sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABGU3lzdGVtLkNvbXBvbmVudE1vZGVsLkNvbXBvc2l0aW9uLkNvbXBvc2l0aW9uQ29udHJhY3RNaXNtYXRjaEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAABGU3lzdGVtLkNvbXBvbmVudE1vZGVsLkNvbXBvc2l0aW9uLkNvbXBvc2l0aW9uQ29udHJhY3RNaXNtYXRjaEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAGRTeXN0ZW0uQ29tcG9uZW50TW9kZWwuQ29tcG9zaXRpb24sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAABGU3lzdGVtLkNvbXBvbmVudE1vZGVsLkNvbXBvc2l0aW9uLkNvbXBvc2l0aW9uQ29udHJhY3RNaXNtYXRjaEV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAICAAAABgMAAABGU3lzdGVtLkNvbXBvbmVudE1vZGVsLkNvbXBvc2l0aW9uLkNvbXBvc2l0aW9uQ29udHJhY3RNaXNtYXRjaEV4Y2VwdGlvbgYEAAAAB21lc3NhZ2UJBQAAAAkGAAAABgcAAAAZaHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbQYIAAAAFFN0YWNrVHJhY2Ugc3RyaW5nLi4uBgkAAAAbUmVtb3RlIFN0YWNrVHJhY2Ugc3RyaW5nLi4uAAAAAAroAwAABgoAAAAXRXhjZXB0aW9uX0NsYXNzX1NhbXBsZXMKBAUAAAApU3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwDAAAABGhlYWQHdmVyc2lvbgVjb3VudAMAADhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQgICQsAAAACAAAAAgAAAAQGAAAAEFN5c3RlbS5FeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCBgwAAAAQU3lzdGVtLkV4Y2VwdGlvbgkEAAAACQ4AAAAJDwAAAAkHAAAACQgAAAAJCQAAAAAAAAAK6AMAAAkKAAAACgQLAAAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlAwAAAANrZXkFdmFsdWUEbmV4dAICAzhTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbCtEaWN0aW9uYXJ5Tm9kZQYUAAAABnNlY3JldAgBAQkVAAAAAQ4AAAAFAAAACRYAAAACAAAAAgAAAAEPAAAABgAAAAkMAAAABhgAAAAXSW5uZXIgZXhjZXB0aW9uIG1lc3NhZ2UKCgoKCgAAAAAKABUTgAoKARUAAAALAAAACAgBAAAABhkAAAADb25lCgEWAAAACwAAAAkUAAAACAEBCRsAAAABGwAAAAsAAAAICAEAAAAJGQAAAAoL", TargetFrameworkMoniker.netfx461) } };
var importCardinalityMismatchException = new ImportCardinalityMismatchException("message", exception);
- yield return new object[] { PopulateException(importCardinalityMismatchException), new string[] { "AAEAAAD/////AQAAAAAAAAAMAgAAAGRTeXN0ZW0uQ29tcG9uZW50TW9kZWwuQ29tcG9zaXRpb24sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABEU3lzdGVtLkNvbXBvbmVudE1vZGVsLkNvbXBvc2l0aW9uLkltcG9ydENhcmRpbmFsaXR5TWlzbWF0Y2hFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAARFN5c3RlbS5Db21wb25lbnRNb2RlbC5Db21wb3NpdGlvbi5JbXBvcnRDYXJkaW5hbGl0eU1pc21hdGNoRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", "AAEAAAD/////AQAAAAAAAAAMAgAAAGRTeXN0ZW0uQ29tcG9uZW50TW9kZWwuQ29tcG9zaXRpb24sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAABEU3lzdGVtLkNvbXBvbmVudE1vZGVsLkNvbXBvc2l0aW9uLkltcG9ydENhcmRpbmFsaXR5TWlzbWF0Y2hFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAARFN5c3RlbS5Db21wb25lbnRNb2RlbC5Db21wb3NpdGlvbi5JbXBvcnRDYXJkaW5hbGl0eU1pc21hdGNoRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=" } };
+ yield return new object[] { PopulateException(importCardinalityMismatchException), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAGRTeXN0ZW0uQ29tcG9uZW50TW9kZWwuQ29tcG9zaXRpb24sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhBQEAAABEU3lzdGVtLkNvbXBvbmVudE1vZGVsLkNvbXBvc2l0aW9uLkltcG9ydENhcmRpbmFsaXR5TWlzbWF0Y2hFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAARFN5c3RlbS5Db21wb25lbnRNb2RlbC5Db21wb3NpdGlvbi5JbXBvcnRDYXJkaW5hbGl0eU1pc21hdGNoRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAMAgAAAGRTeXN0ZW0uQ29tcG9uZW50TW9kZWwuQ29tcG9zaXRpb24sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAABEU3lzdGVtLkNvbXBvbmVudE1vZGVsLkNvbXBvc2l0aW9uLkltcG9ydENhcmRpbmFsaXR5TWlzbWF0Y2hFeGNlcHRpb24MAAAACUNsYXNzTmFtZQdNZXNzYWdlBERhdGEOSW5uZXJFeGNlcHRpb24HSGVscFVSTBBTdGFja1RyYWNlU3RyaW5nFlJlbW90ZVN0YWNrVHJhY2VTdHJpbmcQUmVtb3RlU3RhY2tJbmRleA9FeGNlcHRpb25NZXRob2QHSFJlc3VsdAZTb3VyY2UNV2F0c29uQnVja2V0cwEBAwMBAQEAAQABBylTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbBBTeXN0ZW0uRXhjZXB0aW9uCAgCAgAAAAYDAAAARFN5c3RlbS5Db21wb25lbnRNb2RlbC5Db21wb3NpdGlvbi5JbXBvcnRDYXJkaW5hbGl0eU1pc21hdGNoRXhjZXB0aW9uBgQAAAAHbWVzc2FnZQkFAAAACQYAAAAGBwAAABlodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tBggAAAAUU3RhY2tUcmFjZSBzdHJpbmcuLi4GCQAAABtSZW1vdGUgU3RhY2tUcmFjZSBzdHJpbmcuLi4AAAAACugDAAAGCgAAABdFeGNlcHRpb25fQ2xhc3NfU2FtcGxlcwoEBQAAAClTeXN0ZW0uQ29sbGVjdGlvbnMuTGlzdERpY3Rpb25hcnlJbnRlcm5hbAMAAAAEaGVhZAd2ZXJzaW9uBWNvdW50AwAAOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlCAgJCwAAAAIAAAACAAAABAYAAAAQU3lzdGVtLkV4Y2VwdGlvbgwAAAAJQ2xhc3NOYW1lB01lc3NhZ2UERGF0YQ5Jbm5lckV4Y2VwdGlvbgdIZWxwVVJMEFN0YWNrVHJhY2VTdHJpbmcWUmVtb3RlU3RhY2tUcmFjZVN0cmluZxBSZW1vdGVTdGFja0luZGV4D0V4Y2VwdGlvbk1ldGhvZAdIUmVzdWx0BlNvdXJjZQ1XYXRzb25CdWNrZXRzAQEDAwEBAQABAAEHKVN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsEFN5c3RlbS5FeGNlcHRpb24ICAIGDAAAABBTeXN0ZW0uRXhjZXB0aW9uCQQAAAAJDgAAAAkPAAAACQcAAAAJCAAAAAkJAAAAAAAAAAroAwAACQoAAAAKBAsAAAA4U3lzdGVtLkNvbGxlY3Rpb25zLkxpc3REaWN0aW9uYXJ5SW50ZXJuYWwrRGljdGlvbmFyeU5vZGUDAAAAA2tleQV2YWx1ZQRuZXh0AgIDOFN5c3RlbS5Db2xsZWN0aW9ucy5MaXN0RGljdGlvbmFyeUludGVybmFsK0RpY3Rpb25hcnlOb2RlBhQAAAAGc2VjcmV0CAEBCRUAAAABDgAAAAUAAAAJFgAAAAIAAAACAAAAAQ8AAAAGAAAACQwAAAAGGAAAABdJbm5lciBleGNlcHRpb24gbWVzc2FnZQoKCgoKAAAAAAoAFROACgoBFQAAAAsAAAAICAEAAAAGGQAAAANvbmUKARYAAAALAAAACRQAAAAIAQEJGwAAAAEbAAAACwAAAAgIAQAAAAkZAAAACgs=", TargetFrameworkMoniker.netfx461) } };
}
// Extension of core serializable types
@@ -1415,15 +1416,15 @@ namespace System.Runtime.Serialization.Formatters.Tests
if (!PlatformDetection.IsFullFramework/* ? PlatformDetection.IsNetfx471OrNewer : true*/)
{
// ValueType isn't serializable before net471.
- yield return new object[] { new ValueTuple(), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAABFTeXN0ZW0uVmFsdWVUdXBsZQAAAAAL", "AAEAAAD/////AQAAAAAAAAAEAQAAABFTeXN0ZW0uVmFsdWVUdXBsZQAAAAAL" } };
- yield return new object[] { ValueTuple.Create(1), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAHBTeXN0ZW0uVmFsdWVUdXBsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAAVJdGVtMQAIAQAAAAs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAHBTeXN0ZW0uVmFsdWVUdXBsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAAVJdGVtMQAIAQAAAAs=" } };
- yield return new object[] { ValueTuple.Create(1, "2"), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAM0BU3lzdGVtLlZhbHVlVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAFSXRlbTEFSXRlbTIAAQgBAAAABgIAAAABMgs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAM0BU3lzdGVtLlZhbHVlVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAFSXRlbTEFSXRlbTIAAQgBAAAABgIAAAABMgs=" } };
- yield return new object[] { ValueTuple.Create(1, "2", 3u), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAKoCU3lzdGVtLlZhbHVlVHVwbGVgM1tbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVUludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAFSXRlbTEFSXRlbTIFSXRlbTMAAQAIDwEAAAAGAgAAAAEyAwAAAAs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAKoCU3lzdGVtLlZhbHVlVHVwbGVgM1tbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVUludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAFSXRlbTEFSXRlbTIFSXRlbTMAAQAIDwEAAAAGAgAAAAEyAwAAAAs=" } };
- yield return new object[] { ValueTuple.Create(1, "2", 3u, 4L), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAIYDU3lzdGVtLlZhbHVlVHVwbGVgNFtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVUludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50NjQsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAVJdGVtMQVJdGVtMgVJdGVtMwVJdGVtNAABAAAIDwkBAAAABgIAAAABMgMAAAAEAAAAAAAAAAs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAIYDU3lzdGVtLlZhbHVlVHVwbGVgNFtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVUludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50NjQsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAVJdGVtMQVJdGVtMgVJdGVtMwVJdGVtNAABAAAIDwkBAAAABgIAAAABMgMAAAAEAAAAAAAAAAs=" } };
- yield return new object[] { ValueTuple.Create(1, "2", 3u, 4L, 5.6), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAOMDU3lzdGVtLlZhbHVlVHVwbGVgNVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVUludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50NjQsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5Eb3VibGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBQAAAAVJdGVtMQVJdGVtMgVJdGVtMwVJdGVtNAVJdGVtNQABAAAACA8JBgEAAAAGAgAAAAEyAwAAAAQAAAAAAAAAZmZmZmZmFkAL", "AAEAAAD/////AQAAAAAAAAAEAQAAAOMDU3lzdGVtLlZhbHVlVHVwbGVgNVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVUludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50NjQsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5Eb3VibGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBQAAAAVJdGVtMQVJdGVtMgVJdGVtMwVJdGVtNAVJdGVtNQABAAAACA8JBgEAAAAGAgAAAAEyAwAAAAQAAAAAAAAAZmZmZmZmFkAL" } };
- yield return new object[] { ValueTuple.Create(1, "2", 3u, 4L, 5.6, 7.8f), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAMAEU3lzdGVtLlZhbHVlVHVwbGVgNltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVUludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50NjQsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5Eb3VibGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TaW5nbGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBgAAAAVJdGVtMQVJdGVtMgVJdGVtMwVJdGVtNAVJdGVtNQVJdGVtNgABAAAAAAgPCQYLAQAAAAYCAAAAATIDAAAABAAAAAAAAABmZmZmZmYWQJqZ+UAL", "AAEAAAD/////AQAAAAAAAAAEAQAAAMAEU3lzdGVtLlZhbHVlVHVwbGVgNltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVUludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50NjQsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5Eb3VibGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TaW5nbGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBgAAAAVJdGVtMQVJdGVtMgVJdGVtMwVJdGVtNAVJdGVtNQVJdGVtNgABAAAAAAgPCQYLAQAAAAYCAAAAATIDAAAABAAAAAAAAABmZmZmZmYWQJqZ+UAL" } };
- yield return new object[] { ValueTuple.Create(1, "2", 3u, 4L, 5.6, 7.8f, 9m), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAJ4FU3lzdGVtLlZhbHVlVHVwbGVgN1tbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVUludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50NjQsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5Eb3VibGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TaW5nbGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5EZWNpbWFsLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQcAAAAFSXRlbTEFSXRlbTIFSXRlbTMFSXRlbTQFSXRlbTUFSXRlbTYFSXRlbTcAAQAAAAAACA8JBgsFAQAAAAYCAAAAATIDAAAABAAAAAAAAABmZmZmZmYWQJqZ+UABOQs=", "AAEAAAD/////AQAAAAAAAAAEAQAAAJ4FU3lzdGVtLlZhbHVlVHVwbGVgN1tbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVUludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50NjQsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5Eb3VibGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TaW5nbGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5EZWNpbWFsLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQcAAAAFSXRlbTEFSXRlbTIFSXRlbTMFSXRlbTQFSXRlbTUFSXRlbTYFSXRlbTcAAQAAAAAACA8JBgsFAQAAAAYCAAAAATIDAAAABAAAAAAAAABmZmZmZmYWQJqZ+UABOQs=" } };
- yield return new object[] { ValueTuple.Create(1, "2", 3u, 4L, 5.6, 7.8f, 9m, Tuple.Create(10)), new string[] { "AAEAAAD/////AQAAAAAAAAAEAQAAAL0HU3lzdGVtLlZhbHVlVHVwbGVgOFtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVUludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50NjQsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5Eb3VibGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TaW5nbGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5EZWNpbWFsLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVmFsdWVUdXBsZWAxW1tTeXN0ZW0uVHVwbGVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAVJdGVtMQVJdGVtMgVJdGVtMwVJdGVtNAVJdGVtNQVJdGVtNgVJdGVtNwRSZXN0AAEAAAAAAAMIDwkGCwXPAVN5c3RlbS5WYWx1ZVR1cGxlYDFbW1N5c3RlbS5UdXBsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAGAgAAAAEyAwAAAAQAAAAAAAAAZmZmZmZmFkCamflAATkE/f///88BU3lzdGVtLlZhbHVlVHVwbGVgMVtbU3lzdGVtLlR1cGxlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAAVJdGVtMQNrU3lzdGVtLlR1cGxlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0JBAAAAAQEAAAAa1N5c3RlbS5UdXBsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAAdtX0l0ZW0xAAgKAAAACw==", "AAEAAAD/////AQAAAAAAAAAEAQAAAL0HU3lzdGVtLlZhbHVlVHVwbGVgOFtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVUludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50NjQsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5Eb3VibGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TaW5nbGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5EZWNpbWFsLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVmFsdWVUdXBsZWAxW1tTeXN0ZW0uVHVwbGVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAVJdGVtMQVJdGVtMgVJdGVtMwVJdGVtNAVJdGVtNQVJdGVtNgVJdGVtNwRSZXN0AAEAAAAAAAMIDwkGCwXPAVN5c3RlbS5WYWx1ZVR1cGxlYDFbW1N5c3RlbS5UdXBsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAGAgAAAAEyAwAAAAQAAAAAAAAAZmZmZmZmFkCamflAATkE/f///88BU3lzdGVtLlZhbHVlVHVwbGVgMVtbU3lzdGVtLlR1cGxlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAAVJdGVtMQNrU3lzdGVtLlR1cGxlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0JBAAAAAQEAAAAa1N5c3RlbS5UdXBsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAAdtX0l0ZW0xAAgKAAAACw==" } };
+ yield return new object[] { new ValueTuple(), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABFTeXN0ZW0uVmFsdWVUdXBsZQAAAAAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAABFTeXN0ZW0uVmFsdWVUdXBsZQAAAAAL", TargetFrameworkMoniker.netfx471) } };
+ yield return new object[] { ValueTuple.Create(1), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAHBTeXN0ZW0uVmFsdWVUdXBsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAAVJdGVtMQAIAQAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAHBTeXN0ZW0uVmFsdWVUdXBsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAAVJdGVtMQAIAQAAAAs=", TargetFrameworkMoniker.netfx471) } };
+ yield return new object[] { ValueTuple.Create(1, "2"), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAM0BU3lzdGVtLlZhbHVlVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAFSXRlbTEFSXRlbTIAAQgBAAAABgIAAAABMgs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAM0BU3lzdGVtLlZhbHVlVHVwbGVgMltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQIAAAAFSXRlbTEFSXRlbTIAAQgBAAAABgIAAAABMgs=", TargetFrameworkMoniker.netfx471) } };
+ yield return new object[] { ValueTuple.Create(1, "2", 3u), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAKoCU3lzdGVtLlZhbHVlVHVwbGVgM1tbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVUludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAFSXRlbTEFSXRlbTIFSXRlbTMAAQAIDwEAAAAGAgAAAAEyAwAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAKoCU3lzdGVtLlZhbHVlVHVwbGVgM1tbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVUludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAFSXRlbTEFSXRlbTIFSXRlbTMAAQAIDwEAAAAGAgAAAAEyAwAAAAs=", TargetFrameworkMoniker.netfx471) } };
+ yield return new object[] { ValueTuple.Create(1, "2", 3u, 4L), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAIYDU3lzdGVtLlZhbHVlVHVwbGVgNFtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVUludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50NjQsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAVJdGVtMQVJdGVtMgVJdGVtMwVJdGVtNAABAAAIDwkBAAAABgIAAAABMgMAAAAEAAAAAAAAAAs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAIYDU3lzdGVtLlZhbHVlVHVwbGVgNFtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVUludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50NjQsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBAAAAAVJdGVtMQVJdGVtMgVJdGVtMwVJdGVtNAABAAAIDwkBAAAABgIAAAABMgMAAAAEAAAAAAAAAAs=", TargetFrameworkMoniker.netfx471) } };
+ yield return new object[] { ValueTuple.Create(1, "2", 3u, 4L, 5.6), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOMDU3lzdGVtLlZhbHVlVHVwbGVgNVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVUludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50NjQsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5Eb3VibGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBQAAAAVJdGVtMQVJdGVtMgVJdGVtMwVJdGVtNAVJdGVtNQABAAAACA8JBgEAAAAGAgAAAAEyAwAAAAQAAAAAAAAAZmZmZmZmFkAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAOMDU3lzdGVtLlZhbHVlVHVwbGVgNVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVUludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50NjQsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5Eb3VibGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBQAAAAVJdGVtMQVJdGVtMgVJdGVtMwVJdGVtNAVJdGVtNQABAAAACA8JBgEAAAAGAgAAAAEyAwAAAAQAAAAAAAAAZmZmZmZmFkAL", TargetFrameworkMoniker.netfx471) } };
+ yield return new object[] { ValueTuple.Create(1, "2", 3u, 4L, 5.6, 7.8f), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAMAEU3lzdGVtLlZhbHVlVHVwbGVgNltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVUludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50NjQsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5Eb3VibGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TaW5nbGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBgAAAAVJdGVtMQVJdGVtMgVJdGVtMwVJdGVtNAVJdGVtNQVJdGVtNgABAAAAAAgPCQYLAQAAAAYCAAAAATIDAAAABAAAAAAAAABmZmZmZmYWQJqZ+UAL", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAMAEU3lzdGVtLlZhbHVlVHVwbGVgNltbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVUludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50NjQsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5Eb3VibGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TaW5nbGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dBgAAAAVJdGVtMQVJdGVtMgVJdGVtMwVJdGVtNAVJdGVtNQVJdGVtNgABAAAAAAgPCQYLAQAAAAYCAAAAATIDAAAABAAAAAAAAABmZmZmZmYWQJqZ+UAL", TargetFrameworkMoniker.netfx471) } };
+ yield return new object[] { ValueTuple.Create(1, "2", 3u, 4L, 5.6, 7.8f, 9m), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAJ4FU3lzdGVtLlZhbHVlVHVwbGVgN1tbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVUludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50NjQsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5Eb3VibGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TaW5nbGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5EZWNpbWFsLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQcAAAAFSXRlbTEFSXRlbTIFSXRlbTMFSXRlbTQFSXRlbTUFSXRlbTYFSXRlbTcAAQAAAAAACA8JBgsFAQAAAAYCAAAAATIDAAAABAAAAAAAAABmZmZmZmYWQJqZ+UABOQs=", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAJ4FU3lzdGVtLlZhbHVlVHVwbGVgN1tbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVUludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50NjQsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5Eb3VibGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TaW5nbGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5EZWNpbWFsLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQcAAAAFSXRlbTEFSXRlbTIFSXRlbTMFSXRlbTQFSXRlbTUFSXRlbTYFSXRlbTcAAQAAAAAACA8JBgsFAQAAAAYCAAAAATIDAAAABAAAAAAAAABmZmZmZmYWQJqZ+UABOQs=", TargetFrameworkMoniker.netfx471) } };
+ yield return new object[] { ValueTuple.Create(1, "2", 3u, 4L, 5.6, 7.8f, 9m, Tuple.Create(10)), new TypeSerializableValue[] { new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAL0HU3lzdGVtLlZhbHVlVHVwbGVgOFtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVUludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50NjQsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5Eb3VibGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TaW5nbGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5EZWNpbWFsLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVmFsdWVUdXBsZWAxW1tTeXN0ZW0uVHVwbGVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAVJdGVtMQVJdGVtMgVJdGVtMwVJdGVtNAVJdGVtNQVJdGVtNgVJdGVtNwRSZXN0AAEAAAAAAAMIDwkGCwXPAVN5c3RlbS5WYWx1ZVR1cGxlYDFbW1N5c3RlbS5UdXBsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAGAgAAAAEyAwAAAAQAAAAAAAAAZmZmZmZmFkCamflAATkE/f///88BU3lzdGVtLlZhbHVlVHVwbGVgMVtbU3lzdGVtLlR1cGxlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAAVJdGVtMQNrU3lzdGVtLlR1cGxlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0JBAAAAAQEAAAAa1N5c3RlbS5UdXBsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAAdtX0l0ZW0xAAgKAAAACw==", TargetFrameworkMoniker.netcoreapp20), new TypeSerializableValue("AAEAAAD/////AQAAAAAAAAAEAQAAAL0HU3lzdGVtLlZhbHVlVHVwbGVgOFtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVUludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uSW50NjQsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5Eb3VibGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TaW5nbGUsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5EZWNpbWFsLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldLFtTeXN0ZW0uVmFsdWVUdXBsZWAxW1tTeXN0ZW0uVHVwbGVgMVtbU3lzdGVtLkludDMyLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dCAAAAAVJdGVtMQVJdGVtMgVJdGVtMwVJdGVtNAVJdGVtNQVJdGVtNgVJdGVtNwRSZXN0AAEAAAAAAAMIDwkGCwXPAVN5c3RlbS5WYWx1ZVR1cGxlYDFbW1N5c3RlbS5UdXBsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQEAAAAGAgAAAAEyAwAAAAQAAAAAAAAAZmZmZmZmFkCamflAATkE/f///88BU3lzdGVtLlZhbHVlVHVwbGVgMVtbU3lzdGVtLlR1cGxlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAAVJdGVtMQNrU3lzdGVtLlR1cGxlYDFbW1N5c3RlbS5JbnQzMiwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0JBAAAAAQEAAAAa1N5c3RlbS5UdXBsZWAxW1tTeXN0ZW0uSW50MzIsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAQAAAAdtX0l0ZW0xAAgKAAAACw==", TargetFrameworkMoniker.netfx471) } };
}
}
diff --git a/src/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTests.cs b/src/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTests.cs
index 0caa876e40..a6b814711a 100644
--- a/src/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTests.cs
+++ b/src/System.Runtime.Serialization.Formatters/tests/BinaryFormatterTests.cs
@@ -18,6 +18,31 @@ namespace System.Runtime.Serialization.Formatters.Tests
{
public partial class BinaryFormatterTests : RemoteExecutorTestBase
{
+ private static unsafe bool Is64Bit => sizeof(void*) == 8;
+
+ // On 32-bit we can't test these high inputs as they cause OutOfMemoryExceptions.
+ [ConditionalTheory(nameof(Is64Bit))]
+ [InlineData(2 * 6_584_983 - 2)] // previous limit
+ [InlineData(2 * 7_199_369 - 2)] // last pre-computed prime number
+ public void SerializeHugeObjectGraphs(int limit)
+ {
+ Point[] pointArr = Enumerable.Range(0, limit)
+ .Select(i => new Point(i, i + 1))
+ .ToArray();
+
+ // This should not throw a SerializationException as we removed the artifical limit in the ObjectIDGenerator.
+ // Instead of round tripping we only serialize to minimize test time.
+ // This will throw on .NET Framework as the artificial limit is still enabled.
+ var bf = new BinaryFormatter();
+ AssertExtensions.ThrowsIf<SerializationException>(PlatformDetection.IsFullFramework, () =>
+ {
+ using (MemoryStream ms = new MemoryStream())
+ {
+ bf.Serialize(ms, pointArr);
+ }
+ });
+ }
+
[Theory]
[MemberData(nameof(BasicObjectsRoundtrip_MemberData))]
public void ValidateBasicObjectsRoundtrip(object obj, FormatterAssemblyStyle assemblyFormat, TypeFilterLevel filterLevel, FormatterTypeStyle typeFormat)
@@ -50,15 +75,15 @@ namespace System.Runtime.Serialization.Formatters.Tests
[Theory]
[MemberData(nameof(SerializableObjects_MemberData))]
- public void ValidateAgainstBlobs(object obj, string[] blobs)
+ public void ValidateAgainstBlobs(object obj, TypeSerializableValue[] blobs)
=> ValidateAndRoundtrip(obj, blobs, false);
[Theory]
[MemberData(nameof(SerializableEqualityComparers_MemberData))]
- public void ValidateEqualityComparersAgainstBlobs(object obj, string[] blobs)
+ public void ValidateEqualityComparersAgainstBlobs(object obj, TypeSerializableValue[] blobs)
=> ValidateAndRoundtrip(obj, blobs, true);
- private static void ValidateAndRoundtrip(object obj, string[] blobs, bool isEqualityComparer)
+ private static void ValidateAndRoundtrip(object obj, TypeSerializableValue[] blobs, bool isEqualityComparer)
{
if (obj == null)
{
@@ -73,17 +98,22 @@ namespace System.Runtime.Serialization.Formatters.Tests
SanityCheckBlob(obj, blobs);
- // SqlException isn't deserializable from Desktop --> Core.
+ // SqlException, ReflectionTypeLoadException and LicenseException aren't deserializable from Desktop --> Core.
// Therefore we remove the second blob which is the one from Desktop.
if (!PlatformDetection.IsFullFramework && (obj is SqlException || obj is ReflectionTypeLoadException || obj is LicenseException))
{
- var tmpList = new List<string>(blobs);
+ var tmpList = new List<TypeSerializableValue>(blobs);
tmpList.RemoveAt(1);
+
+ int index = tmpList.FindIndex(b => b.Platform == TargetFrameworkMoniker.netfx461 || b.Platform == TargetFrameworkMoniker.netfx471);
+ if (index >= 0)
+ tmpList.RemoveAt(index);
+
blobs = tmpList.ToArray();
}
// We store our framework blobs in index 1
- int platformBlobIndex = PlatformDetection.IsFullFramework ? 1 : 0;
+ int platformBlobIndex = TypeSerializableValue.GetPlatformIndex(blobs);
for (int i = 0; i < blobs.Length; i++)
{
// Check if the current blob is from the current running platform.
@@ -91,13 +121,13 @@ namespace System.Runtime.Serialization.Formatters.Tests
if (isEqualityComparer)
{
- ValidateEqualityComparer(BinaryFormatterHelpers.FromBase64String(blobs[i], FormatterAssemblyStyle.Simple));
- ValidateEqualityComparer(BinaryFormatterHelpers.FromBase64String(blobs[i], FormatterAssemblyStyle.Full));
+ ValidateEqualityComparer(BinaryFormatterHelpers.FromBase64String(blobs[i].Base64Blob, FormatterAssemblyStyle.Simple));
+ ValidateEqualityComparer(BinaryFormatterHelpers.FromBase64String(blobs[i].Base64Blob, FormatterAssemblyStyle.Full));
}
else
{
- EqualityExtensions.CheckEquals(obj, BinaryFormatterHelpers.FromBase64String(blobs[i], FormatterAssemblyStyle.Simple), isSamePlatform);
- EqualityExtensions.CheckEquals(obj, BinaryFormatterHelpers.FromBase64String(blobs[i], FormatterAssemblyStyle.Full), isSamePlatform);
+ EqualityExtensions.CheckEquals(obj, BinaryFormatterHelpers.FromBase64String(blobs[i].Base64Blob, FormatterAssemblyStyle.Simple), isSamePlatform);
+ EqualityExtensions.CheckEquals(obj, BinaryFormatterHelpers.FromBase64String(blobs[i].Base64Blob, FormatterAssemblyStyle.Full), isSamePlatform);
}
}
}
@@ -486,12 +516,11 @@ namespace System.Runtime.Serialization.Formatters.Tests
Assert.Equal(obj.GetType().GetGenericArguments()[0], objType.GetGenericArguments()[0]);
}
- private static void SanityCheckBlob(object obj, string[] blobs)
+ private static void SanityCheckBlob(object obj, TypeSerializableValue[] blobs)
{
// These types are unstable during serialization and produce different blobs.
if (obj is WeakReference<Point> ||
- obj is Collections.Specialized.HybridDictionary ||
- obj is TimeZoneInfo.AdjustmentRule)
+ obj is Collections.Specialized.HybridDictionary)
{
return;
}
@@ -504,18 +533,18 @@ namespace System.Runtime.Serialization.Formatters.Tests
}
// Check if runtime generated blob is the same as the stored one
- int frameworkBlobNumber = PlatformDetection.IsFullFramework ? 1 : 0;
+ int frameworkBlobNumber = TypeSerializableValue.GetPlatformIndex(blobs);
if (frameworkBlobNumber < blobs.Length)
{
string runtimeBlob = BinaryFormatterHelpers.ToBase64String(obj, FormatterAssemblyStyle.Full);
- string storedComparableBlob = CreateComparableBlobInfo(blobs[frameworkBlobNumber]);
+ string storedComparableBlob = CreateComparableBlobInfo(blobs[frameworkBlobNumber].Base64Blob);
string runtimeComparableBlob = CreateComparableBlobInfo(runtimeBlob);
Assert.True(storedComparableBlob == runtimeComparableBlob,
$"The stored blob for type {obj.GetType().FullName} is outdated and needs to be updated.{Environment.NewLine}{Environment.NewLine}" +
$"-------------------- Stored blob ---------------------{Environment.NewLine}" +
- $"Encoded: {blobs[frameworkBlobNumber]}{Environment.NewLine}" +
+ $"Encoded: {blobs[frameworkBlobNumber].Base64Blob}{Environment.NewLine}" +
$"Decoded: {storedComparableBlob}{Environment.NewLine}{Environment.NewLine}" +
$"--------------- Runtime generated blob ---------------{Environment.NewLine}" +
$"Encoded: {runtimeBlob}{Environment.NewLine}" +
diff --git a/src/System.Runtime.Serialization.Formatters/tests/System.Runtime.Serialization.Formatters.Tests.csproj b/src/System.Runtime.Serialization.Formatters/tests/System.Runtime.Serialization.Formatters.Tests.csproj
index b59b9f9d5e..4134419233 100644
--- a/src/System.Runtime.Serialization.Formatters/tests/System.Runtime.Serialization.Formatters.Tests.csproj
+++ b/src/System.Runtime.Serialization.Formatters/tests/System.Runtime.Serialization.Formatters.Tests.csproj
@@ -4,6 +4,7 @@
<PropertyGroup>
<ProjectGuid>{13CE5E71-D373-4EA6-B3CB-166FF089A42A}</ProjectGuid>
<SkipIncludeNewtonsoftJson>true</SkipIncludeNewtonsoftJson>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Release|AnyCPU'" />
@@ -22,17 +23,16 @@
<Compile Include="SerializationInfoTests.cs" />
<Compile Include="SerializationTypes.cs" />
<Compile Include="SurrogateSelectorTests.cs" />
+ <Compile Include="TypeSerializableValue.cs" />
<Compile Include="$(CommonTestPath)\System\NonRuntimeType.cs">
<Link>Common\System\NonRuntimeType.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)\System\Runtime\Serialization\Formatters\BinaryFormatterHelpers.cs">
<Link>Common\System\Runtime\Serialization\Formatters\BinaryFormatterHelpers.cs</Link>
</Compile>
- </ItemGroup>
- <ItemGroup Condition="'$(TargetGroup)' == 'netfx'">
- <!-- Work-around issue where we are bin-placing the netstandard ref for System.Security.Permissions for netfx. Issue #24517 -->
- <TargetingPackExclusions Include="System.Security.Permissions" />
- </ItemGroup>
+ <Compile Include="$(CommonTestPath)\System\ThreadCultureChange.cs">
+ <Link>Common\System\ThreadCultureChange.cs</Link>
+ </Compile> </ItemGroup>
<ItemGroup>
<EmbeddedResource Include="BinaryFormatterTests.rd.xml" />
</ItemGroup>
diff --git a/src/System.Runtime.Serialization.Formatters/tests/TypeSerializableValue.cs b/src/System.Runtime.Serialization.Formatters/tests/TypeSerializableValue.cs
new file mode 100644
index 0000000000..f02cf45e26
--- /dev/null
+++ b/src/System.Runtime.Serialization.Formatters/tests/TypeSerializableValue.cs
@@ -0,0 +1,70 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace System.Runtime.Serialization.Formatters.Tests
+{
+ public readonly struct TypeSerializableValue
+ {
+ public readonly string Base64Blob;
+
+ // This is the minimum version, when the blob changed.
+ public readonly TargetFrameworkMoniker Platform;
+
+ public TypeSerializableValue(string base64Blob, TargetFrameworkMoniker platform)
+ {
+ Base64Blob = base64Blob;
+ Platform = platform;
+ }
+
+ public static int GetPlatformIndex(TypeSerializableValue[] blobs)
+ {
+ List<TypeSerializableValue> blobList = blobs.ToList();
+
+ // .NET Framework
+ if (PlatformDetection.IsFullFramework)
+ {
+ // Check if a specialized blob for >=netfx471 is present and return if found.
+ if (PlatformDetection.IsNetfx471OrNewer)
+ {
+ int index = blobList.FindIndex(b => b.Platform == TargetFrameworkMoniker.netfx471);
+
+ if (index >= 0)
+ return index;
+ }
+
+ // If no newer blob for >=netfx471 is present use existing one.
+ // If no netfx blob is present then -1 will be returned.
+ return blobList.FindIndex(b => b.Platform == TargetFrameworkMoniker.netfx461);
+ }
+
+ // .NET Core
+ if (PlatformDetection.IsNetCore)
+ {
+ // Check if a specialized blob for >=netcoreapp2.1 is present and return if found.
+ int index = blobList.FindIndex(b => b.Platform == TargetFrameworkMoniker.netcoreapp21);
+
+ if (index >= 0)
+ return index;
+
+ // If no newer blob for >=netcoreapp2.1 is present use existing one.
+ // If no netfx blob is present then -1 will be returned.
+ return blobList.FindIndex((b => b.Platform == TargetFrameworkMoniker.netcoreapp20));
+ }
+
+ return -1;
+ }
+ }
+
+ // The values represent platforms where there was change in the serialization for one or more types.
+ public enum TargetFrameworkMoniker
+ {
+ netfx461,
+ netfx471,
+ netcoreapp20,
+ netcoreapp21,
+ }
+}
diff --git a/src/System.Runtime.Serialization.Json/tests/Performance/System.Runtime.Serialization.Json.Performance.Tests.csproj b/src/System.Runtime.Serialization.Json/tests/Performance/System.Runtime.Serialization.Json.Performance.Tests.csproj
index 1a4a2be2f4..1cdad22492 100644
--- a/src/System.Runtime.Serialization.Json/tests/Performance/System.Runtime.Serialization.Json.Performance.Tests.csproj
+++ b/src/System.Runtime.Serialization.Json/tests/Performance/System.Runtime.Serialization.Json.Performance.Tests.csproj
@@ -10,7 +10,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
<ItemGroup>
- <Compile Include="..\..\..\System.Runtime.Serialization.Xml\tests\Utils.cs" />
+ <Compile Include="$(CommonTestPath)\System\Runtime\Serialization\Utils.cs" />
<Compile Include="..\..\..\System.Runtime.Serialization.Xml\tests\SerializationTypes.cs" />
<Compile Include="..\..\..\System.Runtime.Serialization.Xml\tests\SerializationTypes.RuntimeOnly.cs" />
<Compile Include="..\..\..\System.Runtime.Serialization.Xml\tests\SerializationTypes.CoreCLR.cs" />
@@ -28,4 +28,4 @@
</ProjectReference>
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Runtime.Serialization.Json/tests/ReflectionOnly/System.Runtime.Serialization.Json.ReflectionOnly.Tests.csproj b/src/System.Runtime.Serialization.Json/tests/ReflectionOnly/System.Runtime.Serialization.Json.ReflectionOnly.Tests.csproj
index 35c2c57cb6..3bda63bf6a 100644
--- a/src/System.Runtime.Serialization.Json/tests/ReflectionOnly/System.Runtime.Serialization.Json.ReflectionOnly.Tests.csproj
+++ b/src/System.Runtime.Serialization.Json/tests/ReflectionOnly/System.Runtime.Serialization.Json.ReflectionOnly.Tests.csproj
@@ -10,7 +10,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uapaot-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uapaot-Release|AnyCPU'" />
<ItemGroup>
- <Compile Include="$(TestSourceFolder)..\..\..\System.Runtime.Serialization.Xml\tests\Utils.cs" />
+ <Compile Include="$(CommonTestPath)\System\Runtime\Serialization\Utils.cs" />
<Compile Include="$(TestSourceFolder)..\..\..\System.Runtime.Serialization.Xml\tests\SerializationTypes.cs" />
<Compile Include="$(TestSourceFolder)..\..\..\System.Runtime.Serialization.Xml\tests\SerializationTypes.RuntimeOnly.cs" />
<Compile Include="$(TestSourceFolder)..\DataContractJsonSerializer.cs" />
diff --git a/src/System.Runtime.Serialization.Json/tests/System.Runtime.Serialization.Json.Tests.csproj b/src/System.Runtime.Serialization.Json/tests/System.Runtime.Serialization.Json.Tests.csproj
index 250c5e60a4..8244dec441 100644
--- a/src/System.Runtime.Serialization.Json/tests/System.Runtime.Serialization.Json.Tests.csproj
+++ b/src/System.Runtime.Serialization.Json/tests/System.Runtime.Serialization.Json.Tests.csproj
@@ -13,10 +13,10 @@
<Compile Include="$(TestSourceFolder)..\..\System.Runtime.Serialization.Xml\tests\SerializationTypes.CoreCLR.cs" />
</ItemGroup>
<ItemGroup>
- <Compile Include="$(TestSourceFolder)..\..\System.Runtime.Serialization.Xml\tests\Utils.cs" />
+ <Compile Include="$(CommonTestPath)\System\Runtime\Serialization\Utils.cs" />
<Compile Include="$(TestSourceFolder)..\..\System.Runtime.Serialization.Xml\tests\SerializationTypes.cs" />
<Compile Include="$(TestSourceFolder)..\..\System.Runtime.Serialization.Xml\tests\SerializationTypes.RuntimeOnly.cs" />
<Compile Include="$(TestSourceFolder)DataContractJsonSerializer.cs" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Runtime.Serialization.Xml/src/MatchingRefApiCompatBaseline.txt b/src/System.Runtime.Serialization.Xml/src/MatchingRefApiCompatBaseline.txt
new file mode 100644
index 0000000000..cd47ce98d8
--- /dev/null
+++ b/src/System.Runtime.Serialization.Xml/src/MatchingRefApiCompatBaseline.txt
@@ -0,0 +1,3 @@
+Compat issues with assembly System.Runtime.Serialization.Xml:
+MembersMustExist : Member 'System.Runtime.Serialization.DataContractSerializer..ctor(System.Type, System.Xml.XmlDictionaryString, System.Xml.XmlDictionaryString, System.Collections.Generic.IEnumerable<System.Type>, System.Int32, System.Boolean, System.Boolean, System.Runtime.Serialization.DataContractResolver)' does not exist in the implementation but it does exist in the contract.
+Total Issues: 1
diff --git a/src/System.Runtime.Serialization.Xml/tests/Performance/System.Runtime.Serialization.Xml.Performance.Tests.csproj b/src/System.Runtime.Serialization.Xml/tests/Performance/System.Runtime.Serialization.Xml.Performance.Tests.csproj
index 738256206c..e9b27af44b 100644
--- a/src/System.Runtime.Serialization.Xml/tests/Performance/System.Runtime.Serialization.Xml.Performance.Tests.csproj
+++ b/src/System.Runtime.Serialization.Xml/tests/Performance/System.Runtime.Serialization.Xml.Performance.Tests.csproj
@@ -11,7 +11,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
<ItemGroup>
- <Compile Include="..\Utils.cs" />
+ <Compile Include="$(CommonTestPath)\System\Runtime\Serialization\Utils.cs" />
<Compile Include="..\SerializationTypes.cs" />
<Compile Include="..\SerializationTypes.RuntimeOnly.cs" />
<Compile Include="..\SerializationTypes.CoreCLR.cs" />
diff --git a/src/System.Runtime.Serialization.Xml/tests/ReflectionOnly/System.Runtime.Serialization.Xml.ReflectionOnly.Tests.csproj b/src/System.Runtime.Serialization.Xml/tests/ReflectionOnly/System.Runtime.Serialization.Xml.ReflectionOnly.Tests.csproj
index bbb1216009..688b2ffd7f 100644
--- a/src/System.Runtime.Serialization.Xml/tests/ReflectionOnly/System.Runtime.Serialization.Xml.ReflectionOnly.Tests.csproj
+++ b/src/System.Runtime.Serialization.Xml/tests/ReflectionOnly/System.Runtime.Serialization.Xml.ReflectionOnly.Tests.csproj
@@ -11,14 +11,14 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uapaot-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uapaot-Release|AnyCPU'" />
<ItemGroup>
+ <Compile Include="$(CommonTestPath)\System\Runtime\Serialization\Utils.cs" />
<Compile Include="$(TestSourceFolder)..\DataContractSerializerStressTests.cs" />
- <Compile Include="$(TestSourceFolder)..\Utils.cs" />
<Compile Include="$(TestSourceFolder)..\SerializationTypes.cs" />
<Compile Include="$(TestSourceFolder)..\SerializationTypes.RuntimeOnly.cs" />
<Compile Include="$(TestSourceFolder)..\DataContractSerializer.cs" />
<Compile Include="$(TestSourceFolder)..\MyResolver.cs" />
<Compile Include="$(TestSourceFolder)..\XmlDictionaryReaderTests.cs" />
- <Compile Include="$(TestSourceFolder)..\XmlDictionaryWriterTest.cs" />
+ <Compile Include="$(TestSourceFolder)..\XmlDictionaryWriterTest.cs" />
<Compile Include="$(CommonTestPath)\System\IO\TempFile.cs">
<Link>Common\System\IO\TempFile.cs</Link>
</Compile>
diff --git a/src/System.Runtime.Serialization.Xml/tests/SerializationTypes.cs b/src/System.Runtime.Serialization.Xml/tests/SerializationTypes.cs
index 8db9d14c14..a716ec5785 100644
--- a/src/System.Runtime.Serialization.Xml/tests/SerializationTypes.cs
+++ b/src/System.Runtime.Serialization.Xml/tests/SerializationTypes.cs
@@ -1140,11 +1140,11 @@ public class TypeWithVirtualGenericPropertyDerived<T> : TypeWithVirtualGenericPr
public class DefaultValuesSetToNaN
{
- [DefaultValue(double.NaN)]
- public double DoubleProp { get; set; }
+ [DefaultValue(Double.NaN)]
+ public Double DoubleProp { get; set; }
- [DefaultValue(float.NaN)]
- public float FloatProp { get; set; }
+ [DefaultValue(Single.NaN)]
+ public Single FloatProp { get; set; }
[DefaultValue(Double.NaN)]
public Double DoubleField;
@@ -1167,6 +1167,64 @@ public class DefaultValuesSetToNaN
}
}
+public class DefaultValuesSetToPositiveInfinity
+{
+ [DefaultValue(Double.PositiveInfinity)]
+ public Double DoubleProp { get; set; }
+
+ [DefaultValue(Single.PositiveInfinity)]
+ public Single FloatProp { get; set; }
+
+ [DefaultValue(Double.PositiveInfinity)]
+ public Double DoubleField;
+
+ [DefaultValue(Single.PositiveInfinity)]
+ public Single SingleField;
+
+ public override bool Equals(object obj)
+ {
+ var other = obj as DefaultValuesSetToPositiveInfinity;
+ return other == null ? false :
+ other.DoubleProp == this.DoubleProp && other.FloatProp == this.FloatProp &&
+ other.DoubleField == this.DoubleField && other.SingleField == this.SingleField;
+ }
+
+ public override int GetHashCode()
+ {
+ return this.DoubleProp.GetHashCode() ^ this.FloatProp.GetHashCode() ^
+ this.DoubleField.GetHashCode() ^ this.SingleField.GetHashCode();
+ }
+}
+
+public class DefaultValuesSetToNegativeInfinity
+{
+ [DefaultValue(Double.NegativeInfinity)]
+ public Double DoubleProp { get; set; }
+
+ [DefaultValue(Single.NegativeInfinity)]
+ public Single FloatProp { get; set; }
+
+ [DefaultValue(Double.NegativeInfinity)]
+ public Double DoubleField;
+
+ [DefaultValue(Single.NegativeInfinity)]
+ public Single SingleField;
+
+ public override bool Equals(object obj)
+ {
+ var other = obj as DefaultValuesSetToNegativeInfinity;
+ return other == null ? false :
+ other.DoubleProp == this.DoubleProp && other.FloatProp == this.FloatProp &&
+ other.DoubleField == this.DoubleField && other.SingleField == this.SingleField;
+ }
+
+ public override int GetHashCode()
+ {
+ return this.DoubleProp.GetHashCode() ^ this.FloatProp.GetHashCode() ^
+ this.DoubleField.GetHashCode() ^ this.SingleField.GetHashCode();
+ }
+}
+
[XmlRoot("RootElement")]
public class TypeWithMismatchBetweenAttributeAndPropertyType
{
@@ -1184,4 +1242,4 @@ public class TypeWithMismatchBetweenAttributeAndPropertyType
_intValue = value;
}
}
-} \ No newline at end of file
+}
diff --git a/src/System.Runtime.Serialization.Xml/tests/System.Runtime.Serialization.Xml.Tests.csproj b/src/System.Runtime.Serialization.Xml/tests/System.Runtime.Serialization.Xml.Tests.csproj
index 95fc9e94b3..fe5b3cff85 100644
--- a/src/System.Runtime.Serialization.Xml/tests/System.Runtime.Serialization.Xml.Tests.csproj
+++ b/src/System.Runtime.Serialization.Xml/tests/System.Runtime.Serialization.Xml.Tests.csproj
@@ -11,7 +11,6 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uapaot-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="$(TestSourceFolder)DataContractSerializerStressTests.cs" />
- <Compile Include="$(TestSourceFolder)Utils.cs" />
<Compile Include="$(TestSourceFolder)SerializationTypes.cs" />
<Compile Include="$(TestSourceFolder)SerializationTypes.RuntimeOnly.cs" />
<Compile Include="$(TestSourceFolder)DataContractSerializer.cs" />
@@ -29,6 +28,7 @@
<Compile Include="$(CommonTestPath)\System\Runtime\Serialization\DataContractSerializerHelper.cs">
<Link>Common\System\Runtime\Serialization\DataContractSerializerHelper.cs</Link>
</Compile>
+ <Compile Include="$(CommonTestPath)\System\Runtime\Serialization\Utils.cs" />
<Compile Include="$(TestSourceFolder)SerializationTestTypes\ObjRefSample.cs" />
<Compile Include="SerializationTestTypes\Collections.cs" />
<Compile Include="SerializationTestTypes\DataContract.cs" />
@@ -47,4 +47,4 @@
<EmbeddedResource Include="$(MsBuildThisFileDirectory)Resources\$(AssemblyName).rd.xml" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Runtime.Serialization.Xml/tests/XmlDictionaryReaderTests.cs b/src/System.Runtime.Serialization.Xml/tests/XmlDictionaryReaderTests.cs
index 25c9b5b366..ab3f876315 100644
--- a/src/System.Runtime.Serialization.Xml/tests/XmlDictionaryReaderTests.cs
+++ b/src/System.Runtime.Serialization.Xml/tests/XmlDictionaryReaderTests.cs
@@ -183,5 +183,40 @@ namespace System.Runtime.Serialization.Xml.Tests
return sb.ToString();
}
+
+ [Fact]
+ public static void Close_DerivedReader_Success()
+ {
+ new NotImplementedXmlDictionaryReader().Close();
+ }
+
+ private sealed class NotImplementedXmlDictionaryReader : XmlDictionaryReader
+ {
+ public override ReadState ReadState => ReadState.Initial;
+
+ public override int AttributeCount => throw new NotImplementedException();
+ public override string BaseURI => throw new NotImplementedException();
+ public override int Depth => throw new NotImplementedException();
+ public override bool EOF => throw new NotImplementedException();
+ public override bool IsEmptyElement => throw new NotImplementedException();
+ public override string LocalName => throw new NotImplementedException();
+ public override string NamespaceURI => throw new NotImplementedException();
+ public override XmlNameTable NameTable => throw new NotImplementedException();
+ public override XmlNodeType NodeType => throw new NotImplementedException();
+ public override string Prefix => throw new NotImplementedException();
+ public override string Value => throw new NotImplementedException();
+ public override string GetAttribute(int i) => throw new NotImplementedException();
+ public override string GetAttribute(string name) => throw new NotImplementedException();
+ public override string GetAttribute(string name, string namespaceURI) => throw new NotImplementedException();
+ public override string LookupNamespace(string prefix) => throw new NotImplementedException();
+ public override bool MoveToAttribute(string name) => throw new NotImplementedException();
+ public override bool MoveToAttribute(string name, string ns) => throw new NotImplementedException();
+ public override bool MoveToElement() => throw new NotImplementedException();
+ public override bool MoveToFirstAttribute() => throw new NotImplementedException();
+ public override bool MoveToNextAttribute() => throw new NotImplementedException();
+ public override bool Read() => throw new NotImplementedException();
+ public override bool ReadAttributeValue() => throw new NotImplementedException();
+ public override void ResolveEntity() => throw new NotImplementedException();
+ }
}
}
diff --git a/src/System.Runtime.WindowsRuntime/src/System.Runtime.WindowsRuntime.csproj b/src/System.Runtime.WindowsRuntime/src/System.Runtime.WindowsRuntime.csproj
index 79e53dc4db..5c500ecd68 100644
--- a/src/System.Runtime.WindowsRuntime/src/System.Runtime.WindowsRuntime.csproj
+++ b/src/System.Runtime.WindowsRuntime/src/System.Runtime.WindowsRuntime.csproj
@@ -94,8 +94,8 @@
<Compile Include="$(CommonPath)\Interop\Windows\Interop.Errors.cs">
<Link>Common\Interop\Windows\Interop.Errors.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\IO\Win32Marshal.cs">
- <Link>Common\System\IO\Win32Marshal.cs</Link>
+ <Compile Include="$(CommonPath)\CoreLib\System\IO\Win32Marshal.cs">
+ <Link>Common\CoreLib\System\IO\Win32Marshal.cs</Link>
</Compile>
<Compile Include="System\IO\HANDLE_ACCESS_OPTIONS.cs" />
<Compile Include="System\IO\HANDLE_CREATION_OPTIONS.cs" />
@@ -130,4 +130,4 @@
<Compile Include="System\Windows\UI\Color.cs" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project>
+</Project> \ No newline at end of file
diff --git a/src/System.Runtime.WindowsRuntime/src/System/InternalHelpers.cs b/src/System.Runtime.WindowsRuntime/src/System/InternalHelpers.cs
index 43fbe0f017..2c6753245d 100644
--- a/src/System.Runtime.WindowsRuntime/src/System/InternalHelpers.cs
+++ b/src/System.Runtime.WindowsRuntime/src/System/InternalHelpers.cs
@@ -2,8 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Threading.Tasks;
-using System.Threading;
+using System.Runtime.InteropServices;
namespace System
{
@@ -11,12 +10,7 @@ namespace System
{
internal static void SetErrorCode(this Exception ex, int code)
{
- // Stub, until COM interop guys fix the exception logic
- }
-
- internal static void TryDeregister(this CancellationTokenRegistration ctr)
- {
- //nothing to do for projectN
+ InteropExtensions.SetExceptionErrorCode(ex, code);
}
}
}
diff --git a/src/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/AsyncInfoToTaskBridge.CoreCLR.cs b/src/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/AsyncInfoToTaskBridge.CoreCLR.cs
index 09941a25ca..b92a8efd2f 100644
--- a/src/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/AsyncInfoToTaskBridge.CoreCLR.cs
+++ b/src/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/AsyncInfoToTaskBridge.CoreCLR.cs
@@ -70,7 +70,7 @@ namespace System.Threading.Tasks
}
if (disposeOfCtr)
- ctr.TryDeregister();
+ ctr.Unregister();
}
}
catch (Exception ex)
@@ -150,7 +150,7 @@ namespace System.Threading.Tasks
ctr = _ctr; // under lock to avoid torn reads
_ctr = default(CancellationTokenRegistration);
}
- ctr.TryDeregister(); // It's ok if we end up unregistering a not-initialized registration; it'll just be a nop.
+ ctr.Unregister(); // It's ok if we end up unregistering a not-initialized registration; it'll just be a nop.
try
{
diff --git a/src/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/AsyncInfoToTaskBridge.CoreRT.cs b/src/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/AsyncInfoToTaskBridge.CoreRT.cs
index eec0c38d48..502d470059 100644
--- a/src/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/AsyncInfoToTaskBridge.CoreRT.cs
+++ b/src/System.Runtime.WindowsRuntime/src/System/Threading/Tasks/AsyncInfoToTaskBridge.CoreRT.cs
@@ -2,16 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-
using Internal.Interop;
using Internal.Threading.Tasks;
-using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.Contracts;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices.WindowsRuntime;
using System.Runtime.InteropServices;
-using System.Threading;
using Windows.Foundation;
namespace System.Threading.Tasks
@@ -68,7 +63,7 @@ namespace System.Threading.Tasks
}
if (disposeOfCtr)
- ctr.TryDeregister();
+ ctr.Unregister();
}
}
catch (Exception ex)
@@ -151,7 +146,7 @@ namespace System.Threading.Tasks
ctr = _ctr; // under lock to avoid torn reads
_ctr = default(CancellationTokenRegistration);
}
- ctr.TryDeregister(); // It's ok if we end up unregistering a not-initialized registration; it'll just be a nop.
+ ctr.Unregister(); // It's ok if we end up unregistering a not-initialized registration; it'll just be a nop.
try
{
diff --git a/src/System.Runtime/ref/System.Runtime.cs b/src/System.Runtime/ref/System.Runtime.cs
index bfd34ca190..66fee8c70e 100644
--- a/src/System.Runtime/ref/System.Runtime.cs
+++ b/src/System.Runtime/ref/System.Runtime.cs
@@ -459,7 +459,7 @@ namespace System
public override bool Equals(object obj) { throw null; }
public override int GetHashCode() { throw null; }
public System.TypeCode GetTypeCode() { throw null; }
- public static System.Byte Parse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style=(System.Globalization.NumberStyles)(7), System.IFormatProvider provider=null) { throw null; }
+ public static System.Byte Parse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style = (System.Globalization.NumberStyles)(7), System.IFormatProvider provider = null) { throw null; }
public static System.Byte Parse(string s) { throw null; }
public static System.Byte Parse(string s, System.Globalization.NumberStyles style) { throw null; }
public static System.Byte Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider provider) { throw null; }
@@ -483,7 +483,7 @@ namespace System
public string ToString(System.IFormatProvider provider) { throw null; }
public string ToString(string format) { throw null; }
public string ToString(string format, System.IFormatProvider provider) { throw null; }
- public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format=default(System.ReadOnlySpan<char>), System.IFormatProvider provider=null) { throw null; }
+ public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format = default(System.ReadOnlySpan<char>), System.IFormatProvider provider = null) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> s, out System.Byte result) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style, System.IFormatProvider provider, out System.Byte result) { throw null; }
public static bool TryParse(string s, out System.Byte result) { throw null; }
@@ -652,12 +652,12 @@ namespace System
public static bool operator <=(System.DateTime t1, System.DateTime t2) { throw null; }
public static System.TimeSpan operator -(System.DateTime d1, System.DateTime d2) { throw null; }
public static System.DateTime operator -(System.DateTime d, System.TimeSpan t) { throw null; }
- public static System.DateTime Parse(System.ReadOnlySpan<char> s, System.IFormatProvider provider=null, System.Globalization.DateTimeStyles styles=(System.Globalization.DateTimeStyles)(0)) { throw null; }
+ public static System.DateTime Parse(System.ReadOnlySpan<char> s, System.IFormatProvider provider = null, System.Globalization.DateTimeStyles styles = (System.Globalization.DateTimeStyles)(0)) { throw null; }
public static System.DateTime Parse(string s) { throw null; }
public static System.DateTime Parse(string s, System.IFormatProvider provider) { throw null; }
public static System.DateTime Parse(string s, System.IFormatProvider provider, System.Globalization.DateTimeStyles styles) { throw null; }
- public static System.DateTime ParseExact(System.ReadOnlySpan<char> s, System.ReadOnlySpan<char> format, System.IFormatProvider provider, System.Globalization.DateTimeStyles style=(System.Globalization.DateTimeStyles)(0)) { throw null; }
- public static System.DateTime ParseExact(System.ReadOnlySpan<char> s, string[] formats, System.IFormatProvider provider, System.Globalization.DateTimeStyles style=(System.Globalization.DateTimeStyles)(0)) { throw null; }
+ public static System.DateTime ParseExact(System.ReadOnlySpan<char> s, System.ReadOnlySpan<char> format, System.IFormatProvider provider, System.Globalization.DateTimeStyles style = (System.Globalization.DateTimeStyles)(0)) { throw null; }
+ public static System.DateTime ParseExact(System.ReadOnlySpan<char> s, string[] formats, System.IFormatProvider provider, System.Globalization.DateTimeStyles style = (System.Globalization.DateTimeStyles)(0)) { throw null; }
public static System.DateTime ParseExact(string s, string format, System.IFormatProvider provider) { throw null; }
public static System.DateTime ParseExact(string s, string format, System.IFormatProvider provider, System.Globalization.DateTimeStyles style) { throw null; }
public static System.DateTime ParseExact(string s, string[] formats, System.IFormatProvider provider, System.Globalization.DateTimeStyles style) { throw null; }
@@ -694,7 +694,7 @@ namespace System
public string ToString(string format) { throw null; }
public string ToString(string format, System.IFormatProvider provider) { throw null; }
public System.DateTime ToUniversalTime() { throw null; }
- public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format=default(System.ReadOnlySpan<char>), System.IFormatProvider provider=null) { throw null; }
+ public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format = default(System.ReadOnlySpan<char>), System.IFormatProvider provider = null) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> s, out System.DateTime result) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> s, System.IFormatProvider provider, System.Globalization.DateTimeStyles styles, out System.DateTime result) { throw null; }
public static bool TryParse(string s, out System.DateTime result) { throw null; }
@@ -770,12 +770,12 @@ namespace System
public static bool operator <=(System.DateTimeOffset left, System.DateTimeOffset right) { throw null; }
public static System.TimeSpan operator -(System.DateTimeOffset left, System.DateTimeOffset right) { throw null; }
public static System.DateTimeOffset operator -(System.DateTimeOffset dateTimeOffset, System.TimeSpan timeSpan) { throw null; }
- public static System.DateTimeOffset Parse(System.ReadOnlySpan<char> input, System.IFormatProvider formatProvider=null, System.Globalization.DateTimeStyles styles=(System.Globalization.DateTimeStyles)(0)) { throw null; }
+ public static System.DateTimeOffset Parse(System.ReadOnlySpan<char> input, System.IFormatProvider formatProvider = null, System.Globalization.DateTimeStyles styles = (System.Globalization.DateTimeStyles)(0)) { throw null; }
public static System.DateTimeOffset Parse(string input) { throw null; }
public static System.DateTimeOffset Parse(string input, System.IFormatProvider formatProvider) { throw null; }
public static System.DateTimeOffset Parse(string input, System.IFormatProvider formatProvider, System.Globalization.DateTimeStyles styles) { throw null; }
- public static System.DateTimeOffset ParseExact(System.ReadOnlySpan<char> input, System.ReadOnlySpan<char> format, System.IFormatProvider formatProvider, System.Globalization.DateTimeStyles styles=(System.Globalization.DateTimeStyles)(0)) { throw null; }
- public static System.DateTimeOffset ParseExact(System.ReadOnlySpan<char> input, string[] formats, System.IFormatProvider formatProvider, System.Globalization.DateTimeStyles styles=(System.Globalization.DateTimeStyles)(0)) { throw null; }
+ public static System.DateTimeOffset ParseExact(System.ReadOnlySpan<char> input, System.ReadOnlySpan<char> format, System.IFormatProvider formatProvider, System.Globalization.DateTimeStyles styles = (System.Globalization.DateTimeStyles)(0)) { throw null; }
+ public static System.DateTimeOffset ParseExact(System.ReadOnlySpan<char> input, string[] formats, System.IFormatProvider formatProvider, System.Globalization.DateTimeStyles styles = (System.Globalization.DateTimeStyles)(0)) { throw null; }
public static System.DateTimeOffset ParseExact(string input, string format, System.IFormatProvider formatProvider) { throw null; }
public static System.DateTimeOffset ParseExact(string input, string format, System.IFormatProvider formatProvider, System.Globalization.DateTimeStyles styles) { throw null; }
public static System.DateTimeOffset ParseExact(string input, string[] formats, System.IFormatProvider formatProvider, System.Globalization.DateTimeStyles styles) { throw null; }
@@ -794,7 +794,7 @@ namespace System
public System.DateTimeOffset ToUniversalTime() { throw null; }
public long ToUnixTimeMilliseconds() { throw null; }
public long ToUnixTimeSeconds() { throw null; }
- public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format=default(System.ReadOnlySpan<char>), System.IFormatProvider formatProvider=null) { throw null; }
+ public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format = default(System.ReadOnlySpan<char>), System.IFormatProvider formatProvider = null) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> input, out System.DateTimeOffset result) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> input, System.IFormatProvider formatProvider, System.Globalization.DateTimeStyles styles, out System.DateTimeOffset result) { throw null; }
public static bool TryParse(string input, out System.DateTimeOffset result) { throw null; }
@@ -922,7 +922,7 @@ namespace System
public static System.Decimal operator -(System.Decimal d1, System.Decimal d2) { throw null; }
public static System.Decimal operator -(System.Decimal d) { throw null; }
public static System.Decimal operator +(System.Decimal d) { throw null; }
- public static System.Decimal Parse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style=(System.Globalization.NumberStyles)(7), System.IFormatProvider provider=null) { throw null; }
+ public static System.Decimal Parse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style = (System.Globalization.NumberStyles)(7), System.IFormatProvider provider = null) { throw null; }
public static System.Decimal Parse(string s) { throw null; }
public static System.Decimal Parse(string s, System.Globalization.NumberStyles style) { throw null; }
public static System.Decimal Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider provider) { throw null; }
@@ -969,7 +969,7 @@ namespace System
[System.CLSCompliantAttribute(false)]
public static ulong ToUInt64(System.Decimal d) { throw null; }
public static System.Decimal Truncate(System.Decimal d) { throw null; }
- public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format=default(System.ReadOnlySpan<char>), System.IFormatProvider provider=null) { throw null; }
+ public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format = default(System.ReadOnlySpan<char>), System.IFormatProvider provider = null) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> s, out System.Decimal result) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style, System.IFormatProvider provider, out System.Decimal result) { throw null; }
public static bool TryParse(string s, out System.Decimal result) { throw null; }
@@ -1044,7 +1044,7 @@ namespace System
public static bool operator !=(System.Double left, System.Double right) { throw null; }
public static bool operator <(System.Double left, System.Double right) { throw null; }
public static bool operator <=(System.Double left, System.Double right) { throw null; }
- public static System.Double Parse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style=(System.Globalization.NumberStyles)(7), System.IFormatProvider provider=null) { throw null; }
+ public static System.Double Parse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style = (System.Globalization.NumberStyles)(7), System.IFormatProvider provider = null) { throw null; }
public static System.Double Parse(string s) { throw null; }
public static System.Double Parse(string s, System.Globalization.NumberStyles style) { throw null; }
public static System.Double Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider provider) { throw null; }
@@ -1068,7 +1068,7 @@ namespace System
public string ToString(System.IFormatProvider provider) { throw null; }
public string ToString(string format) { throw null; }
public string ToString(string format, System.IFormatProvider provider) { throw null; }
- public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format=default(System.ReadOnlySpan<char>), System.IFormatProvider provider=null) { throw null; }
+ public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format = default(System.ReadOnlySpan<char>), System.IFormatProvider provider = null) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> s, out System.Double result) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style, System.IFormatProvider provider, out System.Double result) { throw null; }
public static bool TryParse(string s, out System.Double result) { throw null; }
@@ -1332,7 +1332,7 @@ namespace System
public override string ToString() { throw null; }
public string ToString(string format) { throw null; }
public string ToString(string format, System.IFormatProvider provider) { throw null; }
- public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format=default(System.ReadOnlySpan<char>)) { throw null; }
+ public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format = default(System.ReadOnlySpan<char>)) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> input, out System.Guid result) { throw null; }
public static bool TryParse(string input, out System.Guid result) { throw null; }
public static bool TryParseExact(System.ReadOnlySpan<char> input, System.ReadOnlySpan<char> format, out System.Guid result) { throw null; }
@@ -1453,7 +1453,7 @@ namespace System
public override bool Equals(object obj) { throw null; }
public override int GetHashCode() { throw null; }
public System.TypeCode GetTypeCode() { throw null; }
- public static System.Int16 Parse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style=(System.Globalization.NumberStyles)(7), System.IFormatProvider provider=null) { throw null; }
+ public static System.Int16 Parse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style = (System.Globalization.NumberStyles)(7), System.IFormatProvider provider = null) { throw null; }
public static System.Int16 Parse(string s) { throw null; }
public static System.Int16 Parse(string s, System.Globalization.NumberStyles style) { throw null; }
public static System.Int16 Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider provider) { throw null; }
@@ -1477,7 +1477,7 @@ namespace System
public string ToString(System.IFormatProvider provider) { throw null; }
public string ToString(string format) { throw null; }
public string ToString(string format, System.IFormatProvider provider) { throw null; }
- public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format=default(System.ReadOnlySpan<char>), System.IFormatProvider provider=null) { throw null; }
+ public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format = default(System.ReadOnlySpan<char>), System.IFormatProvider provider = null) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style, System.IFormatProvider provider, out System.Int16 result) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> s, out System.Int16 result) { throw null; }
public static bool TryParse(string s, System.Globalization.NumberStyles style, System.IFormatProvider provider, out System.Int16 result) { throw null; }
@@ -1494,7 +1494,7 @@ namespace System
public override bool Equals(object obj) { throw null; }
public override System.Int32 GetHashCode() { throw null; }
public System.TypeCode GetTypeCode() { throw null; }
- public static System.Int32 Parse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style=(System.Globalization.NumberStyles)(7), System.IFormatProvider provider=null) { throw null; }
+ public static System.Int32 Parse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style = (System.Globalization.NumberStyles)(7), System.IFormatProvider provider = null) { throw null; }
public static System.Int32 Parse(string s) { throw null; }
public static System.Int32 Parse(string s, System.Globalization.NumberStyles style) { throw null; }
public static System.Int32 Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider provider) { throw null; }
@@ -1518,7 +1518,7 @@ namespace System
public string ToString(System.IFormatProvider provider) { throw null; }
public string ToString(string format) { throw null; }
public string ToString(string format, System.IFormatProvider provider) { throw null; }
- public bool TryFormat(System.Span<char> destination, out System.Int32 charsWritten, System.ReadOnlySpan<char> format=default(System.ReadOnlySpan<char>), System.IFormatProvider provider=null) { throw null; }
+ public bool TryFormat(System.Span<char> destination, out System.Int32 charsWritten, System.ReadOnlySpan<char> format = default(System.ReadOnlySpan<char>), System.IFormatProvider provider = null) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style, System.IFormatProvider provider, out System.Int32 result) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> s, out System.Int32 result) { throw null; }
public static bool TryParse(string s, System.Globalization.NumberStyles style, System.IFormatProvider provider, out System.Int32 result) { throw null; }
@@ -1535,7 +1535,7 @@ namespace System
public override bool Equals(object obj) { throw null; }
public override int GetHashCode() { throw null; }
public System.TypeCode GetTypeCode() { throw null; }
- public static System.Int64 Parse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style=(System.Globalization.NumberStyles)(7), System.IFormatProvider provider=null) { throw null; }
+ public static System.Int64 Parse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style = (System.Globalization.NumberStyles)(7), System.IFormatProvider provider = null) { throw null; }
public static System.Int64 Parse(string s) { throw null; }
public static System.Int64 Parse(string s, System.Globalization.NumberStyles style) { throw null; }
public static System.Int64 Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider provider) { throw null; }
@@ -1559,7 +1559,7 @@ namespace System
public string ToString(System.IFormatProvider provider) { throw null; }
public string ToString(string format) { throw null; }
public string ToString(string format, System.IFormatProvider provider) { throw null; }
- public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format=default(System.ReadOnlySpan<char>), System.IFormatProvider provider=null) { throw null; }
+ public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format = default(System.ReadOnlySpan<char>), System.IFormatProvider provider = null) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style, System.IFormatProvider provider, out System.Int64 result) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> s, out System.Int64 result) { throw null; }
public static bool TryParse(string s, System.Globalization.NumberStyles style, System.IFormatProvider provider, out System.Int64 result) { throw null; }
@@ -1590,7 +1590,7 @@ namespace System
public static bool operator !=(System.IntPtr value1, System.IntPtr value2) { throw null; }
public static System.IntPtr operator -(System.IntPtr pointer, int offset) { throw null; }
public static System.IntPtr Subtract(System.IntPtr pointer, int offset) { throw null; }
- bool System.IEquatable<System.IntPtr>.Equals(System.IntPtr value) { throw null; }
+ bool System.IEquatable<System.IntPtr>.Equals(System.IntPtr other) { throw null; }
void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }
public int ToInt32() { throw null; }
public long ToInt64() { throw null; }
@@ -1697,15 +1697,16 @@ namespace System
public override bool Equals(object obj) { throw null; }
[System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
public override int GetHashCode() { throw null; }
- public static implicit operator System.Memory<T> (System.ArraySegment<T> arraySegment) { throw null; }
+ public static implicit operator System.Memory<T> (System.ArraySegment<T> segment) { throw null; }
public static implicit operator System.ReadOnlyMemory<T> (System.Memory<T> memory) { throw null; }
public static implicit operator System.Memory<T> (T[] array) { throw null; }
- public System.Buffers.MemoryHandle Retain(bool pin=false) { throw null; }
+ public System.Buffers.MemoryHandle Pin() { throw null; }
+ public System.Buffers.MemoryHandle Retain(bool pin = false) { throw null; }
public System.Memory<T> Slice(int start) { throw null; }
public System.Memory<T> Slice(int start, int length) { throw null; }
public T[] ToArray() { throw null; }
+ public override string ToString() { throw null; }
public bool TryCopyTo(System.Memory<T> destination) { throw null; }
- public bool TryGetArray(out System.ArraySegment<T> arraySegment) { throw null; }
}
public partial class MethodAccessException : System.MemberAccessException
{
@@ -1945,12 +1946,14 @@ namespace System
public bool Equals(System.ReadOnlyMemory<T> other) { throw null; }
[System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
public override int GetHashCode() { throw null; }
- public static implicit operator System.ReadOnlyMemory<T> (System.ArraySegment<T> arraySegment) { throw null; }
+ public static implicit operator System.ReadOnlyMemory<T> (System.ArraySegment<T> segment) { throw null; }
public static implicit operator System.ReadOnlyMemory<T> (T[] array) { throw null; }
- public System.Buffers.MemoryHandle Retain(bool pin=false) { throw null; }
+ public System.Buffers.MemoryHandle Pin() { throw null; }
+ public System.Buffers.MemoryHandle Retain(bool pin = false) { throw null; }
public System.ReadOnlyMemory<T> Slice(int start) { throw null; }
public System.ReadOnlyMemory<T> Slice(int start, int length) { throw null; }
public T[] ToArray() { throw null; }
+ public override string ToString() { throw null; }
public bool TryCopyTo(System.Memory<T> destination) { throw null; }
}
public readonly ref partial struct ReadOnlySpan<T>
@@ -1966,8 +1969,6 @@ namespace System
public int Length { get { throw null; } }
public void CopyTo(System.Span<T> destination) { }
[System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
- public static System.ReadOnlySpan<T> DangerousCreate(object obj, ref T objectData, int length) { throw null; }
- [System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
[System.ObsoleteAttribute("Equals() on ReadOnlySpan will always throw an exception. Use == instead.")]
public override bool Equals(object obj) { throw null; }
public System.ReadOnlySpan<T>.Enumerator GetEnumerator() { throw null; }
@@ -1975,12 +1976,13 @@ namespace System
[System.ObsoleteAttribute("GetHashCode() on ReadOnlySpan will always throw an exception.")]
public override int GetHashCode() { throw null; }
public static bool operator ==(System.ReadOnlySpan<T> left, System.ReadOnlySpan<T> right) { throw null; }
- public static implicit operator System.ReadOnlySpan<T> (System.ArraySegment<T> arraySegment) { throw null; }
+ public static implicit operator System.ReadOnlySpan<T> (System.ArraySegment<T> segment) { throw null; }
public static implicit operator System.ReadOnlySpan<T> (T[] array) { throw null; }
public static bool operator !=(System.ReadOnlySpan<T> left, System.ReadOnlySpan<T> right) { throw null; }
public System.ReadOnlySpan<T> Slice(int start) { throw null; }
public System.ReadOnlySpan<T> Slice(int start, int length) { throw null; }
public T[] ToArray() { throw null; }
+ public override string ToString() { throw null; }
public bool TryCopyTo(System.Span<T> destination) { throw null; }
public ref partial struct Enumerator
{
@@ -2050,7 +2052,7 @@ namespace System
public override int GetHashCode() { throw null; }
public System.TypeCode GetTypeCode() { throw null; }
[System.CLSCompliantAttribute(false)]
- public static System.SByte Parse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style=(System.Globalization.NumberStyles)(7), System.IFormatProvider provider=null) { throw null; }
+ public static System.SByte Parse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style = (System.Globalization.NumberStyles)(7), System.IFormatProvider provider = null) { throw null; }
[System.CLSCompliantAttribute(false)]
public static System.SByte Parse(string s) { throw null; }
[System.CLSCompliantAttribute(false)]
@@ -2078,7 +2080,7 @@ namespace System
public string ToString(System.IFormatProvider provider) { throw null; }
public string ToString(string format) { throw null; }
public string ToString(string format, System.IFormatProvider provider) { throw null; }
- public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format=default(System.ReadOnlySpan<char>), System.IFormatProvider provider=null) { throw null; }
+ public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format = default(System.ReadOnlySpan<char>), System.IFormatProvider provider = null) { throw null; }
[System.CLSCompliantAttribute(false)]
public static bool TryParse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style, System.IFormatProvider provider, out System.SByte result) { throw null; }
[System.CLSCompliantAttribute(false)]
@@ -2122,7 +2124,7 @@ namespace System
public static bool operator !=(System.Single left, System.Single right) { throw null; }
public static bool operator <(System.Single left, System.Single right) { throw null; }
public static bool operator <=(System.Single left, System.Single right) { throw null; }
- public static System.Single Parse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style=(System.Globalization.NumberStyles)(7), System.IFormatProvider provider=null) { throw null; }
+ public static System.Single Parse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style = (System.Globalization.NumberStyles)(7), System.IFormatProvider provider = null) { throw null; }
public static System.Single Parse(string s) { throw null; }
public static System.Single Parse(string s, System.Globalization.NumberStyles style) { throw null; }
public static System.Single Parse(string s, System.Globalization.NumberStyles style, System.IFormatProvider provider) { throw null; }
@@ -2146,7 +2148,7 @@ namespace System
public string ToString(System.IFormatProvider provider) { throw null; }
public string ToString(string format) { throw null; }
public string ToString(string format, System.IFormatProvider provider) { throw null; }
- public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format=default(System.ReadOnlySpan<char>), System.IFormatProvider provider=null) { throw null; }
+ public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format = default(System.ReadOnlySpan<char>), System.IFormatProvider provider = null) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style, System.IFormatProvider provider, out System.Single result) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> s, out System.Single result) { throw null; }
public static bool TryParse(string s, System.Globalization.NumberStyles style, System.IFormatProvider provider, out System.Single result) { throw null; }
@@ -2166,8 +2168,6 @@ namespace System
public void Clear() { }
public void CopyTo(System.Span<T> destination) { }
[System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
- public static System.Span<T> DangerousCreate(object obj, ref T objectData, int length) { throw null; }
- [System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
[System.ObsoleteAttribute("Equals() on Span will always throw an exception. Use == instead.")]
public override bool Equals(object obj) { throw null; }
public void Fill(T value) { }
@@ -2176,13 +2176,14 @@ namespace System
[System.ObsoleteAttribute("GetHashCode() on Span will always throw an exception.")]
public override int GetHashCode() { throw null; }
public static bool operator ==(System.Span<T> left, System.Span<T> right) { throw null; }
- public static implicit operator System.Span<T> (System.ArraySegment<T> arraySegment) { throw null; }
+ public static implicit operator System.Span<T> (System.ArraySegment<T> segment) { throw null; }
public static implicit operator System.ReadOnlySpan<T> (System.Span<T> span) { throw null; }
public static implicit operator System.Span<T> (T[] array) { throw null; }
public static bool operator !=(System.Span<T> left, System.Span<T> right) { throw null; }
public System.Span<T> Slice(int start) { throw null; }
public System.Span<T> Slice(int start, int length) { throw null; }
public T[] ToArray() { throw null; }
+ public override string ToString() { throw null; }
public bool TryCopyTo(System.Span<T> destination) { throw null; }
public ref partial struct Enumerator
{
@@ -2331,14 +2332,14 @@ namespace System
public System.String Replace(System.String oldValue, System.String newValue) { throw null; }
public System.String Replace(System.String oldValue, System.String newValue, bool ignoreCase, System.Globalization.CultureInfo culture) { throw null; }
public System.String Replace(System.String oldValue, System.String newValue, System.StringComparison comparisonType) { throw null; }
- public string[] Split(char separator, int count, System.StringSplitOptions options=(System.StringSplitOptions)(0)) { throw null; }
- public string[] Split(char separator, System.StringSplitOptions options=(System.StringSplitOptions)(0)) { throw null; }
+ public string[] Split(char separator, int count, System.StringSplitOptions options = (System.StringSplitOptions)(0)) { throw null; }
+ public string[] Split(char separator, System.StringSplitOptions options = (System.StringSplitOptions)(0)) { throw null; }
public string[] Split(params char[] separator) { throw null; }
public string[] Split(char[] separator, int count) { throw null; }
public string[] Split(char[] separator, int count, System.StringSplitOptions options) { throw null; }
public string[] Split(char[] separator, System.StringSplitOptions options) { throw null; }
- public string[] Split(System.String separator, int count, System.StringSplitOptions options=(System.StringSplitOptions)(0)) { throw null; }
- public string[] Split(System.String separator, System.StringSplitOptions options=(System.StringSplitOptions)(0)) { throw null; }
+ public string[] Split(System.String separator, int count, System.StringSplitOptions options = (System.StringSplitOptions)(0)) { throw null; }
+ public string[] Split(System.String separator, System.StringSplitOptions options = (System.StringSplitOptions)(0)) { throw null; }
public string[] Split(string[] separator, int count, System.StringSplitOptions options) { throw null; }
public string[] Split(string[] separator, System.StringSplitOptions options) { throw null; }
public bool StartsWith(char value) { throw null; }
@@ -2477,11 +2478,11 @@ namespace System
public static System.TimeSpan operator -(System.TimeSpan t1, System.TimeSpan t2) { throw null; }
public static System.TimeSpan operator -(System.TimeSpan t) { throw null; }
public static System.TimeSpan operator +(System.TimeSpan t) { throw null; }
- public static System.TimeSpan Parse(System.ReadOnlySpan<char> input, System.IFormatProvider formatProvider=null) { throw null; }
+ public static System.TimeSpan Parse(System.ReadOnlySpan<char> input, System.IFormatProvider formatProvider = null) { throw null; }
public static System.TimeSpan Parse(string s) { throw null; }
public static System.TimeSpan Parse(string input, System.IFormatProvider formatProvider) { throw null; }
- public static System.TimeSpan ParseExact(System.ReadOnlySpan<char> input, System.ReadOnlySpan<char> format, System.IFormatProvider formatProvider, System.Globalization.TimeSpanStyles styles=(System.Globalization.TimeSpanStyles)(0)) { throw null; }
- public static System.TimeSpan ParseExact(System.ReadOnlySpan<char> input, string[] formats, System.IFormatProvider formatProvider, System.Globalization.TimeSpanStyles styles=(System.Globalization.TimeSpanStyles)(0)) { throw null; }
+ public static System.TimeSpan ParseExact(System.ReadOnlySpan<char> input, System.ReadOnlySpan<char> format, System.IFormatProvider formatProvider, System.Globalization.TimeSpanStyles styles = (System.Globalization.TimeSpanStyles)(0)) { throw null; }
+ public static System.TimeSpan ParseExact(System.ReadOnlySpan<char> input, string[] formats, System.IFormatProvider formatProvider, System.Globalization.TimeSpanStyles styles = (System.Globalization.TimeSpanStyles)(0)) { throw null; }
public static System.TimeSpan ParseExact(string input, string format, System.IFormatProvider formatProvider) { throw null; }
public static System.TimeSpan ParseExact(string input, string format, System.IFormatProvider formatProvider, System.Globalization.TimeSpanStyles styles) { throw null; }
public static System.TimeSpan ParseExact(string input, string[] formats, System.IFormatProvider formatProvider) { throw null; }
@@ -2490,7 +2491,7 @@ namespace System
public override string ToString() { throw null; }
public string ToString(string format) { throw null; }
public string ToString(string format, System.IFormatProvider formatProvider) { throw null; }
- public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format=default(System.ReadOnlySpan<char>), System.IFormatProvider formatProvider=null) { throw null; }
+ public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format = default(System.ReadOnlySpan<char>), System.IFormatProvider formatProvider = null) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> input, System.IFormatProvider formatProvider, out System.TimeSpan result) { throw null; }
public static bool TryParse(System.ReadOnlySpan<char> s, out System.TimeSpan result) { throw null; }
public static bool TryParse(string input, System.IFormatProvider formatProvider, out System.TimeSpan result) { throw null; }
@@ -3112,7 +3113,7 @@ namespace System
public override int GetHashCode() { throw null; }
public System.TypeCode GetTypeCode() { throw null; }
[System.CLSCompliantAttribute(false)]
- public static System.UInt16 Parse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style=(System.Globalization.NumberStyles)(7), System.IFormatProvider provider=null) { throw null; }
+ public static System.UInt16 Parse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style = (System.Globalization.NumberStyles)(7), System.IFormatProvider provider = null) { throw null; }
[System.CLSCompliantAttribute(false)]
public static System.UInt16 Parse(string s) { throw null; }
[System.CLSCompliantAttribute(false)]
@@ -3140,7 +3141,7 @@ namespace System
public string ToString(System.IFormatProvider provider) { throw null; }
public string ToString(string format) { throw null; }
public string ToString(string format, System.IFormatProvider provider) { throw null; }
- public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format=default(System.ReadOnlySpan<char>), System.IFormatProvider provider=null) { throw null; }
+ public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format = default(System.ReadOnlySpan<char>), System.IFormatProvider provider = null) { throw null; }
[System.CLSCompliantAttribute(false)]
public static bool TryParse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style, System.IFormatProvider provider, out System.UInt16 result) { throw null; }
[System.CLSCompliantAttribute(false)]
@@ -3163,7 +3164,7 @@ namespace System
public override int GetHashCode() { throw null; }
public System.TypeCode GetTypeCode() { throw null; }
[System.CLSCompliantAttribute(false)]
- public static System.UInt32 Parse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style=(System.Globalization.NumberStyles)(7), System.IFormatProvider provider=null) { throw null; }
+ public static System.UInt32 Parse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style = (System.Globalization.NumberStyles)(7), System.IFormatProvider provider = null) { throw null; }
[System.CLSCompliantAttribute(false)]
public static System.UInt32 Parse(string s) { throw null; }
[System.CLSCompliantAttribute(false)]
@@ -3191,7 +3192,7 @@ namespace System
public string ToString(System.IFormatProvider provider) { throw null; }
public string ToString(string format) { throw null; }
public string ToString(string format, System.IFormatProvider provider) { throw null; }
- public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format=default(System.ReadOnlySpan<char>), System.IFormatProvider provider=null) { throw null; }
+ public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format = default(System.ReadOnlySpan<char>), System.IFormatProvider provider = null) { throw null; }
[System.CLSCompliantAttribute(false)]
public static bool TryParse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style, System.IFormatProvider provider, out System.UInt32 result) { throw null; }
[System.CLSCompliantAttribute(false)]
@@ -3214,7 +3215,7 @@ namespace System
public override int GetHashCode() { throw null; }
public System.TypeCode GetTypeCode() { throw null; }
[System.CLSCompliantAttribute(false)]
- public static System.UInt64 Parse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style=(System.Globalization.NumberStyles)(7), System.IFormatProvider provider=null) { throw null; }
+ public static System.UInt64 Parse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style = (System.Globalization.NumberStyles)(7), System.IFormatProvider provider = null) { throw null; }
[System.CLSCompliantAttribute(false)]
public static System.UInt64 Parse(string s) { throw null; }
[System.CLSCompliantAttribute(false)]
@@ -3242,7 +3243,7 @@ namespace System
public string ToString(System.IFormatProvider provider) { throw null; }
public string ToString(string format) { throw null; }
public string ToString(string format, System.IFormatProvider provider) { throw null; }
- public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format=default(System.ReadOnlySpan<char>), System.IFormatProvider provider=null) { throw null; }
+ public bool TryFormat(System.Span<char> destination, out int charsWritten, System.ReadOnlySpan<char> format = default(System.ReadOnlySpan<char>), System.IFormatProvider provider = null) { throw null; }
[System.CLSCompliantAttribute(false)]
public static bool TryParse(System.ReadOnlySpan<char> s, System.Globalization.NumberStyles style, System.IFormatProvider provider, out System.UInt64 result) { throw null; }
[System.CLSCompliantAttribute(false)]
@@ -3275,7 +3276,7 @@ namespace System
public static bool operator !=(System.UIntPtr value1, System.UIntPtr value2) { throw null; }
public static System.UIntPtr operator -(System.UIntPtr pointer, int offset) { throw null; }
public static System.UIntPtr Subtract(System.UIntPtr pointer, int offset) { throw null; }
- bool System.IEquatable<System.UIntPtr>.Equals(System.UIntPtr value) { throw null; }
+ bool System.IEquatable<System.UIntPtr>.Equals(System.UIntPtr other) { throw null; }
void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }
public unsafe void* ToPointer() { throw null; }
public override string ToString() { throw null; }
@@ -3712,7 +3713,7 @@ namespace System.Buffers
{
private object _dummy;
[System.CLSCompliantAttribute(false)]
- public unsafe MemoryHandle(System.Buffers.IRetainable owner, void* pointer=null, System.Runtime.InteropServices.GCHandle handle=default(System.Runtime.InteropServices.GCHandle)) { throw null; }
+ public unsafe MemoryHandle(System.Buffers.IRetainable retainable, void* pointer = null, System.Runtime.InteropServices.GCHandle handle = default(System.Runtime.InteropServices.GCHandle)) { throw null; }
public bool HasPointer { get { throw null; } }
[System.CLSCompliantAttribute(false)]
public unsafe void* Pointer { get { throw null; } }
@@ -3728,10 +3729,10 @@ namespace System.Buffers
public abstract System.Span<T> Span { get; }
public void Dispose() { }
protected abstract void Dispose(bool disposing);
- public abstract MemoryHandle Pin(int offset=0);
+ public abstract System.Buffers.MemoryHandle Pin(int byteOffset = 0);
public abstract bool Release();
public abstract void Retain();
- protected internal abstract bool TryGetArray(out System.ArraySegment<T> arraySegment);
+ protected internal abstract bool TryGetArray(out System.ArraySegment<T> segment);
}
public delegate void ReadOnlySpanAction<T, in TArg>(System.ReadOnlySpan<T> span, TArg arg);
public delegate void SpanAction<T, in TArg>(System.Span<T> span, TArg arg);
@@ -4147,6 +4148,7 @@ namespace System.Globalization
public static double GetNumericValue(char ch) { throw null; }
public static double GetNumericValue(string s, int index) { throw null; }
public static System.Globalization.UnicodeCategory GetUnicodeCategory(char ch) { throw null; }
+ public static System.Globalization.UnicodeCategory GetUnicodeCategory(int codePoint) { throw null; }
public static System.Globalization.UnicodeCategory GetUnicodeCategory(string s, int index) { throw null; }
}
public partial class ChineseLunisolarCalendar : System.Globalization.EastAsianLunisolarCalendar
@@ -5125,19 +5127,19 @@ namespace System.IO
[System.ObsoleteAttribute("Do not call or override this method.")]
protected virtual void ObjectInvariant() { }
public abstract int Read(byte[] buffer, int offset, int count);
- public virtual int Read(System.Span<byte> destination) { throw null; }
+ public virtual int Read(System.Span<byte> buffer) { throw null; }
public System.Threading.Tasks.Task<int> ReadAsync(byte[] buffer, int offset, int count) { throw null; }
public virtual System.Threading.Tasks.Task<int> ReadAsync(byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) { throw null; }
- public virtual System.Threading.Tasks.ValueTask<int> ReadAsync(System.Memory<byte> destination, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken)) { throw null; }
+ public virtual System.Threading.Tasks.ValueTask<int> ReadAsync(System.Memory<byte> buffer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public virtual int ReadByte() { throw null; }
public abstract long Seek(long offset, System.IO.SeekOrigin origin);
public abstract void SetLength(long value);
public static System.IO.Stream Synchronized(System.IO.Stream stream) { throw null; }
public abstract void Write(byte[] buffer, int offset, int count);
- public virtual void Write(System.ReadOnlySpan<byte> source) { }
+ public virtual void Write(System.ReadOnlySpan<byte> buffer) { }
public System.Threading.Tasks.Task WriteAsync(byte[] buffer, int offset, int count) { throw null; }
public virtual System.Threading.Tasks.Task WriteAsync(byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) { throw null; }
- public virtual System.Threading.Tasks.Task WriteAsync(System.ReadOnlyMemory<byte> source, System.Threading.CancellationToken cancellationToken=default(System.Threading.CancellationToken)) { throw null; }
+ public virtual System.Threading.Tasks.ValueTask WriteAsync(System.ReadOnlyMemory<byte> buffer, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public virtual void WriteByte(byte value) { }
}
}
@@ -6337,6 +6339,18 @@ namespace System.Runtime.CompilerServices
{
public AsyncStateMachineAttribute(System.Type stateMachineType) : base (default(System.Type)) { }
}
+ public partial struct AsyncValueTaskMethodBuilder
+ {
+ private object _dummy;
+ public System.Threading.Tasks.ValueTask Task { get { throw null; } }
+ public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : System.Runtime.CompilerServices.INotifyCompletion where TStateMachine : System.Runtime.CompilerServices.IAsyncStateMachine { }
+ public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : System.Runtime.CompilerServices.ICriticalNotifyCompletion where TStateMachine : System.Runtime.CompilerServices.IAsyncStateMachine { }
+ public static System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder Create() { throw null; }
+ public void SetException(System.Exception exception) { }
+ public void SetResult() { }
+ public void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine stateMachine) { }
+ public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : System.Runtime.CompilerServices.IAsyncStateMachine { }
+ }
public partial struct AsyncValueTaskMethodBuilder<TResult>
{
private TResult _result;
@@ -6427,13 +6441,26 @@ namespace System.Runtime.CompilerServices
public void UnsafeOnCompleted(System.Action continuation) { }
}
}
+ public readonly partial struct ConfiguredValueTaskAwaitable
+ {
+ private readonly object _dummy;
+ public System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable.ConfiguredValueTaskAwaiter GetAwaiter() { throw null; }
+ public readonly partial struct ConfiguredValueTaskAwaiter : System.Runtime.CompilerServices.ICriticalNotifyCompletion, System.Runtime.CompilerServices.INotifyCompletion
+ {
+ private readonly object _dummy;
+ public bool IsCompleted { get { throw null; } }
+ public void GetResult() { }
+ public void OnCompleted(System.Action continuation) { }
+ public void UnsafeOnCompleted(System.Action continuation) { }
+ }
+ }
public readonly partial struct ConfiguredValueTaskAwaitable<TResult>
{
private readonly object _dummy;
public System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable<TResult>.ConfiguredValueTaskAwaiter GetAwaiter() { throw null; }
- public partial struct ConfiguredValueTaskAwaiter : System.Runtime.CompilerServices.ICriticalNotifyCompletion, System.Runtime.CompilerServices.INotifyCompletion
+ public readonly partial struct ConfiguredValueTaskAwaiter : System.Runtime.CompilerServices.ICriticalNotifyCompletion, System.Runtime.CompilerServices.INotifyCompletion
{
- private object _dummy;
+ private readonly object _dummy;
public bool IsCompleted { get { throw null; } }
public TResult GetResult() { throw null; }
public void OnCompleted(System.Action continuation) { }
@@ -6713,9 +6740,17 @@ namespace System.Runtime.CompilerServices
{
public UnsafeValueTypeAttribute() { }
}
- public partial struct ValueTaskAwaiter<TResult> : System.Runtime.CompilerServices.ICriticalNotifyCompletion, System.Runtime.CompilerServices.INotifyCompletion
+ public readonly partial struct ValueTaskAwaiter : System.Runtime.CompilerServices.ICriticalNotifyCompletion, System.Runtime.CompilerServices.INotifyCompletion
{
- private object _dummy;
+ private readonly object _dummy;
+ public bool IsCompleted { get { throw null; } }
+ public void GetResult() { }
+ public void OnCompleted(System.Action continuation) { }
+ public void UnsafeOnCompleted(System.Action continuation) { }
+ }
+ public readonly partial struct ValueTaskAwaiter<TResult> : System.Runtime.CompilerServices.ICriticalNotifyCompletion, System.Runtime.CompilerServices.INotifyCompletion
+ {
+ private readonly object _dummy;
public bool IsCompleted { get { throw null; } }
public TResult GetResult() { throw null; }
public void OnCompleted(System.Action continuation) { }
@@ -7494,13 +7529,13 @@ namespace System.Text
public System.Text.StringBuilder Append(long value) { throw null; }
public System.Text.StringBuilder Append(object value) { throw null; }
public System.Text.StringBuilder Append(System.ReadOnlySpan<char> value) { throw null; }
- public System.Text.StringBuilder Append(System.Text.StringBuilder value) { throw null; }
- public System.Text.StringBuilder Append(System.Text.StringBuilder value, int startIndex, int count) { throw null; }
[System.CLSCompliantAttribute(false)]
public System.Text.StringBuilder Append(sbyte value) { throw null; }
public System.Text.StringBuilder Append(float value) { throw null; }
public System.Text.StringBuilder Append(string value) { throw null; }
public System.Text.StringBuilder Append(string value, int startIndex, int count) { throw null; }
+ public System.Text.StringBuilder Append(System.Text.StringBuilder value) { throw null; }
+ public System.Text.StringBuilder Append(System.Text.StringBuilder value, int startIndex, int count) { throw null; }
[System.CLSCompliantAttribute(false)]
public System.Text.StringBuilder Append(ushort value) { throw null; }
[System.CLSCompliantAttribute(false)]
@@ -7527,8 +7562,8 @@ namespace System.Text
public void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count) { }
public void CopyTo(int sourceIndex, System.Span<char> destination, int count) { }
public int EnsureCapacity(int capacity) { throw null; }
+ public bool Equals(System.ReadOnlySpan<char> span) { throw null; }
public bool Equals(System.Text.StringBuilder sb) { throw null; }
- public bool Equals(System.ReadOnlySpan<char> value) { throw null; }
public System.Text.StringBuilder Insert(int index, bool value) { throw null; }
public System.Text.StringBuilder Insert(int index, byte value) { throw null; }
public System.Text.StringBuilder Insert(int index, char value) { throw null; }
@@ -7964,11 +7999,32 @@ namespace System.Threading.Tasks
public bool Observed { get { throw null; } }
public void SetObserved() { }
}
+ [System.Runtime.CompilerServices.AsyncMethodBuilderAttribute(typeof(System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder))]
+ public readonly partial struct ValueTask : System.IEquatable<System.Threading.Tasks.ValueTask>
+ {
+ internal readonly object _dummy;
+ public ValueTask(System.Threading.Tasks.Task task) { throw null; }
+ public ValueTask(System.Threading.Tasks.Sources.IValueTaskSource source, short token) { throw null; }
+ public bool IsCanceled { get { throw null; } }
+ public bool IsCompleted { get { throw null; } }
+ public bool IsCompletedSuccessfully { get { throw null; } }
+ public bool IsFaulted { get { throw null; } }
+ public System.Threading.Tasks.Task AsTask() { throw null; }
+ public System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable ConfigureAwait(bool continueOnCapturedContext) { throw null; }
+ public override bool Equals(object obj) { throw null; }
+ public bool Equals(System.Threading.Tasks.ValueTask other) { throw null; }
+ public System.Runtime.CompilerServices.ValueTaskAwaiter GetAwaiter() { throw null; }
+ public override int GetHashCode() { throw null; }
+ public System.Threading.Tasks.ValueTask Preserve() { throw null; }
+ public static bool operator ==(System.Threading.Tasks.ValueTask left, System.Threading.Tasks.ValueTask right) { throw null; }
+ public static bool operator !=(System.Threading.Tasks.ValueTask left, System.Threading.Tasks.ValueTask right) { throw null; }
+ }
[System.Runtime.CompilerServices.AsyncMethodBuilderAttribute(typeof(System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder<>))]
public readonly partial struct ValueTask<TResult> : System.IEquatable<System.Threading.Tasks.ValueTask<TResult>>
{
internal readonly TResult _result;
public ValueTask(System.Threading.Tasks.Task<TResult> task) { throw null; }
+ public ValueTask(System.Threading.Tasks.Sources.IValueTaskSource<TResult> source, short token) { throw null; }
public ValueTask(TResult result) { throw null; }
public bool IsCanceled { get { throw null; } }
public bool IsCompleted { get { throw null; } }
@@ -7977,14 +8033,42 @@ namespace System.Threading.Tasks
public TResult Result { get { throw null; } }
public System.Threading.Tasks.Task<TResult> AsTask() { throw null; }
public System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable<TResult> ConfigureAwait(bool continueOnCapturedContext) { throw null; }
- [System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
- public static System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder<TResult> CreateAsyncMethodBuilder() { throw null; }
public override bool Equals(object obj) { throw null; }
public bool Equals(System.Threading.Tasks.ValueTask<TResult> other) { throw null; }
public System.Runtime.CompilerServices.ValueTaskAwaiter<TResult> GetAwaiter() { throw null; }
public override int GetHashCode() { throw null; }
+ public System.Threading.Tasks.ValueTask<TResult> Preserve() { throw null; }
public static bool operator ==(System.Threading.Tasks.ValueTask<TResult> left, System.Threading.Tasks.ValueTask<TResult> right) { throw null; }
public static bool operator !=(System.Threading.Tasks.ValueTask<TResult> left, System.Threading.Tasks.ValueTask<TResult> right) { throw null; }
public override string ToString() { throw null; }
}
}
+namespace System.Threading.Tasks.Sources
+{
+ [Flags]
+ public enum ValueTaskSourceOnCompletedFlags
+ {
+ None,
+ UseSchedulingContext = 0x1,
+ FlowExecutionContext = 0x2,
+ }
+ public enum ValueTaskSourceStatus
+ {
+ Pending = 0,
+ Succeeded = 1,
+ Faulted = 2,
+ Canceled = 3
+ }
+ public interface IValueTaskSource
+ {
+ System.Threading.Tasks.Sources.ValueTaskSourceStatus GetStatus(short token);
+ void OnCompleted(System.Action<object> continuation, object state, short token, System.Threading.Tasks.Sources.ValueTaskSourceOnCompletedFlags flags);
+ void GetResult(short token);
+ }
+ public interface IValueTaskSource<out TResult>
+ {
+ System.Threading.Tasks.Sources.ValueTaskSourceStatus GetStatus(short token);
+ void OnCompleted(System.Action<object> continuation, object state, short token, System.Threading.Tasks.Sources.ValueTaskSourceOnCompletedFlags flags);
+ TResult GetResult(short token);
+ }
+}
diff --git a/src/System.Runtime/src/ApiCompatBaseline.uapaot.txt b/src/System.Runtime/src/ApiCompatBaseline.uapaot.txt
new file mode 100644
index 0000000000..ba98be8651
--- /dev/null
+++ b/src/System.Runtime/src/ApiCompatBaseline.uapaot.txt
@@ -0,0 +1,4 @@
+Compat issues with assembly System.Runtime:
+MembersMustExist : Member 'System.Memory<T>.Pin()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.ReadOnlyMemory<T>.Pin()' does not exist in the implementation but it does exist in the contract.
+Total Issues: 2
diff --git a/src/System.Runtime/src/System.Runtime.csproj b/src/System.Runtime/src/System.Runtime.csproj
index 0129b51f90..1a80306018 100644
--- a/src/System.Runtime/src/System.Runtime.csproj
+++ b/src/System.Runtime/src/System.Runtime.csproj
@@ -5,6 +5,7 @@
<ProjectGuid>{56B9D0A9-44D3-488E-8B42-C14A6E30CAB2}</ProjectGuid>
<AssemblyName>System.Runtime</AssemblyName>
<IsPartialFacadeAssembly>true</IsPartialFacadeAssembly>
+ <ILLinkClearInitLocals>true</ILLinkClearInitLocals>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
diff --git a/src/System.Runtime/tests/Performance/System.Runtime.Performance.Tests.csproj b/src/System.Runtime/tests/Performance/System.Runtime.Performance.Tests.csproj
index d65f1a0c6e..54adbd2672 100644
--- a/src/System.Runtime/tests/Performance/System.Runtime.Performance.Tests.csproj
+++ b/src/System.Runtime/tests/Performance/System.Runtime.Performance.Tests.csproj
@@ -38,5 +38,8 @@
<Name>PerfRunner</Name>
</ProjectReference>
</ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.Runtime/tests/System.Runtime.Tests.csproj b/src/System.Runtime/tests/System.Runtime.Tests.csproj
index b4dbe71660..9fdbcd0b05 100644
--- a/src/System.Runtime/tests/System.Runtime.Tests.csproj
+++ b/src/System.Runtime/tests/System.Runtime.Tests.csproj
@@ -7,6 +7,8 @@
<NoWarn>1718</NoWarn>
<DefineConstants Condition="'$(TargetGroup)'=='netcoreapp'">$(DefineConstants);netcoreapp</DefineConstants>
<DefineConstants Condition="'$(TargetGroup)'=='uapaot'">$(DefineConstants);uapaot</DefineConstants>
+ <!-- Please don't delete. We need App.config for netfx -->
+ <NETFxTestRunnerAppConfig Condition="'$(TargetGroup)' == 'netstandard'">$(MSBuildProjectDirectory)\App.config</NETFxTestRunnerAppConfig>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
@@ -95,9 +97,11 @@
<Compile Include="System\NullableTests.cs" />
<Compile Include="System\NullReferenceExceptionTests.cs" />
<Compile Include="System\ObjectTests.cs" />
+ <Compile Include="System\PseudoCustomAttributeTests.cs" />
<Compile Include="System\SByteTests.cs" />
<Compile Include="System\SingleTests.cs" />
<Compile Include="System\StackOverflowExceptionTests.cs" />
+ <Compile Include="System\StringGetHashCodeTests.cs" />
<Compile Include="System\StringTests.cs" />
<Compile Include="System\String.SplitTests.cs" />
<Compile Include="System\SystemExceptionTests.cs" />
@@ -164,6 +168,7 @@
<Compile Include="System\Reflection\TypeTests.GetMember.cs" />
<Compile Include="System\Runtime\MemoryFailPointTests.cs" />
<Compile Include="System\Runtime\NgenServicingAttributesTests.cs" />
+ <Compile Include="System\Runtime\CompilerServices\AttributesTests.cs" />
<Compile Include="System\Runtime\CompilerServices\ConditionalWeakTableTests.cs" />
<Compile Include="System\Runtime\CompilerServices\StrongBoxTests.cs" />
<Compile Include="System\Runtime\CompilerServices\RuntimeHelpersTests.cs" />
@@ -266,5 +271,8 @@
<ItemGroup>
<EmbeddedResource Include="Resources\$(AssemblyName).rd.xml" />
</ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
diff --git a/src/System.Runtime/tests/System/ArraySegmentTests.netcoreapp.cs b/src/System.Runtime/tests/System/ArraySegmentTests.netcoreapp.cs
index 7ed13c5293..69713241b6 100644
--- a/src/System.Runtime/tests/System/ArraySegmentTests.netcoreapp.cs
+++ b/src/System.Runtime/tests/System/ArraySegmentTests.netcoreapp.cs
@@ -98,6 +98,28 @@ namespace System.Tests
var emptyArraySegment = new ArraySegment<T>(new T[1], 0, 0);
Assert.NotSame(emptyArraySegment.Array, emptyArraySegment.ToArray());
}
+
+ [Fact]
+ public void Cast_FromNullArray_ReturnsDefault()
+ {
+ ArraySegment<T> fromNull = null;
+ Assert.Null(fromNull.Array);
+ Assert.Equal(0, fromNull.Offset);
+ Assert.Equal(0, fromNull.Count);
+
+ Assert.True(default(ArraySegment<T>) == null);
+ Assert.True(new ArraySegment<T>(Array.Empty<T>()) != null);
+ }
+
+ [Fact]
+ public void Cast_FromValidArray_ReturnsSegmentForWholeArray()
+ {
+ var array = new T[42];
+ ArraySegment<T> fromArray = array;
+ Assert.Same(array, fromArray.Array);
+ Assert.Equal(0, fromArray.Offset);
+ Assert.Equal(42, fromArray.Count);
+ }
}
public static partial class ArraySegment_Tests
diff --git a/src/System.Runtime/tests/System/BooleanTests.netcoreapp.cs b/src/System.Runtime/tests/System/BooleanTests.netcoreapp.cs
index 07cb323e3c..c812391b9e 100644
--- a/src/System.Runtime/tests/System/BooleanTests.netcoreapp.cs
+++ b/src/System.Runtime/tests/System/BooleanTests.netcoreapp.cs
@@ -12,9 +12,9 @@ namespace System.Tests
[MemberData(nameof(Parse_Valid_TestData))]
public static void Parse_Span_Valid(string value, bool expected)
{
- Assert.Equal(expected, bool.Parse(value.AsReadOnlySpan()));
+ Assert.Equal(expected, bool.Parse(value.AsSpan()));
- Assert.True(bool.TryParse(value.AsReadOnlySpan(), out bool result));
+ Assert.True(bool.TryParse(value.AsSpan(), out bool result));
Assert.Equal(expected, result);
}
@@ -24,9 +24,9 @@ namespace System.Tests
{
if (value != null)
{
- Assert.Throws(exceptionType, () => bool.Parse(value.AsReadOnlySpan()));
+ Assert.Throws(exceptionType, () => bool.Parse(value.AsSpan()));
- Assert.False(bool.TryParse(value.AsReadOnlySpan(), out bool result));
+ Assert.False(bool.TryParse(value.AsSpan(), out bool result));
Assert.Equal(false, result);
}
}
diff --git a/src/System.Runtime/tests/System/ByteTests.netcoreapp.cs b/src/System.Runtime/tests/System/ByteTests.netcoreapp.cs
index 7b95e90915..b60f1a2ac9 100644
--- a/src/System.Runtime/tests/System/ByteTests.netcoreapp.cs
+++ b/src/System.Runtime/tests/System/ByteTests.netcoreapp.cs
@@ -13,9 +13,9 @@ namespace System.Tests
[MemberData(nameof(Parse_Valid_TestData))]
public static void Parse_Span_Valid(string value, NumberStyles style, IFormatProvider provider, byte expected)
{
- Assert.Equal(expected, byte.Parse(value.AsReadOnlySpan(), style, provider));
+ Assert.Equal(expected, byte.Parse(value.AsSpan(), style, provider));
- Assert.True(byte.TryParse(value.AsReadOnlySpan(), style, provider, out byte result));
+ Assert.True(byte.TryParse(value.AsSpan(), style, provider, out byte result));
Assert.Equal(expected, result);
}
@@ -25,9 +25,9 @@ namespace System.Tests
{
if (value != null)
{
- Assert.Throws(exceptionType, () => byte.Parse(value.AsReadOnlySpan(), style, provider));
+ Assert.Throws(exceptionType, () => byte.Parse(value.AsSpan(), style, provider));
- Assert.False(byte.TryParse(value.AsReadOnlySpan(), style, provider, out byte result));
+ Assert.False(byte.TryParse(value.AsSpan(), style, provider, out byte result));
Assert.Equal(0, result);
}
}
diff --git a/src/System.Runtime/tests/System/DateTimeOffsetTests.cs b/src/System.Runtime/tests/System/DateTimeOffsetTests.cs
index 97dec13593..6a20af508d 100644
--- a/src/System.Runtime/tests/System/DateTimeOffsetTests.cs
+++ b/src/System.Runtime/tests/System/DateTimeOffsetTests.cs
@@ -1055,5 +1055,104 @@ namespace System.Tests
var dateTimeOffset = new DateTimeOffset(1, 1, 1, 0, 0, 0, 0, new GregorianCalendar(),TimeSpan.Zero);
VerifyDateTimeOffset(dateTimeOffset, 1, 1, 1, 0, 0, 0, 0, TimeSpan.Zero);
}
+
+ public static IEnumerable<object[]> ToString_MatchesExpected_MemberData()
+ {
+ // Randomly generated data on netfx with:
+ // using System;
+ // class Program
+ // {
+ // static void Main()
+ // {
+ // var rand = new Random(42);
+ // var bytes = new byte[8];
+ // int i = 0;
+ // while (i < 40)
+ // {
+ // DateTimeKind kind = rand.Next(2) == 0 ? DateTimeKind.Utc : DateTimeKind.Unspecified;
+ // string format;
+ // switch (rand.Next(4))
+ // {
+ // case 0: format = "o"; break;
+ // case 1: format = "O"; break;
+ // case 2: format = "r"; break;
+ // default: format = "R"; break;
+ // }
+ //
+ // try
+ // {
+ // rand.NextBytes(bytes);
+ // long seed1 = BitConverter.ToInt64(bytes, 0);
+ // short seed2 = BitConverter.ToInt16(bytes, 0);
+ // var dto = new DateTimeOffset(seed1, TimeSpan.FromSeconds(seed2));
+ // Console.WriteLine($"yield return new object[] {{ new DateTimeOffset({seed1}, TimeSpan.FromSeconds({seed2})), \"{format}\", \"{dto.ToString(format)}\" }};");
+ // i++;
+ // }
+ // catch { }
+ // }
+ // }
+ // }
+
+ yield return new object[] { new DateTimeOffset(2900400428644841236, TimeSpan.FromSeconds(14100)), "R", "Thu, 02 Jan 9192 18:39:24 GMT" };
+ yield return new object[] { new DateTimeOffset(1274262903994885572, TimeSpan.FromSeconds(-23100)), "R", "Fri, 24 Dec 4038 14:11:39 GMT" };
+ yield return new object[] { new DateTimeOffset(1228646631256163984, TimeSpan.FromSeconds(1680)), "R", "Tue, 05 Jun 3894 16:37:25 GMT" };
+ yield return new object[] { new DateTimeOffset(2075652349868341848, TimeSpan.FromSeconds(31320)), "O", "6578-06-25T09:43:06.8341848+08:42" };
+ yield return new object[] { new DateTimeOffset(2552829549675618692, TimeSpan.FromSeconds(8580)), "O", "8090-08-05T19:56:07.5618692+02:23" };
+ yield return new object[] { new DateTimeOffset(2125715934081389968, TimeSpan.FromSeconds(5520)), "o", "6737-02-16T08:50:08.1389968+01:32" };
+ yield return new object[] { new DateTimeOffset(98868902986124576, TimeSpan.FromSeconds(3360)), "O", "0314-04-22T14:24:58.6124576+00:56" };
+ yield return new object[] { new DateTimeOffset(2013251697288306712, TimeSpan.FromSeconds(24600)), "O", "6380-09-28T10:15:28.8306712+06:50" };
+ yield return new object[] { new DateTimeOffset(1037147523427228640, TimeSpan.FromSeconds(23520)), "o", "3287-08-04T05:25:42.7228640+06:32" };
+ yield return new object[] { new DateTimeOffset(2177752403904984188, TimeSpan.FromSeconds(29820)), "r", "Mon, 09 Jan 6902 10:02:50 GMT" };
+ yield return new object[] { new DateTimeOffset(832166470435218996, TimeSpan.FromSeconds(9780)), "r", "Fri, 12 Jan 2638 12:34:23 GMT" };
+ yield return new object[] { new DateTimeOffset(651609783134768240, TimeSpan.FromSeconds(-13200)), "o", "2065-11-13T23:45:13.4768240-03:40" };
+ yield return new object[] { new DateTimeOffset(1436056534611459616, TimeSpan.FromSeconds(-480)), "o", "4551-09-07T11:17:41.1459616-00:08" };
+ yield return new object[] { new DateTimeOffset(1028124353647668124, TimeSpan.FromSeconds(-5220)), "o", "3258-12-30T17:49:24.7668124-01:27" };
+ yield return new object[] { new DateTimeOffset(815446183072290676, TimeSpan.FromSeconds(-10380)), "o", "2585-01-17T10:51:47.2290676-02:53" };
+ yield return new object[] { new DateTimeOffset(2091185090181553120, TimeSpan.FromSeconds(23520)), "r", "Fri, 14 Sep 6627 20:11:38 GMT" };
+ yield return new object[] { new DateTimeOffset(2668855365894778960, TimeSpan.FromSeconds(-20400)), "R", "Mon, 08 Apr 8458 04:56:29 GMT" };
+ yield return new object[] { new DateTimeOffset(1640160533452759488, TimeSpan.FromSeconds(8640)), "O", "5198-06-18T22:49:05.2759488+02:24" };
+ yield return new object[] { new DateTimeOffset(2958665748788957224, TimeSpan.FromSeconds(20520)), "o", "9376-08-21T15:41:18.8957224+05:42" };
+ yield return new object[] { new DateTimeOffset(2902544657562766092, TimeSpan.FromSeconds(-29940)), "R", "Tue, 20 Oct 9198 00:48:16 GMT" };
+ yield return new object[] { new DateTimeOffset(2847595389168931696, TimeSpan.FromSeconds(21360)), "R", "Thu, 02 Sep 9024 17:59:16 GMT" };
+ yield return new object[] { new DateTimeOffset(2010196475667096780, TimeSpan.FromSeconds(9420)), "r", "Sat, 23 Jan 6371 04:22:26 GMT" };
+ yield return new object[] { new DateTimeOffset(613442997756722832, TimeSpan.FromSeconds(32400)), "O", "1944-12-04T11:16:15.6722832+09:00" };
+ yield return new object[] { new DateTimeOffset(921560296274801912, TimeSpan.FromSeconds(13560)), "r", "Wed, 23 Apr 2921 13:21:07 GMT" };
+ yield return new object[] { new DateTimeOffset(1990689515682669052, TimeSpan.FromSeconds(8700)), "o", "6309-03-31T18:59:28.2669052+02:25" };
+ yield return new object[] { new DateTimeOffset(620638066929852080, TimeSpan.FromSeconds(24240)), "O", "1967-09-23T02:18:12.9852080+06:44" };
+ yield return new object[] { new DateTimeOffset(327248350932775524, TimeSpan.FromSeconds(12900)), "O", "1038-01-04T15:58:13.2775524+03:35" };
+ yield return new object[] { new DateTimeOffset(1370257845275318012, TimeSpan.FromSeconds(-10500)), "O", "4343-03-06T13:55:27.5318012-02:55" };
+ yield return new object[] { new DateTimeOffset(1239382730779209800, TimeSpan.FromSeconds(12360)), "O", "3928-06-13T18:04:37.9209800+03:26" };
+ yield return new object[] { new DateTimeOffset(2935667013803687040, TimeSpan.FromSeconds(-17280)), "o", "9303-10-05T17:56:20.3687040-04:48" };
+ yield return new object[] { new DateTimeOffset(2101626275971711700, TimeSpan.FromSeconds(-15660)), "R", "Tue, 16 Oct 6660 00:00:57 GMT" };
+ yield return new object[] { new DateTimeOffset(1417918072364232412, TimeSpan.FromSeconds(28380)), "o", "4494-03-15T21:07:16.4232412+07:53" };
+ yield return new object[] { new DateTimeOffset(962535844977970944, TimeSpan.FromSeconds(3840)), "r", "Thu, 27 Feb 3051 01:44:17 GMT" };
+ yield return new object[] { new DateTimeOffset(2576630638913059544, TimeSpan.FromSeconds(-1320)), "R", "Tue, 07 Jan 8166 09:40:11 GMT" };
+ yield return new object[] { new DateTimeOffset(991481917233718112, TimeSpan.FromSeconds(25440)), "r", "Thu, 19 Nov 3142 05:18:03 GMT" };
+ yield return new object[] { new DateTimeOffset(230115425073485984, TimeSpan.FromSeconds(-10080)), "o", "0730-03-18T07:08:27.3485984-02:48" };
+ yield return new object[] { new DateTimeOffset(1289946780226617584, TimeSpan.FromSeconds(240)), "r", "Sat, 04 Sep 4088 22:56:22 GMT" };
+ yield return new object[] { new DateTimeOffset(3119563990129685280, TimeSpan.FromSeconds(-19680)), "R", "Sun, 04 Jul 9886 16:44:52 GMT" };
+ yield return new object[] { new DateTimeOffset(1167612095351481672, TimeSpan.FromSeconds(-6840)), "r", "Thu, 06 Jan 3701 23:12:55 GMT" };
+ yield return new object[] { new DateTimeOffset(1617181518122280616, TimeSpan.FromSeconds(26280)), "O", "5125-08-24T20:50:12.2280616+07:18" };
+ }
+
+ [Theory]
+ [MemberData(nameof(ToString_MatchesExpected_MemberData))]
+ public static void ToString_MatchesExpected(DateTimeOffset dateTimeOffset, string format, string expected)
+ {
+ Assert.Equal(expected, dateTimeOffset.ToString(format));
+ }
+
+ public static IEnumerable<object[]> ToString_WithCulture_MatchesExpected_MemberData()
+ {
+ yield return new object[] { new DateTimeOffset(636572516255571994, TimeSpan.FromHours(-5)), "M", new CultureInfo("fr-FR"), "21 mars" };
+ yield return new object[] { new DateTimeOffset(636572516255571994, TimeSpan.FromHours(-5)), "Y", new CultureInfo("da-DK"), "marts 2018" };
+ }
+
+ [Theory]
+ [MemberData(nameof(ToString_WithCulture_MatchesExpected_MemberData))]
+ public static void ToString_WithCulture_MatchesExpected(DateTimeOffset dateTimeOffset, string format, CultureInfo culture, string expected)
+ {
+ Assert.Equal(expected, dateTimeOffset.ToString(format, culture));
+ }
}
}
diff --git a/src/System.Runtime/tests/System/DateTimeOffsetTests.netcoreapp.cs b/src/System.Runtime/tests/System/DateTimeOffsetTests.netcoreapp.cs
index 9b65d1fefe..97d677ac4a 100644
--- a/src/System.Runtime/tests/System/DateTimeOffsetTests.netcoreapp.cs
+++ b/src/System.Runtime/tests/System/DateTimeOffsetTests.netcoreapp.cs
@@ -15,13 +15,13 @@ namespace System.Tests
DateTimeOffset expected = DateTimeOffset.MaxValue;
string expectedString = expected.ToString();
- Assert.Equal(expectedString, DateTimeOffset.Parse(expectedString.AsReadOnlySpan()).ToString());
- Assert.Equal(expectedString, DateTimeOffset.Parse(expectedString.AsReadOnlySpan(), null).ToString());
- Assert.Equal(expectedString, DateTimeOffset.Parse(expectedString.AsReadOnlySpan(), null, DateTimeStyles.None).ToString());
+ Assert.Equal(expectedString, DateTimeOffset.Parse(expectedString.AsSpan()).ToString());
+ Assert.Equal(expectedString, DateTimeOffset.Parse(expectedString.AsSpan(), null).ToString());
+ Assert.Equal(expectedString, DateTimeOffset.Parse(expectedString.AsSpan(), null, DateTimeStyles.None).ToString());
- Assert.True(DateTimeOffset.TryParse(expectedString.AsReadOnlySpan(), out DateTimeOffset actual));
+ Assert.True(DateTimeOffset.TryParse(expectedString.AsSpan(), out DateTimeOffset actual));
Assert.Equal(expectedString, actual.ToString());
- Assert.True(DateTimeOffset.TryParse(expectedString.AsReadOnlySpan(), null, DateTimeStyles.None, out actual));
+ Assert.True(DateTimeOffset.TryParse(expectedString.AsSpan(), null, DateTimeStyles.None, out actual));
Assert.Equal(expectedString, actual.ToString());
}
@@ -65,6 +65,19 @@ namespace System.Tests
Assert.Equal(0, actual[actual.Length - 1]);
}
+ [Theory]
+ [MemberData(nameof(ToString_MatchesExpected_MemberData))]
+ public static void TryFormat_MatchesExpected(DateTimeOffset dateTimeOffset, string format, string expected)
+ {
+ var destination = new char[expected.Length];
+
+ Assert.False(dateTimeOffset.TryFormat(destination.AsSpan(0, destination.Length - 1), out _, format));
+
+ Assert.True(dateTimeOffset.TryFormat(destination, out int charsWritten, format));
+ Assert.Equal(destination.Length, charsWritten);
+ Assert.Equal(expected, new string(destination));
+ }
+
[Fact]
public static void UnixEpoch()
{
diff --git a/src/System.Runtime/tests/System/DateTimeTests.cs b/src/System.Runtime/tests/System/DateTimeTests.cs
index 27a4ed0d98..73b3d79655 100644
--- a/src/System.Runtime/tests/System/DateTimeTests.cs
+++ b/src/System.Runtime/tests/System/DateTimeTests.cs
@@ -815,6 +815,17 @@ namespace System.Tests
Assert.Equal(expectedString, result.ToString("g"));
}
+ [Fact]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Needs desktop port: https://github.com/dotnet/coreclr/issues/15896")]
+ // Regression test for https://github.com/dotnet/coreclr/issues/15896
+ public static void TryParseExact_EmptyAMPMDesignator()
+ {
+ var englishCulture = new CultureInfo("en-US");
+ englishCulture.DateTimeFormat.AMDesignator = "";
+ englishCulture.DateTimeFormat.PMDesignator = "";
+ Assert.False(DateTime.TryParseExact(" ", "%t", englishCulture, DateTimeStyles.None, out _));
+ }
+
public static void ParseExact_EscapedSingleQuotes()
{
var formatInfo = DateTimeFormatInfo.GetInstance(new CultureInfo("mt-MT"));
@@ -1027,6 +1038,69 @@ namespace System.Tests
yield return new object[] { "1234-05-06T07:00:00Z", "yyyy-MM-dd'T'HH:mm:ssFFFZ", CultureInfo.InvariantCulture, DateTimeStyles.None, TimeZoneInfo.ConvertTimeFromUtc(new DateTime(1234, 5, 6, 7, 0, 0, DateTimeKind.Utc), TimeZoneInfo.Local) };
yield return new object[] { "1234-05-06T07:00:00GMT", "yyyy-MM-dd'T'HH:mm:ssFFFZ", CultureInfo.InvariantCulture, DateTimeStyles.None, TimeZoneInfo.ConvertTimeFromUtc(new DateTime(1234, 5, 6, 7, 0, 0, DateTimeKind.Utc), TimeZoneInfo.Local) };
+
+ yield return new object[] { "9", "\" \"%d", CultureInfo.InvariantCulture, DateTimeStyles.AllowLeadingWhite, new DateTime(DateTime.Now.Year, 1, 9, 0, 0, 0) };
+ yield return new object[] { "15", "\' \'dd", CultureInfo.InvariantCulture, DateTimeStyles.AllowLeadingWhite, new DateTime(DateTime.Now.Year, 1, 15, 0, 0, 0) };
+
+ yield return new object[] { "9", "\" \"%M", CultureInfo.InvariantCulture, DateTimeStyles.AllowLeadingWhite, new DateTime(DateTime.Now.Year, 9, 1, 0, 0, 0) };
+ yield return new object[] { "09", "\" \"MM", CultureInfo.InvariantCulture, DateTimeStyles.AllowLeadingWhite, new DateTime(DateTime.Now.Year, 9, 1, 0, 0, 0) };
+ yield return new object[] { "Sep", "\" \"MMM", CultureInfo.InvariantCulture, DateTimeStyles.AllowLeadingWhite, new DateTime(DateTime.Now.Year, 9, 1, 0, 0, 0) };
+ yield return new object[] { "September", "\' \'MMMM", CultureInfo.InvariantCulture, DateTimeStyles.AllowLeadingWhite, new DateTime(DateTime.Now.Year, 9, 1, 0, 0, 0) };
+
+ yield return new object[] { "1", "\' \'%y", CultureInfo.InvariantCulture, DateTimeStyles.AllowLeadingWhite, new DateTime(2001, 1, 1, 0, 0, 0) };
+ yield return new object[] { "01", "\" \"yy", CultureInfo.InvariantCulture, DateTimeStyles.AllowLeadingWhite, new DateTime(2001, 1, 1, 0, 0, 0) };
+ yield return new object[] { "2001", "\" \"yyyy", CultureInfo.InvariantCulture, DateTimeStyles.AllowLeadingWhite, new DateTime(2001, 1, 1, 0, 0, 0) };
+
+ yield return new object[] { "3", "\" \"%H", CultureInfo.InvariantCulture, DateTimeStyles.AllowLeadingWhite, DateTime.Today + TimeSpan.FromHours(3) };
+ yield return new object[] { "03", "\" \"HH", CultureInfo.InvariantCulture, DateTimeStyles.AllowLeadingWhite, DateTime.Today + TimeSpan.FromHours(3) };
+
+ yield return new object[] { "3A", "\" \"ht", CultureInfo.InvariantCulture, DateTimeStyles.AllowLeadingWhite, DateTime.Today + TimeSpan.FromHours(3) };
+ yield return new object[] { "03A", "\" \"hht", CultureInfo.InvariantCulture, DateTimeStyles.AllowLeadingWhite, DateTime.Today + TimeSpan.FromHours(3) };
+ yield return new object[] { "3P", "\' \'ht", CultureInfo.InvariantCulture, DateTimeStyles.AllowLeadingWhite, DateTime.Today + TimeSpan.FromHours(12 + 3) };
+ yield return new object[] { "03P", "\" \"hht", CultureInfo.InvariantCulture, DateTimeStyles.AllowLeadingWhite, DateTime.Today + TimeSpan.FromHours(12 + 3) };
+
+ yield return new object[] { "2017-10-11 01:23:45Z", "u", CultureInfo.InvariantCulture, DateTimeStyles.AllowLeadingWhite, new DateTime(2017, 10, 11, 1, 23, 45) };
+ yield return new object[] { "9/8/2017 10:11:12 AM", "\' \'M/d/yyyy HH':'mm':'ss tt", CultureInfo.InvariantCulture, DateTimeStyles.AllowLeadingWhite, new DateTime(2017, 9, 8, 10, 11, 12) };
+ yield return new object[] { "9/8/2017 20:11:12 PM", "\" \"M/d/yyyy HH':'mm':'ss tt", CultureInfo.InvariantCulture, DateTimeStyles.AllowLeadingWhite, new DateTime(2017, 9, 8, 20, 11, 12) };
+ yield return new object[] { "1234-05-06T07:00:00.8Z", "\" \"yyyy-MM-dd'T'HH:mm:ss.FFF'Z'", CultureInfo.InvariantCulture, DateTimeStyles.AllowLeadingWhite, new DateTime(1234, 5, 6, 7, 0, 0, 800) };
+ yield return new object[] { "1234-05-06T07:00:00Z", "\" \"yyyy-MM-dd'T'HH:mm:ss.FFF'Z'", CultureInfo.InvariantCulture, DateTimeStyles.AllowLeadingWhite, new DateTime(1234, 5, 6, 7, 0, 0, 0) };
+ yield return new object[] { "1234-05-06T07:00:00Z", "\' \'yyyy-MM-dd'T'HH:mm:ssFFF'Z'", CultureInfo.InvariantCulture, DateTimeStyles.AllowLeadingWhite, new DateTime(1234, 5, 6, 7, 0, 0, 0) };
+ yield return new object[] { "1234-05-06T07:00:00Z", "\' \'yyyy-MM-dd'T'HH:mm:ssFFF'Z'", CultureInfo.InvariantCulture, DateTimeStyles.AllowLeadingWhite, new DateTime(1234, 5, 6, 7, 0, 0, 0) };
+ yield return new object[] { "1234-05-06T07:00:00Z", "\" \"yyyy-MM-dd'T'HH:mm:ssFFFZ", CultureInfo.InvariantCulture, DateTimeStyles.AllowLeadingWhite, TimeZoneInfo.ConvertTimeFromUtc(new DateTime(1234, 5, 6, 7, 0, 0, DateTimeKind.Utc), TimeZoneInfo.Local) };
+ yield return new object[] { "1234-05-06T07:00:00GMT", "\" \"yyyy-MM-dd'T'HH:mm:ssFFFZ", CultureInfo.InvariantCulture, DateTimeStyles.AllowLeadingWhite, TimeZoneInfo.ConvertTimeFromUtc(new DateTime(1234, 5, 6, 7, 0, 0, DateTimeKind.Utc), TimeZoneInfo.Local) };
+
+
+ yield return new object[] { "9", "%d\" \"", CultureInfo.InvariantCulture, DateTimeStyles.AllowTrailingWhite, new DateTime(DateTime.Now.Year, 1, 9, 0, 0, 0) };
+ yield return new object[] { "15", "dd\' \'", CultureInfo.InvariantCulture, DateTimeStyles.AllowTrailingWhite, new DateTime(DateTime.Now.Year, 1, 15, 0, 0, 0) };
+
+ yield return new object[] { "9", "%M\" \"", CultureInfo.InvariantCulture, DateTimeStyles.AllowTrailingWhite, new DateTime(DateTime.Now.Year, 9, 1, 0, 0, 0) };
+ yield return new object[] { "09", "MM\" \"", CultureInfo.InvariantCulture, DateTimeStyles.AllowTrailingWhite, new DateTime(DateTime.Now.Year, 9, 1, 0, 0, 0) };
+ yield return new object[] { "Sep", "MMM\" \"", CultureInfo.InvariantCulture, DateTimeStyles.AllowTrailingWhite, new DateTime(DateTime.Now.Year, 9, 1, 0, 0, 0) };
+ yield return new object[] { "September", "MMMM\' \'", CultureInfo.InvariantCulture, DateTimeStyles.AllowTrailingWhite, new DateTime(DateTime.Now.Year, 9, 1, 0, 0, 0) };
+
+ yield return new object[] { "1", "%y\' \'", CultureInfo.InvariantCulture, DateTimeStyles.AllowTrailingWhite, new DateTime(2001, 1, 1, 0, 0, 0) };
+ yield return new object[] { "01", "yy\" \"", CultureInfo.InvariantCulture, DateTimeStyles.AllowTrailingWhite, new DateTime(2001, 1, 1, 0, 0, 0) };
+ yield return new object[] { "2001", "yyyy\" \"", CultureInfo.InvariantCulture, DateTimeStyles.AllowTrailingWhite, new DateTime(2001, 1, 1, 0, 0, 0) };
+
+ yield return new object[] { "3", "%H\" \"", CultureInfo.InvariantCulture, DateTimeStyles.AllowTrailingWhite, DateTime.Today + TimeSpan.FromHours(3) };
+ yield return new object[] { "03", "HH\" \"", CultureInfo.InvariantCulture, DateTimeStyles.AllowTrailingWhite, DateTime.Today + TimeSpan.FromHours(3) };
+
+ yield return new object[] { "3A", "ht\" \"", CultureInfo.InvariantCulture, DateTimeStyles.AllowTrailingWhite, DateTime.Today + TimeSpan.FromHours(3) };
+ yield return new object[] { "03A", "hht\" \"", CultureInfo.InvariantCulture, DateTimeStyles.AllowTrailingWhite, DateTime.Today + TimeSpan.FromHours(3) };
+ yield return new object[] { "3P", "ht\' \'", CultureInfo.InvariantCulture, DateTimeStyles.AllowTrailingWhite, DateTime.Today + TimeSpan.FromHours(12 + 3) };
+ yield return new object[] { "03P", "hht\" \"", CultureInfo.InvariantCulture, DateTimeStyles.AllowTrailingWhite, DateTime.Today + TimeSpan.FromHours(12 + 3) };
+
+ yield return new object[] { "2017-10-11 01:23:45Z", "u", CultureInfo.InvariantCulture, DateTimeStyles.AllowTrailingWhite, new DateTime(2017, 10, 11, 1, 23, 45) };
+ yield return new object[] { "9/8/2017 10:11:12 AM", "M/d/yyyy HH':'mm':'ss tt\' \'", CultureInfo.InvariantCulture, DateTimeStyles.AllowTrailingWhite, new DateTime(2017, 9, 8, 10, 11, 12) };
+ yield return new object[] { "9/8/2017 20:11:12 PM", "M/d/yyyy HH':'mm':'ss tt\" \"", CultureInfo.InvariantCulture, DateTimeStyles.AllowTrailingWhite, new DateTime(2017, 9, 8, 20, 11, 12) };
+ yield return new object[] { "1234-05-06T07:00:00.8Z", "yyyy-MM-dd'T'HH:mm:ss.FFF'Z'\" \"", CultureInfo.InvariantCulture, DateTimeStyles.AllowTrailingWhite, new DateTime(1234, 5, 6, 7, 0, 0, 800) };
+ yield return new object[] { "1234-05-06T07:00:00Z", "yyyy-MM-dd'T'HH:mm:ss.FFF'Z'\" \"", CultureInfo.InvariantCulture, DateTimeStyles.AllowTrailingWhite, new DateTime(1234, 5, 6, 7, 0, 0, 0) };
+ yield return new object[] { "1234-05-06T07:00:00Z", "yyyy-MM-dd'T'HH:mm:ssFFF'Z'\' \'", CultureInfo.InvariantCulture, DateTimeStyles.AllowTrailingWhite, new DateTime(1234, 5, 6, 7, 0, 0, 0) };
+ yield return new object[] { "1234-05-06T07:00:00Z", "yyyy-MM-dd'T'HH:mm:ssFFF'Z'\' \'", CultureInfo.InvariantCulture, DateTimeStyles.AllowTrailingWhite, new DateTime(1234, 5, 6, 7, 0, 0, 0) };
+ yield return new object[] { "1234-05-06T07:00:00Z", "yyyy-MM-dd'T'HH:mm:ssFFFZ\" \"", CultureInfo.InvariantCulture, DateTimeStyles.AllowTrailingWhite, TimeZoneInfo.ConvertTimeFromUtc(new DateTime(1234, 5, 6, 7, 0, 0, DateTimeKind.Utc), TimeZoneInfo.Local) };
+ yield return new object[] { "1234-05-06T07:00:00GMT", "yyyy-MM-dd'T'HH:mm:ssFFFZ\" \"", CultureInfo.InvariantCulture, DateTimeStyles.AllowTrailingWhite, TimeZoneInfo.ConvertTimeFromUtc(new DateTime(1234, 5, 6, 7, 0, 0, DateTimeKind.Utc), TimeZoneInfo.Local) };
+
+
var hebrewCulture = new CultureInfo("he-IL");
hebrewCulture.DateTimeFormat.Calendar = new HebrewCalendar();
DateTime today = DateTime.Today;
@@ -1121,5 +1195,90 @@ namespace System.Tests
Assert.False(DateTime.TryParseExact(input, format, culture, style, out DateTime result));
Assert.False(DateTime.TryParseExact(input, new[] { format }, culture, style, out result));
}
+
+ public static IEnumerable<object[]> ToString_MatchesExpected_MemberData()
+ {
+ // Randomly generated data on netfx with:
+ // using System;
+ // class Program
+ // {
+ // static void Main()
+ // {
+ // var rand = new Random(42);
+ // var bytes = new byte[8];
+ // int i = 0;
+ // while (i < 40)
+ // {
+ // DateTimeKind kind = rand.Next(2) == 0 ? DateTimeKind.Utc : DateTimeKind.Unspecified;
+ // string format;
+ // switch (rand.Next(4))
+ // {
+ // case 0: format = "o"; break;
+ // case 1: format = "O"; break;
+ // case 2: format = "r"; break;
+ // default: format = "R"; break;
+ // }
+ //
+ // try
+ // {
+ // rand.NextBytes(bytes);
+ // long seed = BitConverter.ToInt64(bytes, 0);
+ // var dt = new DateTime(seed, kind);
+ // Console.WriteLine($"yield return new object[] {{ new DateTime({seed}, DateTimeKind.{kind}), \"{format}\", \"{dt.ToString(format)}\" }};");
+ // i++;
+ // }
+ // catch { }
+ // }
+ // }
+ //}
+
+ yield return new object[] { new DateTime(2688006240964947440, DateTimeKind.Utc), "O", "8518-12-15T08:01:36.4947440Z" };
+ yield return new object[] { new DateTime(2461197105169450509, DateTimeKind.Utc), "r", "Sun, 23 Mar 7800 18:15:16 GMT" };
+ yield return new object[] { new DateTime(71363981510699949, DateTimeKind.Unspecified), "R", "Fri, 23 Feb 0227 04:49:11 GMT" };
+ yield return new object[] { new DateTime(1678426538898407093, DateTimeKind.Unspecified), "R", "Fri, 22 Sep 5319 07:24:49 GMT" };
+ yield return new object[] { new DateTime(2689041307785948711, DateTimeKind.Utc), "o", "8522-03-27T07:52:58.5948711Z" };
+ yield return new object[] { new DateTime(996610247053299209, DateTimeKind.Unspecified), "r", "Thu, 19 Feb 3159 01:58:25 GMT" };
+ yield return new object[] { new DateTime(3105391438361510074, DateTimeKind.Unspecified), "R", "Fri, 06 Aug 9841 01:17:16 GMT" };
+ yield return new object[] { new DateTime(946433487657072106, DateTimeKind.Utc), "R", "Mon, 17 Feb 3000 03:06:05 GMT" };
+ yield return new object[] { new DateTime(2521748413631767931, DateTimeKind.Unspecified), "R", "Sat, 08 Feb 7992 07:02:43 GMT" };
+ yield return new object[] { new DateTime(49349519375012969, DateTimeKind.Utc), "R", "Fri, 20 May 0157 11:58:57 GMT" };
+ yield return new object[] { new DateTime(796677276139881359, DateTimeKind.Utc), "o", "2525-07-28T04:20:13.9881359Z" };
+ yield return new object[] { new DateTime(3022911536338429542, DateTimeKind.Unspecified), "R", "Mon, 24 Mar 9580 04:53:53 GMT" };
+ yield return new object[] { new DateTime(1144652135553351618, DateTimeKind.Utc), "R", "Tue, 04 Apr 3628 20:39:15 GMT" };
+ yield return new object[] { new DateTime(2570858096011770291, DateTimeKind.Unspecified), "o", "8147-09-23T04:53:21.1770291" };
+ yield return new object[] { new DateTime(15695724649124585, DateTimeKind.Unspecified), "R", "Tue, 27 Sep 0050 08:21:04 GMT" };
+ yield return new object[] { new DateTime(1503933934291527034, DateTimeKind.Unspecified), "O", "4766-10-12T06:37:09.1527034" };
+ yield return new object[] { new DateTime(2688603665097410101, DateTimeKind.Unspecified), "r", "Tue, 05 Nov 8520 19:08:29 GMT" };
+ yield return new object[] { new DateTime(1310336900529542610, DateTimeKind.Unspecified), "r", "Tue, 17 Apr 4153 15:14:12 GMT" };
+ yield return new object[] { new DateTime(2313720085584182693, DateTimeKind.Unspecified), "O", "7332-11-20T18:22:38.4182693" };
+ yield return new object[] { new DateTime(2291958603891779335, DateTimeKind.Unspecified), "o", "7263-12-05T20:46:29.1779335" };
+ yield return new object[] { new DateTime(262036413643976979, DateTimeKind.Unspecified), "o", "0831-05-12T21:16:04.3976979" };
+ yield return new object[] { new DateTime(684781207384421044, DateTimeKind.Utc), "O", "2170-12-26T20:12:18.4421044Z" };
+ yield return new object[] { new DateTime(1444462249169683325, DateTimeKind.Utc), "r", "Mon, 27 Apr 4578 07:21:56 GMT" };
+ yield return new object[] { new DateTime(1155518137384061537, DateTimeKind.Unspecified), "r", "Sun, 10 Sep 3662 06:02:18 GMT" };
+ yield return new object[] { new DateTime(2333390479532380569, DateTimeKind.Unspecified), "O", "7395-03-22T10:12:33.2380569" };
+ yield return new object[] { new DateTime(2217528014591554502, DateTimeKind.Unspecified), "R", "Sat, 26 Jan 7028 08:24:19 GMT" };
+ yield return new object[] { new DateTime(2764551324904480205, DateTimeKind.Utc), "O", "8761-07-08T04:21:30.4480205Z" };
+ yield return new object[] { new DateTime(2880903932678729712, DateTimeKind.Utc), "O", "9130-03-23T13:14:27.8729712Z" };
+ yield return new object[] { new DateTime(507699902578704433, DateTimeKind.Utc), "O", "1609-11-02T15:04:17.8704433Z" };
+ yield return new object[] { new DateTime(2429953022324426129, DateTimeKind.Utc), "O", "7701-03-20T15:03:52.4426129Z" };
+ yield return new object[] { new DateTime(603147512164908366, DateTimeKind.Unspecified), "O", "1912-04-20T09:33:36.4908366" };
+ yield return new object[] { new DateTime(2900400428644841236, DateTimeKind.Utc), "R", "Thu, 02 Jan 9192 22:34:24 GMT" };
+ yield return new object[] { new DateTime(1710845568474490805, DateTimeKind.Utc), "O", "5422-06-16T08:00:47.4490805Z" };
+ yield return new object[] { new DateTime(2988999715803714268, DateTimeKind.Utc), "r", "Sun, 06 Oct 9472 09:53:00 GMT" };
+ yield return new object[] { new DateTime(1068133489112689365, DateTimeKind.Utc), "r", "Wed, 12 Oct 3385 14:41:51 GMT" };
+ yield return new object[] { new DateTime(798784044525059284, DateTimeKind.Unspecified), "R", "Mon, 31 Mar 2532 13:40:52 GMT" };
+ yield return new object[] { new DateTime(2561736813034040593, DateTimeKind.Utc), "O", "8118-10-28T03:55:03.4040593Z" };
+ yield return new object[] { new DateTime(1677975383149674547, DateTimeKind.Utc), "o", "5318-04-18T03:18:34.9674547Z" };
+ yield return new object[] { new DateTime(1101778442151366156, DateTimeKind.Utc), "O", "3492-05-25T12:43:35.1366156Z" };
+ yield return new object[] { new DateTime(221550163152616218, DateTimeKind.Utc), "r", "Sun, 25 Jan 0703 19:11:55 GMT" };
+ }
+
+ [Theory]
+ [MemberData(nameof(ToString_MatchesExpected_MemberData))]
+ public static void ToString_MatchesExpected(DateTime dateTime, string format, string expected)
+ {
+ Assert.Equal(expected, dateTime.ToString(format));
+ }
}
}
diff --git a/src/System.Runtime/tests/System/DateTimeTests.netcoreapp.cs b/src/System.Runtime/tests/System/DateTimeTests.netcoreapp.cs
index 44e806cadf..b11911bea0 100644
--- a/src/System.Runtime/tests/System/DateTimeTests.netcoreapp.cs
+++ b/src/System.Runtime/tests/System/DateTimeTests.netcoreapp.cs
@@ -36,21 +36,34 @@ namespace System.Tests
}
[Theory]
+ [MemberData(nameof(ToString_MatchesExpected_MemberData))]
+ public static void TryFormat_MatchesExpected(DateTime dateTime, string format, string expected)
+ {
+ var destination = new char[expected.Length];
+
+ Assert.False(dateTime.TryFormat(destination.AsSpan(0, destination.Length - 1), out _, format));
+
+ Assert.True(dateTime.TryFormat(destination, out int charsWritten, format));
+ Assert.Equal(destination.Length, charsWritten);
+ Assert.Equal(expected, new string(destination));
+ }
+
+ [Theory]
[MemberData(nameof(Parse_ValidInput_Suceeds_MemberData))]
public static void Parse_Span_ValidInput_Suceeds(string input, CultureInfo culture, DateTime? expected)
{
- Assert.Equal(expected, DateTime.Parse(input.AsReadOnlySpan(), culture));
+ Assert.Equal(expected, DateTime.Parse(input.AsSpan(), culture));
}
[Theory]
[MemberData(nameof(ParseExact_ValidInput_Succeeds_MemberData))]
public static void ParseExact_Span_ValidInput_Succeeds(string input, string format, CultureInfo culture, DateTimeStyles style, DateTime? expected)
{
- DateTime result1 = DateTime.ParseExact(input.AsReadOnlySpan(), format, culture, style);
- DateTime result2 = DateTime.ParseExact(input.AsReadOnlySpan(), new[] { format }, culture, style);
+ DateTime result1 = DateTime.ParseExact(input.AsSpan(), format, culture, style);
+ DateTime result2 = DateTime.ParseExact(input.AsSpan(), new[] { format }, culture, style);
- Assert.True(DateTime.TryParseExact(input.AsReadOnlySpan(), format, culture, style, out DateTime result3));
- Assert.True(DateTime.TryParseExact(input.AsReadOnlySpan(), new[] { format }, culture, style, out DateTime result4));
+ Assert.True(DateTime.TryParseExact(input.AsSpan(), format, culture, style, out DateTime result3));
+ Assert.True(DateTime.TryParseExact(input.AsSpan(), new[] { format }, culture, style, out DateTime result4));
Assert.Equal(result1, result2);
Assert.Equal(result1, result3);
@@ -76,11 +89,11 @@ namespace System.Tests
[MemberData(nameof(ParseExact_InvalidInputs_Fail_MemberData))]
public static void ParseExact_Span_InvalidInputs_Fail(string input, string format, CultureInfo culture, DateTimeStyles style)
{
- Assert.Throws<FormatException>(() => DateTime.ParseExact(input.AsReadOnlySpan(), format, culture, style));
- Assert.Throws<FormatException>(() => DateTime.ParseExact(input.AsReadOnlySpan(), new[] { format }, culture, style));
+ Assert.Throws<FormatException>(() => DateTime.ParseExact(input.AsSpan(), format, culture, style));
+ Assert.Throws<FormatException>(() => DateTime.ParseExact(input.AsSpan(), new[] { format }, culture, style));
- Assert.False(DateTime.TryParseExact(input.AsReadOnlySpan(), format, culture, style, out DateTime result));
- Assert.False(DateTime.TryParseExact(input.AsReadOnlySpan(), new[] { format }, culture, style, out result));
+ Assert.False(DateTime.TryParseExact(input.AsSpan(), format, culture, style, out DateTime result));
+ Assert.False(DateTime.TryParseExact(input.AsSpan(), new[] { format }, culture, style, out result));
}
[Fact]
diff --git a/src/System.Runtime/tests/System/DecimalTests.cs b/src/System.Runtime/tests/System/DecimalTests.cs
index c82adf4d8c..a2a19c7587 100644
--- a/src/System.Runtime/tests/System/DecimalTests.cs
+++ b/src/System.Runtime/tests/System/DecimalTests.cs
@@ -1455,6 +1455,153 @@ namespace System.Tests
}
}
+ [Fact]
+ public static void BigInteger_Floor()
+ {
+ decimal[] decimalValues = GetRandomData(out BigDecimal[] bigDecimals);
+ for (int i = 0; i < decimalValues.Length; i++)
+ {
+ decimal d1 = decimalValues[i];
+ BigDecimal expected = bigDecimals[i].Floor();
+ decimal actual = decimal.Floor(d1);
+ unsafe
+ {
+ if (expected.Scale != (byte)(*(uint*)&actual >> BigDecimal.ScaleShift) || expected.CompareTo(new BigDecimal(actual)) != 0)
+ throw new Xunit.Sdk.AssertActualExpectedException(expected, actual, d1 + " Floor");
+ }
+ }
+ }
+
+ [Fact]
+ public static void BigInteger_Ceiling()
+ {
+ decimal[] decimalValues = GetRandomData(out BigDecimal[] bigDecimals);
+ for (int i = 0; i < decimalValues.Length; i++)
+ {
+ decimal d1 = decimalValues[i];
+ BigDecimal expected = bigDecimals[i].Ceiling();
+ decimal actual = decimal.Ceiling(d1);
+ unsafe
+ {
+ if (expected.Scale != (byte)(*(uint*)&actual >> BigDecimal.ScaleShift) || expected.CompareTo(new BigDecimal(actual)) != 0)
+ throw new Xunit.Sdk.AssertActualExpectedException(expected, actual, d1 + " Ceiling");
+ }
+ }
+ }
+
+ [Fact]
+ public static void BigInteger_Truncate()
+ {
+ decimal[] decimalValues = GetRandomData(out BigDecimal[] bigDecimals);
+ for (int i = 0; i < decimalValues.Length; i++)
+ {
+ decimal d1 = decimalValues[i];
+ BigDecimal expected = bigDecimals[i].Truncate();
+ decimal actual = decimal.Truncate(d1);
+ unsafe
+ {
+ if (expected.Scale != (byte)(*(uint*)&actual >> BigDecimal.ScaleShift) || expected.CompareTo(new BigDecimal(actual)) != 0)
+ throw new Xunit.Sdk.AssertActualExpectedException(expected, actual, d1 + " Truncate");
+ }
+ }
+ }
+
+ [Fact]
+ public static void BigInteger_ToInt32()
+ {
+ decimal[] decimalValues = GetRandomData(out BigDecimal[] bigDecimals);
+ for (int i = 0; i < decimalValues.Length; i++)
+ {
+ decimal d1 = decimalValues[i];
+ int expected = bigDecimals[i].ToInt32(out bool expectedOverflow);
+ if (expectedOverflow)
+ {
+ try
+ {
+ int actual = decimal.ToInt32(d1);
+ throw new Xunit.Sdk.AssertActualExpectedException(typeof(OverflowException), actual, d1 + " ToInt32");
+ }
+ catch (OverflowException) { }
+ }
+ else
+ {
+ int actual = decimal.ToInt32(d1);
+ if (expected != actual)
+ throw new Xunit.Sdk.AssertActualExpectedException(expected, actual, d1 + " ToInt32");
+ }
+ }
+ }
+
+ [Fact]
+ public static void BigInteger_ToOACurrency()
+ {
+ decimal[] decimalValues = GetRandomData(out BigDecimal[] bigDecimals);
+ for (int i = 0; i < decimalValues.Length; i++)
+ {
+ decimal d1 = decimalValues[i];
+ long expected = bigDecimals[i].ToOACurrency(out bool expectedOverflow);
+ if (expectedOverflow)
+ {
+ try
+ {
+ long actual = decimal.ToOACurrency(d1);
+ throw new Xunit.Sdk.AssertActualExpectedException(typeof(OverflowException), actual, d1 + " ToOACurrency");
+ }
+ catch (OverflowException) { }
+ }
+ else
+ {
+ long actual = decimal.ToOACurrency(d1);
+ if (expected != actual)
+ throw new Xunit.Sdk.AssertActualExpectedException(expected, actual, d1 + " ToOACurrency");
+ }
+ }
+ }
+
+ [Fact]
+ public static void BigInteger_Round()
+ {
+ decimal[] decimalValues = GetRandomData(out BigDecimal[] bigDecimals);
+ for (int i = 0; i < decimalValues.Length; i++)
+ {
+ decimal d1 = decimalValues[i];
+ BigDecimal b1 = bigDecimals[i];
+ for (int j = 0; j <= 28; j++)
+ {
+
+ BigDecimal expected = b1.Round(j);
+ decimal actual = decimal.Round(d1, j);
+ unsafe
+ {
+ if (expected.Scale != (byte)(*(uint*)&actual >> BigDecimal.ScaleShift) || expected.CompareTo(new BigDecimal(actual)) != 0)
+ throw new Xunit.Sdk.AssertActualExpectedException(expected, actual, d1 + " Round(" + j + ")");
+ }
+ }
+ }
+ }
+
+ [Fact]
+ public static void BigInteger_RoundAwayFromZero()
+ {
+ decimal[] decimalValues = GetRandomData(out BigDecimal[] bigDecimals);
+ for (int i = 0; i < decimalValues.Length; i++)
+ {
+ decimal d1 = decimalValues[i];
+ BigDecimal b1 = bigDecimals[i];
+ for (int j = 0; j <= 28; j++)
+ {
+
+ BigDecimal expected = b1.RoundAwayFromZero(j);
+ decimal actual = decimal.Round(d1, j, MidpointRounding.AwayFromZero);
+ unsafe
+ {
+ if (expected.Scale != (byte)(*(uint*)&actual >> BigDecimal.ScaleShift) || expected.CompareTo(new BigDecimal(actual)) != 0)
+ throw new Xunit.Sdk.AssertActualExpectedException(expected, actual, d1 + " RoundAwayFromZero(" + j + ")");
+ }
+ }
+ }
+ }
+
static decimal[] GetRandomData(out BigDecimal[] bigDecimals)
{
// some static data to test the limits
@@ -1698,6 +1845,69 @@ namespace System.Tests
}
return false;
}
+
+ public BigDecimal Floor() => FloorCeiling(Integer.Sign < 0);
+ public BigDecimal Ceiling() => FloorCeiling(Integer.Sign > 0);
+
+ BigDecimal FloorCeiling(bool up)
+ {
+ if (Scale == 0)
+ return this;
+ var res = BigInteger.DivRem(Integer, Pow10[Scale], out var remainder);
+ if (up && !remainder.IsZero)
+ res += Integer.Sign;
+ return new BigDecimal(res, 0);
+ }
+
+ public BigDecimal Truncate() => Scale == 0 ? this : new BigDecimal(Integer / Pow10[Scale], 0);
+
+ public int ToInt32(out bool expectedOverflow)
+ {
+ var i = Truncate().Integer;
+ return (expectedOverflow = i < int.MinValue || i > int.MaxValue) ? 0 : (int)i;
+ }
+
+ public long ToOACurrency(out bool expectedOverflow)
+ {
+ var i = Integer;
+ if (Scale < 4)
+ i *= Pow10[4 - Scale];
+ else if (Scale > 4)
+ i = RoundToEven(i, Scale - 4);
+ return (expectedOverflow = i < long.MinValue || i > long.MaxValue) ? 0 : (long)i;
+ }
+
+ static BigInteger RoundToEven(BigInteger value, int scale)
+ {
+ var pow = Pow10[scale];
+ var res = BigInteger.DivRem(value, pow, out var remainder);
+ pow >>= 1;
+ remainder = BigInteger.Abs(remainder);
+ if (remainder > pow || remainder == pow && !res.IsEven)
+ res += value.Sign;
+ return res;
+ }
+
+ public BigDecimal Round(int scale)
+ {
+ var diff = Scale - scale;
+ if (diff <= 0)
+ return this;
+ return new BigDecimal(RoundToEven(Integer, diff), (byte)scale);
+ }
+
+ public BigDecimal RoundAwayFromZero(int scale)
+ {
+ var diff = Scale - scale;
+ if (diff <= 0)
+ return this;
+
+ var pow = Pow10[diff];
+ var res = BigInteger.DivRem(Integer, pow, out var remainder);
+ if (BigInteger.Abs(remainder) >= (pow >> 1))
+ res += Integer.Sign;
+ return new BigDecimal(res, (byte)scale);
+ }
}
}
}
diff --git a/src/System.Runtime/tests/System/DecimalTests.netcoreapp.cs b/src/System.Runtime/tests/System/DecimalTests.netcoreapp.cs
index 6afd958d71..76ad9fea81 100644
--- a/src/System.Runtime/tests/System/DecimalTests.netcoreapp.cs
+++ b/src/System.Runtime/tests/System/DecimalTests.netcoreapp.cs
@@ -13,9 +13,9 @@ namespace System.Tests
[MemberData(nameof(Parse_Valid_TestData))]
public static void Parse_Span_Valid(string value, NumberStyles style, IFormatProvider provider, decimal expected)
{
- Assert.Equal(expected, decimal.Parse(value.AsReadOnlySpan(), style, provider));
+ Assert.Equal(expected, decimal.Parse(value.AsSpan(), style, provider));
- Assert.True(decimal.TryParse(value.AsReadOnlySpan(), style, provider, out decimal result));
+ Assert.True(decimal.TryParse(value.AsSpan(), style, provider, out decimal result));
Assert.Equal(expected, result);
}
@@ -25,9 +25,9 @@ namespace System.Tests
{
if (value != null)
{
- Assert.Throws(exceptionType, () => decimal.Parse(value.AsReadOnlySpan(), style, provider));
+ Assert.Throws(exceptionType, () => decimal.Parse(value.AsSpan(), style, provider));
- Assert.False(decimal.TryParse(value.AsReadOnlySpan(), style, provider, out decimal result));
+ Assert.False(decimal.TryParse(value.AsSpan(), style, provider, out decimal result));
Assert.Equal(0, result);
}
}
diff --git a/src/System.Runtime/tests/System/DoubleTests.cs b/src/System.Runtime/tests/System/DoubleTests.cs
index 69290976b3..9d3310f25e 100644
--- a/src/System.Runtime/tests/System/DoubleTests.cs
+++ b/src/System.Runtime/tests/System/DoubleTests.cs
@@ -205,8 +205,10 @@ namespace System.Tests
[InlineData((double)789, (double)-789, false)]
[InlineData((double)789, (double)0, false)]
[InlineData(double.NaN, double.NaN, true)]
+ [InlineData(double.NaN, -double.NaN, true)]
[InlineData((double)789, (float)789, false)]
[InlineData((double)789, "789", false)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "The fix was made in coreclr that is not in netfx. See https://github.com/dotnet/coreclr/issues/6237")]
public static void Equals(double d1, object value, bool expected)
{
if (value is double d2)
diff --git a/src/System.Runtime/tests/System/DoubleTests.netcoreapp.cs b/src/System.Runtime/tests/System/DoubleTests.netcoreapp.cs
index 90b5aaa60d..e024000ca5 100644
--- a/src/System.Runtime/tests/System/DoubleTests.netcoreapp.cs
+++ b/src/System.Runtime/tests/System/DoubleTests.netcoreapp.cs
@@ -91,9 +91,9 @@ namespace System.Tests
[MemberData(nameof(Parse_Valid_TestData))]
public static void Parse_Span_Valid(string value, NumberStyles style, IFormatProvider provider, double expected)
{
- Assert.Equal(expected, double.Parse(value.AsReadOnlySpan(), style, provider));
+ Assert.Equal(expected, double.Parse(value.AsSpan(), style, provider));
- Assert.True(double.TryParse(value.AsReadOnlySpan(), style, provider, out double result));
+ Assert.True(double.TryParse(value.AsSpan(), style, provider, out double result));
Assert.Equal(expected, result);
}
@@ -103,9 +103,9 @@ namespace System.Tests
{
if (value != null)
{
- Assert.Throws(exceptionType, () => double.Parse(value.AsReadOnlySpan(), style, provider));
+ Assert.Throws(exceptionType, () => double.Parse(value.AsSpan(), style, provider));
- Assert.False(double.TryParse(value.AsReadOnlySpan(), style, provider, out double result));
+ Assert.False(double.TryParse(value.AsSpan(), style, provider, out double result));
Assert.Equal(0, result);
}
}
diff --git a/src/System.Runtime/tests/System/GCTests.cs b/src/System.Runtime/tests/System/GCTests.cs
index 91ff25ec33..da919c5ed7 100644
--- a/src/System.Runtime/tests/System/GCTests.cs
+++ b/src/System.Runtime/tests/System/GCTests.cs
@@ -69,8 +69,8 @@ namespace System.Tests
[InlineData(GCCollectionMode.Optimized + 1)]
public static void Collection_InvalidCollectionMode_ThrowsArgumentOutOfRangeException(GCCollectionMode mode)
{
- AssertExtensions.Throws<ArgumentOutOfRangeException>("mode", "Enum value was out of legal range.", () => GC.Collect(2, mode));
- AssertExtensions.Throws<ArgumentOutOfRangeException>("mode", "Enum value was out of legal range.", () => GC.Collect(2, mode, false));
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("mode", null, () => GC.Collect(2, mode));
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("mode", null, () => GC.Collect(2, mode, false));
}
[Fact]
diff --git a/src/System.Runtime/tests/System/GuidTests.netcoreapp.cs b/src/System.Runtime/tests/System/GuidTests.netcoreapp.cs
index 512f35558b..a8b9f97317 100644
--- a/src/System.Runtime/tests/System/GuidTests.netcoreapp.cs
+++ b/src/System.Runtime/tests/System/GuidTests.netcoreapp.cs
@@ -77,19 +77,19 @@ namespace System.Tests
[MemberData(nameof(GuidStrings_Valid_TestData))]
public static void Parse_Span_ValidInput_Success(string input, string format, Guid expected)
{
- Assert.Equal(expected, Guid.Parse(input.AsReadOnlySpan()));
- Assert.Equal(expected, Guid.ParseExact(input.AsReadOnlySpan(), format.ToUpperInvariant()));
- Assert.Equal(expected, Guid.ParseExact(input.AsReadOnlySpan(), format.ToLowerInvariant())); // Format should be case insensitive
+ Assert.Equal(expected, Guid.Parse(input.AsSpan()));
+ Assert.Equal(expected, Guid.ParseExact(input.AsSpan(), format.ToUpperInvariant()));
+ Assert.Equal(expected, Guid.ParseExact(input.AsSpan(), format.ToLowerInvariant())); // Format should be case insensitive
Guid result;
- Assert.True(Guid.TryParse(input.AsReadOnlySpan(), out result));
+ Assert.True(Guid.TryParse(input.AsSpan(), out result));
Assert.Equal(expected, result);
- Assert.True(Guid.TryParseExact(input.AsReadOnlySpan(), format.ToUpperInvariant(), out result));
+ Assert.True(Guid.TryParseExact(input.AsSpan(), format.ToUpperInvariant(), out result));
Assert.Equal(expected, result);
- Assert.True(Guid.TryParseExact(input.AsReadOnlySpan(), format.ToLowerInvariant(), out result)); // Format should be case insensitive
+ Assert.True(Guid.TryParseExact(input.AsSpan(), format.ToLowerInvariant(), out result)); // Format should be case insensitive
Assert.Equal(expected, result);
}
@@ -107,16 +107,16 @@ namespace System.Tests
{
exceptionType = typeof(FormatException);
}
- Assert.Throws(exceptionType, () => Guid.Parse(input.AsReadOnlySpan()));
+ Assert.Throws(exceptionType, () => Guid.Parse(input.AsSpan()));
- Assert.False(Guid.TryParse(input.AsReadOnlySpan(), out Guid result));
+ Assert.False(Guid.TryParse(input.AsSpan(), out Guid result));
Assert.Equal(Guid.Empty, result);
foreach (string format in new[] { "N", "D", "B", "P", "X" })
{
- Assert.Throws(exceptionType, () => Guid.ParseExact(input.AsReadOnlySpan(), format));
+ Assert.Throws(exceptionType, () => Guid.ParseExact(input.AsSpan(), format));
- Assert.False(Guid.TryParseExact(input.AsReadOnlySpan(), format, out result));
+ Assert.False(Guid.TryParseExact(input.AsSpan(), format, out result));
Assert.Equal(Guid.Empty, result);
}
}
diff --git a/src/System.Runtime/tests/System/Int16Tests.netcoreapp.cs b/src/System.Runtime/tests/System/Int16Tests.netcoreapp.cs
index 4cd5f400c5..a03398fb60 100644
--- a/src/System.Runtime/tests/System/Int16Tests.netcoreapp.cs
+++ b/src/System.Runtime/tests/System/Int16Tests.netcoreapp.cs
@@ -13,9 +13,9 @@ namespace System.Tests
[MemberData(nameof(Parse_Valid_TestData))]
public static void Parse_Span_Valid(string value, NumberStyles style, IFormatProvider provider, short expected)
{
- Assert.Equal(expected, short.Parse(value.AsReadOnlySpan(), style, provider));
+ Assert.Equal(expected, short.Parse(value.AsSpan(), style, provider));
- Assert.True(short.TryParse(value.AsReadOnlySpan(), style, provider, out short result));
+ Assert.True(short.TryParse(value.AsSpan(), style, provider, out short result));
Assert.Equal(expected, result);
}
@@ -25,9 +25,9 @@ namespace System.Tests
{
if (value != null)
{
- Assert.Throws(exceptionType, () => short.Parse(value.AsReadOnlySpan(), style, provider));
+ Assert.Throws(exceptionType, () => short.Parse(value.AsSpan(), style, provider));
- Assert.False(short.TryParse(value.AsReadOnlySpan(), style, provider, out short result));
+ Assert.False(short.TryParse(value.AsSpan(), style, provider, out short result));
Assert.Equal(0, result);
}
}
diff --git a/src/System.Runtime/tests/System/Int32Tests.netcoreapp.cs b/src/System.Runtime/tests/System/Int32Tests.netcoreapp.cs
index b4d8193a71..6cb12dd8eb 100644
--- a/src/System.Runtime/tests/System/Int32Tests.netcoreapp.cs
+++ b/src/System.Runtime/tests/System/Int32Tests.netcoreapp.cs
@@ -13,9 +13,9 @@ namespace System.Tests
[MemberData(nameof(Parse_Valid_TestData))]
public static void Parse_Span_Valid(string value, NumberStyles style, IFormatProvider provider, int expected)
{
- Assert.Equal(expected, int.Parse(value.AsReadOnlySpan(), style, provider));
+ Assert.Equal(expected, int.Parse(value.AsSpan(), style, provider));
- Assert.True(int.TryParse(value.AsReadOnlySpan(), style, provider, out int result));
+ Assert.True(int.TryParse(value.AsSpan(), style, provider, out int result));
Assert.Equal(expected, result);
}
@@ -25,9 +25,9 @@ namespace System.Tests
{
if (value != null)
{
- Assert.Throws(exceptionType, () => int.Parse(value.AsReadOnlySpan(), style, provider));
+ Assert.Throws(exceptionType, () => int.Parse(value.AsSpan(), style, provider));
- Assert.False(int.TryParse(value.AsReadOnlySpan(), style, provider, out int result));
+ Assert.False(int.TryParse(value.AsSpan(), style, provider, out int result));
Assert.Equal(0, result);
}
}
diff --git a/src/System.Runtime/tests/System/Int64Tests.netcoreapp.cs b/src/System.Runtime/tests/System/Int64Tests.netcoreapp.cs
index 7291c5ebbb..94f55b14e7 100644
--- a/src/System.Runtime/tests/System/Int64Tests.netcoreapp.cs
+++ b/src/System.Runtime/tests/System/Int64Tests.netcoreapp.cs
@@ -13,9 +13,9 @@ namespace System.Tests
[MemberData(nameof(Parse_Valid_TestData))]
public static void Parse_Span_Valid(string value, NumberStyles style, IFormatProvider provider, long expected)
{
- Assert.Equal(expected, long.Parse(value.AsReadOnlySpan(), style, provider));
+ Assert.Equal(expected, long.Parse(value.AsSpan(), style, provider));
- Assert.True(long.TryParse(value.AsReadOnlySpan(), style, provider, out long result));
+ Assert.True(long.TryParse(value.AsSpan(), style, provider, out long result));
Assert.Equal(expected, result);
}
@@ -25,9 +25,9 @@ namespace System.Tests
{
if (value != null)
{
- Assert.Throws(exceptionType, () => long.Parse(value.AsReadOnlySpan(), style, provider));
+ Assert.Throws(exceptionType, () => long.Parse(value.AsSpan(), style, provider));
- Assert.False(long.TryParse(value.AsReadOnlySpan(), style, provider, out long result));
+ Assert.False(long.TryParse(value.AsSpan(), style, provider, out long result));
Assert.Equal(0, result);
}
}
diff --git a/src/System.Runtime/tests/System/PseudoCustomAttributeTests.cs b/src/System.Runtime/tests/System/PseudoCustomAttributeTests.cs
new file mode 100644
index 0000000000..e40da39285
--- /dev/null
+++ b/src/System.Runtime/tests/System/PseudoCustomAttributeTests.cs
@@ -0,0 +1,178 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Runtime.Serialization;
+using Xunit;
+
+namespace System.Tests
+{
+ public static partial class PseudoCustomAttributeTests
+ {
+ [Theory]
+ [MemberData(nameof(TestData_AttributeExists))]
+ [MemberData(nameof(TestData_AttributeDoesNotExist))]
+ public static void IsDefined(object target, Type attributeType, Attribute attribute)
+ {
+ switch (target)
+ {
+ case Type type:
+ Assert.Equal(attribute != null, Attribute.IsDefined(type, attributeType));
+ Assert.Equal(attribute != null, Attribute.IsDefined(type, attributeType, true));
+ break;
+ case MemberInfo memberInfo:
+ Assert.Equal(attribute != null, Attribute.IsDefined(memberInfo, attributeType));
+ Assert.Equal(attribute != null, Attribute.IsDefined(memberInfo, attributeType, true));
+ break;
+ case ParameterInfo parameterInfo:
+ Assert.Equal(attribute != null, Attribute.IsDefined(parameterInfo, attributeType));
+ Assert.Equal(attribute != null, Attribute.IsDefined(parameterInfo, attributeType, true));
+ break;
+ default:
+ Assert.True(false);
+ break;
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(TestData_AttributeExists))]
+ [MemberData(nameof(TestData_AttributeDoesNotExist))]
+ public static void GetCustomAttribute(object target, Type attributeType, Attribute attribute)
+ {
+ switch (target)
+ {
+ case Type type:
+ Assert.Equal(attribute, Attribute.GetCustomAttribute(type, attributeType));
+ Assert.Equal(attribute, Attribute.GetCustomAttribute(type, attributeType, true));
+ break;
+ case MemberInfo memberInfo:
+ Assert.Equal(attribute, Attribute.GetCustomAttribute(memberInfo, attributeType));
+ Assert.Equal(attribute, Attribute.GetCustomAttribute(memberInfo, attributeType, true));
+ break;
+ case ParameterInfo parameterInfo:
+ Assert.Equal(attribute, Attribute.GetCustomAttribute(parameterInfo, attributeType));
+ Assert.Equal(attribute, Attribute.GetCustomAttribute(parameterInfo, attributeType, true));
+ break;
+ default:
+ Assert.True(false);
+ break;
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(TestData_AttributeExists))]
+ [MemberData(nameof(TestData_AttributeDoesNotExist))]
+ public static void GetCustomAttributes(object target, Type attributeType, Attribute attribute)
+ {
+ switch (target)
+ {
+ case Type type:
+ Assert.Equal(attribute, Attribute.GetCustomAttributes(type, typeof(Attribute))
+ .Where((e) => e.GetType() == attributeType).SingleOrDefault());
+ Assert.Equal(attribute, Attribute.GetCustomAttributes(type, typeof(Attribute), true)
+ .Where((e) => e.GetType() == attributeType).SingleOrDefault());
+ break;
+ case MemberInfo memberInfo:
+ Assert.Equal(attribute, Attribute.GetCustomAttributes(memberInfo, typeof(Attribute))
+ .Where((e) => e.GetType() == attributeType).SingleOrDefault());
+ Assert.Equal(attribute, Attribute.GetCustomAttributes(memberInfo, typeof(Attribute), true)
+ .Where((e) => e.GetType() == attributeType).SingleOrDefault());
+ break;
+ case ParameterInfo parameterInfo:
+ Assert.Equal(attribute, Attribute.GetCustomAttributes(parameterInfo, typeof(Attribute))
+ .Where((e) => e.GetType() == attributeType).SingleOrDefault());
+ Assert.Equal(attribute, Attribute.GetCustomAttributes(parameterInfo, typeof(Attribute), true)
+ .Where((e) => e.GetType() == attributeType).SingleOrDefault());
+ break;
+ default:
+ Assert.True(false);
+ break;
+ }
+ }
+
+ private static IEnumerable<object[]> TestData_AttributeExists()
+ {
+ yield return new object[] { typeof(TestTypeWithAttributes), typeof(SerializableAttribute), new SerializableAttribute() };
+ yield return new object[] { typeof(ITestComInterface), typeof(ComImportAttribute), new ComImportAttribute() };
+
+ FieldInfo testField = typeof(TestTypeWithAttributes).GetField("_testField");
+ yield return new object[] { testField, typeof(FieldOffsetAttribute), new FieldOffsetAttribute(120) };
+ yield return new object[] { testField, typeof(NonSerializedAttribute), new NonSerializedAttribute() };
+ yield return new object[] { testField, typeof(MarshalAsAttribute), new MarshalAsAttribute(UnmanagedType.ByValTStr) { SizeConst = 100 } };
+
+ MethodInfo testMethod = typeof(TestTypeWithAttributes).GetMethod("TestMethod");
+
+ ParameterInfo testMethodParameter = testMethod.GetParameters()[0];
+ yield return new object[] { testMethodParameter, typeof(MarshalAsAttribute), new MarshalAsAttribute(UnmanagedType.LPArray) { ArraySubType = UnmanagedType.I4 } };
+ yield return new object[] { testMethodParameter, typeof(InAttribute), new InAttribute() };
+ yield return new object[] { testMethodParameter, typeof(OutAttribute), new OutAttribute() };
+ yield return new object[] { testMethodParameter, typeof(OptionalAttribute), new OptionalAttribute() };
+
+ yield return new object[] { testMethod.ReturnParameter, typeof(MarshalAsAttribute), new MarshalAsAttribute(UnmanagedType.Bool) };
+
+ yield return new object[] { testMethod, typeof(DllImportAttribute),
+ new DllImportAttribute("nonexistent") { CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = true, EntryPoint = "MyEntryPoint" } };
+
+ yield return new object[] { testMethod, typeof(PreserveSigAttribute), new PreserveSigAttribute() };
+ }
+
+ private static IEnumerable<object[]> TestData_AttributeDoesNotExist()
+ {
+ yield return new object[] { typeof(TestTypeWithoutAttributes), typeof(SerializableAttribute), null };
+
+ yield return new object[] { typeof(TestTypeWithoutAttributes), typeof(ComImportAttribute), null };
+
+ FieldInfo testField = typeof(TestTypeWithoutAttributes).GetField("_testField");
+ yield return new object[] { testField, typeof(FieldOffsetAttribute), null };
+ yield return new object[] { testField, typeof(NonSerializedAttribute), null };
+ yield return new object[] { testField, typeof(MarshalAsAttribute), null };
+
+ MethodInfo testMethod = typeof(TestTypeWithoutAttributes).GetMethod("TestMethod");
+
+ ParameterInfo testMethodParameter = testMethod.GetParameters()[0];
+ yield return new object[] { testMethodParameter, typeof(MarshalAsAttribute), null };
+ yield return new object[] { testMethodParameter, typeof(InAttribute), null };
+ yield return new object[] { testMethodParameter, typeof(OutAttribute), null };
+ yield return new object[] { testMethodParameter, typeof(OptionalAttribute), null };
+
+ yield return new object[] { testMethod.ReturnParameter, typeof(MarshalAsAttribute), null };
+
+ yield return new object[] { testMethod, typeof(DllImportAttribute), null };
+
+ yield return new object[] { testMethod, typeof(PreserveSigAttribute), null };
+ }
+
+ [SerializableAttribute]
+ [StructLayoutAttribute(LayoutKind.Explicit)]
+ public class TestTypeWithAttributes
+ {
+ [FieldOffsetAttribute(120)]
+ [NonSerializedAttribute]
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
+ public string _testField;
+
+ [PreserveSigAttribute]
+ [return: MarshalAsAttribute(UnmanagedType.Bool)]
+ [DllImportAttribute("nonexistent", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = true, EntryPoint = "MyEntryPoint")]
+ public extern static bool TestMethod([MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I4), In, Out, Optional] int[] x);
+ }
+
+ public class TestTypeWithoutAttributes
+ {
+ public string _testField;
+
+ public static bool TestMethod(int[] x) => false;
+ }
+
+ [ComImport]
+ [Guid("42424242-4242-4242-4242-424242424242"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ public interface ITestComInterface
+ {
+ }
+ }
+}
diff --git a/src/System.Runtime/tests/System/Reflection/AssemblyNameTests.cs b/src/System.Runtime/tests/System/Reflection/AssemblyNameTests.cs
index 0da7b72ae2..f745bdcaae 100644
--- a/src/System.Runtime/tests/System/Reflection/AssemblyNameTests.cs
+++ b/src/System.Runtime/tests/System/Reflection/AssemblyNameTests.cs
@@ -84,6 +84,11 @@ namespace System.Reflection.Tests
AssertExtensions.Throws<ArgumentException>("path", null, () => AssemblyName.GetAssemblyName(string.Empty));
Assert.Throws<System.IO.FileNotFoundException>(() => AssemblyName.GetAssemblyName("IDontExist"));
+ using (var tempFile = new TempFile(Path.GetTempFileName(), 0)) // Zero-size file
+ {
+ Assert.Throws<System.BadImageFormatException>(() => AssemblyName.GetAssemblyName(tempFile.Path));
+ }
+
using (var tempFile = new TempFile(Path.GetTempFileName(), 42))
{
Assert.Throws<System.BadImageFormatException>(() => AssemblyName.GetAssemblyName(tempFile.Path));
@@ -93,6 +98,24 @@ namespace System.Reflection.Tests
Assert.Equal(new AssemblyName(a.FullName).ToString(), AssemblyName.GetAssemblyName(a.Location).ToString());
}
+ [Fact]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "AssemblyName.GetAssemblyName() not supported on UapAot")]
+ public static void GetAssemblyName_LockedFile()
+ {
+ using (var tempFile = new TempFile(Path.GetTempFileName(), 100))
+ using (var fileStream = new FileStream(tempFile.Path, FileMode.Append, FileAccess.Write, FileShare.None))
+ {
+ if (PlatformDetection.IsWindows) // File locking is Windows specific.
+ {
+ Assert.Throws<System.IO.FileLoadException>(() => AssemblyName.GetAssemblyName(tempFile.Path));
+ }
+ else
+ {
+ Assert.Throws<System.BadImageFormatException>(() => AssemblyName.GetAssemblyName(tempFile.Path));
+ }
+ }
+ }
+
public static IEnumerable<object[]> ReferenceMatchesDefinition_TestData()
{
yield return new object[] { new AssemblyName(typeof(AssemblyNameTests).Assembly.FullName), new AssemblyName(typeof(AssemblyNameTests).Assembly.FullName), true };
diff --git a/src/System.Runtime/tests/System/Reflection/PointerTests.cs b/src/System.Runtime/tests/System/Reflection/PointerTests.cs
index 5856e745c3..731a9ef48f 100644
--- a/src/System.Runtime/tests/System/Reflection/PointerTests.cs
+++ b/src/System.Runtime/tests/System/Reflection/PointerTests.cs
@@ -23,6 +23,10 @@ namespace System.Reflection.Tests
}
}
+ unsafe delegate void MethodDelegate(byte* ptr, int expected);
+
+ unsafe delegate bool* ReturnDelegate(int expected);
+
public unsafe class PointerTests
{
[Fact]
@@ -90,6 +94,15 @@ namespace System.Reflection.Tests
Assert.Equal(value, unchecked((int)obj.field));
}
+ [Fact]
+ public void PointerFieldSetNullValue()
+ {
+ var obj = new PointerHolder();
+ FieldInfo field = typeof(PointerHolder).GetField("field");
+ field.SetValue(obj, null);
+ Assert.Equal(0, unchecked((int)obj.field));
+ }
+
[Theory]
[MemberData(nameof(Pointers))]
public void IntPtrFieldSetValue(int value)
@@ -127,7 +140,6 @@ namespace System.Reflection.Tests
[Theory]
[MemberData(nameof(Pointers))]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot, "Pointers through Invoke not implemented: https://github.com/dotnet/corert/issues/2113")]
public void PointerPropertySetValue(int value)
{
var obj = new PointerHolder();
@@ -138,7 +150,6 @@ namespace System.Reflection.Tests
[Theory]
[MemberData(nameof(Pointers))]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot, "Pointers through Invoke not implemented: https://github.com/dotnet/corert/issues/2113")]
public void IntPtrPropertySetValue(int value)
{
var obj = new PointerHolder();
@@ -149,7 +160,6 @@ namespace System.Reflection.Tests
[Theory]
[MemberData(nameof(Pointers))]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot, "Pointers through Invoke not implemented: https://github.com/dotnet/corert/issues/2113")]
public void PointerPropertySetValue_InvalidType(int value)
{
var obj = new PointerHolder();
@@ -162,7 +172,6 @@ namespace System.Reflection.Tests
[Theory]
[MemberData(nameof(Pointers))]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot, "Pointers through Invoke not implemented: https://github.com/dotnet/corert/issues/2113")]
public void PointerPropertyGetValue(int value)
{
var obj = new PointerHolder();
@@ -176,7 +185,6 @@ namespace System.Reflection.Tests
[Theory]
[MemberData(nameof(Pointers))]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot, "Pointers through Invoke not implemented: https://github.com/dotnet/corert/issues/2113")]
public void PointerMethodParameter(int value)
{
var obj = new PointerHolder();
@@ -184,9 +192,16 @@ namespace System.Reflection.Tests
method.Invoke(obj, new[] { Pointer.Box(unchecked((void*)value), typeof(byte*)), value });
}
+ [Fact]
+ public void PointerNullMethodParameter()
+ {
+ var obj = new PointerHolder();
+ MethodInfo method = typeof(PointerHolder).GetMethod("Method");
+ method.Invoke(obj, new object[] { null, 0 });
+ }
+
[Theory]
[MemberData(nameof(Pointers))]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot, "Pointers through Invoke not implemented: https://github.com/dotnet/corert/issues/2113")]
public void IntPtrMethodParameter(int value)
{
var obj = new PointerHolder();
@@ -196,7 +211,6 @@ namespace System.Reflection.Tests
[Theory]
[MemberData(nameof(Pointers))]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot, "Pointers through Invoke not implemented: https://github.com/dotnet/corert/issues/2113")]
public void PointerMethodParameter_InvalidType(int value)
{
var obj = new PointerHolder();
@@ -209,7 +223,6 @@ namespace System.Reflection.Tests
[Theory]
[MemberData(nameof(Pointers))]
- [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot, "Pointers through Invoke not implemented: https://github.com/dotnet/corert/issues/2113")]
public void PointerMethodReturn(int value)
{
var obj = new PointerHolder();
@@ -219,5 +232,55 @@ namespace System.Reflection.Tests
void* actualPointer = Pointer.Unbox(actualValue);
Assert.Equal(value, unchecked((int)actualPointer));
}
+
+ [Theory]
+ [MemberData(nameof(Pointers))]
+ public void PointerMethodDelegateParameter(int value)
+ {
+ var obj = new PointerHolder();
+ MethodDelegate d = obj.Method;
+ d.DynamicInvoke(Pointer.Box(unchecked((void*)value), typeof(byte*)), value);
+ }
+
+ [Fact]
+ public void PointerNullMethodDelegateParameter()
+ {
+ var obj = new PointerHolder();
+ MethodDelegate d = obj.Method;
+ d.DynamicInvoke(null, 0);
+ }
+
+ [Theory]
+ [MemberData(nameof(Pointers))]
+ public void IntPtrMethodDelegateParameter(int value)
+ {
+ var obj = new PointerHolder();
+ MethodDelegate d = obj.Method;
+ d.DynamicInvoke((IntPtr)value, value);
+ }
+
+ [Theory]
+ [MemberData(nameof(Pointers))]
+ public void PointerMethodDelegateParameter_InvalidType(int value)
+ {
+ var obj = new PointerHolder();
+ MethodDelegate d = obj.Method;
+ AssertExtensions.Throws<ArgumentException>(null, () =>
+ {
+ d.DynamicInvoke(Pointer.Box(unchecked((void*)value), typeof(long*)), value);
+ });
+ }
+
+ [Theory]
+ [MemberData(nameof(Pointers))]
+ public void PointerMethodDelegateReturn(int value)
+ {
+ var obj = new PointerHolder();
+ ReturnDelegate d = obj.Return;
+ object actualValue = d.DynamicInvoke(value);
+ Assert.IsType<Pointer>(actualValue);
+ void* actualPointer = Pointer.Unbox(actualValue);
+ Assert.Equal(value, unchecked((int)actualPointer));
+ }
}
}
diff --git a/src/System.Runtime/tests/System/Runtime/CompilerServices/AttributesTests.cs b/src/System.Runtime/tests/System/Runtime/CompilerServices/AttributesTests.cs
new file mode 100644
index 0000000000..876b4d367c
--- /dev/null
+++ b/src/System.Runtime/tests/System/Runtime/CompilerServices/AttributesTests.cs
@@ -0,0 +1,22 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.Runtime.CompilerServices.Tests
+{
+ public static class AttributesTests
+ {
+ [Fact]
+ public static void TypeForwardedToAttributeTests()
+ {
+ string assemblyFullName = "MyAssembly";
+ var attr = new TypeForwardedFromAttribute(assemblyFullName);
+ Assert.Equal(assemblyFullName, attr.AssemblyFullName);
+
+ AssertExtensions.Throws<ArgumentNullException>("assemblyFullName", () => new TypeForwardedFromAttribute(null));
+ AssertExtensions.Throws<ArgumentNullException>("assemblyFullName", () => new TypeForwardedFromAttribute(""));
+ }
+ }
+}
diff --git a/src/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeHelpersTests.cs b/src/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeHelpersTests.cs
index 00cb43b3f8..7c6d90127e 100644
--- a/src/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeHelpersTests.cs
+++ b/src/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeHelpersTests.cs
@@ -3,6 +3,9 @@
// See the LICENSE file in the project root for more information.
using System;
+using System.Reflection;
+using System.Collections;
+using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Xunit;
@@ -110,6 +113,72 @@ namespace System.Runtime.CompilerServices.Tests
{
public static string S;
}
+
+ [Fact]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public static void PrepareMethod()
+ {
+ foreach (MethodInfo m in typeof(RuntimeHelpersTests).GetMethods())
+ RuntimeHelpers.PrepareMethod(m.MethodHandle);
+
+ Assert.Throws<ArgumentException>(() => RuntimeHelpers.PrepareMethod(default(RuntimeMethodHandle)));
+ Assert.ThrowsAny<ArgumentException>(() => RuntimeHelpers.PrepareMethod(typeof(IList).GetMethod("Add").MethodHandle));
+ }
+
+ [Fact]
+ public static void PrepareGenericMethod()
+ {
+ Assert.Throws<ArgumentException>(() => RuntimeHelpers.PrepareMethod(default(RuntimeMethodHandle), null));
+
+ //
+ // Type instantiations
+ //
+
+ // Generic definition with instantiation is valid
+ RuntimeHelpers.PrepareMethod(typeof(List<>).GetMethod("Add").MethodHandle,
+ new RuntimeTypeHandle[] { typeof(TestStruct).TypeHandle });
+
+ // Instantiated method without instantiation is valid
+ RuntimeHelpers.PrepareMethod(typeof(List<int>).GetMethod("Add").MethodHandle,
+ null);
+
+ // Generic definition without instantiation is invalid
+ Assert.Throws<ArgumentException>(() => RuntimeHelpers.PrepareMethod(typeof(List<>).GetMethod("Add").MethodHandle,
+ null));
+
+ // Wrong instantiation
+ Assert.Throws<ArgumentException>(() => RuntimeHelpers.PrepareMethod(typeof(List<>).GetMethod("Add").MethodHandle,
+ new RuntimeTypeHandle[] { typeof(TestStruct).TypeHandle, typeof(TestStruct).TypeHandle }));
+
+ //
+ // Method instantiations
+ //
+
+ // Generic definition with instantiation is valid
+ RuntimeHelpers.PrepareMethod(typeof(Array).GetMethod("Resize").MethodHandle,
+ new RuntimeTypeHandle[] { typeof(TestStruct).TypeHandle });
+
+ // Instantiated method without instantiation is valid
+ RuntimeHelpers.PrepareMethod(typeof(Array).GetMethod("Resize")
+ .MakeGenericMethod(new Type[] { typeof(TestStruct) }).MethodHandle,
+ null);
+
+ // Generic definition without instantiation is invalid
+ Assert.Throws<ArgumentException>(() => RuntimeHelpers.PrepareMethod(typeof(Array).GetMethod("Resize").MethodHandle,
+ null));
+
+ // Wrong instantiation
+ Assert.Throws<ArgumentException>(() => RuntimeHelpers.PrepareMethod(typeof(Array).GetMethod("Resize").MethodHandle,
+ new RuntimeTypeHandle[] { typeof(TestStruct).TypeHandle, typeof(TestStruct).TypeHandle }));
+ }
+
+ [Fact]
+ public static void PrepareDelegate()
+ {
+ RuntimeHelpers.PrepareDelegate((Action)(() => { }));
+ RuntimeHelpers.PrepareDelegate((Func<int>)(() => 1) + (Func<int>)(() => 2));
+ RuntimeHelpers.PrepareDelegate(null);
+ }
}
public struct Age
diff --git a/src/System.Runtime/tests/System/Runtime/ExceptionServices/HandleProcessCorruptedStateExceptions.cs b/src/System.Runtime/tests/System/Runtime/ExceptionServices/HandleProcessCorruptedStateExceptions.cs
index 00b901ff16..03f045e904 100644
--- a/src/System.Runtime/tests/System/Runtime/ExceptionServices/HandleProcessCorruptedStateExceptions.cs
+++ b/src/System.Runtime/tests/System/Runtime/ExceptionServices/HandleProcessCorruptedStateExceptions.cs
@@ -40,14 +40,15 @@ namespace System.Runtime.ExceptionServices.Tests
[ActiveIssue("https://github.com/dotnet/corefx/issues/21123", TargetFrameworkMonikers.Uap)]
public static void ProcessExit_Called()
{
- using (Process p = RemoteInvoke(() => { CauseAVInNative(); return SuccessExitCode; }).Process)
+ using (RemoteInvokeHandle handle = RemoteInvoke(() => { CauseAVInNative(); return SuccessExitCode; }, new RemoteInvokeOptions { CheckExitCode = false }))
{
+ Process p = handle.Process;
p.WaitForExit();
if (PlatformDetection.IsFullFramework)
Assert.Equal(SuccessExitCode, p.ExitCode);
else
Assert.NotEqual(SuccessExitCode, p.ExitCode);
- }
+ }
}
}
}
diff --git a/src/System.Runtime/tests/System/SByteTests.netcoreapp.cs b/src/System.Runtime/tests/System/SByteTests.netcoreapp.cs
index 2c1ad7abd6..9b451b31f9 100644
--- a/src/System.Runtime/tests/System/SByteTests.netcoreapp.cs
+++ b/src/System.Runtime/tests/System/SByteTests.netcoreapp.cs
@@ -13,9 +13,9 @@ namespace System.Tests
[MemberData(nameof(Parse_Valid_TestData))]
public static void Parse_Span_Valid(string value, NumberStyles style, IFormatProvider provider, sbyte expected)
{
- Assert.Equal(expected, sbyte.Parse(value.AsReadOnlySpan(), style, provider));
+ Assert.Equal(expected, sbyte.Parse(value.AsSpan(), style, provider));
- Assert.True(sbyte.TryParse(value.AsReadOnlySpan(), style, provider, out sbyte result));
+ Assert.True(sbyte.TryParse(value.AsSpan(), style, provider, out sbyte result));
Assert.Equal(expected, result);
}
@@ -25,9 +25,9 @@ namespace System.Tests
{
if (value != null)
{
- Assert.Throws(exceptionType, () => sbyte.Parse(value.AsReadOnlySpan(), style, provider));
+ Assert.Throws(exceptionType, () => sbyte.Parse(value.AsSpan(), style, provider));
- Assert.False(sbyte.TryParse(value.AsReadOnlySpan(), style, provider, out sbyte result));
+ Assert.False(sbyte.TryParse(value.AsSpan(), style, provider, out sbyte result));
Assert.Equal(0, result);
}
}
diff --git a/src/System.Runtime/tests/System/SingleTests.cs b/src/System.Runtime/tests/System/SingleTests.cs
index 576b5eb383..df3afd8fb7 100644
--- a/src/System.Runtime/tests/System/SingleTests.cs
+++ b/src/System.Runtime/tests/System/SingleTests.cs
@@ -211,8 +211,10 @@ namespace System.Tests
[InlineData((float)789, (float)-789, false)]
[InlineData((float)789, (float)0, false)]
[InlineData(float.NaN, float.NaN, true)]
+ [InlineData(float.NaN, -float.NaN, true)]
[InlineData((float)789, (double)789, false)]
[InlineData((float)789, "789", false)]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "The fix was made in coreclr that is not in netfx. See https://github.com/dotnet/coreclr/issues/6237")]
public static void Equals(float f1, object value, bool expected)
{
if (value is float f2)
diff --git a/src/System.Runtime/tests/System/SingleTests.netcoreapp.cs b/src/System.Runtime/tests/System/SingleTests.netcoreapp.cs
index 2d68e56c1f..7b8a290104 100644
--- a/src/System.Runtime/tests/System/SingleTests.netcoreapp.cs
+++ b/src/System.Runtime/tests/System/SingleTests.netcoreapp.cs
@@ -91,9 +91,9 @@ namespace System.Tests
[MemberData(nameof(Parse_Valid_TestData))]
public static void Parse_Span_Valid(string value, NumberStyles style, IFormatProvider provider, float expected)
{
- Assert.Equal(expected, float.Parse(value.AsReadOnlySpan(), style, provider));
+ Assert.Equal(expected, float.Parse(value.AsSpan(), style, provider));
- Assert.True(float.TryParse(value.AsReadOnlySpan(), style, provider, out float result));
+ Assert.True(float.TryParse(value.AsSpan(), style, provider, out float result));
Assert.Equal(expected, result);
}
@@ -103,9 +103,9 @@ namespace System.Tests
{
if (value != null)
{
- Assert.Throws(exceptionType, () => float.Parse(value.AsReadOnlySpan(), style, provider));
+ Assert.Throws(exceptionType, () => float.Parse(value.AsSpan(), style, provider));
- Assert.False(float.TryParse(value.AsReadOnlySpan(), style, provider, out float result));
+ Assert.False(float.TryParse(value.AsSpan(), style, provider, out float result));
Assert.Equal(0, result);
}
}
diff --git a/src/System.Runtime/tests/System/StringGetHashCodeTests.cs b/src/System.Runtime/tests/System/StringGetHashCodeTests.cs
new file mode 100644
index 0000000000..1c868b58ac
--- /dev/null
+++ b/src/System.Runtime/tests/System/StringGetHashCodeTests.cs
@@ -0,0 +1,64 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using Xunit;
+
+namespace System.Tests
+{
+ public class StringGetHashCodeTests : RemoteExecutorTestBase
+ {
+ /// <summary>
+ /// Ensure that hash codes are randomized by getting the hash in two processes
+ /// and confirming it is different (modulo possible values of int).
+ /// If the legacy hash codes are being returned, it will not be different.
+ /// </summary>
+ [Theory]
+ [MemberData(nameof(GetHashCode_TestData))]
+ public void GetHashCodeWithStringComparer_UseSameStringInTwoProcesses_ReturnsDifferentHashCodes(int getHashCodeIndex)
+ {
+ Func<string, string, int> method = (parentHash, i) => int.Parse(parentHash) != s_GetHashCodes[int.Parse(i)]() ? SuccessExitCode : -1;
+ int parentHashCode = s_GetHashCodes[getHashCodeIndex]();
+ int exitCode, retry = 0;
+ do
+ {
+ // very small chance the child and parent hashcode are the same. To further reduce chance of collision we try up to 3 times
+ using (RemoteInvokeHandle handle = RemoteInvoke(method, parentHashCode.ToString(), getHashCodeIndex.ToString(), new RemoteInvokeOptions { CheckExitCode = false }))
+ {
+ exitCode = handle.ExitCode;
+ retry++;
+ }
+ } while (exitCode != SuccessExitCode && retry < 3);
+ Assert.Equal(SuccessExitCode, exitCode);
+ }
+
+ public static IEnumerable<object[]> GetHashCode_TestData()
+ {
+ for (int i = 0; i < s_GetHashCodes.Length; i++)
+ {
+ yield return new object[] { i };
+ }
+ }
+
+ private static readonly Func<int>[] s_GetHashCodes = {
+ () => { return StringComparer.CurrentCulture.GetHashCode("abc"); },
+ () => { return StringComparer.CurrentCultureIgnoreCase.GetHashCode("abc"); },
+ () => { return StringComparer.InvariantCulture.GetHashCode("abc"); },
+ () => { return StringComparer.InvariantCultureIgnoreCase.GetHashCode("abc"); },
+ () => { return StringComparer.Ordinal.GetHashCode("abc"); },
+ () => { return StringComparer.OrdinalIgnoreCase.GetHashCode("abc"); },
+ () => { return "abc".GetHashCode(); },
+ () => { return CultureInfo.CurrentCulture.CompareInfo.GetHashCode("abc", CompareOptions.IgnoreCase); },
+ () => { return CultureInfo.CurrentCulture.CompareInfo.GetHashCode("abc", CompareOptions.IgnoreKanaType); },
+ () => { return CultureInfo.CurrentCulture.CompareInfo.GetHashCode("abc", CompareOptions.IgnoreNonSpace); },
+ () => { return CultureInfo.CurrentCulture.CompareInfo.GetHashCode("abc", CompareOptions.IgnoreSymbols); },
+ () => { return CultureInfo.CurrentCulture.CompareInfo.GetHashCode("abc", CompareOptions.IgnoreWidth); },
+ () => { return CultureInfo.CurrentCulture.CompareInfo.GetHashCode("abc", CompareOptions.None); },
+ () => { return CultureInfo.CurrentCulture.CompareInfo.GetHashCode("abc", CompareOptions.Ordinal); },
+ () => { return CultureInfo.CurrentCulture.CompareInfo.GetHashCode("abc", CompareOptions.OrdinalIgnoreCase); }
+ };
+ }
+}
diff --git a/src/System.Runtime/tests/System/StringTests.cs b/src/System.Runtime/tests/System/StringTests.cs
index e01112b773..8a448b0dba 100644
--- a/src/System.Runtime/tests/System/StringTests.cs
+++ b/src/System.Runtime/tests/System/StringTests.cs
@@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
+using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -31,6 +32,10 @@ namespace System.Tests
{
Assert.Equal(expected, new string(value));
}
+ fixed (char* value = &MemoryMarshal.GetReference<char>(valueArray))
+ {
+ Assert.Equal(expected, new string(value));
+ }
}
[Fact]
@@ -173,6 +178,7 @@ namespace System.Tests
public static void Item_Get(string s, int index, char expected)
{
Assert.Equal(expected, s[index]);
+ Assert.Equal(expected, s.AsSpan()[index]);
}
[Fact]
@@ -181,6 +187,10 @@ namespace System.Tests
Assert.Throws<IndexOutOfRangeException>(() => "Hello"[-1]); // Index < 0
Assert.Throws<IndexOutOfRangeException>(() => "Hello"[5]); // Index >= string.Length
Assert.Throws<IndexOutOfRangeException>(() => ""[0]); // Index >= string.Length
+
+ Assert.Throws<IndexOutOfRangeException>(() => "Hello".AsSpan()[-1]); // Index < 0
+ Assert.Throws<IndexOutOfRangeException>(() => "Hello".AsSpan()[5]); // Index >= string.Length
+ Assert.Throws<IndexOutOfRangeException>(() => "".AsSpan()[0]); // Index >= string.Length
}
[Theory]
@@ -191,6 +201,7 @@ namespace System.Tests
public static void Length(string s, int expected)
{
Assert.Equal(expected, s.Length);
+ Assert.Equal(expected, s.AsSpan().Length);
}
public static IEnumerable<object[]> Concat_Strings_TestData()
@@ -435,6 +446,10 @@ namespace System.Tests
char[] dst = new char[expected.Length];
s.CopyTo(sourceIndex, dst, destinationIndex, count);
Assert.Equal(expected, dst);
+
+ Span<char> dstSpan = new char[expected.Length];
+ s.AsSpan().Slice(sourceIndex, count).CopyTo(dstSpan.Slice(destinationIndex, count));
+ Assert.Equal(expected, dstSpan.ToArray());
}
[Fact]
@@ -635,8 +650,7 @@ namespace System.Tests
{
// Use Compare(string, int, string, int, int) or Compare(string, int, string, int, int, false)
Assert.Equal(expected, Math.Sign(string.Compare(strA, indexA, strB, indexB, length)));
- // Uncomment when this is exposed in .NET Core (dotnet/corefx#10066)
- // Assert.Equal(expected, Math.Sign(string.Compare(strA, indexA, strB, indexB, length, ignoreCase: false)));
+ Assert.Equal(expected, Math.Sign(string.Compare(strA, indexA, strB, indexB, length, ignoreCase: false)));
}
}
else if (comparisonType == StringComparison.CurrentCultureIgnoreCase)
@@ -647,8 +661,7 @@ namespace System.Tests
if (!skipNonComparisonOverloads)
{
// Use Compare(string, int, string, int, int, true)
- // Uncomment when this is exposed in .NET Core (dotnet/corefx#10066)
- // Assert.Equal(expected, Math.Sign(string.Compare(strA, indexA, strB, indexB, length, ignoreCase: true)));
+ Assert.Equal(expected, Math.Sign(string.Compare(strA, indexA, strB, indexB, length, ignoreCase: true)));
}
}
else if (comparisonType == StringComparison.Ordinal)
@@ -658,6 +671,21 @@ namespace System.Tests
}
// Use Compare(string, int, string, int, int, StringComparison)
Assert.Equal(expected, Math.Sign(string.Compare(strA, indexA, strB, indexB, length, comparisonType)));
+
+ if (indexA >= 0 && indexB >= 0 && length >= 0)
+ {
+ // Comparing spans from null strings gives different results since span doesn't special case null and treats it the same as an empty string.
+ if (strA == null && strB != null)
+ expected = -1;
+ if (strA != null && strB == null)
+ expected = 1;
+ if (length == 0)
+ expected = 0;
+
+ ReadOnlySpan<char> span = length <= (strA.AsSpan().Length - indexA) ? strA.AsSpan(indexA, length) : strA.AsSpan(indexA);
+ ReadOnlySpan<char> value = length <= (strB.AsSpan().Length - indexB) ? strB.AsSpan(indexB, length) : strB.AsSpan(indexB);
+ Assert.Equal(expected, Math.Sign(span.CompareTo(value, comparisonType)));
+ }
}
[Fact]
@@ -735,6 +763,9 @@ namespace System.Tests
int result = string.Compare("{Policy_PS_Nothing}", 0, veryLongString, 4380, 19, StringComparison.Ordinal);
Assert.True(result < 0);
+
+ result = "{Policy_PS_Nothing}".AsSpan().CompareTo(veryLongString.AsSpan(4380, 19), StringComparison.Ordinal);
+ Assert.True(result < 0);
}
[Fact]
@@ -909,6 +940,9 @@ namespace System.Tests
Assert.Equal(expected, s.EndsWith(value));
}
Assert.Equal(expected, s.EndsWith(value, comparisonType));
+
+ // Cannot use implicit cast from string to ReadOnlySpan for other runtimes, like netfx. Therefore, explicitly call AsSpan.
+ Assert.Equal(expected, s.AsSpan().EndsWith(value.AsSpan(), comparisonType));
}
[Theory]
@@ -924,6 +958,12 @@ namespace System.Tests
Assert.False("te\0st".EndsWith("test", comparison));
Assert.False("test\0".EndsWith("test", comparison));
Assert.False("test".EndsWith("\0st", comparison));
+
+ Assert.True("\0test".AsSpan().EndsWith("test".AsSpan(), comparison));
+ Assert.True("te\0st".AsSpan().EndsWith("e\0st".AsSpan(), comparison));
+ Assert.False("te\0st".AsSpan().EndsWith("test".AsSpan(), comparison));
+ Assert.False("test\0".AsSpan().EndsWith("test".AsSpan(), comparison));
+ Assert.False("test".AsSpan().EndsWith("\0st".AsSpan(), comparison));
}
[Fact]
@@ -1040,6 +1080,13 @@ namespace System.Tests
Assert.Throws<InvalidOperationException>(() => enumerator.Current);
}
+ [Fact]
+ [ActiveIssue(27098, TargetFrameworkMonikers.NetFramework)]
+ public static void GetHashCode_EmbeddedNull_ReturnsDifferentHashCodes()
+ {
+ Assert.NotEqual("\0AAAAAAAAA".GetHashCode(), "\0BBBBBBBBBBBB".GetHashCode());
+ }
+
[Theory]
// CurrentCulture
[InlineData("Hello", "Hello", StringComparison.CurrentCulture, true)]
@@ -1053,6 +1100,7 @@ namespace System.Tests
[InlineData("", "Hello", StringComparison.CurrentCulture, false)]
[InlineData("", "", StringComparison.CurrentCulture, true)]
[InlineData("123", 123, StringComparison.CurrentCulture, false)] // Not a string
+ [InlineData("\0AAAAAAAAA", "\0BBBBBBBBBBBB", StringComparison.CurrentCulture, false)]
// CurrentCultureIgnoreCase
[InlineData("Hello", "Hello", StringComparison.CurrentCultureIgnoreCase, true)]
[InlineData("Hello", "hello", StringComparison.CurrentCultureIgnoreCase, true)]
@@ -1065,6 +1113,7 @@ namespace System.Tests
[InlineData("", "Hello", StringComparison.CurrentCultureIgnoreCase, false)]
[InlineData("", "", StringComparison.CurrentCultureIgnoreCase, true)]
[InlineData("123", 123, StringComparison.CurrentCultureIgnoreCase, false)] // Not a string
+ [InlineData("\0AAAAAAAAA", "\0BBBBBBBBBBBB", StringComparison.CurrentCultureIgnoreCase, false)]
// InvariantCulture
[InlineData("Hello", "Hello", StringComparison.InvariantCulture, true)]
[InlineData("Hello", "hello", StringComparison.InvariantCulture, false)]
@@ -1076,7 +1125,8 @@ namespace System.Tests
[InlineData("Hello", "", StringComparison.InvariantCulture, false)]
[InlineData("", "Hello", StringComparison.InvariantCulture, false)]
[InlineData("", "", StringComparison.InvariantCulture, true)]
- [InlineData("123", 123, StringComparison.InvariantCultureIgnoreCase, false)] // Not a string
+ [InlineData("123", 123, StringComparison.InvariantCulture, false)] // Not a string
+ [InlineData("\0AAAAAAAAA", "\0BBBBBBBBBBBB", StringComparison.InvariantCulture, false)]
// InvariantCultureIgnoreCase
[InlineData("Hello", "Hello", StringComparison.InvariantCultureIgnoreCase, true)]
[InlineData("Hello", "hello", StringComparison.InvariantCultureIgnoreCase, true)]
@@ -1089,6 +1139,7 @@ namespace System.Tests
[InlineData("", "Hello", StringComparison.InvariantCultureIgnoreCase, false)]
[InlineData("", "", StringComparison.InvariantCultureIgnoreCase, true)]
[InlineData("123", 123, StringComparison.InvariantCultureIgnoreCase, false)] // Not a string
+ [InlineData("\0AAAAAAAAA", "\0BBBBBBBBBBBB", StringComparison.InvariantCultureIgnoreCase, false)]
// Ordinal
[InlineData("Hello", "Hello", StringComparison.Ordinal, true)]
[InlineData("Hello", "hello", StringComparison.Ordinal, false)]
@@ -1118,6 +1169,7 @@ namespace System.Tests
[InlineData("", "Hello", StringComparison.OrdinalIgnoreCase, false)]
[InlineData("", "", StringComparison.OrdinalIgnoreCase, true)]
[InlineData("123", 123, StringComparison.OrdinalIgnoreCase, false)] // Not a string
+ [InlineData("\0AAAAAAAAA", "\0BBBBBBBBBBBB", StringComparison.OrdinalIgnoreCase, false)]
public static void Equals(string s1, object obj, StringComparison comparisonType, bool expected)
{
string s2 = obj as string;
@@ -1149,6 +1201,8 @@ namespace System.Tests
{
Assert.Equal(s1.GetHashCode(), s1.GetHashCode());
}
+
+ Assert.Equal(expected, s1.AsSpan().Equals(s2.AsSpan(), comparisonType));
}
public static IEnumerable<object[]> Equals_EncyclopaediaData()
@@ -1176,8 +1230,10 @@ namespace System.Tests
StringComparison comparisonType = (StringComparison)Enum.Parse(typeof(StringComparison), comparisonString);
Assert.Equal(bool.Parse(expectedString), string.Equals(source, target, comparisonType));
+ Assert.Equal(bool.Parse(expectedString), source.AsSpan().Equals(target.AsSpan(), comparisonType));
+
return SuccessExitCode;
- }, comparison.ToString(), expected.ToString());
+ }, comparison.ToString(), expected.ToString()).Dispose();
}
[Theory]
@@ -1305,6 +1361,13 @@ namespace System.Tests
IsSafeForCurrentCultureComparisons(s)
&& IsSafeForCurrentCultureComparisons(target.ToString());
+ ReadOnlySpan<char> span = s.AsSpan();
+ var charArray = new char[1];
+ charArray[0] = target;
+ ReadOnlySpan<char> targetSpan = charArray;
+
+ int expectedFromSpan = expected == -1 ? expected : expected - startIndex;
+
if (count + startIndex == s.Length)
{
if (startIndex == 0)
@@ -1313,32 +1376,47 @@ namespace System.Tests
Assert.Equal(expected, s.IndexOf(target.ToString(), StringComparison.Ordinal));
Assert.Equal(expected, s.IndexOf(target.ToString(), StringComparison.OrdinalIgnoreCase));
+ Assert.Equal(expectedFromSpan, span.IndexOf(targetSpan, StringComparison.Ordinal));
+ Assert.Equal(expectedFromSpan, span.IndexOf(targetSpan, StringComparison.OrdinalIgnoreCase));
+
// To be safe we only want to run CurrentCulture comparisons if
// we know the results will not vary depending on location
if (safeForCurrentCulture)
{
Assert.Equal(expected, s.IndexOf(target.ToString()));
Assert.Equal(expected, s.IndexOf(target.ToString(), StringComparison.CurrentCulture));
+
+ Assert.Equal(expectedFromSpan, span.IndexOf(targetSpan, StringComparison.CurrentCulture));
}
}
Assert.Equal(expected, s.IndexOf(target, startIndex));
Assert.Equal(expected, s.IndexOf(target.ToString(), startIndex, StringComparison.Ordinal));
Assert.Equal(expected, s.IndexOf(target.ToString(), startIndex, StringComparison.OrdinalIgnoreCase));
+ Assert.Equal(expectedFromSpan, span.Slice(startIndex).IndexOf(targetSpan, StringComparison.Ordinal));
+ Assert.Equal(expectedFromSpan, span.Slice(startIndex).IndexOf(targetSpan, StringComparison.OrdinalIgnoreCase));
+
if (safeForCurrentCulture)
{
Assert.Equal(expected, s.IndexOf(target.ToString(), startIndex));
Assert.Equal(expected, s.IndexOf(target.ToString(), startIndex, StringComparison.CurrentCulture));
+
+ Assert.Equal(expectedFromSpan, span.Slice(startIndex).IndexOf(targetSpan, StringComparison.CurrentCulture));
}
}
Assert.Equal(expected, s.IndexOf(target, startIndex, count));
Assert.Equal(expected, s.IndexOf(target.ToString(), startIndex, count, StringComparison.Ordinal));
Assert.Equal(expected, s.IndexOf(target.ToString(), startIndex, count, StringComparison.OrdinalIgnoreCase));
+ Assert.Equal(expectedFromSpan, span.Slice(startIndex, count).IndexOf(targetSpan, StringComparison.Ordinal));
+ Assert.Equal(expectedFromSpan, span.Slice(startIndex, count).IndexOf(targetSpan, StringComparison.OrdinalIgnoreCase));
+
if (safeForCurrentCulture)
{
Assert.Equal(expected, s.IndexOf(target.ToString(), startIndex, count));
Assert.Equal(expected, s.IndexOf(target.ToString(), startIndex, count, StringComparison.CurrentCulture));
+
+ Assert.Equal(expectedFromSpan, span.Slice(startIndex, count).IndexOf(targetSpan, StringComparison.CurrentCulture));
}
}
@@ -1370,6 +1448,7 @@ namespace System.Tests
public static void IndexOf_NullInStrings(string s, string value, int expected)
{
Assert.Equal(expected, s.IndexOf(value));
+ Assert.Equal(expected, s.AsSpan().IndexOf(value.AsSpan(), StringComparison.Ordinal));
}
[Theory]
@@ -1381,23 +1460,31 @@ namespace System.Tests
// First find the substring. We should be able to with all comparison types.
Assert.Equal(startIndex, s.IndexOf(value, comparison)); // in the whole string
Assert.Equal(startIndex, s.IndexOf(value, startIndex, comparison)); // starting at substring
+ Assert.Equal(startIndex, s.AsSpan().IndexOf(value.AsSpan(), comparison)); // in the whole string
+ Assert.Equal(0, s.AsSpan(startIndex).IndexOf(value.AsSpan(), comparison)); // starting at substring
+
if (startIndex > 0)
{
Assert.Equal(startIndex, s.IndexOf(value, startIndex - 1, comparison)); // starting just before substring
+ Assert.Equal(1, s.AsSpan(startIndex - 1).IndexOf(value.AsSpan(), comparison)); // starting just before substring
}
+ Assert.Equal(-1, s.AsSpan(startIndex + 1).IndexOf(value.AsSpan(), comparison)); // starting just after start of substring
Assert.Equal(-1, s.IndexOf(value, startIndex + 1, comparison)); // starting just after start of substring
// Shouldn't be able to find the substring if the count is less than substring's length
Assert.Equal(-1, s.IndexOf(value, 0, value.Length - 1, comparison));
+ Assert.Equal(-1, s.AsSpan(0, value.Length - 1).IndexOf(value.AsSpan(), comparison));
// Now double the source. Make sure we find the first copy of the substring.
int halfLen = s.Length;
s += s;
Assert.Equal(startIndex, s.IndexOf(value, comparison));
+ Assert.Equal(startIndex, s.AsSpan().IndexOf(value.AsSpan(), comparison));
// Now change the case of a letter.
s = s.ToUpperInvariant();
Assert.Equal(ignoringCase ? startIndex : -1, s.IndexOf(value, comparison));
+ Assert.Equal(ignoringCase ? startIndex : -1, s.AsSpan().IndexOf(value.AsSpan(), comparison));
}
[Fact]
@@ -1415,12 +1502,23 @@ namespace System.Tests
Assert.Equal(19, s.IndexOf(value, StringComparison.Ordinal));
Assert.Equal(19, s.IndexOf(value, StringComparison.OrdinalIgnoreCase));
+ ReadOnlySpan<char> span = s.AsSpan();
+ Assert.Equal(19, span.IndexOf(value.AsSpan(), StringComparison.CurrentCulture));
+ Assert.Equal(4, span.IndexOf(value.AsSpan(), StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(19, span.IndexOf(value.AsSpan(), StringComparison.Ordinal));
+ Assert.Equal(19, span.IndexOf(value.AsSpan(), StringComparison.OrdinalIgnoreCase));
+
value = "\u0131";
Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCulture));
Assert.Equal(8, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
Assert.Equal(10, s.IndexOf(value, StringComparison.Ordinal));
Assert.Equal(10, s.IndexOf(value, StringComparison.OrdinalIgnoreCase));
+ Assert.Equal(10, span.IndexOf(value.AsSpan(), StringComparison.CurrentCulture));
+ Assert.Equal(8, span.IndexOf(value.AsSpan(), StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(10, span.IndexOf(value.AsSpan(), StringComparison.Ordinal));
+ Assert.Equal(10, span.IndexOf(value.AsSpan(), StringComparison.OrdinalIgnoreCase));
+
return SuccessExitCode;
}).Dispose();
}
@@ -1439,10 +1537,17 @@ namespace System.Tests
Assert.Equal(19, s.IndexOf(value, StringComparison.CurrentCulture));
Assert.Equal(19, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+ ReadOnlySpan<char> span = s.AsSpan();
+ Assert.Equal(19, span.IndexOf(value.AsSpan(), StringComparison.CurrentCulture));
+ Assert.Equal(19, span.IndexOf(value.AsSpan(), StringComparison.CurrentCultureIgnoreCase));
+
value = "\u0131";
Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCulture));
Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(10, span.IndexOf(value.AsSpan(), StringComparison.CurrentCulture));
+ Assert.Equal(10, span.IndexOf(value.AsSpan(), StringComparison.CurrentCultureIgnoreCase));
+
return SuccessExitCode;
}).Dispose();
}
@@ -1462,10 +1567,17 @@ namespace System.Tests
Assert.Equal(19, s.IndexOf(value, StringComparison.CurrentCulture));
Assert.Equal(19, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+ ReadOnlySpan<char> span = s.AsSpan();
+ Assert.Equal(19, span.IndexOf(value.AsSpan(), StringComparison.CurrentCulture));
+ Assert.Equal(19, span.IndexOf(value.AsSpan(), StringComparison.CurrentCultureIgnoreCase));
+
value = "\u0131";
Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCulture));
Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(10, span.IndexOf(value.AsSpan(), StringComparison.CurrentCulture));
+ Assert.Equal(10, span.IndexOf(value.AsSpan(), StringComparison.CurrentCultureIgnoreCase));
+
return SuccessExitCode;
}).Dispose();
}
@@ -1493,6 +1605,14 @@ namespace System.Tests
Assert.Equal(-1, source.IndexOf(target, StringComparison.Ordinal));
Assert.Equal(-1, source.IndexOf(target, StringComparison.OrdinalIgnoreCase));
+ ReadOnlySpan<char> span = source.AsSpan();
+
+ Assert.Equal(PlatformDetection.IsWindows ? 0 : -1, span.IndexOf(target.AsSpan(), StringComparison.CurrentCulture));
+
+ Assert.Equal(0, span.IndexOf(target.AsSpan(), StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(-1, span.IndexOf(target.AsSpan(), StringComparison.Ordinal));
+ Assert.Equal(-1, span.IndexOf(target.AsSpan(), StringComparison.OrdinalIgnoreCase));
+
return SuccessExitCode;
}).Dispose();
}
@@ -1510,6 +1630,10 @@ namespace System.Tests
Assert.Equal(-1, source.IndexOf(target, StringComparison.CurrentCulture));
Assert.Equal(-1, source.IndexOf(target, StringComparison.CurrentCultureIgnoreCase));
+ ReadOnlySpan<char> span = source.AsSpan();
+ Assert.Equal(-1, span.IndexOf(target.AsSpan(), StringComparison.CurrentCulture));
+ Assert.Equal(-1, span.IndexOf(target.AsSpan(), StringComparison.CurrentCultureIgnoreCase));
+
return SuccessExitCode;
}).Dispose();
}
@@ -1529,6 +1653,12 @@ namespace System.Tests
Assert.Equal(10, s.IndexOf(value, StringComparison.Ordinal));
Assert.Equal(10, s.IndexOf(value, StringComparison.OrdinalIgnoreCase));
+ ReadOnlySpan<char> span = s.AsSpan();
+ Assert.Equal(10, span.IndexOf(value.AsSpan(), StringComparison.CurrentCulture));
+ Assert.Equal(8, span.IndexOf(value.AsSpan(), StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(10, span.IndexOf(value.AsSpan(), StringComparison.Ordinal));
+ Assert.Equal(10, span.IndexOf(value.AsSpan(), StringComparison.OrdinalIgnoreCase));
+
value = "a\u0300"; // this diacritic combines with preceding character
Assert.Equal(8, s.IndexOf(value));
Assert.Equal(8, s.IndexOf(value, StringComparison.CurrentCulture));
@@ -1536,6 +1666,11 @@ namespace System.Tests
Assert.Equal(8, s.IndexOf(value, StringComparison.Ordinal));
Assert.Equal(8, s.IndexOf(value, StringComparison.OrdinalIgnoreCase));
+ Assert.Equal(8, span.IndexOf(value.AsSpan(), StringComparison.CurrentCulture));
+ Assert.Equal(8, span.IndexOf(value.AsSpan(), StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(8, span.IndexOf(value.AsSpan(), StringComparison.Ordinal));
+ Assert.Equal(8, span.IndexOf(value.AsSpan(), StringComparison.OrdinalIgnoreCase));
+
return SuccessExitCode;
}).Dispose();
}
@@ -1553,11 +1688,18 @@ namespace System.Tests
Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCulture));
Assert.Equal(8, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+ ReadOnlySpan<char> span = s.AsSpan();
+ Assert.Equal(10, span.IndexOf(value.AsSpan(), StringComparison.CurrentCulture));
+ Assert.Equal(8, span.IndexOf(value.AsSpan(), StringComparison.CurrentCultureIgnoreCase));
+
value = "a\u0300"; // this diacritic combines with preceding character
Assert.Equal(8, s.IndexOf(value));
Assert.Equal(8, s.IndexOf(value, StringComparison.CurrentCulture));
Assert.Equal(8, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(8, span.IndexOf(value.AsSpan(), StringComparison.CurrentCulture));
+ Assert.Equal(8, span.IndexOf(value.AsSpan(), StringComparison.CurrentCultureIgnoreCase));
+
return SuccessExitCode;
}).Dispose();
}
@@ -1577,6 +1719,12 @@ namespace System.Tests
Assert.Equal(3, s.IndexOf(value, StringComparison.Ordinal));
Assert.Equal(3, s.IndexOf(value, StringComparison.OrdinalIgnoreCase));
+ ReadOnlySpan<char> span = s.AsSpan();
+ Assert.Equal(3, span.IndexOf(value.AsSpan(), StringComparison.CurrentCulture));
+ Assert.Equal(3, span.IndexOf(value.AsSpan(), StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(3, span.IndexOf(value.AsSpan(), StringComparison.Ordinal));
+ Assert.Equal(3, span.IndexOf(value.AsSpan(), StringComparison.OrdinalIgnoreCase));
+
value = "bar";
Assert.Equal(-1, s.IndexOf(value));
Assert.Equal(-1, s.IndexOf(value, StringComparison.CurrentCulture));
@@ -1584,6 +1732,11 @@ namespace System.Tests
Assert.Equal(-1, s.IndexOf(value, StringComparison.Ordinal));
Assert.Equal(4, s.IndexOf(value, StringComparison.OrdinalIgnoreCase));
+ Assert.Equal(-1, span.IndexOf(value.AsSpan(), StringComparison.CurrentCulture));
+ Assert.Equal(4, span.IndexOf(value.AsSpan(), StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(-1, span.IndexOf(value.AsSpan(), StringComparison.Ordinal));
+ Assert.Equal(4, span.IndexOf(value.AsSpan(), StringComparison.OrdinalIgnoreCase));
+
return SuccessExitCode;
}).Dispose();
}
@@ -1601,11 +1754,18 @@ namespace System.Tests
Assert.Equal(3, s.IndexOf(value, StringComparison.CurrentCulture));
Assert.Equal(3, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+ ReadOnlySpan<char> span = s.AsSpan();
+ Assert.Equal(3, span.IndexOf(value.AsSpan(), StringComparison.CurrentCulture));
+ Assert.Equal(3, span.IndexOf(value.AsSpan(), StringComparison.CurrentCultureIgnoreCase));
+
value = "bar";
Assert.Equal(-1, s.IndexOf(value));
Assert.Equal(-1, s.IndexOf(value, StringComparison.CurrentCulture));
Assert.Equal(4, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(-1, span.IndexOf(value.AsSpan(), StringComparison.CurrentCulture));
+ Assert.Equal(4, span.IndexOf(value.AsSpan(), StringComparison.CurrentCultureIgnoreCase));
+
return SuccessExitCode;
}).Dispose();
}
@@ -1743,6 +1903,8 @@ namespace System.Tests
public static void IsNullOrEmpty(string value, bool expected)
{
Assert.Equal(expected, string.IsNullOrEmpty(value));
+
+ Assert.Equal(expected, value.AsSpan().IsEmpty);
}
public static IEnumerable<object[]> IsNullOrWhitespace_TestData()
@@ -2335,6 +2497,8 @@ namespace System.Tests
Assert.Equal(expected, s.StartsWith(value));
}
Assert.Equal(expected, s.StartsWith(value, comparisonType));
+
+ Assert.Equal(expected, s.AsSpan().StartsWith(value.AsSpan(), comparisonType));
}
[Theory]
@@ -2350,6 +2514,12 @@ namespace System.Tests
Assert.True("te\0st".StartsWith("te\0s", comparison));
Assert.True("test\0".StartsWith("test", comparison));
Assert.False("test".StartsWith("te\0", comparison));
+
+ Assert.False("\0test".AsSpan().StartsWith("test".AsSpan(), comparison));
+ Assert.False("te\0st".AsSpan().StartsWith("test".AsSpan(), comparison));
+ Assert.True("te\0st".AsSpan().StartsWith("te\0s".AsSpan(), comparison));
+ Assert.True("test\0".AsSpan().StartsWith("test".AsSpan(), comparison));
+ Assert.False("test".AsSpan().StartsWith("te\0".AsSpan(), comparison));
}
[Fact]
@@ -2380,8 +2550,11 @@ namespace System.Tests
if (startIndex + length == s.Length)
{
Assert.Equal(expected, s.Substring(startIndex));
+ Assert.Equal(expected, s.AsSpan().Slice(startIndex).ToString());
}
Assert.Equal(expected, s.Substring(startIndex, length));
+
+ Assert.Equal(expected, s.AsSpan().Slice(startIndex, length).ToString());
}
[Fact]
@@ -2441,6 +2614,10 @@ namespace System.Tests
public static void ToLower(string s, string expected)
{
Assert.Equal(expected, s.ToLower());
+
+ Span<char> destination = new char[s.Length];
+ Assert.Equal(s.Length, s.AsSpan().ToLower(destination, CultureInfo.CurrentCulture));
+ Assert.Equal(expected, destination.ToString());
}
private static IEnumerable<object[]> ToLower_Culture_TestData()
@@ -2475,6 +2652,10 @@ namespace System.Tests
{
CultureInfo.CurrentCulture = culture;
Assert.True(actual.ToLower().Equals(expected, StringComparison.Ordinal));
+
+ Span<char> destination = new char[actual.Length];
+ Assert.Equal(actual.Length, actual.AsSpan().ToLower(destination, culture));
+ Assert.Equal(expected, destination.ToString());
}
[Theory]
@@ -2484,6 +2665,10 @@ namespace System.Tests
public static void ToLowerInvariant(string s, string expected)
{
Assert.Equal(expected, s.ToLowerInvariant());
+
+ Span<char> destination = new char[s.Length];
+ Assert.Equal(s.Length, s.AsSpan().ToLowerInvariant(destination));
+ Assert.Equal(expected, destination.ToString());
}
[Theory]
@@ -2492,6 +2677,8 @@ namespace System.Tests
public static void ToString(string s)
{
Assert.Same(s, s.ToString());
+
+ Assert.Equal(s, s.AsSpan().ToString());
}
[Theory]
@@ -2501,48 +2688,70 @@ namespace System.Tests
public static void ToUpper(string s, string expected)
{
Assert.Equal(expected, s.ToUpper());
+
+ Span<char> destination = new char[s.Length];
+ Assert.Equal(s.Length, s.AsSpan().ToUpper(destination, CultureInfo.CurrentCulture));
+ Assert.Equal(expected, destination.ToString());
}
- [Fact]
- public static void ToUpper_TurkishI_TurkishCulture()
+ [Theory]
+ [InlineData("H\u0069 World", "H\u0130 WORLD")]
+ [InlineData("H\u0130 World", "H\u0130 WORLD")]
+ [InlineData("H\u0131 World", "H\u0049 WORLD")]
+ public static void ToUpper_TurkishI_TurkishCulture(string s, string expected)
{
- RemoteInvoke(() =>
+ RemoteInvoke((str, expectedString) =>
{
CultureInfo.CurrentCulture = new CultureInfo("tr-TR");
- Assert.True("H\u0069 World".ToUpper().Equals("H\u0130 WORLD", StringComparison.Ordinal));
- Assert.True("H\u0130 World".ToUpper().Equals("H\u0130 WORLD", StringComparison.Ordinal));
- Assert.True("H\u0131 World".ToUpper().Equals("H\u0049 WORLD", StringComparison.Ordinal));
+
+ Assert.True(str.ToUpper().Equals(expectedString, StringComparison.Ordinal));
+
+ Span<char> destination = new char[str.Length];
+ Assert.Equal(str.Length, str.AsSpan().ToUpper(destination, CultureInfo.CurrentCulture));
+ Assert.Equal(expectedString, destination.ToString());
return SuccessExitCode;
- }).Dispose();
+ }, s.ToString(), expected.ToString()).Dispose();
}
- [Fact]
- public static void ToUpper_TurkishI_EnglishUSCulture()
+ [Theory]
+ [InlineData("H\u0069 World", "H\u0049 WORLD")]
+ [InlineData("H\u0130 World", "H\u0130 WORLD")]
+ [InlineData("H\u0131 World", "H\u0049 WORLD")]
+ public static void ToUpper_TurkishI_EnglishUSCulture(string s, string expected)
{
- RemoteInvoke(() =>
+ RemoteInvoke((str, expectedString) =>
{
CultureInfo.CurrentCulture = new CultureInfo("en-US");
- Assert.True("H\u0069 World".ToUpper().Equals("H\u0049 WORLD", StringComparison.Ordinal));
- Assert.True("H\u0130 World".ToUpper().Equals("H\u0130 WORLD", StringComparison.Ordinal));
- Assert.True("H\u0131 World".ToUpper().Equals("H\u0049 WORLD", StringComparison.Ordinal));
+
+ Assert.True(str.ToUpper().Equals(expectedString, StringComparison.Ordinal));
+
+ Span<char> destination = new char[str.Length];
+ Assert.Equal(str.Length, str.AsSpan().ToUpper(destination, CultureInfo.CurrentCulture));
+ Assert.Equal(expectedString, destination.ToString());
return SuccessExitCode;
- }).Dispose();
+ }, s.ToString(), expected.ToString()).Dispose();
}
- [Fact]
- public static void ToUpper_TurkishI_InvariantCulture()
+ [Theory]
+ [InlineData("H\u0069 World", "H\u0049 WORLD")]
+ [InlineData("H\u0130 World", "H\u0130 WORLD")]
+ [InlineData("H\u0131 World", "H\u0131 WORLD")]
+ public static void ToUpper_TurkishI_InvariantCulture(string s, string expected)
{
- RemoteInvoke(() =>
+ RemoteInvoke((str, expectedString) =>
{
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
- Assert.True("H\u0069 World".ToUpper().Equals("H\u0049 WORLD", StringComparison.Ordinal));
- Assert.True("H\u0130 World".ToUpper().Equals("H\u0130 WORLD", StringComparison.Ordinal));
- Assert.True("H\u0131 World".ToUpper().Equals("H\u0131 WORLD", StringComparison.Ordinal));
+
+ Assert.True(str.ToUpper().Equals(expectedString, StringComparison.Ordinal));
+
+ Span<char> destination = new char[str.Length];
+ Assert.Equal(str.Length, str.AsSpan().ToUpper(destination, CultureInfo.CurrentCulture));
+ Assert.Equal(expectedString, destination.ToString());
return SuccessExitCode;
- }).Dispose();
+ }, s.ToString(), expected.ToString()).Dispose();
}
[Theory]
@@ -2552,6 +2761,10 @@ namespace System.Tests
public static void ToUpperInvariant(string s, string expected)
{
Assert.Equal(expected, s.ToUpperInvariant());
+
+ Span<char> destination = new char[s.Length];
+ Assert.Equal(s.Length, s.AsSpan().ToUpperInvariant(destination));
+ Assert.Equal(expected, destination.ToString());
}
[Fact]
@@ -2577,6 +2790,17 @@ namespace System.Tests
Assert.Equal(asciiLower, ascii.ToLowerInvariant());
Assert.Equal(asciiUpper, ascii.ToUpperInvariant());
+
+ Span<char> destinationLower = new char[ascii.Length];
+ Span<char> destinationUpper = new char[ascii.Length];
+
+ Assert.Equal(ascii.Length, ascii.AsSpan().ToLowerInvariant(destinationLower));
+ Assert.Equal(ascii.Length, ascii.AsSpan().ToUpperInvariant(destinationUpper));
+
+ Assert.Equal(ascii.ToLowerInvariant(), destinationLower.ToString());
+ Assert.Equal(ascii.ToUpperInvariant(), destinationUpper.ToString());
+
+ Assert.Equal(ascii, ascii.AsSpan().ToString());
}
[Theory]
@@ -2593,14 +2817,17 @@ namespace System.Tests
if (trimChars == null || trimChars.Length == 0 || (trimChars.Length == 1 && trimChars[0] == ' '))
{
Assert.Equal(expected, s.Trim());
+ Assert.Equal(expected, s.AsSpan().Trim().ToString());
}
if (trimChars?.Length == 1)
{
Assert.Equal(expected, s.Trim(trimChars[0]));
+ Assert.Equal(expected, s.AsSpan().Trim(trimChars[0]).ToString());
}
Assert.Equal(expected, s.Trim(trimChars));
+ Assert.Equal(expected, s.AsSpan().Trim(trimChars).ToString());
}
[Theory]
@@ -2617,14 +2844,17 @@ namespace System.Tests
if (trimChars == null || trimChars.Length == 0 || (trimChars.Length == 1 && trimChars[0] == ' '))
{
Assert.Equal(expected, s.TrimEnd());
+ Assert.Equal(expected, s.AsSpan().TrimEnd().ToString());
}
if (trimChars?.Length == 1)
{
Assert.Equal(expected, s.TrimEnd(trimChars[0]));
+ Assert.Equal(expected, s.AsSpan().TrimEnd(trimChars[0]).ToString());
}
Assert.Equal(expected, s.TrimEnd(trimChars));
+ Assert.Equal(expected, s.AsSpan().TrimEnd(trimChars).ToString());
}
[Theory]
@@ -2641,14 +2871,17 @@ namespace System.Tests
if (trimChars == null || trimChars.Length == 0 || (trimChars.Length == 1 && trimChars[0] == ' '))
{
Assert.Equal(expected, s.TrimStart());
+ Assert.Equal(expected, s.AsSpan().TrimStart().ToString());
}
if (trimChars?.Length == 1)
{
Assert.Equal(expected, s.TrimStart(trimChars[0]));
+ Assert.Equal(expected, s.AsSpan().TrimStart(trimChars[0]).ToString());
}
Assert.Equal(expected, s.TrimStart(trimChars));
+ Assert.Equal(expected, s.AsSpan().TrimStart(trimChars).ToString());
}
[Fact]
@@ -2797,6 +3030,18 @@ namespace System.Tests
CultureInfo ci = CultureInfo.GetCultureInfo(cultureName);
Assert.Equal(lowerForm, upperForm.ToLower(ci));
Assert.Equal(upperForm, lowerForm.ToUpper(ci));
+
+ Span<char> destinationLower = new char[upperForm.Length];
+ Span<char> destinationUpper = new char[lowerForm.Length];
+
+ Assert.Equal(upperForm.Length, upperForm.AsSpan().ToLower(destinationLower, ci));
+ Assert.Equal(lowerForm.Length, lowerForm.AsSpan().ToUpper(destinationUpper, ci));
+
+ Assert.Equal(upperForm.ToLower(ci), destinationLower.ToString());
+ Assert.Equal(lowerForm.ToUpper(ci), destinationUpper.ToString());
+
+ Assert.Equal(lowerForm, lowerForm.AsSpan().ToString());
+ Assert.Equal(upperForm, upperForm.AsSpan().ToString());
}
[Fact]
@@ -2845,6 +3090,47 @@ namespace System.Tests
}
[Fact]
+ [PlatformSpecific(TestPlatforms.AnyUnix)] // These tests assume that UTF8 is the default encoding
+ public static unsafe void ConstructorsTest_InvalidUTF8()
+ {
+ byte[] invalidUTF8Bytes = new byte[] { (byte)'A', (byte)'B', 0xEE, (byte)'C', (byte)'D', 0 };
+
+ fixed (byte* pBytes = invalidUTF8Bytes)
+ {
+ Assert.Equal("AB\ufffdCD", new String((sbyte*)pBytes));
+ Assert.Equal("B\ufffdC", new String((sbyte*)pBytes, 1, 3));
+ }
+ }
+
+ [Fact]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public static unsafe void ConstructorsTest_InvalidArguments ()
+ {
+ AssertExtensions.Throws<ArgumentNullException>("value", () => new String ((sbyte*) null, 0, 1, Encoding.Default));
+ AssertExtensions.Throws<ArgumentNullException>("value", () => new String ((sbyte*) null, 1, 1, Encoding.Default));
+
+ AssertExtensions.Throws<ArgumentNullException>("value", () => new String ((sbyte*) null, 0, 1, null));
+ AssertExtensions.Throws<ArgumentNullException>("value", () => new String ((sbyte*) null, 1, 1, null));
+ }
+
+ [Fact]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public static unsafe void ConstructorsTest_Empty ()
+ {
+ Assert.Equal(string.Empty, new String((sbyte*) null));
+
+ Assert.Equal(string.Empty, new String((char*) null, 0, 0));
+
+ Assert.Equal(string.Empty, new String((sbyte*) null, 0, 0));
+
+ Assert.Equal(string.Empty, new String((sbyte*) null, 0, 0, Encoding.Default));
+ Assert.Equal(string.Empty, new String((sbyte*) null, 1, 0, Encoding.Default));
+
+ Assert.Equal(string.Empty, new String((sbyte*) null, 0, 0, null));
+ Assert.Equal(string.Empty, new String((sbyte*) null, 1, 0, null));
+ }
+
+ [Fact]
public static unsafe void CloneTest()
{
string s = "some string to clone";
diff --git a/src/System.Runtime/tests/System/StringTests.netcoreapp.cs b/src/System.Runtime/tests/System/StringTests.netcoreapp.cs
index 8f14fe13e6..52f088e546 100644
--- a/src/System.Runtime/tests/System/StringTests.netcoreapp.cs
+++ b/src/System.Runtime/tests/System/StringTests.netcoreapp.cs
@@ -20,6 +20,13 @@ namespace System.Tests
Assert.Same(string.Empty, new string(new ReadOnlySpan<char>(new char[length], offset, 0)));
}
+ [Fact]
+ public static unsafe void Ctor_CharSpan_Empty()
+ {
+ Assert.Same(string.Empty, new string((ReadOnlySpan<char>)null));
+ Assert.Same(string.Empty, new string(ReadOnlySpan<char>.Empty));
+ }
+
[Theory]
[InlineData(new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', '\0' }, 0, 8, "abcdefgh")]
[InlineData(new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', '\0', 'i', 'j', 'k' }, 0, 12, "abcdefgh\0ijk")]
@@ -214,6 +221,7 @@ namespace System.Tests
public static void Contains(string s, string value, StringComparison comparisonType, bool expected)
{
Assert.Equal(expected, s.Contains(value, comparisonType));
+ Assert.Equal(expected, s.AsSpan().Contains(value, comparisonType));
}
[Fact]
@@ -225,6 +233,7 @@ namespace System.Tests
CultureInfo.CurrentCulture = new CultureInfo("tr-TR");
Assert.True(source.Contains("\u0069\u0069", StringComparison.CurrentCultureIgnoreCase));
+ Assert.True(source.AsSpan().Contains("\u0069\u0069", StringComparison.CurrentCultureIgnoreCase));
return SuccessExitCode;
}, str).Dispose();
@@ -234,6 +243,7 @@ namespace System.Tests
CultureInfo.CurrentCulture = new CultureInfo("en-US");
Assert.False(source.Contains("\u0069\u0069", StringComparison.CurrentCultureIgnoreCase));
+ Assert.False(source.AsSpan().Contains("\u0069\u0069", StringComparison.CurrentCultureIgnoreCase));
return SuccessExitCode;
}, str).Dispose();
@@ -607,6 +617,9 @@ namespace System.Tests
public static void IndexOf_SingleLetter(string s, char target, StringComparison stringComparison, int expected)
{
Assert.Equal(expected, s.IndexOf(target, stringComparison));
+ var charArray = new char[1];
+ charArray[0] = target;
+ Assert.Equal(expected, s.AsSpan().IndexOf(charArray, stringComparison));
}
[Fact]
@@ -624,12 +637,23 @@ namespace System.Tests
Assert.Equal(19, s.IndexOf(value, StringComparison.Ordinal));
Assert.Equal(19, s.IndexOf(value, StringComparison.OrdinalIgnoreCase));
+ ReadOnlySpan<char> span = s.AsSpan();
+ Assert.Equal(19, span.IndexOf(new char[] { value }, StringComparison.CurrentCulture));
+ Assert.Equal(4, span.IndexOf(new char[] { value }, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(19, span.IndexOf(new char[] { value }, StringComparison.Ordinal));
+ Assert.Equal(19, span.IndexOf(new char[] { value }, StringComparison.OrdinalIgnoreCase));
+
value = '\u0131';
Assert.Equal(10, s.IndexOf(value, StringComparison.CurrentCulture));
Assert.Equal(8, s.IndexOf(value, StringComparison.CurrentCultureIgnoreCase));
Assert.Equal(10, s.IndexOf(value, StringComparison.Ordinal));
Assert.Equal(10, s.IndexOf(value, StringComparison.OrdinalIgnoreCase));
+ Assert.Equal(10, span.IndexOf(new char[] { value }, StringComparison.CurrentCulture));
+ Assert.Equal(8, span.IndexOf(new char[] { value }, StringComparison.CurrentCultureIgnoreCase));
+ Assert.Equal(10, span.IndexOf(new char[] { value }, StringComparison.Ordinal));
+ Assert.Equal(10, span.IndexOf(new char[] { value }, StringComparison.OrdinalIgnoreCase));
+
return SuccessExitCode;
}).Dispose();
}
diff --git a/src/System.Runtime/tests/System/Text/StringBuilderTests.cs b/src/System.Runtime/tests/System/Text/StringBuilderTests.cs
index e68d4046c2..d5e57a118e 100644
--- a/src/System.Runtime/tests/System/Text/StringBuilderTests.cs
+++ b/src/System.Runtime/tests/System/Text/StringBuilderTests.cs
@@ -979,6 +979,40 @@ namespace System.Text.Tests
Assert.Same(string.Empty, builder.ToString());
}
+ [Fact]
+ public static void Clear_Empty_CapacityNotZero()
+ {
+ var builder = new StringBuilder();
+ builder.Clear();
+ Assert.NotEqual(0, builder.Capacity);
+ }
+
+ [Fact]
+ public static void Clear_Empty_CapacityStaysUnchanged()
+ {
+ var sb = new StringBuilder(14);
+ sb.Clear();
+ Assert.Equal(14, sb.Capacity);
+ }
+
+ [Fact]
+ public static void Clear_Full_CapacityStaysUnchanged()
+ {
+ var sb = new StringBuilder(14);
+ sb.Append("Hello World!!!");
+ sb.Clear();
+ Assert.Equal(14, sb.Capacity);
+ }
+
+ [Fact]
+ public static void Clear_AtMaxCapacity_CapacityStaysUnchanged()
+ {
+ var builder = new StringBuilder(14, 14);
+ builder.Append("Hello World!!!");
+ builder.Clear();
+ Assert.Equal(14, builder.Capacity);
+ }
+
[Theory]
[InlineData("Hello", 0, new char[] { '\0', '\0', '\0', '\0', '\0' }, 0, 5, new char[] { 'H', 'e', 'l', 'l', 'o' })]
[InlineData("Hello", 0, new char[] { '\0', '\0', '\0', '\0', '\0', '\0' }, 1, 5, new char[] { '\0', 'H', 'e', 'l', 'l', 'o' })]
diff --git a/src/System.Runtime/tests/System/Text/StringBuilderTests.netcoreapp.cs b/src/System.Runtime/tests/System/Text/StringBuilderTests.netcoreapp.cs
index acc91e312c..848cd2888b 100644
--- a/src/System.Runtime/tests/System/Text/StringBuilderTests.netcoreapp.cs
+++ b/src/System.Runtime/tests/System/Text/StringBuilderTests.netcoreapp.cs
@@ -142,6 +142,67 @@ namespace System.Text.Tests
}
[Theory]
+ [InlineData(1)]
+ [InlineData(10000)]
+ public static void Clear_AppendAndInsertBeforeClearManyTimes_CapacityStaysWithinRange(int times)
+ {
+ var builder = new StringBuilder();
+ var originalCapacity = builder.Capacity;
+ var s = new string(' ', 10);
+ int oldLength = 0;
+ for (int i = 0; i < times; i++)
+ {
+ builder.Append(s);
+ builder.Append(s);
+ builder.Append(s);
+ builder.Insert(0, s);
+ builder.Insert(0, s);
+ oldLength = builder.Length;
+
+ builder.Clear();
+ }
+ Assert.InRange(builder.Capacity, 1, oldLength * 1.2);
+ }
+
+ [Fact]
+ public static void Clear_InitialCapacityMuchLargerThanLength_CapacityReducedToInitialCapacity()
+ {
+ var builder = new StringBuilder(100);
+ var initialCapacity = builder.Capacity;
+ builder.Append(new string('a', 40));
+ builder.Insert(0, new string('a', 10));
+ builder.Insert(0, new string('a', 10));
+ builder.Insert(0, new string('a', 10));
+ var oldCapacity = builder.Capacity;
+ var oldLength = builder.Length;
+ builder.Clear();
+ Assert.NotEqual(oldCapacity, builder.Capacity);
+ Assert.Equal(initialCapacity, builder.Capacity);
+ Assert.NotInRange(builder.Capacity, 1, oldLength * 1.2);
+ Assert.InRange(builder.Capacity, 1, Math.Max(initialCapacity, oldLength * 1.2));
+ }
+
+ [Fact]
+ public static void Clear_StringBuilderHasTwoChunks_OneChunkIsEmpty_ClearReducesCapacity()
+ {
+ var sb = new StringBuilder(string.Empty);
+ int initialCapacity = sb.Capacity;
+ for (int i = 0; i < initialCapacity; i++)
+ {
+ sb.Append('a');
+ }
+ sb.Insert(0, 'a');
+ while (sb.Length > 1)
+ {
+ sb.Remove(1, 1);
+ }
+ int oldCapacity = sb.Capacity;
+ sb.Clear();
+ Assert.Equal(oldCapacity - 1, sb.Capacity);
+ Assert.Equal(initialCapacity, sb.Capacity);
+ }
+
+ [Theory]
[InlineData("Hello", 0, new char[] { '\0', '\0', '\0', '\0', '\0' }, 5, new char[] { 'H', 'e', 'l', 'l', 'o' })]
[InlineData("Hello", 0, new char[] { '\0', '\0', '\0', '\0' }, 4, new char[] { 'H', 'e', 'l', 'l' })]
[InlineData("Hello", 1, new char[] { '\0', '\0', '\0', '\0', '\0' }, 4, new char[] { 'e', 'l', 'l', 'o', '\0' })]
@@ -325,7 +386,7 @@ namespace System.Text.Tests
[MemberData(nameof(Equals_String_TestData))]
public static void Equals(StringBuilder sb1, string value, bool expected)
{
- Assert.Equal(expected, sb1.Equals(value.AsReadOnlySpan()));
+ Assert.Equal(expected, sb1.Equals(value.AsSpan()));
}
}
}
diff --git a/src/System.Runtime/tests/System/Threading/WaitHandleTests.cs b/src/System.Runtime/tests/System/Threading/WaitHandleTests.cs
index 983011c9dd..d0947181ca 100644
--- a/src/System.Runtime/tests/System/Threading/WaitHandleTests.cs
+++ b/src/System.Runtime/tests/System/Threading/WaitHandleTests.cs
@@ -251,7 +251,6 @@ namespace System.Threading.Tests
[Theory]
[MemberData(nameof(SignalAndWait_MemberData))]
- [PlatformSpecific(TestPlatforms.Windows)] // other platforms don't support SignalAndWait
private static void SignalAndWait(
WaitHandle toSignal,
AutoResetEvent toWaitOn,
@@ -296,7 +295,6 @@ namespace System.Threading.Tests
}
[Fact]
- [PlatformSpecific(TestPlatforms.Windows)] // other platforms don't support SignalAndWait
public static void SignalAndWait_InvalidArgs()
{
var toSignal = new ManualResetEvent(false);
@@ -321,17 +319,6 @@ namespace System.Threading.Tests
}
[Fact]
- [PlatformSpecific(TestPlatforms.AnyUnix)] // Unix doesn't support SignalAndWait
- public static void SignalAndWait_PlatformNotSupported()
- {
- var toSignal = new ManualResetEvent(false);
- var toWaitOn = new ManualResetEvent(true);
- Assert.Throws<PlatformNotSupportedException>(() => WaitHandle.SignalAndWait(toSignal, toWaitOn));
- Assert.Throws<PlatformNotSupportedException>(() => WaitHandle.SignalAndWait(toSignal, toWaitOn, 0, false));
- Assert.Throws<PlatformNotSupportedException>(() => WaitHandle.SignalAndWait(toSignal, toWaitOn, TimeSpan.Zero, false));
- }
-
- [Fact]
public static void Close()
{
var wh = new ManualResetEvent(false);
diff --git a/src/System.Runtime/tests/System/TimeSpanTests.netcoreapp.cs b/src/System.Runtime/tests/System/TimeSpanTests.netcoreapp.cs
index c7b5a82eaa..18a46a8752 100644
--- a/src/System.Runtime/tests/System/TimeSpanTests.netcoreapp.cs
+++ b/src/System.Runtime/tests/System/TimeSpanTests.netcoreapp.cs
@@ -115,7 +115,7 @@ namespace System.Tests
[MemberData(nameof(Parse_Valid_TestData))]
public static void Parse_Span(string inputString, IFormatProvider provider, TimeSpan expected)
{
- ReadOnlySpan<char> input = inputString.AsReadOnlySpan();
+ ReadOnlySpan<char> input = inputString.AsSpan();
TimeSpan result;
Assert.Equal(expected, TimeSpan.Parse(input, provider));
@@ -125,7 +125,7 @@ namespace System.Tests
// Also negate
if (!char.IsWhiteSpace(input[0]))
{
- input = ("-" + inputString).AsReadOnlySpan();
+ input = ("-" + inputString).AsSpan();
expected = -expected;
Assert.Equal(expected, TimeSpan.Parse(input, provider));
@@ -140,8 +140,8 @@ namespace System.Tests
{
if (inputString != null)
{
- Assert.Throws(exceptionType, () => TimeSpan.Parse(inputString.AsReadOnlySpan(), provider));
- Assert.False(TimeSpan.TryParse(inputString.AsReadOnlySpan(), provider, out TimeSpan result));
+ Assert.Throws(exceptionType, () => TimeSpan.Parse(inputString.AsSpan(), provider));
+ Assert.False(TimeSpan.TryParse(inputString.AsSpan(), provider, out TimeSpan result));
Assert.Equal(TimeSpan.Zero, result);
}
}
@@ -152,7 +152,7 @@ namespace System.Tests
[MemberData(nameof(ParseExact_Valid_TestData))]
public static void ParseExact_Span_Valid(string inputString, string format, TimeSpan expected)
{
- ReadOnlySpan<char> input = inputString.AsReadOnlySpan();
+ ReadOnlySpan<char> input = inputString.AsSpan();
TimeSpan result;
Assert.Equal(expected, TimeSpan.ParseExact(input, format, new CultureInfo("en-US")));
@@ -188,13 +188,13 @@ namespace System.Tests
{
if (inputString != null && format != null)
{
- Assert.Throws(exceptionType, () => TimeSpan.ParseExact(inputString.AsReadOnlySpan(), format, new CultureInfo("en-US")));
+ Assert.Throws(exceptionType, () => TimeSpan.ParseExact(inputString.AsSpan(), format, new CultureInfo("en-US")));
TimeSpan result;
- Assert.False(TimeSpan.TryParseExact(inputString.AsReadOnlySpan(), format, new CultureInfo("en-US"), out result));
+ Assert.False(TimeSpan.TryParseExact(inputString.AsSpan(), format, new CultureInfo("en-US"), out result));
Assert.Equal(TimeSpan.Zero, result);
- Assert.False(TimeSpan.TryParseExact(inputString.AsReadOnlySpan(), new[] { format }, new CultureInfo("en-US"), out result));
+ Assert.False(TimeSpan.TryParseExact(inputString.AsSpan(), new[] { format }, new CultureInfo("en-US"), out result));
Assert.Equal(TimeSpan.Zero, result);
}
}
@@ -204,11 +204,11 @@ namespace System.Tests
{
TimeSpan result;
- AssertExtensions.Throws<ArgumentNullException>("formats", () => TimeSpan.ParseExact("12:34:56".AsReadOnlySpan(), (string[])null, null));
- Assert.False(TimeSpan.TryParseExact("12:34:56".AsReadOnlySpan(), (string[])null, null, out result));
+ AssertExtensions.Throws<ArgumentNullException>("formats", () => TimeSpan.ParseExact("12:34:56".AsSpan(), (string[])null, null));
+ Assert.False(TimeSpan.TryParseExact("12:34:56".AsSpan(), (string[])null, null, out result));
- Assert.Throws<FormatException>(() => TimeSpan.ParseExact("12:34:56".AsReadOnlySpan(), new string[0], null));
- Assert.False(TimeSpan.TryParseExact("12:34:56".AsReadOnlySpan(), new string[0], null, out result));
+ Assert.Throws<FormatException>(() => TimeSpan.ParseExact("12:34:56".AsSpan(), new string[0], null));
+ Assert.False(TimeSpan.TryParseExact("12:34:56".AsSpan(), new string[0], null, out result));
}
[Theory]
diff --git a/src/System.Runtime/tests/System/TimeZoneInfoTests.cs b/src/System.Runtime/tests/System/TimeZoneInfoTests.cs
index 0ff4adc60c..d535ff3765 100644
--- a/src/System.Runtime/tests/System/TimeZoneInfoTests.cs
+++ b/src/System.Runtime/tests/System/TimeZoneInfoTests.cs
@@ -133,6 +133,23 @@ namespace System.Tests
}
[Fact]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "The full .NET Framework has a bug. See https://github.com/dotnet/corefx/issues/26479")]
+ public static void CaseInsensiveLookup()
+ {
+ Assert.Equal(TimeZoneInfo.FindSystemTimeZoneById(s_strBrasilia), TimeZoneInfo.FindSystemTimeZoneById(s_strBrasilia.ToLowerInvariant()));
+ Assert.Equal(TimeZoneInfo.FindSystemTimeZoneById(s_strJohannesburg), TimeZoneInfo.FindSystemTimeZoneById(s_strJohannesburg.ToUpperInvariant()));
+
+ // Populate internal cache with all timezones. The implementation takes different path for lookup by id
+ // when all timezones are populated.
+ TimeZoneInfo.GetSystemTimeZones();
+
+ // The timezones used for the tests after GetSystemTimeZones calls have to be different from the ones used before GetSystemTimeZones to
+ // exercise the rare path.
+ Assert.Equal(TimeZoneInfo.FindSystemTimeZoneById(s_strSydney), TimeZoneInfo.FindSystemTimeZoneById(s_strSydney.ToLowerInvariant()));
+ Assert.Equal(TimeZoneInfo.FindSystemTimeZoneById(s_strPerth), TimeZoneInfo.FindSystemTimeZoneById(s_strPerth.ToUpperInvariant()));
+ }
+
+ [Fact]
public static void ConvertTime_DateTimeOffset_Invalid()
{
DateTimeOffset time1 = new DateTimeOffset(2006, 5, 12, 0, 0, 0, TimeSpan.Zero);
diff --git a/src/System.Runtime/tests/System/TypeTests.cs b/src/System.Runtime/tests/System/TypeTests.cs
index 34aced8b59..6c052d9ea6 100644
--- a/src/System.Runtime/tests/System/TypeTests.cs
+++ b/src/System.Runtime/tests/System/TypeTests.cs
@@ -402,5 +402,88 @@ namespace System.Tests
Assert.True(!typeof(TypeTestsExtended).IsContextful);
Assert.True(!typeof(ContextBoundClass).IsContextful);
}
+
+#region GetInterfaceMap tests
+ public static IEnumerable<object[]> GetInterfaceMap_TestData()
+ {
+ yield return new object[]
+ {
+ typeof(ISimpleInterface),
+ typeof(SimpleType),
+ new Tuple<MethodInfo, MethodInfo>[]
+ {
+ new Tuple<MethodInfo, MethodInfo>(typeof(ISimpleInterface).GetMethod("Method"), typeof(SimpleType).GetMethod("Method")),
+ new Tuple<MethodInfo, MethodInfo>(typeof(ISimpleInterface).GetMethod("GenericMethod"), typeof(SimpleType).GetMethod("GenericMethod"))
+ }
+ };
+ yield return new object[]
+ {
+ typeof(IGenericInterface<object>),
+ typeof(DerivedType),
+ new Tuple<MethodInfo, MethodInfo>[]
+ {
+ new Tuple<MethodInfo, MethodInfo>(typeof(IGenericInterface<object>).GetMethod("Method"), typeof(DerivedType).GetMethod("Method", new Type[] { typeof(object) })),
+ }
+ };
+ yield return new object[]
+ {
+ typeof(IGenericInterface<string>),
+ typeof(DerivedType),
+ new Tuple<MethodInfo, MethodInfo>[]
+ {
+ new Tuple<MethodInfo, MethodInfo>(typeof(IGenericInterface<string>).GetMethod("Method"), typeof(DerivedType).GetMethod("Method", new Type[] { typeof(string) })),
+ }
+ };
+ }
+
+ [Theory]
+ [MemberData(nameof(GetInterfaceMap_TestData))]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot, "Type.GetInterfaceMap() is not supported on UapAot")]
+ public static void GetInterfaceMap(Type interfaceType, Type classType, Tuple<MethodInfo, MethodInfo>[] expectedMap)
+ {
+ InterfaceMapping actualMapping = classType.GetInterfaceMap(interfaceType);
+
+ Assert.Equal(interfaceType, actualMapping.InterfaceType);
+ Assert.Equal(classType, actualMapping.TargetType);
+
+ Assert.Equal(expectedMap.Length, actualMapping.InterfaceMethods.Length);
+ Assert.Equal(expectedMap.Length, actualMapping.TargetMethods.Length);
+
+ for (int i = 0; i < expectedMap.Length; i++)
+ {
+ Assert.Contains(expectedMap[i].Item1, actualMapping.InterfaceMethods);
+
+ int index = Array.IndexOf(actualMapping.InterfaceMethods, expectedMap[i].Item1);
+ Assert.Equal(expectedMap[i].Item2, actualMapping.TargetMethods[index]);
+ }
+ }
+
+ interface ISimpleInterface
+ {
+ void Method();
+ void GenericMethod<T>();
+ }
+
+ class SimpleType : ISimpleInterface
+ {
+ public void Method() { }
+ public void GenericMethod<T>() { }
+ }
+
+ interface IGenericInterface<T>
+ {
+ void Method(T arg);
+ }
+
+ class GenericBaseType<T> : IGenericInterface<T>
+ {
+ public void Method(T arg) { }
+ }
+
+ class DerivedType : GenericBaseType<object>, IGenericInterface<string>
+ {
+ public void Method(string arg) { }
+ }
+#endregion
}
}
diff --git a/src/System.Runtime/tests/System/TypedReferenceTests.cs b/src/System.Runtime/tests/System/TypedReferenceTests.cs
index 6f44d35967..aba8ccfc59 100644
--- a/src/System.Runtime/tests/System/TypedReferenceTests.cs
+++ b/src/System.Runtime/tests/System/TypedReferenceTests.cs
@@ -1,3 +1,6 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
+
//
// TypedReferenceTest.cs
//
diff --git a/src/System.Runtime/tests/System/UInt16Tests.netcoreapp.cs b/src/System.Runtime/tests/System/UInt16Tests.netcoreapp.cs
index b183f168da..aab8121bfc 100644
--- a/src/System.Runtime/tests/System/UInt16Tests.netcoreapp.cs
+++ b/src/System.Runtime/tests/System/UInt16Tests.netcoreapp.cs
@@ -13,9 +13,9 @@ namespace System.Tests
[MemberData(nameof(Parse_Valid_TestData))]
public static void Parse_Span_Valid(string value, NumberStyles style, IFormatProvider provider, ushort expected)
{
- Assert.Equal(expected, ushort.Parse(value.AsReadOnlySpan(), style, provider));
+ Assert.Equal(expected, ushort.Parse(value.AsSpan(), style, provider));
- Assert.True(ushort.TryParse(value.AsReadOnlySpan(), style, provider, out ushort result));
+ Assert.True(ushort.TryParse(value.AsSpan(), style, provider, out ushort result));
Assert.Equal(expected, result);
}
@@ -25,9 +25,9 @@ namespace System.Tests
{
if (value != null)
{
- Assert.Throws(exceptionType, () => ushort.Parse(value.AsReadOnlySpan(), style, provider));
+ Assert.Throws(exceptionType, () => ushort.Parse(value.AsSpan(), style, provider));
- Assert.False(ushort.TryParse(value.AsReadOnlySpan(), style, provider, out ushort result));
+ Assert.False(ushort.TryParse(value.AsSpan(), style, provider, out ushort result));
Assert.Equal(0, (short)result);
}
}
diff --git a/src/System.Runtime/tests/System/UInt32Tests.netcoreapp.cs b/src/System.Runtime/tests/System/UInt32Tests.netcoreapp.cs
index 594a0230ee..e021c22055 100644
--- a/src/System.Runtime/tests/System/UInt32Tests.netcoreapp.cs
+++ b/src/System.Runtime/tests/System/UInt32Tests.netcoreapp.cs
@@ -13,9 +13,9 @@ namespace System.Tests
[MemberData(nameof(Parse_Valid_TestData))]
public static void Parse_Span_Valid(string value, NumberStyles style, IFormatProvider provider, uint expected)
{
- Assert.Equal(expected, uint.Parse(value.AsReadOnlySpan(), style, provider));
+ Assert.Equal(expected, uint.Parse(value.AsSpan(), style, provider));
- Assert.True(uint.TryParse(value.AsReadOnlySpan(), style, provider, out uint result));
+ Assert.True(uint.TryParse(value.AsSpan(), style, provider, out uint result));
Assert.Equal(expected, result);
}
@@ -25,9 +25,9 @@ namespace System.Tests
{
if (value != null)
{
- Assert.Throws(exceptionType, () => uint.Parse(value.AsReadOnlySpan(), style, provider));
+ Assert.Throws(exceptionType, () => uint.Parse(value.AsSpan(), style, provider));
- Assert.False(uint.TryParse(value.AsReadOnlySpan(), style, provider, out uint result));
+ Assert.False(uint.TryParse(value.AsSpan(), style, provider, out uint result));
Assert.Equal(0, (int)result);
}
}
diff --git a/src/System.Runtime/tests/System/UInt64Tests.netcoreapp.cs b/src/System.Runtime/tests/System/UInt64Tests.netcoreapp.cs
index 8be57929f1..6060db3ef3 100644
--- a/src/System.Runtime/tests/System/UInt64Tests.netcoreapp.cs
+++ b/src/System.Runtime/tests/System/UInt64Tests.netcoreapp.cs
@@ -13,9 +13,9 @@ namespace System.Tests
[MemberData(nameof(Parse_Valid_TestData))]
public static void Parse_Span_Valid(string value, NumberStyles style, IFormatProvider provider, ulong expected)
{
- Assert.Equal(expected, ulong.Parse(value.AsReadOnlySpan(), style, provider));
+ Assert.Equal(expected, ulong.Parse(value.AsSpan(), style, provider));
- Assert.True(ulong.TryParse(value.AsReadOnlySpan(), style, provider, out ulong result));
+ Assert.True(ulong.TryParse(value.AsSpan(), style, provider, out ulong result));
Assert.Equal(expected, result);
}
@@ -25,9 +25,9 @@ namespace System.Tests
{
if (value != null)
{
- Assert.Throws(exceptionType, () => ulong.Parse(value.AsReadOnlySpan(), style, provider));
+ Assert.Throws(exceptionType, () => ulong.Parse(value.AsSpan(), style, provider));
- Assert.False(ulong.TryParse(value.AsReadOnlySpan(), style, provider, out ulong result));
+ Assert.False(ulong.TryParse(value.AsSpan(), style, provider, out ulong result));
Assert.Equal(0, (long)result);
}
}
diff --git a/src/System.Runtime/tests/System/ValueTypeTests.cs b/src/System.Runtime/tests/System/ValueTypeTests.cs
index f4a971fa2c..f9aec19b29 100644
--- a/src/System.Runtime/tests/System/ValueTypeTests.cs
+++ b/src/System.Runtime/tests/System/ValueTypeTests.cs
@@ -28,6 +28,7 @@ namespace System.Tests
obj2.value2 = -0.0;
Assert.True(obj1.Equals(obj2));
+ Assert.Equal(obj1.GetHashCode(), obj2.GetHashCode());
}
[Fact]
@@ -43,6 +44,7 @@ namespace System.Tests
obj2.value2 = -0.0;
Assert.True(obj1.Equals(obj2));
+ Assert.Equal(obj1.GetHashCode(), obj2.GetHashCode());
}
[Fact]
@@ -57,6 +59,7 @@ namespace System.Tests
obj2.value2 = -double.NaN;
Assert.True(obj1.Equals(obj2));
+ Assert.Equal(obj1.GetHashCode(), obj2.GetHashCode());
}
[Fact]
@@ -72,6 +75,7 @@ namespace System.Tests
obj2.value2 = -double.NaN;
Assert.True(obj1.Equals(obj2));
+ Assert.Equal(obj1.GetHashCode(), obj2.GetHashCode());
}
[Fact]
@@ -86,6 +90,7 @@ namespace System.Tests
obj2.value2.value2 = -0.0;
Assert.True(obj1.Equals(obj2));
+ Assert.Equal(obj1.GetHashCode(), obj2.GetHashCode());
}
[Fact]
@@ -101,6 +106,7 @@ namespace System.Tests
obj2.value2.value2 = -0.0;
Assert.True(obj1.Equals(obj2));
+ Assert.Equal(obj1.GetHashCode(), obj2.GetHashCode());
}
[Fact]
@@ -115,6 +121,7 @@ namespace System.Tests
obj2.value2.value2 = -double.NaN;
Assert.True(obj1.Equals(obj2));
+ Assert.Equal(obj1.GetHashCode(), obj2.GetHashCode());
}
[Fact]
@@ -130,9 +137,11 @@ namespace System.Tests
obj2.value2.value2 = -double.NaN;
Assert.True(obj1.Equals(obj2));
+ Assert.Equal(obj1.GetHashCode(), obj2.GetHashCode());
}
[Fact]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "The fix was made in coreclr that is not in netfx. See https://github.com/dotnet/coreclr/issues/6237")]
public static void StructWithFloatFieldNotTightlyPackedZeroCompareTest()
{
StructWithFloatFieldNotTightlyPacked obj1 = new StructWithFloatFieldNotTightlyPacked();
@@ -144,6 +153,7 @@ namespace System.Tests
obj2.value2 = 1;
Assert.True(obj1.Equals(obj2));
+ Assert.Equal(obj1.GetHashCode(), obj2.GetHashCode());
}
[Fact]
@@ -159,9 +169,11 @@ namespace System.Tests
obj2.value2 = 1;
Assert.True(obj1.Equals(obj2));
+ Assert.Equal(obj1.GetHashCode(), obj2.GetHashCode());
}
[Fact]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "The fix was made in coreclr that is not in netfx. See https://github.com/dotnet/coreclr/issues/6237")]
public static void StructWithFloatFieldNotTightlyPackedNaNCompareTest()
{
StructWithFloatFieldNotTightlyPacked obj1 = new StructWithFloatFieldNotTightlyPacked();
@@ -173,6 +185,7 @@ namespace System.Tests
obj2.value2 = 1;
Assert.True(obj1.Equals(obj2));
+ Assert.Equal(obj1.GetHashCode(), obj2.GetHashCode());
}
[Fact]
@@ -188,9 +201,11 @@ namespace System.Tests
obj2.value2 = 1;
Assert.True(obj1.Equals(obj2));
+ Assert.Equal(obj1.GetHashCode(), obj2.GetHashCode());
}
[Fact]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "The fix was made in coreclr that is not in netfx. See https://github.com/dotnet/coreclr/issues/6237")]
public static void StructWithNestedFloatFieldNotTightlyPackedZeroCompareTest()
{
StructWithFloatFieldNestedNotTightlyPacked obj1 = new StructWithFloatFieldNestedNotTightlyPacked();
@@ -202,6 +217,7 @@ namespace System.Tests
obj2.value2.value2 = 1;
Assert.True(obj1.Equals(obj2));
+ Assert.Equal(obj1.GetHashCode(), obj2.GetHashCode());
}
[Fact]
@@ -217,9 +233,11 @@ namespace System.Tests
obj2.value2.value2 = 1;
Assert.True(obj1.Equals(obj2));
+ Assert.Equal(obj1.GetHashCode(), obj2.GetHashCode());
}
[Fact]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "The fix was made in coreclr that is not in netfx. See https://github.com/dotnet/coreclr/issues/6237")]
public static void StructWithNestedFloatFieldNotTightlyPackedNaNCompareTest()
{
StructWithFloatFieldNestedNotTightlyPacked obj1 = new StructWithFloatFieldNestedNotTightlyPacked();
@@ -231,6 +249,7 @@ namespace System.Tests
obj2.value2.value2 = 1;
Assert.True(obj1.Equals(obj2));
+ Assert.Equal(obj1.GetHashCode(), obj2.GetHashCode());
}
[Fact]
@@ -246,6 +265,7 @@ namespace System.Tests
obj2.value2.value2 = 1;
Assert.True(obj1.Equals(obj2));
+ Assert.Equal(obj1.GetHashCode(), obj2.GetHashCode());
}
[Fact]
@@ -260,6 +280,7 @@ namespace System.Tests
obj2.value2.value = 2;
Assert.True(obj1.Equals(obj2));
+ Assert.Equal(obj1.GetHashCode(), obj2.GetHashCode());
}
[Fact]
@@ -275,6 +296,7 @@ namespace System.Tests
obj2.value2.value = 2;
Assert.False(obj1.Equals(obj2));
+ Assert.Equal(obj1.GetHashCode(), obj2.GetHashCode());
}
[Fact]
@@ -289,6 +311,7 @@ namespace System.Tests
obj2.value2 = -0.0;
Assert.True(obj1.Equals(obj2));
+ Assert.Equal(obj1.GetHashCode(), obj2.GetHashCode());
}
public struct S
diff --git a/src/System.Runtime/tests/System/VersionTests.netcoreapp.cs b/src/System.Runtime/tests/System/VersionTests.netcoreapp.cs
index 95dea7888d..2d75d18df6 100644
--- a/src/System.Runtime/tests/System/VersionTests.netcoreapp.cs
+++ b/src/System.Runtime/tests/System/VersionTests.netcoreapp.cs
@@ -17,9 +17,9 @@ namespace System.Tests
return;
}
- Assert.Equal(expected, Version.Parse(input.AsReadOnlySpan()));
+ Assert.Equal(expected, Version.Parse(input.AsSpan()));
- Assert.True(Version.TryParse(input.AsReadOnlySpan(), out Version version));
+ Assert.True(Version.TryParse(input.AsSpan(), out Version version));
Assert.Equal(expected, version);
}
@@ -32,9 +32,9 @@ namespace System.Tests
return;
}
- Assert.Throws(exceptionType, () => Version.Parse(input.AsReadOnlySpan()));
+ Assert.Throws(exceptionType, () => Version.Parse(input.AsSpan()));
- Assert.False(Version.TryParse(input.AsReadOnlySpan(), out Version version));
+ Assert.False(Version.TryParse(input.AsSpan(), out Version version));
Assert.Null(version);
}
diff --git a/src/System.Runtime/tests/app.config b/src/System.Runtime/tests/app.config
new file mode 100644
index 0000000000..f2243cc975
--- /dev/null
+++ b/src/System.Runtime/tests/app.config
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!-- Please don't delete. This file needs to be enabled for netfx -->
+<configuration>
+ <runtime>
+ <developmentMode developerInstallation="true" />
+ <UseRandomizedStringHashAlgorithm enabled="1" />
+ </runtime>
+</configuration>
diff --git a/src/System.Security.AccessControl/pkg/System.Security.AccessControl.pkgproj b/src/System.Security.AccessControl/pkg/System.Security.AccessControl.pkgproj
index 634efabebf..11c00d830b 100644
--- a/src/System.Security.AccessControl/pkg/System.Security.AccessControl.pkgproj
+++ b/src/System.Security.AccessControl/pkg/System.Security.AccessControl.pkgproj
@@ -6,9 +6,9 @@
<SupportedFramework>net461;netcoreapp2.0;$(UAPvNextTFM);$(AllXamarinFrameworks)</SupportedFramework>
</ProjectReference>
<File Include="$(PlaceHolderFile)">
- <TargetPath>runtimes/win/lib/$(UAPvNextTFM)</TargetPath>
+ <TargetPath>runtimes/win/lib/uap10.0.16299</TargetPath>
</File>
- <InboxOnTargetFramework Include="$(UAPvNextTFM)" />
+ <InboxOnTargetFramework Include="uap10.0.16299" />
<ProjectReference Include="..\src\System.Security.AccessControl.csproj" />
<HarvestIncludePaths Include="ref/net46;lib/net46;runtimes/win/lib/net46" />
<HarvestIncludePaths Include="ref/netstandard1.3">
diff --git a/src/System.Security.Cryptography.Algorithms/ref/System.Security.Cryptography.Algorithms.cs b/src/System.Security.Cryptography.Algorithms/ref/System.Security.Cryptography.Algorithms.cs
index b5030ad693..0b737c40a9 100644
--- a/src/System.Security.Cryptography.Algorithms/ref/System.Security.Cryptography.Algorithms.cs
+++ b/src/System.Security.Cryptography.Algorithms/ref/System.Security.Cryptography.Algorithms.cs
@@ -195,13 +195,39 @@ namespace System.Security.Cryptography
public static System.Security.Cryptography.ECCurve nistP521 { get { throw null; } }
}
}
+ public abstract partial class ECDiffieHellman : System.Security.Cryptography.AsymmetricAlgorithm
+ {
+ protected ECDiffieHellman() { }
+ public override string KeyExchangeAlgorithm { get { throw null; } }
+ public abstract System.Security.Cryptography.ECDiffieHellmanPublicKey PublicKey { get; }
+ public override string SignatureAlgorithm { get { throw null; } }
+ public static new System.Security.Cryptography.ECDiffieHellman Create() { throw null; }
+ public static System.Security.Cryptography.ECDiffieHellman Create(System.Security.Cryptography.ECCurve curve) { throw null; }
+ public static System.Security.Cryptography.ECDiffieHellman Create(System.Security.Cryptography.ECParameters parameters) { throw null; }
+ public static new System.Security.Cryptography.ECDiffieHellman Create(string algorithm) { throw null; }
+ public byte[] DeriveKeyFromHash(System.Security.Cryptography.ECDiffieHellmanPublicKey otherPartyPublicKey, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; }
+ public virtual byte[] DeriveKeyFromHash(System.Security.Cryptography.ECDiffieHellmanPublicKey otherPartyPublicKey, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, byte[] secretPrepend, byte[] secretAppend) { throw null; }
+ public byte[] DeriveKeyFromHmac(System.Security.Cryptography.ECDiffieHellmanPublicKey otherPartyPublicKey, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, byte[] hmacKey) { throw null; }
+ public virtual byte[] DeriveKeyFromHmac(System.Security.Cryptography.ECDiffieHellmanPublicKey otherPartyPublicKey, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, byte[] hmacKey, byte[] secretPrepend, byte[] secretAppend) { throw null; }
+ public virtual byte[] DeriveKeyMaterial(System.Security.Cryptography.ECDiffieHellmanPublicKey otherPartyPublicKey) { throw null; }
+ public virtual byte[] DeriveKeyTls(System.Security.Cryptography.ECDiffieHellmanPublicKey otherPartyPublicKey, byte[] prfLabel, byte[] prfSeed) { throw null; }
+ public virtual System.Security.Cryptography.ECParameters ExportExplicitParameters(bool includePrivateParameters) { throw null; }
+ public virtual System.Security.Cryptography.ECParameters ExportParameters(bool includePrivateParameters) { throw null; }
+ public override void FromXmlString(string xmlString) { }
+ public virtual void GenerateKey(System.Security.Cryptography.ECCurve curve) { }
+ public virtual void ImportParameters(System.Security.Cryptography.ECParameters parameters) { }
+ public override string ToXmlString(bool includePrivateParameters) { throw null; }
+ }
public abstract partial class ECDiffieHellmanPublicKey : System.IDisposable
{
+ protected ECDiffieHellmanPublicKey() { }
protected ECDiffieHellmanPublicKey(byte[] keyBlob) { }
public void Dispose() { }
protected virtual void Dispose(bool disposing) { }
public virtual byte[] ToByteArray() { throw null; }
public virtual string ToXmlString() { throw null; }
+ public virtual System.Security.Cryptography.ECParameters ExportExplicitParameters() { throw null; }
+ public virtual System.Security.Cryptography.ECParameters ExportParameters() { throw null; }
}
public abstract partial class ECDsa : System.Security.Cryptography.AsymmetricAlgorithm
{
diff --git a/src/System.Security.Cryptography.Algorithms/ref/System.Security.Cryptography.Algorithms.netcoreapp.cs b/src/System.Security.Cryptography.Algorithms/ref/System.Security.Cryptography.Algorithms.netcoreapp.cs
index bb7b224718..538f9d517b 100644
--- a/src/System.Security.Cryptography.Algorithms/ref/System.Security.Cryptography.Algorithms.netcoreapp.cs
+++ b/src/System.Security.Cryptography.Algorithms/ref/System.Security.Cryptography.Algorithms.netcoreapp.cs
@@ -10,17 +10,17 @@ namespace System.Security.Cryptography
{
public abstract partial class DSA : System.Security.Cryptography.AsymmetricAlgorithm
{
- public virtual bool TryCreateSignature(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten) { throw null; }
- protected virtual bool TryHashData(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) { throw null; }
- public virtual bool TrySignData(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) { throw null; }
+ public virtual bool TryCreateSignature(ReadOnlySpan<byte> hash, Span<byte> destination, out int bytesWritten) { throw null; }
+ protected virtual bool TryHashData(ReadOnlySpan<byte> data, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) { throw null; }
+ public virtual bool TrySignData(ReadOnlySpan<byte> data, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) { throw null; }
public virtual bool VerifyData(ReadOnlySpan<byte> data, ReadOnlySpan<byte> signature, HashAlgorithmName hashAlgorithm) { throw null; }
- public virtual bool VerifySignature(ReadOnlySpan<byte> rgbHash, ReadOnlySpan<byte> rgbSignature) { throw null; }
+ public virtual bool VerifySignature(ReadOnlySpan<byte> hash, ReadOnlySpan<byte> signature) { throw null; }
}
public abstract partial class ECDsa : System.Security.Cryptography.AsymmetricAlgorithm
{
- protected virtual bool TryHashData(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) { throw null; }
- public virtual bool TrySignData(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) { throw null; }
- public virtual bool TrySignHash(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten) { throw null; }
+ protected virtual bool TryHashData(ReadOnlySpan<byte> data, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) { throw null; }
+ public virtual bool TrySignData(ReadOnlySpan<byte> data, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) { throw null; }
+ public virtual bool TrySignHash(ReadOnlySpan<byte> hash, Span<byte> destination, out int bytesWritten) { throw null; }
public virtual bool VerifyData(ReadOnlySpan<byte> data, ReadOnlySpan<byte> signature, HashAlgorithmName hashAlgorithm) { throw null; }
public virtual bool VerifyHash(ReadOnlySpan<byte> hash, ReadOnlySpan<byte> signature) { throw null; }
}
@@ -31,16 +31,17 @@ namespace System.Security.Cryptography
}
public abstract partial class RandomNumberGenerator : System.IDisposable
{
+ public static void Fill(Span<byte> data) => throw null;
public virtual void GetBytes(System.Span<byte> data) { }
public virtual void GetNonZeroBytes(System.Span<byte> data) { }
}
public abstract partial class RSA : System.Security.Cryptography.AsymmetricAlgorithm
{
- public virtual bool TryDecrypt(System.ReadOnlySpan<byte> source, System.Span<byte> destination, RSAEncryptionPadding padding, out int bytesWritten) { throw null; }
- public virtual bool TryEncrypt(System.ReadOnlySpan<byte> source, System.Span<byte> destination, RSAEncryptionPadding padding, out int bytesWritten) { throw null; }
- protected virtual bool TryHashData(System.ReadOnlySpan<byte> source, System.Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) { throw null; }
- public virtual bool TrySignData(System.ReadOnlySpan<byte> source, System.Span<byte> destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding, out int bytesWritten) { throw null; }
- public virtual bool TrySignHash(System.ReadOnlySpan<byte> source, System.Span<byte> destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding, out int bytesWritten) { throw null; }
+ public virtual bool TryDecrypt(System.ReadOnlySpan<byte> data, System.Span<byte> destination, RSAEncryptionPadding padding, out int bytesWritten) { throw null; }
+ public virtual bool TryEncrypt(System.ReadOnlySpan<byte> data, System.Span<byte> destination, RSAEncryptionPadding padding, out int bytesWritten) { throw null; }
+ protected virtual bool TryHashData(System.ReadOnlySpan<byte> data, System.Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) { throw null; }
+ public virtual bool TrySignData(System.ReadOnlySpan<byte> data, System.Span<byte> destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding, out int bytesWritten) { throw null; }
+ public virtual bool TrySignHash(System.ReadOnlySpan<byte> hash, System.Span<byte> destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding, out int bytesWritten) { throw null; }
public virtual bool VerifyData(System.ReadOnlySpan<byte> data, System.ReadOnlySpan<byte> signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) { throw null; }
public virtual bool VerifyHash(System.ReadOnlySpan<byte> hash, System.ReadOnlySpan<byte> signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) { throw null; }
}
diff --git a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.OSX.cs b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.OSX.cs
index b663864fd8..4768666d3a 100644
--- a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.OSX.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.OSX.cs
@@ -27,7 +27,7 @@ namespace Internal.Cryptography
return new AppleDigestProvider(Interop.AppleCrypto.PAL_HashAlgorithm.Sha512);
}
- throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmId));
+ throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmId));
}
public static HashProvider CreateMacProvider(string hashAlgorithmId, byte[] key)
@@ -46,7 +46,7 @@ namespace Internal.Cryptography
return new AppleHmacProvider(Interop.AppleCrypto.PAL_HashAlgorithm.Sha512, key);
}
- throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmId));
+ throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmId));
}
// -----------------------------
diff --git a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.Unix.cs b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.Unix.cs
index 999167d6d1..ff8e91e7c9 100644
--- a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.Unix.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.Unix.cs
@@ -27,7 +27,7 @@ namespace Internal.Cryptography
case HashAlgorithmNames.MD5:
return new EvpHashProvider(Interop.Crypto.EvpMd5());
}
- throw new CryptographicException();
+ throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmId));
}
public static unsafe HashProvider CreateMacProvider(string hashAlgorithmId, byte[] key)
@@ -45,7 +45,7 @@ namespace Internal.Cryptography
case HashAlgorithmNames.MD5:
return new HmacHashProvider(Interop.Crypto.EvpMd5(), key);
}
- throw new CryptographicException();
+ throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmId));
}
// -----------------------------
diff --git a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.OSX.cs b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.OSX.cs
index 012fba22de..5133ef3f60 100644
--- a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.OSX.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.OSX.cs
@@ -8,7 +8,7 @@ namespace System.Security.Cryptography
{
partial class RandomNumberGeneratorImplementation
{
- private void GetBytes(ref byte pbBuffer, int count)
+ private static void GetBytes(ref byte pbBuffer, int count)
{
Debug.Assert(count > 0);
diff --git a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.Unix.cs b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.Unix.cs
index 3065b37c5e..2ea1f828fb 100644
--- a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.Unix.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.Unix.cs
@@ -8,7 +8,7 @@ namespace System.Security.Cryptography
{
partial class RandomNumberGeneratorImplementation
{
- private void GetBytes(ref byte pbBuffer, int count)
+ private static void GetBytes(ref byte pbBuffer, int count)
{
Debug.Assert(count > 0);
diff --git a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.Windows.cs b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.Windows.cs
index a7a0253e88..9374f5e2bf 100644
--- a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.Windows.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.Windows.cs
@@ -8,7 +8,7 @@ namespace System.Security.Cryptography
{
partial class RandomNumberGeneratorImplementation
{
- private void GetBytes(ref byte pbBuffer, int count)
+ private static void GetBytes(ref byte pbBuffer, int count)
{
Debug.Assert(count > 0);
diff --git a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.cs b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.cs
index 5d528f158f..8badd131ea 100644
--- a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RandomNumberGeneratorImplementation.cs
@@ -8,6 +8,16 @@ namespace System.Security.Cryptography
{
internal sealed partial class RandomNumberGeneratorImplementation : RandomNumberGenerator
{
+ // As long as each implementation can provide a static GetBytes(ref byte buf, int length)
+ // they can share this one implementation of FillSpan.
+ internal static void FillSpan(Span<byte> data)
+ {
+ if (data.Length > 0)
+ {
+ GetBytes(ref MemoryMarshal.GetReference(data), data.Length);
+ }
+ }
+
public override void GetBytes(byte[] data)
{
if (data == null) throw new ArgumentNullException(nameof(data));
diff --git a/src/System.Security.Cryptography.Algorithms/src/Resources/Strings.resx b/src/System.Security.Cryptography.Algorithms/src/Resources/Strings.resx
index b5fce95f5e..5a1c94f21c 100644
--- a/src/System.Security.Cryptography.Algorithms/src/Resources/Strings.resx
+++ b/src/System.Security.Cryptography.Algorithms/src/Resources/Strings.resx
@@ -79,6 +79,18 @@
<data name="Arg_CryptographyException" xml:space="preserve">
<value>Error occurred during a cryptographic operation.</value>
</data>
+ <data name="Cryptography_ArgECDHKeySizeMismatch" xml:space="preserve">
+ <value>The keys from both parties must be the same size to generate a secret agreement.</value>
+ </data>
+ <data name="Cryptography_ArgECDHRequiresECDHKey" xml:space="preserve">
+ <value>Keys used with the ECDiffieHellmanCng algorithm must have an algorithm group of ECDiffieHellman.</value>
+ </data>
+ <data name="Cryptography_TlsRequiresLabelAndSeed" xml:space="preserve">
+ <value>The TLS key derivation function requires both the label and seed properties to be set.</value>
+ </data>
+ <data name="Cryptography_TlsRequires64ByteSeed" xml:space="preserve">
+ <value>The TLS key derivation function requires a seed value of exactly 64 bytes.</value>
+ </data>
<data name="Cryptography_BadHashSize_ForAlgorithm" xml:space="preserve">
<value>The provided value of {0} bytes does not match the expected size of {1} bytes for the algorithm ({2}).</value>
</data>
@@ -94,6 +106,9 @@
<data name="Cryptography_DSA_KeyGenNotSupported" xml:space="preserve">
<value>DSA keys can be imported, but new key generation is not supported on this platform.</value>
</data>
+ <data name="Cryptography_Encryption_MessageTooLong" xml:space="preserve">
+ <value>The message exceeds the maximum allowable length for the chosen options ({0}).</value>
+ </data>
<data name="Cryptography_ECXmlSerializationFormatRequired" xml:space="preserve">
<value>XML serialization of an elliptic curve key requires using an overload which specifies the XML format to be used.</value>
</data>
@@ -172,6 +187,9 @@
<data name="Cryptography_Invalid_IA5String" xml:space="preserve">
<value>The string contains a character not in the 7 bit ASCII character set.</value>
</data>
+ <data name="Cryptography_KeyTooSmall" xml:space="preserve">
+ <value>The key is too small for the requested operation.</value>
+ </data>
<data name="Cryptography_MissingIV" xml:space="preserve">
<value>The cipher mode specified requires that an initialization vector (IV) be used.</value>
</data>
@@ -190,9 +208,15 @@
<data name="Cryptography_NotValidPublicOrPrivateKey" xml:space="preserve">
<value>Key is not a valid public or private key.</value>
</data>
+ <data name="Cryptography_OAEP_Decryption_Failed" xml:space="preserve">
+ <value>Error occurred while decoding OAEP padding.</value>
+ </data>
<data name="Cryptography_OpenInvalidHandle" xml:space="preserve">
<value>Cannot open an invalid handle.</value>
</data>
+ <data name="Cryptography_Padding_DecDataTooBig" xml:space="preserve">
+ <value>The data to be decrypted exceeds the maximum for this modulus of {0} bytes.</value>
+ </data>
<data name="Cryptography_PartialBlock" xml:space="preserve">
<value>The input data is not a complete block.</value>
</data>
@@ -211,6 +235,9 @@
<data name="Cryptography_Rijndael_BlockSize" xml:space="preserve">
<value>BlockSize must be 128 in this implementation.</value>
</data>
+ <data name="Cryptography_SignHash_WrongSize" xml:space="preserve">
+ <value>The provided hash value is not the expected size for the specified hash algorithm.</value>
+ </data>
<data name="Cryptography_TransformBeyondEndOfBuffer" xml:space="preserve">
<value>Attempt to transform beyond end of buffer.</value>
</data>
diff --git a/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj b/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj
index 3ca3bbc338..9b1cb26508 100644
--- a/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj
+++ b/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj
@@ -47,7 +47,10 @@
<Compile Include="System\Security\Cryptography\ECCurve.cs" />
<Compile Include="System\Security\Cryptography\ECCurve.ECCurveType.cs" />
<Compile Include="System\Security\Cryptography\ECCurve.NamedCurves.cs" />
+ <Compile Include="System\Security\Cryptography\ECDiffieHellman.cs" />
+ <Compile Include="System\Security\Cryptography\ECDiffieHellman.Xml.cs" />
<Compile Include="System\Security\Cryptography\ECDiffieHellmanPublicKey.cs" />
+ <Compile Include="System\Security\Cryptography\ECDiffieHellmanPublicKey.ExportParameters.cs" />
<Compile Include="System\Security\Cryptography\ECDsa.cs" />
<Compile Include="System\Security\Cryptography\ECDsa.Xml.cs" />
<Compile Include="System\Security\Cryptography\ECParameters.cs" />
@@ -104,12 +107,21 @@
<Compile Include="$(CommonPath)\Internal\Cryptography\UniversalCryptoDecryptor.cs">
<Link>Internal\Cryptography\UniversalCryptoDecryptor.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\RsaPaddingProcessor.cs">
+ <Link>Common\System\Security\Cryptography\RsaPaddingProcessor.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup Condition=" '$(TargetsWindows)' == 'true' and '$(IsPartialFacadeAssembly)' != 'true'">
<Compile Include="System\Security\Cryptography\CngKeyLite.cs" />
<Compile Include="System\Security\Cryptography\DSACng.cs" />
+ <Compile Include="System\Security\Cryptography\ECCngKey.cs" />
<Compile Include="System\Security\Cryptography\ECDsaCng.cs" />
<Compile Include="System\Security\Cryptography\ECDsaCng.Key.cs" />
+ <Compile Include="System\Security\Cryptography\ECDiffieHellman.Create.Cng.cs" />
+ <Compile Include="System\Security\Cryptography\ECDiffieHellmanCng.cs" />
+ <Compile Include="System\Security\Cryptography\ECDiffieHellmanCng.Derive.cs" />
+ <Compile Include="System\Security\Cryptography\ECDiffieHellmanCng.Key.cs" />
+ <Compile Include="System\Security\Cryptography\ECDiffieHellmanCngPublicKey.cs" />
<Compile Include="System\Security\Cryptography\RSACng.cs" />
<Compile Include="Internal\Cryptography\AesImplementation.Windows.cs" />
<Compile Include="Internal\Cryptography\DesImplementation.Windows.cs" />
@@ -168,6 +180,15 @@
<Compile Include="$(CommonPath)\Interop\Windows\BCrypt\Interop.BCryptPropertyStrings.cs">
<Link>Interop\Windows\BCrypt\Interop.BCryptPropertyStrings.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\NCrypt\Interop.NCryptDeriveKeyMaterial.cs">
+ <Link>Internal\Windows\NCrypt\Interop.NCryptDeriveKeyMaterial.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\NCrypt\Interop.NCryptDeriveSecretAgreement.cs">
+ <Link>Internal\Windows\NCrypt\Interop.NCryptDeriveSecretAgreement.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\NCrypt\Interop.NCryptBuffer.cs">
+ <Link>Internal\Windows\NCrypt\Interop.NCryptBuffer.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\Interop\Windows\BCrypt\BCryptAlgorithmCache.cs">
<Link>Internal\Windows\BCrypt\BCryptAlgorithmCache.cs</Link>
</Compile>
@@ -255,6 +276,12 @@
<Compile Include="$(CommonPath)\System\Security\Cryptography\ECCng.ImportExport.cs">
<Link>Common\System\Security\Cryptography\ECCng.ImportExport.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\ECDiffieHellmanCng.cs">
+ <Link>Common\System\Security\Cryptography\ECDsaCng.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\ECDiffieHellmanCng.ImportExport.cs">
+ <Link>Common\System\Security\Cryptography\ECDsaCng.ImportExport.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\ECDsaCng.cs">
<Link>Common\System\Security\Cryptography\ECDsaCng.cs</Link>
</Compile>
@@ -305,6 +332,15 @@
<Compile Include="$(CommonPath)\Interop\Unix\System.Security.Cryptography.Native\Interop.EcKey.cs">
<Link>Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EcKey.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.cs">
+ <Link>Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.EcKey.cs">
+ <Link>Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.EcKey.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.Ecdh.cs">
+ <Link>Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.Ecdh.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Security.Cryptography.Native\Interop.ERR.cs">
<Link>Common\Interop\Unix\System.Security.Cryptography.Native\Interop.ERR.cs</Link>
</Compile>
@@ -344,23 +380,41 @@
<Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeEvpMdCtxHandle.Unix.cs">
<Link>Common\Microsoft\Win32\SafeHandles\SafeEvpMdCtxHandle.Unix.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeEvpPkeyCtxHandle.Unix.cs">
+ <Link>Common\Microsoft\Win32\SafeHandles\SafeEvpPkeyCtxHandle.Unix.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeHmacCtxHandle.Unix.cs">
<Link>Common\Microsoft\Win32\SafeHandles\SafeHmacCtxHandle.Unix.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeInteriorHandle.cs">
<Link>Common\Microsoft\Win32\SafeHandles\SafeInteriorHandle.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeEvpPKeyHandle.Unix.cs">
+ <Link>Common\Microsoft\Win32\SafeHandles\SafeEvpPKeyHandle.Unix.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeRsaHandle.Unix.cs">
<Link>Common\Microsoft\Win32\SafeHandles\SafeRsaHandle.Unix.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\DSAOpenSsl.cs">
<Link>Common\System\Security\Cryptography\DSAOpenSsl.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\ECDiffieHellmanOpenSsl.cs">
+ <Link>Common\System\Security\Cryptography\ECDiffieHellmanOpenSsl.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\ECDiffieHellmanOpenSsl.Derive.cs">
+ <Link>Common\System\Security\Cryptography\ECDiffieHellmanOpenSsl.Derive.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\ECDiffieHellmanOpenSslPublicKey.cs">
+ <Link>Common\System\Security\Cryptography\ECDiffieHellmanOpenSslPublicKey.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\ECDsaOpenSsl.cs">
<Link>Common\System\Security\Cryptography\ECDsaOpenSsl.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\ECDsaOpenSsl.ImportExport.cs">
- <Link>Common\System\Security\Cryptography\ECDsaOpenSsl.ImportExport.cs</Link>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\ECOpenSsl.cs">
+ <Link>Common\System\Security\Cryptography\ECOpenSsl.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\ECOpenSsl.ImportExport.cs">
+ <Link>Common\System\Security\Cryptography\ECOpenSsl.ImportExport.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\RSAOpenSsl.cs">
<Link>Common\System\Security\Cryptography\RSAOpenSsl.cs</Link>
@@ -373,6 +427,7 @@
<Compile Include="Internal\Cryptography\RC2Implementation.Unix.cs" />
<Compile Include="Internal\Cryptography\TripleDesImplementation.Unix.cs" />
<Compile Include="System\Security\Cryptography\ECDsaOpenSsl.cs" />
+ <Compile Include="System\Security\Cryptography\ECDiffieHellman.Create.OpenSsl.cs" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetsOSX)' == 'true' ">
<Compile Include="$(CommonPath)\Interop\OSX\Interop.CoreFoundation.cs">
@@ -405,6 +460,9 @@
<Compile Include="$(CommonPath)\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Hmac.cs">
<Link>Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Hmac.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.KeyAgree.cs">
+ <Link>Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.KeyAgree.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Keychain.cs">
<Link>Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Keychain.cs</Link>
</Compile>
@@ -441,6 +499,12 @@
<Compile Include="$(CommonPath)\System\Security\Cryptography\DSASecurityTransforms.cs">
<Link>Common\System\Security\Cryptography\DSASecurityTransforms.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\EccSecurityTransforms.cs">
+ <Link>Common\System\Security\Cryptography\EccSecurityTransforms.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\ECDiffieHellmanSecurityTransforms.cs">
+ <Link>Common\System\Security\Cryptography\ECDiffieHellmanSecurityTransforms.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\ECDsaSecurityTransforms.cs">
<Link>Common\System\Security\Cryptography\ECDsaSecurityTransforms.cs</Link>
</Compile>
@@ -460,6 +524,7 @@
<Compile Include="Internal\Cryptography\RandomNumberGeneratorImplementation.OSX.cs" />
<Compile Include="Internal\Cryptography\RC2Implementation.OSX.cs" />
<Compile Include="Internal\Cryptography\TripleDesImplementation.OSX.cs" />
+ <Compile Include="System\Security\Cryptography\ECDiffieHellman.Create.SecurityTransforms.cs" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetsUnix)' == 'true'">
<Compile Include="$(CommonPath)\Internal\Cryptography\AsymmetricAlgorithmHelpers.Der.cs">
@@ -474,10 +539,14 @@
<Compile Include="$(CommonPath)\System\Security\Cryptography\DerSequenceReader.cs">
<Link>Common\System\Security\Cryptography\DerSequenceReader.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\ECDiffieHellmanDerivation.cs">
+ <Link>Common\System\Security\Cryptography\ECDiffieHellmanDerivation.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true'">
<Reference Include="System.Buffers" />
<Reference Include="System.Collections" />
+ <Reference Include="System.Collections.Concurrent" />
<Reference Include="System.Diagnostics.Debug" />
<Reference Include="System.Diagnostics.Tools" />
<Reference Include="System.Memory" />
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/CngKeyLite.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/CngKeyLite.cs
index d8dc7f8dfe..42d4d272b0 100644
--- a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/CngKeyLite.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/CngKeyLite.cs
@@ -16,8 +16,9 @@ namespace System.Security.Cryptography
{
internal static class CngKeyLite
{
- private static class KeyPropertyName
+ internal static class KeyPropertyName
{
+ internal const string AlgorithmGroup = "Algorithm Group"; // NCRYPT_ALGORITHM_GROUP_PROPERTY
internal const string ECCCurveName = "ECCCurveName"; // NCRYPT_ECC_CURVE_NAME
internal const string ECCParameters = "ECCParameters"; // BCRYPT_ECC_PARAMETERS
internal const string ExportPolicy = "Export Policy"; // NCRYPT_EXPORT_POLICY_PROPERTY
@@ -327,7 +328,7 @@ namespace System.Security.Cryptography
/// Retrieve a well-known CNG string property. (Note: desktop compat: this helper likes to return special values rather than throw exceptions for missing
/// or ill-formatted property values. Only use it for well-known properties that are unlikely to be ill-formatted.)
/// </summary>
- private static string GetPropertyAsString(SafeNCryptHandle ncryptHandle, string propertyName, CngPropertyOptions options)
+ internal static string GetPropertyAsString(SafeNCryptHandle ncryptHandle, string propertyName, CngPropertyOptions options)
{
Debug.Assert(!ncryptHandle.IsInvalid);
byte[] value = GetProperty(ncryptHandle, propertyName, options);
@@ -449,6 +450,10 @@ namespace Microsoft.Win32.SafeHandles
{
}
+ internal class SafeNCryptSecretHandle : SafeNCryptHandle
+ {
+ }
+
internal class DuplicateSafeNCryptKeyHandle : SafeNCryptKeyHandle
{
public DuplicateSafeNCryptKeyHandle(SafeNCryptKeyHandle original)
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/CryptoConfig.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/CryptoConfig.cs
index 348b55564e..140f5d395d 100644
--- a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/CryptoConfig.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/CryptoConfig.cs
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
+using System.Runtime.InteropServices;
namespace System.Security.Cryptography
{
@@ -29,6 +30,8 @@ namespace System.Security.Cryptography
private const string OID_OIWSEC_SHA512 = "2.16.840.1.101.3.4.2.3";
private const string OID_OIWSEC_RIPEMD160 = "1.3.36.3.2.1";
+ private const string ECDsaIdentifier = "ECDsa";
+
private static volatile Dictionary<string, string> s_defaultOidHT = null;
private static volatile Dictionary<string, object> s_defaultNameHT = null;
private static volatile Dictionary<string, Type> appNameHT = new Dictionary<string, Type>(StringComparer.OrdinalIgnoreCase);
@@ -184,7 +187,12 @@ namespace System.Security.Cryptography
ht.Add("DSA", DSACryptoServiceProviderType);
ht.Add("System.Security.Cryptography.DSA", DSACryptoServiceProviderType);
- ht.Add("ECDsa", ECDsaCngType);
+ // Windows will register the public ECDsaCng type. Non-Windows gets a special handler.
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ ht.Add(ECDsaIdentifier, ECDsaCngType);
+ }
+
ht.Add("ECDsaCng", ECDsaCngType);
ht.Add("System.Security.Cryptography.ECDsaCng", ECDsaCngType);
@@ -357,6 +365,15 @@ namespace System.Security.Cryptography
}
}
+ // Special case asking for "ECDsa" since the default map from .NET Framework uses
+ // a Windows-only type.
+ if (retvalType == null &&
+ (args == null || args.Length == 1) &&
+ name == ECDsaIdentifier)
+ {
+ return ECDsa.Create();
+ }
+
// Maybe they gave us a classname.
if (retvalType == null)
{
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/DSA.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/DSA.cs
index e30085d734..9fdeb2b984 100644
--- a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/DSA.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/DSA.cs
@@ -129,9 +129,9 @@ namespace System.Security.Cryptography
return VerifySignature(hash, signature);
}
- public virtual bool TryCreateSignature(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten)
+ public virtual bool TryCreateSignature(ReadOnlySpan<byte> hash, Span<byte> destination, out int bytesWritten)
{
- byte[] sig = CreateSignature(source.ToArray());
+ byte[] sig = CreateSignature(hash.ToArray());
if (sig.Length <= destination.Length)
{
new ReadOnlySpan<byte>(sig).CopyTo(destination);
@@ -145,13 +145,13 @@ namespace System.Security.Cryptography
}
}
- protected virtual bool TryHashData(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten)
+ protected virtual bool TryHashData(ReadOnlySpan<byte> data, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten)
{
- byte[] array = ArrayPool<byte>.Shared.Rent(source.Length);
+ byte[] array = ArrayPool<byte>.Shared.Rent(data.Length);
try
{
- source.CopyTo(array);
- byte[] hash = HashData(array, 0, source.Length, hashAlgorithm);
+ data.CopyTo(array);
+ byte[] hash = HashData(array, 0, data.Length, hashAlgorithm);
if (destination.Length >= hash.Length)
{
new ReadOnlySpan<byte>(hash).CopyTo(destination);
@@ -166,19 +166,19 @@ namespace System.Security.Cryptography
}
finally
{
- Array.Clear(array, 0, source.Length);
+ Array.Clear(array, 0, data.Length);
ArrayPool<byte>.Shared.Return(array);
}
}
- public virtual bool TrySignData(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten)
+ public virtual bool TrySignData(ReadOnlySpan<byte> data, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten)
{
if (string.IsNullOrEmpty(hashAlgorithm.Name))
{
throw HashAlgorithmNameNullOrEmpty();
}
- if (TryHashData(source, destination, hashAlgorithm, out int hashLength) &&
+ if (TryHashData(data, destination, hashAlgorithm, out int hashLength) &&
TryCreateSignature(destination.Slice(0, hashLength), destination, out bytesWritten))
{
return true;
@@ -214,8 +214,8 @@ namespace System.Security.Cryptography
}
}
- public virtual bool VerifySignature(ReadOnlySpan<byte> rgbHash, ReadOnlySpan<byte> rgbSignature) =>
- VerifySignature(rgbHash.ToArray(), rgbSignature.ToArray());
+ public virtual bool VerifySignature(ReadOnlySpan<byte> hash, ReadOnlySpan<byte> signature) =>
+ VerifySignature(hash.ToArray(), signature.ToArray());
private static Exception DerivedClassMustOverride() =>
new NotImplementedException(SR.NotSupported_SubclassOverride);
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECCngKey.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECCngKey.cs
new file mode 100644
index 0000000000..5224477644
--- /dev/null
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECCngKey.cs
@@ -0,0 +1,216 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using Internal.NativeCrypto;
+using Microsoft.Win32.SafeHandles;
+
+namespace System.Security.Cryptography
+{
+ internal sealed partial class ECCngKey
+ {
+ private SafeNCryptKeyHandle _keyHandle;
+ private int _lastKeySize;
+ private string _lastAlgorithm;
+ private readonly string _algorithmGroup;
+
+ internal ECCngKey(string algorithmGroup)
+ {
+ Debug.Assert(
+ algorithmGroup == BCryptNative.AlgorithmName.ECDH ||
+ algorithmGroup == BCryptNative.AlgorithmName.ECDsa);
+
+ _algorithmGroup = algorithmGroup;
+ }
+
+ internal int KeySize { get; private set; }
+
+ internal string GetCurveName(int callerKeySizeProperty)
+ {
+ // Ensure key\handle is created
+ using (SafeNCryptKeyHandle keyHandle = GetDuplicatedKeyHandle(callerKeySizeProperty))
+ {
+ string algorithm = _lastAlgorithm;
+
+ if (ECCng.IsECNamedCurve(algorithm))
+ {
+ return CngKeyLite.GetCurveName(keyHandle);
+ }
+
+ // Use hard-coded values (for use with pre-Win10 APIs)
+ return ECCng.SpecialNistAlgorithmToCurveName(algorithm);
+ }
+ }
+
+ internal SafeNCryptKeyHandle GetDuplicatedKeyHandle(int callerKeySizeProperty)
+ {
+ if (ECCng.IsECNamedCurve(_lastAlgorithm))
+ {
+ // Curve was previously created, so use that
+ return new DuplicateSafeNCryptKeyHandle(_keyHandle);
+ }
+ else
+ {
+ if (_lastKeySize != callerKeySizeProperty)
+ {
+ // Map the current key size to a CNG algorithm name
+ string algorithm;
+
+ bool isEcdsa = _algorithmGroup == BCryptNative.AlgorithmName.ECDsa;
+
+ switch (callerKeySizeProperty)
+ {
+ case 256:
+ algorithm = isEcdsa
+ ? BCryptNative.AlgorithmName.ECDsaP256
+ : BCryptNative.AlgorithmName.ECDHP256;
+ break;
+ case 384:
+ algorithm = isEcdsa
+ ? BCryptNative.AlgorithmName.ECDsaP384
+ : BCryptNative.AlgorithmName.ECDHP384;
+ break;
+ case 521:
+ algorithm = isEcdsa
+ ? BCryptNative.AlgorithmName.ECDsaP521
+ : BCryptNative.AlgorithmName.ECDHP521;
+ break;
+ default:
+ Debug.Fail("Should not have invalid key size");
+ throw new ArgumentException(SR.Cryptography_InvalidKeySize);
+ }
+
+ if (_keyHandle != null)
+ {
+ DisposeKey();
+ }
+
+ _keyHandle = CngKeyLite.GenerateNewExportableKey(algorithm, callerKeySizeProperty);
+ _lastKeySize = callerKeySizeProperty;
+ _lastAlgorithm = algorithm;
+ KeySize = callerKeySizeProperty;
+ }
+
+ return new DuplicateSafeNCryptKeyHandle(_keyHandle);
+ }
+ }
+
+ internal void GenerateKey(ECCurve curve)
+ {
+ curve.Validate();
+
+ if (_keyHandle != null)
+ {
+ DisposeKey();
+ }
+
+ string algorithm = null;
+ int keySize = 0;
+
+ if (curve.IsNamed)
+ {
+ if (string.IsNullOrEmpty(curve.Oid.FriendlyName))
+ {
+ throw new PlatformNotSupportedException(
+ string.Format(SR.Cryptography_InvalidCurveOid, curve.Oid.Value));
+ }
+
+ // Map curve name to algorithm to support pre-Win10 curves
+ if (_algorithmGroup == BCryptNative.AlgorithmName.ECDsa)
+ {
+ algorithm = ECCng.EcdsaCurveNameToAlgorithm(curve.Oid.FriendlyName);
+ }
+ else
+ {
+ Debug.Assert(_algorithmGroup == BCryptNative.AlgorithmName.ECDH);
+ algorithm = ECCng.EcdhCurveNameToAlgorithm(curve.Oid.FriendlyName);
+ }
+
+ if (ECCng.IsECNamedCurve(algorithm))
+ {
+ try
+ {
+ _keyHandle = CngKeyLite.GenerateNewExportableKey(algorithm, curve.Oid.FriendlyName);
+ keySize = CngKeyLite.GetKeyLength(_keyHandle);
+ }
+ catch (CryptographicException e)
+ {
+ // Map to PlatformNotSupportedException if appropriate
+ Interop.NCrypt.ErrorCode errorCode = (Interop.NCrypt.ErrorCode)e.HResult;
+
+ if (curve.IsNamed && errorCode == Interop.NCrypt.ErrorCode.NTE_INVALID_PARAMETER ||
+ errorCode == Interop.NCrypt.ErrorCode.NTE_NOT_SUPPORTED)
+ {
+ throw new PlatformNotSupportedException(
+ string.Format(SR.Cryptography_CurveNotSupported, curve.Oid.FriendlyName), e);
+ }
+
+ throw;
+ }
+ }
+ else
+ {
+ // Get the proper KeySize from algorithm name
+ switch (algorithm)
+ {
+ case BCryptNative.AlgorithmName.ECDsaP256:
+ case BCryptNative.AlgorithmName.ECDHP256:
+ keySize = 256;
+ break;
+ case BCryptNative.AlgorithmName.ECDsaP384:
+ case BCryptNative.AlgorithmName.ECDHP384:
+ keySize = 384;
+ break;
+ case BCryptNative.AlgorithmName.ECDsaP521:
+ case BCryptNative.AlgorithmName.ECDHP521:
+ keySize = 521;
+ break;
+ default:
+ Debug.Fail(string.Format("Unknown algorithm {0}", algorithm.ToString()));
+ throw new ArgumentException(SR.Cryptography_InvalidKeySize);
+ }
+
+ _keyHandle = CngKeyLite.GenerateNewExportableKey(algorithm, keySize);
+ }
+ }
+ else if (curve.IsExplicit)
+ {
+ algorithm = _algorithmGroup;
+ _keyHandle = CngKeyLite.GenerateNewExportableKey(algorithm, ref curve);
+ keySize = CngKeyLite.GetKeyLength(_keyHandle);
+ }
+ else
+ {
+ throw new PlatformNotSupportedException(
+ string.Format(SR.Cryptography_CurveNotSupported, curve.CurveType.ToString()));
+ }
+
+ _lastAlgorithm = algorithm;
+ _lastKeySize = keySize;
+ KeySize = keySize;
+ }
+
+ internal void DisposeKey()
+ {
+ if (_keyHandle != null)
+ {
+ _keyHandle.Dispose();
+ _keyHandle = null;
+ }
+
+ _lastAlgorithm = null;
+ _lastKeySize = 0;
+ }
+
+ internal void SetHandle(SafeNCryptKeyHandle keyHandle, string algorithmName)
+ {
+ _keyHandle?.Dispose();
+ _keyHandle = keyHandle;
+ _lastAlgorithm = algorithmName;
+
+ KeySize = CngKeyLite.GetKeyLength(keyHandle);
+ _lastKeySize = KeySize;
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellman.Create.Cng.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellman.Create.Cng.cs
new file mode 100644
index 0000000000..4e8362e9ec
--- /dev/null
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellman.Create.Cng.cs
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Security.Cryptography
+{
+ public abstract partial class ECDiffieHellman : AsymmetricAlgorithm
+ {
+ public static new ECDiffieHellman Create()
+ {
+ return new ECDiffieHellmanImplementation.ECDiffieHellmanCng();
+ }
+
+ public static ECDiffieHellman Create(ECCurve curve)
+ {
+ return new ECDiffieHellmanImplementation.ECDiffieHellmanCng(curve);
+ }
+
+ public static ECDiffieHellman Create(ECParameters parameters)
+ {
+ ECDiffieHellman ecdh = new ECDiffieHellmanImplementation.ECDiffieHellmanCng();
+
+ try
+ {
+ ecdh.ImportParameters(parameters);
+ return ecdh;
+ }
+ catch
+ {
+ ecdh.Dispose();
+ throw;
+ }
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellman.Create.OpenSsl.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellman.Create.OpenSsl.cs
new file mode 100644
index 0000000000..4be428f569
--- /dev/null
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellman.Create.OpenSsl.cs
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Security.Cryptography
+{
+ public abstract partial class ECDiffieHellman : AsymmetricAlgorithm
+ {
+ public static new ECDiffieHellman Create()
+ {
+ return new ECDiffieHellmanImplementation.ECDiffieHellmanOpenSsl();
+ }
+
+ public static ECDiffieHellman Create(ECCurve curve)
+ {
+ return new ECDiffieHellmanImplementation.ECDiffieHellmanOpenSsl(curve);
+ }
+
+ public static ECDiffieHellman Create(ECParameters parameters)
+ {
+ ECDiffieHellman ecdh = new ECDiffieHellmanImplementation.ECDiffieHellmanOpenSsl();
+
+ try
+ {
+ ecdh.ImportParameters(parameters);
+ return ecdh;
+ }
+ catch
+ {
+ ecdh.Dispose();
+ throw;
+ }
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellman.Create.SecurityTransforms.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellman.Create.SecurityTransforms.cs
new file mode 100644
index 0000000000..a6945bfdaf
--- /dev/null
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellman.Create.SecurityTransforms.cs
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Security.Cryptography
+{
+ public abstract partial class ECDiffieHellman : AsymmetricAlgorithm
+ {
+ public static new ECDiffieHellman Create()
+ {
+ return new ECDiffieHellmanImplementation.ECDiffieHellmanSecurityTransforms();
+ }
+
+ public static ECDiffieHellman Create(ECCurve curve)
+ {
+ ECDiffieHellman ecdh = Create();
+
+ try
+ {
+ ecdh.GenerateKey(curve);
+ return ecdh;
+ }
+ catch
+ {
+ ecdh.Dispose();
+ throw;
+ }
+ }
+
+ public static ECDiffieHellman Create(ECParameters parameters)
+ {
+ ECDiffieHellman ecdh = Create();
+
+ try
+ {
+ ecdh.ImportParameters(parameters);
+ return ecdh;
+ }
+ catch
+ {
+ ecdh.Dispose();
+ throw;
+ }
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellman.Xml.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellman.Xml.cs
new file mode 100644
index 0000000000..3bd0cc8ee9
--- /dev/null
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellman.Xml.cs
@@ -0,0 +1,19 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Security.Cryptography
+{
+ public abstract partial class ECDiffieHellman : AsymmetricAlgorithm
+ {
+ public override void FromXmlString(string xmlString)
+ {
+ throw new NotImplementedException(SR.Cryptography_ECXmlSerializationFormatRequired);
+ }
+
+ public override string ToXmlString(bool includePrivateParameters)
+ {
+ throw new NotImplementedException(SR.Cryptography_ECXmlSerializationFormatRequired);
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellman.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellman.cs
new file mode 100644
index 0000000000..e471c46b09
--- /dev/null
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellman.cs
@@ -0,0 +1,170 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Security.Cryptography
+{
+ /// <summary>
+ /// Abstract base class for implementations of elliptic curve Diffie-Hellman to derive from
+ /// </summary>
+ public abstract partial class ECDiffieHellman : AsymmetricAlgorithm
+ {
+ public override string KeyExchangeAlgorithm
+ {
+ get { return "ECDiffieHellman"; }
+ }
+
+ public override string SignatureAlgorithm
+ {
+ get { return null; }
+ }
+
+ public static new ECDiffieHellman Create(string algorithm)
+ {
+ if (algorithm == null)
+ {
+ throw new ArgumentNullException(nameof(algorithm));
+ }
+
+ return CryptoConfig.CreateFromName(algorithm) as ECDiffieHellman;
+ }
+
+ public abstract ECDiffieHellmanPublicKey PublicKey { get; }
+
+ // This method must be implemented by derived classes. In order to conform to the contract, it cannot be abstract.
+ public virtual byte[] DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey)
+ {
+ throw DerivedClassMustOverride();
+ }
+
+ /// <summary>
+ /// Derive key material using the formula HASH(x) where x is the computed result of the EC Diffie-Hellman algorithm.
+ /// </summary>
+ /// <param name="otherPartyPublicKey">The public key of the party with which to derive a mutual secret.</param>
+ /// <param name="hashAlgorithm">The identifier for the hash algorithm to use.</param>
+ /// <returns>A hashed output suitable for key material</returns>
+ /// <exception cref="ArgumentException"><paramref name="otherPartyPublicKey"/> is over a different curve than this key</exception>
+ public byte[] DeriveKeyFromHash(ECDiffieHellmanPublicKey otherPartyPublicKey, HashAlgorithmName hashAlgorithm)
+ {
+ return DeriveKeyFromHash(otherPartyPublicKey, hashAlgorithm, null, null);
+ }
+
+ /// <summary>
+ /// Derive key material using the formula HASH(secretPrepend || x || secretAppend) where x is the computed
+ /// result of the EC Diffie-Hellman algorithm.
+ /// </summary>
+ /// <param name="otherPartyPublicKey">The public key of the party with which to derive a mutual secret.</param>
+ /// <param name="hashAlgorithm">The identifier for the hash algorithm to use.</param>
+ /// <param name="secretPrepend">A value to prepend to the derived secret before hashing. A <c>null</c> value is treated as an empty array.</param>
+ /// <param name="secretAppend">A value to append to the derived secret before hashing. A <c>null</c> value is treated as an empty array.</param>
+ /// <returns>A hashed output suitable for key material</returns>
+ /// <exception cref="ArgumentException"><paramref name="otherPartyPublicKey"/> is over a different curve than this key</exception>
+ public virtual byte[] DeriveKeyFromHash(
+ ECDiffieHellmanPublicKey otherPartyPublicKey,
+ HashAlgorithmName hashAlgorithm,
+ byte[] secretPrepend,
+ byte[] secretAppend)
+ {
+ throw DerivedClassMustOverride();
+ }
+
+ /// <summary>
+ /// Derive key material using the formula HMAC(hmacKey, x) where x is the computed
+ /// result of the EC Diffie-Hellman algorithm.
+ /// </summary>
+ /// <param name="otherPartyPublicKey">The public key of the party with which to derive a mutual secret.</param>
+ /// <param name="hashAlgorithm">The identifier for the hash algorithm to use.</param>
+ /// <param name="hmacKey">The key to use in the HMAC. A <c>null</c> value indicates that the result of the EC Diffie-Hellman algorithm should be used as the HMAC key.</param>
+ /// <returns>A hashed output suitable for key material</returns>
+ /// <exception cref="ArgumentException"><paramref name="otherPartyPublicKey"/> is over a different curve than this key</exception>
+ public byte[] DeriveKeyFromHmac(
+ ECDiffieHellmanPublicKey otherPartyPublicKey,
+ HashAlgorithmName hashAlgorithm,
+ byte[] hmacKey)
+ {
+ return DeriveKeyFromHmac(otherPartyPublicKey, hashAlgorithm, hmacKey, null, null);
+ }
+
+ /// <summary>
+ /// Derive key material using the formula HMAC(hmacKey, secretPrepend || x || secretAppend) where x is the computed
+ /// result of the EC Diffie-Hellman algorithm.
+ /// </summary>
+ /// <param name="otherPartyPublicKey">The public key of the party with which to derive a mutual secret.</param>
+ /// <param name="hashAlgorithm">The identifier for the hash algorithm to use.</param>
+ /// <param name="hmacKey">The key to use in the HMAC. A <c>null</c> value indicates that the result of the EC Diffie-Hellman algorithm should be used as the HMAC key.</param>
+ /// <param name="secretPrepend">A value to prepend to the derived secret before hashing. A <c>null</c> value is treated as an empty array.</param>
+ /// <param name="secretAppend">A value to append to the derived secret before hashing. A <c>null</c> value is treated as an empty array.</param>
+ /// <returns>A hashed output suitable for key material</returns>
+ /// <exception cref="ArgumentException"><paramref name="otherPartyPublicKey"/> is over a different curve than this key</exception>
+ public virtual byte[] DeriveKeyFromHmac(
+ ECDiffieHellmanPublicKey otherPartyPublicKey,
+ HashAlgorithmName hashAlgorithm,
+ byte[] hmacKey,
+ byte[] secretPrepend,
+ byte[] secretAppend)
+ {
+ throw DerivedClassMustOverride();
+ }
+
+ /// <summary>
+ /// Derive key material using the TLS pseudo-random function (PRF) derivation algorithm.
+ /// </summary>
+ /// <param name="otherPartyPublicKey">The public key of the party with which to derive a mutual secret.</param>
+ /// <param name="prfLabel">The ASCII encoded PRF label.</param>
+ /// <param name="prfSeed">The 64-byte PRF seed.</param>
+ /// <returns>A 48-byte output of the TLS pseudo-random function.</returns>
+ /// <exception cref="ArgumentException"><paramref name="otherPartyPublicKey"/> is over a different curve than this key</exception>
+ /// <exception cref="ArgumentNullException"><paramref name="prfLabel"/> is null</exception>
+ /// <exception cref="ArgumentNullException"><paramref name="prfSeed"/> is null</exception>
+ /// <exception cref="CryptographicException"><paramref name="prfSeed"/> is not exactly 64 bytes in length</exception>
+ public virtual byte[] DeriveKeyTls(ECDiffieHellmanPublicKey otherPartyPublicKey, byte[] prfLabel, byte[] prfSeed)
+ {
+ throw DerivedClassMustOverride();
+ }
+
+ private static Exception DerivedClassMustOverride()
+ {
+ return new NotImplementedException(SR.NotSupported_SubclassOverride);
+ }
+
+ /// <summary>
+ /// When overridden in a derived class, exports the named or explicit ECParameters for an ECCurve.
+ /// If the curve has a name, the Curve property will contain named curve parameters, otherwise it
+ /// will contain explicit parameters.
+ /// </summary>
+ /// <param name="includePrivateParameters">true to include private parameters, otherwise, false.</param>
+ /// <returns>The ECParameters representing the point on the curve for this key.</returns>
+ public virtual ECParameters ExportParameters(bool includePrivateParameters)
+ {
+ throw DerivedClassMustOverride();
+ }
+
+ /// <summary>
+ /// When overridden in a derived class, exports the explicit ECParameters for an ECCurve.
+ /// </summary>
+ /// <param name="includePrivateParameters">true to include private parameters, otherwise, false.</param>
+ /// <returns>The ECParameters representing the point on the curve for this key, using the explicit curve format.</returns>
+ public virtual ECParameters ExportExplicitParameters(bool includePrivateParameters)
+ {
+ throw DerivedClassMustOverride();
+ }
+
+ /// <summary>
+ /// When overridden in a derived class, imports the specified ECParameters.
+ /// </summary>
+ /// <param name="parameters">The curve parameters.</param>
+ public virtual void ImportParameters(ECParameters parameters)
+ {
+ throw DerivedClassMustOverride();
+ }
+
+ /// <summary>
+ /// When overridden in a derived class, generates a new public/private keypair for the specified curve.
+ /// </summary>
+ /// <param name="curve">The curve to use.</param>
+ public virtual void GenerateKey(ECCurve curve)
+ {
+ throw new NotSupportedException(SR.NotSupported_SubclassOverride);
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanCng.Derive.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanCng.Derive.cs
new file mode 100644
index 0000000000..008cd8227e
--- /dev/null
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanCng.Derive.cs
@@ -0,0 +1,72 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Internal.NativeCrypto;
+using Microsoft.Win32.SafeHandles;
+
+namespace System.Security.Cryptography
+{
+ internal static partial class ECDiffieHellmanImplementation
+ {
+ public sealed partial class ECDiffieHellmanCng : ECDiffieHellman
+ {
+ // For the public ECDiffieHellmanCng this is exposed as the HashAlgorithm property
+ // which is a CngAlgorithm type. We're not doing that, but we do need the default value
+ // for DeriveKeyMaterial.
+ public override byte[] DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey)
+ {
+ if (otherPartyPublicKey == null)
+ {
+ throw new ArgumentNullException(nameof(otherPartyPublicKey));
+ }
+
+ // ECDiffieHellmanCng on .NET Framework will throw an ArgumentException in this method
+ // if otherPartyPublicKey is not an ECDiffieHellmanCngPublicKey. All of the other methods
+ // will use Import/Export to coerce the correct type for interop.
+
+ // None of the other Core types will match that behavior, so the ECDiffieHellman.Create() on
+ // Windows on .NET Core won't, either.
+
+ // The default behavior for ECDiffieHellmanCng / ECDiffieHellman.Create() on .NET Framework was
+ // to derive from hash, no prepend, no append, SHA-2-256.
+ return DeriveKeyFromHash(otherPartyPublicKey, HashAlgorithmName.SHA256);
+ }
+
+ private SafeNCryptSecretHandle DeriveSecretAgreementHandle(ECDiffieHellmanPublicKey otherPartyPublicKey)
+ {
+ if (otherPartyPublicKey == null)
+ {
+ throw new ArgumentNullException(nameof(otherPartyPublicKey));
+ }
+
+ ECParameters otherPartyParameters = otherPartyPublicKey.ExportParameters();
+
+ using (ECDiffieHellmanCng otherPartyCng = (ECDiffieHellmanCng)Create(otherPartyParameters))
+ using (SafeNCryptKeyHandle otherPartyHandle = otherPartyCng.GetDuplicatedKeyHandle())
+ {
+ string importedKeyAlgorithmGroup =
+ CngKeyLite.GetPropertyAsString(
+ otherPartyHandle,
+ CngKeyLite.KeyPropertyName.AlgorithmGroup,
+ CngPropertyOptions.None);
+
+ if (importedKeyAlgorithmGroup != BCryptNative.AlgorithmName.ECDH)
+ {
+ throw new ArgumentException(SR.Cryptography_ArgECDHRequiresECDHKey, nameof(otherPartyPublicKey));
+ }
+
+ if (CngKeyLite.GetKeyLength(otherPartyHandle) != KeySize)
+ {
+ throw new ArgumentException(SR.Cryptography_ArgECDHKeySizeMismatch, nameof(otherPartyPublicKey));
+ }
+
+ using (SafeNCryptKeyHandle localHandle = GetDuplicatedKeyHandle())
+ {
+ return Interop.NCrypt.DeriveSecretAgreement(localHandle, otherPartyHandle);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanCng.Key.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanCng.Key.cs
new file mode 100644
index 0000000000..d6d18ccb79
--- /dev/null
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanCng.Key.cs
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Internal.NativeCrypto;
+using Microsoft.Win32.SafeHandles;
+
+namespace System.Security.Cryptography
+{
+ internal static partial class ECDiffieHellmanImplementation
+ {
+ public sealed partial class ECDiffieHellmanCng : ECDiffieHellman
+ {
+ private readonly ECCngKey _key = new ECCngKey(BCryptNative.AlgorithmName.ECDH);
+
+ private string GetCurveName() => _key.GetCurveName(KeySize);
+
+ public override void GenerateKey(ECCurve curve)
+ {
+ _key.GenerateKey(curve);
+ ForceSetKeySize(_key.KeySize);
+ }
+
+ private SafeNCryptKeyHandle GetDuplicatedKeyHandle() => _key.GetDuplicatedKeyHandle(KeySize);
+
+ private void DisposeKey() => _key.DisposeKey();
+
+ /// <summary>
+ /// Public key used to generate key material with the second party
+ /// </summary>
+ public override ECDiffieHellmanPublicKey PublicKey
+ {
+ get
+ {
+ string curveName = GetCurveName();
+
+ return new ECDiffieHellmanCngPublicKey(
+ curveName == null
+ ? ExportFullKeyBlob(includePrivateParameters: false)
+ : ExportKeyBlob(includePrivateParameters: false),
+ curveName);
+ }
+ }
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanCng.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanCng.cs
new file mode 100644
index 0000000000..e6485509f2
--- /dev/null
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanCng.cs
@@ -0,0 +1,68 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using Microsoft.Win32.SafeHandles;
+using static Internal.NativeCrypto.BCryptNative;
+
+namespace System.Security.Cryptography
+{
+ internal static partial class ECDiffieHellmanImplementation
+ {
+ public sealed partial class ECDiffieHellmanCng : ECDiffieHellman
+ {
+ private void ImportFullKeyBlob(byte[] ecfullKeyBlob, bool includePrivateParameters)
+ {
+ string blobType = includePrivateParameters ?
+ Interop.BCrypt.KeyBlobType.BCRYPT_ECCFULLPRIVATE_BLOB :
+ Interop.BCrypt.KeyBlobType.BCRYPT_ECCFULLPUBLIC_BLOB;
+
+ SafeNCryptKeyHandle keyHandle = CngKeyLite.ImportKeyBlob(blobType, ecfullKeyBlob);
+
+ Debug.Assert(!keyHandle.IsInvalid);
+
+ _key.SetHandle(keyHandle, AlgorithmName.ECDH);
+ ForceSetKeySize(_key.KeySize);
+ }
+
+ private void ImportKeyBlob(byte[] ecKeyBlob, string curveName, bool includePrivateParameters)
+ {
+ string blobType = includePrivateParameters ?
+ Interop.BCrypt.KeyBlobType.BCRYPT_ECCPRIVATE_BLOB :
+ Interop.BCrypt.KeyBlobType.BCRYPT_ECCPUBLIC_BLOB;
+
+ SafeNCryptKeyHandle keyHandle = CngKeyLite.ImportKeyBlob(blobType, ecKeyBlob, curveName);
+
+ Debug.Assert(!keyHandle.IsInvalid);
+
+ _key.SetHandle(keyHandle, ECCng.EcdhCurveNameToAlgorithm(curveName));
+ ForceSetKeySize(_key.KeySize);
+ }
+
+ private byte[] ExportKeyBlob(bool includePrivateParameters)
+ {
+ string blobType = includePrivateParameters ?
+ Interop.BCrypt.KeyBlobType.BCRYPT_ECCPRIVATE_BLOB :
+ Interop.BCrypt.KeyBlobType.BCRYPT_ECCPUBLIC_BLOB;
+
+ using (SafeNCryptKeyHandle keyHandle = GetDuplicatedKeyHandle())
+ {
+ return CngKeyLite.ExportKeyBlob(keyHandle, blobType);
+ }
+ }
+
+ private byte[] ExportFullKeyBlob(bool includePrivateParameters)
+ {
+ string blobType = includePrivateParameters ?
+ Interop.BCrypt.KeyBlobType.BCRYPT_ECCFULLPRIVATE_BLOB :
+ Interop.BCrypt.KeyBlobType.BCRYPT_ECCFULLPUBLIC_BLOB;
+
+ using (SafeNCryptKeyHandle keyHandle = GetDuplicatedKeyHandle())
+ {
+ return CngKeyLite.ExportKeyBlob(keyHandle, blobType);
+ }
+ }
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanCngPublicKey.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanCngPublicKey.cs
new file mode 100644
index 0000000000..8a669b4a1e
--- /dev/null
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanCngPublicKey.cs
@@ -0,0 +1,81 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+
+namespace System.Security.Cryptography
+{
+ internal static partial class ECDiffieHellmanImplementation
+ {
+ public sealed partial class ECDiffieHellmanCngPublicKey : ECDiffieHellmanPublicKey
+ {
+ private byte[] _keyBlob;
+ internal string _curveName;
+
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+ }
+
+ public override string ToXmlString()
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ public static ECDiffieHellmanCngPublicKey FromXmlString(string xml)
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ internal ECDiffieHellmanCngPublicKey(byte[] keyBlob, string curveName) : base(keyBlob)
+ {
+ Debug.Assert(_curveName != null && keyBlob != null);
+
+ _keyBlob = keyBlob;
+ _curveName = curveName;
+ }
+
+ /// <summary>
+ /// Exports the key and explicit curve parameters used by the ECC object into an <see cref="ECParameters"/> object.
+ /// </summary>
+ /// <exception cref="CryptographicException">
+ /// if there was an issue obtaining the curve values.
+ /// </exception>
+ /// <exception cref="PlatformNotSupportedException">
+ /// if explicit export is not supported by this platform. Windows 10 or higher is required.
+ /// </exception>
+ /// <returns>The key and explicit curve parameters used by the ECC object.</returns>
+ public override ECParameters ExportExplicitParameters()
+ {
+ ECParameters ecparams = new ECParameters();
+ ECCng.ExportPrimeCurveParameters(ref ecparams, _keyBlob, includePrivateParameters: false);
+ return ecparams;
+ }
+
+ /// <summary>
+ /// Exports the key used by the ECC object into an <see cref="ECParameters"/> object.
+ /// If the key was created as a named curve, the Curve property will contain named curve parameters
+ /// otherwise it will contain explicit parameters.
+ /// </summary>
+ /// <exception cref="CryptographicException">
+ /// if there was an issue obtaining the curve values.
+ /// </exception>
+ /// <returns>The key and named curve parameters used by the ECC object.</returns>
+ public override ECParameters ExportParameters()
+ {
+ if (string.IsNullOrEmpty(_curveName))
+ {
+ return ExportExplicitParameters();
+ }
+ else
+ {
+ ECParameters ecparams = new ECParameters();
+ ECCng.ExportNamedCurveParameters(ref ecparams, _keyBlob, includePrivateParameters: false);
+ ecparams.Curve = ECCurve.CreateFromFriendlyName(_curveName);
+ return ecparams;
+ }
+ }
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanPublicKey.ExportParameters.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanPublicKey.ExportParameters.cs
new file mode 100644
index 0000000000..44a473d901
--- /dev/null
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanPublicKey.ExportParameters.cs
@@ -0,0 +1,32 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Security.Cryptography
+{
+ /// <summary>
+ /// Wrapper for public key material passed between parties during Diffie-Hellman key material generation
+ /// </summary>
+ public abstract partial class ECDiffieHellmanPublicKey : IDisposable
+ {
+ /// <summary>
+ /// When overridden in a derived class, exports the named or explicit ECParameters for an ECCurve.
+ /// If the curve has a name, the Curve property will contain named curve parameters, otherwise it
+ /// will contain explicit parameters.
+ /// </summary>
+ /// <returns>The ECParameters representing the point on the curve for this key.</returns>
+ public virtual ECParameters ExportParameters()
+ {
+ throw new NotSupportedException(SR.NotSupported_SubclassOverride);
+ }
+
+ /// <summary>
+ /// When overridden in a derived class, exports the explicit ECParameters for an ECCurve.
+ /// </summary>
+ /// <returns>The ECParameters representing the point on the curve for this key, using the explicit curve format.</returns>
+ public virtual ECParameters ExportExplicitParameters()
+ {
+ throw new NotSupportedException(SR.NotSupported_SubclassOverride);
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanPublicKey.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanPublicKey.cs
index 78b04674d1..9a389a477b 100644
--- a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanPublicKey.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanPublicKey.cs
@@ -7,11 +7,18 @@ namespace System.Security.Cryptography
/// <summary>
/// Wrapper for public key material passed between parties during Diffie-Hellman key material generation
/// </summary>
+#if MONO
[Serializable]
- public abstract class ECDiffieHellmanPublicKey : IDisposable
+#endif
+ public abstract partial class ECDiffieHellmanPublicKey : IDisposable
{
private readonly byte[] _keyBlob;
+ protected ECDiffieHellmanPublicKey()
+ {
+ _keyBlob = Array.Empty<byte>();
+ }
+
protected ECDiffieHellmanPublicKey(byte[] keyBlob)
{
if (keyBlob == null)
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDsa.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDsa.cs
index d17ded3926..f5ff11d92c 100644
--- a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDsa.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDsa.cs
@@ -83,14 +83,14 @@ namespace System.Security.Cryptography
return SignHash(hash);
}
- public virtual bool TrySignData(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten)
+ public virtual bool TrySignData(ReadOnlySpan<byte> data, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten)
{
if (string.IsNullOrEmpty(hashAlgorithm.Name))
{
throw new ArgumentException(SR.Cryptography_HashAlgorithmNameNullOrEmpty, nameof(hashAlgorithm));
}
- if (TryHashData(source, destination, hashAlgorithm, out int hashLength) &&
+ if (TryHashData(data, destination, hashAlgorithm, out int hashLength) &&
TrySignHash(destination.Slice(0, hashLength), destination, out bytesWritten))
{
return true;
@@ -191,13 +191,13 @@ namespace System.Security.Cryptography
throw new NotSupportedException(SR.NotSupported_SubclassOverride);
}
- protected virtual bool TryHashData(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten)
+ protected virtual bool TryHashData(ReadOnlySpan<byte> data, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten)
{
- byte[] array = ArrayPool<byte>.Shared.Rent(source.Length);
+ byte[] array = ArrayPool<byte>.Shared.Rent(data.Length);
try
{
- source.CopyTo(array);
- byte[] hash = HashData(array, 0, source.Length, hashAlgorithm);
+ data.CopyTo(array);
+ byte[] hash = HashData(array, 0, data.Length, hashAlgorithm);
if (hash.Length <= destination.Length)
{
new ReadOnlySpan<byte>(hash).CopyTo(destination);
@@ -212,14 +212,14 @@ namespace System.Security.Cryptography
}
finally
{
- Array.Clear(array, 0, source.Length);
+ Array.Clear(array, 0, data.Length);
ArrayPool<byte>.Shared.Return(array);
}
}
- public virtual bool TrySignHash(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten)
+ public virtual bool TrySignHash(ReadOnlySpan<byte> hash, Span<byte> destination, out int bytesWritten)
{
- byte[] result = SignHash(source.ToArray());
+ byte[] result = SignHash(hash.ToArray());
if (result.Length <= destination.Length)
{
new ReadOnlySpan<byte>(result).CopyTo(destination);
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDsaCng.Key.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDsaCng.Key.cs
index 6c5ffbae85..dd126187ac 100644
--- a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDsaCng.Key.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDsaCng.Key.cs
@@ -2,154 +2,28 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using Microsoft.Win32.SafeHandles;
+using static Internal.NativeCrypto.BCryptNative;
+
namespace System.Security.Cryptography
{
- using Microsoft.Win32.SafeHandles;
- using System.Diagnostics;
- using static Internal.NativeCrypto.BCryptNative;
- using static Interop.NCrypt;
internal static partial class ECDsaImplementation
{
public sealed partial class ECDsaCng : ECDsa
{
- private SafeNCryptKeyHandle _keyHandle;
- private int _lastKeySize;
- private string _lastAlgorithm;
-
- internal string GetCurveName()
- {
- using (SafeNCryptKeyHandle keyHandle = GetDuplicatedKeyHandle()) // Ensure key\handle is created
- {
- string algorithm = _lastAlgorithm;
- if (IsECNamedCurve(algorithm))
- {
- return CngKeyLite.GetCurveName(keyHandle);
- }
-
- // Use hard-coded values (for use with pre-Win10 APIs)
- return SpecialNistAlgorithmToCurveName(algorithm);
- }
- }
-
- private SafeNCryptKeyHandle GetDuplicatedKeyHandle()
- {
- if (IsECNamedCurve(_lastAlgorithm))
- {
- // Curve was previously created, so use that
- return new DuplicateSafeNCryptKeyHandle(_keyHandle);
- }
- else
- {
- string algorithm = null;
-
- int keySize = KeySize;
- if (_lastKeySize != keySize)
- {
- // Map the current key size to a CNG algorithm name
- switch (keySize)
- {
- case 256: algorithm = AlgorithmName.ECDsaP256; break;
- case 384: algorithm = AlgorithmName.ECDsaP384; break;
- case 521: algorithm = AlgorithmName.ECDsaP521; break;
- default:
- Debug.Fail("Should not have invalid key size");
- throw new ArgumentException(SR.Cryptography_InvalidKeySize);
- }
- if (_keyHandle != null)
- {
- DisposeKey();
- }
- _keyHandle = CngKeyLite.GenerateNewExportableKey(algorithm, keySize);
- _lastKeySize = keySize;
- _lastAlgorithm = algorithm;
- ForceSetKeySize(keySize);
- }
- return new DuplicateSafeNCryptKeyHandle(_keyHandle);
- }
- }
+ private readonly ECCngKey _key = new ECCngKey(AlgorithmName.ECDsa);
+ private string GetCurveName() => _key.GetCurveName(KeySize);
+
public override void GenerateKey(ECCurve curve)
{
- curve.Validate();
-
- if (_keyHandle != null)
- {
- DisposeKey();
- }
-
- string algorithm = null;
- int keySize = 0;
-
- if (curve.IsNamed)
- {
- if (string.IsNullOrEmpty(curve.Oid.FriendlyName))
- throw new PlatformNotSupportedException(string.Format(SR.Cryptography_InvalidCurveOid, curve.Oid.Value));
-
- // Map curve name to algorithm to support pre-Win10 curves
- algorithm = ECCng.EcdsaCurveNameToAlgorithm(curve.Oid.FriendlyName);
- if (IsECNamedCurve(algorithm))
- {
- try
- {
- _keyHandle = CngKeyLite.GenerateNewExportableKey(algorithm, curve.Oid.FriendlyName);
- keySize = CngKeyLite.GetKeyLength(_keyHandle);
- }
- catch (CryptographicException e)
- {
- // Map to PlatformNotSupportedException if appropriate
- ErrorCode errorCode = (ErrorCode)e.HResult;
-
- if (curve.IsNamed &&
- errorCode == ErrorCode.NTE_INVALID_PARAMETER || errorCode == ErrorCode.NTE_NOT_SUPPORTED)
- {
- throw new PlatformNotSupportedException(string.Format(SR.Cryptography_CurveNotSupported, curve.Oid.FriendlyName), e);
- }
- throw;
- }
- }
- else
- {
- // Get the proper KeySize from algorithm name
- if (algorithm == AlgorithmName.ECDsaP256)
- keySize = 256;
- else if (algorithm == AlgorithmName.ECDsaP384)
- keySize = 384;
- else if (algorithm == AlgorithmName.ECDsaP521)
- keySize = 521;
- else
- {
- Debug.Fail(string.Format("Unknown algorithm {0}", algorithm.ToString()));
- throw new ArgumentException(SR.Cryptography_InvalidKeySize);
- }
- _keyHandle = CngKeyLite.GenerateNewExportableKey(algorithm, keySize);
- }
- }
- else if (curve.IsExplicit)
- {
- algorithm = AlgorithmName.ECDsa;
- _keyHandle = CngKeyLite.GenerateNewExportableKey(algorithm, ref curve);
- keySize = CngKeyLite.GetKeyLength(_keyHandle);
- }
- else
- {
- throw new PlatformNotSupportedException(string.Format(SR.Cryptography_CurveNotSupported, curve.CurveType.ToString()));
- }
-
- _lastAlgorithm = algorithm;
- _lastKeySize = keySize;
- ForceSetKeySize(keySize);
+ _key.GenerateKey(curve);
+ ForceSetKeySize(_key.KeySize);
}
- private void DisposeKey()
- {
- if (_keyHandle != null)
- {
- _keyHandle.Dispose();
- _keyHandle = null;
- }
- _lastAlgorithm = null;
- _lastKeySize = 0;
- }
+ private SafeNCryptKeyHandle GetDuplicatedKeyHandle() => _key.GetDuplicatedKeyHandle(KeySize);
+
+ private void DisposeKey() => _key.DisposeKey();
}
}
}
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDsaCng.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDsaCng.cs
index e2f6bf17b4..70ababc343 100644
--- a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDsaCng.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECDsaCng.cs
@@ -58,13 +58,8 @@ namespace System.Security.Cryptography
Debug.Assert(!keyHandle.IsInvalid);
- _keyHandle = keyHandle;
- _lastAlgorithm = AlgorithmName.ECDsa;
-
- int newKeySize = CngKeyLite.GetKeyLength(keyHandle);
-
- ForceSetKeySize(newKeySize);
- _lastKeySize = newKeySize;
+ _key.SetHandle(keyHandle, AlgorithmName.ECDsa);
+ ForceSetKeySize(_key.KeySize);
}
private void ImportKeyBlob(byte[] ecKeyBlob, string curveName, bool includePrivateParameters)
@@ -77,13 +72,8 @@ namespace System.Security.Cryptography
Debug.Assert(!keyHandle.IsInvalid);
- _keyHandle = keyHandle;
- _lastAlgorithm = ECCng.EcdsaCurveNameToAlgorithm(curveName);
-
- int newKeySize = CngKeyLite.GetKeyLength(keyHandle);
-
- ForceSetKeySize(newKeySize);
- _lastKeySize = newKeySize;
+ _key.SetHandle(keyHandle, ECCng.EcdsaCurveNameToAlgorithm(curveName));
+ ForceSetKeySize(_key.KeySize);
}
private byte[] ExportKeyBlob(bool includePrivateParameters)
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/RSA.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/RSA.cs
index c0e34b19c2..aa5962b0be 100644
--- a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/RSA.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/RSA.cs
@@ -56,9 +56,9 @@ namespace System.Security.Cryptography
protected virtual byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) => throw DerivedClassMustOverride();
protected virtual byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) => throw DerivedClassMustOverride();
- public virtual bool TryDecrypt(ReadOnlySpan<byte> source, Span<byte> destination, RSAEncryptionPadding padding, out int bytesWritten)
+ public virtual bool TryDecrypt(ReadOnlySpan<byte> data, Span<byte> destination, RSAEncryptionPadding padding, out int bytesWritten)
{
- byte[] result = Decrypt(source.ToArray(), padding);
+ byte[] result = Decrypt(data.ToArray(), padding);
if (destination.Length >= result.Length)
{
@@ -71,9 +71,9 @@ namespace System.Security.Cryptography
return false;
}
- public virtual bool TryEncrypt(ReadOnlySpan<byte> source, Span<byte> destination, RSAEncryptionPadding padding, out int bytesWritten)
+ public virtual bool TryEncrypt(ReadOnlySpan<byte> data, Span<byte> destination, RSAEncryptionPadding padding, out int bytesWritten)
{
- byte[] result = Encrypt(source.ToArray(), padding);
+ byte[] result = Encrypt(data.ToArray(), padding);
if (destination.Length >= result.Length)
{
@@ -86,18 +86,18 @@ namespace System.Security.Cryptography
return false;
}
- protected virtual bool TryHashData(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten)
+ protected virtual bool TryHashData(ReadOnlySpan<byte> data, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten)
{
byte[] result;
- byte[] array = ArrayPool<byte>.Shared.Rent(source.Length);
+ byte[] array = ArrayPool<byte>.Shared.Rent(data.Length);
try
{
- source.CopyTo(array);
- result = HashData(array, 0, source.Length, hashAlgorithm);
+ data.CopyTo(array);
+ result = HashData(array, 0, data.Length, hashAlgorithm);
}
finally
{
- Array.Clear(array, 0, source.Length);
+ Array.Clear(array, 0, data.Length);
ArrayPool<byte>.Shared.Return(array);
}
@@ -112,9 +112,9 @@ namespace System.Security.Cryptography
return false;
}
- public virtual bool TrySignHash(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding, out int bytesWritten)
+ public virtual bool TrySignHash(ReadOnlySpan<byte> hash, Span<byte> destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding, out int bytesWritten)
{
- byte[] result = SignHash(source.ToArray(), hashAlgorithm, padding);
+ byte[] result = SignHash(hash.ToArray(), hashAlgorithm, padding);
if (destination.Length >= result.Length)
{
@@ -184,7 +184,7 @@ namespace System.Security.Cryptography
return SignHash(hash, hashAlgorithm, padding);
}
- public virtual bool TrySignData(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding, out int bytesWritten)
+ public virtual bool TrySignData(ReadOnlySpan<byte> data, Span<byte> destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding, out int bytesWritten)
{
if (string.IsNullOrEmpty(hashAlgorithm.Name))
{
@@ -195,7 +195,7 @@ namespace System.Security.Cryptography
throw new ArgumentNullException(nameof(padding));
}
- if (TryHashData(source, destination, hashAlgorithm, out int hashLength) &&
+ if (TryHashData(data, destination, hashAlgorithm, out int hashLength) &&
TrySignHash(destination.Slice(0, hashLength), destination, hashAlgorithm, padding, out bytesWritten))
{
return true;
diff --git a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/RandomNumberGenerator.cs b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/RandomNumberGenerator.cs
index 31c88b7739..8a3895f048 100644
--- a/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/RandomNumberGenerator.cs
+++ b/src/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/RandomNumberGenerator.cs
@@ -91,6 +91,11 @@ namespace System.Security.Cryptography
}
}
+ public static void Fill(Span<byte> data)
+ {
+ RandomNumberGeneratorImplementation.FillSpan(data);
+ }
+
internal void VerifyGetBytes(byte[] data, int offset, int count)
{
if (data == null) throw new ArgumentNullException(nameof(data));
diff --git a/src/System.Security.Cryptography.Algorithms/tests/CryptoConfigTests.cs b/src/System.Security.Cryptography.Algorithms/tests/CryptoConfigTests.cs
index 9e78d3bddb..c4e971b468 100644
--- a/src/System.Security.Cryptography.Algorithms/tests/CryptoConfigTests.cs
+++ b/src/System.Security.Cryptography.Algorithms/tests/CryptoConfigTests.cs
@@ -192,7 +192,7 @@ namespace System.Security.Cryptography.CryptoConfigTests
yield return new object[] { "System.Security.Cryptography.AsymmetricAlgorithm", "System.Security.Cryptography.RSACryptoServiceProvider", true };
yield return new object[] { "DSA", "System.Security.Cryptography.DSACryptoServiceProvider", true };
yield return new object[] { "System.Security.Cryptography.DSA", "System.Security.Cryptography.DSACryptoServiceProvider", true };
- yield return new object[] { "ECDsa", "System.Security.Cryptography.ECDsaCng", false };
+ yield return new object[] { "ECDsa", "System.Security.Cryptography.ECDsaCng", true };
yield return new object[] { "ECDsaCng", "System.Security.Cryptography.ECDsaCng", false };
yield return new object[] { "System.Security.Cryptography.ECDsaCng", null, false };
yield return new object[] { "DES", "System.Security.Cryptography.DESCryptoServiceProvider", true };
@@ -256,7 +256,9 @@ namespace System.Security.Cryptography.CryptoConfigTests
[Theory, MemberData(nameof(AllValidNames))]
public static void CreateFromName_AllValidNames(string name, string typeName, bool supportsUnixMac)
{
- if (supportsUnixMac || RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
+
+ if (supportsUnixMac || isWindows)
{
object obj = CryptoConfig.CreateFromName(name);
Assert.NotNull(obj);
@@ -266,7 +268,15 @@ namespace System.Security.Cryptography.CryptoConfigTests
typeName = name;
}
- Assert.Equal(typeName, obj.GetType().FullName);
+ // ECDsa is special on non-Windows
+ if (isWindows || name != "ECDsa")
+ {
+ Assert.Equal(typeName, obj.GetType().FullName);
+ }
+ else
+ {
+ Assert.NotEqual(typeName, obj.GetType().FullName);
+ }
if (obj is IDisposable)
{
diff --git a/src/System.Security.Cryptography.Algorithms/tests/DSATests.cs b/src/System.Security.Cryptography.Algorithms/tests/DSATests.cs
index c3d1251db6..22c9391ba7 100644
--- a/src/System.Security.Cryptography.Algorithms/tests/DSATests.cs
+++ b/src/System.Security.Cryptography.Algorithms/tests/DSATests.cs
@@ -107,7 +107,7 @@ namespace System.Security.Cryptography.Algorithms.Tests
byte[] signature = wrapperDsa.SignData(input, HashAlgorithmName.SHA1);
Assert.True(wrapperDsa.VerifyData(input.AsSpan(), signature, HashAlgorithmName.SHA1));
- Assert.False(wrapperDsa.VerifyData(input.AsSpan(), signature.AsReadOnlySpan().Slice(0, signature.Length - 1), HashAlgorithmName.SHA1));
+ Assert.False(wrapperDsa.VerifyData(input.AsSpan(), signature.AsSpan(0, signature.Length - 1), HashAlgorithmName.SHA1));
}
}
@@ -126,7 +126,7 @@ namespace System.Security.Cryptography.Algorithms.Tests
byte[] signature = wrapperDsa.SignData(new MemoryStream(input), HashAlgorithmName.SHA1);
Assert.True(wrapperDsa.VerifyData(new MemoryStream(input), signature, HashAlgorithmName.SHA1));
- Assert.False(wrapperDsa.VerifyData(new MemoryStream(input), signature.AsReadOnlySpan().Slice(0, signature.Length - 1).ToArray(), HashAlgorithmName.SHA1));
+ Assert.False(wrapperDsa.VerifyData(new MemoryStream(input), signature.AsSpan(0, signature.Length - 1).ToArray(), HashAlgorithmName.SHA1));
}
}
@@ -143,7 +143,7 @@ namespace System.Security.Cryptography.Algorithms.Tests
byte[] signature = wrapperDsa.SignData(input, HashAlgorithmName.SHA1);
Assert.True(wrapperDsa.VerifyData(input.AsSpan(), signature, HashAlgorithmName.SHA1));
- Assert.False(wrapperDsa.VerifyData(input.AsSpan(), signature.AsReadOnlySpan().Slice(0, signature.Length - 1), HashAlgorithmName.SHA1));
+ Assert.False(wrapperDsa.VerifyData(input.AsSpan(), signature.AsSpan(0, signature.Length - 1), HashAlgorithmName.SHA1));
}
}
diff --git a/src/System.Security.Cryptography.Algorithms/tests/DefaultECDiffieHellmanProvider.Unix.cs b/src/System.Security.Cryptography.Algorithms/tests/DefaultECDiffieHellmanProvider.Unix.cs
new file mode 100644
index 0000000000..21c3c5016e
--- /dev/null
+++ b/src/System.Security.Cryptography.Algorithms/tests/DefaultECDiffieHellmanProvider.Unix.cs
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+
+namespace System.Security.Cryptography.EcDiffieHellman.Tests
+{
+ public partial class ECDiffieHellmanProvider : IECDiffieHellmanProvider
+ {
+ public bool IsCurveValid(Oid oid)
+ {
+ if (PlatformDetection.IsOSX)
+ {
+ return false;
+ }
+ if (!string.IsNullOrEmpty(oid.Value))
+ {
+ // Value is passed before FriendlyName
+ return IsValueOrFriendlyNameValid(oid.Value);
+ }
+ return IsValueOrFriendlyNameValid(oid.FriendlyName);
+ }
+
+ public bool ExplicitCurvesSupported
+ {
+ get
+ {
+ if (PlatformDetection.IsOSX)
+ {
+ return false;
+ }
+
+ return true;
+ }
+ }
+
+ private static bool IsValueOrFriendlyNameValid(string friendlyNameOrValue)
+ {
+ if (string.IsNullOrEmpty(friendlyNameOrValue))
+ {
+ return false;
+ }
+
+ IntPtr key = Interop.Crypto.EcKeyCreateByOid(friendlyNameOrValue);
+ if (key != IntPtr.Zero)
+ {
+ Interop.Crypto.EcKeyDestroy(key);
+ return true;
+ }
+ return false;
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Algorithms/tests/DefaultECDiffieHellmanProvider.Windows.cs b/src/System.Security.Cryptography.Algorithms/tests/DefaultECDiffieHellmanProvider.Windows.cs
new file mode 100644
index 0000000000..a5c2470275
--- /dev/null
+++ b/src/System.Security.Cryptography.Algorithms/tests/DefaultECDiffieHellmanProvider.Windows.cs
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using Test.Cryptography;
+
+namespace System.Security.Cryptography.EcDiffieHellman.Tests
+{
+ public partial class ECDiffieHellmanProvider : IECDiffieHellmanProvider
+ {
+ public bool IsCurveValid(Oid oid)
+ {
+ // Friendly name required for windows
+ return NativeOidFriendlyNameExists(oid.FriendlyName);
+ }
+
+ public bool ExplicitCurvesSupported
+ {
+ get
+ {
+ return PlatformDetection.WindowsVersion >= 10;
+ }
+ }
+
+ private static bool NativeOidFriendlyNameExists(string oidFriendlyName)
+ {
+ if (string.IsNullOrEmpty(oidFriendlyName))
+ return false;
+
+ try
+ {
+ // By specifying OidGroup.PublicKeyAlgorithm, no caches are used
+ // Note: this throws when there is no oid value, even when friendly name is valid
+ // so it cannot be used for curves with no oid value such as curve25519
+ return !string.IsNullOrEmpty(Oid.FromFriendlyName(oidFriendlyName, OidGroup.PublicKeyAlgorithm).FriendlyName);
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+ }
+ }
+}
+
diff --git a/src/System.Security.Cryptography.Algorithms/tests/DefaultECDiffieHellmanProvider.cs b/src/System.Security.Cryptography.Algorithms/tests/DefaultECDiffieHellmanProvider.cs
new file mode 100644
index 0000000000..2885750e10
--- /dev/null
+++ b/src/System.Security.Cryptography.Algorithms/tests/DefaultECDiffieHellmanProvider.cs
@@ -0,0 +1,32 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Security.Cryptography.EcDiffieHellman.Tests
+{
+ public partial class ECDiffieHellmanProvider : IECDiffieHellmanProvider
+ {
+ public ECDiffieHellman Create()
+ {
+ return ECDiffieHellman.Create();
+ }
+
+ public ECDiffieHellman Create(int keySize)
+ {
+ ECDiffieHellman ec = Create();
+ ec.KeySize = keySize;
+ return ec;
+ }
+
+ public ECDiffieHellman Create(ECCurve curve)
+ {
+ return ECDiffieHellman.Create(curve);
+ }
+ }
+
+ public partial class ECDiffieHellmanFactory
+ {
+ private static readonly IECDiffieHellmanProvider s_provider = new ECDiffieHellmanProvider();
+ }
+}
+
diff --git a/src/System.Security.Cryptography.Algorithms/tests/DefaultRSAProvider.cs b/src/System.Security.Cryptography.Algorithms/tests/DefaultRSAProvider.cs
index f3c3414888..873a599b23 100644
--- a/src/System.Security.Cryptography.Algorithms/tests/DefaultRSAProvider.cs
+++ b/src/System.Security.Cryptography.Algorithms/tests/DefaultRSAProvider.cs
@@ -45,13 +45,14 @@ namespace System.Security.Cryptography.Rsa.Tests
}
}
- public bool SupportsSha2Oaep
- {
- // Currently only RSACng does, which is the default provider on Windows.
- get { return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !(Create() is RSACryptoServiceProvider); }
- }
+ public bool SupportsSha2Oaep { get; } =
+ !PlatformDetection.IsFullFramework || !(RSA.Create() is RSACryptoServiceProvider);
+
+ public bool SupportsPss { get; } =
+ !PlatformDetection.IsFullFramework || !(RSA.Create() is RSACryptoServiceProvider);
public bool SupportsDecryptingIntoExactSpaceRequired => RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
+
}
public partial class RSAFactory
diff --git a/src/System.Security.Cryptography.Algorithms/tests/ECDiffieHellmanPublicKeyTests.cs b/src/System.Security.Cryptography.Algorithms/tests/ECDiffieHellmanPublicKeyTests.cs
index a769d4e2c5..c73f6b6e63 100644
--- a/src/System.Security.Cryptography.Algorithms/tests/ECDiffieHellmanPublicKeyTests.cs
+++ b/src/System.Security.Cryptography.Algorithms/tests/ECDiffieHellmanPublicKeyTests.cs
@@ -4,7 +4,7 @@
using Xunit;
-namespace System.Security.Cryptography.ECDiffieHellman.Tests
+namespace System.Security.Cryptography.EcDiffieHellman.Tests
{
public class ECDiffieHellmanPublicKeyTests
{
diff --git a/src/System.Security.Cryptography.Algorithms/tests/ECDiffieHellmanTests.cs b/src/System.Security.Cryptography.Algorithms/tests/ECDiffieHellmanTests.cs
new file mode 100644
index 0000000000..5770079da2
--- /dev/null
+++ b/src/System.Security.Cryptography.Algorithms/tests/ECDiffieHellmanTests.cs
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Tests;
+using System.Text;
+using Test.Cryptography;
+using Xunit;
+
+namespace System.Security.Cryptography.EcDiffieHellman.Tests
+{
+ public partial class ECDiffieHellmanTests
+ {
+ [Fact]
+ public static void ECCurve_ctor()
+ {
+ using (ECDiffieHellman ecdh = ECDiffieHellmanFactory.Create(ECCurve.NamedCurves.nistP256))
+ {
+ Assert.Equal(256, ecdh.KeySize);
+ ecdh.Exercise();
+ }
+
+ using (ECDiffieHellman ecdh = ECDiffieHellmanFactory.Create(ECCurve.NamedCurves.nistP384))
+ {
+ Assert.Equal(384, ecdh.KeySize);
+ ecdh.Exercise();
+ }
+
+ using (ECDiffieHellman ecdh = ECDiffieHellmanFactory.Create(ECCurve.NamedCurves.nistP521))
+ {
+ Assert.Equal(521, ecdh.KeySize);
+ ecdh.Exercise();
+ }
+ }
+
+ [Fact]
+ public static void Equivalence_Hash()
+ {
+ using (ECDiffieHellman ecdh = ECDiffieHellmanFactory.Create())
+ using (ECDiffieHellmanPublicKey publicKey = ecdh.PublicKey)
+ {
+ byte[] newWay = ecdh.DeriveKeyFromHash(publicKey, HashAlgorithmName.SHA256, null, null);
+ byte[] oldWay = ecdh.DeriveKeyMaterial(publicKey);
+ Assert.Equal(newWay, oldWay);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/System.Security.Cryptography.Algorithms/tests/ECDsaTests.cs b/src/System.Security.Cryptography.Algorithms/tests/ECDsaTests.cs
index 644cf412f7..217467798f 100644
--- a/src/System.Security.Cryptography.Algorithms/tests/ECDsaTests.cs
+++ b/src/System.Security.Cryptography.Algorithms/tests/ECDsaTests.cs
@@ -76,7 +76,7 @@ namespace System.Security.Cryptography.Algorithms.Tests
Assert.NotNull(result);
Assert.NotEmpty(result);
- Assert.False(ecdsa.VerifyData(input.AsSpan().Slice(1).ToArray(), result, HashAlgorithmName.SHA256));
+ Assert.False(ecdsa.VerifyData(input.AsSpan(1).ToArray(), result, HashAlgorithmName.SHA256));
Assert.True(ecdsa.VerifyData(input, result, HashAlgorithmName.SHA256));
}
}
@@ -102,7 +102,7 @@ namespace System.Security.Cryptography.Algorithms.Tests
Assert.NotNull(result);
Assert.NotEmpty(result);
- Assert.False(ecdsa.VerifyData(new MemoryStream(input.AsSpan().Slice(1).ToArray()), result, HashAlgorithmName.SHA256));
+ Assert.False(ecdsa.VerifyData(new MemoryStream(input.AsSpan(1).ToArray()), result, HashAlgorithmName.SHA256));
Assert.True(ecdsa.VerifyData(new MemoryStream(input), result, HashAlgorithmName.SHA256));
}
}
diff --git a/src/System.Security.Cryptography.Algorithms/tests/HashAlgorithmTest.netcoreapp.cs b/src/System.Security.Cryptography.Algorithms/tests/HashAlgorithmTest.netcoreapp.cs
index c76951d8dc..5750440f0a 100644
--- a/src/System.Security.Cryptography.Algorithms/tests/HashAlgorithmTest.netcoreapp.cs
+++ b/src/System.Security.Cryptography.Algorithms/tests/HashAlgorithmTest.netcoreapp.cs
@@ -34,7 +34,7 @@ namespace System.Security.Cryptography.Hashing.Algorithms.Tests
actual[actual.Length - 1] = 42;
Assert.True(hash.TryComputeHash(input, actual, out bytesWritten));
Assert.Equal(expected.Length, bytesWritten);
- Assert.Equal(expected, actual.AsSpan().Slice(0, expected.Length).ToArray());
+ Assert.Equal(expected, actual.AsSpan(0, expected.Length).ToArray());
Assert.Equal(42, actual[actual.Length - 1]);
}
}
diff --git a/src/System.Security.Cryptography.Algorithms/tests/IncrementalHashTests.cs b/src/System.Security.Cryptography.Algorithms/tests/IncrementalHashTests.cs
index ee0e6cd5d0..d029cda080 100644
--- a/src/System.Security.Cryptography.Algorithms/tests/IncrementalHashTests.cs
+++ b/src/System.Security.Cryptography.Algorithms/tests/IncrementalHashTests.cs
@@ -265,5 +265,19 @@ namespace System.Security.Cryptography.Algorithms.Tests
Assert.Throws<ObjectDisposedException>(() => hash.GetHashAndReset());
}
}
+
+ [Fact]
+ public static void UnknownDigestAlgorithm()
+ {
+ Assert.ThrowsAny<CryptographicException>(
+ () => IncrementalHash.CreateHash(new HashAlgorithmName("SHA0")));
+ }
+
+ [Fact]
+ public static void UnknownHmacAlgorithm()
+ {
+ Assert.ThrowsAny<CryptographicException>(
+ () => IncrementalHash.CreateHMAC(new HashAlgorithmName("SHA0"), Array.Empty<byte>()));
+ }
}
}
diff --git a/src/System.Security.Cryptography.Algorithms/tests/RandomNumberGeneratorTests.netcoreapp.cs b/src/System.Security.Cryptography.Algorithms/tests/RandomNumberGeneratorTests.netcoreapp.cs
index 3ca4bbabaf..018e2b0088 100644
--- a/src/System.Security.Cryptography.Algorithms/tests/RandomNumberGeneratorTests.netcoreapp.cs
+++ b/src/System.Security.Cryptography.Algorithms/tests/RandomNumberGeneratorTests.netcoreapp.cs
@@ -55,5 +55,42 @@ namespace System.Security.Cryptography.RNG.Tests
Assert.Equal(-1, Array.IndexOf<byte>(rand, 0));
}
}
+
+ [Fact]
+ public static void Fill_ZeroLengthSpan()
+ {
+ byte[] rand = { 1 };
+ RandomNumberGenerator.Fill(new Span<byte>(rand, 0, 0));
+ Assert.Equal(1, rand[0]);
+ }
+
+ [Fact]
+ public static void Fill_SpanLength1()
+ {
+ byte[] rand = { 1 };
+ bool replacedValue = false;
+
+ for (int i = 0; i < 10; i++)
+ {
+ RandomNumberGenerator.Fill(rand);
+
+ if (rand[0] != 1)
+ {
+ replacedValue = true;
+ break;
+ }
+ }
+
+ Assert.True(replacedValue, "Fill eventually wrote a different byte");
+ }
+
+ [Fact]
+ public static void Fill_RandomDistribution()
+ {
+ byte[] random = new byte[2048];
+ RandomNumberGenerator.Fill(random);
+
+ RandomDataGenerator.VerifyRandomDistribution(random);
+ }
}
}
diff --git a/src/System.Security.Cryptography.Algorithms/tests/System.Security.Cryptography.Algorithms.Tests.csproj b/src/System.Security.Cryptography.Algorithms/tests/System.Security.Cryptography.Algorithms.Tests.csproj
index 4ecce64cd1..5698a14e2c 100644
--- a/src/System.Security.Cryptography.Algorithms/tests/System.Security.Cryptography.Algorithms.Tests.csproj
+++ b/src/System.Security.Cryptography.Algorithms/tests/System.Security.Cryptography.Algorithms.Tests.csproj
@@ -52,6 +52,12 @@
<Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\EC\CurveDef.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\CurveDef.cs</Link>
</Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\EC\EccTestBase.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\EccTestBase.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\EC\EccTestData.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\EccTestData.cs</Link>
+ </Compile>
<Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaFactory.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaFactory.cs</Link>
</Compile>
@@ -70,9 +76,6 @@
<Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaTestsBase.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaTestsBase.cs</Link>
</Compile>
- <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaTestData.cs">
- <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaTestData.cs</Link>
- </Compile>
<Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\RSA\EncryptDecrypt.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\EncryptDecrypt.cs</Link>
</Compile>
@@ -129,23 +132,55 @@
<ItemGroup Condition="'$(TargetsWindows)' == 'true'">
<Compile Include="DefaultECDsaProvider.Windows.cs" />
</ItemGroup>
+ <ItemGroup Condition="'$(TargetsWindows)' == 'true' AND '$(TargetGroup)'=='netcoreapp'">
+ <Compile Include="DefaultECDiffieHellmanProvider.Windows.cs" />
+ </ItemGroup>
<ItemGroup Condition="'$(TargetsUnix)' == 'true'">
<Compile Include="DefaultECDsaProvider.Unix.cs" />
<Compile Include="$(CommonPath)\Interop\Unix\Interop.Libraries.cs">
<Link>Common\Interop\Unix\Interop.Libraries.cs</Link>
</Compile>
</ItemGroup>
+ <ItemGroup Condition="'$(TargetsUnix)' == 'true' AND '$(Targetgroup)'=='netcoreapp'">
+ <Compile Include="DefaultECDiffieHellmanProvider.Unix.cs" />
+ </ItemGroup>
<ItemGroup Condition="'$(TargetGroup)'=='netcoreapp'">
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanFactory.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanFactory.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Hash.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Hash.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Hmac.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Hmac.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.ImportExport.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.ImportExport.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.NistValidation.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.NistValidation.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Tls.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Tls.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Xml.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Xml.cs</Link>
+ </Compile>
<Compile Include="AesManagedTests.cs" />
<Compile Include="AsymmetricSignatureFormatterTests.cs" />
<Compile Include="BlockSizeValueTests.cs" />
<Compile Include="CryptoConfigTests.cs" />
<Compile Include="DefaultDSAProvider.cs" />
+ <Compile Include="DefaultECDiffieHellmanProvider.cs" />
<Compile Include="DESProvider.cs" />
<Compile Include="DESTests.cs" />
<Compile Include="DSACreateTests.cs" />
<Compile Include="DSASignatureFormatterTests.cs" />
<Compile Include="DSATests.cs" />
+ <Compile Include="ECDiffieHellmanTests.cs" />
<Compile Include="ECDiffieHellmanPublicKeyTests.cs" />
<Compile Include="ECDsaTests.cs" />
<Compile Include="HashAlgorithmTest.netcoreapp.cs" />
diff --git a/src/System.Security.Cryptography.Cng/pkg/System.Security.Cryptography.Cng.pkgproj b/src/System.Security.Cryptography.Cng/pkg/System.Security.Cryptography.Cng.pkgproj
index 149f0eaee0..83c04f6ad0 100644
--- a/src/System.Security.Cryptography.Cng/pkg/System.Security.Cryptography.Cng.pkgproj
+++ b/src/System.Security.Cryptography.Cng/pkg/System.Security.Cryptography.Cng.pkgproj
@@ -8,9 +8,10 @@
</ProjectReference>
<ProjectReference Include="..\src\System.Security.Cryptography.Cng.csproj" />
<File Include="$(PlaceHolderFile)">
- <TargetPath>runtimes/win/lib/$(UAPvNextTFM)</TargetPath>
+ <TargetPath>runtimes/win/lib/uap10.0.16299</TargetPath>
</File>
- <InboxOnTargetFramework Include="$(UAPvNextTFM)" />
+ <InboxOnTargetFramework Include="uap10.0.16299" />
+ <InboxOnTargetFramework Include="$(AllXamarinFrameworks)" />
<!-- All elements from previous packages that will be included in the newly built package -->
<HarvestIncludePaths Include="ref/net46;lib/net46;runtimes/win/lib/net46" />
<HarvestIncludePaths Include="ref/netstandard1.3" />
diff --git a/src/System.Security.Cryptography.Cng/ref/System.Security.Cryptography.Cng.ECDiffieHellman.cs b/src/System.Security.Cryptography.Cng/ref/System.Security.Cryptography.Cng.ECDiffieHellman.cs
new file mode 100644
index 0000000000..538bbe8b25
--- /dev/null
+++ b/src/System.Security.Cryptography.Cng/ref/System.Security.Cryptography.Cng.ECDiffieHellman.cs
@@ -0,0 +1,70 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ------------------------------------------------------------------------------
+// Changes to this file must follow the http://aka.ms/api-review process.
+// ------------------------------------------------------------------------------
+
+namespace System.Security.Cryptography
+{
+ public sealed partial class ECDiffieHellmanCng : System.Security.Cryptography.ECDiffieHellman
+ {
+ public ECDiffieHellmanCng() { }
+ public ECDiffieHellmanCng(int keySize) { }
+ public ECDiffieHellmanCng(CngKey key) { }
+#if FEATURE_ECPARAMETERS
+ public ECDiffieHellmanCng(System.Security.Cryptography.ECCurve curve) { }
+#endif
+ public System.Security.Cryptography.CngAlgorithm HashAlgorithm { get { throw null; } set { } }
+ public byte[] HmacKey { get { throw null; } set { } }
+ public System.Security.Cryptography.CngKey Key { get { throw null; } }
+ public System.Security.Cryptography.ECDiffieHellmanKeyDerivationFunction KeyDerivationFunction { get { throw null; } set { } }
+ public override int KeySize { get { throw null; } set { } }
+ public byte[] Label { get { throw null; } set { } }
+ public override System.Security.Cryptography.ECDiffieHellmanPublicKey PublicKey { get { throw null; } }
+ public byte[] SecretAppend { get { throw null; } set { } }
+ public byte[] SecretPrepend { get { throw null; } set { } }
+ public byte[] Seed { get { throw null; } set { } }
+ public bool UseSecretAgreementAsHmacKey { get { throw null; } }
+#if FEATURE_ECDH_DERIVEFROM
+ public override byte[] DeriveKeyFromHash(System.Security.Cryptography.ECDiffieHellmanPublicKey otherPartyPublicKey, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, byte[] secretPrepend, byte[] secretAppend) { throw null; }
+ public override byte[] DeriveKeyFromHmac(System.Security.Cryptography.ECDiffieHellmanPublicKey otherPartyPublicKey, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, byte[] hmacKey, byte[] secretPrepend, byte[] secretAppend) { throw null; }
+ public override byte[] DeriveKeyTls(System.Security.Cryptography.ECDiffieHellmanPublicKey otherPartyPublicKey, byte[] prfLabel, byte[] prfSeed) { throw null; }
+#endif
+ public byte[] DeriveKeyMaterial(System.Security.Cryptography.CngKey otherPartyPublicKey) { throw null; }
+ public override byte[] DeriveKeyMaterial(System.Security.Cryptography.ECDiffieHellmanPublicKey otherPartyPublicKey) { throw null; }
+ public Microsoft.Win32.SafeHandles.SafeNCryptSecretHandle DeriveSecretAgreementHandle(System.Security.Cryptography.CngKey otherPartyPublicKey) { throw null; }
+ public Microsoft.Win32.SafeHandles.SafeNCryptSecretHandle DeriveSecretAgreementHandle(System.Security.Cryptography.ECDiffieHellmanPublicKey otherPartyPublicKey) { throw null; }
+ protected override void Dispose(bool disposing) { }
+#if FEATURE_ECPARAMETERS
+ public override System.Security.Cryptography.ECParameters ExportExplicitParameters(bool includePrivateParameters) { throw null; }
+ public override System.Security.Cryptography.ECParameters ExportParameters(bool includePrivateParameters) { throw null; }
+#endif
+ public void FromXmlString(string xml, System.Security.Cryptography.ECKeyXmlFormat format) { }
+#if FEATURE_ECPARAMETERS
+ public override void GenerateKey(System.Security.Cryptography.ECCurve curve) { }
+ public override void ImportParameters(System.Security.Cryptography.ECParameters parameters) { }
+#endif
+ public string ToXmlString(System.Security.Cryptography.ECKeyXmlFormat format) { throw null; }
+ }
+ public sealed partial class ECDiffieHellmanCngPublicKey : System.Security.Cryptography.ECDiffieHellmanPublicKey
+ {
+ private ECDiffieHellmanCngPublicKey() : base(null) { }
+ public System.Security.Cryptography.CngKeyBlobFormat BlobFormat { get { throw null; } }
+ protected override void Dispose(bool disposing) { }
+#if FEATURE_ECPARAMETERS
+ public override System.Security.Cryptography.ECParameters ExportExplicitParameters() { throw null; }
+ public override System.Security.Cryptography.ECParameters ExportParameters() { throw null; }
+#endif
+ public static System.Security.Cryptography.ECDiffieHellmanPublicKey FromByteArray(byte[] publicKeyBlob, System.Security.Cryptography.CngKeyBlobFormat format) { throw null; }
+ public static System.Security.Cryptography.ECDiffieHellmanCngPublicKey FromXmlString(string xml) { throw null; }
+ public System.Security.Cryptography.CngKey Import() { throw null; }
+ public override string ToXmlString() { throw null; }
+ }
+ public enum ECDiffieHellmanKeyDerivationFunction
+ {
+ Hash = 0,
+ Hmac = 1,
+ Tls = 2,
+ }
+}
diff --git a/src/System.Security.Cryptography.Cng/ref/System.Security.Cryptography.Cng.cs b/src/System.Security.Cryptography.Cng/ref/System.Security.Cryptography.Cng.cs
index 1d6c944bf9..ce84ccec1d 100644
--- a/src/System.Security.Cryptography.Cng/ref/System.Security.Cryptography.Cng.cs
+++ b/src/System.Security.Cryptography.Cng/ref/System.Security.Cryptography.Cng.cs
@@ -265,7 +265,7 @@ namespace System.Security.Cryptography
public override string SignatureAlgorithm { get { throw null; } }
protected override void Dispose(bool disposing) { }
public override System.Security.Cryptography.DSAParameters ExportParameters(bool includePrivateParameters) { throw null; }
-#if FEATURE_HASHDATA // uap and netcoreapp specific
+#if FEATURE_DSA_HASHDATA
protected override byte[] HashData(byte[] data, int offset, int count, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; }
protected override byte[] HashData(System.IO.Stream data, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; }
#endif
diff --git a/src/System.Security.Cryptography.Cng/ref/System.Security.Cryptography.Cng.csproj b/src/System.Security.Cryptography.Cng/ref/System.Security.Cryptography.Cng.csproj
index dc15bd1da2..a54f705b1e 100644
--- a/src/System.Security.Cryptography.Cng/ref/System.Security.Cryptography.Cng.csproj
+++ b/src/System.Security.Cryptography.Cng/ref/System.Security.Cryptography.Cng.csproj
@@ -4,7 +4,10 @@
<PropertyGroup>
<DefineConstants Condition="'$(TargetGroup)' != 'netfx' AND '$(TargetGroup)' != 'net462'">$(DefineConstants);FEATURE_ECPARAMETERS</DefineConstants>
<ProjectGuid>{9FD12550-3A7C-49D3-9A1E-C4B7410989DD}</ProjectGuid>
- <DefineConstants Condition="'$(TargetGroup)' == 'uap' Or '$(TargeGroup)' == 'netcoreapp'">$(DefineConstants);FEATURE_HASHDATA</DefineConstants>
+ <!-- FEATURE_DSA_HASHDATA is technically also available on net462+, but it doesn't require being enabled since it is a facade -->
+ <DefineConstants Condition="'$(TargetGroup)' == 'uap' Or '$(TargetGroup)' == 'netcoreapp'">$(DefineConstants);FEATURE_DSA_HASHDATA</DefineConstants>
+ <!-- FEATURE_ECDH_DERIVEFROM is technically also available on net462+, but it doesn't require being enabled since it is a facade -->
+ <DefineConstants Condition="'$(TargetGroup)' == 'uap' Or '$(TargetGroup)' == 'netcoreapp'">$(DefineConstants);FEATURE_ECDH_DERIVEFROM</DefineConstants>
<IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'netfx' OR '$(TargetGroup)' == 'net462' OR '$(TargetGroup)' == 'net47'">true</IsPartialFacadeAssembly>
<!-- We must pin the netstandard2.0 version to match what was shipped in netcoreapp2.0
If we decided to add more Apis to that version of the library we need to also start
@@ -27,6 +30,9 @@
<ItemGroup>
<Compile Include="System.Security.Cryptography.Cng.cs" />
</ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)' != 'netstandard' AND '$(TargetGroup)' != 'netstandard1.3' AND '$(TargetGroup)' != 'netstandard1.4'">
+ <Compile Include="System.Security.Cryptography.Cng.ECDiffieHellman.cs" />
+ </ItemGroup>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' == 'true'">
<Reference Include="mscorlib" />
<Reference Include="System.Core" />
@@ -39,4 +45,4 @@
<ProjectReference Include="..\..\System.Security.Cryptography.Primitives\ref\System.Security.Cryptography.Primitives.csproj" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Security.Cryptography.Cng/src/Internal/Cryptography/CngAlgorithmCore.cs b/src/System.Security.Cryptography.Cng/src/Internal/Cryptography/CngAlgorithmCore.cs
index 08c1404c19..b6bf91efa4 100644
--- a/src/System.Security.Cryptography.Cng/src/Internal/Cryptography/CngAlgorithmCore.cs
+++ b/src/System.Security.Cryptography.Cng/src/Internal/Cryptography/CngAlgorithmCore.cs
@@ -15,6 +15,9 @@ namespace Internal.Cryptography
//
internal struct CngAlgorithmCore
{
+ public CngAlgorithm DefaultKeyType;
+ private CngKey _lazyKey;
+
public static CngKey Duplicate(CngKey key)
{
using (SafeNCryptKeyHandle keyHandle = key.Handle)
@@ -99,7 +102,7 @@ namespace Internal.Cryptography
try
{
- _lazyKey = CngKey.Create(CngAlgorithm.ECDsa, null, creationParameters);
+ _lazyKey = CngKey.Create(DefaultKeyType ?? CngAlgorithm.ECDsa, null, creationParameters);
}
catch (CryptographicException e)
{
@@ -131,7 +134,5 @@ namespace Internal.Cryptography
{
DisposeKey();
}
-
- private CngKey _lazyKey;
}
}
diff --git a/src/System.Security.Cryptography.Cng/src/Internal/Cryptography/KeyPropertyName.cs b/src/System.Security.Cryptography.Cng/src/Internal/Cryptography/KeyPropertyName.cs
index 7a49bf6bf4..75b7bac13b 100644
--- a/src/System.Security.Cryptography.Cng/src/Internal/Cryptography/KeyPropertyName.cs
+++ b/src/System.Security.Cryptography.Cng/src/Internal/Cryptography/KeyPropertyName.cs
@@ -15,6 +15,7 @@ namespace Internal.Cryptography
internal const string Algorithm = "Algorithm Name"; // NCRYPT_ALGORITHM_PROPERTY
internal const string AlgorithmGroup = "Algorithm Group"; // NCRYPT_ALGORITHM_GROUP_PROPERTY
internal const string ECCCurveName = "ECCCurveName"; // NCRYPT_ECC_CURVE_NAME
+ internal const string ECCParameters = "ECCParameters"; // BCRYPT_ECC_PARAMETERS
internal const string ExportPolicy = "Export Policy"; // NCRYPT_EXPORT_POLICY_PROPERTY
internal const string KeyType = "Key Type"; // NCRYPT_KEY_TYPE_PROPERTY
internal const string KeyUsage = "Key Usage"; // NCRYPT_KEY_USAGE_PROPERTY
diff --git a/src/System.Security.Cryptography.Cng/src/Resources/Strings.resx b/src/System.Security.Cryptography.Cng/src/Resources/Strings.resx
index b5c42a56c5..56d4860ad0 100644
--- a/src/System.Security.Cryptography.Cng/src/Resources/Strings.resx
+++ b/src/System.Security.Cryptography.Cng/src/Resources/Strings.resx
@@ -70,6 +70,18 @@
<data name="ArgumentNull_Buffer" xml:space="preserve">
<value>Buffer cannot be null.</value>
</data>
+ <data name="Cryptography_ArgECDHKeySizeMismatch" xml:space="preserve">
+ <value>The keys from both parties must be the same size to generate a secret agreement.</value>
+ </data>
+ <data name="Cryptography_ArgECDHRequiresECDHKey" xml:space="preserve">
+ <value>Keys used with the ECDiffieHellmanCng algorithm must have an algorithm group of ECDiffieHellman.</value>
+ </data>
+ <data name="Cryptography_ArgExpectedECDiffieHellmanCngPublicKey" xml:space="preserve">
+ <value>DeriveKeyMaterial requires an ECDiffieHellmanCngPublicKey.</value>
+ </data>
+ <data name="Cryptography_TlsRequiresLabelAndSeed" xml:space="preserve">
+ <value>The TLS key derivation function requires both the label and seed properties to be set.</value>
+ </data>
<data name="Cryptography_ArgDSARequiresDSAKey" xml:space="preserve">
<value>Keys used with the DSACng algorithm must have an algorithm group of DSA.</value>
</data>
@@ -82,6 +94,9 @@
<data name="Cryptography_CngKeyWrongAlgorithm" xml:space="preserve">
<value>This key is for algorithm '{0}'. Expected '{1}'.</value>
</data>
+ <data name="Cryptography_Encryption_MessageTooLong" xml:space="preserve">
+ <value>The message exceeds the maximum allowable length for the chosen options ({0}).</value>
+ </data>
<data name="Cryptography_HashAlgorithmNameNullOrEmpty" xml:space="preserve">
<value>The hash algorithm name cannot be null or empty.</value>
</data>
@@ -142,6 +157,9 @@
<data name="Cryptography_KeyBlobParsingError" xml:space="preserve">
<value>Key Blob not in expected format.</value>
</data>
+ <data name="Cryptography_KeyTooSmall" xml:space="preserve">
+ <value>The key is too small for the requested operation.</value>
+ </data>
<data name="Cryptography_OpenEphemeralKeyHandleWithoutEphemeralFlag" xml:space="preserve">
<value>The CNG key handle being opened was detected to be ephemeral, but the EphemeralKey open option was not specified.</value>
</data>
@@ -160,9 +178,18 @@
<data name="Cryptography_NotValidPublicOrPrivateKey" xml:space="preserve">
<value>Key is not a valid public or private key.</value>
</data>
+ <data name="Cryptography_OAEP_Decryption_Failed" xml:space="preserve">
+ <value>Error occurred while decoding OAEP padding.</value>
+ </data>
+ <data name="Cryptography_Padding_DecDataTooBig" xml:space="preserve">
+ <value>The data to be decrypted exceeds the maximum for this modulus of {0} bytes.</value>
+ </data>
<data name="Cryptography_PartialBlock" xml:space="preserve">
<value>The input data is not a complete block.</value>
</data>
+ <data name="Cryptography_SignHash_WrongSize" xml:space="preserve">
+ <value>The provided hash value is not the expected size for the specified hash algorithm.</value>
+ </data>
<data name="Cryptography_UnsupportedPaddingMode" xml:space="preserve">
<value>The specified PaddingMode is not supported.</value>
</data>
diff --git a/src/System.Security.Cryptography.Cng/src/System.Security.Cryptography.Cng.csproj b/src/System.Security.Cryptography.Cng/src/System.Security.Cryptography.Cng.csproj
index 2037845560..52fd7dff42 100644
--- a/src/System.Security.Cryptography.Cng/src/System.Security.Cryptography.Cng.csproj
+++ b/src/System.Security.Cryptography.Cng/src/System.Security.Cryptography.Cng.csproj
@@ -17,6 +17,14 @@
<AssemblyVersion Condition="'$(TargetGroup)' == 'netstandard1.4'">4.1.0.0</AssemblyVersion>
<AssemblyVersion Condition="'$(TargetGroup)' == 'netstandard'">4.3.0.0</AssemblyVersion>
</PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'net462-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'net462-Windows_NT-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'net47-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'net47-Windows_NT-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
@@ -25,14 +33,8 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.3-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.4-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.4-Release|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Release|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'net462-Windows_NT-Debug|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'net462-Windows_NT-Release|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'net47-Windows_NT-Debug|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'net47-Windows_NT-Release|AnyCPU'" />
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true' AND '$(TargetsWindows)' == 'true'">
<Compile Include="System\Security\Cryptography\AesCng.cs" />
<Compile Include="System\Security\Cryptography\CngAlgorithm.cs" />
@@ -65,6 +67,11 @@
<Compile Include="System\Security\Cryptography\DSACng.ImportExport.cs" />
<Compile Include="System\Security\Cryptography\DSACng.Key.cs" />
<Compile Include="System\Security\Cryptography\ECCng.ImportExport.cs" />
+ <Compile Include="System\Security\Cryptography\ECDiffieHellmanCng.cs" />
+ <Compile Include="System\Security\Cryptography\ECDiffieHellmanCng.Derive.cs" />
+ <Compile Include="System\Security\Cryptography\ECDiffieHellmanCng.Key.cs" />
+ <Compile Include="System\Security\Cryptography\ECDiffieHellmanCng.Xml.cs" />
+ <Compile Include="System\Security\Cryptography\ECDiffieHellmanCngPublicKey.cs" />
<Compile Include="System\Security\Cryptography\ECDsaCng.cs" />
<Compile Include="System\Security\Cryptography\ECDsaCng.Key.cs" />
<Compile Include="System\Security\Cryptography\ECKeyXmlFormat.cs" />
@@ -171,6 +178,15 @@
<Compile Include="$(CommonPath)\Interop\Windows\NCrypt\Interop.NCryptOpenStorageProvider.cs">
<Link>Internal\Windows\NCrypt\Interop.NCryptOpenStorageProvider.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\NCrypt\Interop.NCryptDeriveKeyMaterial.cs">
+ <Link>Internal\Windows\NCrypt\Interop.NCryptDeriveKeyMaterial.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\NCrypt\Interop.NCryptDeriveSecretAgreement.cs">
+ <Link>Internal\Windows\NCrypt\Interop.NCryptDeriveSecretAgreement.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\NCrypt\Interop.NCryptBuffer.cs">
+ <Link>Internal\Windows\NCrypt\Interop.NCryptBuffer.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\Interop\Windows\NCrypt\Interop.Properties.cs">
<Link>Internal\Windows\NCrypt\Interop.Properties.cs</Link>
</Compile>
@@ -240,6 +256,12 @@
<Compile Include="$(CommonPath)\System\Security\Cryptography\ECCng.ImportExport.cs">
<Link>Common\System\Security\Cryptography\ECCng.ImportExport.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\ECDiffieHellmanCng.cs">
+ <Link>Common\System\Security\Cryptography\ECDiffieHellmanCng.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\ECDiffieHellmanCng.ImportExport.cs">
+ <Link>Common\System\Security\Cryptography\ECDiffieHellmanCng.ImportExport.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\ECDsaCng.ImportExport.cs">
<Link>Common\System\Security\Cryptography\ECDsaCng.ImportExport.cs</Link>
</Compile>
@@ -267,6 +289,9 @@
<Compile Include="$(CommonPath)\System\Security\Cryptography\RSACng.SignVerify.cs">
<Link>Common\System\Security\Cryptography\RSACng.SignVerify.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\RsaPaddingProcessor.cs">
+ <Link>Common\System\Security\Cryptography\RsaPaddingProcessor.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' == 'true'">
<Reference Include="mscorlib" />
@@ -278,17 +303,21 @@
</ItemGroup>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true'">
<Reference Include="System.Buffers" />
+ <Reference Include="System.Collections" />
+ <Reference Include="System.Collections.Concurrent" />
<Reference Include="System.Diagnostics.Debug" />
<Reference Include="System.Diagnostics.Tools" />
<Reference Include="System.Memory" />
<Reference Include="System.Resources.ResourceManager" />
<Reference Include="System.Runtime" />
+ <Reference Include="System.Runtime.CompilerServices.Unsafe" />
<Reference Include="System.Runtime.Extensions" />
<Reference Include="System.Runtime.InteropServices" />
<Reference Include="System.Runtime.InteropServices.RuntimeInformation" />
<Reference Include="System.Security.Cryptography.Algorithms" />
<Reference Include="System.Security.Cryptography.Encoding" />
<Reference Include="System.Security.Cryptography.Primitives" />
+ <Reference Include="System.Threading" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/CngKey.EC.cs b/src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/CngKey.EC.cs
index 442c0e5e3e..6c44c8497c 100644
--- a/src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/CngKey.EC.cs
+++ b/src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/CngKey.EC.cs
@@ -5,6 +5,7 @@
using Internal.Cryptography;
using System.Diagnostics;
using BCRYPT_ECC_PARAMETER_HEADER = Interop.BCrypt.BCRYPT_ECC_PARAMETER_HEADER;
+using Internal.NativeCrypto;
namespace System.Security.Cryptography
{
@@ -100,5 +101,107 @@ namespace System.Security.Cryptography
// All other curves are new in Win10 so use generic algorithm
return CngAlgorithm.ECDsa;
}
+
+ /// <summary>
+ /// Map a curve name to algorithm. This enables curves that worked pre-Win10
+ /// to work with newer APIs for import and export.
+ /// </summary>
+ internal static CngAlgorithm EcdhCurveNameToAlgorithm(string name)
+ {
+ switch (name)
+ {
+ case "nistP256":
+ case "ECDH_P256":
+ return CngAlgorithm.ECDiffieHellmanP256;
+
+ case "nistP384":
+ case "ECDH_P384":
+ return CngAlgorithm.ECDiffieHellmanP384;
+
+ case "nistP521":
+ case "ECDH_P521":
+ return CngAlgorithm.ECDiffieHellmanP521;
+ }
+
+ // All other curves are new in Win10 so use generic algorithm
+ return CngAlgorithm.ECDiffieHellman;
+ }
+
+ internal static CngKey Create(ECCurve curve, Func<string, CngAlgorithm> algorithmResolver)
+ {
+ System.Diagnostics.Debug.Assert(algorithmResolver != null);
+
+ curve.Validate();
+
+ CngKeyCreationParameters creationParameters = new CngKeyCreationParameters
+ {
+ ExportPolicy = CngExportPolicies.AllowPlaintextExport,
+ };
+
+ CngAlgorithm alg;
+
+ if (curve.IsNamed)
+ {
+ if (string.IsNullOrEmpty(curve.Oid.FriendlyName))
+ throw new PlatformNotSupportedException(string.Format(SR.Cryptography_InvalidCurveOid, curve.Oid.Value));
+
+ // Map curve name to algorithm to support pre-Win10 curves
+ alg = algorithmResolver(curve.Oid.FriendlyName);
+
+ if (CngKey.IsECNamedCurve(alg.Algorithm))
+ {
+ creationParameters.Parameters.Add(GetPropertyFromNamedCurve(curve));
+ }
+ else
+ {
+ if (alg == CngAlgorithm.ECDsaP256 || alg == CngAlgorithm.ECDiffieHellmanP256 ||
+ alg == CngAlgorithm.ECDsaP384 || alg == CngAlgorithm.ECDiffieHellmanP384 ||
+ alg == CngAlgorithm.ECDsaP521 || alg == CngAlgorithm.ECDiffieHellmanP521)
+ {
+ // No parameters required, the algorithm ID has everything built-in.
+ }
+ else
+ {
+ Debug.Fail(string.Format("Unknown algorithm {0}", alg.ToString()));
+ throw new ArgumentException(SR.Cryptography_InvalidKeySize);
+ }
+ }
+ }
+ else if (curve.IsPrime)
+ {
+ byte[] parametersBlob = ECCng.GetPrimeCurveParameterBlob(ref curve);
+
+ CngProperty prop = new CngProperty(
+ KeyPropertyName.ECCParameters,
+ parametersBlob,
+ CngPropertyOptions.None);
+
+ creationParameters.Parameters.Add(prop);
+ alg = algorithmResolver(null);
+ }
+ else
+ {
+ throw new PlatformNotSupportedException(string.Format(SR.Cryptography_CurveNotSupported, curve.CurveType.ToString()));
+ }
+
+ try
+ {
+ return Create(alg, null, creationParameters);
+ }
+ catch (CryptographicException e)
+ {
+ Interop.NCrypt.ErrorCode errorCode = (Interop.NCrypt.ErrorCode)e.HResult;
+
+ if (errorCode == Interop.NCrypt.ErrorCode.NTE_INVALID_PARAMETER ||
+ errorCode == Interop.NCrypt.ErrorCode.NTE_NOT_SUPPORTED)
+ {
+ string target = curve.IsNamed ? curve.Oid.FriendlyName : curve.CurveType.ToString();
+ throw new PlatformNotSupportedException(string.Format(SR.Cryptography_CurveNotSupported, target), e);
+ }
+
+ throw;
+ }
+ }
+
}
}
diff --git a/src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/ECCng.ImportExport.cs b/src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/ECCng.ImportExport.cs
index 7296d98896..8c234e1721 100644
--- a/src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/ECCng.ImportExport.cs
+++ b/src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/ECCng.ImportExport.cs
@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using static Interop.BCrypt;
+
namespace System.Security.Cryptography
{
internal static partial class ECCng
@@ -35,5 +37,80 @@ namespace System.Security.Cryptography
CngKeyBlobFormat blobFormat = includePrivateParameters ? CngKeyBlobFormat.EccFullPrivateBlob : CngKeyBlobFormat.EccFullPublicBlob;
return key.Export(blobFormat);
}
+
+ internal static byte[] ExportKeyBlob(
+ CngKey key,
+ bool includePrivateParameters,
+ out CngKeyBlobFormat format,
+ out string curveName)
+ {
+ curveName = key.GetCurveName();
+ bool forceGenericBlob = false;
+
+ if (string.IsNullOrEmpty(curveName))
+ {
+ // Normalize curveName to null.
+ curveName = null;
+
+ forceGenericBlob = true;
+ format = includePrivateParameters ?
+ CngKeyBlobFormat.EccFullPrivateBlob :
+ CngKeyBlobFormat.EccFullPublicBlob;
+ }
+ else
+ {
+ format = includePrivateParameters ?
+ CngKeyBlobFormat.EccPrivateBlob :
+ CngKeyBlobFormat.EccPublicBlob;
+ }
+
+ byte[] blob = key.Export(format);
+
+ // Importing a known NIST curve as explicit parameters NCryptExportKey may
+ // cause it to export with the dwMagic of the known curve and a generic blob body.
+ // This combination can't be re-imported. So correct the dwMagic value to allow it
+ // to import.
+ if (forceGenericBlob)
+ {
+ FixupGenericBlob(blob);
+ }
+
+ return blob;
+ }
+
+ private static unsafe void FixupGenericBlob(byte[] blob)
+ {
+ if (blob.Length > sizeof(BCRYPT_ECCKEY_BLOB))
+ {
+ fixed (byte* pBlob = blob)
+ {
+ BCRYPT_ECCKEY_BLOB* pBcryptBlob = (BCRYPT_ECCKEY_BLOB*)pBlob;
+
+ switch ((KeyBlobMagicNumber)pBcryptBlob->Magic)
+ {
+ case KeyBlobMagicNumber.BCRYPT_ECDH_PUBLIC_P256_MAGIC:
+ case KeyBlobMagicNumber.BCRYPT_ECDH_PUBLIC_P384_MAGIC:
+ case KeyBlobMagicNumber.BCRYPT_ECDH_PUBLIC_P521_MAGIC:
+ pBcryptBlob->Magic = KeyBlobMagicNumber.BCRYPT_ECDH_PUBLIC_GENERIC_MAGIC;
+ break;
+ case KeyBlobMagicNumber.BCRYPT_ECDH_PRIVATE_P256_MAGIC:
+ case KeyBlobMagicNumber.BCRYPT_ECDH_PRIVATE_P384_MAGIC:
+ case KeyBlobMagicNumber.BCRYPT_ECDH_PRIVATE_P521_MAGIC:
+ pBcryptBlob->Magic = KeyBlobMagicNumber.BCRYPT_ECDH_PRIVATE_GENERIC_MAGIC;
+ break;
+ case KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_P256_MAGIC:
+ case KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_P384_MAGIC:
+ case KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_P521_MAGIC:
+ pBcryptBlob->Magic = KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_GENERIC_MAGIC;
+ break;
+ case KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_P256_MAGIC:
+ case KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_P384_MAGIC:
+ case KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_P521_MAGIC:
+ pBcryptBlob->Magic = KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_GENERIC_MAGIC;
+ break;
+ }
+ }
+ }
+ }
}
}
diff --git a/src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/ECDiffieHellmanCng.Derive.cs b/src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/ECDiffieHellmanCng.Derive.cs
new file mode 100644
index 0000000000..16d1b5b6e0
--- /dev/null
+++ b/src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/ECDiffieHellmanCng.Derive.cs
@@ -0,0 +1,143 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using Microsoft.Win32.SafeHandles;
+
+namespace System.Security.Cryptography
+{
+ public sealed partial class ECDiffieHellmanCng : ECDiffieHellman
+ {
+ public override byte[] DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey)
+ {
+ if (otherPartyPublicKey == null)
+ throw new ArgumentNullException(nameof(otherPartyPublicKey));
+
+ if (otherPartyPublicKey is ECDiffieHellmanCngPublicKey otherKey)
+ {
+ using (CngKey import = otherKey.Import())
+ {
+ return DeriveKeyMaterial(import);
+ }
+ }
+
+ // This deviates from the .NET Framework behavior. NetFx can't handle unknown public
+ // key types, but on .NET Core there are automatically two: the public class produced by
+ // this class' PublicKey member, and the private class produced by ECDiffieHellman.Create().PublicKey
+ //
+ // So let's just work.
+ ECParameters otherPartyParameters = otherPartyPublicKey.ExportParameters();
+
+ using (ECDiffieHellmanCng otherPartyCng = new ECDiffieHellmanCng())
+ {
+ otherPartyCng.ImportParameters(otherPartyParameters);
+
+ using (otherKey = (ECDiffieHellmanCngPublicKey)otherPartyCng.PublicKey)
+ using (CngKey importedKey = otherKey.Import())
+ {
+ return DeriveKeyMaterial(importedKey);
+ }
+ }
+ }
+
+ public byte[] DeriveKeyMaterial(CngKey otherPartyPublicKey)
+ {
+ if (otherPartyPublicKey == null)
+ throw new ArgumentNullException(nameof(otherPartyPublicKey));
+ if (otherPartyPublicKey.AlgorithmGroup != CngAlgorithmGroup.ECDiffieHellman)
+ throw new ArgumentException(SR.Cryptography_ArgECDHRequiresECDHKey, nameof(otherPartyPublicKey));
+ if (otherPartyPublicKey.KeySize != KeySize)
+ throw new ArgumentException(SR.Cryptography_ArgECDHKeySizeMismatch, nameof(otherPartyPublicKey));
+
+ // Setting the flag to UseSecretAsHmacKey even when the KDF isn't HMAC, because that's what NetFx does.
+ Interop.NCrypt.SecretAgreementFlags flags =
+ UseSecretAgreementAsHmacKey
+ ? Interop.NCrypt.SecretAgreementFlags.UseSecretAsHmacKey
+ : Interop.NCrypt.SecretAgreementFlags.None;
+
+ using (SafeNCryptSecretHandle handle = DeriveSecretAgreementHandle(otherPartyPublicKey))
+ {
+ switch (KeyDerivationFunction)
+ {
+ case ECDiffieHellmanKeyDerivationFunction.Hash:
+ return Interop.NCrypt.DeriveKeyMaterialHash(
+ handle,
+ HashAlgorithm.Algorithm,
+ _secretPrepend,
+ _secretAppend,
+ flags);
+ case ECDiffieHellmanKeyDerivationFunction.Hmac:
+ return Interop.NCrypt.DeriveKeyMaterialHmac(
+ handle,
+ HashAlgorithm.Algorithm,
+ _hmacKey,
+ _secretPrepend,
+ _secretAppend,
+ flags);
+ case ECDiffieHellmanKeyDerivationFunction.Tls:
+ if (_label == null || _seed == null)
+ {
+ throw new InvalidOperationException(SR.Cryptography_TlsRequiresLabelAndSeed);
+ }
+
+ return Interop.NCrypt.DeriveKeyMaterialTls(
+ handle,
+ _label,
+ _seed,
+ flags);
+ default:
+ Debug.Fail($"Unknown KDF ({KeyDerivationFunction})");
+ // Match NetFx behavior
+ goto case ECDiffieHellmanKeyDerivationFunction.Tls;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Get a handle to the secret agreement generated between two parties
+ /// </summary>
+ public SafeNCryptSecretHandle DeriveSecretAgreementHandle(ECDiffieHellmanPublicKey otherPartyPublicKey)
+ {
+ if (otherPartyPublicKey == null)
+ throw new ArgumentNullException(nameof(otherPartyPublicKey));
+
+ if (otherPartyPublicKey is ECDiffieHellmanCngPublicKey otherKey)
+ {
+ using (CngKey importedKey = otherKey.Import())
+ {
+ return DeriveSecretAgreementHandle(importedKey);
+ }
+ }
+
+ ECParameters otherPartyParameters = otherPartyPublicKey.ExportParameters();
+
+ using (ECDiffieHellmanCng otherPartyCng = (ECDiffieHellmanCng)Create(otherPartyParameters))
+ using (otherKey = (ECDiffieHellmanCngPublicKey)otherPartyCng.PublicKey)
+ using (CngKey importedKey = otherKey.Import())
+ {
+ return DeriveSecretAgreementHandle(importedKey);
+ }
+ }
+
+ /// <summary>
+ /// Get a handle to the secret agreement between two parties
+ /// </summary>
+ public SafeNCryptSecretHandle DeriveSecretAgreementHandle(CngKey otherPartyPublicKey)
+ {
+ if (otherPartyPublicKey == null)
+ throw new ArgumentNullException(nameof(otherPartyPublicKey));
+ if (otherPartyPublicKey.AlgorithmGroup != CngAlgorithmGroup.ECDiffieHellman)
+ throw new ArgumentException(SR.Cryptography_ArgECDHRequiresECDHKey, nameof(otherPartyPublicKey));
+ if (otherPartyPublicKey.KeySize != KeySize)
+ throw new ArgumentException(SR.Cryptography_ArgECDHKeySizeMismatch, nameof(otherPartyPublicKey));
+
+ // This looks strange, but the Handle property returns a duplicate so we need to dispose of it when we're done
+ using (SafeNCryptKeyHandle localHandle = Key.Handle)
+ using (SafeNCryptKeyHandle otherPartyHandle = otherPartyPublicKey.Handle)
+ {
+ return Interop.NCrypt.DeriveSecretAgreement(localHandle, otherPartyHandle);
+ }
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/ECDiffieHellmanCng.Key.cs b/src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/ECDiffieHellmanCng.Key.cs
new file mode 100644
index 0000000000..bcf4c70de2
--- /dev/null
+++ b/src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/ECDiffieHellmanCng.Key.cs
@@ -0,0 +1,137 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using Microsoft.Win32.SafeHandles;
+
+namespace System.Security.Cryptography
+{
+ public sealed partial class ECDiffieHellmanCng : ECDiffieHellman
+ {
+ /// <summary>
+ /// Public key used to generate key material with the second party
+ /// </summary>
+ public override ECDiffieHellmanPublicKey PublicKey
+ {
+ get
+ {
+ return ECDiffieHellmanCngPublicKey.FromKey(Key);
+ }
+ }
+
+ /// <summary>
+ /// Gets the key that will be used by the ECDH object for any cryptographic operation that it uses.
+ /// This key object will be disposed if the key is reset, for instance by changing the KeySize
+ /// property, using ImportParamers to create a new key, or by Disposing of the parent ECDH object.
+ /// Therefore, you should make sure that the key object is no longer used in these scenarios. This
+ /// object will not be the same object as the CngKey passed to the ECDHCng constructor if that
+ /// constructor was used, however it will point at the same CNG key.
+ /// </summary>
+ public CngKey Key
+ {
+ get
+ {
+ return GetKey();
+ }
+
+ private set
+ {
+ if (value == null)
+ throw new ArgumentNullException(nameof(value));
+ if (value.AlgorithmGroup != CngAlgorithmGroup.ECDiffieHellman)
+ throw new ArgumentException(SR.Cryptography_ArgECDHRequiresECDHKey, nameof(value));
+
+ _core.SetKey(value);
+
+ // LegalKeySizes stores the values for either the current named curve or for the three
+ // curves that use size instead of name
+ ForceSetKeySize(value.KeySize);
+ }
+ }
+
+ public override void GenerateKey(ECCurve curve)
+ {
+ curve.Validate();
+ _core.DisposeKey();
+
+ if (curve.IsNamed)
+ {
+ if (string.IsNullOrEmpty(curve.Oid.FriendlyName))
+ throw new PlatformNotSupportedException(string.Format(SR.Cryptography_InvalidCurveOid, curve.Oid.Value));
+
+ // Map curve name to algorithm to support pre-Win10 curves
+ CngAlgorithm alg = CngKey.EcdhCurveNameToAlgorithm(curve.Oid.FriendlyName);
+ if (CngKey.IsECNamedCurve(alg.Algorithm))
+ {
+ CngKey key = _core.GetOrGenerateKey(curve);
+ ForceSetKeySize(key.KeySize);
+ }
+ else
+ {
+ int keySize = 0;
+ // Get the proper KeySize from algorithm name
+ if (alg == CngAlgorithm.ECDiffieHellmanP256)
+ keySize = 256;
+ else if (alg == CngAlgorithm.ECDiffieHellmanP384)
+ keySize = 384;
+ else if (alg == CngAlgorithm.ECDiffieHellmanP521)
+ keySize = 521;
+ else
+ {
+ Debug.Fail(string.Format("Unknown algorithm {0}", alg.ToString()));
+ throw new ArgumentException(SR.Cryptography_InvalidKeySize);
+ }
+ CngKey key = _core.GetOrGenerateKey(keySize, alg);
+ ForceSetKeySize(keySize);
+ }
+ }
+ else if (curve.IsExplicit)
+ {
+ CngKey key = _core.GetOrGenerateKey(curve);
+ ForceSetKeySize(key.KeySize);
+ }
+ else
+ {
+ throw new PlatformNotSupportedException(string.Format(SR.Cryptography_CurveNotSupported, curve.CurveType.ToString()));
+ }
+ }
+
+ private CngKey GetKey()
+ {
+ CngKey key = null;
+
+ if (_core.IsKeyGeneratedNamedCurve())
+ {
+ // Curve was previously created, so use that
+ key = _core.GetOrGenerateKey(null);
+ }
+ else
+ {
+ CngAlgorithm algorithm = null;
+ int keySize = 0;
+
+ // Map the current key size to a CNG algorithm name
+ keySize = KeySize;
+ switch (keySize)
+ {
+ case 256:
+ algorithm = CngAlgorithm.ECDiffieHellmanP256;
+ break;
+ case 384:
+ algorithm = CngAlgorithm.ECDiffieHellmanP384;
+ break;
+ case 521:
+ algorithm = CngAlgorithm.ECDiffieHellmanP521;
+ break;
+ default:
+ Debug.Fail("Should not have invalid key size");
+ throw new ArgumentException(SR.Cryptography_InvalidKeySize);
+ }
+ key = _core.GetOrGenerateKey(keySize, algorithm);
+ }
+
+ return key;
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/ECDiffieHellmanCng.Xml.cs b/src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/ECDiffieHellmanCng.Xml.cs
new file mode 100644
index 0000000000..b78f35eb31
--- /dev/null
+++ b/src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/ECDiffieHellmanCng.Xml.cs
@@ -0,0 +1,19 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Security.Cryptography
+{
+ public sealed partial class ECDiffieHellmanCng : ECDiffieHellman
+ {
+ public void FromXmlString(string xml, ECKeyXmlFormat format)
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ public string ToXmlString(ECKeyXmlFormat format)
+ {
+ throw new PlatformNotSupportedException();
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/ECDiffieHellmanCng.cs b/src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/ECDiffieHellmanCng.cs
new file mode 100644
index 0000000000..e9ce655360
--- /dev/null
+++ b/src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/ECDiffieHellmanCng.cs
@@ -0,0 +1,174 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Internal.Cryptography;
+
+namespace System.Security.Cryptography
+{
+ /// <summary>
+ /// Key derivation functions used to transform the raw secret agreement into key material
+ /// </summary>
+ public enum ECDiffieHellmanKeyDerivationFunction
+ {
+ Hash,
+ Hmac,
+ Tls
+ }
+
+ /// <summary>
+ /// Wrapper for CNG's implementation of elliptic curve Diffie-Hellman key exchange
+ /// </summary>
+ public sealed partial class ECDiffieHellmanCng : ECDiffieHellman
+ {
+ private CngAlgorithmCore _core = new CngAlgorithmCore { DefaultKeyType = CngAlgorithm.ECDiffieHellman };
+ private CngAlgorithm _hashAlgorithm = CngAlgorithm.Sha256;
+ private ECDiffieHellmanKeyDerivationFunction _kdf = ECDiffieHellmanKeyDerivationFunction.Hash;
+ private byte[] _hmacKey;
+ private byte[] _label;
+ private byte[] _secretAppend;
+ private byte[] _secretPrepend;
+ private byte[] _seed;
+
+ public ECDiffieHellmanCng(CngKey key)
+ {
+ if (key == null)
+ throw new ArgumentNullException(nameof(key));
+
+ if (key.AlgorithmGroup != CngAlgorithmGroup.ECDiffieHellman)
+ throw new ArgumentException(SR.Cryptography_ArgECDHRequiresECDHKey, nameof(key));
+
+ Key = CngAlgorithmCore.Duplicate(key);
+ }
+
+ /// <summary>
+ /// Hash algorithm used with the Hash and HMAC KDFs
+ /// </summary>
+ public CngAlgorithm HashAlgorithm
+ {
+ get
+ {
+ return _hashAlgorithm;
+ }
+
+ set
+ {
+ if (_hashAlgorithm == null)
+ {
+ throw new ArgumentNullException("value");
+ }
+
+ _hashAlgorithm = value;
+ }
+ }
+
+ /// <summary>
+ /// KDF used to transform the secret agreement into key material
+ /// </summary>
+ public ECDiffieHellmanKeyDerivationFunction KeyDerivationFunction
+ {
+ get
+ {
+ return _kdf;
+ }
+
+ set
+ {
+ if (value < ECDiffieHellmanKeyDerivationFunction.Hash || value > ECDiffieHellmanKeyDerivationFunction.Tls)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
+ _kdf = value;
+ }
+ }
+
+ /// <summary>
+ /// Key used with the HMAC KDF
+ /// </summary>
+ public byte[] HmacKey
+ {
+ get { return _hmacKey; }
+ set { _hmacKey = value; }
+ }
+
+ /// <summary>
+ /// Label bytes used for the TLS KDF
+ /// </summary>
+ public byte[] Label
+ {
+ get { return _label; }
+ set { _label = value; }
+ }
+
+ /// <summary>
+ /// Bytes to append to the raw secret agreement before processing by the KDF
+ /// </summary>
+ public byte[] SecretAppend
+ {
+ get { return _secretAppend; }
+ set { _secretAppend = value; }
+ }
+
+ /// <summary>
+ /// Bytes to prepend to the raw secret agreement before processing by the KDF
+ /// </summary>
+ public byte[] SecretPrepend
+ {
+ get { return _secretPrepend; }
+ set { _secretPrepend = value; }
+ }
+
+ /// <summary>
+ /// Seed bytes used for the TLS KDF
+ /// </summary>
+ public byte[] Seed
+ {
+ get { return _seed; }
+ set { _seed = value; }
+ }
+
+ /// <summary>
+ /// Use the secret agreement as the HMAC key rather than supplying a seperate one
+ /// </summary>
+ public bool UseSecretAgreementAsHmacKey
+ {
+ get { return HmacKey == null; }
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ _core.Dispose();
+ }
+
+ private void DisposeKey()
+ {
+ _core.DisposeKey();
+ }
+
+ internal string GetCurveName()
+ {
+ return Key.GetCurveName();
+ }
+
+ private void ImportFullKeyBlob(byte[] ecfullKeyBlob, bool includePrivateParameters)
+ {
+ Key = ECCng.ImportFullKeyBlob(ecfullKeyBlob, includePrivateParameters);
+ }
+
+ private void ImportKeyBlob(byte[] ecfullKeyBlob, string curveName, bool includePrivateParameters)
+ {
+ Key = ECCng.ImportKeyBlob(ecfullKeyBlob, curveName, includePrivateParameters);
+ }
+
+ private byte[] ExportKeyBlob(bool includePrivateParameters)
+ {
+ return ECCng.ExportKeyBlob(Key, includePrivateParameters);
+ }
+
+ private byte[] ExportFullKeyBlob(bool includePrivateParameters)
+ {
+ return ECCng.ExportFullKeyBlob(Key, includePrivateParameters);
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/ECDiffieHellmanCngPublicKey.cs b/src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/ECDiffieHellmanCngPublicKey.cs
new file mode 100644
index 0000000000..36f9a2a168
--- /dev/null
+++ b/src/System.Security.Cryptography.Cng/src/System/Security/Cryptography/ECDiffieHellmanCngPublicKey.cs
@@ -0,0 +1,143 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Security.Cryptography
+{
+ /// <summary>
+ /// Public key used to do key exchange with the ECDiffieHellmanCng algorithm
+ /// </summary>
+ public sealed partial class ECDiffieHellmanCngPublicKey : ECDiffieHellmanPublicKey
+ {
+ private CngKeyBlobFormat _format;
+ private string _curveName;
+
+ /// <summary>
+ /// Wrap a CNG key
+ /// </summary>
+ internal ECDiffieHellmanCngPublicKey(byte[] keyBlob, string curveName, CngKeyBlobFormat format) : base(keyBlob)
+ {
+ _format = format;
+ // Can be null for P256, P384, P521, or an explicit blob
+ _curveName = curveName;
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+ }
+
+ public override string ToXmlString()
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ public static ECDiffieHellmanCngPublicKey FromXmlString(string xml)
+ {
+ throw new PlatformNotSupportedException();
+ }
+
+ /// <summary>
+ /// Format the key blob is expressed in
+ /// </summary>
+ public CngKeyBlobFormat BlobFormat
+ {
+ get
+ {
+ return _format;
+ }
+ }
+
+ /// <summary>
+ /// Hydrate a public key from a blob
+ /// </summary>
+ public static ECDiffieHellmanPublicKey FromByteArray(byte[] publicKeyBlob, CngKeyBlobFormat format)
+ {
+ if (publicKeyBlob == null)
+ throw new ArgumentNullException(nameof(publicKeyBlob));
+ if (format == null)
+ throw new ArgumentNullException(nameof(format));
+
+ // Verify that the key can import successfully, because we did in the past.
+ using (CngKey imported = CngKey.Import(publicKeyBlob, format))
+ {
+ if (imported.AlgorithmGroup != CngAlgorithmGroup.ECDiffieHellman)
+ {
+ throw new ArgumentException(SR.Cryptography_ArgECDHRequiresECDHKey);
+ }
+
+ return new ECDiffieHellmanCngPublicKey(publicKeyBlob, null, format);
+ }
+ }
+
+ internal static ECDiffieHellmanCngPublicKey FromKey(CngKey key)
+ {
+ CngKeyBlobFormat format;
+ string curveName;
+ byte[] blob = ECCng.ExportKeyBlob(key, false, out format, out curveName);
+ return new ECDiffieHellmanCngPublicKey(blob, curveName, format);
+ }
+
+ /// <summary>
+ /// Import the public key into CNG
+ /// </summary>
+ /// <returns></returns>
+ public CngKey Import()
+ {
+ return CngKey.Import(ToByteArray(), _curveName, BlobFormat);
+ }
+
+ /// <summary>
+ /// Exports the key and explicit curve parameters used by the ECC object into an <see cref="ECParameters"/> object.
+ /// </summary>
+ /// <exception cref="CryptographicException">
+ /// if there was an issue obtaining the curve values.
+ /// </exception>
+ /// <exception cref="PlatformNotSupportedException">
+ /// if explicit export is not supported by this platform. Windows 10 or higher is required.
+ /// </exception>
+ /// <returns>The key and explicit curve parameters used by the ECC object.</returns>
+ public override ECParameters ExportExplicitParameters()
+ {
+ using (CngKey key = Import())
+ {
+ ECParameters ecparams = new ECParameters();
+ byte[] blob = ECCng.ExportFullKeyBlob(key, includePrivateParameters: false);
+ ECCng.ExportPrimeCurveParameters(ref ecparams, blob, includePrivateParameters: false);
+ return ecparams;
+ }
+ }
+
+ /// <summary>
+ /// Exports the key used by the ECC object into an <see cref="ECParameters"/> object.
+ /// If the key was created as a named curve, the Curve property will contain named curve parameters
+ /// otherwise it will contain explicit parameters.
+ /// </summary>
+ /// <exception cref="CryptographicException">
+ /// if there was an issue obtaining the curve values.
+ /// </exception>
+ /// <returns>The key and named curve parameters used by the ECC object.</returns>
+ public override ECParameters ExportParameters()
+ {
+ using (CngKey key = Import())
+ {
+ ECParameters ecparams = new ECParameters();
+ string curveName = key.GetCurveName();
+
+ if (string.IsNullOrEmpty(curveName))
+ {
+ byte[] fullKeyBlob = ECCng.ExportFullKeyBlob(key, includePrivateParameters: false);
+ ECCng.ExportPrimeCurveParameters(ref ecparams, fullKeyBlob, includePrivateParameters: false);
+ }
+ else
+ {
+ byte[] keyBlob = ECCng.ExportKeyBlob(key, includePrivateParameters: false);
+ ECCng.ExportNamedCurveParameters(ref ecparams, keyBlob, includePrivateParameters: false);
+ ecparams.Curve = ECCurve.CreateFromFriendlyName(curveName);
+ }
+
+ return ecparams;
+ }
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Cng/tests/ECDiffieHellmanCngProvider.cs b/src/System.Security.Cryptography.Cng/tests/ECDiffieHellmanCngProvider.cs
new file mode 100644
index 0000000000..67c5d7b510
--- /dev/null
+++ b/src/System.Security.Cryptography.Cng/tests/ECDiffieHellmanCngProvider.cs
@@ -0,0 +1,63 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Security.Cryptography.EcDiffieHellman.Tests
+{
+ public class ECDiffieHellmanProvider : IECDiffieHellmanProvider
+ {
+ public ECDiffieHellman Create()
+ {
+ return new ECDiffieHellmanCng();
+ }
+
+ public ECDiffieHellman Create(int keySize)
+ {
+ return new ECDiffieHellmanCng(keySize);
+ }
+
+#if netcoreapp
+ public ECDiffieHellman Create(ECCurve curve)
+ {
+ return new ECDiffieHellmanCng(curve);
+ }
+#endif
+
+ public bool IsCurveValid(Oid oid)
+ {
+ // Friendly name required for windows
+ return NativeOidFriendlyNameExists(oid.FriendlyName);
+ }
+
+ public bool ExplicitCurvesSupported
+ {
+ get
+ {
+ return PlatformDetection.WindowsVersion >= 10;
+ }
+ }
+
+ private static bool NativeOidFriendlyNameExists(string oidFriendlyName)
+ {
+ if (string.IsNullOrEmpty(oidFriendlyName))
+ return false;
+
+ try
+ {
+ // By specifying OidGroup.PublicKeyAlgorithm, no caches are used
+ // Note: this throws when there is no oid value, even when friendly name is valid
+ // so it cannot be used for curves with no oid value such as curve25519
+ return !string.IsNullOrEmpty(Oid.FromFriendlyName(oidFriendlyName, OidGroup.PublicKeyAlgorithm).FriendlyName);
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+ }
+ }
+
+ public partial class ECDiffieHellmanFactory
+ {
+ private static readonly IECDiffieHellmanProvider s_provider = new ECDiffieHellmanProvider();
+ }
+}
diff --git a/src/System.Security.Cryptography.Cng/tests/ECDiffieHellmanCngTests.cs b/src/System.Security.Cryptography.Cng/tests/ECDiffieHellmanCngTests.cs
new file mode 100644
index 0000000000..e2197514b7
--- /dev/null
+++ b/src/System.Security.Cryptography.Cng/tests/ECDiffieHellmanCngTests.cs
@@ -0,0 +1,177 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using Xunit;
+
+namespace System.Security.Cryptography.EcDiffieHellman.Tests
+{
+ public partial class ECDiffieHellmanTests
+ {
+ private static ECDiffieHellmanCng NewDefaultECDHCng()
+ {
+ return new ECDiffieHellmanCng();
+ }
+
+#if netcoreapp
+ [Fact]
+ public static void ECCurve_ctor()
+ {
+ using (ECDiffieHellman ecdh = new ECDiffieHellmanCng(ECCurve.NamedCurves.nistP256))
+ {
+ Assert.Equal(256, ecdh.KeySize);
+ ecdh.Exercise();
+ }
+
+ using (ECDiffieHellman ecdh = new ECDiffieHellmanCng(ECCurve.NamedCurves.nistP384))
+ {
+ Assert.Equal(384, ecdh.KeySize);
+ ecdh.Exercise();
+ }
+
+ using (ECDiffieHellman ecdh = new ECDiffieHellmanCng(ECCurve.NamedCurves.nistP521))
+ {
+ Assert.Equal(521, ecdh.KeySize);
+ ecdh.Exercise();
+ }
+ }
+#endif
+
+ [Fact]
+ public static void CngKey_ReusesObject()
+ {
+ using (ECDiffieHellmanCng ecdh = NewDefaultECDHCng())
+ {
+ CngKey key1 = ecdh.Key;
+ CngKey key2 = ecdh.Key;
+
+ Assert.Same(key1, key2);
+ }
+ }
+
+ public static IEnumerable<object[]> HashEquivalenceData()
+ {
+ return new object[][]
+ {
+ new object[] { HashAlgorithmName.SHA256, false, false },
+ new object[] { HashAlgorithmName.SHA256, true, false },
+ new object[] { HashAlgorithmName.SHA256, false, true },
+ new object[] { HashAlgorithmName.SHA256, true, true },
+
+ new object[] { HashAlgorithmName.SHA384, false, false },
+ new object[] { HashAlgorithmName.SHA384, true, false },
+ new object[] { HashAlgorithmName.SHA384, false, true },
+ new object[] { HashAlgorithmName.SHA384, true, true },
+ };
+ }
+
+ [Theory]
+ [MemberData(nameof(HashEquivalenceData))]
+ public static void Equivalence_Hash(HashAlgorithmName algorithm, bool prepend, bool append)
+ {
+ using (ECDiffieHellmanCng ecdh = NewDefaultECDHCng())
+ using (ECDiffieHellmanPublicKey publicKey = ecdh.PublicKey)
+ {
+ byte[] secretPrepend = prepend ? new byte[3] : null;
+ byte[] secretAppend = append ? new byte[4] : null;
+
+ byte[] newWay = ecdh.DeriveKeyFromHash(publicKey, algorithm, secretPrepend, secretAppend);
+
+ ecdh.HashAlgorithm = new CngAlgorithm(algorithm.Name);
+ ecdh.SecretPrepend = secretPrepend;
+ ecdh.SecretAppend = secretAppend;
+ ecdh.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
+
+ byte[] oldWay = ecdh.DeriveKeyMaterial(publicKey);
+
+ Assert.Equal(newWay, oldWay);
+ }
+ }
+
+ public static IEnumerable<object[]> HmacEquivalenceData()
+ {
+ return new object[][]
+ {
+ new object[] { HashAlgorithmName.SHA256, false, false, false },
+ new object[] { HashAlgorithmName.SHA256, true, false, false },
+ new object[] { HashAlgorithmName.SHA256, false, false, true },
+ new object[] { HashAlgorithmName.SHA256, true, false, true },
+ new object[] { HashAlgorithmName.SHA256, false, true, false },
+ new object[] { HashAlgorithmName.SHA256, true, true, false },
+ new object[] { HashAlgorithmName.SHA256, false, true, true },
+ new object[] { HashAlgorithmName.SHA256, true, true, true },
+
+ new object[] { HashAlgorithmName.SHA384, false, false, false },
+ new object[] { HashAlgorithmName.SHA384, true, false, false },
+ new object[] { HashAlgorithmName.SHA384, false, false, true },
+ new object[] { HashAlgorithmName.SHA384, true, false, true },
+ new object[] { HashAlgorithmName.SHA384, false, true, false },
+ new object[] { HashAlgorithmName.SHA384, true, true, false },
+ new object[] { HashAlgorithmName.SHA384, false, true, true },
+ new object[] { HashAlgorithmName.SHA384, true, true, true },
+ };
+ }
+
+ [Theory]
+ [MemberData(nameof(HmacEquivalenceData))]
+ public static void Equivalence_Hmac(HashAlgorithmName algorithm, bool useSecretAgreementAsHmac, bool prepend, bool append)
+ {
+ using (ECDiffieHellmanCng ecdh = NewDefaultECDHCng())
+ using (ECDiffieHellmanPublicKey publicKey = ecdh.PublicKey)
+ {
+ byte[] secretPrepend = prepend ? new byte[3] : null;
+ byte[] secretAppend = append ? new byte[4] : null;
+ byte[] hmacKey = useSecretAgreementAsHmac ? null : new byte[12];
+
+ byte[] newWay = ecdh.DeriveKeyFromHmac(publicKey, algorithm, hmacKey, secretPrepend, secretAppend);
+
+ ecdh.HashAlgorithm = new CngAlgorithm(algorithm.Name);
+ ecdh.HmacKey = hmacKey;
+ ecdh.SecretPrepend = secretPrepend;
+ ecdh.SecretAppend = secretAppend;
+ ecdh.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hmac;
+
+ byte[] oldWay = ecdh.DeriveKeyMaterial(publicKey);
+
+ Assert.Equal(newWay, oldWay);
+ }
+ }
+
+ [Theory]
+ [InlineData(4)]
+ [InlineData(5)]
+ public static void Equivalence_TlsPrf(int labelSize)
+ {
+ using (ECDiffieHellmanCng ecdh = NewDefaultECDHCng())
+ using (ECDiffieHellmanPublicKey publicKey = ecdh.PublicKey)
+ {
+ byte[] label = new byte[labelSize];
+ byte[] seed = new byte[64];
+
+ byte[] newWay = ecdh.DeriveKeyTls(publicKey, label, seed);
+
+ ecdh.Label = label;
+ ecdh.Seed = seed;
+ ecdh.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Tls;
+
+ byte[] oldWay = ecdh.DeriveKeyMaterial(publicKey);
+
+ Assert.Equal(newWay, oldWay);
+ }
+ }
+
+ [Fact]
+ public static void HashDerivation_AlgorithmsCreateECDH()
+ {
+ using (ECDiffieHellman ecdhCng = new ECDiffieHellmanCng())
+ using (ECDiffieHellman ecdhAlgorithms = ECDiffieHellman.Create())
+ {
+ Assert.NotNull(ecdhAlgorithms.PublicKey);
+ byte[] outputCng = ecdhCng.DeriveKeyMaterial(ecdhAlgorithms.PublicKey);
+ byte[] outputAlgorithms = ecdhAlgorithms.DeriveKeyMaterial(ecdhCng.PublicKey);
+ Assert.Equal(outputCng, outputAlgorithms);
+ }
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Cng/tests/ECDsaCngImportExportTests.cs b/src/System.Security.Cryptography.Cng/tests/ECDsaCngImportExportTests.cs
index 303b3d1de6..cce7ca6e09 100644
--- a/src/System.Security.Cryptography.Cng/tests/ECDsaCngImportExportTests.cs
+++ b/src/System.Security.Cryptography.Cng/tests/ECDsaCngImportExportTests.cs
@@ -4,6 +4,7 @@
using Xunit;
using System.Security.Cryptography.EcDsa.Tests;
+using System.Security.Cryptography.Tests;
namespace System.Security.Cryptography.Cng.Tests
{
diff --git a/src/System.Security.Cryptography.Cng/tests/ECDsaCngTests.cs b/src/System.Security.Cryptography.Cng/tests/ECDsaCngTests.cs
index a2e924f295..e73d9abe27 100644
--- a/src/System.Security.Cryptography.Cng/tests/ECDsaCngTests.cs
+++ b/src/System.Security.Cryptography.Cng/tests/ECDsaCngTests.cs
@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Security.Cryptography.EcDsa.Tests;
+using System.Security.Cryptography.Tests;
using Test.Cryptography;
using Xunit;
@@ -19,7 +20,7 @@ namespace System.Security.Cryptography.Cng.Tests
byte[] tamperedSig = ("998791331eb2e1f4259297f5d9cb82fa20dec98e1cb0900e6b8f014a406c3d02cbdbf5238bde471c3155fc25565524301429"
+ "e8713dad9a67eb0a5c355e9e23dc").HexToByteArray();
- bool verified = e.VerifyHash(ECDsaTestData.s_hashSha512, tamperedSig);
+ bool verified = e.VerifyHash(EccTestData.s_hashSha512, tamperedSig);
Assert.False(verified);
}
@@ -31,7 +32,7 @@ namespace System.Security.Cryptography.Cng.Tests
byte[] sig = ("7805c494b17bba8cba09d3e5cdd16d69ce785e56c4f2d9d9061d549fce0a6860cca1cb9326bd534da21ad4ff326a1e0810d8"
+ "2366eb6afc66ede0d1ffe345f6b37ac622ed77838b42825ceb96cd3996d3d77fd6a248357ae1ae6cb85f048b1b04").HexToByteArray();
- bool verified = e.VerifyHash(ECDsaTestData.s_hashSha512, sig);
+ bool verified = e.VerifyHash(EccTestData.s_hashSha512, sig);
Assert.True(verified);
}
@@ -43,7 +44,7 @@ namespace System.Security.Cryptography.Cng.Tests
byte[] tamperedSig = ("7805c494b17bba8cba09d3e5cdd16d69ce785e56c4f2d9d9061d549fce0a6860cca1cb9326bd534da21ad4ff326a1e0810d8"
+ "f366eb6afc66ede0d1ffe345f6b37ac622ed77838b42825ceb96cd3996d3d77fd6a248357ae1ae6cb85f048b1b04").HexToByteArray();
- bool verified = e.VerifyHash(ECDsaTestData.s_hashSha512, tamperedSig);
+ bool verified = e.VerifyHash(EccTestData.s_hashSha512, tamperedSig);
Assert.False(verified);
}
@@ -56,7 +57,7 @@ namespace System.Security.Cryptography.Cng.Tests
byte[] sig = ("0084461450745672df85735fbf89f2dccef804d6b56e86ca45ea5c366a05a5de96327eddb75582821c6315c8bb823c875845"
+ "b6f25963ddab70461b786261507f971401fdc300697824129e0a84e0ba1ab4820ac7b29e7f8248bc2e29d152a9190eb3fcb7"
+ "6e8ebf1aa5dd28ffd582a24cbfebb3426a5f933ce1d995b31c951103d24f6256").HexToByteArray();
- bool verified = e.VerifyHash(ECDsaTestData.s_hashSha512, sig);
+ bool verified = e.VerifyHash(EccTestData.s_hashSha512, sig);
Assert.True(verified);
}
@@ -69,7 +70,7 @@ namespace System.Security.Cryptography.Cng.Tests
byte[] tamperedSig = ("0084461450745672df85735fbf89f2dccef804d6b56e86ca45ea5c366a05a5de96327eddb75582821c6315c8bb823c875845"
+ "a6f25963ddab70461b786261507f971401fdc300697824129e0a84e0ba1ab4820ac7b29e7f8248bc2e29d152a9190eb3fcb7"
+ "6e8ebf1aa5dd28ffd582a24cbfebb3426a5f933ce1d995b31c951103d24f6256").HexToByteArray();
- bool verified = e.VerifyHash(ECDsaTestData.s_hashSha512, tamperedSig);
+ bool verified = e.VerifyHash(EccTestData.s_hashSha512, tamperedSig);
Assert.False(verified);
}
diff --git a/src/System.Security.Cryptography.Cng/tests/RSACngProvider.cs b/src/System.Security.Cryptography.Cng/tests/RSACngProvider.cs
index 17a68f213c..64619b8346 100644
--- a/src/System.Security.Cryptography.Cng/tests/RSACngProvider.cs
+++ b/src/System.Security.Cryptography.Cng/tests/RSACngProvider.cs
@@ -32,6 +32,8 @@ namespace System.Security.Cryptography.Rsa.Tests
public bool SupportsSha2Oaep => true;
+ public bool SupportsPss => true;
+
public bool SupportsDecryptingIntoExactSpaceRequired => true;
}
diff --git a/src/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj b/src/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj
index cfd10b865d..09601d9435 100644
--- a/src/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj
+++ b/src/System.Security.Cryptography.Cng/tests/System.Security.Cryptography.Cng.Tests.csproj
@@ -54,6 +54,12 @@
<Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\EC\CurveDef.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\CurveDef.cs</Link>
</Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\EC\EccTestBase.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\EccTestBase.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\EC\EccTestData.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\EccTestData.cs</Link>
+ </Compile>
<Compile Include="ECDsaCngProvider.cs" />
<Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaFactory.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaFactory.cs</Link>
@@ -73,9 +79,6 @@
<Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaTests.NistValidation.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaTests.NistValidation.cs</Link>
</Compile>
- <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaTestData.cs">
- <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaTestData.cs</Link>
- </Compile>
<Compile Include="RSACngProvider.cs" />
<Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\RSA\EncryptDecrypt.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\EncryptDecrypt.cs</Link>
@@ -166,9 +169,35 @@
<Compile Condition="'$(TargetsWindows)' == 'true'" Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\AES\AesCipherTests.cs">
<Link>CommonTest\AlgorithmImplementations\AES\AesCipherTests.cs</Link>
</Compile>
+ <Compile Include="ECDiffieHellmanCngTests.cs" />
+ <Compile Include="ECDiffieHellmanCngProvider.cs" />
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanFactory.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanFactory.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Hash.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Hash.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Hmac.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Hmac.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.ImportExport.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.ImportExport.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.NistValidation.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.NistValidation.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Tls.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Tls.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Xml.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Xml.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\$(AssemblyName).rd.xml" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/CapiHelper.Windows.cs b/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/CapiHelper.Windows.cs
index b86d500bad..acb1e057a1 100644
--- a/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/CapiHelper.Windows.cs
+++ b/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/CapiHelper.Windows.cs
@@ -906,7 +906,9 @@ namespace Internal.NativeCrypto
// parameter specifies the size of the plaintext to encrypt.
if (!Interop.CryptEncrypt(safeKeyHandle, SafeHashHandle.InvalidHandle, true, dwEncryptFlags, pbEncryptedKey, ref cbKey, cbEncryptedKey))
{
+ throw GetErrorCode().ToCryptographicException();
}
+
Debug.Assert(cbKey == cbEncryptedKey);
Array.Reverse(pbEncryptedKey);
}
diff --git a/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/DSACryptoServiceProvider.Unix.cs b/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/DSACryptoServiceProvider.Unix.cs
index de89a083f0..6df350694f 100644
--- a/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/DSACryptoServiceProvider.Unix.cs
+++ b/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/DSACryptoServiceProvider.Unix.cs
@@ -50,8 +50,8 @@ namespace System.Security.Cryptography
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5351", Justification = "This is the implementation of DSACryptoServiceProvider")]
public override byte[] CreateSignature(byte[] rgbHash) => _impl.CreateSignature(rgbHash);
- public override bool TryCreateSignature(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten) =>
- _impl.TryCreateSignature(source, destination, out bytesWritten);
+ public override bool TryCreateSignature(ReadOnlySpan<byte> hash, Span<byte> destination, out int bytesWritten) =>
+ _impl.TryCreateSignature(hash, destination, out bytesWritten);
public CspKeyContainerInfo CspKeyContainerInfo
{
@@ -94,12 +94,12 @@ namespace System.Security.Cryptography
return AsymmetricAlgorithmHelpers.HashData(data, hashAlgorithm);
}
- protected override bool TryHashData(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten)
+ protected override bool TryHashData(ReadOnlySpan<byte> data, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten)
{
if (hashAlgorithm != HashAlgorithmName.SHA1)
throw new CryptographicException(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name);
- return AsymmetricAlgorithmHelpers.TryHashData(source, destination, hashAlgorithm, out bytesWritten);
+ return AsymmetricAlgorithmHelpers.TryHashData(data, destination, hashAlgorithm, out bytesWritten);
}
public void ImportCspBlob(byte[] keyBlob)
@@ -180,12 +180,12 @@ namespace System.Security.Cryptography
return _impl.SignData(data, hashAlgorithm);
}
- public override bool TrySignData(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten)
+ public override bool TrySignData(ReadOnlySpan<byte> data, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten)
{
if (hashAlgorithm != HashAlgorithmName.SHA1)
throw new CryptographicException(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name);
- return _impl.TrySignData(source, destination, hashAlgorithm, out bytesWritten);
+ return _impl.TrySignData(data, destination, hashAlgorithm, out bytesWritten);
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5351", Justification = "This is the implementation of DSACryptoServiceProvider")]
@@ -251,8 +251,8 @@ namespace System.Security.Cryptography
public override bool VerifySignature(byte[] rgbHash, byte[] rgbSignature) =>
_impl.VerifySignature(rgbHash, rgbSignature);
- public override bool VerifySignature(ReadOnlySpan<byte> rgbHash, ReadOnlySpan<byte> rgbSignature) =>
- _impl.VerifySignature(rgbHash, rgbSignature);
+ public override bool VerifySignature(ReadOnlySpan<byte> hash, ReadOnlySpan<byte> signature) =>
+ _impl.VerifySignature(hash, signature);
// UseMachineKeyStore has no effect in Unix
public static bool UseMachineKeyStore { get; set; }
diff --git a/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/RSACryptoServiceProvider.Unix.cs b/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/RSACryptoServiceProvider.Unix.cs
index 0d9a3bb81e..52b5bc68b3 100644
--- a/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/RSACryptoServiceProvider.Unix.cs
+++ b/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/RSACryptoServiceProvider.Unix.cs
@@ -61,16 +61,16 @@ namespace System.Security.Cryptography
throw PaddingModeNotSupported();
}
- public override bool TryDecrypt(ReadOnlySpan<byte> source, Span<byte> destination, RSAEncryptionPadding padding, out int bytesWritten)
+ public override bool TryDecrypt(ReadOnlySpan<byte> data, Span<byte> destination, RSAEncryptionPadding padding, out int bytesWritten)
{
if (padding == null)
throw new ArgumentNullException(nameof(padding));
- if (source.Length > (KeySize / 8))
+ if (data.Length > (KeySize / 8))
throw new CryptographicException(SR.Format(SR.Cryptography_Padding_DecDataTooBig, Convert.ToString(KeySize / 8)));
if (padding != RSAEncryptionPadding.Pkcs1 && padding != RSAEncryptionPadding.OaepSHA1)
throw PaddingModeNotSupported();
- return _impl.TryDecrypt(source, destination, padding, out bytesWritten);
+ return _impl.TryDecrypt(data, destination, padding, out bytesWritten);
}
protected override void Dispose(bool disposing)
@@ -103,14 +103,14 @@ namespace System.Security.Cryptography
throw PaddingModeNotSupported();
}
- public override bool TryEncrypt(ReadOnlySpan<byte> source, Span<byte> destination, RSAEncryptionPadding padding, out int bytesWritten)
+ public override bool TryEncrypt(ReadOnlySpan<byte> data, Span<byte> destination, RSAEncryptionPadding padding, out int bytesWritten)
{
if (padding == null)
throw new ArgumentNullException(nameof(padding));
if (padding != RSAEncryptionPadding.Pkcs1 && padding != RSAEncryptionPadding.OaepSHA1)
throw PaddingModeNotSupported();
- return _impl.TryEncrypt(source, destination, padding, out bytesWritten);
+ return _impl.TryEncrypt(data, destination, padding, out bytesWritten);
}
public byte[] ExportCspBlob(bool includePrivateParameters)
@@ -125,8 +125,8 @@ namespace System.Security.Cryptography
protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) =>
AsymmetricAlgorithmHelpers.HashData(data, offset, count, hashAlgorithm);
- protected override bool TryHashData(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) =>
- AsymmetricAlgorithmHelpers.TryHashData(source, destination, hashAlgorithm, out bytesWritten);
+ protected override bool TryHashData(ReadOnlySpan<byte> data, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten) =>
+ AsymmetricAlgorithmHelpers.TryHashData(data, destination, hashAlgorithm, out bytesWritten);
protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) =>
AsymmetricAlgorithmHelpers.HashData(data, hashAlgorithm);
@@ -170,13 +170,19 @@ namespace System.Security.Cryptography
public override string SignatureAlgorithm => "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
public override byte[] SignData(Stream data, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) =>
+ padding == null ? throw new ArgumentNullException(nameof(padding)) :
+ padding != RSASignaturePadding.Pkcs1 ? throw PaddingModeNotSupported() :
_impl.SignData(data, hashAlgorithm, padding);
public override byte[] SignData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) =>
+ padding == null ? throw new ArgumentNullException(nameof(padding)) :
+ padding != RSASignaturePadding.Pkcs1 ? throw PaddingModeNotSupported() :
_impl.SignData(data, offset, count, hashAlgorithm, padding);
- public override bool TrySignData(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding, out int bytesWritten) =>
- _impl.TrySignData(source, destination, hashAlgorithm, padding, out bytesWritten);
+ public override bool TrySignData(ReadOnlySpan<byte> data, Span<byte> destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding, out int bytesWritten) =>
+ padding == null ? throw new ArgumentNullException(nameof(padding)) :
+ padding != RSASignaturePadding.Pkcs1 ? throw PaddingModeNotSupported() :
+ _impl.TrySignData(data, destination, hashAlgorithm, padding, out bytesWritten);
public byte[] SignData(byte[] buffer, int offset, int count, object halg) =>
_impl.SignData(buffer, offset, count, HashAlgorithmNames.ObjToHashAlgorithmName(halg), RSASignaturePadding.Pkcs1);
@@ -188,10 +194,14 @@ namespace System.Security.Cryptography
_impl.SignData(inputStream, HashAlgorithmNames.ObjToHashAlgorithmName(halg), RSASignaturePadding.Pkcs1);
public override byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) =>
+ padding == null ? throw new ArgumentNullException(nameof(padding)) :
+ padding != RSASignaturePadding.Pkcs1 ? throw PaddingModeNotSupported() :
_impl.SignHash(hash, hashAlgorithm, padding);
- public override bool TrySignHash(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding, out int bytesWritten) =>
- _impl.TrySignHash(source, destination, hashAlgorithm, padding, out bytesWritten);
+ public override bool TrySignHash(ReadOnlySpan<byte> hash, Span<byte> destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding, out int bytesWritten) =>
+ padding == null ? throw new ArgumentNullException(nameof(padding)) :
+ padding != RSASignaturePadding.Pkcs1 ? throw PaddingModeNotSupported() :
+ _impl.TrySignHash(hash, destination, hashAlgorithm, padding, out bytesWritten);
public byte[] SignHash(byte[] rgbHash, string str)
{
@@ -210,9 +220,13 @@ namespace System.Security.Cryptography
_impl.VerifyData(buffer, signature, HashAlgorithmNames.ObjToHashAlgorithmName(halg), RSASignaturePadding.Pkcs1);
public override bool VerifyData(byte[] data, int offset, int count, byte[] signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) =>
+ padding == null ? throw new ArgumentNullException(nameof(padding)) :
+ padding != RSASignaturePadding.Pkcs1 ? throw PaddingModeNotSupported() :
_impl.VerifyData(data, offset, count, signature, hashAlgorithm, padding);
public override bool VerifyData(ReadOnlySpan<byte> data, ReadOnlySpan<byte> signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) =>
+ padding == null ? throw new ArgumentNullException(nameof(padding)) :
+ padding != RSASignaturePadding.Pkcs1 ? throw PaddingModeNotSupported() :
_impl.VerifyData(data, signature, hashAlgorithm, padding);
public override bool VerifyHash(byte[] hash, byte[] signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding)
diff --git a/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/RSACryptoServiceProvider.Windows.cs b/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/RSACryptoServiceProvider.Windows.cs
index e1493968f1..e1d75bd522 100644
--- a/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/RSACryptoServiceProvider.Windows.cs
+++ b/src/System.Security.Cryptography.Csp/src/System/Security/Cryptography/RSACryptoServiceProvider.Windows.cs
@@ -4,6 +4,7 @@
using System.Diagnostics;
using System.IO;
+using Internal.Cryptography;
using Internal.NativeCrypto;
using static Internal.NativeCrypto.CapiHelper;
@@ -316,6 +317,19 @@ namespace System.Security.Cryptography
throw new ArgumentNullException(nameof(rgb));
}
+ if (fOAEP)
+ {
+ int rsaSize = (KeySize + 7) / 8;
+ const int OaepSha1Overhead = 20 + 20 + 2;
+
+ // Normalize the Windows 7 and Windows 8.1+ exception
+ if (rsaSize - OaepSha1Overhead < rgb.Length)
+ {
+ const int NTE_BAD_LENGTH = unchecked((int)0x80090004);
+ throw NTE_BAD_LENGTH.ToCryptographicException();
+ }
+ }
+
byte[] encryptedKey = null;
CapiHelper.EncryptKey(SafeKeyHandle, rgb, rgb.Length, fOAEP, ref encryptedKey);
return encryptedKey;
diff --git a/src/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderProvider.cs b/src/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderProvider.cs
index f19a756c62..166c3f2489 100644
--- a/src/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderProvider.cs
+++ b/src/System.Security.Cryptography.Csp/tests/RSACryptoServiceProviderProvider.cs
@@ -16,6 +16,8 @@ namespace System.Security.Cryptography.Rsa.Tests
public bool SupportsSha2Oaep => false;
+ public bool SupportsPss => false;
+
public bool SupportsDecryptingIntoExactSpaceRequired => RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
}
diff --git a/src/System.Security.Cryptography.Encoding/src/System.Security.Cryptography.Encoding.csproj b/src/System.Security.Cryptography.Encoding/src/System.Security.Cryptography.Encoding.csproj
index 5ebbedf3e9..9681ef62e4 100644
--- a/src/System.Security.Cryptography.Encoding/src/System.Security.Cryptography.Encoding.csproj
+++ b/src/System.Security.Cryptography.Encoding/src/System.Security.Cryptography.Encoding.csproj
@@ -100,6 +100,7 @@
<Reference Include="System.Collections.Concurrent" />
<Reference Include="System.Diagnostics.Debug" />
<Reference Include="System.Linq" />
+ <Reference Include="System.Memory" />
<Reference Include="System.Resources.ResourceManager" />
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.Extensions" />
diff --git a/src/System.Security.Cryptography.Encoding/tests/Asn1/Reader/ParseTag.cs b/src/System.Security.Cryptography.Encoding/tests/Asn1/Reader/ParseTag.cs
index a9211778f1..33f268530d 100644
--- a/src/System.Security.Cryptography.Encoding/tests/Asn1/Reader/ParseTag.cs
+++ b/src/System.Security.Cryptography.Encoding/tests/Asn1/Reader/ParseTag.cs
@@ -69,7 +69,7 @@ namespace System.Security.Cryptography.Tests.Asn1
byte[] secondBytes = new byte[inputBytes.Length];
int written;
- Assert.False(tag.TryWrite(secondBytes.AsSpan().Slice(0, inputBytes.Length - 1), out written));
+ Assert.False(tag.TryWrite(secondBytes.AsSpan(0, inputBytes.Length - 1), out written));
Assert.Equal(0, written);
Assert.True(tag.TryWrite(secondBytes, out written));
Assert.Equal(inputBytes.Length, written);
diff --git a/src/System.Security.Cryptography.Encoding/tests/Asn1/Reader/ReadBMPString.cs b/src/System.Security.Cryptography.Encoding/tests/Asn1/Reader/ReadBMPString.cs
index 62b8439e0a..dbf647f48d 100644
--- a/src/System.Security.Cryptography.Encoding/tests/Asn1/Reader/ReadBMPString.cs
+++ b/src/System.Security.Cryptography.Encoding/tests/Asn1/Reader/ReadBMPString.cs
@@ -153,7 +153,7 @@ namespace System.Security.Cryptography.Tests.Asn1
output[0] = 'a';
copied = reader.TryCopyBMPString(
- output.AsSpan().Slice(0, expectedValue.Length - 1),
+ output.AsSpan(0, expectedValue.Length - 1),
out charsWritten);
Assert.False(copied, "reader.TryCopyBMPString - too short");
@@ -190,7 +190,7 @@ namespace System.Security.Cryptography.Tests.Asn1
{
output[0] = 32;
- copied = reader.TryCopyBMPStringBytes(output.AsSpan().Slice(0, output.Length - 1),
+ copied = reader.TryCopyBMPStringBytes(output.AsSpan(0, output.Length - 1),
out bytesWritten);
Assert.False(copied, "reader.TryCopyBMPStringBytes - too short");
diff --git a/src/System.Security.Cryptography.Encoding/tests/Asn1/Reader/ReadIA5String.cs b/src/System.Security.Cryptography.Encoding/tests/Asn1/Reader/ReadIA5String.cs
index 42dc62a77e..8a4e24f77b 100644
--- a/src/System.Security.Cryptography.Encoding/tests/Asn1/Reader/ReadIA5String.cs
+++ b/src/System.Security.Cryptography.Encoding/tests/Asn1/Reader/ReadIA5String.cs
@@ -148,7 +148,7 @@ namespace System.Security.Cryptography.Tests.Asn1
{
output[0] = 'a';
- copied = reader.TryCopyIA5String(output.AsSpan().Slice(0, expectedValue.Length - 1),
+ copied = reader.TryCopyIA5String(output.AsSpan(0, expectedValue.Length - 1),
out charsWritten);
Assert.False(copied, "reader.TryCopyIA5String - too short");
@@ -184,7 +184,7 @@ namespace System.Security.Cryptography.Tests.Asn1
{
output[0] = 32;
- copied = reader.TryCopyIA5StringBytes(output.AsSpan().Slice(0, output.Length - 1),
+ copied = reader.TryCopyIA5StringBytes(output.AsSpan(0, output.Length - 1),
out bytesWritten);
Assert.False(copied, "reader.TryCopyIA5StringBytes - too short");
diff --git a/src/System.Security.Cryptography.Encoding/tests/Asn1/Reader/ReadUTF8String.cs b/src/System.Security.Cryptography.Encoding/tests/Asn1/Reader/ReadUTF8String.cs
index 5ab1b6dc51..6348c987b5 100644
--- a/src/System.Security.Cryptography.Encoding/tests/Asn1/Reader/ReadUTF8String.cs
+++ b/src/System.Security.Cryptography.Encoding/tests/Asn1/Reader/ReadUTF8String.cs
@@ -154,7 +154,7 @@ namespace System.Security.Cryptography.Tests.Asn1
copied = reader.TryCopyCharacterString(
UniversalTagNumber.UTF8String,
- output.AsSpan().Slice(0, expectedValue.Length - 1),
+ output.AsSpan(0, expectedValue.Length - 1),
out charsWritten);
Assert.False(copied, "reader.TryCopyUTF8String - too short");
@@ -194,7 +194,7 @@ namespace System.Security.Cryptography.Tests.Asn1
copied = reader.TryCopyCharacterStringBytes(
UniversalTagNumber.UTF8String,
- output.AsSpan().Slice(0, output.Length - 1),
+ output.AsSpan(0, output.Length - 1),
out bytesWritten);
Assert.False(copied, "reader.TryCopyUTF8StringBytes - too short");
diff --git a/src/System.Security.Cryptography.Encoding/tests/Asn1/Serializer/SimpleDeserialize.cs b/src/System.Security.Cryptography.Encoding/tests/Asn1/Serializer/SimpleDeserialize.cs
index 6ca6a21036..1b19ddd670 100644
--- a/src/System.Security.Cryptography.Encoding/tests/Asn1/Serializer/SimpleDeserialize.cs
+++ b/src/System.Security.Cryptography.Encoding/tests/Asn1/Serializer/SimpleDeserialize.cs
@@ -442,7 +442,7 @@ namespace System.Security.Cryptography.Tests.Asn1
}
[Fact]
- public static void TooMuchData()
+ public static void TooMuchDataInValue()
{
// This is { IA5String("IA5"), UTF8String("UTF8") }, which is the opposite
// of the field order of OptionalValues. SO it will see the UTF8String as null,
@@ -452,6 +452,24 @@ namespace System.Security.Cryptography.Tests.Asn1
Assert.Throws<CryptographicException>(
() => AsnSerializer.Deserialize<OptionalValues>(inputData, AsnEncodingRules.BER));
}
+
+ [Fact]
+ public static void TooMuchDataForValue()
+ {
+ // Two empty sequences, which is more data than one OptionalValues value.
+ byte[] inputData = "30003000".HexToByteArray();
+
+ OptionalValues parsed = AsnSerializer.Deserialize<OptionalValues>(
+ inputData,
+ AsnEncodingRules.BER,
+ out int bytesRead);
+
+ Assert.NotNull(parsed);
+ Assert.Equal(2, bytesRead);
+
+ Assert.Throws<CryptographicException>(
+ () => AsnSerializer.Deserialize<OptionalValues>(inputData, AsnEncodingRules.BER));
+ }
}
// RFC 3280 / ITU-T X.509
diff --git a/src/System.Security.Cryptography.Encoding/tests/Asn1/Writer/Asn1WriterTests.cs b/src/System.Security.Cryptography.Encoding/tests/Asn1/Writer/Asn1WriterTests.cs
index 316eb28b59..3016af053f 100644
--- a/src/System.Security.Cryptography.Encoding/tests/Asn1/Writer/Asn1WriterTests.cs
+++ b/src/System.Security.Cryptography.Encoding/tests/Asn1/Writer/Asn1WriterTests.cs
@@ -20,13 +20,13 @@ namespace System.Security.Cryptography.Tests.Asn1
encoded2[0] = 255;
encoded2[encoded.Length] = 254;
- Span<byte> dest = encoded2.AsSpan().Slice(0, encoded.Length - 1);
+ Span<byte> dest = encoded2.AsSpan(0, encoded.Length - 1);
Assert.False(writer.TryEncode(dest, out int bytesWritten), "writer.TryEncode (too small)");
Assert.Equal(0, bytesWritten);
Assert.Equal(255, encoded2[0]);
Assert.Equal(254, encoded2[encoded.Length]);
- dest = encoded2.AsSpan().Slice(0, encoded.Length);
+ dest = encoded2.AsSpan(0, encoded.Length);
Assert.True(writer.TryEncode(dest, out bytesWritten), "writer.TryEncode (exact length)");
Assert.Equal(encoded.Length, bytesWritten);
Assert.True(dest.SequenceEqual(encoded), "dest.SequenceEqual(encoded2) (exact length)");
diff --git a/src/System.Security.Cryptography.Encoding/tests/Asn1/Writer/WriteCharacterString.cs b/src/System.Security.Cryptography.Encoding/tests/Asn1/Writer/WriteCharacterString.cs
index b158615e23..67584074d7 100644
--- a/src/System.Security.Cryptography.Encoding/tests/Asn1/Writer/WriteCharacterString.cs
+++ b/src/System.Security.Cryptography.Encoding/tests/Asn1/Writer/WriteCharacterString.cs
@@ -107,7 +107,7 @@ namespace System.Security.Cryptography.Tests.Asn1
{
using (AsnWriter writer = new AsnWriter(AsnEncodingRules.BER))
{
- WriteSpan(writer, input.AsReadOnlySpan());
+ WriteSpan(writer, input.AsSpan());
Verify(writer, Stringify(StandardTag) + expectedPayloadHex);
}
@@ -118,7 +118,7 @@ namespace System.Security.Cryptography.Tests.Asn1
using (AsnWriter writer = new AsnWriter(AsnEncodingRules.BER))
{
Asn1Tag tag = new Asn1Tag(TagClass.Private, int.MaxValue >> 1);
- WriteSpan(writer, tag, input.AsReadOnlySpan());
+ WriteSpan(writer, tag, input.AsSpan());
Verify(writer, Stringify(tag) + expectedPayloadHex);
}
@@ -128,7 +128,7 @@ namespace System.Security.Cryptography.Tests.Asn1
{
using (AsnWriter writer = new AsnWriter(AsnEncodingRules.BER))
{
- WriteSpan(writer, input.AsReadOnlySpan());
+ WriteSpan(writer, input.AsSpan());
Verify(writer, Stringify(StandardTag) + expectedPayloadHex);
}
@@ -139,7 +139,7 @@ namespace System.Security.Cryptography.Tests.Asn1
using (AsnWriter writer = new AsnWriter(AsnEncodingRules.BER))
{
Asn1Tag tag = new Asn1Tag(TagClass.Application, 30);
- WriteSpan(writer, tag, input.AsReadOnlySpan());
+ WriteSpan(writer, tag, input.AsSpan());
Verify(writer, Stringify(tag) + expectedPayloadHex);
}
@@ -149,7 +149,7 @@ namespace System.Security.Cryptography.Tests.Asn1
{
using (AsnWriter writer = new AsnWriter(AsnEncodingRules.BER))
{
- WriteSpan(writer, input.AsReadOnlySpan());
+ WriteSpan(writer, input.AsSpan());
Verify(writer, Stringify(StandardTag) + expectedPayloadHex);
}
@@ -160,7 +160,7 @@ namespace System.Security.Cryptography.Tests.Asn1
using (AsnWriter writer = new AsnWriter(AsnEncodingRules.BER))
{
Asn1Tag tag = new Asn1Tag(TagClass.ContextSpecific, 31);
- WriteSpan(writer, tag, input.AsReadOnlySpan());
+ WriteSpan(writer, tag, input.AsSpan());
Verify(writer, Stringify(tag) + expectedPayloadHex);
}
@@ -196,7 +196,7 @@ namespace System.Security.Cryptography.Tests.Asn1
{
Asn1Tag standard = StandardTag;
Asn1Tag tag = new Asn1Tag(standard.TagClass, standard.TagValue, isConstructed: true);
- WriteSpan(writer, tag, input.AsReadOnlySpan());
+ WriteSpan(writer, tag, input.AsSpan());
Verify(writer, Stringify(standard) + expectedPayloadHex);
}
@@ -208,7 +208,7 @@ namespace System.Security.Cryptography.Tests.Asn1
{
Asn1Tag tag = new Asn1Tag(TagClass.Private, 24601, isConstructed: true);
Asn1Tag expected = new Asn1Tag(tag.TagClass, tag.TagValue);
- WriteSpan(writer, tag, input.AsReadOnlySpan());
+ WriteSpan(writer, tag, input.AsSpan());
Verify(writer, Stringify(expected) + expectedPayloadHex);
}
@@ -244,7 +244,7 @@ namespace System.Security.Cryptography.Tests.Asn1
{
Asn1Tag standard = StandardTag;
Asn1Tag tag = new Asn1Tag(standard.TagClass, standard.TagValue, isConstructed: true);
- WriteSpan(writer, tag, input.AsReadOnlySpan());
+ WriteSpan(writer, tag, input.AsSpan());
Verify(writer, Stringify(standard) + expectedPayloadHex);
}
@@ -256,7 +256,7 @@ namespace System.Security.Cryptography.Tests.Asn1
{
Asn1Tag tag = new Asn1Tag(TagClass.Application, 11, isConstructed: true);
Asn1Tag expected = new Asn1Tag(tag.TagClass, tag.TagValue);
- WriteSpan(writer, tag, input.AsReadOnlySpan());
+ WriteSpan(writer, tag, input.AsSpan());
Verify(writer, Stringify(expected) + expectedPayloadHex);
}
@@ -292,7 +292,7 @@ namespace System.Security.Cryptography.Tests.Asn1
{
Asn1Tag standard = StandardTag;
Asn1Tag tag = new Asn1Tag(standard.TagClass, standard.TagValue, isConstructed: true);
- WriteSpan(writer, tag, input.AsReadOnlySpan());
+ WriteSpan(writer, tag, input.AsSpan());
Verify(writer, Stringify(standard) + expectedPayloadHex);
}
@@ -304,7 +304,7 @@ namespace System.Security.Cryptography.Tests.Asn1
{
Asn1Tag tag = new Asn1Tag(TagClass.Private, 24601, isConstructed: true);
Asn1Tag expected = new Asn1Tag(tag.TagClass, tag.TagValue);
- WriteSpan(writer, tag, input.AsReadOnlySpan());
+ WriteSpan(writer, tag, input.AsSpan());
Verify(writer, Stringify(expected) + expectedPayloadHex);
}
@@ -346,7 +346,7 @@ namespace System.Security.Cryptography.Tests.Asn1
{
AssertExtensions.Throws<ArgumentException>(
"tag",
- () => WriteSpan(writer, Asn1Tag.EndOfContents, "hi".AsReadOnlySpan()));
+ () => WriteSpan(writer, Asn1Tag.EndOfContents, "hi".AsSpan()));
}
}
@@ -436,7 +436,7 @@ namespace System.Security.Cryptography.Tests.Asn1
Asn1Tag tag = new Asn1Tag(standard.TagClass, standard.TagValue, true);
string tagHex = Stringify(tag);
- WriteSpan(writer, input.AsReadOnlySpan());
+ WriteSpan(writer, input.AsSpan());
VerifyWrite_CERSegmented(writer, tagHex, contentByteCount);
}
}
@@ -448,7 +448,7 @@ namespace System.Security.Cryptography.Tests.Asn1
Asn1Tag tag = new Asn1Tag(TagClass.Private, 7, true);
string tagHex = Stringify(tag);
- WriteSpan(writer, tag, input.AsReadOnlySpan());
+ WriteSpan(writer, tag, input.AsSpan());
VerifyWrite_CERSegmented(writer, tagHex, contentByteCount);
}
}
@@ -461,7 +461,7 @@ namespace System.Security.Cryptography.Tests.Asn1
Asn1Tag tag = new Asn1Tag(standard.TagClass, standard.TagValue, true);
string tagHex = Stringify(tag);
- WriteSpan(writer, tag, input.AsReadOnlySpan());
+ WriteSpan(writer, tag, input.AsSpan());
VerifyWrite_CERSegmented(writer, tagHex, contentByteCount);
}
}
@@ -474,7 +474,7 @@ namespace System.Security.Cryptography.Tests.Asn1
Asn1Tag constr = new Asn1Tag(prim.TagClass, prim.TagValue, true);
string tagHex = Stringify(constr);
- WriteSpan(writer, prim, input.AsReadOnlySpan());
+ WriteSpan(writer, prim, input.AsSpan());
VerifyWrite_CERSegmented(writer, tagHex, contentByteCount);
}
}
@@ -491,7 +491,7 @@ namespace System.Security.Cryptography.Tests.Asn1
{
using (AsnWriter writer = new AsnWriter(AsnEncodingRules.BER))
{
- Assert.Throws<EncoderFallbackException>(() => WriteSpan(writer, input.AsReadOnlySpan()));
+ Assert.Throws<EncoderFallbackException>(() => WriteSpan(writer, input.AsSpan()));
}
}
}
diff --git a/src/System.Security.Cryptography.Encoding/tests/Asn1/Writer/WriteObjectIdentifier.cs b/src/System.Security.Cryptography.Encoding/tests/Asn1/Writer/WriteObjectIdentifier.cs
index 5d480a0082..6b5722f090 100644
--- a/src/System.Security.Cryptography.Encoding/tests/Asn1/Writer/WriteObjectIdentifier.cs
+++ b/src/System.Security.Cryptography.Encoding/tests/Asn1/Writer/WriteObjectIdentifier.cs
@@ -34,7 +34,7 @@ namespace System.Security.Cryptography.Tests.Asn1
{
using (AsnWriter writer = new AsnWriter((AsnEncodingRules)ruleSet))
{
- writer.WriteObjectIdentifier(oidValue.AsReadOnlySpan());
+ writer.WriteObjectIdentifier(oidValue.AsSpan());
Verify(writer, expectedHex);
}
@@ -81,7 +81,7 @@ namespace System.Security.Cryptography.Tests.Asn1
using (AsnWriter writer = new AsnWriter((AsnEncodingRules)ruleSet))
{
Assert.Throws<CryptographicException>(
- () => writer.WriteObjectIdentifier(nonOidValue.AsReadOnlySpan()));
+ () => writer.WriteObjectIdentifier(nonOidValue.AsSpan()));
}
}
@@ -123,7 +123,7 @@ namespace System.Security.Cryptography.Tests.Asn1
{
using (AsnWriter writer = new AsnWriter((AsnEncodingRules)ruleSet))
{
- writer.WriteObjectIdentifier(new Asn1Tag(TagClass.Application, 2), "1.3.14.3.2.26".AsReadOnlySpan());
+ writer.WriteObjectIdentifier(new Asn1Tag(TagClass.Application, 2), "1.3.14.3.2.26".AsSpan());
Verify(writer, "42052B0E03021A");
}
@@ -206,7 +206,7 @@ namespace System.Security.Cryptography.Tests.Asn1
AssertExtensions.Throws<ArgumentException>(
"tag",
- () => writer.WriteObjectIdentifier(Asn1Tag.EndOfContents, "1.1".AsReadOnlySpan()));
+ () => writer.WriteObjectIdentifier(Asn1Tag.EndOfContents, "1.1".AsSpan()));
AssertExtensions.Throws<ArgumentException>(
"tag",
@@ -228,8 +228,8 @@ namespace System.Security.Cryptography.Tests.Asn1
writer.WriteObjectIdentifier(constructedOid, OidValue);
writer.WriteObjectIdentifier(constructedContext0, OidValue);
- writer.WriteObjectIdentifier(constructedOid, OidValue.AsReadOnlySpan());
- writer.WriteObjectIdentifier(constructedContext0, OidValue.AsReadOnlySpan());
+ writer.WriteObjectIdentifier(constructedOid, OidValue.AsSpan());
+ writer.WriteObjectIdentifier(constructedContext0, OidValue.AsSpan());
writer.WriteObjectIdentifier(constructedOid, new Oid(OidValue, OidValue));
writer.WriteObjectIdentifier(constructedContext0, new Oid(OidValue, OidValue));
diff --git a/src/System.Security.Cryptography.Encoding/tests/System.Security.Cryptography.Encoding.Tests.csproj b/src/System.Security.Cryptography.Encoding/tests/System.Security.Cryptography.Encoding.Tests.csproj
index e8d377c7e7..51ad291d9b 100644
--- a/src/System.Security.Cryptography.Encoding/tests/System.Security.Cryptography.Encoding.Tests.csproj
+++ b/src/System.Security.Cryptography.Encoding/tests/System.Security.Cryptography.Encoding.Tests.csproj
@@ -59,6 +59,7 @@
<Compile Include="DerSequenceReaderTests.cs" />
<Compile Include="Oid.cs" />
<Compile Include="OidCollectionTests.cs" />
+ <Compile Include="TestHelpers.cs" />
<Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1V2.cs">
<Link>Common\System\Security\Cryptography\Asn1V2.cs</Link>
</Compile>
diff --git a/src/System.Security.Cryptography.Encoding/tests/TestHelpers.cs b/src/System.Security.Cryptography.Encoding/tests/TestHelpers.cs
new file mode 100644
index 0000000000..5b9d84697a
--- /dev/null
+++ b/src/System.Security.Cryptography.Encoding/tests/TestHelpers.cs
@@ -0,0 +1,12 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System
+{
+ // @todo: https://github.com/dotnet/corefx/issues/26894 - these emulate MemoryExtension apis that we removed. Clean up the callsites and remove this class.
+ internal static class TestHelpers
+ {
+ public static ReadOnlySpan<T> AsReadOnlySpan<T>(this T[] array) => new ReadOnlySpan<T>(array);
+ }
+}
diff --git a/src/System.Security.Cryptography.OpenSsl/System.Security.Cryptography.OpenSsl.sln b/src/System.Security.Cryptography.OpenSsl/System.Security.Cryptography.OpenSsl.sln
index e4df70686f..d65193ffd2 100644
--- a/src/System.Security.Cryptography.OpenSsl/System.Security.Cryptography.OpenSsl.sln
+++ b/src/System.Security.Cryptography.OpenSsl/System.Security.Cryptography.OpenSsl.sln
@@ -30,10 +30,10 @@ Global
{E1DAF7B9-BECB-4D25-AABB-C9E0BC73C690}.Debug|Any CPU.Build.0 = netcoreapp-Unix-Debug|Any CPU
{E1DAF7B9-BECB-4D25-AABB-C9E0BC73C690}.Release|Any CPU.ActiveCfg = netcoreapp-Unix-Release|Any CPU
{E1DAF7B9-BECB-4D25-AABB-C9E0BC73C690}.Release|Any CPU.Build.0 = netcoreapp-Unix-Release|Any CPU
- {78452F3E-BA91-47E7-BB0F-02E8A5C116C4}.Debug|Any CPU.ActiveCfg = netstandard-Debug|Any CPU
- {78452F3E-BA91-47E7-BB0F-02E8A5C116C4}.Debug|Any CPU.Build.0 = netstandard-Debug|Any CPU
- {78452F3E-BA91-47E7-BB0F-02E8A5C116C4}.Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
- {78452F3E-BA91-47E7-BB0F-02E8A5C116C4}.Release|Any CPU.Build.0 = netstandard-Release|Any CPU
+ {78452F3E-BA91-47E7-BB0F-02E8A5C116C4}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
+ {78452F3E-BA91-47E7-BB0F-02E8A5C116C4}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
+ {78452F3E-BA91-47E7-BB0F-02E8A5C116C4}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
+ {78452F3E-BA91-47E7-BB0F-02E8A5C116C4}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
{8DEA82EF-2214-4295-8CC1-9FFB9B18838F}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
{8DEA82EF-2214-4295-8CC1-9FFB9B18838F}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
{8DEA82EF-2214-4295-8CC1-9FFB9B18838F}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
diff --git a/src/System.Security.Cryptography.OpenSsl/ref/System.Security.Cryptography.OpenSsl.cs b/src/System.Security.Cryptography.OpenSsl/ref/System.Security.Cryptography.OpenSsl.cs
index 7b36993625..87de271203 100644
--- a/src/System.Security.Cryptography.OpenSsl/ref/System.Security.Cryptography.OpenSsl.cs
+++ b/src/System.Security.Cryptography.OpenSsl/ref/System.Security.Cryptography.OpenSsl.cs
@@ -27,6 +27,26 @@ namespace System.Security.Cryptography
public override void ImportParameters(System.Security.Cryptography.DSAParameters parameters) { }
public override bool VerifySignature(byte[] rgbHash, byte[] rgbSignature) { throw null; }
}
+#if netcoreapp
+ public sealed partial class ECDiffieHellmanOpenSsl : System.Security.Cryptography.ECDiffieHellman
+ {
+ public ECDiffieHellmanOpenSsl() { }
+ public ECDiffieHellmanOpenSsl(int keySize) { }
+ public ECDiffieHellmanOpenSsl(System.IntPtr handle) { }
+ public ECDiffieHellmanOpenSsl(System.Security.Cryptography.ECCurve curve) { }
+ public ECDiffieHellmanOpenSsl(System.Security.Cryptography.SafeEvpPKeyHandle pkeyHandle) { }
+ public override System.Security.Cryptography.ECDiffieHellmanPublicKey PublicKey { get; }
+ public override byte[] DeriveKeyFromHash(System.Security.Cryptography.ECDiffieHellmanPublicKey otherPartyPublicKey, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, byte[] secretPrepend, byte[] secretAppend) { throw null; }
+ public override byte[] DeriveKeyFromHmac(System.Security.Cryptography.ECDiffieHellmanPublicKey otherPartyPublicKey, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, byte[] hmacKey, byte[] secretPrepend, byte[] secretAppend) { throw null; }
+ public override byte[] DeriveKeyMaterial(System.Security.Cryptography.ECDiffieHellmanPublicKey otherPartyPublicKey) { throw null; }
+ public override byte[] DeriveKeyTls(System.Security.Cryptography.ECDiffieHellmanPublicKey otherPartyPublicKey, byte[] prfLabel, byte[] prfSeed) { throw null; }
+ public System.Security.Cryptography.SafeEvpPKeyHandle DuplicateKeyHandle() { throw null; }
+ public override System.Security.Cryptography.ECParameters ExportExplicitParameters(bool includePrivateParameters) { throw null; }
+ public override System.Security.Cryptography.ECParameters ExportParameters(bool includePrivateParameters) { throw null; }
+ public override void GenerateKey(System.Security.Cryptography.ECCurve curve) { }
+ public override void ImportParameters(System.Security.Cryptography.ECParameters parameters) { }
+ }
+#endif
public sealed partial class ECDsaOpenSsl : System.Security.Cryptography.ECDsa
{
public ECDsaOpenSsl() { }
diff --git a/src/System.Security.Cryptography.OpenSsl/src/Resources/Strings.resx b/src/System.Security.Cryptography.OpenSsl/src/Resources/Strings.resx
index 477deffaf4..9a34c36634 100644
--- a/src/System.Security.Cryptography.OpenSsl/src/Resources/Strings.resx
+++ b/src/System.Security.Cryptography.OpenSsl/src/Resources/Strings.resx
@@ -126,9 +126,15 @@
<data name="Argument_InvalidValue" xml:space="preserve">
<value>Value was invalid.</value>
</data>
+ <data name="Cryptography_ArgECDHKeySizeMismatch" xml:space="preserve">
+ <value>The keys from both parties must be the same size to generate a secret agreement.</value>
+ </data>
<data name="Cryptography_CSP_NoPrivateKey" xml:space="preserve">
<value>Object contains only the public half of a key pair. A private key must also be provided.</value>
</data>
+ <data name="Cryptography_Encryption_MessageTooLong" xml:space="preserve">
+ <value>The message exceeds the maximum allowable length for the chosen options ({0}).</value>
+ </data>
<data name="Cryptography_HashAlgorithmNameNullOrEmpty" xml:space="preserve">
<value>The hash algorithm name cannot be null or empty.</value>
</data>
@@ -168,12 +174,27 @@
<data name="Cryptography_OpenInvalidHandle" xml:space="preserve">
<value>Cannot open an invalid handle.</value>
</data>
+ <data name="Cryptography_Padding_DecDataTooBig" xml:space="preserve">
+ <value>The data to be decrypted exceeds the maximum for this modulus of {0} bytes.</value>
+ </data>
+ <data name="Cryptography_TlsRequires64ByteSeed" xml:space="preserve">
+ <value>The TLS key derivation function requires a seed value of exactly 64 bytes.</value>
+ </data>
<data name="Cryptography_UnknownHashAlgorithm" xml:space="preserve">
<value>'{0}' is not a known hash algorithm.</value>
</data>
<data name="Cryptography_Invalid_IA5String" xml:space="preserve">
<value>The string contains a character not in the 7 bit ASCII character set.</value>
</data>
+ <data name="Cryptography_KeyTooSmall" xml:space="preserve">
+ <value>The key is too small for the requested operation.</value>
+ </data>
+ <data name="Cryptography_OAEP_Decryption_Failed" xml:space="preserve">
+ <value>Error occurred while decoding OAEP padding.</value>
+ </data>
+ <data name="Cryptography_SignHash_WrongSize" xml:space="preserve">
+ <value>The provided hash value is not the expected size for the specified hash algorithm.</value>
+ </data>
<data name="PlatformNotSupported_CryptographyOpenSSL" xml:space="preserve">
<value>OpenSSL is not supported on this platform.</value>
</data>
diff --git a/src/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj b/src/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj
index 736a7b7b9d..095d62bc6d 100644
--- a/src/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj
+++ b/src/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj
@@ -27,9 +27,9 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
<ItemGroup Condition="'$(TargetsUnix)' == 'true'">
<Compile Include="System\Security\Cryptography\DSAOpenSsl.cs" />
+ <Compile Include="System\Security\Cryptography\ECDiffieHellmanOpenSsl.cs" />
<Compile Include="System\Security\Cryptography\ECDsaOpenSsl.cs" />
<Compile Include="System\Security\Cryptography\RSAOpenSsl.cs" />
- <Compile Include="System\Security\Cryptography\SafeEvpPKeyHandle.Unix.cs" />
<Compile Include="$(CommonPath)\Internal\Cryptography\AsymmetricAlgorithmHelpers.Der.cs">
<Link>Common\Internal\Cryptography\AsymmetricAlgorithmHelpers.Der.cs</Link>
</Compile>
@@ -69,6 +69,9 @@
<Compile Include="$(CommonPath)\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.Dsa.cs">
<Link>Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.Dsa.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.Ecdh.cs">
+ <Link>Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.Ecdh.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.EcKey.cs">
<Link>Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.EcKey.cs</Link>
</Compile>
@@ -99,6 +102,12 @@
<Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeEcKeyHandle.Unix.cs">
<Link>Common\Microsoft\Win32\SafeHandles\SafeEcKeyHandle.Unix.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeEvpPkeyCtxHandle.Unix.cs">
+ <Link>Common\Microsoft\Win32\SafeHandles\SafeEvpPkeyCtxHandle.Unix.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeEvpPKeyHandle.Unix.cs">
+ <Link>Common\Microsoft\Win32\SafeHandles\SafeEvpPKeyHandle.Unix.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\DerEncoder.cs">
<Link>Common\System\Security\Cryptography\DerEncoder.cs</Link>
</Compile>
@@ -108,19 +117,38 @@
<Compile Include="$(CommonPath)\System\Security\Cryptography\DSAOpenSsl.cs">
<Link>Common\System\Security\Cryptography\DSAOpenSsl.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\ECDiffieHellmanDerivation.cs">
+ <Link>Common\System\Security\Cryptography\ECDiffieHellmanDerivation.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\ECDiffieHellmanOpenSsl.cs">
+ <Link>Common\System\Security\Cryptography\ECDiffieHellmanOpenSsl.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\ECDiffieHellmanOpenSsl.Derive.cs">
+ <Link>Common\System\Security\Cryptography\ECDiffieHellmanOpenSsl.Derive.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\ECDiffieHellmanOpenSslPublicKey.cs">
+ <Link>Common\System\Security\Cryptography\ECDiffieHellmanOpenSslPublicKey.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\ECDsaOpenSsl.cs">
<Link>Common\System\Security\Cryptography\ECDsaOpenSsl.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)\System\Security\Cryptography\ECDsaOpenSsl.ImportExport.cs">
- <Link>Common\System\Security\Cryptography\ECDsaOpenSsl.ImportExport.cs</Link>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\ECOpenSsl.cs">
+ <Link>Common\System\Security\Cryptography\ECOpenSsl.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\ECOpenSsl.ImportExport.cs">
+ <Link>Common\System\Security\Cryptography\ECOpenSsl.ImportExport.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\RSAOpenSsl.cs">
<Link>Common\System\Security\Cryptography\RSAOpenSsl.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\RsaPaddingProcessor.cs">
+ <Link>Common\System\Security\Cryptography\RsaPaddingProcessor.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp'">
<Reference Include="System.Buffers" />
<Reference Include="System.Collections" />
+ <Reference Include="System.Collections.Concurrent" />
<Reference Include="System.Diagnostics.Debug" />
<Reference Include="System.Diagnostics.Tools" />
<Reference Include="System.Memory" />
diff --git a/src/System.Security.Cryptography.OpenSsl/src/System/Security/Cryptography/ECDiffieHellmanOpenSsl.cs b/src/System.Security.Cryptography.OpenSsl/src/System/Security/Cryptography/ECDiffieHellmanOpenSsl.cs
new file mode 100644
index 0000000000..c5148ba08b
--- /dev/null
+++ b/src/System.Security.Cryptography.OpenSsl/src/System/Security/Cryptography/ECDiffieHellmanOpenSsl.cs
@@ -0,0 +1,88 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using Microsoft.Win32.SafeHandles;
+
+namespace System.Security.Cryptography
+{
+ public sealed partial class ECDiffieHellmanOpenSsl : ECDiffieHellman
+ {
+ /// <summary>
+ /// Create an ECDiffieHellmanOpenSsl from an <see cref="SafeEvpPKeyHandle"/> whose value is an existing
+ /// OpenSSL <c>EVP_PKEY*</c> wrapping an <c>EC_KEY*</c>
+ /// </summary>
+ /// <param name="pkeyHandle">A SafeHandle for an OpenSSL <c>EVP_PKEY*</c></param>
+ /// <exception cref="ArgumentNullException"><paramref name="pkeyHandle"/> is <c>null</c></exception>
+ /// <exception cref="ArgumentException"><paramref name="pkeyHandle"/> <see cref="SafeHandle.IsInvalid" /></exception>
+ /// <exception cref="CryptographicException"><paramref name="pkeyHandle"/> is not a valid enveloped <c>EC_KEY*</c></exception>
+ public ECDiffieHellmanOpenSsl(SafeEvpPKeyHandle pkeyHandle)
+ {
+ if (pkeyHandle == null)
+ throw new ArgumentNullException(nameof(pkeyHandle));
+ if (pkeyHandle.IsInvalid)
+ throw new ArgumentException(SR.Cryptography_OpenInvalidHandle, nameof(pkeyHandle));
+
+ // If ecKey is valid it has already been up-ref'd, so we can just use this handle as-is.
+ SafeEcKeyHandle key = Interop.Crypto.EvpPkeyGetEcKey(pkeyHandle);
+ if (key.IsInvalid)
+ {
+ key.Dispose();
+ throw Interop.Crypto.CreateOpenSslCryptographicException();
+ }
+
+ _key = new ECOpenSsl(key);
+ KeySizeValue = _key.KeySize;
+ }
+
+ /// <summary>
+ /// Create an ECDsaOpenSsl from an existing <see cref="IntPtr"/> whose value is an
+ /// existing OpenSSL <c>EC_KEY*</c>.
+ /// </summary>
+ /// <remarks>
+ /// This method will increase the reference count of the <c>EC_KEY*</c>, the caller should
+ /// continue to manage the lifetime of their reference.
+ /// </remarks>
+ /// <param name="handle">A pointer to an OpenSSL <c>EC_KEY*</c></param>
+ /// <exception cref="ArgumentException"><paramref name="handle" /> is invalid</exception>
+ public ECDiffieHellmanOpenSsl(IntPtr handle)
+ {
+ if (handle == IntPtr.Zero)
+ throw new ArgumentException(SR.Cryptography_OpenInvalidHandle, nameof(handle));
+
+ SafeEcKeyHandle ecKeyHandle = SafeEcKeyHandle.DuplicateHandle(handle);
+ _key = new ECOpenSsl(ecKeyHandle);
+ KeySizeValue = _key.KeySize;
+ }
+
+ /// <summary>
+ /// Obtain a SafeHandle version of an EVP_PKEY* which wraps an EC_KEY* equivalent
+ /// to the current key for this instance.
+ /// </summary>
+ /// <returns>A SafeHandle for the EC_KEY key in OpenSSL</returns>
+ public SafeEvpPKeyHandle DuplicateKeyHandle()
+ {
+ SafeEcKeyHandle currentKey = _key.Value;
+ SafeEvpPKeyHandle pkeyHandle = Interop.Crypto.EvpPkeyCreate();
+
+ try
+ {
+ // Wrapping our key in an EVP_PKEY will up_ref our key.
+ // When the EVP_PKEY is Disposed it will down_ref the key.
+ // So everything should be copacetic.
+ if (!Interop.Crypto.EvpPkeySetEcKey(pkeyHandle, currentKey))
+ {
+ throw Interop.Crypto.CreateOpenSslCryptographicException();
+ }
+
+ return pkeyHandle;
+ }
+ catch
+ {
+ pkeyHandle.Dispose();
+ throw;
+ }
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.OpenSsl/src/System/Security/Cryptography/ECDsaOpenSsl.cs b/src/System.Security.Cryptography.OpenSsl/src/System/Security/Cryptography/ECDsaOpenSsl.cs
index 282b278fa4..d997f10ef2 100644
--- a/src/System.Security.Cryptography.OpenSsl/src/System/Security/Cryptography/ECDsaOpenSsl.cs
+++ b/src/System.Security.Cryptography.OpenSsl/src/System/Security/Cryptography/ECDsaOpenSsl.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
namespace System.Security.Cryptography
@@ -31,7 +32,8 @@ namespace System.Security.Cryptography
throw Interop.Crypto.CreateOpenSslCryptographicException();
}
- SetKey(key);
+ _key = new ECOpenSsl(key);
+ KeySizeValue = _key.KeySize;
}
/// <summary>
@@ -50,7 +52,8 @@ namespace System.Security.Cryptography
throw new ArgumentException(SR.Cryptography_OpenInvalidHandle, nameof(handle));
SafeEcKeyHandle ecKeyHandle = SafeEcKeyHandle.DuplicateHandle(handle);
- SetKey(ecKeyHandle);
+ _key = new ECOpenSsl(ecKeyHandle);
+ KeySizeValue = _key.KeySize;
}
/// <summary>
diff --git a/src/System.Security.Cryptography.OpenSsl/tests/EcDiffieHellmanOpenSslProvider.cs b/src/System.Security.Cryptography.OpenSsl/tests/EcDiffieHellmanOpenSslProvider.cs
new file mode 100644
index 0000000000..c48882553f
--- /dev/null
+++ b/src/System.Security.Cryptography.OpenSsl/tests/EcDiffieHellmanOpenSslProvider.cs
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Security.Cryptography.EcDiffieHellman.Tests
+{
+ public partial class ECDiffieHellmanProvider : IECDiffieHellmanProvider
+ {
+ private EcDsa.Tests.ECDsaProvider _ecdsaProvider = new EcDsa.Tests.ECDsaProvider();
+
+ public ECDiffieHellman Create()
+ {
+ return new ECDiffieHellmanOpenSsl();
+ }
+
+ public ECDiffieHellman Create(int keySize)
+ {
+ return new ECDiffieHellmanOpenSsl(keySize);
+ }
+
+ public ECDiffieHellman Create(ECCurve curve)
+ {
+ return new ECDiffieHellmanOpenSsl(curve);
+ }
+
+ public bool IsCurveValid(Oid oid) => _ecdsaProvider.IsCurveValid(oid);
+
+ public bool ExplicitCurvesSupported => _ecdsaProvider.ExplicitCurvesSupported;
+ }
+
+ public partial class ECDiffieHellmanFactory
+ {
+ private static readonly IECDiffieHellmanProvider s_provider = new ECDiffieHellmanProvider();
+ }
+}
+
diff --git a/src/System.Security.Cryptography.OpenSsl/tests/EcDiffieHellmanOpenSslTests.cs b/src/System.Security.Cryptography.OpenSsl/tests/EcDiffieHellmanOpenSslTests.cs
new file mode 100644
index 0000000000..0cf5e48514
--- /dev/null
+++ b/src/System.Security.Cryptography.OpenSsl/tests/EcDiffieHellmanOpenSslTests.cs
@@ -0,0 +1,283 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Security.Cryptography.EcDiffieHellman.Tests;
+using Test.Cryptography;
+using Xunit;
+
+namespace System.Security.Cryptography.EcDiffieHellman.OpenSsl.Tests
+{
+ public class EcDiffieHellmanOpenSslTests : ECDiffieHellmanTests
+ {
+ [Fact]
+ public void DefaultCtor()
+ {
+ using (var e = new ECDiffieHellmanOpenSsl())
+ {
+ int keySize = e.KeySize;
+ Assert.Equal(521, keySize);
+ e.Exercise();
+ }
+ }
+
+ [Fact]
+ public void Ctor256()
+ {
+ int expectedKeySize = 256;
+ using (var e = new ECDiffieHellmanOpenSsl(expectedKeySize))
+ {
+ int keySize = e.KeySize;
+ Assert.Equal(expectedKeySize, keySize);
+ e.Exercise();
+ }
+ }
+
+ [Fact]
+ public void Ctor384()
+ {
+ int expectedKeySize = 384;
+ using (var e = new ECDiffieHellmanOpenSsl(expectedKeySize))
+ {
+ int keySize = e.KeySize;
+ Assert.Equal(expectedKeySize, keySize);
+ e.Exercise();
+ }
+ }
+
+ [Fact]
+ public void Ctor521()
+ {
+ int expectedKeySize = 521;
+ using (var e = new ECDiffieHellmanOpenSsl(expectedKeySize))
+ {
+ int keySize = e.KeySize;
+ Assert.Equal(expectedKeySize, keySize);
+ e.Exercise();
+ }
+ }
+
+ [ConditionalFact(nameof(ECDsa224Available))]
+ public void CtorHandle224()
+ {
+ IntPtr ecKey = Interop.Crypto.EcKeyCreateByOid(ECDSA_P224_OID_VALUE);
+ Assert.NotEqual(IntPtr.Zero, ecKey);
+ int success = Interop.Crypto.EcKeyGenerateKey(ecKey);
+ Assert.NotEqual(0, success);
+
+ using (var e = new ECDiffieHellmanOpenSsl(ecKey))
+ {
+ int keySize = e.KeySize;
+ Assert.Equal(224, keySize);
+ e.Exercise();
+ }
+
+ Interop.Crypto.EcKeyDestroy(ecKey);
+ }
+
+ [Fact]
+ public void CtorHandle384()
+ {
+ IntPtr ecKey = Interop.Crypto.EcKeyCreateByOid(ECDSA_P384_OID_VALUE);
+ Assert.NotEqual(IntPtr.Zero, ecKey);
+ int success = Interop.Crypto.EcKeyGenerateKey(ecKey);
+ Assert.NotEqual(0, success);
+
+ using (var e = new ECDiffieHellmanOpenSsl(ecKey))
+ {
+ int keySize = e.KeySize;
+ Assert.Equal(384, keySize);
+ e.Exercise();
+ }
+
+ Interop.Crypto.EcKeyDestroy(ecKey);
+ }
+
+ [Fact]
+ public void CtorHandle521()
+ {
+ IntPtr ecKey = Interop.Crypto.EcKeyCreateByOid(ECDSA_P521_OID_VALUE);
+ Assert.NotEqual(IntPtr.Zero, ecKey);
+ int success = Interop.Crypto.EcKeyGenerateKey(ecKey);
+ Assert.NotEqual(0, success);
+
+ using (var e = new ECDiffieHellmanOpenSsl(ecKey))
+ {
+ int keySize = e.KeySize;
+ Assert.Equal(521, keySize);
+ e.Exercise();
+ }
+
+ Interop.Crypto.EcKeyDestroy(ecKey);
+ }
+
+ [Fact]
+ public void CtorHandleDuplicate()
+ {
+ IntPtr ecKey = Interop.Crypto.EcKeyCreateByOid(ECDSA_P521_OID_VALUE);
+ Assert.NotEqual(IntPtr.Zero, ecKey);
+ int success = Interop.Crypto.EcKeyGenerateKey(ecKey);
+ Assert.NotEqual(0, success);
+
+ using (var e = new ECDiffieHellmanOpenSsl(ecKey))
+ {
+ // Make sure ECDsaOpenSsl did his own ref-count bump.
+ Interop.Crypto.EcKeyDestroy(ecKey);
+
+ int keySize = e.KeySize;
+ Assert.Equal(521, keySize);
+ e.Exercise();
+ }
+ }
+
+ [Fact]
+ public void KeySizePropWithExercise()
+ {
+ using (var e = new ECDiffieHellmanOpenSsl())
+ {
+ e.KeySize = 384;
+ Assert.Equal(384, e.KeySize);
+ e.Exercise();
+ ECParameters p384 = e.ExportParameters(false);
+ Assert.Equal(ECCurve.ECCurveType.Named, p384.Curve.CurveType);
+
+ e.KeySize = 521;
+ Assert.Equal(521, e.KeySize);
+ e.Exercise();
+ ECParameters p521 = e.ExportParameters(false);
+ Assert.Equal(ECCurve.ECCurveType.Named, p521.Curve.CurveType);
+
+ // ensure the key was regenerated
+ Assert.NotEqual(p384.Curve.Oid.Value, p521.Curve.Oid.Value);
+ }
+ }
+
+ [Fact]
+ public void VerifyDuplicateKey_ValidHandle()
+ {
+ using (var first = new ECDiffieHellmanOpenSsl())
+ using (SafeEvpPKeyHandle firstHandle = first.DuplicateKeyHandle())
+ using (ECDiffieHellman second = new ECDiffieHellmanOpenSsl(firstHandle))
+ using (ECDiffieHellmanPublicKey firstPublic = first.PublicKey)
+ using (ECDiffieHellmanPublicKey secondPublic = second.PublicKey)
+ {
+ byte[] firstSecond = first.DeriveKeyFromHash(secondPublic, HashAlgorithmName.SHA256);
+ byte[] secondFirst = second.DeriveKeyFromHash(firstPublic, HashAlgorithmName.SHA256);
+ byte[] firstFirst = first.DeriveKeyFromHash(firstPublic, HashAlgorithmName.SHA256);
+
+ Assert.Equal(firstSecond, secondFirst);
+ Assert.Equal(firstFirst, firstSecond);
+ }
+ }
+
+ [Fact]
+ public void VerifyDuplicateKey_DistinctHandles()
+ {
+ using (var first = new ECDiffieHellmanOpenSsl())
+ using (SafeEvpPKeyHandle firstHandle = first.DuplicateKeyHandle())
+ using (SafeEvpPKeyHandle firstHandle2 = first.DuplicateKeyHandle())
+ {
+ Assert.NotSame(firstHandle, firstHandle2);
+ }
+ }
+
+ [Fact]
+ public void VerifyDuplicateKey_RefCounts()
+ {
+ byte[] derived;
+ ECDiffieHellman second;
+
+ using (var first = new ECDiffieHellmanOpenSsl())
+ using (SafeEvpPKeyHandle firstHandle = first.DuplicateKeyHandle())
+ using (ECDiffieHellmanPublicKey firstPublic = first.PublicKey)
+ {
+ derived = first.DeriveKeyFromHmac(firstPublic, HashAlgorithmName.SHA384, null);
+ second = new ECDiffieHellmanOpenSsl(firstHandle);
+ }
+
+ // Now show that second still works, despite first and firstHandle being Disposed.
+ using (second)
+ using (ECDiffieHellmanPublicKey secondPublic = second.PublicKey)
+ {
+ byte[] derived2 = second.DeriveKeyFromHmac(secondPublic, HashAlgorithmName.SHA384, null);
+ Assert.Equal(derived, derived2);
+ }
+ }
+
+ [Fact]
+ public void VerifyDuplicateKey_NullHandle()
+ {
+ SafeEvpPKeyHandle pkey = null;
+ Assert.Throws<ArgumentNullException>(() => new ECDiffieHellmanOpenSsl(pkey));
+ }
+
+ [Fact]
+ public void VerifyDuplicateKey_InvalidHandle()
+ {
+ using (var ecdsa = new ECDiffieHellmanOpenSsl())
+ {
+ SafeEvpPKeyHandle pkey = ecdsa.DuplicateKeyHandle();
+
+ using (pkey)
+ {
+ }
+
+ AssertExtensions.Throws<ArgumentException>("pkeyHandle", () => new ECDiffieHellmanOpenSsl(pkey));
+ }
+ }
+
+ [Fact]
+ public void VerifyDuplicateKey_NeverValidHandle()
+ {
+ using (SafeEvpPKeyHandle pkey = new SafeEvpPKeyHandle(IntPtr.Zero, false))
+ {
+ AssertExtensions.Throws<ArgumentException>("pkeyHandle", () => new ECDiffieHellmanOpenSsl(pkey));
+ }
+ }
+
+ [Fact]
+ public void VerifyDuplicateKey_RsaHandle()
+ {
+ using (RSAOpenSsl rsa = new RSAOpenSsl())
+ using (SafeEvpPKeyHandle pkey = rsa.DuplicateKeyHandle())
+ {
+ Assert.ThrowsAny<CryptographicException>(() => new ECDiffieHellmanOpenSsl(pkey));
+ }
+ }
+
+ [Fact]
+ public void LookupCurveByOidValue()
+ {
+ var ec = new ECDiffieHellmanOpenSsl(ECCurve.CreateFromValue(ECDSA_P256_OID_VALUE)); // Same as nistP256
+ ECParameters param = ec.ExportParameters(false);
+ param.Validate();
+ Assert.Equal(256, ec.KeySize);
+ Assert.True(param.Curve.IsNamed);
+ Assert.Equal("ECDSA_P256", param.Curve.Oid.FriendlyName);
+ Assert.Equal(ECDSA_P256_OID_VALUE, param.Curve.Oid.Value);
+ }
+
+ [Fact]
+ public void LookupCurveByOidFriendlyName()
+ {
+ // prime256v1 is alias for nistP256 for OpenSsl
+ var ec = new ECDiffieHellmanOpenSsl(ECCurve.CreateFromFriendlyName("prime256v1"));
+
+ ECParameters param = ec.ExportParameters(false);
+ param.Validate();
+ Assert.Equal(256, ec.KeySize);
+ Assert.True(param.Curve.IsNamed);
+ Assert.Equal("ECDSA_P256", param.Curve.Oid.FriendlyName); // OpenSsl maps prime256v1 to ECDSA_P256
+ Assert.Equal(ECDSA_P256_OID_VALUE, param.Curve.Oid.Value);
+
+ // secp521r1 is same as nistP521; note Windows uses secP521r1 (uppercase P)
+ ec = new ECDiffieHellmanOpenSsl(ECCurve.CreateFromFriendlyName("secp521r1"));
+ param = ec.ExportParameters(false);
+ param.Validate();
+ Assert.Equal(521, ec.KeySize);
+ Assert.True(param.Curve.IsNamed);
+ Assert.Equal("ECDSA_P521", param.Curve.Oid.FriendlyName); // OpenSsl maps secp521r1 to ECDSA_P521
+ Assert.Equal(ECDSA_P521_OID_VALUE, param.Curve.Oid.Value);
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.OpenSsl/tests/EcDsaOpenSslTests.cs b/src/System.Security.Cryptography.OpenSsl/tests/EcDsaOpenSslTests.cs
index 4051b80298..84960807af 100644
--- a/src/System.Security.Cryptography.OpenSsl/tests/EcDsaOpenSslTests.cs
+++ b/src/System.Security.Cryptography.OpenSsl/tests/EcDsaOpenSslTests.cs
@@ -206,7 +206,7 @@ namespace System.Security.Cryptography.EcDsa.OpenSsl.Tests
public void VerifyDuplicateKey_NullHandle()
{
SafeEvpPKeyHandle pkey = null;
- Assert.Throws<ArgumentNullException>(() => new RSAOpenSsl(pkey));
+ Assert.Throws<ArgumentNullException>(() => new ECDsaOpenSsl(pkey));
}
[Fact]
diff --git a/src/System.Security.Cryptography.OpenSsl/tests/RSAOpenSslProvider.cs b/src/System.Security.Cryptography.OpenSsl/tests/RSAOpenSslProvider.cs
index e467120954..82933734dc 100644
--- a/src/System.Security.Cryptography.OpenSsl/tests/RSAOpenSslProvider.cs
+++ b/src/System.Security.Cryptography.OpenSsl/tests/RSAOpenSslProvider.cs
@@ -12,7 +12,9 @@ namespace System.Security.Cryptography.Rsa.Tests
public bool Supports384PrivateKey => true;
- public bool SupportsSha2Oaep => false;
+ public bool SupportsSha2Oaep => true;
+
+ public bool SupportsPss => true;
public bool SupportsDecryptingIntoExactSpaceRequired => false;
}
diff --git a/src/System.Security.Cryptography.OpenSsl/tests/System.Security.Cryptography.OpenSsl.Tests.csproj b/src/System.Security.Cryptography.OpenSsl/tests/System.Security.Cryptography.OpenSsl.Tests.csproj
index 7d72a33b58..76f01098ce 100644
--- a/src/System.Security.Cryptography.OpenSsl/tests/System.Security.Cryptography.OpenSsl.Tests.csproj
+++ b/src/System.Security.Cryptography.OpenSsl/tests/System.Security.Cryptography.OpenSsl.Tests.csproj
@@ -22,6 +22,36 @@
<Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\EC\CurveDef.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\CurveDef.cs</Link>
</Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\EC\EccTestBase.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\EccTestBase.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\EC\EccTestData.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\EC\EccTestData.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanFactory.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanFactory.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Hash.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Hash.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Hmac.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Hmac.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.ImportExport.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.ImportExport.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.NistValidation.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.NistValidation.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Tls.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Tls.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Xml.cs">
+ <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDiffieHellman\ECDiffieHellmanTests.Xml.cs</Link>
+ </Compile>
<Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaFactory.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaFactory.cs</Link>
</Compile>
@@ -40,9 +70,6 @@
<Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaTestsBase.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaTestsBase.cs</Link>
</Compile>
- <Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaTestData.cs">
- <Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\ECDsa\ECDsaTestData.cs</Link>
- </Compile>
<Compile Include="$(CommonTestPath)\System\Security\Cryptography\AlgorithmImplementations\RSA\EncryptDecrypt.cs">
<Link>CommonTest\System\Security\Cryptography\AlgorithmImplementations\RSA\EncryptDecrypt.cs</Link>
</Compile>
@@ -64,6 +91,8 @@
<Compile Include="$(CommonTestPath)\System\IO\PositionValueStream.cs">
<Link>CommonTest\System\IO\PositionValueStream.cs</Link>
</Compile>
+ <Compile Include="EcDiffieHellmanOpenSslProvider.cs" />
+ <Compile Include="EcDiffieHellmanOpenSslTests.cs" />
<Compile Include="EcDsaOpenSslProvider.cs" />
<Compile Include="RsaOpenSslTests.cs" />
<Compile Include="DsaOpenSslProvider.cs" />
diff --git a/src/System.Security.Cryptography.Pkcs/pkg/System.Security.Cryptography.Pkcs.pkgproj b/src/System.Security.Cryptography.Pkcs/pkg/System.Security.Cryptography.Pkcs.pkgproj
index 688cc3f92a..234c84175e 100644
--- a/src/System.Security.Cryptography.Pkcs/pkg/System.Security.Cryptography.Pkcs.pkgproj
+++ b/src/System.Security.Cryptography.Pkcs/pkg/System.Security.Cryptography.Pkcs.pkgproj
@@ -8,6 +8,12 @@
<ProjectReference Include="..\src\System.Security.Cryptography.Pkcs.csproj" />
<HarvestIncludePaths Include="ref/net46;lib/net46;runtimes/win/lib/net46" />
<HarvestIncludePaths Include="ref/netstandard1.3;runtimes/win/lib/netstandard1.3;lib/netstandard1.3" />
+
+ <!--
+ Suppress NETStandard.Library collpasing as it add more dependencies then needed in some
+ scenarios like .NET Framework which adds an unecessary amount of package dependencies to download
+ -->
+ <SuppressMetaPackage Include="NETStandard.Library" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
diff --git a/src/System.Security.Cryptography.Pkcs/ref/System.Security.Cryptography.Pkcs.csproj b/src/System.Security.Cryptography.Pkcs/ref/System.Security.Cryptography.Pkcs.csproj
index e5d055ae1f..f52fded032 100644
--- a/src/System.Security.Cryptography.Pkcs/ref/System.Security.Cryptography.Pkcs.csproj
+++ b/src/System.Security.Cryptography.Pkcs/ref/System.Security.Cryptography.Pkcs.csproj
@@ -24,6 +24,7 @@
<ProjectReference Include="..\..\System.Runtime\ref\System.Runtime.csproj" />
<ProjectReference Include="..\..\System.Security.Cryptography.Csp\ref\System.Security.Cryptography.Csp.csproj" />
<ProjectReference Include="..\..\System.Security.Cryptography.Encoding\ref\System.Security.Cryptography.Encoding.csproj" />
+ <ProjectReference Include="..\..\System.Security.Cryptography.Primitives\ref\System.Security.Cryptography.Primitives.csproj" />
<ProjectReference Include="..\..\System.Security.Cryptography.X509Certificates\ref\System.Security.Cryptography.X509Certificates.csproj" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
diff --git a/src/System.Security.Cryptography.Pkcs/ref/System.Security.Cryptography.Pkcs.netcoreapp.cs b/src/System.Security.Cryptography.Pkcs/ref/System.Security.Cryptography.Pkcs.netcoreapp.cs
index 1d65c813f0..fc90740267 100644
--- a/src/System.Security.Cryptography.Pkcs/ref/System.Security.Cryptography.Pkcs.netcoreapp.cs
+++ b/src/System.Security.Cryptography.Pkcs/ref/System.Security.Cryptography.Pkcs.netcoreapp.cs
@@ -5,8 +5,60 @@
// Changes to this file must follow the http://aka.ms/api-review process.
// ------------------------------------------------------------------------------
+using System.Security.Cryptography.X509Certificates;
+
namespace System.Security.Cryptography.Pkcs
{
+ public sealed partial class Rfc3161TimestampRequest
+ {
+ private Rfc3161TimestampRequest() { }
+ public int Version => throw null;
+ public ReadOnlyMemory<byte> GetMessageHash() => throw null;
+ public Oid HashAlgorithmId => throw null;
+ public Oid RequestedPolicyId => throw null;
+ public bool RequestSignerCertificate => throw null;
+ public ReadOnlyMemory<byte>? GetNonce() => throw null;
+ public bool HasExtensions => throw null;
+ public X509ExtensionCollection GetExtensions() => throw null;
+ public byte[] Encode() => throw null;
+ public bool TryEncode(Span<byte> destination, out int bytesWritten) => throw null;
+ public Rfc3161TimestampToken ProcessResponse(ReadOnlyMemory<byte> responseBytes, out int bytesConsumed) => throw null;
+ public static Rfc3161TimestampRequest CreateFromData(ReadOnlySpan<byte> data, HashAlgorithmName hashAlgorithm, Oid requestedPolicyId = null, ReadOnlyMemory<byte>? nonce = null, bool requestSignerCertificates = false, X509ExtensionCollection extensions = null) => throw null;
+ public static Rfc3161TimestampRequest CreateFromHash(ReadOnlyMemory<byte> hash, HashAlgorithmName hashAlgorithm, Oid requestedPolicyId = null, ReadOnlyMemory<byte>? nonce = null, bool requestSignerCertificates = false, X509ExtensionCollection extensions = null) => throw null;
+ public static Rfc3161TimestampRequest CreateFromHash(ReadOnlyMemory<byte> hash, Oid hashAlgorithmId, Oid requestedPolicyId = null, ReadOnlyMemory<byte>? nonce = null, bool requestSignerCertificates = false, X509ExtensionCollection extensions = null) => throw null;
+ public static Rfc3161TimestampRequest CreateFromSignerInfo(SignerInfo signerInfo, HashAlgorithmName hashAlgorithm, Oid requestedPolicyId = null, ReadOnlyMemory<byte>? nonce = null, bool requestSignerCertificates = false, X509ExtensionCollection extensions = null) => throw null;
+ public static bool TryDecode(ReadOnlyMemory<byte> encodedBytes, out Rfc3161TimestampRequest request, out int bytesConsumed) => throw null;
+ }
+ public sealed partial class Rfc3161TimestampToken
+ {
+ private Rfc3161TimestampToken() { }
+ public Rfc3161TimestampTokenInfo TokenInfo => throw null;
+ public SignedCms AsSignedCms() => throw null;
+ public bool VerifySignatureForHash(ReadOnlySpan<byte> hash, HashAlgorithmName hashAlgorithm, out X509Certificate2 signerCertificate, X509Certificate2Collection extraCandidates = null) => throw null;
+ public bool VerifySignatureForHash(ReadOnlySpan<byte> hash, Oid hashAlgorithmId, out X509Certificate2 signerCertificate, X509Certificate2Collection extraCandidates = null) => throw null;
+ public bool VerifySignatureForData(ReadOnlySpan<byte> data, out X509Certificate2 signerCertificate, X509Certificate2Collection extraCandidates = null) => throw null;
+ public bool VerifySignatureForSignerInfo(SignerInfo signerInfo, out X509Certificate2 signerCertificate, X509Certificate2Collection extraCandidates = null) => throw null;
+ public static bool TryDecode(ReadOnlyMemory<byte> encodedBytes, out Rfc3161TimestampToken token, out int bytesConsumed) => throw null;
+ }
+ public sealed partial class Rfc3161TimestampTokenInfo
+ {
+ public Rfc3161TimestampTokenInfo(Oid policyId, Oid hashAlgorithmId, ReadOnlyMemory<byte> messageHash, ReadOnlyMemory<byte> serialNumber, DateTimeOffset timestamp, long? accuracyInMicroseconds=null, bool isOrdering=false, ReadOnlyMemory<byte>? nonce=null, ReadOnlyMemory<byte>? timestampAuthorityName=null, X509ExtensionCollection extensions =null) { throw null; }
+ public int Version => throw null;
+ public Oid PolicyId=> throw null;
+ public Oid HashAlgorithmId => throw null;
+ public ReadOnlyMemory<byte> GetMessageHash() { throw null; }
+ public ReadOnlyMemory<byte> GetSerialNumber() { throw null; }
+ public DateTimeOffset Timestamp => throw null;
+ public long? AccuracyInMicroseconds => throw null;
+ public bool IsOrdering => throw null;
+ public ReadOnlyMemory<byte>? GetNonce() { throw null; }
+ public ReadOnlyMemory<byte>? GetTimestampAuthorityName() { throw null; }
+ public bool HasExtensions => throw null;
+ public X509ExtensionCollection GetExtensions() { throw null; }
+ public byte[] Encode() => throw null;
+ public bool TryEncode(Span<byte> destination, out int bytesWritten) => throw null;
+ public static bool TryDecode(ReadOnlyMemory<byte> encodedBytes, out Rfc3161TimestampTokenInfo timestampTokenInfo, out int bytesConsumed) { throw null; }
+ }
public sealed partial class SignerInfo
{
public Oid SignatureAlgorithm => throw null;
diff --git a/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Helpers.cs b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Helpers.cs
index c972345356..abdce600b6 100644
--- a/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Helpers.cs
+++ b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Helpers.cs
@@ -6,6 +6,7 @@ using System;
using System.Buffers;
using System.Text;
using System.Diagnostics;
+using System.IO;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Security.Cryptography.Asn1;
@@ -56,6 +57,22 @@ namespace Internal.Cryptography
}
}
+ internal static string GetOidFromHashAlgorithm(HashAlgorithmName algName)
+ {
+ if (algName == HashAlgorithmName.MD5)
+ return Oids.Md5;
+ if (algName == HashAlgorithmName.SHA1)
+ return Oids.Sha1;
+ if (algName == HashAlgorithmName.SHA256)
+ return Oids.Sha256;
+ if (algName == HashAlgorithmName.SHA384)
+ return Oids.Sha384;
+ if (algName == HashAlgorithmName.SHA512)
+ return Oids.Sha512;
+
+ throw new CryptographicException(SR.Cryptography_Cms_UnknownAlgorithm, algName.Name);
+ }
+
/// <summary>
/// This is not just a convenience wrapper for Array.Resize(). In DEBUG builds, it forces the array to move in memory even if no resize is needed. This should be used by
/// helper methods that do anything of the form "call a native api once to get the estimated size, call it again to get the data and return the data in a byte[] array."
@@ -119,6 +136,26 @@ namespace Internal.Cryptography
return set.SetData;
}
+ internal static byte[] EncodeContentInfo<T>(
+ T value,
+ string contentType,
+ AsnEncodingRules ruleSet = AsnEncodingRules.DER)
+ {
+ using (AsnWriter innerWriter = AsnSerializer.Serialize(value, ruleSet))
+ {
+ ContentInfoAsn content = new ContentInfoAsn
+ {
+ ContentType = contentType,
+ Content = innerWriter.Encode(),
+ };
+
+ using (AsnWriter outerWriter = AsnSerializer.Serialize(content, ruleSet))
+ {
+ return outerWriter.Encode();
+ }
+ }
+ }
+
public static CmsRecipientCollection DeepCopy(this CmsRecipientCollection recipients)
{
CmsRecipientCollection recipientsCopy = new CmsRecipientCollection();
@@ -151,7 +188,7 @@ namespace Internal.Cryptography
public static X509Certificate2Collection GetStoreCertificates(StoreName storeName, StoreLocation storeLocation, bool openExistingOnly)
{
- using (X509Store store = new X509Store())
+ using (X509Store store = new X509Store(storeName, storeLocation))
{
OpenFlags flags = OpenFlags.ReadOnly | OpenFlags.IncludeArchived;
if (openExistingOnly)
@@ -234,14 +271,14 @@ namespace Internal.Cryptography
return skiString.UpperHexStringToByteArray();
}
- public static string ToSkiString(this ReadOnlySpan<byte> skiBytes)
+ public static string ToSkiString(this byte[] skiBytes)
{
return ToUpperHexString(skiBytes);
}
- public static string ToSkiString(this byte[] skiBytes)
+ public static string ToBigEndianHex(this ReadOnlySpan<byte> bytes)
{
- return ToUpperHexString(skiBytes);
+ return ToUpperHexString(bytes);
}
/// <summary>
@@ -398,6 +435,29 @@ namespace Internal.Cryptography
#endif
}
+ internal static byte[] OneShot(this ICryptoTransform transform, byte[] data)
+ {
+ return OneShot(transform, data, 0, data.Length);
+ }
+
+ internal static byte[] OneShot(this ICryptoTransform transform, byte[] data, int offset, int length)
+ {
+ if (transform.CanTransformMultipleBlocks)
+ {
+ return transform.TransformFinalBlock(data, offset, length);
+ }
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ using (var cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))
+ {
+ cryptoStream.Write(data, offset, length);
+ }
+
+ return memoryStream.ToArray();
+ }
+ }
+
private static ReadOnlyMemory<byte> GetSubjectPublicKeyInfo(X509Certificate2 certificate)
{
var parsedCertificate = AsnSerializer.Deserialize<Certificate>(certificate.RawData, AsnEncodingRules.DER);
diff --git a/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Oids.cs b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Oids.cs
index 0abf2df115..2274607c67 100644
--- a/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Oids.cs
+++ b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Oids.cs
@@ -2,19 +2,22 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System;
-using System.Text;
-using System.Diagnostics;
-
namespace Internal.Cryptography
{
internal static class Oids
{
// Symmetric encryption algorithms
+ public const string Rc2Cbc = "1.2.840.113549.3.2";
+ public const string Rc4 = "1.2.840.113549.3.4";
public const string TripleDesCbc = "1.2.840.113549.3.7";
+ public const string DesCbc = "1.3.14.3.2.7";
+ public const string Aes128Cbc = "2.16.840.1.101.3.4.1.2";
+ public const string Aes192Cbc = "2.16.840.1.101.3.4.1.22";
+ public const string Aes256Cbc = "2.16.840.1.101.3.4.1.42";
// Asymmetric encryption algorithms
public const string Rsa = "1.2.840.113549.1.1.1";
+ public const string RsaOaep = "1.2.840.113549.1.1.7";
public const string RsaPss = "1.2.840.113549.1.1.10";
public const string Esdh = "1.2.840.113549.1.9.16.3.5";
@@ -24,6 +27,8 @@ namespace Internal.Cryptography
public const string DocumentDescription = "1.3.6.1.4.1.311.88.2.2";
public const string MessageDigest = "1.2.840.113549.1.9.4";
public const string CounterSigner = "1.2.840.113549.1.9.6";
+ public const string SigningCertificate = "1.2.840.113549.1.9.16.2.12";
+ public const string SigningCertificateV2 = "1.2.840.113549.1.9.16.2.47";
public const string DocumentName = "1.3.6.1.4.1.311.88.2.1";
// Key wrap algorithms
@@ -64,5 +69,9 @@ namespace Internal.Cryptography
// Cert Extensions
public const string SubjectKeyIdentifier = "2.5.29.14";
public const string KeyUsage = "2.5.29.15";
+
+ // RFC3161 Timestamping
+ public const string TstInfo = "1.2.840.113549.1.9.16.1.4";
+ public const string TimeStampingPurpose = "1.3.6.1.5.5.7.3.8";
}
}
diff --git a/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/AsnHelpers.cs b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/AsnHelpers.cs
new file mode 100644
index 0000000000..92f0651835
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/AsnHelpers.cs
@@ -0,0 +1,140 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+using System.Security.Cryptography.Pkcs;
+using System.Security.Cryptography.Pkcs.Asn1;
+using System.Security.Cryptography.X509Certificates;
+using System.Security.Cryptography.Xml;
+
+namespace Internal.Cryptography.Pal.AnyOS
+{
+ internal static class AsnHelpers
+ {
+ internal static SubjectIdentifierOrKey ToSubjectIdentifierOrKey(
+ this OriginatorIdentifierOrKeyAsn originator)
+ {
+ if (originator.IssuerAndSerialNumber != null)
+ {
+ var name = new X500DistinguishedName(originator.IssuerAndSerialNumber.Value.Issuer.ToArray());
+
+ return new SubjectIdentifierOrKey(
+ SubjectIdentifierOrKeyType.IssuerAndSerialNumber,
+ new X509IssuerSerial(
+ name.Name,
+ originator.IssuerAndSerialNumber.Value.SerialNumber.Span.ToBigEndianHex()));
+ }
+
+ if (originator.SubjectKeyIdentifier != null)
+ {
+ return new SubjectIdentifierOrKey(
+ SubjectIdentifierOrKeyType.SubjectKeyIdentifier,
+ originator.SubjectKeyIdentifier.Value.Span.ToBigEndianHex());
+ }
+
+ if (originator.OriginatorKey != null)
+ {
+ OriginatorPublicKeyAsn originatorKey = originator.OriginatorKey;
+
+ return new SubjectIdentifierOrKey(
+ SubjectIdentifierOrKeyType.PublicKeyInfo,
+ new PublicKeyInfo(
+ originatorKey.Algorithm.ToPresentationObject(),
+ originatorKey.PublicKey.ToArray()));
+ }
+
+ Debug.Fail("Unknown SubjectIdentifierOrKey state");
+ return new SubjectIdentifierOrKey(SubjectIdentifierOrKeyType.Unknown, String.Empty);
+ }
+
+ internal static AlgorithmIdentifier ToPresentationObject(this AlgorithmIdentifierAsn asn)
+ {
+ int keyLength;
+
+ switch (asn.Algorithm.Value)
+ {
+ case Oids.Rc2Cbc:
+ {
+ if (asn.Parameters == null)
+ {
+ keyLength = 0;
+ break;
+ }
+
+ Rc2CbcParameters rc2Params = AsnSerializer.Deserialize<Rc2CbcParameters>(
+ asn.Parameters.Value,
+ AsnEncodingRules.BER);
+
+ int keySize = rc2Params.GetEffectiveKeyBits();
+
+ // These are the only values .NET Framework would set.
+ switch (keySize)
+ {
+ case 40:
+ case 56:
+ case 64:
+ case 128:
+ keyLength = keySize;
+ break;
+ default:
+ keyLength = 0;
+ break;
+ }
+
+ break;
+ }
+ case Oids.Rc4:
+ {
+ if (asn.Parameters == null)
+ {
+ keyLength = 0;
+ break;
+ }
+
+ int saltLen = 0;
+ AsnReader reader = new AsnReader(asn.Parameters.Value, AsnEncodingRules.BER);
+
+ // DER NULL is considered the same as not present.
+ // No call to ReadNull() is necessary because the serializer already verified that
+ // there's no data after the [AnyValue] value.
+ if (reader.PeekTag() != Asn1Tag.Null)
+ {
+ if (reader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> contents))
+ {
+ saltLen = contents.Length;
+ }
+ else
+ {
+ Span<byte> salt = stackalloc byte[KeyLengths.Rc4Max_128Bit / 8];
+
+ if (!reader.TryCopyOctetStringBytes(salt, out saltLen))
+ {
+ throw new CryptographicException();
+ }
+ }
+ }
+
+ keyLength = KeyLengths.Rc4Max_128Bit - 8 * saltLen;
+ break;
+ }
+ case Oids.DesCbc:
+ keyLength = KeyLengths.Des_64Bit;
+ break;
+ case Oids.TripleDesCbc:
+ keyLength = KeyLengths.TripleDes_192Bit;
+ break;
+ default:
+ // .NET Framework doesn't set a keylength for AES, or any other algorithm than the ones
+ // listed here.
+ keyLength = 0;
+ break;
+ }
+
+ return new AlgorithmIdentifier(new Oid(asn.Algorithm), keyLength);
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.Asn.cs b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.Asn.cs
new file mode 100644
index 0000000000..361f55ac75
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.Asn.cs
@@ -0,0 +1,149 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Buffers;
+using System.Diagnostics;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+using System.Security.Cryptography.Pkcs.Asn1;
+
+namespace Internal.Cryptography.Pal.AnyOS
+{
+ internal sealed partial class ManagedPkcsPal : PkcsPal
+ {
+ private static readonly byte[] s_invalidEmptyOid = { 0x06, 0x00 };
+
+ public override byte[] EncodeOctetString(byte[] octets)
+ {
+ // Write using DER to support the most readers.
+ using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
+ {
+ writer.WriteOctetString(octets);
+ return writer.Encode();
+ }
+ }
+
+ public override byte[] DecodeOctetString(byte[] encodedOctets)
+ {
+ // Read using BER because the CMS specification says the encoding is BER.
+ AsnReader reader = new AsnReader(encodedOctets, AsnEncodingRules.BER);
+
+ const int ArbitraryStackLimit = 256;
+ Span<byte> tmp = stackalloc byte[ArbitraryStackLimit];
+ // Use stackalloc 0 so data can later hold a slice of tmp.
+ ReadOnlySpan<byte> data = stackalloc byte[0];
+ byte[] poolBytes = null;
+
+ try
+ {
+ if (!reader.TryGetPrimitiveOctetStringBytes(out var contents))
+ {
+ if (reader.TryCopyOctetStringBytes(tmp, out int bytesWritten))
+ {
+ data = tmp.Slice(0, bytesWritten);
+ }
+ else
+ {
+ poolBytes = ArrayPool<byte>.Shared.Rent(reader.PeekContentBytes().Length);
+
+ if (!reader.TryCopyOctetStringBytes(poolBytes, out bytesWritten))
+ {
+ Debug.Fail("TryCopyOctetStringBytes failed with a provably-large-enough buffer");
+ throw new CryptographicException();
+ }
+
+ data = new ReadOnlySpan<byte>(poolBytes, 0, bytesWritten);
+ }
+ }
+ else
+ {
+ data = contents.Span;
+ }
+
+ if (reader.HasData)
+ {
+ throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+ }
+
+ return data.ToArray();
+ }
+ finally
+ {
+ if (poolBytes != null)
+ {
+ Array.Clear(poolBytes, 0, data.Length);
+ ArrayPool<byte>.Shared.Return(poolBytes);
+ }
+ }
+ }
+
+ public override byte[] EncodeUtcTime(DateTime utcTime)
+ {
+ // Write using DER to support the most readers.
+ using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
+ {
+ // Sending the DateTime through ToLocalTime here will cause the right normalization
+ // of DateTimeKind.Unknown.
+ //
+ // Unknown => Local (adjust) => UTC (adjust "back", add Z marker; matches Windows)
+ if (utcTime.Kind == DateTimeKind.Unspecified)
+ {
+ writer.WriteUtcTime(utcTime.ToLocalTime());
+ }
+ else
+ {
+ writer.WriteUtcTime(utcTime);
+ }
+
+ return writer.Encode();
+ }
+ }
+
+ public override DateTime DecodeUtcTime(byte[] encodedUtcTime)
+ {
+ // Read using BER because the CMS specification says the encoding is BER.
+ AsnReader reader = new AsnReader(encodedUtcTime, AsnEncodingRules.BER);
+ DateTimeOffset value = reader.GetUtcTime();
+
+ if (reader.HasData)
+ {
+ throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+ }
+
+ return value.UtcDateTime;
+ }
+
+ public override string DecodeOid(byte[] encodedOid)
+ {
+ // Windows compat.
+ if (s_invalidEmptyOid.AsSpan().SequenceEqual(encodedOid))
+ {
+ return string.Empty;
+ }
+
+ // Read using BER because the CMS specification says the encoding is BER.
+ AsnReader reader = new AsnReader(encodedOid, AsnEncodingRules.BER);
+ string value = reader.ReadObjectIdentifierAsString();
+
+ if (reader.HasData)
+ {
+ throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+ }
+
+ return value;
+ }
+
+ public override Oid GetEncodedMessageType(byte[] encodedMessage)
+ {
+ AsnReader reader = new AsnReader(encodedMessage, AsnEncodingRules.BER);
+
+ ContentInfoAsn contentInfo = AsnSerializer.Deserialize<ContentInfoAsn>(
+ reader.GetEncodedValue(),
+ AsnEncodingRules.BER);
+
+ return new Oid(contentInfo.ContentType);
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.Decode.cs b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.Decode.cs
new file mode 100644
index 0000000000..17e0302c18
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.Decode.cs
@@ -0,0 +1,94 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+using System.Security.Cryptography.Pkcs;
+using System.Security.Cryptography.Pkcs.Asn1;
+using System.Security.Cryptography.X509Certificates;
+
+namespace Internal.Cryptography.Pal.AnyOS
+{
+ internal sealed partial class ManagedPkcsPal : PkcsPal
+ {
+ public override DecryptorPal Decode(
+ byte[] encodedMessage,
+ out int version,
+ out ContentInfo contentInfo,
+ out AlgorithmIdentifier contentEncryptionAlgorithm,
+ out X509Certificate2Collection originatorCerts,
+ out CryptographicAttributeObjectCollection unprotectedAttributes)
+ {
+ // Read using BER because the CMS specification says the encoding is BER.
+ AsnReader reader = new AsnReader(encodedMessage, AsnEncodingRules.BER);
+
+ ContentInfoAsn parsedContentInfo = AsnSerializer.Deserialize<ContentInfoAsn>(
+ reader.GetEncodedValue(),
+ AsnEncodingRules.BER);
+
+ if (parsedContentInfo.ContentType != Oids.Pkcs7Enveloped)
+ {
+ throw new CryptographicException(SR.Cryptography_Cms_InvalidMessageType);
+ }
+
+ byte[] copy = parsedContentInfo.Content.ToArray();
+
+ EnvelopedDataAsn data = AsnSerializer.Deserialize<EnvelopedDataAsn>(
+ copy,
+ AsnEncodingRules.BER);
+
+ version = data.Version;
+
+ contentInfo = new ContentInfo(
+ new Oid(data.EncryptedContentInfo.ContentType),
+ data.EncryptedContentInfo.EncryptedContent?.ToArray() ?? Array.Empty<byte>());
+
+ contentEncryptionAlgorithm =
+ data.EncryptedContentInfo.ContentEncryptionAlgorithm.ToPresentationObject();
+
+ originatorCerts = new X509Certificate2Collection();
+
+ if (data.OriginatorInfo != null && data.OriginatorInfo.CertificateSet != null)
+ {
+ foreach (CertificateChoiceAsn certChoice in data.OriginatorInfo.CertificateSet)
+ {
+ if (certChoice.Certificate != null)
+ {
+ originatorCerts.Add(new X509Certificate2(certChoice.Certificate.Value.ToArray()));
+ }
+ }
+ }
+
+ unprotectedAttributes = SignerInfo.MakeAttributeCollection(data.UnprotectedAttributes);
+
+ var recipientInfos = new List<RecipientInfo>();
+
+ foreach (RecipientInfoAsn recipientInfo in data.RecipientInfos)
+ {
+ if (recipientInfo.Ktri != null)
+ {
+ recipientInfos.Add(new KeyTransRecipientInfo(new ManagedKeyTransPal(recipientInfo.Ktri)));
+ }
+ else if (recipientInfo.Kari != null)
+ {
+ for (int i = 0; i < recipientInfo.Kari.RecipientEncryptedKeys.Length; i++)
+ {
+ recipientInfos.Add(
+ new KeyAgreeRecipientInfo(new ManagedKeyAgreePal(recipientInfo.Kari, i)));
+ }
+ }
+ else
+ {
+ Debug.Fail($"{nameof(RecipientInfoAsn)} deserialized with an unknown recipient type");
+ throw new CryptographicException();
+ }
+ }
+
+ return new ManagedDecryptorPal(copy, data, new RecipientInfoCollection(recipientInfos));
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.Decrypt.cs b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.Decrypt.cs
new file mode 100644
index 0000000000..78a5daf31f
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.Decrypt.cs
@@ -0,0 +1,186 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Buffers;
+using System.Diagnostics;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+using System.Security.Cryptography.Pkcs;
+using System.Security.Cryptography.Pkcs.Asn1;
+using System.Security.Cryptography.X509Certificates;
+
+namespace Internal.Cryptography.Pal.AnyOS
+{
+ internal sealed partial class ManagedPkcsPal : PkcsPal
+ {
+ private sealed class ManagedDecryptorPal : DecryptorPal
+ {
+ private byte[] _dataCopy;
+ private EnvelopedDataAsn _envelopedData;
+
+ public ManagedDecryptorPal(
+ byte[] dataCopy,
+ EnvelopedDataAsn envelopedDataAsn,
+ RecipientInfoCollection recipientInfos)
+ : base(recipientInfos)
+ {
+ _dataCopy = dataCopy;
+ _envelopedData = envelopedDataAsn;
+ }
+
+ public override unsafe ContentInfo TryDecrypt(
+ RecipientInfo recipientInfo,
+ X509Certificate2 cert,
+ X509Certificate2Collection originatorCerts,
+ X509Certificate2Collection extraStore,
+ out Exception exception)
+ {
+ // When encryptedContent is null Windows seems to decrypt the CEK first,
+ // then return a 0 byte answer.
+
+ byte[] cek;
+
+ if (recipientInfo.Pal is ManagedKeyTransPal ktri)
+ {
+ cek = ktri.DecryptCek(cert, out exception);
+ }
+ else
+ {
+ exception = new CryptographicException(
+ SR.Cryptography_Cms_RecipientType_NotSupported,
+ recipientInfo.Type.ToString());
+
+ return null;
+ }
+
+ byte[] decrypted;
+
+ // Pin CEK to prevent it from getting copied during heap compaction.
+ fixed (byte* pinnedCek = cek)
+ {
+ try
+ {
+ if (exception != null)
+ {
+ return null;
+ }
+
+ ReadOnlyMemory<byte>? encryptedContent = _envelopedData.EncryptedContentInfo.EncryptedContent;
+
+ if (encryptedContent == null)
+ {
+ exception = null;
+
+ return new ContentInfo(
+ new Oid(_envelopedData.EncryptedContentInfo.ContentType),
+ Array.Empty<byte>());
+ }
+
+ decrypted = DecryptContent(encryptedContent.Value, cek, out exception);
+ }
+ finally
+ {
+ if (cek != null)
+ {
+ Array.Clear(cek, 0, cek.Length);
+ }
+ }
+ }
+
+ if (exception != null)
+ {
+ return null;
+ }
+
+ if (_envelopedData.EncryptedContentInfo.ContentType == Oids.Pkcs7Data)
+ {
+ byte[] tmp = null;
+
+ try
+ {
+ AsnReader reader = new AsnReader(decrypted, AsnEncodingRules.BER);
+
+ if (reader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> contents))
+ {
+ decrypted = contents.ToArray();
+ }
+ else
+ {
+ tmp = ArrayPool<byte>.Shared.Rent(decrypted.Length);
+
+ if (reader.TryCopyOctetStringBytes(tmp, out int written))
+ {
+ Span<byte> innerContents = new Span<byte>(tmp, 0, written);
+ decrypted = innerContents.ToArray();
+ innerContents.Clear();
+ }
+ else
+ {
+ Debug.Fail("Octet string grew during copy");
+ // If this happens (which requires decrypted was overwritten, which
+ // shouldn't be possible), just leave decrypted alone.
+ }
+ }
+ }
+ catch (CryptographicException)
+ {
+ }
+ finally
+ {
+ if (tmp != null)
+ {
+ // Already cleared
+ ArrayPool<byte>.Shared.Return(tmp);
+ }
+ }
+ }
+
+ exception = null;
+ return new ContentInfo(
+ new Oid(_envelopedData.EncryptedContentInfo.ContentType),
+ decrypted);
+ }
+
+ private byte[] DecryptContent(ReadOnlyMemory<byte> encryptedContent, byte[] cek, out Exception exception)
+ {
+ exception = null;
+ int encryptedContentLength = encryptedContent.Length;
+ byte[] encryptedContentArray = ArrayPool<byte>.Shared.Rent(encryptedContentLength);
+
+ try
+ {
+ encryptedContent.CopyTo(encryptedContentArray);
+
+ AlgorithmIdentifierAsn contentEncryptionAlgorithm =
+ _envelopedData.EncryptedContentInfo.ContentEncryptionAlgorithm;
+
+ using (SymmetricAlgorithm alg = OpenAlgorithm(contentEncryptionAlgorithm))
+ using (ICryptoTransform decryptor = alg.CreateDecryptor(cek, alg.IV))
+ {
+ return decryptor.OneShot(
+ encryptedContentArray,
+ 0,
+ encryptedContentLength);
+ }
+ }
+ catch (CryptographicException e)
+ {
+ exception = e;
+ return null;
+ }
+ finally
+ {
+ Array.Clear(encryptedContentArray, 0, encryptedContentLength);
+ ArrayPool<byte>.Shared.Return(encryptedContentArray);
+ encryptedContentArray = null;
+ }
+ }
+
+ public override void Dispose()
+ {
+ }
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.Encrypt.cs b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.Encrypt.cs
new file mode 100644
index 0000000000..9d9a983b27
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.Encrypt.cs
@@ -0,0 +1,186 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+using System.Security.Cryptography.Pkcs;
+using System.Security.Cryptography.Pkcs.Asn1;
+using System.Security.Cryptography.X509Certificates;
+
+namespace Internal.Cryptography.Pal.AnyOS
+{
+ internal sealed partial class ManagedPkcsPal : PkcsPal
+ {
+ public override unsafe byte[] Encrypt(
+ CmsRecipientCollection recipients,
+ ContentInfo contentInfo,
+ AlgorithmIdentifier contentEncryptionAlgorithm,
+ X509Certificate2Collection originatorCerts,
+ CryptographicAttributeObjectCollection unprotectedAttributes)
+ {
+ byte[] encryptedContent = EncryptContent(
+ contentInfo,
+ contentEncryptionAlgorithm,
+ out byte[] cek,
+ out byte[] parameterBytes);
+
+ // Pin the CEK to prevent it from getting copied during heap compaction.
+ fixed (byte* pinnedCek = cek)
+ {
+ try
+ {
+ return Encrypt(
+ recipients,
+ contentInfo,
+ contentEncryptionAlgorithm,
+ originatorCerts,
+ unprotectedAttributes,
+ encryptedContent,
+ cek,
+ parameterBytes);
+ }
+ finally
+ {
+ Array.Clear(cek, 0, cek.Length);
+ }
+ }
+ }
+
+ private static byte[] Encrypt(
+ CmsRecipientCollection recipients,
+ ContentInfo contentInfo,
+ AlgorithmIdentifier contentEncryptionAlgorithm,
+ X509Certificate2Collection originatorCerts,
+ CryptographicAttributeObjectCollection unprotectedAttributes,
+ byte[] encryptedContent,
+ byte[] cek,
+ byte[] parameterBytes)
+ {
+ EnvelopedDataAsn envelopedData = new EnvelopedDataAsn
+ {
+ EncryptedContentInfo =
+ {
+ ContentType = contentInfo.ContentType.Value,
+
+ ContentEncryptionAlgorithm =
+ {
+ Algorithm = contentEncryptionAlgorithm.Oid,
+ Parameters = parameterBytes,
+ },
+
+ EncryptedContent = encryptedContent,
+ },
+ };
+
+ if (unprotectedAttributes != null && unprotectedAttributes.Count > 0)
+ {
+ List<AttributeAsn> attrList = CmsSigner.BuildAttributes(unprotectedAttributes);
+
+ envelopedData.UnprotectedAttributes = Helpers.NormalizeSet(attrList.ToArray());
+ }
+
+ if (originatorCerts != null && originatorCerts.Count > 0)
+ {
+ CertificateChoiceAsn[] certs = new CertificateChoiceAsn[originatorCerts.Count];
+
+ for (int i = 0; i < originatorCerts.Count; i++)
+ {
+ certs[i].Certificate = originatorCerts[i].RawData;
+ }
+
+ envelopedData.OriginatorInfo = new OriginatorInfoAsn
+ {
+ CertificateSet = certs,
+ };
+ }
+
+ envelopedData.RecipientInfos = new RecipientInfoAsn[recipients.Count];
+
+ bool allRecipientsVersion0 = true;
+
+ for (var i = 0; i < recipients.Count; i++)
+ {
+ CmsRecipient recipient = recipients[i];
+ bool v0Recipient;
+
+ switch (recipient.Certificate.GetKeyAlgorithm())
+ {
+ case Oids.Rsa:
+ envelopedData.RecipientInfos[i].Ktri = MakeKtri(cek, recipient, out v0Recipient);
+ break;
+ default:
+ throw new CryptographicException(
+ SR.Cryptography_Cms_UnknownAlgorithm,
+ recipient.Certificate.GetKeyAlgorithm());
+ }
+
+ allRecipientsVersion0 = allRecipientsVersion0 && v0Recipient;
+ }
+
+ // https://tools.ietf.org/html/rfc5652#section-6.1
+ //
+ // v4 (RFC 3852):
+ // * OriginatorInfo contains certificates with type other (not supported)
+ // * OriginatorInfo contains crls with type other (not supported)
+ // v3 (RFC 3369):
+ // * OriginatorInfo contains v2 attribute certificates (not supported)
+ // * Any PWRI (password) recipients are present (not supported)
+ // * Any ORI (other) recipients are present (not supported)
+ // v2 (RFC 2630):
+ // * OriginatorInfo is present
+ // * Any RecipientInfo has a non-zero version number
+ // * UnprotectedAttrs is present
+ // v1 (not defined for EnvelopedData)
+ // v0 (RFC 2315):
+ // * Anything not already matched
+
+ if (envelopedData.OriginatorInfo != null ||
+ !allRecipientsVersion0 ||
+ envelopedData.UnprotectedAttributes != null)
+ {
+ envelopedData.Version = 2;
+ }
+
+ return Helpers.EncodeContentInfo(envelopedData, Oids.Pkcs7Enveloped);
+ }
+
+ private byte[] EncryptContent(
+ ContentInfo contentInfo,
+ AlgorithmIdentifier contentEncryptionAlgorithm,
+ out byte[] cek,
+ out byte[] parameterBytes)
+ {
+ using (SymmetricAlgorithm alg = OpenAlgorithm(contentEncryptionAlgorithm))
+ using (ICryptoTransform encryptor = alg.CreateEncryptor())
+ {
+ cek = alg.Key;
+
+ if (alg is RC2)
+ {
+ Rc2CbcParameters rc2Params = new Rc2CbcParameters(alg.IV, alg.KeySize);
+
+ using (AsnWriter writer = AsnSerializer.Serialize(rc2Params, AsnEncodingRules.DER))
+ {
+ parameterBytes = writer.Encode();
+ }
+ }
+ else
+ {
+ parameterBytes = EncodeOctetString(alg.IV);
+ }
+
+ byte[] toEncrypt = contentInfo.Content;
+
+ if (contentInfo.ContentType.Value == Oids.Pkcs7Data)
+ {
+ toEncrypt = EncodeOctetString(toEncrypt);
+ }
+
+ return encryptor.OneShot(toEncrypt);
+ }
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.Exceptions.cs b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.Exceptions.cs
new file mode 100644
index 0000000000..0abe53da71
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.Exceptions.cs
@@ -0,0 +1,38 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Security.Cryptography;
+
+namespace Internal.Cryptography.Pal.AnyOS
+{
+ internal sealed partial class ManagedPkcsPal : PkcsPal
+ {
+ public override Exception CreateRecipientsNotFoundException()
+ {
+ return new CryptographicException(SR.Cryptography_Cms_RecipientNotFound);
+ }
+
+ public override Exception CreateRecipientInfosAfterEncryptException()
+ {
+ return CreateInvalidMessageTypeException();
+ }
+
+ public override Exception CreateDecryptAfterEncryptException()
+ {
+ return CreateInvalidMessageTypeException();
+ }
+
+ public override Exception CreateDecryptTwiceException()
+ {
+ return CreateInvalidMessageTypeException();
+ }
+
+ private static Exception CreateInvalidMessageTypeException()
+ {
+ // Windows CRYPT_E_INVALID_MSG_TYPE
+ return new CryptographicException(SR.Cryptography_Cms_InvalidMessageType);
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.KeyAgree.cs b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.KeyAgree.cs
new file mode 100644
index 0000000000..3c8bfd02c2
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.KeyAgree.cs
@@ -0,0 +1,94 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Pkcs;
+using System.Security.Cryptography.Pkcs.Asn1;
+
+namespace Internal.Cryptography.Pal.AnyOS
+{
+ internal sealed partial class ManagedPkcsPal : PkcsPal
+ {
+ private sealed class ManagedKeyAgreePal : KeyAgreeRecipientInfoPal
+ {
+ private readonly KeyAgreeRecipientInfoAsn _asn;
+ private readonly int _index;
+
+ internal ManagedKeyAgreePal(KeyAgreeRecipientInfoAsn asn, int index)
+ {
+ _asn = asn;
+ _index = index;
+ }
+
+ public override byte[] EncryptedKey =>
+ _asn.RecipientEncryptedKeys[_index].EncryptedKey.ToArray();
+
+ public override AlgorithmIdentifier KeyEncryptionAlgorithm =>
+ _asn.KeyEncryptionAlgorithm.ToPresentationObject();
+
+ public override SubjectIdentifier RecipientIdentifier =>
+ new SubjectIdentifier(
+ _asn.RecipientEncryptedKeys[_index].Rid.IssuerAndSerialNumber,
+ _asn.RecipientEncryptedKeys[_index].Rid.RKeyId?.SubjectKeyIdentifier);
+
+ public override int Version => _asn.Version;
+
+ public override DateTime Date
+ {
+ get
+ {
+ KeyAgreeRecipientIdentifierAsn rid = _asn.RecipientEncryptedKeys[_index].Rid;
+
+ if (rid.RKeyId == null)
+ {
+ throw new InvalidOperationException(SR.Cryptography_Cms_Key_Agree_Date_Not_Available);
+ }
+
+ if (rid.RKeyId.Date == null)
+ {
+ // Compatibility with Windows/NetFX.
+ return DateTime.FromFileTimeUtc(0);
+ }
+
+ return rid.RKeyId.Date.Value.LocalDateTime;
+ }
+ }
+
+ public override SubjectIdentifierOrKey OriginatorIdentifierOrKey =>
+ _asn.Originator.ToSubjectIdentifierOrKey();
+
+ public override CryptographicAttributeObject OtherKeyAttribute
+ {
+ get
+ {
+ KeyAgreeRecipientIdentifierAsn rid = _asn.RecipientEncryptedKeys[_index].Rid;
+
+ if (rid.RKeyId == null)
+ {
+ // Yes, "date" (Windows compat)
+ throw new InvalidOperationException(SR.Cryptography_Cms_Key_Agree_Date_Not_Available);
+ }
+
+ if (rid.RKeyId.Other == null)
+ {
+ return null;
+ }
+
+ Oid oid = new Oid(rid.RKeyId.Other.Value.KeyAttrId);
+ byte[] rawData = Array.Empty<byte>();
+
+ if (rid.RKeyId.Other.Value.KeyAttr != null)
+ {
+ rawData = rid.RKeyId.Other.Value.KeyAttr.Value.ToArray();
+ }
+
+ Pkcs9AttributeObject pkcs9AttributeObject = new Pkcs9AttributeObject(oid, rawData);
+ AsnEncodedDataCollection values = new AsnEncodedDataCollection(pkcs9AttributeObject);
+ return new CryptographicAttributeObject(oid, values);
+ }
+ }
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.KeyTrans.cs b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.KeyTrans.cs
new file mode 100644
index 0000000000..152cc116f5
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.KeyTrans.cs
@@ -0,0 +1,179 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Buffers;
+using System.Diagnostics;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Pkcs;
+using System.Security.Cryptography.Pkcs.Asn1;
+using System.Security.Cryptography.X509Certificates;
+
+namespace Internal.Cryptography.Pal.AnyOS
+{
+ internal sealed partial class ManagedPkcsPal : PkcsPal
+ {
+ private static readonly byte[] s_rsaPkcsParameters = { 0x05, 0x00 };
+ private static readonly byte[] s_rsaOaepSha1Parameters = { 0x30, 0x00 };
+
+ private sealed class ManagedKeyTransPal : KeyTransRecipientInfoPal
+ {
+ private readonly KeyTransRecipientInfoAsn _asn;
+
+ internal ManagedKeyTransPal(KeyTransRecipientInfoAsn asn)
+ {
+ _asn = asn;
+ }
+
+ public override byte[] EncryptedKey =>
+ _asn.EncryptedKey.ToArray();
+
+ public override AlgorithmIdentifier KeyEncryptionAlgorithm =>
+ _asn.KeyEncryptionAlgorithm.ToPresentationObject();
+
+ public override SubjectIdentifier RecipientIdentifier =>
+ new SubjectIdentifier(_asn.Rid.IssuerAndSerialNumber, _asn.Rid.SubjectKeyIdentifier);
+
+ public override int Version => _asn.Version;
+
+ internal byte[] DecryptCek(X509Certificate2 cert, out Exception exception)
+ {
+ RSAEncryptionPadding encryptionPadding;
+ ReadOnlyMemory<byte>? parameters = _asn.KeyEncryptionAlgorithm.Parameters;
+
+ switch (_asn.KeyEncryptionAlgorithm.Algorithm.Value)
+ {
+ case Oids.Rsa:
+ if (parameters != null &&
+ !parameters.Value.Span.SequenceEqual(s_rsaPkcsParameters))
+ {
+ exception = new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+ return null;
+ }
+
+ encryptionPadding = RSAEncryptionPadding.Pkcs1;
+ break;
+ case Oids.RsaOaep:
+ if (parameters != null &&
+ !parameters.Value.Span.SequenceEqual(s_rsaOaepSha1Parameters))
+ {
+ exception = new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+ return null;
+ }
+
+ encryptionPadding = RSAEncryptionPadding.OaepSHA1;
+ break;
+ default:
+ exception = new CryptographicException(
+ SR.Cryptography_Cms_UnknownAlgorithm,
+ _asn.KeyEncryptionAlgorithm.Algorithm.Value);
+
+ return null;
+ }
+
+ byte[] cek = null;
+ int cekLength = 0;
+
+ try
+ {
+ using (RSA rsa = cert.GetRSAPrivateKey())
+ {
+ if (rsa == null)
+ {
+ exception = new CryptographicException(SR.Cryptography_Cms_Signing_RequiresPrivateKey);
+ return null;
+ }
+
+#if netcoreapp
+ cek = ArrayPool<byte>.Shared.Rent(rsa.KeySize / 8);
+
+ if (!rsa.TryDecrypt(_asn.EncryptedKey.Span, cek, encryptionPadding, out cekLength))
+ {
+ Debug.Fail("TryDecrypt wanted more space than the key size");
+ exception = new CryptographicException();
+ return null;
+ }
+
+ exception = null;
+ return new Span<byte>(cek, 0, cekLength).ToArray();
+#else
+ exception = null;
+ return rsa.Decrypt(_asn.EncryptedKey.Span.ToArray(), encryptionPadding);
+#endif
+ }
+ }
+ catch (CryptographicException e)
+ {
+ exception = e;
+ return null;
+ }
+ finally
+ {
+ if (cek != null)
+ {
+ Array.Clear(cek, 0, cekLength);
+ ArrayPool<byte>.Shared.Return(cek);
+ }
+ }
+ }
+ }
+
+ private static KeyTransRecipientInfoAsn MakeKtri(
+ byte[] cek,
+ CmsRecipient recipient,
+ out bool v0Recipient)
+ {
+ KeyTransRecipientInfoAsn ktri = new KeyTransRecipientInfoAsn();
+
+ if (recipient.RecipientIdentifierType == SubjectIdentifierType.SubjectKeyIdentifier)
+ {
+ ktri.Version = 2;
+ ktri.Rid.SubjectKeyIdentifier = recipient.Certificate.GetSubjectKeyIdentifier();
+ }
+ else if (recipient.RecipientIdentifierType == SubjectIdentifierType.IssuerAndSerialNumber)
+ {
+ byte[] serial = recipient.Certificate.GetSerialNumber();
+ Array.Reverse(serial);
+
+ IssuerAndSerialNumberAsn iasn = new IssuerAndSerialNumberAsn
+ {
+ Issuer = recipient.Certificate.IssuerName.RawData,
+ SerialNumber = serial,
+ };
+
+ ktri.Rid.IssuerAndSerialNumber = iasn;
+ }
+ else
+ {
+ throw new CryptographicException(
+ SR.Cryptography_Cms_Invalid_Subject_Identifier_Type,
+ recipient.RecipientIdentifierType.ToString());
+ }
+
+ RSAEncryptionPadding padding;
+
+ switch (recipient.Certificate.GetKeyAlgorithm())
+ {
+ case Oids.RsaOaep:
+ padding = RSAEncryptionPadding.OaepSHA1;
+ ktri.KeyEncryptionAlgorithm.Algorithm = new Oid(Oids.RsaOaep, Oids.RsaOaep);
+ ktri.KeyEncryptionAlgorithm.Parameters = s_rsaOaepSha1Parameters;
+ break;
+ default:
+ padding = RSAEncryptionPadding.Pkcs1;
+ ktri.KeyEncryptionAlgorithm.Algorithm = new Oid(Oids.Rsa, Oids.Rsa);
+ ktri.KeyEncryptionAlgorithm.Parameters = s_rsaPkcsParameters;
+ break;
+ }
+
+ using (RSA rsa = recipient.Certificate.GetRSAPublicKey())
+ {
+ ktri.EncryptedKey = rsa.Encrypt(cek, padding);
+ }
+
+ v0Recipient = (ktri.Version == 0);
+ return ktri;
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.cs b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.cs
new file mode 100644
index 0000000000..0e47bb29f7
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.cs
@@ -0,0 +1,176 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+using System.Security.Cryptography.Pkcs;
+using System.Security.Cryptography.Pkcs.Asn1;
+using System.Security.Cryptography.X509Certificates;
+
+namespace Internal.Cryptography.Pal.AnyOS
+{
+ internal sealed partial class ManagedPkcsPal : PkcsPal
+ {
+ public override void AddCertsFromStoreForDecryption(X509Certificate2Collection certs)
+ {
+ certs.AddRange(Helpers.GetStoreCertificates(StoreName.My, StoreLocation.CurrentUser, openExistingOnly: false));
+
+ try
+ {
+ // This store exists on macOS, but not Linux
+ certs.AddRange(
+ Helpers.GetStoreCertificates(StoreName.My, StoreLocation.LocalMachine, openExistingOnly: false));
+ }
+ catch (CryptographicException)
+ {
+ }
+ }
+
+ public override byte[] GetSubjectKeyIdentifier(X509Certificate2 certificate)
+ {
+ return certificate.GetSubjectKeyIdentifier();
+ }
+
+ public override T GetPrivateKeyForSigning<T>(X509Certificate2 certificate, bool silent)
+ {
+ return GetPrivateKey<T>(certificate);
+ }
+
+ public override T GetPrivateKeyForDecryption<T>(X509Certificate2 certificate, bool silent)
+ {
+ return GetPrivateKey<T>(certificate);
+ }
+
+ private T GetPrivateKey<T>(X509Certificate2 certificate) where T : AsymmetricAlgorithm
+ {
+ if (typeof(T) == typeof(RSA))
+ return (T)(object)certificate.GetRSAPrivateKey();
+ if (typeof(T) == typeof(ECDsa))
+ return (T)(object)certificate.GetECDsaPrivateKey();
+#if netcoreapp
+ if (typeof(T) == typeof(DSA))
+ return (T)(object)certificate.GetDSAPrivateKey();
+#endif
+
+ Debug.Fail($"Unknown key type requested: {typeof(T).FullName}");
+ return null;
+ }
+
+ private static SymmetricAlgorithm OpenAlgorithm(AlgorithmIdentifierAsn contentEncryptionAlgorithm)
+ {
+ SymmetricAlgorithm alg = OpenAlgorithm(contentEncryptionAlgorithm.Algorithm);
+
+ if (alg is RC2)
+ {
+ if (contentEncryptionAlgorithm.Parameters == null)
+ {
+ // Windows issues CRYPT_E_BAD_DECODE
+ throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+ }
+
+ Rc2CbcParameters rc2Params = AsnSerializer.Deserialize<Rc2CbcParameters>(
+ contentEncryptionAlgorithm.Parameters.Value,
+ AsnEncodingRules.BER);
+
+ alg.KeySize = rc2Params.GetEffectiveKeyBits();
+ alg.IV = rc2Params.Iv.ToArray();
+ }
+ else
+ {
+ if (contentEncryptionAlgorithm.Parameters == null)
+ {
+ // Windows issues CRYPT_E_BAD_DECODE
+ throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+ }
+
+ AsnReader reader = new AsnReader(contentEncryptionAlgorithm.Parameters.Value, AsnEncodingRules.BER);
+
+ if (reader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> primitiveBytes))
+ {
+ alg.IV = primitiveBytes.ToArray();
+ }
+ else
+ {
+ byte[] iv = new byte[alg.BlockSize / 8];
+
+ if (!reader.TryCopyOctetStringBytes(iv, out int bytesWritten) ||
+ bytesWritten != iv.Length)
+ {
+ throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+ }
+
+ alg.IV = iv;
+ }
+ }
+
+ return alg;
+ }
+
+ private static SymmetricAlgorithm OpenAlgorithm(AlgorithmIdentifier algorithmIdentifier)
+ {
+ SymmetricAlgorithm alg = OpenAlgorithm(algorithmIdentifier.Oid);
+
+ if (alg is RC2)
+ {
+ if (algorithmIdentifier.KeyLength != 0)
+ {
+ alg.KeySize = algorithmIdentifier.KeyLength;
+ }
+ else
+ {
+ alg.KeySize = KeyLengths.Rc2_128Bit;
+ }
+ }
+
+ return alg;
+ }
+
+ private static SymmetricAlgorithm OpenAlgorithm(Oid algorithmIdentifier)
+ {
+ Debug.Assert(algorithmIdentifier != null);
+
+ SymmetricAlgorithm alg;
+
+ switch (algorithmIdentifier.Value)
+ {
+ case Oids.Rc2Cbc:
+#pragma warning disable CA5351
+ alg = RC2.Create();
+#pragma warning restore CA5351
+ break;
+ case Oids.DesCbc:
+#pragma warning disable CA5351
+ alg = DES.Create();
+#pragma warning restore CA5351
+ break;
+ case Oids.TripleDesCbc:
+#pragma warning disable CA5350
+ alg = TripleDES.Create();
+#pragma warning restore CA5350
+ break;
+ case Oids.Aes128Cbc:
+ alg = Aes.Create();
+ alg.KeySize = 128;
+ break;
+ case Oids.Aes192Cbc:
+ alg = Aes.Create();
+ alg.KeySize = 192;
+ break;
+ case Oids.Aes256Cbc:
+ alg = Aes.Create();
+ alg.KeySize = 256;
+ break;
+ default:
+ throw new CryptographicException(SR.Cryptography_Cms_UnknownAlgorithm, algorithmIdentifier.Value);
+ }
+
+ // These are the defaults, but they're restated here for clarity.
+ alg.Padding = PaddingMode.PKCS7;
+ alg.Mode = CipherMode.CBC;
+ return alg;
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/PkcsPal.AnyOS.cs b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/PkcsPal.AnyOS.cs
index 919b1280a7..11e8b43f7f 100644
--- a/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/PkcsPal.AnyOS.cs
+++ b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/PkcsPal.AnyOS.cs
@@ -2,220 +2,12 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System;
-using System.Buffers;
-using System.Diagnostics;
-using System.Security.Cryptography;
-using System.Security.Cryptography.Asn1;
-using System.Security.Cryptography.Pkcs;
-using System.Security.Cryptography.X509Certificates;
+using Internal.Cryptography.Pal.AnyOS;
namespace Internal.Cryptography
{
internal abstract partial class PkcsPal
{
- private static PkcsPal s_instance = new ManagedPkcsPal();
-
- private class ManagedPkcsPal : PkcsPal
- {
- public override byte[] Encrypt(
- CmsRecipientCollection recipients,
- ContentInfo contentInfo,
- AlgorithmIdentifier contentEncryptionAlgorithm,
- X509Certificate2Collection originatorCerts,
- CryptographicAttributeObjectCollection unprotectedAttributes)
- {
- throw new PlatformNotSupportedException(SR.PlatformNotSupported_CryptographyPkcs);
- }
-
- public override DecryptorPal Decode(
- byte[] encodedMessage,
- out int version,
- out ContentInfo contentInfo,
- out AlgorithmIdentifier contentEncryptionAlgorithm,
- out X509Certificate2Collection originatorCerts,
- out CryptographicAttributeObjectCollection unprotectedAttributes)
- {
- throw new PlatformNotSupportedException(SR.PlatformNotSupported_CryptographyPkcs);
- }
-
- public override byte[] EncodeOctetString(byte[] octets)
- {
- // Write using DER to support the most readers.
- using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
- {
- writer.WriteOctetString(octets);
- return writer.Encode();
- }
- }
-
- public override byte[] DecodeOctetString(byte[] encodedOctets)
- {
- // Read using BER because the CMS specification says the encoding is BER.
- AsnReader reader = new AsnReader(encodedOctets, AsnEncodingRules.BER);
-
- const int ArbitraryStackLimit = 256;
- Span<byte> tmp = stackalloc byte[ArbitraryStackLimit];
- // Use stackalloc 0 so data can later hold a slice of tmp.
- ReadOnlySpan<byte> data = stackalloc byte[0];
- byte[] poolBytes = null;
-
- try
- {
- if (!reader.TryGetPrimitiveOctetStringBytes(out var contents))
- {
- if (reader.TryCopyOctetStringBytes(tmp, out int bytesWritten))
- {
- data = tmp.Slice(0, bytesWritten);
- }
- else
- {
- poolBytes = ArrayPool<byte>.Shared.Rent(reader.PeekContentBytes().Length);
-
- if (!reader.TryCopyOctetStringBytes(poolBytes, out bytesWritten))
- {
- Debug.Fail("TryCopyOctetStringBytes failed with a provably-large-enough buffer");
- throw new CryptographicException();
- }
-
- data = new ReadOnlySpan<byte>(poolBytes, 0, bytesWritten);
- }
- }
- else
- {
- data = contents.Span;
- }
-
- if (reader.HasData)
- {
- throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
- }
-
- return data.ToArray();
- }
- finally
- {
- if (poolBytes != null)
- {
- Array.Clear(poolBytes, 0, data.Length);
- ArrayPool<byte>.Shared.Return(poolBytes);
- }
- }
- }
-
- public override byte[] EncodeUtcTime(DateTime utcTime)
- {
- // Write using DER to support the most readers.
- using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
- {
- // Sending the DateTime through ToLocalTime here will cause the right normalization
- // of DateTimeKind.Unknown.
- //
- // Local => Local (noop) => UTC (in WriteUtcTime) (adjust, correct)
- // UTC => Local (adjust) => UTC (adjust back, correct)
- // Unknown => Local (adjust) => UTC (adjust "back", add Z marker; matches Windows)
- writer.WriteUtcTime(utcTime.ToLocalTime());
- return writer.Encode();
- }
- }
-
- public override DateTime DecodeUtcTime(byte[] encodedUtcTime)
- {
- // Read using BER because the CMS specification says the encoding is BER.
- AsnReader reader = new AsnReader(encodedUtcTime, AsnEncodingRules.BER);
- DateTimeOffset value = reader.GetUtcTime();
-
- if (reader.HasData)
- {
- throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
- }
-
- return value.UtcDateTime;
- }
-
- public override string DecodeOid(byte[] encodedOid)
- {
- Span<byte> emptyInvalidOid = stackalloc byte[2];
- emptyInvalidOid[0] = 0x06;
- emptyInvalidOid[1] = 0x00;
-
- // Windows compat.
- if (emptyInvalidOid.SequenceEqual(encodedOid))
- {
- return string.Empty;
- }
-
- // Read using BER because the CMS specification says the encoding is BER.
- AsnReader reader = new AsnReader(encodedOid, AsnEncodingRules.BER);
- string value = reader.ReadObjectIdentifierAsString();
-
- if (reader.HasData)
- {
- throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
- }
-
- return value;
- }
-
- public override Oid GetEncodedMessageType(byte[] encodedMessage)
- {
- throw new PlatformNotSupportedException(SR.PlatformNotSupported_CryptographyPkcs);
- }
-
- public override void AddCertsFromStoreForDecryption(X509Certificate2Collection certs)
- {
- throw new PlatformNotSupportedException(SR.PlatformNotSupported_CryptographyPkcs);
- }
-
- public override Exception CreateRecipientsNotFoundException()
- {
- throw new PlatformNotSupportedException(SR.PlatformNotSupported_CryptographyPkcs);
- }
-
- public override Exception CreateRecipientInfosAfterEncryptException()
- {
- throw new PlatformNotSupportedException(SR.PlatformNotSupported_CryptographyPkcs);
- }
-
- public override Exception CreateDecryptAfterEncryptException()
- {
- throw new PlatformNotSupportedException(SR.PlatformNotSupported_CryptographyPkcs);
- }
-
- public override Exception CreateDecryptTwiceException()
- {
- throw new PlatformNotSupportedException(SR.PlatformNotSupported_CryptographyPkcs);
- }
-
- public override byte[] GetSubjectKeyIdentifier(X509Certificate2 certificate)
- {
- return certificate.GetSubjectKeyIdentifier();
- }
-
- public override T GetPrivateKeyForSigning<T>(X509Certificate2 certificate, bool silent)
- {
- return GetPrivateKey<T>(certificate);
- }
-
- public override T GetPrivateKeyForDecryption<T>(X509Certificate2 certificate, bool silent)
- {
- return GetPrivateKey<T>(certificate);
- }
-
- private T GetPrivateKey<T>(X509Certificate2 certificate) where T : AsymmetricAlgorithm
- {
- if (typeof(T) == typeof(RSA))
- return (T)(object)certificate.GetRSAPrivateKey();
- if (typeof(T) == typeof(ECDsa))
- return (T)(object)certificate.GetECDsaPrivateKey();
-#if netcoreapp
- if (typeof(T) == typeof(DSA))
- return (T)(object)certificate.GetDSAPrivateKey();
-#endif
-
- Debug.Fail($"Unknown key type requested: {typeof(T).FullName}");
- return null;
- }
- }
+ private static readonly PkcsPal s_instance = new ManagedPkcsPal();
}
}
diff --git a/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/Windows/HelpersWindows.cs b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/Windows/HelpersWindows.cs
index 4dc1252a8f..790990c4f3 100644
--- a/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/Windows/HelpersWindows.cs
+++ b/src/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/Windows/HelpersWindows.cs
@@ -359,7 +359,7 @@ namespace Internal.Cryptography.Pal.Windows
throw new CryptographicException();
}
- int provType = BinaryPrimitives.ReadMachineEndian<int>(stackSpan.Slice(0, size));
+ int provType = MemoryMarshal.Read<int>(stackSpan.Slice(0, size));
size = stackSpan.Length;
if (!Interop.Advapi32.CryptGetProvParam(handle, CryptProvParam.PP_KEYSET_TYPE, stackSpan, ref size))
@@ -373,7 +373,7 @@ namespace Internal.Cryptography.Pal.Windows
throw new CryptographicException();
}
- int keysetType = BinaryPrimitives.ReadMachineEndian<int>(stackSpan.Slice(0, size));
+ int keysetType = MemoryMarshal.Read<int>(stackSpan.Slice(0, size));
// Only CRYPT_MACHINE_KEYSET is described as coming back, but be defensive.
CspProviderFlags provFlags =
diff --git a/src/System.Security.Cryptography.Pkcs/src/MatchingRefApiCompatBaseline.netstandard.txt b/src/System.Security.Cryptography.Pkcs/src/MatchingRefApiCompatBaseline.netstandard.txt
new file mode 100644
index 0000000000..c89f8fff9f
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/MatchingRefApiCompatBaseline.netstandard.txt
@@ -0,0 +1,3 @@
+# These members don't belong in netstandard reference because of type unification with netfx (the members are new in net472).
+MembersMustExist : Member 'System.Security.Cryptography.Pkcs.SignerInfo.GetSignature()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Security.Cryptography.Pkcs.SignerInfo.SignatureAlgorithm.get()' does not exist in the implementation but it does exist in the contract.
diff --git a/src/System.Security.Cryptography.Pkcs/src/Resources/Strings.resx b/src/System.Security.Cryptography.Pkcs/src/Resources/Strings.resx
index a755844916..70849195a7 100644
--- a/src/System.Security.Cryptography.Pkcs/src/Resources/Strings.resx
+++ b/src/System.Security.Cryptography.Pkcs/src/Resources/Strings.resx
@@ -199,6 +199,12 @@
<data name="Cryptography_Cms_NoSignerAtIndex" xml:space="preserve">
<value>The signed cryptographic message does not have a signer for the specified signer index.</value>
</data>
+ <data name="Cryptography_Cms_RecipientNotFound" xml:space="preserve">
+ <value>The enveloped-data message does not contain the specified recipient.</value>
+ </data>
+ <data name="Cryptography_Cms_RecipientType_NotSupported" xml:space="preserve">
+ <value>The recipient type '{0}' is not supported for encryption or decryption on this platform.</value>
+ </data>
<data name="Cryptography_Cms_Sign_Empty_Content" xml:space="preserve">
<value>Cannot create CMS signature for empty content.</value>
</data>
@@ -244,6 +250,21 @@
<data name="Cryptography_Pkcs_PssParametersSaltMismatch" xml:space="preserve">
<value>PSS salt size {0} is not supported by this platform with hash algorithm {1}.</value>
</data>
+ <data name="Cryptography_TimestampReq_BadNonce" xml:space="preserve">
+ <value>The response from the timestamping server did not match the request nonce.</value>
+ </data>
+ <data name="Cryptography_TimestampReq_BadResponse" xml:space="preserve">
+ <value>The response from the timestamping server was not understood.</value>
+ </data>
+ <data name="Cryptography_TimestampReq_Failure" xml:space="preserve">
+ <value>The timestamping server did not grant the request. The request status is '{0}' with failure info '{1}'.</value>
+ </data>
+ <data name="Cryptography_TimestampReq_NoCertFound" xml:space="preserve">
+ <value>The timestamping request required the TSA certificate in the response, but it was not found.</value>
+ </data>
+ <data name="Cryptography_TimestampReq_UnexpectedCertFound" xml:space="preserve">
+ <value>The timestamping request required the TSA certificate not be included in the response, but certificates were present.</value>
+ </data>
<data name="InvalidOperation_DuplicateItemNotAllowed" xml:space="preserve">
<value>Duplicate items are not allowed in the collection.</value>
</data>
diff --git a/src/System.Security.Cryptography.Pkcs/src/System.Security.Cryptography.Pkcs.csproj b/src/System.Security.Cryptography.Pkcs/src/System.Security.Cryptography.Pkcs.csproj
index b02bd42ac4..c26a748287 100644
--- a/src/System.Security.Cryptography.Pkcs/src/System.Security.Cryptography.Pkcs.csproj
+++ b/src/System.Security.Cryptography.Pkcs/src/System.Security.Cryptography.Pkcs.csproj
@@ -175,7 +175,30 @@
</ItemGroup>
<!-- Internal types (platform: AnyOS) -->
<ItemGroup Condition="'$(TargetsWindows)' != 'true' AND '$(IsPartialFacadeAssembly)' != 'true'">
+ <Compile Include="Internal\Cryptography\Pal\AnyOS\AsnHelpers.cs" />
+ <Compile Include="Internal\Cryptography\Pal\AnyOS\ManagedPal.cs" />
+ <Compile Include="Internal\Cryptography\Pal\AnyOS\ManagedPal.Asn.cs" />
+ <Compile Include="Internal\Cryptography\Pal\AnyOS\ManagedPal.Decode.cs" />
+ <Compile Include="Internal\Cryptography\Pal\AnyOS\ManagedPal.Decrypt.cs" />
+ <Compile Include="Internal\Cryptography\Pal\AnyOS\ManagedPal.Encrypt.cs" />
+ <Compile Include="Internal\Cryptography\Pal\AnyOS\ManagedPal.Exceptions.cs" />
+ <Compile Include="Internal\Cryptography\Pal\AnyOS\ManagedPal.KeyAgree.cs" />
+ <Compile Include="Internal\Cryptography\Pal\AnyOS\ManagedPal.KeyTrans.cs" />
<Compile Include="Internal\Cryptography\Pal\AnyOS\PkcsPal.AnyOS.cs" />
+ <Compile Include="System\Security\Cryptography\Pkcs\Asn1\EncryptedContentInfoAsn.cs" />
+ <Compile Include="System\Security\Cryptography\Pkcs\Asn1\EnvelopedDataAsn.cs" />
+ <Compile Include="System\Security\Cryptography\Pkcs\Asn1\KeyAgreeRecipientIdentifierAsn.cs" />
+ <Compile Include="System\Security\Cryptography\Pkcs\Asn1\KeyAgreeRecipientInfoAsn.cs" />
+ <Compile Include="System\Security\Cryptography\Pkcs\Asn1\KeyTransRecipientInfoAsn.cs" />
+ <Compile Include="System\Security\Cryptography\Pkcs\Asn1\OriginatorIdentifierOrKeyAsn.cs" />
+ <Compile Include="System\Security\Cryptography\Pkcs\Asn1\OriginatorInfoAsn.cs" />
+ <Compile Include="System\Security\Cryptography\Pkcs\Asn1\OriginatorPublicKeyAsn.cs" />
+ <Compile Include="System\Security\Cryptography\Pkcs\Asn1\OtherKeyAttributeAsn.cs" />
+ <Compile Include="System\Security\Cryptography\Pkcs\Asn1\Rc2CbcParameters.cs" />
+ <Compile Include="System\Security\Cryptography\Pkcs\Asn1\RecipientEncryptedKeyAsn.cs" />
+ <Compile Include="System\Security\Cryptography\Pkcs\Asn1\RecipientIdentifierAsn.cs" />
+ <Compile Include="System\Security\Cryptography\Pkcs\Asn1\RecipientInfoAsn.cs" />
+ <Compile Include="System\Security\Cryptography\Pkcs\Asn1\RecipientKeyIdentifier.cs" />
</ItemGroup>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' == 'true'">
<Reference Include="mscorlib" />
@@ -225,11 +248,19 @@
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\CertificateChoiceAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\ContentInfoAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\EncapsulatedContentInfoAsn.cs" />
+ <Compile Include="System\Security\Cryptography\Pkcs\Asn1\GeneralName.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\IssuerAndSerialNumberAsn.cs" />
+ <Compile Include="System\Security\Cryptography\Pkcs\Asn1\MessageImprint.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\PssParamsAsn.cs" />
+ <Compile Include="System\Security\Cryptography\Pkcs\Asn1\Rfc3161Accuracy.cs" />
+ <Compile Include="System\Security\Cryptography\Pkcs\Asn1\Rfc3161TimeStampReq.cs" />
+ <Compile Include="System\Security\Cryptography\Pkcs\Asn1\Rfc3161TimeStampResp.cs" />
+ <Compile Include="System\Security\Cryptography\Pkcs\Asn1\Rfc3161TstInfo.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\SignedDataAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\SignerIdentifierAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\Asn1\SignerInfoAsn.cs" />
+ <Compile Include="System\Security\Cryptography\Pkcs\Asn1\SigningCertificateAsn.cs" />
+ <Compile Include="System\Security\Cryptography\Pkcs\Asn1\X509ExtensionAsn.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\CmsSignature.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\CmsSignature.ECDsa.cs" />
<Compile Include="System\Security\Cryptography\Pkcs\CmsSignature.RSA.cs" />
@@ -242,6 +273,10 @@
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp'">
<Compile Include="System\Security\Cryptography\Pkcs\CmsSignature.DSA.cs" />
+ <Compile Include="System\Security\Cryptography\Pkcs\Rfc3161RequestResponseStatus.cs" />
+ <Compile Include="System\Security\Cryptography\Pkcs\Rfc3161TimestampRequest.cs" />
+ <Compile Include="System\Security\Cryptography\Pkcs\Rfc3161TimestampToken.cs" />
+ <Compile Include="System\Security\Cryptography\Pkcs\Rfc3161TimestampTokenInfo.cs" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/AlgorithmIdentifierAsn.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/AlgorithmIdentifierAsn.cs
index 575dbb2a5d..47ad9dea35 100644
--- a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/AlgorithmIdentifierAsn.cs
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/AlgorithmIdentifierAsn.cs
@@ -15,6 +15,8 @@ namespace System.Security.Cryptography.Pkcs.Asn1
// parameters ANY DEFINED BY algorithm OPTIONAL }
internal struct AlgorithmIdentifierAsn
{
+ internal static readonly ReadOnlyMemory<byte> ExplicitDerNull = new byte[] { 0x05, 0x00 };
+
[ObjectIdentifier(PopulateFriendlyName = true)]
public Oid Algorithm;
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/EncryptedContentInfoAsn.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/EncryptedContentInfoAsn.cs
new file mode 100644
index 0000000000..a190523804
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/EncryptedContentInfoAsn.cs
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Pkcs.Asn1
+{
+ // https://tools.ietf.org/html/rfc5652#section-6.1
+ //
+ // EncryptedContentInfo ::= SEQUENCE {
+ // contentType ContentType,
+ // contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+ // encryptedContent[0] IMPLICIT EncryptedContent OPTIONAL }
+ //
+ // https://tools.ietf.org/html/rfc5652#section-11.1
+ //
+ // ContentType ::= OBJECT IDENTIFIER
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct EncryptedContentInfoAsn
+ {
+ [ObjectIdentifier]
+ internal string ContentType;
+
+ internal AlgorithmIdentifierAsn ContentEncryptionAlgorithm;
+
+ [OptionalValue]
+ [OctetString]
+ [ExpectedTag(0)]
+ internal ReadOnlyMemory<byte>? EncryptedContent;
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/EnvelopedDataAsn.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/EnvelopedDataAsn.cs
new file mode 100644
index 0000000000..652cc7cba7
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/EnvelopedDataAsn.cs
@@ -0,0 +1,39 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Pkcs.Asn1
+{
+ // https://tools.ietf.org/html/rfc5652#section-6.1
+ //
+ // EnvelopedData ::= SEQUENCE {
+ // version CMSVersion,
+ // originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+ // recipientInfos RecipientInfos,
+ // encryptedContentInfo EncryptedContentInfo,
+ // unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL }
+ //
+ // RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct EnvelopedDataAsn
+ {
+ public int Version;
+
+ [OptionalValue]
+ [ExpectedTag(0)]
+ public OriginatorInfoAsn OriginatorInfo;
+
+ [SetOf]
+ public RecipientInfoAsn[] RecipientInfos;
+
+ public EncryptedContentInfoAsn EncryptedContentInfo;
+
+ [ExpectedTag(1)]
+ [SetOf]
+ [OptionalValue]
+ public AttributeAsn[] UnprotectedAttributes;
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/GeneralName.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/GeneralName.cs
new file mode 100644
index 0000000000..f5895c9b17
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/GeneralName.cs
@@ -0,0 +1,87 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Pkcs.Asn1
+{
+ [Choice]
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct GeneralName
+ {
+ [ExpectedTag(0, ExplicitTag = true)]
+ internal OtherName? OtherName;
+
+ [ExpectedTag(1, ExplicitTag = true)]
+ [IA5String]
+ internal string Rfc822Name;
+
+ [ExpectedTag(2, ExplicitTag = true)]
+ [IA5String]
+ internal string DnsName;
+
+ [ExpectedTag(3, ExplicitTag = true)]
+ [AnyValue]
+ internal ReadOnlyMemory<byte>? X400Address;
+
+ [ExpectedTag(4, ExplicitTag = true)]
+ [AnyValue]
+ internal ReadOnlyMemory<byte>? DirectoryName;
+
+ [ExpectedTag(5, ExplicitTag = true)]
+ internal EdiPartyName? EdiPartyName;
+
+ [ExpectedTag(6, ExplicitTag = true)]
+ [IA5String]
+ internal string Uri;
+
+ [ExpectedTag(7, ExplicitTag = true)]
+ [OctetString]
+ internal ReadOnlyMemory<byte>? IPAddress;
+
+ [ExpectedTag(8, ExplicitTag = true)]
+ [ObjectIdentifier]
+ internal string RegisteredId;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct OtherName
+ {
+ internal string TypeId;
+
+ [ExpectedTag(0, ExplicitTag = true)]
+ [AnyValue]
+ internal ReadOnlyMemory<byte> Value;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct EdiPartyName
+ {
+ [OptionalValue]
+ internal DirectoryString? NameAssigner;
+
+ internal DirectoryString PartyName;
+ }
+
+ [Choice]
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct DirectoryString
+ {
+ [ExpectedTag(TagClass.Universal, (int)UniversalTagNumber.TeletexString)]
+ internal ReadOnlyMemory<byte>? TeletexString;
+
+ [PrintableString]
+ internal string PrintableString;
+
+ [ExpectedTag(TagClass.Universal, (int)UniversalTagNumber.UniversalString)]
+ internal ReadOnlyMemory<byte>? UniversalString;
+
+ [UTF8String]
+ internal string Utf8String;
+
+ [BMPString]
+ internal string BMPString;
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/KeyAgreeRecipientIdentifierAsn.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/KeyAgreeRecipientIdentifierAsn.cs
new file mode 100644
index 0000000000..9fb175717d
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/KeyAgreeRecipientIdentifierAsn.cs
@@ -0,0 +1,24 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Pkcs.Asn1
+{
+ // https://tools.ietf.org/html/rfc5652#section-6.2.2
+ //
+ // KeyAgreeRecipientIdentifier ::= CHOICE {
+ // issuerAndSerialNumber IssuerAndSerialNumber,
+ // rKeyId[0] IMPLICIT RecipientKeyIdentifier }
+ [Choice]
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct KeyAgreeRecipientIdentifierAsn
+ {
+ internal IssuerAndSerialNumberAsn? IssuerAndSerialNumber;
+
+ [ExpectedTag(0)]
+ internal RecipientKeyIdentifier RKeyId;
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/KeyAgreeRecipientInfoAsn.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/KeyAgreeRecipientInfoAsn.cs
new file mode 100644
index 0000000000..bdd89fe9b4
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/KeyAgreeRecipientInfoAsn.cs
@@ -0,0 +1,39 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Pkcs.Asn1
+{
+ // https://tools.ietf.org/html/rfc5652#section-6.2.2
+ //
+ // KeyAgreeRecipientInfo ::= SEQUENCE {
+ // version CMSVersion, -- always set to 3
+ // originator[0] EXPLICIT OriginatorIdentifierOrKey,
+ // ukm[1] EXPLICIT UserKeyingMaterial OPTIONAL,
+ // keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+ // recipientEncryptedKeys RecipientEncryptedKeys }
+ //
+ // https://tools.ietf.org/html/rfc5652#section-10.2.6
+ //
+ // UserKeyingMaterial ::= OCTET STRING
+ [StructLayout(LayoutKind.Sequential)]
+ internal sealed class KeyAgreeRecipientInfoAsn
+ {
+ internal int Version;
+
+ [ExpectedTag(0, ExplicitTag = true)]
+ internal OriginatorIdentifierOrKeyAsn Originator;
+
+ [OptionalValue]
+ [ExpectedTag(1, ExplicitTag = true)]
+ [OctetString]
+ internal ReadOnlyMemory<byte>? Ukm;
+
+ internal AlgorithmIdentifierAsn KeyEncryptionAlgorithm;
+
+ internal RecipientEncryptedKeyAsn[] RecipientEncryptedKeys;
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/KeyTransRecipientInfoAsn.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/KeyTransRecipientInfoAsn.cs
new file mode 100644
index 0000000000..f9fbe258fa
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/KeyTransRecipientInfoAsn.cs
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Pkcs.Asn1
+{
+ // https://tools.ietf.org/html/rfc5652#section-6.2.1
+ //
+ // KeyTransRecipientInfo ::= SEQUENCE {
+ // version CMSVersion, -- always set to 0 or 2
+ // rid RecipientIdentifier,
+ // keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+ // encryptedKey EncryptedKey }
+ //
+ // https://tools.ietf.org/html/rfc5652#section-6.2
+ //
+ // EncryptedKey ::= OCTET STRING
+ [StructLayout(LayoutKind.Sequential)]
+ internal sealed class KeyTransRecipientInfoAsn
+ {
+ internal int Version;
+
+ internal RecipientIdentifierAsn Rid;
+
+ internal AlgorithmIdentifierAsn KeyEncryptionAlgorithm;
+
+ [OctetString]
+ internal ReadOnlyMemory<byte> EncryptedKey;
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/MessageImprint.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/MessageImprint.cs
new file mode 100644
index 0000000000..0d363892b3
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/MessageImprint.cs
@@ -0,0 +1,23 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Pkcs.Asn1
+{
+ // https://tools.ietf.org/html/rfc3161#section-2.4.1
+ //
+ // MessageImprint::= SEQUENCE {
+ // hashAlgorithm AlgorithmIdentifier,
+ // hashedMessage OCTET STRING }
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct MessageImprint
+ {
+ internal AlgorithmIdentifierAsn HashAlgorithm;
+
+ [OctetString]
+ internal ReadOnlyMemory<byte> HashedMessage;
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/OriginatorIdentifierOrKeyAsn.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/OriginatorIdentifierOrKeyAsn.cs
new file mode 100644
index 0000000000..b983ff633b
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/OriginatorIdentifierOrKeyAsn.cs
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Pkcs.Asn1
+{
+ // https://tools.ietf.org/html/rfc5652#section-6.2.2
+ //
+ // OriginatorIdentifierOrKey ::= CHOICE {
+ // issuerAndSerialNumber IssuerAndSerialNumber,
+ // subjectKeyIdentifier[0] SubjectKeyIdentifier,
+ // originatorKey[1] OriginatorPublicKey }
+ //
+ // DEFINITIONS IMPLICIT TAGS, so [0] is [0] IMPLICIT, and [1] is [1] IMPLICIT
+ [StructLayout(LayoutKind.Sequential)]
+ [Choice]
+ internal struct OriginatorIdentifierOrKeyAsn
+ {
+ internal IssuerAndSerialNumberAsn? IssuerAndSerialNumber;
+
+ [OctetString]
+ [ExpectedTag(0)]
+ internal ReadOnlyMemory<byte>? SubjectKeyIdentifier;
+
+ [ExpectedTag(1)]
+ internal OriginatorPublicKeyAsn OriginatorKey;
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/OriginatorInfoAsn.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/OriginatorInfoAsn.cs
new file mode 100644
index 0000000000..09c3793d7d
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/OriginatorInfoAsn.cs
@@ -0,0 +1,28 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Pkcs.Asn1
+{
+ // https://tools.ietf.org/html/rfc5652#section-6.1
+ //
+ // OriginatorInfo ::= SEQUENCE {
+ // certs[0] IMPLICIT CertificateSet OPTIONAL,
+ // crls[1] IMPLICIT RevocationInfoChoices OPTIONAL }
+ [StructLayout(LayoutKind.Sequential)]
+ internal sealed class OriginatorInfoAsn
+ {
+ [OptionalValue]
+ [ExpectedTag(0)]
+ [SetOf]
+ public CertificateChoiceAsn[] CertificateSet;
+
+ [OptionalValue]
+ [ExpectedTag(1)]
+ [AnyValue]
+ public ReadOnlyMemory<byte>? RevocationInfoChoices;
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/OriginatorPublicKeyAsn.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/OriginatorPublicKeyAsn.cs
new file mode 100644
index 0000000000..6d8535a8d4
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/OriginatorPublicKeyAsn.cs
@@ -0,0 +1,23 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Pkcs.Asn1
+{
+ // https://tools.ietf.org/html/rfc5652#section-6.2.2
+ //
+ // OriginatorPublicKey ::= SEQUENCE {
+ // algorithm AlgorithmIdentifier,
+ // publicKey BIT STRING }
+ [StructLayout(LayoutKind.Sequential)]
+ internal sealed class OriginatorPublicKeyAsn
+ {
+ internal AlgorithmIdentifierAsn Algorithm;
+
+ [BitString]
+ internal ReadOnlyMemory<byte> PublicKey;
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/OtherKeyAttributeAsn.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/OtherKeyAttributeAsn.cs
new file mode 100644
index 0000000000..5f2d7968a8
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/OtherKeyAttributeAsn.cs
@@ -0,0 +1,25 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Pkcs.Asn1
+{
+ // https://tools.ietf.org/html/rfc5652#section-10.2.7
+ //
+ // OtherKeyAttribute ::= SEQUENCE {
+ // keyAttrId OBJECT IDENTIFIER,
+ // keyAttr ANY DEFINED BY keyAttrId OPTIONAL }
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct OtherKeyAttributeAsn
+ {
+ [ObjectIdentifier]
+ internal string KeyAttrId;
+
+ [OptionalValue]
+ [AnyValue]
+ internal ReadOnlyMemory<byte>? KeyAttr;
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rc2CbcParameters.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rc2CbcParameters.cs
new file mode 100644
index 0000000000..3f076c4a4e
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rc2CbcParameters.cs
@@ -0,0 +1,80 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Pkcs.Asn1
+{
+ // https://tools.ietf.org/html/rfc3370#section-5.2 (CMS Algorithms, RC2-CBC) says
+ //
+ // The AlgorithmIdentifier parameters field MUST be present, and the
+ // parameters field MUST contain a RC2CBCParameter:
+ //
+ // RC2CBCParameter ::= SEQUENCE {
+ // rc2ParameterVersion INTEGER,
+ // iv OCTET STRING } -- exactly 8 octets
+ //
+ // It then effectively says "see RFC2268" for the version.
+ //
+ // https://tools.ietf.org/html/rfc2268#section-6 provides the table (EkbEncoding),
+ // and provides a different structure for "RC2-CBCParameter" (with a hyphen in this name).
+ //
+ // The RFC3370 structure is the second CHOICE option for RC2-CBCParameter (it has no name).
+ // Since 3370 says to just use that alternative there's no fallback in this code for handling
+ // just an IV which means that an effective key size of 32-bits has been chosen. Since 40-bit is the
+ // smallest supported by .NET that's not really a problem.
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct Rc2CbcParameters
+ {
+ private static readonly byte[] s_rc2EkbEncoding =
+ {
+ 0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a, 0xb0, 0x93, 0xd1, 0x9c, 0x1b, 0x33, 0xfd, 0xd0,
+ 0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b, 0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a,
+ 0x41, 0x9f, 0xe1, 0xd9, 0x4a, 0x4d, 0x9e, 0xda, 0xa0, 0x68, 0x2c, 0xc3, 0x27, 0x5f, 0x80, 0x36,
+ 0x3e, 0xee, 0xfb, 0x95, 0x1a, 0xfe, 0xce, 0xa8, 0x34, 0xa9, 0x13, 0xf0, 0xa6, 0x3f, 0xd8, 0x0c,
+ 0x78, 0x24, 0xaf, 0x23, 0x52, 0xc1, 0x67, 0x17, 0xf5, 0x66, 0x90, 0xe7, 0xe8, 0x07, 0xb8, 0x60,
+ 0x48, 0xe6, 0x1e, 0x53, 0xf3, 0x92, 0xa4, 0x72, 0x8c, 0x08, 0x15, 0x6e, 0x86, 0x00, 0x84, 0xfa,
+ 0xf4, 0x7f, 0x8a, 0x42, 0x19, 0xf6, 0xdb, 0xcd, 0x14, 0x8d, 0x50, 0x12, 0xba, 0x3c, 0x06, 0x4e,
+ 0xec, 0xb3, 0x35, 0x11, 0xa1, 0x88, 0x8e, 0x2b, 0x94, 0x99, 0xb7, 0x71, 0x74, 0xd3, 0xe4, 0xbf,
+ 0x3a, 0xde, 0x96, 0x0e, 0xbc, 0x0a, 0xed, 0x77, 0xfc, 0x37, 0x6b, 0x03, 0x79, 0x89, 0x62, 0xc6,
+ 0xd7, 0xc0, 0xd2, 0x7c, 0x6a, 0x8b, 0x22, 0xa3, 0x5b, 0x05, 0x5d, 0x02, 0x75, 0xd5, 0x61, 0xe3,
+ 0x18, 0x8f, 0x55, 0x51, 0xad, 0x1f, 0x0b, 0x5e, 0x85, 0xe5, 0xc2, 0x57, 0x63, 0xca, 0x3d, 0x6c,
+ 0xb4, 0xc5, 0xcc, 0x70, 0xb2, 0x91, 0x59, 0x0d, 0x47, 0x20, 0xc8, 0x4f, 0x58, 0xe0, 0x01, 0xe2,
+ 0x16, 0x38, 0xc4, 0x6f, 0x3b, 0x0f, 0x65, 0x46, 0xbe, 0x7e, 0x2d, 0x7b, 0x82, 0xf9, 0x40, 0xb5,
+ 0x1d, 0x73, 0xf8, 0xeb, 0x26, 0xc7, 0x87, 0x97, 0x25, 0x54, 0xb1, 0x28, 0xaa, 0x98, 0x9d, 0xa5,
+ 0x64, 0x6d, 0x7a, 0xd4, 0x10, 0x81, 0x44, 0xef, 0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f,
+ 0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf, 0x29, 0x39, 0xb9, 0xe9, 0x4c, 0xff, 0x43, 0xab,
+ };
+
+ internal int Rc2Version;
+
+ [OctetString]
+ internal ReadOnlyMemory<byte> Iv;
+
+ internal Rc2CbcParameters(ReadOnlyMemory<byte> iv, int keySize)
+ {
+ if (keySize > byte.MaxValue)
+ {
+ Rc2Version = keySize;
+ }
+ else
+ {
+ Rc2Version = s_rc2EkbEncoding[keySize];
+ }
+
+ Iv = iv;
+ }
+
+ internal int GetEffectiveKeyBits()
+ {
+ if (Rc2Version > byte.MaxValue)
+ {
+ return Rc2Version;
+ }
+
+ return Array.IndexOf(s_rc2EkbEncoding, (byte)Rc2Version);
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientEncryptedKeyAsn.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientEncryptedKeyAsn.cs
new file mode 100644
index 0000000000..a80537a261
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientEncryptedKeyAsn.cs
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Pkcs.Asn1
+{
+ // https://tools.ietf.org/html/rfc5652#section-6.2.2
+ //
+ // RecipientEncryptedKey ::= SEQUENCE {
+ // rid KeyAgreeRecipientIdentifier,
+ // encryptedKey EncryptedKey }
+ //
+ // https://tools.ietf.org/html/rfc5652#section-6.2
+ //
+ // EncryptedKey ::= OCTET STRING
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct RecipientEncryptedKeyAsn
+ {
+ internal KeyAgreeRecipientIdentifierAsn Rid;
+
+ [OctetString]
+ internal ReadOnlyMemory<byte> EncryptedKey;
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientIdentifierAsn.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientIdentifierAsn.cs
new file mode 100644
index 0000000000..48eda4c305
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientIdentifierAsn.cs
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Pkcs.Asn1
+{
+ // https://tools.ietf.org/html/rfc5652#section-6.2.1
+ //
+ // RecipientIdentifier ::= CHOICE {
+ // issuerAndSerialNumber IssuerAndSerialNumber,
+ // subjectKeyIdentifier[0] SubjectKeyIdentifier }
+ //
+ // DEFINITIONS IMPLICIT TAGS, so [0] is [0] IMPLICIT
+ [StructLayout(LayoutKind.Sequential)]
+ [Choice]
+ internal struct RecipientIdentifierAsn
+ {
+ internal IssuerAndSerialNumberAsn? IssuerAndSerialNumber;
+
+ [OctetString]
+ [ExpectedTag(0)]
+ internal ReadOnlyMemory<byte>? SubjectKeyIdentifier;
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientInfoAsn.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientInfoAsn.cs
new file mode 100644
index 0000000000..465c5c0a02
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientInfoAsn.cs
@@ -0,0 +1,30 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Pkcs.Asn1
+{
+ // https://tools.ietf.org/html/rfc5652#section-6.2
+ //
+ // RecipientInfo ::= CHOICE {
+ // ktri KeyTransRecipientInfo,
+ // kari[1] KeyAgreeRecipientInfo,
+ // kekri[2] KEKRecipientInfo,
+ // pwri[3] PasswordRecipientinfo,
+ // ori[4] OtherRecipientInfo }
+ [StructLayout(LayoutKind.Sequential)]
+ [Choice]
+ internal struct RecipientInfoAsn
+ {
+ internal KeyTransRecipientInfoAsn Ktri;
+
+ [ExpectedTag(1)]
+ internal KeyAgreeRecipientInfoAsn Kari;
+
+ // By not declaring the rest of the types here we get an ASN deserialization
+ // error for unsupported recipient types
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientKeyIdentifier.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientKeyIdentifier.cs
new file mode 100644
index 0000000000..9036a57310
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientKeyIdentifier.cs
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Pkcs.Asn1
+{
+ // https://tools.ietf.org/html/rfc5652#section-6.2.2
+ //
+ // RecipientKeyIdentifier ::= SEQUENCE {
+ // subjectKeyIdentifier SubjectKeyIdentifier,
+ // date GeneralizedTime OPTIONAL,
+ // other OtherKeyAttribute OPTIONAL }
+ //
+ // SubjectKeyIdentifier ::= OCTET STRING
+ [StructLayout(LayoutKind.Sequential)]
+ internal sealed class RecipientKeyIdentifier
+ {
+ [OctetString]
+ internal ReadOnlyMemory<byte> SubjectKeyIdentifier;
+
+ [OptionalValue]
+ [GeneralizedTime]
+ internal DateTimeOffset? Date;
+
+ [OptionalValue]
+ internal OtherKeyAttributeAsn? Other;
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161Accuracy.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161Accuracy.cs
new file mode 100644
index 0000000000..4ba16e4b74
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161Accuracy.cs
@@ -0,0 +1,77 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Pkcs.Asn1
+{
+ // https://tools.ietf.org/html/rfc3161#section-2.4.2
+ //
+ // Accuracy ::= SEQUENCE {
+ // seconds INTEGER OPTIONAL,
+ // millis[0] INTEGER(1..999) OPTIONAL,
+ // micros[1] INTEGER(1..999) OPTIONAL }
+ //
+ // And the ASN.1 module starts as
+ // DEFINITIONS IMPLICIT TAGS
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct Rfc3161Accuracy
+ {
+ [OptionalValue]
+ internal int? Seconds;
+
+ [ExpectedTag(0)]
+ [OptionalValue]
+ internal int? Millis;
+
+ [ExpectedTag(1)]
+ [OptionalValue]
+ internal int? Micros;
+
+ // Parameter name (and exception) match the Rfc3161TimestampTokenInfo ctor.
+ internal Rfc3161Accuracy(long accuracyInMicroseconds)
+ {
+ if (accuracyInMicroseconds < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(accuracyInMicroseconds));
+ }
+
+ long totalMillis = Math.DivRem(accuracyInMicroseconds, 1000, out long micros);
+ long seconds = Math.DivRem(totalMillis, 1000, out long millis);
+
+ if (seconds != 0)
+ {
+ Seconds = checked((int)seconds);
+ }
+ else
+ {
+ Seconds = null;
+ }
+
+ if (millis != 0)
+ {
+ Millis = (int)millis;
+ }
+ else
+ {
+ Millis = null;
+ }
+
+ if (micros != 0)
+ {
+ Micros = (int)micros;
+ }
+ else
+ {
+ Micros = null;
+ }
+ }
+
+ internal long TotalMicros =>
+ 1_000_000L * Seconds.GetValueOrDefault() +
+ 1000L * Millis.GetValueOrDefault() +
+ Micros.GetValueOrDefault();
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TimeStampReq.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TimeStampReq.cs
new file mode 100644
index 0000000000..236520b363
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TimeStampReq.cs
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Pkcs.Asn1
+{
+ // https://tools.ietf.org/html/rfc3161#section-2.4.1
+ //
+ // TimeStampReq ::= SEQUENCE {
+ // version INTEGER { v1(1) },
+ // messageImprint MessageImprint,
+ // --a hash algorithm OID and the hash value of the data to be
+ // --time-stamped
+ // reqPolicy TSAPolicyId OPTIONAL,
+ // nonce INTEGER OPTIONAL,
+ // certReq BOOLEAN DEFAULT FALSE,
+ // extensions [0] IMPLICIT Extensions OPTIONAL }
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct Rfc3161TimeStampReq
+ {
+ public int Version;
+
+ public MessageImprint MessageImprint;
+
+ [OptionalValue]
+ public Oid ReqPolicy;
+
+ [OptionalValue]
+ [Integer]
+ public ReadOnlyMemory<byte>? Nonce;
+
+#pragma warning disable CS3016
+ [DefaultValue(0x01, 0x01, 0x00)]
+#pragma warning restore CS3016
+ public bool CertReq;
+
+ [ExpectedTag(0)]
+ [OptionalValue]
+ internal X509ExtensionAsn[] Extensions;
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TimeStampResp.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TimeStampResp.cs
new file mode 100644
index 0000000000..d05e9ab269
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TimeStampResp.cs
@@ -0,0 +1,76 @@
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Pkcs.Asn1
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct Rfc3161TimeStampResp
+ {
+ public PkiStatusInfo Status;
+
+ // TimeStampToken, but it'll be parsed by something else.
+ [AnyValue]
+ [OptionalValue]
+ public ReadOnlyMemory<byte>? TimeStampToken;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct PkiStatusInfo
+ {
+ public int Status;
+
+ [OptionalValue]
+ [AnyValue]
+ [ExpectedTag(TagClass.Universal, (int)UniversalTagNumber.SequenceOf)]
+ public ReadOnlyMemory<byte>? StatusString;
+
+ [OptionalValue]
+ public PkiFailureInfo? FailInfo;
+ }
+
+ // https://tools.ietf.org/html/rfc4210#section-5.2.3
+ [Flags]
+ internal enum PkiFailureInfo
+ {
+ None = 0,
+ BadAlg = 1 << 0,
+ BadMessageCheck = 1 << 1,
+ BadRequest = 1 << 2,
+ BadTime = 1 << 3,
+ BadCertId = 1 << 4,
+ BadDataFormat = 1 << 5,
+ WrongAuthority = 1 << 6,
+ IncorrectData = 1 << 7,
+ MissingTimeStamp = 1 << 8,
+ BadPop = 1 << 9,
+ CertRevoked = 1 << 10,
+ CertConfirmed = 1 << 11,
+ WrongIntegrity = 1 << 12,
+ BadRecipientNonce = 1 << 13,
+ TimeNotAvailable = 1 << 14,
+ UnacceptedPolicy = 1 << 15,
+ UnacceptedExtension = 1 << 16,
+ AddInfoNotAvailable = 1 << 17,
+ BadSenderNonce = 1 << 18,
+ BadCertTemplate = 1 << 19,
+ SignerNotTrusted = 1 << 20,
+ TransactionIdInUse = 1 << 21,
+ UnsupportedVersion = 1 << 22,
+ NotAuthorized = 1 << 23,
+ SystemUnavail = 1 << 24,
+ SystemFailure = 1 << 25,
+ DuplicateCertReq = 1 << 26,
+ }
+
+ // https://tools.ietf.org/html/rfc4210#section-5.2.3
+ internal enum PkiStatus
+ {
+ Granted = 0,
+ GrantedWithMods = 1,
+ Rejection = 2,
+ Waiting = 3,
+ RevocationWarning = 4,
+ RevocationNotification = 5,
+ KeyUpdateWarning = 6,
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TstInfo.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TstInfo.cs
new file mode 100644
index 0000000000..1a646768e8
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TstInfo.cs
@@ -0,0 +1,68 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Pkcs.Asn1
+{
+ // https://tools.ietf.org/html/rfc3161#section-2.4.2
+ //
+ // TSTInfo ::= SEQUENCE {
+ // version INTEGER { v1(1) },
+ // policy TSAPolicyId,
+ // messageImprint MessageImprint,
+ // -- MUST have the same value as the similar field in
+ // -- TimeStampReq
+ // serialNumber INTEGER,
+ // -- Time-Stamping users MUST be ready to accommodate integers
+ // -- up to 160 bits.
+ // genTime GeneralizedTime,
+ // accuracy Accuracy OPTIONAL,
+ // ordering BOOLEAN DEFAULT FALSE,
+ // nonce INTEGER OPTIONAL,
+ // -- MUST be present if the similar field was present
+ // -- in TimeStampReq.In that case it MUST have the same value.
+ // tsa[0] GeneralName OPTIONAL,
+ // extensions[1] IMPLICIT Extensions OPTIONAL }
+ //
+ [StructLayout(LayoutKind.Sequential)]
+ internal sealed class Rfc3161TstInfo
+ {
+ internal int Version;
+
+ [ObjectIdentifier(PopulateFriendlyName = true)]
+ internal Oid Policy;
+
+ internal MessageImprint MessageImprint;
+
+ [Integer]
+ internal ReadOnlyMemory<byte> SerialNumber;
+
+ // Timestamps SHOULD omit fractions "when there is no need".
+ // That means that we need to still support reading and writing them.
+ [GeneralizedTime(DisallowFractions = false)]
+ internal DateTimeOffset GenTime;
+
+ [OptionalValue]
+ internal Rfc3161Accuracy? Accuracy;
+
+#pragma warning disable CS3016 // Arrays as attribute arguments is not CLS-compliant
+ [DefaultValue(0x01, 0x01, 0x00)]
+#pragma warning restore CS3016 // Arrays as attribute arguments is not CLS-compliant
+ internal bool Ordering;
+
+ [Integer]
+ [OptionalValue]
+ internal ReadOnlyMemory<byte>? Nonce;
+
+ [ExpectedTag(0, ExplicitTag = true)]
+ [OptionalValue]
+ internal GeneralName? Tsa;
+
+ [ExpectedTag(1)]
+ [OptionalValue]
+ internal X509ExtensionAsn[] Extensions;
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/SigningCertificateAsn.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/SigningCertificateAsn.cs
new file mode 100644
index 0000000000..92f147aa75
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/SigningCertificateAsn.cs
@@ -0,0 +1,89 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Pkcs.Asn1
+{
+ // https://tools.ietf.org/html/rfc2634#section-5.4
+ //
+ // SigningCertificate ::= SEQUENCE {
+ // certs SEQUENCE OF ESSCertID,
+ // policies SEQUENCE OF PolicyInformation OPTIONAL
+ // }
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct SigningCertificateAsn
+ {
+ public EssCertId[] Certs;
+
+ [OptionalValue]
+ public PolicyInformation[] Policies;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal sealed class EssCertId
+ {
+ [OctetString]
+ public ReadOnlyMemory<byte> Hash;
+
+ [OptionalValue]
+ public CadesIssuerSerial? IssuerSerial;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct CadesIssuerSerial
+ {
+ public GeneralName[] Issuer;
+
+ [Integer]
+ public ReadOnlyMemory<byte> SerialNumber;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct PolicyInformation
+ {
+ [ObjectIdentifier]
+ public string PolicyIdentifier;
+
+ [OptionalValue]
+ public PolicyQualifierInfo[] PolicyQualifiers;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct PolicyQualifierInfo
+ {
+ [ObjectIdentifier]
+ public string PolicyQualifierId;
+
+ [AnyValue]
+ public ReadOnlyMemory<byte> Qualifier;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct SigningCertificateV2Asn
+ {
+ public EssCertIdV2[] Certs;
+
+
+ [OptionalValue]
+ public PolicyInformation[] Policies;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal sealed class EssCertIdV2
+ {
+#pragma warning disable CS3016 // Arrays as attribute arguments is not CLS-compliant
+ // SEQUENCE(OID(2.16.840.1.101.3.4.2.1))
+ [DefaultValue(0x30, 0x0B, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01)]
+#pragma warning restore CS3016 // Arrays as attribute arguments is not CLS-compliant
+ public AlgorithmIdentifierAsn HashAlgorithm;
+
+ [OctetString]
+ public ReadOnlyMemory<byte> Hash;
+
+ [OptionalValue]
+ public CadesIssuerSerial? IssuerSerial;
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/X509ExtensionAsn.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/X509ExtensionAsn.cs
new file mode 100644
index 0000000000..42ad92bce8
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/X509ExtensionAsn.cs
@@ -0,0 +1,38 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.Asn1;
+using System.Security.Cryptography.X509Certificates;
+using Internal.Cryptography;
+
+namespace System.Security.Cryptography.Pkcs.Asn1
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct X509ExtensionAsn
+ {
+ [ObjectIdentifier]
+ internal string ExtnId;
+
+#pragma warning disable CS3016 // Arrays as attribute arguments is not CLS-compliant
+ [DefaultValue(0x01, 0x01, 0x00)]
+#pragma warning restore CS3016 // Arrays as attribute arguments is not CLS-compliant
+ internal bool Critical;
+
+ [OctetString]
+ internal ReadOnlyMemory<byte> ExtnValue;
+
+ public X509ExtensionAsn(X509Extension extension, bool copyValue=true)
+ {
+ if (extension == null)
+ {
+ throw new ArgumentNullException(nameof(extension));
+ }
+
+ ExtnId = extension.Oid.Value;
+ Critical = extension.Critical;
+ ExtnValue = copyValue ? extension.RawData.CloneByteArray() : extension.RawData;
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSigner.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSigner.cs
index 954c342292..0a98a79bf9 100644
--- a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSigner.cs
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSigner.cs
@@ -255,7 +255,7 @@ namespace System.Security.Cryptography.Pkcs
if (i == last &&
IncludeOption == X509IncludeOption.ExcludeRoot &&
- cert.SubjectName.RawData.AsReadOnlySpan().SequenceEqual(cert.IssuerName.RawData))
+ cert.SubjectName.RawData.AsSpan().SequenceEqual(cert.IssuerName.RawData))
{
break;
}
@@ -269,7 +269,7 @@ namespace System.Security.Cryptography.Pkcs
return newSignerInfo;
}
- private static List<AttributeAsn> BuildAttributes(CryptographicAttributeObjectCollection attributes)
+ internal static List<AttributeAsn> BuildAttributes(CryptographicAttributeObjectCollection attributes)
{
List<AttributeAsn> signedAttrs = new List<AttributeAsn>();
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161RequestResponseStatus.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161RequestResponseStatus.cs
new file mode 100644
index 0000000000..6539625b20
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161RequestResponseStatus.cs
@@ -0,0 +1,19 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Security.Cryptography.Pkcs
+{
+ internal enum Rfc3161RequestResponseStatus
+ {
+ Unknown = 0,
+ Accepted = 1,
+ DoesNotParse = 2,
+ RequestFailed = 3,
+ HashMismatch = 4,
+ VersionTooNew = 5,
+ NonceMismatch = 6,
+ RequestedCertificatesMissing = 7,
+ UnexpectedCertificates = 8,
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampRequest.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampRequest.cs
new file mode 100644
index 0000000000..4be637279f
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampRequest.cs
@@ -0,0 +1,427 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Linq;
+using System.Security.Cryptography.Asn1;
+using System.Security.Cryptography.Pkcs.Asn1;
+using System.Security.Cryptography.X509Certificates;
+using Internal.Cryptography;
+
+namespace System.Security.Cryptography.Pkcs
+{
+ public sealed class Rfc3161TimestampRequest
+ {
+ private byte[] _encodedBytes;
+ private Rfc3161TimeStampReq _parsedData;
+
+ private Rfc3161TimestampRequest()
+ {
+ }
+
+ public int Version => _parsedData.Version;
+ public ReadOnlyMemory<byte> GetMessageHash() => _parsedData.MessageImprint.HashedMessage;
+ public Oid HashAlgorithmId => _parsedData.MessageImprint.HashAlgorithm.Algorithm;
+ public Oid RequestedPolicyId => _parsedData.ReqPolicy;
+ public bool RequestSignerCertificate => _parsedData.CertReq;
+ public ReadOnlyMemory<byte>? GetNonce() => _parsedData.Nonce;
+ public bool HasExtensions => _parsedData.Extensions?.Length > 0;
+
+ public X509ExtensionCollection GetExtensions()
+ {
+ var coll = new X509ExtensionCollection();
+
+ if (!HasExtensions)
+ {
+ return coll;
+ }
+
+ X509ExtensionAsn[] rawExtensions = _parsedData.Extensions;
+
+ foreach (X509ExtensionAsn rawExtension in rawExtensions)
+ {
+ X509Extension extension = new X509Extension(
+ rawExtension.ExtnId,
+ rawExtension.ExtnValue.ToArray(),
+ rawExtension.Critical);
+
+ // Currently there are no extensions defined.
+ // Should this dip into CryptoConfig or other extensible
+ // mechanisms for the CopyTo rich type uplift?
+ coll.Add(extension);
+ }
+
+ return coll;
+ }
+
+ public Rfc3161TimestampToken ProcessResponse(ReadOnlyMemory<byte> source, out int bytesConsumed)
+ {
+ Rfc3161RequestResponseStatus status;
+ Rfc3161TimestampToken token;
+
+ if (ProcessResponse(source, out token, out status, out int localBytesRead, shouldThrow: true))
+ {
+ Debug.Assert(status == Rfc3161RequestResponseStatus.Accepted);
+ bytesConsumed = localBytesRead;
+ return token;
+ }
+
+ Debug.Fail($"AcceptResponse should have thrown or returned true (status={status})");
+ throw new CryptographicException();
+ }
+
+ private bool ProcessResponse(
+ ReadOnlyMemory<byte> source,
+ out Rfc3161TimestampToken token,
+ out Rfc3161RequestResponseStatus status,
+ out int bytesConsumed,
+ bool shouldThrow)
+ {
+ status = Rfc3161RequestResponseStatus.Unknown;
+ token = null;
+
+ Rfc3161TimeStampResp resp;
+
+ try
+ {
+ resp = AsnSerializer.Deserialize<Rfc3161TimeStampResp>(source, AsnEncodingRules.DER, out bytesConsumed);
+ }
+ catch (CryptographicException) when (!shouldThrow)
+ {
+ bytesConsumed = 0;
+ status = Rfc3161RequestResponseStatus.DoesNotParse;
+ return false;
+ }
+
+ // bytesRead will be set past this point
+
+ PkiStatus pkiStatus = (PkiStatus)resp.Status.Status;
+
+ if (pkiStatus != PkiStatus.Granted &&
+ pkiStatus != PkiStatus.GrantedWithMods)
+ {
+ if (shouldThrow)
+ {
+ throw new CryptographicException(
+ SR.Format(
+ SR.Cryptography_TimestampReq_Failure,
+ pkiStatus,
+ resp.Status.FailInfo.GetValueOrDefault()));
+ }
+
+ status = Rfc3161RequestResponseStatus.RequestFailed;
+ return false;
+ }
+
+ if (!Rfc3161TimestampToken.TryDecode(resp.TimeStampToken.GetValueOrDefault(), out token, out _))
+ {
+ if (shouldThrow)
+ {
+ throw new CryptographicException(SR.Cryptography_TimestampReq_BadResponse);
+ }
+
+ bytesConsumed = 0;
+ status = Rfc3161RequestResponseStatus.DoesNotParse;
+ return false;
+ }
+
+ status = ValidateResponse(token, shouldThrow);
+ return status == Rfc3161RequestResponseStatus.Accepted;
+ }
+
+ public byte[] Encode()
+ {
+ return _encodedBytes.CloneByteArray();
+ }
+
+ public bool TryEncode(Span<byte> destination, out int bytesWritten)
+ {
+ if (destination.Length < _encodedBytes.Length)
+ {
+ bytesWritten = 0;
+ return false;
+ }
+
+ _encodedBytes.AsSpan().CopyTo(destination);
+ bytesWritten = _encodedBytes.Length;
+ return true;
+ }
+
+ public static Rfc3161TimestampRequest CreateFromSignerInfo(
+ SignerInfo signerInfo,
+ HashAlgorithmName hashAlgorithm,
+ Oid requestedPolicyId = null,
+ ReadOnlyMemory<byte>? nonce = null,
+ bool requestSignerCertificates = false,
+ X509ExtensionCollection extensions = null)
+ {
+ if (signerInfo == null)
+ {
+ throw new ArgumentNullException(nameof(signerInfo));
+ }
+
+ // https://tools.ietf.org/html/rfc3161, Appendix A.
+ //
+ // The value of messageImprint field within TimeStampToken shall be a
+ // hash of the value of signature field within SignerInfo for the
+ // signedData being time-stamped.
+ return CreateFromData(
+ signerInfo.GetSignature(),
+ hashAlgorithm,
+ requestedPolicyId,
+ nonce,
+ requestSignerCertificates,
+ extensions);
+ }
+
+ public static Rfc3161TimestampRequest CreateFromData(
+ ReadOnlySpan<byte> data,
+ HashAlgorithmName hashAlgorithm,
+ Oid requestedPolicyId = null,
+ ReadOnlyMemory<byte>? nonce = null,
+ bool requestSignerCertificates = false,
+ X509ExtensionCollection extensions = null)
+ {
+ using (IncrementalHash hasher = IncrementalHash.CreateHash(hashAlgorithm))
+ {
+ hasher.AppendData(data);
+ byte[] digest = hasher.GetHashAndReset();
+
+ return CreateFromHash(
+ digest,
+ hashAlgorithm,
+ requestedPolicyId,
+ nonce,
+ requestSignerCertificates,
+ extensions);
+ }
+ }
+
+ public static Rfc3161TimestampRequest CreateFromHash(
+ ReadOnlyMemory<byte> hash,
+ HashAlgorithmName hashAlgorithm,
+ Oid requestedPolicyId = null,
+ ReadOnlyMemory<byte>? nonce = null,
+ bool requestSignerCertificates = false,
+ X509ExtensionCollection extensions = null)
+ {
+ string oidStr = Helpers.GetOidFromHashAlgorithm(hashAlgorithm);
+
+ return CreateFromHash(
+ hash,
+ new Oid(oidStr, oidStr),
+ requestedPolicyId,
+ nonce,
+ requestSignerCertificates,
+ extensions);
+ }
+
+ /// <summary>
+ /// Create a timestamp request using a pre-computed hash value.
+ /// </summary>
+ /// <param name="hash">The pre-computed hash value to be timestamped.</param>
+ /// <param name="hashAlgorithmId">
+ /// The Object Identifier (OID) for the hash algorithm which produced <paramref name="hash"/>.
+ /// </param>
+ /// <param name="requestedPolicyId">
+ /// The Object Identifier (OID) for a timestamp policy the Timestamp Authority (TSA) should use,
+ /// or <c>null</c> to express no preference.
+ /// </param>
+ /// <param name="nonce">
+ /// An optional nonce (number used once) to uniquely identify this request to pair it with the response.
+ /// The value is interpreted as an unsigned big-endian integer and may be normalized to the encoding format.
+ /// </param>
+ /// <param name="requestSignerCertificates">
+ /// Indicates whether the Timestamp Authority (TSA) must (<c>true</c>) or must not (<c>false</c>) include
+ /// the signing certificate in the issued timestamp token.
+ /// </param>
+ /// <param name="extensions">RFC3161 extensions to present with the request.</param>
+ /// <returns>
+ /// An <see cref="Rfc3161TimestampRequest"/> representing the chosen values.
+ /// </returns>
+ /// <seealso cref="Encode"/>
+ /// <seealso cref="TryEncode"/>
+ public static Rfc3161TimestampRequest CreateFromHash(
+ ReadOnlyMemory<byte> hash,
+ Oid hashAlgorithmId,
+ Oid requestedPolicyId = null,
+ ReadOnlyMemory<byte>? nonce = null,
+ bool requestSignerCertificates = false,
+ X509ExtensionCollection extensions = null)
+ {
+ var req = new Rfc3161TimeStampReq
+ {
+ Version = 1,
+ MessageImprint = new MessageImprint
+ {
+ HashAlgorithm =
+ {
+ Algorithm = hashAlgorithmId,
+ Parameters = AlgorithmIdentifierAsn.ExplicitDerNull,
+ },
+
+ HashedMessage = hash,
+ },
+ ReqPolicy = requestedPolicyId,
+ CertReq = requestSignerCertificates,
+ Nonce = nonce,
+ };
+
+ if (extensions != null)
+ {
+ req.Extensions =
+ extensions.OfType<X509Extension>().Select(e => new X509ExtensionAsn(e)).ToArray();
+ }
+
+ // The RFC implies DER (see TryParse), and DER is the most widely understood given that
+ // CER isn't specified.
+ const AsnEncodingRules ruleSet = AsnEncodingRules.DER;
+ AsnWriter writer = AsnSerializer.Serialize(req, ruleSet);
+ byte[] encodedBytes = writer.Encode();
+
+ // Make sure everything normalizes
+ req = AsnSerializer.Deserialize<Rfc3161TimeStampReq>(encodedBytes, ruleSet);
+
+ return new Rfc3161TimestampRequest
+ {
+ _encodedBytes = writer.Encode(),
+ _parsedData = req,
+ };
+ }
+
+ public static bool TryDecode(
+ ReadOnlyMemory<byte> encodedBytes,
+ out Rfc3161TimestampRequest request,
+ out int bytesConsumed)
+ {
+ try
+ {
+ // RFC 3161 doesn't have a concise statement that TimeStampReq will
+ // be DER encoded, but under the email protocol (3.1), file protocol (3.2),
+ // socket protocol (3.3) and HTTP protocol (3.4) they all say DER for the
+ // transmission.
+ //
+ // Since nothing says BER, assume DER only.
+ const AsnEncodingRules RuleSet = AsnEncodingRules.DER;
+
+ AsnReader reader = new AsnReader(encodedBytes, RuleSet);
+ ReadOnlyMemory<byte> firstElement = reader.PeekEncodedValue();
+
+ var req = AsnSerializer.Deserialize<Rfc3161TimeStampReq>(firstElement, RuleSet);
+
+ request = new Rfc3161TimestampRequest
+ {
+ _parsedData = req,
+ _encodedBytes = firstElement.ToArray(),
+ };
+
+ bytesConsumed = firstElement.Length;
+ return true;
+ }
+ catch (CryptographicException)
+ {
+ }
+
+ request = null;
+ bytesConsumed = 0;
+ return false;
+ }
+
+ private Rfc3161RequestResponseStatus ValidateResponse(
+ Rfc3161TimestampToken token,
+ bool shouldThrow)
+ {
+ Debug.Assert(token != null);
+
+ // This method validates the acceptance criteria sprinkled throughout the
+ // field descriptions in https://tools.ietf.org/html/rfc3161#section-2.4.1 and
+ // https://tools.ietf.org/html/rfc3161#section-2.4.2
+
+ if (!token.VerifyHash(GetMessageHash().Span, HashAlgorithmId.Value))
+ {
+ if (shouldThrow)
+ {
+ throw new CryptographicException(SR.Cryptography_BadHashValue);
+ }
+
+ return Rfc3161RequestResponseStatus.HashMismatch;
+ }
+
+ Rfc3161TimestampTokenInfo tokenInfo = token.TokenInfo;
+
+ // We only understand V1 messaging and validation
+ if (tokenInfo.Version != 1)
+ {
+ if (shouldThrow)
+ {
+ throw new CryptographicException(SR.Cryptography_TimestampReq_BadResponse);
+ }
+
+ return Rfc3161RequestResponseStatus.VersionTooNew;
+ }
+
+ // reqPolicy is what the policy SHOULD be, so we can't reject it here.
+
+ ReadOnlyMemory<byte>? requestNonce = GetNonce();
+ ReadOnlyMemory<byte>? responseNonce = tokenInfo.GetNonce();
+
+ // The RFC says that if a nonce was in the request it MUST be present in
+ // the response and it MUST be equal.
+ //
+ // It does not say that if no nonce was requested that the response MUST NOT include one, so
+ // don't check anything if no nonce was requested.
+ if (requestNonce != null)
+ {
+ if (responseNonce == null ||
+ !requestNonce.Value.Span.SequenceEqual(responseNonce.Value.Span))
+ {
+ if (shouldThrow)
+ {
+ throw new CryptographicException(SR.Cryptography_TimestampReq_BadNonce);
+ }
+
+ return Rfc3161RequestResponseStatus.NonceMismatch;
+ }
+ }
+
+ SignedCms tokenCms = token.AsSignedCms();
+
+ if (RequestSignerCertificate)
+ {
+ // If the certificate was requested it
+ // A) MUST be present in token.AsSignedCms().Certificates
+ // B) the ESSCertID(2) identifier MUST be correct.
+ //
+ // Other certificates are permitted, and will not be validated.
+
+ if (tokenCms.SignerInfos[0].Certificate == null)
+ {
+ if (shouldThrow)
+ {
+ throw new CryptographicException(SR.Cryptography_TimestampReq_NoCertFound);
+ }
+
+ return Rfc3161RequestResponseStatus.RequestedCertificatesMissing;
+ }
+ }
+ else
+ {
+ // If no certificate was requested then the CMS Certificates collection
+ // MUST be empty.
+
+ if (tokenCms.Certificates.Count != 0)
+ {
+ if (shouldThrow)
+ {
+ throw new CryptographicException(SR.Cryptography_TimestampReq_UnexpectedCertFound);
+ }
+
+ return Rfc3161RequestResponseStatus.UnexpectedCertificates;
+ }
+ }
+
+ return Rfc3161RequestResponseStatus.Accepted;
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampToken.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampToken.cs
new file mode 100644
index 0000000000..665d5c0b61
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampToken.cs
@@ -0,0 +1,641 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Linq;
+using System.Security.Cryptography.Asn1;
+using System.Security.Cryptography.Pkcs.Asn1;
+using System.Security.Cryptography.X509Certificates;
+using System.Security.Cryptography.Xml;
+using Internal.Cryptography;
+
+namespace System.Security.Cryptography.Pkcs
+{
+ public sealed class Rfc3161TimestampToken
+ {
+ private SignedCms _parsedDocument;
+ private SignerInfo _signerInfo;
+ private EssCertId _essCertId;
+ private EssCertIdV2 _essCertIdV2;
+
+ public Rfc3161TimestampTokenInfo TokenInfo { get; private set; }
+
+ private Rfc3161TimestampToken()
+ {
+ }
+
+ /// <summary>
+ /// Get a SignedCms representation of the RFC3161 Timestamp Token.
+ /// </summary>
+ /// <returns>The SignedCms representation of the RFC3161 Timestamp Token.</returns>
+ /// <remarks>
+ /// Successive calls to this method return the same object.
+ /// The SignedCms class is mutable, but changes to that object are not reflected in the
+ /// <see cref="Rfc3161TimestampToken"/> object which produced it.
+ /// The value from calling <see cref="SignedCms.Encode"/> can be interpreted again as an
+ /// <see cref="Rfc3161TimestampToken"/> via another call to <see cref="TryDecode"/>.
+ /// </remarks>
+ public SignedCms AsSignedCms() => _parsedDocument;
+
+ private X509Certificate2 GetSignerCertificate(X509Certificate2Collection extraCandidates)
+ {
+ Debug.Assert(_signerInfo != null, "_signerInfo != null");
+ X509Certificate2 signerCert = _signerInfo.Certificate;
+
+ if (signerCert != null)
+ {
+ if (CheckCertificate(signerCert, _signerInfo, _essCertId, _essCertIdV2, TokenInfo))
+ {
+ return signerCert;
+ }
+
+ // SignedCms will not try another certificate in this state, so just fail.
+ return null;
+ }
+
+ if (extraCandidates == null || extraCandidates.Count == 0)
+ {
+ return null;
+ }
+
+ foreach (X509Certificate2 candidate in extraCandidates)
+ {
+ if (CheckCertificate(candidate, _signerInfo, _essCertId, _essCertIdV2, TokenInfo))
+ {
+ return candidate;
+ }
+ }
+
+ return null;
+ }
+
+ public bool VerifySignatureForData(
+ ReadOnlySpan<byte> data,
+ out X509Certificate2 signerCertificate,
+ X509Certificate2Collection extraCandidates = null)
+ {
+ signerCertificate = null;
+
+ X509Certificate2 cert = GetSignerCertificate(extraCandidates);
+
+ if (cert == null)
+ {
+ return false;
+ }
+
+ bool ret = VerifyData(data);
+
+ if (ret)
+ {
+ signerCertificate = cert;
+ }
+
+ return ret;
+ }
+
+ public bool VerifySignatureForHash(
+ ReadOnlySpan<byte> hash,
+ HashAlgorithmName hashAlgorithm,
+ out X509Certificate2 signerCertificate,
+ X509Certificate2Collection extraCandidates = null)
+ {
+ signerCertificate = null;
+
+ X509Certificate2 cert = GetSignerCertificate(extraCandidates);
+
+ if (cert == null)
+ {
+ return false;
+ }
+
+ bool ret = VerifyHash(hash, Helpers.GetOidFromHashAlgorithm(hashAlgorithm));
+
+ if (ret)
+ {
+ signerCertificate = cert;
+ }
+
+ return ret;
+ }
+
+ public bool VerifySignatureForHash(
+ ReadOnlySpan<byte> hash,
+ Oid hashAlgorithmId,
+ out X509Certificate2 signerCertificate,
+ X509Certificate2Collection extraCandidates = null)
+ {
+ if (hashAlgorithmId == null)
+ {
+ throw new ArgumentNullException(nameof(hashAlgorithmId));
+ }
+
+ signerCertificate = null;
+
+ X509Certificate2 cert = GetSignerCertificate(extraCandidates);
+
+ if (cert == null)
+ {
+ return false;
+ }
+
+ bool ret = VerifyHash(hash, hashAlgorithmId.Value);
+
+ if (ret)
+ {
+ // REVIEW: Should this return the cert, or new X509Certificate2(cert.RawData)?
+ // SignedCms.SignerInfos builds new objects each call, which makes
+ // ReferenceEquals(cms.SignerInfos[0].Certificate, cms.SignerInfos[0].Certificate) be false.
+ // So maybe it's weird to give back a cert we've copied from that?
+ signerCertificate = cert;
+ }
+
+ return ret;
+ }
+
+ public bool VerifySignatureForSignerInfo(
+ SignerInfo signerInfo,
+ out X509Certificate2 signerCertificate,
+ X509Certificate2Collection extraCandidates = null)
+ {
+ if (signerInfo == null)
+ {
+ throw new ArgumentNullException(nameof(signerInfo));
+ }
+
+ return VerifySignatureForData(
+ signerInfo.GetSignatureMemory().Span,
+ out signerCertificate,
+ extraCandidates);
+ }
+
+ internal bool VerifyHash(ReadOnlySpan<byte> hash, string hashAlgorithmId)
+ {
+ return
+ hash.SequenceEqual(TokenInfo.GetMessageHash().Span) &&
+ hashAlgorithmId == TokenInfo.HashAlgorithmId.Value;
+ }
+
+ private bool VerifyData(ReadOnlySpan<byte> data)
+ {
+ Oid hashAlgorithmId = TokenInfo.HashAlgorithmId;
+ HashAlgorithmName hashAlgorithmName = Helpers.GetDigestAlgorithm(hashAlgorithmId);
+
+ using (IncrementalHash hasher = IncrementalHash.CreateHash(hashAlgorithmName))
+ {
+ hasher.AppendData(data);
+
+ // SHA-2-512 is the biggest hash we currently know about.
+ Span<byte> stackSpan = stackalloc byte[512 / 8];
+
+ if (hasher.TryGetHashAndReset(stackSpan, out int bytesWritten))
+ {
+ return VerifyHash(stackSpan.Slice(0, bytesWritten), hashAlgorithmId.Value);
+ }
+
+ // Something we understood, but is bigger than 512-bit.
+ // Allocate at runtime, trip in a debug build so we can re-evaluate this.
+ Debug.Fail(
+ $"TryGetHashAndReset did not fit in {stackSpan.Length} for hash {hashAlgorithmId.Value}");
+
+ return VerifyHash(hasher.GetHashAndReset(), hashAlgorithmId.Value);
+ }
+ }
+
+ private static bool CheckCertificate(
+ X509Certificate2 tsaCertificate,
+ SignerInfo signer,
+ EssCertId certId,
+ EssCertIdV2 certId2,
+ Rfc3161TimestampTokenInfo tokenInfo)
+ {
+ Debug.Assert(tsaCertificate != null);
+ Debug.Assert(signer != null);
+ Debug.Assert(tokenInfo != null);
+ // certId and certId2 are allowed to be null, they get checked in CertMatchesIds.
+
+ if (!CertMatchesIds(tsaCertificate, certId, certId2))
+ {
+ return false;
+ }
+
+ // Nothing in RFC3161 actually mentions checking the certificate's validity
+ // against the TSTInfo timestamp value, but it seems sensible.
+ //
+ // Accuracy is ignored here, for better replicability in user code.
+
+ if (tsaCertificate.NotAfter < tokenInfo.Timestamp ||
+ tsaCertificate.NotBefore > tokenInfo.Timestamp)
+ {
+ return false;
+ }
+
+ // https://tools.ietf.org/html/rfc3161#section-2.3
+ //
+ // The TSA MUST sign each time-stamp message with a key reserved
+ // specifically for that purpose. A TSA MAY have distinct private keys,
+ // e.g., to accommodate different policies, different algorithms,
+ // different private key sizes or to increase the performance. The
+ // corresponding certificate MUST contain only one instance of the
+ // extended key usage field extension as defined in [RFC2459] Section
+ // 4.2.1.13 with KeyPurposeID having value:
+ //
+ // id-kp-timeStamping. This extension MUST be critical.
+
+ using (var ekuExts = tsaCertificate.Extensions.OfType<X509EnhancedKeyUsageExtension>().GetEnumerator())
+ {
+ if (!ekuExts.MoveNext())
+ {
+ return false;
+ }
+
+ X509EnhancedKeyUsageExtension ekuExt = ekuExts.Current;
+
+ if (!ekuExt.Critical)
+ {
+ return false;
+ }
+
+ bool hasPurpose = false;
+
+ foreach (Oid oid in ekuExt.EnhancedKeyUsages)
+ {
+ if (oid.Value == Oids.TimeStampingPurpose)
+ {
+ hasPurpose = true;
+ break;
+ }
+ }
+
+ if (!hasPurpose)
+ {
+ return false;
+ }
+
+ if (ekuExts.MoveNext())
+ {
+ return false;
+ }
+ }
+
+ try
+ {
+ signer.CheckSignature(new X509Certificate2Collection(tsaCertificate), true);
+ return true;
+ }
+ catch (CryptographicException)
+ {
+ return false;
+ }
+ }
+
+ public static bool TryDecode(ReadOnlyMemory<byte> source, out Rfc3161TimestampToken token, out int bytesConsumed)
+ {
+ bytesConsumed = 0;
+ token = null;
+
+ try
+ {
+ ContentInfoAsn contentInfo =
+ AsnSerializer.Deserialize<ContentInfoAsn>(source, AsnEncodingRules.BER, out int bytesActuallyRead);
+
+ // https://tools.ietf.org/html/rfc3161#section-2.4.2
+ //
+ // A TimeStampToken is as follows. It is defined as a ContentInfo
+ // ([CMS]) and SHALL encapsulate a signed data content type.
+ //
+ // TimeStampToken::= ContentInfo
+ // --contentType is id-signedData([CMS])
+ // --content is SignedData ([CMS])
+ if (contentInfo.ContentType != Oids.Pkcs7Signed)
+ {
+ return false;
+ }
+
+ SignedCms cms = new SignedCms();
+ cms.Decode(source);
+
+ // The fields of type EncapsulatedContentInfo of the SignedData
+ // construct have the following meanings:
+ //
+ // eContentType is an object identifier that uniquely specifies the
+ // content type. For a time-stamp token it is defined as:
+ //
+ // id-ct-TSTInfo OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+ // us(840) rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) ct(1) 4}
+ //
+ // eContent is the content itself, carried as an octet string.
+ // The eContent SHALL be the DER-encoded value of TSTInfo.
+ if (cms.ContentInfo.ContentType.Value != Oids.TstInfo)
+ {
+ return false;
+ }
+
+ // RFC3161:
+ // The time-stamp token MUST NOT contain any signatures other than the
+ // signature of the TSA. The certificate identifier (ESSCertID) of the
+ // TSA certificate MUST be included as a signerInfo attribute inside a
+ // SigningCertificate attribute.
+
+ // RFC5816 says that ESSCertIDv2 should be allowed instead.
+
+ SignerInfoCollection signerInfos = cms.SignerInfos;
+
+ if (signerInfos.Count != 1)
+ {
+ return false;
+ }
+
+ SignerInfo signer = signerInfos[0];
+ EssCertId certId;
+ EssCertIdV2 certId2;
+
+ if (!TryGetCertIds(signer, out certId, out certId2))
+ {
+ return false;
+ }
+
+ X509Certificate2 signerCert = signer.Certificate;
+
+ if (signerCert == null &&
+ signer.SignerIdentifier.Type == SubjectIdentifierType.IssuerAndSerialNumber)
+ {
+ // If the cert wasn't provided, but the identifier was IssuerAndSerialNumber,
+ // and the ESSCertId(V2) has specified an issuerSerial value, ensure it's a match.
+ X509IssuerSerial issuerSerial = (X509IssuerSerial)signer.SignerIdentifier.Value;
+
+ if (certId?.IssuerSerial != null)
+ {
+ if (!IssuerAndSerialMatch(
+ certId.IssuerSerial.Value,
+ issuerSerial.IssuerName,
+ issuerSerial.SerialNumber))
+ {
+ return false;
+ }
+ }
+
+ if (certId2?.IssuerSerial != null)
+ {
+ if (!IssuerAndSerialMatch(
+ certId2.IssuerSerial.Value,
+ issuerSerial.IssuerName,
+ issuerSerial.SerialNumber))
+ {
+ return false;
+ }
+ }
+ }
+
+ Rfc3161TimestampTokenInfo tokenInfo;
+
+ if (Rfc3161TimestampTokenInfo.TryDecode(cms.ContentInfo.Content, out tokenInfo, out _))
+ {
+ if (signerCert != null &&
+ !CheckCertificate(signerCert, signer, certId, certId2, tokenInfo))
+ {
+ return false;
+ }
+
+ token = new Rfc3161TimestampToken
+ {
+ _parsedDocument = cms,
+ _signerInfo = signer,
+ _essCertId = certId,
+ _essCertIdV2 = certId2,
+ TokenInfo = tokenInfo,
+ };
+
+ bytesConsumed = bytesActuallyRead;
+ return true;
+ }
+ }
+ catch (CryptographicException)
+ {
+ }
+
+ return false;
+ }
+
+ private static bool IssuerAndSerialMatch(
+ CadesIssuerSerial issuerSerial,
+ string issuerDirectoryName,
+ string serialNumber)
+ {
+ GeneralName[] issuerNames = issuerSerial.Issuer;
+
+ if (issuerNames == null || issuerNames.Length != 1)
+ {
+ return false;
+ }
+
+ GeneralName requiredName = issuerNames[0];
+
+ if (requiredName.DirectoryName == null)
+ {
+ return false;
+ }
+
+ if (issuerDirectoryName != new X500DistinguishedName(requiredName.DirectoryName.Value.ToArray()).Name)
+ {
+ return false;
+ }
+
+ return serialNumber == issuerSerial.SerialNumber.Span.ToBigEndianHex();
+ }
+
+ private static bool IssuerAndSerialMatch(
+ CadesIssuerSerial issuerSerial,
+ ReadOnlySpan<byte> issuerDirectoryName,
+ ReadOnlySpan<byte> serialNumber)
+ {
+ GeneralName[] issuerNames = issuerSerial.Issuer;
+
+ if (issuerNames == null || issuerNames.Length != 1)
+ {
+ return false;
+ }
+
+ GeneralName requiredName = issuerNames[0];
+
+ if (requiredName.DirectoryName == null)
+ {
+ return false;
+ }
+
+ if (!requiredName.DirectoryName.Value.Span.SequenceEqual(issuerDirectoryName))
+ {
+ return false;
+ }
+
+ return serialNumber.SequenceEqual(issuerSerial.SerialNumber.Span);
+ }
+
+ private static bool CertMatchesIds(X509Certificate2 signerCert, EssCertId certId, EssCertIdV2 certId2)
+ {
+ Debug.Assert(signerCert != null);
+ Debug.Assert(certId != null || certId2 != null);
+ byte[] serialNumber = null;
+
+ if (certId != null)
+ {
+ Span<byte> thumbprint = stackalloc byte[20];
+
+ if (!signerCert.TryGetCertHash(HashAlgorithmName.SHA1, thumbprint, out int written) ||
+ written != thumbprint.Length ||
+ !thumbprint.SequenceEqual(certId.Hash.Span))
+ {
+ return false;
+ }
+
+ if (certId.IssuerSerial != null)
+ {
+ serialNumber = signerCert.GetSerialNumber();
+ Array.Reverse(serialNumber);
+
+ if (!IssuerAndSerialMatch(
+ certId.IssuerSerial.Value,
+ signerCert.IssuerName.RawData,
+ serialNumber))
+ {
+ return false;
+ }
+ }
+ }
+
+ if (certId2 != null)
+ {
+ HashAlgorithmName alg;
+ // SHA-2-512 is the biggest we know about.
+ Span<byte> thumbprint = stackalloc byte[512 / 8];
+
+ try
+ {
+ alg = Helpers.GetDigestAlgorithm(certId2.HashAlgorithm.Algorithm);
+
+ if (signerCert.TryGetCertHash(alg, thumbprint, out int written))
+ {
+ thumbprint = thumbprint.Slice(0, written);
+ }
+ else
+ {
+ Debug.Fail(
+ $"TryGetCertHash did not fit in {thumbprint.Length} for hash {certId2.HashAlgorithm.Algorithm.Value}");
+
+ thumbprint = signerCert.GetCertHash(alg);
+ }
+ }
+ catch (CryptographicException)
+ {
+ return false;
+ }
+
+ if (!thumbprint.SequenceEqual(certId2.Hash.Span))
+ {
+ return false;
+ }
+
+ if (certId2.IssuerSerial != null)
+ {
+ if (serialNumber == null)
+ {
+ serialNumber = signerCert.GetSerialNumber();
+ Array.Reverse(serialNumber);
+ }
+
+ if (!IssuerAndSerialMatch(
+ certId2.IssuerSerial.Value,
+ signerCert.IssuerName.RawData,
+ serialNumber))
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private static bool TryGetCertIds(SignerInfo signer, out EssCertId certId, out EssCertIdV2 certId2)
+ {
+ // RFC 5035 says that SigningCertificateV2 (contains ESSCertIDv2) is a signed
+ // attribute, with OID 1.2.840.113549.1.9.16.2.47, and that it must not be multiply defined.
+
+ // RFC 2634 says that SigningCertificate (contains ESSCertID) is a signed attribute,
+ // with OID 1.2.840.113549.1.9.16.2.12, and that it must not be multiply defined.
+ certId = null;
+ certId2 = null;
+
+ foreach (CryptographicAttributeObject attrSet in signer.SignedAttributes)
+ {
+ string setOid = attrSet.Oid?.Value;
+
+ if (setOid != null &&
+ setOid != Oids.SigningCertificate &&
+ setOid != Oids.SigningCertificateV2)
+ {
+ continue;
+ }
+
+ foreach (AsnEncodedData attr in attrSet.Values)
+ {
+ string attrOid = attr.Oid?.Value;
+
+ if (attrOid == Oids.SigningCertificate)
+ {
+ if (certId != null)
+ {
+ return false;
+ }
+
+ try
+ {
+ SigningCertificateAsn signingCert =
+ AsnSerializer.Deserialize<SigningCertificateAsn>(attr.RawData, AsnEncodingRules.BER);
+
+ if (signingCert.Certs.Length < 1)
+ {
+ return false;
+ }
+
+ // The first one is the signing cert, the rest constrain the chain.
+ certId = signingCert.Certs[0];
+ }
+ catch (CryptographicException)
+ {
+ return false;
+ }
+ }
+
+ if (attrOid == Oids.SigningCertificateV2)
+ {
+ if (certId2 != null)
+ {
+ return false;
+ }
+
+ try
+ {
+ SigningCertificateV2Asn signingCert =
+ AsnSerializer.Deserialize<SigningCertificateV2Asn>(attr.RawData, AsnEncodingRules.BER);
+
+ if (signingCert.Certs.Length < 1)
+ {
+ return false;
+ }
+
+ // The first one is the signing cert, the rest constrain the chain.
+ certId2 = signingCert.Certs[0];
+ }
+ catch (CryptographicException)
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ return certId2 != null || certId != null;
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampTokenInfo.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampTokenInfo.cs
new file mode 100644
index 0000000000..fed6e5605c
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampTokenInfo.cs
@@ -0,0 +1,265 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Linq;
+using System.Security.Cryptography.Asn1;
+using System.Security.Cryptography.Pkcs.Asn1;
+using System.Security.Cryptography.X509Certificates;
+using Internal.Cryptography;
+
+namespace System.Security.Cryptography.Pkcs
+{
+ public sealed class Rfc3161TimestampTokenInfo
+ {
+ private readonly byte[] _encodedBytes;
+ private readonly Rfc3161TstInfo _parsedData;
+ private ReadOnlyMemory<byte>? _tsaNameBytes;
+
+ public Rfc3161TimestampTokenInfo(
+ Oid policyId,
+ Oid hashAlgorithmId,
+ ReadOnlyMemory<byte> messageHash,
+ ReadOnlyMemory<byte> serialNumber,
+ DateTimeOffset timestamp,
+ long? accuracyInMicroseconds = null,
+ bool isOrdering = false,
+ ReadOnlyMemory<byte>? nonce = null,
+ ReadOnlyMemory<byte>? tsaName = null,
+ X509ExtensionCollection extensions = null)
+ {
+ _encodedBytes = Encode(
+ policyId,
+ hashAlgorithmId,
+ messageHash,
+ serialNumber,
+ timestamp,
+ isOrdering,
+ accuracyInMicroseconds,
+ nonce,
+ tsaName,
+ extensions);
+
+ if (!TryDecode(_encodedBytes, true, out _parsedData, out _, out _))
+ {
+ Debug.Fail("Unable to decode the data we encoded");
+ throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+ }
+ }
+
+ private Rfc3161TimestampTokenInfo(byte[] copiedBytes, Rfc3161TstInfo tstInfo)
+ {
+ _encodedBytes = copiedBytes;
+ _parsedData = tstInfo;
+ }
+
+ public int Version => _parsedData.Version;
+ public Oid PolicyId => _parsedData.Policy;
+ public Oid HashAlgorithmId => _parsedData.MessageImprint.HashAlgorithm.Algorithm;
+ public ReadOnlyMemory<byte> GetMessageHash() => _parsedData.MessageImprint.HashedMessage;
+ public ReadOnlyMemory<byte> GetSerialNumber() => _parsedData.SerialNumber;
+ public DateTimeOffset Timestamp => _parsedData.GenTime;
+ public long? AccuracyInMicroseconds => _parsedData.Accuracy?.TotalMicros;
+ public bool IsOrdering => _parsedData.Ordering;
+ public ReadOnlyMemory<byte>? GetNonce() => _parsedData.Nonce;
+ public bool HasExtensions => _parsedData.Extensions?.Length > 0;
+
+ public ReadOnlyMemory<byte>? GetTimestampAuthorityName()
+ {
+ if (_tsaNameBytes == null)
+ {
+ GeneralName? tsaName = _parsedData.Tsa;
+
+ if (tsaName == null)
+ {
+ return null;
+ }
+
+ _tsaNameBytes = AsnSerializer.Serialize(tsaName.Value, AsnEncodingRules.DER).Encode();
+ Debug.Assert(_tsaNameBytes.HasValue);
+ }
+
+ return _tsaNameBytes.Value;
+ }
+
+ public X509ExtensionCollection GetExtensions()
+ {
+ var coll = new X509ExtensionCollection();
+
+ if (!HasExtensions)
+ {
+ return coll;
+ }
+
+ X509ExtensionAsn[] rawExtensions = _parsedData.Extensions;
+
+ foreach (X509ExtensionAsn rawExtension in rawExtensions)
+ {
+ X509Extension extension = new X509Extension(
+ rawExtension.ExtnId,
+ rawExtension.ExtnValue.ToArray(),
+ rawExtension.Critical);
+
+ // Currently there are no extensions defined.
+ // Should this dip into CryptoConfig or other extensible
+ // mechanisms for the CopyTo rich type uplift?
+ coll.Add(extension);
+ }
+
+ return coll;
+ }
+
+ public byte[] Encode()
+ {
+ return _encodedBytes.CloneByteArray();
+ }
+
+ public bool TryEncode(Span<byte> destination, out int bytesWritten)
+ {
+ if (destination.Length < _encodedBytes.Length)
+ {
+ bytesWritten = 0;
+ return false;
+ }
+
+ _encodedBytes.AsSpan().CopyTo(destination);
+ bytesWritten = _encodedBytes.Length;
+ return true;
+ }
+
+ public static bool TryDecode(
+ ReadOnlyMemory<byte> source,
+ out Rfc3161TimestampTokenInfo timestampTokenInfo,
+ out int bytesConsumed)
+ {
+ if (TryDecode(source, false, out Rfc3161TstInfo tstInfo, out bytesConsumed, out byte[] copiedBytes))
+ {
+ timestampTokenInfo = new Rfc3161TimestampTokenInfo(copiedBytes, tstInfo);
+ return true;
+ }
+
+ bytesConsumed = 0;
+ timestampTokenInfo = null;
+ return false;
+ }
+
+ private static bool TryDecode(
+ ReadOnlyMemory<byte> source,
+ bool ownsMemory,
+ out Rfc3161TstInfo tstInfo,
+ out int bytesConsumed,
+ out byte[] copiedBytes)
+ {
+ // https://tools.ietf.org/html/rfc3161#section-2.4.2
+ // The eContent SHALL be the DER-encoded value of TSTInfo.
+ AsnReader reader = new AsnReader(source, AsnEncodingRules.DER);
+
+ try
+ {
+ ReadOnlyMemory<byte> firstElement = reader.PeekEncodedValue();
+
+ if (ownsMemory)
+ {
+ copiedBytes = null;
+ }
+ else
+ {
+ // Copy the data so no ReadOnlyMemory values are pointing back to user data.
+ copiedBytes = firstElement.ToArray();
+ firstElement = copiedBytes;
+ }
+
+ Rfc3161TstInfo parsedInfo = AsnSerializer.Deserialize<Rfc3161TstInfo>(
+ firstElement,
+ AsnEncodingRules.DER);
+
+ // The deserializer doesn't do bounds checks.
+ // Micros and Millis are defined as (1..999)
+ // Seconds doesn't define that it's bounded by 0,
+ // but negative accuracy doesn't make sense.
+ //
+ // (Reminder to readers: a null int? with an inequality operator
+ // has the value false, so if accuracy is missing, or millis or micro is missing,
+ // then the respective checks return false and don't throw).
+ if (parsedInfo.Accuracy?.Micros > 999 ||
+ parsedInfo.Accuracy?.Micros < 1 ||
+ parsedInfo.Accuracy?.Millis > 999 ||
+ parsedInfo.Accuracy?.Millis < 1 ||
+ parsedInfo.Accuracy?.Seconds < 0)
+ {
+ throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+ }
+
+ tstInfo = parsedInfo;
+ bytesConsumed = firstElement.Length;
+ return true;
+ }
+ catch (CryptographicException)
+ {
+ tstInfo = null;
+ bytesConsumed = 0;
+ copiedBytes = null;
+ return false;
+ }
+ }
+
+ private static byte[] Encode(
+ Oid policyId,
+ Oid hashAlgorithmId,
+ ReadOnlyMemory<byte> messageHash,
+ ReadOnlyMemory<byte> serialNumber,
+ DateTimeOffset timestamp,
+ bool isOrdering,
+ long? accuracyInMicroseconds,
+ ReadOnlyMemory<byte>? nonce,
+ ReadOnlyMemory<byte>? tsaName,
+ X509ExtensionCollection extensions)
+ {
+ if (policyId == null)
+ throw new ArgumentNullException(nameof(policyId));
+ if (hashAlgorithmId == null)
+ throw new ArgumentNullException(nameof(hashAlgorithmId));
+
+ var tstInfo = new Rfc3161TstInfo
+ {
+ // The only legal value as of 2017.
+ Version = 1,
+ Policy = policyId,
+ MessageImprint =
+ {
+ HashAlgorithm =
+ {
+ Algorithm = hashAlgorithmId,
+ Parameters = AlgorithmIdentifierAsn.ExplicitDerNull,
+ },
+
+ HashedMessage = messageHash,
+ },
+ SerialNumber = serialNumber,
+ GenTime = timestamp,
+ Ordering = isOrdering,
+ Nonce = nonce,
+ };
+
+ if (accuracyInMicroseconds != null)
+ {
+ tstInfo.Accuracy = new Rfc3161Accuracy(accuracyInMicroseconds.Value);
+ }
+
+ if (tsaName != null)
+ {
+ tstInfo.Tsa = AsnSerializer.Deserialize<GeneralName>(tsaName.Value, AsnEncodingRules.DER);
+ }
+
+ if (extensions != null)
+ {
+ tstInfo.Extensions = extensions.OfType<X509Extension>().
+ Select(ex => new X509ExtensionAsn(ex, copyValue: false)).ToArray();
+ }
+
+ AsnWriter writer = AsnSerializer.Serialize(tstInfo, AsnEncodingRules.DER);
+ return writer.Encode();
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/SignedCms.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/SignedCms.cs
index 64bd9fe8f7..45a0203b67 100644
--- a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/SignedCms.cs
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/SignedCms.cs
@@ -98,19 +98,7 @@ namespace System.Security.Cryptography.Pkcs
throw new InvalidOperationException(SR.Cryptography_Cms_MessageNotSigned);
}
- // Write as DER, so everyone can read it.
- AsnWriter writer = AsnSerializer.Serialize(_signedData, AsnEncodingRules.DER);
- byte[] signedData = writer.Encode();
-
- ContentInfoAsn contentInfo = new ContentInfoAsn
- {
- Content = signedData,
- ContentType = Oids.Pkcs7Signed,
- };
-
- // Write as DER, so everyone can read it.
- writer = AsnSerializer.Serialize(contentInfo, AsnEncodingRules.DER);
- return writer.Encode();
+ return Helpers.EncodeContentInfo(_signedData, Oids.Pkcs7Signed);
}
public void Decode(byte[] encodedMessage)
@@ -118,13 +106,17 @@ namespace System.Security.Cryptography.Pkcs
if (encodedMessage == null)
throw new ArgumentNullException(nameof(encodedMessage));
- // Windows (and thus NetFx) reads the leading data and ignores extra.
- // The deserializer will complain if too much data is given, so use the reader
- // to ask how much we want to deserialize.
- AsnReader reader = new AsnReader(encodedMessage, AsnEncodingRules.BER);
- ReadOnlyMemory<byte> cmsSegment = reader.GetEncodedValue();
+ Decode(new ReadOnlyMemory<byte>(encodedMessage));
+ }
- ContentInfoAsn contentInfo = AsnSerializer.Deserialize<ContentInfoAsn>(cmsSegment, AsnEncodingRules.BER);
+ internal void Decode(ReadOnlyMemory<byte> encodedMessage)
+ {
+ // Windows (and thus NetFx) reads the leading data and ignores extra.
+ // So use the Deserialize overload which doesn't throw on extra data.
+ ContentInfoAsn contentInfo = AsnSerializer.Deserialize<ContentInfoAsn>(
+ encodedMessage,
+ AsnEncodingRules.BER,
+ out int bytesRead);
if (contentInfo.ContentType != Oids.Pkcs7Signed)
{
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/SignerInfo.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/SignerInfo.cs
index 31b22a8c2f..4769dbeb80 100644
--- a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/SignerInfo.cs
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/SignerInfo.cs
@@ -71,6 +71,8 @@ namespace System.Security.Cryptography.Pkcs
}
}
+ internal ReadOnlyMemory<byte> GetSignatureMemory() => _signature;
+
public byte[] GetSignature() => _signature.ToArray();
public X509Certificate2 Certificate
@@ -511,7 +513,7 @@ namespace System.Security.Cryptography.Pkcs
var digestAttr = (Pkcs9MessageDigest)obj.Values[0];
- if (!contentDigest.AsSpan().SequenceEqual(digestAttr.MessageDigest.AsReadOnlySpan()))
+ if (!contentDigest.AsSpan().SequenceEqual(digestAttr.MessageDigest))
{
throw new CryptographicException(SR.Cryptography_BadHashValue);
}
@@ -620,7 +622,7 @@ namespace System.Security.Cryptography.Pkcs
return Helpers.GetDigestAlgorithm(DigestAlgorithm.Value);
}
- private static CryptographicAttributeObjectCollection MakeAttributeCollection(AttributeAsn[] attributes)
+ internal static CryptographicAttributeObjectCollection MakeAttributeCollection(AttributeAsn[] attributes)
{
var coll = new CryptographicAttributeObjectCollection();
diff --git a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/SubjectIdentifier.cs b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/SubjectIdentifier.cs
index 891b072762..506f2dc9b8 100644
--- a/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/SubjectIdentifier.cs
+++ b/src/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/SubjectIdentifier.cs
@@ -3,8 +3,6 @@
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
-using System.Linq;
-using System.Security.Cryptography.Asn1;
using System.Security.Cryptography.Pkcs.Asn1;
using System.Security.Cryptography.X509Certificates;
@@ -44,11 +42,19 @@ namespace System.Security.Cryptography.Pkcs
}
internal SubjectIdentifier(SignerIdentifierAsn signerIdentifierAsn)
+ : this(signerIdentifierAsn.IssuerAndSerialNumber, signerIdentifierAsn.SubjectKeyIdentifier)
{
- if (signerIdentifierAsn.IssuerAndSerialNumber.HasValue)
+
+ }
+
+ internal SubjectIdentifier(
+ IssuerAndSerialNumberAsn? issuerAndSerialNumber,
+ ReadOnlyMemory<byte>? subjectKeyIdentifier)
+ {
+ if (issuerAndSerialNumber.HasValue)
{
- ReadOnlySpan<byte> issuerNameSpan = signerIdentifierAsn.IssuerAndSerialNumber.Value.Issuer.Span;
- ReadOnlySpan<byte> serial = signerIdentifierAsn.IssuerAndSerialNumber.Value.SerialNumber.Span;
+ ReadOnlySpan<byte> issuerNameSpan = issuerAndSerialNumber.Value.Issuer.Span;
+ ReadOnlySpan<byte> serial = issuerAndSerialNumber.Value.SerialNumber.Span;
bool nonZero = false;
@@ -64,7 +70,7 @@ namespace System.Security.Cryptography.Pkcs
// If the serial number is zero and the subject is exactly "CN=Dummy Signer"
// then this is the special "NoSignature" signer.
if (!nonZero &&
- DummySignerEncodedValue.AsReadOnlySpan().SequenceEqual(issuerNameSpan))
+ DummySignerEncodedValue.AsSpan().SequenceEqual(issuerNameSpan))
{
Type = SubjectIdentifierType.NoSignature;
Value = null;
@@ -74,13 +80,13 @@ namespace System.Security.Cryptography.Pkcs
Type = SubjectIdentifierType.IssuerAndSerialNumber;
var name = new X500DistinguishedName(issuerNameSpan.ToArray());
- Value = new X509IssuerSerial(name.Name, serial.ToSkiString());
+ Value = new X509IssuerSerial(name.Name, serial.ToBigEndianHex());
}
}
- else if (signerIdentifierAsn.SubjectKeyIdentifier != null)
+ else if (subjectKeyIdentifier != null)
{
Type = SubjectIdentifierType.SubjectKeyIdentifier;
- Value = signerIdentifierAsn.SubjectKeyIdentifier.Value.Span.ToSkiString();
+ Value = subjectKeyIdentifier.Value.Span.ToBigEndianHex();
}
else
{
diff --git a/src/System.Security.Cryptography.Pkcs/tests/Certificates.cs b/src/System.Security.Cryptography.Pkcs/tests/Certificates.cs
index 4644b764f4..b19fad719d 100644
--- a/src/System.Security.Cryptography.Pkcs/tests/Certificates.cs
+++ b/src/System.Security.Cryptography.Pkcs/tests/Certificates.cs
@@ -11,6 +11,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
public static readonly CertLoader RSAKeyTransfer1 = new CertLoaderFromRawData(RawData.s_RSAKeyTransfer1Cer, RawData.s_RSAKeyTransfer1Pfx, "1111");
public static readonly CertLoader RSAKeyTransfer2 = new CertLoaderFromRawData(RawData.s_RSAKeyTransfer2Cer, RawData.s_RSAKeyTransfer2Pfx, "1111");
public static readonly CertLoader RSAKeyTransfer3 = new CertLoaderFromRawData(RawData.s_RSAKeyTransfer3Cer, RawData.s_RSAKeyTransfer3Pfx, "1111");
+ public static readonly CertLoader RSAKeyTransfer_ExplicitSki = new CertLoaderFromRawData(RawData.s_RSAKeyTransferCer_ExplicitSki, RawData.s_RSAKeyTransferPfx_ExplicitSki, "1111");
public static readonly CertLoader RSAKeyTransferCapi1 = new CertLoaderFromRawData(RawData.s_RSAKeyTransferCapi1Cer, RawData.s_RSAKeyTransferCapi1Pfx, "1111");
public static readonly CertLoader RSASha256KeyTransfer1 = new CertLoaderFromRawData(RawData.s_RSASha256KeyTransfer1Cer, RawData.s_RSASha256KeyTransfer1Pfx, "1111");
public static readonly CertLoader RSASha384KeyTransfer1 = new CertLoaderFromRawData(RawData.s_RSASha384KeyTransfer1Cer, RawData.s_RSASha384KeyTransfer1Pfx, "1111");
@@ -19,6 +20,10 @@ namespace System.Security.Cryptography.Pkcs.Tests
public static readonly CertLoader RSA2048SignatureOnly = new CertLoaderFromRawData(RawData.s_Rsa2048SignatureOnlyCer, RawData.s_Rsa2048SignatureOnlyPfx, "12345");
public static readonly CertLoader Dsa1024 = new CertLoaderFromRawData(RawData.s_dsa1024Cert, RawData.s_dsa1024Pfx, "1234");
public static readonly CertLoader ECDsaP256Win = new CertLoaderFromRawData(RawData.ECDsaP256_DigitalSignature_Cert, RawData.ECDsaP256_DigitalSignature_Pfx_Windows, "Test");
+ public static readonly CertLoader ValidLookingTsaCert = new CertLoaderFromRawData(RawData.ValidLookingTsaCert_Cer, RawData.ValidLookingTsaCert_Pfx, "export");
+ public static readonly CertLoader TwoEkuTsaCert = new CertLoaderFromRawData(RawData.TwoEkuTsaCert, RawData.TwoEkuTsaPfx, "export");
+ public static readonly CertLoader NonCriticalTsaEku = new CertLoaderFromRawData(RawData.NonCriticalTsaEkuCert, RawData.NonCriticalTsaEkuPfx, "export");
+ public static readonly CertLoader TlsClientServerCert = new CertLoaderFromRawData(RawData.TlsClientServerEkuCert, RawData.TlsClientServerEkuPfx, "export");
// Note: the raw data is its own (nested) class to avoid problems with static field initialization ordering.
private static class RawData
@@ -374,6 +379,80 @@ namespace System.Security.Cryptography.Pkcs.Tests
+ "73aef677d25ae8657f81ca1cd5dd50404b70b9373eadcd2d276e263105c00607a86f0c10ab26d1aafd986313a36c70389a4d"
+ "1a8e88").HexToByteArray();
+ public static byte[] s_RSAKeyTransferCer_ExplicitSki =
+ ("3082033E30820226A003020102020900B5EFA7E1E80518B4300D06092A864886F70D01010B0500304D310B3009060355"
+ + "04061302515A310D300B060355040813044C616E643111300F060355040713084D7974686963616C311C301A06035504"
+ + "03131353656C662D5369676E6564204578616D706C65301E170D3136303632383030323034355A170D31363037323830"
+ + "30323034355A304D310B300906035504061302515A310D300B060355040813044C616E643111300F060355040713084D"
+ + "7974686963616C311C301A0603550403131353656C662D5369676E6564204578616D706C6530820122300D06092A8648"
+ + "86F70D01010105000382010F003082010A0282010100D95D63618741AD85354BA58242835CD69D7BC2A41173221E899E"
+ + "109F1354A87F5DC99EF898881293880D55F86E779E353C226CEA0D1FFCC2EE7227216DDC9116B7DF290A81EC9434CDA4"
+ + "408B7C06517B3AFF2C9D0FD458F9FCCDE414849C421402B39D97E197CA0C4F874D65A86EAD20E3041A0701F6ABA063AC"
+ + "B418186F9BF657C604776A6358C0F031608673278EFD702A07EE50B6DC1E090EEE5BB873284E6547F612017A26DEC5C2"
+ + "7533558F10C1894E899E9F8676D8C0E547B6B5C6EEEF23D06AA4A1532144CF104EB199C324F8E7998DB63B251C7E35A0"
+ + "4B7B5AFFD652F5AD228B099863C668772BEEEFF4F60EA753C8F5D0780AAED4CFA7860F1D3D490203010001A321301F30"
+ + "1D0603551D0E0416041401952851C55DB594B0C6167F5863C5B6B67AEFE6300D06092A864886F70D01010B0500038201"
+ + "0100BB7DDDC4EEC4E31163B84C5C3F4EA1B9314B75D4CCCA8F5339503DC6318E279E73826AD77AC6EA4344F2905D8792"
+ + "83D867A66319E1EA383B70CE997A98D545FE258E38C577554E3BBDF42349B98BED9C94B7CE55D51F740EF60ACC75D017"
+ + "F3D0D1438F8F86B2453F2308279521EE4AC09046498F60ECEC8867E7BF011C882A514BF85F6C915A70E0383AB5320034"
+ + "19A107A9FFEDBF34681AEEE57DF6A3DB3759D605A9269FB694D8EA56A90740529159D725BFD70C9141A38B98D4E88CDC"
+ + "31124ABBB4C3D3D49C220CCB6F2F94176B8225A0E2ADDB0F4A72E6B021601CD297AC45A0CAB95EBAC4001C8167899868"
+ + "3188DB9364AAD52D4E28169CC898B621FF84").HexToByteArray();
+
+ // password = "1111"
+ public static byte[] s_RSAKeyTransferPfx_ExplicitSki =
+ ("308209810201033082094706092A864886F70D010701A08209380482093430820930308203E706092A864886F70D0107"
+ + "06A08203D8308203D4020100308203CD06092A864886F70D010701301C060A2A864886F70D010C0106300E0408101C5A"
+ + "3E2DBE2A9102020800808203A0F58476F5E4741F8834F50ED49D1A3A5B2FC8C345B54255C30556B1426C1BA1D9EE4440"
+ + "CD63CD48557B7BDC55D877D656183E2815DEDE92236E036E0D7FD93022174EFA179A85EF76DEE10950EE3BEB004FB118"
+ + "C58D4372A319575DB129F5912B385E63E1E83DC420A8FC8C23A283977480281EDDD745D97EC768328875D19FE414D7D9"
+ + "9D3B0AAA2FBA77346F82E4E1357C54E142B2F5E929CBD6057801F49ED08A8BD2456918CCEDAD6DAD9A7281C4EFD2FCF5"
+ + "6F04EDC5E62E79741024AF8BE401141AA9A9CE08F5D51D4636D8B25F9B3C59B4BC2DD7E60FBABA0A7E8FE15EAECB7221"
+ + "3BC22D8CE56987427B41A79333FB4B9BC5DB6E79C2AE4E954F975C343D155C5587BD7206414B9C0529D00C6DB1470C33"
+ + "A51D2A9BBDE5CC2352C61B0FB9945487FDB0E26981426BE7CCF44CF494E695D4760060468B7D23BA3C6F9B1762AC4B3A"
+ + "428B23A36F275F3FDFD7BAB236197C7C7FB6466A11B05DB39F947FB19EFE9BFED2B18308E2BBD0AB00AA399508194CB2"
+ + "1073B1B278BE389A8AA843B610B439AFA056A0EC81EBDF4061D2AB87C9CB840C3E6B92BB2FC30815D5744593862CC34A"
+ + "EF1C4B7BBCF640CBA2D1E15E13D3B571FD3C403BC927812B291E53EAE6721C994E343148C10A16053AE560A55DFA5695"
+ + "33CA35D83D81643CC7788E7F94C6592F99C09AFB770E9FE1380A1212A646A936BE531BF85F89D19EF57C180E8E3F1F4F"
+ + "BD266032095862E3A0F8394E93CEFF2B8ADAD374DFCB8A041DB498618D1D71765EFD1CD5B024AC13B9FF0F96F975B443"
+ + "08C14AC60965082CC409AE43D033512CF1B83458D475D2E06A49131894F1D4BFAF5FC4CBADA8566B6312E8DA31D8A397"
+ + "273BE77B8395F4CAB4428B22DFE18FD4365C134B7724220D2DCE31938EFCF8E4DFC321E02CF15476BF5EB675F2055205"
+ + "9662166A4549904BC6A5E4B8353C43DAC225317F4B4FA963C900F0B0D0E7FC854BE91A1CFF330FE77B03776EABD0326B"
+ + "0FB37AC5176CF82530960F423B13299E037285C9324E0A872414ECF35735F58463506EBFB2CC91D790FC0D67E2714287"
+ + "960C68FB43A7EE42A14F5397F07E055E75EE4F7D047634907702EEC8ABB08D82C82CEBE2B042B1F20367DFDB839B82AF"
+ + "88F72272AE91DA94CD9B334343196889381FE307A76BE0B627EE32D827582A7CD68BF467D954805030753FA8DABFCC21"
+ + "E68A77E2A76F9E95E61A2FBCA1C8FFC2CE272E9D125E5C65759529BF3FDD2E28722EC9B7B57BD9819BAAC01556002D88"
+ + "3B8BD842C3EB3BCC4A54B4D0B1DB32ECEBA8DD668D67C859A6EB0BAE293082054106092A864886F70D010701A0820532"
+ + "0482052E3082052A30820526060B2A864886F70D010C0A0102A08204EE308204EA301C060A2A864886F70D010C010330"
+ + "0E0408482E476C7712FD7202020800048204C8AF5357D64578320D963917F44B2B7714334AAE6571554F03A599913275"
+ + "4BA03892316159385225C4EEA7C958091BC8A32A9433AECA3A07F791ACE431217F0DFBD53DC15D257069B99DA04EF719"
+ + "892004FD307E151EBB359C1D69AE8FF78A1CC1654470B0862CDAC1AED521608C29AA8D30E81A4015D54F75421B9BDB29"
+ + "5036D79E4535F28D4A2ABF4F203BC67065A709AEF6EAF4D6A3DC7387CB3459D82399F4797CE53FD2BD0A19B1A9566F74"
+ + "246D6B6C50BD2777B6F6DE1A8C469F69D7EBF230018D56DF4C1764862CD982E81F56A543DA4ADB63EF8612A1BB561471"
+ + "56035541B0B41F06BBE2CD47DC402A75023558205870060438CF99D8BFC7CAADDE0583311FE4B854051C83638420BC5E"
+ + "93F999E67EDBBC266F519609E2BE9FC1BC3C7FEE54DBAB04DAC8A94BB347F3DC28DDAB7D28DD3BBFFB44C84E6F23A8E0"
+ + "1CAB36382723DB94CD8973A303D8D4C7A22B9F811C07ED9A78E06135E0426FC93BB408F1DC915DF4ADBF048D22C201D8"
+ + "0FDC0EF942D1E2AC0F39F8A95BA849C07BB0DA165B3F0317478870F704B8A34B7D5816BC4F8CA0C6BDB5346F2211416C"
+ + "79D7117AD1B86E44E0BC0C3793F9895638E5B7A2A5B957E0E691819AC7FA1F05E8D05ED99E4E286C96E3E31DF99633E8"
+ + "CB73CA135109AE727CB047641726A1599492B6F3E8E62195A79239279B2A9FBF47B31FEFF3C20DEC2DFBDB0CE98B183D"
+ + "BA773561DEE404BA1A5BEF5AB9729DBE22FB1C17EFD4D3AC81F04F49F9855CEACECB202090A1290C10E9D676F0658F3D"
+ + "E4C43DCD5A17B88881893DA87060C5F56D5CC9A92E6B1A47A6D16FB32C09925606F6D5C7CAFBC7A82D8E441A05DFBEE0"
+ + "BEC92D89264B62D5DECC342D29D9A7727BBDE4E63EEB7CAED7C76953F6AC8CB570619C7607B753FD46889C76D29C9AC6"
+ + "6F56CB3848323FA9CD16578EA5C6D876AE63D95F65E2CDEF68A1CF3D2FC3DF91D0055B0CDBD1510E291C0E7AC6EAA0D2"
+ + "AB5E8FAD44108C94A592251447926DB7139BC2A433D61711C6DA5EF82A8E18CEBF99AF753E33FFF65126B7D3D3D09FF0"
+ + "C50EFF7822FA8797BAC52383B94E8FE602E62577994ACA6A2150F60A31CA0E79FE6DF3405D6918EADC2231558FB29045"
+ + "034EB9DA9FB87BD71996C6AB6EA71A70EBFBC99BC292338A363176516C14EC92E174C59C6BE82F5BC0296525109C9A7F"
+ + "C9D9E654955992A5C9EDFD39ED9889BEAF105B2EF62B041789F20A6AB26563FCFA1A1482EE2A20E8C1A2F0931ACBA7F8"
+ + "756EE4C9119D29817ACA7D2B81FE736FD7A33D20EC333AC5123D29345647B734DB24B5C56B4576ABBF9B02F782DDE0B4"
+ + "BA277080F28F3D86DEC35F0F19B2B5DB0BD7A59B7C4B2BAE08E8584449BD3685F371F6A24F5F91EA6843DC6ABA89976E"
+ + "589511EB23A733D23F6CE076C952E9E7190ED78D5A34387F93418A87CB02270941F19DD35E1DB5836E67296A7F28A5EB"
+ + "8F32DA73EA7A47D5CEB292E767468CDF938A44B3CEEE6276A34705606A8F7496D7310DA1A0468A604B8A9E7AB50450A6"
+ + "DFE0C4540CEA058CD7919E823D8A32FB811C6BF8754C65D7A9723018ADE95AED5C30978A8DBA185CF0BA36346456CD3E"
+ + "15C511FAD71B445DDFA7C5455A3597FE536E3BB87518C0725D6BE673D05DC5E74B4FF442711D242A37D0CCB88E6D19BD"
+ + "6B7299207D7036EB87D5E86189768CB14AE4F8886BB5AB7864BDA9757D0C26BFFF3FAA4001258557D394313125302306"
+ + "092A864886F70D01091531160414080FB9AAB81BD67FD85C2186B359054CEB13D2D730313021300906052B0E03021A05"
+ + "0004142C205F0B1E9B99B0ED14E83F13D84BC683F66D3B04080D22E45D6A657CC602020800").HexToByteArray();
+
public static byte[] s_Rsa2048SignatureOnlyCer = (
"3082032C30820214A003020102020900E0D8AB6819D7306E300D06092A864886" +
"F70D01010B05003038313630340603550403132D54776F2074686F7573616E64" +
@@ -623,6 +702,504 @@ namespace System.Security.Cryptography.Pkcs.Tests
"0CCCFDF387DB300A06082A8648CE3D040302034800304502201AFE595E19F1AE" +
"4B6A4B231E8851926438C55B5DDE632E6ADF13C1023A65898E022100CBDF434F" +
"DD197D8B594E8026E44263BADE773C2BEBD060CC4109484A498E7C7E").HexToByteArray();
+
+ internal static readonly byte[] ValidLookingTsaCert_Cer = (
+ "308204243082020CA003020102020401020304300D06092A864886F70D01010B" +
+ "05003029312730250603550403131E4578706572696D656E74616C2049737375" +
+ "696E6720417574686F72697479301E170D3138303130393137313532355A170D" +
+ "3138303431303137313532355A302C312A30280603550403132156616C69642D" +
+ "4C6F6F6B696E672054696D657374616D7020417574686F726974793082012230" +
+ "0D06092A864886F70D01010105000382010F003082010A0282010100D32985C3" +
+ "0E46ADE50E0D7D984CC072291E723DC4AA12DF9F0212414C5A6E56CBB9F8F977" +
+ "73E50C2F578F432EDADFCA3A6E5D6A0A3ECFE129F98EAA9A25D1AB6895B90475" +
+ "AD569BF8355A1C4E668A48D7EAD73206CCA97D762EB46DA75CF189E2EC97A8DE" +
+ "BA8A4AF9CFAB6D3FD37B6EB8BBED5ADA192655831CFDAA8C72778A314992AB29" +
+ "65F3860B74D96DEB2E425216D927FCF556B241D43AAF5FA47E2BE68592D2F964" +
+ "F5E0DE784D0FAD663C3E61BD4A4CF55B690291B052EC79CEA9B7F128E6B8B40C" +
+ "5BADCDB8E8A2B3A15C7F0BD982A1F0C1A59C8E1A9C6FC91EE9B82794BA9E79A8" +
+ "C89C88BF8261822813E7465B68FFE3008524707FEA6760AD52339FFF02030100" +
+ "01A351304F30090603551D1304023000300B0603551D0F0404030206C0301606" +
+ "03551D250101FF040C300A06082B06010505070308301D0603551D0E04160414" +
+ "EEA15BD77DF9B404445716D15929ACA4C796D104300D06092A864886F70D0101" +
+ "0B0500038202010046AC07652C232ED9DB6704C0DD318D873043771CD34CA966" +
+ "91C04E5B7A311805E965957E721358B2ABA55A0445864251263E09BFE2EAEB64" +
+ "43EA9B20F05502873B50528E48FF5FD26731BEA1B13CA3E3A3E3654E6A829675" +
+ "B9D7944D734C48D36E19B88B77320A5096BF7462E1B4D69F1DC05F76A9417376" +
+ "D5127027B1BA02380684DCEB75A4B14FA36B2606DDBA53697CE7C997C2FF13E4" +
+ "66234CBE07901DF33A037F323FEF8C4229F2B7D030BAC88B4C3D84601576B0DE" +
+ "32F3116C6DF7E9AA29028289E0CCA89F8B809310C37E9BD514536131D9E66AF0" +
+ "6B1F36BAD55C9F9D6D1393CF724D75D3441AD67491AA76C8C31AADE22209831F" +
+ "C079B49408ACC2C0D975EF8BEE3E0F6A01DA4DFC6045433BA6B1C17BB0E3E181" +
+ "22770667CBD6197413569470BF0983BF358C6E09EC926631B0A2385D3BF9D9F3" +
+ "0B5314170865D705CA773652BD66E1B3C112D7DA97CDFB9447FBFCD4DF674AB8" +
+ "A6F430760276B7D8439BE40961D0B7F9F2B7AC1D291C0E67C1789FE038B6652D" +
+ "24FCAF0A49CDB1E61FBA146AEFA3D934BF3B6AE8A5703CCA80AA500B56DF93FA" +
+ "931E2D71E292042342CFB073431AF0AA1ACC0B5F53EBF66CFECD52EB08B11628" +
+ "000F5EA01AB1D8E89F219178DB67B2CD68AFC2C0C248D8A65FD9AE1A0DBFF84F" +
+ "3BBF2077EBFB373F6ED8D6C7CEA7BFDF0425494078F293949496B0BEAF63CAB5" +
+ "62C297590A737174").HexToByteArray();
+
+ internal static readonly byte[] ValidLookingTsaCert_Pfx = (
+ "30820AAE02010330820A6E06092A864886F70D010701A0820A5F04820A5B3082" +
+ "0A573082059006092A864886F70D010701A08205810482057D30820579308205" +
+ "75060B2A864886F70D010C0A0102A08204EE308204EA301C060A2A864886F70D" +
+ "010C0103300E040809F1CB8B4255EADD020207D0048204C83EF1251C78FF3815" +
+ "CDB0648F20FF20FA0437E5AAC5CB91C0D547755113724A913C02427A12A878E3" +
+ "B161F388F4DA9AEFBBA5FEB274CEF3A35CC2EC4BFE32442E5B6624888D41FC3B" +
+ "EA02BBEDA034BB196A3FA41E23DCEB6F6E906FD86FED066D547518FD628C66F0" +
+ "1AA4B38F3DDD94D63A5B336B587BAC4D2B739EF096A902ECC4216EC284099F10" +
+ "C93785AFC3939A44C22FD027E4E643B03641FB3B76B21DB632D8522A365A495D" +
+ "5AC74CF7765E294CEC55C73F6A4BB45ABD214D7AECBC3735DA41D8FC66CD5C34" +
+ "54F354E16084D0E1984B20423219C29CAE0FDCD16A16C5BF17DB23DD8F2B1C1B" +
+ "DFC9008B647D2FD84E4EC7952BFDF4EA0F0A13D57CD530109BFBA96DD3F37F01" +
+ "7F7BA246C35A9D5C0A2294A2EEFE35B29542A094F373B6FFECE108D70CEDB99C" +
+ "A7172B17C6C647CD6614D3FAE0C02B3D54062FD8392F152AB1B46D1C270A9F19" +
+ "A48A393CCF22EC3DA958C35A8A6A3E7CFFDC2C54090F844B3B73C3CE7F7EF26C" +
+ "982567ED621FDB93E402FC145E6D7E8D7F2F9C56F870823C98B81586F34C7C96" +
+ "CBAA5A67544964FA1BD70B9C5E8284ACF22FFC69BF62E389C5678E44CB10D6C3" +
+ "D3F73DA7BF12B44D74C0233C140ECC93C5F0118C8F0D9B6FFDFB23966ADC070C" +
+ "8DBFAFE78AE1E05F8FA7C75A22FBF7A8458B9C61B1F2BF2AD2F0A6C6D15AAD55" +
+ "D960F173AC3D9890CAF50228796FAD6C7EAB1C8A3C8E9E42E4A4DA99C4A67FB3" +
+ "E2AC958AD989508538C96697A0CFBEEB38E9CF27DAE3AB9492729A205CB25340" +
+ "85CA0D580DCD49E88DA7950F99CD05523885B5257BD302E1B449F03941BD0DA1" +
+ "ECCAE6A22BC9F7E446F7F6FD4EE850CA3BDD7338F705D93C2F196712250BCB1D" +
+ "A18C9661E195486768515BC2761A66F61770589A62D172DF8EC288549E86E518" +
+ "7B04E1550154FF45060945BDA07014F14EB554A5A324F9B79DA192F79AB0745D" +
+ "F30355DF580778773F2FFC76FB7B367EDBE173AC7F70698766DE6BB384A5C88B" +
+ "66B163E8ABBF0AA44C4ED0D3D51D167E8BEFB2E71D36043ADB098BF2DADD409C" +
+ "1F53F5546D1C8A1DC5E7BE566D14C494460161BFA7CB7E936790A81A45763004" +
+ "689FA9BC33F31B4E86A152700D35B20380F87F4304D7850CA7BF583724328E0A" +
+ "0D9B611B919975DF118B334D9DD96A46A21B00FC3B7FCCAFEA968FF030EA5D8F" +
+ "9AD8624F668B2A7E433E54547EB89FB876A7E1AD2E9DAA38F30E938D8BCFB431" +
+ "6E12FB8BEBF57FD0BF542E55386A6DEE074CFC6A33A55A57503CAB7F115DB875" +
+ "C8EBF787670BE98DC03C65F2502D6F8D001ECC819BBB9C60BFC3A88DB8A117D9" +
+ "9E09C13AC23324E15E5EE3C22B084D428FF2DFB37F917F7629F8A15093BB7777" +
+ "B1AD8CACB4A5C6271E8B21A18DB95D6196E9EBD870521CA16930F2D1D43962AB" +
+ "B8413016DA0117E10AB2622FC601DD08826429D8B8AE9BC6F15AE78392C36BC3" +
+ "06FC19C90AD43BADD9AACDFA8CC16075529BFC8C34766C12783BF2F2E0B393CD" +
+ "4F8F05D588B99218806D57CD5935E25DB2AE20DC4CDFD7F5111AF9A9EFE45349" +
+ "42CAAA72F1F95636085FEC84BB98D209FD4222BC5F84DE5926A28FF7A5B7548A" +
+ "B4FC3331431964454A0C532C205CF8D3872C561E83D805F7BD7DC811A0A90C9A" +
+ "CB308E8F06AB739DCE97A840B4AFC0E884982CFC9B37897CF272ED1F46027101" +
+ "BC97B11F04D64B07556DCFD5F609C5C9FB4B3F2AB345CAB46211EF0BE5ADD6BD" +
+ "3174301306092A864886F70D0109153106040401000000305D06092B06010401" +
+ "8237110131501E4E004D006900630072006F0073006F0066007400200053006F" +
+ "0066007400770061007200650020004B00650079002000530074006F00720061" +
+ "00670065002000500072006F00760069006400650072308204BF06092A864886" +
+ "F70D010706A08204B0308204AC020100308204A506092A864886F70D01070130" +
+ "1C060A2A864886F70D010C0106300E0408C10D9837801E56F8020207D0808204" +
+ "78827979D15533A4A7210A435D0189C133B65B00407E85BC44368D066C65007C" +
+ "256EE51A55E35BF8EE7C6FAC3D67FF7CF2031FECDCC356A51396B2977E044A79" +
+ "E6C6CB8859E4AD49765468A4A467071292EFE47AEB39856FF8F00B5C6C6190EA" +
+ "B20CC9A7C630C09E3F351ECB20CEC1BFE7BEB5A3FD534BAF8CDB658318A37279" +
+ "269A11E8A87074FF0B111E2CFC493BD08D7887A7A222743B0C50E47F676F9B47" +
+ "449F8FCBC6AE5F5A3456AE6BC3CB8A3CF28C59D0A16FE4336E0BFCA0AD74F95E" +
+ "0F1010C3F698E16418E46B0059AB8F3DFD31FDB99132665CEC4CDAE8B6C1D0EA" +
+ "9DADB8E591769261C27188CD5FF8D5C56E6866D85E1502254823940EC77096F0" +
+ "6D3A261F49495AA60114BDDCA27C603F78314678CB08738FA2974DE03BE315F9" +
+ "1FCA511446C68127211CF575948550DE4F7FDBF4AC31E395E12EBFD4BB99F470" +
+ "498846940A92B6F85CF5D745B5230EAF994DD368FF55809F299213749CBABE54" +
+ "C54D39B2165370DA43468409E73C55EF784D17496AAF8B6B5CC0F9FF234D7CF5" +
+ "C84C248E91F8B08F74A8A953F60407940A2EB9576655CD9946D468DD6B3DB634" +
+ "A30D4FE8E09C51AAB99C3DB5CC834A447EFBFDACEC9A49AFD675BCB247575B27" +
+ "ADEEA9C5A6F2FCFF71A57EA99B467029C3E40D94D2849527FB90B9BF39294CC1" +
+ "AD1F4CC18F75302FF241E05896A357BAAB88BDA8F7EB22B9AEFC5D7600154631" +
+ "3C2E87452F99997CF4747CA936BD9199C61CEE5E61BBDB80C17978938F241D53" +
+ "AAC97758FD1A77F3C7C28F88F1BDC7E74176CA41B73B7042A6C3C7AE918635E1" +
+ "1EF4F2607588B0FF7C656541C32A1450AC71AEA42C14E94F0408A09902C30D10" +
+ "ABE8396EDF5760991C2E02949EED06D091A2AB64827A53F29FA8B8B79036DA26" +
+ "210A7C34EBE73590DAE990666E0F0F011EE8E41D08E16B28D49F30D8539EF18B" +
+ "61860EE73D9AF98E4D3F17A50D06FC0592C218F38C33E0B526761D030E037B27" +
+ "348CFDBB72C6B635BAEA497BA12618BFA47A9E358EE834FBA8A5FA9D30A66CFE" +
+ "BFAF1E25FAA361F94433B40628E7423491BBA29116EA6ADDC6DFEFFA3AC2AD83" +
+ "83C3EA05DE72B7CE357612A9C60CADCD42DECCD40438A9FC8E5D9413825178A1" +
+ "9D67E7B13449F118A6B56A4F8A5DCC0AA05D0AB40B8FE0820A2399307331524D" +
+ "B3389C97181EDC2ED2C5B72C1318B406CF99120CD784B85238488D1DA062478D" +
+ "1EE6380F9954BE5442C1C00ABF8D284AF95937E2D515E2E8858F3C50516CA00F" +
+ "E3F632BB05EE4AD63A6F2D72C7F2B06DC993866F6A740C1EF5159117437F646C" +
+ "A47AA4BE5936C2F6BEF4C628A744FA2A2E2068752FF43BB9CB29C986D3A466FB" +
+ "F3A107E8D610B8236E4E074CD6B32B50BF1C389CBDC2A92FDD19047450E04B4F" +
+ "B963CA94860C1DF05D9FE1D202227E351BC2226572D6950D7E5242BE17DCC992" +
+ "A989B7D13BAB9C8EC76FF5B8DED7696BBDAC058F6183F6F799365EA1DCC4F1B2" +
+ "43A35027BA2F02E19DFCABEB564536EDA7B073519C60294C4AC25956D9F9DA60" +
+ "3C5E4F335D7570299993460BDC5F20776F22D745A6B3F7E80EC69DA881AC72A4" +
+ "D6B7AADF7EF19C77A2555C1CF8CE1CEB030EBF1C365D40C9C33037301F300706" +
+ "052B0E03021A0414AACBB391FF9626295715807ED7DDEE57F716A5710414658C" +
+ "344F4B20292DD9282953DAA4CB587AD48714").HexToByteArray();
+
+ internal static readonly byte[] TwoEkuTsaCert = (
+ "3082044030820228A003020102020401020304300D06092A864886F70D01010B" +
+ "05003029312730250603550403131E4578706572696D656E74616C2049737375" +
+ "696E6720417574686F72697479301E170D3138303131303137313931325A170D" +
+ "3138303431313137313931325A3026312430220603550403131B54776F20454B" +
+ "552054696D657374616D7020417574686F7269747930820122300D06092A8648" +
+ "86F70D01010105000382010F003082010A0282010100C456AE596BB94EA55CE7" +
+ "D51785F44223F940237C1F0A279533875427547BDC3944B73E8E6F4463800571" +
+ "226147CEA3649972F96F128B673BCA6BBFD70B5178FE93D4DD7BE9E4D450AA0B" +
+ "4D177F24DBCB2A7A13D7F10BABCE0E9AD3B853F01872196F6905F523E260555C" +
+ "AFC5B158A82ED52D62BDA32142982EE8BB4E011E44622B59387B8A287F4DD7A1" +
+ "5C783EAB5D4736CAB0E06A78EE50A7BA59DFE2C35DAEA0637FD581DB485ACA9A" +
+ "57B94585A9E7D7BFAEE31F92F96DB5F95DDCE52B839BC06C30191014FE6804F0" +
+ "CF4CA29412EB34D87303CE5FB49EC3E4B1A7CB001B6F117E1D5846A605ECF5D6" +
+ "8FDC32EA972CC8521B823708518BBE59D15D10DB79990203010001A373307130" +
+ "090603551D1304023000300B0603551D0F0404030206C030160603551D250101" +
+ "FF040C300A06082B0601050507030830200603551D250101FF0416301406082B" +
+ "0601050507030106082B06010505070302301D0603551D0E04160414B163E5F7" +
+ "BBB872522615BB55850DF3D636E8EA6A300D06092A864886F70D01010B050003" +
+ "820201008E5927A04E7D6361819B565EC9C3BFB59F1BBB57007B4534FC5B2F53" +
+ "6A02BAFB2EC19DD8EE65DC77F34E2E7A4A2EA1597EE2019CFEBE8BA45BD35A53" +
+ "D201465818F1B6E0E891FB380813E27FC1F6D9F3D5DC4C23267FB4326960E7C4" +
+ "D69CF837904E694F4DBBD1AA346FC058B158AAC7EDD7F947F67DD09D9183B84E" +
+ "B91CDE170895B830F4DE87850BC79C3E27534298BD8C7E7DAF3CC1242777435B" +
+ "2A80CBD57C015B1B52A5B46D85187E5FF20EE68A96FB705FAFF4E335EF4FDBFF" +
+ "CC5D981943127CE41EFA8C1D7E2E05D03D772E0C02F4443AB3420B6E3D1607BD" +
+ "B2416268AB7D9D2B5824AD82B06ECB58B41C0AE092D704F77023F6CC8918F7D4" +
+ "3128357B7504276C805E6C27A0A5872C89375F69FF14E91B4A11922DFE7B8142" +
+ "8B103B55973214426A063DE2955AAB165CDF105E574F23C00E50FF5B8AB86222" +
+ "460734EF5003A0D780DA6FEE9B8CEF0AF45C0BB1D0D142C4A2FDB2BD9776B049" +
+ "B70FB4B52D2EF2141E3C3EC8F4BD914209C2F2EB31FAB2311F906EB48D4396D8" +
+ "5C5D9B54FDCF52C00FEDB9F399607C1D95BEC1D81BBF8B9E35C36BC72FD90834" +
+ "AE8D4A02DFF4FD65DB9748DB626FD4D387A4E0E5ECB73168AF3BB3C788DFAD4D" +
+ "CECCE43F9513EA99F1AFFB2B900F5AC55DE8D7AF96B243BA663500A63E4A35D4" +
+ "7257229376EE8C0179396C355DFEEEC03F8773BA1DD5B0807E44EA1E11257751" +
+ "67020DF9").HexToByteArray();
+
+ internal static readonly byte[] TwoEkuTsaPfx = (
+ "30820AC602010330820A8606092A864886F70D010701A0820A7704820A733082" +
+ "0A6F3082059006092A864886F70D010701A08205810482057D30820579308205" +
+ "75060B2A864886F70D010C0A0102A08204EE308204EA301C060A2A864886F70D" +
+ "010C0103300E0408C4A9C5FF5EE508D5020207D0048204C8344C1DBD71C360A0" +
+ "B4ECAD9F7F43F25272B5C99F1D54A7A0926401082B4E1512610D52B15CBD8203" +
+ "36AB72F4E57D083B49BBD606F5C1A268B66E7931E0980A06D8EDF5B5C0BCDA51" +
+ "908E21890B24054867912D65125BA0F75B561175A053D2F875C1C846CDC6AFD1" +
+ "7599AE877B8CF18585BC405B1E356FD49AAB207BC7C2BBCEF1B0E9FA2EBE205F" +
+ "E5F98F825BD9564FA45A7FF011EA41A247AAFA06391C62BAC548A004A139F9C8" +
+ "8039B1837066BBF5DD7E8DCEDA3B13ACA5214A53C8D6D748B4DA885CA59741B2" +
+ "5799051D59AECE8F06EE0C637406A91070C7DE72B2FAF982BB0A9D937C517D5D" +
+ "B0F4D0EB69FDB597F8695A9BC42DD5F87F56119AB5F3E051B0E03E4A069FBF39" +
+ "3C5592E1BC28264BDED3ACD7D0CBB5DEE9B426101C6CC5752A5068DF4520C71C" +
+ "F10875F1F23BF84D4B6D3A2E133E059A8B1F02B47258F36F84AF4EAC85045489" +
+ "971E63970A614CB05C3FA28A711F8DA220C23E463E50B17408E05316F1CB32CA" +
+ "37A0C4262081E9C60D897559FF167F2F9B58162399368DD5B85309E9B941FE32" +
+ "356258D2EBBBBAB957F496742DB2CF7D8233EBF879887B3F07156BFF9D2CF87B" +
+ "D495C684CDF46E451715D4CA1DA21F960868BA70CE88D4D8904EDB97EF69435B" +
+ "DC89648A1C330757D51B9D94AF48814109B13EC4AAE6EA99B2ECE5DFDD384F71" +
+ "E3A4D39328F5FC55344E2B6EC68D164F57B92AC17D6BF52AF153D431E06770DF" +
+ "53A8F14AC579E5E130FC5C3A665E5BEE8CCACC5188191B00EFD13A3A0DD1CBA2" +
+ "FAB565CCE5459DCE7CBF8332A3FA1A6E943AB05A2BD28A35025A19DDE18A63E9" +
+ "123BBA96B0147221E7CD90CA3A8DFAD634CF8A24EC1AF619CA7B43D844B078CA" +
+ "AC708A4D1775AE368B583785307CA3F73C370740DAE2163AADC966BED8EF2648" +
+ "28557C1F10BFFED48ACA7ACBB60CA16724F0FD9A2C79B4556A71C7BEAE5549B2" +
+ "BDF5B165760DF0C7A0977D923952C9DDC95D89D379E0DF0E292D1534753938DC" +
+ "8764451A231F132FE3F40C472CDFED28564002A39ACD4B7059CC284E72D27ED6" +
+ "4204DCE2CF30FFF82EE788950CF24358214406CABAB32332CCD7D14A141162BF" +
+ "832B1091EEA2C845DE9338D96917065E0CBEFFD292232B20956DFE8116C724F8" +
+ "EDB03BED1474460B0C3C45A894C7CEAEA083C2FD5162C926F5DD945BA3BF3A53" +
+ "45E82A93F8BCF462AF4C51F4784F8618FC2DB64B4E4A497F0654F573A2F83426" +
+ "DFF119440981C9ECBDBA7BDD2AB18F2D62B5EDEA6E2396537EEF3A4264EEC3DA" +
+ "4843FF0CD344204C8FDF9C92AF1278937694B30EBE6238AC70D19719D43D77C7" +
+ "6B117C4048A7698B822BF371EEC55C1A4C51A13E4A84822F5370616A67B25723" +
+ "0BB9B14443A8FAA13414244CFA353E414C9E652C447BE58AEEF982FE4A12FB64" +
+ "5FCE47038C15499277FD0EA308036497437DDDF39F596D48FAAC1177112E0929" +
+ "234E3F5389DDC21CE14362729AF3EDCD7F2641A8633C13C1E10FBB808E5881D9" +
+ "A19778C52E8A8D9DD97766B18EAA9F147AB7B184D7DA131148A70FA0D2FB079F" +
+ "E4E4062211D0EF4C3E40D49025BC84C68FC2CAD10F2F5AF80D8174B2A05301D7" +
+ "35F3688D854D5D9A2A4646D7F4FD49A16F9432197EB581FB71906AF7D2A0115F" +
+ "418AA18C1F14285C7197F3508D374947A8769A91711B0D159A71CA3258529DA0" +
+ "C918D8E53E0ADA32E8F32AF11552ED557DC1D8F0F1D027669221C00529B44031" +
+ "3174301306092A864886F70D0109153106040401000000305D06092B06010401" +
+ "8237110131501E4E004D006900630072006F0073006F0066007400200053006F" +
+ "0066007400770061007200650020004B00650079002000530074006F00720061" +
+ "00670065002000500072006F00760069006400650072308204D706092A864886" +
+ "F70D010706A08204C8308204C4020100308204BD06092A864886F70D01070130" +
+ "1C060A2A864886F70D010C0106300E0408E42BF45F0D448170020207D0808204" +
+ "90BE13F1716CAB0C61D6269860EF56B1C6695C35AA4B8333CB772579033EC447" +
+ "9B83662C6EF04487BD6BD3EFC7BEE8C17F5EAD6E73389A9EFD73FEE959F4FF68" +
+ "D31616FA6D24D918F0377555CD68AFFF60F7E7AAF1619C2E1F4B057F5D2CC20E" +
+ "DEA3A8683DF2DF5E6D3C062065B38FFC4C16E7AD27BD31742C8732D09114B768" +
+ "FFAE7BEFD13303C64E8CA18F2571BBB1FFCC3A28BDBDE510D841FF781D7C615B" +
+ "178252E13D24B89D0DE8E47D9160CAE6BDF5E3959BA35218EDC43708F68CB2E6" +
+ "B37BFE52D05141B5BBD351C570B18848C68AC15E109467E373904F3AFDA06905" +
+ "0C1596D2ACED9D2733EB1FA0CD503B06828944463C579986BBC24B443261F1C2" +
+ "2C170F13F3EEAA0FF2EF63200612723AB4A0C768B03C6AC3C6B8D967DA306018" +
+ "2D2E3B412EE8E6E0639C282ADEC3899F36D740CF1CEA888824FBCCE2A7A22AF2" +
+ "06681597D80B907F50F7044B928BFAFC10F2580B5F7380E2C43BD6F273CD7EC6" +
+ "36F3F4F3AD5F2DF9F48CF4B0A4EBB8CB3BA1DDE3448C5ADE45C75CB80CCD61A6" +
+ "AFB2E29BA3833A6465C34ACEB7E47CAEDFC1A6B5DB7E3DE594026B648082732C" +
+ "1A3804E882DECC2018BCC27A29AAB4B98873099025449B9709EB9C0B5F84EA34" +
+ "4A7CE3D0829DE1ED1C89B165A1130DDC8333E54486A94E35A8C017B21DC38D74" +
+ "C6C0A685D68103743DD7DFEBBDF0D9BC55DE11DB3F38F762415BA58B2E52CCBC" +
+ "72B76D70EA1BA331B24F3817DC635FF59A1247A8F6EB1AAAA257388709BE7E44" +
+ "E8A3716A4A2FA0D57E07853EBE9BCE05FDDD23215531BFBAE5E304A9DE44DA93" +
+ "6AFF963085CE099665B03357C295D33A338EDFE664EEF200A957484D51736FBA" +
+ "73924014152949BDF128248ACEF561F51F08456E03E3533354283A74D0BDA10F" +
+ "53BEBD5710C0735C2960188781EBE4B9AC0E658723CBD09C8898FFAE79E5D066" +
+ "EBE4586777E1039D38EFF6C74ACB80365341A868C610377C03DE1B691300FC4B" +
+ "76A7192FD2D37864CFB336852EE9C2FA8AB96F196A0EDD84876B3278C4200143" +
+ "11C933D8C759945E3565C80CE8E7782C4BEC074FA87EF25D951D846FC160A0E8" +
+ "ADE67650FAC6B2A7C8F9798CBF8DAD6B23CE7A429995051CFE6941EF7258A10E" +
+ "2BD776B6C7DD59823A50BB767E38D6CA099553AD0E3982296DBA8AE6D72CC473" +
+ "9F4A9476B113FB06DE80B32F65FEFE0545CB44A3F5940C6776806168C534BC18" +
+ "4E73AB8F7B0E855849ABBAFA9D832246329794682331A05DA97848262E9FBCD3" +
+ "0A4894B6EEDF42150B23EADB3362C54CEC2CDFA9F36F67AD22389B3487CEDB98" +
+ "174644FC2A7C5FEA11488F031AAA30A9F7FE15662C86A0AC5EBAF2FB47CF555D" +
+ "B8D1C85410107C2CF40099DA3B281F0DF391E5602B64DA73B585895DCC465338" +
+ "29BC0E72F178F41179238049BED59D0602BCAD8AC9E9BC140306D8BDD4150C6C" +
+ "4DFD8EA353271B928EA23482E719A58D02515EA83DB54252CB8D466EAC9FD1EE" +
+ "71D00DC6D39362883364E31CBC963CD295CDB490074F5C43759D7DD655AA8A46" +
+ "EE5FE06E186AB3025E71AAABA9DFD8A105ED86B85FF7C772F596BEEE31CA5BF2" +
+ "26BAC1F59123893945BB052A48E9BE2254FF1512B1C2E46D34111F7BA35EA906" +
+ "74FBC63FC70A18F095C2AA6CD060A7B52A3037301F300706052B0E03021A0414" +
+ "A519F103F114AFAD5EB7F368DB4D0748559CDD190414584DD2F41EC2DBDAEA69" +
+ "FB2FF401BD9FC3B57572").HexToByteArray();
+
+ internal static readonly byte[] NonCriticalTsaEkuCert = (
+ "308204243082020CA003020102020401020304300D06092A864886F70D01010B" +
+ "05003029312730250603550403131E4578706572696D656E74616C2049737375" +
+ "696E6720417574686F72697479301E170D3138303131303137323532335A170D" +
+ "3138303431313137323532335A302F312D302B060355040313244E6F6E2D4372" +
+ "69746963616C20454B552054696D657374616D7020417574686F726974793082" +
+ "0122300D06092A864886F70D01010105000382010F003082010A0282010100B1" +
+ "74BCC25C16B5B726821C2AD59F0EDB594832A15FE186A087FF40A8BC9396C55B" +
+ "C0DB2B3CE3EC5EF26A11AA87073348435417982D29C439FA3EC94A62B4BCC9EB" +
+ "CE0236B7E5306B3144E71373B05C24D3C1EE7A4D263BF11FC54D09E4B674F593" +
+ "389AAD503930EB7CEFECCA3A64FCCCC15E32E4B304BDAA36267E6BF2DA9584A7" +
+ "66E1862758D04E7FF9CC5C46CB074DFBCFAFDC355BF848337CD38331FE8556B9" +
+ "F350C6780C7260F73FBCA77FC454247B018E937D2002C9590E07804233EBC28E" +
+ "7BC712ACCF6A125EA60B86A87217B23A91866BEAAAE842D0D0D02E87F5F123AB" +
+ "811EDCAD7A6819E88B0F0D0932D0748EE02726D7138B1ACEB7A6D4090245DD02" +
+ "03010001A34E304C30090603551D1304023000300B0603551D0F0404030206C0" +
+ "30130603551D25040C300A06082B06010505070308301D0603551D0E04160414" +
+ "610479D21BFEAEC87835A7D03714613D566F25D3300D06092A864886F70D0101" +
+ "0B050003820201006511E16CB557E9936363DF92EA22776DD9AD1ED6ECBFE1A6" +
+ "B9B718BAF9828AD2B8CE5450F56E1371B54577DE1146FE82089A4331D063DA8B" +
+ "3CE786945ABBE4D11F4465068B1C3E4CF987C2C014BAD8BCECCC946EF3C5C56B" +
+ "0DDECFB11967A10949A6D111DC96C627D2F1D7969CA6BA7AB131367E89D950C5" +
+ "0B756E516CD4CC6BE679BB53684517236846DCE33BB49235CB1601A6657CC154" +
+ "8C2D57E5554B2755FD047922B0FAC86437758AB72C1A6EC458DB08D93CFB31D4" +
+ "8C723494978D7F32B940E5519852F9B6EA4F0363B59FCA7F8A6CCDE595896B91" +
+ "869C1D90FF2CA0CD29F9AA5FF452470B752052BFFBE2CBBE00C68F2DDCBE8C68" +
+ "53136118CFD1916D711BF90021C04FB5879BE0974228F79C71532FB2B5DDA1E1" +
+ "E89BD5EC9015F2207F7C55D72E976A87479AB62A46465E8D75466492F82CA574" +
+ "D788B27A5CA251C9BE3A4EB90F6E7F238CE8AAF46E598DDD70094E148DAE4DAA" +
+ "21275F79095ABCE8A47CC362386FDE498D102CCD42B2313AC88FC11E21DF8283" +
+ "631329E61F35E8DB12EA8D33DD02B8987C7FC38242412EC97CD52A7A913C6992" +
+ "D87E71A75F9654F7F9EDEB80B0BBEA25C5A22CCAF388D109DB0EA7C79247CE4D" +
+ "C89F390EB8C6CCC19FA9EB5DFC5BFA4457DB30B27CA73EE1C19934C8BED63E58" +
+ "F227222B86010D9521324BDDE04F47BF5190778C6B812ED78AC7DD8C82FBD0C4" +
+ "0DA1EE040184500D").HexToByteArray();
+
+ internal static readonly byte[] NonCriticalTsaEkuPfx = (
+ "30820AAE02010330820A6E06092A864886F70D010701A0820A5F04820A5B3082" +
+ "0A573082059006092A864886F70D010701A08205810482057D30820579308205" +
+ "75060B2A864886F70D010C0A0102A08204EE308204EA301C060A2A864886F70D" +
+ "010C0103300E040830D97AD5E5020804020207D0048204C857D388EF52DCE112" +
+ "B6D73E8611F6971BA662ECBA8F80435F83126D213190D6F77369E8D1213CF1C1" +
+ "7791AC985C7A0125D1D4728B841FE7BE3E9C44469CBE672377CD97821B49BBA2" +
+ "75789D64B648F4F243136E9448166EA366EBBB973041C437E1BA70B609761F03" +
+ "03A5ED03C041732D34F070555B006FACA2B8639A0B609D1A7F8A88ABD260CB69" +
+ "3365D9181A638A6ADF69385C96BC094E6EEA507160F18A22E0552183C586A45E" +
+ "C680CE10B56E1D3956F704C89A0981429C470DB378DE1CF21BD67E9EEB43B37F" +
+ "E00117CD3CDB02398FD0D7FD4B48EA38CBF6B19254E957AD2D8A0A4C3AE72355" +
+ "590407AC9FE2622C8AF04BF17E62CBB213F9D29999BF184532BC64E2ED1A5323" +
+ "1501741A1352F492AFE713503A950DF12E9BB505EBE9C80DF4DB6CC9E1EE0CF0" +
+ "02C9CB145E265F7D84A448B9C7462CE25EEBDC9AB3A6E1C996FC535FF7627163" +
+ "1CA7E36C1614A9113C96EDD951F2B3B7508DEC6A2BE6889436A741CD170B6201" +
+ "D546430CC38CE1E874D78A9D6E4D9665CE8261368FBA08C7456E5B01723D3465" +
+ "7AD715328341B4BAD14825D1DB1B0030819B61607E2F4FE76D0EF1616E2C1F96" +
+ "4395FFAAA4A9F7E833A1527B630D862DFF5C8DD6EE6557F55B429C9088020D10" +
+ "309070D8BD46B1512C0D6B68C8C00EBF215C5DC3DE0BD8B4A92E4C3115687194" +
+ "D7DEF524FEA4B02389388C7021BD85EDF13BE19086D08AC682EB8B37F1AC6445" +
+ "67CF6213363D889536CD8A4287A9DC16DD5497A8D06A489D6AB12E4943784EDB" +
+ "559FC02C7DC1E190A9FBCB8EF7D83AEDB31AE1BA8F356742E539E4A7B9D0A516" +
+ "90FCF505BFD5DA6AC8DD67439C2CE9E8D3DFB78A88581BDF0EBB89B810FA7894" +
+ "78D5A5BA44BF287BC8D98DF1B286F2B9109430524DFD5739405E46C755F9C943" +
+ "03C95FF6E89400D1E1D1E814D795FF0B77ECC84AABFF6A8D3C665770778CE9C9" +
+ "A9189DA1E257988AF6588A596F5534D91FA4505581DBB0F8588F97CC3177788D" +
+ "131A2F03972DA2753DCEE18965E032A5326CF50378D7D98233A913387315C71E" +
+ "3FB2D81A78B537BBBD4408C2E8DA4EFE975EFAA785BDEBA40C5CFF9E25CA07A0" +
+ "77DFD9744FE20F783A38A274CDB85A374D1E7723473106DEA578B14C766FEEE8" +
+ "6446C61AAFCED190892AE44C8BDC72D5178C3AB1BE9600CA15F5D3383A6219D0" +
+ "675F2DBA9AED44BF8702777EA6902344AA572535217EF44BEE37C6E507FEB4FA" +
+ "62EF557119608466CD1339C242AFB4F8E0E9EB403E41872B3C5A34B94EF2EBC7" +
+ "91111687C764E4E20A25EF07DAE9E402FB08B79EDB4F5B5C3ADAB14E3CA9004E" +
+ "FEDECD8DA9D4791BA96F6D6493B301698F2202DB9834B423ACFE71324716FDEF" +
+ "6D70FEBC98503E914593A1F511BCD0C39425DAA9981B6BEFA122F8812564D14F" +
+ "B6383F3CB8C2C41449E9B58B3D4EE27651C5B20CEBE786312878E641C20531B2" +
+ "909BE5727E4C4C01FDEFBC635292A663B53A8EAB29A1FA4CEFF11A02AD511AA7" +
+ "F2FD338A86E1876B568074F50B33835186C71C3854945AF082B4DBBD6865581A" +
+ "139B3973A3FD5E62AD88C51D636D616AB18EA808BE982C7C51B20FA239D07014" +
+ "CEE766F9CDF5D592B1D31881AA5939C670A7CCB48D234268D61031A27D99728A" +
+ "4701EF7A241C45A26799C45A8A0A02EA054215973B6F156520544DBE0C3A89DF" +
+ "7BBEEB7AB754495781A4A37F4CDD64B1A3A535826B00E1A710AD4D4A56C17662" +
+ "3174301306092A864886F70D0109153106040401000000305D06092B06010401" +
+ "8237110131501E4E004D006900630072006F0073006F0066007400200053006F" +
+ "0066007400770061007200650020004B00650079002000530074006F00720061" +
+ "00670065002000500072006F00760069006400650072308204BF06092A864886" +
+ "F70D010706A08204B0308204AC020100308204A506092A864886F70D01070130" +
+ "1C060A2A864886F70D010C0106300E0408DBF6A30F31A06E2B020207D0808204" +
+ "783C0D88298EEF3EDDB8C04416DD28F2DA6654714BD9092529FE1181153A60FC" +
+ "552B4D62B0C1F53C6F6337A7C774DBE4396690431E55A963AA509A2351104B91" +
+ "E74B9250AA58812954181B1ED602D9699105960C7B82E91362946292E65C99D5" +
+ "80DCD3B00FCC0FF4B25095AAF4B5E67886B817556D8B69B3016DE071E31F2B86" +
+ "3612A6050FB7D97C5454CE63B842B02FBA72D102DFAFEB01192CCF33BDDEAFB3" +
+ "950C53E1452B449950CA860BEF314B32AFABF6B9F2BB1CAFD064960C073239A3" +
+ "EEC38BA9B30BDF0A9DBA3FCA6F22F47DC8F593BB7102FE0D8039AE5B2317C9E0" +
+ "2DB059C99F06708809362C1676D14D7E5F3DB30E0090697366DDC9900A218E7F" +
+ "99851838A111B9C9C9DD9A696DD096DDAA23175164034407463AFA4664BD5E70" +
+ "3B6AFD659D6C7CD266ABE731F51F96A2D148B919B83888E4416759169C304A15" +
+ "57251FCAE553B5A177DBB5366B031B59149CCE263601A0231544CFD7107BDDFC" +
+ "4037AC0AD99F93D001C4CBC4DBCEDE235875C20789BBE8BEDFDE63D1959C25AA" +
+ "1E410AB081F03CF5562D814C54A9B66A27E74DC261D4E41513927BADA1E993D5" +
+ "20EA81D592B1D4ACEA2577929229B60A8B0AA7499037F3F7F24C1E8E980A06BB" +
+ "6B953090844FE068B611DC4C880A4B2FE21F82002C4305A9AE27C1B17607D59C" +
+ "89589F122721FFB6DC2D95EFB7D96625EE3C6C252E0E3FF25D4407549358F995" +
+ "D9911E9021303FB711B71D7D5F61D6BA845A456B9A832926A098E0EDCA081E53" +
+ "9FABBE54C09DF90D37D349FAA3A9259432491307C216E8D3C160E1D5E994161F" +
+ "BB29C9BBD789CCEB23591B983D35CE3001D7D4A313A9D66356D5B3BC0BB061D6" +
+ "49DFC15CAF2B8B70D3FCF40B1D412E60FFAD5FB4A0F2944F019CD2CD26108345" +
+ "20771F437BF27A586AB0866BF1F5920C488648D463A2C430E217CFB080E91930" +
+ "05589A9670FA9C75050E45100A553E9A21FE300DE621B12CCA03FE189CE65367" +
+ "B1CC452426AD21C67925894905CD594E85C354F85748994C34AAE7E281DC3C71" +
+ "81BEE53119708F6C2D29B2CA987F5620650BE2EA087FAF976BB58349E8B67F67" +
+ "FAAE11559752C31EB34A72FD4BB23B363255530F92E8C0C82FB7ACD6FF4DD7CB" +
+ "AFB831E624522FBDD47A8191957BAF0E9998AB61C5F839B6DFF3A568132A1A21" +
+ "643A576D3562EF72294B13E6662ECF9CBFEC602C7AAC5E01D43759917D95BF3D" +
+ "D572A45B2CAA118965764470C163FACA61D06693273D869214816431963087DE" +
+ "B10FE0316352440E87189532D950E0A9AE5ABE9926907E52F1E4F135B467F4E2" +
+ "8BA57B9F371FC934409526E261926E484B465ED10CFDB25A2F3E6838F41C37F7" +
+ "DF6A88E7063EBAEB6C426B0A4C7842C58CA49581F14337FDF43FC22DAF79900D" +
+ "306E34ED9DACBD6072DF4F34588F28F0F4AE13B431D9F47ACCD6EFB1C4EBBDED" +
+ "D507512B820FB02713948D45F3C595330B271308F0E6DAB862BB917EE9E2B1F4" +
+ "17CE21A26CC17358C11E2BCC514EB241D0767B4971E9B89F94731843B508C20A" +
+ "54345F58E99D430065326FFEA3E1FAC40E24BFB17A51A884CA022944A27436DF" +
+ "8F2C4E296A728496C38076FD3F14B007FEFF015EB42329F7453037301F300706" +
+ "052B0E03021A0414A0E907FF695A237FAB54BBB94CBCE689EE0B4552041426E2" +
+ "132250203B3235FD5023D999B747478D8873").HexToByteArray();
+
+ internal static readonly byte[] TlsClientServerEkuCert = (
+ "3082043130820219A003020102020401020304300D06092A864886F70D01010B" +
+ "05003029312730250603550403131E4578706572696D656E74616C2049737375" +
+ "696E6720417574686F72697479301E170D3138303131303137333331375A170D" +
+ "3138303431313137333331375A302F312D302B060355040313244E6F6E2D4372" +
+ "69746963616C20454B552054696D657374616D7020417574686F726974793082" +
+ "0122300D06092A864886F70D01010105000382010F003082010A0282010100B3" +
+ "CBCBEA8EFAAAEDF982CD046188D2F57FE9FE4F4FEA94ADFB7DE47AE731636624" +
+ "3C4E5F8C2821BF0B01A32048E8A275FD9B3073E0DA2E8870FD9671BFA600A47C" +
+ "8588AAE88150448E6B4C594C5EA288119BE9A3EA369F66EED7C499738B8EAF84" +
+ "5E6B36BCEDF7887D061BC86F12D40982199C1C41CCF5440AEF592A482931B541" +
+ "1B0E0400FB24AF838BA89A3E1393C24B80B4C67AB923DE68B0B8A2218DA93C2C" +
+ "A4908E3B906BF3431839CA6D3FC2A4FC33C4CB58BDEF8982A39DD186D0BB88E8" +
+ "E68819C4A7DA4D29F48F1C1F00098DF41C140FA649204564A3AAB9D0E7486252" +
+ "77F40B9739ED07D385BF9C0F78528CC5DED08A84B6D392874B2A4EB98B3A5102" +
+ "03010001A35B305930090603551D1304023000300B0603551D0F0404030206C0" +
+ "30200603551D250101FF0416301406082B0601050507030106082B0601050507" +
+ "0302301D0603551D0E04160414743B8DC143DEC364FA69992CB3306A9EDEACEA" +
+ "1C300D06092A864886F70D01010B050003820201003A48278ED517B381CA420A" +
+ "E3C12C31C22F49D1DC35EA60B018BCB88C6C3E0FF1E7A301E525B5592649B496" +
+ "7BA62D89AC748DB026CBD73C9333AAE89C5F5D76FC77E970F214F1508CBFBD9B" +
+ "09CD50EF93D61559004027E80BCE6809F196633C22A13CA2CD7596ADE5B4A23E" +
+ "BB4E03367892433357636316F0D235D3DACFEB99631CB437DEB04E4A074B1CBA" +
+ "6C6D722210B058285A3E124EC8148E31B3DE37DCBAECF560076FC0E50965D482" +
+ "DCBF529127CBE2440BA746DC71765516D480E68805C7668A0B538BC489DA2FE5" +
+ "E158BB6786A626BF0AAB74AF042347785B54323CC019CA84347BFF57C025791D" +
+ "69C558A605D46C50297DE1E9576972053A3DDFE5EC8FD2DE0D48B80252C39EE5" +
+ "4410AD46D8128A453758DA442CC2879290A50232B13920D9C6800D8773C2FD82" +
+ "D11755C336CD6416FFE26F97599A29E5D18227949DD4385C74D29547D6C70ECB" +
+ "CBE006AE2D18BCB8708C50E7C46D442A8DEDECEEDCDEAEC47042957B1D18D410" +
+ "96350438DCD8223B17E5FDC3C9C0D9BD47D191E6142A601930817E30F8E0509F" +
+ "D5F5FE269683494F08C55B9ECE6E3D503C81A81F40CC959B858E52BA086D95B5" +
+ "8DC13492C128B64F862E7800384C98A1303EA570D328C003E2B944A804B9794F" +
+ "A5C6040881E61510E90C20F21DEA0A73E0DA5C1A2D178A48D76CC8FAA2ADA660" +
+ "2A98B50AC197B40348A012E83A98EFF2B8D64900DE").HexToByteArray();
+
+ internal static readonly byte[] TlsClientServerEkuPfx = (
+ "30820AB602010330820A7606092A864886F70D010701A0820A6704820A633082" +
+ "0A5F3082059006092A864886F70D010701A08205810482057D30820579308205" +
+ "75060B2A864886F70D010C0A0102A08204EE308204EA301C060A2A864886F70D" +
+ "010C0103300E04084BEC68D6BA25EEEE020207D0048204C8E534D459438245AC" +
+ "EAC40458DAE1FDC42FB28605913F53F859CA1B7D62E385E48352F956A1B4D904" +
+ "B796CE577F18A5E334990367542F7EB0806EDE06892812F914D62BC029E6637D" +
+ "60BB10F125350DFC7F7702D68984F79C9192ECC07178330141B2CD8D88974F30" +
+ "DD2CDF6F82F668AA5BF9F3201F1A8ED58B2546A2683260751F8254C3AC574ED2" +
+ "8FBEF421A4C8B1C2CFB4691875314C06148A801036E39827BF3AA57F9FC32DB0" +
+ "00C0BB9CCEB0E828651AD82E903B710DE378B00533994AEA596AD4FFD5B075E3" +
+ "4BA54099F8FEA4AFCC469D071C48A0EF8BB58B46D3666A251188209AB7FE80F2" +
+ "238EC6977280497ED7833283D3C49DD9546190404E1018C1179DDABBAF18D9B9" +
+ "FE18D71FA4A87976F95A533FAE01E96057CDB05FF19DD14673AABB7FB5C3B01A" +
+ "44F7D8265B320E846244E7C3EE65D01F4B468084F3890D92A065D745F41275D2" +
+ "9650B00BF3CB7B4DB64D14A78591147F9FEA71DE4469DE58D1E90A40B5ABB151" +
+ "B4F24BCA90E1966C9588D96627FE1F69ED8BC7A52F03BEED75CA8E90EBB811B1" +
+ "37BABB34129C5E7AE44E1B6FE3A3DE8EC923F05E4A471BA0D27B134E5880CC4B" +
+ "20CE7404CE9EB2C114C7018E811786A7FFF5FE6A2C7FAC4C4B2FA0CA6223E9D4" +
+ "0A9D6567FB659857A83703D9E995CA2E1BC96FD6EAC678204661CD866530E61B" +
+ "40533A011A250B6632760FD942A8A5741410C1BF0212D66085BB623F5C53A186" +
+ "6699CE7CAD843C9325D54D260D254B3273717DEBE43F4F7FEDFC984546434CEC" +
+ "46D70E3B888A85A11252DC12E7D50A32CAD5D4544C161F81BBCEF0D0DE893F25" +
+ "C762FDCCDE1DF91262C815C925BFC6BA133E5CD42D32E7D2A6FB0BF22AE8482C" +
+ "CEAE15070F1692D5BF3C2E2CCC02D77DF879C4D4F188B80870A234714B92197C" +
+ "7A27F39A7E5366D7A2E99BCBF8BC5576DD627754EC4AEE2DE118EEDF7686D109" +
+ "0B3A59E97051624D56224423BC9B4A2D7A85549596D4F981E29BF4C7F6CA8F38" +
+ "2E4138BF515BB72CF4CF5D44F49274843BCCED64A9CA5A514E29C2DFE75CA4B2" +
+ "FABACCA238DBA202AC6A996BDE4F79C9A568450C849BF12063C0CCEFF4B81057" +
+ "A386697D217F4AD02ADCA127271CC5A3E5E9E3F6722D4173B83B39CEF5DF0BF8" +
+ "F9630D575F3A99BF83BDA8A5A1A8CA5AF876F14BA5360DC6CBA5D1EC2F46C3E2" +
+ "F14F87A03052C3EE4994C6B661248401F40EA0843F011E5186EF09B8917B4218" +
+ "DF0352289252463E2DE1FFED603F330D80D6349C36FA9CF9B721069BDD833491" +
+ "52FB1BA9F994507BB22CA076AE781FCDC5B1A487C9EE8BC2C83476260F61D866" +
+ "0981A7BA1F5471F56C067BC6A3C1C6F4F76C72497DDD8AB961DB8FF673B00EB8" +
+ "7C498624B2C46A184B6D4F248AC9307DF046DCFC70811402AF06468E7E07D6FC" +
+ "353830F4F06B5902FD823A4A94099AAD9CEEC531CC544F74BCE62777F188CAC1" +
+ "B819F6F0F449372E1B3ADC45514C8598A18427D2957511938CAC5439768A97C4" +
+ "8D05A62660628DC2C16D1CFE73920C00B6DBEB4D66D1572F60817FBCCC3DDEB4" +
+ "C5DCBB69799E4D3BC155FCF564B6AEBF25C7AC3A0F0CE7F4F2761738A7485236" +
+ "8B4D950EA6672BA4615A9A040FA5166FF520948CA1D3649D9AD2317B8380FE90" +
+ "4644F2C06F6173C8FB52A572FC50D69C273DBB63EBACA717441C2530CDEDAC0B" +
+ "3796FAA4F9BAEC808A01F70E5B48E42B2AA49AFB65054EEFCB0F10072A38DA5E" +
+ "3174301306092A864886F70D0109153106040401000000305D06092B06010401" +
+ "8237110131501E4E004D006900630072006F0073006F0066007400200053006F" +
+ "0066007400770061007200650020004B00650079002000530074006F00720061" +
+ "00670065002000500072006F00760069006400650072308204C706092A864886" +
+ "F70D010706A08204B8308204B4020100308204AD06092A864886F70D01070130" +
+ "1C060A2A864886F70D010C0106300E0408FDE1F090274C2210020207D0808204" +
+ "8071C27010C2CFFD78D49D28DBB5AEF4269926F1055E9DF0471FFD7077366628" +
+ "DB87AC150E12BD5C636BE9A9CCAB194C87F32749D9544873A0C2360453A5293D" +
+ "E03D5DCC1E3F12FDD89CF5BC37099A08DD9700CC0B6D1E351D5451386513E774" +
+ "C3FAAB375F7A6731C8923C7979F8B283D33C09CF1DFAEFA9EC014845CD779C24" +
+ "A1B085C2F9A8B3AF35197ECAD885B926463D785E9C192326FC6B956695970920" +
+ "8B571E383D1083AD446DFEFADA128E247BC038DC74C43E9B5832922814DCEAED" +
+ "F97E989BDB105642466FE2B2E2FEC3A19F556766DBBD0BCF9C5627876B1D2A19" +
+ "42B3EC2DFA957DE74E669AC767811C6CE6133ED50F97D29FA002FAA0A72980A5" +
+ "CC66C5FB86B1F657BE940489087D473AE6A5475A952B24A585254FC27AD50D80" +
+ "0C3A77B13AC17401453645C03FFC66984FEA1ECC385852EFD7EB008971E31652" +
+ "43A3F672FFB8590F756B4481EB5FFBBF5935C8062741D7AB38A4BE28D141FF16" +
+ "6773ADE4EC3C021DDB5FCC43E2D03CDA4AD6BAC0EE63CA816089B8C971A3244C" +
+ "6186BBEE09C09A31BC29DC8EAC665E7D9C6CC148C3FAD9028FF2E0A9F727DE1B" +
+ "08AD8561D918677FB026A8EBD9BCFB0E106C058C6EFFD53FE13996B9C40F12B3" +
+ "90DDD3CC63107CCA59F1CF861692629F4AFD7D3257218D9F888DF2E7A67BD601" +
+ "2EEF48B82D09F01D1D1EDCEBEE878A771399D58EEA1D50C8F8ADCA3432696F2D" +
+ "49D7253F064F4EC28C335853CD4EF9E72094517EFE61EB3E0A7F50451C1F9CA6" +
+ "B95FCF62F36E6D79B16D99119C9E0D4AFFB36972E68A1FA2E2A099596176EA5D" +
+ "C09756632BB4FC82136BB554FB32A2997DD982BDBD058F9990403FF786342C91" +
+ "F117A98F0076CAB6AAF35F8FD5A5E795F9F3368049849D582E9950B42924BBC6" +
+ "5EA3A0FB8FE87FD0B74C1621B52B673E92FD6475DCCB138425740AD1C006ECE5" +
+ "3633C9AA2B02404384A31F7FE7DC9F41F2CDB4584283B48E6C5D1EE659316F2C" +
+ "FAB3E6D5AEE5F0F986D223E7077C417BD890035E373BAC6B90E62451B14BB701" +
+ "30C263872865F8975165452074A53FD036FC3930FF2F781D2805999DA7955BB6" +
+ "4D4A98D0E67E4C18F73126177D047E89B24A409DEEA7B7B8CAABD0DD39DF3818" +
+ "59E973360EFEE67D8FF9E24275E9F47D5A67E812DD68F8325603F3040180D85E" +
+ "2EF61BD821CA666550E55F8A8C172D93315C6D7E14567BD9DE84A0C298A6A586" +
+ "A63611495C66DD7D9AF83E20CEF31F3A3D3CC25553F2045FBB547C97C1AE43E1" +
+ "F0147C116C82AB442562534E0898023CFB459DB66B7320DECA41E26477D76D5A" +
+ "562BAC06023B778271311E3BC8E2D5ABD90515650A994CDAA99D38F6169D480A" +
+ "122AD01731819FEEB8FE3111C1CF06FB9B5882EB74232B0CDA7DCAD2988FA9F1" +
+ "8F4DCDC7DDC45983128E07F6687AD6C1FB219B3295AA74592B3D8B05C7D9851D" +
+ "140A71CAD10D18EBCCDEB9C9243B39772E29D923D9D5014EA4CED9FE5C7859BD" +
+ "6AAE8902726D5ECBB6C0D028728F316034F991CEA8F435FFDF35B26583C1CC44" +
+ "959BAE4514EB478327BA76E6F9B759E176FDD8BFEDA8BDE6E7BF5E2F9C76CAB8" +
+ "055DBE8A531FA77690A620BC5463431899B7577E3AEF0D382F31955AB5FCC951" +
+ "973037301F300706052B0E03021A0414F2009473DB4B8B63778E28E68613246F" +
+ "D53995810414A911A22D051F1BF45E7FF974C4285F6B4D880B08").HexToByteArray();
}
}
}
diff --git a/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/ContentEncryptionAlgorithmTests.cs b/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/ContentEncryptionAlgorithmTests.cs
index 4e82b880d1..24a66e27c2 100644
--- a/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/ContentEncryptionAlgorithmTests.cs
+++ b/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/ContentEncryptionAlgorithmTests.cs
@@ -2,15 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.IO;
-using System.Linq;
-using System.Globalization;
-using System.Collections.Generic;
-using System.Security.Cryptography;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Security.Cryptography.Pkcs;
-using System.Security.Cryptography.Xml;
using System.Security.Cryptography.X509Certificates;
using Xunit;
@@ -21,6 +12,24 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
{
public static partial class ContentEncryptionAlgorithmTests
{
+ public static bool SupportsRc4 => PlatformDetection.IsWindows;
+ public static bool DoesNotSupportRc4 => !SupportsRc4;
+
+ [Fact]
+ public static void EncryptionAlgorithmRc2_InvalidKeyLength()
+ {
+ // For desktop compat, variable key length ciphers throw an error if the key length provided
+ // is not a multiple of 8.
+ AlgorithmIdentifier algorithm = new AlgorithmIdentifier(new Oid(Oids.Rc2), 3);
+ ContentInfo contentInfo = new ContentInfo(new byte[] { 1, 2, 3 });
+ EnvelopedCms ecms = new EnvelopedCms(contentInfo, algorithm);
+ using (X509Certificate2 cert = Certificates.RSAKeyTransfer1.GetCertificate())
+ {
+ CmsRecipient cmsRecipient = new CmsRecipient(cert);
+ Assert.ThrowsAny<CryptographicException>(() => ecms.Encrypt(cmsRecipient));
+ }
+ }
+
[Fact]
public static void DecodeAlgorithmRc2_128_RoundTrip()
{
@@ -60,6 +69,92 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
}
[Fact]
+ public static void DecodeAlgorithmRc2_40_FixedValue()
+ {
+ ContentInfo expectedContentInfo = new ContentInfo(new byte[] { 1, 2, 3, 4 });
+ byte[] encodedMessage =
+ ("3082011806092A864886F70D010703A0820109308201050201003181CC3081C90201003032301E311C301A0"
+ + "60355040313135253414B65795472616E73666572436170693102105D2FFFF863BABC9B4D3C80AB178A4CCA"
+ + "300D06092A864886F70D010101050004818004E46A48651034B01134B0D4F665C9E85F6C45B58458ECDBAFE"
+ + "B6B55CBFA9AEBEFA52BCBEF3C8811B5118970562623FC35D4B733B55CBC50DA4F49822E1D198834897D3540"
+ + "7B329FECF49277159F2FEAB31173004776B03746381E0DA660B6D656A861E54E79186F36F450105DEB2714D"
+ + "02DB5500921EBE4F1A7D3DFB07E4EE9303106092A864886F70D010701301A06082A864886F70D0302300E02"
+ + "0200A00408D621253C94AF659B800802930ACE6A997122").HexToByteArray();
+ EnvelopedCms ecms = new EnvelopedCms();
+ ecms.Decode(encodedMessage);
+
+ AlgorithmIdentifier algorithm = ecms.ContentEncryptionAlgorithm;
+ Assert.NotNull(algorithm.Oid);
+ Assert.Equal(Oids.Rc2, algorithm.Oid.Value);
+ Assert.Equal(40, algorithm.KeyLength);
+ }
+
+ [Fact]
+ [OuterLoop(/* Leaks key on disk if interrupted */)]
+ public static void DecodeAlgorithmRc2_40_RoundTrip()
+ {
+ ContentInfo contentInfo = new ContentInfo(new byte[] { 1, 2, 3, 4 });
+ EnvelopedCms ecms = new EnvelopedCms(contentInfo, new AlgorithmIdentifier(new Oid(Oids.Rc2), 40));
+
+ using (X509Certificate2 cert = Certificates.RSAKeyTransferCapi1.GetCertificate())
+ {
+ ecms.Encrypt(new CmsRecipient(SubjectIdentifierType.IssuerAndSerialNumber, cert));
+ }
+
+ byte[] encodedMessage = ecms.Encode();
+
+ ecms = new EnvelopedCms();
+ ecms.Decode(encodedMessage);
+
+ AlgorithmIdentifier algorithm = ecms.ContentEncryptionAlgorithm;
+ Assert.NotNull(algorithm.Oid);
+ Assert.Equal(Oids.Rc2, algorithm.Oid.Value);
+ Assert.Equal(40, algorithm.KeyLength);
+ }
+
+ [ConditionalFact(nameof(SupportsRc4))]
+ [OuterLoop(/* Leaks key on disk if interrupted */)]
+ public static void DecodeAlgorithmRc4_40_RoundTrip()
+ {
+ ContentInfo contentInfo = new ContentInfo(new byte[] { 1, 2, 3, 4 });
+ EnvelopedCms ecms = new EnvelopedCms(contentInfo, new AlgorithmIdentifier(new Oid(Oids.Rc4), 40));
+
+ using (X509Certificate2 cert = Certificates.RSAKeyTransferCapi1.GetCertificate())
+ {
+ ecms.Encrypt(new CmsRecipient(SubjectIdentifierType.IssuerAndSerialNumber, cert));
+ }
+
+ byte[] encodedMessage = ecms.Encode();
+
+ ecms = new EnvelopedCms();
+ ecms.Decode(encodedMessage);
+
+ AlgorithmIdentifier algorithm = ecms.ContentEncryptionAlgorithm;
+ Assert.NotNull(algorithm.Oid);
+ Assert.Equal(Oids.Rc4, algorithm.Oid.Value);
+ Assert.Equal(40, algorithm.KeyLength);
+ }
+
+
+ [ConditionalFact(nameof(DoesNotSupportRc4))]
+ [OuterLoop(/* Leaks key on disk if interrupted */)]
+ public static void DecodeAlgorithmRc4_40_PlatformNotSupported()
+ {
+ ContentInfo contentInfo = new ContentInfo(new byte[] { 1, 2, 3, 4 });
+ EnvelopedCms ecms = new EnvelopedCms(contentInfo, new AlgorithmIdentifier(new Oid(Oids.Rc4), 40));
+
+ using (X509Certificate2 cert = Certificates.RSAKeyTransferCapi1.GetCertificate())
+ {
+ CmsRecipient recipient = new CmsRecipient(SubjectIdentifierType.IssuerAndSerialNumber, cert);
+
+ CryptographicException e =
+ Assert.Throws<CryptographicException>(() => ecms.Encrypt(recipient));
+
+ Assert.Contains(Oids.Rc4, e.Message);
+ }
+ }
+
+ [Fact]
public static void DecodeAlgorithmDes_RoundTrip()
{
AlgorithmIdentifier algorithm = new AlgorithmIdentifier(new Oid(Oids.Des));
@@ -134,7 +229,7 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
Assert.Equal(192, algorithm.KeyLength);
}
- [Fact]
+ [ConditionalFact(nameof(SupportsRc4))]
public static void DecodeAlgorithmRc4_RoundTrip()
{
AlgorithmIdentifier algorithm = new AlgorithmIdentifier(new Oid(Oids.Rc4));
@@ -173,6 +268,46 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
}
[Fact]
+ public static void DecodeAlgorithmRc4_40_FixedValue()
+ {
+ byte[] encodedMessage =
+ ("3082011006092A864886F70D010703A08201013081FE0201003181CC3081C90201003032301E311C301A060"
+ + "355040313135253414B65795472616E73666572436170693102105D2FFFF863BABC9B4D3C80AB178A4CCA30"
+ + "0D06092A864886F70D01010105000481809D242C1517B82A58335E0337B0B2CE97B2789AF31A6B31311417B"
+ + "A069D0D76FD08AE5B4F58C290116667FFD00319AA7AFED4EEAD9D5031C0D17A48E6CB39A5EB62C8BD7F4C2C"
+ + "BE8E581EF8B7FF7BA9376923A367B9B7E031F630E4CA6ADCB31209B04B03E64076FB0465E7E437B13D4AEA2"
+ + "70CA89EB58C1A598F0AC88DCB4024302A06092A864886F70D010701301706082A864886F70D0304040B4B5A"
+ + "8F64D714F933642D4A8004C68A936F").HexToByteArray();
+
+ EnvelopedCms ecms = new EnvelopedCms();
+ ecms.Decode(encodedMessage);
+ AlgorithmIdentifier algorithm = ecms.ContentEncryptionAlgorithm;
+ Assert.NotNull(algorithm.Oid);
+ Assert.Equal(Oids.Rc4, algorithm.Oid.Value);
+ Assert.Equal(40, algorithm.KeyLength);
+ }
+
+ [Fact]
+ public static void EncryptionAlgorithmAes128_IgnoresKeyLength()
+ {
+ // For desktop compat, static key length ciphers ignore the key lengths supplied
+ AlgorithmIdentifier algorithm = new AlgorithmIdentifier(new Oid(Oids.Aes128), 3);
+ ContentInfo contentInfo = new ContentInfo(new byte[] { 1, 2, 3 });
+ EnvelopedCms ecms = new EnvelopedCms(contentInfo, algorithm);
+ using (X509Certificate2 cert = Certificates.RSAKeyTransfer1.GetCertificate())
+ {
+ CmsRecipient cmsRecipient = new CmsRecipient(cert);
+ ecms.Encrypt(cmsRecipient);
+ }
+ byte[] encodedMessage = ecms.Encode();
+
+ ecms.Decode(encodedMessage);
+
+ Assert.Equal(Oids.Aes128, ecms.ContentEncryptionAlgorithm.Oid.Value);
+ Assert.Equal(0, ecms.ContentEncryptionAlgorithm.KeyLength);
+ }
+
+ [Fact]
public static void DecodeAlgorithmAes128_RoundTrip()
{
AlgorithmIdentifier algorithm = new AlgorithmIdentifier(new Oid(Oids.Aes128));
diff --git a/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/DecryptTests.KeyPersistence.cs b/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/DecryptTests.KeyPersistence.cs
index f34cee98be..748b8140ae 100644
--- a/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/DecryptTests.KeyPersistence.cs
+++ b/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/DecryptTests.KeyPersistence.cs
@@ -80,6 +80,11 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
[OuterLoop("Leaks key on disk if interrupted")]
public static void Decrypt_Capi_Perphemeral(string algOid)
{
+ if (algOid == Oids.Rc4 && !ContentEncryptionAlgorithmTests.SupportsRc4)
+ {
+ return;
+ }
+
byte[] content = { 1, 1, 2, 3, 5, 8, 13, 21 };
ContentInfo contentInfo = new ContentInfo(content);
TestSimpleDecrypt_RoundTrip(
diff --git a/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/DecryptTests.cs b/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/DecryptTests.cs
index fb31e70a15..9d1a6b5000 100644
--- a/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/DecryptTests.cs
+++ b/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/DecryptTests.cs
@@ -2,14 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.IO;
-using System.Linq;
-using System.Globalization;
-using System.Collections.Generic;
-using System.Security.Cryptography;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography.Xml;
using System.Security.Cryptography.X509Certificates;
using Xunit;
@@ -77,6 +69,80 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
TestSimpleDecrypt_RoundTrip(Certificates.RSASha512KeyTransfer1, contentInfo, Oids.Aes256, SubjectIdentifierType.IssuerAndSerialNumber);
}
+ [ConditionalFact(nameof(SupportsCngCertificates))]
+ [OuterLoop("Leaks key on disk if interrupted")]
+ public static void Decrypt_512_FixedValue()
+ {
+ byte[] content = { 5, 77, 32, 33, 2, 34 };
+ byte[] message = (
+ "3082012506092A864886F70D010703A0820116308201120201003181CE3081CB" +
+ "02010030343020311E301C060355040313155253415368613531324B65795472" +
+ "616E736665723102102F5D9D58A5F41B844650AA233E68F105300D06092A8648" +
+ "86F70D01010105000481803163AA33F8F5E033DC03AE98CCEE158199589FC420" +
+ "19200DCC1D202309CCCAF79CC0278B9502B5709F1311E522DA325338136D3F1E" +
+ "A271FAEA978CC656A3CB94B1C6A8D7AFC836C3193DB693E8B8767472C2C23125" +
+ "BA11E7D0623E4C8B848826BBF99EB411CB88B4731740D1AD834F0E4076BAD0D4" +
+ "BA695CFE8CDB2DE3E77196303C06092A864886F70D010701301D060960864801" +
+ "650304012A0410280AC7A629BFC9FD6FB24F8A42F094B48010B78CDFECFF32A8" +
+ "E86D448989382A93E7"
+ ).HexToByteArray();
+
+ VerifySimpleDecrypt(message, Certificates.RSASha512KeyTransfer1, new ContentInfo(content));
+ }
+
+ [ConditionalFact(nameof(SupportsCngCertificates))]
+ [OuterLoop("Leaks key on disk if interrupted")]
+ public static void Decrypt_512_NoData_FixedValue()
+ {
+ // This is the Decrypt_512_FixedData test re-encoded to remove the
+ // encryptedContentInfo.encryptedContent optional value.
+ byte[] content = Array.Empty<byte>();
+ byte[] message = (
+ "3082011306092A864886F70D010703A0820104308201000201003181CE3081CB" +
+ "02010030343020311E301C060355040313155253415368613531324B65795472" +
+ "616E736665723102102F5D9D58A5F41B844650AA233E68F105300D06092A8648" +
+ "86F70D01010105000481803163AA33F8F5E033DC03AE98CCEE158199589FC420" +
+ "19200DCC1D202309CCCAF79CC0278B9502B5709F1311E522DA325338136D3F1E" +
+ "A271FAEA978CC656A3CB94B1C6A8D7AFC836C3193DB693E8B8767472C2C23125" +
+ "BA11E7D0623E4C8B848826BBF99EB411CB88B4731740D1AD834F0E4076BAD0D4" +
+ "BA695CFE8CDB2DE3E77196302A06092A864886F70D010701301D060960864801" +
+ "650304012A0410280AC7A629BFC9FD6FB24F8A42F094B4"
+ ).HexToByteArray();
+
+ if (PlatformDetection.IsFullFramework)
+ {
+ // On NetFx when Array.Empty should be returned an array of 6 zeros is
+ // returned instead.
+ content = new byte[6];
+ }
+
+ VerifySimpleDecrypt(message, Certificates.RSASha512KeyTransfer1, new ContentInfo(content));
+ }
+
+ [ConditionalFact(nameof(SupportsCngCertificates))]
+ [OuterLoop("Leaks key on disk if interrupted")]
+ public static void Decrypt_512_CekDoesNotDecrypt_FixedValue()
+ {
+ // This is the Decrypt_512_NoData_FixedValue test except that the last
+ // byte of the recipient encrypted key has been changed from 0x96 to 0x95
+ // (the sequence 7195 identifies the changed byte)
+ byte[] content = Array.Empty<byte>();
+ byte[] message = (
+ "3082011306092A864886F70D010703A0820104308201000201003181CE3081CB" +
+ "02010030343020311E301C060355040313155253415368613531324B65795472" +
+ "616E736665723102102F5D9D58A5F41B844650AA233E68F105300D06092A8648" +
+ "86F70D01010105000481803163AA33F8F5E033DC03AE98CCEE158199589FC420" +
+ "19200DCC1D202309CCCAF79CC0278B9502B5709F1311E522DA325338136D3F1E" +
+ "A271FAEA978CC656A3CB94B1C6A8D7AFC836C3193DB693E8B8767472C2C23125" +
+ "BA11E7D0623E4C8B848826BBF99EB411CB88B4731740D1AD834F0E4076BAD0D4" +
+ "BA695CFE8CDB2DE3E77195302A06092A864886F70D010701301D060960864801" +
+ "650304012A0410280AC7A629BFC9FD6FB24F8A42F094B4"
+ ).HexToByteArray();
+
+ Assert.ThrowsAny<CryptographicException>(
+ () => VerifySimpleDecrypt(message, Certificates.RSASha512KeyTransfer1, new ContentInfo(content)));
+ }
+
[Fact]
[OuterLoop(/* Leaks key on disk if interrupted */)]
public static void Decrypt_SignedWithinEnveloped()
@@ -175,6 +241,229 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
Assert.Equal<byte>(content, contentInfo.Content);
}
+ [Fact]
+ [OuterLoop(/* Leaks key on disk if interrupted */)]
+ public static void TestDecryptSimpleAes128_IssuerAndSerial()
+ {
+ // Message encrypted on framework for a recipient using the certificate returned by Certificates.RSAKeyTransfer1.GetCertificate()
+ // and of type IssuerAndSerialNumber. The symmetric algorithm is Aes128
+ byte[] encryptedMessage =
+ ("3082011F06092A864886F70D010703A08201103082010C0201003181C83081C5020100302E301A311830160"
+ + "603550403130F5253414B65795472616E7366657231021031D935FB63E8CFAB48A0BF7B397B67C0300D0609"
+ + "2A864886F70D0101073000048180862175CD3B2932235A67C6A025F75CDA1A43B53E785370895BA9AC8D0DD"
+ + "318EB36DFAE275B16ABD497FEBBFCF2D4B3F38C75B91DC40941A2CC1F7F47E701EEA2D5A770C485565F8726"
+ + "DC0D59DDE17AA6DB0F9384C919FC8BC6CB561A980A9AE6095486FDF9F52249FB466B3676E4AEFE4035C15DC"
+ + "EE769F25E4660D4BE664E7F303C06092A864886F70D010701301D060960864801650304010204100A068EE9"
+ + "03E085EA5A03D1D8B4B73DD88010740E5DE9B798AA062B449F104D0F5D35").HexToByteArray();
+
+ byte[] expectedContent = { 1, 2, 3, 4 };
+ ContentInfo expectedContentInfo = new ContentInfo(expectedContent);
+ CertLoader certLoader = Certificates.RSAKeyTransfer1;
+
+ VerifySimpleDecrypt(encryptedMessage, certLoader, expectedContentInfo);
+ }
+
+ [Fact]
+ [OuterLoop(/* Leaks key on disk if interrupted */)]
+ public static void TestDecryptSimpleAes192_IssuerAndSerial()
+ {
+ // Message encrypted on framework for a recipient using the certificate returned by Certificates.RSAKeyTransfer1.GetCertificate()
+ // and of type IssuerAndSerialNumber. The symmetric algorithm used is Aes192
+ byte[] encryptedMessage =
+ ("3082011F06092A864886F70D010703A08201103082010C0201003181C83081C5020100302E301A311830160"
+ + "603550403130F5253414B65795472616E7366657231021031D935FB63E8CFAB48A0BF7B397B67C0300D0609"
+ + "2A864886F70D010107300004818029B82454B4C301F277D7872A14695A41ED24FD37AC4C9942F9EE96774E0"
+ + "C6ACC18E756993A38AB215E5702CD34F244E52402DA432E8B79DF748405135E8A6D8CB78D88D9E4C142565C"
+ + "06F9FAFB32F5A9A4074E10FCCB0758A708CA758C12A17A4961969FCB3B2A6E6C9EB49F5E688D107E1B1DF3D"
+ + "531BC684B944FCE6BD4550C303C06092A864886F70D010701301D06096086480165030401160410FD7CBBF5"
+ + "6101854387E584C1B6EF3B08801034BD11C68228CB683E0A43AB5D27A8A4").HexToByteArray();
+
+ byte[] expectedContent = { 1, 2, 3, 4 };
+ ContentInfo expectedContentInfo = new ContentInfo(expectedContent);
+ CertLoader certLoader = Certificates.RSAKeyTransfer1;
+
+ VerifySimpleDecrypt(encryptedMessage, certLoader, expectedContentInfo);
+ }
+
+ [Fact]
+ [OuterLoop(/* Leaks key on disk if interrupted */)]
+ public static void TestDecryptSimpleAes256_IssuerAndSerial()
+ {
+ // Message encrypted on framework for a recipient using the certificate returned by Certificates.RSAKeyTransfer1.GetCertificate()
+ // and of type IssuerAndSerialNumber. The symmetric algorithm used is Aes256
+ byte[] encryptedMessage =
+ ("3082011F06092A864886F70D010703A08201103082010C0201003181C83081C5020100302E301A311830160"
+ + "603550403130F5253414B65795472616E7366657231021031D935FB63E8CFAB48A0BF7B397B67C0300D0609"
+ + "2A864886F70D01010730000481800215BF7505BCD5D083F8EFDA01A4F91D61DE3967779B2F5E4360593D4CB"
+ + "96474E36198531A5E20E417B04C5C7E3263C3301DF8FA888FFBECC796500D382858379059C986285AFD605C"
+ + "B5DE125487CCA658DF261C836720E2E14440DA60E2F12D6D5E3992A0DB59973929DF6FC23D8E891F97CA956"
+ + "2A7AD160B502FA3C10477AA303C06092A864886F70D010701301D060960864801650304012A04101287FE80"
+ + "93F3C517AE86AFB95E599D7E80101823D88F47191857BE0743C4C730E39E").HexToByteArray();
+
+ byte[] expectedContent = { 1, 2, 3, 4 };
+ ContentInfo expectedContentInfo = new ContentInfo(expectedContent);
+ CertLoader certLoader = Certificates.RSAKeyTransfer1;
+
+ VerifySimpleDecrypt(encryptedMessage, certLoader, expectedContentInfo);
+ }
+
+ [Fact]
+ [OuterLoop(/* Leaks key on disk if interrupted */)]
+ public static void TestDecryptSimpleTripleDes_IssuerAndSerial()
+ {
+ // Message encrypted on framework for a recipient using the certificate returned by Certificates.RSAKeyTransfer1.GetCertificate()
+ // and of type IssuerAndSerialNumber. The symmetric algorithm used is 3DES-CBC
+ byte[] encryptedMessage =
+ ("3082010C06092A864886F70D010703A081FE3081FB0201003181C83081C5020100302E301A3118301606035"
+ + "50403130F5253414B65795472616E7366657231021031D935FB63E8CFAB48A0BF7B397B67C0300D06092A86"
+ + "4886F70D0101010500048180062F6F16637C8F35B73924AD85BA47D99DBB4800CB8F0C4094F6896050B7C1F"
+ + "11CE79BEE55A638EAAE70F2C32C01FC24B8D09D9D574CB7373788C8BC3A4748124154338C74B644A2A11750"
+ + "9E97D1B3535FAE70E4E7C8F2F866232CBFC6448E89CF9D72B948EDCF9C9FC9C153BCC7104680282A4BBBC1E"
+ + "E367F094F627EE45FCD302B06092A864886F70D010701301406082A864886F70D030704081E3F12D42E4041"
+ + "58800877A4A100165DD0F2").HexToByteArray();
+
+ byte[] expectedContent = { 1, 2, 3, 4 };
+ ContentInfo expectedContentInfo = new ContentInfo(expectedContent);
+ CertLoader certLoader = Certificates.RSAKeyTransfer1;
+
+ VerifySimpleDecrypt(encryptedMessage, certLoader, expectedContentInfo);
+ }
+
+ [Fact]
+ [OuterLoop(/* Leaks key on disk if interrupted */)]
+ public static void TestDecryptSimpleAes256_Ski()
+ {
+ // Message encrypted on framework for a recipient using the certificate returned by Certificates.RSAKeyTransfer1.GetCertificate()
+ // and of type SubjectKeyIdentifier. The symmetric algorithm used is Aes256
+ byte[] encryptedMessage =
+ ("3082010306092A864886F70D010703A081F53081F20201023181AE3081AB0201028014F2008AA9FA3742E83"
+ + "70CB1674CE1D1582921DCC3300D06092A864886F70D010101050004818055F258073615B95426A7021E1B30"
+ + "9CFE8DD135B58D29F174B9FE19AE80CFC84621BCE3DBD63A5422AF30A6FAA3E2DFC05CB1AB5AB4FBA6C84EB"
+ + "1C2E17D5BE5C4959DBE8F96BF1A9701F55B697843032EEC7AFEC58A36815168F017DCFD70C74AD05C48B5E4"
+ + "D9DDEE409FDC9DC3326B6C5BA9F433A9E031FF9B09473176637F50303C06092A864886F70D010701301D060"
+ + "960864801650304012A0410314DA87435ED110DFE4F52FA70CEF7B080104DDA6C617338DEBDD10913A9141B"
+ + "EE52").HexToByteArray();
+
+ byte[] expectedContent = { 1, 2, 3, 4 };
+ ContentInfo expectedContentInfo = new ContentInfo(expectedContent);
+ CertLoader certLoader = Certificates.RSAKeyTransfer1;
+
+ VerifySimpleDecrypt(encryptedMessage, certLoader, expectedContentInfo);
+ }
+
+ [Fact]
+ [OuterLoop(/* Leaks key on disk if interrupted */)]
+ public static void TestDecryptSimpleAes256_RsaTransferCapi()
+ {
+ // Message encrypted on framework for a recipient using the certificate returned by Certificates.RSAKeyTransferCapi1.GetCertificate()
+ // and of type IssuerAndSerialNumber. The symmetric algorithm used is Aes256
+ byte[] encryptedMessage =
+ ("3082012306092A864886F70D010703A0820114308201100201003181CC3081C90201003032301E311C301A0"
+ + "60355040313135253414B65795472616E73666572436170693102105D2FFFF863BABC9B4D3C80AB178A4CCA"
+ + "300D06092A864886F70D01010730000481804F3F4A6707B329AB9A7343C62F20D5C1EAF4E74ECBB2DC66D1C"
+ + "642FC4AA3E40FC4C13547C6C9F73D525EE2FE4147B2043B8FEBF8604C0E4091C657B48DFD83A322F0879580"
+ + "FA002C9B27AD1FCF9B8AF24EDDA927BB6728D11530B3F96EBFC859ED6B9F7B009F992171FACB587A7D05E8B"
+ + "467B3A1DACC08B2F3341413A7E96576303C06092A864886F70D010701301D060960864801650304012A0410"
+ + "6F911E14D9D991DAB93C0B7738D1EC208010044264D201501735F73052FFCA4B2A95").HexToByteArray();
+
+ byte[] expectedContent = { 1, 2, 3, 4 };
+ ContentInfo expectedContentInfo = new ContentInfo(expectedContent);
+ CertLoader certLoader = Certificates.RSAKeyTransferCapi1;
+
+ VerifySimpleDecrypt(encryptedMessage, certLoader, expectedContentInfo);
+ }
+
+ [Fact]
+ [OuterLoop(/* Leaks key on disk if interrupted */)]
+ public static void TestDecryptSimpleAes256_RsaSha256()
+ {
+ // Message encrypted on framework for a recipient using the certificate returned by
+ // Certificates.RSASha256KeyTransfer1.GetCertificate() and of type IssuerAndSerialNumber. The symmetric algorithm used is Aes256
+ byte[] encryptedMessage =
+ ("3082012506092A864886F70D010703A0820116308201120201003181CE3081CB02010030343020311E301C0"
+ + "60355040313155253415368613235364B65795472616E7366657231021072C6C7734916468C4D608253DA01"
+ + "7676300D06092A864886F70D01010730000481805C32FA32EBDCFFC3595166EEDACFC9E9D60842105B581E1"
+ + "8B85DE1409F4C999995637153480438530955EE4481A3B27B866FF4E106A525CDFFC6941BDD01EFECCC6CCC"
+ + "82A3D7F743F7543AB20A61A7831FE4DFB24A1652B072B3758FE4B2588D3B94A29575B6422DC5EF52E432565"
+ + "36CA25A11BB92817D61FEAFBDDDEC6EE331303C06092A864886F70D010701301D060960864801650304012A"
+ + "041021D59FDB89C13A3EC3766EF32FB333D080105AE8DEB71DF50DD85F66FEA63C8113F4").HexToByteArray();
+
+ byte[] expectedContent = { 1, 2, 3, 4 };
+ ContentInfo expectedContentInfo = new ContentInfo(expectedContent);
+ CertLoader certLoader = Certificates.RSASha256KeyTransfer1;
+
+ VerifySimpleDecrypt(encryptedMessage, certLoader, expectedContentInfo);
+ }
+
+ [Fact]
+ [OuterLoop(/* Leaks key on disk if interrupted */)]
+ public static void TestDecryptSimpleAes256_RsaSha384()
+ {
+ // Message encrypted on framework for a recipient using the certificate returned by Certificates.RSASha384KeyTransfer1.GetCertificate()
+ // and of type IssuerAndSerialNumber. The symmetric algorithm used is Aes256
+ byte[] encryptedMessage =
+ ("3082012506092A864886F70D010703A0820116308201120201003181CE3081CB02010030343020311E301C0"
+ + "60355040313155253415368613338344B65795472616E736665723102103C724FB7A0159A9345CAAC9E3DF5"
+ + "F136300D06092A864886F70D010107300004818011C1B85914331C005EA89E30D00364821B29BC0C459A22D"
+ + "917494A1092CDBDA2022792E46C5E88BAD0EE3FD4927B856722311F9B17934FB29CAB8FE595C2AB2B20096B"
+ + "9E2FC6F9D7B92125F571CBFC945C892EE4764D9B63369350FD2DAEFE455B367F48E100CB461F112808E792A"
+ + "8AA49B66C79E511508A877530BBAA896696303C06092A864886F70D010701301D060960864801650304012A"
+ + "0410D653E25E06BFF2EEB0BED4A90D00FE2680106B7EF143912ABA5C24F5E2C151E59D7D").HexToByteArray();
+
+ byte[] expectedContent = { 1, 2, 3, 4 };
+ ContentInfo expectedContentInfo = new ContentInfo(expectedContent);
+ CertLoader certLoader = Certificates.RSASha384KeyTransfer1;
+
+ VerifySimpleDecrypt(encryptedMessage, certLoader, expectedContentInfo);
+ }
+
+ [Fact]
+ [OuterLoop(/* Leaks key on disk if interrupted */)]
+ public static void TestDecryptSimpleAes256_RsaSha512()
+ {
+ // Message encrypted on framework for a recipient using the certificate returned by Certificates.RSASha512KeyTransfer1.GetCertificate()
+ // and of type IssuerAndSerialNumber. The symmetric algorithm used is Aes256
+ byte[] encryptedMessage =
+ ("3082012506092A864886F70D010703A0820116308201120201003181CE3081CB02010030343020311E301C0"
+ + "60355040313155253415368613531324B65795472616E736665723102102F5D9D58A5F41B844650AA233E68"
+ + "F105300D06092A864886F70D01010730000481802156D42FF5ED2F0338302E7298EF79BA1D04E20E68B079D"
+ + "B3239120E1FC03FEDA8B544F59142AACAFBC5E58205E8A0D124AAD17B5DCAA39BFC6BA634E820DE623BFDB6"
+ + "582BC48AF1B3DEF6849A57D2033586AF01079D67C9AB3AA9F6B51754BCC479A19581D4045EBE23145370219"
+ + "98ECB6F5E1BCF8D6BED6A75FE957A40077D303C06092A864886F70D010701301D060960864801650304012A"
+ + "04100B696608E489E7C35914D0A3DB9EB27F80103D362181B54721FB2CB7CE461CB31030").HexToByteArray();
+
+ byte[] expectedContent = { 1, 2, 3, 4 };
+ ContentInfo expectedContentInfo = new ContentInfo(expectedContent);
+ CertLoader certLoader = Certificates.RSASha512KeyTransfer1;
+
+ VerifySimpleDecrypt(encryptedMessage, certLoader, expectedContentInfo);
+ }
+
+ [Fact]
+ [OuterLoop(/* Leaks key on disk if interrupted */)]
+ public static void TestDecryptSimple_ExplicitSki()
+ {
+ // Message encrypted on framework for a recipient using the certificate returned by Certificates.RSAKeyTransfer_ExplicitSki.GetCertificate()
+ // and of type SubjectKeyIdentifier. The symmetric algorithm used is Aes256
+ byte[] encryptedMessage =
+ ("3082018806092A864886F70D010703A082017930820175020102318201303082012C020102801401952851C"
+ + "55DB594B0C6167F5863C5B6B67AEFE6300D06092A864886F70D010101050004820100269EAF029262C87125"
+ + "314DD3FB02302FA212EB3CC06F73DF1474382BBA2A92845F39FF5A7F5020482849C36B4BC6BC82F7AF0E2E3"
+ + "9143548CC32B93B72EF0659C6895F77E6B5839962678532392185C9431658B34D1ABD31F64F4C4A9B348A77"
+ + "56783D60244519ADDD33560405E9377A91617127C2EECF2BAE53AB930FC13AFD25723FB60DB763286EDF6F1"
+ + "187D8124B6A569AA2BD19294A7D551A0D90F8436274690231520A2254C19EA9BF877FC99566059A29CDF503"
+ + "6BEA1D517916BA2F20AC9F1D8F164B6E8ACDD52BA8B2650EBBCC2ED9103561E11AF422D10DF7405404195FA"
+ + "EF79A1FDC680F3A3DC395E3E9C0B10394DF35AE134E6CB719E35152F8E5303C06092A864886F70D01070130"
+ + "1D060960864801650304012A041085072D8771A2A2BB403E3236A7C60C2A80105C71A04E73C57FE75C1DEDD"
+ + "94B57FD01").HexToByteArray();
+
+ byte[] expectedContent = { 1, 2, 3, 4 };
+ ContentInfo expectedContentInfo = new ContentInfo(expectedContent);
+ CertLoader certLoader = Certificates.RSAKeyTransfer_ExplicitSki;
+
+ VerifySimpleDecrypt(encryptedMessage, certLoader, expectedContentInfo);
+ }
+
private static void TestSimpleDecrypt_RoundTrip(CertLoader certLoader, ContentInfo contentInfo, string algorithmOidValue, SubjectIdentifierType type)
{
// Deep-copy the contentInfo since the real ContentInfo doesn't do this. This defends against a bad implementation changing
diff --git a/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/EdgeCasesTests.cs b/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/EdgeCasesTests.cs
index b7de03720f..38b03e90e2 100644
--- a/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/EdgeCasesTests.cs
+++ b/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/EdgeCasesTests.cs
@@ -2,14 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.IO;
-using System.Linq;
-using System.Globalization;
-using System.Collections.Generic;
-using System.Security.Cryptography;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography.Xml;
using System.Security.Cryptography.X509Certificates;
using Xunit;
@@ -21,6 +13,8 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
{
public static partial class EdgeCasesTests
{
+ public static bool SupportsRc4 { get; } = ContentEncryptionAlgorithmTests.SupportsRc4;
+
public static bool SupportsCngCertificates { get; } = (!PlatformDetection.IsFullFramework || PlatformDetection.IsNetfx462OrNewer);
[ConditionalFact(nameof(SupportsCngCertificates))]
@@ -93,6 +87,34 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
}
[Fact]
+ public static void ZeroLengthContextUntagged_FixedValue()
+ {
+ // This test ensures that we can handle when the enveloped message has no content inside. This test differs
+ // from "ZeroLengthContent_FixedValue" in that it doesn't have a context specific [0] in the EncryptedContentInfo
+ // section of the DER encoding of the message.
+ // EncryptedContentInfo ::= SEQUENCE {
+ // contentType ContentType,
+ // contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+ // encryptedContent[0] IMPLICIT EncryptedContent OPTIONAL }
+ // The input was created with ASN1 editor and verified with .NET framework. It's an enveloped message, version 0,
+ // with one Key Transport recipient and holds data encrypted with 3DES.
+ byte[] content =
+ ("3082010206092A864886F70D010703A081F43081F10201003181C83081C5020100302E301A311830160603550403130F"
+ + "5253414B65795472616E7366657231021031D935FB63E8CFAB48A0BF7B397B67C0300D06092A864886F70D0101010500"
+ + "04818009C16B674495C2C3D4763189C3274CF7A9142FBEEC8902ABDC9CE29910D541DF910E029A31443DC9A9F3B05F02"
+ + "DA1C38478C400261C734D6789C4197C20143C4312CEAA99ECB1849718326D4FC3B7FBB2D1D23281E31584A63E99F2C17"
+ + "132BCD8EDDB632967125CD0A4BAA1EFA8CE4C855F7C093339211BDF990CEF5CCE6CD74302106092A864886F70D010701"
+ + "301406082A864886F70D03070408779B3DE045826B18").HexToByteArray();
+
+ EnvelopedCms ecms = new EnvelopedCms();
+ ecms.Decode(content);
+
+ int expected = PlatformDetection.IsFullFramework ? 6 : 0; // Desktop bug gives 6
+ Assert.Equal(expected, ecms.ContentInfo.Content.Length);
+ Assert.Equal(Oids.Pkcs7Data, ecms.ContentInfo.ContentType.Value);
+ }
+
+ [Fact]
[OuterLoop(/* Leaks key on disk if interrupted */)]
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Desktop rejects zero length content: corefx#18724")]
public static void ZeroLengthContent_RoundTrip()
@@ -122,7 +144,7 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
ValidateZeroLengthContent(encodedMessage);
}
- [Fact]
+ [ConditionalFact(nameof(SupportsRc4))]
[OuterLoop(/* Leaks key on disk if interrupted */)]
[SkipOnTargetFramework(TargetFrameworkMonikers.Uap, "RC4 isn't available via CNG, and CNG is the only library available to UWP")]
public static void Rc4AndCngWrappersDontMixTest()
diff --git a/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/GeneralTests.cs b/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/GeneralTests.cs
index 13c91dc05a..2ecd2d5f98 100644
--- a/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/GeneralTests.cs
+++ b/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/GeneralTests.cs
@@ -2,25 +2,21 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.IO;
using System.Linq;
-using System.Globalization;
-using System.Collections.Generic;
-using System.Security.Cryptography;
using System.Runtime.InteropServices;
-using System.Text;
-using System.Security.Cryptography.Pkcs;
+using System.Security.Cryptography.Pkcs.Tests;
using System.Security.Cryptography.Xml;
using System.Security.Cryptography.X509Certificates;
using Xunit;
using Test.Cryptography;
-using System.Security.Cryptography.Pkcs.Tests;
namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
{
public static partial class GeneralTests
{
+ public static bool SupportsDiffieHellman { get; } = KeyAgreeRecipientInfoTests.SupportsDiffieHellman;
+
[Fact]
public static void DecodeVersion0_RoundTrip()
{
@@ -58,7 +54,7 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
Assert.Equal(0, version);
}
- [Fact]
+ [ConditionalFact(nameof(SupportsDiffieHellman))]
public static void DecodeRecipients3_RoundTrip()
{
ContentInfo contentInfo = new ContentInfo(new byte[] { 1, 2, 3 });
@@ -158,6 +154,98 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
Assert.Equal(Oids.Pkcs7Signed, contentType.Value);
}
+ [Fact]
+ public static void TestContent()
+ {
+ // Tests that the content is what it is expected to be, even if it's still encyrpted. This prevents from ambiguous definitions of content.
+
+ // The encoded message was built in ASN.1 editor and tested in framework. It contains an enveloped message version 0 with one recipient of
+ // key transport type. The symmetric algorythm is 3DES and the contained type is data.
+ byte[] encodedMessage =
+ ("3082010c06092a864886f70d010703a081fe3081fb0201003181c83081c5020100302e301a311830160603550403130f5253"
+ + "414b65795472616e7366657231021031d935fb63e8cfab48a0bf7b397b67c0300d06092a864886f70d010101050004818013"
+ + "dc0eb2984a445d04a1f6246b8fe41f1d24507548d449d454d5bb5e0638d75ed101bf78c0155a5d208eb746755fbccbc86923"
+ + "8443760a9ae94770d6373e0197be23a6a891f0c522ca96b3e8008bf23547474b7e24e7f32e8134df3862d84f4dea2470548e"
+ + "c774dd74f149a56cdd966e141122900d00ad9d10ea1848541294a1302b06092a864886f70d010701301406082a864886f70d"
+ + "030704089c8119f6cf6b174c8008bcea3a10d0737eb9").HexToByteArray();
+
+ EnvelopedCms cms = new EnvelopedCms();
+
+ cms.Decode(encodedMessage);
+
+ string expectedHex = "BCEA3A10D0737EB9";
+
+ if (PlatformDetection.IsFullFramework)
+ {
+ expectedHex = "BCEA3A10D0737EB9000000000000";
+ }
+
+ Assert.Equal(expectedHex, cms.ContentInfo.Content.ByteArrayToHex());
+ }
+
+ [Fact]
+ [OuterLoop(/* Leaks key on disk if interrupted */)]
+ public static void MultipleRecipientIdentifiers_RoundTrip()
+ {
+ ContentInfo contentInfo = new ContentInfo(new byte[] { 1, 2, 3 });
+ EnvelopedCms ecms = new EnvelopedCms(contentInfo);
+ CmsRecipientCollection recipients = new CmsRecipientCollection();
+ using (X509Certificate2 issuerSerialCert = Certificates.RSAKeyTransfer1.GetCertificate())
+ using (X509Certificate2 explicitSkiCert = Certificates.RSAKeyTransfer_ExplicitSki.GetCertificate())
+ {
+ // CmsRecipients have different identifiers to test multiple identifier encryption.
+ recipients.Add(new CmsRecipient(SubjectIdentifierType.IssuerAndSerialNumber, issuerSerialCert));
+ recipients.Add(new CmsRecipient(SubjectIdentifierType.SubjectKeyIdentifier, explicitSkiCert));
+ ecms.Encrypt(recipients);
+ }
+
+ byte[] encodedMessage = ecms.Encode();
+
+ ecms = new EnvelopedCms();
+ ecms.Decode(encodedMessage);
+
+ // Try decoding it, doesn't really matter with which cert you want to do it as it's not what this
+ // test aims for.
+
+ using (X509Certificate2 privateCert = Certificates.RSAKeyTransfer_ExplicitSki.TryGetCertificateWithPrivateKey())
+ {
+ if (privateCert == null)
+ return; // CertLoader can't load the private certificate.
+
+ ecms.Decrypt(new X509Certificate2Collection(privateCert));
+ }
+ Assert.Equal(contentInfo.ContentType.Value, ecms.ContentInfo.ContentType.Value);
+ Assert.Equal<byte>(contentInfo.Content, ecms.ContentInfo.Content);
+ }
+
+ [Fact]
+ [OuterLoop(/* Leaks key on disk if interrupted */)]
+ public static void RoundTrip_ExplicitSki()
+ {
+ ContentInfo contentInfo = new ContentInfo(new byte[] { 1, 2, 3 });
+ EnvelopedCms ecms = new EnvelopedCms(contentInfo);
+ using (X509Certificate2 explicitSkiCert = Certificates.RSAKeyTransfer_ExplicitSki.GetCertificate())
+ {
+ CmsRecipient recipient = new CmsRecipient(SubjectIdentifierType.SubjectKeyIdentifier, explicitSkiCert);
+ ecms.Encrypt(recipient);
+ }
+
+ byte[] encodedMessage = ecms.Encode();
+
+ ecms = new EnvelopedCms();
+ ecms.Decode(encodedMessage);
+
+ using (X509Certificate2 privateCert = Certificates.RSAKeyTransfer_ExplicitSki.TryGetCertificateWithPrivateKey())
+ {
+ if (privateCert == null)
+ return; // CertLoader can't load the private certificate.
+
+ ecms.Decrypt(new X509Certificate2Collection(privateCert));
+ }
+ Assert.Equal(contentInfo.ContentType.Value, ecms.ContentInfo.ContentType.Value);
+ Assert.Equal<byte>(contentInfo.Content, ecms.ContentInfo.Content);
+ }
+
private static X509Certificate2[] s_certs =
{
Certificates.RSAKeyTransfer1.GetCertificate(),
diff --git a/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/KeyAgreeRecipientInfoTests.cs b/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/KeyAgreeRecipientInfoTests.cs
index dc878c9cf4..5209ec00a5 100644
--- a/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/KeyAgreeRecipientInfoTests.cs
+++ b/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/KeyAgreeRecipientInfoTests.cs
@@ -2,26 +2,37 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.IO;
-using System.Linq;
-using System.Globalization;
-using System.Collections.Generic;
-using System.Security.Cryptography;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Security.Cryptography.Pkcs;
+using System.Security.Cryptography.Pkcs.Tests;
using System.Security.Cryptography.Xml;
using System.Security.Cryptography.X509Certificates;
using Xunit;
using Test.Cryptography;
-using System.Security.Cryptography.Pkcs.Tests;
namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
{
public static partial class KeyAgreeRecipientInfoTests
{
- [Fact]
+ public static bool SupportsDiffieHellman => PlatformDetection.IsWindows;
+ public static bool DoesNotSupportDiffieHellman => !SupportsDiffieHellman;
+
+ [ConditionalFact(nameof(DoesNotSupportDiffieHellman))]
+ public static void TestKeyAgreement_PlatformNotSupported()
+ {
+ ContentInfo contentInfo = new ContentInfo(new byte[] { 1, 2, 3 });
+ EnvelopedCms ecms = new EnvelopedCms(contentInfo);
+ using (X509Certificate2 cert = Certificates.DHKeyAgree1.GetCertificate())
+ {
+ CmsRecipient cmsRecipient = new CmsRecipient(cert);
+
+ CryptographicException e =
+ Assert.Throws<CryptographicException>(() => ecms.Encrypt(cmsRecipient));
+
+ Assert.Contains(cert.GetKeyAlgorithm(), e.Message);
+ }
+ }
+
+ [ConditionalFact(nameof(SupportsDiffieHellman))]
public static void TestKeyAgreeVersion_RoundTrip()
{
KeyAgreeRecipientInfo recipient = EncodeKeyAgreel();
@@ -35,7 +46,7 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
Assert.Equal(3, recipient.Version);
}
- [Fact]
+ [ConditionalFact(nameof(SupportsDiffieHellman))]
public static void TestKeyAgreeType_RoundTrip()
{
KeyAgreeRecipientInfo recipient = EncodeKeyAgreel();
@@ -49,7 +60,7 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
Assert.Equal(RecipientInfoType.KeyAgreement, recipient.Type);
}
- [Fact]
+ [ConditionalFact(nameof(SupportsDiffieHellman))]
public static void TestKeyAgreesRecipientIdType_RoundTrip()
{
KeyAgreeRecipientInfo recipient = EncodeKeyAgreel();
@@ -65,7 +76,7 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
Assert.Equal(SubjectIdentifierType.IssuerAndSerialNumber, subjectIdentifier.Type);
}
- [Fact]
+ [ConditionalFact(nameof(SupportsDiffieHellman))]
public static void TestKeyAgreeRecipientIdValue_RoundTrip()
{
KeyAgreeRecipientInfo recipient = EncodeKeyAgreel();
@@ -89,7 +100,7 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
Assert.Equal("0AE59B0CB8119F8942EDA74163413A02", xis.SerialNumber);
}
- [Fact]
+ [ConditionalFact(nameof(SupportsDiffieHellman))]
public static void TestKeyAgreeRecipientIdType_Ski_RoundTrip()
{
KeyAgreeRecipientInfo recipient = FixedValueKeyAgree1(SubjectIdentifierType.SubjectKeyIdentifier);
@@ -105,7 +116,7 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
Assert.Equal(SubjectIdentifierType.SubjectKeyIdentifier, subjectIdentifier.Type);
}
- [Fact]
+ [ConditionalFact(nameof(SupportsDiffieHellman))]
public static void TestKeyAgreeRecipientIdValue_Ski_RoundTrip()
{
KeyAgreeRecipientInfo recipient = FixedValueKeyAgree1(SubjectIdentifierType.SubjectKeyIdentifier);
@@ -127,7 +138,7 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
Assert.Equal("10DA1370316788112EB8594C864C2420AE7FBA42", ski);
}
- [Fact]
+ [ConditionalFact(nameof(SupportsDiffieHellman))]
public static void TestKeyAgreeKeyEncryptionAlgorithm_RoundTrip()
{
KeyAgreeRecipientInfo recipient = EncodeKeyAgreel();
@@ -145,7 +156,7 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
Assert.Equal(0, a.KeyLength);
}
- [Fact]
+ [ConditionalFact(nameof(SupportsDiffieHellman))]
public static void TestKeyAgreeEncryptedKey_RoundTrip()
{
KeyAgreeRecipientInfo recipient = EncodeKeyAgreel();
@@ -163,7 +174,7 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
Assert.Equal<byte>(expectedEncryptedKey, encryptedKey);
}
- [Fact]
+ [ConditionalFact(nameof(SupportsDiffieHellman))]
public static void TestKeyAgreeOriginatorIdentifierOrKey_RoundTrip()
{
KeyAgreeRecipientInfo recipient = EncodeKeyAgreel();
@@ -199,7 +210,7 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
Assert.Equal(expectedKey, key);
}
- [Fact]
+ [ConditionalFact(nameof(SupportsDiffieHellman))]
public static void TestKeyAgreeDate_RoundTrip()
{
KeyAgreeRecipientInfo recipient = EncodeKeyAgreel();
@@ -215,7 +226,7 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
Assert.Throws<InvalidOperationException>(() => ignore = recipient.Date);
}
- [Fact]
+ [ConditionalFact(nameof(SupportsDiffieHellman))]
public static void TestKeyAgreeDate_RoundTrip_Ski()
{
KeyAgreeRecipientInfo recipient = EncodeKeyAgreel(SubjectIdentifierType.SubjectKeyIdentifier);
@@ -236,7 +247,7 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
}
- [Fact]
+ [ConditionalFact(nameof(SupportsDiffieHellman))]
public static void TestKeyAgreeOtherKeyAttribute_RoundTrip()
{
KeyAgreeRecipientInfo recipient = EncodeKeyAgreel();
@@ -280,6 +291,66 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
Assert.Equal<byte>(expectedAsnData, asnData.RawData);
}
+ [Fact]
+ public static void TestMultipleKeyAgree_ShortNotation()
+ {
+ // KeyAgreement recipients are defined in RFC 2630 as
+ //
+ // KeyAgreeRecipientInfo::= SEQUENCE {
+ // version CMSVersion, --always set to 3
+ // originator[0] EXPLICIT OriginatorIdentifierOrKey,
+ // ukm[1] EXPLICIT UserKeyingMaterial OPTIONAL,
+ // keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+ // recipientEncryptedKeys RecipientEncryptedKeys }
+ //
+ // RecipientEncryptedKeys::= SEQUENCE OF RecipientEncryptedKey
+ //
+ // RecipientEncryptedKey::= SEQUENCE {
+ // rid KeyAgreeRecipientIdentifier,
+ // encryptedKey EncryptedKey }
+ //
+ // When RecipientEncryptedKeys has more than one sequence in it, then different KeyAgreement recipients are created, where each
+ // recipient hold the information from one RecipientEncryptedKey. This message has one KeyAgreeRecipientInfo object that has two
+ // RecipientEncryptedKeys so it needs to have two recipients in the end.
+
+ byte[] encodedMessage =
+ ("3082019206092A864886F70D010703A08201833082017F0201023182014BA1820147020103A08196A18193300906072A"
+ + "8648CE3E02010381850002818100AC89002E19D3A7DC35DAFBF083413483EF14691FC00A465B957496CA860BA4918182"
+ + "1CAFB50EB25330952BB11A71A44B44691CF9779999F1115497CD1CE238B452CA95622AF968E39F06E165D2EBE1991493"
+ + "70334D925AA47273751AC63A0EF80CDCF6331ED3324CD689BFFC90E61E9CC921C88EF5FB92B863053C4C1FABFE15301E"
+ + "060B2A864886F70D0109100305300F060B2A864886F70D010910030605003081883042A016041410DA1370316788112E"
+ + "B8594C864C2420AE7FBA420428DFBDC19AD44063478A0C125641BE274113441AD5891C78F925097F06A3DF57F3F1E6D1"
+ + "160F8D3C223042A016041411DA1370316788112EB8594C864C2420AE7FBA420428DFBDC19AD44063478A0C125641BE27"
+ + "4113441AD5891C78F925097F06A3DF57F3F1E6D1160F8D3C22302B06092A864886F70D010701301406082A864886F70D"
+ + "030704088AADC286F258F6D78008FC304F518A653F83").HexToByteArray();
+
+ EnvelopedCms ecms = new EnvelopedCms();
+ ecms.Decode(encodedMessage);
+
+ RecipientInfoCollection recipients = ecms.RecipientInfos;
+ Assert.Equal(2, recipients.Count);
+ RecipientInfo recipient0 = recipients[0];
+ RecipientInfo recipient1 = recipients[1];
+
+ Assert.IsType<KeyAgreeRecipientInfo>(recipient0);
+ Assert.IsType<KeyAgreeRecipientInfo>(recipient1);
+
+ KeyAgreeRecipientInfo recipient0Cast = recipient0 as KeyAgreeRecipientInfo;
+ KeyAgreeRecipientInfo recipient1Cast = recipient1 as KeyAgreeRecipientInfo;
+
+ Assert.Equal(3, recipient0.Version);
+ Assert.Equal(3, recipient1.Version);
+
+ Assert.Equal(SubjectIdentifierOrKeyType.PublicKeyInfo, recipient0Cast.OriginatorIdentifierOrKey.Type);
+ Assert.Equal(SubjectIdentifierOrKeyType.PublicKeyInfo, recipient1Cast.OriginatorIdentifierOrKey.Type);
+
+ Assert.Equal(SubjectIdentifierType.SubjectKeyIdentifier, recipient0Cast.RecipientIdentifier.Type);
+ Assert.Equal(SubjectIdentifierType.SubjectKeyIdentifier, recipient1Cast.RecipientIdentifier.Type);
+
+ Assert.Equal("10DA1370316788112EB8594C864C2420AE7FBA42", recipient0Cast.RecipientIdentifier.Value);
+ Assert.Equal("11DA1370316788112EB8594C864C2420AE7FBA42", recipient1Cast.RecipientIdentifier.Value);
+ }
+
private static KeyAgreeRecipientInfo EncodeKeyAgreel(SubjectIdentifierType type = SubjectIdentifierType.IssuerAndSerialNumber)
{
ContentInfo contentInfo = new ContentInfo(new byte[] { 1, 2, 3 });
@@ -328,8 +399,6 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
return (KeyAgreeRecipientInfo)recipientInfo;
}
-
-
private static byte[] s_KeyAgreeEncodedMessage =
("3082019b06092a864886f70d010703a082018c3082018802010231820154a1820150020103a08195a18192300906072a8648"
+ "ce3e0201038184000281806f96ef8c53a6919cc976e88b8f426696e7b7970abc6bd4abbdcf4cf34f89ceb6e8ef675000fad2"
diff --git a/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/KeyTransRecipientInfoTests.cs b/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/KeyTransRecipientInfoTests.cs
index 6dba4cc2bc..2c0bb68ce0 100644
--- a/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/KeyTransRecipientInfoTests.cs
+++ b/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/KeyTransRecipientInfoTests.cs
@@ -117,6 +117,35 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
}
[Fact]
+ [OuterLoop(/* Leaks key on disk if interrupted */)]
+ public static void TestKeyTransRecipientIdValue_ExplicitSki_RoundTrip()
+ {
+ ContentInfo contentInfo = new ContentInfo(new byte[] { 1, 2, 3 });
+ EnvelopedCms ecms = new EnvelopedCms(contentInfo);
+ using (X509Certificate2 cert = Certificates.RSAKeyTransfer_ExplicitSki.GetCertificate())
+ {
+ CmsRecipient cmsRecipient = new CmsRecipient(SubjectIdentifierType.SubjectKeyIdentifier, cert);
+ ecms.Encrypt(cmsRecipient);
+ }
+ byte[] encodedMessage = ecms.Encode();
+
+ EnvelopedCms ecms2 = new EnvelopedCms();
+ ecms2.Decode(encodedMessage);
+
+ RecipientInfoCollection recipients = ecms2.RecipientInfos;
+ Assert.Equal(1, recipients.Count);
+ RecipientInfo recipientInfo = recipients[0];
+ Assert.IsType<KeyTransRecipientInfo>(recipientInfo);
+ KeyTransRecipientInfo recipient = (KeyTransRecipientInfo)recipientInfo;
+
+ SubjectIdentifier subjectIdentifier = recipient.RecipientIdentifier;
+ object value = subjectIdentifier.Value;
+ Assert.IsType<string>(value);
+ string ski = (string)value;
+ Assert.Equal("01952851C55DB594B0C6167F5863C5B6B67AEFE6", ski);
+ }
+
+ [Fact]
public static void TestKeyTransRecipientIdValue_Ski_FixedValue()
{
KeyTransRecipientInfo recipient = FixedValueKeyTrans1(SubjectIdentifierType.SubjectKeyIdentifier);
@@ -183,7 +212,7 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
RecipientInfoCollection recipients = ecms2.RecipientInfos;
Assert.Equal(1, recipients.Count);
RecipientInfo recipientInfo = recipients[0];
- Assert.True(recipientInfo is KeyTransRecipientInfo);
+ Assert.IsType<KeyTransRecipientInfo>(recipientInfo);
return (KeyTransRecipientInfo)recipientInfo;
}
@@ -210,7 +239,7 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
RecipientInfoCollection recipients = ecms.RecipientInfos;
Assert.Equal(1, recipients.Count);
RecipientInfo recipientInfo = recipients[0];
- Assert.True(recipientInfo is KeyTransRecipientInfo);
+ Assert.IsType<KeyTransRecipientInfo>(recipientInfo);
return (KeyTransRecipientInfo)recipientInfo;
}
diff --git a/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/StateTests.cs b/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/StateTests.cs
index 19a0ba344b..fc4b143b0b 100644
--- a/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/StateTests.cs
+++ b/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/StateTests.cs
@@ -180,6 +180,24 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
Assert.Equal<byte>(expectedContentInfo.Content, actualContentInfo.Content);
}
+ [Fact]
+ [OuterLoop(/* Leaks key on disk if interrupted */)]
+ public static void PostEncrypt_Certs()
+ {
+ ContentInfo expectedContentInfo = new ContentInfo(new byte[] { 1, 2, 3 });
+ EnvelopedCms ecms = new EnvelopedCms(expectedContentInfo);
+ ecms.Certificates.Add(Certificates.RSAKeyTransfer2.GetCertificate());
+ ecms.Certificates.Add(Certificates.RSAKeyTransfer3.GetCertificate());
+
+ using (X509Certificate2 cert = Certificates.RSAKeyTransfer1.GetCertificate())
+ {
+ ecms.Encrypt(new CmsRecipient(cert));
+ }
+
+ Assert.Equal(Certificates.RSAKeyTransfer2.GetCertificate(), ecms.Certificates[0]);
+ Assert.Equal(Certificates.RSAKeyTransfer3.GetCertificate(), ecms.Certificates[1]);
+ }
+
//
// State 3: Called Decode()
//
@@ -372,6 +390,40 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
Assert.ThrowsAny<CryptographicException>(() => ecms.Decrypt(r[1], extraStore));
}
}
+
+ [Fact]
+ public static void PostEncode_DifferentData()
+ {
+ // This ensures that the decoding and encoding output different values to make sure Encrypt changes the state of the data.
+ byte[] encoded =
+ ("3082010206092A864886F70D010703A081F43081F10201003181C83081C5020100302E301A311830160603550403130F"
+ + "5253414B65795472616E7366657231021031D935FB63E8CFAB48A0BF7B397B67C0300D06092A864886F70D0101010500"
+ + "04818009C16B674495C2C3D4763189C3274CF7A9142FBEEC8902ABDC9CE29910D541DF910E029A31443DC9A9F3B05F02"
+ + "DA1C38478C400261C734D6789C4197C20143C4312CEAA99ECB1849718326D4FC3B7FBB2D1D23281E31584A63E99F2C17"
+ + "132BCD8EDDB632967125CD0A4BAA1EFA8CE4C855F7C093339211BDF990CEF5CCE6CD74302106092A864886F70D010701"
+ + "301406082A864886F70D03070408779B3DE045826B18").HexToByteArray();
+ EnvelopedCms ecms = new EnvelopedCms();
+ ecms.Decode(encoded);
+ using (X509Certificate2 cert = Certificates.RSAKeyTransfer1.GetCertificate())
+ {
+ ecms.Encrypt(new CmsRecipient(cert));
+ }
+
+ byte[] encrypted = ecms.Encode();
+
+ Assert.NotEqual<byte>(encoded, encrypted);
+ }
+
+ private static void AssertEncryptedContentEqual(byte[] expected, byte[] actual)
+ {
+ if (expected.SequenceEqual(actual))
+ return;
+
+ if (actual.Length > expected.Length && actual.Take(expected.Length).SequenceEqual(expected))
+ throw new Exception("Returned content had extra bytes padded. If you're running this test on the desktop framework, this is a known bug.");
+
+ Assert.Equal<byte>(expected, actual);
+ }
}
}
diff --git a/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/UnprotectedAttributeTests.cs b/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/UnprotectedAttributeTests.cs
index 5c797fe3fc..6c22bb3956 100644
--- a/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/UnprotectedAttributeTests.cs
+++ b/src/System.Security.Cryptography.Pkcs/tests/EnvelopedCms/UnprotectedAttributeTests.cs
@@ -2,15 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.IO;
using System.Linq;
-using System.Globalization;
using System.Collections.Generic;
-using System.Security.Cryptography;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Security.Cryptography.Pkcs;
-using System.Security.Cryptography.Xml;
using System.Security.Cryptography.X509Certificates;
using Xunit;
@@ -412,6 +405,73 @@ namespace System.Security.Cryptography.Pkcs.EnvelopedCmsTests.Tests
Assert.True(a is Pkcs9AttributeObject);
}
+ [Fact]
+ [OuterLoop(/* Leaks key on disk if interrupted */)]
+ public static void PostEncrypt_UnprotectedAttributes()
+ {
+ byte[] docDescription = ("041E4D00790020004400650073006300720069007000740069006F006E000000").HexToByteArray();
+ byte[] docName1 = ("0410AA00790020004E0061006D0065000000").HexToByteArray();
+ byte[] docName2 = ("04104D00790020004E0061006D0065000000").HexToByteArray();
+ ContentInfo expectedContentInfo = new ContentInfo(new byte[] { 1, 2, 3 });
+ EnvelopedCms ecms = new EnvelopedCms(expectedContentInfo);
+ AsnEncodedData[] attributes = {
+ new AsnEncodedData(Oids.DocumentName, docName1),
+ new AsnEncodedData(Oids.DocumentName, docName2),
+ new AsnEncodedData(Oids.DocumentDescription, docDescription)};
+
+ foreach (AsnEncodedData attribute in attributes)
+ {
+ ecms.UnprotectedAttributes.Add(attribute);
+ }
+
+ AsnEncodedData[] before = ecms.UnprotectedAttributes.FlattenAndSort();
+
+ using (X509Certificate2 cert = Certificates.RSAKeyTransfer1.GetCertificate())
+ {
+ ecms.Encrypt(new CmsRecipient(cert));
+ }
+
+ AsnEncodedData[] after = ecms.UnprotectedAttributes.FlattenAndSort();
+
+ // There are three objects, but ecms.UnprotectedAttributes.Count returns the count of different Oids,
+ // not the amount of objects inside.
+ Assert.Equal(2, ecms.UnprotectedAttributes.Count);
+
+ Assert.Equal(before.Length, after.Length);
+ for (int i = 0; i<before.Length; i++)
+ {
+ Assert.Equal(before[i].GetType(), after[i].GetType());
+ Assert.Equal(before[i].Oid.Value, after[i].Oid.Value);
+ Assert.Equal(before[i].RawData, after[i].RawData);
+ }
+ }
+
+ [Theory]
+ [InlineData(false, 0)]
+ [InlineData(true, 2)]
+ [OuterLoop(/* Leaks key on disk if interrupted */)]
+ public static void TestVersionNumber_RoundTrip(bool addUnprotectedAttrs, int expectedVersion)
+ {
+ ContentInfo expectedContentInfo = new ContentInfo(new byte[] { 1, 2, 3 });
+ byte[] docName = ("0410AA00790020004E0061006D0065000000").HexToByteArray();
+ EnvelopedCms ecms = new EnvelopedCms(expectedContentInfo);
+
+ if (addUnprotectedAttrs)
+ ecms.UnprotectedAttributes.Add(new AsnEncodedData(new Oid(Oids.DocumentName), docName));
+
+ using (X509Certificate2 cert = Certificates.RSAKeyTransfer1.GetCertificate())
+ {
+ ecms.Encrypt(new CmsRecipient(cert));
+ }
+
+ byte[] encodedMessage = ecms.Encode();
+
+ ecms = new EnvelopedCms();
+ ecms.Decode(encodedMessage);
+
+ Assert.Equal(expectedVersion, ecms.Version);
+ }
+
private static void AssertIsDocumentationDescription(this AsnEncodedData attribute, string expectedDocumentDescription)
{
Assert.Equal(Oids.DocumentDescription, attribute.Oid.Value);
diff --git a/src/System.Security.Cryptography.Pkcs/tests/Oids.cs b/src/System.Security.Cryptography.Pkcs/tests/Oids.cs
index 98de58953c..77b5730990 100644
--- a/src/System.Security.Cryptography.Pkcs/tests/Oids.cs
+++ b/src/System.Security.Cryptography.Pkcs/tests/Oids.cs
@@ -57,5 +57,9 @@ namespace System.Security.Cryptography.Pkcs.Tests
public const string Sha256 = "2.16.840.1.101.3.4.2.1";
public const string Sha384 = "2.16.840.1.101.3.4.2.2";
public const string Sha512 = "2.16.840.1.101.3.4.2.3";
+
+ // RFC3161 Timestamping
+ public const string TstInfo = "1.2.840.113549.1.9.16.1.4";
+ public const string TimeStampingPurpose = "1.3.6.1.5.5.7.3.8";
}
}
diff --git a/src/System.Security.Cryptography.Pkcs/tests/Pkcs9AttributeTests.cs b/src/System.Security.Cryptography.Pkcs/tests/Pkcs9AttributeTests.cs
index a1d2be92ad..8efcc12a80 100644
--- a/src/System.Security.Cryptography.Pkcs/tests/Pkcs9AttributeTests.cs
+++ b/src/System.Security.Cryptography.Pkcs/tests/Pkcs9AttributeTests.cs
@@ -2,17 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.IO;
-using System.Linq;
-using System.Diagnostics;
-using System.Globalization;
using System.Collections.Generic;
-using System.Security.Cryptography;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Security.Cryptography.Pkcs;
-using System.Security.Cryptography.Xml;
-using System.Security.Cryptography.X509Certificates;
using Xunit;
using Test.Cryptography;
@@ -166,6 +156,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
// the default constructor initializes with DateTime.Now.
Assert.NotNull(p.RawData);
+ Assert.Equal(DateTimeKind.Local, p.SigningTime.Kind);
string oid = p.Oid.Value;
Assert.Equal(s_OidSigningTime, oid);
}
@@ -178,13 +169,14 @@ namespace System.Security.Cryptography.Pkcs.Tests
Pkcs9SigningTime p = new Pkcs9SigningTime(rawData);
Assert.Equal(rawData, p.RawData);
DateTime cookedData = p.SigningTime;
+ Assert.Equal(DateTimeKind.Utc, cookedData.Kind);
Assert.Equal(dateTime, cookedData);
string oid = p.Oid.Value;
Assert.Equal(s_OidSigningTime, oid);
}
[Fact]
- public static void SigningTimeFromCookedData()
+ public static void SigningTimeFromCookedData_Unspecified()
{
DateTime dateTime = new DateTime(2015, 4, 1);
Pkcs9SigningTime p = new Pkcs9SigningTime(dateTime);
@@ -194,6 +186,35 @@ namespace System.Security.Cryptography.Pkcs.Tests
Pkcs9SigningTime p2 = new Pkcs9SigningTime(p.RawData);
DateTime cookedData = p2.SigningTime;
Assert.Equal(dateTime, cookedData);
+ Assert.Equal(DateTimeKind.Utc, cookedData.Kind);
+ }
+
+ [Fact]
+ public static void SigningTimeFromCookedData_Local()
+ {
+ DateTime dateTime = new DateTime(2015, 4, 1, 0, 0, 0, DateTimeKind.Local);
+ Pkcs9SigningTime p = new Pkcs9SigningTime(dateTime);
+ string oid = p.Oid.Value;
+ Assert.Equal(s_OidSigningTime, oid);
+
+ Pkcs9SigningTime p2 = new Pkcs9SigningTime(p.RawData);
+ DateTime cookedData = p2.SigningTime;
+ Assert.Equal(dateTime, cookedData.ToLocalTime());
+ Assert.Equal(DateTimeKind.Utc, cookedData.Kind);
+ }
+
+ [Fact]
+ public static void SigningTimeFromCookedData_Utc()
+ {
+ DateTime dateTime = new DateTime(2015, 4, 1, 0, 0, 0, DateTimeKind.Utc);
+ Pkcs9SigningTime p = new Pkcs9SigningTime(dateTime);
+ string oid = p.Oid.Value;
+ Assert.Equal(s_OidSigningTime, oid);
+
+ Pkcs9SigningTime p2 = new Pkcs9SigningTime(p.RawData);
+ DateTime cookedData = p2.SigningTime;
+ Assert.Equal(dateTime, cookedData);
+ Assert.Equal(DateTimeKind.Utc, cookedData.Kind);
}
[Fact]
diff --git a/src/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampRequestTests.cs b/src/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampRequestTests.cs
new file mode 100644
index 0000000000..cac3c984f3
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampRequestTests.cs
@@ -0,0 +1,783 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Reflection;
+using System.Security.Cryptography.X509Certificates;
+using Test.Cryptography;
+using Xunit;
+
+namespace System.Security.Cryptography.Pkcs.Tests
+{
+ public static class TimestampRequestTests
+ {
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public static void BuildExpectedRequest_FromData(bool viaSpan)
+ {
+ Rfc3161TimestampRequest request = Rfc3161TimestampRequest.CreateFromData(
+ System.Text.Encoding.ASCII.GetBytes("Hello, world!!"),
+ HashAlgorithmName.SHA256,
+ requestSignerCertificates: true);
+
+ VerifyExpectedRequest(request, viaSpan);
+ }
+
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public static void BuildExpectedRequest_FromHashAndName(bool viaSpan)
+ {
+ Rfc3161TimestampRequest request = Rfc3161TimestampRequest.CreateFromHash(
+ "11806C2441295EA697EA96EE4247C0F9C71EE7638863CB8E29CD941A488FCB5A".HexToByteArray(),
+ HashAlgorithmName.SHA256,
+ requestSignerCertificates: true);
+
+ VerifyExpectedRequest(request, viaSpan);
+ }
+
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public static void BuildExpectedRequest_FromHashAndOid(bool viaSpan)
+ {
+ Oid hashAlgorithmId = new Oid("2.16.840.1.101.3.4.2.1", "Nothing should read this friendly name");
+
+ Rfc3161TimestampRequest request = Rfc3161TimestampRequest.CreateFromHash(
+ "11806C2441295EA697EA96EE4247C0F9C71EE7638863CB8E29CD941A488FCB5A".HexToByteArray(),
+ hashAlgorithmId,
+ requestSignerCertificates: true);
+
+ Assert.NotSame(hashAlgorithmId, request.HashAlgorithmId);
+ Assert.Equal(hashAlgorithmId.Value, request.HashAlgorithmId.Value);
+
+ VerifyExpectedRequest(request, viaSpan);
+ }
+
+ private static void VerifyExpectedRequest(Rfc3161TimestampRequest request, bool viaSpan)
+ {
+ // Captured with Fiddler from a CryptRetrieveTimestamp call
+ const string ExpectedHex =
+ "30390201013031300D06096086480165030402010500042011806C2441295EA6" +
+ "97EA96EE4247C0F9C71EE7638863CB8E29CD941A488FCB5A0101FF";
+
+ Assert.Equal(1, request.Version);
+ Assert.Equal(
+ "11806C2441295EA697EA96EE4247C0F9C71EE7638863CB8E29CD941A488FCB5A",
+ request.GetMessageHash().ByteArrayToHex());
+
+ Assert.False(request.GetNonce().HasValue, "request.GetNonce().HasValue");
+ Assert.Equal("2.16.840.1.101.3.4.2.1", request.HashAlgorithmId.Value);
+ Assert.Null(request.RequestedPolicyId);
+ Assert.True(request.RequestSignerCertificate, "request.RequestSignerCertificate");
+ Assert.False(request.HasExtensions);
+
+ if (viaSpan)
+ {
+ // Twice as big as it needs to be.
+ byte[] buf = new byte[ExpectedHex.Length];
+
+ const byte FillByte = 0x55;
+ buf.AsSpan().Fill(FillByte);
+
+ // Too small
+ Assert.False(request.TryEncode(Span<byte>.Empty, out int bytesWritten));
+ Assert.Equal(0, bytesWritten);
+
+ const int WriteOffset = 7;
+
+ // Too small
+ Span<byte> dest = new Span<byte>(buf, WriteOffset, (ExpectedHex.Length / 2) - 1);
+ Assert.False(request.TryEncode(dest, out bytesWritten));
+ Assert.Equal(0, bytesWritten);
+
+ Assert.Equal(new string('5', buf.Length * 2), buf.ByteArrayToHex());
+
+ // Bigger than needed
+ dest = new Span<byte>(buf, WriteOffset, buf.Length - WriteOffset);
+ Assert.True(request.TryEncode(dest, out bytesWritten));
+ Assert.Equal(ExpectedHex.Length / 2, bytesWritten);
+ Assert.Equal(ExpectedHex, dest.Slice(0, bytesWritten).ByteArrayToHex());
+
+ Assert.Equal(FillByte, buf[WriteOffset - 1]);
+ Assert.Equal(FillByte, buf[WriteOffset + bytesWritten]);
+
+ // Reset
+ dest.Fill(FillByte);
+
+ // Perfectly sized
+ dest = dest.Slice(0, bytesWritten);
+ Assert.True(request.TryEncode(dest, out bytesWritten));
+ Assert.Equal(ExpectedHex.Length / 2, bytesWritten);
+ Assert.Equal(ExpectedHex, dest.ByteArrayToHex());
+
+ Assert.Equal(FillByte, buf[WriteOffset - 1]);
+ Assert.Equal(FillByte, buf[WriteOffset + bytesWritten]);
+ }
+ else
+ {
+ byte[] encoded = request.Encode();
+
+ Assert.Equal(ExpectedHex, encoded.ByteArrayToHex());
+ }
+ }
+
+ [Fact]
+ public static void BuildFromSignerInfo()
+ {
+ ContentInfo content = new ContentInfo(new byte[] { 1, 2, 3, 4 });
+ SignedCms cms = new SignedCms(content, false);
+
+ using (X509Certificate2 signerCert = Certificates.RSAKeyTransferCapi1.TryGetCertificateWithPrivateKey())
+ {
+ CmsSigner signer = new CmsSigner(SubjectIdentifierType.SubjectKeyIdentifier, signerCert);
+ signer.SignedAttributes.Add(new Pkcs9SigningTime());
+ cms.ComputeSignature(signer);
+ }
+
+ SignerInfo signerInfo = cms.SignerInfos[0];
+ byte[] sig = signerInfo.GetSignature();
+
+ Rfc3161TimestampRequest fromSigner = Rfc3161TimestampRequest.CreateFromSignerInfo(signerInfo, HashAlgorithmName.SHA256);
+ Rfc3161TimestampRequest fromData = Rfc3161TimestampRequest.CreateFromData(sig, HashAlgorithmName.SHA256);
+
+ Assert.Equal(fromData.Encode().ByteArrayToHex(), fromSigner.Encode().ByteArrayToHex());
+ }
+
+ [Fact]
+ public static void BuildFromNullSignerInfo()
+ {
+ AssertExtensions.Throws<ArgumentNullException>(
+ "signerInfo",
+ () => Rfc3161TimestampRequest.CreateFromSignerInfo(null, HashAlgorithmName.SHA256));
+ }
+
+ [Fact]
+ public static void BuildWithAllOptions()
+ {
+ byte[] data = { 1, 9, 7, 5, 0, 4, 0, 4 };
+ Oid requestedPolicyOid = new Oid("1.2.3", "1.2.3");
+ byte[] nonce = "0123456789".HexToByteArray();
+
+ X509ExtensionCollection extensionsIn = new X509ExtensionCollection
+ {
+ new X509Extension("1.2.3.4.5", new byte[] { 0x05, 0x00 }, false),
+ new X509Extension("0.1.2", new byte[] { 0x04, 0x00 }, false),
+ };
+
+ Rfc3161TimestampRequest req = Rfc3161TimestampRequest.CreateFromData(
+ data,
+ HashAlgorithmName.SHA512,
+ requestedPolicyOid,
+ nonce,
+ true,
+ extensionsIn);
+
+ Assert.NotNull(req);
+ Assert.Equal(512 / 8, req.GetMessageHash().Length);
+ Assert.Equal(Oids.Sha512, req.HashAlgorithmId.Value);
+ Assert.NotNull(req.RequestedPolicyId);
+ Assert.NotSame(requestedPolicyOid, req.RequestedPolicyId);
+ Assert.Equal(requestedPolicyOid.Value, req.RequestedPolicyId.Value);
+ Assert.True(req.GetNonce().HasValue, "req.GetNonce().HasValue");
+ Assert.Equal(nonce.ByteArrayToHex(), req.GetNonce().Value.ByteArrayToHex());
+ Assert.True(req.RequestSignerCertificate, "req.RequestSignerCertificate");
+ Assert.True(req.HasExtensions, "req.HasExtensions");
+
+ X509ExtensionCollection extensionsOut = req.GetExtensions();
+
+ Assert.NotSame(extensionsIn, extensionsOut);
+ Assert.Equal(extensionsIn.Count, extensionsOut.Count);
+ Assert.NotSame(extensionsIn[0], extensionsOut[0]);
+ Assert.NotSame(extensionsIn[0], extensionsOut[1]);
+ Assert.NotSame(extensionsIn[1], extensionsOut[0]);
+ Assert.NotSame(extensionsIn[1], extensionsOut[1]);
+
+ // Extensions is order-preserving
+ Assert.Equal(extensionsIn[0].Oid.Value, extensionsOut[0].Oid.Value);
+ Assert.Equal(extensionsIn[0].RawData, extensionsOut[0].RawData);
+
+ Assert.Equal(extensionsIn[1].Oid.Value, extensionsOut[1].Oid.Value);
+ Assert.Equal(extensionsIn[1].RawData, extensionsOut[1].RawData);
+ }
+
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public static void TryDecode_WithExtensions(bool withExcessData)
+ {
+ const string PaddingHex = "0403010203";
+
+ byte[] inputBytes = (
+ "307C0201013051300D06096086480165030402030500044060EDD3D91924EC2A2AABA0BD16997" +
+ "4AF5A04BC5495342871CF52EF9AF8DF36BAB5B2E456B26C00B42147626C5ADDAAC986291091FA" +
+ "7387D504A5BF62427176AD06022A03020501234567890101FFA016300A06042A0304050402050" +
+ "030080602010204020400" + PaddingHex).HexToByteArray();
+
+ var dataRange = new ReadOnlyMemory<byte>(inputBytes, 0, inputBytes.Length - PaddingHex.Length / 2);
+
+ ReadOnlyMemory<byte> toUse = withExcessData ? inputBytes : dataRange;
+
+ Rfc3161TimestampRequest request;
+ int bytesRead;
+
+ Assert.True(Rfc3161TimestampRequest.TryDecode(toUse, out request, out bytesRead), "TryDecode");
+ Assert.Equal(dataRange.Length, bytesRead);
+ Assert.NotNull(request);
+
+ const string ExpectedHashHex =
+ "60EDD3D91924EC2A2AABA0BD169974AF5A04BC5495342871CF52EF9AF8DF36BA" +
+ "B5B2E456B26C00B42147626C5ADDAAC986291091FA7387D504A5BF62427176AD";
+
+ Assert.Equal(1, request.Version);
+ Assert.Equal(ExpectedHashHex, request.GetMessageHash().ByteArrayToHex());
+ Assert.Equal(Oids.Sha512, request.HashAlgorithmId.Value);
+ Assert.NotNull(request.RequestedPolicyId);
+ Assert.Equal("1.2.3", request.RequestedPolicyId.Value);
+ Assert.True(request.GetNonce().HasValue, "request.GetNonce().HasValue");
+ Assert.Equal("0123456789", request.GetNonce().Value.ByteArrayToHex());
+ Assert.True(request.RequestSignerCertificate, "request.RequestSignerCertificate");
+ Assert.True(request.HasExtensions, "request.HasExtensions");
+
+ X509ExtensionCollection extensions = request.GetExtensions();
+ Assert.Equal(2, extensions.Count);
+ Assert.Equal("1.2.3.4.5", extensions[0].Oid.Value);
+ Assert.Equal("0500", extensions[0].RawData.ByteArrayToHex());
+ Assert.Equal("0.1.2", extensions[1].Oid.Value);
+ Assert.Equal("0400", extensions[1].RawData.ByteArrayToHex());
+ }
+
+ [Theory]
+ [InlineData(Rfc3161RequestResponseStatus.Accepted, 0)]
+ [InlineData(Rfc3161RequestResponseStatus.HashMismatch, 0)]
+ [InlineData(Rfc3161RequestResponseStatus.HashMismatch, 1)]
+ [InlineData(Rfc3161RequestResponseStatus.NonceMismatch, 0)]
+ [InlineData(Rfc3161RequestResponseStatus.UnexpectedCertificates, 0)]
+ [InlineData(Rfc3161RequestResponseStatus.RequestFailed, 0)]
+ [InlineData(Rfc3161RequestResponseStatus.DoesNotParse, 0)]
+ [InlineData(Rfc3161RequestResponseStatus.DoesNotParse, 1)]
+ [InlineData(Rfc3161RequestResponseStatus.DoesNotParse, 2)]
+ [InlineData(Rfc3161RequestResponseStatus.DoesNotParse, 3)]
+ [InlineData(Rfc3161RequestResponseStatus.DoesNotParse, 4)]
+ [InlineData(Rfc3161RequestResponseStatus.DoesNotParse, 5)]
+ [InlineData(Rfc3161RequestResponseStatus.DoesNotParse, 6)]
+ [InlineData(Rfc3161RequestResponseStatus.DoesNotParse, 7)]
+ public static void ProcessResponse_FreeTsa_WithCerts_NoNonce(Rfc3161RequestResponseStatus expectedStatus, int variant)
+ {
+ const string Padding = "0400";
+
+ string inputHex =
+ "30820D2D300302010030820D2406092A864886F70D010702A0820D1530820D11" +
+ "020103310B300906052B0E03021A050030820196060B2A864886F70D01091001" +
+ "04A0820185048201813082017D02010106042A0304013031300D060960864801" +
+ "65030402010500042011806C2441295EA697EA96EE4247C0F9C71EE7638863CB" +
+ "8E29CD941A488FCB5A020306A5C1181632303138303130343136353634302E35" +
+ "39373334385A300A020101800201F48101640101FFA0820111A482010D308201" +
+ "093111300F060355040A13084672656520545341310C300A060355040B130354" +
+ "534131763074060355040D136D54686973206365727469666963617465206469" +
+ "676974616C6C79207369676E7320646F63756D656E747320616E642074696D65" +
+ "207374616D70207265717565737473206D616465207573696E67207468652066" +
+ "7265657473612E6F7267206F6E6C696E65207365727669636573311830160603" +
+ "550403130F7777772E667265657473612E6F72673122302006092A864886F70D" +
+ "0109011613627573696C657A617340676D61696C2E636F6D3112301006035504" +
+ "071309577565727A62757267310B3009060355040613024445310F300D060355" +
+ "0408130642617965726EA082080530820801308205E9A003020102020900C1E9" +
+ "86160DA8E982300D06092A864886F70D01010D05003081953111300F06035504" +
+ "0A130846726565205453413110300E060355040B1307526F6F74204341311830" +
+ "160603550403130F7777772E667265657473612E6F72673122302006092A8648" +
+ "86F70D0109011613627573696C657A617340676D61696C2E636F6D3112301006" +
+ "035504071309577565727A62757267310F300D0603550408130642617965726E" +
+ "310B3009060355040613024445301E170D3136303331333031353733395A170D" +
+ "3236303331313031353733395A308201093111300F060355040A130846726565" +
+ "20545341310C300A060355040B130354534131763074060355040D136D546869" +
+ "73206365727469666963617465206469676974616C6C79207369676E7320646F" +
+ "63756D656E747320616E642074696D65207374616D7020726571756573747320" +
+ "6D616465207573696E672074686520667265657473612E6F7267206F6E6C696E" +
+ "65207365727669636573311830160603550403130F7777772E66726565747361" +
+ "2E6F72673122302006092A864886F70D0109011613627573696C657A61734067" +
+ "6D61696C2E636F6D3112301006035504071309577565727A62757267310B3009" +
+ "060355040613024445310F300D0603550408130642617965726E30820222300D" +
+ "06092A864886F70D01010105000382020F003082020A0282020100B591048C4E" +
+ "486F34E9DC08627FC2375162236984B82CB130BEFF517CFC38F84BCE5C65A874" +
+ "DAB2621AE0BCE7E33563E0EDE934FD5F8823159F07848808227460C1ED882617" +
+ "06F4281334359DFBB81BD1353FC179610AF1A8C8C865DC00EA23B3A89BE6BD03" +
+ "BA85A9EC827D60565905E22D6A584ED1380AE150280CEE397E98A012F3804640" +
+ "07862443BC077CB95F421AF31712D9683CDB6DFFBAF3C8BA5BA566AE523D459D" +
+ "6177346D4D840E27886B7C01C5B890D78A2E27BBA8DD2F9A2812E157D62F921C" +
+ "65962548069DCDB7D06DE181DE0E9570D66F87220CE28B628AB55906F3EE0C21" +
+ "0F7051E8F4858AF8B9A92D09E46AF2D9CBA5BFCFAD168CDF604491A4B06603B1" +
+ "14CAF7031F065E7EEEFA53C575F3490C059D2E32DDC76AC4D4C4C710683B97FD" +
+ "1BE591BC61055186D88F9A0391B307B6F91ED954DAA36F9ACD6A1E14AA2E4ADF" +
+ "17464B54DB18DBB6FFE30080246547370436CE4E77BAE5DE6FE0F3F9D6E7FFBE" +
+ "B461E794E92FB0951F8AAE61A412CCE9B21074635C8BE327AE1A0F6B4A646EB0" +
+ "F8463BC63BF845530435D19E802511EC9F66C3496952D8BECB69B0AA4D4C41F6" +
+ "0515FE7DCBB89319CDDA59BA6AEA4BE3CEAE718E6FCB6CCD7DB9FC50BB15B12F" +
+ "3665B0AA307289C2E6DD4B111CE48BA2D9EFDB5A6B9A506069334FB34F6FC7AE" +
+ "330F0B34208AAC80DF3266FDD90465876BA2CB898D9505315B6E7B0203010001" +
+ "A38201DB308201D730090603551D1304023000301D0603551D0E041604146E76" +
+ "0B7B4E4F9CE160CA6D2CE927A2A294B37737301F0603551D23041830168014FA" +
+ "550D8C346651434CF7E7B3A76C95AF7AE6A497300B0603551D0F0404030206C0" +
+ "30160603551D250101FF040C300A06082B06010505070308306306082B060105" +
+ "0507010104573055302A06082B06010505073002861E687474703A2F2F777777" +
+ "2E667265657473612E6F72672F7473612E637274302706082B06010505073001" +
+ "861B687474703A2F2F7777772E667265657473612E6F72673A32353630303706" +
+ "03551D1F0430302E302CA02AA0288626687474703A2F2F7777772E6672656574" +
+ "73612E6F72672F63726C2F726F6F745F63612E63726C3081C60603551D200481" +
+ "BE3081BB3081B80601003081B2303306082B060105050702011627687474703A" +
+ "2F2F7777772E667265657473612E6F72672F667265657473615F6370732E6874" +
+ "6D6C303206082B060105050702011626687474703A2F2F7777772E6672656574" +
+ "73612E6F72672F667265657473615F6370732E706466304706082B0601050507" +
+ "0202303B1A394672656554534120747275737465642074696D657374616D7069" +
+ "6E6720536F667477617265206173206120536572766963652028536161532930" +
+ "0D06092A864886F70D01010D05000382020100A5C944E2C6FAC0A14D930A7FD0" +
+ "A0B172B41FC1483C3E957C68A2BCD9B9764F1A950161FD72472D41A5EED27778" +
+ "6203B5422240FB3A26CDE176087B6FB1011DF4CC19E2571AA4A051109665E94C" +
+ "46F50BD2ADEE6AC4137E251B25A39DABDA451515D8FF9E07209E8EC20B7874F7" +
+ "E1A0EDE7C00937FE84A334F8B3265CED2D8ED9DF61396583677FEB382C1EE3B2" +
+ "3E6EA5F05DF30DE7B9F89005D25266F612F39C8B4F6DABA6D7BFBAC19632B906" +
+ "37329F52A6F066A10E43EAA81F849A6C5FE3FE8B5EA23275F687F2052E502EA6" +
+ "C30762A668CCE07871DD8E97E315BBA929E25589977A0A312CE96C5106B1437C" +
+ "779F2B361B182888F3EE8A234374FA063E956192627F7C431073965D1260928E" +
+ "BA009E803429AE324CF96F042354F37BCA5AFDDC79F79346AB388BFC79F01DC9" +
+ "861254EA6CC129941076B83D20556F3BE51326837F2876F7833B370E7C3D4105" +
+ "23827D4F53400C72218D75229FF10C6F8893A9A3A1C0C42BB4C898C13DF41C7F" +
+ "6573B4FC56515971A610A7B0D2857C8225A9FB204EACECA2E8971AA1AF87886A" +
+ "2AE3C72FE0A0AAE842980A77BEF16B92115458090D982B5946603764E75A0AD3" +
+ "D11454B9986F678B9AB6AFE8497033AE3ABFD4EB43B7BC9DEE68815949E64815" +
+ "82A82E785277F2282107EFE390200E0508ACB8EA82EA2505276F3C9DA2A3D3B4" +
+ "AD38BBF8842BDA36FC2448291F558DC02DD1E03182035A308203560201013081" +
+ "A33081953111300F060355040A130846726565205453413110300E060355040B" +
+ "1307526F6F74204341311830160603550403130F7777772E667265657473612E" +
+ "6F72673122302006092A864886F70D0109011613627573696C657A617340676D" +
+ "61696C2E636F6D3112301006035504071309577565727A62757267310F300D06" +
+ "03550408130642617965726E310B3009060355040613024445020900C1E98616" +
+ "0DA8E982300906052B0E03021A0500A0818C301A06092A864886F70D01090331" +
+ "0D060B2A864886F70D0109100104301C06092A864886F70D010905310F170D31" +
+ "38303130343136353634305A302306092A864886F70D01090431160414029AC1" +
+ "0A42471FBD0586C107BE51F79FA3080004302B060B2A864886F70D010910020C" +
+ "311C301A301830160414916DA3D860ECCA82E34BC59D1793E7E968875F14300D" +
+ "06092A864886F70D01010105000482020093555D4EA36895232E8D8E3FBAFFD1" +
+ "B625FF0C61363411AD1ECF5A53DEBC6A233046539971BD8B50EEAC06E8CE72F2" +
+ "DC12C28C01F3AEC0D8276955703E88FD043829F7E67A1781C5BBB949897FBD12" +
+ "9ED0E81F252E35FE3E398453783C136A6FAC9B2F519936079C878AF389324D72" +
+ "83C0396A94B432C52344BDC9F561110894978900B0EA8121AB937341A08F1BF3" +
+ "109C41871CD81456C45F41DA306E164F143FCA9FC708C545B6F9A7032541C2AB" +
+ "8B6A8C37114AB66AC142226C740EA695E701E434AE225A488E0484089C785F3D" +
+ "873FCE5D8A8D75DE6AA6AB5915C5C11CE76263A463DF4BA07FE164D989DB9055" +
+ "54B4207A2C622DF10808F0078F40CC75C7B2B9C161C11A17231C2EFABEB50047" +
+ "E7FD76B13A011225ECFB9C8185E82A724C9175C4763D6353F1C3992AE9E6EF0D" +
+ "6D32867DF84CD98F55AD0E1B260B48899019FA903F257FCC2DBA5893FF840A99" +
+ "E22EB0B20E43868C75A2463E38740B79AF183CD5B6AE50D1D6FE5C2D397C2257" +
+ "87C682AF575A7554201725C444747FD6C4644B0029B3BBFE39265ADA82020D5C" +
+ "7EB9DEAAA4EEF9EF404CEEC73C4BC907E0E4006BD9CAA41852F12BE13B1279AF" +
+ "62D502B5A721B4A4ABE3939DBE114E7C473F29719D1B580E8CE92BE2143E8DFA" +
+ "480C07A6CAE881893678BDF0828F7286E47D76A251C6899F41C75728AFADABE6" +
+ "6A47E3E28EB64E734356A6374E4CB05EC3" + Padding;
+
+ byte[] inputBytes = inputHex.HexToByteArray();
+ ReadOnlyMemory<byte>? nonce = null;
+ HashAlgorithmName hashAlgorithmName = HashAlgorithmName.SHA256;
+ byte[] hash = "11806C2441295EA697EA96EE4247C0F9C71EE7638863CB8E29CD941A488FCB5A".HexToByteArray();
+
+ if (expectedStatus == Rfc3161RequestResponseStatus.NonceMismatch)
+ {
+ nonce = new byte[] { 9, 8, 7, 6 };
+ }
+ else if (expectedStatus == Rfc3161RequestResponseStatus.HashMismatch)
+ {
+ if (variant == 0)
+ {
+ hash[0] ^= 0xFF;
+ }
+ else
+ {
+ hashAlgorithmName = HashAlgorithmName.SHA384;
+ }
+ }
+ else if (expectedStatus == Rfc3161RequestResponseStatus.RequestFailed)
+ {
+ // Address determined by data inspection
+ Assert.Equal(0, inputBytes[8]);
+ inputBytes[8] = 3;
+ }
+ else if (expectedStatus == Rfc3161RequestResponseStatus.VersionTooNew)
+ {
+ // Address determined by data inspection
+ Assert.Equal(1, inputBytes[79]);
+ inputBytes[79] = 2;
+ }
+ else if (expectedStatus == Rfc3161RequestResponseStatus.DoesNotParse)
+ {
+ if (variant == 0)
+ {
+ // Change the PkiStatus from a SEQUENCE to a SET.
+
+ // Address determined by data inspection
+ Assert.Equal(0x30, inputBytes[4]);
+ inputBytes[4] = 0x31;
+ }
+ else if (variant == 1)
+ {
+ // Change the SET OF (digestAlgorithms) in the token CMS to SEQUENCE OF
+
+ // Address determined by data inspection
+ Assert.Equal(0x31, inputBytes[35]);
+ inputBytes[35] = 0x30;
+ }
+ else if (variant == 2)
+ {
+ // Change the id-signedData value to id-data.
+
+ // Address determined by data inspection
+ Assert.Equal(2, inputBytes[23]);
+ inputBytes[23] = 1;
+ }
+ else if (variant == 3)
+ {
+ // Change the id-ct-TSTInfo into id-ct-receipt
+
+ // Address determined by data inspection
+ Assert.Equal(4, inputBytes[64]);
+ inputBytes[64] = 1;
+ }
+ else if (variant == 4)
+ {
+ // Change the id-aa-signing-certificate into id-aa-content-hint
+ // Now the signer has no ESSCertId (and it already doesn't have an ESSCertIdV2)
+
+ // Address determined by data inspection
+ Assert.Equal(12, inputBytes[2815]);
+ inputBytes[2815] = 4;
+ }
+ else if (variant == 5)
+ {
+ // Alter a byte in the certificate required hash value, ESSCertId mismatches
+
+ // Address determined by data inspection
+ Assert.Equal(0xD8, inputBytes[2829]);
+ inputBytes[2829] ^= 0xFF;
+ }
+ else if (variant == 6)
+ {
+ // Alter the signerInfo signature algorithm to say it's the PKCS#1 module
+
+ // Address determined by data inspection
+ Assert.Equal(1, inputBytes[2858]);
+ inputBytes[2858] = 0;
+ }
+ else if (variant == 7)
+ {
+ // Change the TSTInfo.Version value, which breaks the signature.
+
+ // Address determined by data inspection
+ Assert.Equal(1, inputBytes[79]);
+ inputBytes[79] = 2;
+ }
+ else if (variant == 7)
+ {
+ // Change one of the SEQUENCE values in ESSCertId to SET
+
+ // Address determined by data inspection
+ Assert.Equal(0x30, inputBytes[2820]);
+ inputBytes[2820] = 0x31;
+ }
+ }
+
+ Rfc3161TimestampRequest request = Rfc3161TimestampRequest.CreateFromHash(
+ hash,
+ hashAlgorithmName,
+ nonce: nonce,
+ requestSignerCertificates: expectedStatus != Rfc3161RequestResponseStatus.UnexpectedCertificates);
+
+ ProcessResponse(expectedStatus, request, inputBytes, Padding.Length / 2);
+ }
+
+ [Theory]
+ [InlineData(Rfc3161RequestResponseStatus.Accepted, 0)]
+ [InlineData(Rfc3161RequestResponseStatus.Accepted, 1)]
+ [InlineData(Rfc3161RequestResponseStatus.HashMismatch, 0)]
+ [InlineData(Rfc3161RequestResponseStatus.HashMismatch, 1)]
+ [InlineData(Rfc3161RequestResponseStatus.NonceMismatch, 0)]
+ [InlineData(Rfc3161RequestResponseStatus.RequestedCertificatesMissing, 0)]
+ [InlineData(Rfc3161RequestResponseStatus.VersionTooNew, 0)]
+ [InlineData(Rfc3161RequestResponseStatus.DoesNotParse, 0)]
+ [InlineData(Rfc3161RequestResponseStatus.DoesNotParse, 1)]
+ [InlineData(Rfc3161RequestResponseStatus.DoesNotParse, 2)]
+ public static void ProcessResponse_Symantec_NoCerts_WithNonce(
+ Rfc3161RequestResponseStatus expectedStatus,
+ int variant)
+ {
+ const string Padding = "0403000000";
+
+ string inputHex =
+ "308203B23003020100308203A906092A864886F70D010702A082039A30820396" +
+ "020103310D300B060960864801650304020130820122060B2A864886F70D0109" +
+ "100104A08201110482010D30820109020101060B6086480186F8450107170330" +
+ "31300D06096086480165030402010500042011806C2441295EA697EA96EE4247" +
+ "C0F9C71EE7638863CB8E29CD941A488FCB5A021500D19949957B5677CF5F5581" +
+ "630A597827BA80EFD6180F32303138303130353137303931365A300302011E02" +
+ "0E3230313830313035313730373030A08186A48183308180310B300906035504" +
+ "0613025553311D301B060355040A131453796D616E74656320436F72706F7261" +
+ "74696F6E311F301D060355040B131653796D616E746563205472757374204E65" +
+ "74776F726B3131302F0603550403132853796D616E7465632053484132353620" +
+ "54696D655374616D70696E67205369676E6572202D2047323182025A30820256" +
+ "02010130818B3077310B3009060355040613025553311D301B060355040A1314" +
+ "53796D616E74656320436F72706F726174696F6E311F301D060355040B131653" +
+ "796D616E746563205472757374204E6574776F726B312830260603550403131F" +
+ "53796D616E746563205348413235362054696D655374616D70696E6720434102" +
+ "105458F2AAD741D644BC84A97BA09652E6300B0609608648016503040201A081" +
+ "A4301A06092A864886F70D010903310D060B2A864886F70D0109100104301C06" +
+ "092A864886F70D010905310F170D3138303130353137303931365A302F06092A" +
+ "864886F70D01090431220420ACA421A6482F4722320ECF53223F8D15099329CA" +
+ "4ADFD71EC562631F522C85553037060B2A864886F70D010910022F3128302630" +
+ "2430220420CF7AC17AD047ECD5FDC36822031B12D4EF078B6F2B4C5E6BA41F8F" +
+ "F2CF4BAD67300B06092A864886F70D010101048201008F4020CFAE55355A0545" +
+ "1A1250CCE1439A2DDD62915C81A1C7661888A74F9D0792922051CD426792D3A1" +
+ "ED3DC47C6AF2281A9A02ED89C605BB9FB7FD63FAF27335FE45A7681E5904C68C" +
+ "C30E5DBB37D127C437785F07BD2EF20C31EB0341AB2FA6F9D70C43ADA15C082E" +
+ "E630D64E59CBB06918F094D6B5B19C9C74DC7B203E2F86EC638761E244B279DB" +
+ "DAFDC87143288A488398FDFAABBAD82D992EFC9845BE9ABF19D00754E4064D24" +
+ "6C8B2C16012FA147B25000570F41C2BE9126082095A4CCA3E2FA3C5C694C1E6B" +
+ "BC7BFF4CA8EA692A07B8B9E6AB8E3114701080923A9A83DD6A4257C4248C865F" +
+ "C51BA0D8DA57FB5692039F4B102608AECA217204BBD4" + Padding;
+
+ byte[] inputBytes = inputHex.HexToByteArray();
+
+ ReadOnlyMemory<byte> nonce = "3230313830313035313730373030".HexToByteArray();
+ HashAlgorithmName hashAlgorithmName = HashAlgorithmName.SHA256;
+ byte[] hash = "11806C2441295EA697EA96EE4247C0F9C71EE7638863CB8E29CD941A488FCB5A".HexToByteArray();
+
+ if (expectedStatus == Rfc3161RequestResponseStatus.NonceMismatch)
+ {
+ nonce = new byte[] { 9, 8, 7, 6 };
+ }
+ else if (expectedStatus == Rfc3161RequestResponseStatus.HashMismatch)
+ {
+ if (variant == 0)
+ {
+ hash[0] ^= 0xFF;
+ }
+ else
+ {
+ hashAlgorithmName = HashAlgorithmName.SHA384;
+ }
+ }
+ else if (expectedStatus == Rfc3161RequestResponseStatus.VersionTooNew)
+ {
+ // Change the TSTInfo.Version value.
+ // Since the certificate isn't embedded the signature check doesn't happen.
+
+ // Address determined by data inspection
+ Assert.Equal(1, inputBytes[81]);
+ inputBytes[81] = 2;
+ }
+ else if (expectedStatus == Rfc3161RequestResponseStatus.DoesNotParse)
+ {
+ if (variant == 0)
+ {
+ // Change the id-aa-signing-certificateV2 into id-aa-binary-signing-time
+ // Now the signer has no ESSCertIdV2 (and it already doesn't have an ESSCertId)
+
+ // Address determined by data inspection
+ Assert.Equal(47, inputBytes[634]);
+ inputBytes[634] = 46;
+ }
+ else if (variant == 1)
+ {
+ // Change one of the SEQUENCE values in ESSCertIdV2 to SET
+
+ // Address determined by data inspection
+ Assert.Equal(0x30, inputBytes[639]);
+ inputBytes[639] = 0x31;
+ }
+ else if (variant == 2)
+ {
+ // Corrupt the structure of the TSTInfo
+
+ // Address determined by data inspection
+ Assert.Equal(0x02, inputBytes[79]);
+ inputBytes[79] = 0x04;
+ }
+ }
+ else if (expectedStatus == Rfc3161RequestResponseStatus.Accepted)
+ {
+ if (variant == 1)
+ {
+ // Tamper with the hash in the ESSCertIdV2. This will be accepted because
+ // the cert is unknown.
+
+ // Address determined by data inspection
+ Assert.Equal(0x7A, inputBytes[646]);
+ inputBytes[646] ^= 0xFF;
+ }
+ }
+ Rfc3161TimestampRequest request = Rfc3161TimestampRequest.CreateFromHash(
+ hash,
+ hashAlgorithmName,
+ nonce: nonce,
+ requestSignerCertificates: expectedStatus == Rfc3161RequestResponseStatus.RequestedCertificatesMissing);
+
+ ProcessResponse(expectedStatus, request, inputBytes, Padding.Length / 2);
+ }
+
+ private static void ProcessResponse(
+ Rfc3161RequestResponseStatus expectedStatus,
+ Rfc3161TimestampRequest request,
+ byte[] inputBytes,
+ int paddingByteCount)
+ {
+ Rfc3161TimestampToken token;
+ int bytesRead;
+ Rfc3161RequestResponseStatus status;
+ bool result = request.TryProcessResponse(inputBytes, out token, out status, out bytesRead);
+
+ Assert.Equal(expectedStatus, status);
+
+ if (expectedStatus == Rfc3161RequestResponseStatus.Accepted)
+ {
+ Assert.True(result, "request.TryProcessResponse return value");
+ }
+ else
+ {
+ Assert.False(result, "request.TryProcessResponse return value");
+ }
+
+ if (expectedStatus == Rfc3161RequestResponseStatus.DoesNotParse)
+ {
+ Assert.Equal(0, bytesRead);
+ }
+ else
+ {
+ Assert.Equal(inputBytes.Length - paddingByteCount, bytesRead);
+ }
+
+ switch (expectedStatus)
+ {
+ case Rfc3161RequestResponseStatus.Accepted:
+ case Rfc3161RequestResponseStatus.HashMismatch:
+ case Rfc3161RequestResponseStatus.NonceMismatch:
+ case Rfc3161RequestResponseStatus.UnexpectedCertificates:
+ case Rfc3161RequestResponseStatus.RequestedCertificatesMissing:
+ case Rfc3161RequestResponseStatus.VersionTooNew:
+ Assert.NotNull(token);
+ break;
+ default:
+ Assert.Null(token);
+ break;
+ }
+
+ if (result)
+ {
+ Rfc3161TimestampToken token2 = request.ProcessResponse(inputBytes, out int bytesRead2);
+
+ Assert.Equal(bytesRead, bytesRead2);
+ Assert.NotNull(token2);
+ Assert.NotSame(token, token2);
+ }
+ else
+ {
+ Assert.Throws<CryptographicException>(() => request.ProcessResponse(inputBytes, out bytesRead));
+ }
+ }
+
+ [Fact]
+ public static void EmptyNonce()
+ {
+ byte[] sha256 = new byte[256 / 8];
+
+ Rfc3161TimestampRequest req = Rfc3161TimestampRequest.CreateFromHash(
+ sha256,
+ HashAlgorithmName.SHA256,
+ nonce: Array.Empty<byte>());
+
+ Assert.Equal("00", req.GetNonce().Value.ByteArrayToHex());
+ }
+
+ [Fact]
+ public static void NegativeNonceIsMadePositive()
+ {
+ byte[] sha256 = new byte[256 / 8];
+ byte[] nonce = { 0xFE };
+
+ Rfc3161TimestampRequest req = Rfc3161TimestampRequest.CreateFromHash(
+ sha256,
+ HashAlgorithmName.SHA256,
+ nonce: nonce);
+
+ Assert.Equal("00FE", req.GetNonce().Value.ByteArrayToHex());
+ }
+
+ [Fact]
+ public static void NonceLeadingZerosIgnored()
+ {
+ byte[] sha256 = new byte[256 / 8];
+ byte[] nonce = { 0x00, 0x00, 0x01, 0xFE };
+
+ Rfc3161TimestampRequest req = Rfc3161TimestampRequest.CreateFromHash(
+ sha256,
+ HashAlgorithmName.SHA256,
+ nonce: nonce);
+
+ Assert.Equal("01FE", req.GetNonce().Value.ByteArrayToHex());
+ }
+
+ [Fact]
+ public static void NoncePaddingZerosIgnored()
+ {
+ byte[] sha256 = new byte[256 / 8];
+ byte[] nonce = { 0x00, 0x00, 0xFE };
+
+ Rfc3161TimestampRequest req = Rfc3161TimestampRequest.CreateFromHash(
+ sha256,
+ HashAlgorithmName.SHA256,
+ nonce: nonce);
+
+ Assert.Equal("00FE", req.GetNonce().Value.ByteArrayToHex());
+ }
+
+ public enum Rfc3161RequestResponseStatus
+ {
+ Unknown = 0,
+ Accepted = 1,
+ DoesNotParse = 2,
+ RequestFailed = 3,
+ HashMismatch = 4,
+ VersionTooNew = 5,
+ NonceMismatch = 6,
+ RequestedCertificatesMissing = 7,
+ UnexpectedCertificates = 8,
+ }
+ }
+
+ internal static class Rfc3161TimestampRequestExtensions
+ {
+ private static readonly MethodInfo s_tryProcesses;
+
+ static Rfc3161TimestampRequestExtensions()
+ {
+ s_tryProcesses = typeof(Rfc3161TimestampRequest)
+ .GetMethod("ProcessResponse", BindingFlags.NonPublic | BindingFlags.Instance);
+ }
+
+ internal static bool TryProcessResponse(
+ this Rfc3161TimestampRequest request,
+ ReadOnlyMemory<byte> inputBytes,
+ out Rfc3161TimestampToken token,
+ out TimestampRequestTests.Rfc3161RequestResponseStatus status,
+ out int bytesRead)
+ {
+ object[] parameters = { inputBytes, null, null, null, false };
+ object result = s_tryProcesses.Invoke(request, parameters);
+
+ token = (Rfc3161TimestampToken)parameters[1];
+
+ status = (TimestampRequestTests.Rfc3161RequestResponseStatus)
+ Enum.ToObject(typeof(TimestampRequestTests.Rfc3161RequestResponseStatus), parameters[2]);
+
+ bytesRead = (int)parameters[3];
+
+ return (bool)result;
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampTokenInfoTests.cs b/src/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampTokenInfoTests.cs
new file mode 100644
index 0000000000..2ab7adda28
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampTokenInfoTests.cs
@@ -0,0 +1,501 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.X509Certificates;
+using Test.Cryptography;
+using Xunit;
+
+namespace System.Security.Cryptography.Pkcs.Tests
+{
+ public static class TimestampTokenInfoTests
+ {
+ [Theory]
+ [InlineData(nameof(TimestampTokenTestData.FreeTsaDotOrg1))]
+ [InlineData(nameof(TimestampTokenTestData.Symantec1))]
+ public static void CreateFromParameters(string testDataName)
+ {
+ TimestampTokenTestData testData = TimestampTokenTestData.GetTestData(testDataName);
+
+ Oid policyId = new Oid(testData.PolicyId, testData.PolicyId);
+ Oid hashAlgorithmOid = new Oid(testData.HashAlgorithmId);
+ byte[] messageHash = testData.HashBytes.ToArray();
+ byte[] serial = testData.SerialNumberBytes.ToArray();
+ DateTimeOffset nonUtcTimestamp = testData.Timestamp.ToOffset(TimeSpan.FromHours(-8));
+ long? accuracyMicrosec = testData.AccuracyInMicroseconds;
+ byte[] nonce = testData.NonceBytes?.ToArray();
+ byte[] tsaNameBytes = testData.TsaNameBytes?.ToArray();
+
+ ReadOnlyMemory<byte>? nonceMemory = null;
+ ReadOnlyMemory<byte>? tsaMemory = null;
+
+ if (nonce != null)
+ {
+ nonceMemory = nonce;
+ }
+
+ if (tsaNameBytes != null)
+ {
+ tsaMemory = tsaNameBytes;
+ }
+
+ var tokenInfo = new Rfc3161TimestampTokenInfo(
+ policyId,
+ hashAlgorithmOid,
+ messageHash,
+ serial,
+ nonUtcTimestamp,
+ accuracyMicrosec,
+ testData.IsOrdering,
+ nonceMemory,
+ tsaMemory);
+
+ // Since AssertEqual will check all the fields the remaining checks in this method are about
+ // input/output value/reference associations.
+ AssertEqual(testData, tokenInfo);
+
+ Assert.NotSame(policyId, tokenInfo.PolicyId);
+ Assert.NotSame(hashAlgorithmOid, tokenInfo.HashAlgorithmId);
+
+ Assert.Equal(nonUtcTimestamp, tokenInfo.Timestamp);
+ Assert.Equal(TimeSpan.Zero, tokenInfo.Timestamp.Offset);
+
+ Assert.Equal(messageHash.ByteArrayToHex(), tokenInfo.GetMessageHash().ByteArrayToHex());
+ // Detached from the original data
+ messageHash[0] ^= 0xFF;
+ Assert.NotEqual(messageHash.ByteArrayToHex(), tokenInfo.GetMessageHash().ByteArrayToHex());
+
+ Assert.Equal(serial.ByteArrayToHex(), tokenInfo.GetSerialNumber().ByteArrayToHex());
+ // Detached from the original data
+ serial[1] ^= 0xFF;
+ Assert.NotEqual(serial.ByteArrayToHex(), tokenInfo.GetSerialNumber().ByteArrayToHex());
+
+
+ if (nonce != null)
+ {
+ ReadOnlyMemory<byte>? tokenNonce = tokenInfo.GetNonce();
+ Assert.True(tokenNonce.HasValue, "tokenInfo.GetNonce().HasValue");
+
+ Assert.Equal(nonce.ByteArrayToHex(), tokenNonce.Value.ByteArrayToHex());
+ // Detached from the original data
+ nonce[0] ^= 0xFF;
+ Assert.NotEqual(nonce.ByteArrayToHex(), tokenNonce.Value.ByteArrayToHex());
+ }
+
+ ReadOnlyMemory<byte>? nameFromToken = tokenInfo.GetTimestampAuthorityName();
+
+ if (tsaNameBytes != null)
+ {
+ Assert.True(nameFromToken.HasValue, "nameFromToken.HasValue");
+ Assert.Equal(tsaNameBytes.ByteArrayToHex(), nameFromToken.Value.ByteArrayToHex());
+ // Detached from the original data
+ tsaNameBytes[5] ^= 0xFF;
+ Assert.NotEqual(tsaNameBytes.ByteArrayToHex(), nameFromToken.Value.ByteArrayToHex());
+ }
+
+ if (testData.ExtensionsBytes == null)
+ {
+ Assert.False(tokenInfo.HasExtensions, "tokenInfo.HasExtensions");
+ Assert.NotNull(tokenInfo.GetExtensions());
+ Assert.Equal(0, tokenInfo.GetExtensions().Count);
+
+ // GetExtensions always returns a new collection.
+ Assert.NotSame(tokenInfo.GetExtensions(), tokenInfo.GetExtensions());
+ }
+ else
+ {
+ Assert.True(tokenInfo.HasExtensions, "tokenInfo.HasExtensions");
+ Assert.NotNull(tokenInfo.GetExtensions());
+
+ Assert.True(false, "A test handler has been written for extensions...");
+
+ // GetExtensions always returns a new collection.
+ Assert.NotSame(tokenInfo.GetExtensions(), tokenInfo.GetExtensions());
+ }
+
+ // Because the token is DER encoded, we should produce byte-for-byte the same value.
+ Assert.Equal(testData.TokenInfoBytes.ByteArrayToHex(), tokenInfo.Encode().ByteArrayToHex());
+ }
+
+ [Theory]
+ [InlineData(nameof(TimestampTokenTestData.FreeTsaDotOrg1), false)]
+ [InlineData(nameof(TimestampTokenTestData.FreeTsaDotOrg1), true)]
+ [InlineData(nameof(TimestampTokenTestData.Symantec1), false)]
+ [InlineData(nameof(TimestampTokenTestData.Symantec1), true)]
+ public static void CreateFromValue(string testDataName, bool viaTry)
+ {
+ TimestampTokenTestData testData = TimestampTokenTestData.GetTestData(testDataName);
+
+ ValidateTokenInfo(
+ testData.TokenInfoBytes,
+ testData,
+ viaTry ? testData.TokenInfoBytes.Length : (int?)null);
+ }
+
+ private static void ValidateTokenInfo(
+ ReadOnlyMemory<byte> tokenInfoBytes,
+ TimestampTokenTestData testData,
+ int? lengthFromTry)
+ {
+ Rfc3161TimestampTokenInfo tokenInfo;
+
+ Assert.True(
+ Rfc3161TimestampTokenInfo.TryDecode(tokenInfoBytes, out tokenInfo, out int bytesRead),
+ "Rfc3161TimestampTokenInfo.TryDecode");
+
+ Assert.NotNull(tokenInfo);
+
+ if (lengthFromTry != null)
+ {
+ Assert.Equal(lengthFromTry.Value, bytesRead);
+ }
+
+ AssertEqual(testData, tokenInfo);
+ }
+
+ [Fact]
+ public static void TryDecode_LongerThanNeeded()
+ {
+ const int ExtraBytes = 11;
+ ReadOnlyMemory<byte> inputTokenData = TimestampTokenTestData.Symantec1.TokenInfoBytes;
+ int len = inputTokenData.Length + ExtraBytes;
+ byte[] inputData = new byte[len];
+
+ for (int i = inputTokenData.Length; i < len; i++)
+ {
+ inputData[i] = unchecked((byte)i);
+ }
+
+ inputTokenData.Span.CopyTo(inputData);
+
+ ValidateTokenInfo(inputData, TimestampTokenTestData.Symantec1, inputTokenData.Length);
+ }
+
+ [Fact]
+ public static void TryDecode_Invalid()
+ {
+ ReadOnlyMemory<byte> inputData = TimestampTokenTestData.Symantec1.TokenInfoBytes;
+
+ Assert.False(
+ Rfc3161TimestampTokenInfo.TryDecode(
+ inputData.Slice(0, inputData.Length - 1),
+ out Rfc3161TimestampTokenInfo tokenInfo,
+ out int bytesRead));
+
+ Assert.Equal(0, bytesRead);
+ Assert.Null(tokenInfo);
+ }
+
+ [Fact]
+ public static void BuilderCtor_PolicyIdRequired()
+ {
+ AssertExtensions.Throws<ArgumentNullException>(
+ "policyId",
+ () => new Rfc3161TimestampTokenInfo(null, null, default, default, default));
+ }
+
+ [Fact]
+ public static void BuilderCtor_HashAlgorithmIdRequired()
+ {
+ Oid policyId = new Oid("0.0", "0.0");
+
+ AssertExtensions.Throws<ArgumentNullException>(
+ "hashAlgorithmId",
+ () => new Rfc3161TimestampTokenInfo(policyId, null, default, default, default));
+ }
+
+ [Fact]
+ public static void BuilderCtor_TsaNameOptional()
+ {
+ Oid policyId = new Oid("0.0", "0.0");
+ Oid hashAlgorithmId = new Oid(Oids.Sha256);
+
+ var tokenInfo = new Rfc3161TimestampTokenInfo(
+ policyId,
+ hashAlgorithmId,
+ new byte[256 / 8],
+ new byte[] { 1 },
+ DateTimeOffset.UtcNow);
+
+ Assert.False(tokenInfo.GetTimestampAuthorityName().HasValue);
+
+ Assert.True(Rfc3161TimestampTokenInfo.TryDecode(tokenInfo.Encode(), out tokenInfo, out _));
+ Assert.False(tokenInfo.GetTimestampAuthorityName().HasValue);
+ }
+
+ [Fact]
+ public static void BuilderCtor_AccuracyOptional()
+ {
+ Oid policyId = new Oid("0.0", "0.0");
+ Oid hashAlgorithmId = new Oid(Oids.Sha256);
+
+ var tokenInfo = new Rfc3161TimestampTokenInfo(
+ policyId,
+ hashAlgorithmId,
+ new byte[256 / 8],
+ new byte[] { 2 },
+ DateTimeOffset.UtcNow);
+
+ Assert.False(tokenInfo.AccuracyInMicroseconds.HasValue);
+
+ Assert.True(Rfc3161TimestampTokenInfo.TryDecode(tokenInfo.Encode(), out tokenInfo, out _));
+ Assert.False(tokenInfo.AccuracyInMicroseconds.HasValue);
+ }
+
+ [Fact]
+ public static void TsaName_SameDataSecondInvocation()
+ {
+ const string InputHex =
+ "3081F8020101060B6086480186F845010717033031300D060960864801650304" +
+ "020105000420315F5BDB76D078C43B8AC0064E4A0164612B1FCE77C869345BFC" +
+ "94C75894EDD302146C77B12D5FCF9F6DC1D4A481E935F446FBA376C4180F3230" +
+ "3137313031303232303835325A300302011EA08186A48183308180310B300906" +
+ "0355040613025553311D301B060355040A131453796D616E74656320436F7270" +
+ "6F726174696F6E311F301D060355040B131653796D616E746563205472757374" +
+ "204E6574776F726B3131302F0603550403132853796D616E7465632053484132" +
+ "35362054696D655374616D70696E67205369676E6572202D204732";
+
+ Rfc3161TimestampTokenInfo tokenInfo;
+ Assert.True(Rfc3161TimestampTokenInfo.TryDecode(InputHex.HexToByteArray(), out tokenInfo, out _));
+
+ ReadOnlyMemory<byte>? tsaName = tokenInfo.GetTimestampAuthorityName();
+ Assert.True(tsaName.HasValue, "tsaName.HasValue");
+ ReadOnlyMemory<byte> tsaName1 = tsaName.Value;
+ ReadOnlyMemory<byte> tsaName2 = tokenInfo.GetTimestampAuthorityName().Value;
+
+ Assert.Equal(tsaName1.Length, tsaName2.Length);
+
+ Assert.True(
+ Unsafe.AreSame(
+ ref MemoryMarshal.GetReference(tsaName1.Span),
+ ref MemoryMarshal.GetReference(tsaName2.Span)),
+ "Second call to GetTimestampAuthorityName is over the same memory");
+ }
+
+ [Fact]
+ public static void ExtensionsRoundtrips()
+ {
+ Oid policyId = new Oid("0.0", "0.0");
+ Oid hashAlgorithmId = new Oid(Oids.Sha256);
+
+ byte[] extensionValue = { 3, 1, 4, 1, 5, 9, 2, 7, 5, 8 };
+
+ var tokenInfo = new Rfc3161TimestampTokenInfo(
+ policyId,
+ hashAlgorithmId,
+ new byte[256 / 8],
+ new byte[] { 3 },
+ DateTimeOffset.UtcNow,
+ extensions: new X509ExtensionCollection
+ {
+ new X509Extension(new Oid("0.0.0", "0.0.0"), extensionValue, true),
+ });
+
+ Assert.True(tokenInfo.HasExtensions);
+
+ Assert.True(Rfc3161TimestampTokenInfo.TryDecode(tokenInfo.Encode(), out tokenInfo, out _));
+
+ Assert.True(tokenInfo.HasExtensions);
+ X509ExtensionCollection extensions = tokenInfo.GetExtensions();
+
+ Assert.Equal(1, extensions.Count);
+ X509Extension extension = extensions[0];
+ Assert.NotNull(extension);
+ Assert.Equal("0.0.0", extension.Oid.Value);
+ Assert.True(extension.Critical, "extension.Critical");
+ Assert.Equal(extensionValue.ByteArrayToHex(), extension.RawData.ByteArrayToHex());
+ }
+
+ [Fact]
+ public static void BuilderCtor_IsOrdering_Roundtrips()
+ {
+ Oid policyId = new Oid("0.0", "0.0");
+ Oid hashAlgorithmId = new Oid(Oids.Sha256);
+
+ var tokenInfo = new Rfc3161TimestampTokenInfo(
+ policyId,
+ hashAlgorithmId,
+ new byte[256 / 8],
+ new byte[] { 7 },
+ DateTimeOffset.UtcNow,
+ isOrdering: true);
+
+ Assert.True(tokenInfo.IsOrdering, "tokenInfo.IsOrdering");
+
+ Assert.True(Rfc3161TimestampTokenInfo.TryDecode(tokenInfo.Encode(), out tokenInfo, out _));
+ Assert.True(tokenInfo.IsOrdering, "tokenInfo.IsOrdering");
+ }
+
+ [Fact]
+ public static void BuilderCtor_Timestamp_KeepsSubSeconds()
+ {
+ // RFC 3161 says that the genTime value should omit fractions "when there is no need"
+ //
+ // We leave the trimming up to the caller, because there are multiple positions for
+ // the accuracy+precision position.
+ DateTimeOffset marker = new DateTimeOffset(2017, 12, 18, 17, 5, 34, TimeSpan.Zero);
+ DateTimeOffset experiment = marker + TimeSpan.FromMilliseconds(17);
+
+ Assert.NotEqual(marker, experiment);
+
+ Oid policyId1 = new Oid("0.0", "0.0");
+ Oid hashAlgorithmId1 = new Oid(Oids.Sha256);
+
+ var tokenInfo = new Rfc3161TimestampTokenInfo(
+ policyId1,
+ hashAlgorithmId1,
+ new byte[256 / 8],
+ new byte[] { 6 },
+ experiment);
+
+ Assert.Equal(experiment, tokenInfo.Timestamp);
+ }
+
+ [Theory]
+ [InlineData("No accuracy", "", true, null)]
+ [InlineData("MicroSeconds = 0", "3003810100", false, null)]
+ [InlineData("MicroSeconds = 1", "3003810101", true, 1L)]
+ [InlineData("MicroSeconds = 999", "3004810203E7", true, 999L)]
+ [InlineData("MicroSeconds = 1000", "3004810203E8", false, null)]
+ [InlineData("MilliSeconds = 0", "3003800100", false, null)]
+ [InlineData("MilliSeconds = 1", "3003800101", true, 1000L)]
+ [InlineData("MilliSeconds = 999", "3004800203E7", true, 999000L)]
+ [InlineData("MilliSeconds = 1000", "3004800203E8", false, null)]
+ [InlineData("Seconds = 0", "3003020100", true, 0L)]
+ [InlineData("Seconds = -1", "30030201FF", false, null)]
+ public static void Accuracy_Bounds_ParsesAsExpected(
+ string description,
+ string accuracyHex,
+ bool shouldParse,
+ long? expectedTotalMicroseconds)
+ {
+ string inputHex =
+ "305A0201010601003031300D0609608648016503040201050004200000000000" +
+ "0000000000000000000000000000000000000000000000000000000201081817" +
+ "32303137313231383138313235342E373438363336345A" + accuracyHex;
+
+ byte[] inputData = inputHex.HexToByteArray();
+ inputData[1] = checked((byte)(0x55 + accuracyHex.Length / 2));
+
+ if (shouldParse)
+ {
+ int bytesRead;
+ Rfc3161TimestampTokenInfo tokenInfo;
+
+ Assert.True(Rfc3161TimestampTokenInfo.TryDecode(inputData, out tokenInfo, out bytesRead));
+ Assert.Equal(inputData.Length, bytesRead);
+ Assert.NotNull(tokenInfo);
+ Assert.Equal(expectedTotalMicroseconds, tokenInfo.AccuracyInMicroseconds);
+ }
+ else
+ {
+ Assert.False(Rfc3161TimestampTokenInfo.TryDecode(inputData, out _, out _));
+ }
+ }
+
+ [Theory]
+ [InlineData(0)]
+ [InlineData(1)]
+ [InlineData(999)]
+ [InlineData(1000)]
+ [InlineData(1001)]
+ [InlineData(1999)]
+ [InlineData(999000)]
+ [InlineData(999001)]
+ [InlineData(999999)]
+ [InlineData(1000000)]
+ [InlineData(1000001)]
+ [InlineData(1000999)]
+ [InlineData(1001000)]
+ [InlineData(1001001)]
+ [InlineData(1999999)]
+ public static void AccuracyRoundtrips(long totalMicroseconds)
+ {
+ Rfc3161TimestampTokenInfo info = new Rfc3161TimestampTokenInfo(
+ new Oid("0.0", "0.0"),
+ new Oid(Oids.Sha256),
+ new byte[256 / 8],
+ new byte[] { 1 },
+ DateTimeOffset.UtcNow,
+ accuracyInMicroseconds: totalMicroseconds);
+
+ Assert.True(info.AccuracyInMicroseconds.HasValue);
+ Assert.Equal(totalMicroseconds, info.AccuracyInMicroseconds.Value);
+
+ byte[] encoded = info.Encode();
+
+ Rfc3161TimestampTokenInfo info2;
+ int bytesConsumed;
+
+ Assert.True(
+ Rfc3161TimestampTokenInfo.TryDecode(encoded, out info2, out bytesConsumed));
+
+ Assert.Equal(encoded.Length, bytesConsumed);
+ Assert.NotNull(info2);
+ Assert.True(info2.AccuracyInMicroseconds.HasValue);
+ Assert.Equal(totalMicroseconds, info2.AccuracyInMicroseconds.Value);
+ }
+
+ [Fact]
+ public static void NegativeAccuracyThrows()
+ {
+ AssertExtensions.Throws<ArgumentOutOfRangeException>(
+ "accuracyInMicroseconds",
+ () => new Rfc3161TimestampTokenInfo(
+ new Oid("0.0", "0.0"),
+ new Oid(Oids.Sha256),
+ new byte[256 / 8],
+ new byte[] { 2 },
+ DateTimeOffset.UtcNow,
+ accuracyInMicroseconds: -1));
+ }
+
+ internal static void AssertEqual(TimestampTokenTestData testData, Rfc3161TimestampTokenInfo tokenInfo)
+ {
+ Assert.Equal(testData.Version, tokenInfo.Version);
+ Assert.Equal(testData.PolicyId, tokenInfo.PolicyId.Value);
+ Assert.Equal(testData.HashAlgorithmId, tokenInfo.HashAlgorithmId.Value);
+ // FriendlyName should be set for known digest algorithms
+ Assert.NotEqual(tokenInfo.HashAlgorithmId.Value, tokenInfo.HashAlgorithmId.FriendlyName);
+ Assert.Equal(testData.HashBytes.ByteArrayToHex(), tokenInfo.GetMessageHash().ByteArrayToHex());
+ Assert.Equal(testData.SerialNumberBytes.ByteArrayToHex(), tokenInfo.GetSerialNumber().ByteArrayToHex());
+ Assert.Equal(testData.Timestamp, tokenInfo.Timestamp);
+ Assert.Equal(TimeSpan.Zero, tokenInfo.Timestamp.Offset);
+ Assert.Equal(testData.AccuracyInMicroseconds, tokenInfo.AccuracyInMicroseconds);
+
+ if (testData.IsOrdering)
+ {
+ Assert.True(tokenInfo.IsOrdering, "tokenInfo.IsOrdering");
+ }
+ else
+ {
+ Assert.False(tokenInfo.IsOrdering, "tokenInfo.IsOrdering");
+ }
+
+ Assert.Equal(testData.NonceBytes?.ByteArrayToHex(), tokenInfo.GetNonce()?.ByteArrayToHex());
+ Assert.Equal(testData.TsaNameBytes?.ByteArrayToHex(), tokenInfo.GetTimestampAuthorityName()?.ByteArrayToHex());
+
+ if (testData.ExtensionsBytes == null)
+ {
+ Assert.False(tokenInfo.HasExtensions, "tokenInfo.HasExtensions");
+ Assert.NotNull(tokenInfo.GetExtensions());
+ Assert.Equal(0, tokenInfo.GetExtensions().Count);
+
+ // GetExtensions always returns a new collection.
+ Assert.NotSame(tokenInfo.GetExtensions(), tokenInfo.GetExtensions());
+ }
+ else
+ {
+ Assert.True(tokenInfo.HasExtensions, "tokenInfo.HasExtensions");
+ Assert.NotNull(tokenInfo.GetExtensions());
+
+ Assert.True(false, "A test handler has been written for extensions...");
+
+ // GetExtensions always returns a new collection.
+ Assert.NotSame(tokenInfo.GetExtensions(), tokenInfo.GetExtensions());
+ }
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampTokenTestData.cs b/src/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampTokenTestData.cs
new file mode 100644
index 0000000000..8bdc43a476
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampTokenTestData.cs
@@ -0,0 +1,301 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Text;
+using Test.Cryptography;
+
+namespace System.Security.Cryptography.Pkcs.Tests
+{
+ internal sealed class TimestampTokenTestData
+ {
+ internal ReadOnlyMemory<byte> MessageContent { get; private set; }
+
+ internal ReadOnlyMemory<byte> FullTokenBytes { get; }
+ internal ReadOnlyMemory<byte>? EmbeddedSigningCertificate { get; private set; }
+ internal ReadOnlyMemory<byte> TokenInfoBytes { get; private set; }
+
+ internal int Version => 1;
+ internal string PolicyId { get; private set; }
+ internal string HashAlgorithmId { get; private set; }
+ internal ReadOnlyMemory<byte> HashBytes { get; private set; }
+ internal ReadOnlyMemory<byte> SerialNumberBytes { get; private set; }
+ internal bool TimestampTooPrecise { get; private set; }
+ internal DateTimeOffset Timestamp { get; private set; }
+ internal long? AccuracyInMicroseconds { get; private set; }
+ internal bool IsOrdering { get; private set; }
+ internal ReadOnlyMemory<byte>? NonceBytes { get; private set; }
+ internal ReadOnlyMemory<byte>? TsaNameBytes { get; private set; }
+ internal ReadOnlyMemory<byte>? ExtensionsBytes { get; private set; }
+
+ internal byte[] ExternalCertificateBytes { get; private set; }
+
+ private TimestampTokenTestData(string inputHex)
+ : this(inputHex.HexToByteArray())
+ {
+ }
+
+ private TimestampTokenTestData(ReadOnlyMemory<byte> fullTokenBytes)
+ {
+ FullTokenBytes = fullTokenBytes;
+ }
+
+ internal static TimestampTokenTestData GetTestData(string testDataName)
+ {
+ switch (testDataName)
+ {
+ case nameof(FreeTsaDotOrg1):
+ return FreeTsaDotOrg1;
+ case nameof(Symantec1):
+ return Symantec1;
+ }
+
+ throw new ArgumentOutOfRangeException(nameof(testDataName), testDataName, "No registered value");
+ }
+
+ internal static readonly TimestampTokenTestData FreeTsaDotOrg1 = ((Func<TimestampTokenTestData>)(() =>
+ {
+ var data = new TimestampTokenTestData(
+ "3082053606092A864886F70D010702A082052730820523020103310B30090605" +
+ "2B0E03021A0500308201B1060B2A864886F70D0109100104A08201A00482019C" +
+ "3082019802010106042A0304013041300D060960864801650304020205000430" +
+ "9111E404B85D1F088C23DBE654943F30B103B6CBFE01898A1F7701A23B055E79" +
+ "C27AEE38BC44CC0F212DBAC0EBE92C580203064F641816323031373132313831" +
+ "37333431362E3830303831325A300A020101800201F48101640101FF02090096" +
+ "31D170EA3B92D4A0820111A482010D308201093111300F060355040A13084672" +
+ "656520545341310C300A060355040B130354534131763074060355040D136D54" +
+ "686973206365727469666963617465206469676974616C6C79207369676E7320" +
+ "646F63756D656E747320616E642074696D65207374616D702072657175657374" +
+ "73206D616465207573696E672074686520667265657473612E6F7267206F6E6C" +
+ "696E65207365727669636573311830160603550403130F7777772E6672656574" +
+ "73612E6F72673122302006092A864886F70D0109011613627573696C657A6173" +
+ "40676D61696C2E636F6D3112301006035504071309577565727A62757267310B" +
+ "3009060355040613024445310F300D0603550408130642617965726E3182035A" +
+ "308203560201013081A33081953111300F060355040A13084672656520545341" +
+ "3110300E060355040B1307526F6F74204341311830160603550403130F777777" +
+ "2E667265657473612E6F72673122302006092A864886F70D0109011613627573" +
+ "696C657A617340676D61696C2E636F6D3112301006035504071309577565727A" +
+ "62757267310F300D0603550408130642617965726E310B300906035504061302" +
+ "4445020900C1E986160DA8E982300906052B0E03021A0500A0818C301A06092A" +
+ "864886F70D010903310D060B2A864886F70D0109100104301C06092A864886F7" +
+ "0D010905310F170D3137313231383137333431365A302306092A864886F70D01" +
+ "090431160414F53C4FC877C8AE82F9695BFE039ED1F0D154D5D3302B060B2A86" +
+ "4886F70D010910020C311C301A301830160414916DA3D860ECCA82E34BC59D17" +
+ "93E7E968875F14300D06092A864886F70D01010105000482020078A64BC950D0" +
+ "0A576DB1F1BBE822C08FA165689198CD19B4A64CB8E65CF3B33E69C7BA6EF4A3" +
+ "A005F8138457063A331D293E822260AD4DDD8DE04D4161103CF5A554283E4B1C" +
+ "7AAF57DA04E84FA3572A7F2DB1409C06B192C10C09A7672B0D45DDF114A5975C" +
+ "388BEC9036FA1D557379B7B81D4B0329A599D98217EF2E7EEFD9439B29746A6E" +
+ "93DB966072EE969B4468168E169DA035AD05A478A90475951EC27C8C32B0920B" +
+ "735B15D32393B9271466B5F8217355B0F86B44DDE7F36CBBA2A90D4F285C15AE" +
+ "17A8A1C8E536B5810B8219016009C0B8F8A2B893B662A4200BABF32E4CD21600" +
+ "6B9132D75B9C7BFB85DE109C65F072E9A419548F2499631D04AD4ED83E420A51" +
+ "64DEB505B3D345158FA936E8D559A860AEC5B5D79D1E7D7A02133868531CBFE7" +
+ "84B32E4A4D74706E0A04161D97C5BA50D190ED8C2792EF1E8834E0982241D668" +
+ "86B9CDACCFBE7CA890F71594818C50AA4EA66E21D539D108FE0A9116E18C421D" +
+ "F544465469AD7F614BF79788E808B09A8C223A02F21D7CF1B1AB1D5210D74EAB" +
+ "7958AD5035CA440BAC27C1CA9EAA603BBB4C85A09DBB4ADFA93FAF5262CFACC2" +
+ "92C0513769CC02554A1315B40D16A9AE547E50F0AC4310D71F13D9E22ADFE241" +
+ "D50DF295F1DB078C84EECBCB30F1018E939B1FEA8615B31F39F87F02EF816EFF" +
+ "FE80A39C0857ECA510882DD2D66D49B743F0E7FF8DBEE4650449");
+
+ data.MessageContent = Encoding.ASCII.GetBytes("This is a test.\n");
+
+ data.TokenInfoBytes = data.FullTokenBytes.Slice(64, 412);
+ data.PolicyId = "1.2.3.4.1";
+ data.HashAlgorithmId = Oids.Sha384;
+ data.HashBytes = data.TokenInfoBytes.Slice(32, 48);
+ data.SerialNumberBytes = data.TokenInfoBytes.Slice(82, 3);
+ data.Timestamp = new DateTimeOffset(2017, 12, 18, 17, 34, 16, TimeSpan.Zero);
+ data.Timestamp += TimeSpan.FromTicks(8008120);
+ data.TimestampTooPrecise = true;
+ data.AccuracyInMicroseconds = 1 * 1000000L + 0x1F4 * 1000 + 0x64;
+ data.IsOrdering = true;
+ data.NonceBytes = data.TokenInfoBytes.Slice(126, 9);
+ data.TsaNameBytes = data.TokenInfoBytes.Slice(139, 273);
+
+ // https://freetsa.org/files/tsa.crt
+ data.ExternalCertificateBytes = Convert.FromBase64String(
+ @"
+MIIIATCCBemgAwIBAgIJAMHphhYNqOmCMA0GCSqGSIb3DQEBDQUAMIGVMREwDwYD
+VQQKEwhGcmVlIFRTQTEQMA4GA1UECxMHUm9vdCBDQTEYMBYGA1UEAxMPd3d3LmZy
+ZWV0c2Eub3JnMSIwIAYJKoZIhvcNAQkBFhNidXNpbGV6YXNAZ21haWwuY29tMRIw
+EAYDVQQHEwlXdWVyemJ1cmcxDzANBgNVBAgTBkJheWVybjELMAkGA1UEBhMCREUw
+HhcNMTYwMzEzMDE1NzM5WhcNMjYwMzExMDE1NzM5WjCCAQkxETAPBgNVBAoTCEZy
+ZWUgVFNBMQwwCgYDVQQLEwNUU0ExdjB0BgNVBA0TbVRoaXMgY2VydGlmaWNhdGUg
+ZGlnaXRhbGx5IHNpZ25zIGRvY3VtZW50cyBhbmQgdGltZSBzdGFtcCByZXF1ZXN0
+cyBtYWRlIHVzaW5nIHRoZSBmcmVldHNhLm9yZyBvbmxpbmUgc2VydmljZXMxGDAW
+BgNVBAMTD3d3dy5mcmVldHNhLm9yZzEiMCAGCSqGSIb3DQEJARYTYnVzaWxlemFz
+QGdtYWlsLmNvbTESMBAGA1UEBxMJV3VlcnpidXJnMQswCQYDVQQGEwJERTEPMA0G
+A1UECBMGQmF5ZXJuMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtZEE
+jE5IbzTp3Ahif8I3UWIjaYS4LLEwvv9RfPw4+EvOXGWodNqyYhrgvOfjNWPg7ek0
+/V+IIxWfB4SICCJ0YMHtiCYXBvQoEzQ1nfu4G9E1P8F5YQrxqMjIZdwA6iOzqJvm
+vQO6hansgn1gVlkF4i1qWE7ROArhUCgM7jl+mKAS84BGQAeGJEO8B3y5X0Ia8xcS
+2Wg8223/uvPIululZq5SPUWdYXc0bU2EDieIa3wBxbiQ14ouJ7uo3S+aKBLhV9Yv
+khxlliVIBp3Nt9Bt4YHeDpVw1m+HIgzii2KKtVkG8+4MIQ9wUej0hYr4uaktCeRq
+8tnLpb/PrRaM32BEkaSwZgOxFMr3Ax8GXn7u+lPFdfNJDAWdLjLdx2rE1MTHEGg7
+l/0b5ZG8YQVRhtiPmgORswe2+R7ZVNqjb5rNah4Uqi5K3xdGS1TbGNu2/+MAgCRl
+RzcENs5Od7rl3m/g8/nW5/++tGHnlOkvsJUfiq5hpBLM6bIQdGNci+MnrhoPa0pk
+brD4RjvGO/hFUwQ10Z6AJRHsn2bDSWlS2L7LabCqTUxB9gUV/n3LuJMZzdpZumrq
+S+POrnGOb8tszX25/FC7FbEvNmWwqjByicLm3UsRHOSLotnv21prmlBgaTNPs09v
+x64zDws0IIqsgN8yZv3ZBGWHa6LLiY2VBTFbbnsCAwEAAaOCAdswggHXMAkGA1Ud
+EwQCMAAwHQYDVR0OBBYEFG52C3tOT5zhYMptLOknoqKUs3c3MB8GA1UdIwQYMBaA
+FPpVDYw0ZlFDTPfns6dsla965qSXMAsGA1UdDwQEAwIGwDAWBgNVHSUBAf8EDDAK
+BggrBgEFBQcDCDBjBggrBgEFBQcBAQRXMFUwKgYIKwYBBQUHMAKGHmh0dHA6Ly93
+d3cuZnJlZXRzYS5vcmcvdHNhLmNydDAnBggrBgEFBQcwAYYbaHR0cDovL3d3dy5m
+cmVldHNhLm9yZzoyNTYwMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuZnJl
+ZXRzYS5vcmcvY3JsL3Jvb3RfY2EuY3JsMIHGBgNVHSAEgb4wgbswgbgGAQAwgbIw
+MwYIKwYBBQUHAgEWJ2h0dHA6Ly93d3cuZnJlZXRzYS5vcmcvZnJlZXRzYV9jcHMu
+aHRtbDAyBggrBgEFBQcCARYmaHR0cDovL3d3dy5mcmVldHNhLm9yZy9mcmVldHNh
+X2Nwcy5wZGYwRwYIKwYBBQUHAgIwOxo5RnJlZVRTQSB0cnVzdGVkIHRpbWVzdGFt
+cGluZyBTb2Z0d2FyZSBhcyBhIFNlcnZpY2UgKFNhYVMpMA0GCSqGSIb3DQEBDQUA
+A4ICAQClyUTixvrAoU2TCn/QoLFytB/BSDw+lXxoorzZuXZPGpUBYf1yRy1Bpe7S
+d3hiA7VCIkD7OibN4XYIe2+xAR30zBniVxqkoFEQlmXpTEb1C9Kt7mrEE34lGyWj
+navaRRUV2P+eByCejsILeHT34aDt58AJN/6EozT4syZc7S2O2d9hOWWDZ3/rOCwe
+47I+bqXwXfMN57n4kAXSUmb2EvOci09tq6bXv7rBljK5Bjcyn1Km8GahDkPqqB+E
+mmxf4/6LXqIydfaH8gUuUC6mwwdipmjM4Hhx3Y6X4xW7qSniVYmXegoxLOlsUQax
+Q3x3nys2GxgoiPPuiiNDdPoGPpVhkmJ/fEMQc5ZdEmCSjroAnoA0Ka4yTPlvBCNU
+83vKWv3cefeTRqs4i/x58B3JhhJU6mzBKZQQdrg9IFVvO+UTJoN/KHb3gzs3Dnw9
+QQUjgn1PU0AMciGNdSKf8QxviJOpo6HAxCu0yJjBPfQcf2VztPxWUVlxphCnsNKF
+fIIlqfsgTqzsouiXGqGvh4hqKuPHL+CgquhCmAp3vvFrkhFUWAkNmCtZRmA3ZOda
+CtPRFFS5mG9ni5q2r+hJcDOuOr/U60O3vJ3uaIFZSeZIFYKoLnhSd/IoIQfv45Ag
+DgUIrLjqguolBSdvPJ2io9O0rTi7+IQr2jb8JEgpH1WNwC3R4A==");
+
+ return data;
+ }))();
+
+ internal static readonly TimestampTokenTestData Symantec1 = ((Func<TimestampTokenTestData>)(() =>
+ {
+ var data = new TimestampTokenTestData(
+ "30820E2406092A864886F70D010702A0820E1530820E11020103310D300B0609" +
+ "6086480165030402013082010E060B2A864886F70D0109100104A081FE0481FB" +
+ "3081F8020101060B6086480186F845010717033031300D060960864801650304" +
+ "020105000420315F5BDB76D078C43B8AC0064E4A0164612B1FCE77C869345BFC" +
+ "94C75894EDD302146C77B12D5FCF9F6DC1D4A481E935F446FBA376C4180F3230" +
+ "3137313031303232303835325A300302011EA08186A48183308180310B300906" +
+ "0355040613025553311D301B060355040A131453796D616E74656320436F7270" +
+ "6F726174696F6E311F301D060355040B131653796D616E746563205472757374" +
+ "204E6574776F726B3131302F0603550403132853796D616E7465632053484132" +
+ "35362054696D655374616D70696E67205369676E6572202D204732A0820A8B30" +
+ "82053830820420A00302010202107B05B1D449685144F7C989D29C199D12300D" +
+ "06092A864886F70D01010B05003081BD310B3009060355040613025553311730" +
+ "15060355040A130E566572695369676E2C20496E632E311F301D060355040B13" +
+ "16566572695369676E205472757374204E6574776F726B313A3038060355040B" +
+ "1331286329203230303820566572695369676E2C20496E632E202D20466F7220" +
+ "617574686F72697A656420757365206F6E6C79313830360603550403132F5665" +
+ "72695369676E20556E6976657273616C20526F6F742043657274696669636174" +
+ "696F6E20417574686F72697479301E170D3136303131323030303030305A170D" +
+ "3331303131313233353935395A3077310B3009060355040613025553311D301B" +
+ "060355040A131453796D616E74656320436F72706F726174696F6E311F301D06" +
+ "0355040B131653796D616E746563205472757374204E6574776F726B31283026" +
+ "0603550403131F53796D616E746563205348413235362054696D655374616D70" +
+ "696E6720434130820122300D06092A864886F70D01010105000382010F003082" +
+ "010A0282010100BB599D59554F9D8C725D1A81A2EB55F3B001AD3C71AC328F05" +
+ "6B869A270032976A4DC964144B29BBC2D929B92EEC63B3E1CF3F0B5690F8621B" +
+ "7EEBA607E2DE7F5E6D4038D49106E7417C791CCBCBAD1BBFD89591F3F0EE6CF8" +
+ "AD96392E7FC127B87839C584A5EDEDAF878ECE8DC76DEAD298B53A1F1E399DC3" +
+ "F49AA8F484E1C4D17C71C60629B43FE4830D26C37B083E4DF90AB73349FFCA3B" +
+ "D4F5B29B4BE188991AF5C0E93314D6DFC780DB91EEFEBC92577277F4CDA8CCFE" +
+ "09F59337BE95886AC5DCF4B14BD4CEE809915FB58479358A78AC19328F23C132" +
+ "411B590EA93EB1CCF9D62BEFB7D8E4D51D6D113A92F693C99CE348EEBB530ED4" +
+ "36978678C5A1370203010001A382017730820173300E0603551D0F0101FF0404" +
+ "0302010630120603551D130101FF040830060101FF02010030660603551D2004" +
+ "5F305D305B060B6086480186F84501071703304C302306082B06010505070201" +
+ "161768747470733A2F2F642E73796D63622E636F6D2F637073302506082B0601" +
+ "050507020230191A1768747470733A2F2F642E73796D63622E636F6D2F727061" +
+ "302E06082B0601050507010104223020301E06082B0601050507300186126874" +
+ "74703A2F2F732E73796D63642E636F6D30360603551D1F042F302D302BA029A0" +
+ "278625687474703A2F2F732E73796D63622E636F6D2F756E6976657273616C2D" +
+ "726F6F742E63726C30130603551D25040C300A06082B06010505070308302806" +
+ "03551D110421301FA41D301B311930170603550403131054696D655374616D70" +
+ "2D323034382D33301D0603551D0E04160414AF63D6CAA34E8572E0A7BC41F329" +
+ "A2387F807562301F0603551D23041830168014B677FA6948479F5312D5C2EA07" +
+ "327607D1970719300D06092A864886F70D01010B0500038201010075EAB02DD5" +
+ "34195C3245FE0EE1D44FA678C16FD7EADDDC4FF3A1C88188F7A78F15E64029AD" +
+ "E65DF4A2D956648471302ADD1E61176620560698198D5D71F2F897BC09FD1C91" +
+ "47C9E2E88D03FBCC902FD60A6C4E33ECD6B493C84C906348394021C4DDD66E89" +
+ "983CB59897E8A906B709C98F535741902FE11E4D4EDCCA10786C426EF0B6C5F8" +
+ "615C52F54EF66B8DF74A7ABEF3CDFD03D7D9F603A80FE353F70A75ECC6752EAA" +
+ "66850499B7F80657E1C60EF6E8AFDAEC9B181FAAB9E33A00BFCE8A94CB01DB9E" +
+ "C738BB0F52ABD1E39403600A4DA0FE276D1432FC3F9740E1BF9989DBE43914BD" +
+ "DAE4D3C3EA2B5AB3955855047DC79AEC23038D852AD2FFAEA961813082054B30" +
+ "820433A00302010202105458F2AAD741D644BC84A97BA09652E6300D06092A86" +
+ "4886F70D01010B05003077310B3009060355040613025553311D301B06035504" +
+ "0A131453796D616E74656320436F72706F726174696F6E311F301D060355040B" +
+ "131653796D616E746563205472757374204E6574776F726B3128302606035504" +
+ "03131F53796D616E746563205348413235362054696D655374616D70696E6720" +
+ "4341301E170D3137303130323030303030305A170D3238303430313233353935" +
+ "395A308180310B3009060355040613025553311D301B060355040A131453796D" +
+ "616E74656320436F72706F726174696F6E311F301D060355040B131653796D61" +
+ "6E746563205472757374204E6574776F726B3131302F0603550403132853796D" +
+ "616E746563205348413235362054696D655374616D70696E67205369676E6572" +
+ "202D20473230820122300D06092A864886F70D01010105000382010F00308201" +
+ "0A028201010099F3FCD804090386F9D75CA693C0427CEA7C63CF5D00E28EF3C0" +
+ "90DF8F29F518EA94B792E5D7B0A07381E8E90A9B4A7C01FF9D8FA439A70EEA45" +
+ "F4220C3A70ED39458BE4C51B5CF0456846240563769B1CFC9E6C2AB156E58A7F" +
+ "5271AEF235D54623061CCF482D1DB4CDB8D976238E1CFF3EBFBB065C6907A665" +
+ "0EF85EAE7D2EED4DAE35EFC9D70042FD28950E9F5D724209BCC3DA44D2EDCC47" +
+ "84E4FCCA2DAC58BEAEF7AED9440D08B7C277D61A4370D16E03DE5292C4100871" +
+ "D9BA2255F21FBCED9B9D3BE25E1D4C83FF970F7B0BE755834ED20DEBBED7ECAE" +
+ "6E47B99FDFA5D651BC0455EDFF27704CC9ED2A4B13E1B1B94C0FC901EE55655F" +
+ "69027866CB3F0203010001A38201C7308201C3300C0603551D130101FF040230" +
+ "0030660603551D20045F305D305B060B6086480186F84501071703304C302306" +
+ "082B06010505070201161768747470733A2F2F642E73796D63622E636F6D2F63" +
+ "7073302506082B0601050507020230191A1768747470733A2F2F642E73796D63" +
+ "622E636F6D2F72706130400603551D1F043930373035A033A031862F68747470" +
+ "3A2F2F74732D63726C2E77732E73796D616E7465632E636F6D2F736861323536" +
+ "2D7473732D63612E63726C30160603551D250101FF040C300A06082B06010505" +
+ "070308300E0603551D0F0101FF040403020780307706082B0601050507010104" +
+ "6B3069302A06082B06010505073001861E687474703A2F2F74732D6F6373702E" +
+ "77732E73796D616E7465632E636F6D303B06082B06010505073002862F687474" +
+ "703A2F2F74732D6169612E77732E73796D616E7465632E636F6D2F7368613235" +
+ "362D7473732D63612E63657230280603551D110421301FA41D301B3119301706" +
+ "03550403131054696D655374616D702D323034382D35301D0603551D0E041604" +
+ "1409B5C1FE96729729439AC9E002BAAEF8FD2FBAF6301F0603551D2304183016" +
+ "8014AF63D6CAA34E8572E0A7BC41F329A2387F807562300D06092A864886F70D" +
+ "01010B0500038201010017B30A88E95C5A5E206B3B0A15B26CC5A98A3287D3B1" +
+ "F41C53AE85BE3F9BFFD7BCB79485B4C7527E94E8BDED61B2D4A799E4C3C993C1" +
+ "353D0BE8680A5D5698BDB1223BD1447AD7BFF06D51328AD523DF380137F6E253" +
+ "2B7A2B118FB74D6C7A33031B7C6B099417BBE4DB58D4211365E7ECD125CA2C75" +
+ "9A9C7FFCC9BB2A68ABC47DB4CFA3C96CA7D9C4009C890A7791F44DA2FB313B86" +
+ "6EF6E61F5003869BBFCB42ABE6769B725A11018AC6EFA56F95E7DDAEBAE62265" +
+ "F018591B11C9CD80B7D897471F4208F8AC711FB04653B3D4B2D5A3AB50754812" +
+ "1782ADCFE0414F327ECD951CBF918A083DA4A7670296DF244CA5D041C08260A3" +
+ "8A17324BD3BCCFA4B48C3182025A3082025602010130818B3077310B30090603" +
+ "55040613025553311D301B060355040A131453796D616E74656320436F72706F" +
+ "726174696F6E311F301D060355040B131653796D616E74656320547275737420" +
+ "4E6574776F726B312830260603550403131F53796D616E746563205348413235" +
+ "362054696D655374616D70696E6720434102105458F2AAD741D644BC84A97BA0" +
+ "9652E6300B0609608648016503040201A081A4301A06092A864886F70D010903" +
+ "310D060B2A864886F70D0109100104301C06092A864886F70D010905310F170D" +
+ "3137313031303232303835325A302F06092A864886F70D01090431220420B50E" +
+ "D0D890F9195926E4D7D2ACC301FB7C33460AF36509BFBE3C692C3BA5EC3B3037" +
+ "060B2A864886F70D010910022F31283026302430220420CF7AC17AD047ECD5FD" +
+ "C36822031B12D4EF078B6F2B4C5E6BA41F8FF2CF4BAD67300B06092A864886F7" +
+ "0D010101048201003368AF4246A64CD0C2FC5CF85A05E923CC64A5DA51CEB9A5" +
+ "46C7ADB1230F1E13A87934C7A857B8B6565AD17CE4C09914F95949DBB34C9F1B" +
+ "25FBDAA9AD777698FA3400708C8BE678B49F19CE222F86A14A00DBC706972119" +
+ "FD93DC6971F9390A826FB1953498569FD646A58C99C46C8A2683378819D4C54E" +
+ "F21EB9846AA69D985DCC68D9FAFDDA365B50D8CBAD7B8865AD58A5B7CD85CC66" +
+ "B2733193C5674971BAC64EDADCA8880944572CBF4D5DD0D22B6BB0421C537885" +
+ "0E8F60BAD98EB85C7B09EBBCE11A759181EA9C32A83C8D1B73E54F3A571D1461" +
+ "FD6B6AB4F89DC6750F14EC2E0134BA61B4D0B2C1FB2F60F622379249CE6381AF" +
+ "667900B17A7BB6AE");
+
+ data.MessageContent = Encoding.ASCII.GetBytes("Hello, world!");
+
+ data.EmbeddedSigningCertificate = data.FullTokenBytes.Slice(1659, 1359);
+
+ data.TokenInfoBytes = data.FullTokenBytes.Slice(64, 251);
+ data.PolicyId = "2.16.840.1.113733.1.7.23.3";
+ data.HashAlgorithmId = Oids.Sha256;
+ data.HashBytes = data.TokenInfoBytes.Slice(38, 32);
+ data.SerialNumberBytes = data.TokenInfoBytes.Slice(72, 20);
+ data.Timestamp = new DateTimeOffset(2017, 10, 10, 22, 8, 52, TimeSpan.Zero);
+ data.AccuracyInMicroseconds = 30 * 1000000L;
+ data.IsOrdering = false;
+ data.TsaNameBytes = data.TokenInfoBytes.Slice(117, 134);
+ return data;
+ }))();
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampTokenTests.cs b/src/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampTokenTests.cs
new file mode 100644
index 0000000000..49a0e72b73
--- /dev/null
+++ b/src/System.Security.Cryptography.Pkcs/tests/Rfc3161/TimestampTokenTests.cs
@@ -0,0 +1,1087 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Linq;
+using System.Security.Cryptography.X509Certificates;
+using Test.Cryptography;
+using Xunit;
+
+namespace System.Security.Cryptography.Pkcs.Tests
+{
+ public static class TimestampTokenTests
+ {
+ [Theory]
+ [InlineData(nameof(TimestampTokenTestData.FreeTsaDotOrg1))]
+ [InlineData(nameof(TimestampTokenTestData.Symantec1))]
+ public static void ParseDocument(string testDataName)
+ {
+ TimestampTokenTestData testData = TimestampTokenTestData.GetTestData(testDataName);
+
+ TestParseDocument(testData.FullTokenBytes, testData, testData.FullTokenBytes.Length);
+ }
+
+ [Theory]
+ [InlineData(nameof(TimestampTokenTestData.FreeTsaDotOrg1))]
+ [InlineData(nameof(TimestampTokenTestData.Symantec1))]
+ public static void ParseDocument_ExcessData(string testDataName)
+ {
+ TimestampTokenTestData testData = TimestampTokenTestData.GetTestData(testDataName);
+
+ int baseLen = testData.FullTokenBytes.Length;
+ byte[] tooMuchData = new byte[baseLen + 30];
+ testData.FullTokenBytes.CopyTo(tooMuchData);
+
+ // Look like an octet string of the remainder of the payload. Should be ignored.
+ tooMuchData[baseLen] = 0x04;
+ tooMuchData[baseLen + 1] = 28;
+
+ TestParseDocument(tooMuchData, testData, baseLen);
+ }
+
+ private static void TestParseDocument(
+ ReadOnlyMemory<byte> tokenBytes,
+ TimestampTokenTestData testData,
+ int? expectedBytesRead)
+ {
+ int bytesRead;
+ Rfc3161TimestampToken token;
+
+ Assert.True(
+ Rfc3161TimestampToken.TryDecode(tokenBytes, out token, out bytesRead),
+ "Rfc3161TimestampToken.TryDecode");
+
+ if (expectedBytesRead != null)
+ {
+ Assert.Equal(expectedBytesRead.Value, bytesRead);
+ }
+
+ Assert.NotNull(token);
+ TimestampTokenInfoTests.AssertEqual(testData, token.TokenInfo);
+
+ SignedCms signedCms = token.AsSignedCms();
+ Assert.NotNull(signedCms);
+ Assert.Equal(Oids.TstInfo, signedCms.ContentInfo.ContentType.Value);
+
+ Assert.Equal(
+ testData.TokenInfoBytes.ByteArrayToHex(),
+ signedCms.ContentInfo.Content.ByteArrayToHex());
+
+ if (testData.EmbeddedSigningCertificate != null)
+ {
+ Assert.NotNull(signedCms.SignerInfos[0].Certificate);
+
+ Assert.Equal(
+ testData.EmbeddedSigningCertificate.Value.ByteArrayToHex(),
+ signedCms.SignerInfos[0].Certificate.RawData.ByteArrayToHex());
+
+ // Assert.NoThrow
+ signedCms.CheckSignature(true);
+ }
+ else
+ {
+ Assert.Null(signedCms.SignerInfos[0].Certificate);
+
+ using (var signerCert = new X509Certificate2(testData.ExternalCertificateBytes))
+ {
+ // Assert.NoThrow
+ signedCms.CheckSignature(
+ new X509Certificate2Collection(signerCert),
+ true);
+ }
+ }
+
+ X509Certificate2 returnedCert;
+ ReadOnlySpan<byte> messageContentSpan = testData.MessageContent.Span;
+ X509Certificate2Collection candidates = null;
+
+ if (testData.EmbeddedSigningCertificate != null)
+ {
+ Assert.True(
+ token.VerifySignatureForData(messageContentSpan, out returnedCert),
+ "token.VerifySignatureForData(correct)");
+
+ Assert.NotNull(returnedCert);
+ Assert.Equal(signedCms.SignerInfos[0].Certificate, returnedCert);
+ }
+ else
+ {
+ candidates = new X509Certificate2Collection
+ {
+ new X509Certificate2(testData.ExternalCertificateBytes),
+ };
+
+ Assert.False(
+ token.VerifySignatureForData(messageContentSpan, out returnedCert),
+ "token.VerifySignatureForData(correct, no cert)");
+
+ Assert.Null(returnedCert);
+
+ Assert.True(
+ token.VerifySignatureForData(messageContentSpan, out returnedCert, candidates),
+ "token.VerifySignatureForData(correct, certs)");
+
+ Assert.NotNull(returnedCert);
+ Assert.Equal(candidates[0], returnedCert);
+ }
+
+ X509Certificate2 previousCert = returnedCert;
+
+ Assert.False(
+ token.VerifySignatureForData(messageContentSpan.Slice(1), out returnedCert, candidates),
+ "token.VerifySignatureForData(incorrect)");
+
+ Assert.Null(returnedCert);
+
+ byte[] messageHash = testData.HashBytes.ToArray();
+
+ Assert.False(
+ token.VerifySignatureForHash(messageHash, HashAlgorithmName.MD5, out returnedCert, candidates),
+ "token.VerifyHash(correct, MD5)");
+ Assert.Null(returnedCert);
+
+ Assert.False(
+ token.VerifySignatureForHash(messageHash, new Oid(Oids.Md5), out returnedCert, candidates),
+ "token.VerifyHash(correct, Oid(MD5))");
+ Assert.Null(returnedCert);
+
+ Assert.True(
+ token.VerifySignatureForHash(messageHash, new Oid(testData.HashAlgorithmId), out returnedCert, candidates),
+ "token.VerifyHash(correct, Oid(algId))");
+ Assert.NotNull(returnedCert);
+ Assert.Equal(previousCert, returnedCert);
+
+ messageHash[0] ^= 0xFF;
+ Assert.False(
+ token.VerifySignatureForHash(messageHash, new Oid(testData.HashAlgorithmId), out returnedCert, candidates),
+ "token.VerifyHash(incorrect, Oid(algId))");
+ Assert.Null(returnedCert);
+ }
+
+ [Fact]
+ public static void TryDecode_Fails_SignedCmsOfData()
+ {
+ Assert.False(
+ Rfc3161TimestampToken.TryDecode(
+ SignedDocuments.RsaPkcs1OneSignerIssuerAndSerialNumber,
+ out Rfc3161TimestampToken token,
+ out int bytesRead),
+ "Rfc3161TimestampToken.TryDecode");
+
+ Assert.Equal(0, bytesRead);
+ Assert.Null(token);
+ }
+
+ [Fact]
+ public static void TryDecode_Fails_Empty()
+ {
+ Assert.False(
+ Rfc3161TimestampToken.TryDecode(
+ ReadOnlyMemory<byte>.Empty,
+ out Rfc3161TimestampToken token,
+ out int bytesRead),
+ "Rfc3161TimestampToken.TryDecode");
+
+ Assert.Equal(0, bytesRead);
+ Assert.Null(token);
+ }
+
+ [Fact]
+ public static void TryDecode_Fails_EnvelopedCms()
+ {
+ byte[] encodedMessage =
+ ("3082010c06092a864886f70d010703a081fe3081fb0201003181c83081c5020100302e301a311830160603550403130f5253"
+ + "414b65795472616e7366657231021031d935fb63e8cfab48a0bf7b397b67c0300d06092a864886f70d010101050004818013"
+ + "dc0eb2984a445d04a1f6246b8fe41f1d24507548d449d454d5bb5e0638d75ed101bf78c0155a5d208eb746755fbccbc86923"
+ + "8443760a9ae94770d6373e0197be23a6a891f0c522ca96b3e8008bf23547474b7e24e7f32e8134df3862d84f4dea2470548e"
+ + "c774dd74f149a56cdd966e141122900d00ad9d10ea1848541294a1302b06092a864886f70d010701301406082a864886f70d"
+ + "030704089c8119f6cf6b174c8008bcea3a10d0737eb9").HexToByteArray();
+
+ Assert.False(
+ Rfc3161TimestampToken.TryDecode(
+ encodedMessage,
+ out Rfc3161TimestampToken token,
+ out int bytesRead),
+ "Rfc3161TimestampToken.TryDecode");
+
+ Assert.Equal(0, bytesRead);
+ Assert.Null(token);
+ }
+
+ [Fact]
+ public static void TryDecode_Fails_MalformedToken()
+ {
+ ContentInfo contentInfo = new ContentInfo(
+ new Oid(Oids.TstInfo, Oids.TstInfo),
+ new byte[] { 1 });
+
+ SignedCms cms = new SignedCms(contentInfo);
+
+ using (X509Certificate2 cert = Certificates.RSAKeyTransferCapi1.TryGetCertificateWithPrivateKey())
+ {
+ cms.ComputeSignature(new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, cert));
+ }
+
+ Assert.False(
+ Rfc3161TimestampToken.TryDecode(
+ cms.Encode(),
+ out Rfc3161TimestampToken token,
+ out int bytesRead),
+ "Rfc3161TimestampToken.TryDecode");
+
+ Assert.Equal(0, bytesRead);
+ Assert.Null(token);
+ }
+
+ [Theory]
+ [InlineData(X509IncludeOption.WholeChain, SigningCertificateOption.ValidHashNoName)]
+ [InlineData(X509IncludeOption.None, SigningCertificateOption.ValidHashNoName)]
+ [InlineData(X509IncludeOption.WholeChain, SigningCertificateOption.ValidHashWithName)]
+ [InlineData(X509IncludeOption.None, SigningCertificateOption.ValidHashWithName)]
+ public static void MatchV1(X509IncludeOption includeOption, SigningCertificateOption v1Option)
+ {
+ CustomBuild_CertMatch(
+ Certificates.ValidLookingTsaCert,
+ new DateTimeOffset(2018, 1, 10, 17, 21, 11, 802, TimeSpan.Zero),
+ v1Option,
+ SigningCertificateOption.Omit,
+ includeOption: includeOption);
+ }
+
+ [Theory]
+ [InlineData(X509IncludeOption.WholeChain)]
+ [InlineData(X509IncludeOption.None)]
+ public static void CertHashMismatchV1(X509IncludeOption includeOption)
+ {
+ CustomBuild_CertMismatch(
+ Certificates.ValidLookingTsaCert,
+ new DateTimeOffset(2018, 1, 10, 17, 21, 11, 802, TimeSpan.Zero),
+ SigningCertificateOption.InvalidHashNoName,
+ SigningCertificateOption.Omit,
+ includeOption: includeOption);
+ }
+
+ [Theory]
+ [InlineData(
+ X509IncludeOption.WholeChain,
+ SigningCertificateOption.ValidHashWithInvalidName,
+ SubjectIdentifierType.SubjectKeyIdentifier)]
+ [InlineData(
+ X509IncludeOption.None,
+ SigningCertificateOption.ValidHashWithInvalidName,
+ SubjectIdentifierType.SubjectKeyIdentifier)]
+ [InlineData(
+ X509IncludeOption.WholeChain,
+ SigningCertificateOption.ValidHashWithInvalidName,
+ SubjectIdentifierType.IssuerAndSerialNumber)]
+ [InlineData(
+ X509IncludeOption.None,
+ SigningCertificateOption.ValidHashWithInvalidName,
+ SubjectIdentifierType.IssuerAndSerialNumber)]
+ public static void CertMismatchIssuerAndSerialV1(
+ X509IncludeOption includeOption,
+ SigningCertificateOption v1Option,
+ SubjectIdentifierType identifierType)
+ {
+ CustomBuild_CertMismatch(
+ Certificates.ValidLookingTsaCert,
+ new DateTimeOffset(2018, 1, 10, 17, 21, 11, 802, TimeSpan.Zero),
+ v1Option,
+ SigningCertificateOption.Omit,
+ includeOption: includeOption,
+ identifierType: identifierType);
+ }
+
+ [Theory]
+ [InlineData(
+ X509IncludeOption.WholeChain,
+ SigningCertificateOption.ValidHashNoName,
+ null)]
+ [InlineData(
+ X509IncludeOption.None,
+ SigningCertificateOption.ValidHashNoName,
+ null)]
+ [InlineData(
+ X509IncludeOption.WholeChain,
+ SigningCertificateOption.ValidHashWithName,
+ "MD5")]
+ [InlineData(
+ X509IncludeOption.None,
+ SigningCertificateOption.ValidHashWithName,
+ "MD5")]
+ [InlineData(
+ X509IncludeOption.WholeChain,
+ SigningCertificateOption.ValidHashWithName,
+ "SHA1")]
+ [InlineData(
+ X509IncludeOption.None,
+ SigningCertificateOption.ValidHashWithName,
+ "SHA1")]
+ [InlineData(
+ X509IncludeOption.WholeChain,
+ SigningCertificateOption.ValidHashWithName,
+ "SHA384")]
+ [InlineData(
+ X509IncludeOption.None,
+ SigningCertificateOption.ValidHashWithName,
+ "SHA384")]
+ public static void MatchV2(
+ X509IncludeOption includeOption,
+ SigningCertificateOption v2Option,
+ string hashAlgName)
+ {
+ CustomBuild_CertMatch(
+ Certificates.ValidLookingTsaCert,
+ new DateTimeOffset(2018, 1, 10, 17, 21, 11, 802, TimeSpan.Zero),
+ SigningCertificateOption.Omit,
+ v2Option,
+ hashAlgName == null ? default(HashAlgorithmName) : new HashAlgorithmName(hashAlgName),
+ includeOption);
+ }
+
+ [Theory]
+ [InlineData(X509IncludeOption.WholeChain, null)]
+ [InlineData(X509IncludeOption.None, null)]
+ [InlineData(X509IncludeOption.WholeChain, "MD5")]
+ [InlineData(X509IncludeOption.None, "MD5")]
+ [InlineData(X509IncludeOption.WholeChain, "SHA1")]
+ [InlineData(X509IncludeOption.None, "SHA1")]
+ [InlineData(X509IncludeOption.WholeChain, "SHA384")]
+ [InlineData(X509IncludeOption.None, "SHA384")]
+ public static void CertHashMismatchV2(X509IncludeOption includeOption, string hashAlgName)
+ {
+ CustomBuild_CertMismatch(
+ Certificates.ValidLookingTsaCert,
+ new DateTimeOffset(2018, 1, 10, 17, 21, 11, 802, TimeSpan.Zero),
+ SigningCertificateOption.Omit,
+ SigningCertificateOption.InvalidHashNoName,
+ hashAlgName == null ? default(HashAlgorithmName) : new HashAlgorithmName(hashAlgName),
+ includeOption: includeOption);
+ }
+
+ [Theory]
+ [InlineData(
+ X509IncludeOption.WholeChain,
+ SigningCertificateOption.ValidHashWithInvalidName,
+ SubjectIdentifierType.SubjectKeyIdentifier,
+ null)]
+ [InlineData(
+ X509IncludeOption.None,
+ SigningCertificateOption.ValidHashWithInvalidName,
+ SubjectIdentifierType.SubjectKeyIdentifier,
+ null)]
+ [InlineData(
+ X509IncludeOption.WholeChain,
+ SigningCertificateOption.ValidHashWithInvalidName,
+ SubjectIdentifierType.SubjectKeyIdentifier,
+ "SHA384")]
+ [InlineData(
+ X509IncludeOption.None,
+ SigningCertificateOption.ValidHashWithInvalidName,
+ SubjectIdentifierType.SubjectKeyIdentifier,
+ "SHA384")]
+ [InlineData(
+ X509IncludeOption.WholeChain,
+ SigningCertificateOption.ValidHashWithInvalidName,
+ SubjectIdentifierType.IssuerAndSerialNumber,
+ null)]
+ [InlineData(
+ X509IncludeOption.None,
+ SigningCertificateOption.ValidHashWithInvalidName,
+ SubjectIdentifierType.IssuerAndSerialNumber,
+ null)]
+ [InlineData(
+ X509IncludeOption.WholeChain,
+ SigningCertificateOption.ValidHashWithInvalidName,
+ SubjectIdentifierType.IssuerAndSerialNumber,
+ "SHA384")]
+ [InlineData(
+ X509IncludeOption.None,
+ SigningCertificateOption.ValidHashWithInvalidName,
+ SubjectIdentifierType.IssuerAndSerialNumber,
+ "SHA384")]
+ public static void CertMismatchIssuerAndSerialV2(
+ X509IncludeOption includeOption,
+ SigningCertificateOption v2Option,
+ SubjectIdentifierType identifierType,
+ string hashAlgName)
+ {
+ CustomBuild_CertMismatch(
+ Certificates.ValidLookingTsaCert,
+ new DateTimeOffset(2018, 1, 10, 17, 21, 11, 802, TimeSpan.Zero),
+ SigningCertificateOption.Omit,
+ v2Option,
+ hashAlgName == null ? default(HashAlgorithmName) : new HashAlgorithmName(hashAlgName),
+ includeOption: includeOption,
+ identifierType: identifierType);
+ }
+
+ [Theory]
+ [InlineData(
+ X509IncludeOption.WholeChain,
+ SigningCertificateOption.ValidHashNoName,
+ SigningCertificateOption.ValidHashNoName,
+ null)]
+ [InlineData(
+ X509IncludeOption.WholeChain,
+ SigningCertificateOption.ValidHashNoName,
+ SigningCertificateOption.ValidHashNoName,
+ "SHA512")]
+ [InlineData(
+ X509IncludeOption.None,
+ SigningCertificateOption.ValidHashNoName,
+ SigningCertificateOption.ValidHashNoName,
+ null)]
+ [InlineData(
+ X509IncludeOption.None,
+ SigningCertificateOption.ValidHashNoName,
+ SigningCertificateOption.ValidHashNoName,
+ "SHA512")]
+ [InlineData(
+ X509IncludeOption.WholeChain,
+ SigningCertificateOption.ValidHashNoName,
+ SigningCertificateOption.ValidHashWithName,
+ null)]
+ [InlineData(
+ X509IncludeOption.WholeChain,
+ SigningCertificateOption.ValidHashNoName,
+ SigningCertificateOption.ValidHashWithName,
+ "SHA384")]
+ [InlineData(
+ X509IncludeOption.None,
+ SigningCertificateOption.ValidHashNoName,
+ SigningCertificateOption.ValidHashWithName,
+ null)]
+ [InlineData(
+ X509IncludeOption.None,
+ SigningCertificateOption.ValidHashNoName,
+ SigningCertificateOption.ValidHashWithName,
+ "SHA384")]
+ [InlineData(
+ X509IncludeOption.WholeChain,
+ SigningCertificateOption.ValidHashWithName,
+ SigningCertificateOption.ValidHashNoName,
+ null)]
+ [InlineData(
+ X509IncludeOption.WholeChain,
+ SigningCertificateOption.ValidHashWithName,
+ SigningCertificateOption.ValidHashNoName,
+ "SHA512")]
+ [InlineData(
+ X509IncludeOption.None,
+ SigningCertificateOption.ValidHashWithName,
+ SigningCertificateOption.ValidHashNoName,
+ null)]
+ [InlineData(
+ X509IncludeOption.None,
+ SigningCertificateOption.ValidHashWithName,
+ SigningCertificateOption.ValidHashNoName,
+ "SHA512")]
+ [InlineData(
+ X509IncludeOption.WholeChain,
+ SigningCertificateOption.ValidHashWithName,
+ SigningCertificateOption.ValidHashWithName,
+ null)]
+ [InlineData(
+ X509IncludeOption.WholeChain,
+ SigningCertificateOption.ValidHashWithName,
+ SigningCertificateOption.ValidHashWithName,
+ "SHA384")]
+ [InlineData(
+ X509IncludeOption.None,
+ SigningCertificateOption.ValidHashWithName,
+ SigningCertificateOption.ValidHashWithName,
+ null)]
+ [InlineData(
+ X509IncludeOption.None,
+ SigningCertificateOption.ValidHashWithName,
+ SigningCertificateOption.ValidHashWithName,
+ "SHA384")]
+ public static void CertMatchV1AndV2(
+ X509IncludeOption includeOption,
+ SigningCertificateOption v1Option,
+ SigningCertificateOption v2Option,
+ string hashAlgName)
+ {
+ CustomBuild_CertMatch(
+ Certificates.ValidLookingTsaCert,
+ new DateTimeOffset(2018, 1, 10, 17, 21, 11, 802, TimeSpan.Zero),
+ v1Option,
+ v2Option,
+ hashAlgName == null ? default(HashAlgorithmName) : new HashAlgorithmName(hashAlgName),
+ includeOption);
+ }
+
+ [Theory]
+ [InlineData(
+ X509IncludeOption.None,
+ SigningCertificateOption.InvalidHashNoName,
+ SigningCertificateOption.ValidHashWithName,
+ SubjectIdentifierType.IssuerAndSerialNumber,
+ null)]
+ [InlineData(
+ X509IncludeOption.WholeChain,
+ SigningCertificateOption.ValidHashWithInvalidSerial,
+ SigningCertificateOption.ValidHashWithName,
+ SubjectIdentifierType.IssuerAndSerialNumber,
+ "SHA384")]
+ [InlineData(
+ X509IncludeOption.WholeChain,
+ SigningCertificateOption.ValidHashWithInvalidName,
+ SigningCertificateOption.InvalidHashNoName,
+ SubjectIdentifierType.SubjectKeyIdentifier,
+ null)]
+ [InlineData(
+ X509IncludeOption.None,
+ SigningCertificateOption.ValidHashWithName,
+ SigningCertificateOption.InvalidHashNoName,
+ SubjectIdentifierType.SubjectKeyIdentifier,
+ "SHA512")]
+ [InlineData(
+ X509IncludeOption.WholeChain,
+ SigningCertificateOption.InvalidHashWithInvalidSerial,
+ SigningCertificateOption.ValidHashNoName,
+ SubjectIdentifierType.IssuerAndSerialNumber,
+ null)]
+ public static void CertMismatchV1OrV2(
+ X509IncludeOption includeOption,
+ SigningCertificateOption v1Option,
+ SigningCertificateOption v2Option,
+ SubjectIdentifierType identifierType,
+ string hashAlgName)
+ {
+ CustomBuild_CertMismatch(
+ Certificates.ValidLookingTsaCert,
+ new DateTimeOffset(2018, 1, 10, 17, 21, 11, 802, TimeSpan.Zero),
+ v1Option,
+ v2Option,
+ hashAlgName == null ? default(HashAlgorithmName) : new HashAlgorithmName(hashAlgName),
+ includeOption: includeOption,
+ identifierType: identifierType);
+ }
+
+ [Theory]
+ [InlineData(X509IncludeOption.WholeChain)]
+ [InlineData(X509IncludeOption.None)]
+ public static void TimestampTooOld(X509IncludeOption includeOption)
+ {
+ CertLoader loader = Certificates.ValidLookingTsaCert;
+ DateTimeOffset referenceTime;
+
+ using (X509Certificate2 cert = loader.GetCertificate())
+ {
+ referenceTime = cert.NotBefore.AddSeconds(-1);
+ }
+
+ CustomBuild_CertMismatch(
+ loader,
+ referenceTime,
+ SigningCertificateOption.ValidHashNoName,
+ SigningCertificateOption.Omit,
+ includeOption: includeOption);
+ }
+
+ [Theory]
+ [InlineData(X509IncludeOption.WholeChain)]
+ [InlineData(X509IncludeOption.None)]
+ public static void TimestampTooNew(X509IncludeOption includeOption)
+ {
+ CertLoader loader = Certificates.ValidLookingTsaCert;
+ DateTimeOffset referenceTime;
+
+ using (X509Certificate2 cert = loader.GetCertificate())
+ {
+ referenceTime = cert.NotAfter.AddSeconds(1);
+ }
+
+ CustomBuild_CertMismatch(
+ loader,
+ referenceTime,
+ SigningCertificateOption.ValidHashNoName,
+ SigningCertificateOption.Omit,
+ includeOption: includeOption);
+ }
+
+ [Theory]
+ [InlineData(X509IncludeOption.WholeChain)]
+ [InlineData(X509IncludeOption.None)]
+ public static void NoEkuExtension(X509IncludeOption includeOption)
+ {
+ CertLoader loader = Certificates.RSA2048SignatureOnly;
+ DateTimeOffset referenceTime;
+
+ using (X509Certificate2 cert = loader.GetCertificate())
+ {
+ referenceTime = cert.NotAfter.AddDays(-1);
+
+ Assert.Equal(0, cert.Extensions.OfType<X509EnhancedKeyUsageExtension>().Count());
+ }
+
+ CustomBuild_CertMismatch(
+ loader,
+ referenceTime,
+ SigningCertificateOption.ValidHashNoName,
+ SigningCertificateOption.Omit,
+ includeOption: includeOption);
+ }
+
+ [Theory]
+ [InlineData(X509IncludeOption.WholeChain)]
+ [InlineData(X509IncludeOption.None)]
+ public static void TwoEkuExtensions(X509IncludeOption includeOption)
+ {
+ CertLoader loader = Certificates.TwoEkuTsaCert;
+ DateTimeOffset referenceTime;
+
+ using (X509Certificate2 cert = loader.GetCertificate())
+ {
+ referenceTime = cert.NotAfter.AddDays(-1);
+
+ var ekuExts = cert.Extensions.OfType<X509EnhancedKeyUsageExtension>().ToList();
+
+ Assert.Equal(2, ekuExts.Count);
+
+ // Make sure we're validating that "early success" doesn't happen.
+ Assert.Contains(
+ Oids.TimeStampingPurpose,
+ ekuExts[0].EnhancedKeyUsages.OfType<Oid>().Select(o => o.Value));
+ }
+
+ CustomBuild_CertMismatch(
+ loader,
+ referenceTime,
+ SigningCertificateOption.ValidHashNoName,
+ SigningCertificateOption.Omit,
+ includeOption: includeOption);
+ }
+
+ [Theory]
+ [InlineData(X509IncludeOption.WholeChain)]
+ [InlineData(X509IncludeOption.None)]
+ public static void NonCriticalEkuExtension(X509IncludeOption includeOption)
+ {
+ CertLoader loader = Certificates.NonCriticalTsaEku;
+ DateTimeOffset referenceTime;
+
+ using (X509Certificate2 cert = loader.GetCertificate())
+ {
+ referenceTime = cert.NotAfter.AddDays(-1);
+
+ var ekuExts = cert.Extensions.OfType<X509EnhancedKeyUsageExtension>().ToList();
+
+ Assert.Equal(1, ekuExts.Count);
+ Assert.False(ekuExts[0].Critical, "ekuExts[0].Critical");
+ }
+
+ CustomBuild_CertMismatch(
+ loader,
+ referenceTime,
+ SigningCertificateOption.ValidHashNoName,
+ SigningCertificateOption.Omit,
+ includeOption: includeOption);
+ }
+
+ [Theory]
+ [InlineData(X509IncludeOption.WholeChain)]
+ [InlineData(X509IncludeOption.None)]
+ public static void NoTsaEku(X509IncludeOption includeOption)
+ {
+ CertLoader loader = Certificates.TlsClientServerCert;
+ DateTimeOffset referenceTime;
+
+ using (X509Certificate2 cert = loader.GetCertificate())
+ {
+ referenceTime = cert.NotAfter.AddDays(-1);
+ }
+
+ CustomBuild_CertMismatch(
+ loader,
+ referenceTime,
+ SigningCertificateOption.ValidHashNoName,
+ SigningCertificateOption.Omit,
+ includeOption: includeOption);
+ }
+
+ private static void CustomBuild_CertMatch(
+ CertLoader loader,
+ DateTimeOffset referenceTime,
+ SigningCertificateOption v1Option,
+ SigningCertificateOption v2Option,
+ HashAlgorithmName v2AlgorithmName = default,
+ X509IncludeOption includeOption = default,
+ SubjectIdentifierType identifierType = SubjectIdentifierType.IssuerAndSerialNumber)
+ {
+ byte[] tokenBytes = BuildCustomToken(
+ loader,
+ referenceTime,
+ v1Option,
+ v2Option,
+ v2AlgorithmName,
+ includeOption,
+ identifierType);
+
+ Rfc3161TimestampToken token;
+ Assert.True(Rfc3161TimestampToken.TryDecode(tokenBytes, out token, out int bytesRead));
+
+ Assert.Equal(tokenBytes.Length, bytesRead);
+ Assert.NotNull(token);
+
+ Assert.Equal(referenceTime, token.TokenInfo.Timestamp);
+
+ using (X509Certificate2 cert = Certificates.ValidLookingTsaCert.GetCertificate())
+ {
+ Assert.True(
+ token.VerifySignatureForHash(
+ token.TokenInfo.GetMessageHash().Span,
+ token.TokenInfo.HashAlgorithmId,
+ out X509Certificate2 signer,
+ new X509Certificate2Collection(cert)));
+
+ Assert.Equal(cert, signer);
+ }
+ }
+
+ private static void CustomBuild_CertMismatch(
+ CertLoader loader,
+ DateTimeOffset referenceTime,
+ SigningCertificateOption v1Option,
+ SigningCertificateOption v2Option,
+ HashAlgorithmName v2AlgorithmName = default,
+ X509IncludeOption includeOption = default,
+ SubjectIdentifierType identifierType = SubjectIdentifierType.IssuerAndSerialNumber)
+ {
+ byte[] tokenBytes = BuildCustomToken(
+ loader,
+ referenceTime,
+ v1Option,
+ v2Option,
+ v2AlgorithmName,
+ includeOption,
+ identifierType);
+
+ Rfc3161TimestampToken token;
+
+ bool willParse = includeOption == X509IncludeOption.None;
+
+ if (willParse && identifierType == SubjectIdentifierType.IssuerAndSerialNumber)
+ {
+ // Because IASN matches against the ESSCertId(V2) directly it will reject the token.
+
+ switch (v1Option)
+ {
+ case SigningCertificateOption.ValidHashWithInvalidName:
+ case SigningCertificateOption.ValidHashWithInvalidSerial:
+ case SigningCertificateOption.InvalidHashWithInvalidName:
+ case SigningCertificateOption.InvalidHashWithInvalidSerial:
+ willParse = false;
+ break;
+ }
+
+ switch (v2Option)
+ {
+ case SigningCertificateOption.ValidHashWithInvalidName:
+ case SigningCertificateOption.ValidHashWithInvalidSerial:
+ case SigningCertificateOption.InvalidHashWithInvalidName:
+ case SigningCertificateOption.InvalidHashWithInvalidSerial:
+ willParse = false;
+ break;
+ }
+ }
+
+ if (willParse)
+ {
+ Assert.True(Rfc3161TimestampToken.TryDecode(tokenBytes, out token, out int bytesRead));
+ Assert.NotNull(token);
+ Assert.Equal(tokenBytes.Length, bytesRead);
+
+ using (X509Certificate2 cert = loader.GetCertificate())
+ {
+ Assert.False(
+ token.VerifySignatureForHash(
+ token.TokenInfo.GetMessageHash().Span,
+ token.TokenInfo.HashAlgorithmId,
+ out X509Certificate2 signer,
+ new X509Certificate2Collection(cert)));
+
+ Assert.Null(signer);
+ }
+ }
+ else
+ {
+ Assert.False(Rfc3161TimestampToken.TryDecode(tokenBytes, out token, out int bytesRead));
+
+ Assert.Null(token);
+ Assert.Equal(0, bytesRead);
+ }
+ }
+
+ private static byte[] BuildCustomToken(
+ CertLoader cert,
+ DateTimeOffset timestamp,
+ SigningCertificateOption v1Option,
+ SigningCertificateOption v2Option,
+ HashAlgorithmName v2DigestAlg=default,
+ X509IncludeOption includeOption=X509IncludeOption.ExcludeRoot,
+ SubjectIdentifierType identifierType=SubjectIdentifierType.IssuerAndSerialNumber)
+ {
+ long accuracyMicroSeconds = (long)(TimeSpan.FromMinutes(1).TotalMilliseconds * 1000);
+
+ byte[] serialNumber = BitConverter.GetBytes(DateTimeOffset.UtcNow.Ticks);
+ Array.Reverse(serialNumber);
+
+ Rfc3161TimestampTokenInfo info = new Rfc3161TimestampTokenInfo(
+ new Oid("0.0", "0.0"),
+ new Oid(Oids.Sha384),
+ new byte[384 / 8],
+ serialNumber,
+ timestamp,
+ accuracyMicroSeconds,
+ isOrdering: true);
+
+ ContentInfo contentInfo = new ContentInfo(new Oid(Oids.TstInfo, Oids.TstInfo), info.Encode());
+ SignedCms cms = new SignedCms(contentInfo);
+
+ using (X509Certificate2 tsaCert = cert.TryGetCertificateWithPrivateKey())
+ {
+ CmsSigner signer = new CmsSigner(identifierType, tsaCert)
+ {
+ IncludeOption = includeOption
+ };
+
+ if (v1Option != SigningCertificateOption.Omit)
+ {
+ ExpandOption(v1Option, out bool validHash, out bool skipIssuerSerial, out bool validName, out bool validSerial);
+
+ // simple SigningCertificate
+ byte[] signingCertificateV1Bytes =
+ "301A3018301604140000000000000000000000000000000000000000".HexToByteArray();
+
+ if (validHash)
+ {
+ using (SHA1 hasher = SHA1.Create())
+ {
+ byte[] hash = hasher.ComputeHash(tsaCert.RawData);
+
+ Buffer.BlockCopy(
+ hash,
+ 0,
+ signingCertificateV1Bytes,
+ signingCertificateV1Bytes.Length - hash.Length,
+ hash.Length);
+ }
+ }
+
+ if (!skipIssuerSerial)
+ {
+ byte[] footer = BuildIssuerAndSerialNumber(tsaCert, validName, validSerial);
+
+ signingCertificateV1Bytes[1] += (byte)footer.Length;
+ signingCertificateV1Bytes[3] += (byte)footer.Length;
+ signingCertificateV1Bytes[5] += (byte)footer.Length;
+
+ Assert.InRange(signingCertificateV1Bytes[1], 0, 127);
+
+ signingCertificateV1Bytes = signingCertificateV1Bytes.Concat(footer).ToArray();
+ }
+
+ signer.SignedAttributes.Add(
+ new AsnEncodedData("1.2.840.113549.1.9.16.2.12", signingCertificateV1Bytes));
+ }
+
+ if (v2Option != SigningCertificateOption.Omit)
+ {
+ byte[] attrBytes;
+ byte[] algBytes = Array.Empty<byte>();
+ byte[] hashBytes;
+ byte[] issuerNameBytes = Array.Empty<byte>();
+
+ if (v2DigestAlg != default)
+ {
+ switch (v2DigestAlg.Name)
+ {
+ case "MD5":
+ algBytes = "300C06082A864886F70D02050500".HexToByteArray();
+ break;
+ case "SHA1":
+ algBytes = "300906052B0E03021A0500".HexToByteArray();
+ break;
+ case "SHA256":
+ // Invalid under DER, because it's the default.
+ algBytes = "300D06096086480165030402010500".HexToByteArray();
+ break;
+ case "SHA384":
+ algBytes = "300D06096086480165030402020500".HexToByteArray();
+ break;
+ case "SHA512":
+ algBytes = "300D06096086480165030402030500".HexToByteArray();
+ break;
+ default:
+ throw new NotSupportedException(v2DigestAlg.Name);
+ }
+ }
+ else
+ {
+ v2DigestAlg = HashAlgorithmName.SHA256;
+ }
+
+ hashBytes = tsaCert.GetCertHash(v2DigestAlg);
+
+ ExpandOption(v2Option, out bool validHash, out bool skipIssuerSerial, out bool validName, out bool validSerial);
+
+ if (!validHash)
+ {
+ hashBytes[0] ^= 0xFF;
+ }
+
+ if (!skipIssuerSerial)
+ {
+ issuerNameBytes = BuildIssuerAndSerialNumber(tsaCert, validName, validSerial);
+ }
+
+ // hashBytes hasn't been wrapped in an OCTET STRING yet, so add 2 more.
+ int payloadSize = algBytes.Length + hashBytes.Length + issuerNameBytes.Length + 2;
+ Assert.InRange(payloadSize, 0, 123);
+
+ attrBytes = new byte[payloadSize + 6];
+
+ int index = 0;
+
+ // SEQUENCE (SigningCertificateV2)
+ attrBytes[index++] = 0x30;
+ attrBytes[index++] = (byte)(payloadSize + 4);
+
+ // SEQUENCE OF => certs
+ attrBytes[index++] = 0x30;
+ attrBytes[index++] = (byte)(payloadSize + 2);
+
+ // SEQUENCE (ESSCertIdV2)
+ attrBytes[index++] = 0x30;
+ attrBytes[index++] = (byte)payloadSize;
+
+ Buffer.BlockCopy(algBytes, 0, attrBytes, index, algBytes.Length);
+ index += algBytes.Length;
+
+ // OCTET STRING (Hash)
+ attrBytes[index++] = 0x04;
+ attrBytes[index++] = (byte)hashBytes.Length;
+ Buffer.BlockCopy(hashBytes, 0, attrBytes, index, hashBytes.Length);
+ index += hashBytes.Length;
+
+ Buffer.BlockCopy(issuerNameBytes, 0, attrBytes, index, issuerNameBytes.Length);
+
+ signer.SignedAttributes.Add(
+ new AsnEncodedData("1.2.840.113549.1.9.16.2.47", attrBytes));
+ }
+
+ cms.ComputeSignature(signer);
+ }
+
+ return cms.Encode();
+ }
+
+ private static byte[] BuildIssuerAndSerialNumber(X509Certificate2 tsaCert, bool validName, bool validSerial)
+ {
+ byte[] issuerNameBytes;
+
+ if (validName)
+ {
+ issuerNameBytes = tsaCert.IssuerName.RawData;
+ }
+ else
+ {
+ issuerNameBytes = new X500DistinguishedName("CN=No Match").RawData;
+ }
+
+ byte[] serialBytes = tsaCert.GetSerialNumber();
+
+ if (validSerial)
+ {
+ Array.Reverse(serialBytes);
+ }
+ else
+ {
+ // If the byte sequence was a palindrome it's still a match,
+ // so flip some bits.
+ serialBytes[0] ^= 0x7F;
+ }
+
+ if (issuerNameBytes.Length + serialBytes.Length > 80)
+ {
+ throw new NotSupportedException(
+ "Issuer name and serial length are bigger than this code can handle");
+ }
+
+ // SEQUENCE
+ // SEQUENCE
+ // CONTEXT-SPECIFIC 4
+ // [IssuerName]
+ // INTEGER
+ // [SerialNumber, big endian]
+
+ byte[] issuerAndSerialNumber = new byte[issuerNameBytes.Length + serialBytes.Length + 8];
+ issuerAndSerialNumber[0] = 0x30;
+ issuerAndSerialNumber[1] = (byte)(issuerAndSerialNumber.Length - 2);
+
+ issuerAndSerialNumber[2] = 0x30;
+ issuerAndSerialNumber[3] = (byte)(issuerNameBytes.Length + 2);
+
+ issuerAndSerialNumber[4] = 0xA4;
+ issuerAndSerialNumber[5] = (byte)(issuerNameBytes.Length);
+ Buffer.BlockCopy(issuerNameBytes, 0, issuerAndSerialNumber, 6, issuerNameBytes.Length);
+
+ issuerAndSerialNumber[issuerNameBytes.Length + 6] = 0x02;
+ issuerAndSerialNumber[issuerNameBytes.Length + 7] = (byte)serialBytes.Length;
+ Buffer.BlockCopy(serialBytes, 0, issuerAndSerialNumber, issuerNameBytes.Length + 8, serialBytes.Length);
+
+ return issuerAndSerialNumber;
+ }
+
+ private static void ExpandOption(
+ SigningCertificateOption option,
+ out bool validHash,
+ out bool skipIssuerSerial,
+ out bool validName,
+ out bool validSerial)
+ {
+ Assert.NotEqual(SigningCertificateOption.Omit, option);
+
+ validHash = option < SigningCertificateOption.InvalidHashNoName;
+
+ skipIssuerSerial =
+ option == SigningCertificateOption.ValidHashNoName ||
+ option == SigningCertificateOption.InvalidHashNoName;
+
+ if (skipIssuerSerial)
+ {
+ validName = validSerial = false;
+ }
+ else
+ {
+ validName =
+ option == SigningCertificateOption.ValidHashWithName ||
+ option == SigningCertificateOption.InvalidHashWithName ||
+ option == SigningCertificateOption.ValidHashWithInvalidSerial ||
+ option == SigningCertificateOption.InvalidHashWithInvalidSerial;
+
+ validSerial =
+ option == SigningCertificateOption.ValidHashWithName ||
+ option == SigningCertificateOption.InvalidHashWithName ||
+ option == SigningCertificateOption.ValidHashWithInvalidName ||
+ option == SigningCertificateOption.InvalidHashWithInvalidName;
+ }
+ }
+
+ public enum SigningCertificateOption
+ {
+ Omit,
+ ValidHashNoName,
+ ValidHashWithName,
+ ValidHashWithInvalidName,
+ ValidHashWithInvalidSerial,
+ InvalidHashNoName,
+ InvalidHashWithName,
+ InvalidHashWithInvalidName,
+ InvalidHashWithInvalidSerial,
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.cs b/src/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.cs
index 4d131a5ea8..22e84fcd5f 100644
--- a/src/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.cs
+++ b/src/System.Security.Cryptography.Pkcs/tests/SignedCms/SignedCmsTests.cs
@@ -204,7 +204,7 @@ namespace System.Security.Cryptography.Pkcs.Tests
{
byte[] basis = SignedDocuments.RsaPkcs1OneSignerIssuerAndSerialNumber;
byte[] data = new byte[basis.Length + 60];
- data.AsSpan().Slice(basis.Length).Fill(0x5E);
+ data.AsSpan(basis.Length).Fill(0x5E);
basis.AsSpan().CopyTo(data);
SignedCms cms = new SignedCms();
diff --git a/src/System.Security.Cryptography.Pkcs/tests/System.Security.Cryptography.Pkcs.Tests.csproj b/src/System.Security.Cryptography.Pkcs/tests/System.Security.Cryptography.Pkcs.Tests.csproj
index b5edb59ea4..d54ffe3590 100644
--- a/src/System.Security.Cryptography.Pkcs/tests/System.Security.Cryptography.Pkcs.Tests.csproj
+++ b/src/System.Security.Cryptography.Pkcs/tests/System.Security.Cryptography.Pkcs.Tests.csproj
@@ -24,16 +24,6 @@
<Compile Include="CertLoader.Settings.cs" />
<Compile Include="CmsRecipientCollectionTests.cs" />
<Compile Include="CryptographicAttributeObjectCollectionTests.cs" />
- <Compile Include="Oids.cs" />
- <Compile Include="Pkcs9AttributeTests.cs" />
- <Compile Include="SignedCms\CounterSigningDerOrder.cs" />
- <Compile Include="SignedCms\SignedCmsTests.cs" />
- <Compile Include="SignedCms\SignedCmsWholeDocumentTests.cs" />
- <Compile Include="SignedCms\SignedDocuments.cs" />
- <Compile Include="SignedCms\SignerInfoTests.cs" />
- </ItemGroup>
- <ItemGroup Condition="'$(TargetsWindows)' == 'true'">
- <Compile Include="RecipientInfoCollectionTests.cs" />
<Compile Include="EnvelopedCms\CertificateTests.cs" />
<Compile Include="EnvelopedCms\ContentEncryptionAlgorithmTests.cs" />
<Compile Include="EnvelopedCms\DecryptTests.cs" />
@@ -43,6 +33,20 @@
<Compile Include="EnvelopedCms\KeyTransRecipientInfoTests.cs" />
<Compile Include="EnvelopedCms\StateTests.cs" />
<Compile Include="EnvelopedCms\UnprotectedAttributeTests.cs" />
+ <Compile Include="Oids.cs" />
+ <Compile Include="Pkcs9AttributeTests.cs" />
+ <Compile Include="RecipientInfoCollectionTests.cs" />
+ <Compile Include="SignedCms\CounterSigningDerOrder.cs" />
+ <Compile Include="SignedCms\SignedCmsTests.cs" />
+ <Compile Include="SignedCms\SignedCmsWholeDocumentTests.cs" />
+ <Compile Include="SignedCms\SignedDocuments.cs" />
+ <Compile Include="SignedCms\SignerInfoTests.cs" />
+ </ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp'">
+ <Compile Include="Rfc3161\TimestampRequestTests.cs" />
+ <Compile Include="Rfc3161\TimestampTokenInfoTests.cs" />
+ <Compile Include="Rfc3161\TimestampTokenTestData.cs" />
+ <Compile Include="Rfc3161\TimestampTokenTests.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetsWindows)' == 'true' AND '$(TargetGroup)'=='netcoreapp'">
<Compile Include="EnvelopedCms\DecryptTests.KeyPersistence.cs" />
diff --git a/src/System.Security.Cryptography.Primitives/System.Security.Cryptography.Primitives.sln b/src/System.Security.Cryptography.Primitives/System.Security.Cryptography.Primitives.sln
index c90a901aea..4eb045691a 100644
--- a/src/System.Security.Cryptography.Primitives/System.Security.Cryptography.Primitives.sln
+++ b/src/System.Security.Cryptography.Primitives/System.Security.Cryptography.Primitives.sln
@@ -7,6 +7,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Security.Cryptograph
{DF73E985-E143-4BF5-9FA4-E199E7D36235} = {DF73E985-E143-4BF5-9FA4-E199E7D36235}
EndProjectSection
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Security.Cryptography.Primitives.Performance.Tests", "tests\Performance\System.Security.Cryptography.Primitives.Performance.Tests.csproj", "{FB3EA273-567D-414F-B36D-3698BE8D198B}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DF73E985-E143-4BF5-9FA4-E199E7D36235} = {DF73E985-E143-4BF5-9FA4-E199E7D36235}
+ EndProjectSection
+EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Security.Cryptography.Primitives", "src\System.Security.Cryptography.Primitives.csproj", "{DF73E985-E143-4BF5-9FA4-E199E7D36235}"
ProjectSection(ProjectDependencies) = postProject
{F050C895-297F-41C6-98C3-406D791AD515} = {F050C895-297F-41C6-98C3-406D791AD515}
@@ -30,6 +35,10 @@ Global
{101EB757-55A4-4F48-841C-C088640B8F57}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
{101EB757-55A4-4F48-841C-C088640B8F57}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
{101EB757-55A4-4F48-841C-C088640B8F57}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
+ {FB3EA273-567D-414F-B36D-3698BE8D198B}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
+ {FB3EA273-567D-414F-B36D-3698BE8D198B}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
+ {FB3EA273-567D-414F-B36D-3698BE8D198B}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
+ {FB3EA273-567D-414F-B36D-3698BE8D198B}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
{DF73E985-E143-4BF5-9FA4-E199E7D36235}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
{DF73E985-E143-4BF5-9FA4-E199E7D36235}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
{DF73E985-E143-4BF5-9FA4-E199E7D36235}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
@@ -44,6 +53,7 @@ Global
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{101EB757-55A4-4F48-841C-C088640B8F57} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
+ {FB3EA273-567D-414F-B36D-3698BE8D198B} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
{DF73E985-E143-4BF5-9FA4-E199E7D36235} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD}
{F050C895-297F-41C6-98C3-406D791AD515} = {2E666815-2EDB-464B-9DF6-380BF4789AD4}
EndGlobalSection
diff --git a/src/System.Security.Cryptography.Primitives/ref/System.Security.Cryptography.Primitives.cs b/src/System.Security.Cryptography.Primitives/ref/System.Security.Cryptography.Primitives.cs
index 73d5d1e6bb..7b4ff0b492 100644
--- a/src/System.Security.Cryptography.Primitives/ref/System.Security.Cryptography.Primitives.cs
+++ b/src/System.Security.Cryptography.Primitives/ref/System.Security.Cryptography.Primitives.cs
@@ -36,6 +36,11 @@ namespace System.Security.Cryptography
[System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
OFB = 3,
}
+ public static partial class CryptographicOperations
+ {
+ public static bool FixedTimeEquals(System.ReadOnlySpan<byte> left, System.ReadOnlySpan<byte> right) => throw null;
+ public static void ZeroMemory(System.Span<byte> buffer) => throw null;
+ }
public partial class CryptographicUnexpectedOperationException : System.Security.Cryptography.CryptographicException
{
public CryptographicUnexpectedOperationException() { }
diff --git a/src/System.Security.Cryptography.Primitives/ref/System.Security.Cryptography.Primitives.csproj b/src/System.Security.Cryptography.Primitives/ref/System.Security.Cryptography.Primitives.csproj
index 1051a19615..abf8101d36 100644
--- a/src/System.Security.Cryptography.Primitives/ref/System.Security.Cryptography.Primitives.csproj
+++ b/src/System.Security.Cryptography.Primitives/ref/System.Security.Cryptography.Primitives.csproj
@@ -17,4 +17,4 @@
<ProjectReference Include="..\..\System.Threading.Tasks\ref\System.Threading.Tasks.csproj" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Security.Cryptography.Primitives/src/Resources/Strings.resx b/src/System.Security.Cryptography.Primitives/src/Resources/Strings.resx
index c6b046c2e2..0f9c473cb2 100644
--- a/src/System.Security.Cryptography.Primitives/src/Resources/Strings.resx
+++ b/src/System.Security.Cryptography.Primitives/src/Resources/Strings.resx
@@ -79,6 +79,9 @@
<data name="Cryptography_CryptoStream_FlushFinalBlockTwice" xml:space="preserve">
<value>FlushFinalBlock() method was called twice on a CryptoStream. It can only be called once.</value>
</data>
+ <data name="Cryptography_DefaultAlgorithm_NotSupported" xml:space="preserve">
+ <value>This platform does not allow the automatic selection of an algorithm.</value>
+ </data>
<data name="Cryptography_HashNotYetFinalized" xml:space="preserve">
<value>Hash must be finalized before the hash value is retrieved.</value>
</data>
diff --git a/src/System.Security.Cryptography.Primitives/src/System.Security.Cryptography.Primitives.csproj b/src/System.Security.Cryptography.Primitives/src/System.Security.Cryptography.Primitives.csproj
index 042b0a1d36..5e37c26e65 100644
--- a/src/System.Security.Cryptography.Primitives/src/System.Security.Cryptography.Primitives.csproj
+++ b/src/System.Security.Cryptography.Primitives/src/System.Security.Cryptography.Primitives.csproj
@@ -13,6 +13,8 @@
<ItemGroup>
<Compile Include="System\Security\Cryptography\AsymmetricAlgorithm.cs" />
<Compile Include="System\Security\Cryptography\CipherMode.cs" />
+ <Compile Include="System\Security\Cryptography\CryptoConfigForwarder.cs" />
+ <Compile Include="System\Security\Cryptography\CryptographicOperations.cs" />
<Compile Include="System\Security\Cryptography\CryptographicUnexpectedOperationException.cs" />
<Compile Include="System\Security\Cryptography\CryptoStream.cs" />
<Compile Include="System\Security\Cryptography\CryptoStreamMode.cs" />
diff --git a/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/AsymmetricAlgorithm.cs b/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/AsymmetricAlgorithm.cs
index d273f4a940..b9757dd565 100644
--- a/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/AsymmetricAlgorithm.cs
+++ b/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/AsymmetricAlgorithm.cs
@@ -11,15 +11,11 @@ namespace System.Security.Cryptography
protected AsymmetricAlgorithm() { }
- public static AsymmetricAlgorithm Create()
- {
- return Create("System.Security.Cryptography.AsymmetricAlgorithm");
- }
+ public static AsymmetricAlgorithm Create() =>
+ throw new PlatformNotSupportedException(SR.Cryptography_DefaultAlgorithm_NotSupported);
- public static AsymmetricAlgorithm Create(string algName)
- {
- throw new PlatformNotSupportedException();
- }
+ public static AsymmetricAlgorithm Create(string algName) =>
+ (AsymmetricAlgorithm)CryptoConfigForwarder.CreateFromName(algName);
public virtual int KeySize
{
diff --git a/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/CryptoConfigForwarder.cs b/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/CryptoConfigForwarder.cs
new file mode 100644
index 0000000000..758208ee8c
--- /dev/null
+++ b/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/CryptoConfigForwarder.cs
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Reflection;
+
+namespace System.Security.Cryptography
+{
+ internal static class CryptoConfigForwarder
+ {
+ private static readonly Func<string, object> s_createFromName = BindCreateFromName();
+
+ private static Func<string, object> BindCreateFromName()
+ {
+ const string CryptoConfigTypeName =
+ "System.Security.Cryptography.CryptoConfig, System.Security.Cryptography.Algorithms";
+
+ const string CreateFromNameMethodName = "CreateFromName";
+
+ Type t = Type.GetType(CryptoConfigTypeName, throwOnError: true);
+ MethodInfo createFromName = t.GetMethod(CreateFromNameMethodName, new[] { typeof(string) });
+
+ if (createFromName == null)
+ {
+ throw new MissingMethodException(t.FullName, CreateFromNameMethodName);
+ }
+
+ return (Func<string, object>)createFromName.CreateDelegate(typeof(Func<string, object>));
+ }
+
+ internal static object CreateFromName(string name) => s_createFromName(name);
+ }
+}
diff --git a/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/CryptoStream.cs b/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/CryptoStream.cs
index c9f420d593..60ba529d6e 100644
--- a/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/CryptoStream.cs
+++ b/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/CryptoStream.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Buffers;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
@@ -238,7 +239,7 @@ namespace System.Security.Cryptography
public override int Read(byte[] buffer, int offset, int count)
{
CheckReadArguments(buffer, offset, count);
- return ReadAsyncCore(buffer, offset, count, default(CancellationToken), useAsync: false).ConfigureAwait(false).GetAwaiter().GetResult();
+ return ReadAsyncCore(buffer, offset, count, default(CancellationToken), useAsync: false).GetAwaiter().GetResult();
}
private void CheckReadArguments(byte[] buffer, int offset, int count)
@@ -270,6 +271,8 @@ namespace System.Security.Cryptography
Buffer.BlockCopy(_outputBuffer, 0, buffer, offset, _outputBufferIndex);
bytesToDeliver -= _outputBufferIndex;
currentOutputIndex += _outputBufferIndex;
+ int toClear = _outputBuffer.Length - _outputBufferIndex;
+ CryptographicOperations.ZeroMemory(new Span<byte>(_outputBuffer, _outputBufferIndex, toClear));
_outputBufferIndex = 0;
}
else
@@ -277,6 +280,10 @@ namespace System.Security.Cryptography
Buffer.BlockCopy(_outputBuffer, 0, buffer, offset, count);
Buffer.BlockCopy(_outputBuffer, count, _outputBuffer, 0, _outputBufferIndex - count);
_outputBufferIndex -= count;
+
+ int toClear = _outputBuffer.Length - _outputBufferIndex;
+ CryptographicOperations.ZeroMemory(new Span<byte>(_outputBuffer, _outputBufferIndex, toClear));
+
return (count);
}
}
@@ -294,65 +301,98 @@ namespace System.Security.Cryptography
int numOutputBytes;
// OK, see first if it's a multi-block transform and we can speed up things
- if (bytesToDeliver > _outputBlockSize)
+ int blocksToProcess = bytesToDeliver / _outputBlockSize;
+
+ if (blocksToProcess > 1 && _transform.CanTransformMultipleBlocks)
{
- if (_transform.CanTransformMultipleBlocks)
+ int numWholeBlocksInBytes = blocksToProcess * _inputBlockSize;
+ byte[] tempInputBuffer = ArrayPool<byte>.Shared.Rent(numWholeBlocksInBytes);
+ byte[] tempOutputBuffer = null;
+
+ try
{
- int BlocksToProcess = bytesToDeliver / _outputBlockSize;
- int numWholeBlocksInBytes = BlocksToProcess * _inputBlockSize;
- byte[] tempInputBuffer = new byte[numWholeBlocksInBytes];
- // get first the block already read
- Buffer.BlockCopy(_inputBuffer, 0, tempInputBuffer, 0, _inputBufferIndex);
- amountRead = _inputBufferIndex;
- amountRead += useAsync ?
- await _stream.ReadAsync(tempInputBuffer, _inputBufferIndex, numWholeBlocksInBytes - _inputBufferIndex, cancellationToken) :
+ amountRead = useAsync ?
+ await _stream.ReadAsync(new Memory<byte>(tempInputBuffer, _inputBufferIndex, numWholeBlocksInBytes - _inputBufferIndex), cancellationToken) :
_stream.Read(tempInputBuffer, _inputBufferIndex, numWholeBlocksInBytes - _inputBufferIndex);
- _inputBufferIndex = 0;
- if (amountRead <= _inputBlockSize)
+ int totalInput = _inputBufferIndex + amountRead;
+
+ // If there's still less than a block, copy the new data into the hold buffer and move to the slow read.
+ if (totalInput < _inputBlockSize)
{
- _inputBuffer = tempInputBuffer;
- _inputBufferIndex = amountRead;
- goto slow;
+ Buffer.BlockCopy(tempInputBuffer, _inputBufferIndex, _inputBuffer, _inputBufferIndex, amountRead);
+ _inputBufferIndex = totalInput;
}
- // Make amountRead an integral multiple of _InputBlockSize
- int numWholeReadBlocksInBytes = (amountRead / _inputBlockSize) * _inputBlockSize;
- int numIgnoredBytes = amountRead - numWholeReadBlocksInBytes;
- if (numIgnoredBytes != 0)
+ else
{
- _inputBufferIndex = numIgnoredBytes;
- Buffer.BlockCopy(tempInputBuffer, numWholeReadBlocksInBytes, _inputBuffer, 0, numIgnoredBytes);
+ // Copy any held data into tempInputBuffer now that we know we're proceeding
+ Buffer.BlockCopy(_inputBuffer, 0, tempInputBuffer, 0, _inputBufferIndex);
+ CryptographicOperations.ZeroMemory(new Span<byte>(_inputBuffer, 0, _inputBufferIndex));
+ amountRead += _inputBufferIndex;
+ _inputBufferIndex = 0;
+
+ // Make amountRead an integral multiple of _InputBlockSize
+ int numWholeReadBlocks = amountRead / _inputBlockSize;
+ int numWholeReadBlocksInBytes = numWholeReadBlocks * _inputBlockSize;
+ int numIgnoredBytes = amountRead - numWholeReadBlocksInBytes;
+
+ if (numIgnoredBytes != 0)
+ {
+ _inputBufferIndex = numIgnoredBytes;
+ Buffer.BlockCopy(tempInputBuffer, numWholeReadBlocksInBytes, _inputBuffer, 0, numIgnoredBytes);
+ }
+
+ tempOutputBuffer = ArrayPool<byte>.Shared.Rent(numWholeReadBlocks * _outputBlockSize);
+ numOutputBytes = _transform.TransformBlock(tempInputBuffer, 0, numWholeReadBlocksInBytes, tempOutputBuffer, 0);
+ Buffer.BlockCopy(tempOutputBuffer, 0, buffer, currentOutputIndex, numOutputBytes);
+
+ // Clear what was written while we know how much that was
+ CryptographicOperations.ZeroMemory(new Span<byte>(tempOutputBuffer, 0, numOutputBytes));
+ ArrayPool<byte>.Shared.Return(tempOutputBuffer);
+ tempOutputBuffer = null;
+
+ bytesToDeliver -= numOutputBytes;
+ currentOutputIndex += numOutputBytes;
}
- byte[] tempOutputBuffer = new byte[(numWholeReadBlocksInBytes / _inputBlockSize) * _outputBlockSize];
- numOutputBytes = _transform.TransformBlock(tempInputBuffer, 0, numWholeReadBlocksInBytes, tempOutputBuffer, 0);
- Buffer.BlockCopy(tempOutputBuffer, 0, buffer, currentOutputIndex, numOutputBytes);
- // Now, tempInputBuffer and tempOutputBuffer are no more needed, so zeroize them to protect plain text
- Array.Clear(tempInputBuffer, 0, tempInputBuffer.Length);
- Array.Clear(tempOutputBuffer, 0, tempOutputBuffer.Length);
- bytesToDeliver -= numOutputBytes;
- currentOutputIndex += numOutputBytes;
+ }
+ finally
+ {
+ // If we rented and then an exception happened we don't know how much was written to,
+ // clear the whole thing and return it.
+ if (tempOutputBuffer != null)
+ {
+ CryptographicOperations.ZeroMemory(tempOutputBuffer);
+ ArrayPool<byte>.Shared.Return(tempOutputBuffer);
+ tempOutputBuffer = null;
+ }
+
+ CryptographicOperations.ZeroMemory(new Span<byte>(tempInputBuffer, 0, numWholeBlocksInBytes));
+ ArrayPool<byte>.Shared.Return(tempInputBuffer);
+ tempInputBuffer = null;
}
}
- slow:
// try to fill _InputBuffer so we have something to transform
while (bytesToDeliver > 0)
{
while (_inputBufferIndex < _inputBlockSize)
{
amountRead = useAsync ?
- await _stream.ReadAsync(_inputBuffer, _inputBufferIndex, _inputBlockSize - _inputBufferIndex, cancellationToken) :
+ await _stream.ReadAsync(new Memory<byte>(_inputBuffer, _inputBufferIndex, _inputBlockSize - _inputBufferIndex), cancellationToken) :
_stream.Read(_inputBuffer, _inputBufferIndex, _inputBlockSize - _inputBufferIndex);
// first, check to see if we're at the end of the input stream
if (amountRead == 0) goto ProcessFinalBlock;
_inputBufferIndex += amountRead;
}
+
numOutputBytes = _transform.TransformBlock(_inputBuffer, 0, _inputBlockSize, _outputBuffer, 0);
_inputBufferIndex = 0;
+
if (bytesToDeliver >= numOutputBytes)
{
Buffer.BlockCopy(_outputBuffer, 0, buffer, currentOutputIndex, numOutputBytes);
+ CryptographicOperations.ZeroMemory(new Span<byte>(_outputBuffer, 0, numOutputBytes));
currentOutputIndex += numOutputBytes;
bytesToDeliver -= numOutputBytes;
}
@@ -361,6 +401,8 @@ namespace System.Security.Cryptography
Buffer.BlockCopy(_outputBuffer, 0, buffer, currentOutputIndex, bytesToDeliver);
_outputBufferIndex = numOutputBytes - bytesToDeliver;
Buffer.BlockCopy(_outputBuffer, bytesToDeliver, _outputBuffer, 0, _outputBufferIndex);
+ int toClear = _outputBuffer.Length - _outputBufferIndex;
+ CryptographicOperations.ZeroMemory(new Span<byte>(_outputBuffer, _outputBufferIndex, toClear));
return count;
}
}
@@ -381,6 +423,8 @@ namespace System.Security.Cryptography
Buffer.BlockCopy(_outputBuffer, 0, buffer, currentOutputIndex, bytesToDeliver);
_outputBufferIndex -= bytesToDeliver;
Buffer.BlockCopy(_outputBuffer, bytesToDeliver, _outputBuffer, 0, _outputBufferIndex);
+ int toClear = _outputBuffer.Length - _outputBufferIndex;
+ CryptographicOperations.ZeroMemory(new Span<byte>(_outputBuffer, _outputBufferIndex, toClear));
return (count);
}
else
@@ -388,6 +432,7 @@ namespace System.Security.Cryptography
Buffer.BlockCopy(_outputBuffer, 0, buffer, currentOutputIndex, _outputBufferIndex);
bytesToDeliver -= _outputBufferIndex;
_outputBufferIndex = 0;
+ CryptographicOperations.ZeroMemory(_outputBuffer);
return (count - bytesToDeliver);
}
}
@@ -475,7 +520,7 @@ namespace System.Security.Cryptography
if (_outputBufferIndex > 0)
{
if (useAsync)
- await _stream.WriteAsync(_outputBuffer, 0, _outputBufferIndex, cancellationToken);
+ await _stream.WriteAsync(new ReadOnlyMemory<byte>(_outputBuffer, 0, _outputBufferIndex), cancellationToken);
else
_stream.Write(_outputBuffer, 0, _outputBufferIndex);
_outputBufferIndex = 0;
@@ -488,7 +533,7 @@ namespace System.Security.Cryptography
numOutputBytes = _transform.TransformBlock(_inputBuffer, 0, _inputBlockSize, _outputBuffer, 0);
// write out the bytes we just got
if (useAsync)
- await _stream.WriteAsync(_outputBuffer, 0, numOutputBytes, cancellationToken);
+ await _stream.WriteAsync(new ReadOnlyMemory<byte>(_outputBuffer, 0, numOutputBytes), cancellationToken);
else
_stream.Write(_outputBuffer, 0, numOutputBytes);
@@ -500,21 +545,38 @@ namespace System.Security.Cryptography
if (bytesToWrite >= _inputBlockSize)
{
// We have at least an entire block's worth to transform
+ int numWholeBlocks = bytesToWrite / _inputBlockSize;
+
// If the transform will handle multiple blocks at once, do that
- if (_transform.CanTransformMultipleBlocks)
+ if (_transform.CanTransformMultipleBlocks && numWholeBlocks > 1)
{
- int numWholeBlocks = bytesToWrite / _inputBlockSize;
int numWholeBlocksInBytes = numWholeBlocks * _inputBlockSize;
- byte[] _tempOutputBuffer = new byte[numWholeBlocks * _outputBlockSize];
- numOutputBytes = _transform.TransformBlock(buffer, currentInputIndex, numWholeBlocksInBytes, _tempOutputBuffer, 0);
-
- if (useAsync)
- await _stream.WriteAsync(_tempOutputBuffer, 0, numOutputBytes, cancellationToken);
- else
- _stream.Write(_tempOutputBuffer, 0, numOutputBytes);
-
- currentInputIndex += numWholeBlocksInBytes;
- bytesToWrite -= numWholeBlocksInBytes;
+ byte[] tempOutputBuffer = ArrayPool<byte>.Shared.Rent(numWholeBlocks * _outputBlockSize);
+ numOutputBytes = 0;
+
+ try
+ {
+ numOutputBytes =
+ _transform.TransformBlock(buffer, currentInputIndex, numWholeBlocksInBytes, tempOutputBuffer, 0);
+
+ if (useAsync)
+ {
+ await _stream.WriteAsync(new ReadOnlyMemory<byte>(tempOutputBuffer, 0, numOutputBytes), cancellationToken);
+ }
+ else
+ {
+ _stream.Write(tempOutputBuffer, 0, numOutputBytes);
+ }
+
+ currentInputIndex += numWholeBlocksInBytes;
+ bytesToWrite -= numWholeBlocksInBytes;
+ }
+ finally
+ {
+ CryptographicOperations.ZeroMemory(new Span<byte>(tempOutputBuffer, 0, numOutputBytes));
+ ArrayPool<byte>.Shared.Return(tempOutputBuffer);
+ tempOutputBuffer = null;
+ }
}
else
{
@@ -522,7 +584,7 @@ namespace System.Security.Cryptography
numOutputBytes = _transform.TransformBlock(buffer, currentInputIndex, _inputBlockSize, _outputBuffer, 0);
if (useAsync)
- await _stream.WriteAsync(_outputBuffer, 0, numOutputBytes, cancellationToken);
+ await _stream.WriteAsync(new ReadOnlyMemory<byte>(_outputBuffer, 0, numOutputBytes), cancellationToken);
else
_stream.Write(_outputBuffer, 0, numOutputBytes);
diff --git a/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/CryptographicOperations.cs b/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/CryptographicOperations.cs
new file mode 100644
index 0000000000..3f1caff6b1
--- /dev/null
+++ b/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/CryptographicOperations.cs
@@ -0,0 +1,63 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.CompilerServices;
+
+namespace System.Security.Cryptography
+{
+ public static class CryptographicOperations
+ {
+ /// <summary>
+ /// Determine the equality of two byte sequences in an amount of time which depends on
+ /// the length of the sequences, but not the values.
+ /// </summary>
+ /// <param name="left">The first buffer to compare.</param>
+ /// <param name="right">The second buffer to compare.</param>
+ /// <returns>
+ /// <c>true</c> if <paramref name="left"/> and <paramref name="right"/> have the same
+ /// values for <see cref="ReadOnlySpan{T}.Length"/> and the same contents, <c>false</c>
+ /// otherwise.
+ /// </returns>
+ /// <remarks>
+ /// This method compares two buffers' contents for equality in a manner which does not
+ /// leak timing information, making it ideal for use within cryptographic routines.
+ /// This method will short-circuit and return <c>false</c> only if <paramref name="left"/>
+ /// and <paramref name="right"/> have different lengths.
+ ///
+ /// Fixed-time behavior is guaranteed in all other cases, including if <paramref name="left"/>
+ /// and <paramref name="right"/> reference the same address.
+ /// </remarks>
+ [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
+ public static bool FixedTimeEquals(ReadOnlySpan<byte> left, ReadOnlySpan<byte> right)
+ {
+ // NoOptimization because we want this method to be exactly as non-short-circuiting
+ // as written.
+ //
+ // NoInlining because the NoOptimization would get lost if the method got inlined.
+
+ if (left.Length != right.Length)
+ {
+ return false;
+ }
+
+ int length = left.Length;
+ int accum = 0;
+
+ for (int i = 0; i < length; i++)
+ {
+ accum |= left[i] - right[i];
+ }
+
+ return accum == 0;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
+ public static void ZeroMemory(Span<byte> buffer)
+ {
+ // NoOptimize to prevent the optimizer from deciding this call is unnecessary
+ // NoInlining to prevent the inliner from forgetting that the method was no-optimize
+ buffer.Clear();
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/HMAC.cs b/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/HMAC.cs
index 7f02b70178..819e3084d5 100644
--- a/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/HMAC.cs
+++ b/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/HMAC.cs
@@ -17,9 +17,11 @@ namespace System.Security.Cryptography
protected HMAC() { }
- public static new HMAC Create() => Create("System.Security.Cryptography.HMAC");
+ public static new HMAC Create() =>
+ throw new PlatformNotSupportedException(SR.Cryptography_DefaultAlgorithm_NotSupported);
- public static new HMAC Create(string algorithmName) => throw new PlatformNotSupportedException();
+ public static new HMAC Create(string algorithmName) =>
+ (HMAC)CryptoConfigForwarder.CreateFromName(algorithmName);
public string HashName
{
diff --git a/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/HashAlgorithm.cs b/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/HashAlgorithm.cs
index 8c8daa18c6..739db28b2f 100644
--- a/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/HashAlgorithm.cs
+++ b/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/HashAlgorithm.cs
@@ -16,9 +16,11 @@ namespace System.Security.Cryptography
protected HashAlgorithm() { }
- public static HashAlgorithm Create() => Create("System.Security.Cryptography.HashAlgorithm");
+ public static HashAlgorithm Create() =>
+ throw new PlatformNotSupportedException(SR.Cryptography_DefaultAlgorithm_NotSupported);
- public static HashAlgorithm Create(string hashName) => throw new PlatformNotSupportedException();
+ public static HashAlgorithm Create(string hashName) =>
+ (HashAlgorithm)CryptoConfigForwarder.CreateFromName(hashName);
public virtual int HashSize => HashSizeValue;
@@ -96,13 +98,23 @@ namespace System.Security.Cryptography
throw new ObjectDisposedException(null);
// Default the buffer size to 4K.
- byte[] buffer = new byte[4096];
- int bytesRead;
- while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0)
+ byte[] buffer = ArrayPool<byte>.Shared.Rent(4096);
+
+ try
{
- HashCore(buffer, 0, bytesRead);
+ int bytesRead;
+ while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0)
+ {
+ HashCore(buffer, 0, bytesRead);
+ }
+
+ return CaptureHashCodeAndReinitialize();
+ }
+ finally
+ {
+ CryptographicOperations.ZeroMemory(buffer);
+ ArrayPool<byte>.Shared.Return(buffer);
}
- return CaptureHashCodeAndReinitialize();
}
private byte[] CaptureHashCodeAndReinitialize()
diff --git a/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/KeyedHashAlgorithm.cs b/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/KeyedHashAlgorithm.cs
index 8bedcd577f..6f75011e4d 100644
--- a/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/KeyedHashAlgorithm.cs
+++ b/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/KeyedHashAlgorithm.cs
@@ -8,15 +8,11 @@ namespace System.Security.Cryptography
{
protected KeyedHashAlgorithm() { }
- public static new KeyedHashAlgorithm Create()
- {
- return Create("System.Security.Cryptography.KeyedHashAlgorithm");
- }
+ public static new KeyedHashAlgorithm Create() =>
+ throw new PlatformNotSupportedException(SR.Cryptography_DefaultAlgorithm_NotSupported);
- public static new KeyedHashAlgorithm Create(string algName)
- {
- throw new PlatformNotSupportedException();
- }
+ public static new KeyedHashAlgorithm Create(string algName) =>
+ (KeyedHashAlgorithm)CryptoConfigForwarder.CreateFromName(algName);
public virtual byte[] Key
{
diff --git a/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/SymmetricAlgorithm.cs b/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/SymmetricAlgorithm.cs
index dad3c11ba4..ee9098876f 100644
--- a/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/SymmetricAlgorithm.cs
+++ b/src/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/SymmetricAlgorithm.cs
@@ -12,15 +12,11 @@ namespace System.Security.Cryptography
PaddingValue = PaddingMode.PKCS7;
}
- public static SymmetricAlgorithm Create()
- {
- return Create("System.Security.Cryptography.SymmetricAlgorithm");
- }
+ public static SymmetricAlgorithm Create() =>
+ throw new PlatformNotSupportedException(SR.Cryptography_DefaultAlgorithm_NotSupported);
- public static SymmetricAlgorithm Create(string algName)
- {
- throw new PlatformNotSupportedException();
- }
+ public static SymmetricAlgorithm Create(string algName) =>
+ (SymmetricAlgorithm)CryptoConfigForwarder.CreateFromName(algName);
public virtual int FeedbackSize
{
diff --git a/src/System.Security.Cryptography.Primitives/tests/CryptoConfigTests.cs b/src/System.Security.Cryptography.Primitives/tests/CryptoConfigTests.cs
index 08a1f864d4..9fbfe2a7d5 100644
--- a/src/System.Security.Cryptography.Primitives/tests/CryptoConfigTests.cs
+++ b/src/System.Security.Cryptography.Primitives/tests/CryptoConfigTests.cs
@@ -9,20 +9,151 @@ namespace System.Security.Cryptography.CryptoConfigTests
public static class CryptoConfigTests
{
[Fact]
- public static void StaticCreateMethods()
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public static void DefaultStaticCreateMethods()
{
- // These are not supported because CryptoConfig exists in Algorithms assembly.
- // CryptoConfig exists in Algorithms partly because it requires the Oid class in Encoding assembly.
+ // .NET Core does not allow the base classes to pick an algorithm.
Assert.Throws<PlatformNotSupportedException>(() => AsymmetricAlgorithm.Create());
- Assert.Throws<PlatformNotSupportedException>(() => AsymmetricAlgorithm.Create(null));
Assert.Throws<PlatformNotSupportedException>(() => HashAlgorithm.Create());
- Assert.Throws<PlatformNotSupportedException>(() => HashAlgorithm.Create(null));
Assert.Throws<PlatformNotSupportedException>(() => KeyedHashAlgorithm.Create());
- Assert.Throws<PlatformNotSupportedException>(() => KeyedHashAlgorithm.Create(null));
Assert.Throws<PlatformNotSupportedException>(() => HMAC.Create());
- Assert.Throws<PlatformNotSupportedException>(() => HMAC.Create(null));
Assert.Throws<PlatformNotSupportedException>(() => SymmetricAlgorithm.Create());
- Assert.Throws<PlatformNotSupportedException>(() => SymmetricAlgorithm.Create(null));
+ }
+
+ [Fact]
+ public static void NamedCreateMethods_NullInput()
+ {
+ AssertExtensions.Throws<ArgumentNullException>("name", () => AsymmetricAlgorithm.Create(null));
+ AssertExtensions.Throws<ArgumentNullException>("name", () => HashAlgorithm.Create(null));
+ AssertExtensions.Throws<ArgumentNullException>("name", () => KeyedHashAlgorithm.Create(null));
+ AssertExtensions.Throws<ArgumentNullException>("name", () => HMAC.Create(null));
+ AssertExtensions.Throws<ArgumentNullException>("name", () => SymmetricAlgorithm.Create(null));
+ }
+
+ // The returned types on .NET Framework can differ when the machine is in FIPS mode.
+ // So check hash algorithms via a more complicated manner.
+ [Theory]
+ [InlineData("MD5", typeof(MD5))]
+ [InlineData("http://www.w3.org/2001/04/xmldsig-more#md5", typeof(MD5))]
+ [InlineData("System.Security.Cryptography.HashAlgorithm", typeof(SHA1))]
+ [InlineData("SHA1", typeof(SHA1))]
+ [InlineData("http://www.w3.org/2000/09/xmldsig#sha1", typeof(SHA1))]
+ [InlineData("SHA256", typeof(SHA256))]
+ [InlineData("SHA-256", typeof(SHA256))]
+ [InlineData("http://www.w3.org/2001/04/xmlenc#sha256", typeof(SHA256))]
+ [InlineData("SHA384", typeof(SHA384))]
+ [InlineData("SHA-384", typeof(SHA384))]
+ [InlineData("http://www.w3.org/2001/04/xmldsig-more#sha384", typeof(SHA384))]
+ [InlineData("SHA512", typeof(SHA512))]
+ [InlineData("SHA-512", typeof(SHA512))]
+ [InlineData("http://www.w3.org/2001/04/xmlenc#sha512", typeof(SHA512))]
+ public static void NamedHashAlgorithmCreate(string identifier, Type baseType)
+ {
+ using (HashAlgorithm created = HashAlgorithm.Create(identifier))
+ {
+ Assert.NotNull(created);
+ Assert.IsAssignableFrom(baseType, created);
+
+ using (HashAlgorithm equivalent =
+ (HashAlgorithm)baseType.GetMethod("Create", Array.Empty<Type>()).Invoke(null, null))
+ {
+ byte[] input = { 1, 2, 3, 4, 5 };
+ byte[] equivHash = equivalent.ComputeHash(input);
+ byte[] createdHash = created.ComputeHash(input);
+ Assert.Equal(equivHash, createdHash);
+ }
+ }
+ }
+
+ [Theory]
+ [InlineData("System.Security.Cryptography.HMAC", typeof(HMACSHA1))]
+ [InlineData("System.Security.Cryptography.KeyedHashAlgorithm", typeof(HMACSHA1))]
+ [InlineData("System.Security.Cryptography.HMACSHA1", typeof(HMACSHA1))]
+ [InlineData("HMACSHA1", typeof(HMACSHA1))]
+ [InlineData("http://www.w3.org/2000/09/xmldsig#hmac-sha1", typeof(HMACSHA1))]
+ [InlineData("System.Security.Cryptography.HMACSHA256", typeof(HMACSHA256))]
+ [InlineData("HMACSHA256", typeof(HMACSHA256))]
+ [InlineData("http://www.w3.org/2001/04/xmldsig-more#hmac-sha256", typeof(HMACSHA256))]
+ [InlineData("System.Security.Cryptography.HMACSHA384", typeof(HMACSHA384))]
+ [InlineData("HMACSHA384", typeof(HMACSHA384))]
+ [InlineData("http://www.w3.org/2001/04/xmldsig-more#hmac-sha384", typeof(HMACSHA384))]
+ [InlineData("System.Security.Cryptography.HMACSHA512", typeof(HMACSHA512))]
+ [InlineData("HMACSHA512", typeof(HMACSHA512))]
+ [InlineData("http://www.w3.org/2001/04/xmldsig-more#hmac-sha512", typeof(HMACSHA512))]
+ [InlineData("System.Security.Cryptography.HMACMD5", typeof(HMACMD5))]
+ [InlineData("HMACMD5", typeof(HMACMD5))]
+ [InlineData("http://www.w3.org/2001/04/xmldsig-more#hmac-md5", typeof(HMACMD5))]
+ public static void NamedKeyedHashAlgorithmCreate(string identifier, Type actualType)
+ {
+ using (KeyedHashAlgorithm kha = KeyedHashAlgorithm.Create(identifier))
+ {
+ Assert.IsType(actualType, kha);
+
+ // .NET Core only has HMAC keyed hash algorithms, so combine the two tests
+ using (HMAC hmac = HMAC.Create(identifier))
+ {
+ Assert.IsType(actualType, hmac);
+ }
+ }
+ }
+
+ [Theory]
+ [InlineData("AES", typeof(Aes))]
+ [InlineData("Rijndael", typeof(Rijndael))]
+ [InlineData("System.Security.Cryptography.Rijndael", typeof(Rijndael))]
+ [InlineData("http://www.w3.org/2001/04/xmlenc#aes128-cbc", typeof(Rijndael))]
+ [InlineData("http://www.w3.org/2001/04/xmlenc#aes192-cbc", typeof(Rijndael))]
+ [InlineData("http://www.w3.org/2001/04/xmlenc#aes256-cbc", typeof(Rijndael))]
+ [InlineData("3DES", typeof(TripleDES))]
+ [InlineData("TripleDES", typeof(TripleDES))]
+ [InlineData("System.Security.Cryptography.TripleDES", typeof(TripleDES))]
+ [InlineData("http://www.w3.org/2001/04/xmlenc#tripledes-cbc", typeof(TripleDES))]
+ [InlineData("DES", typeof(DES))]
+ [InlineData("System.Security.Cryptography.DES", typeof(DES))]
+ [InlineData("http://www.w3.org/2001/04/xmlenc#des-cbc", typeof(DES))]
+ public static void NamedSymmetricAlgorithmCreate(string identifier, Type baseType)
+ {
+ using (SymmetricAlgorithm created = SymmetricAlgorithm.Create(identifier))
+ {
+ Assert.NotNull(created);
+ Assert.IsAssignableFrom(baseType, created);
+ }
+ }
+
+ [Theory]
+ [InlineData("RSA", typeof(RSA))]
+ [InlineData("System.Security.Cryptography.RSA", typeof(RSA))]
+ [InlineData("ECDsa", typeof(ECDsa))]
+ [InlineData("DSA", typeof(DSA))]
+ [InlineData("System.Security.Cryptography.DSA", typeof(DSA))]
+ public static void NamedAsymmetricAlgorithmCreate(string identifier, Type baseType)
+ {
+ using (AsymmetricAlgorithm created = AsymmetricAlgorithm.Create(identifier))
+ {
+ Assert.NotNull(created);
+ Assert.IsAssignableFrom(baseType, created);
+ }
+ }
+
+ [Fact]
+ public static void NamedCreate_Mismatch()
+ {
+ Assert.Throws<InvalidCastException>(() => AsymmetricAlgorithm.Create("SHA1"));
+ Assert.Throws<InvalidCastException>(() => KeyedHashAlgorithm.Create("SHA1"));
+ Assert.Throws<InvalidCastException>(() => HMAC.Create("SHA1"));
+ Assert.Throws<InvalidCastException>(() => SymmetricAlgorithm.Create("SHA1"));
+ Assert.Throws<InvalidCastException>(() => HashAlgorithm.Create("RSA"));
+ }
+
+ [Fact]
+ public static void NamedCreate_Unknown()
+ {
+ const string UnknownAlgorithmName = "XYZZY";
+ Assert.Null(AsymmetricAlgorithm.Create(UnknownAlgorithmName));
+ Assert.Null(HashAlgorithm.Create(UnknownAlgorithmName));
+ Assert.Null(KeyedHashAlgorithm.Create(UnknownAlgorithmName));
+ Assert.Null(HMAC.Create(UnknownAlgorithmName));
+ Assert.Null(SymmetricAlgorithm.Create(UnknownAlgorithmName));
}
}
}
diff --git a/src/System.Security.Cryptography.Primitives/tests/FixedTimeEqualsTests.cs b/src/System.Security.Cryptography.Primitives/tests/FixedTimeEqualsTests.cs
new file mode 100644
index 0000000000..a662a3628b
--- /dev/null
+++ b/src/System.Security.Cryptography.Primitives/tests/FixedTimeEqualsTests.cs
@@ -0,0 +1,109 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using Xunit;
+
+namespace System.Security.Cryptography.Primitives.Tests
+{
+ public static class FixedTimeEqualsTests
+ {
+ [Theory]
+ [InlineData(0)]
+ [InlineData(1)]
+ [InlineData(128 / 8)]
+ [InlineData(256 / 8)]
+ [InlineData(512 / 8)]
+ [InlineData(96)]
+ [InlineData(1024)]
+ public static void EqualReturnsTrue(int byteLength)
+ {
+ byte[] rented = ArrayPool<byte>.Shared.Rent(byteLength);
+ Span<byte> testSpan = new Span<byte>(rented, 0, byteLength);
+ RandomNumberGenerator.Fill(testSpan);
+
+ byte[] rented2 = ArrayPool<byte>.Shared.Rent(byteLength);
+ Span<byte> testSpan2 = new Span<byte>(rented2, 0, byteLength);
+
+ testSpan.CopyTo(testSpan2);
+
+ bool isEqual = CryptographicOperations.FixedTimeEquals(testSpan, testSpan2);
+
+ ArrayPool<byte>.Shared.Return(rented);
+ ArrayPool<byte>.Shared.Return(rented2);
+
+ Assert.True(isEqual);
+ }
+
+ [Theory]
+ [InlineData(1)]
+ [InlineData(128 / 8)]
+ [InlineData(256 / 8)]
+ [InlineData(512 / 8)]
+ [InlineData(96)]
+ [InlineData(1024)]
+ public static void UnequalReturnsFalse(int byteLength)
+ {
+ byte[] rented = ArrayPool<byte>.Shared.Rent(byteLength);
+ Span<byte> testSpan = new Span<byte>(rented, 0, byteLength);
+ RandomNumberGenerator.Fill(testSpan);
+
+ byte[] rented2 = ArrayPool<byte>.Shared.Rent(byteLength);
+ Span<byte> testSpan2 = new Span<byte>(rented2, 0, byteLength);
+
+ testSpan.CopyTo(testSpan2);
+ testSpan[testSpan[0] % testSpan.Length] ^= 0xFF;
+
+ bool isEqual = CryptographicOperations.FixedTimeEquals(testSpan, testSpan2);
+
+ ArrayPool<byte>.Shared.Return(rented);
+ ArrayPool<byte>.Shared.Return(rented2);
+
+ Assert.False(isEqual);
+ }
+
+ [Theory]
+ [InlineData(1)]
+ [InlineData(128 / 8)]
+ [InlineData(256 / 8)]
+ [InlineData(512 / 8)]
+ [InlineData(96)]
+ [InlineData(1024)]
+ public static void DifferentLengthsReturnFalse(int byteLength)
+ {
+ byte[] rented = ArrayPool<byte>.Shared.Rent(byteLength);
+ Span<byte> testSpan = new Span<byte>(rented, 0, byteLength);
+ RandomNumberGenerator.Fill(testSpan);
+
+ byte[] rented2 = ArrayPool<byte>.Shared.Rent(byteLength);
+ Span<byte> testSpan2 = new Span<byte>(rented2, 0, byteLength);
+
+ testSpan.CopyTo(testSpan2);
+
+ bool isEqualA = CryptographicOperations.FixedTimeEquals(testSpan, testSpan2.Slice(0, byteLength - 1));
+ bool isEqualB = CryptographicOperations.FixedTimeEquals(testSpan.Slice(0, byteLength - 1), testSpan2);
+
+ ArrayPool<byte>.Shared.Return(rented);
+ ArrayPool<byte>.Shared.Return(rented2);
+
+ Assert.False(isEqualA, "value, value missing last byte");
+ Assert.False(isEqualB, "value missing last byte, value");
+ }
+
+ [Fact]
+ public static void HasCorrectMethodImpl()
+ {
+ Type t = typeof(CryptographicOperations);
+ MethodInfo mi = t.GetMethod(nameof(CryptographicOperations.FixedTimeEquals));
+
+ // This method cannot be optimized, or it loses its fixed time guarantees.
+ // It cannot be inlined, or it loses its no-optimization guarantee.
+ Assert.Equal(
+ MethodImplAttributes.NoInlining | MethodImplAttributes.NoOptimization,
+ mi.MethodImplementationFlags);
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Primitives/tests/Performance/Configurations.props b/src/System.Security.Cryptography.Primitives/tests/Performance/Configurations.props
new file mode 100644
index 0000000000..d3ac8a63c7
--- /dev/null
+++ b/src/System.Security.Cryptography.Primitives/tests/Performance/Configurations.props
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <BuildConfigurations>
+ netcoreapp;
+ </BuildConfigurations>
+ </PropertyGroup>
+</Project>
diff --git a/src/System.Security.Cryptography.Primitives/tests/Performance/Perf.FixedTimeEquals.cs b/src/System.Security.Cryptography.Primitives/tests/Performance/Perf.FixedTimeEquals.cs
new file mode 100644
index 0000000000..d7fbf81eaf
--- /dev/null
+++ b/src/System.Security.Cryptography.Primitives/tests/Performance/Perf.FixedTimeEquals.cs
@@ -0,0 +1,115 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.Xunit.Performance;
+using Test.Cryptography;
+using Xunit;
+
+namespace System.Security.Cryptography.Primitives.Tests.Performance
+{
+ public class Perf_FixedTimeEquals
+ {
+ private const int IterationCountFor256Bit = 300000;
+
+ [Benchmark(InnerIterationCount = IterationCountFor256Bit)]
+ public static void FixedTimeEquals_256Bit_Equal()
+ {
+ MeasureFixedTimeEquals(
+ "741202531e19d673ad7fff334594549e7c81a285dd02865ddd12530612a96336",
+ "0000000000000000000000000000000000000000000000000000000000000000");
+ }
+
+ [Benchmark(InnerIterationCount = IterationCountFor256Bit)]
+ public static void FixedTimeEquals_256Bit_LastBitDifferent()
+ {
+ MeasureFixedTimeEquals(
+ "741202531e19d673ad7fff334594549e7c81a285dd02865ddd12530612a96336",
+ "0000000000000000000000000000000000000000000000000000000000000001");
+ }
+
+ [Benchmark(InnerIterationCount = IterationCountFor256Bit)]
+ public static void FixedTimeEquals_256Bit_FirstBitDifferent()
+ {
+ MeasureFixedTimeEquals(
+ "741202531e19d673ad7fff334594549e7c81a285dd02865ddd12530612a96336",
+ "8000000000000000000000000000000000000000000000000000000000000000");
+ }
+
+ [Benchmark(InnerIterationCount = IterationCountFor256Bit)]
+ public static void FixedTimeEquals_256Bit_CascadingErrors()
+ {
+ MeasureFixedTimeEquals(
+ "741202531e19d673ad7fff334594549e7c81a285dd02865ddd12530612a96336",
+ "0102040810204080112244880000000000000000000000000000000000000000");
+ }
+
+ [Benchmark(InnerIterationCount = IterationCountFor256Bit)]
+ public static void FixedTimeEquals_256Bit_AllBitsDifferent()
+ {
+ MeasureFixedTimeEquals(
+ "741202531e19d673ad7fff334594549e7c81a285dd02865ddd12530612a96336",
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
+ }
+
+ [Benchmark(InnerIterationCount = IterationCountFor256Bit)]
+ public static void FixedTimeEquals_256Bit_VersusZero()
+ {
+ MeasureFixedTimeEquals(
+ "741202531e19d673ad7fff334594549e7c81a285dd02865ddd12530612a96336",
+ "741202531e19d673ad7fff334594549e7c81a285dd02865ddd12530612a96336");
+ }
+
+ [Benchmark(InnerIterationCount = IterationCountFor256Bit)]
+ public static void FixedTimeEquals_256Bit_SameReference()
+ {
+ byte[] test = "741202531e19d673ad7fff334594549e7c81a285dd02865ddd12530612a96336".HexToByteArray();
+
+ Span<byte> left = test;
+ Span<byte> right = test;
+
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ for (int i = 0; i < Benchmark.InnerIterationCount; i++)
+ {
+ CryptographicOperations.FixedTimeEquals(left, right);
+ }
+ }
+ }
+ }
+
+ // The important statistics from these perf runs aren't the mean, but the t-test for
+ // every set of the same length being the same as when it was equal.
+ private static void MeasureFixedTimeEquals(string baseValueHex, string errorVectorHex)
+ {
+ if (errorVectorHex.Length != baseValueHex.Length)
+ {
+ throw new InvalidOperationException();
+ }
+
+ byte[] a = baseValueHex.HexToByteArray();
+ byte[] b = errorVectorHex.HexToByteArray();
+
+ for (int i = 0; i < a.Length; i++)
+ {
+ b[i] ^= a[i];
+ }
+
+ Span<byte> left = a;
+ Span<byte> right = b;
+
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ for (int i = 0; i < Benchmark.InnerIterationCount; i++)
+ {
+ CryptographicOperations.FixedTimeEquals(left, right);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.Primitives/tests/Performance/System.Security.Cryptography.Primitives.Performance.Tests.csproj b/src/System.Security.Cryptography.Primitives/tests/Performance/System.Security.Cryptography.Primitives.Performance.Tests.csproj
new file mode 100644
index 0000000000..d4f5a9a985
--- /dev/null
+++ b/src/System.Security.Cryptography.Primitives/tests/Performance/System.Security.Cryptography.Primitives.Performance.Tests.csproj
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <Import Project="$(CommonTestPath)\Tests.props" />
+ <PropertyGroup>
+ <IncludePerformanceTests>true</IncludePerformanceTests>
+ <ProjectGuid>{FB3EA273-567D-414F-B36D-3698BE8D198B}</ProjectGuid>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
+ <ItemGroup>
+ <Compile Include="$(CommonTestPath)\System\PerfUtils.cs">
+ <Link>Common\System\PerfUtils.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)\System\Security\Cryptography\ByteUtils.cs">
+ <Link>CommonTest\System\Security\Cryptography\ByteUtils.cs</Link>
+ </Compile>
+ <Compile Include="Perf.FixedTimeEquals.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="$(CommonPath)\..\perf\PerfRunner\PerfRunner.csproj">
+ <Project>{69e46a6f-9966-45a5-8945-2559fe337827}</Project>
+ <Name>PerfRunner</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project> \ No newline at end of file
diff --git a/src/System.Security.Cryptography.Primitives/tests/System.Security.Cryptography.Primitives.Tests.csproj b/src/System.Security.Cryptography.Primitives/tests/System.Security.Cryptography.Primitives.Tests.csproj
index 2159215055..cc2cdbdb68 100644
--- a/src/System.Security.Cryptography.Primitives/tests/System.Security.Cryptography.Primitives.Tests.csproj
+++ b/src/System.Security.Cryptography.Primitives/tests/System.Security.Cryptography.Primitives.Tests.csproj
@@ -11,8 +11,13 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
<ItemGroup>
+ <Compile Include="$(CommonTestPath)\System\IO\PositionValueStream.cs">
+ <Link>CommonTest\System\IO\PositionValueStream.cs</Link>
+ </Compile>
<Compile Include="AsymmetricAlgorithm\Trivial.cs" />
+ <Compile Include="CryptoConfigTests.cs" />
<Compile Include="CryptoStream.cs" />
+ <Compile Include="CryptographicException.cs" />
<Compile Include="HmacAlgorithmTest.cs" />
<Compile Include="KeyedHashAlgorithmTests.cs" />
<Compile Include="Length32Hash.cs" />
@@ -20,14 +25,11 @@
<Compile Include="Sum32Hash.cs" />
<Compile Include="SymmetricAlgorithm\Minimal.cs" />
<Compile Include="SymmetricAlgorithm\Trivial.cs" />
- <Compile Include="CryptographicException.cs" />
- <Compile Include="$(CommonTestPath)\System\IO\PositionValueStream.cs">
- <Link>CommonTest\System\IO\PositionValueStream.cs</Link>
- </Compile>
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)'=='netcoreapp'">
- <Compile Include="CryptoConfigTests.cs" />
+ <Compile Include="FixedTimeEqualsTests.cs" />
<Compile Include="HashAlgorithmTest.netcoreapp.cs" />
+ <Compile Include="ZeroMemoryTests.cs" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Security.Cryptography.Primitives/tests/ZeroMemoryTests.cs b/src/System.Security.Cryptography.Primitives/tests/ZeroMemoryTests.cs
new file mode 100644
index 0000000000..aa4a51bbba
--- /dev/null
+++ b/src/System.Security.Cryptography.Primitives/tests/ZeroMemoryTests.cs
@@ -0,0 +1,77 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Buffers;
+using System.Reflection;
+using Xunit;
+
+namespace System.Security.Cryptography.Primitives.Tests
+{
+ public static class ZeroMemoryTests
+ {
+ [Theory]
+ [InlineData(1)]
+ [InlineData(128 / 8)]
+ [InlineData(256 / 8)]
+ [InlineData(512 / 8)]
+ [InlineData(96)]
+ [InlineData(1024)]
+ public static void MemoryGetsCleared(int byteLength)
+ {
+ byte[] rented = ArrayPool<byte>.Shared.Rent(byteLength);
+ Span<byte> testSpan = new Span<byte>(rented, 0, byteLength);
+
+ bool hasData = false;
+
+ // i should really only iterate when byteLength is 1, and then
+ // only 1/256 executions.
+ //
+ // The chances of this failing are 1 in 1.2e24, unless the RNG is broken.
+ for (int i = 0; i < 10 && !hasData; i++)
+ {
+ RandomNumberGenerator.Fill(testSpan);
+
+ for (int j = 0; j < testSpan.Length; j++)
+ {
+ if (testSpan[j] != 0)
+ {
+ hasData = true;
+ break;
+ }
+ }
+ }
+
+ if (!hasData)
+ {
+ throw new InvalidOperationException("RNG provided all zero-values");
+ }
+
+ // This test cannot guarantee the effect of the memory being cleared
+ // on an otherwise abandoned reference; since the act of measuring it
+ // changes what the optimizer could have done.
+ //
+ // But it can check for it calling clear.
+ CryptographicOperations.ZeroMemory(testSpan);
+
+ for (int i = 0; i < testSpan.Length; i++)
+ {
+ Assert.Equal(0, testSpan[i]);
+ }
+ }
+
+ [Fact]
+ public static void HasCorrectMethodImpl()
+ {
+ Type t = typeof(CryptographicOperations);
+ MethodInfo mi = t.GetMethod(nameof(CryptographicOperations.ZeroMemory));
+
+ // This method cannot be optimized, or the optimizer can decide that a call to Clear
+ // is unnecessary.
+ // It cannot be inlined, or it loses its no-optimization guarantee.
+ Assert.Equal(
+ MethodImplAttributes.NoInlining | MethodImplAttributes.NoOptimization,
+ mi.MethodImplementationFlags);
+ }
+ }
+}
diff --git a/src/System.Security.Cryptography.ProtectedData/src/System.Security.Cryptography.ProtectedData.csproj b/src/System.Security.Cryptography.ProtectedData/src/System.Security.Cryptography.ProtectedData.csproj
index c62b41e383..e00aaaefd4 100644
--- a/src/System.Security.Cryptography.ProtectedData/src/System.Security.Cryptography.ProtectedData.csproj
+++ b/src/System.Security.Cryptography.ProtectedData/src/System.Security.Cryptography.ProtectedData.csproj
@@ -52,6 +52,7 @@
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' != 'netfx'">
<Reference Include="System.Diagnostics.Tools" />
+ <Reference Include="System.Memory" />
<Reference Include="System.Resources.ResourceManager" />
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.InteropServices" />
diff --git a/src/System.Security.Cryptography.ProtectedData/src/System/Security/Cryptography/ProtectedData.cs b/src/System.Security.Cryptography.ProtectedData/src/System/Security/Cryptography/ProtectedData.cs
index 2fdb99bc16..7baa56669a 100644
--- a/src/System.Security.Cryptography.ProtectedData/src/System/Security/Cryptography/ProtectedData.cs
+++ b/src/System.Security.Cryptography.ProtectedData/src/System/Security/Cryptography/ProtectedData.cs
@@ -2,8 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System;
-using System.Diagnostics;
using System.Runtime.InteropServices;
using Internal.Cryptography;
@@ -15,6 +13,8 @@ namespace System.Security.Cryptography
{
public static partial class ProtectedData
{
+ private static readonly byte[] s_nonEmpty = new byte[1];
+
public static byte[] Protect(byte[] userData, byte[] optionalEntropy, DataProtectionScope scope)
{
if (userData == null)
@@ -35,7 +35,12 @@ namespace System.Security.Cryptography
{
unsafe
{
- fixed (byte* pInputData = inputData, pOptionalEntropy = optionalEntropy)
+ // The Win32 API will reject pbData == nullptr, and the fixed statement
+ // maps empty arrays to nullptr... so when the input is empty use the address of a
+ // different array, but still assign cbData to 0.
+ byte[] relevantData = inputData.Length == 0 ? s_nonEmpty : inputData;
+
+ fixed (byte* pInputData = relevantData, pOptionalEntropy = optionalEntropy)
{
DATA_BLOB userDataBlob = new DATA_BLOB((IntPtr)pInputData, (uint)(inputData.Length));
DATA_BLOB optionalEntropyBlob = default(DATA_BLOB);
diff --git a/src/System.Security.Cryptography.ProtectedData/tests/ProtectedDataTests.cs b/src/System.Security.Cryptography.ProtectedData/tests/ProtectedDataTests.cs
index 9532224918..467c8d64c0 100644
--- a/src/System.Security.Cryptography.ProtectedData/tests/ProtectedDataTests.cs
+++ b/src/System.Security.Cryptography.ProtectedData/tests/ProtectedDataTests.cs
@@ -33,6 +33,24 @@ namespace System.Security.Cryptography.ProtectedDataTests
}
}
+ [Theory]
+ [InlineData(DataProtectionScope.CurrentUser, false)]
+ [InlineData(DataProtectionScope.CurrentUser, true)]
+ [InlineData(DataProtectionScope.LocalMachine, false)]
+ [InlineData(DataProtectionScope.LocalMachine, true)]
+ public static void ProtectEmptyData(DataProtectionScope scope, bool useEntropy)
+ {
+ // Use new byte[0] instead of Array.Empty<byte> to prove the implementation
+ // isn't using reference equality
+ byte[] data = new byte[0];
+ byte[] entropy = useEntropy ? new byte[] { 68, 65, 72, 72, 75 } : null;
+ byte[] encrypted = ProtectedData.Protect(data, entropy, scope);
+
+ Assert.NotEqual(data, encrypted);
+ byte[] recovered = ProtectedData.Unprotect(encrypted, entropy, scope);
+ Assert.Equal(data, recovered);
+ }
+
[Fact]
public static void NullEntropyEquivalence()
{
diff --git a/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/ChainPal.cs b/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/ChainPal.cs
index 8f05c0960b..943fda15cb 100644
--- a/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/ChainPal.cs
+++ b/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/ChainPal.cs
@@ -163,11 +163,7 @@ namespace Internal.Cryptography.Pal
{
userIntermediate.Add(cert);
}
- catch (CryptographicException)
- {
- // Saving is opportunistic, just ignore failures
- }
- catch (IOException)
+ catch
{
// Saving is opportunistic, just ignore failures
}
diff --git a/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/DirectoryBasedStoreProvider.cs b/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/DirectoryBasedStoreProvider.cs
index 7c801a1656..83b6fb506e 100644
--- a/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/DirectoryBasedStoreProvider.cs
+++ b/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/DirectoryBasedStoreProvider.cs
@@ -116,6 +116,22 @@ namespace Internal.Cryptography.Pal
throw new CryptographicException(SR.Cryptography_X509_StoreReadOnly);
}
+ try
+ {
+ AddCertToStore(certPal);
+ }
+ catch (CryptographicException)
+ {
+ throw;
+ }
+ catch (Exception e)
+ {
+ throw new CryptographicException(SR.Cryptography_X509_StoreAddFailure, e);
+ }
+ }
+
+ private void AddCertToStore(ICertificatePal certPal)
+ {
// This may well be the first time that we've added something to this store.
Directory.CreateDirectory(_storePath);
diff --git a/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509ChainProcessor.cs b/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509ChainProcessor.cs
index 2cf00f883a..7c0040acc0 100644
--- a/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509ChainProcessor.cs
+++ b/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509ChainProcessor.cs
@@ -380,16 +380,19 @@ namespace Internal.Cryptography.Pal
using (var systemIntermediateStore = new X509Store(StoreName.CertificateAuthority, StoreLocation.LocalMachine))
using (var userRootStore = new X509Store(StoreName.Root, StoreLocation.CurrentUser))
using (var userIntermediateStore = new X509Store(StoreName.CertificateAuthority, StoreLocation.CurrentUser))
+ using (var userMyStore = new X509Store(StoreName.My, StoreLocation.CurrentUser))
{
systemRootStore.Open(OpenFlags.ReadOnly);
systemIntermediateStore.Open(OpenFlags.ReadOnly);
userRootStore.Open(OpenFlags.ReadOnly);
userIntermediateStore.Open(OpenFlags.ReadOnly);
+ userMyStore.Open(OpenFlags.ReadOnly);
X509Certificate2Collection systemRootCerts = systemRootStore.Certificates;
X509Certificate2Collection systemIntermediateCerts = systemIntermediateStore.Certificates;
X509Certificate2Collection userRootCerts = userRootStore.Certificates;
X509Certificate2Collection userIntermediateCerts = userIntermediateStore.Certificates;
+ X509Certificate2Collection userMyCerts = userMyStore.Certificates;
// fill the system trusted collection
foreach (X509Certificate2 userRootCert in userRootCerts)
@@ -416,6 +419,7 @@ namespace Internal.Cryptography.Pal
X509Certificate2Collection[] storesToCheck =
{
extraStore,
+ userMyCerts,
userIntermediateCerts,
systemIntermediateCerts,
userRootCerts,
@@ -452,7 +456,7 @@ namespace Internal.Cryptography.Pal
candidates,
ReferenceEqualityComparer<X509Certificate2>.Instance);
- // Certificates come from 5 sources:
+ // Certificates come from 6 sources:
// 1) extraStore.
// These are cert objects that are provided by the user, we shouldn't dispose them.
// 2) the machine root store
@@ -463,8 +467,11 @@ namespace Internal.Cryptography.Pal
// These certs were either path candidates, or not. If they were, don't dispose them. Otherwise do.
// 5) the user intermediate store
// These certs were either path candidates, or not. If they were, don't dispose them. Otherwise do.
+ // 6) the user my store
+ // These certs were either path candidates, or not. If they were, don't dispose them. Otherwise do.
DisposeUnreferenced(candidatesByReference, systemIntermediateCerts);
DisposeUnreferenced(candidatesByReference, userIntermediateCerts);
+ DisposeUnreferenced(candidatesByReference, userMyCerts);
}
return candidates;
diff --git a/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/ChainPal.GetChainStatusInformation.cs b/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/ChainPal.GetChainStatusInformation.cs
index 18de38235c..2f9c40e35d 100644
--- a/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/ChainPal.GetChainStatusInformation.cs
+++ b/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/ChainPal.GetChainStatusInformation.cs
@@ -34,7 +34,7 @@ namespace Internal.Cryptography.Pal
{
Debug.Assert(index < chainStatus.Length);
- chainStatus[index].StatusInformation = GetSystemErrorString(mapping.Win32ErrorCode);
+ chainStatus[index].StatusInformation = Interop.Kernel32.GetMessage(mapping.Win32ErrorCode);
chainStatus[index].Status = mapping.ChainStatusFlag;
index++;
dwStatus &= ~mapping.Win32Flag;
@@ -60,23 +60,6 @@ namespace Internal.Cryptography.Pal
return chainStatus;
}
- private static string GetSystemErrorString(int errorCode)
- {
- StringBuilder strMessage = new StringBuilder(512);
- int dwErrorCode = Interop.localization.FormatMessage(
- FormatMessageFlags.FORMAT_MESSAGE_FROM_SYSTEM | FormatMessageFlags.FORMAT_MESSAGE_IGNORE_INSERTS,
- IntPtr.Zero,
- errorCode,
- 0,
- strMessage,
- strMessage.Capacity,
- IntPtr.Zero);
- if (dwErrorCode != 0)
- return strMessage.ToString();
- else
- return SR.Unknown_Error;
- }
-
private readonly struct X509ChainErrorMapping
{
public readonly CertTrustErrorStatus Win32Flag;
diff --git a/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/FindPal.cs b/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/FindPal.cs
index 1d4141348f..1336b5e38e 100644
--- a/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/FindPal.cs
+++ b/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/FindPal.cs
@@ -360,7 +360,7 @@ namespace Internal.Cryptography.Pal
// This needs to be kept in sync with IsCertValid in the
// Unix/OpenSSL PAL version (and potentially any other PALs that come about)
ChainPal chainPal = ChainPal.BuildChain(
- true,
+ false,
CertificatePal.FromHandle(pCertContext.DangerousGetHandle()),
null, //extraStore
null, //applicationPolicy
diff --git a/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/Native/Helpers.cs b/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/Native/Helpers.cs
index a29b265dd4..c9c192c584 100644
--- a/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/Native/Helpers.cs
+++ b/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/Native/Helpers.cs
@@ -5,13 +5,9 @@
using System;
using System.Text;
using System.Diagnostics;
-using System.Globalization;
-using System.Collections.Generic;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
-using Internal.Cryptography.Pal;
-
namespace Internal.Cryptography.Pal.Native
{
internal static class Helpers
@@ -30,41 +26,44 @@ namespace Internal.Cryptography.Pal.Native
return SafeLocalAllocHandle.InvalidHandle;
}
- // Copy the oid strings to a local list to prevent a security race condition where
+ // Copy the oid strings to a local array to prevent a security race condition where
// the OidCollection or individual oids can be modified by another thread and
// potentially cause a buffer overflow
- List<byte[]> oidStrings = new List<byte[]>();
- foreach (Oid oid in oids)
+ var oidStrings = new string[oids.Count];
+ for (int i = 0; i < oidStrings.Length; i++)
{
- byte[] oidString = oid.ValueAsAscii();
- oidStrings.Add(oidString);
+ oidStrings[i] = oids[i].Value;
}
- numOids = oidStrings.Count;
unsafe
{
- int allocationSize = checked(numOids * sizeof(void*));
- foreach (byte[] oidString in oidStrings)
+ int allocationSize = checked(oidStrings.Length * sizeof(void*));
+ foreach (string oidString in oidStrings)
{
checked
{
- allocationSize += oidString.Length + 1;
+ allocationSize += oidString.Length + 1; // Encoding.ASCII doesn't have a fallback, so it's fine to use String.Length
}
}
SafeLocalAllocHandle safeLocalAllocHandle = SafeLocalAllocHandle.Create(allocationSize);
byte** pOidPointers = (byte**)(safeLocalAllocHandle.DangerousGetHandle());
- byte* pOidContents = (byte*)(pOidPointers + numOids);
+ byte* pOidContents = (byte*)(pOidPointers + oidStrings.Length);
- for (int i = 0; i < numOids; i++)
+ for (int i = 0; i < oidStrings.Length; i++)
{
+ string oidString = oidStrings[i];
+
pOidPointers[i] = pOidContents;
- byte[] oidString = oidStrings[i];
- Marshal.Copy(oidString, 0, new IntPtr(pOidContents), oidString.Length);
+
+ int bytesWritten = Encoding.ASCII.GetBytes(oidString, new Span<byte>(pOidContents, oidString.Length));
+ Debug.Assert(bytesWritten == oidString.Length);
+
pOidContents[oidString.Length] = 0;
pOidContents += oidString.Length + 1;
}
+ numOids = oidStrings.Length;
return safeLocalAllocHandle;
}
}
diff --git a/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/Native/Primitives.cs b/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/Native/Primitives.cs
index 9853fc8023..6456bc9184 100644
--- a/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/Native/Primitives.cs
+++ b/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/Native/Primitives.cs
@@ -752,13 +752,6 @@ namespace Internal.Cryptography.Pal.Native
public Guid ChainId;
}
- [Flags]
- internal enum FormatMessageFlags : int
- {
- FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000,
- FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200,
- }
-
[StructLayout(LayoutKind.Sequential)]
internal struct CERT_CHAIN_POLICY_PARA
{
diff --git a/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/StorePal.Import.cs b/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/StorePal.Import.cs
index 07c4c1b704..7f957cfbe9 100644
--- a/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/StorePal.Import.cs
+++ b/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/StorePal.Import.cs
@@ -140,9 +140,9 @@ namespace Internal.Cryptography.Pal
// applied to the original store. This has a limit of 99 links per cert context however.
//
- foreach (X509Certificate2 certificate in certificates)
+ for (int i = 0; i < certificates.Count; i++)
{
- SafeCertContextHandle certContext = ((CertificatePal)certificate.Pal).CertContext;
+ SafeCertContextHandle certContext = ((CertificatePal)certificates[i].Pal).CertContext;
if (!Interop.crypt32.CertAddCertificateLinkToStore(certStore, certContext, CertStoreAddDisposition.CERT_STORE_ADD_ALWAYS, IntPtr.Zero))
throw Marshal.GetLastWin32Error().ToCryptographicException();
}
diff --git a/src/System.Security.Cryptography.X509Certificates/src/Resources/Strings.resx b/src/System.Security.Cryptography.X509Certificates/src/Resources/Strings.resx
index 20c4e24975..14b95dea57 100644
--- a/src/System.Security.Cryptography.X509Certificates/src/Resources/Strings.resx
+++ b/src/System.Security.Cryptography.X509Certificates/src/Resources/Strings.resx
@@ -151,6 +151,9 @@
<data name="Cryptography_ECC_NamedCurvesOnly" xml:space="preserve">
<value>Only named curves are supported on this platform.</value>
</data>
+ <data name="Cryptography_Encryption_MessageTooLong" xml:space="preserve">
+ <value>The message exceeds the maximum allowable length for the chosen options ({0}).</value>
+ </data>
<data name="Cryptography_Der_Invalid_Encoding" xml:space="preserve">
<value>ASN1 corrupted data.</value>
</data>
@@ -178,15 +181,27 @@
<data name="Cryptography_InvalidStoreHandle" xml:space="preserve">
<value>The store handle is invalid.</value>
</data>
+ <data name="Cryptography_KeyTooSmall" xml:space="preserve">
+ <value>The key is too small for the requested operation.</value>
+ </data>
+ <data name="Cryptography_OAEP_Decryption_Failed" xml:space="preserve">
+ <value>Error occurred while decoding OAEP padding.</value>
+ </data>
<data name="Cryptography_OpenInvalidHandle" xml:space="preserve">
<value>Cannot open an invalid handle.</value>
</data>
+ <data name="Cryptography_Padding_DecDataTooBig" xml:space="preserve">
+ <value>The data to be decrypted exceeds the maximum for this modulus of {0} bytes.</value>
+ </data>
<data name="Cryptography_PrivateKey_DoesNotMatch" xml:space="preserve">
<value>The provided key does not match the public key for this certificate.</value>
</data>
<data name="Cryptography_PrivateKey_WrongAlgorithm" xml:space="preserve">
<value>The provided key does not match the public key algorithm for this certificate.</value>
</data>
+ <data name="Cryptography_SignHash_WrongSize" xml:space="preserve">
+ <value>The provided hash value is not the expected size for the specified hash algorithm.</value>
+ </data>
<data name="Cryptography_Unix_X509_DisallowedStoreNotEmpty" xml:space="preserve">
<value>The Disallowed store is not supported on this platform, but already has data. All files under '{0}' must be removed.</value>
</data>
@@ -235,6 +250,9 @@
<data name="Cryptography_X509_PKCS7_NoSigner" xml:space="preserve">
<value>Cannot find the original signer.</value>
</data>
+ <data name="Cryptography_X509_StoreAddFailure" xml:space="preserve">
+ <value>The X509 certificate could not be added to the store.</value>
+ </data>
<data name="Cryptography_X509_StoreNoFileAvailable" xml:space="preserve">
<value>The X509 certificate could not be added to the store because all candidate file names were in use.</value>
</data>
diff --git a/src/System.Security.Cryptography.X509Certificates/src/System.Security.Cryptography.X509Certificates.csproj b/src/System.Security.Cryptography.X509Certificates/src/System.Security.Cryptography.X509Certificates.csproj
index a63a66ff53..d850e2e780 100644
--- a/src/System.Security.Cryptography.X509Certificates/src/System.Security.Cryptography.X509Certificates.csproj
+++ b/src/System.Security.Cryptography.X509Certificates/src/System.Security.Cryptography.X509Certificates.csproj
@@ -103,7 +103,6 @@
<Compile Include="Internal\Cryptography\Pal.Windows\Native\Helpers.cs" />
<Compile Include="Internal\Cryptography\Pal.Windows\Native\Interop.cryptoapi.cs" />
<Compile Include="Internal\Cryptography\Pal.Windows\Native\Interop.crypt32.cs" />
- <Compile Include="Internal\Cryptography\Pal.Windows\Native\Interop.localization.cs" />
<Compile Include="Internal\Cryptography\Pal.Windows\Native\Primitives.cs" />
<Compile Include="Internal\Cryptography\Pal.Windows\Native\SafeHandles.cs" />
<Compile Include="Internal\Cryptography\Pal.Windows\StorePal.cs" />
@@ -376,12 +375,18 @@
<Compile Include="$(CommonPath)\System\Security\Cryptography\DSASecurityTransforms.cs">
<Link>Common\System\Security\Cryptography\DSASecurityTransforms.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\EccSecurityTransforms.cs">
+ <Link>Common\System\Security\Cryptography\EccSecurityTransforms.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\ECDsaSecurityTransforms.cs">
<Link>Common\System\Security\Cryptography\ECDsaSecurityTransforms.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\KeyBlobHelpers.cs">
<Link>Common\System\Security\Cryptography\KeyBlobHelpers.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Security\Cryptography\RsaPaddingProcessor.cs">
+ <Link>Common\System\Security\Cryptography\RsaPaddingProcessor.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\System\Security\Cryptography\RSASecurityTransforms.cs">
<Link>Common\System\Security\Cryptography\RSASecurityTransforms.cs</Link>
</Compile>
@@ -407,7 +412,9 @@
<Compile Include="Internal\Cryptography\Pal.Unix\X500NameEncoder.cs" />
</ItemGroup>
<ItemGroup>
+ <Reference Include="System.Buffers" />
<Reference Include="System.Collections" />
+ <Reference Include="System.Collections.Concurrent" />
<Reference Include="System.Collections.NonGeneric" />
<Reference Include="System.Diagnostics.Debug" />
<Reference Include="System.Diagnostics.Tools" />
diff --git a/src/System.Security.Cryptography.X509Certificates/tests/LoadFromFileTests.cs b/src/System.Security.Cryptography.X509Certificates/tests/LoadFromFileTests.cs
index 68ec3359b8..cb7efa6df7 100644
--- a/src/System.Security.Cryptography.X509Certificates/tests/LoadFromFileTests.cs
+++ b/src/System.Security.Cryptography.X509Certificates/tests/LoadFromFileTests.cs
@@ -115,7 +115,7 @@ namespace System.Security.Cryptography.X509Certificates.Tests
byte[] thumbPrint = new byte[expectedSize + 10];
thumbPrint.AsSpan().Fill(FillByte);
- Span<byte> writeDest = thumbPrint.AsSpan().Slice(WriteOffset);
+ Span<byte> writeDest = thumbPrint.AsSpan(WriteOffset);
int bytesWritten;
// Too small.
diff --git a/src/System.Security.Cryptography.Xml/src/MatchingRefApiCompatBaseline.netstandard.txt b/src/System.Security.Cryptography.Xml/src/MatchingRefApiCompatBaseline.netstandard.txt
new file mode 100644
index 0000000000..1f4b419245
--- /dev/null
+++ b/src/System.Security.Cryptography.Xml/src/MatchingRefApiCompatBaseline.netstandard.txt
@@ -0,0 +1,2 @@
+# Type must be public in implementation for serialization to work but we don't want to expose it publicly in the contract as it isn't public on .NET Framework
+TypesMustExist : Type 'System.Security.Cryptography.Xml.CryptoSignedXmlRecursionException' does not exist in the implementation but it does exist in the contract.
diff --git a/src/System.Security.Cryptography.Xml/src/System.Security.Cryptography.Xml.csproj b/src/System.Security.Cryptography.Xml/src/System.Security.Cryptography.Xml.csproj
index c16b4e66a3..739a1c7bc0 100644
--- a/src/System.Security.Cryptography.Xml/src/System.Security.Cryptography.Xml.csproj
+++ b/src/System.Security.Cryptography.Xml/src/System.Security.Cryptography.Xml.csproj
@@ -73,7 +73,6 @@
<Compile Include="System\Security\Cryptography\Xml\TransformChain.cs" />
<Compile Include="System\Security\Cryptography\Xml\TransformInputType.cs" />
<Compile Include="System\Security\Cryptography\Xml\Utils.cs" />
- <Compile Include="System\Security\Cryptography\Xml\X509IssuerSerial.cs" />
<Compile Include="System\Security\Cryptography\Xml\XmlDecryptionTransform.cs" />
<Compile Include="System\Security\Cryptography\Xml\XmlDsigBase64Transform.cs" />
<Compile Include="System\Security\Cryptography\Xml\XmlDsigC14NTransform.cs" />
@@ -106,6 +105,7 @@
<Reference Include="System.Security.Cryptography.Csp" />
<Reference Include="System.Security.Cryptography.Encoding" />
<Reference Include="System.Security.Cryptography.Primitives" />
+ <Reference Include="System.Security.Cryptography.Pkcs" />
<Reference Include="System.Security.Cryptography.X509Certificates" />
<Reference Include="System.Security.Permissions" />
<Reference Include="System.Text.Encoding.Extensions" />
diff --git a/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/CanonicalXml.cs b/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/CanonicalXml.cs
index c043fcd14d..afe1bb1cc2 100644
--- a/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/CanonicalXml.cs
+++ b/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/CanonicalXml.cs
@@ -118,7 +118,7 @@ namespace System.Security.Cryptography.Xml
internal byte[] GetDigestedBytes(HashAlgorithm hash)
{
_c14nDoc.WriteHash(hash, DocPosition.BeforeRootElement, _ancMgr);
- hash.TransformFinalBlock(new byte[0], 0, 0);
+ hash.TransformFinalBlock(Array.Empty<byte>(), 0, 0);
byte[] res = (byte[])hash.Hash.Clone();
// reinitialize the hash so it is still usable after the call
hash.Initialize();
diff --git a/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/ExcCanonicalXml.cs b/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/ExcCanonicalXml.cs
index 2b1bc1d2d4..bd91b30166 100644
--- a/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/ExcCanonicalXml.cs
+++ b/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/ExcCanonicalXml.cs
@@ -66,7 +66,7 @@ namespace System.Security.Cryptography.Xml
internal byte[] GetDigestedBytes(HashAlgorithm hash)
{
_c14nDoc.WriteHash(hash, DocPosition.BeforeRootElement, _ancMgr);
- hash.TransformFinalBlock(new byte[0], 0, 0);
+ hash.TransformFinalBlock(Array.Empty<byte>(), 0, 0);
byte[] res = (byte[])hash.Hash.Clone();
// reinitialize the hash so it is still usable after the call
hash.Initialize();
diff --git a/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/KeyInfoX509Data.cs b/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/KeyInfoX509Data.cs
index f377bd08e9..67a4b87230 100644
--- a/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/KeyInfoX509Data.cs
+++ b/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/KeyInfoX509Data.cs
@@ -16,7 +16,7 @@ namespace System.Security.Cryptography.Xml
{
public class KeyInfoX509Data : KeyInfoClause
{
- // An array of certificates representing the certificate chain
+ // An array of certificates representing the certificate chain
private ArrayList _certificates = null;
// An array of issuer serial structs
private ArrayList _issuerSerials = null;
@@ -167,7 +167,7 @@ namespace System.Security.Cryptography.Xml
if (_issuerSerials == null)
_issuerSerials = new ArrayList();
- _issuerSerials.Add(new X509IssuerSerial(issuerName, h.ToString()));
+ _issuerSerials.Add(Utils.CreateX509IssuerSerial(issuerName, h.ToString()));
}
// When we load an X509Data from Xml, we know the serial number is in decimal representation.
@@ -175,7 +175,7 @@ namespace System.Security.Cryptography.Xml
{
if (_issuerSerials == null)
_issuerSerials = new ArrayList();
- _issuerSerials.Add(new X509IssuerSerial(issuerName, serialNumber));
+ _issuerSerials.Add(Utils.CreateX509IssuerSerial(issuerName, serialNumber));
}
public byte[] CRL
diff --git a/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Utils.cs b/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Utils.cs
index 0eda167c95..0ec93ebdbe 100644
--- a/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Utils.cs
+++ b/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Utils.cs
@@ -309,7 +309,7 @@ namespace System.Security.Cryptography.Xml
// initialize the return value
discardComments = true;
- // Deal with XPointer of type #xpointer(id("ID")). Other XPointer support isn't handled here and is anyway optional
+ // Deal with XPointer of type #xpointer(id("ID")). Other XPointer support isn't handled here and is anyway optional
if (idref.StartsWith("xpointer(id(", StringComparison.Ordinal))
{
int startId = idref.IndexOf("id(", StringComparison.Ordinal);
@@ -328,7 +328,7 @@ namespace System.Security.Cryptography.Xml
{
string idref = uri.Substring(1);
- // Deal with XPointer of type #xpointer(id("ID")). Other XPointer support isn't handled here and is anyway optional
+ // Deal with XPointer of type #xpointer(id("ID")). Other XPointer support isn't handled here and is anyway optional
if (idref.StartsWith("xpointer(id(", StringComparison.Ordinal))
{
int startId = idref.IndexOf("id(", StringComparison.Ordinal);
@@ -356,9 +356,9 @@ namespace System.Security.Cryptography.Xml
}
}
- // Writes one stream (starting from the current position) into
- // an output stream, connecting them up and reading until
- // hitting the end of the input stream.
+ // Writes one stream (starting from the current position) into
+ // an output stream, connecting them up and reading until
+ // hitting the end of the input stream.
// returns the number of bytes copied
internal static long Pump(Stream input, Stream output)
{
@@ -482,7 +482,7 @@ namespace System.Security.Cryptography.Xml
}
}
- // This method gets the attributes that should be propagated
+ // This method gets the attributes that should be propagated
internal static CanonicalXmlNodeList GetPropagatedAttributes(XmlElement elem)
{
if (elem == null)
@@ -606,6 +606,21 @@ namespace System.Security.Cryptography.Xml
return index + 1;
}
+ // Mimic the behavior of the X509IssuerSerial constructor with null and empty checks
+ internal static X509IssuerSerial CreateX509IssuerSerial(string issuerName, string serialNumber)
+ {
+ if (issuerName == null || issuerName.Length == 0)
+ throw new ArgumentException(SR.Arg_EmptyOrNullString, nameof(issuerName));
+ if (serialNumber == null || serialNumber.Length == 0)
+ throw new ArgumentException(SR.Arg_EmptyOrNullString, nameof(serialNumber));
+
+ return new X509IssuerSerial()
+ {
+ IssuerName = issuerName,
+ SerialNumber = serialNumber
+ };
+ }
+
internal static X509Certificate2Collection BuildBagOfCerts(KeyInfoX509Data keyInfoX509Data, CertUsageType certUsageType)
{
X509Certificate2Collection collection = new X509Certificate2Collection();
@@ -620,7 +635,7 @@ namespace System.Security.Cryptography.Xml
collection.Add(certificate);
break;
case CertUsageType.Decryption:
- decryptionIssuerSerials.Add(new X509IssuerSerial(certificate.IssuerName.Name, certificate.SerialNumber));
+ decryptionIssuerSerials.Add(CreateX509IssuerSerial(certificate.IssuerName.Name, certificate.SerialNumber));
break;
}
}
diff --git a/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/X509IssuerSerial.cs b/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/X509IssuerSerial.cs
deleted file mode 100644
index 46454a4daf..0000000000
--- a/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/X509IssuerSerial.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections;
-using System.Runtime.InteropServices;
-using System.Security.Cryptography;
-using System.Security.Cryptography.X509Certificates;
-using System.Text;
-using System.Xml;
-
-namespace System.Security.Cryptography.Xml
-{
- public struct X509IssuerSerial
- {
- private string _issuerName;
- private string _serialNumber;
-
- internal X509IssuerSerial(string issuerName, string serialNumber)
- {
- if (issuerName == null || issuerName.Length == 0)
- throw new ArgumentException(SR.Arg_EmptyOrNullString, nameof(issuerName));
- if (serialNumber == null || serialNumber.Length == 0)
- throw new ArgumentException(SR.Arg_EmptyOrNullString, nameof(serialNumber));
- _issuerName = issuerName;
- _serialNumber = serialNumber;
- }
-
-
- public string IssuerName
- {
- get
- {
- return _issuerName;
- }
- set
- {
- _issuerName = value;
- }
- }
-
- public string SerialNumber
- {
- get
- {
- return _serialNumber;
- }
- set
- {
- _serialNumber = value;
- }
- }
- }
-}
diff --git a/src/System.Security.Cryptography.Xml/tests/AssertCrypto.cs b/src/System.Security.Cryptography.Xml/tests/AssertCrypto.cs
index e34ed93f0c..35f02232f0 100644
--- a/src/System.Security.Cryptography.Xml/tests/AssertCrypto.cs
+++ b/src/System.Security.Cryptography.Xml/tests/AssertCrypto.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// MonoTests.System.Security.Cryptography.Xml.AssertCrypto.cs
//
diff --git a/src/System.Security.Cryptography.Xml/tests/DSAKeyValueTest.cs b/src/System.Security.Cryptography.Xml/tests/DSAKeyValueTest.cs
index 0bd33ca268..005b7ca729 100644
--- a/src/System.Security.Cryptography.Xml/tests/DSAKeyValueTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/DSAKeyValueTest.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// DSAKeyValueTest.cs - Test Cases for DSAKeyValue
//
diff --git a/src/System.Security.Cryptography.Xml/tests/DataObjectTest.cs b/src/System.Security.Cryptography.Xml/tests/DataObjectTest.cs
index b6a6c5b4de..f8190fe638 100644
--- a/src/System.Security.Cryptography.Xml/tests/DataObjectTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/DataObjectTest.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// DataObjectTest.cs - Test Cases for DataObject
//
diff --git a/src/System.Security.Cryptography.Xml/tests/DataReferenceTest.cs b/src/System.Security.Cryptography.Xml/tests/DataReferenceTest.cs
index 83e3fa2823..86cfc46162 100644
--- a/src/System.Security.Cryptography.Xml/tests/DataReferenceTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/DataReferenceTest.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// DataReferenceTest.cs
//
diff --git a/src/System.Security.Cryptography.Xml/tests/EncryptedXmlTest.cs b/src/System.Security.Cryptography.Xml/tests/EncryptedXmlTest.cs
index 7e9f2ffeca..b004fcd5e6 100644
--- a/src/System.Security.Cryptography.Xml/tests/EncryptedXmlTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/EncryptedXmlTest.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// EncryptedXmlTest.cs
//
diff --git a/src/System.Security.Cryptography.Xml/tests/EncryptionMethodTests.cs b/src/System.Security.Cryptography.Xml/tests/EncryptionMethodTests.cs
index c272f20e74..ab725f2673 100644
--- a/src/System.Security.Cryptography.Xml/tests/EncryptionMethodTests.cs
+++ b/src/System.Security.Cryptography.Xml/tests/EncryptionMethodTests.cs
@@ -45,10 +45,7 @@ namespace System.Security.Cryptography.Xml.Tests
public void KeySize_SetNegativeValue_ThrowsArgumentOutOfRangeException(int value)
{
EncryptionMethod method = new EncryptionMethod();
- if (PlatformDetection.IsFullFramework)
- AssertExtensions.Throws<ArgumentOutOfRangeException>("The key size should be a non negative integer.", () => method.KeySize = value);
- else
- AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => method.KeySize = value);
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("value", null, () => method.KeySize = value);
}
[Theory]
diff --git a/src/System.Security.Cryptography.Xml/tests/KeyInfoNameTest.cs b/src/System.Security.Cryptography.Xml/tests/KeyInfoNameTest.cs
index cc58e455d3..eff7bad8a2 100644
--- a/src/System.Security.Cryptography.Xml/tests/KeyInfoNameTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/KeyInfoNameTest.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// KeyInfoNameTest.cs - Test Cases for KeyInfoName
//
diff --git a/src/System.Security.Cryptography.Xml/tests/KeyInfoNodeTest.cs b/src/System.Security.Cryptography.Xml/tests/KeyInfoNodeTest.cs
index 6ef942a8a5..790fa8b9be 100644
--- a/src/System.Security.Cryptography.Xml/tests/KeyInfoNodeTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/KeyInfoNodeTest.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// KeyInfoNodeTest.cs - Test Cases for KeyInfoNode
//
diff --git a/src/System.Security.Cryptography.Xml/tests/KeyInfoRetrievalMethodTest.cs b/src/System.Security.Cryptography.Xml/tests/KeyInfoRetrievalMethodTest.cs
index 4ddbb3483b..4a46d4729d 100644
--- a/src/System.Security.Cryptography.Xml/tests/KeyInfoRetrievalMethodTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/KeyInfoRetrievalMethodTest.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// KeyInfoRetrievalMethodTest.cs - Test Cases for KeyInfoRetrievalMethod
//
diff --git a/src/System.Security.Cryptography.Xml/tests/KeyInfoTest.cs b/src/System.Security.Cryptography.Xml/tests/KeyInfoTest.cs
index 96ef5ef99d..4fc06bb314 100644
--- a/src/System.Security.Cryptography.Xml/tests/KeyInfoTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/KeyInfoTest.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// KeyInfoTest.cs - Test Cases for KeyInfo
//
diff --git a/src/System.Security.Cryptography.Xml/tests/KeyInfoX509DataTest.cs b/src/System.Security.Cryptography.Xml/tests/KeyInfoX509DataTest.cs
index a4b70fc73c..f80b991d98 100644
--- a/src/System.Security.Cryptography.Xml/tests/KeyInfoX509DataTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/KeyInfoX509DataTest.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// KeyInfoX509DataTest.cs - Test Cases for KeyInfoX509Data
//
diff --git a/src/System.Security.Cryptography.Xml/tests/RSAKeyValueTest.cs b/src/System.Security.Cryptography.Xml/tests/RSAKeyValueTest.cs
index 52463f0ff0..2048a4884d 100644
--- a/src/System.Security.Cryptography.Xml/tests/RSAKeyValueTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/RSAKeyValueTest.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// RSAKeyValueTest.cs - Test Cases for RSAKeyValue
//
diff --git a/src/System.Security.Cryptography.Xml/tests/ReferenceTest.cs b/src/System.Security.Cryptography.Xml/tests/ReferenceTest.cs
index ba6d4f31aa..0cbec07cff 100644
--- a/src/System.Security.Cryptography.Xml/tests/ReferenceTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/ReferenceTest.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// ReferenceTest.cs - Test Cases for Reference
//
diff --git a/src/System.Security.Cryptography.Xml/tests/SignatureTest.cs b/src/System.Security.Cryptography.Xml/tests/SignatureTest.cs
index 874e7de794..60415eb8a2 100644
--- a/src/System.Security.Cryptography.Xml/tests/SignatureTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/SignatureTest.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// SignatureTest.cs - Test Cases for SignedXml
//
diff --git a/src/System.Security.Cryptography.Xml/tests/SignedInfoTest.cs b/src/System.Security.Cryptography.Xml/tests/SignedInfoTest.cs
index f2d64dab40..2e1502ac76 100644
--- a/src/System.Security.Cryptography.Xml/tests/SignedInfoTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/SignedInfoTest.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// SignedInfoTest.cs - Test Cases for SignedInfo
//
diff --git a/src/System.Security.Cryptography.Xml/tests/SignedXmlTest.cs b/src/System.Security.Cryptography.Xml/tests/SignedXmlTest.cs
index bdbf97d5a3..d18ed6baf6 100644
--- a/src/System.Security.Cryptography.Xml/tests/SignedXmlTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/SignedXmlTest.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// SignedXmlTest.cs - Test Cases for SignedXml
//
diff --git a/src/System.Security.Cryptography.Xml/tests/TransformChainTest.cs b/src/System.Security.Cryptography.Xml/tests/TransformChainTest.cs
index cccf97b3a3..4421363d86 100644
--- a/src/System.Security.Cryptography.Xml/tests/TransformChainTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/TransformChainTest.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// TransformChainTest.cs - Test Cases for TransformChain
//
diff --git a/src/System.Security.Cryptography.Xml/tests/TransformTest.cs b/src/System.Security.Cryptography.Xml/tests/TransformTest.cs
index 3f5ce535be..24927f31b3 100644
--- a/src/System.Security.Cryptography.Xml/tests/TransformTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/TransformTest.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// Unit tests for Transform
//
diff --git a/src/System.Security.Cryptography.Xml/tests/XmlDecryptionTransformTest.cs b/src/System.Security.Cryptography.Xml/tests/XmlDecryptionTransformTest.cs
index adcc6dcb14..5b2051e3a6 100644
--- a/src/System.Security.Cryptography.Xml/tests/XmlDecryptionTransformTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/XmlDecryptionTransformTest.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// Unit tests for XmlDecryptionTransform
//
diff --git a/src/System.Security.Cryptography.Xml/tests/XmlDsigBase64TransformTest.cs b/src/System.Security.Cryptography.Xml/tests/XmlDsigBase64TransformTest.cs
index 262f92cea3..e47c9c701f 100644
--- a/src/System.Security.Cryptography.Xml/tests/XmlDsigBase64TransformTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/XmlDsigBase64TransformTest.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// XmlDsigBase64TransformTest.cs - Test Cases for XmlDsigBase64Transform
//
diff --git a/src/System.Security.Cryptography.Xml/tests/XmlDsigC14NTransformTest.cs b/src/System.Security.Cryptography.Xml/tests/XmlDsigC14NTransformTest.cs
index fd5366f093..8943993a6f 100644
--- a/src/System.Security.Cryptography.Xml/tests/XmlDsigC14NTransformTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/XmlDsigC14NTransformTest.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// XmlDsigC14NTransformTest.cs - Test Cases for XmlDsigC14NTransform
//
diff --git a/src/System.Security.Cryptography.Xml/tests/XmlDsigC14NWithCommentsTransformTest.cs b/src/System.Security.Cryptography.Xml/tests/XmlDsigC14NWithCommentsTransformTest.cs
index d5889ac43f..7802020b78 100644
--- a/src/System.Security.Cryptography.Xml/tests/XmlDsigC14NWithCommentsTransformTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/XmlDsigC14NWithCommentsTransformTest.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// XmlDsigC14NWithCommentsTransformTest.cs
// - Test Cases for XmlDsigC14NWithCommentsTransform
diff --git a/src/System.Security.Cryptography.Xml/tests/XmlDsigEnvelopedSignatureTransformTest.cs b/src/System.Security.Cryptography.Xml/tests/XmlDsigEnvelopedSignatureTransformTest.cs
index 9bc2bb0581..3c8278e9d4 100644
--- a/src/System.Security.Cryptography.Xml/tests/XmlDsigEnvelopedSignatureTransformTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/XmlDsigEnvelopedSignatureTransformTest.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// XmlDsigEnvelopedSignatureTransformTest.cs
//
diff --git a/src/System.Security.Cryptography.Xml/tests/XmlDsigExcC14NTransformTest.cs b/src/System.Security.Cryptography.Xml/tests/XmlDsigExcC14NTransformTest.cs
index 26f82ffab6..bb4bdd58de 100644
--- a/src/System.Security.Cryptography.Xml/tests/XmlDsigExcC14NTransformTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/XmlDsigExcC14NTransformTest.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// XmlDsigExcC14NTransformTest.cs - Test Cases for XmlDsigExcC14NTransform
//
diff --git a/src/System.Security.Cryptography.Xml/tests/XmlDsigExcC14NWithCommentsTransformTest.cs b/src/System.Security.Cryptography.Xml/tests/XmlDsigExcC14NWithCommentsTransformTest.cs
index 5454d6fcd9..0b9683c26b 100644
--- a/src/System.Security.Cryptography.Xml/tests/XmlDsigExcC14NWithCommentsTransformTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/XmlDsigExcC14NWithCommentsTransformTest.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// XmlDsigExcC14NWithCommentsTransformTest.cs - Test Cases for
// XmlDsigExcC14NWithCommentsTransform
diff --git a/src/System.Security.Cryptography.Xml/tests/XmlDsigXPathTransformTest.cs b/src/System.Security.Cryptography.Xml/tests/XmlDsigXPathTransformTest.cs
index d088954f33..8075df3c28 100644
--- a/src/System.Security.Cryptography.Xml/tests/XmlDsigXPathTransformTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/XmlDsigXPathTransformTest.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// XmlDsigXPathTransformTest.cs - Test Cases for XmlDsigXPathTransform
//
diff --git a/src/System.Security.Cryptography.Xml/tests/XmlDsigXsltTransformTest.cs b/src/System.Security.Cryptography.Xml/tests/XmlDsigXsltTransformTest.cs
index 90abb4928c..027143b018 100644
--- a/src/System.Security.Cryptography.Xml/tests/XmlDsigXsltTransformTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/XmlDsigXsltTransformTest.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// XmlDsigXsltTransformTest.cs - Test Cases for XmlDsigXsltTransform
//
diff --git a/src/System.Security.Cryptography.Xml/tests/XmlLicenseTransformTest.cs b/src/System.Security.Cryptography.Xml/tests/XmlLicenseTransformTest.cs
index 0f6e6114dd..480ed1782c 100644
--- a/src/System.Security.Cryptography.Xml/tests/XmlLicenseTransformTest.cs
+++ b/src/System.Security.Cryptography.Xml/tests/XmlLicenseTransformTest.cs
@@ -1,3 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// See the LICENSE file in the project root for more information
//
// XmlLicenseTransformTest.cs - Test Cases for XmlLicenseTransform
//
diff --git a/src/System.Security.Permissions/ref/Configurations.props b/src/System.Security.Permissions/ref/Configurations.props
index c398e42e89..d9777d8275 100644
--- a/src/System.Security.Permissions/ref/Configurations.props
+++ b/src/System.Security.Permissions/ref/Configurations.props
@@ -3,6 +3,7 @@
<PropertyGroup>
<BuildConfigurations>
netstandard;
+ netfx;
</BuildConfigurations>
</PropertyGroup>
</Project> \ No newline at end of file
diff --git a/src/System.Security.Permissions/ref/System.Security.Permissions.cs b/src/System.Security.Permissions/ref/System.Security.Permissions.cs
index 66c2dfdaf4..d54444edf0 100644
--- a/src/System.Security.Permissions/ref/System.Security.Permissions.cs
+++ b/src/System.Security.Permissions/ref/System.Security.Permissions.cs
@@ -1571,6 +1571,7 @@ namespace System.Security.Policy
public override System.Security.Policy.PolicyStatement Resolve(System.Security.Policy.Evidence evidence) { throw null; }
public override System.Security.Policy.CodeGroup ResolveMatchingCodeGroups(System.Security.Policy.Evidence evidence) { throw null; }
}
+ [System.ObsoleteAttribute("This type is obsolete. See http://go.microsoft.com/fwlink/?LinkID=155570 for more information.")]
public sealed partial class FirstMatchCodeGroup : System.Security.Policy.CodeGroup
{
public FirstMatchCodeGroup(System.Security.Policy.IMembershipCondition membershipCondition, System.Security.Policy.PolicyStatement policy) : base(default(System.Security.Policy.IMembershipCondition), default(System.Security.Policy.PolicyStatement)) { }
@@ -1661,6 +1662,7 @@ namespace System.Security.Policy
public override System.Security.Policy.PolicyStatement Resolve(System.Security.Policy.Evidence evidence) { throw null; }
public override System.Security.Policy.CodeGroup ResolveMatchingCodeGroups(System.Security.Policy.Evidence evidence) { throw null; }
}
+ [System.ObsoleteAttribute("This type is obsolete. See http://go.microsoft.com/fwlink/?LinkID=155570 for more information.")]
public sealed partial class PermissionRequestEvidence : System.Security.Policy.EvidenceBase
{
public PermissionRequestEvidence(System.Security.PermissionSet request, System.Security.PermissionSet optional, System.Security.PermissionSet denied) { }
@@ -1693,6 +1695,7 @@ namespace System.Security.Policy
public void AddFullTrustAssembly(System.Security.Policy.StrongNameMembershipCondition snMC) { }
public void AddNamedPermissionSet(System.Security.NamedPermissionSet permSet) { }
public System.Security.NamedPermissionSet ChangeNamedPermissionSet(string name, System.Security.PermissionSet pSet) { throw null; }
+ [System.ObsoleteAttribute("AppDomain policy levels are obsolete. See http://go.microsoft.com/fwlink/?LinkID=155570 for more information.")]
public static System.Security.Policy.PolicyLevel CreateAppDomainLevel() { throw null; }
public void FromXml(System.Security.SecurityElement e) { }
public System.Security.NamedPermissionSet GetNamedPermissionSet(string name) { throw null; }
@@ -1825,6 +1828,7 @@ namespace System.Security.Policy
Run = 2,
Upgrade = 1,
}
+ [System.ObsoleteAttribute("This type is obsolete. See http://go.microsoft.com/fwlink/?LinkID=155570 for more information.")]
public sealed partial class UnionCodeGroup : System.Security.Policy.CodeGroup
{
public UnionCodeGroup(System.Security.Policy.IMembershipCondition membershipCondition, System.Security.Policy.PolicyStatement policy) : base(default(System.Security.Policy.IMembershipCondition), default(System.Security.Policy.PolicyStatement)) { }
@@ -1883,6 +1887,59 @@ namespace System.Security.Policy
public System.Security.SecurityElement ToXml(System.Security.Policy.PolicyLevel level) { throw null; }
}
}
+namespace System.ServiceProcess
+{
+ public sealed partial class ServiceControllerPermission : System.Security.Permissions.ResourcePermissionBase
+ {
+ public ServiceControllerPermission() { }
+ public ServiceControllerPermission(System.ServiceProcess.ServiceControllerPermissionAccess permissionAccess, string machineName, string serviceName) { }
+ public ServiceControllerPermission(System.ServiceProcess.ServiceControllerPermissionEntry[] permissionAccessEntries) { }
+ public ServiceControllerPermission(System.Security.Permissions.PermissionState state) { }
+ public System.ServiceProcess.ServiceControllerPermissionEntryCollection PermissionEntries { get { throw null; } }
+ }
+ [System.Flags]
+ public enum ServiceControllerPermissionAccess
+ {
+ None = 0,
+ Browse = 1 << 1,
+ Control = 1 << 2 | Browse,
+ }
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class | AttributeTargets.Struct
+ | AttributeTargets.Assembly | AttributeTargets.Event, AllowMultiple = true, Inherited = false)]
+ public partial class ServiceControllerPermissionAttribute : System.Security.Permissions.CodeAccessSecurityAttribute
+ {
+ public ServiceControllerPermissionAttribute(System.Security.Permissions.SecurityAction action) : base(action) { }
+ public string MachineName { get { throw null; } set { } }
+ public System.ServiceProcess.ServiceControllerPermissionAccess PermissionAccess { get { throw null; } set { } }
+ public string ServiceName { get { throw null; } set { } }
+ public override System.Security.IPermission CreatePermission() { throw null; }
+ }
+ public partial class ServiceControllerPermissionEntry
+ {
+ public ServiceControllerPermissionEntry() { }
+ public ServiceControllerPermissionEntry(System.ServiceProcess.ServiceControllerPermissionAccess permissionAccess, string machineName, string serviceName) { }
+ public string MachineName { get { throw null; } }
+ public System.ServiceProcess.ServiceControllerPermissionAccess PermissionAccess { get { throw null; } }
+ public string ServiceName { get { throw null; } }
+ }
+ public sealed class ServiceControllerPermissionEntryCollection : System.Collections.CollectionBase
+ {
+ internal ServiceControllerPermissionEntryCollection() { }
+ public System.ServiceProcess.ServiceControllerPermissionEntry this[int index] { get { throw null; } set { } }
+ public int Add(System.ServiceProcess.ServiceControllerPermissionEntry value) { throw null; }
+ public void AddRange(System.ServiceProcess.ServiceControllerPermissionEntry[] value) { }
+ public void AddRange(System.ServiceProcess.ServiceControllerPermissionEntryCollection value) { }
+ public bool Contains(System.ServiceProcess.ServiceControllerPermissionEntry value) { throw null; }
+ public void CopyTo(System.ServiceProcess.ServiceControllerPermissionEntry[] array, int index) { }
+ public int IndexOf(System.ServiceProcess.ServiceControllerPermissionEntry value) { throw null; }
+ public void Insert(int index, System.ServiceProcess.ServiceControllerPermissionEntry value) { }
+ protected override void OnClear() { }
+ protected override void OnInsert(int index, object value) { }
+ protected override void OnRemove(int index, object value) { }
+ protected override void OnSet(int index, object oldValue, object newValue) { }
+ public void Remove(System.ServiceProcess.ServiceControllerPermissionEntry value) { }
+ }
+}
namespace System.Transactions
{
public sealed partial class DistributedTransactionPermission : System.Security.CodeAccessPermission, System.Security.Permissions.IUnrestrictedPermission
diff --git a/src/System.Security.Permissions/ref/System.Security.Permissions.csproj b/src/System.Security.Permissions/ref/System.Security.Permissions.csproj
index 53bad00887..b3c83900d7 100644
--- a/src/System.Security.Permissions/ref/System.Security.Permissions.csproj
+++ b/src/System.Security.Permissions/ref/System.Security.Permissions.csproj
@@ -3,16 +3,26 @@
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
<ProjectGuid>{07CAF142-B259-418E-86EF-C4BD8B50253E}</ProjectGuid>
- <!-- UAPvNext is not yet mapped to netstandard2.0, manually duplicate this ref -->
- <PackageTargetFramework>netstandard2.0;$(UAPvNextTFM)</PackageTargetFramework>
+ <IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'netfx'">true</IsPartialFacadeAssembly>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="System.Security.Permissions.cs" />
- <SuppressPackageTargetFrameworkCompatibility Include="$(UAPvNextTFM)" />
</ItemGroup>
- <ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)' == 'netfx'">
+ <Reference Include="mscorlib" />
+ <Reference Include="System" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Data.OracleClient" />
+ <Reference Include="System.Drawing" />
+ <Reference Include="System.Net" />
+ <Reference Include="System.ServiceProcess" />
+ <Reference Include="System.Transactions" />
+ </ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)' != 'netfx'">
<ProjectReference Include="..\..\System.Security.AccessControl\ref\System.Security.AccessControl.csproj" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
diff --git a/src/System.Security.Permissions/src/Resources/Strings.resx b/src/System.Security.Permissions/src/Resources/Strings.resx
index fa01deef12..28da01bfd3 100644
--- a/src/System.Security.Permissions/src/Resources/Strings.resx
+++ b/src/System.Security.Permissions/src/Resources/Strings.resx
@@ -82,4 +82,4 @@
<data name="PlatformNotSupported_CAS" xml:space="preserve">
<value>Code Access Security is not supported on this platform.</value>
</data>
-</root>
+</root> \ No newline at end of file
diff --git a/src/System.Security.Permissions/src/System.Security.Permissions.csproj b/src/System.Security.Permissions/src/System.Security.Permissions.csproj
index 56e6f6e0c2..45a6bc5408 100644
--- a/src/System.Security.Permissions/src/System.Security.Permissions.csproj
+++ b/src/System.Security.Permissions/src/System.Security.Permissions.csproj
@@ -6,7 +6,6 @@
<RootNamespace>System.Security.Permissions</RootNamespace>
<AssemblyName>System.Security.Permissions</AssemblyName>
<IsPartialFacadeAssembly>true</IsPartialFacadeAssembly>
- <PackageAsRefAndLib Condition="'$(TargetGroup)' == 'netfx'">true</PackageAsRefAndLib>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Release|AnyCPU'" />
@@ -170,6 +169,11 @@
<Compile Include="System\Security\SecurityState.cs" />
<Compile Include="System\Security\SecurityZone.cs" />
<Compile Include="System\Security\XmlSyntaxException.cs" />
+ <Compile Include="System\ServiceProcess\ServiceControllerPermission.cs" />
+ <Compile Include="System\ServiceProcess\ServiceControllerPermissionAccess.cs" />
+ <Compile Include="System\ServiceProcess\ServiceControllerPermissionAttribute.cs" />
+ <Compile Include="System\ServiceProcess\ServiceControllerPermissionEntry.cs" />
+ <Compile Include="System\ServiceProcess\ServiceControllerPermissionEntryCollection.cs" />
<Compile Include="System\Transactions\DistributedTransactionPermission.cs" />
<Compile Include="System\Transactions\DistributedTransactionPermissionAttribute.cs" />
</ItemGroup>
@@ -181,6 +185,7 @@
<Reference Include="System.Drawing" />
<Reference Include="System.Net" />
<Reference Include="System.Transactions" />
+ <Reference Include="System.ServiceProcess" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Security.AccessControl" />
diff --git a/src/System.Security.Permissions/src/System/Security/Permissions/PrincipalPermission.cs b/src/System.Security.Permissions/src/System/Security/Permissions/PrincipalPermission.cs
index 913ebd17b3..c410ca27ea 100644
--- a/src/System.Security.Permissions/src/System/Security/Permissions/PrincipalPermission.cs
+++ b/src/System.Security.Permissions/src/System/Security/Permissions/PrincipalPermission.cs
@@ -79,7 +79,7 @@ namespace System.Security.Permissions
}
else if (!VerifyType(target))
{
- throw new ArgumentException(SR.Argument_WrongType, GetType().FullName);
+ throw new ArgumentException(SR.Format(SR.Argument_WrongType, GetType().FullName), nameof(target));
}
PrincipalPermission operand = (PrincipalPermission)target;
@@ -122,7 +122,7 @@ namespace System.Security.Permissions
}
else if (!VerifyType(target))
{
- throw new ArgumentException(SR.Argument_WrongType, GetType().FullName);
+ throw new ArgumentException(SR.Format(SR.Argument_WrongType, GetType().FullName), nameof(target));
}
else if (IsUnrestricted())
{
@@ -179,7 +179,7 @@ namespace System.Security.Permissions
}
else if (!VerifyType(other))
{
- throw new ArgumentException(SR.Argument_WrongType, GetType().FullName);
+ throw new ArgumentException(SR.Format(SR.Argument_WrongType, GetType().FullName), nameof(other));
}
PrincipalPermission operand = (PrincipalPermission)other;
@@ -292,7 +292,7 @@ namespace System.Security.Permissions
}
}
else
- _idArray = new IDRole[0];
+ _idArray = Array.Empty<IDRole>();
}
public override string ToString()
diff --git a/src/System.Security.Permissions/src/System/Security/Policy/FirstMatchCodeGroup.cs b/src/System.Security.Permissions/src/System/Security/Policy/FirstMatchCodeGroup.cs
index e53f97c6ba..be8691e2c4 100644
--- a/src/System.Security.Permissions/src/System/Security/Policy/FirstMatchCodeGroup.cs
+++ b/src/System.Security.Permissions/src/System/Security/Policy/FirstMatchCodeGroup.cs
@@ -4,7 +4,7 @@
namespace System.Security.Policy
{
- [Serializable]
+ [Obsolete("This type is obsolete. See http://go.microsoft.com/fwlink/?LinkID=155570 for more information.")]
public sealed partial class FirstMatchCodeGroup : CodeGroup
{
public FirstMatchCodeGroup(IMembershipCondition membershipCondition, PolicyStatement policy) : base(default(IMembershipCondition), default(PolicyStatement)) { }
diff --git a/src/System.Security.Permissions/src/System/Security/Policy/PermissionRequestEvidence.cs b/src/System.Security.Permissions/src/System/Security/Policy/PermissionRequestEvidence.cs
index 629c625fa9..4d8cd6b6a4 100644
--- a/src/System.Security.Permissions/src/System/Security/Policy/PermissionRequestEvidence.cs
+++ b/src/System.Security.Permissions/src/System/Security/Policy/PermissionRequestEvidence.cs
@@ -4,7 +4,7 @@
namespace System.Security.Policy
{
- [Serializable]
+ [Obsolete("This type is obsolete. See http://go.microsoft.com/fwlink/?LinkID=155570 for more information.")]
public sealed partial class PermissionRequestEvidence : EvidenceBase
{
public PermissionRequestEvidence(PermissionSet request, PermissionSet optional, PermissionSet denied) { }
diff --git a/src/System.Security.Permissions/src/System/Security/Policy/PolicyLevel.cs b/src/System.Security.Permissions/src/System/Security/Policy/PolicyLevel.cs
index 350a0e7f97..1af8f36ac3 100644
--- a/src/System.Security.Permissions/src/System/Security/Policy/PolicyLevel.cs
+++ b/src/System.Security.Permissions/src/System/Security/Policy/PolicyLevel.cs
@@ -23,6 +23,7 @@ namespace System.Security.Policy
public void AddFullTrustAssembly(StrongNameMembershipCondition snMC) { }
public void AddNamedPermissionSet(NamedPermissionSet permSet) { }
public NamedPermissionSet ChangeNamedPermissionSet(string name, PermissionSet pSet) { return default(NamedPermissionSet); }
+ [Obsolete("AppDomain policy levels are obsolete. See http://go.microsoft.com/fwlink/?LinkID=155570 for more information.")]
public static PolicyLevel CreateAppDomainLevel() { return default(PolicyLevel); }
public void FromXml(SecurityElement e) { }
public NamedPermissionSet GetNamedPermissionSet(string name) { return default(NamedPermissionSet); }
diff --git a/src/System.Security.Permissions/src/System/Security/Policy/UnionCodeGroup.cs b/src/System.Security.Permissions/src/System/Security/Policy/UnionCodeGroup.cs
index 5c63b20035..ac249fe359 100644
--- a/src/System.Security.Permissions/src/System/Security/Policy/UnionCodeGroup.cs
+++ b/src/System.Security.Permissions/src/System/Security/Policy/UnionCodeGroup.cs
@@ -4,7 +4,7 @@
namespace System.Security.Policy
{
- [Serializable]
+ [Obsolete("This type is obsolete. See http://go.microsoft.com/fwlink/?LinkID=155570 for more information.")]
public sealed partial class UnionCodeGroup : CodeGroup
{
public UnionCodeGroup(IMembershipCondition membershipCondition, PolicyStatement policy) : base(default(IMembershipCondition), default(PolicyStatement)) { }
diff --git a/src/System.Security.Permissions/src/System/ServiceProcess/ServiceControllerPermission.cs b/src/System.Security.Permissions/src/System/ServiceProcess/ServiceControllerPermission.cs
new file mode 100644
index 0000000000..4a74c9e4a2
--- /dev/null
+++ b/src/System.Security.Permissions/src/System/ServiceProcess/ServiceControllerPermission.cs
@@ -0,0 +1,17 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Security.Permissions;
+
+namespace System.ServiceProcess
+{
+ public sealed class ServiceControllerPermission : ResourcePermissionBase
+ {
+ public ServiceControllerPermission() { }
+ public ServiceControllerPermission(PermissionState state) : base(state) { }
+ public ServiceControllerPermission(ServiceControllerPermissionAccess permissionAccess, string machineName, string serviceName) { }
+ public ServiceControllerPermission(ServiceControllerPermissionEntry[] permissionAccessEntries) { }
+ public ServiceControllerPermissionEntryCollection PermissionEntries { get => null; }
+ }
+}
diff --git a/src/System.Security.Permissions/src/System/ServiceProcess/ServiceControllerPermissionAccess.cs b/src/System.Security.Permissions/src/System/ServiceProcess/ServiceControllerPermissionAccess.cs
new file mode 100644
index 0000000000..80466c7c12
--- /dev/null
+++ b/src/System.Security.Permissions/src/System/ServiceProcess/ServiceControllerPermissionAccess.cs
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.ServiceProcess
+{
+ [Flags]
+ public enum ServiceControllerPermissionAccess
+ {
+ None = 0,
+ Browse = 1 << 1,
+ Control = 1 << 2 | Browse,
+ }
+}
diff --git a/src/System.Security.Permissions/src/System/ServiceProcess/ServiceControllerPermissionAttribute.cs b/src/System.Security.Permissions/src/System/ServiceProcess/ServiceControllerPermissionAttribute.cs
new file mode 100644
index 0000000000..5b13ed2a96
--- /dev/null
+++ b/src/System.Security.Permissions/src/System/ServiceProcess/ServiceControllerPermissionAttribute.cs
@@ -0,0 +1,19 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Security;
+using System.Security.Permissions;
+
+namespace System.ServiceProcess
+{
+ [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Assembly | AttributeTargets.Event, AllowMultiple = true, Inherited = false )]
+ public class ServiceControllerPermissionAttribute : CodeAccessSecurityAttribute
+ {
+ public ServiceControllerPermissionAttribute(SecurityAction action): base(action) { }
+ public string MachineName { get => null; set { } }
+ public ServiceControllerPermissionAccess PermissionAccess { get => default(ServiceControllerPermissionAccess); set { } }
+ public string ServiceName { get => null; set { } }
+ public override IPermission CreatePermission() { return default(IPermission); }
+ }
+}
diff --git a/src/System.Security.Permissions/src/System/ServiceProcess/ServiceControllerPermissionEntry.cs b/src/System.Security.Permissions/src/System/ServiceProcess/ServiceControllerPermissionEntry.cs
new file mode 100644
index 0000000000..92c460c905
--- /dev/null
+++ b/src/System.Security.Permissions/src/System/ServiceProcess/ServiceControllerPermissionEntry.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.ServiceProcess
+{
+ public class ServiceControllerPermissionEntry
+ {
+ public ServiceControllerPermissionEntry() { }
+ public ServiceControllerPermissionEntry(ServiceControllerPermissionAccess permissionAccess, string machineName, string serviceName) { }
+ public string MachineName { get => null; }
+ public ServiceControllerPermissionAccess PermissionAccess { get => default(ServiceControllerPermissionAccess); }
+ public string ServiceName { get => null; }
+ }
+}
diff --git a/src/System.Security.Permissions/src/System/ServiceProcess/ServiceControllerPermissionEntryCollection.cs b/src/System.Security.Permissions/src/System/ServiceProcess/ServiceControllerPermissionEntryCollection.cs
new file mode 100644
index 0000000000..56f35b8f3b
--- /dev/null
+++ b/src/System.Security.Permissions/src/System/ServiceProcess/ServiceControllerPermissionEntryCollection.cs
@@ -0,0 +1,26 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections;
+
+namespace System.ServiceProcess
+{
+ public class ServiceControllerPermissionEntryCollection : CollectionBase
+ {
+ internal ServiceControllerPermissionEntryCollection() { }
+ public ServiceControllerPermissionEntry this[int index] { get { return null; } set { } }
+ public int Add(ServiceControllerPermissionEntry value) { return 0; }
+ public void AddRange(ServiceControllerPermissionEntry[] value) { }
+ public void AddRange(ServiceControllerPermissionEntryCollection value) { }
+ public bool Contains(ServiceControllerPermissionEntry value) { return false; }
+ public void CopyTo(ServiceControllerPermissionEntry[] array, int index) { }
+ public int IndexOf(ServiceControllerPermissionEntry value) { return 0; }
+ public void Insert(int index, ServiceControllerPermissionEntry value) { }
+ protected override void OnClear() { }
+ protected override void OnInsert(int index, object value) { }
+ protected override void OnRemove(int index, object value) { }
+ protected override void OnSet(int index, object oldValue, object newValue) { }
+ public void Remove(ServiceControllerPermissionEntry value) { }
+ }
+}
diff --git a/src/System.Security.Permissions/tests/CodeGroupTests.cs b/src/System.Security.Permissions/tests/CodeGroupTests.cs
index e6802ec210..14c6e44a54 100644
--- a/src/System.Security.Permissions/tests/CodeGroupTests.cs
+++ b/src/System.Security.Permissions/tests/CodeGroupTests.cs
@@ -23,7 +23,9 @@ namespace System.Security.Permissions.Tests
[Fact]
public static void FirstMatchCodeGroupCallMethods()
{
+#pragma warning disable 618
FirstMatchCodeGroup fmcg = new FirstMatchCodeGroup(new GacMembershipCondition(), new PolicyStatement(new PermissionSet(new PermissionState())));
+#pragma warning restore 618
CodeGroup cg = fmcg.Copy();
PolicyStatement ps = fmcg.Resolve(new Evidence());
cg = fmcg.ResolveMatchingCodeGroups(new Evidence());
@@ -48,7 +50,9 @@ namespace System.Security.Permissions.Tests
[Fact]
public static void UnionCodeGroupCallMethods()
{
+#pragma warning disable 618
UnionCodeGroup ucg = new UnionCodeGroup(new GacMembershipCondition(), new PolicyStatement(new PermissionSet(new PermissionState())));
+#pragma warning restore 618
CodeGroup cg = ucg.Copy();
PolicyStatement ps = ucg.Resolve(new Evidence());
cg = ucg.ResolveMatchingCodeGroups(new Evidence());
diff --git a/src/System.Security.Permissions/tests/EvidenceBaseTests.cs b/src/System.Security.Permissions/tests/EvidenceBaseTests.cs
index 81e76b0894..25b75cb3de 100644
--- a/src/System.Security.Permissions/tests/EvidenceBaseTests.cs
+++ b/src/System.Security.Permissions/tests/EvidenceBaseTests.cs
@@ -53,8 +53,10 @@ namespace System.Security.Permissions.Tests
public static void PermissionRequestEvidenceCallMethods()
{
PermissionSet ps = new PermissionSet(new PermissionState());
+#pragma warning disable 618
PermissionRequestEvidence pre = new PermissionRequestEvidence(ps, ps, ps);
PermissionRequestEvidence obj = pre.Copy();
+#pragma warning restore 618
string str = ps.ToString();
SecurityElement se = new SecurityElement("");
ps.FromXml(se);
diff --git a/src/System.Security.Permissions/tests/PolicyTests.cs b/src/System.Security.Permissions/tests/PolicyTests.cs
index 5a5ea33e70..9e6a95c9ef 100644
--- a/src/System.Security.Permissions/tests/PolicyTests.cs
+++ b/src/System.Security.Permissions/tests/PolicyTests.cs
@@ -24,7 +24,9 @@ namespace System.Security.Permissions.Tests
NamedPermissionSet nps = new NamedPermissionSet("test");
pl.AddNamedPermissionSet(nps);
nps = pl.ChangeNamedPermissionSet("test", new PermissionSet(new Permissions.PermissionState()));
+#pragma warning disable 618
PolicyLevel.CreateAppDomainLevel();
+#pragma warning restore 618
nps = pl.GetNamedPermissionSet("test");
pl.Recover();
NamedPermissionSet nps2 = pl.RemoveNamedPermissionSet(nps);
diff --git a/src/System.Security.Permissions/tests/PrincipalPermissionTests.cs b/src/System.Security.Permissions/tests/PrincipalPermissionTests.cs
index a51905b15a..4817fa89f2 100644
--- a/src/System.Security.Permissions/tests/PrincipalPermissionTests.cs
+++ b/src/System.Security.Permissions/tests/PrincipalPermissionTests.cs
@@ -201,7 +201,7 @@ namespace System.Security.Permissions.Tests
{
PrincipalPermission p1 = new PrincipalPermission("user", null);
EnvironmentPermission ep2 = new EnvironmentPermission(PermissionState.Unrestricted);
- AssertExtensions.Throws<ArgumentException>("System.Security.Permissions.PrincipalPermission", () => p1.Union(ep2));
+ AssertExtensions.Throws<ArgumentException>("other", () => p1.Union(ep2));
}
[Fact]
@@ -286,7 +286,7 @@ namespace System.Security.Permissions.Tests
{
PrincipalPermission p1 = new PrincipalPermission("user", null);
EnvironmentPermission ep2 = new EnvironmentPermission(PermissionState.Unrestricted);
- AssertExtensions.Throws<ArgumentException>("System.Security.Permissions.PrincipalPermission", () => p1.Intersect(ep2));
+ AssertExtensions.Throws<ArgumentException>("target", () => p1.Intersect(ep2));
}
[Fact]
@@ -351,7 +351,7 @@ namespace System.Security.Permissions.Tests
{
PrincipalPermission p1 = new PrincipalPermission("user", null);
EnvironmentPermission ep2 = new EnvironmentPermission(PermissionState.Unrestricted);
- AssertExtensions.Throws<ArgumentException>("System.Security.Permissions.PrincipalPermission", () => p1.IsSubsetOf(ep2));
+ AssertExtensions.Throws<ArgumentException>("target", () => p1.IsSubsetOf(ep2));
}
}
}
diff --git a/src/System.Security.Principal.Windows/pkg/System.Security.Principal.Windows.pkgproj b/src/System.Security.Principal.Windows/pkg/System.Security.Principal.Windows.pkgproj
index 7d1af3b562..9893075869 100644
--- a/src/System.Security.Principal.Windows/pkg/System.Security.Principal.Windows.pkgproj
+++ b/src/System.Security.Principal.Windows/pkg/System.Security.Principal.Windows.pkgproj
@@ -7,9 +7,9 @@
</ProjectReference>
<ProjectReference Include="..\src\System.Security.Principal.Windows.csproj" />
<File Include="$(PlaceHolderFile)">
- <TargetPath>runtimes/win/lib/$(UAPvNextTFM)</TargetPath>
+ <TargetPath>runtimes/win/lib/uap10.0.16299</TargetPath>
</File>
- <InboxOnTargetFramework Include="$(UAPvNextTFM)" />
+ <InboxOnTargetFramework Include="uap10.0.16299" />
<HarvestIncludePaths Include="ref/net46;lib/net46;runtimes/win/lib/net46" />
<HarvestIncludePaths Include="ref/netstandard1.3;runtimes/win/lib/netstandard1.3;lib/netstandard1.3" />
<!-- this package is part of the implementation closure of NETStandard.Library
diff --git a/src/System.Security.Principal.Windows/ref/System.Security.Principal.Windows.cs b/src/System.Security.Principal.Windows/ref/System.Security.Principal.Windows.cs
index fadfe480b1..334372832f 100644
--- a/src/System.Security.Principal.Windows/ref/System.Security.Principal.Windows.cs
+++ b/src/System.Security.Principal.Windows/ref/System.Security.Principal.Windows.cs
@@ -325,9 +325,11 @@ namespace System.Security.Principal
public WindowsIdentity(System.IntPtr userToken, string type) { }
public WindowsIdentity(string sUserPrincipalName) { }
public WindowsIdentity(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }
+ protected WindowsIdentity(System.Security.Principal.WindowsIdentity identity) { }
public Microsoft.Win32.SafeHandles.SafeAccessTokenHandle AccessToken { get { throw null; } }
public sealed override string AuthenticationType { get { throw null; } }
public override System.Collections.Generic.IEnumerable<System.Security.Claims.Claim> Claims { get { throw null; } }
+ public virtual System.Collections.Generic.IEnumerable<System.Security.Claims.Claim> DeviceClaims { get { throw null; } }
public System.Security.Principal.IdentityReferenceCollection Groups { get { throw null; } }
public System.Security.Principal.TokenImpersonationLevel ImpersonationLevel { get { throw null; } }
public virtual bool IsAnonymous { get { throw null; } }
@@ -338,6 +340,7 @@ namespace System.Security.Principal
public System.Security.Principal.SecurityIdentifier Owner { get { throw null; } }
public virtual IntPtr Token { get { throw null; } }
public System.Security.Principal.SecurityIdentifier User { get { throw null; } }
+ public virtual System.Collections.Generic.IEnumerable<System.Security.Claims.Claim> UserClaims { get { throw null; } }
public override System.Security.Claims.ClaimsIdentity Clone() { throw null; }
public void Dispose() { }
protected virtual void Dispose(bool disposing) { }
@@ -353,10 +356,12 @@ namespace System.Security.Principal
public partial class WindowsPrincipal : System.Security.Claims.ClaimsPrincipal
{
public WindowsPrincipal(System.Security.Principal.WindowsIdentity ntIdentity) { }
+ public virtual System.Collections.Generic.IEnumerable<System.Security.Claims.Claim> DeviceClaims { get { throw null; } }
public override System.Security.Principal.IIdentity Identity { get { throw null; } }
public virtual bool IsInRole(int rid) { throw null; }
public virtual bool IsInRole(System.Security.Principal.SecurityIdentifier sid) { throw null; }
public virtual bool IsInRole(System.Security.Principal.WindowsBuiltInRole role) { throw null; }
public override bool IsInRole(string role) { throw null; }
+ public virtual System.Collections.Generic.IEnumerable<System.Security.Claims.Claim> UserClaims { get { throw null; } }
}
}
diff --git a/src/System.Security.Principal.Windows/src/System.Security.Principal.Windows.csproj b/src/System.Security.Principal.Windows/src/System.Security.Principal.Windows.csproj
index 8840631204..1ff4d0a57e 100644
--- a/src/System.Security.Principal.Windows/src/System.Security.Principal.Windows.csproj
+++ b/src/System.Security.Principal.Windows/src/System.Security.Principal.Windows.csproj
@@ -68,6 +68,9 @@
<Compile Include="$(CommonPath)\Interop\Windows\kernel32\Interop.GetCurrentThread.cs">
<Link>Common\Interop\Interop.GetCurrentThread.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\advapi32\Interop.ClaimSecurityAttributes.cs">
+ <Link>Common\Interop\Interop.ClaimSecurityAttributes.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\Interop\Windows\advapi32\Interop.OpenProcessToken_SafeAccessTokenHandle.cs">
<Link>Common\Interop\Interop.OpenProcessToken.cs</Link>
</Compile>
diff --git a/src/System.Security.Principal.Windows/src/System/Security/Principal/WindowsIdentity.cs b/src/System.Security.Principal.Windows/src/System/Security/Principal/WindowsIdentity.cs
index 486d640a03..63b7320e4d 100644
--- a/src/System.Security.Principal.Windows/src/System/Security/Principal/WindowsIdentity.cs
+++ b/src/System.Security.Principal.Windows/src/System/Security/Principal/WindowsIdentity.cs
@@ -6,6 +6,7 @@ using Microsoft.Win32.SafeHandles;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
+using System.Globalization;
using System.Runtime.InteropServices;
using System.Security.Claims;
using System.Text;
@@ -44,6 +45,8 @@ namespace System.Security.Principal
private List<Claim> _deviceClaims;
private List<Claim> _userClaims;
+ private static bool s_ignoreWindows8Properties;
+
//
// Constructors.
//
@@ -780,7 +783,7 @@ namespace System.Security.Principal
}
- private static SafeLocalAllocHandle GetTokenInformation(SafeAccessTokenHandle tokenHandle, TokenInformationClass tokenInformationClass)
+ private static SafeLocalAllocHandle GetTokenInformation(SafeAccessTokenHandle tokenHandle, TokenInformationClass tokenInformationClass, bool nullOnInvalidParam=false)
{
SafeLocalAllocHandle safeLocalAllocHandle = SafeLocalAllocHandle.InvalidHandle;
uint dwLength = (uint)sizeof(uint);
@@ -813,6 +816,15 @@ namespace System.Security.Principal
break;
case Interop.Errors.ERROR_INVALID_HANDLE:
throw new ArgumentException(SR.Argument_InvalidImpersonationToken);
+ case Interop.Errors.ERROR_INVALID_PARAMETER:
+ if (nullOnInvalidParam)
+ {
+ safeLocalAllocHandle.Dispose();
+ return null;
+ }
+
+ // Throw the exception.
+ goto default;
default:
throw new SecurityException(new Win32Exception(dwErrorCode).Message);
}
@@ -942,6 +954,21 @@ namespace System.Security.Principal
// group sids
AddGroupSidClaims(_userClaims);
+ if (!s_ignoreWindows8Properties)
+ {
+ // Device group sids (may cause s_ignoreWindows8Properties to be set to true, so must be first in this block)
+ AddDeviceGroupSidClaims(_deviceClaims, TokenInformationClass.TokenDeviceGroups);
+
+ if (!s_ignoreWindows8Properties)
+ {
+ // User token claims
+ AddTokenClaims(_userClaims, TokenInformationClass.TokenUserClaimAttributes, ClaimTypes.WindowsUserClaim);
+
+ // Device token claims
+ AddTokenClaims(_deviceClaims, TokenInformationClass.TokenDeviceClaimAttributes, ClaimTypes.WindowsDeviceClaim);
+ }
+ }
+
_claimsInitialized = true;
}
}
@@ -1054,6 +1081,153 @@ namespace System.Security.Principal
safeAllocHandle.Dispose();
}
}
+
+ private void AddDeviceGroupSidClaims(List<Claim> instanceClaims, TokenInformationClass tokenInformationClass)
+ {
+ // special case the anonymous identity.
+ if (_safeTokenHandle.IsInvalid)
+ return;
+
+ SafeLocalAllocHandle safeAllocHandle = SafeLocalAllocHandle.InvalidHandle;
+ try
+ {
+ // Retrieve all group sids
+
+ safeAllocHandle = GetTokenInformation(_safeTokenHandle, tokenInformationClass, nullOnInvalidParam: true);
+
+ if (safeAllocHandle == null)
+ {
+ s_ignoreWindows8Properties = true;
+ return;
+ }
+
+ int count = Marshal.ReadInt32(safeAllocHandle.DangerousGetHandle());
+ IntPtr pSidAndAttributes = new IntPtr((long)safeAllocHandle.DangerousGetHandle() + (long)Marshal.OffsetOf(typeof(Interop.TOKEN_GROUPS), "Groups"));
+ string claimType = null;
+
+ for (int i = 0; i < count; ++i)
+ {
+ Interop.SID_AND_ATTRIBUTES group = (Interop.SID_AND_ATTRIBUTES)Marshal.PtrToStructure(pSidAndAttributes, typeof(Interop.SID_AND_ATTRIBUTES));
+ uint mask = Interop.SecurityGroups.SE_GROUP_ENABLED | Interop.SecurityGroups.SE_GROUP_LOGON_ID | Interop.SecurityGroups.SE_GROUP_USE_FOR_DENY_ONLY;
+ SecurityIdentifier groupSid = new SecurityIdentifier(group.Sid, true);
+ if ((group.Attributes & mask) == Interop.SecurityGroups.SE_GROUP_ENABLED)
+ {
+ claimType = ClaimTypes.WindowsDeviceGroup;
+ Claim claim = new Claim(claimType, groupSid.Value, ClaimValueTypes.String, _issuerName, _issuerName, this);
+ claim.Properties.Add(ClaimTypes.WindowsSubAuthority, Convert.ToString(groupSid.IdentifierAuthority, CultureInfo.InvariantCulture));
+ claim.Properties.Add(claimType, "");
+ instanceClaims.Add(claim);
+ }
+ else if ((group.Attributes & mask) == Interop.SecurityGroups.SE_GROUP_USE_FOR_DENY_ONLY)
+ {
+ claimType = ClaimTypes.DenyOnlyWindowsDeviceGroup;
+ Claim claim = new Claim(claimType, groupSid.Value, ClaimValueTypes.String, _issuerName, _issuerName, this);
+ claim.Properties.Add(ClaimTypes.WindowsSubAuthority, Convert.ToString(groupSid.IdentifierAuthority, CultureInfo.InvariantCulture));
+ claim.Properties.Add(claimType, "");
+ instanceClaims.Add(claim);
+ }
+
+ pSidAndAttributes = new IntPtr((long)pSidAndAttributes + Marshal.SizeOf<Interop.SID_AND_ATTRIBUTES>());
+ }
+ }
+ finally
+ {
+ safeAllocHandle?.Close();
+ }
+ }
+
+ private void AddTokenClaims(List<Claim> instanceClaims, TokenInformationClass tokenInformationClass, string propertyValue)
+ {
+ // special case the anonymous identity.
+ if (_safeTokenHandle.IsInvalid)
+ return;
+
+ SafeLocalAllocHandle safeAllocHandle = SafeLocalAllocHandle.InvalidHandle;
+
+ try
+ {
+ safeAllocHandle = GetTokenInformation(_safeTokenHandle, tokenInformationClass);
+
+ Interop.CLAIM_SECURITY_ATTRIBUTES_INFORMATION claimAttributes = (Interop.CLAIM_SECURITY_ATTRIBUTES_INFORMATION)Marshal.PtrToStructure(safeAllocHandle.DangerousGetHandle(), typeof(Interop.CLAIM_SECURITY_ATTRIBUTES_INFORMATION));
+ // An attribute represents a collection of claims. Inside each attribute a claim can be multivalued, we create a claim for each value.
+ // It is a ragged multi-dimentional array, where each cell can be of different lenghts.
+
+ // index into array of claims.
+ long offset = 0;
+
+ for (int attribute = 0; attribute < claimAttributes.AttributeCount; attribute++)
+ {
+ IntPtr pAttribute = new IntPtr(claimAttributes.Attribute.pAttributeV1.ToInt64() + offset);
+ Interop.CLAIM_SECURITY_ATTRIBUTE_V1 windowsClaim = (Interop.CLAIM_SECURITY_ATTRIBUTE_V1)Marshal.PtrToStructure(pAttribute, typeof(Interop.CLAIM_SECURITY_ATTRIBUTE_V1));
+
+ // the switch was written this way, which appears to have multiple for loops, because each item in the ValueCount is of the same ValueType. This saves the type check each item.
+ switch (windowsClaim.ValueType)
+ {
+ case Interop.ClaimSecurityAttributeType.CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING:
+ IntPtr[] stringPointers = new IntPtr[windowsClaim.ValueCount];
+ Marshal.Copy(windowsClaim.Values.ppString, stringPointers, 0, (int)windowsClaim.ValueCount);
+
+ for (int item = 0; item < windowsClaim.ValueCount; item++)
+ {
+ Claim c = new Claim(windowsClaim.Name, Marshal.PtrToStringAuto(stringPointers[item]), ClaimValueTypes.String, _issuerName, _issuerName, this);
+ c.Properties.Add(propertyValue, string.Empty);
+ instanceClaims.Add(c);
+ }
+ break;
+
+ case Interop.ClaimSecurityAttributeType.CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64:
+ long[] intValues = new long[windowsClaim.ValueCount];
+ Marshal.Copy(windowsClaim.Values.pInt64, intValues, 0, (int)windowsClaim.ValueCount);
+
+ for (int item = 0; item < windowsClaim.ValueCount; item++)
+ {
+ Claim c = new Claim(windowsClaim.Name, Convert.ToString(intValues[item], CultureInfo.InvariantCulture), ClaimValueTypes.Integer64, _issuerName, _issuerName, this);
+ c.Properties.Add(propertyValue, string.Empty);
+ instanceClaims.Add(c);
+ }
+ break;
+
+
+ case Interop.ClaimSecurityAttributeType.CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64:
+ long[] uintValues = new long[windowsClaim.ValueCount];
+ Marshal.Copy(windowsClaim.Values.pUint64, uintValues, 0, (int)windowsClaim.ValueCount);
+
+ for (int item = 0; item < windowsClaim.ValueCount; item++)
+ {
+ Claim c = new Claim(windowsClaim.Name, Convert.ToString((ulong)uintValues[item], CultureInfo.InvariantCulture), ClaimValueTypes.UInteger64, _issuerName, _issuerName, this);
+ c.Properties.Add(propertyValue, string.Empty);
+ instanceClaims.Add(c);
+ }
+ break;
+
+ case Interop.ClaimSecurityAttributeType.CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN:
+ long[] boolValues = new long[windowsClaim.ValueCount];
+ Marshal.Copy(windowsClaim.Values.pUint64, boolValues, 0, (int)windowsClaim.ValueCount);
+
+ for (int item = 0; item < windowsClaim.ValueCount; item++)
+ {
+ Claim c = new Claim(
+ windowsClaim.Name,
+ ((ulong)boolValues[item] != 0).ToString(),
+ ClaimValueTypes.Boolean,
+ _issuerName,
+ _issuerName,
+ this);
+
+ c.Properties.Add(propertyValue, string.Empty);
+ instanceClaims.Add(c);
+ }
+ break;
+ }
+
+ offset += Marshal.SizeOf(windowsClaim);
+ }
+ }
+ finally
+ {
+ safeAllocHandle.Close();
+ }
+ }
}
internal enum WinSecurityContext
diff --git a/src/System.Security.Principal.Windows/tests/WindowsIdentityTests.cs b/src/System.Security.Principal.Windows/tests/WindowsIdentityTests.cs
index 0d3f1b08b3..dd2fc3bc82 100644
--- a/src/System.Security.Principal.Windows/tests/WindowsIdentityTests.cs
+++ b/src/System.Security.Principal.Windows/tests/WindowsIdentityTests.cs
@@ -4,7 +4,8 @@
using Microsoft.Win32.SafeHandles;
using System;
-using System.Runtime.Serialization.Formatters.Tests;
+using System.Linq;
+using System.Security.Claims;
using System.Security.Principal;
using Xunit;
@@ -97,6 +98,32 @@ public class WindowsIdentityTests
Assert.Equal(id.AccessToken.DangerousGetHandle(), id.Token);
}
+ [Fact]
+ public static void CheckDeviceClaims()
+ {
+ using (WindowsIdentity id = WindowsIdentity.GetCurrent())
+ {
+ int manualCount = id.Claims.Count(c => c.Properties.ContainsKey(ClaimTypes.WindowsDeviceClaim));
+ int autoCount = id.DeviceClaims.Count();
+
+ Assert.Equal(manualCount, autoCount);
+ }
+ }
+
+ [Fact]
+ public static void CheckUserClaims()
+ {
+ using (WindowsIdentity id = WindowsIdentity.GetCurrent())
+ {
+ Claim[] allClaims = id.Claims.ToArray();
+ int deviceCount = allClaims.Count(c => c.Properties.ContainsKey(ClaimTypes.WindowsDeviceClaim));
+ int manualCount = allClaims.Length - deviceCount;
+ int autoCount = id.UserClaims.Count();
+
+ Assert.Equal(manualCount, autoCount);
+ }
+ }
+
private static void CheckDispose(WindowsIdentity identity, bool anonymous = false)
{
Assert.False(identity.AccessToken.IsClosed);
diff --git a/src/System.Security.Principal.Windows/tests/WindowsPrincipalTests.cs b/src/System.Security.Principal.Windows/tests/WindowsPrincipalTests.cs
index d379356bde..ac6679b2f9 100644
--- a/src/System.Security.Principal.Windows/tests/WindowsPrincipalTests.cs
+++ b/src/System.Security.Principal.Windows/tests/WindowsPrincipalTests.cs
@@ -2,6 +2,10 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
+using System.ComponentModel;
+using System.Linq;
+using System.Security.Claims;
using System.Security.Principal;
using Xunit;
@@ -12,7 +16,52 @@ public class WindowsPrincipalTests
{
WindowsIdentity windowsIdentity = WindowsIdentity.GetAnonymous();
WindowsPrincipal windowsPrincipal = new WindowsPrincipal(windowsIdentity);
- var ret = windowsPrincipal.IsInRole("FAKEDOMAIN\\nonexist");
- Assert.False(ret);
+
+ try
+ {
+ bool ret = windowsPrincipal.IsInRole("FAKEDOMAIN\\nonexist");
+ Assert.False(ret);
+ }
+ catch (SystemException e)
+ {
+ // If a domain joined machine can't talk to the domain controller then it
+ // can't determine if "FAKEDOMAIN" is resolvable within the AD forest, so it
+ // fails with ERROR_TRUSTED_RELATIONSHIP_FAILURE (resulting in an exception).
+ const int ERROR_TRUSTED_RELATIONSHIP_FAILURE = 0x6FD;
+ Win32Exception win32Exception = new Win32Exception(ERROR_TRUSTED_RELATIONSHIP_FAILURE);
+
+ // NetFx throws a plain SystemException which has the message built via FormatMessage.
+ // CoreFx throws a Win32Exception based on the error, which gets the same message value.
+ Assert.Equal(win32Exception.Message, e.Message);
+ }
+ }
+
+ [Fact]
+ public static void CheckDeviceClaims()
+ {
+ using (WindowsIdentity id = WindowsIdentity.GetCurrent())
+ {
+ WindowsPrincipal principal = new WindowsPrincipal(id);
+
+ int manualCount = principal.Claims.Count(c => c.Properties.ContainsKey(ClaimTypes.WindowsDeviceClaim));
+ int autoCount = principal.DeviceClaims.Count();
+
+ Assert.Equal(manualCount, autoCount);
+ }
+ }
+
+ [Fact]
+ public static void CheckUserClaims()
+ {
+ using (WindowsIdentity id = WindowsIdentity.GetCurrent())
+ {
+ WindowsPrincipal principal = new WindowsPrincipal(id);
+ Claim[] allClaims = principal.Claims.ToArray();
+ int deviceCount = allClaims.Count(c => c.Properties.ContainsKey(ClaimTypes.WindowsDeviceClaim));
+ int manualCount = allClaims.Length - deviceCount;
+ int autoCount = principal.UserClaims.Count();
+
+ Assert.Equal(manualCount, autoCount);
+ }
}
}
diff --git a/src/System.ServiceModel.Syndication/pkg/System.ServiceModel.Syndication.pkgproj b/src/System.ServiceModel.Syndication/pkg/System.ServiceModel.Syndication.pkgproj
index 65f155b7f9..f3b9892674 100644
--- a/src/System.ServiceModel.Syndication/pkg/System.ServiceModel.Syndication.pkgproj
+++ b/src/System.ServiceModel.Syndication/pkg/System.ServiceModel.Syndication.pkgproj
@@ -3,7 +3,7 @@
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<ProjectReference Include="..\ref\System.ServiceModel.Syndication.csproj">
- <SupportedFramework>net461;netcoreapp2.0;$(AllXamarinFrameworks)</SupportedFramework>
+ <SupportedFramework>uap10.0.16299;net461;netcoreapp2.0;$(AllXamarinFrameworks)</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\src\System.ServiceModel.Syndication.csproj" />
</ItemGroup>
diff --git a/src/System.ServiceModel.Syndication/ref/System.ServiceModel.Syndication.netcoreapp.cs b/src/System.ServiceModel.Syndication/ref/System.ServiceModel.Syndication.netcoreapp.cs
index f5b16b6138..26a565f511 100644
--- a/src/System.ServiceModel.Syndication/ref/System.ServiceModel.Syndication.netcoreapp.cs
+++ b/src/System.ServiceModel.Syndication/ref/System.ServiceModel.Syndication.netcoreapp.cs
@@ -7,8 +7,40 @@
namespace System.ServiceModel.Syndication
{
+ public partial struct XmlDateTimeData
+ {
+ public XmlDateTimeData(string dateTimeString, System.Xml.XmlQualifiedName elementQualifiedName) { throw null; }
+ public string DateTimeString { get; }
+ public System.Xml.XmlQualifiedName ElementQualifiedName { get; }
+ }
+ public partial struct XmlUriData
+ {
+ public XmlUriData(string uriString, UriKind uriKind, System.Xml.XmlQualifiedName elementQualifiedName) { throw null; }
+ public System.Xml.XmlQualifiedName ElementQualifiedName { get; }
+ public System.UriKind UriKind { get; }
+ public string UriString { get; }
+ }
+ public partial class SyndicationFeed
+ {
+ public System.ServiceModel.Syndication.SyndicationLink Documentation { get { throw null; } set { } }
+ public System.Collections.ObjectModel.Collection<string> SkipDays { get { throw null; } }
+ public System.Collections.ObjectModel.Collection<int> SkipHours { get { throw null; } }
+ public System.ServiceModel.Syndication.SyndicationTextInput TextInput { get { throw null; } set { } }
+ public System.TimeSpan? TimeToLive { get { throw null; } set { } }
+ }
public abstract partial class SyndicationFeedFormatter
{
-
+ public System.ServiceModel.Syndication.TryParseDateTimeCallback DateTimeParser { get; set; }
+ public System.ServiceModel.Syndication.TryParseUriCallback UriParser { get; set; }
+ }
+ public delegate bool TryParseDateTimeCallback(System.ServiceModel.Syndication.XmlDateTimeData data, out System.DateTimeOffset dateTimeOffset);
+ public delegate bool TryParseUriCallback(System.ServiceModel.Syndication.XmlUriData data, out System.Uri uri);
+ public partial class SyndicationTextInput
+ {
+ public string Description { get { throw null; } set { } }
+ public System.ServiceModel.Syndication.SyndicationLink Link { get { throw null; } set { } }
+ public string Name { get { throw null; } set { } }
+ public string Title { get { throw null; } set { } }
+ public SyndicationTextInput() { }
}
}
diff --git a/src/System.ServiceModel.Syndication/src/MatchingRefApiCompatBaseline.netstandard.txt b/src/System.ServiceModel.Syndication/src/MatchingRefApiCompatBaseline.netstandard.txt
new file mode 100644
index 0000000000..7ded2b4d00
--- /dev/null
+++ b/src/System.ServiceModel.Syndication/src/MatchingRefApiCompatBaseline.netstandard.txt
@@ -0,0 +1,19 @@
+Compat issues with assembly System.ServiceModel.Syndication:
+MembersMustExist : Member 'System.ServiceModel.Syndication.SyndicationFeed.Documentation.get()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.ServiceModel.Syndication.SyndicationFeed.Documentation.set(System.ServiceModel.Syndication.SyndicationLink)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.ServiceModel.Syndication.SyndicationFeed.SkipDays.get()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.ServiceModel.Syndication.SyndicationFeed.SkipHours.get()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.ServiceModel.Syndication.SyndicationFeed.TextInput.get()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.ServiceModel.Syndication.SyndicationFeed.TextInput.set(System.ServiceModel.Syndication.SyndicationTextInput)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.ServiceModel.Syndication.SyndicationFeed.TimeToLive.get()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.ServiceModel.Syndication.SyndicationFeed.TimeToLive.set(System.Nullable<System.TimeSpan>)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.ServiceModel.Syndication.SyndicationFeedFormatter.DateTimeParser.get()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.ServiceModel.Syndication.SyndicationFeedFormatter.DateTimeParser.set(System.ServiceModel.Syndication.TryParseDateTimeCallback)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.ServiceModel.Syndication.SyndicationFeedFormatter.UriParser.get()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.ServiceModel.Syndication.SyndicationFeedFormatter.UriParser.set(System.ServiceModel.Syndication.TryParseUriCallback)' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.ServiceModel.Syndication.SyndicationTextInput' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.ServiceModel.Syndication.TryParseDateTimeCallback' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.ServiceModel.Syndication.TryParseUriCallback' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.ServiceModel.Syndication.XmlDateTimeData' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.ServiceModel.Syndication.XmlUriData' does not exist in the implementation but it does exist in the contract.
+Total Issues: 17
diff --git a/src/System.ServiceModel.Syndication/src/Resources/Strings.resx b/src/System.ServiceModel.Syndication/src/Resources/Strings.resx
index 8f81e0922f..1c4152ee2c 100644
--- a/src/System.ServiceModel.Syndication/src/Resources/Strings.resx
+++ b/src/System.ServiceModel.Syndication/src/Resources/Strings.resx
@@ -105,15 +105,15 @@
</xsd:complexType>
</xsd:element>
</xsd:schema>
- <resheader name="reader">
- <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
- </resheader>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
@@ -138,6 +138,9 @@
<data name="ErrorParsingItem" xml:space="preserve">
<value>An error was encountered when parsing the item's XML. Refer to the inner exception for more details.</value>
</data>
+ <data name="ErrorParsingUri" xml:space="preserve">
+ <value>An error was encountered when parsing a Uri value in the XML.</value>
+ </data>
<data name="ExtensionNameNotSpecified" xml:space="preserve">
<value>The name of the extension element must be specified.</value>
</data>
@@ -151,7 +154,7 @@
<value>The feed created a null category.</value>
</data>
<data name="FeedCreatedNullItem" xml:space="preserve">
- <value>=The feed created a null item.</value>
+ <value>The feed created a null item.</value>
</data>
<data name="FeedCreatedNullPerson" xml:space="preserve">
<value>The feed created a null person.</value>
@@ -255,4 +258,10 @@
<data name="XmlStartElementExpected" xml:space="preserve">
<value>Start element expected. Found {0}.</value>
</data>
-</root>
+ <data name="InvalidSkipHourValue" xml:space="preserve">
+ <value>Cannot parse string `{0}` as skip hour. The value for skip hours must be an integer betwen 0 and 23.</value>
+ </data>
+ <data name="InvalidTimeToLiveValue" xml:space="preserve">
+ <value>The value for TimeToLive must be a non-negative whole number of minutes.</value>
+ </data>
+</root> \ No newline at end of file
diff --git a/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/Atom10FeedFormatter.cs b/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/Atom10FeedFormatter.cs
index db52a42c56..0bb8c25e4b 100644
--- a/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/Atom10FeedFormatter.cs
+++ b/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/Atom10FeedFormatter.cs
@@ -71,7 +71,7 @@ namespace System.ServiceModel.Syndication
_feedType = feedToWrite.GetType();
}
- internal override Func<string, string, string, DateTimeOffset> GetDefaultDateTimeParser()
+ internal override TryParseDateTimeCallback GetDefaultDateTimeParser()
{
return DateTimeHelper.DefaultAtom10DateTimeParser;
}
@@ -309,7 +309,7 @@ namespace System.ServiceModel.Syndication
}
else if (reader.IsStartElement(Atom10Constants.LogoTag, Atom10Constants.Atom10Namespace))
{
- result.ImageUrl = UriParser(reader.ReadElementString(), UriKind.RelativeOrAbsolute, Atom10Constants.LogoTag, Atom10Constants.Atom10Namespace);
+ result.ImageUrl = UriFromString(reader.ReadElementString(), UriKind.RelativeOrAbsolute, Atom10Constants.LogoTag, Atom10Constants.Atom10Namespace, reader);
}
else if (reader.IsStartElement(Atom10Constants.RightsTag, Atom10Constants.Atom10Namespace))
{
@@ -728,7 +728,7 @@ namespace System.ServiceModel.Syndication
if (!string.IsNullOrEmpty(src))
{
- result = new UrlSyndicationContent(UriParser(src, UriKind.RelativeOrAbsolute, Atom10Constants.ContentTag, Atom10Constants.Atom10Namespace), type);
+ result = new UrlSyndicationContent(UriFromString(src, UriKind.RelativeOrAbsolute, Atom10Constants.ContentTag, Atom10Constants.Atom10Namespace, reader), type);
bool isEmpty = reader.IsEmptyElement;
if (reader.HasAttributes)
{
@@ -1081,7 +1081,7 @@ namespace System.ServiceModel.Syndication
link.MediaType = mediaType;
link.RelationshipType = relationship;
link.Title = title;
- link.Uri = (val != null) ? UriParser(val, UriKind.RelativeOrAbsolute, Atom10Constants.LinkTag, Atom10Constants.Atom10Namespace) : null;
+ link.Uri = (val != null) ? UriFromString(val, UriKind.RelativeOrAbsolute, Atom10Constants.LinkTag, Atom10Constants.Atom10Namespace, reader) : null;
}
private SyndicationLink ReadLinkFrom(XmlReader reader, SyndicationFeed feed)
diff --git a/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/DateTimeHelper.cs b/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/DateTimeHelper.cs
index 9ca15bf074..1e97dc647f 100644
--- a/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/DateTimeHelper.cs
+++ b/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/DateTimeHelper.cs
@@ -4,6 +4,7 @@
using System.Globalization;
using System.Text;
+using System.Xml;
namespace System.ServiceModel.Syndication
{
@@ -11,40 +12,34 @@ namespace System.ServiceModel.Syndication
{
private const string Rfc3339DateTimeFormat = "yyyy-MM-ddTHH:mm:ssK";
- public static DateTimeOffset DefaultRss20DateTimeParser(string dateTimeString, string localName, string ns)
+ public static bool DefaultRss20DateTimeParser(XmlDateTimeData XmlDateTimeData, out DateTimeOffset dateTimeOffset)
{
- DateTimeOffset dto;
+ string dateTimeString = XmlDateTimeData.DateTimeString;
// First check if DateTimeOffset default parsing can parse the date
- if (DateTimeOffset.TryParse(dateTimeString, out dto))
+ if (DateTimeOffset.TryParse(dateTimeString, out dateTimeOffset))
{
- return dto;
+ return true;
}
// RSS specifies RFC822
- if (Rfc822DateTimeParser(dateTimeString, out dto))
+ if (Rfc822DateTimeParser(dateTimeString, out dateTimeOffset))
{
- return dto;
+ return true;
}
// Event though RCS3339 is for Atom, someone might be using this for RSS
- if (Rfc3339DateTimeParser(dateTimeString, out dto))
+ if (Rfc3339DateTimeParser(dateTimeString, out dateTimeOffset))
{
- return dto;
+ return true;
}
- // Unable to parse - using a default date;
- throw new FormatException(SR.ErrorParsingDateTime);
+ return false;
}
- public static DateTimeOffset DefaultAtom10DateTimeParser(string dateTimeString, string localName, string ns)
+ public static bool DefaultAtom10DateTimeParser(XmlDateTimeData XmlDateTimeData, out DateTimeOffset dateTimeOffset)
{
- if (Rfc3339DateTimeParser(dateTimeString, out DateTimeOffset dto))
- {
- return dto;
- }
-
- throw new FormatException(SR.ErrorParsingDateTime);
+ return Rfc3339DateTimeParser(XmlDateTimeData.DateTimeString, out dateTimeOffset);
}
private static bool Rfc3339DateTimeParser(string dateTimeString, out DateTimeOffset dto)
diff --git a/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/ExtensibleSyndicationObject.cs b/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/ExtensibleSyndicationObject.cs
index 300a42b729..2586d37a23 100644
--- a/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/ExtensibleSyndicationObject.cs
+++ b/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/ExtensibleSyndicationObject.cs
@@ -117,7 +117,7 @@ namespace System.ServiceModel.Syndication
}
}
- internal void WriteElementExtensions(XmlWriter writer)
+ internal void WriteElementExtensions(XmlWriter writer, Func<string, string, bool> shouldSkipElement = null)
{
if (writer == null)
{
@@ -125,7 +125,7 @@ namespace System.ServiceModel.Syndication
}
if (_elementExtensions != null)
{
- _elementExtensions.WriteTo(writer);
+ _elementExtensions.WriteTo(writer, shouldSkipElement);
}
}
diff --git a/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/Rss20Constants.cs b/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/Rss20Constants.cs
index 5b2b0e8859..a811e7ec76 100644
--- a/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/Rss20Constants.cs
+++ b/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/Rss20Constants.cs
@@ -34,5 +34,13 @@ namespace System.ServiceModel.Syndication
public const string UrlTag = "url";
public const string Version = "2.0";
public const string VersionTag = "version";
+ public const string DocumentationTag = "docs";
+ public const string TimeToLiveTag = "ttl";
+ public const string TextInputTag = "textInput";
+ public const string SkipHoursTag = "skipHours";
+ public const string SkipDaysTag = "skipDays";
+ public const string HourTag = "hour";
+ public const string DayTag = "day";
+ public const string NameTag = "name";
}
}
diff --git a/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/Rss20FeedFormatter.cs b/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/Rss20FeedFormatter.cs
index 409c24b87d..9144e3e162 100644
--- a/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/Rss20FeedFormatter.cs
+++ b/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/Rss20FeedFormatter.cs
@@ -78,7 +78,7 @@ namespace System.ServiceModel.Syndication
_feedType = feedToWrite.GetType();
}
- internal override Func<string, string, string, DateTimeOffset> GetDefaultDateTimeParser()
+ internal override TryParseDateTimeCallback GetDefaultDateTimeParser()
{
return DateTimeHelper.DefaultRss20DateTimeParser;
}
@@ -275,7 +275,7 @@ namespace System.ServiceModel.Syndication
}
}
- private SyndicationLink ReadAlternateLink(XmlReader reader, Uri baseUri)
+ internal static SyndicationLink ReadAlternateLink(XmlReader reader, Uri baseUri, TryParseUriCallback uriParser, bool preserveAttributeExtensions)
{
SyndicationLink link = new SyndicationLink();
link.BaseUri = baseUri;
@@ -290,7 +290,7 @@ namespace System.ServiceModel.Syndication
}
else if (!FeedUtils.IsXmlns(reader.LocalName, reader.NamespaceURI))
{
- if (this.PreserveAttributeExtensions)
+ if (preserveAttributeExtensions)
{
link.AttributeExtensions.Add(new XmlQualifiedName(reader.LocalName, reader.NamespaceURI), reader.Value);
}
@@ -302,8 +302,9 @@ namespace System.ServiceModel.Syndication
}
}
- string uri = reader.ReadElementString();
- link.Uri = UriParser(uri, UriKind.RelativeOrAbsolute, Rss20Constants.LinkTag, Rss20Constants.Rss20Namespace);
+ string uriString = reader.ReadElementString();
+ Uri uri = UriFromString(uriParser, uriString, UriKind.RelativeOrAbsolute, Rss20Constants.LinkTag, Rss20Constants.Rss20Namespace, reader);
+ link.Uri = uri;
return link;
}
@@ -421,7 +422,7 @@ namespace System.ServiceModel.Syndication
}
else if (reader.IsStartElement(Rss20Constants.LinkTag, Rss20Constants.Rss20Namespace))
{
- result.Links.Add(ReadAlternateLink(reader, result.BaseUri));
+ result.Links.Add(ReadAlternateLink(reader, result.BaseUri, UriParser, PreserveAttributeExtensions));
readAlternateLink = true;
}
else if (reader.IsStartElement(Rss20Constants.DescriptionTag, Rss20Constants.Rss20Namespace))
@@ -494,7 +495,7 @@ namespace System.ServiceModel.Syndication
string val = reader.Value;
if (name == Rss20Constants.UrlTag && ns == Rss20Constants.Rss20Namespace)
{
- feed.Links.Add(SyndicationLink.CreateSelfLink(UriParser(val, UriKind.RelativeOrAbsolute, Rss20Constants.UrlTag, Rss20Constants.Rss20Namespace)));
+ feed.Links.Add(SyndicationLink.CreateSelfLink(UriFromString(val, UriKind.RelativeOrAbsolute, Rss20Constants.UrlTag, Rss20Constants.Rss20Namespace, reader)));
}
else if (!FeedUtils.IsXmlns(name, ns))
{
@@ -547,7 +548,7 @@ namespace System.ServiceModel.Syndication
reader.ReadEndElement(); // item
if (!readAlternateLink && fallbackAlternateLink != null)
{
- result.Links.Add(SyndicationLink.CreateAlternateLink(UriParser(fallbackAlternateLink, UriKind.RelativeOrAbsolute, fallbackAlternateLinkLocalName, fallbackAlternateLinkNamespace)));
+ result.Links.Add(SyndicationLink.CreateAlternateLink(UriFromString(fallbackAlternateLink, UriKind.RelativeOrAbsolute, fallbackAlternateLinkLocalName, fallbackAlternateLinkNamespace, reader)));
readAlternateLink = true;
}
@@ -593,7 +594,7 @@ namespace System.ServiceModel.Syndication
string val = reader.Value;
if (name == Rss20Constants.UrlTag && ns == Rss20Constants.Rss20Namespace)
{
- link.Uri = UriParser(val, UriKind.RelativeOrAbsolute, Rss20Constants.EnclosureTag, Rss20Constants.Rss20Namespace);
+ link.Uri = UriFromString(val, UriKind.RelativeOrAbsolute, Rss20Constants.EnclosureTag, Rss20Constants.Rss20Namespace, reader);
}
else if (name == Rss20Constants.TypeTag && ns == Rss20Constants.Rss20Namespace)
{
@@ -737,7 +738,7 @@ namespace System.ServiceModel.Syndication
if (!string.IsNullOrEmpty(baseUri))
{
- result.BaseUri = UriParser(baseUri, UriKind.RelativeOrAbsolute, baseUriLocalName, baseUriNamespace);
+ result.BaseUri = UriFromString(baseUri, UriKind.RelativeOrAbsolute, baseUriLocalName, baseUriNamespace, reader);
}
bool areAllItemsRead = true;
@@ -757,7 +758,7 @@ namespace System.ServiceModel.Syndication
}
else if (reader.IsStartElement(Rss20Constants.LinkTag, Rss20Constants.Rss20Namespace))
{
- result.Links.Add(ReadAlternateLink(reader, result.BaseUri));
+ result.Links.Add(ReadAlternateLink(reader, result.BaseUri, UriParser, PreserveAttributeExtensions));
}
else if (reader.IsStartElement(Rss20Constants.DescriptionTag, Rss20Constants.Rss20Namespace))
{
@@ -811,7 +812,7 @@ namespace System.ServiceModel.Syndication
{
if (reader.IsStartElement(Rss20Constants.UrlTag, Rss20Constants.Rss20Namespace))
{
- result.ImageUrl = UriParser(reader.ReadElementString(), UriKind.RelativeOrAbsolute, Rss20Constants.UrlTag, Rss20Constants.Rss20Namespace);
+ result.ImageUrl = UriFromString(reader.ReadElementString(), UriKind.RelativeOrAbsolute, Rss20Constants.UrlTag, Rss20Constants.Rss20Namespace, reader);
}
else
{
@@ -1025,6 +1026,53 @@ namespace System.ServiceModel.Syndication
writer.WriteEndElement(); // image
}
+ // Optional spec items
+ if (Feed.InternalDocumentation?.Uri != null)
+ {
+ writer.WriteElementString(Rss20Constants.DocumentationTag, Feed.InternalDocumentation.Uri.ToString());
+ }
+
+ if (Feed.InternalTimeToLive != null)
+ {
+ writer.WriteElementString(Rss20Constants.TimeToLiveTag, ((int)Feed.InternalTimeToLive.Value.TotalMinutes).ToString());
+ }
+
+ if (Feed.InternalSkipHours?.Count > 0)
+ {
+ writer.WriteStartElement(Rss20Constants.SkipHoursTag);
+
+ foreach (int hour in Feed.InternalSkipHours)
+ {
+ writer.WriteElementString(Rss20Constants.HourTag, hour.ToString());
+ }
+
+ writer.WriteEndElement();
+ }
+
+ if (Feed.InternalSkipDays?.Count > 0)
+ {
+ writer.WriteStartElement(Rss20Constants.SkipDaysTag);
+
+ foreach (string day in Feed.InternalSkipDays)
+ {
+ writer.WriteElementString(Rss20Constants.DayTag, day);
+ }
+
+ writer.WriteEndElement();
+ }
+
+ if (Feed.InternalTextInput != null)
+ {
+ writer.WriteStartElement(Rss20Constants.TextInputTag);
+
+ writer.WriteElementString(Rss20Constants.DescriptionTag, Feed.InternalTextInput.Description);
+ writer.WriteElementString(Rss20Constants.TitleTag, Feed.InternalTextInput.Title);
+ writer.WriteElementString(Rss20Constants.LinkTag, Feed.InternalTextInput.Link.GetAbsoluteUri().ToString());
+ writer.WriteElementString(Rss20Constants.NameTag, Feed.InternalTextInput.Name);
+
+ writer.WriteEndElement();
+ }
+
if (_serializeExtensionsAsAtom)
{
_atomSerializer.WriteElement(writer, Atom10Constants.IdTag, this.Feed.Id);
diff --git a/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/SyndicationElementExtensionCollection.cs b/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/SyndicationElementExtensionCollection.cs
index aacb074bc6..29830fe38e 100644
--- a/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/SyndicationElementExtensionCollection.cs
+++ b/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/SyndicationElementExtensionCollection.cs
@@ -133,7 +133,7 @@ namespace System.ServiceModel.Syndication
return ReadExtensions<TExtension>(extensionName, extensionNamespace, null, serializer);
}
- internal void WriteTo(XmlWriter writer)
+ internal void WriteTo(XmlWriter writer, Func<string, string, bool> shouldSkipElement)
{
if (_buffer != null)
{
@@ -142,6 +142,12 @@ namespace System.ServiceModel.Syndication
reader.ReadStartElement();
while (reader.IsStartElement())
{
+ if (shouldSkipElement != null && shouldSkipElement(reader.LocalName, reader.NamespaceURI))
+ {
+ reader.Skip();
+ continue;
+ }
+
writer.WriteNode(reader, false);
}
}
diff --git a/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/SyndicationFeed.cs b/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/SyndicationFeed.cs
index 621c98994f..ef8aad0efe 100644
--- a/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/SyndicationFeed.cs
+++ b/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/SyndicationFeed.cs
@@ -2,22 +2,22 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.Text;
-using System.Xml;
-using System.Runtime.Serialization;
using System.Globalization;
-using System.Xml.Serialization;
-using System.Diagnostics.CodeAnalysis;
-using System.Runtime.CompilerServices;
+using System.Linq;
+using System.Xml;
namespace System.ServiceModel.Syndication
{
// NOTE: This class implements Clone so if you add any members, please update the copy ctor
public class SyndicationFeed : IExtensibleSyndicationObject
{
+ private static readonly HashSet<string> s_acceptedDays = new HashSet<string>(
+ new string[] { "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday" },
+ StringComparer.OrdinalIgnoreCase
+ );
+
private Collection<SyndicationPerson> _authors;
private Uri _baseUri;
private Collection<SyndicationCategory> _categories;
@@ -34,6 +34,13 @@ namespace System.ServiceModel.Syndication
private Collection<SyndicationLink> _links;
private TextSyndicationContent _title;
+ // optional RSS tags
+ private SyndicationLink _documentation;
+ private TimeSpan? _timeToLive;
+ private Collection<int> _skipHours;
+ private Collection<string> _skipDays;
+ private SyndicationTextInput _textInput;
+
public SyndicationFeed()
: this((IEnumerable<SyndicationItem>)null)
{
@@ -265,6 +272,273 @@ namespace System.ServiceModel.Syndication
set { _title = value; }
}
+ internal SyndicationLink InternalDocumentation => _documentation;
+
+ public SyndicationLink Documentation
+ {
+ get
+ {
+ if (_documentation == null)
+ {
+ _documentation = TryReadDocumentationFromExtension(ElementExtensions);
+ }
+
+ return _documentation;
+ }
+ set
+ {
+ _documentation = value;
+ }
+ }
+
+ internal TimeSpan? InternalTimeToLive => _timeToLive;
+
+ public TimeSpan? TimeToLive
+ {
+ get
+ {
+ if (!_timeToLive.HasValue)
+ {
+ _timeToLive = TryReadTimeToLiveFromExtension(ElementExtensions);
+ }
+
+ return _timeToLive;
+ }
+ set
+ {
+ if (value.HasValue && (value.Value.Milliseconds != 0 || value.Value.Seconds != 0 || value.Value.TotalMinutes < 0))
+ {
+ throw new ArgumentOutOfRangeException(nameof(value), value.Value, SR.InvalidTimeToLiveValue);
+ }
+
+ _timeToLive = value;
+ }
+ }
+
+ internal Collection<int> InternalSkipHours => _skipHours;
+
+ public Collection<int> SkipHours
+ {
+ get
+ {
+ if (_skipHours == null)
+ {
+ var skipHours = new Collection<int>();
+ TryReadSkipHoursFromExtension(ElementExtensions, skipHours);
+ _skipHours = skipHours;
+ }
+
+ return _skipHours;
+ }
+ }
+
+ internal Collection<string> InternalSkipDays => _skipDays;
+
+ public Collection<string> SkipDays
+ {
+ get
+ {
+ if (_skipDays == null)
+ {
+ var skipDays = new Collection<string>();
+ TryReadSkipDaysFromExtension(ElementExtensions, skipDays);
+ _skipDays = skipDays;
+ }
+
+ return _skipDays;
+ }
+ }
+
+ internal SyndicationTextInput InternalTextInput => _textInput;
+
+ public SyndicationTextInput TextInput
+ {
+ get
+ {
+ if (_textInput == null)
+ {
+ _textInput = TryReadTextInputFromExtension(ElementExtensions);
+ }
+
+ return _textInput;
+ }
+ set
+ {
+ _textInput = value;
+ }
+ }
+
+ private SyndicationLink TryReadDocumentationFromExtension(SyndicationElementExtensionCollection elementExtensions)
+ {
+ SyndicationElementExtension documentationElement = elementExtensions
+ .Where(e => e.OuterName == Rss20Constants.DocumentationTag && e.OuterNamespace == Rss20Constants.Rss20Namespace)
+ .FirstOrDefault();
+
+ if (documentationElement == null)
+ return null;
+
+ using (XmlReader reader = documentationElement.GetReader())
+ {
+ SyndicationLink documentation = Rss20FeedFormatter.ReadAlternateLink(reader, BaseUri, SyndicationFeedFormatter.DefaultUriParser, preserveAttributeExtensions: true);
+ return documentation;
+ }
+ }
+
+ private TimeSpan? TryReadTimeToLiveFromExtension(SyndicationElementExtensionCollection elementExtensions)
+ {
+ SyndicationElementExtension timeToLiveElement = elementExtensions
+ .FirstOrDefault(e => e.OuterName == Rss20Constants.TimeToLiveTag && e.OuterNamespace == Rss20Constants.Rss20Namespace);
+
+ if (timeToLiveElement == null)
+ return null;
+
+ using (XmlReader reader = timeToLiveElement.GetReader())
+ {
+ string value = reader.ReadElementString();
+ if (int.TryParse(value, out int timeToLive))
+ {
+ if (timeToLive >= 0)
+ {
+ return TimeSpan.FromMinutes(timeToLive);
+ }
+ else
+ {
+ return null;
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+ }
+
+ private void TryReadSkipHoursFromExtension(SyndicationElementExtensionCollection elementExtensions, Collection<int> skipHours)
+ {
+ SyndicationElementExtension skipHoursElement = elementExtensions
+ .Where(e => e.OuterName == Rss20Constants.SkipHoursTag && e.OuterNamespace == Rss20Constants.Rss20Namespace)
+ .FirstOrDefault();
+
+ if (skipHoursElement == null)
+ return;
+
+ using (XmlReader reader = skipHoursElement.GetReader())
+ {
+ reader.ReadStartElement();
+
+ while (reader.IsStartElement())
+ {
+ if (reader.LocalName == Rss20Constants.HourTag)
+ {
+ string value = reader.ReadElementString();
+ int hour;
+ bool parsed = int.TryParse(value, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out hour);
+
+ if (!parsed || (hour < 0 || hour > 23))
+ {
+ throw new FormatException(string.Format(SR.InvalidSkipHourValue, value));
+ }
+
+ skipHours.Add(hour);
+ }
+ else
+ {
+ reader.Skip();
+ }
+ }
+ }
+ }
+
+ private void TryReadSkipDaysFromExtension(SyndicationElementExtensionCollection elementExtensions, Collection<string> skipDays)
+ {
+ SyndicationElementExtension skipDaysElement = elementExtensions
+ .Where(e => e.OuterName == Rss20Constants.SkipDaysTag && e.OuterNamespace == Rss20Constants.Rss20Namespace)
+ .FirstOrDefault();
+
+ if (skipDaysElement == null)
+ return;
+
+ using (XmlReader reader = skipDaysElement.GetReader())
+ {
+ reader.ReadStartElement();
+
+ while (reader.IsStartElement())
+ {
+ if (reader.LocalName == Rss20Constants.DayTag)
+ {
+ string day = reader.ReadElementString();
+
+ //Check if the day is actually an accepted day.
+ if (IsValidDay(day))
+ {
+ skipDays.Add(day);
+ }
+ }
+ else
+ {
+ reader.Skip();
+ }
+ }
+
+ reader.ReadEndElement();
+ }
+ }
+
+ private static bool IsValidDay(string day) => s_acceptedDays.Contains(day);
+
+ private SyndicationTextInput TryReadTextInputFromExtension(SyndicationElementExtensionCollection elementExtensions)
+ {
+ SyndicationElementExtension textInputElement = elementExtensions
+ .Where(e => e.OuterName == Rss20Constants.TextInputTag && e.OuterNamespace == Rss20Constants.Rss20Namespace)
+ .FirstOrDefault();
+
+ if (textInputElement == null)
+ return null;
+
+ var textInput = new SyndicationTextInput();
+ using (XmlReader reader = textInputElement.GetReader())
+ {
+ reader.ReadStartElement();
+ while (reader.IsStartElement())
+ {
+ string name = reader.LocalName;
+ string value = reader.ReadElementString();
+
+ switch (name)
+ {
+ case Rss20Constants.DescriptionTag:
+ textInput.Description = value;
+ break;
+
+ case Rss20Constants.TitleTag:
+ textInput.Title = value;
+ break;
+
+ case Rss20Constants.LinkTag:
+ textInput.Link = new SyndicationLink(new Uri(value, UriKind.RelativeOrAbsolute));
+ break;
+
+ case Rss20Constants.NameTag:
+ textInput.Name = value;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ reader.ReadEndElement();
+ }
+
+ return IsValidTextInput(textInput) ? textInput : null;
+ }
+
+ private static bool IsValidTextInput(SyndicationTextInput textInput)
+ {
+ //All textInput items are required, we check if all items were instantiated.
+ return textInput.Description != null && textInput.Title != null && textInput.Name != null && textInput.Link != null;
+ }
+
public static SyndicationFeed Load(XmlReader reader)
{
return Load<SyndicationFeed>(reader);
@@ -359,7 +633,33 @@ namespace System.ServiceModel.Syndication
protected internal virtual void WriteElementExtensions(XmlWriter writer, string version)
{
- _extensions.WriteElementExtensions(writer);
+ _extensions.WriteElementExtensions(writer, ShouldSkipWritingElements);
+ }
+
+ private bool ShouldSkipWritingElements(string localName, string ns)
+ {
+ if (ns == Rss20Constants.Rss20Namespace)
+ {
+ switch (localName)
+ {
+ case Rss20Constants.DocumentationTag:
+ return InternalDocumentation != null;
+
+ case Rss20Constants.TimeToLiveTag:
+ return InternalTimeToLive != null;
+
+ case Rss20Constants.TextInputTag:
+ return InternalTextInput != null;
+
+ case Rss20Constants.SkipHoursTag:
+ return InternalSkipHours != null;
+
+ case Rss20Constants.SkipDaysTag:
+ return InternalSkipDays != null;
+ }
+ }
+
+ return false;
}
internal void LoadElementExtensions(XmlReader readerOverUnparsedExtensions, int maxExtensionSize)
diff --git a/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/SyndicationFeedFormatter.cs b/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/SyndicationFeedFormatter.cs
index 750563c606..71b9445caf 100644
--- a/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/SyndicationFeedFormatter.cs
+++ b/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/SyndicationFeedFormatter.cs
@@ -11,6 +11,9 @@ namespace System.ServiceModel.Syndication
using System.Xml;
using DiagnosticUtility = System.ServiceModel.DiagnosticUtility;
+ public delegate bool TryParseDateTimeCallback(XmlDateTimeData data, out DateTimeOffset dateTimeOffset);
+ public delegate bool TryParseUriCallback(XmlUriData data, out Uri uri);
+
[DataContract]
public abstract class SyndicationFeedFormatter
{
@@ -40,19 +43,19 @@ namespace System.ServiceModel.Syndication
}
}
- public Func<string, UriKind, string, string, Uri> UriParser { get; set; } = DefaultUriParser;
+ public TryParseUriCallback UriParser { get; set; } = DefaultUriParser;
// Different DateTimeParsers are needed for Atom and Rss so can't set inline
- public Func<string, string, string, DateTimeOffset> DateTimeParser { get; set; }
+ public TryParseDateTimeCallback DateTimeParser { get; set; }
- internal virtual Func<string, string, string, DateTimeOffset> GetDefaultDateTimeParser()
+ internal virtual TryParseDateTimeCallback GetDefaultDateTimeParser()
{
return NotImplementedDateTimeParser;
}
- private DateTimeOffset NotImplementedDateTimeParser(string dtoString, string localName, string ns)
+ private bool NotImplementedDateTimeParser(XmlDateTimeData XmlDateTimeData, out DateTimeOffset dateTimeOffset)
{
- throw new NotImplementedException();
+ return false;
}
public abstract string Version
@@ -391,22 +394,69 @@ namespace System.ServiceModel.Syndication
_feed = feed;
}
+ internal Uri UriFromString(string uriString, UriKind uriKind, string localName, string namespaceURI, XmlReader reader)
+ {
+ return UriFromString(UriParser, uriString, uriKind, localName, namespaceURI, reader);
+ }
+
+ internal static Uri UriFromString(TryParseUriCallback uriParser, string uriString, UriKind uriKind, string localName, string namespaceURI, XmlReader reader)
+ {
+ Uri uri = null;
+ var elementQualifiedName = new XmlQualifiedName(localName, namespaceURI);
+ var xmlUriData = new XmlUriData(uriString, uriKind, elementQualifiedName);
+ object[] args = new object[] { xmlUriData, uri };
+ try
+ {
+ foreach (Delegate parser in uriParser.GetInvocationList())
+ {
+ if ((bool)parser.Method.Invoke(parser.Target, args))
+ {
+ uri = (Uri)args[args.Length - 1];
+ return uri;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
+ new XmlException(FeedUtils.AddLineInfo(reader, SR.ErrorParsingUri), e));
+ }
+
+ DefaultUriParser(xmlUriData, out uri);
+ return uri;
+ }
+
internal DateTimeOffset DateFromString(string dateTimeString, XmlReader reader)
{
try
{
- return DateTimeParser(dateTimeString, reader.LocalName, reader.NamespaceURI);
+ DateTimeOffset dateTimeOffset;
+ var elementQualifiedName = new XmlQualifiedName(reader.LocalName, reader.NamespaceURI);
+ var xmlDateTimeData = new XmlDateTimeData(dateTimeString, elementQualifiedName);
+ object[] args = new object[] { xmlDateTimeData, dateTimeOffset };
+ foreach (Delegate dateTimeParser in DateTimeParser.GetInvocationList())
+ {
+ if ((bool)dateTimeParser.Method.Invoke(dateTimeParser.Target, args))
+ {
+ dateTimeOffset = (DateTimeOffset)args[args.Length - 1];
+ return dateTimeOffset;
+ }
+ }
}
- catch (FormatException e)
+ catch (Exception e)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new XmlException(FeedUtils.AddLineInfo(reader, SR.ErrorParsingDateTime), e));
}
+
+ throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
+ new XmlException(FeedUtils.AddLineInfo(reader, SR.ErrorParsingDateTime)));
}
- private static Uri DefaultUriParser(string value, UriKind kind, string localName, string ns)
+ internal static bool DefaultUriParser(XmlUriData XmlUriData, out Uri uri)
{
- return new Uri(value, kind);
+ uri = new Uri(XmlUriData.UriString, XmlUriData.UriKind);
+ return true;
}
internal static void CloseBuffer(XmlBuffer buffer, XmlDictionaryWriter extWriter)
diff --git a/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/SyndicationTextInput.cs b/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/SyndicationTextInput.cs
new file mode 100644
index 0000000000..f987478a2e
--- /dev/null
+++ b/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/SyndicationTextInput.cs
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.ServiceModel.Syndication
+{
+ public class SyndicationTextInput
+ {
+ public string Description { get; set; }
+ public string Title { get; set; }
+ public SyndicationLink Link { get; set; }
+ public string Name { get; set; }
+ }
+}
diff --git a/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/XmlDateTimeData.cs b/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/XmlDateTimeData.cs
new file mode 100644
index 0000000000..b8031a5889
--- /dev/null
+++ b/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/XmlDateTimeData.cs
@@ -0,0 +1,21 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Xml;
+
+namespace System.ServiceModel.Syndication
+{
+ public struct XmlDateTimeData
+ {
+ public XmlDateTimeData(string dateTimeString, XmlQualifiedName elementQualifiedName)
+ {
+ DateTimeString = dateTimeString;
+ ElementQualifiedName = elementQualifiedName;
+ }
+
+ public string DateTimeString { get; }
+
+ public XmlQualifiedName ElementQualifiedName { get; }
+ }
+}
diff --git a/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/XmlUriData.cs b/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/XmlUriData.cs
new file mode 100644
index 0000000000..f4917be320
--- /dev/null
+++ b/src/System.ServiceModel.Syndication/src/System/ServiceModel/Syndication/XmlUriData.cs
@@ -0,0 +1,24 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Xml;
+
+namespace System.ServiceModel.Syndication
+{
+ public struct XmlUriData
+ {
+ public XmlUriData(string uriString, UriKind uriKind, XmlQualifiedName elementQualifiedName)
+ {
+ UriString = uriString;
+ UriKind = uriKind;
+ ElementQualifiedName = elementQualifiedName;
+ }
+
+ public XmlQualifiedName ElementQualifiedName { get; }
+
+ public UriKind UriKind { get; }
+
+ public string UriString { get; }
+ }
+}
diff --git a/src/System.ServiceModel.Syndication/tests/BasicScenarioTests.cs b/src/System.ServiceModel.Syndication/tests/BasicScenarioTests.cs
index f6c858c0a2..23c29822ce 100644
--- a/src/System.ServiceModel.Syndication/tests/BasicScenarioTests.cs
+++ b/src/System.ServiceModel.Syndication/tests/BasicScenarioTests.cs
@@ -23,15 +23,16 @@ namespace System.ServiceModel.Syndication.Tests
try
{
// *** SETUP *** \\
- SyndicationFeed sf = new SyndicationFeed("First feed on .net core ever!!", "This is the first feed on .net core ever!", new Uri("https://github.com/dotnet/wcf"));
+ var sf = new SyndicationFeed("First feed on .net core ever!!", "This is the first feed on .net core ever!", new Uri("https://github.com/dotnet/wcf"));
Assert.True(sf != null);
- XmlWriter xmlw = XmlWriter.Create(filePath);
- Rss20FeedFormatter rssf = new Rss20FeedFormatter(sf);
+ using (XmlWriter xmlw = XmlWriter.Create(filePath))
+ {
+ var rssf = new Rss20FeedFormatter(sf);
- // *** EXECUTE *** \\
- rssf.WriteTo(xmlw);
- xmlw.Close();
+ // *** EXECUTE *** \\
+ rssf.WriteTo(xmlw);
+ }
// *** VALIDATE *** \\
Assert.True(File.Exists(filePath));
@@ -51,16 +52,20 @@ namespace System.ServiceModel.Syndication.Tests
try
{
// *** SETUP *** \\\
- XmlReader xmlr = XmlReader.Create(@"SimpleRssFeed.xml");
- SyndicationFeed sf = SyndicationFeed.Load(xmlr);
- Assert.True(sf != null);
+ SyndicationFeed sf;
+ using (XmlReader xmlr = XmlReader.Create(@"SimpleRssFeed.xml"))
+ {
+ sf = SyndicationFeed.Load(xmlr);
+ Assert.True(sf != null);
+ }
// *** EXECUTE *** \\
//Write the same feed that was read.
- XmlWriter xmlw = XmlWriter.Create(path);
- Rss20FeedFormatter atomFeed = new Rss20FeedFormatter(sf);
- atomFeed.WriteTo(xmlw);
- xmlw.Close();
+ using (XmlWriter xmlw = XmlWriter.Create(path))
+ {
+ var rss20FeedFormatter = new Rss20FeedFormatter(sf);
+ rss20FeedFormatter.WriteTo(xmlw);
+ }
// *** VALIDATE *** \\
Assert.True(File.Exists(path));
@@ -80,19 +85,21 @@ namespace System.ServiceModel.Syndication.Tests
try
{
// *** SETUP *** \\\
- XmlReaderSettings settingsReader = new XmlReaderSettings();
- XmlReader xmlr = XmlReader.Create(@"rssSpecExample.xml", settingsReader);
- SyndicationFeed sf = SyndicationFeed.Load(xmlr);
- Assert.True(sf != null);
+ SyndicationFeed sf;
+ using (XmlReader xmlr = XmlReader.Create(@"rssSpecExample.xml"))
+ {
+ sf = SyndicationFeed.Load(xmlr);
+ Assert.True(sf != null);
+ }
// *** EXECUTE *** \\
//Write the same feed that was read.
XmlWriterSettings settingsWriter = new XmlWriterSettings();
- XmlWriter xmlw = XmlWriter.Create(path, settingsWriter);
- Rss20FeedFormatter atomFeed = new Rss20FeedFormatter(sf);
- atomFeed.WriteTo(xmlw);
-
- xmlw.Close();
+ using (XmlWriter xmlw = XmlWriter.Create(path, settingsWriter))
+ {
+ var rss20FeedFormatter = new Rss20FeedFormatter(sf);
+ rss20FeedFormatter.WriteTo(xmlw);
+ }
// *** VALIDATE *** \\
Assert.True(File.Exists(path));
@@ -112,17 +119,20 @@ namespace System.ServiceModel.Syndication.Tests
try
{
// *** SETUP *** \\\
- XmlReaderSettings setting = new XmlReaderSettings();
- XmlReader xmlr = XmlReader.Create(@"SimpleAtomFeed.xml", setting);
- SyndicationFeed sf = SyndicationFeed.Load(xmlr);
- Assert.True(sf != null);
+ SyndicationFeed sf;
+ using (XmlReader xmlr = XmlReader.Create(@"SimpleAtomFeed.xml"))
+ {
+ sf = SyndicationFeed.Load(xmlr);
+ Assert.True(sf != null);
+ }
// *** EXECUTE *** \\
//Write the same feed that was read.
- XmlWriter xmlw = XmlWriter.Create(path);
- Atom10FeedFormatter atomFeed = new Atom10FeedFormatter(sf);
- atomFeed.WriteTo(xmlw);
- xmlw.Close();
+ using (XmlWriter xmlw = XmlWriter.Create(path))
+ {
+ var atom10FeedFormatter = new Atom10FeedFormatter(sf);
+ atom10FeedFormatter.WriteTo(xmlw);
+ }
// *** VALIDATE *** \\
Assert.True(File.Exists(path));
@@ -142,19 +152,20 @@ namespace System.ServiceModel.Syndication.Tests
try
{
// *** SETUP *** \\\
- XmlReaderSettings readerSettings = new XmlReaderSettings();
- XmlReader xmlr = XmlReader.Create(@"atom_spec_example.xml", readerSettings);
- SyndicationFeed sf = SyndicationFeed.Load(xmlr);
- Assert.True(sf != null);
+ SyndicationFeed sf;
+ using (XmlReader xmlr = XmlReader.Create(@"atom_spec_example.xml"))
+ {
+ sf = SyndicationFeed.Load(xmlr);
+ Assert.True(sf != null);
+ }
// *** EXECUTE *** \\
//Write the same feed that was read.
- XmlWriterSettings writerSettings = new XmlWriterSettings();
-
- XmlWriter xmlw = XmlWriter.Create(path, writerSettings);
- Atom10FeedFormatter atomFeed = new Atom10FeedFormatter(sf);
- atomFeed.WriteTo(xmlw);
- xmlw.Close();
+ using (XmlWriter xmlw = XmlWriter.Create(path))
+ {
+ var atom10FeedFormatter = new Atom10FeedFormatter(sf);
+ atom10FeedFormatter.WriteTo(xmlw);
+ }
// *** VALIDATE *** \\
Assert.True(File.Exists(path));
@@ -195,22 +206,19 @@ namespace System.ServiceModel.Syndication.Tests
feed.BaseUri = new Uri("http://mypage.com");
// Write to XML > rss
- XmlWriterSettings settings = new XmlWriterSettings();
- XmlWriter xmlwRss = XmlWriter.Create(RssPath, settings);
- Rss20FeedFormatter rssff = new Rss20FeedFormatter(feed);
+ using (XmlWriter xmlwRss = XmlWriter.Create(RssPath))
+ {
+ Rss20FeedFormatter rssff = new Rss20FeedFormatter(feed);
+ rssff.WriteTo(xmlwRss);
+ }
// Write to XML > atom
- XmlWriter xmlwAtom = XmlWriter.Create(AtomPath);
- Atom10FeedFormatter atomf = new Atom10FeedFormatter(feed);
-
-
- // *** EXECUTE *** \\
- rssff.WriteTo(xmlwRss);
- xmlwRss.Close();
-
- atomf.WriteTo(xmlwAtom); ;
- xmlwAtom.Close();
+ using (XmlWriter xmlwAtom = XmlWriter.Create(AtomPath))
+ {
+ Atom10FeedFormatter atomf = new Atom10FeedFormatter(feed);
+ atomf.WriteTo(xmlwAtom);
+ }
// *** ASSERT *** \\
Assert.True(File.Exists(RssPath));
@@ -302,7 +310,7 @@ namespace System.ServiceModel.Syndication.Tests
SyndicationItem[] items = res.Items.ToArray();
DateTimeOffset dateTimeOffset;
Assert.Throws<XmlException>(() => dateTimeOffset = items[2].PublishDate);
- }
+ }
[Fact]
public static void AtomEntryPositiveTest()
@@ -487,7 +495,7 @@ namespace System.ServiceModel.Syndication.Tests
}
}
- private static void ReadWriteSyndicationFeed(string file, Func<SyndicationFeed, SyndicationFeedFormatter> feedFormatter, List<AllowableDifference> allowableDifferences = null)
+ private static void ReadWriteSyndicationFeed(string file, Func<SyndicationFeed, SyndicationFeedFormatter> feedFormatter, List<AllowableDifference> allowableDifferences = null, Action<SyndicationFeed> verifySyndicationFeedRead = null)
{
string serializeFilePath = Path.GetTempFileName();
bool toDeletedFile = true;
@@ -500,6 +508,7 @@ namespace System.ServiceModel.Syndication.Tests
using (XmlReader reader = XmlDictionaryReader.CreateTextReader(fileStream, XmlDictionaryReaderQuotas.Max))
{
feedObjct = SyndicationFeed.Load(reader);
+ verifySyndicationFeedRead?.Invoke(feedObjct);
}
}
diff --git a/src/System.ServiceModel.Syndication/tests/System.ServiceModel.Syndication.Tests.csproj b/src/System.ServiceModel.Syndication/tests/System.ServiceModel.Syndication.Tests.csproj
index 449cfd5d6b..02d154e36c 100644
--- a/src/System.ServiceModel.Syndication/tests/System.ServiceModel.Syndication.Tests.csproj
+++ b/src/System.ServiceModel.Syndication/tests/System.ServiceModel.Syndication.Tests.csproj
@@ -14,11 +14,6 @@
<ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp'">
<Compile Include="$(MsBuildThisFileDirectory)netcoreapp\**\*.cs" />
</ItemGroup>
- <ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp'">
- <ReferenceFromRuntime Include="System.ServiceModel.Syndication">
- <Private>true</Private>
- </ReferenceFromRuntime>
- </ItemGroup>
<ItemGroup>
<Content Include="$(MsBuildThisFileDirectory)\TestFeeds\**\*.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
diff --git a/src/System.ServiceModel.Syndication/tests/TestFeeds/rssOptionalElements.xml b/src/System.ServiceModel.Syndication/tests/TestFeeds/rssOptionalElements.xml
new file mode 100644
index 0000000000..45a9dcc2ad
--- /dev/null
+++ b/src/System.ServiceModel.Syndication/tests/TestFeeds/rssOptionalElements.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<rss version="2.0">
+ <channel customAttribute="customAtt">
+ <title>Liftoff News</title>
+ <link>http://contoso.com/</link>
+ <description>Liftoff to Space Exploration.</description>
+ <language>en-us</language>
+ <lastBuildDate>Tue, 10 Jun 2003 09:41:01 Z</lastBuildDate>
+ <docs>http://contoso.com/rss</docs>
+ <generator>Weblog Editor 2.0</generator>
+ <managingEditor>editor@example.com</managingEditor>
+ <category>TestingFeeds</category>
+ <copyright>Contoso Rights.</copyright>
+ <ttl>60</ttl>
+ <skipHours>
+ <hour>1</hour>
+ <hour>2</hour>
+ <hour>3</hour>
+ </skipHours>
+ <skipDays>
+ <day>Saturday</day>
+ <day>Sunday</day>
+ </skipDays>
+ <textInput>
+ <description>Search Online</description>
+ <title>Search</title>
+ <link>http://www.contoso.no/search?</link>
+ <name>input Name</name>
+ </textInput>
+ </channel>
+</rss> \ No newline at end of file
diff --git a/src/System.ServiceModel.Syndication/tests/TestFeeds/rssSpecExample.xml b/src/System.ServiceModel.Syndication/tests/TestFeeds/rssSpecExample.xml
index 8be629d90d..1e9b06630d 100644
--- a/src/System.ServiceModel.Syndication/tests/TestFeeds/rssSpecExample.xml
+++ b/src/System.ServiceModel.Syndication/tests/TestFeeds/rssSpecExample.xml
@@ -2,11 +2,11 @@
<rss version="2.0">
<channel customAttribute="customAtt">
<title>Liftoff News</title>
- <link>http://liftoff.msfc.nasa.gov/</link>
+ <link>http://contoso.com/</link>
<description>Liftoff to Space Exploration.</description>
<language>en-us</language>
<lastBuildDate>Tue, 10 Jun 2003 09:41:01 GMT</lastBuildDate>
- <docs>http://blogs.law.harvard.edu/tech/rss</docs>
+ <docs>http://contoso.com/rss</docs>
<generator>Weblog Editor 2.0</generator>
<managingEditor>editor@example.com</managingEditor>
<category>TestingFeeds</category>
@@ -18,6 +18,11 @@
<hour>3</hour>
</skipHours>
<skipDays>
+ <day>Monday</day>
+ <day>TUESDAY</day>
+ <day>Wednesday</day>
+ <day>Thursday</day>
+ <day>FridaY</day>
<day>Saturday</day>
<day>Sunday</day>
</skipDays>
@@ -37,33 +42,33 @@
</image>
<item>
<title>Star City</title>
- <link>http://liftoff.msfc.nasa.gov/news/2003/news-starcity.asp</link>
+ <link>http://contoso.com/news/2003/news-starcity.asp</link>
<description>
How do Americans get ready to work with Russians aboard the International Space Station? They take a crash course in culture, language and protocol at Russia's Star City.
</description>
<pubDate>Tue, 03 Jun 2003 09:39:21 GMT</pubDate>
- <guid>http://liftoff.msfc.nasa.gov/2003/06/03.html#item573</guid>
+ <guid>http://contoso.com/2003/06/03.html#item573</guid>
</item>
<item>
<description>
Sky watchers in Europe, Asia, and parts of Alaska and Canada will experience a partial eclipse of the Sun on Saturday, May 31st.
</description>
<pubDate>Fri, 30 May 2003 11:06:42 GMT</pubDate>
- <guid>http://liftoff.msfc.nasa.gov/2003/05/30.html#item572</guid>
+ <guid>http://contoso.com/2003/05/30.html#item572</guid>
</item>
<item>
<title>The Engine That Does More</title>
- <link>http://liftoff.msfc.nasa.gov/news/2003/news-VASIMR.asp</link>
+ <link>http://contoso.com/news/2003/news-VASIMR.asp</link>
<description>Before man travels to Mars, NASA hopes to design new engines that will let us fly through the Solar System more quickly. The proposed VASIMR engine would do that.</description>
<pubDate>Tue, 27 May 2003 08:37:32 GMT</pubDate>
- <guid>http://liftoff.msfc.nasa.gov/2003/05/27.html#item571</guid>
+ <guid>http://contoso.com/2003/05/27.html#item571</guid>
</item>
<item>
<title>Astronauts' Dirty Laundry</title>
- <link>http://liftoff.msfc.nasa.gov/news/2003/news-laundry.asp</link>
+ <link>http://contoso.com/news/2003/news-laundry.asp</link>
<description>Compared to earlier spacecraft, the International Space Station has many luxuries, but laundry facilities are not one of them. Instead, astronauts have other options.</description>
<pubDate>Tue, 20 May 2003 08:56:02 GMT</pubDate>
- <guid>http://liftoff.msfc.nasa.gov/2003/05/20.html#item570</guid>
+ <guid>http://contoso.com/2003/05/20.html#item570</guid>
</item>
</channel>
</rss> \ No newline at end of file
diff --git a/src/System.ServiceModel.Syndication/tests/netcoreapp/BasicScenarioTests.netcoreapp.cs b/src/System.ServiceModel.Syndication/tests/netcoreapp/BasicScenarioTests.netcoreapp.cs
index 78a25b6868..dbd5fd7ee0 100644
--- a/src/System.ServiceModel.Syndication/tests/netcoreapp/BasicScenarioTests.netcoreapp.cs
+++ b/src/System.ServiceModel.Syndication/tests/netcoreapp/BasicScenarioTests.netcoreapp.cs
@@ -2,14 +2,10 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System;
using System.Collections.Generic;
-using System.Text;
-using System.ServiceModel.Syndication;
+using System.Linq;
using System.Xml;
-using System.IO;
using Xunit;
-using System.Linq;
namespace System.ServiceModel.Syndication.Tests
{
@@ -25,7 +21,11 @@ namespace System.ServiceModel.Syndication.Tests
using (XmlReader reader = XmlReader.Create(@"RssSpecCustomParser.xml"))
{
var formatter = new Rss20FeedFormatter();
- formatter.DateTimeParser = (value, localName, ns) => dto;
+ formatter.DateTimeParser = (XmlDateTimeData xmlDateTimeData, out DateTimeOffset dateTimeOffset) =>
+ {
+ dateTimeOffset = dto;
+ return true;
+ };
formatter.ReadFrom(reader);
feed = formatter.Feed;
}
@@ -45,7 +45,11 @@ namespace System.ServiceModel.Syndication.Tests
{
var formatter = new Rss20FeedFormatter
{
- UriParser = (value, kind, localName, ns) => new Uri($"http://value-{value}-kind-{kind}-localName-{localName}-ns-{ns}-end")
+ UriParser = (XmlUriData xmlUriData, out Uri uri) =>
+ {
+ uri = new Uri($"http://value-{xmlUriData.UriString}-kind-{xmlUriData.UriKind}-localName-{xmlUriData.ElementQualifiedName.Name}-ns-{xmlUriData.ElementQualifiedName.Namespace}-end");
+ return true;
+ }
};
formatter.ReadFrom(reader);
feed = formatter.Feed;
@@ -76,7 +80,11 @@ namespace System.ServiceModel.Syndication.Tests
{
var formatter = new Atom10FeedFormatter
{
- DateTimeParser = (value, localName, ns) => dto
+ DateTimeParser = (XmlDateTimeData xmlDateTimeData, out DateTimeOffset dateTimeOffset) =>
+ {
+ dateTimeOffset = dto;
+ return true;
+ }
};
formatter.ReadFrom(reader);
feed = formatter.Feed;
@@ -101,7 +109,11 @@ namespace System.ServiceModel.Syndication.Tests
{
var formatter = new Atom10FeedFormatter
{
- UriParser = (value, kind, localName, ns) => new Uri($"http://value-{value}-kind-{kind}-localName-{localName}-ns-{ns}-end")
+ UriParser = (XmlUriData xmlUriData, out Uri uri) =>
+ {
+ uri = new Uri($"http://value-{xmlUriData.UriString}-kind-{xmlUriData.UriKind}-localName-{xmlUriData.ElementQualifiedName.Name}-ns-{xmlUriData.ElementQualifiedName.Namespace}-end");
+ return true;
+ }
};
formatter.ReadFrom(reader);
feed = formatter.Feed;
@@ -118,5 +130,132 @@ namespace System.ServiceModel.Syndication.Tests
Assert.Equal(new Uri("http://value-EntryLinkHref-kind-relativeorabsolute-localName-link-ns-http//www.w3.org/2005/Atom-end"), feed.Items.First().Links.First().Uri);
Assert.Equal(new Uri("http://value-EntryContentSrc-kind-relativeorabsolute-localName-content-ns-http://www.w3.org/2005/Atom-end"), ((UrlSyndicationContent)feed.Items.First().Content).Url);
}
+
+ [Fact]
+ public static void SyndicationFeed_RSS_Optional_Elements()
+ {
+ using (XmlReader reader = XmlReader.Create(@"rssSpecExample.xml"))
+ {
+ SyndicationFeed feed = SyndicationFeed.Load(reader);
+
+ Assert.NotNull(feed.Documentation);
+ Assert.Equal("http://contoso.com/rss", feed.Documentation.GetAbsoluteUri().ToString());
+
+ Assert.NotNull(feed.TimeToLive);
+ Assert.Equal(TimeSpan.FromMinutes(60), feed.TimeToLive.Value);
+
+ Assert.NotNull(feed.SkipHours);
+ Assert.Equal(3, feed.SkipHours.Count);
+
+ Assert.NotNull(feed.SkipDays);
+ Assert.Equal(7, feed.SkipDays.Count);
+
+ Assert.NotNull(feed.TextInput);
+ Assert.Equal("Search Online", feed.TextInput.Description);
+ Assert.Equal("Search", feed.TextInput.Title);
+ Assert.Equal("input Name", feed.TextInput.Name);
+ Assert.Equal("http://www.contoso.no/search?", feed.TextInput.Link.Uri.ToString());
+ }
+ }
+
+ [Fact]
+ public static void SyndicationFeed_Load_Write_RSS_With_Optional_Elements()
+ {
+ List<AllowableDifference> allowableDifferences = GetRssFeedPositiveTestAllowableDifferences();
+ ReadWriteSyndicationFeed(
+ file: "rssOptionalElements.xml",
+ feedFormatter: (feedObject) => new Rss20FeedFormatter(feedObject),
+ allowableDifferences: allowableDifferences
+ );
+ }
+
+ [Fact]
+ public static void SyndicationFeed_Load_Write_RSS_Use_Optional_Element_Properties()
+ {
+ List<AllowableDifference> allowableDifferences = GetRssFeedPositiveTestAllowableDifferences();
+ ReadWriteSyndicationFeed(
+ file: "rssOptionalElements.xml",
+ feedFormatter: (feedObject) => new Rss20FeedFormatter(feedObject),
+ allowableDifferences: allowableDifferences,
+ verifySyndicationFeedRead: (feed) =>
+ {
+ Assert.NotNull(feed);
+ Assert.NotNull(feed.Documentation);
+ Assert.True(feed.Documentation.GetAbsoluteUri().ToString() == "http://contoso.com/rss");
+
+ Assert.NotNull(feed.TimeToLive);
+ Assert.Equal(TimeSpan.FromMinutes(60), feed.TimeToLive.Value);
+
+ Assert.NotNull(feed.SkipHours);
+ Assert.Equal(3, feed.SkipHours.Count);
+
+ Assert.NotNull(feed.SkipDays);
+ Assert.Equal(2, feed.SkipDays.Count);
+
+ Assert.NotNull(feed.TextInput);
+ Assert.Equal("Search Online", feed.TextInput.Description);
+ Assert.Equal("Search", feed.TextInput.Title);
+ Assert.Equal("input Name", feed.TextInput.Name);
+ Assert.Equal("http://www.contoso.no/search?", feed.TextInput.Link.Uri.ToString());
+ });
+ }
+
+ public static TheoryData<TimeSpan> InvalidTimeToLiveValues
+ {
+ get
+ {
+ TheoryData<TimeSpan> data = new TheoryData<TimeSpan>();
+
+ data.Add(new TimeSpan(days: 0, hours: 0, minutes: 1, seconds: 1, milliseconds: 0));
+ data.Add(new TimeSpan(days: 0, hours: 0, minutes: 1, seconds: 0, milliseconds: 1));
+ data.Add(new TimeSpan(hours: 0, minutes: -1, seconds: 0));
+
+ return data;
+ }
+ }
+
+ public static TheoryData<TimeSpan> ValidTimeToLiveValues
+ {
+ get
+ {
+ TheoryData<TimeSpan> data = new TheoryData<TimeSpan>();
+
+ data.Add(new TimeSpan(hours: 0, minutes: 0, seconds: 0));
+ data.Add(new TimeSpan(hours: 0, minutes: 1, seconds: 0));
+ data.Add(new TimeSpan(hours: 0, minutes: 1000, seconds: 0));
+
+ return data;
+ }
+ }
+
+ [Theory, MemberData(nameof(InvalidTimeToLiveValues))]
+ public static void SyndicationFeed_TimeToLive_Validation_Throws(TimeSpan invalidTimeToLive)
+ {
+ Assert.Throws<ArgumentOutOfRangeException>(() =>
+ {
+ var feed = new SyndicationFeed("Contoso News", "<div>Most recent news from Contoso</div>",
+ new Uri("http://www.Contoso.com/news"));
+ feed.TimeToLive = invalidTimeToLive;
+ });
+ }
+
+ [Theory, MemberData(nameof(ValidTimeToLiveValues))]
+ public static void SyndicationFeed_TimeToLive_Success(TimeSpan validTimeToLive)
+ {
+ var feed = new SyndicationFeed("Contoso News", "<div>Most recent news from Contoso</div>",
+ new Uri("http://www.Contoso.com/news"));
+ feed.TimeToLive = validTimeToLive;
+ Assert.Equal(validTimeToLive, feed.TimeToLive.Value);
+ }
+
+ [Fact]
+ public static void SyndicationFeed_TimeToLive_Null_Success()
+ {
+ var feed = new SyndicationFeed("Contoso News", "<div>Most recent news from Contoso</div>",
+ new Uri("http://www.Contoso.com/news"));
+ feed.TimeToLive = null;
+ Assert.False(feed.TimeToLive.HasValue);
+ }
+
}
}
diff --git a/src/System.ServiceProcess.ServiceController/ref/System.ServiceProcess.ServiceController.cs b/src/System.ServiceProcess.ServiceController/ref/System.ServiceProcess.ServiceController.cs
index 948bf0f33d..6456523fd9 100644
--- a/src/System.ServiceProcess.ServiceController/ref/System.ServiceProcess.ServiceController.cs
+++ b/src/System.ServiceProcess.ServiceController/ref/System.ServiceProcess.ServiceController.cs
@@ -106,6 +106,12 @@ namespace System.ServiceProcess
Manual = 3,
System = 1,
}
+ [AttributeUsage(AttributeTargets.All)]
+ public partial class ServiceProcessDescriptionAttribute : System.ComponentModel.DescriptionAttribute
+ {
+ public ServiceProcessDescriptionAttribute(string description) : base(description) { }
+ public override string Description { get { throw null; } }
+ }
[System.FlagsAttribute]
public enum ServiceType
{
diff --git a/src/System.ServiceProcess.ServiceController/src/Configurations.props b/src/System.ServiceProcess.ServiceController/src/Configurations.props
index ad80ed9c3b..f3c3ca0d61 100644
--- a/src/System.ServiceProcess.ServiceController/src/Configurations.props
+++ b/src/System.ServiceProcess.ServiceController/src/Configurations.props
@@ -3,7 +3,7 @@
<PropertyGroup>
<PackageConfigurations>
netstandard;
- netcoreapp2.0-Windows_NT;
+ netstandard-Windows_NT;
netfx-Windows_NT;
</PackageConfigurations>
<BuildConfigurations>
diff --git a/src/System.ServiceProcess.ServiceController/src/System.ServiceProcess.ServiceController.csproj b/src/System.ServiceProcess.ServiceController/src/System.ServiceProcess.ServiceController.csproj
index 617fbc9101..afe05cbff1 100644
--- a/src/System.ServiceProcess.ServiceController/src/System.ServiceProcess.ServiceController.csproj
+++ b/src/System.ServiceProcess.ServiceController/src/System.ServiceProcess.ServiceController.csproj
@@ -8,19 +8,19 @@
<ProjectGuid>{F4821CB6-91A3-4546-BC4F-E00DBFBDAA05}</ProjectGuid>
<IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'netfx'">true</IsPartialFacadeAssembly>
<ResourcesSourceOutputDirectory Condition="'$(TargetGroup)' == 'netfx'">None</ResourcesSourceOutputDirectory>
- <GeneratePlatformNotSupportedAssemblyMessage Condition="'$(TargetGroup)' == 'netstandard'">SR.PlatformNotSupported_ServiceController</GeneratePlatformNotSupportedAssemblyMessage>
+ <GeneratePlatformNotSupportedAssemblyMessage Condition="'$(TargetGroup)' == 'netstandard' AND '$(TargetsWindows)' != 'true'">SR.PlatformNotSupported_ServiceController</GeneratePlatformNotSupportedAssemblyMessage>
<!-- Although we have a netstandard configuration, we know we are not currently UAP compatible-->
<UWPCompatible>false</UWPCompatible>
</PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Windows_NT-Debug|AnyCPU'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp2.0-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
- <ItemGroup Condition="$(TargetGroup.StartsWith('netcoreapp'))">
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Windows_NT-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Windows_NT-Release|AnyCPU'" />
+ <ItemGroup Condition="$(TargetGroup.StartsWith('netcoreapp')) OR ('$(TargetGroup)' == 'netstandard' AND '$(TargetsWindows)' == 'true')">
<Compile Include="$(CommonPath)\Interop\Windows\Interop.Libraries.cs">
<Link>Common\Interop\Windows\Interop.Libraries.cs</Link>
</Compile>
@@ -96,6 +96,7 @@
<Compile Include="System\ServiceProcess\ServiceController.cs" />
<Compile Include="System\ServiceProcess\ServiceControllerStatus.cs" />
<Compile Include="System\ServiceProcess\ServiceStartMode.cs" />
+ <Compile Include="System\ServiceProcess\ServiceProcessDescriptionAttribute.cs" />
<Compile Include="System\ServiceProcess\ServiceType.cs" />
<Compile Include="System\ServiceProcess\SessionChangeDescription.cs" />
<Compile Include="System\ServiceProcess\SessionChangeReason.cs" />
@@ -105,7 +106,7 @@
<Reference Include="mscorlib" />
<Reference Include="System.ServiceProcess" />
</ItemGroup>
- <ItemGroup Condition="$(TargetGroup.StartsWith('netcoreapp'))">
+ <ItemGroup Condition="$(TargetGroup.StartsWith('netcoreapp')) OR ('$(TargetGroup)' == 'netstandard' AND '$(TargetsWindows)' == 'true')">
<Reference Include="Microsoft.Win32.Primitives" />
<Reference Include="System.Collections" />
<Reference Include="System.Console" />
diff --git a/src/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceBase.cs b/src/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceBase.cs
index 0286919d61..26f28af8ec 100644
--- a/src/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceBase.cs
+++ b/src/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceBase.cs
@@ -8,6 +8,7 @@ using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
+using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Threading;
@@ -29,6 +30,7 @@ namespace System.ServiceProcess
private ServiceMainCallback _mainCallback;
private IntPtr _handleName;
private ManualResetEvent _startCompletedSignal;
+ private ExceptionDispatchInfo _startFailedException;
private int _acceptedCommands;
private string _serviceName;
private bool _nameFrozen; // set to true once we've started running and ServiceName can't be changed any more.
@@ -620,7 +622,21 @@ namespace System.ServiceProcess
// While the service is running, this function will never return. It will return when the service
// is stopped.
+ // After it returns, SCM might terminate the process at any time
+ // (so subsequent code is not guaranteed to run).
bool res = StartServiceCtrlDispatcher(entriesPointer);
+
+ foreach (ServiceBase service in services)
+ {
+ if (service._startFailedException != null)
+ {
+ // Propagate exceptions throw during OnStart.
+ // Note that this same exception is also thrown from ServiceMainCallback
+ // (so SCM can see it as well).
+ service._startFailedException.Throw();
+ }
+ }
+
string errorMessage = "";
if (!res)
@@ -830,6 +846,12 @@ namespace System.ServiceProcess
{
WriteLogEntry(SR.Format(SR.StartFailed, e.ToString()), true);
_status.currentState = ServiceControlStatus.STATE_STOPPED;
+
+ // We capture the exception so that it can be propagated
+ // from ServiceBase.Run.
+ // We also use the presence of this exception to inform SCM
+ // that the service failed to start successfully.
+ _startFailedException = ExceptionDispatchInfo.Capture(e);
}
_startCompletedSignal.Set();
}
@@ -901,8 +923,20 @@ namespace System.ServiceProcess
// since NT will terminate this thread right after this function
// finishes.
_startCompletedSignal = new ManualResetEvent(false);
+ _startFailedException = null;
ThreadPool.QueueUserWorkItem(new WaitCallback(this.ServiceQueuedMainCallback), args);
_startCompletedSignal.WaitOne();
+
+ if (_startFailedException != null)
+ {
+ // Inform SCM that the service could not be started successfully.
+ // (Unless the service has already provided another failure exit code)
+ if (_status.win32ExitCode == 0)
+ {
+ _status.win32ExitCode = ServiceControlStatus.ERROR_EXCEPTION_IN_SERVICE;
+ }
+ }
+
statusOK = SetServiceStatus(_statusHandle, pStatus);
if (!statusOK)
{
diff --git a/src/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceProcessDescriptionAttribute.cs b/src/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceProcessDescriptionAttribute.cs
new file mode 100644
index 0000000000..ff716f8837
--- /dev/null
+++ b/src/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceProcessDescriptionAttribute.cs
@@ -0,0 +1,42 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.ComponentModel;
+
+namespace System.ServiceProcess
+{
+ /// <summary>
+ /// DescriptionAttribute marks a property, event, or extender with a
+ /// description. Visual designers can display this description when referencing
+ /// the member.
+ /// </summary>
+ [AttributeUsage(AttributeTargets.All)]
+ public class ServiceProcessDescriptionAttribute : DescriptionAttribute
+ {
+ private bool replaced = false;
+
+ /// <summary>
+ /// Constructs a new sys description
+ /// </summary>
+ public ServiceProcessDescriptionAttribute(string description) : base(description)
+ {
+ }
+
+ /// <summary>
+ /// Retrieves the description text.
+ /// </summary>
+ public override string Description
+ {
+ get
+ {
+ if (!replaced)
+ {
+ replaced = true;
+ DescriptionValue = base.Description;
+ }
+ return base.Description;
+ }
+ }
+ }
+}
diff --git a/src/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs b/src/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs
index e09e915ac5..2d08cc7d19 100644
--- a/src/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs
+++ b/src/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs
@@ -2,10 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using Microsoft.Win32;
-using System;
using System.Diagnostics;
-using System.Security.Principal;
using Xunit;
/// <summary>
@@ -16,6 +13,7 @@ namespace System.ServiceProcess.Tests
[OuterLoop(/* Modifies machine state */)]
public class ServiceBaseTests : IDisposable
{
+ private const int connectionTimeout = 30000;
private readonly TestServiceProvider _testService;
private static readonly Lazy<bool> s_isElevated = new Lazy<bool>(() => AdminHelpers.IsProcessElevated());
@@ -41,11 +39,11 @@ namespace System.ServiceProcess.Tests
Assert.True(testServiceController.CanShutdown);
}
- //[Fact]
+ // [Fact]
// To cleanup lingering Test Services uncomment the Fact attribute and run the following command
- // msbuild /t:rebuildandtest /p:XunitMethodName=System.ServiceProcess.Tests.ServiceBaseTests.Cleanup
+ // msbuild /t:rebuildandtest /p:XunitMethodName=System.ServiceProcess.Tests.ServiceBaseTests.Cleanup /p:OuterLoop=true
// Remember to comment out the Fact again before running tests otherwise it will cleanup tests running in parallel
- // and casue them to fail.
+ // and cause them to fail.
public void Cleanup()
{
string currentService = "";
@@ -75,104 +73,92 @@ namespace System.ServiceProcess.Tests
[ConditionalFact(nameof(IsProcessElevated))]
public void TestOnStartThenStop()
{
- var controller = new ServiceController(_testService.TestServiceName);
- AssertExpectedProperties(controller);
- string expected =
-@"OnStart args=
-OnStop
-";
+ ServiceController controller = ConnectToServer();
+
controller.Stop();
+ Assert.Equal((int)PipeMessageByteCode.Stop, _testService.GetByte());
controller.WaitForStatus(ServiceControllerStatus.Stopped);
- Assert.Equal(expected, _testService.GetServiceOutput());
}
[ConditionalFact(nameof(IsProcessElevated))]
public void TestOnStartWithArgsThenStop()
{
- var controller = new ServiceController(_testService.TestServiceName);
- AssertExpectedProperties(controller);
+ ServiceController controller = ConnectToServer();
+
controller.Stop();
+ Assert.Equal((int)PipeMessageByteCode.Stop, _testService.GetByte());
controller.WaitForStatus(ServiceControllerStatus.Stopped);
- string expected =
-@"OnStart args=a,b,c
-OnStop
-";
- controller.Start(new string[] { "a", "b", "c" });
+ controller.Start(new string[] { "StartWithArguments", "a", "b", "c" });
+ _testService.Client = null;
+ _testService.Client.Connect();
+
+ // There is no definite order between start and connected when tests are running on multiple threads.
+ // In this case we dont care much about the order, so we are just checking whether the appropiate bytes have been sent.
+ Assert.Equal((int)(PipeMessageByteCode.Connected | PipeMessageByteCode.Start), _testService.GetByte() | _testService.GetByte());
controller.WaitForStatus(ServiceControllerStatus.Running);
+
controller.Stop();
+ Assert.Equal((int)PipeMessageByteCode.Stop, _testService.GetByte());
controller.WaitForStatus(ServiceControllerStatus.Stopped);
- Assert.Equal(expected, _testService.GetServiceOutput());
}
[ConditionalFact(nameof(IsProcessElevated))]
public void TestOnPauseThenStop()
{
- var controller = new ServiceController(_testService.TestServiceName);
- AssertExpectedProperties(controller);
- string expected =
-@"OnStart args=
-OnPause
-OnStop
-";
+ ServiceController controller = ConnectToServer();
+
controller.Pause();
+ Assert.Equal((int)PipeMessageByteCode.Pause, _testService.GetByte());
controller.WaitForStatus(ServiceControllerStatus.Paused);
+
controller.Stop();
+ Assert.Equal((int)PipeMessageByteCode.Stop, _testService.GetByte());
controller.WaitForStatus(ServiceControllerStatus.Stopped);
- Assert.Equal(expected, _testService.GetServiceOutput());
}
[ConditionalFact(nameof(IsProcessElevated))]
public void TestOnPauseAndContinueThenStop()
{
- var controller = new ServiceController(_testService.TestServiceName);
- AssertExpectedProperties(controller);
- string expected =
-@"OnStart args=
-OnPause
-OnContinue
-OnStop
-";
+ ServiceController controller = ConnectToServer();
+
controller.Pause();
+ Assert.Equal((int)PipeMessageByteCode.Pause, _testService.GetByte());
controller.WaitForStatus(ServiceControllerStatus.Paused);
+
controller.Continue();
+ Assert.Equal((int)PipeMessageByteCode.Continue, _testService.GetByte());
controller.WaitForStatus(ServiceControllerStatus.Running);
+
controller.Stop();
+ Assert.Equal((int)PipeMessageByteCode.Stop, _testService.GetByte());
controller.WaitForStatus(ServiceControllerStatus.Stopped);
- Assert.Equal(expected, _testService.GetServiceOutput());
}
[ConditionalFact(nameof(IsProcessElevated))]
public void TestOnExecuteCustomCommand()
{
- var controller = new ServiceController(_testService.TestServiceName);
- AssertExpectedProperties(controller);
- string expected =
-@"OnStart args=
-OnCustomCommand command=128
-OnStop
-";
+ ServiceController controller = ConnectToServer();
+
controller.ExecuteCommand(128);
- controller.WaitForStatus(ServiceControllerStatus.Running);
+ Assert.Equal(128, _testService.GetByte());
+
controller.Stop();
+ Assert.Equal((int)PipeMessageByteCode.Stop, _testService.GetByte());
controller.WaitForStatus(ServiceControllerStatus.Stopped);
- Assert.Equal(expected, _testService.GetServiceOutput());
}
[ConditionalFact(nameof(IsProcessElevated))]
public void TestOnContinueBeforePause()
{
- var controller = new ServiceController(_testService.TestServiceName);
- AssertExpectedProperties(controller);
- string expected =
-@"OnStart args=
-OnStop
-";
+ ServiceController controller = ConnectToServer();
+
controller.Continue();
controller.WaitForStatus(ServiceControllerStatus.Running);
+
controller.Stop();
+ Assert.Equal((int)PipeMessageByteCode.Stop, _testService.GetByte());
controller.WaitForStatus(ServiceControllerStatus.Stopped);
- Assert.Equal(expected, _testService.GetServiceOutput());
}
[ConditionalFact(nameof(IsElevatedAndSupportsEventLogs))]
@@ -193,7 +179,7 @@ OnStop
sb.Stop();
EventLog.DeleteEventSource(sb.ServiceName);
}
- }
+ }
}
[ConditionalFact(nameof(IsElevatedAndSupportsEventLogs))]
@@ -214,6 +200,27 @@ OnStop
}
}
}
+
+ [ConditionalFact(nameof(IsProcessElevated))]
+ public void PropagateExceptionFromOnStart()
+ {
+ string serviceName = nameof(PropagateExceptionFromOnStart) + Guid.NewGuid().ToString();
+ TestServiceProvider _testService = new TestServiceProvider(serviceName);
+ _testService.Client.Connect(connectionTimeout);
+ Assert.Equal((int)PipeMessageByteCode.Connected, _testService.GetByte());
+ Assert.Equal((int)PipeMessageByteCode.ExceptionThrown, _testService.GetByte());
+ _testService.DeleteTestServices();
+ }
+
+ private ServiceController ConnectToServer()
+ {
+ _testService.Client.Connect(connectionTimeout);
+ Assert.Equal((int)PipeMessageByteCode.Connected, _testService.GetByte());
+
+ ServiceController controller = new ServiceController(_testService.TestServiceName);
+ AssertExpectedProperties(controller);
+ return controller;
+ }
public void Dispose()
{
diff --git a/src/System.ServiceProcess.ServiceController/tests/ServiceControllerTests.cs b/src/System.ServiceProcess.ServiceController/tests/ServiceControllerTests.cs
index 11978dfe06..c39395cb40 100644
--- a/src/System.ServiceProcess.ServiceController/tests/ServiceControllerTests.cs
+++ b/src/System.ServiceProcess.ServiceController/tests/ServiceControllerTests.cs
@@ -2,10 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using Microsoft.Win32;
-using System;
-using System.Diagnostics;
-using System.Security.Principal;
using Xunit;
namespace System.ServiceProcess.Tests
@@ -13,6 +9,7 @@ namespace System.ServiceProcess.Tests
[OuterLoop(/* Modifies machine state */)]
public class ServiceControllerTests : IDisposable
{
+ private const int connectionTimeout = 30000;
private readonly TestServiceProvider _testService;
private static readonly Lazy<bool> s_isElevated = new Lazy<bool>(() => AdminHelpers.IsProcessElevated());
@@ -77,27 +74,6 @@ namespace System.ServiceProcess.Tests
}
[ConditionalFact(nameof(IsProcessElevated))]
- public void StartWithArguments()
- {
- var controller = new ServiceController(_testService.TestServiceName);
- controller.WaitForStatus(ServiceControllerStatus.Running, _testService.ControlTimeout);
- Assert.Equal(ServiceControllerStatus.Running, controller.Status);
-
- controller.Stop();
- controller.WaitForStatus(ServiceControllerStatus.Stopped, _testService.ControlTimeout);
- Assert.Equal(ServiceControllerStatus.Stopped, controller.Status);
-
- var args = new[] { "a", "b", "c", "d", "e" };
- controller.Start(args);
- controller.WaitForStatus(ServiceControllerStatus.Running, _testService.ControlTimeout);
- Assert.Equal(ServiceControllerStatus.Running, controller.Status);
-
- string argsOutput = _testService.GetServiceOutput().Trim();
- string argsInput = "OnStart args=" + string.Join(",", args);
- Assert.Equal(argsInput, argsOutput);
- }
-
- [ConditionalFact(nameof(IsProcessElevated))]
public void Start_NullArg_ThrowsArgumentNullException()
{
var controller = new ServiceController(_testService.TestServiceName);
@@ -126,20 +102,32 @@ namespace System.ServiceProcess.Tests
[ConditionalFact(nameof(IsProcessElevated))]
public void PauseAndContinue()
{
- var controller = new ServiceController(_testService.TestServiceName);
+ string serviceName = _testService.TestServiceName;
+ var controller = new ServiceController(serviceName);
+
controller.WaitForStatus(ServiceControllerStatus.Running, _testService.ControlTimeout);
Assert.Equal(ServiceControllerStatus.Running, controller.Status);
+ _testService.Client.Connect(connectionTimeout);
+ Assert.Equal((int)PipeMessageByteCode.Connected, _testService.GetByte());
+
for (int i = 0; i < 2; i++)
{
controller.Pause();
+ Assert.Equal((int)PipeMessageByteCode.Pause, _testService.GetByte());
controller.WaitForStatus(ServiceControllerStatus.Paused, _testService.ControlTimeout);
Assert.Equal(ServiceControllerStatus.Paused, controller.Status);
controller.Continue();
+ Assert.Equal((int)PipeMessageByteCode.Continue, _testService.GetByte());
controller.WaitForStatus(ServiceControllerStatus.Running, _testService.ControlTimeout);
Assert.Equal(ServiceControllerStatus.Running, controller.Status);
}
+
+ controller.Stop();
+ Assert.Equal((int)PipeMessageByteCode.Stop, _testService.GetByte());
+ controller.WaitForStatus(ServiceControllerStatus.Stopped, _testService.ControlTimeout);
+ Assert.Equal(ServiceControllerStatus.Stopped, controller.Status);
}
[ConditionalFact(nameof(IsProcessElevated))]
diff --git a/src/System.ServiceProcess.ServiceController/tests/ServiceProcessDescriptionAttributeTests.cs b/src/System.ServiceProcess.ServiceController/tests/ServiceProcessDescriptionAttributeTests.cs
new file mode 100644
index 0000000000..5e609da0a5
--- /dev/null
+++ b/src/System.ServiceProcess.ServiceController/tests/ServiceProcessDescriptionAttributeTests.cs
@@ -0,0 +1,23 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.ServiceProcess.Tests
+{
+ public class ServiceProcessDescriptionAttributeTests
+ {
+ public static TheoryData<string> Ctor_Data => new TheoryData<string>
+ {
+ { string.Empty },
+ { null },
+ { "hello" }
+ };
+
+ [Theory,
+ MemberData(nameof(Ctor_Data))]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void CtorAndGetDescription_test(string input) => Assert.Equal(input, new ServiceProcessDescriptionAttribute(input).Description);
+ }
+}
diff --git a/src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/Helpers.cs b/src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/Helpers.cs
new file mode 100644
index 0000000000..5f9e7cbe8c
--- /dev/null
+++ b/src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/Helpers.cs
@@ -0,0 +1,18 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.ServiceProcess.Tests
+{
+ [Flags]
+ public enum PipeMessageByteCode
+ {
+ Start = 0,
+ Continue = 1,
+ Pause = 2,
+ Stop = 4,
+ OnCustomCommand = 8,
+ ExceptionThrown = 16,
+ Connected = 32
+ };
+}
diff --git a/src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/Program.cs b/src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/Program.cs
index e812baca1f..38f2301ae2 100644
--- a/src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/Program.cs
+++ b/src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/Program.cs
@@ -2,11 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Text;
-
namespace System.ServiceProcess.Tests
{
public class Program
@@ -15,8 +10,32 @@ namespace System.ServiceProcess.Tests
{
if (args.Length == 1 || args.Length == 2)
{
- TestService testService = new TestService(args[0]);
- ServiceBase.Run(testService);
+ TestService testService;
+ if (args[0].StartsWith("PropagateExceptionFromOnStart"))
+ {
+ var expectedException = new InvalidOperationException("Fail on startup.");
+ testService = new TestService(args[0], expectedException);
+ try
+ {
+ ServiceBase.Run(testService);
+ }
+ catch (Exception actualException)
+ {
+ if (object.ReferenceEquals(expectedException, actualException))
+ {
+ testService.WriteStreamAsync(PipeMessageByteCode.ExceptionThrown).Wait();
+ }
+ else
+ {
+ throw actualException;
+ }
+ }
+ }
+ else
+ {
+ testService = new TestService(args[0]);
+ ServiceBase.Run(testService);
+ }
return 0;
}
else if (args.Length == 3)
diff --git a/src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/System.ServiceProcess.ServiceController.TestService.csproj b/src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/System.ServiceProcess.ServiceController.TestService.csproj
index f9a346b6d3..62b33ff7f1 100644
--- a/src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/System.ServiceProcess.ServiceController.TestService.csproj
+++ b/src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/System.ServiceProcess.ServiceController.TestService.csproj
@@ -11,6 +11,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Release|AnyCPU'" />
<ItemGroup>
+ <Compile Include="Helpers.cs" />
<Compile Include="Program.cs" />
<Compile Include="TestServiceInstaller.cs" />
<Compile Include="TestService.cs">
@@ -46,6 +47,9 @@
<Compile Include="$(CommonPath)\Interop\Windows\advapi32\Interop.DeleteService.cs">
<Link>Common\Interop\Windows\Interop.DeleteService.cs</Link>
</Compile>
+ <Compile Include="$(CommonTestPath)\System\Threading\Tasks\TaskTimeoutExtensions.cs">
+ <Link>Common\System\Threading\Tasks\TaskTimeoutExtensions.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup>
<Content Include="System.ServiceProcess.ServiceController.TestService.runtimeconfig.json">
diff --git a/src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/TestService.cs b/src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/TestService.cs
index 93445c4b09..c50f129e8e 100644
--- a/src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/TestService.cs
+++ b/src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/TestService.cs
@@ -2,22 +2,20 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.ComponentModel;
using System.Diagnostics;
-using System;
-using System.Collections;
-using System.IO;
-using System.Reflection;
-using System.Threading;
-using System.Text;
-using System.Runtime.InteropServices;
-using System.Globalization;
+using System.IO.Pipes;
+using System.Threading.Tasks;
namespace System.ServiceProcess.Tests
{
public class TestService : ServiceBase
{
- public TestService(string serviceName)
+ private bool _disposed;
+ private Task _waitClientConnect;
+ private NamedPipeServerStream _serverStream;
+ private readonly Exception _exception;
+
+ public TestService(string serviceName, Exception throwException = null)
{
this.ServiceName = serviceName;
@@ -29,66 +27,100 @@ namespace System.ServiceProcess.Tests
// We cannot easily test these so disable the events
this.CanHandleSessionChangeEvent = false;
this.CanHandlePowerEvent = false;
- }
+ this._exception = throwException;
- public static string GetLogPath(string serviceName)
- {
- return typeof(TestService).Assembly.Location + "." + serviceName + ".log";
+ this._serverStream = new NamedPipeServerStream(serviceName);
+ _waitClientConnect = this._serverStream.WaitForConnectionAsync();
+ _waitClientConnect.ContinueWith((t) => WriteStreamAsync(PipeMessageByteCode.Connected));
}
protected override void OnContinue()
{
- WriteLog(nameof(OnContinue));
base.OnContinue();
+ WriteStreamAsync(PipeMessageByteCode.Continue).Wait();
}
protected override void OnCustomCommand(int command)
{
- WriteLog(nameof(OnCustomCommand) + " command=" + command);
base.OnCustomCommand(command);
+ WriteStreamAsync(PipeMessageByteCode.OnCustomCommand, command).Wait();
}
protected override void OnPause()
{
- WriteLog(nameof(OnPause));
base.OnPause();
+ WriteStreamAsync(PipeMessageByteCode.Pause).Wait();
}
protected override void OnSessionChange(SessionChangeDescription changeDescription)
{
- WriteLog(nameof(OnSessionChange) + " change=" + changeDescription.ToString());
base.OnSessionChange(changeDescription);
}
protected override bool OnPowerEvent(PowerBroadcastStatus powerStatus)
{
- WriteLog(nameof(OnPowerEvent) + " status=" + powerStatus.ToString());
return base.OnPowerEvent(powerStatus);
}
protected override void OnShutdown()
{
- WriteLog(nameof(OnShutdown));
base.OnShutdown();
}
protected override void OnStart(string[] args)
{
- File.Delete(GetLogPath(ServiceName));
-
- WriteLog(nameof(OnStart) + " args=" + string.Join(",", args));
base.OnStart(args);
+ if (_exception != null)
+ {
+ throw _exception;
+ }
+
+ if (args.Length == 4 && args[0] == "StartWithArguments")
+ {
+ Debug.Assert(args[1] == "a");
+ Debug.Assert(args[2] == "b");
+ Debug.Assert(args[3] == "c");
+ WriteStreamAsync(PipeMessageByteCode.Start).Wait();
+ }
}
protected override void OnStop()
{
- WriteLog(nameof(OnStop));
base.OnStop();
+ WriteStreamAsync(PipeMessageByteCode.Stop).Wait();
+ }
+
+ public async Task WriteStreamAsync(PipeMessageByteCode code, int command = 0)
+ {
+ if (_waitClientConnect.IsCompleted)
+ {
+ Task writeCompleted;
+ const int WriteTimeout = 60000;
+ if (code == PipeMessageByteCode.OnCustomCommand)
+ {
+ writeCompleted = _serverStream.WriteAsync(new byte[] { (byte)command }, 0, 1);
+ }
+ else
+ {
+ writeCompleted = _serverStream.WriteAsync(new byte[] { (byte)code }, 0, 1);
+ }
+ await writeCompleted.TimeoutAfter(WriteTimeout).ConfigureAwait(false);
+ }
+ else
+ {
+ // We get here if the service is getting torn down before a client ever connected.
+ // some tests do this.
+ }
}
- private void WriteLog(string msg)
+ protected override void Dispose(bool disposing)
{
- File.AppendAllText(GetLogPath(ServiceName), msg + Environment.NewLine);
+ if (!_disposed)
+ {
+ _serverStream.Dispose();
+ _disposed = true;
+ base.Dispose();
+ }
}
}
}
diff --git a/src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/TestServiceInstaller.cs b/src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/TestServiceInstaller.cs
index 0f68314816..d0218da2d6 100644
--- a/src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/TestServiceInstaller.cs
+++ b/src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.TestService/TestServiceInstaller.cs
@@ -4,7 +4,6 @@
using System.ComponentModel;
using System.Diagnostics;
-using System.Threading;
using System.Text;
using System.Runtime.InteropServices;
@@ -14,8 +13,6 @@ namespace System.ServiceProcess.Tests
{
public const string LocalServiceName = "NT AUTHORITY\\LocalService";
- private string _removalStack;
-
public TestServiceInstaller()
{
}
@@ -94,7 +91,7 @@ namespace System.ServiceProcess.Tests
ServiceCommandLine, null, IntPtr.Zero, servicesDependedOn, username, password);
if (serviceHandle == IntPtr.Zero)
- throw new Win32Exception();
+ throw new Win32Exception("Cannot create service");
// A local variable in an unsafe method is already fixed -- so we don't need a "fixed { }" blocks to protect
// across the p/invoke calls below.
@@ -106,7 +103,7 @@ namespace System.ServiceProcess.Tests
bool success = Interop.Advapi32.ChangeServiceConfig2(serviceHandle, Interop.Advapi32.ServiceConfigOptions.SERVICE_CONFIG_DESCRIPTION, ref serviceDesc);
Marshal.FreeHGlobal(serviceDesc.description);
if (!success)
- throw new Win32Exception();
+ throw new Win32Exception("Cannot set description");
}
// Start the service after creating it
@@ -115,7 +112,8 @@ namespace System.ServiceProcess.Tests
if (svc.Status != ServiceControllerStatus.Running)
{
svc.Start();
- svc.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(30));
+ if (!ServiceName.StartsWith("PropagateExceptionFromOnStart"))
+ svc.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(30));
}
}
}
@@ -130,24 +128,30 @@ namespace System.ServiceProcess.Tests
public void RemoveService()
{
- if (ServiceName == null)
- throw new InvalidOperationException($"Already removed service at stack ${_removalStack}");
-
- // Store the stack for logging in case we're called twice
try
{
- throw new Exception();
+ StopService();
}
- catch (Exception e)
+ finally
{
- _removalStack = e.StackTrace;
+ // If the service didn't stop promptly, we will get a TimeoutException.
+ // This means the test service has gotten "jammed".
+ // Meantime we still want this service to get deleted, so we'll go ahead and call
+ // DeleteService, which will schedule it to get deleted on reboot.
+ // We won't catch the exception: we do want the test to fail.
+
+ DeleteService();
+
+ ServiceName = null;
}
+ }
- // Stop the service
+ private void StopService()
+ {
using (ServiceController svc = new ServiceController(ServiceName))
{
// The Service exists at this point, but OpenService is failing, possibly because its being invoked concurrently for another service.
- // https://github.com/dotnet/corefx/issues/23388
+ // https://github.com/dotnet/corefx/issues/23388
if (svc.Status != ServiceControllerStatus.Stopped)
{
try
@@ -156,17 +160,26 @@ namespace System.ServiceProcess.Tests
}
catch (InvalidOperationException)
{
- ServiceName = null;
+ // Already stopped
return;
}
- svc.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(30));
+ // var sw = Stopwatch.StartNew();
+ svc.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(120));
+ // sw.Stop();
+ // if (sw.Elapsed > TimeSpan.FromSeconds(30))
+ // {
+ // Console.WriteLine($"Took unexpectedly long to stop a service: {sw.Elapsed.TotalSeconds}");
+ // }
}
}
+ }
+ private void DeleteService()
+ {
IntPtr serviceManagerHandle = Interop.Advapi32.OpenSCManager(null, null, Interop.Advapi32.ServiceControllerOptions.SC_MANAGER_ALL);
if (serviceManagerHandle == IntPtr.Zero)
- throw new Win32Exception();
+ throw new Win32Exception("Could not open SCM");
IntPtr serviceHandle = IntPtr.Zero;
try
@@ -175,10 +188,10 @@ namespace System.ServiceProcess.Tests
ServiceName, Interop.Advapi32.ServiceOptions.STANDARD_RIGHTS_DELETE);
if (serviceHandle == IntPtr.Zero)
- throw new Win32Exception();
+ throw new Win32Exception($"Could not find service '{ServiceName}'");
if (!Interop.Advapi32.DeleteService(serviceHandle))
- throw new Win32Exception();
+ throw new Win32Exception($"Could not delete service '{ServiceName}'");
}
finally
{
@@ -187,8 +200,6 @@ namespace System.ServiceProcess.Tests
Interop.Advapi32.CloseServiceHandle(serviceManagerHandle);
}
-
- ServiceName = null;
}
}
} \ No newline at end of file
diff --git a/src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.Tests.csproj b/src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.Tests.csproj
index 52c5fd1475..6e5a4a4aa6 100644
--- a/src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.Tests.csproj
+++ b/src/System.ServiceProcess.ServiceController/tests/System.ServiceProcess.ServiceController.Tests.csproj
@@ -13,6 +13,7 @@
<Compile Include="TestServiceProvider.cs" />
<Compile Include="SafeServiceControllerTests.cs" />
<Compile Include="ServiceControllerTests.cs" />
+ <Compile Include="ServiceProcessDescriptionAttributeTests.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include=".\System.ServiceProcess.ServiceController.TestService\System.ServiceProcess.ServiceController.TestService.csproj" />
diff --git a/src/System.ServiceProcess.ServiceController/tests/TestServiceProvider.cs b/src/System.ServiceProcess.ServiceController/tests/TestServiceProvider.cs
index 47800befb6..e1d00ded30 100644
--- a/src/System.ServiceProcess.ServiceController/tests/TestServiceProvider.cs
+++ b/src/System.ServiceProcess.ServiceController/tests/TestServiceProvider.cs
@@ -2,26 +2,47 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using Microsoft.Win32;
-using System;
using System.Diagnostics;
+using System.IO.Pipes;
using System.Security.Principal;
-using Xunit;
-using System.IO;
-using System.Threading;
+using System.Threading.Tasks;
namespace System.ServiceProcess.Tests
{
internal sealed class TestServiceProvider
{
+ private const int readTimeout = 60000;
+
private static readonly Lazy<bool> s_runningWithElevatedPrivileges = new Lazy<bool>(
() => new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator));
+ private NamedPipeClientStream _client;
+
public static bool RunningWithElevatedPrivileges
{
get { return s_runningWithElevatedPrivileges.Value; }
}
+ public NamedPipeClientStream Client
+ {
+ get
+ {
+ if (_client == null)
+ {
+ _client = new NamedPipeClientStream(".", TestServiceName, PipeDirection.In);
+ }
+ return _client;
+ }
+ set
+ {
+ if (value == null)
+ {
+ _client.Dispose();
+ _client = null;
+ }
+ }
+ }
+
public readonly string TestServiceAssembly = typeof(TestService).Assembly.Location;
public readonly string TestMachineName;
public readonly TimeSpan ControlTimeout;
@@ -53,12 +74,24 @@ namespace System.ServiceProcess.Tests
CreateTestServices();
}
+ public async Task<byte> ReadPipeAsync()
+ {
+ Task readTask;
+ byte[] received = new byte[] { 0 };
+ readTask = Client.ReadAsync(received, 0, 1);
+ await readTask.TimeoutAfter(readTimeout).ConfigureAwait(false);
+ return received[0];
+ }
+
+ public byte GetByte() => ReadPipeAsync().Result;
+
private void CreateTestServices()
{
TestServiceInstaller testServiceInstaller = new TestServiceInstaller();
testServiceInstaller.ServiceName = TestServiceName;
testServiceInstaller.DisplayName = TestServiceDisplayName;
+ testServiceInstaller.Description = "__Dummy Test Service__";
if (_dependentServices != null)
{
@@ -90,22 +123,15 @@ namespace System.ServiceProcess.Tests
{
try
{
+ if (_client != null)
+ {
+ _client.Dispose();
+ _client = null;
+ }
+
TestServiceInstaller testServiceInstaller = new TestServiceInstaller();
testServiceInstaller.ServiceName = TestServiceName;
testServiceInstaller.RemoveService();
-
- if (File.Exists(LogPath))
- {
- try
- {
- File.Delete(LogPath);
- }
- catch (IOException)
- {
- // Don't fail simply because the service was not fully cleaned up
- // and is still holding a handle to the log file
- }
- }
}
finally
{
@@ -117,16 +143,5 @@ namespace System.ServiceProcess.Tests
}
}
}
-
- private string LogPath => TestService.GetLogPath(TestServiceName);
-
- public string GetServiceOutput()
- {
- // Need to open with FileShare.ReadWrite because we expect the service still has it open for write
- using (StreamReader reader = new StreamReader(File.Open(LogPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
- {
- return reader.ReadToEnd();
- }
- }
}
}
diff --git a/src/System.Text.Encoding.CodePages/ref/System.Text.Encoding.CodePages.cs b/src/System.Text.Encoding.CodePages/ref/System.Text.Encoding.CodePages.cs
index 71c444cab2..44737d78f9 100644
--- a/src/System.Text.Encoding.CodePages/ref/System.Text.Encoding.CodePages.cs
+++ b/src/System.Text.Encoding.CodePages/ref/System.Text.Encoding.CodePages.cs
@@ -5,12 +5,13 @@
// Changes to this file must follow the http://aka.ms/api-review process.
// ------------------------------------------------------------------------------
-
namespace System.Text
{
- public sealed partial class CodePagesEncodingProvider
+ public sealed partial class CodePagesEncodingProvider : System.Text.EncodingProvider
{
internal CodePagesEncodingProvider() { }
public static System.Text.EncodingProvider Instance { get { throw null; } }
+ public override System.Text.Encoding GetEncoding(int codepage) { throw null; }
+ public override System.Text.Encoding GetEncoding(string name) { throw null; }
}
}
diff --git a/src/System.Text.Encoding/tests/Decoder/DecoderSpanTests.netcoreapp.cs b/src/System.Text.Encoding/tests/Decoder/DecoderSpanTests.netcoreapp.cs
index 1f51d02a57..4a2e3d5c7e 100644
--- a/src/System.Text.Encoding/tests/Decoder/DecoderSpanTests.netcoreapp.cs
+++ b/src/System.Text.Encoding/tests/Decoder/DecoderSpanTests.netcoreapp.cs
@@ -26,7 +26,7 @@ namespace System.Text.Encodings.Tests
byte[] textBytes = e.GetBytes(TextString);
char[] chars = new char[TextString.Length];
- Assert.Equal(chars.Length, e.GetDecoder().GetChars(textBytes.AsReadOnlySpan(), chars.AsSpan(), flush: true));
+ Assert.Equal(chars.Length, e.GetDecoder().GetChars(textBytes, chars.AsSpan(), flush: true));
Assert.Equal(TextString, new string(chars));
}
@@ -40,7 +40,7 @@ namespace System.Text.Encodings.Tests
char[] chars;
chars = new char[TextString.Length];
- decoder.Convert(textBytes.AsSpan(), chars.AsSpan().Slice(0, 2), true, out int bytesUsed, out int charsUsed, out bool completed);
+ decoder.Convert(textBytes.AsSpan(), chars.AsSpan(0, 2), true, out int bytesUsed, out int charsUsed, out bool completed);
Assert.Equal("he", new string(chars, 0, 2));
Assert.Equal(2, bytesUsed);
Assert.Equal(2, charsUsed);
diff --git a/src/System.Text.Encoding/tests/Encoder/EncoderSpanTests.netcoreapp.cs b/src/System.Text.Encoding/tests/Encoder/EncoderSpanTests.netcoreapp.cs
index e6c81c47fc..105c864115 100644
--- a/src/System.Text.Encoding/tests/Encoder/EncoderSpanTests.netcoreapp.cs
+++ b/src/System.Text.Encoding/tests/Encoder/EncoderSpanTests.netcoreapp.cs
@@ -13,7 +13,7 @@ namespace System.Text.Encodings.Tests
{
const string TextString = "hello world";
Encoding e = Encoding.UTF8;
- Assert.Equal(e.GetByteCount(TextString), e.GetEncoder().GetByteCount(TextString.AsReadOnlySpan(), flush: true));
+ Assert.Equal(e.GetByteCount(TextString), e.GetEncoder().GetByteCount(TextString.AsSpan(), flush: true));
}
[Fact]
@@ -23,7 +23,7 @@ namespace System.Text.Encodings.Tests
Encoding e = Encoding.UTF8;
byte[] bytes = new byte[e.GetByteCount(TextString)];
- Assert.Equal(bytes.Length, e.GetEncoder().GetBytes(TextString.AsReadOnlySpan(), bytes, flush: true));
+ Assert.Equal(bytes.Length, e.GetEncoder().GetBytes(TextString.AsSpan(), bytes, flush: true));
Assert.Equal(e.GetBytes(TextString), bytes);
}
@@ -36,14 +36,14 @@ namespace System.Text.Encodings.Tests
byte[] bytes;
bytes = new byte[encoding.GetByteCount(TextString)];
- encoder.Convert(TextString.AsReadOnlySpan(), bytes.AsSpan().Slice(0, 2), true, out int charsUsed, out int bytesUsed, out bool completed);
- Assert.Equal(encoding.GetBytes(TextString).AsSpan().Slice(0, 2).ToArray(), bytes.AsSpan().Slice(0, 2).ToArray());
+ encoder.Convert(TextString.AsSpan(), bytes.AsSpan(0, 2), true, out int charsUsed, out int bytesUsed, out bool completed);
+ Assert.Equal(encoding.GetBytes(TextString).AsSpan(0, 2).ToArray(), bytes.AsSpan(0, 2).ToArray());
Assert.Equal(2, charsUsed);
Assert.Equal(2, bytesUsed);
Assert.False(completed);
bytes = new byte[encoding.GetByteCount(TextString)];
- encoder.Convert(TextString.AsReadOnlySpan(), bytes, true, out charsUsed, out bytesUsed, out completed);
+ encoder.Convert(TextString.AsSpan(), bytes, true, out charsUsed, out bytesUsed, out completed);
Assert.Equal(encoding.GetBytes(TextString), bytes);
Assert.Equal(TextString.Length, charsUsed);
Assert.Equal(bytes.Length, bytesUsed);
diff --git a/src/System.Text.Encoding/tests/Encoding/EncodingGetEncodingTests.cs b/src/System.Text.Encoding/tests/Encoding/EncodingGetEncodingTests.cs
index cf5475b76c..2713ff6545 100644
--- a/src/System.Text.Encoding/tests/Encoding/EncodingGetEncodingTests.cs
+++ b/src/System.Text.Encoding/tests/Encoding/EncodingGetEncodingTests.cs
@@ -2,12 +2,13 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Diagnostics;
using System.Globalization;
using Xunit;
namespace System.Text.Tests
{
- public class EncodingGetEncodingTest
+ public class EncodingGetEncodingTest : RemoteExecutorTestBase
{
[Fact]
public void GetEncoding_String_Invalid()
@@ -99,10 +100,10 @@ namespace System.Text.Tests
[Fact]
public void GetEncoding_EncodingName()
{
- CultureInfo originalUICulture = CultureInfo.CurrentUICulture;
- try
+ // Workaround issue: UWP culture is process wide
+ RemoteInvoke(() =>
{
- CultureInfo.CurrentCulture = new CultureInfo("en-US");
+ CultureInfo.CurrentUICulture = CultureInfo.InvariantCulture;
foreach (var map in s_mapping)
{
@@ -115,11 +116,7 @@ namespace System.Text.Tests
Assert.All(name, ch => Assert.InRange(ch, 0, 127));
}
- }
- finally
- {
- CultureInfo.CurrentUICulture = originalUICulture;
- }
+ }).Dispose();
}
[Fact]
diff --git a/src/System.Text.Encoding/tests/EncodingTestHelpers.netcoreapp.cs b/src/System.Text.Encoding/tests/EncodingTestHelpers.netcoreapp.cs
index f82e81ae46..470baace3e 100644
--- a/src/System.Text.Encoding/tests/EncodingTestHelpers.netcoreapp.cs
+++ b/src/System.Text.Encoding/tests/EncodingTestHelpers.netcoreapp.cs
@@ -14,7 +14,10 @@ namespace System.Text.Tests
Assert.Equal(expected, encoding.GetByteCount(chars, index, count));
// Use GetByteCount(ReadOnlySpan<char> chars)
- Assert.Equal(expected, encoding.GetByteCount(chars.AsReadOnlySpan().Slice(index, count)));
+ Assert.Equal(expected, encoding.GetByteCount(chars.AsSpan(index, count)));
+
+ if (count == 0)
+ Assert.Equal(expected, encoding.GetByteCount(ReadOnlySpan<char>.Empty));
}
static partial void GetBytes_NetCoreApp(Encoding encoding, string chars, int index, int count, byte[] expected)
@@ -25,14 +28,20 @@ namespace System.Text.Tests
// Use GetBytes(ReadOnlySpan<char>, Span<byte>)
Array.Clear(stringResultAdvanced, 0, stringResultAdvanced.Length);
- Assert.Equal(expected.Length, encoding.GetBytes(chars.AsReadOnlySpan().Slice(index, count), (Span<byte>)stringResultAdvanced));
+ Assert.Equal(expected.Length, encoding.GetBytes(chars.AsSpan(index, count), (Span<byte>)stringResultAdvanced));
VerifyGetBytes(stringResultAdvanced, 0, stringResultAdvanced.Length, new byte[expected.Length], expected);
+
+ if (count == 0)
+ Assert.Equal(expected.Length, encoding.GetBytes(ReadOnlySpan<char>.Empty, (Span<byte>)stringResultAdvanced));
}
static partial void GetCharCount_NetCoreApp(Encoding encoding, byte[] bytes, int index, int count, int expected)
{
// Use GetCharCount(ReadOnlySpan<byte>)
Assert.Equal(expected, encoding.GetCharCount(new ReadOnlySpan<byte>(bytes, index, count)));
+
+ if (count == 0)
+ Assert.Equal(expected, encoding.GetCharCount(ReadOnlySpan<byte>.Empty));
}
static partial void VerifyGetChars_NetCoreApp(Encoding encoding, byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex, char[] expectedChars)
@@ -42,12 +51,21 @@ namespace System.Text.Tests
int charCount = encoding.GetChars(new ReadOnlySpan<byte>(bytes, byteIndex, byteCount), new Span<char>(byteChars).Slice(charIndex));
VerifyGetChars(byteChars, charIndex, charCount, (char[])chars.Clone(), expectedChars);
Assert.Equal(expectedChars.Length, charCount);
+
+ if (byteCount == 0)
+ {
+ charCount = encoding.GetChars(ReadOnlySpan<byte>.Empty, new Span<char>(byteChars).Slice(charIndex));
+ Assert.Equal(expectedChars.Length, charCount);
+ }
}
static partial void GetString_NetCoreApp(Encoding encoding, byte[] bytes, int index, int count, string expected)
{
// Use GetString(ReadOnlySpan<byte>)
Assert.Equal(expected, encoding.GetString(new ReadOnlySpan<byte>(bytes, index, count)));
+
+ if (count == 0)
+ Assert.Equal(expected, encoding.GetString(ReadOnlySpan<byte>.Empty));
}
}
}
diff --git a/src/System.Text.Encoding/tests/System.Text.Encoding.Tests.csproj b/src/System.Text.Encoding/tests/System.Text.Encoding.Tests.csproj
index f9f3aed6ae..ecea2a8a2c 100644
--- a/src/System.Text.Encoding/tests/System.Text.Encoding.Tests.csproj
+++ b/src/System.Text.Encoding/tests/System.Text.Encoding.Tests.csproj
@@ -81,5 +81,11 @@
<Compile Include="Decoder\Decoder.cs" />
<Compile Include="Encoder\Encoder.cs" />
</ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="$(CommonTestPath)\System\Diagnostics\RemoteExecutorConsoleApp\RemoteExecutorConsoleApp.csproj">
+ <Project>{69e46a6f-9966-45a5-8945-2559fe337827}</Project>
+ <Name>RemoteExecutorConsoleApp</Name>
+ </ProjectReference>
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.Text.Encoding/tests/UTF8Encoding/UTF8EncodingDecode.cs b/src/System.Text.Encoding/tests/UTF8Encoding/UTF8EncodingDecode.cs
index 78a5f4da6f..618858cbc5 100644
--- a/src/System.Text.Encoding/tests/UTF8Encoding/UTF8EncodingDecode.cs
+++ b/src/System.Text.Encoding/tests/UTF8Encoding/UTF8EncodingDecode.cs
@@ -103,7 +103,6 @@ namespace System.Text.Tests
[Theory]
[MemberData(nameof(Decode_TestData))]
- [ActiveIssue("https://github.com/dotnet/corefx/issues/20525", TargetFrameworkMonikers.UapAot)]
public void Decode(byte[] bytes, int index, int count, string expected)
{
EncodingHelpers.Decode(new UTF8Encoding(true, false), bytes, index, count, expected);
diff --git a/src/System.Text.Encoding/tests/UnicodeEncoding/UnicodeEncodingDecode.cs b/src/System.Text.Encoding/tests/UnicodeEncoding/UnicodeEncodingDecode.cs
index cbded91274..a057429ba2 100644
--- a/src/System.Text.Encoding/tests/UnicodeEncoding/UnicodeEncodingDecode.cs
+++ b/src/System.Text.Encoding/tests/UnicodeEncoding/UnicodeEncodingDecode.cs
@@ -73,7 +73,6 @@ namespace System.Text.Tests
[Theory]
[MemberData(nameof(Decode_TestData))]
- [ActiveIssue("https://github.com/dotnet/corefx/issues/20525", TargetFrameworkMonikers.UapAot)]
public void Decode(byte[] littleEndianBytes, int index, int count, string expected)
{
byte[] bigEndianBytes = GetBigEndianBytes(littleEndianBytes, index, count);
diff --git a/src/System.Text.RegularExpressions/System.Text.RegularExpressions.sln b/src/System.Text.RegularExpressions/System.Text.RegularExpressions.sln
index 2680b4879d..aff3ca264e 100644
--- a/src/System.Text.RegularExpressions/System.Text.RegularExpressions.sln
+++ b/src/System.Text.RegularExpressions/System.Text.RegularExpressions.sln
@@ -7,6 +7,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Text.RegularExpressi
{2C58640B-5BED-4E83-9554-CD2B9762643F} = {2C58640B-5BED-4E83-9554-CD2B9762643F}
EndProjectSection
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Text.RegularExpressions.Performance.Tests", "tests\Performance\System.Text.RegularExpressions.Performance.Tests.csproj", "{7f4b8c48-8692-4885-bf84-feb7ea82e34b}"
+ ProjectSection(ProjectDependencies) = postProject
+ {2C58640B-5BED-4E83-9554-CD2B9762643F} = {2C58640B-5BED-4E83-9554-CD2B9762643F}
+ EndProjectSection
+EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Text.RegularExpressions", "src\System.Text.RegularExpressions.csproj", "{2C58640B-5BED-4E83-9554-CD2B9762643F}"
ProjectSection(ProjectDependencies) = postProject
{B262B15E-13E6-4C1E-A25E-16D06E222A09} = {B262B15E-13E6-4C1E-A25E-16D06E222A09}
@@ -30,6 +35,10 @@ Global
{94B106C2-D574-4392-80AB-3EE308A078DF}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
{94B106C2-D574-4392-80AB-3EE308A078DF}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
{94B106C2-D574-4392-80AB-3EE308A078DF}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
+ {7f4b8c48-8692-4885-bf84-feb7ea82e34b}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
+ {7f4b8c48-8692-4885-bf84-feb7ea82e34b}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
+ {7f4b8c48-8692-4885-bf84-feb7ea82e34b}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
+ {7f4b8c48-8692-4885-bf84-feb7ea82e34b}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
{2C58640B-5BED-4E83-9554-CD2B9762643F}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
{2C58640B-5BED-4E83-9554-CD2B9762643F}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
{2C58640B-5BED-4E83-9554-CD2B9762643F}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
@@ -44,6 +53,7 @@ Global
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{94B106C2-D574-4392-80AB-3EE308A078DF} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
+ {7f4b8c48-8692-4885-bf84-feb7ea82e34b} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
{2C58640B-5BED-4E83-9554-CD2B9762643F} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD}
{B262B15E-13E6-4C1E-A25E-16D06E222A09} = {2E666815-2EDB-464B-9DF6-380BF4789AD4}
EndGlobalSection
diff --git a/src/System.Text.RegularExpressions/src/MatchingRefApiCompatBaseline.txt b/src/System.Text.RegularExpressions/src/MatchingRefApiCompatBaseline.txt
new file mode 100644
index 0000000000..43f5db97fe
--- /dev/null
+++ b/src/System.Text.RegularExpressions/src/MatchingRefApiCompatBaseline.txt
@@ -0,0 +1,2 @@
+# API is only for Debug purposes
+MembersMustExist : Member 'System.Text.RegularExpressions.RegexOptions System.Text.RegularExpressions.RegexOptions.Debug' does not exist in the implementation but it does exist in the contract.
diff --git a/src/System.Text.RegularExpressions/src/System.Text.RegularExpressions.csproj b/src/System.Text.RegularExpressions/src/System.Text.RegularExpressions.csproj
index 8b3d02dd91..f7ebf80342 100644
--- a/src/System.Text.RegularExpressions/src/System.Text.RegularExpressions.csproj
+++ b/src/System.Text.RegularExpressions/src/System.Text.RegularExpressions.csproj
@@ -5,36 +5,45 @@
<ProjectGuid>{2C58640B-5BED-4E83-9554-CD2B9762643F}</ProjectGuid>
<AssemblyName>System.Text.RegularExpressions</AssemblyName>
<DefineConstants Condition="'$(TargetGroup)' == 'netcoreapp'">$(DefineConstants);FEATURE_COMPILED</DefineConstants>
+ <ILLinkClearInitLocals>true</ILLinkClearInitLocals>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Windows_NT-Release|AnyCPU'" />
<ItemGroup>
- <Compile Include="System\Text\RegularExpressions\HashtableExtensions.cs" />
+ <Compile Include="System\Collections\Generic\ValueListBuilder.Pop.cs" />
+ <Compile Include="System\Collections\HashtableExtensions.cs" />
+ <Compile Include="System\Text\RegularExpressions\Capture.cs" />
+ <Compile Include="System\Text\RegularExpressions\CaptureCollection.cs" />
+ <Compile Include="System\Text\RegularExpressions\CollectionDebuggerProxy.cs" />
+ <Compile Include="System\Text\RegularExpressions\Group.cs" />
+ <Compile Include="System\Text\RegularExpressions\GroupCollection.cs" />
+ <Compile Include="System\Text\RegularExpressions\Match.cs" />
+ <Compile Include="System\Text\RegularExpressions\MatchCollection.cs" />
+ <Compile Include="System\Text\RegularExpressions\Reference.cs" />
+ <Compile Include="System\Text\RegularExpressions\Regex.Cache.cs" />
<Compile Include="System\Text\RegularExpressions\Regex.cs" />
+ <Compile Include="System\Text\RegularExpressions\Regex.Match.cs" />
+ <Compile Include="System\Text\RegularExpressions\Regex.Replace.cs" />
+ <Compile Include="System\Text\RegularExpressions\Regex.Split.cs" />
+ <Compile Include="System\Text\RegularExpressions\Regex.Timeout.cs" />
<Compile Include="System\Text\RegularExpressions\RegexBoyerMoore.cs" />
- <Compile Include="System\Text\RegularExpressions\RegexCapture.cs" />
- <Compile Include="System\Text\RegularExpressions\RegexCaptureCollection.cs" />
<Compile Include="System\Text\RegularExpressions\RegexCharClass.cs" />
<Compile Include="System\Text\RegularExpressions\RegexCode.cs" />
- <Compile Include="System\Text\RegularExpressions\RegexCollectionDebuggerProxy.cs" />
<Compile Include="System\Text\RegularExpressions\RegexCompilationInfo.cs" />
<Compile Include="System\Text\RegularExpressions\RegexFCD.cs" />
- <Compile Include="System\Text\RegularExpressions\RegexGroup.cs" />
- <Compile Include="System\Text\RegularExpressions\RegexGroupCollection.cs" />
<Compile Include="System\Text\RegularExpressions\RegexInterpreter.cs" />
- <Compile Include="System\Text\RegularExpressions\RegexMatch.cs" />
- <Compile Include="System\Text\RegularExpressions\RegexMatchCollection.cs" />
<Compile Include="System\Text\RegularExpressions\RegexMatchTimeoutException.cs" />
<Compile Include="System\Text\RegularExpressions\RegexNode.cs" />
<Compile Include="System\Text\RegularExpressions\RegexOptions.cs" />
<Compile Include="System\Text\RegularExpressions\RegexParser.cs" />
+ <Compile Include="System\Text\RegularExpressions\RegexPrefix.cs" />
<Compile Include="System\Text\RegularExpressions\RegexReplacement.cs" />
<Compile Include="System\Text\RegularExpressions\RegexRunner.cs" />
+ <Compile Include="System\Text\RegularExpressions\RegexRunnerFactory.cs" />
<Compile Include="System\Text\RegularExpressions\RegexTree.cs" />
<Compile Include="System\Text\RegularExpressions\RegexWriter.cs" />
- <Compile Include="System\Text\RegularExpressions\RegexRunnerFactory.cs" />
<!-- Common or Common-branched source files -->
<Compile Include="$(CommonPath)\System\NotImplemented.cs">
<Link>Common\System\NotImplemented.cs</Link>
@@ -42,6 +51,9 @@
<Compile Include="$(CommonPath)\System\IO\StringBuilderCache.cs">
<Link>Common\System\IO\StringBuilderCache.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\CoreLib\System\Collections\Generic\ValueListBuilder.cs">
+ <Link>Common\System\Collections\Generic\ValueListBuilder.cs</Link>
+ </Compile>
</ItemGroup>
<!-- Files that enable compiled feature -->
<ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp'">
@@ -51,9 +63,11 @@
<Compile Include="System\Text\RegularExpressions\RegexLWCGCompiler.cs" />
</ItemGroup>
<ItemGroup>
+ <Reference Include="System.Buffers" />
<Reference Include="System.Collections" />
<Reference Include="System.Diagnostics.Debug" />
<Reference Include="System.Diagnostics.Tools" />
+ <Reference Include="System.Memory" />
<Reference Include="System.Resources.ResourceManager" />
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.Extensions" />
diff --git a/src/System.Text.RegularExpressions/src/System/Collections/Generic/ValueListBuilder.Pop.cs b/src/System.Text.RegularExpressions/src/System/Collections/Generic/ValueListBuilder.Pop.cs
new file mode 100644
index 0000000000..18075c0261
--- /dev/null
+++ b/src/System.Text.RegularExpressions/src/System/Collections/Generic/ValueListBuilder.Pop.cs
@@ -0,0 +1,21 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.CompilerServices;
+
+namespace System.Collections.Generic
+{
+ /// <summary>
+ /// These public methods are required by RegexWriter.
+ /// </summary>
+ internal ref partial struct ValueListBuilder<T>
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public T Pop()
+ {
+ _pos--;
+ return _span[_pos];
+ }
+ }
+}
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/HashtableExtensions.cs b/src/System.Text.RegularExpressions/src/System/Collections/HashtableExtensions.cs
index f86c9b8076..c2ad00b428 100644
--- a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/HashtableExtensions.cs
+++ b/src/System.Text.RegularExpressions/src/System/Collections/HashtableExtensions.cs
@@ -2,9 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Collections;
-
-namespace System.Text.RegularExpressions
+namespace System.Collections
{
internal static class HashtableExtensions
{
@@ -15,7 +13,7 @@ namespace System.Text.RegularExpressions
value = (T)table[key];
return true;
}
- value = default(T);
+ value = default;
return false;
}
}
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Capture.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Capture.cs
new file mode 100644
index 0000000000..6c5610b02c
--- /dev/null
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Capture.cs
@@ -0,0 +1,61 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// Capture is just a location/length pair that indicates the
+// location of a regular expression match. A single regexp
+// search may return multiple Capture within each capturing
+// RegexGroup.
+
+namespace System.Text.RegularExpressions
+{
+ /// <summary>
+ /// Represents the results from a single subexpression capture. The object represents
+ /// one substring for a single successful capture.
+ /// </summary>
+ public class Capture
+ {
+ internal Capture(string text, int index, int length)
+ {
+ Text = text;
+ Index = index;
+ Length = length;
+ }
+
+ /// <summary>
+ /// Returns the position in the original string where the first character of
+ /// captured substring was found.
+ /// </summary>
+ public int Index { get; private protected set; }
+
+ /// <summary>
+ /// Returns the length of the captured substring.
+ /// </summary>
+ public int Length { get; private protected set; }
+
+ /// <summary>
+ /// The original string
+ /// </summary>
+ internal string Text { get; private protected set; }
+
+ /// <summary>
+ /// Returns the value of this Regex Capture.
+ /// </summary>
+ public string Value => Text.Substring(Index, Length);
+
+ /// <summary>
+ /// Returns the substring that was matched.
+ /// </summary>
+ public override string ToString() => Value;
+
+ /// <summary>
+ /// The substring to the left of the capture
+ /// </summary>
+ internal ReadOnlySpan<char> GetLeftSubstring() => Text.AsSpan(0, Index);
+
+ /// <summary>
+ /// The substring to the right of the capture
+ /// </summary>
+ internal ReadOnlySpan<char> GetRightSubstring() => Text.AsSpan(Index + Length, Text.Length - Index - Length);
+ }
+}
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCaptureCollection.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/CaptureCollection.cs
index b4bf1d0101..0c738317dc 100644
--- a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCaptureCollection.cs
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/CaptureCollection.cs
@@ -21,8 +21,10 @@ namespace System.Text.RegularExpressions
/// to return the set of captures done by a single capturing group.
/// </summary>
[DebuggerDisplay("Count = {Count}")]
- [DebuggerTypeProxy(typeof(RegexCollectionDebuggerProxy<Capture>))]
+#if !MONO
[Serializable]
+#endif
+ [DebuggerTypeProxy(typeof(CollectionDebuggerProxy<Capture>))]
public class CaptureCollection : IList<Capture>, IReadOnlyList<Capture>, IList
{
private readonly Group _group;
@@ -68,16 +70,24 @@ namespace System.Text.RegularExpressions
// first time a capture is accessed, compute them all
if (_captures == null)
{
- _captures = new Capture[_capcount];
- for (int j = 0; j < _capcount - 1; j++)
- {
- _captures[j] = new Capture(_group._text, _group._caps[j * 2], _group._caps[j * 2 + 1]);
- }
+ ForceInitialized();
}
return _captures[i];
}
+ /// <summary>
+ /// Compute all captures
+ /// </summary>
+ internal void ForceInitialized()
+ {
+ _captures = new Capture[_capcount];
+ for (int j = 0; j < _capcount - 1; j++)
+ {
+ _captures[j] = new Capture(_group.Text, _group._caps[j * 2], _group._caps[j * 2 + 1]);
+ }
+ }
+
public bool IsSynchronized => false;
public object SyncRoot => _group;
@@ -110,12 +120,14 @@ namespace System.Text.RegularExpressions
int IList<Capture>.IndexOf(Capture item)
{
- var comparer = EqualityComparer<Capture>.Default;
for (int i = 0; i < Count; i++)
{
- if (comparer.Equals(this[i], item))
+ if (EqualityComparer<Capture>.Default.Equals(this[i], item))
+ {
return i;
+ }
}
+
return -1;
}
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCollectionDebuggerProxy.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/CollectionDebuggerProxy.cs
index 5caea8d58f..e8ef9dc896 100644
--- a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCollectionDebuggerProxy.cs
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/CollectionDebuggerProxy.cs
@@ -7,16 +7,13 @@ using System.Diagnostics;
namespace System.Text.RegularExpressions
{
- internal sealed class RegexCollectionDebuggerProxy<T>
+ internal sealed class CollectionDebuggerProxy<T>
{
private readonly ICollection<T> _collection;
- public RegexCollectionDebuggerProxy(ICollection<T> collection)
+ public CollectionDebuggerProxy(ICollection<T> collection)
{
- if (collection == null)
- throw new ArgumentNullException(nameof(collection));
-
- _collection = collection;
+ _collection = collection ?? throw new ArgumentNullException(nameof(collection));
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
@@ -24,7 +21,7 @@ namespace System.Text.RegularExpressions
{
get
{
- T[] items = new T[_collection.Count];
+ var items = new T[_collection.Count];
_collection.CopyTo(items, 0);
return items;
}
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/CompiledRegexRunner.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/CompiledRegexRunner.cs
index 2ae5caf18d..2d2bd2fc6a 100644
--- a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/CompiledRegexRunner.cs
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/CompiledRegexRunner.cs
@@ -10,9 +10,9 @@ namespace System.Text.RegularExpressions
private Func<RegexRunner, bool> _findFirstCharMethod;
private Action<RegexRunner> _initTrackCountMethod;
- internal CompiledRegexRunner() { }
+ public CompiledRegexRunner() { }
- internal void SetDelegates(Action<RegexRunner> go, Func<RegexRunner,bool> firstChar, Action<RegexRunner> trackCount)
+ public void SetDelegates(Action<RegexRunner> go, Func<RegexRunner,bool> firstChar, Action<RegexRunner> trackCount)
{
_goMethod = go;
_findFirstCharMethod = firstChar;
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/CompiledRegexRunnerFactory.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/CompiledRegexRunnerFactory.cs
index 1f81283199..8b7a9f1fbc 100644
--- a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/CompiledRegexRunnerFactory.cs
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/CompiledRegexRunnerFactory.cs
@@ -2,6 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+// This is the only concrete implementation of RegexRunnerFactory,
+// but we cannot combine them due to RegexRunnerFactory having shipped public.
+
using System.Reflection.Emit;
namespace System.Text.RegularExpressions
@@ -12,7 +15,7 @@ namespace System.Text.RegularExpressions
private readonly DynamicMethod _findFirstCharMethod;
private readonly DynamicMethod _initTrackCountMethod;
- internal CompiledRegexRunnerFactory(DynamicMethod go, DynamicMethod firstChar, DynamicMethod trackCount)
+ public CompiledRegexRunnerFactory(DynamicMethod go, DynamicMethod firstChar, DynamicMethod trackCount)
{
_goMethod = go;
_findFirstCharMethod = firstChar;
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexGroup.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Group.cs
index b84359e472..4f441ffadc 100644
--- a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexGroup.cs
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Group.cs
@@ -16,46 +16,28 @@ namespace System.Text.RegularExpressions
[Serializable]
public class Group : Capture
{
- // the empty group object
internal static readonly Group s_emptyGroup = new Group(string.Empty, Array.Empty<int>(), 0, string.Empty);
internal readonly int[] _caps;
internal int _capcount;
internal CaptureCollection _capcoll;
- internal readonly string _name;
internal Group(string text, int[] caps, int capcount, string name)
-
- : base(text, capcount == 0 ? 0 : caps[(capcount - 1) * 2],
+ : base(text, capcount == 0 ? 0 : caps[(capcount - 1) * 2],
capcount == 0 ? 0 : caps[(capcount * 2) - 1])
{
_caps = caps;
_capcount = capcount;
- _name = name;
+ Name = name;
}
/// <summary>
/// Indicates whether the match is successful.
/// </summary>
- public bool Success
- {
- get
- {
- return _capcount != 0;
- }
- }
+ public bool Success => _capcount != 0;
- public string Name
- {
- get
- {
- return _name;
- }
- }
+ public string Name { get; }
- /*
- * The collection of all captures for this group
- */
/// <summary>
/// Returns a collection of all the captures matched by the capturing
/// group, in innermost-leftmost-first order (or innermost-rightmost-first order if
@@ -72,9 +54,6 @@ namespace System.Text.RegularExpressions
}
}
- /*
- * Convert to a thread-safe object by precomputing cache contents
- */
/// <summary>
/// Returns a Group object equivalent to the one supplied that is safe to share between
/// multiple threads.
@@ -85,14 +64,11 @@ namespace System.Text.RegularExpressions
throw new ArgumentNullException(nameof(inner));
// force Captures to be computed.
-
- CaptureCollection capcoll;
- Capture dummy;
-
- capcoll = inner.Captures;
-
- if (inner._capcount > 0)
- dummy = capcoll[0];
+ CaptureCollection capcoll = inner.Captures;
+ if (inner.Success)
+ {
+ capcoll.ForceInitialized();
+ }
return inner;
}
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexGroupCollection.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/GroupCollection.cs
index bb68ae3bc1..51ae057a4e 100644
--- a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexGroupCollection.cs
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/GroupCollection.cs
@@ -16,8 +16,10 @@ namespace System.Text.RegularExpressions
/// to return the set of captures done by a single capturing group.
/// </summary>
[DebuggerDisplay("Count = {Count}")]
- [DebuggerTypeProxy(typeof(RegexCollectionDebuggerProxy<Group>))]
+#if MONO
[Serializable]
+#endif
+ [DebuggerTypeProxy(typeof(CollectionDebuggerProxy<Group>))]
public class GroupCollection : IList<Group>, IReadOnlyList<Group>, IList
{
private readonly Match _match;
@@ -56,8 +58,7 @@ namespace System.Text.RegularExpressions
{
if (_captureMap != null)
{
- int groupNumImpl;
- if (_captureMap.TryGetValue(groupnum, out groupNumImpl))
+ if (_captureMap.TryGetValue(groupnum, out int groupNumImpl))
{
return GetGroupImpl(groupNumImpl);
}
@@ -86,7 +87,7 @@ namespace System.Text.RegularExpressions
for (int i = 0; i < _groups.Length; i++)
{
string groupname = _match._regex.GroupNameFromNumber(i + 1);
- _groups[i] = new Group(_match._text, _match._matches[i + 1], _match._matchcount[i + 1], groupname);
+ _groups[i] = new Group(_match.Text, _match._matches[i + 1], _match._matchcount[i + 1], groupname);
}
}
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexMatch.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Match.cs
index 97ad8fb80f..f9581a249f 100644
--- a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexMatch.cs
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Match.cs
@@ -36,7 +36,6 @@ namespace System.Text.RegularExpressions
[Serializable]
public class Match : Group
{
- internal static readonly Match s_empty = new Match(null, 1, string.Empty, 0, 0, 0);
internal GroupCollection _groupcoll;
// input to the match
@@ -52,23 +51,11 @@ namespace System.Text.RegularExpressions
internal bool _balancing; // whether we've done any balancing with this match. If we
// have done balancing, we'll need to do extra work in Tidy().
- /// <summary>
- /// Returns an empty Match object.
- /// </summary>
- public static Match Empty
- {
- get
- {
- return s_empty;
- }
- }
-
internal Match(Regex regex, int capcount, string text, int begpos, int len, int startpos)
: base(text, new int[2], 0, "0")
{
_regex = regex;
_matchcount = new int[capcount];
-
_matches = new int[capcount][];
_matches[0] = _caps;
_textbeg = begpos;
@@ -77,17 +64,19 @@ namespace System.Text.RegularExpressions
_balancing = false;
// No need for an exception here. This is only called internally, so we'll use an Assert instead
- System.Diagnostics.Debug.Assert(!(_textbeg < 0 || _textstart < _textbeg || _textend < _textstart || _text.Length < _textend),
+ System.Diagnostics.Debug.Assert(!(_textbeg < 0 || _textstart < _textbeg || _textend < _textstart || Text.Length < _textend),
"The parameters are out of range.");
}
- /*
- * Nonpublic set-text method
- */
+ /// <summary>
+ /// Returns an empty Match object.
+ /// </summary>
+ public static Match Empty { get; } = new Match(null, 1, string.Empty, 0, 0, 0);
+
internal virtual void Reset(Regex regex, string text, int textbeg, int textend, int textstart)
{
_regex = regex;
- _text = text;
+ Text = text;
_textbeg = textbeg;
_textend = textend;
_textstart = textstart;
@@ -121,7 +110,7 @@ namespace System.Text.RegularExpressions
if (_regex == null)
return this;
- return _regex.Run(false, _length, _text, _textbeg, _textend - _textbeg, _textpos);
+ return _regex.Run(false, Length, Text, _textbeg, _textend - _textbeg, _textpos);
}
/// <summary>
@@ -131,29 +120,20 @@ namespace System.Text.RegularExpressions
/// </summary>
public virtual string Result(string replacement)
{
- RegexReplacement repl;
-
if (replacement == null)
throw new ArgumentNullException(nameof(replacement));
if (_regex == null)
throw new NotSupportedException(SR.NoResultOnFailed);
- repl = (RegexReplacement)_regex._replref.Get();
-
- if (repl == null || !repl.Pattern.Equals(replacement))
- {
- repl = RegexParser.ParseReplacement(replacement, _regex.caps, _regex.capsize, _regex.capnames, _regex.roptions);
- _regex._replref.Cache(repl);
- }
+ // Gets the weakly cached replacement helper or creates one if there isn't one already.
+ RegexReplacement repl = RegexReplacement.GetOrCreate(_regex._replref, replacement, _regex.caps, _regex.capsize,
+ _regex.capnames, _regex.roptions);
return repl.Replacement(this);
}
- /*
- * Used by the replacement code
- */
- internal virtual string GroupToStringImpl(int groupnum)
+ internal virtual ReadOnlySpan<char> GroupToStringImpl(int groupnum)
{
int c = _matchcount[groupnum];
if (c == 0)
@@ -161,26 +141,18 @@ namespace System.Text.RegularExpressions
int[] matches = _matches[groupnum];
- return _text.Substring(matches[(c - 1) * 2], matches[(c * 2) - 1]);
+ return Text.AsSpan(matches[(c - 1) * 2], matches[(c * 2) - 1]);
}
- /*
- * Used by the replacement code
- */
- internal string LastGroupToStringImpl()
+ internal ReadOnlySpan<char> LastGroupToStringImpl()
{
return GroupToStringImpl(_matchcount.Length - 1);
}
-
- /*
- * Convert to a thread-safe object by precomputing cache contents
- */
/// <summary>
/// Returns a Match instance equivalent to the one supplied that is safe to share
/// between multiple threads.
/// </summary>
-
public static Match Synchronized(Match inner)
{
if (inner == null)
@@ -201,9 +173,9 @@ namespace System.Text.RegularExpressions
return inner;
}
- /*
- * Nonpublic builder: add a capture to the group specified by "cap"
- */
+ /// <summary>
+ /// Adds a capture to the group specified by "cap"
+ /// </summary>
internal virtual void AddMatch(int cap, int start, int len)
{
int capcount;
@@ -236,14 +208,11 @@ namespace System.Text.RegularExpressions
*/
internal virtual void BalanceMatch(int cap)
{
- int capcount;
- int target;
-
_balancing = true;
// we'll look at the last capture first
- capcount = _matchcount[cap];
- target = capcount * 2 - 2;
+ int capcount = _matchcount[cap];
+ int target = capcount * 2 - 2;
// first see if it is negative, and therefore is a reference to the next available
// capture group for balancing. If it is, we'll reset target to point to that capture.
@@ -260,25 +229,25 @@ namespace System.Text.RegularExpressions
AddMatch(cap, -3 - target, -4 - target /* == -3 - (target + 1) */ );
}
- /*
- * Nonpublic builder: removes a group match by capnum
- */
+ /// <summary>
+ /// Removes a group match by capnum
+ /// </summary>
internal virtual void RemoveMatch(int cap)
{
_matchcount[cap]--;
}
- /*
- * Nonpublic: tells if a group was matched by capnum
- */
+ /// <summary>
+ /// Tells if a group was matched by capnum
+ /// </summary>
internal virtual bool IsMatched(int cap)
{
return cap < _matchcount.Length && _matchcount[cap] > 0 && _matches[cap][_matchcount[cap] * 2 - 1] != (-3 + 1);
}
- /*
- * Nonpublic: returns the index of the last specified matched group by capnum
- */
+ /// <summary>
+ /// Returns the index of the last specified matched group by capnum
+ /// </summary>
internal virtual int MatchIndex(int cap)
{
int i = _matches[cap][_matchcount[cap] * 2 - 2];
@@ -288,9 +257,9 @@ namespace System.Text.RegularExpressions
return _matches[cap][-3 - i];
}
- /*
- * Nonpublic: returns the length of the last specified matched group by capnum
- */
+ /// <summary>
+ /// Returns the length of the last specified matched group by capnum
+ /// </summary>
internal virtual int MatchLength(int cap)
{
int i = _matches[cap][_matchcount[cap] * 2 - 1];
@@ -300,16 +269,14 @@ namespace System.Text.RegularExpressions
return _matches[cap][-3 - i];
}
- /*
- * Nonpublic: tidy the match so that it can be used as an immutable result
- */
+ /// <summary>
+ /// Tidy the match so that it can be used as an immutable result
+ /// </summary>
internal virtual void Tidy(int textpos)
{
- int[] interval;
-
- interval = _matches[0];
- _index = interval[0];
- _length = interval[1];
+ int[] interval = _matches[0];
+ Index = interval[0];
+ Length = interval[1];
_textpos = textpos;
_capcount = _matchcount[0];
@@ -387,7 +354,7 @@ namespace System.Text.RegularExpressions
string text = "";
if (_matches[i][j * 2] >= 0)
- text = _text.Substring(_matches[i][j * 2], _matches[i][j * 2 + 1]);
+ text = Text.Substring(_matches[i][j * 2], _matches[i][j * 2 + 1]);
System.Diagnostics.Debug.WriteLine(" (" + _matches[i][j * 2].ToString(CultureInfo.InvariantCulture) + "," + _matches[i][j * 2 + 1].ToString(CultureInfo.InvariantCulture) + ") " + text);
}
@@ -396,23 +363,16 @@ namespace System.Text.RegularExpressions
#endif
}
-
- /*
- * MatchSparse is for handling the case where slots are
- * sparsely arranged (e.g., if somebody says use slot 100000)
- */
+ /// <summary>
+ /// MatchSparse is for handling the case where slots are sparsely arranged (e.g., if somebody says use slot 100000)
+ /// </summary>
internal class MatchSparse : Match
{
// the lookup hashtable
- new internal Hashtable _caps;
-
- /*
- * Nonpublic constructor
- */
- internal MatchSparse(Regex regex, Hashtable caps, int capcount,
- string text, int begpos, int len, int startpos)
+ new internal readonly Hashtable _caps;
- : base(regex, capcount, text, begpos, len, startpos)
+ internal MatchSparse(Regex regex, Hashtable caps, int capcount, string text, int begpos, int len, int startpos)
+ : base(regex, capcount, text, begpos, len, startpos)
{
_caps = caps;
}
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexMatchCollection.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/MatchCollection.cs
index 9f26b793ee..eee2924be2 100644
--- a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexMatchCollection.cs
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/MatchCollection.cs
@@ -21,8 +21,10 @@ namespace System.Text.RegularExpressions
/// names in a regular expression.
/// </summary>
[DebuggerDisplay("Count = {Count}")]
- [DebuggerTypeProxy(typeof(RegexCollectionDebuggerProxy<Match>))]
+#if MONO
[Serializable]
+#endif
+ [DebuggerTypeProxy(typeof(CollectionDebuggerProxy<Match>))]
public class MatchCollection : IList<Match>, IReadOnlyList<Match>, IList
{
private readonly Regex _regex;
@@ -113,7 +115,7 @@ namespace System.Text.RegularExpressions
_matches.Add(match);
- _prevlen = match._length;
+ _prevlen = match.Length;
_startat = match._textpos;
} while (_matches.Count <= i);
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Reference.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Reference.cs
new file mode 100644
index 0000000000..eb7d2755a3
--- /dev/null
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Reference.cs
@@ -0,0 +1,88 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading;
+
+namespace System.Text.RegularExpressions
+{
+ /// <summary>
+ /// Used to cache one exclusive runner reference
+ /// </summary>
+ internal sealed class ExclusiveReference
+ {
+ private RegexRunner _ref;
+ private RegexRunner _obj;
+ private volatile int _locked;
+
+ /// <summary>
+ /// Return an object and grab an exclusive lock.
+ ///
+ /// If the exclusive lock can't be obtained, null is returned;
+ /// if the object can't be returned, the lock is released.
+ /// </summary>
+ public RegexRunner Get()
+ {
+ // try to obtain the lock
+
+ if (0 == Interlocked.Exchange(ref _locked, 1))
+ {
+ // grab reference
+ RegexRunner obj = _ref;
+
+ // release the lock and return null if no reference
+ if (obj == null)
+ {
+ _locked = 0;
+
+ return null;
+ }
+
+ // remember the reference and keep the lock
+ _obj = obj;
+
+ return obj;
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Release an object back to the cache.
+ ///
+ /// If the object is the one that's under lock, the lock is released.
+ /// If there is no cached object, then the lock is obtained and the object is placed in the cache.
+ /// </summary>
+ public void Release(RegexRunner obj)
+ {
+ if (obj == null)
+ throw new ArgumentNullException(nameof(obj));
+
+ // if this reference owns the lock, release it
+ if (_obj == obj)
+ {
+ _obj = null;
+ _locked = 0;
+
+ return;
+ }
+
+ // if no reference owns the lock, try to cache this reference
+ if (_obj == null)
+ {
+ // try to obtain the lock
+ if (0 == Interlocked.Exchange(ref _locked, 1))
+ {
+ // if there's really no reference, cache this reference
+ if (_ref == null)
+ _ref = obj;
+
+ // release the lock
+ _locked = 0;
+
+ return;
+ }
+ }
+ }
+ }
+}
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Cache.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Cache.cs
new file mode 100644
index 0000000000..e14be8eec6
--- /dev/null
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Cache.cs
@@ -0,0 +1,303 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using SysDebug = System.Diagnostics.Debug; // as Regex.Debug
+using System.Collections.Generic;
+using System.Collections;
+using System.Runtime.CompilerServices;
+using System.Threading;
+
+namespace System.Text.RegularExpressions
+{
+ public partial class Regex
+ {
+ private const int CacheDictionarySwitchLimit = 10;
+
+ private static int s_cacheSize = 15;
+ // the cache of code and factories that are currently loaded:
+ // Dictionary for large cache
+ private static readonly Dictionary<CachedCodeEntryKey, CachedCodeEntry> s_cache = new Dictionary<CachedCodeEntryKey, CachedCodeEntry>(s_cacheSize);
+ // linked list for MRU and for small cache
+ private static int s_cacheCount = 0;
+ private static CachedCodeEntry s_cacheFirst;
+ private static CachedCodeEntry s_cacheLast;
+
+ public static int CacheSize
+ {
+ get
+ {
+ return s_cacheSize;
+ }
+ set
+ {
+ if (value < 0)
+ throw new ArgumentOutOfRangeException(nameof(value));
+
+ lock (s_cache)
+ {
+ s_cacheSize = value; // not to allow other thread to change it while we use cache
+ while (s_cacheCount > s_cacheSize)
+ {
+ CachedCodeEntry last = s_cacheLast;
+ if (s_cacheCount >= CacheDictionarySwitchLimit)
+ {
+ SysDebug.Assert(s_cache.ContainsKey(last.Key));
+ s_cache.Remove(last.Key);
+ }
+
+ // update linked list:
+ s_cacheLast = last.Next;
+ if (last.Next != null)
+ {
+ SysDebug.Assert(s_cacheFirst != null);
+ SysDebug.Assert(s_cacheFirst != last);
+ SysDebug.Assert(last.Next.Previous == last);
+ last.Next.Previous = null;
+ }
+ else // last one removed
+ {
+ SysDebug.Assert(s_cacheFirst == last);
+ s_cacheFirst = null;
+ }
+
+ s_cacheCount--;
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Find cache based on options+pattern+culture and optionally add new cache if not found
+ /// </summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private CachedCodeEntry GetCachedCode(CachedCodeEntryKey key, bool isToAdd)
+ {
+ // to avoid lock:
+ CachedCodeEntry first = s_cacheFirst;
+ if (first?.Key == key)
+ return first;
+ if (s_cacheSize == 0)
+ return null;
+
+ return GetCachedCodeEntryInternal(key, isToAdd);
+ }
+
+ private CachedCodeEntry GetCachedCodeEntryInternal(CachedCodeEntryKey key, bool isToAdd)
+ {
+ lock (s_cache)
+ {
+ // first look for it in the cache and move it to the head
+ CachedCodeEntry entry = LookupCachedAndPromote(key);
+ // it wasn't in the cache, so we'll add a new one
+ if (entry == null && isToAdd && s_cacheSize != 0) // check cache size again in case it changed
+ {
+ entry = new CachedCodeEntry(key, capnames, capslist, _code, caps, capsize, _runnerref, _replref);
+ // put first in linked list:
+ if (s_cacheFirst != null)
+ {
+ SysDebug.Assert(s_cacheFirst.Next == null);
+ s_cacheFirst.Next = entry;
+ entry.Previous = s_cacheFirst;
+ }
+ s_cacheFirst = entry;
+
+ s_cacheCount++;
+ if (s_cacheCount >= CacheDictionarySwitchLimit)
+ {
+ if (s_cacheCount == CacheDictionarySwitchLimit)
+ FillCacheDictionary();
+ else
+ s_cache.Add(key, entry);
+ SysDebug.Assert(s_cacheCount == s_cache.Count);
+ }
+
+ // update last in linked list:
+ if (s_cacheLast == null)
+ {
+ s_cacheLast = entry;
+ }
+ else if (s_cacheCount > s_cacheSize) // remove last
+ {
+ CachedCodeEntry last = s_cacheLast;
+ if (s_cacheCount >= CacheDictionarySwitchLimit)
+ {
+ SysDebug.Assert(s_cache[last.Key] == s_cacheLast);
+ s_cache.Remove(last.Key);
+ }
+
+ SysDebug.Assert(last.Previous == null);
+ SysDebug.Assert(last.Next != null);
+ SysDebug.Assert(last.Next.Previous == last);
+ last.Next.Previous = null;
+ s_cacheLast = last.Next;
+ s_cacheCount--;
+ }
+
+ }
+ return entry;
+ }
+ }
+
+ private void FillCacheDictionary()
+ {
+ s_cache.Clear();
+ CachedCodeEntry next = s_cacheFirst;
+ while (next != null)
+ {
+ s_cache.Add(next.Key, next);
+ next = next.Previous;
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)] // Unprofitable inline - JIT overly pessimistic
+ private static bool TryGetCacheValue(CachedCodeEntryKey key, out CachedCodeEntry entry)
+ {
+ if (s_cacheCount >= CacheDictionarySwitchLimit)
+ {
+ SysDebug.Assert((s_cacheFirst != null && s_cacheLast != null && s_cache.Count > 0) ||
+ (s_cacheFirst == null && s_cacheLast == null && s_cache.Count == 0),
+ "Linked list and Dict should be synchronized");
+ return s_cache.TryGetValue(key, out entry);
+ }
+
+ return TryGetCacheValueSmall(key, out entry);
+ }
+
+ private static bool TryGetCacheValueSmall(CachedCodeEntryKey key, out CachedCodeEntry entry)
+ {
+ entry = s_cacheFirst?.Previous; // first already checked
+ while (entry != null)
+ {
+ if (entry.Key == key)
+ return true;
+ entry = entry.Previous;
+ }
+
+ return false;
+ }
+
+ private static CachedCodeEntry LookupCachedAndPromote(CachedCodeEntryKey key)
+ {
+ SysDebug.Assert(Monitor.IsEntered(s_cache));
+ if (s_cacheFirst?.Key == key) // again check this as could have been promoted by other thread
+ return s_cacheFirst;
+
+ if (TryGetCacheValue(key, out CachedCodeEntry entry))
+ {
+ // promote:
+ SysDebug.Assert(s_cacheFirst != entry, "key should not get s_livecode_first");
+ SysDebug.Assert(s_cacheFirst != null, "as Dict has at least one");
+ SysDebug.Assert(s_cacheFirst.Next == null);
+ SysDebug.Assert(s_cacheFirst.Previous != null);
+ SysDebug.Assert(entry.Next != null, "not first so Next should exist");
+ SysDebug.Assert(entry.Next.Previous == entry);
+ if (s_cacheLast == entry)
+ {
+ SysDebug.Assert(entry.Previous == null, "last");
+ s_cacheLast = entry.Next;
+ }
+ else
+ {
+ SysDebug.Assert(entry.Previous != null, "in middle");
+ SysDebug.Assert(entry.Previous.Next == entry);
+ entry.Previous.Next = entry.Next;
+ }
+ entry.Next.Previous = entry.Previous;
+
+ s_cacheFirst.Next = entry;
+ entry.Previous = s_cacheFirst;
+ entry.Next = null;
+ s_cacheFirst = entry;
+ }
+
+ return entry;
+ }
+
+ /// <summary>
+ /// Used as a key for CacheCodeEntry
+ /// </summary>
+ internal readonly struct CachedCodeEntryKey : IEquatable<CachedCodeEntryKey>
+ {
+ private readonly RegexOptions _options;
+ private readonly string _cultureKey;
+ private readonly string _pattern;
+
+ public CachedCodeEntryKey(RegexOptions options, string cultureKey, string pattern)
+ {
+ SysDebug.Assert(cultureKey != null, "Culture must be provided");
+ SysDebug.Assert(pattern != null, "Pattern must be provided");
+
+ _options = options;
+ _cultureKey = cultureKey;
+ _pattern = pattern;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return obj is CachedCodeEntryKey && Equals((CachedCodeEntryKey)obj);
+ }
+
+ public bool Equals(CachedCodeEntryKey other)
+ {
+ return _pattern.Equals(other._pattern) && _options == other._options && _cultureKey.Equals(other._cultureKey);
+ }
+
+ public static bool operator ==(CachedCodeEntryKey left, CachedCodeEntryKey right)
+ {
+ return left.Equals(right);
+ }
+
+ public static bool operator !=(CachedCodeEntryKey left, CachedCodeEntryKey right)
+ {
+ return !left.Equals(right);
+ }
+
+ public override int GetHashCode()
+ {
+ return ((int)_options) ^ _cultureKey.GetHashCode() ^ _pattern.GetHashCode();
+ }
+ }
+
+ /// <summary>
+ /// Used to cache byte codes
+ /// </summary>
+ internal sealed class CachedCodeEntry
+ {
+ public CachedCodeEntry Next;
+ public CachedCodeEntry Previous;
+ public readonly CachedCodeEntryKey Key;
+ public RegexCode Code;
+ public readonly Hashtable Caps;
+ public readonly Hashtable Capnames;
+ public readonly string[] Capslist;
+#if FEATURE_COMPILED
+ public RegexRunnerFactory Factory;
+#endif
+ public readonly int Capsize;
+ public readonly ExclusiveReference Runnerref;
+ public readonly WeakReference<RegexReplacement> ReplRef;
+
+ public CachedCodeEntry(CachedCodeEntryKey key, Hashtable capnames, string[] capslist, RegexCode code,
+ Hashtable caps, int capsize, ExclusiveReference runner, WeakReference<RegexReplacement> replref)
+ {
+ Key = key;
+ Capnames = capnames;
+ Capslist = capslist;
+ Code = code;
+ Caps = caps;
+ Capsize = capsize;
+ Runnerref = runner;
+ ReplRef = replref;
+ }
+
+#if FEATURE_COMPILED
+ public void AddCompiled(RegexRunnerFactory factory)
+ {
+ Factory = factory;
+ Code = null;
+ }
+#endif
+ }
+ }
+}
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Match.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Match.cs
new file mode 100644
index 0000000000..e7aece5572
--- /dev/null
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Match.cs
@@ -0,0 +1,184 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Text.RegularExpressions
+{
+ public partial class Regex
+ {
+ /// <summary>
+ /// Searches the input string for one or more occurrences of the text supplied in the given pattern.
+ /// </summary>
+ public static bool IsMatch(string input, string pattern)
+ {
+ return IsMatch(input, pattern, RegexOptions.None, s_defaultMatchTimeout);
+ }
+
+ /// <summary>
+ /// Searches the input string for one or more occurrences of the text
+ /// supplied in the pattern parameter with matching options supplied in the options
+ /// parameter.
+ /// </summary>
+ public static bool IsMatch(string input, string pattern, RegexOptions options)
+ {
+ return IsMatch(input, pattern, options, s_defaultMatchTimeout);
+ }
+
+ public static bool IsMatch(string input, string pattern, RegexOptions options, TimeSpan matchTimeout)
+ {
+ return new Regex(pattern, options, matchTimeout, true).IsMatch(input);
+ }
+
+ /*
+ * Returns true if the regex finds a match within the specified string
+ */
+ /// <summary>
+ /// Searches the input string for one or more matches using the previous pattern,
+ /// options, and starting position.
+ /// </summary>
+ public bool IsMatch(string input)
+ {
+ if (input == null)
+ throw new ArgumentNullException(nameof(input));
+
+ return IsMatch(input, UseOptionR() ? input.Length : 0);
+ }
+
+ /*
+ * Returns true if the regex finds a match after the specified position
+ * (proceeding leftward if the regex is leftward and rightward otherwise)
+ */
+ /// <summary>
+ /// Searches the input string for one or more matches using the previous pattern and options,
+ /// with a new starting position.
+ /// </summary>
+ public bool IsMatch(string input, int startat)
+ {
+ if (input == null)
+ throw new ArgumentNullException(nameof(input));
+
+ return (null == Run(true, -1, input, 0, input.Length, startat));
+ }
+
+ /// <summary>
+ /// Searches the input string for one or more occurrences of the text
+ /// supplied in the pattern parameter.
+ /// </summary>
+ public static Match Match(string input, string pattern)
+ {
+ return Match(input, pattern, RegexOptions.None, s_defaultMatchTimeout);
+ }
+
+ /// <summary>
+ /// Searches the input string for one or more occurrences of the text
+ /// supplied in the pattern parameter. Matching is modified with an option
+ /// string.
+ /// </summary>
+ public static Match Match(string input, string pattern, RegexOptions options)
+ {
+ return Match(input, pattern, options, s_defaultMatchTimeout);
+ }
+
+ public static Match Match(string input, string pattern, RegexOptions options, TimeSpan matchTimeout)
+ {
+ return new Regex(pattern, options, matchTimeout, true).Match(input);
+ }
+
+ /*
+ * Finds the first match for the regular expression starting at the beginning
+ * of the string (or at the end of the string if the regex is leftward)
+ */
+ /// <summary>
+ /// Matches a regular expression with a string and returns
+ /// the precise result as a RegexMatch object.
+ /// </summary>
+ public Match Match(string input)
+ {
+ if (input == null)
+ throw new ArgumentNullException(nameof(input));
+
+ return Match(input, UseOptionR() ? input.Length : 0);
+ }
+
+ /*
+ * Finds the first match, starting at the specified position
+ */
+ /// <summary>
+ /// Matches a regular expression with a string and returns
+ /// the precise result as a RegexMatch object.
+ /// </summary>
+ public Match Match(string input, int startat)
+ {
+ if (input == null)
+ throw new ArgumentNullException(nameof(input));
+
+ return Run(false, -1, input, 0, input.Length, startat);
+ }
+
+ /*
+ * Finds the first match, restricting the search to the specified interval of
+ * the char array.
+ */
+ /// <summary>
+ /// Matches a regular expression with a string and returns the precise result as a
+ /// RegexMatch object.
+ /// </summary>
+ public Match Match(string input, int beginning, int length)
+ {
+ if (input == null)
+ throw new ArgumentNullException(nameof(input));
+
+ return Run(false, -1, input, beginning, length, UseOptionR() ? beginning + length : beginning);
+ }
+
+ /// <summary>
+ /// Returns all the successful matches as if Match were called iteratively numerous times.
+ /// </summary>
+ public static MatchCollection Matches(string input, string pattern)
+ {
+ return Matches(input, pattern, RegexOptions.None, s_defaultMatchTimeout);
+ }
+
+ /// <summary>
+ /// Returns all the successful matches as if Match were called iteratively numerous times.
+ /// </summary>
+ public static MatchCollection Matches(string input, string pattern, RegexOptions options)
+ {
+ return Matches(input, pattern, options, s_defaultMatchTimeout);
+ }
+
+ public static MatchCollection Matches(string input, string pattern, RegexOptions options, TimeSpan matchTimeout)
+ {
+ return new Regex(pattern, options, matchTimeout, true).Matches(input);
+ }
+
+ /*
+ * Finds the first match for the regular expression starting at the beginning
+ * of the string Enumerator(or at the end of the string if the regex is leftward)
+ */
+ /// <summary>
+ /// Returns all the successful matches as if Match was called iteratively numerous times.
+ /// </summary>
+ public MatchCollection Matches(string input)
+ {
+ if (input == null)
+ throw new ArgumentNullException(nameof(input));
+
+ return Matches(input, UseOptionR() ? input.Length : 0);
+ }
+
+ /*
+ * Finds the first match, starting at the specified position
+ */
+ /// <summary>
+ /// Returns all the successful matches as if Match was called iteratively numerous times.
+ /// </summary>
+ public MatchCollection Matches(string input, int startat)
+ {
+ if (input == null)
+ throw new ArgumentNullException(nameof(input));
+
+ return new MatchCollection(this, input, 0, input.Length, startat);
+ }
+ }
+}
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Replace.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Replace.cs
new file mode 100644
index 0000000000..3e58ee328c
--- /dev/null
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Replace.cs
@@ -0,0 +1,230 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.IO;
+
+namespace System.Text.RegularExpressions
+{
+ // Callback class
+ public delegate string MatchEvaluator(Match match);
+
+ public partial class Regex
+ {
+ /// <summary>
+ /// Replaces all occurrences of the pattern with the <paramref name="replacement"/> pattern, starting at
+ /// the first character in the input string.
+ /// </summary>
+ public static string Replace(string input, string pattern, string replacement)
+ {
+ return Replace(input, pattern, replacement, RegexOptions.None, s_defaultMatchTimeout);
+ }
+
+ /// <summary>
+ /// Replaces all occurrences of
+ /// the <paramref name="pattern "/>with the <paramref name="replacement "/>
+ /// pattern, starting at the first character in the input string.
+ /// </summary>
+ public static string Replace(string input, string pattern, string replacement, RegexOptions options)
+ {
+ return Replace(input, pattern, replacement, options, s_defaultMatchTimeout);
+ }
+
+ public static string Replace(string input, string pattern, string replacement, RegexOptions options, TimeSpan matchTimeout)
+ {
+ return new Regex(pattern, options, matchTimeout, true).Replace(input, replacement);
+ }
+
+ /// <summary>
+ /// Replaces all occurrences of the previously defined pattern with the
+ /// <paramref name="replacement"/> pattern, starting at the first character in the
+ /// input string.
+ /// </summary>
+ public string Replace(string input, string replacement)
+ {
+ if (input == null)
+ throw new ArgumentNullException(nameof(input));
+
+ return Replace(input, replacement, -1, UseOptionR() ? input.Length : 0);
+ }
+
+ /// <summary>
+ /// Replaces all occurrences of the previously defined pattern with the
+ /// <paramref name="replacement"/> pattern, starting at the first character in the
+ /// input string.
+ /// </summary>
+ public string Replace(string input, string replacement, int count)
+ {
+ if (input == null)
+ throw new ArgumentNullException(nameof(input));
+
+ return Replace(input, replacement, count, UseOptionR() ? input.Length : 0);
+ }
+
+ /// <summary>
+ /// Replaces all occurrences of the previously defined pattern with the
+ /// <paramref name="replacement"/> pattern, starting at the character position
+ /// <paramref name="startat"/>.
+ /// </summary>
+ public string Replace(string input, string replacement, int count, int startat)
+ {
+ if (input == null)
+ throw new ArgumentNullException(nameof(input));
+
+ if (replacement == null)
+ throw new ArgumentNullException(nameof(replacement));
+
+ // Gets the weakly cached replacement helper or creates one if there isn't one already.
+ RegexReplacement repl = RegexReplacement.GetOrCreate(_replref, replacement, caps, capsize, capnames, roptions);
+
+ return repl.Replace(this, input, count, startat);
+ }
+
+ /// <summary>
+ /// Replaces all occurrences of the <paramref name="pattern"/> with the recent
+ /// replacement pattern.
+ /// </summary>
+ public static string Replace(string input, string pattern, MatchEvaluator evaluator)
+ {
+ return Replace(input, pattern, evaluator, RegexOptions.None, s_defaultMatchTimeout);
+ }
+
+ /// <summary>
+ /// Replaces all occurrences of the <paramref name="pattern"/> with the recent
+ /// replacement pattern, starting at the first character.
+ /// </summary>
+ public static string Replace(string input, string pattern, MatchEvaluator evaluator, RegexOptions options)
+ {
+ return Replace(input, pattern, evaluator, options, s_defaultMatchTimeout);
+ }
+
+ public static string Replace(string input, string pattern, MatchEvaluator evaluator, RegexOptions options, TimeSpan matchTimeout)
+ {
+ return new Regex(pattern, options, matchTimeout, true).Replace(input, evaluator);
+ }
+
+ /// <summary>
+ /// Replaces all occurrences of the previously defined pattern with the recent
+ /// replacement pattern, starting at the first character position.
+ /// </summary>
+ public string Replace(string input, MatchEvaluator evaluator)
+ {
+ if (input == null)
+ throw new ArgumentNullException(nameof(input));
+
+ return Replace(input, evaluator, -1, UseOptionR() ? input.Length : 0);
+ }
+
+ /// <summary>
+ /// Replaces all occurrences of the previously defined pattern with the recent
+ /// replacement pattern, starting at the first character position.
+ /// </summary>
+ public string Replace(string input, MatchEvaluator evaluator, int count)
+ {
+ if (input == null)
+ throw new ArgumentNullException(nameof(input));
+
+ return Replace(input, evaluator, count, UseOptionR() ? input.Length : 0);
+ }
+
+ /// <summary>
+ /// Replaces all occurrences of the previously defined pattern with the recent
+ /// replacement pattern, starting at the character position
+ /// <paramref name="startat"/>.
+ /// </summary>
+ public string Replace(string input, MatchEvaluator evaluator, int count, int startat)
+ {
+ if (input == null)
+ throw new ArgumentNullException(nameof(input));
+
+ return Replace(evaluator, this, input, count, startat);
+ }
+
+ /// <summary>
+ /// Replaces all occurrences of the regex in the string with the
+ /// replacement evaluator.
+ ///
+ /// Note that the special case of no matches is handled on its own:
+ /// with no matches, the input string is returned unchanged.
+ /// The right-to-left case is split out because StringBuilder
+ /// doesn't handle right-to-left string building directly very well.
+ /// </summary>
+ private static string Replace(MatchEvaluator evaluator, Regex regex, string input, int count, int startat)
+ {
+ if (evaluator == null)
+ throw new ArgumentNullException(nameof(evaluator));
+ if (count < -1)
+ throw new ArgumentOutOfRangeException(nameof(count), SR.CountTooSmall);
+ if (startat < 0 || startat > input.Length)
+ throw new ArgumentOutOfRangeException(nameof(startat), SR.BeginIndexNotNegative);
+
+ if (count == 0)
+ return input;
+
+ Match match = regex.Match(input, startat);
+
+ if (!match.Success)
+ {
+ return input;
+ }
+ else
+ {
+ StringBuilder sb = StringBuilderCache.Acquire();
+
+ if (!regex.RightToLeft)
+ {
+ int prevat = 0;
+
+ do
+ {
+ if (match.Index != prevat)
+ sb.Append(input, prevat, match.Index - prevat);
+
+ prevat = match.Index + match.Length;
+
+ sb.Append(evaluator(match));
+
+ if (--count == 0)
+ break;
+
+ match = match.NextMatch();
+ } while (match.Success);
+
+ if (prevat < input.Length)
+ sb.Append(input, prevat, input.Length - prevat);
+ }
+ else
+ {
+ List<string> al = new List<string>();
+ int prevat = input.Length;
+
+ do
+ {
+ if (match.Index + match.Length != prevat)
+ al.Add(input.Substring(match.Index + match.Length, prevat - match.Index - match.Length));
+
+ prevat = match.Index;
+
+ al.Add(evaluator(match));
+
+ if (--count == 0)
+ break;
+
+ match = match.NextMatch();
+ } while (match.Success);
+
+ if (prevat > 0)
+ sb.Append(input, 0, prevat);
+
+ for (int i = al.Count - 1; i >= 0; i--)
+ {
+ sb.Append(al[i]);
+ }
+ }
+
+ return StringBuilderCache.GetStringAndRelease(sb);
+ }
+ }
+ }
+}
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Split.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Split.cs
new file mode 100644
index 0000000000..4e4205ebbd
--- /dev/null
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Split.cs
@@ -0,0 +1,165 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+
+namespace System.Text.RegularExpressions
+{
+ public partial class Regex
+ {
+ /// <summary>
+ /// Splits the <paramref name="input "/>string at the position defined
+ /// by <paramref name="pattern"/>.
+ /// </summary>
+ public static string[] Split(string input, string pattern)
+ {
+ return Split(input, pattern, RegexOptions.None, s_defaultMatchTimeout);
+ }
+
+ /// <summary>
+ /// Splits the <paramref name="input "/>string at the position defined by <paramref name="pattern"/>.
+ /// </summary>
+ public static string[] Split(string input, string pattern, RegexOptions options)
+ {
+ return Split(input, pattern, options, s_defaultMatchTimeout);
+ }
+
+ public static string[] Split(string input, string pattern, RegexOptions options, TimeSpan matchTimeout)
+ {
+ return new Regex(pattern, options, matchTimeout, true).Split(input);
+ }
+
+ /// <summary>
+ /// Splits the <paramref name="input"/> string at the position defined by a
+ /// previous pattern.
+ /// </summary>
+ public string[] Split(string input)
+ {
+ if (input == null)
+ throw new ArgumentNullException(nameof(input));
+
+ return Split(input, 0, UseOptionR() ? input.Length : 0);
+ }
+
+ /// <summary>
+ /// Splits the <paramref name="input"/> string at the position defined by a
+ /// previous pattern.
+ /// </summary>
+ public string[] Split(string input, int count)
+ {
+ if (input == null)
+ throw new ArgumentNullException(nameof(input));
+
+ return Split(this, input, count, UseOptionR() ? input.Length : 0);
+ }
+
+ /// <summary>
+ /// Splits the <paramref name="input"/> string at the position defined by a previous pattern.
+ /// </summary>
+ public string[] Split(string input, int count, int startat)
+ {
+ if (input == null)
+ throw new ArgumentNullException(nameof(input));
+
+ return Split(this, input, count, startat);
+ }
+
+ /// <summary>
+ /// Does a split. In the right-to-left case we reorder the
+ /// array to be forwards.
+ /// </summary>
+ private static string[] Split(Regex regex, string input, int count, int startat)
+ {
+ if (count < 0)
+ throw new ArgumentOutOfRangeException(nameof(count), SR.CountTooSmall);
+ if (startat < 0 || startat > input.Length)
+ throw new ArgumentOutOfRangeException(nameof(startat), SR.BeginIndexNotNegative);
+
+ string[] result;
+
+ if (count == 1)
+ {
+ result = new string[1];
+ result[0] = input;
+ return result;
+ }
+
+ count -= 1;
+
+ Match match = regex.Match(input, startat);
+
+ if (!match.Success)
+ {
+ result = new string[1];
+ result[0] = input;
+ return result;
+ }
+ else
+ {
+ List<string> al = new List<string>();
+
+ if (!regex.RightToLeft)
+ {
+ int prevat = 0;
+
+ for (; ; )
+ {
+ al.Add(input.Substring(prevat, match.Index - prevat));
+
+ prevat = match.Index + match.Length;
+
+ // add all matched capture groups to the list.
+ for (int i = 1; i < match.Groups.Count; i++)
+ {
+ if (match.IsMatched(i))
+ al.Add(match.Groups[i].ToString());
+ }
+
+ if (--count == 0)
+ break;
+
+ match = match.NextMatch();
+
+ if (!match.Success)
+ break;
+ }
+
+ al.Add(input.Substring(prevat, input.Length - prevat));
+ }
+ else
+ {
+ int prevat = input.Length;
+
+ for (; ; )
+ {
+ al.Add(input.Substring(match.Index + match.Length, prevat - match.Index - match.Length));
+
+ prevat = match.Index;
+
+ // add all matched capture groups to the list.
+ for (int i = 1; i < match.Groups.Count; i++)
+ {
+ if (match.IsMatched(i))
+ al.Add(match.Groups[i].ToString());
+ }
+
+ if (--count == 0)
+ break;
+
+ match = match.NextMatch();
+
+ if (!match.Success)
+ break;
+ }
+
+ al.Add(input.Substring(0, prevat));
+
+ al.Reverse(0, al.Count);
+ }
+
+ return al.ToArray();
+ }
+ }
+ }
+}
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Timeout.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Timeout.cs
new file mode 100644
index 0000000000..b59f294428
--- /dev/null
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.Timeout.cs
@@ -0,0 +1,104 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading;
+
+namespace System.Text.RegularExpressions
+{
+ public partial class Regex
+ {
+ // We need this because time is queried using Environment.TickCount for performance reasons
+ // (Environment.TickCount returns milliseconds as an int and cycles):
+ private static readonly TimeSpan s_maximumMatchTimeout = TimeSpan.FromMilliseconds(int.MaxValue - 1);
+
+ // During static initialisation of Regex we check
+ private const string DefaultMatchTimeout_ConfigKeyName = "REGEX_DEFAULT_MATCH_TIMEOUT";
+
+ // DefaultMatchTimeout specifies the match timeout to use if no other timeout was specified
+ // by one means or another. Typically, it is set to InfiniteMatchTimeout.
+ internal static readonly TimeSpan s_defaultMatchTimeout;
+
+ // InfiniteMatchTimeout specifies that match timeout is switched OFF. It allows for faster code paths
+ // compared to simply having a very large timeout.
+ // We do not want to ask users to use System.Threading.Timeout.InfiniteTimeSpan as a parameter because:
+ // (1) We do not want to imply any relation between having using a RegEx timeout and using multi-threading.
+ // (2) We do not want to require users to take ref to a contract assembly for threading just to use RegEx.
+ // There may in theory be a SKU that has RegEx, but no multithreading.
+ // We create a public Regex.InfiniteMatchTimeout constant, which for consistency uses the save underlying
+ // value as Timeout.InfiniteTimeSpan creating an implementation detail dependency only.
+ public static readonly TimeSpan InfiniteMatchTimeout = Timeout.InfiniteTimeSpan;
+
+ // timeout for the execution of this regex
+ protected internal TimeSpan internalMatchTimeout;
+
+ static Regex()
+ {
+ s_defaultMatchTimeout = InitDefaultMatchTimeout();
+ }
+
+ /// <summary>
+ /// The match timeout used by this Regex instance.
+ /// </summary>
+ public TimeSpan MatchTimeout => internalMatchTimeout;
+
+ // Note: "&lt;" is the XML entity for smaller ("<").
+ /// <summary>
+ /// Validates that the specified match timeout value is valid.
+ /// The valid range is <code>TimeSpan.Zero &lt; matchTimeout &lt;= Regex.MaximumMatchTimeout</code>.
+ /// </summary>
+ /// <param name="matchTimeout">The timeout value to validate.</param>
+ /// <exception cref="ArgumentOutOfRangeException">If the specified timeout is not within a valid range.
+ /// </exception>
+ protected internal static void ValidateMatchTimeout(TimeSpan matchTimeout)
+ {
+ if (InfiniteMatchTimeout == matchTimeout)
+ return;
+
+ // Change this to make sure timeout is not longer then Environment.Ticks cycle length:
+ if (TimeSpan.Zero < matchTimeout && matchTimeout <= s_maximumMatchTimeout)
+ return;
+
+ throw new ArgumentOutOfRangeException(nameof(matchTimeout));
+ }
+
+ /// <summary>
+ /// Specifies the default RegEx matching timeout value (i.e. the timeout that will be used if no
+ /// explicit timeout is specified).
+ /// The default is queried from the current <code>AppDomain</code>.
+ /// If the AddDomain's data value for that key is not a <code>TimeSpan</code> value or if it is outside the
+ /// valid range, an exception is thrown.
+ /// If the AddDomain's data value for that key is <code>null</code>, a fallback value is returned.
+ /// </summary>
+ /// <returns>The default RegEx matching timeout for this AppDomain</returns>
+ private static TimeSpan InitDefaultMatchTimeout()
+ {
+ // Query AppDomain
+ AppDomain ad = AppDomain.CurrentDomain;
+ object defaultMatchTimeoutObj = ad.GetData(DefaultMatchTimeout_ConfigKeyName);
+
+ // If no default is specified, use fallback
+ if (defaultMatchTimeoutObj == null)
+ {
+ return InfiniteMatchTimeout;
+ }
+
+ if (defaultMatchTimeoutObj is TimeSpan defaultMatchTimeOut)
+ {
+ // If default timeout is outside the valid range, throw. It will result in a TypeInitializationException:
+ try
+ {
+ ValidateMatchTimeout(defaultMatchTimeOut);
+ }
+ catch (ArgumentOutOfRangeException)
+ {
+ throw new ArgumentOutOfRangeException(SR.Format(SR.IllegalDefaultRegexMatchTimeoutInAppDomain, DefaultMatchTimeout_ConfigKeyName, defaultMatchTimeOut));
+ }
+
+ return defaultMatchTimeOut;
+ }
+
+ throw new InvalidCastException(SR.Format(SR.IllegalDefaultRegexMatchTimeoutInAppDomain, DefaultMatchTimeout_ConfigKeyName, defaultMatchTimeoutObj));
+ }
+ }
+}
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.cs
index d078cda53a..77158bf5ca 100644
--- a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.cs
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/Regex.cs
@@ -6,7 +6,6 @@
// expression.
using System.Collections;
-using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reflection;
@@ -15,7 +14,6 @@ using System.Reflection.Emit;
using System.Runtime.CompilerServices;
#endif
using System.Runtime.Serialization;
-using System.Threading;
namespace System.Text.RegularExpressions
{
@@ -24,101 +22,26 @@ namespace System.Text.RegularExpressions
/// contains static methods that allow use of regular expressions without instantiating
/// a Regex explicitly.
/// </summary>
- [Serializable]
- public class Regex : ISerializable
+ public partial class Regex : ISerializable
{
+ internal const int MaxOptionShift = 10;
+
protected internal string pattern; // The string pattern provided
protected internal RegexOptions roptions; // the top-level options from the options string
-
- // *********** Match timeout fields { ***********
-
- // We need this because time is queried using Environment.TickCount for performance reasons
- // (Environment.TickCount returns milliseconds as an int and cycles):
- private static readonly TimeSpan MaximumMatchTimeout = TimeSpan.FromMilliseconds(int.MaxValue - 1);
-
- // InfiniteMatchTimeout specifies that match timeout is switched OFF. It allows for faster code paths
- // compared to simply having a very large timeout.
- // We do not want to ask users to use System.Threading.Timeout.InfiniteTimeSpan as a parameter because:
- // (1) We do not want to imply any relation between having using a RegEx timeout and using multi-threading.
- // (2) We do not want to require users to take ref to a contract assembly for threading just to use RegEx.
- // There may in theory be a SKU that has RegEx, but no multithreading.
- // We create a public Regex.InfiniteMatchTimeout constant, which for consistency uses the save underlying
- // value as Timeout.InfiniteTimeSpan creating an implementation detail dependency only.
- public static readonly TimeSpan InfiniteMatchTimeout = Timeout.InfiniteTimeSpan;
-
- protected internal TimeSpan internalMatchTimeout; // timeout for the execution of this regex
-
- // During static initialisation of Regex we check
- private const string DefaultMatchTimeout_ConfigKeyName = "REGEX_DEFAULT_MATCH_TIMEOUT";
-
- // DefaultMatchTimeout specifies the match timeout to use if no other timeout was specified
- // by one means or another. Typically, it is set to InfiniteMatchTimeout.
- internal static readonly TimeSpan DefaultMatchTimeout = InitDefaultMatchTimeout();
-
- // *********** } match timeout fields ***********
-
protected internal RegexRunnerFactory factory;
-
- protected internal Hashtable caps; // if captures are sparse, this is the hashtable capnum->index
- protected internal Hashtable capnames; // if named captures are used, this maps names->index
-
- protected internal string[] capslist; // if captures are sparse or named captures are used, this is the sorted list of names
- protected internal int capsize; // the size of the capture array
-
- [CLSCompliant(false)]
- protected IDictionary Caps
- {
- get
- {
- return caps;
- }
- set
- {
- if (value == null)
- throw new ArgumentNullException(nameof(value));
-
- caps = value as Hashtable;
- if (caps == null)
- {
- caps = new Hashtable(value);
- }
- }
- }
-
- [CLSCompliant(false)]
- protected IDictionary CapNames
- {
- get
- {
- return capnames;
- }
- set
- {
- if (value == null)
- throw new ArgumentNullException(nameof(value));
-
- capnames = value as Hashtable;
- if (capnames == null)
- {
- capnames = new Hashtable(value);
- }
- }
- }
-
-
- internal ExclusiveReference _runnerref; // cached runner
- internal SharedReference _replref; // cached parsed replacement pattern
- internal RegexCode _code; // if interpreted, this is the code for RegexInterpreter
+ protected internal Hashtable caps; // if captures are sparse, this is the hashtable capnum->index
+ protected internal Hashtable capnames; // if named captures are used, this maps names->index
+ protected internal string[] capslist; // if captures are sparse or named captures are used, this is the sorted list of names
+ protected internal int capsize; // the size of the capture array
+
+ internal ExclusiveReference _runnerref; // cached runner
+ internal WeakReference<RegexReplacement> _replref; // cached parsed replacement pattern
+ internal RegexCode _code; // if interpreted, this is the code for RegexInterpreter
internal bool _refsInitialized = false;
- internal static LinkedList<CachedCodeEntry> s_livecode = new LinkedList<CachedCodeEntry>();// the cache of code and factories that are currently loaded
- internal static int s_cacheSize = 15;
-
- internal const int MaxOptionShift = 10;
-
protected Regex()
{
- internalMatchTimeout = DefaultMatchTimeout;
+ internalMatchTimeout = s_defaultMatchTimeout;
}
/// <summary>
@@ -126,7 +49,7 @@ namespace System.Text.RegularExpressions
/// expression.
/// </summary>
public Regex(string pattern)
- : this(pattern, RegexOptions.None, DefaultMatchTimeout, false)
+ : this(pattern, RegexOptions.None, s_defaultMatchTimeout, false)
{
}
@@ -135,7 +58,7 @@ namespace System.Text.RegularExpressions
/// specified regular expression with options that modify the pattern.
/// </summary>
public Regex(string pattern, RegexOptions options)
- : this(pattern, options, DefaultMatchTimeout, false)
+ : this(pattern, options, s_defaultMatchTimeout, false)
{
}
@@ -183,50 +106,50 @@ namespace System.Text.RegularExpressions
ValidateMatchTimeout(matchTimeout);
- string cultureKey;
- if ((options & RegexOptions.CultureInvariant) != 0)
- cultureKey = CultureInfo.InvariantCulture.ToString();
- else
- cultureKey = CultureInfo.CurrentCulture.ToString();
-
- // Try to look up this regex in the cache.
- var key = new CachedCodeEntryKey(options, cultureKey, pattern);
- CachedCodeEntry cached = LookupCachedAndUpdate(key);
-
+ // After parameter validation assign
this.pattern = pattern;
roptions = options;
internalMatchTimeout = matchTimeout;
+ // Cache handling. Try to look up this regex in the cache.
+ string cultureKey = (options & RegexOptions.CultureInvariant) != 0 ?
+ CultureInfo.InvariantCulture.ToString() :
+ CultureInfo.CurrentCulture.ToString();
+ var key = new CachedCodeEntryKey(options, cultureKey, pattern);
+ CachedCodeEntry cached = GetCachedCode(key, false);
+
if (cached == null)
{
// Parse the input
RegexTree tree = RegexParser.Parse(pattern, roptions);
// Extract the relevant information
- capnames = tree._capnames;
- capslist = tree._capslist;
+ capnames = tree.CapNames;
+ capslist = tree.CapsList;
_code = RegexWriter.Write(tree);
- caps = _code._caps;
- capsize = _code._capsize;
+ caps = _code.Caps;
+ capsize = _code.CapSize;
InitializeReferences();
tree = null;
if (addToCache)
- cached = CacheCode(key);
+ cached = GetCachedCode(key, true);
}
else
{
- caps = cached._caps;
- capnames = cached._capnames;
- capslist = cached._capslist;
- capsize = cached._capsize;
- _code = cached._code;
+ caps = cached.Caps;
+ capnames = cached.Capnames;
+ capslist = cached.Capslist;
+ capsize = cached.Capsize;
+ _code = cached.Code;
#if FEATURE_COMPILED
- factory = cached._factory;
+ factory = cached.Factory;
#endif
- _runnerref = cached._runnerref;
- _replref = cached._replref;
+
+ // Cache runner and replacement
+ _runnerref = cached.Runnerref;
+ _replref = cached.ReplRef;
_refsInitialized = true;
}
@@ -246,63 +169,36 @@ namespace System.Text.RegularExpressions
#endif
}
- // Note: "&lt;" is the XML entity for smaller ("<").
- /// <summary>
- /// Validates that the specified match timeout value is valid.
- /// The valid range is <code>TimeSpan.Zero &lt; matchTimeout &lt;= Regex.MaximumMatchTimeout</code>.
- /// </summary>
- /// <param name="matchTimeout">The timeout value to validate.</param>
- /// <exception cref="ArgumentOutOfRangeException">If the specified timeout is not within a valid range.
- /// </exception>
- protected internal static void ValidateMatchTimeout(TimeSpan matchTimeout)
+ [CLSCompliant(false)]
+ protected IDictionary Caps
{
- if (InfiniteMatchTimeout == matchTimeout)
- return;
-
- // Change this to make sure timeout is not longer then Environment.Ticks cycle length:
- if (TimeSpan.Zero < matchTimeout && matchTimeout <= MaximumMatchTimeout)
- return;
+ get
+ {
+ return caps;
+ }
+ set
+ {
+ if (value == null)
+ throw new ArgumentNullException(nameof(value));
- throw new ArgumentOutOfRangeException(nameof(matchTimeout));
+ caps = value as Hashtable ?? new Hashtable(value);
+ }
}
- /// <summary>
- /// Specifies the default RegEx matching timeout value (i.e. the timeout that will be used if no
- /// explicit timeout is specified).
- /// The default is queried from the current <code>AppDomain</code>.
- /// If the AddDomain's data value for that key is not a <code>TimeSpan</code> value or if it is outside the
- /// valid range, an exception is thrown.
- /// If the AddDomain's data value for that key is <code>null</code>, a fallback value is returned.
- /// </summary>
- /// <returns>The default RegEx matching timeout for this AppDomain</returns>
- private static TimeSpan InitDefaultMatchTimeout()
+ [CLSCompliant(false)]
+ protected IDictionary CapNames
{
- // Query AppDomain
- AppDomain ad = AppDomain.CurrentDomain;
- object defaultMatchTimeoutObj = ad.GetData(DefaultMatchTimeout_ConfigKeyName);
-
- // If no default is specified, use fallback
- if (defaultMatchTimeoutObj == null)
+ get
{
- return InfiniteMatchTimeout;
+ return capnames;
}
-
- if (defaultMatchTimeoutObj is TimeSpan defaultMatchTimeOut)
+ set
{
- // If default timeout is outside the valid range, throw. It will result in a TypeInitializationException:
- try
- {
- ValidateMatchTimeout(defaultMatchTimeOut);
- }
- catch (ArgumentOutOfRangeException)
- {
- throw new ArgumentOutOfRangeException(SR.Format(SR.IllegalDefaultRegexMatchTimeoutInAppDomain, DefaultMatchTimeout_ConfigKeyName, defaultMatchTimeOut));
- }
+ if (value == null)
+ throw new ArgumentNullException(nameof(value));
- return defaultMatchTimeOut;
+ capnames = value as Hashtable ?? new Hashtable(value);
}
-
- throw new InvalidCastException(SR.Format(SR.IllegalDefaultRegexMatchTimeoutInAppDomain, DefaultMatchTimeout_ConfigKeyName, defaultMatchTimeoutObj));
}
#if FEATURE_COMPILED
@@ -316,6 +212,21 @@ namespace System.Text.RegularExpressions
{
return RegexCompiler.Compile(code, roptions);
}
+
+ public static void CompileToAssembly(RegexCompilationInfo[] regexinfos, AssemblyName assemblyname)
+ {
+ throw new PlatformNotSupportedException(SR.PlatformNotSupported_CompileToAssembly);
+ }
+
+ public static void CompileToAssembly(RegexCompilationInfo[] regexinfos, AssemblyName assemblyname, CustomAttributeBuilder[] attributes)
+ {
+ throw new PlatformNotSupportedException(SR.PlatformNotSupported_CompileToAssembly);
+ }
+
+ public static void CompileToAssembly(RegexCompilationInfo[] regexinfos, AssemblyName assemblyname, CustomAttributeBuilder[] attributes, string resourceFile)
+ {
+ throw new PlatformNotSupportedException(SR.PlatformNotSupported_CompileToAssembly);
+ }
#endif
/// <summary>
@@ -338,7 +249,6 @@ namespace System.Text.RegularExpressions
/// <summary>
/// Unescapes any escaped characters in the input string.
/// </summary>
- [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Unescape", Justification = "Already shipped since v1 - can't fix without causing a breaking change")]
public static string Unescape(string str)
{
if (str == null)
@@ -347,65 +257,20 @@ namespace System.Text.RegularExpressions
return RegexParser.Unescape(str);
}
- [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "Reviewed for thread-safety")]
- public static int CacheSize
- {
- get
- {
- return s_cacheSize;
- }
- set
- {
- if (value < 0)
- throw new ArgumentOutOfRangeException(nameof(value));
-
- s_cacheSize = value;
- if (s_livecode.Count > s_cacheSize)
- {
- lock (s_livecode)
- {
- while (s_livecode.Count > s_cacheSize)
- s_livecode.RemoveLast();
- }
- }
- }
- }
-
/// <summary>
/// Returns the options passed into the constructor
/// </summary>
- public RegexOptions Options
- {
- get { return roptions; }
- }
-
-
- /// <summary>
- /// The match timeout used by this Regex instance.
- /// </summary>
- public TimeSpan MatchTimeout
- {
- get { return internalMatchTimeout; }
- }
+ public RegexOptions Options => roptions;
/// <summary>
/// Indicates whether the regular expression matches from right to left.
/// </summary>
- public bool RightToLeft
- {
- get
- {
- return UseOptionR();
- }
- }
+ public bool RightToLeft => UseOptionR();
/// <summary>
/// Returns the regular expression pattern passed into the constructor
/// </summary>
- public override string ToString()
- {
- return pattern;
- }
+ public override string ToString() => pattern;
/*
* Returns an array of the group names that are used to capture groups
@@ -434,7 +299,6 @@ namespace System.Text.RegularExpressions
else
{
result = new string[capslist.Length];
-
Array.Copy(capslist, 0, result, 0, capslist.Length);
}
@@ -559,412 +423,6 @@ namespace System.Text.RegularExpressions
return -1;
}
- /*
- * Static version of simple IsMatch call
- */
- /// <summary>
- /// Searches the input string for one or more occurrences of the text supplied in the given pattern.
- /// </summary>
- public static bool IsMatch(string input, string pattern)
- {
- return IsMatch(input, pattern, RegexOptions.None, DefaultMatchTimeout);
- }
-
- /*
- * Static version of simple IsMatch call
- */
- /// <summary>
- /// Searches the input string for one or more occurrences of the text
- /// supplied in the pattern parameter with matching options supplied in the options
- /// parameter.
- /// </summary>
- public static bool IsMatch(string input, string pattern, RegexOptions options)
- {
- return IsMatch(input, pattern, options, DefaultMatchTimeout);
- }
-
- public static bool IsMatch(string input, string pattern, RegexOptions options, TimeSpan matchTimeout)
- {
- return new Regex(pattern, options, matchTimeout, true).IsMatch(input);
- }
-
- /*
- * Returns true if the regex finds a match within the specified string
- */
- /// <summary>
- /// Searches the input string for one or more matches using the previous pattern,
- /// options, and starting position.
- /// </summary>
- public bool IsMatch(string input)
- {
- if (input == null)
- throw new ArgumentNullException(nameof(input));
-
- return IsMatch(input, UseOptionR() ? input.Length : 0);
- }
-
- /*
- * Returns true if the regex finds a match after the specified position
- * (proceeding leftward if the regex is leftward and rightward otherwise)
- */
- /// <summary>
- /// Searches the input string for one or more matches using the previous pattern and options,
- /// with a new starting position.
- /// </summary>
- public bool IsMatch(string input, int startat)
- {
- if (input == null)
- throw new ArgumentNullException(nameof(input));
-
- return (null == Run(true, -1, input, 0, input.Length, startat));
- }
-
- /*
- * Static version of simple Match call
- */
- /// <summary>
- /// Searches the input string for one or more occurrences of the text
- /// supplied in the pattern parameter.
- /// </summary>
- public static Match Match(string input, string pattern)
- {
- return Match(input, pattern, RegexOptions.None, DefaultMatchTimeout);
- }
-
- /*
- * Static version of simple Match call
- */
- /// <summary>
- /// Searches the input string for one or more occurrences of the text
- /// supplied in the pattern parameter. Matching is modified with an option
- /// string.
- /// </summary>
- public static Match Match(string input, string pattern, RegexOptions options)
- {
- return Match(input, pattern, options, DefaultMatchTimeout);
- }
-
-
- public static Match Match(string input, string pattern, RegexOptions options, TimeSpan matchTimeout)
- {
- return new Regex(pattern, options, matchTimeout, true).Match(input);
- }
-
- /*
- * Finds the first match for the regular expression starting at the beginning
- * of the string (or at the end of the string if the regex is leftward)
- */
- /// <summary>
- /// Matches a regular expression with a string and returns
- /// the precise result as a RegexMatch object.
- /// </summary>
- public Match Match(string input)
- {
- if (input == null)
- throw new ArgumentNullException(nameof(input));
-
- return Match(input, UseOptionR() ? input.Length : 0);
- }
-
- /*
- * Finds the first match, starting at the specified position
- */
- /// <summary>
- /// Matches a regular expression with a string and returns
- /// the precise result as a RegexMatch object.
- /// </summary>
- public Match Match(string input, int startat)
- {
- if (input == null)
- throw new ArgumentNullException(nameof(input));
-
- return Run(false, -1, input, 0, input.Length, startat);
- }
-
- /*
- * Finds the first match, restricting the search to the specified interval of
- * the char array.
- */
- /// <summary>
- /// Matches a regular expression with a string and returns the precise result as a
- /// RegexMatch object.
- /// </summary>
- public Match Match(string input, int beginning, int length)
- {
- if (input == null)
- throw new ArgumentNullException(nameof(input));
-
- return Run(false, -1, input, beginning, length, UseOptionR() ? beginning + length : beginning);
- }
-
- /*
- * Static version of simple Matches call
- */
- /// <summary>
- /// Returns all the successful matches as if Match were called iteratively numerous times.
- /// </summary>
- public static MatchCollection Matches(string input, string pattern)
- {
- return Matches(input, pattern, RegexOptions.None, DefaultMatchTimeout);
- }
-
- /*
- * Static version of simple Matches call
- */
- /// <summary>
- /// Returns all the successful matches as if Match were called iteratively numerous times.
- /// </summary>
- public static MatchCollection Matches(string input, string pattern, RegexOptions options)
- {
- return Matches(input, pattern, options, DefaultMatchTimeout);
- }
-
- public static MatchCollection Matches(string input, string pattern, RegexOptions options, TimeSpan matchTimeout)
- {
- return new Regex(pattern, options, matchTimeout, true).Matches(input);
- }
-
- /*
- * Finds the first match for the regular expression starting at the beginning
- * of the string Enumerator(or at the end of the string if the regex is leftward)
- */
- /// <summary>
- /// Returns all the successful matches as if Match was called iteratively numerous times.
- /// </summary>
- public MatchCollection Matches(string input)
- {
- if (input == null)
- throw new ArgumentNullException(nameof(input));
-
- return Matches(input, UseOptionR() ? input.Length : 0);
- }
-
- /*
- * Finds the first match, starting at the specified position
- */
- /// <summary>
- /// Returns all the successful matches as if Match was called iteratively numerous times.
- /// </summary>
- public MatchCollection Matches(string input, int startat)
- {
- if (input == null)
- throw new ArgumentNullException(nameof(input));
-
- return new MatchCollection(this, input, 0, input.Length, startat);
- }
-
- /// <summary>
- /// Replaces all occurrences of the pattern with the <paramref name="replacement"/> pattern, starting at
- /// the first character in the input string.
- /// </summary>
- public static string Replace(string input, string pattern, string replacement)
- {
- return Replace(input, pattern, replacement, RegexOptions.None, DefaultMatchTimeout);
- }
-
- /// <summary>
- /// Replaces all occurrences of
- /// the <paramref name="pattern "/>with the <paramref name="replacement "/>
- /// pattern, starting at the first character in the input string.
- /// </summary>
- public static string Replace(string input, string pattern, string replacement, RegexOptions options)
- {
- return Replace(input, pattern, replacement, options, DefaultMatchTimeout);
- }
-
- public static string Replace(string input, string pattern, string replacement, RegexOptions options, TimeSpan matchTimeout)
- {
- return new Regex(pattern, options, matchTimeout, true).Replace(input, replacement);
- }
-
- /// <summary>
- /// Replaces all occurrences of the previously defined pattern with the
- /// <paramref name="replacement"/> pattern, starting at the first character in the
- /// input string.
- /// </summary>
- public string Replace(string input, string replacement)
- {
- if (input == null)
- throw new ArgumentNullException(nameof(input));
-
- return Replace(input, replacement, -1, UseOptionR() ? input.Length : 0);
- }
-
- /// <summary>
- /// Replaces all occurrences of the previously defined pattern with the
- /// <paramref name="replacement"/> pattern, starting at the first character in the
- /// input string.
- /// </summary>
- public string Replace(string input, string replacement, int count)
- {
- if (input == null)
- throw new ArgumentNullException(nameof(input));
-
- return Replace(input, replacement, count, UseOptionR() ? input.Length : 0);
- }
-
- /// <summary>
- /// Replaces all occurrences of the previously defined pattern with the
- /// <paramref name="replacement"/> pattern, starting at the character position
- /// <paramref name="startat"/>.
- /// </summary>
- public string Replace(string input, string replacement, int count, int startat)
- {
- if (input == null)
- throw new ArgumentNullException(nameof(input));
-
- if (replacement == null)
- throw new ArgumentNullException(nameof(replacement));
-
- // a little code to grab a cached parsed replacement object
- RegexReplacement repl = (RegexReplacement)_replref.Get();
-
- if (repl == null || !repl.Pattern.Equals(replacement))
- {
- repl = RegexParser.ParseReplacement(replacement, caps, capsize, capnames, roptions);
- _replref.Cache(repl);
- }
-
- return repl.Replace(this, input, count, startat);
- }
-
- /// <summary>
- /// Replaces all occurrences of the <paramref name="pattern"/> with the recent
- /// replacement pattern.
- /// </summary>
- public static string Replace(string input, string pattern, MatchEvaluator evaluator)
- {
- return Replace(input, pattern, evaluator, RegexOptions.None, DefaultMatchTimeout);
- }
-
- /// <summary>
- /// Replaces all occurrences of the <paramref name="pattern"/> with the recent
- /// replacement pattern, starting at the first character.
- /// </summary>
- public static string Replace(string input, string pattern, MatchEvaluator evaluator, RegexOptions options)
- {
- return Replace(input, pattern, evaluator, options, DefaultMatchTimeout);
- }
-
- public static string Replace(string input, string pattern, MatchEvaluator evaluator, RegexOptions options, TimeSpan matchTimeout)
- {
- return new Regex(pattern, options, matchTimeout, true).Replace(input, evaluator);
- }
-
- /// <summary>
- /// Replaces all occurrences of the previously defined pattern with the recent
- /// replacement pattern, starting at the first character position.
- /// </summary>
- public string Replace(string input, MatchEvaluator evaluator)
- {
- if (input == null)
- throw new ArgumentNullException(nameof(input));
-
- return Replace(input, evaluator, -1, UseOptionR() ? input.Length : 0);
- }
-
- /// <summary>
- /// Replaces all occurrences of the previously defined pattern with the recent
- /// replacement pattern, starting at the first character position.
- /// </summary>
- public string Replace(string input, MatchEvaluator evaluator, int count)
- {
- if (input == null)
- throw new ArgumentNullException(nameof(input));
-
- return Replace(input, evaluator, count, UseOptionR() ? input.Length : 0);
- }
-
- /// <summary>
- /// Replaces all occurrences of the previously defined pattern with the recent
- /// replacement pattern, starting at the character position
- /// <paramref name="startat"/>.
- /// </summary>
- public string Replace(string input, MatchEvaluator evaluator, int count, int startat)
- {
- if (input == null)
- throw new ArgumentNullException(nameof(input));
-
- return RegexReplacement.Replace(evaluator, this, input, count, startat);
- }
-
- /// <summary>
- /// Splits the <paramref name="input "/>string at the position defined
- /// by <paramref name="pattern"/>.
- /// </summary>
- public static string[] Split(string input, string pattern)
- {
- return Split(input, pattern, RegexOptions.None, DefaultMatchTimeout);
- }
-
- /// <summary>
- /// Splits the <paramref name="input "/>string at the position defined by <paramref name="pattern"/>.
- /// </summary>
- public static string[] Split(string input, string pattern, RegexOptions options)
- {
- return Split(input, pattern, options, DefaultMatchTimeout);
- }
-
- public static string[] Split(string input, string pattern, RegexOptions options, TimeSpan matchTimeout)
- {
- return new Regex(pattern, options, matchTimeout, true).Split(input);
- }
-
- /// <summary>
- /// Splits the <paramref name="input"/> string at the position defined by a
- /// previous pattern.
- /// </summary>
- public string[] Split(string input)
- {
- if (input == null)
- throw new ArgumentNullException(nameof(input));
-
- return Split(input, 0, UseOptionR() ? input.Length : 0);
- }
-
- /// <summary>
- /// Splits the <paramref name="input"/> string at the position defined by a
- /// previous pattern.
- /// </summary>
- public string[] Split(string input, int count)
- {
- if (input == null)
- throw new ArgumentNullException(nameof(input));
-
- return RegexReplacement.Split(this, input, count, UseOptionR() ? input.Length : 0);
- }
-
- /// <summary>
- /// Splits the <paramref name="input"/> string at the position defined by a previous pattern.
- /// </summary>
- public string[] Split(string input, int count, int startat)
- {
- if (input == null)
- throw new ArgumentNullException(nameof(input));
-
- return RegexReplacement.Split(this, input, count, startat);
- }
-
-#if FEATURE_COMPILED
- [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "assemblyname", Justification = "Microsoft: already shipped since v1 - can't fix without causing a breaking change")]
- public static void CompileToAssembly(RegexCompilationInfo[] regexinfos, AssemblyName assemblyname)
- {
- throw new PlatformNotSupportedException(SR.PlatformNotSupported_CompileToAssembly);
- }
-
- [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "assemblyname", Justification = "Microsoft: already shipped since v1 - can't fix without causing a breaking change")]
- public static void CompileToAssembly(RegexCompilationInfo[] regexinfos, AssemblyName assemblyname, CustomAttributeBuilder[] attributes)
- {
- throw new PlatformNotSupportedException(SR.PlatformNotSupported_CompileToAssembly);
- }
-
- [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "assemblyname", Justification = "Microsoft: already shipped since v1 - can't fix without causing a breaking change")]
- public static void CompileToAssembly(RegexCompilationInfo[] regexinfos, AssemblyName assemblyname, CustomAttributeBuilder[] attributes, string resourceFile)
- {
- throw new PlatformNotSupportedException(SR.PlatformNotSupported_CompileToAssembly);
- }
-#endif
-
protected void InitializeReferences()
{
if (_refsInitialized)
@@ -972,18 +430,15 @@ namespace System.Text.RegularExpressions
_refsInitialized = true;
_runnerref = new ExclusiveReference();
- _replref = new SharedReference();
+ _replref = new WeakReference<RegexReplacement>(null);
}
-
- /*
- * Internal worker called by all the public APIs
- */
+ /// <summary>
+ /// Internal worker called by all the public APIs
+ /// </summary>
+ /// <returns></returns>
internal Match Run(bool quick, int prevlen, string input, int beginning, int length, int startat)
{
- Match match;
- RegexRunner runner = null;
-
if (startat < 0 || startat > input.Length)
throw new ArgumentOutOfRangeException(nameof(startat), SR.BeginIndexNotNegative);
@@ -991,21 +446,19 @@ namespace System.Text.RegularExpressions
throw new ArgumentOutOfRangeException(nameof(length), SR.LengthNotNegative);
// There may be a cached runner; grab ownership of it if we can.
-
- runner = (RegexRunner)_runnerref.Get();
+ RegexRunner runner = _runnerref.Get();
// Create a RegexRunner instance if we need to
-
if (runner == null)
{
// Use the compiled RegexRunner factory if the code was compiled to MSIL
-
if (factory != null)
runner = factory.CreateInstance();
else
runner = new RegexInterpreter(_code, UseOptionInvariant() ? CultureInfo.InvariantCulture : CultureInfo.CurrentCulture);
}
+ Match match;
try
{
// Do the scan starting at the requested position
@@ -1024,312 +477,20 @@ namespace System.Text.RegularExpressions
return match;
}
- /*
- * Find code cache based on options+pattern
- */
- private static CachedCodeEntry LookupCachedAndUpdate(CachedCodeEntryKey key)
- {
- lock (s_livecode)
- {
- for (LinkedListNode<CachedCodeEntry> current = s_livecode.First; current != null; current = current.Next)
- {
- if (current.Value._key == key)
- {
- // If we find an entry in the cache, move it to the head at the same time.
- s_livecode.Remove(current);
- s_livecode.AddFirst(current);
- return current.Value;
- }
- }
- }
-
- return null;
- }
-
- /*
- * Add current code to the cache
- */
- private CachedCodeEntry CacheCode(CachedCodeEntryKey key)
- {
- CachedCodeEntry newcached = null;
-
- lock (s_livecode)
- {
- // first look for it in the cache and move it to the head
- for (LinkedListNode<CachedCodeEntry> current = s_livecode.First; current != null; current = current.Next)
- {
- if (current.Value._key == key)
- {
- s_livecode.Remove(current);
- s_livecode.AddFirst(current);
- return current.Value;
- }
- }
-
- // it wasn't in the cache, so we'll add a new one. Shortcut out for the case where cacheSize is zero.
- if (s_cacheSize != 0)
- {
- newcached = new CachedCodeEntry(key, capnames, capslist, _code, caps, capsize, _runnerref, _replref);
- s_livecode.AddFirst(newcached);
- if (s_livecode.Count > s_cacheSize)
- s_livecode.RemoveLast();
- }
- }
-
- return newcached;
- }
-
- protected bool UseOptionC()
- {
- return (roptions & RegexOptions.Compiled) != 0;
- }
+ protected bool UseOptionC() => (roptions & RegexOptions.Compiled) != 0;
/*
* True if the L option was set
*/
- protected internal bool UseOptionR()
- {
- return (roptions & RegexOptions.RightToLeft) != 0;
- }
+ protected internal bool UseOptionR() => (roptions & RegexOptions.RightToLeft) != 0;
- internal bool UseOptionInvariant()
- {
- return (roptions & RegexOptions.CultureInvariant) != 0;
- }
+ internal bool UseOptionInvariant() => (roptions & RegexOptions.CultureInvariant) != 0;
#if DEBUG
- /*
- * True if the regex has debugging enabled
- */
- internal bool Debug
- {
- get
- {
- return (roptions & RegexOptions.Debug) != 0;
- }
- }
-#endif
- }
-
-
- /*
- * Callback class
- */
- public delegate string MatchEvaluator(Match match);
-
- /*
- * Used as a key for CacheCodeEntry
- */
- internal readonly struct CachedCodeEntryKey : IEquatable<CachedCodeEntryKey>
- {
- private readonly RegexOptions _options;
- private readonly string _cultureKey;
- private readonly string _pattern;
-
- internal CachedCodeEntryKey(RegexOptions options, string cultureKey, string pattern)
- {
- _options = options;
- _cultureKey = cultureKey;
- _pattern = pattern;
- }
-
- public override bool Equals(object obj)
- {
- return obj is CachedCodeEntryKey && Equals((CachedCodeEntryKey)obj);
- }
-
- public bool Equals(CachedCodeEntryKey other)
- {
- return this == other;
- }
-
- public static bool operator ==(CachedCodeEntryKey left, CachedCodeEntryKey right)
- {
- return left._options == right._options && left._cultureKey == right._cultureKey && left._pattern == right._pattern;
- }
-
- public static bool operator !=(CachedCodeEntryKey left, CachedCodeEntryKey right)
- {
- return !(left == right);
- }
-
- public override int GetHashCode()
- {
- return ((int)_options) ^ _cultureKey.GetHashCode() ^ _pattern.GetHashCode();
- }
- }
-
- /*
- * Used to cache byte codes
- */
- internal sealed class CachedCodeEntry
- {
- internal CachedCodeEntryKey _key;
- internal RegexCode _code;
- internal Hashtable _caps;
- internal Hashtable _capnames;
- internal string[] _capslist;
-#if FEATURE_COMPILED
- internal RegexRunnerFactory _factory;
-#endif
- internal int _capsize;
- internal ExclusiveReference _runnerref;
- internal SharedReference _replref;
-
- internal CachedCodeEntry(CachedCodeEntryKey key, Hashtable capnames, string[] capslist, RegexCode code, Hashtable caps, int capsize, ExclusiveReference runner, SharedReference repl)
- {
- _key = key;
- _capnames = capnames;
- _capslist = capslist;
-
- _code = code;
- _caps = caps;
- _capsize = capsize;
-
- _runnerref = runner;
- _replref = repl;
- }
-
-#if FEATURE_COMPILED
- internal void AddCompiled(RegexRunnerFactory factory)
- {
- _factory = factory;
- _code = null;
- }
+ /// <summary>
+ /// True if the regex has debugging enabled
+ /// </summary>
+ internal bool Debug => (roptions & RegexOptions.Debug) != 0;
#endif
}
-
- /*
- * Used to cache one exclusive runner reference
- */
- internal sealed class ExclusiveReference
- {
- private RegexRunner _ref;
- private object _obj;
- private int _locked;
-
- /*
- * Return an object and grab an exclusive lock.
- *
- * If the exclusive lock can't be obtained, null is returned;
- * if the object can't be returned, the lock is released.
- *
- */
- internal object Get()
- {
- // try to obtain the lock
-
- if (0 == Interlocked.Exchange(ref _locked, 1))
- {
- // grab reference
-
-
- object obj = _ref;
-
- // release the lock and return null if no reference
-
- if (obj == null)
- {
- _locked = 0;
- return null;
- }
-
- // remember the reference and keep the lock
-
- _obj = obj;
- return obj;
- }
-
- return null;
- }
-
- /*
- * Release an object back to the cache
- *
- * If the object is the one that's under lock, the lock
- * is released.
- *
- * If there is no cached object, then the lock is obtained
- * and the object is placed in the cache.
- *
- */
- internal void Release(object obj)
- {
- if (obj == null)
- throw new ArgumentNullException(nameof(obj));
-
- // if this reference owns the lock, release it
-
- if (_obj == obj)
- {
- _obj = null;
- _locked = 0;
- return;
- }
-
- // if no reference owns the lock, try to cache this reference
-
- if (_obj == null)
- {
- // try to obtain the lock
-
- if (0 == Interlocked.Exchange(ref _locked, 1))
- {
- // if there's really no reference, cache this reference
-
- if (_ref == null)
- _ref = (RegexRunner)obj;
-
- // release the lock
-
- _locked = 0;
- return;
- }
- }
- }
- }
-
- /*
- * Used to cache a weak reference in a threadsafe way
- */
- internal sealed class SharedReference
- {
- private WeakReference _ref = new WeakReference(null);
- private int _locked;
-
- /*
- * Return an object from a weakref, protected by a lock.
- *
- * If the exclusive lock can't be obtained, null is returned;
- *
- * Note that _ref.Target is referenced only under the protection
- * of the lock. (Is this necessary?)
- */
- internal object Get()
- {
- if (0 == Interlocked.Exchange(ref _locked, 1))
- {
- object obj = _ref.Target;
- _locked = 0;
- return obj;
- }
-
- return null;
- }
-
- /*
- * Suggest an object into a weakref, protected by a lock.
- *
- * Note that _ref.Target is referenced only under the protection
- * of the lock. (Is this necessary?)
- */
- internal void Cache(object obj)
- {
- if (0 == Interlocked.Exchange(ref _locked, 1))
- {
- _ref.Target = obj;
- _locked = 0;
- }
- }
- }
}
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexBoyerMoore.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexBoyerMoore.cs
index d70e2d906b..734a6ecf23 100644
--- a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexBoyerMoore.cs
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexBoyerMoore.cs
@@ -19,34 +19,26 @@ namespace System.Text.RegularExpressions
{
internal sealed class RegexBoyerMoore
{
- internal readonly int[] _positive;
- internal readonly int[] _negativeASCII;
- internal readonly int[][] _negativeUnicode;
- internal readonly string _pattern;
- internal readonly int _lowASCII;
- internal readonly int _highASCII;
- private readonly bool _rightToLeft;
- internal readonly bool _caseInsensitive;
+ public readonly int[] Positive;
+ public readonly int[] NegativeASCII;
+ public readonly int[][] NegativeUnicode;
+ public readonly string Pattern;
+ public readonly int LowASCII;
+ public readonly int HighASCII;
+ public readonly bool RightToLeft;
+ public readonly bool CaseInsensitive;
private readonly CultureInfo _culture;
/// <summary>
/// Constructs a Boyer-Moore state machine for searching for the string
/// pattern. The string must not be zero-length.
/// </summary>
- internal RegexBoyerMoore(string pattern, bool caseInsensitive, bool rightToLeft, CultureInfo culture)
+ public RegexBoyerMoore(string pattern, bool caseInsensitive, bool rightToLeft, CultureInfo culture)
{
// Sorry, you just can't use Boyer-Moore to find an empty pattern.
// We're doing this for your own protection. (Really, for speed.)
Debug.Assert(pattern.Length != 0, "RegexBoyerMoore called with an empty string. This is bad for perf");
- int beforefirst;
- int last;
- int bump;
- int examine;
- int scan;
- int match;
- char ch;
-
// We do the ToLower character by character for consistency. With surrogate chars, doing
// a ToLower on the entire string could actually change the surrogate pair. This is more correct
// linguistically, but since Regex doesn't support surrogates, it's more important to be
@@ -59,11 +51,15 @@ namespace System.Text.RegularExpressions
pattern = StringBuilderCache.GetStringAndRelease(sb);
}
- _pattern = pattern;
- _rightToLeft = rightToLeft;
- _caseInsensitive = caseInsensitive;
+ Pattern = pattern;
+ RightToLeft = rightToLeft;
+ CaseInsensitive = caseInsensitive;
_culture = culture;
+ int beforefirst;
+ int last;
+ int bump;
+
if (!rightToLeft)
{
beforefirst = -1;
@@ -86,12 +82,14 @@ namespace System.Text.RegularExpressions
// This algorithm is a simplified variant of the standard
// Boyer-Moore good suffix calculation.
- _positive = new int[pattern.Length];
+ Positive = new int[pattern.Length];
- examine = last;
- ch = pattern[examine];
- _positive[examine] = bump;
+ int examine = last;
+ char ch = pattern[examine];
+ Positive[examine] = bump;
examine -= bump;
+ int scan;
+ int match;
for (; ;)
{
@@ -118,8 +116,8 @@ namespace System.Text.RegularExpressions
// at the end of the match, note the difference in _positive
// this is not the length of the match, but the distance from the internal match
// to the tail suffix.
- if (_positive[match] == 0)
- _positive[match] = match - scan;
+ if (Positive[match] == 0)
+ Positive[match] = match - scan;
// System.Diagnostics.Debug.WriteLine("Set positive[" + match + "] to " + (match - scan));
@@ -146,8 +144,8 @@ namespace System.Text.RegularExpressions
// should mean a little more work rather than skipping a potential match.
while (match != beforefirst)
{
- if (_positive[match] == 0)
- _positive[match] = bump;
+ if (Positive[match] == 0)
+ Positive[match] = bump;
match -= bump;
}
@@ -164,13 +162,13 @@ namespace System.Text.RegularExpressions
// appear in the string are in the table. (Maximum size with
// Unicode is 65K; ASCII only case is 512 bytes.)
- _negativeASCII = new int[128];
+ NegativeASCII = new int[128];
for (int i = 0; i < 128; i++)
- _negativeASCII[i] = last - beforefirst;
+ NegativeASCII[i] = last - beforefirst;
- _lowASCII = 127;
- _highASCII = 0;
+ LowASCII = 127;
+ HighASCII = 0;
for (examine = last; examine != beforefirst; examine -= bump)
{
@@ -178,26 +176,26 @@ namespace System.Text.RegularExpressions
if (ch < 128)
{
- if (_lowASCII > ch)
- _lowASCII = ch;
+ if (LowASCII > ch)
+ LowASCII = ch;
- if (_highASCII < ch)
- _highASCII = ch;
+ if (HighASCII < ch)
+ HighASCII = ch;
- if (_negativeASCII[ch] == last - beforefirst)
- _negativeASCII[ch] = last - examine;
+ if (NegativeASCII[ch] == last - beforefirst)
+ NegativeASCII[ch] = last - examine;
}
else
{
int i = ch >> 8;
int j = ch & 0xFF;
- if (_negativeUnicode == null)
+ if (NegativeUnicode == null)
{
- _negativeUnicode = new int[256][];
+ NegativeUnicode = new int[256][];
}
- if (_negativeUnicode[i] == null)
+ if (NegativeUnicode[i] == null)
{
int[] newarray = new int[256];
@@ -206,63 +204,64 @@ namespace System.Text.RegularExpressions
if (i == 0)
{
- Array.Copy(_negativeASCII, 0, newarray, 0, 128);
- _negativeASCII = newarray;
+ Array.Copy(NegativeASCII, 0, newarray, 0, 128);
+ NegativeASCII = newarray;
}
- _negativeUnicode[i] = newarray;
+ NegativeUnicode[i] = newarray;
}
- if (_negativeUnicode[i][j] == last - beforefirst)
- _negativeUnicode[i][j] = last - examine;
+ if (NegativeUnicode[i][j] == last - beforefirst)
+ NegativeUnicode[i][j] = last - examine;
}
}
}
private bool MatchPattern(string text, int index)
{
- if (_caseInsensitive)
+ if (CaseInsensitive)
{
- if (text.Length - index < _pattern.Length)
+ if (text.Length - index < Pattern.Length)
{
return false;
}
TextInfo textinfo = _culture.TextInfo;
- for (int i = 0; i < _pattern.Length; i++)
+ for (int i = 0; i < Pattern.Length; i++)
{
- Debug.Assert(textinfo.ToLower(_pattern[i]) == _pattern[i], "pattern should be converted to lower case in constructor!");
- if (textinfo.ToLower(text[index + i]) != _pattern[i])
+ Debug.Assert(textinfo.ToLower(Pattern[i]) == Pattern[i], "pattern should be converted to lower case in constructor!");
+ if (textinfo.ToLower(text[index + i]) != Pattern[i])
{
return false;
}
}
+
return true;
}
else
{
- return (0 == string.CompareOrdinal(_pattern, 0, text, index, _pattern.Length));
+ return (0 == string.CompareOrdinal(Pattern, 0, text, index, Pattern.Length));
}
}
/// <summary>
/// When a regex is anchored, we can do a quick IsMatch test instead of a Scan
/// </summary>
- internal bool IsMatch(string text, int index, int beglimit, int endlimit)
+ public bool IsMatch(string text, int index, int beglimit, int endlimit)
{
- if (!_rightToLeft)
+ if (!RightToLeft)
{
- if (index < beglimit || endlimit - index < _pattern.Length)
+ if (index < beglimit || endlimit - index < Pattern.Length)
return false;
return MatchPattern(text, index);
}
else
{
- if (index > endlimit || index - beglimit < _pattern.Length)
+ if (index > endlimit || index - beglimit < Pattern.Length)
return false;
- return MatchPattern(text, index - _pattern.Length);
+ return MatchPattern(text, index - Pattern.Length);
}
}
@@ -274,38 +273,37 @@ namespace System.Text.RegularExpressions
/// The direction and case-sensitivity of the match is determined
/// by the arguments to the RegexBoyerMoore constructor.
/// </summary>
- internal int Scan(string text, int index, int beglimit, int endlimit)
+ public int Scan(string text, int index, int beglimit, int endlimit)
{
+ int defadv;
int test;
- int test2;
- int match;
int startmatch;
int endmatch;
- int advance;
- int defadv;
int bump;
- char chMatch;
- char chTest;
- int[] unicodeLookup;
- if (!_rightToLeft)
+ if (!RightToLeft)
{
- defadv = _pattern.Length;
- startmatch = _pattern.Length - 1;
+ defadv = Pattern.Length;
+ startmatch = Pattern.Length - 1;
endmatch = 0;
test = index + defadv - 1;
bump = 1;
}
else
{
- defadv = -_pattern.Length;
+ defadv = -Pattern.Length;
startmatch = 0;
endmatch = -defadv - 1;
test = index + defadv;
bump = -1;
}
- chMatch = _pattern[startmatch];
+ char chMatch = Pattern[startmatch];
+ char chTest;
+ int test2;
+ int match;
+ int advance;
+ int[] unicodeLookup;
for (; ;)
{
@@ -314,14 +312,14 @@ namespace System.Text.RegularExpressions
chTest = text[test];
- if (_caseInsensitive)
+ if (CaseInsensitive)
chTest = _culture.TextInfo.ToLower(chTest);
if (chTest != chMatch)
{
if (chTest < 128)
- advance = _negativeASCII[chTest];
- else if (null != _negativeUnicode && (null != (unicodeLookup = _negativeUnicode[chTest >> 8])))
+ advance = NegativeASCII[chTest];
+ else if (null != NegativeUnicode && (null != (unicodeLookup = NegativeUnicode[chTest >> 8])))
advance = unicodeLookup[chTest & 0xFF];
else
advance = defadv;
@@ -336,22 +334,22 @@ namespace System.Text.RegularExpressions
for (; ;)
{
if (match == endmatch)
- return (_rightToLeft ? test2 + 1 : test2);
+ return (RightToLeft ? test2 + 1 : test2);
match -= bump;
test2 -= bump;
chTest = text[test2];
- if (_caseInsensitive)
+ if (CaseInsensitive)
chTest = _culture.TextInfo.ToLower(chTest);
- if (chTest != _pattern[match])
+ if (chTest != Pattern[match])
{
- advance = _positive[match];
+ advance = Positive[match];
if ((chTest & 0xFF80) == 0)
- test2 = (match - startmatch) + _negativeASCII[chTest];
- else if (null != _negativeUnicode && (null != (unicodeLookup = _negativeUnicode[chTest >> 8])))
+ test2 = (match - startmatch) + NegativeASCII[chTest];
+ else if (null != NegativeUnicode && (null != (unicodeLookup = NegativeUnicode[chTest >> 8])))
test2 = (match - startmatch) + unicodeLookup[chTest & 0xFF];
else
{
@@ -359,7 +357,7 @@ namespace System.Text.RegularExpressions
break;
}
- if (_rightToLeft ? test2 < advance : test2 > advance)
+ if (RightToLeft ? test2 < advance : test2 > advance)
advance = test2;
test += advance;
@@ -370,35 +368,32 @@ namespace System.Text.RegularExpressions
}
}
+#if DEBUG
/// <summary>
/// Used when dumping for debugging.
/// </summary>
- public override string ToString()
- {
- return _pattern;
- }
+ public override string ToString() => Pattern;
-#if DEBUG
public string Dump(string indent)
{
StringBuilder sb = new StringBuilder();
- sb.Append(indent + "BM Pattern: " + _pattern + "\n");
+ sb.Append(indent + "BM Pattern: " + Pattern + "\n");
sb.Append(indent + "Positive: ");
- for (int i = 0; i < _positive.Length; i++)
+ for (int i = 0; i < Positive.Length; i++)
{
- sb.Append(_positive[i].ToString(CultureInfo.InvariantCulture) + " ");
+ sb.Append(Positive[i].ToString(CultureInfo.InvariantCulture) + " ");
}
sb.Append("\n");
- if (_negativeASCII != null)
+ if (NegativeASCII != null)
{
sb.Append(indent + "Negative table\n");
- for (int i = 0; i < _negativeASCII.Length; i++)
+ for (int i = 0; i < NegativeASCII.Length; i++)
{
- if (_negativeASCII[i] != _pattern.Length)
+ if (NegativeASCII[i] != Pattern.Length)
{
- sb.Append(indent + " " + Regex.Escape(Convert.ToString((char)i, CultureInfo.InvariantCulture)) + " " + _negativeASCII[i].ToString(CultureInfo.InvariantCulture) + "\n");
+ sb.Append(indent + " " + Regex.Escape(Convert.ToString((char)i, CultureInfo.InvariantCulture)) + " " + NegativeASCII[i].ToString(CultureInfo.InvariantCulture) + "\n");
}
}
}
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCapture.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCapture.cs
deleted file mode 100644
index 060d1a0652..0000000000
--- a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCapture.cs
+++ /dev/null
@@ -1,106 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-// Capture is just a location/length pair that indicates the
-// location of a regular expression match. A single regexp
-// search may return multiple Capture within each capturing
-// RegexGroup.
-
-namespace System.Text.RegularExpressions
-{
- /// <summary>
- /// Represents the results from a single subexpression capture. The object represents
- /// one substring for a single successful capture.
- /// </summary>
- [Serializable]
- public class Capture
- {
- internal string _text;
- internal int _index;
- internal int _length;
-
- internal Capture(string text, int i, int l)
- {
- _text = text;
- _index = i;
- _length = l;
- }
-
- /*
- * The index of the beginning of the matched capture
- */
- /// <summary>
- /// Returns the position in the original string where the first character of
- /// captured substring was found.
- /// </summary>
- public int Index
- {
- get
- {
- return _index;
- }
- }
-
- /*
- * The length of the matched capture
- */
- /// <summary>
- /// Returns the length of the captured substring.
- /// </summary>
- public int Length
- {
- get
- {
- return _length;
- }
- }
-
- /// <summary>
- /// Returns the value of this Regex Capture.
- /// </summary>
- public string Value
- {
- get
- {
- return _text.Substring(_index, _length);
- }
- }
-
- /*
- * The capture as a string
- */
- /// <summary>
- /// Returns the substring that was matched.
- /// </summary>
- override public string ToString()
- {
- return Value;
- }
-
- /*
- * The original string
- */
- internal string GetOriginalString()
- {
- return _text;
- }
-
- /*
- * The substring to the left of the capture
- */
- internal string GetLeftSubstring()
- {
- return _text.Substring(0, _index);
- }
-
- /*
- * The substring to the right of the capture
- */
- internal string GetRightSubstring()
- {
- return _text.Substring(_index + _length, _text.Length - _index - _length);
- }
-
- }
-}
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCharClass.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCharClass.cs
index d4ab864958..42bf64bf9c 100644
--- a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCharClass.cs
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCharClass.cs
@@ -29,13 +29,6 @@ namespace System.Text.RegularExpressions
{
internal sealed class RegexCharClass
{
- // instance data
- private List<SingleRange> _rangelist;
- private StringBuilder _categories;
- private bool _canonical;
- private bool _negate;
- private RegexCharClass _subtractor;
-
// Constants
private const int FLAGS = 0;
private const int SETLENGTH = 1;
@@ -43,32 +36,28 @@ namespace System.Text.RegularExpressions
private const int SETSTART = 3;
private const string NullCharString = "\0";
-
private const char NullChar = '\0';
private const char LastChar = '\uFFFF';
-
private const char GroupChar = (char)0;
-
private const short SpaceConst = 100;
private const short NotSpaceConst = -100;
private const char ZeroWidthJoiner = '\u200D';
private const char ZeroWidthNonJoiner = '\u200C';
-
private static readonly string s_internalRegexIgnoreCase = "__InternalRegexIgnoreCase__";
private static readonly string s_space = "\x64";
private static readonly string s_notSpace = "\uFF9C";
private static readonly string s_word = "\u0000\u0002\u0004\u0005\u0003\u0001\u0006\u0009\u0013\u0000";
private static readonly string s_notWord = "\u0000\uFFFE\uFFFC\uFFFB\uFFFD\uFFFF\uFFFA\uFFF7\uFFED\u0000";
- internal static readonly string SpaceClass = "\u0000\u0000\u0001\u0064";
- internal static readonly string NotSpaceClass = "\u0001\u0000\u0001\u0064";
- internal static readonly string WordClass = "\u0000\u0000\u000A\u0000\u0002\u0004\u0005\u0003\u0001\u0006\u0009\u0013\u0000";
- internal static readonly string NotWordClass = "\u0001\u0000\u000A\u0000\u0002\u0004\u0005\u0003\u0001\u0006\u0009\u0013\u0000";
- internal static readonly string DigitClass = "\u0000\u0000\u0001\u0009";
- internal static readonly string NotDigitClass = "\u0000\u0000\u0001\uFFF7";
+ public static readonly string SpaceClass = "\u0000\u0000\u0001\u0064";
+ public static readonly string NotSpaceClass = "\u0001\u0000\u0001\u0064";
+ public static readonly string WordClass = "\u0000\u0000\u000A\u0000\u0002\u0004\u0005\u0003\u0001\u0006\u0009\u0013\u0000";
+ public static readonly string NotWordClass = "\u0001\u0000\u000A\u0000\u0002\u0004\u0005\u0003\u0001\u0006\u0009\u0013\u0000";
+ public static readonly string DigitClass = "\u0000\u0000\u0001\u0009";
+ public static readonly string NotDigitClass = "\u0000\u0000\u0001\uFFF7";
private const string ECMASpaceSet = "\u0009\u000E\u0020\u0021";
private const string NotECMASpaceSet = "\0\u0009\u000E\u0020\u0021";
@@ -77,15 +66,15 @@ namespace System.Text.RegularExpressions
private const string ECMADigitSet = "\u0030\u003A";
private const string NotECMADigitSet = "\0\u0030\u003A";
- internal const string ECMASpaceClass = "\x00\x04\x00" + ECMASpaceSet;
- internal const string NotECMASpaceClass = "\x01\x04\x00" + ECMASpaceSet;
- internal const string ECMAWordClass = "\x00\x0A\x00" + ECMAWordSet;
- internal const string NotECMAWordClass = "\x01\x0A\x00" + ECMAWordSet;
- internal const string ECMADigitClass = "\x00\x02\x00" + ECMADigitSet;
- internal const string NotECMADigitClass = "\x01\x02\x00" + ECMADigitSet;
+ public const string ECMASpaceClass = "\x00\x04\x00" + ECMASpaceSet;
+ public const string NotECMASpaceClass = "\x01\x04\x00" + ECMASpaceSet;
+ public const string ECMAWordClass = "\x00\x0A\x00" + ECMAWordSet;
+ public const string NotECMAWordClass = "\x01\x0A\x00" + ECMAWordSet;
+ public const string ECMADigitClass = "\x00\x02\x00" + ECMADigitSet;
+ public const string NotECMADigitClass = "\x01\x02\x00" + ECMADigitSet;
- internal const string AnyClass = "\x00\x01\x00\x00";
- internal const string EmptyClass = "\x00\x00\x00";
+ public const string AnyClass = "\x00\x01\x00\x00";
+ public const string EmptyClass = "\x00\x00\x00";
// UnicodeCategory is zero based, so we add one to each value and subtract it off later
private const int DefinedCategoriesCapacity = 38;
@@ -279,7 +268,6 @@ namespace System.Text.RegularExpressions
+"\u3041\u3097\u3099\u30A0\u30A1\u30FB\u30FC\u3100\u3105\u312D\u3131\u318F\u3190\u31B8\u31F0\u321D\u3220\u3244\u3251\u327C\u327F\u32CC\u32D0\u32FF\u3300\u3377\u337B\u33DE\u33E0\u33FF\u3400\u4DB6\u4E00\u9FA6\uA000\uA48D\uA490\uA4C7\uAC00\uD7A4\uF900\uFA2E\uFA30\uFA6B\uFB00\uFB07\uFB13\uFB18\uFB1D\uFB37\uFB38\uFB3D\uFB3E\uFB3F\uFB40\uFB42\uFB43\uFB45\uFB46\uFBB2\uFBD3\uFD3E\uFD50\uFD90\uFD92\uFDC8\uFDF0\uFDFD\uFE00\uFE10\uFE20\uFE24\uFE62\uFE63\uFE64\uFE67\uFE69\uFE6A\uFE70\uFE75\uFE76\uFEFD\uFF04\uFF05\uFF0B\uFF0C\uFF10\uFF1A\uFF1C\uFF1F\uFF21\uFF3B\uFF3E\uFF3F\uFF40\uFF5B\uFF5C\uFF5D\uFF5E\uFF5F\uFF66\uFFBF\uFFC2\uFFC8\uFFCA\uFFD0\uFFD2\uFFD8\uFFDA\uFFDD\uFFE0\uFFE7\uFFE8\uFFEF\uFFFC\uFFFE"},
};
-
/**************************************************************************
Let U be the set of Unicode character values and let L be the lowercase
function, mapping from U to U. To perform case insensitive matching of
@@ -411,6 +399,12 @@ namespace System.Text.RegularExpressions
new LowerCaseMapping('\uFF21', '\uFF3A', LowercaseAdd, 32),
};
+ private List<SingleRange> _rangelist;
+ private StringBuilder _categories;
+ private bool _canonical;
+ private bool _negate;
+ private RegexCharClass _subtractor;
+
#if DEBUG
static RegexCharClass()
{
@@ -432,7 +426,7 @@ namespace System.Text.RegularExpressions
/// <summary>
/// Creates an empty character class.
/// </summary>
- internal RegexCharClass()
+ public RegexCharClass()
{
_rangelist = new List<SingleRange>(6);
_canonical = true;
@@ -448,7 +442,7 @@ namespace System.Text.RegularExpressions
_subtractor = subtraction;
}
- internal bool CanMerge
+ public bool CanMerge
{
get
{
@@ -456,12 +450,12 @@ namespace System.Text.RegularExpressions
}
}
- internal bool Negate
+ public bool Negate
{
set { _negate = value; }
}
- internal void AddChar(char c)
+ public void AddChar(char c)
{
AddRange(c, c);
}
@@ -469,7 +463,7 @@ namespace System.Text.RegularExpressions
/// <summary>
/// Adds a regex char class
/// </summary>
- internal void AddCharClass(RegexCharClass cc)
+ public void AddCharClass(RegexCharClass cc)
{
int i;
@@ -480,7 +474,7 @@ namespace System.Text.RegularExpressions
// if the new char class to add isn't canonical, we're not either.
_canonical = false;
}
- else if (_canonical && RangeCount() > 0 && cc.RangeCount() > 0 && cc.GetRangeAt(0)._first <= GetRangeAt(RangeCount() - 1)._last)
+ else if (_canonical && RangeCount() > 0 && cc.RangeCount() > 0 && cc.GetRangeAt(0).First <= GetRangeAt(RangeCount() - 1).Last)
_canonical = false;
for (i = 0; i < cc.RangeCount(); i += 1)
@@ -499,7 +493,7 @@ namespace System.Text.RegularExpressions
int i;
if (_canonical && RangeCount() > 0 && set.Length > 0 &&
- set[0] <= GetRangeAt(RangeCount() - 1)._last)
+ set[0] <= GetRangeAt(RangeCount() - 1).Last)
_canonical = false;
for (i = 0; i < set.Length - 1; i += 2)
@@ -513,7 +507,7 @@ namespace System.Text.RegularExpressions
}
}
- internal void AddSubtraction(RegexCharClass sub)
+ public void AddSubtraction(RegexCharClass sub)
{
Debug.Assert(_subtractor == null, "Can't add two subtractions to a char class. ");
_subtractor = sub;
@@ -522,20 +516,19 @@ namespace System.Text.RegularExpressions
/// <summary>
/// Adds a single range of characters to the class.
/// </summary>
- internal void AddRange(char first, char last)
+ public void AddRange(char first, char last)
{
_rangelist.Add(new SingleRange(first, last));
if (_canonical && _rangelist.Count > 0 &&
- first <= _rangelist[_rangelist.Count - 1]._last)
+ first <= _rangelist[_rangelist.Count - 1].Last)
{
_canonical = false;
}
}
- internal void AddCategoryFromName(string categoryName, bool invert, bool caseInsensitive, string pattern)
+ public void AddCategoryFromName(string categoryName, bool invert, bool caseInsensitive, string pattern)
{
- string category;
- if (s_definedCategories.TryGetValue(categoryName, out category) && !categoryName.Equals(s_internalRegexIgnoreCase))
+ if (s_definedCategories.TryGetValue(categoryName, out string category) && !categoryName.Equals(s_internalRegexIgnoreCase))
{
if (caseInsensitive)
{
@@ -562,7 +555,7 @@ namespace System.Text.RegularExpressions
/// Adds to the class any lowercase versions of characters already
/// in the class. Used for case-insensitivity.
/// </summary>
- internal void AddLowercase(CultureInfo culture)
+ public void AddLowercase(CultureInfo culture)
{
_canonical = false;
@@ -570,14 +563,14 @@ namespace System.Text.RegularExpressions
for (int i = 0; i < count; i++)
{
SingleRange range = _rangelist[i];
- if (range._first == range._last)
+ if (range.First == range.Last)
{
- char lower = culture.TextInfo.ToLower(range._first);
+ char lower = culture.TextInfo.ToLower(range.First);
_rangelist[i] = new SingleRange(lower, lower);
}
else
{
- AddLowercaseRange(range._first, range._last, culture);
+ AddLowercaseRange(range.First, range.Last, culture);
}
}
}
@@ -595,7 +588,7 @@ namespace System.Text.RegularExpressions
for (i = 0, iMax = s_lcTable.Length; i < iMax;)
{
iMid = (i + iMax) / 2;
- if (s_lcTable[iMid]._chMax < chMin)
+ if (s_lcTable[iMid].ChMax < chMin)
i = iMid + 1;
else
iMax = iMid;
@@ -604,25 +597,25 @@ namespace System.Text.RegularExpressions
if (i >= s_lcTable.Length)
return;
- for (; i < s_lcTable.Length && (lc = s_lcTable[i])._chMin <= chMax; i++)
+ for (; i < s_lcTable.Length && (lc = s_lcTable[i]).ChMin <= chMax; i++)
{
- if ((chMinT = lc._chMin) < chMin)
+ if ((chMinT = lc.ChMin) < chMin)
chMinT = chMin;
- if ((chMaxT = lc._chMax) > chMax)
+ if ((chMaxT = lc.ChMax) > chMax)
chMaxT = chMax;
- switch (lc._lcOp)
+ switch (lc.LcOp)
{
case LowercaseSet:
- chMinT = (char)lc._data;
- chMaxT = (char)lc._data;
+ chMinT = (char)lc.Data;
+ chMaxT = (char)lc.Data;
break;
case LowercaseAdd:
unchecked
{
- chMinT += (char)lc._data;
- chMaxT += (char)lc._data;
+ chMinT += (char)lc.Data;
+ chMaxT += (char)lc.Data;
}
break;
case LowercaseBor:
@@ -640,7 +633,7 @@ namespace System.Text.RegularExpressions
}
}
- internal void AddWord(bool ecma, bool negate)
+ public void AddWord(bool ecma, bool negate)
{
if (negate)
{
@@ -658,7 +651,7 @@ namespace System.Text.RegularExpressions
}
}
- internal void AddSpace(bool ecma, bool negate)
+ public void AddSpace(bool ecma, bool negate)
{
if (negate)
{
@@ -676,7 +669,7 @@ namespace System.Text.RegularExpressions
}
}
- internal void AddDigit(bool ecma, bool negate, string pattern)
+ public void AddDigit(bool ecma, bool negate, string pattern)
{
if (ecma)
{
@@ -689,7 +682,7 @@ namespace System.Text.RegularExpressions
AddCategoryFromName("Nd", negate, false, pattern);
}
- internal static string ConvertOldStringsToClass(string set, string category)
+ public static string ConvertOldStringsToClass(string set, string category)
{
StringBuilder sb = StringBuilderCache.Acquire(set.Length + category.Length + 3);
@@ -715,29 +708,26 @@ namespace System.Text.RegularExpressions
/// <summary>
/// Returns the char
/// </summary>
- internal static char SingletonChar(string set)
+ public static char SingletonChar(string set)
{
Debug.Assert(IsSingleton(set) || IsSingletonInverse(set), "Tried to get the singleton char out of a non singleton character class");
return set[SETSTART];
}
- internal static bool IsMergeable(string charClass)
+ public static bool IsMergeable(string charClass)
{
return (!IsNegated(charClass) && !IsSubtraction(charClass));
}
- internal static bool IsEmpty(string charClass)
+ public static bool IsEmpty(string charClass)
{
- if (charClass[CATEGORYLENGTH] == 0 && charClass[FLAGS] == 0 && charClass[SETLENGTH] == 0 && !IsSubtraction(charClass))
- return true;
- else
- return false;
+ return (charClass[CATEGORYLENGTH] == 0 && charClass[FLAGS] == 0 && charClass[SETLENGTH] == 0 && !IsSubtraction(charClass));
}
/// <summary>
/// <c>true</c> if the set contains a single character only
/// </summary>
- internal static bool IsSingleton(string set)
+ public static bool IsSingleton(string set)
{
if (set[FLAGS] == 0 && set[CATEGORYLENGTH] == 0 && set[SETLENGTH] == 2 && !IsSubtraction(set) &&
(set[SETSTART] == LastChar || set[SETSTART] + 1 == set[SETSTART + 1]))
@@ -746,7 +736,7 @@ namespace System.Text.RegularExpressions
return false;
}
- internal static bool IsSingletonInverse(string set)
+ public static bool IsSingletonInverse(string set)
{
if (set[FLAGS] == 1 && set[CATEGORYLENGTH] == 0 && set[SETLENGTH] == 2 && !IsSubtraction(set) &&
(set[SETSTART] == LastChar || set[SETSTART] + 1 == set[SETSTART + 1]))
@@ -760,12 +750,12 @@ namespace System.Text.RegularExpressions
return (charClass.Length > SETSTART + charClass[SETLENGTH] + charClass[CATEGORYLENGTH]);
}
- internal static bool IsNegated(string set)
+ private static bool IsNegated(string set)
{
return (set != null && set[FLAGS] == 1);
}
- internal static bool IsECMAWordChar(char ch)
+ public static bool IsECMAWordChar(char ch)
{
// According to ECMA-262, \s, \S, ., ^, and $ use Unicode-based interpretations of
// whitespace and newline, while \d, \D\, \w, \W, \b, and \B use ASCII-only
@@ -775,7 +765,7 @@ namespace System.Text.RegularExpressions
return CharInClass(ch, ECMAWordClass);
}
- internal static bool IsWordChar(char ch)
+ public static bool IsWordChar(char ch)
{
// According to UTS#18 Unicode Regular Expressions (http://www.unicode.org/reports/tr18/)
// RL 1.4 Simple Word Boundaries The class of <word_character> includes all Alphabetic
@@ -784,13 +774,12 @@ namespace System.Text.RegularExpressions
return CharInClass(ch, WordClass) || ch == ZeroWidthJoiner || ch == ZeroWidthNonJoiner;
}
- internal static bool CharInClass(char ch, string set)
+ public static bool CharInClass(char ch, string set)
{
return CharInClassRecursive(ch, set, 0);
}
-
- internal static bool CharInClassRecursive(char ch, string set, int start)
+ private static bool CharInClassRecursive(char ch, string set, int start)
{
int mySetLength = set[start + SETLENGTH];
int myCategoryLength = set[start + CATEGORYLENGTH];
@@ -977,7 +966,7 @@ namespace System.Text.RegularExpressions
return StringBuilderCache.GetStringAndRelease(sb);
}
- internal static RegexCharClass Parse(string charClass)
+ public static RegexCharClass Parse(string charClass)
{
return ParseRecursive(charClass, 0);
}
@@ -1023,7 +1012,7 @@ namespace System.Text.RegularExpressions
/// <summary>
/// Constructs the string representation of the class.
/// </summary>
- internal string ToStringClass()
+ public string ToStringClass()
{
if (!_canonical)
Canonicalize();
@@ -1047,10 +1036,10 @@ namespace System.Text.RegularExpressions
for (int i = 0; i < _rangelist.Count; i++)
{
SingleRange currentRange = _rangelist[i];
- sb.Append(currentRange._first);
+ sb.Append(currentRange.First);
- if (currentRange._last != LastChar)
- sb.Append((char)(currentRange._last + 1));
+ if (currentRange.Last != LastChar)
+ sb.Append((char)(currentRange.Last + 1));
}
sb[SETLENGTH] = (char)(sb.Length - SETSTART);
@@ -1095,7 +1084,7 @@ namespace System.Text.RegularExpressions
for (i = 1, j = 0; ; i++)
{
- for (last = _rangelist[j]._last; ; i++)
+ for (last = _rangelist[j].Last; ; i++)
{
if (i == _rangelist.Count || last == LastChar)
{
@@ -1103,14 +1092,14 @@ namespace System.Text.RegularExpressions
break;
}
- if ((CurrentRange = _rangelist[i])._first > last + 1)
+ if ((CurrentRange = _rangelist[i]).First > last + 1)
break;
- if (last < CurrentRange._last)
- last = CurrentRange._last;
+ if (last < CurrentRange.Last)
+ last = CurrentRange.Last;
}
- _rangelist[j] = new SingleRange(_rangelist[j]._first, last);
+ _rangelist[j] = new SingleRange(_rangelist[j].First, last);
j++;
@@ -1159,10 +1148,20 @@ namespace System.Text.RegularExpressions
#if DEBUG
+ public static readonly char[] Hex = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+ public static readonly string[] Categories = new string[] {"Lu", "Ll", "Lt", "Lm", "Lo", s_internalRegexIgnoreCase,
+ "Mn", "Mc", "Me",
+ "Nd", "Nl", "No",
+ "Zs", "Zl", "Zp",
+ "Cc", "Cf", "Cs", "Co",
+ "Pc", "Pd", "Ps", "Pe", "Pi", "Pf", "Po",
+ "Sm", "Sc", "Sk", "So",
+ "Cn" };
+
/// <summary>
/// Produces a human-readable description for a set string.
/// </summary>
- internal static string SetDescription(string set)
+ public static string SetDescription(string set)
{
int mySetLength = set[SETLENGTH];
int myCategoryLength = set[CATEGORYLENGTH];
@@ -1208,7 +1207,7 @@ namespace System.Text.RegularExpressions
int lastindex = set.IndexOf(GroupChar, index + 1);
string group = set.Substring(index, lastindex - index + 1);
- foreach (var kvp in s_definedCategories)
+ foreach (KeyValuePair<string, string> kvp in s_definedCategories)
{
if (group.Equals(kvp.Value))
{
@@ -1256,20 +1255,10 @@ namespace System.Text.RegularExpressions
return desc.ToString();
}
- internal static readonly char[] Hex = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
- internal static readonly string[] Categories = new string[] {"Lu", "Ll", "Lt", "Lm", "Lo", s_internalRegexIgnoreCase,
- "Mn", "Mc", "Me",
- "Nd", "Nl", "No",
- "Zs", "Zl", "Zp",
- "Cc", "Cf", "Cs", "Co",
- "Pc", "Pd", "Ps", "Pe", "Pi", "Pf", "Po",
- "Sm", "Sc", "Sk", "So",
- "Cn" };
-
/// <summary>
/// Produces a human-readable description for a single character.
/// </summary>
- internal static string CharDescription(char ch)
+ public static string CharDescription(char ch)
{
if (ch == '\\')
return "\\\\";
@@ -1325,18 +1314,18 @@ namespace System.Text.RegularExpressions
/// </summary>
private readonly struct LowerCaseMapping
{
+ public readonly char ChMin;
+ public readonly char ChMax;
+ public readonly int LcOp;
+ public readonly int Data;
+
internal LowerCaseMapping(char chMin, char chMax, int lcOp, int data)
{
- _chMin = chMin;
- _chMax = chMax;
- _lcOp = lcOp;
- _data = data;
+ ChMin = chMin;
+ ChMax = chMax;
+ LcOp = lcOp;
+ Data = data;
}
-
- internal readonly char _chMin;
- internal readonly char _chMax;
- internal readonly int _lcOp;
- internal readonly int _data;
}
/// <summary>
@@ -1352,7 +1341,7 @@ namespace System.Text.RegularExpressions
public int Compare(SingleRange x, SingleRange y)
{
- return x._first.CompareTo(y._first);
+ return x.First.CompareTo(y.First);
}
}
@@ -1361,14 +1350,14 @@ namespace System.Text.RegularExpressions
/// </summary>
private readonly struct SingleRange
{
+ public readonly char First;
+ public readonly char Last;
+
internal SingleRange(char first, char last)
{
- _first = first;
- _last = last;
+ First = first;
+ Last = last;
}
-
- internal readonly char _first;
- internal readonly char _last;
}
}
}
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCode.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCode.cs
index b500772081..21738410f0 100644
--- a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCode.cs
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCode.cs
@@ -27,98 +27,98 @@ namespace System.Text.RegularExpressions
// The following primitive operations come directly from the parser
// lef/back operands description
- internal const int Onerep = 0; // lef,back char,min,max a {n}
- internal const int Notonerep = 1; // lef,back char,min,max .{n}
- internal const int Setrep = 2; // lef,back set,min,max [\d]{n}
+ public const int Onerep = 0; // lef,back char,min,max a {n}
+ public const int Notonerep = 1; // lef,back char,min,max .{n}
+ public const int Setrep = 2; // lef,back set,min,max [\d]{n}
- internal const int Oneloop = 3; // lef,back char,min,max a {,n}
- internal const int Notoneloop = 4; // lef,back char,min,max .{,n}
- internal const int Setloop = 5; // lef,back set,min,max [\d]{,n}
+ public const int Oneloop = 3; // lef,back char,min,max a {,n}
+ public const int Notoneloop = 4; // lef,back char,min,max .{,n}
+ public const int Setloop = 5; // lef,back set,min,max [\d]{,n}
- internal const int Onelazy = 6; // lef,back char,min,max a {,n}?
- internal const int Notonelazy = 7; // lef,back char,min,max .{,n}?
- internal const int Setlazy = 8; // lef,back set,min,max [\d]{,n}?
+ public const int Onelazy = 6; // lef,back char,min,max a {,n}?
+ public const int Notonelazy = 7; // lef,back char,min,max .{,n}?
+ public const int Setlazy = 8; // lef,back set,min,max [\d]{,n}?
- internal const int One = 9; // lef char a
- internal const int Notone = 10; // lef char [^a]
- internal const int Set = 11; // lef set [a-z\s] \w \s \d
+ public const int One = 9; // lef char a
+ public const int Notone = 10; // lef char [^a]
+ public const int Set = 11; // lef set [a-z\s] \w \s \d
- internal const int Multi = 12; // lef string abcd
- internal const int Ref = 13; // lef group \#
+ public const int Multi = 12; // lef string abcd
+ public const int Ref = 13; // lef group \#
- internal const int Bol = 14; // ^
- internal const int Eol = 15; // $
- internal const int Boundary = 16; // \b
- internal const int Nonboundary = 17; // \B
- internal const int Beginning = 18; // \A
- internal const int Start = 19; // \G
- internal const int EndZ = 20; // \Z
- internal const int End = 21; // \Z
+ public const int Bol = 14; // ^
+ public const int Eol = 15; // $
+ public const int Boundary = 16; // \b
+ public const int Nonboundary = 17; // \B
+ public const int Beginning = 18; // \A
+ public const int Start = 19; // \G
+ public const int EndZ = 20; // \Z
+ public const int End = 21; // \Z
- internal const int Nothing = 22; // Reject!
+ public const int Nothing = 22; // Reject!
// Primitive control structures
- internal const int Lazybranch = 23; // back jump straight first
- internal const int Branchmark = 24; // back jump branch first for loop
- internal const int Lazybranchmark = 25; // back jump straight first for loop
- internal const int Nullcount = 26; // back val set counter, null mark
- internal const int Setcount = 27; // back val set counter, make mark
- internal const int Branchcount = 28; // back jump,limit branch++ if zero<=c<limit
- internal const int Lazybranchcount = 29; // back jump,limit same, but straight first
- internal const int Nullmark = 30; // back save position
- internal const int Setmark = 31; // back save position
- internal const int Capturemark = 32; // back group define group
- internal const int Getmark = 33; // back recall position
- internal const int Setjump = 34; // back save backtrack state
- internal const int Backjump = 35; // zap back to saved state
- internal const int Forejump = 36; // zap backtracking state
- internal const int Testref = 37; // backtrack if ref undefined
- internal const int Goto = 38; // jump just go
-
- internal const int Prune = 39; // prune it baby
- internal const int Stop = 40; // done!
-
- internal const int ECMABoundary = 41; // \b
- internal const int NonECMABoundary = 42; // \B
+ public const int Lazybranch = 23; // back jump straight first
+ public const int Branchmark = 24; // back jump branch first for loop
+ public const int Lazybranchmark = 25; // back jump straight first for loop
+ public const int Nullcount = 26; // back val set counter, null mark
+ public const int Setcount = 27; // back val set counter, make mark
+ public const int Branchcount = 28; // back jump,limit branch++ if zero<=c<limit
+ public const int Lazybranchcount = 29; // back jump,limit same, but straight first
+ public const int Nullmark = 30; // back save position
+ public const int Setmark = 31; // back save position
+ public const int Capturemark = 32; // back group define group
+ public const int Getmark = 33; // back recall position
+ public const int Setjump = 34; // back save backtrack state
+ public const int Backjump = 35; // zap back to saved state
+ public const int Forejump = 36; // zap backtracking state
+ public const int Testref = 37; // backtrack if ref undefined
+ public const int Goto = 38; // jump just go
+
+ public const int Prune = 39; // prune it baby
+ public const int Stop = 40; // done!
+
+ public const int ECMABoundary = 41; // \b
+ public const int NonECMABoundary = 42; // \B
// Modifiers for alternate modes
- internal const int Mask = 63; // Mask to get unmodified ordinary operator
- internal const int Rtl = 64; // bit to indicate that we're reverse scanning.
- internal const int Back = 128; // bit to indicate that we're backtracking.
- internal const int Back2 = 256; // bit to indicate that we're backtracking on a second branch.
- internal const int Ci = 512; // bit to indicate that we're case-insensitive.
-
- internal readonly int[] _codes; // the code
- internal readonly string[] _strings; // the string/set table
- internal readonly int _trackcount; // how many instructions use backtracking
- internal readonly Hashtable _caps; // mapping of user group numbers -> impl group slots
- internal readonly int _capsize; // number of impl group slots
- internal readonly RegexPrefix _fcPrefix; // the set of candidate first characters (may be null)
- internal readonly RegexBoyerMoore _bmPrefix; // the fixed prefix string as a Boyer-Moore machine (may be null)
- internal readonly int _anchors; // the set of zero-length start anchors (RegexFCD.Bol, etc)
- internal readonly bool _rightToLeft; // true if right to left
-
- internal RegexCode(int[] codes, List<string> stringlist, int trackcount,
+ public const int Mask = 63; // Mask to get unmodified ordinary operator
+ public const int Rtl = 64; // bit to indicate that we're reverse scanning.
+ public const int Back = 128; // bit to indicate that we're backtracking.
+ public const int Back2 = 256; // bit to indicate that we're backtracking on a second branch.
+ public const int Ci = 512; // bit to indicate that we're case-insensitive.
+
+ public readonly int[] Codes; // the code
+ public readonly string[] Strings; // the string/set table
+ public readonly int TrackCount; // how many instructions use backtracking
+ public readonly Hashtable Caps; // mapping of user group numbers -> impl group slots
+ public readonly int CapSize; // number of impl group slots
+ public readonly RegexPrefix? FCPrefix; // the set of candidate first characters (may be null)
+ public readonly RegexBoyerMoore BMPrefix; // the fixed prefix string as a Boyer-Moore machine (may be null)
+ public readonly int Anchors; // the set of zero-length start anchors (RegexFCD.Bol, etc)
+ public readonly bool RightToLeft; // true if right to left
+
+ public RegexCode(int[] codes, List<string> stringlist, int trackcount,
Hashtable caps, int capsize,
- RegexBoyerMoore bmPrefix, RegexPrefix fcPrefix,
+ RegexBoyerMoore bmPrefix, RegexPrefix? fcPrefix,
int anchors, bool rightToLeft)
{
Debug.Assert(codes != null, "codes cannot be null.");
Debug.Assert(stringlist != null, "stringlist cannot be null.");
- _codes = codes;
- _strings = stringlist.ToArray();
- _trackcount = trackcount;
- _caps = caps;
- _capsize = capsize;
- _bmPrefix = bmPrefix;
- _fcPrefix = fcPrefix;
- _anchors = anchors;
- _rightToLeft = rightToLeft;
+ Codes = codes;
+ Strings = stringlist.ToArray();
+ TrackCount = trackcount;
+ Caps = caps;
+ CapSize = capsize;
+ BMPrefix = bmPrefix;
+ FCPrefix = fcPrefix;
+ Anchors = anchors;
+ RightToLeft = rightToLeft;
}
- internal static bool OpcodeBacktracks(int Op)
+ public static bool OpcodeBacktracks(int Op)
{
Op &= Mask;
@@ -151,7 +151,7 @@ namespace System.Text.RegularExpressions
}
}
- internal static int OpcodeSize(int opcode)
+ public static int OpcodeSize(int opcode)
{
opcode &= Mask;
@@ -212,7 +212,7 @@ namespace System.Text.RegularExpressions
}
#if DEBUG
- private static readonly string[] CodeStr = new string[]
+ private static readonly string[] s_codeStr = new string[]
{
"Onerep", "Notonerep", "Setrep",
"Oneloop", "Notoneloop", "Setloop",
@@ -231,21 +231,21 @@ namespace System.Text.RegularExpressions
#endif
};
- internal static string OperatorDescription(int Opcode)
+ private static string OperatorDescription(int Opcode)
{
bool isCi = ((Opcode & Ci) != 0);
bool isRtl = ((Opcode & Rtl) != 0);
bool isBack = ((Opcode & Back) != 0);
bool isBack2 = ((Opcode & Back2) != 0);
- return CodeStr[Opcode & Mask] +
+ return s_codeStr[Opcode & Mask] +
(isCi ? "-Ci" : "") + (isRtl ? "-Rtl" : "") + (isBack ? "-Back" : "") + (isBack2 ? "-Back2" : "");
}
- internal string OpcodeDescription(int offset)
+ public string OpcodeDescription(int offset)
{
StringBuilder sb = new StringBuilder();
- int opcode = _codes[offset];
+ int opcode = Codes[offset];
sb.AppendFormat("{0:D6} ", offset);
sb.Append(OpcodeBacktracks(opcode & Mask) ? '*' : ' ');
@@ -265,7 +265,7 @@ namespace System.Text.RegularExpressions
case Onelazy:
case Notonelazy:
sb.Append("Ch = ");
- sb.Append(RegexCharClass.CharDescription((char)_codes[offset + 1]));
+ sb.Append(RegexCharClass.CharDescription((char)Codes[offset + 1]));
break;
case Set:
@@ -273,34 +273,34 @@ namespace System.Text.RegularExpressions
case Setloop:
case Setlazy:
sb.Append("Set = ");
- sb.Append(RegexCharClass.SetDescription(_strings[_codes[offset + 1]]));
+ sb.Append(RegexCharClass.SetDescription(Strings[Codes[offset + 1]]));
break;
case Multi:
sb.Append("String = ");
- sb.Append(_strings[_codes[offset + 1]]);
+ sb.Append(Strings[Codes[offset + 1]]);
break;
case Ref:
case Testref:
sb.Append("Index = ");
- sb.Append(_codes[offset + 1]);
+ sb.Append(Codes[offset + 1]);
break;
case Capturemark:
sb.Append("Index = ");
- sb.Append(_codes[offset + 1]);
- if (_codes[offset + 2] != -1)
+ sb.Append(Codes[offset + 1]);
+ if (Codes[offset + 2] != -1)
{
sb.Append(", Unindex = ");
- sb.Append(_codes[offset + 2]);
+ sb.Append(Codes[offset + 2]);
}
break;
case Nullcount:
case Setcount:
sb.Append("Value = ");
- sb.Append(_codes[offset + 1]);
+ sb.Append(Codes[offset + 1]);
break;
case Goto:
@@ -310,7 +310,7 @@ namespace System.Text.RegularExpressions
case Branchcount:
case Lazybranchcount:
sb.Append("Addr = ");
- sb.Append(_codes[offset + 1]);
+ sb.Append(Codes[offset + 1]);
break;
}
@@ -326,19 +326,19 @@ namespace System.Text.RegularExpressions
case Setloop:
case Setlazy:
sb.Append(", Rep = ");
- if (_codes[offset + 2] == int.MaxValue)
+ if (Codes[offset + 2] == int.MaxValue)
sb.Append("inf");
else
- sb.Append(_codes[offset + 2]);
+ sb.Append(Codes[offset + 2]);
break;
case Branchcount:
case Lazybranchcount:
sb.Append(", Limit = ");
- if (_codes[offset + 2] == int.MaxValue)
+ if (Codes[offset + 2] == int.MaxValue)
sb.Append("inf");
else
- sb.Append(_codes[offset + 2]);
+ sb.Append(Codes[offset + 2]);
break;
}
@@ -347,24 +347,24 @@ namespace System.Text.RegularExpressions
return sb.ToString();
}
- internal void Dump()
+ public void Dump()
{
int i;
- Debug.WriteLine("Direction: " + (_rightToLeft ? "right-to-left" : "left-to-right"));
- Debug.WriteLine("Firstchars: " + (_fcPrefix == null ? "n/a" : RegexCharClass.SetDescription(_fcPrefix.Prefix)));
- Debug.WriteLine("Prefix: " + (_bmPrefix == null ? "n/a" : Regex.Escape(_bmPrefix.ToString())));
- Debug.WriteLine("Anchors: " + RegexFCD.AnchorDescription(_anchors));
+ Debug.WriteLine("Direction: " + (RightToLeft ? "right-to-left" : "left-to-right"));
+ Debug.WriteLine("Firstchars: " + (FCPrefix == null ? "n/a" : RegexCharClass.SetDescription(FCPrefix.GetValueOrDefault().Prefix)));
+ Debug.WriteLine("Prefix: " + (BMPrefix == null ? "n/a" : Regex.Escape(BMPrefix.ToString())));
+ Debug.WriteLine("Anchors: " + RegexFCD.AnchorDescription(Anchors));
Debug.WriteLine("");
- if (_bmPrefix != null)
+ if (BMPrefix != null)
{
Debug.WriteLine("BoyerMoore:");
- Debug.WriteLine(_bmPrefix.Dump(" "));
+ Debug.WriteLine(BMPrefix.Dump(" "));
}
- for (i = 0; i < _codes.Length;)
+ for (i = 0; i < Codes.Length;)
{
Debug.WriteLine(OpcodeDescription(i));
- i += OpcodeSize(_codes[i]);
+ i += OpcodeSize(Codes[i]);
}
Debug.WriteLine("");
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompilationInfo.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompilationInfo.cs
index 2f27e09f40..9bed23d25e 100644
--- a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompilationInfo.cs
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompilationInfo.cs
@@ -15,7 +15,7 @@ namespace System.Text.RegularExpressions
private TimeSpan _matchTimeout;
public RegexCompilationInfo(string pattern, RegexOptions options, string name, string fullnamespace, bool ispublic)
- : this(pattern, options, name, fullnamespace, ispublic, Regex.DefaultMatchTimeout)
+ : this(pattern, options, name, fullnamespace, ispublic, Regex.s_defaultMatchTimeout)
{
}
@@ -63,10 +63,7 @@ namespace System.Text.RegularExpressions
public string Namespace
{
get => _nspace;
- set
- {
- _nspace = value ?? throw new ArgumentNullException(nameof(Namespace));
- }
+ set => _nspace = value ?? throw new ArgumentNullException(nameof(Namespace));
}
public RegexOptions Options { get; set; }
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs
index fac86269ec..5f585ba7d3 100644
--- a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs
@@ -7,11 +7,9 @@
// subclass of the RegexRunner type.
using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reflection;
using System.Reflection.Emit;
-using System.Runtime.Versioning;
namespace System.Text.RegularExpressions
{
@@ -28,90 +26,90 @@ namespace System.Text.RegularExpressions
internal abstract class RegexCompiler
{
// fields that never change (making them saves about 6% overall running time)
- internal static FieldInfo s_textbegF;
- internal static FieldInfo s_textendF;
- internal static FieldInfo s_textstartF;
- internal static FieldInfo s_textposF;
- internal static FieldInfo s_textF;
- internal static FieldInfo s_trackposF;
- internal static FieldInfo s_trackF;
- internal static FieldInfo s_stackposF;
- internal static FieldInfo s_stackF;
- internal static FieldInfo s_trackcountF;
-
- internal static MethodInfo s_ensurestorageM;
- internal static MethodInfo s_captureM;
- internal static MethodInfo s_transferM;
- internal static MethodInfo s_uncaptureM;
- internal static MethodInfo s_ismatchedM;
- internal static MethodInfo s_matchlengthM;
- internal static MethodInfo s_matchindexM;
- internal static MethodInfo s_isboundaryM;
- internal static MethodInfo s_isECMABoundaryM;
- internal static MethodInfo s_chartolowerM;
- internal static MethodInfo s_getcharM;
- internal static MethodInfo s_crawlposM;
- internal static MethodInfo s_charInSetM;
- internal static MethodInfo s_getCurrentCulture;
- internal static MethodInfo s_getInvariantCulture;
- internal static MethodInfo s_checkTimeoutM;
+ private static FieldInfo s_textbegF;
+ private static FieldInfo s_textendF;
+ private static FieldInfo s_textstartF;
+ private static FieldInfo s_textposF;
+ private static FieldInfo s_textF;
+ private static FieldInfo s_trackposF;
+ private static FieldInfo s_trackF;
+ private static FieldInfo s_stackposF;
+ private static FieldInfo s_stackF;
+ private static FieldInfo s_trackcountF;
+
+ private static MethodInfo s_ensurestorageM;
+ private static MethodInfo s_captureM;
+ private static MethodInfo s_transferM;
+ private static MethodInfo s_uncaptureM;
+ private static MethodInfo s_ismatchedM;
+ private static MethodInfo s_matchlengthM;
+ private static MethodInfo s_matchindexM;
+ private static MethodInfo s_isboundaryM;
+ private static MethodInfo s_isECMABoundaryM;
+ private static MethodInfo s_chartolowerM;
+ private static MethodInfo s_getcharM;
+ private static MethodInfo s_crawlposM;
+ private static MethodInfo s_charInSetM;
+ private static MethodInfo s_getCurrentCulture;
+ private static MethodInfo s_getInvariantCulture;
+ private static MethodInfo s_checkTimeoutM;
#if DEBUG
- internal static MethodInfo s_dumpstateM;
+ private static MethodInfo s_dumpstateM;
#endif
- internal ILGenerator _ilg;
+ protected ILGenerator _ilg;
// tokens representing local variables
- internal LocalBuilder _textstartV;
- internal LocalBuilder _textbegV;
- internal LocalBuilder _textendV;
- internal LocalBuilder _textposV;
- internal LocalBuilder _textV;
- internal LocalBuilder _trackposV;
- internal LocalBuilder _trackV;
- internal LocalBuilder _stackposV;
- internal LocalBuilder _stackV;
- internal LocalBuilder _tempV;
- internal LocalBuilder _temp2V;
- internal LocalBuilder _temp3V;
-
- internal RegexCode _code; // the RegexCode object (used for debugging only)
- internal int[] _codes; // the RegexCodes being translated
- internal string[] _strings; // the stringtable associated with the RegexCodes
- internal RegexPrefix _fcPrefix; // the possible first chars computed by RegexFCD
- internal RegexBoyerMoore _bmPrefix; // a prefix as a boyer-moore machine
- internal int _anchors; // the set of anchors
-
- internal Label[] _labels; // a label for every operation in _codes
- internal BacktrackNote[] _notes; // a list of the backtracking states to be generated
- internal int _notecount; // true count of _notes (allocation grows exponentially)
- internal int _trackcount; // count of backtracking states (used to reduce allocations)
-
- internal Label _backtrack; // label for backtracking
-
-
- internal int _regexopcode; // the current opcode being processed
- internal int _codepos; // the current code being translated
- internal int _backpos; // the current backtrack-note being translated
-
- internal RegexOptions _options; // options
+ private LocalBuilder _textstartV;
+ private LocalBuilder _textbegV;
+ private LocalBuilder _textendV;
+ private LocalBuilder _textposV;
+ private LocalBuilder _textV;
+ private LocalBuilder _trackposV;
+ private LocalBuilder _trackV;
+ private LocalBuilder _stackposV;
+ private LocalBuilder _stackV;
+ private LocalBuilder _tempV;
+ private LocalBuilder _temp2V;
+ private LocalBuilder _temp3V;
+
+ protected RegexCode _code; // the RegexCode object (used for debugging only)
+ protected int[] _codes; // the RegexCodes being translated
+ protected string[] _strings; // the stringtable associated with the RegexCodes
+ protected RegexPrefix? _fcPrefix; // the possible first chars computed by RegexFCD
+ protected RegexBoyerMoore _bmPrefix; // a prefix as a boyer-moore machine
+ protected int _anchors; // the set of anchors
+
+ private Label[] _labels; // a label for every operation in _codes
+ private BacktrackNote[] _notes; // a list of the backtracking states to be generated
+ private int _notecount; // true count of _notes (allocation grows exponentially)
+ protected int _trackcount; // count of backtracking states (used to reduce allocations)
+
+ private Label _backtrack; // label for backtracking
+
+
+ private int _regexopcode; // the current opcode being processed
+ private int _codepos; // the current code being translated
+ private int _backpos; // the current backtrack-note being translated
+
+ protected RegexOptions _options; // options
// special code fragments
- internal int[] _uniquenote; // _notes indices for code that should be emitted <= once
- internal int[] _goto; // indices for forward-jumps-through-switch (for allocations)
+ private int[] _uniquenote; // _notes indices for code that should be emitted <= once
+ private int[] _goto; // indices for forward-jumps-through-switch (for allocations)
// indices for unique code fragments
- internal const int Stackpop = 0; // pop one
- internal const int Stackpop2 = 1; // pop two
- internal const int Stackpop3 = 2; // pop three
- internal const int Capback = 3; // uncapture
- internal const int Capback2 = 4; // uncapture 2
- internal const int Branchmarkback2 = 5; // back2 part of branchmark
- internal const int Lazybranchmarkback2 = 6; // back2 part of lazybranchmark
- internal const int Branchcountback2 = 7; // back2 part of branchcount
- internal const int Lazybranchcountback2 = 8; // back2 part of lazybranchcount
- internal const int Forejumpback = 9; // back part of forejump
- internal const int Uniquecount = 10;
+ private const int Stackpop = 0; // pop one
+ private const int Stackpop2 = 1; // pop two
+ private const int Stackpop3 = 2; // pop three
+ private const int Capback = 3; // uncapture
+ private const int Capback2 = 4; // uncapture 2
+ private const int Branchmarkback2 = 5; // back2 part of branchmark
+ private const int Lazybranchmarkback2 = 6; // back2 part of lazybranchmark
+ private const int Branchcountback2 = 7; // back2 part of branchcount
+ private const int Lazybranchcountback2 = 8; // back2 part of lazybranchcount
+ private const int Forejumpback = 9; // back part of forejump
+ private const int Uniquecount = 10;
static RegexCompiler()
{
@@ -161,7 +159,6 @@ namespace System.Text.RegularExpressions
return typeof(RegexRunner).GetMethod(methname, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
}
-
/*
* Entry point to dynamically compile a regular expression. The expression is compiled to
* an in-memory assembly.
@@ -175,25 +172,25 @@ namespace System.Text.RegularExpressions
* Keeps track of an operation that needs to be referenced in the backtrack-jump
* switch table, and that needs backtracking code to be emitted (if flags != 0)
*/
- internal sealed class BacktrackNote
+ private sealed class BacktrackNote
{
- internal BacktrackNote(int flags, Label label, int codepos)
+ internal int _codepos;
+ internal int _flags;
+ internal Label _label;
+
+ public BacktrackNote(int flags, Label label, int codepos)
{
_codepos = codepos;
_flags = flags;
_label = label;
}
-
- internal int _codepos;
- internal int _flags;
- internal Label _label;
}
/*
* Adds a backtrack note to the list of them, and returns the index of the new
* note (which is also the index for the jump used by the switch table)
*/
- internal int AddBacktrackNote(int flags, Label l, int codepos)
+ private int AddBacktrackNote(int flags, Label l, int codepos)
{
if (_notes == null || _notecount >= _notes.Length)
{
@@ -212,7 +209,7 @@ namespace System.Text.RegularExpressions
* Adds a backtrack note for the current operation; creates a new label for
* where the code will be, and returns the switch index.
*/
- internal int AddTrack()
+ private int AddTrack()
{
return AddTrack(RegexCode.Back);
}
@@ -221,7 +218,7 @@ namespace System.Text.RegularExpressions
* Adds a backtrack note for the current operation; creates a new label for
* where the code will be, and returns the switch index.
*/
- internal int AddTrack(int flags)
+ private int AddTrack(int flags)
{
return AddBacktrackNote(flags, DefineLabel(), _codepos);
}
@@ -230,7 +227,7 @@ namespace System.Text.RegularExpressions
* Adds a switchtable entry for the specified position (for the forward
* logic; does not cause backtracking logic to be generated)
*/
- internal int AddGoto(int destpos)
+ private int AddGoto(int destpos)
{
if (_goto[destpos] == -1)
_goto[destpos] = AddBacktrackNote(0, _labels[destpos], destpos);
@@ -243,7 +240,7 @@ namespace System.Text.RegularExpressions
* if it's already marked to be generated, returns the switch index
* for the unique piece of code.
*/
- internal int AddUniqueTrack(int i)
+ private int AddUniqueTrack(int i)
{
return AddUniqueTrack(i, RegexCode.Back);
}
@@ -253,7 +250,7 @@ namespace System.Text.RegularExpressions
* if it's already marked to be generated, returns the switch index
* for the unique piece of code.
*/
- internal int AddUniqueTrack(int i, int flags)
+ private int AddUniqueTrack(int i, int flags)
{
if (_uniquenote[i] == -1)
_uniquenote[i] = AddTrack(flags);
@@ -264,7 +261,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.DefineLabel
*/
- internal Label DefineLabel()
+ private Label DefineLabel()
{
return _ilg.DefineLabel();
}
@@ -272,7 +269,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.MarkLabel
*/
- internal void MarkLabel(Label l)
+ private void MarkLabel(Label l)
{
_ilg.MarkLabel(l);
}
@@ -280,7 +277,7 @@ namespace System.Text.RegularExpressions
/*
* Returns the ith operand of the current operation
*/
- internal int Operand(int i)
+ private int Operand(int i)
{
return _codes[_codepos + i + 1];
}
@@ -288,7 +285,7 @@ namespace System.Text.RegularExpressions
/*
* True if the current operation is marked for the leftward direction
*/
- internal bool IsRtl()
+ private bool IsRtl()
{
return (_regexopcode & RegexCode.Rtl) != 0;
}
@@ -296,7 +293,7 @@ namespace System.Text.RegularExpressions
/*
* True if the current operation is marked for case insensitive operation
*/
- internal bool IsCi()
+ private bool IsCi()
{
return (_regexopcode & RegexCode.Ci) != 0;
}
@@ -305,14 +302,14 @@ namespace System.Text.RegularExpressions
/*
* True if we need to do the backtrack logic for the current operation
*/
- internal bool IsBack() {
+ private bool IsBack() {
return(_regexopcode & RegexCode.Back) != 0;
}
/*
* True if we need to do the second-backtrack logic for the current operation
*/
- internal bool IsBack2() {
+ private bool IsBack2() {
return(_regexopcode & RegexCode.Back2) != 0;
}
#endif
@@ -320,12 +317,12 @@ namespace System.Text.RegularExpressions
/*
* Returns the raw regex opcode (masking out Back and Rtl)
*/
- internal int Code()
+ private int Code()
{
return _regexopcode & RegexCode.Mask;
}
- internal void Ldstr(string str)
+ private void Ldstr(string str)
{
_ilg.Emit(OpCodes.Ldstr, str);
}
@@ -333,7 +330,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for the various forms of Ldc
*/
- internal void Ldc(int i)
+ private void Ldc(int i)
{
if (i <= 127 && i >= -128)
_ilg.Emit(OpCodes.Ldc_I4_S, (byte)i);
@@ -341,7 +338,7 @@ namespace System.Text.RegularExpressions
_ilg.Emit(OpCodes.Ldc_I4, i);
}
- internal void LdcI8(long i)
+ private void LdcI8(long i)
{
if (i <= int.MaxValue && i >= int.MinValue)
{
@@ -357,7 +354,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Dup)
*/
- internal void Dup()
+ private void Dup()
{
_ilg.Emit(OpCodes.Dup);
}
@@ -365,7 +362,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Ret)
*/
- internal void Ret()
+ private void Ret()
{
_ilg.Emit(OpCodes.Ret);
}
@@ -373,7 +370,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Pop)
*/
- internal void Pop()
+ private void Pop()
{
_ilg.Emit(OpCodes.Pop);
}
@@ -381,7 +378,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Add)
*/
- internal void Add()
+ private void Add()
{
_ilg.Emit(OpCodes.Add);
}
@@ -389,7 +386,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Add); a true flag can turn it into a Sub
*/
- internal void Add(bool negate)
+ private void Add(bool negate)
{
if (negate)
_ilg.Emit(OpCodes.Sub);
@@ -400,7 +397,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Sub)
*/
- internal void Sub()
+ private void Sub()
{
_ilg.Emit(OpCodes.Sub);
}
@@ -408,7 +405,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Sub); a true flag can turn it into a Add
*/
- internal void Sub(bool negate)
+ private void Sub(bool negate)
{
if (negate)
_ilg.Emit(OpCodes.Add);
@@ -419,7 +416,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Ldloc);
*/
- internal void Ldloc(LocalBuilder lt)
+ private void Ldloc(LocalBuilder lt)
{
_ilg.Emit(OpCodes.Ldloc_S, lt);
}
@@ -427,7 +424,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Stloc);
*/
- internal void Stloc(LocalBuilder lt)
+ private void Stloc(LocalBuilder lt)
{
_ilg.Emit(OpCodes.Stloc_S, lt);
}
@@ -435,7 +432,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Ldarg_0);
*/
- internal void Ldthis()
+ private void Ldthis()
{
_ilg.Emit(OpCodes.Ldarg_0);
}
@@ -443,7 +440,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for Ldthis(); Ldfld();
*/
- internal void Ldthisfld(FieldInfo ft)
+ private void Ldthisfld(FieldInfo ft)
{
Ldthis();
_ilg.Emit(OpCodes.Ldfld, ft);
@@ -452,7 +449,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for Ldthis(); Ldfld(); Stloc();
*/
- internal void Mvfldloc(FieldInfo ft, LocalBuilder lt)
+ private void Mvfldloc(FieldInfo ft, LocalBuilder lt)
{
Ldthisfld(ft);
Stloc(lt);
@@ -461,7 +458,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for Ldthis(); Ldthisfld(); Stloc();
*/
- internal void Mvlocfld(LocalBuilder lt, FieldInfo ft)
+ private void Mvlocfld(LocalBuilder lt, FieldInfo ft)
{
Ldthis();
Ldloc(lt);
@@ -471,7 +468,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Stfld);
*/
- internal void Stfld(FieldInfo ft)
+ private void Stfld(FieldInfo ft)
{
_ilg.Emit(OpCodes.Stfld, ft);
}
@@ -479,7 +476,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Callvirt);
*/
- internal void Callvirt(MethodInfo mt)
+ private void Callvirt(MethodInfo mt)
{
_ilg.Emit(OpCodes.Callvirt, mt);
}
@@ -487,7 +484,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Call);
*/
- internal void Call(MethodInfo mt)
+ private void Call(MethodInfo mt)
{
_ilg.Emit(OpCodes.Call, mt);
}
@@ -495,7 +492,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Newobj);
*/
- internal void Newobj(ConstructorInfo ct)
+ private void Newobj(ConstructorInfo ct)
{
_ilg.Emit(OpCodes.Newobj, ct);
}
@@ -503,7 +500,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Brfalse) (long form)
*/
- internal void BrfalseFar(Label l)
+ private void BrfalseFar(Label l)
{
_ilg.Emit(OpCodes.Brfalse, l);
}
@@ -511,7 +508,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Brtrue) (long form)
*/
- internal void BrtrueFar(Label l)
+ private void BrtrueFar(Label l)
{
_ilg.Emit(OpCodes.Brtrue, l);
}
@@ -519,7 +516,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Br) (long form)
*/
- internal void BrFar(Label l)
+ private void BrFar(Label l)
{
_ilg.Emit(OpCodes.Br, l);
}
@@ -527,7 +524,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Ble) (long form)
*/
- internal void BleFar(Label l)
+ private void BleFar(Label l)
{
_ilg.Emit(OpCodes.Ble, l);
}
@@ -535,7 +532,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Blt) (long form)
*/
- internal void BltFar(Label l)
+ private void BltFar(Label l)
{
_ilg.Emit(OpCodes.Blt, l);
}
@@ -543,7 +540,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Bge) (long form)
*/
- internal void BgeFar(Label l)
+ private void BgeFar(Label l)
{
_ilg.Emit(OpCodes.Bge, l);
}
@@ -551,7 +548,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Bgt) (long form)
*/
- internal void BgtFar(Label l)
+ private void BgtFar(Label l)
{
_ilg.Emit(OpCodes.Bgt, l);
}
@@ -559,7 +556,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Bne) (long form)
*/
- internal void BneFar(Label l)
+ private void BneFar(Label l)
{
_ilg.Emit(OpCodes.Bne_Un, l);
}
@@ -567,7 +564,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Beq) (long form)
*/
- internal void BeqFar(Label l)
+ private void BeqFar(Label l)
{
_ilg.Emit(OpCodes.Beq, l);
}
@@ -575,7 +572,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Brfalse_S) (short jump)
*/
- internal void Brfalse(Label l)
+ private void Brfalse(Label l)
{
_ilg.Emit(OpCodes.Brfalse_S, l);
}
@@ -583,7 +580,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Br_S) (short jump)
*/
- internal void Br(Label l)
+ private void Br(Label l)
{
_ilg.Emit(OpCodes.Br_S, l);
}
@@ -591,7 +588,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Ble_S) (short jump)
*/
- internal void Ble(Label l)
+ private void Ble(Label l)
{
_ilg.Emit(OpCodes.Ble_S, l);
}
@@ -599,7 +596,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Blt_S) (short jump)
*/
- internal void Blt(Label l)
+ private void Blt(Label l)
{
_ilg.Emit(OpCodes.Blt_S, l);
}
@@ -607,7 +604,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Bge_S) (short jump)
*/
- internal void Bge(Label l)
+ private void Bge(Label l)
{
_ilg.Emit(OpCodes.Bge_S, l);
}
@@ -615,7 +612,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Bgt_S) (short jump)
*/
- internal void Bgt(Label l)
+ private void Bgt(Label l)
{
_ilg.Emit(OpCodes.Bgt_S, l);
}
@@ -623,7 +620,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Bleun_S) (short jump)
*/
- internal void Bgtun(Label l)
+ private void Bgtun(Label l)
{
_ilg.Emit(OpCodes.Bgt_Un_S, l);
}
@@ -631,7 +628,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Bne_S) (short jump)
*/
- internal void Bne(Label l)
+ private void Bne(Label l)
{
_ilg.Emit(OpCodes.Bne_Un_S, l);
}
@@ -639,7 +636,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for _ilg.Emit(OpCodes.Beq_S) (short jump)
*/
- internal void Beq(Label l)
+ private void Beq(Label l)
{
_ilg.Emit(OpCodes.Beq_S, l);
}
@@ -647,7 +644,7 @@ namespace System.Text.RegularExpressions
/*
* A macro for the Ldlen instruction
*/
- internal void Ldlen()
+ private void Ldlen()
{
_ilg.Emit(OpCodes.Ldlen);
}
@@ -655,7 +652,7 @@ namespace System.Text.RegularExpressions
/*
* Loads the char to the right of the current position
*/
- internal void Rightchar()
+ private void Rightchar()
{
Ldloc(_textV);
Ldloc(_textposV);
@@ -665,7 +662,7 @@ namespace System.Text.RegularExpressions
/*
* Loads the char to the right of the current position and advances the current position
*/
- internal void Rightcharnext()
+ private void Rightcharnext()
{
Ldloc(_textV);
Ldloc(_textposV);
@@ -679,7 +676,7 @@ namespace System.Text.RegularExpressions
/*
* Loads the char to the left of the current position
*/
- internal void Leftchar()
+ private void Leftchar()
{
Ldloc(_textV);
Ldloc(_textposV);
@@ -691,7 +688,7 @@ namespace System.Text.RegularExpressions
/*
* Loads the char to the left of the current position and advances (leftward)
*/
- internal void Leftcharnext()
+ private void Leftcharnext()
{
Ldloc(_textV);
Ldloc(_textposV);
@@ -705,7 +702,7 @@ namespace System.Text.RegularExpressions
/*
* Creates a backtrack note and pushes the switch index it on the tracking stack
*/
- internal void Track()
+ private void Track()
{
ReadyPushTrack();
Ldc(AddTrack());
@@ -717,9 +714,8 @@ namespace System.Text.RegularExpressions
* logic will be repeated again next time we backtrack here.
*
* <
-
-*/
- internal void Trackagain()
+ */
+ private void Trackagain()
{
ReadyPushTrack();
Ldc(_backpos);
@@ -729,7 +725,7 @@ namespace System.Text.RegularExpressions
/*
* Saves the value of a local variable on the tracking stack
*/
- internal void PushTrack(LocalBuilder lt)
+ private void PushTrack(LocalBuilder lt)
{
ReadyPushTrack();
Ldloc(lt);
@@ -740,7 +736,7 @@ namespace System.Text.RegularExpressions
* Creates a backtrack note for a piece of code that should only be generated once,
* and emits code that pushes the switch index on the backtracking stack.
*/
- internal void TrackUnique(int i)
+ private void TrackUnique(int i)
{
ReadyPushTrack();
Ldc(AddUniqueTrack(i));
@@ -752,7 +748,7 @@ namespace System.Text.RegularExpressions
* generated once, and emits code that pushes the switch index on the
* backtracking stack.
*/
- internal void TrackUnique2(int i)
+ private void TrackUnique2(int i)
{
ReadyPushTrack();
Ldc(AddUniqueTrack(i, RegexCode.Back2));
@@ -762,7 +758,7 @@ namespace System.Text.RegularExpressions
/*
* Prologue to code that will push an element on the tracking stack
*/
- internal void ReadyPushTrack()
+ private void ReadyPushTrack()
{
_ilg.Emit(OpCodes.Ldloc_S, _trackV);
_ilg.Emit(OpCodes.Ldloc_S, _trackposV);
@@ -775,7 +771,7 @@ namespace System.Text.RegularExpressions
/*
* Pops an element off the tracking stack (leave it on the operand stack)
*/
- internal void PopTrack()
+ private void PopTrack()
{
_ilg.Emit(OpCodes.Ldloc_S, _trackV);
_ilg.Emit(OpCodes.Ldloc_S, _trackposV);
@@ -789,7 +785,7 @@ namespace System.Text.RegularExpressions
/*
* Retrieves the top entry on the tracking stack without popping
*/
- internal void TopTrack()
+ private void TopTrack()
{
_ilg.Emit(OpCodes.Ldloc_S, _trackV);
_ilg.Emit(OpCodes.Ldloc_S, _trackposV);
@@ -799,7 +795,7 @@ namespace System.Text.RegularExpressions
/*
* Saves the value of a local variable on the grouping stack
*/
- internal void PushStack(LocalBuilder lt)
+ private void PushStack(LocalBuilder lt)
{
ReadyPushStack();
_ilg.Emit(OpCodes.Ldloc_S, lt);
@@ -823,7 +819,7 @@ namespace System.Text.RegularExpressions
/*
* Prologue to code that will push an element on the grouping stack
*/
- internal void ReadyPushStack()
+ private void ReadyPushStack()
{
_ilg.Emit(OpCodes.Ldloc_S, _stackV);
_ilg.Emit(OpCodes.Ldloc_S, _stackposV);
@@ -836,7 +832,7 @@ namespace System.Text.RegularExpressions
/*
* Retrieves the top entry on the stack without popping
*/
- internal void TopStack()
+ private void TopStack()
{
_ilg.Emit(OpCodes.Ldloc_S, _stackV);
_ilg.Emit(OpCodes.Ldloc_S, _stackposV);
@@ -846,7 +842,7 @@ namespace System.Text.RegularExpressions
/*
* Pops an element off the grouping stack (leave it on the operand stack)
*/
- internal void PopStack()
+ private void PopStack()
{
_ilg.Emit(OpCodes.Ldloc_S, _stackV);
_ilg.Emit(OpCodes.Ldloc_S, _stackposV);
@@ -860,7 +856,7 @@ namespace System.Text.RegularExpressions
/*
* Pops 1 element off the grouping stack and discards it
*/
- internal void PopDiscardStack()
+ private void PopDiscardStack()
{
PopDiscardStack(1);
}
@@ -868,7 +864,7 @@ namespace System.Text.RegularExpressions
/*
* Pops i elements off the grouping stack and discards them
*/
- internal void PopDiscardStack(int i)
+ private void PopDiscardStack(int i)
{
_ilg.Emit(OpCodes.Ldloc_S, _stackposV);
Ldc(i);
@@ -879,7 +875,7 @@ namespace System.Text.RegularExpressions
/*
* Epilogue to code that will replace an element on a stack (use Ld* in between)
*/
- internal void DoReplace()
+ private void DoReplace()
{
_ilg.Emit(OpCodes.Stelem_I4);
}
@@ -887,7 +883,7 @@ namespace System.Text.RegularExpressions
/*
* Epilogue to code that will push an element on a stack (use Ld* in between)
*/
- internal void DoPush()
+ private void DoPush()
{
_ilg.Emit(OpCodes.Stelem_I4);
}
@@ -895,7 +891,7 @@ namespace System.Text.RegularExpressions
/*
* Jump to the backtracking switch
*/
- internal void Back()
+ private void Back()
{
_ilg.Emit(OpCodes.Br, _backtrack);
}
@@ -915,7 +911,7 @@ namespace System.Text.RegularExpressions
*
* Since forward gotos pose no threat, they just turn into a Br.
*/
- internal void Goto(int i)
+ private void Goto(int i)
{
if (i < _codepos)
{
@@ -944,7 +940,7 @@ namespace System.Text.RegularExpressions
* Returns the position of the next operation in the regex code, taking
* into account the different numbers of arguments taken by operations
*/
- internal int NextCodepos()
+ private int NextCodepos()
{
return _codepos + RegexCode.OpcodeSize(_codes[_codepos]);
}
@@ -952,7 +948,7 @@ namespace System.Text.RegularExpressions
/*
* The label for the next (forward) operation
*/
- internal Label AdvanceLabel()
+ private Label AdvanceLabel()
{
return _labels[NextCodepos()];
}
@@ -960,12 +956,12 @@ namespace System.Text.RegularExpressions
/*
* Goto the next (forward) operation
*/
- internal void Advance()
+ private void Advance()
{
_ilg.Emit(OpCodes.Br, AdvanceLabel());
}
- internal void CallToLower()
+ private void CallToLower()
{
if ((_options & RegexOptions.CultureInvariant) != 0)
Call(s_getInvariantCulture);
@@ -981,7 +977,7 @@ namespace System.Text.RegularExpressions
*
* In the absence of backtracking, this is all we would need.
*/
- internal void GenerateForwardSection()
+ private void GenerateForwardSection()
{
int codepos;
@@ -1029,7 +1025,7 @@ namespace System.Text.RegularExpressions
* and it also contains the calls that expand the tracking and the
* grouping stack when they get too full.
*/
- internal void GenerateMiddleSection()
+ private void GenerateMiddleSection()
{
Label l1 = DefineLabel();
Label[] table;
@@ -1056,14 +1052,13 @@ namespace System.Text.RegularExpressions
table[i] = _notes[i]._label;
_ilg.Emit(OpCodes.Switch, table);
-
}
/*
* Generates the last section of the MSIL. This section contains all of
* the backtracking logic.
*/
- internal void GenerateBacktrackSection()
+ private void GenerateBacktrackSection()
{
int i;
@@ -1088,7 +1083,7 @@ namespace System.Text.RegularExpressions
// !!!! This function must be kept synchronized with FindFirstChar in !!!!
// !!!! RegexInterpreter.cs !!!!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- internal void GenerateFindFirstChar()
+ protected void GenerateFindFirstChar()
{
_textposV = DeclareInt();
_textV = DeclareString();
@@ -1097,7 +1092,7 @@ namespace System.Text.RegularExpressions
if (0 != (_anchors & (RegexFCD.Beginning | RegexFCD.Start | RegexFCD.EndZ | RegexFCD.End)))
{
- if (!_code._rightToLeft)
+ if (!_code.RightToLeft)
{
if (0 != (_anchors & RegexFCD.Beginning))
{
@@ -1230,7 +1225,7 @@ namespace System.Text.RegularExpressions
Ldc(1);
Ret();
}
- else if (_bmPrefix != null && _bmPrefix._negativeUnicode == null)
+ else if (_bmPrefix != null && _bmPrefix.NegativeUnicode == null)
{
// Compiled Boyer-Moore string matching
// <
@@ -1253,35 +1248,35 @@ namespace System.Text.RegularExpressions
int last;
Label[] table;
- if (!_code._rightToLeft)
+ if (!_code.RightToLeft)
{
beforefirst = -1;
- last = _bmPrefix._pattern.Length - 1;
+ last = _bmPrefix.Pattern.Length - 1;
}
else
{
- beforefirst = _bmPrefix._pattern.Length;
+ beforefirst = _bmPrefix.Pattern.Length;
last = 0;
}
- chLast = _bmPrefix._pattern[last];
+ chLast = _bmPrefix.Pattern[last];
Mvfldloc(s_textF, _textV);
- if (!_code._rightToLeft)
+ if (!_code.RightToLeft)
Ldthisfld(s_textendF);
else
Ldthisfld(s_textbegF);
Stloc(limitV);
Ldthisfld(s_textposF);
- if (!_code._rightToLeft)
+ if (!_code.RightToLeft)
{
- Ldc(_bmPrefix._pattern.Length - 1);
+ Ldc(_bmPrefix.Pattern.Length - 1);
Add();
}
else
{
- Ldc(_bmPrefix._pattern.Length);
+ Ldc(_bmPrefix.Pattern.Length);
Sub();
}
Stloc(_textposV);
@@ -1289,10 +1284,10 @@ namespace System.Text.RegularExpressions
MarkLabel(lDefaultAdvance);
- if (!_code._rightToLeft)
- Ldc(_bmPrefix._pattern.Length);
+ if (!_code.RightToLeft)
+ Ldc(_bmPrefix.Pattern.Length);
else
- Ldc(-_bmPrefix._pattern.Length);
+ Ldc(-_bmPrefix.Pattern.Length);
MarkLabel(lAdvance);
@@ -1304,13 +1299,13 @@ namespace System.Text.RegularExpressions
Ldloc(_textposV);
Ldloc(limitV);
- if (!_code._rightToLeft)
+ if (!_code.RightToLeft)
BgeFar(lFail);
else
BltFar(lFail);
Rightchar();
- if (_bmPrefix._caseInsensitive)
+ if (_bmPrefix.CaseInsensitive)
CallToLower();
Dup();
@@ -1319,34 +1314,34 @@ namespace System.Text.RegularExpressions
BeqFar(lPartialMatch);
Ldloc(chV);
- Ldc(_bmPrefix._lowASCII);
+ Ldc(_bmPrefix.LowASCII);
Sub();
Dup();
Stloc(chV);
- Ldc(_bmPrefix._highASCII - _bmPrefix._lowASCII);
+ Ldc(_bmPrefix.HighASCII - _bmPrefix.LowASCII);
Bgtun(lDefaultAdvance);
- table = new Label[_bmPrefix._highASCII - _bmPrefix._lowASCII + 1];
+ table = new Label[_bmPrefix.HighASCII - _bmPrefix.LowASCII + 1];
- for (i = _bmPrefix._lowASCII; i <= _bmPrefix._highASCII; i++)
+ for (i = _bmPrefix.LowASCII; i <= _bmPrefix.HighASCII; i++)
{
- if (_bmPrefix._negativeASCII[i] == beforefirst)
- table[i - _bmPrefix._lowASCII] = lDefaultAdvance;
+ if (_bmPrefix.NegativeASCII[i] == beforefirst)
+ table[i - _bmPrefix.LowASCII] = lDefaultAdvance;
else
- table[i - _bmPrefix._lowASCII] = DefineLabel();
+ table[i - _bmPrefix.LowASCII] = DefineLabel();
}
Ldloc(chV);
_ilg.Emit(OpCodes.Switch, table);
- for (i = _bmPrefix._lowASCII; i <= _bmPrefix._highASCII; i++)
+ for (i = _bmPrefix.LowASCII; i <= _bmPrefix.HighASCII; i++)
{
- if (_bmPrefix._negativeASCII[i] == beforefirst)
+ if (_bmPrefix.NegativeASCII[i] == beforefirst)
continue;
- MarkLabel(table[i - _bmPrefix._lowASCII]);
+ MarkLabel(table[i - _bmPrefix.LowASCII]);
- Ldc(_bmPrefix._negativeASCII[i]);
+ Ldc(_bmPrefix.NegativeASCII[i]);
BrFar(lAdvance);
}
@@ -1355,29 +1350,29 @@ namespace System.Text.RegularExpressions
Ldloc(_textposV);
Stloc(testV);
- for (i = _bmPrefix._pattern.Length - 2; i >= 0; i--)
+ for (i = _bmPrefix.Pattern.Length - 2; i >= 0; i--)
{
Label lNext = DefineLabel();
int charindex;
- if (!_code._rightToLeft)
+ if (!_code.RightToLeft)
charindex = i;
else
- charindex = _bmPrefix._pattern.Length - 1 - i;
+ charindex = _bmPrefix.Pattern.Length - 1 - i;
Ldloc(_textV);
Ldloc(testV);
Ldc(1);
- Sub(_code._rightToLeft);
+ Sub(_code.RightToLeft);
Dup();
Stloc(testV);
Callvirt(s_getcharM);
- if (_bmPrefix._caseInsensitive)
+ if (_bmPrefix.CaseInsensitive)
CallToLower();
- Ldc(_bmPrefix._pattern[charindex]);
+ Ldc(_bmPrefix.Pattern[charindex]);
Beq(lNext);
- Ldc(_bmPrefix._positive[charindex]);
+ Ldc(_bmPrefix.Positive[charindex]);
BrFar(lAdvance);
MarkLabel(lNext);
@@ -1386,7 +1381,7 @@ namespace System.Text.RegularExpressions
Ldthis();
Ldloc(testV);
- if (_code._rightToLeft)
+ if (_code.RightToLeft)
{
Ldc(1);
Add();
@@ -1398,7 +1393,7 @@ namespace System.Text.RegularExpressions
MarkLabel(lFail);
Ldthis();
- if (!_code._rightToLeft)
+ if (!_code.RightToLeft)
Ldthisfld(s_textendF);
else
Ldthisfld(s_textbegF);
@@ -1406,7 +1401,7 @@ namespace System.Text.RegularExpressions
Ldc(0);
Ret();
}
- else if (_fcPrefix == null)
+ else if (!_fcPrefix.HasValue)
{
Ldc(1);
Ret();
@@ -1424,7 +1419,7 @@ namespace System.Text.RegularExpressions
Mvfldloc(s_textposF, _textposV);
Mvfldloc(s_textF, _textV);
- if (!_code._rightToLeft)
+ if (!_code.RightToLeft)
{
Ldthisfld(s_textendF);
Ldloc(_textposV);
@@ -1448,24 +1443,24 @@ namespace System.Text.RegularExpressions
Sub();
Stloc(cV);
- if (_code._rightToLeft)
+ if (_code.RightToLeft)
Leftcharnext();
else
Rightcharnext();
- if (_fcPrefix.CaseInsensitive)
+ if (_fcPrefix.GetValueOrDefault().CaseInsensitive)
CallToLower();
- if (!RegexCharClass.IsSingleton(_fcPrefix.Prefix))
+ if (!RegexCharClass.IsSingleton(_fcPrefix.GetValueOrDefault().Prefix))
{
- Ldstr(_fcPrefix.Prefix);
+ Ldstr(_fcPrefix.GetValueOrDefault().Prefix);
Call(s_charInSetM);
BrtrueFar(l2);
}
else
{
- Ldc(RegexCharClass.SingletonChar(_fcPrefix.Prefix));
+ Ldc(RegexCharClass.SingletonChar(_fcPrefix.GetValueOrDefault().Prefix));
Beq(l2);
}
@@ -1473,7 +1468,7 @@ namespace System.Text.RegularExpressions
Ldloc(cV);
Ldc(0);
- if (!RegexCharClass.IsSingleton(_fcPrefix.Prefix))
+ if (!RegexCharClass.IsSingleton(_fcPrefix.GetValueOrDefault().Prefix))
BgtFar(l1);
else
Bgt(l1);
@@ -1522,7 +1517,7 @@ namespace System.Text.RegularExpressions
Ldloc(_textposV);
Ldc(1);
- Sub(_code._rightToLeft);
+ Sub(_code.RightToLeft);
Stloc(_textposV);
Ldc(1);
@@ -1541,7 +1536,7 @@ namespace System.Text.RegularExpressions
/*
* Generates a very simple method that sets the _trackcount field.
*/
- internal void GenerateInitTrackCount()
+ protected void GenerateInitTrackCount()
{
Ldthis();
Ldc(_trackcount);
@@ -1552,7 +1547,7 @@ namespace System.Text.RegularExpressions
/*
* Declares a local int
*/
- internal LocalBuilder DeclareInt()
+ private LocalBuilder DeclareInt()
{
return _ilg.DeclareLocal(typeof(int));
}
@@ -1560,7 +1555,7 @@ namespace System.Text.RegularExpressions
/*
* Declares a local int array
*/
- internal LocalBuilder DeclareIntArray()
+ private LocalBuilder DeclareIntArray()
{
return _ilg.DeclareLocal(typeof(int[]));
}
@@ -1568,7 +1563,7 @@ namespace System.Text.RegularExpressions
/*
* Declares a local string
*/
- internal LocalBuilder DeclareString()
+ private LocalBuilder DeclareString()
{
return _ilg.DeclareLocal(typeof(string));
}
@@ -1576,7 +1571,7 @@ namespace System.Text.RegularExpressions
/*
* Generates the code for "RegexRunner.Go"
*/
- internal void GenerateGo()
+ protected void GenerateGo()
{
// declare some locals
@@ -1614,12 +1609,12 @@ namespace System.Text.RegularExpressions
/*
* Some simple debugging stuff
*/
- internal static MethodInfo s_debugWriteLine = typeof(Debug).GetMethod("WriteLine", new Type[] {typeof(string)});
+ private static MethodInfo s_debugWriteLine = typeof(Debug).GetMethod("WriteLine", new Type[] {typeof(string)});
/*
* Debug only: emit code to print out a message
*/
- internal void Message(string str) {
+ private void Message(string str) {
Ldstr(str);
Call(s_debugWriteLine);
}
@@ -1638,7 +1633,7 @@ namespace System.Text.RegularExpressions
* dealt with one-at-a-time in RegexIntepreter. We can also unroll loops that
* iterate over constant strings or sets.
*/
- internal void GenerateOneCode()
+ private void GenerateOneCode()
{
#if DEBUG
if ((_options & RegexOptions.Debug) != 0) {
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexFCD.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexFCD.cs
index a116994dd5..a9c30fa650 100644
--- a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexFCD.cs
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexFCD.cs
@@ -11,65 +11,77 @@
// This step is as simple as walking the tree and emitting
// sequences of codes.
+using System.Collections.Generic;
using System.Globalization;
namespace System.Text.RegularExpressions
{
- internal sealed class RegexFCD
+ internal ref struct RegexFCD
{
- private int[] _intStack;
- private int _intDepth;
- private RegexFC[] _fcStack;
- private int _fcDepth;
- private bool _skipAllChildren; // don't process any more children at the current level
- private bool _skipchild; // don't process the current child.
- private bool _failed = false;
-
+ private const int StackBufferSize = 32;
private const int BeforeChild = 64;
private const int AfterChild = 128;
// where the regex can be pegged
- internal const int Beginning = 0x0001;
- internal const int Bol = 0x0002;
- internal const int Start = 0x0004;
- internal const int Eol = 0x0008;
- internal const int EndZ = 0x0010;
- internal const int End = 0x0020;
- internal const int Boundary = 0x0040;
- internal const int ECMABoundary = 0x0080;
-
- /*
- * This is the one of the only two functions that should be called from outside.
- * It takes a RegexTree and computes the set of chars that can start it.
- */
- internal static RegexPrefix FirstChars(RegexTree t)
+ public const int Beginning = 0x0001;
+ public const int Bol = 0x0002;
+ public const int Start = 0x0004;
+ public const int Eol = 0x0008;
+ public const int EndZ = 0x0010;
+ public const int End = 0x0020;
+ public const int Boundary = 0x0040;
+ public const int ECMABoundary = 0x0080;
+
+ private readonly List<RegexFC> _fcStack;
+ private ValueListBuilder<int> _intStack; // must not be readonly
+ private bool _skipAllChildren; // don't process any more children at the current level
+ private bool _skipchild; // don't process the current child.
+ private bool _failed;
+
+ private RegexFCD(Span<int> intStack)
+ {
+ _fcStack = new List<RegexFC>(StackBufferSize);
+ _intStack = new ValueListBuilder<int>(intStack);
+ _failed = false;
+ _skipchild = false;
+ _skipAllChildren = false;
+ }
+
+ /// <summary>
+ /// This is the one of the only two functions that should be called from outside.
+ /// It takes a RegexTree and computes the set of chars that can start it.
+ /// </summary>
+ public static RegexPrefix? FirstChars(RegexTree t)
{
- RegexFCD s = new RegexFCD();
+ // Create/rent buffers
+ Span<int> intSpan = stackalloc int[StackBufferSize];
+
+ RegexFCD s = new RegexFCD(intSpan);
RegexFC fc = s.RegexFCFromRegexTree(t);
+ s.Dispose();
if (fc == null || fc._nullable)
return null;
- CultureInfo culture = ((t._options & RegexOptions.CultureInvariant) != 0) ? CultureInfo.InvariantCulture : CultureInfo.CurrentCulture;
- return new RegexPrefix(fc.GetFirstChars(culture), fc.IsCaseInsensitive());
+ CultureInfo culture = ((t.Options & RegexOptions.CultureInvariant) != 0) ? CultureInfo.InvariantCulture : CultureInfo.CurrentCulture;
+
+ return new RegexPrefix(fc.GetFirstChars(culture), fc.CaseInsensitive);
}
- /*
- * This is a related computation: it takes a RegexTree and computes the
- * leading substring if it see one. It's quite trivial and gives up easily.
- */
- internal static RegexPrefix Prefix(RegexTree tree)
+ /// <summary>
+ /// This is a related computation: it takes a RegexTree and computes the
+ /// leading substring if it see one. It's quite trivial and gives up easily.
+ /// </summary>
+ public static RegexPrefix Prefix(RegexTree tree)
{
- RegexNode curNode;
+ RegexNode curNode = tree.Root;
RegexNode concatNode = null;
int nextChild = 0;
- curNode = tree._root;
-
for (; ;)
{
- switch (curNode._type)
+ switch (curNode.NType)
{
case RegexNode.Concatenate:
if (curNode.ChildCount() > 0)
@@ -87,19 +99,29 @@ namespace System.Text.RegularExpressions
case RegexNode.Oneloop:
case RegexNode.Onelazy:
- if (curNode._m > 0)
+
+ // In release, cutoff at a length to which we can still reasonably construct a string
+ // In debug, use a smaller cutoff to exercise the cutoff path in tests
+ const int Cutoff =
+ #if DEBUG
+ 50;
+ #else
+ 1_000_000;
+ #endif
+
+ if (curNode.M > 0 && curNode.M < Cutoff)
{
- string pref = string.Empty.PadRight(curNode._m, curNode._ch);
- return new RegexPrefix(pref, 0 != (curNode._options & RegexOptions.IgnoreCase));
+ string pref = string.Empty.PadRight(curNode.M, curNode.Ch);
+ return new RegexPrefix(pref, 0 != (curNode.Options & RegexOptions.IgnoreCase));
}
else
return RegexPrefix.Empty;
case RegexNode.One:
- return new RegexPrefix(curNode._ch.ToString(), 0 != (curNode._options & RegexOptions.IgnoreCase));
+ return new RegexPrefix(curNode.Ch.ToString(), 0 != (curNode.Options & RegexOptions.IgnoreCase));
case RegexNode.Multi:
- return new RegexPrefix(curNode._str, 0 != (curNode._options & RegexOptions.IgnoreCase));
+ return new RegexPrefix(curNode.Str, 0 != (curNode.Options & RegexOptions.IgnoreCase));
case RegexNode.Bol:
case RegexNode.Eol:
@@ -125,22 +147,22 @@ namespace System.Text.RegularExpressions
}
}
- /*
- * Yet another related computation: it takes a RegexTree and computes the
- * leading anchors that it encounters.
- */
- internal static int Anchors(RegexTree tree)
+ /// <summary>
+ /// Yet another related computation: it takes a RegexTree and computes
+ /// the leading anchors that it encounters.
+ /// </summary>
+ public static int Anchors(RegexTree tree)
{
RegexNode curNode;
RegexNode concatNode = null;
int nextChild = 0;
int result = 0;
- curNode = tree._root;
+ curNode = tree.Root;
for (; ;)
{
- switch (curNode._type)
+ switch (curNode.NType)
{
case RegexNode.Concatenate:
if (curNode.ChildCount() > 0)
@@ -164,7 +186,7 @@ namespace System.Text.RegularExpressions
case RegexNode.Start:
case RegexNode.EndZ:
case RegexNode.End:
- return result | AnchorFromType(curNode._type);
+ return result | AnchorFromType(curNode.NType);
case RegexNode.Empty:
case RegexNode.Require:
@@ -182,9 +204,9 @@ namespace System.Text.RegularExpressions
}
}
- /*
- * Convert anchor type to anchor bit.
- */
+ /// <summary>
+ /// Convert anchor type to anchor bit.
+ /// </summary>
private static int AnchorFromType(int type)
{
switch (type)
@@ -202,18 +224,26 @@ namespace System.Text.RegularExpressions
}
#if DEBUG
- internal static string AnchorDescription(int anchors)
+ public static string AnchorDescription(int anchors)
{
StringBuilder sb = new StringBuilder();
- if (0 != (anchors & Beginning)) sb.Append(", Beginning");
- if (0 != (anchors & Start)) sb.Append(", Start");
- if (0 != (anchors & Bol)) sb.Append(", Bol");
- if (0 != (anchors & Boundary)) sb.Append(", Boundary");
- if (0 != (anchors & ECMABoundary)) sb.Append(", ECMABoundary");
- if (0 != (anchors & Eol)) sb.Append(", Eol");
- if (0 != (anchors & End)) sb.Append(", End");
- if (0 != (anchors & EndZ)) sb.Append(", EndZ");
+ if (0 != (anchors & Beginning))
+ sb.Append(", Beginning");
+ if (0 != (anchors & Start))
+ sb.Append(", Start");
+ if (0 != (anchors & Bol))
+ sb.Append(", Bol");
+ if (0 != (anchors & Boundary))
+ sb.Append(", Boundary");
+ if (0 != (anchors & ECMABoundary))
+ sb.Append(", ECMABoundary");
+ if (0 != (anchors & Eol))
+ sb.Append(", Eol");
+ if (0 != (anchors & End))
+ sb.Append(", End");
+ if (0 != (anchors & EndZ))
+ sb.Append(", EndZ");
if (sb.Length >= 2)
return (sb.ToString(2, sb.Length - 2));
@@ -222,118 +252,83 @@ namespace System.Text.RegularExpressions
}
#endif
- /*
- * private constructor; can't be created outside
- */
- private RegexFCD()
+ /// <summary>
+ /// To avoid recursion, we use a simple integer stack.
+ /// </summary>
+ private void PushInt(int i)
{
- _fcStack = new RegexFC[32];
- _intStack = new int[32];
+ _intStack.Append(i);
}
- /*
- * To avoid recursion, we use a simple integer stack.
- * This is the push.
- */
- private void PushInt(int I)
- {
- if (_intDepth >= _intStack.Length)
- {
- int[] expanded = new int[_intDepth * 2];
-
- Array.Copy(_intStack, 0, expanded, 0, _intDepth);
-
- _intStack = expanded;
- }
-
- _intStack[_intDepth++] = I;
- }
-
- /*
- * True if the stack is empty.
- */
private bool IntIsEmpty()
{
- return _intDepth == 0;
+ return _intStack.Length == 0;
}
- /*
- * This is the pop.
- */
private int PopInt()
{
- return _intStack[--_intDepth];
+ return _intStack.Pop();
}
- /*
- * We also use a stack of RegexFC objects.
- * This is the push.
- */
+ /// <summary>
+ /// We also use a stack of RegexFC objects.
+ /// </summary>
private void PushFC(RegexFC fc)
{
- if (_fcDepth >= _fcStack.Length)
- {
- RegexFC[] expanded = new RegexFC[_fcDepth * 2];
-
- Array.Copy(_fcStack, 0, expanded, 0, _fcDepth);
- _fcStack = expanded;
- }
-
- _fcStack[_fcDepth++] = fc;
+ _fcStack.Add(fc);
}
- /*
- * True if the stack is empty.
- */
private bool FCIsEmpty()
{
- return _fcDepth == 0;
+ return _fcStack.Count == 0;
}
- /*
- * This is the pop.
- */
private RegexFC PopFC()
{
- return _fcStack[--_fcDepth];
+ RegexFC item = TopFC();
+ _fcStack.RemoveAt(_fcStack.Count - 1);
+
+ return item;
}
- /*
- * This is the top.
- */
private RegexFC TopFC()
{
- return _fcStack[_fcDepth - 1];
+ return _fcStack[_fcStack.Count - 1];
}
- /*
- * The main FC computation. It does a shortcutted depth-first walk
- * through the tree and calls CalculateFC to emits code before
- * and after each child of an interior node, and at each leaf.
- */
- private RegexFC RegexFCFromRegexTree(RegexTree tree)
+ /// <summary>
+ /// Return rented buffers.
+ /// </summary>
+ public void Dispose()
{
- RegexNode curNode;
- int curChild;
+ _intStack.Dispose();
+ }
- curNode = tree._root;
- curChild = 0;
+ /// <summary>
+ /// The main FC computation. It does a shortcutted depth-first walk
+ /// through the tree and calls CalculateFC to emits code before
+ /// and after each child of an interior node, and at each leaf.
+ /// </summary>
+ private RegexFC RegexFCFromRegexTree(RegexTree tree)
+ {
+ RegexNode curNode = tree.Root;
+ int curChild = 0;
for (; ;)
{
- if (curNode._children == null)
+ if (curNode.Children == null)
{
// This is a leaf node
- CalculateFC(curNode._type, curNode, 0);
+ CalculateFC(curNode.NType, curNode, 0);
}
- else if (curChild < curNode._children.Count && !_skipAllChildren)
+ else if (curChild < curNode.Children.Count && !_skipAllChildren)
{
// This is an interior node, and we have more children to analyze
- CalculateFC(curNode._type | BeforeChild, curNode, curChild);
+ CalculateFC(curNode.NType | BeforeChild, curNode, curChild);
if (!_skipchild)
{
- curNode = curNode._children[curChild];
+ curNode = curNode.Children[curChild];
// this stack is how we get a depth first walk of the tree.
PushInt(curChild);
curChild = 0;
@@ -354,9 +349,9 @@ namespace System.Text.RegularExpressions
break;
curChild = PopInt();
- curNode = curNode._next;
+ curNode = curNode.Next;
- CalculateFC(curNode._type | AfterChild, curNode, curChild);
+ CalculateFC(curNode.NType | AfterChild, curNode, curChild);
if (_failed)
return null;
@@ -369,17 +364,17 @@ namespace System.Text.RegularExpressions
return PopFC();
}
- /*
- * Called in Beforechild to prevent further processing of the current child
- */
+ /// <summary>
+ /// Called in Beforechild to prevent further processing of the current child
+ /// </summary>
private void SkipChild()
{
_skipchild = true;
}
- /*
- * FC computation and shortcut cases for each node type
- */
+ /// <summary>
+ /// FC computation and shortcut cases for each node type
+ /// </summary>
private void CalculateFC(int NodeType, RegexNode node, int CurIndex)
{
bool ci = false;
@@ -387,9 +382,9 @@ namespace System.Text.RegularExpressions
if (NodeType <= RegexNode.Ref)
{
- if ((node._options & RegexOptions.IgnoreCase) != 0)
+ if ((node.Options & RegexOptions.IgnoreCase) != 0)
ci = true;
- if ((node._options & RegexOptions.RightToLeft) != 0)
+ if ((node.Options & RegexOptions.RightToLeft) != 0)
rtl = true;
}
@@ -447,7 +442,7 @@ namespace System.Text.RegularExpressions
case RegexNode.Loop | AfterChild:
case RegexNode.Lazyloop | AfterChild:
- if (node._m == 0)
+ if (node.M == 0)
TopFC()._nullable = true;
break;
@@ -471,35 +466,35 @@ namespace System.Text.RegularExpressions
case RegexNode.One:
case RegexNode.Notone:
- PushFC(new RegexFC(node._ch, NodeType == RegexNode.Notone, false, ci));
+ PushFC(new RegexFC(node.Ch, NodeType == RegexNode.Notone, false, ci));
break;
case RegexNode.Oneloop:
case RegexNode.Onelazy:
- PushFC(new RegexFC(node._ch, false, node._m == 0, ci));
+ PushFC(new RegexFC(node.Ch, false, node.M == 0, ci));
break;
case RegexNode.Notoneloop:
case RegexNode.Notonelazy:
- PushFC(new RegexFC(node._ch, true, node._m == 0, ci));
+ PushFC(new RegexFC(node.Ch, true, node.M == 0, ci));
break;
case RegexNode.Multi:
- if (node._str.Length == 0)
+ if (node.Str.Length == 0)
PushFC(new RegexFC(true));
else if (!rtl)
- PushFC(new RegexFC(node._str[0], false, false, ci));
+ PushFC(new RegexFC(node.Str[0], false, false, ci));
else
- PushFC(new RegexFC(node._str[node._str.Length - 1], false, false, ci));
+ PushFC(new RegexFC(node.Str[node.Str.Length - 1], false, false, ci));
break;
case RegexNode.Set:
- PushFC(new RegexFC(node._str, false, ci));
+ PushFC(new RegexFC(node.Str, false, ci));
break;
case RegexNode.Setloop:
case RegexNode.Setlazy:
- PushFC(new RegexFC(node._str, node._m == 0, ci));
+ PushFC(new RegexFC(node.Str, node.M == 0, ci));
break;
case RegexNode.Ref:
@@ -528,17 +523,16 @@ namespace System.Text.RegularExpressions
internal sealed class RegexFC
{
- internal RegexCharClass _cc;
- internal bool _nullable;
- internal bool _caseInsensitive;
+ private RegexCharClass _cc;
+ public bool _nullable;
- internal RegexFC(bool nullable)
+ public RegexFC(bool nullable)
{
_cc = new RegexCharClass();
_nullable = nullable;
}
- internal RegexFC(char ch, bool not, bool nullable, bool caseInsensitive)
+ public RegexFC(char ch, bool not, bool nullable, bool caseInsensitive)
{
_cc = new RegexCharClass();
@@ -554,19 +548,19 @@ namespace System.Text.RegularExpressions
_cc.AddRange(ch, ch);
}
- _caseInsensitive = caseInsensitive;
+ CaseInsensitive = caseInsensitive;
_nullable = nullable;
}
- internal RegexFC(string charClass, bool nullable, bool caseInsensitive)
+ public RegexFC(string charClass, bool nullable, bool caseInsensitive)
{
_cc = RegexCharClass.Parse(charClass);
_nullable = nullable;
- _caseInsensitive = caseInsensitive;
+ CaseInsensitive = caseInsensitive;
}
- internal bool AddFC(RegexFC fc, bool concatenate)
+ public bool AddFC(RegexFC fc, bool concatenate)
{
if (!_cc.CanMerge || !fc._cc.CanMerge)
{
@@ -587,59 +581,19 @@ namespace System.Text.RegularExpressions
_nullable = true;
}
- _caseInsensitive |= fc._caseInsensitive;
+ CaseInsensitive |= fc.CaseInsensitive;
_cc.AddCharClass(fc._cc);
return true;
}
- internal String GetFirstChars(CultureInfo culture)
+ public bool CaseInsensitive { get; private set; }
+
+ public string GetFirstChars(CultureInfo culture)
{
- if (_caseInsensitive)
+ if (CaseInsensitive)
_cc.AddLowercase(culture);
return _cc.ToStringClass();
}
-
- internal bool IsCaseInsensitive()
- {
- return _caseInsensitive;
- }
- }
-
- internal sealed class RegexPrefix
- {
- internal string _prefix;
- internal bool _caseInsensitive;
-
- internal static RegexPrefix _empty = new RegexPrefix(string.Empty, false);
-
- internal RegexPrefix(string prefix, bool ci)
- {
- _prefix = prefix;
- _caseInsensitive = ci;
- }
-
- internal string Prefix
- {
- get
- {
- return _prefix;
- }
- }
-
- internal bool CaseInsensitive
- {
- get
- {
- return _caseInsensitive;
- }
- }
- internal static RegexPrefix Empty
- {
- get
- {
- return _empty;
- }
- }
}
}
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexInterpreter.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexInterpreter.cs
index 4a1f0d8814..9170757392 100644
--- a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexInterpreter.cs
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexInterpreter.cs
@@ -2,9 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-// This RegexInterpreter class is internal to the RegularExpression package.
-// It executes a block of regular expression codes while consuming
-// input.
+// The RegexInterpreter executes a block of regular expression codes
+// while consuming input.
using System.Diagnostics;
using System.Globalization;
@@ -20,7 +19,7 @@ namespace System.Text.RegularExpressions
private bool _rightToLeft;
private bool _caseInsensitive;
- internal RegexInterpreter(RegexCode code, CultureInfo culture)
+ public RegexInterpreter(RegexCode code, CultureInfo culture)
{
Debug.Assert(code != null, "code cannot be null.");
Debug.Assert(culture != null, "culture cannot be null.");
@@ -31,13 +30,13 @@ namespace System.Text.RegularExpressions
protected override void InitTrackCount()
{
- runtrackcount = _code._trackcount;
+ runtrackcount = _code.TrackCount;
}
private void Advance(int i)
{
_codepos += (i + 1);
- SetOperator(_code._codes[_codepos]);
+ SetOperator(_code.Codes[_codepos]);
}
private void Goto(int newpos)
@@ -46,7 +45,7 @@ namespace System.Text.RegularExpressions
if (newpos < _codepos)
EnsureStorage();
- SetOperator(_code._codes[newpos]);
+ SetOperator(_code.Codes[newpos]);
_codepos = newpos;
}
@@ -131,11 +130,11 @@ namespace System.Text.RegularExpressions
if (newpos < 0)
{
newpos = -newpos;
- SetOperator(_code._codes[newpos] | RegexCode.Back2);
+ SetOperator(_code.Codes[newpos] | RegexCode.Back2);
}
else
{
- SetOperator(_code._codes[newpos] | RegexCode.Back);
+ SetOperator(_code.Codes[newpos] | RegexCode.Back);
}
// When branching backward, ensure storage
@@ -223,7 +222,7 @@ namespace System.Text.RegularExpressions
private int Operand(int i)
{
- return _code._codes[_codepos + i + 1];
+ return _code.Codes[_codepos + i + 1];
}
private int Leftchars()
@@ -355,77 +354,74 @@ namespace System.Text.RegularExpressions
protected override bool FindFirstChar()
{
- int i;
- string set;
-
- if (0 != (_code._anchors & (RegexFCD.Beginning | RegexFCD.Start | RegexFCD.EndZ | RegexFCD.End)))
+ if (0 != (_code.Anchors & (RegexFCD.Beginning | RegexFCD.Start | RegexFCD.EndZ | RegexFCD.End)))
{
- if (!_code._rightToLeft)
+ if (!_code.RightToLeft)
{
- if ((0 != (_code._anchors & RegexFCD.Beginning) && runtextpos > runtextbeg) ||
- (0 != (_code._anchors & RegexFCD.Start) && runtextpos > runtextstart))
+ if ((0 != (_code.Anchors & RegexFCD.Beginning) && runtextpos > runtextbeg) ||
+ (0 != (_code.Anchors & RegexFCD.Start) && runtextpos > runtextstart))
{
runtextpos = runtextend;
return false;
}
- if (0 != (_code._anchors & RegexFCD.EndZ) && runtextpos < runtextend - 1)
+ if (0 != (_code.Anchors & RegexFCD.EndZ) && runtextpos < runtextend - 1)
{
runtextpos = runtextend - 1;
}
- else if (0 != (_code._anchors & RegexFCD.End) && runtextpos < runtextend)
+ else if (0 != (_code.Anchors & RegexFCD.End) && runtextpos < runtextend)
{
runtextpos = runtextend;
}
}
else
{
- if ((0 != (_code._anchors & RegexFCD.End) && runtextpos < runtextend) ||
- (0 != (_code._anchors & RegexFCD.EndZ) && (runtextpos < runtextend - 1 ||
+ if ((0 != (_code.Anchors & RegexFCD.End) && runtextpos < runtextend) ||
+ (0 != (_code.Anchors & RegexFCD.EndZ) && (runtextpos < runtextend - 1 ||
(runtextpos == runtextend - 1 && CharAt(runtextpos) != '\n'))) ||
- (0 != (_code._anchors & RegexFCD.Start) && runtextpos < runtextstart))
+ (0 != (_code.Anchors & RegexFCD.Start) && runtextpos < runtextstart))
{
runtextpos = runtextbeg;
return false;
}
- if (0 != (_code._anchors & RegexFCD.Beginning) && runtextpos > runtextbeg)
+ if (0 != (_code.Anchors & RegexFCD.Beginning) && runtextpos > runtextbeg)
{
runtextpos = runtextbeg;
}
}
- if (_code._bmPrefix != null)
+ if (_code.BMPrefix != null)
{
- return _code._bmPrefix.IsMatch(runtext, runtextpos, runtextbeg, runtextend);
+ return _code.BMPrefix.IsMatch(runtext, runtextpos, runtextbeg, runtextend);
}
return true; // found a valid start or end anchor
}
- else if (_code._bmPrefix != null)
+ else if (_code.BMPrefix != null)
{
- runtextpos = _code._bmPrefix.Scan(runtext, runtextpos, runtextbeg, runtextend);
+ runtextpos = _code.BMPrefix.Scan(runtext, runtextpos, runtextbeg, runtextend);
if (runtextpos == -1)
{
- runtextpos = (_code._rightToLeft ? runtextbeg : runtextend);
+ runtextpos = (_code.RightToLeft ? runtextbeg : runtextend);
return false;
}
return true;
}
- else if (_code._fcPrefix == null)
+ else if (_code.FCPrefix == null)
{
return true;
}
- _rightToLeft = _code._rightToLeft;
- _caseInsensitive = _code._fcPrefix.CaseInsensitive;
- set = _code._fcPrefix.Prefix;
+ _rightToLeft = _code.RightToLeft;
+ _caseInsensitive = _code.FCPrefix.GetValueOrDefault().CaseInsensitive;
+ string set = _code.FCPrefix.GetValueOrDefault().Prefix;
if (RegexCharClass.IsSingleton(set))
{
char ch = RegexCharClass.SingletonChar(set);
- for (i = Forwardchars(); i > 0; i--)
+ for (int i = Forwardchars(); i > 0; i--)
{
if (ch == Forwardcharnext())
{
@@ -436,7 +432,7 @@ namespace System.Text.RegularExpressions
}
else
{
- for (i = Forwardchars(); i > 0; i--)
+ for (int i = Forwardchars(); i > 0; i--)
{
if (RegexCharClass.CharInClass(Forwardcharnext(), set))
{
@@ -445,6 +441,7 @@ namespace System.Text.RegularExpressions
}
}
}
+
return false;
}
@@ -889,7 +886,7 @@ namespace System.Text.RegularExpressions
continue;
case RegexCode.Set:
- if (Forwardchars() < 1 || !RegexCharClass.CharInClass(Forwardcharnext(), _code._strings[Operand(0)]))
+ if (Forwardchars() < 1 || !RegexCharClass.CharInClass(Forwardcharnext(), _code.Strings[Operand(0)]))
break;
advance = 1;
@@ -897,7 +894,7 @@ namespace System.Text.RegularExpressions
case RegexCode.Multi:
{
- if (!Stringmatch(_code._strings[Operand(0)]))
+ if (!Stringmatch(_code.Strings[Operand(0)]))
break;
advance = 1;
@@ -964,7 +961,7 @@ namespace System.Text.RegularExpressions
if (Forwardchars() < c)
break;
- string set = _code._strings[Operand(0)];
+ string set = _code.Strings[Operand(0)];
while (c-- > 0)
if (!RegexCharClass.CharInClass(Forwardcharnext(), set))
@@ -1033,7 +1030,7 @@ namespace System.Text.RegularExpressions
if (c > Forwardchars())
c = Forwardchars();
- string set = _code._strings[Operand(0)];
+ string set = _code.Strings[Operand(0)];
int i;
for (i = c; i > 0; i--)
@@ -1154,7 +1151,7 @@ namespace System.Text.RegularExpressions
int pos = TrackPeek(1);
Textto(pos);
- if (!RegexCharClass.CharInClass(Forwardcharnext(), _code._strings[Operand(0)]))
+ if (!RegexCharClass.CharInClass(Forwardcharnext(), _code.Strings[Operand(0)]))
break;
int i = TrackPeek();
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexLWCGCompiler.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexLWCGCompiler.cs
index d37ab1a0bd..e5833b02c5 100644
--- a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexLWCGCompiler.cs
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexLWCGCompiler.cs
@@ -9,27 +9,23 @@ using System.Globalization;
namespace System.Text.RegularExpressions
{
- internal class RegexLWCGCompiler : RegexCompiler
+ internal sealed class RegexLWCGCompiler : RegexCompiler
{
private static int s_regexCount = 0;
private static Type[] s_paramTypes = new Type[] { typeof(RegexRunner) };
- internal RegexLWCGCompiler()
- {
- }
-
/*
* The top-level driver. Initializes everything then calls the Generate* methods.
*/
- internal RegexRunnerFactory FactoryInstanceFromCode(RegexCode code, RegexOptions options)
+ public RegexRunnerFactory FactoryInstanceFromCode(RegexCode code, RegexOptions options)
{
_code = code;
- _codes = code._codes;
- _strings = code._strings;
- _fcPrefix = code._fcPrefix;
- _bmPrefix = code._bmPrefix;
- _anchors = code._anchors;
- _trackcount = code._trackcount;
+ _codes = code.Codes;
+ _strings = code.Strings;
+ _fcPrefix = code.FCPrefix;
+ _bmPrefix = code.BMPrefix;
+ _anchors = code.Anchors;
+ _trackcount = code.TrackCount;
_options = options;
// pick a unique number for the methods we generate
@@ -51,7 +47,7 @@ namespace System.Text.RegularExpressions
/*
* Begins the definition of a new method (no args) with a specified return value
*/
- internal DynamicMethod DefineDynamicMethod(string methname, Type returntype, Type hostType)
+ public DynamicMethod DefineDynamicMethod(string methname, Type returntype, Type hostType)
{
// We're claiming that these are static methods, but really they are instance methods.
// By giving them a parameter which represents "this", we're tricking them into
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs
index f60e800def..339e3d7139 100644
--- a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexNode.cs
@@ -51,113 +51,108 @@ namespace System.Text.RegularExpressions
// The following are leaves, and correspond to primitive operations
- internal const int Oneloop = RegexCode.Oneloop; // c,n a*
- internal const int Notoneloop = RegexCode.Notoneloop; // c,n .*
- internal const int Setloop = RegexCode.Setloop; // set,n \d*
-
- internal const int Onelazy = RegexCode.Onelazy; // c,n a*?
- internal const int Notonelazy = RegexCode.Notonelazy; // c,n .*?
- internal const int Setlazy = RegexCode.Setlazy; // set,n \d*?
-
- internal const int One = RegexCode.One; // char a
- internal const int Notone = RegexCode.Notone; // char . [^a]
- internal const int Set = RegexCode.Set; // set [a-z] \w \s \d
-
- internal const int Multi = RegexCode.Multi; // string abcdef
- internal const int Ref = RegexCode.Ref; // index \1
-
- internal const int Bol = RegexCode.Bol; // ^
- internal const int Eol = RegexCode.Eol; // $
- internal const int Boundary = RegexCode.Boundary; // \b
- internal const int Nonboundary = RegexCode.Nonboundary; // \B
- internal const int ECMABoundary = RegexCode.ECMABoundary; // \b
- internal const int NonECMABoundary = RegexCode.NonECMABoundary; // \B
- internal const int Beginning = RegexCode.Beginning; // \A
- internal const int Start = RegexCode.Start; // \G
- internal const int EndZ = RegexCode.EndZ; // \Z
- internal const int End = RegexCode.End; // \z
+ public const int Oneloop = RegexCode.Oneloop; // c,n a*
+ public const int Notoneloop = RegexCode.Notoneloop; // c,n .*
+ public const int Setloop = RegexCode.Setloop; // set,n \d*
+
+ public const int Onelazy = RegexCode.Onelazy; // c,n a*?
+ public const int Notonelazy = RegexCode.Notonelazy; // c,n .*?
+ public const int Setlazy = RegexCode.Setlazy; // set,n \d*?
+
+ public const int One = RegexCode.One; // char a
+ public const int Notone = RegexCode.Notone; // char . [^a]
+ public const int Set = RegexCode.Set; // set [a-z] \w \s \d
+
+ public const int Multi = RegexCode.Multi; // string abcdef
+ public const int Ref = RegexCode.Ref; // index \1
+
+ public const int Bol = RegexCode.Bol; // ^
+ public const int Eol = RegexCode.Eol; // $
+ public const int Boundary = RegexCode.Boundary; // \b
+ public const int Nonboundary = RegexCode.Nonboundary; // \B
+ public const int ECMABoundary = RegexCode.ECMABoundary; // \b
+ public const int NonECMABoundary = RegexCode.NonECMABoundary; // \B
+ public const int Beginning = RegexCode.Beginning; // \A
+ public const int Start = RegexCode.Start; // \G
+ public const int EndZ = RegexCode.EndZ; // \Z
+ public const int End = RegexCode.End; // \z
// Interior nodes do not correspond to primitive operations, but
// control structures compositing other operations
// Concat and alternate take n children, and can run forward or backwards
- internal const int Nothing = 22; // []
- internal const int Empty = 23; // ()
-
- internal const int Alternate = 24; // a|b
- internal const int Concatenate = 25; // ab
-
- internal const int Loop = 26; // m,x * + ? {,}
- internal const int Lazyloop = 27; // m,x *? +? ?? {,}?
-
- internal const int Capture = 28; // n ()
- internal const int Group = 29; // (?:)
- internal const int Require = 30; // (?=) (?<=)
- internal const int Prevent = 31; // (?!) (?<!)
- internal const int Greedy = 32; // (?>) (?<)
- internal const int Testref = 33; // (?(n) | )
- internal const int Testgroup = 34; // (?(...) | )
-
- // RegexNode data members
-
- internal int _type;
-
- internal List<RegexNode> _children;
-
- internal string _str;
- internal char _ch;
- internal int _m;
- internal int _n;
- internal readonly RegexOptions _options;
-
- internal RegexNode _next;
-
- internal RegexNode(int type, RegexOptions options)
+ public const int Nothing = 22; // []
+ public const int Empty = 23; // ()
+
+ public const int Alternate = 24; // a|b
+ public const int Concatenate = 25; // ab
+
+ public const int Loop = 26; // m,x * + ? {,}
+ public const int Lazyloop = 27; // m,x *? +? ?? {,}?
+
+ public const int Capture = 28; // n () - capturing group
+ public const int Group = 29; // (?:) - noncapturing group
+ public const int Require = 30; // (?=) (?<=) - lookahead and lookbehind assertions
+ public const int Prevent = 31; // (?!) (?<!) - negative lookahead and lookbehind assertions
+ public const int Greedy = 32; // (?>) - greedy subexpression
+ public const int Testref = 33; // (?(n) | ) - alternation, reference
+ public const int Testgroup = 34; // (?(...) | )- alternation, expression
+
+ public int NType;
+ public List<RegexNode> Children;
+ public string Str;
+ public char Ch;
+ public int M;
+ public int N;
+ public readonly RegexOptions Options;
+ public RegexNode Next;
+
+ public RegexNode(int type, RegexOptions options)
{
- _type = type;
- _options = options;
+ NType = type;
+ Options = options;
}
- internal RegexNode(int type, RegexOptions options, char ch)
+ public RegexNode(int type, RegexOptions options, char ch)
{
- _type = type;
- _options = options;
- _ch = ch;
+ NType = type;
+ Options = options;
+ Ch = ch;
}
- internal RegexNode(int type, RegexOptions options, string str)
+ public RegexNode(int type, RegexOptions options, string str)
{
- _type = type;
- _options = options;
- _str = str;
+ NType = type;
+ Options = options;
+ Str = str;
}
- internal RegexNode(int type, RegexOptions options, int m)
+ public RegexNode(int type, RegexOptions options, int m)
{
- _type = type;
- _options = options;
- _m = m;
+ NType = type;
+ Options = options;
+ M = m;
}
- internal RegexNode(int type, RegexOptions options, int m, int n)
+ public RegexNode(int type, RegexOptions options, int m, int n)
{
- _type = type;
- _options = options;
- _m = m;
- _n = n;
+ NType = type;
+ Options = options;
+ M = m;
+ N = n;
}
- internal bool UseOptionR()
+ public bool UseOptionR()
{
- return (_options & RegexOptions.RightToLeft) != 0;
+ return (Options & RegexOptions.RightToLeft) != 0;
}
- internal RegexNode ReverseLeft()
+ public RegexNode ReverseLeft()
{
- if (UseOptionR() && _type == Concatenate && _children != null)
+ if (UseOptionR() && NType == Concatenate && Children != null)
{
- _children.Reverse(0, _children.Count);
+ Children.Reverse(0, Children.Count);
}
return this;
@@ -166,17 +161,17 @@ namespace System.Text.RegularExpressions
/// <summary>
/// Pass type as OneLazy or OneLoop
/// </summary>
- internal void MakeRep(int type, int min, int max)
+ private void MakeRep(int type, int min, int max)
{
- _type += (type - One);
- _m = min;
- _n = max;
+ NType += (type - One);
+ M = min;
+ N = max;
}
/// <summary>
/// Removes redundant nodes from the subtree, and returns a reduced subtree.
/// </summary>
- internal RegexNode Reduce()
+ private RegexNode Reduce()
{
RegexNode n;
@@ -217,12 +212,12 @@ namespace System.Text.RegularExpressions
/// one child strip out the intermediate node. If it has zero children,
/// turn it into an empty.
/// </summary>
- internal RegexNode StripEnation(int emptyType)
+ private RegexNode StripEnation(int emptyType)
{
switch (ChildCount())
{
case 0:
- return new RegexNode(emptyType, _options);
+ return new RegexNode(emptyType, Options);
case 1:
return Child(0);
default:
@@ -234,7 +229,7 @@ namespace System.Text.RegularExpressions
/// Simple optimization. Once parsed into a tree, non-capturing groups
/// serve no function, so strip them out.
/// </summary>
- internal RegexNode ReduceGroup()
+ private RegexNode ReduceGroup()
{
RegexNode u;
@@ -248,18 +243,13 @@ namespace System.Text.RegularExpressions
/// Nested repeaters just get multiplied with each other if they're not
/// too lumpy
/// </summary>
- internal RegexNode ReduceRep()
+ private RegexNode ReduceRep()
{
- RegexNode u;
+ RegexNode u = this;
RegexNode child;
- int type;
- int min;
- int max;
-
- u = this;
- type = Type();
- min = _m;
- max = _n;
+ int type = Type();
+ int min = M;
+ int max = N;
for (; ;)
{
@@ -280,49 +270,50 @@ namespace System.Text.RegularExpressions
// child can be too lumpy to blur, e.g., (a {100,105}) {3} or (a {2,})?
// [but things like (a {2,})+ are not too lumpy...]
- if (u._m == 0 && child._m > 1 || child._n < child._m * 2)
+ if (u.M == 0 && child.M > 1 || child.N < child.M * 2)
break;
u = child;
- if (u._m > 0)
- u._m = min = ((int.MaxValue - 1) / u._m < min) ? int.MaxValue : u._m * min;
- if (u._n > 0)
- u._n = max = ((int.MaxValue - 1) / u._n < max) ? int.MaxValue : u._n * max;
+ if (u.M > 0)
+ u.M = min = ((int.MaxValue - 1) / u.M < min) ? int.MaxValue : u.M * min;
+ if (u.N > 0)
+ u.N = max = ((int.MaxValue - 1) / u.N < max) ? int.MaxValue : u.N * max;
}
- return min == int.MaxValue ? new RegexNode(Nothing, _options) : u;
+ return min == int.MaxValue ? new RegexNode(Nothing, Options) : u;
}
/// <summary>
/// Simple optimization. If a set is a singleton, an inverse singleton,
/// or empty, it's transformed accordingly.
/// </summary>
- internal RegexNode ReduceSet()
+ private RegexNode ReduceSet()
{
// Extract empty-set, one and not-one case as special
- if (RegexCharClass.IsEmpty(_str))
+ if (RegexCharClass.IsEmpty(Str))
{
- _type = Nothing;
- _str = null;
+ NType = Nothing;
+ Str = null;
}
- else if (RegexCharClass.IsSingleton(_str))
+ else if (RegexCharClass.IsSingleton(Str))
{
- _ch = RegexCharClass.SingletonChar(_str);
- _str = null;
- _type += (One - Set);
+ Ch = RegexCharClass.SingletonChar(Str);
+ Str = null;
+ NType += (One - Set);
}
- else if (RegexCharClass.IsSingletonInverse(_str))
+ else if (RegexCharClass.IsSingletonInverse(Str))
{
- _ch = RegexCharClass.SingletonChar(_str);
- _str = null;
- _type += (Notone - Set);
+ Ch = RegexCharClass.SingletonChar(Str);
+ Str = null;
+ NType += (Notone - Set);
}
return this;
}
/// <summary>
+ /// Combine adjacent sets/chars.
/// Basic optimization. Single-letter alternations can be replaced
/// by faster set specifications, and nested alternations with no
/// intervening operators can be flattened:
@@ -330,55 +321,49 @@ namespace System.Text.RegularExpressions
/// a|b|c|def|g|h -> [a-c]|def|[gh]
/// apple|(?:orange|pear)|grape -> apple|orange|pear|grape
/// </summary>
- internal RegexNode ReduceAlternation()
+ private RegexNode ReduceAlternation()
{
- // Combine adjacent sets/chars
+ if (Children == null)
+ return new RegexNode(Nothing, Options);
- bool wasLastSet;
- bool lastNodeCannotMerge;
- RegexOptions optionsLast;
+ bool wasLastSet = false;
+ bool lastNodeCannotMerge = false;
+ RegexOptions optionsLast = 0;
RegexOptions optionsAt;
int i;
int j;
RegexNode at;
RegexNode prev;
- if (_children == null)
- return new RegexNode(Nothing, _options);
-
- wasLastSet = false;
- lastNodeCannotMerge = false;
- optionsLast = 0;
-
- for (i = 0, j = 0; i < _children.Count; i++, j++)
+ for (i = 0, j = 0; i < Children.Count; i++, j++)
{
- at = _children[i];
+ at = Children[i];
if (j < i)
- _children[j] = at;
+ Children[j] = at;
for (; ;)
{
- if (at._type == Alternate)
+ if (at.NType == Alternate)
{
- for (int k = 0; k < at._children.Count; k++)
- at._children[k]._next = this;
+ for (int k = 0; k < at.Children.Count; k++)
+ at.Children[k].Next = this;
- _children.InsertRange(i + 1, at._children);
+ Children.InsertRange(i + 1, at.Children);
j--;
}
- else if (at._type == Set || at._type == One)
+ else if (at.NType == Set || at.NType == One)
{
// Cannot merge sets if L or I options differ, or if either are negated.
- optionsAt = at._options & (RegexOptions.RightToLeft | RegexOptions.IgnoreCase);
+ optionsAt = at.Options & (RegexOptions.RightToLeft | RegexOptions.IgnoreCase);
- if (at._type == Set)
+ if (at.NType == Set)
{
- if (!wasLastSet || optionsLast != optionsAt || lastNodeCannotMerge || !RegexCharClass.IsMergeable(at._str))
+ if (!wasLastSet || optionsLast != optionsAt || lastNodeCannotMerge || !RegexCharClass.IsMergeable(at.Str))
{
wasLastSet = true;
- lastNodeCannotMerge = !RegexCharClass.IsMergeable(at._str);
+ lastNodeCannotMerge = !RegexCharClass.IsMergeable(at.Str);
optionsLast = optionsAt;
break;
}
@@ -395,33 +380,33 @@ namespace System.Text.RegularExpressions
// The last node was a Set or a One, we're a Set or One and our options are the same.
// Merge the two nodes.
j--;
- prev = _children[j];
+ prev = Children[j];
RegexCharClass prevCharClass;
- if (prev._type == One)
+ if (prev.NType == One)
{
prevCharClass = new RegexCharClass();
- prevCharClass.AddChar(prev._ch);
+ prevCharClass.AddChar(prev.Ch);
}
else
{
- prevCharClass = RegexCharClass.Parse(prev._str);
+ prevCharClass = RegexCharClass.Parse(prev.Str);
}
- if (at._type == One)
+ if (at.NType == One)
{
- prevCharClass.AddChar(at._ch);
+ prevCharClass.AddChar(at.Ch);
}
else
{
- RegexCharClass atCharClass = RegexCharClass.Parse(at._str);
+ RegexCharClass atCharClass = RegexCharClass.Parse(at.Str);
prevCharClass.AddCharClass(atCharClass);
}
- prev._type = Set;
- prev._str = prevCharClass.ToStringClass();
+ prev.NType = Set;
+ prev.Str = prevCharClass.ToStringClass();
}
- else if (at._type == Nothing)
+ else if (at.NType == Nothing)
{
j--;
}
@@ -435,56 +420,52 @@ namespace System.Text.RegularExpressions
}
if (j < i)
- _children.RemoveRange(j, i - j);
+ Children.RemoveRange(j, i - j);
return StripEnation(Nothing);
}
/// <summary>
+ /// Eliminate empties and concat adjacent strings/chars.
/// Basic optimization. Adjacent strings can be concatenated.
///
/// (?:abc)(?:def) -> abcdef
/// </summary>
- internal RegexNode ReduceConcatenation()
+ private RegexNode ReduceConcatenation()
{
- // Eliminate empties and concat adjacent strings/chars
+ if (Children == null)
+ return new RegexNode(Empty, Options);
- bool wasLastString;
- RegexOptions optionsLast;
+ bool wasLastString = false;
+ RegexOptions optionsLast = 0;
RegexOptions optionsAt;
int i;
int j;
- if (_children == null)
- return new RegexNode(Empty, _options);
-
- wasLastString = false;
- optionsLast = 0;
-
- for (i = 0, j = 0; i < _children.Count; i++, j++)
+ for (i = 0, j = 0; i < Children.Count; i++, j++)
{
RegexNode at;
RegexNode prev;
- at = _children[i];
+ at = Children[i];
if (j < i)
- _children[j] = at;
+ Children[j] = at;
- if (at._type == Concatenate &&
- ((at._options & RegexOptions.RightToLeft) == (_options & RegexOptions.RightToLeft)))
+ if (at.NType == Concatenate &&
+ ((at.Options & RegexOptions.RightToLeft) == (Options & RegexOptions.RightToLeft)))
{
- for (int k = 0; k < at._children.Count; k++)
- at._children[k]._next = this;
+ for (int k = 0; k < at.Children.Count; k++)
+ at.Children[k].Next = this;
- _children.InsertRange(i + 1, at._children);
+ Children.InsertRange(i + 1, at.Children);
j--;
}
- else if (at._type == Multi ||
- at._type == One)
+ else if (at.NType == Multi ||
+ at.NType == One)
{
// Cannot merge strings if L or I options differ
- optionsAt = at._options & (RegexOptions.RightToLeft | RegexOptions.IgnoreCase);
+ optionsAt = at.Options & (RegexOptions.RightToLeft | RegexOptions.IgnoreCase);
if (!wasLastString || optionsLast != optionsAt)
{
@@ -493,30 +474,30 @@ namespace System.Text.RegularExpressions
continue;
}
- prev = _children[--j];
+ prev = Children[--j];
- if (prev._type == One)
+ if (prev.NType == One)
{
- prev._type = Multi;
- prev._str = Convert.ToString(prev._ch, CultureInfo.InvariantCulture);
+ prev.NType = Multi;
+ prev.Str = Convert.ToString(prev.Ch, CultureInfo.InvariantCulture);
}
if ((optionsAt & RegexOptions.RightToLeft) == 0)
{
- if (at._type == One)
- prev._str += at._ch.ToString();
+ if (at.NType == One)
+ prev.Str += at.Ch.ToString();
else
- prev._str += at._str;
+ prev.Str += at.Str;
}
else
{
- if (at._type == One)
- prev._str = at._ch.ToString() + prev._str;
+ if (at.NType == One)
+ prev.Str = at.Ch.ToString() + prev.Str;
else
- prev._str = at._str + prev._str;
+ prev.Str = at.Str + prev.Str;
}
}
- else if (at._type == Empty)
+ else if (at.NType == Empty)
{
j--;
}
@@ -527,66 +508,62 @@ namespace System.Text.RegularExpressions
}
if (j < i)
- _children.RemoveRange(j, i - j);
+ Children.RemoveRange(j, i - j);
return StripEnation(Empty);
}
- internal RegexNode MakeQuantifier(bool lazy, int min, int max)
+ public RegexNode MakeQuantifier(bool lazy, int min, int max)
{
- RegexNode result;
-
if (min == 0 && max == 0)
- return new RegexNode(Empty, _options);
+ return new RegexNode(Empty, Options);
if (min == 1 && max == 1)
return this;
- switch (_type)
+ switch (NType)
{
case One:
case Notone:
case Set:
-
MakeRep(lazy ? Onelazy : Oneloop, min, max);
return this;
default:
- result = new RegexNode(lazy ? Lazyloop : Loop, _options, min, max);
+ var result = new RegexNode(lazy ? Lazyloop : Loop, Options, min, max);
result.AddChild(this);
return result;
}
}
- internal void AddChild(RegexNode newChild)
+ public void AddChild(RegexNode newChild)
{
- RegexNode reducedChild;
-
- if (_children == null)
- _children = new List<RegexNode>(4);
-
- reducedChild = newChild.Reduce();
+ if (Children == null)
+ Children = new List<RegexNode>(4);
- _children.Add(reducedChild);
- reducedChild._next = this;
+ RegexNode reducedChild = newChild.Reduce();
+ Children.Add(reducedChild);
+ reducedChild.Next = this;
}
- internal RegexNode Child(int i)
+
+ public RegexNode Child(int i)
{
- return _children[i];
+ return Children[i];
}
- internal int ChildCount()
+ public int ChildCount()
{
- return _children == null ? 0 : _children.Count;
+ return Children == null ? 0 : Children.Count;
}
- internal int Type()
+ public int Type()
{
- return _type;
+ return NType;
}
#if DEBUG
- internal static readonly string[] TypeStr = new string[] {
+ private const string Space = " ";
+ private static readonly string[] s_typeStr = new string[] {
"Onerep", "Notonerep", "Setrep",
"Oneloop", "Notoneloop", "Setloop",
"Onelazy", "Notonelazy", "Setlazy",
@@ -601,28 +578,28 @@ namespace System.Text.RegularExpressions
"Capture", "Group", "Require", "Prevent", "Greedy",
"Testref", "Testgroup"};
- internal string Description()
+ private string Description()
{
StringBuilder ArgSb = new StringBuilder();
- ArgSb.Append(TypeStr[_type]);
+ ArgSb.Append(s_typeStr[NType]);
- if ((_options & RegexOptions.ExplicitCapture) != 0)
+ if ((Options & RegexOptions.ExplicitCapture) != 0)
ArgSb.Append("-C");
- if ((_options & RegexOptions.IgnoreCase) != 0)
+ if ((Options & RegexOptions.IgnoreCase) != 0)
ArgSb.Append("-I");
- if ((_options & RegexOptions.RightToLeft) != 0)
+ if ((Options & RegexOptions.RightToLeft) != 0)
ArgSb.Append("-L");
- if ((_options & RegexOptions.Multiline) != 0)
+ if ((Options & RegexOptions.Multiline) != 0)
ArgSb.Append("-M");
- if ((_options & RegexOptions.Singleline) != 0)
+ if ((Options & RegexOptions.Singleline) != 0)
ArgSb.Append("-S");
- if ((_options & RegexOptions.IgnorePatternWhitespace) != 0)
+ if ((Options & RegexOptions.IgnorePatternWhitespace) != 0)
ArgSb.Append("-X");
- if ((_options & RegexOptions.ECMAScript) != 0)
+ if ((Options & RegexOptions.ECMAScript) != 0)
ArgSb.Append("-E");
- switch (_type)
+ switch (NType)
{
case Oneloop:
case Notoneloop:
@@ -630,26 +607,26 @@ namespace System.Text.RegularExpressions
case Notonelazy:
case One:
case Notone:
- ArgSb.Append("(Ch = " + RegexCharClass.CharDescription(_ch) + ")");
+ ArgSb.Append("(Ch = " + RegexCharClass.CharDescription(Ch) + ")");
break;
case Capture:
- ArgSb.Append("(index = " + _m.ToString(CultureInfo.InvariantCulture) + ", unindex = " + _n.ToString(CultureInfo.InvariantCulture) + ")");
+ ArgSb.Append("(index = " + M.ToString(CultureInfo.InvariantCulture) + ", unindex = " + N.ToString(CultureInfo.InvariantCulture) + ")");
break;
case Ref:
case Testref:
- ArgSb.Append("(index = " + _m.ToString(CultureInfo.InvariantCulture) + ")");
+ ArgSb.Append("(index = " + M.ToString(CultureInfo.InvariantCulture) + ")");
break;
case Multi:
- ArgSb.Append("(String = " + _str + ")");
+ ArgSb.Append("(String = " + Str + ")");
break;
case Set:
case Setloop:
case Setlazy:
- ArgSb.Append("(Set = " + RegexCharClass.SetDescription(_str) + ")");
+ ArgSb.Append("(Set = " + RegexCharClass.SetDescription(Str) + ")");
break;
}
- switch (_type)
+ switch (NType)
{
case Oneloop:
case Notoneloop:
@@ -659,16 +636,14 @@ namespace System.Text.RegularExpressions
case Setlazy:
case Loop:
case Lazyloop:
- ArgSb.Append("(Min = " + _m.ToString(CultureInfo.InvariantCulture) + ", Max = " + (_n == int.MaxValue ? "inf" : Convert.ToString(_n, CultureInfo.InvariantCulture)) + ")");
+ ArgSb.Append("(Min = " + M.ToString(CultureInfo.InvariantCulture) + ", Max = " + (N == int.MaxValue ? "inf" : Convert.ToString(N, CultureInfo.InvariantCulture)) + ")");
break;
}
return ArgSb.ToString();
}
- internal const string Space = " ";
-
- internal void Dump()
+ public void Dump()
{
List<int> Stack = new List<int>();
RegexNode CurNode;
@@ -681,10 +656,10 @@ namespace System.Text.RegularExpressions
for (; ;)
{
- if (CurNode._children != null && CurChild < CurNode._children.Count)
+ if (CurNode.Children != null && CurChild < CurNode.Children.Count)
{
Stack.Add(CurChild + 1);
- CurNode = CurNode._children[CurChild];
+ CurNode = CurNode.Children[CurChild];
CurChild = 0;
int Depth = Stack.Count;
@@ -700,7 +675,7 @@ namespace System.Text.RegularExpressions
CurChild = Stack[Stack.Count - 1];
Stack.RemoveAt(Stack.Count - 1);
- CurNode = CurNode._next;
+ CurNode = CurNode.Next;
}
}
}
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexParser.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexParser.cs
index b94abe2e48..3217400c26 100644
--- a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexParser.cs
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexParser.cs
@@ -19,34 +19,34 @@ namespace System.Text.RegularExpressions
{
internal sealed class RegexParser
{
- internal RegexNode _stack;
- internal RegexNode _group;
- internal RegexNode _alternation;
- internal RegexNode _concatenation;
- internal RegexNode _unit;
+ private const int MaxValueDiv10 = int.MaxValue / 10;
+ private const int MaxValueMod10 = int.MaxValue % 10;
- internal string _pattern;
- internal int _currentPos;
- internal CultureInfo _culture;
+ private RegexNode _stack;
+ private RegexNode _group;
+ private RegexNode _alternation;
+ private RegexNode _concatenation;
+ private RegexNode _unit;
- internal int _autocap;
- internal int _capcount;
- internal int _captop;
- internal int _capsize;
+ private string _pattern;
+ private int _currentPos;
+ private CultureInfo _culture;
- internal Hashtable _caps;
- internal Hashtable _capnames;
+ private int _autocap;
+ private int _capcount;
+ private int _captop;
+ private int _capsize;
- internal int[] _capnumlist;
- internal List<string> _capnamelist;
+ private Hashtable _caps;
+ private Hashtable _capnames;
- internal RegexOptions _options;
- internal List<RegexOptions> _optionsStack;
+ private int[] _capnumlist;
+ private List<string> _capnamelist;
- internal bool _ignoreNextParen = false;
+ private RegexOptions _options;
+ private List<RegexOptions> _optionsStack;
- internal const int MaxValueDiv10 = int.MaxValue / 10;
- internal const int MaxValueMod10 = int.MaxValue % 10;
+ private bool _ignoreNextParen = false;
/*
* This static call constructs a RegexTree from a regular expression
@@ -54,7 +54,7 @@ namespace System.Text.RegularExpressions
*
* The method creates, drives, and drops a parser instance.
*/
- internal static RegexTree Parse(string re, RegexOptions op)
+ public static RegexTree Parse(string re, RegexOptions op)
{
RegexParser p;
RegexNode root;
@@ -81,7 +81,7 @@ namespace System.Text.RegularExpressions
* This static call constructs a flat concatenation node given
* a replacement pattern.
*/
- internal static RegexReplacement ParseReplacement(string rep, Hashtable caps, int capsize, Hashtable capnames, RegexOptions op)
+ public static RegexReplacement ParseReplacement(string rep, Hashtable caps, int capsize, Hashtable capnames, RegexOptions op)
{
RegexParser p;
RegexNode root;
@@ -100,7 +100,7 @@ namespace System.Text.RegularExpressions
/*
* Escapes all metacharacters (including |,(,),[,{,|,^,$,*,+,?,\, spaces and #)
*/
- internal static string Escape(string input)
+ public static string Escape(string input)
{
for (int i = 0; i < input.Length; i++)
{
@@ -155,7 +155,7 @@ namespace System.Text.RegularExpressions
/*
* Escapes all metacharacters (including (,),[,],{,},|,^,$,*,+,?,\, spaces and #)
*/
- internal static string Unescape(string input)
+ public static string Unescape(string input)
{
for (int i = 0; i < input.Length; i++)
{
@@ -200,7 +200,7 @@ namespace System.Text.RegularExpressions
/*
* Drops a string into the pattern buffer.
*/
- internal void SetPattern(string Re)
+ private void SetPattern(string Re)
{
if (Re == null)
Re = string.Empty;
@@ -211,7 +211,7 @@ namespace System.Text.RegularExpressions
/*
* Resets parsing to the beginning of the pattern.
*/
- internal void Reset(RegexOptions topopts)
+ private void Reset(RegexOptions topopts)
{
_currentPos = 0;
_autocap = 1;
@@ -227,7 +227,7 @@ namespace System.Text.RegularExpressions
/*
* The main parsing function.
*/
- internal RegexNode ScanRegex()
+ private RegexNode ScanRegex()
{
char ch = '@'; // nonspecial ch, means at beginning
bool isQuantifier = false;
@@ -288,7 +288,7 @@ namespace System.Text.RegularExpressions
goto ContinueOuterScan;
case '[':
- AddUnitSet(ScanCharClass(UseOptionI()).ToStringClass());
+ AddUnitSet(ScanCharClass(UseOptionI(), scanOnly: false).ToStringClass());
break;
case '(':
@@ -326,7 +326,7 @@ namespace System.Text.RegularExpressions
break;
case '\\':
- AddUnitNode(ScanBackslash());
+ AddUnitNode(ScanBackslash(scanOnly: false));
break;
case '^':
@@ -367,7 +367,7 @@ namespace System.Text.RegularExpressions
goto ContinueOuterScan;
}
- ch = MoveRightGetChar();
+ ch = RightCharMoveRight();
// Handle quantifiers
while (Unit() != null)
@@ -409,7 +409,7 @@ namespace System.Text.RegularExpressions
}
}
- if (startpos == Textpos() || CharsRight() == 0 || MoveRightGetChar() != '}')
+ if (startpos == Textpos() || CharsRight() == 0 || RightCharMoveRight() != '}')
{
AddConcatenate();
Textto(startpos - 1);
@@ -457,7 +457,7 @@ namespace System.Text.RegularExpressions
/*
* Simple parsing for replacement patterns
*/
- internal RegexNode ScanReplacement()
+ private RegexNode ScanReplacement()
{
int c;
int startpos;
@@ -482,7 +482,7 @@ namespace System.Text.RegularExpressions
if (c > 0)
{
- if (MoveRightGetChar() == '$')
+ if (RightCharMoveRight() == '$')
AddUnitNode(ScanDollar());
AddConcatenate();
}
@@ -495,16 +495,7 @@ namespace System.Text.RegularExpressions
* Scans contents of [] (not including []'s), and converts to a
* RegexCharClass.
*/
- internal RegexCharClass ScanCharClass(bool caseInsensitive)
- {
- return ScanCharClass(caseInsensitive, false);
- }
-
- /*
- * Scans contents of [] (not including []'s), and converts to a
- * RegexCharClass.
- */
- internal RegexCharClass ScanCharClass(bool caseInsensitive, bool scanOnly)
+ private RegexCharClass ScanCharClass(bool caseInsensitive, bool scanOnly)
{
char ch = '\0';
char chPrev = '\0';
@@ -526,7 +517,7 @@ namespace System.Text.RegularExpressions
for (; CharsRight() > 0; firstChar = false)
{
bool fTranslatedChar = false;
- ch = MoveRightGetChar();
+ ch = RightCharMoveRight();
if (ch == ']')
{
if (!firstChar)
@@ -537,7 +528,7 @@ namespace System.Text.RegularExpressions
}
else if (ch == '\\' && CharsRight() > 0)
{
- switch (ch = MoveRightGetChar())
+ switch (ch = RightCharMoveRight())
{
case 'D':
case 'd':
@@ -606,7 +597,7 @@ namespace System.Text.RegularExpressions
MoveRight();
name = ScanCapname();
- if (CharsRight() < 2 || MoveRightGetChar() != ':' || MoveRightGetChar() != ']')
+ if (CharsRight() < 2 || RightCharMoveRight() != ':' || RightCharMoveRight() != ']')
Textto(savePos);
// else lookup name (nyi)
}
@@ -624,7 +615,7 @@ namespace System.Text.RegularExpressions
// In that case, we'll add chPrev to our char class, skip the opening [, and
// scan the new character class recursively.
cc.AddChar(chPrev);
- cc.AddSubtraction(ScanCharClass(caseInsensitive, false));
+ cc.AddSubtraction(ScanCharClass(caseInsensitive, scanOnly));
if (CharsRight() > 0 && RightChar() != ']')
throw MakeException(SR.SubtractionMustBeLast);
@@ -652,7 +643,7 @@ namespace System.Text.RegularExpressions
if (!scanOnly)
{
MoveRight(1);
- cc.AddSubtraction(ScanCharClass(caseInsensitive, false));
+ cc.AddSubtraction(ScanCharClass(caseInsensitive, scanOnly));
if (CharsRight() > 0 && RightChar() != ']')
throw MakeException(SR.SubtractionMustBeLast);
@@ -660,7 +651,7 @@ namespace System.Text.RegularExpressions
else
{
MoveRight(1);
- ScanCharClass(caseInsensitive, true);
+ ScanCharClass(caseInsensitive, scanOnly);
}
}
else
@@ -684,7 +675,7 @@ namespace System.Text.RegularExpressions
* a RegexNode for the type of group scanned, or null if the group
* simply changed options (?cimsx-cimsx) or was a comment (#...).
*/
- internal RegexNode ScanGroupOpen()
+ private RegexNode ScanGroupOpen()
{
char ch = '\0';
int NodeType;
@@ -713,23 +704,27 @@ namespace System.Text.RegularExpressions
if (CharsRight() == 0)
break;
- switch (ch = MoveRightGetChar())
+ switch (ch = RightCharMoveRight())
{
case ':':
+ // noncapturing group
NodeType = RegexNode.Group;
break;
case '=':
+ // lookahead assertion
_options &= ~(RegexOptions.RightToLeft);
NodeType = RegexNode.Require;
break;
case '!':
+ // negative lookahead assertion
_options &= ~(RegexOptions.RightToLeft);
NodeType = RegexNode.Prevent;
break;
case '>':
+ // greedy subexpression
NodeType = RegexNode.Greedy;
break;
@@ -742,12 +737,13 @@ namespace System.Text.RegularExpressions
if (CharsRight() == 0)
goto BreakRecognize;
- switch (ch = MoveRightGetChar())
+ switch (ch = RightCharMoveRight())
{
case '=':
if (close == '\'')
goto BreakRecognize;
+ // lookbehind assertion
_options |= RegexOptions.RightToLeft;
NodeType = RegexNode.Require;
break;
@@ -756,6 +752,7 @@ namespace System.Text.RegularExpressions
if (close == '\'')
goto BreakRecognize;
+ // negative lookbehind assertion
_options |= RegexOptions.RightToLeft;
NodeType = RegexNode.Prevent;
break;
@@ -804,7 +801,7 @@ namespace System.Text.RegularExpressions
// grab part after - if any
- if ((capnum != -1 || proceed == true) && CharsRight() > 0 && RightChar() == '-')
+ if ((capnum != -1 || proceed == true) && CharsRight() > 1 && RightChar() == '-')
{
MoveRight();
ch = RightChar();
@@ -842,7 +839,7 @@ namespace System.Text.RegularExpressions
// actually make the node
- if ((capnum != -1 || uncapnum != -1) && CharsRight() > 0 && MoveRightGetChar() == close)
+ if ((capnum != -1 || uncapnum != -1) && CharsRight() > 0 && RightCharMoveRight() == close)
{
return new RegexNode(RegexNode.Capture, _options, capnum, uncapnum);
}
@@ -862,7 +859,7 @@ namespace System.Text.RegularExpressions
if (ch >= '0' && ch <= '9')
{
int capnum = ScanDecimal();
- if (CharsRight() > 0 && MoveRightGetChar() == ')')
+ if (CharsRight() > 0 && RightCharMoveRight() == ')')
{
if (IsCaptureSlot(capnum))
return new RegexNode(RegexNode.Testref, _options, capnum);
@@ -876,7 +873,7 @@ namespace System.Text.RegularExpressions
{
string capname = ScanCapname();
- if (IsCaptureName(capname) && CharsRight() > 0 && MoveRightGetChar() == ')')
+ if (IsCaptureName(capname) && CharsRight() > 0 && RightCharMoveRight() == ')')
return new RegexNode(RegexNode.Testref, _options, CaptureSlotFromName(capname));
}
}
@@ -911,12 +908,12 @@ namespace System.Text.RegularExpressions
NodeType = RegexNode.Group;
// Disallow options in the children of a testgroup node
- if (_group._type != RegexNode.Testgroup)
+ if (_group.NType != RegexNode.Testgroup)
ScanOptions();
if (CharsRight() == 0)
goto BreakRecognize;
- if ((ch = MoveRightGetChar()) == ')')
+ if ((ch = RightCharMoveRight()) == ')')
return null;
if (ch != ':')
@@ -937,7 +934,7 @@ namespace System.Text.RegularExpressions
/*
* Scans whitespace or x-mode comments.
*/
- internal void ScanBlank()
+ private void ScanBlank()
{
if (UseOptionX())
{
@@ -988,7 +985,7 @@ namespace System.Text.RegularExpressions
* Scans chars following a '\' (not counting the '\'), and returns
* a RegexNode for the type of atom scanned.
*/
- internal RegexNode ScanBackslash()
+ private RegexNode ScanBackslash(bool scanOnly)
{
char ch;
RegexCharClass cc;
@@ -1005,40 +1002,54 @@ namespace System.Text.RegularExpressions
case 'Z':
case 'z':
MoveRight();
+ if (scanOnly)
+ return null;
return new RegexNode(TypeFromCode(ch), _options);
case 'w':
MoveRight();
+ if (scanOnly)
+ return null;
if (UseOptionE())
return new RegexNode(RegexNode.Set, _options, RegexCharClass.ECMAWordClass);
return new RegexNode(RegexNode.Set, _options, RegexCharClass.WordClass);
case 'W':
MoveRight();
+ if (scanOnly)
+ return null;
if (UseOptionE())
return new RegexNode(RegexNode.Set, _options, RegexCharClass.NotECMAWordClass);
return new RegexNode(RegexNode.Set, _options, RegexCharClass.NotWordClass);
case 's':
MoveRight();
+ if (scanOnly)
+ return null;
if (UseOptionE())
return new RegexNode(RegexNode.Set, _options, RegexCharClass.ECMASpaceClass);
return new RegexNode(RegexNode.Set, _options, RegexCharClass.SpaceClass);
case 'S':
MoveRight();
+ if (scanOnly)
+ return null;
if (UseOptionE())
return new RegexNode(RegexNode.Set, _options, RegexCharClass.NotECMASpaceClass);
return new RegexNode(RegexNode.Set, _options, RegexCharClass.NotSpaceClass);
case 'd':
MoveRight();
+ if (scanOnly)
+ return null;
if (UseOptionE())
return new RegexNode(RegexNode.Set, _options, RegexCharClass.ECMADigitClass);
return new RegexNode(RegexNode.Set, _options, RegexCharClass.DigitClass);
case 'D':
MoveRight();
+ if (scanOnly)
+ return null;
if (UseOptionE())
return new RegexNode(RegexNode.Set, _options, RegexCharClass.NotECMADigitClass);
return new RegexNode(RegexNode.Set, _options, RegexCharClass.NotDigitClass);
@@ -1046,6 +1057,8 @@ namespace System.Text.RegularExpressions
case 'p':
case 'P':
MoveRight();
+ if (scanOnly)
+ return null;
cc = new RegexCharClass();
cc.AddCategoryFromName(ParseProperty(), (ch != 'p'), UseOptionI(), _pattern);
if (UseOptionI())
@@ -1054,14 +1067,14 @@ namespace System.Text.RegularExpressions
return new RegexNode(RegexNode.Set, _options, cc.ToStringClass());
default:
- return ScanBasicBackslash();
+ return ScanBasicBackslash(scanOnly);
}
}
/*
* Scans \-style backreferences and character escapes
*/
- internal RegexNode ScanBasicBackslash()
+ private RegexNode ScanBasicBackslash(bool scanOnly)
{
if (CharsRight() == 0)
throw MakeException(SR.IllegalEndEscape);
@@ -1081,7 +1094,7 @@ namespace System.Text.RegularExpressions
if (CharsRight() >= 2)
{
MoveRight();
- ch = MoveRightGetChar();
+ ch = RightCharMoveRight();
if (ch == '<' || ch == '\'')
{
@@ -1107,14 +1120,16 @@ namespace System.Text.RegularExpressions
ch = RightChar();
}
- // Try to parse backreference: \<1> or \<cap>
+ // Try to parse backreference: \<1>
if (angled && ch >= '0' && ch <= '9')
{
int capnum = ScanDecimal();
- if (CharsRight() > 0 && MoveRightGetChar() == close)
+ if (CharsRight() > 0 && RightCharMoveRight() == close)
{
+ if (scanOnly)
+ return null;
if (IsCaptureSlot(capnum))
return new RegexNode(RegexNode.Ref, _options, capnum);
else
@@ -1141,11 +1156,13 @@ namespace System.Text.RegularExpressions
newcapnum = newcapnum * 10 + (int)(ch - '0');
}
if (capnum >= 0)
- return new RegexNode(RegexNode.Ref, _options, capnum);
+ return scanOnly ? null : new RegexNode(RegexNode.Ref, _options, capnum);
}
else
{
int capnum = ScanDecimal();
+ if (scanOnly)
+ return null;
if (IsCaptureSlot(capnum))
return new RegexNode(RegexNode.Ref, _options, capnum);
else if (capnum <= 9)
@@ -1153,12 +1170,17 @@ namespace System.Text.RegularExpressions
}
}
+
+ // Try to parse backreference: \<foo>
+
else if (angled && RegexCharClass.IsWordChar(ch))
{
string capname = ScanCapname();
- if (CharsRight() > 0 && MoveRightGetChar() == close)
+ if (CharsRight() > 0 && RightCharMoveRight() == close)
{
+ if (scanOnly)
+ return null;
if (IsCaptureName(capname))
return new RegexNode(RegexNode.Ref, _options, CaptureSlotFromName(capname));
else
@@ -1174,13 +1196,13 @@ namespace System.Text.RegularExpressions
if (UseOptionI())
ch = _culture.TextInfo.ToLower(ch);
- return new RegexNode(RegexNode.One, _options, ch);
+ return scanOnly ? null : new RegexNode(RegexNode.One, _options, ch);
}
/*
* Scans $ patterns recognized within replacement patterns
*/
- internal RegexNode ScanDollar()
+ private RegexNode ScanDollar()
{
if (CharsRight() == 0)
return new RegexNode(RegexNode.One, _options, '$');
@@ -1240,7 +1262,7 @@ namespace System.Text.RegularExpressions
else
{
int capnum = ScanDecimal();
- if (!angled || CharsRight() > 0 && MoveRightGetChar() == '}')
+ if (!angled || CharsRight() > 0 && RightCharMoveRight() == '}')
{
if (IsCaptureSlot(capnum))
return new RegexNode(RegexNode.Ref, _options, capnum);
@@ -1251,7 +1273,7 @@ namespace System.Text.RegularExpressions
{
string capname = ScanCapname();
- if (CharsRight() > 0 && MoveRightGetChar() == '}')
+ if (CharsRight() > 0 && RightCharMoveRight() == '}')
{
if (IsCaptureName(capname))
return new RegexNode(RegexNode.Ref, _options, CaptureSlotFromName(capname));
@@ -1304,13 +1326,13 @@ namespace System.Text.RegularExpressions
/*
* Scans a capture name: consumes word chars
*/
- internal string ScanCapname()
+ private string ScanCapname()
{
int startpos = Textpos();
while (CharsRight() > 0)
{
- if (!RegexCharClass.IsWordChar(MoveRightGetChar()))
+ if (!RegexCharClass.IsWordChar(RightCharMoveRight()))
{
MoveLeft();
break;
@@ -1324,7 +1346,7 @@ namespace System.Text.RegularExpressions
/*
* Scans up to three octal digits (stops before exceeding 0377).
*/
- internal char ScanOctal()
+ private char ScanOctal()
{
int d;
int i;
@@ -1356,7 +1378,7 @@ namespace System.Text.RegularExpressions
/*
* Scans any number of decimal digits (pegs value at 2^31-1 if too large)
*/
- internal int ScanDecimal()
+ private int ScanDecimal()
{
int i = 0;
int d;
@@ -1378,7 +1400,7 @@ namespace System.Text.RegularExpressions
/*
* Scans exactly c hex digits (c=2 for \xFF, c=4 for \uFFFF)
*/
- internal char ScanHex(int c)
+ private char ScanHex(int c)
{
int i;
int d;
@@ -1387,7 +1409,7 @@ namespace System.Text.RegularExpressions
if (CharsRight() >= c)
{
- for (; c > 0 && ((d = HexDigit(MoveRightGetChar())) >= 0); c -= 1)
+ for (; c > 0 && ((d = HexDigit(RightCharMoveRight())) >= 0); c -= 1)
{
i *= 0x10;
i += d;
@@ -1403,7 +1425,7 @@ namespace System.Text.RegularExpressions
/*
* Returns n <= 0xF for a hex digit.
*/
- internal static int HexDigit(char ch)
+ private static int HexDigit(char ch)
{
int d;
@@ -1422,14 +1444,14 @@ namespace System.Text.RegularExpressions
/*
* Grabs and converts an ASCII control character
*/
- internal char ScanControl()
+ private char ScanControl()
{
char ch;
if (CharsRight() <= 0)
throw MakeException(SR.MissingControl);
- ch = MoveRightGetChar();
+ ch = RightCharMoveRight();
// \ca interpreted as \cA
@@ -1445,7 +1467,7 @@ namespace System.Text.RegularExpressions
/*
* Returns true for options allowed only at the top level
*/
- internal bool IsOnlyTopOption(RegexOptions option)
+ private bool IsOnlyTopOption(RegexOptions option)
{
return (option == RegexOptions.RightToLeft
|| option == RegexOptions.CultureInvariant
@@ -1456,7 +1478,7 @@ namespace System.Text.RegularExpressions
/*
* Scans cimsx-cimsx option string, stops at the first unrecognized char.
*/
- internal void ScanOptions()
+ private void ScanOptions()
{
char ch;
bool off;
@@ -1491,11 +1513,11 @@ namespace System.Text.RegularExpressions
/*
* Scans \ code for escape codes that map to single Unicode chars.
*/
- internal char ScanCharEscape()
+ private char ScanCharEscape()
{
char ch;
- ch = MoveRightGetChar();
+ ch = RightCharMoveRight();
if (ch >= '0' && ch <= '7')
{
@@ -1537,13 +1559,13 @@ namespace System.Text.RegularExpressions
/*
* Scans X for \p{X} or \P{X}
*/
- internal string ParseProperty()
+ private string ParseProperty()
{
if (CharsRight() < 3)
{
throw MakeException(SR.IncompleteSlashP);
}
- char ch = MoveRightGetChar();
+ char ch = RightCharMoveRight();
if (ch != '{')
{
throw MakeException(SR.MalformedSlashP);
@@ -1552,7 +1574,7 @@ namespace System.Text.RegularExpressions
int startpos = Textpos();
while (CharsRight() > 0)
{
- ch = MoveRightGetChar();
+ ch = RightCharMoveRight();
if (!(RegexCharClass.IsWordChar(ch) || ch == '-'))
{
MoveLeft();
@@ -1561,7 +1583,7 @@ namespace System.Text.RegularExpressions
}
string capname = _pattern.Substring(startpos, Textpos() - startpos);
- if (CharsRight() == 0 || MoveRightGetChar() != '}')
+ if (CharsRight() == 0 || RightCharMoveRight() != '}')
throw MakeException(SR.IncompleteSlashP);
return capname;
@@ -1570,7 +1592,7 @@ namespace System.Text.RegularExpressions
/*
* Returns ReNode type for zero-length assertions with a \ code.
*/
- internal int TypeFromCode(char ch)
+ private int TypeFromCode(char ch)
{
switch (ch)
{
@@ -1594,7 +1616,7 @@ namespace System.Text.RegularExpressions
/*
* Returns option bit from single-char (?cimsx) code.
*/
- internal static RegexOptions OptionFromCode(char ch)
+ private static RegexOptions OptionFromCode(char ch)
{
// case-insensitive
if (ch >= 'A' && ch <= 'Z')
@@ -1629,7 +1651,7 @@ namespace System.Text.RegularExpressions
* a prescanner for deducing the slots used for
* captures by doing a partial tokenization of the pattern.
*/
- internal void CountCaptures()
+ private void CountCaptures()
{
char ch;
@@ -1640,12 +1662,12 @@ namespace System.Text.RegularExpressions
while (CharsRight() > 0)
{
int pos = Textpos();
- ch = MoveRightGetChar();
+ ch = RightCharMoveRight();
switch (ch)
{
case '\\':
if (CharsRight() > 0)
- MoveRight();
+ ScanBackslash(scanOnly: true);
break;
case '#':
@@ -1657,7 +1679,7 @@ namespace System.Text.RegularExpressions
break;
case '[':
- ScanCharClass(false, true);
+ ScanCharClass(caseInsensitive: false, scanOnly: true);
break;
case ')':
@@ -1741,7 +1763,7 @@ namespace System.Text.RegularExpressions
/*
* Notes a used capture slot
*/
- internal void NoteCaptureSlot(int i, int pos)
+ private void NoteCaptureSlot(int i, int pos)
{
if (!_caps.ContainsKey(i))
{
@@ -1763,7 +1785,7 @@ namespace System.Text.RegularExpressions
/*
* Notes a used capture slot
*/
- internal void NoteCaptureName(string name, int pos)
+ private void NoteCaptureName(string name, int pos)
{
if (_capnames == null)
{
@@ -1781,7 +1803,7 @@ namespace System.Text.RegularExpressions
/*
* For when all the used captures are known: note them all at once
*/
- internal void NoteCaptures(Hashtable caps, int capsize, Hashtable capnames)
+ private void NoteCaptures(Hashtable caps, int capsize, Hashtable capnames)
{
_caps = caps;
_capsize = capsize;
@@ -1791,7 +1813,7 @@ namespace System.Text.RegularExpressions
/*
* Assigns unused slot numbers to the capture names
*/
- internal void AssignNameSlots()
+ private void AssignNameSlots()
{
if (_capnames != null)
{
@@ -1869,7 +1891,7 @@ namespace System.Text.RegularExpressions
/*
* Looks up the slot number for a given name
*/
- internal int CaptureSlotFromName(string capname)
+ private int CaptureSlotFromName(string capname)
{
return (int)_capnames[capname];
}
@@ -1877,7 +1899,7 @@ namespace System.Text.RegularExpressions
/*
* True if the capture slot was noted
*/
- internal bool IsCaptureSlot(int i)
+ private bool IsCaptureSlot(int i)
{
if (_caps != null)
return _caps.ContainsKey(i);
@@ -1888,7 +1910,7 @@ namespace System.Text.RegularExpressions
/*
* Looks up the slot number for a given name
*/
- internal bool IsCaptureName(string capname)
+ private bool IsCaptureName(string capname)
{
if (_capnames == null)
return false;
@@ -1899,7 +1921,7 @@ namespace System.Text.RegularExpressions
/*
* True if N option disabling '(' autocapture is on.
*/
- internal bool UseOptionN()
+ private bool UseOptionN()
{
return (_options & RegexOptions.ExplicitCapture) != 0;
}
@@ -1907,7 +1929,7 @@ namespace System.Text.RegularExpressions
/*
* True if I option enabling case-insensitivity is on.
*/
- internal bool UseOptionI()
+ private bool UseOptionI()
{
return (_options & RegexOptions.IgnoreCase) != 0;
}
@@ -1915,7 +1937,7 @@ namespace System.Text.RegularExpressions
/*
* True if M option altering meaning of $ and ^ is on.
*/
- internal bool UseOptionM()
+ private bool UseOptionM()
{
return (_options & RegexOptions.Multiline) != 0;
}
@@ -1923,7 +1945,7 @@ namespace System.Text.RegularExpressions
/*
* True if S option altering meaning of . is on.
*/
- internal bool UseOptionS()
+ private bool UseOptionS()
{
return (_options & RegexOptions.Singleline) != 0;
}
@@ -1931,7 +1953,7 @@ namespace System.Text.RegularExpressions
/*
* True if X option enabling whitespace/comment mode is on.
*/
- internal bool UseOptionX()
+ private bool UseOptionX()
{
return (_options & RegexOptions.IgnorePatternWhitespace) != 0;
}
@@ -1939,21 +1961,21 @@ namespace System.Text.RegularExpressions
/*
* True if E option enabling ECMAScript behavior is on.
*/
- internal bool UseOptionE()
+ private bool UseOptionE()
{
return (_options & RegexOptions.ECMAScript) != 0;
}
- internal const byte Q = 5; // quantifier
- internal const byte S = 4; // ordinary stopper
- internal const byte Z = 3; // ScanBlank stopper
- internal const byte X = 2; // whitespace
- internal const byte E = 1; // should be escaped
+ private const byte Q = 5; // quantifier
+ private const byte S = 4; // ordinary stopper
+ private const byte Z = 3; // ScanBlank stopper
+ private const byte X = 2; // whitespace
+ private const byte E = 1; // should be escaped
/*
* For categorizing ASCII characters.
*/
- internal static readonly byte[] _category = new byte[] {
+ private static readonly byte[] s_category = new byte[] {
// 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F
0,0,0,0,0,0,0,0,0,X,X,0,X,X,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
// ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
@@ -1966,28 +1988,28 @@ namespace System.Text.RegularExpressions
/*
* Returns true for those characters that terminate a string of ordinary chars.
*/
- internal static bool IsSpecial(char ch)
+ private static bool IsSpecial(char ch)
{
- return (ch <= '|' && _category[ch] >= S);
+ return (ch <= '|' && s_category[ch] >= S);
}
/*
* Returns true for those characters that terminate a string of ordinary chars.
*/
- internal static bool IsStopperX(char ch)
+ private static bool IsStopperX(char ch)
{
- return (ch <= '|' && _category[ch] >= X);
+ return (ch <= '|' && s_category[ch] >= X);
}
/*
* Returns true for those characters that begin a quantifier.
*/
- internal static bool IsQuantifier(char ch)
+ private static bool IsQuantifier(char ch)
{
- return (ch <= '{' && _category[ch] >= Q);
+ return (ch <= '{' && s_category[ch] >= Q);
}
- internal bool IsTrueQuantifier()
+ private bool IsTrueQuantifier()
{
int nChars = CharsRight();
if (nChars == 0)
@@ -1995,7 +2017,7 @@ namespace System.Text.RegularExpressions
int startpos = Textpos();
char ch = CharAt(startpos);
if (ch != '{')
- return ch <= '{' && _category[ch] >= Q;
+ return ch <= '{' && s_category[ch] >= Q;
int pos = startpos;
while (--nChars > 0 && (ch = CharAt(++pos)) >= '0' && ch <= '9') ;
if (nChars == 0 || pos - startpos == 1)
@@ -2011,24 +2033,24 @@ namespace System.Text.RegularExpressions
/*
* Returns true for whitespace.
*/
- internal static bool IsSpace(char ch)
+ private static bool IsSpace(char ch)
{
- return (ch <= ' ' && _category[ch] == X);
+ return (ch <= ' ' && s_category[ch] == X);
}
/*
* Returns true for chars that should be escaped.
*/
- internal static bool IsMetachar(char ch)
+ private static bool IsMetachar(char ch)
{
- return (ch <= '|' && _category[ch] >= E);
+ return (ch <= '|' && s_category[ch] >= E);
}
/*
* Add a string to the last concatenate.
*/
- internal void AddConcatenate(int pos, int cch, bool isReplacement)
+ private void AddConcatenate(int pos, int cch, bool isReplacement)
{
RegexNode node;
@@ -2069,23 +2091,23 @@ namespace System.Text.RegularExpressions
/*
* Push the parser state (in response to an open paren)
*/
- internal void PushGroup()
+ private void PushGroup()
{
- _group._next = _stack;
- _alternation._next = _group;
- _concatenation._next = _alternation;
+ _group.Next = _stack;
+ _alternation.Next = _group;
+ _concatenation.Next = _alternation;
_stack = _concatenation;
}
/*
* Remember the pushed state (in response to a ')')
*/
- internal void PopGroup()
+ private void PopGroup()
{
_concatenation = _stack;
- _alternation = _concatenation._next;
- _group = _alternation._next;
- _stack = _group._next;
+ _alternation = _concatenation.Next;
+ _group = _alternation.Next;
+ _stack = _group.Next;
// The first () inside a Testgroup group goes directly to the group
if (_group.Type() == RegexNode.Testgroup && _group.ChildCount() == 0)
@@ -2101,7 +2123,7 @@ namespace System.Text.RegularExpressions
/*
* True if the group stack is empty.
*/
- internal bool EmptyStack()
+ private bool EmptyStack()
{
return _stack == null;
}
@@ -2109,7 +2131,7 @@ namespace System.Text.RegularExpressions
/*
* Start a new round for the parser state (in response to an open paren or string start)
*/
- internal void StartGroup(RegexNode openGroup)
+ private void StartGroup(RegexNode openGroup)
{
_group = openGroup;
_alternation = new RegexNode(RegexNode.Alternate, _options);
@@ -2119,7 +2141,7 @@ namespace System.Text.RegularExpressions
/*
* Finish the current concatenation (in response to a |)
*/
- internal void AddAlternate()
+ private void AddAlternate()
{
// The | parts inside a Testgroup group go directly to the group
@@ -2138,7 +2160,7 @@ namespace System.Text.RegularExpressions
/*
* Finish the current quantifiable (when a quantifier is not found or is not possible)
*/
- internal void AddConcatenate()
+ private void AddConcatenate()
{
// The first (| inside a Testgroup group goes directly to the group
@@ -2149,7 +2171,7 @@ namespace System.Text.RegularExpressions
/*
* Finish the current quantifiable (when a quantifier is found)
*/
- internal void AddConcatenate(bool lazy, int min, int max)
+ private void AddConcatenate(bool lazy, int min, int max)
{
_concatenation.AddChild(_unit.MakeQuantifier(lazy, min, max));
_unit = null;
@@ -2158,7 +2180,7 @@ namespace System.Text.RegularExpressions
/*
* Returns the current unit
*/
- internal RegexNode Unit()
+ private RegexNode Unit()
{
return _unit;
}
@@ -2166,7 +2188,7 @@ namespace System.Text.RegularExpressions
/*
* Sets the current unit to a single char node
*/
- internal void AddUnitOne(char ch)
+ private void AddUnitOne(char ch)
{
if (UseOptionI())
ch = _culture.TextInfo.ToLower(ch);
@@ -2177,7 +2199,7 @@ namespace System.Text.RegularExpressions
/*
* Sets the current unit to a single inverse-char node
*/
- internal void AddUnitNotone(char ch)
+ private void AddUnitNotone(char ch)
{
if (UseOptionI())
ch = _culture.TextInfo.ToLower(ch);
@@ -2188,7 +2210,7 @@ namespace System.Text.RegularExpressions
/*
* Sets the current unit to a single set node
*/
- internal void AddUnitSet(string cc)
+ private void AddUnitSet(string cc)
{
_unit = new RegexNode(RegexNode.Set, _options, cc);
}
@@ -2196,7 +2218,7 @@ namespace System.Text.RegularExpressions
/*
* Sets the current unit to a subtree
*/
- internal void AddUnitNode(RegexNode node)
+ private void AddUnitNode(RegexNode node)
{
_unit = node;
}
@@ -2204,7 +2226,7 @@ namespace System.Text.RegularExpressions
/*
* Sets the current unit to an assertion of the specified type
*/
- internal void AddUnitType(int type)
+ private void AddUnitType(int type)
{
_unit = new RegexNode(type, _options);
}
@@ -2212,7 +2234,7 @@ namespace System.Text.RegularExpressions
/*
* Finish the current group (in response to a ')' or end)
*/
- internal void AddGroup()
+ private void AddGroup()
{
if (_group.Type() == RegexNode.Testgroup || _group.Type() == RegexNode.Testref)
{
@@ -2233,7 +2255,7 @@ namespace System.Text.RegularExpressions
/*
* Saves options on a stack.
*/
- internal void PushOptions()
+ private void PushOptions()
{
_optionsStack.Add(_options);
}
@@ -2241,7 +2263,7 @@ namespace System.Text.RegularExpressions
/*
* Recalls options from the stack.
*/
- internal void PopOptions()
+ private void PopOptions()
{
_options = _optionsStack[_optionsStack.Count - 1];
_optionsStack.RemoveAt(_optionsStack.Count - 1);
@@ -2250,7 +2272,7 @@ namespace System.Text.RegularExpressions
/*
* True if options stack is empty.
*/
- internal bool EmptyOptionsStack()
+ private bool EmptyOptionsStack()
{
return (_optionsStack.Count == 0);
}
@@ -2258,7 +2280,7 @@ namespace System.Text.RegularExpressions
/*
* Pops the option stack, but keeps the current options unchanged.
*/
- internal void PopKeepOptions()
+ private void PopKeepOptions()
{
_optionsStack.RemoveAt(_optionsStack.Count - 1);
}
@@ -2266,7 +2288,7 @@ namespace System.Text.RegularExpressions
/*
* Fills in an ArgumentException
*/
- internal ArgumentException MakeException(string message)
+ private ArgumentException MakeException(string message)
{
return new ArgumentException(SR.Format(SR.MakeException, _pattern, message));
}
@@ -2274,7 +2296,7 @@ namespace System.Text.RegularExpressions
/*
* Returns the current parsing position.
*/
- internal int Textpos()
+ private int Textpos()
{
return _currentPos;
}
@@ -2282,7 +2304,7 @@ namespace System.Text.RegularExpressions
/*
* Zaps to a specific parsing position.
*/
- internal void Textto(int pos)
+ private void Textto(int pos)
{
_currentPos = pos;
}
@@ -2290,7 +2312,7 @@ namespace System.Text.RegularExpressions
/*
* Returns the char at the right of the current parsing position and advances to the right.
*/
- internal char MoveRightGetChar()
+ private char RightCharMoveRight()
{
return _pattern[_currentPos++];
}
@@ -2298,12 +2320,12 @@ namespace System.Text.RegularExpressions
/*
* Moves the current position to the right.
*/
- internal void MoveRight()
+ private void MoveRight()
{
MoveRight(1);
}
- internal void MoveRight(int i)
+ private void MoveRight(int i)
{
_currentPos += i;
}
@@ -2311,7 +2333,7 @@ namespace System.Text.RegularExpressions
/*
* Moves the current parsing position one to the left.
*/
- internal void MoveLeft()
+ private void MoveLeft()
{
--_currentPos;
}
@@ -2319,7 +2341,7 @@ namespace System.Text.RegularExpressions
/*
* Returns the char left of the current parsing position.
*/
- internal char CharAt(int i)
+ private char CharAt(int i)
{
return _pattern[i];
}
@@ -2335,7 +2357,7 @@ namespace System.Text.RegularExpressions
/*
* Returns the char i chars right of the current parsing position.
*/
- internal char RightChar(int i)
+ private char RightChar(int i)
{
return _pattern[_currentPos + i];
}
@@ -2343,7 +2365,7 @@ namespace System.Text.RegularExpressions
/*
* Number of characters to the right of the current parsing position.
*/
- internal int CharsRight()
+ private int CharsRight()
{
return _pattern.Length - _currentPos;
}
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefix.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefix.cs
new file mode 100644
index 0000000000..081cace866
--- /dev/null
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexPrefix.cs
@@ -0,0 +1,21 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Text.RegularExpressions
+{
+ internal readonly struct RegexPrefix
+ {
+ internal RegexPrefix(string prefix, bool ci)
+ {
+ Prefix = prefix;
+ CaseInsensitive = ci;
+ }
+
+ internal bool CaseInsensitive { get; }
+
+ internal static RegexPrefix Empty { get; } = new RegexPrefix(string.Empty, false);
+
+ internal string Prefix { get; }
+ }
+}
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexReplacement.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexReplacement.cs
index 579980bfa7..b4887737dc 100644
--- a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexReplacement.cs
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexReplacement.cs
@@ -15,13 +15,12 @@ namespace System.Text.RegularExpressions
internal sealed class RegexReplacement
{
// Constants for special insertion patterns
- internal const int Specials = 4;
- internal const int LeftPortion = -1;
- internal const int RightPortion = -2;
- internal const int LastGroup = -3;
- internal const int WholeString = -4;
+ private const int Specials = 4;
+ public const int LeftPortion = -1;
+ public const int RightPortion = -2;
+ public const int LastGroup = -3;
+ public const int WholeString = -4;
- private readonly string _rep;
private readonly List<string> _strings; // table of string constants
private readonly List<int> _rules; // negative -> group #, positive -> string #
@@ -30,7 +29,7 @@ namespace System.Text.RegularExpressions
/// the constructor takes a RegexNode which is a concatenation
/// of constant strings and backreferences.
/// </summary>
- internal RegexReplacement(string rep, RegexNode concat, Hashtable _caps)
+ public RegexReplacement(string rep, RegexNode concat, Hashtable _caps)
{
if (concat.Type() != RegexNode.Concatenate)
throw new ArgumentException(SR.ReplacementError);
@@ -46,11 +45,11 @@ namespace System.Text.RegularExpressions
switch (child.Type())
{
case RegexNode.Multi:
- sb.Append(child._str);
+ sb.Append(child.Str);
break;
case RegexNode.One:
- sb.Append(child._ch);
+ sb.Append(child.Ch);
break;
case RegexNode.Ref:
@@ -60,7 +59,7 @@ namespace System.Text.RegularExpressions
strings.Add(sb.ToString());
sb.Length = 0;
}
- int slot = child._m;
+ int slot = child.M;
if (_caps != null && slot >= 0)
slot = (int)_caps[slot];
@@ -81,12 +80,35 @@ namespace System.Text.RegularExpressions
StringBuilderCache.Release(sb);
- _rep = rep;
+ Pattern = rep;
_strings = strings;
_rules = rules;
}
/// <summary>
+ /// Either returns a weakly cached RegexReplacement helper or creates one and caches it.
+ /// </summary>
+ /// <returns></returns>
+ public static RegexReplacement GetOrCreate(WeakReference<RegexReplacement> replRef, string replacement, Hashtable caps,
+ int capsize, Hashtable capnames, RegexOptions roptions)
+ {
+ RegexReplacement repl;
+
+ if (!replRef.TryGetTarget(out repl) || !repl.Pattern.Equals(replacement))
+ {
+ repl = RegexParser.ParseReplacement(replacement, caps, capsize, capnames, roptions);
+ replRef.SetTarget(repl);
+ }
+
+ return repl;
+ }
+
+ /// <summary>
+ /// The original pattern string
+ /// </summary>
+ public string Pattern { get; }
+
+ /// <summary>
/// Given a Match, emits into the StringBuilder the evaluated
/// substitution pattern.
/// </summary>
@@ -113,7 +135,7 @@ namespace System.Text.RegularExpressions
sb.Append(match.LastGroupToStringImpl());
break;
case WholeString:
- sb.Append(match.GetOriginalString());
+ sb.Append(match.Text);
break;
}
}
@@ -132,22 +154,22 @@ namespace System.Text.RegularExpressions
if (r >= 0) // string lookup
al.Add(_strings[r]);
else if (r < -Specials) // group lookup
- al.Add(match.GroupToStringImpl(-Specials - 1 - r));
+ al.Add(match.GroupToStringImpl(-Specials - 1 - r).ToString());
else
{
switch (-Specials - 1 - r)
{ // special insertion patterns
case LeftPortion:
- al.Add(match.GetLeftSubstring());
+ al.Add(match.GetLeftSubstring().ToString());
break;
case RightPortion:
- al.Add(match.GetRightSubstring());
+ al.Add(match.GetRightSubstring().ToString());
break;
case LastGroup:
- al.Add(match.LastGroupToStringImpl());
+ al.Add(match.LastGroupToStringImpl().ToString());
break;
case WholeString:
- al.Add(match.GetOriginalString());
+ al.Add(match.Text);
break;
}
}
@@ -155,17 +177,9 @@ namespace System.Text.RegularExpressions
}
/// <summary>
- /// The original pattern string
- /// </summary>
- internal string Pattern
- {
- get { return _rep; }
- }
-
- /// <summary>
/// Returns the replacement result for a single match
/// </summary>
- internal string Replacement(Match match)
+ public string Replacement(Match match)
{
StringBuilder sb = StringBuilderCache.Acquire();
@@ -186,7 +200,7 @@ namespace System.Text.RegularExpressions
/// The right-to-left case is split out because StringBuilder
/// doesn't handle right-to-left string building directly very well.
/// </summary>
- internal string Replace(Regex regex, string input, int count, int startat)
+ public string Replace(Regex regex, string input, int count, int startat)
{
if (count < -1)
throw new ArgumentOutOfRangeException(nameof(count), SR.CountTooSmall);
@@ -255,189 +269,5 @@ namespace System.Text.RegularExpressions
return StringBuilderCache.GetStringAndRelease(sb);
}
}
-
- /// <summary>
- /// Replaces all occurrences of the regex in the string with the
- /// replacement evaluator.
- ///
- /// Note that the special case of no matches is handled on its own:
- /// with no matches, the input string is returned unchanged.
- /// The right-to-left case is split out because StringBuilder
- /// doesn't handle right-to-left string building directly very well.
- /// </summary>
- internal static string Replace(MatchEvaluator evaluator, Regex regex,
- string input, int count, int startat)
- {
- if (evaluator == null)
- throw new ArgumentNullException(nameof(evaluator));
- if (count < -1)
- throw new ArgumentOutOfRangeException(nameof(count), SR.CountTooSmall);
- if (startat < 0 || startat > input.Length)
- throw new ArgumentOutOfRangeException(nameof(startat), SR.BeginIndexNotNegative);
-
- if (count == 0)
- return input;
-
- Match match = regex.Match(input, startat);
-
- if (!match.Success)
- {
- return input;
- }
- else
- {
- StringBuilder sb = StringBuilderCache.Acquire();
-
- if (!regex.RightToLeft)
- {
- int prevat = 0;
-
- do
- {
- if (match.Index != prevat)
- sb.Append(input, prevat, match.Index - prevat);
-
- prevat = match.Index + match.Length;
-
- sb.Append(evaluator(match));
-
- if (--count == 0)
- break;
-
- match = match.NextMatch();
- } while (match.Success);
-
- if (prevat < input.Length)
- sb.Append(input, prevat, input.Length - prevat);
- }
- else
- {
- List<string> al = new List<string>();
- int prevat = input.Length;
-
- do
- {
- if (match.Index + match.Length != prevat)
- al.Add(input.Substring(match.Index + match.Length, prevat - match.Index - match.Length));
-
- prevat = match.Index;
-
- al.Add(evaluator(match));
-
- if (--count == 0)
- break;
-
- match = match.NextMatch();
- } while (match.Success);
-
- if (prevat > 0)
- sb.Append(input, 0, prevat);
-
- for (int i = al.Count - 1; i >= 0; i--)
- {
- sb.Append(al[i]);
- }
- }
-
- return StringBuilderCache.GetStringAndRelease(sb);
- }
- }
-
- /// <summary>
- /// Does a split. In the right-to-left case we reorder the
- /// array to be forwards.
- /// </summary>
- internal static string[] Split(Regex regex, string input, int count, int startat)
- {
- if (count < 0)
- throw new ArgumentOutOfRangeException(nameof(count), SR.CountTooSmall);
- if (startat < 0 || startat > input.Length)
- throw new ArgumentOutOfRangeException(nameof(startat), SR.BeginIndexNotNegative);
-
- string[] result;
-
- if (count == 1)
- {
- result = new string[1];
- result[0] = input;
- return result;
- }
-
- count -= 1;
-
- Match match = regex.Match(input, startat);
-
- if (!match.Success)
- {
- result = new string[1];
- result[0] = input;
- return result;
- }
- else
- {
- List<string> al = new List<string>();
-
- if (!regex.RightToLeft)
- {
- int prevat = 0;
-
- for (; ;)
- {
- al.Add(input.Substring(prevat, match.Index - prevat));
-
- prevat = match.Index + match.Length;
-
- // add all matched capture groups to the list.
- for (int i = 1; i < match.Groups.Count; i++)
- {
- if (match.IsMatched(i))
- al.Add(match.Groups[i].ToString());
- }
-
- if (--count == 0)
- break;
-
- match = match.NextMatch();
-
- if (!match.Success)
- break;
- }
-
- al.Add(input.Substring(prevat, input.Length - prevat));
- }
- else
- {
- int prevat = input.Length;
-
- for (; ;)
- {
- al.Add(input.Substring(match.Index + match.Length, prevat - match.Index - match.Length));
-
- prevat = match.Index;
-
- // add all matched capture groups to the list.
- for (int i = 1; i < match.Groups.Count; i++)
- {
- if (match.IsMatched(i))
- al.Add(match.Groups[i].ToString());
- }
-
- if (--count == 0)
- break;
-
- match = match.NextMatch();
-
- if (!match.Success)
- break;
- }
-
- al.Add(input.Substring(0, prevat));
-
- al.Reverse(0, al.Count);
- }
-
- return al.ToArray();
- }
- }
}
}
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexRunner.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexRunner.cs
index ae72533ef4..92d0c72efc 100644
--- a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexRunner.cs
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexRunner.cs
@@ -206,15 +206,16 @@ namespace System.Text.RegularExpressions
if (_ignoreTimeout)
return;
- if (--_timeoutChecksToSkip != 0)
- return;
-
- _timeoutChecksToSkip = TimeoutCheckFrequency;
DoCheckTimeout();
}
private void DoCheckTimeout()
{
+ if (--_timeoutChecksToSkip != 0)
+ return;
+
+ _timeoutChecksToSkip = TimeoutCheckFrequency;
+
// Note that both, Environment.TickCount and timeoutOccursAt are ints and can overflow and become negative.
// See the comment in StartTimeoutWatch().
@@ -566,7 +567,7 @@ namespace System.Text.RegularExpressions
Debug.WriteLine("Stack: " + StackDescription(runstack, runstackpos));
}
- internal static string StackDescription(int[] a, int index)
+ private static string StackDescription(int[] a, int index)
{
var sb = new StringBuilder();
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexTree.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexTree.cs
index d7e0c35847..09c29b91cc 100644
--- a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexTree.cs
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexTree.cs
@@ -11,36 +11,36 @@ namespace System.Text.RegularExpressions
{
internal sealed class RegexTree
{
- internal RegexTree(RegexNode root, Hashtable caps, int[] capnumlist, int captop, Hashtable capnames, string[] capslist, RegexOptions opts)
+ public readonly RegexNode Root;
+ public readonly Hashtable Caps;
+ public readonly int[] CapNumList;
+ public readonly int CapTop;
+ public readonly Hashtable CapNames;
+ public readonly string[] CapsList;
+ public readonly RegexOptions Options;
+
+ internal RegexTree(RegexNode root, Hashtable caps, int[] capNumList, int capTop, Hashtable capNames, string[] capsList, RegexOptions options)
{
- _root = root;
- _caps = caps;
- _capnumlist = capnumlist;
- _capnames = capnames;
- _capslist = capslist;
- _captop = captop;
- _options = opts;
+ Root = root;
+ Caps = caps;
+ CapNumList = capNumList;
+ CapTop = capTop;
+ CapNames = capNames;
+ CapsList = capsList;
+ Options = options;
}
- internal readonly RegexNode _root;
- internal readonly Hashtable _caps;
- internal readonly int[] _capnumlist;
- internal readonly Hashtable _capnames;
- internal readonly string[] _capslist;
- internal readonly RegexOptions _options;
- internal readonly int _captop;
-
#if DEBUG
- internal void Dump()
+ public void Dump()
{
- _root.Dump();
+ Root.Dump();
}
- internal bool Debug
+ public bool Debug
{
get
{
- return (_options & RegexOptions.Debug) != 0;
+ return (Options & RegexOptions.Debug) != 0;
}
}
#endif
diff --git a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexWriter.cs b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexWriter.cs
index 734f42f422..b0bc0d1e5a 100644
--- a/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexWriter.cs
+++ b/src/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexWriter.cs
@@ -18,89 +18,136 @@ using System.Globalization;
namespace System.Text.RegularExpressions
{
- internal sealed class RegexWriter
+ internal ref struct RegexWriter
{
- private int[] _intStack;
- private int _depth;
- private int[] _emitted;
- private int _curpos;
- private readonly Dictionary<string, int> _stringhash;
- private readonly List<string> _stringtable;
- private bool _counting;
- private int _count;
- private int _trackcount;
- private Hashtable _caps;
-
private const int BeforeChild = 64;
private const int AfterChild = 128;
+ // Distribution of common patterns indicates an average amount of 56 op codes.
+ private const int EmittedSize = 56;
+ private const int IntStackSize = 32;
+
+ private ValueListBuilder<int> _emitted;
+ private ValueListBuilder<int> _intStack;
+ private readonly Dictionary<string, int> _stringHash;
+ private readonly List<string> _stringTable;
+ private Hashtable _caps;
+ private int _trackCount;
+
+ private RegexWriter(Span<int> emittedSpan, Span<int> intStackSpan)
+ {
+ _emitted = new ValueListBuilder<int>(emittedSpan);
+ _intStack = new ValueListBuilder<int>(intStackSpan);
+ _stringHash = new Dictionary<string, int>();
+ _stringTable = new List<string>();
+ _caps = null;
+ _trackCount = 0;
+ }
/// <summary>
/// This is the only function that should be called from outside.
/// It takes a RegexTree and creates a corresponding RegexCode.
/// </summary>
- internal static RegexCode Write(RegexTree t)
+ public static RegexCode Write(RegexTree tree)
{
- RegexWriter w = new RegexWriter();
- RegexCode retval = w.RegexCodeFromRegexTree(t);
+ Span<int> emittedSpan = stackalloc int[EmittedSize];
+ Span<int> intStackSpan = stackalloc int[IntStackSize];
+
+ var writer = new RegexWriter(emittedSpan, intStackSpan);
+ RegexCode code = writer.RegexCodeFromRegexTree(tree);
+ writer.Dispose();
+
#if DEBUG
- if (t.Debug)
+ if (tree.Debug)
{
- t.Dump();
- retval.Dump();
+ tree.Dump();
+ code.Dump();
}
#endif
- return retval;
+
+ return code;
}
- // Private constructor; can't be created outside
- private RegexWriter()
+ /// <summary>
+ /// Return rented buffers.
+ /// </summary>
+ public void Dispose()
{
- _intStack = new int[32];
- _emitted = new int[32];
- _stringhash = new Dictionary<string, int>();
- _stringtable = new List<string>();
+ _emitted.Dispose();
+ _intStack.Dispose();
}
/// <summary>
- /// To avoid recursion, we use a simple integer stack.
- /// This is the push.
+ /// The top level RegexCode generator. It does a depth-first walk
+ /// through the tree and calls EmitFragment to emits code before
+ /// and after each child of an interior node, and at each leaf.
/// </summary>
- private void PushInt(int i)
+ public RegexCode RegexCodeFromRegexTree(RegexTree tree)
{
- if (_depth >= _intStack.Length)
+ // construct sparse capnum mapping if some numbers are unused
+ int capsize;
+ if (tree.CapNumList == null || tree.CapTop == tree.CapNumList.Length)
{
- int[] expanded = new int[_depth * 2];
+ capsize = tree.CapTop;
+ _caps = null;
+ }
+ else
+ {
+ capsize = tree.CapNumList.Length;
+ _caps = tree.Caps;
+ for (int i = 0; i < tree.CapNumList.Length; i++)
+ _caps[tree.CapNumList[i]] = i;
+ }
- Array.Copy(_intStack, 0, expanded, 0, _depth);
+ RegexNode curNode = tree.Root;
+ int curChild = 0;
- _intStack = expanded;
+ Emit(RegexCode.Lazybranch, 0);
+
+ for (; ; )
+ {
+ if (curNode.Children == null)
+ {
+ EmitFragment(curNode.NType, curNode, 0);
+ }
+ else if (curChild < curNode.Children.Count)
+ {
+ EmitFragment(curNode.NType | BeforeChild, curNode, curChild);
+
+ curNode = curNode.Children[curChild];
+ _intStack.Append(curChild);
+ curChild = 0;
+ continue;
+ }
+
+ if (_intStack.Length == 0)
+ break;
+
+ curChild = _intStack.Pop();
+ curNode = curNode.Next;
+
+ EmitFragment(curNode.NType | AfterChild, curNode, curChild);
+ curChild++;
}
- _intStack[_depth++] = i;
- }
+ PatchJump(0, _emitted.Length);
+ Emit(RegexCode.Stop);
- /// <summary>
- /// <c>true</c> if the stack is empty.
- /// </summary>
- private bool EmptyStack()
- {
- return _depth == 0;
- }
+ RegexPrefix? fcPrefix = RegexFCD.FirstChars(tree);
+ RegexPrefix prefix = RegexFCD.Prefix(tree);
+ bool rtl = ((tree.Options & RegexOptions.RightToLeft) != 0);
- /// <summary>
- /// This is the pop.
- /// </summary>
- private int PopInt()
- {
- return _intStack[--_depth];
- }
+ CultureInfo culture = (tree.Options & RegexOptions.CultureInvariant) != 0 ? CultureInfo.InvariantCulture : CultureInfo.CurrentCulture;
+ RegexBoyerMoore bmPrefix;
- /// <summary>
- /// Returns the current position in the emitted code.
- /// </summary>
- private int CurPos()
- {
- return _curpos;
+ if (prefix.Prefix.Length > 0)
+ bmPrefix = new RegexBoyerMoore(prefix.Prefix, prefix.CaseInsensitive, rtl, culture);
+ else
+ bmPrefix = null;
+
+ int anchors = RegexFCD.Anchors(tree);
+ int[] emitted = _emitted.AsSpan().ToArray();
+
+ return new RegexCode(emitted, _stringTable, _trackCount, _caps, capsize, bmPrefix, fcPrefix, anchors, rtl);
}
/// <summary>
@@ -119,14 +166,10 @@ namespace System.Text.RegularExpressions
/// </summary>
private void Emit(int op)
{
- if (_counting)
- {
- _count += 1;
- if (RegexCode.OpcodeBacktracks(op))
- _trackcount += 1;
- return;
- }
- _emitted[_curpos++] = op;
+ if (RegexCode.OpcodeBacktracks(op))
+ _trackCount++;
+
+ _emitted.Append(op);
}
/// <summary>
@@ -134,15 +177,11 @@ namespace System.Text.RegularExpressions
/// </summary>
private void Emit(int op, int opd1)
{
- if (_counting)
- {
- _count += 2;
- if (RegexCode.OpcodeBacktracks(op))
- _trackcount += 1;
- return;
- }
- _emitted[_curpos++] = op;
- _emitted[_curpos++] = opd1;
+ if (RegexCode.OpcodeBacktracks(op))
+ _trackCount++;
+
+ _emitted.Append(op);
+ _emitted.Append(opd1);
}
/// <summary>
@@ -150,16 +189,12 @@ namespace System.Text.RegularExpressions
/// </summary>
private void Emit(int op, int opd1, int opd2)
{
- if (_counting)
- {
- _count += 3;
- if (RegexCode.OpcodeBacktracks(op))
- _trackcount += 1;
- return;
- }
- _emitted[_curpos++] = op;
- _emitted[_curpos++] = opd1;
- _emitted[_curpos++] = opd2;
+ if (RegexCode.OpcodeBacktracks(op))
+ _trackCount++;
+
+ _emitted.Append(op);
+ _emitted.Append(opd1);
+ _emitted.Append(opd2);
}
/// <summary>
@@ -168,18 +203,15 @@ namespace System.Text.RegularExpressions
/// </summary>
private int StringCode(string str)
{
- if (_counting)
- return 0;
-
if (str == null)
str = string.Empty;
int i;
- if (!_stringhash.TryGetValue(str, out i))
+ if (!_stringHash.TryGetValue(str, out i))
{
- i = _stringtable.Count;
- _stringhash[str] = i;
- _stringtable.Add(str);
+ i = _stringTable.Count;
+ _stringHash[str] = i;
+ _stringTable.Add(str);
}
return i;
@@ -203,106 +235,6 @@ namespace System.Text.RegularExpressions
}
/// <summary>
- /// The top level RegexCode generator. It does a depth-first walk
- /// through the tree and calls EmitFragment to emits code before
- /// and after each child of an interior node, and at each leaf.
- ///
- /// It runs two passes, first to count the size of the generated
- /// code, and second to generate the code.
- ///
- /// We should time it against the alternative, which is
- /// to just generate the code and grow the array as we go.
- /// </summary>
- private RegexCode RegexCodeFromRegexTree(RegexTree tree)
- {
- RegexNode curNode;
- int curChild;
- int capsize;
- RegexPrefix fcPrefix;
- RegexPrefix prefix;
- int anchors;
- RegexBoyerMoore bmPrefix;
- bool rtl;
-
- // construct sparse capnum mapping if some numbers are unused
-
- if (tree._capnumlist == null || tree._captop == tree._capnumlist.Length)
- {
- capsize = tree._captop;
- _caps = null;
- }
- else
- {
- capsize = tree._capnumlist.Length;
- _caps = tree._caps;
- for (int i = 0; i < tree._capnumlist.Length; i++)
- _caps[tree._capnumlist[i]] = i;
- }
-
- _counting = true;
-
- for (; ;)
- {
- if (!_counting)
- _emitted = new int[_count];
-
- curNode = tree._root;
- curChild = 0;
-
- Emit(RegexCode.Lazybranch, 0);
-
- for (; ;)
- {
- if (curNode._children == null)
- {
- EmitFragment(curNode._type, curNode, 0);
- }
- else if (curChild < curNode._children.Count)
- {
- EmitFragment(curNode._type | BeforeChild, curNode, curChild);
-
- curNode = curNode._children[curChild];
- PushInt(curChild);
- curChild = 0;
- continue;
- }
-
- if (EmptyStack())
- break;
-
- curChild = PopInt();
- curNode = curNode._next;
-
- EmitFragment(curNode._type | AfterChild, curNode, curChild);
- curChild++;
- }
-
- PatchJump(0, CurPos());
- Emit(RegexCode.Stop);
-
- if (!_counting)
- break;
-
- _counting = false;
- }
-
- fcPrefix = RegexFCD.FirstChars(tree);
-
- prefix = RegexFCD.Prefix(tree);
- rtl = ((tree._options & RegexOptions.RightToLeft) != 0);
-
- CultureInfo culture = (tree._options & RegexOptions.CultureInvariant) != 0 ? CultureInfo.InvariantCulture : CultureInfo.CurrentCulture;
- if (prefix != null && prefix.Prefix.Length > 0)
- bmPrefix = new RegexBoyerMoore(prefix.Prefix, prefix.CaseInsensitive, rtl, culture);
- else
- bmPrefix = null;
-
- anchors = RegexFCD.Anchors(tree);
-
- return new RegexCode(_emitted, _stringtable, _trackcount, _caps, capsize, bmPrefix, fcPrefix, anchors, rtl);
- }
-
- /// <summary>
/// The main RegexCode generator. It does a depth-first walk
/// through the tree and calls EmitFragment to emits code before
/// and after each child of an interior node, and at each leaf.
@@ -315,7 +247,7 @@ namespace System.Text.RegularExpressions
{
if (node.UseOptionR())
bits |= RegexCode.Rtl;
- if ((node._options & RegexOptions.IgnoreCase) != 0)
+ if ((node.Options & RegexOptions.IgnoreCase) != 0)
bits |= RegexCode.Ci;
}
@@ -327,28 +259,28 @@ namespace System.Text.RegularExpressions
break;
case RegexNode.Alternate | BeforeChild:
- if (curIndex < node._children.Count - 1)
+ if (curIndex < node.Children.Count - 1)
{
- PushInt(CurPos());
+ _intStack.Append(_emitted.Length);
Emit(RegexCode.Lazybranch, 0);
}
break;
case RegexNode.Alternate | AfterChild:
{
- if (curIndex < node._children.Count - 1)
+ if (curIndex < node.Children.Count - 1)
{
- int LBPos = PopInt();
- PushInt(CurPos());
+ int LBPos = _intStack.Pop();
+ _intStack.Append(_emitted.Length);
Emit(RegexCode.Goto, 0);
- PatchJump(LBPos, CurPos());
+ PatchJump(LBPos, _emitted.Length);
}
else
{
int I;
for (I = 0; I < curIndex; I++)
{
- PatchJump(PopInt(), CurPos());
+ PatchJump(_intStack.Pop(), _emitted.Length);
}
}
break;
@@ -359,9 +291,9 @@ namespace System.Text.RegularExpressions
{
case 0:
Emit(RegexCode.Setjump);
- PushInt(CurPos());
+ _intStack.Append(_emitted.Length);
Emit(RegexCode.Lazybranch, 0);
- Emit(RegexCode.Testref, MapCapnum(node._m));
+ Emit(RegexCode.Testref, MapCapnum(node.M));
Emit(RegexCode.Forejump);
break;
}
@@ -372,18 +304,18 @@ namespace System.Text.RegularExpressions
{
case 0:
{
- int Branchpos = PopInt();
- PushInt(CurPos());
+ int Branchpos = _intStack.Pop();
+ _intStack.Append(_emitted.Length);
Emit(RegexCode.Goto, 0);
- PatchJump(Branchpos, CurPos());
+ PatchJump(Branchpos, _emitted.Length);
Emit(RegexCode.Forejump);
- if (node._children.Count > 1)
+ if (node.Children.Count > 1)
break;
// else fallthrough
goto case 1;
}
case 1:
- PatchJump(PopInt(), CurPos());
+ PatchJump(_intStack.Pop(), _emitted.Length);
break;
}
break;
@@ -394,7 +326,7 @@ namespace System.Text.RegularExpressions
case 0:
Emit(RegexCode.Setjump);
Emit(RegexCode.Setmark);
- PushInt(CurPos());
+ _intStack.Append(_emitted.Length);
Emit(RegexCode.Lazybranch, 0);
break;
}
@@ -408,19 +340,19 @@ namespace System.Text.RegularExpressions
Emit(RegexCode.Forejump);
break;
case 1:
- int Branchpos = PopInt();
- PushInt(CurPos());
+ int Branchpos = _intStack.Pop();
+ _intStack.Append(_emitted.Length);
Emit(RegexCode.Goto, 0);
- PatchJump(Branchpos, CurPos());
+ PatchJump(Branchpos, _emitted.Length);
Emit(RegexCode.Getmark);
Emit(RegexCode.Forejump);
- if (node._children.Count > 2)
+ if (node.Children.Count > 2)
break;
// else fallthrough
goto case 2;
case 2:
- PatchJump(PopInt(), CurPos());
+ PatchJump(_intStack.Pop(), _emitted.Length);
break;
}
break;
@@ -428,32 +360,32 @@ namespace System.Text.RegularExpressions
case RegexNode.Loop | BeforeChild:
case RegexNode.Lazyloop | BeforeChild:
- if (node._n < int.MaxValue || node._m > 1)
- Emit(node._m == 0 ? RegexCode.Nullcount : RegexCode.Setcount, node._m == 0 ? 0 : 1 - node._m);
+ if (node.N < int.MaxValue || node.M > 1)
+ Emit(node.M == 0 ? RegexCode.Nullcount : RegexCode.Setcount, node.M == 0 ? 0 : 1 - node.M);
else
- Emit(node._m == 0 ? RegexCode.Nullmark : RegexCode.Setmark);
+ Emit(node.M == 0 ? RegexCode.Nullmark : RegexCode.Setmark);
- if (node._m == 0)
+ if (node.M == 0)
{
- PushInt(CurPos());
+ _intStack.Append(_emitted.Length);
Emit(RegexCode.Goto, 0);
}
- PushInt(CurPos());
+ _intStack.Append(_emitted.Length);
break;
case RegexNode.Loop | AfterChild:
case RegexNode.Lazyloop | AfterChild:
{
- int StartJumpPos = CurPos();
+ int StartJumpPos = _emitted.Length;
int Lazy = (nodetype - (RegexNode.Loop | AfterChild));
- if (node._n < int.MaxValue || node._m > 1)
- Emit(RegexCode.Branchcount + Lazy, PopInt(), node._n == int.MaxValue ? int.MaxValue : node._n - node._m);
+ if (node.N < int.MaxValue || node.M > 1)
+ Emit(RegexCode.Branchcount + Lazy, _intStack.Pop(), node.N == int.MaxValue ? int.MaxValue : node.N - node.M);
else
- Emit(RegexCode.Branchmark + Lazy, PopInt());
+ Emit(RegexCode.Branchmark + Lazy, _intStack.Pop());
- if (node._m == 0)
- PatchJump(PopInt(), StartJumpPos);
+ if (node.M == 0)
+ PatchJump(_intStack.Pop(), StartJumpPos);
}
break;
@@ -466,7 +398,7 @@ namespace System.Text.RegularExpressions
break;
case RegexNode.Capture | AfterChild:
- Emit(RegexCode.Capturemark, MapCapnum(node._m), MapCapnum(node._n));
+ Emit(RegexCode.Capturemark, MapCapnum(node.M), MapCapnum(node.N));
break;
case RegexNode.Require | BeforeChild:
@@ -489,13 +421,13 @@ namespace System.Text.RegularExpressions
case RegexNode.Prevent | BeforeChild:
Emit(RegexCode.Setjump);
- PushInt(CurPos());
+ _intStack.Append(_emitted.Length);
Emit(RegexCode.Lazybranch, 0);
break;
case RegexNode.Prevent | AfterChild:
Emit(RegexCode.Backjump);
- PatchJump(PopInt(), CurPos());
+ PatchJump(_intStack.Pop(), _emitted.Length);
Emit(RegexCode.Forejump);
break;
@@ -509,40 +441,40 @@ namespace System.Text.RegularExpressions
case RegexNode.One:
case RegexNode.Notone:
- Emit(node._type | bits, node._ch);
+ Emit(node.NType | bits, node.Ch);
break;
case RegexNode.Notoneloop:
case RegexNode.Notonelazy:
case RegexNode.Oneloop:
case RegexNode.Onelazy:
- if (node._m > 0)
- Emit(((node._type == RegexNode.Oneloop || node._type == RegexNode.Onelazy) ?
- RegexCode.Onerep : RegexCode.Notonerep) | bits, node._ch, node._m);
- if (node._n > node._m)
- Emit(node._type | bits, node._ch, node._n == int.MaxValue ?
- int.MaxValue : node._n - node._m);
+ if (node.M > 0)
+ Emit(((node.NType == RegexNode.Oneloop || node.NType == RegexNode.Onelazy) ?
+ RegexCode.Onerep : RegexCode.Notonerep) | bits, node.Ch, node.M);
+ if (node.N > node.M)
+ Emit(node.NType | bits, node.Ch, node.N == int.MaxValue ?
+ int.MaxValue : node.N - node.M);
break;
case RegexNode.Setloop:
case RegexNode.Setlazy:
- if (node._m > 0)
- Emit(RegexCode.Setrep | bits, StringCode(node._str), node._m);
- if (node._n > node._m)
- Emit(node._type | bits, StringCode(node._str),
- (node._n == int.MaxValue) ? int.MaxValue : node._n - node._m);
+ if (node.M > 0)
+ Emit(RegexCode.Setrep | bits, StringCode(node.Str), node.M);
+ if (node.N > node.M)
+ Emit(node.NType | bits, StringCode(node.Str),
+ (node.N == int.MaxValue) ? int.MaxValue : node.N - node.M);
break;
case RegexNode.Multi:
- Emit(node._type | bits, StringCode(node._str));
+ Emit(node.NType | bits, StringCode(node.Str));
break;
case RegexNode.Set:
- Emit(node._type | bits, StringCode(node._str));
+ Emit(node.NType | bits, StringCode(node.Str));
break;
case RegexNode.Ref:
- Emit(node._type | bits, MapCapnum(node._m));
+ Emit(node.NType | bits, MapCapnum(node.M));
break;
case RegexNode.Nothing:
@@ -556,7 +488,7 @@ namespace System.Text.RegularExpressions
case RegexNode.Start:
case RegexNode.EndZ:
case RegexNode.End:
- Emit(node._type);
+ Emit(node.NType);
break;
default:
diff --git a/src/System.Text.RegularExpressions/tests/Performance/Configurations.props b/src/System.Text.RegularExpressions/tests/Performance/Configurations.props
new file mode 100644
index 0000000000..2845c11c54
--- /dev/null
+++ b/src/System.Text.RegularExpressions/tests/Performance/Configurations.props
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <BuildConfigurations>
+ netcoreapp;
+ </BuildConfigurations>
+ </PropertyGroup>
+</Project> \ No newline at end of file
diff --git a/src/System.Text.RegularExpressions/tests/Performance/Perf.Regex.Cache.cs b/src/System.Text.RegularExpressions/tests/Performance/Perf.Regex.Cache.cs
new file mode 100644
index 0000000000..7ed8b7c20a
--- /dev/null
+++ b/src/System.Text.RegularExpressions/tests/Performance/Perf.Regex.Cache.cs
@@ -0,0 +1,122 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.Xunit.Performance;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace System.Text.RegularExpressions.Tests
+{
+ public class Perf_Regex_Cache
+ {
+ private const int MaxConcurrency = 4;
+ private volatile bool _isMatch;
+
+ private static string[] CreatePatterns(int total, int unique)
+ {
+ var regexps = new string[total];
+ // create:
+ {
+ var i = 0;
+ for (; i < unique; i++)
+ {
+ // "(0+)" "(1+)" .. "(9+)(9+)(8+)" ..
+ var sb = new StringBuilder();
+ foreach (var c in i.ToString())
+ sb.Append("(" + c + "+)");
+ regexps[i] = sb.ToString();
+ }
+ for (; i < total; i++) regexps[i] = regexps[i % unique];
+ }
+
+ // shuffle:
+ const int someSeed = 101; // seed for reproducability
+ var random = new Random(someSeed);
+ for (var i = 0; i < total; i++)
+ {
+ var r = random.Next(i, total);
+ var t = regexps[i];
+ regexps[i] = regexps[r];
+ regexps[r] = t;
+ }
+
+ return regexps;
+ }
+
+ [Benchmark]
+ [MeasureGCAllocations]
+ [InlineData(400_000, 7, 15)] // default size, most common
+ [InlineData(400_000, 1, 15)] // default size, to test MRU
+ [InlineData(40_000, 7, 0)] // cache turned off
+ [InlineData(40_000, 1_600, 15)] // default size, to compare when cache used
+ [InlineData(40_000, 1_600, 800)] // larger size, to test cache is not O(n)
+ [InlineData(40_000, 1_600, 3_200)] // larger size, to test cache always hit
+ public void IsMatch(int total, int unique, int cacheSize)
+ {
+ var cacheSizeOld = Regex.CacheSize;
+ string[] patterns = CreatePatterns(total, unique);
+
+ try
+ {
+ Regex.CacheSize = 0; // clean up cache
+ Regex.CacheSize = cacheSize;
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ using (iteration.StartMeasurement())
+ RunTest(0, total, patterns);
+ }
+ finally
+ {
+ Regex.CacheSize = cacheSizeOld;
+ }
+ }
+
+ private void RunTest(int start, int total, string[] regexps)
+ {
+ for (var i = 0; i < total; i++)
+ _isMatch = Regex.IsMatch("0123456789", regexps[start + i]);
+ }
+
+ [Benchmark]
+ [MeasureGCAllocations]
+ [InlineData(400_000, 7, 15)] // default size, most common
+ [InlineData(400_000, 1, 15)] // default size, to test MRU
+ [InlineData(40_000, 7, 0)] // cache turned off
+ [InlineData(40_000, 1_600, 15)] // default size, to compare when cache used
+ [InlineData(40_000, 1_600, 800)] // larger size, to test cache is not O(n)
+ [InlineData(40_000, 1_600, 3_200)] // larger size, to test cache always hit
+ public async Task IsMatch_Multithreading(int total, int unique, int cacheSize)
+ {
+ int cacheSizeOld = Regex.CacheSize;
+ string[] patterns = CreatePatterns(total, unique);
+
+ try
+ {
+ Regex.CacheSize = 0; // clean up cache
+ Regex.CacheSize = cacheSize;
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ int sliceLength = total / MaxConcurrency;
+ var tasks = new Task[MaxConcurrency];
+
+ for (int i = 0; i < MaxConcurrency; i++)
+ {
+ int start = i * sliceLength;
+ tasks[i] = Task.Run(() => RunTest(start, sliceLength, patterns));
+ }
+
+ await Task.WhenAll(tasks);
+ }
+ }
+ }
+ finally
+ {
+ Regex.CacheSize = cacheSizeOld;
+ }
+ }
+ }
+}
diff --git a/src/System.Text.RegularExpressions/tests/Performance/Perf.Regex.cs b/src/System.Text.RegularExpressions/tests/Performance/Perf.Regex.cs
new file mode 100644
index 0000000000..96718a624f
--- /dev/null
+++ b/src/System.Text.RegularExpressions/tests/Performance/Perf.Regex.cs
@@ -0,0 +1,452 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using Microsoft.Xunit.Performance;
+
+namespace System.Text.RegularExpressions.Tests
+{
+ /// <summary>
+ /// Performance tests for Regular Expressions
+ /// </summary>
+ public class Perf_Regex
+ {
+ private const int InnerIterations = 100;
+
+ [Benchmark]
+ [MeasureGCAllocations]
+ public void Match()
+ {
+ var cacheSizeOld = Regex.CacheSize;
+ try
+ {
+ Regex.CacheSize = 0; // disable cache to get clearer results
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ using (iteration.StartMeasurement())
+ {
+ for (int i = 0; i < InnerIterations; i++)
+ {
+ foreach (var test in Match_TestData())
+ Regex.Match((string)test[1], (string)test[0], (RegexOptions)test[2]);
+ }
+ }
+ }
+ }
+ finally
+ {
+ Regex.CacheSize = cacheSizeOld;
+ }
+ }
+
+ // A series of patterns (all valid and non pathological) and inputs (which they may or may not match)
+ public static IEnumerable<object[]> Match_TestData()
+ {
+ yield return new object[] { "[abcd-[d]]+", "dddaabbccddd", RegexOptions.None };
+ yield return new object[] { @"[\d-[357]]+", "33312468955", RegexOptions.None };
+ yield return new object[] { @"[\d-[357]]+", "51246897", RegexOptions.None };
+ yield return new object[] { @"[\d-[357]]+", "3312468977", RegexOptions.None };
+ yield return new object[] { @"[\w-[b-y]]+", "bbbaaaABCD09zzzyyy", RegexOptions.None };
+ yield return new object[] { @"[\w-[\d]]+", "0AZaz9", RegexOptions.None };
+ yield return new object[] { @"[\w-[\p{Ll}]]+", "a09AZz", RegexOptions.None };
+ yield return new object[] { @"[\d-[13579]]+", "1024689", RegexOptions.ECMAScript };
+ yield return new object[] { @"[\d-[13579]]+", "\x066102468\x0660", RegexOptions.ECMAScript };
+ yield return new object[] { @"[\d-[13579]]+", "\x066102468\x0660", RegexOptions.None };
+ yield return new object[] { @"[\w-[b-y]]+", "bbbaaaABCD09zzzyyy", RegexOptions.None };
+ yield return new object[] { @"[\w-[b-y]]+", "bbbaaaABCD09zzzyyy", RegexOptions.None };
+ yield return new object[] { @"[\w-[b-y]]+", "bbbaaaABCD09zzzyyy", RegexOptions.None };
+ yield return new object[] { @"[\p{Ll}-[ae-z]]+", "aaabbbcccdddeee", RegexOptions.None };
+ yield return new object[] { @"[\p{Nd}-[2468]]+", "20135798", RegexOptions.None };
+ yield return new object[] { @"[\P{Lu}-[ae-z]]+", "aaabbbcccdddeee", RegexOptions.None };
+ yield return new object[] { @"[\P{Nd}-[\p{Ll}]]+", "az09AZ'[]", RegexOptions.None };
+ yield return new object[] { "[abcd-[def]]+", "fedddaabbccddd", RegexOptions.None };
+ yield return new object[] { @"[\d-[357a-z]]+", "az33312468955", RegexOptions.None };
+ yield return new object[] { @"[\d-[de357fgA-Z]]+", "AZ51246897", RegexOptions.None };
+ yield return new object[] { @"[\d-[357\p{Ll}]]+", "az3312468977", RegexOptions.None };
+ yield return new object[] { @"[\w-[b-y\s]]+", " \tbbbaaaABCD09zzzyyy", RegexOptions.None };
+ yield return new object[] { @"[\w-[\d\p{Po}]]+", "!#0AZaz9", RegexOptions.None };
+ yield return new object[] { @"[\w-[\p{Ll}\s]]+", "a09AZz", RegexOptions.None };
+ yield return new object[] { @"[\d-[13579a-zA-Z]]+", "AZ1024689", RegexOptions.ECMAScript };
+ yield return new object[] { @"[\d-[13579abcd]]+", "abcd\x066102468\x0660", RegexOptions.ECMAScript };
+ yield return new object[] { @"[\d-[13579\s]]+", " \t\x066102468\x0660", RegexOptions.None };
+ yield return new object[] { @"[\w-[b-y\p{Po}]]+", "!#bbbaaaABCD09zzzyyy", RegexOptions.None };
+ yield return new object[] { @"[\w-[b-y!.,]]+", "!.,bbbaaaABCD09zzzyyy", RegexOptions.None };
+ yield return new object[] { "[\\w-[b-y\x00-\x0F]]+", "\0bbbaaaABCD09zzzyyy", RegexOptions.None };
+ yield return new object[] { @"[\p{Ll}-[ae-z0-9]]+", "09aaabbbcccdddeee", RegexOptions.None };
+ yield return new object[] { @"[\p{Nd}-[2468az]]+", "az20135798", RegexOptions.None };
+ yield return new object[] { @"[\P{Lu}-[ae-zA-Z]]+", "AZaaabbbcccdddeee", RegexOptions.None };
+ yield return new object[] { @"[\P{Nd}-[\p{Ll}0123456789]]+", "09az09AZ'[]", RegexOptions.None };
+ yield return new object[] { "[abc-[defg]]+", "dddaabbccddd", RegexOptions.None };
+ yield return new object[] { @"[\d-[abc]]+", "abc09abc", RegexOptions.None };
+ yield return new object[] { @"[\d-[a-zA-Z]]+", "az09AZ", RegexOptions.None };
+ yield return new object[] { @"[\d-[\p{Ll}]]+", "az09az", RegexOptions.None };
+ yield return new object[] { @"[\w-[\x00-\x0F]]+", "bbbaaaABYZ09zzzyyy", RegexOptions.None };
+ yield return new object[] { @"[\w-[\s]]+", "0AZaz9", RegexOptions.None };
+ yield return new object[] { @"[\w-[\W]]+", "0AZaz9", RegexOptions.None };
+ yield return new object[] { @"[\w-[\p{Po}]]+", "#a09AZz!", RegexOptions.None };
+ yield return new object[] { @"[\d-[\D]]+", "azAZ1024689", RegexOptions.ECMAScript };
+ yield return new object[] { @"[\d-[a-zA-Z]]+", "azAZ\x066102468\x0660", RegexOptions.ECMAScript };
+ yield return new object[] { @"[\d-[\p{Ll}]]+", "\x066102468\x0660", RegexOptions.None };
+ yield return new object[] { @"[a-zA-Z0-9-[\s]]+", " \tazAZ09", RegexOptions.None };
+ yield return new object[] { @"[a-zA-Z0-9-[\W]]+", "bbbaaaABCD09zzzyyy", RegexOptions.None };
+ yield return new object[] { @"[a-zA-Z0-9-[^a-zA-Z0-9]]+", "bbbaaaABCD09zzzyyy", RegexOptions.None };
+ yield return new object[] { @"[\p{Ll}-[A-Z]]+", "AZaz09", RegexOptions.None };
+ yield return new object[] { @"[\p{Nd}-[a-z]]+", "az09", RegexOptions.None };
+ yield return new object[] { @"[\P{Lu}-[\p{Lu}]]+", "AZazAZ", RegexOptions.None };
+ yield return new object[] { @"[\P{Lu}-[A-Z]]+", "AZazAZ", RegexOptions.None };
+ yield return new object[] { @"[\P{Nd}-[\p{Nd}]]+", "azAZ09", RegexOptions.None };
+ yield return new object[] { @"[\P{Nd}-[2-8]]+", "1234567890azAZ1234567890", RegexOptions.None };
+ yield return new object[] { @"([ ]|[\w-[0-9]])+", "09az AZ90", RegexOptions.None };
+ yield return new object[] { @"([0-9-[02468]]|[0-9-[13579]])+", "az1234567890za", RegexOptions.None };
+ yield return new object[] { @"([^0-9-[a-zAE-Z]]|[\w-[a-zAF-Z]])+", "azBCDE1234567890BCDEFza", RegexOptions.None };
+ yield return new object[] { @"([\p{Ll}-[aeiou]]|[^\w-[\s]])+", "aeiobcdxyz!@#aeio", RegexOptions.None };
+ yield return new object[] { @"98[\d-[9]][\d-[8]][\d-[0]]", "98911 98881 98870 98871", RegexOptions.None };
+ yield return new object[] { @"m[\w-[^aeiou]][\w-[^aeiou]]t", "mbbt mect meet", RegexOptions.None };
+ yield return new object[] { "[abcdef-[^bce]]+", "adfbcefda", RegexOptions.None };
+ yield return new object[] { "[^cde-[ag]]+", "agbfxyzga", RegexOptions.None };
+ yield return new object[] { @"[\p{L}-[^\p{Lu}]]+", "09',.abcxyzABCXYZ", RegexOptions.None };
+ yield return new object[] { @"[\p{IsGreek}-[\P{Lu}]]+", "\u0390\u03FE\u0386\u0388\u03EC\u03EE\u0400", RegexOptions.None };
+ yield return new object[] { @"[\p{IsBasicLatin}-[G-L]]+", "GAFMZL", RegexOptions.None };
+ yield return new object[] { "[a-zA-Z-[aeiouAEIOU]]+", "aeiouAEIOUbcdfghjklmnpqrstvwxyz", RegexOptions.None };
+ yield return new object[] { @"^
+ (?<octet>^
+ (
+ (
+ (?<Octet2xx>[\d-[013-9]])
+ |
+ [\d-[2-9]]
+ )
+ (?(Octet2xx)
+ (
+ (?<Octet25x>[\d-[01-46-9]])
+ |
+ [\d-[5-9]]
+ )
+ (
+ (?(Octet25x)
+ [\d-[6-9]]
+ |
+ [\d]
+ )
+ )
+ |
+ [\d]{2}
+ )
+ )
+ |
+ ([\d][\d])
+ |
+ [\d]
+ )$"
+ , "255", RegexOptions.IgnorePatternWhitespace };
+ yield return new object[] { @"[abcd\-d-[bc]]+", "bbbaaa---dddccc", RegexOptions.None };
+ yield return new object[] { @"[abcd\-d-[bc]]+", "bbbaaa---dddccc", RegexOptions.None };
+ yield return new object[] { @"[^a-f-[\x00-\x60\u007B-\uFFFF]]+", "aaafffgggzzz{{{", RegexOptions.None };
+ yield return new object[] { @"[\[\]a-f-[[]]+", "gggaaafff]]][[[", RegexOptions.None };
+ yield return new object[] { @"[\[\]a-f-[]]]+", "gggaaafff[[[]]]", RegexOptions.None };
+ yield return new object[] { @"[ab\-\[cd-[-[]]]]", "a]]", RegexOptions.None };
+ yield return new object[] { @"[ab\-\[cd-[-[]]]]", "b]]", RegexOptions.None };
+ yield return new object[] { @"[ab\-\[cd-[-[]]]]", "c]]", RegexOptions.None };
+ yield return new object[] { @"[ab\-\[cd-[-[]]]]", "d]]", RegexOptions.None };
+ yield return new object[] { @"[ab\-\[cd-[[]]]]", "a]]", RegexOptions.None };
+ yield return new object[] { @"[ab\-\[cd-[[]]]]", "b]]", RegexOptions.None };
+ yield return new object[] { @"[ab\-\[cd-[[]]]]", "c]]", RegexOptions.None };
+ yield return new object[] { @"[ab\-\[cd-[[]]]]", "d]]", RegexOptions.None };
+ yield return new object[] { @"[ab\-\[cd-[[]]]]", "-]]", RegexOptions.None };
+ yield return new object[] { @"[a-[c-e]]+", "bbbaaaccc", RegexOptions.None };
+ yield return new object[] { @"[a-[c-e]]+", "```aaaccc", RegexOptions.None };
+ yield return new object[] { @"[a-d\--[bc]]+", "cccaaa--dddbbb", RegexOptions.None };
+ yield return new object[] { @"[\0- [bc]+", "!!!\0\0\t\t [[[[bbbcccaaa", RegexOptions.None };
+ yield return new object[] { "[[abcd]-[bc]]+", "a-b]", RegexOptions.None };
+ yield return new object[] { "[-[e-g]+", "ddd[[[---eeefffggghhh", RegexOptions.None };
+ yield return new object[] { "[-e-g]+", "ddd---eeefffggghhh", RegexOptions.None };
+ yield return new object[] { "[-e-g]+", "ddd---eeefffggghhh", RegexOptions.None };
+ yield return new object[] { "[a-e - m-p]+", "---a b c d e m n o p---", RegexOptions.None };
+ yield return new object[] { "[^-[bc]]", "b] c] -] aaaddd]", RegexOptions.None };
+ yield return new object[] { "[^-[bc]]", "b] c] -] aaa]ddd]", RegexOptions.None };
+ yield return new object[] { @"[a\-[bc]+", "```bbbaaa---[[[cccddd", RegexOptions.None };
+ yield return new object[] { @"[a\-[\-\-bc]+", "```bbbaaa---[[[cccddd", RegexOptions.None };
+ yield return new object[] { @"[a\-\[\-\[\-bc]+", "```bbbaaa---[[[cccddd", RegexOptions.None };
+ yield return new object[] { @"[abc\--[b]]+", "[[[```bbbaaa---cccddd", RegexOptions.None };
+ yield return new object[] { @"[abc\-z-[b]]+", "```aaaccc---zzzbbb", RegexOptions.None };
+ yield return new object[] { @"[a-d\-[b]+", "```aaabbbcccddd----[[[[]]]", RegexOptions.None };
+ yield return new object[] { @"[abcd\-d\-[bc]+", "bbbaaa---[[[dddccc", RegexOptions.None };
+ yield return new object[] { "[a - c - [ b ] ]+", "dddaaa ccc [[[[ bbb ]]]", RegexOptions.IgnorePatternWhitespace };
+ yield return new object[] { "[a - c - [ b ] +", "dddaaa ccc [[[[ bbb ]]]", RegexOptions.IgnorePatternWhitespace };
+ yield return new object[] { @"(\p{Lu}\w*)\s(\p{Lu}\w*)", "Hello World", RegexOptions.None };
+ yield return new object[] { @"(\p{Lu}\p{Ll}*)\s(\p{Lu}\p{Ll}*)", "Hello World", RegexOptions.None };
+ yield return new object[] { @"(\P{Ll}\p{Ll}*)\s(\P{Ll}\p{Ll}*)", "Hello World", RegexOptions.None };
+ yield return new object[] { @"(\P{Lu}+\p{Lu})\s(\P{Lu}+\p{Lu})", "hellO worlD", RegexOptions.None };
+ yield return new object[] { @"(\p{Lt}\w*)\s(\p{Lt}*\w*)", "\u01C5ello \u01C5orld", RegexOptions.None };
+ yield return new object[] { @"(\P{Lt}\w*)\s(\P{Lt}*\w*)", "Hello World", RegexOptions.None };
+ yield return new object[] { @"[@-D]+", "eE?@ABCDabcdeE", RegexOptions.IgnoreCase };
+ yield return new object[] { @"[>-D]+", "eE=>?@ABCDabcdeE", RegexOptions.IgnoreCase };
+ yield return new object[] { @"[\u0554-\u0557]+", "\u0583\u0553\u0554\u0555\u0556\u0584\u0585\u0586\u0557\u0558", RegexOptions.IgnoreCase };
+ yield return new object[] { @"[X-\]]+", "wWXYZxyz[\\]^", RegexOptions.IgnoreCase };
+ yield return new object[] { @"[X-\u0533]+", "\u0551\u0554\u0560AXYZaxyz\u0531\u0532\u0533\u0561\u0562\u0563\u0564", RegexOptions.IgnoreCase };
+ yield return new object[] { @"[X-a]+", "wWAXYZaxyz", RegexOptions.IgnoreCase };
+ yield return new object[] { @"[X-c]+", "wWABCXYZabcxyz", RegexOptions.IgnoreCase };
+ yield return new object[] { @"[X-\u00C0]+", "\u00C1\u00E1\u00C0\u00E0wWABCXYZabcxyz", RegexOptions.IgnoreCase };
+ yield return new object[] { @"[\u0100\u0102\u0104]+", "\u00FF \u0100\u0102\u0104\u0101\u0103\u0105\u0106", RegexOptions.IgnoreCase };
+ yield return new object[] { @"[B-D\u0130]+", "aAeE\u0129\u0131\u0068 BCDbcD\u0130\u0069\u0070", RegexOptions.IgnoreCase };
+ yield return new object[] { @"[\u013B\u013D\u013F]+", "\u013A\u013B\u013D\u013F\u013C\u013E\u0140\u0141", RegexOptions.IgnoreCase };
+ yield return new object[] { "(Cat)\r(Dog)", "Cat\rDog", RegexOptions.None };
+ yield return new object[] { "(Cat)\t(Dog)", "Cat\tDog", RegexOptions.None };
+ yield return new object[] { "(Cat)\f(Dog)", "Cat\fDog", RegexOptions.None };
+ yield return new object[] { @"{5", "hello {5 world", RegexOptions.None };
+ yield return new object[] { @"{5,", "hello {5, world", RegexOptions.None };
+ yield return new object[] { @"{5,6", "hello {5,6 world", RegexOptions.None };
+ yield return new object[] { @"(?n:(?<cat>cat)(\s+)(?<dog>dog))", "cat dog", RegexOptions.None };
+ yield return new object[] { @"(?n:(cat)(\s+)(dog))", "cat dog", RegexOptions.None };
+ yield return new object[] { @"(?n:(cat)(?<SpaceChars>\s+)(dog))", "cat dog", RegexOptions.None };
+ yield return new object[] { @"(?x:
+ (?<cat>cat) # Cat statement
+ (\s+) # Whitespace chars
+ (?<dog>dog # Dog statement
+ ))", "cat dog", RegexOptions.None };
+ yield return new object[] { @"(?+i:cat)", "CAT", RegexOptions.None };
+ yield return new object[] { @"cat([\d]*)dog", "hello123cat230927dog1412d", RegexOptions.None };
+ yield return new object[] { @"([\D]*)dog", "65498catdog58719", RegexOptions.None };
+ yield return new object[] { @"cat([\s]*)dog", "wiocat dog3270", RegexOptions.None };
+ yield return new object[] { @"cat([\S]*)", "sfdcatdog 3270", RegexOptions.None };
+ yield return new object[] { @"cat([\w]*)", "sfdcatdog 3270", RegexOptions.None };
+ yield return new object[] { @"cat([\W]*)dog", "wiocat dog3270", RegexOptions.None };
+ yield return new object[] { @"([\p{Lu}]\w*)\s([\p{Lu}]\w*)", "Hello World", RegexOptions.None };
+ yield return new object[] { @"([\P{Ll}][\p{Ll}]*)\s([\P{Ll}][\p{Ll}]*)", "Hello World", RegexOptions.None };
+ yield return new object[] { @"(cat)([\x41]*)(dog)", "catAAAdog", RegexOptions.None };
+ yield return new object[] { @"(cat)([\u0041]*)(dog)", "catAAAdog", RegexOptions.None };
+ yield return new object[] { @"(cat)([\a]*)(dog)", "cat\a\a\adog", RegexOptions.None };
+ yield return new object[] { @"(cat)([\b]*)(dog)", "cat\b\b\bdog", RegexOptions.None };
+ yield return new object[] { @"(cat)([\e]*)(dog)", "cat\u001B\u001B\u001Bdog", RegexOptions.None };
+ yield return new object[] { @"(cat)([\f]*)(dog)", "cat\f\f\fdog", RegexOptions.None };
+ yield return new object[] { @"(cat)([\r]*)(dog)", "cat\r\r\rdog", RegexOptions.None };
+ yield return new object[] { @"(cat)([\v]*)(dog)", "cat\v\v\vdog", RegexOptions.None };
+ yield return new object[] { @"cat([\d]*)dog", "hello123cat230927dog1412d", RegexOptions.ECMAScript };
+ yield return new object[] { @"([\D]*)dog", "65498catdog58719", RegexOptions.ECMAScript };
+ yield return new object[] { @"cat([\s]*)dog", "wiocat dog3270", RegexOptions.ECMAScript };
+ yield return new object[] { @"cat([\S]*)", "sfdcatdog 3270", RegexOptions.ECMAScript };
+ yield return new object[] { @"cat([\w]*)", "sfdcatdog 3270", RegexOptions.ECMAScript };
+ yield return new object[] { @"cat([\W]*)dog", "wiocat dog3270", RegexOptions.ECMAScript };
+ yield return new object[] { @"([\p{Lu}]\w*)\s([\p{Lu}]\w*)", "Hello World", RegexOptions.ECMAScript };
+ yield return new object[] { @"([\P{Ll}][\p{Ll}]*)\s([\P{Ll}][\p{Ll}]*)", "Hello World", RegexOptions.ECMAScript };
+ yield return new object[] { @"(cat)\d*dog", "hello123cat230927dog1412d", RegexOptions.ECMAScript };
+ yield return new object[] { @"\D*(dog)", "65498catdog58719", RegexOptions.ECMAScript };
+ yield return new object[] { @"(cat)\s*(dog)", "wiocat dog3270", RegexOptions.ECMAScript };
+ yield return new object[] { @"(cat)\S*", "sfdcatdog 3270", RegexOptions.ECMAScript };
+ yield return new object[] { @"(cat)\w*", "sfdcatdog 3270", RegexOptions.ECMAScript };
+ yield return new object[] { @"(cat)\W*(dog)", "wiocat dog3270", RegexOptions.ECMAScript };
+ yield return new object[] { @"\p{Lu}(\w*)\s\p{Lu}(\w*)", "Hello World", RegexOptions.ECMAScript };
+ yield return new object[] { @"\P{Ll}\p{Ll}*\s\P{Ll}\p{Ll}*", "Hello World", RegexOptions.ECMAScript };
+ yield return new object[] { @"cat(?<dog121>dog)", "catcatdogdogcat", RegexOptions.None };
+ yield return new object[] { @"(?<cat>cat)\s*(?<cat>dog)", "catcat dogdogcat", RegexOptions.None };
+ yield return new object[] { @"(?<1>cat)\s*(?<1>dog)", "catcat dogdogcat", RegexOptions.None };
+ yield return new object[] { @"(?<2048>cat)\s*(?<2048>dog)", "catcat dogdogcat", RegexOptions.None };
+ yield return new object[] { @"(?<cat>cat)\w+(?<dog-cat>dog)", "cat_Hello_World_dog", RegexOptions.None };
+ yield return new object[] { @"(?<cat>cat)\w+(?<-cat>dog)", "cat_Hello_World_dog", RegexOptions.None };
+ yield return new object[] { @"(?<cat>cat)\w+(?<cat-cat>dog)", "cat_Hello_World_dog", RegexOptions.None };
+ yield return new object[] { @"(?<1>cat)\w+(?<dog-1>dog)", "cat_Hello_World_dog", RegexOptions.None };
+ yield return new object[] { @"(?<cat>cat)\w+(?<2-cat>dog)", "cat_Hello_World_dog", RegexOptions.None };
+ yield return new object[] { @"(?<1>cat)\w+(?<2-1>dog)", "cat_Hello_World_dog", RegexOptions.None };
+ yield return new object[] { @"(?<cat>cat){", "STARTcat{", RegexOptions.None };
+ yield return new object[] { @"(?<cat>cat){fdsa", "STARTcat{fdsa", RegexOptions.None };
+ yield return new object[] { @"(?<cat>cat){1", "STARTcat{1", RegexOptions.None };
+ yield return new object[] { @"(?<cat>cat){1END", "STARTcat{1END", RegexOptions.None };
+ yield return new object[] { @"(?<cat>cat){1,", "STARTcat{1,", RegexOptions.None };
+ yield return new object[] { @"(?<cat>cat){1,END", "STARTcat{1,END", RegexOptions.None };
+ yield return new object[] { @"(?<cat>cat){1,2", "STARTcat{1,2", RegexOptions.None };
+ yield return new object[] { @"(?<cat>cat){1,2END", "STARTcat{1,2END", RegexOptions.None };
+ yield return new object[] { @"(cat) #cat
+ \s+ #followed by 1 or more whitespace
+ (dog) #followed by dog
+ ", "cat dog", RegexOptions.IgnorePatternWhitespace };
+ yield return new object[] { @"(cat) #cat
+ \s+ #followed by 1 or more whitespace
+ (dog) #followed by dog", "cat dog", RegexOptions.IgnorePatternWhitespace };
+ yield return new object[] { @"(cat) (?#cat) \s+ (?#followed by 1 or more whitespace) (dog) (?#followed by dog)", "cat dog", RegexOptions.IgnorePatternWhitespace };
+ yield return new object[] { @"(?<cat>cat)(?<dog>dog)\k<cat>", "asdfcatdogcatdog", RegexOptions.None };
+ yield return new object[] { @"(?<cat>cat)\s+(?<dog>dog)\k<cat>", "asdfcat dogcat dog", RegexOptions.None };
+ yield return new object[] { @"(?<cat>cat)\s+(?<dog>dog)\k'cat'", "asdfcat dogcat dog", RegexOptions.None };
+ yield return new object[] { @"(?<cat>cat)\s+(?<dog>dog)\<cat>", "asdfcat dogcat dog", RegexOptions.None };
+ yield return new object[] { @"(?<cat>cat)\s+(?<dog>dog)\'cat'", "asdfcat dogcat dog", RegexOptions.None };
+ yield return new object[] { @"(?<cat>cat)\s+(?<dog>dog)\k<1>", "asdfcat dogcat dog", RegexOptions.None };
+ yield return new object[] { @"(?<cat>cat)\s+(?<dog>dog)\k'1'", "asdfcat dogcat dog", RegexOptions.None };
+ yield return new object[] { @"(?<cat>cat)\s+(?<dog>dog)\<1>", "asdfcat dogcat dog", RegexOptions.None };
+ yield return new object[] { @"(?<cat>cat)\s+(?<dog>dog)\'1'", "asdfcat dogcat dog", RegexOptions.None };
+ yield return new object[] { @"(?<cat>cat)\s+(?<dog>dog)\1", "asdfcat dogcat dog", RegexOptions.None };
+ yield return new object[] { @"(?<cat>cat)\s+(?<dog>dog)\1", "asdfcat dogcat dog", RegexOptions.ECMAScript };
+ yield return new object[] { @"(?<cat>cat)\s+(?<dog>dog)\k<dog>", "asdfcat dogdog dog", RegexOptions.None };
+ yield return new object[] { @"(?<cat>cat)\s+(?<dog>dog)\2", "asdfcat dogdog dog", RegexOptions.None };
+ yield return new object[] { @"(?<cat>cat)\s+(?<dog>dog)\2", "asdfcat dogdog dog", RegexOptions.ECMAScript };
+ yield return new object[] { @"(cat)(\077)", "hellocat?dogworld", RegexOptions.None };
+ yield return new object[] { @"(cat)(\77)", "hellocat?dogworld", RegexOptions.None };
+ yield return new object[] { @"(cat)(\176)", "hellocat~dogworld", RegexOptions.None };
+ yield return new object[] { @"(cat)(\400)", "hellocat\0dogworld", RegexOptions.None };
+ yield return new object[] { @"(cat)(\300)", "hellocat\u00C0dogworld", RegexOptions.None };
+ yield return new object[] { @"(cat)(\300)", "hellocat\u00C0dogworld", RegexOptions.None };
+ yield return new object[] { @"(cat)(\477)", "hellocat\u003Fdogworld", RegexOptions.None };
+ yield return new object[] { @"(cat)(\777)", "hellocat\u00FFdogworld", RegexOptions.None };
+ yield return new object[] { @"(cat)(\7770)", "hellocat\u00FF0dogworld", RegexOptions.None };
+ yield return new object[] { @"(cat)(\077)", "hellocat?dogworld", RegexOptions.ECMAScript };
+ yield return new object[] { @"(cat)(\77)", "hellocat?dogworld", RegexOptions.ECMAScript };
+ yield return new object[] { @"(cat)(\7)", "hellocat\adogworld", RegexOptions.ECMAScript };
+ yield return new object[] { @"(cat)(\40)", "hellocat dogworld", RegexOptions.ECMAScript };
+ yield return new object[] { @"(cat)(\040)", "hellocat dogworld", RegexOptions.ECMAScript };
+ yield return new object[] { @"(cat)(\176)", "hellocatcat76dogworld", RegexOptions.ECMAScript };
+ yield return new object[] { @"(cat)(\377)", "hellocat\u00FFdogworld", RegexOptions.ECMAScript };
+ yield return new object[] { @"(cat)(\400)", "hellocat 0Fdogworld", RegexOptions.ECMAScript };
+ yield return new object[] { @"(cat)\s+(?<2147483646>dog)", "asdlkcat dogiwod", RegexOptions.None };
+ yield return new object[] { @"(cat)\s+(?<2147483647>dog)", "asdlkcat dogiwod", RegexOptions.None };
+ yield return new object[] { @"(cat)(\x2a*)(dog)", "asdlkcat***dogiwod", RegexOptions.None };
+ yield return new object[] { @"(cat)(\x2b*)(dog)", "asdlkcat+++dogiwod", RegexOptions.None };
+ yield return new object[] { @"(cat)(\x2c*)(dog)", "asdlkcat,,,dogiwod", RegexOptions.None };
+ yield return new object[] { @"(cat)(\x2d*)(dog)", "asdlkcat---dogiwod", RegexOptions.None };
+ yield return new object[] { @"(cat)(\x2e*)(dog)", "asdlkcat...dogiwod", RegexOptions.None };
+ yield return new object[] { @"(cat)(\x2A*)(dog)", "asdlkcat***dogiwod", RegexOptions.None };
+ yield return new object[] { @"(cat)(\x2B*)(dog)", "asdlkcat+++dogiwod", RegexOptions.None };
+ yield return new object[] { @"(cat)(\x2C*)(dog)", "asdlkcat,,,dogiwod", RegexOptions.None };
+ yield return new object[] { @"(cat)(\x2D*)(dog)", "asdlkcat---dogiwod", RegexOptions.None };
+ yield return new object[] { @"(cat)(\x2E*)(dog)", "asdlkcat...dogiwod", RegexOptions.None };
+ yield return new object[] { @"(cat)(\c@*)(dog)", "asdlkcat\0\0dogiwod", RegexOptions.None };
+ yield return new object[] { @"(cat)(\cA*)(dog)", "asdlkcat\u0001dogiwod", RegexOptions.None };
+ yield return new object[] { @"(cat)(\ca*)(dog)", "asdlkcat\u0001dogiwod", RegexOptions.None };
+ yield return new object[] { @"(cat)(\cC*)(dog)", "asdlkcat\u0003dogiwod", RegexOptions.None };
+ yield return new object[] { @"(cat)(\cc*)(dog)", "asdlkcat\u0003dogiwod", RegexOptions.None };
+ yield return new object[] { @"(cat)(\cD*)(dog)", "asdlkcat\u0004dogiwod", RegexOptions.None };
+ yield return new object[] { @"(cat)(\cd*)(dog)", "asdlkcat\u0004dogiwod", RegexOptions.None };
+ yield return new object[] { @"(cat)(\cX*)(dog)", "asdlkcat\u0018dogiwod", RegexOptions.None };
+ yield return new object[] { @"(cat)(\cx*)(dog)", "asdlkcat\u0018dogiwod", RegexOptions.None };
+ yield return new object[] { @"(cat)(\cZ*)(dog)", "asdlkcat\u001adogiwod", RegexOptions.None };
+ yield return new object[] { @"(cat)(\cz*)(dog)", "asdlkcat\u001adogiwod", RegexOptions.None };
+ yield return new object[] { @"\A(cat)\s+(dog)", "cat \n\n\n dog", RegexOptions.None };
+ yield return new object[] { @"\A(cat)\s+(dog)", "cat \n\n\n dog", RegexOptions.Multiline };
+ yield return new object[] { @"\A(cat)\s+(dog)", "cat \n\n\n dog", RegexOptions.ECMAScript };
+ yield return new object[] { @"(cat)\s+(dog)\Z", "cat \n\n\n dog", RegexOptions.None };
+ yield return new object[] { @"(cat)\s+(dog)\Z", "cat \n\n\n dog", RegexOptions.Multiline };
+ yield return new object[] { @"(cat)\s+(dog)\Z", "cat \n\n\n dog", RegexOptions.ECMAScript };
+ yield return new object[] { @"(cat)\s+(dog)\Z", "cat \n\n\n dog\n", RegexOptions.None };
+ yield return new object[] { @"(cat)\s+(dog)\Z", "cat \n\n\n dog\n", RegexOptions.Multiline };
+ yield return new object[] { @"(cat)\s+(dog)\Z", "cat \n\n\n dog\n", RegexOptions.ECMAScript };
+ yield return new object[] { @"(cat)\s+(dog)\z", "cat \n\n\n dog", RegexOptions.None };
+ yield return new object[] { @"(cat)\s+(dog)\z", "cat \n\n\n dog", RegexOptions.Multiline };
+ yield return new object[] { @"(cat)\s+(dog)\z", "cat \n\n\n dog", RegexOptions.ECMAScript };
+ yield return new object[] { @"\b@cat", "123START123@catEND", RegexOptions.None };
+ yield return new object[] { @"\b\<cat", "123START123<catEND", RegexOptions.None };
+ yield return new object[] { @"\b,cat", "satwe,,,START,catEND", RegexOptions.None };
+ yield return new object[] { @"\b\[cat", "`12START123[catEND", RegexOptions.None };
+ yield return new object[] { @"\B@cat", "123START123;@catEND", RegexOptions.None };
+ yield return new object[] { @"\B\<cat", "123START123'<catEND", RegexOptions.None };
+ yield return new object[] { @"\B,cat", "satwe,,,START',catEND", RegexOptions.None };
+ yield return new object[] { @"\B\[cat", "`12START123'[catEND", RegexOptions.None };
+ yield return new object[] { @"(\w+)\s+(\w+)", "cat\u02b0 dog\u02b1", RegexOptions.None };
+ yield return new object[] { @"(cat\w+)\s+(dog\w+)", "STARTcat\u30FC dog\u3005END", RegexOptions.None };
+ yield return new object[] { @"(cat\w+)\s+(dog\w+)", "STARTcat\uff9e dog\uff9fEND", RegexOptions.None };
+ yield return new object[] { @"[^a]|d", "d", RegexOptions.None };
+ yield return new object[] { @"([^a]|[d])*", "Hello Worlddf", RegexOptions.None };
+ yield return new object[] { @"([^{}]|\n)+", "{{{{Hello\n World \n}END", RegexOptions.None };
+ yield return new object[] { @"([a-d]|[^abcd])+", "\tonce\n upon\0 a- ()*&^%#time?", RegexOptions.None };
+ yield return new object[] { @"([^a]|[a])*", "once upon a time", RegexOptions.None };
+ yield return new object[] { @"([a-d]|[^abcd]|[x-z]|^wxyz])+", "\tonce\n upon\0 a- ()*&^%#time?", RegexOptions.None };
+ yield return new object[] { @"([a-d]|[e-i]|[^e]|wxyz])+", "\tonce\n upon\0 a- ()*&^%#time?", RegexOptions.None };
+ yield return new object[] { @"^(([^b]+ )|(.* ))$", "aaa ", RegexOptions.None };
+ yield return new object[] { @"^(([^b]+ )|(.*))$", "aaa", RegexOptions.None };
+ yield return new object[] { @"^(([^b]+ )|(.* ))$", "bbb ", RegexOptions.None };
+ yield return new object[] { @"^(([^b]+ )|(.*))$", "bbb", RegexOptions.None };
+ yield return new object[] { @"^((a*)|(.*))$", "aaa", RegexOptions.None };
+ yield return new object[] { @"^((a*)|(.*))$", "aaabbb", RegexOptions.None };
+ yield return new object[] { @"(([0-9])|([a-z])|([A-Z]))*", "{hello 1234567890 world}", RegexOptions.None };
+ yield return new object[] { @"(([0-9])|([a-z])|([A-Z]))+", "{hello 1234567890 world}", RegexOptions.None };
+ yield return new object[] { @"(([0-9])|([a-z])|([A-Z]))*", "{HELLO 1234567890 world}", RegexOptions.None };
+ yield return new object[] { @"(([0-9])|([a-z])|([A-Z]))+", "{HELLO 1234567890 world}", RegexOptions.None };
+ yield return new object[] { @"(([0-9])|([a-z])|([A-Z]))*", "{1234567890 hello world}", RegexOptions.None };
+ yield return new object[] { @"(([0-9])|([a-z])|([A-Z]))+", "{1234567890 hello world}", RegexOptions.None };
+ yield return new object[] { @"^(([a-d]*)|([a-z]*))$", "aaabbbcccdddeeefff", RegexOptions.None };
+ yield return new object[] { @"^(([d-f]*)|([c-e]*))$", "dddeeeccceee", RegexOptions.None };
+ yield return new object[] { @"^(([c-e]*)|([d-f]*))$", "dddeeeccceee", RegexOptions.None };
+ yield return new object[] { @"(([a-d]*)|([a-z]*))", "aaabbbcccdddeeefff", RegexOptions.None };
+ yield return new object[] { @"(([d-f]*)|([c-e]*))", "dddeeeccceee", RegexOptions.None };
+ yield return new object[] { @"(([c-e]*)|([d-f]*))", "dddeeeccceee", RegexOptions.None };
+ yield return new object[] { @"(([a-d]*)|(.*))", "aaabbbcccdddeeefff", RegexOptions.None };
+ yield return new object[] { @"(([d-f]*)|(.*))", "dddeeeccceee", RegexOptions.None };
+ yield return new object[] { @"(([c-e]*)|(.*))", "dddeeeccceee", RegexOptions.None };
+ yield return new object[] { @"\p{Pi}(\w*)\p{Pf}", "\u00ABCat\u00BB \u00BBDog\u00AB'", RegexOptions.None };
+ yield return new object[] { @"\p{Pi}(\w*)\p{Pf}", "\u2018Cat\u2019 \u2019Dog\u2018'", RegexOptions.None };
+ yield return new object[] { @"(?<cat>cat)\s+(?<dog>dog)\s+\123\s+\234", "asdfcat dog cat23 dog34eia", RegexOptions.ECMAScript };
+ yield return new object[] { @"<div>
+ (?>
+ <div>(?<DEPTH>) |
+ </div> (?<-DEPTH>) |
+ .?
+ )*?
+ (?(DEPTH)(?!))
+ </div>", "<div>this is some <div>red</div> text</div></div></div>", RegexOptions.IgnorePatternWhitespace };
+ yield return new object[] { @"(
+ ((?'open'<+)[^<>]*)+
+ ((?'close-open'>+)[^<>]*)+
+ )+", "<01deep_01<02deep_01<03deep_01>><02deep_02><02deep_03<03deep_03>>>", RegexOptions.IgnorePatternWhitespace };
+ yield return new object[] { @"(
+ (?<start><)?
+ [^<>]?
+ (?<end-start>>)?
+ )*", "<01deep_01<02deep_01<03deep_01>><02deep_02><02deep_03<03deep_03>>>", RegexOptions.IgnorePatternWhitespace };
+ yield return new object[] { @"(
+ (?<start><[^/<>]*>)?
+ [^<>]?
+ (?<end-start></[^/<>]*>)?
+ )*", "<b><a>Cat</a></b>", RegexOptions.IgnorePatternWhitespace };
+ yield return new object[] { @"(
+ (?<start><(?<TagName>[^/<>]*)>)?
+ [^<>]?
+ (?<end-start></\k<TagName>>)?
+ )*", "<b>cat</b><a>dog</a>", RegexOptions.IgnorePatternWhitespace };
+ yield return new object[] { @"([0-9]+?)([\w]+?)", "55488aheiaheiad", RegexOptions.ECMAScript };
+ yield return new object[] { @"([0-9]+?)([a-z]+?)", "55488aheiaheiad", RegexOptions.ECMAScript };
+ yield return new object[] { @"\G<%#(?<code>.*?)?%>", @"<%# DataBinder.Eval(this, ""MyNumber"") %>", RegexOptions.Singleline };
+ yield return new object[] { @"^[abcd]{0,0x10}*$", "a{0,0x10}}}", RegexOptions.None };
+ yield return new object[] { @"([a-z]*?)([\w])", "cat", RegexOptions.IgnoreCase };
+ yield return new object[] { @"^([a-z]*?)([\w])$", "cat", RegexOptions.IgnoreCase };
+ yield return new object[] { @"([a-z]*)([\w])", "cat", RegexOptions.IgnoreCase };
+ yield return new object[] { @"^([a-z]*)([\w])$", "cat", RegexOptions.IgnoreCase };
+ yield return new object[] { @"(cat){", "cat{", RegexOptions.None };
+ yield return new object[] { @"(cat){}", "cat{}", RegexOptions.None };
+ yield return new object[] { @"(cat){,", "cat{,", RegexOptions.None };
+ yield return new object[] { @"(cat){,}", "cat{,}", RegexOptions.None };
+ yield return new object[] { @"(cat){cat}", "cat{cat}", RegexOptions.None };
+ yield return new object[] { @"(cat){cat,5}", "cat{cat,5}", RegexOptions.None };
+ yield return new object[] { @"(cat){5,dog}", "cat{5,dog}", RegexOptions.None };
+ yield return new object[] { @"(cat){cat,dog}", "cat{cat,dog}", RegexOptions.None };
+ yield return new object[] { @"(cat){,}?", "cat{,}?", RegexOptions.None };
+ yield return new object[] { @"(cat){cat}?", "cat{cat}?", RegexOptions.None };
+ yield return new object[] { @"(cat){cat,5}?", "cat{cat,5}?", RegexOptions.None };
+ yield return new object[] { @"(cat){5,dog}?", "cat{5,dog}?", RegexOptions.None };
+ yield return new object[] { @"(cat){cat,dog}?", "cat{cat,dog}?", RegexOptions.None };
+ yield return new object[] { @"()", "cat", RegexOptions.None };
+ yield return new object[] { @"(?<cat>)", "cat", RegexOptions.None };
+ yield return new object[] { @"(?'cat')", "cat", RegexOptions.None };
+ yield return new object[] { @"(?:)", "cat", RegexOptions.None };
+ yield return new object[] { @"(?imn)", "cat", RegexOptions.None };
+ yield return new object[] { @"(?imn)cat", "(?imn)cat", RegexOptions.None };
+ yield return new object[] { @"(?=)", "cat", RegexOptions.None };
+ yield return new object[] { @"(?<=)", "cat", RegexOptions.None };
+ yield return new object[] { @"(?>)", "cat", RegexOptions.None };
+ yield return new object[] { @"(?()|)", "(?()|)", RegexOptions.None };
+ yield return new object[] { @"(?(cat)|)", "cat", RegexOptions.None };
+ yield return new object[] { @"(?(cat)|)", "dog", RegexOptions.None };
+ yield return new object[] { @"(?(cat)catdog|)", "catdog", RegexOptions.None };
+ yield return new object[] { @"(?(cat)catdog|)", "dog", RegexOptions.None };
+ yield return new object[] { @"(?(cat)dog|)", "dog", RegexOptions.None };
+ yield return new object[] { @"(?(cat)dog|)", "cat", RegexOptions.None };
+ yield return new object[] { @"(?(cat)|catdog)", "cat", RegexOptions.None };
+ yield return new object[] { @"(?(cat)|catdog)", "catdog", RegexOptions.None };
+ yield return new object[] { @"(?(cat)|dog)", "dog", RegexOptions.None };
+ yield return new object[] { "([\u0000-\uFFFF-[azAZ09]]|[\u0000-\uFFFF-[^azAZ09]])+", "azAZBCDE1234567890BCDEFAZza", RegexOptions.None };
+ yield return new object[] { "[\u0000-\uFFFF-[\u0000-\uFFFF-[\u0000-\uFFFF-[\u0000-\uFFFF-[\u0000-\uFFFF-[a]]]]]]+", "abcxyzABCXYZ123890", RegexOptions.None };
+ yield return new object[] { "[\u0000-\uFFFF-[\u0000-\uFFFF-[\u0000-\uFFFF-[\u0000-\uFFFF-[\u0000-\uFFFF-[\u0000-\uFFFF-[a]]]]]]]+", "bcxyzABCXYZ123890a", RegexOptions.None };
+ yield return new object[] { "[\u0000-\uFFFF-[\\p{P}\\p{S}\\p{C}]]+", "!@`';.,$+<>=\x0001\x001FazAZ09", RegexOptions.None };
+ yield return new object[] { @"[\uFFFD-\uFFFF]+", "\uFFFC\uFFFD\uFFFE\uFFFF", RegexOptions.IgnoreCase };
+ yield return new object[] { @"[\uFFFC-\uFFFE]+", "\uFFFB\uFFFC\uFFFD\uFFFE\uFFFF", RegexOptions.IgnoreCase };
+ yield return new object[] { @"([a*]*)+?$", "ab", RegexOptions.None };
+ yield return new object[] { @"(a*)+?$", "b", RegexOptions.None };
+ }
+ }
+}
diff --git a/src/System.Text.RegularExpressions/tests/Performance/Perf.RegexRedux.cs b/src/System.Text.RegularExpressions/tests/Performance/Perf.RegexRedux.cs
new file mode 100644
index 0000000000..de980c885c
--- /dev/null
+++ b/src/System.Text.RegularExpressions/tests/Performance/Perf.RegexRedux.cs
@@ -0,0 +1,70 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.IO;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using System.Diagnostics;
+using System.Threading;
+using System.Collections.Generic;
+using Xunit;
+using Microsoft.Xunit.Performance;
+
+namespace System.Text.RegularExpressions.Tests
+{
+ public class RegexRedux
+ {
+ static readonly string input = File.ReadAllText(Path.Combine("regexredux", "200_000.in"));
+
+ static Regex regex(string re, RegexOptions options)
+ {
+ return new Regex(re, options);
+ }
+
+ static string regexCount(string s, string r, RegexOptions options)
+ {
+ int c = 0;
+ var m = regex(r, options).Match(s);
+ while (m.Success) { c++; m = m.NextMatch(); }
+ return r + " " + c;
+ }
+
+ [Benchmark]
+ [InlineData(RegexOptions.None)]
+ [InlineData(RegexOptions.Compiled)]
+ public void RegexReduxMini(RegexOptions options)
+ {
+ foreach (var iteration in Benchmark.Iterations)
+ using (iteration.StartMeasurement())
+ {
+ string sequences = input;
+ var initialLength = sequences.Length;
+ sequences = Regex.Replace(sequences, ">.*\n|\n", "");
+
+ var magicTask = Task.Run(() =>
+ {
+ var newseq = regex("tHa[Nt]", options).Replace(sequences, "<4>");
+ newseq = regex("aND|caN|Ha[DS]|WaS", options).Replace(newseq, "<3>");
+ newseq = regex("a[NSt]|BY", options).Replace(newseq, "<2>");
+ newseq = regex("<[^>]*>", options).Replace(newseq, "|");
+ newseq = regex("\\|[^|][^|]*\\|", options).Replace(newseq, "-");
+ return newseq.Length;
+ });
+
+ var variant2 = Task.Run(() => regexCount(sequences, "[cgt]gggtaaa|tttaccc[acg]", options));
+ var variant3 = Task.Run(() => regexCount(sequences, "a[act]ggtaaa|tttacc[agt]t", options));
+ var variant7 = Task.Run(() => regexCount(sequences, "agggt[cgt]aa|tt[acg]accct", options));
+ var variant6 = Task.Run(() => regexCount(sequences, "aggg[acg]aaa|ttt[cgt]ccct", options));
+ var variant4 = Task.Run(() => regexCount(sequences, "ag[act]gtaaa|tttac[agt]ct", options));
+ var variant5 = Task.Run(() => regexCount(sequences, "agg[act]taaa|ttta[agt]cct", options));
+ var variant1 = Task.Run(() => regexCount(sequences, "agggtaaa|tttaccct", options));
+ var variant9 = Task.Run(() => regexCount(sequences, "agggtaa[cgt]|[acg]ttaccct", options));
+ var variant8 = Task.Run(() => regexCount(sequences, "agggta[cgt]a|t[acg]taccct", options));
+
+ Task.WaitAll(magicTask, variant1, variant2, variant3, variant4, variant5, variant6, variant7, variant8, variant9);
+ }
+ }
+ }
+}
diff --git a/src/System.Text.RegularExpressions/tests/Performance/System.Text.RegularExpressions.Performance.Tests.csproj b/src/System.Text.RegularExpressions/tests/Performance/System.Text.RegularExpressions.Performance.Tests.csproj
new file mode 100644
index 0000000000..be6f5e04ec
--- /dev/null
+++ b/src/System.Text.RegularExpressions/tests/Performance/System.Text.RegularExpressions.Performance.Tests.csproj
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <IncludePerformanceTests>true</IncludePerformanceTests>
+ <ProjectGuid>{7F4B8C48-8692-4885-BF84-FEB7EA82E34B}</ProjectGuid>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
+ <!-- Default configurations to help VS understand the configurations -->
+ <ItemGroup>
+ <Compile Include="Perf.Regex.Cache.cs" />
+ <Compile Include="Perf.Regex.cs" />
+ <Compile Include="Perf.RegexRedux.cs" />
+ <Compile Include="$(CommonTestPath)\System\PerfUtils.cs">
+ <Link>Common\System\PerfUtils.cs</Link>
+ </Compile>
+ </ItemGroup>
+ <ItemGroup>
+ <SupplementalTestData Include="$(PackagesDir)system.text.regularexpressions.testdata\1.0.2\content\**\*.*">
+ <Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
+ </SupplementalTestData>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="$(CommonPath)\..\perf\PerfRunner\PerfRunner.csproj">
+ <Project>{69e46a6f-9966-45a5-8945-2559fe337827}</Project>
+ <Name>PerfRunner</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project> \ No newline at end of file
diff --git a/src/System.Text.RegularExpressions/tests/Performance/THIRD-PARTY-NOTICES b/src/System.Text.RegularExpressions/tests/Performance/THIRD-PARTY-NOTICES
new file mode 100644
index 0000000000..51b5799e35
--- /dev/null
+++ b/src/System.Text.RegularExpressions/tests/Performance/THIRD-PARTY-NOTICES
@@ -0,0 +1,31 @@
+.NET Core uses third-party libraries or other resources that may be
+distributed under licenses different than the .NET Core 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.
+
+===============
+
+The Computer Language
+Benchmarks Game
+Revised BSD license
+This is a specific instance of the Open Source Initiative (OSI) BSD license template.
+
+Copyright (c) 2004-2008 Brent Fulgham, 2005-2018 Isaac Gouy
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+Neither the name of "The Computer Language Benchmarks Game" nor the name of "The Computer Language Shootout Benchmarks" nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/src/System.Text.RegularExpressions/tests/Regex.Cache.Tests.cs b/src/System.Text.RegularExpressions/tests/Regex.Cache.Tests.cs
new file mode 100644
index 0000000000..17694afcc5
--- /dev/null
+++ b/src/System.Text.RegularExpressions/tests/Regex.Cache.Tests.cs
@@ -0,0 +1,156 @@
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.Reflection;
+using Xunit;
+
+namespace System.Text.RegularExpressions.Tests
+{
+ public class RegexCacheTests : RemoteExecutorTestBase
+ {
+ [Theory]
+ [InlineData(0)]
+ [InlineData(12)]
+ public void CacheSize_Set(int newCacheSize)
+ {
+ int originalCacheSize = Regex.CacheSize;
+
+ try
+ {
+ Regex.CacheSize = newCacheSize;
+ Assert.Equal(newCacheSize, Regex.CacheSize);
+ }
+ finally
+ {
+ Regex.CacheSize = originalCacheSize;
+ }
+ }
+
+ [Fact]
+ public void CacheSize_Set_NegativeValue_ThrowsArgumentOutOfRangeException()
+ {
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => Regex.CacheSize = -1);
+ }
+
+ [Fact]
+ public void Ctor_Cache_Second_drops_first()
+ {
+ RemoteInvoke(() =>
+ {
+ Regex.CacheSize = 1;
+ Assert.True(Regex.IsMatch("1", "1"));
+ Assert.True(Regex.IsMatch("2", "2")); // previous removed from cache
+ Assert.True(GetCachedItemsNum() == 1);
+ return SuccessExitCode;
+ }).Dispose();
+ }
+
+ [Fact]
+ public void Ctor_Cache_Shrink_cache()
+ {
+ RemoteInvoke(() =>
+ {
+ Regex.CacheSize = 2;
+ Assert.True(Regex.IsMatch("1", "1"));
+ Assert.True(Regex.IsMatch("2", "2"));
+ Assert.True(GetCachedItemsNum() == 2);
+ Regex.CacheSize = 1;
+ Assert.True(GetCachedItemsNum() == 1);
+ Regex.CacheSize = 0; // clear
+ Assert.True(GetCachedItemsNum() == 0);
+ return SuccessExitCode;
+ }).Dispose();
+ }
+
+ [Fact]
+ public void Ctor_Cache_Promote_entries()
+ {
+ RemoteInvoke(() =>
+ {
+ Regex.CacheSize = 3;
+ Assert.True(Regex.IsMatch("1", "1"));
+ Assert.True(Regex.IsMatch("2", "2"));
+ Assert.True(Regex.IsMatch("3", "3"));
+ Assert.True(GetCachedItemsNum() == 3);
+ Assert.True(Regex.IsMatch("1", "1")); // should be put first
+ Assert.True(GetCachedItemsNum() == 3);
+ Regex.CacheSize = 1; // only 1 stays
+ Assert.True(GetCachedItemsNum() == 1);
+ return SuccessExitCode;
+ }).Dispose();
+ }
+
+ [Fact]
+ public void Ctor_Cache_Uses_culture_and_options()
+ {
+ RemoteInvoke(() =>
+ {
+ Regex.CacheSize = 0;
+ Regex.CacheSize = 3;
+ Assert.True(Regex.IsMatch("1", "1", RegexOptions.IgnoreCase));
+ Assert.True(Regex.IsMatch("1", "1", RegexOptions.Multiline));
+ Assert.True(GetCachedItemsNum() == 2);
+ CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("de-DE");
+ Assert.True(Regex.IsMatch("1", "1", RegexOptions.Multiline));
+ Assert.True(GetCachedItemsNum() == 3);
+ return SuccessExitCode;
+ }).Dispose();
+ }
+
+ [Fact]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)] // different cache structure
+ public void Ctor_Cache_Uses_dictionary_linked_list_switch_does_not_throw()
+ {
+ // assume the limit is less than the cache size so we cross it two times:
+ RemoteInvoke(() =>
+ {
+ int original = Regex.CacheSize;
+ Regex.CacheSize = 0;
+ Fill(original);
+ const int limit = 10;
+ Regex.CacheSize = limit - 1;
+ Regex.CacheSize = 0;
+ Fill(original);
+ Remove(original);
+
+ void Fill(int n)
+ {
+ for (int i = 0; i < n; i++)
+ {
+ Regex.CacheSize++;
+ Assert.True(Regex.IsMatch(i.ToString(), i.ToString()));
+ Assert.True(GetCachedItemsNum() == i + 1);
+ }
+ }
+ void Remove(int n)
+ {
+ for (int i = 0; i < original; i++)
+ {
+ Regex.CacheSize--;
+ Assert.True(GetCachedItemsNum() == Regex.CacheSize);
+ }
+ }
+ return SuccessExitCode;
+ }).Dispose();
+ }
+
+ private int GetCachedItemsNum()
+ {
+ // On .NET Framework we have a different cache structure.
+ if (PlatformDetection.IsFullFramework)
+ {
+ object linkedList = typeof(Regex)
+ .GetField("livecode", BindingFlags.NonPublic | BindingFlags.Static)
+ .GetValue(null);
+ return (int)linkedList.GetType()
+ .GetProperty("Count", BindingFlags.Public | BindingFlags.Instance)
+ .GetValue(linkedList);
+ }
+
+ string cacheFieldName = PlatformDetection.IsFullFramework ? "cacheSize" : "s_cacheCount";
+ return (int)typeof(Regex)
+ .GetField(cacheFieldName, BindingFlags.NonPublic | BindingFlags.Static)
+ .GetValue(null);
+ }
+ }
+}
diff --git a/src/System.Text.RegularExpressions/tests/Regex.Ctor.Tests.cs b/src/System.Text.RegularExpressions/tests/Regex.Ctor.Tests.cs
index fc63daef93..615c9753ca 100644
--- a/src/System.Text.RegularExpressions/tests/Regex.Ctor.Tests.cs
+++ b/src/System.Text.RegularExpressions/tests/Regex.Ctor.Tests.cs
@@ -85,7 +85,7 @@ namespace System.Text.RegularExpressions.Tests
Assert.Throws<TypeInitializationException>(() => Regex.InfiniteMatchTimeout);
return SuccessExitCode;
- });
+ }).Dispose();
}
[Fact]
@@ -97,32 +97,7 @@ namespace System.Text.RegularExpressions.Tests
Assert.Throws<TypeInitializationException>(() => Regex.InfiniteMatchTimeout);
return SuccessExitCode;
- });
- }
-
- [Fact]
- public void CacheSize_Get()
- {
- Assert.Equal(15, Regex.CacheSize);
- }
-
- [Theory]
- [InlineData(0)]
- [InlineData(12)]
- public void CacheSize_Set(int newCacheSize)
- {
- int originalCacheSize = Regex.CacheSize;
-
- Regex.CacheSize = newCacheSize;
- Assert.Equal(newCacheSize, Regex.CacheSize);
-
- Regex.CacheSize = originalCacheSize;
- }
-
- [Fact]
- public void CacheSize_Set_NegativeValue_ThrowsArgumentOutOfRangeException()
- {
- AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => Regex.CacheSize = -1);
+ }).Dispose();
}
[Theory]
@@ -235,8 +210,10 @@ namespace System.Text.RegularExpressions.Tests
[InlineData("(?<=", RegexOptions.None)]
[InlineData("(?<!", RegexOptions.None)]
[InlineData("(?>", RegexOptions.None)]
+ [InlineData("(?>-", RegexOptions.None)]
[InlineData("(?)", RegexOptions.None)]
[InlineData("(?<)", RegexOptions.None)]
+ [InlineData("(?<", RegexOptions.None)]
[InlineData("(?')", RegexOptions.None)]
[InlineData(@"\1", RegexOptions.None)]
[InlineData(@"\1", RegexOptions.None)]
@@ -283,6 +260,14 @@ namespace System.Text.RegularExpressions.Tests
}
[Theory]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Full framework throws InvalidOperationException")]
+ [InlineData("(?<-", RegexOptions.None)]
+ public void Ctor_InvalidPattern_NotNetFramework(string pattern, RegexOptions options)
+ {
+ AssertExtensions.Throws<ArgumentException>(null, () => new Regex(pattern, options));
+ }
+
+ [Theory]
// Testgroup with options
[InlineData("(?(?i))", RegexOptions.None, typeof(NullReferenceException))]
[InlineData("(?(?I))", RegexOptions.None, typeof(NullReferenceException))]
diff --git a/src/System.Text.RegularExpressions/tests/Regex.Groups.Tests.cs b/src/System.Text.RegularExpressions/tests/Regex.Groups.Tests.cs
index c28be6399f..c1ade0a8c3 100644
--- a/src/System.Text.RegularExpressions/tests/Regex.Groups.Tests.cs
+++ b/src/System.Text.RegularExpressions/tests/Regex.Groups.Tests.cs
@@ -322,6 +322,7 @@ namespace System.Text.RegularExpressions.Tests
yield return new object[] { @"(cat) (?#cat) \s+ (?#followed by 1 or more whitespace) (dog) (?#followed by dog)", "cat dog", RegexOptions.IgnorePatternWhitespace, new string[] { "cat dog", "cat", "dog" } };
// Back Reference
+ yield return new object[] { @"(?<cat>cat)(?<dog>dog)\k<cat>", "asdfcatdogcatdog", RegexOptions.None, new string[] { "catdogcat", "cat", "dog" } };
yield return new object[] { @"(?<cat>cat)\s+(?<dog>dog)\k<cat>", "asdfcat dogcat dog", RegexOptions.None, new string[] { "cat dogcat", "cat", "dog" } };
yield return new object[] { @"(?<cat>cat)\s+(?<dog>dog)\k'cat'", "asdfcat dogcat dog", RegexOptions.None, new string[] { "cat dogcat", "cat", "dog" } };
yield return new object[] { @"(?<cat>cat)\s+(?<dog>dog)\<cat>", "asdfcat dogcat dog", RegexOptions.None, new string[] { "cat dogcat", "cat", "dog" } };
@@ -394,6 +395,12 @@ namespace System.Text.RegularExpressions.Tests
yield return new object[] { @"(cat)(\cZ*)(dog)", "asdlkcat\u001adogiwod", RegexOptions.None, new string[] { "cat\u001adog", "cat", "\u001a", "dog" } };
yield return new object[] { @"(cat)(\cz*)(dog)", "asdlkcat\u001adogiwod", RegexOptions.None, new string[] { "cat\u001adog", "cat", "\u001a", "dog" } };
+ if (!PlatformDetection.IsFullFramework) // missing fix for #26501
+ {
+ yield return new object[] { @"(cat)(\c[*)(dog)", "asdlkcat\u001bdogiwod", RegexOptions.None, new string[] { "cat\u001bdog", "cat", "\u001b", "dog" } };
+ yield return new object[] { @"(cat)(\c[*)(dog)", "asdlkcat\u001Bdogiwod", RegexOptions.None, new string[] { "cat\u001Bdog", "cat", "\u001B", "dog" } };
+ }
+
// Atomic Zero-Width Assertions \A \Z \z \G \b \B
//\A
yield return new object[] { @"\A(cat)\s+(dog)", "cat \n\n\n dog", RegexOptions.None, new string[] { "cat \n\n\n dog", "cat", "dog" } };
diff --git a/src/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs b/src/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs
index 672f29ce88..0d15939704 100644
--- a/src/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs
+++ b/src/System.Text.RegularExpressions/tests/Regex.Match.Tests.cs
@@ -14,6 +14,8 @@ namespace System.Text.RegularExpressions.Tests
{
public static IEnumerable<object[]> Match_Basic_TestData()
{
+ // pattern, input, options, beginning, length, expectedSuccess, expectedValue
+
// Testing octal sequence matches: "\\060(\\061)?\\061"
// Octal \061 is ASCII 49 ('1')
yield return new object[] { @"\060(\061)?\061", "011", RegexOptions.None, 0, 3, true, "011" };
@@ -28,6 +30,28 @@ namespace System.Text.RegularExpressions.Tests
// Using *, +, ?, {}: Actual - "a+\\.?b*\\.?c{2}"
yield return new object[] { @"a+\.?b*\.+c{2}", "ab.cc", RegexOptions.None, 0, 5, true, "ab.cc" };
+ // Using long loop prefix
+ yield return new object[] { @"a{10}", new string('a', 10), RegexOptions.None, 0, 10, true, new string('a', 10) };
+ yield return new object[] { @"a{100}", new string('a', 100), RegexOptions.None, 0, 100, true, new string('a', 100) };
+
+ yield return new object[] { @"a{10}b", new string('a', 10) + "bc", RegexOptions.None, 0, 12, true, new string('a', 10) + "b" };
+ yield return new object[] { @"a{100}b", new string('a', 100) + "bc", RegexOptions.None, 0, 102, true, new string('a', 100) + "b" };
+
+ yield return new object[] { @"a{11}b", new string('a', 10) + "bc", RegexOptions.None, 0, 12, false, string.Empty };
+ yield return new object[] { @"a{101}b", new string('a', 100) + "bc", RegexOptions.None, 0, 102, false, string.Empty };
+
+ yield return new object[] { @"a{1,3}b", "bc", RegexOptions.None, 0, 2, false, string.Empty };
+ yield return new object[] { @"a{1,3}b", "abc", RegexOptions.None, 0, 3, true, "ab" };
+ yield return new object[] { @"a{1,3}b", "aaabc", RegexOptions.None, 0, 5, true, "aaab" };
+ yield return new object[] { @"a{1,3}b", "aaaabc", RegexOptions.None, 0, 6, true, "aaab" };
+
+ yield return new object[] { @"a{2,}b", "abc", RegexOptions.None, 0, 3, false, string.Empty };
+ yield return new object[] { @"a{2,}b", "aabc", RegexOptions.None, 0, 4, true, "aab" };
+
+ // {,n} is treated as a literal rather than {0,n} as it should be
+ yield return new object[] { @"a{,3}b", "a{,3}bc", RegexOptions.None, 0, 6, true, "a{,3}b" };
+ yield return new object[] { @"a{,3}b", "aaabc", RegexOptions.None, 0, 5, false, String.Empty };
+
// Using [a-z], \s, \w: Actual - "([a-zA-Z]+)\\s(\\w+)"
yield return new object[] { @"([a-zA-Z]+)\s(\w+)", "David Bau", RegexOptions.None, 0, 9, true, "David Bau" };
@@ -263,6 +287,10 @@ namespace System.Text.RegularExpressions.Tests
yield return new object[] { @"[ab\-\[cd-[[]]]]", "e]]", RegexOptions.None, 0, 3, false, string.Empty };
yield return new object[] { @"[a-[a-f]]", "abcdefghijklmnopqrstuvwxyz", RegexOptions.None, 0, 26, false, string.Empty };
+
+ // \c
+ if (!PlatformDetection.IsFullFramework) // missing fix for #26501
+ yield return new object[] { @"(cat)(\c[*)(dog)", "asdlkcat\u00FFdogiwod", RegexOptions.None, 0, 15, false, string.Empty };
}
[Theory]
@@ -342,7 +370,7 @@ namespace System.Text.RegularExpressions.Tests
Assert.Throws<RegexMatchTimeoutException>(() => new Regex(Pattern).Match(input));
return SuccessExitCode;
- });
+ }).Dispose();
}
public static IEnumerable<object[]> Match_Advanced_TestData()
@@ -736,6 +764,20 @@ namespace System.Text.RegularExpressions.Tests
}
[Fact]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Full framework needs fix for #26484")]
+ public void Match_ExcessPrefix()
+ {
+ RemoteInvoke(() =>
+ {
+ // Should not throw out of memory
+ Assert.False(Regex.IsMatch("a", @"a{2147483647,}"));
+ Assert.False(Regex.IsMatch("a", @"a{1000001,}")); // 1 over the cutoff for Boyer-Moore prefix
+
+ Assert.False(Regex.IsMatch("a", @"a{50000}")); // creates string for Boyer-Moore but not so large that tests fail and start paging
+ }).Dispose();
+ }
+
+ [Fact]
public void Match_Invalid()
{
// Input is null
diff --git a/src/System.Text.RegularExpressions/tests/RegexCompilationHelper.cs b/src/System.Text.RegularExpressions/tests/RegexCompilationHelper.cs
index 5a20e154f2..418d3651fb 100644
--- a/src/System.Text.RegularExpressions/tests/RegexCompilationHelper.cs
+++ b/src/System.Text.RegularExpressions/tests/RegexCompilationHelper.cs
@@ -33,7 +33,7 @@ namespace System.Text.RegularExpressions.Tests
return result;
}
}
-
+
throw new Exception($"Test method '{testDataMethodName}' not found");
}
diff --git a/src/System.Text.RegularExpressions/tests/System.Text.RegularExpressions.Tests.csproj b/src/System.Text.RegularExpressions/tests/System.Text.RegularExpressions.Tests.csproj
index aca9ba82ba..6ec879d5ba 100644
--- a/src/System.Text.RegularExpressions/tests/System.Text.RegularExpressions.Tests.csproj
+++ b/src/System.Text.RegularExpressions/tests/System.Text.RegularExpressions.Tests.csproj
@@ -5,6 +5,12 @@
<ProjectGuid>{94B106C2-D574-4392-80AB-3EE308A078DF}</ProjectGuid>
<AppDesignerFolder>Properties</AppDesignerFolder>
</PropertyGroup>
+ <PropertyGroup>
+ <!-- Temporary property to diagnose hanging test
+ <XunitShowProgress>true</XunitShowProgress>
+ <XunitMaxThreads>1</XunitMaxThreads>
+ -->
+ </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
@@ -15,6 +21,7 @@
<Compile Include="CaptureCollectionTests.cs" />
<Compile Include="GroupCollectionTests.cs" />
<Compile Include="MatchCollectionTests.cs" />
+ <Compile Include="Regex.Cache.Tests.cs" />
<Compile Include="Regex.EscapeUnescape.Tests.cs" />
<Compile Include="Regex.GetGroupNames.Tests.cs" />
<Compile Include="Regex.Ctor.Tests.cs" />
@@ -44,4 +51,4 @@
</ItemGroup>
<!-- Automatically added by VS -->
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project>
+</Project> \ No newline at end of file
diff --git a/src/System.Threading.Channels/System.Threading.Channels.sln b/src/System.Threading.Channels/System.Threading.Channels.sln
index 0baa0b1633..d2a964cd63 100644
--- a/src/System.Threading.Channels/System.Threading.Channels.sln
+++ b/src/System.Threading.Channels/System.Threading.Channels.sln
@@ -2,22 +2,22 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Threading.Channels.Tests", "tests\System.Threading.Channels.Tests.csproj", "{9E984EB2-827E-4029-9647-FB5F8B67C553}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Threading.Channels.Tests", "tests\System.Threading.Channels.Tests.csproj", "{1AF01469-DBFC-4BA1-9331-8E39AA639FEE}"
ProjectSection(ProjectDependencies) = postProject
- {1032D5F6-5AE7-4002-A0E4-FEBEADFEA977} = {1032D5F6-5AE7-4002-A0E4-FEBEADFEA977}
+ {AAADA5D3-CF64-4E9D-943C-EFDC006D6366} = {AAADA5D3-CF64-4E9D-943C-EFDC006D6366}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Threading.Channels.Performance.Tests", "tests\Performance\System.Threading.Channels.Performance.Tests.csproj", "{11ABE2F8-4FB9-48AC-91AA-D04503059550}"
ProjectSection(ProjectDependencies) = postProject
- {1032D5F6-5AE7-4002-A0E4-FEBEADFEA977} = {1032D5F6-5AE7-4002-A0E4-FEBEADFEA977}
+ {AAADA5D3-CF64-4E9D-943C-EFDC006D6366} = {AAADA5D3-CF64-4E9D-943C-EFDC006D6366}
EndProjectSection
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Threading.Channels", "src\System.Threading.Channels.csproj", "{1032D5F6-5AE7-4002-A0E4-FEBEADFEA977}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Threading.Channels", "src\System.Threading.Channels.csproj", "{AAADA5D3-CF64-4E9D-943C-EFDC006D6366}"
ProjectSection(ProjectDependencies) = postProject
- {9C524CA0-92FF-437B-B568-BCE8A794A69A} = {9C524CA0-92FF-437B-B568-BCE8A794A69A}
+ {97DB4782-7AB3-4F4C-B716-CF722A0E6066} = {97DB4782-7AB3-4F4C-B716-CF722A0E6066}
EndProjectSection
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Threading.Channels", "ref\System.Threading.Channels.csproj", "{9C524CA0-92FF-437B-B568-BCE8A794A69A}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Threading.Channels", "ref\System.Threading.Channels.csproj", "{97DB4782-7AB3-4F4C-B716-CF722A0E6066}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{1A2F9F4A-A032-433E-B914-ADD5992BB178}"
EndProject
@@ -31,30 +31,30 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {9E984EB2-827E-4029-9647-FB5F8B67C553}.Debug|Any CPU.ActiveCfg = netstandard-Debug|Any CPU
- {9E984EB2-827E-4029-9647-FB5F8B67C553}.Debug|Any CPU.Build.0 = netstandard-Debug|Any CPU
- {9E984EB2-827E-4029-9647-FB5F8B67C553}.Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
- {9E984EB2-827E-4029-9647-FB5F8B67C553}.Release|Any CPU.Build.0 = netstandard-Release|Any CPU
+ {1AF01469-DBFC-4BA1-9331-8E39AA639FEE}.Debug|Any CPU.ActiveCfg = netstandard-Debug|Any CPU
+ {1AF01469-DBFC-4BA1-9331-8E39AA639FEE}.Debug|Any CPU.Build.0 = netstandard-Debug|Any CPU
+ {1AF01469-DBFC-4BA1-9331-8E39AA639FEE}.Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
+ {1AF01469-DBFC-4BA1-9331-8E39AA639FEE}.Release|Any CPU.Build.0 = netstandard-Release|Any CPU
{11ABE2F8-4FB9-48AC-91AA-D04503059550}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
{11ABE2F8-4FB9-48AC-91AA-D04503059550}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
{11ABE2F8-4FB9-48AC-91AA-D04503059550}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
{11ABE2F8-4FB9-48AC-91AA-D04503059550}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
- {1032D5F6-5AE7-4002-A0E4-FEBEADFEA977}.Debug|Any CPU.ActiveCfg = netstandard-Debug|Any CPU
- {1032D5F6-5AE7-4002-A0E4-FEBEADFEA977}.Debug|Any CPU.Build.0 = netstandard-Debug|Any CPU
- {1032D5F6-5AE7-4002-A0E4-FEBEADFEA977}.Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
- {1032D5F6-5AE7-4002-A0E4-FEBEADFEA977}.Release|Any CPU.Build.0 = netstandard-Release|Any CPU
- {9C524CA0-92FF-437B-B568-BCE8A794A69A}.Debug|Any CPU.ActiveCfg = netstandard-Debug|Any CPU
- {9C524CA0-92FF-437B-B568-BCE8A794A69A}.Debug|Any CPU.Build.0 = netstandard-Debug|Any CPU
- {9C524CA0-92FF-437B-B568-BCE8A794A69A}.Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
- {9C524CA0-92FF-437B-B568-BCE8A794A69A}.Release|Any CPU.Build.0 = netstandard-Release|Any CPU
+ {AAADA5D3-CF64-4E9D-943C-EFDC006D6366}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
+ {AAADA5D3-CF64-4E9D-943C-EFDC006D6366}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
+ {AAADA5D3-CF64-4E9D-943C-EFDC006D6366}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
+ {AAADA5D3-CF64-4E9D-943C-EFDC006D6366}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
+ {97DB4782-7AB3-4F4C-B716-CF722A0E6066}.Debug|Any CPU.ActiveCfg = netstandard-Debug|Any CPU
+ {97DB4782-7AB3-4F4C-B716-CF722A0E6066}.Debug|Any CPU.Build.0 = netstandard-Debug|Any CPU
+ {97DB4782-7AB3-4F4C-B716-CF722A0E6066}.Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
+ {97DB4782-7AB3-4F4C-B716-CF722A0E6066}.Release|Any CPU.Build.0 = netstandard-Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
- {9E984EB2-827E-4029-9647-FB5F8B67C553} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
+ {1AF01469-DBFC-4BA1-9331-8E39AA639FEE} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
{11ABE2F8-4FB9-48AC-91AA-D04503059550} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
- {1032D5F6-5AE7-4002-A0E4-FEBEADFEA977} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD}
- {9C524CA0-92FF-437B-B568-BCE8A794A69A} = {2E666815-2EDB-464B-9DF6-380BF4789AD4}
+ {AAADA5D3-CF64-4E9D-943C-EFDC006D6366} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD}
+ {97DB4782-7AB3-4F4C-B716-CF722A0E6066} = {2E666815-2EDB-464B-9DF6-380BF4789AD4}
EndGlobalSection
EndGlobal
diff --git a/src/System.Threading.Channels/ref/System.Threading.Channels.cs b/src/System.Threading.Channels/ref/System.Threading.Channels.cs
index 7ac0268176..d484aab487 100644
--- a/src/System.Threading.Channels/ref/System.Threading.Channels.cs
+++ b/src/System.Threading.Channels/ref/System.Threading.Channels.cs
@@ -26,8 +26,6 @@ namespace System.Threading.Channels
public static System.Threading.Channels.Channel<T> CreateBounded<T>(System.Threading.Channels.BoundedChannelOptions options) { throw null; }
public static System.Threading.Channels.Channel<T> CreateUnbounded<T>() { throw null; }
public static System.Threading.Channels.Channel<T> CreateUnbounded<T>(System.Threading.Channels.UnboundedChannelOptions options) { throw null; }
- public static System.Threading.Channels.Channel<T> CreateUnbuffered<T>() { throw null; }
- public static System.Threading.Channels.Channel<T> CreateUnbuffered<T>(System.Threading.Channels.UnbufferedChannelOptions options) { throw null; }
}
public partial class ChannelClosedException : System.InvalidOperationException
{
@@ -49,7 +47,7 @@ namespace System.Threading.Channels
public virtual System.Threading.Tasks.Task Completion { get { throw null; } }
public virtual System.Threading.Tasks.ValueTask<T> ReadAsync(CancellationToken cancellationToken = default) { throw null; }
public abstract bool TryRead(out T item);
- public abstract System.Threading.Tasks.Task<bool> WaitToReadAsync(System.Threading.CancellationToken cancellationToken=default);
+ public abstract System.Threading.Tasks.ValueTask<bool> WaitToReadAsync(System.Threading.CancellationToken cancellationToken=default);
}
public abstract partial class ChannelWriter<T>
{
@@ -57,8 +55,8 @@ namespace System.Threading.Channels
public void Complete(System.Exception error=null) { }
public virtual bool TryComplete(System.Exception error=null) { throw null; }
public abstract bool TryWrite(T item);
- public abstract System.Threading.Tasks.Task<bool> WaitToWriteAsync(System.Threading.CancellationToken cancellationToken=default);
- public virtual System.Threading.Tasks.Task WriteAsync(T item, System.Threading.CancellationToken cancellationToken=default) { throw null; }
+ public abstract System.Threading.Tasks.ValueTask<bool> WaitToWriteAsync(System.Threading.CancellationToken cancellationToken=default);
+ public virtual System.Threading.Tasks.ValueTask WriteAsync(T item, System.Threading.CancellationToken cancellationToken=default) { throw null; }
}
public abstract partial class Channel<T> : System.Threading.Channels.Channel<T, T>
{
@@ -76,8 +74,4 @@ namespace System.Threading.Channels
{
public UnboundedChannelOptions() { }
}
- public sealed partial class UnbufferedChannelOptions : System.Threading.Channels.ChannelOptions
- {
- public UnbufferedChannelOptions() { }
- }
}
diff --git a/src/System.Threading.Channels/ref/System.Threading.Channels.csproj b/src/System.Threading.Channels/ref/System.Threading.Channels.csproj
index 6f9782d4ff..492262d3e8 100644
--- a/src/System.Threading.Channels/ref/System.Threading.Channels.csproj
+++ b/src/System.Threading.Channels/ref/System.Threading.Channels.csproj
@@ -2,10 +2,12 @@
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
- <ProjectGuid>{9C524CA0-92FF-437B-B568-BCE8A794A69A}</ProjectGuid>
+ <ProjectGuid>{97DB4782-7AB3-4F4C-B716-CF722A0E6066}</ProjectGuid>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.3-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.3-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="System.Threading.Channels.cs" />
</ItemGroup>
@@ -20,4 +22,4 @@
<ProjectReference Include="..\..\System.Threading.Tasks.Extensions\ref\System.Threading.Tasks.Extensions.csproj" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project>
+</Project> \ No newline at end of file
diff --git a/src/System.Threading.Channels/src/Configurations.props b/src/System.Threading.Channels/src/Configurations.props
index 5f3b2623ed..7eb3ac6025 100644
--- a/src/System.Threading.Channels/src/Configurations.props
+++ b/src/System.Threading.Channels/src/Configurations.props
@@ -4,6 +4,7 @@
<BuildConfigurations>
netstandard1.3;
netstandard;
+ netcoreapp;
</BuildConfigurations>
</PropertyGroup>
</Project>
diff --git a/src/System.Threading.Channels/src/Resources/Strings.resx b/src/System.Threading.Channels/src/Resources/Strings.resx
index 2beea8a357..01229ace1d 100644
--- a/src/System.Threading.Channels/src/Resources/Strings.resx
+++ b/src/System.Threading.Channels/src/Resources/Strings.resx
@@ -120,4 +120,13 @@
<data name="ChannelClosedException_DefaultMessage" xml:space="preserve">
<value>The channel has been closed.</value>
</data>
-</root> \ No newline at end of file
+ <data name="InvalidOperation_IncompleteAsyncOperation" xml:space="preserve">
+ <value>The asynchronous operation has not completed.</value>
+ </data>
+ <data name="InvalidOperation_MultipleContinuations" xml:space="preserve">
+ <value>Another continuation was already registered.</value>
+ </data>
+ <data name="InvalidOperation_IncorrectToken" xml:space="preserve">
+ <value>The result of the operation was already consumed and may not be used again.</value>
+ </data>
+</root>
diff --git a/src/System.Threading.Channels/src/System.Threading.Channels.csproj b/src/System.Threading.Channels/src/System.Threading.Channels.csproj
index 9dc268ec36..072d3a5b67 100644
--- a/src/System.Threading.Channels/src/System.Threading.Channels.csproj
+++ b/src/System.Threading.Channels/src/System.Threading.Channels.csproj
@@ -2,12 +2,16 @@
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
- <ProjectGuid>{1032D5F6-5AE7-4002-A0E4-FEBEADFEA977}</ProjectGuid>
+ <ProjectGuid>{AAADA5D3-CF64-4E9D-943C-EFDC006D6366}</ProjectGuid>
<RootNamespace>System.Threading.Channels</RootNamespace>
<DocumentationFile>$(OutputPath)$(MSBuildProjectName).xml</DocumentationFile>
</PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.3-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.3-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="System\VoidResult.cs" />
<Compile Include="System\Collections\Generic\Dequeue.cs" />
@@ -22,10 +26,9 @@
<Compile Include="System\Threading\Channels\Channel_1.cs" />
<Compile Include="System\Threading\Channels\Channel_2.cs" />
<Compile Include="System\Threading\Channels\IDebugEnumerator.cs" />
- <Compile Include="System\Threading\Channels\Interactor.cs" />
+ <Compile Include="System\Threading\Channels\AsyncOperation.cs" />
<Compile Include="System\Threading\Channels\SingleConsumerUnboundedChannel.cs" />
<Compile Include="System\Threading\Channels\UnboundedChannel.cs" />
- <Compile Include="System\Threading\Channels\UnbufferedChannel.cs" />
<Compile Include="$(CommonPath)\System\Collections\Concurrent\SingleProducerConsumerQueue.cs">
<Link>Common\System\Collections\Concurrent\SingleProducerConsumerQueue.cs</Link>
</Compile>
diff --git a/src/System.Threading.Channels/src/System/Threading/Channels/AsyncOperation.cs b/src/System.Threading.Channels/src/System/Threading/Channels/AsyncOperation.cs
new file mode 100644
index 0000000000..257ccf6b37
--- /dev/null
+++ b/src/System.Threading.Channels/src/System/Threading/Channels/AsyncOperation.cs
@@ -0,0 +1,449 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Runtime.ExceptionServices;
+using System.Threading.Tasks;
+using System.Threading.Tasks.Sources;
+
+namespace System.Threading.Channels
+{
+ internal abstract class AsyncOperation
+ {
+ /// <summary>Sentinel object used in a field to indicate the operation is available for use.</summary>
+ protected static readonly Action<object> s_availableSentinel = new Action<object>(s => Debug.Fail($"{nameof(AsyncOperation)}.{nameof(s_availableSentinel)} invoked with {s}."));
+ /// <summary>Sentinel object used in a field to indicate the operation has completed.</summary>
+ protected static readonly Action<object> s_completedSentinel = new Action<object>(s => Debug.Fail($"{nameof(AsyncOperation)}.{nameof(s_completedSentinel)} invoked with {s}"));
+
+ /// <summary>Throws an exception indicating that the operation's result was accessed before the operation completed.</summary>
+ protected static void ThrowIncompleteOperationException() =>
+ throw new InvalidOperationException(SR.InvalidOperation_IncompleteAsyncOperation);
+
+ /// <summary>Throws an exception indicating that multiple continuations can't be set for the same operation.</summary>
+ protected static void ThrowMultipleContinuations() =>
+ throw new InvalidOperationException(SR.InvalidOperation_MultipleContinuations);
+
+ /// <summary>Throws an exception indicating that the operation was used after it was supposed to be used.</summary>
+ protected static void ThrowIncorrectCurrentIdException() =>
+ throw new InvalidOperationException(SR.InvalidOperation_IncorrectToken);
+ }
+
+ /// <summary>The representation of an asynchronous operation that has a result value.</summary>
+ /// <typeparam name="TResult">Specifies the type of the result. May be <see cref="VoidResult"/>.</typeparam>
+ internal class AsyncOperation<TResult> : AsyncOperation, IValueTaskSource, IValueTaskSource<TResult>
+ {
+ /// <summary>Registration with a provided cancellation token.</summary>
+ private readonly CancellationTokenRegistration _registration;
+ /// <summary>true if this object is pooled and reused; otherwise, false.</summary>
+ /// <remarks>
+ /// If the operation is cancelable, then it can't be pooled. And if it's poolable, there must never be race conditions to complete it,
+ /// which is the main reason poolable objects can't be cancelable, as then cancellation could fire, the object could get reused,
+ /// and then we may end up trying to complete an object that's used by someone else.
+ /// </remarks>
+ private readonly bool _pooled;
+ /// <summary>Whether continuations should be forced to run asynchronously.</summary>
+ private readonly bool _runContinuationsAsynchronously;
+
+ /// <summary>Only relevant to cancelable operations; 0 if the operation hasn't had completion reserved, 1 if it has.</summary>
+ private volatile int _completionReserved = 0;
+ /// <summary>The result of the operation.</summary>
+ private TResult _result;
+ /// <summary>Any error that occurred during the operation.</summary>
+ private ExceptionDispatchInfo _error;
+ /// <summary>The continuation callback.</summary>
+ /// <remarks>
+ /// This may be the completion sentinel if the operation has already completed.
+ /// This may be the available sentinel if the operation is being pooled and is available for use.
+ /// This may be null if the operation is pending.
+ /// This may be another callback if the operation has had a callback hooked up with OnCompleted.
+ /// </remarks>
+ private Action<object> _continuation;
+ /// <summary>State object to be passed to <see cref="_continuation"/>.</summary>
+ private object _continuationState;
+ /// <summary>Scheduling context (a <see cref="SynchronizationContext"/> or <see cref="TaskScheduler"/>) to which to queue the continuation. May be null.</summary>
+ private object _schedulingContext;
+ /// <summary>Execution context to use when invoking <see cref="_continuation"/>. May be null.</summary>
+ private ExecutionContext _executionContext;
+ /// <summary>The token value associated with the current operation.</summary>
+ /// <remarks>
+ /// IValueTaskSource operations on this instance are only valid if the provided token matches this value,
+ /// which is incremented once GetResult is called to avoid multiple awaits on the same instance.
+ /// </remarks>
+ private short _currentId;
+
+ /// <summary>Initializes the interactor.</summary>
+ /// <param name="runContinuationsAsynchronously">true if continuations should be forced to run asynchronously; otherwise, false.</param>
+ /// <param name="cancellationToken">The cancellation token used to cancel the operation.</param>
+ /// <param name="pooled">Whether this instance is pooled and reused.</param>
+ public AsyncOperation(bool runContinuationsAsynchronously, CancellationToken cancellationToken = default, bool pooled = false)
+ {
+ _continuation = pooled ? s_availableSentinel : null;
+ _pooled = pooled;
+ _runContinuationsAsynchronously = runContinuationsAsynchronously;
+ if (cancellationToken.CanBeCanceled)
+ {
+ Debug.Assert(!_pooled, "Cancelable operations can't be pooled");
+ CancellationToken = cancellationToken;
+ _registration = cancellationToken.Register(s =>
+ {
+ var thisRef = (AsyncOperation<TResult>)s;
+ thisRef.TrySetCanceled(thisRef.CancellationToken);
+ }, this);
+ }
+ }
+
+ /// <summary>Gets or sets the next operation in the linked list of operations.</summary>
+ public AsyncOperation<TResult> Next { get; set; }
+ /// <summary>Gets the cancellation token associated with this operation.</summary>
+ public CancellationToken CancellationToken { get; }
+ /// <summary>Gets a <see cref="ValueTask"/> backed by this instance and its current token.</summary>
+ public ValueTask ValueTask => new ValueTask(this, _currentId);
+ /// <summary>Gets a <see cref="ValueTask{TResult}"/> backed by this instance and its current token.</summary>
+ public ValueTask<TResult> ValueTaskOfT => new ValueTask<TResult>(this, _currentId);
+
+ /// <summary>Gets the current status of the operation.</summary>
+ /// <param name="token">The token that must match <see cref="_currentId"/>.</param>
+ public ValueTaskSourceStatus GetStatus(short token)
+ {
+ if (_currentId == token)
+ {
+ return
+ !IsCompleted ? ValueTaskSourceStatus.Pending :
+ _error == null ? ValueTaskSourceStatus.Succeeded :
+ _error.SourceException is OperationCanceledException ? ValueTaskSourceStatus.Canceled :
+ ValueTaskSourceStatus.Faulted;
+ }
+
+ ThrowIncorrectCurrentIdException();
+ return default; // just to satisfy compiler
+ }
+
+ /// <summary>Gets whether the operation has completed.</summary>
+ /// <remarks>
+ /// The operation is considered completed if both a) it's in the completed state,
+ /// AND b) it has a non-null continuation. We need to consider both because they're
+ /// not set atomically. If we only considered the state, then if we set the state to
+ /// completed and then set the continuation, it's possible for an awaiter to check
+ /// IsCompleted, see true, call GetResult, and return the object to the pool, and only
+ /// then do we try to store the continuation into an object we no longer own. If we
+ /// only considered the state, then if we set the continuation and then set the state,
+ /// a racing awaiter could see the continuation set before the state has transitioned
+ /// to completed and could end up calling GetResult in an incomplete state. And if we
+ /// only considered the continuation, then we have issues if OnCompleted is used before
+ /// the operation completes, as the continuation will be
+ /// </remarks>
+ internal bool IsCompleted => ReferenceEquals(_continuation, s_completedSentinel);
+
+ /// <summary>Gets the result of the operation.</summary>
+ /// <param name="token">The token that must match <see cref="_currentId"/>.</param>
+ public TResult GetResult(short token)
+ {
+ if (_currentId != token)
+ {
+ ThrowIncorrectCurrentIdException();
+ }
+
+ if (!IsCompleted)
+ {
+ ThrowIncompleteOperationException();
+ }
+
+ ExceptionDispatchInfo error = _error;
+ TResult result = _result;
+ _currentId++;
+
+ if (_pooled)
+ {
+ Volatile.Write(ref _continuation, s_availableSentinel); // only after fetching all needed data
+ }
+
+ error?.Throw();
+ return result;
+ }
+
+ /// <summary>Gets the result of the operation.</summary>
+ /// <param name="token">The token that must match <see cref="_currentId"/>.</param>
+ void IValueTaskSource.GetResult(short token)
+ {
+ if (_currentId != token)
+ {
+ ThrowIncorrectCurrentIdException();
+ }
+
+ if (!IsCompleted)
+ {
+ ThrowIncompleteOperationException();
+ }
+
+ ExceptionDispatchInfo error = _error;
+ _currentId++;
+
+ if (_pooled)
+ {
+ Volatile.Write(ref _continuation, s_availableSentinel); // only after fetching all needed data
+ }
+
+ error?.Throw();
+ }
+
+ /// <summary>Attempts to take ownership of the pooled instance.</summary>
+ /// <returns>true if the instance is now owned by the caller, in which case its state has been reset; otherwise, false.</returns>
+ public bool TryOwnAndReset()
+ {
+ Debug.Assert(_pooled, "Should only be used for pooled objects");
+ if (ReferenceEquals(Interlocked.CompareExchange(ref _continuation, null, s_availableSentinel), s_availableSentinel))
+ {
+ _continuationState = null;
+ _result = default;
+ _error = null;
+ _schedulingContext = null;
+ _executionContext = null;
+ return true;
+ }
+
+ return false;
+ }
+
+ /// <summary>Hooks up a continuation callback for when the operation has completed.</summary>
+ /// <param name="continuation">The callback.</param>
+ /// <param name="state">The state to pass to the callback.</param>
+ /// <param name="token">The current token that must match <see cref="_currentId"/>.</param>
+ /// <param name="flags">Flags that influence the behavior of the callback.</param>
+ public void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags)
+ {
+ if (_currentId != token)
+ {
+ ThrowIncorrectCurrentIdException();
+ }
+
+ // We need to store the state before the CompareExchange, so that if it completes immediately
+ // after the CompareExchange, it'll find the state already stored. If someone misuses this
+ // and schedules multiple continuations erroneously, we could end up using the wrong state.
+ // Make a best-effort attempt to catch such misuse.
+ if (_continuationState != null)
+ {
+ ThrowMultipleContinuations();
+ }
+ _continuationState = state;
+
+ // Capture the execution context if necessary.
+ Debug.Assert(_executionContext == null);
+ if ((flags & ValueTaskSourceOnCompletedFlags.FlowExecutionContext) != 0)
+ {
+ _executionContext = ExecutionContext.Capture();
+ }
+
+ // Capture the scheduling context if necessary.
+ Debug.Assert(_schedulingContext == null);
+ SynchronizationContext sc = null;
+ TaskScheduler ts = null;
+ if ((flags & ValueTaskSourceOnCompletedFlags.UseSchedulingContext) != 0)
+ {
+ sc = SynchronizationContext.Current;
+ if (sc != null && sc.GetType() != typeof(SynchronizationContext))
+ {
+ _schedulingContext = sc;
+ }
+ else
+ {
+ ts = TaskScheduler.Current;
+ if (ts != TaskScheduler.Default)
+ {
+ _schedulingContext = ts;
+ }
+ }
+ }
+
+ // Try to set the provided continuation into _continuation. If this succeeds, that means the operation
+ // has not yet completed, and the completer will be responsible for invoking the callback. If this fails,
+ // that means the operation has already completed, and we must invoke the callback, but because we're still
+ // inside the awaiter's OnCompleted method and we want to avoid possible stack dives, we must invoke
+ // the continuation asynchronously rather than synchronously.
+ Action<object> prevContinuation = Interlocked.CompareExchange(ref _continuation, continuation, null);
+ if (prevContinuation != null)
+ {
+ // If the set failed because there's already a delegate in _continuation, but that delegate is
+ // something other than s_completedSentinel, something went wrong, which should only happen if
+ // the instance was erroneously used, likely to hook up multiple continuations.
+ Debug.Assert(IsCompleted, $"Expected IsCompleted");
+ if (!ReferenceEquals(prevContinuation, s_completedSentinel))
+ {
+ Debug.Assert(prevContinuation != s_availableSentinel, "Continuation was the available sentinel.");
+ ThrowMultipleContinuations();
+ }
+
+ // Queue the continuation.
+ if (sc != null)
+ {
+ sc.Post(s =>
+ {
+ var t = (Tuple<Action<object>, object>)s;
+ t.Item1(t.Item2);
+ }, Tuple.Create(continuation, state));
+ }
+ else
+ {
+ Task.Factory.StartNew(continuation, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, ts ?? TaskScheduler.Default);
+ }
+ }
+ }
+
+ /// <summary>Unregisters from cancellation.</summary>
+ /// <remarks>
+ /// This is important for two reasons:
+ /// 1. To avoid leaking a registration into a token, so it must be done prior to completing the operation.
+ /// 2. To avoid having to worry about concurrent completion; once invoked, the caller can be guaranteed
+ /// that no one else will try to complete the operation (assuming the caller is properly constructed
+ /// and themselves guarantees only a single completer other than through cancellation).
+ /// </remarks>
+ public void UnregisterCancellation() => _registration.Dispose();
+
+ /// <summary>Completes the operation with a success state and the specified result.</summary>
+ /// <param name="item">The result value.</param>
+ /// <returns>true if the operation could be successfully transitioned to a completed state; false if it was already completed.</returns>
+ public bool TrySetResult(TResult item)
+ {
+ UnregisterCancellation();
+
+ if (TryReserveCompletionIfCancelable())
+ {
+ _result = item;
+ SignalCompletion();
+ return true;
+ }
+
+ return false;
+ }
+
+ /// <summary>Completes the operation with a failed state and the specified error.</summary>
+ /// <param name="exception">The error.</param>
+ /// <returns>true if the operation could be successfully transitioned to a completed state; false if it was already completed.</returns>
+ public bool TrySetException(Exception exception)
+ {
+ UnregisterCancellation();
+
+ if (TryReserveCompletionIfCancelable())
+ {
+ _error = ExceptionDispatchInfo.Capture(exception);
+ SignalCompletion();
+ return true;
+ }
+
+ return false;
+ }
+
+ /// <summary>Completes the operation with a failed state and a cancellation error.</summary>
+ /// <param name="cancellationToken">The cancellation token that caused the cancellation.</param>
+ /// <returns>true if the operation could be successfully transitioned to a completed state; false if it was already completed.</returns>
+ public bool TrySetCanceled(CancellationToken cancellationToken = default)
+ {
+ if (TryReserveCompletionIfCancelable())
+ {
+ _error = ExceptionDispatchInfo.Capture(new OperationCanceledException(cancellationToken));
+ SignalCompletion();
+ return true;
+ }
+
+ return false;
+ }
+
+ /// <summary>Attempts to reserve this instance for completion.</summary>
+ /// <remarks>
+ /// This will always return true for non-cancelable objects, as they only ever have a single owner
+ /// responsible for completion. For cancelable operations, this will attempt to atomically transition
+ /// from Initialized to CompletionReserved.
+ /// </remarks>
+ private bool TryReserveCompletionIfCancelable() =>
+ !CancellationToken.CanBeCanceled ||
+ Interlocked.CompareExchange(ref _completionReserved, 1, 0) == 0;
+
+ /// <summary>Signals to a registered continuation that the operation has now completed.</summary>
+ private void SignalCompletion()
+ {
+ if (_continuation != null || Interlocked.CompareExchange(ref _continuation, s_completedSentinel, null) != null)
+ {
+ ExecutionContext ec = _executionContext;
+ if (ec != null)
+ {
+ ExecutionContext.Run(ec, s => ((AsyncOperation<TResult>)s).SignalCompletionCore(), this);
+ }
+ else
+ {
+ SignalCompletionCore();
+ }
+ }
+ }
+
+ /// <summary>Invokes the registered continuation; separated out of SignalCompletion for convenience so that it may be invoked on multiple code paths.</summary>
+ private void SignalCompletionCore()
+ {
+ Debug.Assert(_continuation != s_completedSentinel, $"The continuation was the completion sentinel.");
+ Debug.Assert(_continuation != s_availableSentinel, $"The continuation was the available sentinel.");
+
+ if (_schedulingContext == null)
+ {
+ // There's no captured scheduling context. If we're forced to run continuations asynchronously, queue it.
+ // Otherwise fall through to invoke it synchronously.
+ if (_runContinuationsAsynchronously)
+ {
+ Task.Factory.StartNew(s => ((AsyncOperation<TResult>)s).SetCompletionAndInvokeContinuation(), this,
+ CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
+ return;
+ }
+ }
+ else if (_schedulingContext is SynchronizationContext sc)
+ {
+ // There's a captured synchronization context. If we're forced to run continuations asynchronously,
+ // or if there's a current synchronization context that's not the one we're targeting, queue it.
+ // Otherwise fall through to invoke it synchronously.
+ if (_runContinuationsAsynchronously || sc != SynchronizationContext.Current)
+ {
+ sc.Post(s => ((AsyncOperation<TResult>)s).SetCompletionAndInvokeContinuation(), this);
+ return;
+ }
+ }
+ else
+ {
+ // There's a captured TaskScheduler. If we're forced to run continuations asynchronously,
+ // or if there's a current scheduler that's not the one we're targeting, queue it.
+ // Otherwise fall through to invoke it synchronously.
+ TaskScheduler ts = (TaskScheduler)_schedulingContext;
+ Debug.Assert(ts != null, "Expected a TaskScheduler");
+ if (_runContinuationsAsynchronously || ts != TaskScheduler.Current)
+ {
+ Task.Factory.StartNew(s => ((AsyncOperation<TResult>)s).SetCompletionAndInvokeContinuation(), this,
+ CancellationToken.None, TaskCreationOptions.DenyChildAttach, ts);
+ return;
+ }
+ }
+
+ // Invoke the continuation synchronously.
+ SetCompletionAndInvokeContinuation();
+ }
+
+ private void SetCompletionAndInvokeContinuation()
+ {
+ Action<object> c = _continuation;
+ _continuation = s_completedSentinel;
+ c(_continuationState);
+ }
+ }
+
+ /// <summary>The representation of an asynchronous operation that has a result value and carries additional data with it.</summary>
+ /// <typeparam name="TData">Specifies the type of data being written.</typeparam>
+ internal sealed class VoidAsyncOperationWithData<TData> : AsyncOperation<VoidResult>
+ {
+ /// <summary>Initializes the interactor.</summary>
+ /// <param name="runContinuationsAsynchronously">true if continuations should be forced to run asynchronously; otherwise, false.</param>
+ /// <param name="cancellationToken">The cancellation token used to cancel the operation.</param>
+ /// <param name="pooled">Whether this instance is pooled and reused.</param>
+ public VoidAsyncOperationWithData(bool runContinuationsAsynchronously, CancellationToken cancellationToken = default, bool pooled = false) :
+ base(runContinuationsAsynchronously, cancellationToken, pooled)
+ {
+ }
+
+ /// <summary>The item being written.</summary>
+ public TData Item { get; set; }
+ }
+}
diff --git a/src/System.Threading.Channels/src/System/Threading/Channels/BoundedChannel.cs b/src/System.Threading.Channels/src/System/Threading/Channels/BoundedChannel.cs
index 23047aba28..a4ff7d070f 100644
--- a/src/System.Threading.Channels/src/System/Threading/Channels/BoundedChannel.cs
+++ b/src/System.Threading.Channels/src/System/Threading/Channels/BoundedChannel.cs
@@ -9,7 +9,7 @@ using System.Threading.Tasks;
namespace System.Threading.Channels
{
/// <summary>Provides a channel with a bounded capacity.</summary>
- [DebuggerDisplay("Items={ItemsCountForDebugger}, Capacity={_bufferedCapacity}")]
+ [DebuggerDisplay("Items={ItemsCountForDebugger}, Capacity={_bufferedCapacity}, Mode={_mode}, Closed={ChannelIsClosedForDebugger}")]
[DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))]
internal sealed class BoundedChannel<T> : Channel<T>, IDebugEnumerable<T>
{
@@ -21,12 +21,14 @@ namespace System.Threading.Channels
private readonly int _bufferedCapacity;
/// <summary>Items currently stored in the channel waiting to be read.</summary>
private readonly Dequeue<T> _items = new Dequeue<T>();
+ /// <summary>Readers waiting to read from the channel.</summary>
+ private readonly Dequeue<AsyncOperation<T>> _blockedReaders = new Dequeue<AsyncOperation<T>>();
/// <summary>Writers waiting to write to the channel.</summary>
- private readonly Dequeue<WriterInteractor<T>> _blockedWriters = new Dequeue<WriterInteractor<T>>();
- /// <summary>Task signaled when any WaitToReadAsync waiters should be woken up.</summary>
- private ReaderInteractor<bool> _waitingReaders;
- /// <summary>Task signaled when any WaitToWriteAsync waiters should be woken up.</summary>
- private ReaderInteractor<bool> _waitingWriters;
+ private readonly Dequeue<VoidAsyncOperationWithData<T>> _blockedWriters = new Dequeue<VoidAsyncOperationWithData<T>>();
+ /// <summary>Linked list of WaitToReadAsync waiters.</summary>
+ private AsyncOperation<bool> _waitingReadersTail;
+ /// <summary>Linked list of WaitToWriteAsync waiters.</summary>
+ private AsyncOperation<bool> _waitingWritersTail;
/// <summary>Whether to force continuations to be executed asynchronously from producer writes.</summary>
private readonly bool _runContinuationsAsynchronously;
/// <summary>Set to non-null once Complete has been called.</summary>
@@ -49,10 +51,20 @@ namespace System.Threading.Channels
Writer = new BoundedChannelWriter(this);
}
- private sealed class BoundedChannelReader : ChannelReader<T>
+ [DebuggerDisplay("Items={ItemsCountForDebugger}")]
+ [DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))]
+ private sealed class BoundedChannelReader : ChannelReader<T>, IDebugEnumerable<T>
{
internal readonly BoundedChannel<T> _parent;
- internal BoundedChannelReader(BoundedChannel<T> parent) => _parent = parent;
+ private readonly AsyncOperation<T> _readerSingleton;
+ private readonly AsyncOperation<bool> _waiterSingleton;
+
+ internal BoundedChannelReader(BoundedChannel<T> parent)
+ {
+ _parent = parent;
+ _readerSingleton = new AsyncOperation<T>(parent._runContinuationsAsynchronously, pooled: true);
+ _waiterSingleton = new AsyncOperation<bool>(parent._runContinuationsAsynchronously, pooled: true);
+ }
public override Task Completion => _parent._completion.Task;
@@ -75,11 +87,54 @@ namespace System.Threading.Channels
return false;
}
- public override Task<bool> WaitToReadAsync(CancellationToken cancellationToken)
+ public override ValueTask<T> ReadAsync(CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
- return Task.FromCanceled<bool>(cancellationToken);
+ return new ValueTask<T>(Task.FromCanceled<T>(cancellationToken));
+ }
+
+ BoundedChannel<T> parent = _parent;
+ lock (parent.SyncObj)
+ {
+ parent.AssertInvariants();
+
+ // If there are any items, hand one back.
+ if (!parent._items.IsEmpty)
+ {
+ return new ValueTask<T>(DequeueItemAndPostProcess());
+ }
+
+ // There weren't any items. If we're done writing so that there
+ // will never be more items, fail.
+ if (parent._doneWriting != null)
+ {
+ return ChannelUtilities.GetInvalidCompletionValueTask<T>(parent._doneWriting);
+ }
+
+ // If we're able to use the singleton reader, do so.
+ if (!cancellationToken.CanBeCanceled)
+ {
+ AsyncOperation<T> singleton = _readerSingleton;
+ if (singleton.TryOwnAndReset())
+ {
+ parent._blockedReaders.EnqueueTail(singleton);
+ return singleton.ValueTaskOfT;
+ }
+ }
+
+ // Otherwise, queue the reader.
+ var reader = new AsyncOperation<T>(parent._runContinuationsAsynchronously, cancellationToken);
+ parent._blockedReaders.EnqueueTail(reader);
+ return reader.ValueTaskOfT;
+ }
+ }
+
+ public override ValueTask<bool> WaitToReadAsync(CancellationToken cancellationToken)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return new ValueTask<bool>(Task.FromCanceled<bool>(cancellationToken));
}
BoundedChannel<T> parent = _parent;
@@ -90,20 +145,35 @@ namespace System.Threading.Channels
// If there are any items available, a read is possible.
if (!parent._items.IsEmpty)
{
- return ChannelUtilities.s_trueTask;
+ return new ValueTask<bool>(true);
}
// There were no items available, so if we're done writing, a read will never be possible.
if (parent._doneWriting != null)
{
return parent._doneWriting != ChannelUtilities.s_doneWritingSentinel ?
- Task.FromException<bool>(parent._doneWriting) :
- ChannelUtilities.s_falseTask;
+ new ValueTask<bool>(Task.FromException<bool>(parent._doneWriting)) :
+ default;
}
// There were no items available, but there could be in the future, so ensure
// there's a blocked reader task and return it.
- return ChannelUtilities.GetOrCreateWaiter(ref parent._waitingReaders, parent._runContinuationsAsynchronously, cancellationToken);
+
+ // If we're able to use the singleton waiter, do so.
+ if (!cancellationToken.CanBeCanceled)
+ {
+ AsyncOperation<bool> singleton = _waiterSingleton;
+ if (singleton.TryOwnAndReset())
+ {
+ ChannelUtilities.QueueWaiter(ref parent._waitingReadersTail, singleton);
+ return singleton.ValueTaskOfT;
+ }
+ }
+
+ // Otherwise, queue a reader.
+ var waiter = new AsyncOperation<bool>(parent._runContinuationsAsynchronously, cancellationToken);
+ ChannelUtilities.QueueWaiter(ref _parent._waitingReadersTail, waiter);
+ return waiter.ValueTaskOfT;
}
}
@@ -117,40 +187,68 @@ namespace System.Threading.Channels
// Dequeue an item.
T item = parent._items.DequeueHead();
- // If we're now empty and we're done writing, complete the channel.
- if (parent._doneWriting != null && parent._items.IsEmpty)
+ if (parent._doneWriting != null)
{
- ChannelUtilities.Complete(parent._completion, parent._doneWriting);
+ // We're done writing, so if we're now empty, complete the channel.
+ if (parent._items.IsEmpty)
+ {
+ ChannelUtilities.Complete(parent._completion, parent._doneWriting);
+ }
}
-
- // If there are any writers blocked, there's now room for at least one
- // to be promoted to have its item moved into the items queue. We need
- // to loop while trying to complete the writer in order to find one that
- // hasn't yet been canceled (canceled writers transition to canceled but
- // remain in the physical queue).
- while (!parent._blockedWriters.IsEmpty)
+ else
{
- WriterInteractor<T> w = parent._blockedWriters.DequeueHead();
- if (w.Success(default))
+ // If there are any writers blocked, there's now room for at least one
+ // to be promoted to have its item moved into the items queue. We need
+ // to loop while trying to complete the writer in order to find one that
+ // hasn't yet been canceled (canceled writers transition to canceled but
+ // remain in the physical queue).
+ //
+ // (It's possible for _doneWriting to be non-null due to Complete
+ // having been called but for there to still be blocked/waiting writers.
+ // This is a temporary condition, after which Complete has set _doneWriting
+ // and then exited the lock; at that point it'll proceed to clean this up,
+ // so we just ignore them.)
+
+ while (!parent._blockedWriters.IsEmpty)
{
- parent._items.EnqueueTail(w.Item);
- return item;
+ VoidAsyncOperationWithData<T> w = parent._blockedWriters.DequeueHead();
+ if (w.TrySetResult(default))
+ {
+ parent._items.EnqueueTail(w.Item);
+ return item;
+ }
}
- }
- // There was no blocked writer, so see if there's a WaitToWriteAsync
- // we should wake up.
- ChannelUtilities.WakeUpWaiters(ref parent._waitingWriters, result: true);
+ // There was no blocked writer, so see if there's a WaitToWriteAsync
+ // we should wake up.
+ ChannelUtilities.WakeUpWaiters(ref parent._waitingWritersTail, result: true);
+ }
// Return the item
return item;
}
+
+ /// <summary>Gets the number of items in the channel. This should only be used by the debugger.</summary>
+ private int ItemsCountForDebugger => _parent._items.Count;
+
+ /// <summary>Gets an enumerator the debugger can use to show the contents of the channel.</summary>
+ IEnumerator<T> IDebugEnumerable<T>.GetEnumerator() => _parent._items.GetEnumerator();
}
- private sealed class BoundedChannelWriter : ChannelWriter<T>
+ [DebuggerDisplay("Items={ItemsCountForDebugger}, Capacity={CapacityForDebugger}")]
+ [DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))]
+ private sealed class BoundedChannelWriter : ChannelWriter<T>, IDebugEnumerable<T>
{
internal readonly BoundedChannel<T> _parent;
- internal BoundedChannelWriter(BoundedChannel<T> parent) => _parent = parent;
+ private readonly VoidAsyncOperationWithData<T> _writerSingleton;
+ private readonly AsyncOperation<bool> _waiterSingleton;
+
+ internal BoundedChannelWriter(BoundedChannel<T> parent)
+ {
+ _parent = parent;
+ _writerSingleton = new VoidAsyncOperationWithData<T>(runContinuationsAsynchronously: true, pooled: true);
+ _waiterSingleton = new AsyncOperation<bool>(runContinuationsAsynchronously: true, pooled: true);
+ }
public override bool TryComplete(Exception error)
{
@@ -181,14 +279,15 @@ namespace System.Threading.Channels
ChannelUtilities.Complete(parent._completion, error);
}
- // At this point, _blockedWriters and _waitingReaders/Writers will not be mutated:
+ // At this point, _blockedReaders/Writers and _waitingReaders/Writers will not be mutated:
// they're only mutated by readers/writers while holding the lock, and only if _doneWriting is null.
// We also know that only one thread (this one) will ever get here, as only that thread
// will be the one to transition from _doneWriting false to true. As such, we can
// freely manipulate them without any concurrency concerns.
- ChannelUtilities.FailInteractors<WriterInteractor<T>, VoidResult>(parent._blockedWriters, ChannelUtilities.CreateInvalidCompletionException(error));
- ChannelUtilities.WakeUpWaiters(ref parent._waitingReaders, result: false, error: error);
- ChannelUtilities.WakeUpWaiters(ref parent._waitingWriters, result: false, error: error);
+ ChannelUtilities.FailOperations<AsyncOperation<T>, T>(parent._blockedReaders, ChannelUtilities.CreateInvalidCompletionException(error));
+ ChannelUtilities.FailOperations<VoidAsyncOperationWithData<T>, VoidResult>(parent._blockedWriters, ChannelUtilities.CreateInvalidCompletionException(error));
+ ChannelUtilities.WakeUpWaiters(ref parent._waitingReadersTail, result: false, error: error);
+ ChannelUtilities.WakeUpWaiters(ref parent._waitingWritersTail, result: false, error: error);
// Successfully transitioned to completed.
return true;
@@ -196,7 +295,8 @@ namespace System.Threading.Channels
public override bool TryWrite(T item)
{
- ReaderInteractor<bool> waitingReaders = null;
+ AsyncOperation<T> blockedReader = null;
+ AsyncOperation<bool> waitingReadersTail = null;
BoundedChannel<T> parent = _parent;
lock (parent.SyncObj)
@@ -214,16 +314,34 @@ namespace System.Threading.Channels
if (count == 0)
{
- // There are no items in the channel, which means we may have waiting readers.
- // Store the item.
- parent._items.EnqueueTail(item);
- waitingReaders = parent._waitingReaders;
- if (waitingReaders == null)
+ // There are no items in the channel, which means we may have blocked/waiting readers.
+
+ // If there are any blocked readers, find one that's not canceled
+ // and store it to complete outside of the lock, in case it has
+ // continuations that'll run synchronously
+ while (!parent._blockedReaders.IsEmpty)
{
- // If no one's waiting to be notified about a 0-to-1 transition, we're done.
- return true;
+ AsyncOperation<T> r = parent._blockedReaders.DequeueHead();
+ r.UnregisterCancellation(); // ensure that once we grab it, we own its completion
+ if (!r.IsCompleted)
+ {
+ blockedReader = r;
+ break;
+ }
+ }
+
+ if (blockedReader == null)
+ {
+ // If there wasn't a blocked reader, then store the item. If no one's waiting
+ // to be notified about a 0-to-1 transition, we're done.
+ parent._items.EnqueueTail(item);
+ waitingReadersTail = parent._waitingReadersTail;
+ if (waitingReadersTail == null)
+ {
+ return true;
+ }
+ parent._waitingReadersTail = null;
}
- parent._waitingReaders = null;
}
else if (count < parent._bufferedCapacity)
{
@@ -257,19 +375,32 @@ namespace System.Threading.Channels
}
}
- // We stored an item bringing the count up from 0 to 1. Alert
- // any waiting readers that there may be something for them to consume.
- // Since we're no longer holding the lock, it's possible we'll end up
- // waking readers that have since come in.
- waitingReaders.Success(item: true);
+ // We either wrote the item already, or we're transferring it to the blocked reader we grabbed.
+ if (blockedReader != null)
+ {
+ Debug.Assert(waitingReadersTail == null, "Shouldn't have any waiters to wake up");
+
+ // Transfer the written item to the blocked reader.
+ bool success = blockedReader.TrySetResult(item);
+ Debug.Assert(success, "We should always be able to complete the reader.");
+ }
+ else
+ {
+ // We stored an item bringing the count up from 0 to 1. Alert
+ // any waiting readers that there may be something for them to consume.
+ // Since we're no longer holding the lock, it's possible we'll end up
+ // waking readers that have since come in.
+ ChannelUtilities.WakeUpWaiters(ref waitingReadersTail, result: true);
+ }
+
return true;
}
- public override Task<bool> WaitToWriteAsync(CancellationToken cancellationToken)
+ public override ValueTask<bool> WaitToWriteAsync(CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
- return Task.FromCanceled<bool>(cancellationToken);
+ return new ValueTask<bool>(Task.FromCanceled<bool>(cancellationToken));
}
BoundedChannel<T> parent = _parent;
@@ -281,8 +412,8 @@ namespace System.Threading.Channels
if (parent._doneWriting != null)
{
return parent._doneWriting != ChannelUtilities.s_doneWritingSentinel ?
- Task.FromException<bool>(parent._doneWriting) :
- ChannelUtilities.s_falseTask;
+ new ValueTask<bool>(Task.FromException<bool>(parent._doneWriting)) :
+ default;
}
// If there's space to write, a write is possible.
@@ -290,22 +421,38 @@ namespace System.Threading.Channels
// full we'll just drop an element to make room.
if (parent._items.Count < parent._bufferedCapacity || parent._mode != BoundedChannelFullMode.Wait)
{
- return ChannelUtilities.s_trueTask;
+ return new ValueTask<bool>(true);
}
// We're still allowed to write, but there's no space, so ensure a waiter is queued and return it.
- return ChannelUtilities.GetOrCreateWaiter(ref parent._waitingWriters, runContinuationsAsynchronously: true, cancellationToken);
+
+ // If we're able to use the singleton waiter, do so.
+ if (!cancellationToken.CanBeCanceled)
+ {
+ AsyncOperation<bool> singleton = _waiterSingleton;
+ if (singleton.TryOwnAndReset())
+ {
+ ChannelUtilities.QueueWaiter(ref parent._waitingWritersTail, singleton);
+ return singleton.ValueTaskOfT;
+ }
+ }
+
+ // Otherwise, queue a waiter.
+ var waiter = new AsyncOperation<bool>(runContinuationsAsynchronously: true, cancellationToken);
+ ChannelUtilities.QueueWaiter(ref parent._waitingWritersTail, waiter);
+ return waiter.ValueTaskOfT;
}
}
- public override Task WriteAsync(T item, CancellationToken cancellationToken)
+ public override ValueTask WriteAsync(T item, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
- return Task.FromCanceled(cancellationToken);
+ return new ValueTask(Task.FromCanceled(cancellationToken));
}
- ReaderInteractor<bool> waitingReaders = null;
+ AsyncOperation<T> blockedReader = null;
+ AsyncOperation<bool> waitingReadersTail = null;
BoundedChannel<T> parent = _parent;
lock (parent.SyncObj)
@@ -315,7 +462,7 @@ namespace System.Threading.Channels
// If we're done writing, trying to write is an error.
if (parent._doneWriting != null)
{
- return Task.FromException(ChannelUtilities.CreateInvalidCompletionException(parent._doneWriting));
+ return new ValueTask(Task.FromException(ChannelUtilities.CreateInvalidCompletionException(parent._doneWriting)));
}
// Get the number of items in the channel currently.
@@ -323,16 +470,34 @@ namespace System.Threading.Channels
if (count == 0)
{
- // There are no items in the channel, which means we may have waiting readers.
- // Store the item.
- parent._items.EnqueueTail(item);
- waitingReaders = parent._waitingReaders;
- if (waitingReaders == null)
+ // There are no items in the channel, which means we may have blocked/waiting readers.
+
+ // If there are any blocked readers, find one that's not canceled
+ // and store it to complete outside of the lock, in case it has
+ // continuations that'll run synchronously
+ while (!parent._blockedReaders.IsEmpty)
+ {
+ AsyncOperation<T> r = parent._blockedReaders.DequeueHead();
+ r.UnregisterCancellation(); // ensure that once we grab it, we own its completion
+ if (!r.IsCompleted)
+ {
+ blockedReader = r;
+ break;
+ }
+ }
+
+ if (blockedReader == null)
{
- // If no one's waiting to be notified about a 0-to-1 transition, we're done.
- return ChannelUtilities.s_trueTask;
+ // If there wasn't a blocked reader, then store the item. If no one's waiting
+ // to be notified about a 0-to-1 transition, we're done.
+ parent._items.EnqueueTail(item);
+ waitingReadersTail = parent._waitingReadersTail;
+ if (waitingReadersTail == null)
+ {
+ return default;
+ }
+ parent._waitingReadersTail = null;
}
- parent._waitingReaders = null;
}
else if (count < parent._bufferedCapacity)
{
@@ -340,21 +505,35 @@ namespace System.Threading.Channels
// since there's room, we can simply store the item and exit without having to
// worry about blocked/waiting readers.
parent._items.EnqueueTail(item);
- return ChannelUtilities.s_trueTask;
+ return default;
}
else if (parent._mode == BoundedChannelFullMode.Wait)
{
- // The channel is full and we're in a wait mode.
- // Queue the writer.
- var writer = WriterInteractor<T>.Create(runContinuationsAsynchronously: true, item, cancellationToken);
+ // The channel is full and we're in a wait mode. We need to queue a writer.
+
+ // If we're able to use the singleton writer, do so.
+ if (!cancellationToken.CanBeCanceled)
+ {
+ VoidAsyncOperationWithData<T> singleton = _writerSingleton;
+ if (singleton.TryOwnAndReset())
+ {
+ singleton.Item = item;
+ parent._blockedWriters.EnqueueTail(singleton);
+ return singleton.ValueTask;
+ }
+ }
+
+ // Otherwise, queue a new writer.
+ var writer = new VoidAsyncOperationWithData<T>(runContinuationsAsynchronously: true, cancellationToken);
+ writer.Item = item;
parent._blockedWriters.EnqueueTail(writer);
- return writer.Task;
+ return writer.ValueTask;
}
else if (parent._mode == BoundedChannelFullMode.DropWrite)
{
// The channel is full and we're in ignore mode.
// Ignore the item but say we accepted it.
- return ChannelUtilities.s_trueTask;
+ return default;
}
else
{
@@ -364,17 +543,37 @@ namespace System.Threading.Channels
parent._items.DequeueTail() :
parent._items.DequeueHead();
parent._items.EnqueueTail(item);
- return ChannelUtilities.s_trueTask;
+ return default;
}
}
- // We stored an item bringing the count up from 0 to 1. Alert
- // any waiting readers that there may be something for them to consume.
- // Since we're no longer holding the lock, it's possible we'll end up
- // waking readers that have since come in.
- waitingReaders.Success(item: true);
- return ChannelUtilities.s_trueTask;
+ // We either wrote the item already, or we're transfering it to the blocked reader we grabbed.
+ if (blockedReader != null)
+ {
+ // Transfer the written item to the blocked reader.
+ bool success = blockedReader.TrySetResult(item);
+ Debug.Assert(success, "We should always be able to complete the reader.");
+ }
+ else
+ {
+ // We stored an item bringing the count up from 0 to 1. Alert
+ // any waiting readers that there may be something for them to consume.
+ // Since we're no longer holding the lock, it's possible we'll end up
+ // waking readers that have since come in.
+ ChannelUtilities.WakeUpWaiters(ref waitingReadersTail, result: true);
+ }
+
+ return default;
}
+
+ /// <summary>Gets the number of items in the channel. This should only be used by the debugger.</summary>
+ private int ItemsCountForDebugger => _parent._items.Count;
+
+ /// <summary>Gets the capacity of the channel. This should only be used by the debugger.</summary>
+ private int CapacityForDebugger => _parent._bufferedCapacity;
+
+ /// <summary>Gets an enumerator the debugger can use to show the contents of the channel.</summary>
+ IEnumerator<T> IDebugEnumerable<T>.GetEnumerator() => _parent._items.GetEnumerator();
}
[Conditional("DEBUG")]
@@ -385,16 +584,23 @@ namespace System.Threading.Channels
if (!_items.IsEmpty)
{
- Debug.Assert(_waitingReaders == null, "There are items available, so there shouldn't be any waiting readers.");
+ Debug.Assert(_blockedReaders.IsEmpty, "There are items available, so there shouldn't be any blocked readers.");
+ Debug.Assert(_waitingReadersTail == null, "There are items available, so there shouldn't be any waiting readers.");
}
if (_items.Count < _bufferedCapacity)
{
Debug.Assert(_blockedWriters.IsEmpty, "There's space available, so there shouldn't be any blocked writers.");
- Debug.Assert(_waitingWriters == null, "There's space available, so there shouldn't be any waiting writers.");
+ Debug.Assert(_waitingWritersTail == null, "There's space available, so there shouldn't be any waiting writers.");
+ }
+ if (!_blockedReaders.IsEmpty)
+ {
+ Debug.Assert(_items.IsEmpty, "There shouldn't be queued items if there's a blocked reader.");
+ Debug.Assert(_blockedWriters.IsEmpty, "There shouldn't be any blocked writer if there's a blocked reader.");
}
if (!_blockedWriters.IsEmpty)
{
Debug.Assert(_items.Count == _bufferedCapacity, "We should have a full buffer if there's a blocked writer.");
+ Debug.Assert(_blockedReaders.IsEmpty, "There shouldn't be any blocked readers if there's a blocked writer.");
}
if (_completion.Task.IsCompleted)
{
@@ -405,6 +611,9 @@ namespace System.Threading.Channels
/// <summary>Gets the number of items in the channel. This should only be used by the debugger.</summary>
private int ItemsCountForDebugger => _items.Count;
+ /// <summary>Report if the channel is closed or not. This should only be used by the debugger.</summary>
+ private bool ChannelIsClosedForDebugger => _doneWriting != null;
+
/// <summary>Gets an enumerator the debugger can use to show the contents of the channel.</summary>
IEnumerator<T> IDebugEnumerable<T>.GetEnumerator() => _items.GetEnumerator();
}
diff --git a/src/System.Threading.Channels/src/System/Threading/Channels/Channel.cs b/src/System.Threading.Channels/src/System/Threading/Channels/Channel.cs
index ed1b3f34ef..5a4d6693f8 100644
--- a/src/System.Threading.Channels/src/System/Threading/Channels/Channel.cs
+++ b/src/System.Threading.Channels/src/System/Threading/Channels/Channel.cs
@@ -52,25 +52,5 @@ namespace System.Threading.Channels
return new BoundedChannel<T>(options.Capacity, options.FullMode, !options.AllowSynchronousContinuations);
}
-
- /// <summary>Creates a channel that doesn't buffer any items.</summary>
- /// <typeparam name="T">Specifies the type of data in the channel.</typeparam>
- /// <returns>The created channel.</returns>
- public static Channel<T> CreateUnbuffered<T>() =>
- new UnbufferedChannel<T>();
-
- /// <summary>Creates a channel that doesn't buffer any items.</summary>
- /// <typeparam name="T">Specifies the type of data in the channel.</typeparam>
- /// <param name="options">Options that guide the behavior of the channel.</param>
- /// <returns>The created channel.</returns>
- public static Channel<T> CreateUnbuffered<T>(UnbufferedChannelOptions options)
- {
- if (options == null)
- {
- throw new ArgumentNullException(nameof(options));
- }
-
- return new UnbufferedChannel<T>();
- }
}
}
diff --git a/src/System.Threading.Channels/src/System/Threading/Channels/ChannelOptions.cs b/src/System.Threading.Channels/src/System/Threading/Channels/ChannelOptions.cs
index 9172889de8..a949c601b2 100644
--- a/src/System.Threading.Channels/src/System/Threading/Channels/ChannelOptions.cs
+++ b/src/System.Threading.Channels/src/System/Threading/Channels/ChannelOptions.cs
@@ -99,9 +99,4 @@ namespace System.Threading.Channels
public sealed class UnboundedChannelOptions : ChannelOptions
{
}
-
- /// <summary>Provides options that control the behavior of <see cref="UnbufferedChannel{T}"/> instances.</summary>
- public sealed class UnbufferedChannelOptions : ChannelOptions
- {
- }
}
diff --git a/src/System.Threading.Channels/src/System/Threading/Channels/ChannelReader.cs b/src/System.Threading.Channels/src/System/Threading/Channels/ChannelReader.cs
index 8b2469ed1d..2a838e8231 100644
--- a/src/System.Threading.Channels/src/System/Threading/Channels/ChannelReader.cs
+++ b/src/System.Threading.Channels/src/System/Threading/Channels/ChannelReader.cs
@@ -29,10 +29,10 @@ namespace System.Threading.Channels
/// A <see cref="Task{Boolean}"/> that will complete with a <c>true</c> result when data is available to read
/// or with a <c>false</c> result when no further data will ever be available to be read.
/// </returns>
- public abstract Task<bool> WaitToReadAsync(CancellationToken cancellationToken = default);
+ public abstract ValueTask<bool> WaitToReadAsync(CancellationToken cancellationToken = default);
- /// <summary>Asynchronously reads an item from the channel.</summary>
- /// <param name="cancellationToken">A <see cref="CancellationToken"/> used to cancel the read operation.</param>
+ /// <summary>Asynchronously reads an item from the channel.</summary>
+ /// <param name="cancellationToken">A <see cref="CancellationToken"/> used to cancel the read operation.</param>
/// <returns>A <see cref="ValueTask{TResult}"/> that represents the asynchronous read operation.</returns>
public virtual ValueTask<T> ReadAsync(CancellationToken cancellationToken = default)
{
@@ -57,25 +57,18 @@ namespace System.Threading.Channels
async ValueTask<T> ReadAsyncCore(CancellationToken ct)
{
- try
+ while (true)
{
- while (true)
+ if (!await WaitToReadAsync(ct).ConfigureAwait(false))
{
- if (!await WaitToReadAsync(ct))
- {
- throw new ChannelClosedException();
- }
+ throw new ChannelClosedException();
+ }
- if (TryRead(out T item))
- {
- return item;
- }
+ if (TryRead(out T item))
+ {
+ return item;
}
}
- catch (Exception exc) when (!(exc is ChannelClosedException || exc is OperationCanceledException))
- {
- throw new ChannelClosedException(exc);
- }
}
}
}
diff --git a/src/System.Threading.Channels/src/System/Threading/Channels/ChannelUtilities.cs b/src/System.Threading.Channels/src/System/Threading/Channels/ChannelUtilities.cs
index 17d412f04b..ab0282cb18 100644
--- a/src/System.Threading.Channels/src/System/Threading/Channels/ChannelUtilities.cs
+++ b/src/System.Threading.Channels/src/System/Threading/Channels/ChannelUtilities.cs
@@ -23,7 +23,7 @@ namespace System.Threading.Channels
/// <summary>Completes the specified TaskCompletionSource.</summary>
/// <param name="tcs">The source to complete.</param>
/// <param name="error">
- /// The optional exception with which to complete.
+ /// The optional exception with which to complete.
/// If this is null or the DoneWritingSentinel, the source will be completed successfully.
/// If this is an OperationCanceledException, it'll be completed with the exception's token.
/// Otherwise, it'll be completed as faulted with the exception.
@@ -44,74 +44,71 @@ namespace System.Threading.Channels
}
}
- /// <summary>Wake up all of the waiters and null out the field.</summary>
- /// <param name="waiters">The waiters.</param>
- /// <param name="result">The value with which to complete each waiter.</param>
- internal static void WakeUpWaiters(ref ReaderInteractor<bool> waiters, bool result)
+ /// <summary>Gets a value task representing an error.</summary>
+ /// <typeparam name="T">Specifies the type of the value that would have been returned.</typeparam>
+ /// <param name="error">The error. This may be <see cref="s_doneWritingSentinel"/>.</param>
+ /// <returns>The failed task.</returns>
+ internal static ValueTask<T> GetInvalidCompletionValueTask<T>(Exception error)
{
- ReaderInteractor<bool> w = waiters;
- if (w != null)
- {
- w.Success(result);
- waiters = null;
- }
+ Debug.Assert(error != null);
+
+ Task<T> t =
+ error == s_doneWritingSentinel ? Task.FromException<T>(CreateInvalidCompletionException()) :
+ error is OperationCanceledException oce ? Task.FromCanceled<T>(oce.CancellationToken.IsCancellationRequested ? oce.CancellationToken : new CancellationToken(true)) :
+ Task.FromException<T>(CreateInvalidCompletionException(error));
+
+ return new ValueTask<T>(t);
}
- /// <summary>Wake up all of the waiters and null out the field.</summary>
- /// <param name="waiters">The waiters.</param>
- /// <param name="result">The success value with which to complete each waiter if <paramref name="error">error</paramref> is null.</param>
- /// <param name="error">The failure with which to cmplete each waiter, if non-null.</param>
- internal static void WakeUpWaiters(ref ReaderInteractor<bool> waiters, bool result, Exception error = null)
+ internal static ValueTask<bool> QueueWaiter(ref AsyncOperation<bool> tail, AsyncOperation<bool> waiter)
{
- ReaderInteractor<bool> w = waiters;
- if (w != null)
+ AsyncOperation<bool> c = tail;
+ if (c == null)
{
- if (error != null)
- {
- w.Fail(error);
- }
- else
- {
- w.Success(result);
- }
- waiters = null;
+ waiter.Next = waiter;
}
+ else
+ {
+ waiter.Next = c.Next;
+ c.Next = waiter;
+ }
+ tail = waiter;
+ return waiter.ValueTaskOfT;
}
- /// <summary>Removes all interactors from the queue, failing each.</summary>
- /// <param name="interactors">The queue of interactors to complete.</param>
- /// <param name="error">The error with which to complete each interactor.</param>
- internal static void FailInteractors<T, TInner>(Dequeue<T> interactors, Exception error) where T : Interactor<TInner>
+ internal static void WakeUpWaiters(ref AsyncOperation<bool> listTail, bool result, Exception error = null)
{
- Debug.Assert(error != null);
- while (!interactors.IsEmpty)
+ AsyncOperation<bool> tail = listTail;
+ if (tail != null)
{
- interactors.DequeueHead().Fail(error);
+ listTail = null;
+
+ AsyncOperation<bool> head = tail.Next;
+ AsyncOperation<bool> c = head;
+ do
+ {
+ AsyncOperation<bool> next = c.Next;
+ c.Next = null;
+
+ bool completed = error != null ? c.TrySetException(error) : c.TrySetResult(result);
+ Debug.Assert(completed || c.CancellationToken.CanBeCanceled);
+
+ c = next;
+ }
+ while (c != head);
}
}
- /// <summary>Gets or creates a "waiter" (e.g. WaitForRead/WriteAsync) interactor.</summary>
- /// <param name="waiter">The field storing the waiter interactor.</param>
- /// <param name="runContinuationsAsynchronously">true to force continuations to run asynchronously; otherwise, false.</param>
- /// <param name="cancellationToken">The token to use to cancel the wait.</param>
- internal static Task<bool> GetOrCreateWaiter(ref ReaderInteractor<bool> waiter, bool runContinuationsAsynchronously, CancellationToken cancellationToken)
+ /// <summary>Removes all operations from the queue, failing each.</summary>
+ /// <param name="operations">The queue of operations to complete.</param>
+ /// <param name="error">The error with which to complete each operations.</param>
+ internal static void FailOperations<T, TInner>(Dequeue<T> operations, Exception error) where T : AsyncOperation<TInner>
{
- // Get the existing waiters interactor.
- ReaderInteractor<bool> w = waiter;
-
- // If there isn't one, create one. This explicitly does not include the cancellation token,
- // as we reuse it for any number of waiters that overlap.
- if (w == null)
+ Debug.Assert(error != null);
+ while (!operations.IsEmpty)
{
- waiter = w = ReaderInteractor<bool>.Create(runContinuationsAsynchronously);
+ operations.DequeueHead().TrySetException(error);
}
-
- // If the cancellation token can't be canceled, then just return the waiter task.
- // If it can, we need to return a task that will complete when the waiter task does but that can also be canceled.
- // Easiest way to do that is with a cancelable continuation.
- return cancellationToken.CanBeCanceled ?
- w.Task.ContinueWith(t => t.Result, cancellationToken, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default) :
- w.Task;
}
/// <summary>Creates and returns an exception object to indicate that a channel has been closed.</summary>
diff --git a/src/System.Threading.Channels/src/System/Threading/Channels/ChannelWriter.cs b/src/System.Threading.Channels/src/System/Threading/Channels/ChannelWriter.cs
index d09fa1b0d0..2399c4187a 100644
--- a/src/System.Threading.Channels/src/System/Threading/Channels/ChannelWriter.cs
+++ b/src/System.Threading.Channels/src/System/Threading/Channels/ChannelWriter.cs
@@ -31,38 +31,38 @@ namespace System.Threading.Channels
/// A <see cref="Task{Boolean}"/> that will complete with a <c>true</c> result when space is available to write an item
/// or with a <c>false</c> result when no further writing will be permitted.
/// </returns>
- public abstract Task<bool> WaitToWriteAsync(CancellationToken cancellationToken = default);
+ public abstract ValueTask<bool> WaitToWriteAsync(CancellationToken cancellationToken = default);
/// <summary>Asynchronously writes an item to the channel.</summary>
/// <param name="item">The value to write to the channel.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> used to cancel the write operation.</param>
/// <returns>A <see cref="Task"/> that represents the asynchronous write operation.</returns>
- public virtual Task WriteAsync(T item, CancellationToken cancellationToken = default)
+ public virtual ValueTask WriteAsync(T item, CancellationToken cancellationToken = default)
{
try
{
return
- cancellationToken.IsCancellationRequested ? Task.FromCanceled<T>(cancellationToken) :
- TryWrite(item) ? Task.CompletedTask :
- WriteAsyncCore(item, cancellationToken);
+ cancellationToken.IsCancellationRequested ? new ValueTask(Task.FromCanceled<T>(cancellationToken)) :
+ TryWrite(item) ? default :
+ new ValueTask(WriteAsyncCore(item, cancellationToken));
}
catch (Exception e)
{
- return Task.FromException(e);
+ return new ValueTask(Task.FromException(e));
}
+ }
- async Task WriteAsyncCore(T innerItem, CancellationToken ct)
+ private async Task WriteAsyncCore(T innerItem, CancellationToken ct)
+ {
+ while (await WaitToWriteAsync(ct).ConfigureAwait(false))
{
- while (await WaitToWriteAsync(ct).ConfigureAwait(false))
+ if (TryWrite(innerItem))
{
- if (TryWrite(innerItem))
- {
- return;
- }
+ return;
}
-
- throw ChannelUtilities.CreateInvalidCompletionException();
}
+
+ throw ChannelUtilities.CreateInvalidCompletionException();
}
/// <summary>Mark the channel as being complete, meaning no more items will be written to it.</summary>
diff --git a/src/System.Threading.Channels/src/System/Threading/Channels/Interactor.cs b/src/System.Threading.Channels/src/System/Threading/Channels/Interactor.cs
deleted file mode 100644
index f4e0c74767..0000000000
--- a/src/System.Threading.Channels/src/System/Threading/Channels/Interactor.cs
+++ /dev/null
@@ -1,149 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Threading.Tasks;
-
-namespace System.Threading.Channels
-{
- /// <summary>A base class for a blocked or waiting reader or writer.</summary>
- /// <typeparam name="T">Specifies the type of data passed to the reader or writer.</typeparam>
- internal abstract class Interactor<T> : TaskCompletionSource<T>
- {
- /// <summary>Initializes the interactor.</summary>
- /// <param name="runContinuationsAsynchronously">true if continuations should be forced to run asynchronously; otherwise, false.</param>
- protected Interactor(bool runContinuationsAsynchronously) :
- base(runContinuationsAsynchronously ? TaskCreationOptions.RunContinuationsAsynchronously : TaskCreationOptions.None) { }
-
- /// <summary>Completes the interactor with a success state and the specified result.</summary>
- /// <param name="item">The result value.</param>
- /// <returns>true if the interactor could be successfully transitioned to a completed state; false if it was already completed.</returns>
- internal bool Success(T item)
- {
- UnregisterCancellation();
- return TrySetResult(item);
- }
-
- /// <summary>Completes the interactor with a failed state and the specified error.</summary>
- /// <param name="exception">The error.</param>
- /// <returns>true if the interactor could be successfully transitioned to a completed state; false if it was already completed.</returns>
- internal bool Fail(Exception exception)
- {
- UnregisterCancellation();
- return TrySetException(exception);
- }
-
- /// <summary>Unregister cancellation in case cancellation was registered.</summary>
- internal virtual void UnregisterCancellation() { }
- }
-
- /// <summary>A blocked or waiting reader.</summary>
- /// <typeparam name="T">Specifies the type of data being read.</typeparam>
- internal class ReaderInteractor<T> : Interactor<T>
- {
- /// <summary>Initializes the reader.</summary>
- /// <param name="runContinuationsAsynchronously">true if continuations should be forced to run asynchronously; otherwise, false.</param>
- protected ReaderInteractor(bool runContinuationsAsynchronously) : base(runContinuationsAsynchronously) { }
-
- /// <summary>Creates a reader.</summary>
- /// <param name="runContinuationsAsynchronously">true if continuations should be forced to run asynchronously; otherwise, false.</param>
- /// <returns>The reader.</returns>
- public static ReaderInteractor<T> Create(bool runContinuationsAsynchronously) =>
- new ReaderInteractor<T>(runContinuationsAsynchronously);
-
- /// <summary>Creates a reader.</summary>
- /// <param name="runContinuationsAsynchronously">true if continuations should be forced to run asynchronously; otherwise, false.</param>
- /// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the read operation.</param>
- /// <returns>The reader.</returns>
- public static ReaderInteractor<T> Create(bool runContinuationsAsynchronously, CancellationToken cancellationToken) =>
- cancellationToken.CanBeCanceled ?
- new CancelableReaderInteractor<T>(runContinuationsAsynchronously, cancellationToken) :
- new ReaderInteractor<T>(runContinuationsAsynchronously);
- }
-
- /// <summary>A blocked or waiting writer.</summary>
- /// <typeparam name="T">Specifies the type of data being written.</typeparam>
- internal class WriterInteractor<T> : Interactor<VoidResult>
- {
- /// <summary>Initializes the writer.</summary>
- /// <param name="runContinuationsAsynchronously">true if continuations should be forced to run asynchronously; otherwise, false.</param>
- protected WriterInteractor(bool runContinuationsAsynchronously) : base(runContinuationsAsynchronously) { }
-
- /// <summary>The item being written.</summary>
- internal T Item { get; private set; }
-
- /// <summary>Creates a writer.</summary>
- /// <param name="runContinuationsAsynchronously">true if continuations should be forced to run asynchronously; otherwise, false.</param>
- /// <param name="item">The item being written.</param>
- /// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the read operation.</param>
- /// <returns>The reader.</returns>
- public static WriterInteractor<T> Create(bool runContinuationsAsynchronously, T item, CancellationToken cancellationToken)
- {
- WriterInteractor<T> w = cancellationToken.CanBeCanceled ?
- new CancelableWriter<T>(runContinuationsAsynchronously, cancellationToken) :
- new WriterInteractor<T>(runContinuationsAsynchronously);
- w.Item = item;
- return w;
- }
- }
-
- /// <summary>A blocked or waiting reader where the read can be canceled.</summary>
- /// <typeparam name="T">Specifies the type of data being read.</typeparam>
- internal sealed class CancelableReaderInteractor<T> : ReaderInteractor<T>
- {
- /// <summary>The token used for cancellation.</summary>
- private readonly CancellationToken _token;
- /// <summary>Registration in <see cref="_token"/> that should be disposed of when the operation has completed.</summary>
- private CancellationTokenRegistration _registration;
-
- /// <summary>Initializes the cancelable reader.</summary>
- /// <param name="runContinuationsAsynchronously">true if continuations should be forced to run asynchronously; otherwise, false.</param>
- /// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the read operation.</param>
- internal CancelableReaderInteractor(bool runContinuationsAsynchronously, CancellationToken cancellationToken) : base(runContinuationsAsynchronously)
- {
- _token = cancellationToken;
- _registration = cancellationToken.Register(s =>
- {
- var thisRef = (CancelableReaderInteractor<T>)s;
- thisRef.TrySetCanceled(thisRef._token);
- }, this);
- }
-
- /// <summary>Unregister cancellation in case cancellation was registered.</summary>
- internal override void UnregisterCancellation()
- {
- _registration.Dispose();
- _registration = default;
- }
- }
-
- /// <summary>A blocked or waiting reader where the read can be canceled.</summary>
- /// <typeparam name="T">Specifies the type of data being read.</typeparam>
- internal sealed class CancelableWriter<T> : WriterInteractor<T>
- {
- /// <summary>The token used for cancellation.</summary>
- private CancellationToken _token;
- /// <summary>Registration in <see cref="_token"/> that should be disposed of when the operation has completed.</summary>
- private CancellationTokenRegistration _registration;
-
- /// <summary>Initializes the cancelable writer.</summary>
- /// <param name="runContinuationsAsynchronously">true if continuations should be forced to run asynchronously; otherwise, false.</param>
- /// <param name="cancellationToken">A <see cref="CancellationToken"/> that can be used to cancel the read operation.</param>
- internal CancelableWriter(bool runContinuationsAsynchronously, CancellationToken cancellationToken) : base(runContinuationsAsynchronously)
- {
- _token = cancellationToken;
- _registration = cancellationToken.Register(s =>
- {
- var thisRef = (CancelableWriter<T>)s;
- thisRef.TrySetCanceled(thisRef._token);
- }, this);
- }
-
- /// <summary>Unregister cancellation in case cancellation was registered.</summary>
- internal override void UnregisterCancellation()
- {
- _registration.Dispose();
- _registration = default;
- }
- }
-}
diff --git a/src/System.Threading.Channels/src/System/Threading/Channels/SingleConsumerUnboundedChannel.cs b/src/System.Threading.Channels/src/System/Threading/Channels/SingleConsumerUnboundedChannel.cs
index b3435b88ae..75cbd1cf79 100644
--- a/src/System.Threading.Channels/src/System/Threading/Channels/SingleConsumerUnboundedChannel.cs
+++ b/src/System.Threading.Channels/src/System/Threading/Channels/SingleConsumerUnboundedChannel.cs
@@ -13,7 +13,7 @@ namespace System.Threading.Channels
/// Provides a buffered channel of unbounded capacity for use by any number
/// of writers but at most a single reader at a time.
/// </summary>
- [DebuggerDisplay("Items={ItemsCountForDebugger}")]
+ [DebuggerDisplay("Items={ItemsCountForDebugger}, Closed={ChannelIsClosedForDebugger}")]
[DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))]
internal sealed class SingleConsumerUnboundedChannel<T> : Channel<T>, IDebugEnumerable<T>
{
@@ -31,8 +31,11 @@ namespace System.Threading.Channels
/// <summary>non-null if the channel has been marked as complete for writing.</summary>
private volatile Exception _doneWriting;
+ /// <summary>An <see cref="AsyncOperation{T}"/> if there's a blocked reader.</summary>
+ private AsyncOperation<T> _blockedReader;
+
/// <summary>A waiting reader (e.g. WaitForReadAsync) if there is one.</summary>
- private ReaderInteractor<bool> _waitingReader;
+ private AsyncOperation<bool> _waitingReader;
/// <summary>Initialize the channel.</summary>
/// <param name="runContinuationsAsynchronously">Whether to force continuations to be executed asynchronously.</param>
@@ -45,13 +48,76 @@ namespace System.Threading.Channels
Writer = new UnboundedChannelWriter(this);
}
- private sealed class UnboundedChannelReader : ChannelReader<T>
+ [DebuggerDisplay("Items={ItemsCountForDebugger}")]
+ [DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))]
+ private sealed class UnboundedChannelReader : ChannelReader<T>, IDebugEnumerable<T>
{
internal readonly SingleConsumerUnboundedChannel<T> _parent;
- internal UnboundedChannelReader(SingleConsumerUnboundedChannel<T> parent) => _parent = parent;
+ private readonly AsyncOperation<T> _readerSingleton;
+ private readonly AsyncOperation<bool> _waiterSingleton;
+
+ internal UnboundedChannelReader(SingleConsumerUnboundedChannel<T> parent)
+ {
+ _parent = parent;
+ _readerSingleton = new AsyncOperation<T>(parent._runContinuationsAsynchronously, pooled: true);
+ _waiterSingleton = new AsyncOperation<bool>(parent._runContinuationsAsynchronously, pooled: true);
+ }
public override Task Completion => _parent._completion.Task;
+ public override ValueTask<T> ReadAsync(CancellationToken cancellationToken)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return new ValueTask<T>(Task.FromCanceled<T>(cancellationToken));
+ }
+
+ if (TryRead(out T item))
+ {
+ return new ValueTask<T>(item);
+ }
+
+ SingleConsumerUnboundedChannel<T> parent = _parent;
+
+ AsyncOperation<T> oldBlockedReader, newBlockedReader;
+ lock (parent.SyncObj)
+ {
+ // Now that we hold the lock, try reading again.
+ if (TryRead(out item))
+ {
+ return new ValueTask<T>(item);
+ }
+
+ // If no more items will be written, fail the read.
+ if (parent._doneWriting != null)
+ {
+ return ChannelUtilities.GetInvalidCompletionValueTask<T>(parent._doneWriting);
+ }
+
+ // Try to use the singleton reader. If it's currently being used, then the channel
+ // is being used erroneously, and we cancel the outstanding operation.
+ oldBlockedReader = parent._blockedReader;
+ if (!cancellationToken.CanBeCanceled && _readerSingleton.TryOwnAndReset())
+ {
+ newBlockedReader = _readerSingleton;
+ if (newBlockedReader == oldBlockedReader)
+ {
+ // The previous operation completed, so null out the "old" reader
+ // so we don't end up canceling the new operation.
+ oldBlockedReader = null;
+ }
+ }
+ else
+ {
+ newBlockedReader = new AsyncOperation<T>(_parent._runContinuationsAsynchronously, cancellationToken);
+ }
+ parent._blockedReader = newBlockedReader;
+ }
+
+ oldBlockedReader?.TrySetCanceled();
+ return newBlockedReader.ValueTaskOfT;
+ }
+
public override bool TryRead(out T item)
{
SingleConsumerUnboundedChannel<T> parent = _parent;
@@ -66,55 +132,79 @@ namespace System.Threading.Channels
return false;
}
- public override Task<bool> WaitToReadAsync(CancellationToken cancellationToken)
+ public override ValueTask<bool> WaitToReadAsync(CancellationToken cancellationToken)
{
// Outside of the lock, check if there are any items waiting to be read. If there are, we're done.
- return
- cancellationToken.IsCancellationRequested ? Task.FromCanceled<bool>(cancellationToken) :
- !_parent._items.IsEmpty ? ChannelUtilities.s_trueTask :
- WaitToReadAsyncCore(cancellationToken);
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return new ValueTask<bool>(Task.FromCanceled<bool>(cancellationToken));
+ }
- Task<bool> WaitToReadAsyncCore(CancellationToken ct)
+ if (!_parent._items.IsEmpty)
{
- SingleConsumerUnboundedChannel<T> parent = _parent;
- ReaderInteractor<bool> oldWaiter = null, newWaiter;
- lock (parent.SyncObj)
+ return new ValueTask<bool>(true);
+ }
+
+ SingleConsumerUnboundedChannel<T> parent = _parent;
+ AsyncOperation<bool> oldWaitingReader = null, newWaitingReader;
+ lock (parent.SyncObj)
+ {
+ // Again while holding the lock, check to see if there are any items available.
+ if (!parent._items.IsEmpty)
{
- // Again while holding the lock, check to see if there are any items available.
- if (!parent._items.IsEmpty)
- {
- return ChannelUtilities.s_trueTask;
- }
+ return new ValueTask<bool>(true);
+ }
- // There aren't any items; if we're done writing, there never will be more items.
- if (parent._doneWriting != null)
+ // There aren't any items; if we're done writing, there never will be more items.
+ if (parent._doneWriting != null)
+ {
+ return parent._doneWriting != ChannelUtilities.s_doneWritingSentinel ?
+ new ValueTask<bool>(Task.FromException<bool>(parent._doneWriting)) :
+ default;
+ }
+
+ // Try to use the singleton waiter. If it's currently being used, then the channel
+ // is being used erroneously, and we cancel the outstanding operation.
+ oldWaitingReader = parent._waitingReader;
+ if (!cancellationToken.CanBeCanceled && _waiterSingleton.TryOwnAndReset())
+ {
+ newWaitingReader = _waiterSingleton;
+ if (newWaitingReader == oldWaitingReader)
{
- return parent._doneWriting != ChannelUtilities.s_doneWritingSentinel ?
- Task.FromException<bool>(parent._doneWriting) :
- ChannelUtilities.s_falseTask;
+ // The previous operation completed, so null out the "old" waiter
+ // so we don't end up canceling the new operation.
+ oldWaitingReader = null;
}
-
- // Create the new waiter. We're a bit more tolerant of a stray waiting reader
- // than we are of a blocked reader, as with usage patterns it's easier to leave one
- // behind, so we just cancel any that may have been waiting around.
- oldWaiter = parent._waitingReader;
- parent._waitingReader = newWaiter = ReaderInteractor<bool>.Create(parent._runContinuationsAsynchronously, ct);
}
-
- oldWaiter?.TrySetCanceled();
- return newWaiter.Task;
+ else
+ {
+ newWaitingReader = new AsyncOperation<bool>(_parent._runContinuationsAsynchronously, cancellationToken);
+ }
+ parent._waitingReader = newWaitingReader;
}
+
+ oldWaitingReader?.TrySetCanceled();
+ return newWaitingReader.ValueTaskOfT;
}
+
+ /// <summary>Gets the number of items in the channel. This should only be used by the debugger.</summary>
+ private int ItemsCountForDebugger => _parent._items.Count;
+
+ /// <summary>Gets an enumerator the debugger can use to show the contents of the channel.</summary>
+ IEnumerator<T> IDebugEnumerable<T>.GetEnumerator() => _parent._items.GetEnumerator();
}
- private sealed class UnboundedChannelWriter : ChannelWriter<T>
+ [DebuggerDisplay("Items={ItemsCountForDebugger}")]
+ [DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))]
+ private sealed class UnboundedChannelWriter : ChannelWriter<T>, IDebugEnumerable<T>
{
internal readonly SingleConsumerUnboundedChannel<T> _parent;
internal UnboundedChannelWriter(SingleConsumerUnboundedChannel<T> parent) => _parent = parent;
public override bool TryComplete(Exception error)
{
- ReaderInteractor<bool> waitingReader = null;
+ AsyncOperation<T> blockedReader = null;
+ AsyncOperation<bool> waitingReader = null;
bool completeTask = false;
SingleConsumerUnboundedChannel<T> parent = _parent;
@@ -136,6 +226,12 @@ namespace System.Threading.Channels
{
completeTask = true;
+ if (parent._blockedReader != null)
+ {
+ blockedReader = parent._blockedReader;
+ parent._blockedReader = null;
+ }
+
if (parent._waitingReader != null)
{
waitingReader = parent._waitingReader;
@@ -150,16 +246,26 @@ namespace System.Threading.Channels
ChannelUtilities.Complete(parent._completion, error);
}
- // Complete a waiting reader if necessary.
+ Debug.Assert(blockedReader == null || waitingReader == null, "There should only ever be at most one reader.");
+
+ // Complete a blocked reader if necessary
+ if (blockedReader != null)
+ {
+ error = ChannelUtilities.CreateInvalidCompletionException(error);
+ blockedReader.TrySetException(error);
+ }
+
+ // Complete a waiting reader if necessary. (We really shouldn't have both a blockedReader
+ // and a waitingReader, but it's more expensive to prevent it than to just tolerate it.)
if (waitingReader != null)
{
if (error != null)
{
- waitingReader.Fail(error);
+ waitingReader.TrySetException(error);
}
else
{
- waitingReader.Success(item: false);
+ waitingReader.TrySetResult(item: false);
}
}
@@ -172,7 +278,8 @@ namespace System.Threading.Channels
SingleConsumerUnboundedChannel<T> parent = _parent;
while (true) // in case a reader was canceled and we need to try again
{
- ReaderInteractor<bool> waitingReader = null;
+ AsyncOperation<T> blockedReader = null;
+ AsyncOperation<bool> waitingReader = null;
lock (parent.SyncObj)
{
@@ -182,42 +289,71 @@ namespace System.Threading.Channels
return false;
}
- // Queue the item being written; then if there's a waiting
- // reader, store it for notification outside of the lock.
- parent._items.Enqueue(item);
-
- waitingReader = parent._waitingReader;
- if (waitingReader == null)
+ // If there's a blocked reader, store it into a local for completion outside of the lock.
+ // If there isn't a blocked reader, queue the item being written; then if there's a waiting
+ blockedReader = parent._blockedReader;
+ if (blockedReader != null)
{
- return true;
+ parent._blockedReader = null;
+ }
+ else
+ {
+ parent._items.Enqueue(item);
+
+ waitingReader = parent._waitingReader;
+ if (waitingReader == null)
+ {
+ return true;
+ }
+ parent._waitingReader = null;
}
- parent._waitingReader = null;
}
- // If we get here, we grabbed a waiting reader.
- // Notify it that an item was written and exit.
- Debug.Assert(waitingReader != null, "Expected a waiting reader");
- waitingReader.Success(item: true);
- return true;
+ // If we get here, we grabbed a blocked or a waiting reader.
+ Debug.Assert((blockedReader != null) ^ (waitingReader != null), "Expected either a blocked or waiting reader, but not both");
+
+ // If we have a waiting reader, notify it that an item was written and exit.
+ if (waitingReader != null)
+ {
+ // If we get here, we grabbed a waiting reader.
+ waitingReader.TrySetResult(item: true);
+ return true;
+ }
+
+ // Otherwise we have a blocked reader: complete it with the item being written.
+ // In the case of a ReadAsync(CancellationToken), it's possible the reader could
+ // have been completed due to cancellation by the time we get here. In that case,
+ // we'll loop around to try again so as not to lose the item being written.
+ Debug.Assert(blockedReader != null);
+ if (blockedReader.TrySetResult(item))
+ {
+ return true;
+ }
}
}
- public override Task<bool> WaitToWriteAsync(CancellationToken cancellationToken)
+ public override ValueTask<bool> WaitToWriteAsync(CancellationToken cancellationToken)
{
Exception doneWriting = _parent._doneWriting;
return
- cancellationToken.IsCancellationRequested ? Task.FromCanceled<bool>(cancellationToken) :
- doneWriting == null ? ChannelUtilities.s_trueTask :
- doneWriting != ChannelUtilities.s_doneWritingSentinel ? Task.FromException<bool>(doneWriting) :
- ChannelUtilities.s_falseTask;
+ cancellationToken.IsCancellationRequested ? new ValueTask<bool>(Task.FromCanceled<bool>(cancellationToken)) :
+ doneWriting == null ? new ValueTask<bool>(true) :
+ doneWriting != ChannelUtilities.s_doneWritingSentinel ? new ValueTask<bool>(Task.FromException<bool>(doneWriting)) :
+ default;
}
- public override Task WriteAsync(T item, CancellationToken cancellationToken) =>
+ public override ValueTask WriteAsync(T item, CancellationToken cancellationToken) =>
// Writing always succeeds (unless we've already completed writing or cancellation has been requested),
// so just TryWrite and return a completed task.
- cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) :
- TryWrite(item) ? Task.CompletedTask :
- Task.FromException(ChannelUtilities.CreateInvalidCompletionException(_parent._doneWriting));
+ cancellationToken.IsCancellationRequested ? new ValueTask(Task.FromCanceled(cancellationToken)) :
+ TryWrite(item) ? default :
+ new ValueTask(Task.FromException(ChannelUtilities.CreateInvalidCompletionException(_parent._doneWriting)));
+
+ /// <summary>Gets the number of items in the channel. This should only be used by the debugger.</summary>
+ private int ItemsCountForDebugger => _parent._items.Count;
+
+ /// <summary>Gets an enumerator the debugger can use to show the contents of the channel.</summary>
+ IEnumerator<T> IDebugEnumerable<T>.GetEnumerator() => _parent._items.GetEnumerator();
}
private object SyncObj => _items;
@@ -225,6 +361,9 @@ namespace System.Threading.Channels
/// <summary>Gets the number of items in the channel. This should only be used by the debugger.</summary>
private int ItemsCountForDebugger => _items.Count;
+ /// <summary>Report if the channel is closed or not. This should only be used by the debugger.</summary>
+ private bool ChannelIsClosedForDebugger => _doneWriting != null;
+
/// <summary>Gets an enumerator the debugger can use to show the contents of the channel.</summary>
IEnumerator<T> IDebugEnumerable<T>.GetEnumerator() => _items.GetEnumerator();
}
diff --git a/src/System.Threading.Channels/src/System/Threading/Channels/UnboundedChannel.cs b/src/System.Threading.Channels/src/System/Threading/Channels/UnboundedChannel.cs
index 33ca00c6af..5ac4a2d91b 100644
--- a/src/System.Threading.Channels/src/System/Threading/Channels/UnboundedChannel.cs
+++ b/src/System.Threading.Channels/src/System/Threading/Channels/UnboundedChannel.cs
@@ -10,7 +10,7 @@ using System.Threading.Tasks;
namespace System.Threading.Channels
{
/// <summary>Provides a buffered channel of unbounded capacity.</summary>
- [DebuggerDisplay("Items={ItemsCountForDebugger}")]
+ [DebuggerDisplay("Items={ItemsCountForDebugger}, Closed={ChannelIsClosedForDebugger}")]
[DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))]
internal sealed class UnboundedChannel<T> : Channel<T>, IDebugEnumerable<T>
{
@@ -18,11 +18,13 @@ namespace System.Threading.Channels
private readonly TaskCompletionSource<VoidResult> _completion;
/// <summary>The items in the channel.</summary>
private readonly ConcurrentQueue<T> _items = new ConcurrentQueue<T>();
+ /// <summary>Readers blocked reading from the channel.</summary>
+ private readonly Dequeue<AsyncOperation<T>> _blockedReaders = new Dequeue<AsyncOperation<T>>();
/// <summary>Whether to force continuations to be executed asynchronously from producer writes.</summary>
private readonly bool _runContinuationsAsynchronously;
/// <summary>Readers waiting for a notification that data is available.</summary>
- private ReaderInteractor<bool> _waitingReaders;
+ private AsyncOperation<bool> _waitingReadersTail;
/// <summary>Set to non-null once Complete has been called.</summary>
private Exception _doneWriting;
@@ -31,17 +33,77 @@ namespace System.Threading.Channels
{
_runContinuationsAsynchronously = runContinuationsAsynchronously;
_completion = new TaskCompletionSource<VoidResult>(runContinuationsAsynchronously ? TaskCreationOptions.RunContinuationsAsynchronously : TaskCreationOptions.None);
- base.Reader = new UnboundedChannelReader(this);
+ Reader = new UnboundedChannelReader(this);
Writer = new UnboundedChannelWriter(this);
}
- private sealed class UnboundedChannelReader : ChannelReader<T>
+ [DebuggerDisplay("Items={ItemsCountForDebugger}")]
+ [DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))]
+ private sealed class UnboundedChannelReader : ChannelReader<T>, IDebugEnumerable<T>
{
internal readonly UnboundedChannel<T> _parent;
- internal UnboundedChannelReader(UnboundedChannel<T> parent) => _parent = parent;
+ private readonly AsyncOperation<T> _readerSingleton;
+ private readonly AsyncOperation<bool> _waiterSingleton;
+
+ internal UnboundedChannelReader(UnboundedChannel<T> parent)
+ {
+ _parent = parent;
+ _readerSingleton = new AsyncOperation<T>(parent._runContinuationsAsynchronously, pooled: true);
+ _waiterSingleton = new AsyncOperation<bool>(parent._runContinuationsAsynchronously, pooled: true);
+ }
public override Task Completion => _parent._completion.Task;
+ public override ValueTask<T> ReadAsync(CancellationToken cancellationToken)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ return new ValueTask<T>(Task.FromCanceled<T>(cancellationToken));
+ }
+
+ // Dequeue an item if we can.
+ UnboundedChannel<T> parent = _parent;
+ if (parent._items.TryDequeue(out T item))
+ {
+ CompleteIfDone(parent);
+ return new ValueTask<T>(item);
+ }
+
+ lock (parent.SyncObj)
+ {
+ parent.AssertInvariants();
+
+ // Try to dequeue again, now that we hold the lock.
+ if (parent._items.TryDequeue(out item))
+ {
+ CompleteIfDone(parent);
+ return new ValueTask<T>(item);
+ }
+
+ // There are no items, so if we're done writing, fail.
+ if (parent._doneWriting != null)
+ {
+ return ChannelUtilities.GetInvalidCompletionValueTask<T>(parent._doneWriting);
+ }
+
+ // If we're able to use the singleton reader, do so.
+ if (!cancellationToken.CanBeCanceled)
+ {
+ AsyncOperation<T> singleton = _readerSingleton;
+ if (singleton.TryOwnAndReset())
+ {
+ parent._blockedReaders.EnqueueTail(singleton);
+ return singleton.ValueTaskOfT;
+ }
+ }
+
+ // Otherwise, create and queue a reader.
+ var reader = new AsyncOperation<T>(parent._runContinuationsAsynchronously, cancellationToken);
+ parent._blockedReaders.EnqueueTail(reader);
+ return reader.ValueTaskOfT;
+ }
+ }
+
public override bool TryRead(out T item)
{
UnboundedChannel<T> parent = _parent;
@@ -49,11 +111,7 @@ namespace System.Threading.Channels
// Dequeue an item if we can
if (parent._items.TryDequeue(out item))
{
- if (parent._doneWriting != null && parent._items.IsEmpty)
- {
- // If we've now emptied the items queue and we're not getting any more, complete.
- ChannelUtilities.Complete(parent._completion, parent._doneWriting);
- }
+ CompleteIfDone(parent);
return true;
}
@@ -61,43 +119,75 @@ namespace System.Threading.Channels
return false;
}
- public override Task<bool> WaitToReadAsync(CancellationToken cancellationToken)
+ private void CompleteIfDone(UnboundedChannel<T> parent)
{
- // If there are any items, readers can try to get them.
- return !_parent._items.IsEmpty ?
- ChannelUtilities.s_trueTask :
- WaitToReadAsyncCore(cancellationToken);
+ if (parent._doneWriting != null && parent._items.IsEmpty)
+ {
+ // If we've now emptied the items queue and we're not getting any more, complete.
+ ChannelUtilities.Complete(parent._completion, parent._doneWriting);
+ }
+ }
- Task<bool> WaitToReadAsyncCore(CancellationToken ct)
+ public override ValueTask<bool> WaitToReadAsync(CancellationToken cancellationToken)
+ {
+ if (cancellationToken.IsCancellationRequested)
{
- UnboundedChannel<T> parent = _parent;
+ return new ValueTask<bool>(Task.FromCanceled<bool>(cancellationToken));
+ }
- lock (parent.SyncObj)
+ if (!_parent._items.IsEmpty)
+ {
+ return new ValueTask<bool>(true);
+ }
+
+ UnboundedChannel<T> parent = _parent;
+
+ lock (parent.SyncObj)
+ {
+ parent.AssertInvariants();
+
+ // Try again to read now that we're synchronized with writers.
+ if (!parent._items.IsEmpty)
{
- parent.AssertInvariants();
+ return new ValueTask<bool>(true);
+ }
- // Try again to read now that we're synchronized with writers.
- if (!parent._items.IsEmpty)
- {
- return ChannelUtilities.s_trueTask;
- }
+ // There are no items, so if we're done writing, there's never going to be data available.
+ if (parent._doneWriting != null)
+ {
+ return parent._doneWriting != ChannelUtilities.s_doneWritingSentinel ?
+ new ValueTask<bool>(Task.FromException<bool>(parent._doneWriting)) :
+ default;
+ }
- // There are no items, so if we're done writing, there's never going to be data available.
- if (parent._doneWriting != null)
+ // If we're able to use the singleton waiter, do so.
+ if (!cancellationToken.CanBeCanceled)
+ {
+ AsyncOperation<bool> singleton = _waiterSingleton;
+ if (singleton.TryOwnAndReset())
{
- return parent._doneWriting != ChannelUtilities.s_doneWritingSentinel ?
- Task.FromException<bool>(parent._doneWriting) :
- ChannelUtilities.s_falseTask;
+ ChannelUtilities.QueueWaiter(ref parent._waitingReadersTail, singleton);
+ return singleton.ValueTaskOfT;
}
-
- // Queue the waiter
- return ChannelUtilities.GetOrCreateWaiter(ref parent._waitingReaders, parent._runContinuationsAsynchronously, ct);
}
+
+ // Otherwise, create and queue a waiter.
+ var waiter = new AsyncOperation<bool>(parent._runContinuationsAsynchronously, cancellationToken);
+ ChannelUtilities.QueueWaiter(ref parent._waitingReadersTail, waiter);
+ return waiter.ValueTaskOfT;
}
}
+
+ /// <summary>Gets the number of items in the channel. This should only be used by the debugger.</summary>
+ private int ItemsCountForDebugger => _parent._items.Count;
+
+ /// <summary>Gets an enumerator the debugger can use to show the contents of the channel.</summary>
+ IEnumerator<T> IDebugEnumerable<T>.GetEnumerator() => _parent._items.GetEnumerator();
}
- private sealed class UnboundedChannelWriter : ChannelWriter<T>
+ [DebuggerDisplay("Items={ItemsCountForDebugger}")]
+ [DebuggerTypeProxy(typeof(DebugEnumeratorDebugView<>))]
+ private sealed class UnboundedChannelWriter : ChannelWriter<T>, IDebugEnumerable<T>
{
internal readonly UnboundedChannel<T> _parent;
internal UnboundedChannelWriter(UnboundedChannel<T> parent) => _parent = parent;
@@ -132,12 +222,11 @@ namespace System.Threading.Channels
ChannelUtilities.Complete(parent._completion, error);
}
- // At this point, _waitingReaders will not be mutated:
- // it's only mutated by readers while holding the lock, and only if _doneWriting is null.
- // We also know that only one thread (this one) will ever get here, as only that thread
- // will be the one to transition from _doneWriting false to true. As such, we can
- // freely manipulate _waitingReaders without any concurrency concerns.
- ChannelUtilities.WakeUpWaiters(ref parent._waitingReaders, result: false, error: error);
+ // At this point, _blockedReaders and _waitingReaders will not be mutated:
+ // they're only mutated by readers while holding the lock, and only if _doneWriting is null.
+ // freely manipulate _blockedReaders and _waitingReaders without any concurrency concerns.
+ ChannelUtilities.FailOperations<AsyncOperation<T>, T>(parent._blockedReaders, ChannelUtilities.CreateInvalidCompletionException(error));
+ ChannelUtilities.WakeUpWaiters(ref parent._waitingReadersTail, result: false, error: error);
// Successfully transitioned to completed.
return true;
@@ -148,7 +237,8 @@ namespace System.Threading.Channels
UnboundedChannel<T> parent = _parent;
while (true)
{
- ReaderInteractor<bool> waitingReaders = null;
+ AsyncOperation<T> blockedReader = null;
+ AsyncOperation<bool> waitingReadersTail = null;
lock (parent.SyncObj)
{
// If writing has already been marked as done, fail the write.
@@ -158,42 +248,70 @@ namespace System.Threading.Channels
return false;
}
- // Add the data to the queue, and let any waiting readers know that they should try to read it.
- // We can only complete such waiters here under the lock if they run continuations asynchronously
- // (otherwise the synchronous continuations could be invoked under the lock). If we don't complete
- // them here, we need to do so outside of the lock.
- parent._items.Enqueue(item);
- waitingReaders = parent._waitingReaders;
- if (waitingReaders == null)
+ // If there aren't any blocked readers, just add the data to the queue,
+ // and let any waiting readers know that they should try to read it.
+ // We can only complete such waiters here under the lock if they run
+ // continuations asynchronously (otherwise the synchronous continuations
+ // could be invoked under the lock). If we don't complete them here, we
+ // need to do so outside of the lock.
+ if (parent._blockedReaders.IsEmpty)
{
- return true;
+ parent._items.Enqueue(item);
+ waitingReadersTail = parent._waitingReadersTail;
+ if (waitingReadersTail == null)
+ {
+ return true;
+ }
+ parent._waitingReadersTail = null;
+ }
+ else
+ {
+ // There were blocked readers. Grab one, and then complete it outside of the lock.
+ blockedReader = parent._blockedReaders.DequeueHead();
}
- parent._waitingReaders = null;
}
- // Wake up all of the waiters. Since we've released the lock, it's possible
- // we could cause some spurious wake-ups here, if we tell a waiter there's
- // something available but all data has already been removed. It's a benign
- // race condition, though, as consumers already need to account for such things.
- waitingReaders.Success(item: true);
- return true;
+ if (blockedReader != null)
+ {
+ // Complete the reader. It's possible the reader was canceled, in which
+ // case we loop around to try everything again.
+ if (blockedReader.TrySetResult(item))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ // Wake up all of the waiters. Since we've released the lock, it's possible
+ // we could cause some spurious wake-ups here, if we tell a waiter there's
+ // something available but all data has already been removed. It's a benign
+ // race condition, though, as consumers already need to account for such things.
+ ChannelUtilities.WakeUpWaiters(ref waitingReadersTail, result: true);
+ return true;
+ }
}
}
- public override Task<bool> WaitToWriteAsync(CancellationToken cancellationToken)
+ public override ValueTask<bool> WaitToWriteAsync(CancellationToken cancellationToken)
{
Exception doneWriting = _parent._doneWriting;
return
- cancellationToken.IsCancellationRequested ? Task.FromCanceled<bool>(cancellationToken) :
- doneWriting == null ? ChannelUtilities.s_trueTask : // unbounded writing can always be done if we haven't completed
- doneWriting != ChannelUtilities.s_doneWritingSentinel ? Task.FromException<bool>(doneWriting) :
- ChannelUtilities.s_falseTask;
+ cancellationToken.IsCancellationRequested ? new ValueTask<bool>(Task.FromCanceled<bool>(cancellationToken)) :
+ doneWriting == null ? new ValueTask<bool>(true) : // unbounded writing can always be done if we haven't completed
+ doneWriting != ChannelUtilities.s_doneWritingSentinel ? new ValueTask<bool>(Task.FromException<bool>(doneWriting)) :
+ default;
}
- public override Task WriteAsync(T item, CancellationToken cancellationToken) =>
- cancellationToken.IsCancellationRequested ? Task.FromCanceled(cancellationToken) :
- TryWrite(item) ? ChannelUtilities.s_trueTask :
- Task.FromException(ChannelUtilities.CreateInvalidCompletionException(_parent._doneWriting));
+ public override ValueTask WriteAsync(T item, CancellationToken cancellationToken) =>
+ cancellationToken.IsCancellationRequested ? new ValueTask(Task.FromCanceled(cancellationToken)) :
+ TryWrite(item) ? default :
+ new ValueTask(Task.FromException(ChannelUtilities.CreateInvalidCompletionException(_parent._doneWriting)));
+
+ /// <summary>Gets the number of items in the channel. This should only be used by the debugger.</summary>
+ private int ItemsCountForDebugger => _parent._items.Count;
+
+ /// <summary>Gets an enumerator the debugger can use to show the contents of the channel.</summary>
+ IEnumerator<T> IDebugEnumerable<T>.GetEnumerator() => _parent._items.GetEnumerator();
}
/// <summary>Gets the object used to synchronize access to all state on this instance.</summary>
@@ -209,11 +327,12 @@ namespace System.Threading.Channels
{
if (_runContinuationsAsynchronously)
{
- Debug.Assert(_waitingReaders == null, "There's data available, so there shouldn't be any waiting readers.");
+ Debug.Assert(_blockedReaders.IsEmpty, "There's data available, so there shouldn't be any blocked readers.");
+ Debug.Assert(_waitingReadersTail == null, "There's data available, so there shouldn't be any waiting readers.");
}
Debug.Assert(!_completion.Task.IsCompleted, "We still have data available, so shouldn't be completed.");
}
- if (_waitingReaders != null && _runContinuationsAsynchronously)
+ if ((!_blockedReaders.IsEmpty || _waitingReadersTail != null) && _runContinuationsAsynchronously)
{
Debug.Assert(_items.IsEmpty, "There are blocked/waiting readers, so there shouldn't be any data available.");
}
@@ -221,11 +340,14 @@ namespace System.Threading.Channels
{
Debug.Assert(_doneWriting != null, "We're completed, so we must be done writing.");
}
- }
+ }
/// <summary>Gets the number of items in the channel. This should only be used by the debugger.</summary>
private int ItemsCountForDebugger => _items.Count;
+ /// <summary>Report if the channel is closed or not. This should only be used by the debugger.</summary>
+ private bool ChannelIsClosedForDebugger => _doneWriting != null;
+
/// <summary>Gets an enumerator the debugger can use to show the contents of the channel.</summary>
IEnumerator<T> IDebugEnumerable<T>.GetEnumerator() => _items.GetEnumerator();
}
diff --git a/src/System.Threading.Channels/src/System/Threading/Channels/UnbufferedChannel.cs b/src/System.Threading.Channels/src/System/Threading/Channels/UnbufferedChannel.cs
deleted file mode 100644
index 0cb75b67a5..0000000000
--- a/src/System.Threading.Channels/src/System/Threading/Channels/UnbufferedChannel.cs
+++ /dev/null
@@ -1,324 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Threading.Tasks;
-
-namespace System.Threading.Channels
-{
- /// <summary>Provides an unbuffered channel, such that a reader and a writer must rendezvous to succeed.</summary>
- [DebuggerDisplay("Writers Waiting/Blocked: {WaitingWritersForDebugger}/{BlockedWritersCountForDebugger}, Readers Waiting/Blocked: {WaitingReadersForDebugger}/{BlockedReadersCountForDebugger}")]
- [DebuggerTypeProxy(typeof(UnbufferedChannel<>.DebugView))]
- internal sealed class UnbufferedChannel<T> : Channel<T>
- {
- /// <summary>Task that represents the completion of the channel.</summary>
- private readonly TaskCompletionSource<VoidResult> _completion = new TaskCompletionSource<VoidResult>(TaskCreationOptions.RunContinuationsAsynchronously);
- /// <summary>A queue of readers blocked waiting to be matched with a writer.</summary>
- private readonly Dequeue<ReaderInteractor<T>> _blockedReaders = new Dequeue<ReaderInteractor<T>>();
- /// <summary>A queue of writers blocked waiting to be matched with a reader.</summary>
- private readonly Dequeue<WriterInteractor<T>> _blockedWriters = new Dequeue<WriterInteractor<T>>();
-
- /// <summary>Task signaled when any WaitToReadAsync waiters should be woken up.</summary>
- private ReaderInteractor<bool> _waitingReaders;
- /// <summary>Task signaled when any WaitToReadAsync waiters should be woken up.</summary>
- private ReaderInteractor<bool> _waitingWriters;
-
- private sealed class UnbufferedChannelReader : ChannelReader<T>
- {
- internal readonly UnbufferedChannel<T> _parent;
- internal UnbufferedChannelReader(UnbufferedChannel<T> parent) => _parent = parent;
-
- public override Task Completion => _parent._completion.Task;
-
- public override bool TryRead(out T item)
- {
- UnbufferedChannel<T> parent = _parent;
- lock (parent.SyncObj)
- {
- parent.AssertInvariants();
-
- // Try to find a writer to pair with
- while (!parent._blockedWriters.IsEmpty)
- {
- WriterInteractor<T> w = parent._blockedWriters.DequeueHead();
- if (w.Success(default))
- {
- item = w.Item;
- return true;
- }
- }
- }
-
- // None found
- item = default;
- return false;
- }
-
- public override ValueTask<T> ReadAsync(CancellationToken cancellationToken)
- {
- if (cancellationToken.IsCancellationRequested)
- {
- return new ValueTask<T>(Task.FromCanceled<T>(cancellationToken));
- }
-
- UnbufferedChannel<T> parent = _parent;
- lock (parent.SyncObj)
- {
- parent.AssertInvariants();
-
- // If we're already completed, nothing to read.
- if (parent._completion.Task.IsCompleted)
- {
- return new ValueTask<T>(
- parent._completion.Task.IsCanceled ? Task.FromCanceled<T>(new CancellationToken(true)) :
- Task.FromException<T>(
- parent._completion.Task.IsFaulted ?
- ChannelUtilities.CreateInvalidCompletionException(parent._completion.Task.Exception.InnerException) :
- ChannelUtilities.CreateInvalidCompletionException()));
- }
-
- // If there are any blocked writers, find one to pair up with
- // and get its data. Writers that got canceled will remain in the queue,
- // so we need to loop to skip past them.
- while (!parent._blockedWriters.IsEmpty)
- {
- WriterInteractor<T> w = parent._blockedWriters.DequeueHead();
- if (w.Success(default(VoidResult)))
- {
- return new ValueTask<T>(w.Item);
- }
- }
-
- // No writer found to pair with. Queue the reader.
- var r = ReaderInteractor<T>.Create(true, cancellationToken);
- parent._blockedReaders.EnqueueTail(r);
-
- // And let any waiting writers know it's their lucky day.
- ChannelUtilities.WakeUpWaiters(ref parent._waitingWriters, result: true);
-
- return new ValueTask<T>(r.Task);
- }
- }
-
- public override Task<bool> WaitToReadAsync(CancellationToken cancellationToken)
- {
- if (cancellationToken.IsCancellationRequested)
- {
- return Task.FromCanceled<bool>(cancellationToken);
- }
-
- UnbufferedChannel<T> parent = _parent;
- lock (parent.SyncObj)
- {
- // If we're done writing, fail.
- if (parent._completion.Task.IsCompleted)
- {
- return parent._completion.Task.IsFaulted ?
- Task.FromException<bool>(parent._completion.Task.Exception.InnerException) :
- ChannelUtilities.s_falseTask;
- }
-
- // If there's a blocked writer, we can read.
- if (!parent._blockedWriters.IsEmpty)
- {
- return ChannelUtilities.s_trueTask;
- }
-
- // Otherwise, queue the waiter.
- return ChannelUtilities.GetOrCreateWaiter(ref parent._waitingReaders, runContinuationsAsynchronously: true, cancellationToken);
- }
- }
- }
-
- private sealed class UnbufferedChannelWriter : ChannelWriter<T>
- {
- internal readonly UnbufferedChannel<T> _parent;
- internal UnbufferedChannelWriter(UnbufferedChannel<T> parent) => _parent = parent;
-
- public override bool TryComplete(Exception error)
- {
- UnbufferedChannel<T> parent = _parent;
- lock (parent.SyncObj)
- {
- parent.AssertInvariants();
-
- // Mark the channel as being done. Since there's no buffered data, we can complete immediately.
- if (parent._completion.Task.IsCompleted)
- {
- return false;
- }
- ChannelUtilities.Complete(parent._completion, error);
-
- // Fail any blocked readers/writers, as there will be no writers/readers to pair them with.
- ChannelUtilities.FailInteractors<ReaderInteractor<T>, T>(parent._blockedReaders, ChannelUtilities.CreateInvalidCompletionException(error));
- ChannelUtilities.FailInteractors<WriterInteractor<T>, VoidResult>(parent._blockedWriters, ChannelUtilities.CreateInvalidCompletionException(error));
-
- // Let any waiting readers and writers know there won't be any more data
- ChannelUtilities.WakeUpWaiters(ref parent._waitingReaders, result: false, error: error);
- ChannelUtilities.WakeUpWaiters(ref parent._waitingWriters, result: false, error: error);
- }
-
- return true;
- }
-
- public override bool TryWrite(T item)
- {
- UnbufferedChannel<T> parent = _parent;
- lock (parent.SyncObj)
- {
- parent.AssertInvariants();
-
- // Try to find a reader to pair with
- while (!parent._blockedReaders.IsEmpty)
- {
- ReaderInteractor<T> r = parent._blockedReaders.DequeueHead();
- if (r.Success(item))
- {
- return true;
- }
- }
- }
-
- // None found
- return false;
- }
-
- public override Task<bool> WaitToWriteAsync(CancellationToken cancellationToken)
- {
- if (cancellationToken.IsCancellationRequested)
- {
- return Task.FromCanceled<bool>(cancellationToken);
- }
-
- UnbufferedChannel<T> parent = _parent;
- lock (parent.SyncObj)
- {
- // If we're done writing, fail.
- if (parent._completion.Task.IsCompleted)
- {
- return parent._completion.Task.IsFaulted ?
- Task.FromException<bool>(parent._completion.Task.Exception.InnerException) :
- ChannelUtilities.s_falseTask;
- }
-
- // If there's a blocked reader, we can write
- if (!parent._blockedReaders.IsEmpty)
- {
- return ChannelUtilities.s_trueTask;
- }
-
- // Otherwise, queue the writer
- return ChannelUtilities.GetOrCreateWaiter(ref parent._waitingWriters, true, cancellationToken);
- }
- }
-
- public override Task WriteAsync(T item, CancellationToken cancellationToken)
- {
- if (cancellationToken.IsCancellationRequested)
- {
- return Task.FromCanceled(cancellationToken);
- }
-
- UnbufferedChannel<T> parent = _parent;
- lock (parent.SyncObj)
- {
- // Fail if we've already completed
- if (parent._completion.Task.IsCompleted)
- {
- return
- parent._completion.Task.IsCanceled ? Task.FromCanceled<T>(new CancellationToken(true)) :
- Task.FromException<T>(
- parent._completion.Task.IsFaulted ?
- ChannelUtilities.CreateInvalidCompletionException(parent._completion.Task.Exception.InnerException) :
- ChannelUtilities.CreateInvalidCompletionException());
- }
-
- // Try to find a reader to pair with. Canceled readers remain in the queue,
- // so we need to loop until we find one.
- while (!parent._blockedReaders.IsEmpty)
- {
- ReaderInteractor<T> r = parent._blockedReaders.DequeueHead();
- if (r.Success(item))
- {
- return Task.CompletedTask;
- }
- }
-
- // No reader was available. Queue the writer.
- var w = WriterInteractor<T>.Create(true, item, cancellationToken);
- parent._blockedWriters.EnqueueTail(w);
-
- // And let any waiting readers know it's their lucky day.
- ChannelUtilities.WakeUpWaiters(ref parent._waitingReaders, result: true);
-
- return w.Task;
- }
- }
- }
-
- /// <summary>Initialize the channel.</summary>
- internal UnbufferedChannel()
- {
- base.Reader = new UnbufferedChannelReader(this);
- Writer = new UnbufferedChannelWriter(this);
- }
-
- /// <summary>Gets an object used to synchronize all state on the instance.</summary>
- private object SyncObj => _completion;
-
- [Conditional("DEBUG")]
- private void AssertInvariants()
- {
- Debug.Assert(SyncObj != null, "The sync obj must not be null.");
- Debug.Assert(Monitor.IsEntered(SyncObj), "Invariants can only be validated while holding the lock.");
-
- if (!_blockedReaders.IsEmpty)
- {
- Debug.Assert(_blockedWriters.IsEmpty, "If there are blocked readers, there can't be blocked writers.");
- }
- if (!_blockedWriters.IsEmpty)
- {
- Debug.Assert(_blockedReaders.IsEmpty, "If there are blocked writers, there can't be blocked readers.");
- }
- if (_completion.Task.IsCompleted)
- {
- Debug.Assert(_blockedReaders.IsEmpty, "No readers can be blocked after we've completed.");
- Debug.Assert(_blockedWriters.IsEmpty, "No writers can be blocked after we've completed.");
- }
- }
-
- /// <summary>Gets whether there are any waiting writers. This should only be used by the debugger.</summary>
- private bool WaitingWritersForDebugger => _waitingWriters != null;
- /// <summary>Gets whether there are any waiting readers. This should only be used by the debugger.</summary>
- private bool WaitingReadersForDebugger => _waitingReaders != null;
- /// <summary>Gets the number of blocked writers. This should only be used by the debugger.</summary>
- private int BlockedWritersCountForDebugger => _blockedWriters.Count;
- /// <summary>Gets the number of blocked readers. This should only be used by the debugger.</summary>
- private int BlockedReadersCountForDebugger => _blockedReaders.Count;
-
- private sealed class DebugView
- {
- private readonly UnbufferedChannel<T> _channel;
-
- public DebugView(UnbufferedChannel<T> channel) => _channel = channel;
-
- public bool WaitingReaders => _channel._waitingReaders != null;
- public bool WaitingWriters => _channel._waitingWriters != null;
- public int BlockedReaders => _channel._blockedReaders.Count;
- public T[] BlockedWriters
- {
- get
- {
- var items = new List<T>();
- foreach (WriterInteractor<T> blockedWriter in _channel._blockedWriters)
- {
- items.Add(blockedWriter.Item);
- }
- return items.ToArray();
- }
- }
- }
- }
-}
diff --git a/src/System.Threading.Channels/tests/BoundedChannelTests.cs b/src/System.Threading.Channels/tests/BoundedChannelTests.cs
index b19bc8605a..903d85c2a0 100644
--- a/src/System.Threading.Channels/tests/BoundedChannelTests.cs
+++ b/src/System.Threading.Channels/tests/BoundedChannelTests.cs
@@ -1,5 +1,6 @@
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
using System.Threading.Tasks;
using Xunit;
@@ -8,11 +9,11 @@ namespace System.Threading.Channels.Tests
{
public class BoundedChannelTests : ChannelTestBase
{
- protected override Channel<int> CreateChannel() => Channel.CreateBounded<int>(1);
- protected override Channel<int> CreateFullChannel()
+ protected override Channel<T> CreateChannel<T>() => Channel.CreateBounded<T>(new BoundedChannelOptions(1) { AllowSynchronousContinuations = AllowSynchronousContinuations });
+ protected override Channel<T> CreateFullChannel<T>()
{
- var c = Channel.CreateBounded<int>(1);
- c.Writer.WriteAsync(42).Wait();
+ var c = Channel.CreateBounded<T>(new BoundedChannelOptions(1) { AllowSynchronousContinuations = AllowSynchronousContinuations });
+ c.Writer.WriteAsync(default).AsTask().Wait();
return c;
}
@@ -217,16 +218,16 @@ namespace System.Threading.Channels.Tests
public async Task CancelPendingWrite_Reading_DataTransferredFromCorrectWriter()
{
var c = Channel.CreateBounded<int>(1);
- Assert.Equal(TaskStatus.RanToCompletion, c.Writer.WriteAsync(42).Status);
+ Assert.True(c.Writer.WriteAsync(42).IsCompletedSuccessfully);
var cts = new CancellationTokenSource();
- Task write1 = c.Writer.WriteAsync(43, cts.Token);
+ Task write1 = c.Writer.WriteAsync(43, cts.Token).AsTask();
Assert.Equal(TaskStatus.WaitingForActivation, write1.Status);
cts.Cancel();
- Task write2 = c.Writer.WriteAsync(44);
+ Task write2 = c.Writer.WriteAsync(44).AsTask();
Assert.Equal(42, await c.Reader.ReadAsync());
Assert.Equal(44, await c.Reader.ReadAsync());
@@ -341,10 +342,10 @@ namespace System.Threading.Channels.Tests
var c = Channel.CreateBounded<int>(1);
Assert.True(c.Writer.TryWrite(1));
- Task<bool> write1 = c.Writer.WaitToWriteAsync();
+ Task<bool> write1 = c.Writer.WaitToWriteAsync().AsTask();
Assert.False(write1.IsCompleted);
- Task<bool> write2 = c.Writer.WaitToWriteAsync();
+ Task<bool> write2 = c.Writer.WaitToWriteAsync().AsTask();
Assert.False(write2.IsCompleted);
Assert.Equal(1, await c.Reader.ReadAsync());
@@ -361,12 +362,12 @@ namespace System.Threading.Channels.Tests
var c = Channel.CreateBounded<int>(new BoundedChannelOptions(1) { AllowSynchronousContinuations = allowSynchronousContinuations });
int expectedId = Environment.CurrentManagedThreadId;
- Task r = c.Reader.WaitToReadAsync().ContinueWith(_ =>
+ Task r = c.Reader.WaitToReadAsync().AsTask().ContinueWith(_ =>
{
Assert.Equal(allowSynchronousContinuations, expectedId == Environment.CurrentManagedThreadId);
}, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
- Assert.Equal(TaskStatus.RanToCompletion, c.Writer.WriteAsync(42).Status);
+ Assert.True(c.Writer.WriteAsync(42).IsCompletedSuccessfully);
((IAsyncResult)r).AsyncWaitHandle.WaitOne(); // avoid inlining the continuation
r.GetAwaiter().GetResult();
}
@@ -390,13 +391,13 @@ namespace System.Threading.Channels.Tests
}
[Fact]
- public void TryWrite_NoBlockedReaders_WaitingReader_WaiterNotifified()
+ public async Task TryWrite_NoBlockedReaders_WaitingReader_WaiterNotified()
{
Channel<int> c = CreateChannel();
- Task<bool> r = c.Reader.WaitToReadAsync();
+ Task<bool> r = c.Reader.WaitToReadAsync().AsTask();
Assert.True(c.Writer.TryWrite(42));
- AssertSynchronousTrue(r);
+ Assert.True(await r);
}
}
}
diff --git a/src/System.Threading.Channels/tests/ChannelClosedExceptionTests.cs b/src/System.Threading.Channels/tests/ChannelClosedExceptionTests.cs
index 38a1e9bb50..01a3b34ee5 100644
--- a/src/System.Threading.Channels/tests/ChannelClosedExceptionTests.cs
+++ b/src/System.Threading.Channels/tests/ChannelClosedExceptionTests.cs
@@ -1,5 +1,6 @@
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
using Xunit;
diff --git a/src/System.Threading.Channels/tests/ChannelTestBase.cs b/src/System.Threading.Channels/tests/ChannelTestBase.cs
index 3260dbf2f9..1572c655cf 100644
--- a/src/System.Threading.Channels/tests/ChannelTestBase.cs
+++ b/src/System.Threading.Channels/tests/ChannelTestBase.cs
@@ -1,9 +1,11 @@
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
+using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Xunit;
@@ -11,9 +13,13 @@ namespace System.Threading.Channels.Tests
{
public abstract class ChannelTestBase : TestBase
{
- protected abstract Channel<int> CreateChannel();
- protected abstract Channel<int> CreateFullChannel();
+ protected Channel<int> CreateChannel() => CreateChannel<int>();
+ protected abstract Channel<T> CreateChannel<T>();
+ protected Channel<int> CreateFullChannel() => CreateFullChannel<int>();
+ protected abstract Channel<T> CreateFullChannel<T>();
+
+ protected virtual bool AllowSynchronousContinuations => false;
protected virtual bool RequiresSingleReader => false;
protected virtual bool RequiresSingleWriter => false;
protected virtual bool BuffersItems => true;
@@ -78,10 +84,10 @@ namespace System.Threading.Channels.Tests
public async Task Complete_BeforeEmpty_WaitingReaders_TriggersCompletion()
{
Channel<int> c = CreateChannel();
- Task<int> read = c.Reader.ReadAsync().AsTask();
+ ValueTask<int> read = c.Reader.ReadAsync();
c.Writer.Complete();
await c.Reader.Completion;
- await Assert.ThrowsAnyAsync<InvalidOperationException>(() => read);
+ await Assert.ThrowsAnyAsync<InvalidOperationException>(async () => await read);
}
[Fact]
@@ -246,18 +252,18 @@ namespace System.Threading.Channels.Tests
public void WaitToReadAsync_DataAvailableBefore_CompletesSynchronously()
{
Channel<int> c = CreateChannel();
- Task write = c.Writer.WriteAsync(42);
- Task<bool> read = c.Reader.WaitToReadAsync();
- Assert.Equal(TaskStatus.RanToCompletion, read.Status);
+ ValueTask write = c.Writer.WriteAsync(42);
+ ValueTask<bool> read = c.Reader.WaitToReadAsync();
+ Assert.True(read.IsCompletedSuccessfully);
}
[Fact]
public void WaitToReadAsync_DataAvailableAfter_CompletesAsynchronously()
{
Channel<int> c = CreateChannel();
- Task<bool> read = c.Reader.WaitToReadAsync();
+ ValueTask<bool> read = c.Reader.WaitToReadAsync();
Assert.False(read.IsCompleted);
- Task write = c.Writer.WriteAsync(42);
+ ValueTask write = c.Writer.WriteAsync(42);
Assert.True(read.Result);
}
@@ -266,8 +272,8 @@ namespace System.Threading.Channels.Tests
{
Channel<int> c = CreateChannel();
c.Writer.Complete();
- Task<bool> read = c.Reader.WaitToReadAsync();
- Assert.Equal(TaskStatus.RanToCompletion, read.Status);
+ ValueTask<bool> read = c.Reader.WaitToReadAsync();
+ Assert.True(read.IsCompletedSuccessfully);
Assert.False(read.Result);
}
@@ -275,7 +281,7 @@ namespace System.Threading.Channels.Tests
public void WaitToReadAsync_BeforeComplete_AsynchronouslyCompletes()
{
Channel<int> c = CreateChannel();
- Task<bool> read = c.Reader.WaitToReadAsync();
+ ValueTask<bool> read = c.Reader.WaitToReadAsync();
Assert.False(read.IsCompleted);
c.Writer.Complete();
Assert.False(read.Result);
@@ -286,8 +292,8 @@ namespace System.Threading.Channels.Tests
{
Channel<int> c = CreateChannel();
c.Writer.Complete();
- Task<bool> write = c.Writer.WaitToWriteAsync();
- Assert.Equal(TaskStatus.RanToCompletion, write.Status);
+ ValueTask<bool> write = c.Writer.WaitToWriteAsync();
+ Assert.True(write.IsCompletedSuccessfully);
Assert.False(write.Result);
}
@@ -300,8 +306,8 @@ namespace System.Threading.Channels.Tests
}
Channel<int> c = CreateChannel();
- Task<bool> write = c.Writer.WaitToWriteAsync();
- Assert.Equal(TaskStatus.RanToCompletion, write.Status);
+ ValueTask<bool> write = c.Writer.WaitToWriteAsync();
+ Assert.True(write.IsCompletedSuccessfully);
Assert.True(write.Result);
}
@@ -315,7 +321,7 @@ namespace System.Threading.Channels.Tests
Channel<int> c = CreateChannel();
- Task[] writers = Enumerable.Range(0, 100).Select(_ => c.Writer.WaitToWriteAsync()).ToArray();
+ Task[] writers = Enumerable.Range(0, 100).Select(_ => c.Writer.WaitToWriteAsync().AsTask()).ToArray();
Task[] readers = Enumerable.Range(0, 100).Select(_ => c.Reader.ReadAsync().AsTask()).ToArray();
await Task.WhenAll(writers);
@@ -333,7 +339,7 @@ namespace System.Threading.Channels.Tests
public void TryRead_DataAvailable_Success()
{
Channel<int> c = CreateChannel();
- Task write = c.Writer.WriteAsync(42);
+ ValueTask write = c.Writer.WriteAsync(42);
Assert.True(c.Reader.TryRead(out int result));
Assert.Equal(42, result);
}
@@ -359,7 +365,7 @@ namespace System.Threading.Channels.Tests
{
Channel<int> c = CreateChannel();
c.Writer.Complete();
- await Assert.ThrowsAnyAsync<InvalidOperationException>(() => c.Writer.WriteAsync(42));
+ await Assert.ThrowsAnyAsync<InvalidOperationException>(async () => await c.Writer.WriteAsync(42));
}
[Fact]
@@ -392,10 +398,10 @@ namespace System.Threading.Channels.Tests
Channel<int> c = CreateFullChannel();
if (c != null)
{
- Task write = c.Writer.WriteAsync(42);
+ ValueTask write = c.Writer.WriteAsync(42);
var exc = new FormatException();
c.Writer.Complete(exc);
- Assert.Same(exc, (await Assert.ThrowsAsync<ChannelClosedException>(() => write)).InnerException);
+ Assert.Same(exc, (await Assert.ThrowsAsync<ChannelClosedException>(async () => await write)).InnerException);
}
}
@@ -405,18 +411,18 @@ namespace System.Threading.Channels.Tests
Channel<int> c = CreateChannel();
var exc = new FormatException();
c.Writer.Complete(exc);
- Task write = c.Writer.WriteAsync(42);
- Assert.Same(exc, (await Assert.ThrowsAsync<ChannelClosedException>(() => write)).InnerException);
+ ValueTask write = c.Writer.WriteAsync(42);
+ Assert.Same(exc, (await Assert.ThrowsAsync<ChannelClosedException>(async () => await write)).InnerException);
}
[Fact]
public async Task Complete_WithException_PropagatesToExistingWaitingReader()
{
Channel<int> c = CreateChannel();
- Task<bool> read = c.Reader.WaitToReadAsync();
+ ValueTask<bool> read = c.Reader.WaitToReadAsync();
var exc = new FormatException();
c.Writer.Complete(exc);
- await Assert.ThrowsAsync<FormatException>(() => read);
+ await Assert.ThrowsAsync<FormatException>(async () => await read);
}
[Fact]
@@ -425,8 +431,8 @@ namespace System.Threading.Channels.Tests
Channel<int> c = CreateChannel();
var exc = new FormatException();
c.Writer.Complete(exc);
- Task<bool> read = c.Reader.WaitToReadAsync();
- await Assert.ThrowsAsync<FormatException>(() => read);
+ ValueTask<bool> read = c.Reader.WaitToReadAsync();
+ await Assert.ThrowsAsync<FormatException>(async () => await read);
}
[Fact]
@@ -435,8 +441,8 @@ namespace System.Threading.Channels.Tests
Channel<int> c = CreateChannel();
var exc = new FormatException();
c.Writer.Complete(exc);
- Task<bool> write = c.Writer.WaitToWriteAsync();
- await Assert.ThrowsAsync<FormatException>(() => write);
+ ValueTask<bool> write = c.Writer.WaitToWriteAsync();
+ await Assert.ThrowsAsync<FormatException>(async () => await write);
}
[Theory]
@@ -453,7 +459,7 @@ namespace System.Threading.Channels.Tests
const int NumItems = 2000;
- Task[] writers = new Task[NumItems];
+ ValueTask[] writers = new ValueTask[NumItems];
for (int i = 0; i < writers.Length; i++)
{
writers[i] = c.Writer.WriteAsync(i);
@@ -475,11 +481,11 @@ namespace System.Threading.Channels.Tests
{
Channel<int> c = CreateChannel();
- Task writeTask = c.Writer.WriteAsync(42, new CancellationToken(true));
- Assert.Equal(TaskStatus.Canceled, writeTask.Status);
+ ValueTask writeTask = c.Writer.WriteAsync(42, new CancellationToken(true));
+ Assert.True(writeTask.IsCanceled);
- Task<bool> waitTask = c.Writer.WaitToWriteAsync(new CancellationToken(true));
- Assert.Equal(TaskStatus.Canceled, waitTask.Status);
+ ValueTask<bool> waitTask = c.Writer.WaitToWriteAsync(new CancellationToken(true));
+ Assert.True(writeTask.IsCanceled);
}
[Fact]
@@ -490,13 +496,19 @@ namespace System.Threading.Channels.Tests
AssertSynchronousTrue(c.Reader.WaitToReadAsync());
}
- [Fact]
- public void Precancellation_WaitToReadAsync_ReturnsImmediately()
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public void Precancellation_WaitToReadAsync_ReturnsImmediately(bool dataAvailable)
{
Channel<int> c = CreateChannel();
+ if (dataAvailable)
+ {
+ Assert.True(c.Writer.TryWrite(42));
+ }
- Task writeTask = c.Reader.WaitToReadAsync(new CancellationToken(true));
- Assert.Equal(TaskStatus.Canceled, writeTask.Status);
+ ValueTask<bool> waitTask = c.Reader.WaitToReadAsync(new CancellationToken(true));
+ Assert.True(waitTask.IsCanceled);
}
[Theory]
@@ -507,10 +519,10 @@ namespace System.Threading.Channels.Tests
Channel<int> c = CreateChannel();
CancellationToken token = cancelable ? new CancellationTokenSource().Token : default;
- Task<bool> read = c.Reader.WaitToReadAsync(token);
+ ValueTask<bool> read = c.Reader.WaitToReadAsync(token);
Assert.False(read.IsCompleted);
- Task write = c.Writer.WriteAsync(42, token);
+ ValueTask write = c.Writer.WriteAsync(42, token);
Assert.True(await read);
}
@@ -521,10 +533,10 @@ namespace System.Threading.Channels.Tests
Channel<int> c = CreateChannel();
var cts = new CancellationTokenSource();
- Task<bool> read = c.Reader.WaitToReadAsync(cts.Token);
+ ValueTask<bool> read = c.Reader.WaitToReadAsync(cts.Token);
Assert.False(read.IsCompleted);
cts.Cancel();
- await Assert.ThrowsAnyAsync<OperationCanceledException>(() => read);
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await read);
}
[Fact]
@@ -535,7 +547,7 @@ namespace System.Threading.Channels.Tests
ValueTask<int> r = c.Reader.ReadAsync();
Assert.False(r.IsCompleted);
- Task w = c.Writer.WriteAsync(42);
+ ValueTask w = c.Writer.WriteAsync(42);
AssertSynchronousSuccess(w);
Assert.Equal(42, await r);
@@ -546,21 +558,27 @@ namespace System.Threading.Channels.Tests
{
Channel<int> c = CreateChannel();
- Task w = c.Writer.WriteAsync(42);
+ ValueTask w = c.Writer.WriteAsync(42);
ValueTask<int> r = c.Reader.ReadAsync();
- await Task.WhenAll(w, r.AsTask());
+ await Task.WhenAll(w.AsTask(), r.AsTask());
Assert.Equal(42, await r);
}
- [Fact]
- public void ReadAsync_Precanceled_CanceledSynchronously()
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public void Precancellation_ReadAsync_ReturnsImmediately(bool dataAvailable)
{
Channel<int> c = CreateChannel();
- var cts = new CancellationTokenSource();
- cts.Cancel();
- AssertSynchronouslyCanceled(c.Reader.ReadAsync(cts.Token).AsTask(), cts.Token);
+ if (dataAvailable)
+ {
+ Assert.True(c.Writer.TryWrite(42));
+ }
+
+ ValueTask<int> readTask = c.Reader.ReadAsync(new CancellationToken(true));
+ Assert.True(readTask.IsCanceled);
}
[Fact]
@@ -613,8 +631,8 @@ namespace System.Threading.Channels.Tests
Channel<int> c = CreateChannel();
const int Items = 100;
- ValueTask<int>[] readers = (from i in Enumerable.Range(0, Items) select c.Reader.ReadAsync()).ToArray();
- var remainingReaders = new List<Task<int>>(readers.Select(r => r.AsTask()));
+ Task<int>[] readers = (from i in Enumerable.Range(0, Items) select c.Reader.ReadAsync().AsTask()).ToArray();
+ var remainingReaders = new List<Task<int>>(readers);
for (int i = 0; i < Items; i++)
{
@@ -624,7 +642,7 @@ namespace System.Threading.Channels.Tests
remainingReaders.Remove(r);
}
- Assert.Equal((Items * (Items - 1)) / 2, Enumerable.Sum(await Task.WhenAll(readers.Select(r => r.AsTask()))));
+ Assert.Equal((Items * (Items - 1)) / 2, Enumerable.Sum(await Task.WhenAll(readers)));
}
[Fact]
@@ -690,5 +708,520 @@ namespace System.Threading.Channels.Tests
Assert.Equal(i, await r);
}
}
+
+ [Fact]
+ public async Task ReadAsync_ConsecutiveReadsSucceed()
+ {
+ Channel<int> c = CreateChannel();
+ for (int i = 0; i < 5; i++)
+ {
+ ValueTask<int> r = c.Reader.ReadAsync();
+ await c.Writer.WriteAsync(i);
+ Assert.Equal(i, await r);
+ }
+ }
+
+ [Fact]
+ public async Task WaitToReadAsync_ConsecutiveReadsSucceed()
+ {
+ Channel<int> c = CreateChannel();
+ for (int i = 0; i < 5; i++)
+ {
+ ValueTask<bool> r = c.Reader.WaitToReadAsync();
+ await c.Writer.WriteAsync(i);
+ Assert.True(await r);
+ Assert.True(c.Reader.TryRead(out int item));
+ Assert.Equal(i, item);
+ }
+ }
+
+ [Theory]
+ [InlineData(false, null)]
+ [InlineData(false, false)]
+ [InlineData(false, true)]
+ [InlineData(true, null)]
+ [InlineData(true, false)]
+ [InlineData(true, true)]
+ public void WaitToReadAsync_MultipleContinuations_Throws(bool onCompleted, bool? continueOnCapturedContext)
+ {
+ Channel<int> c = CreateChannel();
+
+ ValueTask<bool> read = c.Reader.WaitToReadAsync();
+ switch (continueOnCapturedContext)
+ {
+ case null:
+ if (onCompleted)
+ {
+ read.GetAwaiter().OnCompleted(() => { });
+ Assert.Throws<InvalidOperationException>(() => read.GetAwaiter().OnCompleted(() => { }));
+ }
+ else
+ {
+ read.GetAwaiter().UnsafeOnCompleted(() => { });
+ Assert.Throws<InvalidOperationException>(() => read.GetAwaiter().UnsafeOnCompleted(() => { }));
+ }
+ break;
+
+ default:
+ if (onCompleted)
+ {
+ read.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().OnCompleted(() => { });
+ Assert.Throws<InvalidOperationException>(() => read.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().OnCompleted(() => { }));
+ }
+ else
+ {
+ read.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().UnsafeOnCompleted(() => { });
+ Assert.Throws<InvalidOperationException>(() => read.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().UnsafeOnCompleted(() => { }));
+ }
+ break;
+ }
+ }
+
+ [Theory]
+ [InlineData(false, null)]
+ [InlineData(false, false)]
+ [InlineData(false, true)]
+ [InlineData(true, null)]
+ [InlineData(true, false)]
+ [InlineData(true, true)]
+ public void ReadAsync_MultipleContinuations_Throws(bool onCompleted, bool? continueOnCapturedContext)
+ {
+ Channel<int> c = CreateChannel();
+
+ ValueTask<int> read = c.Reader.ReadAsync();
+ switch (continueOnCapturedContext)
+ {
+ case null:
+ if (onCompleted)
+ {
+ read.GetAwaiter().OnCompleted(() => { });
+ Assert.Throws<InvalidOperationException>(() => read.GetAwaiter().OnCompleted(() => { }));
+ }
+ else
+ {
+ read.GetAwaiter().UnsafeOnCompleted(() => { });
+ Assert.Throws<InvalidOperationException>(() => read.GetAwaiter().UnsafeOnCompleted(() => { }));
+ }
+ break;
+
+ default:
+ if (onCompleted)
+ {
+ read.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().OnCompleted(() => { });
+ Assert.Throws<InvalidOperationException>(() => read.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().OnCompleted(() => { }));
+ }
+ else
+ {
+ read.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().UnsafeOnCompleted(() => { });
+ Assert.Throws<InvalidOperationException>(() => read.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().UnsafeOnCompleted(() => { }));
+ }
+ break;
+ }
+ }
+
+ [Fact]
+ public async Task WaitToReadAsync_AwaitThenGetResult_Throws()
+ {
+ Channel<int> c = CreateChannel();
+
+ ValueTask<bool> read = c.Reader.WaitToReadAsync();
+ Assert.True(c.Writer.TryWrite(42));
+ Assert.True(await read);
+ Assert.Throws<InvalidOperationException>(() => read.GetAwaiter().IsCompleted);
+ Assert.Throws<InvalidOperationException>(() => read.GetAwaiter().OnCompleted(() => { }));
+ Assert.Throws<InvalidOperationException>(() => read.GetAwaiter().GetResult());
+ }
+
+ [Fact]
+ public async Task ReadAsync_AwaitThenGetResult_Throws()
+ {
+ Channel<int> c = CreateChannel();
+
+ ValueTask<int> read = c.Reader.ReadAsync();
+ Assert.True(c.Writer.TryWrite(42));
+ Assert.Equal(42, await read);
+ Assert.Throws<InvalidOperationException>(() => read.GetAwaiter().IsCompleted);
+ Assert.Throws<InvalidOperationException>(() => read.GetAwaiter().OnCompleted(() => { }));
+ Assert.Throws<InvalidOperationException>(() => read.GetAwaiter().GetResult());
+ }
+
+ [Fact]
+ public async Task WaitToWriteAsync_AwaitThenGetResult_Throws()
+ {
+ Channel<int> c = CreateFullChannel();
+ if (c == null)
+ {
+ return;
+ }
+
+ ValueTask<bool> write = c.Writer.WaitToWriteAsync();
+ await c.Reader.ReadAsync();
+ Assert.True(await write);
+ Assert.Throws<InvalidOperationException>(() => write.GetAwaiter().IsCompleted);
+ Assert.Throws<InvalidOperationException>(() => write.GetAwaiter().OnCompleted(() => { }));
+ Assert.Throws<InvalidOperationException>(() => write.GetAwaiter().GetResult());
+ }
+
+ [Fact]
+ public async Task WriteAsync_AwaitThenGetResult_Throws()
+ {
+ Channel<int> c = CreateFullChannel();
+ if (c == null)
+ {
+ return;
+ }
+
+ ValueTask write = c.Writer.WriteAsync(42);
+ await c.Reader.ReadAsync();
+ await write;
+ Assert.Throws<InvalidOperationException>(() => write.GetAwaiter().IsCompleted);
+ Assert.Throws<InvalidOperationException>(() => write.GetAwaiter().OnCompleted(() => { }));
+ Assert.Throws<InvalidOperationException>(() => write.GetAwaiter().GetResult());
+ }
+
+ [Theory]
+ [InlineData(false, null)]
+ [InlineData(false, false)]
+ [InlineData(false, true)]
+ [InlineData(true, null)]
+ [InlineData(true, false)]
+ [InlineData(true, true)]
+ public void WaitToWriteAsync_MultipleContinuations_Throws(bool onCompleted, bool? continueOnCapturedContext)
+ {
+ Channel<int> c = CreateFullChannel();
+ if (c == null)
+ {
+ return;
+ }
+
+ ValueTask<bool> write = c.Writer.WaitToWriteAsync();
+ switch (continueOnCapturedContext)
+ {
+ case null:
+ if (onCompleted)
+ {
+ write.GetAwaiter().OnCompleted(() => { });
+ Assert.Throws<InvalidOperationException>(() => write.GetAwaiter().OnCompleted(() => { }));
+ }
+ else
+ {
+ write.GetAwaiter().UnsafeOnCompleted(() => { });
+ Assert.Throws<InvalidOperationException>(() => write.GetAwaiter().UnsafeOnCompleted(() => { }));
+ }
+ break;
+
+ default:
+ if (onCompleted)
+ {
+ write.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().OnCompleted(() => { });
+ Assert.Throws<InvalidOperationException>(() => write.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().OnCompleted(() => { }));
+ }
+ else
+ {
+ write.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().UnsafeOnCompleted(() => { });
+ Assert.Throws<InvalidOperationException>(() => write.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().UnsafeOnCompleted(() => { }));
+ }
+ break;
+ }
+ }
+
+ [Theory]
+ [InlineData(false, null)]
+ [InlineData(false, false)]
+ [InlineData(false, true)]
+ [InlineData(true, null)]
+ [InlineData(true, false)]
+ [InlineData(true, true)]
+ public void WriteAsync_MultipleContinuations_Throws(bool onCompleted, bool? continueOnCapturedContext)
+ {
+ Channel<int> c = CreateFullChannel();
+ if (c == null)
+ {
+ return;
+ }
+
+ ValueTask write = c.Writer.WriteAsync(42);
+ switch (continueOnCapturedContext)
+ {
+ case null:
+ if (onCompleted)
+ {
+ write.GetAwaiter().OnCompleted(() => { });
+ Assert.Throws<InvalidOperationException>(() => write.GetAwaiter().OnCompleted(() => { }));
+ }
+ else
+ {
+ write.GetAwaiter().UnsafeOnCompleted(() => { });
+ Assert.Throws<InvalidOperationException>(() => write.GetAwaiter().UnsafeOnCompleted(() => { }));
+ }
+ break;
+
+ default:
+ if (onCompleted)
+ {
+ write.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().OnCompleted(() => { });
+ Assert.Throws<InvalidOperationException>(() => write.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().OnCompleted(() => { }));
+ }
+ else
+ {
+ write.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().UnsafeOnCompleted(() => { });
+ Assert.Throws<InvalidOperationException>(() => write.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().UnsafeOnCompleted(() => { }));
+ }
+ break;
+ }
+ }
+
+ public static IEnumerable<object[]> Reader_ContinuesOnCurrentContextIfDesired_MemberData() =>
+ from readOrWait in new[] { true, false }
+ from completeBeforeOnCompleted in new[] { true, false }
+ from flowExecutionContext in new[] { true, false }
+ from continueOnCapturedContext in new bool?[] { null, false, true }
+ select new object[] { readOrWait, completeBeforeOnCompleted, flowExecutionContext, continueOnCapturedContext };
+
+ [Theory]
+ [MemberData(nameof(Reader_ContinuesOnCurrentContextIfDesired_MemberData))]
+ public async Task Reader_ContinuesOnCurrentSynchronizationContextIfDesired(
+ bool readOrWait, bool completeBeforeOnCompleted, bool flowExecutionContext, bool? continueOnCapturedContext)
+ {
+ if (AllowSynchronousContinuations)
+ {
+ return;
+ }
+
+ await Task.Run(async () =>
+ {
+ Assert.Null(SynchronizationContext.Current);
+
+ Channel<bool> c = CreateChannel<bool>();
+ ValueTask<bool> vt = readOrWait ?
+ c.Reader.ReadAsync() :
+ c.Reader.WaitToReadAsync();
+
+ var continuationRan = new TaskCompletionSource<bool>();
+ var asyncLocal = new AsyncLocal<int>();
+ bool schedulerWasFlowed = false;
+ bool executionContextWasFlowed = false;
+ Action continuation = () =>
+ {
+ schedulerWasFlowed = SynchronizationContext.Current is CustomSynchronizationContext;
+ executionContextWasFlowed = 42 == asyncLocal.Value;
+ continuationRan.SetResult(true);
+ };
+
+ if (completeBeforeOnCompleted)
+ {
+ Assert.False(vt.IsCompleted);
+ Assert.False(vt.IsCompletedSuccessfully);
+ c.Writer.TryWrite(true);
+ }
+
+ SynchronizationContext.SetSynchronizationContext(new CustomSynchronizationContext());
+ asyncLocal.Value = 42;
+ switch (continueOnCapturedContext)
+ {
+ case null:
+ if (flowExecutionContext)
+ {
+ vt.GetAwaiter().OnCompleted(continuation);
+ }
+ else
+ {
+ vt.GetAwaiter().UnsafeOnCompleted(continuation);
+ }
+ break;
+ default:
+ if (flowExecutionContext)
+ {
+ vt.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().OnCompleted(continuation);
+ }
+ else
+ {
+ vt.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().UnsafeOnCompleted(continuation);
+ }
+ break;
+ }
+ asyncLocal.Value = 0;
+ SynchronizationContext.SetSynchronizationContext(null);
+
+ if (!completeBeforeOnCompleted)
+ {
+ Assert.False(vt.IsCompleted);
+ Assert.False(vt.IsCompletedSuccessfully);
+ c.Writer.TryWrite(true);
+ }
+
+ await continuationRan.Task;
+ Assert.True(vt.IsCompleted);
+ Assert.True(vt.IsCompletedSuccessfully);
+
+ Assert.Equal(continueOnCapturedContext != false, schedulerWasFlowed);
+ if (completeBeforeOnCompleted) // OnCompleted will simply queue using a mechanism that happens to flow
+ {
+ Assert.True(executionContextWasFlowed);
+ }
+ else
+ {
+ Assert.Equal(flowExecutionContext, executionContextWasFlowed);
+ }
+ });
+ }
+
+ [Theory]
+ [MemberData(nameof(Reader_ContinuesOnCurrentContextIfDesired_MemberData))]
+ public async Task Reader_ContinuesOnCurrentTaskSchedulerIfDesired(
+ bool readOrWait, bool completeBeforeOnCompleted, bool flowExecutionContext, bool? continueOnCapturedContext)
+ {
+ if (AllowSynchronousContinuations)
+ {
+ return;
+ }
+
+ await Task.Run(async () =>
+ {
+ Assert.Null(SynchronizationContext.Current);
+
+ Channel<bool> c = CreateChannel<bool>();
+ ValueTask<bool> vt = readOrWait ?
+ c.Reader.ReadAsync() :
+ c.Reader.WaitToReadAsync();
+
+ var continuationRan = new TaskCompletionSource<bool>();
+ var asyncLocal = new AsyncLocal<int>();
+ bool schedulerWasFlowed = false;
+ bool executionContextWasFlowed = false;
+ Action continuation = () =>
+ {
+ schedulerWasFlowed = TaskScheduler.Current is CustomTaskScheduler;
+ executionContextWasFlowed = 42 == asyncLocal.Value;
+ continuationRan.SetResult(true);
+ };
+
+ if (completeBeforeOnCompleted)
+ {
+ Assert.False(vt.IsCompleted);
+ Assert.False(vt.IsCompletedSuccessfully);
+ c.Writer.TryWrite(true);
+ }
+
+ await Task.Factory.StartNew(() =>
+ {
+ Assert.IsType<CustomTaskScheduler>(TaskScheduler.Current);
+ asyncLocal.Value = 42;
+ switch (continueOnCapturedContext)
+ {
+ case null:
+ if (flowExecutionContext)
+ {
+ vt.GetAwaiter().OnCompleted(continuation);
+ }
+ else
+ {
+ vt.GetAwaiter().UnsafeOnCompleted(continuation);
+ }
+ break;
+ default:
+ if (flowExecutionContext)
+ {
+ vt.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().OnCompleted(continuation);
+ }
+ else
+ {
+ vt.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().UnsafeOnCompleted(continuation);
+ }
+ break;
+ }
+ asyncLocal.Value = 0;
+ }, CancellationToken.None, TaskCreationOptions.None, new CustomTaskScheduler());
+
+ if (!completeBeforeOnCompleted)
+ {
+ Assert.False(vt.IsCompleted);
+ Assert.False(vt.IsCompletedSuccessfully);
+ c.Writer.TryWrite(true);
+ }
+
+ await continuationRan.Task;
+ Assert.True(vt.IsCompleted);
+ Assert.True(vt.IsCompletedSuccessfully);
+
+ Assert.Equal(continueOnCapturedContext != false, schedulerWasFlowed);
+ if (completeBeforeOnCompleted) // OnCompleted will simply queue using a mechanism that happens to flow
+ {
+ Assert.True(executionContextWasFlowed);
+ }
+ else
+ {
+ Assert.Equal(flowExecutionContext, executionContextWasFlowed);
+ }
+ });
+ }
+
+ [Fact]
+ public void ValueTask_GetResultWhenNotCompleted_Throws()
+ {
+ ValueTaskAwaiter<int> readVt = CreateChannel().Reader.ReadAsync().GetAwaiter();
+ Assert.Throws<InvalidOperationException>(() => readVt.GetResult());
+
+ ValueTaskAwaiter<bool> waitReadVt = CreateChannel().Reader.WaitToReadAsync().GetAwaiter();
+ Assert.Throws<InvalidOperationException>(() => waitReadVt.GetResult());
+
+ if (CreateFullChannel() != null)
+ {
+ ValueTaskAwaiter writeVt = CreateFullChannel().Writer.WriteAsync(42).GetAwaiter();
+ Assert.Throws<InvalidOperationException>(() => writeVt.GetResult());
+
+ ValueTaskAwaiter<bool> waitWriteVt = CreateFullChannel().Writer.WaitToWriteAsync().GetAwaiter();
+ Assert.Throws<InvalidOperationException>(() => waitWriteVt.GetResult());
+ }
+ }
+
+ [Fact]
+ public void ValueTask_MultipleContinuations_Throws()
+ {
+ ValueTaskAwaiter<int> readVt = CreateChannel().Reader.ReadAsync().GetAwaiter();
+ readVt.OnCompleted(() => { });
+ Assert.Throws<InvalidOperationException>(() => readVt.OnCompleted(() => { }));
+
+ ValueTaskAwaiter<bool> waitReadVt = CreateChannel().Reader.WaitToReadAsync().GetAwaiter();
+ waitReadVt.OnCompleted(() => { });
+ Assert.Throws<InvalidOperationException>(() => waitReadVt.OnCompleted(() => { }));
+
+ if (CreateFullChannel() != null)
+ {
+ ValueTaskAwaiter writeVt = CreateFullChannel().Writer.WriteAsync(42).GetAwaiter();
+ writeVt.OnCompleted(() => { });
+ Assert.Throws<InvalidOperationException>(() => writeVt.OnCompleted(() => { }));
+
+ ValueTaskAwaiter<bool> waitWriteVt = CreateFullChannel().Writer.WaitToWriteAsync().GetAwaiter();
+ waitWriteVt.OnCompleted(() => { });
+ Assert.Throws<InvalidOperationException>(() => waitWriteVt.OnCompleted(() => { }));
+ }
+ }
+
+ private sealed class CustomSynchronizationContext : SynchronizationContext
+ {
+ public override void Post(SendOrPostCallback d, object state)
+ {
+ ThreadPool.QueueUserWorkItem(delegate
+ {
+ SetSynchronizationContext(this);
+ try
+ {
+ d(state);
+ }
+ finally
+ {
+ SetSynchronizationContext(null);
+ }
+ }, null);
+ }
+ }
+
+ private sealed class CustomTaskScheduler : TaskScheduler
+ {
+ protected override void QueueTask(Task task) => ThreadPool.QueueUserWorkItem(_ => TryExecuteTask(task));
+ protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) => false;
+ protected override IEnumerable<Task> GetScheduledTasks() => null;
+ }
}
}
diff --git a/src/System.Threading.Channels/tests/ChannelTests.cs b/src/System.Threading.Channels/tests/ChannelTests.cs
index 26cf71448d..c9147750fc 100644
--- a/src/System.Threading.Channels/tests/ChannelTests.cs
+++ b/src/System.Threading.Channels/tests/ChannelTests.cs
@@ -50,9 +50,6 @@ namespace System.Threading.Channels.Tests
Assert.NotNull(Channel.CreateBounded<int>(1));
Assert.NotNull(Channel.CreateBounded<int>(new BoundedChannelOptions(1)));
- Assert.NotNull(Channel.CreateUnbuffered<int>());
- Assert.NotNull(Channel.CreateUnbuffered<int>(new UnbufferedChannelOptions()));
-
Assert.NotNull(Channel.CreateUnbounded<int>());
Assert.NotNull(Channel.CreateUnbounded<int>(new UnboundedChannelOptions()));
}
@@ -61,7 +58,6 @@ namespace System.Threading.Channels.Tests
public void Create_NullOptions_ThrowsArgumentException()
{
AssertExtensions.Throws<ArgumentNullException>("options", () => Channel.CreateUnbounded<int>(null));
- AssertExtensions.Throws<ArgumentNullException>("options", () => Channel.CreateUnbuffered<int>(null));
AssertExtensions.Throws<ArgumentNullException>("options", () => Channel.CreateBounded<int>(null));
}
@@ -96,7 +92,7 @@ namespace System.Threading.Channels.Tests
{
var c = new TestChannelWriter<int>(10);
Assert.False(c.TryComplete());
- Assert.Equal(TaskStatus.Canceled, c.WriteAsync(42, new CancellationToken(true)).Status);
+ Assert.Equal(TaskStatus.Canceled, c.WriteAsync(42, new CancellationToken(true)).AsTask().Status);
int count = 0;
try
@@ -121,9 +117,9 @@ namespace System.Threading.Channels.Tests
public async Task DefaultWriteAsync_CatchesTryWriteExceptions()
{
var w = new TryWriteThrowingWriter<int>();
- Task t = w.WriteAsync(42);
- Assert.Equal(TaskStatus.Faulted, t.Status);
- await Assert.ThrowsAsync<FormatException>(() => t);
+ ValueTask t = w.WriteAsync(42);
+ Assert.True(t.IsFaulted);
+ await Assert.ThrowsAsync<FormatException>(async () => await t);
}
[Fact]
@@ -135,6 +131,72 @@ namespace System.Threading.Channels.Tests
await Assert.ThrowsAsync<FieldAccessException>(() => t);
}
+ [Fact]
+ public async void TestBaseClassReadAsync()
+ {
+ WrapperChannel<int> channel = new WrapperChannel<int>(10);
+ ChannelReader<int> reader = channel.Reader;
+ ChannelWriter<int> writer = channel.Writer;
+
+ // 1- do it through synchronous TryRead()
+ writer.TryWrite(50);
+ Assert.Equal(50, await reader.ReadAsync());
+
+ // 2- do it through async
+ ValueTask<int> readTask = reader.ReadAsync();
+ writer.TryWrite(100);
+ Assert.Equal(100, await readTask);
+
+ // 3- use cancellation token
+ CancellationToken ct = new CancellationToken(true); // cancelled token
+ await Assert.ThrowsAsync<TaskCanceledException>(() => reader.ReadAsync(ct).AsTask());
+
+ // 4- throw during reading
+ readTask = reader.ReadAsync();
+ ((WrapperChannelReader<int>)reader).ForceThrowing = true;
+ writer.TryWrite(200);
+ await Assert.ThrowsAsync<InvalidOperationException>(() => readTask.AsTask());
+
+ // 5- close the channel while waiting reading
+ ((WrapperChannelReader<int>)reader).ForceThrowing = false;
+ Assert.Equal(200, await reader.ReadAsync());
+ readTask = reader.ReadAsync();
+ channel.Writer.TryComplete();
+ await Assert.ThrowsAsync<ChannelClosedException>(() => readTask.AsTask());
+ }
+
+ // This reader doesn't override ReadAsync to force using the base class ReadAsync method
+ private sealed class WrapperChannelReader<T> : ChannelReader<T>
+ {
+ private ChannelReader<T> _reader;
+ internal bool ForceThrowing { get; set; }
+
+ public WrapperChannelReader(Channel<T> channel) {_reader = channel.Reader; }
+
+ public override bool TryRead(out T item)
+ {
+ if (ForceThrowing)
+ throw new InvalidOperationException();
+
+ return _reader.TryRead(out item);
+ }
+
+ public override ValueTask<bool> WaitToReadAsync(CancellationToken cancellationToken)
+ {
+ return _reader.WaitToReadAsync(cancellationToken);
+ }
+ }
+
+ public class WrapperChannel<T> : Channel<T>
+ {
+ public WrapperChannel(int capacity)
+ {
+ Channel<T> channel = Channel.CreateBounded<T>(capacity);
+ Writer = channel.Writer;
+ Reader = new WrapperChannelReader<T>(channel);
+ }
+ }
+
private sealed class TestChannelWriter<T> : ChannelWriter<T>
{
private readonly Random _rand = new Random(42);
@@ -145,10 +207,10 @@ namespace System.Threading.Channels.Tests
public override bool TryWrite(T item) => _rand.Next(0, 2) == 0 && _count++ < _max; // succeed if we're under our limit, and add random failures
- public override Task<bool> WaitToWriteAsync(CancellationToken cancellationToken) =>
- _count >= _max ? Task.FromResult(false) :
- _rand.Next(0, 2) == 0 ? Task.Delay(1).ContinueWith(_ => true) : // randomly introduce delays
- Task.FromResult(true);
+ public override ValueTask<bool> WaitToWriteAsync(CancellationToken cancellationToken) =>
+ _count >= _max ? new ValueTask<bool>(Task.FromResult(false)) :
+ _rand.Next(0, 2) == 0 ? new ValueTask<bool>(Task.Delay(1).ContinueWith(_ => true)) : // randomly introduce delays
+ new ValueTask<bool>(Task.FromResult(true));
}
private sealed class TestChannelReader<T> : ChannelReader<T>
@@ -184,22 +246,22 @@ namespace System.Threading.Channels.Tests
return true;
}
- public override Task<bool> WaitToReadAsync(CancellationToken cancellationToken) =>
+ public override ValueTask<bool> WaitToReadAsync(CancellationToken cancellationToken) => new ValueTask<bool>(
_closed ? Task.FromResult(false) :
_rand.Next(0, 2) == 0 ? Task.Delay(1).ContinueWith(_ => true) : // randomly introduce delays
- Task.FromResult(true);
+ Task.FromResult(true));
}
private sealed class TryWriteThrowingWriter<T> : ChannelWriter<T>
{
public override bool TryWrite(T item) => throw new FormatException();
- public override Task<bool> WaitToWriteAsync(CancellationToken cancellationToken = default) => throw new InvalidDataException();
+ public override ValueTask<bool> WaitToWriteAsync(CancellationToken cancellationToken = default) => throw new InvalidDataException();
}
private sealed class TryReadThrowingReader<T> : ChannelReader<T>
{
public override bool TryRead(out T item) => throw new FieldAccessException();
- public override Task<bool> WaitToReadAsync(CancellationToken cancellationToken = default) => throw new DriveNotFoundException();
+ public override ValueTask<bool> WaitToReadAsync(CancellationToken cancellationToken = default) => throw new DriveNotFoundException();
}
private sealed class CanReadFalseStream : MemoryStream
diff --git a/src/System.Threading.Channels/tests/DebugAttributeTests.cs b/src/System.Threading.Channels/tests/DebugAttributeTests.cs
new file mode 100644
index 0000000000..34197aa1e3
--- /dev/null
+++ b/src/System.Threading.Channels/tests/DebugAttributeTests.cs
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Threading.Channels;
+using System.Collections.Generic;
+using Xunit;
+
+namespace System.Threading.Channels.Tests
+{
+ public class DebugAttributeTests
+ {
+ public static IEnumerable<object[]> TestData()
+ {
+ var c1 = Channel.CreateUnbounded<int>();
+ yield return new object[] { c1 };
+ yield return new object[] { c1.Reader };
+ yield return new object[] { c1.Writer };
+
+ var c2 = Channel.CreateUnbounded<int>(new UnboundedChannelOptions() { SingleReader = true });
+ yield return new object[] { c2 };
+ yield return new object[] { c2.Reader };
+ yield return new object[] { c2.Writer };
+
+ var c3 = Channel.CreateBounded<int>(10);
+ yield return new object[] { c3 };
+ yield return new object[] { c3.Reader };
+ yield return new object[] { c3.Writer };
+ }
+
+ [Theory]
+ [MemberData(nameof(TestData))]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot, "Cannot do DebuggerAttribute testing on UapAot: requires internal Reflection on framework types.")]
+ public void TestDebuggerDisplaysAndTypeProxies(object obj)
+ {
+ DebuggerAttributes.ValidateDebuggerDisplayReferences(obj);
+ DebuggerAttributes.ValidateDebuggerTypeProxyProperties(obj);
+ }
+
+ [Fact]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.UapAot, "Cannot do DebuggerAttribute testing on UapAot: requires internal Reflection on framework types.")]
+ public void TestDequeueClass()
+ {
+ var c = Channel.CreateBounded<int>(10);
+ DebuggerAttributes.ValidateDebuggerDisplayReferences(DebuggerAttributes.GetFieldValue(c, "_items"));
+ }
+
+ }
+}
diff --git a/src/System.Threading.Channels/tests/Performance/Perf.Channel.cs b/src/System.Threading.Channels/tests/Performance/Perf.Channel.cs
index 913054a244..78b7ab1f6c 100644
--- a/src/System.Threading.Channels/tests/Performance/Perf.Channel.cs
+++ b/src/System.Threading.Channels/tests/Performance/Perf.Channel.cs
@@ -7,28 +7,25 @@ using Microsoft.Xunit.Performance;
namespace System.Threading.Channels.Tests
{
- public sealed class Perf_UnboundedChannelTests : Perf_BufferingTests
+ public sealed class UnboundedChannelPerfTests : PerfTests
{
public override Channel<int> CreateChannel() => Channel.CreateUnbounded<int>();
}
- public sealed class Perf_UnboundedSpscChannelTests : Perf_BufferingTests
+ public sealed class SpscUnboundedChannelPerfTests : PerfTests
{
public override Channel<int> CreateChannel() => Channel.CreateUnbounded<int>(new UnboundedChannelOptions { SingleReader = true, SingleWriter = true });
}
- public sealed class Perf_BoundedChannelTests : Perf_BufferingTests
+ public sealed class BoundedChannelPerfTests : PerfTests
{
public override Channel<int> CreateChannel() => Channel.CreateBounded<int>(10);
}
- public sealed class Perf_UnbufferedChannelTests : Perf_Tests
+ public abstract class PerfTests
{
- public override Channel<int> CreateChannel() => Channel.CreateUnbuffered<int>();
- }
+ public abstract Channel<int> CreateChannel();
- public abstract class Perf_BufferingTests : Perf_Tests
- {
[Benchmark(InnerIterationCount = 1_000_000), MeasureGCAllocations]
public void TryWriteThenTryRead()
{
@@ -92,16 +89,12 @@ namespace System.Threading.Channels.Tests
}
}
}
- }
-
- public abstract class Perf_Tests
- {
- public abstract Channel<int> CreateChannel();
[Benchmark(InnerIterationCount = 1_000_000), MeasureGCAllocations]
- public async Task ConcurrentReadAsyncWriteAsync()
+ public async Task PingPong()
{
- Channel<int> channel = CreateChannel();
+ Channel<int> channel1 = CreateChannel();
+ Channel<int> channel2 = CreateChannel();
foreach (BenchmarkIteration iteration in Benchmark.Iterations)
{
@@ -111,17 +104,21 @@ namespace System.Threading.Channels.Tests
await Task.WhenAll(
Task.Run(async () =>
{
- ChannelReader<int> reader = channel.Reader;
+ ChannelReader<int> reader = channel1.Reader;
+ ChannelWriter<int> writer = channel2.Writer;
for (int i = 0; i < iters; i++)
{
+ await writer.WriteAsync(i);
await reader.ReadAsync();
}
}),
Task.Run(async () =>
{
- ChannelWriter<int> writer = channel.Writer;
+ ChannelWriter<int> writer = channel1.Writer;
+ ChannelReader<int> reader = channel2.Reader;
for (int i = 0; i < iters; i++)
{
+ await reader.ReadAsync();
await writer.WriteAsync(i);
}
}));
diff --git a/src/System.Threading.Channels/tests/Stress.cs b/src/System.Threading.Channels/tests/Stress.cs
new file mode 100644
index 0000000000..d2d80e5c2d
--- /dev/null
+++ b/src/System.Threading.Channels/tests/Stress.cs
@@ -0,0 +1,212 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using System;
+using Xunit;
+
+namespace System.Threading.Channels.Tests
+{
+ public class StressTests
+ {
+ public static IEnumerable<object[]> TestData()
+ {
+ foreach (var readDelegate in new Func<ChannelReader<int>, Task<bool>>[] { ReadSynchronous, ReadAsynchronous, ReadSyncAndAsync} )
+ foreach (var writeDelegate in new Func<ChannelWriter<int>, int, Task>[] { WriteSynchronous, WriteAsynchronous, WriteSyncAndAsync} )
+ foreach (bool singleReader in new [] {false, true})
+ foreach (bool singleWriter in new [] {false, true})
+ foreach (bool allowSynchronousContinuations in new [] {false, true})
+ {
+ Func<ChannelOptions, Channel<int>> unbounded = o => Channel.CreateUnbounded<int>((UnboundedChannelOptions)o);
+ yield return new object[] { unbounded, new UnboundedChannelOptions
+ {
+ SingleReader = singleReader,
+ SingleWriter = singleWriter,
+ AllowSynchronousContinuations = allowSynchronousContinuations
+ }, readDelegate, writeDelegate
+ };
+ }
+
+ foreach (var readDelegate in new Func<ChannelReader<int>, Task<bool>>[] { ReadSynchronous, ReadAsynchronous, ReadSyncAndAsync} )
+ foreach (var writeDelegate in new Func<ChannelWriter<int>, int, Task>[] { WriteSynchronous, WriteAsynchronous, WriteSyncAndAsync} )
+ foreach (BoundedChannelFullMode bco in Enum.GetValues(typeof(BoundedChannelFullMode)))
+ foreach (int capacity in new [] { 1, 1000 })
+ foreach (bool singleReader in new [] {false, true})
+ foreach (bool singleWriter in new [] {false, true})
+ foreach (bool allowSynchronousContinuations in new [] {false, true})
+ {
+ Func<ChannelOptions, Channel<int>> bounded = o => Channel.CreateBounded<int>((BoundedChannelOptions)o);
+ yield return new object[] { bounded, new BoundedChannelOptions(capacity)
+ {
+ SingleReader = singleReader,
+ SingleWriter = singleWriter,
+ AllowSynchronousContinuations = allowSynchronousContinuations,
+ FullMode = bco
+ }, readDelegate, writeDelegate
+ };
+ }
+ }
+
+ private static async Task<bool> ReadSynchronous(ChannelReader<int> reader)
+ {
+ while (!reader.TryRead(out int value))
+ {
+ if (!await reader.WaitToReadAsync())
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private static async Task<bool> ReadAsynchronous(ChannelReader<int> reader)
+ {
+ if (await reader.WaitToReadAsync())
+ {
+ await reader.ReadAsync();
+ return true;
+ }
+
+ return false;
+ }
+
+ private static async Task<bool> ReadSyncAndAsync(ChannelReader<int> reader)
+ {
+ if (!reader.TryRead(out int value))
+ {
+ if (await reader.WaitToReadAsync())
+ {
+ await reader.ReadAsync();
+ return true;
+ }
+ return false;
+ }
+
+ return true;
+ }
+
+ private static async Task WriteSynchronous(ChannelWriter<int> writer, int value)
+ {
+ while (!writer.TryWrite(value))
+ {
+ if (!await writer.WaitToWriteAsync())
+ {
+ break;
+ }
+ }
+ }
+
+ private static async Task WriteAsynchronous(ChannelWriter<int> writer, int value)
+ {
+ if (await writer.WaitToWriteAsync())
+ {
+ await writer.WriteAsync(value);
+ }
+ }
+
+ private static async Task WriteSyncAndAsync(ChannelWriter<int> writer, int value)
+ {
+ if (!writer.TryWrite(value))
+ {
+ if (await writer.WaitToWriteAsync())
+ {
+ await writer.WriteAsync(value);
+ }
+ }
+ }
+
+ const int MaxNumberToWriteToChannel = 400_000;
+ private static readonly int MaxTaskCounts = Math.Max(2, Environment.ProcessorCount);
+
+ [ConditionalTheory(typeof(TestEnvironment), nameof(TestEnvironment.IsStressModeEnabled))]
+ [MemberData(nameof(TestData))]
+ public void RunInStressMode(
+ Func<ChannelOptions, Channel<int>> channelCreator,
+ ChannelOptions options,
+ Func<ChannelReader<int>, Task<bool>> readDelegate,
+ Func<ChannelWriter<int>, int, Task> writeDelegate)
+ {
+ Channel<int> channel = channelCreator(options);
+ ChannelReader<int> reader = channel.Reader;
+ ChannelWriter<int> writer = channel.Writer;
+ BoundedChannelOptions boundedOptions = options as BoundedChannelOptions;
+ bool shouldReadAllWrittenValues = boundedOptions == null || boundedOptions.FullMode == BoundedChannelFullMode.Wait;
+
+ List<Task> taskList = new List<Task>();
+
+ int readerTasksCount;
+ int writerTasksCount;
+
+ if (options.SingleReader)
+ {
+ readerTasksCount = 1;
+ writerTasksCount = options.SingleWriter ? 1 : MaxTaskCounts - 1;
+ }
+ else if (options.SingleWriter)
+ {
+ writerTasksCount = 1;
+ readerTasksCount = MaxTaskCounts - 1;
+ }
+ else
+ {
+ readerTasksCount = MaxTaskCounts / 2;
+ writerTasksCount = MaxTaskCounts - readerTasksCount;
+ }
+
+ int readCount = 0;
+
+ for (int i=0; i < readerTasksCount; i++)
+ {
+ taskList.Add(Task.Run(async delegate
+ {
+ try
+ {
+ while (true)
+ {
+ if (!await readDelegate(reader))
+ break;
+ Interlocked.Increment(ref readCount);
+ }
+ }
+ catch (ChannelClosedException)
+ {
+ }
+ }));
+ }
+
+ int numberToWriteToQueue = -1;
+ int remainingWriters = writerTasksCount;
+
+ for (int i=0; i < writerTasksCount; i++)
+ {
+ taskList.Add(Task.Run(async delegate
+ {
+ int num = Interlocked.Increment(ref numberToWriteToQueue);
+ while (num < MaxNumberToWriteToChannel)
+ {
+ await writeDelegate(writer, num);
+ num = Interlocked.Increment(ref numberToWriteToQueue);
+ }
+
+ if (Interlocked.Decrement(ref remainingWriters) == 0)
+ writer.Complete();
+ }));
+ }
+
+ Task.WaitAll(taskList.ToArray());
+
+ if (shouldReadAllWrittenValues)
+ {
+ Assert.Equal(MaxNumberToWriteToChannel, readCount);
+ }
+ else
+ {
+ Assert.InRange(readCount, 0, MaxNumberToWriteToChannel);
+ }
+
+ }
+ }
+}
diff --git a/src/System.Threading.Channels/tests/System.Threading.Channels.Tests.csproj b/src/System.Threading.Channels/tests/System.Threading.Channels.Tests.csproj
index 33068d1346..20f56b57fa 100644
--- a/src/System.Threading.Channels/tests/System.Threading.Channels.Tests.csproj
+++ b/src/System.Threading.Channels/tests/System.Threading.Channels.Tests.csproj
@@ -2,7 +2,7 @@
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
- <ProjectGuid>{9E984EB2-827E-4029-9647-FB5F8B67C553}</ProjectGuid>
+ <ProjectGuid>{1AF01469-DBFC-4BA1-9331-8E39AA639FEE}</ProjectGuid>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Release|AnyCPU'" />
@@ -13,7 +13,8 @@
<Compile Include="ChannelTests.cs" />
<Compile Include="TestBase.cs" />
<Compile Include="UnboundedChannelTests.cs" />
- <Compile Include="UnbufferedChannelTests.cs" />
+ <Compile Include="Stress.cs" />
+ <Compile Include="DebugAttributeTests.cs" />
<Compile Include="$(CommonTestPath)\System\Diagnostics\DebuggerAttributes.cs">
<Link>Common\System\Diagnostics\DebuggerAttributes.cs</Link>
</Compile>
diff --git a/src/System.Threading.Channels/tests/TestBase.cs b/src/System.Threading.Channels/tests/TestBase.cs
index d3af1ba7eb..e41a613952 100644
--- a/src/System.Threading.Channels/tests/TestBase.cs
+++ b/src/System.Threading.Channels/tests/TestBase.cs
@@ -15,7 +15,11 @@ namespace System.Threading.Channels.Tests
{
Assert.Equal(TaskStatus.Canceled, task.Status);
OperationCanceledException oce = Assert.ThrowsAny<OperationCanceledException>(() => task.GetAwaiter().GetResult());
- Assert.Equal(token, oce.CancellationToken);
+ if (PlatformDetection.IsNetCore)
+ {
+ // Earlier netstandard versions didn't have the APIs to always make this possible.
+ Assert.Equal(token, oce.CancellationToken);
+ }
}
protected async Task AssertCanceled(Task task, CancellationToken token)
@@ -24,6 +28,8 @@ namespace System.Threading.Channels.Tests
AssertSynchronouslyCanceled(task, token);
}
+ protected void AssertSynchronousSuccess<T>(ValueTask<T> task) => Assert.True(task.IsCompletedSuccessfully);
+ protected void AssertSynchronousSuccess(ValueTask task) => Assert.True(task.IsCompletedSuccessfully);
protected void AssertSynchronousSuccess(Task task) => Assert.Equal(TaskStatus.RanToCompletion, task.Status);
protected void AssertSynchronousTrue(Task<bool> task)
@@ -32,6 +38,12 @@ namespace System.Threading.Channels.Tests
Assert.True(task.Result);
}
+ protected void AssertSynchronousTrue(ValueTask<bool> task)
+ {
+ AssertSynchronousSuccess(task);
+ Assert.True(task.Result);
+ }
+
internal sealed class DelegateObserver<T> : IObserver<T>
{
public Action<T> OnNextDelegate = null;
diff --git a/src/System.Threading.Channels/tests/UnboundedChannelTests.cs b/src/System.Threading.Channels/tests/UnboundedChannelTests.cs
index 71d8e91f43..dec1e50f3e 100644
--- a/src/System.Threading.Channels/tests/UnboundedChannelTests.cs
+++ b/src/System.Threading.Channels/tests/UnboundedChannelTests.cs
@@ -10,14 +10,13 @@ namespace System.Threading.Channels.Tests
{
public abstract class UnboundedChannelTests : ChannelTestBase
{
- protected abstract bool AllowSynchronousContinuations { get; }
- protected override Channel<int> CreateChannel() => Channel.CreateUnbounded<int>(
+ protected override Channel<T> CreateChannel<T>() => Channel.CreateUnbounded<T>(
new UnboundedChannelOptions
{
SingleReader = RequiresSingleReader,
AllowSynchronousContinuations = AllowSynchronousContinuations
});
- protected override Channel<int> CreateFullChannel() => null;
+ protected override Channel<T> CreateFullChannel<T>() => null;
[Fact]
public async Task Complete_BeforeEmpty_NoWaiters_TriggersCompletion()
@@ -107,12 +106,12 @@ namespace System.Threading.Channels.Tests
Channel<int> c = CreateChannel();
int expectedId = Environment.CurrentManagedThreadId;
- Task r = c.Reader.WaitToReadAsync().ContinueWith(_ =>
+ Task r = c.Reader.WaitToReadAsync().AsTask().ContinueWith(_ =>
{
Assert.Equal(AllowSynchronousContinuations, expectedId == Environment.CurrentManagedThreadId);
}, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
- Assert.Equal(TaskStatus.RanToCompletion, c.Writer.WriteAsync(42).Status);
+ Assert.True(c.Writer.WriteAsync(42).IsCompletedSuccessfully);
((IAsyncResult)r).AsyncWaitHandle.WaitOne(); // avoid inlining the continuation
r.GetAwaiter().GetResult();
}
@@ -155,14 +154,25 @@ namespace System.Threading.Channels.Tests
public async Task MultipleWaiters_CancelsPreviousWaiter()
{
Channel<int> c = CreateChannel();
- Task<bool> t1 = c.Reader.WaitToReadAsync();
- Task<bool> t2 = c.Reader.WaitToReadAsync();
- await Assert.ThrowsAnyAsync<OperationCanceledException>(() => t1);
+ ValueTask<bool> t1 = c.Reader.WaitToReadAsync();
+ ValueTask<bool> t2 = c.Reader.WaitToReadAsync();
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await t1);
Assert.True(c.Writer.TryWrite(42));
Assert.True(await t2);
}
[Fact]
+ public async Task MultipleReaders_CancelsPreviousReader()
+ {
+ Channel<int> c = CreateChannel();
+ ValueTask<int> t1 = c.Reader.ReadAsync();
+ ValueTask<int> t2 = c.Reader.ReadAsync();
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await t1);
+ Assert.True(c.Writer.TryWrite(42));
+ Assert.Equal(42, await t2);
+ }
+
+ [Fact]
public void Stress_TryWrite_TryRead()
{
const int NumItems = 3000000;
diff --git a/src/System.Threading.Channels/tests/UnbufferedChannelTests.cs b/src/System.Threading.Channels/tests/UnbufferedChannelTests.cs
deleted file mode 100644
index 7ef42056ac..0000000000
--- a/src/System.Threading.Channels/tests/UnbufferedChannelTests.cs
+++ /dev/null
@@ -1,95 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Linq;
-using System.Threading.Tasks;
-using Xunit;
-
-namespace System.Threading.Channels.Tests
-{
- public class UnbufferedChannelTests : ChannelTestBase
- {
- protected override Channel<int> CreateChannel() => Channel.CreateUnbuffered<int>();
- protected override Channel<int> CreateFullChannel() => CreateChannel();
- protected override bool BuffersItems => false;
-
- [Fact]
- public async Task Complete_BeforeEmpty_WaitingWriters_TriggersCompletion()
- {
- Channel<int> c = CreateChannel();
- Task write1 = c.Writer.WriteAsync(42);
- Task write2 = c.Writer.WriteAsync(43);
- c.Writer.Complete();
- await c.Reader.Completion;
- await Assert.ThrowsAnyAsync<InvalidOperationException>(() => write1);
- await Assert.ThrowsAnyAsync<InvalidOperationException>(() => write2);
- }
-
- [Fact]
- public void TryReadWrite_NoPartner_Fail()
- {
- Channel<int> c = CreateChannel();
- Assert.False(c.Writer.TryWrite(42));
- Assert.False(c.Reader.TryRead(out int result));
- Assert.Equal(result, 0);
- }
-
- [Fact]
- public void TryRead_WriteAsync_Success()
- {
- Channel<int> c = CreateChannel();
- Task w = c.Writer.WriteAsync(42);
- Assert.False(w.IsCompleted);
- Assert.True(c.Reader.TryRead(out int result));
- Assert.Equal(42, result);
- }
-
- [Theory]
- [InlineData(false)]
- [InlineData(true)]
- public async Task Read_MultipleUnpartneredWrites_CancelSome_ReadSucceeds(bool useReadAsync)
- {
- Channel<int> c = CreateChannel();
- var cts = new CancellationTokenSource();
-
- Task[] cancelableWrites = (from i in Enumerable.Range(0, 10) select c.Writer.WriteAsync(42, cts.Token)).ToArray();
- Assert.All(cancelableWrites, cw => Assert.Equal(TaskStatus.WaitingForActivation, cw.Status));
-
- Task w = c.Writer.WriteAsync(84);
-
- cts.Cancel();
- foreach (Task t in cancelableWrites)
- {
- await AssertCanceled(t, cts.Token);
- }
-
- if (useReadAsync)
- {
- Assert.True(c.Reader.TryRead(out int result));
- Assert.Equal(84, result);
- }
- else
- {
- Assert.Equal(84, await c.Reader.ReadAsync());
- }
- }
-
- [Fact]
- public async Task Cancel_PartneredWrite_Success()
- {
- Channel<int> c = CreateChannel();
- var cts = new CancellationTokenSource();
-
- Task w = c.Writer.WriteAsync(42, cts.Token);
- Assert.False(w.IsCompleted);
-
- ValueTask<int> r = c.Reader.ReadAsync();
- Assert.True(r.IsCompletedSuccessfully);
-
- cts.Cancel();
- await w; // no throw
- }
-
- }
-}
diff --git a/src/System.Threading.Tasks.Dataflow/pkg/System.Threading.Tasks.Dataflow.pkgproj b/src/System.Threading.Tasks.Dataflow/pkg/System.Threading.Tasks.Dataflow.pkgproj
index e62f1b9c18..cd56866eec 100644
--- a/src/System.Threading.Tasks.Dataflow/pkg/System.Threading.Tasks.Dataflow.pkgproj
+++ b/src/System.Threading.Tasks.Dataflow/pkg/System.Threading.Tasks.Dataflow.pkgproj
@@ -1,10 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
- <PropertyGroup>
- <!-- we need to be supported on pre-nuget-3 platforms (Dev12, Dev11, etc) -->
- <MinClientVersion>2.8.6</MinClientVersion>
- </PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\src\System.Threading.Tasks.Dataflow.csproj">
<SupportedFramework>net45;netcore45;wp8;wpa81;netcoreapp1.0;$(AllXamarinFrameworks)</SupportedFramework>
@@ -12,20 +8,12 @@
<!-- Since UAP and .NETCoreApp are package based we still want to enable
OOBing libraries that happen to overlap with their framework package.
- This avoids us having to lock the API in our NuGet packages just
- to match what shipped inbox: since we can provide a new library
+ This avoids us having to lock the API in our NuGet packages just
+ to match what shipped inbox: since we can provide a new library
we can update it to add API without raising the netstandard version. -->
<ValidatePackageSuppression Include="TreatAsOutOfBox">
<Value>.NETCoreApp;UAP</Value>
</ValidatePackageSuppression>
-
- <!--
- Include empty dependency group for net45 and higher to avoid unncessary package dependencies
- because all the dependencies are known to be inbox already.
- -->
- <Dependency Include="_._">
- <TargetFramework>net45</TargetFramework>
- </Dependency>
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.Threading.Tasks.Extensions/System.Threading.Tasks.Extensions.sln b/src/System.Threading.Tasks.Extensions/System.Threading.Tasks.Extensions.sln
index a16e156cad..913593de27 100644
--- a/src/System.Threading.Tasks.Extensions/System.Threading.Tasks.Extensions.sln
+++ b/src/System.Threading.Tasks.Extensions/System.Threading.Tasks.Extensions.sln
@@ -7,6 +7,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Threading.Tasks.Exte
{DE90AD0B-649D-4062-B8D9-9658DE140532} = {DE90AD0B-649D-4062-B8D9-9658DE140532}
EndProjectSection
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Threading.Tasks.Extensions.Performance.Tests", "tests\Performance\System.Threading.Tasks.Extensions.Performance.Tests.csproj", "{77E38A48-61ED-4D79-9136-D88617EE3558}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DE90AD0B-649D-4062-B8D9-9658DE140532} = {DE90AD0B-649D-4062-B8D9-9658DE140532}
+ EndProjectSection
+EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Threading.Tasks.Extensions", "src\System.Threading.Tasks.Extensions.csproj", "{DE90AD0B-649D-4062-B8D9-9658DE140532}"
ProjectSection(ProjectDependencies) = postProject
{0DF7FA9A-E7D3-4CEF-862B-A37F5BBBB54C} = {0DF7FA9A-E7D3-4CEF-862B-A37F5BBBB54C}
@@ -30,6 +35,10 @@ Global
{275B161B-D525-48A0-B1DE-344273AB9A99}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
{275B161B-D525-48A0-B1DE-344273AB9A99}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
{275B161B-D525-48A0-B1DE-344273AB9A99}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
+ {77E38A48-61ED-4D79-9136-D88617EE3558}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
+ {77E38A48-61ED-4D79-9136-D88617EE3558}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
+ {77E38A48-61ED-4D79-9136-D88617EE3558}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
+ {77E38A48-61ED-4D79-9136-D88617EE3558}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
{DE90AD0B-649D-4062-B8D9-9658DE140532}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU
{DE90AD0B-649D-4062-B8D9-9658DE140532}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
{DE90AD0B-649D-4062-B8D9-9658DE140532}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
@@ -44,6 +53,7 @@ Global
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{275B161B-D525-48A0-B1DE-344273AB9A99} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
+ {77E38A48-61ED-4D79-9136-D88617EE3558} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
{DE90AD0B-649D-4062-B8D9-9658DE140532} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD}
{0DF7FA9A-E7D3-4CEF-862B-A37F5BBBB54C} = {2E666815-2EDB-464B-9DF6-380BF4789AD4}
EndGlobalSection
diff --git a/src/System.Threading.Tasks.Extensions/dir.props b/src/System.Threading.Tasks.Extensions/dir.props
index 69547aae1d..fd2614ee74 100644
--- a/src/System.Threading.Tasks.Extensions/dir.props
+++ b/src/System.Threading.Tasks.Extensions/dir.props
@@ -2,7 +2,7 @@
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\dir.props" />
<PropertyGroup>
- <AssemblyVersion>4.1.2.0</AssemblyVersion>
+ <AssemblyVersion>4.2.0.0</AssemblyVersion>
<AssemblyKey>Open</AssemblyKey>
<IsNETCoreApp>true</IsNETCoreApp>
<IsUAP>true</IsUAP>
diff --git a/src/System.Threading.Tasks.Extensions/pkg/System.Threading.Tasks.Extensions.pkgproj b/src/System.Threading.Tasks.Extensions/pkg/System.Threading.Tasks.Extensions.pkgproj
index be069b8134..1a84c5f2a8 100644
--- a/src/System.Threading.Tasks.Extensions/pkg/System.Threading.Tasks.Extensions.pkgproj
+++ b/src/System.Threading.Tasks.Extensions/pkg/System.Threading.Tasks.Extensions.pkgproj
@@ -11,7 +11,7 @@
</ProjectReference>
<ProjectReference Include="..\src\System.Threading.Tasks.Extensions.csproj" />
- <InboxOnTargetFramework Include="netcoreapp2.0" />
+ <InboxOnTargetFramework Include="netcoreapp2.1" />
<InboxOnTargetFramework Include="$(UAPvNextTFM)" />
<!-- this package is part of the implementation closure of NETStandard.Library
@@ -19,4 +19,4 @@
<SuppressMetaPackage Include="NETStandard.Library" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Threading.Tasks.Extensions/ref/System.Threading.Tasks.Extensions.cs b/src/System.Threading.Tasks.Extensions/ref/System.Threading.Tasks.Extensions.cs
index 2b8bd30e91..cbb77814f7 100644
--- a/src/System.Threading.Tasks.Extensions/ref/System.Threading.Tasks.Extensions.cs
+++ b/src/System.Threading.Tasks.Extensions/ref/System.Threading.Tasks.Extensions.cs
@@ -13,6 +13,18 @@ namespace System.Runtime.CompilerServices
public AsyncMethodBuilderAttribute(System.Type builderType) { }
public System.Type BuilderType { get { throw null; } }
}
+ public partial struct AsyncValueTaskMethodBuilder
+ {
+ private object _dummy;
+ public System.Threading.Tasks.ValueTask Task { get { throw null; } }
+ public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : System.Runtime.CompilerServices.INotifyCompletion where TStateMachine : System.Runtime.CompilerServices.IAsyncStateMachine { }
+ public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : System.Runtime.CompilerServices.ICriticalNotifyCompletion where TStateMachine : System.Runtime.CompilerServices.IAsyncStateMachine { }
+ public static System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder Create() { throw null; }
+ public void SetException(System.Exception exception) { }
+ public void SetResult() { }
+ public void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine stateMachine) { }
+ public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : System.Runtime.CompilerServices.IAsyncStateMachine { }
+ }
public partial struct AsyncValueTaskMethodBuilder<TResult>
{
private TResult _result;
@@ -25,22 +37,43 @@ namespace System.Runtime.CompilerServices
public void SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine stateMachine) { }
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : System.Runtime.CompilerServices.IAsyncStateMachine { }
}
+ public readonly partial struct ConfiguredValueTaskAwaitable
+ {
+ private readonly object _dummy;
+ public System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable.ConfiguredValueTaskAwaiter GetAwaiter() { throw null; }
+ public readonly partial struct ConfiguredValueTaskAwaiter : System.Runtime.CompilerServices.ICriticalNotifyCompletion, System.Runtime.CompilerServices.INotifyCompletion
+ {
+ private readonly object _dummy;
+ public bool IsCompleted { get { throw null; } }
+ public void GetResult() { }
+ public void OnCompleted(System.Action continuation) { }
+ public void UnsafeOnCompleted(System.Action continuation) { }
+ }
+ }
public readonly partial struct ConfiguredValueTaskAwaitable<TResult>
{
private readonly object _dummy;
public System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable<TResult>.ConfiguredValueTaskAwaiter GetAwaiter() { throw null; }
- public partial struct ConfiguredValueTaskAwaiter : System.Runtime.CompilerServices.ICriticalNotifyCompletion, System.Runtime.CompilerServices.INotifyCompletion
+ public readonly partial struct ConfiguredValueTaskAwaiter : System.Runtime.CompilerServices.ICriticalNotifyCompletion, System.Runtime.CompilerServices.INotifyCompletion
{
- private object _dummy;
+ private readonly object _dummy;
public bool IsCompleted { get { throw null; } }
public TResult GetResult() { throw null; }
public void OnCompleted(System.Action continuation) { }
public void UnsafeOnCompleted(System.Action continuation) { }
}
}
- public partial struct ValueTaskAwaiter<TResult> : System.Runtime.CompilerServices.ICriticalNotifyCompletion, System.Runtime.CompilerServices.INotifyCompletion
+ public readonly partial struct ValueTaskAwaiter : System.Runtime.CompilerServices.ICriticalNotifyCompletion, System.Runtime.CompilerServices.INotifyCompletion
{
- private object _dummy;
+ private readonly object _dummy;
+ public bool IsCompleted { get { throw null; } }
+ public void GetResult() { }
+ public void OnCompleted(System.Action continuation) { }
+ public void UnsafeOnCompleted(System.Action continuation) { }
+ }
+ public readonly partial struct ValueTaskAwaiter<TResult> : System.Runtime.CompilerServices.ICriticalNotifyCompletion, System.Runtime.CompilerServices.INotifyCompletion
+ {
+ private readonly object _dummy;
public bool IsCompleted { get { throw null; } }
public TResult GetResult() { throw null; }
public void OnCompleted(System.Action continuation) { }
@@ -49,11 +82,32 @@ namespace System.Runtime.CompilerServices
}
namespace System.Threading.Tasks
{
+ [System.Runtime.CompilerServices.AsyncMethodBuilderAttribute(typeof(System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder))]
+ public readonly partial struct ValueTask : System.IEquatable<System.Threading.Tasks.ValueTask>
+ {
+ internal readonly object _dummy;
+ public ValueTask(System.Threading.Tasks.Task task) { throw null; }
+ public ValueTask(System.Threading.Tasks.Sources.IValueTaskSource source, short token) { throw null; }
+ public bool IsCanceled { get { throw null; } }
+ public bool IsCompleted { get { throw null; } }
+ public bool IsCompletedSuccessfully { get { throw null; } }
+ public bool IsFaulted { get { throw null; } }
+ public System.Threading.Tasks.Task AsTask() { throw null; }
+ public System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable ConfigureAwait(bool continueOnCapturedContext) { throw null; }
+ public override bool Equals(object obj) { throw null; }
+ public bool Equals(System.Threading.Tasks.ValueTask other) { throw null; }
+ public System.Runtime.CompilerServices.ValueTaskAwaiter GetAwaiter() { throw null; }
+ public override int GetHashCode() { throw null; }
+ public System.Threading.Tasks.ValueTask Preserve() { throw null; }
+ public static bool operator ==(System.Threading.Tasks.ValueTask left, System.Threading.Tasks.ValueTask right) { throw null; }
+ public static bool operator !=(System.Threading.Tasks.ValueTask left, System.Threading.Tasks.ValueTask right) { throw null; }
+ }
[System.Runtime.CompilerServices.AsyncMethodBuilderAttribute(typeof(System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder<>))]
public readonly partial struct ValueTask<TResult> : System.IEquatable<System.Threading.Tasks.ValueTask<TResult>>
{
internal readonly TResult _result;
public ValueTask(System.Threading.Tasks.Task<TResult> task) { throw null; }
+ public ValueTask(System.Threading.Tasks.Sources.IValueTaskSource<TResult> source, short token) { throw null; }
public ValueTask(TResult result) { throw null; }
public bool IsCanceled { get { throw null; } }
public bool IsCompleted { get { throw null; } }
@@ -62,14 +116,42 @@ namespace System.Threading.Tasks
public TResult Result { get { throw null; } }
public System.Threading.Tasks.Task<TResult> AsTask() { throw null; }
public System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable<TResult> ConfigureAwait(bool continueOnCapturedContext) { throw null; }
- [System.ComponentModel.EditorBrowsableAttribute((System.ComponentModel.EditorBrowsableState)(1))]
- public static System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder<TResult> CreateAsyncMethodBuilder() { throw null; }
public override bool Equals(object obj) { throw null; }
public bool Equals(System.Threading.Tasks.ValueTask<TResult> other) { throw null; }
public System.Runtime.CompilerServices.ValueTaskAwaiter<TResult> GetAwaiter() { throw null; }
public override int GetHashCode() { throw null; }
+ public System.Threading.Tasks.ValueTask<TResult> Preserve() { throw null; }
public static bool operator ==(System.Threading.Tasks.ValueTask<TResult> left, System.Threading.Tasks.ValueTask<TResult> right) { throw null; }
public static bool operator !=(System.Threading.Tasks.ValueTask<TResult> left, System.Threading.Tasks.ValueTask<TResult> right) { throw null; }
public override string ToString() { throw null; }
}
}
+namespace System.Threading.Tasks.Sources
+{
+ [System.Flags]
+ public enum ValueTaskSourceOnCompletedFlags
+ {
+ None,
+ UseSchedulingContext = 0x1,
+ FlowExecutionContext = 0x2,
+ }
+ public enum ValueTaskSourceStatus
+ {
+ Pending = 0,
+ Succeeded = 1,
+ Faulted = 2,
+ Canceled = 3
+ }
+ public interface IValueTaskSource
+ {
+ System.Threading.Tasks.Sources.ValueTaskSourceStatus GetStatus(short token);
+ void OnCompleted(System.Action<object> continuation, object state, short token, System.Threading.Tasks.Sources.ValueTaskSourceOnCompletedFlags flags);
+ void GetResult(short token);
+ }
+ public interface IValueTaskSource<out TResult>
+ {
+ System.Threading.Tasks.Sources.ValueTaskSourceStatus GetStatus(short token);
+ void OnCompleted(System.Action<object> continuation, object state, short token, System.Threading.Tasks.Sources.ValueTaskSourceOnCompletedFlags flags);
+ TResult GetResult(short token);
+ }
+}
diff --git a/src/System.Threading.Tasks.Extensions/ref/System.Threading.Tasks.Extensions.csproj b/src/System.Threading.Tasks.Extensions/ref/System.Threading.Tasks.Extensions.csproj
index 063e479478..767f1de2aa 100644
--- a/src/System.Threading.Tasks.Extensions/ref/System.Threading.Tasks.Extensions.csproj
+++ b/src/System.Threading.Tasks.Extensions/ref/System.Threading.Tasks.Extensions.csproj
@@ -4,12 +4,6 @@
<PropertyGroup>
<ProjectGuid>{0DF7FA9A-E7D3-4CEF-862B-A37F5BBBB54C}</ProjectGuid>
<IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'netcoreapp' Or '$(TargetGroup)' == 'uap'">true</IsPartialFacadeAssembly>
- <!--
- Netstandard assembly version is frozen and thus cannot adde any more APIs to it because
- the types have been moved inbox and type-forwarded into CoreLib. The only way to add more
- APIs is to add them directly to the particular platform.
- -->
- <AssemblyVersion Condition="$(TargetGroup.StartsWith('netstandard'))">4.1.1.0</AssemblyVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
diff --git a/src/System.Threading.Tasks.Extensions/src/System.Threading.Tasks.Extensions.csproj b/src/System.Threading.Tasks.Extensions/src/System.Threading.Tasks.Extensions.csproj
index 0bc93927d5..d6986d894c 100644
--- a/src/System.Threading.Tasks.Extensions/src/System.Threading.Tasks.Extensions.csproj
+++ b/src/System.Threading.Tasks.Extensions/src/System.Threading.Tasks.Extensions.csproj
@@ -6,8 +6,8 @@
<DocumentationFile>$(OutputPath)$(MSBuildProjectName).xml</DocumentationFile>
<PackageTargetFramework Condition="'$(TargetGroup)' == 'netstandard1.0'">netstandard1.0;portable-net45+win8+wp8+wpa81</PackageTargetFramework>
<IsPartialFacadeAssembly Condition="'$(TargetGroup)' != 'netstandard' and '$(TargetGroup)' != 'netstandard1.0'">true</IsPartialFacadeAssembly>
+ <DefineConstants Condition="'$(IsPartialFacadeAssembly)' != 'true'">$(DefineConstants);netstandard</DefineConstants>
<ExcludeResourcesImport Condition="'$(IsPartialFacadeAssembly)'=='true'">true</ExcludeResourcesImport>
- <AssemblyVersion Condition="$(TargetGroup.StartsWith('netstandard'))">4.1.1.0</AssemblyVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Unix-Release|AnyCPU'" />
@@ -23,15 +23,34 @@
<ReferenceFromRuntime Include="System.Private.CoreLib" />
</ItemGroup>
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true'">
- <Compile Include="System\Runtime\CompilerServices\AsyncMethodBuilderAttribute.cs" />
- <Compile Include="System\Runtime\CompilerServices\AsyncValueTaskMethodBuilder.cs" />
- <Compile Include="System\Runtime\CompilerServices\ConfiguredValueTaskAwaitable.cs" />
- <Compile Include="System\Runtime\CompilerServices\ValueTaskAwaiter.cs" />
- <Compile Include="System\Threading\Tasks\ValueTask.cs" />
+ <Compile Include="System\ThrowHelper.cs" />
+ <Compile Include="$(CommonPath)\CoreLib\System\Diagnostics\StackTraceHiddenAttribute.cs">
+ <Link>Common\CoreLib\System\Diagnostics\StackTraceHiddenAttribute.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\CoreLib\System\Runtime\CompilerServices\AsyncMethodBuilderAttribute.cs">
+ <Link>Common\CoreLib\System\Runtime\CompilerServices\AsyncMethodBuilderAttribute.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\CoreLib\System\Runtime\CompilerServices\AsyncValueTaskMethodBuilder.cs">
+ <Link>Common\CoreLib\System\Runtime\CompilerServices\AsyncValueTaskMethodBuilder.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\CoreLib\System\Runtime\CompilerServices\ConfiguredValueTaskAwaitable.cs">
+ <Link>Common\CoreLib\System\Runtime\CompilerServices\ConfiguredValueTaskAwaitable.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\CoreLib\System\Runtime\CompilerServices\ValueTaskAwaiter.cs">
+ <Link>Common\CoreLib\System\Runtime\CompilerServices\ValueTaskAwaiter.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\CoreLib\System\Threading\Tasks\ValueTask.cs">
+ <Link>Common\CoreLib\System\Threading\Tasks\ValueTask.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\CoreLib\System\Threading\Tasks\Sources\IValueTaskSource.cs">
+ <Link>Common\CoreLib\System\Threading\Tasks\Sources\IValueTaskSource.cs</Link>
+ </Compile>
+
<Reference Include="System.Collections" />
<Reference Include="System.Diagnostics.Debug" />
<Reference Include="System.Runtime" />
+ <Reference Include="System.Runtime.CompilerServices.Unsafe" />
<Reference Include="System.Threading.Tasks" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/AsyncMethodBuilderAttribute.cs b/src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/AsyncMethodBuilderAttribute.cs
deleted file mode 100644
index 688a3a01ba..0000000000
--- a/src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/AsyncMethodBuilderAttribute.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-namespace System.Runtime.CompilerServices
-{
- /// <summary>
- /// Indicates the type of the async method builder that should be used by a language compiler to
- /// build the attributed type when used as the return type of an async method.
- /// </summary>
- [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Delegate | AttributeTargets.Enum, Inherited = false, AllowMultiple = false)]
- public sealed class AsyncMethodBuilderAttribute : Attribute
- {
- /// <summary>Initializes the <see cref="AsyncMethodBuilderAttribute"/>.</summary>
- /// <param name="builderType">The <see cref="Type"/> of the associated builder.</param>
- public AsyncMethodBuilderAttribute(Type builderType) => BuilderType = builderType;
-
- /// <summary>Gets the <see cref="Type"/> of the associated builder.</summary>
- public Type BuilderType { get; }
- }
-}
diff --git a/src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs b/src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs
deleted file mode 100644
index 8cbcdc562f..0000000000
--- a/src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/AsyncValueTaskMethodBuilder.cs
+++ /dev/null
@@ -1,102 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Runtime.InteropServices;
-using System.Security;
-using System.Threading.Tasks;
-
-namespace System.Runtime.CompilerServices
-{
- /// <summary>Represents a builder for asynchronous methods that returns a <see cref="ValueTask{TResult}"/>.</summary>
- /// <typeparam name="TResult">The type of the result.</typeparam>
- [StructLayout(LayoutKind.Auto)]
- public struct AsyncValueTaskMethodBuilder<TResult>
- {
- /// <summary>The <see cref="AsyncTaskMethodBuilder{TResult}"/> to which most operations are delegated.</summary>
- private AsyncTaskMethodBuilder<TResult> _methodBuilder;
- /// <summary>The result for this builder, if it's completed before any awaits occur.</summary>
- private TResult _result;
- /// <summary>true if <see cref="_result"/> contains the synchronous result for the async method; otherwise, false.</summary>
- private bool _haveResult;
- /// <summary>true if the builder should be used for setting/getting the result; otherwise, false.</summary>
- private bool _useBuilder;
-
- /// <summary>Creates an instance of the <see cref="AsyncValueTaskMethodBuilder{TResult}"/> struct.</summary>
- /// <returns>The initialized instance.</returns>
- public static AsyncValueTaskMethodBuilder<TResult> Create() =>
- new AsyncValueTaskMethodBuilder<TResult>() { _methodBuilder = AsyncTaskMethodBuilder<TResult>.Create() };
-
- /// <summary>Begins running the builder with the associated state machine.</summary>
- /// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
- /// <param name="stateMachine">The state machine instance, passed by reference.</param>
- public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine =>
- _methodBuilder.Start(ref stateMachine); // will provide the right ExecutionContext semantics
-
- /// <summary>Associates the builder with the specified state machine.</summary>
- /// <param name="stateMachine">The state machine instance to associate with the builder.</param>
- public void SetStateMachine(IAsyncStateMachine stateMachine) => _methodBuilder.SetStateMachine(stateMachine);
-
- /// <summary>Marks the task as successfully completed.</summary>
- /// <param name="result">The result to use to complete the task.</param>
- public void SetResult(TResult result)
- {
- if (_useBuilder)
- {
- _methodBuilder.SetResult(result);
- }
- else
- {
- _result = result;
- _haveResult = true;
- }
- }
-
- /// <summary>Marks the task as failed and binds the specified exception to the task.</summary>
- /// <param name="exception">The exception to bind to the task.</param>
- public void SetException(Exception exception) => _methodBuilder.SetException(exception);
-
- /// <summary>Gets the task for this builder.</summary>
- public ValueTask<TResult> Task
- {
- get
- {
- if (_haveResult)
- {
- return new ValueTask<TResult>(_result);
- }
- else
- {
- _useBuilder = true;
- return new ValueTask<TResult>(_methodBuilder.Task);
- }
- }
- }
-
- /// <summary>Schedules the state machine to proceed to the next action when the specified awaiter completes.</summary>
- /// <typeparam name="TAwaiter">The type of the awaiter.</typeparam>
- /// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
- /// <param name="awaiter">the awaiter</param>
- /// <param name="stateMachine">The state machine.</param>
- public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
- where TAwaiter : INotifyCompletion
- where TStateMachine : IAsyncStateMachine
- {
- _useBuilder = true;
- _methodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine);
- }
-
- /// <summary>Schedules the state machine to proceed to the next action when the specified awaiter completes.</summary>
- /// <typeparam name="TAwaiter">The type of the awaiter.</typeparam>
- /// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
- /// <param name="awaiter">the awaiter</param>
- /// <param name="stateMachine">The state machine.</param>
- public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
- where TAwaiter : ICriticalNotifyCompletion
- where TStateMachine : IAsyncStateMachine
- {
- _useBuilder = true;
- _methodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
- }
- }
-}
diff --git a/src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs b/src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs
deleted file mode 100644
index e0b92e5de1..0000000000
--- a/src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Runtime.InteropServices;
-using System.Threading.Tasks;
-
-namespace System.Runtime.CompilerServices
-{
- /// <summary>Provides an awaitable type that enables configured awaits on a <see cref="ValueTask{TResult}"/>.</summary>
- /// <typeparam name="TResult">The type of the result produced.</typeparam>
- [StructLayout(LayoutKind.Auto)]
- public readonly struct ConfiguredValueTaskAwaitable<TResult>
- {
- /// <summary>The wrapped <see cref="ValueTask{TResult}"/>.</summary>
- private readonly ValueTask<TResult> _value;
- /// <summary>true to attempt to marshal the continuation back to the original context captured; otherwise, false.</summary>
- private readonly bool _continueOnCapturedContext;
-
- /// <summary>Initializes the awaitable.</summary>
- /// <param name="value">The wrapped <see cref="ValueTask{TResult}"/>.</param>
- /// <param name="continueOnCapturedContext">
- /// true to attempt to marshal the continuation back to the original synchronization context captured; otherwise, false.
- /// </param>
- internal ConfiguredValueTaskAwaitable(ValueTask<TResult> value, bool continueOnCapturedContext)
- {
- _value = value;
- _continueOnCapturedContext = continueOnCapturedContext;
- }
-
- /// <summary>Returns an awaiter for this <see cref="ConfiguredValueTaskAwaitable{TResult}"/> instance.</summary>
- public ConfiguredValueTaskAwaiter GetAwaiter() =>
- new ConfiguredValueTaskAwaiter(_value, _continueOnCapturedContext);
-
- /// <summary>Provides an awaiter for a <see cref="ConfiguredValueTaskAwaitable{TResult}"/>.</summary>
- [StructLayout(LayoutKind.Auto)]
- public readonly struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion
- {
- /// <summary>The value being awaited.</summary>
- private readonly ValueTask<TResult> _value;
- /// <summary>The value to pass to ConfigureAwait.</summary>
- private readonly bool _continueOnCapturedContext;
-
- /// <summary>Initializes the awaiter.</summary>
- /// <param name="value">The value to be awaited.</param>
- /// <param name="continueOnCapturedContext">The value to pass to ConfigureAwait.</param>
- internal ConfiguredValueTaskAwaiter(ValueTask<TResult> value, bool continueOnCapturedContext)
- {
- _value = value;
- _continueOnCapturedContext = continueOnCapturedContext;
- }
-
- /// <summary>Gets whether the <see cref="ConfiguredValueTaskAwaitable{TResult}"/> has completed.</summary>
- public bool IsCompleted => _value.IsCompleted;
-
- /// <summary>Gets the result of the ValueTask.</summary>
- public TResult GetResult() =>
- _value._task == null ?
- _value._result :
- _value._task.GetAwaiter().GetResult();
-
- /// <summary>Schedules the continuation action for the <see cref="ConfiguredValueTaskAwaitable{TResult}"/>.</summary>
- public void OnCompleted(Action continuation) =>
- _value.AsTask().ConfigureAwait(_continueOnCapturedContext).GetAwaiter().OnCompleted(continuation);
-
- /// <summary>Schedules the continuation action for the <see cref="ConfiguredValueTaskAwaitable{TResult}"/>.</summary>
- public void UnsafeOnCompleted(Action continuation) =>
- _value.AsTask().ConfigureAwait(_continueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation);
- }
- }
-}
diff --git a/src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/ValueTaskAwaiter.cs b/src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/ValueTaskAwaiter.cs
deleted file mode 100644
index 2774ba6ad3..0000000000
--- a/src/System.Threading.Tasks.Extensions/src/System/Runtime/CompilerServices/ValueTaskAwaiter.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Runtime.InteropServices;
-using System.Threading.Tasks;
-
-namespace System.Runtime.CompilerServices
-{
- /// <summary>Provides an awaiter for a <see cref="ValueTask{TResult}"/>.</summary>
- public readonly struct ValueTaskAwaiter<TResult> : ICriticalNotifyCompletion
- {
- /// <summary>The value being awaited.</summary>
- private readonly ValueTask<TResult> _value;
-
- /// <summary>Initializes the awaiter.</summary>
- /// <param name="value">The value to be awaited.</param>
- internal ValueTaskAwaiter(ValueTask<TResult> value) => _value = value;
-
- /// <summary>Gets whether the <see cref="ValueTask{TResult}"/> has completed.</summary>
- public bool IsCompleted => _value.IsCompleted;
-
- /// <summary>Gets the result of the ValueTask.</summary>
- public TResult GetResult() =>
- _value._task == null ?
- _value._result :
- _value._task.GetAwaiter().GetResult();
-
- /// <summary>Schedules the continuation action for this ValueTask.</summary>
- public void OnCompleted(Action continuation) =>
- _value.AsTask().ConfigureAwait(continueOnCapturedContext: true).GetAwaiter().OnCompleted(continuation);
-
- /// <summary>Schedules the continuation action for this ValueTask.</summary>
- public void UnsafeOnCompleted(Action continuation) =>
- _value.AsTask().ConfigureAwait(continueOnCapturedContext: true).GetAwaiter().UnsafeOnCompleted(continuation);
- }
-}
diff --git a/src/System.Threading.Tasks.Extensions/src/System/Threading/Tasks/ValueTask.cs b/src/System.Threading.Tasks.Extensions/src/System/Threading/Tasks/ValueTask.cs
deleted file mode 100644
index f91e6da4cb..0000000000
--- a/src/System.Threading.Tasks.Extensions/src/System/Threading/Tasks/ValueTask.cs
+++ /dev/null
@@ -1,167 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-#if !MONO
-using System.ComponentModel;
-#endif
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-namespace System.Threading.Tasks
-{
- /// <summary>
- /// Provides a value type that wraps a <see cref="Task{TResult}"/> and a <typeparamref name="TResult"/>,
- /// only one of which is used.
- /// </summary>
- /// <typeparam name="TResult">The type of the result.</typeparam>
- /// <remarks>
- /// <para>
- /// Methods may return an instance of this value type when it's likely that the result of their
- /// operations will be available synchronously and when the method is expected to be invoked so
- /// frequently that the cost of allocating a new <see cref="Task{TResult}"/> for each call will
- /// be prohibitive.
- /// </para>
- /// <para>
- /// There are tradeoffs to using a <see cref="ValueTask{TResult}"/> instead of a <see cref="Task{TResult}"/>.
- /// For example, while a <see cref="ValueTask{TResult}"/> can help avoid an allocation in the case where the
- /// successful result is available synchronously, it also contains two fields whereas a <see cref="Task{TResult}"/>
- /// as a reference type is a single field. This means that a method call ends up returning two fields worth of
- /// data instead of one, which is more data to copy. It also means that if a method that returns one of these
- /// is awaited within an async method, the state machine for that async method will be larger due to needing
- /// to store the struct that's two fields instead of a single reference.
- /// </para>
- /// <para>
- /// Further, for uses other than consuming the result of an asynchronous operation via await,
- /// <see cref="ValueTask{TResult}"/> can lead to a more convoluted programming model, which can in turn actually
- /// lead to more allocations. For example, consider a method that could return either a <see cref="Task{TResult}"/>
- /// with a cached task as a common result or a <see cref="ValueTask{TResult}"/>. If the consumer of the result
- /// wants to use it as a <see cref="Task{TResult}"/>, such as to use with in methods like Task.WhenAll and Task.WhenAny,
- /// the <see cref="ValueTask{TResult}"/> would first need to be converted into a <see cref="Task{TResult}"/> using
- /// <see cref="ValueTask{TResult}.AsTask"/>, which leads to an allocation that would have been avoided if a cached
- /// <see cref="Task{TResult}"/> had been used in the first place.
- /// </para>
- /// <para>
- /// As such, the default choice for any asynchronous method should be to return a <see cref="Task"/> or
- /// <see cref="Task{TResult}"/>. Only if performance analysis proves it worthwhile should a <see cref="ValueTask{TResult}"/>
- /// be used instead of <see cref="Task{TResult}"/>. There is no non-generic version of <see cref="ValueTask{TResult}"/>
- /// as the Task.CompletedTask property may be used to hand back a successfully completed singleton in the case where
- /// a <see cref="Task"/>-returning method completes synchronously and successfully.
- /// </para>
- /// </remarks>
- [AsyncMethodBuilder(typeof(AsyncValueTaskMethodBuilder<>))]
- [StructLayout(LayoutKind.Auto)]
- public readonly struct ValueTask<TResult> : IEquatable<ValueTask<TResult>>
- {
- /// <summary>The task to be used if the operation completed asynchronously or if it completed synchronously but non-successfully.</summary>
- internal readonly Task<TResult> _task;
- /// <summary>The result to be used if the operation completed successfully synchronously.</summary>
- internal readonly TResult _result;
-
- /// <summary>Initialize the <see cref="ValueTask{TResult}"/> with the result of the successful operation.</summary>
- /// <param name="result">The result.</param>
- public ValueTask(TResult result)
- {
- _task = null;
- _result = result;
- }
-
- /// <summary>
- /// Initialize the <see cref="ValueTask{TResult}"/> with a <see cref="Task{TResult}"/> that represents the operation.
- /// </summary>
- /// <param name="task">The task.</param>
- public ValueTask(Task<TResult> task)
- {
- _task = task ?? throw new ArgumentNullException(nameof(task));
- _result = default(TResult);
- }
-
- /// <summary>Returns the hash code for this instance.</summary>
- public override int GetHashCode() =>
- _task != null ? _task.GetHashCode() :
- _result != null ? _result.GetHashCode() :
- 0;
-
- /// <summary>Returns a value indicating whether this value is equal to a specified <see cref="object"/>.</summary>
- public override bool Equals(object obj) =>
- obj is ValueTask<TResult> &&
- Equals((ValueTask<TResult>)obj);
-
- /// <summary>Returns a value indicating whether this value is equal to a specified <see cref="ValueTask{TResult}"/> value.</summary>
- public bool Equals(ValueTask<TResult> other) =>
- _task != null || other._task != null ?
- _task == other._task :
- EqualityComparer<TResult>.Default.Equals(_result, other._result);
-
- /// <summary>Returns a value indicating whether two <see cref="ValueTask{TResult}"/> values are equal.</summary>
- public static bool operator==(ValueTask<TResult> left, ValueTask<TResult> right) =>
- left.Equals(right);
-
- /// <summary>Returns a value indicating whether two <see cref="ValueTask{TResult}"/> values are not equal.</summary>
- public static bool operator!=(ValueTask<TResult> left, ValueTask<TResult> right) =>
- !left.Equals(right);
-
- /// <summary>
- /// Gets a <see cref="Task{TResult}"/> object to represent this ValueTask. It will
- /// either return the wrapped task object if one exists, or it'll manufacture a new
- /// task object to represent the result.
- /// </summary>
- public Task<TResult> AsTask() =>
- // Return the task if we were constructed from one, otherwise manufacture one. We don't
- // cache the generated task into _task as it would end up changing both equality comparison
- // and the hash code we generate in GetHashCode.
- _task ?? Task.FromResult(_result);
-
- /// <summary>Gets whether the <see cref="ValueTask{TResult}"/> represents a completed operation.</summary>
- public bool IsCompleted => _task == null || _task.IsCompleted;
-
- /// <summary>Gets whether the <see cref="ValueTask{TResult}"/> represents a successfully completed operation.</summary>
- public bool IsCompletedSuccessfully => _task == null || _task.Status == TaskStatus.RanToCompletion;
-
- /// <summary>Gets whether the <see cref="ValueTask{TResult}"/> represents a failed operation.</summary>
- public bool IsFaulted => _task != null && _task.IsFaulted;
-
- /// <summary>Gets whether the <see cref="ValueTask{TResult}"/> represents a canceled operation.</summary>
- public bool IsCanceled => _task != null && _task.IsCanceled;
-
- /// <summary>Gets the result.</summary>
- public TResult Result => _task == null ? _result : _task.GetAwaiter().GetResult();
-
- /// <summary>Gets an awaiter for this value.</summary>
- public ValueTaskAwaiter<TResult> GetAwaiter() => new ValueTaskAwaiter<TResult>(this);
-
- /// <summary>Configures an awaiter for this value.</summary>
- /// <param name="continueOnCapturedContext">
- /// true to attempt to marshal the continuation back to the captured context; otherwise, false.
- /// </param>
- public ConfiguredValueTaskAwaitable<TResult> ConfigureAwait(bool continueOnCapturedContext) =>
- new ConfiguredValueTaskAwaitable<TResult>(this, continueOnCapturedContext: continueOnCapturedContext);
-
- /// <summary>Gets a string-representation of this <see cref="ValueTask{TResult}"/>.</summary>
- public override string ToString()
- {
- if (_task != null)
- {
- return _task.Status == TaskStatus.RanToCompletion && _task.Result != null ?
- _task.Result.ToString() :
- string.Empty;
- }
- else
- {
- return _result != null ?
- _result.ToString() :
- string.Empty;
- }
- }
-
- // TODO: Remove CreateAsyncMethodBuilder once the C# compiler relies on the AsyncBuilder attribute.
-
- /// <summary>Creates a method builder for use with an async method.</summary>
- /// <returns>The created builder.</returns>
-#if !MONO
- [EditorBrowsable(EditorBrowsableState.Never)] // intended only for compiler consumption
-#endif
- public static AsyncValueTaskMethodBuilder<TResult> CreateAsyncMethodBuilder() => AsyncValueTaskMethodBuilder<TResult>.Create();
- }
-}
diff --git a/src/System.Threading.Tasks.Extensions/src/System/ThrowHelper.cs b/src/System.Threading.Tasks.Extensions/src/System/ThrowHelper.cs
new file mode 100644
index 0000000000..5824a165ec
--- /dev/null
+++ b/src/System.Threading.Tasks.Extensions/src/System/ThrowHelper.cs
@@ -0,0 +1,40 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+
+namespace System
+{
+ internal static class ThrowHelper
+ {
+ internal static void ThrowArgumentNullException(ExceptionArgument argument) =>
+ throw GetArgumentNullException(argument);
+
+ internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument) =>
+ throw GetArgumentOutOfRangeException(argument);
+
+ private static ArgumentNullException GetArgumentNullException(ExceptionArgument argument) =>
+ new ArgumentNullException(GetArgumentName(argument));
+
+ private static ArgumentOutOfRangeException GetArgumentOutOfRangeException(ExceptionArgument argument) =>
+ new ArgumentOutOfRangeException(GetArgumentName(argument));
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static string GetArgumentName(ExceptionArgument argument)
+ {
+ Debug.Assert(Enum.IsDefined(typeof(ExceptionArgument), argument),
+ $"The enum value is not defined, please check the {nameof(ExceptionArgument)} enum.");
+
+ return argument.ToString();
+ }
+ }
+
+ internal enum ExceptionArgument
+ {
+ task,
+ source,
+ state
+ }
+}
diff --git a/src/System.Threading.Tasks.Extensions/tests/AsyncMethodBuilderAttributeTests.cs b/src/System.Threading.Tasks.Extensions/tests/AsyncMethodBuilderAttributeTests.cs
index 29dfa236f4..02f1d8b4cd 100644
--- a/src/System.Threading.Tasks.Extensions/tests/AsyncMethodBuilderAttributeTests.cs
+++ b/src/System.Threading.Tasks.Extensions/tests/AsyncMethodBuilderAttributeTests.cs
@@ -11,6 +11,7 @@ namespace System.Runtime.CompilerServices.Tests
[Theory]
[InlineData(typeof(string))]
[InlineData(typeof(int))]
+ [InlineData(typeof(AsyncValueTaskMethodBuilder))]
[InlineData(typeof(AsyncValueTaskMethodBuilder<>))]
[InlineData(typeof(AsyncValueTaskMethodBuilder<int>))]
[InlineData(typeof(AsyncValueTaskMethodBuilder<string>))]
diff --git a/src/System.Threading.Tasks.Extensions/tests/AsyncValueTaskMethodBuilderTests.cs b/src/System.Threading.Tasks.Extensions/tests/AsyncValueTaskMethodBuilderTests.cs
index 94827c91b5..258404f925 100644
--- a/src/System.Threading.Tasks.Extensions/tests/AsyncValueTaskMethodBuilderTests.cs
+++ b/src/System.Threading.Tasks.Extensions/tests/AsyncValueTaskMethodBuilderTests.cs
@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System;
using System.Runtime.CompilerServices;
using Xunit;
@@ -11,16 +10,32 @@ namespace System.Threading.Tasks.Tests
public class AsyncValueTaskMethodBuilderTests
{
[Fact]
- public void Create_ReturnsDefaultInstance()
+ public void NonGeneric_Create_ReturnsDefaultInstance()
{
- AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
- Assert.Equal(default(AsyncValueTaskMethodBuilder<int>), b); // implementation detail being verified
+ AsyncValueTaskMethodBuilder b = default;
+ Assert.Equal(default, b); // implementation detail being verified
}
[Fact]
- public void SetResult_BeforeAccessTask_ValueTaskContainsValue()
+ public void Generic_Create_ReturnsDefaultInstance()
{
- AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
+ AsyncValueTaskMethodBuilder<int> b = default;
+ Assert.Equal(default, b); // implementation detail being verified
+ }
+
+ [Fact]
+ public void NonGeneric_SetResult_BeforeAccessTask_ValueTaskIsDefault()
+ {
+ AsyncValueTaskMethodBuilder b = default;
+ b.SetResult();
+ ValueTask vt = b.Task;
+ Assert.True(vt == default);
+ }
+
+ [Fact]
+ public void Generic_SetResult_BeforeAccessTask_ValueTaskContainsValue()
+ {
+ AsyncValueTaskMethodBuilder<int> b = default;
b.SetResult(42);
ValueTask<int> vt = b.Task;
Assert.True(vt.IsCompletedSuccessfully);
@@ -29,9 +44,20 @@ namespace System.Threading.Tasks.Tests
}
[Fact]
- public void SetResult_AfterAccessTask_ValueTaskContainsValue()
+ public void NonGeneric_SetResult_AfterAccessTask_ValueTaskContainsValue()
+ {
+ AsyncValueTaskMethodBuilder b = default;
+ ValueTask vt = b.Task;
+ b.SetResult();
+ Assert.False(vt == default);
+ Assert.True(vt.IsCompletedSuccessfully);
+ Assert.True(WrapsTask(vt));
+ }
+
+ [Fact]
+ public void Generic_SetResult_AfterAccessTask_ValueTaskContainsValue()
{
- AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
+ AsyncValueTaskMethodBuilder<int> b = default;
ValueTask<int> vt = b.Task;
b.SetResult(42);
Assert.True(vt.IsCompletedSuccessfully);
@@ -40,9 +66,20 @@ namespace System.Threading.Tasks.Tests
}
[Fact]
- public void SetException_BeforeAccessTask_FaultsTask()
+ public void NonGeneric_SetException_BeforeAccessTask_FaultsTask()
{
- AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
+ AsyncValueTaskMethodBuilder b = default;
+ var e = new FormatException();
+ b.SetException(e);
+ ValueTask vt = b.Task;
+ Assert.True(vt.IsFaulted);
+ Assert.Same(e, Assert.Throws<FormatException>(() => vt.GetAwaiter().GetResult()));
+ }
+
+ [Fact]
+ public void Generic_SetException_BeforeAccessTask_FaultsTask()
+ {
+ AsyncValueTaskMethodBuilder<int> b = default;
var e = new FormatException();
b.SetException(e);
ValueTask<int> vt = b.Task;
@@ -51,9 +88,20 @@ namespace System.Threading.Tasks.Tests
}
[Fact]
- public void SetException_AfterAccessTask_FaultsTask()
+ public void NonGeneric_SetException_AfterAccessTask_FaultsTask()
+ {
+ AsyncValueTaskMethodBuilder b = default;
+ var e = new FormatException();
+ ValueTask vt = b.Task;
+ b.SetException(e);
+ Assert.True(vt.IsFaulted);
+ Assert.Same(e, Assert.Throws<FormatException>(() => vt.GetAwaiter().GetResult()));
+ }
+
+ [Fact]
+ public void Generic_SetException_AfterAccessTask_FaultsTask()
{
- AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
+ AsyncValueTaskMethodBuilder<int> b = default;
var e = new FormatException();
ValueTask<int> vt = b.Task;
b.SetException(e);
@@ -62,9 +110,20 @@ namespace System.Threading.Tasks.Tests
}
[Fact]
- public void SetException_OperationCanceledException_CancelsTask()
+ public void NonGeneric_SetException_OperationCanceledException_CancelsTask()
{
- AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
+ AsyncValueTaskMethodBuilder b = default;
+ var e = new OperationCanceledException();
+ ValueTask vt = b.Task;
+ b.SetException(e);
+ Assert.True(vt.IsCanceled);
+ Assert.Same(e, Assert.Throws<OperationCanceledException>(() => vt.GetAwaiter().GetResult()));
+ }
+
+ [Fact]
+ public void Generic_SetException_OperationCanceledException_CancelsTask()
+ {
+ AsyncValueTaskMethodBuilder<int> b = default;
var e = new OperationCanceledException();
ValueTask<int> vt = b.Task;
b.SetException(e);
@@ -73,23 +132,64 @@ namespace System.Threading.Tasks.Tests
}
[Fact]
- public void Start_InvokesMoveNext()
+ public void NonGeneric_Start_InvokesMoveNext()
{
- AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
+ AsyncValueTaskMethodBuilder b = default;
int invokes = 0;
var dsm = new DelegateStateMachine { MoveNextDelegate = () => invokes++ };
b.Start(ref dsm);
Assert.Equal(1, invokes);
}
+ [Fact]
+ public void Generic_Start_InvokesMoveNext()
+ {
+ AsyncValueTaskMethodBuilder<int> b = default;
+ int invokes = 0;
+ var dsm = new DelegateStateMachine { MoveNextDelegate = () => invokes++ };
+ b.Start(ref dsm);
+ Assert.Equal(1, invokes);
+ }
+
+ [Theory]
+ [InlineData(1, false)]
+ [InlineData(2, false)]
+ [InlineData(1, true)]
+ [InlineData(2, true)]
+ public void NonGeneric_AwaitOnCompleted_ForcesTaskCreation(int numAwaits, bool awaitUnsafe)
+ {
+ AsyncValueTaskMethodBuilder b = default;
+
+ var dsm = new DelegateStateMachine();
+ TaskAwaiter<int> t = new TaskCompletionSource<int>().Task.GetAwaiter();
+
+ Assert.InRange(numAwaits, 1, int.MaxValue);
+ for (int i = 1; i <= numAwaits; i++)
+ {
+ if (awaitUnsafe)
+ {
+ b.AwaitUnsafeOnCompleted(ref t, ref dsm);
+ }
+ else
+ {
+ b.AwaitOnCompleted(ref t, ref dsm);
+ }
+ }
+
+ b.SetResult();
+
+ Assert.True(WrapsTask(b.Task));
+ Assert.True(b.Task.IsCompletedSuccessfully);
+ }
+
[Theory]
[InlineData(1, false)]
[InlineData(2, false)]
[InlineData(1, true)]
[InlineData(2, true)]
- public void AwaitOnCompleted_ForcesTaskCreation(int numAwaits, bool awaitUnsafe)
+ public void Generic_AwaitOnCompleted_ForcesTaskCreation(int numAwaits, bool awaitUnsafe)
{
- AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
+ AsyncValueTaskMethodBuilder<int> b = default;
var dsm = new DelegateStateMachine();
TaskAwaiter<int> t = new TaskCompletionSource<int>().Task.GetAwaiter();
@@ -115,14 +215,56 @@ namespace System.Threading.Tasks.Tests
[Fact]
[ActiveIssue("https://github.com/dotnet/corefx/issues/22506", TargetFrameworkMonikers.UapAot)]
- public void SetStateMachine_InvalidArgument_ThrowsException()
+ public void NonGeneric_SetStateMachine_InvalidArgument_ThrowsException()
{
- AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
+ AsyncValueTaskMethodBuilder b = default;
AssertExtensions.Throws<ArgumentNullException>("stateMachine", () => b.SetStateMachine(null));
}
[Fact]
- public void Start_ExecutionContextChangesInMoveNextDontFlowOut()
+ [ActiveIssue("https://github.com/dotnet/corefx/issues/22506", TargetFrameworkMonikers.UapAot)]
+ public void Generic_SetStateMachine_InvalidArgument_ThrowsException()
+ {
+ AsyncValueTaskMethodBuilder<int> b = default;
+ AssertExtensions.Throws<ArgumentNullException>("stateMachine", () => b.SetStateMachine(null));
+ }
+
+ [Fact]
+ public void NonGeneric_Start_ExecutionContextChangesInMoveNextDontFlowOut()
+ {
+ var al = new AsyncLocal<int> { Value = 0 };
+ int calls = 0;
+
+ var dsm = new DelegateStateMachine
+ {
+ MoveNextDelegate = () =>
+ {
+ al.Value++;
+ calls++;
+ }
+ };
+
+ dsm.MoveNext();
+ Assert.Equal(1, al.Value);
+ Assert.Equal(1, calls);
+
+ dsm.MoveNext();
+ Assert.Equal(2, al.Value);
+ Assert.Equal(2, calls);
+
+ AsyncValueTaskMethodBuilder b = default;
+ b.Start(ref dsm);
+ Assert.Equal(2, al.Value); // change should not be visible
+ Assert.Equal(3, calls);
+
+ // Make sure we've not caused the Task to be allocated
+ b.SetResult();
+ ValueTask vt = b.Task;
+ Assert.False(WrapsTask(vt));
+ }
+
+ [Fact]
+ public void Generic_Start_ExecutionContextChangesInMoveNextDontFlowOut()
{
var al = new AsyncLocal<int> { Value = 0 };
int calls = 0;
@@ -144,7 +286,7 @@ namespace System.Threading.Tasks.Tests
Assert.Equal(2, al.Value);
Assert.Equal(2, calls);
- AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
+ AsyncValueTaskMethodBuilder<int> b = default;
b.Start(ref dsm);
Assert.Equal(2, al.Value); // change should not be visible
Assert.Equal(3, calls);
@@ -160,7 +302,25 @@ namespace System.Threading.Tasks.Tests
[InlineData(1)]
[InlineData(2)]
[InlineData(10)]
- public static async Task UsedWithAsyncMethod_CompletesSuccessfully(int yields)
+ public static async Task NonGeneric_UsedWithAsyncMethod_CompletesSuccessfully(int yields)
+ {
+ await ValueTaskReturningAsyncMethod(42);
+
+ ValueTask vt = ValueTaskReturningAsyncMethod(84);
+ Assert.Equal(yields > 0, WrapsTask(vt));
+
+ async ValueTask ValueTaskReturningAsyncMethod(int result)
+ {
+ for (int i = 0; i < yields; i++) await Task.Yield();
+ }
+ }
+
+ [Theory]
+ [InlineData(0)]
+ [InlineData(1)]
+ [InlineData(2)]
+ [InlineData(10)]
+ public static async Task Generic_UsedWithAsyncMethod_CompletesSuccessfully(int yields)
{
Assert.Equal(42, await ValueTaskReturningAsyncMethod(42));
@@ -175,7 +335,129 @@ namespace System.Threading.Tasks.Tests
}
}
- /// <summary>Gets whether the ValueTask has a non-null Task.</summary>
+ [Fact]
+ public static async Task AwaitTasksAndValueTasks_InTaskAndValueTaskMethods()
+ {
+ for (int i = 0; i < 2; i++)
+ {
+ await TaskReturningMethod();
+ Assert.Equal(17, await TaskInt32ReturningMethod());
+ await ValueTaskReturningMethod();
+ Assert.Equal(18, await ValueTaskInt32ReturningMethod());
+ }
+
+ async Task TaskReturningMethod()
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ // Complete
+ await Task.CompletedTask;
+ await Task.FromResult(42);
+ await new ValueTask();
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(Task.FromException<int>(new FormatException())));
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(ManualResetValueTaskSource.Completed(0, new FormatException()), 0));
+ Assert.Equal(42, await new ValueTask<int>(42));
+ Assert.Equal(42, await new ValueTask<int>(Task.FromResult(42)));
+ Assert.Equal(42, await new ValueTask<int>(ManualResetValueTaskSource.Completed(42, null), 0));
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(Task.FromException<int>(new FormatException())));
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(ManualResetValueTaskSource.Completed(0, new FormatException()), 0));
+
+ // Incomplete
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(Task.Delay(1).ContinueWith(_ => throw new FormatException())));
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(ManualResetValueTaskSource.Delay(1, 0, new FormatException()), 0));
+ Assert.Equal(42, await new ValueTask<int>(Task.Delay(1).ContinueWith(_ => 42)));
+ Assert.Equal(42, await new ValueTask<int>(ManualResetValueTaskSource.Delay(1, 42, null), 0));
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(Task.Delay(1).ContinueWith<int>(_ => throw new FormatException())));
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(ManualResetValueTaskSource.Delay(1, 0, new FormatException()), 0));
+ await Task.Yield();
+ }
+ }
+
+ async Task<int> TaskInt32ReturningMethod()
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ // Complete
+ await Task.CompletedTask;
+ await Task.FromResult(42);
+ await new ValueTask();
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(Task.FromException<int>(new FormatException())));
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(ManualResetValueTaskSource.Completed(0, new FormatException()), 0));
+ Assert.Equal(42, await new ValueTask<int>(42));
+ Assert.Equal(42, await new ValueTask<int>(Task.FromResult(42)));
+ Assert.Equal(42, await new ValueTask<int>(ManualResetValueTaskSource.Completed(42, null), 0));
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(Task.FromException<int>(new FormatException())));
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(ManualResetValueTaskSource.Completed(0, new FormatException()), 0));
+
+ // Incomplete
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(Task.Delay(1).ContinueWith(_ => throw new FormatException())));
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(ManualResetValueTaskSource.Delay(1, 0, new FormatException()), 0));
+ Assert.Equal(42, await new ValueTask<int>(Task.Delay(1).ContinueWith(_ => 42)));
+ Assert.Equal(42, await new ValueTask<int>(ManualResetValueTaskSource.Delay(1, 42, null), 0));
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(Task.Delay(1).ContinueWith<int>(_ => throw new FormatException())));
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(ManualResetValueTaskSource.Delay(1, 0, new FormatException()), 0));
+ await Task.Yield();
+ }
+ return 17;
+ }
+
+ async ValueTask ValueTaskReturningMethod()
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ // Complete
+ await Task.CompletedTask;
+ await Task.FromResult(42);
+ await new ValueTask();
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(Task.FromException<int>(new FormatException())));
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(ManualResetValueTaskSource.Completed(0, new FormatException()), 0));
+ Assert.Equal(42, await new ValueTask<int>(42));
+ Assert.Equal(42, await new ValueTask<int>(Task.FromResult(42)));
+ Assert.Equal(42, await new ValueTask<int>(ManualResetValueTaskSource.Completed(42, null), 0));
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(Task.FromException<int>(new FormatException())));
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(ManualResetValueTaskSource.Completed(0, new FormatException()), 0));
+
+ // Incomplete
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(Task.Delay(1).ContinueWith(_ => throw new FormatException())));
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(ManualResetValueTaskSource.Delay(1, 0, new FormatException()), 0));
+ Assert.Equal(42, await new ValueTask<int>(Task.Delay(1).ContinueWith(_ => 42)));
+ Assert.Equal(42, await new ValueTask<int>(ManualResetValueTaskSource.Delay(1, 42, null), 0));
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(Task.Delay(1).ContinueWith<int>(_ => throw new FormatException())));
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(ManualResetValueTaskSource.Delay(1, 0, new FormatException()), 0));
+ await Task.Yield();
+ }
+ }
+
+ async ValueTask<int> ValueTaskInt32ReturningMethod()
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ // Complete
+ await Task.CompletedTask;
+ await Task.FromResult(42);
+ await new ValueTask();
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(Task.FromException<int>(new FormatException())));
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(ManualResetValueTaskSource.Completed(0, new FormatException()), 0));
+ Assert.Equal(42, await new ValueTask<int>(42));
+ Assert.Equal(42, await new ValueTask<int>(Task.FromResult(42)));
+ Assert.Equal(42, await new ValueTask<int>(ManualResetValueTaskSource.Completed(42, null), 0));
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(Task.FromException<int>(new FormatException())));
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(ManualResetValueTaskSource.Completed(0, new FormatException()), 0));
+
+ // Incomplete
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(Task.Delay(1).ContinueWith(_ => throw new FormatException())));
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask(ManualResetValueTaskSource.Delay(1, 0, new FormatException()), 0));
+ Assert.Equal(42, await new ValueTask<int>(Task.Delay(1).ContinueWith(_ => 42)));
+ Assert.Equal(42, await new ValueTask<int>(ManualResetValueTaskSource.Delay(1, 42, null), 0));
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(Task.Delay(1).ContinueWith<int>(_ => throw new FormatException())));
+ await Assert.ThrowsAsync<FormatException>(async () => await new ValueTask<int>(ManualResetValueTaskSource.Delay(1, 0, new FormatException()), 0));
+ await Task.Yield();
+ }
+ return 18;
+ }
+ }
+
+ private static bool WrapsTask(ValueTask vt) => vt != default;
private static bool WrapsTask<T>(ValueTask<T> vt) => ReferenceEquals(vt.AsTask(), vt.AsTask());
private struct DelegateStateMachine : IAsyncStateMachine
diff --git a/src/System.Threading.Tasks.Extensions/tests/Configurations.props b/src/System.Threading.Tasks.Extensions/tests/Configurations.props
index c701755863..7de0087598 100644
--- a/src/System.Threading.Tasks.Extensions/tests/Configurations.props
+++ b/src/System.Threading.Tasks.Extensions/tests/Configurations.props
@@ -4,6 +4,7 @@
<BuildConfigurations>
netcoreapp;
uap;
+ netfx;
</BuildConfigurations>
</PropertyGroup>
</Project> \ No newline at end of file
diff --git a/src/System.Threading.Tasks.Extensions/tests/ManualResetValueTaskSource.cs b/src/System.Threading.Tasks.Extensions/tests/ManualResetValueTaskSource.cs
new file mode 100644
index 0000000000..4e6c328038
--- /dev/null
+++ b/src/System.Threading.Tasks.Extensions/tests/ManualResetValueTaskSource.cs
@@ -0,0 +1,164 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.ExceptionServices;
+using System.Threading.Tasks.Sources;
+
+namespace System.Threading.Tasks.Tests
+{
+ internal static class ManualResetValueTaskSource
+ {
+ public static ManualResetValueTaskSource<T> Completed<T>(T result, Exception error = null)
+ {
+ var vts = new ManualResetValueTaskSource<T>();
+ if (error != null)
+ {
+ vts.SetException(error);
+ }
+ else
+ {
+ vts.SetResult(result);
+ }
+ return vts;
+ }
+
+ public static ManualResetValueTaskSource<T> Delay<T>(int delayMs, T result, Exception error = null)
+ {
+ var vts = new ManualResetValueTaskSource<T>();
+ Task.Delay(delayMs).ContinueWith(_ =>
+ {
+ if (error != null)
+ {
+ vts.SetException(error);
+ }
+ else
+ {
+ vts.SetResult(result);
+ }
+ });
+ return vts;
+ }
+ }
+
+ internal sealed class ManualResetValueTaskSource<T> : IValueTaskSource<T>, IValueTaskSource
+ {
+ private static readonly Action<object> s_sentinel = new Action<object>(s => { });
+ private Action<object> _continuation;
+ private object _continuationState;
+ private SynchronizationContext _capturedContext;
+ private ExecutionContext _executionContext;
+ private bool _completed;
+ private T _result;
+ private ExceptionDispatchInfo _error;
+
+ public ValueTaskSourceStatus GetStatus(short token) =>
+ !_completed ? ValueTaskSourceStatus.Pending :
+ _error == null ? ValueTaskSourceStatus.Succeeded :
+ _error.SourceException is OperationCanceledException ? ValueTaskSourceStatus.Canceled :
+ ValueTaskSourceStatus.Faulted;
+
+ public T GetResult(short token)
+ {
+ if (!_completed)
+ {
+ throw new Exception("Not completed");
+ }
+
+ _error?.Throw();
+ return _result;
+ }
+
+ void IValueTaskSource.GetResult(short token)
+ {
+ GetResult(token);
+ }
+
+ public void Reset()
+ {
+ _completed = false;
+ _continuation = null;
+ _continuationState = null;
+ _result = default;
+ _error = null;
+ _executionContext = null;
+ _capturedContext = null;
+ }
+
+ public void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags)
+ {
+ if ((flags & ValueTaskSourceOnCompletedFlags.FlowExecutionContext) != 0)
+ {
+ _executionContext = ExecutionContext.Capture();
+ }
+
+ if ((flags & ValueTaskSourceOnCompletedFlags.UseSchedulingContext) != 0)
+ {
+ _capturedContext = SynchronizationContext.Current;
+ }
+
+ _continuationState = state;
+ if (Interlocked.CompareExchange(ref _continuation, continuation, null) != null)
+ {
+ SynchronizationContext sc = _capturedContext;
+ if (sc != null)
+ {
+ sc.Post(s =>
+ {
+ var tuple = (Tuple<Action<object>, object>)s;
+ tuple.Item1(tuple.Item2);
+ }, Tuple.Create(continuation, state));
+ }
+ else
+ {
+ Task.Factory.StartNew(continuation, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
+ }
+ }
+ }
+
+ public void SetResult(T result)
+ {
+ _result = result;
+ SignalCompletion();
+ }
+
+ public void SetException(Exception error)
+ {
+ _error = ExceptionDispatchInfo.Capture(error);
+ SignalCompletion();
+ }
+
+ private void SignalCompletion()
+ {
+ _completed = true;
+ if (Interlocked.CompareExchange(ref _continuation, s_sentinel, null) != null)
+ {
+ if (_executionContext != null)
+ {
+ ExecutionContext.Run(_executionContext, s => ((ManualResetValueTaskSource<T>)s).InvokeContinuation(), this);
+ }
+ else
+ {
+ InvokeContinuation();
+ }
+ }
+ }
+
+ private void InvokeContinuation()
+ {
+ SynchronizationContext sc = _capturedContext;
+ if (sc != null)
+ {
+ sc.Post(s =>
+ {
+ var thisRef = (ManualResetValueTaskSource<T>)s;
+ thisRef._continuation(thisRef._continuationState);
+ }, this);
+ }
+ else
+ {
+ _continuation(_continuationState);
+ }
+ }
+ }
+}
diff --git a/src/System.Threading.Tasks.Extensions/tests/Performance/Configurations.props b/src/System.Threading.Tasks.Extensions/tests/Performance/Configurations.props
new file mode 100644
index 0000000000..d3ac8a63c7
--- /dev/null
+++ b/src/System.Threading.Tasks.Extensions/tests/Performance/Configurations.props
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <BuildConfigurations>
+ netcoreapp;
+ </BuildConfigurations>
+ </PropertyGroup>
+</Project>
diff --git a/src/System.Threading.Tasks.Extensions/tests/Performance/Perf.ValueTask.cs b/src/System.Threading.Tasks.Extensions/tests/Performance/Perf.ValueTask.cs
new file mode 100644
index 0000000000..27c335dd3a
--- /dev/null
+++ b/src/System.Threading.Tasks.Extensions/tests/Performance/Perf.ValueTask.cs
@@ -0,0 +1,189 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.CompilerServices;
+using Microsoft.Xunit.Performance;
+using Xunit;
+
+namespace System.Threading.Tasks
+{
+ public class ValueTaskPerfTest
+ {
+ [Benchmark(InnerIterationCount = 10_000_000), MeasureGCAllocations]
+ public async Task Await_FromResult()
+ {
+ ValueTask<int> vt = new ValueTask<int>(42);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ long iters = Benchmark.InnerIterationCount;
+ using (iteration.StartMeasurement())
+ {
+ for (long i = 0; i < iters; i++)
+ {
+ await vt;
+ }
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = 10_000_000), MeasureGCAllocations]
+ public async Task Await_FromCompletedTask()
+ {
+ ValueTask<int> vt = new ValueTask<int>(Task.FromResult(42));
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ long iters = Benchmark.InnerIterationCount;
+ using (iteration.StartMeasurement())
+ {
+ for (long i = 0; i < iters; i++)
+ {
+ await vt;
+ }
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = 10_000_000), MeasureGCAllocations]
+ public async Task CreateAndAwait_FromResult()
+ {
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ long iters = Benchmark.InnerIterationCount;
+ using (iteration.StartMeasurement())
+ {
+ for (long i = 0; i < iters; i++)
+ {
+ await new ValueTask<int>((int)i);
+ }
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = 10_000_000), MeasureGCAllocations]
+ public async Task CreateAndAwait_FromResult_ConfigureAwait()
+ {
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ long iters = Benchmark.InnerIterationCount;
+ using (iteration.StartMeasurement())
+ {
+ for (long i = 0; i < iters; i++)
+ {
+ await new ValueTask<int>((int)i).ConfigureAwait(false);
+ }
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = 10_000_000), MeasureGCAllocations]
+ public async Task CreateAndAwait_FromCompletedTask()
+ {
+ Task<int> t = Task.FromResult(42);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ long iters = Benchmark.InnerIterationCount;
+ using (iteration.StartMeasurement())
+ {
+ for (long i = 0; i < iters; i++)
+ {
+ await new ValueTask<int>(t);
+ }
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = 10_000_000), MeasureGCAllocations]
+ public async Task CreateAndAwait_FromCompletedTask_ConfigureAwait()
+ {
+ Task<int> t = Task.FromResult(42);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ long iters = Benchmark.InnerIterationCount;
+ using (iteration.StartMeasurement())
+ {
+ for (long i = 0; i < iters; i++)
+ {
+ await new ValueTask<int>(t).ConfigureAwait(false);
+ }
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = 1_000_000), MeasureGCAllocations]
+ public async Task CreateAndAwait_FromYieldingAsyncMethod()
+ {
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ long iters = Benchmark.InnerIterationCount;
+ using (iteration.StartMeasurement())
+ {
+ for (long i = 0; i < iters; i++)
+ {
+ await new ValueTask<int>(YieldOnce());
+ }
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = 1_000_000), MeasureGCAllocations]
+ public async Task CreateAndAwait_FromDelayedTCS()
+ {
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ long iters = Benchmark.InnerIterationCount;
+ using (iteration.StartMeasurement())
+ {
+ for (long i = 0; i < iters; i++)
+ {
+ var tcs = new TaskCompletionSource<int>();
+ ValueTask<int> vt = AwaitTcsAsValueTask(tcs);
+ tcs.SetResult(42);
+ await vt;
+ }
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = 10_000_000), MeasureGCAllocations]
+ public void Copy_PassAsArgumentAndReturn_FromResult()
+ {
+ ValueTask<int> vt = new ValueTask<int>(42);
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ long iters = Benchmark.InnerIterationCount;
+ using (iteration.StartMeasurement())
+ {
+ for (long i = 0; i < iters; i++)
+ {
+ vt = ReturnValueTask(vt);
+ }
+ }
+ }
+ }
+
+ [Benchmark(InnerIterationCount = 10_000_000), MeasureGCAllocations]
+ public void Copy_PassAsArgumentAndReturn_FromTask()
+ {
+ ValueTask<int> vt = new ValueTask<int>(Task.FromResult(42));
+ foreach (BenchmarkIteration iteration in Benchmark.Iterations)
+ {
+ long iters = Benchmark.InnerIterationCount;
+ using (iteration.StartMeasurement())
+ {
+ for (long i = 0; i < iters; i++)
+ {
+ vt = ReturnValueTask(vt);
+ }
+ }
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static ValueTask<int> ReturnValueTask(ValueTask<int> vt) => vt;
+
+ private async ValueTask<int> AwaitTcsAsValueTask(TaskCompletionSource<int> tcs) => await new ValueTask<int>(tcs.Task).ConfigureAwait(false);
+
+ private async Task<int> YieldOnce() { await Task.Yield(); return 42; }
+ }
+}
diff --git a/src/System.Threading.Tasks.Extensions/tests/Performance/System.Threading.Tasks.Extensions.Performance.Tests.csproj b/src/System.Threading.Tasks.Extensions/tests/Performance/System.Threading.Tasks.Extensions.Performance.Tests.csproj
new file mode 100644
index 0000000000..7a173afdaf
--- /dev/null
+++ b/src/System.Threading.Tasks.Extensions/tests/Performance/System.Threading.Tasks.Extensions.Performance.Tests.csproj
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <IncludePerformanceTests>true</IncludePerformanceTests>
+ <ProjectGuid>{77E38A48-61ED-4D79-9136-D88617EE3558}</ProjectGuid>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
+ <!-- Default configurations to help VS understand the configurations -->
+ <ItemGroup>
+ <Compile Include="Perf.ValueTask.cs" />
+ <Compile Include="$(CommonTestPath)\System\PerfUtils.cs">
+ <Link>Common\System\PerfUtils.cs</Link>
+ </Compile>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="$(CommonPath)\..\perf\PerfRunner\PerfRunner.csproj">
+ <Project>{69e46a6f-9966-45a5-8945-2559fe337827}</Project>
+ <Name>PerfRunner</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project> \ No newline at end of file
diff --git a/src/System.Threading.Tasks.Extensions/tests/System.Threading.Tasks.Extensions.Tests.csproj b/src/System.Threading.Tasks.Extensions/tests/System.Threading.Tasks.Extensions.Tests.csproj
index ab5b04af66..e9791a458a 100644
--- a/src/System.Threading.Tasks.Extensions/tests/System.Threading.Tasks.Extensions.Tests.csproj
+++ b/src/System.Threading.Tasks.Extensions/tests/System.Threading.Tasks.Extensions.Tests.csproj
@@ -6,12 +6,18 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'uap-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="AsyncMethodBuilderAttributeTests.cs" />
<Compile Include="AsyncValueTaskMethodBuilderTests.cs" />
+ <Compile Include="ManualResetValueTaskSource.cs" />
<Compile Include="ValueTaskTests.cs" />
</ItemGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project> \ No newline at end of file
diff --git a/src/System.Threading.Tasks.Extensions/tests/ValueTaskTests.cs b/src/System.Threading.Tasks.Extensions/tests/ValueTaskTests.cs
index af9ef3be4b..ff0003c8cf 100644
--- a/src/System.Threading.Tasks.Extensions/tests/ValueTaskTests.cs
+++ b/src/System.Threading.Tasks.Extensions/tests/ValueTaskTests.cs
@@ -5,14 +5,31 @@
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
+using System.Threading.Tasks.Sources;
using Xunit;
namespace System.Threading.Tasks.Tests
{
public class ValueTaskTests
{
+ public enum CtorMode
+ {
+ Result,
+ Task,
+ ValueTaskSource
+ }
+
+ [Fact]
+ public void NonGeneric_DefaultValueTask_DefaultValue()
+ {
+ Assert.True(default(ValueTask).IsCompleted);
+ Assert.True(default(ValueTask).IsCompletedSuccessfully);
+ Assert.False(default(ValueTask).IsFaulted);
+ Assert.False(default(ValueTask).IsCanceled);
+ }
+
[Fact]
- public void DefaultValueTask_ValueType_DefaultValue()
+ public void Generic_DefaultValueTask_DefaultValue()
{
Assert.True(default(ValueTask<int>).IsCompleted);
Assert.True(default(ValueTask<int>).IsCompletedSuccessfully);
@@ -27,21 +44,32 @@ namespace System.Threading.Tasks.Tests
Assert.Equal(null, default(ValueTask<string>).Result);
}
- [Fact]
- public void CreateFromValue_IsRanToCompletion()
+ [Theory]
+ [InlineData(CtorMode.Result)]
+ [InlineData(CtorMode.Task)]
+ [InlineData(CtorMode.ValueTaskSource)]
+ public void NonGeneric_CreateFromSuccessfullyCompleted_IsCompletedSuccessfully(CtorMode mode)
{
- ValueTask<int> t = new ValueTask<int>(42);
+ ValueTask t =
+ mode == CtorMode.Result ? default :
+ mode == CtorMode.Task ? new ValueTask(Task.CompletedTask) :
+ new ValueTask(ManualResetValueTaskSource.Completed(0, null), 0);
Assert.True(t.IsCompleted);
Assert.True(t.IsCompletedSuccessfully);
Assert.False(t.IsFaulted);
Assert.False(t.IsCanceled);
- Assert.Equal(42, t.Result);
}
- [Fact]
- public void CreateFromCompletedTask_IsRanToCompletion()
+ [Theory]
+ [InlineData(CtorMode.Result)]
+ [InlineData(CtorMode.Task)]
+ [InlineData(CtorMode.ValueTaskSource)]
+ public void Generic_CreateFromSuccessfullyCompleted_IsCompletedSuccessfully(CtorMode mode)
{
- ValueTask<int> t = new ValueTask<int>(Task.FromResult(42));
+ ValueTask<int> t =
+ mode == CtorMode.Result ? new ValueTask<int>(42) :
+ mode == CtorMode.Task ? new ValueTask<int>(Task.FromResult(42)) :
+ new ValueTask<int>(ManualResetValueTaskSource.Completed(42, null), 0);
Assert.True(t.IsCompleted);
Assert.True(t.IsCompletedSuccessfully);
Assert.False(t.IsFaulted);
@@ -49,18 +77,87 @@ namespace System.Threading.Tasks.Tests
Assert.Equal(42, t.Result);
}
- [Fact]
- public void CreateFromNotCompletedTask_IsNotRanToCompletion()
+ [Theory]
+ [InlineData(CtorMode.Task)]
+ [InlineData(CtorMode.ValueTaskSource)]
+ public void NonGeneric_CreateFromNotCompleted_ThenCompleteSuccessfully(CtorMode mode)
{
- var tcs = new TaskCompletionSource<int>();
- ValueTask<int> t = new ValueTask<int>(tcs.Task);
+ object completer = null;
+ ValueTask t = default;
+ switch (mode)
+ {
+ case CtorMode.Task:
+ var tcs = new TaskCompletionSource<int>();
+ t = new ValueTask(tcs.Task);
+ completer = tcs;
+ break;
+
+ case CtorMode.ValueTaskSource:
+ var mre = new ManualResetValueTaskSource<int>();
+ t = new ValueTask(mre, 0);
+ completer = mre;
+ break;
+ }
Assert.False(t.IsCompleted);
Assert.False(t.IsCompletedSuccessfully);
Assert.False(t.IsFaulted);
Assert.False(t.IsCanceled);
- tcs.SetResult(42);
+ switch (mode)
+ {
+ case CtorMode.Task:
+ ((TaskCompletionSource<int>)completer).SetResult(42);
+ break;
+
+ case CtorMode.ValueTaskSource:
+ ((ManualResetValueTaskSource<int>)completer).SetResult(42);
+ break;
+ }
+
+ Assert.True(t.IsCompleted);
+ Assert.True(t.IsCompletedSuccessfully);
+ Assert.False(t.IsFaulted);
+ Assert.False(t.IsCanceled);
+ }
+
+ [Theory]
+ [InlineData(CtorMode.Task)]
+ [InlineData(CtorMode.ValueTaskSource)]
+ public void Generic_CreateFromNotCompleted_ThenCompleteSuccessfully(CtorMode mode)
+ {
+ object completer = null;
+ ValueTask<int> t = default;
+ switch (mode)
+ {
+ case CtorMode.Task:
+ var tcs = new TaskCompletionSource<int>();
+ t = new ValueTask<int>(tcs.Task);
+ completer = tcs;
+ break;
+
+ case CtorMode.ValueTaskSource:
+ var mre = new ManualResetValueTaskSource<int>();
+ t = new ValueTask<int>(mre, 0);
+ completer = mre;
+ break;
+ }
+
+ Assert.False(t.IsCompleted);
+ Assert.False(t.IsCompletedSuccessfully);
+ Assert.False(t.IsFaulted);
+ Assert.False(t.IsCanceled);
+
+ switch (mode)
+ {
+ case CtorMode.Task:
+ ((TaskCompletionSource<int>)completer).SetResult(42);
+ break;
+
+ case CtorMode.ValueTaskSource:
+ ((ManualResetValueTaskSource<int>)completer).SetResult(42);
+ break;
+ }
Assert.Equal(42, t.Result);
Assert.True(t.IsCompleted);
@@ -69,93 +166,609 @@ namespace System.Threading.Tasks.Tests
Assert.False(t.IsCanceled);
}
+ [Theory]
+ [InlineData(CtorMode.Task)]
+ [InlineData(CtorMode.ValueTaskSource)]
+ public void NonGeneric_CreateFromNotCompleted_ThenFault(CtorMode mode)
+ {
+ object completer = null;
+ ValueTask t = default;
+ switch (mode)
+ {
+ case CtorMode.Task:
+ var tcs = new TaskCompletionSource<int>();
+ t = new ValueTask(tcs.Task);
+ completer = tcs;
+ break;
+
+ case CtorMode.ValueTaskSource:
+ var mre = new ManualResetValueTaskSource<int>();
+ t = new ValueTask(mre, 0);
+ completer = mre;
+ break;
+ }
+
+ Assert.False(t.IsCompleted);
+ Assert.False(t.IsCompletedSuccessfully);
+ Assert.False(t.IsFaulted);
+ Assert.False(t.IsCanceled);
+
+ Exception e = new InvalidOperationException();
+
+ switch (mode)
+ {
+ case CtorMode.Task:
+ ((TaskCompletionSource<int>)completer).SetException(e);
+ break;
+
+ case CtorMode.ValueTaskSource:
+ ((ManualResetValueTaskSource<int>)completer).SetException(e);
+ break;
+ }
+
+ Assert.True(t.IsCompleted);
+ Assert.False(t.IsCompletedSuccessfully);
+ Assert.True(t.IsFaulted);
+ Assert.False(t.IsCanceled);
+
+ Assert.Same(e, Assert.Throws<InvalidOperationException>(() => t.GetAwaiter().GetResult()));
+ }
+
+ [Theory]
+ [InlineData(CtorMode.Task)]
+ [InlineData(CtorMode.ValueTaskSource)]
+ public void Generic_CreateFromNotCompleted_ThenFault(CtorMode mode)
+ {
+ object completer = null;
+ ValueTask<int> t = default;
+ switch (mode)
+ {
+ case CtorMode.Task:
+ var tcs = new TaskCompletionSource<int>();
+ t = new ValueTask<int>(tcs.Task);
+ completer = tcs;
+ break;
+
+ case CtorMode.ValueTaskSource:
+ var mre = new ManualResetValueTaskSource<int>();
+ t = new ValueTask<int>(mre, 0);
+ completer = mre;
+ break;
+ }
+
+ Assert.False(t.IsCompleted);
+ Assert.False(t.IsCompletedSuccessfully);
+ Assert.False(t.IsFaulted);
+ Assert.False(t.IsCanceled);
+
+ Exception e = new InvalidOperationException();
+
+ switch (mode)
+ {
+ case CtorMode.Task:
+ ((TaskCompletionSource<int>)completer).SetException(e);
+ break;
+
+ case CtorMode.ValueTaskSource:
+ ((ManualResetValueTaskSource<int>)completer).SetException(e);
+ break;
+ }
+
+ Assert.True(t.IsCompleted);
+ Assert.False(t.IsCompletedSuccessfully);
+ Assert.True(t.IsFaulted);
+ Assert.False(t.IsCanceled);
+
+ Assert.Same(e, Assert.Throws<InvalidOperationException>(() => t.Result));
+ Assert.Same(e, Assert.Throws<InvalidOperationException>(() => t.GetAwaiter().GetResult()));
+ }
+
+ [Theory]
+ [InlineData(CtorMode.Task)]
+ [InlineData(CtorMode.ValueTaskSource)]
+ public void NonGeneric_CreateFromFaulted_IsFaulted(CtorMode mode)
+ {
+ InvalidOperationException e = new InvalidOperationException();
+ ValueTask t = mode == CtorMode.Task ? new ValueTask(Task.FromException(e)) : new ValueTask(ManualResetValueTaskSource.Completed<int>(0, e), 0);
+
+ Assert.True(t.IsCompleted);
+ Assert.False(t.IsCompletedSuccessfully);
+ Assert.True(t.IsFaulted);
+ Assert.False(t.IsCanceled);
+
+ Assert.Same(e, Assert.Throws<InvalidOperationException>(() => t.GetAwaiter().GetResult()));
+ }
+
+ [Theory]
+ [InlineData(CtorMode.Task)]
+ [InlineData(CtorMode.ValueTaskSource)]
+ public void Generic_CreateFromFaulted_IsFaulted(CtorMode mode)
+ {
+ InvalidOperationException e = new InvalidOperationException();
+ ValueTask<int> t = mode == CtorMode.Task ? new ValueTask<int>(Task.FromException<int>(e)) : new ValueTask<int>(ManualResetValueTaskSource.Completed<int>(0, e), 0);
+
+ Assert.True(t.IsCompleted);
+ Assert.False(t.IsCompletedSuccessfully);
+ Assert.True(t.IsFaulted);
+ Assert.False(t.IsCanceled);
+
+ Assert.Same(e, Assert.Throws<InvalidOperationException>(() => t.Result));
+ Assert.Same(e, Assert.Throws<InvalidOperationException>(() => t.GetAwaiter().GetResult()));
+ }
+
[Fact]
- public void CreateFromNullTask_Throws()
+ public void NonGeneric_CreateFromNullTask_Throws()
{
- Assert.Throws<ArgumentNullException>(() => new ValueTask<int>((Task<int>)null));
- Assert.Throws<ArgumentNullException>(() => new ValueTask<string>((Task<string>)null));
+ AssertExtensions.Throws<ArgumentNullException>("task", () => new ValueTask((Task)null));
+ AssertExtensions.Throws<ArgumentNullException>("source", () => new ValueTask((IValueTaskSource)null, 0));
}
[Fact]
- public void CreateFromTask_AsTaskIdempotent()
+ public void Generic_CreateFromNullTask_Throws()
+ {
+ AssertExtensions.Throws<ArgumentNullException>("task", () => new ValueTask<int>((Task<int>)null));
+ AssertExtensions.Throws<ArgumentNullException>("task", () => new ValueTask<string>((Task<string>)null));
+
+ AssertExtensions.Throws<ArgumentNullException>("source", () => new ValueTask<int>((IValueTaskSource<int>)null, 0));
+ AssertExtensions.Throws<ArgumentNullException>("source", () => new ValueTask<string>((IValueTaskSource<string>)null, 0));
+ }
+
+ [Fact]
+ public void NonGeneric_CreateFromTask_AsTaskIdempotent()
+ {
+ Task source = Task.FromResult(42);
+ var t = new ValueTask(source);
+ Assert.Same(source, t.AsTask());
+ Assert.Same(t.AsTask(), t.AsTask());
+ }
+
+ [Fact]
+ public void Generic_CreateFromTask_AsTaskIdempotent()
{
Task<int> source = Task.FromResult(42);
- ValueTask<int> t = new ValueTask<int>(source);
+ var t = new ValueTask<int>(source);
Assert.Same(source, t.AsTask());
Assert.Same(t.AsTask(), t.AsTask());
}
[Fact]
- public void CreateFromValue_AsTaskNotIdempotent()
+ public void NonGeneric_CreateFromDefault_AsTaskIdempotent()
+ {
+ var t = new ValueTask();
+ Assert.Same(t.AsTask(), t.AsTask());
+ }
+
+ [Fact]
+ public void Generic_CreateFromValue_AsTaskNotIdempotent()
{
- ValueTask<int> t = new ValueTask<int>(42);
+ var t = new ValueTask<int>(42);
Assert.NotSame(Task.FromResult(42), t.AsTask());
Assert.NotSame(t.AsTask(), t.AsTask());
}
[Fact]
- public async Task CreateFromValue_Await()
+ public void NonGeneric_CreateFromValueTaskSource_AsTaskIdempotent() // validates unsupported behavior specific to the backing IValueTaskSource
{
- ValueTask<int> t = new ValueTask<int>(42);
- Assert.Equal(42, await t);
- Assert.Equal(42, await t.ConfigureAwait(false));
- Assert.Equal(42, await t.ConfigureAwait(true));
+ var vt = new ValueTask(ManualResetValueTaskSource.Completed<int>(42, null), 0);
+ Task t = vt.AsTask();
+ Assert.NotNull(t);
+ Assert.Same(t, vt.AsTask());
+ Assert.Same(Task.CompletedTask, vt.AsTask());
}
[Fact]
- public async Task CreateFromTask_Await_Normal()
+ public void Generic_CreateFromValueTaskSource_AsTaskNotIdempotent() // validates unsupported behavior specific to the backing IValueTaskSource
+ {
+ var t = new ValueTask<int>(ManualResetValueTaskSource.Completed<int>(42, null), 0);
+ Assert.NotSame(Task.FromResult(42), t.AsTask());
+ Assert.NotSame(t.AsTask(), t.AsTask());
+ }
+
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task NonGeneric_CreateFromValueTaskSource_Success(bool sync)
+ {
+ var vt = new ValueTask(sync ? ManualResetValueTaskSource.Completed(0) : ManualResetValueTaskSource.Delay(1, 0), 0);
+ Task t = vt.AsTask();
+ if (sync)
+ {
+ Assert.True(t.Status == TaskStatus.RanToCompletion);
+ }
+ await t;
+ }
+
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task Generic_CreateFromValueTaskSource_Success(bool sync)
{
- Task<int> source = Task.Delay(1).ContinueWith(_ => 42);
- ValueTask<int> t = new ValueTask<int>(source);
+ var vt = new ValueTask<int>(sync ? ManualResetValueTaskSource.Completed(42) : ManualResetValueTaskSource.Delay(1, 42), 0);
+ Task<int> t = vt.AsTask();
+ if (sync)
+ {
+ Assert.True(t.Status == TaskStatus.RanToCompletion);
+ }
Assert.Equal(42, await t);
}
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task NonGeneric_CreateFromValueTaskSource_Faulted(bool sync)
+ {
+ var vt = new ValueTask(sync ? ManualResetValueTaskSource.Completed(0, new FormatException()) : ManualResetValueTaskSource.Delay(1, 0, new FormatException()), 0);
+ Task t = vt.AsTask();
+ if (sync)
+ {
+ Assert.True(t.IsFaulted);
+ Assert.IsType<FormatException>(t.Exception.InnerException);
+ }
+ else
+ {
+ await Assert.ThrowsAsync<FormatException>(() => t);
+ }
+ }
+
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task Generic_CreateFromValueTaskSource_Faulted(bool sync)
+ {
+ var vt = new ValueTask<int>(sync ? ManualResetValueTaskSource.Completed(0, new FormatException()) : ManualResetValueTaskSource.Delay(1, 0, new FormatException()), 0);
+ Task<int> t = vt.AsTask();
+ if (sync)
+ {
+ Assert.True(t.IsFaulted);
+ Assert.IsType<FormatException>(t.Exception.InnerException);
+ }
+ else
+ {
+ await Assert.ThrowsAsync<FormatException>(() => t);
+ }
+ }
+
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task NonGeneric_CreateFromValueTaskSource_Canceled(bool sync)
+ {
+ var vt = new ValueTask(sync ? ManualResetValueTaskSource.Completed(0, new OperationCanceledException()) : ManualResetValueTaskSource.Delay(1, 0, new OperationCanceledException()), 0);
+ Task t = vt.AsTask();
+ if (sync)
+ {
+ Assert.True(t.IsCanceled);
+ }
+ else
+ {
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(() => t);
+ Assert.True(t.IsCanceled);
+ }
+ }
+
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task Generic_CreateFromValueTaskSource_Canceled(bool sync)
+ {
+ var vt = new ValueTask<int>(sync ? ManualResetValueTaskSource.Completed(0, new OperationCanceledException()) : ManualResetValueTaskSource.Delay(1, 0, new OperationCanceledException()), 0);
+ Task<int> t = vt.AsTask();
+ if (sync)
+ {
+ Assert.True(t.IsCanceled);
+ }
+ else
+ {
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(() => t);
+ Assert.True(t.IsCanceled);
+ }
+ }
+
+ [Fact]
+ public void NonGeneric_Preserve_FromResult_NoChanges()
+ {
+ ValueTask vt1 = default;
+ ValueTask vt2 = vt1.Preserve();
+ Assert.True(vt1 == vt2);
+ }
+
+ [Fact]
+ public void NonGeneric_Preserve_FromTask_EqualityMaintained()
+ {
+ ValueTask vt1 = new ValueTask(Task.FromResult(42));
+ ValueTask vt2 = vt1.Preserve();
+ Assert.True(vt1 == vt2);
+ }
+
+ [Fact]
+ public void NonGeneric_Preserve_FromValueTaskSource_TransitionedToTask()
+ {
+ ValueTask vt1 = new ValueTask(ManualResetValueTaskSource.Completed(42), 0);
+ ValueTask vt2 = vt1.Preserve();
+ ValueTask vt3 = vt2.Preserve();
+ Assert.True(vt1 != vt2);
+ Assert.True(vt2 == vt3);
+ Assert.Same(vt2.AsTask(), vt2.AsTask());
+ }
+
[Fact]
- public async Task CreateFromTask_Await_ConfigureAwaitFalse()
+ public void Generic_Preserve_FromResult_EqualityMaintained()
{
- Task<int> source = Task.Delay(1).ContinueWith(_ => 42);
- ValueTask<int> t = new ValueTask<int>(source);
- Assert.Equal(42, await t.ConfigureAwait(false));
+ ValueTask<int> vt1 = new ValueTask<int>(42);
+ ValueTask<int> vt2 = vt1.Preserve();
+ Assert.True(vt1 == vt2);
}
[Fact]
- public async Task CreateFromTask_Await_ConfigureAwaitTrue()
+ public void Generic_Preserve_FromTask_EqualityMaintained()
{
- Task<int> source = Task.Delay(1).ContinueWith(_ => 42);
- ValueTask<int> t = new ValueTask<int>(source);
- Assert.Equal(42, await t.ConfigureAwait(true));
+ ValueTask<int> vt1 = new ValueTask<int>(Task.FromResult(42));
+ ValueTask<int> vt2 = vt1.Preserve();
+ Assert.True(vt1 == vt2);
}
[Fact]
- public async Task Awaiter_OnCompleted()
+ public void Generic_Preserve_FromValueTaskSource_TransitionedToTask()
{
- // Since ValueTask implements both OnCompleted and UnsafeOnCompleted,
- // OnCompleted typically won't be used by await, so we add an explicit test
- // for it here.
+ ValueTask<int> vt1 = new ValueTask<int>(ManualResetValueTaskSource.Completed(42), 0);
+ ValueTask<int> vt2 = vt1.Preserve();
+ ValueTask<int> vt3 = vt2.Preserve();
+ Assert.True(vt1 != vt2);
+ Assert.True(vt2 == vt3);
+ Assert.Same(vt2.AsTask(), vt2.AsTask());
+ }
+
+ [Theory]
+ [InlineData(CtorMode.Result)]
+ [InlineData(CtorMode.Task)]
+ [InlineData(CtorMode.ValueTaskSource)]
+ public async Task NonGeneric_CreateFromCompleted_Await(CtorMode mode)
+ {
+ ValueTask Create() =>
+ mode == CtorMode.Result ? new ValueTask() :
+ mode == CtorMode.Task ? new ValueTask(Task.FromResult(42)) :
+ new ValueTask(ManualResetValueTaskSource.Completed(0, null), 0);
+
+ int thread = Environment.CurrentManagedThreadId;
+
+ await Create();
+ Assert.Equal(thread, Environment.CurrentManagedThreadId);
+
+ await Create().ConfigureAwait(false);
+ Assert.Equal(thread, Environment.CurrentManagedThreadId);
+
+ await Create().ConfigureAwait(true);
+ Assert.Equal(thread, Environment.CurrentManagedThreadId);
+ }
+
+ [Theory]
+ [InlineData(CtorMode.Result)]
+ [InlineData(CtorMode.Task)]
+ [InlineData(CtorMode.ValueTaskSource)]
+ public async Task Generic_CreateFromCompleted_Await(CtorMode mode)
+ {
+ ValueTask<int> Create() =>
+ mode == CtorMode.Result ? new ValueTask<int>(42) :
+ mode == CtorMode.Task ? new ValueTask<int>(Task.FromResult(42)) :
+ new ValueTask<int>(ManualResetValueTaskSource.Completed(42, null), 0);
+
+ int thread = Environment.CurrentManagedThreadId;
+
+ Assert.Equal(42, await Create());
+ Assert.Equal(thread, Environment.CurrentManagedThreadId);
+
+ Assert.Equal(42, await Create().ConfigureAwait(false));
+ Assert.Equal(thread, Environment.CurrentManagedThreadId);
+
+ Assert.Equal(42, await Create().ConfigureAwait(true));
+ Assert.Equal(thread, Environment.CurrentManagedThreadId);
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task NonGeneric_CreateFromTask_Await_Normal(bool? continueOnCapturedContext)
+ {
+ var t = new ValueTask(Task.Delay(1));
+ switch (continueOnCapturedContext)
+ {
+ case null: await t; break;
+ default: await t.ConfigureAwait(continueOnCapturedContext.Value); break;
+ }
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task Generic_CreateFromTask_Await_Normal(bool? continueOnCapturedContext)
+ {
+ var t = new ValueTask<int>(Task.Delay(1).ContinueWith(_ => 42));
+ switch (continueOnCapturedContext)
+ {
+ case null: Assert.Equal(42, await t); break;
+ default: Assert.Equal(42, await t.ConfigureAwait(continueOnCapturedContext.Value)); break;
+ }
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task CreateFromValueTaskSource_Await_Normal(bool? continueOnCapturedContext)
+ {
+ var mre = new ManualResetValueTaskSource<int>();
+ var t = new ValueTask(mre, 0);
+ var ignored = Task.Delay(1).ContinueWith(_ => mre.SetResult(42));
+ switch (continueOnCapturedContext)
+ {
+ case null: await t; break;
+ default: await t.ConfigureAwait(continueOnCapturedContext.Value); break;
+ }
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task Generic_CreateFromValueTaskSource_Await_Normal(bool? continueOnCapturedContext)
+ {
+ var mre = new ManualResetValueTaskSource<int>();
+ var t = new ValueTask<int>(mre, 0);
+ var ignored = Task.Delay(1).ContinueWith(_ => mre.SetResult(42));
+ switch (continueOnCapturedContext)
+ {
+ case null: Assert.Equal(42, await t); break;
+ default: Assert.Equal(42, await t.ConfigureAwait(continueOnCapturedContext.Value)); break;
+ }
+ }
+
+ [Theory]
+ [InlineData(CtorMode.Result)]
+ [InlineData(CtorMode.Task)]
+ [InlineData(CtorMode.ValueTaskSource)]
+ public async Task NonGeneric_Awaiter_OnCompleted(CtorMode mode)
+ {
+ ValueTask t =
+ mode == CtorMode.Result ? new ValueTask() :
+ mode == CtorMode.Task ? new ValueTask(Task.CompletedTask) :
+ new ValueTask(ManualResetValueTaskSource.Completed(0, null), 0);
- ValueTask<int> t = new ValueTask<int>(42);
var tcs = new TaskCompletionSource<bool>();
t.GetAwaiter().OnCompleted(() => tcs.SetResult(true));
await tcs.Task;
}
[Theory]
- [InlineData(true)]
- [InlineData(false)]
- public async Task ConfiguredAwaiter_OnCompleted(bool continueOnCapturedContext)
+ [InlineData(CtorMode.Result)]
+ [InlineData(CtorMode.Task)]
+ [InlineData(CtorMode.ValueTaskSource)]
+ public async Task NonGeneric_Awaiter_UnsafeOnCompleted(CtorMode mode)
{
- // Since ValueTask implements both OnCompleted and UnsafeOnCompleted,
- // OnCompleted typically won't be used by await, so we add an explicit test
- // for it here.
+ ValueTask t =
+ mode == CtorMode.Result ? new ValueTask() :
+ mode == CtorMode.Task ? new ValueTask(Task.CompletedTask) :
+ new ValueTask(ManualResetValueTaskSource.Completed(0, null), 0);
+
+ var tcs = new TaskCompletionSource<bool>();
+ t.GetAwaiter().UnsafeOnCompleted(() => tcs.SetResult(true));
+ await tcs.Task;
+ }
+
+ [Theory]
+ [InlineData(CtorMode.Result)]
+ [InlineData(CtorMode.Task)]
+ [InlineData(CtorMode.ValueTaskSource)]
+ public async Task Generic_Awaiter_OnCompleted(CtorMode mode)
+ {
+ ValueTask<int> t =
+ mode == CtorMode.Result ? new ValueTask<int>(42) :
+ mode == CtorMode.Task ? new ValueTask<int>(Task.FromResult(42)) :
+ new ValueTask<int>(ManualResetValueTaskSource.Completed(42, null), 0);
+
+ var tcs = new TaskCompletionSource<bool>();
+ t.GetAwaiter().OnCompleted(() => tcs.SetResult(true));
+ await tcs.Task;
+ }
+
+ [Theory]
+ [InlineData(CtorMode.Result)]
+ [InlineData(CtorMode.Task)]
+ [InlineData(CtorMode.ValueTaskSource)]
+ public async Task Generic_Awaiter_UnsafeOnCompleted(CtorMode mode)
+ {
+ ValueTask<int> t =
+ mode == CtorMode.Result ? new ValueTask<int>(42) :
+ mode == CtorMode.Task ? new ValueTask<int>(Task.FromResult(42)) :
+ new ValueTask<int>(ManualResetValueTaskSource.Completed(42, null), 0);
+
+ var tcs = new TaskCompletionSource<bool>();
+ t.GetAwaiter().UnsafeOnCompleted(() => tcs.SetResult(true));
+ await tcs.Task;
+ }
+
+ [Theory]
+ [InlineData(CtorMode.Result, true)]
+ [InlineData(CtorMode.Task, true)]
+ [InlineData(CtorMode.ValueTaskSource, true)]
+ [InlineData(CtorMode.Result, false)]
+ [InlineData(CtorMode.Task, false)]
+ [InlineData(CtorMode.ValueTaskSource, false)]
+ public async Task NonGeneric_ConfiguredAwaiter_OnCompleted(CtorMode mode, bool continueOnCapturedContext)
+ {
+ ValueTask t =
+ mode == CtorMode.Result ? new ValueTask() :
+ mode == CtorMode.Task ? new ValueTask(Task.CompletedTask) :
+ new ValueTask(ManualResetValueTaskSource.Completed(0, null), 0);
- ValueTask<int> t = new ValueTask<int>(42);
var tcs = new TaskCompletionSource<bool>();
t.ConfigureAwait(continueOnCapturedContext).GetAwaiter().OnCompleted(() => tcs.SetResult(true));
await tcs.Task;
}
- [Fact]
- public async Task Awaiter_ContinuesOnCapturedContext()
+ [Theory]
+ [InlineData(CtorMode.Result, true)]
+ [InlineData(CtorMode.Task, true)]
+ [InlineData(CtorMode.ValueTaskSource, true)]
+ [InlineData(CtorMode.Result, false)]
+ [InlineData(CtorMode.Task, false)]
+ [InlineData(CtorMode.ValueTaskSource, false)]
+ public async Task NonGeneric_ConfiguredAwaiter_UnsafeOnCompleted(CtorMode mode, bool continueOnCapturedContext)
+ {
+ ValueTask t =
+ mode == CtorMode.Result ? new ValueTask() :
+ mode == CtorMode.Task ? new ValueTask(Task.CompletedTask) :
+ new ValueTask(ManualResetValueTaskSource.Completed(0, null), 0);
+
+ var tcs = new TaskCompletionSource<bool>();
+ t.ConfigureAwait(continueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(() => tcs.SetResult(true));
+ await tcs.Task;
+ }
+
+ [Theory]
+ [InlineData(CtorMode.Result, true)]
+ [InlineData(CtorMode.Task, true)]
+ [InlineData(CtorMode.ValueTaskSource, true)]
+ [InlineData(CtorMode.Result, false)]
+ [InlineData(CtorMode.Task, false)]
+ [InlineData(CtorMode.ValueTaskSource, false)]
+ public async Task Generic_ConfiguredAwaiter_OnCompleted(CtorMode mode, bool continueOnCapturedContext)
+ {
+ ValueTask<int> t =
+ mode == CtorMode.Result ? new ValueTask<int>(42) :
+ mode == CtorMode.Task ? new ValueTask<int>(Task.FromResult(42)) :
+ new ValueTask<int>(ManualResetValueTaskSource.Completed(42, null), 0);
+
+ var tcs = new TaskCompletionSource<bool>();
+ t.ConfigureAwait(continueOnCapturedContext).GetAwaiter().OnCompleted(() => tcs.SetResult(true));
+ await tcs.Task;
+ }
+
+ [Theory]
+ [InlineData(CtorMode.Result, true)]
+ [InlineData(CtorMode.Task, true)]
+ [InlineData(CtorMode.ValueTaskSource, true)]
+ [InlineData(CtorMode.Result, false)]
+ [InlineData(CtorMode.Task, false)]
+ [InlineData(CtorMode.ValueTaskSource, false)]
+ public async Task Generic_ConfiguredAwaiter_UnsafeOnCompleted(CtorMode mode, bool continueOnCapturedContext)
+ {
+ ValueTask<int> t =
+ mode == CtorMode.Result ? new ValueTask<int>(42) :
+ mode == CtorMode.Task ? new ValueTask<int>(Task.FromResult(42)) :
+ new ValueTask<int>(ManualResetValueTaskSource.Completed(42, null), 0);
+
+ var tcs = new TaskCompletionSource<bool>();
+ t.ConfigureAwait(continueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(() => tcs.SetResult(true));
+ await tcs.Task;
+ }
+
+ [Theory]
+ [InlineData(CtorMode.Result)]
+ [InlineData(CtorMode.Task)]
+ [InlineData(CtorMode.ValueTaskSource)]
+ public async Task NonGeneric_Awaiter_ContinuesOnCapturedContext(CtorMode mode)
{
await Task.Run(() =>
{
@@ -163,7 +776,11 @@ namespace System.Threading.Tasks.Tests
SynchronizationContext.SetSynchronizationContext(tsc);
try
{
- ValueTask<int> t = new ValueTask<int>(42);
+ ValueTask t =
+ mode == CtorMode.Result ? new ValueTask() :
+ mode == CtorMode.Task ? new ValueTask(Task.CompletedTask) :
+ new ValueTask(ManualResetValueTaskSource.Completed(0, null), 0);
+
var mres = new ManualResetEventSlim();
t.GetAwaiter().OnCompleted(() => mres.Set());
Assert.True(mres.Wait(10000));
@@ -177,9 +794,84 @@ namespace System.Threading.Tasks.Tests
}
[Theory]
- [InlineData(true)]
- [InlineData(false)]
- public async Task ConfiguredAwaiter_ContinuesOnCapturedContext(bool continueOnCapturedContext)
+ [InlineData(CtorMode.Task, false)]
+ [InlineData(CtorMode.ValueTaskSource, false)]
+ [InlineData(CtorMode.Result, true)]
+ [InlineData(CtorMode.Task, true)]
+ [InlineData(CtorMode.ValueTaskSource, true)]
+ public async Task Generic_Awaiter_ContinuesOnCapturedContext(CtorMode mode, bool sync)
+ {
+ await Task.Run(() =>
+ {
+ var tsc = new TrackingSynchronizationContext();
+ SynchronizationContext.SetSynchronizationContext(tsc);
+ try
+ {
+ ValueTask<int> t =
+ mode == CtorMode.Result ? new ValueTask<int>(42) :
+ mode == CtorMode.Task ? new ValueTask<int>(sync ? Task.FromResult(42) : Task.Delay(1).ContinueWith(_ => 42)) :
+ new ValueTask<int>(sync ? ManualResetValueTaskSource.Completed(42, null) : ManualResetValueTaskSource.Delay(1, 42, null), 0);
+
+ var mres = new ManualResetEventSlim();
+ t.GetAwaiter().OnCompleted(() => mres.Set());
+ Assert.True(mres.Wait(10000));
+ Assert.Equal(1, tsc.Posts);
+ }
+ finally
+ {
+ SynchronizationContext.SetSynchronizationContext(null);
+ }
+ });
+ }
+
+ [Theory]
+ [InlineData(CtorMode.Task, true, false)]
+ [InlineData(CtorMode.ValueTaskSource, true, false)]
+ [InlineData(CtorMode.Task, false, false)]
+ [InlineData(CtorMode.ValueTaskSource, false, false)]
+ [InlineData(CtorMode.Result, true, true)]
+ [InlineData(CtorMode.Task, true, true)]
+ [InlineData(CtorMode.ValueTaskSource, true, true)]
+ [InlineData(CtorMode.Result, false, true)]
+ [InlineData(CtorMode.Task, false, true)]
+ [InlineData(CtorMode.ValueTaskSource, false, true)]
+ public async Task NonGeneric_ConfiguredAwaiter_ContinuesOnCapturedContext(CtorMode mode, bool continueOnCapturedContext, bool sync)
+ {
+ await Task.Run(() =>
+ {
+ var tsc = new TrackingSynchronizationContext();
+ SynchronizationContext.SetSynchronizationContext(tsc);
+ try
+ {
+ ValueTask t =
+ mode == CtorMode.Result ? new ValueTask() :
+ mode == CtorMode.Task ? new ValueTask(sync ? Task.CompletedTask : Task.Delay(1)) :
+ new ValueTask(sync ? ManualResetValueTaskSource.Completed(0, null) : ManualResetValueTaskSource.Delay(42, 0, null), 0);
+
+ var mres = new ManualResetEventSlim();
+ t.ConfigureAwait(continueOnCapturedContext).GetAwaiter().OnCompleted(() => mres.Set());
+ Assert.True(mres.Wait(10000));
+ Assert.Equal(continueOnCapturedContext ? 1 : 0, tsc.Posts);
+ }
+ finally
+ {
+ SynchronizationContext.SetSynchronizationContext(null);
+ }
+ });
+ }
+
+ [Theory]
+ [InlineData(CtorMode.Task, true, false)]
+ [InlineData(CtorMode.ValueTaskSource, true, false)]
+ [InlineData(CtorMode.Task, false, false)]
+ [InlineData(CtorMode.ValueTaskSource, false, false)]
+ [InlineData(CtorMode.Result, true, true)]
+ [InlineData(CtorMode.Task, true, true)]
+ [InlineData(CtorMode.ValueTaskSource, true, true)]
+ [InlineData(CtorMode.Result, false, true)]
+ [InlineData(CtorMode.Task, false, true)]
+ [InlineData(CtorMode.ValueTaskSource, false, true)]
+ public async Task Generic_ConfiguredAwaiter_ContinuesOnCapturedContext(CtorMode mode, bool continueOnCapturedContext, bool sync)
{
await Task.Run(() =>
{
@@ -187,7 +879,11 @@ namespace System.Threading.Tasks.Tests
SynchronizationContext.SetSynchronizationContext(tsc);
try
{
- ValueTask<int> t = new ValueTask<int>(42);
+ ValueTask<int> t =
+ mode == CtorMode.Result ? new ValueTask<int>(42) :
+ mode == CtorMode.Task ? new ValueTask<int>(sync ? Task.FromResult(42) : Task.Delay(1).ContinueWith(_ => 42)) :
+ new ValueTask<int>(sync ? ManualResetValueTaskSource.Completed(42, null) : ManualResetValueTaskSource.Delay(1, 42, null), 0);
+
var mres = new ManualResetEventSlim();
t.ConfigureAwait(continueOnCapturedContext).GetAwaiter().OnCompleted(() => mres.Set());
Assert.True(mres.Wait(10000));
@@ -201,60 +897,170 @@ namespace System.Threading.Tasks.Tests
}
[Fact]
- public void GetHashCode_ContainsResult()
+ public void NonGeneric_GetHashCode_FromDefault_0()
{
- ValueTask<int> t = new ValueTask<int>(42);
- Assert.Equal(t.Result.GetHashCode(), t.GetHashCode());
+ Assert.Equal(0, new ValueTask().GetHashCode());
}
[Fact]
- public void GetHashCode_ContainsTask()
+ public void Generic_GetHashCode_FromResult_ContainsResult()
{
- ValueTask<string> t = new ValueTask<string>(Task.FromResult("42"));
- Assert.Equal(t.AsTask().GetHashCode(), t.GetHashCode());
+ var vt = new ValueTask<int>(42);
+ Assert.Equal(vt.Result.GetHashCode(), vt.GetHashCode());
+
+ var rt = new ValueTask<string>((string)null);
+ Assert.Equal(0, rt.GetHashCode());
+ rt = new ValueTask<string>("12345");
+ Assert.Equal(rt.Result.GetHashCode(), rt.GetHashCode());
+ }
+
+ [Theory]
+ [InlineData(CtorMode.Task)]
+ [InlineData(CtorMode.ValueTaskSource)]
+ public void NonGeneric_GetHashCode_FromObject_MatchesObjectHashCode(CtorMode mode)
+ {
+ object obj;
+ ValueTask vt;
+ if (mode == CtorMode.Task)
+ {
+ Task t = Task.CompletedTask;
+ vt = new ValueTask(t);
+ obj = t;
+ }
+ else
+ {
+ var t = ManualResetValueTaskSource.Completed(42, null);
+ vt = new ValueTask(t, 0);
+ obj = t;
+ }
+
+ Assert.Equal(obj.GetHashCode(), vt.GetHashCode());
+ }
+
+ [Theory]
+ [InlineData(CtorMode.Task)]
+ [InlineData(CtorMode.ValueTaskSource)]
+ public void Generic_GetHashCode_FromObject_MatchesObjectHashCode(CtorMode mode)
+ {
+ object obj;
+ ValueTask<int> vt;
+ if (mode == CtorMode.Task)
+ {
+ Task<int> t = Task.FromResult(42);
+ vt = new ValueTask<int>(t);
+ obj = t;
+ }
+ else
+ {
+ ManualResetValueTaskSource<int> t = ManualResetValueTaskSource.Completed(42, null);
+ vt = new ValueTask<int>(t, 0);
+ obj = t;
+ }
+
+ Assert.Equal(obj.GetHashCode(), vt.GetHashCode());
}
[Fact]
- public void GetHashCode_ContainsNull()
+ public void NonGeneric_OperatorEquals()
{
- ValueTask<string> t = new ValueTask<string>((string)null);
- Assert.Equal(0, t.GetHashCode());
+ var completedTcs = new TaskCompletionSource<int>();
+ completedTcs.SetResult(42);
+
+ var completedVts = ManualResetValueTaskSource.Completed(42, null);
+
+ Assert.True(new ValueTask() == new ValueTask());
+ Assert.True(new ValueTask(Task.CompletedTask) == new ValueTask(Task.CompletedTask));
+ Assert.True(new ValueTask(completedTcs.Task) == new ValueTask(completedTcs.Task));
+ Assert.True(new ValueTask(completedVts, 0) == new ValueTask(completedVts, 0));
+
+ Assert.False(new ValueTask(Task.CompletedTask) == new ValueTask(completedTcs.Task));
+ Assert.False(new ValueTask(Task.CompletedTask) == new ValueTask(completedVts, 0));
+ Assert.False(new ValueTask(completedTcs.Task) == new ValueTask(completedVts, 0));
+ Assert.False(new ValueTask(completedVts, 17) == new ValueTask(completedVts, 18));
}
[Fact]
- public void OperatorEquals()
+ public void Generic_OperatorEquals()
{
+ var completedTask = Task.FromResult(42);
+ var completedVts = ManualResetValueTaskSource.Completed(42, null);
+
Assert.True(new ValueTask<int>(42) == new ValueTask<int>(42));
- Assert.False(new ValueTask<int>(42) == new ValueTask<int>(43));
+ Assert.True(new ValueTask<int>(completedTask) == new ValueTask<int>(completedTask));
+ Assert.True(new ValueTask<int>(completedVts, 17) == new ValueTask<int>(completedVts, 17));
Assert.True(new ValueTask<string>("42") == new ValueTask<string>("42"));
Assert.True(new ValueTask<string>((string)null) == new ValueTask<string>((string)null));
+ Assert.False(new ValueTask<int>(42) == new ValueTask<int>(43));
Assert.False(new ValueTask<string>("42") == new ValueTask<string>((string)null));
Assert.False(new ValueTask<string>((string)null) == new ValueTask<string>("42"));
Assert.False(new ValueTask<int>(42) == new ValueTask<int>(Task.FromResult(42)));
Assert.False(new ValueTask<int>(Task.FromResult(42)) == new ValueTask<int>(42));
+ Assert.False(new ValueTask<int>(ManualResetValueTaskSource.Completed(42, null), 0) == new ValueTask<int>(42));
+ Assert.False(new ValueTask<int>(completedTask) == new ValueTask<int>(completedVts, 0));
+ Assert.False(new ValueTask<int>(completedVts, 17) == new ValueTask<int>(completedVts, 18));
}
[Fact]
- public void OperatorNotEquals()
+ public void NonGeneric_OperatorNotEquals()
{
+ var completedTcs = new TaskCompletionSource<int>();
+ completedTcs.SetResult(42);
+
+ var completedVts = ManualResetValueTaskSource.Completed(42, null);
+
+ Assert.False(new ValueTask() != new ValueTask());
+ Assert.False(new ValueTask(Task.CompletedTask) != new ValueTask(Task.CompletedTask));
+ Assert.False(new ValueTask(completedTcs.Task) != new ValueTask(completedTcs.Task));
+ Assert.False(new ValueTask(completedVts, 0) != new ValueTask(completedVts, 0));
+
+ Assert.True(new ValueTask(Task.CompletedTask) != new ValueTask(completedTcs.Task));
+ Assert.True(new ValueTask(Task.CompletedTask) != new ValueTask(completedVts, 0));
+ Assert.True(new ValueTask(completedTcs.Task) != new ValueTask(completedVts, 0));
+ Assert.True(new ValueTask(completedVts, 17) != new ValueTask(completedVts, 18));
+ }
+
+ [Fact]
+ public void Generic_OperatorNotEquals()
+ {
+ var completedTask = Task.FromResult(42);
+ var completedVts = ManualResetValueTaskSource.Completed(42, null);
+
Assert.False(new ValueTask<int>(42) != new ValueTask<int>(42));
- Assert.True(new ValueTask<int>(42) != new ValueTask<int>(43));
+ Assert.False(new ValueTask<int>(completedTask) != new ValueTask<int>(completedTask));
+ Assert.False(new ValueTask<int>(completedVts, 0) != new ValueTask<int>(completedVts, 0));
Assert.False(new ValueTask<string>("42") != new ValueTask<string>("42"));
Assert.False(new ValueTask<string>((string)null) != new ValueTask<string>((string)null));
+ Assert.True(new ValueTask<int>(42) != new ValueTask<int>(43));
Assert.True(new ValueTask<string>("42") != new ValueTask<string>((string)null));
Assert.True(new ValueTask<string>((string)null) != new ValueTask<string>("42"));
Assert.True(new ValueTask<int>(42) != new ValueTask<int>(Task.FromResult(42)));
Assert.True(new ValueTask<int>(Task.FromResult(42)) != new ValueTask<int>(42));
+ Assert.True(new ValueTask<int>(ManualResetValueTaskSource.Completed(42, null), 0) != new ValueTask<int>(42));
+ Assert.True(new ValueTask<int>(completedTask) != new ValueTask<int>(completedVts, 0));
+ Assert.True(new ValueTask<int>(completedVts, 17) != new ValueTask<int>(completedVts, 18));
}
[Fact]
- public void Equals_ValueTask()
+ public void NonGeneric_Equals_ValueTask()
+ {
+ Assert.True(new ValueTask().Equals(new ValueTask()));
+
+ Assert.False(new ValueTask().Equals(new ValueTask(Task.CompletedTask)));
+ Assert.False(new ValueTask(Task.CompletedTask).Equals(new ValueTask()));
+ Assert.False(new ValueTask(ManualResetValueTaskSource.Completed(42, null), 0).Equals(new ValueTask()));
+ Assert.False(new ValueTask().Equals(new ValueTask(ManualResetValueTaskSource.Completed(42, null), 0)));
+ Assert.False(new ValueTask(Task.CompletedTask).Equals(new ValueTask(ManualResetValueTaskSource.Completed(42, null), 0)));
+ Assert.False(new ValueTask(ManualResetValueTaskSource.Completed(42, null), 0).Equals(new ValueTask(Task.CompletedTask)));
+ }
+
+ [Fact]
+ public void Generic_Equals_ValueTask()
{
Assert.True(new ValueTask<int>(42).Equals(new ValueTask<int>(42)));
Assert.False(new ValueTask<int>(42).Equals(new ValueTask<int>(43)));
@@ -267,10 +1073,29 @@ namespace System.Threading.Tasks.Tests
Assert.False(new ValueTask<int>(42).Equals(new ValueTask<int>(Task.FromResult(42))));
Assert.False(new ValueTask<int>(Task.FromResult(42)).Equals(new ValueTask<int>(42)));
+ Assert.False(new ValueTask<int>(ManualResetValueTaskSource.Completed(42, null), 0).Equals(new ValueTask<int>(42)));
+ }
+
+ [Fact]
+ public void NonGeneric_Equals_Object()
+ {
+ Assert.True(new ValueTask().Equals((object)new ValueTask()));
+
+ Assert.False(new ValueTask().Equals((object)new ValueTask(Task.CompletedTask)));
+ Assert.False(new ValueTask(Task.CompletedTask).Equals((object)new ValueTask()));
+ Assert.False(new ValueTask(ManualResetValueTaskSource.Completed(42, null), 0).Equals((object)new ValueTask()));
+ Assert.False(new ValueTask().Equals((object)new ValueTask(ManualResetValueTaskSource.Completed(42, null), 0)));
+ Assert.False(new ValueTask(Task.CompletedTask).Equals((object)new ValueTask(ManualResetValueTaskSource.Completed(42, null), 0)));
+ Assert.False(new ValueTask(ManualResetValueTaskSource.Completed(42, null), 0).Equals((object)new ValueTask(Task.CompletedTask)));
+
+ Assert.False(new ValueTask().Equals(null));
+ Assert.False(new ValueTask().Equals("12345"));
+ Assert.False(new ValueTask(Task.CompletedTask).Equals("12345"));
+ Assert.False(new ValueTask(ManualResetValueTaskSource.Completed(42, null), 0).Equals("12345"));
}
[Fact]
- public void Equals_Object()
+ public void Generic_Equals_Object()
{
Assert.True(new ValueTask<int>(42).Equals((object)new ValueTask<int>(42)));
Assert.False(new ValueTask<int>(42).Equals((object)new ValueTask<int>(43)));
@@ -283,6 +1108,7 @@ namespace System.Threading.Tasks.Tests
Assert.False(new ValueTask<int>(42).Equals((object)new ValueTask<int>(Task.FromResult(42))));
Assert.False(new ValueTask<int>(Task.FromResult(42)).Equals((object)new ValueTask<int>(42)));
+ Assert.False(new ValueTask<int>(ManualResetValueTaskSource.Completed(42, null), 0).Equals((object)new ValueTask<int>(42)));
Assert.False(new ValueTask<int>(42).Equals((object)null));
Assert.False(new ValueTask<int>(42).Equals(new object()));
@@ -290,19 +1116,31 @@ namespace System.Threading.Tasks.Tests
}
[Fact]
- public void ToString_Success()
+ public void NonGeneric_ToString_Success()
+ {
+ Assert.Equal("System.Threading.Tasks.ValueTask", new ValueTask().ToString());
+ Assert.Equal("System.Threading.Tasks.ValueTask", new ValueTask(Task.CompletedTask).ToString());
+ Assert.Equal("System.Threading.Tasks.ValueTask", new ValueTask(ManualResetValueTaskSource.Completed(42, null), 0).ToString());
+ }
+
+ [Fact]
+ public void Generic_ToString_Success()
{
Assert.Equal("Hello", new ValueTask<string>("Hello").ToString());
Assert.Equal("Hello", new ValueTask<string>(Task.FromResult("Hello")).ToString());
+ Assert.Equal("Hello", new ValueTask<string>(ManualResetValueTaskSource.Completed("Hello", null), 0).ToString());
Assert.Equal("42", new ValueTask<int>(42).ToString());
Assert.Equal("42", new ValueTask<int>(Task.FromResult(42)).ToString());
+ Assert.Equal("42", new ValueTask<int>(ManualResetValueTaskSource.Completed(42, null), 0).ToString());
Assert.Same(string.Empty, new ValueTask<string>(string.Empty).ToString());
Assert.Same(string.Empty, new ValueTask<string>(Task.FromResult(string.Empty)).ToString());
+ Assert.Same(string.Empty, new ValueTask<string>(ManualResetValueTaskSource.Completed(string.Empty, null), 0).ToString());
Assert.Same(string.Empty, new ValueTask<string>(Task.FromException<string>(new InvalidOperationException())).ToString());
Assert.Same(string.Empty, new ValueTask<string>(Task.FromException<string>(new OperationCanceledException())).ToString());
+ Assert.Same(string.Empty, new ValueTask<string>(ManualResetValueTaskSource.Completed<string>(null, new InvalidOperationException()), 0).ToString());
Assert.Same(string.Empty, new ValueTask<string>(Task.FromCanceled<string>(new CancellationToken(true))).ToString());
@@ -310,15 +1148,28 @@ namespace System.Threading.Tasks.Tests
Assert.Same(string.Empty, default(ValueTask<string>).ToString());
Assert.Same(string.Empty, new ValueTask<string>((string)null).ToString());
Assert.Same(string.Empty, new ValueTask<string>(Task.FromResult<string>(null)).ToString());
+ Assert.Same(string.Empty, new ValueTask<string>(ManualResetValueTaskSource.Completed<string>(null, null), 0).ToString());
Assert.Same(string.Empty, new ValueTask<DateTime>(new TaskCompletionSource<DateTime>().Task).ToString());
}
[Theory]
+ [InlineData(typeof(ValueTask))]
+ public void NonGeneric_AsyncMethodBuilderAttribute_ValueTaskAttributed(Type valueTaskType)
+ {
+ CustomAttributeData cad = valueTaskType.GetTypeInfo().CustomAttributes.Single(attr => attr.AttributeType == typeof(AsyncMethodBuilderAttribute));
+ Type builderTypeCtorArg = (Type)cad.ConstructorArguments[0].Value;
+ Assert.Equal(typeof(AsyncValueTaskMethodBuilder), builderTypeCtorArg);
+
+ AsyncMethodBuilderAttribute amba = valueTaskType.GetTypeInfo().GetCustomAttribute<AsyncMethodBuilderAttribute>();
+ Assert.Equal(builderTypeCtorArg, amba.BuilderType);
+ }
+
+ [Theory]
[InlineData(typeof(ValueTask<>))]
[InlineData(typeof(ValueTask<int>))]
[InlineData(typeof(ValueTask<string>))]
- public void AsyncMethodBuilderAttribute_ValueTaskAttributed(Type valueTaskType)
+ public void Generic_AsyncMethodBuilderAttribute_ValueTaskAttributed(Type valueTaskType)
{
CustomAttributeData cad = valueTaskType.GetTypeInfo().CustomAttributes.Single(attr => attr.AttributeType == typeof(AsyncMethodBuilderAttribute));
Type builderTypeCtorArg = (Type)cad.ConstructorArguments[0].Value;
@@ -328,6 +1179,88 @@ namespace System.Threading.Tasks.Tests
Assert.Equal(builderTypeCtorArg, amba.BuilderType);
}
+ [Fact]
+ public void NonGeneric_AsTask_ValueTaskSourcePassesInvalidStateToOnCompleted_Throws()
+ {
+ void Validate(IValueTaskSource vts)
+ {
+ var vt = new ValueTask(vts, 0);
+ Assert.Throws<ArgumentOutOfRangeException>(() => { vt.AsTask(); });
+ }
+
+ Validate(new DelegateValueTaskSource<int> { OnCompletedFunc = (continuation, state, token, flags) => continuation(null) });
+ Validate(new DelegateValueTaskSource<int> { OnCompletedFunc = (continuation, state, token, flags) => continuation(new object()) });
+ Validate(new DelegateValueTaskSource<int> { OnCompletedFunc = (continuation, state, token, flags) => { continuation(state); continuation(state); } });
+ }
+
+ [Fact]
+ public void Generic_AsTask_ValueTaskSourcePassesInvalidStateToOnCompleted_Throws()
+ {
+ void Validate(IValueTaskSource<int> vts)
+ {
+ var vt = new ValueTask<int>(vts, 0);
+ Assert.Throws<ArgumentOutOfRangeException>(() => { vt.AsTask(); });
+ }
+
+ Validate(new DelegateValueTaskSource<int> { OnCompletedFunc = (continuation, state, token, flags) => continuation(null) });
+ Validate(new DelegateValueTaskSource<int> { OnCompletedFunc = (continuation, state, token, flags) => continuation(new object()) });
+ Validate(new DelegateValueTaskSource<int> { OnCompletedFunc = (continuation, state, token, flags) => { continuation(state); continuation(state); } });
+ }
+
+ [Fact]
+ public void NonGeneric_OnCompleted_ValueTaskSourcePassesInvalidStateToOnCompleted_Throws()
+ {
+ void Validate(IValueTaskSource vts)
+ {
+ var vt = new ValueTask(vts, 0);
+ Assert.Throws<ArgumentOutOfRangeException>(() => vt.GetAwaiter().OnCompleted(() => { }));
+ Assert.Throws<ArgumentOutOfRangeException>(() => vt.GetAwaiter().UnsafeOnCompleted(() => { }));
+ foreach (bool continueOnCapturedContext in new[] { true, false })
+ {
+ Assert.Throws<ArgumentOutOfRangeException>(() => vt.ConfigureAwait(false).GetAwaiter().OnCompleted(() => { }));
+ Assert.Throws<ArgumentOutOfRangeException>(() => vt.ConfigureAwait(false).GetAwaiter().UnsafeOnCompleted(() => { }));
+ }
+ }
+
+ Validate(new DelegateValueTaskSource<int> { OnCompletedFunc = (continuation, state, token, flags) => continuation(null) });
+ Validate(new DelegateValueTaskSource<int> { OnCompletedFunc = (continuation, state, token, flags) => continuation(new object()) });
+ }
+
+ [Fact]
+ public void Generic_OnCompleted_ValueTaskSourcePassesInvalidStateToOnCompleted_Throws()
+ {
+ void Validate(IValueTaskSource<int> vts)
+ {
+ var vt = new ValueTask<int>(vts, 0);
+ Assert.Throws<ArgumentOutOfRangeException>(() => vt.GetAwaiter().OnCompleted(() => { }));
+ Assert.Throws<ArgumentOutOfRangeException>(() => vt.GetAwaiter().UnsafeOnCompleted(() => { }));
+ foreach (bool continueOnCapturedContext in new[] { true, false })
+ {
+ Assert.Throws<ArgumentOutOfRangeException>(() => vt.ConfigureAwait(false).GetAwaiter().OnCompleted(() => { }));
+ Assert.Throws<ArgumentOutOfRangeException>(() => vt.ConfigureAwait(false).GetAwaiter().UnsafeOnCompleted(() => { }));
+ }
+ }
+
+ Validate(new DelegateValueTaskSource<int> { OnCompletedFunc = (continuation, state, token, flags) => continuation(null) });
+ Validate(new DelegateValueTaskSource<int> { OnCompletedFunc = (continuation, state, token, flags) => continuation(new object()) });
+ }
+
+ private sealed class DelegateValueTaskSource<T> : IValueTaskSource, IValueTaskSource<T>
+ {
+ public Func<short, ValueTaskSourceStatus> GetStatusFunc = null;
+ public Action<short> GetResultAction = null;
+ public Func<short, T> GetResultFunc = null;
+ public Action<Action<object>, object, short, ValueTaskSourceOnCompletedFlags> OnCompletedFunc;
+
+ public ValueTaskSourceStatus GetStatus(short token) => GetStatusFunc?.Invoke(token) ?? ValueTaskSourceStatus.Pending;
+
+ public void GetResult(short token) => GetResultAction?.Invoke(token);
+ T IValueTaskSource<T>.GetResult(short token) => GetResultFunc != null ? GetResultFunc(token) : default;
+
+ public void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) =>
+ OnCompletedFunc?.Invoke(continuation, state, token, flags);
+ }
+
private sealed class TrackingSynchronizationContext : SynchronizationContext
{
internal int Posts { get; set; }
diff --git a/src/System.Threading.Tasks.Parallel/src/System/Threading/Tasks/ParallelETWProvider.cs b/src/System.Threading.Tasks.Parallel/src/System/Threading/Tasks/ParallelETWProvider.cs
index 66869e80e4..3f3f6ecd46 100644
--- a/src/System.Threading.Tasks.Parallel/src/System/Threading/Tasks/ParallelETWProvider.cs
+++ b/src/System.Threading.Tasks.Parallel/src/System/Threading/Tasks/ParallelETWProvider.cs
@@ -113,18 +113,36 @@ namespace System.Threading.Tasks
{
EventData* eventPayload = stackalloc EventData[6];
- eventPayload[0].Size = sizeof(Int32);
- eventPayload[0].DataPointer = ((IntPtr)(&OriginatingTaskSchedulerID));
- eventPayload[1].Size = sizeof(Int32);
- eventPayload[1].DataPointer = ((IntPtr)(&OriginatingTaskID));
- eventPayload[2].Size = sizeof(Int32);
- eventPayload[2].DataPointer = ((IntPtr)(&ForkJoinContextID));
- eventPayload[3].Size = sizeof(Int32);
- eventPayload[3].DataPointer = ((IntPtr)(&OperationType));
- eventPayload[4].Size = sizeof(Int64);
- eventPayload[4].DataPointer = ((IntPtr)(&InclusiveFrom));
- eventPayload[5].Size = sizeof(Int64);
- eventPayload[5].DataPointer = ((IntPtr)(&ExclusiveTo));
+ eventPayload[0] = new EventData
+ {
+ Size = sizeof(Int32),
+ DataPointer = ((IntPtr)(&OriginatingTaskSchedulerID))
+ };
+ eventPayload[1] = new EventData
+ {
+ Size = sizeof(Int32),
+ DataPointer = ((IntPtr)(&OriginatingTaskID))
+ };
+ eventPayload[2] = new EventData
+ {
+ Size = sizeof(Int32),
+ DataPointer = ((IntPtr)(&ForkJoinContextID))
+ };
+ eventPayload[3] = new EventData
+ {
+ Size = sizeof(Int32),
+ DataPointer = ((IntPtr)(&OperationType))
+ };
+ eventPayload[4] = new EventData
+ {
+ Size = sizeof(Int64),
+ DataPointer = ((IntPtr)(&InclusiveFrom))
+ };
+ eventPayload[5] = new EventData
+ {
+ Size = sizeof(Int64),
+ DataPointer = ((IntPtr)(&ExclusiveTo))
+ };
WriteEventCore(PARALLELLOOPBEGIN_ID, 6, eventPayload);
}
@@ -153,14 +171,26 @@ namespace System.Threading.Tasks
{
EventData* eventPayload = stackalloc EventData[4];
- eventPayload[0].Size = sizeof(Int32);
- eventPayload[0].DataPointer = ((IntPtr)(&OriginatingTaskSchedulerID));
- eventPayload[1].Size = sizeof(Int32);
- eventPayload[1].DataPointer = ((IntPtr)(&OriginatingTaskID));
- eventPayload[2].Size = sizeof(Int32);
- eventPayload[2].DataPointer = ((IntPtr)(&ForkJoinContextID));
- eventPayload[3].Size = sizeof(Int64);
- eventPayload[3].DataPointer = ((IntPtr)(&TotalIterations));
+ eventPayload[0] = new EventData
+ {
+ Size = sizeof(Int32),
+ DataPointer = ((IntPtr)(&OriginatingTaskSchedulerID))
+ };
+ eventPayload[1] = new EventData
+ {
+ Size = sizeof(Int32),
+ DataPointer = ((IntPtr)(&OriginatingTaskID))
+ };
+ eventPayload[2] = new EventData
+ {
+ Size = sizeof(Int32),
+ DataPointer = ((IntPtr)(&ForkJoinContextID))
+ };
+ eventPayload[3] = new EventData
+ {
+ Size = sizeof(Int64),
+ DataPointer = ((IntPtr)(&TotalIterations))
+ };
WriteEventCore(PARALLELLOOPEND_ID, 4, eventPayload);
}
@@ -189,16 +219,31 @@ namespace System.Threading.Tasks
{
EventData* eventPayload = stackalloc EventData[5];
- eventPayload[0].Size = sizeof(Int32);
- eventPayload[0].DataPointer = ((IntPtr)(&OriginatingTaskSchedulerID));
- eventPayload[1].Size = sizeof(Int32);
- eventPayload[1].DataPointer = ((IntPtr)(&OriginatingTaskID));
- eventPayload[2].Size = sizeof(Int32);
- eventPayload[2].DataPointer = ((IntPtr)(&ForkJoinContextID));
- eventPayload[3].Size = sizeof(Int32);
- eventPayload[3].DataPointer = ((IntPtr)(&OperationType));
- eventPayload[4].Size = sizeof(Int32);
- eventPayload[4].DataPointer = ((IntPtr)(&ActionCount));
+ eventPayload[0] = new EventData
+ {
+ Size = sizeof(Int32),
+ DataPointer = ((IntPtr)(&OriginatingTaskSchedulerID))
+ };
+ eventPayload[1] = new EventData
+ {
+ Size = sizeof(Int32),
+ DataPointer = ((IntPtr)(&OriginatingTaskID))
+ };
+ eventPayload[2] = new EventData
+ {
+ Size = sizeof(Int32),
+ DataPointer = ((IntPtr)(&ForkJoinContextID))
+ };
+ eventPayload[3] = new EventData
+ {
+ Size = sizeof(Int32),
+ DataPointer = ((IntPtr)(&OperationType))
+ };
+ eventPayload[4] = new EventData
+ {
+ Size = sizeof(Int32),
+ DataPointer = ((IntPtr)(&ActionCount))
+ };
WriteEventCore(PARALLELINVOKEBEGIN_ID, 5, eventPayload);
}
diff --git a/src/System.Threading.Tasks/ref/System.Threading.Tasks.cs b/src/System.Threading.Tasks/ref/System.Threading.Tasks.cs
index 91dda148e3..3049cab881 100644
--- a/src/System.Threading.Tasks/ref/System.Threading.Tasks.cs
+++ b/src/System.Threading.Tasks/ref/System.Threading.Tasks.cs
@@ -116,6 +116,7 @@ namespace System.Threading.Tasks
public TaskCanceledException() { }
public TaskCanceledException(string message) { }
public TaskCanceledException(string message, System.Exception innerException) { }
+ public TaskCanceledException(string message, System.Exception innerException, System.Threading.CancellationToken token) : base(message, innerException, token) { }
public TaskCanceledException(System.Threading.Tasks.Task task) { }
protected TaskCanceledException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }
public System.Threading.Tasks.Task Task { get { throw null; } }
diff --git a/src/System.Threading.Tasks/tests/System.Runtime.CompilerServices/AsyncTaskMethodBuilderTests.cs b/src/System.Threading.Tasks/tests/System.Runtime.CompilerServices/AsyncTaskMethodBuilderTests.cs
index c61e8f5e75..79f4c34171 100644
--- a/src/System.Threading.Tasks/tests/System.Runtime.CompilerServices/AsyncTaskMethodBuilderTests.cs
+++ b/src/System.Threading.Tasks/tests/System.Runtime.CompilerServices/AsyncTaskMethodBuilderTests.cs
@@ -375,6 +375,16 @@ namespace System.Threading.Tasks.Tests
TaskMethodBuilderT_UsesCompletedCache(result, shouldBeCached);
}
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "https://github.com/dotnet/coreclr/pull/16588")]
+ [Fact]
+ [ActiveIssue("TFS 450361 - Codegen optimization issue", TargetFrameworkMonikers.UapAot)]
+ public static void TaskMethodBuilderDecimal_DoesntUseCompletedCache()
+ {
+ TaskMethodBuilderT_UsesCompletedCache(0m, shouldBeCached: false);
+ TaskMethodBuilderT_UsesCompletedCache(0.0m, shouldBeCached: false);
+ TaskMethodBuilderT_UsesCompletedCache(42m, shouldBeCached: false);
+ }
+
[Theory]
[InlineData((string)null, true)]
[InlineData("test", false)]
@@ -393,6 +403,11 @@ namespace System.Threading.Tasks.Tests
atmb2.SetResult(result);
Assert.Equal(shouldBeCached, object.ReferenceEquals(atmb1.Task, atmb2.Task));
+ if (result != null)
+ {
+ Assert.Equal(result.ToString(), atmb1.Task.Result.ToString());
+ Assert.Equal(result.ToString(), atmb2.Task.Result.ToString());
+ }
}
[Fact]
@@ -529,7 +544,7 @@ namespace System.Threading.Tasks.Tests
{
Assert.NotNull(e);
Assert.NotNull(e.StackTrace);
- Assert.Contains("End of stack trace", e.StackTrace);
+ Assert.Matches(@"---.+---", e.StackTrace);
}
private class TrackOperationsSynchronizationContext : SynchronizationContext
diff --git a/src/System.Threading.Tasks/tests/System.Runtime.CompilerServices/TaskAwaiterTests.cs b/src/System.Threading.Tasks/tests/System.Runtime.CompilerServices/TaskAwaiterTests.cs
index e4b12e36c8..06da40cc18 100644
--- a/src/System.Threading.Tasks/tests/System.Runtime.CompilerServices/TaskAwaiterTests.cs
+++ b/src/System.Threading.Tasks/tests/System.Runtime.CompilerServices/TaskAwaiterTests.cs
@@ -124,6 +124,53 @@ namespace System.Threading.Tasks.Tests
}
[Fact]
+ public async Task Await_TaskCompletesOnNonDefaultSyncCtx_ContinuesOnDefaultSyncCtx()
+ {
+ await Task.Run(async delegate // escape xunit's sync context
+ {
+ Assert.Null(SynchronizationContext.Current);
+ Assert.Same(TaskScheduler.Default, TaskScheduler.Current);
+
+ var ctx = new ValidateCorrectContextSynchronizationContext();
+ var tcs = new TaskCompletionSource<bool>();
+ var ignored = Task.Delay(1).ContinueWith(_ =>
+ {
+ SynchronizationContext orig = SynchronizationContext.Current;
+ SynchronizationContext.SetSynchronizationContext(ctx);
+ try
+ {
+ tcs.SetResult(true);
+ }
+ finally
+ {
+ SynchronizationContext.SetSynchronizationContext(orig);
+ }
+ }, TaskScheduler.Default);
+ await tcs.Task;
+
+ Assert.Null(SynchronizationContext.Current);
+ Assert.Same(TaskScheduler.Default, TaskScheduler.Current);
+ });
+ }
+
+ [Fact]
+ public async Task Await_TaskCompletesOnNonDefaultScheduler_ContinuesOnDefaultScheduler()
+ {
+ await Task.Run(async delegate // escape xunit's sync context
+ {
+ Assert.Null(SynchronizationContext.Current);
+ Assert.Same(TaskScheduler.Default, TaskScheduler.Current);
+
+ var tcs = new TaskCompletionSource<bool>();
+ var ignored = Task.Delay(1).ContinueWith(_ => tcs.SetResult(true), new QUWITaskScheduler());
+ await tcs.Task;
+
+ Assert.Null(SynchronizationContext.Current);
+ Assert.Same(TaskScheduler.Default, TaskScheduler.Current);
+ });
+ }
+
+ [Fact]
public static void GetResult_Completed_Success()
{
Task task = Task.CompletedTask;
diff --git a/src/System.Threading.Tasks/tests/System.Threading.Tasks.Tests.csproj b/src/System.Threading.Tasks/tests/System.Threading.Tasks.Tests.csproj
index b0745a5e54..cf269e21ed 100644
--- a/src/System.Threading.Tasks/tests/System.Threading.Tasks.Tests.csproj
+++ b/src/System.Threading.Tasks/tests/System.Threading.Tasks.Tests.csproj
@@ -54,6 +54,7 @@
</ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp'">
<Compile Include="CancellationTokenTests.netcoreapp.cs" />
+ <Compile Include="Task\TaskCanceledExceptionTests.netcoreapp.cs" />
<Compile Include="Task\TaskStatusTest.netcoreapp.cs" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
diff --git a/src/System.Threading.Tasks/tests/Task/TaskCanceledExceptionTests.netcoreapp.cs b/src/System.Threading.Tasks/tests/Task/TaskCanceledExceptionTests.netcoreapp.cs
new file mode 100644
index 0000000000..a315e04097
--- /dev/null
+++ b/src/System.Threading.Tasks/tests/Task/TaskCanceledExceptionTests.netcoreapp.cs
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using Xunit;
+
+namespace System.Threading.Tasks.Tests
+{
+ public class TaskCanceledExceptionTests
+ {
+ [Fact]
+ public void TaskCanceledException_Ctor_StringExceptionToken()
+ {
+ string message = "my exception message";
+ var ioe = new InvalidOperationException();
+ var cts = new CancellationTokenSource();
+ cts.Cancel();
+
+ var tce = new TaskCanceledException(message, ioe, cts.Token);
+ Assert.Equal(message, tce.Message);
+ Assert.Null(tce.Task);
+ Assert.Same(ioe, tce.InnerException);
+ Assert.Equal(cts.Token, tce.CancellationToken);
+ }
+ }
+}
diff --git a/src/System.Threading.Thread/System.Threading.Thread.sln b/src/System.Threading.Thread/System.Threading.Thread.sln
index c69c4d62bb..587b253d3b 100644
--- a/src/System.Threading.Thread/System.Threading.Thread.sln
+++ b/src/System.Threading.Thread/System.Threading.Thread.sln
@@ -7,6 +7,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Threading.Thread.Tes
{06197EED-FF48-43F3-976D-463839D43E8C} = {06197EED-FF48-43F3-976D-463839D43E8C}
EndProjectSection
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MTAMain", "tests\MTAMain\MTAMain.csproj", "{06B19C7D-9EBE-420F-BD33-137DB18A1FEB}"
+ ProjectSection(ProjectDependencies) = postProject
+ {06197EED-FF48-43F3-976D-463839D43E8C} = {06197EED-FF48-43F3-976D-463839D43E8C}
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "STAMain", "tests\STAMain\STAMain.csproj", "{8045E634-C181-4C6C-AE48-71AC18D1C637}"
+ ProjectSection(ProjectDependencies) = postProject
+ {06197EED-FF48-43F3-976D-463839D43E8C} = {06197EED-FF48-43F3-976D-463839D43E8C}
+ EndProjectSection
+EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Threading.Thread", "src\System.Threading.Thread.csproj", "{06197EED-FF48-43F3-976D-463839D43E8C}"
ProjectSection(ProjectDependencies) = postProject
{82D06A2D-008D-4A4A-A83D-FB7F04721C87} = {82D06A2D-008D-4A4A-A83D-FB7F04721C87}
@@ -26,10 +36,18 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {33F5A50E-B823-4FDD-8571-365C909ACEAE}.Debug|Any CPU.ActiveCfg = netstandard-Debug|Any CPU
- {33F5A50E-B823-4FDD-8571-365C909ACEAE}.Debug|Any CPU.Build.0 = netstandard-Debug|Any CPU
- {33F5A50E-B823-4FDD-8571-365C909ACEAE}.Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
- {33F5A50E-B823-4FDD-8571-365C909ACEAE}.Release|Any CPU.Build.0 = netstandard-Release|Any CPU
+ {33F5A50E-B823-4FDD-8571-365C909ACEAE}.Debug|Any CPU.ActiveCfg = netcoreapp-Debug|Any CPU
+ {33F5A50E-B823-4FDD-8571-365C909ACEAE}.Debug|Any CPU.Build.0 = netcoreapp-Debug|Any CPU
+ {33F5A50E-B823-4FDD-8571-365C909ACEAE}.Release|Any CPU.ActiveCfg = netcoreapp-Release|Any CPU
+ {33F5A50E-B823-4FDD-8571-365C909ACEAE}.Release|Any CPU.Build.0 = netcoreapp-Release|Any CPU
+ {06B19C7D-9EBE-420F-BD33-137DB18A1FEB}.Debug|Any CPU.ActiveCfg = netstandard-Debug|Any CPU
+ {06B19C7D-9EBE-420F-BD33-137DB18A1FEB}.Debug|Any CPU.Build.0 = netstandard-Debug|Any CPU
+ {06B19C7D-9EBE-420F-BD33-137DB18A1FEB}.Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
+ {06B19C7D-9EBE-420F-BD33-137DB18A1FEB}.Release|Any CPU.Build.0 = netstandard-Release|Any CPU
+ {8045E634-C181-4C6C-AE48-71AC18D1C637}.Debug|Any CPU.ActiveCfg = netstandard-Debug|Any CPU
+ {8045E634-C181-4C6C-AE48-71AC18D1C637}.Debug|Any CPU.Build.0 = netstandard-Debug|Any CPU
+ {8045E634-C181-4C6C-AE48-71AC18D1C637}.Release|Any CPU.ActiveCfg = netstandard-Release|Any CPU
+ {8045E634-C181-4C6C-AE48-71AC18D1C637}.Release|Any CPU.Build.0 = netstandard-Release|Any CPU
{06197EED-FF48-43F3-976D-463839D43E8C}.Debug|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Debug|Any CPU
{06197EED-FF48-43F3-976D-463839D43E8C}.Debug|Any CPU.Build.0 = netcoreapp-Windows_NT-Debug|Any CPU
{06197EED-FF48-43F3-976D-463839D43E8C}.Release|Any CPU.ActiveCfg = netcoreapp-Windows_NT-Release|Any CPU
@@ -44,6 +62,8 @@ Global
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{33F5A50E-B823-4FDD-8571-365C909ACEAE} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
+ {06B19C7D-9EBE-420F-BD33-137DB18A1FEB} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
+ {8045E634-C181-4C6C-AE48-71AC18D1C637} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
{06197EED-FF48-43F3-976D-463839D43E8C} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD}
{82D06A2D-008D-4A4A-A83D-FB7F04721C87} = {2E666815-2EDB-464B-9DF6-380BF4789AD4}
EndGlobalSection
diff --git a/src/System.Threading.Thread/ref/System.Threading.Thread.cs b/src/System.Threading.Thread/ref/System.Threading.Thread.cs
index 561a4695ef..a7364a6def 100644
--- a/src/System.Threading.Thread/ref/System.Threading.Thread.cs
+++ b/src/System.Threading.Thread/ref/System.Threading.Thread.cs
@@ -65,6 +65,7 @@ namespace System.Threading
public System.Threading.ApartmentState GetApartmentState() { throw null; }
[System.ObsoleteAttribute("Thread.GetCompressedStack is no longer supported. Please use the System.Threading.CompressedStack class")]
public System.Threading.CompressedStack GetCompressedStack() { throw null; }
+ public static int GetCurrentProcessorId() { throw null; }
public static object GetData(System.LocalDataStoreSlot slot) { throw null; }
public static System.AppDomain GetDomain() { throw null; }
public static int GetDomainID() { throw null; }
diff --git a/src/System.Threading.Thread/src/System/Threading/Thread.cs b/src/System.Threading.Thread/src/System/Threading/Thread.cs
index f53dc42bda..c504b7c7d6 100644
--- a/src/System.Threading.Thread/src/System/Threading/Thread.cs
+++ b/src/System.Threading.Thread/src/System/Threading/Thread.cs
@@ -272,6 +272,7 @@ namespace System.Threading
throw new InvalidOperationException(SR.Thread_GetSetCompressedStack_NotSupported);
}
+ public static int GetCurrentProcessorId() => RuntimeThread.GetCurrentProcessorId();
public static AppDomain GetDomain() => AppDomain.CurrentDomain;
public static int GetDomainID() => GetDomain().Id;
public override int GetHashCode() => ManagedThreadId;
diff --git a/src/System.Threading.Thread/tests/Configurations.props b/src/System.Threading.Thread/tests/Configurations.props
index c398e42e89..f2e3342d5b 100644
--- a/src/System.Threading.Thread/tests/Configurations.props
+++ b/src/System.Threading.Thread/tests/Configurations.props
@@ -3,6 +3,8 @@
<PropertyGroup>
<BuildConfigurations>
netstandard;
+ netcoreapp;
+ uap;
</BuildConfigurations>
</PropertyGroup>
</Project> \ No newline at end of file
diff --git a/src/System.Threading.Thread/tests/System.Threading.Thread.Tests.csproj b/src/System.Threading.Thread/tests/System.Threading.Thread.Tests.csproj
index 2402a73d29..4531542b7f 100644
--- a/src/System.Threading.Thread/tests/System.Threading.Thread.Tests.csproj
+++ b/src/System.Threading.Thread/tests/System.Threading.Thread.Tests.csproj
@@ -7,12 +7,19 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netstandard-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netstandard-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netcoreapp-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netcoreapp-Release|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='uap-Debug|AnyCPU'" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='uap-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="CompressedStackTests.cs" />
<Compile Include="ExceptionTests.cs" />
<Compile Include="ThreadExceptionEventArgsTests.cs" />
<Compile Include="ThreadTests.cs" />
</ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)' != 'netstandard'">
+ <Compile Include="ThreadTests.netcoreapp.cs" />
+ </ItemGroup>
<ItemGroup>
<Compile Include="$(CommonTestPath)\System\Threading\ThreadTestHelpers.cs">
<Link>CommonTest\System\Threading\ThreadPoolHelpers.cs</Link>
diff --git a/src/System.Threading.Thread/tests/ThreadTests.cs b/src/System.Threading.Thread/tests/ThreadTests.cs
index 22f0f88e50..091ed868d4 100644
--- a/src/System.Threading.Thread/tests/ThreadTests.cs
+++ b/src/System.Threading.Thread/tests/ThreadTests.cs
@@ -18,7 +18,7 @@ namespace System.Threading.Threads.Tests
public static string HostRunnerTest = HostRunner;
}
- public static class ThreadTests
+ public static partial class ThreadTests
{
private const int UnexpectedTimeoutMilliseconds = ThreadTestHelpers.UnexpectedTimeoutMilliseconds;
private const int ExpectedTimeoutMilliseconds = ThreadTestHelpers.ExpectedTimeoutMilliseconds;
@@ -506,12 +506,43 @@ namespace System.Threading.Threads.Tests
[Fact]
public static void NameTest()
{
- var t = new Thread(() => { });
+ string name = Guid.NewGuid().ToString("N");
+ Action waitForThread;
+ var t =
+ ThreadTestHelpers.CreateGuardedThread(out waitForThread, () =>
+ {
+ var ct = Thread.CurrentThread;
+ Assert.Equal(name, ct.Name);
+ Assert.Throws<InvalidOperationException>(() => ct.Name = null);
+ Assert.Throws<InvalidOperationException>(() => ct.Name = name + "b");
+ Assert.Equal(name, ct.Name);
+ });
+ t.IsBackground = true;
Assert.Null(t.Name);
- t.Name = "a";
- Assert.Equal("a", t.Name);
- Assert.Throws<InvalidOperationException>(() => t.Name = "b");
- Assert.Equal("a", t.Name);
+ t.Name = null;
+ t.Name = null;
+ Assert.Null(t.Name);
+ t.Name = name;
+ Assert.Equal(name, t.Name);
+ Assert.Throws<InvalidOperationException>(() => t.Name = null);
+ Assert.Throws<InvalidOperationException>(() => t.Name = name + "b");
+ Assert.Equal(name, t.Name);
+ t.Start();
+ waitForThread();
+
+ ThreadTestHelpers.RunTestInBackgroundThread(() =>
+ {
+ var ct = Thread.CurrentThread;
+ Assert.Null(ct.Name);
+ ct.Name = null;
+ ct.Name = null;
+ Assert.Null(ct.Name);
+ ct.Name = name;
+ Assert.Equal(name, ct.Name);
+ Assert.Throws<InvalidOperationException>(() => ct.Name = null);
+ Assert.Throws<InvalidOperationException>(() => ct.Name = name + "b");
+ Assert.Equal(name, ct.Name);
+ });
}
[Fact]
@@ -893,7 +924,12 @@ namespace System.Threading.Threads.Tests
{
var e = new AutoResetEvent(false);
Action waitForThread;
- var t = ThreadTestHelpers.CreateGuardedThread(out waitForThread, e.CheckedWait);
+ Thread t = null;
+ t = ThreadTestHelpers.CreateGuardedThread(out waitForThread, () =>
+ {
+ e.CheckedWait();
+ Assert.Same(t, Thread.CurrentThread);
+ });
t.IsBackground = true;
Assert.Throws<InvalidOperationException>(() => t.Start(null));
Assert.Throws<InvalidOperationException>(() => t.Start(t));
@@ -915,17 +951,29 @@ namespace System.Threading.Threads.Tests
Assert.Throws<ThreadStateException>(() => t.Start(null));
Assert.Throws<ThreadStateException>(() => t.Start(t));
- t = ThreadTestHelpers.CreateGuardedThread(out waitForThread, parameter => Assert.Null(parameter));
+ t = ThreadTestHelpers.CreateGuardedThread(out waitForThread, parameter =>
+ {
+ Assert.Null(parameter);
+ Assert.Same(t, Thread.CurrentThread);
+ });
t.IsBackground = true;
t.Start();
waitForThread();
- t = ThreadTestHelpers.CreateGuardedThread(out waitForThread, parameter => Assert.Null(parameter));
+ t = ThreadTestHelpers.CreateGuardedThread(out waitForThread, parameter =>
+ {
+ Assert.Null(parameter);
+ Assert.Same(t, Thread.CurrentThread);
+ });
t.IsBackground = true;
t.Start(null);
waitForThread();
- t = ThreadTestHelpers.CreateGuardedThread(out waitForThread, parameter => Assert.Equal(t, parameter));
+ t = ThreadTestHelpers.CreateGuardedThread(out waitForThread, parameter =>
+ {
+ Assert.Same(t, parameter);
+ Assert.Same(t, Thread.CurrentThread);
+ });
t.IsBackground = true;
t.Start(t);
waitForThread();
diff --git a/src/System.Threading.Thread/tests/ThreadTests.netcoreapp.cs b/src/System.Threading.Thread/tests/ThreadTests.netcoreapp.cs
new file mode 100644
index 0000000000..79e306397a
--- /dev/null
+++ b/src/System.Threading.Thread/tests/ThreadTests.netcoreapp.cs
@@ -0,0 +1,16 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Xunit;
+
+namespace System.Threading.Threads.Tests
+{
+ public static partial class ThreadTests
+ {
+ public static void GetCurrentProcessorId()
+ {
+ Assert.True(Thread.GetCurrentProcessorId() >= 0);
+ }
+ }
+}
diff --git a/src/System.Threading.ThreadPool/ref/System.Threading.ThreadPool.cs b/src/System.Threading.ThreadPool/ref/System.Threading.ThreadPool.cs
index bb4b87c06c..7d1911d50a 100644
--- a/src/System.Threading.ThreadPool/ref/System.Threading.ThreadPool.cs
+++ b/src/System.Threading.ThreadPool/ref/System.Threading.ThreadPool.cs
@@ -23,7 +23,7 @@ namespace System.Threading
public static void GetMinThreads(out int workerThreads, out int completionPortThreads) { throw null; }
public static bool QueueUserWorkItem(System.Threading.WaitCallback callBack) { throw null; }
public static bool QueueUserWorkItem(System.Threading.WaitCallback callBack, object state) { throw null; }
- public static bool QueueUserWorkItem(System.Threading.WaitCallback callBack, object state, bool preferLocal) { throw null; }
+ public static bool QueueUserWorkItem<TState>(System.Action<TState> callBack, TState state, bool preferLocal) { throw null; }
public static System.Threading.RegisteredWaitHandle RegisterWaitForSingleObject(System.Threading.WaitHandle waitObject, System.Threading.WaitOrTimerCallback callBack, object state, int millisecondsTimeOutInterval, bool executeOnlyOnce) { throw null; }
public static System.Threading.RegisteredWaitHandle RegisterWaitForSingleObject(System.Threading.WaitHandle waitObject, System.Threading.WaitOrTimerCallback callBack, object state, long millisecondsTimeOutInterval, bool executeOnlyOnce) { throw null; }
public static System.Threading.RegisteredWaitHandle RegisterWaitForSingleObject(System.Threading.WaitHandle waitObject, System.Threading.WaitOrTimerCallback callBack, object state, System.TimeSpan timeout, bool executeOnlyOnce) { throw null; }
diff --git a/src/System.Threading.ThreadPool/src/ApiCompatBaseline.uapaot.txt b/src/System.Threading.ThreadPool/src/ApiCompatBaseline.uapaot.txt
new file mode 100644
index 0000000000..7070e8721b
--- /dev/null
+++ b/src/System.Threading.ThreadPool/src/ApiCompatBaseline.uapaot.txt
@@ -0,0 +1 @@
+MembersMustExist : Member 'System.Threading.ThreadPool.QueueUserWorkItem<TState>(System.Action<TState>, TState, System.Boolean)' does not exist in the implementation but it does exist in the contract. \ No newline at end of file
diff --git a/src/System.Threading.ThreadPool/tests/ThreadPoolTests.netcoreapp.cs b/src/System.Threading.ThreadPool/tests/ThreadPoolTests.netcoreapp.cs
index c3b9a92c3a..4aac66daed 100644
--- a/src/System.Threading.ThreadPool/tests/ThreadPoolTests.netcoreapp.cs
+++ b/src/System.Threading.ThreadPool/tests/ThreadPoolTests.netcoreapp.cs
@@ -14,7 +14,7 @@ namespace System.Threading.ThreadPools.Tests
[InlineData(true)]
public void QueueUserWorkItem_PreferLocal_InvalidArguments_Throws(bool preferLocal)
{
- Assert.Throws<ArgumentNullException>(() => ThreadPool.QueueUserWorkItem(null, new object(), preferLocal));
+ AssertExtensions.Throws<ArgumentNullException>("callBack", () => ThreadPool.QueueUserWorkItem(null, new object(), preferLocal));
}
[Theory]
@@ -23,24 +23,54 @@ namespace System.Threading.ThreadPools.Tests
public async Task QueueUserWorkItem_PreferLocal_NullValidForState(bool preferLocal)
{
var tcs = new TaskCompletionSource<int>();
- ThreadPool.QueueUserWorkItem(s =>
- {
- tcs.SetResult(84);
- }, null, preferLocal);
+ ThreadPool.QueueUserWorkItem(s => tcs.SetResult(84), (object)null, preferLocal);
Assert.Equal(84, await tcs.Task);
}
[Theory]
[InlineData(false)]
[InlineData(true)]
- public async Task QueueUserWorkItem_PreferLocal_StateObjectPassedThrough(bool preferLocal)
+ public async Task QueueUserWorkItem_PreferLocal_ReferenceTypeStateObjectPassedThrough(bool preferLocal)
{
var tcs = new TaskCompletionSource<int>();
- ThreadPool.QueueUserWorkItem(s =>
- {
- ((TaskCompletionSource<int>)s).SetResult(84);
- }, tcs, preferLocal);
+ ThreadPool.QueueUserWorkItem(s => s.SetResult(84), tcs, preferLocal);
Assert.Equal(84, await tcs.Task);
}
+
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task QueueUserWorkItem_PreferLocal_ValueTypeStateObjectPassedThrough(bool preferLocal)
+ {
+ var tcs = new TaskCompletionSource<int>();
+ ThreadPool.QueueUserWorkItem(s => s.tcs.SetResult(s.value), (tcs, value: 42), preferLocal);
+ Assert.Equal(42, await tcs.Task);
+ }
+
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task QueueUserWorkItem_PreferLocal_RunsAsynchronously(bool preferLocal)
+ {
+ await Task.Factory.StartNew(() =>
+ {
+ int origThread = Environment.CurrentManagedThreadId;
+ var tcs = new TaskCompletionSource<int>();
+ ThreadPool.QueueUserWorkItem(s => s.SetResult(Environment.CurrentManagedThreadId), tcs, preferLocal);
+ Assert.NotEqual(origThread, tcs.Task.GetAwaiter().GetResult());
+ }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
+ }
+
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task QueueUserWorkItem_PreferLocal_ExecutionContextFlowed(bool preferLocal)
+ {
+ var tcs = new TaskCompletionSource<int>();
+ var asyncLocal = new AsyncLocal<int>() { Value = 42 };
+ ThreadPool.QueueUserWorkItem(s => s.SetResult(asyncLocal.Value), tcs, preferLocal);
+ asyncLocal.Value = 0;
+ Assert.Equal(42, await tcs.Task);
+ }
}
}
diff --git a/src/System.Threading/src/System/Threading/CDSsyncETWBCLProvider.cs b/src/System.Threading/src/System/Threading/CDSsyncETWBCLProvider.cs
index 53600ee0ab..8541f941c4 100644
--- a/src/System.Threading/src/System/Threading/CDSsyncETWBCLProvider.cs
+++ b/src/System.Threading/src/System/Threading/CDSsyncETWBCLProvider.cs
@@ -76,10 +76,16 @@ namespace System.Threading
EventData* eventPayload = stackalloc EventData[2];
Int32 senseAsInt32 = currentSense ? 1 : 0; // write out Boolean as Int32
- eventPayload[0].Size = sizeof(int);
- eventPayload[0].DataPointer = ((IntPtr)(&senseAsInt32));
- eventPayload[1].Size = sizeof(long);
- eventPayload[1].DataPointer = ((IntPtr)(&phaseNum));
+ eventPayload[0] = new EventData
+ {
+ Size = sizeof(int),
+ DataPointer = ((IntPtr)(&senseAsInt32))
+ };
+ eventPayload[1] = new EventData
+ {
+ Size = sizeof(long),
+ DataPointer = ((IntPtr)(&phaseNum))
+ };
WriteEventCore(BARRIER_PHASEFINISHED_ID, 2, eventPayload);
}
diff --git a/src/System.Threading/tests/AsyncLocalTests.cs b/src/System.Threading/tests/AsyncLocalTests.cs
index b2624ae5e3..39085759ff 100644
--- a/src/System.Threading/tests/AsyncLocalTests.cs
+++ b/src/System.Threading/tests/AsyncLocalTests.cs
@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Collections.Generic;
+using System.Linq;
using System.Threading.Tasks;
using Xunit;
@@ -68,6 +70,55 @@ namespace System.Threading.Tests
Assert.Equal(local.Value, 12);
}
+ [Theory]
+ [MemberData(nameof(GetCounts))]
+ public static async Task CaptureAndRestoreNullAsyncLocals(int count)
+ {
+ AsyncLocal<object>[] locals = new AsyncLocal<object>[count];
+ for (var i = 0; i < locals.Length; i++)
+ {
+ locals[i] = new AsyncLocal<object>();
+ }
+
+ ExecutionContext ec = ExecutionContext.Capture();
+
+ ExecutionContext.Run(
+ ec,
+ _ =>
+ {
+ for (var i = 0; i < locals.Length; i++)
+ {
+ AsyncLocal<object> local = locals[i];
+
+ Assert.Null(local.Value);
+ local.Value = 56;
+ Assert.IsType<int>(local.Value);
+ Assert.Equal(56, (int)local.Value);
+ }
+ },
+ null);
+
+ for (var i = 0; i < locals.Length; i++)
+ {
+ Assert.Null(locals[i].Value);
+ }
+ }
+
+ [Fact]
+ public static async Task CaptureAndRunOnFlowSupressedContext()
+ {
+ ExecutionContext.SuppressFlow();
+ try
+ {
+ ExecutionContext ec = ExecutionContext.Capture();
+ Assert.Throws<InvalidOperationException>(() => ExecutionContext.Run(ec, _ => { }, null));
+ }
+ finally
+ {
+ ExecutionContext.RestoreFlow();
+ }
+ }
+
[Fact]
public static async Task NotifyOnValuePropertyChange()
{
@@ -365,10 +416,11 @@ namespace System.Threading.Tests
Assert.Equal(local.Value, 42);
}
- [Fact]
- public static async Task AddAndUpdateManyLocals_ValueType()
+ [Theory]
+ [MemberData(nameof(GetCounts))]
+ public static async Task AddAndUpdateManyLocals_ValueType(int count)
{
- var locals = new AsyncLocal<int>[40];
+ var locals = new AsyncLocal<int>[count];
for (int i = 0; i < locals.Length; i++)
{
locals[i] = new AsyncLocal<int>();
@@ -387,10 +439,11 @@ namespace System.Threading.Tests
}
}
- [Fact]
- public static async Task AddUpdateAndRemoveManyLocals_ReferenceType()
+ [Theory]
+ [MemberData(nameof(GetCounts))]
+ public static async Task AddUpdateAndRemoveManyLocals_ReferenceType(int count)
{
- var locals = new AsyncLocal<string>[40];
+ var locals = new AsyncLocal<string>[count];
for (int i = 0; i < locals.Length; i++)
{
@@ -419,5 +472,180 @@ namespace System.Threading.Tests
}
}
}
+
+ [Theory]
+ [MemberData(nameof(GetCounts))]
+ public static async Task AsyncLocalsUnwind(int count)
+ {
+ AsyncLocal<object>[] asyncLocals = new AsyncLocal<object>[count];
+
+ ExecutionContext Default = ExecutionContext.Capture();
+ int[] manuallySetCounts = new int[count];
+ int[] automaticallyUnsetCounts = new int[count];
+ int[] automaticallySetCounts = new int[count];
+ ExecutionContext[] capturedContexts = new ExecutionContext[count];
+
+ // Setup the AsyncLocals; capturing ExecutionContext for each level
+ await SetLocalsRecursivelyAsync(count - 1);
+
+ ValidateCounts(thresholdIndex: 0, maunalSets: 1, automaticUnsets: 1, automaticSets: 0);
+ ValidateAsyncLocalsValuesNull();
+
+ // Check Running with the contexts captured when setting the locals
+ TestCapturedExecutionContexts();
+
+ ExecutionContext.SuppressFlow();
+ try
+ {
+ // Re-check restoring, but starting with a suppressed flow
+ TestCapturedExecutionContexts();
+ }
+ finally
+ {
+ ExecutionContext.RestoreFlow();
+ }
+
+ // -- Local functions --
+ void ValidateAsyncLocalsValuesNull()
+ {
+ // Check AsyncLocals haven't leaked
+ for (int i = 0; i < asyncLocals.Length; i++)
+ {
+ Assert.Null(asyncLocals[i].Value);
+ }
+ }
+
+ void ValidateAsyncLocalsValues(int thresholdIndex)
+ {
+ for (int localsIndex = 0; localsIndex < asyncLocals.Length; localsIndex++)
+ {
+ if (localsIndex >= thresholdIndex)
+ {
+ Assert.Equal(localsIndex, (int)asyncLocals[localsIndex].Value);
+ }
+ else
+ {
+ Assert.Null(asyncLocals[localsIndex].Value);
+ }
+ }
+ }
+
+ void TestCapturedExecutionContexts()
+ {
+ for (int contextIndex = 0; contextIndex < asyncLocals.Length; contextIndex++)
+ {
+ ClearCounts();
+
+ ExecutionContext.Run(
+ capturedContexts[contextIndex].CreateCopy(),
+ (o) => TestCapturedExecutionContext((int)o),
+ contextIndex);
+
+ // Validate locals have been restored to the Default context's values
+ ValidateAsyncLocalsValuesNull();
+ }
+ }
+
+ void TestCapturedExecutionContext(int contextIndex)
+ {
+ ValidateCounts(thresholdIndex: contextIndex, maunalSets: 0, automaticUnsets: 0, automaticSets: 1);
+ // Validate locals have been restored to the outer context's values
+ ValidateAsyncLocalsValues(thresholdIndex: contextIndex);
+
+ // Validate locals are correctly reset Running with a Default context from a non-Default context
+ ExecutionContext.Run(
+ Default.CreateCopy(),
+ _ => ValidateAsyncLocalsValuesNull(),
+ null);
+
+ ValidateCounts(thresholdIndex: contextIndex, maunalSets: 0, automaticUnsets: 1, automaticSets: 2);
+ // Validate locals have been restored to the outer context's values
+ ValidateAsyncLocalsValues(thresholdIndex: contextIndex);
+
+ for (int innerContextIndex = 0; innerContextIndex < asyncLocals.Length; innerContextIndex++)
+ {
+ // Validate locals are correctly restored Running with another non-Default context from a non-Default context
+ ExecutionContext.Run(
+ capturedContexts[innerContextIndex].CreateCopy(),
+ o => ValidateAsyncLocalsValues(thresholdIndex: (int)o),
+ innerContextIndex);
+
+ // Validate locals have been restored to the outer context's values
+ ValidateAsyncLocalsValues(thresholdIndex: contextIndex);
+ }
+ }
+
+ void ValidateCounts(int thresholdIndex, int maunalSets, int automaticUnsets, int automaticSets)
+ {
+ for (int localsIndex = 0; localsIndex < asyncLocals.Length; localsIndex++)
+ {
+ Assert.Equal(localsIndex < thresholdIndex ? 0 : maunalSets, manuallySetCounts[localsIndex]);
+ Assert.Equal(localsIndex < thresholdIndex ? 0 : automaticUnsets, automaticallyUnsetCounts[localsIndex]);
+ Assert.Equal(localsIndex < thresholdIndex ? 0 : automaticSets, automaticallySetCounts[localsIndex]);
+ }
+ }
+
+ // Synchronous function is async to create different ExectutionContexts for each set, and check async unwinding
+ async Task SetLocalsRecursivelyAsync(int index)
+ {
+ // Set AsyncLocal
+ asyncLocals[index] = new AsyncLocal<object>(CountValueChanges)
+ {
+ Value = index
+ };
+
+ // Capture context with AsyncLocal set
+ capturedContexts[index] = ExecutionContext.Capture();
+
+ if (index > 0)
+ {
+ // Go deeper into async stack
+ int nextIndex = index - 1;
+ await SetLocalsRecursivelyAsync(index - 1);
+ // Set is undone by the await
+ Assert.Null(asyncLocals[nextIndex].Value);
+ }
+ }
+
+ void CountValueChanges(AsyncLocalValueChangedArgs<object> args)
+ {
+ if (!args.ThreadContextChanged)
+ {
+ // Manual create, previous should be null
+ Assert.Null(args.PreviousValue);
+ Assert.IsType<int>(args.CurrentValue);
+ manuallySetCounts[(int)args.CurrentValue]++;
+ }
+ else
+ {
+ // Automatic change, only one value should be not null
+ if (args.CurrentValue != null)
+ {
+ Assert.Null(args.PreviousValue);
+ Assert.IsType<int>(args.CurrentValue);
+ automaticallySetCounts[(int)args.CurrentValue]++;
+ }
+ else
+ {
+ Assert.Null(args.CurrentValue);
+ Assert.NotNull(args.PreviousValue);
+ Assert.IsType<int>(args.PreviousValue);
+ automaticallyUnsetCounts[(int)args.PreviousValue]++;
+ }
+ }
+ }
+
+ void ClearCounts()
+ {
+ Array.Clear(manuallySetCounts, 0, count);
+ Array.Clear(automaticallyUnsetCounts, 0, count);
+ Array.Clear(automaticallySetCounts, 0, count);
+ }
+ }
+
+ // The data structure that holds AsyncLocals changes based on size;
+ // so it needs to be tested at a variety of sizes
+ public static IEnumerable<object[]> GetCounts()
+ => Enumerable.Range(1, 40).Select(i => new object[] { i });
}
}
diff --git a/src/System.Threading/tests/MonitorTests.cs b/src/System.Threading/tests/MonitorTests.cs
index 55dd51c976..2d37c4b8c1 100644
--- a/src/System.Threading/tests/MonitorTests.cs
+++ b/src/System.Threading/tests/MonitorTests.cs
@@ -3,19 +3,20 @@
// See the LICENSE file in the project root for more information.
using System;
+using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
namespace System.Threading.Tests
{
- static partial class MonitorTests
+ public static class MonitorTests
{
private const int FailTimeoutMilliseconds = 30000;
// Attempts a single recursive acquisition/release cycle of a newly-created lock.
[Fact]
- public static void BasicRecursion(ref string message)
+ public static void BasicRecursion()
{
var obj = new object();
Assert.True(Monitor.TryEnter(obj));
@@ -32,7 +33,7 @@ namespace System.Threading.Tests
// Attempts to overflow the recursion count of a newly-created lock.
[Fact]
- public static void DeepRecursion(ref string message)
+ public static void DeepRecursion()
{
var obj = new object();
var hc = obj.GetHashCode();
@@ -51,7 +52,7 @@ namespace System.Threading.Tests
}
Monitor.Exit(obj);
- Assert.True(Monitor.IsEntered(obj));
+ Assert.False(Monitor.IsEntered(obj));
}
[Fact]
@@ -98,7 +99,7 @@ namespace System.Threading.Tests
Monitor.Enter(obj, ref lockTaken);
Assert.True(lockTaken);
Monitor.Exit(obj);
- Assert.False(lockTaken);
+ Assert.True(lockTaken);
}
[Fact]
@@ -107,13 +108,13 @@ namespace System.Threading.Tests
bool lockTaken = false;
var obj = new object();
- AssertExtensions.Throws<ArgumentNullException>("obj", () => Monitor.Enter(null));
- AssertExtensions.Throws<ArgumentNullException>("obj", () => Monitor.Enter(null, ref lockTaken));
+ Assert.Throws<ArgumentNullException>(() => Monitor.Enter(null));
+ Assert.Throws<ArgumentNullException>(() => Monitor.Enter(null, ref lockTaken));
Assert.False(lockTaken);
lockTaken = true;
AssertExtensions.Throws<ArgumentException>("lockTaken", () => Monitor.Enter(obj, ref lockTaken));
- Assert.False(lockTaken);
+ Assert.True(lockTaken);
}
[Fact]
@@ -121,7 +122,7 @@ namespace System.Threading.Tests
{
var obj = new object();
int valueType = 1;
- AssertExtensions.Throws<ArgumentNullException>("obj", () => Monitor.Exit(null));
+ Assert.Throws<ArgumentNullException>(() => Monitor.Exit(null));
Assert.Throws<SynchronizationLockException>(() => Monitor.Exit(obj));
Assert.Throws<SynchronizationLockException>(() => Monitor.Exit(new object()));
@@ -180,7 +181,7 @@ namespace System.Threading.Tests
Monitor.TryEnter(obj, ref lockTaken);
Assert.True(lockTaken);
Monitor.Exit(obj);
- Assert.False(lockTaken);
+ Assert.True(lockTaken);
}
[Fact]
@@ -189,35 +190,217 @@ namespace System.Threading.Tests
bool lockTaken = false;
var obj = new object();
- AssertExtensions.Throws<ArgumentNullException>("obj", () => Monitor.TryEnter(null));
- AssertExtensions.Throws<ArgumentNullException>("obj", () => Monitor.TryEnter(null, ref lockTaken));
- AssertExtensions.Throws<ArgumentNullException>("obj", () => Monitor.TryEnter(null, 1));
- AssertExtensions.Throws<ArgumentNullException>("obj", () => Monitor.TryEnter(null, 1, ref lockTaken));
- AssertExtensions.Throws<ArgumentNullException>("obj", () => Monitor.TryEnter(null, TimeSpan.Zero));
- AssertExtensions.Throws<ArgumentNullException>("obj", () => Monitor.TryEnter(null, TimeSpan.Zero, ref lockTaken));
+ Assert.Throws<ArgumentNullException>(() => Monitor.TryEnter(null));
+ Assert.Throws<ArgumentNullException>(() => Monitor.TryEnter(null, ref lockTaken));
+ Assert.Throws<ArgumentNullException>(() => Monitor.TryEnter(null, 1));
+ Assert.Throws<ArgumentNullException>(() => Monitor.TryEnter(null, 1, ref lockTaken));
+ Assert.Throws<ArgumentNullException>(() => Monitor.TryEnter(null, TimeSpan.Zero));
+ Assert.Throws<ArgumentNullException>(() => Monitor.TryEnter(null, TimeSpan.Zero, ref lockTaken));
- AssertExtensions.Throws<ArgumentOutOfRangeException>("millisecondsTimeout", () => Monitor.TryEnter(null, -1));
- AssertExtensions.Throws<ArgumentOutOfRangeException>("millisecondsTimeout", () => Monitor.TryEnter(null, -1, ref lockTaken));
- AssertExtensions.Throws<ArgumentOutOfRangeException>("timeout", () => Monitor.TryEnter(null, TimeSpan.FromMilliseconds(-1)));
- AssertExtensions.Throws<ArgumentOutOfRangeException>("timeout", () => Monitor.TryEnter(null, TimeSpan.FromMilliseconds(-1), ref lockTaken));
+ Assert.Throws<ArgumentOutOfRangeException>(() => Monitor.TryEnter(obj, -2));
+ Assert.Throws<ArgumentOutOfRangeException>(() => Monitor.TryEnter(obj, -2, ref lockTaken));
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("timeout", () => Monitor.TryEnter(obj, TimeSpan.FromMilliseconds(-2)));
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("timeout", () => Monitor.TryEnter(obj, TimeSpan.FromMilliseconds(-2), ref lockTaken));
lockTaken = true;
AssertExtensions.Throws<ArgumentException>("lockTaken", () => Monitor.TryEnter(obj, ref lockTaken));
- lockTaken = true;
+ Assert.True(lockTaken);
AssertExtensions.Throws<ArgumentException>("lockTaken", () => Monitor.TryEnter(obj, 0, ref lockTaken));
- lockTaken = true;
+ Assert.True(lockTaken);
AssertExtensions.Throws<ArgumentException>("lockTaken", () => Monitor.TryEnter(obj, TimeSpan.Zero, ref lockTaken));
}
[Fact]
+ public static void Enter_HasToWait()
+ {
+ var thinLock = new object();
+ var awareLock = new object();
+
+ // Actually transition the aware lock to an aware lock by having a background thread wait for a lock
+ {
+ Action waitForThread;
+ Thread t =
+ ThreadTestHelpers.CreateGuardedThread(out waitForThread, () =>
+ Assert.False(Monitor.TryEnter(awareLock, ThreadTestHelpers.ExpectedTimeoutMilliseconds)));
+ t.IsBackground = true;
+ lock (awareLock)
+ {
+ t.Start();
+ waitForThread();
+ }
+ }
+
+ // When the current thread has the lock, have background threads wait for the lock in various ways. After a short
+ // duration, release the lock and allow the background threads to acquire the lock.
+ {
+ var backgroundTestDelegates = new List<Action<object>>();
+ Barrier readyBarrier = null;
+
+ backgroundTestDelegates.Add(lockObj =>
+ {
+ readyBarrier.SignalAndWait();
+ Monitor.Enter(lockObj);
+ Monitor.Exit(lockObj);
+ });
+
+ backgroundTestDelegates.Add(lockObj =>
+ {
+ readyBarrier.SignalAndWait();
+ bool lockTaken = false;
+ Monitor.Enter(lockObj, ref lockTaken);
+ Assert.True(lockTaken);
+ Monitor.Exit(lockObj);
+ });
+
+ backgroundTestDelegates.Add(lockObj =>
+ {
+ readyBarrier.SignalAndWait();
+ lock (lockObj)
+ {
+ }
+ });
+
+ backgroundTestDelegates.Add(lockObj =>
+ {
+ readyBarrier.SignalAndWait();
+ Assert.True(Monitor.TryEnter(lockObj, ThreadTestHelpers.UnexpectedTimeoutMilliseconds));
+ Monitor.Exit(lockObj);
+ });
+
+ backgroundTestDelegates.Add(lockObj =>
+ {
+ readyBarrier.SignalAndWait();
+ Assert.True(
+ Monitor.TryEnter(lockObj, TimeSpan.FromMilliseconds(ThreadTestHelpers.UnexpectedTimeoutMilliseconds)));
+ Monitor.Exit(lockObj);
+ });
+
+ backgroundTestDelegates.Add(lockObj =>
+ {
+ readyBarrier.SignalAndWait();
+ bool lockTaken = false;
+ Monitor.TryEnter(lockObj, ThreadTestHelpers.UnexpectedTimeoutMilliseconds, ref lockTaken);
+ Assert.True(lockTaken);
+ Monitor.Exit(lockObj);
+ });
+
+ backgroundTestDelegates.Add(lockObj =>
+ {
+ readyBarrier.SignalAndWait();
+ bool lockTaken = false;
+ Monitor.TryEnter(
+ lockObj,
+ TimeSpan.FromMilliseconds(ThreadTestHelpers.UnexpectedTimeoutMilliseconds),
+ ref lockTaken);
+ Assert.True(lockTaken);
+ Monitor.Exit(lockObj);
+ });
+
+ int testCount = backgroundTestDelegates.Count * 2; // two iterations each, one for thin lock and one for aware lock
+ readyBarrier = new Barrier(testCount + 1); // plus main thread
+ var waitForThreadArray = new Action[testCount];
+ for (int i = 0; i < backgroundTestDelegates.Count; ++i)
+ {
+ int icopy = i; // for use in delegates
+ Thread t =
+ ThreadTestHelpers.CreateGuardedThread(out waitForThreadArray[i * 2],
+ () => backgroundTestDelegates[icopy](thinLock));
+ t.IsBackground = true;
+ t.Start();
+ t = ThreadTestHelpers.CreateGuardedThread(out waitForThreadArray[i * 2 + 1],
+ () => backgroundTestDelegates[icopy](awareLock));
+ t.IsBackground = true;
+ t.Start();
+ }
+
+ lock (thinLock)
+ {
+ lock (awareLock)
+ {
+ readyBarrier.SignalAndWait(ThreadTestHelpers.UnexpectedTimeoutMilliseconds);
+ Thread.Sleep(ThreadTestHelpers.ExpectedTimeoutMilliseconds);
+ }
+ }
+ foreach (Action waitForThread in waitForThreadArray)
+ waitForThread();
+ }
+
+ // When the current thread has the lock, have background threads wait for the lock in various ways and time out
+ // after a short duration
+ {
+ var backgroundTestDelegates = new List<Action<object>>();
+ Barrier readyBarrier = null;
+
+ backgroundTestDelegates.Add(lockObj =>
+ {
+ readyBarrier.SignalAndWait();
+ Assert.False(Monitor.TryEnter(lockObj, ThreadTestHelpers.ExpectedTimeoutMilliseconds));
+ });
+
+ backgroundTestDelegates.Add(lockObj =>
+ {
+ readyBarrier.SignalAndWait();
+ Assert.False(
+ Monitor.TryEnter(lockObj, TimeSpan.FromMilliseconds(ThreadTestHelpers.ExpectedTimeoutMilliseconds)));
+ });
+
+ backgroundTestDelegates.Add(lockObj =>
+ {
+ readyBarrier.SignalAndWait();
+ bool lockTaken = false;
+ Monitor.TryEnter(lockObj, ThreadTestHelpers.ExpectedTimeoutMilliseconds, ref lockTaken);
+ Assert.False(lockTaken);
+ });
+
+ backgroundTestDelegates.Add(lockObj =>
+ {
+ readyBarrier.SignalAndWait();
+ bool lockTaken = false;
+ Monitor.TryEnter(
+ lockObj,
+ TimeSpan.FromMilliseconds(ThreadTestHelpers.ExpectedTimeoutMilliseconds),
+ ref lockTaken);
+ Assert.False(lockTaken);
+ });
+
+ int testCount = backgroundTestDelegates.Count * 2; // two iterations each, one for thin lock and one for aware lock
+ readyBarrier = new Barrier(testCount + 1); // plus main thread
+ var waitForThreadArray = new Action[testCount];
+ for (int i = 0; i < backgroundTestDelegates.Count; ++i)
+ {
+ int icopy = i; // for use in delegates
+ Thread t =
+ ThreadTestHelpers.CreateGuardedThread(out waitForThreadArray[i * 2],
+ () => backgroundTestDelegates[icopy](thinLock));
+ t.IsBackground = true;
+ t.Start();
+ t = ThreadTestHelpers.CreateGuardedThread(out waitForThreadArray[i * 2 + 1],
+ () => backgroundTestDelegates[icopy](awareLock));
+ t.IsBackground = true;
+ t.Start();
+ }
+
+ lock (thinLock)
+ {
+ lock (awareLock)
+ {
+ readyBarrier.SignalAndWait(ThreadTestHelpers.UnexpectedTimeoutMilliseconds);
+ foreach (Action waitForThread in waitForThreadArray)
+ waitForThread();
+ }
+ }
+ }
+ }
+
+ [Fact]
public static void Wait_Invalid()
{
var obj = new object();
- AssertExtensions.Throws<ArgumentNullException>("obj", () => Monitor.Wait(null));
- AssertExtensions.Throws<ArgumentNullException>("obj", () => Monitor.Wait(null, 1));
- AssertExtensions.Throws<ArgumentNullException>("obj", () => Monitor.Wait(null, TimeSpan.Zero));
- AssertExtensions.Throws<ArgumentOutOfRangeException>("millisecondsTimeout", () => Monitor.Wait(null, -1));
- AssertExtensions.Throws<ArgumentOutOfRangeException>("timeout", () => Monitor.Wait(null, TimeSpan.FromMilliseconds(-1)));
+ Assert.Throws<ArgumentNullException>(() => Monitor.Wait(null));
+ Assert.Throws<ArgumentNullException>(() => Monitor.Wait(null, 1));
+ Assert.Throws<ArgumentNullException>(() => Monitor.Wait(null, TimeSpan.Zero));
+ Assert.Throws<ArgumentOutOfRangeException>(() => Monitor.Wait(obj, -2));
+ AssertExtensions.Throws<ArgumentOutOfRangeException>("timeout", () => Monitor.Wait(obj, TimeSpan.FromMilliseconds(-2)));
}
[Fact]
diff --git a/src/System.Threading/tests/SemaphoreTests.cs b/src/System.Threading/tests/SemaphoreTests.cs
index 7d88d42892..6ef952e4b6 100644
--- a/src/System.Threading/tests/SemaphoreTests.cs
+++ b/src/System.Threading/tests/SemaphoreTests.cs
@@ -290,7 +290,7 @@ namespace System.Threading.Tests
// Create the two semaphores and the other process with which to synchronize
using (var inbound = new Semaphore(1, 1, inboundName))
using (var outbound = new Semaphore(0, 1, outboundName))
- using (var remote = RemoteInvoke(PingPong_OtherProcess, outboundName, inboundName))
+ using (var remote = RemoteInvoke(new Func<string, string, int>(PingPong_OtherProcess), outboundName, inboundName))
{
// Repeatedly wait for count in one semaphore and then release count into the other
for (int i = 0; i < 10; i++)
diff --git a/src/System.ValueTuple/pkg/System.ValueTuple.pkgproj b/src/System.ValueTuple/pkg/System.ValueTuple.pkgproj
index 9965ac4782..405cb51526 100644
--- a/src/System.ValueTuple/pkg/System.ValueTuple.pkgproj
+++ b/src/System.ValueTuple/pkg/System.ValueTuple.pkgproj
@@ -8,7 +8,7 @@
<ProjectReference Include="..\src\System.ValueTuple.csproj" />
<InboxOnTargetFramework Include="netstandard2.0" />
<InboxOnTargetFramework Include="netcoreapp2.0" />
- <InboxOnTargetFramework Include="$(UAPvNextTFM)" />
+ <InboxOnTargetFramework Include="uap10.0.16299" />
<InboxOnTargetFramework Include="$(AllXamarinFrameworks)" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
diff --git a/src/System.Xml.XDocument/src/MatchingRefApiCompatBaseline.uap.txt b/src/System.Xml.XDocument/src/MatchingRefApiCompatBaseline.uap.txt
new file mode 100644
index 0000000000..330c6c9add
--- /dev/null
+++ b/src/System.Xml.XDocument/src/MatchingRefApiCompatBaseline.uap.txt
@@ -0,0 +1,2 @@
+# Exposed publicly only in implementation for serialization compat
+MembersMustExist : Member 'System.Xml.Linq.XElement..ctor()' does not exist in the implementation but it does exist in the contract.
diff --git a/src/System.Xml.XmlSerializer/src/MatchingRefApiCompatBaseline.netcoreapp.txt b/src/System.Xml.XmlSerializer/src/MatchingRefApiCompatBaseline.netcoreapp.txt
new file mode 100644
index 0000000000..b362774c2c
--- /dev/null
+++ b/src/System.Xml.XmlSerializer/src/MatchingRefApiCompatBaseline.netcoreapp.txt
@@ -0,0 +1,7 @@
+Compat issues with assembly System.Xml.XmlSerializer:
+CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlSchemaImporter' does not inherit from base type 'System.Xml.Serialization.SchemaImporter' in the implementation but it does in the contract.
+MembersMustExist : Member 'System.Xml.Serialization.XmlSchemaImporter..ctor(System.Xml.Serialization.XmlSchemas, System.Xml.Serialization.CodeGenerationOptions, System.Xml.Serialization.ImportContext)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Serialization.XmlSchemaImporter..ctor(System.Xml.Serialization.XmlSchemas, System.Xml.Serialization.CodeIdentifiers, System.Xml.Serialization.CodeGenerationOptions)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Serialization.XmlSerializationReader.ReadString()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Serialization.XmlSerializer.GenerateSerializer(System.Type[], System.Xml.Serialization.XmlMapping[], System.IO.Stream)' does not exist in the implementation but it does exist in the contract.
+Total Issues: 5
diff --git a/src/System.Xml.XmlSerializer/src/MatchingRefApiCompatBaseline.uap.txt b/src/System.Xml.XmlSerializer/src/MatchingRefApiCompatBaseline.uap.txt
new file mode 100644
index 0000000000..b362774c2c
--- /dev/null
+++ b/src/System.Xml.XmlSerializer/src/MatchingRefApiCompatBaseline.uap.txt
@@ -0,0 +1,7 @@
+Compat issues with assembly System.Xml.XmlSerializer:
+CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlSchemaImporter' does not inherit from base type 'System.Xml.Serialization.SchemaImporter' in the implementation but it does in the contract.
+MembersMustExist : Member 'System.Xml.Serialization.XmlSchemaImporter..ctor(System.Xml.Serialization.XmlSchemas, System.Xml.Serialization.CodeGenerationOptions, System.Xml.Serialization.ImportContext)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Serialization.XmlSchemaImporter..ctor(System.Xml.Serialization.XmlSchemas, System.Xml.Serialization.CodeIdentifiers, System.Xml.Serialization.CodeGenerationOptions)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Serialization.XmlSerializationReader.ReadString()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Serialization.XmlSerializer.GenerateSerializer(System.Type[], System.Xml.Serialization.XmlMapping[], System.IO.Stream)' does not exist in the implementation but it does exist in the contract.
+Total Issues: 5
diff --git a/src/System.Xml.XmlSerializer/src/MatchingRefApiCompatBaseline.uapaot.txt b/src/System.Xml.XmlSerializer/src/MatchingRefApiCompatBaseline.uapaot.txt
new file mode 100644
index 0000000000..52460f4dcd
--- /dev/null
+++ b/src/System.Xml.XmlSerializer/src/MatchingRefApiCompatBaseline.uapaot.txt
@@ -0,0 +1,10 @@
+Compat issues with assembly System.Xml.XmlSerializer:
+CannotRemoveBaseTypeOrInterface : Type 'System.Xml.Serialization.XmlSchemaImporter' does not inherit from base type 'System.Xml.Serialization.SchemaImporter' in the implementation but it does in the contract.
+MembersMustExist : Member 'System.Xml.Serialization.XmlSchemaImporter..ctor(System.Xml.Serialization.XmlSchemas, System.Xml.Serialization.CodeGenerationOptions, System.Xml.Serialization.ImportContext)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Serialization.XmlSchemaImporter..ctor(System.Xml.Serialization.XmlSchemas, System.Xml.Serialization.CodeIdentifiers, System.Xml.Serialization.CodeGenerationOptions)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Serialization.XmlSerializationReader.ReadString()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.String System.Xml.Serialization.XmlSerializer.DefaultNamespace' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Serialization.XmlSerializer.Mode.get()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Serialization.XmlSerializer.Mode.set(System.Xml.Serialization.SerializationMode)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.Xml.Serialization.XmlSerializer.SetXmlSerializerContract(System.Xml.Serialization.XmlSerializerImplementation)' does not exist in the implementation but it does exist in the contract.
+Total Issues: 8
diff --git a/src/packages.builds b/src/packages.builds
index 7a64b5729a..fefdcc5505 100644
--- a/src/packages.builds
+++ b/src/packages.builds
@@ -15,6 +15,41 @@
</Project>
</ItemGroup>
+ <!-- Need the PackageIndexFile file property from baseline.props -->
+ <Import Project="../pkg/baseline/baseline.props" />
+
+ <UsingTask TaskName="UpdatePackageIndex" AssemblyFile="$(PackagingTaskDir)Microsoft.DotNet.Build.Tasks.Packaging.dll"/>
+
+ <!--
+ Updates the package index to mark all packages we are building that can go stable as stable.
+ this will allow for a kicked off build to control package stability at queue time. This does edit
+ the package index in-place but that shouldn't cause any problems for official builds are the only
+ ones that might do this. After we ship a stable set of packages this target should be ran and the
+ changes to the package index should be commited to the repo.
+ -->
+ <Target Name="UpdatePackageIndexWithStableVersions"
+ BeforeTargets="BuildAllProjects"
+ Condition="'$(IncludePreReleaseLabelInPackageVersion)' != 'true'">
+ <ItemGroup>
+ <PkgProjects Include="$(MSBuildThisFileDirectory)..\pkg\*\*.pkgproj" />
+ <PkgProjects Include="*\pkg\**\*.pkgproj" />
+ </ItemGroup>
+
+ <MSBuild Targets="GetPackageIdentityIfStable"
+ BuildInParallel="$(BuildInParallel)"
+ Projects="@(PkgProjects)">
+ <Output TaskParameter="TargetOutputs"
+ ItemName="_StablePackages" />
+ </MSBuild>
+
+ <Message Text="Marking package '%(_StablePackages.Identity)' stable with version '%(_StablePackages.Version)'" />
+
+ <UpdatePackageIndex
+ PackageIndexFile="$(PackageIndexFile)"
+ StablePackages="@(_StablePackages)" />
+
+ </Target>
+
<UsingTask TaskName="GenerateNetStandardSupportTable" AssemblyFile="$(PackagingTaskDir)Microsoft.DotNet.Build.Tasks.Packaging.dll" />
<Target Name="GenerateNETStandardDocs">
<Error Condition="'$(WcfPackageReportDir)' == ''"
diff --git a/src/publish.proj b/src/publish.proj
index 90c42841de..32216cc300 100644
--- a/src/publish.proj
+++ b/src/publish.proj
@@ -4,6 +4,7 @@
<Import Project="$(ToolsDir)PublishContent.targets" />
<Import Project="$(ToolsDir)versioning.targets" />
<Import Project="$(PackagesDir)/$(FeedTasksPackage.ToLower())/$(FeedTasksPackageVersion)/build/$(FeedTasksPackage).targets" />
+ <Import Project="$(PackagesDir)/$(PublishSymbolsPackage.ToLower())/$(PublishSymbolsPackageVersion)/build/PublishSymbols.targets" />
<PropertyGroup>
<PublishPattern Condition="'$(PublishPattern)' == ''">$(PackageOutputRoot)\**\*.nupkg</PublishPattern>
@@ -65,4 +66,21 @@
ManifestBranch="$(ManifestBranch)"
ManifestCommit="$(ManifestCommit)" />
</Target>
-</Project> \ No newline at end of file
+
+
+ <Target Name="PublishAllSymbols"
+ DependsOnTargets="SetupPublishSymbols;PublishSymbols"/>
+
+ <Target Name="SetupPublishSymbols">
+ <PropertyGroup>
+ <ConvertPortablePdbsToWindowsPdbs Condition="'$(ConvertPortablePdbsToWindowsPdbs)'==''">true</ConvertPortablePdbsToWindowsPdbs>
+ <SymbolVerboseLogging>true</SymbolVerboseLogging>
+ </PropertyGroup>
+ <ItemGroup>
+ <SymbolPackagesToPublish Include="$(FinalSymbolsPackagesPattern)" />
+ </ItemGroup>
+ <Error Condition="'$(SymbolServerPath)'==''" Text="Missing property SymbolServerPath" />
+ <Error Condition="'$(SymbolServerPAT)'==''" Text="Missing property SymbolServerPAT" />
+ <Message Importance="High" Text="Publishing @(SymbolPackagesToPublish) to $(SymbolServerPath)"/>
+ </Target>
+</Project>
diff --git a/src/shims/ApiCompat.proj b/src/shims/ApiCompat.proj
index 2a5e4ad105..f55eb98bb9 100644
--- a/src/shims/ApiCompat.proj
+++ b/src/shims/ApiCompat.proj
@@ -59,6 +59,8 @@
<Output TaskParameter="ExitCode" PropertyName="ApiCompatExitCode" />
</Exec>
+ <Error Condition="'$(ApiCompatExitCode)' != '0'" Text="ApiCompat failed comparing netfx to $(TargetGroup)" />
+
<PropertyGroup>
<NETStandard20OnlyRef>$(NetStandardRefPath)/netstandard.dll</NETStandard20OnlyRef>
<!-- For netcoreapp also pass in System.Runtime to workaround issue in apicompat tool when it cannot find a core assembly -->
@@ -73,6 +75,8 @@
<Output TaskParameter="ExitCode" PropertyName="ApiCompatExitCode" />
</Exec>
+ <Error Condition="'$(ApiCompatExitCode)' != '0'" Text="ApiCompat failed comparing netstandard.dll to $(TargetGroup)" />
+
<Exec Command="$(ApiCompatCmd) &quot;$(NetStandardRefPath)&quot; @&quot;$(ApiCompatResponseFile)&quot; -baseline:$(ApiCompatNSBaselineFile)"
CustomErrorRegularExpression="^[a-zA-Z]+ :"
StandardOutputImportance="Low"
@@ -81,6 +85,8 @@
<Output TaskParameter="ExitCode" PropertyName="ApiCompatExitCode" />
</Exec>
+ <Error Condition="'$(ApiCompatExitCode)' != '0'" Text="ApiCompat failed comparing netstandard to $(TargetGroup)" />
+
</Target>
<Target Name="Build" DependsOnTargets="RunApiCompat" />
diff --git a/src/shims/ApiCompatBaseline.netcoreapp.netstandard20.txt b/src/shims/ApiCompatBaseline.netcoreapp.netstandard20.txt
index b68ab3b6eb..449b28d590 100644
--- a/src/shims/ApiCompatBaseline.netcoreapp.netstandard20.txt
+++ b/src/shims/ApiCompatBaseline.netcoreapp.netstandard20.txt
@@ -1,6 +1,18 @@
Compat issues with assembly mscorlib:
-TypeCannotChangeClassification : Type 'System.RuntimeArgumentHandle' is a 'ref struct' in the implementation but is a 'struct' in the contract.
TypesMustExist : Type 'System.TupleExtensions' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.Runtime.CompilerServices.TupleElementNamesAttribute' does not exist in the implementation but it does exist in the contract.
+Compat issues with assembly netstandard:
+TypeCannotChangeClassification : Type 'System.RuntimeArgumentHandle' is a 'ref struct' in the implementation but is a 'struct' in the contract.
+TypeCannotChangeClassification : Type 'System.TypedReference' is a 'ref struct' in the implementation but is a 'struct' in the contract.
+Compat issues with assembly System.Core:
+TypesMustExist : Type 'System.Security.Cryptography.ECCurve' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.Security.Cryptography.ECParameters' does not exist in the implementation but it does exist in the contract.
+TypesMustExist : Type 'System.Security.Cryptography.ECPoint' does not exist in the implementation but it does exist in the contract.
+
+# Compat issues complaining about class vs delegate and class vs struct are because of a bug in APICompat tool where the implementation is picking
+# the wrong core assembly. It is picking System.Runtime instead of System.Private.CoreLib, there isn't any straight forward way to fix so baselining.
+
+TypeCannotChangeClassification : Type 'System.RuntimeArgumentHandle' is a 'ref struct' in the implementation but is a 'struct' in the contract.
TypeCannotChangeClassification : Type 'System.TypedReference' is a 'ref struct' in the implementation but is a 'struct' in the contract.
TypesMustExist : Type 'System.ValueTuple' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'System.ValueTuple<T1>' does not exist in the implementation but it does exist in the contract.
@@ -11,12 +23,4 @@ TypesMustExist : Type 'System.ValueTuple<T1, T2, T3, T4, T5>' does not exist in
TypesMustExist : Type 'System.ValueTuple<T1, T2, T3, T4, T5, T6>' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'System.ValueTuple<T1, T2, T3, T4, T5, T6, T7>' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'System.ValueTuple<T1, T2, T3, T4, T5, T6, T7, TRest>' does not exist in the implementation but it does exist in the contract.
-TypesMustExist : Type 'System.Runtime.CompilerServices.TupleElementNamesAttribute' does not exist in the implementation but it does exist in the contract.
-Compat issues with assembly netstandard:
-TypeCannotChangeClassification : Type 'System.RuntimeArgumentHandle' is a 'ref struct' in the implementation but is a 'struct' in the contract.
-TypeCannotChangeClassification : Type 'System.TypedReference' is a 'ref struct' in the implementation but is a 'struct' in the contract.
-Compat issues with assembly System.Core:
-TypesMustExist : Type 'System.Security.Cryptography.ECCurve' does not exist in the implementation but it does exist in the contract.
-TypesMustExist : Type 'System.Security.Cryptography.ECParameters' does not exist in the implementation but it does exist in the contract.
-TypesMustExist : Type 'System.Security.Cryptography.ECPoint' does not exist in the implementation but it does exist in the contract.
-Total Issues: 18
+
diff --git a/src/shims/ApiCompatBaseline.uap.netstandard20.txt b/src/shims/ApiCompatBaseline.uap.netstandard20.txt
index b6d9449567..c89c017dc8 100644
--- a/src/shims/ApiCompatBaseline.uap.netstandard20.txt
+++ b/src/shims/ApiCompatBaseline.uap.netstandard20.txt
@@ -1,7 +1,5 @@
Compat issues with assembly mscorlib:
-TypeCannotChangeClassification : Type 'System.RuntimeArgumentHandle' is a 'ref struct' in the implementation but is a 'struct' in the contract.
TypesMustExist : Type 'System.TupleExtensions' does not exist in the implementation but it does exist in the contract.
-TypeCannotChangeClassification : Type 'System.TypedReference' is a 'ref struct' in the implementation but is a 'struct' in the contract.
TypesMustExist : Type 'System.Runtime.CompilerServices.TupleElementNamesAttribute' does not exist in the implementation but it does exist in the contract.
Compat issues with assembly netstandard:
TypeCannotChangeClassification : Type 'System.RuntimeArgumentHandle' is a 'ref struct' in the implementation but is a 'struct' in the contract.
@@ -10,4 +8,25 @@ Compat issues with assembly System.Core:
TypesMustExist : Type 'System.Security.Cryptography.ECCurve' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'System.Security.Cryptography.ECParameters' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'System.Security.Cryptography.ECPoint' does not exist in the implementation but it does exist in the contract.
-Total Issues: 9
+
+# Compat issues complaining about class vs delegate and class vs struct are because of a bug in APICompat tool where the implementation is picking
+# the wrong core assembly. It is picking System.Runtime instead of System.Private.CoreLib, there isn't any straight forward way to fix so baselining.
+TypeCannotChangeClassification : Type 'System.Action<T1, T2, T3, T4, T5, T6, T7, T8, T9>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.IO.HandleInheritability' is a 'class' in the implementation but is a 'struct' in the contract.
+TypeCannotChangeClassification : Type 'System.IO.FileAttributes' is a 'class' in the implementation but is a 'struct' in the contract.
+
diff --git a/src/shims/ApiCompatBaseline.uapaot.netstandard20.txt b/src/shims/ApiCompatBaseline.uapaot.netstandard20.txt
index b6d9449567..181752efce 100644
--- a/src/shims/ApiCompatBaseline.uapaot.netstandard20.txt
+++ b/src/shims/ApiCompatBaseline.uapaot.netstandard20.txt
@@ -1,7 +1,5 @@
Compat issues with assembly mscorlib:
-TypeCannotChangeClassification : Type 'System.RuntimeArgumentHandle' is a 'ref struct' in the implementation but is a 'struct' in the contract.
TypesMustExist : Type 'System.TupleExtensions' does not exist in the implementation but it does exist in the contract.
-TypeCannotChangeClassification : Type 'System.TypedReference' is a 'ref struct' in the implementation but is a 'struct' in the contract.
TypesMustExist : Type 'System.Runtime.CompilerServices.TupleElementNamesAttribute' does not exist in the implementation but it does exist in the contract.
Compat issues with assembly netstandard:
TypeCannotChangeClassification : Type 'System.RuntimeArgumentHandle' is a 'ref struct' in the implementation but is a 'struct' in the contract.
@@ -10,4 +8,29 @@ Compat issues with assembly System.Core:
TypesMustExist : Type 'System.Security.Cryptography.ECCurve' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'System.Security.Cryptography.ECParameters' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'System.Security.Cryptography.ECPoint' does not exist in the implementation but it does exist in the contract.
-Total Issues: 9
+
+Compat issues with assembly System.Runtime:
+MembersMustExist : Member 'System.Memory<T>.Pin()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.ReadOnlyMemory<T>.Pin()' does not exist in the implementation but it does exist in the contract.
+
+# Compat issues complaining about class vs delegate and class vs struct are because of a bug in APICompat tool where the implementation is picking
+# the wrong core assembly. It is picking System.Runtime instead of System.Private.CoreLib, there isn't any straight forward way to fix so baselining.
+TypeCannotChangeClassification : Type 'System.Action<T1, T2, T3, T4, T5, T6, T7, T8, T9>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TResult>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TResult>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TResult>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TResult>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TResult>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TResult>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, TResult>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult>' is a 'class' in the implementation but is a 'delegate' in the contract.
+TypeCannotChangeClassification : Type 'System.IO.HandleInheritability' is a 'class' in the implementation but is a 'struct' in the contract.
+TypeCannotChangeClassification : Type 'System.IO.FileAttributes' is a 'class' in the implementation but is a 'struct' in the contract.
+
diff --git a/src/shims/manual/System.Data.csproj b/src/shims/manual/System.Data.csproj
index 3807fda917..445f060ba7 100644
--- a/src/shims/manual/System.Data.csproj
+++ b/src/shims/manual/System.Data.csproj
@@ -1,24 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="dir.props" />
<PropertyGroup>
- <BuildConfigurations>
- netcoreapp;
- uap;
- </BuildConfigurations>
- <IsNETCoreApp>true</IsNETCoreApp>
- <IsUAP>true</IsUAP>
- </PropertyGroup>
- <!-- need to by-pass the dir.props in the shims directory for this project -->
- <Import Project="..\..\..\dir.props" />
- <PropertyGroup>
- <AssemblyVersion>4.0.0.0</AssemblyVersion>
- <AssemblyKey>ECMA</AssemblyKey>
- <IsPartialFacadeAssembly>true</IsPartialFacadeAssembly>
- <HasMatchingContract>true</HasMatchingContract>
- <ContractAssemblyPath>$(NetFxRefPath)System.Data.dll</ContractAssemblyPath>
- <GenFacadesIgnoreMissingTypes>true</GenFacadesIgnoreMissingTypes>
- <IsRuntimeAssembly>true</IsRuntimeAssembly>
- <DefineConstants Condition="'$(TargetGroup)' == 'netcoreapp'">$(DefineConstants);netcoreapp</DefineConstants>
<ProjectGuid>{5E51460E-C9DC-4B6B-B87E-0ED742FC6733}</ProjectGuid>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'" />
diff --git a/src/shims/manual/System.csproj b/src/shims/manual/System.csproj
index 84ff025bf7..09bc263d27 100644
--- a/src/shims/manual/System.csproj
+++ b/src/shims/manual/System.csproj
@@ -1,24 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="dir.props" />
<PropertyGroup>
- <BuildConfigurations>
- netcoreapp;
- uap;
- </BuildConfigurations>
- <IsNETCoreApp>true</IsNETCoreApp>
- <IsUAP>true</IsUAP>
- </PropertyGroup>
- <!-- need to by-pass the dir.props in the shims directory for this project -->
- <Import Project="..\..\..\dir.props" />
- <PropertyGroup>
- <AssemblyVersion>4.0.0.0</AssemblyVersion>
- <AssemblyKey>ECMA</AssemblyKey>
- <IsPartialFacadeAssembly>true</IsPartialFacadeAssembly>
- <HasMatchingContract>true</HasMatchingContract>
- <ContractAssemblyPath>$(NetFxRefPath)System.dll</ContractAssemblyPath>
- <GenFacadesIgnoreMissingTypes>true</GenFacadesIgnoreMissingTypes>
- <IsRuntimeAssembly>true</IsRuntimeAssembly>
- <DefineConstants Condition="'$(TargetGroup)' == 'netcoreapp'">$(DefineConstants);netcoreapp</DefineConstants>
<ProjectGuid>{1FB7650D-7165-49B9-98B0-E345D56983DB}</ProjectGuid>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'" />
diff --git a/src/shims/manual/dir.props b/src/shims/manual/dir.props
new file mode 100644
index 0000000000..03a82d2305
--- /dev/null
+++ b/src/shims/manual/dir.props
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <BuildConfigurations>
+ netcoreapp;
+ uap;
+ </BuildConfigurations>
+ <IsNETCoreApp>true</IsNETCoreApp>
+ <IsUAP>true</IsUAP>
+ </PropertyGroup>
+ <!-- need to by-pass the dir.props in the shims directory for this project -->
+ <Import Project="..\..\..\dir.props" />
+ <PropertyGroup>
+ <AssemblyVersion>4.0.0.0</AssemblyVersion>
+ <AssemblyKey>ECMA</AssemblyKey>
+ <IsPartialFacadeAssembly>true</IsPartialFacadeAssembly>
+ <GenFacadesForceZeroVersionSeeds>true</GenFacadesForceZeroVersionSeeds>
+ <GenFacadesIgnoreMissingTypes>true</GenFacadesIgnoreMissingTypes>
+ <IsRuntimeAssembly>true</IsRuntimeAssembly>
+ <HasMatchingContract>true</HasMatchingContract>
+ <ContractAssemblyPath>$(NetFxRefPath)$(MSBuildProjectName).dll</ContractAssemblyPath>
+ <DefineConstants Condition="'$(TargetGroup)' == 'netcoreapp'">$(DefineConstants);netcoreapp</DefineConstants>
+ </PropertyGroup>
+</Project> \ No newline at end of file
diff --git a/src/shims/manual/mscorlib.csproj b/src/shims/manual/mscorlib.csproj
index a522c16713..040aaffc68 100644
--- a/src/shims/manual/mscorlib.csproj
+++ b/src/shims/manual/mscorlib.csproj
@@ -1,24 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="dir.props" />
<PropertyGroup>
- <BuildConfigurations>
- netcoreapp;
- uap;
- </BuildConfigurations>
- <IsNETCoreApp>true</IsNETCoreApp>
- <IsUAP>true</IsUAP>
- </PropertyGroup>
- <!-- need to by-pass the dir.props in the shims directory for this project -->
- <Import Project="..\..\..\dir.props" />
- <PropertyGroup>
- <AssemblyVersion>4.0.0.0</AssemblyVersion>
- <AssemblyKey>ECMA</AssemblyKey>
- <IsPartialFacadeAssembly>true</IsPartialFacadeAssembly>
- <HasMatchingContract>true</HasMatchingContract>
- <ContractAssemblyPath>$(NetFxRefPath)mscorlib.dll</ContractAssemblyPath>
- <GenFacadesIgnoreMissingTypes>true</GenFacadesIgnoreMissingTypes>
- <IsRuntimeAssembly>true</IsRuntimeAssembly>
- <DefineConstants Condition="'$(TargetGroup)' == 'netcoreapp'">$(DefineConstants);netcoreapp</DefineConstants>
<ProjectGuid>{CEAE2042-461E-490A-974C-AD7FBD4E294E}</ProjectGuid>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'" />
diff --git a/src/syncAzure.proj b/src/syncAzure.proj
index 7d34e17d27..80f1278fcd 100644
--- a/src/syncAzure.proj
+++ b/src/syncAzure.proj
@@ -3,9 +3,8 @@
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
- <ContainerNamePrefix Condition="'$(ContainerNamePrefix)' == ''">corefx-$(PreReleaseLabel)</ContainerNamePrefix>
- <ContainerName Condition="'$(ContainerNamePrefix)' != '' and '$(BuildNumberMajor)' != '' and '$(BuildNumberMinor)' != ''">$(ContainerNamePrefix)-$(BuildNumberMajor)-$(BuildNumberMinor)</ContainerName>
- <DownloadDirectory>$(PackagesDir)AzureTransfer</DownloadDirectory>
+ <ContainerName>$(ContainerName.Replace(".","-"))</ContainerName>
+ <DownloadDirectory Condition="'$(DownloadDirectory)' == ''">$(PackagesDir)AzureTransfer</DownloadDirectory>
</PropertyGroup>
<Import Project="$(ToolsDir)SyncCloudContent.targets" />
diff --git a/src/upload-tests.proj b/src/upload-tests.proj
index 9b12dea43c..6616318fef 100644
--- a/src/upload-tests.proj
+++ b/src/upload-tests.proj
@@ -61,6 +61,8 @@
<HelixJobType Condition="'$(HelixJobType)'==''">test/functional/cli/</HelixJobType>
+ <!-- Detect whether we are on a product construction build via ProductBuildId. If so, set source appropriately -->
+ <HelixSource Condition="'$(HelixSource)'=='' And '$(IsOfficial)'!='' And '$(TestProduct)'!='' And '$(Branch)'!='' And '$(ProductBuildId)'!=''">prodcon/$(TestProduct)/$(Branch)/</HelixSource>
<HelixSource Condition="'$(HelixSource)'=='' And '$(IsOfficial)'!='' And '$(TestProduct)'!='' And '$(Branch)'!=''">official/$(TestProduct)/$(Branch)/</HelixSource>
<HelixSource Condition="'$(HelixSource)'=='' And '$(IsOfficial)'=='' And '$(TestProduct)'!='' And '$(Branch)'!=''">pr/$(TestProduct)/$(Branch)/</HelixSource>
<HelixSource Condition="'$(HelixSource)'==''">pr/unknown/</HelixSource>
@@ -70,7 +72,8 @@
<!-- Properties used for submission by CloudTest.Helix.Targets-->
<BuildMoniker>$(CurrentDate)</BuildMoniker>
- <BuildMoniker Condition="'$(IsOfficial)'=='true'">$(OfficialBuildId)</BuildMoniker>
+ <BuildMoniker Condition="'$(IsOfficial)'=='true' And '$(ProductBuildId)'==''">$(OfficialBuildId)</BuildMoniker>
+ <BuildMoniker Condition="'$(IsOfficial)'=='true' And '$(ProductBuildId)'!=''">$(ProductBuildId)</BuildMoniker>
<HelixArchLabel>$(ArchGroup)</HelixArchLabel>
<HelixConfigLabel>$(ConfigurationGroup)</HelixConfigLabel>
</PropertyGroup>
@@ -161,4 +164,4 @@
<Message Text="Work Item:%(LocalExecutionLogs.WorkItemFriendlyName)%0a@(LocalExecutionLogs, '%0a')%0a" />
</Target>
-</Project> \ No newline at end of file
+</Project>